<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    Chunk-Proxy:僅需一條http請求創建的Socks代理隧道

    一顆小胡椒2022-05-10 19:33:26

    簡介

    分塊傳輸編碼(Chunked transfer encoding)是超文本傳輸協議(HTTP)中的一種數據傳輸機制,允許 HTTP 由應用服務器發送給客戶端應用( 通常是網頁瀏覽器)的數據可以分成多個部分。分塊傳輸編碼只在 HTTP 協議 1.1 版本(HTTP/1.1)中提供。

    通常,HTTP 應答消息中發送的數據是整個發送的,Content-Length 消息頭字段表示數據的長度。數據的長度很重要,因為客戶端需要知道哪里是應答消息的結束,以及后續應答消息的開始。然而,使用分塊傳輸編碼,數據分解成一系列數據塊,并以一個或多個塊發送,這樣服務器可以發送數據而不需要預先知道發送內容的總大小。通常數據塊的大小是一致的,但也不總是這種情況。

    通過 Request獲得Socket

    在2020年看先知帖子搞反序列化回顯的時候,發現可以通過request對象獲取到真實的Socket套接字流,獲得真實套接字流之后可以直接做Socks代理。

    測試代碼

    主要是從request.getInputStream() 獲取輸入流,然后讀取到buf。

    獲取Socket的真實輸入流與輸出流

    斷點下到Socket的InputStream類 會斷到org.apache.coyote.http11.InternalInputBuffer類的fill方法,這個類是一個輸入流的包裝類。

    其中最主要的就是它的inputStream變量,它是Socket套接字的輸入流

    通過堆棧回溯我們可以通過request.request.coyoteRequest.inputBuffer.inputStream獲取Socket的輸入流,同時可以看到SocketInputStream類里面有一個socket字段存放著這個輸入流所屬的套接字(Socket)

    request.request.coyoteRequest.inputBuffer.inputStream
    

    獲取到Socket之后我們就可以直接操作Socket的輸入與輸出流做一個Socks代理。

    代碼:

    <%@ page import="java.io.InputStream" %>
    <%@ page import="java.io.OutputStream" %>
    <%@ page import="java.lang.reflect.Field" %>
    <%@ page import="java.util.StringTokenizer" %>
    <%@ page import="java.net.Socket" %>
    <%!
      public static Object getFieldValue(Object obj,String fieldName){
          if (obj!=null){
            Class clazz = obj.getClass();
            while (clazz!=null){
              try {
                Field field = clazz.getDeclaredField(fieldName);
                field.setAccessible(true);
                return field.get(obj);
              } catch (Exception e) {
                  clazz = clazz.getSuperclass();
              }
            }
          }
          return null;
      }
      public static Object getFieldValueEx(Object obj,String fieldName){
        StringTokenizer stringTokenizer = new StringTokenizer(fieldName,"->");
        while (stringTokenizer.hasMoreTokens()){
          String realFieldName = stringTokenizer.nextToken();
          obj = getFieldValue(obj,realFieldName);
        }
        return obj;
      }
    %>
    <%
      Socket socket = (Socket) getFieldValueEx(request,"request->coyoteRequest->inputBuffer->inputStream->socket");
      socket.getOutputStream().write("hacker".getBytes());
      socket.getOutputStream().flush();
      socket.close();
      System.out.println(socket);
    %>
    

    查看流量,我們成功劫持了Socket,并輸出了我們想要的內容。

    現在我們已經控制了Socket可以用來做Socks代理了,不過這種方法只適用于Tomcat,那有沒有更加通用的方法呢?請看下面的內容。

    通用HTTP Chunk Socks代理

    我們繼續查看inputstream.read的調用堆棧 發現是ChunkedInputFilter類調用的SocketInputSteam類的read方法

    我們再來看一下ChunkedInputFilter類,看看它實現了哪些接口。

    發現它實現了InputFilter接口,我們發現它一共有5個子類:

    1. BufferedInputFilter 過濾器 負責讀取和緩沖請求Body的
    2. VoidInputFilter 空的輸入過濾器,比如Body沒有數據或者是請求方法是GET都是這個過濾器 讀取返回空
    3. IdentityInputFilter 過濾器 在請求包含content-length協議頭并且指定的長度大于0時使用
    4. ChunkedInputFilter 過濾器 Http Chunk請求會走這個過濾器讀取 只要客戶端有發數據,就可以一直讀取
    5. ChunkedInputFilter 過濾器 負責在FORM認證后恢復保存的請求時重放請求的正文

    從InputFilter接口的實現類來看,如果要實現一個Socks代理,ChunkedInputFilter是我們唯一的選擇。

    如何讓我們的請求走到ChunkedInputFilter呢?只要添加一個Transfer-Encoding協議頭并且值為chunked即可。

    接下來我們寫一個測試代碼,看看能不能行得通,看一下能否同時讀取并寫出數據呢?

    下面是一個例子,服務端寫出服務端的時間并讀取輸出客戶端發送的時間,客戶端寫出客戶端的時間并讀取輸出服務端發送的時間。

    server jsp

    <%@ page import="java.io.InputStream" %>
    <%@ page import="java.io.OutputStream" %>
    <%@ page import="java.text.DateFormat" %>
    <%@ page import="java.util.Locale" %>
    <%@ page import="java.util.Date" %>
    <%@ page import="java.util.Arrays" %>
    <%
      InputStream inputStream = request.getInputStream();
      response.setHeader("Transfer-Encoding","chunked");//設置響應也是HTTP CHUNK
      response.setBufferSize(1024);
      OutputStream outputStream = response.getOutputStream();
      byte[] buf = new byte[1024];
      for (int i = 0; i < 10; i++) {
        //通過chunk 寫出當前的時間
        String currentTime = DateFormat.getTimeInstance( DateFormat.FULL, Locale.getDefault()).format(new Date());
        currentTime += "\r";
        outputStream.write(currentTime.getBytes());
        outputStream.flush();
        //讀取客戶端發來的時間并輸出
        int read = inputStream.read(buf);
        System.out.println("server read " + new String(Arrays.copyOf(buf,read)));
        Thread.sleep(1000);
      }
      
      outputStream.close();
    %>
    

    client

    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.text.DateFormat;
    import java.util.Arrays;
    import java.util.Date;
    import java.util.Locale;
    public class Main {
        public static void main(String[] args) throws Throwable {
            //創建HTTP連接
            URL url = new URL("http://localhost:8080/chunk/index.jsp");
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            //設置請求方法為POST
            httpURLConnection.setRequestMethod("POST");
            //允許寫出數據
            httpURLConnection.setDoOutput(true);
            //允許讀取數據
            httpURLConnection.setDoInput(true);
            //設置請求body發送方式為chunk
            httpURLConnection.setRequestProperty("Transfer-Encoding","chunked");
            //設置請求body為二進制流
            httpURLConnection.setRequestProperty("Content-Type", "application/octet-stream");
            //設置Chunk的塊大小
            httpURLConnection.setChunkedStreamingMode(1024);
            //發送連接
            httpURLConnection.connect();
            //獲取寫到服務端的輸出流 我們設置了chunk就可以一直向服務端寫數據
            OutputStream outputStream = httpURLConnection.getOutputStream();
            //獲取服務器發送來的數據 服務端設置了chunk就可以一直讀 直到服務端關閉輸出流
            InputStream inputStream = httpURLConnection.getInputStream();
            byte[] buf = new byte[1024];
            for (int i = 0; i < 10; i++) {
                //通過chunk 寫出當前的時間
                String currentTime = DateFormat.getTimeInstance( DateFormat.FULL, Locale.getDefault()).format(new Date());
                currentTime += "\r";
                outputStream.write(currentTime.getBytes());
                outputStream.flush();
                //讀取服務端發來的時間并輸出
                int read = inputStream.read(buf);
                System.out.println("client read " + new String(Arrays.copyOf(buf,read)));
                Thread.sleep(1000);
            }
        }
    }
    

    運行后發現客戶端報錯了,異常消息說輸出流已經被關閉了,但是我們的代碼并沒有關閉輸出流。

    Exception in thread "main" java.io.IOException: Stream is closed
      at sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.checkError(HttpURLConnection.java:3591)
      at sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.write(HttpURLConnection.java:3580)
      at sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.write(HttpURLConnection.java:3575)
      at Main.main(Main.java:39)
    

    我們在類sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream的close方法下一個斷點,看看是誰關閉了我們的輸出流。

    我們發現在我們調用HttpURLConnection類的getInputStream方法時,在getInputStream0方法會關閉我們打開的輸出流,我們要想辦法繞過去不讓JDK關閉我們的輸出流,這里有三種解決方案:

    1. 修改JDK源碼(太費事了)
    2. 通過JavaAgent動態修補類(也太廢事了)
    3. 反射修改類sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream的closed字段設置為flase獲得輸入流之后再設置成true

    綜上所述1和2方法過于繁瑣,所以我們直接采用第三種方法反射修改closed字段的值(在調用類sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream的close方法時,方法會先檢查是否已經關閉如果已經關閉就直接返回)

    修改后的代碼

    import java.io.InputStream;
    import java.io.OutputStream;
    import java.lang.reflect.Field;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.text.DateFormat;
    import java.util.Arrays;
    import java.util.Date;
    import java.util.Locale;
    public class Main {
        public static void main(String[] args) throws Throwable {
            //創建HTTP連接
            URL url = new URL("http://localhost:8080/chunk/index.jsp");
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            //設置請求方法為POST
            httpURLConnection.setRequestMethod("POST");
            //允許寫出數據
            httpURLConnection.setDoOutput(true);
            //允許讀取數據
            httpURLConnection.setDoInput(true);
            //設置請求body發送方式為chunk
            httpURLConnection.setRequestProperty("Transfer-Encoding","chunked");
            //設置請求body為二進制流
            httpURLConnection.setRequestProperty("Content-Type", "application/octet-stream");
            //設置Chunk的塊大小
            httpURLConnection.setChunkedStreamingMode(1024);
            //發送連接
            httpURLConnection.connect();
            //獲取寫到服務端的輸出流 我們設置了chunk就可以一直向服務端寫數據
            OutputStream outputStream = httpURLConnection.getOutputStream();
            //設置輸出流的狀態為關閉
            Field closedField = outputStream.getClass().getDeclaredField("closed");
            closedField.setAccessible(true);
            closedField.set(outputStream,true);
            //獲取服務器發送來的數據 服務端設置了chunk就可以一直讀 直到服務端關閉輸出流
            InputStream inputStream = httpURLConnection.getInputStream();
            //設置輸出流的狀態為開啟
            closedField.set(outputStream,false);
            byte[] buf = new byte[1024];
            for (int i = 0; i < 10; i++) {
                //通過chunk 寫出當前的時間
                String currentTime = DateFormat.getTimeInstance( DateFormat.FULL, Locale.getDefault()).format(new Date());
                currentTime += "\r";
                outputStream.write(currentTime.getBytes());
                outputStream.flush();
                //讀取服務端發來的時間并輸出
                int read = inputStream.read(buf);
                System.out.println("client read " + new String(Arrays.copyOf(buf,read),"gbk"));
                Thread.sleep(1000);
            }
        }
    }
    

    我們可以看到服務端和客戶端都是雙工流輸出(同時讀取并且輸出)

    客戶端成功讀取服務端每隔一秒發送的時間

    服務端成功讀取客戶端每隔一秒發送的時間

    我們來看一下流量 從流量中也可以看出來 不論是服務端還是客戶端都在讀取的同時也在發送,真正的全雙工流(紅色是我們發送給服務端的,藍色是服務端發送給我們的),有了全雙工流我們就可以做Socks代理了。

    通過Http Chunk編寫的Socks代理(僅需一條Http請求)

    在tomcat6-10、weblogic、jetty、樹脂、iis上均已經過測試。這里已經寫好并開源了,大家下載下來就可以使用了。歡迎Star下~

    Github https://github.com/BeichenDream/Chunk-Proxy/releases/tag/jar-v1.10

    usage: java -jar chunk-Proxy.jar type listenPort targetUrl
    type: .net|java
    example: java -jar chunk-Proxy.jar java 1088 http://10.10.10.1:8080/proxy.jsp
    

    http代理socket
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    給木馬帶雙眼睛
    2023-04-18 09:56:25
    近月,內存馬的技術也產生新的變化,如利用websocket進行通信,Executor內存馬進行socket通信。本文介紹利用Poller內存馬實現全流量監控,這樣,攻擊方可以實時監控經過系統的每一個請求,或者增加了釣魚等信息利用的便利。這也就是說注入Poller的內存馬一定是不能出任何bug的,一旦出了,整個服務直接崩潰。反向,Executor是一個任務類,創建后就執行一個線程任務,如果這次業務異常,最多這次的請求無法正常執行罷了。
    從目標接收到的每個數據都將打包到HTTP POST請求的Body中,其中的URL將包含“SERVER_RESPONSE”。隨后,這些請求都將被發送到本地HTTP攔截服務器。修改數據包的另一種方法就是使用一個Python腳本,HTTP攔截服務器在接收消息時將運行該腳本。在所有修改操作完成之后,攔截服務器還將作為HTTP響應Body進行回顯。
    云函數簡介 云函數是騰訊云為企業和開發者們提供的無服務器執行環境,可以無需購買和管理服務器的情況下運行代碼。只需使用平臺支持的語言編寫核心代碼并設置代碼運行的條件,即可在騰訊云基礎設施上彈性、安全地運行代碼。SCF是實時文件處理和數據處理等場景下理想的計算平臺。服務端配置云函數基礎配置選擇自定義創建,地域自選,部署模式,代碼部署,運行環境Python3.6,其余默認即可。
    內網滲透合集(三)
    2023-01-28 09:44:16
    jsp端口轉發滲透過程中,由于windows和linux的差別以及運行語言環境的限制導致端口轉發經常出現問題。于是自己寫了個簡單的JSP的端口轉發腳本。仿造 LCX的功能,具有正向、反向、監聽三種模式。對于目前數量眾多的JAVA WEB網站來說,可以比較方便的實現端口轉發。在這里發布出來,小伙伴們使用過程中,如果發現什么bug歡迎提交哈~參數說明/KPortTran.jsp?lip = local ip / 本地ip //一般為內網主機IP. lp = local port / 本地端口 //一般為內網主機端口
    內網滲透-代理
    2021-12-01 05:44:01
    利用代理工具將內網的流量代理到本地進行訪問,這樣就可以對內網進行下一步滲透,同時也可以利用代理工具將其他網段的流量轉發到本地進行縱向滲透。代理的本質是Socks協議(防火墻安全會話轉換協議),工作在OSI參考模型的第5層(會話層)。使用TCP協議傳輸數據,因而不提供如傳遞ICMP信息之類的網絡層相關服務。目前支持SOCKS4和SOCKS5兩個版本:
    腳本運行機制在使用該腳本的過程中,用戶僅需要加載MoveKit.cna腳本即可,它將加載所有其他的所需腳本。除此之外,用戶可能還需要對代碼進行編譯,并存放至Assemblies目錄中,具體取決于SharpMove和SharpRDP程序集所要采取的行為。首先,用戶需要選擇一個在遠程系統上執行的命令,命令將通過WMI、DCOM、計劃任務、RDP或SCM執行。然后,使用File方法將文件存儲至目標系統并執行它。在使用信標命令時,它將讀取默認配置,并使用幾個命令行參數。
    CobaltStrike被廣泛利用于滲透攻擊中,可以與其他攻擊工具(如Mimikatz、Metasploit和PowerShell Empire)聯合使用,支持在網絡中橫向移動。
    2023年,浪潮云威脅情報中心持續對境內的APT團伙進行追蹤。發現包括代號為“OldFox”的團伙持久性攻擊。由于該團伙隱匿在高緯度的安全對抗空間中,因此,我們稱這種模式為“量子陰謀“。
    一. 應用層隧道技術1. ssh隧道建立雙向安全隧道將其他TCP端口的通信通過SSH連接轉發用SSH作為傳輸層協議,對流量自動加解密突破防火墻訪問規則的限制SSH本地端口轉發本機偵聽端口
    一顆小胡椒
    暫無描述
      亚洲 欧美 自拍 唯美 另类