Reverse MD5 on SIP Auth

MD5 isn’t a particularly well regarded hashing function these days, but it’s still pretty ubiquitous.

SIP authentication, for the most part, still uses MD5 in the form of Message Digest Authentication,

If we were to take the password password and hash it using an online tool to generate MD5 Hashes we’d get “5f4dcc3b5aa765d61d8327deb882cf99”


If we hash password again with MD5 we’d get the same output – “5f4dcc3b5aa765d61d8327deb882cf99”,


The catch with this is if you put “5f4dcc3b5aa765d61d8327deb882cf99” into a search engine, Google immediately tells you it’s plain text value. That’s because the MD5 of password is always 5f4dcc3b5aa765d61d8327deb882cf99, hashing the same input phase “password” always results in the same output MD5 hash aka “response”.

By using Message Digest Authentication we introduce a “nonce” value and mix it (“salt”) with the SIP realm, username, password and request URI, to ensure that the response is different every time.

Let’s look at this example REGISTER flow:

We can see a REGISTER message has been sent by Bob to the SIP Server.

REGISTER sips:ss2.biloxi.example.com SIP/2.0    
Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7
Max-Forwards: 70
From: Bob <sips:[email protected]>;tag=a73kszlfl
To: Bob <sips:[email protected]>
Call-ID: [email protected]
CSeq: 1 REGISTER
Contact: <sips:[email protected]>
Content-Length: 0

The SIP Server has sent back a 401 Unauthorised message, but includes the WWW-Authenticate header field, from this, we can grab a Realm value, and a Nonce, which we’ll use to generate our response that we’ll send back.

 SIP/2.0 401 Unauthorized    
Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashds7 ;received=192.0.2.201
From: Bob <sips:[email protected]>;tag=a73kszlfl
To: Bob <sips:[email protected]>;tag=1410948204
Call-ID: [email protected]
CSeq: 1 REGISTER
WWW-Authenticate: Digest realm="atlanta.example.com", qop="auth",nonce="ea9c8e88df84f1cec4341ae6cbe5a359", opaque="", stale=FALSE, algorithm=MD5
Content-Length: 0

The formula for generating the response looks rather complex but really isn’t that bad.

HA1=MD5(username:realm:password)
HA2=MD5(method:digestURI)
response=MD5(HA1:nonce:HA2)

Let’s say in this case Bob’s password is “bobspassword”, let’s generate a response back to the server.

We know the username which is bob, the realm which is atlanta.example.com, digest URI is sips:biloxi.example.com, method is REGISTER and the password which is bobspassword. This seems like a lot to go through but all of these values, with the exception of the password, we just get from the 401 headers above.

So let’s generate the first part called HA1 using the formula HA1=MD5(username:realm:password), so let’s substitute this with our real values:
HA1 = MD5(bob:atlanta.example.com:bobspassword)
So if we drop bob:atlanta.example.com:bobspassword into our MD5 hasher and we get our HA1 hash and it it looks like 2da91700e1ef4f38df91500c8729d35f, so HA1 = 2da91700e1ef4f38df91500c8729d35f

Now onto the second part, we know the Method is REGISTER, and our digestURI is sips:biloxi.example.com
HA2=MD5(method:digestURI)
HA2=MD5(REGISTER:sips:biloxi.example.com)
Again, drop REGISTER:sips:biloxi.example.com into our MD5 hasher, and grab the output – 8f2d44a2696b3b3ed781d2f44375b3df
This means HA2 = 8f2d44a2696b3b3ed781d2f44375b3df

Finally we join HA1, the nonce and HA2 in one string and hash it:
Response = MD5(2da91700e1ef4f38df91500c8729d35f:ea9c8e88df84f1cec4341ae6cbe5a359:8f2d44a2696b3b3ed781d2f44375b3df)

Which gives us our final response of “bc2f51f99c2add3e9dfce04d43df0c6a”, so let’s see what happens when Bob sends this to the SIP Server.

REGISTER sips:ss2.biloxi.example.com SIP/2.0 
Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashd92
Max-Forwards: 70
From: Bob <sips:[email protected]>;tag=ja743ks76zlflH
To: Bob <sips:[email protected]>
Call-ID: [email protected]
CSeq: 2 REGISTER
Contact: <sips:[email protected]>
Authorization: Digest username="bob", realm="atlanta.example.com", nonce="ea9c8e88df84f1cec4341ae6cbe5a359", opaque="", uri="sips:ss2.biloxi.example.com", response="bc2f51f99c2add3e9dfce04d43df0c6a"
Content-Length: 0
SIP/2.0 200 OK
Via: SIP/2.0/TLS client.biloxi.example.com:5061;branch=z9hG4bKnashd92;received=192.0.2.201
From: Bob <sips:[email protected]>;tag=ja743ks76zlflH
To: Bob <sips:[email protected]>;tag=37GkEhwl6
Call-ID: [email protected]
CSeq: 2 REGISTER
Contact: <sips:[email protected]>;expires=3600
Content-Length: 0

There you have it, a 200 OK response and Bob is registered on biloxi.example.com.

