[LINUX] Die Geschichte des Versuchs, SSH_AUTH_SOCK mit LD_PRELOAD auf dem Bildschirm veraltet zu halten

\ <ins > 26.04.2018 Nachtrag

Was ist nach zwei Jahren passiert?

Schreiben Sie eine Shell-Funktion namens "find_agent", um sie jedes Mal manuell aufzulösen. Es ist sicherlich praktisch, automatisch zu wechseln, aber es gibt nicht viele Male, in denen dies erforderlich ist, und LD_PRELOAD stört manchmal beim Debuggen, sodass es nicht viel Nutzen gab ...

Ich habe github verwendet, um die Verbindung von SSH_AUTH_SOCK zu überprüfen. Die Tasten, die ich normalerweise benutze, werden normalerweise in Github abgelegt, daher habe ich Probleme mit ssh, weil es um das Timing des Git-Push geht. Socket-Dateien sollten mit Pfadnamen versehen sein

find_agent () {
    local GLOBS=("/tmp/com.apple.launchd.*/Listeners" "/tmp/ssh-*/agent.*");
    for g in "${GLOBS[@]}"; do
        for c in ${g}; do
            SSH_AUTH_SOCK="$c";
            [ ! -S "${SSH_AUTH_SOCK}" ] && continue;
            ssh -T [email protected];
            [ $? -eq 1 ] && return 0;
        done;
    done
}

</ins>

Nachfolgend finden Sie die Beschreibung vom 12.02.2016


github https://github.com/takei-yuya/alt_ssh_auth_sock

Ich bin auf einem Skiausflug nach Akita gekommen, aber ich war frei im Gasthaus, also habe ich es geschrieben.

Was ist das?

Eine Story, um das Problem zu vermeiden, dass die Referenz von SSH_AUTH_SOCK, die für die Übertragung von SSH-Agenten durch Trennen / Anhängen verwendet wird, falsch ausgerichtet ist, wenn der Bildschirm am Verbindungsziel von SSH verwendet wird.

Mit anderen Worten, so etwas

local $ # ssh-Aktivieren Sie die Agentenübertragung und stellen Sie eine Verbindung zu hostA her
local $ ssh -A hostA

hostA $ #SSH automatisch am Verbindungsziel_AUTH_Die Umgebungsvariable SOCK ist gesetzt
hostA $ declare -p SSH_AUTH_SOCK
declare -x SSH_AUTH_SOCK="/tmp/ssh-XXXXXXXXXX/agent.11111"
hostA $ #Dieser Socket ist für diese Sitzung mit dem sshd verbunden
hostA $ ps -p 11111
  PID TTY          TIME CMD
11111 ?        00:00:00 sshd
hostA $ #Selbst wenn auf hostA kein Schlüssel vorhanden ist, werden die Schlüsselinformationen über den Socket übertragen.
hostA $ #Sie können mit Schlüsselauthentifizierung eine Verbindung zu einem anderen Host herstellen
hostA $ ssh hostB  
hostB $ exit

hostA $ #Bildschirm speichert die Umgebungsvariablen, wenn der Bildschirm gestartet wird
hostA $ screen -S ssh_test
hostA(screen) $ declare -p SSH_AUTH_SOCK
declare -x SSH_AUTH_SOCK="/tmp/ssh-XXXXXXXXXX/agent.11111"
hostA(screen) $ ^A^D  #Ablösen

hostA $ #Dieser Socket wird ungültig, wenn die SSH-Sitzung abläuft
hostA $ #Versuchen Sie, die Verbindung wiederherzustellen
hostA $ exit
local $ ssh -A hostA
hostA $ #Der Socket-Pfad ändert sich, weil sich die Sitzung geändert hat
hostA $ declare -p SSH_AUTH_SOCK
declare -x SSH_AUTH_SOCK="/tmp/ssh-YYYYYYYYYY/agent.33333"
hostA $ #Alte Sitzung sshd ist weg
hostA $ ps -p 11111
  PID TTY          TIME CMD

