├── .github ├── FUNDING.yml ├── banner.png ├── example_dn.png ├── example_value.png └── workflows │ ├── commit.yaml │ └── release.yaml ├── .gitignore ├── README.md ├── go.mod ├── go.sum ├── main.go └── src ├── go.mod ├── go.sum ├── ldap ├── ldap.go ├── sid.go └── utils.go ├── logger └── logger.go ├── main.go └── windows ├── RelativeIDs.go └── sAMAccountType.go /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: p0dalirius 4 | patreon: Podalirius 5 | -------------------------------------------------------------------------------- /.github/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheManticoreProject/DescribeNTSecurityDescriptor/be5d346c17d1dfac9198770cea70041e47cf89ce/.github/banner.png -------------------------------------------------------------------------------- /.github/example_dn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheManticoreProject/DescribeNTSecurityDescriptor/be5d346c17d1dfac9198770cea70041e47cf89ce/.github/example_dn.png -------------------------------------------------------------------------------- /.github/example_value.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheManticoreProject/DescribeNTSecurityDescriptor/be5d346c17d1dfac9198770cea70041e47cf89ce/.github/example_value.png -------------------------------------------------------------------------------- /.github/workflows/commit.yaml: -------------------------------------------------------------------------------- 1 | name: Build on commit 2 | 3 | on: 4 | push: 5 | branches: 6 | - '*' 7 | 8 | jobs: 9 | build: 10 | name: Build Release Assets 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | os: [linux, windows, darwin] 16 | arch: [amd64, arm64, 386] 17 | binaryname: [DescribeNTSecurityDescriptor] 18 | # Exclude incompatible couple of GOOS and GOARCH values 19 | exclude: 20 | - os: darwin 21 | arch: 386 22 | 23 | env: 24 | GO111MODULE: 'on' 25 | CGO_ENABLED: '0' 26 | 27 | steps: 28 | - name: Checkout Repository 29 | uses: actions/checkout@v3 30 | 31 | - name: Set up Go 32 | uses: actions/setup-go@v4 33 | with: 34 | go-version: '1.22.1' 35 | 36 | - name: Build Binary 37 | env: 38 | GOOS: ${{ matrix.os }} 39 | GOARCH: ${{ matrix.arch }} 40 | run: | 41 | mkdir -p build 42 | ls -lha 43 | OUTPUT_PATH="../build/${{ matrix.binaryname }}-${{ matrix.os }}-${{ matrix.arch }}" 44 | # Build the binary 45 | cd ./src/; 46 | go build -ldflags="-s -w" -o $OUTPUT_PATH${{ matrix.os == 'windows' && '.exe' || '' }} 47 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Build and Release 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | build: 9 | name: Build Release Assets 10 | runs-on: ubuntu-latest 11 | 12 | strategy: 13 | matrix: 14 | os: [linux, windows, darwin] 15 | arch: [amd64, arm64, 386] 16 | binaryname: [DescribeNTSecurityDescriptor] 17 | # Exclude incompatible couple of GOOS and GOARCH values 18 | exclude: 19 | - os: darwin 20 | arch: 386 21 | 22 | env: 23 | GO111MODULE: 'on' 24 | CGO_ENABLED: '0' 25 | 26 | steps: 27 | - name: Checkout Repository 28 | uses: actions/checkout@v3 29 | 30 | - name: Set up Go 31 | uses: actions/setup-go@v4 32 | with: 33 | go-version: '1.22.1' 34 | 35 | - name: Build Binary 36 | env: 37 | GOOS: ${{ matrix.os }} 38 | GOARCH: ${{ matrix.arch }} 39 | run: | 40 | mkdir -p bin 41 | ls -lha 42 | OUTPUT_PATH="../build/${{ matrix.binaryname }}-${{ matrix.os }}-${{ matrix.arch }}" 43 | # Build the binary 44 | cd ./src/; 45 | go build -ldflags="-s -w" -o $OUTPUT_PATH${{ matrix.os == 'windows' && '.exe' || '' }} 46 | 47 | - name: Prepare Release Assets 48 | if: ${{ success() }} 49 | run: | 50 | mkdir -p ./release/ 51 | cp ./build/${{ matrix.binaryname }}-* ./release/ 52 | 53 | - name: Upload the Release binaries 54 | uses: svenstaro/upload-release-action@v2 55 | with: 56 | repo_token: ${{ secrets.GITHUB_TOKEN }} 57 | tag: ${{ github.ref }} 58 | file: ./release/${{ matrix.binaryname }}-* 59 | file_glob: true 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # If you prefer the allow list template instead of the deny list, see community template: 2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 3 | # 4 | # Binaries for programs and plugins 5 | *.exe 6 | *.exe~ 7 | *.dll 8 | *.so 9 | *.dylib 10 | 11 | # Test binary, built with `go test -c` 12 | *.test 13 | 14 | # Output of the go coverage tool, specifically when used with LiteIDE 15 | *.out 16 | 17 | # Dependency directories (remove the comment below to include it) 18 | # vendor/ 19 | 20 | # Go workspace file 21 | go.work 22 | go.work.sum 23 | 24 | # env file 25 | .env 26 | 27 | # Builds dir 28 | ./bin/ 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](./.github/banner.png) 2 | 3 |

4 | A cross-platform tool to parse and describe the contents of a raw ntSecurityDescriptor structure. 5 |
6 | Build and Release 7 | GitHub release (latest by date) 8 | Go Report Card 9 |
10 |

