pyVoIP icon indicating copy to clipboard operation
pyVoIP copied to clipboard

Still have FritzBox authentication error on 1.6.2

Open mattiarainieri opened this issue 2 years ago • 24 comments

Hi, I've updated the library to the last 1.6.2 version but I still have problems authenticating to my fritz box.

Schermata 2022-10-18 alle 16 25 38 Schermata 2022-10-18 alle 16 26 09

mattiarainieri avatar Oct 18 '22 14:10 mattiarainieri

i have the same error:

  1. pyVoIP:
REGISTER sip:192.168.11.7 SIP/2.0
Via: SIP/2.0/UDP 192.168.11.88:5060;branch=z9hG4bK088986c7b2844e5797488dd0f;rport
From: "101" <sip:[email protected]>;tag=13639361
To: "101" <sip:[email protected]>
Call-ID: [email protected]:5060
CSeq: 1 REGISTER
Contact: <sip:[email protected]:5060;transport=UDP>;+sip.instance="<urn:uuid:533EA043-3D65-47B8-A23B-D4345D7B3071>"
Allow: INVITE, ACK, BYE, CANCEL
Max-Forwards: 70
Allow-Events: org.3gpp.nwinitdereg
User-Agent: pyVoIP 1.6.2
Expires: 120
Content-Length: 0
  1. Asterisk:
SIP/2.0 401 Unauthorized
Via: SIP/2.0/UDP 192.168.11.88:5060;branch=z9hG4bK088986c7b2844e5797488dd0f;received=192.168.11.88;rport=5060
From: "101" <sip:[email protected]>;tag=13639361
To: "101" <sip:[email protected]>;tag=as7f240d2c
Call-ID: [email protected]:5060
CSeq: 1 REGISTER
Server: FPBX-13.0.74(11.21.0)
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, MESSAGE
Supported: replaces, timer
WWW-Authenticate: Digest algorithm=**MD5**, **realm**="asterisk", **nonce**="0c943d28"
Content-Length: 0
  1. pyVoIP:
REGISTER sip:192.168.11.7 SIP/2.0
Via: SIP/2.0/UDP 192.168.11.88:5060;branch=z9hG4bKd95ce81ab1e54bcaa1150c8b3;rport
From: "101" <sip:[email protected]>;tag=13639361
To: "101" <sip:[email protected]>
Call-ID: [email protected]:5060
CSeq: 2 REGISTER
Contact: <sip:[email protected]:5060;transport=UDP>;+sip.instance="<urn:uuid:533EA043-3D65-47B8-A23B-D4345D7B3071>"
Allow: INVITE, ACK, BYE, CANCEL
Max-Forwards: 70
Allow-Events: org.3gpp.nwinitdereg
User-Agent: pyVoIP 1.6.2
Expires: 120
Authorization: Digest **username**="101",**realm**="asterisk",**nonce**="0c943d28",uri="sip:192.168.11.7;transport=UDP",**response**="8c8fff877ffa698a19bada31ed1fa46d",algorithm=MD5
Content-Length: 0

(password = "123123")

  1. Asterisk:
SIP/2.0 401 **Unauthorized**
Via: SIP/2.0/UDP 192.168.11.88:5060;branch=z9hG4bKd95ce81ab1e54bcaa1150c8b3;received=192.168.11.88;rport=5060
From: "101" <sip:[email protected]>;tag=13639361
To: "101" <sip:[email protected]>;tag=as55b5d463
Call-ID: [email protected]:5060
CSeq: 2 REGISTER
Server: FPBX-13.0.74(11.21.0)
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, MESSAGE
Supported: replaces, timer
WWW-Authenticate: Digest algorithm=MD5, realm="asterisk", nonce="3bb11a60"
Content-Length: 0
  1. pyVoIP: Invalid Username or Password for SIP server 192.168.11.7:5060

how to check the response?

AndreySozonov avatar Oct 18 '22 16:10 AndreySozonov

I did all the hashing myself and it all checks out so I'm not sure what the issue is here @AndreySozonov There seems to have been some semi recent RFCs updating the WWW-Authenticate scheme but they recommend not using algorithm=MD5 and the use of additional parameters, so it does not seem to be using it. Did a previous version of pyVoIP work for you?

Also you can use the following code for easier debugging on registry, but you may need to install from source instead of PyPI.

