Category Archives: All

Security implications of WebRTC (part 1): The STUN gun

WebRTC compatible browsers use STUN / ICE mechanisms to establish peer to peer connections between endpoints (where possible).

To determine if a direct connection is possible ICE connectivity checks are used. This functionality is encapsulated inside the RTCPeerConnection JavaScript API. A JavaScript application does not require any special permission or consent by the user to use the PeerConnection API (only access to the user’s microphone and camera require the user’s consent).

Receive-only PeerConnections (e.g. for receiving streaming video) use exactly the same STUN / ICE mechanisms as fullduplex connections.

Section 18.5.2 of RFC 5245 describes a STUN amplification attack which works by inserting ICE candidates with the victim’s IP address into a SDP offer or answer. Back in the days when this RFC was crafted the attack required the attacker to be in the signaling path to trick ICE agents into flooding the victim with ICE connectivity checks.

The beauty of WebRTC is that there is no defined signaling mechanism, meaning you need to build your own utilizing the PeerConnection JavaScript API. That means now the attacker only needs to be able to inject JavaScript code (e.g. through Cross-site scripting (XSS)) to flood arbitrary hosts with ICE connectivity checks. Appendix B1 of RFC 5235 defines a pacing mechanism limiting the bandwidth used for connectivity checks to the bandwith that the actual media flow would be using (which can be quite significant for video streams).

Tests with Google Chrome have shown that one PeerConnection usually generates around 20 to 25 kbit’s of ICE connectivity checks (no matter how many ICE candidates are provided). By “massaging” the session description passed to the PeerConnection in the SDP answer (e.g. by replacing the short generated ICE credentials with really really really long credentials) this bandwidth generator can be amplified by a factor of 10. After 10 seconds the ICE connectivity checks are stopped by Chrome (FireFox does this a lot earlier creating other problems for regular use cases).

Chrome has a limit of 10 active PeerConnections per browser tab. That means by creating 10 concurrent PeerConnections with long ICE credentials every 10 seconds a malicious script can generate a permanent stream with 2.0 to 2.5 mbit/s of UDP traffic out of thin air, which can be directed at any host (without being bound to any constraints like the usual same origin constraint). The throttling of ICE connectivity checks (in Chrome) is done on each PeerConnection separately which means that all 10 concurrent connections can direct their traffic to the same IP and port.

Fortunately Chrome does not allow ICE candidates with ports less than 1024, so you cannot point your STUN gun towards DNS servers. But there are still some interesting UDP based services running on higher ports (e.g. SIP, OpenVPN, …) and apart from targeting particular services the accumulated bandwidth of a few thousand clients can cause some problems (“plugin-free denial of service”). FireFox does not have any constraints regarding the port of ICE candidates.



By using even longer ICE credentials the amount of generated dos bandwith can be scaled, e.g. an ICE username of 5000 characters and an ICE password of 5000 characters result in around 10 mbit/s of UDP traffic. Shouldn’t there be a length limit for ICE credentials???

Reversing SIP digest authentication in JavaScript (node.js)

SIP digest authentication RFC 3261 is based on HTTP digest authentication RFC 2617.
The purpose of digest authentication is not having to exchange the password in plaintext.

When a client issues a request that needs to be authenticatd (e.g. a SIP REGISTER request) the server will respond with a “401 Unauthorized” response, which includes a “WWW-Authenticate” header, for example:

WWW-Authenticate: Digest algorithm=MD5, realm=”asterisk”, nonce=”40787c47″

The client will go through the digest authentication procedure and resend the request, including an “Authorization” header:

Authorization: Digest username=”myusername”, realm=”asterisk”, nonce=”40787c47″, uri=””, response=”3bc3cedaa7ee0f0b9bec12c50c8827cb”,algorithm=MD5

The client has calculated the “repsonse” like this:

HA1 = MD5(“myusername:asterisk:password”)

HA2 = MD5(“”)

response = MD5(HA1+”:40787c47:”+HA2);

On the server side exactly the same computation is performed and the result is compared to the “response” transmitted by the client. If both hashes are equal then the request has been authenticated.

If an attacker can get access to the “Authorization” header of the client request (e.g. by sniffing packets on the client or server LAN) then the password can be recovered by bruteforcing it. Transport layer security (TLS) can protect against packet sniffing. However there are mechanisms for getting access to the “Authorization” header without needing to sniff packets.

Bruteforcing the password is a pretty straightforward process. You generate a list of all possible passwords (depending on which characters you are expecting), run it through the digest authentication procedure and compare the hashes.

The HA2 part of the calculation is constant (it is a hash of the request type and the SIP URI) and can be precomputed. Trying each password involves two MD5 hash operations.

