设为首页收藏本站

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 2216|回复: 2

Reverse Engineering Java; or How to get a free Canadian DID

[复制链接]
发表于 2011-5-13 23:14:36 | 显示全部楼层 |阅读模式
So I was asked to create a component for a support application that automatically pulls in customer information when said customer calls in to receive support. It makes life easier for the agent (they get pertinent info quicker) and makes life easier for the customer (they don’t have to spend time giving the agent information). That way you don’t get this:

Though anyone whose called Telus’ tech support knows that’s the least of their problems.
Anyway, writing this little script involved making use of the AGI (an API) in Asterisk (free PBX software). So like any good developer I read the API specification, installed Asterisk and wrote some code to handle incoming calls. But I pondered how I would test this beast; I didn’t wanna throw it up on a production server (we all know what happens when we publish untested code right guys?)… but then I remembered a good friend of mine, Alex, had recently told me about this free DID he’d gotten. Perfect! Except his free DID was from Washington and I didn’t want to be calling long distance. What do?

A quick trip to Google provided me with a solution to said problem; this amazing site: http://www.freephoneline.ca. A free Canadian DID in Vancouver, with unlimited incoming and local outgoing; too good to be true, right? And it almost was. Which is why this article is here. That little bit of “almost” was solved with a little bit of reverse engineering sorcery.

When you sign up you’ll be asked for a username (your email) and a password. Nothing unusual here. Then you must download their soft-phone client to interact with their SIP gateway. Their softphone requests your email/password combination you used to signup; trying to pass this as a SIP username and password in another VOIP client (Asterisk, other softphones, etc.), however, will get you nowhere.

A trip to their website told me I could pay them $50 so they could send me a config file with the SIP information in it. Except I knew in order for their softphone to work that same $50 worth of information existed in my computer absolutely free. Their site is “FREEphoneline.ca” after all.
Like any curious mind you can simply open up Wireshark and check out all the SIP traffic that’s heading out to their server. As it turns out your email/password combination is used to retrieve your SIP username/password; unfortunately one quickly comes to the conclusion that this information is encrypted and therefore not immediately useable. But, since the softphone obviously uses it to authenticate with their SIP service, the ability to decrypt those credentials must be present in the softphone software! And thus we begin our foray into abusing the softphone until it begs for mercy and yields us our SIP password.
Their softphone is called “FreePhoneLine”. If we take a quick peek into the program’s folder we notice that there is a “FreePhoneLine.jar” file. Add that to the fact they advertise it running on both Mac OS X and Windows, we can safely assume that this is a Java program.
Cool thing about Java “JAR” files: they’re just zip files. So let’s start digging into this program. Decompress “FreePhoneLine.jar”. (7zip will do this rather nicely). Ugh. All the Java class files are there but they all have names like “a”, “ab”, “b”, “c” and so on. Looks like someone ran this guy through an obfuscator to make our work a little bit more difficult. We can use tools like Ollydbg or IDA to inspect memory and DLLs that this program uses, but they are both primarily x86 debuggers; we need a program to debug Java opcodes, and what better one to use than Eclipse.

Load up Eclipse, create a new Java project and name it whatever you feel like.

Click “Add External Class Folder” and select the folder you just decompressed the JAR into. Next, click “Add External JARs” and go into the “FreePhoneLine/lib” folder and add all the JARs in there. Finish making the project.

Now, we need to find the class with the “main” function in order to start it running. Thankfully, JARs contain this nice little “META-INF/MANIFEST.MF” file which tells us which class has “main” in it. Open up the “MANAFEST.MF” file and you’ll see “Main-Class: vonix.ua.MainWnd”. How simple! In Eclipse open up the “vonix.ua” package, browse down to “MainWnd”, right click and select “Debug”.

So now that we’ve this program running, let’s actually go abuse it! Fill in your login information but don’t hit the login button. This next part is a little bit of a gamble. We know that the softphone retrieves your SIP credentials and then decrypts them and then connects the softphone to their SIP service. We’re going to make the gamble that if we hit login and pause the program in the debugger quick enough, there’s going to be some object still floating around with our SIP credentials.

With a little bit of probing it looks like we’ve hit the jackpot! There’s class named “kc” that contains the server information as well as the SIP username and decrypted password (found in the field “g”)! Copy that password somewhere and you basically have SIP credentials for a free DID with unlimited incoming and local outgoing calls.

