PHP 代码审计(一)

释放双眼,带上耳机,听听看~!


点击上方“凌天实验室”,“星标或置顶公众号”

漏洞、技术还是其他,我都想第一时间和你分享


0x01

代码审计(Code audit)


代码审计是一种以发现程序中的错误、安全漏洞、违反程序规范为目标的源代码分析。软件代码审计是对编程项目中源代码的全面分析,旨在发现错误,安全漏洞或违反编程约定。它是防御性编程范例的一个组成部分,它的主要目的是在软件发布之前减少存在的错误或安全隐患。


 0x001.代码审计方法 


代码审计常见方法分静态代码分析动态代码调试


静态代码分析是指在不运行代码的方式下,通过词法分析、语法分析、控制流、数据流分析等技术对程序代码进行扫描,验证代码是否满足规范性、安全性、可靠性、可维护性等指标的一种代码分析技术。目前静态分析技术向模拟执行的技术发展以能够发现更多传统意义上动态测试才能发现的缺陷,例如符号执行、抽象解释、值依赖分析等等并采用数学约束求解工具进行路径约减或者可达性分析以减少误报增加效率。


动态代码分析是在静态分析的基础上,将代码运行起来通过动态调试的方式,分析代码处理流程、语法、控制流、数据流处理等,验证代码是否满足规范性、安全性、可靠性、可维护性等指标的一种代码分析技术。目前越来越多的的代码审计工具都在向自动化动态调试方向发展。


[×]ASP  [√]ASP.NET  [√]PHP  [√]Java ……



ASP (VBScript | Active Server Pages)

ASP即Active Server Pages,是Microsoft公司开发的服务器端脚本环境,可用来创建动态交互式网页并建立强大的web应用程序。


