How To: Securely Sniff Wi-Fi Packets with Sniffglue

Securely Sniff Wi-Fi Packets with Sniffglue

Sniffing packets over a network is an easy way for hackers to gather information on a target without needing to do much work. But doing so can be risky if sniffing packets on an untrusted network because a payload within the packets being captured could be executed on your system. To prevent that, Sniffglue sandboxes packet sniffing to provide an extra layer of security.

Passive sniffing is stealthy and effective, making it the obvious first step for hackers and pentesters putting together information about a target network. But if you've ever run Wireshark as root before, you might have seen a warning against running it as root. That's because doing so can put your computer at risk, and running a program as root and then having it being hijacked by a zero-day vulnerability is a real risk when capturing random radio traffic.

It's very unsecure running Wireshark this way as every possible Wireshark exploit will be running with the administrator account being able to compromise the whole system.

That means that if an exploit for Wireshark is found or known to some already, that exploit will be able to run as root on your computer if you run Wireshark as root. Because we deal with so many unknowns when receiving radio data, it's essential to take steps to minimize the damage that could occur.

The proper way to avoid radio zero-days is to set up a user that can use the network adapter but can't execute as root. However, it can be confusing for someone setting things up their first time.

For anyone interested in packet sniffing with a program that has security features against these risks built-in, Sniffglue is it. It's a passive recon tool that lets you sniff traffic over a network without the risk of being detected. Unlike an ARP-scan or other active scanning tools, Sniffglue passively listens for traffic without doing anything to generate the traffic itself, as doing so would reveal its presence.

One of the keys to this is sandboxing, which Sniffglue builds in by default. The application itself is prevented from doing anything it doesn't need to do, avoiding an exploit from getting the same kind of traction. Written in Rust to be optimized for using all available CPU resources for processing packets, the additional attention to security makes Sniffglue worth trying out.

What You'll Need

To use Sniffglue, you'll need a computer with Rust installed, since the program is written in the Rust language. I recommend using Kali Linux, Ubuntu, or another Debian or Arch Linux system. I tried running this on macOS and found it pretty difficult. Chances are, you already have Rust installed because it comes preinstalled on some systems. For instance, we already had it on a fresh Kali system.

Before going further, install libseccomp-dev and libpcap-dev, which is for the secure computing module and the pcap parsing, respectively.

~$ sudo apt-get install libseccomp-dev libpcap-dev

Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
  libseccomp2
The following packages will be upgraded:
  libseccomp-dev libseccomp2
2 upgraded, 0 newly installed, 0 to remove and 1760 not upgraded.
Need to get 0 B/116 kB of archives.
After this operation, 68.6 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Reading changelogs... Done
(Reading database ... 411760 files and directories currently installed.)
Preparing to unpack .../libseccomp-dev_2.4.2-2_amd64.deb ...
Unpacking libseccomp-dev:amd64 (2.4.2-2) over (2.4.1-2) ...
Preparing to unpack .../libseccomp2_2.4.2-2_amd64.deb ...
Unpacking libseccomp2:amd64 (2.4.2-2) over (2.4.1-2) ...
Setting up libseccomp2:amd64 (2.4.2-2) ...
Setting up libseccomp-dev:amd64 (2.4.2-2) ...
Processing triggers for man-db (2.8.5-2) ...
Processing triggers for libc-bin (2.28-8) ...

Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages will be upgraded:
  libpcap-dev
1 upgraded, 0 newly installed, 0 to remove and 1759 not upgraded.
Need to get 0 B/29.0 kB of archives.
After this operation, 2,048 B of additional disk space will be used.
Reading changelogs... Done
(Reading database ... 411761 files and directories currently installed.)
Preparing to unpack .../libpcap-dev_1.9.1-2_amd64.deb ...
Unpacking libpcap-dev:amd64 (1.9.1-2) over (1.9.0-2) ...
Setting up libpcap-dev:amd64 (1.9.1-2) ...

Step 1: Download & Install Sniffglue

