Lord of the BufferOverflow Fedora Core3
[ Level1_Gate -> Iron_golem ]
바로 시작합니다.
다음은 fc3의 iron_golem.c의 소스입니다.
![](https://t1.daumcdn.net/cfile/tistory/262388335686CCA023)
주어진 힌트는 fake ebp 기법을 사용하여 풀이 할 수 있다고 합니다.
![](https://t1.daumcdn.net/cfile/tistory/2323A8335686CCA223)
iron_golem 바이너리를 cp 명령어로 melog_nori로 복사 한 후 gdb로 main 함수를 disassemble 해보았습니다.
main+3의 위치를 확인 해 보면 esp 레지스터를 0x108만큼 빼주는 것을 알 수 있습니다. 이는 곧 선언 된 변수를 위해 메모리에 공간을 할당해주는 작업이라는 뜻입니다. 0x108은 10진수로 264로, buffer변수에서 할당했던 256byte에 8byte만큼의 dummy 값이 포함 된 만큼의 공간이라고 볼 수 있습니다.
![](https://t1.daumcdn.net/cfile/tistory/2221EC335686CCA322)
또한, 위의 esp 값을 보면 실행 할 때마다 esp 레지스터의 위치가 바뀌는 것으로 보아 스택이 랜덤하게 변하는 것을 알 수 있습니다. 게다가 스택의 시작 주소가 0xfe인 것부터 redhat6.0 환경과 다르기에, 페도라 코어3와의 차이를 알아보았습니다.
|
Redhat 9.0
|
Fedora Core3
|
Random Stack
|
O |
O
|
Non Executable Stack
|
X |
O |
Libc Address
|
16MB↑
|
16MB↓
|
스택에서의 실행 권한을 주지 않는 것을 보니, 쉘코드를 직접 실행하기는 어려울 것 같습니다. 힌트로 제시 된 Fake EBP를 이용한 Beist's Execl 방법으로 풀이하도록 하겠습니다.
일반적인 RTL을 이용한 풀이도 해 보았지만, 위의 표에서도 알 수 있듯이 라이브러리 함수들의 주소가 16MB 미만이기 때문에 불가능하였습니다.
16MB는 16진수로 0x01000000인데, 그 미만이기 때문에 0x00ffffff까지밖에 존재하지 않습니다. 따라서 RTL을 위해서는 system()과 같은 함수의 주소를 포함하여 '/bin/sh'의 주소를 프로그램의 파라미터로 넘겨주어야 하는데 system 함수의 주소에 0x00(NULL Byte)가 포함되어 뒤의 값들을 인식하지 못해 exploit을 할 수 없습니다. 이와 같이 첫 바이트에 0x00이 존재하는 주소를 ASCII-Armor라고 합니다. 이를 우회하기 위한 방법이 Beist's Execl 방법입니다.
Beist's Execl 방법은 Beist LAB의 Beist님께서 Fedora Core의 Exec-Shield를 우회하기 위해 제시 한 기법입니다. Execl 함수가 내부적으로 Execve 함수를 호출하는데, 이 때 ebp+8의 위치를 참조하는 특성을 이용하여 shell을 얻어내는 방법입니다. 이를 위해서는 아래와 같은 준비가 선행되어야 합니다.
- execl함수의 주소
- Data Section 내의 특정한 주소
execl함수는 gdb 내에서 print 명령어를 통해 간단하게 구할 수 있지만, 그 아래 있는 Data Section 내의 주소는 무엇일까요?
이 것을 설명하기 전에 execl 함수의 원형을 살펴보도록 하겠습니다.
int execl( const char *path, const char *arg, ...); |
execl 함수는 위와 같이 최소 3개의 파라미터를 가집니다. 그렇다면 가장 적은 인자를 가질 때는 아래와 같을 것입니다.
execl(*path, *arg, NULL);
즉, execl 함수의 가장 마지막 인자는 NULL(0)이 되어야 한다는 뜻입니다.
그럼 다시 본론으로 돌아오겠습니다. 페도라 코어에서는 스택 내에서의 실행을 제한 할 뿐만 아니라 스택의 주소 자체가 랜덤하게 배정되기 때문에 argv[1]과 같은 파라미터에 데이터를 넣어 주어도 해당 데이터가 있는 주소를 특정하기 어렵기 때문에 실행 할 때마다 변하지 않는 주소를 이용하여야 합니다. 그 중 하나가 Data Section인 것입니다. Data Section 중에서도 GOT 부분은 항상 NULL Byte로 끝나기 때문에 이 부분을 이용하면 execl 함수의 인자 조건을 만족 시킬 수 있는 것이죠.
![](https://t1.daumcdn.net/cfile/tistory/272256335686CCA723)
gdb를 이용하여 execl 함수의 주소를 먼저 구해줍니다.
- execl의 주소 : 0x007a5720
![](https://t1.daumcdn.net/cfile/tistory/222204335686CCA824)
readelf 명령어를 이용하여 got section을 찾아보면 0x0804618인 것을 확인 할 수 있습니다. 이를 gdb에서 찾아보도록 하죠.
![](https://t1.daumcdn.net/cfile/tistory/243AC6395686CCAA32)
0x8049634 부분을 확인하면 GOT의 끝부분이기 때문에 0x00000000이 있는 것을 확인 할 수 있습니다. 그렇다면 8byte 전인 0x804962c를 확인해봅시다.
가리키고 있는 주소는 0x0804830e로, 찾아가보면 0x00001068이 있습니다. 바로 이 부분이 우리가 전달하는 포인터로 사용할 부분입니다. 첫 번째 파라미터는 실행하고자 하는 프로그램의 이름이기 때문에 우리는 심볼릭 링크를 이용하여 실행하려는 파일의 이름을 0x1068로 바꿔 줄 필요가 있습니다.
- 특정 주소 : 0x804962c
말 나온 김에 실행 할 프로그램부터 살펴보도록 하겠습니다.
![](https://t1.daumcdn.net/cfile/tistory/213AD8395686CCAB32)
setreuid, setregid를 이용하여 권한을 재설정하고, execl을 이용해 쉘을 띄워주는 간단한 코드입니다. 이를 shell이라는 이름으로 컴파일 한후, 심볼릭 링크를 이용하여 0x1068로 바꿔주도록 합니다.
![](https://t1.daumcdn.net/cfile/tistory/243CA4395686CCAC32)
프로그램 또한 정상적으로 작동하는 것을 확인했습니다!
이제 exploit만 남았습니다. payload를 살펴보기 전에, 이 기법의 원리부터 간단하게 알아보도록 하겠습니다.
beist's execl을 처음 소개할 때 언급했듯이, execl 함수는 내부적으로 execve 함수를 호출합니다. 이 때 ebp는 우리가 넘겨주는 '첫 번째 파라미터의 위치'입니다. 여기서 ebp+8의 위치를 참조한다고 하였으므로, 결과적으로 우리가 넘겨주어야 할 첫번째 파라미터의 주소는 8만큼 빼 주어야 한다는 말이 됩니다.
아까부터 첫 번째 파라미터를 넘겨준다고 설명하였는데, 이 파라미터는 또 어떻게 넘겨준다는 것일까?
여기서 FakeEBP 기법이 이용됩니다. 현재 iron_golem의 스택 구조는 다음과 같습니다.
[buffer][dummy][SFP][RET]
--(256)----(4)-----(4)---(4)--
main 함수에서 leave;ret을 하게 되면 SFP가 EBP로 이동되고, RET의 주소로 jmp하게 됩니다. 그리고 jmp 한 주소가 함수라면, 함수 프롤로그를 통해 main함수의 SFP를 push하고 EBP가 main함수의 ESP 값을 가지게 되죠. 하지만 이 때, RET가 함수의 주소이지만, 함수+3의 위치로 return을 하게 되면 어떻게 될까요?
바로 함수의 프롤로그를 뛰어 넘고 함수를 실행하게 됩니다. 즉, EBP(main 함수의 SFP)의 값을 그대로 가지고 함수를 실행 할 수 있다는 뜻이 됩니다.
여기서 내부적으로 execve가 실행되고, 그 파라미터로 ebp+8의 값이 넘어가면서 ebp+8이 참조하고 있는 위치의 문자열(파일 경로)을 실행하게 되는겁니다.
이런 생각은 대체 어떻게 하는건지... 정말 대단한 것 같습니다.
그럼 설명한 내용을 토대로 payload를 작성 해 보도록 하겠습니다.
./iron_golem $(python -c "print 'A'*264+[0x804962c - 8]+[0x007a5720 + 3]") ->
./iron_golem $(python -c "print 'A'*264+'0x8049624'+'0x007a5723'")
![](https://t1.daumcdn.net/cfile/tistory/263CCC395686CCAD30)
shell이 띄워졌으며, id 명령어를 통해 iron_golem으로 권한이 상승한 것을 확인 할 수 있습니다.
References
- FEDORA CORE2에서 EXEC-SHIELD를 우회하여 STACK 기반 OVERFLOW 공격 기법 한번에 성공하기(beist)
- 해커 지망자들이 알아야 할 Buffer Overflow Attack의 기초(달고나)
- Redhat 9 부터 Fedora 5 까지의 Return into Libc 기법(이경호)