hostA $ #In der Bildschirmsitzung sind die Umgebungsvariablen jedoch immer noch veraltet ...
hostA $ screen -x ssh_test
hostA(screen) $ declare -p SSH_AUTH_SOCK
declare -x SSH_AUTH_SOCK="/tmp/ssh-XXXXXXXXXX/agent.11111"
hostA(screen) $ #Altes ssh-Agententransfer stellt keine Verbindung her ...
hostA(screen) $ ssh hostB
Permission denied (publickey).

Es ist also lange her, aber diese Art von Phänomen. Ich möchte etwas dagegen tun.

Die Ursache ist, dass die Umgebungsvariablen in der Sitzung auf dem Bildschirm nicht aktualisiert werden.

was wirst du tun?

Versuchen Sie es mit einem Mechanismus namens LD_PRELOAD.

Grob gesagt scheint es ein Mechanismus zu sein, eine dynamische Bibliothek beim Starten eines Prozesses zwangsweise einzufügen. Es kann verwendet werden, um 400.000 Systemaufrufe und Bibliotheksfunktionsaufrufe zu verknüpfen oder zu stehlen.

Die Zielfunktion ist getenv. Mit anderen Worten, die Idee, Umgebungsvariablen von außen gewaltsam zu manipulieren.

Überprüfen Sie den aktuellen SSH_AUTH_SOCK und versuchen Sie es mit einem anderen Socket, wenn Sie keine Verbindung zum Socket herstellen können. Die zu versuchenden Socket-Kandidaten werden durch das Dateikugelmuster einer anderen Umgebungsvariablen angegeben.

Mit anderen Worten

hostA(screen) $ ssh hostB
Permission denied (publickey).
hostA(screen) $ export LD_PRELOAD="/path/to/injection_lib"
hostA(screen) $ export ALT_SSH_AUTH_SOCK="/tmp/ssh-*/agent.*"
hostA(screen) $ ssh hostB

Das passiert

github: https://github.com/takei-yuya/alt_ssh_auth_sock

#define _GNU_SOURCE  // for RTLD_NEXT
#include <stdlib.h>
#include <dlfcn.h>
#include <string.h>

#include <glob.h>

#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

//Statische Variable zum Speichern des ursprünglichen getenv
static char* (*_original_getenv)(const char *name) = NULL;

//Es scheint, dass Sie mithilfe der GNU-Erweiterung eine Funktion erstellen können, die vor der Hauptfunktion ausgeführt werden soll.
static void _alt_ssh_auth_sock_init() __attribute__((constructor));
static void _alt_ssh_auth_sock_init() {
  //Speichern Sie das Original getenv
  _original_getenv = dlsym(RTLD_NEXT, "getenv");
}

//Stellen Sie sicher, dass die Steckdose aktiv ist. ...... Ich verbinde mich nur.
int check_socket(const char* socket_file_path) {
  struct sockaddr_un addr;
  addr.sun_family = AF_UNIX;
  strncpy(addr.sun_path, socket_file_path, sizeof(addr.sun_path) / sizeof(char));

  int fd = socket(AF_UNIX, SOCK_STREAM, 0);
  int ret = connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un));
  close(fd);
  return ret;
}

