美文网首页
2016-pediy-ctf-04

2016-pediy-ctf-04

作者: ZERO_47ce | 来源:发表于2019-03-19 10:14 被阅读0次

2016-pediy-ctf-04

发现主程序很简单,主要过程在窗口回调

Image.png

通过GetDlgItemText得到输入,并对其字数进行比较,锁定关键函数


Image [3].png

查看关键函数,发现里边的代码很混乱,利用PEID和exeinfo查壳,发现并没有检测到壳,顺便利用PEID工具检测一下加密算法,发现MD5算法


Image [4].png Image [5].png

搜索字符串并不能发现其他有用的东西
所以我们直接进行动态调试
输入 1234567890三次,得到30位输入进行调试关键函数

动态调试发现该过程存在循环

Image [6].png
其实该过程为虚拟机,即VMP,上图esi为handler,
直接查看esi全部handle,在最后几个下内存断点
Image [7].png
注意这个操作,出虚拟机的操作,我们直接下断点
Image [8].png

笔者由于个人水平有限,还是不能说清楚关于虚拟机的种种操作,所以这里只是在关键位置提一下,只能说关联代码前后凭感觉去找出虚拟机的操作,并且作者在关键代码并没有VM,如果作者所有代码都进行VM操作,可能以笔者水平,并不能搞完这个题

出虚拟机后
004014F0
发现我们之前用插件得到的MD5, 进入该函数发现第一次作比较把我们输入的前七位拷贝之后ret,不过很可能之后依旧会进入该函数,并很可能进行MD5操作
ret后发现再次进入虚拟机,我们直接运行到虚拟机出口

Image [13].png

004015c0
该函数的两个函数主要操作

Image [10].png

第一次进入004014F0加了结束标志符,并把后边清0

Image [11].png

第二次,MD5操作

Image [12].png

拷贝MD5值并把内存清0


Image [14].png

00401187
获取之后的23位,与指定数进行xor

Image [15].png

之后该值会与之后的MD5值进行XOR,注意MD5值16字节,重复循环,xor,直到23字节
得到值

Image [16].png

这两个赋值操作是对迷宫的初始化,后期会用到的

Image [17].png

而且此时的数值才是正确的,因为之后经过VM后,有些数值会发生变化,导致后边计算错误

之后就是迷宫走法的核心计算,下边是如何计算每一步及其规则

Image [18].png

详细说一下这里吧
首先00401248这里cl被赋值为6,4,2,0,
0040124E这个edx取我们输入后处理的值,and 3,得到其值
然后通过00401253计算跳到哪里,这里可以得到
0 ---> 向上走
1 ---> 向前走
2 ---> 向下走
3 ---> 向后走
所以一个字节可以走四步

然后接下来是迷宫的计算

Image [19].png

我们首先得到
part 1

Image [20].png
part 2
Image [21].png
首先是对Part 1根据上边的走法取对应值然后ror,这条指令我们用程序模拟还是挺麻烦的,在找到对应的part 2值,进行xor
之后我们通过爆破,发现0x58是出口
了解了具体的步骤
我们开始写程序爆破
程序后边代码
#程序参考来自https://bbs.pediy.com/thread-213791.htm   〇〇木一
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import md5
import binascii

p1 = "6ED41B695F4EE8AA95F6AFCE321A62D9021874951FC24D333CF03BECE9814B9C"
p1 += "0F475CADD909B087539BF2E30F01928DC2F50CDD42CCAFB4D5E486D39A0B6263"
p1 += "A7D41B695F4EE8AA95F6AFCE321A62D9021874951FC24D3338F03BECED814B9C"
p1 += "0B475CADDD09B087579BF2E30B01928DC2F50CDD42CCAFB4D5E486D39A0B6263"
p1 += "A7D41B695F4EE8AA95F6AFCE321A62D9021874951FC24D3338F03BECE9814B9C"
p1 += "0F475CADD909B087539BF2E30F01928DC2F50CDD42CCAFB4D5E486D39A0B6263"
p1 += "A7D41B695B4EE8AA91F6AFCE361A62D9021874951FC24D3338F03BECE9814B9C"
p1 += "0B475CADDD09B087579BF2E30B01928DC6F50CDD42CCAFB4D5E486D39A0B6263"

