coded_conspiracy

Original Writeup on finnersioâs blog
As part of the challenge we are provided with a binary and something to netcat to, we also know these programs are communicating with each other.
Running file
on the provided binary we see itâs stripped, meaning we wonât have any debugging symbols like function names to help us analyse the program.
$ file mystery
mystery: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
Running the strings
command we can see the file is presumably written in the go programming language.
$ strings mystery | tail
.noptrbss
.go.fuzzcntrs
.go.buildinfo
.elfdata
.rodata
.typelink
.itablink
.gosymtab
.gopclntab
.shstrtab
Running the binary, we get what looks to be gibberish or encoded data:
./mystery
Received: bhOz*
;
*
rt^RGLwOQ~DH~N1iSu^Yu^OSL~oODoToGP tDH~DH6fYuMHs(
tDR~IHrER!
_wEO~'6_KH~VER7
+
o~Z)/
+ +
{V~1yYi\Yi^ip]
hK_4 (k 1cGP;\YiYUtD9~D_tNUuM9COt#6$6'
xTihBzy;BHvFK~Wc4k(i4nh_
dS~qW
5OX]uYUoCSuKP4y6;
;
;
6^NzDOr^UtD]wXoN% s^Qw*xOncBHvF
DvFRhs^Hk4]KlK(SiM*"Ds^QcGP!F]uM9OR9
;UEH;cQkFYvORoOX'Hr^P~6sO]6^tNE% 5T* +6
% 5'^tNE% 4BHvFB
For those wondering what this says, youâll want to investigate the while loop at the end of the main function
We get some more gibberish when we connect via nc
:
$ nc chals.secedu.site 5018
DS;LPzM}EN;SSn
After doing a quick google on reversing Go binaries it looks like you can get most of the function names back in debuggers like IDA and Ghidra using some scripts. I decided to use Ghidra and GoReSym to get the function names back.
After running GoReSym we can see a main.main
function is identified in the functions window. There is a lot of stuff going on but right near the top of the function is a for loop which is XORâing some variable.
for (lVar4 = 0; lVar4 < 0x29; lVar4 = lVar4 + 1) {
uVar2 = lVar4 + (SUB168(SEXT816(-0x5555555555555555) * SEXT816(lVar4),8) + lVar4 >> 1) * -3;
if (2 < uVar2) goto LAB_004d2ea5;
*(byte *)(lVar1 + lVar4) = *(byte *)((long)&local_7b + uVar2) ^ *(byte *)(lVar4 + local_18);
}
Letâs investigate, click on the beginning of the for loop and take a look at the listing window in ghidra and find the memory address for the instruction. Start up gdb and set a breakpoint:
gdb mystery
(gdb) break *0x004d2be4
Breakpoint 1 at 0x4d2be4
(gdb) r
Thread 1 "mystery" hit Breakpoint 1, 0x00000000004d2be4 in ?? ()
After taking a look at the registries, I didnât find much. Letâs see what they look like after an iteration of the loop.
(gdb) c
Continuing.
Thread 1 "mystery" hit Breakpoint 1, 0x00000000004d2be4 in ?? ()
(gdb) i r
...
(gdb) x/s $rsi
0xc0000b6000: "Hello, Server! Can I get the flag please?"
(gdb) x/s $rax
0xc00001c0f0: "b"
After inspecting all the registries I found rsi
and rax
were storing strings, presumably the data being XORâd in rsi
and the result of the XOR in rax
. Letâs find out, back in Ghidra find the ^ in the for loopâs body and set another breakpoint in gdb at this memory address.
(gdb) break *0x004d2bcc
Breakpoint 2 at 0x4d2bcc
(gdb) r
(gdb) c
(gdb) c
Continuing.
Thread 1 "mystery" hit Breakpoint 2, 0x00000000004d2bcc in ?? ()
Analysing the instruction pointer we can see edx
and edi
are being XORâd
(gdb) x/i $rip
=> 0x4d2bcc: xor %edx,%edi
(gdb) i r
...
rdx 0x48 72
rdi 0x2a 42
...
We see rdx
is storing 0x48
which corresponds to the ASCII value of âHâ and rdi
is storing 0x2a
. 0x48 ^ 0x2a = 0x62
aka âbâ, terrific news weâll call it a day and skip to the end of the for loopâŠ
(gdb) x/s $rsi
0xc0000b2000: "Hello, Server! Can I get the flag please?"
(gdb) x/s $rax
0xc0000b2030: "bYwFS7\no~XJ~X\035;i]u\nu;MYo\nHsO\034}F]|\nLwO]hO\003"
Ah, not so fast rsi ^ 0x2a
is not whatâs ended up in rax
, maybe the key is different for every characterâŠ
Letâs head back to breakpoint 2 and continue through the loop, examining the contents of the XOR key in rdi
each time.
// First iteration
rdi = 0x2a
// Second Iteration
rdi = 0x3c
// Third Iteration
rdi = 0x1b
// Fourth iteration
rdi = 0x2a
// Fifth Iteration
rdi = 0x3c
// Sixth Iteration
rdi = 0x1b
...
From this we can determine the XOR key is 2a3c1b
. We can also confirm this by looking at the value of rax
which increments a counter to 2 on each iteration of the loop before resetting to 0.
Letâs send the string in rax
to the server and see what we get:
$ echo -ne "bYwFS7\no~XJ~X\035;i]u\nu;MYo\nHsO\034}F]|\nLwO]hO\003" | nc chals.secedu.site 5018
bYwFS7
_wCYu^;O~
HsCO;^S;XYj_Yh^oBY;LPzM;DSuERt
#ZNZz#(
We get a different response this time, letâs decode this with our new found XOR key:
Hello, client! Use this to request the flag: nonono5783fddfa9383839
Take the nonono5783fddfa9383839
and XOR that with the key and convert the result to hex with delimiter \x
using cyberchef. Letâs send that back to the server like it asked:
$ echo -ne "\x44\x53\x75\x45\x52\x74\x1f\x0b\x23\x19\x5a\x7f\x4e\x5a\x7a\x13\x0f\x23\x19\x04\x28\x13" | nc chals.secedu.site 5018 | xxd
We get some non-ascii characters in the response so I will take a hexdump instead and again XOR the result in cyberchef for the flag: SECEDU{X0R_Y0UR_3Y3S_0NLY}
Flag: SECEDU{X0R_Y0UR_3Y3S_0NLY}