P1sec / pycrate

A Python library to ease the development of encoders and decoders for various protocols and file formats; contains ASN.1 and CSN.1 compilers.
GNU Lesser General Public License v2.1
382 stars 132 forks source link

SCCP module does not support the ANSI / T1.112 address layout #236

Open davidlag-telus opened 1 year ago

davidlag-telus commented 1 year ago

Hi,

I am trying to extract the SSN's from the SCCP layer. So far, I tried these (just for CallingPartyAddr, same for CalledPartyAddr anyways):

sccp_message["CallingPartyAddr"].show()

### CallingPartyAddr ###
 <Len : 9>
 ### Value ###
  ### AddrInd ###
   <res : 1>
   <RoutingInd : 0 (route on GT)>
   <GTInd : 2 (global title includes translation type only)>
   <SSNInd : 0>
   <PCInd : 1>
  <PC : <redacted>>
  ### GT : 2 -> GT_2 ###
   <TranslationType : 97>
   <Addr : <redacted>>

The SSNInd value above is incorrect because the SSN is really present.

sccp_message["CallingPartyAddr"]["Value"].show()

### Value ###
 ### AddrInd ###
  <res : 1>
  <RoutingInd : 0 (route on GT)>
  <GTInd : 2 (global title includes translation type only)>
  <SSNInd : 0>
  <PCInd : 1>
 <PC : <redacted>>
 ### GT : 2 -> GT_2 ###
  <TranslationType : 97>
  <Addr : <redacted>>

Same comment as above regarding the SSNInd value.

sccp_message["CallingPartyAddr"]["SSN"].show()

<SSN [transparent] : 0 (SSN not known/not used)>

The SSN value is either not shown or is set to 0. I don't know if the SCCP flavor we use (ANSI) makes a difference here. I had to patch the ANSI version of MTP3 to get the point codes. Maybe I have to do the same here?

Thank you!

davidlag-telus commented 1 year ago

I wanted to chime in with my findings to avoid lost time. I checked T1.112 (ANSI) and Q.713 (ITU-T) and ANSI has the "SSN Indicator" and "Point Code Indicator" reversed as compared to the ITU-T standard. I will start by a simple patch to reverse these fields and will comment back here. If I need to make other changes, I will mention them here as well.

davidlag-telus commented 1 year ago

Alright, the patching approach worked. I went up the chain of function calls and changed the items I needed to change in SCCP.SCCPTypeClasses to point to patched classes that have locally defined functions named CalledPartyAddr and CallingPartyAddr. I had to keep them the same name because there is code looking specifically for functions named like these elsewhere in pycrate. These 2 classes are inherited from my patched SCCPPartyAddr class which is inherited from the original pycrate class of the same name.

This last patched class was modified to call my modified _SCCPAddr class - this was only done because these classes were part of the code chain up to the last class where I needed my changes for SSN's. Finally, I have modified the original _SCCPAddr class to reverse the order of these lines in the code:

                Uint("PCInd", val=0, bl=1),
                Uint("SSNInd", val=0, bl=1),

and

        Uint8("SSN", val=0, dic=SCCP._SSN_dict),  # presence depends on SSNInd
        Uint16LE("PC"),  # presence depends on PCInd

It is a bit of hacking but it works well! I haven't looked at other differences between T1.112 and Q.713 flavors of SCCP because I was only after getting the calling and called SSN's.

Hopefully this can be useful for others!

p1-bmu commented 1 year ago

Thanks for the analysis. I may look in the future to split this SCCP module into ITUT and ANSSI variants. So let's keep this issue open for this purpose.

p1-bmu commented 1 year ago

May I had @davidlag-telus, that if you can share (privately if needed) a tiny ANSSI SCCP pcap, this would help a lot.