Normaltic 모의해킹 취업반 스터디 8기 - 5주차 (SQL Injection)

containerxox·2025년 4월 30일
post-thumbnail

📢 1개월차 스터디 Review

• WEB - WAS - DB 관계

  • Web서버는 파일(정적 리소스)를 전달하는 역할
  • WAS는 동적페이지를 담당
  • DB는 데이터를 보관하는 역할
  • WAS가 DB에 있는 데이터를 가져오거나 저장함.
  • DB에 데이터를 조작하는 언어는 SQL
  • WAS에 SQL쿼리를 작성해놓으면 DB와 상호작용을 하며 데이터를 관리
     
  • Front-End( HTML, CSS, JavaScript ) - Back-End ( PHP, JSP, Python, Javascript )



• 로그인

↳ 로그인 인증

  • 식별: 자신의 정체를 선언하는 것
  • 인증: 식별된 사용자가 진짜 맞는지 검증하는 것.

↳ 로그인 상태 유지

  • 쿠키: 브라우저 안에 저장하는 작은 데이터 조각
  • 세션: 서버에 저장된 사용자 데이터 덩어리 (사용자의 로그인 상태같은 정보들을 저장)
  • 세션ID: 서버에 저장된 세션 데이터를 식별하기 위한 key(고유 식별자)



• Burp Suite

: Web Proxy Tool




  

✅ SQL Injection

: 웹 어플리케이션에서 사용자의 입력값을 제대로 검증하지 않고, SQL 쿼리에 포함시킬 때 발생하는 보안 취약점

  • 공격자는 DB에 원래 의도하지 않은 SQL 명령을 삽입하거나 실행하게 만들어서,
    DB의 데이터를 탈취하거나 조작 가능!

☑️ 실습

실습 사이트: http://ctf.segfaulthub.com:1020/

👉 [1] SQL

  
select * from member 입력

select * from member where id='normaltic' 입력
→ id가 normaltic인 레코드만 결과에 뜸.

select id, pass from member where id='normaltic' 입력
→ id가 normaltic인 레코드에서 id 컬럼과 pass컬럼만 출력되게 함.

  
 

💁‍♀️ 이제 SQL 인젝션이 뭔지 본격적으로 공부해보자.

👉 [2] SQL Injection

⓪ normaltic이라는 id를 조회 ( normaltic 검색 )

💁 normaltic을 검색하게 되었을때,
서버에서 일어나는 과정에 대해서 설명해볼게

  • 검색을 하면, 웹 서버로 normaltic이라는 글자가 전달됨
    Burp Suite로 확인해보자 (Intercept 기능 이용하기)
    query=normaltic을 보니 normaltic이라는 문자열을 웹 서버로 보내고 있는 것을 알 수있다!
    → WAS에서 select * from member where id='___'이라는 SQL문을 준비해두고 있음을 파악할 수 있다!



① 빈칸에 normaltic' 삽입

💁 만약에 작은 따옴표(')를 추가하면 어떻게 될까?(normaltic')
normaltic'으로 작성하고 Enter
→ 에러 발생!

🤔 왜 에러가 발생할까?
→ SQL 문법 에러 발생 (You have an error in your SQL syntax;)
→ 웹 서버의 입장에서는 준비된 SQL 쿼리(select * from member where id='___')의 빈공간에 입력한 문자를 넣는건데,
normaltic'을 넣으면, select * from member where id='normaltic''이 된다.
😕 웹 서버 입장: normaltic 옆의 ' 이거 뭐야?!
→ SQL 문법에서 벗어남
→ 그래서 에러 발생!



② 빈칸에 normaltic' and '1'='1 삽입

💁‍♀️select * from member where id=‘normaltic’ and ‘1’=‘1’의 경우,
조건이 id='normaltic' (참)이고 '1'='1' (참)으로 AND 연산에 의해 둘다 참이므로 결과가 참이다.
👉 이걸 이용해서 normaltic 계정으로 로그인 가능하지 않을까? (로그인 우회)


➡️ normaltic 으로 로그인 성공!



③ 빈칸에 normaltic' and pass='1234 삽입

💁‍♀️select * from member where id=‘normaltic’ and pass='1234’의 경우,
조건이 id='normaltic' (참)이고 pass='1234'(참)으로 AND 연산에 의해 둘다 참이므로 결과가 참이다.
👉 이걸 이용해서 normaltic 계정으로 로그인 가능하지 않을까? (로그인 우회)


➡️ normaltic 으로 로그인 성공!



④ 빈칸에 normaltic' or '1'='1 삽입

💁‍♀️select * from member where id=‘normaltic’ or ‘1’='1'의 경우,
조건이 id='normaltic'(참)이거나 '1'='1'(이건 무조건 참)
OR 연산에 의해 둘 중에 하나만 참이면 최종결과가 참이다.
따라서, 위 조건은 두 조건다 참이므로 OR연산에 의해 최종 결과가 참이 된다.
➡️id가 normaltic인 경우의 레코드와 '1'='1'이라는 조건에 의해 모든 레코드들이 출력된다.


➡️ memeber 테이블의 모든 레코드가 출력됨



👉 [3] SQL Injection 2

① 주어진 정보 id: normaltic, pass: 1234를 이용해 로그인 시도


➡️ 로그인 성공!

② id와 pw를 잘못 입력하여 로그인 실패한 경우


➡️ WAS를 통해 DB를 조작(관리)하니까 로그인 하는 과정에서 SQL Injection 공격을 할 수 있을거야.
➡️ WAS에서 준비한 SQL 쿼리는 select * from member wher id='_____' and pass='______'로 예상됨.
➡️ 해당 빈칸들을 잘 이용해서 SQL Injection 공격을 성공시켜보자!




③ id부분의 빈칸에 normaltic'# 또는 normaltic'-- 삽입>


→ id 부분에 normaltic'# 또는 normaltic'-- , pw 부분에는 아무거나 입력
→ pw를 아무거나 입력하는 이유는, #, -- (주석)을 통해 뒤에 있는 부분은 주석처리 되기때문!
PW를 모르는 상태에서도 normaltic 계정으로 로그인 성공! (SQL Injection 성공)

<< MySQL에서 주석 종류 >>

  • --
    ↳ 반드시 뒤에 공백(또는 제어문자) 있어야 함.
    하이픈(-)이 두 개여야 주석으로 인정됨.
     
  • #
     
  • /**/
    ↳ 여러 줄 주석 처리 가능




💁‍♀️ 그러면 주석 말고도 다른 방법으로 우회하는 방법이 있을까?

④ id부분의 빈칸에 normaltic' or '1'='1 삽입


→ id부분에 normaltic' or '1'='1, pw부분에는 아무거나 입력함.
→ 실행되는 SQL 쿼리는
select * from member where id=‘normaltic’ or ‘1’=‘1’ and pass=‘아무거나’
 

→ 연산자 우선순위를 고려하여, AND 연산 후 OR 연산을 해보자.
 
'1'='1' and pass='아무거나' 조건을 보면, '1'='1'은 무조건 참, pass='아무거나'거짓이되므로
AND연산을 통해 최종 결과는 거짓이된다.
id=‘normaltic’ or 거짓이되고, OR연산에 의해 최종결과는 참
결국, 조건은 id='normaltic'만 참이되므로 normaltic 계정만 조회됨.
 
PW를 모르는 상태에서도 normaltic 계정으로 로그인 성공! (SQL Injection 성공)



☑️ 내 웹사이트에서 실습

< 내가 만든 로그인 페이지에서 SQL Injection 실습해보자>






✅ CTF write up

SegFault 웹 해킹 실습장 : http://ctf.segfaulthub.com/

☑️ 탐색 및 추론 과정

❶ 내가 입력한 데이터가 SQL 쿼리에서 삽입되어 실행되는 걸 인식하기
'1'='1'로 SQL 인젝션 공격이 실행이 되는지 체크해보기
❸ 만약 로그인 안되면 SQL 취약점이 없을 수 있다는 가정이 나옴.
❹ 로그인이 되면 SQL 취약점이 존재함을 알수있다.
❺ 식별/인증을 동시에 하는지, 따로 하는지 파악하기

① Login Bypass1 문제

( 로그인 페이지 탐색하기 with Burp Suite )

1️⃣ 주어진 정보를 이용하자! → ID는 doldol, PW는 dol1234로 로그인 → 로그인 성공

  
2️⃣ Burp suite 이용해서 로그인 프로세스를 탐색해보자!

ID, PW가 맞는 경우, ( ID는 doldol, PW는 dol1234로 로그인 )
Sign in 클릭(login.php) → index.php로 이동
➡️ 로그인 성공 페이지를 출력함.
 
login.php의 요청 & 응답
index.php의 응답

 
ID, PW가 틀린 경우,
Sign in 클릭(login.php) ➡️ 로그인 실패 페이지를 출력



☑️ login.php 탐색

