首页
论坛
课程
招聘
[原创]CTF2017第7题分析
2017-6-15 12:02 2381

[原创]CTF2017第7题分析

2017-6-15 12:02
2381

 

1.调试分析

OD加载,发现入口不是OEP指定的,估计有tls,直接清掉了tls,然后根据正常运行的程序,修复了OEP,这时就能正常断在OEP了,后面调试发现有个文件校验,有修改就退出程序了.

这里修改后,就可以patch程序了.

 

调试过程中,发现输入后验证就会异常,刚开始根据异常链查了半天,陷进去了,后来翻了下作者之前的帖子,发下之前有个Cm是在顶级异常处理那处理的.

直接IDA找到:

 

看了下,就是判断异常类型,然后发消息,直接索引ds:Msg,定位到关键点:

 

 

调试时候,可以输入字符串后,断在40E3E5,然后设置EIP40E3ED,就可以跟踪字符串的验证操作了.

 

大概流程是:

004104FC  |.  FF15 283E4500      call dword ptr ds:[<&USER32.GetDlgItemTextA>] 

先用GetDlgItemTextA读取到输入字符串,然后解码一个函数00411B30并调用 

00410558  E8 D3150000  call 7crackme.00411B30    

这里面先是对输入字符串依次XOR 0xCC


然后就是对各个字符查表处理,得到的结果再通过sub_410F75 异或移位处理,然后在sub_411975中每个字符通过对4的商和余数,转化成2个字节,形成的字节流要和已知的一致,相关具体数据见代码.

验证通过后,会再根据输入字符串,解码一段数据,还原成功时候弹框用的函数.

 

2.  程序实现

程序是边调试边修改的,变量有点乱,不过可能更方便看流程.

 

function ctf_7() {

    //首先根据确定表,反推出一个确定串

    var checkBuf = new Buffer([

        0x02, 0x02, 0x00, 0x03, 0x00, 0x00, 0x02, 0x03, 0x00, 0x01,

        0x02, 0x03, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, 0x02, 0x02,

        0x02, 0x03, 0x02, 0x03, 0x01, 0x00, 0x02, 0x02, 0x02, 0x01,

        0x02, 0x03, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x02, 0x03,

        0x02, 0x01, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,

        0x00, 0x03, 0x01, 0x02, 0x02, 0x03, 0x02, 0x00, 0x00, 0x02,

        0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00,

        0x02, 0x02, 0x02, 0x03, 0x00, 0x02, 0x01, 0x00, 0x00, 0x03]);

 

    var resultBuf = new Buffer(checkBuf.length / 2);

    var pattern = new Buffer("0123456789ABCDEF");

 

    for (var i = 0; i < checkBuf.length; i=i+2)

    {

        var iTemp = checkBuf.readUInt8(i) * 4 + checkBuf.readUInt8(i + 1);

        resultBuf[i / 2] = pattern[iTemp];

    }

 

    console.log(resultBuf.toString());

 

    var resultBuf2 = Buffer.from(resultBuf.toString(), 'hex');

    console.log(resultBuf2);

    console.log(resultBuf2.toString('hex').toUpperCase());

    //return;

    //原始串加密过程

   

    var srcBuf = new Buffer("12345678901234567890");

  

 

    //2. 查表

    var tableBuf = new Buffer([

        0x89, 0xBC, 0x95, 0xFC, 0xFB, 0xBA, 0xED, 0x9A, 0xBB, 0xAE,

        0xFE, 0x99, 0xA2, 0x98, 0xB9, 0xF9, 0x9F, 0x84, 0x9C, 0xFD,

        0x83, 0xAD, 0xB6, 0xA9, 0xA5, 0xF5, 0x8C, 0xA7, 0x9E, 0x96,

        0x8A, 0xF4, 0x85, 0xBE, 0xA8, 0x8F, 0x86, 0xAF, 0x88, 0x9D,

        0x87, 0xBF, 0xFF, 0xA1, 0x8B, 0x81, 0xA0, 0xAB, 0x8E, 0xBD,

        0xB5, 0xAA, 0x82, 0x94, 0xA4, 0x8D, 0xA3, 0xF8, 0xB4, 0xFA,

        0x9B, 0xA6, 0xB8, 0x80

    ]);

 

    var pattern2 = new Buffer("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");

    var initBuf = new Buffer(srcBuf.length);

 

    for (var i = 0; i < srcBuf.length; i++) {

        //枚举,修改srcBuf的值

        for (var loopIndex = 0; loopIndex < pattern2.length; loopIndex++) {

             srcBuf[i] = pattern2[loopIndex]; 

            //1. xor 0xCC

            srcBuf[i] ^= 0xCC; 

            //定位索引

            var iFoundIndex = 0; 

            for (var index = 0; index < tableBuf.length; index++) {

                if (srcBuf[i] == tableBuf[index]) {

                    iFoundIndex = index;

                    //console.log("iFoundIndex: " + iFoundIndex.toString(16));

                    for (var iCount = 0; iCount <= i; iCount++) {

                        if (iFoundIndex == 0) iFoundIndex = 1;

 

                        //余数+5,要循环的次数,再加上原来的索引 /0x40(超过表大小,就从头开始),得到新的值

                        iFoundIndex = parseInt(iFoundIndex / 5) + 5 + iFoundIndex;

                        iFoundIndex = iFoundIndex % 0x40; 

                        //如果为0,则设1

                        if (iFoundIndex == 0) iFoundIndex = 1; 

                    }

                    //得到新的索引后,再查表,更新为查到的新值

                    srcBuf[i] = tableBuf[iFoundIndex]; 

                    srcBuf[i] = 8 * (srcBuf[i] ^ 0xCC) | ((srcBuf[i] ^ 0xCC) >> 5); 

                    break;

                }

            }

           

            if (srcBuf[i] == resultBuf2[i]) {

                console.log("found :" + srcBuf[i].toString(16) + " " + resultBuf2[i].toString());

                console.log("i: " +i+" found2 :" + pattern2[loopIndex].toString());

 

                initBuf[i] = pattern2[loopIndex];

               //break;

            }

            else {

                //console.log("not found :");

            }

        }

    }

 

    console.log(initBuf);

    console.log(initBuf.toString());

 

}

结果其实有多种组合,这个不确定是不是有其它的限制条件没看到,不过也是考虑到时间,直接从这里面选了带Pediy2017的字符串,尝试了几个去验证解码上面提到的函数(还原成功时候弹框用的函数,其实也可以验证函数中的操作码),确定结果:

BwnsAtPediy2017KX9Ok



[注意] 欢迎加入看雪团队!base上海,招聘CTF安全工程师,将兴趣和工作融合在一起!看雪20年安全圈的口碑,助你快速成长!

收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回