BoxCutter analysis write-up

Reversal of the BoxCutter problem

Table of contents

Analysis

Let's begin with the BoxCutter problem. You can find it here https://github.com/Arr-n-D/htb-cyber-ctf-reversing-problems/blob/master/rev_boxcutter.zip The description for this problem is as follows:

You've received a supply of valuable food and medicine from a generous sponsor. There's just one problem - the box is made of solid steel! Luckily, there's a dumb automated defense robot which you may be able to trick into opening the box for you - it's programmed to only attack things with the correct label.

Let's start by opening the process on a Linux machine, as the file format is an ELF, and see what happens.

Attempt at opening the file

So this file is a shared library, meaning we can't execute it. Let's disassemble it. When I was first disassembling it, I went with IDA Free, so let's start there.

Disassembly of the Cutter program with IDA Free

Since the difficulty rating for the challenge was "very easy", I took a very easy approach and assumed that the flag would be found in the strings. I was hilariously wrong after testing a couple of the strings as flags for the answer, so I decided to take a closer look, and decided to treat this program as a malware; I would go function by function and try to understand the program in its entirety. Taking this approach was also the wrong one, but let's ignore that part and focus on what I've done.

When I started reversing Cutter, I immediately went and tried to figure out everything and rewrite the whole thing in Python. Let's start with the first code block, and what it does

    file= byte ptr -20h 
    var_18= qword ptr -18h 
    fd= dword ptr -8 
    var_4= dword ptr -4
    ; __unwind { 
    push rbp ; 
    mov rbp, rsp ; Pushes the stack pointer into rbp, so we can reference variables using rbp+variable
    sub rsp, 20h ; Allocates space for our local variables 
    mov rax, 540345434C75637Fh
    mov rdx, 68045F4368505906h 
    mov qword ptr [rbp+file], rax ; File is now equal to 540345434C75637Fh or 0x540345434C75637F
    mov [rbp+var_18], rdx ; var_18 is now 68045F4368505906h or x68045F4368505906
    mov rax, 374A025B5B035468h 
    mov [rbp+var_18+7], rax ; This gets tricky. I'll explain in a comment below. 
    mov [rbp+var_4], 0 ; Self-explanatory, sets the value of var_4 to 0
    jmp short loc_11B0

I don't completely understand line 14, but my theory is as follows: The RBP register is 8 bytes(64 bits). When we're moving data into rbp+var_18+7, we're 1 offset short with our +7, so that means some data will be truncated. In this case, we lose 1 byte when moving the content of rax, so 374A025B5B035468h -> 374A025B5B0354h. Additionally, since we're not completely overwriting var_18, we create two new variables on the stack, the 68 that we lost, and the rest of var_18, 045F4368505906, or 0x45F4368505906. So at that point, we have these values

  • file: 0x540345434C75637F

  • var_18: 0x374A025B5B0354

  • new_stack_value_1: 0x68

  • new_stack_value_2: 0x45F4368505906

The next two blocks are relatively simple, and it's where we'll end our analysis, and I'll explain why.

loc_11B0:
mov     eax, [rbp+var_4]
cmp     eax, 16h
jbe     short loc_1194

loc_1194:
mov     eax, [rbp+var_4]
cdqe
movzx   eax, [rbp+rax+file]
xor     eax, 37h
mov     edx, eax
mov     eax, [rbp+var_4]
cdqe
mov     [rbp+rax+file], dl
add     [rbp+var_4], 1

In the above block, we have a for loop that iterates over var_4 and compares it to 0x16(22 decimal) and increments it in the loc_1194. At that point in time, I ended up opening Ghidra and checking the decompiled code, and I didn't have the values noted above ( new_stack_value, new_stack_value_2) The decompiled code, though, did have those values, and it's at that point I asked for help from different .

Solutions

The first statement that I wrote about the library and that we cannot open it was false. Unfortunately, I couldn't apply the first solution due to a dependency issue on my malware analysis machine. In the end, there were two possible solutions.

  • Using gdb(GNU debugger) we could have stepped through the program, and we'd have seen that it was basically iterating and decrypting a string

  • Reading the assembly and using the that IDA displays for our values, we could have used Cyberchef to decrypt our string fairly easily. In the end, the solution to our problem was finding the correct flag for it, which is as follows: HTB{tr4c1ng_th3_c4ll5}

What did we learn

In this exercise, which is a relatively simple one, I learned that while yes, stepping through a program and analyzing what it does step by step is very useful when it comes to malware analysis, but that looking at the big picture is also important. I probably could have done this myself in the end had I looked at the big picture a bit more Additionally, I learned that this field is definitely for me. It was engaging, frustrating, satisfying to work around the problem, and reminded me of my early days of software development as a junior where everything is new.

A very big thank you to

Last updated

Was this helpful?