Repuest(요청)을 보면,

  • 전송 방식: POST
  • 전송 데이터
    Userid: doldol
    Password: dol1234
    Submit: Login
    ➡️ 브라우저가 id와 pw 값을 서버로 전송함!
     
     
    Response(응답)을 보면,
  • HTTP 상태코드: 302 Found
    ↳ 302 상태코드 : 클라이언트(브라우저)에게 다른 URL로 리다이렉션 하라는 응답이다.
    ↳ 3으로 시작하는 상태코드는 Location이라는 헤더가 있다!
  • Location 헤더
    ↳ 클라이언트(브라우저)는 응답을 받고 index.php로 이동하게 됨



🤔 SQL Injection이 된다는 증거 없이 무작정 공격 시도하지말고, 먼저 문법을 추론하자!

먼저, 서버가 내부적으로 어떤 SQL 문법을 사용하는지
입력필드(준비된 SQL쿼리)의 특징과 동작을 통해 추론해야한다!

로그인 기능이 있다! → 내부적으로 SELECT쿼리가 사용될 가능성 높음
❷ 사용자가 입력한 id, pw를 기반으로 사용자 정보를 조회할 것이다.
id는 식별자(Primary key)로 자주 쓰이므로, 쿼리의 조건절에 사용될 가능성 높음.
select ? from member where id='____'
(물음표(?)부분은 테이블의 컬럼명을 모르기때문에 물음표로 임시로 적어놓은 것뿐임.)
 
 
💁‍♀️ 이 다음 단계는 식별/인증을 동시에 하느냐, 분리되었느냐인데, 아직 모름.
🤨 하지만, id를 쿼리 구문에 사용한다는 것은 확실해!
 
 
💁‍♀️ 위의 탐색정보를 가지고 SQL Injection이 발생하는지 체크해보자! (Repeater 이용)
➡️ id부분에 doldol' and '1'='1 입력, pw부분에 dol1234입력
➡️ 응답을 보면, 302상태코드와 location:index.php로 이동하여 로그인 성공 페이지를 출력함.
➡️즉, doldol이라는 아이디로 로그인을 성공함!
➡️ SQL Injection 발생하네!
➡️ doldol 뒤의 '가 SQL Injection 문법으로 인식이 되고, AND조건도 추가가 된다는 것을 알 수 있었다!

 
💁‍♀️ 식별/인증을 어떻게 하는지 탐색 및 추론해보자!
➡️ id부분에 doldol' or '1'='1을 입력하고 pw부분에 아무거나 입력하면
➡️ 로그인이 성공한다.
➡️ WAS에 준비된 SQL쿼리는
select * member whre id='____' and pw='_____'로 예상
➡️즉, 식별/인증을 동시에 함을 알 수 있다!
➡️ 실행된 쿼리가 select * from member where id='doldol' or '1'='1' and pw='아무거나'라면,
연산자 우선순위에 의해 '1'='1' and pw='아무거나'를 하면 참 and 거짓으로 결과가 거짓이되고,
id='doldol' or 거짓참 or 거짓 으로 최종결과가 참이 된다.
➡️ 따라서, 비밀번호를 몰라도 doldol 계정으로 로그인이 가능하다!
➡️ SQL Injection 발생함!

💡항등원이란?

: 계산을 했을 때 자기 자신이 나오는 값을 항등원이라 한다.

  • 예) 1 + 0 = 1 ➡️ 덧셈에서 항등원은 0
  • 예) 1 x 0 = 0 ➡️ 곱셈에서 항등원은 1
  • 예) where id='doldol' and '1'='1' ➡️ AND 연산에서 항등원은 '1'='1'




(인증/식별 동시에 한다는 가정하에) 이제 SQL Injection을 통해 normaltic1계정으로 로그인 우회해보자!

1️⃣ 첫 번째 시도
# 주석을 이용하자


➡️ 주석 처리되어서 비밀번호를 몰라도 normaltic1 계정으로 로그인 성공!![]



2️⃣ 두 번째 시도
↳ id부분에 normaltic1' or '1'='1 입력


➡️ 비밀번호를 몰라도 normaltic1 계정으로 로그인 성공!!



② GetAdmin 문제

( 로그인 페이지 탐색하기 with Burp Suite )
1️⃣ 주어진 정보를 이용하자! → ID는 doldol, PW는 dol1234로 로그인 → 로그인 성공




2️⃣ Burp suite 이용해서 로그인 프로세스를 탐색해보자

ID, PW가 맞는 경우, ( ID는 doldol, PW는 dol1234로 로그인 )
 
Sign in 클릭(login.php) → index.php로 이동
➡️ 로그인 성공 페이지를 출력함.
 