ASP.NET (C# | Active Server Pages +)

Aspx文件是微软的在服务器端运行的动态网页文件,属于ASP.NET技术。[1] ASP.NET是由微软在·NET Framework框架中所提供,开发Web应用程序的类库,封装在System.Web.dll文件中,显露出System.Web命名空间,并提供ASP.NET网页处理、扩充以及HTTP通道的应用程序与通信处理等工作,以及Web Service的基础架构。ASP.NET是ASP技术的后继者,但它的发展性要比ASP技术强大许多!


PHP ( Hypertext Preprocessor)

PHP是在服务器端执行的脚本语言,与C语言类似,是常用的网站编程语言。PHP独特的语法混合了C、Java、Perl以及 PHP 自创的语法。


Java ()

Java是面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。


要学好WEB代码审计首先要掌握以下几点

编程语言的特性和基础

WEB前端编程基础

漏洞形成原理

代码审计思路

不同系统、中间件之间的特性差异


 0x002.WEB应用层漏洞主要包括以下几类 



 0x003.大分类中包含的漏洞类型 


1.认证机制


敏感数据明文传输 , 后台存在默认密码 , 新用户使用默认密码 , 账户无错误锁定机制 , 认证绕过 , 认证重放攻击 , 认证弱口令 , 不安全的验证码 , 验证码前端校验 , 暴力破解 , 用户名/账户可以枚举 , HTTP认证泄露漏洞


2.会话管理


CSRF漏洞 , SSRF漏洞 , 无会话超时设置 , 会话标识未失效漏洞 , 会话固定攻击 , URL重定向漏洞


3.数据校验


XSS跨站脚本攻击-存储型 , XSS跨站脚本攻击-反射型 , SQL注入 , CRLF注入 , XML注入 , ORM注入 , HTTP响应头注入 , XXE外部实体注入 , 本地文件包含漏洞 , 远程文件包含漏洞 , 文件上传漏洞 , 未验证上传文件类型


4.通信安全


未使用加密传输协议 , 通过未加密信道发送敏感数据


5.业务流程安全


越权漏洞 , 用户未授权访问 , 后台管理系统未授权访问 , 绕过原密码修改密码 , 任意重置用户密码 , 批量重置所有用户密码 , 修改任意用户信息 , 支付逻辑漏洞 , 恶意注册用户 , 注册覆盖 , 手机号/用户名爆破 , 验证码重放攻击 , 手机验证码暴力破解 , 短信验证码泄露 , 验证码无绑定 , 验证码不唯一 , 短信轰炸 , 邮件轰炸 , 密保答案泄露 , 不安全的Sessionid机制


6.敏感信息保护


内部IP泄露 , 数据库明文存储 , 注释敏感信息泄露 , 文件内泄露敏感信息 , 站点的绝对路径泄露


7.框架漏洞


Struts2代码执行漏洞 , jBoss远程执行漏洞 , Thinkphp命令执行 , SpringMVC命令执行漏洞 , Django命令执行漏洞 , Java反序列化任意命令执行漏洞 , 编辑器漏洞


0x02

 PHP 代码审计工具


 0x001. PHP 代码调试 


搭建调试环境必要软件工具列表



1.IDE 用于代码编写及调试



PHPStorm 用于PHP代码编写调试, Phpstorm是大多数PHP程序员们爱不释手的一款编码集成开发工具。它支持所有PHP语言功能, 提供最优秀的代码补全、重构、实时错误预防等等功能


2.PHP 运行环境



  • mamp (MacOS) 链接:https://www.mamp.info/en/

  • PHPStudy(CentOS、Ubuntu、Debian、Fedora、Deepin) 

    链接: http://phpstudy.php.cn/


3.WEB 容器的选择


  • Apache or Nginx WEB服务环境

  • 参考: https://cloud.tencent.com/developer/news/233604


4.Debug 调试模块安装配置


<?php 

$x = 5985;

var_dump($x);

echo “<br>”; 

$x = -345; // 负数

var_dump($x);

echo “<br>”; 

$x = 0x8C; // 十六进制数

var_dump($x);

echo “<br>”;

$x = 047; // 八进制数

var_dump($x);

?>


  • Zend-debugger https://www.jetbrains.com/help/phpstorm/configuring-zend-debugger.html

  • Xdebug https://www.jetbrains.com/help/phpstorm/configuring-xdebug.html


 0x002. 常见的代码审计辅助工具 


1.Fortify SCA



可分析 C/C++, C#, ColdFusion, Java, PHP, PL/SQL, T-SQL, XML, VB.NET and other 等多种语言,其内置了5大分析引擎:


* 数据流:检测用户输入流是否在程序执行中产生危害,如检测用户输入的数据是否用来构建SQL语句进行SQL注入

* 控制流: 检测程序执行流程中可能存在的危险操作

* 语义: 检测可能引发危险函数、或api调用的情况

* 结构: 检测危险的程序定义,如函数调用变量定义等

* 配置: 检测配置是否合理,如是否存在硬编码等相关配置风险


2.RIPS



RIPS是一个用 PHP 编写的源代码分析工具,它使用静态分析技术,通过自动化分析 PHP 源代码潜在的安全漏洞。渗透测试人员可以直接容易的审阅分析结果,而不用审阅整个程序代码。


RIPS 有以下优点:


1) 能够检测XSS、SQL注入、文件泄露、本地/远程文件包含、远程命令执行以及更多种类型的漏洞。

2) 有5种级别选项用于显示以及辅助调试扫描结果。

3) 标记存在漏洞的代码行。

4) 对变量高亮显示。

5) 在用户定义函数上悬停光标可以显示函数调用。

6) 在函数定义和调用之间灵活跳转。

7) 详细列出所有用户定义函数(包括定义和调用)、所有程序入口点(用户输入)和所有扫描过文件(包括include的文件)。

8) 以可视化的图表展示源代码文件、包含文件、函数及其调用。

9) 仅用几个鼠标点击就可以使用CURL创建针对检测到漏洞的EXP实例。

10) 详细列出每个漏洞的描述、举例、PoC、补丁和安全函数。

11) 7种不同的语法高亮显示模式。

