꿀벌로 추정되는 사진을 준다. 

 

 

 

 

"바로 밑에는 사라진 링크는 어디 갔을까?"라는 문장도 있다.  

 

문제 풀이에 도움을 얻기 위해서 page source를 열어보니 html 주석으로 이상한 문장들이 적혀 있다. un, pw 값으로 보인다. 

아무래도 username을 줄여서 un, password를 줄여서 pw를 의미하는 것 같다. 

 

<!--
un: 'BZh91AY&SYA\xaf\x82\r\x00\x00\x01\x01\x80\x02\xc0\x02\x00 \x00!\x9ah3M\x07<]\xc9\x14\xe1BA\x06\xbe\x084'
pw: 'BZh91AY&SY\x94$|\x0e\x00\x00\x00\x81\x00\x03$ \x00!\x9ah3M\x13<]\xc9\x14\xe1BBP\x91\xf08'
-->

 

꿀벌 사진을 눌러보면 다음레벨의 url을 알 수 있다. 문제는 사용자 이름과 비밀번호를 입력해야 한다는 것이다. 

 

http://www.pythonchallenge.com/pc/def/good.html

 

 

아까 전에 html 주석에 사용자 이름과 비밀번호를 알아내기 위해서 준 힌트인 것 같다.  HTML 주석을 자세히 살펴보면 un과 pw의 공통점이 있다. 바로 앞부분이 BZh91AY로 시작한다는 것이다. 

 

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

 

*nix 경험이 많다면 BZh91을 보자마자 Bzip2 파일의 signature라는 것을 알 수 있다. 우리가 사용하는 대부분의 파일들 (ZIP, JPEG, Bzip2...)은 파일 고유의 signature를 사용하고 있다. 파일 signature를 사용하면 파일의 종류를 파악하기 용이하다. 

 

Bzip2는 이름에서 알 수 있다시피 compression을 수행한다. 파일이 BZh91으로 시작한다면 bzip2으로 압축이 되어있으므로 압축을 풀어야 한다. Python에서는 bz2 module로 Bzip2 compression, decompression을 처리할 수 있다.

bz2 역시 Python의 built-in module이므로 pip install 없이 import bz2로 바로 사용할 수 없다. 

bz2.decompress 함수로 Bzip2 파일의 압축을 풀 수 있다. bz2.decompress는 bytes를 argument로 받으니 un과 pw 앞에 b를 붙여서 byte-string으로 만든 후에 사용하자. 

 

import bz2

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'

print(bz2.decompress(un),bz2.decompress(pw))

 

코드를 실행하니 un은 huge, pw는 file이라고 한다. 

 

b'huge' b'file'

 

꿀벌 사진을 클릭하여 un, pw 값을 입력하면 다음 레벨로 넘어간다.  참고로 지금처럼 HTTP auth(username, pw 있음)가 켜져 있는 웹사이트의 경우 un:pw@를 www 앞에 붙이면 username, password 값을 입력하지 않고 접속할 수 있다.

 

http://huge:file@www.pythonchallenge.com/pc/return/good.html

 

이 문제는 bzip2 파일을 사용해 본 적이 있다면 어렵지 않다. 그래서 코드도 매우 짧다. The Python Challenge는 Python은 물론이고 Python 이외의 외적인 CS 지식도 참 다채롭게 물어보는 것 같다. 

'Python > The Python Challenge' 카테고리의 다른 글

Level 6  (0) 2024.11.27
Level 0  (0) 2024.11.22

지퍼가 달린 옷 사진이 하나 주어진다. 

 

 

HTML 파일 이름은 channel이고 title은 now there are pairs이다. 아직까지는 도움이 될 만한 힌트가 없어서 page source를 살펴봤다. 

 

HTML 주석에 zip이라고 적혀 있다. 

 

<!-- <-- zip -->

 

지퍼가 달린 옷 사진 밑에는 PayPal 링크가 하나 있는데 이건 문제풀이와는 상관이 없다고 한다. The Python Challenge를 만든 사람이 기부를 해주면 매우 고맙겠다는 멘트를 남기고 싶어서 적은 것 같다. 

 

<!-- The following has nothing to do with the riddle itself. I just
thought it would be the right point to offer you to donate to the
Python Challenge project. Any amount will be greatly appreciated.

-thesamet
-->

 

위에서 zip이라는 힌트를 줘서 url 을 zip으로 바꿔 봤다. 

http://www.pythonchallenge.com/pc/def/channel.zip

 

URL을 바꿨더니 zip 파일을 받을 수 있었다. 

 

