$ file ./lets_go lets_go: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
When trying to run it, it gives us the usages message.
$ ./lets_go Usage: ./lets_go <password>
So obviously we have to find the password. I opened it in IDA, there are so many subroutines in the executable; this was my first experience with anything related to go so I did not know which subs were library functions or which subs were user defined. To narrow down our subs list i tried string search for
password but they did not lead me anywhere. Nothing fancy, i just searched for main function in IDA and i found these:
runtime_main runtime_main_func1 runtime_main_func2 main main_usage main_iep4thiequai1athieSe main_f1151e71905f3d94b49b0 main_Wuyeiqua4ievohR4ahng main_Xerei4oreeshex6zien0 main_UhoCh5ooSeith0ee7Ien main_main main_init
main function did not have much just jumping to
runtime_rt0_go; so I figured that main must be calling main_* functions at dynamically. So i started reversing main_* functions. I also started analyzing it in gdb at the same time with input “ABCDEFGH” so i can see what was happening with my input. So this is what i found as my first overview of these functions
main_mainis the real main function
- If password is not provided
main.UhoCh5ooSeith0ee7Iento generates a weird string “WPnq7JEM2AskwjoX3VRx9aHbiYfd4#Zp05TUGc1SBCFNgvhz8rQl6@ytIKumDeOL” (this is where i realized that this binary was passing args to function by putting data on stack even though it was 64 bit compiled, it also returned values on stack)
main.Xerei4oreeshex6zien0(check for password happened here)
Now I started to reverse
- Its calling
main_Wuyeiqua4ievohR4ahngwhich is taking (my password, password_len, weird_string, weird_string_len) as input and generating a base64 like string as its output (for input password “ABCDEFGH” output of this function was “39AqV7aEV60==”) but I could not decode it
- Then a byte by byte checking happens with output of
main_Wuyeiqua4ievohR4ahng(“39AqV7aEV60==”) with a fixed string “R6aYb@VboTG==”
- Still there was a lot of code in this function but I did not bother for this at this time; first I had to validate the check above.
After a little thought and looking at base64 wiki page I realized that in base64 algorithm after splitting the plain text into 6 bits; value of that 6 bits is taken as an index to “ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+”
So for example “000101”(5) indexed to “ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+” gives “F”
As length of
WPnq7JEM2AskwjoX3VRx9aHbiYfd4#Zp05TUGc1SBCFNgvhz8rQl6@ytIKumDeOL string was also 64; I thought maybe its indexing from this string to generate a base64 like string.
So I made a decoder for this base64 with
weird_string as index string and fed “R6aYb@VboTG==” into it. And we got the password “KEY_TW:)”.
WAIT BUT THERE IS MORE
As soon as I fed the binary “KEY_TW:)” as password; it asked me to input flag. Such a drag. Time for more reversing.
Now I remembered that I had skipped a lot of code in
- So the code after the password check there was a
fmt_scanto take flag from us through stdin
- Then it was checking if flag length was 0x30 or not (so I made a dummy flag of 48 chars and run the binary in gdb to do binary analysis at the same time)
- Then it splits our flag input into chunks of 8 chars and fed to
- Output of
main_f1151e71905f3d94b49b0(for each 8 bytes of flag) and a fix list of 8 bytes gets fed into
reflect_DeepEqual(I guessed that it just checks both 8byte ints are equal or not). I extracted the fix list of 8 bytes from memory into my python script.
Now it was time to reverse
main_f1151e71905f3d94b49b0 (here I am writing a python like code for this function)
stack_array = fix string on stack; key = "KEY_TW:)" input_flag = flag we want rol = rotate left for i in range(0x20): for j in range(0x8): t = stack_array[key[j] + input_flag[j]] +input_flag[(j+1)%8] input_flag[(j+1)%8] = rol(t)
So we can assume that this is a encryption function which takes key and input_flag as input and its output gets checked to a element of a fix list of 8 bytes
At this moment I wrote a decryption function for this encryption which will basically be this
ror = rotate right for i in range(0x20): for j in range(0x7, -1, -1): t = ror(input_flag[(j+1)%8]) input_flag[(j+1)%8] = t - stack_array[key[j] + input_flag[j]]
Now I just wrote a python script to decrypt fix list of 8 bytes to get the whole flag
#!/usr/bin/python from pwn import * stack_array = [0xc56f6bf27b777c63, 0x76abd7fe2b670130, 0xf04759fa7dc982ca, 0xc072a49cafa2d4ad, 0xccf73f362693fdb7, 0x1531d871f1e5a534, 0x9a059618c323c704, 0x75b227ebe2801207, 0xa05a6e1b1a2c8309, 0x842fe329b3d63b52, 0x5bb1fc20ed00d153, 0xcf584c4a39becb6a, 0x85334d43fbaaefd0, 0xa89f3c507f02f945, 0xf5389d928f40a351, 0xd2f3ff1021dab6bc, 0x1744975fec130ccd, 0x73195d643d7ea7c4, 0x88902a22dc4f8160, 0xdb0b5ede14b8ee46, 0x5c2406490a3a32e0, 0x79e4959162acd3c2, 0xa94ed58d6d37c8e7, 0x8ae7a65eaf4566c, 0xc6b4a61c2e2578ba, 0x8a8bbd4b1f74dde8, 0xef6034866b53e70, 0x9e1dc186b9573561, 0x948ed9691198f8e1, 0xdf2855cee9871e9b, 0x6842e6bf0d89a18c, 0x16bb54b00f2d9941] stack = '' for x in stack_array: stack += p64(x) key = "KEY_TW:)" enc_array = [0x48fd9fdd395cfe4a, 0x555ed4725bde6cf0, 0xb492d5de09fa160, 0x9c326531f39e320e, 0x5eecc9092cef233d, 0x10b4e73f5fd73945] def ror(b_char): t = bin(ord(b_char))[2:].zfill(8) return chr(int((t[-1] + t[:-1]), 2)) def decrypt(enc_int): enc_str = list(p64(enc_int)) for i in range(0x20): for j in range(0x7, -1, -1): t = ror(enc_str[(j+1)%8]) enc_str[(j+1)%8] = chr((ord(t) - ord(stack[(ord(key[j]) + ord(enc_str[j]))&0xff]))&0xff) return ''.join(enc_str) dec_array =  for x in enc_array: dec_array.append(decrypt(x)) print ''.join(dec_array)