[CTF Writeup / Crypto] IrisCTF 2024 - Accessible Sesamum Indicum

Accessible Sesamum Indicum

guess the password lol



#!/usr/bin/env python3

import random

MAX_DIGITS = 65536

def vault(attempt) -> bool:

pin = "".join([random.choice("0123456789abcdef") for _ in range(4)])
print(f"* pin : {pin}")
digits = ["z", "z", "z", "z"]
counter = 0

print("What is the 4-digit PIN?")

while True:
for _ in range(len(attempt)):

digits.insert(0, attempt.pop())
digits.pop()

# print(f'* digits : {"".join(digits)}')

if "".join(digits) == pin:
return True

counter += 1
if counter > MAX_DIGITS:
return False

return False

def main(attempt):

print("You're burgling a safehouse one night (as you often do) when you run into a")
print("vault. The vault is protected by a 16-digit pad for a 4-digit PIN. The")
print("safehouse is guarded by an alarm system and if you're not careful, it'll go")
print("off, which is no good for you. After this, there are 15 more vaults.\n")

for n in range(16):

print(f"You've made it to vault #{n+1}.\n")

print("|---|---|---|---|")
print("| 0 | 1 | 2 | 3 |")
print("|---|---|---|---|")
print("|---|---|---|---|")
print("| 4 | 5 | 6 | 7 |")
print("|---|---|---|---|")
print("|---|---|---|---|")
print("| 8 | 9 | a | b |")
print("|---|---|---|---|")
print("|---|---|---|---|")
print("| c | d | e | f |")
print("|---|---|---|---|\n")

if not vault(attempt):
print("The alarm goes off and you're forced to flee. Maybe next time!")
return
print("You've defeated this vault.")

print("You unlock the vault and find the flag.\n")
with open("flag.txt", "r") as f:
print(f.read(), end="")


문제를 보면 위와 같이 랜덤 패스워드를 생성한 뒤, 사용자에게 인풋을 받아서 일치하는지 체크한다.

패스워드는 랜덤픽이라서 찾아낼 수는 없다. 그런데 16번이나 연속으로 맞춰야 flag를 준다. pop insert를 이용해 한글자씩 추가하며 비교한다는 점을 이용해서 사용자 인풋값을 매우 길게 해서 bruteforce 처럼 공격할 수 있다.


from pwn import *
import time

def payload():
attempt = ''

while len(attempt) < 63000:
c = random.choice("0123456789abcdef")
if len(attempt) > 4:
block = attempt[-3:] + c
if block in attempt:
continue
attempt += c

if len(attempt) % 10000 == 0:
log.info(f'step {len(attempt)}')
return attempt

log.info('payload creating...')
attempt = payload()
log.success('ok')

# attack
while True:
x = remote('accessible-sesasum-indicum.chal.irisc.tf', 10104)
try:
for i in range(16):
if i==16:
context.log_level = 'debug'
x.recvuntil(b"You've made it to ", timeout=2)
_line = x.recvline()
log.info(_line)
x.sendline(attempt.encode())
x.interactive()
break
except:
log.warn('fail')
x.close()
time.sleep(2)
continue


익스 코드다. 우선 인풋으로 전송할 페이로드를 작성한다.

MAX_DIGITS = 65536

최대 길이가 65536임을 고려하여 대충 63000글자의 페이로드를 만든다. 더 정교하고 합리적인 알고리즘이 있겠지만, 지능 이슈로 문제처럼 랜덤픽을 했다. 단, 4글자가 겹치지 않아야 한다는 조건을 추가해서 하나의 페이로드가 여러 경우의 수를 포함하도록 구성했다.

위 페이로드로 한번에 익스가 성공되지는 않는다. 성공할 때까지 반복하도록 코드를 작성했고, 두번만에 성공했다.

irisctf{de_bru1jn_s3quenc3s_c4n_mass1vely_sp33d_up_bru7e_t1me_f0r_p1ns}

댓글