If you want to keep probing for passwords, simply add a function breakpoint to the “kc” class’ constructor. That way you don’t need to make gambles about when you should stop the debugger; every time a decrypted password is passed into “kc”, Eclipse will pause the program and show you it.

Awesome? I think so.

And remember kids: security by obscurity never works. Ever. With perhaps one exception: you find a way to completely blackbox your code. This is the trusted client problem. If FreePhoneLine wants to fix up this wonderful little hole they need to assume their code can and will be introspected.
There is no real solution when you offer free service based on a standard protocol, but want to restrict it based on code running on the client’s machine! You cannot trust clients.  Anything that needs trust should be happening on the server. It’s a more sophisticated equivalent of those sites that try and force you to view them using Internet Explorer via the “User-Agent” header.
As an added bonus I’ll throw in the Asterisk config so you can get this bad boy rolling on your very own free phone server.
01; /etc/asterisk/sip.conf

02

03[general]

04useragent=FreePhoneLine 2.2.3.0 ; not sure if this is needed but it can't hurt

05register => YOURPHONENUMBER:YOURPASSWORD@voip.freephoneline.ca:5060

06

07[incoming]

08type=friend

09context=incoming

10username=YOURPHONENUMBER ; e.g. 16041234567

11secret=YOURPASSWORD ; eg 4RswqQ3

12fromuser=YOURPHONENUMBER

13qualify=no

14insecure=port,invite

15canreinvite=no

16allow=ulaw ; you might be able to get away with other codecs in here

17host=voip.freephoneline.ca

18port=5060

19realm=208.65.240.142 ; the IP address of voip.freephoneline.ca, not sure if this is needed though



As an exercise to the reader, you could have some extra fun and trace up the call stack from kc’s constructor and find the actual method that decrypts the password. From there on you could just decompile (ah the advantages of reverse engineering Java) the method block and create your own Java program to decrypt these passwords. Much easier than having to load the Eclipse debugger every time!

http://izaakschroeder.wordpress.com/2010/07/05/reverse-engineering-java-or-how-to-get-a-free-canadian-did/

 楼主| 发表于 2011-5-13 23:17:18 | 显示全部楼层
FreePhoneLine and Tom – A Truly Deep Reverse Engineering Adventure!                                            September 1, 2010 by izaakschroeder
NOTE: If you haven’t read the previous post related to this subject, you need to do so before you can make sense of any of this. This article is long and complicated and not for the faint of heart. It is, however, terribly fun!

So I was minding my own business, as usual, until I received this email:
Dear Mr Schroeder!
My name is Tom Shao from Canada. I was excited that you can reverse Engineering Java and obtain the secret password. Your instruction in the weblog is very detailed. However I don’t have eclipse installed on my desktop. I just wonder if you can do me a favor to help me get my password. My information is as follows:
[Omitted for obvious privacy reasons]
Any help would be much appreciated.
Thanks,
Tom
Now normally I don’t go off and just do work for people asking for stuff, given it’s supposed to be a learning experience; not a “hurr hurr give me free stuff” experience. However, only a few hours later I receive ANOTHER email!
I downloaded Eclipse and tried to debug it with no lock [sic] as the class KC is different with yours. I assume they updated the new version and fixed the problem.
Can you send me your Freephoneline software? I am desperate to need your help?
Thanks,
Tom
So you at least get some points for trying. As it turns out, they did indeed update their software, but it certainly wasn’t to “fix” that problem; in fact if anything they turned their program from a reasonable softphone client to a horrendously ugly (like I’ve taken shits that look better kind of ugly), slow, ad-filled piece of garbage.

The reason you can’t exactly follow my previous post is that the obfuscation process randomizes class names, methods and so on; every time they release a new version you will end up with a different naming scheme. The process of finding your credentials works the exact same way in the new version, introducing a manual break in the program and hunting through the class variables until you find the password.
But all is not lost for you Tom! I will help you redeem yourself! I have provided a handy comparison chart for the rest of our readers:

Thanks to you Tom, (but mostly me), other people now too can have free calls with little effort! This blog post covers something a bit more interesting and useful than what was discussed previously. It deals with discovering the FreePhoneLine authentication protocol itself and how to emulate it; it also exposes a possible security hole in that particular protocol.

