circuit123 picoCTF2018 题解

本题来自于picoCTF2018的一个逆向题

题目描述

Can you crack the key to decrypt map2 for us? The key to map1 is 11443513758266689915.

Hints

Have you heard of z3?

分析

提供了三个文件,和一个key,这个key应该是map1key

查看了一下map1.txt的内容,并没有看出来是个啥。

map1.txt
再看看decrypt.py内容,首先看一下主题逻辑,分析过程都在备注里面了。

if __name__ == '__main__':
  # 输入应该是python decrypt.py key map.txt的形式,有三个参数
    if len(sys.argv) < 3:
        print 'Usage: ' + sys.argv[0] + ' <key> <map.txt>'
        print 'Example: Try Running ' + sys.argv[0] + ' 11443513758266689915 map1.txt'
        exit(1)
     # 打开map.txt,cipher用来与key一起进行sha512解密用的
    with open(sys.argv[2], 'r') as f:
        cipher, chalbox = eval(f.read())
    # map1.txt中chalbox[0]=64, key应该小于2**64
    key = int(sys.argv[1]) % (1 << chalbox[0])
    print 'Attempting to decrypt ' + sys.argv[2] + '...'
    # 验证key,主要需要分析的函数
    if verify(key, chalbox):
        print 'Congrats the flag for ' + sys.argv[2] + ' is:', dec(key, cipher)
    else:
        print 'Wrong key for ' + sys.argv[2] + '.'

然后分析一下verify函数,以map1为例分析一下,因为map1已经给出了key

def verify(x, chalbox):
  # length=64,check=(570, True)
    length, gates, check = chalbox
    # 将b转换为二进制,从低位到高位组成一个数组,大小为64
    b = [(x >> i) & 1 for i in range(length)]
    for name, args in gates:
      # ('true', []) 为入口
        if name == 'true':
            b.append(1)
        else:
          # args由四个元素组成,name有两种,一个是or一个是xor
            u1 = b[args[0][0]] ^ args[0][1]
            u2 = b[args[1][0]] ^ args[1][1]
            if name == 'or':
                b.append(u1 | u2)
            elif name == 'xor':
                b.append(u1 ^ u2)
    # 返回b[570] ^ True,一开始b是64位,最后b应该是570+1位
    return b[check[0]] ^ check[1]

题目的大致逻辑:

  • key按照64位二进制展开(低位对应数组的前面),得到一个64位大小的由01组成的数组b
  • 根据每一个 gates 中的tuple计算一个b元素,一直到b[570]
  • 最后,返回b[570] ^ True 的结果

b[0]b[63] 未知,后面的运算相当于解64元方程的算式,所以这只是个变种的z3题型。

Z3 是一个微软出品的开源约束求解器,能够解决很多种情况下的给定部分约束条件寻求一组满足条件的解的问题,功能强大且易于使用,常用于解决CTF当中的密码题或逆向题,Z3 在工业应用中实际上常见于软件验证、程序分析等。

我们用z3来求解,按照decrypt重新写一个脚本

#!/usr/bin/python2
# -*- coding: utf-8 -*-

import sys
from z3 import *

if __name__ == "__main__":
   # 需要将key值去掉,后面会定义求解
    if len(sys.argv) != 2:
        print('Usage: ' + sys.argv[0] + '  <map.txt>')
        exit(1)
    with open(sys.argv[1], 'r') as f:
        cipher, chalbox = eval(f.read())

    s = Solver()
    v = []
    length, gates, check = chalbox
    # 由于key会被转换为由0和1组成的数组,所以将key定义成bool类型的数组
    for i in range(length):
        e = Bool('v' + str(i))
        v.append(e)

    for name, args in gates:
        if name == 'true':
            v.append(True)
        else:
          # 将异或操作改写成z3里面的异或
            u1 = Xor(v[args[0][0]], args[0][1])
            u2 = Xor(v[args[1][0]], args[1][1])
            if name == 'or':
                v.append(Or(u1, u2))
            elif name == 'xor':
                v.append(Xor(u1, u2))    
    s.add(Xor(v[check[0]], check[1]) == True)
    flag = []
    if s.check() == sat:
        m = s.model()
        for i in range(length):
            flag.append('1' if m[v[i]] else '0')
        flag = ''.join(flag[::-1])
        print(flag)
        print(int(flag, 2))

我们用map1.txt去验证一下

key1
得到的结果正是题目给出的key,然后去求解map2key

key2

用他给的decrypt.py和自己解出来的key去获得flag

circuit123-flag

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值