nightmare --- beg for me
문제 풀기 전에 아래의 명령어를 반드시 쳐야한다.
$export SHELL=/bin/bash2
$/bin/bash2
우선 nightmare의 디렉터리를 확인한다.
xavius라는 의심스러운 파일이 존재한다.
xavius는 xavius의 권한을 가지고 있고, setuid가 걸려있는 파일이다.
xavius.c를 가지고 xavius elf 파일을 만들었을 가능성이 있기 때문에, xavius 파일을 본 뒤 어떤 취약점을 가지고 있는지 확인해보자.
지역 변수를 선언한다.
1 2 | char buffer[40]; char *ret_addr; | cs |
buffer에 256 byte의 입력을 저장하고 buffer를 출력한다.
1 2 | fgets(buffer, 256, stdin); printf("%s\n", buffer); | cs |
*(buffer+47) == '\xbf' 이면 "stack retbayed you!\n"를 출력하고 종료한다.
1 2 3 4 5 | if(*(buffer+47) == '\xbf') { printf("stack retbayed you!\n"); exit(0); } | cs |
*(buffer+47) == '\x08'이면 "binary image retbayed you, too!!\n"를 출력하고 종료한다.
1 2 3 4 5 | if(*(buffer+47) == '\x08') { printf("binary image retbayed you, too!!\n"); exit(0); } | cs |
buffer+44가 가리키는 곳부터 4 byte 만큼 &ret_addr에 저장한다.
1 | memcpy(&ret_addr, buffer+44, 4); | cs |
memcpy 함수
void *memcpy(void *destination, const void *source, size_t num);
source가 가리키는 곳부터 num byte 만큼 destination이 가리키는 곳으로 복사한다.
return 값은 destination의 포인터를 return 한다.
"\x90\x90"을 ret_addr에 2 byte 씩 저장한다.
만일 *ret_addr == '\xc9'이고, *(ret_addr+1) == '\xc3'이면
"You cannot use library function!\n"을 출력하고 종료한다.
ret_addr++
1 2 3 4 5 6 7 8 9 10 | while(memcmp(ret_addr, "\x90\x90", 2) != 0) // end point of function { if(*ret_addr == '\xc9' ){ // leave if(*(ret_addr+1) == '\xc3'){ // ret printf("You cannot use library function!\n"); exit(0); } } ret_addr++; } | cs |
buffer를 0으로 초기화하고, buffer+48~0xbfffffff까지 stack 영역을 0으로 초기화한다.
1 2 3 | // stack destroyer memset(buffer, 0, 44); memset(buffer+48, 0, 0xbfffffff - (int)(buffer+48)); | cs |
buffer의 스텍 윗 부분을 40 byte를 제외하고 모두 0으로 초기화 한다.
1 2 3 | // LD_* eraser // 40 : extra space for memset function memset(buffer-3000, 0, 3000-40); | cs |
xavius의 메모리 구조를 예상해보면 아래와 같다.
실제 변수가 할당될 때, gcc가 최적화를 위해 자동적으로 dummy를 생성할 수 있다.
gdb를 이용해 xavius를 분석해보자. xavius를 gdb로 실행하는 도중 permission denied가 발생하면 cp 명령을 이용하여 파일을 복사하면 된다. 현재 user의 권한으로 똑같은 파일을 가질 수 있기 때문이다.
위와 같이 xavius가 nightmare의 권한으로 복사된 것을 확인할 수 있다.
dummy가 생성되었는지 gdb를 통해 확인할 수 있다.
dummy가 추가적으로 생성되지 않고 정확히 44(0x2C) byte가 생성된 것을 확인할 수 잇다.
문제의 제한으로 인하여, stack 영역, library 영역, code 영역 모두 사용할 수 없다.
그렇다면 우리가 사용할 수 있는 공간은 어디일까??
소스코드를 잘 살펴보면 stdin을 이용하는 것을 확인할 수 있다.
stdin은 표준입력 파일 스트림으로, 우리가 입력한 문자열을 가지고 있는 버퍼이다.
그렇다면 이곳을 이용할 수 있지 않을까???
gdb를 통해 stdin의 주소를 찾아 분석해보자.
fgets(buffer, 256, stdin); 형식으로 사용했다.
즉, fgets를 호출하기전에 제일 먼저 push하는 값이 stdin의 주소이다.
stdin의 주소는 0x401068c0라는것을 알 수 있다.
더 자세히 알아보면 아래와 같다.
위와 같이 stdin(*0x8049a3c)가 가리키는 값도 확인 가능하다.
start of ptr = 0x40015000이다. start of ptr + 16(A*16) + 1(\n)를 통해 end of ptr을 유추할 수 있다.
end of ptr = 0x40015011이다.
stdin 구조체를 공부하고 조사해보면, stdin에서 실행이 가능하다.
따라서 우리의 payload는 stdin에서 실행하게 작성할 것이다.
nop(20) + shellcode(24) + ret(4) 로 구성된다.
다음과 같이 공격에 성공할 수 있다.
일반적으로 stdin(표준입력)이 EOF(End of File)을 돌려주기 때문에 단순 쉘 코드를 작성하면 쉘이 종료된다.
따라서 이러한 문제를 없에기 위해서 cat(표준출력)을 이용한다.
'Wargame > LOB' 카테고리의 다른 글
해커스쿨 LOB xavius 풀이, write-up [미완] (0) | 2018.10.28 |
---|---|
해커스쿨 LOB succubus 풀이, write-up (0) | 2018.10.12 |
해커스쿨 LOB zombie_assassin 풀이, write-up (0) | 2018.09.20 |
해커스쿨 LOB assassin 풀이, write up (0) | 2018.09.17 |
해커스쿨 LOB giant 풀이, write up (0) | 2018.09.16 |