Path to SQL Injection in Zend Framework

    Perhaps a slightly loud title of the article, but this question was raised.

    First moment


    If you follow all the rules, i.e. use internal mechanisms of Zend, prepare parameters in methods - at the moment there is no information about the possibility of sql injection. We are talking about similar designs:
    $select->order($value);
    

    Which one way or another found in practice.

    Second moment


    What is the salt? The fact is that even when parameters arrive at such methods without any preparation, internal mechanisms still prepare them. Only not all (and some partially) - this is what we are talking about.

    Although we have the source code for this library, we will consider this topic as a “black box”, it will be more clear and understandable. More specifically, the MySQL adapter, the Zend_Db_Select class (the same thing was tested on PgSQL)

    Third moment


    In order to inject Zend, we need to close the previous back quote (for example, in the case of the syntax from = select * from `table` ), or the apostrophe - ( where id = '1' ), since Zend follows the rules and specifying the parameter opens the desired "frame". In the first case, when passing tab`ble to the input , we should have ta``ble at the output , in the second: at the input 1'2 , at the output 1''2 .
    Once again, we are talking about "raw" sending data to a method.

    We have three possible cases:
    1. FQ - all parameters are prepared (fully quoted)
    2. NQ -data is not prepared, everything will "go away" to the database, as it was transmitted (no quoted)
    3. PQ - some parameters are being processed, some are not (partially quoted)


    Let's go in order, in order in the SQL syntax

    1) -> from - FQ

    The code:
    $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)->order($value);
    

    [queryString] => SELECT `wp_users`.* FROM `wp_users` ORDER BY `i``d` ASC

    8) -> limit - FQ

    It’s not even FQ, but simply type casting (to 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
    To here -> limitPage (), similar work

    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

    Summary data


    FQ: -> from, -> group, -> order, -> limit, -> limitPage
    PQ: -> join, -> joinUsing
    NQ: -> where, -> having, -> union

    In practice, non-filtered data can be found for example in ajax handlers.

    PS Besides everything else, maybe someone will take this data to himself in CTF.

    UPD: Moment 4: The article is more for pentesters, who may meet the application on Zend.

    Also popular now: