2017. 5. 30. 09:14ㆍSystemHacking/FTZ
level19번 문제입니다
이번 문제는 에그쉘을 이용해 쉘을 실행시키는 방법과 RTL기법을 활용해서 문제를 풀어보도록 하겠습니다
먼저 힌트파일을 보겠습니다.
< 그림 19.1 >
다른 문제들과 다르게 소스파일에 setreuid() 함수가 없습니다
따라서 이전 문제처럼 쉘 생성코드만 작성하고 실행시킨다고 level20계정의 권한을 얻을 수 없습니다
setreuid()함수를 실행할 수 있는 코드를 직접 만들어야 합니다
이제 해당 파일의 스택구조를 살펴보겠습니다
< 그림 19.2 >
gdb분석 결과 Procedure prelude 과정에서 sub $0x28,$esp 부분이 보이실겁니다
40byte만큼 지역변수 공간을 할당해주었습니다. 따라서 스택구조는 다음과 같습니다
buffer |
SFP |
RET |
환경변수 등등.. |
40byte |
4byte |
4byte |
... |
해당 문제 풀이방법은 2가지가 있습니다. 먼저 익숙한 에그쉘을 이용해서 풀어보도록 하겠습니다
1.에그쉘을 이용한 문제풀이
< 그림 19.3 >
기존의 쉘 생성코드는 단순히 쉘을 실행시키는 코드만 들어있었습니다
따라서 해당 쉘코드를 RET주소에 넣어서 쉘을 실행시켜도 권한은 level19입니다
그럼 쉘 생성코드에 setreuid()함수를 실행시키는 코드를 작성시켜 환경변수에 저장시키면 해당권한을 가져올 수 있습니다
setreuid()함수 코드를 작성해볼까요?
< 그림 19.4 >
에그쉘파일에서 기존의 쉘 코드를 setreuid(3100,3100) 코드를 추가하였습니다
( 어셈블러코드를 잘 몰라서 얻어왔습니다... )
< 그림 19.5 >
해당 에그쉘 파일을 컴파일하여 실행시키면 level20권한의 setreuid가 걸려있는 쉘을 실행시키는 환경변수가 저장된다
그 환경변수의 주소를 얻어와서 버퍼 오버 플로우 시켜 RET주소공간에 넣어주면 쉘이 떨어지게된다
에그쉘에 대해서 잘 모르신다면 해당 링크에 설명해두었습니다. http://itsaessak.tistory.com/113
이제 이번 문제의 하이라이트인 RTL기법에 대해서 소개해드리겠습니다
2. RTL기법 ( Return to Libc )
RTL기법은 스텍 영역의 코드를 실행하지 못하게 하는 non-executable stack보호기법 등을 뚫기 위해 고안된 공격법입니다
함수들은 libc 라는 라이브러리에 저장되는데 해당 함수가 저장되어 있는 주소를 RET주소공간에 덮어씌워서 프로그램이 종료될 때
RET에 덮어 씌운 함수를 실행시키는 원리이다
그럼 쉘을 떨어뜨리려면 어떤 함수를 사용해야 할까? 여기서는 " system("/bin/sh") " 을 사용해보겠습니다
먼저 " system() " 함수의 libc에서의 주소를 알아내야합니다
< 그림 19.6 >
먼저 system함수를 실행시키는 소스파일을 하나 작성하고, gdb를 실행시킵니다
< 그림 19.7 >
해당 프로그램의 Procedure prelude 과정에서 libc 라이브러리를 호출한 직후에 break를 걸어주었습니다
함수를 호출한 지점은 "0x8048258" 이지만 libc 라이브러리에서의 system()함수의 시작점을 구해야합니다
system()함수의 시작점 : 0x4203f2c0
exit()함수의 시작점 : 0x42029bb0
그리고 system()함수의 인자로 들어갈 " /bin/sh " 문자열 만들어보도록 하겠습니다
< 그림 19.8 >
환경변수 LV19를 " /bin/sh "라는 문자열로 초기화 시키고 환경변수의 주소를 얻어왔습니다
에그쉘을 사용하지 않고 사용자가 직접 환경변수를 설정하고 그 주소를 얻어오는 과정은 생략했습니다
해당 과정을 모르신다면 다음 링크를 참고하세요. http://itsaessak.tistory.com/111
[ 스택구조 ]
buffer |
SFP |
RET ( &system() ) |
&exit() |
&LV19(/bin/sh) |
"A" * 40 |
"A" * 4 |
\xc0\xf2\x03\x42 |
\xb0\x9b\x02\x42 |
\xaf\xff\xff\xbf |
해당 프로그램이 종료될 때 RET주소에 있는 system()함수의 시작주소로 이동한다
그리고 +8byte 지점의 주소값을 인자로 가져온 뒤 실행시키고 exit()함수를 실행하여 함수를 종료한다
=> 쉘이 떨어진다 ( setreuid()함수의 부재로 level19의 권한으로 실행된다
참고로 exit()함수의 시작주소는 정상적으로 함수를 종료시키기 위해 넣어놓은 것 ( 아무값이나 넣어도 됩니다 )
하지만 &system()함수의 위치 + 8byte 지점에는 인자값이 있어야 합니다.
간단히 이유를 말하면 함수가 호출되면 함수종료시 실행할 명령어주소를 스택에 대입하고 base pointer를 대입하고 함수를 실행한다
즉, 함수의 인자로 들어갈 값들은 이미 스택에 push되어 있고 그 아래로 다음 명령어의 주소 , base pointer 가 차례로 push된다
이번 문제에서 base pointer 는 RET주소공간에 있는 값 ( &system() ) 이 되고, 다음 명령어의 주소는 &exit() 가 됩니다
함수의 인자로 들어갈 위치에는 &LV19 가 있으므로 해당 값이 system()함수의 인자로 들어가게되는 것입니다
이해가 잘안된다면 http://itsaessak.tistory.com/110 해당 페이지를 참고하세요
RTL기법에 대해서 어느정도 이해가 되었을 겁니다. 이제 RTL Chaining 기술을 소개해드리겠습니다. ( setreuid()사용을 위해 )
RTL Chaing
쉽게말해서 소스코드를 엮어서 사용하겠다. why? setreuid() 함수의 코드와 system()함수 코드를 함께 사용해야 하니까
그럼 먼저 setreuid()함수의 libc에서의 주소를 알아야겠습니다
위에서 system()함수의 주소를 알아낸 것과 같은 방식으로 구합니다
< 그림 19.9 >
setreuid()함수의 시작주소 : 0x420d7920
그리고 여기서 한가지 더 중요한 개념이있다
PPR ( Pop - Pop - Ret )가젯 : 스택의 push되어있는 값을 pop하여 꺼내고 (2개) , 다음 주소로 return 한다
그림으로 표현 해보겠습니다
[ 스택 구조 ]
buffer |
SFP |
RET &setreuid() |
PPR |
argv1 |
argv2 |
RET &system() |
&exit() |
&LV19 (/bin/sh) |
"A" * 40 |
"A" * 4 |
\x20\x79\x0d\x42 |
A |
B |
C |
\xc0\xf2\x03\x42 |
\xb0\x9b\x02\x42 |
\xaf\xff\xff\xbf |
먼저 프로그램이 실행되면, 44byte만큼 버퍼오버플로우 되고 RET주소에 있는 setreuid()함수가 실행됩니다
B , C 를 pop하여 인자로 사용한 후 함수가 종료되면 다시 system()함수의 주소로 리턴됩니다.
A와 B, C가 어떤 값인지 알아보도록 하겠습니다. B와C는 setreuid()함수에 들어갈 인자값에 해당합니다
$cat /etc/passwd 명령을 통해 level20의 UID값이 3100 임을 알아냈습니다
B,C : " \xc1c "
Pop_Pop_Ret 가젯을 구하기 위해서 공격대상파일에서 쓸 수있는 코드가 있는지 확인해 봅시다
[level19 @FTZ tmp]$ objdump -d /home/level19/attackme | grep "ret" -B3
< 그림 19.10 >
" objdump " 명령어로 기계어를 출력하고 " -d " 옵션으로 파일을 disassemble하였고 그 중에서 문자 " ret " 를 찾아서 위 3줄을
출력하도록 하였습니다
< 그림 19.11 >
Pop_Pop_Ret가젯으로 사용할 코드를 찾아냈습니다. ( pop - pop - ret 순으로 실행 )
Pop_Pop_Ret 가젯의 주소는 " 0x0804849d " 가 되겠습니다
필요한 코드는 모두 구했습니다. 그럼 실제로 공격파일에 적용 시켜보겠습니다.
&setreuid() : 0x420d7920
&PPR : 0x0804849d
argv1,argv2 : 0x00000c1c
&system() : 0x4203f2c0
&exit() : 0x42029bb0
&/bin/sh : 0xbfffffaf
[ 스택 구조 ]
buffer |
SFP |
RET |
PPR |
argv1 |
argv2 |
RET &system() |
&exit() |
&LV19 (/bin/sh) |
< 그림 19.12 >
level20의 권한으로 쉘이 떨어진 것을 확인 할 수 있습니다. 공격성공 !
* RTL기법 : libc에 저장된 함수의 시작주소를 RET주소위에 덮어 씌운다
* 해당 함수에 인자를 대입시키려면 RET주소 + 8 byte 지점에 인자를 입력해야한다 ( Stack의 특성 )
* 현 문제에서는 setreuid()함수가 실행되지 않아 직접 작성하였다
=> 1번방법에서는 어셈블러코드를 작성해서 에그쉘을 이용한 환경변수 생성 및 주소를 이용한 공격
=> 2번방법에서는 setreuid()함수의 libc에서의 시작주소를 알아내고 PPR가젯을 이용한 pop과 ret명령어를 활용하여 권한을 얻고 쉘을 얻어냈다
'SystemHacking > FTZ' 카테고리의 다른 글
FTZ level20 포맷 스트링 버그 [FSB] (0) | 2017.05.30 |
---|---|
FTZ level18 포인터 특성 활용 (0) | 2017.05.28 |
FTZ level17 포인터 변조 2 (0) | 2017.05.28 |
FTZ level16 포인터 변조 1 (0) | 2017.05.23 |
FTZ level15 분기 루틴 2 (0) | 2017.05.23 |