看雪.纽盾 KCTF 2019 Q3 | 第八题点评及解题思路
2019-10-02 19:00:00 Author: mp.weixin.qq.com(查看原文) 阅读量:61 收藏

稷下三贤者培养了许多极具天分的弟子,孙膑是其中佼佼者之一。这个天才少年将兵法与机关术巧妙地结合在一起。
孙膑的成果令师兄庞涓感到威胁,甚至当众诋毁他。
一次,孙膑在调查遗迹的途中遭遇狂暴的魔种。被追赶时摔下山崖,埋入一片废墟中。田忌发现好友失踪闯入废墟,试图解救孙膑。不幸的是,触动机关,田忌被卷入黑暗的漩涡。

造成事故的巧合并非偶然。庞涓精心策划的完美报复实现了。后来孙膑被救出,保住了生命,代价则是双腿和好友田忌。
田忌,一定还在某个地方活着,孙膑坚信。就像噩梦的夜晚,田忌焦急呼唤着他名字一样,现在轮到他以机关术的力量,重新打开无边无垠的时空之门,将最好的朋友带回家。

题目简介

本题共有1008人围观,最终只有13支团队攻破成功。第一名LookLook战队耗时约16个小时,成功破解此题。看似简单的题目,实际上包含出题人精心策划的巧妙算法。
攻破此题的战队排名一览:
接下来我们一起来看一下这道题的点评和详细解析吧。
看雪评委crownless点评
该题目假装是一个基于ECC椭圆加密求解的题目,如果按照ECC解法做反而是做不出来的。作者还实现了一个很简单的反调试壳。


出题团队简介
本题出题战队 iret:
下面是团队简介:

某安全公司实习生,目前正在学习逆向和木马分析,希望能从各位大佬身上学习并提升自己。



设计思路
1、该题目假装是一个基于ECC椭圆加密求解的题目。之前发了一篇ECC椭圆加密的原理分析:https://bbs.pediy.com/thread-253672.htm,相信误导了不少解题朋友,在此给大家道歉,如果按照ECC解法做反而是做不出来的,具体解法在源码中。
2、题目说明:

如果按照ECC解法:

根据椭圆曲线的基本概念,首先给出了椭圆曲线Ep:Ep = y^2 = x^3 + 125*x 以及关键的参数:素域p=127,基点G=(11,4) 公钥K=(120,41)。

私钥在代码和新增的区段中都有说明,没有给出直接提示:

私钥在源代码中的体现:

一个简单的异或可以得到x=9。

而根据椭圆曲线定义:
公钥K = 基点G * 私钥k

所以私钥=x=9。
但实际上的变换操作为,加密函数的源代码:

未做混淆,攻击方可以直接通过阅读IDA获取。
 
代码手动写了一个超级简单的反调试壳。

首先通过010Editor给程序新增加了一个区段,区段名顺便提示了私钥:

 
然后把程序原OEP更改到了新增的区段Offset处:
使用x32dbg后,使用了:
mov byte ptr ss:[ebp-5],0
mov eax, dword ptr fs:[0x30]
mov al, byte ptr [eax + 2]
mov byte ptr [ebp - 5], al
movzx eax, byte ptr [ebp - 5]

几行简单的代码判断是否处于调试状态。

如果处于调试状态,则设置两个循环跳转使得程序sleep。

如果未处于调试状态,则jmp到程序真实的OEP。

这里手动将一部分实际应用到的汇编代码拷贝了过来,起到一点干扰作用。

 
输入判断:

最开始将用户输入的字符串传入的加密函数ECode得到了一个加密的字符串,将加密字符串的ASCII打印出来如下:

 
保存该字符串的ASCII:

 
然后将用户输入后的字符串加密后与该字符串进行比较:

 
最后删除解密函数以及多余的打印信息build成exe进行手动加壳。

解题思路
本题解题思路由看雪论坛 ODPan 提供:
初步分析程序
start有一处PEB(02:BeingDebugged)反调试,直接跳过。程序有混淆,但可以带着分析程序。
k_is_9:0042F000 start           proc near
k_is_9:0042F000                 mov     byte ptr [ebp-5], 0
k_is_9:0042F004                 mov     eax, large fs:30h
k_is_9:0042F00A                 mov     al, [eax+2]
k_is_9:0042F00D                 mov     [ebp-5], al
k_is_9:0042F010                 movzx   eax, byte ptr [ebp-5]
k_is_9:0042F014                 test    eax, eax
k_is_9:0042F016
k_is_9:0042F016 loc_42F016: ; CODE XREF: start:loc_42F08Aj
k_is_9:0042F016                 jnz     short loc_42F08A
k_is_9:0042F018                 jmp     sub_4110FF

