小白的代码审计之路
此文由猪八戒SRC,代码审计小鲜肉“呆呆的骗子大婶”倾情奉献~欢迎勾搭!
7798f30d6353962e61cc76a7c8bbc46c.jpg (19.55 KB, 下载次数: 82)
2017-4-18 09:50 上传一、代码审计命令注入
PHP自带的函数中提供了几个可以执行系统命令的函数,在web项目的开发中一般是不会用到的,但有些程序员为了更简洁的操作,使用了这些函数就会导致一些安全问题的发生。可以执行系统命令的常见函数有:system、exec、passthru、shell_exec、popen、proc_open、pcntl_exec。下面将分别进行介绍:
string system(string $command [, int &$return_var ]):执行外部程序,并且显示输出.含有两个参数,command为要执行的命令。return_var为可选,如果提供此参数,则外部命令执行后的返回状态将会被设置到此变量中。
string exec(string command, string [array], int [return_var]):执行外部程序,但不直接输出结果。返回字符串只是外部程序执行后返回的最后一行。
string passthru(string command, int [return_var]):本函数类似exec()用来执行 command 指令,并输出结果。
string shell_exec ( string $cmd ):执行命令并返回完整的输出为一个字符串,功能跟反引号类似。
resource popen ( string $command , string $mode ):打开进程文件指针,command 为要执行的命令,mode为规定连接模式。与proc_open类似。
bool pcntl_exec ( string $path [, array $args [, array $envs ]] )以指定的参数执行程序,当发生错误时返回 FALSE ,没有错误时没有返回。
因此在不需要的web项目中应禁用掉这些危险函数,可以通过php.ini配置文件的disable_functions项来禁用。如果确实需要使用,可以根据情况使用escapeshellarg和escapeshellcmd来过滤一些元字符来,配合保证安全。
二、代码执行注入
代码执行注入不同于命令注入,它是把用户请求的参数注入到应用中最终到webserver去执行的。一个执行的是系统命令,一个执行的是PHP命令。
容易出现此类问题的函数有eval()、assert()、preg_replace()、call_user_func()、call_user_func_array()、array_map()等。
eval和assert函数都是把变量中的值当成PHP代码执行。因此当传递给此函数的变量可控,并且未做严格处理,就可能导致代码执行。
call_user_func和call_user_func_array函数本来的功能是调用函数,比如框架开发中动态的调用函数处理传递的值等。
array_map函数将用户自定义函数作用到数组中的每个值上,并返回用户自定义函数作用后的带有新值的数组。
preg_replace函数通过正则进行字符串处理,但当正则包含了修饰符e并且存在可控参数时可造成代码执行。
因此当使用这些函数的时候应尽量不使用可控参数,如需要使用应根据业务场景严格限制可控参数。代码执行示例如图:
04567c379796b854b10ddacc01a7c4cf.jpg (19.67 KB, 下载次数: 71)
2017-4-18 09:50 上传三、xss漏洞
xss漏洞及跨站脚本攻击,相信大家都不陌生,都是因为外部提交的参数中含有恶意的js代码。后端接收后并未严格的处理就返回给了客户端、输出到页面或存入数据库中造成的。利用场景主要还是在获取用户cookie上,其实前端能做的事,xss都能做。(经常xss漏洞,开发人员都会问,你谈个框出来有什么危害,有没有!~~)
在用框架开发PHP项目中,大多数人都会写一个统一的过滤函数,然后在每次取参数时进行调用后,再赋值给变量。一些没有太多复杂交互的网站也会用全局过滤配置。这样取出来的值就是已经被过滤了的。
下面以ThinkPHP为例,说一说全局过滤,如图,当我们访问一个ThinkPHP开发的web时,会先执行index.php中的代码,index.php中引入了ThinkPHP.php文件,我们找到此文件。
e895fdcac1ba09882a3c61441f0d3937.jpg (14 KB, 下载次数: 57)
2017-4-18 09:50 上传在ThinkPHP文件加载了系统常量定义等等之后,最后一行初始化了我们的应用。
6530194317e4e104eadf90c6453937c6.jpg (20.66 KB, 下载次数: 68)
2017-4-18 09:51 上传
Start()静态方法会加载一些应用配置文件中的信息之后,在最后一行,开始运行应用。
4b3fbeb25d8993549ff21ac6f47aab3d.jpg (20.89 KB, 下载次数: 70)
2017-4-18 09:51 上传在run方法的开头,首先调用了init()初始方法。
ef3cc0e4bb88a50c19b2f036eb30963c.jpg (34.07 KB, 下载次数: 80)
2017-4-18 09:51 上传然后在init方法中,有如下一段代码,它会首先判断REQUEST_VARS_FILTER配置是否为真,为真的情况下,就会把所有接收的参数一个一个取出来用think_filter函数来进行过滤。
3cfca34307b81557c327f0c8f9de462f.jpg (13.84 KB, 下载次数: 67)
2017-4-18 09:51 上传think_filter是写在ThinkPHP/Common目录下的function.php文件中的。
cc18edec0035d977dbde6e3eac8e96eb.jpg (19.09 KB, 下载次数: 63)
2017-4-18 09:51 上传因此在做全局过滤的时候,大多会在此单独写一个方法来做全局过滤。
在ThinkPHP中还有如下几种常用过滤方式,第一、二种都是调用的框架函数来获取传递的参数值,不同的是一个是指定函数进行过滤,一个是读取配置文件中指定的函数来过滤,如果没有就不过滤,第三种就是常规过滤了。
e932e41d1375d11058236103e74deeb0.jpg (5.14 KB, 下载次数: 68)
2017-4-18 09:51 上传其中框架I方法能过滤的原因就在于ThinkPHP/Common目录下的function.php文件中定义了一个I方法,并且在获取前端传递的值时,判断是否传递了过滤函数名,如果有就取此函数名,如果没有就取配置文件中函数名来进行过滤。
efc20ea3669db636fbb06fcbfdf4c541.jpg (17.28 KB, 下载次数: 53)
2017-4-18 09:51 上传在了解了这些之后,我们才能更好的定位是否存在参数未过滤的情况,至于怎么才算完整过滤,和各种绕过技巧之类的网上已有很丰富的文章~~~~就不再献丑了。
四、本系列后续文章
1、代码审计之SQL注入
2、其他待定
下期文章:5月上旬
往期文章:请关注公众号查看
留言互动:我们将从留言中选出点赞数最高的3条,在下一期技术文章中公布,并送上精美礼物一份。欢迎参与留言点赞哦!上期技术文章留言点赞数最高三位如下:
没见了
如梦幻泡
影渔夫
ce4a608fce0a97a18c1e36866c27d7e1.jpg (20.75 KB, 下载次数: 54)
2017-4-18 09:51 上传