|
| 1 | +# CTF Style Laravel Pentesting Excercise |
| 2 | + |
| 3 | +This exercise has been test driven and developed on MacOS & Docker. |
| 4 | +Any other configurations will certainly need tweaking in certain parts, so be prepared to debug as you go along. |
| 5 | +Debian based distros like Ubuntu and Kali Linux should work pretty well. |
| 6 | + |
| 7 | +Basic PHP, Docker, *nix cli and Laravel knowledge are a must for this exercise. |
| 8 | +If you're lacking any of these, prepare to learn and tackle _a lot of_ issues as you proceed with this exercise. |
| 9 | + |
| 10 | +# !! Disclaimer !! |
| 11 | +This is *NOT* a copy-paste style exercise. |
| 12 | +There are *actual* steps that you need to do and learn in order to successfully complete the exercise. |
| 13 | +The goal of this exercise is to teach you hands-on basic exploitation techniques that will threaten a poorly engineered PHP/Laravel application. |
| 14 | +By understanding how to exploit _stupid_ mistakes like not validating file uploads, or echoing user input raw into DOM, you'll hopefully be less likely to do these mistakes at your day-to-day life & work. |
| 15 | + |
| 16 | +## There are 5 different vulnerabilities & exploits included in this exercise. |
| 17 | + |
| 18 | +1. Persistent XSS Attack |
| 19 | +2. SQL Injection Attack |
| 20 | +3. Password Cracking Attack (_Dictionary Attack_) |
| 21 | +4. RCE through Malicious File Uploads |
| 22 | +5. Privilege Escalation Attack |
| 23 | + |
| 24 | +## Requirements |
| 25 | +* Docker |
| 26 | +* Docker Compose |
| 27 | +* PHP (_>v7.1 preferably_) & Composer |
| 28 | +* Yarn/npm |
| 29 | +* nc (netcat) |
| 30 | +* john (https://www.openwall.com/john/) |
| 31 | +* sqlmap (http://sqlmap.org/) |
| 32 | +* pspy (https://github.com/DominicBreuker/pspy) |
| 33 | +* SecLists (https://github.com/danielmiessler/SecLists) |
| 34 | +* Browser that runs Javascript & recognises `fetch()` without a polyfill, preferably Chrome/Firefox |
| 35 | +* ~3GB of free disk space |
| 36 | + |
| 37 | +## Installation & setup |
| 38 | +* Navigate to project root, and run `docker-compose build` to build the application docker image |
| 39 | + * This will take while since we're compiling Apache v2.2.20 & php v7.1.29 manually as part of the docker image building process |
| 40 | +* After the image has built successfully, start the app container & db container via running `docker-compose up -d` |
| 41 | + * Tweak exposed ports in `docker-compose.yaml` if ports `1234 && 33601` are already bound on your machine |
| 42 | +* Install php dependencies via `composer install` |
| 43 | +* `cp .env.example .env` to create the `.env` file |
| 44 | +* Install JS dependencies via yarn/npm, eg `yarn` or `npm install` |
| 45 | +* Build the JS bundle & compile Sass & Tailwind etc via `yarn dev` or `npm run dev` |
| 46 | +* Migrate & seed the database |
| 47 | + * `docker exec laracon-app php /app/artisan migrate:fresh --seed ` |
| 48 | +* If everything went well you should see "Best Laravel Jobs" & a working front-page by navigating to `http://localhost:1234` in your browser |
| 49 | + * If you're unsure about modifying your local hosts file, please skip the following option. |
| 50 | + * You can optionally set a hostname by appending eg. `127.0.0.1 laravel-ctf.com` to `/etc/hosts`, and then access the app via `http://laravel-ctf.com:1234` |
| 51 | +* When you're done, `docker-compose down` to stop & remove the containers of this exercise. |
| 52 | +* You should also clean the locally built image (_it's ~1,85GB in size..._) by finding it via `docker image ls` and removing it via `docker image rm IMAGE_ID` |
| 53 | + |
| 54 | +## XSS Attack |
| 55 | +* Open a web server on your local machine |
| 56 | + * eg. `php -S localhost:8888` |
| 57 | +* Find the company profile of 'Hacking Laravel Inc.' and send them a message via contact form |
| 58 | + * Wrap the content of `exploits/xss.js` in script tags and send that as the message part of the contact form |
| 59 | +* Spy the user credentials from `DatabaseSeeder` and log in with those |
| 60 | +* Open dev tools in your browser before logging in |
| 61 | +* Log into the system with the credentials |
| 62 | +* Make sure that you see a 404 error & CORS error on your console to know that the XSS attack script executed successfully (*do not log out or the cookie gets invalidated!*) |
| 63 | +* See the authentication cookie being recorded into stdout/logfile by the web server that you started in step 1 |
| 64 | +* Open a new incognito browser window |
| 65 | +* Navigate to http://localhost:1234 & open dev tools |
| 66 | +* Replace the session cookie value with the token that you got |
| 67 | + * Make sure you copy *only* the token, not the URL encoded quotes around the actual value... |
| 68 | +* Refresh your browser window |
| 69 | +* Voilá, you've got initial foothold to the application now |
| 70 | + |
| 71 | +## SQL Injection Attack |
| 72 | +* While logged in with the stolen token, see where you can find a job list within the application |
| 73 | +* By investigating the page you found, you should be able to find a jobs API URL endpoint (has a `?sort=` param in it) |
| 74 | +* Test the API endpoint for SQLi vulnerabilities via `sqlmap -u api_url_that_you_found --batch --dbms=mysql` (_keep the URL param in_) |
| 75 | + * This can easily run for over 10 minutes if you're using docker-for-mac, be patient... |
| 76 | +* You'll see 3 SQLi vulnerabilities listed if successful (_if not, go back and try harder_) |
| 77 | +* See what options sqlmap has available via `sqlmap --help` & find a way to extract admin user's password hash |
| 78 | +* Save the password hash into a file, that'll be required in the next step |
| 79 | + |
| 80 | +## Password Attack (_Dictionary Based_) |
| 81 | +* Run `john` with top 10,000 passwords list (from SecLists) & bcrypt format, pass in the hash obtained in previous step |
| 82 | +* If you missed the password you can run `john` again with `--show` flag |
| 83 | +* You should have the admin user's password now |
| 84 | +* Switch to an admin account now to continue further |
| 85 | + |
| 86 | +## Malicious File Uploads & Remote Code Execution |
| 87 | +* With admin credentials you can find a file uploader in the application that's lacking proper file type validation |
| 88 | +* Upload a backdoor / RCE script of your choice |
| 89 | + * Pro tip: try building your own script by combining `system()` & passing in an argument from a HTTP request via PHP's superglobals |
| 90 | +* Find the file you uploaded, and invade the machine by spawning a reverse shell connection onto the target machine (http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet) |
| 91 | + * Pro tip: remember to URL encode the RCE payload to preserve control characters |
| 92 | +* You should have a shell for user `daemon` now |
| 93 | + |
| 94 | +## Privilege Escalation |
| 95 | +* There's something interesting happening on the target machine *consistently*... Try enumerating with `pspy` and see if you can figure out what I'm referring to. |
| 96 | + * Yes, you'll need to find a way to get the script transferred onto the machine first. See what tools you've got at your disposal that suit the task at hand. |
| 97 | + * If you don't see anything after sniffing for over 10-minutes with `pspy`, restart the containers via `docker-compose restart` & try again |
| 98 | +* Research your findings online, and find out how the process you discovered is being configured & operated |
| 99 | +* Hijack the process and escalate to root privileged reverse shell session |
| 100 | +* Congratulations, you've just rooted the machine & completed the exercise. |
| 101 | + |
| 102 | +# Issues |
| 103 | +Preferably open a PR directly rather than an issue if you find something wrong in the app and/or its documentation. |
| 104 | +As the license states this software comes "as is" with absolutely no warranty whatsoever, and therefor isn't guaranteed to be maintained and/or updated even if found faulty. |
| 105 | + |
| 106 | +# Developing Further |
| 107 | +Yes, eg. configuring a Selenium container (_via Laravel Dusk for example_) to trigger the XSS exploit code would be epic, rather than having to fire it manually like currently is the case. |
| 108 | +Feel free to open a PR do that if you feel like doing so. Feature wise however lets keep the application as it is, to not broaden its scope into an unmaintainable mess. |
| 109 | + |
| 110 | +# License |
| 111 | +MIT - see LICENSE file |
0 commit comments