PyHSS 1.0.2.
A request that is well-formed at the Diameter layer but carries an unexpected AVP value (or omits an expected AVP) makes the handler throw before it builds the answer, so the transaction just times out on the peer. A few I hit while sending malformed Cx/S6a requests:
User-Name that isn't a SIP URI — MAR (Answer_16777216_303) does username.split('@')[1]:
File "/pyhss/lib/diameter.py", line 2569, in Answer_16777216_303
domain = username.split('@')[1]
IndexError: list index out of range
Missing Session-Id — UAR (Answer_16777216_300) indexes an empty list:
File "/pyhss/lib/diameter.py", line 822, in generateDiameterResponse
File "/pyhss/lib/diameter.py", line 2316, in Answer_16777216_300
session_id = self.get_avp_data(avps, 263)[0]
IndexError: list index out of range
User-Name that isn't hex / isn't UTF-8 — same handler, later:
username = binascii.unhexlify(username).decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfe in position 0: invalid start byte
Same shape shows up in the S6a handlers too (AIR/PUR do the same unhexlify(...).decode() on User-Name, ULR/AIR index get_avp_data(...)[0]), and passing a grouped AVP where a scalar is expected hits binascii.unhexlify() with a list → TypeError.
Root cause is the handlers assume the AVP is present and well-formed. get_avp_data(avps, N)[0] throws IndexError when the AVP is absent, and binascii.unhexlify(x).decode('utf-8') throws when x isn't hex / isn't UTF-8. Would it make sense to validate these centrally — return DIAMETER_MISSING_AVP / DIAMETER_INVALID_AVP_VALUE instead of letting the exception kill the response? Happy to send a PoC packet for any of these.
Line numbers below are against current master.
The MAR handler Answer_16777216_303 reads several AVPs at the top of the function with no guarding:
lib/diameter.py
3151 public_identity = self.get_avp_data(avps, 601)[0]
3152 public_identity = binascii.unhexlify(public_identity).decode('utf-8')
3154 username = self.get_avp_data(avps, 1)[0]
3155 username = binascii.unhexlify(username).decode('utf-8')
3156 imsi = username.split('@')[0]
3157 domain = username.split('@')[1]
3162 session_id = self.get_avp_data(avps, 263)[0]
A single malformed MAR reaches each of these:
- a missing
Public-Identity / User-Name / Session-Id makes get_avp_data(...)[0] index an empty list and raises IndexError
- a
User-Name that isn't hex or isn't UTF-8 raises binascii.Error / UnicodeDecodeError at 3152/3155
- a
User-Name without an @ raises IndexError at 3157
None of this is inside a try/except — the first try starts at 3169 around Get_Subscriber. The exception propagates out of the handler and no MAA is generated, so the transaction times out on the peer.
The same unguarded extraction is in the S6a handlers: AIR/PUR unhexlify(...).decode() the User-Name, ULR/AIR index get_avp_data(...)[0].
UAR (Answer_16777216_300) already wraps its User-Name handling in try/except (2915–2924), so it is not affected in the same way — MAR is the representative case here. (The UAR except branch has a separate defect, filed on its own.)
The fix is to check presence and wrap the decode before use, returning DIAMETER_MISSING_AVP / DIAMETER_INVALID_AVP_VALUE instead of letting the handler raise.
PyHSS 1.0.2.
A request that is well-formed at the Diameter layer but carries an unexpected AVP value (or omits an expected AVP) makes the handler throw before it builds the answer, so the transaction just times out on the peer. A few I hit while sending malformed Cx/S6a requests:
User-Namethat isn't a SIP URI — MAR (Answer_16777216_303) doesusername.split('@')[1]:Missing
Session-Id— UAR (Answer_16777216_300) indexes an empty list:User-Namethat isn't hex / isn't UTF-8 — same handler, later:Same shape shows up in the S6a handlers too (AIR/PUR do the same
unhexlify(...).decode()onUser-Name, ULR/AIR indexget_avp_data(...)[0]), and passing a grouped AVP where a scalar is expected hitsbinascii.unhexlify()with a list →TypeError.Root cause is the handlers assume the AVP is present and well-formed.
get_avp_data(avps, N)[0]throwsIndexErrorwhen the AVP is absent, andbinascii.unhexlify(x).decode('utf-8')throws whenxisn't hex / isn't UTF-8. Would it make sense to validate these centrally — returnDIAMETER_MISSING_AVP/DIAMETER_INVALID_AVP_VALUEinstead of letting the exception kill the response? Happy to send a PoC packet for any of these.Line numbers below are against current
master.The MAR handler
Answer_16777216_303reads several AVPs at the top of the function with no guarding:A single malformed MAR reaches each of these:
Public-Identity/User-Name/Session-Idmakesget_avp_data(...)[0]index an empty list and raisesIndexErrorUser-Namethat isn't hex or isn't UTF-8 raisesbinascii.Error/UnicodeDecodeErrorat 3152/3155User-Namewithout an@raisesIndexErrorat 3157None of this is inside a try/except — the first
trystarts at 3169 aroundGet_Subscriber. The exception propagates out of the handler and no MAA is generated, so the transaction times out on the peer.The same unguarded extraction is in the S6a handlers: AIR/PUR
unhexlify(...).decode()theUser-Name, ULR/AIR indexget_avp_data(...)[0].UAR (
Answer_16777216_300) already wraps itsUser-Namehandling in try/except (2915–2924), so it is not affected in the same way — MAR is the representative case here. (The UAR except branch has a separate defect, filed on its own.)The fix is to check presence and wrap the decode before use, returning
DIAMETER_MISSING_AVP/DIAMETER_INVALID_AVP_VALUEinstead of letting the handler raise.