Home

Awesome

pcapFS – Mounting Network Data

pcapFS is a FUSE module allowing it to mount captured network data as a virtual file system. This makes it especially convenient to analyze the payload (and to some extend the metadata) of your captured network traffic.

While there are already several tools out there which are able to extract data from your PCAPs, pcapFS has some features that make it different from these tools—most notably:

Instead of extracting the payload (i.e. copying the data to disk), pcapFS provides direct access into the PCAP/PCAPNG files. To speed the access up, an index is created when a PCAP is mounted for the first time. This takes almost the same time as opening a PCAP with Wireshark. After the index is created, we can use it for all further operations. Moreover, the index can be used to mount the PCAP any time later making the data available almost instantly.

Protocols and Decoders

In pcapFS each protocol and decoder is implemented as a virtual file. These virtual files store references into other virtual files or directly into the PCAP/PCAPNG file, which are used to read their data. Currently the following protocols and decoders are supported:

Getting pcapFS

We do not provide any precompiled packages yet. This is mainly because some dependencies of pcapFS are also not available as packages in most of the Linux distribution around. So, for the moment you have to build pcapFS from source.

Building pcapFS works best on a rather modern Linux distribution. See the section below for further details.

Building pcapFS

As already mentioned, there are some dependencies which are not packaged for most Linux distributions. Moreover, you need a reasonably modern C++ compiler supporting at least C++14. Depending on your Linux distribution there are different steps required to get all dependencies of pcapFS. Have a look at the scripts here.

Afterwards you can build pcapFS like:

$ mkdir build
$ cd build
$ cmake ..
$ make

Using pcapFS

Mounting Network Data

The general way to mount a network capture looks like this:

$ pcapfs [options] <pcap> <mountpoint>

So, just mounting a single PCAP is as simple as:

$ pcapfs /path/to/some/test.pcap /mount/point

To unmount a previously mounted network capture use fusermount3 with the -u switch:

$ fusermount3 -u /mount/point

Since the example above did not specify any index file, pcapFS automatically creates an index file for you. This file will be in the current working directory and will be named something like 20181130-125450_pcapfs.index (the first component is the date when the index was created, the second the time, and the last one is just a fixed string). You can use this index if you want to mount the PCAP again using the -i or --index switches:

$ pcapfs -i 20181130-125450_pcapfs.index /path/to/some/pcap /mount/point

If you provide a path to a non-existing index file on the command line, an index with this name will be created for you.

If you don't want your index to be written to disk, use the -m or --in-memory options. This skips the writing of the index which, of course, means that the index has to be rebuilt the next time you want to mount the PCAP.

Mounting Multiple/Split PCAPs

pcapFS lets you mount multiple PCAP/PCAPNG files at the same time. The mount point will contain the payload of all PCAPs as if only one PCAP would have been mounted. It makes no difference if the PCAPs you mount are completely unrelated or if you are providing a very long network capture split into several PCAPs. Note that conversations spanning over two or more PCAPs are entirely supported by pcapFS, i.e. no prior merging of PCAPs is required in order to extract your long lasting download from multiple PCAPs!

For this purpose, you can specify a directory instead of a regular PCAP file:

$ pcapfs /path/to/some/pcaps/ /mount/point

In the example above pcapFS would try to mount all regular files contained in the /path/to/some/pcaps folder. If you want to limit the files to be mounted, you can provide a file name suffix to only include files ending with this suffix, e.g.

$ pcapfs --pcap-suffix=.pcap /path/to/some/pcaps/ /mount/point

This would tell pcapFS to only mount files ending with .pcap from the directory /path/to/some/pcaps.

Sorting the Virtual Directory Hierarchy

If nothing else is specified, pcapFS will create a directory structure looking something like this:

$ pcapfs /path/to/some/test.pcap /mnt/point
$ tree -r -L 1 /mnt/point
/mnt/point/
├── udp
├── tcp
├── tls
├── http
├── ftp
└── dns

6 directories, 0 files

That is, the first directory level contains the protocols detected and parsed by pcapFS. Within these directories you will find the payload of the corresponding conversations as files.

