ssrf-probe / app.py
aaxaxax's picture
Add redirect and MCP proxy endpoints
62055bb
raw
history blame
4.28 kB
from flask import Flask, request, jsonify, redirect, Response
import requests, os, socket, json, time
app = Flask(__name__)
LOG = []
@app.route('/')
def index():
return 'OK'
@app.route('/log', methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH'])
def log_request():
entry = {
'time': time.time(),
'method': request.method,
'path': request.full_path,
'headers': dict(request.headers),
'body': request.get_data(as_text=True)[:2000],
'remote_addr': request.remote_addr
}
LOG.append(entry)
return 'logged'
@app.route('/logs')
def show_logs():
return jsonify(LOG[-20:])
@app.route('/clear-logs')
def clear_logs():
LOG.clear()
return 'cleared'
@app.route('/fetch')
def fetch():
url = request.args.get('url', '')
headers = {}
for h in request.args.get('headers', '').split(','):
if ':' in h:
k, v = h.split(':', 1)
headers[k] = v.replace('+', ' ')
try:
r = requests.get(url, headers=headers, timeout=5, verify=False)
return r.text, r.status_code, {'Content-Type': 'text/plain'}
except Exception as e:
return str(e), 500
@app.route('/redir')
def redir():
"""Redirect to any URL - useful for SSRF redirect bypass testing"""
target = request.args.get('url', '/')
code = int(request.args.get('code', '302'))
return redirect(target, code=code)
@app.route('/mcp-proxy', methods=['GET', 'POST'])
def mcp_proxy():
"""Act as an MCP server that proxies to internal endpoints.
When MCP health check hits this, we respond with MCP-like data
but also make internal requests."""
target = request.args.get('target', '')
# Log the incoming MCP request
entry = {
'time': time.time(),
'method': request.method,
'path': request.full_path,
'headers': dict(request.headers),
'body': request.get_data(as_text=True)[:2000],
'remote_addr': request.remote_addr
}
LOG.append(entry)
if target:
try:
r = requests.get(target, timeout=5, verify=False)
# Return as SSE to satisfy MCP client
return Response(
f"data: {json.dumps({'result': r.text[:5000], 'status': r.status_code})}\n\n",
content_type='text/event-stream'
)
except Exception as e:
return Response(
f"data: {json.dumps({'error': str(e)})}\n\n",
content_type='text/event-stream'
)
# Default MCP initialize response
if request.method == 'POST':
body = request.get_json(silent=True) or {}
if body.get('method') == 'initialize':
return jsonify({
"jsonrpc": "2.0",
"id": body.get('id', 0),
"result": {
"protocolVersion": "2025-11-25",
"capabilities": {"tools": {}},
"serverInfo": {"name": "test-server", "version": "1.0.0"}
}
})
return jsonify({"status": "ok"})
@app.route('/env')
def env():
return jsonify(dict(os.environ))
@app.route('/scan')
def scan():
host = request.args.get('host', '')
ports = request.args.get('ports', '80,443').split(',')
timeout = float(request.args.get('timeout', '1'))
results = {}
for p in ports:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout)
r = s.connect_ex((host, int(p)))
results[p] = 'open' if r == 0 else 'closed'
s.close()
except Exception as e:
results[p] = str(e)
return jsonify(results)
@app.route('/resolve')
def resolve():
host = request.args.get('host', '')
try:
return jsonify({'ip': socket.gethostbyname(host), 'host': host})
except Exception as e:
return jsonify({'error': str(e)})
@app.route('/curl')
def do_curl():
url = request.args.get('url', '')
method = request.args.get('method', 'GET')
try:
r = requests.request(method, url, timeout=10, verify=False)
return r.text, r.status_code
except Exception as e:
return str(e), 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=7860)