☑️ login.php 탐색
login.php의 요청
✓ 요청(Request)에서 Userid=doldol, Password=dol1234, Submit=Login
브라우저가 id와 pw 값을 서버로 전송!
 
login.php의 응답
✓ 응답(Response)에서 302 Found HTTP 상태코드
✓ 응답(Response)에서 Location헤더를 보면 index.php로,
클라이언트(브라우저)는 응답을 받고 index.php로 이동함!
✓ 응답(Response)에서 Set-Cookie헤더를 보면 loginUser=doldol로,
서버가 클라이언트(브라우저)에게 해당 쿠키를 저장하게 함.

 
☑️ index.php 탐색
index.php의 요청
✓ 요청(Request)에서 Cookie헤더를 보면 loginUser=doldol로,
위의 login.php 응답에 의해 브라우저에 저장한 쿠키를 요청(Request)과 함께 서버로 전송
로그인 성공 페이지 출력



ID, PW가 틀린 경우,
Sign in 클릭(login.php) ➡️ 로그인 실패 페이지를 출력


💡 << Cookie헤더 & Set-Cookie헤더 >>

  • Cookie 헤더
    요청(Request)에서 사용
    클라이언트(브라우저)가 서버에 요청을 보낼 때,
    자신이 저장하고 있는 쿠키를 Cookie헤더에 담아서 보냄
     
  • Set-Cookie 헤더
    응답(Response)에서 사용
    서버가 클라이언트(브라우저)에게 쿠키를 저장하라고 지시할 때,
    Set-Cookie헤더를 응답에 포함시킴

  
 
🤔 쿠키를 이용해서 로그인 우회해볼까?

쿠키는 클라이언트(브라우저)에 저장되니까
내가 변경(조작)이 가능해! → 로그인 우회 가능!
 

  • Burp suiteintercept 기능 이용하기
    👉 doldol로 로그인하면 index.php로 이동 → 로그인 성공 페이지 출력됨.
    👉 그 상태에서 intercpet on 설정
    👉 페이지 새로고침 누르기

    👉Request에서 Cookie헤더 값을 변경하자! (doldoladmin)
    👉 Forward 클릭

    👉 admin 계정으로 로그인 성공!



③ PIN CODE Bypass 문제

▶ ( 로그인 페이지 탐색하기 with Burp Suite )

  • /3 페이지 탐색


    ☑️ 응답을 보면, Fire 버튼 클릭 시, step1.php로 이동한다는 것을 알 수 있다.

     
     
  • Fire 버튼 클릭 → step1.php로 이동


    ☑️ 응답을 보면, 확인버튼 클릭 시, step2.php로 이동한다는 것을 알 수 있다.

     
     
  • 확인버튼 클릭 → step2.php로 이동!


    ☑️ 응답을 보면, 인증버튼을 클릭하게 되면,
    현재 페이지의 URL로,
    GET방식을 이용하여 GET /3/step2.php?admin_pass=입력값'의 요청이 발생한다는 것을 알 수 있다.

     
     
  • 관리자 비밀번호를 아무거나(hello) 입력해보자!
    ➡️ GET 방식을 이용하여 GET /3/step2.php?admin_pass=hello'의 요청이 발생

    ☑️ 응답을 보면, "비밀번호가 일치하지 않습니다"라는 알림창이 뜨는 것을 알 수 있다!

    ➡️ 비밀번호 일치하지 않는다는 알림창이 뜸.

     
     
    😕 하지만, 나는 관리자 비밀번호를 몰라.
    보아하니, 다음 단계로 갈때마다 /3 ➡️ /3/step1.php ➡️ /3/step2.php의 형태로 진행이 되는 것 같아!

    💁 아마도 그 다음단계는 /3/step3.php가 아닐까?
    ( 관리자 비밀번호 인증을 건너뛰는 거야! )

    ➡️ GET방식으로 URL에 /3/step3.php를 요청해보자!
     
     
  • Burp suite의 intercept 기능을 이용하여, 우회해보자!
    intercept on 설정
    /3/step2.php페이지를 새로고침!

    /3/step2.php?admin_pass=hello/3/step3.php로 변경하고, forward 클릭

     
     
  • /3/gogoHack.php로 이동 → Fire 버튼 클릭

    ☑️ 응답을 보면, 플래그가 알림창에 출력되고, 이전 기록인 /3/step2.php?admin_pass=hello로 페이지 이동하는 것을 알 수 있다.


    확인 버튼 클릭 → /3/step2.php?admin_pass=hello로 페이지로 이동

     
     
    📢 결론
    ➡️ 페이지를 건너뛰어서 관리자 인증을 우회 성공함!

0개의 댓글