
Web서버는 파일(정적 리소스)를 전달하는 역할WAS는 동적페이지를 담당DB는 데이터를 보관하는 역할- WAS가 DB에 있는 데이터를 가져오거나 저장함.
- DB에 데이터를 조작하는 언어는 SQL
- WAS에 SQL쿼리를 작성해놓으면 DB와 상호작용을 하며 데이터를 관리
Front-End( HTML, CSS, JavaScript ) -Back-End( PHP, JSP, Python, Javascript )
식별: 자신의 정체를 선언하는 것인증: 식별된 사용자가 진짜 맞는지 검증하는 것.
쿠키: 브라우저 안에 저장하는 작은 데이터 조각세션: 서버에 저장된 사용자 데이터 덩어리 (사용자의 로그인 상태같은 정보들을 저장)세션ID: 서버에 저장된 세션 데이터를 식별하기 위한 key(고유 식별자)
: Web Proxy Tool
: 웹 어플리케이션에서 사용자의 입력값을 제대로 검증하지 않고, SQL 쿼리에 포함시킬 때 발생하는 보안 취약점
- 공격자는 DB에 원래 의도하지 않은 SQL 명령을 삽입하거나 실행하게 만들어서,
DB의 데이터를 탈취하거나 조작 가능!
실습 사이트: http://ctf.segfaulthub.com:1020/
① select * from member 입력

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

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

💁♀️ 이제
SQL 인젝션이 뭔지 본격적으로 공부해보자.
⓪ 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 테이블의 모든 레코드가 출력됨
① 주어진 정보 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 실습해보자>
SegFault 웹 해킹 실습장 : http://ctf.segfaulthub.com/
❶ 내가 입력한 데이터가 SQL 쿼리에서 삽입되어 실행되는 걸 인식하기
❷'1'='1'로 SQL 인젝션 공격이 실행이 되는지 체크해보기
❸ 만약 로그인 안되면 SQL 취약점이 없을 수 있다는 가정이 나옴.
❹ 로그인이 되면 SQL 취약점이 존재함을 알수있다.
❺ 식별/인증을 동시에 하는지, 따로 하는지 파악하기

▶ ( 로그인 페이지 탐색하기 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 계정으로 로그인 성공!!

▶ ( 로그인 페이지 탐색하기 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 FoundHTTP 상태코드
✓ 응답(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 suite의 intercept 기능 이용하기
👉 doldol로 로그인하면index.php로 이동 → 로그인 성공 페이지 출력됨.
👉 그 상태에서intercpet on설정
👉 페이지 새로고침 누르기
👉Request에서 Cookie헤더 값을 변경하자! (doldol→admin)
👉 Forward 클릭
👉 admin 계정으로 로그인 성공!

▶ ( 로그인 페이지 탐색하기 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로 페이지로 이동
📢 결론
➡️ 페이지를 건너뛰어서 관리자 인증을 우회 성공함!