12) 使用自顶向下或者自底向上的方式追溯显示扫描结果。

13) 一个支持PHP的本地服务器和浏览器即可满足使用需求。

14) 正则搜索功能。


RIPS 下载:https://sourceforge.net/projects/rips-scanner/


3.Seay源代码审计工具



Seay源码审计工具是基于规则检索的代码审计,可自定义分析插件,主要通过规则识别匹配进行检测,如结合数据库日志分析可提高检测准确率


下载地址: https://www.jb51.net/softs/199462.html


4.VCG(Visual Code Grepper)



VCG是一个基于字典的自动化源代码扫描工具,可以由用户自定义需要扫描的数据。它可以对源代码中所有可能存在风险的函数和文本做一个快速的定位。而且VCG是一个只有800多KB的一个代码审计工具


VCG 下载:http://sourceforge.net/projects/visualcodegrepp/


5.其他常见代码分析工具或脚本列表



内容地址: https://github.com/ver007/php-static-analysis-tools


6.结合AST和数据流跟踪分析代码 python 实现


内容地址: https://github.com/lcatro/PHP_Source_Audit_Tools

 

0x03

PHP 代码审计基础


 0x001. 参数接收及调用 


1.参数接收示例


PHP 数据接收常见方法、超全局变量:


register_globals , $GLOBALS , $_SERVER , $_ENV , $_FILES 

$_GET , $_POST , $_COOKIE , $_REQUEST , $_SESSION , php://? , $argv $argc


register_globals 配置项 – 注册全局变量的配置项


register_globals  存在于 php.ini  文件内,其功能用于注册以下为全局变量:

(Environment  环境变量,GET  信息, POST  信息, Cookie  信息, Server  信息)


$GLOBALS — 引用全局作用域中可用的全部变量


<?php

$var_test=’www.google.cn’;

echo $GLOBALS[‘var_test’];


<!– 结果将打印为:–>

www.google.cn


  • 一个包含了全部变量的全局组合数组。

  • 变量的名字就是数组的键 $var_test ‘var_test ‘

  • 即出现过的全局变量,就可以通过$GLOBALS这个数组取得。

  • PHP生命周期中,定义在函数体外部的所谓全局变量,函数内部是不能直接获得的。


$_SERVER — 服务器和执行环境信息


  • $_SERVER  是一个包含诸如头信息(header )、路径(path )和脚本位置(script locations )的数组。它是 PHP 中一个超级全局变量,我们可以在 PHP 程序的任何地方直接访问它。


$_SERVER[‘HTTP_HOST’]  请求头信息中的Host内容,获取当前域名。

$_SERVER[“SERVER_NAME”]  输出配置文件httpd.conf中的ServerName,一般情况下与HTTP_HOST值相同,但如果服务器端口不是默认的80端口,或者协议规范不是HTTP/1.1时,HTTP_HOST会包含这些信息,而SERVER_NAME不一定包含。(主要看配置文件的设置)。

$_SERVER[“HTTP_USER_AGENT”]  获取用户相关信息,包括用户浏览器、操作系统等信息。

$_SERVER[‘HTTP_ACCEPT’]  当前请求的ACCEPT头部信息。

$_SERVER[“HTTP_ACCEPT_LANGUAGE”]  这个值是由浏览器发送,表明用户默认的语言设置,后面的q值表示用户对该语言的喜好程度。

$_SERVER[“HTTP_ACCEPT_ENCODING”]  大部分的现代浏览器都支持gzip压缩,并会把这一信息报告给服务器。这时服务器就会压缩过的HTML发送给浏览器。这可以减少近80%的文件大小,以节省下载时间和带宽。

$_SERVER[“HTTP_COOKIE”]  浏览器的cookie信息。

$_SERVER[“HTTP_CONNECTION”]  当前请求的连接情况。

$_SERVER[“HTTP_UPGRADE_INSECURE_REQUESTS”]  表示浏览器可读懂服务器发过来的请求,

