bandit Write-up

Bandit Level 21 ~ 25

부산영롱 2023. 12. 5. 18:36

Bandit Level 21 → Level 22

cron에 의해 자동으로 프로그램이 일정한 간격으로 실행되고 있고 /etc/cron.d/ 에서 어떤 명령이 실행되고 있는지 확인해보라고 한다. 

/etc/cron.d 디렉토리에 들어가서 어떤 파일들이 있는지 확인해보았다.

여러 스케줄링 작업이 있는데 우리가 필요한 bandit22의 cron을 살펴보니 매 분마다 cronjob_bandit22.sh 라는 스크립트를 실행하고 표준 출력과 표준 오류를 모두 /dev/null로 리다이렉션하여 출력을 무시하는 작업이 등록되어있다.

 

'&> /dev/null' 는 출력을 생성하지 않고 명령을 조용히 실행하기 위해 종종 수행된다고 한다.

공격자가 root권한으로 cron에 작업을 등록하여 원하는 데이터를 지속적으로 탈취할 수 있을 듯 하다.

 ** 참고 : 해킹한 후 백도어를 실행시키기 위해 cron을 이용한다고 한다

 

'cronjob_bandit22.sh' 는 어떤 스크립트인지 확인해봐야겠다.

/tmp 디렉토리에 644 권한을 가진 특정문자열의 파일을 생성하고 bandit22의 패스워드를 그 파일로 입력하는 스크립트다.

생성된 파일은 누구나 읽을 수 있기 때문에 bandit21 계정으로도 읽을 수 있었다.


Bandit Level 22 → Level 23

이번에도 cron 문제이다. 똑같이 /etc/cron.d 디렉토리에 있는 파일을 확인하여 어떻게 동작하는지 확인해보라고 한다.

cron에 의해 /usr/bin/cronjob_bandit23.sh 스크립트가 조용히 실행되고 있고 해당 스크립트 내용을 불러왔다.

 

현재 사용자의 이름을 얻어와서 변수 'myname'에 할당하고 'myname' 변수의 값을 이용하여 "I am user" 다음에 오는 문자열을 만들고, 이 문자열을 MD5 해시로 변환한 후, 그 해시 값을 'mytarget' 변수에 할당한다.

마지막으로, /etc/bandit_pass/ 디렉토리에 있는 현재 사용자의 비밀번호 파일을 '/tmp/(변환된 MD5 해시값)에 복사했다는 메시지를 출력한다.

 

어떻게 동작하는지 하나씩 테스트 해보자

첫번째는, 현재 사용자를 묻는 'whoami' 명령어를 사용하여 'bandit22' 를 출력한다.

두번째는, "I am user bandit22" 문자열을 md5 해시로 변환한 값이다. 뒤에 출력되는 '-' 은 파일명이 들어갈 자리인데 파일이 아닌 데이터를 입력으로 받아왔기 때문에 '-' 이 표시된다.

세번째는, md5 해시로 변환한 데이터에서 ' '(공백)을 구분자로 정하고 첫번째 필드인 해시값을 출력한다.

네번째는 스크립트를 실행한 결과이고 bandit22의 패스워드를 /tmp/(해시값) 파일에 복사했다는 메시지가 뜬다.

 

하지만 우리는 bandit23의 패스워드가 필요하기에 "I am user bandit23" 문자열의 md5 해시값을 알아야한다.

"I am user bandit23" 문자열의 md5 해시값을 확인한 뒤 해당 파일을 확인하면 다음 패스워드를 알 수 있다.


Bandit Level 23 → Level 24

역시 cron 문제이고 이번 레벨에서는 첫번째 쉘 스크립트를 직접 작성해야한다. 그런거 해본적 없는데.. 고난이 예상된다.

먼저 /etc/cron.d 에 있는 cronjob_bandit24 파일을 확인해보자

'@reboot'은 시스템이 부팅될 때마다 실행하라는 뜻이다. ' cronjob_bandit24' 파일 내용을 설명하자면 시스템 부팅 시 & 매 분 마다 'bandit24' 사용자로서 '/usr/bin/cronjob_bandit24.sh' 스크립트를 실행하고 아무 출력도 나오지 않도록 동작한다.

 

이제 '/usr/bin/cronjob_bandit24.sh' 스크립트가 어떤 내용인지 확인해보자

