2023 FIESTA 금융보안 위협 분석 대회 #3 시나리오 - APT

2023. 10. 18. 21:38CTF

목차

01) 시나리오 - 랜섬웨어 1

02) 시나리오 - 공급망 공격 1, 2

03) 시나리오 - APT 1, 2

04) 시나리오 - 악성 앱 1, 2

05) 침해대응 - 문제 3


시나리오 - APT 1 (50+63 pts)

APT 1

EML Extractor 툴을 이용하여 .eml파일에서 첨부파일을 추출하였다.

https://github.com/diogo-alves/eml-extractor

 

GitHub - diogo-alves/eml-extractor: A python package to extract attachments from .eml files (email messages saved as files)

A python package to extract attachments from .eml files (email messages saved as files) - GitHub - diogo-alves/eml-extractor: A python package to extract attachments from .eml files (email messages...

github.com

 

$ eml-extractor --source ./output --destination ./out

추출한 파일을 명령어 cp ./out/*/*.zip ./extract/ 를 통해 zip파일만을 추출하였다.

 

- a.bash

for file in *.zip; do
        unzip "$file"
done
$ bash a.bash

스크립트 실행을 통해 일괄적으로 압축 해제한 결과 exe 파일과 docx 파일을 추출할 수 있었다.

$ mv ./*.exe ../result
$ mv ./*.docx ../result

그 결과 exe 파일 6개와 docx파일 279를 획득하였고 exe 파일 중 becauseq1af2332.exe 가 플래그에 해당하는 악성코드임을 알 수 있었다.

$ shasum -a 256 becauseq1af2332.exe

악성코드의  sha256  확인

 

fiesta{bcb10a8e6250ecb142932ba59cbe94e47f2e143564df1886a5838317bc275b40}

시나리오 - APT 2 (250+90 pts)

APT 2

1 문제를 통해 알아낸 악성코드를 디컴파일 IDA 확인한 결과 해당 악성코드는 go언어로 작성, 컴파일되었기 때문에 바로 분석이 어려웠다.

따라서 IDA python 스크립트 기능을 통해 go parser 플러그인을 사용하여 분석했다.

 https://github.com/0xjiayu/go_parser

 

GitHub - 0xjiayu/go_parser: Yet Another Golang binary parser for IDAPro

Yet Another Golang binary parser for IDAPro. Contribute to 0xjiayu/go_parser development by creating an account on GitHub.

github.com

패킷을 분석 결과, 악성코드는 http 통신을 이용해 암호화된 값을 전송한다.

악성코드 통신 패킷

 

http 통신을 보내는 함수인 mineral_operator__Server_Handshake (0x000066C5A0)data를 암호화하는 로직이 존재한다.

 

time_Now() 함수를 통해 컴퓨터의 실제 시간을 이용하여 아래와 같은 루틴으로 키를 생성한다.

mineral_operator__Server_ Handshake (0x66C5A0)

 

컴퓨터의 현재 시간을 제외하고 피해자 컴퓨터 정보를 포함한 연산이 없기 때문에, 문제에서 주어진 패킷 시간으로 컴퓨터 시간을 조절 동적 디버깅을 통해 획득이 가능하다.

 

생성 이후, 공격 서버와의 공유를 위해 json 형식으로 인코딩한 키를 아래와 같은 로직을 이용해 암호화 공격 서버에 전송한다. v83[3], v83[4] 값이 연산에 사용되는데, 초기 값은 0, 256이다.

mineral_operator__Server_Handshake (0x66C5A0)

 

서버에서 응답 값을 받은 , 복호화 과정을 거친다. 복호화 과정은 암호화 로직과 같다.

mineral_operator_SendResult (0x66d260)

v83[3] timeNow() 이용하여 생성한 키와 상수 255 사용된다. 복호화 결과, 공격 서버 쪽에서의 키를 획득할 있다.

 

교환 이후에 발생하는 통신에 대해서는 피해자 컴퓨터에서 생성한 키와, 공격자 서버에서 생성한 이용하여 암호화한다.

 

도메인 복호화/암호화하기 위해 사용되는 키는 아래 표와 같다.

도메인 1 2 암호화 내용
QyODUwZD.php 0 255 피해자 컴퓨터 키
QyODUwZD.php의 응답 피해자 컴퓨터 키 255 공격자 서버 키
mZTcxMjU.php 피해자 컴퓨터 키 공격자 서버 키 컴퓨터 파일

 

악성파일은 C:\flag.txt를 공격 서버로 전송한다.

flag.txt의 크기가 작을 것이라는 가정하에, 패킷 중 길이가 작은 패킷부터 복호화를 진행했고, 플래그를 획득했다.

 

- decrypt.py

real = [0x0c, 0x10, 0xed, 0x0e, 0x85, 0x9d, 0x91, 0xe2, 0xc5, 0x64, 0x22, 0x8a, 0xf7, 0x27, 0x7e, 0x6a, 0xb8, 0x82, 0xe9, 0x3a, 0x0b, 0xaa, 0x49, 0xfa, 0x94, 0x52, 0xff, 0xad, 0x7b, 0x64, 0x20, 0x83, 0x67, 0x7b, 0x6d, 0xd3, 0x80, 0x7c, 0xea, 0x12, 0xa7, 0x8d, 0x2a, 0xc6, 0x5c, 0x14, 0x68, 0x3b, 0xb9, 0x2f, 0x35, 0xff, 0x38, 0xa5, 0xe0, 0x2c, 0xfa, 0xef, 0xcc, 0xc8, 0xf8, 0x1b, 0xf1, 0x50, 0xef, 0x0a, 0xb1, 0xbe, 0xdf, 0x7f, 0xc5, 0xce] # {"1":3230992749343881762,"2":"e67cfe09-4863-4ac1-9b7b-28ec70f78166"}
real = [0x88, 0x05, 0x54, 0x46, 0x67, 0xa4, 0x2d, 0xee, 0xbe, 0x59, 0x89, 0xb6, 0xb5, 0x21, 0x5f, 0x7a, 0xd0, 0x01, 0xa4, 0xd5, 0x1d, 0x84, 0x72, 0x52, 0xca, 0x05, 0xbd, 0xe8, 0x25] # real
real = [0xb7, 0x23, 0x42, 0x6f, 0xaf, 0xae, 0x5a, 0xf4, 0x8f, 0x7a, 0xd7, 0x55, 0x61, 0xb6, 0xc0, 0x0d, 0x0b, 0x55, 0xc9, 0x06, 0x02, 0xf3, 0xe6, 0x8c, 0x61, 0xb7, 0x1e, 0xef, 0xbd, 0xae, 0xab, 0xfd, 0x07, 0x61, 0xf5, 0xad, 0x8c, 0x29, 0xfe, 0x90, 0xff, 0x79, 0xf1, 0x49, 0x9b, 0x18, 0xb3, 0xc6, 0x1c, 0x00, 0xd4, 0x2a, 0x33, 0x24, 0xbb, 0x90, 0x4c, 0x8f, 0xad, 0x6d, 0xba, 0xa0, 0x60, 0x66, 0xae, 0xe0, 0x69, 0x4c, 0x6e, 0xd9, 0x98, 0x95, 0x41, 0x92, 0xfe, 0x44, 0xce, 0x22, 0x3c, 0x92, 0x87, 0xf9, 0x5c, 0xe6, 0x3d, 0xff, 0xc6, 0x6c, 0x04, 0x1f, 0xd8, 0xb0, 0x1f, 0x86, 0xe3, 0x37, 0x52, 0x9e, 0xbd, 0xa8, 0x62, 0xba, 0xa6, 0xa3, 0xfe, 0x5e, 0xb2, 0x8c, 0x44, 0x10, 0x6a, 0xd7, 0x2e, 0x69] # {"1":4,"2":"Zmllc3Rhe2I2ZTllNGY4N2JlZmJlZTQxMzA5ZGQxYjc4NzNkZjZjMzhkZDA2ZTA0YjAwNTgzZTVhZGNhNzc4Y2MzYTRmOTZ9"}

All = real
v34 = len(All) - 4
print(hex(v34))
v35 = [1, 2, 3 ,4, 5]
v35[3] = 3230992749343881762
v35[4] = 9122131998151730639
for j in range(v34):
    v37 = ((v35[3] << 23) & 0xffffffffffffffff) ^ v35[3]
    v38 = v35[4]
    v39 = ((v37 >> 17) ^ v37) ^ v38
    v40 = v38
    v41 = v39 ^ (v38 >> 26)
    v35[3] = v40 & 0xffffffffffffffff
    v35[4] = v41
    All[j + 4] ^= ((v41 & 0xFF) + (v40 & 0xFF) & 0xff)


for i in All[4:]:
    print(chr(i), end = "")

decrypt.py 실행 결과 화면

- 결과값

Zmllc3Rhe2I2ZTllNGY4N2JlZmJlZTQxMzA5ZGQxYjc4NzNkZjZjMzhkZDA2ZTA0YjAwNTgzZTVhZGNhNzc4Y2MzYTRmOTZ9

Base64 디코딩

fiesta{b6e9e4f87befbee41309dd1b7873df6c38dd06e04b00583e5adca778cc3a4f96}