본문으로 바로가기

해커스쿨 LOB skeleton 풀이, write-up

category Wargame/LOB 2018. 8. 16. 10:30

skeleton --- shellcoder



우선 skeleton의 디렉터리를 확인한다.





golem이라는 의심스러운 파일이 존재한다. golem은 golem의 권한을 가지고 있고, setuid가 걸려있는 파일이다.



golem.c를 가지고 golem 파일을 만들었을 가능성이 있기 때문에, golem.c 파일을 본 뒤 어떤 취약점을 가지고 있는지 확인해보자.





환경변수 리스트의 포인터를 선언한다.



1
extern char **environ;                                                                
cs



지역 변수를 선언한다.



1
2
char buffer[40];                                                                    
int i;
cs



인자가 없으면 "argv error\n"를 출력하고 종료한다.



1
2
3
4
if(argv < 2) {
    printf("argv error\n);                                                            
    exit(0);
}
cs



첫 번째 인자의 48번째 문자가 '\xbf'가 아니면 "stack is still your friend!\n"를 출력하고 종료한다.



1
2
3
4
5
if(argv[1][47!= '\xbf')
{
    printf("stack is still your friend.\n");                                        
    exit(0);
}
cs



인자를 버퍼에 저장하고 출력한다.



1
2
strcpy(buffer, argv[1]);                                                            
printf("%s\n", buffer);
cs



buffer와 RET이 끝나는 공간부터 스택 영역의 시작 영역까지 모두 0으로 초기화 한다.



1
2
memset(buffer, 044);
memset(buffer+4800xbfffffff - (int)(buffer+48));                                
cs



golem의 메모리 구조를 예상해보면 아래와 같이 그릴 수 있다.





실제 배열과 변수가 할당될 때 gcc가 최적화를 위해 자동적으로 dummy를 생성할 수 있다.


gdb를 이용해서 golem을 분석해보자. golem을 gdb로 실행하는 도중 permission denied가 발생하면 cp 명령을 이용해 파일을 복사하면 된다. 현재 user의 권한으로 똑같은 파일을 가질 수 있기 때문이다.




위와 같이 golemcp가 skeleton의 권한으로 복사된 것을 확인할 수 있다.



dummy가 생성되었는지 gdb를 통해 확인해보자.





dummy가 추가적으로 생성되지 않고 정확히 44(0x2C) byte가 생성된 것을 확인할 수 있다.



RET이 할당된 공간부터 스택 영역의 시작 영역(0xbfffffff)까지 모두 0으로 초기화 된다.

인자, 버퍼, 환경변수 모두 이용할 수 없다.


우리가 공격을 위해 이용할 수 있는 부분은 buffer의 주소보다 낮은 공간을 이용해야 한다.


이제 함수의 관점에서 생각할 때이다.


프로그램이 실행되면 메모리에는 많은 정보들이 올라간다.

함수를 실행하기 위해서 함수도 메모리에 올라가야하고 함수의 주소를 참조하여 함수를 실행한다.

golem.c에는 memset, strcpy도 당연히 메모리 공간에 올라가야한다.


이를 위해 존재하는 환경 변수 LD_PRELOAD가 있다.

LD_PRELOAD가 메모리에 올라가는 영역은 공유라이브러리 영역이다.


메모리 구조를 자세히 나타내면 아래와 같이 나타낼 수 있다.



공유 라이브러리 영역은 buffer의 위에 로드되므로 우리가 이용 가능한 공간이다.


LD_PRELOAD 환경변수에 파일이 등록되면, 프로그램이 메모리에 올라가기 전에 환경변수에 등록한 파일을 먼저 메모리에 로드한다.


LD_PRELOAD 환경변수 등록 방법


빈 파일을 만든 후 shell code로 컴파일 한다.

- fPIC 옵션 : Position-Independent Code의 약자로, CPU에 관계없이 동작하도록 컴파일 한다.

- shared 옵션 : 우선 공유 라이브러리와 링크하고 공유 라이브러리가 없으면 정적 라이브러리와 링크한다.

- 반드시 절대 경로로 파일명을 지정해야 오류가 발생하지 않는다.





이제 gdb로 golem을 뜯어보면 LD_PRELOAD에 의해 공유라이브러리 영역에 쉘코드가 들어갈 것이다.





공유메모리를 위에서 공부한데로 0xbffff9ec보다 작은 주소에 위치할 것이다.

0xbffff000부터 스택 영역을 살펴보며 쉘코드를 찾아보자.





위와 같이 쉘코드가 저장된 주소를 찾았다.

공격주소를 0xbffff590으로 잡고 RET을 0xbffff590으로 수정하자