Shall we find out?
Let’s start with what we know. You provide your FreePhoneLine username and password, which gets sent to the server and they send you your SIP username and password back; all of this is encrypted and therefore one can’t simply WireShark the information off the network.
We want to be able to achieve two things:
  • Be able to construct the appropriate request to get our encrypted username/password
  • Be able to decrypt the response so that we may use our SIP username/password
We’ll start things off the same way we did the previous article, breaking the program and finding out which class holds the clear-text password, and from there which class actually decrypts the password to its clear-text form. I’m not going to bore you with old hat; setup the project the same way as before and use the same techniques achieve the following result:

We’ve discovered that the class called “f” contains the connection information; particularly of interest are fields “e” and “g” which hold the SIP username and password respectively. We’re interested in finding out what modifies those variables; since they are public variables, (denoted by the green circle), they can be modified by any class; so we can use a feature in Eclipse very similar to a breakpoint called a watchpoint!
Watchpoints monitor variables; they will pause the execution of the program when a variable is read from, written to or both. Those familiar with x86 debuggers will note a similar feat can be achieved with hardware breakpoints. To set a watchpoint, find the class in the package viewer and select “Toggle watchpoint”.

Close the program if it’s being run and start debugging it again. The program will suspend immediately and drop you back into the debugger. What’s happened? The password isn’t being loaded in so soon obviously, as we have not even logged in yet. The answer is disappointingly simple; the variable is simply being initialized to null, (i.e. the program is writing null into the variable). We can just resume the program. But wait! It pauses again! What’s going on this time? Again, the answer is disappointingly simple. The variable is being set to the empty string “”. Remember! Null is not the same as the empty string! The empty string is still a string object, the null string is nothing. You can see this by hitting the “Step over” button and you can watch “g” change from null to the empty string.

Anyway, we can go back to running the program and you should be able to hit up the login box and enter your credentials before the program breaks you back into the debugger again. You should then end up with something like the following:

This looks promising! You’ll note if you look in the variables view that the field “g” still does not have your password. That means if we hit “step over” your password will suddenly appear! That’s because something within “wo.c” (remember, “c” is a method of the class “wo”) is saying “g = SIPPassword”. That’s the whole purpose of a watchpoint. So we basically want to understand what goes on inside “wo.c” that is setting our password.

But how on Earth do we begin to do that when we don’t have any source code to work with? Well, we just make source code! Using a tool called a decompiler we can turn a Java “.class” file back into a “.java” file! Pretty impressive! Not all decompilers were created equal, and a lot of semantic information is lost in the decompilation process, but the result is still extremely useful!
I have chosen to use a Java decompiler called JD. (Original name, eh?) You can get your copy here. Extract “JD-GUI”, and run it. Open the “wo.class” file with it.

And then find the “c(ActionEvent)” method within it. There’s a lot of code in that class, so I won’t bother pasting it all. I will, however, highlight a few parts that tell us we’re probably going in the right direction!
1String str1 = this.a.getText();

2String str2 = String.valueOf(this.i.getPassword());



See that “getPassword()” there? That’s probably getting the password you entered, and the “getText()” above it is probably fetching your username! And as we scroll down that code chunk:
1this.l.e = zc.d();

2this.l.g = dc.a(zc.f(), this.l.e); //THIS LINE TRIGGERED OUR WATCHPOINT! l.g IS ASSIGNED HERE!

3setVisible(false);



And once you see it visually the correlation becomes even more obvious:

We can make an educated guess that “zc.d” fetches the username, “zc.f” fetches the encrypted password and “dc.a” handles the decryption! And once everything is done the login windows calls “setVisible(false)” to hide itself from view. Things are coming together nicely! In JD simply click on the underlined “dc” class and we can start checking out the “dc.a” function.
1import javax.crypto.Cipher;

2import javax.crypto.spec.IvParameterSpec;

3import javax.crypto.spec.SecretKeySpec;



When you see things like that at the top the file, you just know you’re in the right spot; they’re using standard ol’ Java cryptography APIs! That will make things even easier on us because all those APIs are very well documented. We can check out the rest of the file and we realize that there are a few functions called “a”. The one that’s being called takes two arguments.
1this.l.g = dc.a( //returns a string because l.g is a string, obvious from the debugger

2    zc.f(), //we don't know this type; we could check the return type of zc.f though

3    this.l.e //this is a string type, obvious from the debugger

4);