file channel.zip 
channel.zip: Zip archive data, at least v2.0 to extract, compression method=deflate

 

zip 파일의 압축을 푸니 엄청난 양의 숫자.txt 파일들이 나왔다. readme.txt가 있어서 읽어보니 90052부터 시작하라는 힌트와 답은 zip 파일 안에 있다는 힌트를 주었다. 

 

cat readme.txt 
welcome to my zipped list.

hint1: start from 90052
hint2: answer is inside the zip

 

문제와 연관된 90052가 90052.txt밖에 없어서 90052.txt 파일을 읽어보니 next nothing 값을 알려준다. Level4에서 풀었던 문제와 비슷한 것 같다.

 

cat 90052.txt 
Next nothing is 94191

 

cat 94191.txt 
Next nothing is 85503

 

더 이상 손으로 모든 txt 파일들을 읽는 것은 어렵다고 생각이 들어서 Python 코드를 작성했다. 

 

number=90052
while True:
    with open(f'{number}.txt','r') as f:
        content=f.read()
    print(content)
    number=content.split()[-1]
    print(number)
    if 'Next nothing is ' not in content:
        break

 

 

코드를 실행하고 나니 맨 끝에 주석을 모으라고 한다. 주석은 zip 파일에 주석을 모으라는 뜻이 아닌가 싶다.

 

Collect the comments.
comments.

 

Python은 zip 파일을 다루는 zipfile module이 있다. zipfile은 built-in module이기 때문에 특별한 설치 없이 import zipfile로 사용할 수 있다.

 

zipfile.ZipFile Object로 zip 파일을 열 수 있다. ZipFile.getinfo 함수는 zip archive member(zip으로 압축 된 파일)에 대한 정보를 알려준다. ZipFile.comment는 zip 파일의 comment를 bytes로 보여준다. 65535 bytes 보다 긴 comment들은 잘린다고 한다. 

참고로 Python에서 with open 으로 파일을 열면 자동으로 close 해주기 때문에 open 함수로 파일을 여는 것보다 with open으로 코드를 작성하는 게 더 Pythonic 하다고 한다. 

 

import zipfile 

number=90052
comments=[]
while True:
    with open(f'{number}.txt','r') as f:
        content=f.read()
    print(content)
    number=content.split()[-1]
    print(number)
    if number=='comments.':
        break
    with zipfile.ZipFile('channel.zip', 'r') as zipf:
        print(zipf.getinfo(f'{number}.txt').comment.decode())
        comments.append(zipf.getinfo(f'{number}.txt').comment.decode())
print(*comments)

 

 

https://stackoverflow.com/questions/31334061/file-read-using-open-vs-with-open

 

File read using "open()" vs "with open()"

I know there are plenty of articles and questions answered regarding reading files in python. But still I'm wondering what made python to have multiple ways to do the same task. Simply what I want to

stackoverflow.com

 

https://www.reddit.com/r/learnpython/comments/nfszml/with_open_vs_open_in_python/

 

From the learnpython community on Reddit

Explore this post and more from the learnpython community

www.reddit.com

 

 

 

각 txt 파일에서 '*'이 comment로 한개씩 나왔는데 comment를 하나씩 모으다 보니 HOCKEY라고 써져 있는 ascii art가 완성되었다.  

 

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 * *                                                                                                                         * * 
 * *       O O         O O         X X             Y Y Y Y         G G         G G     E E E E E E   N N             N N     * * 
 * *       O O         O O     X X X X X X       Y Y Y Y Y Y       G G       G G       E E E E E E     N N         N N       * * 
 * *       O O         O O   X X X     X X X   Y Y Y       Y Y     G G   G G           E E               N N     N N         * * 
 * *       O O O O O O O O   X X         X X   Y Y                 G G G               E E E E E           N N N N           * * 
 * *       O O O O O O O O   X X         X X   Y Y                 G G G               E E E E E             N N             * * 
 * *       O O         O O   X X X     X X X   Y Y Y       Y Y     G G   G G           E E                   N N             * * 
 * *       O O         O O     X X X X X X       Y Y Y Y Y Y       G G       G G       E E E E E E           N N             * * 
 * *       O O         O O         X X             Y Y Y Y         G G         G G     E E E E E E           N N             * * 
 * *                                                                                                                         * * 
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

 

URL을 hockey로 바꿨더니 답은 나오지 않았다. 그러나 공기중에 있고 글자를 살펴보라고 한다.

 

http://www.pythonchallenge.com/pc/def/hockey.html

 

