PHP 代码审计与安全编码
代码审计的目的
- 目的决定行为
- 代码审计前的准备
- 得到代码
- 开源程序
- 非开源程序(黑盒扫描)
- 得到平台信息
- php 版本及 php.ini 一些基本配置, os配置, web 服务信息, 数据库应用
- 得到代码
代码审计的本质
- 两大根本:变量与函数
- 漏洞现成的条件
- 可以控制的变量(一切输入都是有害的)
- 变量到达有利用价值的函数(一切进入函数的变量都是有害的)
函数导致的漏洞
- 文件包含 -> 包含漏洞
- 代码执行 -> 执行任意代码漏洞
- 命令执行 -> 执行任意命令漏洞
- 文件系统操作 -> 文件(目录)读写等漏洞
- 数据库操作 -> SQL注射漏洞
- 数据显示 -> XSS等客服端漏洞
- …
代码审计通用思路
- 找漏洞 -> 找对应变量与函数
- 通过变量找函数(正向跟踪变量)
- 通过函数找变量(逆向跟踪变量)
- …
补丁对比技术
- 基于源代码
- 对比工具
- 系统命令: fc; diff
- 专业工具: Beyond Compare; UltraCompare
- 常见的安全补丁方式
- 变量初始化
- 变量过滤
业务功能与漏洞
- 实现业务功能的同时引入安全风险
- 上传功能 -> 上传漏洞
- 数据存储与查询 -> SQL注入漏洞
- 后台或者 API 接口 -> 安全认证绕过
- 数据库备用 -> 导出 webshell
- 新的功能必定带来新的安全隐患
- 功能越强大说明漏洞的几率越大
相似性漏洞挖掘
- 天下武学同出少林[天下代码一把抄]
- 最经典的 asp: 动网上传漏洞
- 每个程序员都有自己的代码风格习惯
- 相同的功能带来同样的漏洞
- 寻找相似性漏洞
基于白盒的 fuzz
- 变量的储存
- 对于数据库储存查询
常用变量与函数
- 如 include/require; eval; system 等函数
高级的代码审计
- 寻找新的 “变量与函数”
PHP 代码审计漏洞发现与安全编码
注入
普通的 SQL 注入
- 字符串拼接
变量的传递与二次漏洞
- 什么是二次漏洞
- 通过一个现有漏洞,创造新的漏洞使漏洞利用最大化
<?php
highlight_file(__file__);
function dbconnection(){
@$con = mysql_connect("localhost","root","root");
if (!$con){
echo "Failed to connect to MySQL: " . mysql_error();
}
@mysql_select_db("ctf",$con) or die ( "Unable to connect to the database");
mysql_query("SET character set 'UTF8'");
}
dbconnection();
Session_start();
function reg(){
$username = addslashes($_GET['username']);
$password = addslashes($_GET['password']);
$sql = "insert into users values(null,'$username','test@test.com','$password')";
echo $sql;
mysql_query($sql);
}
function login(){
$username = addslashes($_GET['username']);
$password = addslashes($_GET['password']);
$sql = "select * from users where username='$username' and password='$password'";
echo $sql;
$result=mysql_query($sql);
if(@$row = mysql_fetch_array($result)){
//登录成功
$_SESSION['userid'] = $row['id'];
$_SESSION['username'] = $row['username'];
}
}
function insert_news(){
$content = addslashes($_GET['content']);
$username = $_SESSION['username'];
$sql = "insert into news(author,content) values('$username','$content')";
echo $sql;
mysql_query($sql);
}
function show_news(){
$sql = "select * from news";
$result=mysql_query($sql);
while(@$row = mysql_fetch_array($result)){
echo 'author:'.$row['author'].' content:'.$row['content'].'<br>';
}
}
$action = $_GET['action'];
if(in_array($action,array("reg","login","insert_news","show_news"))){
call_user_func($action);
}
SQL 注入通用防治
- 预编译
- 对类型判断
X-Forwarded-For 注入防范
- 检测 ip
XSS
CSRF
不安全的反序列化
-
php 反序列化漏洞又称对象注入,可能会导致远程代码执行。php 中执行 unserialize 函数,调用某一类并执行 magic method,之后执行类中函数,可能会产生安全问题。
-
反序列化常用的 magic method
- _destruct()
- _wakeup()
- _toString()
- _get()
- _set()
- _isset()
- _unset()
- _call()
- _invoke()
XML 外部实体 (XXE)
- 另一篇博文
- 如何修复
- 禁用外部实体
- 过滤用户提交的 xml 数据