Onapsis CTF from EkoParty writeups.

This CTF was one of the many hosted for the EkoParty event in Argentina. We were sadly not able to physically attend, although we did play the CTF, and it was great fun, learning some interesting things along the way. These are the challenges that will appear in the following post:

DonkeyDrop

Challenge description:
We've found a weird usb key in front of our office. We made a dump of it. Could you find a clue of the attacker's idendity? The flag is the sha1sum of the attacker's hostname.

This challenge is 100% one of my favourites. I had never interacted with a rubber ducky before so it was definitely a learning experience. We start of with a USB image, which of course is mountable.

Making, mounting and listing.

At first I was confused about the binary, but after a quick google search, it turns out inject.bin is the malicious executable that is put on rubber duckies, so I head straight to figuring out how to decode it, when I stumble across a GitHub that has a python script in it for decoding these binaries. https://github.com/JPaulMora/Duck-Decoder

Running this script presents us with what the actual inject.bin is doing, and as we can see, it is making two new env variables, makes a new directory called "/tmp/.X8-lock" and then stores two files from pastebin in the directory, "key1" and "key2". After, it combines the two files by catting them both and redirecting the output to "key". Once the key is created, the binary will echo some hex, decode it, pipe it to openssl and decrypt the content with the "key" file, to then send it to /bin/sh. So all we need to do is find a way to get the keys.

After examining each of the pastebin links, one has been taken offline, and the other just contains:

We removed everything. The key is removed, you are too late !! Mouhaha !!!

We know that anonymous users on pastebin cannot edit files, and if this URL was hardcoded into the binary, and it has not been taken down, then it is still the same as it has always been. So we can assume that text is the actual key itself. Now for the "key1", this key has in fact been taken offline, so we need to think where can we possibly find this file. The pastebin is a no-go, so where else has it previously been? The usb itself, so we can use a disk analysis / file recovery tool call testdisk to see if there are any traces.

Bingo! Testdisk's file recovery feature managed to locate "key1", so we can copy it to our current directory and carry on (shoutout to tamas). We can follow what the rubber ducky does now, without actually sending the output to sh, so it is not executed.

And finally, we have the decoded payload, with the attackers hostname (64356637338.attacker.com) sha1 encrypted as the flag.

ONA{0d8d39c8739059fda6e01378e2c93a61d7fe6d8c}

Standard Dialog Protocol

Challenge description:
We believe that one of our SAP Systems was attacked by a login bruteforce. Could you find any clue of it?

