// Ruby für Pentester · Teil 1
Dein erstes Recon-Werkzeug
Installiere Ruby 4, lerne irb kennen und schreib dein allererstes Skript — einen HTTP-Client, der ein Ziel fingerabdruckt. Wir richten ihn auf die pensionierte HackTheBox-Maschine Bizness und bestätigen, was läuft.
Willkommen. In dieser Reihe lernst du Ruby so, wie du es als Pentester wirklich einsetzt: indem du dein eigenes Werkzeug schreibst und es auf ein echtes Ziel richtest. Dieses Ziel ist Bizness, eine pensionierte HackTheBox-Maschine. Am Ende des letzten Teils hast du ein einzelnes Ruby-Programm — und danach ein echtes Metasploit-Modul —, das die gesamte Kette von einem leeren Terminal bis zur root-Shell trägt.
Kein Ruby-Vorwissen nötig. Dieser erste Teil ist das Fundament: bring die Sprache zum Laufen, lern, wie ein Ruby-Programm aufgebaut ist, und schreib ein Skript, das HTTP spricht und uns sagt, was auf der Box läuft.
Alles hier richtet sich gegen eine pensionierte Lab-Maschine, zu der du eine Verbindung besitzt. Bau Werkzeuge, richte sie auf Dinge, die du berühren darfst.
Ruby 4 besorgen
Die Seite, die du gerade liest, läuft auf Ruby 4, also ziehen wir gleich. Prüf, was du hast:
$ ruby -v
ruby 4.0.6 (2025-12-25 revision ...) [x86_64-linux]
Wenn das eine 4.x-Version ausgibt, bist du startklar. Falls nicht, installiere
es mit dem Versionsmanager deiner Plattform (rbenv install 4.0.6,
mise use ruby@4.0.6 oder das Paket deiner Distribution). Das exakte
Patch-Level spielt für diese Reihe keine Rolle; alles auf der 4.0-Linie passt.
irb: dein Notizblock
Ruby bringt eine interaktive Shell namens irb mit. Sie führt Code aus, während du ihn tippst, und ist damit der schnellste Weg, etwas auszuprobieren. Starte sie, rechne ein bisschen und bau dann einen String:
$ irb
irb(main):001> 40 + 2
=> 42
irb(main):002> "hello".upcase
=> "HELLO"
Zwei Dinge fallen auf. Erstens: alles ist ein Ausdruck — 40 + 2 und
"hello".upcase geben beide einen Wert zurück (irb druckt ihn nach dem =>).
Zweitens: "hello" ist ein Objekt, und .upcase ist eine Methode, die
du darauf aufrufst. In Ruby weiß selbst ein einfacher String, wie man Dinge tut.
Darauf wirst du dich ständig stützen.
Tipp exit, um irb zu verlassen.
Dein erstes Skript
irb ist für Experimente; echte Werkzeuge leben in Dateien. Öffne eine Datei
namens recon.rb und beginn mit einer Zeile:
puts 'hello from Ruby'
puts („put string”) gibt sein Argument samt Zeilenumbruch aus. Führ die
Datei aus:
$ ruby recon.rb
hello from Ruby
Das ist die ganze Schleife, die du für immer nutzt: in eine .rb-Datei
schreiben, mit ruby ausführen. Wenn du sie oft direkt startest, füg als erste
Zeile eine Shebang hinzu, damit die Shell weiß, wie sie auszuführen ist:
#!/usr/bin/env ruby
puts 'hello from Ruby'
Dann chmod +x recon.rb, und du kannst ./recon.rb ausführen.
Variablen und Strings
Eine Variable ist ein Name für einen Wert. Keine Typdeklarationen — du weist einfach zu:
target = 'bizness.htb'
puts "scanning #{target}"
Das #{...} innerhalb eines doppelt gequoteten Strings ist Interpolation:
Ruby wertet den Ausdruck aus und lässt das Ergebnis in den String fallen. Das
ist sauberer als Strings mit + zusammenzukleben, und du wirst es in jedem
Payload nutzen, den du später baust.
HTTP sprechen
Aufklärung beginnt mit einer einfachen Frage: Was antwortet, wenn ich anklopfe?
Rubys Standardbibliothek hat einen HTTP-Client eingebaut — keine Gems zu
installieren. Zieh ihn mit require herein:
require 'net/http'
require 'uri'
target = URI('https://bizness.htb/')
http = Net::HTTP.new(target.host, target.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE # lab box uses a self-signed cert
response = http.get('/')
puts "Status: #{response.code} #{response.message}"
puts "Server: #{response['server']}"
Zeile für Zeile:
require 'net/http'lädt den HTTP-Client;require 'uri'lädt den URL-Parser.URI('https://bizness.htb/')macht aus dem String ein URL-Objekt, sodass wir es nach.host(bizness.htb) und.port(443) fragen können, statt Strings von Hand zu zerlegen.Net::HTTP.new(host, port)erzeugt einen Client.use_ssl = true, weil es HTTPS ist. Lab-Boxen liefern selbstsignierte Zertifikate aus, also sagtverify_mode = VERIFY_NONERuby, die Verbindung nicht abzulehnen — das reale Gegenstück zucurl -k.http.get('/')schickt die Anfrage und reicht ein Response-Objekt zurück.response.code,.messageundresponse['server']lesen Status und einen Header von diesem Objekt ab.
Führ es aus:
$ ruby recon.rb
Status: 200 OK
Server: nginx/1.18.0 (Ubuntu)
Ein nginx-Reverse-Proxy — aber das ist nur die Vordertür. Das Interessante ist, was dahinter steckt.
Wenn das Klopfen unbeantwortet bleibt
Ein echtes Ziel ist nicht immer erreichbar. Ist der Host down, der Port
gefiltert oder das VPN abgebrochen, gibt http.get keine Response zurück — es
wirft eine Exception, und dein Skript stirbt mit einem Backtrace. Ein
Recon-Werkzeug sollte das erwarten und stattdessen etwas Nützliches sagen. Pack
den riskanten Aufruf in begin/rescue:
begin
response = http.get('/')
rescue StandardError => e
abort "[-] #{target.host} is not answering: #{e.message}"
end
begin ... rescue ... endführt den Code aus und fängt jeden darin geworfenen Fehler.StandardErrorist der Elternteil der alltäglichen Fehler — eine abgelehnte Verbindung, ein Timeout, ein DNS-Fehlschlag —, sodass einrescuesie abdeckt;=> ebindet das Exception-Objekt, damit wire.messagelesen können.abortgibt auf stderr aus und beendet mit Nicht-Null, so wie ein Kommandozeilen-Werkzeug scheitern sollte.
Exceptions sind Rubys Fehlerkanal. Du wirst sie rescue-n, wann immer du das
Netzwerk, das Dateisystem oder irgendetwas anfasst, das unter dir wegbrechen
kann — was in diesem Metier die meisten Dinge sind.
Die App fingerabdrucken
Der Response-Body ist das HTML, das der Server geschickt hat. Suchen wir nach einem Hinweis. Ergänze:
body = response.body
if body.include?('Apache OFBiz')
puts '[+] Apache OFBiz detected'
else
puts '[-] OFBiz not found in body'
end
response.body ist einfach ein String, und String#include? gibt true
oder false zurück — einen Boolean —, je nachdem, ob der Teilstring
vorhanden ist. Den füttern wir an ein if/else, um zu verzweigen. Lauf es
erneut:
$ ruby recon.rb
Status: 200 OK
Server: nginx/1.18.0 (Ubuntu)
[+] Apache OFBiz detected
Da ist es. Apache OFBiz — eine große Java-ERP-Suite — hinter nginx. Diese eine Tatsache entscheidet die ganze Engagement: OFBiz hat eine bekannte Authentifizierungs-Bypass-CVE aus 2023, und den Stack zu bestätigen ist das, was uns dorthin weist. Du hast gerade das Werkzeug geschrieben, das ihn fand.
Das fertige Skript
Zusammengesetzt, dein erstes Recon-Werkzeug:
#!/usr/bin/env ruby
require 'net/http'
require 'uri'
target = URI('https://bizness.htb/')
http = Net::HTTP.new(target.host, target.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
response = http.get('/')
puts "Status: #{response.code} #{response.message}"
puts "Server: #{response['server']}"
if response.body.include?('Apache OFBiz')
puts '[+] Apache OFBiz detected'
else
puts '[-] OFBiz not found in body'
end
Zwanzig Zeilen, keine Abhängigkeiten, und es tut etwas Echtes.
Erkenntnisse
- Ruby-Code lebt in
.rb-Dateien, die du mitrubyausführst, oder du experimentierst live inirb. Alles ist ein Objekt, und du rufst Methoden auf Objekten auf. putsgibt aus; Variablen sind nur Namen, die du zuweist; die"#{...}"-Interpolation baut Strings sauber zusammen.net/http+urigeben dir einen vollständigen HTTP-Client in der Standardbibliothek —Net::HTTP.new,use_ssl,VERIFY_NONEfür Lab-Certs,.get, dann.code/.bodyvom Response ablesen.- Aufklärung ist nur, eine Frage zu stellen und die Antwort zu lesen. Unsere fand Apache OFBiz, und das ist der Faden, an dem wir als Nächstes ziehen.
Übungen
Ein Werkzeug zu lesen ist nicht, eines zu schreiben. Probier diese, bevor du weitergehst:
- Gib den
Content-Type-Header der Response und die Länge des Bodys in einer Zeile per Interpolation aus — z. B.text/html; charset=utf-8, 24187 bytes. - Füge ein
elsifhinzu: Erwähnt der Body kein OFBiz, enthält aber derServer-Headernginx, melde[?] nginx, unknown app. Fall nur in den[-]-Zweig, wenn keines passt. - Richte das Skript auf einen Port, auf dem nichts lauscht
(
URI('https://bizness.htb:9999/')), und bestätige, dass deinbegin/rescueeine saubere Zeile statt eines Backtraces ausgibt.
Weiter — Teil 2: Wir verwandeln diesen OFBiz-Fund in Zugang und schreiben eine Ruby-Funktion, die direkt durch die Authentifizierungsprüfung marschiert.