首页
社区
课程
招聘
[原创]NSCTF - Reverse WirteUp
发表于: 2015-10-2 10:33 21796

[原创]NSCTF - Reverse WirteUp

2015-10-2 10:33
21796

这图片简直弄不对啊..
发现群里小伙伴都在NSCTF,闲来无事也参与了一下,只做了Reverse部分,其他的都没看(当然Twitter这种送分的题目我还是看了下下)
现在比赛已经结束了,写写WirteUp练习练习,很少写不是很规范,请大家指点。

## 0x01 Re100 简单的逆向
---
这题确实挺简单的,算法我也没有怎么分析,ASPack加壳,用ESP定律直接过,也不需要脱壳,直接可以分析程序了,其实只要在OEP的地方来个硬件断点,可以直接到的。


来到入口点,直接搜索ASCII字符串:

我们找到`please xxx --- `这一句,直接看汇编就会发现验证密码是`nsF0!Sx01`,直接输入,可跳出输入循环打印flag。

开始我以为flag就是这样子的,交上去发现并不是,而输入循环跳出后,只有一个jle影响一个函数选择,OK我强制进入这个函数,发现里面其实做了xor解码


解码过后:
`"flag:{NSCTF_md5712df97688fe0b7a399f076d9dc60437}"`
提交,得分!

## 0x02 Re250 较简单的逆向
---
这名字我真心有点醉,打开以后发现是个GUI程序,GetFlag不能点,直接OD断`GetItemWindowText`,结果发现并没有断下,确定并不是通过textChange进行GetFlag解锁;
ok直接用一个老办法:灰色按钮克星,这软件不知道啥时候下的了,上来就把我虚拟机搞挂了(伤不起),重新来过以后,解锁GetFlag按钮,

点击后,算法基本没变,还是依然的xor解码:

解开后Flag:
`"flag:{NSCTF_md50b7dfc60761e798328a0d9793f96d4f7}"`

## 0x02 Re400 逆向
---
这题还挺有意思的,也花了一番功夫;
运行一下发现只甩你一句Reverse!???????,看来没有什么输入之类的东西,用IDA来解析一下exe分析,main函数如下:


前面这么多,其实就只判断了一下环境变量`_MEIPASS2`存不存在,区别在于是否执行下面一段代码:


这段代码在!sub_403380(&v25)判断失败后,也依然会执行,ok用OD执行一下,发现实际是向C盘中的临时目录写入N个文件,并设置_MEIPASS2环境变量为`_MEIPASS2 = C:\xxx\xxx\temp\_MEIPASS2XX(临时目录)`,然后通过`CreateProcess`函数,**在执行一遍自己**,


这时候回想上文判断环境变量的代码会直接成功。进行不一样的执行代码;
我在这里绕了不少时间,总想着强制跳转进入,然后就各种错误T_T。我省略了很多分析阶段的过程,这中间比较多的就是对路径的解析,我也没去细看是不是有信息在里面,额,其实是我确实不知道怎么写,看来还是需要看看别人的分析

分析到这里,我做了一个假设,既然文件中看见了Python27.dll与*.pyd等文件,那么估计是用来执行Python脚本的,在Python27.dll中,可以铜鼓`Python27.PyRun_SimpleString`来执行一段Python命令,我们在结果中看到的Reverse!???????,也并没有在程序字符串中出现,并且结合bz2等模块,猜测他是把压缩过后的代码,overloop到文件结尾,然后通过文件名或者什么其他手段解析并解压,最终调用`Python27.PyRun_SimpleString`函数执行之,

其实之前生成的这么多文件,也证明是铜鼓这种方法,不多说
OK我建立了_MEIPASS2 = C:\1234\,并把在临时目录中生成的文件也放在改目录中,此时程序中环境变量存在的条件满足,进入关键函数
`sub_403A10`:


程序判断加密表索引(附加在exe文件末尾)中的文件名,以b开头的文件名,进行一种处理,以s开头的文件名,进行另一种处理:


针对s开头的文件,解压过后,发现`sReversre03`文件名会解出如下Python代码:

        data = \."\x1c\x7a\x16\x77\x10\x2a\x51\x1f\x4c\x0f\x5b\x1d\x42\x2f\x4b\x7e\x4a\x7a\x4a\x7b" +\."\x49\x7f\x4a\x7f\x1e\x78\x4c\x75\x10\x28\x18\x2b\x48\x7e\x46\x23\x12\x24\x11\x72"+\."\x4b\x2e\x1b\x7e\x4f\x2b\x12\x76\x0b"  
        '''
        char buf[] = "flag:{NSCTF_md5098f6bcd4621d373cade4e832627b4f6}";
        int _tmain(int argc, _TCHAR*argv[]) {  
        printf("%d\n", strlen(buf));  
        char key = '\x0b';
        buf[47] ^= key;
        for (int i = 1; i< 48; i++) {
                buf[48 - i - 1] ^= buf[48 - i];
        }
        return 0;
        }
        '''
        print "Revese it?????????"