Downloading and running the Sniffglue program is done using Cargo, the package manager for Rust, which is similar to Pip for Python for anyone familiar with that. After installing Rust, if you didn't already have it, Cargo should be installed by default.

After updating your system, make sure you have Cargo installed by running apt install cargo. A lot of different packages should compile. Then, run the cargo install sniffglue command to install Sniffglue via the Cargo package manager or to see if Snifglue is already installed, which is should be after installing Cargo.

~$ apt update

Hit:1 http://archive.linux.duke.edu/kalilinux/kali kali-rolling InRelease
Reading package lists... Done
Building dependency tree
Reading state information... Done
1759 packages can be upgraded. Run 'apt list --upgradable' to see them.

~$ apt install cargo

Reading package lists... Done
Building dependency tree
Reading state information... Done
The following package was automatically installed and is no longer required:
  libgit2-27
Use 'apt autoremove' to remove it.
The following additional packages will be installed:
  libc-bin libc-dev-bin libc-l10n libc6 libc6-dbg libc6-dev libc6-i386
  libgit2-28 locales locales-all
Suggested packages:
  cargo-doc glibc-doc
...
Setting up cargo (0.37.0-3+b1) ...
Setting up libc6-i386 (2.29-3) ...
Setting up libc-dev-bin (2.29-3) ...
Setting up libc6-dev:amd64 (2.29-3) ...
Processing triggers for man-db (2.8.5-2) ...
Processing triggers for libc-bin (2.29-3) ...

~$ cargo install sniffglue

    Updating crates.io index
error: binary `sniffglue` already exists in destination as part of `sniffglue v0.9.0`
Add --force to overwrite

Step 2: Run Cargo Binary

Now, we can either spend the time adding Sniffglue to our path or just navigate to the directory Cargo installs Sniffglue into to run it directly. Let's go directly to where the binary is (cd ~/.cargo/bin) and run it with sudo ./sniffglue -h. We should see the output for the help file, signaling that Sniffglue is installed and ready to run.

~$ cd ~/.cargo/bin
~/.cargo/bin$ sudo ./sniffglue -h

sniffglue 0.9.0
kpcyrd <git@rxv.cc>
Secure multithreaded packet sniffer

USAGE:
    sniffglue [FLAGS] [OPTIONS] [device]

FLAGS:
    -d, --detailed    Detailed output
    -h, --help        Prints help information
    -j, --json        Json output (unstable)
    -p, --promisc     Set device to promisc
    -r, --read        Open device as pcap file
    -V, --version     Prints version information
    -v, --verbose     Show more packets (maximum: 4)

OPTIONS:
    -n, --cpus <cpus>    Number of cores

ARGS:
    <device>    Device for sniffing

Step 3: Sniff on a Network Interface

Now, let's sniff on a network interface. First, we'll find the name of our network cards by running ip a | grep MULTICAST.

~/.cargo/bin$ ip a | grep MULTICAST

2: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
3: wlp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000

Then, run Sniffglue on the interface you want to start sniffing packets on.

~/.cargo/bin$ sudo ./sniffglue enp2s0

Listening on device: "enp2s0"

50:7b:9d:7a:c8:8a -> 40:70:09:85:d1:a7, udp 192.168.0.37:57251 -> 209.18.47.62:53 dns req, (A, "null-byte.wonderhowto.com")

50:7b:9d:7a:c8:8a -> 40:70:09:85:d1:a7, udp 192.168.0.37:50381 -> 209.18.47.62:53 dns req, (AAAA, "null-byte.wonderhowto.com")

40:70:09:85:d1:a7 -> 50:7b:9d:7a:c8:8a, udp 209.18.47.62:53 -> 192.168.0.37:57251 dns resp, ("null-byte.wonderhowto.com", A(104.193.19.59))

40:70:09:85:d1:a7 -> 50:7b:9d:7a:c8:8a, udp 209.18.47.62:53 -> 192.168.0.37:50381 dns resp,

