Redis(Remote Dictionary Server)
레디스(Redis)는 "키-값" 구조의 비정형 데이터를 저장하고 관리하기 위한
오픈 소스 기반의 비관계형 데이터베이스 관리 시스템(DBMS)이다.
데이터를 string, list, set, hash, stored set, bitmap 형태로 저장할 수 있다.
레디스는 모든 데이터를 메모리에 저장하고 조회한다.
(인메모리 데이터베이스)
레디스는 지속성을 보장하기 위해 데이터를 DISK에 저장할 수 있다.
서버가 내려가더라도 DISK에 저장된 데이터를 읽어서 메모리에 로딩을 한다.
데이터를 DISK에 저장하는 방식은 크게 두 가지 방식이 있다.
RDB(Snapshotting) 방식 : 순간적으로 메모리에 있는 내용을 DISK에 전체를 옮겨 담는 방식
AOF (Append On File) 방식 : Redis의 모든 write/update 연산 자체를 모두 log 파일에 기록하는 방식
레디스에선 아래와 같은 명령어를 사용해 데이터 조작, DBMS 관리를 수행한다.
명령어 | 구조 | 설명 |
GET | GET key | 단일 데이터 조회 |
MGET | MGET key [key ...] | 여러 데이터 조회 |
SET | SET key value | 새로운 단일 데이터 추가 |
MSET | MSET key value [key value ...] | 새로운 여러 데이터 추가 |
DEL | DEL key [key ...] | 데이터 삭제 |
EXISTS | EXISTS key [key ...] | 데이터 유무 확인 |
INCR | INCR key | 데이터 값에 1을 더함 |
DECR | DECR key | 데이터 값에 1을 뺀다 |
INFO | INFO [section] | DBMS 정보 조회 |
CONFIG GET | CONFIG GET parameter | 설정 조회 |
CONFIG SET | CONFIG SET parameter value | 새로운 설정 입력 |
Redis 공격 기법
SSRF in Node JS redis module
Redis는 기본적으로 인증 수단이 존재하지 않으며"127.0.0.1"로 서비스를 바인딩하기 때문에
직접 접근하여 인증 과정 없이 명령어를 실행할 수 있다.
따라서 공격자는 SSRF 취약점을 통해 Redis 서버에 접근하여 DB의 정보를 획득할 수 있다.
또한, Redis는 유효하지 않은 명령어가 입력돼도 연결이 끊어지지 않고 다음 명령어를 실행한다.
대표적인 공격 기법으로는 HTTP 프로토콜을 이용한 방법이 있으며
이는 HTTP의 Body 데이터에 실행할 명령어를 포함시켜 요청을 전송한다.
애플리케이션에서 Redis 명령어가 포함된 Body 데이터를 처리할 때
"SET key value" 명령어가 Redis에서 실행된다.
Redis는 HTTP 프로토콜을 이용한 SSRF를 막고자
프로토콜에서 사용하는 주요 키워드가 명령어로 입력되면 연결을 끊어버려 공격이 불가능하도록 패치했지만
이는 HTTP 프로토콜을 이용한 공격만을 막기 때문에 다른 프로토콜을 이용한 공격에는 여전히 취약하다.
django-redis-cache (python)
직렬화(Serialize) : 객체 또는 데이터의 타입을 특정한 포맷을 가진 형태로 변환
역직렬화(Deserialize) : 직렬화된 데이터를 본래 객체 또는 데이터의 타입으로 되돌림
django-redis-cache는 Django에서 Redis를 사용한 캐시(Cache)를 구현할 수 있는 파이썬 모듈이다.
해당 모듈의 기본 Serializer는 PickleSerializer이다.
Redis에 임의의 데이터를 저장하고 해당 데이터를 Deserialize 할 수 있다면
Pickle 모듈을 이용해 공격을 수행할 수 있다.
(공격자는 역직렬화 과정을 악용하여 악의적인 행위를 수행하거나 특정 상황에서 호출되는 메소드를 이용해 공격 가능)
파이썬에서 직렬화와 역직렬화를 수행하는 대표적인 모듈로 pickle과 yaml이 존재한다.
pickle 모듈은 객체를 직렬화하여 파일에 저장할 수 있는 기능과 파일에 저장된 객체를 가져와 역직렬화하는 기능도 제공한다.
모듈의 공식 문서를 살펴보면 신뢰할 수 있는 데이터에 한해서 역직렬화를 수행하라는 경고문을 확인할 수 있다.
해당 모듈은 다양한 클래스 인스턴스를 제공하는데
이 중 object.__reduce__()는객체 계층 구조를 unpickling 할 때 객체를 재구성하는 튜플을 반환해주는 메소드로
호출 가능한 객체를 반환할 수 있다.
호출 가능한 객체에 system과 같이 명령어를 실행할 수 있는 함수를 반환하면 시스템 명령어를 실행할 수 있다.
Redis 명령어: SAVE
Redis는 인 메모리 데이터베이스 이다.
메모리는 휘발성이라는 특징을 갖고 있기 때문에
데이터 손실 방지를 위해 일정 시간마다 메모리 데이터를 파일 시스템에 저장한다.
Redis는 명령어를 이용해 메모리 데이터를 저장하는 파일의 저장 주기를 지정하거나 즉시 저장할 수 있으며
저장되는 파일의 경로, 이름, 저장할 데이터를 함께 설정할 수 있다.
Redis 명령어: SLAVEOF / REPLICAOF
다른 Redis의 노드를 현재 명령어를 실행하는 노드의 마스터 노드로 지정할 수 있다.
지정한 노드와 연결을 맺으면, 마스터 노드의 데이터를 복제하고 저장한다.
해당 명령어를 실행되면 마스터 노드에 네트워크 연결을 맺는다.
해당 과정에서 발생하는 네트워크 트래픽을 통해 Redis 공격의 성공 여부를 원격으로 확인할 수 있다.
포트를 바인딩하는 서버는 노드의 상태를 확인하기 위한 데이터를 수신한다.
Redis 명령어: MODULE LOAD
Redis 4.0 버전부터 새로운 라이브러리를 추가해 사용할 수 있도록 module load 명령어를 제공한다.
이용자는 RedisModuleSDK를 기반하여 공유 라이브러리를 제작하고
해당 명령어를 통해 라이브러리를 로드하여 임의 코드를 실행할 수 있다.
라이브러리를 업로드해 공격하기 위해서는
Redis 클라이언트가 접근할 수 있는 디렉터리에 라이브러리를 업로드 생성할 수 있어야 한다.
레퍼런스
https://ko.wikipedia.org/wiki/%EB%A0%88%EB%94%94%EC%8A%A4
https://kimpaper.github.io/2016/07/27/redis-datatype/
'background > web' 카테고리의 다른 글
Command Injection for Linux (2) (1) | 2022.11.27 |
---|---|
Command Injection for Linux (1) (0) | 2022.11.26 |
[NoSQL] CouchDB (0) | 2022.11.24 |
SSTI(Server Side Template Injection) (0) | 2022.09.29 |
XXE Injection 이해를 위한 XML 기초 지식 (0) | 2022.08.29 |