真实渗透的经验,通过:众测,补天
利用大模型:github,魔塔 阿里
hugg
viewsource函数展示文件
调试看c语言代码
题目1 trim,非顶层
<?php
$password = trim($_REQUEST['password'] ?? '');
$name = trim($_REQUEST['name'] ?? 'viewsource');
function viewsource() {show_source(__FILE__);}
if (strcmp(hash('sha256', $password), 'ca572756809c324632167240d208681a03b4bd483036581a6190789165e1387a') === 0) {
function readflag() {
echo 'flag';
}
}
$name();
?>
顶层和非顶层
区别:
顶层函数:也叫全局函数,是指不嵌套在任何类、结构体、接口、命名空间或其他函数内部的独立函数,直接定义在程序的最外层作用域中。 非顶层函数:是指嵌套在其他代码结构内部的函数,常见形式包括类 / 对象的成员方法、嵌套函数(函数内部定义的函数)、命名空间内的函数等,依赖于外部包裹结构而存在。
# 顶层函数:直接定义在文件最外层,无任何包裹
def top_level_function():
return "这是顶层函数"
# 非顶层函数1:类的成员方法(嵌套在类内部)
class MyClass:
def non_top_level_method(self):
return "这是类内的非顶层函数(成员方法)"
# 非顶层函数2:嵌套函数(嵌套在其他函数内部)
def outer_function():
def inner_nested_function():
return "这是函数内的非顶层函数(嵌套函数)"
return inner_nested_function()
1.如何处理
2.编译执行
3.php底层在在做什么:
词法(切割),
语法分析,ast树的构建,
编译成opcode指令,将语法树转成opcode数组,
opcode包含每一个变量对应的hander(c语言函数)
4.执行调用
zend_execute_scripts:php底层虚拟机,虚拟机底层脚本
解题在编译过程和执行过程
php编译函数:zend_compile_func_decl
看关键代码部分 三个变量,返回结果,是、ast,是否是顶层函数
命名空间:命名空间不痛函数变量相同不影响,使用方法:别名/导入 例如:函数名/变量
魔术常量:魔术常量会根据使用位置而变化
php闭包(closure),匿名函数,通过closure(变量)实现即把没有名字的函数赋值给变量
is_method 有function 一般都是类方法
zend_begin_func_decl 普通函数
顶层函数
把函数名放进去
不是顶层函数:在函数编译过程中会有一个新的函数名
生成一个临时的key值
命名规范:\0,+函数名(有key加入临时生成的)+文件路径+:+函数开始行号+$+访问函数次数
php底层研究:\0+函数名称+文件绝对路径+:+函数名称行号+$+访问次数(0)
本题目解决方法:
调用key,根据底层非顶层函数命名方法命名
利用trim函数
trim 函数
清除首位的空白字符或者其他(\0\t\v\n\r)
解决方法:加上反斜杠(\)
思考1
1.通信流量 是否可以被中间人解密(无条件 直接抓包 直接解密) 不能 为什么?
不可能,通信中间人不可能拿到私钥,用的rsa非对称加密(无人能破解2)密钥加密aes对称加密(不能破解)私钥
私钥拿不到就不会有问题,不能被伪造,
服务器将公钥用sha384加密交给ca私密加密,客服端拿到后用ca公钥解密,对比两者,实现了身份认证无法篡改
客户端生成的对称密钥aes,用服务器的公钥加密,发给服务端,服务端用私钥解密中间人无法解密,安全传递给了服务端
2.wireshark 如何自动解密tls流量
2. Wireshark 自动解密 TLS 流量的核心是获取 TLS 会话的密钥材料,再通过配置密钥路径或利用会话记录实现解密,主要有 3 种方式,适用于不同场景:
方式 1:利用 Pre-Master Secret(PMS)或 Master Secret 文件(通用场景)
TLS 握手过程中会生成 Master Secret(主密钥),客户端可导出该密钥并保存为文件,Wireshark 读取后即可解密。
操作步骤:
配置客户端导出密钥
不同客户端设置方式不同,以 Chrome/Firefox 为例:
启动浏览器前,设置环境变量(Windows/Linux/macOS 通用逻辑):
bash
运行
# Linux/macOS 终端
export SSLKEYLOGFILE=/path/to/sslkey.log
# Windows cmd
set SSLKEYLOGFILE=C:\path\to\sslkey.log
启动浏览器,访问目标 HTTPS 网站,此时客户端会自动将 TLS 密钥写入 sslkey.log。
配置 Wireshark 读取密钥文件
打开 Wireshark → 点击 Edit → Preferences → Protocols → TLS。
在 (Pre)-Master-Secret log filename 处,选择刚才生成的 sslkey.log 文件 → 保存。
开始抓包(或导入已抓取的 TLS 包),Wireshark 会自动解密,Info 列会显示 Application Data 对应的明文内容。
方式 2:针对 RSA 密钥交换 场景(仅 TLS 1.2 及以下,已逐步淘汰)
如果 TLS 会话使用 RSA 非对称加密 交换密钥(非 ECDHE 等前向保密算法),可直接导入服务器的私钥解密。
操作步骤:
获取服务器的私钥文件(格式为 PEM、P12 等,如 Nginx 的 server.key)。
Wireshark 配置:Edit → Preferences → Protocols → TLS → RSA keys list → 点击 Add。
填写参数:
IP address:服务器 IP
Port:HTTPS 端口(默认 443)
Protocol:选择 http(或对应应用层协议)
Key File:选择服务器私钥文件 → 保存。
抓包后自动解密,注意:此方法对 ECDHE 等支持前向保密(FS)的算法无效。
方式 3:利用 SSLKEYLOG 环境变量(适用于本地客户端流量)
和方式 1 原理一致,本质是让客户端自动生成密钥日志,适合抓包本地浏览器、APP 的 TLS 流量,无需额外配置服务器。
关键限制:
必须能控制客户端(导出密钥)或获取服务器私钥;
对 TLS 1.3,仅支持通过 SSLKEYLOGFILE 方式解密(RSA 私钥方式无效)。
3.burpsuite 作为中间人 可以解密 满足什么条件 才可以看到抓取的明文数据?
Burp Suite 采用 Man-in-the-Middle(MITM,中间人) 攻击原理解密 TLS 流量,核心是让客户端信任 Burp 的 CA 证书,并完成 TLS 会话的代理劫持,具体需满足 4 个核心条件:
条件 1:客户端流量必须经过 Burp 代理
Burp 只能解密流经自身代理的流量,因此需要:
客户端(浏览器 / APP)的 HTTP/HTTPS 代理配置指向 Burp(默认 Burp 代理端口是 8080,即 127.0.0.1:8080);
若目标是 HTTPS 流量,客户端必须支持 HTTP CONNECT 方法(用于建立 TLS 隧道,这是 HTTPS 代理的基础)。
条件 2:客户端必须信任 Burp 生成的 CA 证书
这是最核心的条件,原理是:
Burp 作为中间人,会动态生成伪造的服务器证书(证书中的域名与目标网站一致);
该伪造证书由 Burp 自身的 CA 根证书 签名;
若客户端不信任 Burp 的 CA 根证书,会提示 “证书不安全” 并拒绝建立连接,无法完成流量劫持。
配置方法:
导出 Burp CA 证书:Burp → Proxy → Options → Import/export CA certificate → 保存为 der 或 pem 格式;
在客户端(浏览器 / 手机)中安装并信任该 CA 证书(浏览器需设为 “受信任的根证书颁发机构”)。
条件 3:目标 TLS 会话不启用证书锁定(Certificate Pinning)
证书锁定(Cert Pinning) 是客户端的安全机制:客户端内置目标服务器的证书哈希值,连接时会校验服务器证书的哈希是否与内置值一致。
如果目标 APP / 网站启用了 Cert Pinning,即使客户端信任 Burp CA,也会因 Burp 伪造的证书哈希不匹配而拒绝连接,Burp 无法劫持流量;
绕过方式:需对客户端进行逆向(如安卓 APP 反编译删除 Pinning 代码)或使用 Frida 等工具 Hook 掉 Pinning 校验函数。
条件 4:TLS 握手能正常完成(无特殊加密 / 验证机制)
排除客户端证书认证场景:如果服务端要求客户端提供证书(如金融、政务网站),Burp 需配置客户端证书才能通过校验,否则无法建立 TLS 连接;
不支持非标准 TLS 扩展:部分自定义客户端可能修改 TLS 握手流程,Burp 无法识别时会导致解密失败。
原理
如何抵御bp抓包行为
双向认证 服务端和客户端双方认证
证书绑定(服务器的公钥指纹绑定在在app上)
绕过防御bp
证书绑定绕过:frida 底层函数检查公钥,hook钩住她让他为ture
双向认证绕过: rocapture框架 app底层 把密钥拿到监听
rocapture框架:防御:vmp
app上了vmp基本上不可能绕过。中小型公司不会上这个
vmp是什么
思考:app的包,后端服务器的地址,和通讯地址,遇到什么问题
思考:分析蚁剑的流量
文件包含 主要是include(php)
include("")
包含任意文件都会被当做php代码执行,include c语言不看后缀,<?php 开始标识符
php伪协议
file://、php://filter、php://input、zip://、compress.bzip2://、compress.zlib://、data://
PHP.ini:
allow_url_fopen :off/on
allow_url_include:off/on
file://协议 文件读取
file:// 协议在双off的情况下也可以正常使用;
file访问本地协议不受上面的影响
使用方法:
file=file://文件绝对路径
php://filter协议 可以看源码
php:// 协议不需要开启或者关闭
在ctf和真实渗透中常见
php://filter 可以实现read,write
过滤器里面还可以实现编码解码
消除标签
base64编码标签
filter 可以进行文件read和write
string.strip_tags
base64
convert.base64-encode and convert.base64-decode
后面加入多个编码
convert.iconv.* 高级的技巧 CTF 大型赛事 经常出现
base64 编解码 使用
base64编码然后去根据解码
file=php://filter/read=convert.base64-encode/resource=./文件名
先用base64加密在解码
file=php://filter/read=convert.base64-decode/resource=./文件名
stri_tags 去除标签 iconv
题目:所有漏洞必须用户可控
<?php
$content = '<?php exit; ?>';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);
// base64 + string.strip_tags
// strip_tags|base64-decode
用base64编码解码只包含0-9a-z,其他的都是非法字符,四位一组,4的倍数
strip_tags
用base64------decode直接解码去掉无效代码,需要注入的语句直接base64加密,位数不足在前面加
第一种方法filename=php://filter/write=convert.base64-decode/resource=shell.php&txt=写入内容的base64编码
第二种方法: strip_tags|base64-decode
filename=php://filter/write=string.strip_tags|convert.base64-decode/resource=shell.php&txt=写入内容的base64编码
file_put-contents:文件写入函数
参数1写入文件名,写入文件内容
php://input
必须双on,默认不是双on
传参post和get同时存在,先将<?php info();> 用post传参给file=php://input。然后用get传参给include
file=php://input
要接受post传参

