首页
社区
课程
招聘
[原创]看雪.深信服 2021 KCTF 春季赛 第六题 寻回宝剑 WP
发表于: 2021-5-19 12:07 8313

[原创]看雪.深信服 2021 KCTF 春季赛 第六题 寻回宝剑 WP

2021-5-19 12:07
8313

此题是个console程序,运行情况如下,有错误提示。就是那个提问不知道有什么特殊含义没有。再看阁下的数学成绩堪忧,请回吧。这个错误提示,莫非此题需要深厚的数学功底?

静态加载程序,发现全屏的花指令,没见到一个正常的函数,翻了半天没了看到比较正常的指令,看来真实指令被淹没在代码海中了,又是体力活。看到基本都是call pop xor的样式,于是尝试去花,把这段代码直接改成了jmp,如下图:

但是去完后发现,还有嵌套的这种模式,地址计算除了xor,还有add之类的指令,这可不好去花了。而且还有更复杂的情况:有好几个地址会跳到一小段代码的不同位置。于是放弃继续去花,别寻他法。

想着如果能从中找到什么规律或能大概了解程序的业务流程结构就好了。考虑到既然有校验,那肯定比较,看了下导入函数,有strcmpstrncmp,在访问这两个函数的地方下断,运行后随便输入,有调用strcmp,比较对象竟然是1764,那个提问的答案,又尝试了几次,没什么用。既然函数方面下断没有帮助,那就考虑指令方面吧。试想如果找到跳转的地方,大概结构就可以慢慢动态出来了。于是一计浮上心头:代码搜索+断点大法。
先看有多少跳转,还要筛选出有用的,但是跳转的地方代码看不到数据,不知道因为校验或比较什么而跳转了。为了解决此问题,稍微改变下着手点,把搜索跳转代码改成搜索cmp指令。搜索了下,大概100出头的cmp,直接导入到调试器动态调试,动态过程中去掉无用的断点。慢慢地能看出了一部分的流程。

再然后只能看到嵌套循环了,不知道计算了什么。于是再来搜索指令,先把所有用到的指令列出来,挑了数目比较少感觉可能用到的,比如subidivimul,再来下数据大法,多跟了几次,就把算法跟出来了,如下的模拟计算:

42个数两两计算,abcd分别为两个数的42进制低位和高位,结果唯一。

综合来看,这应该是一个42*42的矩阵,上面放置42个点,行列唯一,列的出现顺序还要有要求,有点像N皇后问题,但是应该是变形的。要求两两连线不平行。空间有点大,而且可能有多解,比较难算。后来注意到还有个疑似42进制的字串,在strncmp处断下与输入前28个字符比较,这样空间就小多了。解算代码如下:

结果为:02152S3X4Z5Q6C7T819/ADB%CDLEIFUG3HRIHJ6K7L0MBNKOJPPQ=RNS+TEUOVWWGXYYMZ9+4-8F/-%V=A

 
 
def get_dis(a,b,c,d):
  dx = c - d
  dy = a - b
  if dx < 0:
    dy = -dy
    dx = -dx
  dy += 0x29
  return dy*42+dx
def get_dis(a,b,c,d):
  dx = c - d
  dy = a - b
  if dx < 0:
    dy = -dy
    dx = -dx
  dy += 0x29
  return dy*42+dx
# -*- coding:utf-8 -*-
import copy
 
ts = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-*/%='
mat = [2,5,28,33,35,26,12,29,1,39,13,40,38,21]
dis = {}
 
def get_dis(a,b,c,d):
  dx = c - d
  dy = a - b
  if dx < 0:
    dy = -dy
    dx = -dx
  dy += 0x29
  return dy*42+dx 
 
def get_dis_all(p):
  dis = []
  for i in range(len(p)-1):
    for j in range(i+1,len(p)):
      dis.append(get_dis(i,j,p[i],p[j]))
  return dis
 
def search(cur):
  global count,mat,dis
  if cur == 42:
    out = ''
    for i in range(42):
      out += '{}{}'.format(ts[i],ts[mat[i]])
    print out
    prettyprint(mat)   
    exit()
  for i in range(cur,42):
    flag = True
    for j in range(cur):     
      if get_dis(j,cur,mat[j],mat[i]) in dis:
        flag = False
        break
    if flag:
      for k in range(cur):
        dis[get_dis(k,cur,mat[k],mat[i])] = 1
 
      mat[i],mat[cur] = mat[cur],mat[i]
      search(cur+1)
      mat[i],mat[cur] = mat[cur],mat[i]
      for k in range(cur):
        dis.pop(get_dis(k,cur,mat[k],mat[i]))
 
def prettyprint(solution): 
    def line(pos, length=len(solution)):
        return ' . ' * (pos) + ' x ' + ' . ' * (length - pos - 1)
    for pos in solution:
        print(line(pos))
 
def main():
  global dis
  for i in get_dis_all(mat[:14]):
    dis[i] = 1
 
  for i in range(42):
    if i not in mat:
      mat.append(i)
  search(14)
 
  print 'end.'
 
if __name__ == '__main__':
  main()
# -*- coding:utf-8 -*-
import copy
 
ts = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-*/%='
mat = [2,5,28,33,35,26,12,29,1,39,13,40,38,21]
dis = {}
 
def get_dis(a,b,c,d):
  dx = c - d
  dy = a - b
  if dx < 0:
    dy = -dy
    dx = -dx
  dy += 0x29
  return dy*42+dx 
 
def get_dis_all(p):
  dis = []
  for i in range(len(p)-1):
    for j in range(i+1,len(p)):
      dis.append(get_dis(i,j,p[i],p[j]))
  return dis
 
def search(cur):
  global count,mat,dis
  if cur == 42:
    out = ''
    for i in range(42):

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

收藏
免费 1
支持
分享
最新回复 (2)
雪    币: 80
活跃值: (94)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
现在的CTF感觉有点偏了,为了考试而出题。
2021-5-19 16:04
0
雪    币: 214
活跃值: (283)
能力值: ( LV5,RANK:77 )
在线值:
发帖
回帖
粉丝
3
我就是没解出来这个42皇后题,爆破太慢了,跑了半天才到30位。没想到后面还给条件,大意了。
2021-5-19 17:55
0
游客
登录 | 注册 方可回帖
返回
//