스크립트 내용을 찬찬히 뜯어보도록 하자.

    1. myname=$(whoami): 현재 사용자의 이름을 변수 myname에 저장합니다.
    2. cd /var/spool/$myname/foo: /var/spool/$myname/foo 디렉토리로 이동합니다.
    3. echo "Executing and deleting all scripts in /var/spool/$myname/foo:": 실행 메시지를 출력합니다.
    4. for i in * .*;: 현재 디렉토리의 모든 파일과 숨겨진 파일에 대해 반복합니다.
    5. if [ "$i" != "." -a "$i" != ".." ]; then: 현재 파일이 .이나 ..이 아닌 경우에만 아래의 작업을 수행합니다.
    6. echo "Handling $i": 현재 처리 중인 파일을 출력합니다.
    7. owner="$(stat --format "%U" ./$i)": 현재 파일의 소유자를 확인하고, 이를 owner 변수에 저장합니다.
    8. if [ "${owner}" = "bandit23" ]; then: 파일의 소유자가 "bandit23"인 경우에만 아래의 작업을 수행합니다.
    9. timeout -s 9 60 ./$i: 파일을 60초 동안 실행하고, 실행 중에 시간 초과(signal 9)가 발생하면 프로세스를 종료합니다.
    10. rm -f ./$i: 파일을 삭제합니다.
    11. fi: if 문의 끝을 나타냅니다.
    12. done: for 루프의 끝을 나타냅니다.

그래서 이 문제의 핵심은 '/var/spool/bandit24/foo' 디렉토리 안에 'bandit23' 계정에서 생성한(소유자가 'bandit23'인) 스크립트를 심어놓으면 소유자가 'bandit23'인 스크립트를 찾아서 'bandit24' 사용자 쉘(권한)로 실행한다는 것이다.

 

따라서, 우리는 'bandit24' 사용자가 자신의 패스워드를 우리에게 전달시킬 스크립트를 생성하여 '/var/spool/bandit24/foo' 디렉토리에 심으면 된다.

일단 작업을 할 디렉토리를 만들고 해당 디렉토리 안에 스크립트를 생성한다.

'/etc/bandit_pass/bandit24' 에 있는 bandit24 패스워드를 'hun23.txt'로 보내기로 했다.

패스워드를 받을 'hun23.txt' 파일도 생성했고.. 스크립트를 심어놓기 전에 권한 수정이 필요할 듯 하다.

others(bandit24)가 스크립트를 실행하고 .txt 파일에 데이터를 써야하니 스크립트에는 실행 권한을, 텍스트 파일에는 쓰기 권한을 주면 될 것 같다.

권한 설정도 완료했고 이제 스크립트를 '/var/spool/bandit24/foo' 디렉토리에 복사해놓고 패스워드가 잘 들어오는지 지켜보면된다. 매 분 마다 스크립트가 실행되기 때문에 잘 작동한다면 1분안에 패스워드가 들어올 것이다.

성공!!


Bandit Level 24 → Level 25

'bandit24' 패스워드와 4자리 PIN번호를 30002 포트로 전송하면 다음 패스워드를 준다고 한다.

4자리 PIN 번호는 무차별 대입공격인 브루트 포싱을 사용해야하고 매 시도마다 새로운 커넥션을 생성하지 않아도 된다고 하니 모든 경우의 수를 한번에 넘겨줘야할 것 같다. 

30002 포트에 접속해보니 패스워드를 어떻게 입력해야하는지 설명이 나온다.

'bandit24' 패스워드와 pincode를 한 줄에 입력해야하고 띄어쓰기로 구분을 지으라고 한다.

테스트로 '현재 패스워드 0000'를 입력해보니 정확한 핀코드를 입력하라는 메시지가 나온다.

설명에 맞게 스크립트를 작성해보자.

우리가 작업할 폴더를 하나 만들고 거기에 'bandit24' 패스워드 + PIN번호를 생성하여 localhost의 30002 포트로 전송하는 스크립트를 만들었다.

초기 권한은 664로 되어있어 실행권한이 없으니 chmod 명령어로 실행권한을 부여하고 스크립트를 실행해보았다.

 

흠.. 비밀번호 하나 입력하는데 10초정도 걸리고 모든 경우의 수를 다 시도하려면 하루종일 기다려도 부족할 것 같다.

이거 아닌거 같은데.. 다시 보니 내가 만든 스크립트는 매 시도마다 새로운 커넥션을 생성해 안내메시지가 매 시도마다 나오고 있었다.

 

