본문 바로가기

Pwnable/FTZ

[ProjectH4C] [Write-up] 해커스쿨 FTZ Level 2

level2에 접속 후, ls를 입력하면 level1과 동일하게 나온다.

 

 

level1을 통해 어느정도 감이 잡혔다고 생각이 들어서, hint는 마지막의 마지막까지 보지 않을 생각이다.

일단 SetUID부터 확인해보았는데, level1 때의 출력 결과와 같다. ExecuteMe를 제외한 나머지 파일들은 특별한게 없어보이고 ExecuteMe는 level1에서 사용했으니 열쇠가 되진 않을 것 같다. 하기야 level1과 접근 방법이 똑같을 리가 없겠지...

 

우선 해당 디렉토리에 있는 것들부터 하나씩 확인한다. tmp에는 역시 아무것도 없고, public_html 에는 index.html이 하나있다. index의 내용을 출력해 보니 다음과 같았다.

 

[level2@ftz public_html]$ cat index.html
<html><title>for 경환</title>
<meta http-equiv="refresh" content="3;url=http://www.yahoo.co.kr">
</head>
<body>여긴 뭐하는데지..;;</br>
이거 건드리면 머라고 하시려나.. -.,-;;</br>
by 9b7d722b58370498cd39104b2d971978
</body></html>

어라라?

 

분명 level1에선 index.html이 아무것도 안적혀 있었다. 이게 뭔가 단서가 될 것 같은데..

마지막에 보면 by 9b7d722b58370498cd39104b2d971978 라고 적혀있는데, 누가봐도 "나 16진수에요" 라고 하는 것 같다.

이를 1바이트 단위로 나누어봤다. 참고로 16진수 한자리는 4비트이고, 두 자리가 1바이트이다.

 

9b 7d 72 2b 58 37 04 98 cd 39 10 4b 2d 97 19 78

두 자리씩 딱 나누어 떨어진다. 수상하다 수상해.

하나하나 번역하기 번거로우니, C언어를 이용해서 16진수를 %c 형식으로 출력해보았다.

//trans.c


#include <stdio.h>

int main(){
	char ch[16];
	int i;

	for(i=0; i<16; i++){
		scanf("%x ", &ch[i]);
	}
	for(i=0; i<16; i++){
		printf("%c", ch[i]);
	}

	return 0;
}

 

이게 아닌가보다...

일단 level1에서 했던것처럼 level3 유저 소유의 파일을 한번 찾아보았다.

 

오오... 딱 하나 나왔다. 심지어 그룹도 level2에 속해있어서 읽고 실행하는 것도 가능하다. 아마도 이것이 단서인가 보다. 바로 실행한다.

 

이런식으로 나온다. 뭐지? 진짜 그냥 편집기 인건가..?

 

:help를 입력했더니 진짜 설명서가 나온다. 이걸로 뭘 해야하는 걸까. 분명 권한부분을 보면 SetUID가 설정되어 있다. 이걸 잘 활용해야 하는 것 같은데...

 

혹시 몰라 디버깅 해보았더니 위와 같이 나온다. 사용하는 함수는 setreuid와 system이다. 먼저 system 함수의 인자가 무엇인지 봐야겠다.

run을 사용하였더니 또 권한 문제가 생긴다. 해당 파일을 level2/tmp에 옮겨서 다시 실행하였다.

 

단순하게 /bin/vi를 실행하는 명령어이다. 이걸 가지고 무얼 해야하는건가... 싶다. 일단 /bin/vi를 실행하는 editor 실행 파일을 왜 만들었는지 생각하면서 ls -al /bin/vi를 실행해보았다.

 

root의 소유이며, root 그룹에 속해있는 /bin/vi 파일인 것이었다...! 

 

일단 조금 더 알아보기 위해 /usr/bin/editor 를 실행한 후에 아무거나 입력하고 test라는 이름으로 저장하였다. 그 후에 ls -al을 이용해서 파일의 정보를 보았다.

 

