Sometimes there are a few occasions that edge network devices are not accessible from remote. The reason varies from security reasons to environmental reasons(no global ip address is assigned and no access to the ISP router etc). In my previous project, I used code from Python Blackhat to show how Windows PC becomes a victim to expose its command access. In this time, I use this similar code for good.
This can be used to deploy periodically or can be triggered by syslog messages via EEM.
Output Example:
[ In the Server ]
# python3 cisco_revshell_server.py $(hostname -I) 2022
[+] Listening for connection ...
[+] Got a connection!
[+] Authenticated!
connected to us-east-1_e-rtr-01
us-east-1_e-rtr-01(guestshell)# ls -l /bootflash
total 406928
drwxr-xr-x 2 65534 65534 4096 May 28 06:20 CRDU
drwxr-xr-x 3 65534 65534 4096 May 28 06:19 core
-rw-r----- 1 65534 65534 377189336 Jan 17 19:31 csr1000v-mono-universalk9.16.07.01a.SPA.pkg
-rw-r--r-- 1 65534 65534 38986404 Jan 17 19:31 csr1000v-rpboot.16.07.01a.SPA.pkg
-rw-r--r-- 1 65534 65534 157 Jun 3 20:51 csrlxc-cfg.log
-rw-r--r-- 1 65534 65534 0 Jun 3 20:51 cvac.log
drwxrwxr-x 2 guestshell guestshell 4096 Jun 3 22:57 gs_scripts
-rw-r--r-- 1 65534 65534 174 Jun 3 20:50 iid_check.log
drwxr-xr-x 18 65534 65534 4096 Jun 3 20:51 iox
drwx------ 2 65534 65534 16384 Jan 17 19:30 lost+found
-rw-r--r-- 1 65534 65534 16 May 28 06:20 ovf-env.xml.md5
-rw-r--r-- 1 65534 65534 1967 Jan 17 19:31 packages.conf
drwxr-xr-x 2 65534 65534 4096 Jun 3 22:30 syslog
-rw-r--r-- 1 65534 65534 30 Jun 3 20
us-east-1_e-rtr-01(guestshell)# python -c "import cli;cli.executep('show ip route')"
Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP
D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area
N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2
E1 - OSPF external type 1, E2 - OSPF external type 2
i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2
ia - IS-IS inter area, * - candidate default, U - per-user static route
o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP
a - application route
+ - replicated route, % - next hop override, p - overrides from PfR
Gateway of last resort is 172.31.1.1 to network 0.0.0.0
S* 0.0.0.0/0 [1/0] via 172.31.1.1, GigabitEthernet1
1.0.0.0/32 is subnetted, 1 subnets
C 1.1.1.1 is directly connected, Loopback0
10.0.0.0/8 is variably subnetted, 4 subnets, 2 masks
C 10.0.0.0/24 is directly connected, VirtualPortGroup0
L 10.0.0.254/32 is directly connected, VirtualPortGroup0
C 10.10.10.0/24 is dir
us-east-1_e-rtr-01(guestshell)# exit
exiting
[-] Caught exception: exit
Here is the code:
[ In Cisco Box ] cisco_revshell_client.py
import sys
import paramiko
import subprocess
def ssh_command(ip, user, passwd, port, command):
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(ip, username=user, password=passwd, port=port)
ssh_session = client.get_transport().open_session()
if ssh_session.active:
ssh_session.send(command)
print(ssh_session.recv(1024) + b'%s' % ip)
while True:
command = ssh_session.recv(1024)
try:
cmd_output = subprocess.check_output(command, shell=True)
ssh_session.send(cmd_output)
except Exception as e:
ssh_session.send(str(e))
client.close()
return
if __name__ == "__main__":
if len(sys.argv) != 2:
print "Usage: %s 'hostname'" % sys.argv[0]
sys.exit(0)
ssh_command('XX.XX.XX.XX', 'cisco-rtr', 'passw0rd', 2022, sys.argv[1])
[ In the Server ] cisco_revshell_server.py
import socket
import threading
import paramiko
import sys
class Server(paramiko.ServerInterface):
def __init__(self):
self.event = threading.Event()
def check_channel_request(self, kind, chanid):
if kind == 'session':
return paramiko.OPEN_SUCCEEDED
def check_auth_password(self, username, password):
if (username == 'cisco-rtr') and (password == 'passw0rd'):
return paramiko.AUTH_SUCCESSFUL
return paramiko.AUTH_FAILED
server = sys.argv[1]
ssh_port = int(sys.argv[2])
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((server, ssh_port))
sock.listen(100)
print("[+] Listening for connection ...")
client, addr = sock.accept()
except Exception as e:
print(f"[-] Listen failed: {str(e)}")
sys.exit(1)
print("[+] Got a connection!")
try:
bhSession = paramiko.Transport(client)
bhSession.add_server_key(host_key)
server = Server()
try:
bhSession.start_server(server=server)
except paramiko.SSHException as x:
print("[-] SSH negotiation failed.")
chan = bhSession.accept(20)
print("[+] Authenticated!")
hostname = str(chan.recv(1024), 'utf-8')
print(f"connected to {hostname}.")
chan.send('remote connection is created to ')
while True:
try:
command = input(f"{hostname}# ")
if command != 'exit':
chan.send(command)
print(str(chan.recv(1024),'utf-8'))
else:
chan.send('exit')
print('exiting')
bhSession.close()
raise Exception('exit')
except KeyboardInterrupt:
bhSession.close()
except Exception as e:
print(f"[-] Caught exception: {str(e)}")
try:
bhSession.close()
except:
pass
sys.exit(1)