반복문 안에 nc 명령어를 넣으니 매 시도마다 접속을 시도하는 것이다.

이 방법이 아니라 반복문으로 모든 경우의 비밀번호 파일을 만든 뒤에 한꺼번에 nc 명령어로 넘겨야 할 것 같다.

한꺼번에 여러줄을 입력할 수 있는지 간단하게 테스트 파일을 만들어서 시도해보았다.

음.. 되는 것 같다! 스크립트를 수정해보자.

반복문이 실행된 결과를 누적시키기 위해 '>>'를 사용했고 'result'라는 파일로 출력하도록 했다.

이제 'result'파일을 30002 포트로 보내기만하면 끝인가..!

또 문제가 발생했다...  'result' 파일을 전송했는데 라인이 너무 길어서 그런지 중간에 멈추는 현상이 발생했다.

결과값을 'result.txt'로 출력해서 라인 수를 확인했더니 6302번째 라인에서 멈추는 것을 확인할 수 있었다.

5천개 라인씩 파일을 만들어서 보내야겠다.

미션 클리어!


Bandit Level 25 → Level 26

다음 레벨인 'bandit26'로 접속하는 것은 상당히 쉬울 것이라고 한다...(??)

'bandit26'은 bash가 아닌 다른 쉘을 사용한다고 하고 우리는 이 쉘이 어떻게 작동하는지 찾고, 그것을 탈출(?)하는 방법을 찾아야한다.

상당히 쉬울 것이라고 해서 그런지 'bandit26' 계정의 개인키가 떡하니 들어있다.

 

다른 쉘을 사용한다 했으니 passwd 파일에서 어떤 쉘을 사용하는지 확인하고 해당 파일을 확인해보았다.

Bourne Shell로 동작하고 'more' 명령어로 'text.txt' 파일을 읽고 종료하는 것 같다.

어떻게 풀어라는건지 감이 잡히질 않아서 일단 접속해보기로 했다.

접속되는 듯 하더니 연결이 끊긴다. 어쩌라는것인가..

권한 때문에 passwd에서 쉘 경로를 수정할 수도 없고.. 'ssh' 명령어 뒤에 'cat' 명령어로 패스워드 파일을 읽는 것도 안된다.

 

결국.. 다른 사람의 풀이를 참고했다..

이 문제의 핵심은 'more' 명령어였다. 'cat' 명령어처럼 파일 내용을 모두다 보여주는게 아니라 한 페이지씩 보여주는 명령어인 것 정도야 알고있었지만 숨겨진 기능들까지는 알지 못했다.

ssh로 bandit26 계정에 접속할때 'more' 명령어가 실행되려면 페이지에 파일 내용 전부가 나올 수 없도록 해야한다.

 

위에서 ssh로 접속했을 때 접속되는 듯하다가 연결이 끊기는 이유는 text.txt 파일의 내용이 화면에 모두다 출력됐기에 'more' 명령어가 실행되지 못한 것이었다.

 

우리는 한 페이지에 bandit26이라는 글자가 다 나올 수 없을 정도로 창크기를 줄여서 ssh 접속을 해야한다.

'more' 명령어가 실행되고 있다. 현재 'bandit26' 계정에 접속해서 'more' 명령어를 실행 중인 상태이다.

 

여기서 또 알아야 할 사실은 'more' 명령어가 실행 중일 때 v를 눌러서 vim 편집모드를 사용할 수 있고 ':e' 명령으로 원하는 파일을 불러올 수 있다.

 

이 기능을 사용하여 /etc/bandit_pass/bandit26에 있는 패스워드를 가져오면 된다.

여기서 끝이 아니다. vim 편집모드에서 :set shell ? 을 입력하면 현재 쉘을 확인할 수 있다.(shell=/usr/bin/showtext)

:set shell=/bin/bash를 입력해서 bash쉘로 바꾼 뒤 :shell 혹은 :sh를 이용해서 shell(:12)로 빠져나갈 수 있다

 

 

'bandit Write-up' 카테고리의 다른 글

Bandit Level 31 ~ 33  (0) 2023.12.13
Bandit Level 26 ~ 30  (0) 2023.12.10
Bandit Level 16 ~ 20  (1) 2023.12.05
Bandit Level 11 ~ 15  (1) 2023.12.04
Bandit Level 6 ~ 10  (0) 2023.12.01