Return into libc 기법
스텍 영역의 코드를 실행하지 못하게 하는 non-executable stack보호 기법이나 일부 IDS에서 네트워크를 통해 쉘 코드가 유입되는 것을 차단하는 보호 기법을 뚫기 위한 방법으로 제안.
non-executable stack 기법
-스텍 영역에 있는 코드를 실행하지 못하게 하는 것.
-CPU 레벨, 운영체제 영역 에서의 보호 기법.
-위의 사진처럼 butter overflow 취약점이 있는 버퍼를 공격.
-버퍼를 overflow시켜 butter위에 있는 return address영역에 실행시키고자 하는 libc 함수의 주소를 넣어줌.
-return address가 libc함수로 바뀌어서 함수가 리턴되면서 libc함수가 실행.
-system()함수의 시작지점은 0x4005ca4c
-system()함수의 호출지점은 0x8048258 이지만 실행 후 system()함수의 시작점을 찾아야 함.
-system() 함수가 실행되는 시점에 유의!
-call instruction은 다음 수행할 instruction의 address 즉 return address를 스텍에 PUSH 한 다음에 해당 함수의 시작점으로 이동한다.
but 여기서는 main()함수가 수행을 마치고 return할 때 return 시점이 system()함수의 시작 지점이 된다는 것을 조심.
- system() 함수를 보면 함수 프롤로그가 끝난 다음에 mov 0x8(%ebp),%eax 를 수행하는데, 이것이 system() 함수의 argument 처리 과정임.
- argument가 있는 곳의 address는 ebp+8 byte 지점에 있고 이를 eax 레지스터에 넣은 후 do_system을 호출함. 따라서 “/bin/sh”가 있는 곳의 주소는 이 시점에서의 ebp+8 지점이 되어야 함.
-
따라서 0x80485e6에 있는 명령을 수행할 시점의 스택 구조는 위 사진처럼 되어 있어야 함.
-
그림 50을 보면 main() 함수가 수행을 마치고 return address를 따라 system() 함수의 시작점으로 가게 될 것이고, argument를 얻어서 do_system을 호출하게 될 것임.
-
그러므로 main()함수의 메모리 구조에 system() 함수가 필요로 하는 데이터를 채워주면 됨.
-
vul.c를 overflow 시킬 데이터의 구조는 그림 51과 같음.
-
다음으로 “/bin/sh”를 메모리상에 올리고 그 주소를 알아와야 함. → 환경변수 이용
-
MYSHELL 환경변수
-
env.c를 이용해 환경변수가 위치한 메모리의 address를 알아냄.
-
공격에 사용된 데이터는 “ABCD”를 7번 반복하여 총 28byte의 dummy 값과 system() 함수의 address, 4 byte dummy(“KKKK”), “/bin/sh”가 환경변수로 등록되어 있는 곳의 address를 연결하여 생성함.
-
system() 함수 내에서의 return address가 “KKKK”로 조작되어 있기 때문에 exit를 해서 쉘 문을 빠져나오면 Segmentation fault가 뜨는 것을 볼 수 있음.
beist’s execl 방법
-
현재 컴파일된 vul이 setuid 비트가 set 되어 있지만 root의 쉘이 떨어지지 않았음.
-
이는 system() 함수가 단순히 호출만 하는 역할을 하기 때문
-
따라서 root의 권한을 얻어오기 위해서는 execl() 함수를 사용할 수 있음
-
공격의 기본 개념
-
buffer overflow 취약점을 가진 프로그램(vul.c)를 Return-into-libc 기법으로 overflow 시켜 공격함.
-
main() 함수 return 시에 return할 libc 함수는 execl.
-
execl은 man 페이지에서 볼 수 있듯이 세 개의 argument를 가짐
-
첫 번째 인자는 실행할 프로그램의 full path와 실행파일 이름으로 구성된 문자열의 address, 실행 파일 실행시에 주어질 argument들, NULL을 넣어주면 됨. → 여기서 쉘을 띄우는 프로그램은 shell.c
-
shell.c는 setreuid()와 setregid()를 이용하여 소유자의 권한을 얻어오는 역할을 해줌.
-
먼저 공격에 사용될 데이터의 구조를 살펴보면 그림 55와 같음.
-
이 구조의 버퍼에 그림 56과 같은 형식의 공격 코드를 집어 넣음.
-
다음은 execl() 함수가 있는 곳의 address를 찾고 argv[2]의 주소를 찾으면 됨.(argv[2]: 그림 54에서 본 쉘을 띄우는 프로그램의 실행명령)
argv[2]의 주소를 알기 위해 vul을 실행시켜 보자.
argument를 쉘을 띄울 프로그램 실행 명령을 주었는데 “.shell”앞에 한 칸을 띄어야 argument 가 분리된다.
- main 함수의 base pointer, ebp를 기점으로 argv[0]의 주소(0xbffffab4) 를 찾을 수 있는데 이를 따라가 보면 각 각 포인터들이 각각이 argument를 가르키고 있다는 것을 알 수 있다.
- argv[0]의 주소 뒤 8byte 지점(0xbffffabc)에 있음을 알 수 있다.
따라서 argv[2]의 주소 -8은 argv[0]의 주소와 같은 값(0xbffffab4) 이다.
이제는 공격을 시도해 볼 차례이다.
execl 함수를 disassemble하면 다음과 같다.
굵은 글씨를 보았을 때 execl +3 을 하는 이유는 execl 함수가 시작되고 함수 프롤로그 작업을 하지 않게 하기 위해서다. 따라서 이 지점의 주소를 return address로 지정해 주었다.
다음으로 pushl 0x89%ebp
즉 ebp 레지스터가 가르키는 곳의 8byte 뒤의 값을 스텍에 집어 넣고 exeve()를 호출한다. 우리는 argv[2]의 주소-8에 있는 주소를 넣어놨음으로 +8을 하게 되면 (0xbfffabc)를 가르키게 되고 여기에는 “./shell” 이라는 쉘 프로그램 실행 명령이 들어있음을 shell을 실행하게 된다.
'3. Pwnable (포너블) > 2) 개념 정리' 카테고리의 다른 글
[2021.03.20] 3주차 : C언어 기본 다지기(2), Bandit Level 0~2 (0) | 2021.03.20 |
---|---|
[2021.03.13] 2주차 : C언어로 기본 다지기 (1) (0) | 2021.03.13 |
[2020.11.14] 4너블 4ever - 달고나 문서 58p ~ 70p (0) | 2020.11.14 |
[2020.11.07] 4너블4ever - 달고나 문서 44p~57p (0) | 2020.11.07 |
[2020.9.19] 4너블4ever - 리눅스 기초 명령어 + 달고나 문서 ~p12 (0) | 2020.09.20 |