Flag Service Revolution – Alles!CTF

In the recent Alles!CTF, I came by this game challenge, Flag Service Revolution. The challenge file was a .dol file which I absolutely had no idea of what that was, so I googled up to get wiser on what it meant and figured that it was a Nintendo gamecube executable file which was released back in 2001 for, well… obviously, a game. And that’s all I wanted to know about it.

Next up, debugging and Emulation. On pondering around in the world wide web for a while I found out about the emulator dolphin which I could immediately set up and run the .dol file and for the debug part, I wasted a few hours trying to see if any of the ones i found over the internet works and wasted my precious sleep hours installing random stuff without knowing what I was doing up until one of my friends figured out the damned dolphin had a debugger itself which worked with simply

$ dolphin-emu -d

Running the tool in debug mode. It loads with a warning, but nvm.

Next I started debugging the elf I cooked up from the .dol file with a random online tool which helped me immensely, in fact it did most of the work. So I loaded the elf I converted from the .dol and loaded it to ghidra from where I went through about 50 functions and did not find anything close to what I was looking for – like strings. Then I decided to do it the right way, I searched for strings on Ghidra which dumped a couple hundred string from where I filtered for the welcome message string “Welcome to Our Great Flag{Service_Revolution}” . In no time it took me to the Main function which ran in a while(true) loop – Infinite Loop. This function in turned called a couple other functions which again was a dead end to me. So I had to go for the next filtering, where I searched for the strings printed by the game when we press different keys on our keyboard like :

and other keys like A, B, Left, Right, Up, Down etc..

These keys took me to a switch case which basically checked if the user input was in the order A, B, RIGHT, LEFT, RIGHT, LEFT, DOWN, DOWN, UP, UP, which I later came to realise was the Konami code, but in reverse. And that gave me the flag.

Flaaaag!

Well this challenge, to me was the first game challenge that I was able to understand completely in the process of solving and for that reason it was a really fun and new learning experience.

Reversing Rust And Go Binaries

Why do we have Rust and Go???

Languages like C/C++ are general purpouse programming languages used widely for competative programming. Whereas Languages like rust and go are development oriented language or a procedural programming language. The language Go was developed by Google and launched in 2009. The language was developed to solve large scale problems faced by google as an open source programming language.

The language is platform independant like Java and hence can be compiled on any platform and is incredibly easy to learn as it is a lot like python in terms of syntax. These languages are Scripting languages are extremely great for writing services.

Speaking of GoLang

  1. A high performance language , providing great efficiency like C/C++.
  2. Provides high concurrency as in Java.
    • Concurrency is the efficiency of the programme to utilize the untapped capabilities of the OS and the machine hardware. Eg. threading to enable faster execution of the programme.
  3. Easy to learn and fun to code like python : ) !!

Summing it up if you’re looking for scalability and efficiency in a programming language you should probably consider Go!

Go is a win win for the user as well as the processor in terms of efficiency and understandability for the developers !!

GoLang C++
It does not use header files instead of header file go use packages.It contain header file and does not contain package.
It does not support implicit type conversion. It support implicit type conversion.
Go use panic and recover for resolving error. C++ use try, catch, and throw for resolving error.
It does not have while or do-while statements. It have while or do-while statements.
It is more strong typed as comparison to C++ language. It is less strong typed as compare to Go language.
Go contains goroutines and channel. C++ does not contain goroutines and channel.
It does not support inheritance.  It supports Inheritance

Basics of GoLang

Go is pretty much a combo of C/C++ and python in terms of syntax.

Example 1:

“Hello, World” in Go!!

To compile:

$ go build <file name> -o <outfile>

$ ./outfile

Example 2:

Just to Familiarise with the datatypes I tried this example and you can see its quite similar to python.

The output is as follows:

Data types in Go:

As far as reversing a Go binary is concerned as you may have noticed in example 2, the initialisation of variables is not done as it is done in python where the data type need not be mentioned and therefore everytime a variable is initialised it is checked with all the available types in this structure below to determine the type.

  • Bool 
  • String
  • Int 8 ,16 ,32 ,64
  • Uint8 , uint16, uint32 , uint64
  • Complex32, complex64
  • To name a few…

So that’s all you need to know about go language for now ! 

Let’s get started with reversing

Here for analysing the binary , I am using IDA pro . 

Our simple hello World programme has been compiled to ~1800 functions which is not very ideal for reversing. And hence , figuring out our main function is Important.z