//Überschreiben Sie das Verhalten von getenv
char* getenv(const char *name) {
  if (!_original_getenv) {
    //etwas__attribute__((constructor))Funktioniert möglicherweise nicht, also nur für den Fall
    _alt_ssh_auth_sock_init();
  }

  if (strcmp(name, "SSH_AUTH_SOCK") != 0) {
    // SSH_AUTH_Mit Ausnahme von SOCK wird die ursprüngliche Funktion unverändert verwendet.
    return _original_getenv(name);
  }

  char* ssh_auth_sock = _original_getenv("SSH_AUTH_SOCK");
  if (!ssh_auth_sock) {
    // SSH_AUTH_Wenn SOCK nicht definiert ist, kehren Sie so zurück, wie es ist.
    return ssh_auth_sock; // == NULL
  }

  char* alt_ssh_auth_sock = _original_getenv("ALT_SSH_AUTH_SOCK");
  if (!alt_ssh_auth_sock) {
    //Wenn das alternative Socket-Muster nicht angegeben ist, kann nichts unternommen werden. Geben Sie also auf und kehren Sie so zurück, wie es ist
    return ssh_auth_sock;
  }

  if (check_socket(ssh_auth_sock) == 0) {
    //Wenn der aktuelle Socket aktiv ist, kehren Sie wie er ist zurück, ohne den Glob zu erweitern
    return ssh_auth_sock;
  }

  //Erweitern Sie das Glob-Muster
  glob_t pglob;
  if (glob(alt_ssh_auth_sock, GLOB_NOSORT, NULL, &pglob) != 0) {
    globfree(&pglob);
  }

  int i;
  for (i = 0; i < pglob.gl_pathc; ++i) {
    if (check_socket(pglob.gl_pathv[i]) == 0) {
      //Wenn Sie eine lebende Steckdose finden
      break;
    }
  }
  if (i < pglob.gl_pathc) {
    // SSH_AUTH_SOCK überschreiben
    setenv("SSH_AUTH_SOCK", pglob.gl_pathv[i], 1);
    ssh_auth_sock = _original_getenv("SSH_AUTH_SOCK");
  }
  globfree(&pglob);

  return ssh_auth_sock;
}

Alles gepostet, weil es kurz ist. Die Details sind wie im Kommentar geschrieben, aber nachdem ich das ursprüngliche getenv gespeichert habe, verwende ich es aus getenv heraus, um es zu überschreiben.

Wie zu bauen

cc -Wall -fPIC -shared -o libaltsshauthsock.so alt_ssh_auth_sock.c -ldl

Vielleicht brauchst du Soname. Ein bisschen passend hier.

Wie benutzt man

Derzeit denke ich, dass es am besten ist, Umgebungsvariablen in bashrc oder so zu setzen.

$ echo 'export LD_PRELOAD="/path/to/libaltsshauthsock.so"' >> ~/.bashrc
$ echo 'export ALT_SSH_AUTH_SOCK="/tmp/ssh-*/agent.*"' >> ~/.bashrc

Alles was Sie tun müssen, ist den Bildschirm wie gewohnt zu verwenden. Sie sollten in der Lage sein, ssh und git zu verwenden, ohne etwas zu tun, selbst wenn Sie das Anhängen / Trennen und Trennen der Sitzung wiederholen.

Was macht man als nächstes

TODO:

Recommended Posts

