|
| 1 | +--- |
| 2 | +title: "0x41414141 CTF - 0x414141" |
| 3 | +author: "Lyell Read" |
| 4 | +date: 2021-02-02T00:00:00-07:00 |
| 5 | +categories: ['Writeups'] |
| 6 | +tags: ['0x41414141 ctf'] |
| 7 | +caption: "0x41414141 CTF logo" |
| 8 | + |
| 9 | +draft: false |
| 10 | +--- |
| 11 | + |
| 12 | +## Prompt |
| 13 | + |
| 14 | +I think offshift promised to opensource some of their code |
| 15 | + |
| 16 | +author: notforsale |
| 17 | + |
| 18 | +## Solution |
| 19 | + |
| 20 | +First off, we navigate to the [offshift-dev](https://github.com/offshift-dev/assets/commits/master) github account, linked from the offshift site. Unfortunately, nothing there. Searching google for “offshift github” brings us to a different github with a [single suspicious repository](https://github.com/offshift-protocol/promo). This has two commits, one where files are uploaded, and one in which the \__pycache__ folder is deleted. That folder sounds interesting, so we clone the repository, and checkout the commit where the files were added: |
| 21 | + |
| 22 | +``` |
| 23 | +git clone git@github.com:offshift-protocol/promo.git |
| 24 | +cd promo |
| 25 | +git checkout dc43c1ac33f767a7d30dbeab123a1c87566e885d |
| 26 | +cd __pycache__ |
| 27 | +``` |
| 28 | + |
| 29 | +There, we see one `.pyc` file, which is very likely where the interesting part of this challenge is. To understand it, we use uncompyle6: |
| 30 | + |
| 31 | +``` |
| 32 | +pip3 install uncompyle6 --user |
| 33 | +uncompyle6 script.cpython-38.pyc > ../../uncompyled.py |
| 34 | +``` |
| 35 | + |
| 36 | +Now, upon reviewing that file, we see that we have some interesting cipher of sorts that uses XOR and base64 somehow: |
| 37 | + |
| 38 | +``` |
| 39 | +import base64 |
| 40 | +secret = 'https://google.com' |
| 41 | +cipher2 = [b'NDE=', b'NTM=', b'NTM=', b'NDk=', b'NTA=', b'MTIz', b'MTEw', b'MTEw', b'MzI=', b'NTE=', b'MzQ=', b'NDE=', b'NDA=', b'NTU=', b'MzY=', b'MTEx', b'NDA=', b'NTA=', b'MTEw', b'NDY=', b'MTI=', b'NDU=', b'MTE2', b'MTIw'] |
| 42 | +cipher1 = [base64.b64encode(str(ord(i) ^ 65).encode()) for i in secret] |
| 43 | +``` |
| 44 | + |
| 45 | +From a little deduction, we can guess that the creation of `cipher1` based on `secret` is how the list `cipher2` was developed. Therefore, to decipher that array, we simply need to reverse the list comprehension that generates `cipher1`. |
| 46 | + |
| 47 | +Working from the outside to the inside (to reverse the operations done during enciphering), we will need to first base64 decode each element. Then, we will have to cast it to an int (the output of `ord()`), and then use `chr()` to undo the `ord()` operation. Lastly we must undo the XOR with 65, which can be done by simply XORing it again. This can all be accomplished as so: |
| 48 | + |
| 49 | +``` |
| 50 | +print(''.join([chr(int(base64.b64decode(x)) ^ 65) for x in cipher2])) |
| 51 | +``` |
| 52 | + |
| 53 | +From that, we get a URL: [https://archive.is/oMl59](https://archive.is/oMl59). That archive is a post on 4chan’s /x/ board where the original poster included a link to a [mega.nz file download](https://mega.nz/file/AAdDyIoB#gpj5s9N9-VnbNhSdkJ24Yyq3BWSYimoxanP-p03gQWs). This downloads what appears to be a corrupt “PDF” [file called smashing.pdf], which `file` identifies as “data”, indicating that there are no identifiable magic bytes. |
| 54 | + |
| 55 | +> NOTE: At this point, inference is made that this PDF is encrypted with a repeating key that makes use of the magic bytes to reverse. |
| 56 | +
|
| 57 | +From Wikipedia, we can see that a PDF file should start with `25 50 44 46 2d`, so we perform an XOR to determine what the key that was used to encrypt this PDF was. |
| 58 | + |
| 59 | +``` |
| 60 | + 25 50 44 46 2d -- PDF Magic Bytes |
| 61 | +^ 64 11 05 07 6c -- Start of smashing.pdf |
| 62 | +---------------- |
| 63 | += 41 41 41 41 41 -- key used to encrypt |
| 64 | +``` |
| 65 | + |
| 66 | +I would not expect anything less. Therefore, we need to decrypt the whole PDF using this key, and for that, we can use a python script like this one: |
| 67 | + |
| 68 | +``` |
| 69 | +with open("smashing.pdf", "rb") as f: |
| 70 | + contents = f.read() |
| 71 | +
|
| 72 | +key = b"\x41\x41\x41\x41" |
| 73 | +out = b"" |
| 74 | +for i in range(len(contents)): |
| 75 | + out += bytes([contents[i] ^ key[i % len(key)]]) |
| 76 | +
|
| 77 | +with open("done_xor.pdf", "wb") as f: |
| 78 | + f.write(out) |
| 79 | +``` |
| 80 | + |
| 81 | +``` |
| 82 | +file done_xor.pdf |
| 83 | +done_xor.pdf: PDF document, version 1.4 |
| 84 | +``` |
| 85 | + |
| 86 | +That’s much better, but there’s more. When running `strings` on that file, we see references to `flag.txt`, so this could be real steganography. To find out, we use `foremost`: |
| 87 | + |
| 88 | +``` |
| 89 | +dd if=done_xor.pdf | foremost |
| 90 | +Processing: stdin |
| 91 | +|360+1 records in |
| 92 | +360+1 records out |
| 93 | +184539 bytes (185 kB, 180 KiB) copied, 0.0017788 s, 104 MB/s |
| 94 | +foundat=flag.txtUT |
| 95 | +*| |
| 96 | +``` |
| 97 | + |
| 98 | +Interesting, so we appear to have recovered something. Looking through `foremost`‘s [output folder](https://github.com/lyellread/ctf-writeups/blob/master/2021-0x41414141/0x414141/output), we can see that it sliced a PDF and a Zip archive. Next, we have to unzip that, presumably. Let’s give that a shot: |
| 99 | + |
| 100 | +``` |
| 101 | +unzip foremost.zip |
| 102 | +Archive: foremost.zip |
| 103 | +[foremost.zip] flag.txt password: |
| 104 | +``` |
| 105 | + |
| 106 | +We need a password, and because we do not know it, we are going to have to crack it. To do so, we must build John The Ripper from source (to have access to `zip2john`). For that, I followed [this handy guide](https://hackthestuff.com/article/how-to-install-john-the-ripper-in-linux-and-crack-password). Once installed, it’s as easy as: |
| 107 | + |
| 108 | +``` |
| 109 | +zip2john foremost.zip > hashes |
| 110 | +john hashes --show |
| 111 | +foremost/flag.txt:passwd:flag.txt:foremost::foremost |
| 112 | +1 password hash cracked, 0 left |
| 113 | +``` |
| 114 | + |
| 115 | +Armed with our password `passwd`, we attack the Zip, and get the flag: |
| 116 | + |
| 117 | +``` |
| 118 | +flag{1t_b33n_A_l0ng_w@y8742} |
| 119 | +``` |
| 120 | + |
| 121 | +~ Lyell |
0 commit comments