ELFx64 GolangBasic

A simple writeup about a CTF from Rootme

28/12/2021

Introduction

I would like to write something about this CTF because it makes me take a deeper look at how a simple Go binary is formed. When just looking over a binary formed from Go it’s impossible not to think how weird this binary is, more because of the large size for small instructions written, easily a “Hello World” compiled gets more than one megabyte.

The main reason is because all of those functions called “runtime” (light weight threads) have the ability to improve things in executing time, automating management that in turn of other languages ​​like C would demand a lot from the developer even if building programs with simple goals. Go as a language is aiming to be simple but empowered for high scaling, performance and security.

Go includes in its binary a more powerful runtime support which provides a garbage collection process to manage those objects that are no longer in use allocated in heap memory. Garbage collection will usually affect performance, in fact, Go spends a disproportionate amount of time collecting garbage and this can be seen in any benchmark, however this feature probably will help a lot by automating explicit deallocation and avoiding its problems, but that’s not the focus at the moment.

Another look at the importance of knowing how to analyse binaries from the Golang compiler it is because a lot of malware is being created in this way, with perhaps the most interesting example, the formidable Mirai Botnet, the one that made CDNs suck in 2016, what a good story.

The syntax is simple, powerful and the libraries are already compiled along with the code, another important point for the file size. And it’s fast, so simpler programs use fewer resources. Want a better way to create malware?

The CTF

In reviewing this reverse engineering and cracking CTF I will not be using any functionality to recreate a pseudo code from the instructions that some tools provide because assembly is cooler and a pain at the same time, but alright.

When running the binary on the machine, it asks for user input, after that it prints the message “wrong flag” on the screen and terminates the process, so it needs the correct password.

To debug the binary I usually like to use the GDB (GNU Debugger) with a plugin named Gef, which extends the GDB a lot in the matter of possibilities and also makes the interface more intuitive.

After running gdb the first thing to do is to list all functions and try to take some good information from this enumeration, however, the number of functions is easily bigger than one thousand, so it’s not helpful to analyze it, because it would take a long time.

The first step is to set a breakpoint at entry to function “main” which initializes the program.

Disassembly Main

gef➤ disas main

Dump of assembler code for function main:
   0x0000000000452310 <+0>:    lea    rax,[rip+0xffffffffffffc7a9]        # 0x44eac0 <runtime.rt0_go>
   0x0000000000452317 <+7>:    jmp    rax

What appears to be a “runtime” (function), there is nothing useful in the main() function. If we dig in a bit further we can see that the actual code we are interested in is inside of main.main that really has the main functions inside this.

disas *main.main

!The full code is at the end!

The main function is extensive which makes me think that all the code worth analyzing is in here, the rest are imported libraries. There are some interesting functions to mention right at the beginning.

This part is not important for resolution but it is how a new object (structure) is created. Objects are instantiated using runtime.newobject, taking a structure pointer as an argument. The structure definition is being defined in the .typelink section of the binary.

<+47>:    lea    rax,[rip+0x1053a]        # 0x4a33e0
<+54>:    mov    QWORD PTR [rsp],rax
<+58>:    call   0x40ec00 <runtime.newobject>

Inside main +150 there is a function that waits for user input:

<+150>:    call   0x48d970 <fmt.Scanln>

What was entered is sent to memory and its address pointer is stored in the register r10.

$r10   : 0x000000c4200180d0  →  0x0000000000616161 ("aaa"?)
…
gef➤  print $r10
$1 =  0xc4200180d0
gef➤  x/1xs $r10
0xc4200180d0:    "aaa")

Then there is a loop passing the string into a xor function, which uses “rootme” as a key to encode the input from the user.

Another thing to pay attention to when analyzing Go binaries is that strings do not end in null bytes, and are usually concatenated with other strings, so it is always important to pay attention to the length of the string that is passed along with it.

Using the tool radare2 makes it more friendly to see the memory exchanges with strings ascii format.

0488d053a1503.   lea rax, [0x004c446d]   ; "rootmesignalstatusstringstructsw…
4889442408       mov qword [var_8h], rax
48c744241006.    mov qword [var_10h], 6

