CTF/리버싱

[HouseplantCTF] thedanzman - 리버싱 / Python / ROT13 / Base64

SecurityMan 2022. 6. 17. 11:00

마지막 Python 리버싱 문제.

문제 설명을 읽어보면,

EZ, PZ, LEMON, SQUEEZY 문제보다 훨씬 어렵게 만들어서

플래그를 절대 획득하지 못할것이라고 한다.
(EZ : https://hackingstudypad.tistory.com/167)
(PZ : https://hackingstudypad.tistory.com/169)
(LEMON : https://hackingstudypad.tistory.com/171)
(SQUEEZY : https://hackingstudypad.tistory.com/172)

반응형


하지만 역시나 차근차근 계산하면 충분히 풀 수 있는 문제이다.


주어지는 문제파일은 pass4.py 파일이다.


패턴은 이전 문제와 똑같다.

IDLE을 이용해 py 파일을 실행시켜 보니

Enter the password: 라는 문구가 나오고,

123을 입력해봤더니 Incorrect password! 라는 문구가 나오면서

저번처럼 약올리는듯한 멘트를 출력한다.

import base64
import codecs
def checkpass():
  userinput = input("Enter the password: ")
  key = "nyameowpurrpurrnyanyapurrpurrnyanya"
  key = codecs.encode(key, "rot_13")
  a = nope(key,userinput)
  b = str.encode(a)
  c = base64.b64encode(b, altchars=None)
  c = str(c)
  d = codecs.encode(c, 'rot_13')
  result = wow(d)
  if result == "'=ZkXipjPiLIXRpIYTpQHpjSQkxIIFbQCK1FR3DuJZxtPAtkR'o":
      return True
  else:
      return False

def main():
    access = checkpass()
    if access == True:
        print("Unlocked. The flag is the password.")
        print("pwease let me do my nya~ next time!!")
        exit()
    else:
        print("Incorrect password!")
        print("sowwy but now you gunnu have to listen to me spweak in cat giwrl speak uwu~")
        catmain()

def catmain():
    access = catcheckpass()
    if access == True:
        print("s-senpai... i unwocked it fowr you.. uwu~")
        print("t-the fwlag is... the password.. nya!")
        exit()
    else:
        print("sowwy but that wasnt quite rwight nya~... pwease twy again")
        catmain()

def catcheckpass():
  userinput = input("pwease enter youwr password... uwu~ nya!!: ")
  key = "nyameowpurrpurrnyanyapurrpurrnyanya"
  key = codecs.encode(key, "rot_13")
  a = nope(key,userinput)
  b = str.encode(a)
  c = base64.b64encode(b, altchars=None)
  c = str(c)
  d = codecs.encode(c, 'rot_13')
  result = wow(d)
  if result == "'=ZkXipjPiLIXRpIYTpQHpjSQkxIIFbQCK1FR3DuJZxtPAtkR'o":
      return True
  else:
      return False

def nope(s1,s2):
    return ''.join(chr(ord(a) ^ ord(b)) for a,b in zip(s1,s2))

def wow(x):
  return x[::-1]

access = False
main()


pass4.py 파일의 내용은 위와 같다.

역시나 길어보이는 내용이지만

실행되지 않는 더미 코드들이 많이 끼어있어서 그렇게 보이는 것이다.


이번에도 똑같은 패턴이다.

main 함수를 먼저 살펴보면

access 변수에 checkpass() 변수의 실행 결과를 담아주고,

access에 담긴 값이 True 경우 플래그를 획득할 수 있다.

checkpass() 함수를 살펴보자.


이 부분이 이전 문제들보다 조금 더 복잡해졌다.

가장먼저 userinput 변수에 사용자가 입력한 값을 담아주고,

key 변수를 선언해 그안에 nyameowpurrpurrnyanyapurrpurrnyanya 라는 값을 넣어준다.

그다음 key 변수를 rot13 으로 인코딩해주고,

nope(key, userinput) 함수를 수행한 결과를 a에 담아준다.


nope 함수는 단순히 두 인자를 XOR(^) 해주는 역할을 한다.

다음으로 nope 함수 수행 결과를 base64 인코딩 한 뒤, 다시한번 rot13으로 인코딩해주고,

마지막으로 wow() 함수를 수행한 결과를 result에 저장하는데


wow 함수는 단순히 역순으로 출력하는 역할을 한다.

그렇게 해서 결과가 =ZkXipjPiLIXRpIYTpQHpjSQkxIIFbQCK1FR3DuJZxtPAtkR 이면 True를 리턴한다.

이번에도 간단하게 식으로 표현해보자면

reverse(rot13(base64encode(userinput ^ rot13(key)))) = result 이다.

이걸 역으로 계산하면

base64decode(rot13(reverse(result))) ^ rot13(key) = userinput 가 될것이다.


계산은 CyberChef(https://gchq.github.io/CyberChef/)에서 쉽게 가능하다.

가장 먼저 key값인 nyameowpurrpurrnyanyapurrpurrnyanya를 rot13 으로 인코딩한 값을 계산해준다.

alnzrbjcheecheealnalncheecheealnaln 값이 나온것을 확인해주고


reverse, rot13, base64, xor을 차례대로 넣어주면

플래그를 획득할 수 있다.


프로그램을 실행시키고 password에 플래그를 넣어주면

정상적으로 Unlocked 라고 뜨는걸 볼 수 있다.

반응형