███                   █████                          
            ░░░                   ░░███                           
 ████████   ████   █████   ██████  ░███████    ██████   █████ ████
░░███░░███ ░░███  ███░░   ███░░███ ░███░░███  ░░░░░███ ░░███ ░███ 
 ░███ ░███  ░███ ░░█████ ░███ ░░░  ░███ ░███   ███████  ░███ ░███ 
 ░███ ░███  ░███  ░░░░███░███  ███ ░███ ░███  ███░░███  ░███ ░███ 
 ████ █████ █████ ██████ ░░██████  ████ █████░░████████ ░░███████ 
░░░░ ░░░░░ ░░░░░ ░░░░░░   ░░░░░░  ░░░░ ░░░░░  ░░░░░░░░   ░░░░░███ 
                                                         ███ ░███ 
                                                        ░░██████  
                                                         ░░░░░░   
	

Arab Security Cyber Wargames

Image describing the post

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.

The important function

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.

XOR'ing function

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,

Result

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.

readString

Here, we can see the binary taking the MD5 of something, probably our input.

MD5

This is what it’s comparing it with:

actual hash

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}.

flag found

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:

checker

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}.

done

Thanks for reading until now, and my teammates will probably upload their writeups soon in their respective blogs/github.

Contact me