Structure of a Go binary

The main of a Go binary is called the “ main.main ”

On further digging we figure out the actual main function that we have written resides in the main.main.

And in the main we can see the call being made to the function Println().

Now lets move on to solving a simple custom challenge.

Challenge Description: make the binary print 1 . : )

Now, since we know what to do first, lets get straight to the main.main function and see the decompilation on IDA!

So our required input is : thebadcat

Now moving onto Rust.

Rust is a more innovative system-level language. Creators produced this language with safety in mind. Notably, they aimed to beat C++ by offering safer memory management while keeping their speed advantage. Rust will lead to the production of fast software.The language frequently supports projects aimed at high-security and high-concurrency .

Rust is also largely known as a memory safe Language

Advantages and Disadvantages :

ProsCons
Highly safe[memory safe language]
Not very friendly in terms of syntax
High speed of execution, almost as much as C/C++
You can’t develop code as ‘fast’ as scripting languages like Python or Ruby
High Concurrency
The binaries produced by rust compiler are larger compared to C/C++
High level of abstraction

Now let’s analyse the binary:

When  you run the binary on IDA, first you see the main and on looking at the graph it is sort of like the libc_start function on C binaries which call the main. And similarly here you can see the highlighted function being called is our actual main function that we wrote.This is what we’ll be analysing next.

So this is the decompilation of our main which clearly shows what the entire programme does , ie , initialises the count , add 1, and prints the value of count till the value of count hits 20,

Now let’s talk about the stack frames in Rust and Go.

The normal C stack frame:

The normal stack frame -Segmented Stack Frame

The stack frame implemented by C binaries where the stack grows from the top, as each new function gets called a new stack frame is created where the local variables are allocated space on the top of the stack -Segmented Stack frames

Stack Frames in Rust and GoLang:

Go provides a light and smart goroutines management. Light because the goroutine stack starts at 2Kb only, and smart since goroutines can grow / shrink automatically according to our needs.

This default stack size is sometimes not enough to run our program. This is when Go automatically adjusts the size of the stack

Function calls in Go binaries

In Go binaries , when a function gets called ,it actually accepts any amount of data and leaves it to the compiler to check the type and length etc of the arguments passed. 

And on analysing , the return value wasn’t on any of the registers , instead the stack held the return value

So here ;

Split Stack and Stack Copying:

So this programme simply calls the functions a,b,c  and prints a line…

Stack copying is a lot like , multiple segmented stacks. The Go routine is running along using the stack space and when it runs out, it hits the stack overflow check and gets copied to a bigger stack space.

However, instead of having a link back to the previous segment, it creates the new segment with double the size and copies the old segment into it. This means that when the stack shrinks back to its old size, the runtime doesn’t have to do anything. Shrinking is now a free operation. Additionally, when the stack grows again, the runtime doesn’t have to do anything. We just reuse the space that we allocated earlier.

Thank You 🙂

Volga CTF: 2020

Excel – RE

I solved this challenge A while ago forgot to put up a writeup and for that reason I confess I don not entirely remember the challenge but still I couldnt stop myself from sharing this solution just cuz.

Anyways a senior and I collabed on this challenge to get it solved so I will be focussing more on my contribution which was mainly in the reversing of the code which was given in the format of a complicated algorithm performed on matrices which were hardcoded in the matrix.

We used z3 because for Obvious reasons we did not want to manually find each value and that would have been a messy job. So what we did was we etraceted the matrix from the excel sheet given and copied it to a new sheet names ‘val.xlsm’ and used the values from that matrix to obtain the flag values

The script we used is:

from z3 import *
from xlrd import *
wb = open_workbook('val.xlsm')
arr = []
for sb in wb.sheets():
    for row in range(sb.nrows):
        values = []
        for col in range(sb.ncols):
            values.append(int(sb.cell(row,col).value))
        arr.append(values)
s=Solver()

cmparray=[490493,-7845,-54593,210672,-407144,533417,-320176,-83622,147210,-344141,507384,429295,-272727,309196,-247072,-382979,-29820,-665472,-51995,-224011,-16181,-91699,-572802,-440533,-442324,-29239,-585661,106807,-412046,1312536,44628,232490,-383077,436266,107084,-117467,309109,71961,21720,49050,-84381,-302598,-52964,209341,102350]
f = [z3.BitVec("f%d" % i, 8) for i in range(45)]
s.add(f[0]==ord('V'))
s.add(f[1]==ord('o'))
s.add(f[2]==ord('l'))
s.add(f[3]==ord('g'))
s.add(f[4]==ord('a'))
s.add(f[5]==ord('C'))
s.add(f[6]==ord('T'))
s.add(f[7]==ord('F'))
s.add(f[8]==ord('{'))

