ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Improper Null Termination (SSP)
    Hack/Pwnable 2015. 11. 20. 05:34

    #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>


    int main ()

    {

        int size;

        char buf [100];

        char line [10];


    setlinebuf(stdout);

        fgets (buf, sizeof (buf),stdin);

        size = atoi (buf);

        fgets(buf, sizeof (buf),stdin);

        strncpy (line, buf, size);

        puts (line);


        gets (line);

        puts (line);


        return 0;

    }


    소스코드이다. 컴파일을 하자.


    $ gcc test.c


    소스는 별거없이 입력받는값을 변수에넣고 출력시키는 프로그램이다.




    (gdb) disas main

    Dump of assembler code for function main:

       0x000000000040077d <+0>: push   %rbp

       0x000000000040077e <+1>: mov    %rsp,%rbp

       0x0000000000400781 <+4>: push   %rbx

       0x0000000000400782 <+5>: sub    $0x98,%rsp

       0x0000000000400789 <+12>: mov    %fs:0x28,%rax

       0x0000000000400792 <+21>: mov    %rax,-0x18(%rbp)

       0x0000000000400796 <+25>: xor    %eax,%eax

       0x0000000000400798 <+27>: mov    0x2008d1(%rip),%rax        # 0x601070 <stdout@@GLIBC_2.2.5>

       0x000000000040079f <+34>: mov    %rax,%rdi

       0x00000000004007a2 <+37>: callq  0x400630 <setlinebuf@plt>

       0x00000000004007a7 <+42>: mov    0x2008ca(%rip),%rdx        # 0x601078 <stdin@@GLIBC_2.2.5>

       0x00000000004007ae <+49>: lea    -0x80(%rbp),%rax

       0x00000000004007b2 <+53>: mov    $0x64,%esi

       0x00000000004007b7 <+58>: mov    %rax,%rdi

       0x00000000004007ba <+61>: callq  0x400650 <fgets@plt>

       0x00000000004007bf <+66>: lea    -0x80(%rbp),%rax

       0x00000000004007c3 <+70>: mov    %rax,%rdi

       0x00000000004007c6 <+73>: callq  0x400680 <atoi@plt>

       0x00000000004007cb <+78>: mov    %eax,-0x94(%rbp)

       0x00000000004007d1 <+84>: mov    0x2008a0(%rip),%rdx        # 0x601078 <st---Type <return> to continue, or q <return> to quit---

    din@@GLIBC_2.2.5>

       0x00000000004007d8 <+91>: lea    -0x80(%rbp),%rax

       0x00000000004007dc <+95>: mov    $0x64,%esi

       0x00000000004007e1 <+100>: mov    %rax,%rdi

       0x00000000004007e4 <+103>: callq  0x400650 <fgets@plt>

       0x00000000004007e9 <+108>: mov    -0x94(%rbp),%eax

       0x00000000004007ef <+114>: movslq %eax,%rdx

       0x00000000004007f2 <+117>: lea    -0x80(%rbp),%rcx

       0x00000000004007f6 <+121>: lea    -0x90(%rbp),%rax

       0x00000000004007fd <+128>: mov    %rcx,%rsi

       0x0000000000400800 <+131>: mov    %rax,%rdi

       0x0000000000400803 <+134>: callq  0x400600 <strncpy@plt>

       0x0000000000400808 <+139>: lea    -0x90(%rbp),%rax

       0x000000000040080f <+146>: mov    %rax,%rdi

       0x0000000000400812 <+149>: callq  0x400610 <puts@plt>

       0x0000000000400817 <+154>: lea    -0x90(%rbp),%rax

       0x000000000040081e <+161>: mov    %rax,%rdi

       0x0000000000400821 <+164>: callq  0x400670 <gets@plt>

       0x0000000000400826 <+169>: lea    -0x90(%rbp),%rax

       0x000000000040082d <+176>: mov    %rax,%rdi

       0x0000000000400830 <+179>: callq  0x400610 <puts@plt>

       0x0000000000400835 <+184>: mov    $0x0,%eax

       0x000000000040083a <+189>: mov    -0x18(%rbp),%rbx

    ---Type <return> to continue, or q <return> to quit---

       0x000000000040083e <+193>: xor    %fs:0x28,%rbx

       0x0000000000400847 <+202>: je     0x40084e <main+209>

       0x0000000000400849 <+204>: callq  0x400620 <__stack_chk_fail@plt>

       0x000000000040084e <+209>: add    $0x98,%rsp

       0x0000000000400855 <+216>: pop    %rbx

       0x0000000000400856 <+217>: pop    %rbp

       0x0000000000400857 <+218>: retq   

    End of assembler dump.

    (gdb)




    디스어셈블한 결과이다.


    SSP가 추가되어있는것이 보인다. puts 함수 다음에 브레이크포인트를 걸고 실행해보자


    (gdb) b *main+154

    Breakpoint 1 at 0x400817

    (gdb) r

    The program being debugged has been started already.

    Start it from the beginning? (y or n) y

    Starting program: /home/songsari/a.out 

    5

    AAAAA

    AAAAA


    프로그램이 정상적으로 돌아간다. 한번 스택을 확인해보자 


    0x7fffffffe956: 0xe5200000 0x0005f7ff 0x41410000 0x7f414141

    0x7fffffffe966: 0xe9800000 0x7fffffff 0x41410000 0x0a414141


    우리가 입력한값이 고스란히 잘 들어가있다.

    (gdb) x/x $rbp-0x18

    0x7fffffffe9d8: 0x5ad7ff00


    요길보면 카나리가 존재하는것을 볼수있다.


    랜덤으로 바뀌는거까지 확인해보면 카나리가맞다.


    우리는 strncpy함수를 가지고있는데, 원본 문자열이 지정된 길이를 초과하면 널에서 끊기지않는다. 

    그래서 코드에서 문자열끝에 널을 세팅하지않으면 그앞에있는데이터까지 처리된다.

    이것이 바로 널을 따로 지정해주지않아 발생하는 Improper Null Termination이다.


    카나리는 하위 1바이트가 널이기때문에 이를 충족한다. ( strcpy 함수등에의한 읽기 및 쓰기를 방지하기위해 널이 존재)


    우리는 여기서 릭을 해올수있다는것을 알수있다.


    (gdb) r

    The program being debugged has been started already.

    Start it from the beginning? (y or n) y

    Starting program: /home/songsari/a.out 

    11

    AAAAAAAAAAA

    AAAAAAAAAAA??


    Breakpoint 1, 0x0000000000400817 in main ()

    (gdb) 


    뭔가가 릭이된다는것을 알수있다.


    릭이 됨과 동시에 카나리를 확인해보면 A하나가  하위 1바이트인 널을 덮는것을 확인할수있다.


    SSP가 바뀌는것을 감지하여 프로그램이 메세지를 띄우고 종료하지만 스택오버플로우할수있는곳이있다면 이 SSP를 릭할수있있다는것이 해당 기법의 특징이다. 

    gets에서 오버플로우가 터지기때문에이를 이용한다. 



    'Hack > Pwnable' 카테고리의 다른 글

    FPO(Frame Pointer Overwrite]  (0) 2015.12.02
    Sigreturn Oriented Programming(SROP)  (0) 2015.11.24
    puts 어셈블리 프로그래밍  (0) 2015.10.06
    어셈블리 프로그래밍  (0) 2015.10.05
    SSP Leak Prob  (0) 2015.09.30

    댓글

Designed by Tistory.