[转]php安全代码审计小结


#冷夜@upker.net
From:http://www.bhst.org & http://upker.net
文章仅为一段时间整理的笔记总结,一个分析框架,没有实例化分析

0x01 工具篇
编辑器(notepad++,editplus,UE等等,看个人习惯)
TommSearch(字符串检索) || grep
HttpProtocolDebugger(http协议调试器)
Fiddler(分析包,改包)
Seay PHP代码审计工具(php-code-audit分析辅助)
几个有趣的项目
dvwa(代码审计测试平台)
phpmvs
php security audit check
PHP Vulnerability Hunter

0x02 函数篇
addslashed()添加反斜杠
stripslashed()去掉反斜杠
get_magic_quotes_gpc() 判断是否开启gpc
expode(“.”,$array)分割成数组
is_numeric()判断是否为数字
sizeof()判断长度
trim() 去除字符串开头和末尾的空格或其他字符
system() 输出并返回最后一行shell结果。
exec() 不输出结果,返回最后一行shell结果,所有结果可以保存到一个返回的数组里面。
passthru() 只调用命令,把命令的运行结果原样地直接输出到标准输出设备上。
EscapeShellCmd(),把一个字符串中所有可能瞒过Shell而去执行另外一个命令的字符转义。这些字符在Shell中是有特殊含义的,象分号(;),重定向(>)和从文件读入 (<)等。
EscapeShellArg() 。在给定的字符串两边加上单引号,并把字符串中的单引号转义,这样这个字符串就可以安全地作为命令的参数。
用popen()函数打开进程
上面的方法只能简单地执行命令,却不能与命令交互。但有些时候必须向命令输入一些东西,如在增加Linux的系统用户时,要调用su来把当前用户换到root才行,而su命令必须要在命令行上输入root的密码。这种情况下,用上面提到的方法显然是不行的。
popen ()函数打开一个进程管道来执行给定的命令,返回一个文件句柄。既然返回的是一个文件句柄,那么就可以对它读和写了。在PHP3中,对这种句柄只能做单一 的操作模式,要么写,要么读;从PHP4开始,可以同时读和写了。除非这个句柄是以一种模式(读或写)打开的,否则必须调用pclose()函数来关闭 它。
例子1:
/* PHP中如何增加一个系统用户
下面是一段例程,增加一个名字为james的用户,
root密码是 verygood。仅供参考
*/
$sucommand = “su –login root –command”;
$useradd = “useradd “;
$rootpasswd = “verygood”;
$user = “james”;
$user_add = sprintf(“%s “%s %s””,$sucommand,$useradd,$user);
$fp = @popen($user_add,”w”);
@fputs($fp,$rootpasswd);
@pclose($fp);

require在被包含文件有错误代码时将不再往下执行
include在被包含文件有错误代码时仍然往下执行

htmlspecialchars() 函数把一些预定义的字符转换为 HTML 实体。
预定义的字符是:
& (和号) 成为 &
” (双引号) 成为 ”
‘ (单引号) 成为 ‘
< (小于) 成为 <
> (大于) 成为 >

move_uploaded_file() 函数将上传的文件移动到新位置。

extract() 函数从数组中把变量导入到当前的符号表中。
对于数组中的每个元素,键名用于变量名,键值用于变量值。
第二个参数 type 用于指定当某个变量已经存在,而数组中又有同名元素时,extract() 函数如何对待这样的冲突。
本函数返回成功设置的变量数目。
语法
extract(array,extract_rules,prefix)

parse_str() 函数把查询字符串解析到变量中. (常见于变量覆盖漏洞)
语法
parse_str(string,array)
参数 描述
string 必需。规定要解析的字符串。
array 可选。规定存储变量的数组名称。该参数指示变量存储到数组中。

针对变量指定攻击
不使用foreach遍历$_GET变量,改用$_GET[(index)]

eval() 函数把字符串按照 PHP 代码来计算。该字符串必须是合法的 PHP 代码,且必须以分号结尾。
如果没有在代码字符串中调用 return 语句,则返回 NULL。如果代码中存在解析错误,则 eval() 函数返回 false。

