Sunday, February 26, 2012

Solution to Codegate 2012 Net100

Challenge (with Big-Daddy team) :

Someone has leaked very important documents. We couldn't find any proof without one PCAP file. But this file was damaged.

The password of disclosure document is very weakness and based on Time, can be found easily.
Cryptographic algorithm is below.

Msg = "ThisIsNotARealEncryption!SeemToEncoding"
Key = 0x20120224 (if date format is 2012/02/24 00:01:01)
Cryto = C(M) = Msg * Key = 0xa92fd3a82cb4eb2ad323d795322c34f2d809f78

Answer: Decrypt(Msg)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Download : A0EBE9F0416498632193F769867744A3

Keywords : pcap, wireshark, zip.

First let's ensure that we understand the encryption correctly using python console :

    >>> Crypto = 0xa92fd3a82cb4eb2ad323d795322c34f2d809f78
    >>> Key = 0x20120224
    >>> Crypto / Key
    112197289306199430549845498164079773038L
    >>> hex(Crypto / Key)
    '0x5468697349734e6f74415265616c456eL'
    >>> import binascii
    >>> binascii.unhexlify('5468697349734e6f74415265616c456e')
    'ThisIsNotARealEn'

So, we need to find Crypto and Key somewhere in the attached file to recover the flag.

The file format is not known to unix 'file' utility, but we can guess is it a damaged pcap. No luck, wireshark is not able to open it either. It's time to pull out an hexadecimal viewer.

    $ file A0EBE9F0416498632193F769867744A3
    A0EBE9F0416498632193F769867744A3: data
    $ xxd A0EBE9F0416498632193F769867744A3 | head
    0000000: e48d 3b4f a485 0400 3e00 0000 3e00 0000  ..;O....>...>...
    0000010: ffff ffff ffff ffff ffff ffff 0800 4500  ..............E.
    0000020: 0030 2e87 4000 8006 c63b 0101 0101 0202  .0..@....;......
    0000030: 0202 fdf2 0050 9a11 262d 0000 0000 7002  .....P..&-....p.
    0000040: 2000 9e98 0000 0204 05b4 0101 0402 e48d   ...............
    0000050: 3b4f b88b 0400 3e00 0000 3e00 0000 ffff  ;O....>...>.....
    0000060: ffff ffff ffff ffff ffff 0800 4500 0030  ............E..0
    0000070: 0000 4000 3e06 36c3 0202 0202 0101 0101  ..@.>.6.........
    0000080: 0050 fdf2 adb5 c924 9a11 262e 7012 16d0  .P.....$..&.p...
    0000090: 30dd 0000 0204 05b4 0101 0402 e48d 3b4f  0.............;O

After comparing this file with other valid pcap in my possession, it seems that the pcap header is missing. The pcap format specification can be found here. Let's rebuild the header :

    $ perl -e 'print "\xd4\xc3\xb2\xa1"'  > header.pcap  # magic number
    $ perl -e 'print "\x02\x00"'         >> header.pcap  # major version number
    $ perl -e 'print "\x04\x00"'         >> header.pcap  # minor version number
    $ perl -e 'print "\x00\x00\x00\x00"' >> header.pcap  # GMT to local correction
    $ perl -e 'print "\x00\x00\x00\x00"' >> header.pcap  # accuracy of timestamps
    $ perl -e 'print "\xff\xff\x00\x00"' >> header.pcap  # max length of captured packets, in octets
    $ perl -e 'print "\x01\x00\x00\x00"' >> header.pcap  # data link type
    $ xxd header.pcap
    0000000: d4c3 b2a1 0200 0400 0000 0000 0000 0000  ................
    0000010: ffff 0000 0100 0000                      ........
    $ file header.pcap
    header.pcap: tcpdump capture file (little-endian) - version 2.4 (Ethernet, capture length 65535)
    $ cat header.pcap A0EBE9F0416498632193F769867744A3 > chall.pcap

Now that we have reconstructed the header, we can try to open the file in wireshark, but we get this error :

Obviously the file is still damaged and wireshark only displays the very beginning of it. If we analyse the file more closely, it appears that one packet header and some data has been removed : See here for packet header specification.

