Daily Archives: February 7, 2013

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=”sip:sip.example.com”, response=”3bc3cedaa7ee0f0b9bec12c50c8827cb”,algorithm=MD5

The client has calculated the “repsonse” like this:

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

HA2 = MD5(“REGISTER:sip:sip.example.com”)

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 sip:sip.example.com 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 224.0.1.75 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 224.0.1.75:5060
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.