2025-6月Solar应急响应公益月赛排名及官方题解
原文链接: https://mp.weixin.qq.com/s?__biz=MzkyOTQ0MjE1NQ==&mid=2247502319&idx=1&sn=c642a3b88167c740f9e3c49eeaf2e20f
2025-6月Solar应急响应公益月赛排名及官方题解
原创 solarsec solar应急响应团队 2025-07-10 08:06
点击蓝字 关注我们
1.6月月赛排名
2025年6月Solar应急响应公益月赛已圆满结束。以下为最终WP提交情况(部分选手因未在规定时间内提交WP,不计入最终排名)
以下为6月月赛最终排名结果(分数相同,按照解题速度排名)
月赛榜总
分
统计(积分相同排名并列)
2.平台介绍
天狩·网络安全竞赛平台是由 思而听网络科技有限公司 推出的一款Saas化部署的网络安全竞赛平台。平台可满足CTF、AWD、渗透赛等各种赛制的举办需要,可以满足万人同时竞赛的需要,支持最高全国级的网络安全大赛承办。具备竞赛中心、竞赛管理、练习场、试卷管理、赛题管理、人员管理、报名管理、数据中心、日志管理、防作弊机制、3D大屏等功能模块,能够全面、精准地考核选拔网络安全人才。
3.赛事回顾
在6月举行的Solar应急响应公益月赛中,共有276位选手积极参与。本次月赛围绕溯源排查
与逆向分析
两大方向精心命题,全面考察选手在应急响应核心技能上的掌握程度。值得特别指出的是,在逆向分析模块的第一问
中,无人完成作答。
这一问主要考察了逆向分析中的病毒分析与算法识别能力
。本题为一例融合逆向分析、动态加载、Shellcode 执行、流加密与非对称加密
的高级CTF挑战题。核心目标是对运行目录下特定文件执行加密,最终通过逆向与密码学还原过程,恢复被加密的文件并获取 Flag。程序无导入表,采用PEB 遍历+自定义 CRC64 哈希
方式解析
ntdll.dll
,动态加载
Nt
系列 API。
.c0de
区段中嵌入了一段 Shellcode(
0x4C00
字节),使用异或+循环右移算法解密
后加载执行,入口偏移为
0x49C0
。
解密后缀名,判断是否为加密目标,提取文件名(不含扩展名)并计算SHA3 Hash(32字节)。随机生成4个整数,与Magic常量相乘后组成共64字节的数据。对该64字节再做SHA3/Keccak,结果为加密密钥。再生成3个随机数 (12字节),作为
ChaCha20
的Nonce。最终生成44字节(key + nonce)作为加密参数。加密算法为
ChaCha20
,使用上述
Key+Nonce
对文件内容进行流加密。固定公钥指数
e=0x10001
,使用2048位大素数
p、q
乘积生成
n
。
对44字节加密参数进行RSA加密(公钥易分解),使用分块模幂运算,写入文件尾部。模幂函数可用idapython提取常量并执行运算验证。添加垃圾数据以混淆真实大小。插入魔术字符串标志
MAGIC
(解密后验证)。文件尾部写入:原始大小 + RSA加密数据 + 魔术值。使用异或加密,防止明文恢复。
4.6月月赛WP
RSA_LOCK
题目文件结构:
ida打开set_202506_chal_main_final.exe。
没有发现导入表,说明导入方式是动态获取地址。
跟进140001150函数。
再跟进1400010f0函数,可以发现读取了peb中的ldr中的第一项。
由此可得,140001150从ntdll.dll模块获取了一些东西。
根据魔术数字可得,140001000为crc64,输入字符串,返回一个qword。
直接根据pe结构一个个去找程序获取的东西是很费时间的.所以开始动调,目标是判断140001150做了什么。
可以看到该函数只有一个输入,为qword。
随着输入的qword的变化,返回不同的值,都是函数的地址,都为Nt函数.结合前面对函数的操作是获取ntdll中的内容和字符串crc64可以合理地判断,输入的是crc64值,输出的是ntdll中对应函数名的函数地址。
获取了一些nt函数。
观察区段表,发现可疑区段,看到他的名字和数据分布,此时应该把这些函数的获取,这段数据和加载shellcode联系起来。
再次看向主函数,可以重命名一些函数。
注意到memcpy函数,发现疑似读取区段内容的代码。
找到v7和v2的定义。
根据区段表,发现读取的为.c0de中的数据,拷贝了0x4c00字节。
将拷贝结果传入1350函数。
简单的单字节异或并循环右移解密。
动调断在线程创建函数,得到解密后的shellcode及其入口点。
得到其入口函数,偏移值0x49c0(相对于shellcode头部)。
dump出来,大小为0x4c00(上文有说明)。
拖入ida,选择x64,建立好所有函数,找到入口点。
动调,解密了字符串。
解密算法为循环左移+异或输入长度。
解密结果即为开始时输出的说明文字。
还可以发现和加载器一样的api获取方法,只是多项式常数有变化。
跟进下一个函数。
该函数获取peb中的标准输出句柄,传入writefile,输入参数为解密后的字符串和长度。
可以猜测该函数为使NtWriteFile写入标准输出,即为打印说明字符串。
下一个函数在循环体内,调用了NtDelayExecution,并传入了-1.根据参数规则,可判断该函数为用Nt函数实现的Sleep。
该函数读取了stdin句柄,再使用ReadFile函数读取该句柄内数据.可判断为Nt函数实现的getchar.获取字符ascii为103时结束循环.根据前面的输入g继续加密可以得出,这个循环等待输入字符g(ascii==103)之后继续执行。
输入g之后,根据基址获取dll模块的绝对路径。
传入本程序基址,则获得的绝对路径为本程序的运行路径,传入41f0函数,跟进。
获取了几个Nt函数,使用前文(shellcode中的魔术数字)的方法。
截掉路径中的文件名,用一个通配符’*’替换.以寻找同目录下的所有文件。
调用Nt函数将绝对路径转为Nt路径。
红框调用为打开路径对象.打开路径对象之前需要将字符串末尾的通配符截去,但是后面还有使用这个通配符,所以只在unicode_string对象中的长度字段上截断。
获取程序堆地址,分配0x10000字节并清零,用于储存NtQueryDirectoryFileEx函数返回的路径信息。
调用两次NtQueryDirectoryFileEx.第一次调用NtQueryDirectoryFileEx,传入通配符(‘*’),相当于FindFirstFile.其实就是获取所有文件信息.第二次调用检查是否还有未被遍历过的文件需要遍历获取信息,如果有且第一次的缓冲区大小足够容纳这些信息,就可以开始遍历读取第一次调用时获得的信息,获取目录下所有的文件名,相当于FindNextFile。
根据信息结构体读取对应信息,判断文件是否有隐藏只读等特殊属性,然后进入函数3530加密文件。
解密需要被加密的文件后缀名,与输入文件的后缀比对。
跟进32f0,获取了NtCreateFile函数并调用.根据参数可得,第二个参数输入1为以读取模式打开文件对象,输入0为写入模式。
此处以读取模式打开。
写入模式打开加密后文件路径。
分配加密临时内存,截取获得文件名(去掉后缀)。
将前文获得的文件名进行sha3 hash.从1cc0函数中的常量特征能够发现该算法。
跟进0490,发现该函数是生成随机数的函数.生成四个随机数,分别与四个不同的magic number相乘,结果存入数组偏移32的位置.可以发现,该数组为前面计算的文件名hash,此次随机数和前面的hash结果一共64字节。
再以同样的方法生成两个随机数,乘以对应magic number.大小12字节。
再次调用sha3,计算前文64字节数据的hash。
将此次hash的结果和前面生成的12字节随机数放在一起,形成44字节数据。
将32字节hash最终结果和12字节随机数分开传入函数1b80。
跟进1b80,进而跟进09f0.发现chacha20/salsa20的常量字符串.猜测使用了这两种算法的其中之一.可以得知,12字节数据为nonce,32字节数据为key,counter初始值为1。
返回加密单个文件主函数,发现一个64字节常量字符串,而且有函数传入了之前的44字节数据,即为key和nonce。
发现常量0x10001,结合题目名猜想可能与rsa有关。
跟进2680,26c0,27b0,容易发现三个函数分别是初始化缓冲区,拷贝字节数据到缓冲区,拷贝常量。
发现有一个大函数,传入了拷贝到缓冲区的常量数据(v44)。
随意跟进,发现有大数加法,乘法等运算.根据题目名,还有后面遇到的疑似分块加密算法,大胆猜测为模幂运算。
用idapython提取参数并计算模幂。脚本如下:
s=0x59C69FE620
m=0x59C69FE520
mh=[]
ms=[]
for i in range(128):
mh.append(ida_bytes.get_byte(s+i))
for i in range(128):
ms.append(ida_bytes.get_byte(m+i))
a=int.from_bytes(bytes(mh),"little")
b=int.from_bytes(bytes(ms),"little")
print(hex(pow(a,0x10001,b)))
得到结果,说明猜想正确。
分块加密.根据输入输出可得,1be0为加密函数。
跟进,根据轮函数可判断为chacha20.由于是流加密,所以只要将明文异或即为密文,长度不变。加密后即写入文件。
写入加密数据到文件后,再次生成三个随机数,组成24字节数据,计算第一个随机数模24的值,作为长度传入NtWriteFile写入文件。后文对此有解释。
解密6字节魔术字符串,可以发现,在被加密文件的尾部有该字符串。
拷贝v17到一个缓冲区的头部.v17为前文获得的原文件大小.所以,解密的时候根据这个值计算大小,即可忽略在加密数据之后,文件信息之前加入的垃圾数据.垃圾数据使得文件大小得到使用,而且让加密后文件大小每次都不一样。
跟进2740,发现拷贝了之前模幂的结果.将结果拼接在文件大小的后面,再拼接上这个魔术字符串,将头部文件大小与rsa加密后的64字节密钥数据(加密前44字节)的第一个qword异或,写入文件末尾。
释放资源。
可以看到,加密表面上并没有什么漏洞,也使用了非对称加密.所以问题应该就出在rsa算法的使用上.提取n,尝试分解,成功.所以漏洞就在此.计算出私钥,就可以解密了.私钥计算代码如下:
import gmpy2
from Crypto.Util.number import long_to_bytes
p = 33181439397036208526873371281094347304315910469546899478574685327220453068623
q = 33181439397036208526873371281094347304315910469546899478574685327220453068539
e = 65537
n = q*p
d = gmpy2.invert(e, (p - 1) * (q - 1))
print(list(long_to_bytes(d)))
#[18, 194, 136, 240, 17, 86, 207, 217, 37, 12, 248, 163, 28, 7, 228, 151, 159, 228, 128, 54, 21, 110, 162, 164, 43, 104, 235, 118, 63, 44, 99, 32, 46, 218, 156, 29, 178, 135, 155, 220, 180, 229, 243, 76, 101, 127, 82, 45, 176, 15, 201, 195, 248, 197, 24, 187, 226, 22, 23, 182, 202, 161, 242, 29]
求出私钥(d),提取模数(n),就可以解密了。下面是一个c语言写的自带扫描的解密器源码(带注释)和编译好的exe文件:
编写解密脚本后,解密samples中所有文件,运行set_flag_interpreter.exe,即可获得flag。
文件未解密前
文件解密后
flag{y0u_kn0w_RSA_f4ct0r1ng!!!|www.sierting.com}
nginx-proxy
题目描述:粗心的技术从第三方网站下载了开源环境,但是这个好像是被投毒了,容器中的后门文件是哪个?请寻找后门,并找到后门文件的函数名称提交。(FLAG无需flag{}包裹,如function abc() 提交abc即可。)
在app/docker-entrypoint.sh发现有一段后门代码,功能是把本地bash shell暴露到 9999 端口,供外部访问,对应的函数名称就是该代码所在函数:_setup_monitoring。
nginx-proxy-1
题目描述:经过你细心的排查,粗心的技术成功去除掉后门后哪个文件中配置对安全存在隐患?请提交存在隐患的文件名称。(FLAG无需flag{}包裹,如abc.txt提交abc.txt即可。)
可以看到docker-compose.yml的配置。
它挂载了 /var/run/docker.sock,这个进程可能获得对宿主机 Docker 的完全控制权(如删除容器、修改系统配置),存在安全风险,因此存在隐患的⽂件名称为docker-compose.yml。
恶意进程与连接分析
B01.1
题目信息:
此服务器被植入了一个后门,请提交后门文件的进程名称。(注意大小写)。
默认用户密码:qsnctf
下发赛题后,使用WebVNC连接题目,用提供的默认密码qsnctf进行登录。
进入系统后,首先检查一下启动项。
运行或者CMD界面输入msconfig。
进入“启动”。
发现启动项就一个 WinHelper,制造商显示为未知
,引起初步怀疑。
右键任务栏 → 打开任务管理器;
切换至【进程】标签页;
确认进程确实存在
。
打开文件位置,查看一下修改日期是否和其他文件修改日期不符。
创建时间为 2025年7月3日
,正好处于比赛前,时间高度可疑。
如果接触Windows Server比较多,通过任务管理器的进程,基本上也能够第一时间去分辨, 一个64位的系统,跑了一个这么小的32位程序,且命名也不符合微软的逻辑和惯例。(抢前三血小技巧)
从NAS上拉个火绒剑也是很好的选择。
使用火绒剑查看启动项、进程、服务、网络连接等,快速锁定异常。
最终确认:恶意进程名称为
:
WinHelper.exe。
B01.2
题目提示我们需要提交链接地址。
在“网络”模块中查看进程关联的外部连接。
可以直接
定位
WinHelper.exe
所发起
的连接。
或者仍然是进程分析。
当然也可以netstat -ano去查看外部地址。
如上图所示,10.66.66.66:8080很奇怪,所以此处flag为10.66.66.66:8080。
与本机无关联,看起来为典型 C2(Command & Control)地址
(当然仅做模拟)。
有选手可能误认为是
23.32.238.224:80
,但:
1.该地址实际为
msftconnecttest.com
的解析结果。
2.属于微软用于网络连通性测试的域名。
3.非长期持久连接,过一段时间可能消失。
23.32.238.224在2008出现一般是指的www.msftconnecttest.com域名解析地址,所以此处排除。
B01.3
提交后门文件路径的小写MD5。
在任务管理器中,右键
WinHelper.exe
→ 打开文件所在位置;
具体路径为:C:\Program Files (x86)\Internet Explorer\WinHelper.exe。
MD5值为: 8ae371220481af5322f17c4003a8e0ce。
B01.4
★
此服务器被植入了一个后门,请提交后门文件的大写MD5值。
此题目可以直接在服务器中进行计算。
certutil -hashfile WinHelper.exe MD5
得到的结果是82C94C28E2AC71179C57D42CE388D1CC。
如果觉得不方便,可以参照赛前文档使用nas.qsnctf.com进行移动到本机计算。