This challenge was a very simple, quick one. It consisted of a pcap that just needed decoding via a wireshark plugin (https://github.com/SecureAuthCorp/SAP-Dissection-plug-in-for-Wireshark). Once this plugin is installed, simply reopen the pcap and search for the flag.

Secret Spy Message

Challenge description:
Our secret spy has recorded something that seems useful but we don't know how! Can you help us?

This challenge was fun, although it took me longer than it should have due to a fault in an online tool. It is a fairly simple analysis of DTMF (Dual Tone Multi Frequency), I have done this before in previous CTFs, so I have a decent idea of what to do.

Firstly I used an online tool to extract the DTMF Tones, although it cut off after a while and didn't pick up all of them, so I turned to DTMFCheck on Linux to extract the tones.

After formatting these and putting them into dcode.fr, you get an idea of what the plaintext is. Although, you need to take into account where the pauses are between each dial, since this will affect your output. So I listened to the audio again, and stepped through each beep accordingly.

Cool! So the output is THEPASSWORDISMONKEYSARECOOLIFYOUGIVETHEMBANANAS (The Password Is Monkeys Are Cool If You Give Them Bananas). The flag was just ONA{SHA1(MONKEYSARECOOLIFYOUGIVETHEMBANANAS)}.

Trivia

Challenge description:
Take the trivia and have fun.

This challenge was probably one of my least favourites. We were given a binary and an image. The image seemed to be irrelevant, so we run the binary, and it just gave us multiple choice questions, with a different letter for each of the answers. Now we can guess that these letters at the end will build the password or something for steghide on the image, since EVERYTHING we are given in a CTF is used at some point, and the image didn't seem to be relevant otherwise. So, if you know me, you will know I hate sitting through trivia's and questionnaires. So for this challenge, I made a script that generated a wordlist, depending on the answers. Some of the questions were like "What does a MITM consist of" or "What is a keylogger", so we were sure about the answers to those, meaning we could refine down our wordlist a bit.

In the end I came up with the following script:

I know, 1337 af.

Once the wordlist was generated, I ran stegcracker on the image file, and surely enough, I extracted the flag.

Guess My Number

Challenge description:
Let's play a game :). I will pick a number of 5 digits without telling you which one it is. You'll have to guess it in 4 or less attempts. Each attempt you make will have answer. This answer will be two numbers: X Y
X is the amount of good digits Y is the amount of regular digits.
A good digit means that you have correctly guessed the position of a digit. A regular digit means that a digit of your guess is inside the number that was chosen but is not in the correct place.
For example: If the number chosen is 91246 and your attempt is 12345, the answer will be: 1 2. Why? 1 good because the digit 4 is inside the number and also in the correct place 2 regulars because the digits 1 and 2 are in the number, but in diffrent positions than the ones attempted.
Good luck !
nc 198.211.123.92 1337

This challenge was just mastermind challenge, and to solve it, we just used an online mastermind solver written in JS (https://nebupookins.github.io/JS-Mastermind-Solver/).

Get My Neighbor's Flag

Challenge description:
My neighbor has challenged me to obtain his flag, which is transmitted through a high secured WiFi connection (or at least this is what he thinks). Help us to obtain the prize that he has promised to us if we get it!

We are given a pcap file. "breakmynetwork.pcap" and once we open it with wireshark and we can see it is IEEE 802.11 traffic so we can't really read a lot of info from it. My first idea was to just try run it through aircrack with rockyou and see if we get lucky.

That failed so let’s try something else, looking closer at some of the packets we can see the name of a device "Fibertel wifi 206".

So, we have the SSID. Let’s try googling that SSID and see if we can find more info about it and maybe a default password (we find http://usedmyhead.blogspot.com/2017/06/como-hackear-contrasenas-wpa-wpa2-psk.html).

This post is in Spanish, but we get some very useful information from it. For all the default passwords, they use the same method to generate it. "If the client is a woman, the prefix is 014 and if it is a man 004." This is then followed by their number. which will be 7 random digits we don’t know. The challenge says, “Help us obtain the prize that he promised to us if we get it!”, so let’s try 004.

import itertools

prefix = "004"

for combo in itertools.permutations(range(10), 7):

print prefix + "".join(map(str,combo))

This gives is a list of numbers starting with 004 followed by 7 random digits. Let’s run this with "aircrack-ng breakmynetwork.pcap -w 004.txt" and we get "KEY FOUND! [ 0043675498 ]. now we just open up wireshark and give it the new key "Edit > Preferences > Protocols > IEEE 802.11 > Edit Decryption Keys".

We put the key in and we can read the packets now. Right click and follow TCP stream and we get the flag.

The Rich Text

Challenge description:
A student has encrypted a file with a really powerful  but well known technique (according to him). Can you decrypt it?

We are given just a single file. Once downloaded I ran file on it, and it tells us it’s a 'floppy image data (IBM SaveDskF)'. After trying a few things with that we figured it was a false positive. This challenge was in the cryptography section. We only have 1 file and there is not much else to go on, running strings on the file does not give us much info. It was the first challenge in the cryptography section so we could assume it would be straight forward enough. So, let’s try some XOR on it. The first thing we can do it just run "xortool text.enc" this will give the most probable key lengths.

Here we can see that 6 is the most probable so let’s try that. Next we run "xortool -l 6 -b ../../text.enc" (-l is the key length which we will try as 6 and -b will brute force all possible most frequent chars).

From this, we get a lot of out files, so we need to sort later.

Of course we can just strings and grep, so we get our flag!

Running out of favorite things!

We were the only team to solve this challenge during the CTF. It certainly wasn't easy. We start off with a pcap file, so we export any HTTP objects and obtain some images.

Obviously the_final_race.jpg is the heaviest file, so we need to look into that a lot more. Although binwalk shows nothing... maybe steghide has something? We then tried cracking the steghide password with stegcracker:

The password was smiley1, so we can now extract some files from the image, obtaining a new file with the following contents:

CLIENT_RANDOM 29163d4699e0cfc4934012b1be7251b52393567bc922c40f25cd5472829f869f 290b824ba8fbe63e36a6f6eaf03267b5bc43d7275257151133ac199609ab7c09815a1082c4257359937a48d2369b02fa
CLIENT_RANDOM 87ca83b4e15baa90f95194ae6fc0b062b7bdf4c45d9ede18d8a69c5f5f285f0e 6a2a9839d4402ec9be1af4557a4aa320cd98e0ec0ce2f0cddba2c13228520bda23053f7ce25ba6820b461a0bca802afe
CLIENT_RANDOM 6673a69a6eaa2cdbc48572153cea624f59a2d1dc8a77ed5986d43aa7e5281795 209202d77a0eb65ecfc7ff9e728b0c5bbc8bfd90a4fb7ca1419cb4247180f0bf7a644345a20548fbc11d4fe7e570fa86
CLIENT_RANDOM 1848aad38039bf676016d7d651396e3d1e2d0dc541abc866c68a037b095acc2a c99dac39780af10dc7fea898ed2ed118ab4940c3d522b1180ffa1edaed28028d2bea5bdc3151ed3fbd6aff9788897e3d

This is of course a pre master log, so we can use it to decode the SSL data in the pcap file. Under Preferences and SSL protocols if we add that new file to the Pre Master Secret Log, we decrypt some of the files in the SSL:

From the SSL data, we obtain c01.part, c14.part, c16.part and c17.part. And after running file on these we get that 3 of them just say data and 1 says its "GPG symmetrically encrypted data (AES256 cipher)". C14 is the one that gives us this, but if we try and decrypt it with gpg it gives us an error.

So maybe the file is corrupt or not complete. The files do end in .part so maybe we need to put them together. I’m going to assume c14 is the first file as it contains header information. There are only a few combos that it can be so let’s just try them out. 2 of them seem to give us a working file. The correct order is: c14.part c17.part c01.part c16.part, and using cat, we make the working file:
cat c14.part c17.part c01.part c16.part > 14-17-01-16.out
It now gives us the correct output. we just need a password. We tried to brute force with rockyou and it didn’t work. But then we remember, one of the images said that password reuse was bad, and there was a packet in the pcap that used basic auth, maybe it's the same password...

onapsis:nPa5Wk6AVFSlpJN2k3fxyxwLVjYZJCtVAEMjWVZacyE=

We now have a username:password. Let’s try this new password on our file.
It works! We get a new file called eko15onapsis.

Running file on it tells us its binary:
eko15onapsis: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=f0db44e44e22d9507432e843c4a6af8e615befb9, stripped

We can see the "password" we have and then there is some changes to it.
This part of the challenge was a bit strange, the creator of the challenge gave a hint saying that the first letter was a 0. So we assumed it was something to do with onapsis in leet speak. Initially we had "0n4p515", and then we managed to bruteforce / guess the rest (I am also disappointed with this part).
./eko15onapsis 0n4p515Rul3z!
Seems you got the flag... Hash your input with sha1 and congratz!
and the flag is: ONA{a5dc8b63d2911e32f9db2a940e684a59a76b86c0}

Extra FAT

Alright so, this one's quite straight forward if you're OK with reading and understanding some code. Luckily, it's all Python.

We're given a .fs file that's supposedly a disk image that's using this file system. We're also given the code that was used to create it, which is missing the parts necessary to access the files.

So what does the filesystem do when you wanna put a file in it?

Okay yes, I'll admit, that looks scary at the first glance. It's really not though!

fs[2] is the numpy table that stores the block utilization.

If fs[2][r][c] is 4294967294, the block (r, c) is not used. Otherwise, as we'll see near the end of this function, it lets us know where the next block is.

At the start of the write file function, it decides on an unused block to use as its first block, randomly.

Then, it opens the filesystem file and the file to be written, and starts reading the file to be written in blocks of the block size of the filesystem (fs[1]).

Seeks to where the block (r, c) corrisponds to inside the filesystem file, and writes the block.

Then it picks a next block, writes the next block picked inside the block utilization table, and does a read of the block size from the file to be written again, to continue the loop.

We're mainly concerned here about how the next block information is stored inside the table. It's the block coordinates converted to 2 bytes of data each, put next to each other to make 4 bytes in total, then converted back to a python int, all in little endian.

Let's start writing a function that reads a file, given a starting block. Should just be seek, read, calculate where the next block is, loop.

I made it print too, and we may be getting UnicodeDecodeErrors if we get any files from the middle of a block, so covered for that. I'm also marking each block traversed as an empty block (by setting its block utilization table entry to 4294967294) so that I can do what we're getting at.
How do we predict starting blocks though? We don't! Let's just go through the entire file.

Interestingly, there were some fake flags in this, which I only got to see once I got the real flag too.

Overall, very nice challenge. Also comes with a free e-book I guess.

FlagOS

I was not sure about what people found so hard about this challenge until I saw IDA 7.0's output on it. Guess the choice of tools really matters on this one, and this time weirdly open source software wins?!
So yes, we're using Ghidra for this one. Thanks NSA, I'll take my laptop camera cover off for a few days I guess.
Let's begin with the .debug version. Surely it's not stripped:

Ayy, that's pretty good, we see that there's a clear main function, we go in there, it's the usual stuff, binary (an OS this time I guess?) asks for username and password, if you enter them right, it'll get you the flag.

... Wait, is the "decryption" just substracting the length of the password from all characters of the "encrypted flag"?

But where does the ENCRYPTED_FLAG even come from? It's not defined anywhere in the decompiled function so far. I'll try just double clicking on it.

Ghidra is too good. Select it, right click, Copy Special, Byte String.

Then we just go to CyberChef and boom!

GG EZ no RE, also I have no idea why they also included a stripped version if the flag's not changed, which it isn't.

Kudos