Before starting, I must say that this exposure has been wide open in FusionPBX since I have memory. It is not a vulnerability, but an exposure; other PBX brands may be affected then.
So, a few months ago, one of my customers told me that one of his carriers had billed an unusually large amount and that he was "hacked". Sadly, his poor communication skills didn't help, and all we did was change passwords. A few weeks ago, one of my job peers told me something similar, with more time and patience, the issue was that odd calls were terminated while the extension owner (we were able to trace back that) claimed she hadn't used that phone for months. Digging into FreeSWITCH logs, I could find the call logs, but I couldn't find any registration (no on FusionPBX, no in FreeSWITCH CLI).
Besides having a password leak, what happened?
The SIP Protocol and FreeSWITCH
FreeSWITCH uses SIP Profiles as endpoints for accepting or sending TCP/IP data over the network. Among the many parameters you can configure there, you can set whether authentication is required or not to allow the call flow.
If an SIP payload arrives (e.g., an INVITE) and authentication is required, but the Proxy-Authorization header is missing, the PBX will respond with a 407 Proxy Authentication Required error. The endpoint must send the same payload and include the Proxy-Authentication header. If the authentication information is correct, the PBX will respond with a 100, 200, or 300 error code; otherwise, it will return a 401.

If the INVITE includes the authentication header on the first try, this handshake won't occur, and the call flow will proceed.
The Registration
So what about registration? Isn't this the authentication step we all go through when configuring an extension? Sadly no. The first thing we must remember is that the SIP protocol is stateless. Yes, the S stands for SESSION, but it's a different kind of session. Each payload that requires authentication must have a valid authentication header.
Then, what's the main purpose of registering? Registration is how you tell the PBX where a specific endpoint is. When an endpoint registers, one of the most important pieces of information it provides to the PBX is its IP address and port. Think of the worst-case scenario: hundreds of endpoints behind a single public IP registering with the same PBX; the only way the PBX can reach endpoint A and not B is by knowing the port that the endpoint's router assigned (also known as a NAT pinhole).
Do you see the Problem?
It is not that obvious. Let's enumerate the facts:
- A registration is not required to make outbound calls.
- An INVITE payload with the correct authentication header is sufficient to allow the call to proceed.
What do you require to build the Auth Header?
To build the Authorization header, you need 3 things:
- the username,
- the password, and
- the realm (on multi-tenant PBXes is the tenant, otherwise it is the public IP of the PBX).
An authorization header looks like this:
Authorization: Digest username="105", realm="client1.inside-out.xyz", nonce="171e0a03-0f61-461a-990b-4aa1f6b42de2", uri="sip:client1.inside-out.xyz", response="df03c20af98ae8ad2264125da4cccfe9", algorithm=MD5, cnonce="12835927", qop=auth, nc=00000409
If I am not mistaken, there is an easy way to find the realm and extension number for the endpoint. Because most endpoints use UDP to connect, an attacker can perform a port scan on a random IP to find all the NAT pinholes, and by sending a valid SIP payload, the endpoint will respond, revealing two of the three data components you need. The attacker can use brute force or a dictionary attack to crack the password; there are public databases of the most common passwords, and without knowing the correct one, maybe one is the right one. To this point, the attacker hasn't touched the PBX at all, but an endpoint.
Unfortunately, most endpoints will respond to any valid SIP payload that reaches them. A few, like Grandstream, have a security option that prevents responding to SIP payloads from a source IP different from the registered endpoint (however, this option is off by default). Another way to mitigate this vulnerability is to use TCP or TLS instead of UDP, being aware of the tradeoff.
Once an attacker has a confirmed username, password, and realm from a given endpoint, the only thing missing is the destination IP. In most cases, the realm is a valid FQDN.
The Solution
After understanding what is happening, the solution is to add a capability to the PBX that forbids any INVITE, regardless of whether the auth header is valid, unless the source IP matches the IP reported by the same registered extension.
My LUA script can be found on GitHub. The script is basic, and I believe there is a lot of opportunity to enhance it. So far, this is the behaviour:
- If the auth header is missing, the call flow is allowed.
- If the auth header is present, and the source IP of the INVITE matches the IP reported by that registered extension, the call flow is allowed.
- In any other case, the call is forbidden with a 603 error code.
Why is this a Good Solution?
This script adds a fourth element in order to allow an endpoint to route a call. Meaning that, regardless of whether the password crack is successful, it now needs to be routed from the source IP of the endpoint.
Good luck!