$_SERVER[“HTTP_CACHE_CONTROL”]  表示浏览器是否会缓存这个页面信息。

$_SERVER[“PATH”]  当前脚本所在文件系统。

$_SERVER[“SystemRoot”]  当前服务器的操作系统。

$_SERVER[“COMSPEC”]  指向cmd.exe的路径。

$_SERVER[“PATHEXT”]  环境变量设置。

$_SERVER[“WINDIR”]  脚本指向的系统目录。

$_SERVER[“SERVER_SIGNATURE”]  包含服务器版本和虚拟主机名的字符串。

$_SERVER[“SERVER_SOFTWARE”]  服务器软件配置信息。

$_SERVER[“SERVER_ADDR”]  当前运行脚本的服务器的ip地址。

$_SERVER[“SERVER_PORT”]  服务器端口。

$_SERVER[“REMOTE_ADDR”]  浏览网页的用户ip。

$_SERVER[“DOCUMENT_ROOT”]  当前运行脚本所在的根目录。

$_SERVER[“REQUEST_SCHEME”]  服务器通信协议,是http或https。

$_SERVER[“CONTEXT_PREFIX”]  前缀。

$_SERVER[“CONTEXT_DOCUMENT_ROOT”]  当前脚本所在的文档根目录。

$_SERVER[“SERVER_ADMIN”]  服务器管理员信息。

$_SERVER[“SCRIPT_FILENAME”]  当前执行脚本的绝对路径。

$_SERVER[“REMOTE_PORT”]  用户连接到服务器时所使用的端口。

$_SERVER[“GATEWAY_INTERFACE”]  服务器使用的CGI规范的版本。

$_SERVER[“SERVER_PROTOCOL”]  请求页面时通信协议的名称和版本。

$_SERVER[“REQUEST_METHOD”]  请求提交数据的方式。

$_SERVER[“QUERY_STRING”]  服务器请求时?后面的参数。

$_SERVER[“REQUEST_URI”]  当前脚本路径,根目录之后的目录。

$_SERVER[“SCRIPT_NAME”]  当前脚本的路径。这在页面需要指向自己时非常有用。

$_SERVER[“PHP_SELF”]  当前正在执行脚本的文件名。

$_SERVER[“REQUEST_TIME”]  得到请求开始时的时间戳。


$_ENV — 服务器和执行环境信息



  • $_ENV  数组中的内容是在php解析器运行时,从php所在服务器中的环境变量信息转变为php全局变量信息。


$_FILES — $HTTP_POST_FILES (已弃用) HTTP 文件上传变量


<html>

<body>

    <form action=”upload.php” method=”post” enctype=”multipart/form-data”>

        <label for=”file”>文件上传:</label>

        <input type=”file” name=”file” id=”file” />

        <input type=”submit” name=”submit” value=”Submit” />

    </form>

</body>

</html>


<?php 

if (isset($_FILES)){

    if ($_FILES[“file”][“error”] > 0) {

      echo “错误: ” . $_FILES[“file”][“error”] . “<br />”;

    } else {

      echo “文件名: ” . $_FILES[“file”][“name”] . “<br />”;

      echo “文件类型: ” . $_FILES[“file”][“type”] . “<br />”;

      echo “文件大小: ” . ( $_FILES[“file”][“size”] / 1024) . ” Kb<br />”;

      echo “临时文件名: ” . $_FILES[“file”][“tmp_name”];

    }

}



  • 通过 HTTP POST  方式上传到当前脚本的项目的数组

  • $HTTP_POST_FILES  包含相同的信息,但它不是一个超全局变量

  • 注意 $HTTP_POST_FILES  和 $_FILES  是不同的变量,PHP 处理它们的方式不同

  • $_FILES  数组基本内容如下:


`$_FILES[‘myFile’][‘name’]` 客户端文件的原名称,

`$_FILES[‘myFile’][‘type’]` 文件的 MIME 类型,需要浏览器提供该信息的支持,例如`”image/gif”`

`$_FILES[‘myFile’][‘size’]` 已上传文件的大小,单位为字节

