python趣味挑战WP

目录

第0题

第一题

第二题

第三题

第四题

第五题

第六题

第七题

第八题

第九题

第十题

第十一题

第十二题

第十三题

第十四题

第十五题

第十六题

第十七题

第十八题

第十九题

第二十题

第二十二题

第二十三题

第二十三题


 

第0题

第0题应该算个热身题,有简单提示Hint: try to change the URL address,再仔细观察图片尝试将2的38次方作为下一道题的链接入口,即274877906944

所以将http://www.pythonchallenge.com/pc/def/0.html第0题的

链接改成http://www.pythonchallenge.com/pc/def/274877906944.html就可以看见第一题

第一题

第一题通过观察图片可以推断应该是个简单的字母位移题,K到M,O到Q,E到G都是向后移了两位,由此推测解密方式均是向右移位两位

用一个现成工具可以很快的得到解密后的答案为

i hope you didnt translate it by hand. thats what computers are for. doing it in by hand is inefficient and that's why this text is so long. using string.maketrans() is recommended. now apply on the url. 

其实这里已经可以知道下一题的链接,但是它告诉我们不要等手动的去转换,而是用一种算法来实现,因为遇到很长的字符串时手动转换的效率不高,另外它还给了我们另一种方法就是使用 string.maketrans() 进行转换,所以就有了第二种解法

s = """
g fmnc wms bgblr rpylqjyrc gr zw fylb. rfyrq ufyr amknsrcpq ypc dmp. bmgle gr gl zw fylb gq glcddgagclr ylb rfyr'q ufw rfgq rcvr gq qm jmle. sqgle qrpgle.kyicrpylq() gq pcamkkclbcb. lmu ynnjw ml rfc spj.
"""
t = str.maketrans("abcdefghijklmnopqrstuvwxyz", "cdefghijklmnopqrstuvwxyzab")
a=s.translate(t)
print(a)

得到了如上图转换出来的一致的答案,所以根据转换后的提示可得下一题的链接为本题链接后移两位map.html变成ocr.html,进入第二题http://www.pythonchallenge.com/pc/def/ocr.html

第二题

根据图片提示,查看网页源码:

 

可以观察到提示 find rare characters in the mess below,所以需要编写py程序来找出这堆字符串中的字母,想到可以使用re模块来解决这个问题,编写如下代码

import urllib.request as ur
import re

url = "http://www.pythonchallenge.com/pc/def/ocr.html"

def main():
    global url

    response = ur.urlopen(url)
    body = response.read()

    text = re.search("<!--\n%(.|\s)+",body.decode())
    dic={}
    #print(text.group(0))
    for x in text.group(0):
        if x not in dic:
            dic[x] = 1
        else:
            dic[x] += 1 

    print(dic)
    for i in dic:
        if (dic[i]== 1 and 'a' <= i <='z'):
            print(i)

if __name__ == '__main__':
    main()

 

运行代码找到字母,可以拼成单词equality,更改网页链接,得到第三题的入口http://www.pythonchallenge.com/pc/def/equality.html

第三题

提示:One small letter, surrounded by EXACTLY three big bodyguards on each of its sides.需要找出两边都被三个大写字母包围的小写字母,查看网页源代码,发现需要解密的字符串藏在注释中,可以和第二题一样使用re模块来处理字符串

import urllib.request as ur
import re

url = "http://www.pythonchallenge.com/pc/def/equality.html"

def main():
    response = ur.urlopen(url)
    body = response.read()

    pattern="[^A-Z][A-Z][A-Z][A-Z]([a-z])[A-Z][A-Z][A-Z][^A-Z]"

    result = re.findall(pattern,body.decode())
    print(result)

if __name__ == '__main__':
    main()

运行结果为linkedlist,尝试修改url,得到提示应该为php文件

可得下一题入口为http://www.pythonchallenge.com/pc/def/linkedlist.php

第四题

只有一张图片,查看网页源码,可以看到标题有follow the chain,又有一个href,点击之后页面显示“next nothing is ....”猜想是不断地访问下一个url直到答案出现

再仔细查看源码注释可以得到提示:urllib may help. DON'T TRY ALL NOTHINGS, since it will never end. 400 times is more than enough,根据之前的尝试,应该只需要用urllib去抓去the next nothing is后面跟的数字,然后改变url

import urllib.request as ur
import re
url = "http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing=8022"
def main():
    global url
    global body
    while 1:    
        print(url)
        response = ur.urlopen(url)
        body = response.read()
        pattern="and the next nothing is ([0-9]+)"
        #search从string的anywhere开始找
        result = re.search(pattern,body.decode())
        if result:
            num = result.group(1)
            print(result.group(0))
            print(num)
            url = "http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing=%s" % num
        else:
            break
    print(body)
if __name__ == '__main__':
    main()

一直运行到最后得到peak.html,可以知道下一题链接为http://www.pythonchallenge.com/pc/def/peak.html

第五题

得到第五题的图片,只有一个pronounce it! 的提示,查看源码:

可以得到提示 peak hell sounds familiar ?  peak hell读起来像是什么?查找py中的模块,有一个pickle模块,专门用于序列化和反序列化

源码中有一个peakhell的标签,并且后面写了banner.p,所以编写代码尝试对其进行反序列化

import urllib.request
import pickle

url = "http://www.pythonchallenge.com/pc/def/banner.p"

with urllib.request.urlopen(url) as f:
    print(pickle.load(f))

观察到反序列化之后是一系列的数组,可以看见第一个数组和最后一个数组的第二位都是95,猜测是不是一个95的矩阵,可以将输出的格式调整一下,可以观察到每一行的数字相加都等于95,可以验证刚才的想法,并且应该是个图形矩阵,输出相应次数的符号,所以最终调整代码

import urllib.request
import pickle

url = "http://www.pythonchallenge.com/pc/def/banner.p"

with urllib.request.urlopen(url) as f:
    result = pickle.load(f)
    for r in result:
        for i in r:
            for j in range(i[1]):
                print(i[0],end="")
        print()

可得到用#排列的一个图形,得到单词channel

更改url,可得到下一题链接:http://www.pythonchallenge.com/pc/def/channel.html

第六题

当图片没有提示的时候还是习惯性查看源码,可以看到注释zip,把html的后缀改成zip,下载一个压缩包

 

可以观察到解压后的文件夹里有许多的txt文档,打开README文档,得到两个提示,并且随机打开以后写的是Next nothing is……,想到之前的不停跳转链接,这道题解法应该和第四题是一样的,所以编写了以下代码:

import re
import glob as gb
import os
nextNothing ='90052'

basepath = 'C:/Users/Bumor/Desktop/channel/'
toalpath = gb.glob(basepath)#获取所有文件路径
##此函数并无太多意义 只是回顾一下之前的知识
i =0
def getName():
    global i
    fileNumber = []
    for path in toalpath:
        i += 1
        _, filename = os.path.split(path)
        number = re.search("\d+",filename).group(0)
        fileNumber.append(number)
    return fileNumber,i

def anwser():
    global nextNothing
    number = re.compile("\d+")
    for i in range(0,909):
        with open('C:/Users/Bumor/Desktop/channel/'+nextNothing+'.txt') as f:
            reader = f.readlines()
            number = re.search('\d+',str(reader)).group(0)
            if number:
                print(number)
                nextNothing = number
            else:
                print(reader)

if __name__ == '__main__':
    # print(getName())
    anwser()

但是运行到46145的时候发生了bug,打开46145.txt查看,Collect the comments.可以理解为收集注释,根据提示继续解题

使用py的zipfile模块尝试求解:

import re
import zipfile

global nextNothing
nextNothing ='90052'

file = zipfile.ZipFile('C:/Users/Bumor/Desktop/channel.zip','r')
print(file)
for name in file.namelist():
    
    line = str(file.read("%s.txt" %nextNothing))
    m = re.search('Next nothing is ([0-9]+)', line)
    print (file.getinfo("%s.txt" % nextNothing).comment.decode("utf-8"), end=" ")
    nextNothing = m.group(1)

运行后得到

通过对字母的判断可以大概的得到一个单词oxygen,氧气的单词,更改url,得到第七题的入口http://www.pythonchallenge.com/pc/def/oxygen.html

第七题

查看源码并没有发现有什么注释或者异常,有一张oxygen.png,但是打开也没有什么不正常的,但是图片中有类似马赛克的东西,所以想到会不会是考查py的图像解析,py的图像处理使用image library

import urllib.request as ur
import PIL.Image as Image

file = open('oxygen.png', 'wb')  
file.write(ur.urlopen('http://www.pythonchallenge.com/pc/def/oxygen.png').read())  
file.close()  

image = Image.open('oxygen.png')  
data = image.convert('L').getdata()  

message = []  
for i in range(3,608,7):  
        message.append(chr(data[image.size[0]*50+i]))
result=''.join(message)
print(result) 

解析图片信息,得到一串话,并且后面跟着的数组,对数组进行处理

看到数组首先想到ASCII码,可以直接用在线工具进行转换或者编写一段代码

numbers = [105, 110, 116, 101, 103, 114, 105, 116, 121]  
word = []  
for number in numbers:  
        word.append(chr(number)) 
result=''.join(word)
print(result)  

转换出来一个单词integrity,修改url得到第八题的链接http://www.pythonchallenge.com/pc/def/integrity.html

第八题

图片提示还有一个link,并且打开源码看见了一个href

打开之后发现是一个登录框,并且在源码的注释中有一个un和pw,应该是用户名和登录密码,值应该是后面的编码,开头的BZh91AY相同,通过搜索发现,该种编码方式应该是压缩编码,可以用py的bz2模块尝试解码

import bz2

def main():
    username = bz2.decompress(un)
    password = bz2.decompress(pw)
    print(username.decode(), password.decode())

if __name__ == '__main__':
    un = b'BZh91AY&SYA\xaf\x82\r\x00\x00\x01\x01\x80\x02\xc0\x02\x00 \x00!\x9ah3M\x07<]\xc9\x14\xe1BA\x06\xbe\x084'
    pw = b'BZh91AY&SY\x94$|\x0e\x00\x00\x00\x81\x00\x03$ \x00!\x9ah3M\x13<]\xc9\x14\xe1BBP\x91\xf08'
    main()

求解后得到两个单词huge file,输如入登录框尝试登陆,登陆后直接进入第九题

第九题

标题写着connect the dots,猜测可能需要连接图中的黑点,查看源码

提示first+second=?,这俩后面都是一个一个数字,猜测应该是像素点,估计是两段像素点拼接在一起,得到一个图像,应该使用py的PIL模块,图像处理来解题

import PIL.Image as Image
import PIL.ImageDraw as ImageDraw

first = [……]
second = [……]
im = Image.new("RGBA", (500, 500), "#FFFFFF")
draw = ImageDraw.Draw(im)
draw.line(first, fill="#000000")
draw.line(second, fill="#000000")
im.save("D:/result.bmp")

得到一张牛的图片,尝试输入cow,emmm应该是bull

再次更改url,进入下一题http://www.pythonchallenge.com/pc/return/bull.html

第十题

图片一开始就给了提示,计算a[30]的长度?所以这个数组在哪里?打开网页源码查看

有一个href,点进链接

观察数组,观察规律进行解密发现,后面一个数组是对前一个数组的有几个数字的一个表述,编写代码

strings = ['1','11']  

for i in range(1,31):
        j = 0  
        temp = ''  
        while j < len(strings[i]):  
                count = 1
                while j<(len(strings[i])-1) and (strings[i][j]==strings[i][j+1]):  
                        j = j + 1  
                        count = count + 1  
                temp = '%s%d%c' % (temp,count,strings[i][j])  
                j = j + 1  
        strings.append(temp)  
print (len(strings[30]))

得到答案5808,得到下一题的入口http://www.pythonchallenge.com/pc/return/5808.html

第十一题

这道题没有提示,打开源码也没有任何提示,标题为odd even,看起来也是没有任何的头绪,只能仔细观察图片,看起来像是两张图片叠加出来的,一张是黑色的点点,还有应该是彩色的正常图片,看起来感觉两张图的像素点交错分布了,彩色的那张像打了马赛克一样,所以可以用PIL模块和numpy模块来处理,尝试把看起来交错排列的两张照片的像素点分别挪到两边,看看效果,可以把图片下载下来进行图像处理

import numpy as np
import PIL.Image as Image

im0 = Image.open("cave.jpg")
mat0 = np.asarray(im0)
mat1 = np.zeros_like(mat0)
for i, row in enumerate(mat0):
    j1, j2 = -1, 319
    for j, pixel in enumerate(row):
        if (i + j) % 2 == 0:
            j2 += 1
            mat1[i][j2] = mat0[i][j]
        else:
            j1 += 1
            mat1[i][j1] = mat0[i][j]
im1 = Image.fromarray(mat1)
im1.save("result.jpg")

处理后的两张图片,可以在右边的图片上看到evil的单词,更改url,得到下一题链接http://www.pythonchallenge.com/pc/return/evil.html

第十二题

查看网页源码

发现图片命名为evil1,猜想是不是还有evil2、evil3……,所以更改url,查看图片

evil2提示后缀应该是gfx,将后缀改了以后下载了一个二进制文档

evil3提示没有更多evil了,但是还是想看看evil4,发现提示go back!然后继续查看evil5,发现已经404了,就不再继续查看了

返回刚才下载的二进制文档,想想该怎么处理这个二进制文档,题目的第一张图片是分牌图片,将卡牌分成了5堆,所以尝试将这个二进制文档的数据按照次序分成五份,循环分组,试图得到五组图片

with open("evil2.gfx", "rb") as file:
    file_bytes = file.read()
for i in range(5):
    piece_bytes = file_bytes[i::5]
    with open(f"{i}.jpeg", "wb") as file:
        file.write(piece_bytes)

输出的五张图可以拼成一个单词disproportionality,更改url,进入下一题http://www.pythonchallenge.com/pc/return/disproportional.html

第十三题

图片是一个座机的样子,并且写着phone that evil,还不明白是什么意思,先查看源码

有一个php的链接,打开看看

应该考察的py的xmlrpc模块,RPC(Remote Procedure Call,远程过程调用)尝试调用phone(),提示是打给evil,想到在上一题的时候说Bert是evil,所以尝试拨号给Bert

from xmlrpc.client import ServerProxy
server = ServerProxy("http://www.pythonchallenge.com/pc/phonebook.php")  
response = server.phone("Bert")
print(response)

得到结果555-ITALY,更改url,输入小写italy得到下一题http://www.pythonchallenge.com/pc/return/italy.html

第十四题

这道题目给了提示<!-- remember: 100*100 = (100+99+99+98) + (...  -->,但是不怎么能理解这个提示到底是什么意思,再看标题写的是walk around,绕着走……

感觉这道题目的提示就很迷,想了很久未果……第二次再打开仔细看了看,好像这道题目给了两张图,开始猜测应该是和PIL图像处理有关的,下面那张图看不出来什么眉目,猜测如果对第二张的图片进行处理,好像就知道提示在说什么了,用第二张图片像第一张的面包一样螺旋缠绕起来,然后结合注释的提示可能需要处理出一张100*100的图片,并且将第二张图按照提示(100+99+99+98) 的序列规律来由外向内的一圈一圈的环绕,尝试编写代码

def next_pos(x, y, f):
    if f == 0:
        if y != 99 and mat1[x][y + 1] == 0:
            y += 1
        else:
            x, f = x + 1, 1
    elif f == 1:
        if x != 99 and mat1[x + 1][y] == 0:
            x += 1
        else:
            y, f = y - 1, 2
    elif f == 2:
        if y != 0 and mat1[x][y - 1] == 0:
            y -= 1
        else:
            x, f = x - 1, 3
    elif f == 3:
        if x != 0 and mat1[x - 1][y] == 0:
            x -= 1
        else:
            y, f = y + 1, 0
    mat1[x][y] = 1
    return x, y, f

import numpy as np
from PIL import Image
im0 = Image.open("wire.png")
im1 = Image.new("RGB", (100, 100), "#FFFFFF")
mat1 = np.zeros((100, 100), dtype=np.int)
i, j, d = 0, -1, 0
for k in range(10000):
    i, j, d = next_pos(i, j, d)
    pixel = im0.getpixel((k, 0))
    im1.putpixel((i, j), pixel)
im1 = im1.rotate(-90)
im1.save("result.png")

得到一张猫咪的照片,更改url为cat

又出现了一个新网页,说猫的名字是uzi,那看来下一题链接应该是http://www.pythonchallenge.com/pc/return/uzi.html

第十五题

查看源码,得到两段注释,<!-- todo: buy flowers for tomorrow -->这段可以知道1月27日应该是一个什么特殊的日子,但是无法知道是年份,题目原图只提示了是1xx6年,基本解题思路应该是通过该日历来求解出正确的年份,来得到一个具体日期,该题用到py的datetime模块和calendar模块,再仔细观察图片,二月只有29天,说明是个闰年,并且1月1日是周四,通过这两个条件可以尽量缩小范围

import calendar
from datetime import date
d = date(1006, 1, 1)
while d.year < 2000:
    if d.isoweekday() == 4 and calendar.isleap(d.year):
        print(d.isoformat())
    d = d.replace(year=d.year + 10)

得到答案

<!-- he ain't the youngest, he is the second -->再查看第一条注释,应该选第二大的年份,那应该是1756年1月27日,可以百度一下这个日期

那很显然这个题目最终指向的是mozart,更改url进入下一题http://www.pythonchallenge.com/pc/return/mozart.html

第十六题

查看源码可知标题提示let me get this straight,显然本题需要用py的PIL模块来处理图片,将像素点拉直,观察图片可以看到很明显的粉色横线,可以以粉色为基准线,将所有像素点排直,就是将粉色点移到最左边

import PIL.Image as Image

im = Image.open("mozart.gif")
for y in range(im.size[1]):
    line=[im.getpixel((x, y)) for x in range(im.size[0])]
    idx=line.index(195)
    line=line[idx:]+line[:idx]
    [im.putpixel((x, y),line[x]) for x in range(len(line))]

im.show()

得到单词romance,更改url,进入下一题http://www.pythonchallenge.com/pc/return/romance.html

第十七题

看题目左下角有个图片很眼熟,翻回去看看,这个图片就是之前的跳转链接的the next nothing is……的那道题

查看源代码之后,发现图片名称为cookies,网页中也有cookies,查看一下

info中有you+should+have+followed+busynothing...的提示,直接更改url没有用,提示了第四关,那就尝试用第四关的url+busynothing试一试http://www.pythonchallenge.com/pc/def/linkedlist.php?busynothing

形式与第四题的形式差不多,那就修改第四题的代码来追踪url,修改第四题代码之后运行结果不能得到一个提示的html的文件,提示查看cookie,那就改为跟踪记录cookie值试试能否得到有效值

import urllib.request as request
import http.cookiejar as cookiejar
epochs = 0
busynothing = "12345"
info = ""
while str.isdigit(busynothing):
    epochs += 1
    url = f"http://www.pythonchallenge.com/pc/def/linkedlist.php?busynothing={busynothing}"
    cookie = cookiejar.MozillaCookieJar()
    handler = request.HTTPCookieProcessor(cookie)
    opener = request.build_opener(handler)
    response = opener.open(url)
    text = response.read().decode()
    print(f"{epochs:<3d}\tbusynothing = {busynothing}\n\t{text}")
    for c in cookie:
        print(f"\t{c.name} = {c.value}")
        if c.name == "info":
            info += c.value
        busynothing = str(text.split(' ')[-1])
    print(info.encode())

追踪118次得到一段BZ码BZh91AY%26SY%94%3A%E2I%00%00%21%19%80P%81%11%00%AFg%9E%A0+%00hE%3DM%B5%23%D0%D4%D1%E2%8D%06%A9%FA%26S%D4%D3%21%A1%EAi7h%9B%9A%2B%BF%60%22%C5WX%E1%ADL%80%E8V%3C%C6%A8%DBH%2632%18%A8x%01%08%21%8DS%0B%C8%AF%96KO%CA2%B0%F1%BD%1Du%A0%86%05%92s%B0%92%C4Bc%F1w%24S%85%09%09C%AE%24%90

之前也做到过BZ码的题目,用py的bz2模块就可以简单求解

import bz2
import urllib.parse as parse
info='BZh91AY%26SY%94%3A%E2I%00%00%21%19%80P%81%11%00%AFg%9E%A0+%00hE%3DM%B5%23%D0%D4%D1%E2%8D%06%A9%FA%26S%D4%D3%21%A1%EAi7h%9B%9A%2B%BF%60%22%C5WX%E1%ADL%80%E8V%3C%C6%A8%DBH%2632%18%A8x%01%08%21%8DS%0B%C8%AF%96KO%CA2%B0%F1%BD%1Du%A0%86%05%92s%B0%92%C4Bc%F1w%24S%85%09%09C%AE%24%90'
info=info.replace('+','%20')
info=parse.unquote_to_bytes(info)
info = bz2.decompress(info)
print(info)

is it the 26th already? call his father and inform him that "the flowers are on their way". he\'ll understand.

解码后又是一句新的提示,这句话提示的是之前莫扎特的那道题,显然需要用到RPC模块和evil那题一样,调用方法来呼叫莫扎特的父亲leopold

from xmlrpc.client import ServerProxy
server = ServerProxy("http://www.pythonchallenge.com/pc/phonebook.php")  
response = server.phone("Leopold")
print(response)

得到回复555-VIOLIN,更改url的时候提示正确路径

但是并没有进入下一题,标题提示what do you want?,bz2解码后提示要带上花,而本题一直围绕着cookie在做,所以尝试修改该网页的cookie,将名称改为info,值改为the flowers are on their way

人像下面多了一句话oh well, don't you dare to forget the balloons.最后的答案应该是balloons,进入下一题http://www.pythonchallenge.com/pc/return/balloons.html

第十八题

提示找不同,不要把问题想复杂,两张图就是亮度不同,所以直接把url改成brightness

源代码中注释变了,注释提示下载deltas.gz,下载以后是个文本文件,但是很明显被分成了左右两块,而且乍一看左右两边的十六进制数都一样,但是应该是有不同的,所以找到左右两块数据的相同和不同的地方,分别按顺序写进三个文件

本题需要用到py的difflib模块,difflib模块可以比较两组数据d1和d2的差异,“-”表示d1有但d2没有,“+”表示d1没有但d2有,“ ”表示d1和d2内容一致。根据每行以哪种符号开头,由此可以把数据分成三类,分别存入三个文件中

import gzip
import difflib
from PIL import Image
from io import BytesIO
data1_list, data2_list = [], []
with gzip.open("deltas.gz", "rb") as file:
    for data in file:
        data = data.decode("utf-8")
        data1, data2 = data[:53].rstrip(' ') + "\n", data[56:]
        if data1 != "\n":
            data1_list.append(data1)
        if data2 != "\n":
            data2_list.append(data2)

diff = difflib.Differ().compare(data1_list, data2_list)

space_bytes, plus_bytes, minus_bytes = b"", b"", b""
for data in diff:
    data_list = data[2:].strip('\n').split(' ')
    byte = bytes([int(i, 16) for i in data_list])
    if data[0] == '+':
        plus_bytes += byte
    elif data[0] == '-':
        minus_bytes += byte
    elif data[0] == ' ':
        space_bytes += byte

stream = BytesIO(space_bytes)
image_space = Image.open(stream)
image_space.save("space.png")

stream = BytesIO(plus_bytes)
image_space = Image.open(stream)
image_space.save("plus.png")

stream = BytesIO(minus_bytes)
image_space = Image.open(stream)
image_space.save("minus.png")

得到三张图片,可以看到下一题的链接http://www.pythonchallenge.com/pc/hex/bin.html

并且出现用户登陆,应该分别是butter  fly

第十九题

查看源码中有一大段邮件形式的注释,来自leopold.moz@pythonchallenge.com,附带了一大堆base64编码,使用py的base64模块来解码,并且根据提示将解码后的数据写入文件indian.wave

import base64
with open('base64.txt','r') as file:
    text = file.read().replace("\n", "")
stream = base64.b64decode(text.encode())
with open("indian.wav", "wb") as file:
    file.write(stream)

打开Indian.wave,只听到一堆噪音,中间有一个男的喊了一句sorry,然后就没了,尝试将sorry改成url

并不能进入下一关,仔细观察图片发现,海洋和大陆颜色是相反的,感觉应该也是一个提示,尝试反转文件数据,需要用到py的wave模块

import wave
with wave.open("indian.wav", "rb") as f1:
    with wave.open("reverse.wav", "wb") as f2:
        f2.setparams(f1.getparams())
        for _ in range(f1.getnframes()):
            f2.writeframes(f1.readframes(1)[::-1])

再打开反转后的音频文件,,,,有一个女人唱歌"you are the idiot,hhhhhh"……好吧,那这题答案应该是idiot了,更改url

有一个中转页面,回应了前面尝试修改sorry的页面,点击进入下一题http://www.pythonchallenge.com/pc/hex/idiot2.html

第二十题

图上写着‘private property beyond this fence‘,下面文字却说‘ but inspecting it carefully is allowed.’

查看源码没有什么注释,打开图片看看,发现网页头部Content-Range:bytes 0-30202/2123456789,发现图片采用了“断点续传”技术,并没有把全部数据传回来,所以就需要用到网络爬虫技术,修改网页头部Content-Range:bytes 0-xxx

该网页爬虫需要带用户名和密码,即butter   fly

刚开始是从头开始爬取的即Content-Range:bytes 0-0,但是爬到30237的时候提示了we can go on in this way for really long time.从头开始会耗时很久,并且爬到30347的时候就网页错误了

所以换方向从尾开始爬取即Content-Range:bytes 0-2123456789开始爬取,向前爬取

from urllib import request, error
url = "http://www.pythonchallenge.com/pc/hex/unreal.jpg"
user = "butter"
password = "fly"
password_mgr = request.HTTPPasswordMgrWithDefaultRealm()
password_mgr.add_password(None, url, user, password)
handler = request.HTTPBasicAuthHandler(password_mgr)
opener = request.build_opener(handler)

#start = -1
start = 2123456790
#start = 1152983632
for _ in range(100):
    #start += 1     # this is for start = -1
    start -= 1   # this is for start = 2123456790 and start = 1152983632
    print(f"{start}", end="\t")
    opener.addheaders = [("range", f"bytes={start}-"), ]
    try:
        response = opener.open(url)
    except error.HTTPError:
        print("HTTP Error 416")
    else:
        data = response.read()
        headers = dict(response.info())
        content_range = str(headers['Content-Range'])
        print(f"\033[31m{content_range}\t{data}\033[0m")
        start = int(content_range.split('-')[1].split('/')[0])     # this is for start = -1
        # start = int(content_range.split(' ')[1].split('-')[0])   # this is for start = 2123456790 and start = 1152983632
]) 

向前爬取的时候得到提示

esrever ni emankcin wen ruoy si drowssap eht

反过来就是''the password is your new nickname in reverse' 那就是将invader逆向变成redavni

并且提示去爬取2123456742,爬取可以看到一个PK开头的数据流,明显是一个压缩文件,就将该数据流写入文件

        
with open("invader.zip", "wb") as file:
    opener.addheaders = [("range", f"bytes=1152983631-"), ]
    response = opener.open(url)
    data = response.read()
    file.write(data)

解压压缩包需要密码,输入之前提示得到的密码,解压后得到两个文件

打开readme,就已经进入下一关了

第二十二题

用winhex查看package文件

观察“package.pack”中的数据,发现是以b"x\x9c"开头的,是zlib算法压缩的数据,使用zlib模块解码

 

重复运行几次,发现有以b"BZ"开头的,这是bz2压缩的数据,使用bz2模块解码

bz2运行几次后,发现有以b"\x80\x8d"开头的,看看第2条提示,发现字节流是以b"\x9cx"结尾的,反转整个字节流

最终得到一句话“look at your logs”

那就打印解压日志,但是不知道该如何打印,将三种解压方式分别设为三个字符,打印一下知道了三种频率,大概猜测应该是会打印出一个图形之类的东西,尝试若以bz2解压则打印“*”,若以zlib解压则打印空格,若反转操作则打印换行符,最终得到一幅像素画,答案是“copper”

import bz2
import zlib
with open("package.pack", "rb") as file:
    data = file.read()
print(data[::-1])
while data != b"sgol ruoy ta kool":
    if data.startswith(b"x\x9c"):
        data = zlib.decompress(data)
        print(' ', end='')
    elif data.startswith(b"BZ"):
        data = bz2.decompress(data)
        print('*', end='')
    elif data.endswith(b"\x9cx"):
        data = data[::-1]
        print()
print()

更改url进入下一题http://www.pythonchallenge.com/pc/hex/copper.html

第二十三题

查看网页源代码,下载white.gif

用ps打开发现有很多帧,但是每一帧都不是纯黑的,联想到题目图片是游戏操纵杆,并且每一帧的白点都是在围绕中心点(100,100)运动,并且每过几张白点就会回到中心点,就像操纵杆在玩游戏一样,每回到中心点就是一次新的操作,最后的结果显示通过操纵点的运动一共画出了5个字母的轮廓,就是当白点回归到中心的时候,就是画下一个字母的信号了。

import PIL.Image as Image
import PIL.ImageDraw as ImageDraw
import PIL.ImageSequence as ImageSequence
img = Image.open('white.gif')
new = Image.new('RGB',(200,200),'black')
newimg = ImageDraw.Draw(new)
x = 0
y = 0
for s in ImageSequence.Iterator(img):
    l,u,r,d = img.getbbox()
    dx = (l-100)
    dy = (u-100)
    x+=dx
    y+=dy
    if dx==dy==0:
        x+=30
        y+=30
    newimg.point((x,y))
new.save('out22.png')

最后得到bonus,更改url可以进入下一关http://www.pythonchallenge.com/pc/hex/bonus.html

第二十三题

查看网页源代码

第一段注释就是一个关于该闯关内容与本题没什么关系,第二段注释乍一看也没有什么提示,第三段的编码一看就想到之前也使用过凯撒密码,所以尝试用凯撒来列出所有位移情况,这里可以使用CTFCrackTools工具来解码,也可以自己写py脚本列出可能性

alphabets = "abcdefghijklmnopqrstuvwxyz"
text = "va gur snpr bs jung?"
for offset in range(26):
    new_aplhabets = alphabets[offset:] + alphabets[:offset]
    trans = str.maketrans(alphabets, new_aplhabets)
    new_text = text.translate(trans)
    print(new_text)

可以看到解码内容应该是 in the face of what?

再联想刚才的第二段注释,this is an undocument module.百度搜索原来py还有一个this模块,可以百度搜索到this模块的内容,也可以直接import this 得到内容

The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren’t special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you’re Dutch.
Now is better than never.
Although never is often better than right now.
If the implementation is hard to explain, it’s a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea – let’s do more of those!

可以查看到引出一个新单词 ambiguity,尝试更改url,得到下一题http://www.pythonchallenge.com/pc/hex/ambiguity.html

第二十四题

该题图片是一个粉色的迷宫,初步猜测可能是需要走迷宫,查看源代码

只有一个标题提示从上往下,那猜测应该是迷宫的入口在上方,需要从上方进入迷宫,然后走出来

观察到入口在右上方,出口在左下方,并且整个迷宫中有很多的红色像素点,想要画出迷宫的正确走法,肯定需要用到py的PIL图像处理

但是得到的路线看起来好像没有任何信息,也不像什么图像

但是路线上有很多的红色像素点,可以保存一下通道上的R值看一下,将路线上的R值保存下来发现数据流是以PK开头的,那就将数据写进压缩文件,得到一个压缩文件夹,解压后得到一张图片和另一个压缩包

import numpy as np
from PIL import Image
im0 = Image.open("C:/Users/Bumor/Desktop/maze.png")
rgba_array = np.asarray(im0, dtype=np.uint8).copy()
im0 = im0.convert(mode="1")
maze_array = np.asarray(im0, dtype=np.uint8).copy()
maze_array = 1 - maze_array

n, m = maze_array.shape
queue_list = [(0, m - 2)]
path_array = np.zeros((n, m, 2), dtype=np.int)
dx_tuple, dy_tuple = (0, 0, 1, -1), (1, -1, 0, 0)
while queue_list:
    x, y = queue_list.pop(0)
    maze_array[x, y] = 0
    if x == n - 1:
        break
    for dx, dy in zip(dx_tuple, dy_tuple):
        xx, yy = x + dx, y + dy
        if 0 <= xx < n and 0 <= yy < m and maze_array[xx, yy]:
            maze_array[xx, yy] = False
            path_array[xx, yy] = [x, y]
            queue_list.append((xx, yy))

im1 = Image.new(mode="1", size=(n, m), color=1)
r_list = []
x, y = n - 1, 1
while x != 0 or y != 0:
    im1.putpixel((x, y), 0)
    r_list.append(rgba_array[x, y, 0])
    x, y = path_array[x, y]
im1.save("path.png")

r_list = r_list[-2::-2]
r_bytes = bytes(r_list)
with open("red.rar", "wb") as file:
    file.write(r_bytes)


有一个打不开的压缩包,还可以看到一张lake的图片,猜测应该为下一题的入口http://www.pythonchallenge.com/pc/hex/lake.html

第二十五题

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值