본문 바로가기

Pwnable/OvertheWire

[ProjectH4C] OverTheWire Bandit 0 ~ 25 write-up

OverTheWire에서 제공하는 워게임 중 Bandit는 리눅스의 기능을 익힐 수 있도록 만들어진 워게임이다. 시스템 해킹을 위해선 리눅스를 능숙하게 다룰 줄 알아야 하기 때문에, 해당 워게임을 통해 리눅스에 대해 공부해보고자 한다.

OverTheWire 워게임은 ssh를 이용해 접속해야 한다. MacOS 기준으로 작성하자면, ssh 접속을 위한 명령어는 아래와 같다.

 

ssh [사용자 이름]@[서버 이름] -p [포트 번호]

OverTheWire에서 Bandit 탭을 클릭하면 왼쪽 상단에 서버 이름과 포트 번호가 나온다. 서버 이름은 bandit.labs.overthewire.org 이고 포트 번호는 2220이다. 참고로 시작 단계인 bandit0의 비밀번호는 bandit0이다.

 


 

Bandit 0

먼저, 리눅스의 기본 명령어 중 "ls" 라는 것이 있다. ls는 "List Segment"의 약자로, 파일 및 디렉토리를 표시하는 기능을 한다. ls 명령어의 옵션 중에 파일의 상세 정보를 출력하기 위해선 "-l" 옵션을 사용하고, 숨김 파일까지 모두 보기 위해서는 "-a" 옵션을 사용한다. 숨김 파일까지 모두 출력하고, 상세정보를 출력하려면 두 옵션을 합쳐서 "-al"로 사용할 수 있다.

 

두 번째로 "cat"이란 명령어가 있다. cat은 파일 안의 내용을 출력하거나, 파일을 생성 또는 수정하거나, 다른 파일에 내용을 복사하는 용도로 쓰이는데 보통은 내용을 출력할 때 많이 쓰인다.

 

리눅스는 처음 로그인하면 윈도우처럼 화면에 아이콘들이 떠 있는 것이 아니기 때문에 다른 디렉토리로 이동하거나 파일을 사용하기 위해선 ls 명령어로 파일 및 디렉토리 목록을 출력해주어야 한다. 

Bandit0에 로그인 한 후에 ls -l 명령어를 실행하면 readme라는 파일이 보인다. 참고로 ls -l의 결과 중 맨 앞의 -rw-r----- 부분은 권한을 나타내는 부분인데, 맨 앞에 "d"라면 해당 파일이 디렉토리라는 것이고, "-"라면 디렉토리가 아니라는 뜻이다. 파일의 내용을 출력하기 위해 cat readme 명령어를 실행한다.

 

해당 내용이 다음 레벨의 패스워드이다. 로그아웃한 후 bandit1로 로그인하면 된다.

 

 

 

 

Bandit 1

로그인 한 후에 ls -l 명령어를 사용해 어떠한 파일이 있는지 확인해준다.

 

이름이 "-"인 파일이 하나 출력되었다. 이를 출력하기 위해 cat -을 입력하면 파일의 내용이 출력되는 것이 아니라 입력 대기 상태가 된다. 이 상태에서 무언가 입력하면 입력한 것이 그대로 출력되어 나온다. [cat 파일이름]을 실행하면 파일 이름이 입력되어 파일의 내용이 출력되는 형식이지만 실행인자 없이 cat만 사용하면 입력한 값을 그대로 출력하게 된다. "-"은 어떠한 명령어에 옵션을 부여할 때 사용되는 기호인데, cat - 명령어를 실행하면 "-"이 옵션에 관련된 기호로 인식되어 파일 이름이 출력되지 않는다. 이를 파일 이름으로 사용하기 위해선 디렉토리 명을 전부 입력해주면 된다.

디렉토리에는 절대 경로와 상대 경로가 존재한다. 절대 경로란, 최상위 디렉토리인 "/"에서부터 해당 위치까지의 경로를 말하며 상대 경로는 현재 위치에서부터의 경로를 뜻한다.

현재 나의 위치가 최상위 디렉토리에 있는 home 안에 존재하는 bandit1 디렉토리라고 가정하고, bandit1에는 "file"이라는 텍스트 파일이 존재한다고 가정하면, 해당 파일의 경로를 상대 경로와 절대 경로로 나타낼 수 있다.

절대 경로로 표현한다면 /home/bandit1/file 이 되고, 상대 경로는 ./file 로 나타낼 수 있다. "./"은 현재 디렉토리를 의미한다. 반대로, 해당 디렉토리 바로 위에 있는 디렉토리를 나타낼 땐 "../"을 이용한다. 위의 경우엔 "../"은 home 디렉토리가 된다.

 

다시 문제로 돌아와서, "cat -"에서 -가 옵션을 의미하는 기호가 아닌 파일명으로 인식하게 하려면 경로 명을 포함해서 "cat ./-"를 실행하면 된다.이는 현재 디렉토리 내의 "-"라는 파일의 내용을 출력하라는 의미가 된다. 해당 명령어를 실행하면 패스워드가 출력된다.

 

Bandit2의 암호이다.

 

 

 

Bandit 2

"ls -l"을 실행해주면 다음과 같이 나온다.

 

이를 출력하기 위해 "cat spaces in this filename"을 입력하면 다음과 같은 오류가 나온다.

cat은 한번에 여러 개의 파일을 출력할 수도 있는데, 이러한 경우 각각의 파일을 띄어쓰기로 구분해서 입력해주어야 한다. 위의 경우 이름이 각각 "spaces", "in", "this", "filename"인 파일 4개를 출력하라는 명령어로 인식된다. 파일 이름에 띄어쓰기가 들어있을 경우, 띄어쓰기 앞에 \(역슬래시)를 입력해서 해당 띄어쓰기가 하나의 문자로 처리되게끔 할 수 있다.

입력을 cat spaces\ in\ this\ filename으로 해주면 제대로 된 결과를 얻을 수 있다.

 

bandit3의 패스워드이다. 

 

 

Bandit 3

"ls -l"을 실행하면 다음과 같이 나온다.

 

맨 앞이 "d"이기 때문에 inhere는 파일이 아닌 디렉토리이다. 리눅스에서 디렉토리를 이동하는 명령어로 "cd"가 존재한다.

"cd"는 "Change Directory"의 약자로, 디렉토리 간에 이동할 때 사용된다. 사용법은 "cd 디렉토리명"이며, 현재 위치하는 디렉토리에서 한 단계 위의 디렉토리로 이동하려면 "cd .."을 입력하면 된다. 디렉토리는 한 번에 한 단계만 이동할 수 있는 것은 아니며, 이동하고자 하는 경로를 순서대로 입력하면 한 번에 여러개를 이동할 수 있다. 예를 들어 현재 나의 위치가 최상위 디렉토리( "/" )이고, home 디렉토리 안의 bandit3으로 이동하고자 한다면 "cd /home/bandit3"을 입력하면 한 번에 이동할 수 있다.

 

문제의 inhere 디렉토리로 이동하기 위해 "cd inhere" 명령어를 입력한다. 이동 후에 inhere 내의 파일을 확인하기 위해 "ls -l"을 입력한다.

 

파일이 하나도 출력되지 않는다. 숨김 파일이 있을 수도 있으니 "-al" 옵션을 주어서 "ls -al"을 다시 실행해본다.

.hidden이라는 파일이 출력되었다. 리눅스에선 파일을 숨김처리 할 땐, 파일 이름 앞에 " . "을 붙여주기만 하면 된다. ".hidden" 파일은 숨김 파일 처리가 되어있는 것이다. 해당 파일의 내용을 출력할 땐 "hidden"이 아닌 ".hidden"으로 점(.)까지 전부 붙여줘야 한다.

 

