003. re

关卡地址#

解决方案:#

思路:#

这一关同样不贴图了,直接看图片下提示:

One small letter, surrounded by EXACTLY three big bodyguards on each of its sides.

和上一关一样,需要从源代码中找到“一个两边完全被三个大写字母包围的小写字母”,这样的序列组成的字符串。

最后得到的是: linkedlist

访问 linkedlist.html 会提示你下一关地址是 linkedlist.php

代码:#

import helper
msg=helper.readFile("../../Data/003/msg.txt")

import re

# pattern=re.compile("[^A-Z][A-Z]{3}([a-z])[A-Z]{3}[^A-Z]")

# matches=pattern.findall(msg)

# print(''.join(matches))

print(''.join(re.findall("[^A-Z][A-Z]{3}([a-z])[A-Z]{3}[^A-Z]",msg)))
$msg=(Get-Content (Resolve-Path "../../Data/003/msg.txt").Path -Raw).Replace("`r`n","")

$pattern=[regex]"[^A-Z][A-Z]{3}([a-z])[A-Z]{3}[^A-Z]"

$outstr=""
$pattern.Matches($msg) | foreach {$outstr += $_.Groups[1].Value}

Write-Output $outstr
package main

import (
	"fmt"
	"regexp"
)

func (c *Challenge) Challenge003() {
	msg:=ReadFile("../../Data/003/msg.txt")

	pattern:=regexp.MustCompile("[^A-Z][A-Z]{3}([a-z])[A-Z]{3}[^A-Z]")

	// 返回一个二维数组
	matches:=pattern.FindAllStringSubmatch(msg,-1)

	outstr:=""
	for _,ch := range matches {
		outstr+=ch[1]
	}

	fmt.Println(outstr)
}

最终结果: linkedlist#

下一关地址#

004. follow the chain

关卡地址#

解决方案:#

思路:#

这一关鼠标移动到图片上指针会变成小手,点击会得到如下信息:

and the next nothing is 44827

同时,url后面多了参数?nothing=12345。回退回关卡地址,查看源代码得到如下提示:

urllib may help. DON’T TRY ALL NOTHINGS, since it will never end. 400 times is more than enough.

结合标题,需要借助urllib库发送400次请求,每次请求都会得到下一次请求的参数,替换参数继续请求,最终得到下一关地址。

PS: 在测试时,遇到这样的提示:Yes. Divide by two and keep going.,已在程序中做判断处理(之前并没有遇到这样的情况,看官方攻略也不像是网站最近更新了,看来是之前比较幸运😝)。

代码:#

url='http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing='
param='12345'

import urllib.request
import re

pattern=re.compile("the next nothing is (/d+)")

for i in range(400):
    # print("request %4d url: %s " %(i,url+param))
    resp=urllib.request.urlopen(url+param).read().decode('utf-8')
    try:
        param=pattern.search(resp).group(1)
    except:
        print("param %s, response: %s" %(param,resp))
        if resp == "Yes. Divide by two and keep going.":
            try:
                tmpParam=str(int(int(param)/2))
                param=tmpParam
                continue
            except:
                break
        break

print('completed')
$url="http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing="
$param="12345"

$pattern=[regex]"the next nothing is (\d+)"

for ($i=0; $i -lt 400; $i++) {
    $resp = (Invoke-WebRequest -Uri $url+$param | Select-Object -ExcludeProperty Content).Content
    $match = $pattern.Match($resp)
    if ($match.Success) {
        $param = $match.Groups[1].Value
    } else {
        [System.Console]::WriteLine($("param: {0}, resp: {1}" -f $param,$resp))
        if ($resp -eq "Yes. Divide by two and keep going.") {
            $param=$param/2
            continue
        }
        break
    }
}

[System.Console]::WriteLine("completed")
package main

import (
	"fmt"
	"net/http"
	"io/ioutil"
	"regexp"
	"strings"
	"strconv"
)

func (c *Challenge) Challenge004() {
	url:="http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing="
	param:="12345"

	pattern:=regexp.MustCompile("the next nothing is (/d+)")

	for i:=0; i<400; i++ {
		resp := httpGet(url+param)
		tmpParam:=pattern.FindStringSubmatch(resp)
		if len(tmpParam) != 2 {
			fmt.Printf("param: %s, response: %s\n",param, resp)
			if strings.Compare(resp,"Yes. Divide by two and keep going.") == 0 {
				intParam,err := strconv.Atoi(param)
				if err == nil {
					param = string(intParam/2)
					continue
				}
			}
			break
		} else {
			param=tmpParam[1]
		}
	}

	fmt.Println("completed")
}

func httpGet(url string) string {
	resp, err := http.Get(url)
	if err == nil {
		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		if err == nil {
			return string(body)
		}
	}
	return ""
}

最终结果: peak.html#

