[Frage] lighttpd: Wie kann man bei aktiviertem chroot Bash-Befehle in cgi-Dateien nutzen?

PeterPawn

IPPF-Urgestein
Mitglied seit
10 Mai 2006
Beiträge
13,010
Punkte für Reaktionen
981
Punkte
113
Da stehen doch schon welche.
Eben ... ich habe Dir die Konsequenzen dieser Anführungszeichen versucht vor Augen zu führen. Ist das nach Deiner Ansicht alles ein einziger Parameter?

Kannst du kurz andeuten, woran ich da (noch) denken sollte?
Das kommt darauf an, was das genau soll und wer da alles Zugriff hat. Es ist generell keine gute Idee, Eingabedaten aus "unbekannter Quelle" (und hier noch in unbekanntem Umfang) einfach in einem anderen Kommando weiterzuverwenden. Da komme ich einfach noch mal auf das Beispiel mit dem "printf" an anderer Stelle zurück ... Du kannst ja mal probieren, wie das "curl" reagiert, wenn Du die Eingabedaten mit zwei Bindestrichen (--) beginnen läßt und/oder ungültige Optionen/Formate in den Daten angibst.

Oder als weiteres Beispiel mal probieren, was bei einer Option "--output /var/post_install" passiert ... ich wäre sehr verblüfft, wenn der Inhalt dieser Datei dann nicht mit dem Inhalt des Downloads von der URL überschrieben würde - und das ist exakt das Shell-Skript, was von Deiner FRITZ!Box beim nächsten "shutdown"- oder "reboot"-Kommando abgearbeitet wird. Wie geschrieben ... es kommt natürlich darauf an, wer oder was diese "Seite" benutzen darf - aber eine unsichere Seite ist (gerade auch mit "bash") extrem schnell erstellt und wenn die dann "in die falschen Hände gerät", verliert man leicht die "Herrschaft" über das entsprechende Gerät. Das mit "--output" und der "post_install" ist auch nur ein (eher simples) Beispiel - mir fallen da garantiert noch jede Menge anderer denkbarer "Angriffe" ein.

Wenn man so etwas macht, sollte man nicht die gesamten Optionen als Zeichenkette "rüberwachsen" lassen, sondern so viel wie möglich "fest" im Skript setzen und nur die unbedingt notwendigen Variablen aus dem Request nehmen. Wenn ich weiß, daß der Body eine Property namens "URL" enthält und darin die URL zu finden ist, kann ich das auch "quoten" und damit dafür sorgen, daß darin eingeschmuggelte "--output"-Optionen eben nicht als solche erkannt, sondern als Teil der URL angesehen werden, was dann i.d.R. zum Fehler beim Download und nicht zum Überschreiben einer Datei führt. Wie das geht mit dem "als Ganzes" für eine Variable, hast Du ja schon schön vorgeführt.
 

FischersFreetz

Neuer User
Mitglied seit
22 Feb 2019
Beiträge
64
Punkte für Reaktionen
2
Punkte
8
Ist das nach Deiner Ansicht alles ein einziger Parameter?
Das sieht mir nach einem "Gestückel" von '....' ' '_______' ' '----------------' aus, mal "ecaped", mal nicht, ...
Aber dennoch weiß ich nicht, wie ich es richtig machen könnte.
Mir ist nämlich auch unklar, wie dieses "Gestückel" zustande kommt.

Und Danke für deine Hinweise zu den Sicherheitsbedenken.
 

PeterPawn

IPPF-Urgestein
Mitglied seit
10 Mai 2006
Beiträge
13,010
Punkte für Reaktionen
981
Punkte
113
Aber dennoch weiß ich nicht, wie ich es richtig machen könnte.
Wie wäre es denn, wenn Du einfach mal die "double quotes" wegläßt?

Und solange man nicht erfährt, woher der Request kommt und was das am Ende soll, tappt man auch weiterhin im Dunklen, was das "Gestückel" angeht - das kannst nur Du irgendwie aufklären.

