Ich muss einige sensible Argumente für ein von mir ausgeführtes Programm verbergen, habe aber keinen Zugriff auf den Quellcode. Ich führe dies auch auf einem gemeinsam genutzten Server aus, sodass ich so etwas nicht verwenden kann, hidepid
weil ich keine sudo-Berechtigungen habe.
Hier sind einige Dinge, die ich ausprobiert habe:
export SECRET=[my arguments]
, gefolgt von einem Anruf bei./program $SECRET
, aber das scheint nicht zu helfen../program `cat secret.txt`
Wosecret.txt
sind meine Argumente, aber der Allmächtigeps
kann meine Geheimnisse aufspüren.
Gibt es eine andere Möglichkeit, meine Argumente zu verbergen, ohne dass der Administrator eingreift?
ps
tut nichts Magisches, um "deine Geheimnisse herauszuspüren". Auf jeden Fall sollten vernünftig geschriebene Programme stattdessen eine Befehlszeilenoption bieten, mit der ein Geheimnis aus einer angegebenen Datei oder aus stdin gelesen werden kann, anstatt es direkt als Argument zu verwenden.Antworten:
Wie hier erklärt , fügt Linux die Argumente eines Programms in den Datenraum des Programms ein und behält einen Zeiger auf den Anfang dieses Bereichs bei. Dies wird von
ps
usw. verwendet, um die Programmargumente zu finden und anzuzeigen.Da sich die Daten im Speicherbereich des Programms befinden, können sie bearbeitet werden. Um dies zu tun, ohne das Programm selbst zu ändern, muss ein Shim mit einer
main()
Funktion geladen werden, die vor der eigentlichen Hauptfunktion des Programms aufgerufen wird. Dieser Shim kann die echten Argumente in ein neues Feld kopieren und dann die ursprünglichen Argumente überschreiben, sodassps
nur nuls angezeigt werden.Der folgende C-Code führt das aus.
Es ist nicht möglich, einzugreifen
main()
, aber Sie können in die Standard-C-Bibliotheksfunktion eingreifen__libc_start_main
, die dann main aufruft. Kompilieren Sie diese Dateishim_main.c
wie im Kommentar zu Beginn angegeben und führen Sie sie wie gezeigt aus. Ich habe einenprintf
im Code hinterlassen, damit Sie überprüfen, ob er tatsächlich aufgerufen wird. Führen Sie beispielsweise ausdann tut ein
ps
und Sie erhalten ein leerer Befehl und args werden abgebildet.Es gibt noch eine kleine Zeitspanne, in der die Befehlsargumente möglicherweise sichtbar sind. Um dies zu vermeiden, können Sie beispielsweise das Shim ändern, um Ihr Geheimnis aus einer Datei zu lesen und es zu den an das Programm übergebenen Argumenten hinzuzufügen.
quelle
/proc/pid/cmdline
das Geheimnis angezeigt wird (genau wie beimcurl
Versuch, das in der Befehlszeile angegebene Kennwort zu verbergen). Während Sie LD_PRELOAD verwenden, können Sie main so umbrechen, dass das Geheimnis aus der Umgebung in das Argument kopiert wird, das main empfängt. Wie anrufen,LD_PRELOAD=x SECRET=y cmd
wo Siemain()
mit demargv[]
Sein anrufen[argv[0], getenv("SECRET")]
/proc/pid/environ
. Dies kann auf die gleiche Weise wie die Argumente überschrieben werden, aber es bleibt das gleiche Fenster./proc/pid/cmdline
ist öffentlich,/proc/pid/environ
ist nicht. Es gab einige Systeme, auf denenps
(eine Setuid-Programmdatei) die Umgebung eines Prozesses offengelegt hat, aber ich glaube nicht, dass Sie heutzutage darauf stoßen werden. Die Umwelt wird im Allgemeinen als sicher genug angesehen . Es ist nicht sicher, Prozesse mit derselben euid auszuloten, aber diese können häufig die Erinnerung an Prozesse mit derselben euid lesen, sodass Sie nicht viel dagegen tun können.main
Methode des umschlossenen Programms weiterleitet, im Idealfall auch die Umgebungsvariable, um ein versehentliches Verlieren für untergeordnete Prozesse zu vermeiden. Alternativ könnte der Wrapper alle Befehlszeilenargumente aus einer Datei lesen .Lesen Sie die Dokumentation der Befehlszeilenschnittstelle der betreffenden Anwendung. Es kann durchaus eine Option geben, das Geheimnis aus einer Datei anstatt direkt als Argument anzugeben.
Wenn dies fehlschlägt, reichen Sie einen Fehlerbericht für die Anwendung mit der Begründung ein, dass es keine sichere Möglichkeit gibt, ein Geheimnis für die Anwendung bereitzustellen.
Sie können die Lösung in meuhs Antwort jederzeit sorgfältig (!) An Ihre spezifischen Bedürfnisse anpassen . Achten Sie besonders auf Stéphanes Kommentar und seine Folgemaßnahmen.
quelle
Wenn Sie Argumente an das Programm übergeben müssen, um es zum Laufen zu bringen, haben Sie Pech, egal was Sie tun, wenn Sie es nicht
hidepid
für procfs verwenden können.Da Sie erwähnt haben, dass dies ein Bash-Skript ist, sollten Sie den Quellcode bereits verfügbar haben, da Bash keine kompilierte Sprache ist.
Andernfalls können Sie möglicherweise die Cmdline des Prozesses mit
gdb
oder ähnlichem umschreiben und mitargc
/ herumspielen,argv
sobald er bereits gestartet wurde.Ich würde wirklich nur empfehlen, den Quellcode zu beschaffen oder mit dem Hersteller zu sprechen, um den Code zu modifizieren. Die Angabe von Geheimnissen in der Befehlszeile in einem POSIX-Betriebssystem ist nicht mit dem sicheren Betrieb kompatibel.
quelle
Wenn ein Prozess einen Befehl ausführt (über den
execve()
Systemaufruf), wird sein Speicher gelöscht. Um einige Informationen über die Ausführung weiterzuleiten, benötigt derexecve()
Systemaufruf zwei Argumente: die Arraysargv[]
undenvp[]
.Das sind zwei Arrays von Strings:
argv[]
enthält die Argumenteenvp[]
Enthält die Umgebungsvariablendefinitionen als Zeichenfolgen imvar=value
Format (gemäß Konvention).Wenn Sie das tun:
(hier die fehlenden Anführungszeichen um die Parametererweiterung hinzugefügt).
Sie führen
cmd
mit secret (value
) aus, das sowohl inargv[]
als auch übergeben wurdeenvp[]
.argv[]
wird["cmd", "value"]
undenvp[]
so ähnlich sein[..., "PATH=/bin:...", "HOME=...", ..., "SECRET=value", "TERM=xterm", ...]
. Dacmd
keinegetenv("SECRET")
oder eine gleichwertige Aktion zum Abrufen des Werts des Geheimnisses von dieserSECRET
Umgebungsvariablen ausgeführt wird, ist es nicht sinnvoll, es in die Umgebung zu stellen.argv[]
ist öffentliches Wissen. Es zeigt in der Ausgabe vonps
.envp[]
heutzutage nicht. Unter Linux wird dies in angezeigt/proc/pid/environ
. Es wird in der Ausgabe vonps ewww
BSDs (und mit procps-ngsps
unter Linux) angezeigt , jedoch nur für Prozesse, die mit derselben effektiven UID ausgeführt werden (und mit weiteren Einschränkungen für ausführbare setuid / setgid-Dateien). Es wird möglicherweise in einigen Überwachungsprotokollen angezeigt, aber auf diese Überwachungsprotokolle sollten nur Administratoren zugreifen können.Kurz gesagt, die Umgebung, die an eine ausführbare Datei übergeben wird, soll privat sein oder zumindest ungefähr so privat wie der interne Speicher eines Prozesses (auf den ein anderer Prozess mit den richtigen Berechtigungen unter Umständen auch mit einem Debugger zugreifen kann und kann) auch auf die Festplatte gespeichert werden).
Da dies
argv[]
allgemein bekannt ist, ist ein Befehl, der Daten erwartet, die in seiner Befehlszeile geheim sein sollen, vom Entwurf her fehlerhaft.In der Regel stellen Befehle, die geheim gehalten werden müssen, eine andere Schnittstelle zur Verfügung, z. B. über eine Umgebungsvariable. Zum Beispiel:
Oder über einen dedizierten Dateideskriptor wie stdin:
(
echo
Wird eingebaut, wird in der Ausgabe von nicht angezeigt.ps
)Oder eine Datei, wie die
.netrc
fürftp
und ein paar andere Befehle oderEinige Anwendungen wie
curl
(und das ist auch der Ansatz von @meuh hier ) versuchen, das Passwort, das sieargv[]
von neugierigen Blicken erhalten haben , zu verbergen (auf einigen Systemen, indem sie den Teil des Speichers überschreiben, in dem sich das befindet)argv[]
Zeichenfolgen gespeichert wurden). Aber das hilft nicht wirklich und gibt ein falsches Sicherheitsversprechen. Dadurch bleibt ein Fenster zwischen demexecve()
und dem Überschreiben, in demps
das Geheimnis noch angezeigt wird.Wenn ein Angreifer zum Beispiel weiß, dass Sie ein Skript ausführen, das einen
curl -u user:somesecret https://...
(zum Beispiel in einem Cron-Job) ausführt, muss er nur die (vielen) Bibliotheken aus dem Cache entfernen,curl
die (zum Beispiel durch Ausführen eines) verwendet werdensh -c 'a=a;while :; do a=$a$a;done'
) verwendet werden Um den Startvorgang zu verlangsamen,until grep 'curl.*[-]u' /proc/*/cmdline; do :; done
reicht es aus, dieses Kennwort in meinen Tests abzufangen.Wenn die Argumente die einzige Möglichkeit sind, das Geheimnis an die Befehle weiterzugeben, gibt es möglicherweise noch einige Dinge, die Sie versuchen könnten.
Auf einigen Systemen, einschließlich älterer Linux-Versionen, können nur die ersten Bytes (4096 unter Linux 4.1 und früher) der eingegebenen Zeichenfolgen
argv[]
abgefragt werden.Dort könnten Sie tun:
Und das Geheimnis wäre verborgen, weil es hinter den ersten 4096 Bytes ist. Jetzt müssen Leute, die diese Methode verwendet haben, es jetzt bereuen, da Linux seit 4.2 die Liste der Argumente in nicht mehr abschneidet
/proc/pid/cmdline
. Beachten Sie auch, dass es nicht so ist, weilps
nicht mehr als so viele Bytes einer Befehlszeile angezeigt werden (wie bei FreeBSD, wo es auf 2048 beschränkt zu sein scheint), dass man nicht dieselbe APIps
verwenden kann, um mehr zu erhalten. Dieser Ansatz ist jedoch auf Systemen gültig, auf denenps
nur ein normaler Benutzer diese Informationen abrufen kann (z. B. wenn die API privilegiert ist undps
setgid oder setuid ist, um sie zu verwenden), die dort jedoch möglicherweise nicht zukunftssicher sind.Ein anderer Ansatz wäre, das Geheimnis nicht weiterzugeben,
argv[]
sondern Code in das Programm einzufügen (mithilfe vongdb
oder einem$LD_PRELOAD
Hack), bevormain()
es gestartet wird, der das Geheimnis in dasargv[]
empfangene von einfügtexecve()
.Mit
LD_PRELOAD
für nicht-setuid / setgid dynamisch verknüpfte ausführbare Dateien auf einem GNU-System:Dann:
Zu keinem Zeitpunkt hätte
ps
sich dasps -opid,args
dort gezeigt (-opid,args
in diesem Beispiel das Geheimnis). Beachten Sie, dass wir Elemente der sind zu ersetzenargv[]
Array von Zeigern , die Saiten nicht zwingend durch diese Zeiger zeigten auf, weshalb unsere Änderungen werden nicht in dem Ausgangps
.Mit
gdb
, immer noch für nicht-setuid / setgid dynamisch verknüpfte ausführbare Dateien und auf GNU-Systemen:Noch mit
gdb
, ein nicht-GNU spezifischen Ansatz, der nicht auf ausführbare Dateien angewiesen ist dynamisch gelinkt oder Debug - Symbole werden und sollte für jede ELF ausführbare Datei auf Linux zumindest sein könnte funktionieren:Testen mit einer statisch verknüpften ausführbaren Datei:
Wenn die ausführbare Datei möglicherweise statisch ist, haben wir keine zuverlässige Möglichkeit, Speicher zum Speichern des Geheimnisses zuzuweisen. Daher müssen wir das Geheimnis von einer anderen Stelle abrufen, die sich bereits im Prozessspeicher befindet. Deshalb ist die Umwelt hier die naheliegende Wahl. Wir verbergen auch diese Umgebungsvariable für
SECRET
den Prozess (indem wir sie in ändernSECRE=
), um zu verhindern, dass sie verloren geht, wenn der Prozess aus irgendeinem Grund beschließt, seine Umgebung zu sichern oder nicht vertrauenswürdige Anwendungen auszuführen.Das funktioniert auch auf Solaris 11 (vorausgesetzt , GDB und GNU binutils installiert sind (Sie müssen umbenennen können
objdump
zugobjdump
).Unter FreeBSD (mindestens x86_64, ich bin mir nicht sicher, welche der ersten 24 Bytes (die 16 werden, wenn gdb (8.0.1) interaktiv ist und darauf hindeutet, dass es dort einen Fehler in gdb gibt) auf dem Stack sind), ersetzen Sie die
argc
undargv
-Definitionen mit:(Möglicherweise müssen Sie auch das
gdb
Paket / den Port installieren, da die Version, die sonst mit dem System geliefert wird, veraltet ist.)quelle
Was Sie tun könnten, ist
Nehmen Sie dann an, Sie schreiben Ihr
./program
in C (oder jemand anderes kann es für Sie ändern oder verbessern), und verwenden Sie getenv (3) in diesem Programm, vielleicht alsund nach dem
export
laufen sie einfach./program
in der gleichen shell. Oder der Name der Umgebungsvariablen könnte übergeben werden (durch Ausführen von./program --secret-var=SECRET
etc ...)ps
Ich werde nichts über dein Geheimnis verraten, aber proc (5) kann immer noch eine Menge Informationen liefern (zumindest für andere Prozesse desselben Benutzers).Lesen Sie auch diese Informationen, um die Übergabe von Programmargumenten zu vereinfachen.
In dieser Antwort finden Sie eine bessere Erklärung zum Globbing und zur Rolle einer Shell.
Vielleicht haben Sie
program
andere Möglichkeiten, um Daten abzurufen (oder die Kommunikation zwischen Prozessen klüger zu gestalten) als mit einfachen Programmargumenten (dies sollte auf jeden Fall der Fall sein, wenn sensible Informationen verarbeitet werden sollen). Lesen Sie die Dokumentation. Oder Sie missbrauchen dieses Programm (das nicht zur Verarbeitung geheimer Daten vorgesehen ist).Geheime Daten zu verstecken ist wirklich schwierig. Es reicht nicht aus, es nicht durch Programmargumente zu geben.
quelle
./program
, sodass die erste Hälfte dieser Antwort nicht relevant zu sein scheint.