writeups by ch4nsec

[Midnight Flag CTF 2026] Blackbank

Midnight Flag CTF 2026에서 출제된 Blackbank 문제 풀이

#ctf#web#Midnight Flag CTF#sql injection#prng prediction

문제 개요

katarina:Kathax0r_sk1d0s라는 계정이 주어지고, 해당 계정으로 로그인할 수 있는 은행 서비스와 메일 서비스가 주어진다.

midnightflagctf_blackbank1

해당 계정으로 로그인했을 때 알아낼 수 있는 Vladizlow라는 관리자 계정에 접근하는 것이 문제

코드

(블랙박스)

풀이

인스턴스 제한 이슈로 캡처가 제한적

은행쪽 서비스에 SQL injection 취약점이 존재했다.

midnightflagctf_blackbank2

username 또는 password에 SQLi를 발생시켜 Vladizlow 계정으로 1차 침입이 가능하다.

로그인이 2FA로 이루어져 있기 때문에 2차 인증을 통과해야 한다.

로그인을 수행하면 해당 사용자의 메일로 인증번호가 발송된다.

midnightflagctf_blackbank3

대충 이런식으로

초기 접근은 SQLi를 통해 Vladizlow라는 계정으로 로그인을 하면서 katarina 메일 계정으로 인증번호를 보내는 방식이었다.

users 테이블의 column으로 idx, username, password, emailUser가 존재했기 때문에, 'abc' union select 1,'Vladizlow','123','katarina'-- - 와 같은 payload를 삽입하면 Vladizlow라는 username으로 katarina의 계정에 인증 메일을 보낼 수 있을 것이라는 가설이었다.

이 가설은 실패하였는데, 로그인 식별을 username으로 하고 있었던 것은 맞지만, 이메일을 보내는 목적지도 emailUser가 아닌 username을 통해 지정하고 있었던 것으로 추정한다. (왜 그랬는지는 잘 모르겠다.)

두 번째 접근은 race condition이었다. katarina와 Vladizlow로 동시에 로그인을 시도했을 때, Vladizlow의 인증번호가 katarina로 올 것이라는 가설이었는데, 이 역시 실패하였다.

마지막 접근은 PRNG prediction이었다.

midnightflagctf_blackbank4

인증번호를 많이 뽑다보면 대부분 8자리가 나오지만, 간혹 6자리 또는 7자리가 출력되는 경우가 존재했다.

이 현상을 보고 인증번호 결정 로직을 추측할 수 있었는데, 모종의 random() 함수를 통해 랜덤 수를 뽑아내고 (e.g. 0.617298623) 여기에 10^8을 곱한 결과의 정수값을 인증번호로 사용한다는 점을 알 수 있었다. 앞자리 숫자가 0이 하나도 존재하지 않았다는 점과 자릿수가 대부분 8자리이지만 일정하지는 않았다는 점이 그 근거였다.

V8엔진에서 사용하는 xorshift128+ 알고리즘에 의해 다음 값을 예측할 수 있었다.