import pyVoIP
pyVoIP.DEBUG = True

Also, please be sure to use code blocks with posting code with Ctrl+e.

tayler6000 avatar Oct 19 '22 00:10 tayler6000

I've gotten to the point where I have downloaded the source code to Asterisk 11 to see where the error is happening. However my C is rusty, if anyone can figure out why some people are getting an error while other's are not, I would be greatly appreciative.

tayler6000 avatar Oct 19 '22 02:10 tayler6000

I've also reinstalled it from the source and enabled debugging. This is the message

SENT
REGISTER sip:fritz.box SIP/2.0
Via: SIP/2.0/UDP 0.0.0.0:5060;branch=z9hG4bK138a8aa6cabd4b8c92c2b325d;rport
From: "alarmnegozio" <sip:[email protected]>;tag=2a7547e5
To: "alarmnegozio" <sip:[email protected]>
Call-ID: [email protected]:5060
CSeq: 1 REGISTER
Contact: <sip:[email protected]:5060;transport=UDP>;+sip.instance="<urn:uuid:DA030FE3-24AE-4ADE-86DD-AC5FD0A37397>"
Allow: INVITE, ACK, BYE, CANCEL
Max-Forwards: 70
Allow-Events: org.3gpp.nwinitdereg
User-Agent: pyVoIP 1.6.2
Expires: 120
Content-Length: 0

RECEIVED
Status: 401 Unauthorized
Headers:
Via: [{'type': 'SIP/2.0/UDP', 'address': ('0.0.0.0', '5060'), 'branch': 'z9hG4bK138a8aa6cabd4b8c92c2b325d', 'rport': '5060', 'received': '192.168.1.200'}]
From: {'raw': '"alarmnegozio" <sip:[email protected]>', 'tag': '2a7547e5', 'address': '[email protected]', 'number': 'alarmnegozio', 'caller': 'alarmnegozio" ', 'host': 'fritz.box'}
To: {'raw': '"alarmnegozio" <sip:[email protected]>', 'tag': '6DC5C2CCC210248B', 'address': '[email protected]', 'number': 'alarmnegozio', 'caller': 'alarmnegozio" ', 'host': 'fritz.box'}
Call-ID: [email protected]:5060
CSeq: {'check': '1', 'method': 'REGISTER'}
WWW-Authenticate: {'realm': 'fritz.box', 'nonce': '0648C4E9C7FDC385'}
User-Agent: FRITZ!OS
Content-Length: 0


Body:
Raw:
b'SIP/2.0 401 Unauthorized\r\nVia: SIP/2.0/UDP 0.0.0.0:5060;branch=z9hG4bK138a8aa6cabd4b8c92c2b325d;rport=5060;received=192.168.1.200\r\nFrom: "alarmnegozio" <sip:[email protected]>;tag=2a7547e5\r\nTo: "alarmnegozio" <sip:[email protected]>;tag=6DC5C2CCC210248B\r\nCall-ID: [email protected]:5060\r\nCSeq: 1 REGISTER\r\nWWW-Authenticate: Digest realm="fritz.box", nonce="0648C4E9C7FDC385"\r\nUser-Agent: FRITZ!OS\r\nContent-Length: 0\r\n\r\n'

RECEIVED
Status: 401 Unauthorized
Headers:
Via: [{'type': 'SIP/2.0/UDP', 'address': ('0.0.0.0', '5060'), 'branch': 'z9hG4bK658a06ae91aa4db3a3b094cc7', 'rport': '5060', 'received': '192.168.1.200'}]
From: {'raw': '"alarmnegozio" <sip:[email protected]>', 'tag': '2a7547e5', 'address': '[email protected]', 'number': 'alarmnegozio', 'caller': 'alarmnegozio" ', 'host': 'fritz.box'}
To: {'raw': '"alarmnegozio" <sip:[email protected]>', 'tag': '68CE7BCC0655CAE8', 'address': '[email protected]', 'number': 'alarmnegozio', 'caller': 'alarmnegozio" ', 'host': 'fritz.box'}
Call-ID: [email protected]:5060
CSeq: {'check': '2', 'method': 'REGISTER'}
WWW-Authenticate: {'realm': 'fritz.box', 'nonce': 'AB140D882868700D'}
User-Agent: FRITZ!OS
Content-Length: 0

