Reverse Engineering

ChallengeLink

Beginner Rev (50 pts)

ARMory (190 pts)

Off The Hook (300 pts) 🥇

McGuffin Hunt (500 pts) 🥇

Beginner Rev (50 pts)

Description

To all the new CTFers who are starting to dip their toes in the wonderful world of cybersecurity, we wish you all the best in your CTF journey!ts

Solution

Given ELF file, open it using IDA

So it just basic validation, to get valid input just xor byte_402010 with 0x41. Here is my solver

a = [  0x32, 0x36, 0x20, 0x2C, 0x31, 0x02, 0x15, 0x07, 0x3A, 0x19, 
  0x71, 0x13, 0x1E, 0x28, 0x2F, 0x37, 0x71, 0x2D, 0x34, 0x35, 
  0x28, 0x71, 0x2F, 0x1E, 0x28, 0x74, 0x1E, 0x22, 0x71, 0x71, 
  0x2D, 0x3C]

flag = b""
for i in a:
	flag += bytes([i ^ 0x41])
print(flag)

Flag: swampCTF{X0R_inv0luti0n_i5_c00l}

ARMory (190 pts)

Description

This new phone from UFSIT is running, SwampOS, which is highly secure version of AOSP. Running with full disk encryption by default, figure out the password to unlock the phone.

Solution

Given ELF file, open it using IDA.

It looks like previous challenge but with more operations. The program above actually did the operation below

a_0 == input[i] ^ 0x41 ^ salt_1[i%len(salt)]

So to get the input we can reverse the operation, here is my solver

a = [0xEC, 0x9B, 0x9E, 0xC3, 0xEF, 0xAF, 0xAB, 0xE8, 0xE4, 0x95, 
  0xCF, 0xDB, 0xED, 0xB3, 0xCB, 0xDC, 0xF2, 0xB3, 0xCA, 0xC5, 
  0xAE, 0x80, 0x93, 0x9B, 0xC0, 0x82, 0xCC, 0x9D, 0xFB, 0xB3, 
  0xCE, 0xC3, 0xEF, 0x9E, 0xCF, 0xD8, 0xAC, 0x81, 0xCC, 0xC0, 
  0xA8, 0xB3, 0xC9, 0xCD, 0xFB, 0xDF, 0x99, 0x9B, 0xE2, 0x00]

salt = [0xde, 0xad, 0xbe, 0xef]
flag = b""
for i in range(len(a)):
    flag += bytes([a[i] ^ 0x41 ^ salt[i % len(salt)]])
print(flag)

Flag: swampCTF{y0ur_4rm_5k1ll5_n33d_1mpr0v3m3n7_6cd3f5}

Off The Hook (300 pts)

Description

We did some dabbling with apk's, have fun!

Solution

Given APK file, decompile using jadx-gui.

From MainActivity we can see that there is getFlag function. There is validation during getFlag function.

  • If argument == Onions, throw exception

  • If checkLeet (native function) != 1337., throw exception

The program above will always throw exception because getFlag call verify function with hardcoded string "Onions". checkLeet also do the same thing, it will return value != 1337

To get the flag my idea is patching verify function. First, decompile swamp.apk using apktool.

apktool d swamp.apk
MainActivity.smali
...
.method public verify(Ljava/lang/String;)V
    .locals 2

    const-string v0, "Onionz"

    .line 51
    invoke-virtual {p1, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

    move-result p1

    if-nez p1, :cond_1

    .line 55
    invoke-virtual {p0}, Lcom/rumpelstiltskin/anative/MainActivity;->checkLeet()I

    move-result p1

    const/16 v1, 0x539

    if-eq p1, v1, :cond_0

    return-void

    .line 56
    :cond_0
    new-instance p1, Ljava/lang/IllegalStateException;
...
  • Line 5: change from Onions to Onionz

  • Line 21: change from checkLeet() != 1337 to checkLeet() == 1337

Compile the APK and sign it. Finally, just click "PRESS ME" and flag will be shown.

apktool b swamp
uber-apk-signer --allowResig -a swamp/dist/swamp.apk

Flag: swampCTF{TH@TLL_D0_D0NK!}

McGuffin Hunt (500 pts)

Description

Sometimes an object as simple as a fence can slow the main character of a story down, but notice how I didn't say stop....

Solution

Given several files.

So this is the first time i do reverse engineering for any TI-* . Lets read README.txt.

README.txt show us how to run the SWAMPCTF.8xp file using given emulator (Wabbitemu64.exe). Before we can run the program, we must download the ROM which is TI-84+ ROM. After following the instruction we will see display like image below.

There is debug menu in toolbar, click it and click open debugger.

Looks like it is not x86/x64 assembly, so lets try to find reference about it. This reference give me help about disassembling the program. From that reference i know that the base address of the program is 0x9d95. After successfuly disassembly the program using IDA, lets validate it with the assembly on debugger.

Okay looks like same. Now, take a look on available strings on the program.

So those strings are used in the program but when we try to find reference to those strings IDA can't find it.

From image above we can see that the string shown on the calculator is same like we found on IDA. So the next step i do is trying to find assembly that use address of string as operand.

I found instruction that use 0xa341 as operand. 0xa341 store strings value that shown during conversation with people near the gate.

Opening sub_a2c3, we can see that there are some string address loaded before sub_A09F (ld hl, <string_address>. In this step i assume that sub_A09F do the print things. In sub_a2c3, IDA can't detect any reference to that function.

We know that sub_a2c3 is called, because IDA can't detect the reference lets utilize the debugger. Set breakpoint on A2C3 that continue the program.

If we hit the people object (phi) near the gate, the program will break at 0xa2c3. To understand the instruction i use this reference from Resources/Zilog Z80 Microprocessor Instruction Table.url file. There is a cp instruction, basically it does substract operation and will set zero flag that will affect the jump instruction (jr). If we change the z flags (zero flag) the flow will be different, the program will not show "If Only ..." but it will show "You Got ...". It is the same like the logic we found on sub_a2c3.

With assembly knowledge, we know that after ret instruction we will go back to previous frame that call current function. So lets set breakpoint on ret then step the debugger.

Lets take a look on 9fbe on IDA.

There are many branch on sub_9ead. From the conversation in program we know that there is something outside the fence and there are some type of object in the game. So in this step i tried to find out which address is executed by each object. I did it by analyzing the branch and debug it, at the end i found information below

  • 1 - Collide with "wall" , address executed : 9e8f

  • 2 - Collide with ".." (change map) , address executed : 9ef1

  • 3 - Collide with "door" , address executed : 9f41

  • 4 - No collision

  • 5 - Collide with "phi" , address executed : 9f7f

Because my assumption that we need to bypass the wall, i change my focus to analyzing sub_9e8f. First, i tried to collide with wall on left.

There are some interesting value on 9341-9344, lets try to hit another two walls. Go down from previous position and hit wall on left.

Last, with previous position hit wall on bottom.

From above experiments, we can conclude that sub_9e8f make our target coordinate back to latest coordinate.

  • Target coordinate

    • 9341 = x, 9342 = y

  • Last coordinate

    • 9343 = x, 9344 = y

To implement my idea (bypass the wall), i tried to change the target coordinate outside the wall when it hits instruction ret (0x9e9d).

  • Change 0x9341 to 0x1

  • Run the program and got the flag

Flag: SwampCTF{MC6UFF1N_F0UND}

Last updated