Here, we are sniffing our Ethernet card, enp2s0, and we can see DNS requests to Null Byte. If we were plugged into a LAN tap or Hak5 Packet Squirrel, we could easily read any unencrypted traffic passing through a cable we have access to.

Step 4: Sniff Wi-Fi in Promiscuous Mode

Next, we'll turn our attention to our wireless card. First, we can get the name of our card by running ip a again and filtering the output.

~/.cargo/bin$ ip a | grep MULTICAST

2: enp2s0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
3: wlp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000

Then, on our system, we'll run Sniffglue with the -d argument to show more detail from each request, and the -p argument to put our card into promiscuous mode. In the example below, I navigated to "badsite.com" after starting to sniff the wireless traffic on card wlp1s0.

~/.cargo/bin$ sudo ./sniffglue wlp1s0 -d -p

Listening on device: "wlp1s0"
eth: EthernetFrame { source_mac: MacAddress([48, 82, 203, 107, 118, 95]), dest_mac: MacAddress([64, 112, 9, 133, 209, 167]), ethertype: IPv4 }
    ipv4: IPv4Header { version: 4, ihl: 20, tos: 0, length: 73, id: 44379, flags: 2, fragment_offset: 0, ttl: 64, protocol: UDP, chksum: 52279, source_addr: 192.168.0.24, dest_addr: 209.18.47.62 }
        udp: UdpHeader { source_port: 43195, dest_port: 53, length: 53, checksum: 13395 }
            dns: Request(Request { questions: [(A, "googleads.g.doubleclick.net")] })
eth: EthernetFrame { source_mac: MacAddress([64, 112, 9, 133, 209, 167]), dest_mac: MacAddress([48, 82, 203, 107, 118, 95]), ethertype: IPv4 }
    ipv4: IPv4Header { version: 4, ihl: 20, tos: 0, length: 114, id: 51085, flags: 2, fragment_offset: 0, ttl: 57, protocol: UDP, chksum: 47324, source_addr: 209.18.47.62, dest_addr: 192.168.0.24 }
        udp: UdpHeader { source_port: 53, dest_port: 43195, length: 94, checksum: 33904 }
            dns: Response(Response { answers: [("googleads.g.doubleclick.net", CNAME("pagead46.l.doubleclick.net")), ("pagead46.l.doubleclick.net", A(172.217.14.66))] })
eth: EthernetFrame { source_mac: MacAddress([48, 82, 203, 107, 118, 95]), dest_mac: MacAddress([64, 112, 9, 133, 209, 167]), ethertype: IPv4 }
    ipv4: IPv4Header { version: 4, ihl: 20, tos: 0, length: 60, id: 45283, flags: 2, fragment_offset: 0, ttl: 64, protocol: UDP, chksum: 51388, source_addr: 192.168.0.24, dest_addr: 209.18.47.62 }
        udp: UdpHeader { source_port: 33734, dest_port: 53, length: 40, checksum: 35194 }
            dns: Request(Request { questions: [(AAAA, "www.google.com")] })
eth: EthernetFrame { source_mac: MacAddress([64, 112, 9, 133, 209, 167]), dest_mac: MacAddress([48, 82, 203, 107, 118, 95]), ethertype: IPv4 }
    ipv4: IPv4Header { version: 4, ihl: 20, tos: 0, length: 88, id: 41776, flags: 2, fragment_offset: 0, ttl: 57, protocol: UDP, chksum: 56659, source_addr: 209.18.47.62, dest_addr: 192.168.0.24 }
        udp: UdpHeader { source_port: 53, dest_port: 33734, length: 68, checksum: 49539 }
            dns: Response(Response { answers: [("www.google.com", AAAA(2607:f8b0:4007:80c::2004))] })
