diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100755 index 0000000..69d9543 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,37 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + target-branch: "dev" + commit-message: + prefix: "chore" + include: "scope" + + # Maintain dependencies for go modules + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + target-branch: "dev" + commit-message: + prefix: "chore" + include: "scope" + + # Maintain dependencies for docker + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "weekly" + target-branch: "dev" + commit-message: + prefix: "chore" + include: "scope" \ No newline at end of file diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml new file mode 100755 index 0000000..07c4e77 --- /dev/null +++ b/.github/workflows/build-test.yml @@ -0,0 +1,21 @@ +name: Build +on: + pull_request: + workflow_dispatch: + +jobs: + build: + name: Test Builds + runs-on: ubuntu-latest + steps: + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.18 + + - name: Check out code + uses: actions/checkout@v3 + + - name: Build + run: go build . + working-directory: cmd/crack/ \ No newline at end of file diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100755 index 0000000..8da69a8 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,38 @@ +name: CodeQL + +on: + workflow_dispatch: + pull_request: + branches: + - dev + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'go' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 \ No newline at end of file diff --git a/.github/workflows/lint-test.yml b/.github/workflows/lint-test.yml new file mode 100755 index 0000000..1309c28 --- /dev/null +++ b/.github/workflows/lint-test.yml @@ -0,0 +1,19 @@ +name: Lint +on: + push: + pull_request: + workflow_dispatch: + +jobs: + lint: + name: Lint Test + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v3 + - name: Run golangci-lint + uses: golangci/golangci-lint-action@v3.2.0 + with: + version: latest + args: --timeout 5m + working-directory: . \ No newline at end of file diff --git a/.github/workflows/release-binary.yml b/.github/workflows/release-binary.yml new file mode 100755 index 0000000..a029d6a --- /dev/null +++ b/.github/workflows/release-binary.yml @@ -0,0 +1,31 @@ +name: Release +on: + create: + tags: + - v* + workflow_dispatch: + +jobs: + release: + runs-on: ubuntu-latest + steps: + - + name: "Check out code" + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - + name: "Set up Go" + uses: actions/setup-go@v3 + with: + go-version: 1.18 + - + env: + GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + name: "Create release on GitHub" + uses: goreleaser/goreleaser-action@v3 + with: + distribution: goreleaser + version: latest + args: "release --rm-dist" + workdir: . \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..79a9306 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.idea/ +.DS_Store +dist/ +bin/ +cmd/crack/crack +cmd/crack/crack.txt \ No newline at end of file diff --git a/.goreleaser.yml b/.goreleaser.yml new file mode 100755 index 0000000..2ded1af --- /dev/null +++ b/.goreleaser.yml @@ -0,0 +1,42 @@ +before: + hooks: + - go mod tidy + - go generate ./... + +builds: +- env: + - CGO_ENABLED=0 + goos: + - linux + - windows + - darwin + goarch: + - amd64 + - arm64 + - arm + - "386" + goarm: + - "6" + - "7" + flags: + - -trimpath + ldflags: + - -s -w + ignore: + - goos: windows + goarch: arm64 + - goos: windows + goarch: arm + - goos: linux + goarch: mips64 + + binary: '{{ .ProjectName }}' + main: cmd/crack/crack.go + +archives: +- format: zip + replacements: + darwin: macOS + +checksum: + algorithm: sha256 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1912db0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM golang:1.18.4-alpine as builder +RUN apk add --no-cache make git +WORKDIR /crack-src +COPY . /crack-src +RUN go mod download && \ + make docker && \ + mv ./bin/crack-docker /crack + +FROM alpine:latest +COPY --from=builder /crack / + +ENTRYPOINT ["/crack"] \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..32740dc --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright © 2020-2022 zu1k i@zu1k.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8988a41 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +NAME=crack +BUILDPATH=cmd/crack/crack.go +BINDIR=bin +VERSION=$(shell git describe --tags || echo "unknown version") +GOBUILD=CGO_ENABLED=0 go build -trimpath -ldflags '-w -s' + +docker: + $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ $(BUILDPATH) + +sha256sum: + cd $(BINDIR); for file in *; do sha256sum $$file > $$file.sha256; done + +clean: + rm $(BINDIR)/* \ No newline at end of file diff --git a/README.md b/README.md index 3fccbb0..754e595 100644 --- a/README.md +++ b/README.md @@ -1,142 +1,92 @@ -### 声明 - -仅限用于技术研究和获得正式授权的测试活动。 - -### 项目说明 - -我过去内网渗透中弱口令爆破一般使用超级弱口令(shack2),但是存在部分问题。一是只支持windows系统+图形化界面,这就意味着要走代理或者 3389 连接上去使用;二是每次爆破都需要选择协议、ip 列表、字典文件,略显麻烦。 - -然后正好过年的时候看了《白帽子安全开发实战》,发现 go 语言真香,速度快+跨平台编译十分方便,因此花了点时间开发这个项目。 - -项目大致思路:只需要将端口扫描的结果放入 input.txt,即可启动go-crack,会根据端口对应默认服务,并加载对应服务的爆破字典进行爆破。 - -### 使用介绍 - -![](images/008i3skNly1gpuu4bn73tj312u0qona7-20210424150635645.jpg) - -- 目前支持的类型(即端口对应的默认服务) - -弱口令 - -``` - 21: "ftp", - 22: "ssh", - 135: "wmi", - 161: "snmp", - 445: "smb", - 1433: "mssql", - //1521: "oracle", - 3306: "mysql", - 3389: "rdp", - 5432: "postgresql", - 5985: "winrm", - 6379: "redis", - 27017: "mongodb", -``` - -漏洞(445 端口) - -``` - MS17-010 - CVE-2020-0796 -``` - -未授权 - -``` - 9200: "elasticsearch", - 11211: "memcached", -``` - -web - -``` - tomcat - phpmyadmin -``` - -- 并发数 - -启动时我们需要控制的唯一参数就是并发数,`-n`指定即可,不指定的话默认为 10。 - -- 输入文件 - -固定输入文件名为:input.txt,每一行的格式为`ip:port`或者`ip:port|porotocol`,后面那种主要是针对修改了默认端口的服务。 - -135 端口默认对应 wmi 爆破,如果要 hash 爆破的话请指定porotocol 为 wmihash。 - -445 端口自动会检查 MS-17010和CVE-2020-0796。 - -tomcat和 phpmyadmin 必须指定模块,如`127.0.0.1:8080|tomcat`。 - -- 输出文件 - -固定输出文件名为:output.txt。 - -- 字典 - -字典放在/dict 下,根据爆破的服务加载对应的字典,可以自行根据实际情况更新字典。 - -### 使用演示 - -执行 +

+ crack +

+ +

常见服务弱口令爆破工具

+ +

+ + + + + + + + Github Actions + + + + + + + +