But since this function, “dc.a” is called from “wo.c”, we know that whatever particular “a” is being called also needs to be a public method! This narrows it down to just one function:
1public static String a(byte[] paramArrayOfByte, String paramString)



Which we observe basically only does one important thing:
1byte[] arrayOfByte = a(false, paramArrayOfByte, paramString);

2return new String(arrayOfByte).trim();



It calls ANOTHER a and returns its value in string form! That particular “a” is easily identifiable as being the only one which takes a boolean argument initially.
1private static byte[] a(boolean paramBoolean, byte[] paramArrayOfByte, String paramString)

2{

3    int i = cc.c;

4    byte[] arrayOfByte1 = a(paramString);

5    SecretKeySpec localSecretKeySpec = new SecretKeySpec(arrayOfByte1, z[1]);

6    Cipher localCipher = Cipher.getInstance(z[2]);

7    IvParameterSpec localIvParameterSpec = new IvParameterSpec(z[0].getBytes());

8    //...

9}



Is obviously the most interesting one; it actually makes use of cryptographic functions! A quick trip to their API documentation pages reveals the purpose of their arguments.
Now we know:
01private static byte[] a(boolean paramBoolean, byte[] paramArrayOfByte, String paramString)

02{

03    int i = cc.c;

04    byte[] arrayOfByte1 = a(paramString);

05    //First argument is the decryption/encryption key, second argument is the algorithm being used

06    SecretKeySpec localSecretKeySpec = new SecretKeySpec(arrayOfByte1, z[1]);

07

08    //Only argument is the algorithm being used

09    Cipher localCipher = Cipher.getInstance(z[2]);

10

11    //Only argument is the data for the initialization vector

12    IvParameterSpec localIvParameterSpec = new IvParameterSpec(z[0].getBytes());

13

14    //...

15}



We are, however, lacking all values of “z”; these values are important as they’ll clearly tell us both the algorithm used for decryption and the initialization vector. They are not present in the decompiled code, so we’ll have to get them from the debugger. We also note “z” is a static class variable, and so we should be able to pick out said values any time. Given we’re interested how the decryption function works, we should breakpoint that and then we can start to kill two birds with one stone!

We can also now disable the watchpoint on “f.g” as we’ve found the method of interest. Restart the process and wait till you hit the breakpoint from logging in. (You’ll hit the breakpoint once when the program starts, but I have yet to figure out why).

Expressions let us inspect arbitrary parts of the program. It’s time to add one so we can find out the value of that mysterious “z”! Right click in the expressions pane and select “Add Watch Expression…”

And then enter the value “dc.z” as that is the variable we are interested in.

And then watch the magic!

This tells us some very important things! They’re just using plain old AES to encrypt their data and what the initialization vector is they use to encrypt it! So that’s one bird. Now for the other; we want to see how the function is actually used and what values are fed into it. If you go back to the variables tab you’ll see what the arguments to the function are. But things are not as they seem…

What on earth is the web username doing there?
1this.l.g = dc.a(

2    zc.f(), //we assume this returns encrypted data

3    this.l.e //this is the SIP username, NOT the web username!! So what gives?

4);



Well clearly “dc.a” is being called from somewhere other than just that line above or we’ve really messed things up; but to be safe we’ll hit “Continue” in the debugger and see if we can reach a point where “arg2″ is the value we expect, the SIP username (i.e. phone number).

Our patience is rewarded! Let’s go back and see how this plays out in our function.
01private static byte[] a(boolean paramBoolean, byte[] paramArrayOfByte, String paramString)