s.add(f[44]==ord('}'))
for i in range(len(f)):
    s.add(z3.And(f[i] > 32 , f[i] <= 125))
for i in range(len(f)):
    x = 0
    for j in range(len(f)):
        x=x+arr[i][j]*f[j]
    s.add(cmparray[i]==x)
print(s.check())
print(s.model())

The script took around an hour during which I took a nap and woke up to the flag 🙂

HSCTF2020 Writeups

Dis – Python Bytecode Challenge

The challenge was a python bytecode challenge where the approach I chose was to maually replicate the bytecode from the documentation of the dis module in python which took up a while. Im not sure if there’s a less time consuming approach but once that was done the reversing part was automated using Z3.

bytestring=b'\xae\xc0\xa1\xab\xef\x15\xd8\xca\x18\xc6\xab\x17\x93\xa8\x11\xd7\x18\x15\xd7\x17\xbd\x9a\xc0\xe9\x93\x11\xa7\x04\xa1\x1c\x1c\xed'
from z3 import *


def a(s):
    o = [0] * 32
    for i in range(32):
        o[i] = ((s[i]+s[i])-60)
    return o
def b(s,t):
    for x,y in zip(s,t):
        yield(x+y)-50
def c(s):
    return [x+5 for x in s]

def e(s):
    s = [ i for i in s ]
    o = [ (o^5)-30 for o in b(a(s),c(s)) ]
    return o

def main():
    sol=Solver()
    o=b'\xae\xc0\xa1\xab\xef\x15\xd8\xca\x18\xc6\xab\x17\x93\xa8\x11\xd7\x18\x15\xd7\x17\xbd\x9a\xc0\xe9\x93\x11\xa7\x04\xa1\x1c\x1c\xed'
    l=list(o)
    s = [ BitVec('s[%s]' % i, 8) for i in range(32) ]
    s = e(s)
    for i in range(len(l)):
        sol.add(s[i]==l[i])
    print(sol.check())
    print(sol.model())
main()

And the flag we get is :flag{5tr4ng3_d1s45s3mbly_1c0a88}

Emojis – Misc

This challenge was made using emojigram language which is an esolang made using Emojis. All that we need to do is repicate the code in python and generate the flag from it by reversing the code.

The replicated code looked like this.
But since there are conditional jumps and all that we are given is the output when the flag is given, we have no choice but to guess whether the jumps are taken or not inorder to obttain the desired input.
And to achieve the same we played around with a few of the instructions and put together the possibilities to get the Flag.


flag=[120, 66, 94, 114, 95, 69, 110, 125, 73, 78, 99, 52, 118]
flag[9]=flag[9]+flag[1]
flag[7]=flag[7]+flag[11]
flag[2]=47
flag[4]=flag[4]+flag[11]
flag[0]=flag[0]+flag[2]
flag[8]=flag[8]-8
flag[6]=flag[6]+flag[8]
flag[6]=flag[6]-flag[8]
flag[6]=flag[6]-flag[8]
flag[10]=flag[10]+8
flag[11]=flag[11]-1
flag[4]=flag[4]-flag[9]
flag[3]=flag[3]-2
flag[2]=flag[2]-4
flag[0]=flag[0]-flag[11]
flag[1]=flag[1]-flag[3]
flag[1]=flag[1]+flag[3]
flag[1]=flag[1]+flag[3]
flag[1]=flag[1]-flag[7]
flag[3]=flag[12]
flag[2]=flag[2]+8
flag[9]=flag[9]-flag[6]
flag[2]=flag[2]+flag[4]
#flag[1]==flag[5]
#False
flag[2]=flag[5]
#flag[1]==flag[12]
#False
#flag[11]=flag[11]+flag[0]
flag[12]=118

Solved!

Flag: flag{tr3v0r-pAck3p}

APLab:English

Another java Reversing Challenge. We are given a java file which is to be reversed.

Solution:

s="1dd3|y_3tttb5g\`q]^dhn3j"
def unxor(string):
    ret=''
    xorstr=[4,1,3,1,2,1,3,0,1,4,3,1,2,0,1,4,1,2,3,2,1,0,3]
    for i in range(len(string)):
        ret+=chr(ord(string[i])^xorstr[i])
    return ret




def untranspose(string):
    ret=[None]\*23
    transpose=[11,18,15,19,8,17,5,2,12,6,21,0,22,7,13,14,4,16,20,1,3,10,9]
    for i in range(len(transpose)):
        ret[transpose[i]]=string[i]
    return ''.join(ret)


for i in range(3):
    s=unxor(s)
    print(s)
    s=untranspose(s)
    print(s)

The Output looks like this:

5eg2~x\3upwc7gau\\gjo3i
cj3o\\pg~i35uaug\xe2gw7
gk0n^]sgm04watc]zf0fw4
40gf]sma^4wgtc0z]knf0w
01dg_rna_0tf}tb4{_hlg0t
flag{n0t_t00_b4d_r1ght}

And we finally Obtain the flag!

pcme0 (Writeup)

pancrackme: v0

This crackme from crackmes.one was a relatively easy one where the basic idea is the implementaion of multiprocessing using the fork system call and how such challenges can be debugged. My approach was good old gdb and IDAPro where I used IDA for static analysis and decompilation and gdb for the dynamic analysis.

On running the binary!

On running the binary using gdb!

Here we can see that including the parent process there are a total of three processes switching between themselves to finally give the “yeah” output. From the image we can figure out that the first parent process prints the line “pancrackme: v1.0” . And then switches to the new process which writes “Password: ” before it makes the next switch which reads and checks the user input.

Next , on going through the disassembly , we know the second fork call actually produces the process which reads and checks the input. Here the child process . First you follow the default child process on gdb using

$ set follow-fork-mode child

Before the second fork is called , we reset the fork settings on gdb and follow the parent process

$ set follow-fork-mode parent

now in the disassembly we can see that the winwin function as marked and renamed in the following image prints out the yeah statement. In turn it checks our input.

Here we can see a debugger check implementation using ptrace which is bypassed by changing the reaturn value of ptrace.

The lines 49 to 52 can be precisely called the input check where it reads input of maximum 128 characters . If there is a valid input we are taken to the winwin function where the elaborate input check happens in the ‘real_funct’ which on passing allows the filedescriptor to write yeah into the write end of the pipe which is printed if the input is correct.

The check is basically :

input[i]^0x3a==BYTE PTR[arr] // where arr is the hardcoded string in the binary at the location [ 0x804a240+0x7c ] , which can be spotted only on dynamic analysis of the binary. This part of the binary is not decompiled by IDA due to dynamic allocation and unpacking of the binary!

Thus to get the input values, all we have to do is reverse xor the hard coded values and there you have the input to the crack me!

AND FINALLY YEAH! 🙂

HackIm’16 zorro_pub(Writeup)

  • The binary zorro_bin is a stripped file.

In this challenge basically the binary asks you for a number initially, (that is the number of drinks ). And further asks for the drinks’ id’s.If the first input is x, then a loop runs for x times xoring the values of drink id’s , which becomes the seed to a rand function in the code. The drink ids have to have their value in the range (16,0xffff). The seed value is checked against a function which checks whether the bin(seed) has 10 1’s if the condition is satisfied , the seed for the rand function is set and the rand values are updated to a string which is MD5 hashed and eventually checked against a hardcoded hash in the binary. Thats pretty much much it for the description for the challenge.

Solution:

My approach to this was to write a python script to find the input that would give the hash.

import random
import hashlib
from ctypes import *
libc=CDLL('libc.so.6')
arr=[0x3c8,0x32,0x2ce,0x302,0x7f,0x1b8,0x37e,0x188,0x349,0x27f,0x5e,0x234,0x354,0x1a3,0x96,0x340,0x128,0x2fc,0x300,0x28e,0x126,0x1b,0x32a,0x2f5,0x15f,0x368,0x1eb,0x79,0x11d,0x24e]
for j in range(16,0xffff):
    n=j
    c=0
    while(n!=0 and n>0):
        c=c+1
        n=n&(n-1)
    if(c==10):
        n=j
        libc.srand(n)
        c=0
        st=''
        final=''
        for i in range(30):
            a = libc.rand()%1000
            st = st + str(a)
            final = final + chr((a^arr[i])&0xff)
        final =final+'0'
        result = hashlib.md5(st.encode())
        if(result.hexdigest()=='5eba99aff105c9ff6a1a913e343fec67'):
            print(j)
            print(a)
            break

This script will give two outputs the first one being the seed value.