mal "ecaped", mal nicht, ...
Hier darfst Du die Debug-Ausgabe der Shell nicht mit der "resultierenden Zeile" aus dem Shell-Skript verwechseln - bei der Debug-Anzeige werden generell "einfache Anführungszeichen" (aka "quotes") verwendet zur "Abgrenzung" einzelner Parameter und wenn diese Zeichenketten ihrerseits dann "quotes" enthalten, müssen die natürlich "escaped" werden. Das erste und das letzte "quote" um den Parameter nach dem "curl" an dieser Stelle:
Code:
+ curl '--header [...]'
in der Debug-Anzeige, sind eigentlich diejenigen, die bei Dir als "double quotes" um $input herum stehen.
 
Zuletzt bearbeitet:

FischersFreetz

Neuer User
Mitglied seit
22 Feb 2019
Beiträge
64
Punkte für Reaktionen
2
Punkte
8
Wie wäre es denn, wenn Du einfach mal die "double quotes" wegläßt?
( * das habe ich doch schon... mal mit ", mal ohne, mal einfache '.... * )
Dann sieht es nicht besser aus. Und so sieht ein einziger Parameter auch nicht aus, oder? Sieh' selbst:
Rich (BBCode):
+ read -n 482 input
+ curl --header ''\''Host:' 'ipv4.download.thinkbroadband.com'\''' --user-agent ''\''Mozilla/5.0' '(Windows' NT '10.0;' 'Win64;' 'x64;' 'rv:76.0)' Gecko/20100101 'Firefox/76.0'\''' --header ''\''Accept:' 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'\''' --header ''\''Accept-Language:' 'de,en-US;q=0.7,en;q=0.3'\''' --header ''\''DNT:' '1'\''' --cookie ''\''__cfduid=d232daa84d0d2c871127f260f90b7fd391590482231'\''' --header ''\''Upgrade-Insecure-Requests:' '1'\''' ''\''http://ipv4.download.thinkbroadband.com/20MB.zip'\''' --output ''\''20MB.zip'\'''
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0curl: (6) Could not resolve host: ipv4.download.thinkbroadband.com'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0curl: (6) Could not resolve host: (Windows
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0curl: (6) Could not resolve host: NT
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0curl: (6) Could not resolve host: 10.0;
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0curl: (6) Could not resolve host: Win64;
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0curl: (6) Could not resolve host: x64;
curl: (3) Error
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0curl: (6) Could not resolve host: Gecko
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0curl: (6) Could not resolve host: Firefox
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0curl: (6) Could not resolve host: text
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0curl: (6) Could not resolve host: de,en-US;q=0.7,en;q=0.3'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0curl: (6) Could not resolve host: 1'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0curl: (6) Could not resolve host: 1'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0curl: (6) Could not resolve host: 'http
Die inputdaten bestimme ich schon selbst. Die stammen hier vom Firefox-Addon "cliget" (This addon will generate commands that emulate the request as though it was coming from your browser by sending the same cookies, user agent string and referrer).
 
Zuletzt bearbeitet:

PeterPawn

IPPF-Urgestein
Mitglied seit
10 Mai 2006
Beiträge
13,010
Punkte für Reaktionen
981
Punkte
113
Na ja, zumindest ist es jetzt ja nicht länger nur ein einziger (falscher) Parameter ... wenn Du schon mal "curl" in Aktion gesehen hast, versucht das Kommando ja jetzt wenigstens, Daten zu laden (man sieht's an den "Statistiken").

Nur werden jetzt die nicht korrekt gequoteten Parameter alle als (einzelne) URLs angesehen (daher die ständigen "Could not resolve host"-Messages) - vielleicht gibst Du einfach mal den Inhalt von "$input" ohne "curl"-Aufruf aus, dann kannst Du Dir ansehen, was da tatsächlich drin steht. Und am Ende landet das dann doch wieder bei "einzelnen Parametern", auch wenn wir ja immer noch im Dunklen gelassen werden, was das nun eigentlich alles soll. Denn irgendjemand muß das dann "korrekt quoten" und wenn es der Absender des Requests nicht macht, muß es eben das aufgerufene Skript leisten.
 

FischersFreetz

Neuer User
Mitglied seit
22 Feb 2019
Beiträge
64
Punkte für Reaktionen
2
Punkte
8
Code:
read -n $CONTENT_LENGTH input
$input
===ergibt===>>
+ read -n 484 daten
+ --header ''\''Host:' 'ipv4.download.thinkbroadband.com'\''' --user-agent ''\''Mozilla/5.0' '(Windows' NT '10.0;' 'Win64;' 'x64;' 'rv:76.0)' Gecko/20100101 'Firefox/76.0'\''' --header ''\''Accept:' 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'\''' --header ''\''Accept-Language:' 'de,en-US;q=0.7,en;q=0.3'\''' --header ''\''DNT:' '1'\''' --cookie ''\''__cfduid=d232daa84d0d2c871127f260f90b7fd391590482231'\''' --header ''\''Upgrade-Insecure-Requests:' '1'\''' ''\''http://ipv4.download.thinkbroadband.com/100MB.zip'\''' --output ''\''100MB.zip'\'''
/websites/cgi-bin/start-ddl.shcgi: line 7: --header: command not found
Die inputdaten bestimme ich schon selbst. Die stammen hier vom Firefox-Addon "cliget" (This addon will generate commands that emulate the request as though it was coming from your browser by sending the same cookies, user agent string and referrer).

Übrings: Wenn ich diese Input-Zeile in der Shell hinter ein curl setze, dann funktioniert der Download.
curl --header 'Host: ipv4.download.thinkbroadband.com' --user-agent 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0' --header 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' --header 'Accept-Language: de,en-US;q=0.7,en;q=0.3' --header 'DNT: 1' --cookie '__cfduid=d232daa84d0d2c871127f260f90b7fd391590482231' --header 'Upgrade-Insecure-Requests: 1' 'http://ipv4.download.thinkbroadband.com/100MB.zip' --output '100MB.zip'

Und hier noch ein paar wirre Gedanken meinerseits:
:rolleyes: Werden die input-Daten vielleicht bei der Übertragung "vermatscht"? :rolleyes: Müssen die wieder "hingematscht" werden? :rolleyes: urldecode?
 
Zuletzt bearbeitet:

PeterPawn

IPPF-Urgestein
Mitglied seit
10 Mai 2006
Beiträge
13,010
Punkte für Reaktionen
981
Punkte
113
Übrings: Wenn ich diese Input-Zeile in der Shell hinter ein curl setze, dann funktioniert der Download.
Ja und? Das ist ja auch zu erwarten, wenn die Parameter stimmen - wie man sehen kann, passen hier ja auch die "single quotes". Jede Option steht da "einzeln" und jeder Wert für eine Option ist ordentlich in "single quotes" eingeschlossen, obwohl das nur dann erfolderlich ist, wenn er Zeichen enthält, die von der Shell als Trennzeichen interpretiert werden (der Cookie wäre ein Beispiel für einen Wert, wo das nicht der Fall ist und wo die "single quotes" rundherum nicht erforderlich wären).

Warum Du hier mit der direkten Angabe der Variablen in einer Zeile (konkret in Zeile 2 im "CODE"-Block in #26) am Ende doch wieder "nur" die Debug-Ausgabe verwenden willst (und daß "--header" kein gültiges Kommando sein wird, darauf hätte ich wetten können) und nicht einfach mal ein "printf" oder meinetwegen auch ein "echo" benutzt, hat welchen Grund genau?

Ich schlage vor, daß Du Dich mal mit Shell-Variablen und Quoting etwas eingehender befaßt - aber nicht in Form von "try & error", sondern in Form von Dokumentationen, z.B. dieser hier: https://tldp.org/LDP/abs/html/ (gibt's auch irgendwo als PDF zum Download und damit als "Lektüre" für viele Gelegenheiten).
 

FischersFreetz

Neuer User
Mitglied seit
22 Feb 2019
Beiträge
64
Punkte für Reaktionen
2
Punkte
8
Bemerkungen zu den Sicherheitsaspekten...
...wenn Du die Eingabedaten mit zwei Bindestrichen (--) beginnen läßt...
Genau das curl --header ... soll ja realisiert/probiert werden.
... was bei einer Option "--output /var/post_install" passiert ...
Ich denke, dass die chroot-Umgebung, einen solchen Zugriff verhindert. (Daneben könnte ich ja noch den Output in andere Verzeichnisse unterbinden.)
... so viel wie möglich "fest" im Skript setzen und nur die unbedingt notwendigen Variablen aus dem Request nehmen.
ich werde die input-Daten mal client-seitig auswerten und nur die variablen Teile zum Server senden. Das ist zwar mehr Aufwand, bietet aber auch mehr Sicherheit. Und ich brauche mich nicht mit dem einen String aus mehreren Parametern "herumschlagen", obwohl mich die internen Zusammenhänge schon interessieren.
... mir fallen da garantiert noch jede Menge anderer denkbarer "Angriffe" ein.
Wenn du Lust und Laune hast, kannst du sie gern kurz umreißen.
 
Zuletzt bearbeitet:

PeterPawn

IPPF-Urgestein
Mitglied seit
10 Mai 2006
Beiträge
13,010
Punkte für Reaktionen
981
Punkte
113
Genau das curl --header ... soll ja realisiert/probiert werden.
Ich sprach aber von zwei Bindestrichen ohne weitere Zeichen dahinter (in diesem Token). Das signalisiert nach POSIX das Ende von Optionen und alles danach soll nur noch als Argument interpretiert werden: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html - Punkt 12.2, Guideline 10 - wenn das also auch von "curl" berücksichtigt wird, sind das danach plötzlich alles keine Optionen mehr, sondern nur noch "URLs" ... ich weiß aber nicht, ob "curl" das tatsächlich POSIX-konform handhabt.

Ansonsten hilft so ein "chroot jail" sicherlich auch bei Sicherheitsaspekten ... nur wirst Du auch irgendwo ein beschreibbares Verzeichnis in diesem Teil der Verzeichnisstruktur haben müssen und solange ein Angreifer "bestimmen" kann, daß die Ausgabe dorthin geschrieben werden soll, kann er auch darin liegende Dateien überschreiben. Das gilt sicherlich nicht für das, was ohnehin "read-only" ist, weil es in einem r/o-Dateisystem (wie einem SquashFS-Image) liegt - aber schon Dein CGI-Skript wäre ein geeignetes Ziel für solches "Überschreiben" durch einen Angreifer oder er legt noch eines daneben ab, in dem er dann "das Sagen" hat, was die auszuführenden Kommandos angeht.

Was auch immer Du tust ... Du solltest in jedem Falle verhindern, daß der Aufrufer am Ende entscheidet, wo Daten hingeschrieben werden - wer das zuläßt, hat häufig ("chroot" hin oder her) die Kontrolle über den Webserver schon verloren und wenn dann noch ein "Ausbruch" aus dem Gefängnis möglich ist (das FRITZ!OS arbeitet halt intern immer als "root" und auch Freetz ändert da das Rechtekonzept nur sehr marginal und nicht wirklich "wirksam", weil es sonst selbst nicht mehr als "Owner" auf Dateien zugreifen könnte), dann ist die ganze Box "verloren".

Das geht schon damit los, daß ein Schreibzugriff auf das "procfs" (was sicherlich auch im "chroot jail" gemountet sein muß, weil die BusyBox ohne kaum arbeiten kann) bereits ausreicht, um das Urlader-Environment zu verändern. Ein "chroot jail" alleine bringt also schon mal per se nichts ... der nächste Punkt, den man dann einrichten muß, ist der Betrieb unter einem nicht-privilegierten User, damit der keine Schreibrechte in den diversen virtuellen Dateisystemen (debugfs, sysfs, procfs, etc. - schau Dir die Liste selbst an unter "/proc/filesystems") hat. Schon mit einem Schreibzugriff auf "/proc/mtd" kann man (bei geeigneten Boxen, wo AVM die passenden Routinen im Kernel-Treiber ergänzt hat) den kompletten Flash einer FRITZ!Box löschen lassen - man braucht allerdings dafür "character-oriented I/O", wenn ich mich richtig erinnere und ggf. arbeitet Dein "curl" block-basiert.

Der Verzicht auf "eval" ist in jedem Falle auch anzuraten (zumindest so, wie das oben mal gezeigt wurde) ... denn (wie Du vielleicht richtig erkannt hast?) wenn man da einfach noch weitere Kommandos an die "Freitext-Optionen" anhängt (mit einem Semikolon getrennt), kann man wieder beliebige andere (im "chroot jail" verfügbare) Kommandos ausführen.

Und einen "Grundstock" an Kommandos braucht es nun mal ... das "procfs" kann man - nebenbei bemerkt - auch mittels "echo" (was dann wieder ein Shell-Builtin ist, ebenso wie "printf") beschreiben und auch das Auslesen von Daten klappt über solche Builtins mit Redirections problemlos, dafür braucht man gar nicht unbedingt ein "cat" o.ä. - mit einem while read l;do echo $l;done</var/flash/vpn.cfg liest man z.B. eine Datei aus dem TFFS ausschließlich mit den Shell-Builtins (read und echo/printf) und obendrein noch POSIX-kompatibel; ggf. noch mit Quoting, damit für die dort enthaltenen Zeilen mit Sternen kein Globbing erfolgt. Da hilft es dann auch nicht, wenn im "chroot jail" nichts anderes als die Shell selbst verwendbar sein sollte, ggf. noch mit einigen benötigten externen Kommandos. Wenn das tatsächlich schon sicher wäre, hätte es zusätzliche Layer wie SELinux oder AppArmor (was wohl ab 07.20 in den Boxen mit SMB-Server enthalten sein wird) nie gebraucht.

Daneben könnte ich ja noch den Output in andere Verzeichnisse unterbinden.
Das klingt zwar schlüssig, aber wie genau machst Du das eigentlich? Zeig's doch einfach mal als Beispiel - sonst kann man auch keine "Schwachstellen" in einem solchen Plan erkennen, wenn der nicht konkrete Züge angenommen hat.
 

FischersFreetz

Neuer User
Mitglied seit
22 Feb 2019
Beiträge
64
Punkte für Reaktionen
2
Punkte
8
Apropos "Mounten von procfs" in der chroot-Umgebnung...ist das der richtige Befehl mit den richtigen Parametern?
mount -t proc proc /var/media/ftp/freetz/lighthttpd/www/proc

Es gibt dabei nämlich ein Problem. Nach diesem Befehl verhält sich die Box zuerst erwartungsgemäß. Aber am nächsten Morgen erhielt ich folgende Meldung bei einem Shell-Zugiff:
Code:
cat: can't open '/proc/sys/urlader/environment': No such file or directory
cat: can't open '/proc/cmdline': No such file or directory
cat: can't open '/proc/sys/urlader/firmware_version': No such file or directory
cat: can't open '/proc/sys/urlader/annex': No such file or directory
...
-bash: cd: /var/media/ftp/uStor01:  No such file or directory/
Wer oder was reagiert auf den zweiten Mount von "proc" allergisch? Und warum so zeitverzögert?
Was müsste man also noch beachten, wenn man "proc" in der chroot ein zweites Mal einhängt?

EDIT : Ich habe bezüglich dieser Fragestellungen ein eigenes Thema eröffnet.
 
Zuletzt bearbeitet:
3CX

Statistik des Forums

Themen
235,269
Beiträge
2,058,259
Mitglieder
355,837
Neuestes Mitglied
exa201