SkillAgentSearch skills...

Diafuzzer

Diameter interfaces fuzzer. Its fuzzing process is based on concrete network traces, and it uses 3gpp and ETSI specifications to fuzz efficiently.

Install / Use

/learn @Orange-OpenSource/Diafuzzer
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<a href="https://scan.coverity.com/projects/11469"> <img alt="Coverity Scan Build Status" src="https://scan.coverity.com/projects/11469/badge.svg"/> </a>

diafuzzer

Diameter fuzzer, based on specifications of Diameter applications following rfc 3588 / 6733

Overview

Diafuzzer is composed of several different tools:

  • simple and accurate Diameter callflows, based on pcap traces
  • script language to perform additional functions such as logging, database lookup or others
  • detailed description of Diameter applications defined at 3GPP and ETSI
  • runtime helpers to perform unit testing and fuzz testing

It is developped in Python, with four major components:

  • Diameter.py: contains Python classes named Msg and Avp which mirror wire. Both classes implement default values for unspecified fields, and compute fields which value depends on other fields.
  • Dia.py: parses dia files. It contains Python classes to model message structure and avp cardinality, plus their datatype.
  • pcap2scn.py and pcap2pdu.py: shall be given a pcap file as first argument. They will both produce a Python form of Diameter PDUs contained in trace, based on Diameter.py module above. pcap2scn.py will produce a client and/or server scenario, made of interleaved send and receive operations, whereas pcap2pdu.py will only dump PDUs as objects.
  • unit.py and fuzz.py: shall be given four arguments, amongst which a scenario, and a role. unit.py will replay the given scenario, and fuzz.py will use scenario as a baseline to produce fuzzing operations.

It is not compatible with Python3.

Diameter.py

Avp usage

Make sure to import Avp class from Diameter module

>>> from Diameter import Avp

To create an Avp instance:

>>> a = Avp()
>>> a
Avp(code=0,vendor=0)

The following parameters can be given when building a new instance:

Parameter | Default value when not specified | Meaning --------- | ------------------- | ----- code | 0 | AVP code V | False | AVP Vendor bit M | False | AVP Mandatory bit P | False | AVP Protected bit reserved | None | reserved bits (5 bits) vendor | 0 | vendor id (32 bits) avps | [] | inner AVPs data | None | value length | None, will be computed during encoding | length (32 bits)

For example, to create an Origin-Host Avp instance:

>>> Avp(code=264, data='hss.openims.test')
Avp(code=264, vendor=0, data='hss.openims.test')

Several ways are provided to supply values instead of raw bytes:

>>> Avp(code=266, u32=323)
Avp(code=266, vendor=0, data='\x00\x00\x01C')

The table below gives parameter names that can be used, and their format:

Parameter | Format | Argument type --------- | ------ | ------------- u32 | !L | Integer s32 | !I | Integer u64 | !Q | Integer f32 | !f | Float f64 | !d | Float v4 | NA | Dotted IPv4 address as a string, such as '0.0.0.0' v6 | NA | Colon separated IPv6 as a string, such as '::1'

To create a wire-ready version of the instance:

>>> Avp(code=266, u32=323).encode()
'\x00\x00\x01\n\x00\x00\x00\x0c\x00\x00\x01C'

To create an instance from raw bytes:

>>> Avp.decode('\x00\x00\x01\n\x00\x00\x00\x0c\x00\x00\x01C')
Avp(code=266, vendor=0, data='\x00\x00\x01C')

Msg usage

Make sure to import Msg and Avp classes from Diameter module

>>> from Diameter import Msg, Avp

To create a Msg instance:

>>> m = Msg()
>>> m
Msg(code=0, app_id=0x0, avps=[
])

Parameter | Default value when not specified | Meaning --------- | ------------------- | ------- version | 1 | version (8 bits) length | None, will be computed during encoding | length (32 bits) R | False | Request bit P | False | Proxyable bit E | False | Error bit T | False | reTransmitted bit reserved | None, will be set to zeros | reserved bits (4 bits) code | 0 | code (32 bits) app_id | 0 | application ID (32 bits) e2e_id | None, will be randomly generated during encoding | end-to-end ID (32 bits) h2h_id | None, will be randomly generated during encoding | hop-by-hop ID (32 bits) avps | [] | inner AVPs

For example, to create a Device-Watchdog Request Msg instance:

>>> m = Msg(code=280, R=True)
>>> m
Msg(R=True, code=280, app_id=0x0, avps=[
])

In order to create a real-world Capabilities-Exchange Request Msg instance:

>>> m = Msg(R=True, code=257, app_id=0x0, avps=[
...   Avp(code=264, M=True, vendor=0, data='127.0.0.1'),
...   Avp(code=296, M=True, vendor=0, data='org.domain.com'),
...   Avp(code=257, M=True, vendor=0, data='\x00\x01\x7f\x00\x00\x01'),
...   Avp(code=266, M=True, vendor=0, data='\x00\x00\x00\x00'),
...   Avp(code=269, M=True, vendor=0, data='Mu Service Analyzer Diameter Implementation'),
...   Avp(code=299, M=True, vendor=0, data='\x00\x00\x00\x00'),
...   Avp(code=260, M=True, vendor=0, avps=[
...     Avp(code=266, M=True, vendor=0, data='\x00\x00(\xaf'),
...     Avp(code=258, M=True, vendor=0, data='\x01\x00\x00\x00'),
...   ]),
... ])
>>> m
Msg(R=True, code=257, app_id=0x0, avps=[
  Avp(code=264, M=True, vendor=0, data='127.0.0.1'),
  Avp(code=296, M=True, vendor=0, data='org.domain.com'),
  Avp(code=257, M=True, vendor=0, data='\x00\x01\x7f\x00\x00\x01'),
  Avp(code=266, M=True, vendor=0, data='\x00\x00\x00\x00'),
  Avp(code=269, M=True, vendor=0, data='Mu Service Analyzer Diameter Implementation'),
  Avp(code=299, M=True, vendor=0, data='\x00\x00\x00\x00'),
  Avp(code=260, M=True, vendor=0, avps=[
    Avp(code=266, M=True, vendor=0, data='\x00\x00(\xaf'),
    Avp(code=258, M=True, vendor=0, data='\x01\x00\x00\x00'),
  ]),
])