程序的关键函数,根据界面提示搜索字串直接定位。 流程很明确获取输入,生成key,和目标字串进行比较检测。
int __usercall keyFunc@<eax>(int a1@<xmm0>)
{
  int v1;
  int v2;
  int v3;
  int v4;
  int v5;
  int v6;
  int v7;
  int v8;
  int v9;
  int v10;
  _DWORD *v11;
  int v12;
  int v13;
  void *v14;
  int v16;
  int v17;
  void *v18;
  char v19;
  struc_String *keyString_1;
  struc_String *keyString;
  int v22;
  char goalBuf[56];
  char v24;
  int v25;
  char v26;
  char v27;
  struc_String sting;
  int *v29;
  int v30;
  int v31;
  struc_String goalString;
  struc_String keyStringFromInput;
  int v34;
  int v35;
  int savedregs;
 
  G1.x = 11;
  G1.y = 4;
  v30 = j_timesPiont((struc_Point *)a1, &G1, times);
  v31 = v1;
  G2.x = v30;
  G2.y = v1;
  sub_4113B6((int)&keyStringFromInput, a1, byte_4252C2);
  v35 = 0;
  v2 = sub_411802(std::cout, "Ep = y^2 = x^3 + 125*x ");
  v3 = std::basic_ostream<char,std::char_traits<char>>::operator<<(v2, sub_411159);
  j_asmFun(v4, &v19 == &v19, v3, a1);
  v5 = sub_411802(std::cout, "Prime field p=127,base point G(11,4),publicK(120,41) please find private key k");
  v6 = std::basic_ostream<char,std::char_traits<char>>::operator<<(v5, sub_411159);
  j_asmFun(v7, &v19 == &v19, v6, a1);
  v8 = sub_411802(std::cout, "input your flag:");
  v9 = std::basic_ostream<char,std::char_traits<char>>::operator<<(v8, sub_411159);
  j_asmFun(v10, &v19 == &v19, v9, a1);
  getInput(a1, std::cin, &keyStringFromInput);
  v29 = &v16;
  v22 = sub_411447(&v16, a1, &keyStringFromInput);
  keyString = (struc_String *)calcuKey(a1, (int)&sting);
  keyString_1 = keyString;
  stringCopy(&keyStringFromInput, a1, keyString);
  releaseString(&sting, a1);
  goalBuf[0] = 0x5E;
  goalBuf[1] = 0x26;
  goalBuf[2] = 0;
  goalBuf[3] = 0x13;
  goalBuf[4] = 94;
  goalBuf[5] = 38;
  goalBuf[6] = 86;
  goalBuf[7] = 94;
  goalBuf[8] = 94;
  goalBuf[9] = 38;
  goalBuf[10] = 45;
  goalBuf[11] = 121;
  goalBuf[12] = 94;
  goalBuf[13] = 38;
  goalBuf[14] = 4;
  goalBuf[15] = 5;
  goalBuf[16] = 94;
  goalBuf[17] = 38;
  goalBuf[18] = 90;
  goalBuf[19] = 116;
  goalBuf[20] = 94;
  goalBuf[21] = 38;
  goalBuf[22] = 49;
  goalBuf[23] = 73;
  goalBuf[24] = 94;
  goalBuf[25] = 38;
  goalBuf[26] = 8;
  goalBuf[27] = 41;
  goalBuf[28] = 94;
  goalBuf[29] = 38;
  goalBuf[30] = 94;
  goalBuf[31] = 55;
  goalBuf[32] = 94;
  goalBuf[33] = 38;
  goalBuf[34] = 53;
  goalBuf[35] = 2;
  goalBuf[36] = 94;
  goalBuf[37] = 38;
  goalBuf[38] = 12;
  goalBuf[39] = 92;
  goalBuf[40] = 94;
  goalBuf[41] = 38;
  goalBuf[42] = 98;
  goalBuf[43] = 50;
  goalBuf[44] = 94;
  goalBuf[45] = 38;
  goalBuf[46] = 57;
  goalBuf[47] = 41;
  goalBuf[48] = 94;
  goalBuf[49] = 38;
  goalBuf[50] = 16;
  goalBuf[51] = 51;
  goalBuf[52] = 94;
  goalBuf[53] = 38;
  goalBuf[54] = 102;
  goalBuf[55] = 18;
  v18 = j_getThis_0((int)&v27);
  v11 = sub_4112C1(&v26, (int)goalBuf, (int)&v24);
  createString(&goalString, a1, *v11, v11[1], (int)v18);
  if ( stringCmp((int)&keyStringFromInput, a1, (int)&goalString) )
    sub_41186B("try again", v19);
  else
    sub_41186B("Congratulations~~", v19);
  v12 = system("pause");
  j_asmFun(v13, &v19 == &v19, v12, a1);
  v25 = 0;
  releaseString(&goalString, a1);
  v35 = -1;
  releaseString(&keyStringFromInput, a1);
  v18 = v14;
  v17 = v25;
  sub_411677((int)&savedregs, (int)&dword_41BC54);
  return j_asmFun((unsigned int)&savedregs ^ v34, 1, v17, a1);
}