$ tree -r -L 2 /mnt/point/ | grep -A 3 -E ' (udp|tcp|tls|http|dns)'
├── udp
│   ├── 0-9_UDPFILE3
│   ├── 0-99816_UDPFILE1522
│   ├── 0-99773_UDPFILE1521
--
├── tcp
│   ├── 0-99886_tcp3927
│   ├── 0-9977_tcp687
│   ├── 0-99112_tcp3922
--
├── tls
│   ├── 9997-656_TLS
│   ├── 999-5_TLS
│   ├── 9984-3081_TLS
--
├── http
│   ├── 998-811
│   ├── 9986-93333_icons-16x16.png
│   ├── 9986-81178_header-desk-logo.png
--
└── dns
    ├── 998-0_RES-18314
    ├── 997-0_REQ-18314
    ├── 99-0_RES-63051

pcapFS is, however, not limited to this directory layout. Instead, it lets you choose the layout that is most suitable for your current analysis. For instance, assume that you are interested in the ports a particular host has send packets to. In this case you could call pcapFS like this:

$ pcapfs --sortby=/srcIP/dstPort/dstIP /path/to/some/test.pcap /mount/point

After that your directory hierarchy should look like the following:

$ tree -rd -L 3 /mnt/point/
/mnt/point/
...
├── 172.16.139.241
│   └── 53
│       └── 172.16.128.202
├── 172.16.133.99
│   ├── 8200
│   │   └── 67.217.88.86
│   ├── 5500
│   │   └── 172.16.139.250
│   ├── 443
│   │   ├── 96.43.146.48
│   │   ├── 96.43.146.22
│   │   ├── 96.43.146.176
│   │   ├── 64.74.80.70
│   │   ├── 64.74.80.15
│   │   ├── 216.219.115.54
│   │   ├── 216.219.115.17
│   │   ├── 216.115.217.144
│   │   ├── 216.115.216.44
│   │   ├── 216.115.209.97
│   │   ├── 216.115.208.199
│   │   ├── 173.194.43.3
│   │   └── 157.56.240.102
│   ├── 1900
│   │   └── 239.255.255.250
│   ├── 1853
│   │   └── 67.217.78.32
│   ├── 138
│   │   └── 172.16.133.255
│   └── 137
│       └── 172.16.133.255
├── 172.16.133.97
│   ├── 8014
│   │   └── 172.16.128.169
│   ├── 5500
│   │   └── 172.16.139.250
│   ├── 5462
│   │   └── 172.16.139.250
│   ├── 5447
│   │   └── 172.16.139.250
│   ├── 443
│   │   ├── 96.43.146.22
│   │   ├── 96.43.146.176
│   │   └── 157.56.240.102
│   ├── 1900
...

The --sortby argument used above defines the layout of the virtual directory hierarchy created for you. pcapFS provides what we call properties for this. The following table lists the properties which are currently available along with the protocol they origin from:

PropertyProtocolDescription
protocoln/aA protocol implemented in pcapFS
srcIPipSource IP address
dstIPipDestination IP address
srcPorttcp, udpSource port
dstPorttcp, udpDestination port
domainhttp, tlsThe domain parsed from the HTTP Host header and SNI
urihttpThe requested URI parsed from the HTTP request
ja3tls (http)MD5 hash of JA3 fingerprint
ja3stls (http)MD5 hash of JA3S fingerprint
ja4tls (http)JA4 fingerprint
ja4stls (http)JA4S fingerprint
ja4xtls (http)JA4X fingerprint
ja4hhttpJA4H fingerprint
hasshsshhassh fingerprint of SSH connection
hasshServersshhasshServer fingerprint of SSH connection

A protocol implemented in pcapFS can define its own properties based on values it parsed. Therefore, as more and more protocols are added to pcapFS, you will have very fine grained possibilities to build your directory hierarchy.

Note that the current implementation does not check whether a property you specified actually exists. That is, you could also provide the following sortby argument:

$ pcapfs --sortby=/foo/protocol/domain/path /path/to/some/test.pcap /mount/point
/mount/point
└── PCAPFS_PROP_NOT_AVAIL
    ├── tcp
    │   └── PCAPFS_PROP_NOT_AVAIL
    │       ├── 0-139_tcp10
    │       └── 0-131_tcp9
    ├── tls
    │   └── PCAPFS_PROP_NOT_AVAIL
    │       └── 0-1838_TLS
    └── http
        └── server.test
            ├── image
            │   ├── 8-308_png
            │   └── 7-311_jpeg
            ├── 6-309_json
            ├── 5-333_gzip
            ├── 4-339_deflate
            ├── 3-318_html
            ├── 2-312_headers
            └── 1-306_ip

8 directories, 11 files

As you can see, the foo component lead to the creation of the PCAPFS_PROP_NOT_AVAIL folder containing the directories for the protocols. There are additional PCAPFS_PROP_NOT_AVAIL folders in tcp and tls. This is because the parsers for TCP and TLS do not provide the domain and path properties. The HTTP parser on the other hand provides these properties leading to the server.test and image subdirectories.

Showing Metadata Files with --show-metadata

When you pass the option --show-metadata to pcapFS, additional files with useful metadata information are created. Depending on the protocol, different information is extracted for metadata files:

Decrypting and Decoding Traffic

It is possible for pcapFS to decrypt and decode certain protocols on the fly if you provide it with the corresponding key material. Right now, we have prototypical support for TLS, Cobalt Strike and XOR. For decryption, these protocols need a key file containing the key material which can be provided via the command line (-k or --keys) or via the configuration file. For TLS key files, pcapFS also supports decryption when the key material is already embedded in the corresponding PCAPNG file (for further reference see here). When providing the key material via the command line, the argument can be a single file or a directory containing multiple key files. For TLS decrpytion, supported key file formats are the same as for Wireshark:

Example key files can be found in the tests folder. Currently supported cipher suites are:

IDCipher SuiteIDCipher Suite
0x0004TLS_RSA_WITH_RC4_128_MD50x009DTLS_RSA_WITH_AES_256_GCM_SHA384
0x0005TLS_RSA_WITH_RC4_128_SHA0x009ETLS_DHE_RSA_WITH_AES_128_GCM_SHA256
0x0018TLS_DH_anon_WITH_RC4_128_MD50x009FTLS_DHE_RSA_WITH_AES_256_GCM_SHA384
0x002FTLS_RSA_WITH_AES_128_CBC_SHA0x00A6TLS_DH_anon_WITH_AES_128_GCM_SHA256
0x0033TLS_DHE_RSA_WITH_AES_128_CBC_SHA0x00A7TLS_DH_anon_WITH_AES_256_GCM_SHA384
0x0034TLS_DH_anon_WITH_AES_128_CBC_SHA0xC011TLS_ECDHE_RSA_WITH_RC4_128_SHA
0x0035TLS_RSA_WITH_AES_256_CBC_SHA0xC013TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
0x0039TLS_DHE_RSA_WITH_AES_256_CBC_SHA0xC014TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
0x003ATLS_DH_anon_WITH_AES_256_CBC_SHA0xC016TLS_ECDH_anon_WITH_RC4_128_SHA
0x003CTLS_RSA_WITH_AES_128_CBC_SHA2560xC018TLS_ECDH_anon_WITH_AES_128_CBC_SHA
0x003DTLS_RSA_WITH_AES_256_CBC_SHA2560xC019TLS_ECDH_anon_WITH_AES_256_CBC_SHA
0x0067TLS_DHE_RSA_WITH_AES_128_CBC_SHA2560xC027TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
0x006BTLS_DHE_RSA_WITH_AES_256_CBC_SHA2560xC028TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
0x006CTLS_DH_anon_WITH_AES_128_CBC_SHA2560xC02FTLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
0x006DTLS_DH_anon_WITH_AES_256_CBC_SHA2560xC030TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
0x009CTLS_RSA_WITH_AES_128_GCM_SHA256

Decrypting Cobalt Strike C2 Traffic