haaaa我看到了print Reverse!???????,中间还嵌入了一段C代码?提交一下这个flag发现不对,运行一下C代码看看:

得到的结果发现和上面的data非常相似,那么对data数据做正向的xor解密,即可得到最终的flag:

        import sys
        import re
        import string
       
        data = "[1c[7a[16[77[10[2a[51[1f[4c[0f[5b[1d[42[2f[4b[7e[4a[7a[4a[7b[49[7f[4a[7f[1e[78[4c[75[10[28[18[2b[48[7e[46[23[12[24[11[72[4b[2e[1b[7e[4f[2b[12[76[0b"
       
        tmp = re.findall(r'\[.{1,2}', data)
        datas = []
        for i in tmp:
            datas.append((string.atoi(i[1:3], 16)))
       
        print len(datas)
       
        for i in range(0, len(datas)-1):
            datas[i] ^= datas[i + 1]
       
        print datas
       
        for i in datas:
            print chr(i),

*output:*

        49
        [102, 108, 97, 103, 58, 123, 78, 83, 67, 84, 70, 95, 109, 100, 53, 52, 48, 48, 49, 50, 54, 53, 53, 97, 102, 52, 57, 101, 56, 48, 51, 99, 54, 56, 101, 49, 54, 53, 99, 57, 101, 53, 101, 49, 100, 57, 100, 125, 11]
        f l a g : { N S C T F _ m d 5 4 0 0 1 2 6 5 5 a f 4 9 e 8 0 3 c 6 8 e 1 6 5 c 9 e 5 e 1 d 9 d }

## 0x03 Re500 ????(名字我不记得了)
---

这题我没有提交,等我弄出来,发现这比赛在不知不觉中已经结束了(囧),得出的flag不具有确定性,这里就说下解题的思路吧
这题其实就是pyc的逆向,用uncompyler直接反编译一下:

反编译失败,出来一大堆字节码,看不懂也听不懂
既然是字节码,Python中dis,marshal模块可以协助我们分析PyObject,那我可以自己写程序翻译源代码,然后对应翻译反编译pyc得到字节码文件,尝试还原源码。

贴出我们反编译pyc为字节码的程序,这个程序不是我写的,也是以前在网上找的,确实忘记了原作者是哪个,现在百度搜这个东西找到的链接有很多:
> http://blog.csdn.net/I2Cbus/article/details/41383401
一模一样,大家可以参考学习

反编译出Revesre04.pyc的字节码我就不贴了,太多了
我大致写一下字节码对应的代码(可能不是非常的准确,但是本次逆向是够用了,具体可以去了解python的实现机制)

                                NOP                 
              1 LOAD_CONST               0 ("M,\x1d-\x18}E'\x1ezN~\x1b*\x19+\x12%\x1d-")
              4 LOAD_CONST               0 ("M,\x1d-\x18}E'\x1ezN~\x1b*\x19+\x12%\x1d-")
              7 NOP                 
              8 LOAD_CONST               0 ("M,\x1d-\x18}E'\x1ezN~\x1b*\x19+\x12%\x1d-")
             11 LOAD_CONST               1 ('I\x7fM(I{I\x7fJ.\x16wWcRj\x0e6\x0fn')
             14 BINARY_ADD         
                         #字符串 "M,\x1d-\x18}E'\x1ezN~\x1b*\x19+\x12%\x1d-" + 'I\x7fM(I{I\x7fJ.\x16wWcRj\x0e6\x0fn' 下同
             15 LOAD_CONST               2 ('Zo\nn\x0fk\t1R7\x03g\x067\x00eUb\x043')
             18 BINARY_ADD         
             19 LOAD_CONST               3 ('\x014\x071Rr\x14x\x19~D?q"a5s,A%')
             22 BINARY_ADD         
             23 LOAD_CONST               4 ("\x10'\x11uLyA%\x1d|DrFv\x12t\x11#B&")
             26 BINARY_ADD         

             27 LOAD_CONST               5 ('GsKzK*O)\x1c%GuC>\x1e\x7f\x1b+\x19*')
             30 BINARY_ADD         
             31 LOAD_CONST               6 ('\x1e&\x14-\x1f/\x1axAqBq@yO-LtE}')

                         34 BINARY_ADD         
             35 LOAD_CONST               7 ('\x1b,MuBp\x12')
             38 BINARY_ADD         
             39 STORE_GLOBAL             0 (data)
*分割*

         5 LOAD_CONST               9 (None)
         48 IMPORT_NAME              1 (os)
         51 STORE_NAME               1 (os)
        #实际上就是import os

         150 LOAD_CONST              10 (0)
     153 STORE_GLOBAL            10 (count)
        #实际就是 count = 0 (global)

        193 STORE_NAME              14 (decrpyt)
    196 LOAD_CONST              14 (<code object GetFlag1 at 029C9F98, file "decrypt.py", line 34>)
        #定义函数def decrpyt(?):

        0 LOAD_FAST                0 (string)
        3 LOAD_CONST               0 (None)
        6 LOAD_CONST               0 (None)
        9 LOAD_CONST               1 (-1)
        12 BUILD_SLICE              3
        15 BINARY_SUBSCR      
        16 RETURN_VALUE      
        #BUILD_SLICE就是切片操作,BINARY_SUBSCR则是取值操作[]
        #对应代码: string[None:None:-1]

