-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdecode_sap_logon_ticket.py
More file actions
executable file
·122 lines (95 loc) · 3.6 KB
/
decode_sap_logon_ticket.py
File metadata and controls
executable file
·122 lines (95 loc) · 3.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#!/usr/bin/env python3
from argparse import ArgumentParser
from urllib.parse import unquote
from base64 import b64decode
import struct
from SAPLogonTicket import (
ID_AUTHSCHEME,
ID_CREATE_CLIENT,
ID_CREATE_NAME,
ID_CREATE_TIME,
ID_FLAGS,
ID_LANGUAGE,
ID_RECIPIENT_CLIENT,
ID_RECIPIENT_SID,
ID_RFC,
ID_SIGNATURE,
ID_USER,
ID_USER_UTF,
ID_VALID_TIME,
ID_VALID_TIME_MIN,
SAPLogonTicket,
)
def parse_options():
description = "Decode a SAP Logon Ticket. It is usually stored as a cookie with the name MYSAPSSO2 after logging in."
usage = "%(prog)s Base64Encoded_MYSAPSSO2"
parser = ArgumentParser(usage=usage, description=description)
parser.add_argument(
"--extract-data-to-sign",
help="If specified, write the data to sign (i.e. everything except the signature and its header) to the file.",
)
parser.add_argument(
"--extract-signature",
help="If specified, write the signature to the file.",
)
options, args = parser.parse_known_args()
return options, args
def parse_logon_ticket(content: str):
"""Parses a LogonTicket file and produces"""
# According to https://community.sap.com/t5/technology-q-a/problems-known-with-nw2004s-sp11-and-ticket-toolkit/qaa-p/2003187/highlight/true#M877273
# the encoding is not strictly base64, it replace + with !
data = b64decode(unquote(content).encode(), "!/")
logon_ticket = SAPLogonTicket(data)
show_logon_ticket(logon_ticket)
return logon_ticket
def show_logon_ticket(ticket: SAPLogonTicket):
codepage = ticket.data_to_sign.target_system_codepage.decode()
match codepage:
case "4103":
encoding = "utf-16-le"
case "4102":
encoding = "utf-16-be"
case _:
encoding = "utf-16-le"
print(f"Unknown encoding: {codepage}. Defaulting to {encoding}")
print(f"Codepage: {codepage} (encoding = {encoding})")
for unit in ticket.data_to_sign.info_units:
TEXT_VALUES = {
ID_USER: "User name",
ID_CREATE_CLIENT: "Client",
ID_CREATE_NAME: "SID",
ID_CREATE_TIME: "Creation time",
ID_RFC: "RFC Ticket",
ID_FLAGS: "Flags",
ID_SIGNATURE: "PKCS#7 Signature",
ID_LANGUAGE: "Default language of the user",
ID_USER_UTF: "User name (utf-8 encoded)",
ID_AUTHSCHEME: "Authscheme",
ID_RECIPIENT_CLIENT: "Recipient client",
ID_RECIPIENT_SID: "Recipient system",
}
INT_VALUES = {
ID_VALID_TIME: "Valid time (hours)",
ID_VALID_TIME_MIN: "Valid time (minutes)",
}
if unit.unit_id in TEXT_VALUES:
name = TEXT_VALUES[unit.unit_id]
value = unit.unit_value.decode(encoding, errors="ignore")
elif unit.unit_id in INT_VALUES:
name = INT_VALUES[unit.unit_id]
value = str(struct.unpack("!I", unit.unit_value)[0])
else:
name = f"0x{unit.unit_id:02x}"
value = str(unit.unit_value)
print(f"{name}: {value}")
signature = ticket.pkcs7_signature
print(f"Signature: {signature.hex()}")
if __name__ == "__main__":
options, args = parse_options()
logon_ticket = parse_logon_ticket(args[0])
if options.extract_data_to_sign is not None:
with open(options.extract_data_to_sign, "wb") as f:
f.write(bytes(logon_ticket.data_to_sign))
if options.extract_signature is not None:
with open(options.extract_signature, "wb") as f:
f.write(bytes(logon_ticket.pkcs7_signature))