I made another simple node.js application to which you feed the parameters obtained from a sniffed “Authorization” header (username, realm, nonce, SIP URI, response hash) and the length of the password to be bruteforced, e.g.:

node sipdigest-bruteforce.js myuser asterisk 40787c47 ac4d7f3684ec6c176ced252917af449f 5

Depending on the length of the password you can now go and grab a coffee (or go on vacation):

Alphabet: “,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z”
Password length: 5
Number of permutations: 14348907
Precomputed HA2: 2c207d3d673349fe58bb06d3d5f7ae67
found password: keins
real    0m58.892s

It took less than a minute on my laptop to find my super secret password. Please note that i have replaced all values in this example with dummy values. That means if you try to run the above example you will not find the password.

On my 2 Ghz i7 CPU i get around 200k passwords / second (when utilizing just 1 CPU core). You can easily adapt the application to use multiple cores by splitting different regions of permutations over several threads.

The ability to parallelize the computation makes it very suitable to run it on a GPU (or several GPUs). Current of the shelf GPUs (even two or three years old) can achieve crazy performance for MD5 calculation, e.g. a AMD Radeon HD5790 can deliver up to 4 GHash/sec (MD5) which translates to 2 billion passwords per second.

A nice upgrade path exists as node.js has support for OpenCL (through WebGL).

You can download my node.js application here.

Resetting SNOM HTTP credentials for the lazy

Sometimes somebody locks your SNOM phone down to user mode and also sets credentials for the webinterface. You can revoke those changes either by using the HTTP provisioning mechanism or by flashing a recovery image via TFTP.

If you already have a working provisioning mechanism (e.g. by setting the option in your DHCP server) to unlock your phone then it wasn’t a problem in the first place.

Flashing a recovery image via TFTP is no fun either as you need physical access to the phone (for setting up a static ip address, etc) and also it deletes all settings (especially those you might be interested in…).

Fortunately SNOM phones have a plug and play mode which can be (ab)used by somebody on the local network. By default, a phone will send a SIP Subscribe message to the multicast ip address after each boot. A provisioning server can then send a SIP Notify message containg a HTTP URL for provisioning.

I made a small node.js application that listens for those SIP Subscribe messages and feeds them a XML configuration that resets the HTTP username and password to “admin” and also switches from user mode to admin mode.

Just start it with “node snomreset.js <yourIpAddress>” and have fun:

SIP listening
Received SUBSCRIBE from MAC 0004134001F4
Sending Ok
Sending NOTIFY with provisioning URL
Resetting HTTP user and password to “admin”, enabling admin mode.
Resetting HTTP user and password to “admin”, enabling admin mode.
Resetting HTTP user and password to “admin”, enabling admin mode.

You can download the snomreset.js application here.

Mass deployment of SIP phones

While implementing a mass deployment of SIP phones for a client, I took a closer look at how the process works and i found things on the public internet that you wouldn’t believe!

Scanning for SIP servers and bruteforcing accounts is very popular these days. But it is a lot more efficient when you can just ask for the SIP accounts without scanning (reverse mass deployment).

How does mass deployment work?

After booting (or in regular intervals) a device will contact a provisioning server (usually via HTTP, HTTPS or TFTP) to download a configuration file (usually XML or a proprietary format).

The URL of the provisioning server and configuration file is either learned by a DHCP option, a SIP Notify message or stored in the configuration of the device.

To identify individual devices the MAC address of the device is either part of the configuration file name or is passed as a parameter to a HTTP/HTTPS URL.

In most cases there is no authentication between the device and the provisioning server. The provisioning server will transmit the configuration data to anybody who is providing a valid MAC address (“valid” meaning “the address is known by the server”) .

What is a MAC address?

MAC (Media Access Control) addresses are unique identifiers assigned to network interfaces for communications on the the physical network segment.

Each MAC address consists of 6 octets. The 3 most significant octets are called the OUI (Organisationally Unique Identifier) and are identifying the manufacturer of the device.

The structuring of the remaining 3 octets are up to the device manufacturer.

What is a MAC address NOT?

A MAC address is a unique identifier. It is NOT an unguessable token suitable for authentication! Don’t confuse a sequence of 12 hexadecimal characters with something like a SHA1 hash. Just because it is hexadecimal doesn’t mean it is unguessable or secure.

There are only 16.7 million (2^24) addresses for one OUI (and the OUI is always known).

Some manufacturers use the most significant octet (of their 3 octets) to identify the device model, leaving only 2 octets for actual devices, reducing the number of MAC addresses for a known device model prefix to 65536.

