Python Challenge 5의 url은 다음과 같다.

Python challenge 5 : http://www.pythonchallenge.com/pc/def/peak.html

 

peak hell

 

www.pythonchallenge.com


구성

무슨 사진이 떡하니 있다. 이번엔 특별한 상호작용도 없는 거 같다. 사진을 다운로드하여보면 사진 이름이 peakhell.jpg 이라는 점이 특이한 상황인 거 같다. 번역은 다음과 같다.

 

발음해봐

 

ㅋㅋㅋㅋ발음했다 포스팅 재목에


해결 아이디어

peakhell을 발음하면 피-켈이다. pickle이라는 모듈을 모듈 소개시간에 소개한 적이 있는데, 모르는 사람은 읽고 오기를 추천한다.

2021.04.11 - [분류 전체보기] - [Python] - 모듈탐구 pickle - 자료구조의 저장과 불러오기

 

[Python] - 모듈탐구 pickle - 자료구조의 저장과 불러오기

컴퓨터 세계에서 자주 사용되는 json이라는 표준이다. json은 Python을 자주 사용하는 사람이라면 아는 dictionary이라는 자료구조와 유사하게 생겼는데, 광범위하게 데이터 오브젝트를 인간이 읽을

tutoreducto.tistory.com

pickle은 파이선전용으로 자료를 직렬화 하기 위해 만들어진 모듈이다. 소스파일에 처음 보는 html 태그가 있다. 바로 <peakhell> 이라는 태그인데, src프로퍼티에 banner.p가 있다. 아마 이 banner.p에 우리 문제의 해결 key가 들어 있을 듯하다 다운로드하여 코딩 시간이다.

import pickle

if __name__=="__main__" :
  with open("banner.p","rb") as f :
    ans = pickle.load(f)

  print(ans)

출력 결과는 다음과 같다.

