문제 확인
SQL(Structured Query Language)이란?
데이터베이스에서 데이터를 추출하고 조작하는 데에 사용하는 데이터 처리 언어이다.
- 쉽게 말해 데이터베이스에 저장된 정보를 쉽게 찾고 정리하는 데에 도움을 주는 도구
- 시장 트렌드 분석이나 고객 행동 패턴 파악 등을 통해 적합한 전략을 수립할 수 있다.
- SQL을 통해 데이터베이스에서 원하는 정보를 추출하고, 데이터의 흐름이나 특정 조건에 따른 데이터 분석을 할 수 있다.
* SQL을 사용하기 위해서는 데이터베이스 관리 시스템(DBMS)을 설치하고, 해당 DBMS에 맞는 SQL 프로그램을 선택하여 사용한다.
* 대표적인 DBMS로는 Oracle, MySQL, MS SQL(Microsoft SQL Server) 등이 있으며, 이들 DBMS는 각각의 데이터베이스의 관리, 데이터 조작, 데이터 보안 등 다양한 기능을 제공하고 있어, 사용 목적에 맞게 선택하여 사용해야 한다.
대표적인 관리 시스템 3가지의 특징
Oracle, My SQL, MS SQL
Oracle
- 대규모 기업용 데이터베이스 시스템
- 유닉스/리눅스 환경에서 가장 많이 사용되는 DBMS
- 안정성과 확장성이 높음
MySQL
- 오픈 소스 기반의 관계형 데이터베이스 관리 시스템
- 빠른 속도와 높은 성능을 지원
- 가벼운 설치와 사용이 가능하며, 웹 애플리케이션과 소규모 비즈니스에 많이 사용됨
MY SQL(Microsoft SQL Server)
- Microsoft가 개발한 관계형 데이터베이스 관리 시스템
- Windows 운영 체제에 친화적인 시스템
- 편리한 관리 도구와 호환성이 높은 특징으로 기업용 솔루션으로 많이 사용됨
Error based SQLi
데이터베이스 오류 메시지를 활용하여 데이터베이스에 대한 정보를 획득하는 SQL Injection 기법
- 잘못된 SQL 문법이나 자료형 불일치 등으로 인해 데이터베이스가 발생시키는 오류 메시지를 이용하여 공격자는 데이터베이스의 구조와 정보를 파악할 수 있다.
- XPath와 Double Query
XPath
extractvalue() 함수를 활용한 기법으로 MySQL 기준 5.1 버전 이상에서만 가능하다.
extractvalue(xml_frag, xpath_expr)
위와 같이 extractvalue()는 XML(xml_frag 인수)과 XPath 표현식(xpath_expr 인수), 두 개의 인수가 필요
두 개의 인수를 통해 XML에서 XPath 표현식에 일치하는 데이터를 추출하여 반환
이 함수는 xpath_expr이라는 두 번째 인수에 유효하지 않은 XPath 표현식이 사용된다면 다음과 같은 오류가 발생한다.
ERROR 1105 (HY000): XPATH syntax error: 'xpath_expr 인수의 값'
xpath_expr 인수로 임의의 SQL 쿼리를 지정했을 때 이 쿼리의 실행 결과가 오류 메시지에 포함된다.
이 점을 이용해 오류기반 SQLi를 수행할 수 있다.
두 번째 인수가 항상 유효하지 않은 XPath 표현식이 되도록 하기 위해 concat() 함수를 이용해 콜론(:)을 앞에 추가합니다. 0x3a는 콜론의 16진수 표기법입니다.
첫 번째 인수는 임의의 값을 지정하기 위해 rand() 함수를 사용합니다.
그리고 마지막으로 후속 쿼리를 무효화하기 위해 가장 끝에 주석 문자(--)와 공백 문자(스페이스)를 추가한다.
주석 문자 뒤에 공백 문자를 추가하는 것을 잊으면 안 된다.
AND extractvalue(rand(), concat(0x3a, Excutable-SQL-Query))--
위의 extractvalue() 함수의 오류 메시지는 단일 행(한 줄)으로 반환되므로 LIMIT을 사용하여 한 번에 하나의 행만 출력될 수 있도록 한다. 계속해서 다음 행의 데이터를 추출하기 위해서는 아래와 같이 반복하여 실행하면 된다.
...LIMIT 0, 1)))-- (SQL 쿼리에서 반환된 레코드셋의 첫번째 행 반환)
...LIMIT 1, 1)))-- (SQL 쿼리에서 반환된 레코드셋의 두번째 행 반환)
...LIMIT 2, 1)))-- (SQL 쿼리에서 반환된 레코드셋의 세번째 행 반환)
...LIMIT 3, 1)))-- (SQL 쿼리에서 반환된 레코드셋의 네번째 행 반환)
... 생략 ...
위의 방식과 유사한 기법으로 updatexml() 함수를 이용할 수도 있다.
기본형은 아래와 같으며 추출하고자 하는 데이터에 따라 "실행할-SQL-쿼리" 부분만 위의 방식대로 변경해주면 된다.
AND updatexml(null, 실행할-SQL-쿼리, null)--
SQL Injection 관련 문제
문제 풀이
파일을 다운받는다.
MySQL 데이터베이스를 생성하고 사용자 권한을 설정하며, 테이블을 생성하고 데이터를 삽입하는 과정에 대한 SQL 스크립트이다.
이 스크립트를 자세히 살펴보도록 하겠다.
- users라는 이름의 데이터베이스가 존재하지 않으면 새로 생성
CREATE DATABASE IF NOT EXISTS `users`;
- users 데이터베이스에 대한 모든 권한을 'dbuser'라는 사용자에게 부여
- 이 사용자는 localhost에서 접속하며, 비밀번호는 'dbpass'.
GRANT ALL PRIVILEGES ON users.* TO 'dbuser'@'localhost' IDENTIFIED BY 'dbpass';
- users 데이터베이스를 활성화하여 이후의 모든 작업이 이 데이터베이스에 대해 실행되도록 설정
USE `users;
- user라는 테이블을 생성
- idx 필드는 정수형이며 자동으로 증가(auto_increment)하고 기본 키(primary key)로 설정됨
- uid 필드는 사용자 ID로 varchar(128) 데이터 형식을 가지며, NULL 값을 허용하지 않음
- upw 필드는 사용자 비밀번호로 varchar(128) 데이터 형식을 가지며, NULL 값을 허용하지 않음
CREATE TABLE user(
idx int auto_increment primary key,
uid varchar(128) not null,
upw varchar(128) not null
);
- user 테이블에 세 개의 레코드를 삽입
- 첫 번째 레코드: uid가 'admin'이고 upw가 'DH{FLAG}'인 사용자가 추가됨
- 두 번째 레코드: uid가 'guest'이고 upw가 'guest'인 사용자가 추가됨
- 세 번째 레코드: uid가 'test'이고 upw가 'test'인 사용자가 추가됨
-> admin 유저의 upw를 알아야내야 하는 것 같다.
INSERT INTO user(uid, upw) values('admin', 'DH{**FLAG**}');
INSERT INTO user(uid, upw) values('guest', 'guest');
INSERT INTO user(uid, upw) values('test', 'test');
- 권한 변경 사항을 즉시 적용하여 MySQL 서버가 변경된 권한을 인식하도록 함
FLUSH PRIVILEGES;
서버를 생성한다.
그래도 1단계이니.. 혼자 힘으로 해보려고 나름 이런저런 시도들을 해보았으나 아무것도 되지 않았다.
그래서 질문을 보니 이러한 게 있었고 '에러를 일부러 발생시킨다.' 에 초점을 맞추어 풀어보도록 하겠다.
EXTRACTVALUE()를 사용해 user 테이블에서 upw 값을 추출하는 방법이다.
- SQL 인젝션을 이용해 데이터베이스의 응답 에러 메시지에 중요한 정보를 노출시키는 방식
1' : 이 부분은 user_input처럼 사용자가 입력할 수 있는 값으로, SQL 인젝션 공격에서 기존의 SQL 문을 닫는 역할을 한다. 쿼리가 닫히고 새로운 조건이 추가되도록 만들 수 있다.
and extractvalue() :
extractvalue() 함수는 원래 XML 데이터를 추출하는 데 사용되는 함수지만, 여기서는 에러 기반 SQL 인젝션을 유발하는 데 사용된다. 잘못된 XPath를 전달하여 데이터베이스 에러 메시지에 중요한 정보를 출력하게 하는 방식이다.
0x3a :
0x3a는 16진수로 : (콜론) 문자에 해당한다. 즉, 에러 메시지를 출력할 때 데이터 앞에 콜론을 붙여서 가독성을 높이기 위한 목적으로 사용된다.
concat(0x3a, ...) :
concat() 함수는 여러 문자열을 결합하는 함수이다. 여기서는 0x3a(16진수로 콜론 :에 해당)와 쿼리의 결과를 결합하려고 한다. 에러 메시지에 콜론과 함께 데이터를 출력할 수 있도록 한 것이다.
(SELECT upw FROM user LIMIT 0,1) :
이 서브쿼리는 user 테이블에서 첫 번째 레코드의 upw(비밀번호)를 선택하려고 한다.
- SELECT upw FROM user LIMIT 0,1:
user 테이블에서 첫 번째 사용자의 upw 값을 선택한다. LIMIT 0,1은 첫 번째 레코드만 반환하라는 의미이다.
이 쿼리는 첫 번째 사용자의 비밀번호(upw) 값을 추출한다.
1' and extractvalue(1,concat(0x3a,(SELECT upw FROM user LIMIT 0,1)));
위와 같이 입력을 하니 Flag 가 잘려서 출력된다.
질문들을 보았을 때 잘린다는 게 꽤 많았는데 나도 피해갈 수 없었나보다..
답변을 보면 xml 내장함수가 에러를 출력할 때 길이 제한을 갖고있기 때문이라고 한다,
-> 에러 출력시 32글자 제한이 있기에 substr과 같은 함수로 출력되는값을 잘 나누어 값을 얻어낸다.
1' and extractvalue(1,concat(0x3a,(SELECT substr(upw,29,20) FROM user LIMIT 0,1)));
SELECT substr(upw,29,20) FROM user LIMIT 0,1:
- substr(upw,29,20)는 upw(비밀번호)에서 29번째 문자부터 20자를 추출하려고 한다.
- 비밀번호 전체를 가져오는 대신, 비밀번호의 일부만 추출한다.
- 결과: 비밀번호의 일부만 추출할 수 있다.
위의 방법으로 시도했는데 이제는 방화벽 때문인지 사이트에 연결이 되지 않아 질문을 찾아보니 나와 같은 상황의 사람이 있어서 다른 네트워크 이것저것 시도해보았다. 그럼에도 연결되지 않아 혹시나 싶어 시크릿모드로 들어가보니 플래그를 확인할 수 있었다! 아직 1단계도 어떻게 풀어야 하는지 감이 잘 잡히지 않는 걸 보니 한참 더 공부를 많이 해야할 것 같다..
연결하면 -> DH{c3968c78840750168774ad951fc98bf788563c4d}
[참고]
'SWLUG > CTF' 카테고리의 다른 글
[CTF/ Dreamhack] weblog-1 (0) | 2024.10.30 |
---|---|
[WebHack][WebGoat] SQL Injection (intro) (3) | 2024.10.02 |
[CTF/ Dreamhack] blind sql injection advanced (0) | 2024.09.30 |
[CTF/ Dreamhack] CProxy: Inject (0) | 2024.09.25 |
[WebHack][Webhacking.kr] old-52 (1) | 2024.09.23 |