mattiarainieri avatar Oct 19 '22 09:10 mattiarainieri

@mattiarainieri @AndreySozonov What is the username associated with these numbers?

tayler6000 avatar Oct 19 '22 17:10 tayler6000

I don't see any instance of this check in Asterisk 11 that I found, however it may be worth noting that this is said in RFC 3261 Section 8.1.1.4

Note that when requests are retried after certain failure responses that solicit an amendment to a request (for example, a challenge for authentication), these retried requests are not considered new requests, and therefore do not need new Call-ID header fields; see Section 8.1.3.5.

This doesn't use any keywords from BCP 14 but that doesn't mean that an engineer hasn't relied on this behavior for routing messages, and we do not currently do this. Will be implementing this in 2.0.

tayler6000 avatar Oct 19 '22 23:10 tayler6000

@tayler6000 the voip username is “alarmnegozio”

mattiarainieri avatar Oct 20 '22 05:10 mattiarainieri

User "101". The registration error occurred when connecting to different versions of Asterisk (I tested 11 and 13). MicroSip softphone with the same credentials connected without problems. Perhaps the reason is related to the OS used: me and @mattiarainieri used Asterisk on Raspberry Pi. Tomorrow i will test pyVoIP on another server with an asterisk.

AndreySozonov avatar Oct 20 '22 19:10 AndreySozonov

Hello again. I'm wondering what's going wrong there. Since I'm not that good at reading foreign code but much better in implementing my own I experimented with a simple protocol class structure for SIP and there, authentication against my fritz.box works fine. What's missing here now is RTP protocol so my experiments are pretty useless so far. I don't really want to build a concurrent library so I don't think that I'll complete that thing.. unless someone tells me how to send and receive audio data via rtp..

Maybe my source helps you to figure out what's wrong with yours: https://github.com/TecDroiD/simple_voip

Edit: didn't clean up my files.. this one should be the interesting part: https://github.com/TecDroiD/simple_voip/blob/master/voip/sipmessage.py

TecDroiD avatar Oct 21 '22 15:10 TecDroiD

@TecDroiD Thank you, this will help a lot

tayler6000 avatar Oct 21 '22 20:10 tayler6000

@TecDroiD Our authentication systems are the same so I'm still unsure what the issue is. Could you maybe upload a packet capture of each system trying to authenticate?

tayler6000 avatar Oct 25 '22 19:10 tayler6000

well.. there seems to be some more binary data in your capture pyvoip.txt simple_voip.txt

TecDroiD avatar Oct 26 '22 09:10 TecDroiD

well.. there seems to be some more binary data in your capture

pyvoip.txt

simple_voip.txt

Can you merge my PR and then get me the simple_voip again? Your code has some significantly malformed headers and I'm genuinely concerned you stumbled across a vulnerability in fritz.box.

tayler6000 avatar Oct 26 '22 11:10 tayler6000

simple_voip.txt here it is. I end up unauthorized now

TecDroiD avatar Oct 26 '22 11:10 TecDroiD

simple_voip.txt

here it is. I end up unauthorized now

Ok, I don't have access to a Fritz box to test, but I have a feeling if you delete the comma before the response it'll work on your box because it'll fail to read it and assume it's right. If deleting that comma makes it work I highly recommend you contact fritz box and tell them they have a vulnerability in their code.

tayler6000 avatar Oct 26 '22 11:10 tayler6000

Honestly, they'll probably give you a bounty for it.

tayler6000 avatar Oct 26 '22 11:10 tayler6000

We'll see.. still, I cannot make any call yet

TecDroiD avatar Oct 26 '22 11:10 TecDroiD

Just found something else: in my sipmessage.py, line 160 you changed t3cDr01d to z9hG4bKt3cDr01d. When I roll this back, I can make a call.. Also when I remove only one character from your id text. currently looking for that entry in your code but maybe the entry is too long for fritzbox?

TecDroiD avatar Oct 26 '22 11:10 TecDroiD

Hmm, weird. It's a RFC requirement to have that prefix for the branch. I'm pretty sure I referenced it in the commit but if you just search for magic cookie in the RFC you'll find it.

tayler6000 avatar Oct 26 '22 12:10 tayler6000