First we need to clearly identify the damaged section of the file. According to wireshark, the last correct packet is the 22nd (SYN/ACK), so we assume that the next one is corrupted. Hexdump of 22nd packet in wireshark :

    0000  ff ff ff ff ff ff ff ff  ff ff ff ff 08 00 45 00   ........ ......E.
    0010  00 30 00 00 40 00 3e 06  36 c3 02 02 02 02 01 01   .0..@.>. 6.......
    0020  01 01 00 50 fd f4 bc 3e  ec 5f e5 49 9b ca 70 12   ...P...> ._.I..p.
    0030  16 d0 3e 42 00 00 02 04  05 b4 01 01 ca bc         ..>B.... ......

We search for it (actually only a part of it is enough) in the original data file using bgrep :

    $ bgrep 16d03e420000020405b40101cabc A0EBE9F0416498632193F769867744A3
    A0EBE9F0416498632193F769867744A3: 00000d44
    $ xxd -s 0x00000d44 A0EBE9F0416498632193F769867744A3 | head
    0000d44: 16d0 3e42 0000 0204 05b4 0101 cabc 3eec  ..>B..........>.
    0000d54: 6050 18fa f062 2c00 0047 4554 202f 776f  `P...b,..GET /wo
    0000d64: 6f73 2f68 6163 6b74 6865 7061 636b 6574  os/hackthepacket
    0000d74: 2f25 4533 2538 3525 3842 2545 3325 3835  /%E3%85%8B%E3%85
    0000d84: 2538 4225 4533 2538 3525 3842 2545 3325  %8B%E3%85%8B%E3%
    0000d94: 3835 2538 4225 4533 2538 3525 3842 2545  85%8B%E3%85%8B%E
    0000da4: 3325 3835 2538 4220 4854 5450 2f31 2e31  3%85%8B HTTP/1.1
    0000db4: 0d0a 486f 7374 3a20 636f 6765 2e68 6163  ..Host: coge.hac
    0000dc4: 6b74 6865 7061 636b 6574 2e63 6f6d 0d0a  kthepacket.com..
    0000dd4: 436f 6e6e 6563 7469 6f6e 3a20 6b65 6570  Connection: keep

As we can see, the last byte of the 22nd packet is located at 0xd51, while the HTTP GET begins at 0xd5d, which means that the 23rd pcap packet header, the Ethernet, IP and TCP headers are missing. What is left of it is this weird chunk of data (that looks like TCP) :

    0000d44:                                    3eec              ..>.
    0000d54: 6050 18fa f062 2c00 00                   `P...b,..

Now we have 2 choices, either we can reconstruct the missing part, or we can simply drop this packet. I will go for the second one ;)

During the CTF, I simply truncated the whole first part of the file since it only contains a few http requests and responses that are not necessary to solve the challenge. But it's much more refined just to isolate the damaged packet ;)

