Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Time format broken in SAPRouterInfoClient #12

Closed
gelim opened this issue Feb 19, 2017 · 3 comments
Closed

Time format broken in SAPRouterInfoClient #12

gelim opened this issue Feb 19, 2017 · 3 comments
Labels

Comments

@gelim
Copy link
Contributor

gelim commented Feb 19, 2017

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

@gelim
Copy link
Contributor Author

gelim commented Feb 20, 2017

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

@martingalloar
Copy link
Collaborator

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.

@gelim
Copy link
Contributor Author

gelim commented Feb 20, 2017

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 :-))

martingalloar added a commit that referenced this issue Feb 20, 2017
Improved client list printing. If tabulate is available use it (in the same way that BaseConsole). Pointed out by @gelim in #12, thanks!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants