picoCTF 2022 Write-up: TorrentAnalyze

This includes my standalone write-up for the forensics challenge ‘TorrentAnalyze’ from picoCTF 2022 as it was something I never looked into and was an interesting challenge for network forensics!


We’re provided with a .pcap file.
We can notice some DNS standard queries being made to server domains like ipv6.torrent.ubuntu.com & torrent.ubuntu.com

These standard queries are made to get the IPs corresponding to aforementioned FQDNs.

We can see the request and response packets for these standard queries by filtering on the host IP address, in this case, We’ll see later how we know the host IP address.

Since we are dealing with some kind of P2P torrent protocol, we can search and enable them in Wireshark to get all the data templates.

Make sure to enable bittorrent_dht_udp and bt_utp_udp, under Analyze > Enabled Protocols.

I’m putting some good links in the reference section which explains how BitTorrent protocol works. Dive into that to fully understand our network traffic here. To cover it shortly, whenever a user begins downloading files via any P2P protocols such as BitTorrent, the user joins the torrent swarm first and now becomes a ‘peer’. As P2P is decentralized, normally every peer not only downloads pieces of files but uploads the requested pieces for other peers in the torrent swarm. A swarm is said to be healthy when there are more seeders than leechers. They are exactly how they sound, seeders are those who have upload ratio > 1 and leechers are those with their upload ratio < 1.

If we observe the PCAP file, we can see one IP address stand out from others,, as it appears in both ‘Source’ and ‘Destination’ columns. Other IP addresses are either seeders for our host or leechers.

Sorting by protocol, let’s examine packets with the BT-DHT protocol. Before we dive in, note that the contents of the packets are all bencoded (binary encoded), which is an encoding exclusively used by BitTorrent in it’s P2P file sharing system.

Notice how every packet where above IP is the Source, mentions additional 8 nodes. These nodes are the leechers for the peer that was our host.
And packets where above IP is the Destination, either has request type set to find_node, get_peers, announce_peer or ping.

This is also mentioned in the DHT protocol specification, here.

Now, remember we can not find the files downloaded from the torrent file in the packet capture unless the packets were captured for the entire duration of downloading. But, we can still find the torrent file’s meta data as the torrent file must have been downloaded first unless a magnet link was used.

The interesting field here is info_hash which is a 20 byte SHA-1 hash binary encoded.

From the official BitTorrent Protocol Specification, here.
Here, we can see the info_hash field of one packet.

To extract all the hashes, I used tshark to first extract the entire bencoded string, and processed the hashes separately in a list.

I used the filter frame contains info_hash, not only to get the hashes for the torrent metadata but also to get those packets with their request type set to either get_peers or announce_peer, as these two are the only ones to query the info_hash field. In other words, we’re filtering those packets which tells us something about the state of the torrent, as explained later in this post.

Curate a hash list with clean newlines, to pass to grep later.

Now, we can simply lookup the hash or perform a search against a torrent database.

During the event, I Googled one of the hashes at random and luckily found a match which was the flag too.

But let us use a database and properly return all the metadata for all the hashes in our hash list.

I found this amazing database, shout out to the owner torrentdb!
We get 3 hits for valid hashes. I tried to lookup the other 5 hashes but was unable to find anything. I speculate the reason to be deleted trackers or the torrent file itself.

The typical flow for a node to enter the torrent swarm works similar to the TCP handshake: A node sends get_peers query to other nodes in the swarm. Other nodes in the swarm respond to this query with a token value. Now, to acknowledge the token, the node sends announce_peer query as it joins the torrent swarm, and begins downloading and uploading pieces of the files.

If we take a look at the 3 packets that these hashes came from, we can see that only the first torrent, Zoo (2017) 720p WEB-DL x264 ESubs - MkvHub.Com, had the request type announce_peer meaning that the host’s node had successfully joined the torrent swarm. We see no other packets corresponding to that hash. I’m not sure if that’s enough evidence to speculate that the torrent was immediately paused/stopped/deleted after adding it to the host’s torrent client. Other two has the request type get_peers indicating that they were waiting for other nodes in the swarm to send the response to their get_peers queries for joining the swarm. So, those two torrents were just added to the host’s torrent client and had not yet been a part of the swarm.

Putting this in a real case scenario, countries which practice strict laws against piracy could take legal action against the host owner. Most countries doesn’t allow file distribution for copyrighted media. The act of torrenting itself isn’t illegal however. It is just a P2P file sharing system. Read more here.

We can view the bencoded dictionaries of any torrent file on this awesome Project Nayuki! I downloaded the official (and legal) ubuntu torrent file found from the Google search earlier, to take a closer look at the dictionaries.

It seems like the info dictionary also contains SHA-1 hashes for every piece the torrent file will download. This is to verify the integrity of all the pieces before stitching them together to get the original file.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store