Utilizing NFQueue, Scapy, and HTTP for persistence.

By Matt Hart –


Last semester I enrolled in a Wireless Security course while studying at Rochester Institute of Technology. Throughout the semester we were assigned projects like creating a Man in the Middle (MITM)attack tool, as well as a Captive Portal for our wireless network. While working on these projects, I got some hands-on experience working with libnetfilter_queue (NFQueue) and Scapy. This year, while taking the Network System Security Audit class, we were tasked to do some research and create a blog post of our findings. Due to my familiarity with the previously mentioned tools, I wanted to work with them further. The first idea that came to my head was utilizing NFQueue to somehow pass commands to a server that had been compromised, essentially setting up persistence. The following sections will detail my proof of concept and my findings. All code can be found on my GitHub here!


For those not familiar with NFQueue, it is an iptables target which allows for packets to be pulled from the kernel into userland. This presents the opportunity for a program in the userland to dictate the decision of what occurs to the packet. The two standard decisions available are ACCEPT or DROP. Fortunately, for those who love Python, there are Python bindings that allow you to leverage libnetfilter_queue. The reason I think NFQueue is so neat is that it allows access to raw packet data in userland. This is where Scapy comes in.


Scapy is an amazing packet manipulation tool written in Python. It is incredibly well documented and super versatile. This toolset becomes convenient when paired with the ability of the libnetfilter_queue Python bindings to directly alter packets. Finally, this is where HTTP comes into play.


HTTP is the primary protocol used to move data on the web. I chose the HTTP protocol specifically because a large majority of publicly available devices are running a web server, sometimes without the admins knowledge. This also provides an attack vector as most edge devices and host firewalls will be allowing traffic through on port 80 (the default port for HTTP).

Proof of Concept

Now we know the basics, we can tie this all together to create a tool for establishing persistence on a compromised server. My proof of concept relied on three key components.

  1. An iptables rule that would send specific packets to an NFQUEUE
  2. A program to send this data to the target host
  3. A userland program that would be able to process this data

Step One:

This seemed to be the easy part. Once the server is compromised, simply add a rule to the top of iptables that would send traffic coming from a specific port to a queue. This can be achieved with the following rule:

iptables -A INPUT -p tcp --sport 6666 --dport 80 -j NFQUEUE --queue-num 0

This rule tells iptables to take any traffic that comes in port 80, with a source port of 6666, and send it to queue 0. This packet is now available in the userland and will remain in the queue until further directed.

Step Two:

Now, we need a program to send our specific packet. For the reasons above I chose HTTP and more specifically an HTTP GET request packet. This packet will need a source and destination port that corresponds to our iptable’s rule (6666, 80) and contains some sort of flag or data for our listening program. For this, Scapy is perfect and allows you to craft the desired packet. The following script is used to create and send the packet:

from netfilterqueue import NetfilterQueue
 from scapy.all import *
 pkt=Ether(src=”00:13:37:00:17:bb”)/IP(src=””,dst=””)/TCP(dport=80,sport=6666)/”GET /index.html bmV0Y2F0\n”

This script creates the packet we need and sends it using the sendp Scapy function. Notice, the string bmV0Y2F0 in the data section. This is a Base64 encoded string that translates to netcat.

Step Three:

Finally, we have a program that is sitting on the vulnerable server, bound to the queue waiting for packets. The two main functions of this script can be found below. A detailed version can be found on my GitHub here.

def HandlePacket(pkt):

data = pkt.get_payload()
 newPacket = IP(data)
 test = CheckPacket(newPacket)

def CheckPacket(packet):

ret = "\n".join(packet.sprintf("{Raw:%Raw.load%}\n").split(r"\r\n"))
 if "bmV0Y2F0" in ret:

print "Executing Netcat on port 7777\n"
 #execute your commands here

elif "ZHJvcGZ3" in ret:

print "Executing IPtables -F\n"
 #execute your commands here


print "String not found."

These two functions make up the bulk of this POC. The HandlePacket function uses the libnetfilter_queue bindings to take the packet data from the queue and pass it to the checkPacket function. In checkPacket, the data is parsed looking for specific Base64 encoded strings which will execute a command.

Seen below are screenshots of the POC being executed between a server and client based on the above code.

Successfully sending the command packet.


Successful execution on the target host.


Overall, I thought this was a cool concept. We can see that it is possible to send commands through HTTP requests from a client to a server that has the proper malicious configuration and program running. There are many considerations (and issues) with this idea. For starters, the fact that there is a blatant iptables rule sitting at the top of the ACL, an unknown process running on the server, and suspicious traffic if you’re looking. However, I think many of these issues can be overcome by replacing and spoofing the iptables binary, hiding the process, and crafting more covert packets. Moving forward, I would like to continue this research as a pet project in my free time. First, I plan on adding more functionality between the sending program and receiving application such as custom command execution and predefined command options. Feel free to connect with me at mhart@mail.rit.edu if you have any questions or would like to spitball some ideas!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s