2023年6月21日发(作者:)
漏洞挖掘与防范(基础篇)SQL注⼊漏洞本⽂记录代码审计的学习过程。教程为《代码审计-企业级Web代码安全架构》,练习靶场为DVWA、Sqli-labs-master和Bugku。
⽬录 SQL注⼊漏洞是我们知道的最多的漏洞,原理是由于开发者在编写操作数据库代码时,直接将外部可控的参数拼接到SQL语句中,没有经过任何过滤就直接放⼊数据库引擎执⾏。 SQL注⼊是直接对数据库进⾏攻击的,通常利⽤SQL注⼊攻击⽅式有下⾯⼏种:⼀是在权限⽐较⼤的情况下,通过SQL注⼊可以直接写⼊webshell,或者执⾏系统命令等;⼆是在权限较⼩的情况下,可以通过注⼊来获得管理员的密码等信息,或者修改数据库内容进⾏⼀些钓鱼或者其他间接利⽤。
⼀、挖掘1. 普通注⼊ DVWA源代码:if( isset( $_POST[ 'Submit' ] ) ) { // Get input $id = $_POST[ 'id' ]; $id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id); $query = "SELECT first_name, last_name FROM users WHERE user_id = $id;"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query) or die( '
' . mysqli_error($GLOBALS["___mysqli_ston"]) . '' ); // Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Display values $first = $row["first_name"]; $last = $row["last_name"]; // Feedback for end user echo "
ID: {$id}"; }}// This is used later on in the page// Setting it here so we can close the database connection in here like in the rest of the source scripts$query = "SELECT COUNT(*) FROM users;";$number_of_rows = mysqli_fetch_row( $result )[0];mysqli_close($GLOBALS["___mysqli_ston"]);
First name: {$first}
Surname: {$last}
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysq DVWA 中⽤到的防御函数: mysql_real_escape_string() 函数转义 SQL 语句中使⽤的字符串中的特殊字符。 下列字符受影响: x00 n r ' " x1a 如果成功,则该函数返回被转义的字符串。如果失败,则返回 false。 语法: mysql_real_escape_string(string,connection)2. 编码注⼊(1)宽字节注⼊ sqli-labs源代码:function check_addslashes($string){ $string= addslashes($string);
return $string;}// take the variables
if(isset($_GET['id'])){$id=check_addslashes($_GET['id']);//echo "The filtered request is :" .$id . "
";//logging the connection parameters to a file for analysis.$fp=fopen('','a');fwrite($fp,'ID:'.$id."n");fclose($fp);// connectivity
mysql_query("SET NAMES gbk");$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";$result=mysql_query($sql);$row = mysql_fetch_array($result); if($row) { echo '';
echo 'Your Login name:'. $row['username']; echo "
"; echo 'Your Password:' .$row['password']; echo ""; } else
{ echo ''; print_r(mysql_error()); echo "";
}} else { echo "Please input the ID as parameter with numeric value";} sqli-labs 中⽤到的防御函数: addslashes() 对字符串进⾏反斜杠转义。
[GET] 此时,我们可以⽤宽字节注⼊,注⼊参数中带⼊%df%27,把程序中过滤的(%5c)吃掉。 使之在MySQL中运⾏的SQL语句为:select * from user where username = '運' and 1=1#' Payload: [POST] 此时,我们可以将utf-8转换为utf-16或 utf-32,例如将 ' 转为utf-16为 �'。 Payload:
宽字节注⼊防御⼿段:1) 在执⾏查询之前先执⾏set names 'gbk',character_set_client=binary设置字符集2) 使⽤mysql_set_charset('gbk')设置编码,然后使⽤mysql_real_escape_string()过滤3) 使⽤pdo⽅式,在php5.3.6及以下版本需要设置setAttribute(PDO:ATTR_EMULATE_PREPARES,false); 来禁⽤preparestatement的仿真效果
(2)⼆次urldecode注⼊ bugku源代码:if(eregi("hackerDJ",$_GET[id])) { echo("not allowed!"); exit();}$_GET[id] = urldecode($_GET[id]);if($_GET[id] == "hackerDJ"){ echo "Access granted!"; echo "flag";} 本题中⽤到的函数: urldecode(),易导致⼆次编码⽣成单引号⽽引发注⼊。 Payload: 使⽤⼩葵⼆次url编码即可,只选⼀个字母即可。
⼆、防范1. 开启gpc/rutime魔术引号通常数据污染有两种⽅式: ⼀是应⽤被动接收参数,类似于GET、POST等; ⼆是主动获取参数,类似于读取远程页⾯或者⽂件内容等。所以防⽌SQL注⼊的⽅法就是要守住这两条路。
在本书第1章第3节介绍了PHP的核⼼配置,⾥⾯详细介绍了GPC等魔术引号配置的⽅法: magic_quotes_gpc()负责对GET、POST、COOKIE的值进⾏过滤; magic_quotes_runtime()对从数据库或者⽂件中获取的数据进⾏过滤。通常在开启这两个选项之后能防住部分SQL注⼊漏洞被利⽤。
为什么说是部分呢?因为它们只对单引号(')、双引号(")、反斜杠()及空字符NULL进⾏过滤,在int型的注⼊上是没有多⼤作⽤的。PHP4.2.3以及之前的版本可以在任何地⽅设置开启,即配置⽂件和代码中,之后的版本可以在 、 以及.htaccess中开启。 2. 过滤函数和类⼏个常见的:addslashes()mysql_real_escape_string()intval()
3. PDO prepare 预编译 如果之前了解过.NET的SqlParameter或者java⾥⾯的prepareStatement,那么就很容易能够理解PHP pdo的prepare,它们三个的作⽤是⼀样的,都是通过预编译的⽅式来处理数据库查询。 我们先来看⼀段代码:dbh = new PDO("mysql:host=localhost; dbname=demo", "user", "pass");$dbh->exec("set names 'gbk'");$sql = "select * from test where name=? and password=?"$stmt = $dbh->prepare($sql);$exeres = $stmt->execute(array($name, $pass)); 上⾯这段代码虽然使⽤了pdo的prepare⽅式来处理sql查询,但是当PHP版本<5.3.6之前还是存在宽字节SQL注⼈漏洞,原因在于这样的查询⽅式是使⽤了PHP本地模拟prepare,再把完整的SQL语句发送给MySQL服务器,并且有使⽤set names 'gbk'语句,所以会有PHP和MySQL编码不⼀致的原因导致SQL注⼈,正确的写法应该是使⽤ATTR_ EMULATE_ PREPARES来禁⽤PHP本地模拟prepare,代码如下:dbh = new PDO("mysql:host=localhost; dbname=demo", "user", "pass");$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);$dbh->exec("set names 'utf8'");$sql = "select * from test where name=? and password=?"$stmt = $dbh->prepare($sql);$exeres = $stmt->execute(array($name, $pass));
4. 关键字过滤 bugku中⼀道题的源代码://过滤sql
$array = array('table','union','and','or','load_file','create','delete','select','update','sleep','alter','drop','truncate','from','max','min','order','limit');
foreach ($array as $value)
{
if (substr_count($id, $value) > 0)
{
exit('包含敏感关键字!'.$value);
}
}
//xss过滤
$id = strip_tags($id);
$query = "SELECT * FROM temp WHERE id={$id} LIMIT 1"; 本题中⽤到的函数: strip_tags() 函数剥去字符串中的 HTML、XML 以及 PHP 的标签。那么我们可以利⽤这点,在union等敏感字中间加上
等标签。 Payload:103.238.227.13:10087/?id=-1 union select 1,hash from .key
2023年6月21日发(作者:)
漏洞挖掘与防范(基础篇)SQL注⼊漏洞本⽂记录代码审计的学习过程。教程为《代码审计-企业级Web代码安全架构》,练习靶场为DVWA、Sqli-labs-master和Bugku。
⽬录 SQL注⼊漏洞是我们知道的最多的漏洞,原理是由于开发者在编写操作数据库代码时,直接将外部可控的参数拼接到SQL语句中,没有经过任何过滤就直接放⼊数据库引擎执⾏。 SQL注⼊是直接对数据库进⾏攻击的,通常利⽤SQL注⼊攻击⽅式有下⾯⼏种:⼀是在权限⽐较⼤的情况下,通过SQL注⼊可以直接写⼊webshell,或者执⾏系统命令等;⼆是在权限较⼩的情况下,可以通过注⼊来获得管理员的密码等信息,或者修改数据库内容进⾏⼀些钓鱼或者其他间接利⽤。
⼀、挖掘1. 普通注⼊ DVWA源代码:if( isset( $_POST[ 'Submit' ] ) ) { // Get input $id = $_POST[ 'id' ]; $id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id); $query = "SELECT first_name, last_name FROM users WHERE user_id = $id;"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query) or die( '
' . mysqli_error($GLOBALS["___mysqli_ston"]) . '' ); // Get results while( $row = mysqli_fetch_assoc( $result ) ) { // Display values $first = $row["first_name"]; $last = $row["last_name"]; // Feedback for end user echo "ID: {$id}"; }}// This is used later on in the page// Setting it here so we can close the database connection in here like in the rest of the source scripts$query = "SELECT COUNT(*) FROM users;";$number_of_rows = mysqli_fetch_row( $result )[0];mysqli_close($GLOBALS["___mysqli_ston"]);
First name: {$first}
Surname: {$last}$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '
' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysq DVWA 中⽤到的防御函数: mysql_real_escape_string() 函数转义 SQL 语句中使⽤的字符串中的特殊字符。 下列字符受影响: x00 n r ' " x1a 如果成功,则该函数返回被转义的字符串。如果失败,则返回 false。 语法: mysql_real_escape_string(string,connection)2. 编码注⼊(1)宽字节注⼊ sqli-labs源代码:function check_addslashes($string){ $string= addslashes($string);
return $string;}// take the variables
if(isset($_GET['id'])){$id=check_addslashes($_GET['id']);//echo "The filtered request is :" .$id . "
";//logging the connection parameters to a file for analysis.$fp=fopen('','a');fwrite($fp,'ID:'.$id."n");fclose($fp);// connectivity
mysql_query("SET NAMES gbk");$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";$result=mysql_query($sql);$row = mysql_fetch_array($result); if($row) { echo '';
echo 'Your Login name:'. $row['username']; echo "
"; echo 'Your Password:' .$row['password']; echo ""; } else
{ echo ''; print_r(mysql_error()); echo "";
}} else { echo "Please input the ID as parameter with numeric value";} sqli-labs 中⽤到的防御函数: addslashes() 对字符串进⾏反斜杠转义。
[GET] 此时,我们可以⽤宽字节注⼊,注⼊参数中带⼊%df%27,把程序中过滤的(%5c)吃掉。 使之在MySQL中运⾏的SQL语句为:select * from user where username = '運' and 1=1#' Payload: [POST] 此时,我们可以将utf-8转换为utf-16或 utf-32,例如将 ' 转为utf-16为 �'。 Payload:
宽字节注⼊防御⼿段:1) 在执⾏查询之前先执⾏set names 'gbk',character_set_client=binary设置字符集2) 使⽤mysql_set_charset('gbk')设置编码,然后使⽤mysql_real_escape_string()过滤3) 使⽤pdo⽅式,在php5.3.6及以下版本需要设置setAttribute(PDO:ATTR_EMULATE_PREPARES,false); 来禁⽤preparestatement的仿真效果
(2)⼆次urldecode注⼊ bugku源代码:if(eregi("hackerDJ",$_GET[id])) { echo("not allowed!"); exit();}$_GET[id] = urldecode($_GET[id]);if($_GET[id] == "hackerDJ"){ echo "Access granted!"; echo "flag";} 本题中⽤到的函数: urldecode(),易导致⼆次编码⽣成单引号⽽引发注⼊。 Payload: 使⽤⼩葵⼆次url编码即可,只选⼀个字母即可。
⼆、防范1. 开启gpc/rutime魔术引号通常数据污染有两种⽅式: ⼀是应⽤被动接收参数,类似于GET、POST等; ⼆是主动获取参数,类似于读取远程页⾯或者⽂件内容等。所以防⽌SQL注⼊的⽅法就是要守住这两条路。
在本书第1章第3节介绍了PHP的核⼼配置,⾥⾯详细介绍了GPC等魔术引号配置的⽅法: magic_quotes_gpc()负责对GET、POST、COOKIE的值进⾏过滤; magic_quotes_runtime()对从数据库或者⽂件中获取的数据进⾏过滤。通常在开启这两个选项之后能防住部分SQL注⼊漏洞被利⽤。
为什么说是部分呢?因为它们只对单引号(')、双引号(")、反斜杠()及空字符NULL进⾏过滤,在int型的注⼊上是没有多⼤作⽤的。PHP4.2.3以及之前的版本可以在任何地⽅设置开启,即配置⽂件和代码中,之后的版本可以在 、 以及.htaccess中开启。 2. 过滤函数和类⼏个常见的:addslashes()mysql_real_escape_string()intval()
3. PDO prepare 预编译 如果之前了解过.NET的SqlParameter或者java⾥⾯的prepareStatement,那么就很容易能够理解PHP pdo的prepare,它们三个的作⽤是⼀样的,都是通过预编译的⽅式来处理数据库查询。 我们先来看⼀段代码:dbh = new PDO("mysql:host=localhost; dbname=demo", "user", "pass");$dbh->exec("set names 'gbk'");$sql = "select * from test where name=? and password=?"$stmt = $dbh->prepare($sql);$exeres = $stmt->execute(array($name, $pass)); 上⾯这段代码虽然使⽤了pdo的prepare⽅式来处理sql查询,但是当PHP版本<5.3.6之前还是存在宽字节SQL注⼈漏洞,原因在于这样的查询⽅式是使⽤了PHP本地模拟prepare,再把完整的SQL语句发送给MySQL服务器,并且有使⽤set names 'gbk'语句,所以会有PHP和MySQL编码不⼀致的原因导致SQL注⼈,正确的写法应该是使⽤ATTR_ EMULATE_ PREPARES来禁⽤PHP本地模拟prepare,代码如下:dbh = new PDO("mysql:host=localhost; dbname=demo", "user", "pass");$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);$dbh->exec("set names 'utf8'");$sql = "select * from test where name=? and password=?"$stmt = $dbh->prepare($sql);$exeres = $stmt->execute(array($name, $pass));
4. 关键字过滤 bugku中⼀道题的源代码://过滤sql
$array = array('table','union','and','or','load_file','create','delete','select','update','sleep','alter','drop','truncate','from','max','min','order','limit');
foreach ($array as $value)
{
if (substr_count($id, $value) > 0)
{
exit('包含敏感关键字!'.$value);
}
}
//xss过滤
$id = strip_tags($id);
$query = "SELECT * FROM temp WHERE id={$id} LIMIT 1"; 本题中⽤到的函数: strip_tags() 函数剥去字符串中的 HTML、XML 以及 PHP 的标签。那么我们可以利⽤这点,在union等敏感字中间加上
等标签。 Payload:103.238.227.13:10087/?id=-1 union select 1,hash from .key
发布评论