上来先看了下壳,没有。直接上IDA,发现原来是MAC系统下的东西,我没有MAC,看来要在IDA下一条路走到黑了。
进了IDA,如图:
西普CTF-Poppy-以夕阳落款
函数不多,松了口气。直接进start。
西普CTF-Poppy-以夕阳落款
似乎程序总体结构一览无余。先输入KEY,然后由两个sub进行KEY的变换,所得结果与aN进行比较。进KEY变换的两个sub看了下,第二个sub比较复杂。

西普CTF-Poppy-以夕阳落款

第二个sub我不上图了,简单说下,主要是多层循环控制结构,主要进行移位、或、与、取反、异或操作,没整明白。但仔细看下,发现对KEY的变换操作特别少,而且没有对aN的操作。aN在程序中初始状态如图。

西普CTF-Poppy-以夕阳落款
所以aN不是flag,这也正符合提示:没有输出的内容。接着往下看,下面还有个函数sub_100001530,输入参数是KEY经过第一个字串处理函数变换后的值。

西普CTF-Poppy-以夕阳落款

先对输入参数分别与两个字串进行变换,然后进入一个循环,访问网络并对字串进行处理。折腾很久,没有折腾出结果。后来网上找到一篇WP(http://www.secpulse.com/archives/39058.html),一切就清楚了,写这篇WP就是想把网上WP略过的东西说说。毕竟我是小菜,flag不是目的,学习才是目的。
如果把sub_100001530的输入参数记作a,如网上的WP如说,在sub_100001480中用a的前6位与目标字串进行异或生成一个url,url的开头肯定是http://或者https://。这样就可以反推出a的前6位,并再得出url。而且还可以用a算出另一个字串的变换结果。直接上代码,两种可能性都算,一看便知真假。

# -*- coding:utf-8 -*-
# code by poyoten

def main():
  t1 = r'http:/'
  t2 = r'https:'
  #b为unk_1000020E0
  b = [0x3c,0x44,0x19,0x11,0x7,0x55,0x7B,0x1F,0x0E,0x15,0x12,0x1B,0x3D,0x5D,\
        0x8,0x4F,0x1B,0x1D,0x33,0x1F,0x8,0x17,0x11,0x1,0x20,0x1F]
  #c为unk_100002100      
  c =  [0xF1,0x31,0x78,0x98,0xC0,0x62,0x50,0x7A,0xDA,0x62,0x70,0x9D,0xFE,0x2D,\
        0x6E,0xC3,0xEE,0x7A,0x51,0xA,0xC8,0x74,0x74,0xE,0xC2,0x31,0x6D,0xBD,0xFB,\
        0x6A,0x57,0x94,0xEC,0x6E,0x7C,0x77,0xF1,0x37,0x6F,0x95,0x3,0x56,0x57,0xD8,\
        0xE0,0x6A,0x70,0x5D,0xCE,0x33,0x6F,0x61,0xD1,0x64,0x55,0x75,0xC7,0x66,0x74,\
        0xC0,0xD5,0x3B,0x6E,0x19,0xE0,0x62,0x5C,0x18,0xDA,0x44,0x75,0x9A]
        
  a1 = ''
  a2 = ''
  for i in range(6):
    a1 += chr(ord(t1[i]) ^ b[i])
    a2 += chr(ord(t2[i]) ^ b[i])
    
  print a1,'\t',a2
  b1 = ''
  b2 = ''
  for i in range(len(b)):
    b1 += chr((b[i]^ord(a1[i%len(a1)])))
    b2 += chr((b[i]^ord(a2[i%len(a2)])))
    
  c1 = []
  c2 = []
  for i in range(len(c)):
    c1.append(c[i]^ord(a1[i%len(a1)]))
    c2.append(c[i]^ord(a2[i%len(a2)]))

  print b1,'\n',b2,'\n',c1,'\n',c2

if __name__ == '__main__':
  main()
  print 'done'
  pass

得出一个网址和一组数,代入sub_10000133进行运算,最终能得出flag。既然内容没有输出,我也没有MAC,那我们输出内容吧。代码如下,尽量保持了伪代码的原样。