[[(' ', 95)], [(' ', 14), ('#', 5), (' ', 70), ('#', 5), (' ', 1)], 
[(' ', 15), ('#', 4), (' ', 71), ('#', 4), (' ', 1)], [(' ', 15), 
('#', 4), (' ', 71), ('#', 4), (' ', 1)], [(' ', 15), ('#', 4), 
(' ', 71), ('#', 4), (' ', 1)], [(' ', 15), ('#', 4), (' ', 71), 
('#', 4), (' ', 1)], [(' ', 15), ('#', 4), (' ', 71), ('#', 4), 
(' ', 1)], [(' ', 15), ('#', 4), (' ', 71), ('#', 4), (' ', 1)],
[(' ', 15), ('#', 4), (' ', 71), ('#', 4), (' ', 1)], [(' ', 6), 
('#', 3), (' ', 6), ('#', 4), (' ', 3), ('#', 3), (' ', 9), ('#', 3), 
(' ', 7), ('#', 5), (' ', 3), ('#', 3), (' ', 4), ('#', 5), (' ', 3), 
('#', 3), (' ', 10), ('#', 3), (' ', 7), ('#', 4), (' ', 1)], [(' ', 3), 
('#', 3), (' ', 3), ('#', 2), (' ', 4), ('#', 4), (' ', 1), ('#', 7),
(' ', 5), ('#', 2), (' ', 2), ('#', 3), (' ', 6), ('#', 4), (' ', 1),
('#', 7), (' ', 3), ('#', 4), (' ', 1), ('#', 7), (' ', 5), ('#', 3), 
(' ', 2), ('#', 3), (' ', 5), ('#', 4), (' ', 1)], [(' ', 2), ('#', 3), 
(' ', 5), ('#', 3), (' ', 2), ('#', 5), (' ', 4), ('#', 4), (' ', 3),
('#', 3), (' ', 3), ('#', 4), (' ', 4), ('#', 5), (' ', 4), ('#', 4),
(' ', 2), ('#', 5), (' ', 4), ('#', 4), (' ', 3), ('#', 3), (' ', 5),
('#', 3), (' ', 3), ('#', 4), (' ', 1)], [(' ', 1), ('#', 3), (' ', 11),
('#', 4), (' ', 5), ('#', 4), (' ', 3), ('#', 3), (' ', 4), ('#', 3), 
(' ', 4), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 4), (' ', 5),
('#', 4), (' ', 2), ('#', 3), (' ', 6), ('#', 4), (' ', 2), ('#', 4),
(' ', 1)], [(' ', 1), ('#', 3), (' ', 11), ('#', 4), (' ', 5), ('#', 4),
(' ', 10), ('#', 3), (' ', 4), ('#', 4), (' ', 5), ('#', 4), (' ', 2), 
('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 3), (' ', 7), ('#', 3), 
(' ', 2), ('#', 4), (' ', 1)], [('#', 4), (' ', 11), ('#', 4), (' ', 5),
('#', 4), (' ', 5), ('#', 2), (' ', 3), ('#', 3), (' ', 4), ('#', 4), 
(' ', 5), ('#', 4), (' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 1), 
('#', 4), (' ', 7), ('#', 3), (' ', 2), ('#', 4), (' ', 1)], [('#', 4),
(' ', 11), ('#', 4), (' ', 5), ('#', 4), (' ', 3), ('#', 10), (' ', 4),
('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 4), (' ', 5), ('#', 4), 
(' ', 1), ('#', 14), (' ', 2), ('#', 4), (' ', 1)], [('#', 4), (' ', 11),
('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 3), (' ', 4), ('#', 4),
(' ', 4), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 4), (' ', 5), 
('#', 4), (' ', 1), ('#', 4), (' ', 12), ('#', 4), (' ', 1)], [('#', 4), 
(' ', 11), ('#', 4), (' ', 5), ('#', 4), (' ', 1), ('#', 4), (' ', 5),
('#', 3), (' ', 4), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 4),
(' ', 5), ('#', 4), (' ', 1), ('#', 4), (' ', 12), ('#', 4), (' ', 1)],
[(' ', 1), ('#', 3), (' ', 11), ('#', 4), (' ', 5), ('#', 4), (' ', 1), 
('#', 4), (' ', 5), ('#', 3), (' ', 4), ('#', 4), (' ', 5), ('#', 4), 
(' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 3), (' ', 12), 
('#', 4), (' ', 1)], [(' ', 2), ('#', 3), (' ', 6), ('#', 2), (' ', 2), 
('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 3), (' ', 4), ('#', 4),
(' ', 4), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 4), (' ', 5),
('#', 4), (' ', 3), ('#', 3), (' ', 6), ('#', 2), (' ', 3), ('#', 4), 
(' ', 1)], [(' ', 3), ('#', 3), (' ', 4), ('#', 2), (' ', 3), ('#', 4),
(' ', 5), ('#', 4), (' ', 3), ('#', 11), (' ', 3), ('#', 4), (' ', 5), 
('#', 4), (' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 4), ('#', 3),
(' ', 4), ('#', 2), (' ', 4), ('#', 4), (' ', 1)], [(' ', 6), ('#', 3), 
(' ', 5), ('#', 6), (' ', 4), ('#', 5), (' ', 4), ('#', 2), (' ', 4),
('#', 4), (' ', 1), ('#', 6), (' ', 4), ('#', 11), (' ', 4), ('#', 5),
(' ', 6), ('#', 3), (' ', 6), ('#', 6)], [(' ', 95)]]

SHIT! 진정하자. 파일 이름이 banner임을 기억하자. " "와 "#"로 이루어진 것을 보면 이는 ASCII art일 가능성이 농후하다. 그도 그럴 것이 2차원 배열로 이루어진 이 자료구조 원소들의 1번째 인덱스의 합은 전부 95로 동일하다. 같은 길이의 행이라는 것을 암시하는 것이다. 코딩 타임이다.

import pickle

if __name__=="__main__" :
  with open("banner.p","rb") as f :
    ans = pickle.load(f)

  for i in range(len(ans)) :
    for j in range(len(ans[i])) :
      print(ans[i][j][0]*ans[i][j][1],end="")
    print("")

출력 결과는 다음과 같다. 잘려서 사진으로 올린다.

찾았다.

Answer Url : http://www.pythonchallenge.com/pc/def/channel.html

Python Challenge 4의 url은 다음과 같다.

Python challenge 4 : http://www.pythonchallenge.com/pc/def/linkedlist.php

 

follow the chain

 

www.pythonchallenge.com


구성

으흠; 그림이 어떤 걸 의미하는지는 모르겠다. 관습적으로 소스 페이지를 확인해보자

그림에 a태그 href로 nothing=12345가 걸려있다. 눌러보자

오호 어떤 건지 알겠다. 재귀적으로 탐색하며 다음 nothing을 전달하다 보면 해결각이 나오나 보다 코딩 타임이다.


해결 아이디어

주석에는 urllib를 쓰라고 되어있는데 외부 모듈인 requests에 익숙해져 있는 필자는 이걸 쓰겠다. 문자열 탐색은 본문 페이지의 있는 nothing is가 고정임을 이용해서 저번 시간 사용한 정규표현식 re를 써본다.

import re
from requests import *

if __name__=="__main__" :
  url = "http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing="
  nothing = "12345"

  while(True) :
    new_url = url+nothing
    res = get(new_url)
    print(res.text)
    nothing = re.findall("nothing is (\d+)",res.text, re.DOTALL)[-1]

그릏다. re.findall 모듈은 정규표현식이 ()로 둘러싸인 곳만 list화 한다. 하다 보면 오류가 난다

...
and the next nothing is 54249
and the next nothing is 29247
and the next nothing is 13115
and the next nothing is 23053
and the next nothing is 3875
and the next nothing is 16044
Yes. Divide by two and keep going.
Traceback (most recent call last):
  File "\python_challenge\4.py", line 13, in <module>
    nothing = re.findall("nothing is (\d+)",res.text, re.DOTALL)[-1]
IndexError: list index out of range

반으로 나누란다. 8022를 집어넣고 계속해보자 중간에 무슨 잘못된 안내가 있다고 하는데, 우리가 짠 코드로는 그냥 넘어갈 수 있으니, 그냥 넘어가고 계속하다 보면 다음과 같은 결과가 나온다.

...
and the next nothing is 96791
and the next nothing is 75635
and the next nothing is 52899
and the next nothing is 66831
peak.html
Traceback (most recent call last):
  File "\python_challenge\4.py", line 13, in <module>
    nothing = re.findall("nothing is (\d+)",res.text, re.DOTALL)[-1]
IndexError: list index out of range

찾았다.

Answer Url : http://www.pythonchallenge.com/pc/def/peak.html

Python Challenge 3의 url은 다음과 같다.

Python challenge 3 : http://www.pythonchallenge.com/pc/def/equality.html

 

re

 

www.pythonchallenge.com


구성

페이지 번역은 다음과 같다.

 

정확하게 세 개의 큰 보디가드를 양옆에 둔 하나의 작은 문자를 찾으시오

 

또다시 페이지 주석을 보자

또다시 많은 문자열들이 보인다. 설루션대로 문제의 풀이를 위해서는 정규표현식의 힘을 빌려야 될 거 같다. 

정규표현식이 무엇인지 모르는 사람은 아래를, Python에서 정규표현식 사용법은 그 아래를 참고하고 오도록 하자

2021.04.17 - [정보보안-이론] - 정규표현식에 대하여

 

정규표현식에 대하여

정규표현식은 여러 목적으로 사용된다. 정규표현식 자체는 어렵지 않다. 정규식(正規式)은 특정한 규칙을 가진 문자열의 집합을 표현하는 데 사용하는 형식 언어이다. < 정규표현식의 정의 : 출

tutoreducto.tistory.com

2021.04.19 - [개발/Python] - [Python] - 모듈탐구 re - [^정규표현식$?]

 

[Python] - 모듈탐구 re - [^정규표현식$?]

정규표현식을 모르고 있는 사람은 아래 포스팅을 읽고 오자 2021.04.17 - [정보보안-이론] - 정규표현식에 대하여 정규표현식에 대하여 정규표현식은 여러 목적으로 사용된다. 정규표현식 자체는

tutoreducto.tistory.com


해결 아이디어

이전문제와 동일하게 문자열은 3.dat에 저장하였으나, 개행 변환은 하지 않았다. 이번에는 개행 문자의 유무가 문제풀이에 영향이 갈 거 같았다. re모델을 통해 작성한 탐색용 정규표현식은 [A-Z]{3}[a-z]{1}[A-Z]{3}이다.

import re

if __name__=="__main__" :
  with open("3.dat","r") as f:
    data = f.read()

  answer = re.findall("[a-z][A-Z]{3}[a-z][A-Z]{3}[a-z]",data)

  for i in range(len(answer)) :
    print(answer[i][4],end="")

 

출력은 다음과 같았다.

>>> 
linkedlist

찾았다.

Answer Url : http://www.pythonchallenge.com/pc/def/linkedlist.html? 

 

힝 속았지! 페이지는 php에 있다고 한다 다음부터는 정적인 스크립트는 안쓸생각인가 보다

Answer Url : http://www.pythonchallenge.com/pc/def/linkedlist.php

 

Python Challenge 2의 url은 다음과 같다.

Python challenge 2 : http://www.pythonchallenge.com/pc/def/ocr.html

 

ocr

 

www.pythonchallenge.com


구성

페이지 번역은 다음과 같다. 힌트는 쓰지 않겠다.

 

"문자를 인식하시오. 책 안에 있을 수도 있으나, 혹시 Page Source에 있을 수도 있습니다."

 

말장난이다. Page가 장임을 이용해서 BOOK과 소속 관계를 2ke2ke하는거 같은데, Page Source안에는 다음과 같은 주석을 찾을 수 있다.

엄청많은 특수문자들이 있고, 위에 한 줄 주석으로 다음의 값 중 희귀한 값을 뽑아 보라고 한다. 코딩 타임이다.


해결 아이디어

문자열이 너무 길어 2.dat에 저장하였고, 개행 문자는 다 ""로 치환했다. 문자열이 약 10만 개 정도 되는데, 이는 순차 탐색이나, 간단한 명령어로도 반복 효율이 1초 이하로 나오기 때문에, set으로 변환을 해서 distinct 한 값으로 변환하고 이를 count 해서 가장 적게 나온 값을 출력했다.

if __name__=="__main__" :

    with open("2.dat","r") as f:
        raw_string = f.read().replace("\n","")

    raw_set = set(list(raw_string))
    raw_dict = {x:raw_string.count(x) for x in raw_set}

    new_dict = sorted(raw_dict.items(),key=(lambda x:x[1]))
    
    for i in new_dict :
        print(i[0],end="")

출력은 아래와 같았다.

>>> 
eutqilya^*&{$+!%}[_#](@)

응? 이게 무슨 글자지? 문제는 여기서 발생한다. set은 순서 없는 자료구조이다 보니, 아마 글자에서 나온 순서대로 보여준 게 아닐 거다. 코드를 조금 추가해서 eutqilya가 코드에 나온 순서로 정렬되게 바꾸자

if __name__=="__main__" :

    with open("2.dat","r") as f:
        raw_string = f.read().replace("\n","")

    raw_set = set(list(raw_string))
    raw_dict = {x:raw_string.count(x) for x in raw_set}

    new_dict = sorted(raw_dict.items(),key=(lambda x:x[1]))
    
    for i in new_dict :
        print(i[0],end="")

    target_string = "eutqilya"
    answer_list = list()
    for i in range(len(target_string)) :
        answer_list.append([target_string[i],raw_string.find(target_string[i])])

    answer_list = sorted(answer_list,key=(lambda x:x[1]))
    
    print("")
    
    for item in answer_list :
        print(item[0],end="")
    

출력은 다음과 같다.

>>> 
utylaqie^*&${+!%}[_#](@)
equality

찾았다 요놈

 

Answer Url : http://www.pythonchallenge.com/pc/def/equality.html


여담으로 이문제를 쉽게 해결하는 방법은 모듈인 collections을 활용하는 방법이다. 필자가 위에서 뻘짓을 한걸 미리 구현해 둔 모듈이다. collections을 활용한 풀이는 다음과 같다.

import collections


if __name__ == "__main__" :
    with open("2.dat","r") as f:
        res = f.read().replace("\n","")
        
    ans = collections.Counter(res)
    print(ans.most_common())

출력은 아래와 같다.

>>> 
[(')', 6186), ('@', 6157), ('(', 6154), (']', 6152), ('#', 6115), ('_', 6112), 
('[', 6108), ('}', 6105), ('%', 6104), ('!', 6079), ('+', 6066), ('$', 6046), 
('{', 6046), ('&', 6043), ('*', 6034), ('^', 6030), 
('e', 1), ('q', 1), ('u', 1), ('a', 1), ('l', 1), ('i', 1), ('t', 1), ('y', 1)]

 

Python Challenge 1의 url은 다음과 같다.

Python challenge 1 : 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


구성

화면의 글자는 다음과 같다.

 

모두들 이걸 풀기 전에 한 번 더 생각하세요

 

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.

 

일반적인 TIP

* 힌트를 사용하세요, 보통 유용하답니다

* 당신에게 주어진 데이터를 조사하세요

* 스포일러를 조심하세요

 

으흠;; 핑크색 글자의 K를 M으로 O를 Q로, E를 G로 바꾸면 될라나? 다음과 같은 코드를 작성해 보았다.

def change(letters,src,dst) :
    return letters.replace(src,dst)

if __name__=="__main__" :
    string = "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."

    string = change(string,"k","m")
    string = change(string,"o","q")
    string = change(string,"e","g")

    print(string)
    
출력결과 : 
g fmnc wms bgblr rpylqjyrc gr zw fylb. rfyrq ufyr ammnsrcpq ypc dmp. bmglg gr gl 
zw fylb gq glcddgagclr ylb rfyr q ufw rfgq rcvr gq qm jmlg. sqglg qrpglg.myicrpylq() 
gq pcammmclbcb. lmu ynnjw ml rfc spj.

어? 그래도 틀리다. 조금더 세밀하게 규칙을 보면 패턴을 찾을 수 있다.

맞다 눈치챈사람들도 있겠지만 이는 ROT2의 Shifting 암호이다.

문제는 우리에게 일부 항목만을 보여 주었을 뿐이다. 프로그램을 조금 수정하자 

if __name__=="__main__" :
    string = "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."
    new_string = ""
    
    for i in range(len(string)) :
        ### ord('a')가 97이고, ord('z')가 122이다.
        if(ord(string[i]) >= 97 and ord(string[i]) <= 122) :
            new_string += chr(97+(ord(string[i])-95)%26)
        else :
            new_string += string[i]

    print(new_string)

두 칸씩 밀릴 수 있게 소문자 ascii 값을 2씩 더해주면서 새로운 new_string을 생성했다. 출력은 다음과 같다.

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()라는 함수가 있다고 한다. 뭐 어떤가 이런 방법 저런 방법 있는 거지 

그런데 이제 어떻게 다음문제를 넘어갈 수 있을까?? 이번 문제의 소스는 map.html이다 map이라는 문자열을 ROT2 하면 OCR이다. 자 넘어가자

 

Answer Url : http://www.pythonchallenge.com/pc/def/ocr.html

 

Python Challenge 0의 url은 다음과 같다.

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

 

warming up

Hint: try to change the URL address.

www.pythonchallenge.com


구성

url address를 바꾸어 보라고 하는데 0.html이 페이지 스크립트인 것을 이용해서 1.html로 바꾸어보았다.

으흠; 이곳을 바꾸는것은 맞는 거 같다. 화면에 있는 2의 38 제곱을 계산하자

>>> 2**38
274877906944

대부분의 경우에서 2의 38제곱은 오버플로우가 일어나기 쉬운 큰 수이다. 아마 "얘 Python은 이것도 된단다"를 이야기하고 싶었던 거 같다.

 

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

+ Recent posts