珂兰寺小课堂|PHP代码审计(一)

代码审计(code audit)是一种通过分析源代码来发现程序错误、安全漏洞和违反程序规范的技术。它属于防御性编程的一部分,旨在减少程序发布前的错误。

C和C++源代码是最常见的审计对象,因为其他高级语言如python,其底层实现依赖于c语言,经过处理后被Python封装,易受攻击的功能较少(例如,Python几乎不需要考虑边界检查函数的漏洞)。

代码审计的对象包括但不限于对windowslinux系统下的以下语言进行审核:Java,C,C#,ASP,phpjsp,.NET。

本系列代码审计文章主要针对PHP语言展开,第一课首先为大家介绍一些PHP基础知识。

PHP网页工作原理

立即学习PHP免费学习笔记(深入)”;

要学习PHP代码审计,首先需要了解PHP网页的组成部分。

  1. 语言网页类型:网页中有动态语言和静态语言,具体区别如下表所示。
动态语言 静态语言
PHP语言 html,文本文件,图片文件
需要专门的解释器才能被服务器识别 可以被服务器(如nginxapache等Web服务器)直接识别
对每个客户端的返回可能不一样 返回固定
  1. 接口协议CGI协议(公共网关接口)工作在Web服务器与Web应用程序之间,实现数据交换,使解释器和服务器能够通信。CGI处理一个请求需要fork一个进程,处理结束后关闭进程,非常浪费CPU资源。

因此,引入了FastCGI,实现了master进程和worker进程常驻,优化了效率。

Web服务器和CGI接口通过一些环境变量向CGI程序传递重要参数。以下是一些常用的CGI环境变量:

变量名 描述
CONTENT_TYPE 指示所传递信息的MIME类型。通常为application/x-www-form-urlencoded,表示数据来自HTML表单。
CONTENT_LENGTH 如果服务器与CGI程序信息的传递方式是POST,这个环境变量的值表示从标准输入STDIN中可读的有效数据的字节数。在读取输入数据时必须使用。
http_Cookie 客户机内的COOKIE内容。
HTTP_USER_AGENT 提供包含版本号或其他专有数据的客户浏览器信息。
PATH_INFO 表示紧接在CGI程序名之后的其他路径信息,常作为CGI程序的参数出现。
QUERY_STRING 如果服务器与CGI程序信息的传递方式是GET,这个环境变量的值表示所传递的信息,信息跟在CGI程序名之后,两者中间用一个问号’?’分隔。
REMOTE_ADDR 发送请求的客户机的IP地址。例如上面的192.168.1.67。这个值总是存在的,是Web客户机需要提供给Web服务器的唯一标识,可用于区分不同的Web客户机。
REMOTE_HOST 包含发送CGI请求的客户机的主机名。如果不支持查询,则无需定义此环境变量。
REQUEST_METHOD 提供脚本被调用的方法。对于使用HTTP/1.0协议的脚本,仅GET和POST有意义。
SCRIPT_FILENAME CGI脚本的完整路径
SCRIPT_NAME CGI脚本的名称
SERVER_NAME 你的WEB服务器的主机名、别名或IP地址。
SERVER_SOFTWARE 包含了调用CGI程序的HTTP服务器的名称和版本号。例如,上面的值为Apache/2.2.14(unix)
  1. 服务器:不同服务器的特点、优点和缺点如下表所示。
Web Server 特点 优点 缺点
Nginx 基于事件驱动 性能、负载均衡,稳定性高,支持热部署 /
Apache 基于进程驱动 支持几乎所有平台,组件多 系统压力大,不支持热部署
iis 最适合ASP.NET、ASP 产品相较成熟 只能运行在Windows平台

PHP核心配置

代码在不同环境下执行结果会有不同,不同版本会导致指令的变更,因此代码审计需要熟悉各个版本配置文件的核心指令,以达到以下两个基本目的:

  1. 扩展审计过程中的攻击面(访问目录,访问输出内容,数据过滤,文件处理范围,函数调用等)。
  2. 方便审计过程中调试和信息的输出(display_errors, error_reporting控制错误信息显示)。

两个主要的PHP配置文件

  • php.ini:PHP配置中的几种模式及其含义如下:
模式 含义
PHP_INI_USER 可在用户脚本(例如ini_set())或Windows注册表以及.user.ini中设定
PHP_INI_PERDIR 可在php.ini, .htAccess或httpd.conf设定
PHP_INI_SYSTEM 可在php.ini或https.conf中设定
PHP_INI_ALL 可在任何地方设定
  • .user.ini:用户自定义的小型php.ini,会影响到PHP_INI_USER, PHP_INI_PERDIR模式下的配置。除了主php.ini之外,PHP还会在每个目录下扫描.user.ini文件,且.user.ini能被动态加载,修改后不需要重启服务器。

