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)