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

    如何解析并白嫖xray yml V2 poc

    VSole2022-03-31 07:35:09

    從去年開始 xray的yml poc升級到了v2版本和v1版本相比,執行流程上有了較大變化,以較為簡單的thinkphp5的poc來看

    v1版本

    name: poc-yaml-thinkphp5-controller-rce
    rules:
      - method: GET
        path: /index.php?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=printf&vars[1][]=a29hbHIgaXMg%25%25d2F0Y2hpbmcgeW91
        expression: |
          response.body.bcontains(b"a29hbHIgaXMg%d2F0Y2hpbmcgeW9129")
    
    detail:
      links:
        - https://github.com/vulhub/vulhub/tree/master/thinkphp/5-rce
    

    v2版本

    name: poc-yaml-thinkphp5-controller-rce
    manual: true
    transport: http
    rules:
        r0:
            request:
                cache: true
                method: GET
                path: /index.php?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=printf&vars[1][]=a29hbHIgaXMg%25%25d2F0Y2hpbmcgeW91
            expression: response.body.bcontains(b"a29hbHIgaXMg%d2F0Y2hpbmcgeW9129")
    expression: r0()
    detail:
        links:
            - https://github.com/vulhub/vulhub/tree/master/thinkphp/5-rce
    

    最主要的區別是是新增了transport、expression兩個字段。

    transport的取值范圍為tcp、udp、http,給xray賦予了探測tcp協議的漏洞。

    expression字段改變了v1 poc的執行流程,可利用短路的邏輯來設計執行的流程。

    為了徹底搞明白cel執行yml poc的流程,今天就寫一個最簡單的yml 執行引擎demo,來學習執行的整體流程以及思路。

    xray是使用cel-go來做執行引擎的,所以需要cel-go和golang的基礎

    關于cel語法的demo,可以查看

    https://github.com/google/cel-go/blob/master/examples/README.md
    https://codelabs.developers.google.com/codelabs/cel-go#0

    1.反序列化yml文件

    執行yml文件第一步是要把yml反序列化到golang的結構體,根據poc文件可以提取出如下結構體

    package main
    
    import (
        "gopkg.in/yaml.v2"
        "io/ioutil"
    )
    
    type Poc struct {
        Name       string            `yaml:"name"`
        Transport  string            `yaml:"transport"`
        Set        map[string]string `yaml:"set"`
        Rules      map[string]Rule            `yaml:"rules"`
        Expression string            `yaml:"expression"`
        Detail     Detail            `yaml:"detail"`
    }
    
    type Rule struct {
        Request    RuleRequest `yaml:"request"`
        Expression string      `yaml:"expression"`
    }
    
    type RuleRequest struct {
        Cache  bool   `yaml:"cache"`
        method string `yaml:"method"`
        path   string `yaml:"path"`
        Expression string      `yaml:"expression"`
    }
    
    type Detail struct {
        Links []string `yaml:"links"`
    }
    
    func main() {
        poc := Poc{}
        pocFile, _ := ioutil.ReadFile("poc.yml")
        err := yaml.Unmarshal(pocFile,&poc)
        if err != nil{
            println(err.Error())
        }
        println(pocFile)
    }
    

    符合預期

    2.處理set 全局變量

    盡管這個poc中沒有使用到set這個結構,但是其他poc中大量使用set結構來保存全局變量

    所以需要一個定義一個map來保存變量,而變量的值就是來源于cel-go執行語句,并獲取out,可以定義如下函數

    func execSetExpression(Expression string) (interface{}, error) {
        //定義set 內部函數接口
        setFuncsInterface := cel.Declarations(
            decls.NewFunction("randomInt",
                decls.NewOverload("randomInt_int_int",
                    []*exprpb.Type{decls.Int, decls.Int},
                    decls.String)),
            decls.NewFunction("randomLowercase",
                decls.NewOverload("randomLowercase_string",
                    []*exprpb.Type{decls.Int},
                    decls.String)),
        )
    
        //實現set 內部函數接口
        setFuncsImpl := cel.Functions(
            &functions.Overload{
                Operator: "randomInt_int_int",
                Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
                    randSource := rand.New(rand.NewSource(time.Now().UnixNano()))
                    min := int(lhs.Value().(int64))
                    max := int(rhs.Value().(int64))
                    return types.String(strconv.Itoa(min + randSource.Intn(max-min)))
                }},
            &functions.Overload{
                Operator: "randomLowercase_string",
                Unary: func(lhs ref.Val) ref.Val {
                    n := lhs.Value().(int64)
                    letterBytes := "abcdefghijklmnopqrstuvwxyz"
                    randSource := rand.New(rand.NewSource(time.Now().UnixNano()))
                    const (
                        letterIdxBits = 6                    // 6 bits to represent a letter index
                        letterIdxMask = 1<
                        letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
                    )
                    randBytes := make([]byte, n)
                    for i, cache, remain := n-1, randSource.Int63(), letterIdxMax; i >= 0; {
                        if remain == 0 {
                            cache, remain = randSource.Int63(), letterIdxMax
                        }
                        if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
                            randBytes[i] = letterBytes[idx]
                            i--
                        }
                        cache >>= letterIdxBits
                        remain--
                    }
                    return types.String(randBytes)
                }},
        )
    
        //創建set 執行環境
        env, err := cel.NewEnv(setFuncsInterface)
        if err != nil {
            log.Fatalf("environment creation error: %v", err)
        }
        ast, iss := env.Compile(Expression)
        if iss.Err() != nil {
            log.Fatalln(iss.Err())
            return nil, iss.Err()
        }
        prg, err := env.Program(ast, setFuncsImpl)
        if err != nil {
            return nil, errors.New(fmt.Sprintf("Program creation error: %v", err))
        }
        out, _, err := prg.Eval(map[string]interface{}{})
        if err != nil {
            log.Fatalf("Evaluation error: %v", err)
            return nil, errors.New(fmt.Sprintf("Evaluation error: %v", err))
        }
        return out, nil
    }
    

    進行測試,符合預期


    3.生成request和response

    部分request中會{{rand}}這種格式來使用上一步中生成的全局變量,

    可以定義如下渲染函數


    // 渲染函數 渲染變量到request中
    func render(v string, setMap map[string]interface{}) string {
        for k1, v1 := range setMap {
            _, isMap := v1.(map[string]string)
            if isMap {
                continue
            }
            v1Value := fmt.Sprintf("%v", v1)
            t := "{{" + k1 + "}}"
            if !strings.Contains(v, t) {
                continue
            }
            v = strings.ReplaceAll(v, t, v1Value)
        }
        return v
    }
    

    再看expression字段中response.body.bcontains(b"a29hbHIgaXMg%d2F0Y2hpbmcgeW9129")

    有一個response結構體,抽象成golang代碼,大概如下


    type Response struct {
        Body []byte
    }
    

    但是在cel中是不能直接使用golang的struct的,需要用proto來做一個轉換

    定義如下proto文件


    syntax = "proto3";
    option go_package = "./;structs";
    package structs;
    
    message Response {
      //數據類型 字段名稱 字段id
      bytes body = 1;
    }
    

    通過protoc -I . --go_out=. requests.proto生成go文件

    然后定義如下函數來執行單條rule的表達式,返回值為如bool,來判斷單條rule是否成立

    func execRuleExpression(Expression string, variableMap map[string]interface{}) bool {
       env, _ := cel.NewEnv(
          cel.Container("structs"),
          cel.Types(&structs.Response{}),
          cel.Declarations(
             decls.NewVar("response", decls.NewObjectType("structs.Response")),
             decls.NewFunction("bcontains",
                decls.NewInstanceOverload("bytes_bcontains_bytes",
                   []*exprpb.Type{decls.Bytes, decls.Bytes},
                   decls.Bool)),
          ),
       )
       funcImpl := []cel.ProgramOption{
          cel.Functions(
             &functions.Overload{
                Operator: "bytes_bcontains_bytes",
                Binary: func(lhs ref.Val, rhs ref.Val) ref.Val {
                   v1, ok := lhs.(types.Bytes)
                   if !ok {
                      return types.ValOrErr(lhs, "unexpected type '%v' passed to bcontains", lhs.Type())
                   }
                   v2, ok := rhs.(types.Bytes)
                   if !ok {
                      return types.ValOrErr(rhs, "unexpected type '%v' passed to bcontains", rhs.Type())
                   }
                   return types.Bool(bytes.Contains(v1, v2))
                },
             },
          )}
       ast, iss := env.Compile(Expression)
       if iss.Err() != nil {
          log.Fatalln(iss.Err())
       }
       prg, err := env.Program(ast, funcImpl...)
       if err != nil {
          log.Fatalf("Program creation error: %v", err)
       }
       out, _, err := prg.Eval(variableMap)
       if err != nil {
          log.Fatalf("Evaluation error: %v", err)
       }
       return out.Value().(bool)
    }
    

    然后根據request流程,可以抽象為如下匿名函數,方便最后執行poc中的Expression

    var RequestsInvoke = func(target string, setMap map[string]interface{}, rule Rule) bool {
        var req *http.Request
        var err error
        if rule.Request.Body == "" {
            req, err = http.NewRequest(rule.Request.Method, target+render(rule.Request.Path, setMap), nil)
        } else {
            req, err = http.NewRequest(rule.Request.Method, target+render(rule.Request.Path, setMap), bytes.NewBufferString(render(rule.Request.Body, setMap)))
        }
        if err != nil {
            log.Println(fmt.Sprintf("http request error: %s", err.Error()))
            return false
        }
        resp, err := http.DefaultClient.Do(req)
        if err != nil {
            println(err.Error())
            return false
        }
        response := &structs.Response{}
        response.Body, _ = ioutil.ReadAll(resp.Body)
        return execRuleExpression(rule.Expression, map[string]interface{}{"response": response})
    }
    

    4.執行poc Expression

    將前面生成的request匿名函數,按照rules中的key定義成函數。注入到cel執行環境中,即可實現短路的邏輯,避免無效請求。

    func execPocExpression(target string, setMap map[string]interface{}, Expression string, rules map[string]Rule) bool {   var funcsInterface []*exprpb.Decl   var funcsImpl []*functions.Overload   for key, rule := range rules {      funcName := key      funcRule := rule      funcsInterface = append(funcsInterface, decls.NewFunction(key, decls.NewOverload(key, []*exprpb.Type{}, decls.Bool)))      funcsImpl = append(funcsImpl,         &functions.Overload{            Operator: funcName,            Function: func(values ...ref.Val) ref.Val {               return types.Bool(RequestsInvoke(target, setMap, funcRule))            },         })   }   env, err := cel.NewEnv(cel.Declarations(funcsInterface...))   if err != nil {      log.Fatalf("environment creation error: %v", err)   }   ast, iss := env.Compile(Expression)   if iss.Err() != nil {      log.Fatalln(iss.Err())   }   prg, err := env.Program(ast, cel.Functions(funcsImpl...))   if err != nil {      log.Fatalln(fmt.Sprintf("Program creation error: %v", err))   }   out, _, err := prg.Eval(map[string]interface{}{})   return out.Value().(bool)}
    

    代碼僅為學習使用,為了精簡代碼體量,絕大多數函數和結構體未實現。

    5.測試

    項目代碼全部開源在:

    https://github.com/lanyi1998/yml-poc-demo

    參考項目:

    https://github.com/google/cel-go
    https://github.com/jjf012/gopoc
    https://github.com/WAY29/pocV
    https://docs.xray.cool/#/guide/poc/v2
    stringresponse
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    APP協議分析心得
    2023-07-18 09:23:41
    對脫殼流程有不明白的可參考我之前寫的文章:[原創]ART環境下dex加載流程分析及frida dump dex方案。var magic_Hex = [0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00];var dex_path = "/data/data/" + apk_Name + "/" + dex_size + ".dex";
    從fofa中搜索RDP,會看到它會解析出RDP的信息。本文探索如何自己實現一個。1. Nmap指紋在http
    從去年開始 xray的yml poc升級到了v2版本和v1版本相比,執行流程上有了較大變化,以較為簡單的thinkphp5的poc來看 v1版本 name: poc-yaml-thinkphp5-controller-rce rules: - method: GET path: /index.php?s=/Index/\think\app/invokefunction&functi
    命令行版 HTTP 工具集,自動化檢查網站狀態。
    前段時間Confluence發布了CVE-2021-26085補丁,剛好之前分析過Confluence的漏洞,免去了搭建漏洞分析環境的麻煩,因此分析下這個漏洞。 分析過程 漏洞點定位 這個漏洞爆出來已經有一段時間了,所以已經有公開的POC了
    Spring MVC是一種基于Java的實現了Web MVC設計模式的請求驅動類型的輕量級Web框架,即使用了MVC架構模式的思想,將web層進行職責解耦,基于請求驅動指的就是使用請求-響應模型,框架的目的就是幫助我們簡化開發,Spring Web MVC也是要簡化我們日常Web開發的
    引言 在JavaWeb應用中,任意文件上傳一直是關注的重點,攻擊者通過上傳惡意jsp文件,可以獲取服務器權限。但是在Springboot框架對JSP解析存在一定的限制。 Spring官方原文如下,大概意思是jsp對內嵌的容器的支持不太...
    一款盲目WAF識別工具
    2023-05-19 08:58:46
    一種識別工具,可以基于盲目推理識別Web保護類型。盲推理是通過檢查由一組預定義的攻擊性有效載荷引起的響應來完成的,其中這些有效載荷僅用于觸發介于兩者之間的Web保護系統(例如),目前,它支持80多種不同的保護產品。____ ___ ___ ____ ______ | T T __ __ ____ _____. l j| \ / _]| \ | T| | || T__T T / T| __|. | T | \ / [_ | _ Yl_j l_j| ~ || | | |Y o || l_. | | | D YY _]| | | | | |___ || | | || || _|. j l | || [_ | | | | | | !-h, --help Show this help message and exit. --proxy-file=PRO.. Load HTTP proxy list from a file
    在前天的沙龍上,師傅們積極探討,期間提出了一些關于app抓包的相關問題。在此小小的總結一波有關的分析以及解決辦法。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类