Encoding and decoding to/from raw bytes work the same as for Avp:

>>> m = Msg.decode('\x01\x00\x00\xbc\x80\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x08@\x00\x00\x11127.0.0.1\x00\x00\x00\x00\x00\x01(@\x00\x00\x16org.domain.com\x00\x00\x00\x00\x01\x01@\x00\x00\x0e\x00\x01\x7f\x00\x00\x01\x00\x00\x00\x00\x01\n@\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x01\r@\x00\x003Mu Service Analyzer Diameter Implementation\x00\x00\x00\x01+@\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x01\x04@\x00\x00 \x00\x00\x01\n@\x00\x00\x0c\x00\x00(\xaf\x00\x00\x01\x02@\x00\x00\x0c\x01\x00\x00\x00')
>>> m
Msg(R=True, code=257, app_id=0x0, avps=[
  Avp(code=264, M=True, vendor=0, data='127.0.0.1'),
  Avp(code=296, M=True, vendor=0, data='org.domain.com'),
  Avp(code=257, M=True, vendor=0, data='\x00\x01\x7f\x00\x00\x01'),
  Avp(code=266, M=True, vendor=0, data='\x00\x00\x00\x00'),
  Avp(code=269, M=True, vendor=0, data='Mu Service Analyzer Diameter Implementation'),
  Avp(code=299, M=True, vendor=0, data='\x00\x00\x00\x00'),
  Avp(code=260, M=True, vendor=0, avps=[
    Avp(code=266, M=True, vendor=0, data='\x00\x00(\xaf'),
    Avp(code=258, M=True, vendor=0, data='\x01\x00\x00\x00'),
  ]),
])
>>> m.encode()
'\x01\x00\x00\xbc\x80\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x08@\x00\x00\x11127.0.0.1\x00\x00\x00\x00\x00\x01(@\x00\x00\x16org.domain.com\x00\x00\x00\x00\x01\x01@\x00\x00\x0e\x00\x01\x7f\x00\x00\x01\x00\x00\x00\x00\x01\n@\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x01\r@\x00\x003Mu Service Analyzer Diameter Implementation\x00\x00\x00\x01+@\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x01\x04@\x00\x00 \x00\x00\x01\n@\x00\x00\x0c\x00\x00(\xaf\x00\x00\x01\x02@\x00\x00\x0c\x01\x00\x00\x00'

Dia.py

Dia file format

The file format is based on a sequence of sections, each section beginning with

@<keyword> ...
...

Depending on the keyword, arguments may follow, and content of section may not be empty.

The example below defines one of the S13 application message:

@id     16777252
@name   S13

@inherits       ietf-avps
@inherits       3gpp-avps

@messages
ME-Identity-Check-Request ::= <Diameter Header: 324, REQ, PXY, 16777252>
      < Session-Id >
      [ Vendor-Specific-Application-Id ]
      { Auth-Session-State }
      { Origin-Host }
      { Origin-Realm }
      [ Destination-Host ]
      { Destination-Realm }
      { Terminal-Information }
      [ User-Name ]
  *   [ AVP ]
  *   [ Proxy-Info ]
  *   [ Route-Record ]

Application are defined using an id and a name:

@id     16777252
@name   S13

Most applications will use AVPs inherited from both IETF and 3GPP:

@inherits       ietf-avps
@inherits       3gpp-avps

Messages are defined using their Command Code format:

@messages
ME-Identity-Check-Request ::= <Diameter Header: 324, REQ, PXY, 16777252>
      < Session-Id >
      [ Vendor-Specific-Application-Id ]
      { Auth-Session-State }
      { Origin-Host }
      { Origin-Realm }
      [ Destination-Host ]
      { Destination-Realm }
      { Terminal-Information }
      [ User-Name ]
  *   [ AVP ]
  *   [ Proxy-Info ]
  *   [ Route-Record ]

AVPs are defined by their code, datatype and flags:

@avp_types
User-Name                                       1               UTF8String              M
User-Password                                   2               OctetString             M
NAS-IP-Address                                  4               OctetString             M
NAS-Port                                        5               Unsigned32              M

For AVP of type Grouped, the corresponding Command Code format must be defined in a grouped section:

@grouped
Vendor-Specific-Application-Id ::= <AVP Header: 260>
      { Vendor-Id }
      [ Auth-Application-Id ]
      [ Acct-Application-Id ]

Failed-AVP ::= <AVP Header: 279>
 1*   { AVP }

For AVP of type Enumerated, the corresponding values must defined in an enum section, with AVP name in argument:

@enum Timezone-Flag
UTC                                             0
LOCAL                                           1
OFFSET                                          2

@enum QoS-Semantics
QOS_DESIRED                      
View on GitHub
GitHub Stars57
CategoryProduct
Updated3mo ago
Forks22

Languages

Python

Security Score

92/100

Audited on Dec 24, 2025

No findings