鱼C论坛

 找回密码
 立即注册
查看: 6341|回复: 53

[技术交流] #鱼C五周年嘉年华#《Python 闯关》完整过关攻略

[复制链接]
发表于 2015-2-22 19:11:44 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 戴宇轩 于 2015-2-27 13:34 编辑

<过关攻略>

首先AT小甲鱼老师和版主们: @小甲鱼 @~风介~ @wei_Y (不分优先级, 仅根据UID大小排序)

Python 鱼C闯关攻略(这里都用的是Python 3), 程序都测试过, 运行正常:
第一关(welcome.html)
这一关有点弱智(&#172;_&#172;)...不能按右键, 那就按下F12调出开发者工具, 查看网页源代码, 注释里有一段写着: gogogo.html
So, 下一关地址是: gogogo.html
或者直接上Python!
  1. import urllib.request

  2. print(urllib.request.urlopen('http://python.fishc.com/challenge/welcome.html').read().decode('utf-8'))
复制代码

第二关(gogogo.html)
不要告诉我你没有发现过关地址:sweat:。。。
点击图片右上角, 直接进入下一关, Done!

第三关(hidden.html)
这一关跟第一关差不多, 不过这次直接右键, 查看源代码, 注释又很明确的写着: forward.html, 所以...

第四关(forward.html)
这一关的提示纯属迷惑人, 版主你这是玩我们?。。。
点击 Tip 按钮, 密码就在下面, 输入密码, 过关!
或者来个Pythonic一点的, 直接上脚本!
  1. import urllib.request
  2. import re

  3. data = urllib.request.urlopen('http://python.fishc.com/challenge/forward.html').read().decode('utf-8')
  4. print(re.findall(r'[a-z]+\.html', data))
复制代码

得到  randint.html, 输入地址, 过关!

第五关(randint.html)
这一关更简单了, Python下标从0开始, 0, 英文就是zero, 所以下一关地址...zero.html

第六关(zero.html)
网页标题写着: this is first, 显然过关地址是this.html,
什么? 问我为什么? 版主以前写的标题是: This is the answer, 翻译过来是: this是答案, 现在版主为了加大难度, 改了一下, 强烈建议大家揍版主
正确解法:
因为Python的禅(The zen of Python)写在this模块里, 所以答案是this
  1. import this
  2. print(this.s)
复制代码


第七关(this.html)
右边写着大大的2和2的上标, 是问2的多少次方
再看内容, 这关告诉我们一月有30天, 所以答案是2 ** 30?
那你就错了! 那是版主迷惑我们, 因为1月有31天, 所以结果是: 2 ** 31
脚本:
  1. print(str(2 ** 31) + '.html')
复制代码

下一关地址是: 2147483648.html

第八关(2147483648.html)
这关让我们'解密', 看图片, 每个字母向后移动了三位, 我们再来看密码:
bhv,brx ilqg d sdvvzdug,lw'v 'loyni',exw li brx qhhg fudfn.

这里面有一个词用引号括了起来, 我们重点来看 'loyni' 这个词, 我们要写一个程序来将这个词的字母向后移动1~25位, 来看看有没有真正的'单词'。。。
过程就像: 第一次把a变成b, 第二次变成c......最后一次变成z

  1. for i in range(1, 26): # 向后移1~25位
  2.     result = '' # 结果存放处
  3.     for j in 'loyni':
  4.         result += chr(97 + (ord(j) - 97 + i) % 26) # 考虑到超过z要回到a, 将结果加入result
  5.     print(result, i)
复制代码


执行这个程序, 在执行到第20个循环时, 我们终于看到了一个真正的单词: 'fishc' !!!

那么下一关地址: fishc.html
过关!

第九关(fishc.html)
我们来看看网页源代码, 看到一大串密文, 把它复制下来, 并保存为 code.txt:
  1. f = open('code.txt')
  2. temp = f.read()
  3. f.close
复制代码


接下来都要用到temp, 就是把下面的脚本接到上面的脚本上:
  1. result = '' # 这里放结果
  2. for i in temp: # 逐个查看字符串
  3.     if i.isalpha(): # 如果i是字母
  4.         result += i # 将i放入结果
  5. print(result)
复制代码


或者你可以用正则

  1. import re

  2. print(''.join(re.findall(r'\w', temp)))
复制代码

得到结果: carpediem
不过这样实在是大材小用!

再来一个很Pythonic的写法!
  1. print(''.join(i for i in temp if i.isalpha())) # 一行解决!
复制代码

同样得到结果: carpediem

下一关地址: carpediem.html

第十关(carpediem.html)
这关要我们输入密码。。。
先看源代码, 有一行是这样的:
  1. if (passwd=="letgo") {alert("OK,密码正确!"); window.location="letgo.html";}
复制代码

正常人应该都能看得懂一些的...翻译如下:
如果密码为letgo, 显示密码正确, 并进入letgo.html

So......输入密码letgo或者输入地址letgo.html

轻松过关!

第十一关(letgo.html)
这一关提示, 让我们点击密码页, 结果进入了论坛, 不要怀疑自己点错了。。。

仔细观察一下主页, 你会发现页面上方有一大串16进制的数字, 应该是ASCII码

我们些一段程序来将这些数字转为明文:
  1. source = '5A 75 6C 77 68 23 77 6B 68 23 66 72 67 68 31 4A 6F 68 75 6E 6C 27 61 6F 6C 27 64 76 79 73 6B 35'
  2. source = source.split(' ') # 按照空格分离
  3. result = ''.join(chr(int(i, 16)) for i in source) # 把16进制的ASCII码转为ASCII字符串, 因为是16进制, 所以要加上: 16
  4. print(result)
复制代码
  1. Zulwh#wkh#frgh1Johunl'aol'dvysk5
复制代码

结果, 我们得到了一堆没用的文字?

当然不是! 前面第八关不是用了字母后移的方法得到了明文吗?

我们试试用之前的程序来解密
首先把各种符号数字变成空格或者去掉

  1. print("Zulwh#wkh#frgh1Johunl'aol'dvysk5".replace('#', ' ').replace("'", ' ').replace('1', ' ')[:-1])
复制代码


得到结果Zulwh wkh frgh Johunl aol dvysk

等等! 我好像发现了什么!

密码中有两个大写字母, 很可能要将密码分成两部分!

将它们手动转换成这样(元组里两个字符串):
('zulwh wkh frgh', 'johunl aol dvysk')
我们再回到密码页, 发现密码的左右两边有一些点和杠
这难道是摩尔斯电码!?

翻译一下:

左边 ...-- 是 3
右边 --... 是 7

可能是要将字母向前或者向后移动3位和7位, 而我们有两个词组(刚才的元组)

那我们试试前面部分向后移动3位或23位(向后移动23位就是向前移动3位)

后面部分向后移动7位或者19位(向后移动19位就是向前移动7位)

我们写个程序来验证一下:

  1. counter = True
  2. for i in ('zulwh wkh frgh', 'johunl aol dvysk'):
  3.     result = []
  4.     if counter:
  5.         result.append('')
  6.         for j in i: # 后移3位
  7.             if j != ' ':
  8.                 result[-1] += chr(97 + (ord(j) - 97 + 3) % 26)
  9.             else:
  10.                 result[-1] += ' '
  11.         result.append('')
  12.         for j in i: # 前移3位
  13.             if j != ' ':
  14.                 result[-1] += chr(97 + (ord(j) - 97 + 23) % 26)
  15.             else:
  16.                 result[-1] += ' '
  17.     else:
  18.         result.append('')
  19.         for j in i: # 后移7位
  20.             if j != ' ':
  21.                 result[-1] += chr(97 + (ord(j) - 97 + 7) % 26)
  22.             else:
  23.                 result[-1] += ' '
  24.         result.append('')
  25.         for j in i: # 前移7位
  26.             if j != ' ':
  27.                 result[-1] += chr(97 + (ord(j) - 97 + 19) % 26)
  28.             else:
  29.                 result[-1] += ' '
  30.     print(result)
  31.     counter = False
复制代码


得到结果:
第一个词组:
+3: cxozk znk iujk (wrong)
-3: write the code (right)

第二个词组:
+7: qvobus hvs kcfzr (wrong)
-7: change the world (right)

把对的部分拼到一起, 变成了:
write the code change the world
(让代码改变世界)

题目让我们找到回文字符串, 只有首字母是回文

取首字母, 得到wtcctw
所以我们得到了下一关地址(不是下关地址!): wtcctw.html

(&#8722;_&#8722;#)NiMa过这关真不容易!

第十二关(wtcctw.html)
这关看似让我们输入密码, 其实源代码里根本就没有下一关地址!

所以我们忽略密码
接下来看看剩下的部分:
True是唯一的单词

所以我们立刻得知下一关地址: true.html

第十三关(true.html)
这题似乎没有着手点。但是看看图片, 上面写了'zip', 所以网页名和zip有关
我们将网页名改成true.zip并下载
打开后竟然提示要密码!

没关系~~下载一个破解软件(破解zip密码的)
得到密码: ~@_#%$
输入密码并解压, 里面有一个txt文件, 打开它, 问我们有没有吃过'泡菜', 泡菜, 英文名pickle...
所以下一关地址就是: pickle.html

第十四关(pickle.html)
由于小甲鱼教我们pickle模块时, 习惯将pickle文件名写成*.pkl
根据题意, 结合13关方法, 下载pickle.pkl
所以我们用python的pickle模块打开它, 代码如下:
  1. import pickle

  2. f = open('pickle.pkl', 'rb')
  3. result = pickle.load(f)
  4. f.close()
  5. print(type(result), result)
复制代码


我们发现得到的数据是一个列表, 里面存着几个字符串, 我们试着逐行打印它:
  1. print('\n'.join(result))
复制代码

  1. password:
  2.   ****      ****
  3. ******      ******
  4. ******    ******
  5.   ******  ******
  6.    *****  *****
  7.     **********
  8.      ********
  9.       ******
  10.        ****
  11.         **
复制代码

得到一个心形, 英文是heart

So, 下一关地址: heart.html

第十五关(heart.html)
这关的意思是让我们找出所有左右两边分别只有3个大写字母的小写字母
再来看看源代码, 里面有一串密码

提示写着: 这题可以用正则解, 所以我们用正则...我们将密码存在 code.txt 里:
  1. import re

  2. f = open('code.txt')
  3. string = f.read()
  4. f.close
  5. pattern = re.compile('(?<=[a-z][A-Z]{3})[a-z](?=[A-Z]{3}[a-z])') # 这是正则表达式, {3}表示重复三次, 应该能看懂吧...
  6. result = re.findall(pattern, 'a' + string + 'a') # 为了匹配开头结尾, 在开头和结尾分别加上一个小写字母
  7. print(''.join(result))
复制代码


完成! 结果是onwya, 但是你会发现它不对, 因为它被打乱了!

所以我们再写这样一段, 来找出所有排列组合

  1. import itertools

  2. string = 'onwya'
  3. urls = ('http://python.fishc.com/challenge/%s.html' % (''.join(i)) for i in itertools.permutations(string, 5))
复制代码


itertools.permutations函数需要两个参数, 第一个是迭代对象, 第二个是从迭代对象里抽取几个不同的值(这里是5个)

现在urls里面存放着所有可能的网页名, 可以用
  1. for i in urls:
  2.         print(i)
复制代码

来浏览, 网页格式是 http://python.fishc.com/challenge/某某某.html

于是我们找到了所有组合, 接着一个一个找?
那当然, 不过我们用urllib, 脚本如下:

  1. import urllib.request

  2. print('请稍等...')
  3. for i in urls:
  4.     try:
  5.         urllib.request.urlopen(i) # 试着打开这个链接
  6.     except: # 如果报错(页面不存在)
  7.         continue # 尝试下一个地址
  8.     else: # 没有报错的话, 就是找到了过关地址
  9.         print('过关地址是:', i) # 将地址打印出来
  10.         break # 跳出循环
复制代码


大功告成! 地址是noway.html

第十六关(noway.html)
这一关除了标题之外, 其他信息纯属迷惑人...
看看标题: Dawn!
那过关地址就是dawn.html。。。
(PS: 这是我除了第二关以外过的最快的一关(&#8722;_&#8722;#)。。。)
正确解法:
用记事本打开图片, 翻到最后, 写着下一关地址: dawn.html

第十七关(dawn.html)
这一关的提示似乎和下一关无关, 看看源代码, 里面有线索, 是一个由数字组成的地址, 进入下一个, 又有一条线索。。。据说有49层!
这样手真的会抽筋的。。。
不说了, 上脚本! 召唤(import)正则!
  1. import re
  2. import urllib.request

  3. pattern = re.compile(r'\d+\.html') # 过滤出线索提供的地址
  4. url = 'http://python.fishc.com/challenge/%s' % (re.findall(pattern, urllib.request.urlopen('http://python.fishc.com/challenge/dawn.html').read().decode('utf-8'))[-1]) # 形成一个完整地址, 方便以后用

  5. try:
  6.     while True: # 尝试每一个线索, 直到找不到线索为止
  7.         url = 'http://python.fishc.com/challenge/%s' % (re.findall(pattern, urllib.request.urlopen(url).read().decode('utf-8'))[-1]) # 替换为下一个地址
  8. except: # 如果找完了所有线索
  9.     print(urllib.request.urlopen(url).read().decode('utf-8')) # 输出网页源代码
复制代码


完成! 源代码里写着: 本关地址cramp.html
打开它, 提示写着: 本关地址 cramp.php

进入cramp.php

第十八关(cramp.php)
这关看似没有着手点, 实际上, 关键词是: 登录

我用的是firerox浏览器, 看到这个php有一个cookie, 里面有一个参数: login, 它的值为: no

cramp.php 提示我们要登录, 于是将login的值改成yes, 然后刷新

(如何改cookie? 网上教程多得是!)

教程: http://jingyan.baidu.com/m/article/6b18230954dbc0ba59e15960.html

接着, 网页上出现了下一关地址~: logins.html

请同时参考以下聊天记录~~~

wei_Y 2015-2-8 14:35
想让你们改cookies的。。

戴宇轩 2015-2-8 14:38
改cookies? 怎么改?

wei_Y 2015-2-8 14:40
把里面login的no改成yes。。

戴宇轩 2015-2-8 14:41
然后再打开网页?

wei_Y 2015-2-8 14:43
刷新。。

wei_Y 2015-2-8 14:44
靠。一不小心说出来了。。

第十九关(logins.html)
这一关的密码页提示我们要用IE5.79, 而网页用User-Agent来识别我们的浏览方式, 我们可以更改User-Agent, 改为 Mozilla/4.0 (compatible; MSIE 5.79; Windows NT 5.0), 脚本如下:
  1. import urllib.request

  2. header = {'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.79; Windows NT 5.0)'}
  3. data = urllib.request.urlopen(urllib.request.Request('http://python.fishc.com/challenge/logins.php', None, header))

  4. print(data.read().decode('utf-8'))
复制代码
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.         <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
  5.         <title>loading.</title>
  6. </head>
  7. <body bgcolor="#E8F9E8">
  8. <h1>Python——鱼C闯关。第十九关。</h1><hr>Yes,密码是fishcpython</body>
  9. </html>
复制代码
好的~~~我们有了密码, 接着回到logins.html, 输入密码

。。。。。。

不幸的是, 版主在源代码里多加了一个斜杠, 不能进入checks.php, 只能用程序代替了!
  1. import urllib.request
  2. import urllib.parse

  3. passwd = urllib.parse.urlencode({'passwd': 'fishcpython'}).encode('utf-8') # 密码

  4. data = urllib.request.urlopen(urllib.request.Request('http://python.fishc.com/challenge/checks.php', passwd)) # 带密码进入checks.php

  5. print(data.read().decode('utf-8')) # 查看源代码
复制代码
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.         <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
  5.         <title>loading.</title>
  6. </head>
  7. <body bgcolor="#E8F9E8">
  8. <script>location.href='loading.html';</script></body>
  9. </html>
复制代码
所以下一关地址是 loading.html

第二十关(loading.html)
这一关还不是终点, 版主已经把密码告诉我们了。。。输入密码: woshikeaidexiaomima
然后在跳转的最后一瞬间看一下标签页!!!==。细心一点可以看到 先经过turn22.php, 再跳到 404.html, 来看一下turn22.html源代码:
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.         <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
  5.         <title>404 NOT Found!</title>
  6. </head>
  7. <body>
  8. <h1>Python——鱼C闯关。第21关。</h1>
  9. <hr>
  10. <div align="center">
  11. <img src="pic/rsa/rsa.png">
  12. <p>下关地址: ?????????.html</p>
  13. </div>
  14. <hr>
  15. Tip: 简单粗暴就是干!<br />
  16. 公钥(2178551,2175599)<br />
  17. 密文[1704953, 968245, 778054, 778054, 1742841, 1573398, 1742841, 778054, 544638]
  18. </body>
  19. <!-- gift key: 1F8DD4B60ACFC294091D09954924C48E -->
  20. <script>location.href='404.html'</script></html>
复制代码

这就是传说中的RSA算法!?
上百度学习学习, 然后经过复杂的计算, 发现私钥等于公钥!
下面上一段程序来将密文解密:
  1. key = (2178551, 2175599) # 密钥
  2. password = [1704953, 968245, 778054, 778054, 1742841, 1573398, 1742841, 778054, 544638] # 密文

  3. temp = [pow(i, key[1], key[0]) for i in password] # 解密算法, 相当于 i ** key[1] % key[0]

  4. # >>> temp
  5. # [23, 9, 14, 14, 5, 18, 5, 14, 4]
  6. # 你会发现每个数字都在1~26之间, 换成小写字母试试

  7. result = [chr(96 + i) for i in temp] # 每个值增加96以后就是对应字母的ASCII值

  8. print(''.join(result))
复制代码
得到结果: winnerend, 根据源代码提示, 下一关地址是 winnerend.html

第二十一关(winnerend.html)
照样查看源代码。。。
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.         <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
  5.         <title>Challenge never end.</title>
  6. </head>
  7. <body bgcolor="#E8F9E8">
  8. <h1>Python——鱼C闯关。第21关.</h1>
  9. <hr>
  10. <p>You win.</p>
  11. <p>gift key: A6105C0A611B41B08F1209506350279E</p>
  12. <hr>
  13. Tip:
  14. 你知道python怎么压缩字符串吗?
  15. <!-- Tip:b'x\x9c\xf3u1U\xc8OSP\xcf,\xcf\xccSWH\xccKQHIM\xceOI\x05\t\xa6g\xa6\x95(d\xa7V\xea\x01\x00\xdb\x91\x0c\x0e'-->


  16. </body>
  17. </html>
复制代码
Python 如何压缩字符串? 用zlib模块, 将Tip里的字符串复制下来, 解压:
  1. import zlib

  2. print(zlib.decompress(b'x\x9c\xf3u1U\xc8OSP\xcf,\xcf\xccSWH\xccKQHIM\xceOI\x05\t\xa6g\xa6\x95(d\xa7V\xea\x01\x00\xdb\x91\x0c\x0e'))
复制代码
  1. MD5 of 'iwin' and decode of gift key.
复制代码
中文翻译: ('iwin' 和 gift key 的解码结果) 的 MD5
应该是作为gift key, 随便找一个MD5解密的网站, 得到结果: yes
把它和'iwin'拼起来, 变成'yesiwin'后, 算MD5
  1. import hashlib

  2. a = hashlib.md5()
  3. a.update('yesiwin')
  4. print(a.hexdigest().upper())
复制代码
得到结果: 7AB0F4EF2F04946B64CFAA8B722E22CC
这就是最终的gift key


Challenge never end.

</过关攻略>

评分

参与人数 3荣誉 +18 鱼币 +23 贡献 +8 收起 理由
freeparty + 5 + 5 + 3 感谢楼主无私奉献!
拈花小仙 + 8 + 8 + 5 感谢楼主无私奉献!
康小泡 + 5 + 10 支持楼主!

查看全部评分

本帖被以下淘专辑推荐:

  • · Python|主题: 15, 订阅: 0
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2015-2-25 08:19:12 | 显示全部楼层

回帖奖励 +5 鱼币

有没搞错这还要隐藏啊!!!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-4 13:22

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表