@etcsec-com/etc-collector 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +60 -0
- package/.env.test.example +33 -0
- package/.github/workflows/ci.yml +83 -0
- package/.github/workflows/release.yml +246 -0
- package/.prettierrc.json +10 -0
- package/CHANGELOG.md +15 -0
- package/Dockerfile +57 -0
- package/LICENSE +190 -0
- package/README.md +194 -0
- package/dist/api/controllers/audit.controller.d.ts +21 -0
- package/dist/api/controllers/audit.controller.d.ts.map +1 -0
- package/dist/api/controllers/audit.controller.js +179 -0
- package/dist/api/controllers/audit.controller.js.map +1 -0
- package/dist/api/controllers/auth.controller.d.ts +16 -0
- package/dist/api/controllers/auth.controller.d.ts.map +1 -0
- package/dist/api/controllers/auth.controller.js +146 -0
- package/dist/api/controllers/auth.controller.js.map +1 -0
- package/dist/api/controllers/export.controller.d.ts +27 -0
- package/dist/api/controllers/export.controller.d.ts.map +1 -0
- package/dist/api/controllers/export.controller.js +80 -0
- package/dist/api/controllers/export.controller.js.map +1 -0
- package/dist/api/controllers/health.controller.d.ts +5 -0
- package/dist/api/controllers/health.controller.d.ts.map +1 -0
- package/dist/api/controllers/health.controller.js +16 -0
- package/dist/api/controllers/health.controller.js.map +1 -0
- package/dist/api/controllers/jobs.controller.d.ts +13 -0
- package/dist/api/controllers/jobs.controller.d.ts.map +1 -0
- package/dist/api/controllers/jobs.controller.js +125 -0
- package/dist/api/controllers/jobs.controller.js.map +1 -0
- package/dist/api/controllers/providers.controller.d.ts +15 -0
- package/dist/api/controllers/providers.controller.d.ts.map +1 -0
- package/dist/api/controllers/providers.controller.js +112 -0
- package/dist/api/controllers/providers.controller.js.map +1 -0
- package/dist/api/dto/AuditRequest.dto.d.ts +6 -0
- package/dist/api/dto/AuditRequest.dto.d.ts.map +1 -0
- package/dist/api/dto/AuditRequest.dto.js +3 -0
- package/dist/api/dto/AuditRequest.dto.js.map +1 -0
- package/dist/api/dto/AuditResponse.dto.d.ts +17 -0
- package/dist/api/dto/AuditResponse.dto.d.ts.map +1 -0
- package/dist/api/dto/AuditResponse.dto.js +3 -0
- package/dist/api/dto/AuditResponse.dto.js.map +1 -0
- package/dist/api/dto/TokenRequest.dto.d.ts +6 -0
- package/dist/api/dto/TokenRequest.dto.d.ts.map +1 -0
- package/dist/api/dto/TokenRequest.dto.js +3 -0
- package/dist/api/dto/TokenRequest.dto.js.map +1 -0
- package/dist/api/dto/TokenResponse.dto.d.ts +12 -0
- package/dist/api/dto/TokenResponse.dto.d.ts.map +1 -0
- package/dist/api/dto/TokenResponse.dto.js +3 -0
- package/dist/api/dto/TokenResponse.dto.js.map +1 -0
- package/dist/api/middlewares/authenticate.d.ts +12 -0
- package/dist/api/middlewares/authenticate.d.ts.map +1 -0
- package/dist/api/middlewares/authenticate.js +141 -0
- package/dist/api/middlewares/authenticate.js.map +1 -0
- package/dist/api/middlewares/errorHandler.d.ts +3 -0
- package/dist/api/middlewares/errorHandler.d.ts.map +1 -0
- package/dist/api/middlewares/errorHandler.js +30 -0
- package/dist/api/middlewares/errorHandler.js.map +1 -0
- package/dist/api/middlewares/rateLimit.d.ts +3 -0
- package/dist/api/middlewares/rateLimit.d.ts.map +1 -0
- package/dist/api/middlewares/rateLimit.js +34 -0
- package/dist/api/middlewares/rateLimit.js.map +1 -0
- package/dist/api/middlewares/validate.d.ts +4 -0
- package/dist/api/middlewares/validate.d.ts.map +1 -0
- package/dist/api/middlewares/validate.js +31 -0
- package/dist/api/middlewares/validate.js.map +1 -0
- package/dist/api/routes/audit.routes.d.ts +5 -0
- package/dist/api/routes/audit.routes.d.ts.map +1 -0
- package/dist/api/routes/audit.routes.js +24 -0
- package/dist/api/routes/audit.routes.js.map +1 -0
- package/dist/api/routes/auth.routes.d.ts +6 -0
- package/dist/api/routes/auth.routes.d.ts.map +1 -0
- package/dist/api/routes/auth.routes.js +22 -0
- package/dist/api/routes/auth.routes.js.map +1 -0
- package/dist/api/routes/export.routes.d.ts +5 -0
- package/dist/api/routes/export.routes.d.ts.map +1 -0
- package/dist/api/routes/export.routes.js +16 -0
- package/dist/api/routes/export.routes.js.map +1 -0
- package/dist/api/routes/health.routes.d.ts +4 -0
- package/dist/api/routes/health.routes.d.ts.map +1 -0
- package/dist/api/routes/health.routes.js +11 -0
- package/dist/api/routes/health.routes.js.map +1 -0
- package/dist/api/routes/index.d.ts +10 -0
- package/dist/api/routes/index.d.ts.map +1 -0
- package/dist/api/routes/index.js +20 -0
- package/dist/api/routes/index.js.map +1 -0
- package/dist/api/routes/providers.routes.d.ts +5 -0
- package/dist/api/routes/providers.routes.d.ts.map +1 -0
- package/dist/api/routes/providers.routes.js +13 -0
- package/dist/api/routes/providers.routes.js.map +1 -0
- package/dist/api/validators/audit.schemas.d.ts +60 -0
- package/dist/api/validators/audit.schemas.d.ts.map +1 -0
- package/dist/api/validators/audit.schemas.js +55 -0
- package/dist/api/validators/audit.schemas.js.map +1 -0
- package/dist/api/validators/auth.schemas.d.ts +17 -0
- package/dist/api/validators/auth.schemas.d.ts.map +1 -0
- package/dist/api/validators/auth.schemas.js +21 -0
- package/dist/api/validators/auth.schemas.js.map +1 -0
- package/dist/app.d.ts +3 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +62 -0
- package/dist/app.js.map +1 -0
- package/dist/config/config.schema.d.ts +65 -0
- package/dist/config/config.schema.d.ts.map +1 -0
- package/dist/config/config.schema.js +95 -0
- package/dist/config/config.schema.js.map +1 -0
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +75 -0
- package/dist/config/index.js.map +1 -0
- package/dist/container.d.ts +47 -0
- package/dist/container.d.ts.map +1 -0
- package/dist/container.js +137 -0
- package/dist/container.js.map +1 -0
- package/dist/data/database.d.ts +13 -0
- package/dist/data/database.d.ts.map +1 -0
- package/dist/data/database.js +68 -0
- package/dist/data/database.js.map +1 -0
- package/dist/data/jobs/token-cleanup.job.d.ts +23 -0
- package/dist/data/jobs/token-cleanup.job.d.ts.map +1 -0
- package/dist/data/jobs/token-cleanup.job.js +96 -0
- package/dist/data/jobs/token-cleanup.job.js.map +1 -0
- package/dist/data/migrations/migration.runner.d.ts +13 -0
- package/dist/data/migrations/migration.runner.d.ts.map +1 -0
- package/dist/data/migrations/migration.runner.js +136 -0
- package/dist/data/migrations/migration.runner.js.map +1 -0
- package/dist/data/models/Token.model.d.ts +30 -0
- package/dist/data/models/Token.model.d.ts.map +1 -0
- package/dist/data/models/Token.model.js +3 -0
- package/dist/data/models/Token.model.js.map +1 -0
- package/dist/data/repositories/token.repository.d.ts +16 -0
- package/dist/data/repositories/token.repository.d.ts.map +1 -0
- package/dist/data/repositories/token.repository.js +97 -0
- package/dist/data/repositories/token.repository.js.map +1 -0
- package/dist/providers/azure/auth.provider.d.ts +5 -0
- package/dist/providers/azure/auth.provider.d.ts.map +1 -0
- package/dist/providers/azure/auth.provider.js +13 -0
- package/dist/providers/azure/auth.provider.js.map +1 -0
- package/dist/providers/azure/azure-errors.d.ts +40 -0
- package/dist/providers/azure/azure-errors.d.ts.map +1 -0
- package/dist/providers/azure/azure-errors.js +121 -0
- package/dist/providers/azure/azure-errors.js.map +1 -0
- package/dist/providers/azure/azure-retry.d.ts +41 -0
- package/dist/providers/azure/azure-retry.d.ts.map +1 -0
- package/dist/providers/azure/azure-retry.js +85 -0
- package/dist/providers/azure/azure-retry.js.map +1 -0
- package/dist/providers/azure/graph-client.d.ts +26 -0
- package/dist/providers/azure/graph-client.d.ts.map +1 -0
- package/dist/providers/azure/graph-client.js +146 -0
- package/dist/providers/azure/graph-client.js.map +1 -0
- package/dist/providers/azure/graph.provider.d.ts +23 -0
- package/dist/providers/azure/graph.provider.d.ts.map +1 -0
- package/dist/providers/azure/graph.provider.js +161 -0
- package/dist/providers/azure/graph.provider.js.map +1 -0
- package/dist/providers/azure/queries/app.queries.d.ts +6 -0
- package/dist/providers/azure/queries/app.queries.d.ts.map +1 -0
- package/dist/providers/azure/queries/app.queries.js +9 -0
- package/dist/providers/azure/queries/app.queries.js.map +1 -0
- package/dist/providers/azure/queries/policy.queries.d.ts +6 -0
- package/dist/providers/azure/queries/policy.queries.d.ts.map +1 -0
- package/dist/providers/azure/queries/policy.queries.js +9 -0
- package/dist/providers/azure/queries/policy.queries.js.map +1 -0
- package/dist/providers/azure/queries/user.queries.d.ts +7 -0
- package/dist/providers/azure/queries/user.queries.d.ts.map +1 -0
- package/dist/providers/azure/queries/user.queries.js +10 -0
- package/dist/providers/azure/queries/user.queries.js.map +1 -0
- package/dist/providers/interfaces/IGraphProvider.d.ts +31 -0
- package/dist/providers/interfaces/IGraphProvider.d.ts.map +1 -0
- package/dist/providers/interfaces/IGraphProvider.js +3 -0
- package/dist/providers/interfaces/IGraphProvider.js.map +1 -0
- package/dist/providers/interfaces/ILDAPProvider.d.ts +37 -0
- package/dist/providers/interfaces/ILDAPProvider.d.ts.map +1 -0
- package/dist/providers/interfaces/ILDAPProvider.js +3 -0
- package/dist/providers/interfaces/ILDAPProvider.js.map +1 -0
- package/dist/providers/ldap/acl-parser.d.ts +8 -0
- package/dist/providers/ldap/acl-parser.d.ts.map +1 -0
- package/dist/providers/ldap/acl-parser.js +157 -0
- package/dist/providers/ldap/acl-parser.js.map +1 -0
- package/dist/providers/ldap/ad-mappers.d.ts +8 -0
- package/dist/providers/ldap/ad-mappers.d.ts.map +1 -0
- package/dist/providers/ldap/ad-mappers.js +162 -0
- package/dist/providers/ldap/ad-mappers.js.map +1 -0
- package/dist/providers/ldap/ldap-client.d.ts +33 -0
- package/dist/providers/ldap/ldap-client.d.ts.map +1 -0
- package/dist/providers/ldap/ldap-client.js +195 -0
- package/dist/providers/ldap/ldap-client.js.map +1 -0
- package/dist/providers/ldap/ldap-errors.d.ts +48 -0
- package/dist/providers/ldap/ldap-errors.d.ts.map +1 -0
- package/dist/providers/ldap/ldap-errors.js +120 -0
- package/dist/providers/ldap/ldap-errors.js.map +1 -0
- package/dist/providers/ldap/ldap-retry.d.ts +14 -0
- package/dist/providers/ldap/ldap-retry.d.ts.map +1 -0
- package/dist/providers/ldap/ldap-retry.js +102 -0
- package/dist/providers/ldap/ldap-retry.js.map +1 -0
- package/dist/providers/ldap/ldap-sanitizer.d.ts +12 -0
- package/dist/providers/ldap/ldap-sanitizer.d.ts.map +1 -0
- package/dist/providers/ldap/ldap-sanitizer.js +104 -0
- package/dist/providers/ldap/ldap-sanitizer.js.map +1 -0
- package/dist/providers/ldap/ldap.provider.d.ts +21 -0
- package/dist/providers/ldap/ldap.provider.d.ts.map +1 -0
- package/dist/providers/ldap/ldap.provider.js +165 -0
- package/dist/providers/ldap/ldap.provider.js.map +1 -0
- package/dist/providers/ldap/queries/computer.queries.d.ts +6 -0
- package/dist/providers/ldap/queries/computer.queries.d.ts.map +1 -0
- package/dist/providers/ldap/queries/computer.queries.js +9 -0
- package/dist/providers/ldap/queries/computer.queries.js.map +1 -0
- package/dist/providers/ldap/queries/group.queries.d.ts +6 -0
- package/dist/providers/ldap/queries/group.queries.d.ts.map +1 -0
- package/dist/providers/ldap/queries/group.queries.js +9 -0
- package/dist/providers/ldap/queries/group.queries.js.map +1 -0
- package/dist/providers/ldap/queries/user.queries.d.ts +7 -0
- package/dist/providers/ldap/queries/user.queries.d.ts.map +1 -0
- package/dist/providers/ldap/queries/user.queries.js +10 -0
- package/dist/providers/ldap/queries/user.queries.js.map +1 -0
- package/dist/providers/smb/smb.provider.d.ts +68 -0
- package/dist/providers/smb/smb.provider.d.ts.map +1 -0
- package/dist/providers/smb/smb.provider.js +382 -0
- package/dist/providers/smb/smb.provider.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +44 -0
- package/dist/server.js.map +1 -0
- package/dist/services/audit/ad-audit.service.d.ts +70 -0
- package/dist/services/audit/ad-audit.service.d.ts.map +1 -0
- package/dist/services/audit/ad-audit.service.js +1019 -0
- package/dist/services/audit/ad-audit.service.js.map +1 -0
- package/dist/services/audit/attack-graph.service.d.ts +62 -0
- package/dist/services/audit/attack-graph.service.d.ts.map +1 -0
- package/dist/services/audit/attack-graph.service.js +702 -0
- package/dist/services/audit/attack-graph.service.js.map +1 -0
- package/dist/services/audit/audit.service.d.ts +4 -0
- package/dist/services/audit/audit.service.d.ts.map +1 -0
- package/dist/services/audit/audit.service.js +10 -0
- package/dist/services/audit/audit.service.js.map +1 -0
- package/dist/services/audit/azure-audit.service.d.ts +37 -0
- package/dist/services/audit/azure-audit.service.d.ts.map +1 -0
- package/dist/services/audit/azure-audit.service.js +153 -0
- package/dist/services/audit/azure-audit.service.js.map +1 -0
- package/dist/services/audit/detectors/ad/accounts.detector.d.ts +37 -0
- package/dist/services/audit/detectors/ad/accounts.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/accounts.detector.js +881 -0
- package/dist/services/audit/detectors/ad/accounts.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/adcs.detector.d.ts +21 -0
- package/dist/services/audit/detectors/ad/adcs.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/adcs.detector.js +227 -0
- package/dist/services/audit/detectors/ad/adcs.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/advanced.detector.d.ts +63 -0
- package/dist/services/audit/detectors/ad/advanced.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/advanced.detector.js +867 -0
- package/dist/services/audit/detectors/ad/advanced.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/attack-paths.detector.d.ts +16 -0
- package/dist/services/audit/detectors/ad/attack-paths.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/attack-paths.detector.js +369 -0
- package/dist/services/audit/detectors/ad/attack-paths.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/compliance.detector.d.ts +28 -0
- package/dist/services/audit/detectors/ad/compliance.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/compliance.detector.js +896 -0
- package/dist/services/audit/detectors/ad/compliance.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/computers.detector.d.ts +30 -0
- package/dist/services/audit/detectors/ad/computers.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/computers.detector.js +799 -0
- package/dist/services/audit/detectors/ad/computers.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/gpo.detector.d.ts +17 -0
- package/dist/services/audit/detectors/ad/gpo.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/gpo.detector.js +257 -0
- package/dist/services/audit/detectors/ad/gpo.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/groups.detector.d.ts +19 -0
- package/dist/services/audit/detectors/ad/groups.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/groups.detector.js +488 -0
- package/dist/services/audit/detectors/ad/groups.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/index.d.ts +15 -0
- package/dist/services/audit/detectors/ad/index.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/index.js +51 -0
- package/dist/services/audit/detectors/ad/index.js.map +1 -0
- package/dist/services/audit/detectors/ad/kerberos.detector.d.ts +17 -0
- package/dist/services/audit/detectors/ad/kerberos.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/kerberos.detector.js +293 -0
- package/dist/services/audit/detectors/ad/kerberos.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/monitoring.detector.d.ts +23 -0
- package/dist/services/audit/detectors/ad/monitoring.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/monitoring.detector.js +328 -0
- package/dist/services/audit/detectors/ad/monitoring.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/network.detector.d.ts +39 -0
- package/dist/services/audit/detectors/ad/network.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/network.detector.js +257 -0
- package/dist/services/audit/detectors/ad/network.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/password.detector.d.ts +14 -0
- package/dist/services/audit/detectors/ad/password.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/password.detector.js +235 -0
- package/dist/services/audit/detectors/ad/password.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/permissions.detector.d.ts +20 -0
- package/dist/services/audit/detectors/ad/permissions.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/permissions.detector.js +392 -0
- package/dist/services/audit/detectors/ad/permissions.detector.js.map +1 -0
- package/dist/services/audit/detectors/ad/trusts.detector.d.ts +11 -0
- package/dist/services/audit/detectors/ad/trusts.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/ad/trusts.detector.js +186 -0
- package/dist/services/audit/detectors/ad/trusts.detector.js.map +1 -0
- package/dist/services/audit/detectors/azure/app-security.detector.d.ts +11 -0
- package/dist/services/audit/detectors/azure/app-security.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/azure/app-security.detector.js +184 -0
- package/dist/services/audit/detectors/azure/app-security.detector.js.map +1 -0
- package/dist/services/audit/detectors/azure/conditional-access.detector.d.ts +10 -0
- package/dist/services/audit/detectors/azure/conditional-access.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/azure/conditional-access.detector.js +130 -0
- package/dist/services/audit/detectors/azure/conditional-access.detector.js.map +1 -0
- package/dist/services/audit/detectors/azure/privilege-security.detector.d.ts +8 -0
- package/dist/services/audit/detectors/azure/privilege-security.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/azure/privilege-security.detector.js +113 -0
- package/dist/services/audit/detectors/azure/privilege-security.detector.js.map +1 -0
- package/dist/services/audit/detectors/azure/user-security.detector.d.ts +14 -0
- package/dist/services/audit/detectors/azure/user-security.detector.d.ts.map +1 -0
- package/dist/services/audit/detectors/azure/user-security.detector.js +198 -0
- package/dist/services/audit/detectors/azure/user-security.detector.js.map +1 -0
- package/dist/services/audit/detectors/index.d.ts +2 -0
- package/dist/services/audit/detectors/index.d.ts.map +1 -0
- package/dist/services/audit/detectors/index.js +38 -0
- package/dist/services/audit/detectors/index.js.map +1 -0
- package/dist/services/audit/response-formatter.d.ts +176 -0
- package/dist/services/audit/response-formatter.d.ts.map +1 -0
- package/dist/services/audit/response-formatter.js +240 -0
- package/dist/services/audit/response-formatter.js.map +1 -0
- package/dist/services/audit/scoring.service.d.ts +15 -0
- package/dist/services/audit/scoring.service.d.ts.map +1 -0
- package/dist/services/audit/scoring.service.js +139 -0
- package/dist/services/audit/scoring.service.js.map +1 -0
- package/dist/services/auth/crypto.service.d.ts +19 -0
- package/dist/services/auth/crypto.service.d.ts.map +1 -0
- package/dist/services/auth/crypto.service.js +135 -0
- package/dist/services/auth/crypto.service.js.map +1 -0
- package/dist/services/auth/errors.d.ts +19 -0
- package/dist/services/auth/errors.d.ts.map +1 -0
- package/dist/services/auth/errors.js +46 -0
- package/dist/services/auth/errors.js.map +1 -0
- package/dist/services/auth/token.service.d.ts +41 -0
- package/dist/services/auth/token.service.d.ts.map +1 -0
- package/dist/services/auth/token.service.js +208 -0
- package/dist/services/auth/token.service.js.map +1 -0
- package/dist/services/config/config.service.d.ts +6 -0
- package/dist/services/config/config.service.d.ts.map +1 -0
- package/dist/services/config/config.service.js +64 -0
- package/dist/services/config/config.service.js.map +1 -0
- package/dist/services/export/export.service.d.ts +28 -0
- package/dist/services/export/export.service.d.ts.map +1 -0
- package/dist/services/export/export.service.js +28 -0
- package/dist/services/export/export.service.js.map +1 -0
- package/dist/services/export/formatters/csv.formatter.d.ts +8 -0
- package/dist/services/export/formatters/csv.formatter.d.ts.map +1 -0
- package/dist/services/export/formatters/csv.formatter.js +46 -0
- package/dist/services/export/formatters/csv.formatter.js.map +1 -0
- package/dist/services/export/formatters/json.formatter.d.ts +40 -0
- package/dist/services/export/formatters/json.formatter.d.ts.map +1 -0
- package/dist/services/export/formatters/json.formatter.js +58 -0
- package/dist/services/export/formatters/json.formatter.js.map +1 -0
- package/dist/services/jobs/azure-job-runner.d.ts +38 -0
- package/dist/services/jobs/azure-job-runner.d.ts.map +1 -0
- package/dist/services/jobs/azure-job-runner.js +199 -0
- package/dist/services/jobs/azure-job-runner.js.map +1 -0
- package/dist/services/jobs/index.d.ts +4 -0
- package/dist/services/jobs/index.d.ts.map +1 -0
- package/dist/services/jobs/index.js +20 -0
- package/dist/services/jobs/index.js.map +1 -0
- package/dist/services/jobs/job-runner.d.ts +64 -0
- package/dist/services/jobs/job-runner.d.ts.map +1 -0
- package/dist/services/jobs/job-runner.js +952 -0
- package/dist/services/jobs/job-runner.js.map +1 -0
- package/dist/services/jobs/job-store.d.ts +27 -0
- package/dist/services/jobs/job-store.d.ts.map +1 -0
- package/dist/services/jobs/job-store.js +261 -0
- package/dist/services/jobs/job-store.js.map +1 -0
- package/dist/services/jobs/job.types.d.ts +67 -0
- package/dist/services/jobs/job.types.d.ts.map +1 -0
- package/dist/services/jobs/job.types.js +36 -0
- package/dist/services/jobs/job.types.js.map +1 -0
- package/dist/types/ad.types.d.ts +74 -0
- package/dist/types/ad.types.d.ts.map +1 -0
- package/dist/types/ad.types.js +3 -0
- package/dist/types/ad.types.js.map +1 -0
- package/dist/types/adcs.types.d.ts +58 -0
- package/dist/types/adcs.types.d.ts.map +1 -0
- package/dist/types/adcs.types.js +38 -0
- package/dist/types/adcs.types.js.map +1 -0
- package/dist/types/attack-graph.types.d.ts +135 -0
- package/dist/types/attack-graph.types.d.ts.map +1 -0
- package/dist/types/attack-graph.types.js +58 -0
- package/dist/types/attack-graph.types.js.map +1 -0
- package/dist/types/audit.types.d.ts +34 -0
- package/dist/types/audit.types.d.ts.map +1 -0
- package/dist/types/audit.types.js +3 -0
- package/dist/types/audit.types.js.map +1 -0
- package/dist/types/azure.types.d.ts +61 -0
- package/dist/types/azure.types.d.ts.map +1 -0
- package/dist/types/azure.types.js +3 -0
- package/dist/types/azure.types.js.map +1 -0
- package/dist/types/config.types.d.ts +63 -0
- package/dist/types/config.types.d.ts.map +1 -0
- package/dist/types/config.types.js +3 -0
- package/dist/types/config.types.js.map +1 -0
- package/dist/types/error.types.d.ts +33 -0
- package/dist/types/error.types.d.ts.map +1 -0
- package/dist/types/error.types.js +70 -0
- package/dist/types/error.types.js.map +1 -0
- package/dist/types/finding.types.d.ts +133 -0
- package/dist/types/finding.types.d.ts.map +1 -0
- package/dist/types/finding.types.js +3 -0
- package/dist/types/finding.types.js.map +1 -0
- package/dist/types/gpo.types.d.ts +39 -0
- package/dist/types/gpo.types.d.ts.map +1 -0
- package/dist/types/gpo.types.js +15 -0
- package/dist/types/gpo.types.js.map +1 -0
- package/dist/types/token.types.d.ts +26 -0
- package/dist/types/token.types.d.ts.map +1 -0
- package/dist/types/token.types.js +3 -0
- package/dist/types/token.types.js.map +1 -0
- package/dist/types/trust.types.d.ts +45 -0
- package/dist/types/trust.types.d.ts.map +1 -0
- package/dist/types/trust.types.js +71 -0
- package/dist/types/trust.types.js.map +1 -0
- package/dist/utils/entity-converter.d.ts +17 -0
- package/dist/utils/entity-converter.d.ts.map +1 -0
- package/dist/utils/entity-converter.js +285 -0
- package/dist/utils/entity-converter.js.map +1 -0
- package/dist/utils/graph.util.d.ts +66 -0
- package/dist/utils/graph.util.d.ts.map +1 -0
- package/dist/utils/graph.util.js +382 -0
- package/dist/utils/graph.util.js.map +1 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +86 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/type-name-normalizer.d.ts +5 -0
- package/dist/utils/type-name-normalizer.d.ts.map +1 -0
- package/dist/utils/type-name-normalizer.js +218 -0
- package/dist/utils/type-name-normalizer.js.map +1 -0
- package/docker-compose.yml +26 -0
- package/docs/api/README.md +178 -0
- package/docs/api/openapi.yaml +1524 -0
- package/eslint.config.js +54 -0
- package/jest.config.js +38 -0
- package/package.json +97 -0
- package/scripts/fetch-ad-cert.sh +142 -0
- package/src/.gitkeep +0 -0
- package/src/api/.gitkeep +0 -0
- package/src/api/controllers/.gitkeep +0 -0
- package/src/api/controllers/audit.controller.ts +313 -0
- package/src/api/controllers/auth.controller.ts +258 -0
- package/src/api/controllers/export.controller.ts +153 -0
- package/src/api/controllers/health.controller.ts +16 -0
- package/src/api/controllers/jobs.controller.ts +187 -0
- package/src/api/controllers/providers.controller.ts +165 -0
- package/src/api/dto/.gitkeep +0 -0
- package/src/api/dto/AuditRequest.dto.ts +8 -0
- package/src/api/dto/AuditResponse.dto.ts +19 -0
- package/src/api/dto/TokenRequest.dto.ts +8 -0
- package/src/api/dto/TokenResponse.dto.ts +14 -0
- package/src/api/middlewares/.gitkeep +0 -0
- package/src/api/middlewares/authenticate.ts +203 -0
- package/src/api/middlewares/errorHandler.ts +54 -0
- package/src/api/middlewares/rateLimit.ts +35 -0
- package/src/api/middlewares/validate.ts +32 -0
- package/src/api/routes/.gitkeep +0 -0
- package/src/api/routes/audit.routes.ts +77 -0
- package/src/api/routes/auth.routes.ts +71 -0
- package/src/api/routes/export.routes.ts +34 -0
- package/src/api/routes/health.routes.ts +14 -0
- package/src/api/routes/index.ts +40 -0
- package/src/api/routes/providers.routes.ts +24 -0
- package/src/api/validators/.gitkeep +0 -0
- package/src/api/validators/audit.schemas.ts +59 -0
- package/src/api/validators/auth.schemas.ts +59 -0
- package/src/app.ts +87 -0
- package/src/config/.gitkeep +0 -0
- package/src/config/config.schema.ts +108 -0
- package/src/config/index.ts +82 -0
- package/src/container.ts +221 -0
- package/src/data/.gitkeep +0 -0
- package/src/data/database.ts +78 -0
- package/src/data/jobs/token-cleanup.job.ts +166 -0
- package/src/data/migrations/.gitkeep +0 -0
- package/src/data/migrations/001_initial_schema.sql +47 -0
- package/src/data/migrations/migration.runner.ts +125 -0
- package/src/data/models/.gitkeep +0 -0
- package/src/data/models/Token.model.ts +35 -0
- package/src/data/repositories/.gitkeep +0 -0
- package/src/data/repositories/token.repository.ts +160 -0
- package/src/providers/.gitkeep +0 -0
- package/src/providers/azure/.gitkeep +0 -0
- package/src/providers/azure/auth.provider.ts +14 -0
- package/src/providers/azure/azure-errors.ts +189 -0
- package/src/providers/azure/azure-retry.ts +168 -0
- package/src/providers/azure/graph-client.ts +315 -0
- package/src/providers/azure/graph.provider.ts +294 -0
- package/src/providers/azure/queries/app.queries.ts +9 -0
- package/src/providers/azure/queries/policy.queries.ts +9 -0
- package/src/providers/azure/queries/user.queries.ts +10 -0
- package/src/providers/interfaces/.gitkeep +0 -0
- package/src/providers/interfaces/IGraphProvider.ts +117 -0
- package/src/providers/interfaces/ILDAPProvider.ts +142 -0
- package/src/providers/ldap/.gitkeep +0 -0
- package/src/providers/ldap/acl-parser.ts +231 -0
- package/src/providers/ldap/ad-mappers.ts +280 -0
- package/src/providers/ldap/ldap-client.ts +259 -0
- package/src/providers/ldap/ldap-errors.ts +188 -0
- package/src/providers/ldap/ldap-retry.ts +267 -0
- package/src/providers/ldap/ldap-sanitizer.ts +273 -0
- package/src/providers/ldap/ldap.provider.ts +293 -0
- package/src/providers/ldap/queries/computer.queries.ts +9 -0
- package/src/providers/ldap/queries/group.queries.ts +9 -0
- package/src/providers/ldap/queries/user.queries.ts +10 -0
- package/src/providers/smb/smb.provider.ts +653 -0
- package/src/server.ts +60 -0
- package/src/services/.gitkeep +0 -0
- package/src/services/audit/.gitkeep +0 -0
- package/src/services/audit/ad-audit.service.ts +1481 -0
- package/src/services/audit/attack-graph.service.ts +1104 -0
- package/src/services/audit/audit.service.ts +12 -0
- package/src/services/audit/azure-audit.service.ts +286 -0
- package/src/services/audit/detectors/ad/accounts.detector.ts +1232 -0
- package/src/services/audit/detectors/ad/adcs.detector.ts +449 -0
- package/src/services/audit/detectors/ad/advanced.detector.ts +1270 -0
- package/src/services/audit/detectors/ad/attack-paths.detector.ts +600 -0
- package/src/services/audit/detectors/ad/compliance.detector.ts +1421 -0
- package/src/services/audit/detectors/ad/computers.detector.ts +1188 -0
- package/src/services/audit/detectors/ad/gpo.detector.ts +485 -0
- package/src/services/audit/detectors/ad/groups.detector.ts +685 -0
- package/src/services/audit/detectors/ad/index.ts +84 -0
- package/src/services/audit/detectors/ad/kerberos.detector.ts +424 -0
- package/src/services/audit/detectors/ad/monitoring.detector.ts +501 -0
- package/src/services/audit/detectors/ad/network.detector.ts +538 -0
- package/src/services/audit/detectors/ad/password.detector.ts +324 -0
- package/src/services/audit/detectors/ad/permissions.detector.ts +637 -0
- package/src/services/audit/detectors/ad/trusts.detector.ts +315 -0
- package/src/services/audit/detectors/azure/app-security.detector.ts +246 -0
- package/src/services/audit/detectors/azure/conditional-access.detector.ts +186 -0
- package/src/services/audit/detectors/azure/privilege-security.detector.ts +176 -0
- package/src/services/audit/detectors/azure/user-security.detector.ts +280 -0
- package/src/services/audit/detectors/index.ts +18 -0
- package/src/services/audit/response-formatter.ts +604 -0
- package/src/services/audit/scoring.service.ts +234 -0
- package/src/services/auth/.gitkeep +0 -0
- package/src/services/auth/crypto.service.ts +230 -0
- package/src/services/auth/errors.ts +47 -0
- package/src/services/auth/token.service.ts +420 -0
- package/src/services/config/.gitkeep +0 -0
- package/src/services/config/config.service.ts +75 -0
- package/src/services/export/.gitkeep +0 -0
- package/src/services/export/export.service.ts +99 -0
- package/src/services/export/formatters/csv.formatter.ts +124 -0
- package/src/services/export/formatters/json.formatter.ts +160 -0
- package/src/services/jobs/azure-job-runner.ts +312 -0
- package/src/services/jobs/index.ts +9 -0
- package/src/services/jobs/job-runner.ts +1280 -0
- package/src/services/jobs/job-store.ts +384 -0
- package/src/services/jobs/job.types.ts +182 -0
- package/src/types/.gitkeep +0 -0
- package/src/types/ad.types.ts +91 -0
- package/src/types/adcs.types.ts +107 -0
- package/src/types/attack-graph.types.ts +260 -0
- package/src/types/audit.types.ts +42 -0
- package/src/types/azure.types.ts +68 -0
- package/src/types/config.types.ts +79 -0
- package/src/types/error.types.ts +69 -0
- package/src/types/finding.types.ts +284 -0
- package/src/types/gpo.types.ts +72 -0
- package/src/types/smb2.d.ts +73 -0
- package/src/types/token.types.ts +32 -0
- package/src/types/trust.types.ts +140 -0
- package/src/utils/.gitkeep +0 -0
- package/src/utils/entity-converter.ts +453 -0
- package/src/utils/graph.util.ts +609 -0
- package/src/utils/logger.ts +111 -0
- package/src/utils/type-name-normalizer.ts +302 -0
- package/tests/.gitkeep +0 -0
- package/tests/e2e/.gitkeep +0 -0
- package/tests/fixtures/.gitkeep +0 -0
- package/tests/integration/.gitkeep +0 -0
- package/tests/integration/README.md +156 -0
- package/tests/integration/ad-audit.integration.test.ts +216 -0
- package/tests/integration/api/.gitkeep +0 -0
- package/tests/integration/api/endpoints.integration.test.ts +431 -0
- package/tests/integration/auth/jwt-authentication.integration.test.ts +358 -0
- package/tests/integration/providers/.gitkeep +0 -0
- package/tests/integration/providers/azure-basic.integration.test.ts +167 -0
- package/tests/integration/providers/ldap-basic.integration.test.ts +152 -0
- package/tests/integration/providers/ldap-connectivity.test.ts +44 -0
- package/tests/integration/providers/ldap-provider.integration.test.ts +347 -0
- package/tests/mocks/.gitkeep +0 -0
- package/tests/setup.ts +16 -0
- package/tests/unit/.gitkeep +0 -0
- package/tests/unit/api/middlewares/authenticate.test.ts +446 -0
- package/tests/unit/providers/.gitkeep +0 -0
- package/tests/unit/providers/azure/azure-errors.test.ts +193 -0
- package/tests/unit/providers/azure/azure-retry.test.ts +254 -0
- package/tests/unit/providers/azure/graph-provider.test.ts +313 -0
- package/tests/unit/providers/ldap/ad-mappers.test.ts +392 -0
- package/tests/unit/providers/ldap/ldap-provider.test.ts +376 -0
- package/tests/unit/providers/ldap/ldap-retry.test.ts +377 -0
- package/tests/unit/providers/ldap/ldap-sanitizer.test.ts +301 -0
- package/tests/unit/sample.test.ts +19 -0
- package/tests/unit/services/.gitkeep +0 -0
- package/tests/unit/services/audit/detectors/ad/accounts.detector.test.ts +393 -0
- package/tests/unit/services/audit/detectors/ad/advanced.detector.test.ts +380 -0
- package/tests/unit/services/audit/detectors/ad/computers.detector.test.ts +440 -0
- package/tests/unit/services/audit/detectors/ad/groups.detector.test.ts +276 -0
- package/tests/unit/services/audit/detectors/ad/kerberos.detector.test.ts +215 -0
- package/tests/unit/services/audit/detectors/ad/password.detector.test.ts +226 -0
- package/tests/unit/services/audit/detectors/ad/permissions.detector.test.ts +244 -0
- package/tests/unit/services/audit/detectors/azure/app-security.detector.test.ts +349 -0
- package/tests/unit/services/audit/detectors/azure/conditional-access.detector.test.ts +374 -0
- package/tests/unit/services/audit/detectors/azure/privilege-security.detector.test.ts +374 -0
- package/tests/unit/services/audit/detectors/azure/user-security.detector.test.ts +297 -0
- package/tests/unit/services/auth/crypto.service.test.ts +296 -0
- package/tests/unit/services/auth/token.service.test.ts +579 -0
- package/tests/unit/services/export/export.service.test.ts +241 -0
- package/tests/unit/services/export/formatters/csv.formatter.test.ts +270 -0
- package/tests/unit/services/export/formatters/json.formatter.test.ts +258 -0
- package/tests/unit/utils/.gitkeep +0 -0
- package/tsconfig.json +50 -0
|
@@ -0,0 +1,637 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permissions & ACL Security Vulnerability Detector
|
|
3
|
+
*
|
|
4
|
+
* Detects ACL-related vulnerabilities in AD.
|
|
5
|
+
* Story 1.7: AD Vulnerability Detection Engine
|
|
6
|
+
*
|
|
7
|
+
* Vulnerabilities detected (15):
|
|
8
|
+
* CRITICAL (1) - Phase 4:
|
|
9
|
+
* - ACL_DS_REPLICATION_GET_CHANGES
|
|
10
|
+
*
|
|
11
|
+
* HIGH (4):
|
|
12
|
+
* - ACL_GENERICALL
|
|
13
|
+
* - ACL_WRITEDACL
|
|
14
|
+
* - ACL_WRITEOWNER
|
|
15
|
+
* - ACL_SELF_MEMBERSHIP - Phase 4
|
|
16
|
+
*
|
|
17
|
+
* MEDIUM (10):
|
|
18
|
+
* - ACL_GENERICWRITE
|
|
19
|
+
* - ACL_FORCECHANGEPASSWORD
|
|
20
|
+
* - EVERYONE_IN_ACL
|
|
21
|
+
* - WRITESPN_ABUSE
|
|
22
|
+
* - GPO_LINK_POISONING
|
|
23
|
+
* - ADMINSDHOLDER_BACKDOOR
|
|
24
|
+
* - ACL_ADD_MEMBER - Phase 4
|
|
25
|
+
* - ACL_WRITE_PROPERTY_EXTENDED - Phase 4
|
|
26
|
+
* - ACL_USER_FORCE_CHANGE_PASSWORD - Phase 4
|
|
27
|
+
* - ACL_COMPUTER_WRITE_VALIDATED_DNS - Phase 4
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import { Finding } from '../../../../types/finding.types';
|
|
31
|
+
import { AclEntry } from '../../../../types/ad.types';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Helper to get unique objects from ACL entries
|
|
35
|
+
*/
|
|
36
|
+
function getUniqueObjects(entries: AclEntry[]): string[] {
|
|
37
|
+
return [...new Set(entries.map((ace) => ace.objectDn))];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Check for GenericAll permission on sensitive objects
|
|
42
|
+
*
|
|
43
|
+
* GENERIC_ALL can be stored as:
|
|
44
|
+
* - 0x10000000 (raw GENERIC_ALL)
|
|
45
|
+
* - 0x000F01FF (Full Control for AD objects - mapped rights)
|
|
46
|
+
*/
|
|
47
|
+
export function detectAclGenericAll(aclEntries: AclEntry[], includeDetails: boolean): Finding {
|
|
48
|
+
// GENERIC_ALL raw value
|
|
49
|
+
const GENERIC_ALL = 0x10000000;
|
|
50
|
+
// Full control mask for AD objects (all specific AD rights + standard rights)
|
|
51
|
+
// This is what GENERIC_ALL maps to when stored in AD ACLs
|
|
52
|
+
const AD_FULL_CONTROL = 0x000f01ff;
|
|
53
|
+
|
|
54
|
+
const affected = aclEntries.filter((ace) => {
|
|
55
|
+
// Check for raw GENERIC_ALL
|
|
56
|
+
if ((ace.accessMask & GENERIC_ALL) !== 0) return true;
|
|
57
|
+
// Check for Full Control (GENERIC_ALL mapped to AD rights)
|
|
58
|
+
// The mask 0x000F01FF includes: DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER | all DS rights
|
|
59
|
+
return (ace.accessMask & AD_FULL_CONTROL) === AD_FULL_CONTROL;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const uniqueObjects = getUniqueObjects(affected);
|
|
63
|
+
const totalInstances = affected.length;
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
type: 'ACL_GENERICALL',
|
|
67
|
+
severity: 'high',
|
|
68
|
+
category: 'permissions',
|
|
69
|
+
title: 'ACL GenericAll',
|
|
70
|
+
description: 'GenericAll permission on sensitive AD objects. Full control over object (reset passwords, modify groups, etc.).',
|
|
71
|
+
count: uniqueObjects.length,
|
|
72
|
+
totalInstances: totalInstances !== uniqueObjects.length ? totalInstances : undefined,
|
|
73
|
+
affectedEntities: includeDetails ? uniqueObjects : undefined,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Check for WriteDACL permission on sensitive objects
|
|
79
|
+
*/
|
|
80
|
+
export function detectAclWriteDacl(aclEntries: AclEntry[], includeDetails: boolean): Finding {
|
|
81
|
+
const WRITE_DACL = 0x00040000;
|
|
82
|
+
|
|
83
|
+
const affected = aclEntries.filter((ace) => {
|
|
84
|
+
return (ace.accessMask & WRITE_DACL) !== 0;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const uniqueObjects = getUniqueObjects(affected);
|
|
88
|
+
const totalInstances = affected.length;
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
type: 'ACL_WRITEDACL',
|
|
92
|
+
severity: 'high',
|
|
93
|
+
category: 'permissions',
|
|
94
|
+
title: 'ACL WriteDACL',
|
|
95
|
+
description: "WriteDACL permission on sensitive AD objects. Can modify object's security descriptor to grant additional permissions.",
|
|
96
|
+
count: uniqueObjects.length,
|
|
97
|
+
totalInstances: totalInstances !== uniqueObjects.length ? totalInstances : undefined,
|
|
98
|
+
affectedEntities: includeDetails ? uniqueObjects : undefined,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Check for WriteOwner permission on sensitive objects
|
|
104
|
+
*/
|
|
105
|
+
export function detectAclWriteOwner(aclEntries: AclEntry[], includeDetails: boolean): Finding {
|
|
106
|
+
const WRITE_OWNER = 0x00080000;
|
|
107
|
+
|
|
108
|
+
const affected = aclEntries.filter((ace) => {
|
|
109
|
+
return (ace.accessMask & WRITE_OWNER) !== 0;
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const uniqueObjects = getUniqueObjects(affected);
|
|
113
|
+
const totalInstances = affected.length;
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
type: 'ACL_WRITEOWNER',
|
|
117
|
+
severity: 'high',
|
|
118
|
+
category: 'permissions',
|
|
119
|
+
title: 'ACL WriteOwner',
|
|
120
|
+
description: 'WriteOwner permission on sensitive AD objects. Can take ownership of object and modify permissions.',
|
|
121
|
+
count: uniqueObjects.length,
|
|
122
|
+
totalInstances: totalInstances !== uniqueObjects.length ? totalInstances : undefined,
|
|
123
|
+
affectedEntities: includeDetails ? uniqueObjects : undefined,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Check for GenericWrite permission on sensitive objects
|
|
129
|
+
*/
|
|
130
|
+
export function detectAclGenericWrite(aclEntries: AclEntry[], includeDetails: boolean): Finding {
|
|
131
|
+
const GENERIC_WRITE = 0x40000000;
|
|
132
|
+
|
|
133
|
+
const affected = aclEntries.filter((ace) => {
|
|
134
|
+
return (ace.accessMask & GENERIC_WRITE) !== 0;
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const uniqueObjects = getUniqueObjects(affected);
|
|
138
|
+
const totalInstances = affected.length;
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
type: 'ACL_GENERICWRITE',
|
|
142
|
+
severity: 'medium',
|
|
143
|
+
category: 'permissions',
|
|
144
|
+
title: 'ACL GenericWrite',
|
|
145
|
+
description: 'GenericWrite permission on sensitive AD objects. Can modify many object attributes.',
|
|
146
|
+
count: uniqueObjects.length,
|
|
147
|
+
totalInstances: totalInstances !== uniqueObjects.length ? totalInstances : undefined,
|
|
148
|
+
affectedEntities: includeDetails ? uniqueObjects : undefined,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Check for ForceChangePassword extended right
|
|
154
|
+
*/
|
|
155
|
+
export function detectAclForceChangePassword(aclEntries: AclEntry[], includeDetails: boolean): Finding {
|
|
156
|
+
const FORCE_CHANGE_PASSWORD_GUID = '00299570-246d-11d0-a768-00aa006e0529';
|
|
157
|
+
|
|
158
|
+
const affected = aclEntries.filter((ace) => {
|
|
159
|
+
return ace.objectType === FORCE_CHANGE_PASSWORD_GUID;
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const uniqueObjects = getUniqueObjects(affected);
|
|
163
|
+
const totalInstances = affected.length;
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
type: 'ACL_FORCECHANGEPASSWORD',
|
|
167
|
+
severity: 'medium',
|
|
168
|
+
category: 'permissions',
|
|
169
|
+
title: 'ACL Force Change Password',
|
|
170
|
+
description: 'ExtendedRight to force password change on user accounts. Can reset passwords without knowing current password.',
|
|
171
|
+
count: uniqueObjects.length,
|
|
172
|
+
totalInstances: totalInstances !== uniqueObjects.length ? totalInstances : undefined,
|
|
173
|
+
affectedEntities: includeDetails ? uniqueObjects : undefined,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Check for Everyone/Authenticated Users with write permissions
|
|
179
|
+
*/
|
|
180
|
+
export function detectEveryoneInAcl(aclEntries: AclEntry[], includeDetails: boolean): Finding {
|
|
181
|
+
const EVERYONE_SID = 'S-1-1-0';
|
|
182
|
+
const AUTHENTICATED_USERS_SID = 'S-1-5-11';
|
|
183
|
+
const WRITE_MASK = 0x00020000; // ADS_RIGHT_DS_WRITE_PROP
|
|
184
|
+
|
|
185
|
+
const affected = aclEntries.filter((ace) => {
|
|
186
|
+
const isEveryone = ace.trustee === EVERYONE_SID || ace.trustee === AUTHENTICATED_USERS_SID;
|
|
187
|
+
const hasWrite = (ace.accessMask & WRITE_MASK) !== 0;
|
|
188
|
+
return isEveryone && hasWrite;
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const uniqueObjects = getUniqueObjects(affected);
|
|
192
|
+
const totalInstances = affected.length;
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
type: 'EVERYONE_IN_ACL',
|
|
196
|
+
severity: 'medium',
|
|
197
|
+
category: 'permissions',
|
|
198
|
+
title: 'Everyone in ACL',
|
|
199
|
+
description: 'Everyone or Authenticated Users with write permissions in ACL. Overly permissive access.',
|
|
200
|
+
count: uniqueObjects.length,
|
|
201
|
+
totalInstances: totalInstances !== uniqueObjects.length ? totalInstances : undefined,
|
|
202
|
+
affectedEntities: includeDetails ? uniqueObjects : undefined,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Check for WriteProperty permission for servicePrincipalName
|
|
208
|
+
*/
|
|
209
|
+
export function detectWriteSpnAbuse(aclEntries: AclEntry[], includeDetails: boolean): Finding {
|
|
210
|
+
const SPN_PROPERTY_GUID = 'f3a64788-5306-11d1-a9c5-0000f80367c1';
|
|
211
|
+
|
|
212
|
+
const affected = aclEntries.filter((ace) => {
|
|
213
|
+
return ace.objectType === SPN_PROPERTY_GUID;
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
const uniqueObjects = getUniqueObjects(affected);
|
|
217
|
+
const totalInstances = affected.length;
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
type: 'WRITESPN_ABUSE',
|
|
221
|
+
severity: 'medium',
|
|
222
|
+
category: 'permissions',
|
|
223
|
+
title: 'Write SPN Abuse',
|
|
224
|
+
description: 'WriteProperty permission for servicePrincipalName attribute. Can set SPNs for targeted Kerberoasting.',
|
|
225
|
+
count: uniqueObjects.length,
|
|
226
|
+
totalInstances: totalInstances !== uniqueObjects.length ? totalInstances : undefined,
|
|
227
|
+
affectedEntities: includeDetails ? uniqueObjects : undefined,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Check for weak ACLs on Group Policy Objects
|
|
233
|
+
*/
|
|
234
|
+
export function detectGpoLinkPoisoning(aclEntries: AclEntry[], includeDetails: boolean): Finding {
|
|
235
|
+
const GENERIC_WRITE = 0x40000000;
|
|
236
|
+
const GENERIC_ALL = 0x10000000;
|
|
237
|
+
const WRITE_DACL = 0x00040000;
|
|
238
|
+
|
|
239
|
+
const affected = aclEntries.filter((ace) => {
|
|
240
|
+
const isGpo = ace.objectDn.includes('CN=Policies,CN=System');
|
|
241
|
+
const hasDangerousPermission =
|
|
242
|
+
(ace.accessMask & GENERIC_ALL) !== 0 ||
|
|
243
|
+
(ace.accessMask & GENERIC_WRITE) !== 0 ||
|
|
244
|
+
(ace.accessMask & WRITE_DACL) !== 0;
|
|
245
|
+
|
|
246
|
+
return isGpo && hasDangerousPermission;
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
const uniqueObjects = getUniqueObjects(affected);
|
|
250
|
+
const totalInstances = affected.length;
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
type: 'GPO_LINK_POISONING',
|
|
254
|
+
severity: 'medium',
|
|
255
|
+
category: 'permissions',
|
|
256
|
+
title: 'GPO Link Poisoning',
|
|
257
|
+
description: 'Weak ACLs on Group Policy Objects. Can modify GPO to execute code on targeted systems.',
|
|
258
|
+
count: uniqueObjects.length,
|
|
259
|
+
totalInstances: totalInstances !== uniqueObjects.length ? totalInstances : undefined,
|
|
260
|
+
affectedEntities: includeDetails ? uniqueObjects : undefined,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Check for unexpected ACL on AdminSDHolder object
|
|
266
|
+
*/
|
|
267
|
+
export function detectAdminSdHolderBackdoor(aclEntries: AclEntry[], includeDetails: boolean): Finding {
|
|
268
|
+
const affected = aclEntries.filter((ace) => {
|
|
269
|
+
return ace.objectDn.includes('CN=AdminSDHolder,CN=System');
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
const uniqueObjects = getUniqueObjects(affected);
|
|
273
|
+
const totalInstances = affected.length;
|
|
274
|
+
|
|
275
|
+
return {
|
|
276
|
+
type: 'ADMINSDHOLDER_BACKDOOR',
|
|
277
|
+
severity: 'medium',
|
|
278
|
+
category: 'permissions',
|
|
279
|
+
title: 'AdminSDHolder Backdoor',
|
|
280
|
+
description: 'Unexpected ACL on AdminSDHolder object. Persistent permissions on admin accounts.',
|
|
281
|
+
count: uniqueObjects.length,
|
|
282
|
+
totalInstances: totalInstances !== uniqueObjects.length ? totalInstances : undefined,
|
|
283
|
+
affectedEntities: includeDetails ? uniqueObjects : undefined,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Detect Self-membership rights on groups
|
|
289
|
+
*
|
|
290
|
+
* Self-membership allows adding oneself to a group, enabling privilege escalation.
|
|
291
|
+
*
|
|
292
|
+
* @param aclEntries - Array of ACL entries
|
|
293
|
+
* @param includeDetails - Whether to include affected entity details
|
|
294
|
+
* @returns Finding for ACL_SELF_MEMBERSHIP
|
|
295
|
+
*/
|
|
296
|
+
export function detectAclSelfMembership(aclEntries: AclEntry[], includeDetails: boolean): Finding {
|
|
297
|
+
// Self-membership GUID: bf9679c0-0de6-11d0-a285-00aa003049e2
|
|
298
|
+
const SELF_MEMBERSHIP_GUID = 'bf9679c0-0de6-11d0-a285-00aa003049e2';
|
|
299
|
+
const WRITE_SELF = 0x8; // ADS_RIGHT_DS_SELF
|
|
300
|
+
|
|
301
|
+
const affected = aclEntries.filter((ace) => {
|
|
302
|
+
const hasWriteSelf = (ace.accessMask & WRITE_SELF) !== 0;
|
|
303
|
+
const isSelfMembership =
|
|
304
|
+
ace.objectType?.toLowerCase() === SELF_MEMBERSHIP_GUID ||
|
|
305
|
+
ace.objectType?.toLowerCase().includes('member');
|
|
306
|
+
return hasWriteSelf || isSelfMembership;
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
const uniqueObjects = getUniqueObjects(affected);
|
|
310
|
+
const totalInstances = affected.length;
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
type: 'ACL_SELF_MEMBERSHIP',
|
|
314
|
+
severity: 'high',
|
|
315
|
+
category: 'permissions',
|
|
316
|
+
title: 'Self-Membership Rights',
|
|
317
|
+
description:
|
|
318
|
+
'Principals with self-membership rights on groups. ' +
|
|
319
|
+
'Allows adding oneself to a group, potentially gaining elevated privileges.',
|
|
320
|
+
count: uniqueObjects.length,
|
|
321
|
+
totalInstances: totalInstances !== uniqueObjects.length ? totalInstances : undefined,
|
|
322
|
+
affectedEntities: includeDetails ? uniqueObjects : undefined,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Detect Add-Member rights on groups
|
|
328
|
+
*
|
|
329
|
+
* Add-Member allows adding arbitrary users to groups.
|
|
330
|
+
*
|
|
331
|
+
* @param aclEntries - Array of ACL entries
|
|
332
|
+
* @param includeDetails - Whether to include affected entity details
|
|
333
|
+
* @returns Finding for ACL_ADD_MEMBER
|
|
334
|
+
*/
|
|
335
|
+
export function detectAclAddMember(aclEntries: AclEntry[], includeDetails: boolean): Finding {
|
|
336
|
+
// Member attribute GUID: bf9679c0-0de6-11d0-a285-00aa003049e2
|
|
337
|
+
const MEMBER_GUID = 'bf9679c0-0de6-11d0-a285-00aa003049e2';
|
|
338
|
+
const WRITE_PROPERTY = 0x20;
|
|
339
|
+
|
|
340
|
+
const affected = aclEntries.filter((ace) => {
|
|
341
|
+
const hasWriteProperty = (ace.accessMask & WRITE_PROPERTY) !== 0;
|
|
342
|
+
const isMemberProperty = ace.objectType?.toLowerCase() === MEMBER_GUID;
|
|
343
|
+
return hasWriteProperty && isMemberProperty;
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
const uniqueObjects = getUniqueObjects(affected);
|
|
347
|
+
const totalInstances = affected.length;
|
|
348
|
+
|
|
349
|
+
return {
|
|
350
|
+
type: 'ACL_ADD_MEMBER',
|
|
351
|
+
severity: 'medium',
|
|
352
|
+
category: 'permissions',
|
|
353
|
+
title: 'Add-Member Rights on Groups',
|
|
354
|
+
description:
|
|
355
|
+
'Principals with rights to add members to groups. ' +
|
|
356
|
+
'Can be abused to add accounts to privileged groups.',
|
|
357
|
+
count: uniqueObjects.length,
|
|
358
|
+
totalInstances: totalInstances !== uniqueObjects.length ? totalInstances : undefined,
|
|
359
|
+
affectedEntities: includeDetails ? uniqueObjects : undefined,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Detect extended write property rights
|
|
365
|
+
*
|
|
366
|
+
* Extended write property rights can be abused for various attacks.
|
|
367
|
+
*
|
|
368
|
+
* @param aclEntries - Array of ACL entries
|
|
369
|
+
* @param includeDetails - Whether to include affected entity details
|
|
370
|
+
* @returns Finding for ACL_WRITE_PROPERTY_EXTENDED
|
|
371
|
+
*/
|
|
372
|
+
export function detectAclWritePropertyExtended(
|
|
373
|
+
aclEntries: AclEntry[],
|
|
374
|
+
includeDetails: boolean
|
|
375
|
+
): Finding {
|
|
376
|
+
// Common dangerous extended properties
|
|
377
|
+
const DANGEROUS_PROPERTIES = [
|
|
378
|
+
'00299570-246d-11d0-a768-00aa006e0529', // User-Force-Change-Password
|
|
379
|
+
'bf967a68-0de6-11d0-a285-00aa003049e2', // Script-Path
|
|
380
|
+
'bf967950-0de6-11d0-a285-00aa003049e2', // Home-Directory
|
|
381
|
+
'5f202010-79a5-11d0-9020-00c04fc2d4cf', // ms-DS-Key-Credential-Link (Shadow Credentials)
|
|
382
|
+
];
|
|
383
|
+
|
|
384
|
+
const WRITE_PROPERTY = 0x20;
|
|
385
|
+
|
|
386
|
+
const affected = aclEntries.filter((ace) => {
|
|
387
|
+
const hasWriteProperty = (ace.accessMask & WRITE_PROPERTY) !== 0;
|
|
388
|
+
const isDangerousProperty =
|
|
389
|
+
ace.objectType && DANGEROUS_PROPERTIES.includes(ace.objectType.toLowerCase());
|
|
390
|
+
return hasWriteProperty && isDangerousProperty;
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
const uniqueObjects = getUniqueObjects(affected);
|
|
394
|
+
const totalInstances = affected.length;
|
|
395
|
+
|
|
396
|
+
return {
|
|
397
|
+
type: 'ACL_WRITE_PROPERTY_EXTENDED',
|
|
398
|
+
severity: 'medium',
|
|
399
|
+
category: 'permissions',
|
|
400
|
+
title: 'Extended Write Property Rights',
|
|
401
|
+
description:
|
|
402
|
+
'Principals with dangerous extended write property rights. ' +
|
|
403
|
+
'Can modify script paths, home directories, or key credentials.',
|
|
404
|
+
count: uniqueObjects.length,
|
|
405
|
+
totalInstances: totalInstances !== uniqueObjects.length ? totalInstances : undefined,
|
|
406
|
+
affectedEntities: includeDetails ? uniqueObjects : undefined,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Detect DS-Replication-Get-Changes rights (DCSync capability)
|
|
412
|
+
*
|
|
413
|
+
* These rights allow extracting password hashes from the domain.
|
|
414
|
+
*
|
|
415
|
+
* @param aclEntries - Array of ACL entries
|
|
416
|
+
* @param includeDetails - Whether to include affected entity details
|
|
417
|
+
* @returns Finding for ACL_DS_REPLICATION_GET_CHANGES
|
|
418
|
+
*/
|
|
419
|
+
export function detectAclDsReplicationGetChanges(
|
|
420
|
+
aclEntries: AclEntry[],
|
|
421
|
+
includeDetails: boolean
|
|
422
|
+
): Finding {
|
|
423
|
+
// DS-Replication-Get-Changes: 1131f6aa-9c07-11d1-f79f-00c04fc2dcd2
|
|
424
|
+
// DS-Replication-Get-Changes-All: 1131f6ad-9c07-11d1-f79f-00c04fc2dcd2
|
|
425
|
+
const REPLICATION_GUIDS = [
|
|
426
|
+
'1131f6aa-9c07-11d1-f79f-00c04fc2dcd2',
|
|
427
|
+
'1131f6ad-9c07-11d1-f79f-00c04fc2dcd2',
|
|
428
|
+
];
|
|
429
|
+
|
|
430
|
+
const affected = aclEntries.filter((ace) => {
|
|
431
|
+
return (
|
|
432
|
+
ace.objectType && REPLICATION_GUIDS.includes(ace.objectType.toLowerCase())
|
|
433
|
+
);
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
const uniqueObjects = getUniqueObjects(affected);
|
|
437
|
+
const totalInstances = affected.length;
|
|
438
|
+
|
|
439
|
+
return {
|
|
440
|
+
type: 'ACL_DS_REPLICATION_GET_CHANGES',
|
|
441
|
+
severity: 'critical',
|
|
442
|
+
category: 'permissions',
|
|
443
|
+
title: 'DS-Replication-Get-Changes Rights (DCSync)',
|
|
444
|
+
description:
|
|
445
|
+
'Non-standard principals with directory replication rights. ' +
|
|
446
|
+
'Enables DCSync attacks to extract all password hashes from the domain.',
|
|
447
|
+
count: uniqueObjects.length,
|
|
448
|
+
totalInstances: totalInstances !== uniqueObjects.length ? totalInstances : undefined,
|
|
449
|
+
affectedEntities: includeDetails ? uniqueObjects : undefined,
|
|
450
|
+
details: {
|
|
451
|
+
risk: 'Complete domain compromise through password hash extraction.',
|
|
452
|
+
recommendation: 'Remove replication rights from all non-DC accounts.',
|
|
453
|
+
},
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Detect User-Force-Change-Password rights
|
|
459
|
+
*
|
|
460
|
+
* This right allows resetting user passwords without knowing the current password.
|
|
461
|
+
*
|
|
462
|
+
* @param aclEntries - Array of ACL entries
|
|
463
|
+
* @param includeDetails - Whether to include affected entity details
|
|
464
|
+
* @returns Finding for ACL_USER_FORCE_CHANGE_PASSWORD
|
|
465
|
+
*/
|
|
466
|
+
export function detectAclUserForceChangePassword(
|
|
467
|
+
aclEntries: AclEntry[],
|
|
468
|
+
includeDetails: boolean
|
|
469
|
+
): Finding {
|
|
470
|
+
// User-Force-Change-Password: 00299570-246d-11d0-a768-00aa006e0529
|
|
471
|
+
const FORCE_CHANGE_PASSWORD_GUID = '00299570-246d-11d0-a768-00aa006e0529';
|
|
472
|
+
|
|
473
|
+
const affected = aclEntries.filter((ace) => {
|
|
474
|
+
return ace.objectType?.toLowerCase() === FORCE_CHANGE_PASSWORD_GUID;
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
const uniqueObjects = getUniqueObjects(affected);
|
|
478
|
+
const totalInstances = affected.length;
|
|
479
|
+
|
|
480
|
+
return {
|
|
481
|
+
type: 'ACL_USER_FORCE_CHANGE_PASSWORD',
|
|
482
|
+
severity: 'medium',
|
|
483
|
+
category: 'permissions',
|
|
484
|
+
title: 'User-Force-Change-Password Rights',
|
|
485
|
+
description:
|
|
486
|
+
'Principals with rights to force password change on user accounts. ' +
|
|
487
|
+
'Can reset passwords to take over accounts.',
|
|
488
|
+
count: uniqueObjects.length,
|
|
489
|
+
totalInstances: totalInstances !== uniqueObjects.length ? totalInstances : undefined,
|
|
490
|
+
affectedEntities: includeDetails ? uniqueObjects : undefined,
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Detect Validated-Write-DNS rights on computers
|
|
496
|
+
*
|
|
497
|
+
* This right allows modifying DNS records for computers.
|
|
498
|
+
*
|
|
499
|
+
* @param aclEntries - Array of ACL entries
|
|
500
|
+
* @param includeDetails - Whether to include affected entity details
|
|
501
|
+
* @returns Finding for ACL_COMPUTER_WRITE_VALIDATED_DNS
|
|
502
|
+
*/
|
|
503
|
+
export function detectAclComputerWriteValidatedDns(
|
|
504
|
+
aclEntries: AclEntry[],
|
|
505
|
+
includeDetails: boolean
|
|
506
|
+
): Finding {
|
|
507
|
+
// Validated-Write to DNS-Host-Name: 72e39547-7b18-11d1-adef-00c04fd8d5cd
|
|
508
|
+
const VALIDATED_DNS_GUID = '72e39547-7b18-11d1-adef-00c04fd8d5cd';
|
|
509
|
+
|
|
510
|
+
const affected = aclEntries.filter((ace) => {
|
|
511
|
+
const isComputerObject = ace.objectDn.toLowerCase().includes('cn=computers');
|
|
512
|
+
const hasDnsRight = ace.objectType?.toLowerCase() === VALIDATED_DNS_GUID;
|
|
513
|
+
return isComputerObject && hasDnsRight;
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
const uniqueObjects = getUniqueObjects(affected);
|
|
517
|
+
const totalInstances = affected.length;
|
|
518
|
+
|
|
519
|
+
return {
|
|
520
|
+
type: 'ACL_COMPUTER_WRITE_VALIDATED_DNS',
|
|
521
|
+
severity: 'medium',
|
|
522
|
+
category: 'permissions',
|
|
523
|
+
title: 'Validated-Write-DNS on Computers',
|
|
524
|
+
description:
|
|
525
|
+
'Principals with rights to modify DNS host names on computer objects. ' +
|
|
526
|
+
'Can be used for DNS spoofing and MITM attacks.',
|
|
527
|
+
count: uniqueObjects.length,
|
|
528
|
+
totalInstances: totalInstances !== uniqueObjects.length ? totalInstances : undefined,
|
|
529
|
+
affectedEntities: includeDetails ? uniqueObjects : undefined,
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Check for GenericAll permission on computer objects
|
|
535
|
+
* PingCastle: Computer_ACL_GenericAll
|
|
536
|
+
*
|
|
537
|
+
* @param aclEntries - Array of ACL entries
|
|
538
|
+
* @param includeDetails - Whether to include affected entity details
|
|
539
|
+
* @param computerDns - Optional array of computer DNs for accurate matching
|
|
540
|
+
*/
|
|
541
|
+
export function detectComputerAclGenericAll(
|
|
542
|
+
aclEntries: AclEntry[],
|
|
543
|
+
includeDetails: boolean,
|
|
544
|
+
computerDns?: string[]
|
|
545
|
+
): Finding {
|
|
546
|
+
// GENERIC_ALL raw value
|
|
547
|
+
const GENERIC_ALL = 0x10000000;
|
|
548
|
+
// Full control mask for AD objects (all specific AD rights + standard rights)
|
|
549
|
+
const AD_FULL_CONTROL = 0x000f01ff;
|
|
550
|
+
|
|
551
|
+
// Build a Set of lowercase computer DNs for fast lookup
|
|
552
|
+
const computerDnSet = new Set(
|
|
553
|
+
computerDns ? computerDns.map((dn) => dn.toLowerCase()) : []
|
|
554
|
+
);
|
|
555
|
+
|
|
556
|
+
// Filter ACLs targeting computer objects
|
|
557
|
+
const computerAcls = aclEntries.filter((ace) => {
|
|
558
|
+
const dn = ace.objectDn.toLowerCase();
|
|
559
|
+
|
|
560
|
+
// If we have a list of computer DNs, use exact matching
|
|
561
|
+
if (computerDnSet.size > 0) {
|
|
562
|
+
return computerDnSet.has(dn);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Fallback: heuristic detection (less accurate)
|
|
566
|
+
// Computer accounts end with $ in their sAMAccountName (which may appear in CN)
|
|
567
|
+
const cnMatch = dn.match(/cn=([^,]+)/i);
|
|
568
|
+
if (cnMatch && cnMatch[1] && cnMatch[1].endsWith('$')) {
|
|
569
|
+
return true;
|
|
570
|
+
}
|
|
571
|
+
// Also check for computer-related OUs
|
|
572
|
+
return (
|
|
573
|
+
dn.includes('ou=computers') ||
|
|
574
|
+
dn.includes('ou=workstations') ||
|
|
575
|
+
dn.includes('ou=servers') ||
|
|
576
|
+
dn.includes('cn=computers,')
|
|
577
|
+
);
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
const affected = computerAcls.filter((ace) => {
|
|
581
|
+
// Check for raw GENERIC_ALL
|
|
582
|
+
if ((ace.accessMask & GENERIC_ALL) !== 0) return true;
|
|
583
|
+
// Check for Full Control (GENERIC_ALL mapped to AD rights)
|
|
584
|
+
return (ace.accessMask & AD_FULL_CONTROL) === AD_FULL_CONTROL;
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
const uniqueObjects = getUniqueObjects(affected);
|
|
588
|
+
const totalInstances = affected.length;
|
|
589
|
+
|
|
590
|
+
return {
|
|
591
|
+
type: 'COMPUTER_ACL_GENERICALL',
|
|
592
|
+
severity: 'high',
|
|
593
|
+
category: 'permissions',
|
|
594
|
+
title: 'Computer ACL GenericAll',
|
|
595
|
+
description:
|
|
596
|
+
'GenericAll permission on computer objects. Attacker with this permission can take over the computer, ' +
|
|
597
|
+
'configure Resource-Based Constrained Delegation (RBCD), or extract credentials.',
|
|
598
|
+
count: uniqueObjects.length,
|
|
599
|
+
totalInstances: totalInstances !== uniqueObjects.length ? totalInstances : undefined,
|
|
600
|
+
affectedEntities: includeDetails ? uniqueObjects : undefined,
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Detect all permission-related vulnerabilities
|
|
606
|
+
*
|
|
607
|
+
* @param aclEntries - Array of ACL entries
|
|
608
|
+
* @param includeDetails - Whether to include affected entity details
|
|
609
|
+
* @param computerDns - Optional array of computer DNs for accurate COMPUTER_ACL_GENERICALL detection
|
|
610
|
+
*/
|
|
611
|
+
export function detectPermissionsVulnerabilities(
|
|
612
|
+
aclEntries: AclEntry[],
|
|
613
|
+
includeDetails: boolean,
|
|
614
|
+
computerDns?: string[]
|
|
615
|
+
): Finding[] {
|
|
616
|
+
return [
|
|
617
|
+
// High
|
|
618
|
+
detectAclGenericAll(aclEntries, includeDetails),
|
|
619
|
+
detectComputerAclGenericAll(aclEntries, includeDetails, computerDns),
|
|
620
|
+
detectAclWriteDacl(aclEntries, includeDetails),
|
|
621
|
+
detectAclWriteOwner(aclEntries, includeDetails),
|
|
622
|
+
// Medium
|
|
623
|
+
detectAclGenericWrite(aclEntries, includeDetails),
|
|
624
|
+
detectAclForceChangePassword(aclEntries, includeDetails),
|
|
625
|
+
detectEveryoneInAcl(aclEntries, includeDetails),
|
|
626
|
+
detectWriteSpnAbuse(aclEntries, includeDetails),
|
|
627
|
+
detectGpoLinkPoisoning(aclEntries, includeDetails),
|
|
628
|
+
detectAdminSdHolderBackdoor(aclEntries, includeDetails),
|
|
629
|
+
// Phase 4: Advanced ACL detections
|
|
630
|
+
detectAclSelfMembership(aclEntries, includeDetails),
|
|
631
|
+
detectAclAddMember(aclEntries, includeDetails),
|
|
632
|
+
detectAclWritePropertyExtended(aclEntries, includeDetails),
|
|
633
|
+
detectAclDsReplicationGetChanges(aclEntries, includeDetails),
|
|
634
|
+
detectAclUserForceChangePassword(aclEntries, includeDetails),
|
|
635
|
+
detectAclComputerWriteValidatedDns(aclEntries, includeDetails),
|
|
636
|
+
].filter((finding) => finding.count > 0);
|
|
637
|
+
}
|