eth: EthernetFrame { source_mac: MacAddress([48, 82, 203, 107, 118, 95]), dest_mac: MacAddress([64, 112, 9, 133, 209, 167]), ethertype: IPv4 }
    ipv4: IPv4Header { version: 4, ihl: 20, tos: 0, length: 569, id: 20264, flags: 2, fragment_offset: 0, ttl: 64, protocol: TCP, chksum: 30553, source_addr: 192.168.0.24, dest_addr: 172.217.4.164 }
        tcp: TcpHeader { source_port: 46596, dest_port: 443, sequence_no: 766031290, ack_no: 3289351807, data_offset: 8, reserved: 0, flag_urg: false, flag_ack: true, flag_psh: true, flag_rst: false, flag_syn: false, flag_fin: false, window: 229, checksum: 42372, urgent_pointer: 0, options: None }
            tls: ClientHello { hostname: Some("www.google.com") }
eth: EthernetFrame { source_mac: MacAddress([48, 82, 203, 107, 118, 95]), dest_mac: MacAddress([64, 112, 9, 133, 209, 167]), ethertype: IPv4 }
    ipv4: IPv4Header { version: 4, ihl: 20, tos: 0, length: 57, id: 45378, flags: 2, fragment_offset: 0, ttl: 64, protocol: UDP, chksum: 51296, source_addr: 192.168.0.24, dest_addr: 209.18.47.62 }
        udp: UdpHeader { source_port: 48260, dest_port: 53, length: 37, checksum: 40572 }
            dns: Request(Request { questions: [(A, "badsite.com")] })
eth: EthernetFrame { source_mac: MacAddress([64, 112, 9, 133, 209, 167]), dest_mac: MacAddress([48, 82, 203, 107, 118, 95]), ethertype: IPv4 }
    ipv4: IPv4Header { version: 4, ihl: 20, tos: 0, length: 89, id: 8256, flags: 2, fragment_offset: 0, ttl: 57, protocol: UDP, chksum: 24643, source_addr: 209.18.47.62, dest_addr: 192.168.0.24 }
        udp: UdpHeader { source_port: 53, dest_port: 48260, length: 69, checksum: 26142 }
            dns: Response(Response { answers: [("badsite.com", A(104.200.23.95)), ("badsite.com", A(104.200.22.130))] })
eth: EthernetFrame { source_mac: MacAddress([48, 82, 203, 107, 118, 95]), dest_mac: MacAddress([64, 112, 9, 133, 209, 167]), ethertype: IPv4 }
    ipv4: IPv4Header { version: 4, ihl: 20, tos: 0, length: 57, id: 45384, flags: 2, fragment_offset: 0, ttl: 64, protocol: UDP, chksum: 51290, source_addr: 192.168.0.24, dest_addr: 209.18.47.62 }
        udp: UdpHeader { source_port: 57772, dest_port: 53, length: 37, checksum: 61497 }
            dns: Request(Request { questions: [(AAAA, "badsite.com")] })
eth: EthernetFrame { source_mac: MacAddress([64, 112, 9, 133, 209, 167]), dest_mac: MacAddress([48, 82, 203, 107, 118, 95]), ethertype: IPv4 }
    ipv4: IPv4Header { version: 4, ihl: 20, tos: 0, length: 125, id: 46568, flags: 2, fragment_offset: 0, ttl: 57, protocol: UDP, chksum: 51830, source_addr: 209.18.47.62, dest_addr: 192.168.0.24 }
        udp: UdpHeader { source_port: 53, dest_port: 57772, length: 105, checksum: 44123 }
            dns: Response(Response { answers: [] })
eth: EthernetFrame { source_mac: MacAddress([48, 82, 203, 107, 118, 95]), dest_mac: MacAddress([64, 112, 9, 133, 209, 167]), ethertype: IPv4 }
    ipv4: IPv4Header { version: 4, ihl: 20, tos: 0, length: 371, id: 25136, flags: 2, fragment_offset: 0, ttl: 64, protocol: TCP, chksum: 38509, source_addr: 192.168.0.24, dest_addr: 104.200.23.95 }
        tcp: TcpHeader { source_port: 43706, dest_port: 80, sequence_no: 3479674440, ack_no: 2159468974, data_offset: 8, reserved: 0, flag_urg: false, flag_ack: true, flag_psh: true, flag_rst: false, flag_syn: false, flag_fin: false, window: 229, checksum: 33053, urgent_pointer: 0, options: None }
            http: "GET http://badsite.com/ HTTP/1.1" Request { method: "GET", uri: "/", version: "1.1", host: Some("badsite.com"), agent: Some("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0"), referer: None, auth: None, cookies: None }