preg_replace 执行一个正则表达式的搜索和替换
/e参数执行代码

0x03 漏洞篇
———————————————–
[1].Sql-Injection
留意:cookie及x-forward-for,宽字节,报错注射等
挖掘漏洞参考
变量
$_GET[“”],$_POST[“”],$_COOKIE[“”], $SERVER[“”]
数据库操作函数
mysql_query()
数字型注入防范:
1.is_numeric() ctype_digit() intval()
2.str_length()确定长度
字符型注入防范:
1.mysql_real_escape_string()
2.数据库查询语句前加@防爆错
3.str_length()确定长度
———————————————–
[2].Command-Execution
函数:
system(),passthru(),popen(),exec()
数据库操作函数:
exec,system,popen,passthru,proc_open,shell_exec
执行命令管道符 % | >
测试如0 | dir c:
|| 双竖线的作用,前面语句执行错误则执行后面语句
如xx”+||+whoami+||+echo
———————————————–
[3].File-Inclusion
函数:
include(),require(),include_once(),require_once()
远程文件包含漏洞要求
allow_url_fopen() allow_url_include() file_get_contents()
绕过:zlib://和ogg://
5.2.0之后版本
data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8+ //
@eval(file_get_contents(‘php://input’)); //POST phpinfo();
配合%00截断,新版本自动转义
———————————————–
[4].CSRF
CSRF防范策略
1>验证http-referer字段
安全性低,易被伪造
2>在请求地址中添加token并验证
token可在用户登录后存放在session中,每次请求时将token从session中取出,去请求的token对比以防范CSRF
GET方式:http://url/?=token

如果一个网站接受请求地方比较多,则在每次页面加载时遍历整个dom树,在dom中每个a和form标签后加入token
但在动态页面加载后产生的html代码,则需要以硬编码的形式手工添加
这种方式安全性弱点在于,如在论坛等交互比较频繁的地方hacker可构造环境盗取token并进而构造csrf攻击
故手工关闭referer
3>在HTTP头中自定义属性并进行验证。通过XMLHttpRequest类。
通常用于Ajax方法对页面局部的异步刷新
但适应性一般,对已有的网站架构局限性较大
———————————————–
[5].XSS(Cross Site Script)
反射型与存储型
控制$_GET,$_POST,$_COOKIE 各种传入的变量
使用htmlspecialchars()函数进行基础过滤
结合CSRF实现自动化利用
———————————————–
[6].File_Upload
函数:move_uploaded_file()
变量:$_FILES
php文件上传利用form表单进行文件上传时必须为post使用multipart/form-data才能完整的传递文件数据
php利用$_FILES系统函数的相关参数与函数move_upload_file函数来实例把由$_FILES全局变量生成的临时文件移动到指定目录完成文件的上传
$_FILES[‘files’][‘name’]客户端文件的原名称
$_FILES[‘files’][‘type’]文件的MIME类型
$_FILES[‘files’][‘size’]已上传文件的大小
$_FILES[‘files’][‘tmp_name’]储存的临时文件名,一般为系统默认
$_FILES[‘files’][‘error’]该文件上传到相关的错误代码
防范方式:
1>判断MIME TYPE文件类型如$_FILES[‘files’][‘type’]==”image/jpeg”,判断文件大小,如$_FILES[‘files’][‘size’]<10000 && $_FILES[‘files’][‘size’]>100
2>指定上传文件名,如依赖时间生成hash(time).jpg等方式
3>根据文件后缀名判断文件
如file_ext=substr($filename,$strrpos($filename,’.’)+1);
注意是否可能有双扩展名,二次上传突破等逻辑问题
4>服务器尝试渲染文件等方式判断是否为图片
5>不依赖于客户端js脚本限制上传文件类型
6>白名单规则
apache服务器常见上传安全问题
1>配合.htaccess利用上传
AllOverride ALL 允许子规则覆盖父规则
.htaccess添加AddType Application/x-httpd-php .jpg
2>文件名解析漏洞
*.php.123
在.htaccess添加AddHandler php5-script .php,文件名中包含php扩展名可以php脚本执行,如x.php.jpg
.php3 .php4扩展名

0x04 配置篇
1>关注漏洞信息,及时更新版本
2>php.ini httpd.conf .htaccess文件配置
1)safe_mode相关配置
2)register_globals关闭
3)open_basedir配置,防范目录遍历
4)allow_url_fopen关闭
5)disable_functions配置
6)magic_quotes_gpc打开
7)error_reporting=E_ALL & ~E_NOTICE
8)display_errors=Off避免攻击者获取更多信息
9)expose_php=Off隐藏版本信息
3>最小化服务器其他账户权限
4>第三方安全加固软件安装
5>调用第三方安全防护文件,配置php.ini
include_path=”.:/php/includes”
auto_pretend_file=”anti-inj.php”
auto_appent_file=