`$_FILES[‘myFile’][‘tmp_name’]` 文件被上传后在服务端储存的临时文件名,一般是系统默认


  • 可以在php.ini  upload_tmp_dir  指定,但 用 putenv()  函数设置是不起作用的, $_FILES[‘myFile’][‘error’]  和该文件上传相关的错误代码。[‘error’ ]  是在 PHP 4.2.0 版本中增加的。


$_GET 请求参数存储变量


  • $_GET是我们最常用的获取GET数据的方式,对URL进行编码处理,如urldecode ,可以解析所有从URL中传入的参数


$_POST 请求参数存储变量


  • $_POST 也是我们最常用的获取POST数据的方式,它是以关联数组方式组织提交的数据,并对此进行编码处理,如urldecode,甚至编码转换,识别的数据类型是PHP默认识别的数据类型 application/x-www.form-urlencoded

  • 无法解析如text/xml application/json 等非 application/x-www.form-urlencoded 数据类型的内容


HTTP_RAW_POST_DATA (PHP7 移除)


  • 前面说过PHP默认识别的数据类型是application/x-www.form-urlencoded  ,用Content-Type=application/json 类型,提交的POST数据这时候 $_POST 就无法获取到了,但是使用 $GLOBALS[‘HTTP_RAW_POST_DATA’]   可以获取到。因为在PHP无法识别Content-Type的时候,就会把 POST 数据填入到 $HTTP_RAW_POST_DATA 中。

  • 需要设置 php.ini 中的 always_populate_raw_post_data 值为 On 才会生效

  • 当$_POST 与php://input  可以取到值时 $HTTP_RAW_POST_DATA 为空

  • 不能用于 enctype=”multipart/form-data” 

  • PHP7中已经移除了这个全局变量,用 php://input 替代


$_COOKIE — $HTTP_COOKIE_VARS [已弃用] — HTTP Cookies


  • 引用 http://php.net/manual/zh/reserved.variables.cookies.php

  • 通过 HTTP Cookies  方式传递给当前脚本的变量的数组。

  • $HTTP_COOKIE_VARS  包含相同的信息,但它不是一个超全局变量。

  • (注意 $HTTP_COOKIE_VARS $_COOKIE  是不同的变量,PHP 处理它们的方式不同)4.1.0 引入 $_COOKIE  ,弃用$HTTP_COOKIE_VARS 


$_REQUEST — HTTP Request 变量


  • 默认情况下包含了$_GET   $_POST  $_COOKIE  的数组。

  • 5.3.0 引入request_order   。该指令会影响 $_REQUEST   的内容。

  • 4.3.0 $_FILES   信息被从 $_REQUEST   中移除。

  • 4.1.0 引入 $_REQUEST


$_SESSION — Session 变量


<?php

// 会向服务器注册用户的会话

session_start();

if(isset($_SESSION[‘views’]))

  $_SESSION[‘views’]=$_SESSION[‘views’]+1;

else

  $_SESSION[‘views’]=1;

echo “Views=”. $_SESSION[‘views’];

?>



  • PHP $_SESSION 变量用于存储有关用户会话的信息,或更改用户会话的设置。Session 变量保存的信息是单一用户的,并且可供应用程序中的所有页面使用。


php://* 用于访问各种输入输出流


  • php://input 是个可以访问请求的原始数据的只读流。POST 请求的情况下,最好使用 php://input 来代替 $HTTP_RAW_POST_DATA ,因为它不依赖于特定的 php.ini 指令。而且,这样的情况下$HTTP_RAW_POST_DATA 默认没有填充, 比激活always_populate_raw_post_data 使用的内存更少。enctype=”multipart/form-data”  的时候 php://input 是无效的

  • 其他支持的协议: php://output, php://stdin, php://stdout, php://stderr, php://input, php://fd, php://filter, php://temp, php://memory

  • php://*  不需要任何特殊的 php.ini 配置

  • 不能用于 enctype=”multipart/form-data”

  • 参考资料: https://www.php.net/manual/zh/wrappers.php.php


