Time format broken in SAPRouterInfoClient
gelim opened this issue · 3 comments
Hi,
while playing with router_admin.py -l
I noticed timestamp (connected_on
, started_on
) where broken showing date like June 2121.
I don't really know what format SAP use for that, but "reversed" a bit those fields to get something plausible with following modifications:
--- a/pysap/SAPRouter.py
+++ b/pysap/SAPRouter.py
@@ -206,7 +206,8 @@ class SAPRouterInfoClient(PacketNoPadded):
BitField("flag_traced", 0, 1),
BitField("flag_connected", 0, 1),
BitField("flag_routed", 0, 1),
- LongField("connected_on", 0),
+ IntField("XXXX", 0),
+ IntField("connected_on", 0),
StrNullFixedLenField("address", None, length=45),
StrNullFixedLenField("partner", None, length=45),
StrNullFixedLenField("service", None, length=27),
@@ -234,7 +235,8 @@ class SAPRouterInfoServer(PacketNoPadded):
fields_desc = [
IntField("pid", 0),
IntField("ppid", 0),
- LongField("started_on", 0),
+ IntField("XXX", 0),
+ IntField("started_on", 0),
ShortField("port", 0),
ShortField("pport", 0),
]
and in router_admin.py
code, do some offseting:
--- a/examples/router_admin.py
+++ b/examples/router_admin.py
@@ -39,6 +39,7 @@ bind_layers(SAPNI, SAPRouter, )
# Set the verbosity to 0
conf.verb = 0
+TIME_CS = 1000000000 # Hack on time format
# Command line options parser
def parse_options():
@@ -242,12 +243,11 @@ def main():
flag = "(*)" if client.flag_traced else "(+)" if client.flag_routed else ""
fields = [str(client.id),
- client.address,
- "%s%s" % (flag, client.partner) if client.flag_routed else "(no partner)",
- client.service if client.flag_routed else "",
- datetime.fromtimestamp(client.connected_on).ctime()]
+ client.address.replace('\x00', '|'),
+ "%s%s" % (flag, client.partner.replace('\x00', '|')) if client.flag_routed else "(no partner)",
+ client.service.replace('\x00', '|') if client.flag_routed else "",
+ datetime.fromtimestamp(client.connected_on + TIME_CS).ctime()]
clients.append("\t".join(fields))
-
# Decode the second packet as server info
raw_response = conn.recv()
raw_response.decode_payload_as(SAPRouterInfoServer)
@@ -255,7 +255,7 @@ def main():
print("SAP Network Interface Router running on port %d (PID = %d)\n"
"Started on: %s\n"
"Parent process: PID = %d, port = %d\n" % (raw_response.port, raw_response.pid,
- datetime.fromtimestamp(raw_response.started_on).ctime(),
+ datetime.fromtimestamp(raw_response.started_on + TIME_CS).ctime(),
raw_response.ppid, raw_response.pport))
It's quick and dirty so you got the idea.
Adding the offset should be done at the field level, but my scapy skills are a bit rusty.
Cheers,
NB: btw I changed the '\x00' by '|', more easy to read in my opinion
-- Mathieu
Another variant not casting the Long to Int in the dissector could be to apply this transformation at client:
sapts
being what's returned by the dissector, and return value of lambda func is a more common UNIX timestamp ready to be consumed by datetime.fromtimestamp()
.
sapts_to_epoch=lambda sapts: (sapts & 0xFFFFFFFF) + 1000000000
I found the same weirdeness when started playing with those fields. In the end, figured out that the first 4 bytes were used as some way of time zone, and the remaining 4 bytes were the actual timestamp. Date is somewhat used in the server's local time zone, instead of using UTC, which is not the best decision by SAP.
Will check your changes to see if that covers the different scenarios, we need to check how that works across time zones. The best way to solve this might be maybe creating a new Scapy field that abstracts the implementation.
Actually I have several testcases on different timezone (India, Asia, US) where the first Int is always 0x01.
datetime.fromtimestamp
is properly printing time in my local timezone.
I would bet for the timezone of Walldorf, DE (UTC+1) being hardcoded :-))