[Tutoriel] Cacher un service derrière un autre avec LD_PRELOAD
|
05-04-2016, 12h08
(Modification du message : 05-04-2016, 15h02 par ark.)
Message : #1
|
|
b0fh
Membre actif Messages : 210 Sujets : 17 Points: 309 Inscription : Jul 2012 |
[Tutoriel] Cacher un service derrière un autre avec LD_PRELOAD
Bonjour,
Découvrons ensemble un petit gadget très pratique qui vous permettra, sous Linux, de dissimuler facilement (qui à dit backdoor ?) un service réseau derrière un autre, sans avoir à modifier du code existant, et sans faire de saletés avec iptables. Spécifications Le scénario typique est le suivant: vous êtes dans une entreprise/école/assoce/cybercafé fasciste qui interdit le traffic sortant vers tous les ports sauf le 80. Vous avez un serveur à disposition, mais vous ne voulez pas dédier le port 80 à SSH, car vous voulez garder votre serveur web existant. Il serait bien pratique d'avoir un gadget pour multiplexer les deux services sur le même port. SSH comme HTTP ont un point en commun: le client envoie un message dès que la connexion est ouverte. Dans le cas de ssh2, c'est un banner qui commence par "SSH-2.0-<version du client>", alors que dans le cas de HTTP c'est une requête comme "GET / HTTP/1.1". La taille minimum d'une requête HTTP, comme illustré, est donc de 16 bytes en HTTP 1.0, 22 bytes en HTTP 1.1. Il faudra décider en moins que ça quel protocole utiliser, pour éviter les I/O asynchrones, et le préfixe "SSH-2.0-" sera donc suffisant. Dans les autres cas, nous souhaitons que par défaut, notre port se comporte comme un serveur HTTP (et donc renvoie l'erreur pertinente), et ne se comporte comme un serveur SSH que lorsqu'il est face à un client SSH. Un serveur SSH doit tourner en root, pour pouvoir ensuite prendre l'identité de l'utilisateur qui se connecte. Mais faire tourner un serveur HTTP en root sera généralement une mauvaise idée. Pour contourner ce problème, en cas de connexion SSH, nous allons simplement rediriger le traffic vers le port SSH local, ce qui ne demande pas de privilèges particuliers, et laisser le sshd système s'en occuper. Pour ce faire, nous allons simplement exécuter netcat. Architecture Pour intercepter les connexions entrantes d'un processus, sans discrimination de protocole, nous allons intercepter l'appel systeme accept(). Pour mémoire, après avoir créé un socket, attaché a une addresse et un port locaux avec bind(), puis l'avoir placé en mode écoute avec listen(), un serveur doit appeler accept() en boucle. Cet appel est bloquant, jusqu'a ce qu'une nouvelle connexion arrive; accept() retourne alors un descripteur vers le socket spécifique a la connexion. Sur un Linux moderne, Le symbole accept() est fourni par la libc, qui est liée dynamiquement. Nous allons utiliser le mécanisme LD_PRELOAD, décrit par mon estimé collègue ark dans un autre tuto, pour remplacer accept() par une autre version qui inclura notre fonctionnalité magique. Le travail de notre remplacement à accept() sera donc d'appeler l'accept() original, puis de décider si la connexion doit être gérée de manière normale (auquel cas on passera la main au programme hôte comme si rien ne s'était passé), ou de manière alternative (auquel cas on exécutera un handler alternatif, sans informer l'hôte de l'existence de cette connexion). Le handler utilisera une interface similaire à celle utilisée par inetd, c'est-à-dire que le socket lui sera présenté sur stdin/stdout. Cette interface est utilisable avec le mode -i de sshd (si le programme hôte tourne en root), ou simplement avec netcat pour rediriger la connexion vers un autre port. C'est ce qui est fait ci-dessous. Implémentation Je vous laisse maintenant découvrir le code commenté pour l'occasion: Code C :
Utilisation On compile en objet partagé. L'option PIC est nécessaire comme l'addresse de chargement d'une lib peut changer. On linke avec la libdl, nécessaire pour intéragir avec le linker dyamique: Code : $> gcc -Wall -shared -fPIC -o magic.so magic.c -ldl Lançons maintenant un serveur arbitraire, muni de notre greffon: Code : $> LD_PRELOAD=./magic.so python -m SimpleHTTPServer Ce serveur fonctionne comme un serveur http normal: Code : $> curl http://localhost:8000 >/dev/null Et la requête s'affiche dans le log serveur: Code : 127.0.0.1 - - [05/Apr/2016 12:03:43] "GET / HTTP/1.1" 200 - En revanche, si j'essaie avec SSH: Code : $> ssh -p 8000 localhost Et rien dans le log du serveur :) |
|
05-04-2016, 14h56
Message : #2
|
|
fr0g
NTEuNDI2MzcsLTEuNzc4NDg4 Messages : 348 Sujets : 22 Points: 56 Inscription : Aug 2011 |
RE: [Tutoriel] Cacher un service derrière un autre avec LD_PRELOAD
Pas bête, j'ai pas mal joué avec ld_preload et j'avais jamais pensé à ça
merci pour le trick |
|
06-04-2016, 09h52
Message : #3
|
|
thxer
:(){ :|:& };: Messages : 382 Sujets : 60 Points: 162 Inscription : Feb 2013 |
RE: [Tutoriel] Cacher un service derrière un autre avec LD_PRELOAD
Vraiment top ! Merci pour le partage et les explications !
|
|
30-11-2016, 00h06
Message : #4
|
|
ZeR0-@bSoLu
Angel Of Byte Messages : 43 Sujets : 2 Points: 4 Inscription : Feb 2016 |
RE: [Tutoriel] Cacher un service derrière un autre avec LD_PRELOAD
J'aime beaucoup , le petit tricks qui permet de belles choses bien joué
|
|
« Sujet précédent | Sujet suivant »
|
Sujets apparemment similaires… | |||||
Sujet | Auteur | Réponses | Affichages | Dernier message | |
Introduction a LD_PRELOAD | ark | 10 | 3,436 |
28-06-2012, 13h42 Dernier message: ark |
Utilisateur(s) parcourant ce sujet : 4 visiteur(s)