System/Linux2012. 8. 27. 00:53

Fedora Core 5 환경에서 bof를 해보자.

 

취약 소스는 아래와 같다.

 

 

gdb로 디스어셈한 코드를 가져온 것이다.

0x080483e4 <main+0>:    lea    0x4(%esp),%ecx
0x080483e8 <main+4>:    and    $0xfffffff0,%esp
0x080483eb <main+7>:    pushl  0xfffffffc(%ecx)
0x080483ee <main+10>:   push   %ebp
0x080483ef <main+11>:   mov    %esp,%ebp
0x080483f1 <main+13>:   push   %ecx
0x080483f2 <main+14>:   sub    $0x114,%esp
0x080483f8 <main+20>:   mov    %ecx,0xfffffef8(%ebp)
0x080483fe <main+26>:   mov    0xfffffef8(%ebp),%eax
0x08048404 <main+32>:   cmpl   $0x2,(%eax)
0x08048407 <main+35>:   je     0x8048415 <main+49>
0x08048409 <main+37>:   movl   $0x1,(%esp)
0x08048410 <main+44>:   call   0x8048310
0x08048415 <main+49>:   mov    0xfffffef8(%ebp),%edx
0x0804841b <main+55>:   mov    0x4(%edx),%eax
0x0804841e <main+58>:   add    $0x4,%eax
0x08048421 <main+61>:   mov    (%eax),%eax
0x08048423 <main+63>:   mov    %eax,0x4(%esp)
0x08048427 <main+67>:   lea    0xfffffefc(%ebp),%eax
0x0804842d <main+73>:   mov    %eax,(%esp)
0x08048430 <main+76>:   call   0x8048330 <__gmon_start__@plt+16>
0x08048435 <main+81>:   lea    0xfffffefc(%ebp),%eax
0x0804843b <main+87>:   mov    %eax,0x4(%esp)
0x0804843f <main+91>:   movl   $0x8048510,(%esp)
0x08048446 <main+98>:   call   0x8048300
0x0804844b <main+103>:  mov    $0x0,%eax
0x08048450 <main+108>:  add    $0x114,%esp
0x08048456 <main+114>:  pop    %ecx
0x08048457 <main+115>:  pop    %ebp
0x08048458 <main+116>:  lea    0xfffffffc(%ecx),%esp
0x0804845b <main+119>:  ret

 

빨간 부분을 보면 이전의 프롤로그, 에필로그와는 차이가 있다는 것을 알 수 있다.

 

 

위의 스택 구조를 도식화 하면 아래와 같다.

 

--------------
|         ?        |  <-- ecx가 가리키는 부분
--------------
|        ret       |
--------------
|         .        |
|         .        |
|         .        |
--------------
|  copied ret  |
--------------
|       ebp      |
--------------

|       ecx      |

--------------

|                  | 

|       buf       |

|                  |

--------------

 

buf를 덮어서 바꾸는 ret은 그냥 원본에서 복사된  fake ret같은 것이기 때문에 위쪽의 ecx-4부분의 ret이 진짜 ret하는 부분이다.

 

main+4부분에 브레이크를 걸고 esp를 알아보니 아래와 같이 맨 마지막 바이트는 전부다 c로 끝나서 ret과 copied ret의 거리는 12byte로 예측할 수 있었다.

위쪽의 진짜 ret을 덮으려면 buf위에 있는 ecx까지 덮어야 하는데 진짜 ret을 참조하는데 ecx를 사용하므로 랜덤 스택인 환경에서는 불가능하다. 따라서 ecx를 바꿔서 실행 흐름을 바꾸는 것이다. 랜덤 스택이기 때문에 단순히 ecx를 1byte만 바꿔서 ret으로 참조하는 부분을 buf영역으로 내려버리는 것이다. 그럼 buf의 어딘가로 esp가 내려가고 우린 확률을 높이기 위해 ret sleding으로 채운다. 그 뒤에는 main의 에필로그를 실행한다.

 

| ret sleding ... ret sleding ... ret sleding ...  | main의 에필로그 |

 

- main의 에필로그가 의미하는 부분이다.

0x08048450 <main+108>:  add    $0x114,%esp
0x08048456 <main+114>:  pop    %ecx
0x08048457 <main+115>:  pop    %ebp
0x08048458 <main+116>:  lea    0xfffffffc(%ecx),%esp
0x0804845b <main+119>:  ret

 

중요한 부분은 add    $0x114,%esp 으로 esp값을 0x114만큼이나 올릴 수 있다는 것이다. 저 정도 올라가면 환경변수나 argv영역의 포인터 영역으로 esp가 이동하며 이를 이용해 exploit한다. (add 해주는 값이 너무 작거나 많으면 다른 방법을 이용해야할 듯..)

 

 

epilogue주소 : 0x08048450

&ret : 0x0804845b

 

256(buf) + 4(ecx) + 4(ebp) +4(ret)의 구조이다.

따라서 buf에 63개의 &ret과 1개의 에필로그를 넣으면 되겠다. 물론 마지막 \x00로 ecx를 1byte 바꿔주고..


아래는 공격 소스이다.

 

 

 

위를 보고 ecx-4부분은 E25라는 것을 알 수 있다.(ret영역을 실행해서 Further execution is probably impossible을 띄어주고 esp+4한 값이 E26이므로)

 

그럼 E25에 함수를 넣고 E26, 27 ..에 인자를 구성해주면 되겠다.

함수는 execl을 사용하고 인자구성은 system함수의 "/bin/sh"부분을 이용하자.

&execl : 0x19c2fc

인자 주소 : 0x228117 "execl이 0x19c5bc일때 - /bin/sh의 주소"

여기서 인자 주소에 +5를 해서 "sh"를 프로그램 이름으로 하여 setreuid를 사용한 프로그램을 만든다.

 

 

이렇게 정리한 공격 소스는 아래와 같다.

 

 

 

공격!

 

while [ 1 ]; do ./attack; done

 

 

root쉘 획득@~

 

계속하다보니 libc.so.6의 랜덤 라이브러리가 2가지로만 나오고 금방 깨지는 것 같네요 ;.

 

 

 

 

Posted by bbolmin

댓글을 달아 주세요