Bypassing File Upload Restrictions with Magic Byte and a Hex Editor

This is a pretty cool, but easy, trick I learned today when working on a challenge. We've talked a bit about Magic Byte in the past when we did Networked on HTB.

Basically, it's a string that indicates a file type. You can check out a bunch of them here.

I was working on a challenge that required me to upload a file, but restricted me to certain image files. Unfortunately, GIF was not one of them, otherwise, I could have just appended GIF8; to the start of my webshell and called it good. That wasn't the case, and I had to figure out how to trick the target into accepting my file upload.

A bit of Google searching and I stumbled onto the the following post on Geeks for Geeks. The objective was different in that it discussed repairing a file with a corrupted magic number. However, it taught me the coolness of hexedit, which you can install with:

sudo apt-get install hexedit

In the following example, I have a text file called "tacos.txt.jpg". If I cat the file out, I see the actual text:

nux@KakaLinpoop:~/Documents/htb/boxes/magic/uploads$ cat tacos.txt.jpg 

Drink Pepsi.
Pop Boxes.
Drop Shells.
Eat Tacos.

Okay, cool.

Running xxd | head results in the following:

nux@KakaLinpoop:~/Documents/htb/boxes/magic/uploads$ xxd tacos.txt.jpg | head 
00000000: 0a44 7269 6e6b 2050 6570 7369 2e0a 506f  .Drink Pepsi..Po
00000010: 7020 426f 7865 732e 0a44 726f 7020 5368  p Boxes..Drop Sh
00000020: 656c 6c73 2e0a 4561 7420 5461 636f 732e  ells..Eat Tacos.
00000030: 0a

Then checking the filetype with file gives us:

nux@KakaLinpoop:~/Documents/htb/boxes/magic/uploads$ file tacos.txt.jpg 
tacos.txt.jpg: ASCII text

It's a text file. That's correct.

Magic Numbers

Now, based on what we know from Geeks for Geeks, a jpg file usually has one of the following magic numbers: FFD8 DDE0, FFD8 FFDB or FFD8 FFE1. When uploading our file, we just have to go with trial and error attempts. I had to try the first one, fail then try the second combination to make it work in the challenge I was working on.

Another useful post came from StackOverFlow. It pointed to a Wikipedia entry that said JPEG image files begin with FFD8 and end with FFD9. Now we know the bytes that start and end a valid jpg file. Let's apply it.

Creating a "jpeg" File

First, we run hexedit: hexedit tacos.txt.jpg.

We see something like this:

hexedit lets us edit the file's hex. Let's change the first bytes and the last bytes as we saw above:

  • First bytes will be: FFD8 FFDB
  • Last bytes will be: FFD9

It's a little difficult to tell here, but these are the first and last bytes. There's a wraparound and I've only cropped the relevant portion:

Now, when we run xxd, we see this:

nux@KakaLinpoop:~/Documents/htb/boxes/magic/uploads$ xxd tacos.txt.jpg 
00000000: ffd8 ffdb 6e6b 2050 6570 7369 2e0a 506f  ....nk Pepsi..Po
00000010: 7020 426f 7865 732e 0a44 726f 7020 5368  p Boxes..Drop Sh
00000020: 656c 6c73 2e0a 4561 7420 5461 636f 732e  ells..Eat Tacos.
00000030: ffd9 

If we check the filetype, we will see that it's a "jpeg":

nux@KakaLinpoop:~/Documents/htb/boxes/magic/uploads$ file tacos.txt.jpg 
tacos.txt.jpg: JPEG image data

This is great for bypassing file upload restrictions for uploading things like php webshells. It's a pretty cool trick, and it's really easy.