FTZ level19 Return to Libc

2017. 5. 30. 09:14SystemHacking/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

 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
&setreuid()

 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