def gen_branch(self, length=32) -> str:
        """
        Generate unique branch id according to
        https://datatracker.ietf.org/doc/html/rfc3261#section-8.1.1.7
        """
        branchid = uuid.uuid4().hex[: length - 7]
        return f"z9hG4bK{branchid}"

tayler6000 avatar Oct 26 '22 12:10 tayler6000

as far as i understood, that magic cookie identifies the newer version of SIP RFC. Maybe it enables some extra checks on fritzos? I already found out that there are some optional entries (think it was Contact) which are required by fritzbox.. What if there's just something stupid missing, just because its optional?

TecDroiD avatar Oct 26 '22 12:10 TecDroiD

I think you're right about the extra checks. The RFC says the branch should be globally unique if following the new standard. So maybe the second register needs to use a different branch not the same one from the original request?

tayler6000 avatar Oct 26 '22 12:10 tayler6000

@xyc0815 Welcome back, please, do you have any thoughts on this?

tayler6000 avatar Nov 03 '22 21:11 tayler6000

When I use web SIP services I had problems with username in contact in the first request (def gen_first_response(self, deregister=False))

        regRequest += (
            "Contact: "
            + f"<sip:{self.username}@{self.bind_ip}:{self.bind_port};"
            + "transport=UDP>;+sip.instance="
            + f'"<urn:uuid:{self.urnUUID}>"\r\n'
        )

So I don't use the username in this function. Because I've can also use a SIP proxy in between, I've other functions to get the right IP and port.

        regRequest += 'Contact: ' + \
                      f'<sip:{self.get_my_ip()}:{self.get_my_port()};' + \
                      'transport=UDP>;+sip.instance=' + \
                      f'"<urn:uuid:{self.urnUUID}>"\r\n'

With the second register call I've also send the username in the contact element. Maybe we have here the same problem.

xyc0815 avatar Nov 03 '22 22:11 xyc0815

I also wasn't able to register or make a call with FritzBox. I debugged this a lot and compared packet captures with those from MicroSIP client. I modified pyVoip until I could make it work. Eventually, it was all about the Call-ID field and the branch.

For REGISTER with authorization there are two requests. The Call-ID needs to be the same for first request without and for the second request with authorization.

For INVITE I figured, the Call-ID should also remain the same troughout the whole transaction (first and second request) however the branch needs to be different when doing authentication with the second INVITE request. The current implementation keeps the same branch for both.

philipp-fischer avatar Dec 10 '22 20:12 philipp-fischer

Hi @philipp-fischer , could you please share your changes? I'm trying to authenticate pyvoip to my fritz box just to receive the signalling for detecting calls from a dect doorbell. The fritz internal call monitor does not log or signal internal calls, but I would like to log them and maybe add smart home actions such as "doorbell rings --> turn on light if it's dark"

hartwigt avatar Jan 11 '23 11:01 hartwigt

Hi @philipp-fischer , could you please share your changes? I'm trying to authenticate pyvoip to my fritz box just to receive the signalling for detecting calls from a dect doorbell. The fritz internal call monitor does not log or signal internal calls, but I would like to log them and maybe add smart home actions such as "doorbell rings --> turn on light if it's dark"

In the end I resorted to an entirely new mini-implementation I created. I can share that when I return from vacation.

philipp-fischer avatar Jan 13 '23 06:01 philipp-fischer

Hello,

As far as I understand, the connection runs via UDP. In the following project, the connection runs via TCP by default: https://github.com/astoeckel/femtosip For me it works perfectly on the Fritz!Box 7490 with TCP. With UDP it gives me an authentication error. I am called anyway, but with an error message. That might solve the problem. An optional choice for UDP or TCP would be desirable.

Good luck

EDIT: I am called NOT if I use UDP with femtosip. Only TCP

nicofpunkt avatar Jan 13 '23 19:01 nicofpunkt

@hartwigt: Here is the code I created for the purpose of making a call: https://gist.github.com/philipp-fischer/d7fa8df8541955863aebcf24291af007 It also contains a stub to register with the server to receive calls, but I never tested this. Maybe this femtosip that @epicbananana posted above is worth a try?

philipp-fischer avatar Jan 14 '23 19:01 philipp-fischer

I will test it

nicofpunkt avatar Jan 14 '23 20:01 nicofpunkt