"""
HTTP Verb Tampering Vulnerability Tester
"""
import requests
from requests.auth import HTTPBasicAuth
class VerbTamperingTester:
def __init__(self, base_url):
self.base_url = base_url
self.findings = []
self.session = requests.Session()
HTTP_METHODS = [
'GET', 'POST', 'PUT', 'DELETE', 'PATCH',
'HEAD', 'OPTIONS', 'TRACE', 'CONNECT',
'PROPFIND', 'PROPPATCH', 'MKCOL', 'COPY', 'MOVE',
'LOCK', 'UNLOCK', 'VERSION-CONTROL', 'REPORT',
'CHECKOUT', 'CHECKIN', 'UNCHECKOUT',
'JEFF', 'FAKE', 'TEST', 'DEBUG'
]
def test_methods(self, endpoint):
"""Test all HTTP methods on endpoint"""
print(f"\n[*] Testing methods on {endpoint}")
results = {}
url = f"{self.base_url}{endpoint}"
for method in self.HTTP_METHODS:
try:
response = self.session.request(method, url, timeout=10)
results[method] = {
'status': response.status_code,
'length': len(response.content)
}
print(f" {method}: {response.status_code} ({len(response.content)} bytes)")
except Exception as e:
results[method] = {'status': 'Error', 'error': str(e)}
return results
def test_auth_bypass(self, protected_endpoint, valid_creds=None):
"""Test if authentication can be bypassed via method change"""
print(f"\n[*] Testing authentication bypass...")
url = f"{self.base_url}{protected_endpoint}"
if valid_creds:
auth = HTTPBasicAuth(valid_creds[0], valid_creds[1])
auth_response = self.session.get(url, auth=auth)
print(f" Authenticated GET: {auth_response.status_code}")
unauth_get = self.session.get(url)
print(f" Unauthenticated GET: {unauth_get.status_code}")
bypass_methods = ['POST', 'PUT', 'HEAD', 'OPTIONS', 'TRACE', 'JEFF']
for method in bypass_methods:
try:
response = self.session.request(method, url)
if response.status_code == 200 and unauth_get.status_code in [401, 403]:
print(f" [VULN] {method} bypasses authentication! ({response.status_code})")
self.findings.append({
'type': 'Authentication Bypass',
'method': method,
'endpoint': protected_endpoint,
'severity': 'Critical'
})
except:
pass
def test_authorization_bypass(self, admin_endpoint, user_session):
"""Test if authorization can be bypassed via method change"""
print(f"\n[*] Testing authorization bypass...")
url = f"{self.base_url}{admin_endpoint}"
self.session.cookies.update(user_session)
methods = ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'JEFF']
for method in methods:
try:
response = self.session.request(method, url)
if response.status_code == 200:
if 'admin' in response.text.lower() or len(response.content) > 100:
print(f" [WARN] {method} returns content ({response.status_code})")
self.findings.append({
'type': 'Potential Authorization Bypass',
'method': method,
'endpoint': admin_endpoint,
'severity': 'High'
})
except:
pass
def test_trace_xst(self):
"""Test for Cross-Site Tracing (XST) via TRACE method"""
print(f"\n[*] Testing for XST (TRACE method)...")
url = self.base_url
headers = {'X-Custom-Header': 'XST-Test-Value'}
try:
response = self.session.request('TRACE', url, headers=headers)
if response.status_code == 200:
if 'XST-Test-Value' in response.text:
print(f" [VULN] TRACE method enabled - XST possible!")
self.findings.append({
'type': 'Cross-Site Tracing (XST)',
'method': 'TRACE',
'severity': 'Medium',
'detail': 'TRACE reflects headers including cookies'
})
else:
print(f" [INFO] TRACE enabled but not reflecting headers")
else:
print(f" [OK] TRACE method disabled ({response.status_code})")
except:
pass
def test_webdav_methods(self):
"""Test for WebDAV methods"""
print(f"\n[*] Testing WebDAV methods...")
webdav_methods = ['PROPFIND', 'PROPPATCH', 'MKCOL', 'COPY', 'MOVE', 'LOCK', 'UNLOCK']
for method in webdav_methods:
try:
response = self.session.request(method, self.base_url)
if response.status_code not in [405, 501]:
print(f" [WARN] {method} enabled ({response.status_code})")
self.findings.append({
'type': 'WebDAV Method Enabled',
'method': method,
'severity': 'Low',
'detail': 'WebDAV methods should be disabled if not needed'
})
except:
pass
def generate_report(self):
"""Generate findings report"""
print("\n" + "="*60)
print("HTTP VERB TAMPERING REPORT")
print("="*60)
if not self.findings:
print("\nNo significant vulnerabilities found.")
else:
for f in self.findings:
print(f"\n[{f['severity']}] {f['type']}")
print(f" Method: {f['method']}")
if 'endpoint' in f:
print(f" Endpoint: {f['endpoint']}")
if 'detail' in f:
print(f" Detail: {f['detail']}")
def run_tests(self, endpoints=None):
"""Run all verb tampering tests"""
if endpoints is None:
endpoints = ['/admin', '/api/admin', '/dashboard', '/settings']
for endpoint in endpoints:
self.test_methods(endpoint)
self.test_auth_bypass('/admin')
self.test_trace_xst()
self.test_webdav_methods()
self.generate_report()
tester = VerbTamperingTester("https://target.com")
tester.run_tests()
from flask import Flask, request, abort
app = Flask(__name__)
@app.route('/api/resource', methods=['GET', 'POST'])
def resource():
if request.method == 'GET':
return get_resource()
elif request.method == 'POST':
return create_resource()
@app.before_request
def check_method():
allowed = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS']
if request.method not in allowed:
abort(405)
@app.after_request
def disable_trace(response):
if request.method == 'TRACE':
return '', 405
return response