보안개구리
[게시판 실습] - SQL Injection (2) 데이터 조회 공격(Union-Based SQL Injection) 본문
[게시판 실습] - SQL Injection (2) 데이터 조회 공격(Union-Based SQL Injection)
보안개구리 2024. 8. 16. 12:05[설 명]
SQL Injection은 사용자의 입력 값으로 웹 사이트 SQL 쿼리가 완성되는 약점을 이용하며, 입력값을 변조하여 비정상적인 SQL 쿼리를 조합하거나 실행하는 공격으로 개발자가 생각지 못한 SQL문을 실행하게 함으로써 데이터베이스를 비정상적으로 조작 가능한 공격으로 소스코드에 SQL 쿼리를 입력값으로 받는 함수나 코드를 사용할 경우, 비정상적인 SQL 쿼리로 DBMS 및 데이터를 열람하거나 조작 가능하므로 사용자의 입력 값에 대한 필터링을 구현하여야 한다.
[점검 내용]
웹 페이지 내 SQL Injection 취약점 존재 여부 점검
[점검 기준]
임의의 SQL Query 입력에 대한 검증이 이루어지지 않는 경우 취약
[대응 방법]
* SQL 쿼리에 사용되는 문자열의 유효성을 검증하는 로직 구현
* 특수문자를 사용자 입력 값으로 지정 금지
* Dynamic SQL 구문 사용을 지양하며 파라미터에 문자열 검사 필수 적용
* 시스템에서 제공하는 에러 메시지 및 DBMS에서 제공하는 에러 코드가 노출되지 않도록 예외처리
* Stored Procedure 사용
* 필터링 등 입력값 검증 프로세스는 Client side script가 아닌 Server 페이지로 구현
[진단 과정]
1) 게시판에 접속 후 기능을 확인합니다. 현재 3개의 게시글이 존재하며 게시글 번호. 게시글 제목, 게시글 작성자 검색을 통해 게시글을 조회할 수 있습니다.
2) 데이터 조회 공격에 앞서 먼저 연결 연산자를 통해 DBMS를 확인하겠습니다. 연결 연산자를 사용하여(te' 'st) 조회 시 기존과 마찬가지로 검색을 되는 것을 보아 MySQL을 사용하는 것을 추측할 수 있습니다.
※ MySQL: 공백 / MsSQL: + / Oracle: ||
3) 다음으로는 게시글 조회 시 쿼리 구문을 추측해보도록 하겠습니다. 기본적으로 게시글 검색 시 구조는 SELECT * FROM [테이블] WHERE [조건]; 이런 식으로 들어갈 텐데 게시글 제목으로 te 검색 시 test 게시판이라는 제목이 검색되는 것으로 보아 like 연산자를 사용하는 것을 알 수 있고 이때 BurpSwite를 통해 요청값 확인 결과 searchType이 postTitle인 것을 보아 전체적인 쿼리는 SELECT * FROM [테이블] WHERE postTitle like '%[조건]%'; 형식임을 유추할 수 있습니다.(물론 실제로는 다를 수 있습니다/)
4) Order By 구문을 이용하여 컬럼의 개수를 확인합니다. order by절을 사용하면 현재 게시판에서 사용하는 테이블의 칼럼에 따라 정렬방식을 달리하여 컬럼의 개수를 파악할 수 있습니다. 만약 컬럼의 개수가 10개라고 가정한다면 order by 1# ~ order by 10# 까지는 전부 참이 되어 작성된 게시글이 목록에 노출되겠지만 order by 11#의 경우 거짓이 되어 게시글이 목록에 노출되지 않는 점을 이용합니다.
이 때 컬럼의 개수가 많을 수 있기 때문에 Burp Swite를 이용하여 확인하겠습니다.
5) Payload에 들어가 있는 값이 Order by 다음에 들어가는 숫자로 8까지는 3851의 길이값을 가졌으나 숫자 9 이후로는 길이값이 확연히 줄어든 것을 볼 수 있습니다. 따라서 현재 게시판의 컬럼 개수는 총 8개임을 알 수 있습니다. 확실하게 확인하기 위하여 다시 한번 게시글에 검색해 보도록 하겠습니다.
6) 아래와 같이 order by 8#입력시 쿼리 구문이 참이 되어 게시글이 출력되었으나 order by 9# 쿼리 구문이 거짓이 되어 게시글이 출력되지 않았습니다. 이를 통해 다시 한번 컬럼의 개수가 8개임을 알 수 있습니다.
7) 실제 컬럼의 개수는 8개이지만 현재 게시판을 보면 번호/제목/작성자/작성일/첨부파일 총 5개의 컬럼만 노출되었습니다. 따라서 우리는 실제 존재하는 컬럼 중 어떤 컬럼들이 게시판에 노출되는지 확인해야 합니다. 이때 사용하는 것이 Union-Based SQL Injection입니다.
8) ' union select 1,2,3,4,5,6,7,8#을 입력해보겠습니다.입력 시 입력한 숫자 중 1,2,5가 게시글 내 출력이 되었습니다. 작성일의 경우 데이터타입 문제로 인하여 N/A가 발생하였고 번호의 경우는 숫자형 데이터만 출력이 가능하기 때문에 이번 실습에서는 2,5 즉 제목과 작성자 컬럼 부분을 이용하여 실습하겠습니다.
여기서 현재 실습의 경우 게시글의 개수가 적기 때문에 우리가 입력한 데이터를 쉽게 확인할 수 있으나 만약 데이터가 굉장히 많을 경우 ' union select 1,2,3,4,5,6,7,8# 구문이 아닌 ' and 1=2 union select 1,2,3,4,5,6,7,8#을 통하여 더 쉽게 확인이 가능합니다.
9) 해당 컬럼들을 통해 간단한 정보들을 획득할 수 있는데 user(), version(), database(), @@datadir 등의 정보를 획득할 수 이 있습니다. ' and 1=2 union select 1,database(),3,4,user(),6,7,8#를 입력하여 스키마명과 유저명을 확인하였습니다.
10) 데이터 조회 공격 시 DB명 획득 -> 테이블명 획득 -> 컬럼명 획득 -> 중요정보 획득 순서로 하는 편인데 우선 9번 과정을 통해 DB명을 획득했기 때문에 테이블명을 획득해 보도록 하겠습니다.
' and 1=2 union select 1,table_name,3,4,5,6,7,8 from information_schema.tables where table_schema='yb'# 를 입력하면 member, post 두 가지거 검색되는데 바로 yb 스키나 내 존재하는 테이블명입니다. 여기서 테이블 이름을 조회 시 information_schema.tables를 사용했는데 해당 DB정보는 아래와 같습니다.
information_schema.schemata: MySQL 서버에 존재하는 모든 DB(스키마)의 정보를 담고 있으며 주요 컬럼으로는 schema_name 등이 있습니다.
information_schema.tables: MySQL 서버에 존재하는 모든 테이블에 대한 정보를 담고 있으며 주요 컬럼으로는 table_schema, table_name, table_type 등이 있습니다.
information_schema.columns: MySQL 서버에 존재하는 모든 테이블의 열(컬럼)에 대한 정보를 담고 있으며 주요 컬럼으로는 table_schema, table_name, column_name, data_type 등이 있습니다.
따라서 information_schema.schemata를 통해 DB(스키마)명을 획득하고 information_schema.tables를 통해 테이블명을, information_schema.columns를 통해 컬럼명을 각각 순서대로 획득한다고 생각하면 됩니다.
11) DB명 획득 -> 테이블명 획득 -> 컬럼명 획득 -> 중요정보 획득 중 테이블명('member', 'post') 획득까지 성공하였습니다. 현재의 경우는 테이블의 개수가 적기 이름이 직관적이기 때문에 게시판에서 사용되는 테이블이 post이고 member는 회원가입 관련 테이블로 추측할 수 있습니다.
10번 과정에서 말한것처럼 information_schema.columns를 통해 'memeber'테이블 내 컬럼들을 확인해보겠습니다.
' and 1=2 union select 1,column_name,3,4,5,6,7,8 from information_schema.columns where table_schema='yb' and table_name='member'# 입력 시 아래와 같이 6개의 컬럼이 존재함을 확인할 수 있고 각각의 컬럼명을 획득하였습니다.
12) DB명 획득 -> 테이블명 획득 -> 컬럼명 획득 -> 중요정보 획득 중 컬럼명까지 획득하였고 해당 컬럼중에서 중요정보라 할 수 있는 userID값과 userPW값을 확인해보겠습니다. ' and 1=2 union select 1,userID,3,4,userPW,6,7,8 from member#을 입력하여 제목에는 id값을 작성자에는 pw값이 출력이 되는데 현재 db 내 존재하는 id는 admin/hacker/userA이고 해당 pw는 각각 admin/123/votmdnjem1! 임을 알 수 있습니다.
13) 해당 정보의 진위 여부를 확인하기 위해 실제 DB 내에서 조회해 보도록 하겠습니다. DB 확인 시 위에서 획득한 정보와 일치하는 것을 확인하였습니다.
'웹 진단 > 게시판 실습' 카테고리의 다른 글
[게시판 실습] - 파일 업로드 (1) 웹쉘 파일 업로드 확인 (1) | 2024.06.16 |
---|---|
[게시판 실습] - 파일 다운로드 (1) 파일 다운로드 시 지정된 경로 우회 가능 (0) | 2024.06.12 |
[게시판 실습] - 불충분한 인가 (2) 삭제된 게시글 조회 가능 (0) | 2024.06.10 |
[게시판 실습] - 불충분한 인가 (1) 관리자 페이지 접속 시 검증 로직 미흡 (0) | 2024.06.10 |
[게시판 실습] - 불충분한 인증 (2) 타인의 게시글 수정 및 삭제 가능 (0) | 2024.06.10 |