网鼎杯第三场Writeup

SimpleSMC



这里的0x400aa6函数点过去一看就可以发现它是乱的字节无法执行,根据题目SMC(Self-Modifying Code)可以猜到这个函数就是被修改的目标了


查看它的交叉引用可以发现有两个函数有调用sub_400c48关键代码如下


是一个函数字节码异或的固定调用,直接写个IDC脚本解就行查看这个函数的交叉引用是在init_array中,所以是在调用之前调用的sub_400bac


根据key进行逐字节异或,这里的key从调用方可以看出是Input的一部分,所以要猜key

根据密码学常识,单表替换即key仅有一个字节的时候通常是根据词频统计来解决的,在机器码中一般00较多而本题是类似于维吉尼亚的多表替换,循环长度为7,如果当函数字节足够长的话也是可以用上述方式解决的--将整个密文分成7段,每段内独立进行词频统计。尝试了一下,本题由于密文不够大,因此统计规律应用的不是很顺畅,仅能解出密钥的最后一个字节e

既然词频统计不好使的话,就得从一些固定字节来思考了这个题目里key不是input的开头,因此没有固定的内容但对于一个被加密的函数而言,如果非手写汇编的话,通常会以push rbp;mov rbp, rsp开头,通过这几个字节进行异或可以得到一个全可见字符的串

于是根据这个key也可以写出一个解密脚本:


要注意的一点是,这两个异或顺序是不可变的--因为它们判断结束的标志是加密前的0xC3,而先异或0x41e1b0时是不会产生0xc3的中间字节的,但是如果先异或key,会产生0xC3的中间字节,导致第二次异或时被截断当然如果将解密循环改为固定长度就可以规避这个BUG

解密得到


其中a1是input,sub_4009AE很明显对它进行处理,然后sub_400360进行校验

那么我们首先看一下check方法emmmm有点乱,我觉得不太对劲,退回去看一眼这是plt段的跳转,也就是说这是一个静态链接的库函数

再根据它的另一个函数来想,很明显就是strcmp啦

那么只需要专心看sub_4009AE是怎么变换的了点进去看注意这里有花指令,按D将它们调成数据后,将脏字节E8改成90(NOP)即可

然后即可F5了
这里是一个63x5的迭代内层计算同样有花指令,同样清除以后即可反编译


外层计算由于不影响参数,因此只是重复计算另一方面,由于内层计算全部都是异或,因此偶数次计算会使得数组还原。我觉得是出题人的失误23333不过影响也不大就是了

内层计算的逆运算比较简单,逆序异或即可


l_like_pack

IDA加载一看啥都没有,再根据题目名显然是个壳windows下脱壳相对而言麻烦一些,ExeInfoPe查壳啊、各种壳的针对性操作啊啥的Linux下一方面系统开源随便魔改,另一方面有一个/proc/pid/mem的文件可以直接读取进程的内存,使得dump极为容易

本题放到系统下跑起来后发现如果输入会回显“NO”,而不输入的话大概三秒就会自动结束这显然是alarm函数的功劳

如果仅是alarm函数的话,其实可以比拼一下手速,毕竟三秒钟还算在人类的反应速度内,另一方面也可以通过sh脚本来执行dump试了一下cat /proc/pid/mem会报错,在这里有官方的说明,提供了三种方法

  1. 获取maps,根据模块地址来读取程序的内存

  2. open mem以后attach目标进程使其暂停,然后即可读

  3. gcore pid

尝试了一下,其中第一种方法可以直接使用--因为只是读取mem文件通过这个脚本


操作方法如下:后台起一个进程可以快速获得pid然后通过上面的脚本来dump

而第二、第三种方法由于依赖ptrace,对于使用ptrace(TRACE_ME)的进程就会报错本题中的程序就有使用这个方法来反调试

对于trace_me,有两种方法可以绕过:

  1. 直接用调试器启动子进程,断在ptrace之前然后跳过它的执行

    不过这种方法会被alarm中断掉,当然也很好绕过,只需要同样跳过alarm的执行就好 缺点有两个,1是浪费时间,2是静态链接很难识别,本题是使用动态链接,相对还算好找

  2. 通过LD_PRELOAD来覆盖函数

    LD_PRELOAD可以指定加载库,此时如果库中有与其他动态链接库同名的函数将会覆盖,使得原函数失效

这里讲一下后者的操作方法:


将上述代码编译成sogcc --shared fake.c -o fake.so然后通过LD_PRELOAD加载LD_PRELOAD=./fake.so ./re此时即可发现alarm失效

然后通过ps或其他方法查到pid后,用gcore pid即可dump

然后通过字符串搜索即可找到main函数一个数组乱序比对,直接dump即可得到flag

a = [11, 8, 7, 7, 8, 12, 3, 2, 16, 6, 13, 5, 7, 16, 4, 1, 0, 15, 16, 8, 3, 6, 14, 16, 0, 8, 6, 9, 12, 14, 13, 11, 15, 7, 11,14]

for i in range(36):
    print(chr(Dword(a[i]*4+0x60f0e0)+45)),


最好的语言

这题问题太大了!做之前我先去找了web队友过来严阵以待,打开以后根本不是PHP!

打开以后发现跟之前SUCTF的一题一毛一样,给了解析过后的pyc文本当时写过轮子可以按照pyc格式进行解析和还原这个pyc解析网上大概有两种pyc解析1pyc解析2

除了都把解析出的字节码删去以外,区别主要在两点属性标题一种为argcount另一种为<argcount>xxx</argcount>排列顺序一种将consts放在names之前,另一种将consts放在之后

我写的脚本仅能针对前者,而本题遇到的后者需要手动修改一下不过其实难度也不大,通过正则替换还是比较容易的

脚本在这里

解析得到pyc,然后在线反编译即可得到python源码


前后两段是通过随机数异或出来的,中间一段则是md5分析一下可以知道_函数加密后长度不变,因此12~12+32扔去解密得到613u21i前一段由"flag"得到key="5914"后一段由结尾字符"}"得到key的第二位为8其余位爆破,筛选出在ASCII范围内的,然后肉眼选择看起来像的


soEasy

题目叫soeasy,应该不难,运行起来给了一个奇怪的地址,输出超长字符串直接报错,目测战溢出。

gdb 运行,生成pattern,确定偏移为76,发现上面地址为栈地址,没有开nx,直接扔shellcode。

最终脚本


pesp

正常选单题目,开正常保护。

在change_item 出存在堆溢出,堆申请大小可控,可以直接做fastbin attack。

发现有个secret函数,很开心。。。。。。。。。。

劫持程序流过去就打印一个假的flag。。。。。。。。

直接写got因为pattern对齐会破坏之后的函数调用,所以利用修改bss的堆指针,达到任意写

最终脚本




note

拿到题目名字叫deathnote,一瞬间想起pwnable,尝试输入负数下标志,失败。

ida打开,发现没有用atoi,而是自己的函数转换数字。

输入-10 ,存在相同和alivenote相同漏洞,然而八字节变成了四字节

上次写这种shellcode的过程相当痛苦,决定找其他方法做。作者自己实现的堆申请和释放函数。

malloc 

free

发现data区域有指向自己的指针可以任意读写code空间,成功leak libc地址,距离成功一大半。最后发现,还是需要写shellcode,由于每次只能输入4byte,无法修改高四位指针。卒!!!!


本文作者:白帽100安全攻防实验室

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/75049.html

Tags:
评论  (0)
快来写下你的想法吧!

白帽100安全攻防实验室

文章数:22 积分: 52

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号