와! editor가 level3의 소유면, 해당 프로그램을 통해 만들어지는 파일도 level3의 소유가 되는 것 같다!

그렇다면, /usr/bin/editor를 이용해서 my-pass 명령어를 실행하는 코드를 작성한 다음에, 그걸 실행시키면 파일 소유자인 level3의 비밀번호가 나오지 않을까?

 

//source.c
#include <stdio.h>

int main(){
        system("my-pass");
        
        return 0;

 

엥..? 왜 그런가 봤더니 

 

source.c는 level3의 파일이지만, source 실행파일은 level2의 파일이다. 이렇게 되는 거구나...

 

그렇다면 source.c 의 내용을 그냥 a.out 이라는 이름의 파일로 저장한 다음 실행시키면 실행이 될까? 

 

될 리가 없지...

혹시나 해서 system("my-pass") 대신 system("/bin/bash")를 사용한 test2.c를 만들어서 실행해보았다.

 

역시나 level2의 소유이다. 그렇다면.. /usr/bin/editor을 이용해서 만든 level3 소유의 파일을 바로 실행시킬 수 있는 방법은 없을까..?

 

C언어를 사용하는 방법이 생각이 났는데 테스트를 먼저 해봐야 할 것 같다. 생각한 방법은 다음과 같다.

1. 만약 system 함수에 인자로 "ls"를 보내는게 아닌, "ls"를 저장한 문자열 s1을 인자로 넘겨도 똑같이 ls 명령어가 사용될까?

2. 가능하다면 /usr/bin/editor를 이용해서 my-pass 라는 문자열을 저장한 mypass 텍스트 파일을 만들어서,

3. 1번의 실행파일을 test로 가정한다면, ./test << mypass를 이용해 level3 소유의 텍스트파일의 문자열을 argv[1]로 넘겨서 my-pass가 실행되게 한다면

4. level3의 비밀번호가 나오지 않을까?

 

먼저 system 함수의 인자로 문자열 변수가 올 수 있는지 테스트해보았다.

//test.c
//gcc -o test test.c
#include <stdio.h>
int main(){
        char* s1="ls";
        system(s1);
        
        return 0;                    
}       

 

 

오! 정상적으로 ls 명령어가 실행된다. 그렇다면 이제 /usr/bin/editor를 이용해 mypass 파일을 만들어본다. 그리고 코드도 살짝 바꾸어준다.

 

//test.c
//gcc -o test test.c
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]){
        system(argv[1]);
        
        return 0;                    
}   