题目input
<?php
show_source(__FILE__);
include('flag.php');
$a=$_GET["a"];
// file_get_contents 读取文件内容
if(isset($a)&&(file_get_contents($a,'r') === 'I want flag')){
echo "success\n";
echo $flag;
}
file_get_contents 读取文件内容
file_put_contents
可以用stream伪协议的流--input
zip://
一个php文件压缩,不需要指定后缀名
自动解压压缩包 然后把压缩包的文件放下include 进行文件包含
触发:?file=zip://压缩文件的绝对路径%23文件内的子文件名
bzip2://
file=compress.bzip2://file.bzip2
zlib://协议
使用方法:
compress.zlib://file.gz
phar://路径/文件名
phar://./2.jpg/2.php
zip压缩包改名后可以利用phar访问到
data//
必须是双on
伪协议题目input
hint提示就是用input
<?php
$file = $_GET["file"];
if (!$file) echo '<a href="?file=upload">upload?</a>';
if(stristr($file,"input")||stristr($file, "filter")||stristr($file,"data")/*||stristr($file,"phar")*/){
echo "hick?";
exit();
}else{
include($file.".php");
}
?>
已经禁用,就只能用input
还是修改post部分:file=php://input
在get部分利用读取函数读取flag
<?php print_r(scandir('.'));?>找到文件
禁用了可以换其他的函数:问ai
读取文件:<?php print_r(file('./flag.php'));?>
show_source
<?php print_r(show_source('./flag.php'));?>
<?php echo file_get_contents('./flag.php');?>
<?php system('type flag.php');?>
linux:方式更多
伪协议题目filter
<meta charset="utf8">
<?php
error_reporting(0);
$file = $_GET["file"];
if(stristr($file,"php://input") || stristr($file,"zip://") || stristr($file,"phar://") || stristr($file,"data:")){
exit('hacker!');
}
if($file){
include($file);
}else{
echo '<a href="?file=flag.php">tips</a>';
}
?>
知道文件名:
?file=php://filter/read=convert.base64-encode/resource=flag.php
伪协议题目zip
//index.php
<meta charset="utf8">
<?php
error_reporting(0);
$file = $_GET["file"];
if (!$file) echo '<a href="?file=upload">upload?</a>';
if(stristr($file,"input")||stristr($file, "filter")||stristr($file,"data")/*||stristr($file,"phar")*/){
echo "hick?";
exit();
}else{
include($file.".php");
}
?>
<!-- flag在当前目录的某个文件中 -->
//upload.php
<meta charset="utf-8">
<form action="upload.php" method="post" enctype="multipart/form-data" >
<input type="file" name="fupload" />
<input type="submit" value="upload!" />
</form>
you can upload jpg,png,zip....<br />
<?php
if( isset( $_FILES['fupload'] ) ) {
$uploaded_name = $_FILES[ 'fupload' ][ 'name' ]; //文件名
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1); //文件后缀
$uploaded_size = $_FILES[ 'fupload' ][ 'size' ]; //文件大小
$uploaded_tmp = $_FILES[ 'fupload' ][ 'tmp_name' ]; // 存储在服务器的文件的临时副本的名称
$target_path = "uploads\\".md5(uniqid(rand())).".".$uploaded_ext;
if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" || strtolower( $uploaded_ext ) == "zip" ) &&
( $uploaded_size < 100000 ) ) {
if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {// No
echo '<pre>upload error</pre>';
}
else {// Yes!
echo "<pre>".dirname(__FILE__)."\\{$target_path} succesfully uploaded!</pre>";
}
}
else {
echo '<pre>you can upload jpg,png,zip....</pre>';
}
}
?>
?file=zip://绝对路径/2.zip%2/32
包含APACHE日志文件
1.找到日志文件位置
url text.php?file=/var/log/nginx/access.log(日志位置)
apm安装一定在/etc/nginx/nginx.cont/
编译安装可能在任何位置
问题
权限问题
物理文件路径
日志太大:日志分割最好是在12点或者凌晨以后再包含
思考:任意文件读取作用:直接窃取敏感信息如系统配置文件,应用配置文件,业务数据,源码文件,为后续攻击铺路,可以知道文件路径可以进行包含
包含SESSION--真实环境下很难
记录登录行为,记录账号信息,一定时间内免密登陆
cookie'---session
1.xss存储型,可以盗取icookie
插入xss代码:js代码让管理员触发,入侵者拿到cookie免密登陆
2.session可以预防逻辑漏洞,
平行权限会产生漏洞
防范平行权限:加入 session uid select username from uses where uid =$uid and session[uid]
利用session条件:知道路径
常见路径:/var/lib/php/sess_phpSESSID
/tmp/sess_phpSESSID
见到以下可能会出现文件包含
file=
action=php[:////filter/read=conver.base64_encode/resource
act=
img=
包含临时文件
知道文件路径,php上传时会出现生成一个临时文件,再临时文件删除之前完成
后端不会接临时文件,但是还是会删除临时文件,被自动删除了
条件:1文件不能删:利用程序要快,多次上传,2猜到临时文件名称 在linux下使用/tmp目录,而在windows下使用c:\winsdows\temp目录(可以暴力)