5 Stimmen

PHP die Ausführung eines Bash-Skripts mit Root-Rechten erlauben

Wie kann ich einem PHP-Skript erlauben, ein Bash-Skript mit Root-Rechten auszuführen?

Nehmen wir an, es gibt ein PHP-Skript...

<?php
// location: /var/www/script.php
exec("bash /var/scripts/test.sh"); // "sudo bash ..." does not work
?>

und ein Bash-Skript ...

#!/bin/bash
# location: /var/scripts/test.sh
sudo mkdir /test

Natürlich sollten PHP und Apache nicht als Root laufen und bestenfalls kann das Skript mit Root-Rechten ausgeführt werden. Irgendwelche Ideen?

Mit freundlichen Grüßen, Jimbo

6voto

Pekka Punkte 429407

Jede PHP-basierte Lösung, die an irgendeiner Stelle der Kette Root-Rechte verleiht, ist gefährlich: Ein Angreifer, der Zugriff auf den PHP-Benutzer hat, könnte sich Zugang zum Root-Benutzer verschaffen, und das ist unter Sicherheitsaspekten nicht hinnehmbar.

Ich habe dies nie selbst umgesetzt, aber ich werde vorschlagen, was ich vorgeschlagen habe aquí : Lassen Sie ein Skript/einen Cron-Job mit Root-Rechten regelmäßig nach einem Zeichen des PHP-Skripts suchen, dass ein Job erledigt werden soll - zum Beispiel eine Datei mit einem bestimmten Namen oder ein Eintrag in einer Job-Datenbank.

Wenn diese Datei gefunden wird, tut das Root-Skript seine Arbeit und entfernt die Datei wieder.

Wenn Ihr PHP-Skript keine direkte Antwort vom Root-Skript benötigt, halte ich dies für den besten Weg. (Eine Antwort könnte natürlich auch dadurch erleichtert werden, dass das Root-Skript eine Statusmeldung in die Datei schreibt).

Solange Sie die Art der Aufgaben, die PHP für das Root-Skript schreiben kann, eng begrenzen, ist dies eine wasserdichte Lösung, da sich der Root-Benutzer nicht in die Angelegenheiten von PHP einmischt.

6voto

jm666 Punkte 58205

Wenn Sie nicht auf cron warten wollen, finden Sie hier einen einfachen Wrapper in C, den Sie von php aus aufrufen werden.

#include <unistd.h>
#include <errno.h>
#define WEBUID 500
main( int argc, char ** argv, char ** envp ) {
    if( getuid() != WEBUID ) exit(1);
    /* some more security checks */
    if( setuid(geteuid()) ) perror( "setuid error" );
    envp = 0; /* don't want environment - security problem */
    system( "/hardcoded/path/to/script.bash", argv, envp );
}

Dieser kompilierte Wrapper sollte Root, Gruppe "www" und "s-bit" haben.
chwon root.www wrapper; chmod 4440 wrapper also

  • wenn er ausgeführt wird, ist seine effektive UID Root
  • Ausführen kann es nur die Gruppe www (Gruppe des Webservers)
  • und wenn die UID des Aufrufers kein Webserver ist, wird

2voto

Sie müssen einen Blick auf incron (Cron für Dateisystemereignisse) werfen. Lassen Sie php in eine Datei schreiben und stellen Sie incron so ein, dass Ihr Skript beim Schließen der geschriebenen Datei gestartet wird (incron ist sehr spezifisch). Ihr Skript sollte wahrscheinlich auch die Eingabedatei bereinigen, um Code-Injektion zu verhindern, und den lockfile-Befehl verwenden, um Race Conditions zwischen mehreren Webbenutzern zu verhindern.

Ich habe eine Mini-Webschnittstelle, auf der man anonymes FTP oder andere Dienste für 1 Stunde mit einem Passwort aktivieren kann. www läuft mit normalen Rechten, ebenso www-data (der php-Benutzer), aber incron ruft das Eingabeskript als Root auf.

Mike

1voto

minorgod Punkte 574

Sie brauchen PHP oder Apache nicht unbedingt als Root laufen zu lassen. Wenn Sie die Kontrolle über Ihren Server haben, können Sie ein Apache-Modul namens suPHP verwenden und in der Konfiguration den Benutzer angeben, unter dem Apache für Ihre PHP-Skripte ausgeführt werden soll. Sie können dies für jeden Standort einzeln tun, so dass Sie suPHP nur für Skripte auf einer bestimmten Domain ausführen müssen. Mir fehlt das Fachwissen, um Sie bei der Installation zu beraten, aber ich habe unsere dedizierte Serverfirma gebeten, es für mich zu tun, damit ein Github-Post-Receive-Hook ein Skript auf meinem Entwicklungsserver aufrufen kann, das jedes Mal einen Git-Pull auf dem Entwicklungsserver auslöst, wenn jemand etwas in die Github-Repos einpflegt. Ich konnte es nicht anders hinbekommen, da Apache als Eigentümer der lokalen Repos laufen muss, damit es funktioniert.

Ich dachte gerade an eine andere mögliche Lösung basierend auf den anderen Kommentaren hier - Sie könnten in der Lage sein, ein einfaches PHP-Skript zu schreiben, um die Anfrage vom Github-Hook zu empfangen und einige beliebige Informationen in eine Datei in einem Verzeichnis mit 777 Berechtigungen oder in die Datenbank zu schreiben. Dann kann man einen Cron-Job einrichten, der jede Minute überprüft, ob sich die Datei oder die Datenbank geändert hat, und wenn ja, die Git-Pull-Anfrage direkt stellt, da Cron normalerweise bereits als Root läuft. Du könntest auch einfach nachsehen, ob sich der Zeitstempel der Datei geändert hat, um festzustellen, ob ein Git Pull durchgeführt werden soll. Sie könnten Ihr Cron-Skript zu dem Benutzer wechseln lassen, dem die Repos gehören, und dann den Git-Pull auslösen. Das ist zwar keine echte Echtzeitlösung, aber wenn das Cron-Skript sehr einfach ist, würde es Ihr System nicht wirklich ausbremsen, wenn Sie es alle ein oder zwei Minuten aufrufen. Ich hoffe, das hilft.

0voto

Caleb Punkte 323

Verwenden Sie einen Daemon, der als Root läuft (vielleicht in C geschrieben) und der die Shell-Skripte für Sie startet. Um die Ausführung von Shell-Skripten aus dem PHP-Skript heraus anzustoßen, verwenden Sie einfach IPC (Message Queues).

Schauen Sie hier nach, um eine Vorstellung davon zu bekommen, wovon ich spreche: http://php.net/manual/en/function.msg-send.php#114831

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X