来这里找志同道合的小伙伴!
CTF 大 赛
近日,京东安全联合安全界的黄埔军校看雪论坛举办了一次线上CTF大赛,近3w人参赛。参与解答“京东AI CTF大挑战特别题”的同学有1435人,最终解出题目的只有2人。
>>>> 解题报告一
这是一道很有意思的题目,成功的激起了我的兴趣。做的不一定对,也不一定好,跟大家分享。
>>>> 一、审题
download附件,解压文件,审题。
1、题目
题目提供了二进制序列的十进制数列,共200个数。使用机器学习的模型对这两百个数进行判断,是函数入口就打个1,问题是现在学习出来的全是0,少了唯一的一个1。
2、h5文件
这个文件是Keras的model文件,使用load_model可以加载。
>>>> 二、环境
1、windows
2、x32dbg
3、anaconda3
4、keras(windows下pip安装keras主体没问题,但是可视化的部分有坑,弃之)
5、vscode
>>>> 三、手工分析数据
题目已经说明,两百个样本点是“二进制代码”,但是数据看起来被加工过,数据在[1,256]之间。特别是多次出现神奇的256,这不在正常的0x00--0xff的区间,所以推测手工分析数据应该全减一。
处理一下数据,输出成能复制粘贴的形式:
结果:
复制到x32dbg中查看:
发现代码确实处于可阅读的状态了,而结果表中1的位置在40(从0算起),对应到sub esp,C的位置,确实符合题目函数入口的要求,而对比其余ret片段,前面几段短的未涉及esp(0x83)的代码不算在题目要求之列,而后面几段只有add esp,未做平衡的代码也明显不是正常函数。
推测:题目所要求“函数入口”需局部变量的堆栈平衡操作,特征以0x83为主。
>>>> 四、模型分析
可以看到,模型分三层网络,最后输出200*2的结果,直接把题目样本给进去,看结果:
其中0.999999是我先大概看了一下输出之后选的阀值,因为大多数值都很接近1了。
可以看到,只有40的概率相对高(很多),但是也未突破0.5。另外注意到 0x31对应到xor,0xb8对应到mov。
>>>> 五、目标推测
可以看到这个模型的问题在于,1的置信度不够,也就是说,原样本的0太多了,需要多一点1的样例来让机器确定这就是“函数入口”。
那么基于原样本改造出训练样本的思路也就出来了,在训练集多加符合题意的1,那么我就加了一个函数入口,在168的位置:
转换回数据之后训练:
这次的原样本预测结果:
结果应该是满足要求了,只有一个位置的概率大于50%,并且是正确的位置。
至此,题目按我的理解应该是pass了。
>>>> 六、优化
1、构造的数据集可以有更丰富的组合来避免掉一些误判,如add和sub的顺序调换,降低mov的命中概率等等;
2、optimizer完全是默认的,还没有观察和改造。这部分就不深入研究啦。
>>>> 解题报告二
前不久自己也思考过能不能将热门的AI技术与CTF比赛结合起来,没想到就意外发现了这道题,感觉非常有趣。
>>>> 一、题目解析
首先,阅读题目。发现模型是使用深度学习来检测一段二进制代码中是否存在函数入口,存在的话将入口点标为1,否则为0。而题目需要我们对模型机进行微调,使得模型能够识别出一段不能识别的二进制代码的入口点。说白就是我们需要造一些样本,重新训练模型使得模型能够识别给定样本的函数入口点并保证不是入口点也能识别正确。题目提供了模型的文件和样本点2个数据。
接着,我们需要看看模型是使用什么框架生成的,查看模型文件的二进制代码,发现是hdf文件:
使用python的h5py工具解析,发现模型是基于theano工具的keras框架生成的,使用的RNN算法:
代码:
之后使用keras自带的模型绘制接口,将模型结构图打印出来:
代码:
知道了模型使用的框架,那么之后重新训练模型就非常方便了。
再来看看样本点:观察发现,一段正常二进制代码应该会存在很多个0,而样本点存在很多个1且没有0,同时单字节存在几个256(单字节最大应该只有255),所以这里的二进制代码是经过加1运算后的代码,我们通过减1再进行反汇编,看看函数的入口特征:
题目提示说,这一段代码的函数入口点是在下标为40的点,也就是上面所示的 0048E028 地址的 sub esp,0xC 这一句函数的入口点模型无法识别,这个函数反编译后的结果其实是一个switch结构,类似如下:
题目解析到这里,接下来说说如何解答。
>>>> 二、解题方法
首先,我们把样本点输入到模型中,看模型预测的结果,发现每个点输出一个包含2个元素的向量,第1个表示不是入口点的概率,第2个表示是入口点的概率。
从输出的结果可以看出,除去第40个点的概率是 [0.722,0.278],其他基本都是 [1,0],说明模型差一点就能识别出函数的入口点,而其它的点也没有识别错误。
模型预测的结果:
那么,最简单的办法就是将样本点随便改改,然后输入到模型重新训练,应该就能识别。(这里题目没有要求模型需要保证在原始的样本中保持某一个准确度)
我这里将样本点的第0个点 50 改成 49,也就是将第一句的 xor eax,eax 改成 xor al,al ,作为模型的一个训练样本,使用SGD作为优化方法,参数学习率 lr=0.0001, 动量momentum=0.9,使用的迭代次数为10次,并且冻结除RNN的其他层,再重新训练,结果如下:
代码如下:
>>>> 三、结束语
感觉这道题的逆向要求不是很高,然后深度学习算法的要求也不是很高,但是两者结合起来感觉挺有意思的。不过,没有其他限制的话,模型是可以过拟合的(只识别一个提供的样本点),为了避免模型过拟合,主办方其实可以提供一些样本,要求新的模型在这些样本下也能够保持准确度。