p2 = "D805F66AE7A20B9B548CDA82BDB6A846B1362D55F78163FC3F0CFE0B4B50E217"
p2 += "F2E1275B46731CD0E5D78DC9F2709453814C3246A002DB1C450991C496F2A8E8"
p2 += "D905F66BE7A20A9B548CDA82BDB7A946B0362D54F78163FC3E0CFE0B4B50E317"
p2 += "F2E0265A47731CD1E5D68CC8F2709553804C3347A002DB1C440891C496F2A9E8"
p2 += "D904F66AE7A20A9B558CDB83BCB6A946B0372D55F78163FD3E0DFE0B4A50E317"
p2 += "F3E0275B46731DD0E4D78CC8F3709553804C3347A003DB1D450891C496F2A9E8"
p2 += "D904F66AE6A30A9A548CDB82BCB7A946B0372C54F68162FD3E0DFE0A4A50E217"
p2 += "F2E1275B47721CD0E5D78CC9F2709453814D3347A003DB1C440891C5979AA8E8"

#生成迷宫
pp1 = binascii.a2b_hex(p1.encode())
pp2 = binascii.a2b_hex(p2.encode())
pp3 = ""
def ror2(a):
    return ((a&3)<<6)|(a>>2) & 0xFF

for i in range(len(pp1)):
    pp3+=chr(ror2(ord(pp1[i])) ^ ord(pp2[i]))
print(len(pp3))

#16字节一行打印
for i in range(16):
    ps = ""
    for j in range(16):
        ps+=binascii.b2a_hex(pp3[i*16+j]).upper()
    print(ps)

x = 0
y = 0
x0 = 0
y0 = 0
t = [(0,-1),(1,0),(0,1),(-1,0)]
#打印程序指定的道路
path = ""
while(ord(pp3[y*16+x]) != 0x58):
    for i in range(4):
        xx = x + t[i][0]
        yy = y + t[i][1]
        if(xx >= 0 and xx < 16 and yy < 16 and yy >=0 and (xx != x0 or yy != y0)):
            if ord(pp3[yy*16+xx]) != 0x30:
                path += str(i)
                x0 = x
                y0 = y
                x = xx
                y = yy
                break
print(path)

#按照之前的走法,将其合并为每四步为一个字节    one byte for 4 steps,
pn0 = ""
for i in range(23):
    a = 0
    for j in range(4):
        a = (a | int(path[i*4+j])<<((3-j)*2))&0xFF
    pn0 += chr(a)

print(binascii.b2a_hex(pn0).upper())

#处理输入
## 在程序中存在以下操作
## 对前七位进行MD5操作,并循环扩展到0x17位,
## 然后剩余23位与44 AD 5C CC 12 90 73 8D 47 81 E3 89 84 9C DF F9 47 6A B6 9E 11 30 27 sn0进行xor得到sn
## 然后MD5与sn进行xor得到sn_1
## 存在 path = md5[x1] ^ x2 ^ sn0

def getmd5(src):
    m1 = md5.new()
    m1.update(src)
    ret = m1.digest()
    ret = ret + ret[0:7]
    return ret

pn1 = binascii.a2b_hex("44AD5CCC1290738D4781E389849CDFF9476AB69E113027")
pnx=""
#因为是xor操作,有可逆性,所以我们直接得到他之前的值
for i in range(23):
    pnx += chr(ord(pn0[i])^ord(pn1[i]))
print("pnx:", binascii.b2a_hex(pnx).upper())

def xorpm(pm):
    global pnx
    pno=""
    for i in range(23):
        pno += chr(ord(pnx[i])^ord(pm[i]))
    return pno

def isstr(s):
    for a in s:
        aa = ord(a)
        if aa < 32 or aa > 126:
            return False
    return True

# 枚举,
tab='0456123789abcdef'
t0 = time.time();
for a0 in tab:
  for a1 in tab:
    for a2 in tab:
      for a3 in tab:
        for a4 in tab:
          for a5 in tab:
            for a6 in tab:
              aaa=a0+a1+a2+a3+a4+a5+a6
              pppp=xorpm(getmd5(aaa))
              if isstr(pppp):
                print(aaa+pppp)
                break

你也可以在这里查看:
https://github.com/ZEROSHE/ctf/tree/master/ctf/Pediy/2016%20ctf/4
本人水平有限,只能知其一二,很多地方可能存在不当或者错误还请指出,谢谢。

参考链接:
https://ctf.pediy.com/game-fight-5.htm

相关文章

  • 2016-pediy-ctf-04

    2016-pediy-ctf-04 发现主程序很简单,主要过程在窗口回调 通过GetDlgItemText得到输入...

网友评论

      本文标题:2016-pediy-ctf-04

      本文链接:https://www.haomeiwen.com/subject/ixiwmqtx.html