bandit4의 패스워드가 출력되었다.

 

 

Bandit 4

로그인 한 후에 "ls -l" 명령어를 입력하면 inhere 디렉토리가 보인다. "cd inhere" 명령어로 해당 디렉토리로 이동한다.

 

이동한 후에 "ls -l" 명령어를 실행하면 위와 같이 출력된다.

cat 명령어를 이용해 파일의 내용을 하나하나 다 확인할 수도 있지만, 모든 파일의 내용을 한번에 출력하는 것도 가능하다. 이 때는 more 명령어나 head 명령어를 사용하면 된다.

 

more [파일명]

파일의 내용을 읽어서 화면 단위로 끊어서 보여진다. 기존적으로 한 화면에 보여줄 수 있는 만큼 출력되고, 내용이 더 존재한다면 <Enter> 키를 이용해서 한 줄씩 넘기거나, <Space bar> 키를 입력해서 한 화면씩 넘길 수 있다. more 명령어로 출력한 내용은 한 번 지나가면 다시 볼 수 없기 때문에, 다시 보고자한다면 more 명령어를 다시 입력해서 봐야한다는 단점이 있다.

 

head [파일명]

파일의 내용을 한 행을 단위로 나누어서 출력한다. 아무 옵션 없이 입력하면 앞에서 10행까지의 내용만 보여준다. 만약 파일의 내용이 10행을 넘어가게 되면 -n [출력 행 수] 옵션을 이용해서 더 많이 출력할 수 있다.

 

리눅스도 윈도우와 동일하게, 모든 파일을 가리킬 땐 " * " 을 이용해서 표현한다. 예를 들어 "cat ./*" 명령어를 입력하면 현재 디렉토리 내의 모든 파일을 출력한다는 의미이다. 이를 이용해서 inhere 내의 모든 파일을 한번에 출력할 수 있지만, 실제 결과를 보면 쭉 이어져서 어디서부터 어디까지가 한 파일의 내용인지 알 수가 없다. more 또는 head 명령어가 적합할 것 같다.

"ls -l " 출력 결과를 다시 보면 bandit5 bandit4 뒤에 33이라고 써있는데 이는 파일의 크기를 나타낸다. 33이면 그리 크지 않은 사이즈이기 때문에 head 명령어를 이용해서 모든 파일의 내용을 출력해주면 된다. 명령어는 다음과 같다.

 