eth: EthernetFrame { source_mac: MacAddress([64, 112, 9, 133, 209, 167]), dest_mac: MacAddress([48, 82, 203, 107, 118, 95]), ethertype: IPv4 }
    ipv4: IPv4Header { version: 4, ihl: 20, tos: 0, length: 1040, id: 62478, flags: 2, fragment_offset: 0, ttl: 53, protocol: TCP, chksum: 3314, source_addr: 104.200.23.95, dest_addr: 192.168.0.24 }
        tcp: TcpHeader { source_port: 80, dest_port: 43706, sequence_no: 2159468974, ack_no: 3479674759, data_offset: 8, reserved: 0, flag_urg: false, flag_ack: true, flag_psh: false, flag_rst: false, flag_syn: false, flag_fin: true, window: 235, checksum: 55524, urgent_pointer: 0, options: None }
            remaining: "HTTP/1.1 302 Found\r\nServer: openresty/1.13.6.1\r\nDate: Mon, 24 Jun 2019 11:52:24 GMT\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: 0\r\nConnection: close\r\nLocation: http://www6.badsite.com/?s_token=1561377144.1272041333&kw=Best+Personal+Credit+Cards&term=Best%20Personal%20Credit%20Cards&term=Fast%20Online%20College%20Degrees&term=Job%20Posting%20Boards&term=Movie%20Media%20Server&backfill=0&tdfs=1\r\nX-Mtm-Path: 0\r\nVary: Accept-Language\r\nContent-Language: en\r\nSet-Cookie: mtm_delivered=WyJiYWRzaXRlLmNvbSIsImh0dHA6Ly93d3c2LmJhZHNpdGUuY29tLz9zX3Rva2VuPTE1NjEzNzcxNDQuMTI3MjA0MTMzMyZrdz1CZXN0K1BlcnNvbmFsK0NyZWRpdCtDYXJkcyZ0ZXJtPUJlc3QgUGVyc29uYWwgQ3JlZGl0IENhcmRzJnRlcm09RmFzdCBPbmxpbmUgQ29sbGVnZSBEZWdyZWVzJnRlcm09Sm9iIFBvc3RpbmcgQm9hcmRzJnRlcm09TW92aWUgTWVkaWEgU2VydmVyJmJhY2tmaWxsPTAmdGRmcz0xIiwxLCIyMDE5LTA2LTI0IDExOjUyOjI0IiwiMTU2MTM3NzE0NC4xMjcyMDQxMzMzIiw3NCxudWxsLG51bGxd:1hfNWK:v7-Oji2CCHg8ECfi3-6CthImT5w; expires=Mon, 24-Jun-2019 12:52:24 GMT; Max-Age=3600; Path=/\r\n\r\n"

In just a few seconds, I sniffed traffic telling me the operating system of the computer making the request, the website requested, and even the entire website sent-in response encoded in HTML. I can even see the default search engine being used to make the request.

Sniffglue Snoops on Network Traffic with Less Risk

Thanks to the sandboxing features of Sniffglue, you can learn about network activity without worrying about an exploit running as root on your system. That makes it a valuable tool for passive reconnaissance that can be run over SSH and only highlights useful information. Because Snifflglue leaves no trace of running on the network, unlike more active scanners, you can feel free to run this on any network without fear of being detected.

I hope you enjoyed this guide to securely sniffing packets! If you have any questions about this tutorial on packet sniffing or you have a comment, ask below or feel free to reach me on Twitter @KodyKinzie.

Cover image via Kody/Null Byte

Never Miss a Hacking or Security Guide

Get new Null Byte guides every week.

Be the First to Comment

Share Your Thoughts

  • Hot
  • Latest