ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Linux Exploitation & Mitigation] NX bit / RTL
    System Security/dreamhack 2021. 3. 15. 15:12

     

    * 드림핵 <system exploitation fundamental> 공부한 후 정리한 내용이다.

     

    1. NX bit의 등장

     

    return addr overwrite과 nop sled 에서는 버퍼 오버플로우 취약점을 이용해 스택에 쉘코드를 넣어 해당 쉘코드가 실행될 수 있도록 실행 흐름을 조작하는 방법을 다뤘다. 하지만 일반적인 프로그램에서는 스택을 프로그램을 실행하는 용도로 사용하지 않고 일시적으로 데이터를 읽고 쓰는 데 사용되기 때문에 실행권한이 필요하지 않다. 따라서 공격을 어렵게하기 위하여 메모리에 대해 쓰고 읽는 권한을 주지 않는 No-eXecute bit (NX bit)가 등장하였다.

     

    example2.c

    example2.c는 쉘코드를 데이터 영역에 저장한 후 실행시키는 예제이다.

    서로 다른 컴파일 옵션을 통해 nx bit 보호 기법을 적용한 example2_nx 바이너리와, 적용하지 않은 example_nx 바이너리를 생성한다.

    example2_nx

     

    example2_x

     

    각각 gdb로 디버깅 해서 메모리 권한을 확인해 보자.

    먼저 example2_nx를 디버깅한 결과다.

     

    example2_nx 의 메모리 맵

    shell cat /proc/`pidof example2_x`/maps 명령어는프로세스 아이디가 example2_x인 프로세스의 map을 출력하라는 것이다. 출력 결과를 보면 

    example2_nx의 데이터와 스택영역은 rwx권한을 가지고 있는 것을 확인할 수 있다. 이 경우 해당 바이너리 파일을 실행시키면 정상적으로 쉘이 실행된다.

     

    이제 example2_x의 디버깅 결과를 살펴보자.

    exmaple2_nx 의 메모리 맵

     

    스택과 데이터 영역의 메모리 모두 rw의 권한만 가지고 있다. 이 경우 해당 바이너리 파일을 실행시켰을 때 데이터 영역에 대한 실행 권한이 없기 때문에 segmentation fault가 발생한다.

     

     

    2. Bypassing NX Bit

     

    NX bit가 설정되어 있을 경우에는 쓰기, 실행권한이 동시에 있는 메모리 영역이 존재하지 않는다. 따라서 스택에 쉘코드를 저장해 실행흐름을 바꾸는 공격은 사용할 수 없게 된다. 공격자의 공격 코드를 메모리에 저장할 수 없게 되니, 실행 권한이 있는 메모리 영역에 존재하는 코드만을 이용해 공격해야 한다.

     

    예를 들어 printf 와 같은 라이브러리 함수가 사용될 때, 프로그램은 메모리에 로딩된 라이브러리 파일에서 호출된 함수의 주소를 찾아 실행한다. 프로그램에서 호출된 함수 이외에도 system과 같이 익스플로잇에 유용한 함수 코드들도 함께 로딩된다.

    helloworld를 출력하는 프로그램을 예제로 살펴보자.

     

    HelloWorld 메모리의 맵

     

    0xb7dd0000~0xb7ded000 영역이 libc.so.6 라이브러리 코드영역 주소이다. 해당 printf 함수말고도 다른 함수들이 메모리에 존재한다는 것을 확인할 수 있다. 이처럼 라이브러리 파일에서 호출된 함수의 주소를 찾아 리턴 주소를 이 주소로 변경하면 해당하는 함수가 호출될 수 있다. (스택 버퍼 오버플로우 취약점이 있다는 전제 하에)

    더보기

    libc.so.6 라이브러리

    execve, execlp, execl, execvp, system, popen 등 프로그램을 실행할 수 있는 다양한 함수들이 존재

     

    3. RTL

     

    Return To Libc, RTL 은 리턴 주소를 라이브러리 내에 존재하는 함수의 주소로 바꿔 nx bit를 우회하는 공격 기법이다.

    lib.so.6라이브러리 안 system 함수는 인자가 1개라 익스플로잇 공격에 자주 사용되며 인자로 문자열의 주소를 넣으면 바이너리가 실행된다.

    더보기

    system(실행할 쉘 명령어 문자열의 주소)

     

    example.c 파일에 nx bit를 추가하여 example1_nx로 컴파일해서 RTL 실습을 해보자.

     

    example.c
    example1_nx 생성

     

    retrun address overwrite이나 nop sled는 스택내에 쉘코드를 넣고 실행시켜 execve 시스템 콜을 호출하는 것이 목표였고,

    RTL 실습의 목표는 라이브러리 내에 존재하는 system 함수를 호출해 /bin/sh를 실행시키는 것이다. 쉘코드를 넣어 실행시키는 것이 아니라서 nx bit 보호기법의 우회가 가능하다.

     

     

    # system 함수를 실행하기 위해 알아야 하는 값

     

    ① system 함수의 주소

    -> print 명령어로 system 함수의 주소를 찾는다.

    system()의 주소는 0xb7e14f50이다.

     

    ② /bin/sh 문자열 주소

     

    방법(1)

    find 명령어를 통해 libc.so.6 라이브러리에 존재하는 /bin/sh 문자열의 주소를 찾는다.

    system과 같은 쉘 실행 명령어들은 내부적으로 /bin/sh 를 사용하기 때문에 라이브러리 메모리 안에서 /bin/sh 문자열을 찾을 수 있다.

     

     

     

    방법 (2)

    리눅스 자체의 system()함수가 있는 라이브러리에서 system()함수 주소와 /bin/sh 문자열 주소를 구한다. 그 후 그 두 주소의 차(거리)를 구한뒤, example1_nx 프로그램을 실행시켰을 때의 system() 의 주소를 구한 뒤 앞에서 구한 거리만큼 더하여 /bin/sh 문자열 주소를 구한다.

     

    sysyem() 함수의 주소
    /bin/sh 문자열 주소

     

    거리
    example1_nx 프로그램 실행 시 system() 함수 주소

     

    거리만큼 system()주소에서 뺀 /bin/sh문자열 주소

     

    /bin/sh의 주소는 0xb7f5c33c이다.

     

     

    알아낸 system ()주소와 /bin/sh 문자열 주소를 가지고서 익스플로잇 코드를 작성해보자.

    example1_nx의 메모리 구조를 그림으로 나타내 보았다.

     

    example1_nx의 메모리 구조

     

    해당 메모리 구조를 참고하여 공격코드를 생각해보자.

    buf~sfp (return addr 전)를 A로 채워서 넘기고 return addr에는 system 함수의 주소를 넣어 system()이 실행되게 할 것이다. 이 후 인자 1은 system함수의 return 값이 들어가게 되므로 아무값이나 넣어도 된다. 인자2에는 system()의 인자 값인 /bin/sh문자열의 주소가 들어가야 한다.

     

    "A"*40 + "system()주소" + "BBBB" + "/bin/sh문자열 주소"

    ==> "A"*40 + "\x50\x4f\xe1\xb7" + "BBBB" + "\x3c\xc3\xf5\xb7"

     

    페이로드 작성을 끝냈으면 이제 적용해보자.

     

    먼저 ret에 bp를 건 후, 공격 코드를 입력한다.

    eip를 확인하면 return addr을 가리키고 있고

    esp를 3개 확인해보니 system()함수 주소 , 문자열 BBBB, /bin/sh 문자열 주소 가 차례로 들어가 있는 것을 확인할 수 있다.

     

     

    이제 익스플로잇 코드를 실행해보자.

    $ ./example1_nx `python -c 'print "A"*36 + "\x50\x4f\xe1\xb7" + "BBBB" +"\x3c\xc3\xf5\xb7"'`

    실행하면 $쉘이 실행될 것이다.

     

    segmentation falut 오류가 났다. 메모리 보호기법때문에 주소가 달라져서 오류가 나는 것 같다.

     

    aslr을 끄고 진행해보니

    성공!

     

     

    4. NX Bit가 설정되어 있는 지 확인하는 방법

     

    바이너리에 nx bit가 설정되어 있는 지를 알아내는 것은 스택 메모리 권한을 검사하는 것으로도 충분하다. elf 파일의 분석도구인 readelf를 사용하면 nx bit 설정여부를 확인할 수 있다.

     

     

    example2_x는 nx bit가 설정되어 있지 않기 때문에 RWE로 나와 있고 example2_nx는 nx bit가 설정되어 있어 RW권한을 갖는다는 것을 확인할 수 있다.

     

    지금까지 라이브러리 메모리에 존재하는 함수를 이용하여 공격하는 방법인 RTL 공격을 통해 nx bit 보호기법을 우회하는 방법을 알아보았다.

     

    'System Security > dreamhack' 카테고리의 다른 글

    [Linux Exploitation & Mitigation]-ASLR / PLT,GOT  (0) 2021.03.16
    시스템 해킹 기초  (0) 2021.03.09

    댓글

Designed by Tistory.