我当时比较纠结的就这些指令,我贴出源码来大家可以对应着看,到时候我也想去系统学习一下这方便的知识,形成学习笔记:

        data = "M,\x1d-\x18}E'\x1ezN~\x1b*\x19+\x12%\x1d-" + 'I\x7fM(I{I\x7fJ.\x16wWcRj\x0e6\x0fn' + 'Zo\nn\x0fk\t1R7\x03g\x067\x00eUb\x043' + '\x014\x071Rr\x14x\x19~D?q"a5s,A%' + "\x10'\x11uLyA%\x1d|DrFv\x12t\x11#B&" + 'GsKzK*O)\x1c%GuC>\x1e\x7f\x1b+\x19*' + '\x1e&\x14-\x1f/\x1axAqBq@yO-LtE}' + '\x1b,MuBp\x12'
        import os, sys, struct, cStringIO, string, dis, marshal, types, random
        count = 0
       
        def reverse(strings):
            return strings[::-1]
       
        data_list = list(reverse(data)[1:])
       
        def decrpyt(c, key2):
            global data_list
            global count
            try:
                data_list[count] = c ^ key2
                count += 1;
            except:
                pass
            pass
       
        def GetFlag1():
            global data_list
            global count
            key = struct.unpack('B', data[len(data) - 8])[0]
            for c in data_list:
                if (count == 0):
                    decrpyt((struct.unpack('B', c))[0], key)
                else:
                    key = struct.unpack('B',data[len(data) - 3])[0]
                    decrpyt(struct.unpack('B',c)[0], key)
                   
            for c in data_list[::-1]:
                print chr(c)
            pass
       
        def GetFlag2():
            global data_list
            global count
            key = struct.unpack('B', data[len(data) - 11])[0]
            for c in data_list:
                if (count == 0):
                    decrpyt((struct.unpack('B', c))[0], key)
                else:
                    key = struct.unpack('B',data[len(data) - 4 - count])[0]
                    decrpyt(struct.unpack('B',c)[0], key)
            for c in data_list[::-1]:
                print chr(c)   
            pass   
       
        def GetFlag3():
            global data_list
            global count
            key = struct.unpack('B', data[len(data) - 5])[0]
            for c in data_list:
                if (count == 0):
                    decrpyt((struct.unpack('B', c))[0], key)
                else:
                    key = struct.unpack('B',data[len(data) - 2 - count])[0]
                    decrpyt(struct.unpack('B',c)[0], key)
            for c in data_list[::-1]:
                print chr(c)        
            pass
       
        def GetFlag4():
            global data_list
            global count
            key = struct.unpack('B', data[len(data) - 1])[0]
            for c in data_list:
                if (count == 0):
                    decrpyt((struct.unpack('B', c))[0], key)
                else:
                    key = struct.unpack('B',data[len(data) - 1 - count])[0]
                    decrpyt(struct.unpack('B',c)[0], key)
            count = 0
            for c in data_list[::-1]:
                print chr(c)
            pass
       
        def GetFlag5():
            global data_list
            global count
            key = struct.unpack('B', data[len(data) - 9])[0]
            for c in data_list:
                if (count == 0):
                    decrpyt((struct.unpack('B', c))[0], key)
                else:
                    key = struct.unpack('B',data[len(data) - 3 - count])[0]
                    decrpyt(struct.unpack('B',c)[0], key)
            for c in data_list[::-12]:
                print chr(c)        
            pass
       
        GetFlag4()

直接运行GetFlag4()
既可以得到flag:
`flag:{NSCTF_md576d958d8a8640dfe2ada4811aef59b26}`
因为网站已经关闭,没法验证这个flag是否就是最终的flag,还是有别的坑,不过源码以及100%还原了,不对的话,还请大家告诉我,我在继续分析。

我的blog: http://yzolaphilo.com/
欢迎大家访问


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 3
支持
分享
最新回复 (5)
雪    币: 289
活跃值: (83)
能力值: ( LV9,RANK:200 )
在线值:
发帖
回帖
粉丝
2
还有两个exploit题呢
2015-10-2 12:14
0
雪    币: 341
活跃值: (143)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
3
路过学习看看
2015-10-2 21:41
0
雪    币: 15
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
呵呵                              被我发现了
2015-10-6 12:39
0
雪    币: 261
活跃值: (55)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
5
额?被你发现啥了哇?
2015-10-6 21:50
0
雪    币: 28
活跃值: (10)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6
re400看得不是很明白 能不能加个好友详细说一下?
2016-9-6 12:32
0
游客
登录 | 注册 方可回帖
返回
//