本作品采用知識共享署名-非商業(yè)性使用-相同方式共享 3.0Unported許可協(xié)議進(jìn)行許可。允許非商業(yè)轉(zhuǎn)載,但應(yīng)注明作者及出處。
作者:xialulee
最初發(fā)布于:2012年03月04日,http://blog.sina.com.cn/xialulee
這一個(gè)關(guān)卡頁面的圖像顯示了很多cookie(一開始我還以為是一堆石頭),說明這一關(guān)與cookie有關(guān)。在圖像的左下角有一幅小圖,曾經(jīng)在linkedlist那一關(guān)出現(xiàn)過,說明這又是一個(gè)linkedlist演伸出來的關(guān)卡(之前還有一個(gè)讀zip注釋的)。在Firefox中用shift+ctrl+k打開JavaScript控制臺,輸入:
alert(document.cookie)
可以看見如下的說明:
cookie說:you should have followedbusynothing??磥磉@一關(guān),是要一邊遍歷linkedlist,一邊讀取cookie。之前是有一個(gè)關(guān)卡是一邊遍歷linkedlist,一邊讀取zip中的注釋,那時(shí)我用awk+python搞定的,awk遍歷linkedlist,python讀取注釋。
先來看看鏈表的節(jié)點(diǎn)是什么樣的。打開http://www.pythonchallenge.com/pc/def/linkedlist.php?busynothing=12345進(jìn)入第一個(gè)節(jié)點(diǎn):
頁面中給出了下一個(gè)節(jié)點(diǎn)的ID:
If you came here from level 4 - go back!
You should follow the obvious chain...
and the next busynothing is 44827
44827即是下一個(gè)節(jié)點(diǎn)的ID。看看這個(gè)頁面的cookie是什么,還是打開JavaScript控制臺,輸入alert(document.cookie),得到:info=B;...接著進(jìn)入下一個(gè)節(jié)點(diǎn)http://www.pythonchallenge.com/pc/def/linkedlist.php?busynothing=44827
得到下一個(gè)節(jié)點(diǎn)的ID:
and the next busynothing is 45439
再用JavaScript控制臺,執(zhí)行代碼,得到cookie為:info=Z;...
回想一下,遍歷了兩個(gè)節(jié)點(diǎn),得到兩個(gè)字符“BZ”,BZ看起來是不是很眼熟呢?原來之前有一個(gè)關(guān)卡(level8),就是獲取用戶名和密碼的那一個(gè),利用bzip2算法。那時(shí)的bzip2數(shù)據(jù),就是以BZ開頭的。所以,這一關(guān)應(yīng)該是遍歷所有的節(jié)點(diǎn),找出每個(gè)節(jié)點(diǎn)cookie中的字符,將它們拼接起來,用bzip2解壓縮。
之前在攻克遍歷linkedlist的關(guān)卡時(shí),都是用的awk,這一次也不例外。第一次的時(shí)候直接利用gawk的網(wǎng)絡(luò)編程能力來完成的。這一次不用這么麻煩的手法,來個(gè)比較輕松一點(diǎn)的,awk調(diào)用wget。wget可以輸出responseheader的信息,例如:
我們只需要過濾出含有“Set-Cookie”和“and the next busynothing is(d+)”的行,即可得到下一個(gè)節(jié)點(diǎn)的ID和當(dāng)前節(jié)點(diǎn)包含的數(shù)據(jù)。于是編寫了如下的gawk腳本(在msys中執(zhí)行,使用的wget來自GnuWin32):
#!/usr/bin/gawk-f
#2012.03.04PM07:53
#level17
#xialulee
BEGIN{
RS="rn";
command="wget-SO-http://huge:file@www.pythonchallenge.com/pc/def/linkedlist.php?busynothing=%d2>&1";
idx=12345;
bzstr[0]=0;
while(((cmd=sprintf(command,idx))|getline)>0){

if(match($0,/^[t]*Set-Cookie:info=([^;]+);/,result)){
bzstr[cnt++]=result[1];
printresult[1];
}
if(match($0,/andthenextbusynothingis([0-9]+)/,result)){
close(cmd);
idx=result[1];
printidx;
}
}
bunzip2="bunzip2";
for(i=0;i<cnt;++i){
ch=bzstr[i];
sub(/+/,"",ch);
if(sub(/^%/,"0x",ch)){
printf("%c",strtonum(ch))|bunzip2;
}else{
printf("%s",ch)|bunzip2;
}
}
close(bunzip2);
}
值得說明的有這樣幾點(diǎn)。
一、while循環(huán),會不斷地從wget輸出的數(shù)據(jù)中讀取行,進(jìn)行分析,但是一旦遇到了含有“and the nextbusynothing is(d+)”的行,就會提取其中的數(shù)值保存到變量idx中,作為下一個(gè)節(jié)點(diǎn)的ID,關(guān)閉當(dāng)前的wget,以新的ID開始一個(gè)新的wget進(jìn)程。如果遍歷到了尾部的節(jié)點(diǎn),則idx不會更新,while循環(huán)會一直讀取這個(gè)wget進(jìn)程stdin的所有輸出,然后退出。
二、遍歷所有節(jié)點(diǎn)得到的數(shù)據(jù)需要進(jìn)行相當(dāng)于Python中的urllib.unquote_plus操作,在上面的gawk腳本中由最后的for循環(huán)來完成。同時(shí),將unquote之后的數(shù)據(jù)通過管道傳遞給一個(gè)bunzip2進(jìn)程,讓其進(jìn)行解壓縮操作。
腳本最后的輸出結(jié)果為:
“is it the 26th already? call his father and inform him that "theflowers are on their way". he'llunderstand.”這句話看來和Mozart那一個(gè)level(level15)有關(guān)。同時(shí)又說要打電話,說明可能和圖像是電話的那一關(guān)(level13)有關(guān)。給Mozart的老爸打電話試試:
In [5]: s =Server('http://www.pythonchallenge.com/pc/phonebook.php')
In [6]: s.phone('Leopold')
Out[6]: '555-VIOLIN'
用violin構(gòu)造URL:http://www.pythonchallenge.com/pc/return/violin.html,得到說明:
no! i mean yes! but ../stuff/violin.php.
再進(jìn)入(..表示上一級目錄):http://www.pythonchallenge.com/pc/stuff/violin.php,出現(xiàn)一張大頭照,頁面的標(biāo)題為:it'sme. what do you want?
對于這種猜謎型的實(shí)在是有點(diǎn)搞不懂,在參考了http://unixwars.com/2007/09/23/python-challenge-level-17-eat/之后,才知道接下來的做法,在Vimperator中輸入:
:js << EOF
var xhr = new XMLHttpRequest();
xhr.open("GET","http://www.pythonchallenge.com/pc/stuff/violin.php");
xhr.setRequestHeader("Cookie","info=the+flowers+are+on+their+way");
xhr.onreadystatechange = function(aEvt) {
if (xhr.readyState==4&& xhr.status==200) {
alert(xhr.responseText);
}
}
xhr.send(null);
EOF
彈出:
其中的ballons,就是通關(guān)密語。終于過了這一關(guān)!
愛華網(wǎng)



