Wie werden ssh Remote-Befehlszeilenargumente analysiert?

11

Ich habe die Fragen und Antworten über die Notwendigkeit gesehen, die Argumente für Remote-SSH-Befehle doppelt zu umgehen. Meine Frage ist: Genau wo und wann wird die zweite Analyse durchgeführt?

Wenn ich Folgendes ausführe:

$ ssh otherhost pstree -a -p

Ich sehe folgendes in der Ausgabe:

  |-sshd,3736
  |   `-sshd,1102
  |       `-sshd,1109
  |           `-pstree,1112 -a -p

Der übergeordnete Prozess für den Remote-Befehl ( pstree) lautet sshd: Es scheint dort keine Shell zu geben, die die Befehlszeilenargumente für den Remote-Befehl analysiert. Es scheint also nicht so, als wäre ein doppeltes Anführungszeichen oder ein Escapezeichen erforderlich ( aber es ist definitiv). Wenn ich stattdessen zuerst dort ssh und eine Login-Shell bekomme und dann starte, pstree -a -psehe ich Folgendes in der Ausgabe:

  ├─sshd,3736
     └─sshd,3733
         └─sshd,3735
             └─bash,3737
                 └─pstree,4130 -a -p

Es gibt also eindeutig eine bashShell, die in diesem Fall das Parsen von Befehlszeilen durchführen würde. In dem Fall, in dem ich einen Remote-Befehl direkt verwende, scheint es keine Shell zu geben. Warum ist also ein doppeltes Anführungszeichen erforderlich?

nur keiner
quelle

Antworten:

22

Es gibt immer eine Remote-Shell. Im SSH-Protokoll sendet der Client dem Server eine Zeichenfolge zur Ausführung. Der SSH-Befehlszeilenclient nimmt seine Befehlszeilenargumente und verkettet sie mit einem Leerzeichen zwischen den Argumenten. Der Server nimmt diese Zeichenfolge, führt die Anmeldeshell des Benutzers aus und übergibt ihr diese Zeichenfolge.

Es ist unmöglich, die Remote-Shell zu umgehen. Das Protokoll hat nichts mit dem Senden eines Arrays von Zeichenfolgen zu tun, die als argv-Array auf dem Server analysiert werden könnten. Der SSH-Server umgeht die Remote-Shell nicht, da dies eine Sicherheitsbeschränkung darstellen kann: Die Verwendung eines eingeschränkten Programms als Benutzer-Shell ist eine Möglichkeit, ein eingeschränktes Konto bereitzustellen, das nur bestimmte Befehle ausführen darf (z. B. ein Nur-Rsync-Konto oder ein Nur-Git-Konto).

Möglicherweise sehen Sie die Shell nicht, pstreeda sie möglicherweise bereits verschwunden ist. Viele Shells haben eine Optimierung, bei der die Shell execvestattdessen " dieses externen Befehls" ausführt, wenn sie feststellen, dass sie "diesen externen Befehl ausführen, warten, bis er abgeschlossen ist, und mit dem Befehlsstatus beenden ". Dies geschieht in Ihrem ersten Beispiel. Vergleichen Sie die folgenden drei Befehle:

ssh otherhost pstree -a -p
ssh otherhost 'pstree -a -p'
ssh otherhost 'pstree -a -p; true'

Die ersten beiden sind identisch: Der Client sendet genau die gleichen Daten an den Server. Der dritte sendet einen Shell-Befehl, der die Exec-Optimierung der Shell zunichte macht.

Gilles 'SO - hör auf böse zu sein'
quelle
2
Ha! Ich kann nicht glauben, dass du mich geschlagen hast, um meine eigene Frage zu beantworten. Ich fand es in der Mitte des Postings der Frage heraus und dachte mir, ich sollte es einfach selbst fragen und beantworten.
Nur am
10

Ich glaube, ich habe es herausgefunden:

$ ssh otherhost pstree -a -p -s '$$'
init,1         
  `-sshd,3736
      `-sshd,11998
          `-sshd,12000
              `-pstree,12001 -a -p -s 12001

Die Argumente pstreesind: anzeigen Befehlszeilenargumente, zeigen pids und zeigen nur übergeordnete Prozesse des gegebenen pid. Dies '$$'ist eine spezielle Shell-Variable, die bash durch eine eigene pid ersetzt, wenn bash die Befehlszeilenargumente auswertet. Es wird einmal zitiert, um zu verhindern, dass es von meiner lokalen Shell interpretiert wird. Es wird jedoch nicht doppelt zitiert oder maskiert, damit es von der Remote-Shell interpretiert werden kann.

Wie wir sehen können, wird es durch ersetzt, 12001so dass dies die PID der Shell ist. Wir können auch aus der Ausgabe pstree,12001ersehen, dass der Prozess mit einer PID von 12001 selbst pstree ist. Also pstreeist die Schale?

Was ich dort sammle, ist, dass bashes aufgerufen wird und die Befehlszeilenargumente analysiert, aber dann aufgerufen wird exec, um sich durch den ausgeführten Befehl zu ersetzen.

Es scheint, dass dies nur bei einem einzelnen Remote-Befehl der Fall ist:

$ ssh otherhost pstree -a -p -s '$$' \; echo hi
init,1         
  `-sshd,3736
      `-sshd,17687
          `-sshd,17690
              `-bash,17691 -c pstree -a -p -s $$ ; echo hi
                  `-pstree,17692 -a -p -s 17691