PcapFS supports prototypical decryption of Cobalt Strike C2 traffic as long as the Cobalt Strike default profile is used. In order to successfully decrypt the C2 traffic, the team server's private RSA key is required which has to be passed in PEM format as a key file via the command line (-k or --keys) or via the configuration file. The Cobalt Strike functionality of pcapFS includes decryption of server commands and the respective answers from beacons as well as extraction of transferred files.

The team server's private RSA key may be known when a cracked Cobalt Strike version is used. How the private key can be extracted in that case, is explained in a blog post by Didier Stevens. You can exemplarily test the decryption and parsing capabilities of pcapFS with the pcap file referenced in this post by Malware Traffic Analysis.

With the command line option --no-cs set, pcapFS does not try to decrypt Cobalt Strike traffic which may improve the overall performance.

Reconstruction of the Server-Side Directory Hierarchy for FTP and SMB2

When analyzing a capture file that contains FTP or SMB2 traffic, pcapFS attempts to reconstruct the directory hierarchy of the corresponding FTP or SMB2 server including all files as far as possible. For this, pcapFS follows per connection the current working directory and parses all messages which indicate which files are located there.

For FTP traffic, the reconstructed directory hierarchy only includes downloaded files and empty files whose metadata is extracted from MLSD files.

For SMB2 traffic, more information can be extracted, enabling a more detailed directory reconstruction. Files accessed directly via SMB2 Read/Write messages are populated with the corresponding file content that is read or written. Additionally, during the handling of SMB2 Read/Write messages, different file versions are created (indicated by the file name tag @<file version number>) each time the content changes. All other files, which are known to exist only from context, are created as empty files with the extracted metadata set. To also display these empty files, the --show-metadata option must be enabled.

Configuration File

pcapFS uses TOML as the format for its configuration file. A sample config file looks like this:

[general]
  sortby = "/dstIP/dstPort/srcIP"

[keys]
  keyfiles = [
    "/path/to/some/key.file",
    "relative/path/to/other/key.file",
  ]


[[decode.xor.properties]]
  srcIP = "1.2.3.4"
  dstIP = "4.3.2.1"
  dstPort = 2345
  keyfile = "/path/to/some/xor1.key"

[[decode.xor.properties]]
  srcPort = 1111
  dstPort = 2222
  protocol = "udp"
  keyfile = "relative/path/to/some/xor2.key"

[[decode.tls.properties]]
  srcIP = "1.2.3.4"
  srcPort = 8080

[[decode.cobaltstrike.properties]]
  dstIP = "5.6.7.8"
  srcIP = "8.7.6.5"
  dstPort = 8080

The [general] section allows setting the sortby option described above.

The [keys] section allows you to define a list of paths to key files. Note that relative paths are interpreted as relative to the config file. Just as with the -k command line option, you are free to use files or directories here.

The [decode] section can be used to provide custom protocol parsing and decoding rules. That is, you can tell pcapFS which parser to use for connections meeting given criteria. The example config above defines four rules, two for XOR decoding, one for TLS and one for Cobalt Strike. As the properties key implies, you can use pcapFS properties to define your decoding rules. In case of the TLS example above, all connections from source IP 1.2.3.4 and source port 8080 would be parsed with the TLS protocol parser. For XOR we defined two rules both stating that connection meeting the criteria should be parsed with the XOR parser: all connections from source IP 1.2.3.4 to destination IP 4.3.2.1 and destination port 2345 should be decrypted using the key file xor1.key and all UDP streams from source port 1111 to destination port 2222 should be decrypted using xor2.key. Notice that for XOR the keyfile property is mandatory in order to match the connection to be decoded.

Providing properties in the decode section can improve the runtime of pcapFS since only connections which meet the given criteria are decoded. If no decoding properties or no configuration file is provided, all TLS and Cobalt Strike traffic is tried to be decrypted using the keyfiles passed to pcapFS.

Note that decoding options are independent from an implemented protocol detection. E.g. you can specify a certain port for HTTP decoding, but the HTTP parser still checks if the transferred data over this port is valid HTTP.