$ head ./*

 

현재 디렉토리에 있는 모든 파일의 앞 10행을 출력하라는 명령어이다. 명령어를 사용하면 다음과 같은 출력을 얻을 수 있다.

 

모든 파일의 내용은 한 줄이고, 이상한 문자들이 들어있지만 -file07에는 누가봐도 비밀번호 같은 문자열이 저장되어 있다. 해당 비밀번호를 입력해 bandit5에 로그인하면 된다.

 

 

Bandit 5

로그인 후에 ls -al 명령어를 입력하면 inhere 디렉토리가 하나 보인다. cd inhere 로 이동해준다. 이동한 후에 ls -al 명령어를 다시 실행하면 다음과 같이 나온다. 

 

 

리눅스에선 파일을 찾을 때 find 명령어를 사용하면 된다. 기본적인 사용 방법은 아래와 같다.

$ find [경로]

위 명령어만 사용하면 해당 경로 아래에 있는 모든 파일들을 출력한다. 그 파일들 중 원하는 파일을 찾기 위해선 몇 가지 옵션을 더 설정해야 한다. find 명령어의 옵션은 다음과 같다.

-user 유저이름
해당 유저 소유의 파일들을 찾는다.

-group 그룹이름
해당 그룹 권한의 파일들을 찾는다.

-name 파일이름
파일이름에 검색하고자 하는 문자열이 들어있는 파일을 찾는다.

-perm 권한
해당 권한을 가진 파일을 출력한다. 예를 들어, -perm 644로 입력하면 rw-r--r-- 권한을 가진 파일을 찾는다.
-perm +644로 입력하면 6 4 4 중 하나라도 만족하는 파일을 찾는다.
-perm -644로 입력하면 해당 권한 이상의 파일들을 모두 찾는다.


-size 크기
해당 크기와 일치하는 파일들을 찾는다. 
이 때, 기본 단위는 블록이며, 찾고자 하는 파일 크기의 단위를 바이트로 지정하고 싶다면 뒤에 c를 붙이면 된다.
지정한 크기보다 큰 파일들을 찾고 싶다면 +크기, 작은 파일들을 찾고 싶다면 -크기로 입력하면 된다.

 

OverTheWire 홈페이지에 각 레벨마다 목표가 적혀있다. Bandit 5는 다음과 같이 적혀있다.

Level Goal
The password for the next level is stored in a file somewhere under the inhere directory and has all of the following properties:

human-readable
1033 bytes in size
not executable

 

사람이 읽을 수 있는 형태이고 1033 바이트의 크기를 가지며, 실행파일이 아니라고 적혀있다. find 명령어의 옵션 중 size 옵션을 사용하면 된다. 단위는 바이트이기 때문에 -size 1033c로 입력해야 한다.

 

파일이 딱 하나 나온다. cat 명령어를 이용해 패스워드를 출력한 다음, bandit6에 로그인하면 된다.

 

 

 

Bandit 6

해당 레벨의 목표는 다음과 같다.

 

Level Goal
The password for the next level is stored somewhere on the server and has all of the following properties:

owned by user bandit7
owned by group bandit6
33 bytes in size

서버 어딘가에 패스워드가 저장된 파일이 숨어있는데 파일의 정보는 다음과 같다.

1. bandit7 유저의 파일.

2. bandit6 그룹의 파일.

3. 파일 크기는 33바이트.

 

find 명령어를 이용해 쉽게 찾아낼 수 있다. 위의 조건들을 전부 사용해서 find 명령을 입력하면 된다. 서버 어딘가에 저장되어 있기 때문에 현재 디렉토리 아래에 저장되어 있지 않을수도 있다. 이럴 땐 경로를 최상위 디렉토리 ( / )로 입력하면 모든 파일에 대해 검색하게 된다.

 

$ find / -user bandit7 -group bandit6 -size 33c

 

 

Permission denied가 굉장히 많이 떠서 찾아보기가 힘든데, 이럴 땐 명령어의 뒤에 2>/dev/null을 입력해주면 허가 거부된 파일에 대해서는 출력하지 않을 수 있다.

 

출력이 하나만 나왔고, 파일이름도 bandit7password인걸 보니 해당 파일이 맞는 듯 하다. 

 

2>/dev/null에 대해 설명하자면, 먼저 /dev/null이란 말 그대로 null 즉, 0인 파일이다. 기본적으로 0바이트이고 뭘 넣어도 0바이트인 파일이다. 그 앞의 2는 표준 에러를 뜻한다. 해석하자면 표준 에러를 리다이렉션(>)을 이용해 화면에 출력하지 않고 /dev/null 파일에 저장한다는 의미이기 때문에 화면상에 출력되지 않는 것이다. /dev/null 파일에 들어간 표준 에러는 사라지게 된다.

앞의 숫자가 0이면 표준 입력, 1이면 표준 출력, 2이면 표준 에러를 뜻한다.

 

 

bandit7.password 파일의 내용을 출력하고 bandit7로 로그인하면 된다. 출력할 땐 현재 디렉토리에 존재하는 파일이 아니기 때문에 경로를 전부 써주어야 한다.

 

Bandit 7

해당 레벨의 목표는 다음과 같다.

 

Level Goal

The password for the next level is stored in the file data.txt next to the word millionth

data.txt 파일의 내용 중 millionth 라는 단어 뒤에 패스워드가 저장되어 있다고 한다.

 

ls를 입력하면 data.txt 파일이 하나 보인다. cat을 이용해 출력하면 단어와 암호화 형식의 키가 한 쌍을 이루는 사전 형식으로 구성되어 있다. 이 중 millionth라는 단어와 쌍을 이루는 키가 패스워드가 될 것이다.

 

이 많은 단어들을 하나씩 찾아볼 수는 없으니, grep 명령어를 이용하도록 한다.

 

Grep

파일 내에서 원하는 내용을 찾을 때 사용되는 명령어이다. 사용법은 다음과 같다.

 

$ grep [옵션] [찾을 문자열] [파일명]

 

해당 파일에서 찾고자 하는 문자열이 포함된 행을 출력해준다.

이를 이용해서 data.txt 파일에서 millionth 단어를 찾으면 된다.

 

패스워드를 찾았으니 bandit8에 로그인하면 된다.

 

 

Bandit 8

해당 레벨의 목표는 다음과 같다.

 

Level Goal
The password for the next level is stored in the file data.txt and is the only line of text that occurs only once

해석하자면, 패스워드는 data.txt 파일에 저장되어 있고 한번만 입력된 유일한 문자열이라고 한다. 

해당 파일을 정렬을 이용해 재출력하면 된다.

 

sort

파일의 내용을 옵션에 따라 정리한다. 기본 사용법은 다음과 같다.

cat 파일이름 | sort

이 때, 파일 이름과 sort 사이에 있는 것을 파이프라고 한다. 파이프는 왼쪽의 출력을 오른쪽의 입력으로 보내주는 연결 통로 역할을 한다.

위의 경우엔 파일의 내용을 출력한 결과를 sort 명령어의 입력으로 보내서 파일의 내용을 정리시키는데 사용 된다.

 

sort의 출력을 uniq -c 명령어에 입력해주면 중복을 제거할 수 있다. 이 때, -c 옵션을 이용해 몇 회 중복되었는지 카운팅이 가능하다.

이들을 이용해서 data.txt 파일에서 중복되지 않은 패스워드가 무엇인지 알 수 있다. 명령어는 다음과 같다.

$ cat data.txt | sort | uniq -c

 

문자열이 정렬되고, 몇 회 중복되었는지 문자열 앞에 나타나게 되는데, 이 중에 중복횟수가 1인 문자열이 있다. 이 것이 bandit9의 패스워드이다.

 

 

Bandit 9

해당 레벨의 목표는 다음과 같다.

 

The password for the next level is stored in the file data.txt in one of the few human-readable strings, preceded by several ‘=’ characters.

패스워드는 사람이 읽을 수 있는 문자열 형태이고 앞에 '='이 여러개 들어가 있다고 한다. 먼저, 홈 디렉토리에 존재하는 data.txt를 출력해본다.

알 수 없는 형태의 문자들이다. 이러한 파일을 이진 파일 혹은 바이너리 파일이라고 한다. 사람의 언어로 쓰여있지 않기 때문에, 이를 우리가 읽을 수 있게 바꾸려면 strings 명령어를 이용하면 된다.

 

strings data.txt 명령을 실행하면 다음과 같이 사람이 알아볼 수 있는 형태로 문자열들이 출력된다. 이들 중에서 문자열의 시작이 '=' 여러개로 시작되는 문자열을 찾아야 한다. grep을 이용한다.

 

strings data.txt | grep ==

여러 개라 했으니 한 개는 아닐 것이기 때문에 가볍게 두 개로 검색해보았다.

 

쭉 연결해서 읽어보면 the password is ... 가 된다. 해당 문자열이 bandit10의 패스워드이다.

 

 

Bandit 10

해당 레벨의 목표는 다음과 같다.

 

Level Goal
The password for the next level is stored in the file data.txt, which contains base64 encoded data

data.txt 파일에 숨어있으며 base64 형태로 인코딩 되어있다고 한다.

 


Base64

직역하면 64진법이라는 뜻이며, Binary Data를 문자로 바꾸어주는 인코딩 방식중 하나이다. 바꾸는 값은 ASCII 영역의 문자로만 바꿀 수 있다. 변경하는 방법은, binary data를 6 bit씩 나누어준 뒤에 Base64 색인표에 근거하여 6bit 값에 해당하는 문자로 치환해준다.

 

텍스트에 대해 base64 인코딩을 해주는 방법은 간단하다. text.txt 파일을 인코딩하기 위해선 base64 text.txt 명령어를 실행해주면 된다. 반대로 인코딩 된 파일을 디코딩 하기 위해서는 -d 옵션을 사용하면 된다.

 


data.txt를 그냥 출력해주면 base64로 인코딩 된 문자열이 출력된다. 이를 원래의 문자열로 출력하려면 base 64 -d 명령어를 사용하면 된다.

 

 

bandit11의 패스워드가 출력되었다.

 

 

Bandit11

해당 레벨의 목표는 다음과 같다.

The password for the next level is stored in the file data.txt, where all lowercase (a-z) and uppercase (A-Z) letters have been rotated by 13 positions

data.txt에 패스워드가 저장되어 있고, 모든 문자들이 13씩 이동되어 있다고 한다. data.txt의 내용은 다음과 같다.

 

얼핏보면 The Password is ... 와 형태가 비슷하다. 원래의 문자열을 13씩 빼서 만든 문자열 같다. 해당 문자열을 13씩 뒤로 이동시키면 될 것 같다. rot13 명령어를 이용하면 된다.

 

 


ROT13

rot13에 대해 이해하기 전에 카이사르 암호를 알아보고자 한다. 카이사르 암호란 문자열 암호화 방식 중 하나이며, 가장 기본적인 암호화이다. 모든 문자열을 특정한 숫자만큼 더하거나 빼주는 방식이다. 예를 들어 apple 이라는 문자열을 +3이라는 키값을 주어서 카이사르 암호로 만들면 각 문자에 +3을 해주는 것과 같으며 결과는 dssoh가 된다. 

이러한 카이사르 암호 중에서 키 값을 +13을 준 암호를 ROT13이라고 하는데, 암호화와 복호화가 같은 방식이기 때문에 특별히 이름을 지어준 것이라고 한다. 알파벳은 총 26개이기 때문에, ROT13으로 암호화를 두 번 하면 원래의 문자+26이 되어서 문자열에 변함이 없기 때문이다.


리눅스에서는 지정한 문자열을 바꾸어주는 명령어로 tr이 있다. 사용법은 아래와 같다.

 

$ tr [대상 문자] [바꿀 문자]

대상 문자를 바꿀 문자로 바꾸어 준다. 이를 이용해서 ROT13을 암호화(복호화)할 수 있다. 명령어는 아래와 같다.

$ tr 'A-Za-z' 'N-ZA-Mn-za-m'

'A-Z'와 'a-z'를 각각 'N-Z' 또는 'A-M'과 'n-z' 또는 'a-m'으로 바꾼다. 즉, 대소문자 모두 A ~ M의 문자는 N ~ Z로, N ~ Z는 A ~ M으로 바꾸는 명령어이다. data.txt의 내용을 바꾸어줄 것이기 때문에 입력은 파이프를 통해 data.txt의 내용으로 지정해주면 된다.

$ cat data.txt | tr 'A-Za-z' 'N-ZA-Mn-za-m'

명령어를 입력하면 원래의 문자로 복호화되어 출력되는 것을 볼 수 있다.

 

Bandit12

해당 레벨의 목표는 다음과 같다.

 

The password for the next level is stored in the file data.txt, which is a hexdump of a file that has been repeatedly compressed. For this level it may be useful to create a directory under /tmp in which you can work using mkdir. For example: mkdir /tmp/myname123. Then copy the datafile using cp, and rename it using mv (read the manpages!)

data.txt에 패스워드가 저장되어 있고, data.txt 파일은 반복적인 압축을 통해 나온 파일을 헥사코드로 바꾸어 놓은 것이라고 한다. 해당 레벨을 풀기 위해선 /tmp 디렉토리에 디렉토리를 하나 만들고 data.txt 파일을 복사해서 이름을 바꾸고 이용하는게 좋을 것 같다고 말하고 있다. mkdir /tmp/test 를 이용해 tmp 디렉토리 아래에 test 디렉토리를 만들고, cp data.txt /tmp/test/test.txt 를 이용해 파일을 복사 하였다. 먼저 test.txt는 헥사덤프가 이루어진 파일이기 때문에 xxd -r 명령어를 이용해 바이너리 파일로 만들어주어야 한다. 

xxd 파일이름 : 해당 파일을 헥사코드로 바꾼다.
xxd -r 파일이름 : 헥사코드로 이루어진 파일을 원래의 파일로 되돌린다.

리다이렉션을 이용해 test2.txt 파일에 해당 내용을 저장한다.

 

test2.txt 파일이 생성되었다. 해당 파일이 어떤 파일인지 알아보기 위해선 file 명령어를 이용하면 된다.

 

file 파일이름 : 해당 파일의 종류를 출력한다.

"data2.bin"이라는 파일을 gzip 압축을 이용해 압축한 파일이라고 한다. gzip은 리눅스에서 제공하는 압축 기법중 하나인데, gzip을 이용해 생성되는 압축파일의 이름은 [파일이름.gz]이다. 원래 파일의 이름이 data2.bin이였으니, data2.bin.gz로 이름을 바꾸어 준 후 압축을 풀어보도록 한다.

 

gzip 파일이름 : 해당 파일을 gzip 방식으로 압축한다.
gzip -d 파일이름 : .gz 파일을 압축 해제한다.

 

압축해제한 파일의 종류를 확인해주면 이번엔 bzip2 방식으로 압축 된 파일이라고 한다. bzip2 압축 파일의 이름은 [파일이름.bz2]이다.

data2.bin.bz2로 이름을 바꾸어준 뒤에 bzip2 명령어로 압축을 풀어준다.

 

bzip2 파일이름 : 해당 파일을 bzip2 방식으로 압축한다.
bzip2 -d 파일이름 : .bz2 파일을 압축 해제한다.

 

이번엔 또 data4.bin 파일을 gzip 방식으로 압축한 파일이라고 한다. 이름을 data4.bin.gz 로 바꿔준 뒤에 압축을 해제한다.

 

data4.bin은 tar 파일이라고 한다. tar 파일이란 여러 개의 파일을 하나로 합쳐놓은 것인데, 리눅스에서는 압축할 땐 하나의 파일만 압축할 수 있기 때문에 여러 파일을 한번에 압축할 땐 tar 명령어를 이용해서 여러 개의 파일을 하나로 합친 후에 tar 파일을 압축한다. 그래서 압축 파일들을 보면 .tar.gz 의 형태를 많이 볼 수 있다. tar 명령어 사용법은 다음과 같다.

 

tar cvf 합친이름 파일1 파일2 ... : 파일들을 하나로 합친다.
tar xvf 합친이름 : 하나로 합친 파일들을 각각의 파일로 나누어준다.

 

tar xvf를 이용해서 파일을 분리시켜준다.

data5.bin도 tar 파일이라고 한다. 한번 더 tar xvf를 이용한다.

 

data6.bin 파일이 나왔고, bzip2 방식으로 압축 된 파일이라고 한다. data6.bin.bz2로 이름을 바꾼 후에 압축을 해제한다.

 

data6.bin은 tar 파일이라고 한다. tar xvf를 이용한다.

 

data9.bin 파일을 gzip 방식으로 압축한 파일이라고 한다... data9.bin.gz로 바꾼 후에 압축 해제한다.

 

data9.bin은 텍스트 파일이라고 한다. cat을 이용해 출력해준다.

 

드디어 패스워드가 나왔다. bandit13에 로그인하면 된다.

 

Bandit13

해당 레벨의 목표는 다음과 같다.

 

The password for the next level is stored in /etc/bandit_pass/bandit14 and can only be read by user bandit14. For this level, you don’t get the next password, but you get a private SSH key that can be used to log into the next level. Note: localhost is a hostname that refers to the machine you are working on

 

 

패스워드는 /etc/bandit_pass/bandit14 파일에 저장되어 있고 오직 bandit14 유저만 읽을 수 있다. 이번 레벨에선 패스워드를 얻어내는 것이 아니라 SSH Key를 이용해서 다음 레벨에 로그인하라고 한다.

 


ssh-key

ssh 접속을 할 땐 비밀번호가 아닌 sshkey를 넘겨서 로그인 하는 방법이 있다.

sshkey는 ssh-keygen 명령어를 이용해 만들 수 있는데, public key와 private key가 생성된다. public key는 서버에 생성되고, private key는 로컬(사용자)에 저장된다. ssh 접속을 시도하면 로컬의 private key와 서버의 public key를 비교해서 일치하면 접속시켜주는 방식이다.

ssh key를 이용해 접속할 땐 [-i key이름] 옵션을 사용해야 한다.


 

ls 명령어를 입력하면 sshkey.private 파일이 보인다. 해당 키를 이용해서 bandit14에 접속할 수 있다. 명령어는 아래와 같다.

 

패스워드 없이 ssh-key만 이용해서 bandit14에 로그인하였다. 이제 /etc/bandit_pass/bandit14에 저장된 패스워드를 출력한 후에 bandit14에 접속하면 된다.

 

Bandit14

해당 레벨의 목표는 다음과 같다.

 

The password for the next level can be retrieved by submitting the password of the current level to port 30000 on localhost.

다음 레벨의 패스워드는 현재 레벨의 패스워드를 localhost 서버의 포트번호 30000에 전송해서 얻어낼 수 있다. 라고 해석된다.

 

ssh 통신으로는 값을 넘길 수가 없기 때문에 nc를 이용하도록 한다.

 

NetCat

TCP, UDP를 사용해서 네트워크에 연결해서 데이터를 읽고 쓸 때 사용되는 유틸리티이다. network cat의 줄임말로 네트워크의 연결상태를 읽거나 쓸 때 주로 사용되며, 네트워크에 대한 디버깅, 네트워크 테스트 등을 할 때 주로 사용된다.

기본 사용법은 다음과 같다.

 

$ nc [서버이름] [포트번호]

nc를 이용해 해당 서버에 데이터를 보낼 때는 파이프를 이용해야 한다.

 

$ cat file.txt | nc [서버이름] [포트번호]

 

위의 명령어를 이용해서 해당 서버에 데이터를 전송할 수 있다.

 

 


 

bandit14의 패스워드를 nc를 이용해 전송하려 한다. 패스워드를 파일에 저장한 후에 해당 파일의 출력을 파이프를 통해 넘겨줄 수도 있지만, 홈 디렉토리에선 쓰기 권한이 없기 때문에 echo 명령어를 이용한다. echo는 문자열을 출력해주는 명령어인데, echo [문자열] 을 입력하면 문자열이 그대로 출력된다.

 

해당 레벨의 패스워드를 입력하면 다음 레벨의 패스워드가 출력되도록 nc 설정이 되어있는 듯 하다. 해당 패스워드로 bandit15에 로그인하면 된다.

 

Bandit15

 

해당 레벨의 목표는 다음과 같다.

The password for the next level can be retrieved by submitting the password of the current level to port 30001 on localhost using SSL encryption.

Helpful note: Getting “HEARTBEATING” and “Read R BLOCK”? Use -ign_eof and read the “CONNECTED COMMANDS” section in the manpage. Next to ‘R’ and ‘Q’, the ‘B’ command also works in this version of that command…

다음 레벨의 패스워드는 현재 레벨의 패스워드를 SSL 암호화 한 후에 localhost 서버의 30001 포트에 전송하면 얻을 수 있다. 해당 문제를 풀기 전에 SSL에 대해 알아야 한다.

 

SSL (Secure Socket Layer)

보안 소켓 레이어라고도 하며, 전자상거래 등의 보안을 목적으로 넷스케이프사에서 개발한 규약이다. 이후에 TLS (Transport Layer Security)라는 이름으로 바뀌었다.

SSL은 전송 계층의 암호화 방식이기 때문에 응용계층의 프로토콜에 관계 없이 사용할 수 있다는 장점이 있다.

 

OpenSSL

SSL 자체는 보안 통신을 위한 규약이고, 이를 기술적으로 구현한 라이브러리 중 하나가 바로 OpenSSL이다. OpenSSL을 이용해서 통신 전문, 문서를 암호화 할 수 있다.

 

S_client

openssl 명령으로 운영되는 웹서버의 ssl 인증서 정보를 살펴보기 위해 사용되는 명령어이다. s_client를 사용하는 방법은 다음과 같다.

 

openssl s_client -connect [서버이름]:[포트번호]

 


openssl 명령어를 이용해 localhost:30001 서버에 bandit15의 패스워드를 전송하면 된다. 

먼저 아래의 명령어를 입력한다.

openssl s_client -connect localhost:30001

 

 

 

CONNECTED(00000003)
depth=0 CN = localhost
verify error:num=18:self signed certificate
verify return:1
depth=0 CN = localhost
verify return:1
---
Certificate chain
 0 s:/CN=localhost
   i:/CN=localhost
---
Server certificate
-----BEGIN CERTIFICATE-----
MIICBjCCAW+gAwIBAgIEDU18oTANBgkqhkiG9w0BAQUFADAUMRIwEAYDVQQDDAls
b2NhbGhvc3QwHhcNMjAwNTA3MTgxNTQzWhcNMjEwNTA3MTgxNTQzWjAUMRIwEAYD
VQQDDAlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAK3CPNFR
FEypcqUa8NslmIMWl9xq53Cwhs/fvYHAvauyfE3uDVyyX79Z34Tkot6YflAoufnS
+puh2Kgq7aDaF+xhE+FPcz1JE0C2bflGfEtx4l3qy79SRpLiZ7eio8NPasvduG5e
pkuHefwI4c7GS6Y7OTz/6IpxqXBzv3c+x93TAgMBAAGjZTBjMBQGA1UdEQQNMAuC
CWxvY2FsaG9zdDBLBglghkgBhvhCAQ0EPhY8QXV0b21hdGljYWxseSBnZW5lcmF0
ZWQgYnkgTmNhdC4gU2VlIGh0dHBzOi8vbm1hcC5vcmcvbmNhdC8uMA0GCSqGSIb3
DQEBBQUAA4GBAC9uy1rF2U/OSBXbQJYuPuzT5mYwcjEEV0XwyiX1MFZbKUlyFZUw
rq+P1HfFp+BSODtk6tHM9bTz+p2OJRXuELG0ly8+Nf/hO/mYS1i5Ekzv4PL9hO8q
PfmDXTHs23Tc7ctLqPRj4/4qxw6RF4SM+uxkAuHgT/NDW1LphxkJlKGn
-----END CERTIFICATE-----
subject=/CN=localhost
issuer=/CN=localhost
---
No client certificate CA names sent
Peer signing digest: SHA512
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 1019 bytes and written 269 bytes
Verification error: self signed certificate
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 1024 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384
    Session-ID: DAD9D78D0146D759DCA9A517C32F5C64AD0094560DC5474A810C917365A23E76
    Session-ID-ctx: 
    Master-Key: 48A28FA4F859DF09F481D534ECCCF98C6FABAB95B0274E43D63A12FC64697E6D62908AF77E8BA5D8E235D1C958D86976
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 7200 (seconds)
    TLS session ticket:
    0000 - aa 02 e6 3a 2e 0b c8 5d-6f 54 4a 1b 5a e0 2c 0e   ...:...]oTJ.Z.,.
    0010 - c6 0b f8 c1 ac a6 3e 32-df 8c 79 d5 a5 ff ec 87   ......>2..y.....
    0020 - ed 81 b4 ff a8 c2 e3 2e-d8 01 f8 20 aa 3d 91 fa   ........... .=..
    0030 - 94 0a 3c a3 3b 46 f6 57-79 00 80 37 2f 49 16 1d   ..<.;F.Wy..7/I..
    0040 - 00 79 80 95 99 d0 ab 79-48 d2 92 a6 ff f4 e2 97   .y.....yH.......
    0050 - e0 b6 aa 78 7d 3f 5e 2f-a5 c5 18 b6 79 f4 86 ab   ...x}?^/....y...
    0060 - e9 30 c2 ec 46 a1 69 e5-d4 68 d3 87 8e e0 4b 52   .0..F.i..h....KR
    0070 - e1 fe 88 a6 84 b7 8a b2-c1 70 ac 58 a6 85 dd ad   .........p.X....
    0080 - b6 73 3c 3e 1c 18 8d f9-48 7f ab 72 e0 e5 4d 40   .s<>....H..r..M@
    0090 - 85 b8 56 c4 e3 75 9f c5-b6 ec 40 cf 7d f4 b7 cc   ..V..u....@.}...

    Start Time: 1597913971
    Timeout   : 7200 (sec)
    Verify return code: 18 (self signed certificate)
    Extended master secret: yes
---

 

해당 서버의 ssl 인증서 정보가 쭉 출력되고, 마지막에 입력 대기 상태가 된다. 이 곳을 통해 현재 레벨의 패스워드를 보내면, 다음 레벨의 패스워드를 받을 수 있다.

 

 

 

 

Bandit 16

The credentials for the next level can be retrieved by submitting the password of the current level to a port on localhost in the range 31000 to 32000. 
First find out which of these ports have a server listening on them. 
Then find out which of those speak SSL and which don’t. 
There is only 1 server that will give the next credentials, the others will simply send back to you whatever you send to it.

 

다음 레벨에 로그인할 자격은 현재 레벨의 패스워드를 localhost 서버의 31000 ~ 32000 포트 중 하나에 보내면 얻을 수 있다. 

먼저 포트들이 서버에 존재하는지 확인해야 하고, 이 들중 SSL 통신이 가능한 것을 찾아야 한다.

검색 된 포트 중 한 개만 다음 레벨에 대한 자격이 주어지고, 나머지는 입력한 것이 그대로 출력될 것이다.

 

먼저 31000 ~ 32000 사이에 존재하는 포트들을 검색해야 한다.

포트 번호를 검색하기 위해 nmap 명령어를 사용하면 된다. nmap의 사용법은 다음과 같다.

nmap -p [포트번호] [서버이름]

만약, 범위 내에 존재하는 포트를 찾고 싶다면 포트 번호에 31000-32000 처럼 하이픈을 입력해서 범위를 지정해 줄 수 있다.

 

 

총 5개의 포트가 검색 되었다. 이들을 하나하나 openssl s_client 명령어를 이용해서 접속 요청을 하면, 입력이 그대로 나오지만 31790 포트는 다음과 같은 결과를 얻을 수 있다.

 

cluFn7wTiGryunymYOu4RcffSxQluehd
Correct!
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAvmOkuifmMg6HL2YPIOjon6iWfbp7c3jx34YkYWqUH57SUdyJ
imZzeyGC0gtZPGujUSxiJSWI/oTqexh+cAMTSMlOJf7+BrJObArnxd9Y7YT2bRPQ
Ja6Lzb558YW3FZl87ORiO+rW4LCDCNd2lUvLE/GL2GWyuKN0K5iCd5TbtJzEkQTu
DSt2mcNn4rhAL+JFr56o4T6z8WWAW18BR6yGrMq7Q/kALHYW3OekePQAzL0VUYbW
JGTi65CxbCnzc/w4+mqQyvmzpWtMAzJTzAzQxNbkR2MBGySxDLrjg0LWN6sK7wNX
x0YVztz/zbIkPjfkU1jHS+9EbVNj+D1XFOJuaQIDAQABAoIBABagpxpM1aoLWfvD
KHcj10nqcoBc4oE11aFYQwik7xfW+24pRNuDE6SFthOar69jp5RlLwD1NhPx3iBl
J9nOM8OJ0VToum43UOS8YxF8WwhXriYGnc1sskbwpXOUDc9uX4+UESzH22P29ovd
d8WErY0gPxun8pbJLmxkAtWNhpMvfe0050vk9TL5wqbu9AlbssgTcCXkMQnPw9nC
YNN6DDP2lbcBrvgT9YCNL6C+ZKufD52yOQ9qOkwFTEQpjtF4uNtJom+asvlpmS8A
vLY9r60wYSvmZhNqBUrj7lyCtXMIu1kkd4w7F77k+DjHoAXyxcUp1DGL51sOmama
+TOWWgECgYEA8JtPxP0GRJ+IQkX262jM3dEIkza8ky5moIwUqYdsx0NxHgRRhORT
8c8hAuRBb2G82so8vUHk/fur85OEfc9TncnCY2crpoqsghifKLxrLgtT+qDpfZnx
SatLdt8GfQ85yA7hnWWJ2MxF3NaeSDm75Lsm+tBbAiyc9P2jGRNtMSkCgYEAypHd
HCctNi/FwjulhttFx/rHYKhLidZDFYeiE/v45bN4yFm8x7R/b0iE7KaszX+Exdvt
SghaTdcG0Knyw1bpJVyusavPzpaJMjdJ6tcFhVAbAjm7enCIvGCSx+X3l5SiWg0A
R57hJglezIiVjv3aGwHwvlZvtszK6zV6oXFAu0ECgYAbjo46T4hyP5tJi93V5HDi
Ttiek7xRVxUl+iU7rWkGAXFpMLFteQEsRr7PJ/lemmEY5eTDAFMLy9FL2m9oQWCg
R8VdwSk8r9FGLS+9aKcV5PI/WEKlwgXinB3OhYimtiG2Cg5JCqIZFHxD6MjEGOiu
L8ktHMPvodBwNsSBULpG0QKBgBAplTfC1HOnWiMGOU3KPwYWt0O6CdTkmJOmL8Ni
blh9elyZ9FsGxsgtRBXRsqXuz7wtsQAgLHxbdLq/ZJQ7YfzOKU4ZxEnabvXnvWkU
YOdjHdSOoKvDQNWu6ucyLRAWFuISeXw9a/9p7ftpxm0TSgyvmfLF2MIAEwyzRqaM
77pBAoGAMmjmIJdjp+Ez8duyn3ieo36yrttF5NSsJLAbxFpdlc1gvtGCWW+9Cq0b
dxviW8+TFVEBl1O4f7HVm6EpTscdDxU+bCXWkfjuRb7Dy9GOtt9JPsX8MBTakzh3
vBgsyi/sN3RqRBcGU40fOoZyfAMT8s1m/uYv52O6IgeuZ/ujbjY=
-----END RSA PRIVATE KEY-----

 

Bandit13에서 ssh.private을 이용해 로그인 한 것과 같은 방식으로 진행하면 된다.

먼저 ssh.private 파일을 만들고 위의 내용을 저장한다. 홈 디렉토리에서는 권한이 없기 때문에 /tmp/test 디렉토리로 이동한 후 진행한다.

해당 키를 이용해 ssh 접속을 하면 된다. 이 때, sshkey는 600의 권한을 가지고 있어야 하기 때문에 다음의 명령어를 이용해 sshkey.private의 권한을 바꾸어주어야 한다.

$ chmod 600 sshkey.private
$ ssh -i ./sshkey.private bandit17@localhost

로그인에 성공하였다. /etc/bandit_pass에 존재하는 bandit17의 내용을 출력해서 패스워드를 얻어내면 된다.

 

 

Bandit17

There are 2 files in the homedirectory: passwords.old and passwords.new. 
The password for the next level is in passwords.new and is the only line that has been changed between passwords.old and passwords.new

홈 디렉토리엔 passwords.old와 passwords.new 두 파일이 존재한다.

다음 레벨의 패스워드는 passwords.new에 저장되어 있으며 passwords.old와 passwords.new의 유일한 다른 행이 패스워드이다.

 

두 파일을 비교하여 다른 부분을 출력하면 된다. 두 파일을 비교할 땐 diff 명령어를 이용하면 된다.

 

diff [파일1] [파일2]

두 파일의 다른 부분을 출력해준다. diff를 이용해 passwords.old와 passwords.new의 다른 부분을 찾고, 그 중 passwords.new의 내용이 패스워드이다.

 

위의 kfBf.... 가 bandit18의 암호이다.

 

 

Bandit18

The password for the next level is stored in a file readme in the homedirectory. 
Unfortunately, someone has modified .bashrc to log you out when you log in with SSH.

패스워드는 홈디렉토리에 readme 파일 안에 존재하지만, 누군가가 .bashrc 파일을 수정해서 SSH로 로그인하면 로그아웃 되도록 설정했다.

 

로그인하자마자 로그아웃되기 때문에 cat readme를 실행할 수가 없다. 이럴 땐 ssh 명령어의 뒷 부분에 원하는 동작을 작성해서 원격으로 실행할 수 있다. 

$ ssh bandit18@bandit.labs.overthewire.org -p 2220 cat readme

위의 명령어를 실행하면 bandit18로 접속만 하는것이 아니라, bandit18로 로그인 한 다음 cat readme를 실행했을 때의 결과만 출력하게 된다.

 

cat readme의 결과가 출력되었다.

 

Bandit19

To gain access to the next level, you should use the setuid binary in the homedirectory. 
Execute it without arguments to find out how to use it. 
The password for this level can be found in the usual place (/etc/bandit_pass), after you have used the setuid binary.

다음 레벨에 접근하려면 홈 디렉토리에 있는 setuid 바이너리를 이용해야 한다.

인자 없이 실행한 후에 사용법을 익히도록 한다.

다음 레벨의 패스워드는 /etc/bandit_pass에 저장되어 있으니, setuid를 이용해서 내용을 출력해야 한다.

 

ls -al을 이용해 파일 목록을 확인한다.

 

bandit20-do라는 파일이 보인다. 해당 파일을 실행하는 동안 bandit20의 권한을 획득하며, 이를 이용해 /etc/bandit_pass 디렉토리에 있는 bandit20을 출력해야 한다.

어떤 파일인지 실행시켜보았다.

 

 

다른 유저인것처럼 커맨드를 실행하라고 한다.

혹시 실행 인자로 넘긴 명령어를 bandit20의 권한으로 실행시키는 건가 싶어서 ./bandit20-do cat /etc/bandit_pass/bandit20 을 실행시켜보았다.

 

 

bandit20-do 는 실행 인자로서 명령어를 받고, 해당 명령어를 bandit20의 권한으로 실행시키는 프로그램인 듯 하다.

 

Bandit20

There is a setuid binary in the homedirectory that does the following: 
it makes a connection to localhost on the port you specify as a commandline argument. 
It then reads a line of text from the connection and compares it to the password in the previous level (bandit20). If the password is correct, it will transmit the password for the next level (bandit21).

홈 디렉토리에 setuid가 설정된 파일이 존재한다. 해당 파일은 포트 번호를 실행 인자로 받는데, 해당 포트 번호에 연결한 후에 한 줄을 읽어들이고, 정상적인 패스워드라면 그 다음 레벨의 암호를 출력해준다.

 

먼저 임의의 포트를 설정하고, 해당 포트에 현재 레벨의 패스워드를 보내야 한다. nc 명령어를 이용한다. 임의의 포트는 7777로 지정하도록 한다. nc를 이용해 포트를 새롭게 열어줄 땐 -l 옵션을 사용하며, 이를 백 그라운드에서 실행하고자 할 땐 마지막에 &를 붙여준다.

 

$ echo GbKksEFF4yrVs6il55v6gwY5aVje5f0j | nc -l -p 7777 localhost &

 

 

이제 홈 디렉토리의 suconnect 실행 파일을 이용해 7777포트에 연결하도록 한다.

 

 

다음 레벨의 패스워드가 출력되었다. 작업을 마친 후엔 kill [pid] 명령어를 이용해 백그라운드에서 실행중인 nc를 종료해주도록 한다.

 

Bandit21

A program is running automatically at regular intervals from cron, the time-based job scheduler. 
Look in /etc/cron.d/ for the configuration and see what command is being executed.

프로그램이 자동으로 cron에 의해 정기적으로 실행된다고 한다. cron은 time-based 스케줄러이고, /etc/cron.d 를 보고 설정과 어떠한 명령어가 실행되는지 확인해야 한다.

 


Cron

Unix 운영체제에서 특정한 시간에 특정한 작업을 실행시키기 위한 데몬이다. 예를 들어 특정 서버에 가서 특정 데이터를 받아오는 등의 기능을 정해진 시간에 수행시킬 수 있다. 서버는 24시간 항상 돌아가는데, 이 점을 이용한 방법이다.

이러한 작업을 설정하는 파일을 Crontab 이라고 한다. 리눅스에서는 해당 파일이 /etc/cron.d 디렉토리에 저장되고, 해당 파일을 조작할 땐 crontab 명령어를 이용하면 된다.


 

 

 

 

/etc/cron.d 디렉토리로 이동 후에 파일들을 확인해주었다.

이중 bandit22의 패스워드를 알아야하기 때문에 cronjob_bandit22의 내용을 출력해보았다.

 

 

cronjob_bandit22.sh 라는 명령어를 실행시키도록 하는 cron이다. 해당 명령어의 내용을 출력해보았다.

 

 

 

쉘을 실행시킨 후 /tmp/t7O6lds9S0RqQh9aMcz6ShpAoZKF7fgv 파일의 권한을 변경한 다음에 bandit22의 패스워드를 해당 파일에 복사하는 명령어이다. 해당 파일을 출력해준다.

 

bandit22의 패스워드가 출력되었다. bandit22로 로그인하면 된다.

 

 

Bandit22

A program is running automatically at regular intervals from cron, the time-based job scheduler. 
Look in /etc/cron.d/ for the configuration and see what command is being executed.

이전 단계와 목표가 동일하다. 

/etc/cron.d 디렉토리로 이동한다.

 

cronjob_bandit23의 내용을 출력해준다.

 

cronjob_bandit23.sh 명령어를 실행하는 cron이다. 해당 명령어의 내용을 출력해준다.

 

myname 변수에 whoami의 결과를 저장한다. 그런 다음의 myname 유저의 패스워드를 복사해서 /tmp/I am user [myname] 파일에 저장한다. mytarget에 저장되는 값은, I am user [username]을 md5 암호화를 통해 나온 암호문을 cut 명령어를 이용해 각 필드를 띄어쓰기로 구분하며 그 중 첫 번째 필드의 값을 mytarget에 저장한다.

 

echo I am user $myname | md5sum | cut -d ' ' -f 1 에서 myname에 bandit23을 넣어서 그대로 출력해보았다.

 

위와 같은 결과가 나왔다. 그러니 bandit23의 패스워드는 /tmp/8ca319486bfbbc3663ea0fbe81326349에 저장되어 있다는 의미이다. 해당 파일을 출력해준다.

 

bandit23의 비밀번호가 출력되었다.

 

 

Bandit23

A program is running automatically at regular intervals from cron, the time-based job scheduler. 
Look in /etc/cron.d/ for the configuration and see what command is being executed.

 

이번에도 역시 cron에 관련된 문제이다. /etc/cron.d에 존재하는 cronjob_bandit24 파일을 이용하면 된다.

 

NOTE: This level requires you to create your own first shell-script. 
This is a very big step and you should be proud of yourself when you beat this level!

NOTE 2: Keep in mind that your shell script is removed once executed, so you may want to keep a copy around…

 

NOTE 1: 해당 레벨에선 처음으로 쉘 스크립트를 만들어야 하는 것을 요구한다. 이것은 아주 큰 발전이 될 것이다!

NOTE 2: 쉘 스크립트는 한번 실행하면 삭제되기 때문에 사본을 항상 만들어둬야 한다.

 

 

우선 해당 파일의 내용을 출력해준다.

 

cronjob_bandit24.sh 명령어의 내용을 출력한다.

 

해당 쉘 스크립트를 해석하면 다음과 같다. 참고로 cronjob_bandit24.sh 쉘 스크립트는 bandit24 소유의 파일이다.

 

myname = $(whoami)  => myname에 "bandit24" 저장

 

cd /var/spool/$myname => /var/spool/bandit24로 이동.

echo "Executing and deleting all scripts in /var/spool/$myname:" => 해당 문자열 출력

for i in * .*; => 모든 파일에 대해 반복함.

do

    if [ "$i" !="." -a "$i" != ".." ];  =>  해당 파일이 . (현재 디렉토리)이 아니고 ..(상위 디렉토리)이 아니라면,

    then

            echo "Handling $i"  => Handling [파일이름] 출력

            owner="$(stat --format "%U" ./Si)" => 파일의 소유자 이름을 owner에 저장.

            if [ "%{owner}" = "bandit23" ]; then  => 파일의 소유자가 "bandit23" 이라면,

                timeout -s 9 60 ./%i  =>  60초 후에 해당 파일을 종료한다.

            fi

            rm -f ./$i => 해당 파일 강제 삭제.

    fi

done

 

 

요약하자면, /var/spool/bandit24에 존재하는 모든 파일을 실행하고 삭제하는 쉘 스크립트이다. 처음에 파일의 복사본을 만들라고 했던 이유가 이것 때문이였다.

쉘 스크립트를 작성해야 하기 때문에 쉘 스크립트 언어의 기본 문법만 익혀보도록 한다.

 

 


 

먼저, 쉘 스크립트를 작성하는 법은 다음과 같다.

 

  1. vi 파일이름 을 이용해서 편집모드로 들어간다.
  2. 첫 번째 줄에 #! /bin/bash 를 작성하고, 이후에 코드를 작성한다.
  3. 코드 작성이 끝나면 exit 0을 입력하고 esc를 눌러 편집모드를 비활성화 시킨 후에 :wq를 입력해서 저장 후 종료한다.

쉘 스크립트의 기본 문법은 다음과 같다.

 

1. 출력

echo와 printf가 있다. echo는 자동으로 개행 문자를 뒤에 삽입하며, printf는 개행문자를 삽입하지 않는다.

 

#! /bin/bash
echo "Echo"
printf "printf"
printf "%s %s" print test

 

 

 

2. 조건문

if로 시작하며 조건문의 마지막에 fi를 써주어야 한다. 형태는 다음과 같다.

 

if 조건
then
	실행할 내용
elif 조건
	실행할 내용
else
	실행할 내용
fi

 

 

3. 반복문

for을 사용하는 형태는 다음과 같다.

for 변수 in [값들]
do
	실행 내용
done

 

파이썬과 형태가 비슷하다.

 

 

while을 사용하면 다음과 같다.

 

while 조건문
do
	실행 내용
done

 

쉘 스크립트 파일은 실행시키기 위해 항상 chmod +x 명령어로 실행 권한을 부여해주어야 한다. 

$ chmod +x ./test.sh

 

 

 


bandit24 권한의 /usr/bin/cronjob_bandit24.sh 쉘 스크립트로 /etc/bandit_pass/bandit24 의 내용을 /tmp/shell/pass.txt 파일에 복사하면 된다. 쉘 스크립트는 생각보다 간단하다.

 

#! /bin/bash

cat /etc/bandit_pass/bandit24 > /tmp/shell/test.txt

exit 0

 

해당 파일을 /var/spool/bandit24에 복사해놓고 /usr/bin/cronjob_bandit24.sh을 실행한다.

 

 

test.txt 파일의 권한이 없다고 한다. test.txt 파일은 bandit23만 읽고 쓸 수가 있기 때문인데, 해당 파일의 권한을 777로 바꿔준 후에 다시 하면 된다.

 

bandit24의 패스워드가 test.txt에 저장되었다.

 

 

Bandit24

 

A daemon is listening on port 30002 and will give you the password for bandit25 if given the password for bandit24 and a secret numeric 4-digit pincode. 
There is no way to retrieve the pincode except by going through all of the 10000 combinations, called brute-forcing.

 

30002 포트에서 데몬이 실행중이고, 30002 포트에 현재 비밀번호와 4자리 정수를 함께 보내면 bandit25의 패스워드를 줄 것이다. 

핀코드를 검색하는 방법은 없고, 브루트 포스를 이용해 10000가지의 경우의 수를 직접 해봐야 한다.

 

브루트 포스에 대해 알아봐야 할 듯 하다.

 


브루트 포스 (Brute Force)

브루트 포스란 문제를 해결하기 위해 가능한 모든 경우를 직접 실행시키는 방법을 말한다. 예를 들어, 1부터 100까지의 합을 구하는 데에 있어서, 등차수열의 합 공식을 이용해 구할 수도 있지만, 단순히 1부터 100까지 전부 다 더해서 구하는 방법도 존재한다. 이러한 풀이를 브루트 포스라고 한다.

 


 

nc 명령어를 이용해 30002 포트에 연결해보았다.

 

bandit24의 패스워드와 4자리의 핀 코드를 공백으로 구분해서 입력하라고 한다. 핀 코드가 틀리면 다시 입력하라는 창이 뜬다.

 

직접 10000번 시도할 순 없기에 쉘 스크립트를 작성해서 0~9999까지 입력하는 코드를 작성했다.

 

#! /bin/bash                                                                
  2  
  3 password="UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ"
  4  
  5 for i in {0..9999}
  6 do
  8     echo "$password $i" | nc localhost 30002 >> ./result.txt
  9 done
 10  
 11 exit 0

처음엔 이렇게 작성하고 실행시켜보았지만, 1회 실행할 때마다 시간이 너무 오래걸려서 다른 방법을 생각해냈다.

 

[password] [pin Code]의 리스트를 pass.txt에 저장해놓은 다음에, 해당 파일의 출력을 nc 명령어의 입력으로 넣어주었다.

 

 

  1 #! /bin/bash                           
  2                                        
  3 password="UoMYTrfrBFHyQXmg6gzctqAwOmw1IohZ"
  4                                        
  5 for i in {0..9999}                     
  6 do                                     
  7     echo "try : $i"                    
  8     echo "$password $i" >> ./result.txt                                     
  9 done                                   
 10                                        
 11 exit 0

 

$ ./shell.sh

 

./shell.sh 실행 화면
cat result.txt

해당 텍스트 파일을 nc의 입력 인자로 넘긴다.

 

$ cat result.txt | nc localhost 30002

 

올바른 핀코드를 넘기는 순간 패스워드를 넘겨주며 응답하고 프로그램이 종료되기 때문에 더 이상 입력이 실행되지 않는다.

 

 

 

Bandit25 

Logging in to bandit26 from bandit25 should be fairly easy… 
The shell for user bandit26 is not /bin/bash, but something else. 
Find out what it is, how it works and how to break out of it.

 

bandit26의 쉘은 /bin/bash가 아닌 다른 것이다. 무엇인지 찾아보고, 어떻게 작동하는지 알아보도록 한다.

 

 

ls를 입력하면 bandit26.sshkey 파일이 보인다. 해당 키를 이용해 bandit26에 로그인한다.

 

$ ssh -i ./bandit26.sshkey bandit26@localhost

 

 

하지만 로그인하자마자 연결이 끊기게 된다.   레벨 목표에서 bandit26은 /bin/bash를 사용하지 않는다 하였기 때문에, 계정에 로그인하면 어떤 프로그램이 실행되는지 확인해준다. 로그인할 때 실행되는 프로그램의 정보는 /etc/passwd 파일에 있다. grep bandit26을 이용해 bandit26계정에 대해서만 출력해준다.

 

$ cat /etc/passwd | grep bandit26

 

bandit26에 로그인하면 /usr/bin/showtext 파일이 실행된다. 해당 파일이 무엇인지 확인해주도록 한다.

 

/bin/bash가 아닌 /bin/sh를 사용하고 있다. 또, 홈 디렉토리의 text.txt 파일을 more 명령어로 출력하고 프로그램을 종료한다.

more 명령어는 한 화면에 출력할 수 있는 만큼 출력해주고, 엔터 혹은 스페이스로 다음 줄을 읽어들이는 명령어인데, 왼쪽 하단에 얼만큼 읽었는지 퍼센트(%)로 나와있다. MacOS의 터미널의 기본 크기로 한번에 출력할 수 있을 정도이기 때문에 한번에 출력되고 종료되는 듯 하다. 터미널의 세로 길이를 최소로 줄인다음 bandit26에 다시 로그인해본다.

 

 

66%만큼 출력되었고, More 명령어가 현재 실행중에 있다. more 명령어가 실행중일 때는 "v"를 입력하면 vi 편집기를 실행시킬 수 있고, vi 편집기에서 " : "을 입력해 커맨드라인을 실행시킬 수 있다. 커맨드 라인에서 e 옵션을 사용하면 다른 파일을 열 수 있는데, 해당 vi text.txt가 bandit26의 권한으로 실행되었기 때문에 /etc/bandit_pass/bandit26 파일을 불러올 수 있다.

 

bandit26의 패스워드가 출력되었다.

또한, bandit26에 로그인하기 위해선 로그인 시에 /usr/bin/showtext가 실행되는게 아닌 shell을 실행하도록 설정을 바꿔주어야 한다.

vi의 커맨드라인에서는 : 뒤에 명령어를 작성하면 해당 명령어를 실행시킬 수 있다. 위에서 사용한 e (edit) 등이 대표적인 예이다.

커맨드라인에서 사용하는 명령어중 set 명령어가 있다. 이를 이용해 shell을 변경해줄 수 있다.

 

: set shell=[쉘 경로]

 

여태까지 사용한 쉘이 /bin/bash였기 때문에 /bin/bash로 바꾸어준다.

 

이후 shell을 입력하면 입력하면, /bin/bash가 실행된다.

 

 

 

'Pwnable > OvertheWire' 카테고리의 다른 글

[ProjectH4C] OverTheWire Bandit 26 ~ 32 write-up  (0) 2020.08.31