본문으로 바로가기

[Protostar] Stack6 풀이, write-up

category Wargame/Protostar 2019. 1. 16. 20:43

Protostar --- Stack6



Stack6의 내용이다.


This level can be done in a couple of ways, such as finding the duplicate of the payload (objdump -s) will help with this, or ret2libc, or even return orientated programming.


Stack6의 내용을 해석해보면 아래와 같다.


이번 level은 몇 가지 방법으로 실행될 수 있다.

1. payload의 복사본을 발견하는것.

2. retunr to library(RTL).

3. return 지향 프로그래밍.



Stack6의 소스를 분석해보자.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
 
void getpath()
{
  char buffer[64];
  unsigned int ret;
 
  printf("input path please: "); fflush(stdout);                                        
 
  gets(buffer);
 
  ret = __builtin_return_address(0);
 
  if((ret & 0xbf000000== 0xbf000000) {
      printf("bzzzt (%p)\n", ret);
      _exit(1);
  }
 
  printf("got path %s\n", buffer);
}
 
int main(int argc, char **argv)
{
 
  getpath();
 
}
cs



getpath() 함수를 호출한다.



1
2
3
4
5
6
int main(int argc, char **argv)                                                        
{
 
  getpath();
 
}
cs



char type array buffer를 64 byte를 정의한다.

unsigned int type ret을 정의한다.



1
2
3
4
void getpath()                                                                        
{
  char buffer[64];
  unsigned int ret;
cs



"input path please: "를 출력하고, fflush()함수를 이용해 stdout을 비운다.

gets() 함수를 통해서, user로부터 buffer에 입력을 받는다.


__builtin_return_address(0) 함수의 설명은 아래와 같다.

This function returns the return address of the current function, or of one of its callers.


__builtin_return_address() 함수는 RET(EIP)를 return 하는 함수이다. 

RET(EIP)를 ret에 저장한다.



1
2
3
4
5
 printf("input path please: "); fflush(stdout);                                        
 
  gets(buffer);
 
  ret = __builtin_return_address(0);
cs



만일 ret이 stack 영역(0xbfxxxxxx)을 사용하고 있다면 "bzzzt ret\n"을 출력하고 종료한다.

"got path buffer\n"를 출력한다.



1
2
3
4
5
6
7
  if((ret & 0xbf000000== 0xbf000000) {                                        
      printf("bzzzt (%p)\n", ret);
      _exit(1);
  }
 
  printf("got path %s\n", buffer);
}
cs



stack6가 어떤 stack 구조를 가지고 있는지 확인하기위해, gdb를 통해 분석해보자.





gdb를 통해 분석한 내용을 바탕으로 stack 구조를 그려보면 다음과 같이 그릴 수 있다.




이번 level에서 getpatch's RET 주소를 0xbf000000과 AND 연산하여, getpatch's RET가 stack을 가리키고 있는지 확인한다.


따라서, getpatch's RET의 주소가 stack 영역을 가르키면 안된다.


따라서 getpatch's RET를 system() 함수로 overwriting 하여, stack 영역이 아닌 library 영역으로 overwriting 하는 RTL(return to library)을 이용한다.


RTL 기법을 위해 필요한것을 아래의 3가지이다.


1) buffer부터 RET까지의 거리

2) system() 함수의 주소

3) "/bin/sh"의 주소


stack 구조를 통해 RET에 도달하기 위해 80 byte padding이 필요한것을 확인할 수 있다.


system() 함수의 주소는 gdb를 통해 알아낼 수 있다.

system() 함수의 주소는 0xf7e117e0이다.




"/bin/sh"의 문자열은 coding을 통해 보다 쉽게 찾을 수 있다. 

system() 내부에 "/bin/sh"가 포함된다는것이 힌트이다.



1
2
3
4
5
6
7
8
9
// whereissh.c                                                                        
#include <stdio.h>
main()
{
        long shell = 0xf7e117e0;
        while(memcmp((void*)shell, "/bin/sh"8))                                
                shell++;
        printf("%x\n", shell);
}
cs



whereissh.c를 컴파일 후 실행하면 "/bin/sh"의 주소가 0xf7f50968임을 확인할 수 있다.





RTL의 payload는 80 byte padding + system() address + 4 byte dummy + "/bin/sh" address이다.





'Wargame > Protostar' 카테고리의 다른 글

[Protostar] Stack5 풀이, write-up  (0) 2019.01.12
[Protostar] Stack4 풀이, write-up  (0) 2019.01.09
[Protostar] Stack3 풀이, write-up  (1) 2019.01.08
[Protostar] Stack2 풀이, write-up  (0) 2019.01.07
[Protostar] Stack1 풀이, write-up  (0) 2019.01.06