오오.... 이제 ./test에 mypass의 문자열을 넣어주면 되는데, 이때 ./test mypass 라고 입력하면 "mypass"라는 문자열이 인자로 넘어간다. 문자열을 그대로 넘기는게 아니라 해당 파일 내의 문자열을 넘기고 싶다면 백틱(`)을 이용하면 된다. 예를 들어, pwd를 입력하면 현재 디렉토리인 /home/level2가 나온다. 이 때, ./test pwd 를 실행하면 system("pwd")가 되어서 /home/level2 가 출력되지만, ./test `pwd`를 실행하면 system("/home/level2")가 되는 것이다. 같은 원리로, cat mypass를 사용하면 my-pass가 출력되는데, 이 my-pass를 사용해야 하기 때문에 인자로 `cat mypass`를 넘겨줘 보았다.

 

으... 이걸 원한게 아닌데... 열심히 했는데 결국 뻘짓(?)이였다. 입력하는 텍스트 파일이 level3의 파일이여도, 실행 파일이 level2의 파일이여서 그런것 같다. 다시 원점으로 돌아가서, /usr/bin/editor 실행파일을 어떻게 활용할까...

도저히 안되겠어서 hint 파일을 열어보았다.

텍스트 파일 편집 중 쉘의 명령을 실행시킬 수 있다는데...

아니 선생님!!!!!!! 지금 그걸 못하고 있는 거잖아요 제가!!!!! 

후.. 그래도 틀린 길로 가고 있지 않다는 말 같아서 그나마 위로가 된다.

아니 잠깐 근데 편집 중에 실행시킨다고? 

편집을 통해 텍스트 파일을 만드는게 아니라 편집 "중에" 쉘을 띄울 수 있는 방법이 있다는 말 같다.

그래도 모르겠는데... 풀이를 보기는 죽어도 싫다.. 그래서 편집창을 키고 이것 저것 해보다가, 엄청난 것을 발견했다.

 

아무생각 없이 쓴 pwd인데, 실제로 경로가 출력이 됐다. 이건가보다..! 무턱대고 :my-pass를 쳐보았다.

이게 아닌가보다...!

예전에 얼핏 봤을 때, 명령어 여러개를 ;으로 구분하여서 한줄에 쓰는 방법이 있다고 봤다. 예를 들어,

[level2@ftz tmp]$ clear;ls

이렇게 입력하면, 우선 clear로 화면을 다 지워주고, ls가 실행되는 식이다. editor의 하단부분에서도 :pwd가 정상적으로 실행되니까 :pwd;my-pass를 입력하면 pwd가 실행 된 후에 my-pass까지 실행되진 않을까

 

실행되지 않았다고 한다...

 

위의 텍스트 편집 공간은 입력만 있을 뿐 반응이 없지만, 맨 아래의 한줄은 입력하는 즉시 반응이 온다. 분명 무언가 이 곳을 통해서 쉘을 불러내야 할 것 같은 직감이 든다.

ls를 입력해도 오류가 출력되지 않는 걸 보니, 명령어로 인식되어 어떠한 동작이 이루어진 것이라 판단했다. 이것저것 입력해보다가  !만 입력해보았다. !는 어떠한 명령어와 함께 사용되어야 하는 기호인데 예를 들어, :q가 종료이고, :!q는 강제종료인 그런 느낌이다. 만약 !하나만 사용하면 어떻게 될까.

:!
[No write since last change]

Hit ENTER or type command to continue

별거 없어보이지만, 이전의 명령어들 과는 다르게 한 줄이 아닌 여러 줄이 출력되었다. 그럼 혹시 아까의 ls도 출력이 다음 줄로 넘어가서 보이지 않았던건가 싶어서 !ls를 입력해보았더니, 그 전에는 출력이 안되던게 출력되었다.

~
~
~
:ls



~
~
~
:!ls
[No write since last change]
1234  editor  ls

Hit ENTER or type command to continue

출력이 다음 줄로 넘어가서 안보였던 게 맞았나보다. 여러 줄을 출력해야 하는 기본 명령어 !와 함께 사용하니 그 아랫줄에 출력 결과가 나온 것이다.

좀만 더 해보면 될 것 같은데...! 혹시나 하는 마음에 :!my-pass 를 입력해보았다.

 

.....?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!?!??!???!?!?!?!

이거였구나... 드디어.... 5시간의 노력이 빛을 발하는 순간이다... 

정리하자면 이렇다.

1.

[level2@ftz tmp]$ ls -al /usr/bin/editor
-rwsr-x---    1 level3   level2      11651  9월 10  2011 /usr/bin/editor

유저의 실행권한이 s로 되어 있기 때문에, 그룹 사용자가 해당 파일을 실행하면 일시적으로 유저의 권한을 얻게 된다. 해당 실행 파일은 level3의 실행파일 이기 때문에, level2의 유저가 해당 파일을 실행하는 동안 level3이 되는것이다. 이 때, my-pass 명령어를 실행했기 때문에 level3의 암호가 출력된 것이다.

 

2.

vim을 사용하는 중에 맨 하단에 옵션을 설정하는 부분(?)에서 :!명령어 를 사용하면 해당 명령어의 결과가 출력된다. 쉘을 이용할 수 있다는 말이다.

 

 

이제 level3으로 고고~!