+ + +## 功能 + +- 支持常见服务口令爆破(未授权检测) + - ftp + - ssh + - wmi + - wmihash + - smb + - mssql + - oracle + - mysql + - rdp + - postgres + - redis + - memcached + - mongodb +- 多线程爆破,支持进度条 +- 全部插件测试用例([pkg/crack/plugins/plugins_test.go](https://github.com/niudaii/crack/blob/main/pkg/crack/plugins/plugins_test.go)) +- API调用,可参考([internal/runner/runner.go](https://github.com/niudaii/crack/blob/main/internal/runner/runner.go)) + +## 使用 ``` -./go-crack_darwin_amd64 go-crack -./go-crack_darwin_amd64 go-crack -n 15 +➜ crack ./crack -h +Service cracker + +Usage: + ./crack [flags] + +Flags: +INPUT: + -i, -input string crack service input(example: -i '127.0.0.1:3306', -i '127.0.0.1:3307|mysql') + -f, -input-file string crack services file(example: -f 'xxx.txt') + -m, -module string choose one module to crack(ftp,ssh,wmi,mssql,oracle,mysql,rdp,postgres,redis,memcached,mongodb) (default "all") + -user string user(example: -user 'admin,root') + -pass string pass(example: -pass 'admin,root') + -user-file string user file(example: -user-file 'user.txt') + -pass-file string pass file(example: -pass-file 'pass.txt') + +CONFIG: + -threads int number of threads (default 1) + -timeout int timeout in seconds (default 10) + -delay int delay between requests in seconds (0 to disable) + -crack-all crack all user:pass + +OUTPUT: + -o, -output string output file to write found results (default "crack.txt") + -nc, -no-color disable colors in output + +DEBUG: + -silent show only results in output + -debug show debug output ``` -![](images/008i3skNly1gpuu2jwqsxj318c0u0npd.jpg) - -可以看到除了弱口令之外,扫描出可能存在 MS-17010,可以进一步确认。 - -### 后续计划 +## 截图 -- [x] rdp、oracle 协议爆破。 -- [x] tomcat、weblogic 等web 弱口令爆破。 -- [ ] 加入端口扫描+指纹识别(那么只需要输入 IP 即可一键大保健)。 +![image-20220903092817097](https://nnotes.oss-cn-hangzhou.aliyuncs.com/notes/image-20220903092817097.png) -### 更新记录 +## 说明 -2021.04.20 +已经停止更新,该项目作为 [zpscan](https://github.com/niudaii/zpscan) 的模块之一,后续更新参考 zpscan。 -- 第一版。 - -2021.04.24 - -- 增加了 wmi爆破和 wmihash 爆破模块。 - -2021.04.30 - -- mac实现 RDP、oracle,但是 oracle 多次爆破会锁定账户,因此移除。(windows 和 linux 看情况加,反正也没人 star🐶,建议下载`Release V1.1`因为支持多平台)。 -- 增加了 tomcat 和 phpmyadmin爆破,weblogic 多次爆破会锁定账户,因此移除。(ps,`cve-2020-14882`)。 -- 更新了一波大字典,也能在几分钟内完成。 - -2021.05.15 - -- 之前确实测试的较少,根据最近实战中遇到的一些问题,增加了一些可选参数 - - ``` - -m "mssql" 指定要爆破的协议模块,可指定多个,比如 -m "mssql,mysql" - -u "diyuser.txt" 加载自定义用户名字典,这时不加载爆破的服务对应的用户名字典,仍加载对应的密码字典 - -p "diypass.txt" 加载自定义密码字典,密码字典支持{user}格式,自动替换为当前爆破任务的用户名,比如{user}@2020,用户名为 admin时变为 admin@2020 - -i "input.txt" 输入文件 - -o "output.txt" 输出文件,默认为时间戳 - ``` - -- 修改字典 - -### 参考链接 +## 参考 https://github.com/netxfly/x-crack -https://github.com/k8gege/LadonGo - -https://github.com/shadow1ng/fscan - -https://github.com/zsdevX/DarkEye - ---- - -喜欢的话给个Star吧,希望你不要不识抬举🐶。 - +https://github.com/shadow1ng/fscan \ No newline at end of file diff --git a/cmd/crack/crack.go b/cmd/crack/crack.go new file mode 100644 index 0000000..d1c2d2f --- /dev/null +++ b/cmd/crack/crack.go @@ -0,0 +1,22 @@ +package main + +import ( + "github.com/niudaii/crack/internal/runner" + "github.com/projectdiscovery/gologger" + "time" +) + +func main() { + options := runner.ParseOptions() + + start := time.Now() + gologger.Info().Msgf("当前时间: %v", start.Format("2006-01-02 15:04:05")) + + newRunner, err := runner.NewRunner(options) + if err != nil { + gologger.Fatal().Msgf("Could not create runner: %v", err) + } + newRunner.Run() + + gologger.Info().Msgf("运行时间: %v", time.Since(start)) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..00b2896 --- /dev/null +++ b/go.mod @@ -0,0 +1,55 @@ +module github.com/niudaii/crack + +go 1.18 + +require ( + github.com/C-Sto/goWMIExec v0.0.1-deva + github.com/cheggaaa/pb/v3 v3.1.0 + github.com/denisenkom/go-mssqldb v0.12.2 + github.com/go-redis/redis v6.15.9+incompatible + github.com/go-sql-driver/mysql v1.6.0 + github.com/jlaffaye/ftp v0.0.0-20220829015825-b85cf1edccd4 + github.com/lib/pq v1.10.6 + github.com/projectdiscovery/goflags v0.0.9 + github.com/projectdiscovery/gologger v1.1.4 + github.com/sijms/go-ora/v2 v2.5.3 + github.com/stacktitan/smb v0.0.0-20190531122847-da9a425dceb8 + github.com/tomatome/grdp v0.0.0-20220713105348-9917c8b96a4f + go.uber.org/zap v1.23.0 + golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 + golang.org/x/text v0.3.7 + gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 +) + +require ( + github.com/VividCortex/ewma v1.1.1 // indirect + github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 // indirect + github.com/fatih/color v1.10.0 // indirect + github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect + github.com/golang-sql/sqlexp v0.1.0 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/huin/asn1ber v0.0.0-20120622192748-af09f62e6358 // indirect + github.com/icodeface/tls v0.0.0-20190904083142-17aec93c60e5 // indirect + github.com/json-iterator/go v1.1.10 // indirect + github.com/karrick/godirwalk v1.16.1 // indirect + github.com/logrusorgru/aurora v2.0.3+incompatible // indirect + github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect + github.com/mattn/go-colorable v0.1.8 // indirect + github.com/mattn/go-isatty v0.0.12 // indirect + github.com/mattn/go-runewidth v0.0.12 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/onsi/ginkgo v1.16.5 // indirect + github.com/onsi/gomega v1.20.2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/projectdiscovery/fileutil v0.0.0-20210928100737-cab279c5d4b5 // indirect + github.com/projectdiscovery/stringsutil v0.0.0-20210804142656-fd3c28dbaafe // indirect + github.com/rivo/uniseg v0.2.0 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace github.com/tomatome/grdp v0.0.0-20220713105348-9917c8b96a4f => github.com/shadow1ng/grdp v1.0.3 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..1771dc5 --- /dev/null +++ b/go.sum @@ -0,0 +1,491 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/C-Sto/goWMIExec v0.0.1-deva h1:z78Hr/s/JvCv7U9kbNqUI63B5g0oix/iD0YBBLuej1Y= +github.com/C-Sto/goWMIExec v0.0.1-deva/go.mod h1:p7KNiMhZQzgHl0wRxuxQvsxraevlQaznbrgW2o8EXbc= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM= +github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cheggaaa/pb/v3 v3.1.0 h1:3uouEsl32RL7gTiQsuaXD4Bzbfl5tGztXGUvXbs4O04= +github.com/cheggaaa/pb/v3 v3.1.0/go.mod h1:YjrevcBqadFDaGQKRdmZxTY42pXEqda48Ea3lt0K/BE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08 h1:ox2F0PSMlrAAiAdknSRMDrAr8mfxPCfSZolH+/qQnyQ= +github.com/cnf/structhash v0.0.0-20201127153200-e1b16c1ebc08/go.mod h1:pCxVEbcm3AMg7ejXyorUXi6HQCzOIBf7zEDVPtw0/U4= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/denisenkom/go-mssqldb v0.12.2 h1:1OcPn5GBIobjWNd+8yjfHNIaFX14B1pWI3F9HZy5KXw= +github.com/denisenkom/go-mssqldb v0.12.2/go.mod h1:lnIw1mZukFRZDJYQ0Pb833QS2IaC3l5HkEfra2LJ+sk= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= +github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-gl/gl v0.0.0-20181026044259-55b76b7df9d2/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= +github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= +github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= +github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/gomodule/redigo v1.8.4/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gxui v0.0.0-20151028112939-f85e0a97b3a4/go.mod h1:Pw1H1OjSNHiqeuxAduB1BKYXIwFtsyrY47nEqSgEiCM= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googollee/go-socket.io v1.6.0/go.mod h1:0vGP8/dXR9SZUMMD4+xxaGo/lohOw3YWMh2WRiWeKxg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20210621113107-84c6004145de/go.mod h1:MtKwTfDNYAP5EtbQSMYjTSqvj1aXJKQRASWq3bwaP+g= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/goxjs/gl v0.0.0-20210104184919-e3fafc6f8f2a/go.mod h1:dy/f2gjY09hwVfIyATps4G2ai7/hLwLkc5TrPqONuXY= +github.com/goxjs/glfw v0.0.0-20191126052801-d2efb5f20838/go.mod h1:oS8P8gVOT4ywTcjV6wZlOU4GuVFQ8F5328KY3MJ79CY= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huin/asn1ber v0.0.0-20120622192748-af09f62e6358 h1:hVXNJ57IHkOA8FBq80UG263MEBwNUMfS9c82J2QE5UQ= +github.com/huin/asn1ber v0.0.0-20120622192748-af09f62e6358/go.mod h1:qBE210J2T9uLXRB3GNc73SvZACDEFAmDCOlDkV47zbY= +github.com/icodeface/tls v0.0.0-20190904083142-17aec93c60e5 h1:ZcsPFW8UgACapqjcrBJx0PuyT4ppArO5VFn0vgnkvmc= +github.com/icodeface/tls v0.0.0-20190904083142-17aec93c60e5/go.mod h1:VJNHW2GxCtQP/IQtXykBIPBV8maPJ/dHWirVTwm9GwY= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jlaffaye/ftp v0.0.0-20220829015825-b85cf1edccd4 h1:8bWaY08VCoFn17gezYWKLhCwAJr2Er8tUOZCvDVshos= +github.com/jlaffaye/ftp v0.0.0-20220829015825-b85cf1edccd4/go.mod h1:hhq4G4crv+nW2qXtNYcuzLeOudG92Ps37HEKeg2e3lE= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= +github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs= +github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= +github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= +github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc= +github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.12 h1:Y41i/hVW3Pgwr8gV+J23B9YEY0zxjptBuCWEaxmAOow= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.20.2 h1:8uQq0zMgLEfa0vRrrBgaJF2gyW9Da9BmfGV+OyUzfkY= +github.com/onsi/gomega v1.20.2/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/projectdiscovery/fileutil v0.0.0-20210928100737-cab279c5d4b5 h1:2dbm7UhrAKnccZttr78CAmG768sSCd+MBn4ayLVDeqA= +github.com/projectdiscovery/fileutil v0.0.0-20210928100737-cab279c5d4b5/go.mod h1:U+QCpQnX8o2N2w0VUGyAzjM3yBAe4BKedVElxiImsx0= +github.com/projectdiscovery/goflags v0.0.9 h1:bPsYIPE1LvdgYaM3XNX0YmS68e6huv22W22rKh5IscI= +github.com/projectdiscovery/goflags v0.0.9/go.mod h1:t/dEhv2VDOzayugXZCkbkX8n+pPeVmRD+WgQRSgReeI= +github.com/projectdiscovery/gologger v1.1.4 h1:qWxGUq7ukHWT849uGPkagPKF3yBPYAsTtMKunQ8O2VI= +github.com/projectdiscovery/gologger v1.1.4/go.mod h1:Bhb6Bdx2PV1nMaFLoXNBmHIU85iROS9y1tBuv7T5pMY= +github.com/projectdiscovery/stringsutil v0.0.0-20210804142656-fd3c28dbaafe h1:tQTgf5XLBgZbkJDPtnV3SfdP9tzz5ZWeDBwv8WhnH9Q= +github.com/projectdiscovery/stringsutil v0.0.0-20210804142656-fd3c28dbaafe/go.mod h1:oTRc18WBv9t6BpaN9XBY+QmG28PUpsyDzRht56Qf49I= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shadow1ng/grdp v1.0.3 h1:d29xgHDK4aa3ljm/e/yThdJxygf26zJyRPBunrWT65k= +github.com/shadow1ng/grdp v1.0.3/go.mod h1:3ZMSLWUvPOwoRr6IwpAQCzKbLEZqT80sbyxxe6YgcTg= +github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= +github.com/sijms/go-ora/v2 v2.5.3 h1:klGKmhqRONVTtIzTdfYTvrW94kdJkdmZl93u2A3vchI= +github.com/sijms/go-ora/v2 v2.5.3/go.mod h1:EHxlY6x7y9HAsdfumurRfTd+v8NrEOTR3Xl4FWlH6xk= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/stacktitan/smb v0.0.0-20190531122847-da9a425dceb8 h1:GVFkBBJAEO3CpzIYcDDBdpUObzKwVW9okNWcLYL/nnU= +github.com/stacktitan/smb v0.0.0-20190531122847-da9a425dceb8/go.mod h1:phLSETqH/UJsBtwDVBxSfJKwwkbJcGyy2Q/h4k+bmww= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tfriedel6/canvas v0.12.1/go.mod h1:WIe1YgsQiKA1awmU6tSs8e5DkceDHC5MHgV5vQQZr/0= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/veandco/go-sdl2 v0.4.0/go.mod h1:FB+kTpX9YTE+urhYiClnRzpOXbiWgaU3+5F2AB78DPg= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= +go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20181026062114-a27dd33d354d/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/js/dom v0.0.0-20200509013220-d4405f7ab4d8/go.mod h1:sUMDUKNB2ZcVjt92UnLy3cdGs+wDAcrPdV3JP6sVgA4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/images/008i3skNly1gpuu2jwqsxj318c0u0npd.jpg b/images/008i3skNly1gpuu2jwqsxj318c0u0npd.jpg deleted file mode 100644 index 87131d7..0000000 Binary files a/images/008i3skNly1gpuu2jwqsxj318c0u0npd.jpg and /dev/null differ diff --git a/images/008i3skNly1gpuu4bn73tj312u0qona7-20210424150635645.jpg b/images/008i3skNly1gpuu4bn73tj312u0qona7-20210424150635645.jpg deleted file mode 100644 index 7012a99..0000000 Binary files a/images/008i3skNly1gpuu4bn73tj312u0qona7-20210424150635645.jpg and /dev/null differ diff --git a/images/image-20210420171457750.png b/images/image-20210420171457750.png deleted file mode 100644 index c0c231f..0000000 Binary files a/images/image-20210420171457750.png and /dev/null differ diff --git a/internal/runner/banner.go b/internal/runner/banner.go new file mode 100644 index 0000000..5dd97b9 --- /dev/null +++ b/internal/runner/banner.go @@ -0,0 +1,19 @@ +package runner + +import "github.com/projectdiscovery/gologger" + +const Banner = ` + __ + ______________ ______/ /__ + / ___/ ___/ __ / ___/ //_/ +/ /__/ / / /_/ / /__/ / \ +\___/_/ \__,_/\___/_/|_| + + ` + Version + ` by zp857 +` + +const Version = `v2.1` + +func showBanner() { + gologger.Print().Msgf("%v\n", Banner) +} diff --git a/internal/runner/options.go b/internal/runner/options.go new file mode 100644 index 0000000..1dbf992 --- /dev/null +++ b/internal/runner/options.go @@ -0,0 +1,168 @@ +package runner + +import ( + "encoding/json" + "fmt" + "github.com/niudaii/crack/internal/utils" + "github.com/projectdiscovery/goflags" + "github.com/projectdiscovery/gologger" + "github.com/projectdiscovery/gologger/formatter" + "github.com/projectdiscovery/gologger/levels" + "strings" +) + +type Options struct { + // input + Input string + InputFile string + Module string + User string + Pass string + UserFile string + PassFile string + // config + Threads int + Timeout int + Delay int + CrackAll bool + // output + OutputFile string + NoColor bool + // debug + Silent bool + Debug bool + + Targets []string + UserDict []string + PassDict []string +} + +func ParseOptions() *Options { + options := &Options{} + + flagSet := goflags.NewFlagSet() + flagSet.SetDescription(`Service cracker`) + + flagSet.CreateGroup("input", "Input", + flagSet.StringVarP(&options.Input, "input", "i", "", "crack service input(example: -i '127.0.0.1:3306', -i '127.0.0.1:3307|mysql')"), + flagSet.StringVarP(&options.InputFile, "input-file", "f", "", "crack services file(example: -f 'xxx.txt')"), + flagSet.StringVarP(&options.Module, "module", "m", "all", "choose one module to crack(ftp,ssh,wmi,mssql,oracle,mysql,rdp,postgres,redis,memcached,mongodb)"), + flagSet.StringVar(&options.User, "user", "", "user(example: -user 'admin,root')"), + flagSet.StringVar(&options.Pass, "pass", "", "pass(example: -pass 'admin,root')"), + flagSet.StringVar(&options.UserFile, "user-file", "", "user file(example: -user-file 'user.txt')"), + flagSet.StringVar(&options.PassFile, "pass-file", "", "pass file(example: -pass-file 'pass.txt')"), + ) + + flagSet.CreateGroup("config", "Config", + flagSet.IntVar(&options.Threads, "threads", 1, "number of threads"), + flagSet.IntVar(&options.Timeout, "timeout", 10, "timeout in seconds"), + flagSet.IntVar(&options.Delay, "delay", 0, "delay between requests in seconds (0 to disable)"), + flagSet.BoolVarP(&options.CrackAll, "crack-all", "", false, "crack all user:pass"), + ) + + flagSet.CreateGroup("output", "Output", + flagSet.StringVarP(&options.OutputFile, "output", "o", "crack.txt", "output file to write found results"), + flagSet.BoolVarP(&options.NoColor, "no-color", "nc", false, "disable colors in output"), + ) + + flagSet.CreateGroup("debug", "Debug", + flagSet.BoolVar(&options.Silent, "silent", false, "show only results in output"), + flagSet.BoolVar(&options.Debug, "debug", false, "show debug output"), + ) + + if err := flagSet.Parse(); err != nil { + gologger.Fatal().Msgf("Program exiting: %v", err) + } + + options.configureOutput() + + showBanner() + + if err := options.validateOptions(); err != nil { + gologger.Fatal().Msgf("Program exiting: %v", err) + } + + if err := options.configureOptions(); err != nil { + gologger.Fatal().Msgf("Program exiting: %v", err) + } + + return options +} + +// configureOutput 配置输出 +func (o *Options) configureOutput() { + if o.NoColor { + gologger.DefaultLogger.SetFormatter(formatter.NewCLI(true)) + } + + if o.Debug { + gologger.DefaultLogger.SetMaxLevel(levels.LevelDebug) + } + + if o.Silent { + gologger.DefaultLogger.SetMaxLevel(levels.LevelSilent) + } + + gologger.DefaultLogger.SetWriter(utils.NewCLI(o.OutputFile)) +} + +// validateOptions 验证选项 +func (o *Options) validateOptions() error { + if o.Input == "" && o.InputFile == "" { + return fmt.Errorf("no service input provided") + } + if o.Debug && o.Silent { + return fmt.Errorf("both debug and silent mode specified") + } + if o.Delay < 0 { + return fmt.Errorf("delay can't be negative") + } + if o.UserFile != "" && !utils.FileExists(o.UserFile) { + return fmt.Errorf("file %v does not exist", o.UserFile) + } + if o.PassFile != "" && !utils.FileExists(o.PassFile) { + return fmt.Errorf("file %v does not exist", o.PassFile) + } + + return nil +} + +// configureOptions 配置选项 +func (o *Options) configureOptions() error { + var err error + if o.Input != "" { + o.Targets = append(o.Targets, o.Input) + } else { + var lines []string + lines, err = utils.ReadLines(o.InputFile) + if err != nil { + return err + } + o.Targets = append(o.Targets, lines...) + } + if o.User != "" { + o.UserDict = strings.Split(o.User, ",") + } + if o.Pass != "" { + o.PassDict = strings.Split(o.Pass, ",") + } + if o.UserFile != "" { + if o.UserDict, err = utils.ReadLines(o.UserFile); err != nil { + return err + } + } + if o.PassFile != "" { + if o.PassDict, err = utils.ReadLines(o.PassFile); err != nil { + return err + } + } + // 去重 + o.Targets = utils.RemoveDuplicate(o.Targets) + o.UserDict = utils.RemoveDuplicate(o.UserDict) + o.PassDict = utils.RemoveDuplicate(o.PassDict) + // 打印配置 + opt, _ := json.Marshal(o) + gologger.Debug().Msgf("当前选项: %v", string(opt)) + + return nil +} diff --git a/internal/runner/runner.go b/internal/runner/runner.go new file mode 100644 index 0000000..9b25958 --- /dev/null +++ b/internal/runner/runner.go @@ -0,0 +1,52 @@ +package runner + +import ( + "fmt" + "github.com/niudaii/crack/pkg/crack" + "github.com/projectdiscovery/gologger" +) + +type Runner struct { + options *Options + crackRunner *crack.Runner +} + +func NewRunner(options *Options) (*Runner, error) { + crackOptions := &crack.Options{ + Threads: options.Threads, + Timeout: options.Timeout, + Delay: options.Delay, + CrackAll: options.CrackAll, + Silent: options.Silent, + } + crackRunner, err := crack.NewRunner(crackOptions) + if err != nil { + return nil, fmt.Errorf("crack.NewRunner() err, %v", err) + } + return &Runner{ + options: options, + crackRunner: crackRunner, + }, nil +} + +func (r *Runner) Run() { + // 解析目标 + addrs := crack.ParseTargets(r.options.Targets) + addrs = crack.FilterModule(addrs, r.options.Module) + if len(addrs) == 0 { + gologger.Info().Msgf("目标为空") + return + } + // 存活探测 + gologger.Info().Msgf("存活探测") + addrs = r.crackRunner.CheckAlive(addrs) + gologger.Info().Msgf("存活数量: %v", len(addrs)) + // 服务爆破 + results := r.crackRunner.Run(addrs, r.options.UserDict, r.options.PassDict) + if len(results) > 0 { + gologger.Info().Msgf("爆破成功: %v", len(results)) + for _, result := range results { + gologger.Print().Msgf("%v -> %v %v", result.Protocol, result.Addr, result.UserPass) + } + } +} diff --git a/internal/utils/fileutil.go b/internal/utils/fileutil.go new file mode 100644 index 0000000..e6d3ac3 --- /dev/null +++ b/internal/utils/fileutil.go @@ -0,0 +1,27 @@ +package utils + +import ( + "bufio" + "os" +) + +func ReadLines(filename string) (lines []string, err error) { + f, err := os.Open(filename) + if err != nil { + return + } + defer f.Close() + s := bufio.NewScanner(f) + for s.Scan() { + lines = append(lines, s.Text()) + } + return +} + +func FileExists(filename string) bool { + info, err := os.Stat(filename) + if os.IsNotExist(err) || err != nil || info == nil { + return false + } + return !info.IsDir() +} diff --git a/internal/utils/log.go b/internal/utils/log.go new file mode 100644 index 0000000..e5f1e60 --- /dev/null +++ b/internal/utils/log.go @@ -0,0 +1,55 @@ +package utils + +import ( + "fmt" + "github.com/projectdiscovery/gologger/levels" + "github.com/projectdiscovery/gologger/writer" + "os" + "sync" +) + +type CLI struct { + outputFile string + mutex *sync.Mutex +} + +var _ writer.Writer = &CLI{} + +func NewCLI(outputFile string) *CLI { + cli := &CLI{ + outputFile: outputFile, + mutex: &sync.Mutex{}, + } + if !FileExists(outputFile) { + fp, err := os.Create(outputFile) + if err != nil { + fmt.Printf("Create %v err, %v\n", outputFile, err) + return cli + } + defer fp.Close() + } + return cli +} + +func (w *CLI) Write(data []byte, level levels.Level) { + w.mutex.Lock() + defer w.mutex.Unlock() + + switch level { + case levels.LevelSilent: + os.Stdout.Write(data) + os.Stdout.Write([]byte("\n")) + + default: + os.Stderr.Write(data) + os.Stderr.Write([]byte("\n")) + } + fl, err := os.OpenFile(w.outputFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) + if err != nil { + fmt.Printf("Open %v err, %v\n", w.outputFile, err) + return + } + _, _ = fl.Write(data) + _, _ = fl.Write([]byte("\n")) + fl.Close() +} diff --git a/internal/utils/utils.go b/internal/utils/utils.go new file mode 100644 index 0000000..0b0673d --- /dev/null +++ b/internal/utils/utils.go @@ -0,0 +1,28 @@ +package utils + +import ( + "crypto/md5" + "encoding/hex" +) + +func RemoveDuplicate(list []string) []string { + var set []string + hashSet := make(map[string]struct{}) + for _, v := range list { + hashSet[v] = struct{}{} + } + for k := range hashSet { + // 去除空字符串 + if k == "" { + continue + } + set = append(set, k) + } + return set +} + +func Md5(s string) string { + m := md5.New() + m.Write([]byte(s)) + return hex.EncodeToString(m.Sum(nil)) +} diff --git a/pkg/crack/check.go b/pkg/crack/check.go new file mode 100644 index 0000000..261b49e --- /dev/null +++ b/pkg/crack/check.go @@ -0,0 +1,59 @@ +package crack + +import ( + "fmt" + "github.com/cheggaaa/pb/v3" + "net" + "sync" + "time" +) + +// CheckAlive 存活检测 +func (r *Runner) CheckAlive(addrs []*IpAddr) (results []*IpAddr) { + // RunTask + mutex := &sync.Mutex{} + wg := &sync.WaitGroup{} + taskChan := make(chan *IpAddr, r.options.Threads) + for i := 0; i < r.options.Threads; i++ { + go func() { + for task := range taskChan { + if r.conn(task) { + mutex.Lock() + results = append(results, task) + mutex.Unlock() + } + wg.Done() + } + }() + } + + if r.options.Silent { + for _, task := range addrs { + wg.Add(1) + taskChan <- task + } + close(taskChan) + wg.Wait() + } else { + bar := pb.StartNew(len(addrs)) + for _, task := range addrs { + bar.Increment() + wg.Add(1) + taskChan <- task + } + close(taskChan) + wg.Wait() + bar.Finish() + } + + return +} + +// conn 建立tcp连接 +func (r *Runner) conn(ipAddr *IpAddr) (alive bool) { + _, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", ipAddr.Ip, ipAddr.Port), time.Duration(r.options.Timeout)*time.Second) + if err == nil { + alive = true + } + return +} diff --git a/pkg/crack/config.go b/pkg/crack/config.go new file mode 100644 index 0000000..3bd2735 --- /dev/null +++ b/pkg/crack/config.go @@ -0,0 +1,58 @@ +package crack + +var ( + PortNames = map[int]string{ + 21: "ftp", + 22: "ssh", + 135: "wmi", + 445: "smb", + 1433: "mssql", + 1521: "oracle", + 3306: "mysql", + 3389: "rdp", + 5432: "postgres", + 6379: "redis", + 11211: "memcached", + 27017: "mongodb", + } + + SupportProtocols = map[string]bool{ + "ftp": true, + "ssh": true, + "wmi": true, + "wmihash": true, + "smb": true, + "mssql": true, + "oracle": true, + "mysql": true, + "rdp": true, + "postgres": true, + "redis": true, + "memcached": true, + "mongodb": true, + } +) + +var ( + UserMap = map[string][]string{ + //"ftp": {"ftp", "admin", "www"}, + "ftp": {"ftp"}, + //"ssh": {"root", "oracle", "admin"}, + "ssh": {"root"}, + "wmi": {"administrator"}, + "wmihash": {"administrator"}, + "smb": {"administrator"}, + "mssql": {"sa"}, + "oracle": {"oracle", "system"}, + "mysql": {"root"}, + "rdp": {"administrator"}, + "postgres": {"postgres", "admin"}, + "redis": {""}, + "memcached": {""}, + "mongodb": {"admin", "root"}, + } + + TemplatePass = []string{"{user}", "{user}!@#123", "{user}!@#456", "{user}#123", "{user}*PWD", "{user}1", "{user}11", "{user}12#$", "{user}123", "{user}123456", "{user}@111", "{user}@123", "{user}@123#4", "{user}@2016", "{user}@2017", "{user}@2018", "{user}@2019", "{user}@2020", "{user}@2021", "{user}@2022", "{user}_123"} + + CommonPass = []string{"", "!QAZ2wsx", "000000", "1", "111111", "123", "123123", "12313", "123321", "1234", "12345!@#$%abc", "123456", "12345678", "123456789", "1234567890", "12345678;abc", "123456Aa", "123qwe!@#", "123qweASD", "1q2w3e", "1qaz2wsx", "1QAZ2wsx", "1qaz@WSX", "1QAZ@WSX", "1qazxsw2", "654321", "666666", "8888888", "a11111", "a123123", "a12345", "a123456", "a123456", "a123456.", "Aa123123", "Aa1234", "Aa1234.", "Aa12345", "Aa12345.", "Aa123456", "Aa123456!", "Aa123456789", "abc+123", "abc123", "abc123456", "abc@123", "admin", "admin123", "Admin123", "admin123!@#", "admin888", "admin@123", "Admin@123", "Admin@1234", "admin@888", "adminadmin", "adminPwd", "Asdfg@123", "Charge123", "P@ssw0rd", "P@ssw0rd!", "P@ssword", "p@ssword", "pass123", "pass@123", "Passw0rd", "password", "qwe123", "qwe123!@#", "root", "sysadmin", "system", "test", "test123", "xcv@123", "zxc1qaz", "Zxcvb123"} +) diff --git a/pkg/crack/parse.go b/pkg/crack/parse.go new file mode 100644 index 0000000..dc8a4ce --- /dev/null +++ b/pkg/crack/parse.go @@ -0,0 +1,53 @@ +package crack + +import ( + "strconv" + "strings" +) + +func ParseTargets(targets []string) (results []*IpAddr) { + for _, target := range targets { + target = strings.TrimSpace(target) + tmp := strings.Split(target, ":") + if len(tmp) != 2 { + continue + } + ip := tmp[0] + tmp = strings.Split(tmp[1], "|") + if len(tmp) == 2 { // ip列表中指定了端口对应的服务 + port, _ := strconv.Atoi(tmp[0]) + protocol := tmp[1] + if SupportProtocols[protocol] { + results = append(results, &IpAddr{ + Ip: ip, + Port: port, + Protocol: protocol, + }) + } + } else { // 通过端口查默认服务 + port, _ := strconv.Atoi(tmp[0]) + protocol, ok := PortNames[port] + if ok && SupportProtocols[protocol] { + results = append(results, &IpAddr{ + Ip: ip, + Port: port, + Protocol: protocol, + }) + } + } + } + + return +} + +func FilterModule(addrs []*IpAddr, module string) (results []*IpAddr) { + if module == "all" { + return addrs + } + for _, addr := range addrs { + if addr.Protocol == module { + results = append(results, addr) + } + } + return results +} diff --git a/pkg/crack/plugins/ftp.go b/pkg/crack/plugins/ftp.go new file mode 100755 index 0000000..079471b --- /dev/null +++ b/pkg/crack/plugins/ftp.go @@ -0,0 +1,21 @@ +package plugins + +import ( + "fmt" + "github.com/jlaffaye/ftp" + "time" +) + +func FtpCrack(serv *Service) int { + addr := fmt.Sprintf("%v:%v", serv.Ip, serv.Port) + servConn, err := ftp.Dial(addr, ftp.DialWithTimeout(time.Duration(serv.Timeout)*time.Second)) + if err != nil { + return CrackError + } + err = servConn.Login(serv.User, serv.Pass) + if err != nil { + return CrackFail + } + defer servConn.Logout() // nolint + return CrackSuccess +} diff --git a/pkg/crack/plugins/grdp/grdp.go b/pkg/crack/plugins/grdp/grdp.go new file mode 100644 index 0000000..bccb9d1 --- /dev/null +++ b/pkg/crack/plugins/grdp/grdp.go @@ -0,0 +1,217 @@ +// nolint +package grdp + +import ( + "errors" + "fmt" + "github.com/tomatome/grdp/core" + "github.com/tomatome/grdp/glog" + "github.com/tomatome/grdp/protocol/nla" + "github.com/tomatome/grdp/protocol/pdu" + "github.com/tomatome/grdp/protocol/rfb" + "github.com/tomatome/grdp/protocol/sec" + "github.com/tomatome/grdp/protocol/t125" + "github.com/tomatome/grdp/protocol/tpkt" + "github.com/tomatome/grdp/protocol/x224" + "log" + "net" + "os" + "sync" + "time" +) + +const ( + PROTOCOL_RDP = "PROTOCOL_RDP" + PROTOCOL_SSL = "PROTOCOL_SSL" +) + +type Client struct { + Host string // ip:port + tpkt *tpkt.TPKT + x224 *x224.X224 + mcs *t125.MCSClient + sec *sec.Client + pdu *pdu.Client + vnc *rfb.RFB + Timeout int +} + +func NewClient(host string, timeout int, logLevel glog.LEVEL) *Client { + glog.SetLevel(logLevel) + logger := log.New(os.Stdout, "", 0) + glog.SetLogger(logger) + return &Client{ + Host: host, + Timeout: timeout, + } +} + +func (g *Client) loginForSSL(domain, user, pwd string) error { + conn, err := net.DialTimeout("tcp", g.Host, time.Duration(g.Timeout)*time.Second) + if err != nil { + return fmt.Errorf("[dial err] %v", err) + } + err = conn.SetReadDeadline(time.Now().Add(time.Duration(g.Timeout) * time.Second)) + if err != nil { + return err + } + defer conn.Close() + glog.Info(conn.LocalAddr().String()) + + g.tpkt = tpkt.New(core.NewSocketLayer(conn), nla.NewNTLMv2(domain, user, pwd)) + g.x224 = x224.New(g.tpkt) + g.mcs = t125.NewMCSClient(g.x224) + g.sec = sec.NewClient(g.mcs) + g.pdu = pdu.NewClient(g.sec) + + g.sec.SetUser(user) + g.sec.SetPwd(pwd) + g.sec.SetDomain(domain) + + g.tpkt.SetFastPathListener(g.sec) + g.sec.SetFastPathListener(g.pdu) + g.pdu.SetFastPathSender(g.tpkt) + + err = g.x224.Connect() + if err != nil { + return fmt.Errorf("[x224 connect err] %v", err) + } + glog.Info("wait connect ok") + wg := &sync.WaitGroup{} + breakFlag := false + wg.Add(1) + + g.pdu.On("error", func(e error) { + err = e + glog.Error("error", e) + g.pdu.Emit("done") + }) + g.pdu.On("close", func() { + err = errors.New("close") + glog.Info("on close") + g.pdu.Emit("done") + }) + g.pdu.On("success", func() { + err = nil + glog.Info("on success") + g.pdu.Emit("done") + }) + g.pdu.On("ready", func() { + glog.Info("on ready") + g.pdu.Emit("done") + }) + g.pdu.On("update", func(rectangles []pdu.BitmapData) { + glog.Info("on update:", rectangles) + }) + g.pdu.On("done", func() { + if breakFlag == false { + breakFlag = true + wg.Done() + } + }) + wg.Wait() + return err +} + +func (g *Client) loginForRDP(domain, user, pwd string) error { + conn, err := net.DialTimeout("tcp", g.Host, time.Duration(g.Timeout)*time.Second) + if err != nil { + return fmt.Errorf("[dial err] %v", err) + } + err = conn.SetReadDeadline(time.Now().Add(time.Duration(g.Timeout) * time.Second)) + if err != nil { + return err + } + defer conn.Close() + glog.Info(conn.LocalAddr().String()) + + g.tpkt = tpkt.New(core.NewSocketLayer(conn), nla.NewNTLMv2(domain, user, pwd)) + g.x224 = x224.New(g.tpkt) + g.mcs = t125.NewMCSClient(g.x224) + g.sec = sec.NewClient(g.mcs) + g.pdu = pdu.NewClient(g.sec) + + g.sec.SetUser(user) + g.sec.SetPwd(pwd) + g.sec.SetDomain(domain) + + g.tpkt.SetFastPathListener(g.sec) + g.sec.SetFastPathListener(g.pdu) + g.pdu.SetFastPathSender(g.tpkt) + + g.x224.SetRequestedProtocol(x224.PROTOCOL_RDP) + + err = g.x224.Connect() + if err != nil { + return fmt.Errorf("[x224 connect err] %v", err) + } + glog.Info("wait connect ok") + wg := &sync.WaitGroup{} + breakFlag := false + updateCount := 0 + wg.Add(1) + + g.pdu.On("error", func(e error) { + err = e + glog.Error("error", e) + g.pdu.Emit("done") + }) + g.pdu.On("close", func() { + err = errors.New("close") + glog.Info("on close") + g.pdu.Emit("done") + }) + g.pdu.On("success", func() { + err = nil + glog.Info("on success") + g.pdu.Emit("done") + }) + g.pdu.On("ready", func() { + glog.Info("on ready") + }) + g.pdu.On("update", func(rectangles []pdu.BitmapData) { + glog.Info("on update:", rectangles) + updateCount += 1 + //fmt.Println(updateCount," ",rectangles[0].BitmapLength) + }) + g.pdu.On("done", func() { + if breakFlag == false { + breakFlag = true + wg.Done() + } + }) + + //wait 2 Second + time.Sleep(time.Second * 3) + if breakFlag == false { + breakFlag = true + wg.Done() + } + wg.Wait() + + if updateCount > 50 { + return nil + } + err = errors.New("login failed") + return err +} + +func Login(target, domain, username, password string, timeout int) error { + var err error + g := NewClient(target, timeout, glog.NONE) + //SSL协议登录测试 + err = g.loginForSSL(domain, username, password) + if err == nil { + return nil + } + if err.Error() != PROTOCOL_RDP { + return err + } + //RDP协议登录测试 + err = g.loginForRDP(domain, username, password) + if err == nil { + return nil + } else { + return err + } +} diff --git a/pkg/crack/plugins/memcached.go b/pkg/crack/plugins/memcached.go new file mode 100755 index 0000000..449afa2 --- /dev/null +++ b/pkg/crack/plugins/memcached.go @@ -0,0 +1,37 @@ +package plugins + +import ( + "fmt" + "net" + "strings" + "time" +) + +func MemcachedCrack(serv *Service) int { + // 未授权 + return MemcachedUnAuth(serv) +} + +func MemcachedUnAuth(serv *Service) int { + addr := fmt.Sprintf("%v:%v", serv.Ip, serv.Port) + conn, err := net.DialTimeout("tcp", addr, time.Duration(serv.Timeout)*time.Second) + if err != nil { + return CrackError + } + err = conn.SetDeadline(time.Now().Add(time.Duration(serv.Timeout) * time.Second)) + if err != nil { + return CrackError + } + defer conn.Close() + _, err = conn.Write([]byte("stats\n")) + if err == nil { + rev := make([]byte, 1024) + n, err := conn.Read(rev) + if err == nil { + if strings.Contains(string(rev[:n]), "STAT") { + return CrackSuccess + } + } + } + return CrackError +} diff --git a/pkg/crack/plugins/mongodb.go b/pkg/crack/plugins/mongodb.go new file mode 100755 index 0000000..b4a8634 --- /dev/null +++ b/pkg/crack/plugins/mongodb.go @@ -0,0 +1,61 @@ +package plugins + +import ( + "fmt" + "gopkg.in/mgo.v2" + "net" + "strings" + "time" +) + +func MongodbCrack(serv *Service) int { + // 未授权 + if res := MongodbUnAuth(serv); res != -1 { + return res + } + // 口令爆破 + url := fmt.Sprintf("mongodb://%v:%v@%v:%v/%v", serv.User, serv.Pass, serv.Ip, serv.Port, serv.User) + session, err := mgo.Dial(url) + if err != nil { + if strings.Contains(err.Error(), "Authentication failed") { + return CrackFail + } + return CrackError + } + defer session.Close() + err = session.Ping() + if err != nil { + return CrackFail + } + return CrackSuccess +} + +var senddata = []byte{72, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 212, 7, 0, 0, 0, 0, 0, 0, 97, 100, 109, 105, 110, 46, 36, 99, 109, 100, 0, 0, 0, 0, 0, 1, 0, 0, 0, 33, 0, 0, 0, 2, 103, 101, 116, 76, 111, 103, 0, 16, 0, 0, 0, 115, 116, 97, 114, 116, 117, 112, 87, 97, 114, 110, 105, 110, 103, 115, 0, 0} + +func MongodbUnAuth(serv *Service) int { + addr := fmt.Sprintf("%v:%v", serv.Ip, serv.Port) + conn, err := net.DialTimeout("tcp", addr, time.Duration(serv.Timeout)*time.Second) + if err != nil { + return CrackError + } + err = conn.SetDeadline(time.Now().Add(time.Duration(serv.Timeout) * time.Second)) + if err != nil { + return CrackError + } + defer conn.Close() + _, err = conn.Write(senddata) + if err != nil { + return CrackError + } + buf := make([]byte, 1024) + count, err := conn.Read(buf) + if err != nil { + fmt.Println(err) + return CrackError + } + text := string(buf[0:count]) + if strings.Contains(text, "totalLinesWritten") { + return CrackSuccess + } + return -1 +} diff --git a/pkg/crack/plugins/mssql.go b/pkg/crack/plugins/mssql.go new file mode 100755 index 0000000..d25639e --- /dev/null +++ b/pkg/crack/plugins/mssql.go @@ -0,0 +1,32 @@ +package plugins + +import ( + "database/sql" + "fmt" + _ "github.com/denisenkom/go-mssqldb" + "strings" + "time" +) + +func MssqlCrack(serv *Service) int { + dataSourceName := fmt.Sprintf("sqlserver://%v:%v@%v:%v?encrypt=disable&dial+timeout=%v&connection+timeout=%v", serv.User, serv.Pass, serv.Ip, serv.Port, serv.Timeout, serv.Timeout) + db, err := sql.Open("sqlserver", dataSourceName) + if err != nil { + if strings.Contains(err.Error(), "timeout") { + return CrackError + } + return CrackFail + } + db.SetConnMaxLifetime(time.Duration(serv.Timeout) * time.Second) + db.SetConnMaxIdleTime(time.Duration(serv.Timeout) * time.Second) + db.SetMaxIdleConns(0) + defer db.Close() + err = db.Ping() + if err != nil { + if strings.Contains(err.Error(), "timeout") { + return CrackError + } + return CrackFail + } + return CrackSuccess +} diff --git a/pkg/crack/plugins/mysql.go b/pkg/crack/plugins/mysql.go new file mode 100755 index 0000000..e4bd552 --- /dev/null +++ b/pkg/crack/plugins/mysql.go @@ -0,0 +1,29 @@ +package plugins + +import ( + "database/sql" + "fmt" + _ "github.com/go-sql-driver/mysql" + "strings" + "time" +) + +func MysqlCrack(serv *Service) int { + dataSourceName := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=utf8&timeout=%v&readTimeout=%v", serv.User, serv.Pass, serv.Ip, serv.Port, "", time.Duration(serv.Timeout)*time.Second, time.Duration(serv.Timeout)*time.Second) + db, err := sql.Open("mysql", dataSourceName) + if err != nil { + return CrackError + } + db.SetConnMaxLifetime(time.Duration(serv.Timeout) * time.Second) + db.SetConnMaxIdleTime(time.Duration(serv.Timeout) * time.Second) + db.SetMaxIdleConns(0) + defer db.Close() + err = db.Ping() + if err != nil { + if strings.Contains(err.Error(), "1045") { + return CrackFail + } + return CrackError + } + return CrackSuccess +} diff --git a/pkg/crack/plugins/oracle.go b/pkg/crack/plugins/oracle.go new file mode 100755 index 0000000..114cbc7 --- /dev/null +++ b/pkg/crack/plugins/oracle.go @@ -0,0 +1,51 @@ +package plugins + +import ( + "database/sql" + "fmt" + "github.com/sijms/go-ora/v2" + _ "github.com/sijms/go-ora/v2" + "strings" + "time" +) + +var services = []string{ + "orcl", + "xe", + "oracle", +} + +func OracleCrack(serv *Service) int { + for _, service := range services { + conn, err := Conn(serv, service) + if err != nil { + if strings.Contains(err.Error(), "timeout") { + return CrackError + } + } + if conn { + return CrackSuccess + } + } + return CrackFail +} + +func Conn(serv *Service, service string) (conn bool, err error) { + urlOptions := map[string]string{ + "CONNECTION TIMEOUT": fmt.Sprintf("%v", serv.Timeout), + } + dataSourceName := go_ora.BuildUrl(serv.Ip, serv.Port, service, serv.User, serv.Pass, urlOptions) + db, err := sql.Open("oracle", dataSourceName) + if err != nil { + return + } + db.SetConnMaxLifetime(time.Duration(serv.Timeout) * time.Second) + db.SetConnMaxIdleTime(time.Duration(serv.Timeout) * time.Second) + db.SetMaxIdleConns(0) + err = db.Ping() + defer db.Close() + if err == nil { + conn = true + } + return +} diff --git a/pkg/crack/plugins/plugins.go b/pkg/crack/plugins/plugins.go new file mode 100644 index 0000000..16a0360 --- /dev/null +++ b/pkg/crack/plugins/plugins.go @@ -0,0 +1,39 @@ +package plugins + +type Service struct { + Ip string + Port int + Protocol string + User string + Pass string + Timeout int +} + +const ( + CrackError = iota + CrackFail + CrackSuccess +) + +type ScanFunc func(serv *Service) int + +var ( + ScanFuncMap map[string]ScanFunc +) + +func init() { + ScanFuncMap = make(map[string]ScanFunc) + ScanFuncMap["ftp"] = FtpCrack + ScanFuncMap["ssh"] = SshCrack + ScanFuncMap["wmi"] = WmiCrack + ScanFuncMap["wmihash"] = WmiHashCrack + ScanFuncMap["smb"] = SmbCrack + ScanFuncMap["mssql"] = MssqlCrack + ScanFuncMap["oracle"] = OracleCrack + ScanFuncMap["mysql"] = MysqlCrack + ScanFuncMap["rdp"] = RdpCrack + ScanFuncMap["postgres"] = PostgresCrack + ScanFuncMap["redis"] = RedisCrack + ScanFuncMap["memcached"] = MemcachedCrack + ScanFuncMap["mongodb"] = MongodbCrack +} diff --git a/pkg/crack/plugins/plugins_test.go b/pkg/crack/plugins/plugins_test.go new file mode 100644 index 0000000..417d45b --- /dev/null +++ b/pkg/crack/plugins/plugins_test.go @@ -0,0 +1,675 @@ +package plugins + +import ( + "testing" +) + +var RespMap = map[int]string{ + CrackSuccess: "success", + CrackFail: "fail", + CrackError: "error", +} + +func TestFtpCrack(t *testing.T) { + /* + === RUN TestFtpCrack + === RUN TestFtpCrack/success + plugins_test.go:43: success ftp:ftp + === RUN TestFtpCrack/fail + plugins_test.go:43: fail ftp:xxx + === RUN TestFtpCrack/error + plugins_test.go:43: error ftp:xxx + --- PASS: TestFtpCrack (10.02s) + --- PASS: TestFtpCrack/success (0.01s) + --- PASS: TestFtpCrack/fail (0.01s) + --- PASS: TestFtpCrack/error (10.00s) + PASS + ok crack/pkg/crack/plugins 10.033s + */ + tests := map[string]Service{ + "success": { + Ip: "192.168.31.245", + Port: 21, + User: "ftp", + Pass: "ftp", + Timeout: 10, + }, + "fail": { + Ip: "192.168.31.245", + Port: 21, + User: "ftp", + Pass: "xxx", + Timeout: 10, + }, + "error": { + Ip: "127.0.0.2", + Port: 21, + User: "ftp", + Pass: "xxx", + Timeout: 10, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := FtpCrack(&tc) + t.Logf("%v %v:%v", RespMap[got], tc.User, tc.Pass) + if name != RespMap[got] { + t.Error("sth wrong") + } + }) + } +} + +func TestSshCrack(t *testing.T) { + /* + === RUN TestSshCrack + === RUN TestSshCrack/success + plugins_test.go:78: success root:root + === RUN TestSshCrack/fail + plugins_test.go:78: fail root:xxx + === RUN TestSshCrack/error + plugins_test.go:78: error root:xxx + --- PASS: TestSshCrack (11.54s) + --- PASS: TestSshCrack/success (0.14s) + --- PASS: TestSshCrack/fail (1.40s) + --- PASS: TestSshCrack/error (10.00s) + PASS + ok crack/pkg/crack/plugins 11.555s + */ + tests := map[string]Service{ + "success": { + Ip: "192.168.243.11", + Port: 22, + User: "root", + Pass: "root", + Timeout: 10, + }, + "fail": { + Ip: "192.168.243.11", + Port: 22, + User: "root", + Pass: "xxx", + Timeout: 10, + }, + "error": { + Ip: "127.0.0.2", + Port: 22, + User: "root", + Pass: "xxx", + Timeout: 10, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := SshCrack(&tc) + t.Logf("%v %v:%v", RespMap[got], tc.User, tc.Pass) + if name != RespMap[got] { + t.Error("sth wrong") + } + }) + } +} + +func TestWmiCrack(t *testing.T) { + /* + === RUN TestWmiCrack + === RUN TestWmiCrack/success + plugins_test.go:130: success administrator:123qweASD + === RUN TestWmiCrack/fail + plugins_test.go:130: fail administrator:xxx + === RUN TestWmiCrack/error + plugins_test.go:130: error administrator:xxx + --- PASS: TestWmiCrack (10.95s) + --- PASS: TestWmiCrack/success (0.09s) + --- PASS: TestWmiCrack/fail (0.74s) + --- PASS: TestWmiCrack/error (10.12s) + PASS + ok crack/pkg/crack/plugins 10.963s + */ + tests := map[string]Service{ + "success": { + Ip: "192.168.243.10", + Port: 135, + User: "administrator", + Pass: "123qweASD", + Timeout: 10, + }, + "fail": { + Ip: "192.168.243.10", + Port: 135, + User: "administrator", + Pass: "xxx", + Timeout: 10, + }, + "error": { + Ip: "127.0.0.2", + Port: 135, + User: "administrator", + Pass: "xxx", + Timeout: 10, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := WmiCrack(&tc) + t.Logf("%v %v:%v", RespMap[got], tc.User, tc.Pass) + if name != RespMap[got] { + t.Error("sth wrong") + } + }) + } +} + +func TestWmiHashCrack(t *testing.T) { + /* + === RUN TestWmiHashCrack + === RUN TestWmiHashCrack/success + plugins_test.go:145: success administrator:257c7efa85ba45bb30b7da33f46a5225 + === RUN TestWmiHashCrack/fail + plugins_test.go:145: fail administrator:257c7efa85ba45bb30b7da33f46a5220 + === RUN TestWmiHashCrack/error + plugins_test.go:145: error administrator:257c7efa85ba45bb30b7da33f46a5220 + --- PASS: TestWmiHashCrack (10.02s) + --- PASS: TestWmiHashCrack/success (0.01s) + --- PASS: TestWmiHashCrack/fail (0.01s) + --- PASS: TestWmiHashCrack/error (10.00s) + PASS + ok crack/pkg/crack/plugins 10.031s + */ + tests := map[string]Service{ + "success": { + Ip: "192.168.243.10", + Port: 135, + User: "administrator", + Pass: "257c7efa85ba45bb30b7da33f46a5225", + Timeout: 10, + }, + "fail": { + Ip: "192.168.243.10", + Port: 135, + User: "administrator", + Pass: "257c7efa85ba45bb30b7da33f46a5220", + Timeout: 10, + }, + "error": { + Ip: "127.0.0.2", + Port: 135, + User: "administrator", + Pass: "257c7efa85ba45bb30b7da33f46a5220", + Timeout: 10, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := WmiHashCrack(&tc) + t.Logf("%v %v:%v", RespMap[got], tc.User, tc.Pass) + if name != RespMap[got] { + t.Error("sth wrong") + } + }) + } +} + +func TestSmbCrack(t *testing.T) { + /* + === RUN TestSmbCrack + === RUN TestSmbCrack/success + plugins_test.go:181: success administrator:123qweASD + === RUN TestSmbCrack/fail + plugins_test.go:181: fail administrator:xxx + === RUN TestSmbCrack/error + plugins_test.go:181: error administrator:xxx + --- PASS: TestSmbCrack (10.01s) + --- PASS: TestSmbCrack/success (0.01s) + --- PASS: TestSmbCrack/fail (0.01s) + --- PASS: TestSmbCrack/error (10.00s) + PASS + ok crack/pkg/crack/plugins 10.028s + */ + tests := map[string]Service{ + "success": { + Ip: "192.168.243.10", + Port: 445, + User: "administrator", + Pass: "123qweASD", + Timeout: 10, + }, + "fail": { + Ip: "192.168.243.10", + Port: 445, + User: "administrator", + Pass: "xxx", + Timeout: 10, + }, + "error": { + Ip: "127.0.0.2", + Port: 445, + User: "administrator", + Pass: "xxx", + Timeout: 10, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := SmbCrack(&tc) + t.Logf("%v %v:%v", RespMap[got], tc.User, tc.Pass) + if name != RespMap[got] { + t.Error("sth wrong") + } + }) + } +} + +func TestMssqlCrack(t *testing.T) { + /* + === RUN TestMssqlCrack + === RUN TestMssqlCrack/success + plugins_test.go:218: success sa:123qweASD + === RUN TestMssqlCrack/fail + plugins_test.go:218: fail sa:xxx + === RUN TestMssqlCrack/error + plugins_test.go:218: error sa:xxx + --- PASS: TestMssqlCrack (10.02s) + --- PASS: TestMssqlCrack/success (0.01s) + --- PASS: TestMssqlCrack/fail (0.01s) + --- PASS: TestMssqlCrack/error (10.00s) + PASS + ok crack/pkg/crack/plugins 10.031s + */ + tests := map[string]Service{ + "success": { + Ip: "127.0.0.1", + Port: 1433, + User: "sa", + Pass: "123qweASD", + Timeout: 10, + }, + "fail": { + Ip: "127.0.0.1", + Port: 1433, + User: "sa", + Pass: "xxx", + Timeout: 10, + }, + "error": { + Ip: "127.0.0.2", + Port: 1433, + User: "sa", + Pass: "xxx", + Timeout: 10, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := MssqlCrack(&tc) + t.Logf("%v %v:%v", RespMap[got], tc.User, tc.Pass) + if name != RespMap[got] { + t.Error("sth wrong") + } + }) + } +} + +func TestOracleCrack(t *testing.T) { + /* + === RUN TestOracleCrack + === RUN TestOracleCrack/success + &{28002 4 ORA-28002: the password will expire within 5 days + } + plugins_test.go:253: success system:oracle + === RUN TestOracleCrack/fail + plugins_test.go:253: fail system:xxx + === RUN TestOracleCrack/error + plugins_test.go:253: error system:xxx + --- PASS: TestOracleCrack (10.08s) + --- PASS: TestOracleCrack/success (0.05s) + --- PASS: TestOracleCrack/fail (0.03s) + --- PASS: TestOracleCrack/error (10.00s) + PASS + ok crack/pkg/crack/plugins 10.096s + */ + tests := map[string]Service{ + "success": { + Ip: "127.0.0.1", + Port: 1521, + User: "system", + Pass: "oracle", + Timeout: 10, + }, + "fail": { + Ip: "127.0.0.1", + Port: 1521, + User: "system", + Pass: "xxx", + Timeout: 10, + }, + "error": { + Ip: "127.0.0.2", + Port: 1521, + User: "system", + Pass: "xxx", + Timeout: 10, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := OracleCrack(&tc) + t.Logf("%v %v:%v", RespMap[got], tc.User, tc.Pass) + if name != RespMap[got] { + t.Error("sth wrong") + } + }) + } +} + +func TestMysqlCrack(t *testing.T) { + /* + === RUN TestMysqlCrack + === RUN TestMysqlCrack/success + plugins_test.go:288: success root:123456 + === RUN TestMysqlCrack/fail + plugins_test.go:288: fail root:xxx + === RUN TestMysqlCrack/error + plugins_test.go:288: error root:xxx + --- PASS: TestMysqlCrack (10.02s) + --- PASS: TestMysqlCrack/success (0.01s) + --- PASS: TestMysqlCrack/fail (0.00s) + --- PASS: TestMysqlCrack/error (10.00s) + PASS + ok crack/pkg/crack/plugins 10.029s + */ + tests := map[string]Service{ + "success": { + Ip: "127.0.0.1", + Port: 3306, + //User: "root", + //Pass: "123456", + User: "test_user", + Pass: "test2022@", + Timeout: 10, + }, + "fail": { + Ip: "127.0.0.1", + Port: 3306, + User: "root", + Pass: "xxx", + Timeout: 10, + }, + "error": { + Ip: "127.0.0.2", + Port: 3306, + User: "root", + Pass: "xxx", + Timeout: 10, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := MysqlCrack(&tc) + t.Logf("%v %v:%v", RespMap[got], tc.User, tc.Pass) + if name != RespMap[got] { + t.Error("sth wrong") + } + }) + } +} + +func TestRdpCrack(t *testing.T) { + /* + === RUN TestRdpCrack + === RUN TestRdpCrack/success + plugins_test.go:321: success administrator:123qweASD + === RUN TestRdpCrack/fail + plugins_test.go:321: fail administrator:xxx + === RUN TestRdpCrack/error + plugins_test.go:321: error administrator:xxx + --- PASS: TestRdpCrack (11.21s) + --- PASS: TestRdpCrack/success (0.12s) + --- PASS: TestRdpCrack/fail (1.09s) + --- PASS: TestRdpCrack/error (10.00s) + PASS + ok crack/pkg/crack/plugins 11.225s + */ + tests := map[string]Service{ + "success": { + Ip: "192.168.243.10", + Port: 3389, + User: "administrator", + Pass: "123qweASD", + Timeout: 10, + }, + "fail": { + Ip: "192.168.243.10", + Port: 3389, + User: "administrator", + Pass: "xxx", + Timeout: 10, + }, + "error": { + Ip: "192.168.243.11", + Port: 3389, + User: "administrator", + Pass: "xxx", + Timeout: 10, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := RdpCrack(&tc) + t.Logf("%v %v:%v", RespMap[got], tc.User, tc.Pass) + if name != RespMap[got] { + t.Error("sth wrong") + } + }) + } +} + +func TestPostgresCrack(t *testing.T) { + /* + === RUN TestPostgresCrack + === RUN TestPostgresCrack/success + plugins_test.go:355: success postgres:password + === RUN TestPostgresCrack/fail + plugins_test.go:355: fail postgres:xxx + === RUN TestPostgresCrack/error + plugins_test.go:355: error postgres:xxx + --- PASS: TestPostgresCrack (10.01s) + --- PASS: TestPostgresCrack/success (0.01s) + --- PASS: TestPostgresCrack/fail (0.01s) + --- PASS: TestPostgresCrack/error (10.00s) + PASS + ok crack/pkg/crack/plugins 10.027s + */ + tests := map[string]Service{ + "success": { + Ip: "127.0.0.1", + Port: 5432, + User: "postgres", + Pass: "password", + Timeout: 10, + }, + "fail": { + Ip: "127.0.0.1", + Port: 5432, + User: "postgres", + Pass: "xxx", + Timeout: 10, + }, + "error": { + Ip: "127.0.0.2", + Port: 5432, + User: "postgres", + Pass: "xxx", + Timeout: 10, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := PostgresCrack(&tc) + t.Logf("%v %v:%v", RespMap[got], tc.User, tc.Pass) + if name != RespMap[got] { + t.Error("sth wrong") + } + }) + } +} + +func TestRedisCrack(t *testing.T) { + /* + === RUN TestRedisCrack + === RUN TestRedisCrack/success + plugins_test.go:390: success :123456 + === RUN TestRedisCrack/fail + plugins_test.go:390: fail :xxx + === RUN TestRedisCrack/error + plugins_test.go:390: error :xxx + --- PASS: TestRedisCrack (10.02s) + --- PASS: TestRedisCrack/success (0.02s) + --- PASS: TestRedisCrack/fail (0.00s) + --- PASS: TestRedisCrack/error (10.00s) + PASS + ok crack/pkg/crack/plugins 10.036s + */ + tests := map[string]Service{ + "success": { + Ip: "127.0.0.1", + Port: 6379, + User: "", + Pass: "123456", + Timeout: 10, + }, + "fail": { + Ip: "127.0.0.1", + Port: 6379, + User: "", + Pass: "xxx", + Timeout: 10, + }, + "error": { + Ip: "127.0.0.2", + Port: 6379, + User: "", + Pass: "xxx", + Timeout: 10, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := RedisCrack(&tc) + t.Logf("%v %v:%v", RespMap[got], tc.User, tc.Pass) + if name != RespMap[got] { + t.Error("sth wrong") + } + }) + } +} + +func TestMemcachedCrack(t *testing.T) { + /* + 只检查未授权,不需要 TestMongodbCrack/fail 测试用例 + + === RUN TestMemcachedCrack + === RUN TestMemcachedCrack/error + plugins_test.go:432: error :xxx + === RUN TestMemcachedCrack/success + plugins_test.go:432: success :xxx + --- PASS: TestMemcachedCrack (10.01s) + --- PASS: TestMemcachedCrack/error (10.00s) + --- PASS: TestMemcachedCrack/success (0.01s) + PASS + ok crack/pkg/crack/plugins 10.021s + */ + tests := map[string]Service{ + "success": { + Ip: "127.0.0.1", + Port: 11211, + User: "", + Pass: "xxx", + Timeout: 10, + }, + "error": { + Ip: "127.0.0.2", + Port: 11211, + User: "", + Pass: "xxx", + Timeout: 10, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := MemcachedCrack(&tc) + t.Logf("%v %v:%v", RespMap[got], tc.User, tc.Pass) + if name != RespMap[got] { + t.Error("sth wrong") + } + }) + } +} + +func TestMongodbCrack(t *testing.T) { + /* + === RUN TestMongodbCrack + === RUN TestMongodbCrack/success + plugins_test.go:413: success admin:123456 + === RUN TestMongodbCrack/fail + plugins_test.go:413: fail admin:xxx + === RUN TestMongodbCrack/error + plugins_test.go:413: error admin:xxx + --- PASS: TestMongodbCrack (10.01s) + --- PASS: TestMongodbCrack/success (0.01s) + --- PASS: TestMongodbCrack/fail (0.00s) + --- PASS: TestMongodbCrack/error (10.00s) + PASS + ok crack/pkg/crack/plugins 10.026s + + 未授权时 TestMongodbCrack/fail 认证通过 + + === RUN TestMongodbCrack + === RUN TestMongodbCrack/error + plugins_test.go:428: error admin:xxx + === RUN TestMongodbCrack/success + plugins_test.go:428: success admin:123456 + === RUN TestMongodbCrack/fail + plugins_test.go:428: success admin:xxx + plugins_test.go:430: sth wrong + --- FAIL: TestMongodbCrack (10.00s) + --- PASS: TestMongodbCrack/error (10.00s) + --- PASS: TestMongodbCrack/success (0.00s) + --- FAIL: TestMongodbCrack/fail (0.00s) + FAIL + exit status 1 + FAIL crack/pkg/crack/plugins 10.016s + */ + tests := map[string]Service{ + "success": { + Ip: "127.0.0.1", + Port: 27017, + User: "admin", + Pass: "123456", + Timeout: 10, + }, + "fail": { + Ip: "127.0.0.1", + Port: 27017, + User: "admin", + Pass: "xxx", + Timeout: 10, + }, + "error": { + Ip: "127.0.0.2", + Port: 27017, + User: "admin", + Pass: "xxx", + Timeout: 10, + }, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + got := MongodbCrack(&tc) + t.Logf("%v %v:%v", RespMap[got], tc.User, tc.Pass) + if name != RespMap[got] { + t.Error("sth wrong") + } + }) + } +} diff --git a/pkg/crack/plugins/postgres.go b/pkg/crack/plugins/postgres.go new file mode 100755 index 0000000..1bb7dac --- /dev/null +++ b/pkg/crack/plugins/postgres.go @@ -0,0 +1,30 @@ +package plugins + +import ( + "database/sql" + "fmt" + _ "github.com/lib/pq" + "strings" + "time" +) + +func PostgresCrack(serv *Service) int { + dataSourceName := fmt.Sprintf("postgres://%v:%v@%v:%v/%v?sslmode=%v&connect_timeout=%v", serv.User, serv.Pass, serv.Ip, serv.Port, "", "disable", serv.Timeout) + db, err := sql.Open("postgres", dataSourceName) + if err != nil { + if strings.Contains(err.Error(), "timeout") { + return CrackError + } + return CrackFail + } + db.SetConnMaxLifetime(time.Duration(serv.Timeout) * time.Second) + defer db.Close() + err = db.Ping() + if err != nil { + if strings.Contains(err.Error(), "timeout") { + return CrackError + } + return CrackFail + } + return CrackSuccess +} diff --git a/pkg/crack/plugins/rdp.go b/pkg/crack/plugins/rdp.go new file mode 100755 index 0000000..24a6cf7 --- /dev/null +++ b/pkg/crack/plugins/rdp.go @@ -0,0 +1,19 @@ +package plugins + +import ( + "fmt" + "github.com/niudaii/crack/pkg/crack/plugins/grdp" + "strings" +) + +func RdpCrack(serv *Service) int { + addr := fmt.Sprintf("%v:%v", serv.Ip, serv.Port) + err := grdp.Login(addr, "", serv.User, serv.Pass, serv.Timeout) + if err != nil { + if strings.Contains(err.Error(), "timeout") { + return CrackError + } + return CrackFail + } + return CrackSuccess +} diff --git a/pkg/crack/plugins/redis.go b/pkg/crack/plugins/redis.go new file mode 100755 index 0000000..941d534 --- /dev/null +++ b/pkg/crack/plugins/redis.go @@ -0,0 +1,28 @@ +package plugins + +import ( + "fmt" + "github.com/go-redis/redis" + "strings" + "time" +) + +func RedisCrack(serv *Service) int { + addr := fmt.Sprintf("%v:%v", serv.Ip, serv.Port) + opt := redis.Options{ + Addr: addr, + Password: serv.Pass, + DB: 0, + DialTimeout: time.Duration(serv.Timeout) * time.Second, + } + client := redis.NewClient(&opt) + defer client.Close() + _, err := client.Ping().Result() + if err != nil { + if strings.Contains(err.Error(), "timeout") { + return CrackError + } + return CrackFail + } + return CrackSuccess +} diff --git a/pkg/crack/plugins/smb.go b/pkg/crack/plugins/smb.go new file mode 100755 index 0000000..45988d7 --- /dev/null +++ b/pkg/crack/plugins/smb.go @@ -0,0 +1,30 @@ +package plugins + +import ( + "github.com/niudaii/crack/pkg/crack/plugins/smb" + "strings" +) + +func SmbCrack(serv *Service) int { + options := smb.Options{ + Host: serv.Ip, + Port: serv.Port, + User: serv.User, + Password: serv.Pass, + Domain: "", + Workstation: "", + Timeout: serv.Timeout, + } + session, err := smb.NewSession(options, false) + if err != nil { + if strings.Contains(err.Error(), "timeout") { + return CrackError + } + return CrackFail + } + session.Close() + if session.IsAuthenticated { + return CrackSuccess + } + return CrackFail +} diff --git a/pkg/crack/plugins/smb/session.go b/pkg/crack/plugins/smb/session.go new file mode 100644 index 0000000..8625ce1 --- /dev/null +++ b/pkg/crack/plugins/smb/session.go @@ -0,0 +1,394 @@ +//nolint +package smb + +import ( + "bufio" + "bytes" + "encoding/asn1" + "encoding/binary" + "encoding/hex" + "errors" + "fmt" + "io" + "log" + "net" + "runtime/debug" + "time" + + "github.com/stacktitan/smb/gss" + "github.com/stacktitan/smb/ntlmssp" + "github.com/stacktitan/smb/smb/encoder" +) + +type Session struct { + IsSigningRequired bool + IsAuthenticated bool + debug bool + securityMode uint16 + messageID uint64 + sessionID uint64 + conn net.Conn + dialect uint16 + options Options + trees map[string]uint32 +} + +type Options struct { + Host string + Port int + Workstation string + Domain string + User string + Password string + Hash string + + Timeout int +} + +func validateOptions(opt Options) error { + if opt.Host == "" { + return errors.New("Missing required option: Host") + } + if opt.Port < 1 || opt.Port > 65535 { + return errors.New("Invalid or missing value: Port") + } + return nil +} + +func NewSession(opt Options, debug bool) (s *Session, err error) { + + if err = validateOptions(opt); err != nil { + return nil, err + } + + conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", opt.Host, opt.Port), time.Duration(opt.Timeout)*time.Second) + if err != nil { + return + } + + s = &Session{ + IsSigningRequired: false, + IsAuthenticated: false, + debug: debug, + securityMode: 0, + messageID: 0, + sessionID: 0, + dialect: 0, + conn: conn, + options: opt, + trees: make(map[string]uint32), + } + + s.Debug("Negotiating protocol", nil) + err = s.NegotiateProtocol() + if err != nil { + return + } + + return s, nil +} + +func (s *Session) Debug(msg string, err error) { + if s.debug { + log.Println("[ DEBUG ] ", msg) + if err != nil { + debug.PrintStack() + } + } +} + +func (s *Session) NegotiateProtocol() error { + negReq := s.NewNegotiateReq() + s.Debug("Sending NegotiateProtocol request", nil) + buf, err := s.send(negReq) + if err != nil { + s.Debug("", err) + return err + } + + negRes := NewNegotiateRes() + s.Debug("Unmarshalling NegotiateProtocol response", nil) + if err := encoder.Unmarshal(buf, &negRes); err != nil { + s.Debug("Raw:\n"+hex.Dump(buf), err) + return err + } + + if negRes.Header.Status != StatusOk { + return fmt.Errorf(fmt.Sprintf("NT Status Error: %d\n", negRes.Header.Status)) + } + + // Check SPNEGO security blob + spnegoOID, err := gss.ObjectIDStrToInt(gss.SpnegoOid) + if err != nil { + return err + } + oid := negRes.SecurityBlob.OID + if !oid.Equal(asn1.ObjectIdentifier(spnegoOID)) { + return errors.New(fmt.Sprintf( + "Unknown security type OID [expecting %s]: %s\n", + gss.SpnegoOid, + negRes.SecurityBlob.OID)) + } + + // Check for NTLMSSP support + ntlmsspOID, err := gss.ObjectIDStrToInt(gss.NtLmSSPMechTypeOid) + if err != nil { + s.Debug("", err) + return err + } + + hasNTLMSSP := false + for _, mechType := range negRes.SecurityBlob.Data.MechTypes { + if mechType.Equal(asn1.ObjectIdentifier(ntlmsspOID)) { + hasNTLMSSP = true + break + } + } + if !hasNTLMSSP { + return errors.New("Server does not support NTLMSSP") + } + + s.securityMode = negRes.SecurityMode + s.dialect = negRes.DialectRevision + + // Determine whether signing is required + mode := uint16(s.securityMode) + if mode&SecurityModeSigningEnabled > 0 { + if mode&SecurityModeSigningRequired > 0 { + s.IsSigningRequired = true + } else { + s.IsSigningRequired = false + } + } else { + s.IsSigningRequired = false + } + + s.Debug("Sending SessionSetup1 request", nil) + ssreq, err := s.NewSessionSetup1Req() + if err != nil { + s.Debug("", err) + return err + } + ssres, err := NewSessionSetup1Res() + if err != nil { + s.Debug("", err) + return err + } + buf, err = encoder.Marshal(ssreq) + if err != nil { + s.Debug("", err) + return err + } + + buf, err = s.send(ssreq) + if err != nil { + s.Debug("Raw:\n"+hex.Dump(buf), err) + return err + } + + s.Debug("Unmarshalling SessionSetup1 response", nil) + if err := encoder.Unmarshal(buf, &ssres); err != nil { + s.Debug("", err) + return err + } + + challenge := ntlmssp.NewChallenge() + resp := ssres.SecurityBlob + if err := encoder.Unmarshal(resp.ResponseToken, &challenge); err != nil { + s.Debug("", err) + return err + } + + if ssres.Header.Status != StatusMoreProcessingRequired { + status := StatusMap[negRes.Header.Status] + return fmt.Errorf(fmt.Sprintf("NT Status Error: %s\n", status)) + } + s.sessionID = ssres.Header.SessionID + + s.Debug("Sending SessionSetup2 request", nil) + ss2req, err := s.NewSessionSetup2Req() + if err != nil { + s.Debug("", err) + return err + } + + var auth ntlmssp.Authenticate + if s.options.Hash != "" { + // Hash present, use it for auth + s.Debug("Performing hash-based authentication", nil) + auth = ntlmssp.NewAuthenticateHash(s.options.Domain, s.options.User, s.options.Workstation, s.options.Hash, challenge) + } else { + // No hash, use password + s.Debug("Performing password-based authentication", nil) + auth = ntlmssp.NewAuthenticatePass(s.options.Domain, s.options.User, s.options.Workstation, s.options.Password, challenge) + } + + responseToken, err := encoder.Marshal(auth) + if err != nil { + s.Debug("", err) + return err + } + resp2 := ss2req.SecurityBlob + resp2.ResponseToken = responseToken + ss2req.SecurityBlob = resp2 + ss2req.Header.Credits = 127 + buf, err = encoder.Marshal(ss2req) + if err != nil { + s.Debug("", err) + return err + } + + buf, err = s.send(ss2req) + if err != nil { + s.Debug("", err) + return err + } + s.Debug("Unmarshalling SessionSetup2 response", nil) + var authResp Header + if err := encoder.Unmarshal(buf, &authResp); err != nil { + s.Debug("Raw:\n"+hex.Dump(buf), err) + return err + } + if authResp.Status != StatusOk { + status := StatusMap[authResp.Status] + return errors.New(fmt.Sprintf("NT Status Error: %s\n", status)) + } + s.IsAuthenticated = true + + s.Debug("Completed NegotiateProtocol and SessionSetup", nil) + return nil +} + +func (s *Session) TreeConnect(name string) error { + s.Debug("Sending TreeConnect request ["+name+"]", nil) + req, err := s.NewTreeConnectReq(name) + if err != nil { + s.Debug("", err) + return err + } + buf, err := s.send(req) + if err != nil { + s.Debug("", err) + return err + } + var res TreeConnectRes + s.Debug("Unmarshalling TreeConnect response ["+name+"]", nil) + if err := encoder.Unmarshal(buf, &res); err != nil { + s.Debug("Raw:\n"+hex.Dump(buf), err) + return err + } + + if res.Header.Status != StatusOk { + return errors.New("Failed to connect to tree: " + StatusMap[res.Header.Status]) + } + s.trees[name] = res.Header.TreeID + + s.Debug("Completed TreeConnect ["+name+"]", nil) + return nil +} + +func (s *Session) TreeDisconnect(name string) error { + + var ( + treeid uint32 + pathFound bool + ) + for k, v := range s.trees { + if k == name { + treeid = v + pathFound = true + break + } + } + + if !pathFound { + err := errors.New("Unable to find tree path for disconnect") + s.Debug("", err) + return err + } + + s.Debug("Sending TreeDisconnect request ["+name+"]", nil) + req, err := s.NewTreeDisconnectReq(treeid) + if err != nil { + s.Debug("", err) + return err + } + buf, err := s.send(req) + if err != nil { + s.Debug("", err) + return err + } + s.Debug("Unmarshalling TreeDisconnect response for ["+name+"]", nil) + var res TreeDisconnectRes + if err := encoder.Unmarshal(buf, &res); err != nil { + s.Debug("Raw:\n"+hex.Dump(buf), err) + return err + } + if res.Header.Status != StatusOk { + return errors.New("Failed to disconnect from tree: " + StatusMap[res.Header.Status]) + } + delete(s.trees, name) + + s.Debug("TreeDisconnect completed ["+name+"]", nil) + return nil +} + +func (s *Session) Close() { + s.Debug("Closing session", nil) + for k, _ := range s.trees { + s.TreeDisconnect(k) + } + s.Debug("Closing TCP connection", nil) + s.conn.Close() + s.Debug("Session close completed", nil) +} + +func (s *Session) send(req interface{}) (res []byte, err error) { + buf, err := encoder.Marshal(req) + if err != nil { + s.Debug("", err) + return nil, err + } + + b := new(bytes.Buffer) + if err = binary.Write(b, binary.BigEndian, uint32(len(buf))); err != nil { + s.Debug("", err) + return + } + + rw := bufio.NewReadWriter(bufio.NewReader(s.conn), bufio.NewWriter(s.conn)) + if _, err = rw.Write(append(b.Bytes(), buf...)); err != nil { + s.Debug("", err) + return + } + rw.Flush() + + var size uint32 + if err = binary.Read(rw, binary.BigEndian, &size); err != nil { + s.Debug("", err) + return + } + if size > 0x00FFFFFF { + return nil, errors.New("Invalid NetBIOS Session message") + } + + data := make([]byte, size) + l, err := io.ReadFull(rw, data) + if err != nil { + s.Debug("", err) + return nil, err + } + if uint32(l) != size { + return nil, errors.New("Message size invalid") + } + + protID := data[0:4] + switch string(protID) { + default: + return nil, errors.New("Protocol Not Implemented") + case ProtocolSmb2: + } + + s.messageID++ + return data, nil +} diff --git a/pkg/crack/plugins/smb/smb.go b/pkg/crack/plugins/smb/smb.go new file mode 100644 index 0000000..ab38b96 --- /dev/null +++ b/pkg/crack/plugins/smb/smb.go @@ -0,0 +1,421 @@ +//nolint +package smb + +import ( + "errors" + "fmt" + + "github.com/stacktitan/smb/gss" + "github.com/stacktitan/smb/ntlmssp" + "github.com/stacktitan/smb/smb/encoder" +) + +const ProtocolSmb = "\xFFSMB" +const ProtocolSmb2 = "\xFESMB" + +const StatusOk = 0x00000000 +const StatusMoreProcessingRequired = 0xc0000016 +const StatusInvalidParameter = 0xc000000d +const StatusLogonFailure = 0xc000006d +const StatusUserSessionDeleted = 0xc0000203 + +var StatusMap = map[uint32]string{ + StatusOk: "OK", + StatusMoreProcessingRequired: "More Processing Required", + StatusInvalidParameter: "Invalid Parameter", + StatusLogonFailure: "Logon failed", + StatusUserSessionDeleted: "User session deleted", +} + +const DialectSmb_2_0_2 = 0x0202 +const DialectSmb_2_1 = 0x0210 +const DialectSmb_3_0 = 0x0300 +const DialectSmb_3_0_2 = 0x0302 +const DialectSmb_3_1_1 = 0x0311 +const DialectSmb2_ALL = 0x02FF + +const ( + CommandNegotiate uint16 = iota + CommandSessionSetup + CommandLogoff + CommandTreeConnect + CommandTreeDisconnect + CommandCreate + CommandClose + CommandFlush + CommandRead + CommandWrite + CommandLock + CommandIOCtl + CommandCancel + CommandEcho + CommandQueryDirectory + CommandChangeNotify + CommandQueryInfo + CommandSetInfo + CommandOplockBreak +) + +const ( + _ uint16 = iota + SecurityModeSigningEnabled + SecurityModeSigningRequired +) + +const ( + _ byte = iota + ShareTypeDisk + ShareTypePipe + ShareTypePrint +) + +const ( + ShareFlagManualCaching uint32 = 0x00000000 + ShareFlagAutoCaching uint32 = 0x00000010 + ShareFlagVDOCaching uint32 = 0x00000020 + ShareFlagNoCaching uint32 = 0x00000030 + ShareFlagDFS uint32 = 0x00000001 + ShareFlagDFSRoot uint32 = 0x00000002 + ShareFlagRestriceExclusiveOpens uint32 = 0x00000100 + ShareFlagForceSharedDelete uint32 = 0x00000200 + ShareFlagAllowNamespaceCaching uint32 = 0x00000400 + ShareFlagAccessBasedDirectoryEnum uint32 = 0x00000800 + ShareFlagForceLevelIIOplock uint32 = 0x00001000 + ShareFlagEnableHashV1 uint32 = 0x00002000 + ShareFlagEnableHashV2 uint32 = 0x00004000 + ShareFlagEncryptData uint32 = 0x00008000 +) + +const ( + ShareCapDFS uint32 = 0x00000008 + ShareCapContinuousAvailability uint32 = 0x00000010 + ShareCapScaleout uint32 = 0x00000020 + ShareCapCluster uint32 = 0x00000040 + ShareCapAsymmetric uint32 = 0x00000080 +) + +type Header struct { + ProtocolID []byte `smb:"fixed:4"` + StructureSize uint16 + CreditCharge uint16 + Status uint32 + Command uint16 + Credits uint16 + Flags uint32 + NextCommand uint32 + MessageID uint64 + Reserved uint32 + TreeID uint32 + SessionID uint64 + Signature []byte `smb:"fixed:16"` +} + +type NegotiateReq struct { + Header + StructureSize uint16 + DialectCount uint16 `smb:"count:Dialects"` + SecurityMode uint16 + Reserved uint16 + Capabilities uint32 + ClientGuid []byte `smb:"fixed:16"` + ClientStartTime uint64 + Dialects []uint16 +} + +type NegotiateRes struct { + Header + StructureSize uint16 + SecurityMode uint16 + DialectRevision uint16 + Reserved uint16 + ServerGuid []byte `smb:"fixed:16"` + Capabilities uint32 + MaxTransactSize uint32 + MaxReadSize uint32 + MaxWriteSize uint32 + SystemTime uint64 + ServerStartTime uint64 + SecurityBufferOffset uint16 `smb:"offset:SecurityBlob"` + SecurityBufferLength uint16 `smb:"len:SecurityBlob"` + Reserved2 uint32 + SecurityBlob *gss.NegTokenInit +} + +type SessionSetup1Req struct { + Header + StructureSize uint16 + Flags byte + SecurityMode byte + Capabilities uint32 + Channel uint32 + SecurityBufferOffset uint16 `smb:"offset:SecurityBlob"` + SecurityBufferLength uint16 `smb:"len:SecurityBlob"` + PreviousSessionID uint64 + SecurityBlob *gss.NegTokenInit +} + +type SessionSetup1Res struct { + Header + StructureSize uint16 + Flags uint16 + SecurityBufferOffset uint16 `smb:"offset:SecurityBlob"` + SecurityBufferLength uint16 `smb:"len:SecurityBlob"` + SecurityBlob *gss.NegTokenResp +} + +type SessionSetup2Req struct { + Header + StructureSize uint16 + Flags byte + SecurityMode byte + Capabilities uint32 + Channel uint32 + SecurityBufferOffset uint16 `smb:"offset:SecurityBlob"` + SecurityBufferLength uint16 `smb:"len:SecurityBlob"` + PreviousSessionID uint64 + SecurityBlob *gss.NegTokenResp +} + +type SessionSetup2Res struct { + Header + StructureSize uint16 + Flags uint16 + SecurityBufferOffset uint16 `smb:"offset:SecurityBlob"` + SecurityBufferLength uint16 `smb:"len:SecurityBlob"` + SecurityBlob *gss.NegTokenResp +} + +type TreeConnectReq struct { + Header + StructureSize uint16 + Reserved uint16 + PathOffset uint16 `smb:"offset:Path"` + PathLength uint16 `smb:"len:Path"` + Path []byte +} + +type TreeConnectRes struct { + Header + StructureSize uint16 + ShareType byte + Reserved byte + ShareFlags uint32 + Capabilities uint32 + MaximalAccess uint32 +} + +type TreeDisconnectReq struct { + Header + StructureSize uint16 + Reserved uint16 +} + +type TreeDisconnectRes struct { + Header + StructureSize uint16 + Reserved uint16 +} + +func newHeader() Header { + return Header{ + ProtocolID: []byte(ProtocolSmb2), + StructureSize: 64, + CreditCharge: 0, + Status: 0, + Command: 0, + Credits: 0, + Flags: 0, + NextCommand: 0, + MessageID: 0, + Reserved: 0, + TreeID: 0, + SessionID: 0, + Signature: make([]byte, 16), + } +} + +func (s *Session) NewNegotiateReq() NegotiateReq { + header := newHeader() + header.Command = CommandNegotiate + header.CreditCharge = 1 + header.MessageID = s.messageID + + dialects := []uint16{ + uint16(DialectSmb_2_1), + } + return NegotiateReq{ + Header: header, + StructureSize: 36, + DialectCount: uint16(len(dialects)), + SecurityMode: SecurityModeSigningEnabled, + Reserved: 0, + Capabilities: 0, + ClientGuid: make([]byte, 16), + ClientStartTime: 0, + Dialects: dialects, + } +} + +func NewNegotiateRes() NegotiateRes { + return NegotiateRes{ + Header: newHeader(), + StructureSize: 0, + SecurityMode: 0, + DialectRevision: 0, + Reserved: 0, + ServerGuid: make([]byte, 16), + Capabilities: 0, + MaxTransactSize: 0, + MaxReadSize: 0, + MaxWriteSize: 0, + SystemTime: 0, + ServerStartTime: 0, + SecurityBufferOffset: 0, + SecurityBufferLength: 0, + Reserved2: 0, + SecurityBlob: &gss.NegTokenInit{}, + } +} + +func (s *Session) NewSessionSetup1Req() (SessionSetup1Req, error) { + header := newHeader() + header.Command = CommandSessionSetup + header.CreditCharge = 1 + header.MessageID = s.messageID + header.SessionID = s.sessionID + + ntlmsspneg := ntlmssp.NewNegotiate(s.options.Domain, s.options.Workstation) + data, err := encoder.Marshal(ntlmsspneg) + if err != nil { + return SessionSetup1Req{}, err + } + + if s.sessionID != 0 { + return SessionSetup1Req{}, errors.New("Bad session ID for session setup 1 message") + } + + // Initial session setup request + init, err := gss.NewNegTokenInit() + if err != nil { + return SessionSetup1Req{}, err + } + init.Data.MechToken = data + + return SessionSetup1Req{ + Header: header, + StructureSize: 25, + Flags: 0x00, + SecurityMode: byte(SecurityModeSigningEnabled), + Capabilities: 0, + Channel: 0, + SecurityBufferOffset: 88, + SecurityBufferLength: 0, + PreviousSessionID: 0, + SecurityBlob: &init, + }, nil +} + +func NewSessionSetup1Res() (SessionSetup1Res, error) { + resp, err := gss.NewNegTokenResp() + if err != nil { + return SessionSetup1Res{}, err + } + ret := SessionSetup1Res{ + Header: newHeader(), + SecurityBlob: &resp, + } + return ret, nil +} + +func (s *Session) NewSessionSetup2Req() (SessionSetup2Req, error) { + header := newHeader() + header.Command = CommandSessionSetup + header.CreditCharge = 1 + header.MessageID = s.messageID + header.SessionID = s.sessionID + + ntlmsspneg := ntlmssp.NewNegotiate(s.options.Domain, s.options.Workstation) + data, err := encoder.Marshal(ntlmsspneg) + if err != nil { + return SessionSetup2Req{}, err + } + + if s.sessionID == 0 { + return SessionSetup2Req{}, errors.New("Bad session ID for session setup 2 message") + } + + // Session setup request #2 + resp, err := gss.NewNegTokenResp() + if err != nil { + return SessionSetup2Req{}, err + } + resp.ResponseToken = data + + return SessionSetup2Req{ + Header: header, + StructureSize: 25, + Flags: 0x00, + SecurityMode: byte(SecurityModeSigningEnabled), + Capabilities: 0, + Channel: 0, + SecurityBufferOffset: 88, + SecurityBufferLength: 0, + PreviousSessionID: 0, + SecurityBlob: &resp, + }, nil +} + +func NewSessionSetup2Res() (SessionSetup2Res, error) { + resp, err := gss.NewNegTokenResp() + if err != nil { + return SessionSetup2Res{}, err + } + ret := SessionSetup2Res{ + Header: newHeader(), + SecurityBlob: &resp, + } + return ret, nil +} + +// NewTreeConnectReq creates a new TreeConnect message and accepts the share name +// as input. +func (s *Session) NewTreeConnectReq(name string) (TreeConnectReq, error) { + header := newHeader() + header.Command = CommandTreeConnect + header.CreditCharge = 1 + header.MessageID = s.messageID + header.SessionID = s.sessionID + + path := fmt.Sprintf("\\\\%s\\%s", s.options.Host, name) + return TreeConnectReq{ + Header: header, + StructureSize: 9, + Reserved: 0, + PathOffset: 0, + PathLength: 0, + Path: encoder.ToUnicode(path), + }, nil +} + +func NewTreeConnectRes() (TreeConnectRes, error) { + return TreeConnectRes{}, nil +} + +func (s *Session) NewTreeDisconnectReq(treeId uint32) (TreeDisconnectReq, error) { + header := newHeader() + header.Command = CommandTreeDisconnect + header.CreditCharge = 1 + header.MessageID = s.messageID + header.SessionID = s.sessionID + header.TreeID = treeId + + return TreeDisconnectReq{ + Header: header, + StructureSize: 4, + Reserved: 0, + }, nil +} + +func NewTreeDisconnectRes() (TreeDisconnectRes, error) { + return TreeDisconnectRes{}, nil +} diff --git a/pkg/crack/plugins/ssh.go b/pkg/crack/plugins/ssh.go new file mode 100755 index 0000000..cf730b1 --- /dev/null +++ b/pkg/crack/plugins/ssh.go @@ -0,0 +1,37 @@ +package plugins + +import ( + "fmt" + "golang.org/x/crypto/ssh" + "net" + "strings" + "time" +) + +func SshCrack(serv *Service) int { + config := &ssh.ClientConfig{ + User: serv.User, + Auth: []ssh.AuthMethod{ + ssh.Password(serv.Pass), + }, + Timeout: time.Duration(serv.Timeout) * time.Second, + HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { + return nil + }, + } + client, err := ssh.Dial("tcp", fmt.Sprintf("%v:%v", serv.Ip, serv.Port), config) + if err != nil { + if strings.Contains(err.Error(), "timeout") { + return CrackError + } + return CrackFail + } + defer client.Close() + session, err := client.NewSession() + errRet := session.Run("echo zp857") + if err != nil || errRet != nil { + return CrackFail + } + defer session.Close() + return CrackSuccess +} diff --git a/pkg/crack/plugins/wmi.go b/pkg/crack/plugins/wmi.go new file mode 100755 index 0000000..c5f982b --- /dev/null +++ b/pkg/crack/plugins/wmi.go @@ -0,0 +1,18 @@ +package plugins + +import ( + "github.com/niudaii/crack/pkg/crack/plugins/wmiexec" + "strconv" + "strings" +) + +func WmiCrack(serv *Service) int { + err := wmiexec.WMIExec(serv.Ip+":"+strconv.Itoa(serv.Port), serv.User, serv.Pass, "", "", "", "", serv.Timeout, nil) + if err != nil { + if strings.Contains(err.Error(), "timeout") { + return CrackError + } + return CrackFail + } + return CrackSuccess +} diff --git a/pkg/crack/plugins/wmiexec/dcom.go b/pkg/crack/plugins/wmiexec/dcom.go new file mode 100644 index 0000000..9bee7db --- /dev/null +++ b/pkg/crack/plugins/wmiexec/dcom.go @@ -0,0 +1,592 @@ +//nolint +package wmiexec + +import ( + "bytes" + "encoding/binary" + "math" + + "github.com/C-Sto/goWMIExec/pkg/uuid" +) + +type DCOMORPCThis struct { + VersionMajor uint16 + VersionMinor uint16 + Flags uint32 + Reserved uint32 + CausalityID [16]byte + Unknown uint32 +} + +type IActProperties struct { + CntData uint32 + OBJREF OBJREF +} + +type OBJREF struct { + Signature uint32 + Flags uint32 + IID [16]byte + CUSTOMOBJREF CUSTOMOBJREF +} + +type CUSTOMOBJREF struct { + CLSID [16]byte + CBExtension uint32 + Size uint32 + IActProperties IActProperties2 +} + +//idk man, I'm doing this from the wireshark dissection, not the standard ok +type IActProperties2 struct { + TotalSize uint32 + Reserved uint32 + CustomHeader CustomHeader + Properties IAct2Properties +} + +type CustomHeader struct { + CommonHeader CommonTypeHeader + PrivateHeader PrivateHeader + TotalSize uint32 + CustomHeaderSize uint32 + Reserved uint32 + DestinationContext uint32 + NumActivationProptertyStructs uint32 + ClassInfoClsid [16]byte + ClsId ClsId +} + +type CommonTypeHeader struct { + Version byte + Endianness byte + CommonHeaderLength uint16 + Filler uint32 +} + +func NewCommonHeader1(endian int) CommonTypeHeader { + return CommonTypeHeader{ + Version: 1, + Endianness: 0x10, //little endian + CommonHeaderLength: 8, + Filler: 0xcccccccc, + } +} + +type PrivateHeader struct { + ObjectBufferLength uint32 + Filler uint32 +} + +func NewPrivateHeader(buflen uint32) PrivateHeader { + return PrivateHeader{ + ObjectBufferLength: buflen, + Filler: 0x0000, + } +} + +type ClsId struct { + PtrReferentID uint32 + PtrSizesReferentID uint32 + NULLPointer uint32 + PtrMaxCount uint32 + PtrPropertyStructGUID [16]byte + PtrPropertyStructGUID2 [16]byte + PtrPropertyStructGUID3 [16]byte + PtrPropertyStructGUID4 [16]byte + PtrPropertyStructGUID5 [16]byte + PtrPropertyStructGUID6 [16]byte + SizesPtrMaxCount uint32 + SizesPtrPropertyDataSize uint32 + SizesPtrPropertyDataSize2 uint32 + SizesPtrPropertyDataSize3 uint32 + SizesPtrPropertyDataSize4 uint32 + SizesPtrPropertyDataSize5 uint32 + SizesPtrPropertyDataSize6 uint32 +} + +type IAct2Properties struct { + SpecialSystemProperties SpecialSystemProperties + InstantiationInfo InstantiationInfo + ActivationContextInfo ActivationContextInfo + SecurityInfo SecurityInfo + LocationInfo LocationInfo + ScmRequestInfo ScmRequestInfo +} + +type SpecialSystemProperties struct { + CommonHeader CommonTypeHeader + PrivateHeader PrivateHeader + SessionID uint32 + RemoteThisSessionID uint32 + ClientImpersonating uint32 + PartitionIDPresent uint32 + DefaultAuthnLevel uint32 + PartitionGUID [16]byte + ProcessRequestFlags uint32 + OriginalClassContext uint32 + Flags uint32 + Reserved [32]byte + UnusedBuffer uint64 +} + +type InstantiationInfo struct { + CommonHeader CommonTypeHeader + PrivateHeader PrivateHeader + InstantiatedObjectClsId [16]byte + ClassContext, + ActivationFlags, + FlagsSurrogate, + InterfaceIdCount, + InstantiationFlag, + InterfaceIdsPtr, + EntirePropertySize uint32 + VersionMajor, VersionMinor uint16 + InterfaceIdsMaxCount uint32 + InterfaceIds [16]byte + UnusedBuffer uint32 +} + +type ActivationContextInfo struct { + CommonHeader CommonTypeHeader + PrivateHeader PrivateHeader + ClientOk uint32 + Reserved uint32 + Reserved2 uint32 + Reserved3 uint32 + ClientPtrReferentID uint32 + NULLPtr uint32 + ClientPtrClientContextUnknown uint32 + ClientPtrClientContextCntData uint32 + ClientPtrClientContextOBJREFSignature uint32 + ClientPtrClientContextOBJREFFlags uint32 + ClientPtrClientContextOBJREFIID [16]byte + ClientPtrClientContextOBJREFCUSTOMOBJREFCLSID [16]byte + ClientPtrClientContextOBJREFCUSTOMOBJREFCBExtension uint32 + ClientPtrClientContextOBJREFCUSTOMOBJREFSize uint32 + UnusedBuffer [48]byte +} + +type SecurityInfo struct { + CommonHeader CommonTypeHeader + PrivateHeader PrivateHeader //", packet_private_header); + AuthenticationFlags uint32 + ServerInfoPtrReferentID uint32 + NULLPtr uint32 + ServerInfoServerInfoReserved uint32 + ServerInfoServerInfoNameReferentID uint32 + ServerInfoServerInfoNULLPtr uint32 + ServerInfoServerInfoReserved2 uint32 + ServerInfoServerInfoNameMaxCount uint32 //", packet_target_length); + ServerInfoServerInfoNameOffset uint32 + ServerInfoServerInfoNameActualCount uint32 //", packet_target_length); + ServerInfoServerInfoNameString []byte // uint32//uint", packet_target_unicode); + +} + +type LocationInfo struct { + CommonHeader CommonTypeHeader + PrivateHeader PrivateHeader + NULLPtr uint32 + ProcessID uint32 + ApartmentID uint32 + ContextID uint32 +} + +type ScmRequestInfo struct { + CommonHeader CommonTypeHeader + PrivateHeader PrivateHeader + NULLPtr uint32 + RemoteRequestPtrReferentID uint32 + RemoteRequestPtrRemoteRequestClientImpersonationLevel uint32 + RemoteRequestPtrRemoteRequestNumProtocolSequences uint16 + RemoteRequestPtrRemoteRequestUnknown uint16 + RemoteRequestPtrRemoteRequestProtocolSeqsArrayPtrReferentID uint32 + RemoteRequestPtrRemoteRequestProtocolSeqsArrayPtrMaxCount uint32 + RemoteRequestPtrRemoteRequestProtocolSeqsArrayPtrProtocolSeq uint16 + UnusedBuffer [6]byte // = 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +} + +type PacketDCOMRemoteInstance struct { + /* + DCOMVersionMajor uint16 + DCOMVersionMinor uint16 + DCOMFlags uint32 + DCOMReserved uint32 + DCOMCausalityID [16]byte + Unknown uint32 + */ + DCOMORPCThis DCOMORPCThis + Unknown2 uint32 + Unknown3 uint32 + Unknown4 uint32 + IActProperties IActProperties +} + +func NewDCOMRemoteInstance(causality [16]byte, target string) PacketDCOMRemoteInstance { + r := PacketDCOMRemoteInstance{} + + targetU, _ := toUnicodeS(target) + targetL := uint32(len(target)) + 1 + + targetB := []byte(targetU) + + b := uint32(math.Trunc(float64(len(targetB))/8+1)*8 - float64(len(targetB))) + nulls := make([]byte, b) + targetB = append(targetB, nulls...) + + targetCnt := uint32(len(targetB)) + 720 + pktSize := uint32(len(targetB)) + 680 + pktTotal := uint32(len(targetB)) + 664 + privHeader := uint32(len(targetB) + 40) + propDataSize := uint32(len(targetB) + 56) + + r.DCOMORPCThis.VersionMajor = 0x05 + r.DCOMORPCThis.VersionMinor = 0x07 + r.DCOMORPCThis.Flags = 0x01 + r.DCOMORPCThis.Reserved = 0x00 + r.DCOMORPCThis.CausalityID = causality // packet_causality_ID); + r.DCOMORPCThis.Unknown = 0x00 + r.Unknown2 = 0x00 + r.Unknown3 = 0x020000 + r.Unknown4 = targetCnt //", packet_cntdata); + + r.IActProperties.CntData = targetCnt //", packet_cntdata); + r.IActProperties.OBJREF.Signature = 0x574f454d // 0x4d, 0x45, 0x4f, 0x57 + r.IActProperties.OBJREF.Flags = 0x04 + r.IActProperties.OBJREF.IID = uuid.IID_IActivationPropertiesIn + r.IActProperties.OBJREF.CUSTOMOBJREF.CLSID = uuid.CLSID_ActivationPropertiesIn + r.IActProperties.OBJREF.CUSTOMOBJREF.CBExtension = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.Size = pktSize //", packet_size); + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.TotalSize = pktTotal //", packet_total_size); + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Reserved = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.CommonHeader = NewCommonHeader1(0x10) // + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.PrivateHeader = NewPrivateHeader(0xb0) // 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.TotalSize = pktTotal //", packet_total_size); + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.CustomHeaderSize = 0xc0 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.Reserved = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.DestinationContext = 0x02 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.NumActivationProptertyStructs = 0x06 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.ClassInfoClsid = uuid.NULL + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.ClsId.PtrReferentID = 0x020000 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.ClsId.PtrSizesReferentID = 0x00020004 //0x04, 0x00, 0x02, 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.ClsId.NULLPointer = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.ClsId.PtrMaxCount = 0x06 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.ClsId.PtrPropertyStructGUID = uuid.CLSID_SpecialSystemProperties + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.ClsId.PtrPropertyStructGUID2 = uuid.CLSID_InstantiationInfo + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.ClsId.PtrPropertyStructGUID3 = uuid.CLSID_ActivationContextInfo + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.ClsId.PtrPropertyStructGUID4 = uuid.CLSID_SecurityInfo + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.ClsId.PtrPropertyStructGUID5 = uuid.CLSID_ServerLocationInfo + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.ClsId.PtrPropertyStructGUID6 = uuid.CLSID_ScmRequestInfo + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.ClsId.SizesPtrMaxCount = 0x06 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.ClsId.SizesPtrPropertyDataSize = 0x68 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.ClsId.SizesPtrPropertyDataSize2 = 0x58 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.ClsId.SizesPtrPropertyDataSize3 = 0x90 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.ClsId.SizesPtrPropertyDataSize4 = propDataSize //", packet_property_data_size); + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.ClsId.SizesPtrPropertyDataSize5 = 0x20 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.CustomHeader.ClsId.SizesPtrPropertyDataSize6 = 0x30 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SpecialSystemProperties.CommonHeader = NewCommonHeader1(0x10) // 0xcccccccc00081001 // 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SpecialSystemProperties.PrivateHeader = NewPrivateHeader(0x58) + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SpecialSystemProperties.SessionID = 0xffffffff + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SpecialSystemProperties.RemoteThisSessionID = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SpecialSystemProperties.ClientImpersonating = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SpecialSystemProperties.PartitionIDPresent = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SpecialSystemProperties.DefaultAuthnLevel = 0x02 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SpecialSystemProperties.PartitionGUID = uuid.NULL + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SpecialSystemProperties.ProcessRequestFlags = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SpecialSystemProperties.OriginalClassContext = 0x14 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SpecialSystemProperties.Flags = 0x02 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SpecialSystemProperties.Reserved = [32]byte{} // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SpecialSystemProperties.UnusedBuffer = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.InstantiationInfo.CommonHeader = NewCommonHeader1(0x10) //0xcccccccc00081001 //0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.InstantiationInfo.PrivateHeader = NewPrivateHeader(0x48) + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.InstantiationInfo.InstantiatedObjectClsId = uuid.CLSID_WMIAppID + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.InstantiationInfo.ClassContext = 0x14 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.InstantiationInfo.ActivationFlags = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.InstantiationInfo.FlagsSurrogate = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.InstantiationInfo.InterfaceIdCount = 0x01 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.InstantiationInfo.InstantiationFlag = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.InstantiationInfo.InterfaceIdsPtr = 0x0200 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.InstantiationInfo.EntirePropertySize = 0x58 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.InstantiationInfo.VersionMajor = 0x05 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.InstantiationInfo.VersionMinor = 0x07 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.InstantiationInfo.InterfaceIdsMaxCount = 0x01 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.InstantiationInfo.InterfaceIds = uuid.CLSID_WbemLevel1Login + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.InstantiationInfo.UnusedBuffer = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ActivationContextInfo.CommonHeader = NewCommonHeader1(0x10) // 0xcccccccc00081001 // 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ActivationContextInfo.PrivateHeader = NewPrivateHeader(0x80) + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ActivationContextInfo.ClientOk = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ActivationContextInfo.Reserved = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ActivationContextInfo.Reserved2 = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ActivationContextInfo.Reserved3 = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ActivationContextInfo.ClientPtrReferentID = 0x0200 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ActivationContextInfo.NULLPtr = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ActivationContextInfo.ClientPtrClientContextUnknown = 0x60 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ActivationContextInfo.ClientPtrClientContextCntData = 0x60 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ActivationContextInfo.ClientPtrClientContextOBJREFSignature = 0x574f454d // 0x4d, 0x45, 0x4f, 0x57 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ActivationContextInfo.ClientPtrClientContextOBJREFFlags = 0x04 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ActivationContextInfo.ClientPtrClientContextOBJREFIID = uuid.IID_IContext + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ActivationContextInfo.ClientPtrClientContextOBJREFCUSTOMOBJREFCLSID = uuid.CLSID_ContextMarshaler + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ActivationContextInfo.ClientPtrClientContextOBJREFCUSTOMOBJREFCBExtension = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ActivationContextInfo.ClientPtrClientContextOBJREFCUSTOMOBJREFSize = 0x30 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ActivationContextInfo.UnusedBuffer = [48]byte{0x01, 0x00, 0x01, 0x00, 0x63, 0x2c, 0x80, 0x2a, 0xa5, 0xd2, 0xaf, 0xdd, 0x4d, 0xc4, 0xbb, 0x37, 0x4d, 0x37, 0x76, 0xd7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00} + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SecurityInfo.CommonHeader = NewCommonHeader1(0x10) // 0xcccccccc00081001 // 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SecurityInfo.PrivateHeader = NewPrivateHeader(privHeader) //", packet_private_header); + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SecurityInfo.AuthenticationFlags = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SecurityInfo.ServerInfoPtrReferentID = 0x0200 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SecurityInfo.NULLPtr = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SecurityInfo.ServerInfoServerInfoReserved = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SecurityInfo.ServerInfoServerInfoNameReferentID = 0x00020004 // 0x04, 0x00, 0x02, 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SecurityInfo.ServerInfoServerInfoNULLPtr = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SecurityInfo.ServerInfoServerInfoReserved2 = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SecurityInfo.ServerInfoServerInfoNameMaxCount = targetL // ", packet_target_length); + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SecurityInfo.ServerInfoServerInfoNameOffset = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SecurityInfo.ServerInfoServerInfoNameActualCount = targetL //", packet_target_length); + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SecurityInfo.ServerInfoServerInfoNameString = make([]byte, len(targetB)) //", packet_target_unicode); + copy(r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.SecurityInfo.ServerInfoServerInfoNameString[:], targetB) + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.LocationInfo.CommonHeader = NewCommonHeader1(0x10) //0xcccccccc00081001 //0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.LocationInfo.PrivateHeader = NewPrivateHeader(0x10) //0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.LocationInfo.NULLPtr = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.LocationInfo.ProcessID = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.LocationInfo.ApartmentID = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.LocationInfo.ContextID = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ScmRequestInfo.CommonHeader = NewCommonHeader1(0x10) // 0xcccccccc00081001 // 0x01, 0x10, 0x08, 0x00, 0xcc, 0xcc, 0xcc, 0xcc + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ScmRequestInfo.PrivateHeader = NewPrivateHeader(0x20) + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ScmRequestInfo.NULLPtr = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ScmRequestInfo.RemoteRequestPtrReferentID = 0x0200 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ScmRequestInfo.RemoteRequestPtrRemoteRequestClientImpersonationLevel = 0x02 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ScmRequestInfo.RemoteRequestPtrRemoteRequestNumProtocolSequences = 0x01 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ScmRequestInfo.RemoteRequestPtrRemoteRequestUnknown = 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ScmRequestInfo.RemoteRequestPtrRemoteRequestProtocolSeqsArrayPtrReferentID = 0x00020004 // 0x04, 0x00, 0x02, 0x00 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ScmRequestInfo.RemoteRequestPtrRemoteRequestProtocolSeqsArrayPtrMaxCount = 0x01 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ScmRequestInfo.RemoteRequestPtrRemoteRequestProtocolSeqsArrayPtrProtocolSeq = 0x07 + r.IActProperties.OBJREF.CUSTOMOBJREF.IActProperties.Properties.ScmRequestInfo.UnusedBuffer = [6]byte{} + return r +} + +func (p PacketDCOMRemoteInstance) Bytes() []byte { + buff := bytes.Buffer{} + binary.Write(&buff, binary.LittleEndian, p.DCOMORPCThis) + binary.Write(&buff, binary.LittleEndian, p.Unknown2) + binary.Write(&buff, binary.LittleEndian, p.Unknown3) + binary.Write(&buff, binary.LittleEndian, p.Unknown4) + binary.Write(&buff, binary.LittleEndian, p.IActProperties.Bytes()) + return buff.Bytes() +} + +func (i IActProperties) Bytes() []byte { + buff := bytes.Buffer{} + binary.Write(&buff, binary.LittleEndian, i.CntData) + binary.Write(&buff, binary.LittleEndian, i.OBJREF.Signature) + binary.Write(&buff, binary.LittleEndian, i.OBJREF.Flags) + binary.Write(&buff, binary.LittleEndian, i.OBJREF.IID) + binary.Write(&buff, binary.LittleEndian, i.OBJREF.CUSTOMOBJREF.Bytes()) + + return buff.Bytes() +} + +func (i CUSTOMOBJREF) Bytes() []byte { + buff := bytes.Buffer{} + binary.Write(&buff, binary.LittleEndian, i.CLSID) + binary.Write(&buff, binary.LittleEndian, i.CBExtension) + binary.Write(&buff, binary.LittleEndian, i.Size) + binary.Write(&buff, binary.LittleEndian, i.IActProperties.Bytes()) + + return buff.Bytes() +} + +func (i IActProperties2) Bytes() []byte { + buff := bytes.Buffer{} + binary.Write(&buff, binary.LittleEndian, i.TotalSize) + binary.Write(&buff, binary.LittleEndian, i.Reserved) + binary.Write(&buff, binary.LittleEndian, i.CustomHeader) + binary.Write(&buff, binary.LittleEndian, i.Properties.SpecialSystemProperties) + binary.Write(&buff, binary.LittleEndian, i.Properties.InstantiationInfo) + binary.Write(&buff, binary.LittleEndian, i.Properties.ActivationContextInfo) + binary.Write(&buff, binary.LittleEndian, i.Properties.SecurityInfo.Bytes()) + binary.Write(&buff, binary.LittleEndian, i.Properties.LocationInfo) + binary.Write(&buff, binary.LittleEndian, i.Properties.ScmRequestInfo) + + return buff.Bytes() +} + +func (i SecurityInfo) Bytes() []byte { + buff := bytes.Buffer{} + binary.Write(&buff, binary.LittleEndian, i.CommonHeader) + binary.Write(&buff, binary.LittleEndian, i.PrivateHeader) + binary.Write(&buff, binary.LittleEndian, i.AuthenticationFlags) + binary.Write(&buff, binary.LittleEndian, i.ServerInfoPtrReferentID) + binary.Write(&buff, binary.LittleEndian, i.NULLPtr) + binary.Write(&buff, binary.LittleEndian, i.ServerInfoServerInfoReserved) + binary.Write(&buff, binary.LittleEndian, i.ServerInfoServerInfoNameReferentID) + binary.Write(&buff, binary.LittleEndian, i.ServerInfoServerInfoNULLPtr) + binary.Write(&buff, binary.LittleEndian, i.ServerInfoServerInfoReserved2) + binary.Write(&buff, binary.LittleEndian, i.ServerInfoServerInfoNameMaxCount) + binary.Write(&buff, binary.LittleEndian, i.ServerInfoServerInfoNameOffset) + binary.Write(&buff, binary.LittleEndian, i.ServerInfoServerInfoNameActualCount) + binary.Write(&buff, binary.LittleEndian, i.ServerInfoServerInfoNameString) + return buff.Bytes() +} + +type PacketDCOMRemQueryInterface struct { + VersionMajor uint16 + VersionMinor uint16 + Flags uint32 + Reserved uint32 + CausalityID [16]byte + Reserved2 uint32 + IPID [16]byte + Refs uint32 + IIDs uint16 + Unknown [6]byte + IID [16]byte +} + +func NewPacketDCOMRemQueryInterface(causalityID, IPID, IID []byte) PacketDCOMRemQueryInterface { + r := PacketDCOMRemQueryInterface{ + VersionMajor: 5, + VersionMinor: 7, + Flags: 0, + Reserved: 0, + //CausalityID: + Reserved2: 0, + //IPID: + Refs: 5, + IIDs: 1, + Unknown: [6]byte{0, 0, 1, 0, 0, 0}, + } + copy(r.CausalityID[:], causalityID) + copy(r.IPID[:], IPID) + copy(r.IID[:], IID) + return r +} + +func (p PacketDCOMRemQueryInterface) Bytes() []byte { + buff := bytes.Buffer{} + binary.Write(&buff, binary.LittleEndian, p) + return buff.Bytes() +} + +type PacketDCOMMemRelease struct { + VersionMajor uint16 + VersionMinor uint16 + Flags uint32 + Reserved uint32 + CausalityID [16]byte + Reserved2 uint32 + Unknown uint32 + InterfaceRefs uint32 + IPID [16]byte + PublicRefs uint32 + PrivateRefs uint32 + packetIPID2 [16]byte + PublicRefs2 uint32 + PrivateRefs2 uint32 +} + +func NewPacketDCOMMemRelease(causality, ipid, ipid2 []byte) PacketDCOMMemRelease { + r := PacketDCOMMemRelease{ + VersionMajor: 0x05, + VersionMinor: 0x07, + Flags: 0x00, + Reserved: 0x00, + //CausalityID: packet_causality_ID); + Reserved2: 0x00, + Unknown: 0x02, + InterfaceRefs: 0x02, + //IPID: packet_IPID); + PublicRefs: 0x05, + PrivateRefs: 0x00, + //packet_IPID2: packet_IPID2); + PublicRefs2: 0x05, + PrivateRefs2: 0x00, + } + + copy(r.CausalityID[:], causality) + copy(r.IPID[:], ipid) + copy(r.packetIPID2[:], ipid2) + + return r +} + +func (p PacketDCOMMemRelease) Bytes() []byte { + buff := bytes.Buffer{} + binary.Write(&buff, binary.LittleEndian, p) + return buff.Bytes() +} + +type DCOMOXIDResolver struct { + VersionMajor uint16 + VersionMinor uint16 + Unknown [8]byte + NumEntries uint16 + SecurityOffset uint16 + StringBindings []DCOMStringBinding + SecurityBindings []DCOMSecurityBinding + Unknown2 [8]byte +} + +type DCOMSecurityBinding struct { + AuthnSvc uint16 + AuthzSvc uint16 + PrincName []byte +} + +type DCOMStringBinding struct { + TowerId uint16 + NetworkAddr []byte +} + +func NewDCOMOXIDResolver(b []byte) DCOMOXIDResolver { + r := DCOMOXIDResolver{} + cursor := 0 + r.VersionMajor = binary.LittleEndian.Uint16(b[cursor : cursor+2]) + cursor += 2 + r.VersionMajor = binary.LittleEndian.Uint16(b[cursor : cursor+2]) + cursor += 2 + copy(r.Unknown[:], b[cursor:cursor+8]) + cursor += 8 + + r.NumEntries = binary.LittleEndian.Uint16(b[cursor : cursor+2]) + cursor += 2 + r.SecurityOffset = binary.LittleEndian.Uint16(b[cursor : cursor+2]) + cursor += 2 + + for !bytes.HasPrefix(b[cursor:], []byte{0, 0}) { + newBind := DCOMStringBinding{} + newBind.TowerId = binary.LittleEndian.Uint16(b[cursor : cursor+2]) + cursor += 2 + //yep, scan to double null top kek + if bytes.HasPrefix(b[cursor:], []byte{0, 0}) { + newBind.NetworkAddr = []byte{0, 0} + cursor += 2 + } else { + end := bytes.Index(b[cursor:], []byte{0, 0, 0}) + newBind.NetworkAddr = b[cursor : end+cursor+1] + cursor += end + 3 + } + r.StringBindings = append(r.StringBindings, newBind) + } + cursor += 2 + + for !bytes.HasPrefix(b[cursor:], []byte{0, 0}) { + newBind := DCOMSecurityBinding{} + newBind.AuthnSvc = binary.LittleEndian.Uint16(b[cursor : cursor+2]) + cursor += 2 + newBind.AuthzSvc = binary.LittleEndian.Uint16(b[cursor : cursor+2]) + cursor += 2 + //yep, scan to double null top kek + if bytes.HasPrefix(b[cursor:], []byte{0, 0}) { + newBind.PrincName = []byte{0, 0} + cursor += 2 + } else { + end := bytes.Index(b[cursor:], []byte{0, 0, 0}) + newBind.PrincName = b[cursor : end+cursor] + cursor += end + 1 + } + r.SecurityBindings = append(r.SecurityBindings, newBind) + } + cursor += 2 + + return r +} diff --git a/pkg/crack/plugins/wmiexec/wmiexec.go b/pkg/crack/plugins/wmiexec/wmiexec.go new file mode 100644 index 0000000..dd96a48 --- /dev/null +++ b/pkg/crack/plugins/wmiexec/wmiexec.go @@ -0,0 +1,821 @@ +//nolint +package wmiexec + +import ( + "bytes" + "errors" + "io" + + "github.com/C-Sto/goWMIExec/pkg/ntlmssp" + + "github.com/C-Sto/goWMIExec/pkg/rpce" + + "github.com/C-Sto/goWMIExec/pkg/uuid" + + "go.uber.org/zap/zapcore" + + "encoding/binary" + "encoding/hex" + "fmt" + "math/rand" + "net" + "strconv" + "strings" + "time" + + "go.uber.org/zap" + "golang.org/x/text/encoding/unicode" +) + +//var logger, logerr = zap.NewProduction() +//var sugar = logger.Sugar() + +type WmiExecConfig struct { + username, password, hash, domain string + targetAddress, clientHostname string + timeout int + + verbose bool + logger *zap.Logger +} + +func NewExecConfig(username, password, hash, domain, target, clientHostname string, timeout int, verbose bool, logger *zap.Logger, writer io.Writer) (WmiExecConfig, error) { + r := WmiExecConfig{} + + if logger == nil && writer == nil { + //default logger + //r.logger = zap.new + var err error + cfg := zap.NewProductionConfig() + cfg.Encoding = "console" + logger, err = cfg.Build() + if err != nil { + return r, err + } + r.logger = logger + } else if writer != nil && logger == nil { + writeser := zapcore.AddSync(writer) + customWriter := zapcore.Lock(writeser) + c := zapcore.NewConsoleEncoder(zap.NewProductionEncoderConfig()) + core := zapcore.NewCore(c, customWriter, zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { + return lvl < zapcore.ErrorLevel + })) + logger = zap.New(core) + + } + + clientHostname = strings.ToUpper(clientHostname) + if len(clientHostname) > 16 { + clientHostname = clientHostname[:15] + r.logger.Sugar().Infof("Hostname too long (over 16 chars). Using first 15 chars: %s", clientHostname) + } + + unihn, err := toUnicodeS(clientHostname) + if err != nil { + return WmiExecConfig{}, err + } + + r = WmiExecConfig{ + username: username, password: password, hash: hash, domain: domain, + targetAddress: target, clientHostname: unihn, + timeout: timeout, + verbose: verbose, + logger: logger, + } + + return r, nil +} + +type wmiExecer struct { + log *zap.SugaredLogger + logProper *zap.Logger + config *WmiExecConfig + tcpClient net.Conn + + timeout int + + targetHostname string + targetRPCPort int + assGroup uint32 + objectUUID []byte + causality []byte + ipid []byte + clientSigningKey []byte + oxid []byte + objUUID2 []byte + + stage string +} + +func NewExecer(cfg *WmiExecConfig) *wmiExecer { + r := wmiExecer{ + log: cfg.logger.Sugar(), + logProper: cfg.logger, + config: cfg, + stage: "exit", + timeout: cfg.timeout, + } + + return &r +} + +func (e *wmiExecer) Connect() error { + var err error + + e.tcpClient, err = net.DialTimeout("tcp", e.config.targetAddress, time.Duration(e.timeout)*time.Second) + if err != nil { + //e.log.Error(err.Error()) + return err + } + err = e.tcpClient.SetReadDeadline(time.Now().Add(time.Duration(e.timeout) * time.Second)) + if err != nil { + return err + } + defer e.tcpClient.Close() + + //Hello, please are you ok to connect? + //we seem to be using the iobjectexporter abstract syntax... whatever that means? + abs := rpce.NewPSyntaxID(uuid.IID_IObjectExporter, 0) + + ctxList := rpce.NewPcontextList() + ctxList.AddContext( //I tried to make it neater... I failed :( + rpce.NewPcontextElem( + 0, + abs, + []rpce.PSyntaxID{ + rpce.NewPSyntaxID(uuid.NDRTransferSyntax_V2, 2), + }, + ), + ) + + ctxList.AddContext( //I tried to make it neater... I failed :( + rpce.NewPcontextElem( + 0, + abs, + []rpce.PSyntaxID{ + rpce.NewPSyntaxID(uuid.BindTimeFeatureReneg, 0x01000000), + }, + ), + ) + packetRPC := rpce.NewBindReq(2, ctxList, nil) + + recv := make([]byte, 2048) + + e.tcpClient.Write(packetRPC.Bytes()) + e.tcpClient.Read(recv) + recvHdr := rpce.CommonHead{} + + binary.Read(bytes.NewReader(recv), binary.LittleEndian, &recvHdr) + + if recvHdr.PacketType != 12 { + //e.log.Info("No, can't connect soz lol") + return errors.New("Got an unexpected response. Wanted 12 (0x0c) got ") + } + + //cool, can we auth? + packetRPCReq := rpce.NewRequestReq(2, 0, 5, nil, nil) + e.tcpClient.Write(packetRPCReq.Bytes()) + + e.tcpClient.Read(recv) + if err != nil { + //e.log.Error("Error reading tcp thing") + return err + } + + //e.log.Info("Successfully connected to host and sent an RPC request packet") + // rsp := NewDCOMResponse(recv[:n]) + recvHdr = rpce.CommonHead{} + readr := bytes.NewReader(recv) + binary.Read(readr, binary.LittleEndian, &recvHdr) + if recvHdr.PacketType != 2 { + return fmt.Errorf("Got an unexpected response. Wanted 0x02 got %x", recvHdr.PacketType) + } + rsp := rpce.ParseResponse(recv) + + resolved := NewDCOMOXIDResolver(rsp.StubData) + + //e.log.Infof("Resolved names, all network string bindings for host:") + for _, x := range resolved.StringBindings { + //decode for output to user (this should probably be in main... whatever) + dcoder := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewDecoder() + _, er := dcoder.Bytes(x.NetworkAddr) + if er != nil { + //e.log.Error(er.Error()) + continue + } + //e.log.Infof("\t%v", string(b)) //strs = append(strs, unicode.UTF16( // string(x.NetworkAddr)) + } + + b, err := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewDecoder().Bytes(resolved.StringBindings[0].NetworkAddr) + if err != nil { + //e.log.Error("Couldn't decode hostname from response") + return err + } + //e.log.Info("Using first value as target hostname: ", string(b)) + e.targetHostname = string(b) + return nil +} + +func (e *wmiExecer) Auth() error { + var err error + e.tcpClient, err = net.DialTimeout("tcp", e.config.targetAddress, time.Duration(e.timeout)*time.Second) + if err != nil { + return err + } + err = e.tcpClient.SetReadDeadline(time.Now().Add(time.Duration(e.timeout) * time.Second)) + if err != nil { + return err + } + defer e.tcpClient.Close() + + //ey, can I please talk to SCM? I will use NTLM SSP to auth.. + ctxList := rpce.NewPcontextList() + ctxList.AddContext(rpce.NewPcontextElem( + 1, + rpce.NewPSyntaxID(uuid.IID_IRemoteSCMActivator, 0), + []rpce.PSyntaxID{ + rpce.NewPSyntaxID(uuid.NDRTransferSyntax_V2, 2), + }, + )) + + flags := ntlmssp.NTLMSSP_NEGOTIATE_UNICODE | ntlmssp.NTLM_NEGOTIATE_OEM | + ntlmssp.NTLMSSP_REQUEST_TARGET | ntlmssp.NTLMSSP_NEGOTIATE_NTLM | + ntlmssp.NTLMSSP_NEGOTIATE_ALWAYS_SIGN | ntlmssp.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | + ntlmssp.NTLMSSP_NEGOTIATE_VERSION | ntlmssp.NTLMSSP_NEGOTIATE_128 | + ntlmssp.NTLMSSP_NEGOTIATE_56 + n := ntlmssp.NewSSPNegotiate(flags) //todo: make this flags... value below + + auth := rpce.NewAuthVerifier( + rpce.RPC_C_AUTHN_WINNT, + rpce.RPC_C_AUTHN_LEVEL_CONNECT, + 0, + n.Bytes(), + ) + + packetRPC := rpce.NewBindReq(3, ctxList, &auth) + recv := make([]byte, 2048) + e.tcpClient.Write(packetRPC.Bytes()) + + e.tcpClient.Read(recv) + + //should probably check here that it's not an error + bindAck := rpce.ParseBindAck(recv) + + challengeInfo := ntlmssp.ParseSSPChallenge(bindAck.AuthVerifier.AuthValue) + ntlmChal := challengeInfo.ServerChallenge[:] + deets := challengeInfo.Payload.GetTargetInfoBytes() + timebytes := challengeInfo.Payload.GetTimeBytes() + + hostname := e.config.clientHostname + + domain := []byte(e.config.domain) + uniuser, err := toUnicodeS(e.config.username) + if err != nil { + return err + } + username := []byte(uniuser) + + key1, err := ntlmssp.NTLMV2Hash(e.config.password, string(e.config.hash), e.config.username, string(e.config.domain)) + if err != nil { + return err + } + + ntlmResp := ntlmssp.NTLMV2Response(key1, ntlmChal, timebytes, deets) + sspResp := ntlmssp.NewSSPAuthenticate(ntlmResp, domain, username, []byte(hostname), nil).Bytes() + + packetAuth := rpce.NewAuth3Req(3, rpce.RPC_C_AUTHN_LEVEL_CONNECT, sspResp) + prepBytes2 := packetAuth.Bytes() + e.tcpClient.Write(prepBytes2) + + cause_id_bytes := [16]byte{} + rand.Seed(time.Now().UnixNano()) + rand.Read(cause_id_bytes[:]) + + dcomThing := NewDCOMRemoteInstance(cause_id_bytes, e.config.targetAddress) + + p := rpce.NewRequestReq(3, 1, 4, dcomThing.Bytes(), nil) + //fmt.Println(pp) + prepBytes3 := p.Bytes() + recv3 := make([]byte, 2048) + e.tcpClient.Write(prepBytes3) + e.tcpClient.Read(recv3) + + if recv3[2] == 3 { + pf := rpce.ParseFault(recv3) + //e.log.Error("Error: ", pf.StatusString(), " ", pf.Status) + return errors.New(pf.StatusString()) + } + + //should probably check here that it's not an error + rsp := rpce.ParseResponse(recv3) + + //if rsp.CommonHead.PacketType == 2 { + //e.log.Info("WMI Access possible!") + //} + + unihn, err := toUnicodeS(e.targetHostname + "[") + if err != nil { + return err + } + targ := "\x07\x00" + unihn + tgtIndex := bytes.Index(rsp.StubData, []byte(targ)) + portString := rsp.StubData[tgtIndex+len(unihn)+2 : tgtIndex+len(unihn)+12] + s, err := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewDecoder().String(string(portString)) + if err != nil { + return err + } + portNum, err := strconv.Atoi(s) + if err != nil { + return err + } + if portNum == 0 { + //e.log.Error("Got portNum 0.") + return fmt.Errorf("did not expect port number to be 0") + } + + //meow... MS must have been smoking crack when this was developed + meowSig, _ := hex.DecodeString("4D454F570100000018AD09F36AD8D011A07500C04FB68820") + meowIndex := bytes.Index(rsp.StubData, meowSig) + ipid := rsp.StubData[meowIndex+48 : meowIndex+64] + e.oxid = rsp.StubData[meowIndex+32 : meowIndex+40] + oxid2Index := bytes.Index(rsp.StubData[meowIndex+100:], e.oxid) + objUUID := rsp.StubData[meowIndex+100+oxid2Index+12 : meowIndex+100+oxid2Index+28] + e.targetRPCPort = portNum + e.causality = cause_id_bytes[:] + e.ipid = ipid + e.objectUUID = objUUID + + return nil +} + +func (e *wmiExecer) RPCConnect() error { + var err error + //e.log.Infof("Connecting to %s:%d", e.config.targetAddress[:strings.Index(e.config.targetAddress, ":")], e.targetRPCPort) + + //this is 'intentionally' left open (no deferred close!). This is the channel we send stuff on after RPC has been connected, so it needs to persist. + //I should probably determine a better way to make sure it closes gracefully. Alas. + e.tcpClient, err = net.DialTimeout("tcp", fmt.Sprintf("%s:%d", e.config.targetAddress[:strings.Index(e.config.targetAddress, ":")], e.targetRPCPort), time.Duration(e.timeout)*time.Second) + if err != nil { + return err + } + err = e.tcpClient.SetReadDeadline(time.Now().Add(time.Duration(e.timeout) * time.Second)) + if err != nil { + return err + } + ctxList := rpce.NewPcontextList() + ctxList.AddContext(rpce.NewPcontextElem( + 0, + rpce.NewPSyntaxID(uuid.IID_IRemUnknown2, 0), + []rpce.PSyntaxID{ + rpce.NewPSyntaxID(uuid.NDRTransferSyntax_V2, 2), + }, + )) + + ctxList.AddContext(rpce.NewPcontextElem( + 1, + rpce.NewPSyntaxID(uuid.IID_IRemUnknown2, 0), + []rpce.PSyntaxID{ + rpce.NewPSyntaxID(uuid.NDR64TransferSyntax, 0x01000000), + }, + )) + + ctxList.AddContext(rpce.NewPcontextElem( + 0x0200, //unsure of the signifigance of this value.. + rpce.NewPSyntaxID(uuid.IID_IRemUnknown2, 0), + []rpce.PSyntaxID{ + rpce.NewPSyntaxID(uuid.BindTimeFeatureReneg, 0x01000000), + }, + )) + + flags := ntlmssp.NTLMSSP_NEGOTIATE_UNICODE | ntlmssp.NTLM_NEGOTIATE_OEM | + ntlmssp.NTLMSSP_REQUEST_TARGET | ntlmssp.NTLMSSP_NEGOTIATE_SIGN | + ntlmssp.NTLMSSP_NEGOTIATE_LM_KEY | ntlmssp.NTLMSSP_NEGOTIATE_NTLM | + ntlmssp.NTLMSSP_NEGOTIATE_ALWAYS_SIGN | ntlmssp.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | + ntlmssp.NTLMSSP_NEGOTIATE_VERSION | ntlmssp.NTLMSSP_NEGOTIATE_128 | + ntlmssp.NTLMSSP_NEGOTIATE_56 + n := ntlmssp.NewSSPNegotiate(flags) + + auth := rpce.NewAuthVerifier( + rpce.RPC_C_AUTHN_WINNT, + rpce.RPC_C_AUTHN_LEVEL_PKT, + 0, + n.Bytes(), + ) + bindPacket := rpce.NewBindReq(2, ctxList, &auth) + + recv := make([]byte, 2048) + e.tcpClient.Write(bindPacket.Bytes()) + e.tcpClient.Read(recv) + + rsp := rpce.ParseBindAck(recv) + + //e.assGroup = binary.LittleEndian.Uint32(recv[20:24]) + e.assGroup = rsp.AssocGroupID + challengeInfo := ntlmssp.ParseSSPChallenge(rsp.AuthVerifier.AuthValue) + ntlmChal := challengeInfo.ServerChallenge[:] + deets := challengeInfo.Payload.GetTargetInfoBytes() + timebytes := challengeInfo.Payload.GetTimeBytes() + + hostname := e.config.clientHostname + + domain := []byte(e.config.domain) + uniuser, err := toUnicodeS(e.config.username) + if err != nil { + return err + } + username := []byte(uniuser) + + key1, err := ntlmssp.NTLMV2Hash(e.config.password, string(e.config.hash), e.config.username, string(e.config.domain)) + if err != nil { + return err + } + + ntlmResp := ntlmssp.NTLMV2Response(key1, ntlmChal, timebytes, deets) + sspResp := ntlmssp.NewSSPAuthenticate(ntlmResp, domain, username, []byte(hostname), nil).Bytes() + packetAuth := rpce.NewAuth3Req(3, rpce.RPC_C_AUTHN_LEVEL_PKT, sspResp) + + e.tcpClient.Write(packetAuth.Bytes()) + + packetRemQ := NewPacketDCOMRemQueryInterface(e.causality, e.ipid, uuid.IID_IWbemLoginClientID[:]) + + //the empty value at the end is a placeholder for the message signature struct, to ensure the length offsets are all correct. + authv := rpce.NewAuthVerifier(0x0a, 4, 0, make([]byte, 16)) + + packetRPC := rpce.NewRequestReq(2, 0, 3, append(e.objectUUID, packetRemQ.Bytes()...), &authv) + packetRPC.CommonHead.PFCFlags = 0x83 + + e.clientSigningKey = ntlmssp.GenerateClientSigningKey(key1, ntlmResp) + + messagesig := ntlmssp.NewMessageSignature(packetRPC.AuthBytes(), e.clientSigningKey, 0) + + authv.AuthValue = messagesig.Bytes() + wmiClientSend := packetRPC.Bytes() + e.tcpClient.Write(wmiClientSend) + recv3 := make([]byte, 2048) + e.tcpClient.Read(recv3) + + resp := rpce.ParseResponse(recv3) + + if resp.CommonHead.PacketType == 3 { + pf := rpce.ParseFault(recv3) + //log maybe + //e.log.Error("Error: ", pf.StatusString(), pf.Status) + return errors.New(pf.StatusString()) + } + + e.objUUID2 = make([]byte, 16) + if resp.CommonHead.PacketType == 2 { + oxidInd := bytes.Index(resp.StubData, e.oxid) + e.objUUID2 = resp.StubData[oxidInd+16 : oxidInd+32] + e.stage = "AlterContext" + } else { + return fmt.Errorf("Did not receive expected value. Wanted 2, got %d", recv3[2]) + } + + return nil + +} + +func (e *wmiExecer) Exec(command string) error { + + sequence := uint32(0) + + var stubData, ipid2 []byte + var callID uint32 + var contextID, opNum uint16 + var rqUUID []byte + resp := make([]byte, 2048) + for e.stage != "exit" { + if resp[2] == 3 { + pf := rpce.ParseFault(resp) + //e.log.Error("Error: ", pf.StatusString(), pf.Status) + return errors.New(pf.StatusString()) + } + switch e.stage { + case "AlterContext": + acID := uint32(0) + acConID := uint16(0) + acUUID := uuid.UUID{} + + switch sequence { + case 0: + acID = 3 + acConID = 2 + acUUID = uuid.IID_IWbemLoginClientID + case 1: + acID = 4 + acConID = 3 + acUUID = uuid.CLSID_WbemLevel1Login + + case 6: + acID = 9 + acConID = 4 + acUUID = uuid.IID_IWbemServices + } + + ctxList := rpce.NewPcontextList() + ctxList.AddContext(rpce.NewPcontextElem( + acConID, + rpce.NewPSyntaxID(acUUID, 0), + []rpce.PSyntaxID{ + rpce.NewPSyntaxID(uuid.NDRTransferSyntax_V2, 2), + }, + )) + packetRPC := rpce.NewAlterContextReq( + acID, + e.assGroup, + ctxList, + nil) + e.tcpClient.Write(packetRPC.Bytes()) + resp = make([]byte, 2048) + e.tcpClient.Read(resp) + e.stage = "Request" + + case "Request": + nextStage := "Request" + switch sequence { + case 0: + sequence = 1 + callID = 3 + contextID = 2 + opNum = 3 + rqUUID = e.objUUID2 + s, ee := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewDecoder().String(e.config.clientHostname) + if ee != nil { + return ee + } + + hnLen := uint32(len(s) + 1) + hnBytes := append([]byte(e.config.clientHostname), 0, 0) + type setClientInfo struct { + VersionMajor uint16 + VersionMinor uint16 + } + stubData = []byte{ + 0x05, 0x00, //version major + 0x07, 0x00, //version minor + 0x00, 0x00, 0x00, 0x00, //flags + 0x00, 0x00, 0x00, 0x00, //reserved + } + stubData = append(stubData, e.causality...) //causality (obviously), which is a 16 byte value + + //extent array? https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dcom/87f24bd8-83dd-49a5-a9e8-bfb1b023abc0 + stubData = append(stubData, + 0, 0, 0, 0, //size? + 0, 0, 2, 0) // ??? reserved?? + hnLenByte := make([]byte, 4) + binary.LittleEndian.PutUint32(hnLenByte, hnLen) + stubData = append(stubData, hnLenByte...) //32bit length (assume this is maxlen) + stubData = append(stubData, 0, 0, 0, 0) //32 bit nulls (pointer to first value) + stubData = append(stubData, hnLenByte...) //32bit length (assume this is actuallen) + stubData = append(stubData, hnBytes...) //actual name + //processID + pid := []byte{0, 0} + rand.Read(pid) + stubData = append(stubData, pid...) //pid (ofc) + stubData = append(stubData, 0, 0, 0, 0, 0, 0) //6 bytes of null? + nextStage = "AlterContext" + + case 1: + sequence = 2 + callID = 4 + contextID = 3 + rqUUID = e.ipid + stubData = []byte{0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + stubData = append(stubData, e.causality...) + stubData = append(stubData, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + + case 2: + sequence = 3 + callID = 5 + contextID = 3 + opNum = 6 + rqUUID = e.ipid + wminameLen := uint32(len(e.targetHostname) + 14) + hnLenByte := make([]byte, 4) + binary.LittleEndian.PutUint32(hnLenByte, wminameLen) + wmiNameStr, err := toUnicodeS("\\\\" + e.targetHostname + "\\root\\cimv2") + if err != nil { + return err + } + wmiNameUni := []byte(wmiNameStr) + wmiNameUni = append(wmiNameUni, 0, 0) + + stubData = []byte{0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + stubData = append(stubData, e.causality...) + stubData = append(stubData, 0, 0, 0, 0, 0, 0, 2, 0) + stubData = append(stubData, hnLenByte...) + stubData = append(stubData, 0, 0, 0, 0) + stubData = append(stubData, hnLenByte...) + stubData = append(stubData, wmiNameUni...) + stubData = append(stubData, 0x04, 0x00, 0x02, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x2d, 0x00, 0x55, 0x00, 0x53, 0x00, 0x2c, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + + case 3: + sequence = 4 + contextID = 0 + callID = 6 + opNum = 5 + rqUUID = e.objectUUID + oxidID := bytes.Index(resp, e.oxid) + ipid2 = resp[oxidID+16 : oxidID+32] + pktMemRelease := NewPacketDCOMMemRelease(e.causality, e.objUUID2, e.ipid) + stubData = pktMemRelease.Bytes() + + case 4: + sequence = 5 + contextID = 0 + callID = 7 + opNum = 3 + rqUUID = e.objectUUID + remqry := NewPacketDCOMRemQueryInterface(e.causality, ipid2, []byte{0x9e, 0xc1, 0xfc, 0xc3, 0x70, 0xa9, 0xd2, 0x11, 0x8b, 0x5a, 0x00, 0xa0, 0xc9, 0xb7, 0xc9, 0xc4}) + stubData = remqry.Bytes() + + case 5: + sequence = 6 + callID = 8 + contextID = 0 + opNum = 3 + rqUUID = e.objectUUID + nextStage = "AlterContext" + remqry := NewPacketDCOMRemQueryInterface(e.causality, ipid2, []byte{0x83, 0xb2, 0x96, 0xb1, 0xb4, 0xba, 0x1a, 0x10, 0xb6, 0x9c, 0x00, 0xaa, 0x00, 0x34, 0x1d, 0x07}) + stubData = remqry.Bytes() + + case 6: + sequence = 7 + callID = 9 + contextID = 4 + opNum = 6 + rqUUID = ipid2 + stubData = []byte{0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + stubData = append(stubData, e.causality...) + stubData = append(stubData, 0x00, 0x00, 0x00, 0x00, 0x55, 0x73, 0x65, 0x72, 0x0d, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x77, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x33, 0x00, 0x32, 0x00, 0x5f, 0x00, 0x70, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + + case 7: + sequence = 8 + callID = 0x10 + contextID = 4 + opNum = 6 + rqUUID = ipid2 + stubData = []byte{0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + stubData = append(stubData, e.causality...) + stubData = append(stubData, 0x00, 0x00, 0x00, 0x00, 0x55, 0x73, 0x65, 0x72, 0x0d, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x77, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x33, 0x00, 0x32, 0x00, 0x5f, 0x00, 0x70, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + + default: + if sequence < 8 { + return fmt.Errorf("Undefined behaviour in Exec Request. Expected sequence < 8, got %d", sequence) + } + + sequence = 9 + contextID = 4 + callID = 0x0b + opNum = 0x18 + rqUUID = ipid2 + + stubLen := uint16(len(command) + 1769) + stubLen2 := uint16(len(command) + 1727) + stubLen3 := uint16(len(command) + 1713) + commLen := uint16(len(command) + 93) + commLen2 := uint16(len(command) + 16) + + stubLenB := make([]byte, 2) + binary.LittleEndian.PutUint16(stubLenB, stubLen) + stubLen2B := make([]byte, 2) + binary.LittleEndian.PutUint16(stubLen2B, stubLen2) + + stubLen3B := make([]byte, 2) + binary.LittleEndian.PutUint16(stubLen3B, stubLen3) + commLenB := make([]byte, 2) + binary.LittleEndian.PutUint16(commLenB, commLen) + commLen2B := make([]byte, 2) + binary.LittleEndian.PutUint16(commLen2B, commLen2) + + commandBytes := []byte(command) + if len(command)%4 == 0 { + commandBytes = append(commandBytes, 0, 0, 0, 0) + } else { + commandBytes = append(commandBytes, make([]byte, len(command)%4)...) + } + + stubData = []byte{0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + stubData = append(stubData, e.causality...) + stubData = append(stubData, 0x00, 0x00, 0x00, 0x00, 0x55, 0x73, 0x65, 0x72, 0x0d, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x57, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x33, 0x00, 0x32, 0x00, 0x5f, 0x00, 0x50, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 0x00, 0x00, 0x55, 0x73, 0x65, 0x72, 0x06, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x63, 0x00, 0x72, 0x00, 0x65, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00) + stubData = append(stubData, stubLenB...) + stubData = append(stubData, 0, 0) + stubData = append(stubData, stubLenB...) + stubData = append(stubData, 0x00, 0x00, 0x4d, 0x45, 0x4f, 0x57, 0x04, 0x00, 0x00, 0x00, 0x81, 0xa6, 0x12, 0xdc, 0x7f, 0x73, 0xcf, 0x11, 0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24, 0x12, 0xf8, 0x90, 0x45, 0x3a, 0x1d, 0xd0, 0x11, 0x89, 0x1f, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24, 0x00, 0x00, 0x00, 0x00) + stubData = append(stubData, stubLen2B...) + stubData = append(stubData, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12) + stubData = append(stubData, stubLen3B...) + stubData = append(stubData, 0x00, 0x00, 0x02, 0x53, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, 0x73, 0x01, 0x00, 0x00, 0x76, 0x02, 0x00, 0x00, 0xd4, 0x02, 0x00, 0x00, 0xb1, 0x03, 0x00, 0x00, 0x15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x12, 0x04, 0x00, 0x80, 0x00, 0x5f, 0x5f, 0x50, 0x41, 0x52, 0x41, 0x4d, 0x45, 0x54, 0x45, 0x52, 0x53, 0x00, 0x00, 0x61, 0x62, 0x73, 0x74, 0x72, 0x61, 0x63, 0x74, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x80, 0x03, 0x08, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x80, 0x03, 0x08, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x02, 0x0b, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x00, 0x57, 0x69, 0x6e, 0x33, 0x32, 0x41, 0x50, 0x49, 0x7c, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x7c, 0x6c, 0x70, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x20, 0x00, 0x00, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x80, 0x03, 0x08, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x02, 0x0b, 0x00, 0x00, 0x00, 0xff, 0xff, 0xca, 0x00, 0x00, 0x00, 0x02, 0x08, 0x20, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x49, 0x44, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x80, 0x03, 0x08, 0x00, 0x00, 0x00, 0x59, 0x01, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0xff, 0xff, 0xca, 0x00, 0x00, 0x00, 0x02, 0x08, 0x20, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x11, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x80, 0x03, 0x08, 0x00, 0x00, 0x00, 0x85, 0x01, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x80, 0x03, 0x08, 0x00, 0x00, 0x00, 0x85, 0x01, 0x00, 0x00, 0xac, 0x01, 0x00, 0x00, 0x02, 0x0b, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xe2, 0x01, 0x00, 0x00, 0x00, 0x57, 0x69, 0x6e, 0x33, 0x32, 0x41, 0x50, 0x49, 0x7c, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x54, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x7c, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x7c, 0x6c, 0x70, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x00, 0x00, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x80, 0x03, 0x08, 0x00, 0x00, 0x00, 0x85, 0x01, 0x00, 0x00, 0xac, 0x01, 0x00, 0x00, 0x02, 0x0b, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2b, 0x02, 0x00, 0x00, 0x02, 0x08, 0x20, 0x00, 0x00, 0xda, 0x01, 0x00, 0x00, 0x00, 0x49, 0x44, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x80, 0x03, 0x08, 0x00, 0x00, 0x00, 0xba, 0x02, 0x00, 0x00, 0xac, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2b, 0x02, 0x00, 0x00, 0x02, 0x08, 0x20, 0x00, 0x00, 0xda, 0x01, 0x00, 0x00, 0x72, 0x02, 0x00, 0x00, 0x11, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x80, 0x03, 0x08, 0x00, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x80, 0x03, 0x08, 0x00, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, 0x16, 0x03, 0x00, 0x00, 0x02, 0x0b, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x4c, 0x03, 0x00, 0x00, 0x00, 0x57, 0x4d, 0x49, 0x7c, 0x57, 0x69, 0x6e, 0x33, 0x32, 0x5f, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x00, 0x00, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x80, 0x03, 0x08, 0x00, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, 0x16, 0x03, 0x00, 0x00, 0x02, 0x0b, 0x00, 0x00, 0x00, 0xff, 0xff, 0x66, 0x03, 0x00, 0x00, 0x02, 0x08, 0x20, 0x00, 0x00, 0x44, 0x03, 0x00, 0x00, 0x00, 0x49, 0x44, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x80, 0x03, 0x08, 0x00, 0x00, 0x00, 0xf5, 0x03, 0x00, 0x00, 0x16, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0xff, 0xff, 0x66, 0x03, 0x00, 0x00, 0x02, 0x08, 0x20, 0x00, 0x00, 0x44, 0x03, 0x00, 0x00, 0xad, 0x03, 0x00, 0x00, 0x11, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x3a, 0x57, 0x69, 0x6e, 0x33, 0x32, 0x5f, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x53, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70) + stubData = append(stubData, make([]byte, 501)...) + stubData = append(stubData, commLenB...) + stubData = append(stubData, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01) + stubData = append(stubData, commLen2B...) + stubData = append(stubData, 0x00, 0x80, 0x00, 0x5f, 0x5f, 0x50, 0x41, 0x52, 0x41, 0x4d, 0x45, 0x54, 0x45, 0x52, 0x53, 0x00, 0x00) + stubData = append(stubData, commandBytes...) + stubData = append(stubData, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) + if len(stubData) > 5500 { + return fmt.Errorf("Long request packet not yet implemented. Needed below 5500, got %d", len(stubData)) + } + nextStage = "Result" + } + + authv := rpce.NewAuthVerifier(0x0a, 4, 0, make([]byte, 16)) + packetRPC := rpce.NewRequestReq(callID, contextID, opNum, append(rqUUID, stubData...), &authv) + packetRPC.CommonHead.PFCFlags = 0x83 + + messagesig := ntlmssp.NewMessageSignature(packetRPC.AuthBytes(), e.clientSigningKey, sequence) + authv.AuthValue = messagesig.Bytes() + + wmiSend := packetRPC.Bytes() + e.tcpClient.Write(wmiSend) + + //reads 16 bytes + hdr := rpce.Response{} + for hdr.CommonHead.PFCFlags&rpce.PFCLastFrag == 0 { + hbuff := make([]byte, 16) + n, err := e.tcpClient.Read(hbuff) + hdr = rpce.ParseResponse(hbuff) + buff := make([]byte, hdr.CommonHead.FragLength-16) + n, err = e.tcpClient.Read(buff) + n = n + 16 + resp = append(hbuff, buff...) + if err != nil && err == io.EOF { + //e.log.Error("Conn closed BRUH") + return err + } + + if uint16(n) < hdr.CommonHead.FragLength { + buff := make([]byte, hdr.CommonHead.FragLength-uint16(n)) + e.tcpClient.Read(buff) + resp = append(resp, buff...) + } + } + if nextStage == "Result" { + if len(resp) > 1145 { + //e.log.Info("PID? ", binary.LittleEndian.Uint16(resp[1141:1145])) + return nil + } else { + //e.log.Info("Response shorter than expected... possible error in command? Expected > 1145, got ", len(resp)) + return nil + } + + } + e.stage = nextStage + + } + } + + return nil +} + +func WMIExec(target, username, password, hash, domain, command, clientHostname string, timeout int, cfgIn *WmiExecConfig) error { + // 随机 sleep 防止出现 connect: host is down + r := rand.Intn(1000) + time.Sleep(time.Duration(r) * time.Millisecond) + // + if cfgIn == nil { + cfg, err := NewExecConfig(username, password, hash, domain, target, clientHostname, timeout, true, nil, nil) + if err != nil { + return err + } + cfgIn = &cfg + } + execer := NewExecer(cfgIn) + err := execer.Connect() + if err != nil { + return err + } + + err = execer.Auth() + if err != nil { + return err + } + + if command != "" { + if execer.targetRPCPort == 0 { + //execer.log.Error("RPC Port is 0, cannot connect") + return errors.New("RPC Port is 0, cannot connect") + } + + err = execer.RPCConnect() + if err != nil { + return err + } + err = execer.Exec(command) + if err != nil { + return err + } + } + + return nil + +} + +func toUnicodeS(s string) (string, error) { + s, e := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder().String(s) + if e != nil { + return "", e + } + return s, nil +} diff --git a/pkg/crack/plugins/wmihash.go b/pkg/crack/plugins/wmihash.go new file mode 100755 index 0000000..07eab3b --- /dev/null +++ b/pkg/crack/plugins/wmihash.go @@ -0,0 +1,18 @@ +package plugins + +import ( + "github.com/niudaii/crack/pkg/crack/plugins/wmiexec" + "strconv" + "strings" +) + +func WmiHashCrack(serv *Service) int { + err := wmiexec.WMIExec(serv.Ip+":"+strconv.Itoa(serv.Port), serv.User, "", serv.Pass, "", "", "", serv.Timeout, nil) + if err != nil { + if strings.Contains(err.Error(), "timeout") { + return CrackError + } + return CrackFail + } + return CrackSuccess +} diff --git a/pkg/crack/runner.go b/pkg/crack/runner.go new file mode 100644 index 0000000..8268cc3 --- /dev/null +++ b/pkg/crack/runner.go @@ -0,0 +1,156 @@ +package crack + +import ( + "fmt" + "github.com/cheggaaa/pb/v3" + "github.com/niudaii/crack/internal/utils" + "github.com/niudaii/crack/pkg/crack/plugins" + "github.com/projectdiscovery/gologger" + "strings" + "sync" + "time" +) + +type Options struct { + Threads int + Timeout int + Delay int + CrackAll bool + Silent bool +} + +type Runner struct { + options *Options +} + +func NewRunner(options *Options) (*Runner, error) { + return &Runner{ + options: options, + }, nil +} + +type Result struct { + Addr string + Protocol string + UserPass string +} + +type IpAddr struct { + Ip string + Port int + Protocol string +} + +func (r *Runner) Run(addrs []*IpAddr, userDict []string, passDict []string) (results []*Result) { + for _, addr := range addrs { + results = append(results, r.Crack(addr, userDict, passDict)...) + } + return +} + +func (r *Runner) Crack(addr *IpAddr, userDict []string, passDict []string) (results []*Result) { + gologger.Info().Msgf("开始爆破: %v:%v %v", addr.Ip, addr.Port, addr.Protocol) + + var tasks []plugins.Service + var taskHash string + taskHashMap := map[string]bool{} + // GenTask + if len(userDict) == 0 { + userDict = UserMap[addr.Protocol] + } + if len(passDict) == 0 { + passDict = append(passDict, TemplatePass...) + passDict = append(passDict, CommonPass...) + } + for _, user := range userDict { + for _, pass := range passDict { + // 替换{user} + pass = strings.ReplaceAll(pass, "{user}", user) + // 任务去重 + taskHash = utils.Md5(fmt.Sprintf("%v%v%v%v%v", addr.Ip, addr.Port, addr.Protocol, user, pass)) + if taskHashMap[taskHash] { + continue + } + taskHashMap[taskHash] = true + tasks = append(tasks, plugins.Service{ + Ip: addr.Ip, + Port: addr.Port, + Protocol: addr.Protocol, + User: user, + Pass: pass, + Timeout: r.options.Timeout, + }) + } + } + // RunTask + stopHashMap := map[string]bool{} + mutex := &sync.Mutex{} + wg := &sync.WaitGroup{} + taskChan := make(chan plugins.Service, r.options.Threads) + for i := 0; i < r.options.Threads; i++ { + go func() { + for task := range taskChan { + addrStr := fmt.Sprintf("%v:%v", addr.Ip, addr.Port) + userPass := fmt.Sprintf("%v:%v", task.User, task.Pass) + addrHash := utils.Md5(addrStr) + // 判断是否已经停止爆破 + mutex.Lock() + if stopHashMap[addrHash] { + wg.Done() + mutex.Unlock() + continue + } + mutex.Unlock() + gologger.Debug().Msgf("[trying] %v", userPass) + scanFunc := plugins.ScanFuncMap[task.Protocol] + resp := scanFunc(&task) + switch resp { + case plugins.CrackSuccess: + if !r.options.CrackAll { + mutex.Lock() + stopHashMap[addrHash] = true + mutex.Unlock() + } + gologger.Silent().Msgf("%v -> %v %v", addr.Protocol, addrStr, userPass) + results = append(results, &Result{ + Addr: addrStr, + Protocol: addr.Protocol, + UserPass: userPass, + }) + case plugins.CrackError: + mutex.Lock() + stopHashMap[addrHash] = true + mutex.Unlock() + case plugins.CrackFail: + } + if r.options.Delay > 0 { + time.Sleep(time.Duration(r.options.Delay) * time.Second) + } + wg.Done() + } + }() + } + + if r.options.Silent { + for _, task := range tasks { + wg.Add(1) + taskChan <- task + } + close(taskChan) + wg.Wait() + } else { + bar := pb.StartNew(len(tasks)) + for _, task := range tasks { + bar.Increment() + wg.Add(1) + taskChan <- task + } + close(taskChan) + wg.Wait() + bar.Finish() + } + + gologger.Info().Msgf("爆破结束") + + return +} diff --git a/pkg/crack/runner_test.go b/pkg/crack/runner_test.go new file mode 100644 index 0000000..538c7e5 --- /dev/null +++ b/pkg/crack/runner_test.go @@ -0,0 +1,55 @@ +package crack + +import ( + "testing" +) + +func TestCrackAll(t *testing.T) { + /* + === RUN TestCrackAll + === RUN TestCrackAll/false + [INF] 开始爆破: 127.0.0.1:3306 mysql + [INF] success root:123456 + 4 / 4 [-----------------------------------------------------------------------------------------------] 100.00% ? p/s + === RUN TestCrackAll/true + [INF] 开始爆破: 127.0.0.1:3306 mysql + [INF] success root:123456 + [INF] success test_user:test2022@ + 4 / 4 [-----------------------------------------------------------------------------------------------] 100.00% ? p/s + --- PASS: TestCrackAll (0.02s) + --- PASS: TestCrackAll/false (0.01s) + --- PASS: TestCrackAll/true (0.01s) + PASS + ok crack/pkg/crack 0.036s + */ + tests := map[string]*Runner{ + "false": { + options: &Options{ + Threads: 1, + Timeout: 10, + CrackAll: false, + }, + }, + "true": { + options: &Options{ + Threads: 1, + Timeout: 10, + CrackAll: true, + }, + }, + } + addrs := []*IpAddr{ + { + Ip: "127.0.0.1", + Port: 3306, + Protocol: "mysql", + }, + } + userDict := []string{"root", "test_user"} + passDict := []string{"123456", "test2022@"} + for name, runner := range tests { + t.Run(name, func(t *testing.T) { + runner.Run(addrs, userDict, passDict) + }) + } +}