IDF实验室-谁是卧底
来源:互联网 发布:将改革进行到底 知乎 编辑:程序博客网 时间:2024/05/05 13:28
一、原题
[原题链接]
武林中某知名杀手在一次任务中失败,然后逃窜到了人群中,当时那个社会并没有我们现在这么发达,满地都是文盲,而这些文盲甚至连一句完整的英文都说不出来,所以其实只要用心去发现,就会很容易发现这个稍微有些文化的杀手是谁哦~答案wctf{杀手的英文名}
人群→ http://pan.baidu.com/s/1bnq6nmR
密码: 988u
二、writeup
1、初步分析
下载文件,得到whoiswoldy.txt
,5.6MB
大小,用wc
命令统计一下:
wc whoiswoldy.txt输出为:0 1 5586640 whoiswoldy.txt
0行,1个词,55586640个字符,也就说文件里只有一个大字符串,字符数是千万级。
和小伙伴商量解体思路,观察到文件名有woldy
这个词,首先找一下它吧。 vim
打开之,/woldy
之,找是找到了,无奈文件太大,这个词出现过几十次,而且上下文里没有一个完整的单词,全是乱序字母。搜flag
结果一样。
继续观察文件,发现文件里零零落落地分散着许多单词,但周围全是无序字母,不成句子。然后小伙伴做了常用词的词频统计:
not: 497kill: 184iam: 292whois: 1you: 415name: 68my: 7510woldy: 50we: 9841are: 1855
结合题目——而这些文盲甚至连一句完整的英文都说不出来
懂了:
这是一个由英文单词和随机字母拼合而成的文件文件中应该存在完整的英文句子,flag就在那儿
接下来需要在文件中寻找整句的英文。
2、编写程序
用肉眼在5000多万
字符里找一句话无疑是大海捞针,需要编程解决,接下来要考虑编程的思路了。
一个直接的想法是:
句子由单词组成,只要能够找到文件里所有的单词,其中单词密度最大的地方就是完整英文句子所在的地方。
于是问题分为两步:
1)统计汇总文件中所有单词的位置(单词首字母在字符串中的位置)2)找到单词分布最为密集的位置
首先第一步,需要找一个txt
格式的字典文件,英文常用3000词应该足够,每行一个单词,文件名为words.txt
,然后跑程序记录每个单词出现过的位置就可以了。
#定义寻找字串位置的函数#subString:子串#fullString:完整字符串#indexs:字串出现的所有位置#即接受子串和完整字符串,返回子串在完整字符串里出现的所有位置#例如findSubStr('hi','hiworldhiworld')得到[0,7]def findSubStr(subString,fullString): indexs = [] fullLength = len(fullString) subLength = len(subString) for i in range(fullLength-subLength): if fullString[i:i+subLength] == subString: indexs.append(i) return indexs#读取题目文件内的字符串with open('whoiswoldy.txt','r') as f: s = f.read()#逐行读取字典words.txt内的单词,寻找其在s内的所有位置#places为单词出现过的所有位置places = []with open('words.txt','r') as f: while 1: line = f.readline() line=line.strip('\n') if not line: break places += findSubStr(line,s)#用pickle库将得到的位置数组places保存到result.txt中import picklewith open('result.txt','w') as f: pickle.dump(places,r)
运行此段程序,即可得到单词的位置统计,是一个list
,每一项为一整数,即出现过单词的位置,保存在result.txt
中。
上一段程序存在性能问题,直接用python
运行的时间目测要上小时,不想费时间优化,改用PyPy
解释器,2分钟跑完。由此发现对于纯python
代码,尤其是循环较多的情况下,PyPy
比CPython
真的要快上好多倍。
然后第二步,统计单词密度。
由第一步得到的位置数据,每个位置附近出现单词数的多少即可反映单词的密度。比如假设得到的位置数据是这样的:
[1,8,13,15,20,25,28,100,220,33000...]
显然在1~28
单词分布密集,极有可能这里就是一句话。
一句话的长度大概几十词左右,长一点的会上百,简单的取100
这个参数,统计[position,position+100]
这一范围内出现了多少个单词。
比如对于上一个列表,对于位置'1'
,在[1,101]
范围内,有1,8,13,15,20,25,28,100
共8个位置出现过单词,即1往后100的范围内有8个单词。所以对1
这个位置的密度记为8
。同理位置8
的密度记为7
。
而对于100
这个位置,在[100,201]
范围内除了100
本身没有其他位置出现过单词。因此对于位置100
的密度记为1。
需要注意的是进行统计之前首先要对位置数据进行去重复处理。
第二步程序:
#读取题目字符串with open('whoiswoldy.txt','r') as f: s = f.read()#加载前一步得到的位置数据import picklewith open('result.txt','r') as f: b = pickle.load(f)#将位置数据b,一个list转化为集合set,即可实现去重复处理#同时查找元素的时间由list的O(n)变为set的O(1),因为set是hashable的setb = set(b)#den为密度统计,每个元素的形式为(int位置,int密度)den = []for number in setb: k = 1 for i in range(number,number+100): if i in setb: k += 1 den.append((number,k))#根据密度进行排序sortedDen = sorted(den,key=lambda x:x[1],reverse=True)#输出密度排名前10的位置print sortedDen[0:10]index = sortedDen[0][0]print s[index:index+150]
其中print sortedDen[0:10]
的输出为
[ (3197571, 34), (3197573, 33), (3197581, 32), (3197583, 31), (3197586, 31), (3197600, 31), (4738813, 31), (4738831, 31), (3197603, 30), (3197618, 30)]
几乎可以肯定319757x~31976xx
存在完整句子了。 index = sortedDen[0][0] = 3197571
print s[index:index+150]
将3197571
及其往后150个字符打印出来,结果为
ananjpywlqclassifyubcjesqtqyjhazbornndomhfchvlc(手打分隔线)--whatwillyouseeifyouthrowthebutteroutthewindow--(手打分隔线)wzqmtwmyjutipvqetrsshyosypzydevelopponaxoezspdespairkuoqig
nice,看到了这么一句 what will you see if you throw the butter out the window
用眼睛看就知道这是个谜语,搜之,谜底
butterfly
三、flag
wctf{butterfly}
四、知识点
pypy神器
- IDF实验室-谁是卧底
- 谁是卧底
- idf实验室
- 谁是卧底-CTF题目writeup
- 我的谁是卧底游戏代码总结
- IDF实验室WriteUp
- IDF实验室:牛刀小试--啥?
- IDF实验室-抓到一只苍蝇
- IDF实验室之牛刀小试
- IDF 实验室 啥?
- IDF实验室 摩斯密码
- 谁是卧底的Android应用 (原型源码)
- 主流架构打造社交游戏《谁是卧底》(一)
- IDF实验室之牛刀小试啥?
- IDF实验室:倒行逆施--python ByteCode
- IDF实验室:天罗地网--COOKIE欺骗
- IDF实验室:牛刀小试--摩斯密码
- IDF实验室-伟人的名字
- 微信获取openID以及token
- 第十三周--阅读程序(1)
- STL源码剖析---heap
- 液晶拼接幕墙
- profile介绍
- IDF实验室-谁是卧底
- 60寸液晶拼接墙
- 创建一个图片搜索引擎的完整指南
- Git使用1
- 第十三周项目1————动物这样叫(1)
- 屏幕拼接墙
- SAP生产订单状态详解
- 黑马程序员——Map集合
- 根据url获取视频的缩略图和数据