The fragment above shows an address being loaded into rax, the address refers to a string which contains the key. As mentioned Go binaries does not separate strings with null bytes, the line below is moving the length in bytes that will be loaded.

$r8    : 0x000000c42003df10  →  0x0000656d746f6f72 ("rootme"?)
…
    0x492fed <main.main+381>  movzx  edx, BYTE PTR [r8+rdx*1]
→   0x492ff2 <main.main+386>  xor    r10d, edx

The xor function will be called in the loop the number of times it relates to the length of the string entered, and then register r9 will be incremented each time it passes through the loop. which defines the position of the array that will index the character.

the value representing the position in the key array is also incremented, in this way the string character is XORed with the character that matches with it in the key.

If the current character of the entered string is not the last character, the loop continues performing a jump to main.

<+318>:    inc    r9
….
<+381>:    movzx  edx, BYTE PTR [r8+rdx*1]
<+386>:    xor    r10d, edx
<+389>:    cmp    r9, rcx
<+392>:    jb     0x492fa7 <main.main+311>

r10d The current caractere from the entered string. rcx The length of the entered string. edx Current string from the key. jb Jump if below.

Once the string has been encoded it will be sent as the argument to a function that compares bytes to validate if the entered password is the correct one. then there is the password already encoded stored in memory, this password just needs to be found.

<+404>:    mov  QWORD PTR [rsp],rbx
<+408>:    mov  QWORD PTR [rsp+0x8],0xe
<+417>:    mov  QWORD PTR [rsp+0x10],0xe
<+426>:    mov  QWORD PTR [rsp+0x18],rdx
<+431>:    mov  QWORD PTR [rsp+0x20],rcx
<+436>:    mov  QWORD PTR [rsp+0x28],rax
<+441>:    call   0x4510d0 <bytes.Compare>

I set a breakpoint at the calling of the “bytes.Compare” function and ran the program. In the code above it is possible to see that the content from the register rbx has been moved to rsp. Then the value 0xe in hex is moved as well, which will be passed as an argument being the length of the string.

In this way it is possible to extract the contents of rbx in a range of 14 (0xe) bytes, as the length of the string is seen being passed to rsp+0x10.

gef➤  x/14xb $rbx
0x3b    0x02    0x23    0x1b    0x1b    0x0c    0x1c    0x08
0x28    0x1b    0x21    0x04    0x1c    0x0b

Decoding this byte string with the key “rootme” using the xor function the result is: ImLoving******

$ ./ch32.bin  
ImLoving******
u can validate with this flag

Conclusion

I learnt from this CTF that analysing Golang binaries is a pain at the first look, but understanding how it works and how the functions are handled, it is very intuitive. The assembly formed can look like a mess when comparing with C, but it is unfair, considering that Golango’s own team cites it as the new C and that, the attribution of easier to use, in thi case other features are lost such as the simplicity of instructions, which gives the quality of speed and lightness.

Full code

Here i left the full code from the main.main().

