For this challenge we are given a packet capture in .PCAP format, this should be an indication that we are going to be doing some packet analysis and likely file carving in order to continue on. At first glance we can quickly identify the HTTP2 protocol being used, which should be no surprise since the name of this challenge is HTTP2. Before we begin, read a quick blurb on HTTP2. This is a great resource that provides just enough detail that can help us succeed in solving this challenge: https://www.gitbook.com/book/bagder/http2-explained/details

After reading through the basics of HTTP2, we don’t need to explain much more detail on the specific protocol…let’s solve the challenge!

First things first, we start looking at the HTTP2 traffic and can see some data being transferred via DATA and also some PUSH_PROMISE frames. These are important because DATA frames contain actual data that is going to be important in almost any scenario and PUSH_PROMISE frames inform the endpoint of any streams that the sender intends to initiate transfer of.

Just by analyzing frame #8 (as seen above), we are able to identify four different HEADERS within this frame, each with StreamID’s, there is also a chunk of data. The StreamID’s are important to remember, here we have 2, 4, 6, and 13. Based on what we read previously and our knowledge of HTTP2, we have a good idea that in the subsequent frames within this PCAP we are going to find some data being transferred in these streams. Each of these StreamID’s can be thought of almost as an identifier for a particular data stream that we should be able to identify within this PCAP.

Looking back at the previous items we identified, the PUSH_PROMISE’s each contain a file path in the Header field, each PUSH_PROMISE contains a different path and from first glance these appear to be names of files that are in the directory /files/encrypted_execs.

The three different paths are as follows:

  • /files/encrypted_execs/Iilll11Ti1lllIIl

  • /files/encrypted_execs/iilililli1ll1llI

  • /files/encrypted_execs/iiLLlIll1ll1l1IIIl1l111I

The Header fields for each different StreamID contain a content length, these are as follows:

  • StreamID #2 – Length: 3811624

  • StreamID #4 – Length: 3811704

  • StreamID #6 – Length: 3814728

Lastly, this particular frame also contains a DATA stream with StreamID

13. If we open that stream and look at the actual data being

transferred, we see:

Anyone familiar with ELF binary analysis should be familiar with those first few hexadecimal bytes in the Data field. 0x7F454c46 is the ELF file header and in ascii it reads as .ELF. We found an executable file! This is a win, now all we have to do is make sure we get the entire file carved out correctly. Based on our knowledge of HTTP2, we know it’s imperative that we find all the DATA streams that contain StreamID #13 and concatenate the data together into one file in order to successfully carve out this file. Wireshark allows us to enter filters and the one I am using to get all of these data segments is http2.streamid==13. This should filter out all the frames that contain anything related to StreamID #13.

By right-clicking on the Data field and selecting “Show packet bytes…” we can select ‘Raw’ as the encoding type and view the raw bytes as seen below:

If we continue to do this for all of the frames which contain Data for StreamID #13 we are able to successfully carve out the ELF executable that is being transferred via HTTP2 in this stream. The file we end up with is:

FileName: index.html

FileSize: 3840704 bytes

SHA-256: 8F014641406F66F050D8C373147B82FC9B437C40DBC2DB6D61C0002E0B6C2E16

Now that we’ve got the first file carved, lets look back at the other streams we identified in the aforementioned PUSH_PROMISE’s, StreamID’s 2,4, and 6. Starting with StreamID #2 we look at the Data field and see that the ELF header isn’t present here like it was in the first file. This really shouldn’t be much of a surprise, since we identified that these streams were all initiated with file names/paths like “/files/encrypted_execs/Iilll11Ti1lllIIl”. If these files are all encrypted executables, then they likely will have no discernable file traits, our only hope is to carve out every data stream related to each of these StreamID’s and make sure the lengths match up with those identified previously.

After carving out the data streams for StreamID’s #2, #4, and #6, we end up with the following files:

FileName: Iilll11Ti1lllIIl

FileSize: 3811624 bytes

SHA-256: 55E1BE27EE2AC42DADF4A419C649F1AEDEC0AB42271BA4209E32303C83DF1F03

FileName: iilililli1ll1llI

FileSize: 3811704 bytes

SHA-256: 280DB3CB9CC0C4759A07DF62E32F4ECD1AA074B56627801EA17BF04DAF33718F

FileName: iiLLlIll1ll1l1IIIl1l111I

FileSize: 3814728 bytes

SHA-256: D7C44613D3D6919ED0F024FC6B7BB407FB6701EF6902DE0C2E1C020C5364005E

After finally carving all of these files out and getting matching file sizes from the sizes we initially found in the first PUSH_PROMISE’s in frame #8, we are on to trying to make sense of all these files. The only file we have that looks promising so far is the first file from StreamID #13, index.html. This file appears to be an ELF and after attempting to execute it with little to no results it’s time to do a little static analysis and see what we can figure out. By looking at the strings we can see it has some characteristics of a compiled Python script, likely created with PyInstaller, we also see numerous references to AES and Python crypto libraries. Open it up in our favorite disassembler and start taking a look.

Based on previous experience and the types of files that we have at this time, I’m going to assume that the crypto references in this executable are there because it’s going to decrypt the other files we carved out previously. This is especially evident since the files names are actually transmitted from the path “encrypted_execs”. At this point I decide to feed the executable some values along with the names of the files carved out, it appears that the underlying Python script is actually decryptor.py and that I am on the right track.

Since my input resulted in the word “test” giving me an error related to “decrypt_file” in the script, it is safe to assume that this actually needs to be the filename. In any case, I feed the filename twice to continue testing…it appears this was a good move.

After using the filenames as both argument 1 and 2, it appears that I have gotten some decrypted output. Running the “file” command on these output files shows that they are indeed ELF executables, YAY.

Now, let’s run them and see what we’ve got!

The first one appears to be some ASCII art, which I’m going to skip over because I want to know what the others are. The second file just tells me the current time and the third file gives me the key. Winning!

PAN{http2_should_have_been_named_tcpv6!!}