Writeup to the Decompetition capture the flag (2020)
Tags: Hacking, Reverse Engineering, Ctf, Go, Cybersecurity

dem challenges

I don’t want to discuss all the challenges that I solved, but I do want to discuss some of them and the strategies that I used to work out their solutions.

prime

The first challenge that I want to discuss is the prime binary. Like the name suggests, this little programme generates prime numbers under some number n . There are a number of algorithms to compute prime numbers, with the Sieve of Eratosthenes being the most common one:

# From the Wikipedia entry on the Sieve of Eratosthenes ( 29 Oct., 2020 revision ), note that this algorithm might not be exactly how it's implemented in the prime binary in Decompetition. algorithm Sieve of Eratosthenes is

input: an integer n > 1.

output: all prime numbers from 2 through n.



let A be an array of Boolean values, indexed by integers 2 to n,

initially all set to true.



for i = 2, 3, 4, ..., not exceeding √n do

if A[i] is true

for j = i2, i2+i, i2+2i, i2+3i, ..., not exceeding n do

A[j] := false



return all i such that A[i] is true.

When reversing binaries written in the C or C++ language, I simply used Ghidra’s decompiler. It makes it a lot easier to rewrite the original binary; all I have to do is tweak the output so that it makes sense in context of compilation:

fabulous

Or, when a maths background can be helpful…

Unfortunately, my technique of using Ghidra’s decompiler to work out an approximation for source code didn’t fly with Go or the other languages. I suppose their compilers generate different disassembly patterns that confused Ghidra’s decompiler, so I had to be a little creative.

I took a black-box approach to rewriting the fabulous binary. I ran it without any arguments and got this output:

$ ./fabulous

panic: runtime error: index out of range [1] with length 1 goroutine 1 [running]:

main.main()

/mnt/go/fibl/fibl.go:13 +0x247

Okay, it looks like it needs an argument. Let’s see what happens when I input a 1 :

$ ./fabulous 1

1

Interesting. Now, let’s try a range of numbers for fabulous :

$ for x in range {1..10}; do ./fabulous $x | tr '\r

' ' '; done

1 1 2 3 5 8 13 21 34 55 89

Now this is where having a maths background can prove to be helpful. I immediately noticed that this is a Fibonacci sequence, and whipped up a Golang implementation:

baby-go

Or, when a coding background can be helpful…

As with fabulous , I took a black-box approach to reverse engineering baby-go . I started by running it without any arguments:

$ ./baby-go

panic: runtime error: index out of range [1] with length 1 goroutine 1 [running]:

main.main()

/mnt/go/fizzbuzz/interview.go:12 +0x275

Okay, now let’s introduce an argument:

$ ./baby-go 1

1

Now let’s probe the function and see if we can work out a pattern:

$ for x in range {1..50}; do ./baby-go $x | tr ‘\r

’ ‘ ‘; done

Green 1 2 Yellow 4 Blue Yellow 7 8 Yellow Blue 11 Yellow 13 14 Green 16 17 Yellow 19 Blue Yellow 22 23 Yellow Blue 26 Yellow 28 29 Green 31 32 Yellow 34 Blue Yellow 37 38 Yellow Blue 41 Yellow 43 44 Green 46 47 Yellow 49 Blue

Again, this is where the coding background can come in handy. I noticed that this is an implementation of the FizzBuzz challenge used as a litmus test to weed out lousy programmers, and immediately was able to come up with an implementation: