File upload HTB skill assessment
Introduction
This is the skill assessment section in the File Upload Attack module of the HTB. We are going to use the skills learned - including the front-end filter, black list filter, whitelist filter and - to get the flag at the root directory.
Path to the flag
1. Front-end verification:
Firstly, we find the file upload page of the target site. When inspecting the page, we found that there is a front-end file verification function. Only after deleting it can we send a file upload request containing the payload.
2. Read source code with XXE:
To avoid fuzzing, we can try read the source code of the upload filter. We can try XXE with a svg file. The reponse will contain the source code encoded in base64.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
require_once('./common-functions.php');
// uploaded files directory
$target_dir = "./user_feedback_submissions/";
// rename before storing
$fileName = date('ymd') . '_' . basename($_FILES["uploadFile"]["name"]);
$target_file = $target_dir . $fileName;
// get content headers
$contentType = $_FILES['uploadFile']['type'];
$MIMEtype = mime_content_type($_FILES['uploadFile']['tmp_name']);
// blacklist test
if (preg_match('/.+\.ph(p|ps|tml)/', $fileName)) {
echo "Extension not allowed";
die();
}
// whitelist test
if (!preg_match('/^.+\.[a-z]{2,3}g$/', $fileName)) {
echo "Only images are allowed";
die();
}
// type test
foreach (array($contentType, $MIMEtype) as $type) {
if (!preg_match('/image\/[a-z]{2,3}g/', $type)) {
echo "Only images are allowed";
die();
}
}
// size test
if ($_FILES["uploadFile"]["size"] > 500000) {
echo "File too large";
die();
}
if (move_uploaded_file($_FILES["uploadFile"]["tmp_name"], $target_file)) {
displayHTMLImage($target_file);
} else {
echo "File failed to upload";
}
3. Analyze the filter:
Blacklist : The code uses a regular expression to block file uploads that have an extension matching
.php
,.phps
, or.phtml
. This is aimed at preventing the upload of executable PHP scripts.Whitelist : It checks that the file name ends with a pattern that seems to intend to allow only images. The regex pattern looks for file names ending with a period followed by 2 to 3 characters and then a “g” (e.g.,
.jpg
,.png
), aiming to match common image extensions.Type : This part checks both the
Content-Type
header and the MIME type of the actual file content, looking for types that start withimage/
and end with 2 to 3 characters followed by “g” (matching types likeimage/jpeg
orimage/png
).Size : The file must be smaller than 500,000 bytes.
4. Bypass the MIME type filter:
The filter about the file name,Content-Type
, or size is easy to bypass. But we need to craft a pretending legitimate picture to bypass the MIME type filter. [The wikipedia](List of file signatures - Wikipediacontains the signature of different types of file. We notice that FF D8 FF D8
is the signature of the .jpg
file. Let’s add this at the beginning of our payload.
5. Remote code execution:
From the source code we can also find that the directory storing the uploaded file: ./user_feedback_submissions/
and the name of the file will get a data prefix: fileName = date('ymd') . '_' . basename(_FILES["uploadFile"]["name"]);
Knowing this, we can visit the payload and execute our code. The flag is then obtained.