BSidesSF CTF 2019 - dribbles (250pt)
blind reversing
March 4, 2019
reversing
dribbles (250pt)
Reversing
Description: You’ll have to “dribble” some information out for this one…
Location - dribbles-c4d3cee3.challenges.bsidessf.net:9999
Solution
This challenge does not include a file, so we need to first gather information from the remote server.
When we connect, we are able to enter a symbol that will be resolved:
[1/3] Resolve symbol>
Typing in main
for example gives us:
[1/3] Resolve symbol> main
main (buf@0x7ffd97ee7220) = 0x55ed193b43a9
[2/3] Resolve symbol>
From this we can tell that PIE is enabled. After we resolve three symbols, the program allows us to read chunks of memory:
Provide address and number of bytes to read>
At this point it would be useful to read the entire file so we have something to work with. Since this is a PIE binary, the base of the file is going to be aligned and equal to the PIE base. First I guessed that it would simply be main - 0x3a9
however this was incorrect. I guessed again main - 0x13a9
and this resulted in reading an ELF header as such:
Provide address and number of bytes to read> 0x55ed193b3000 20
0x55ed193b3000: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
0x55ed193b3010: 03 00 3e 00
The binary appeared to limit how large the chunk could be so I wrote a small program that read the entire file piece by piece and wrote the output to a file.
After opening the file in Hopper, we need to do a bit of cleaning up to make sure the procedures are loaded. Eventually, we obtain some useful assembly.
At the start of the main
routine, we see a strange call that involves the string “flag.txt”. After some reversing, it essentially boils down to the following pseudocode:
FILE *f = open("flag.txt");
int64_t *buf = malloc(0x10);
buf[0] = 1;
// mmap will return a pointer to the new memory region
buf[1] = mmap(0, 0x1000, 1, 2, f, 0);
buf[1] ^= 0x5555555555555555;
So we know that the flag file is memory mapped to some region and we have a buffer (on the heap) that contains a pointer. We also know that there is a pointer to the buffer on the stack since this is a local variable in the main
method. At this point we need a stack leak to start reading memory.
Luckly we can use the environ
symbol in the libc library to leak a stack pointer.
[3/3] Resolve symbol> environ
environ (buf@0x7ffc36c61d50) = 0x7f37c4a0ef38
Provide address and number of bytes to read> 0x7f37c4a0ef38, 8
0x7f37c4a0ef38: ffffff98 1f ffffffc6 36 fffffffc 7f 00 00
(the large looking values are just bytes being printed as 4-bit signed bytes, hence the leading 0xff
’s)
Using this stack leak, I essentially wrote a program that would traverse the stack backwards and dereference each values as a buffer pointer. Then I tried to XOR the second buffer item and dereference it as another pointer. Eventually, I found the stack offset that corresponded with the buf
pointer and I was able to read the flag from the memory mapped region.