Возможно слегка громкое название статьи, но вопрос поднят именно этот.
Момент первый
Если следовать всем правилам, т.е. использовать внутренние механизмы Zend, подготавливать параметры в методах — то на данный момент нет информации о возможности проведения sql-инъекции. Речь идет о подобных конструкциях:
$select->order($value);
Которые так или иначе встречаются на практике.
Момент второй
В чем же соль? В том, что даже при поступлении параметров в подобные методы без какой-либо подготовки внутренние механизмы все же их подготавливают. Только не все (а некоторые частично) — об этом и речь.
Хоть у нас и есть исходный код данной библиотеки, мы рассмотрим данную тему как «черный ящик», будет нагляднее и понятнее. Конкретнее — адаптер MySQL, класс Zend_Db_Select (тоже самое проверялось и на PgSQL)
Момент третий
Для того, чтобы провести инъекцию в Zend, нам нужно закрыть предыдущую обратную кавычку (к примеру в случае синтаксиса from = select * from `table`), или апостроф — (where id = '1'), так как Zend следует правилам и при указании параметра открывает нужное «обрамление». В первом случае, при передаче на вход tab`ble у нас на выходе должно быть ta``ble, во втором: на входе 1'2, на выходе 1''2.
Еще раз, мы ведем речь о «сырой» отправке данных методу.
У нас возможны три случая:
- FQ — все параметры подготавливаются (fully quoted)
- NQ — данные не подготавливаются, к БД все «уйдет», так, как и передали (no quoted)
- PQ — некоторые параметры проходят обработку, некоторые нет (partially quoted)
Пойдем по порядку, по порядку в синтаксисе SQL
1) ->from — FQ
Код:
$table = "wp_use`rs";
$select->from($table);
[queryString] => SELECT `wp_use``rs`.* FROM `wp_use``rs
2) ->join — PQ
$table1 = 'tab`le1';
$table2 = 'tab`le2';
$key = 'i`d';
$data = 'da`ta';
$select = $db->select()->from($table1)->join($table2, $table1.'.'.$key.' = '.$table2.'.'.$key, array($data));
[queryString] => SELECT `tab``le1`.*, `tab``le2`.`da``ta` FROM `tab``le1` INNER JOIN `tab``le2` ON tab`le1.i`d = tab`le2.i`d
3) ->joinUsing — PQ
$table1 = 'tab`le1';
$table2 = 'tab`le2';
$key = 'i`d';
$column = 'c`ol'u;m"n';
$select = $db->select()->from($table1)->joinUsing($table2, $column);
[queryString] => SELECT `tab``le1`.*, `tab``le2`.* FROM `tab``le1` INNER JOIN `tab``le2` ON `tab``le2`.c`ol'u;m"n = `tab``le1`.c`ol'u;m"n
4) ->where — NQ
$select->from($table);
$value = "1)2'3 --";
$select->where($value);
[queryString] => SELECT `wp_users`.* FROM `wp_users` WHERE (1)2'3 --)
5) ->group — FQ
$table = "wp_users";
$value = 'i`d';
$select = $db->select()->from($table)->group($value);
[queryString] => SELECT `wp_users`.* FROM `wp_users` GROUP BY `i``d`
6) ->having — NQ
$table = "wp_users";
$value = 'some_count > 0); hello habr -- 10';
$select = $db->select()->from($table)->having($value);
[queryString] => SELECT `wp_users`.* FROM `wp_users` HAVING (some_count > 0); hello habr -- 10)
7) ->order — FQ
$table = "wp_users";
$value = i`d';
$select = $db->select()->from($table)->having($value);
[queryString] => SELECT `wp_users`.* FROM `wp_users` ORDER BY `i``d` ASC
8) ->limit — FQ
Тут даже не FQ, а просто — приведение типов (к int)
$table = "wp_users";
$limit1 = '1; hello -- ';
$limit2 = '2; hello -- ';
$select = $db->select()->from($table)->limit($limit1, $limit2);
[queryString] => SELECT `wp_users`.* FROM `wp_users` LIMIT 1 OFFSET 2
Сюда же ->limitPage(), аналогичная работа
9) ->union — NQ
$db->select + string
$table = "wp_users";
$select = $db->select()->from($table);
$select2 = "select * from ta"b'le`2";
$select3 = $db->select()->union(array($select, $select2));
$db->query($select3);
[queryString] => SELECT `wp_users`.* FROM `wp_users` UNION select * from ta"b'le`2
Сводные данные
FQ: ->from, ->group, ->order, ->limit, ->limitPage
PQ: ->join, ->joinUsing
NQ: ->where, ->having, ->union
На практике не фильтруемые данные можно встретить к примеру в ajax-обработчиках.
Выводы
Я не возьмусь делать глобальных выводов, но то, что ваш инструмент может повести себя не так, как вы ожидаете — факт. Будьте бдительны ;]
P.S. Кроме всего прочего, возможно эти данные кто-нибудь возьмет к себе в CTF.
Автор: BeLove