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

Python을 손에서 놓은 지 한 달이 넘어가고 있다. 어쩔 수 없긴 했는데, 개발언어라는 것이 안 하고 있으면 까먹기 십상이니 조금 기억을 환기할 겸 Python Challenge를 시작하려고 한다,

http://www.pythonchallenge.com/index.php

 

The Python Challenge

What people have said about us: "These sorts of things are in my opinion the best way to learn a language.", brberg at Media Cloisters "It's the best web site of the year so far.", Andy Todd at halfcooked "Addictive way to learn the ins and outs of Python.

www.pythonchallenge.com

필자는 10단계 이상 가본 적이 없다 ㅋㅋㅋㅋㅋㅋㅋㅋ

이번에 공부하면서 공략 글을 올리고 내 실력도 조금 올려놔야 되겠다.

 

Python Challenge는 로그인이 없이 웹 파라미터를 가지고 Url을 이동하면서 문제풀이가 진행된다.(어? directory traversal이나 listing으로 2 ke2 ke 할 수 있나?)

+ Recent posts