The end of damaged packet (HTTP GET) can be found easily with xxd :

    $ xxd -s 0x00000f00 A0EBE9F0416498632193F769867744A3 | head
    0000f00: 3d30 2e34 0d0a 4163 6365 7074 2d43 6861  =0.4..Accept-Cha
    0000f10: 7273 6574 3a20 7769 6e64 6f77 732d 3934  rset: windows-94
    0000f20: 392c 7574 662d 383b 713d 302e 372c 2a3b  9,utf-8;q=0.7,*;
    0000f30: 713d 302e 330d 0a0d 0af4 8d3b 4f30 a200  q=0.3......;O0..
    0000f40: 003c 0000 003c 0000 00ff ffff ffff ffff  .<...<..........
    0000f50: ffff ffff ff08 0045 0000 286f 9740 003e  .......E..(o.@.>
    0000f60: 06c7 3302 0202 0201 0101 0100 50fd f4bc  ..3.........P...

[0x..., 0xf38] : HTTP GET
[0xf39, 0xf48] : Pcap packet header.
At 0xf49 : Beginning of Ethernet frame, 0xffff... being the broadcast MAC address.
We need to get rid of [0xd52, 0xf38] which is invalid.

The following python script will do the whole thing for us :

    #! /usr/bin/env python2

    f = open('A0EBE9F0416498632193F769867744A3')
    o = open('chall.pcap', 'w')
    content = f.read()

    # Fix pcap header
    o.write('\xd4\xc3\xb2\xa1\x02\x00\x04\x00')
    o.write('\x00\x00\x00\x00\x00\x00\x00\x00')
    o.write('\xff\xff\x00\x00\x01\x00\x00\x00')

    # Get the first part
    o.write(content[:0xd51+1])
    # Get the end of file
    o.write(content[0xf38+1:])

    o.close()
    f.close()

From now on, chall.pcap opens nicely is wireshark. We notice two things. Firstly, the server date is weird in the last HTTP OK response, but we remember that the password is based on time.

    HTTP/1.1 200 OK
    Date: Wed, 28 Nov 1984 10:50:28 GMT
    Server: Apache/2.2.15 (CentOS)
    Last-Modified: Wed, 28 Nov 1984 10:49:55 GMT

We now have Key = 0x19841128.

Secondly, a huge amount of data is transfered. At first glance it is a large file, probably an archive since we can see the name of 3 files inside it : 1984-was-not-supposed-to-be-an-instruction-manual2-1.jpg, George_Orwell.jpg, et key !! We definitely need to extract this file.
Wireshark -> Export selected packet bytes...

As suggested by a teammate, the multiple 'PK' strings in the file make us thing of ZIP file format. Basically, a ZIP file is constituted of one header beginning with 0x04034b50, where 0x50 and 0x4b translate to 'PK' into ascii, and one footer beginning with 0x06054b50.

    $ file file.zip
    file.zip: data
    $ unzip file.zip
    Archive:  file.zip
      End-of-central-directory signature not found.  Either this file is not
      a zipfile, or it constitutes one disk of a multi-part archive.  In the
      latter case the central directory and zipfile comment will be found on
      the last disk(s) of this archive.
    unzip:  cannot find zipfile directory in one of file.zip or
            file.zip.zip, and cannot find file.zip.ZIP, period.

But again, the zip file is corrupted somehow. At that time, we tried to extract all possible chunks beginning with 'PK', but they were all corrupted. I eventually realized that the beginning of the file is not so different from a valid ZIP header, because it contains \x03\x04, except that the two first bytes \x50\x4b are missing.
Let's restore those two bytes :

    $ (echo -n 'PK';cat file.zip) > file_pk.zip
    $ file file_pk.zip
    file_pk.zip: Zip archive data, at least v2.0 to extract

But again, the same error message when trying to unzip it. The clue is to look at the footer too :

    $ xxd file_pk.zip | tail
    0030ad0: 7765 6c6c 2e6a 7067 0a00 2000 0000 0000  well.jpg.. .....
    0030ae0: 0100 1800 86e3 212f cfeb cc01 c4b2 c330  ......!/.......0
    0030af0: cfeb cc01 8d0c b530 cfeb cc01 504b 0102  .......0....PK..
    0030b00: 3f00 1400 0100 0000 389d 4f40 cf06 cb9c  ?.......8.O@....
    0030b10: 3100 0000 2500 0000 0300 2400 0000 0000  1...%.....$.....
    0030b20: 0000 2000 0000 bd09 0300 6b65 790a 0020  .. .......key.. 
    0030b30: 0000 0000 0001 0018 0037 620d 6bce ebcc  .........7b.k...
    0030b40: 01f1 0bcf 2dcc ebcc 01d6 b8c7 2dcc ebcc  ....-.......-...
    0030b50: 0150 5b05 0600 0000 0003 0003 0042 0100  .P[..........B..
    0030b60: 000f 0a03 0000 00                        .......

We notice that the End-of-central-directory signature (normally 0x06054b50) has been replaced by 0x06055b50 (at offset 0x30b51). We replace the wrong byte with an hexadecimal editor such as hexedit. Then we can unzip the file using the date 19841128 as password.

    $ unzip file_pk.zip
    Archive:  file_pk.zip
    [file_pk.zip] 1984-was-not-supposed-to-be-an-instruction-manual2-1.jpg password:
      inflating: 1984-was-not-supposed-to-be-an-instruction-manual2-1.jpg
      inflating: George_Orwell.jpg
     extracting: key
    $ cat key
    be7790a9f6e79752d1f9e55a79a33f421cf68

Aha, we are close ! Using the notations of the chall, we've just found Crypto. Some python will do the rest :

    >>> hex(0xbe7790a9f6e79752d1f9e55a79a33f421cf68 / 0x19841128)
    '0x776f30306f735230634b696e473a29L'
    >>> import binascii
    >>> binascii.unhexlify('776f30306f735230634b696e473a29')
    'wo00osR0cKinG:)'

We have the flag, and 100pts !

posted by po.