Die Geschichte des Versuchs, SSH_AUTH_SOCK mit LD_PRELOAD auf dem Bildschirm veraltet zu halten
Die Geschichte des Versuchs, den Client wieder zu verbinden
Die Geschichte, dass "calendar.day_abbr" auf dem Admin-Bildschirm von django nicht aktualisiert werden konnte
Die Geschichte des Versuchs, Tensorboard mit Pytorch zu verwenden
Eine Geschichte über den Versuch, mit der kostenlosen Stufe von AWS zur COVID-19-Analyse beizutragen, und das Scheitern
Die Geschichte, dass man mit Pycharm kein Pygame spielen kann
Die Geschichte, MeCab in Ubuntu 16.04 zu setzen
Die Geschichte, deep3d auszuprobieren und zu verlieren
Die Geschichte von pep8 wechselt zu pycodestyle
Eine Geschichte über einen Anfänger im Deep Learning, der versucht, Gitarren mit CNN zu klassifizieren
Die Geschichte des tiefen Lernens mit TPU
Einführung in Python mit Atom (unterwegs)
Die Geschichte, Sourcetrail × macOS × VS Code auszuprobieren
Die Geschichte von soracom_exporter (Ich habe versucht, SORACOM Air mit Prometheus zu überwachen)
Die Geschichte vom Umzug von Pipenv zur Poesie
Die Geschichte eines hochrangigen Technikers, der versucht, das Überleben der Titanic vorherzusagen
Eine Geschichte, die fehlgeschlagen ist, als versucht wurde, das Suffix mit rstrip aus einem String zu entfernen
Ich kann die Uhrenquelle tsc nicht finden! ?? Die Geschichte des Versuchs, einen Kernel-Patch zu schreiben
Ich möchte die Standortinformationen von GTFS Realtime auf Jupyter zeichnen! (Mit Ballon)
Einfache Möglichkeit, 0 abhängig von der Anzahl der Ziffern vorangestellt [Python]
Ein Memo darüber, wie man das schwierige Problem der Erfassung von FX mit AI überwinden kann
Ein Hinweis auf Missverständnisse beim Versuch, das gesamte selbst erstellte Modul mit Python3 zu laden
Eine Geschichte über den Versuch, Linter mitten in einem Python (Flask) -Projekt vorzustellen
Die Geschichte des Stoppens des Produktionsdienstes mit dem Befehl hostname
Fügen Sie mit Matplotlib Informationen am unteren Rand der Abbildung hinzu
Die Geschichte des Teilens der Pyenv-Umgebung mit mehreren Benutzern
Versuchen Sie, die Anzahl der Likes auf Twitter zu schätzen
Versuchen Sie, den Inhalt von Word mit Golang zu erhalten
Übergang zum Update-Bildschirm mit dem Django-Tag
Die Geschichte, ein Ring-Fit-Abenteuer kaufen zu wollen
Die Geschichte der Verwendung von Circleci zum Bau vieler Linux-Räder
So registrieren Sie dieselben Daten mehrmals mit einer Eingabe auf dem Verwaltungsbildschirm von Django
Wie man die Anzahl der GPUs aus Python kennt ~ Hinweise zur Verwendung von Multiprocessing mit pytorch ~
Ich habe versucht, die Entropie des Bildes mit Python zu finden
Memo, um den Wert auf der HTML-Javascript-Seite mit Jupiter zu erhalten
Die Geschichte der Implementierung des Themas Facebook Messenger Bot mit Python
Ich habe versucht, mit TensorFlow den Durchschnitt mehrerer Spalten zu ermitteln
Lesen Sie das Tag, das Ihnen in ec2 mit boto3 zugewiesen wurde
Sakura Die Geschichte, wie die Python-Flasche im Internet funktioniert hat
Die Geschichte der Einführung von Jedi (automatisches Vervollständigungspaket von Python) in Emacs
Lassen Sie uns den Befehl pünktlich mit dem Bot der Zwietracht ausführen
Einstellungen zum Eingeben und Debuggen des Inhalts der Bibliothek mit VS-Code
Die Geschichte eines Rubinisten, der mit Python :: Dict-Daten mit Pycall kämpft
Versuchen Sie, den Betrieb von Netzwerkgeräten mit Python zu automatisieren
Bis zum Start des Django-Tutorials mit Pycharm unter Windows
Eine Geschichte über den Umgang mit dem CORS-Problem
Die Geschichte des Kopierens von Daten von S3 auf Googles TeamDrive
Wenn ich mit matplotlib eine große Anzahl von Diagrammen generiere, möchte ich das Diagramm nicht auf dem Bildschirm anzeigen (Jupyter-Umgebung).
Technologie, die Jupiter unterstützt: Traitlets (Geschichte des Entschlüsselungsversuchs)
Speichern Sie Bilder im Web mit Python (Colab) auf einem Laufwerk.
Die Geschichte, den privaten Schlüssel mit chmod auf 600 zu setzen
Die Geschichte, wie man mit discord.py einen Fragenkasten-Bot erstellt
Rufen Sie den Hostnamen des Host-PCs mit Docker unter Linux ab
Holen Sie sich die Quelle der Seite unbegrenzt mit Python zu laden.
Versuchen Sie, Merkmale von Sensordaten mit CNN zu extrahieren
Ich habe versucht, den Sesam für Eingang 2 mit einem einzigen Druck auf die AWS IoT-Taste zu entsperren
Zwei-Faktor-Authentifizierung mit Cognito + Amplify (Geben Sie zur Authentifizierung ID / PW / "Zwei-Faktor-Code-Wert" auf dem Anmeldebildschirm ein)
Eine Geschichte, in der der Algorithmus zu einem lächerlichen Ergebnis kam, als er versuchte, das Problem der reisenden Verkäufer richtig zu lösen
Die Geschichte des Baus von Zabbix 4.4