hi

In diesem Fall fordere ich die Ausführung pstreevon zwei Befehlen an: gefolgt von echo. Und wir können hier sehen, dass bashdies tatsächlich im Prozessbaum als übergeordnetes Element von angezeigt wird pstree.

nur keiner
quelle
Jep ! + 1. Es zeigt beispielhaft, was Gilles formeller an erster Stelle und beispielhaft an zweiter Stelle stellte. Vielleicht ist es angebracht, ihm Anerkennung für seine frühe Antwort zu geben?
Cbhihe
0

Als Unterstützung für die anderen Antworten habe ich den Code nachgeschlagen, der Befehle auf der Fernbedienung aufruft: https://github.com/openssh/openssh-portable/blob/4f29309c4cb19bcb1774931db84cacc414f17d29/session.c#L1660 ...

1660    /*
1661     * Execute the command using the user's shell.  This uses the -c
1662     * option to execute the command.
1663     */
1664    argv[0] = (char *) shell0;
1665    argv[1] = "-c";
1666    argv[2] = (char *) command;
1667    argv[3] = NULL;
1668    execve(shell, argv, env);
1669    perror(shell);
1670    exit(1);

... die, wie Sie sehen, shellmit dem ersten -cund dem zweiten Argument bedingungslos aufruft command. Zuvor wurde die shellVariable auf die Login-Shell des Benutzers gesetzt, wie in aufgezeichnet /etc/passwd. commandist ein Argument für diese Funktion und wird letztendlich auf eine Zeichenfolge gesetzt, die wörtlich von der Leitung gelesen wird (siehe session_exec_reqin derselben Datei ). Der Server interpretiert den Befehl also überhaupt nicht, aber auf der Fernbedienung wird immer eine Shell aufgerufen.

Der relevante Teil der SSH-Protokollspezifikation scheint dieses Verhalten jedoch nicht zu erfordern. es heißt nur

 byte      SSH_MSG_CHANNEL_REQUEST
 uint32    recipient channel
 string    "exec"
 boolean   want reply
 string    command

Diese Nachricht fordert den Server auf, die Ausführung des angegebenen Befehls zu starten. Die 'Befehlszeichenfolge' kann einen Pfad enthalten. Es MÜSSEN normale Vorsichtsmaßnahmen getroffen werden, um die Ausführung nicht autorisierter Befehle zu verhindern.

Dies liegt wahrscheinlich daran, dass nicht alle Betriebssysteme das Konzept einer Befehlszeilen-Shell haben. Zum Beispiel wäre es für einen klassischen MacOS-SSH-Server nicht verrückt gewesen, stattdessen dem AppleScript- Interpreter "exec" -Befehlszeichenfolgen zuzuführen .

zwol
quelle