下一关地址#

007. smarty

关卡地址#

解决方案:#

思路:#

这一关源代码中没有任何提示信息,看来信息都在图片中了。

smarty

图片中间位置有一条灰度图像,灰度图取值范围与ASCII码范围一致,所以可以将灰度值转换为ASCII码。小灰度条的宽度都是7px(除了第一条是5px)。需要注意灰度图与图片右边界有21px空白。

行动起来吧。

经过灰度值转换得到如下信息:

smart guy, you made it. the next level is [105, 110, 116, 101, 103, 114, 105, 116, 121]

将列表中数值转换后就是下一关的地址了。

代码:#

import helper
path="../../Data/007"
helper.ensureDir(path)

import urllib.request
img="http://www.pythonchallenge.com/pc/def/oxygen.png"
(filename, headers)=urllib.request.urlretrieve(img, path+"/oxygen.png")

# python3图像处理库Pillow(friendly PIL fork)
# 文档地址:https://pillow.readthedocs.io/en/5.3.x/
from PIL import Image
im=Image.open(filename)
(w,h)=im.size
px=im.load()

outstr=[]
# 21px是灰度图右边空白的宽度
for i in range(0,w-21,7):
    (r,g,b,a)=px[i,h/2]
    # 灰度图r,g,b三个分量值相等
    outstr.append(chr(r))
im.close()

msg=''.join(outstr)
print(msg)

import re
pattern=re.compile(r'[\d]+')

nextlevel=''.join(map(chr,map(int,pattern.findall(msg))))
print(nextlevel)
$path="../../Data/007"

. .\helper.ps1
New-Dir -Dir $path
$path=$(Resolve-Path $path).Path

$url="http://www.pythonchallenge.com/pc/def/oxygen.png"
$filename=$path+"/oxygen.png"
Invoke-WebRequest -Uri $url -OutFile $filename

[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$img=[System.Drawing.Image]::FromFile($filename)

$msg=""
for ($i=0; $i -lt $img.Width-21; $i+=7) {
    $msg+=[char]$img.GetPixel($i,$img.Height/2).R
}
$img.Dispose()

Write-Output $msg

$outstr=""
$pattern=[regex]"\d+"
$pattern.Matches($msg) | ForEach-Object {$outstr+=[char][int]$_.Value}

Write-Output $outstr
package main

import (
	"fmt"
	"regexp"
	"strconv"
	_ "image/png"
)

func (c *Challenge) Challenge007() {
	path:="../../Data/007"
	EnsureDir(path)

	filename:=path+"/oxygen.png"
	channel:="http://www.pythonchallenge.com/pc/def/oxygen.png"
	Download(channel,filename)

	im:=OpenImage(filename)

	bounds := im.Bounds()

	msg := ""
	y:=(bounds.Max.Y-bounds.Min.Y)/2
	for x:=bounds.Min.X; x<bounds.Max.X-21; x+=7 {
		r,_,_,_ := im.At(x,y).RGBA()
		msg+=string(byte(r))
	}

	fmt.Println(msg)

	pattern:=regexp.MustCompile("/d+")
	matches:=pattern.FindAllString(msg, -1)

	outstr:=""
	for _,match := range matches {
		i,err:=strconv.Atoi(match)
		if err == nil {
			outstr+=string(byte(i))
		}
	}

	fmt.Println(outstr)
}

最终结果: integrity#

下一关地址#

017. eat?

关卡地址#

解决方案:#

思路:#

这一关图片中是曲奇饼干,左下角图片是不是有点熟悉?是第四关啦!

查看源代码并没有什么提示。

但是!根据cookie可以联想到什么?对!就是浏览器缓存。

通过浏览器开发者工具查看cookie后,可以得到如下提示:

you+should+have+followed+busynothing…

在第四关,我们请求的是:http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing=

这里需要将nothing替换为busynothing,并且收集cookieinfo的值。

之后得到BZh91AY开头的经过url编码的字符串,是不是又有点熟悉?不熟悉的请回顾第八关

使用python在解码时会有小问题:

OSError: Invalid data stream

在解码前将+替换为%20可以解决该问题。

解码后得到提示:

is it the 26th already? call his father and inform him that “the flowers are on their way”. he’ll understand.

这句话信息量有点大,26号暗示第十五关call his father则暗示第十三关,Mozart的父亲是Leopold(注意L大写)。

给Leopold打电话之后得到:

555-VIOLIN

访问violin.html得到如下提示:

no! i mean yes! but ../stuff/violin.php.

替换url之后访问,得到的是一张Leopold的照片,及:

it’s me. what do you want?

额。。。对,and inform him that “the flowers are on their way”

❤️ 如果这篇文章对你有帮助,欢迎赞助支持我继续维护 ❤️

☕ Support me ⚡ 爱发电赞助