The BodgeIt store part one
The Bodgelt store
The BodgeIt Store created by Psiinon is a vulnerable web application. It consists of a wide variety of vulnerabilities and is NOT intended to be hosted on a production environment.
Features of The BodgeIt Store:
- Drag and drop the WAR file to setup the vulnerable web application
- Cross platform. Can work on both Windows and Linux without any changes to the code or the servlet engine
- Open source and available for code review
- NO database setup required. Uses HSQLDB as backend database (Sqlmap and Havij won't work here)
This vulnerable web application also has a scoring page which lists 12 challenges to complete. Reporting of any other vulnerability discovered is welcome.
Note: From here on we will refer to The BodgeIt Store as "TBS."
To run TBS we require a servlet engine. Here we will be using "Apache Tomcat."
The BodgeIt Store can be downloaded from Google Code.
At the time of writing this article the available version of TBS was v1.4.0.
- Extract the archive of Apache Tomcat to a suitable location.
- Now extract the archive of TBS and you will get a WAR (web archive) file, "bodgeit.war."
- Copy the WAR file to the "webapps" directory in the Apache Tomcat installation.
Start Tomcat by opening:
- "startup.sh" for Linux
- "startup.bat" for Windows
- Now point your browser to http://127.0.0.1:8080/bodgeit/
The BodgeIt Store is now up and running.
The BodgeIt store in action
The home page of TBS looks like this:
Please note that we won't be using any vulnerability scanners or crawlers to test the web application. It will be a completely manual testing and vulnerability discovery.
Before going any further, it is always a good practice to check out all the links and content on the web application. I recommend you to go ahead and open the links available on the website and also the HTML source code of the web pages.
After manually crawling the website, we have a list of items that we are going to find useful:
- The "About Us" page leads to a "Scoring Page" (http://10.0.0.2:8080/bodgeit/score.jsp)
- The "Contact Us" page has a feedback form (http://10.0.0.2:8080/bodgeit/contact.jsp)
- Login page: http://10.0.0.2:8080/bodgeit/login.jsp
- User registration page: http://10.0.0.2:8080/bodgeit/login.jsp
- Basket for registered users (http://10.0.0.2:8080/bodgeit/basket.jsp)
- Search page: http://10.0.0.2:8080/bodgeit/search.jsp
- Advanced search page: http://10.0.0.2:8080/bodgeit/advanced.jsp
- Products pages: http://10.0.0.2:8080/bodgeit/product.jsp?typeid=5 and http://10.0.0.2:8080/bodgeit/product.jsp?prodid=22
The HTML source of the pages has a HTML comment:<!-- td align="center" width="16%"><a href="admin.jsp">Admin</a></td-->
The scoring page lists 12 challenges that need to be completed:
It is not compulsory to complete the challenges in the order they are listed, so we will complete them as we go on testing the web application.
The BodgeIt store testing
Previously, in our reconnaissance phase, we discovered that there is a HTML comment in the HTML source code of the pages. The HTML comment says:
<!-- td align="center" width="16%"><a href="admin.jsp">Admin</a></td-->
It is a hyperlink in a table which has been commented out. The hyperlink leads to a page in the web application "admin.jsp." As the name suggests it could be an administration panel.
If we open the page in our browser by pointing it to:
We get this:
As you can see, it is an unprotected administration panel.
It lists the users on the website with the userid, email address, role, basketid, and details about every user's. The basketid, along with the userid, identifies every user's purchase state on the web site.
This completes one of our challenges:
What we learned from this challenge:
- HTML comments that are necessary and cannot be avoided should only be placed in the file and no sensitive information should ever be placed in the HTML source as comments.
- The sensitive portions of the website should be protected with a secure login mechanism and should be well tested before deploying.
Let's go to the search page at http://10.0.0.2:8080/bodgeit/search.jsp
This page has a search form which accepts user input and performs a search operation. Let's test it by entering a product name; the response we receive is:
If we look closely our search term does get printed on screen. Here it is "Doodahs."
In such a case it is a good option to inject some HTML code and watch the response for the same. Now enter the search term as:
The response that we receive now is:
Our HTML code does get injected and appropriate response is generated.
This could lead to completing one of the challenges, which asks to
Now inject the HTML search term as:
The response now is a popup box:
What we learn:
- The input from a user should never be trusted.
- The user input should be validated, filtered, and checked thoroughly before it is processed any further.
Moving on to the contact us page located at: http://10.0.0.2:8080/bodgeit/contact.jsp
Here we have a feedback form. Let us again input some normal text and watch the response. Then we will lay down our strategy further.
Again our code gets printed on screen. Now we will insert some HTML code like:
The HTML code did execute. So now let us insert the other challenge code to popup a box:
Unfortunately, this doesn't give the desired output and we simply get "alert(XSS)" as response.
On analyzing our response and the HTML source, we find out that few things have been stripped out of our injected code:
Since our previous HTML code did get executed then there is a probability that we can get our popup code to execute, too.
We can assume that the server side script is be checking our input for the <script> tag and double quotes and stripping them out if present.
Many developers do this by checking user input against a blacklist to remove it from the input string. Here the blacklist words and characters are and double quotes (").
But if the code is checking our script for only <script> then we can change its case to or into a mixed case format like. Similarly for the closing tag as
Same goes for the double quotes, we can replace it with single quotes (').
In some cases the developer also checks for the uppercase string and then our code won't get executed and will be stripped. To get past that we can use the mixed case user input. It will also lead to the same response.
Unfortunately this does not complete one of the challenges, to popup a box with XSS as message. But still we found vulnerability.
On checking out the products page we get to know that to have access to the "basket" we need to a registered account on the website. Let us go ahead and create one.
I created a test account with the login credentials:
After logging in you will see that the email address we registered with is shown in the top right hand side. Again, there is a possibility that the user registration is vulnerable to HTML code injection.
Let us give some HTML input in the registration page, such as as username and anything as password.
The page responds with an error message: "Invalid username - please supply a valid email address"
This means that the username should be a valid email address.
Many a time developers make the mistake of implementing a buggy validation mechanism. We can test the form validation for a bug.
We can give it a valid email address along with some HTML code. For example:
Our code did get executed and the form validation also passed. Now we can input our as input and watch for the response
This marks the completion of another XSS challenge.
Login with the tester account created previously. The account password can be changed by clicking the email address in the top right hand side (http://10.0.0.2:8080/bodgeit/password.jsp).
We have a challenge that asks to change the password using a GET request. So before changing the password enable "Live HTTP Headers" (https://addons.mozilla.org/en-US/firefox/addon/live-http-headers/).
As we can see, the password change request is being sent using a POST request. Our goal is to change the password using a GET request. To accomplish that we can use a handy Firefox add-on, "Firebug" (https://addons.mozilla.org/En-us/firefox/addon/firebug/)
Right click on a form element and click "Inspect with Firebug." Scroll up a little bit and change the "method" attribute of <form> tag from POST to GET.
Now send the password change request with a new password.
Now the password change request is sent using GET request and is acknowledged by a message:
Your password has been changed
Let us buy some stuff from the products page.
Clicking the "Add to Basket" page takes us to "basked.jsp," where we can see the status of our basket and can also update it.
Again enable "Live HTTP Headers" to log how and what data flows upon clicking update basket.
The request sends the quantity and its value as POST data. But if we change the value of quantity to some negative number then we can make the store owe us money.
When we try to reduce the value of quantity to a negative value by using the minus button on the "basket.jsp" page, we get to know that it stops decreasing after value is zero. And the text box containing the quantity value is read only.
We can use "Tamper Data" (https://addons.mozilla.org/en-us/firefox/addon/tamper-data/) to change the value before it is sent to the server.
- Start tampering using Tamper Data.
- Update the basket.
- Change the value of quantity parameter to some negative number
- Submit the request.
- Stop tampering.
So the store owes us money now.
Online shopping websites maintain some data in cookies in the browser during our session on that website. This data is maintained in cookies. Cookies contain textual data that is stored in the browser and used to retrieve/manage some kind of data.
That is the case with TBS. The web application maintains a cookie in the browser named "b_id". We interpret it as "basket id". You can access and manage cookies using a Firefox add-on, "Cookie Manager+" (https://addons.mozilla.org/en-us/firefox/addon/cookies-manager-plus/)
One of the challenges asks us to access the basket of another user. Now the question arises: How do we find the basket id of another user? The answer is simple: previously we found an admin page that lists details of the registered users. The same page also listed the basket id of other users.
Now we can change the value of the "b_id" cookie to another user's basket id using "Cookie Manager+."
Now update your basket and refresh the page.
The response we receive:
The update basket process reads the new cookie value and shows its contents in our account, thus completing the challenge.
Note: Sometimes you might see that the challenge is not completed even when you have entered the correct the basket id. If it happens enter some other basket id and try again. The code is vulnerable.
What we learn:
- Cookies are accessible to users, so they should not be trusted blindly.
- Cookie values can be manipulated, so they should not hold any sensitive information.
- Avoid validating user information solely on the basis of cookie information.