PHP 其他支持的协议和封装协议


file://    http://    ftp://

zlib://    data://    glob://

phar://    ssh2://    rar://

ogg://     expect://


参考资料: https://www.php.net/manual/zh/wrappers.php


$argv $argc 终端传递给脚本的参数


<?php

var_dump($argc);

var_dump($argv);



  • 使用以上变量需在 php.ini  中对 register_argc_argv  进行设置且必须重启服务

  • register_argc_argv  该设置只对 $argv  和 $argc  这两个变量有影响

  • register_argc_argv  该设置仅限命令行使用

  • getopt() –  从命令行参数列表中获取选项

  • 参考: https://www.php.net/manual/zh/function.getopt.php


$php_errormsg PHP 上一个错误信息


 0x002. PHP 基础知识 


1.PHP 基本类型


字符串、整数、浮点数、逻辑、数组、对象、NULL


PHP 字符串 字符串可以是引号内的任何文本。


<?php 

$x = “Hello world!”;

echo $x;


PHP 整数 整数是没有小数的数字。


整数规则:

整数必须有至少一个数字(0-9)

整数不能包含逗号或空格

整数不能有小数点

整数正负均可

可以用三种格式规定整数:十进制、十六进制(前缀是 0x)或八进制(前缀是 0)


<?php 

$x = 5985;

var_dump($x);

echo “<br>”; 

$x = -345; // 负数

var_dump($x);

echo “<br>”; 

$x = 0x8C; // 十六进制数

var_dump($x);

echo “<br>”;

$x = 047; // 八进制数

var_dump($x);

?>


PHP 浮点数 浮点数是有小数点或指数形式的数字。


<?php 

$x = 10.365;

var_dump($x);

echo “<br>”; 

$x = 2.4e3;

var_dump($x);

echo “<br>”; 

$x = 8E-5;

var_dump($x);

?>


PHP 逻辑 逻辑是 true 或 false。


<?php

$x=true;

$y=false;

if ($x){

    echo “is true”;

}  


PHP 数组 数组在一个变量中存储多个值。


<?php 

$cars=array(“Volvo”,”BMW”,”SAAB”);

var_dump($cars);


PHP 对象 对象是存储数据和有关如何处理数据的信息的数据类型。


在 PHP 中,必须明确地声明对象。

首先我们必须声明对象的类。我们在对象类中定义数据类型,然后在该类的实例中使用此数据类型:

<?php

class Car {

  var $color;

  // 实例函数

  function Car($color=”green”) {

    $this->color = $color;

  }

  // 内部函数

  function what_color() {

    return $this->color;

  }

}

?>


PHP NULL值 特殊的 NULL 值表示变量为空。也用于区分空字符串与空值数据。


<?php

$x=”Hello world!”;

$x=null;

var_dump($x);

?>


PHP 代码运算符号


  • PHP 算数运算符

  • PHP 赋值运算符

  • PHP 字符串运算符

  • PHP 递增/递减运算符

  • PHP 比较运算符

  • PHP 逻辑运算符


参考资料: http://www.w3school.com.cn/php/php_operators.asp


=== 未完待续 ===


凌天
实验室

凌天实验室,是安百科技旗下针对应用安全领域进行攻防研究的专业技术团队,其核心成员来自原乌云创始团队及社区知名白帽子,团队专业性强、技术层次高且富有实战经验。实验室成立于2016年,发展至今团队成员已达35人,在应用安全领域深耕不辍,向网络安全行业顶尖水平攻防技术团队的方向夯实迈进。


“阅读原文”我们一起穿越安百信息安全资讯平台~

本篇文章来源于微信公众号凌天实验室: 凌天实验室

人已赞赏
安全教程

如何写出让同事无法维护的代码?

2019-10-13 9:10:07

安全教程

FastJson =< 1.2.47 反序列化漏洞浅析

2019-10-13 9:11:50

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索