If the list of device model prefixes is known then the attacker is able to select which type of device to bruteforce first (users of expensive business phones might have more interesting SIP accounts than users of cheaper phones).

How does reverse mass deployment work?

If an attacker knows the URL of the provisioning server, e.g. by having a device that is configured by his SIP provider (hosted PBX, etc), it is trivial to extract the configuration of all other devices by simply bruteforcing the MAC address which is part of the provisioning URL (given that there is no additional authentication apart from the MAC address).

Some provisioning systems generate the configuration on demand and are vulnerable to the usual SQL injection attacks. Usually it’s just a bit of PHP and MySQL.

Others generate static files and store them on a HTTP/HTTPS or TFTP server and allow access to the directory listing from the public internet!

What can be done to make mass deployment more secure?

The only secure way of provisioning requires mutual authentication between the device and the provisioning server, e.g. by storing individual client certificates on the device.
To implement this the device firmware needs to be modified, so it can only be implemented by the manufacturer. There is also a good chance that someone will get the SSL stuff wrong (once more).

Instead of the MAC address a UUID (Universally Unique IDentifier) should be used. It is a 16 octet number defined in RFC 4122, e.g. “550e8400-e29b-11d4-a716-446655440000”.

Ideally it would be generated and stored in non-volatile memory when the device is manufactured. Again this needs to be implemented by the manufacturer.

However something similar can be built without the help of the manufacturer if the provisioning server URL in the device can be configured (which is true in most cases). In a two step process a UUID will be generated and stored as part of the provisioning server URL:

First step (MAC-UUID pairing):

The regular MAC addressed based provisioning mechanism is used. The provisioning server will lookup the device in an “unconfigured devices” database table by its MAC address.

It generates a UUID which is inserted into a “configured_devices” database table, deletes the MAC address from the “unconfigured devices” table (or marks it as “paired”) and stores a new provisioning server URL (including the generated UUID) into the device. All configuration data is associated to the UUID (not the MAC).

Second step (UUID-based provisioning):

The device retrieves its configuration from the provisioning server by providing the UUID.

Please note that this solution does not protect against man-in-the-middle attacks.

Need help securing your mass deployment? Got feedback?

Please contact me at

Things I have learned from being hit by a SIP bruteforce attack…

The attac:k

This week it happened to me, too. Somebody (with an IP address from Belize) managed to bruteforce the password of a SIP account on one of our internal Asterisk servers. I noticed it purely by accident. Usually i never look at the CLI of that machine (except when things fail, which is pretty rare). Fortunately, luck is with the stupid, so i noticed it just two hours after the first calls were made.

Calls were made to a single number in the British Indian Ocean Territory. The same number seems to be used by a few malicious Android applications, too. I have learned that the username “droid” and password “android” are not secure enough for a SIP account. ;-)

Immediately i redirected all calls from that account to one of my SIP phones, which started ringing very soon. Unfortunately there was no one at the other end when i answered the call. The other side (which claimed to be an Asterisk) was only sending silence (in g.711 RTP). So, our BRI lines were not abused for call termination but probably for a premium number scam. I can’t wait to get the invoice next month. :-(

Things I have learned:

  • Do not use a dialplan pattern like “_X.” in your context for external calls. Set up an extension for every country you need to call, e.g. “_0049.”. I had this on all of our ITSP machines, but of course not on our internal box (“The shoemaker got the worst shoes.”).
  • Use good usernames and passwords. Try to avoid numeric usernames.
  • Protect you accounts from being bruteforced by using something like fail2ban.
  • When possible use a SIP domain instead of IP addresses. Make sure the domain cannot be guessed from the IP address!

The new setup:

Instead of setting up fail2ban on our Asterisk box, I decided to use kamailio in front of Asterisk. All authentication is done by kamailio and all calls are forwarded to Asterisk (even calls between local subscribers). The “antiflood” feature of kamailio keeps our fellow bruteforces outside.

The authentication between Asterisk and kamailio is done on a trusted IP basis. There are no SIP accounts on the Asterisk box. An very nice side effect is that you can now register the same SIP account on multiple SIP phones without any effort! Before I had to have one SIP account for each of my phones.

Kamailio’s multi-domain support is enabled. All automatic aliases have been removed. It is only listening to requests for the domains configured in the database. The SIP domain we use cannot be guessed from the IP address of the box. This feature alone would probably be sufficient to protect the accounts against bruteforcing!


I have just made some tests with the metasploit SIP options scanner and SIP enumerator. With kamailio’s multidomain support configured to a non-guessable domain it does not even respond to the SIP options message from the scanner. That way our fellow bruteforcers dont even recognize the kamailio server as a SIP server. And leave it alone. :-)