分析核心的key生成函数
生成函数的依据是椭圆曲线方程,用输入字串的每个字符和字符的index进行倍点运算。
for ( i = 0; ; ++i )
  {
    len = getInpuKeyLen((int)sting, a1);
    if ( i >= len )
      break;
    index = i;
    oneKey = *(char *)getKeyByIndex((int)sting, a1, i);
    pointPair_1 = (struc_PointPair *)timesPiontByOneKey(a1, &pointPair, index, oneKey);
    copyPoint_1(&pointPair_2, a1, pointPair_1);
    j_addZuobiao2Buf_0(a1, (struc_String *)&resultStr, pointPair_2.p1_x);
    j_addZuobiao2Buf_0(a1, (struc_String *)&resultStr, pointPair_2.p1_y);
    j_addZuobiao2Buf_0(a1, (struc_String *)&resultStr, pointPair_2.p2_x);
    j_addZuobiao2Buf_0(a1, (struc_String *)&resultStr, pointPair_2.p2_y);
  }

运算过程如下:
int __usercall timesPiontByOneKey_0@<eax>(struc_Point *a1@<xmm0>, struc_PointPair *result, int index, int onekey)
{
  int y1AfterTimes;
  int y2AfterTimes;
  struc_Point p1;
  struc_Point p2;
  int v9;
  int savedregs;
 
  p2.x = j_timesPiont(a1, &G1, 17);
  p2.y = y1AfterTimes;
  p1.x = index * j_timesPiont(a1, &G2, 17) % 127;
  p1.y = onekey * y2AfterTimes % 127;
  copyPoint(result, (int)a1, (int)&p2, (int)&p1);
  sub_411677((int)&savedregs, (int)&dword_417788);
  return j_asmFun((unsigned int)&savedregs ^ v9, 1, (int)result, (int)a1);
}

程序中有连个G点,G1(11,4),G2(14,91);根据G1,G2分别生成P1和P2两个点。
完成计算后分别将带你的坐标p.x,p.y保存。
结果对比
生成目标字符串和以计算出坐标为内容的字串,进行比对。
createString(&goalString, a1, *v11, v11[1], (int)v18);
  if ( stringCmp((int)&keyStringFromInput, a1, (int)&goalString) )
    sub_41186B("try again", v19);
  else
    sub_41186B("Congratulations~~", v19);
逆向输入
public class Q3CTF8 {
     
    static char [] result1 = {0x13,0x5E,0x79,0x05,0x74,0x49,0x29,0x37,0x02,0x5C,0x32,0x29,0x33,0x12};
    static char key;
     public static void main(String[] args)
     
{
        for(int k = 0;k<result1.length;k++)
        {
            key = result1[k];
            for(int i =0;i<0xff;i++)
            {
                if(i*0x5A%127==key)
                {
                    System.out.printf("%c",i);
                    break;
                }
                 
            }
        }
         
     }
 
}

得到最终的key:Kanxue_2019_Q3。
看完讲解的你有没有其他思路呢?来录制一段CTF赛题讲解的视频吧!让你的长假不再无聊!看雪带你体验解题新形式!

详情请查看 录制你的专属视频,玩出CTF新花样!

- End -

往期赛题

* 看雪.纽盾 KCTF 2019 Q3 | 第一题点评及解题思路

* 看雪.纽盾 KCTF 2019 Q3 | 第二题点评及解题思路

* 看雪.纽盾 KCTF 2019 Q3 | 第三题点评及解题思路

* 看雪.纽盾 KCTF 2019 Q3 | 第四题点评及解题思路

* 看雪.纽盾 KCTF 2019 Q3 | 第五题点评及解题思路

* 看雪.纽盾 KCTF 2019 Q3 | 第六题点评及解题思路

* 看雪.纽盾 KCTF 2019 Q3 | 第七题点评及解题思路

合作伙伴


上海纽盾科技股份有限公司(www.newdon.net)成立于2009年,是一家以“网络安全”为主轴,以“科技源自生活,纽盾服务社会”为核心经营理念,以网络安全产品的研发、生产、销售、售后服务与相关安全服务为一体的专业安全公司,致力于为数字化时代背景下的用户提供安全产品、安全服务以及等级保护等安全解决方案。
公众号ID:ikanxue
官方微博:看雪安全
商务合作:[email protected]
“阅读原文”一起来充电吧!

文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&amp;mid=2458299480&amp;idx=2&amp;sn=393b3fabcac858327803d647fef78b57&amp;chksm=b1819cd286f615c4594ae3204a4508f5bf51add3828b6e072aed5f59024532575ea013524aec#rd
如有侵权请联系:admin#unsafe.sh