注意,PHP的核心配置项不一定是在php.ini中设置的。

审计中常涉及的配置

  1. register_globals(在PHP5.4.0被移除):隐患是直接将用户通过GET、POST提交的参数注册为全局变量,并初始化值为参数对应的值,使参数可以在脚本中直接使用。

  2. magic_quote_gpc(PHP 5.4后被取消):开启后会对GET、POST、Cookie变量中的单引号、双引号、反斜杠以及空字符(NULL)前面加上反斜杠。隐患是若在代码层再次对单引号等进行特殊转换过滤,可能导致过滤失效。

  3. magic_quotes_runtime:与magic_quotes_gpc相同,是在单引号、双引号、反斜杠以及空字符前面加反斜杠,区别是magic_quotes_runtime是对从数据库或文件中获取的数据进行过滤。隐患是当该项开启时,若在代码层再次对单引号等进行特殊转换过滤,可能导致过滤失败。

  4. magic_quotes_sybase(PHP5.4后被取消):当magic_quotes_gpc也开启时,会覆盖掉magic_quotes_gpc的配置,同样对GET、POST、Cookie进行处理,但仅仅是把转移空字符和单引号变成双单引号(用单引号来转义单引号)。

    • Magic_quotes_sybase=0时,addslashes将对” ‘ 进行转义操作;
    • Magic_quotes_sybase=1时,addslashes将对’进行”转义操作。

    隐患是当该项与magic_quotes_gpc同时开启时,可能导致参数意外闭合。

    实例如下:

    珂兰寺小课堂|PHP代码审计(一)

    注意,%27经URL解码后为’

  5. safe_mode(PHP5.3以上的版本弃用):PHP的安全模式是一个非常重要的内嵌安全机制,能够控制一些PHP中的函数是否能够正常使用,比如system(),同时对很多文件操作函数进行权限控制,也不允许对某些关键文件进行操作,比如/etc/passwd,除非使用safe_mode_include_dir和safe_mode_exec_dir指定一个可被包含和存放了外部脚本的安全目录。

    珂兰寺小课堂|PHP代码审计(一)

    隐患是当该项开启时,如果本身敏感操作的拼接为双引号,可能导致参数意外闭合。

  6. allow_url_includeallow_url_fopen:使include()、include_once()、require()、require_once()都可以引入URL类型协议,允许其包含远程文件。

    • allow_url_fopen:是否允许将URL(如http://或ftp://)作为文件处理。
    • allow_url_include:是否允许include/require打开URL(如http://或ftp://)作为文件处理。

    隐患是从PHP5.2开始allow_url_include就默认为Off,而allow_url_fopen一直是On的。在文件包含漏洞中,会产生远程文件包含的动作,增加攻击面。

  7. open_basedir:open_basedir是PHP设置中为了防御PHP跨目录进行文件(目录)读写的方法,所有PHP中有关文件读、写的函数都会经过open_basedir的检查。将PHP所有能打开的文件限制在指定的目录树,包括文件本身。

    本指令不受安全模式打开或关闭的影响。

    隐患是虽然在PHP5.3以后很少有能够绕过open_basedir读写文件的方法,但是有很多可以绕过open_basedir的限制对其进行输出目录的绕过方法。

  8. disable_functions:可以禁止一些敏感函数的使用。

    一个目前推荐的禁用函数列表有:

    函数 作用
    dl() 载入指定参数的PHP扩展
    exec() 执行一个外部程序
    system() 执行外部程序,并且显示输出
    passthru() 同exec()函数类似,passthru()函数也是用来执行外部命令的
    proc_open() 执行一个命令,并且打开用来输入/输出的文件指针
    pcntl_exec() 在当前进程空间执行指定程序,可指定参数
    shell_exec() 通过shell环境执行命令,并且将完整的输出以字符串的方式返回
    mail() 发送邮件
    imap_open() 打开IMAP流,参数username为用户帐号。参数password为用户的密码
    imap_mail() 通过IMAP发送邮件
    putenv() 添加setting到服务器环境变量。环境变量仅存活于当前请求期间。在请求结束时环境会恢复到初始状态
    ini_set() 设置指定配置选项的值。这个选项会在脚本运行时保持新的值,并在脚本结束时恢复
    apache_setenv() 设置Apache子进程环境变量
    symlink() 建立符号连接
    link() 建立一个硬连接
  9. display_errorserror_reporting:在调试PHP时,打开错误信息,设置错误显示级别。

    隐患是敏感信息泄露。在审计中,开启错误信息显示可以更加直观地了解数据产生的错误提示,会暴露目录、绝对路径,造成sql注入的错误信息。

  10. auto_append_fileauto_prepend_file:自动在文件的尾或头处通过require引入特定的文件。

    隐患是通过上传.user.ini可能造成上传白名单扩展名的文件也能getshell。

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享