it's in the air. look at the letters.

 

자세히 보면 HOCKEY의 각 글자가 글자로 이루어진 것을 볼 수 있다. 불필요한 '*'를 제거하고 살펴보니 O, X, Y, G, E, N으로 이루어져 있다.

 

In [1]: ascii='''* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
   ...:  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
   ...:  * *                                                                                                                         * * 
   ...:  * *       O O         O O         X X             Y Y Y Y         G G         G G     E E E E E E   N N             N N     * * 
   ...:  * *       O O         O O     X X X X X X       Y Y Y Y Y Y       G G       G G       E E E E E E     N N         N N       * * 
   ...:  * *       O O         O O   X X X     X X X   Y Y Y       Y Y     G G   G G           E E               N N     N N         * * 
   ...:  * *       O O O O O O O O   X X         X X   Y Y                 G G G               E E E E E           N N N N           * * 
   ...:  * *       O O O O O O O O   X X         X X   Y Y                 G G G               E E E E E             N N             * * 
   ...:  * *       O O         O O   X X X     X X X   Y Y Y       Y Y     G G   G G           E E                   N N             * * 
   ...:  * *       O O         O O     X X X X X X       Y Y Y Y Y Y       G G       G G       E E E E E E           N N             * * 
   ...:  * *       O O         O O         X X             Y Y Y Y         G G         G G     E E E E E E           N N             * * 
   ...:  * *                                                                                                                         * * 
   ...:  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
   ...:    * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * '''

In [2]: print(ascii.replace('*',''))
                                                               
                                                                 
                                                                                                                             
         O O         O O         X X             Y Y Y Y         G G         G G     E E E E E E   N N             N N       
         O O         O O     X X X X X X       Y Y Y Y Y Y       G G       G G       E E E E E E     N N         N N         
         O O         O O   X X X     X X X   Y Y Y       Y Y     G G   G G           E E               N N     N N           
         O O O O O O O O   X X         X X   Y Y                 G G G               E E E E E           N N N N             
         O O O O O O O O   X X         X X   Y Y                 G G G               E E E E E             N N               
         O O         O O   X X X     X X X   Y Y Y       Y Y     G G   G G           E E                   N N               
         O O         O O     X X X X X X       Y Y Y Y Y Y       G G       G G       E E E E E E           N N               
         O O         O O         X X             Y Y Y Y         G G         G G     E E E E E E           N N

 

OXYGEN은  산소, 그래서 공기 중에 있다고 한 거였다.  URL을 oxygen으로 바꿔보면 다음 레벨로 넘어간다. 

 

http://www.pythonchallenge.com/pc/def/oxygen.html

 

smarty

 

www.pythonchallenge.com

 

이 문제는 이전 레벨들에 비해서 상대적으로 Python 이외의 외적인 지식을 많이 물어보지 않아서 그래도 조금 풀기 수월하지 않았나 싶다. 이번 기회를 통해서 zipfile module을 익히고 잘 사용해 보자. 

 

'Python > The Python Challenge' 카테고리의 다른 글

Level 8  (0) 2024.11.28
Level 0  (0) 2024.11.22

옛날 컴퓨터에 2의 38 제곱이 적혀 있다. 컴퓨터 밑에 URL 주소를 바꿔보라는 힌트를 줬다. 

 

 

Python에서는 다양한 방법으로 거듭제곱을 계산할 수 있다. C, C++와 달리 큰 수도 쉽게 계산할 수 있으니 지수가 커져도 걱정하지 않아도 된다.

 

ipython
Python 3.13.0 (v3.13.0:60403a5409f, Oct  7 2024, 00:37:40) [Clang 15.0.0 (clang-1500.3.9.4)]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.29.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: 2**38
Out[1]: 274877906944

In [2]: 2<<37
Out[2]: 274877906944

In [3]: pow(2,38)
Out[3]: 274877906944

 

URL 주소는 다음과 같다. 0을 274877906944로 바꾸면 다음 레벨로 넘어가지 않을까 싶다. 

http://www.pythonchallenge.com/pc/def/0.html

 

http://www.pythonchallenge.com/pc/def/274877906944.html

 

다음과 같이 바꾸니 다음 레벨로 넘어간다.

 

http://www.pythonchallenge.com/pc/def/map.html

 

 

What about making trans?

everybody thinks twice before solving this. 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.

www.pythonchallenge.com

 

'Python > The Python Challenge' 카테고리의 다른 글

Level 8  (0) 2024.11.28
Level 6  (0) 2024.11.27

+ Recent posts