Update 2021: Jason Murley has contributed a much more robust version of the code below, which is way better than what I’d made!

You can find his code here.

I’ve written a little tool in Python to generate the correct response based on the nonce and values associated with it:

import hashlib

nonce = 'ea9c8e88df84f1cec4341ae6cbe5a359'
realm = 'sips:biloxi.example.com'
password = 'bobspassword'
username    =   str("bob")
requesturi  =   str(s"ips:biloxi.example.com")
print("username: " + username)
print("nonce: " + nonce)
print("realm: " + realm)
print("password: " + password)
print("\n")

HA1str = username + ":" + realm + ":" + password
HA1enc = (hashlib.md5(HA1str.encode()).hexdigest())
print ("HA1 String: " + HA1str)
print ("HA1 Encrypted: " + HA1enc)
HA2str = "REGISTER:" + requesturi
HA2enc = (hashlib.md5(HA2str.encode()).hexdigest())

print ("HA2 String: " + HA2str)
print ("HA2 Encrypted: " + HA2enc)

responsestr = HA1enc + ":" + nonce + ":" + HA2enc
print("Response String: " + responsestr)
responseenc = str((hashlib.md5(responsestr.encode()).hexdigest()))
print("Response Encrypted" + responseenc)

12 thoughts on “Reverse MD5 on SIP Auth

  1. I was trying to figure out an easy way to compare SIP digest passwords and came across your site here. The information was helpful and I created an improved Python script for doing this.
    Check it out if you want over at:
    https://github.com/jmurley/sip_md5

    1. Thanks Jason, that’s great, I’ve updated the article to include a link to your GitHub page, keep up the good work!

  2. Thanks Nick for sharing this information. For my use case I have to use a slightly varied formula for response, adding in the comments for anyone who has cnonce and qop values in the REGISTER message.

    HA1=MD5(username:realm:password)
    HA2=MD5(method:digestURI)
    response=MD5(HA1:nonce:nc:cnonce:auth:HA2)

  3. This proved extremely helpful to me today in figuring out that my phone system was truncating my password. However, I just want to say a couple things.

    In your write-up, you said your Digest URI was “sips:biloxi.example.com”. But in your examples, you used “sips:ss2.biloxi.example.com” instead. Your response MD5 values in both reflect the former, though.

    Also, if your using CNonce sent back from your client, you have to calculate the response a little different, as Gary said above. The full formula is the MD5 of:

    {HA1}:{Digest Nonce}:{Digest Nonce Count}:{Digest CNonce}:{Digest QOP}:{HA2}

    Gary has the formula right, I just wanted to clarify that his “nc” is the nonce count, and his “auth” is the QOP.

  4. Hi Nick,
    I’m a student of electrical engineering (telecommunication systems) in the master’s degree and working on a research project and article that is related to the fields of VoLTE, IMS, etc.
    I intend to register the IMS network to use VoLTE services with the help of a customized Python code and a rooted phone in the lab. My goal is to check the vulnerabilities of the network and then I intend to test in the real network and finally present the article.

    In this research, I will check the sent and received messages with the help of Wireshark.
    First, I sent the first Register message to the network and received 401 Unauthorized which contains the “nonce” value. Then, in the second step, I want to generate the “response” value using the “nonce” value received in the 401 Unauthorized message and then send it to the network in the second Register message for receive the 200ok message.
    I have done the first step, but I have a problem with the second step.
    In the second step, using the “nonce” value received from the IMS network, I should be able to create an algorithm or code to calculate the “response” value and send it to the network (My network uses MD5-AKAv1 algorithm).

    The code you introduced here is used in the VoIP network and has password value, which are not present in the received 401 Unauthorized message from the network side, and as a result, it isn’t possible to calculate the “response” value in the IMS network using this code.

    Will there be a way to calculate and use this code in the IMS network?
    If you are able to share code and collaborate, you and the code being shared will be credited (as a contributor) as part of the work done in the article.

    My Email is “[email protected]”.I will be happy to be able to use your help to solve my questions and problems.
    Best Regard,
    Ergün Kik.

      1. Hi Nick,
        thanks, but I have already read this link. My question is about something else.
        The code you introduced here is used in the VoIP network and has “password” value, which are not present in the received 401 Unauthorized message from the network side, and as a result, it isn’t possible to calculate the “response” value in the IMS network using this code.
        I want to know if Will there be a way to calculate and use this code in the IMS network?

  5. Having only the “Nonce” value from 401 Unauthorized massage, how can I calculate the “Response” value for send to newtork?

  6. Very interesting and helpful article! You have a new follower in the Telco industry 🙂

    However, let me know if there’s something I’m missing; at the beginning you say:
    “If we were to take the password password and hash it using an online tool to generate MD5 Hashes we’d get “482c811da5d5b4bc6d497ffa98491e38””

    If I go to the link provided and hash “password” I get 5f4dcc3b5aa765d61d8327deb882cf99, not 482c811da5d5b4bc6d497ffa98491e38

Leave a Reply

Your email address will not be published. Required fields are marked *