02{

03    int i = cc.c;

04

05    //So this basically calls a("16042834338") and sets arrayOfByte1 to its value

06    byte[] arrayOfByte1 = a(paramString);

07

08    //This creates a new key using the output of the previous function for an "AES" cipher

09    SecretKeySpec localSecretKeySpec = new SecretKeySpec(arrayOfByte1, z[1]);

10

11    //Creates an "AES/CBC/NoPadding" cipher instance

12    Cipher localCipher = Cipher.getInstance(z[2]);

13

14    //Creates an initialization vector using the string "fedcba9876543210"

15    IvParameterSpec localIvParameterSpec = new IvParameterSpec(z[0].getBytes());



The next part appears dependent on the boolean parameter. We need to know a little more about the “Cipher” object before we can determine what this function does. A quick trip to the API reference shows the first parameter determines the ciphers operating mode (encryption vs decryption for example), with the other arguments being self explanatory: the encryption key and the initialization vector. “arrayOfByte2″ appears to be the data which is either encrypted or decrypted.
01  byte[] arrayOfByte2;

02  if (i == 0)

03  {

04    if (paramBoolean) //false in our case

05    {

06      //initialize to encryption mode

07      localCipher.init(1, localSecretKeySpec, localIvParameterSpec);

08

09      //set the data to be encrypted via "md.a" using the third parameter of this function

10      arrayOfByte2 = md.a(paramArrayOfByte);

11      if (i == 0);

12    }

13    else //so we go here

14    {

15      //initialize to decryption mode

16      localCipher.init(2, localSecretKeySpec, localIvParameterSpec);

17    }

18  }

19  else

20    //data to be processed is just the input

21    arrayOfByte2 = paramArrayOfByte;

22

23  //perform the encryption/decryption of arrayOfByte2

24  byte[] arrayOfByte3 = localCipher.doFinal(arrayOfByte2);

25

26  //return the processed data

27  return arrayOfByte3;

28}



The “i” variable is a little confusing and it may be a side-affect of the decompiler not doing something right; from here on out we have to start making some educated guesses. We know the processing key is ALWAYS altered by some function, (ironically ALSO called “a”), we know one function does both encryption and decryption, we know that when the SIP username is involved as part of the key argument this function operates in decryption mode. It is likely safe to assume that the second parameter is therefore the encrypted SIP password.
I’m going to briefly force you to go back in time, to when the web username was present instead of the SIP username. Look at the first parameter; it’s true instead of false! This means that your web username is being used to encrypt something! This might be useful knowledge for later!
We’re getting really close now! We basically need to understand what the key modification function does.
1byte[] arrayOfByte1 = a(paramString);



You will find its basic purpose is thus:
1ec localec = new ec(paramString);

2byte[] arrayOfByte = md.b(localec.a().substring(0, 16));

3return arrayOfByte;



We’re now involving another TWO new classes! Egads! So we need to understand “ec” as well as the function “md.b”. Let’s deal with “ec” first by opening it up in the decompiler. The constructor is nothing interesting, it just saves the given key to a local variable. We’re interested in the “ec.a” function, which does nothing really but call “ec.b”. So let’s look at that.
It seems to involve message digests and another missing variable!
1localMessageDigest = MessageDigest.getInstance(z[1]);



Not even looking I imagine just like how “AES” was selected as the crypto algorithm, “z[1]” represents the choice of message digest algorithm. What is “z[1]“? Remember how we found “dc.z”? You can use exactly the same trick to find “ec.z”. Add a method breakpoint to “b”, add a watch expression for “ec.z”, disable all your other breakpoints and restart the debugger. You’ll have your z in no time!

So we now know that MD5 is somehow involved in transforming the given crypto key. Not like MD5 and AES has ever been used before…

1arrayOfByte = localMessageDigest.digest(this.a.getBytes());



Seems to perform the actual MD5 on the crypto key. We then observe what happens to the variable “arrayOfByte”. We see a loop and observe a lot of “Integer.toHexString(arrayOfByte);” calls. The educated guess says that the returned MD5 hash is raw binary data and they are turning it into its hex form. However, we should attempt to verify this. We note at the very end:
1return this.b;



They use b to store the result of the transform. We can simply add a watchpoint to “ec.b” and we’ll be able to test!

We know “ec.a” stores the plaintext value, so we just disable all other breakpoints, restart the program and compare! Remember, when the breakpoint hits, use “Step Over” so the value actually gets assigned. The first breakpoint you hit will likely be “b” being initialized to “null”, but the second… well that should be just magical.

And now we just check to make sure our hypothesis is correct:
1echo -n "16042834338" | md5sum

2b904785204cd684ff3965bc263220fc6



And it is! Fantastic! We now know “ec” is basically an MD5 hashing class. We go back to the line of code dealing with the transform and note that it appears to take only the resultant first 16 characters of the hex form of the MD5 hash and then pass those 16 characters into “md.b”.
1md.b(localec.a().substring(0, 16));



So once again open up the decompiler and find the “md.b” that takes a single string as its argument. It seems to involve a bunch of checks, but its main purpose seems to revolve around the line:
1arrayOfByte = (byte)paramString.charAt(i);