11 | 12 | ## Features 13 | 14 | - [x] Reads source value from a file containing a raw ntSecurityDescriptor structure, in raw bytes, hex string or base64 string formats. 15 | - [x] Reads source value from the LDAP. 16 | - [ ] Outputs a human readable summary of accesses with `--summary` 17 | - [x] Parsing of Access Control Entries (ACE) of various types: 18 | - [x] ACE type [`ACCESS_ALLOWED_ACE`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/72e7c7ea-bc02-4c74-a619-818a16bf6adb?wt.mc_id=SEC-MVP-5005286) 19 | - [x] ACE type [`ACCESS_ALLOWED_OBJECT_ACE`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/c79a383c-2b3f-4655-abe7-dcbb7ce0cfbe?wt.mc_id=SEC-MVP-5005286) 20 | - [x] ACE type [`ACCESS_DENIED_ACE`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/b1e1321d-5816-4513-be67-b65d8ae52fe8?wt.mc_id=SEC-MVP-5005286) 21 | - [x] ACE type [`ACCESS_DENIED_OBJECT_ACE`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/8720fcf3-865c-4557-97b1-0b3489a6c270?wt.mc_id=SEC-MVP-5005286) 22 | - [x] ACE type [`ACCESS_ALLOWED_CALLBACK_ACE`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/c9579cf4-0f4a-44f1-9444-422dfb10557a?wt.mc_id=SEC-MVP-5005286) 23 | - [x] ACE type [`ACCESS_DENIED_CALLBACK_ACE`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/35adad6b-fda5-4cc1-b1b5-9beda5b07d2e?wt.mc_id=SEC-MVP-5005286) 24 | - [x] ACE type [`ACCESS_ALLOWED_CALLBACK_OBJECT_ACE`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/fe1838ea-ea34-4a5e-b40e-eb870f8322ae?wt.mc_id=SEC-MVP-5005286) 25 | - [x] ACE type [`ACCESS_DENIED_CALLBACK_OBJECT_ACE`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/4652f211-82d5-4b90-bd58-43bf3b0fc48d?wt.mc_id=SEC-MVP-5005286) 26 | - [x] ACE type [`SYSTEM_AUDIT_ACE`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/9431fd0f-5b9a-47f0-b3f0-3015e2d0d4f9?wt.mc_id=SEC-MVP-5005286) 27 | - [x] ACE type [`SYSTEM_AUDIT_OBJECT_ACE`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/c8da72ae-6b54-4a05-85f4-e2594936d3d5?wt.mc_id=SEC-MVP-5005286) 28 | - [x] ACE type [`SYSTEM_AUDIT_CALLBACK_ACE`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/bd6b6fd8-4bef-427e-9a43-b9b46457e934?wt.mc_id=SEC-MVP-5005286) 29 | - [x] ACE type [`SYSTEM_MANDATORY_LABEL_ACE`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/25fa6565-6cb0-46ab-a30a-016b32c4939a?wt.mc_id=SEC-MVP-5005286) 30 | - [x] ACE type [`SYSTEM_AUDIT_CALLBACK_OBJECT_ACE`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/949b02e7-f55d-4c26-969f-52a009597469?wt.mc_id=SEC-MVP-5005286) 31 | - [x] ACE type [`SYSTEM_RESOURCE_ATTRIBUTE_ACE`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/352944c7-4fb6-4988-8036-0a25dcedc730?wt.mc_id=SEC-MVP-5005286) 32 | - [x] ACE type [`SYSTEM_SCOPED_POLICY_ID_ACE`](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/aa0c0f62-4b4c-44f0-9718-c266a6accd9f?wt.mc_id=SEC-MVP-5005286) 33 | - [x] Parsing of SID 34 | - [x] Connect to LDAP to resolve sAMAccountNames of not well known SIDs 35 | - [x] Resolve names of well known SIDs 36 | - [ ] Parsing of Access Control Lists (ACL): 37 | - [ ] Print if ACL is in [canonical form](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/20233ed8-a6c6-4097-aafa-dd545ed24428?wt.mc_id=SEC-MVP-5005286) 38 | 39 | 40 | ## Usage 41 | 42 | ``` 43 | $ ./DescribeNTSecurityDescriptor -h 44 | DescribeNTSecurityDescriptor - by Remi GASCOU (Podalirius) @ TheManticoreProject - v1.3.0 45 | 46 | Usage: DescribeNTSecurityDescriptor [--debug] [--domain ] [--username ] [--password ] [--hashes ] [--dc-ip ] [--port ] [--use-ldaps] [--distinguished-name ] [--file-hex ] [--file-base64 ] [--file-raw ] [--value-hex ] [--value-base64 ] 47 | 48 | -d, --debug Debug mode. (default: false) 49 | 50 | Authentication: 51 | -d, --domain Active Directory domain to authenticate to. (default: "") 52 | -u, --username User to authenticate as. (default: "") 53 | -p, --password Password to authenticate with. (default: "") 54 | -H, --hashes NT/LM hashes, format is LMhash:NThash. (default: "") 55 | 56 | LDAP Connection Settings: 57 | -dc, --dc-ip IP Address of the domain controller or KDC (Key Distribution Center) for Kerberos. If omitted, it will use the domain part (FQDN) specified in the identity parameter. (default: "") 58 | -P, --port Port number to connect to LDAP server. (default: 389) 59 | -l, --use-ldaps Use LDAPS instead of LDAP. (default: false) 60 | 61 | Source Values: 62 | -D, --distinguished-name Distinguished Name. (default: "") 63 | -fh, --file-hex Path to file containing the hexadecimal string value of NTSecurityDescriptor. (default: "") 64 | -fb, --file-base64 Path to file containing the base64 encoded value of NTSecurityDescriptor. (default: "") 65 | -fr, --file-raw Path to file containing the raw binary value of NTSecurityDescriptor. (default: "") 66 | -vh, --value-hex Raw hexadecimal string value of NTSecurityDescriptor. (default: "") 67 | -vb, --value-base64 Raw base64 encoded value of NTSecurityDescriptor. (default: "") 68 | ``` 69 | 70 | 71 | ## Demonstration with a `--distinguished-name` 72 | 73 | ```bash 74 | ./DescribeNTSecurityDescriptor --debug --username "Administrator" --domain "LAB.local" --password "Admin123!" --dc-ip "10.0.0.201" --distinguished-name "CN=Administrator,CN=Users,DC=LAB,DC=local" 75 | ``` 76 | 77 | ![](./.github/example_dn.png) 78 | 79 | ## Demonstration with a `--value-hex` 80 | 81 | ```bash 82 | ./DescribeNTSecurityDescriptor --username "Administrator" --domain "LAB.local" --password "Admin123!" --dc-ip "10.0.0.201" --debug --value-hex "0100149ccc000000e800000014000000a000000004008c00030000000240140020000c00010100000000000100000000075a38002000000003000000be3b0ef3f09fd111b6030000f80367c1a57a96bfe60dd011a28500aa003049e2010100000000000100000000075a38002000000003000000bf3b0ef3f09fd111b6030000f80367c1a57a96bfe60dd011a28500aa003049e201010000000000010000000002002c000100000000002400ff010f0001050000000000051500000028bb82279261b9fe2474aa5d0002000001050000000000051500000028bb82279261b9fe2474aa5d0002000001050000000000051500000028bb82279261b9fe2000000" 83 | ``` 84 | 85 | ![](./.github/example_value.png) 86 | 87 | 88 | ## Building the project 89 | 90 | To build the project, use the following Docker command in this directory: 91 | 92 | ```bash 93 | docker run -v $(pwd):/workspace/ podalirius/build-go-project 94 | ``` 95 | 96 | Or, if you want to build it manually, you can use the following commands: 97 | 98 | ``` 99 | GOOS=linux GOARCH=amd64; mkdir -p "/workspace/bin/linux/${GOOS}/${GOARCH}/" && /usr/local/go/bin/go build -o "/workspace/bin/linux/${GOOS}/${GOARCH}/DescribeNTSecurityDescriptor" -buildvcs=false 100 | ``` 101 | 102 | ## Contributing 103 | 104 | Pull requests are welcome. Feel free to open an issue if you want to add other features. 105 | 106 | ## Credits 107 | - [@p0dalirius](https://github.com/p0dalirius) for the creation of the [DescribeNTSecurityDescriptor](https://github.com/p0dalirius/DescribeNTSecurityDescriptor) project before transferring it to TheManticoreProject. 108 | 109 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/TheManticoreProject/DescribeNTSecurityDescriptor 2 | 3 | go 1.24.0 4 | 5 | require ( 6 | github.com/TheManticoreProject/Manticore v1.0.1 7 | github.com/TheManticoreProject/goopts v1.2.1 8 | github.com/TheManticoreProject/winacl v1.2.11 9 | ) 10 | 11 | require ( 12 | github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect 13 | github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect 14 | github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect 15 | github.com/go-ldap/ldap/v3 v3.4.11 // indirect 16 | github.com/google/uuid v1.6.0 // indirect 17 | github.com/hashicorp/go-uuid v1.0.3 // indirect 18 | github.com/jcmturner/aescts/v2 v2.0.0 // indirect 19 | github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect 20 | github.com/jcmturner/gofork v1.7.6 // indirect 21 | github.com/jcmturner/goidentity/v6 v6.0.1 // indirect 22 | github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect 23 | github.com/jcmturner/rpc/v2 v2.0.3 // indirect 24 | golang.org/x/crypto v0.38.0 // indirect 25 | golang.org/x/net v0.39.0 // indirect 26 | ) 27 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= 2 | github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= 3 | github.com/TheManticoreProject/Manticore v1.0.1 h1:b4MFQyiDrnADDFfu0bwAoVmgMEegd9nyMk6bCQUGaj0= 4 | github.com/TheManticoreProject/Manticore v1.0.1/go.mod h1:2YzwHihKSODuo1YP0UuHL/AgcwkQLtc5j/ihuvke4/k= 5 | github.com/TheManticoreProject/goopts v1.2.1 h1:/VhIRpQNEvbo01Yi6WHK6KG9SyNVi2yb6AIsOviqJ3Q= 6 | github.com/TheManticoreProject/goopts v1.2.1/go.mod h1:NaM3hXXCeN+x9ZSlkS6Bm8i8Lfqe28/rveBsfrMUrAo= 7 | github.com/TheManticoreProject/winacl v1.2.11 h1:0v1bHqzAYZ4H/mRuO7Agu2Rq+p9QXWs4SC8NI26NTwM= 8 | github.com/TheManticoreProject/winacl v1.2.11/go.mod h1:Xji/qLzY8AkdBNXRgOS7g+UBEuqMQBBZllr+rl7Hzko= 9 | github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= 10 | github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= 11 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 12 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 13 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 14 | github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 h1:BP4M0CvQ4S3TGls2FvczZtj5Re/2ZzkV9VwqPHH/3Bo= 15 | github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= 16 | github.com/go-ldap/ldap/v3 v3.4.11 h1:4k0Yxweg+a3OyBLjdYn5OKglv18JNvfDykSoI8bW0gU= 17 | github.com/go-ldap/ldap/v3 v3.4.11/go.mod h1:bY7t0FLK8OAVpp/vV6sSlpz3EQDGcQwc8pF0ujLgKvM= 18 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 19 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 20 | github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= 21 | github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= 22 | github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= 23 | github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= 24 | github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 25 | github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= 26 | github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 27 | github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= 28 | github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= 29 | github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= 30 | github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= 31 | github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= 32 | github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= 33 | github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= 34 | github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= 35 | github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= 36 | github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= 37 | github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= 38 | github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= 39 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 40 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 41 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 42 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 43 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 44 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 45 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 46 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 47 | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= 48 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 49 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 50 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 51 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 52 | golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= 53 | golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= 54 | golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= 55 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 56 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 57 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 58 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 59 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 60 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 61 | golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 62 | golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= 63 | golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= 64 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 65 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 66 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 67 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 68 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 69 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 70 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 71 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 72 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 73 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 74 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 75 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 76 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 77 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 78 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 79 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 80 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 81 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 82 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 83 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 84 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 85 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 86 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 87 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 88 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/base64" 5 | "encoding/hex" 6 | "fmt" 7 | "os" 8 | 9 | "github.com/TheManticoreProject/Manticore/logger" 10 | "github.com/TheManticoreProject/Manticore/network/ldap" 11 | "github.com/TheManticoreProject/Manticore/windows/credentials" 12 | "github.com/TheManticoreProject/goopts/parser" 13 | "github.com/TheManticoreProject/winacl/securitydescriptor" 14 | ) 15 | 16 | var ( 17 | // Configuration 18 | useLdaps bool 19 | debug bool 20 | 21 | // Network settings 22 | domainController string 23 | ldapPort int 24 | 25 | // Authentication details 26 | authDomain string 27 | authUsername string 28 | authPassword string 29 | authHashes string 30 | useKerberos bool 31 | 32 | // Source values 33 | distinguishedName string 34 | 35 | sourceFileHex string 36 | sourceFileBase64 string 37 | sourceFileRaw string 38 | valueHex string 39 | valueBase64 string 40 | ) 41 | 42 | func parseArgs() { 43 | ap := parser.ArgumentsParser{Banner: "DescribeNTSecurityDescriptor - by Remi GASCOU (Podalirius) @ TheManticoreProject - v1.3.1"} 44 | 45 | // Configuration flags 46 | ap.NewBoolArgument(&debug, "-d", "--debug", false, "Debug mode.") 47 | 48 | // Source value 49 | group_sourceValues, err := ap.NewRequiredMutuallyExclusiveArgumentGroup("Source Values") 50 | if err != nil { 51 | fmt.Printf("[error] Error creating ArgumentGroup: %s\n", err) 52 | } else { 53 | group_sourceValues.NewStringArgument(&distinguishedName, "-D", "--distinguished-name", "", false, "Distinguished Name.") 54 | // File sources 55 | group_sourceValues.NewStringArgument(&sourceFileHex, "-fh", "--file-hex", "", false, "Path to file containing the hexadecimal string value of NTSecurityDescriptor.") 56 | group_sourceValues.NewStringArgument(&sourceFileBase64, "-fb", "--file-base64", "", false, "Path to file containing the base64 encoded value of NTSecurityDescriptor.") 57 | group_sourceValues.NewStringArgument(&sourceFileRaw, "-fr", "--file-raw", "", false, "Path to file containing the raw binary value of NTSecurityDescriptor.") 58 | // Value sources 59 | group_sourceValues.NewStringArgument(&valueHex, "-vh", "--value-hex", "", false, "Raw hexadecimal string value of NTSecurityDescriptor.") 60 | group_sourceValues.NewStringArgument(&valueBase64, "-vb", "--value-base64", "", false, "Raw base64 encoded value of NTSecurityDescriptor.") 61 | } 62 | 63 | group_ldapSettings, err := ap.NewArgumentGroup("LDAP Connection Settings") 64 | if err != nil { 65 | fmt.Printf("[error] Error creating ArgumentGroup: %s\n", err) 66 | } else { 67 | group_ldapSettings.NewStringArgument(&domainController, "-dc", "--dc-ip", "", false, "IP Address of the domain controller or KDC (Key Distribution Center) for Kerberos. If omitted, it will use the domain part (FQDN) specified in the identity parameter.") 68 | group_ldapSettings.NewTcpPortArgument(&ldapPort, "-P", "--port", 389, false, "Port number to connect to LDAP server.") 69 | group_ldapSettings.NewBoolArgument(&useLdaps, "-l", "--use-ldaps", false, "Use LDAPS instead of LDAP.") 70 | group_ldapSettings.NewBoolArgument(&useKerberos, "-k", "--use-kerberos", false, "Use Kerberos instead of NTLM.") 71 | } 72 | 73 | group_auth, err := ap.NewArgumentGroup("Authentication") 74 | if err != nil { 75 | fmt.Printf("[error] Error creating ArgumentGroup: %s\n", err) 76 | } else { 77 | group_auth.NewStringArgument(&authDomain, "-d", "--domain", "", false, "Active Directory domain to authenticate to.") 78 | group_auth.NewStringArgument(&authUsername, "-u", "--username", "", false, "User to authenticate as.") 79 | group_auth.NewStringArgument(&authPassword, "-p", "--password", "", false, "Password to authenticate with.") 80 | group_auth.NewStringArgument(&authHashes, "-H", "--hashes", "", false, "NT/LM hashes, format is LMhash:NThash.") 81 | } 82 | 83 | ap.Parse() 84 | 85 | if useLdaps && !group_ldapSettings.LongNameToArgument["--port"].IsPresent() { 86 | ldapPort = 636 87 | } 88 | 89 | if len(distinguishedName) != 0 && (len(domainController) == 0 || len(authUsername) == 0 || len(authPassword) == 0) { 90 | logger.Warn("Error: Options --dc-ip, --username, --password are required when using --distinguished-name.") 91 | os.Exit(1) 92 | } 93 | } 94 | 95 | func main() { 96 | parseArgs() 97 | 98 | creds, err := credentials.NewCredentials(authDomain, authUsername, authPassword, authHashes) 99 | if err != nil { 100 | logger.Warn(fmt.Sprintf("Error creating credentials: %s", err)) 101 | return 102 | } 103 | 104 | rawNtsdValue := []byte{} 105 | 106 | // Parsing input values for hex format 107 | if len(rawNtsdValue) == 0 && (len(sourceFileHex) != 0 || len(valueHex) != 0) { 108 | value_hex_string := "" 109 | if len(valueHex) != 0 { 110 | value_hex_string = valueHex 111 | } 112 | if len(sourceFileHex) != 0 { 113 | data, err := os.ReadFile(sourceFileHex) 114 | if err != nil { 115 | logger.Warn(fmt.Sprintf("Error reading file: %s", err)) 116 | return 117 | } 118 | value_hex_string = string(data) 119 | } 120 | // Decoding the hex string 121 | if len(value_hex_string) != 0 { 122 | if len(value_hex_string)%2 == 1 { 123 | // encoding/hex: odd length hex string 124 | value_hex_string = value_hex_string + "0" 125 | } 126 | value, err := hex.DecodeString(value_hex_string) 127 | if err != nil { 128 | logger.Warn(fmt.Sprintf("Error decoding Hex value: %s", err)) 129 | return 130 | } else { 131 | rawNtsdValue = value 132 | } 133 | } 134 | } 135 | 136 | // Parsing input values for base64 format 137 | if len(rawNtsdValue) == 0 && (len(sourceFileBase64) != 0 || len(valueBase64) != 0) { 138 | value_base64_string := "" 139 | if len(valueBase64) != 0 { 140 | value_base64_string = valueBase64 141 | } 142 | if len(sourceFileBase64) != 0 { 143 | data, err := os.ReadFile(sourceFileBase64) 144 | if err != nil { 145 | logger.Warn(fmt.Sprintf("Error reading file: %s", err)) 146 | return 147 | } 148 | value_base64_string = string(data) 149 | } 150 | 151 | // Decoding the base64 string 152 | if len(value_base64_string) != 0 { 153 | value, err := base64.StdEncoding.DecodeString(value_base64_string) 154 | if err != nil { 155 | logger.Warn(fmt.Sprintf("Error decoding Base64 value: %s", err)) 156 | return 157 | } else { 158 | rawNtsdValue = value 159 | } 160 | } 161 | } 162 | 163 | // Parsing input values for raw format 164 | if len(rawNtsdValue) == 0 && len(sourceFileRaw) != 0 { 165 | data, err := os.ReadFile(sourceFileRaw) 166 | if err != nil { 167 | logger.Warn(fmt.Sprintf("Error reading file: %s", err)) 168 | return 169 | } 170 | rawNtsdValue = data 171 | } 172 | 173 | if len(rawNtsdValue) == 0 && len(distinguishedName) != 0 { 174 | // Parsing input values for Distinguished Name 175 | if debug { 176 | if !useLdaps { 177 | logger.Debug(fmt.Sprintf("Connecting to remote ldap://%s:%d ...", domainController, ldapPort)) 178 | } else { 179 | logger.Debug(fmt.Sprintf("Connecting to remote ldaps://%s:%d ...", domainController, ldapPort)) 180 | } 181 | } 182 | ldapSession := ldap.Session{} 183 | ldapSession.InitSession(domainController, ldapPort, creds, useLdaps, useKerberos) 184 | connected, err := ldapSession.Connect() 185 | if err != nil { 186 | logger.Warn(fmt.Sprintf("Error connecting to LDAP: %s", err)) 187 | return 188 | } 189 | 190 | if connected { 191 | logger.Info(fmt.Sprintf("Connected as '%s\\%s'", authDomain, authUsername)) 192 | 193 | query := fmt.Sprintf("(distinguishedName=%s)", distinguishedName) 194 | 195 | if debug { 196 | logger.Debug(fmt.Sprintf("LDAP query used: %s", query)) 197 | } 198 | 199 | attributes := []string{"distinguishedName", "ntSecurityDescriptor"} 200 | ldapResults, err := ldapSession.QueryWholeSubtree("", query, attributes) 201 | if err != nil { 202 | logger.Warn(fmt.Sprintf("Error querying LDAP: %s", err)) 203 | return 204 | } 205 | 206 | for _, entry := range ldapResults { 207 | if debug { 208 | logger.Debug(fmt.Sprintf("| distinguishedName: %s", entry.GetAttributeValue("distinguishedName"))) 209 | } 210 | rawNtsdValue = entry.GetEqualFoldRawAttributeValue("ntSecurityDescriptor") 211 | } 212 | } else { 213 | if debug { 214 | logger.Warn("Error: Could not create ldapSession.") 215 | } 216 | } 217 | } 218 | 219 | if len(rawNtsdValue) != 0 { 220 | ntsd := securitydescriptor.NtSecurityDescriptor{} 221 | logger.Debug(fmt.Sprintf("| ntSecurityDescriptor: %s", hex.EncodeToString(rawNtsdValue))) 222 | _, err := ntsd.Unmarshal(rawNtsdValue) 223 | if err != nil { 224 | logger.Warn(fmt.Sprintf("Error unmarshalling NTSecurityDescriptor: %s", err)) 225 | return 226 | } 227 | ntsd.Describe(0) 228 | } else { 229 | logger.Warn("No NTSecurityDescriptor found in source values.") 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/TheManticoreProject/DescribeNTSecurityDescriptor 2 | 3 | go 1.24.0 4 | 5 | require ( 6 | github.com/TheManticoreProject/goopts v1.1.7 7 | github.com/TheManticoreProject/winacl v1.2.6 8 | github.com/go-ldap/ldap/v3 v3.4.10 9 | ) 10 | 11 | require ( 12 | github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect 13 | github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect 14 | github.com/google/uuid v1.6.0 // indirect 15 | golang.org/x/crypto v0.37.0 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /src/go.sum: -------------------------------------------------------------------------------- 1 | github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= 2 | github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= 3 | github.com/TheManticoreProject/goopts v1.1.7 h1:fYuaUnZsL4X9InmHmpd1cgAfS8u0TMymTI3ke+Pp0sk= 4 | github.com/TheManticoreProject/goopts v1.1.7/go.mod h1:NaM3hXXCeN+x9ZSlkS6Bm8i8Lfqe28/rveBsfrMUrAo= 5 | github.com/TheManticoreProject/winacl v1.2.6 h1:2LiMx7l811UBqwYAOqvHNSfRJTbqITmUZbtkFjXzYsI= 6 | github.com/TheManticoreProject/winacl v1.2.6/go.mod h1:Xji/qLzY8AkdBNXRgOS7g+UBEuqMQBBZllr+rl7Hzko= 7 | github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= 8 | github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= 9 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 11 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 12 | github.com/go-asn1-ber/asn1-ber v1.5.7 h1:DTX+lbVTWaTw1hQ+PbZPlnDZPEIs0SS/GCZAl535dDk= 13 | github.com/go-asn1-ber/asn1-ber v1.5.7/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= 14 | github.com/go-ldap/ldap/v3 v3.4.10 h1:ot/iwPOhfpNVgB1o+AVXljizWZ9JTp7YF5oeyONmcJU= 15 | github.com/go-ldap/ldap/v3 v3.4.10/go.mod h1:JXh4Uxgi40P6E9rdsYqpUtbW46D9UTjJ9QSwGRznplY= 16 | github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 17 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 18 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 19 | github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= 20 | github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= 21 | github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 22 | github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= 23 | github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 24 | github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= 25 | github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= 26 | github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= 27 | github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= 28 | github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg= 29 | github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo= 30 | github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= 31 | github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= 32 | github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8= 33 | github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= 34 | github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= 35 | github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= 36 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 37 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 38 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 39 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 40 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 41 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 42 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 43 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 44 | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= 45 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 46 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 47 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 48 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 49 | golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= 50 | golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= 51 | golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= 52 | golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= 53 | golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= 54 | golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= 55 | golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= 56 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 57 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 58 | golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 59 | golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 60 | golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 61 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 62 | golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 63 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 64 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 65 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 66 | golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 67 | golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= 68 | golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= 69 | golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= 70 | golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= 71 | golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= 72 | golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= 73 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 74 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 75 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 76 | golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 77 | golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 78 | golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 79 | golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 80 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 81 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 82 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 83 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 84 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 85 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 86 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 87 | golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 88 | golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 89 | golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 90 | golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 91 | golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= 92 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 93 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 94 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 95 | golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= 96 | golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= 97 | golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= 98 | golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= 99 | golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= 100 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 101 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 102 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 103 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 104 | golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 105 | golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= 106 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 107 | golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 108 | golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= 109 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 110 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 111 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 112 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 113 | golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= 114 | golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= 115 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 116 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 117 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 118 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 119 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 120 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 121 | -------------------------------------------------------------------------------- /src/ldap/ldap.go: -------------------------------------------------------------------------------- 1 | package ldap 2 | 3 | import ( 4 | "github.com/TheManticoreProject/DescribeNTSecurityDescriptor/logger" 5 | 6 | "crypto/tls" 7 | "fmt" 8 | "strings" 9 | 10 | "github.com/go-ldap/ldap/v3" 11 | ) 12 | 13 | type Entry ldap.Entry 14 | 15 | type Session struct { 16 | // Network 17 | host string 18 | port int 19 | connection *ldap.Conn 20 | // Credentials 21 | domain string 22 | username string 23 | password string 24 | // Config 25 | debug bool 26 | useldaps bool 27 | } 28 | 29 | type Domain struct { 30 | NetBIOSName string `json:"netbiosName"` 31 | DNSName string `json:"dnsName"` 32 | DistinguishedName string `json:"distinguishedName"` 33 | SID string `json:"sid"` 34 | } 35 | 36 | func (s *Session) InitSession(host string, port int, useldaps bool, domain string, username string, password string, debug bool) { 37 | // Network 38 | s.host = host 39 | s.port = port 40 | // Credentials 41 | s.domain = domain 42 | s.username = username 43 | s.password = password 44 | // Config 45 | s.useldaps = useldaps 46 | s.debug = debug 47 | } 48 | 49 | func (s *Session) Connect() bool { 50 | // Check if TCP port is valid 51 | if s.port < 1 || s.port > 65535 { 52 | logger.Warn("Invalid port number. Port must be in the range 1-65535.") 53 | return false 54 | } 55 | 56 | // Set up LDAP connection 57 | var ldapConnection *ldap.Conn 58 | var err error 59 | 60 | // Check if LDAPS is available 61 | if s.useldaps { 62 | // LDAPS connection 63 | ldapConnection, err = ldap.DialURL( 64 | fmt.Sprintf("ldaps://%s:%d", s.host, s.port), 65 | ldap.DialWithTLSConfig(&tls.Config{ 66 | InsecureSkipVerify: true, 67 | }), 68 | ) 69 | if err != nil { 70 | logger.Warn(fmt.Sprintf("Error connecting to LDAPS server: %s", err)) 71 | return false 72 | } 73 | // 74 | } else { 75 | // Regular LDAP connection 76 | ldapConnection, err = ldap.DialURL(fmt.Sprintf("ldap://%s:%d", s.host, s.port)) 77 | if err != nil { 78 | logger.Warn(fmt.Sprintf("Error connecting to LDAP server: %s", err)) 79 | return false 80 | } 81 | } 82 | 83 | // Bind with credentials if provided 84 | if len(s.password) > 0 { 85 | // Binding with credentials 86 | if s.debug { 87 | logger.Debug(fmt.Sprintf("Performing authenticated NTLM bind as '%s\\%s' ...", s.domain, s.username)) 88 | } 89 | err = ldapConnection.NTLMBind(s.domain, s.username, s.password) 90 | if err != nil { 91 | logger.Warn(fmt.Sprintf("Error binding: %s", err)) 92 | return false 93 | } 94 | 95 | } else { 96 | // Unauthenticated Bind 97 | bindDN := "" 98 | if s.username != "" { 99 | bindDN = fmt.Sprintf("%s@%s", s.username, s.domain) 100 | if s.debug { 101 | logger.Debug(fmt.Sprintf("Using bindDN: '%s'", bindDN)) 102 | } 103 | } 104 | 105 | if s.debug { 106 | logger.Debug("Performing unauthenticated bind ...") 107 | } 108 | err = ldapConnection.UnauthenticatedBind(bindDN) 109 | if err != nil { 110 | logger.Warn(fmt.Sprintf("Error binding: %s", err)) 111 | } 112 | } 113 | 114 | s.connection = ldapConnection 115 | return true 116 | } 117 | 118 | func (s *Session) ReConnect() bool { 119 | s.connection.Close() 120 | return s.Connect() 121 | } 122 | 123 | func GetRootDSE(ldapSession *Session) *ldap.Entry { 124 | // Specify LDAP search parameters 125 | // https://pkg.go.dev/gopkg.in/ldap.v3#NewSearchRequest 126 | searchRequest := ldap.NewSearchRequest( 127 | // Base DN blank 128 | "", 129 | // Scope Base 130 | ldap.ScopeBaseObject, 131 | // DerefAliases 132 | ldap.NeverDerefAliases, 133 | // SizeLimit 134 | 1, 135 | // TimeLimit 136 | 0, 137 | // TypesOnly 138 | false, 139 | // Search filter 140 | "(objectClass=*)", 141 | // Attributes to retrieve 142 | []string{"*"}, 143 | // Controls 144 | nil, 145 | ) 146 | 147 | // Perform LDAP search 148 | searchResult, err := ldapSession.connection.Search(searchRequest) 149 | if err != nil { 150 | logger.Warn(fmt.Sprintf("Error searching LDAP: %s", err)) 151 | return nil 152 | } 153 | 154 | return searchResult.Entries[0] 155 | } 156 | 157 | func RawQuery(ldapSession *Session, baseDN string, query string, attributes []string, scope int) []*ldap.Entry { 158 | debug := false 159 | 160 | // Parsing parameters 161 | if len(baseDN) == 0 { 162 | baseDN = "defaultNamingContext" 163 | } 164 | if strings.ToLower(baseDN) == "defaultnamingcontext" { 165 | rootDSE := GetRootDSE(ldapSession) 166 | if debug { 167 | logger.Debug(fmt.Sprintf("Using defaultNamingContext %s ...\n", rootDSE.GetAttributeValue("defaultNamingContext"))) 168 | } 169 | baseDN = rootDSE.GetAttributeValue("defaultNamingContext") 170 | } else if strings.ToLower(baseDN) == "configurationnamingcontext" { 171 | rootDSE := GetRootDSE(ldapSession) 172 | if debug { 173 | logger.Debug(fmt.Sprintf("Using configurationNamingContext %s ...\n", rootDSE.GetAttributeValue("configurationNamingContext"))) 174 | } 175 | baseDN = rootDSE.GetAttributeValue("configurationNamingContext") 176 | } else if strings.ToLower(baseDN) == "schemanamingcontext" { 177 | rootDSE := GetRootDSE(ldapSession) 178 | if debug { 179 | logger.Debug(fmt.Sprintf("Using schemaNamingContext CN=Schema,%s ...\n", rootDSE.GetAttributeValue("configurationNamingContext"))) 180 | } 181 | baseDN = fmt.Sprintf("CN=Schema,%s", rootDSE.GetAttributeValue("configurationNamingContext")) 182 | 183 | } 184 | 185 | if (scope != ldap.ScopeBaseObject) && (scope != ldap.ScopeSingleLevel) && (scope != ldap.ScopeWholeSubtree) { 186 | scope = ldap.ScopeWholeSubtree 187 | } 188 | 189 | // Specify LDAP search parameters 190 | // https://pkg.go.dev/gopkg.in/ldap.v3#NewSearchRequest 191 | searchRequest := ldap.NewSearchRequest( 192 | // Base DN 193 | baseDN, 194 | // Scope 195 | scope, 196 | // DerefAliases 197 | ldap.NeverDerefAliases, 198 | // SizeLimit 199 | 0, 200 | // TimeLimit 201 | 0, 202 | // TypesOnly 203 | false, 204 | // Search filter 205 | query, 206 | // Attributes to retrieve 207 | attributes, 208 | // Controls 209 | nil, 210 | ) 211 | 212 | // Perform LDAP search 213 | searchResult, err := ldapSession.connection.SearchWithPaging(searchRequest, 1000) 214 | if err != nil { 215 | logger.Warn(fmt.Sprintf("Error searching LDAP: %s", err)) 216 | return nil 217 | } 218 | 219 | return searchResult.Entries 220 | } 221 | 222 | func QueryBaseObject(ldapSession *Session, baseDN string, query string, attributes []string) []*ldap.Entry { 223 | entries := RawQuery(ldapSession, baseDN, query, attributes, ldap.ScopeBaseObject) 224 | return entries 225 | } 226 | 227 | func QuerySingleLevel(ldapSession *Session, baseDN string, query string, attributes []string) []*ldap.Entry { 228 | entries := RawQuery(ldapSession, baseDN, query, attributes, ldap.ScopeSingleLevel) 229 | return entries 230 | } 231 | 232 | func QueryWholeSubtree(ldapSession *Session, baseDN string, query string, attributes []string) []*ldap.Entry { 233 | entries := RawQuery(ldapSession, baseDN, query, attributes, ldap.ScopeWholeSubtree) 234 | return entries 235 | } 236 | 237 | func QueryAllNamingContexts(ldapSession *Session, query string, attributes []string, scope int) []*ldap.Entry { 238 | // Fetch the RootDSE entry to get the naming contexts 239 | rootDSE := GetRootDSE(ldapSession) 240 | if rootDSE == nil { 241 | // logger.Warn("Could not retrieve RootDSE.") 242 | return nil 243 | } 244 | 245 | // Retrieve the namingContexts attribute 246 | namingContexts := rootDSE.GetAttributeValues("namingContexts") 247 | if len(namingContexts) == 0 { 248 | //logger.Warn("No naming contexts found.") 249 | return nil 250 | } 251 | 252 | // Store all entries from all naming contexts 253 | var allEntries []*ldap.Entry 254 | 255 | // Iterate over each naming context and perform the query 256 | for _, context := range namingContexts { 257 | entries := RawQuery(ldapSession, context, query, attributes, scope) 258 | if entries != nil { 259 | allEntries = append(allEntries, entries...) 260 | } 261 | } 262 | 263 | return allEntries 264 | } 265 | -------------------------------------------------------------------------------- /src/ldap/sid.go: -------------------------------------------------------------------------------- 1 | package ldap 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | // ParseSIDFromBytes parses raw bytes representing an SID and returns the SID string 10 | func ParseSIDFromBytes(sidBytes []byte) string { 11 | debug := false 12 | 13 | // Ensure the SID has a valid format 14 | if len(sidBytes) < 8 || sidBytes[0] != 1 { 15 | return "" 16 | } 17 | 18 | // Extract revisionLevel 19 | revisionLevel := int(sidBytes[0]) 20 | if debug { 21 | fmt.Printf("revisionLevel = 0x%02x\n", revisionLevel) 22 | fmt.Println(sidBytes[1:]) 23 | } 24 | // Extract subAuthorityCount 25 | subAuthorityCount := int(sidBytes[1]) 26 | if debug { 27 | fmt.Printf("subAuthorityCount = 0x%02x\n", subAuthorityCount) 28 | fmt.Println(sidBytes[2:]) 29 | } 30 | 31 | // Extract identifierAuthority 32 | identifierAuthority := uint64(sidBytes[2+0]) << 40 33 | identifierAuthority |= uint64(sidBytes[2+1]) << 32 34 | identifierAuthority |= uint64(sidBytes[2+2]) << 24 35 | identifierAuthority |= uint64(sidBytes[2+3]) << 16 36 | identifierAuthority |= uint64(sidBytes[2+4]) << 8 37 | identifierAuthority |= uint64(sidBytes[2+5]) 38 | if debug { 39 | fmt.Printf("identifierAuthority = 0x%08x\n", identifierAuthority) 40 | fmt.Println(sidBytes[8:]) 41 | } 42 | 43 | // Extract subAuthorities 44 | subAuthorities := make([]string, 0) 45 | for k := 0; k < subAuthorityCount-1; k++ { 46 | subAuthority := binary.LittleEndian.Uint32(sidBytes[8+(4*k):]) 47 | subAuthorities = append(subAuthorities, fmt.Sprintf("%d", subAuthority)) 48 | if debug { 49 | fmt.Printf("subAuthority = 0x%08x\n", subAuthority) 50 | fmt.Println(sidBytes[8+(4*k):]) 51 | } 52 | } 53 | 54 | // Parse the relativeIdentifier 55 | relativeIdentifier := binary.LittleEndian.Uint32(sidBytes[8+((subAuthorityCount-1)*4):]) 56 | if debug { 57 | fmt.Printf("relativeIdentifier = 0x%08x\n", relativeIdentifier) 58 | fmt.Println(sidBytes[8+((subAuthorityCount-1)*4):]) 59 | } 60 | 61 | // Construct the parsed SID 62 | parsedSID := fmt.Sprintf("S-%d-%d-%s-%d", revisionLevel, identifierAuthority, strings.Join(subAuthorities, "-"), relativeIdentifier) 63 | 64 | return parsedSID 65 | } 66 | -------------------------------------------------------------------------------- /src/ldap/utils.go: -------------------------------------------------------------------------------- 1 | package ldap 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | "time" 8 | ) 9 | 10 | const UnixTimestampStart int64 = 116444736000000000 // Monday, January 1, 1601 12:00:00 AM 11 | 12 | func GetDomainFromDistinguishedName(distinguishedName string) string { 13 | domainParts := strings.Split(distinguishedName, ",") 14 | 15 | domain := "" 16 | for _, part := range domainParts { 17 | if strings.HasPrefix(part, "DC=") { 18 | domain += strings.TrimPrefix(part, "DC=") + "." 19 | } 20 | } 21 | 22 | domain = strings.TrimSuffix(domain, ".") 23 | 24 | return domain 25 | } 26 | 27 | func ConvertLDAPTimeStampToUnixTimeStamp(value string) int64 { 28 | convertedValue := int64(0) 29 | 30 | if len(value) != 0 { 31 | valueInt, err := strconv.ParseInt(value, 10, 64) 32 | 33 | if err != nil { 34 | fmt.Printf("[!] Error converting value to int64: %s\n", err) 35 | return convertedValue 36 | } 37 | 38 | if valueInt < UnixTimestampStart { 39 | // Typically for dates on year 1601 40 | convertedValue = 0 41 | } else { 42 | delta := int64((valueInt - UnixTimestampStart) * 100) 43 | convertedValue = int64(time.Unix(0, delta).Unix()) 44 | } 45 | } 46 | 47 | return convertedValue 48 | } 49 | 50 | func ConvertLDAPDurationToSeconds(value string) int64 { 51 | convertedValue := int64(0) 52 | 53 | if len(value) != 0 { 54 | valueInt, err := strconv.ParseInt(value, 10, 64) 55 | if err != nil { 56 | fmt.Printf("[!] Error converting value to int64: %s\n", err) 57 | return convertedValue 58 | } 59 | 60 | if valueInt < 0 { 61 | valueInt = valueInt * int64(-1) 62 | } 63 | 64 | // Convert intervals of 100-nanoseconds to Seconds 65 | convertedValue = valueInt / int64(1e7) 66 | } 67 | 68 | return convertedValue 69 | } 70 | 71 | func ConvertSecondsToLDAPDuration(value int64) string { 72 | convertedValue := fmt.Sprintf("%d", value*int64(1e7)) 73 | return convertedValue 74 | } 75 | 76 | func ConvertUnixTimeStampToLDAPTimeStamp(value time.Time) int64 { 77 | ldapvalue := value.Unix() * (1e7) 78 | ldapvalue = ldapvalue + UnixTimestampStart 79 | return int64(ldapvalue) 80 | } 81 | -------------------------------------------------------------------------------- /src/logger/logger.go: -------------------------------------------------------------------------------- 1 | package logger 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func Info(message string) { 9 | currentTime := time.Now().Format("2006-01-02 15:04:05") 10 | fmt.Printf("[%s] INFO: %s\n", currentTime, message) 11 | } 12 | 13 | func Warn(message string) { 14 | currentTime := time.Now().Format("2006-01-02 15:04:05") 15 | fmt.Printf("[%s] WARN: %s\n", currentTime, message) 16 | } 17 | 18 | func Debug(message string) { 19 | currentTime := time.Now().Format("2006-01-02 15:04:05") 20 | fmt.Printf("[%s] DEBUG: %s\n", currentTime, message) 21 | } 22 | -------------------------------------------------------------------------------- /src/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/TheManticoreProject/DescribeNTSecurityDescriptor/ldap" 7 | "github.com/TheManticoreProject/DescribeNTSecurityDescriptor/logger" 8 | 9 | "encoding/base64" 10 | "encoding/hex" 11 | "fmt" 12 | 13 | "github.com/TheManticoreProject/goopts/parser" 14 | "github.com/TheManticoreProject/winacl/securitydescriptor" 15 | ) 16 | 17 | var ( 18 | // Configuration 19 | useLdaps bool 20 | debug bool 21 | 22 | // Network settings 23 | domainController string 24 | ldapPort int 25 | 26 | // Authentication details 27 | authDomain string 28 | authUsername string 29 | authPassword string 30 | authHashes string 31 | 32 | // Source values 33 | distinguishedName string 34 | 35 | sourceFileHex string 36 | sourceFileBase64 string 37 | sourceFileRaw string 38 | valueHex string 39 | valueBase64 string 40 | ) 41 | 42 | func parseArgs() { 43 | ap := parser.ArgumentsParser{Banner: "DescribeNTSecurityDescriptor - by Remi GASCOU (Podalirius) @ TheManticoreProject - v1.3.0"} 44 | 45 | // Configuration flags 46 | ap.NewBoolArgument(&debug, "-d", "--debug", false, "Debug mode.") 47 | 48 | // Source value 49 | group_sourceValues, err := ap.NewRequiredMutuallyExclusiveArgumentGroup("Source Values") 50 | if err != nil { 51 | fmt.Printf("[error] Error creating ArgumentGroup: %s\n", err) 52 | } else { 53 | group_sourceValues.NewStringArgument(&distinguishedName, "-D", "--distinguished-name", "", false, "Distinguished Name.") 54 | // File sources 55 | group_sourceValues.NewStringArgument(&sourceFileHex, "-fh", "--file-hex", "", false, "Path to file containing the hexadecimal string value of NTSecurityDescriptor.") 56 | group_sourceValues.NewStringArgument(&sourceFileBase64, "-fb", "--file-base64", "", false, "Path to file containing the base64 encoded value of NTSecurityDescriptor.") 57 | group_sourceValues.NewStringArgument(&sourceFileRaw, "-fr", "--file-raw", "", false, "Path to file containing the raw binary value of NTSecurityDescriptor.") 58 | // Value sources 59 | group_sourceValues.NewStringArgument(&valueHex, "-vh", "--value-hex", "", false, "Raw hexadecimal string value of NTSecurityDescriptor.") 60 | group_sourceValues.NewStringArgument(&valueBase64, "-vb", "--value-base64", "", false, "Raw base64 encoded value of NTSecurityDescriptor.") 61 | } 62 | 63 | group_ldapSettings, err := ap.NewArgumentGroup("LDAP Connection Settings") 64 | if err != nil { 65 | fmt.Printf("[error] Error creating ArgumentGroup: %s\n", err) 66 | } else { 67 | group_ldapSettings.NewStringArgument(&domainController, "-dc", "--dc-ip", "", false, "IP Address of the domain controller or KDC (Key Distribution Center) for Kerberos. If omitted, it will use the domain part (FQDN) specified in the identity parameter.") 68 | group_ldapSettings.NewTcpPortArgument(&ldapPort, "-P", "--port", 389, false, "Port number to connect to LDAP server.") 69 | group_ldapSettings.NewBoolArgument(&useLdaps, "-l", "--use-ldaps", false, "Use LDAPS instead of LDAP.") 70 | } 71 | 72 | group_auth, err := ap.NewArgumentGroup("Authentication") 73 | if err != nil { 74 | fmt.Printf("[error] Error creating ArgumentGroup: %s\n", err) 75 | } else { 76 | group_auth.NewStringArgument(&authDomain, "-d", "--domain", "", false, "Active Directory domain to authenticate to.") 77 | group_auth.NewStringArgument(&authUsername, "-u", "--username", "", false, "User to authenticate as.") 78 | group_auth.NewStringArgument(&authPassword, "-p", "--password", "", false, "Password to authenticate with.") 79 | group_auth.NewStringArgument(&authHashes, "-H", "--hashes", "", false, "NT/LM hashes, format is LMhash:NThash.") 80 | } 81 | 82 | ap.Parse() 83 | 84 | if useLdaps && !group_ldapSettings.LongNameToArgument["--port"].IsPresent() { 85 | ldapPort = 636 86 | } 87 | 88 | if len(distinguishedName) != 0 && (len(domainController) == 0 || len(authUsername) == 0 || len(authPassword) == 0) { 89 | logger.Warn("Error: Options --dc-ip, --username, --password are required when using --distinguished-name.") 90 | os.Exit(1) 91 | } 92 | } 93 | 94 | func main() { 95 | parseArgs() 96 | 97 | rawNtsdValue := []byte{} 98 | 99 | // Parsing input values for hex format 100 | if len(rawNtsdValue) == 0 && (len(sourceFileHex) != 0 || len(valueHex) != 0) { 101 | value_hex_string := "" 102 | if len(valueHex) != 0 { 103 | value_hex_string = valueHex 104 | } 105 | if len(sourceFileHex) != 0 { 106 | data, err := os.ReadFile(sourceFileHex) 107 | if err != nil { 108 | logger.Warn(fmt.Sprintf("Error reading file: %s", err)) 109 | return 110 | } 111 | value_hex_string = string(data) 112 | } 113 | // Decoding the hex string 114 | if len(value_hex_string) != 0 { 115 | if len(value_hex_string)%2 == 1 { 116 | // encoding/hex: odd length hex string 117 | value_hex_string = value_hex_string + "0" 118 | } 119 | value, err := hex.DecodeString(value_hex_string) 120 | if err != nil { 121 | logger.Warn(fmt.Sprintf("Error decoding Hex value: %s", err)) 122 | return 123 | } else { 124 | rawNtsdValue = value 125 | } 126 | } 127 | } 128 | 129 | // Parsing input values for base64 format 130 | if len(rawNtsdValue) == 0 && (len(sourceFileBase64) != 0 || len(valueBase64) != 0) { 131 | value_base64_string := "" 132 | if len(valueBase64) != 0 { 133 | value_base64_string = valueBase64 134 | } 135 | if len(sourceFileBase64) != 0 { 136 | data, err := os.ReadFile(sourceFileBase64) 137 | if err != nil { 138 | logger.Warn(fmt.Sprintf("Error reading file: %s", err)) 139 | return 140 | } 141 | value_base64_string = string(data) 142 | } 143 | 144 | // Decoding the base64 string 145 | if len(value_base64_string) != 0 { 146 | value, err := base64.StdEncoding.DecodeString(value_base64_string) 147 | if err != nil { 148 | logger.Warn(fmt.Sprintf("Error decoding Base64 value: %s", err)) 149 | return 150 | } else { 151 | rawNtsdValue = value 152 | } 153 | } 154 | } 155 | 156 | // Parsing input values for raw format 157 | if len(rawNtsdValue) == 0 && len(sourceFileRaw) != 0 { 158 | data, err := os.ReadFile(sourceFileRaw) 159 | if err != nil { 160 | logger.Warn(fmt.Sprintf("Error reading file: %s", err)) 161 | return 162 | } 163 | rawNtsdValue = data 164 | } 165 | 166 | if len(rawNtsdValue) == 0 && len(distinguishedName) != 0 { 167 | // Parsing input values for Distinguished Name 168 | if debug { 169 | if !useLdaps { 170 | logger.Debug(fmt.Sprintf("Connecting to remote ldap://%s:%d ...", domainController, ldapPort)) 171 | } else { 172 | logger.Debug(fmt.Sprintf("Connecting to remote ldaps://%s:%d ...", domainController, ldapPort)) 173 | } 174 | } 175 | ldapSession := ldap.Session{} 176 | ldapSession.InitSession( 177 | domainController, 178 | ldapPort, 179 | useLdaps, 180 | authDomain, 181 | authUsername, 182 | authPassword, 183 | debug, 184 | ) 185 | connected := ldapSession.Connect() 186 | 187 | if connected { 188 | logger.Info(fmt.Sprintf("Connected as '%s\\%s'", authDomain, authUsername)) 189 | 190 | query := fmt.Sprintf("(distinguishedName=%s)", distinguishedName) 191 | 192 | if debug { 193 | logger.Debug(fmt.Sprintf("LDAP query used: %s", query)) 194 | } 195 | 196 | attributes := []string{"distinguishedName", "ntSecurityDescriptor"} 197 | ldapResults := ldap.QueryWholeSubtree(&ldapSession, "", query, attributes) 198 | 199 | for _, entry := range ldapResults { 200 | if debug { 201 | logger.Debug(fmt.Sprintf("| distinguishedName: %s", entry.GetAttributeValue("distinguishedName"))) 202 | } 203 | rawNtsdValue = entry.GetEqualFoldRawAttributeValue("ntSecurityDescriptor") 204 | } 205 | } else { 206 | if debug { 207 | logger.Warn("Error: Could not create ldapSession.") 208 | } 209 | } 210 | } 211 | 212 | if len(rawNtsdValue) != 0 { 213 | ntSecurityDescriptor := securitydescriptor.NtSecurityDescriptor{} 214 | logger.Debug(fmt.Sprintf("| ntSecurityDescriptor: %s", hex.EncodeToString(rawNtsdValue))) 215 | ntSecurityDescriptor.Parse(rawNtsdValue) 216 | ntSecurityDescriptor.Describe(0) 217 | } else { 218 | logger.Warn("No NTSecurityDescriptor found in source values.") 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /src/windows/RelativeIDs.go: -------------------------------------------------------------------------------- 1 | package windows 2 | 3 | // Predefined RIDs 4 | // Src: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/565a6584-3061-4ede-a531-f5c53826504b 5 | const ( 6 | RID_DOMAIN_USER_KRBTGT = 0x000001F6 7 | RID_DOMAIN_USER_ADMIN = 0x000001F4 8 | RID_DOMAIN_USER_GUEST = 0x000001F5 9 | RID_DOMAIN_GROUP_ADMINS = 0x00000200 10 | RID_DOMAIN_GROUP_USERS = 0x00000201 11 | RID_DOMAIN_GROUP_GUESTS = 0x00000202 12 | RID_DOMAIN_GROUP_COMPUTERS = 0x00000203 13 | RID_DOMAIN_GROUP_CONTROLLERS = 0x00000204 14 | RID_DOMAIN_GROUP_CERT_PUBLISHERS = 0x00000205 15 | RID_DOMAIN_GROUP_ENTERPRISE_READONLY_DOMAIN_CONTROLLERS = 0x000001F2 16 | RID_DOMAIN_GROUP_SCHEMA_ADMINS = 0x00000206 17 | RID_DOMAIN_GROUP_ENTERPRISE_ADMINS = 0x00000207 18 | RID_DOMAIN_GROUP_POLICY_ADMINS = 0x00000208 19 | RID_DOMAIN_GROUP_READONLY_CONTROLLERS = 0x00000209 20 | RID_DOMAIN_GROUP_CLONEABLE_CONTROLLERS = 0x0000020A 21 | RID_DOMAIN_GROUP_CDC_RESERVED = 0x0000020C 22 | RID_DOMAIN_GROUP_PROTECTED_USERS = 0x0000020D 23 | RID_DOMAIN_GROUP_KEY_ADMINS = 0x0000020E 24 | RID_DOMAIN_GROUP_ENTERPRISE_KEY_ADMINS = 0x0000020F 25 | RID_DOMAIN_GROUP_DENIED_RODC_PASSWORD_REPLICATION = 0x0000023C 26 | RID_DOMAIN_GROUP_ALIAS_CERTSVC_DCOM_ACCESS = 0x0000023E 27 | ) 28 | 29 | var DomainRIDs = []int{ 30 | RID_DOMAIN_USER_KRBTGT, 31 | RID_DOMAIN_USER_ADMIN, 32 | RID_DOMAIN_USER_GUEST, 33 | RID_DOMAIN_GROUP_ADMINS, 34 | RID_DOMAIN_GROUP_USERS, 35 | RID_DOMAIN_GROUP_GUESTS, 36 | RID_DOMAIN_GROUP_COMPUTERS, 37 | RID_DOMAIN_GROUP_CONTROLLERS, 38 | RID_DOMAIN_GROUP_CERT_PUBLISHERS, 39 | RID_DOMAIN_GROUP_ENTERPRISE_READONLY_DOMAIN_CONTROLLERS, 40 | RID_DOMAIN_GROUP_SCHEMA_ADMINS, 41 | RID_DOMAIN_GROUP_ENTERPRISE_ADMINS, 42 | RID_DOMAIN_GROUP_POLICY_ADMINS, 43 | RID_DOMAIN_GROUP_READONLY_CONTROLLERS, 44 | RID_DOMAIN_GROUP_CLONEABLE_CONTROLLERS, 45 | RID_DOMAIN_GROUP_CDC_RESERVED, 46 | RID_DOMAIN_GROUP_PROTECTED_USERS, 47 | RID_DOMAIN_GROUP_KEY_ADMINS, 48 | RID_DOMAIN_GROUP_ENTERPRISE_KEY_ADMINS, 49 | RID_DOMAIN_GROUP_DENIED_RODC_PASSWORD_REPLICATION, 50 | RID_DOMAIN_GROUP_ALIAS_CERTSVC_DCOM_ACCESS, 51 | } 52 | 53 | // Local RID 54 | // Src: https://learn.microsoft.com/en-us/windows/win32/secauthz/well-known-sids 55 | const ( 56 | RID_LOCAL_ADMINS = 0x00000220 57 | RID_LOCAL_USERS = 0x00000221 58 | RID_LOCAL_GUESTS = 0x00000222 59 | RID_LOCAL_POWER_USERS = 0x00000223 60 | RID_LOCAL_ACCOUNT_OPS = 0x00000224 61 | RID_LOCAL_SERVER_OPS = 0x00000225 62 | RID_LOCAL_PRINT_OPS = 0x00000226 63 | RID_LOCAL_BACKUP_OPS = 0x00000227 64 | RID_LOCAL_REPLICATOR = 0x00000228 65 | RID_LOCAL_RAS_SERVERS = 0x00000229 66 | RID_LOCAL_PREW2KCOMPACCESS = 0x0000022A 67 | RID_LOCAL_REMOTE_DESKTOP_USERS = 0x0000022B 68 | RID_LOCAL_NETWORK_CONFIGURATION_OPS = 0x0000022C 69 | RID_LOCAL_INCOMING_FOREST_TRUST_BUILDERS = 0x0000022D 70 | RID_LOCAL_MONITORING_USERS = 0x0000022E 71 | RID_LOCAL_LOGGING_USERS = 0x0000022F 72 | RID_LOCAL_AUTHORIZATIONACCESS = 0x00000230 73 | RID_LOCAL_TS_LICENSE_SERVERS = 0x00000231 74 | RID_LOCAL_DCOM_USERS = 0x00000232 75 | RID_LOCAL_IUSERS = 0x00000238 76 | RID_LOCAL_CRYPTO_OPERATORS = 0x00000239 77 | RID_LOCAL_CACHEABLE_PRINCIPALS_GROUP = 0x0000023B 78 | RID_LOCAL_NON_CACHEABLE_PRINCIPALS_GROUP = 0x0000023C 79 | RID_LOCAL_EVENT_LOG_READERS_GROUP = 0x0000023D 80 | RID_LOCAL_CERTSVC_DCOM_ACCESS_GROUP = 0x0000023E 81 | RID_LOCAL_RDS_REMOTE_ACCESS_SERVERS = 0x0000023F 82 | RID_LOCAL_RDS_ENDPOINT_SERVERS = 0x00000240 83 | RID_LOCAL_RDS_MANAGEMENT_SERVERS = 0x00000241 84 | RID_LOCAL_HYPER_V_ADMINS = 0x00000242 85 | RID_LOCAL_ACCESS_CONTROL_ASSISTANCE_OPS = 0x00000243 86 | RID_LOCAL_REMOTE_MANAGEMENT_USERS = 0x00000244 87 | RID_LOCAL_DEFAULT_ACCOUNT = 0x00000245 88 | RID_LOCAL_STORAGE_REPLICA_ADMINS = 0x00000246 89 | RID_LOCAL_DEVICE_OWNERS = 0x00000247 90 | ) 91 | 92 | var LocalRIDs = []int{ 93 | RID_LOCAL_ADMINS, 94 | RID_LOCAL_USERS, 95 | RID_LOCAL_GUESTS, 96 | RID_LOCAL_POWER_USERS, 97 | RID_LOCAL_ACCOUNT_OPS, 98 | RID_LOCAL_SERVER_OPS, 99 | RID_LOCAL_PRINT_OPS, 100 | RID_LOCAL_BACKUP_OPS, 101 | RID_LOCAL_REPLICATOR, 102 | RID_LOCAL_RAS_SERVERS, 103 | RID_LOCAL_PREW2KCOMPACCESS, 104 | RID_LOCAL_REMOTE_DESKTOP_USERS, 105 | RID_LOCAL_NETWORK_CONFIGURATION_OPS, 106 | RID_LOCAL_INCOMING_FOREST_TRUST_BUILDERS, 107 | RID_LOCAL_MONITORING_USERS, 108 | RID_LOCAL_LOGGING_USERS, 109 | RID_LOCAL_AUTHORIZATIONACCESS, 110 | RID_LOCAL_TS_LICENSE_SERVERS, 111 | RID_LOCAL_DCOM_USERS, 112 | RID_LOCAL_IUSERS, 113 | RID_LOCAL_CRYPTO_OPERATORS, 114 | RID_LOCAL_CACHEABLE_PRINCIPALS_GROUP, 115 | RID_LOCAL_NON_CACHEABLE_PRINCIPALS_GROUP, 116 | RID_LOCAL_EVENT_LOG_READERS_GROUP, 117 | RID_LOCAL_CERTSVC_DCOM_ACCESS_GROUP, 118 | RID_LOCAL_RDS_REMOTE_ACCESS_SERVERS, 119 | RID_LOCAL_RDS_ENDPOINT_SERVERS, 120 | RID_LOCAL_RDS_MANAGEMENT_SERVERS, 121 | RID_LOCAL_HYPER_V_ADMINS, 122 | RID_LOCAL_ACCESS_CONTROL_ASSISTANCE_OPS, 123 | RID_LOCAL_REMOTE_MANAGEMENT_USERS, 124 | RID_LOCAL_DEFAULT_ACCOUNT, 125 | RID_LOCAL_STORAGE_REPLICA_ADMINS, 126 | RID_LOCAL_DEVICE_OWNERS, 127 | } 128 | -------------------------------------------------------------------------------- /src/windows/sAMAccountType.go: -------------------------------------------------------------------------------- 1 | package windows 2 | 3 | // sAMAccountType Values 4 | // Src: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/e742be45-665d-4576-b872-0bc99d1e1fbe 5 | const ( 6 | SAM_DOMAIN_OBJECT = 0x00000000 7 | SAM_GROUP_OBJECT = 0x10000000 8 | SAM_NON_SECURITY_GROUP_OBJECT = 0x10000001 9 | SAM_ALIAS_OBJECT = 0x20000000 10 | SAM_NON_SECURITY_ALIAS_OBJECT = 0x20000001 11 | SAM_USER_OBJECT = 0x30000000 12 | SAM_MACHINE_ACCOUNT = 0x30000001 13 | SAM_TRUST_ACCOUNT = 0x30000002 14 | SAM_APP_BASIC_GROUP = 0x40000000 15 | SAM_APP_QUERY_GROUP = 0x40000001 16 | ) 17 | --------------------------------------------------------------------------------