Writeups

Neo

(Crypto 200)

Summary:
The challenge was a basic padding oracle attack. A padding oracle attack is present when: 1) A server attempts decryption with padding on controllable data, and 2) The server returns different a different result (i.e. error message) if the cipher text did not unpad correctly (i.e. an oracle). By attempting decryption of specially crafted data, the oracle reveals if unpadding was successful. From that oracle the plaintext can be recovered without the original key.

The challenge presents to you a website that states "Decrypt the matrix", and an input box that generates a new seemingly random base64 string on refresh. Playing around with submitting the box prints a different message depending on the input, either:

From that, I then found some things already built for crafting/testing differently crafted data. I choose, https://github.com/mwielgoszewski/python-paddingoracle (I also have it easily installable in my sec-tools), as the best one for me. It's a nice Python API, where basically all you have to do is define an oracle function, and make it either Throw a 'BadPaddingException' based on your own logic for what throws that, or make it return successfully. The logic to throw a BadPaddingException can be actual crypto, or it can be a web request, it just has to be logic that causes an oracle to speak.

Note:
It's kind of deceptive in the challenge how a new random base64 string is printed to you on every website refresh. Because of that it can be difficult to figure out what you're supposed to decrypt. I ended up actually editing python-paddingoracle to also print the 'IV' (see the padding oracle article above, but basically IV = intermediate value ^ decrypted 1st block). I saw that the IV was \00*16 (typical default for CBC), so that gave me hope that I was on the right path, and that this really was some usefully encrypted data, and that my padding oracle attack was in fact working.

The Rock

(Reversing 100)

Summary:
Fairly straight forward ELF64 C++ reverse engineering. Using a mix of static, and dynamic tools you can get a feel of what the program is doing. It was mostly figuring out which functions do something useful.

In this challenge we're give an ELF64 binary. Opening it up in IDA reveals the main function, and that it's written in C++, which means there's going to be a lot more garbage data (virtualism, object-oriented, std library, etc. cruft) to sift through.

There's 3 ways to go down from this:

Purely static analysis - Figure out what each function does, if it's useful or not, typically starting by backtracking from the function that looks most likely to be a validate function. There should be an algorithm that some how compares some form of the input key, to some form of the known good key. The algorithm maybe tricky, and the keys may be shuffled in all sorts of ways, but it boils down to essentially a comparison.

Purely dynamic analysis - Input a key, and follow it down the call stack, and find what it's compared to. Feed that known good key as your input key. This will really only work if the input key is compared without any encoding to it.

Some combination of the above 2.

I ended up doing (1), but (2) was the smarter choice as the input key was being compared directly to an encoded known good key, so simply putting a breakpoint, recording that known good key, and passing it as my input key would do the trick.
But, for whatever reason I wrote the code for (1) instead.

Key

(Reversing 125)

Summary:
In this challenge you're given a PE32 executable. The executable looks inside of a key file, and compares the contents to an encoded key. The contents of the file are compared as is to the encoded key.

Executing the program gives us:

"W?h?a?t h?a?p?p?e?n?"

Opening it up in IDA, and searching for that string, and then backtracing for the root cause reveals to us another interesting string:

Note:
Executing the program in wine on Linux crashes... apparently the PE32 uses something that wine hasn't implemented, so you really do need to run this on a Windows box.

So it's pretty obvious that file has to exist. The key is probably put into it and compared directly (it is), but you can verify through running the program in a debugger. That's what I ended up doing, but you can actually skip that and solve this quicker by not.

After getting past the error print, spending some more time debugging, and tracking memory flow reviews to us that the algorithm of this program is basically:

1. Encode the string 'themidathemidathem' by XORing it with a constant key
2. Encode the result from (1) via some more gibberish.
3. Compare (3) to the input file key.

We can follow the flow of the program, and find the result of (2):

idg_cni~bjbfi|gsxb

Regexpire

(Misc 100)

Summary:
In this challenge you connect to a server, and it prompts you to provide a correct string that will satisfy a regex expression. You must answer with a satisfiable string, and repeat this process until the server spits out the flag.

I googled for 'reverse regex', and ended up finding the python library rstr. It takes in a regex expression, and returns a string that satisfies it, exactly what we want.

import rstr
import telnetlib
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("misc.chal.csaw.io", 8001))
s.recv(1024) # junk read
while True:
question = s.recv(1024)
print("Asking for: " + question)
if 'Irregular' in question: # printed when we messed up
break
if 'flag' in question: # hoping this is printed when we're done
break
ans = rstr.xeger(question)
print("Answering: " + ans)
# The server can't handle '\n' in the middle of an answer
# as it thinks that's the end of the answer, so we have to ask
# again for an answer that doesn't have '\n' in it.
while '\n' in ans[:-1]:
print('we fucked')
ans = rstr.xeger(question)
print("Answering: " + ans)
s.send(ans)