It essentially seems to just convert a string into an array of bytes. Why they weren’t using String.toBytes() who knows. But to say the least that function doesn’t seem to bastardize anything about the crypto key.
With all this information it is hard to think that we are not done yet. We still don’t know how to get the encrypted password and we still need to test our ability to decrypt that password. We know the encrypted password is sent to us over the air, so we can at least start there. Disable all your breakpoints, restart the program and fire up WireShark.
NOTE: For your own good, turn off your torrents, streaming music and other things which obsessively fire packets off over your network. It will make your life MUCH easier trying to sift through things in WireShark.

With as little delay as possible start capturing packets and log into FreePhoneLine. As soon as you see yourself log in stop capturing packets and start to browse through the dump looking for things related to FreePhoneLine. One quickly finds that the authentication happens over HTTP and that the typical response looks something like:

One can make an educated guess that the encrypted password is base-64 encoded, simply by seeing the “==” on the end and knowing that encrypted data almost always falls outside the printable ASCII range.
So let’s build a program to decrypt these passwords! I’m going to use (yea haters gonna hate) PHP because it comes with cryptography functions built in and is fast to prototype things with.
01<?php

02

03function new_freephoneline_crypto_context($Key) {

04    $Key = substr(md5($Key), 0, 16); //The first 16 characters of the hex represntation of the MD5 of the key

05    $IV = 'fedcba9876543210'; //The IV they use

06    if ($CryptoModule = mcrypt_module_open('rijndael-128', '', 'cbc', '')) { //Open the cipher (AES _is_ Rijindael)

07        mcrypt_generic_init($CryptoModule, $Key, $IV); //Initialize

08        return $CryptoModule; //Return

09    } else {

10        die('Initializing mcrypt failed!');

11    }

12}

13

14function delete_freephoneline_crypto_context($CryptoModule) {

15    mcrypt_generic_deinit($CryptoModule);

16    mcrypt_module_close($CryptoModule);

17}

18

19$SIPUsername = '16042834338';

20$EncryptedSIPPassword = base64_decode('WhubSHQz2nqFNK/N0xGMvw==');

21

22$Context = new_freephoneline_crypto_context($SIPUsername);

23$DecryptedPassword = mdecrypt_generic($Context, $EncryptedSIPPassword);

24delete_freephoneline_crypto_context($Context);

25

26$Output = 'Username is: '.$SIPUsername.', and password is: '.$DecryptedPassword;

27

28echo $Output;

29?>



Funny thing is, it works. You can now successfully take any of their encrypted SIP passwords and derive their plaintext ones. But we’re not done yet. So far we still need to use WireShark to get at those encrypted passwords. We want a truly automated process. We need to know how FreePhoneLine requests that information as well. You can easily find it in WireShark.

Le sigh. It looks like they encrypt the web password going out as well, and we’re going to have to mimic that. But wait… don’t you remember that one time we saw the debugger stop and use our web username as a key for ENCRYPTION? It’s starting to come together now isn’t it? We can make another educated guess in that it simply encrypts our web password with our web username in the exact same manner it decrypts the SIP one. We can write another program to test this!
This is also a bit of a crapshoot, as I have no idea how “key” is generated, or even if its necessary. But after some testing it turned out that not providing “key” doesn’t make any difference.
01<?php

02

03$WebUsername = 'izaak.schroeder@gmail.com';

04$WebPassword = 'lolfreephoneline';

05

06$Context = new_freephoneline_crypto_context($WebUsername);

07$EncryptedWebPassword = mcrypt_generic($Context, $WebPassword);

08delete_freephoneline_crypto_context($Context);

09

10if ($CURLHandle = curl_init('http://www.freephoneline.ca/services/init')) {

11    curl_setopt($CURLHandle, CURLOPT_RETURNTRANSFER, true);

12    curl_setopt($CURLHandle, CURLOPT_HEADER, false);

13    curl_setopt($CURLHandle, CURLOPT_POST, true);

14    curl_setopt($CURLHandle, CURLOPT_POSTFIELDS, ''

15        .'web_username='.urlencode($WebUsername).'&'

16        .'web_password='.urlencode(base64_encode($EncryptedWebPassword)).'&'

17        .'key='

18    );

19

20    $Data = array();

21    foreach(explode("\r\n", curl_exec($CURLHandle)) as $Line)

22        if (false !== $Target = strpos($Line, '='))

23            $Data[trim(substr($Line,0,$Target))] = trim(substr($Line, $Target+1));

24    curl_close($CURLHandle);

25    echo 'SIP username: '.$Data['sip_username'].', encrypted SIP password: '.$Data['sip_password'];

26} else {

27    die('Initializing CURL failed!');

28}