Dump of assembler code for function main.main:                                                                                                                                                                                                                                                                                                                                                                                                                        
   0x0000000000492e70 <+0>:     mov    rcx,QWORD PTR fs:0xfffffffffffffff8                                                                                                                                                                                                                                                                                                                                                                                            
   0x0000000000492e79 <+9>:     lea    rax,[rsp-0x38]                                                                                                                                                                                                                                                                                                                                                                                                                 
   0x0000000000492e7e <+14>:    cmp    rax,QWORD PTR [rcx+0x10]                                                                                                                                                                                                                                                                                                                                                                                                       
   0x0000000000492e82 <+18>:    jbe    0x49310a                                                                                                                                                                                                                                                                                                                                                                                                        
   0x0000000000492e88 <+24>:    sub    rsp,0xb8                                                                                                                                                                                                                                                                                                                                                                                                                       
   0x0000000000492e8f <+31>:    mov    QWORD PTR [rsp+0xb0],rbp                                                                                                                                                                                                                                                                                                                                                                                                       
   0x0000000000492e97 <+39>:    lea    rbp,[rsp+0xb0]                                                                                                                                                                                                                                                                                                                                                                                                                 
   0x0000000000492e9f <+47>:    lea    rax,[rip+0x1053a]        # 0x4a33e0                                                                                                                                                                                                                                                                                                                                                                                            
   0x0000000000492ea6 <+54>:    mov    QWORD PTR [rsp],rax                                                                                                                                                                                                                                                                                                                                                                                                            
   0x0000000000492eaa <+58>:    call   0x40ec00                                                                                                                                                                                                                                                                                                                                                                                                    
   0x0000000000492eaf <+63>:    mov    rax,QWORD PTR [rsp+0x8]                                                                                                                                                                                                                                                                                                                                                                                                        
   0x0000000000492eb4 <+68>:    mov    QWORD PTR [rsp+0x78],rax                                                                                                                                                                                                                                                                                                                                                                                                       
   0x0000000000492eb9 <+73>:    mov    QWORD PTR [rsp+0x80],0x0                                                                                                                                                                                                                                                                                                                                                                                                       
   0x0000000000492ec5 <+85>:    mov    QWORD PTR [rsp+0x88],0x0                                                                                                                                                                                                                                                                                                                                                                                                       
   0x0000000000492ed1 <+97>:    lea    rcx,[rip+0xbea8]        # 0x49ed80                                                                                                                                                                                                                                                                                                                                                                                             
   0x0000000000492ed8 <+104>:   mov    QWORD PTR [rsp+0x80],rcx                                                                                                                                                                                                                                                                                                                                                                                                       
   0x0000000000492ee0 <+112>:   mov    QWORD PTR [rsp+0x88],rax                                                                                                                                                                                                                                                                                                                                                                                                       
   0x0000000000492ee8 <+120>:   lea    rcx,[rsp+0x80]                                                                                                                                                                                                                                                                                                                                                                                                                 
   0x0000000000492ef0 <+128>:   mov    QWORD PTR [rsp],rcx                                                       
   0x0000000000492ef4 <+132>:   mov    QWORD PTR [rsp+0x8],0x1                                                   
   0x0000000000492efd <+141>:   mov    QWORD PTR [rsp+0x10],0x1                                                  
   0x0000000000492f06 <+150>:   call   0x48d970                                                      
   0x0000000000492f0b <+155>:   mov    rax,QWORD PTR [rip+0x4312e]        # 0x4d6040                                                                                                                             
   0x0000000000492f12 <+162>:   mov    rcx,QWORD PTR [rip+0x4312d]        # 0x4d6046                                                                                                                           
   0x0000000000492f19 <+169>:   mov    QWORD PTR [rsp+0x42],rax                                                  
   0x0000000000492f1e <+174>:   mov    QWORD PTR [rsp+0x48],rcx                                                  
   0x0000000000492f23 <+179>:   lea    rax,[rsp+0x50]                                                            
   0x0000000000492f28 <+184>:   mov    QWORD PTR [rsp],rax                                                       
   0x0000000000492f2c <+188>:   lea    rax,[rip+0x3153a]        # 0x4c446d                                                                                                                                                         
   0x0000000000492f33 <+195>:   mov    QWORD PTR [rsp+0x8],rax                                                   
   0x0000000000492f38 <+200>:   mov    QWORD PTR [rsp+0x10],0x6                                                  
   0x0000000000492f41 <+209>:   call   0x43ed90                                                                                                                                                         
   0x0000000000492f46 <+214>:   mov    rax,QWORD PTR [rsp+0x18]                                                  
   0x0000000000492f4b <+219>:   mov    QWORD PTR [rsp+0x70],rax                                                  
   0x0000000000492f50 <+224>:   mov    rcx,QWORD PTR [rsp+0x20]                                                  
   0x0000000000492f55 <+229>:   mov    QWORD PTR [rsp+0x38],rcx                                                  
   0x0000000000492f5a <+234>:   mov    rdx,QWORD PTR [rsp+0x78]                                                  
   0x0000000000492f5f <+239>:   mov    rbx,QWORD PTR [rdx+0x8]                                                   
   0x0000000000492f63 <+243>:   lea    rsi,[rip+0x11756]        # 0x4a46c0                                                                                                                                                         
   0x0000000000492f6a <+250>:   mov    QWORD PTR [rsp],rsi                                                       
   0x0000000000492f6e <+254>:   mov    QWORD PTR [rsp+0x8],rbx                                                   
   0x0000000000492f73 <+259>:   mov    QWORD PTR [rsp+0x10],rbx                                                  
   0x0000000000492f78 <+264>:   call   0x43b1a0                                               
   0x0000000000492f7d <+269>:   mov    rax,QWORD PTR [rsp+0x28]                                                  
   0x0000000000492f82 <+274>:   mov    rcx,QWORD PTR [rsp+0x20]                                                  
   0x0000000000492f87 <+279>:   mov    rdx,QWORD PTR [rsp+0x18]                                                  
   0x0000000000492f8c <+284>:   mov    rbx,QWORD PTR [rsp+0x78]                                                  
   0x0000000000492f91 <+289>:   mov    rsi,QWORD PTR [rbx+0x8]                                                   
   0x0000000000492f95 <+293>:   mov    rbx,QWORD PTR [rbx]                                                       
   0x0000000000492f98 <+296>:   mov    rdi,QWORD PTR [rsp+0x38]                                                  
   0x0000000000492f9d <+301>:   mov    r8,QWORD PTR [rsp+0x70]                                                   
   0x0000000000492fa2 <+306>:   xor    r9d,r9d                                                                   
   0x0000000000492fa5 <+309>:   jmp    0x492fb7                                                   
   0x0000000000492fa7 <+311>:   mov    BYTE PTR [r12+r9*1],r10b                                                  
   0x0000000000492fab <+315>:   inc    rbx                                                                       
   0x0000000000492fae <+318>:   inc    r9                                                                        
   0x0000000000492fb1 <+321>:   mov    rax,r11                                                                   
   0x0000000000492fb4 <+324>:   mov    rdx,r12                                                                   
   0x0000000000492fb7 <+327>:   cmp    r9,rsi                                                                    
   0x0000000000492fba <+330>:   jge    0x492fff                                                   
   0x0000000000492fbc <+332>:   movzx  r10d,BYTE PTR [rbx]                                                       
   0x0000000000492fc0 <+336>:   test   rdi,rdi                                                                   
   0x0000000000492fc3 <+339>:   je     0x493103                                                   
   0x0000000000492fc9 <+345>:   mov    r11,rax                                                                   
   0x0000000000492fcc <+348>:   mov    rax,r9                                                                    
   0x0000000000492fcf <+351>:   mov    r12,rdx                                                                   
   0x0000000000492fd2 <+354>:   cmp    rdi,0xffffffffffffffff                                                    
   0x0000000000492fd6 <+358>:   je     0x492fdf                                                   
   0x0000000000492fd8 <+360>:   cqo                                                                              
   0x0000000000492fda <+362>:   idiv   rdi                                                                       
   0x0000000000492fdd <+365>:   jmp    0x492fe4                                                   
   0x0000000000492fdf <+367>:   neg    rax                                                                       
   0x0000000000492fe2 <+370>:   xor    edx,edx                                                                   
   0x0000000000492fe4 <+372>:   cmp    rdx,rdi                                                                   
   0x0000000000492fe7 <+375>:   jae    0x4930fc                                                   
   0x0000000000492fed <+381>:   movzx  edx,BYTE PTR [r8+rdx*1]                                                   
   0x0000000000492ff2 <+386>:   xor    r10d,edx                                                                  
   0x0000000000492ff5 <+389>:   cmp    r9,rcx                                                                    
   0x0000000000492ff8 <+392>:   jb     0x492fa7                                                   
   0x0000000000492ffa <+394>:   jmp    0x4930fc                                                   
   0x0000000000492fff <+399>:   lea    rbx,[rsp+0x42]                                                            
   0x0000000000493004 <+404>:   mov    QWORD PTR [rsp],rbx                                                       
   0x0000000000493008 <+408>:   mov    QWORD PTR [rsp+0x8],0xe                                                   
   0x0000000000493011 <+417>:   mov    QWORD PTR [rsp+0x10],0xe                                                  
   0x000000000049301a <+426>:   mov    QWORD PTR [rsp+0x18],rdx                                                  
   0x000000000049301f <+431>:   mov    QWORD PTR [rsp+0x20],rcx                                                  
   0x0000000000493024 <+436>:   mov    QWORD PTR [rsp+0x28],rax                                                  
   0x0000000000493029 <+441>:   call   0x4510d0                                                   
   0x000000000049302e <+446>:   mov    rax,QWORD PTR [rsp+0x30]                                                  
   0x0000000000493033 <+451>:   test   rax,rax                                                                   
   0x0000000000493036 <+454>:   jne    0x4930a1                                                   
   0x0000000000493038 <+456>:   mov    QWORD PTR [rsp+0xa0],0x0                                                  
   0x0000000000493044 <+468>:   mov    QWORD PTR [rsp+0xa8],0x0                                                  
   0x0000000000493050 <+480>:   lea    rax,[rip+0x11529]        # 0x4a4580                                                                                                                                                         
   0x0000000000493057 <+487>:   mov    QWORD PTR [rsp+0xa0],rax                                                  
   0x000000000049305f <+495>:   lea    rax,[rip+0x4306a]        # 0x4d60d0                                                                                                                                       
   0x0000000000493066 <+502>:   mov    QWORD PTR [rsp+0xa8],rax                                                  
   0x000000000049306e <+510>:   lea    rax,[rsp+0xa0]                                                            
   0x0000000000493076 <+518>:   mov    QWORD PTR [rsp],rax                                                       
   0x000000000049307a <+522>:   mov    QWORD PTR [rsp+0x8],0x1                                                   
   0x0000000000493083 <+531>:   mov    QWORD PTR [rsp+0x10],0x1                                                  
   0x000000000049308c <+540>:   call   0x486bc0                                                       
   0x0000000000493091 <+545>:   mov    rbp,QWORD PTR [rsp+0xb0]                                                  
   0x0000000000493099 <+553>:   add    rsp,0xb8                                                                  
   0x00000000004930a0 <+560>:   ret 
   0x00000000004930a0 <+560>:   ret                                                                              
   0x00000000004930a1 <+561>:   mov    QWORD PTR [rsp+0x90],0x0                                                  
   0x00000000004930ad <+573>:   mov    QWORD PTR [rsp+0x98],0x0                                                  
   0x00000000004930b9 <+585>:   lea    rax,[rip+0x114c0]        # 0x4a4580                                                                                                                                                         
   0x00000000004930c0 <+592>:   mov    QWORD PTR [rsp+0x90],rax                                                  
   0x00000000004930c8 <+600>:   lea    rax,[rip+0x43011]        # 0x4d60e0                                                                                                                                       
   0x00000000004930cf <+607>:   mov    QWORD PTR [rsp+0x98],rax                                                  
   0x00000000004930d7 <+615>:   lea    rax,[rsp+0x90]                                                            
   0x00000000004930df <+623>:   mov    QWORD PTR [rsp],rax                                                       
   0x00000000004930e3 <+627>:   mov    QWORD PTR [rsp+0x8],0x1                                                   
   0x00000000004930ec <+636>:   mov    QWORD PTR [rsp+0x10],0x1                                                  
   0x00000000004930f5 <+645>:   call   0x486bc0                                                       
   0x00000000004930fa <+650>:   jmp    0x493091                                                   
   0x00000000004930fc <+652>:   call   0x425a40                                              
   0x0000000000493101 <+657>:   ud2                                                                              
   0x0000000000493103 <+659>:   call   0x425b20                                                                                                                                                               
   0x0000000000493108 <+664>:   ud2                                                                              
   0x000000000049310a <+666>:   call   0x44ef70                                                                                                                                                          
   0x000000000049310f <+671>:   jmp    0x492e70