- /bin/ExecuteMe
ExecuteMe가 어떻게 이루어져 있기에 level1이 실행했을때 level2 권한을 가지고 명령어를 실행하는지 확인한다.
- gdb
소스코드가 없으므로 실행파일을 가지고 disassemble 과정을 거쳐 확인한다.
- 확인
[level1@ftz level1]$ gdb /bin/ExecuteMe
|
GNU gdb Red Hat Linux (5.3post-0.20021129.18rh) Copyright 2003 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux-gnu"... (gdb) disassemble main Dump of assembler code for function main: 0x08048488 <main+0>: push %ebp 0x08048489 <main+1>: mov %esp,%ebp 0x0804848b <main+3>: sub $0x28,%esp 0x0804848e <main+6>: and $0xfffffff0,%esp 0x08048491 <main+9>: mov $0x0,%eax 0x08048496 <main+14>: sub %eax,%esp 0x08048498 <main+16>: sub $0xc,%esp 0x0804849b <main+19>: push $0x8048680 0x080484a0 <main+24>: call 0x8048358 <system> 0x080484a5 <main+29>: add $0x10,%esp 0x080484a8 <main+32>: sub $0xc,%esp 0x080484ab <main+35>: push $0x804868f 0x080484b0 <main+40>: call 0x8048378 <chdir> 0x080484b5 <main+45>: add $0x10,%esp 0x080484b8 <main+48>: sub $0xc,%esp 0x080484bb <main+51>: push $0x80486a0 0x080484c0 <main+56>: call 0x80483a8 <printf> 0x080484c5 <main+61>: add $0x10,%esp 0x080484c8 <main+64>: sub $0xc,%esp 0x080484cb <main+67>: push $0x80486e0 0x080484d0 <main+72>: call 0x80483a8 <printf> 0x080484d5 <main+77>: add $0x10,%esp ---Type <return> to continue, or q <return> to quit--- 0x080484d8 <main+80>: sub $0xc,%esp 0x080484db <main+83>: push $0x8048720 0x080484e0 <main+88>: call 0x80483a8 <printf> 0x080484e5 <main+93>: add $0x10,%esp 0x080484e8 <main+96>: sub $0xc,%esp 0x080484eb <main+99>: push $0x8048760 0x080484f0 <main+104>: call 0x80483a8 <printf> 0x080484f5 <main+109>: add $0x10,%esp 0x080484f8 <main+112>: sub $0xc,%esp 0x080484fb <main+115>: push $0x8048782 0x08048500 <main+120>: call 0x80483a8 <printf> 0x08048505 <main+125>: add $0x10,%esp 0x08048508 <main+128>: sub $0x4,%esp 0x0804850b <main+131>: pushl 0x8049948 0x08048511 <main+137>: push $0x1e 0x08048513 <main+139>: lea 0xffffffd8(%ebp),%eax 0x08048516 <main+142>: push %eax 0x08048517 <main+143>: call 0x8048368 <fgets> 0x0804851c <main+148>: add $0x10,%esp 0x0804851f <main+151>: lea 0xffffffd8(%ebp),%eax 0x08048522 <main+154>: sub $0x8,%esp 0x08048525 <main+157>: push $0x804879c 0x0804852a <main+162>: push %eax ---Type <return> to continue, or q <return> to quit--- 0x0804852b <main+163>: call 0x8048388 <strstr> 0x08048530 <main+168>: add $0x10,%esp 0x08048533 <main+171>: test %eax,%eax 0x08048535 <main+173>: je 0x8048551 <main+201> 0x08048537 <main+175>: sub $0xc,%esp 0x0804853a <main+178>: push $0x80487c0 0x0804853f <main+183>: call 0x80483a8 <printf> 0x08048544 <main+188>: add $0x10,%esp 0x08048547 <main+191>: sub $0xc,%esp 0x0804854a <main+194>: push $0x0 0x0804854c <main+196>: call 0x80483c8 <exit> 0x08048551 <main+201>: lea 0xffffffd8(%ebp),%eax 0x08048554 <main+204>: sub $0x8,%esp 0x08048557 <main+207>: push $0x80487e8 0x0804855c <main+212>: push %eax 0x0804855d <main+213>: call 0x8048388 <strstr> 0x08048562 <main+218>: add $0x10,%esp 0x08048565 <main+221>: test %eax,%eax 0x08048567 <main+223>: je 0x8048583 <main+251> 0x08048569 <main+225>: sub $0xc,%esp 0x0804856c <main+228>: push $0x8048800 0x08048571 <main+233>: call 0x80483a8 <printf> 0x08048576 <main+238>: add $0x10,%esp ---Type <return> to continue, or q <return> to quit--- 0x08048579 <main+241>: sub $0xc,%esp 0x0804857c <main+244>: push $0x0 0x0804857e <main+246>: call 0x80483c8 <exit> 0x08048583 <main+251>: sub $0xc,%esp 0x08048586 <main+254>: push $0x8048826 0x0804858b <main+259>: call 0x80483a8 <printf> 0x08048590 <main+264>: add $0x10,%esp 0x08048593 <main+267>: sub $0x8,%esp 0x08048596 <main+270>: push $0xbba 0x0804859b <main+275>: push $0xbba 0x080485a0 <main+280>: call 0x80483b8 <setreuid> 0x080485a5 <main+285>: add $0x10,%esp 0x080485a8 <main+288>: sub $0xc,%esp 0x080485ab <main+291>: lea 0xffffffd8(%ebp),%eax 0x080485ae <main+294>: push %eax 0x080485af <main+295>: call 0x8048358 <system> 0x080485b4 <main+300>: add $0x10,%esp 0x080485b7 <main+303>: leave 0x080485b8 <main+304>: ret 0x080485b9 <main+305>: nop 0x080485ba <main+306>: nop 0x080485bb <main+307>: nop End of assembler dump. (gdb) |
|
|
0x0804849b <main+19>: push $0x8048680 0x080484a0 <main+24>: call 0x8048358 <system> |
|
> system 이라는 함수가 실행 된 것 같다.
$ man system
|
SYNOPSIS #include <stdlib.h> int system(const char *string); DESCRIPTION system() executes a command specified in string by calling /bin/sh -c string, and returns after the command has been completed. During exe- cution of the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT will be ignored. |
|
> /bin/sh-c [string] : string을 쉘로 실행해주는 함수
> string 이라는 하나의 파라미터(매개변수)값을 가진다. ( 바로 위 push 로 입력받은 값 )
|
(gdb) x/s 0x8048680 0x8048680 <_IO_stdin_used+28>: "/usr/bin/clear" |
|
> push의 주소를 x/s ( 문자형식으로 출력) 명령어를 사용해보니 clear 명령어임을 확인할 수 있다.
같은 방법으로 어떤 함수가 실행 됬는지 확인한다.
|
0x080484ab <main+35>: push $0x804868f 0x080484b0 <main+40>: call 0x8048378 <chdir>
|
|
$ man chdir
|
SYNOPSIS #include <unistd.h> int chdir(const char *path); int fchdir(int fd); DESCRIPTION chdir changes the current directory to that specified in path. fchdir is identical to chdir, only that the directory is given as an open file descriptor. |
|
> 디렉토리를 변경하는 명령어
|
(gdb) x/s 0x804868f 0x804868f <_IO_stdin_used+43>: "/home/level2" |
|
> path의 값은 level2의 홈 디렉토리
|
0x080484bb <main+51>: push $0x80486a0 0x080484c0 <main+56>: call 0x80483a8 <printf> ............ 0x080484cb <main+67>: push $0x80486e0 0x080484d0 <main+72>: call 0x80483a8 <printf> ............ 0x080484db <main+83>: push $0x8048720 0x080484e0 <main+88>: call 0x80483a8 <printf> ............ 0x080484eb <main+99>: push $0x8048760 0x080484f0 <main+104>: call 0x80483a8 <printf> ............ 0x080484fb <main+115>: push $0x8048782 0x08048500 <main+120>: call 0x80483a8 <printf> |
|
> printf , 출력문이 연속된다.
> /bin/ExecuteMe 를 실행 했을때 출력되는 것을 살펴보면 아마 그 글을 출력할 것이다.
$ /bin/ExecuteMe
|
레벨2의 권한으로 당신이 원하는 명령어를 한가지 실행시켜 드리겠습니다. (단, my-pass 와 chmod는 제외) 어떤 명령을 실행시키겠습니까? [level2@ftz level2]$ |
|
|
(gdb) x/s 0x8048782 0x8048782 <_IO_stdin_used+286>: "\n\n\t\t[level2@ftz level2]$ " |
|
|
0x0804850b <main+131>: pushl 0x8049948 0x08048511 <main+137>: push $0x1e 0x08048513 <main+139>: lea 0xffffffd8(%ebp),%eax 0x08048516 <main+142>: push %eax 0x08048517 <main+143>: call 0x8048368 <fgets> |
|
$ man fgets
|
#include <stdio.h>
char *fgets(char *s, int size, FILE *stream); fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A '\0' is stored after the last character in the buffer. |
|
> 입력받는 함수
> 3개의 파라미터가 필요하기 때문에 3개의 push
|
(gdb) x/s 0x8049948 0x8049948 <stdin@@GLIBC_2.0>: "" |
|
> 아직 입력값이 없기 때문에 빈공간으로 남아있다.
> 스택이 LIFO 이기 때문에 먼저 push된 0x8049948이 마지막 파라미터인 FILE *stream의 변수 값이 된다.
-> 즉 스택에는 거꾸로 들어가야 읽어 들일 때 순서대로 읽을 수 있다.
> 0x1e : (10진수) 30
|
0x08048525 <main+157>: push $0x804879c 0x0804852a <main+162>: push %eax ---Type <return> to continue, or q <return> to quit--- 0x0804852b <main+163>: call 0x8048388 <strstr> 0x08048530 <main+168>: add $0x10,%esp 0x08048533 <main+171>: test %eax,%eax 0x08048535 <main+173>: je 0x8048551 <main+201> 0x08048537 <main+175>: sub $0xc,%esp 0x0804853a <main+178>: push $0x80487c0 0x0804853f <main+183>: call 0x80483a8 <printf> 0x08048544 <main+188>: add $0x10,%esp 0x08048547 <main+191>: sub $0xc,%esp 0x0804854a <main+194>: push $0x0 0x0804854c <main+196>: call 0x80483c8 <exit> 0x08048551 <main+201>: lea 0xffffffd8(%ebp),%eax
|
|
$ man strstr
|
SYNOPSIS #include <string.h> char *strstr(const char *haystack, const char *needle); DESCRIPTION The strstr() function finds the first occurrence of the substring nee- dle in the string haystack. The terminating `\0' characters are not compared. |
|
> 두 개의 매개변수를 비교한다. \0은 같지 않을 때의 캐릭터이다.
|
(gdb) x/s 0x804879c 0x804879c <_IO_stdin_used+312>: "my-pass" |
|
> 비교하는 스트링 하나는 내가 입력한 명령어 하나는 my-pass 이다.
|
(gdb) x/s 0x80487c0 0x80487c0 <_IO_stdin_used+348>: "\n\t\tmy-pass 명령은 사용할 수 없습니다.\n\n" |
|
> 비교하여 같으면 printf 함수를 실행한 후 exit 로 종료한다.
> 같지 않으면 main+201로 점프한다.
다음 반복되는 strstr은 /bin/ExecuteMe 의 출력문을 보아 아마 chmod 명령어를 위와 같은 조건으로 판별하는 것 같다.
|
0x08048596 <main+270>: push $0xbba 0x0804859b <main+275>: push $0xbba 0x080485a0 <main+280>: call 0x80483b8 <setreuid> 0x080485a5 <main+285>: add $0x10,%esp 0x080485a8 <main+288>: sub $0xc,%esp 0x080485ab <main+291>: lea 0xffffffd8(%ebp),%eax 0x080485ae <main+294>: push %eax 0x080485af <main+295>: call 0x8048358 <system> |
|
$ man streuid
|
SYNOPSIS #include <sys/types.h> #include <unistd.h> int setreuid(uid_t ruid, uid_t euid); int setregid(gid_t rgid, gid_t egid); DESCRIPTION setreuid sets real and effective user IDs of the current process. Unprivileged users may only set the real user ID to the real user ID or the effective user ID, and may only set the effective user ID to the real user ID, the effective user ID or the saved user ID. Supplying a value of -1 for either the real or effective user ID forces the system to leave that ID unchanged. If the real user ID is set or the effective user ID is set to a value not equal to the previous real user ID, the saved user ID will be set to the new effective user ID. Completely analogously, setregid sets real and effective group ID's of the current process, and all of the above holds with "group" instead of "user". |
|
> real uid 와 effective uid 를 변경한다.
> push 값이 0xbba(3002) 이다.
[level1@ftz level1]$ id level2
|
uid=3002(level2) gid=3002(level2) groups=3002(level2) |
|
> level2 의 uid임을 확인 할 수 있다.
>system 함수는 처음에 확인한 것과 같이 쉘로 명령어를 실행 시켜준다.
> setreuid로 권한이 level2이 된 것으로 입력한 명령어를 실행 시켜 준다.
- 의사 코드 복원
분석한 내용으로는 처음에 /bin/clear를 하고 level2의 홈디렉토리로 옮긴 뒤, 몇 가지 글을 출력하고
입력받는 명령어를 my-pass와 chmod를 조건문으로 가려낸 후 setreuid로 권한 상승후 system으로 실행한다.
|
#include<stdio.h> #include<string.h> #include<unistd.h> #include<stdlib.h> int main(void) { char input[30];
system("/bin/clear"); printf(" 레벨 2의 권한으로 명령어를 실행 시키겠습니다"\n); printf(" ( 단 my-pass와 chmod는 제외 ) \n"); printf(" [level2@ftz level2]$ "); fgets(input, sizeof(input), stdin); if(strstr(input, "my-pass") != \0 ) { printf( " my-pass 명령어는 사용할 수 없습니다. " ); exit(0); } if(strstr(input,"chmod") != \0 ) { printf("chmod 명령어는 사용할 수 없습니다. "); exit(0); } setreuid(3002,3002); system(input); } |
|
> 출력문이 완벽하지는 않지만 같은 동작을 하는 소스를 유추해 낼 수 있다.
'Security > 리버싱' 카테고리의 다른 글
Level2 문제 분석/응용 (0) | 2017.11.28 |
---|---|
Level2 문제 해결 (0) | 2017.11.28 |
level 1 문제 해결 (0) | 2017.11.27 |
GDB 사용법 (1) | 2017.11.27 |
리버싱 실습환경 구성 (0) | 2017.11.27 |