29?>



Oh look, it works! We have effectively and nearly completely (save for whatever “key” does) emulated the FreePhoneLine authentication protocol. Combining those two scripts might leave you with something like:
01<?php

02

03//This file is called ffd.php

04

05$Output = 'Nothing interesting to show here Capt\'n';

06

07function new_freephoneline_crypto_context($Key) {

08    $Key = substr(md5($Key), 0, 16);

09    $IV = 'fedcba9876543210';

10    if ($CryptoModule = mcrypt_module_open('rijndael-128', '', 'cbc', '')) {

11        mcrypt_generic_init($CryptoModule, $Key, $IV);

12        return $CryptoModule;

13    } else {

14        die('Initializing mcrypt failed!');

15    }

16}

17

18function delete_freephoneline_crypto_context($CryptoModule) {

19    mcrypt_generic_deinit($CryptoModule);

20    mcrypt_module_close($CryptoModule);

21}

22

23if (isset($_REQUEST['u']) && isset($_REQUEST['p'])) {

24

25    $WebUsername = $_REQUEST['u']; $WebPassword = $_REQUEST['p'];

26

27    $Context = new_freephoneline_crypto_context($WebUsername);

28    $EncryptedWebPassword = mcrypt_generic($Context, $WebPassword);

29    delete_freephoneline_crypto_context($Context);

30

31    if ($CURLHandle = curl_init('http://www.freephoneline.ca/services/init')) {

32        curl_setopt($CURLHandle, CURLOPT_RETURNTRANSFER, true);

33        curl_setopt($CURLHandle, CURLOPT_HEADER, false);

34        curl_setopt($CURLHandle, CURLOPT_POST, true);

35        curl_setopt($CURLHandle, CURLOPT_POSTFIELDS, ''

36            .'web_username='.urlencode($WebUsername).'&'

37            .'web_password='.urlencode(base64_encode($EncryptedWebPassword)).'&'

38            .'key='

39        );

40

41        $Data = array();

42        foreach(explode("\r\n", curl_exec($CURLHandle)) as $Line)

43            if (false !== $Target = strpos($Line, '='))

44                $Data[trim(substr($Line,0,$Target))] = trim(substr($Line, $Target+1));

45        curl_close($CURLHandle);

46

47        if (!isset($Data['sip_username']) || !isset($Data['sip_password'])) {

48            $Output = 'Error getting credentials; perhaps wrong username or password?)';

49        } else {

50            $SIPUsername = $Data['sip_username'];

51            $EncryptedSIPPassword = base64_decode($Data['sip_password']);

52

53            $Context = new_freephoneline_crypto_context($SIPUsername);

54            $DecryptedPassword = mdecrypt_generic($Context, $EncryptedSIPPassword);

55            delete_freephoneline_crypto_context($Context);

56

57            $Output = 'Username is: '.$SIPUsername.', and password is: '.$DecryptedPassword;

58        }

59    } else {

60        die('Initializing CURL failed!');

61    }

62}

63?><html>

64    <head>

65        <title>Freephoneline SIP Credentials Decryptor</title>

66    </head>

67    <body>

68        <form method="post" action="ffd.php">

69            <fieldset>

70                <legend>FreePhoneLine Login Information</legend>

71                <div>

72                    <label>Username:</label>

73                    <input style="width: 200px;" type="text" name="u" placeholder="username" value="<?php echo isset($_REQUEST['u']) ? $_REQUEST['u'] : '' ; ?>"/>

74                </div>

75                <div>

76                    <label>Password:</label>

77                    <input style="width: 200px;" type="password" name="p" placeholder="password" value="<?php echo isset($_REQUEST['p']) ? $_REQUEST['p'] : ''; ?>"/>

78                </div>

79            </div>

80            <div><input type="submit" value="Get My SIP Info"/></div>

81        </form>

82        <hr/> <?php echo $Output; ?>

83    </body>

84</html>



After such a long journey seeing something like:

is immensely satisfying, isn’t it Tom?
And what about that security hole I mentioned? Well thing is, they encrypt your web password with your web username… both of which are sent in plaintext over the wire. You can already see how dumb of an idea this is. If someone is using FreePhoneLine on your network and you have WireShark going and you get their encrypted web password and their login… guess what! You have their decrypted web password too!
Anyway, hope you’ve enjoyed this little adventure. And remember kids, only you can prevent bad designs from being used!
Until next time!

9 Votes


  • Share this:


                                                                                                                        Filed under Uncategorized                                                
               
                                                                About izaakschroeder
I sell cheese and cheese accessories.
            
                                                Like
Be the first to like this post.

                12 Responses to FreePhoneLine and Tom – A Truly Deep Reverse Engineering Adventure!                
  •                                                                                 Matt says:               
                                    November 6, 2010 at 7:26 pm
                    after work FPL call me said I didn’t buy SIP setting and they won’t allow me to use that function. how do they know I am using a ATA?

                                            Reply               
           
           
    •                                                                                 izaakschroeder says:               
                                      November 6, 2010 at 7:31 pm
                      I imagine they keep a record of all phone numbers which have had SIP settings purchased for; I then imagine they check that against the User-Agent SIP header or something similar to see if you’re using their client or another (e.g. Asterisk). I’m sure it’s maskable if one was to look at the protocol more in-depth.
      Cheers,

                                              Reply               
             

  •                                                                                 Jimmy T says:               
                                    November 15, 2010 at 12:46 pm
                    Howdy!
    My question is very simple.  I followed the last post on the original version, compared to this one.  I got lost, then managed to follow along again.  My question is, how can I build the php code to work, as you posted it there?
    I am not a code wizard, but understand the principle.  I just wanna use the code now, but have nothing to build or test it with, that works–I tried using firefox, IE, and even things like http://forumferney.free.fr/stester.html.  How can I get the script to work, or a compiled executable version for win32?
    Thanks big papa

                                            Reply               
           
  •                                                                                 Jimmy T says:               
                                    November 15, 2010 at 1:18 pm
                    P.S. The html form looks normal, but the fields are already prefilled.  The username is filled with “”
    the password is filled with hidden info, I bet it’s the same code format as above.  Something wrong with splicing php and html forms?
    Please let me know, what is wrong with me.
    Merci

                                            Reply               
           
  •                                                                                 sb says:               
                                    January 31, 2011 at 10:05 am
                    Thanks a lot!
    The PHP code is working perfect!!

                                            Reply               
           
           
    •                                                                                 izaakschroeder says:               
                                      February 17, 2011 at 12:27 am
                      Awww yeea!

                                              Reply               
             

  •                                                                                 MJ says:               
                                    February 19, 2011 at 10:57 pm
                    I don’t have a webserver running, so I tried a hosted server to run php. It looks like most servers don’t have the ‘mcrypt’ module installed. It throws me an error – “Call to undefined function mcrypt_module_open()”
    Any way around it? Do anyone know of any php hosts with mcrypt installed?

                                            Reply               
           
           
    •                                                                                 izaakschroeder says:               
                                      February 20, 2011 at 9:06 pm
                      Hey hey,
      CodeRun supports both mcrypt and curl: http://www.coderun.com/ide/. Naturally you’ll have to replace “ffd.php” with “index.php”, but other than that it should work.

                                              Reply               
             
             
      •                                                                                 mic says:               
                                        March 3, 2011 at 1:41 am
                        this is really awesome.
        any help on masking so fpl cannot find out if we are using their client or asterisk / ata ?
        thanks

                       
               
      •                                                                                 izaakschroeder says:               
                                        March 4, 2011 at 4:14 pm
                        Glad you enjoyed it! Your question was mentioned previously, though to reiterate: I’m not entirely sure if it’s possible to make it so they can’t find out, but it’s simple enough to do things like change the SIP user agent header from Asterisk to the one used by their client. (Likewise matching up other configuration options such as codecs used to ones as close to their client as you can).






发表于 2011-5-20 13:00:40 | 显示全部楼层
呵呵 支持楼主  好帖必顶!




今年度Millasha美胸Millasha丰胸被誉为Millasha热潮Millasha团体,成为最热门的Millasha话题与Millasha模式
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|小黑屋|BC Morning Website ( Best Deal Inc. 001 )  

GMT-8, 2025-8-26 04:55 , Processed in 0.019231 second(s), 17 queries .

Supported by Best Deal Online X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表