ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • ELF Technique - RTL(Return To Library)
    System hacking training/Knowledge 2018. 2. 16. 16:58

    RTL이란?


    return to library 의 약자이고 linux에서는 return to libc라고 불리기도 한다.

    (linux에서 library가 libc)


    이 기법을 이용하면 프로그램에 system()가 없어도 라이브러리의 system()를 호출하여 사용이 가능하다.


    이 기법을 익히기 전에 먼저 알고가야할 것들이 있다.


    바로 plt와 got이다.




    plt 란?

    procedure linkage table의 약자로, 사용자가 만든 함수는 plt를 참조할 필요가 없지만 외부 라이브러리에서 가져다 쓸 경우 plt를 참조하게 된다.

    예를 들어 우리가 바이너리에서 만든 함수들 (main(), func() 등)은 plt를 참조할 필요가 없다.

    plt는 어떤 함수들이 나열되어있는 테이블이라고 생각을 하고 넘어간다.


    got 란?

    global offset table의 약자로, 함수들의 주소를 담고 있는 테이블이다.

    실제 함수들의 주소를 담고있는 테이블이고,

    라이브러리에서 함수를 호출할때 plt가 got를 참조한다.


    결론적으로

    어떤 외부 라이브러리에서 함수를 사용할때 plt에서 got로 넘어가고 got에는 실제 라이브러리 함수의 주소가 들어있다.


    [gdb로 plt에 들어간 함수 확인]


    뒤에 @plt가 붙어있는것이 plt 테이블에 들어가 있는 외부 라이브러리 함수이다.


    // plt 와 got에 대한 내용은 좀 복잡하고 어려워서 나중에 깊이 공부해야겠다.




    다시 RTL로 넘어와서 이 기법은 DEP/NX를 우회하기 위함인데


    여기서 DEP는 데이터 실행 방지로 스택이나 힙에서 쉘코드 실행을 막아주는 메모리 보호 기법이다.

    (자세한 내용 : http://hackstoryadmin.tistory.com/56?category=276534 )


    따라서 DEP/NX 가 걸린 바이너리는 쉘코드를 실행시키지 못하기 때문에 쉘코드를 사용하지 않는 RTL로 우회를 한다.


    직접 해보기 위해 바이너리 하나를 만들었다.




    [RTL.c]

    #include <stdio.h>


    int main(int argc, char *argv[])

    {

        char buf[128];

        strcpy(buf,argv[1]);


        printf("%s\n",buf);


        return 0;

    }


    이 예제 바이너리를 보면 system()가 호출 되지 않았다.


    하지만 RTL을 이용하여 system("/bin/sh")를 실행시켜보겠다.


    메모리 보호기법중 DEP/NX 만 걸고 컴파일을 하였다.


    물론 ASLR도 해제하였다.(system()의 주소가 계속 변하면 곤란하자낭ㅎ)


    [gdb RTL]



    먼저 컴파일 옵션에서 dummy를 제거하였기 때문에 버퍼가 128byte, SFP 4byte를 채운 뒤 system()의 주소를 구하여 ret에 넣어주면 system()가 호출되고,

    인자로 /bin/sh를 넣으면 쉘을 띄울 수 있다.


    먼저 스택 구조를 확인해보면


    | char buf[128] | SFP | RET | dummy | parameter |


    이런 구조인것을 알 수 있다.


    RET에 system()의 주소를 넣어주고, 인자로 /bin/sh를 넣어줘야하는데


    중간에 dummy가 있다.


    이 dummy에는 return address 다음 return 할 address가 저장되어있다.


    따라서 인자로 /bin/sh를 넣기 위해 dummy 4byte를 덮어준 다음 위치에 가서 인자를 넣어줘야한다.


    이제 /bin/sh를 어떻게 인자로 넣어줄지 결정해야하는데 


    이는 코드 섹션에 고정되어 있는 값을 이용하였다. (변할일이 없겠쥬?)



    // 먼저 p system으로 시스템함수의 주소를 구했고


    코드 섹션에서 키보드로 입력할 수 있는 아스키값 하나 잡고


    ./(아스키값) 이라는 실행파일에 /bin/sh를 카피하여 쉘이 실행되도록 만들고, 환경변수 PATH에 현재 위치를 등록함으로써


    해당 아스키값을 실행하면 쉘이 실행되도록 만들어주었다.


    여기서 0x44 == D 를 이용하였다.(주소는 0x80480e4)



    이 처럼 ./D (D는 아스키값)를 입력하면 쉘이 실행된다.


    따라서 이런 페이로드로 쉘을 실행할 수 있었다.



    | AAA....(132개) | system()의 주소 | AAAA(dummy) | D의 주소 |



    이렇게 SFP까지 임의의 값 A로 덮어버리고, RET를 system()의 주소로 덮은 뒤

    /bin/sh를 띄울 수 있는 D의 주소를 적어주었다. 


    '''

    함수가 호출되었을때 첫번째 스택은 그 다음 리턴될 곳을 가리키고 있고

    바로 그 다음이 함수의 인자를 가리키기 때문에 AAAA 4byte 를 덮어주었다. 

    '''


    참고 : http://shayete.tistory.com/entry/4-Return-to-Library-RTL?category=857069


    RTL_Attack_정리.txt


    반응형

    'System hacking training > Knowledge' 카테고리의 다른 글

    ELF PLT & GOT  (1) 2018.02.27
    ELF Technique - RTL Chaining  (1) 2018.02.22
    gdb 명령어  (0) 2018.02.13
    ELF Memory Protection - DEP/NX  (0) 2018.02.10
    ELF Memory Protection - ASCII Armor  (0) 2018.02.06
Designed by Tistory.