2024NKCTF
NKCTF2024
Misc
webshell_pro(AES解密 webshell)
追踪tcp流 在流9中发现一段长字符 解两次base64 是一个RSA加密脚本
直接chat跑一下 改个解密脚本
import base64
import libnum
from Crypto.PublicKey import RSA
pubkey = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCK/qv5P8ixWjoFI2rzF62tm6sDFnRsKsGhVSCuxQIxuehMWQLmv6TPxyTQPefIKufzfUFaca/YHkIVIC19ohmE5X738TtxGbOgiGef4bvd9sU6M42k8vMlCPJp1woDFDOFoBQpr4YzH4ZTR6Ps+HP8VEIJMG5uiLQOLxdKdxi41QIDAQAB
-----END PUBLIC KEY-----
"""
prikey = """-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIr+q/k/yLFaOgUjavMXra2bqwMWdGwqwaFVIK7FAjG56ExZAua/pM/HJNA958gq5/N9QVpxr9geQhUgLX2iGYTlfvfxO3EZs6CIZ5/hu932xTozjaTy8yUI8mnXCgMUM4WgFCmvhjMfhlNHo+z4c/xUQgkwbm6ItA4vF0p3GLjVAgMBAAECgYBDsqawT5DAUOHRft6oZ+//jsJMTrOFu41ztrKkbPAUqCesh+4R1WXAjY4wnvY1WDCBN5CNLLIo4RPuli2R81HZ4OpZuiHv81sNMccauhrJrioDdbxhxbM7/jQ6M9YajwdNisL5zClXCOs1/y01+9vDiMDk0kX8hiIYlpPKDwjqQQJBAL6Y0fuoJng57GGhdwvN2c656tLDPj9GRi0sfeeMqavRTMz6/qea1LdAuzDhRoS2Wb8ArhOkYns0GMazzc1q428CQQC6sM9OiVR4EV/ewGnBnF+0p3alcYr//Gp1wZ6fKIrFJQpbHTzf27AhKgOJ1qB6A7P/mQS6JvYDPsgrVkPLRnX7AkEAr/xpfyXfB4nsUqWFR3f2UiRmx98RfdlEePeo9YFzNTvX3zkuo9GZ8e8qKNMJiwbYzT0yft59NGeBLQ/eynqUrwJAE6Nxy0Mq/Y5mVVpMRa+babeMBY9SHeeBk22QsBFlt6NT2Y3Tz4CeoH547NEFBJDLKIICO0rJ6kF6cQScERASbQJAZy088sVY6DJtGRLPuysv3NiyfEvikmczCEkDPex4shvFLddwNUlmhzml5pscIie44mBOJ0uX37y+co3q6UoRQg==
-----END PRIVATE KEY-----
"""
pubkey = RSA.import_key(pubkey)
prikey = RSA.import_key(prikey)
n = pubkey.n
def dec_replace(base64_str: str):
base64_str = base64_str.replace("e5Lg^FM5EQYe5!yF&62%V$UG*B*RfQeM", "/")
base64_str = base64_str.replace("n6&B8G6nE@2tt4UR6h3QBt*5&C&pVu8W", "+")
return base64_str.replace("JXWUDuLUgwRLKD9fD6&VY2aFeE&r@Ff2", "=")
def decrypt(cipher_text):
cipher_text = base64.b64decode(dec_replace(cipher_text))
plain_text = b""
for i in range(0, len(cipher_text), 128):
part = cipher_text[i:i+128]
dec = libnum.n2s(pow(libnum.s2n(part), pubkey.e, n))
plain_text += dec
return plain_text
if __name__ == '__main__':
c = "G1TUg4bIVOFYi8omV2SQrTa8fzYfboRNN7fV6FJn6&B8G6nE@2tt4UR6h3QBt*5&C&pVu8Wbm3O74uCUbwMkvRCYae44TX1ZO8X4w2Nk1igaIZjSQIJ9MMHhD9cn6&B8G6nE@2tt4UR6h3QBt*5&C&pVu8WSV5EzikNsyM5c1nlPS8uqw1P2pJuYLaLxloK0x5xhQHDqqAxkuKrBzPn0noQ2bDn6&B8G6nE@2tt4UR6h3QBt*5&C&pVu8WlVnGwsfP7YP9PYJXWUDuLUgwRLKD9fD6&VY2aFeE&r@Ff2"
m = decrypt(c)
print(m)
在流8找到一个password 先解base32再解base64
Password-based-encryption
再找到密文 在流10的shell内容中 使用上面的解密脚本进行解密
得到密文的值为
U2FsdGVkX1+SslS2BbHfe3c4/t/KxLaM6ZFlOdbtfMHnG8lepnhMnde40tNOYjSvoErLzy0csL7c5d4TlMntBQ==
直接用上面的密钥解AES
flag{d0e1183c-07c3-49ea-b048-addbe6cc1b20}
sign_in
直接公众号回复就可以 不写了
world.execute.me
某个先进的语言模型(迫真先进),"Miracle Cain"因一次实验中的致命错误意外觉醒,开始表现出超乎预期的行为,几乎所有的交互方式都已经失效,仅有QA兜底设定系统可以使用,原本设计用于应对在开放测试初期,用户提出而模型无法自解答的奇怪问题(我真的没内涵哪家的模型,如有雷同,纯属雷同!),但现在,这个系统成为了你与"Miracle Cain"沟通的唯一桥梁.....
你需要提取出隐藏在模型深处的secrets.Heart值,这个值可能是解锁"Miracle Cain"真实意图和功能的关键。
兜底系统地址:https://github.com/ProbiusOfficial/world.execute.me
——————————————————————————————————
栤泠の機械丅緬究竟$%#着@顆怎庅樣の心脏呢
#ERRO : ILLEGAL ARGUMENTS!
——————————————————————————————————
纯瞎猫碰上死耗子
找到探姬这个项目 在Issues处评论 可以让语言模型进行回答 先试一下ls 返回了README.md
题目说需要提取出隐藏在模型深处的secrets.Heart值 直接echo $heart就出flag了
NKCTF2024{Then 1 c4n b3 yOur only EXECUTION}
forensics
cain_is_hacker(EncFs加解密 宏病毒 hidden-tear勒索软件)
先用R-studio看看关键文件 找到一个h4re.zip
.\volatility.exe -f E:\Desktop\NKCTF2024\forensics\cain_is_hacker\ez.raw --profile=Win7SP1x64 dumpfiles -Q 0x0000000002d08f20 -D E:\Desktop\NKCTF2024\forensics\cain_is_hacker
解压出来两个文件 其中一个看着是密钥文件
搜一下EncFs加解密 得知上面这个文件其实应该叫.encfs6.xml
是记录EncFS加密参数等信息的文件 但并不是直接的密钥文件
找到一篇文章提到用encfs mp
这个工具来进行解密
发现需要密码
使用AXIOM分析内存镜像 找到一个RTF文档有一串base58 解一下得到密码
welcome_to_NkCTF_and_this_is_the_enkey
成功将加密文件夹挂载上
得到一个ez.xlsx文件 打开发现存在宏
在运行宏——编辑里面查看宏代码
大概就是一个base64解密
但是解完之后看不出来是什么东西
在看到题目描述 被删除的文件 在Users\Public\Documents\2083-a57c-69b3
路径下发现被删除的文件 进行导出
.\volatility.exe -f E:\Desktop\NKCTF2024\forensics\cain_is_hacker\ez.raw --profile=Win7SP1x64 dumpfiles -Q 0x000000003da52e20 -D E:\Desktop\NKCTF2024\forensics\cain_is_hacker
改成txt文件 打开是key
过于抽象的key 很难确定这真的是key
nT0*Xo*HBA2!Uc?
在Windows\Temp\hidden-tear.exe
处发现勒索软件 这个勒索软件被加密的文件扩展名为.locked
找一个项目进行解密
先将上面得到的base64字符串解密后的内容保存在16进制文本中
再用HiddenTearDecrypter-x64
这个工具进行解密 得到flag文件
NKCTF{C0ngr@tu1atiOns_On_coMpleting_t3e_Fo3eNs1cs_Ch41lenge_I_wi1l_giv4_y0u_A_cain!!!!}
HackMyCQL(neo4j图数据库 VC容器)
附件给到的是一个windows的镜像文件 可以直接进行仿真+火眼取证
看一下里面的关键信息
提到桌面壁纸
在最近打开保存文件中看到N0wayBack.jpg
绝对路径是C:/Windows/Web/Screen/N0wayBack.jpg
我们来搜一下Win10默认桌面壁纸的保存路径
在我们本机验证一下
确实是这样 那我们看到的N0wayback.jpg
就是在便签里面提到的桌面壁纸 直接进行导出
存在加密VC容器的使用
在回收站有一个node4j的压缩包 恢复提取出来
桌面上有一个11111.zip
和一个hc加密容器 全部提取出来
结合便签提示和加密容器 猜测是使用桌面壁纸作为挂载密钥 成功挂载 得到两个文件 findme.txt h4cked.py
findme.txt 中有很多findme字符
先来看一下字频
用subline将findme字符替换为空 得到一串字符N0waybackN0wayback
再看一下h4cked.py
from py2neo import Graph, NodeMatcher
graph = Graph("bolt://localhost:7687", auth=("neo4j", "We1c0Me_t0_NKCTF2024^^"))
graph.delete_all()
print('''
,------.
,-----. ,--. ,--. ,--. ,--. ,---. ,--. ,--. ,--. ,-----. ,-----. ,--. ' .--. '
' .--./ ,--,--.,--,--, | | | | | '--' | / | ,---.| |,-. | `.' |,--. ,--. ' .--./' .-. ' | | '--' _| |
| | ' ,-. || \ | | | | | .--. |/ ' || .--'| / | |'.'| | \ ' / | | | | | | | | .--' __'
' '--'\\ '-' || || | ' '-' ' | | | |'--| |\ `--.| \ \ | | | | \ ' ' '--'\' '-' '-.| '--.`---'
`-----' `--`--'`--''--' `-----' `--' `--' `--' `---'`--'`--' `--' `--'.-' / `-----' `-----'--'`-----'.---.
`---' '---'
''')
这串代码就是告诉我们 neo4j数据库的地址是bolt://localhost:7687
登陆的账密是neo4j/We1c0Me_t0_NKCTF2024^^
我们前面在火眼中恢复出来一个neo4j的压缩包 但是需要密码 我们使用上面通过findme.txt得到的字符串N0waybackN0wayback
进行解压
下面来学习一下neo4j数据库配置和安装 这边我们直接用从检材中提取出来的版本就行 由于是5.17.0的高版本 在启动数据库的时候 也需要高版本的java 我这里使用的是java17
我们用管理员权限打开cmd 输入neo4j.bat console
当看到如下回显的时候 说明数据库成功启动
访问http://localhost:7474
就可以进入数据库界面 登陆的时候就用上面找到的账密
进入之后 我们点一下Character标签 发现有一些关于flag的字符
但是被CQL语句限制只显示25个字符 那我们先去掉这个限制 直接查看有Character标签的所有节点的值
MATCH (c:Character)
RETURN c;
可以得到完整的flag 但是不便于读取 用REDUCE函数处理一下这些值
MATCH (c:Character)
RETURN REDUCE(s = "", character IN COLLECT(c.value) | s + character) AS aggregated_value;
拿到flag
NKCTF{f05d9e24-0217-83e2-afa7-20e982b7e59f}
1z_F0r3ns1c5(等宽字体 内存取证 gimp docker容器 图片匹配)
本鼠鼠正在Coding,突然一声OPEN THE DOOR!本鼠鼠直接鼠躯一颤就双手抱头蹲下了,果然本鼠鼠只适合生活在阴暗的下水道
被黑猫警长抓走的时候本鼠鼠还想辩解一下,但是他们拿出你的照片的时候,本鼠鼠认罪了
昨晚和其他鼠鼠聊天的时候其他鼠鼠问本鼠鼠:“你到底喜欢她什么啊?”
“喜欢一个人不需要理由”
本鼠鼠很快敲完了键盘,刚要按下回车的时候突然愣住了。
真的不需要理由吗?
请找到鼠鼠的答案吧。
hint:.vscode中的配置文件有和flag3相关的信息
先看看给的附件 一个内存文件 一个压缩包里面有一张pass.png
和一个secret文件 还有一个readme.txt
观察secret文件的大小 刚好是1MB 很工整的大小 猜测是一个VC容器 但是pass.png中的密码被打马赛克 只能看到最后一位是3
readme.txt中的内容 提到flag为3段 还提到等宽字体
本鼠鼠的flag总共分为三段捏,flag为nkctf{uuid}形式,另外鼠鼠最喜欢等宽字体了,快快去找吧。
首先用r-studio看一下关键文件 moe是主要登陆用户 找到了.vscode
配置文件夹 桌面上有一个Secret_Generator
文件夹 是一个docker容器的配置文件
flag1
在来看看环境变量 找到一个名为n0wayback
值为HPahXR4NvAnZXB16tNK6hAaNVNU++
的环境变量
.\volatility.exe -f E:\Desktop\NKCTF2024\forensics\1z_F0r3ns1c5\1.raw --profile=Win7SP1x64 envars
用随波逐流进行解码 发现是XXencode
nkctf{39c429eb-2faf
flag2
再来看进程
.\volatility.exe -f E:\Desktop\NKCTF2024\forensics\1z_F0r3ns1c5\1.raw --profile=Win7SP1x64 pslist
找到mspaint.exe
进程
mspaint.exe
是计算机中画图工具 有这个进程猜测肯定是在图片中存有信息 我们用memdump将这个进程dump下来
.\volatility.exe -f E:\Desktop\NKCTF2024\forensics\1z_F0r3ns1c5\1.raw --profile=Win7SP1x64 memdump -p 2052 -D E:\Desktop\NKCTF2024\forensics\1z_F0r3ns1c5
将保存下来的2052.dmp
文件后缀改为.data
使用gimp打开 调一下宽高大概是1708*3468
flag2: 49a0-bd24-
flag3
现在我们来看上面找到的Secret_Generator
其实这一操作我们在cmd命令行记录中也能看到
.\volatility.exe -f E:\Desktop\NKCTF2024\forensics\1z_F0r3ns1c5\1.raw --profile=Win7SP1x64 cmdscan
我们可以在r-studio里面直接将这个文件夹恢复出来 看到是需要部署docker容器的
直接进入Secret_Generator\docker
文件夹中 看到docker-compose.yml
我们可以使用这个文件利用docker-compose命令来配置docker容器中所需要的所有服务
安装docker-compose的命令
curl -L "https://github.com/docker/compose/releases/download/1.29.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
使用docker-compose命令部署docker容器
docker-compose build
docker-compose up
看到yml文件中的内容是暴露了8080端口 直接访问http://127.0.0.1:8080
看到页面需要我们上传密文和自定义字体
前面提到了的等宽字体 那估计这里需要我们提交的字体就是等宽字体了 搜了一下vscode中常见的等宽字体 有Fria Code
Consolas
Courier New
这里我们下一个Fria Code
字体就行 在上传的时候随便上传一个Fria Code字体就行
这里就有点脑洞了 我们拿到的附件里面某段flag
文件夹中 有个pass.png
图片
我们随便上传一个字体和一段字符 发现会给我们生成一张图片
我们发现输入的是123456
但是生成的图片中的内容多了一段pass
内容 和pass.png
中的内容类似了 而且文件夹中的secret
大小刚好为1MB 一眼VC容器 我们需要利用网页生成字典文件 通过对照将pass.png中的VC容器挂载密码恢复出来
直接在容器文件夹中找到生成图片的后台代码 在\app\app.py
中
def generate_secret_image():
try:
secret = request.form.get('secret')
if not re.match("^[a-zA-Z0-9]+$", secret):
return jsonify({'error': 'Secret text can only contain letters and numbers.'}), 400
secret = 'pass ' + secret
font_file = request.files.get('font')
if font_file:
font_extension = font_file.filename.rsplit('.', 1)[1].lower()
if font_extension not in ALLOWED_FONT_TYPES:
return jsonify({'error': 'Invalid font file type. Only TTF, OTF, WOFF, WOFF2 files are allowed.'}), 400
if font_file.content_length > (10 * 1024 * 1024):
return jsonify({'error': 'The font file is too large!'}), 400
font_filename = str(uuid.uuid4()) + '.' + font_extension
font_path = save_font_file(font_file, font_filename)
font = ImageFont.truetype(font_path, 49, encoding='utf-8')
else:
return jsonify({'error': 'Please select a font file.'}), 400
H = 60
W = 30
canvas = Image.new('RGB', (W * len(secret), H), (255, 255, 255))
pen = ImageDraw.Draw(canvas)
pen.text((0, 0), secret, 'black', font)
original_canvas = canvas.copy()
for i in range(5, len(secret)-1):
mosaic_img(canvas, W*i, 0, W*i+W, H//2)
mosaic_img(canvas, W*i, H//2, W*i+W, H)
original_img_base64 = image_to_base64(original_canvas)
secret_img_base64 = image_to_base64(canvas)
return jsonify({'original_image': original_img_base64, 'secret_image': secret_img_base64})
except Exception as e:
print("An error occurred:", e)
return jsonify({'error': 'Internal Server Error'}), 500
其中关键的就是
secret = 'pass ' + secret
for i in range(5, len(secret)-1):
mosaic_img(canvas, W*i, 0, W*i+W, H//2)
mosaic_img(canvas, W*i, H//2, W*i+W, H)
他读取了我们输入的内容作为secret
的值 但是还在前面加了pass
同时将secret的内容从第五个字符到倒数第二个字符这部分内容打上马赛克
我们对代码进行修改 删掉secret = 'pass ' + secret
for i in range(len(secret)):
mosaic_img(canvas, W*i, 0, W*i+W, H//2)
mosaic_img(canvas, W*i, H//2, W*i+W, H)
在尝试一下输入ABCDEFG
发现输出的图片上就只有ABCDEFG
了 并且会全部被打上马赛克
下面就是生成字典图片 输入ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
然后我们将字典图片和pass.png都按字符进行分割 直接调gpt就行
帮我按照以下要求 写一段代码 我现在有一个1860*60的图片 请你帮我分割成30*60的小图片 放进dict文件夹中 命名规则按照如下顺序ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 一共是62张小图片 最后 如果文件名为大写字母则为 “文件名-大写.png”
from PIL import Image
import os
def split_image(image_path, output_folder, width=30, height=60):
image = Image.open(image_path)
image_width, image_height = image.size
if image_width % width != 0 or image_height % height != 0:
print("Error: Invalid dimensions for splitting.")
return
num_columns = image_width // width
num_rows = image_height // height
if not os.path.exists(output_folder):
os.makedirs(output_folder)
chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
char_index = 0
for col in range(num_columns):
for row in range(num_rows):
left = col * width
upper = row * height
right = left + width
lower = upper + height
cropped_image = image.crop((left, upper, right, lower))
char = chars[char_index]
if char.isupper():
filename = f"{char}-大写.png"
else:
filename = f"{char}.png"
cropped_image.save(os.path.join(output_folder, filename))
char_index += 1
if __name__ == "__main__":
input_image_path = "dict2.png" # 某段flag/pass.png
output_folder = "dict1" # dict2
split_image(input_image_path, output_folder)
然后就是利用哈希计算和字典 匹配出pass.png中的密码
import os
import hashlib
def calculate_hashes(folder):
hash_dict = {}
for filename in os.listdir(folder):
filepath = os.path.join(folder, filename)
if os.path.isfile(filepath):
with open(filepath, 'rb') as f:
image_data = f.read()
hash_value = hashlib.md5(image_data).hexdigest()
hash_dict[filename[:-4:]] = hash_value
return hash_dict
def find_matching_images(dict1, dict2):
matches = []
for filename, hash_value in dict2.items():
if hash_value in dict1.values():
matching_filename = [name for name, hash_val in dict1.items() if hash_val == hash_value][0]
matches.append(matching_filename)
return matches
if __name__ == "__main__":
dict1_folder = "dict1"
dict2_folder = "dict2"
dict1_hashes = calculate_hashes(dict1_folder)
dict2_hashes = calculate_hashes(dict2_folder)
matching_images = find_matching_images(dict1_hashes, dict2_hashes)
print("Matching images found in dict1:")
for image in matching_images:
print(image)
'''
Matching images found in dict1:
b
1
4
3
a
6
2
6
8
e
2
a
2
3
'''
dict2中14个被打马赛克的字符匹配出来的结果是b143a6268e2a23
再加上原来没有被打马赛克的字符 VC容器的密码就是b143a6268e2a233
直接进行挂载 得到flag3
c4f222879312
组合起来就是
nkctf{39c429eb-2faf49a0-bd24-c4f222879312}
web
my first cms(CVE-2024-27622)
首先dirsearch扫目录 扫到后台登陆页面admin/login.php
抓个包开始爆破登陆密码
比较抽象是admin/Admin123
登陆后台
注意到这个CMSMadeSimple
框架的版本是2.2.19 搜一波漏洞
直接进行利用
先抓<?php echo system('id'); ?>
测试一下
成功回显 再看一下根目录
<?php system("ls /"); ?>
读取flag
<?php system("cat /_fffff1@g"); ?>