严正声明:本文仅限于技术讨论与学术学习研究之用,严禁用于其他用途(特别是非法用途,比如非授权攻击之类),否则自行承担后果,一切与作者和平台无关,如有发现不妥之处,请及时联系作者和平台
翻译:ForrestX386
预估稿费:100RMB
投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿
0x00 前言
有时候,通过正则表达式来对字符串进行白名单过滤并不好使。本文通过例子演示正则表达式在对字符串进行白名单过滤的时候可能引发OSCI(Operating System Command Injection)漏洞。
0x01 正文
测试代码如下:
<?php
$file_name = $_GET["path"];
if(!preg_match("/^[/a-zA-Z0-9-s_]+.rpt$/m", $file_name)) {
echo "regex failed";
} else {
echo exec("/usr/bin/file -i -b " . $file_name);
}
?>
咋一看这段代码好像没什么问题,就是匹配文件名由字母、数字、下划线、破则号、斜杠、空白字符各种组合的并且后缀名是rpt的文件,如果匹配成功,就执行系统命令file打印文件的类型和编码信息,如果匹配失败就打印’regex failed’.
刚开始的时候,我也是尝试了各种attack payload,但是都没有成功进行命令注入,后来我才发现原来攻击点在s这正则过滤上,s 意思是匹配任何空白字符,何为空白字符,就是常见的[trnf] (Tab、回车、换行、换页)等特殊字符,这里换行符就很危险,换行符在其他场景可能没有风险,但是在shell环境下,就有可能造成命令注入,看看下面这段payload
file%0Aid%0A.rpt
%0A是URL编码后的换行符,显然这段payload 匹配上述正则,当这段payload在shell环境中执行,会发生什么呢?
为什么会这样呢。因为在shell环境中多个命令的分隔符除了;之外还有换行符,上述payload 传入shell之后,就变成两条命令执行:
file -i -b file%0A
id%0A
.rpt
所以就出现了打印id 命令执行的内容
那么如何解决呢,很好办,把s替换成” ” (space)就ok了
是不是以为这样修改就万事大吉了? 年轻人,too young too simple,看看下面的payload
file.rpt%0aid
看看执行后会是什么鬼?
很意外吧,命令注入成功,我们来看看什么原因导致了
注意到正则表达式结尾的/m 了,在php中,/m表示开启多行匹配模式,开启多行匹配模式之后^和$的含义就发生了变化,没开启多行模式之前(即单行匹配模式), ^ 和$ 是匹配字符串的开始和结尾,开启多行模式之后,多行模式^,$可以匹配每行的开头和结尾,所以上述payload里面含有换行符,被当做两行处理,一行匹配OK即可,所以进入了exec执行分支,进而导致命令执行。
0x02 总结
所以,当我们在使用正则表达式构建白名单的时候,一定要小心一些,尤其涉及到命令执行的时候,有时候,白名单越明确越好,比如遇到类似上述场景,我们可以定义一些完整的被允许的文件名,而不是用正则表达式。