腾讯极客挑战赛:第一期题解
原题:https://mp.weixin.qq.com/s/tZ9BmXfzGYpzrNm2Jl5Mrw
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from Crypto.Cipher import AES
import base64
import time
import gzip
from hashlib import md5
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='utf-8', line_buffering=True)
def Decrypt(key:str, text:str) -> str:
if len(key) < 32: key += ' ' * (32 - len(key))
elif len(key) > 32: key = key[0:32]
cipher = AES.new(bytes(key,encoding='utf-8'), AES.MODE_CBC, bytes(AES.block_size))
return str(gzip.decompress(bytes.strip(cipher.decrypt(base64.b64decode(text)))), encoding='utf-8')
def Pass(id, priv_key):
prefix = str(id) + str(int(time.time()))
pub_key = prefix + md5(bytes(prefix + priv_key, 'utf8')).hexdigest()
print('恭喜通过第%d关,通关公钥:%s' % (id, pub_key))
key=input('1+1=')
exec(Decrypt(key,'JIvH7KUKFAKDu6ZfRjsV9VsCODat2VbDd6S+QAGKEXtGlSxvhUIhqHfXq/1EhGohqhFelniKn3294DpzdccOhP6KcQQPxpGVgKcQJfezn+4JA4Aq0rvWkVoYew8OkRCt2/7MmgVwLCxlqhIrI5SvibCg2Yg0nBs/qe+7rI2EcC16ncIiBICvQFIvewAsYLcIEHFFdbzkM2nwfjxFnQ1bqgchYMm0lsKvztSAxxRS6ZFrdZqNb3u8Iyg6DB1vRu2BZFu5ed3E0g926LASeliCxvltvE5EJaJfJtquFAMeJxlcDTEkRdWbdoi5zbB2UK7ZM+i+STJPK+QKo0MEMAm+pkXmm0ZYttEYXDSqJHoutOVGX73EHnsBtGSYqs20UVHT5AbFXu8adbUtM5eqWJ5NRy8spXVnd/hOZo/qoS/Yp6LAKwWccC/J1As//SDpm+gsYENoKVgGoqJFStWccrqk6pWGIwEwimUq2tXaTsfCbHYCNT+AOrWYD0w6c3LJdFj38PrZSYjEceJHFeP7bdX2u5JmXlXKrZgpDNVP/RnQS1Zhw76ZTid31IPprHVHD1indT21WapbtdVuhDijAYpAFvzVmjeFPXjaUuAZwJw9voW/jg9Ucfe0OScMs82xVTW0EfBqPpM2WH+OXjC+xZUrrlqkuqG67qaf66Lhl+uSuuGinTIbzaMnlY8CyNpRBbJyHpu4/keDWZC2n0C5DCdvmWIQHtM0UJs0v4MICgu74Rrf11tmuUvKb4htLMTGT3BDjELZQvejWqMNjKods8W+B62hKYqLJDyJEsxjGe1uZWdmyZnm4oPLwzpJLlOZqIUL+uJkm7/nCkqadPdRQT/80xXz+K4btjaNkiKmTPSBtnCs3clWH1ZDHehMTZXu6Md2Y9TUjVXoEB7f96ZmWmuttFuLBnLpT9FsOxxHL1XBXSusgltORLgJx7t2zrcFJr+z8Uw3fyiN6XiR/YdbMhhUucgroPLhJB0Z6g0h5pdKjmyHsXzQ9k9PA8hdXHzME4MG7rdi7IsHPMC56PPoxenrkNLnFrcwxJ4vmVPhXHqljKo0PrtGsfFHw3Yy5/MqOmz5ZSN9F92gZQiHZwhKLXW/HNGnOexEONDCSccDch7Nt7ztqlcA3fygD6Kx8/N+YNTtiudlw6ZG3FzCaZusn9JQsswrhYMN2lWCSSB+JB2Ol1yOHwIGRKCJ+cj6XShojG/KHbfDahNt4GPZi7fK+8kIUir+9KQ8PqEFi1K9N868oqlY1JN85LhA55WPdvVlTAe8o7XQCVYM31ce9iM/ZCRLC6uAu/EVK1aju4zgMumxQumfSDn4J3m80R4WANDvyPSmqqhB950TqarXHc9ni9g91wp6OqmZcs43Mtwyj5DLpITc1AZTGagiLDC8ChDZJQ7v2o5Hegf4iPdTSB4j8bMkRYDOAjLutSix4tqA5uDt7z069UPIhNUSFWOhGkN2jzUqoITNbOx1Icxbj4YPsiZ3bT3DUXoEzAtjf6JW8N9X3iItG9kz8LqdnkpUmOtaMlDwTXnbQC1/gkFZKuCPK0Nf4PXiEmWLUcaajM1mCuKDrTRqaevcqsOXIVw2dODsQQTLysnQaAXlWJv9jYYCpcenvQ9dVGc5XJz7NNzBcy1XmNBrctQuiUvc1v2IkQfKVlmlEo4OaN0ZkxjQZZUkg3ghyr7dA3qve3VRn6i9ObPC1MmATr5NjXsBoyhDO9nidqZYfRhJamhL5AuCR4Y91PI2h9qapdGbRYJs1WX3d5qZ/wVTt6dHFAZPwxL7wEHmevLCoGw6Fp8YnxVZGynwsonR37WfQt6BcNYUZMPr4Is9rO79tRmbsOe932VOCi1dZ2eEvEMM5hah6/1fc266Ssu6HHsmkkrwe8C74QTwduP0vpxD1kX5GSu9jq2Y4Keg5nCRtBlMg2xdIeyyg4CIDX7BYDkmP4Yn/3xczpbB7+PfB80x0qi70u4mfEikdwuasaxkChIEXBBaMAdjUj7rVfJvasy/hUNZ6tp2AJwwBfLKSLxsKIb7p0E+a/Vz0lJ88u3HHjqiL/UjN6qTV5oWFJcU303Bpbh8wlTRoFU89Jq31GfkPbuifwGEmTgjyzQpg6AJP0K9wJX3f7C8W2TbEeUA3noWkNtl814jvbovSIB/inK1DWuChLsn9eInyLJ7d7u/OFL/UFPA/C5fvAsS/l+Kwf68ghZRB8ftr/x8b835k2woU2LWgbi70R3iNVBQ/q04lxYJYImYaHWGRyQCjv4n6WF1c53fN7l9ATuNOwR57Ap7XpEwHSSAeP/kt7pkhM4wp6o17XRYiHjzZI/hv+9LieLPB+uLpth1PoL2Lo0w5930Dj/g1gLtJAdowfjyvSjcIUUHwVZOkjmgm/vvEH0pFohWTZr7ZSPkGvXwEEdjocWA/4qNCHSbXXceqDqEaW7w/599WkEKbA5zTw04c0AsXSrCjPGgm99ZGvIn0/8I7XUdR7uPbw36ybgwjBYCq37jqCDf5wxNp7UhXLLHehn4TtGGlX6v6iwDVU2tWBS3U8BfWRIqTTUtrr+b3U1J2bHi2cDmvLS4ym5eci0Kv7XHD9cj2aBj6cPOkXt0kgBNiylVwFJg0bcuNWYOXeN36kj3PIVrSJ7mDqCYT1wupgQT/PlYZpq6uy1YuBS8loSfi0TP3uXr5gz4ZKCd5UhA5Dj4qeSYJs2tOkpSOhMQMguZYNHeZrPnHJMRq7I3LqZOAnQ299Y9JEN5YNT2s5PrgqkzzQka4IV9bE3JgxykW66ZJxapHG820aH9s5RvOMcdJJms/FA/kX0oOiLNrYW450Ec70MPi4ZGzom4tqavSyPj/iYZlVHAt2WIB3zoToIgf4rcjkgshN81tGg33zpIV59j3sWJ7paqEoE7BszOz0193AUML7NC7dJJpJStH+pkGncL91at4eeMplBXUBIuKknrrEti/X4eFvBY8ns0hHH+pI5uv3tyGxdI3GkHpwLRxGlyLR4Wril9VcIqiTMhdcag/JS5AByd68RkHkKJScwX7Qb9t1uWsplbQ0SlSvqZgQqNO5Rw126B/ywXPHOLgpUfrgp3EnhJ/3mxdxDF8Lj6GP+nEChzVa4eZ0lZBLsyDJeGI2rmKKDQLMGZMs+xtLB9kfrIvlvLyTTuSXzlX/EDJ+BEmVlURyELCEDezhWT60Lt2kGJwCp2hl+pzbQh7wc0bbBgWRJwzdD74rZgWlHG8D8wOYlf+obtM2tjY5DCsxZtiEVatcdnhPqSZI3eIHnLHpfDZu69VMm01FlQwWirtK6cHIJAjXYnQEnj6H90Rp2LczNhzJkzS1vo/sV1N5iHP0Y+NE5Q1kypPHwTkOc0XdSlh3WIYwiYFtXu5PsLvYqbCcbjaBP6MbbOjTiwE73uMzp3T3hG3VzoqGWCYQFsDYtuz8/3uhHFEMFKjd0dhvV8q7bdCMgfJ8gm9CaEvnTH4h6Ta/fnermWvkBGveV7hE5lCDknDoKJzNU2giiHZHv77HvQuqnHG2UxLwFWrWNsYtqA8GTUYyxxr7sKxikCKdl079qVDUp99Xb/0CpNx8f1ajVg3VWGPHwY7v0BTITax+z/JG8EolLRua9oyb2uCx827/9F6A+D5bmZaKbImeOzejSslLx7lZkA/8cs1JzbdpgBcXP2cHvXmrWutxiLJkDiKgXOEE/trdSwzYXn5TwWSRCtRx65D3RGKnjA7mPpSpHWmOJz7NpIxgi3CJSGmZAkPp6NjskpIhqPMAD1MjyY6BmlqSXvgNVArNEHegOoZWCwHVgO/0hxM2hUcSq1f1SPoq1N61qXQvw66DjgCYOLLb47lW3Y9OWWFCtDxnbR9w52xv8XyohW+26c/QGx07Z4Tt4k2Em7gslWSQiqvclL+P0cjVy75uwG0a0ARbBBADit9QFVFnsZyLQ3qCyTLi73LGRVzD11PsL6se7pRvRWMNmvmiQKw/4SfTaYF1srWpaDxgVwHoF2l2bufgatZufXyGOqMQW1b4Oim943Fobf81+jhPipKeonMspKrx1S/8iifz7UVXAVh2MebJo8YEQszRg38DzMcK2AxpXFANWA8i2tdVtU++njqXzM655+wblloZYa2s/x8iOO/YMHw4Q4iH5YfIp602tbOTUdYbTw3avhIC0vBsAzwi1kPOvfZeWXSPfqMChAvBboPPsEmu5ST/RFbWF3Wph/MPjKr548wudh29MRdKDqvTvK8ZCA9ymEIs6/nXyXVrPg3WMlVCwuiST+zsd4Aph3G2S051ndEiOqgirG6CVejwGg40YKG4f7jUWxL+Kps69ialit/Fz2+gG5jeZG+PmagxjnYHZtCzrWu4uYV+IQuJXcqlNIFznSTsEsvU2lbQgCbkSp9/CFtZqE4bXz8Oe02/j/rjnSGylT8VlrRa25O64byQYljv6Gvr6kgxcp8FygFcAjMzBaamYZydH5ZnSNBBrzrWeuWP2NfamUM0eGccSbhf3mWeJjm7O1ybYxAJdLqOTTh3AYE+nzhl9nOoF7QSC4eIIDGO0+PFMCr9IltBaNwx7AmhrIvaAOwyct+tJuDT0EKxPhuNfIJWNJ6ub3UT7iGB4xPVzIERA1Mue7UuvLdardWhMqAqFhBEDzFwNwM7b/lJsoRPFoc+WJr8isCLLfiGjzZhpuHmzVfMXwCOUvZnzYBUqHsxx4SAJPwk0PW6qUWkUG3vYCrRb6I/qge9QuYHPTQ5OE9WzQef9HIm7tp6bqywArRM+b7Mm0ldUz/ugebDo9cKGQqm4I3rBZ0FXh/VMdxbH6e/+0snAWdmL36VuLgXAVHko1hPsHe3PO/DVQhUXQQITMMJ2yUajWCmGHqFIyS9gqVqG9E9WdTSkmxs+2h4g+sk5OuPKdczvzm9Yf5oA49lksQuJcWD3M0MaXnvH07xwEsQuJiRWdo0JzPXA0OuMcQ1GPUV5E/rMiNn4yjRPP/HAFP7LlfKmkguFfcOsYyXhkNQ2zow9Q4+F12qXiHJGT5ShL4dZWiSU6PCgAmh/cLqFSD6+ILK4wOBRz9gqlck1pocJJazkP8FaXadW6+pfIWSeVSKQcsZDIXySu453ZsNxAtHOp1/TgtQZFpuarIVSGbUIpwqUacoL3NcuxuBhznHVLUp6WVvxNks4Z5O4wWH4c3tnE7qrx8r0qcVeuFrTRw96ICkDHqWNEr+gZrIlKAed9KIqGqMzjBZK+QtXDMECCXaS0nIab+ZlRNKFpWiqObLKPkSpLKZ5owcuO7EOudaeI6xc50wa7z6FBNMd2oCS9JWt14bbtMLnPXvZ+iMXMgEP929qnFtKZzeRcvkkvnMbaGrqsb/yiQVX5wan6rUzunAWPdTVgcqJT1Pi54G/OQxiVlcyvg4/PRAfV+8RLW0qeHhJExUVPIS8mz5fE3MIvLNgBHCqsQe/GnLMBV2aUqH1l5o1WsvVTWYJYWZHKZbxpSixxkx1qLeHO+W2NHGJHL6rWOJctmVuW9IDusIjeGC/L4t1ZygZlkKgpq848PIhMetJxD9j8Aq6GK3gxlXax7dpQ2y/J53kgHbDEvslD5x6MlswhgWcwC9hDcb/gYYTr8BmrZd0LtvCzrOJAYsCPObZbZPqOO37gbykhRhJ2FQv0+Lvp+lj/M5OoRmHtrTPjqNaDVmDncSPTIajXjAItkRxJLJboacSeEsGsJvSD0H0xgUhzhOfK0QepXXLfzG4aX/ow7we9pOXw3G7ydfdd9iB1yCiIICaW3SAavL2zy/dHMb5/0a0WxMza89pRW8KMZ/GQSxZOS2Ek8fJ954mEbJv8c5ZrzKyC9fbO89FsZmHimnBNZBlGyNrKckhBywYcHI/k4ytgkWMpFmYiNxV8j0WVmw1NDXuF/FCnRHHnexgRiVoZU8SWtnBWAqz4gZt3Z9ehoGXYKWXjS8eG0bWX6ueeNYrNKND5b1zXEd3SlN1UTqrtiqa2NKFAht0DlsMxYqweGTBMk4h06w=='))
第一关:
题目:1+1=2
思路:略
第二关:
题目:(x*18-27)/3-(x+7496)=0, x=1501
思路:略
第三关:
题目:41*x-31*x^2+74252906=0,(x^2表示x的2次方,下同),x的某个根=-1547
思路:求根公式
第四关:
题目:(1234567^12345678901234567890)%999999997=42031180
思路:
直接算是不可能的,
取模公式 (a^b) % c = a^(e*f) % c =( a^e)^f % c =d^f % c
其中 b = e*f, (a^e )% c = d
同时有 (a^e) % c = (a * a * a * ......a) %c, 其中有e个a
a=1234567
b=12345678901234567890
c=999999997
先对b进行因式分解,直接谷歌一个在线分解网站:
https://zh.numberempire.com/numberfactorizer.php
b=2*3^2*5*101*3541*3607*3803*27961=9090 * 3541 * 3607 * 3803 * 27961
接下来的步骤由脚本level4.py完成。
即使无法分解,也可以用小于b且和b邻近的合数计算,比如b=k+h,
(a^b)%c = (a^k)*(a^h)%c = (a^k)%c * (a^h)%c, 这个问题就等价于原来的那个问题,一个数的高合数次幂的结果的模。
第五关:
题目:1_2_3_4_5_6_7_8_9=-497,每处_填入1个运算符+-*/,且4个运算符必须都用上,使得等式成立(答案保证唯一),表达式为? 1/2*3*4-5+6-7*8*9
思路:
总共8个operator, 每个Operator有4种可能,所以总的搜索空间在4^8 = 65536
暴力搜索编程解决可行且快又简单,接下来步骤由脚本level5.py完成。
第六关:
题目:x^5-2*x^4+3*x^3-4*x^2-5*x-6=0, x(精确到小数点后14位)=2.19488134060852
思路:
其实考察的是二分法或者牛顿迭代求解近似值,但是比赛也没限制方法,,,就用在线网站解算了一下:http://tools.jb51.net/jisuanqi/equ_jisuanqi
不过事后我再补一个正经的解答:
考虑到一元5次,多项式方程在实数域连续,第一步是找到解的一个单调域,用程序的做法就是以0.1的步长在一个范围内搜索,看正负值变化所在的范围,根据打印出来的方程值和X的值的情况在调整范围和步长,这一步可以确定搜索范围在2.1和2.2之间。
然后进行二分搜索法(比牛顿迭代简单,效率也不低),接下来的步骤由脚本level6.py完成。
第七关:
题目:请输入8位数字PIN码:
思路:
1. 尝试输入了几个弱密码,都报错,而且不知道这个输入PIN码到底是干啥的,所以就先想办法看到这一关的校验代码,在原始decrypt.py,exec之前打印出字符串,然后就看到了第7关的代码。
2. 代码的逻辑是对pin码计算一千万次md5哈希,然后和目标md5值做比对,如果匹配,将key传入解密。而对单个pin的执行计时后发现,需要约5秒,那么如果对8位pin码空间进行搜索,需要5787天,及时用C++改写,预计加速100倍,再用多进程多线程多服务器甚至CUDA计算加速个几十倍,也是数小时级别的,这样看来要么费钱要么费时。
3. 再想想,既然是安全实验室出题,这个验证其实是可以绕过的,我不去走验证,直接尝试解密,虽然AES解密可以用任意key进行解密,大不了明文是乱码,但是按照gzip解压密文的时候,如果字节流是乱码会导致异常抛出,所以直接利用这个特性进行攻击。
4. 按照思路编写level7.py,一百万次尝试只需要1.4秒,那么总共1亿的搜索空间只需要两分钟,剩下的交给level7.py去完成了。
第八关:
题目:计算第8关密钥中,时间可能非常长...
思路:
1. 从dump下来的代码看,这个代码无论从结构还是变量名都没有掩饰其作为虚拟处理器的功能。由于时间比较晚了,加上题目暗示跑的时间很长,,,抱着侥幸心理,先改写成C++跑着吧,于是有了level8-v1.cpp,顺便对比了下速度,提升了150倍,10Mps,恩,先这么跑着吧。
2. 一到速度优化的时候就有点停不住手,于是又优化了几版,把原始的指令获取/指令数据获取,指令执行,跳转,访存等转换成了按指令位置的状态机表示,每个状态机基本只有一个加减乘除/push/pop操作和状态转移操作。把速度最终提升到 0.2Gps,这里依然是以执行的虚拟处理器的指令数衡量的速度,然后放着跑了一天。。。(为了能不浪费旧版本的代码已经运行的进度,每隔一段时间会对虚拟内存栈/寄存器做dump,然后恢复的时候重新编译到栈和寄存器内继续跑)。
3. 休息了一天继续看,通过程序不断打印出的栈和寄存器,发现了一点规律,于是想到单纯靠暴力是不可能解决的,还是要老老实实逆向代码,只有知道了代码的真实逻辑,才能达到最终的优化效果,由于有前面改写代码加速的工作基础,逆向容易了些。之前写了个python脚本用来解析code指令,详见level8-parse.py,这样不用手动翻译那些代码。
4. 之前过分注重代码优化,没有思考代码的含义,所以把code区的所有代码都写到了状态机里,实际指令的数据部分是无效的状态,也是无效的指令,所以前述优化也并不彻底。。。另外一个原因是,本着小心翼翼探坑的思想,不知道出题人会不会使个绊子,比如把某个数据既当指令代码又当成指令数据,然后某个位置暴力跳转到这个指令数据的位置,那么草草排除掉会导致执行的异常,不过这一切在把代码屡清楚后就很清晰了,这种担心是不必的。指令解码后的内容见level8-instruction-decode.txt。
5. 解码后的内容看,程序意图非常明显了:
X0=5, Y0=6
X[n]=3*X[n-1] + 9*Y[n-1]
X[n]=7*X[n-1] + 8*Y[n-1]
接下来就是分析迭代次数,先是向栈内推入127,126,125......1,并间隔插入30(指令位置),然后开始递归,往回递归的时候,每遇到指令32就继续递归,每遇到指令30就开始新一轮执行。因而对于执行次数:
Total_ = Total[126] + 126,
其中Total[1] = 1,Total[n] = Total[n-1]*2 + n,
Total[n]+n-2 = (Total[n-1] + n-1)*2
令Total_v[n] = Total[n]+n
Total_v[n]-2 = 2* Total_v[n-1]
Total_v[n] = 2*Total_v[n-1]+2
= 2*(2*Total_v[n-2]+2)+2
= 2^k * Total_v[n-k]+2^k+2^(k-1)+.....2
= 2^(n-1) * Total_v[1] + 2^n - 2
= 2^(n+1) - 2
Total[n] +n = Total_v[n] = 2^(n+1) - 2
Total_ = 2^127 -2
迭代次数知道了,剩下就是求解了。
首先明确模的恒等关系:
(a*b + c*d )%z = ((a%z)*(b%z) + (c%z)*(d%z))%z
为了后续公式的清晰,后面省略每一步计算中的取模运算
我们先定义:
X[2^k+n] = a[k]*X[n] + b[k]*Y[n]
即,X[n] = a[k]*X[n-2^k] + b[k]*Y[n-2^k]
则 a[k+1] = a[k]*a[k] + b[k]*c[k],
.....(也可以矩阵表示)....
Y[2^k+n] = c[k]*X[n] + d[k]*Y[n]
其中a[0] = 3, b[0]=9,c[0]=7,d[0]=8,
通过python脚本level8-calc.py计算
再定义:
X[2^k-2] = u[0]*X[2^(k-1)-2] + v[0]*Y[2^(k-1)-2]
= u[0]*(a[k-1] * X[2^(k-2)-2] +b[k-1]*Y[2^(k-2)-2])+
v[0]*(t[k-1] * X[2^(k-2)-2] +s[k-1]*Y[2^(k-2)-2])
= u[1]*X[2^(k-2)-2] + v[1]*Y[2^(k-2)-2]
= u[k-1] *X[0] + v[k-1]*Y[0]
u[p+1] = u[p]*a[k] + v[p]*c[k],
其中p+k=126,
u[0]=a[126], v[0]=b[126], t[0]=c[126], s[0]=d[126],
Y[2^k-2] = t[0]*X[2^(k-1)-2] + s[0]*Y[2^(k-1)-2]
最终所求:
X[2^127-2]=(u[126]*x[0] + v[126]*y[0])%z
Y[2^127-2]=(t[126]*x[0] + s[126]*y[0])%z
计算过程见脚本level8-calc.py
后记,这个比赛是小伙伴发给我的,起初没在意,端午放假后发现还挺有意思,题目设计的很巧妙,立意也蛮好,出题人好有爱啊。。。
后记2:我还真去投了简历,以为是安全室招人,结果是搞后端业务开发的~
解题代码稍后贴上,看此帖热度吧。。。