Arab Security Cyber Wargames
Description: I solved all three challs, therefore I made a writeup
Introduction
This CTF was the Qualifier to the finals, and rev was pretty easy. Anyways, for people that might not have understood how to solve certain challenges, this writeup is for them.
Check
TL;DR: Manipulate environment variables for fun and flags
I got this challenge while the main server was down, in the github. Let’s take a quick look in IDA.
We can see that it uses getenv
to get the value of some environment variable, and then it XOR decodes the actual value that it needs to be. The XOR’ing happens in functions like this one.
There was no actual need to find out what it’s XOR’ing with, because in the end, there’s a strcmp with the input value anyways, so this didn’t require a lot of thinking. By decoding the values in this way, we get the following values for the environment variables:
HOSTNAME=Machine
USER=reenigne
Sure enough,
The flag is ASCWG{3nv_v4r5_4r3_u53ful}
DOOM
TL;DR: Crack an MD5 Hash.
Once you open the binary in IDA, you see the helpfully named functions, main
, getString
, printFlag
, and verifyFlag
. Getting to verifyFlag isn’t that hard, either. Just change EIP
at the right moment and you’re good to go!
The binary reads a file called string.txt, probably where we need to put the flag to check it.
Here, we can see the binary taking the MD5 of something, probably our input.
This is what it’s comparing it with:
Now it’s just a matter of getting the hash and cracking it.
The hash is B9448DD62F8F39451767741F799C8D8B
and crackstation tells me that it’s an MD5 hash of apocolypsedoomsday
. Bingo!
Sure enough, the flag is ASCWG{apocolypsedoomsday}
.
Key
This one was a rust challenge in Windows, and I suck at both. It was therefore kinda reassuring that me studying this stuff had an effect.
Since this is a rust chall, there’s a lot of stuff happening. The most important parts are often hidden somewhere deep in the code. I’m a noob and not competent at stuff like Lighthouse, and so I decided to not learn something in the middle of a CTF and go with my guts.
This binary seems to be asking for parameters from argv, and therefore, I put 16 bits of input.
Now, onto the interesting bit:
Somewhere deep in the function, we come across this bit of code:
Now, to my non-rust-programmer head, this looked exactly like a checker in C:
if(!cond1){
if(!cond2){
if(!cond3){
// fail
}
}
}
else{
// goodboy
}
Therefore, I decided to make sense of it and make a Z3py script to take care of the majority of finding out the values.
from z3 import Int, Solver, solve, Xor, BitVec, And
a = [BitVec('a%s' %i,16) for i in range(16)]
s = Solver()
s.add(a[0] == 2*a[7])
s.add(a[1] == 48)
s.add(a[2] == 52)
s.add(a[3] == 50)
s.add(a[9] == 38)
s.add(a[4] == a[7] - 7)
s.add(a[4] & 0xf4 == 36)
s.add(0x5a ^ a[5] == 113)
s.add(a[7] == 45)
s.add(a[6] == (a[5] | 0x7e))
s.add(a[8] == 66)
s.add(a[10] == 83)
s.add(a[11] == 92)
s.add(a[12] + a[6] == 0x89) #-119?
s.add(a[13] == (0x5a & 0x26 ^ 0x42))
s.add(a[14] == 40)
s.add(a[15] == 41)
print(s.check())
print(s.model())
m = s.model()
b= []
for i in range(16):
b.append(chr(int(m[a[i]].as_string())))
c = ''.join(b)
print(c)
for i in range(16):
print(i,b[i])
Now, if you run this script, you’ll find that a[6] and a[12] are left undefined. That’s because I couldn’t figure out a way to statically get those values, and had to get it using other ways, i.e., dynamic debugging.
Anyways, the key turns out to be Z042&+~-B&S\/@()
and the flag is ASCWG{RustyRevEngineer}
.
Thanks for reading until now, and my teammates will probably upload their writeups soon in their respective blogs/github.