0x05 思路篇
刚开始练习审计时,拿到一套源码,马上做的事情就是,丢到工具里,去扫敏感的函数,然后去一个一个的回溯它,找到入口点。但是,这样审计很浪费时间,每次都要在回溯过程中,不断的去寻找源码中定义的一些通用函数。由于不了解整个源码的流程,导致在找这些通用函数的过 程中浪费了很多的时间与精力。
所以,我重新调整了我的审计流程。在拿到源码之后,先从它开始的地方(一般是根目录下的index文件)按照执行的顺序去读代码,一直到它的初始化内容, 和基本功能实现完毕为止。这样,可以明确的了解整套源码的结构,哪一种函数文件放在哪个文件夹下;知道通用函数放在哪个文件中。这对我们在之后阅读“疑似”有问题的代码时,有很好的帮助,例如,在看到一个通用函数时,我们可以快速的切换到通用函数文件,查找这个函数的实现代码。
注:此处引用修改唐门三少文章《PHP代码审计学习总结》

0x06 小结
代码审计一如逆向工程,均需要耐心与细心。
此外,关注漏洞发布平台上最新漏洞并跟踪加以分析也是一个很快提升自己能力的方法。

来源: <http://upker.net/index.php/archives/749/>

《 “[转]php安全代码审计小结” 》 有 16 条评论

  1. 在PHP中执行系统命令
    http://php.net/manual/en/ref.exec.php
    `
    escapeshellarg — Escape a string to be used as a shell argument(将要传递给shell做参数的字符串进行转义)
    escapeshellcmd — Escape shell metacharacters(对shell命令字符串做转义)
    exec — Execute an external program(用于执行一个外部命令)
    passthru — Execute an external program and display raw output(用于执行一个外部命令并返回执行结果——可能是二进制格式)
    proc_close — Close a process opened by proc_open and return the exit code of that process(关闭由proc_open打开的进程,并返回该进程的退出状态码)
    proc_get_status — Get information about a process opened by proc_open(获取由proc_open打开的进程的相关信息)
    proc_nice — Change the priority of the current process(修改当前进程的优先级)
    proc_open — Execute a command and open file pointers for input/output(在执行一个命令的同时打开stdio/stdout的文件指针)
    proc_terminate — Kills a process opened by proc_open(杀死由proc_open打开的进程)
    shell_exec — Execute command via shell and return the complete output as a string(调用shell执行外部命令并以字符串形式返回命令输出结果)
    system — Execute an external program and display the output(用于执行一个外部命令并显示输出结果)
    `
    http://php.net/manual/en/function.system.php
    http://php.net/manual/en/function.shell-exec.php

    PHP – exec() vs system() vs passthru()
    http://stackoverflow.com/questions/732832/php-exec-vs-system-vs-passthru
    http://stackoverflow.com/questions/7093860/php-shell-exec-vs-exec
    `
    exec() is for calling a system command, and perhaps dealing with the output yourself.
    system() is for executing a system command and immediately displaying the output – presumably text.
    passthru() is for executing a system command which you wish the raw return from – presumably something binary.
    `

  2. PHP代码审计分段讲解
    https://github.com/bowu678/php_bugs
    `
    01 extract变量覆盖.php
    02 绕过过滤的空白字符.php
    03 多重加密.php
    04 SQL注入_WITH ROLLUP绕过.php
    05 ereg正则%00截断.php
    06 strcmp比较字符串.php
    07 sha()函数比较绕过.php
    08 SESSION验证绕过.php
    09 密码md5比较绕过.php
    10 urldecode二次编码绕过.php
    11 sql闭合绕过.php
    12 X-Forwarded-For绕过指定IP地址.php
    13 md5加密相等绕过.php
    14 intval函数四舍五入.php
    15 strpos数组绕过NULL与ereg正则%00截断.php
    16 SQL注入or绕过.php
    17 密码md5比较绕过.php
    18 md5()函数===使用数组绕过.php
    19 ereg()函数strpos() 函数用数组返回NULL绕过.php
    20 十六进制与数字比较.php
    21 数字验证正则绕过.php
    22 弱类型整数大小比较绕过.php
    23 md5函数验证绕过.php
    24 md5函数true绕过注入.php
    25 switch没有break 字符与0比较绕过.php
    26 unserialize()序列化.php
    `

  3. [译] 2018 PHP 应用程序安全设计指北
    https://laravel-china.org/articles/7235/2018-php-application-security-design
    https://paragonie.com/blog/2017/12/2018-guide-building-secure-php-software
    `
    前言
    PHP 版本 / PHP Versions
    Composer 依赖管理 / Dependency Management with Composer
      推荐扩展 / Recommended Packages
    HTTPS 和浏览器安全 / HTTPS and Browser Security
      安全头 / Security Headers
      子资源完整性 / Subresource Integrity
      文档关系 / Document Relationships
    开发安全的 PHP 程序 / Developing Secure PHP Software
      数据库注入 / Database Interaction
      文件上传 / File Uploads
      跨站脚本 / Cross-Site Scripting (XSS)
      跨站请求伪造 / Cross-Site Request Forgery (CSRF)
      XML 攻击 / XML attacks (XXE, XPath Injection)
      反序列化和 PHP 对象注入 / Deserialization and PHP Object Injection
      密码散列 / Password Hashing
      通用加密 / General-Purpose Cryptography
      随机性 / Randomness
      服务器端 HTTPS 请求 / Server-Side HTTPS Requests
      避免的事情 / Things to Avoid
    专业用法 / Specialized Use-Cases
      可搜索的加密 / Searchable Encryption
      没有 Side-Channels 的基于令牌的身份验证 / Token-based Authentication without Side-Channels
      开发安全的 API / Developing Secure APIs
      使用 Chronicle 记录安全事件 / Security Event Logging with Chronicle
    作者的一些话 / A Word From the Author
    资源 / Resources
    `

  4. 【技术干货】甲方代码审计之道与术
    https://mp.weixin.qq.com/s/OvuZbfk6QoKCD7OTwhxXXg
    `
    甲方代码审计的特点

    # 势在必行
    漏洞攻防从来都是不对等的,这句话曾被用来形容防守方防守的是整个面,而攻击方只需要突破单个点即可侵入。但在漏洞攻防上,防守方也有攻击方无法具备的优势:他们拥有代码。相比黑盒测试,代码审计有从代码实现逻辑的根源去挖掘漏洞的天然优势;相比教条式的修复指引,代码审计也可以从代码实现逻辑上为漏洞修复提出更有针对性、可行性的方案,甚至可以在此基础上演化出安全开发组件、框架。

    在SDLC和DevSecOps大行其道的今天,代码审计已经成为甲方开展深度防御、安全融入业务的必经之路。在此大背景下,甲方推行代码审计势在必行。

    另外,需要注意,本文所述代码审计,包括自动化代码漏洞扫描以及人工代码审计两部分。

    # 甲方代码审计与白帽子代码审计的区别

    目标与初衷导致覆盖范围、使用方法不通,不仅在于挖掘漏洞、也在于风险发现,不仅在于提供加固意见、更在于梳理研发体系为编码规范的制订与安全开发组件建设提供数据支持,不仅在于人工、更在于自动化体系建设,此外甲方代码审计强调完整覆盖面,而白帽子可能只是关注个别点,只要突破一个点即可入侵。

    审计的代码不同:甲方通常审计的是自研代码,而白帽子通常审计的是开源代码,两者在业务逻辑复杂度、编码可读性区别较大。

    代码审计方法论
    # 痛点
    1、代码与架构复杂
    2、工具准召率
    3、心态

    # 整体思路
    1、自动手动结合
    代码扫描工具->ast/正则表达式->复核
    词法分析->语法分析->(语义分析->中间代码)->AST

    2、黑白盒结合
    黑盒求覆盖->白盒求重点

    3、正反向跟踪
    • 正向:变量->函数/敏感操作->输出
    $_GET->$param->eval($param)->return $param

    • 反向:函数/敏感操作回溯->输出
    eval($param)->$param->$GET->return $param

    4、动静结合
    (1)静态审计
    (2)规则匹配
    (3)代码解析法
    (4)动态审计

    5、过往与当下结合
    • 是否采用存在漏洞的框架版本;
    • 是否出自同一个存在不良编码习惯或安全意识薄弱的开发者之手;
    • 是否出现过漏洞,可能没彻底修复或者其他业务有类似的问题;
    • 这个功能、模块、类、函数出现的漏洞是否可能出现在其他功能模块、类函数。

    6、checklist与安全编码规范结合
    梳理常见漏洞场景、常见漏洞类型、常见功能安全编码模板,对比实现方式,编码规范可以参考《OWASP安全编码规范》,相关checklist可以下一部分的内容。

    7、通读与走读结合
    类似英语阅读文章的阅读技巧,先粗略读一遍,再根据漏洞类型与业务场景跳着读。
    • 首先要看程序的大体代码结构
    • 关注框架文件、核心功能

    # 覆盖
    结合上面谈到的总体思路,下文将介绍在业务中具体落地代码审计的三大重要模块,业务基础信息、代码逻辑是基础、平台化手段是助推器、流程标准化是关键。
    1、依赖代码仓库和业务基础信息
    2、平台化建设
    3、覆盖业务范围

    # 一些Tips
    1、如何快速看懂代码
    2、业务思维
    3、如何提高准召率

    # 开源工具评测
    1、cobra
    官方版本支持php/java ast,其他语言使用正则表达式、关键词匹配的方法,但用户可通过重写扫描引擎和自定义规则进行优化。建议可以关注基于cobra二次开发的cobra-w,该工具重写了ast解析,主攻准确性。

    2、bandit
    python代码审计工具,支持ast、支持丰富的漏洞类型和报告格式、可自定义插件和报告格式。

    3、nodejsscan
    nodejs代码审计工具,使用正则表达式匹配方式,基本覆盖了nodejs常见漏洞以及nodejs开发最佳实践。

    4、gosec
    使用ast parser,支持20+漏洞类型检测,是一款比较全面的golang代码审计工具。但实际测试效果不太理想,需要进一步troubleshooting。

    5、devskim/auditjs/dependence-check/clockwalk
    这几款工具主要用于pip包、npm包和jar包的cve漏洞检测,但误报挺高,因为代码中其实有不少组件引入后并没有使用,可作为风险项进行提醒。

    # 商业工具评测
    1、CheckMarx
    2、Fortify
    3、IDE

    一些实际的case
    PHP代码审计
    js代码审计
    Python代码审计
    Golang代码审计
    `

  5. Java框架级SSM代码审计思路
    https://paper.seebug.org/1075/
    https://mp.weixin.qq.com/s?__biz=Mzg3MDAzMDQxNw==&mid=2247487592&idx=1&sn=b17808935868f9af51de882caf4d8df0
    `
    1 SSM框架简介
    1.1 SpringMVC
    1.2 Spring
    1.3 Mybatis
    1.4 Servlet

    2 SSM框架代码执行流程和审计思路
    2.1 审计的出发点web.xml
    2.2 Spring核心配置文件applicationContext.xml
    2.3 SSM之SpringMVC执行流程
    2.4 SSM之Spring执行流程
    2.5 SSM之Mybatis执行流程
    2.6 审计的重点filter过滤器

    3 SSM框架审计思路总结
    3.1 思路总结
    3.2 补充知识
    3.3 学习建议
    `

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注