티스토리 뷰

728x90
반응형

문제 설명

SecCorp has reached us about a recent cyber security incident. They are confident that a malicious entity has managed to access a shared folder that stores confidential files. Our threat intel informed us about an active dark web forum where disgruntled employees offer to give access to their employer's internal network for a financial reward. In this forum, one of SecCorp's employees offers to provide access to a low-privileged domain-joined user for 10K in cryptocurrency. Your task is to find out how they managed to gain access to the folder and what corporate secrets did they steal.

 

이번 문제는 capture.pcapng 파일 하나만 주어진 문제였습니다. 2022년도 Hackthebox CTF 문제 중 Forensics 분야의 Medium 난이도 문제입니다.

 

문제 풀이

주어진 문제 파일은 network packet 캡쳐파일 하나뿐이었기에 분석을 해보면 우선 TCP 패킷이 보입니다.

내용을 보니 공격자가 로컬 PC에 침입을 한 것처럼보이는데요. 들어오자마자 어떤 계정으로 접속하였는지 확인을 하더니 관리자 권한을 가지고 있는지도 확인하고 있습니다. 그러곤 바로 powershell 코드로 comsvcs.dll 로 lsass 프로세스에 대한 minidump 를 뜨고, ftp 로 해커의 서버에 방금 뜬 minidump 파일을 전송하고 있는 것이 보입니다.

 

그렇기에 네트워크 패킷 순서상 그 다음엔 바로 FTP 통신이 있음을 알 수 있습니다.

그리고 공격자의 ftp 서버로 업로드하고 있는 파일의 이름은 3858793632.zip 인 걸 알 수 있습니다. 실제로 공격자가 덤프한 파일의 내용물을 캡쳐된 패킷 내용을 가지고서 확인해볼 수 있습니다. FTP-DATA 프로토콜로 정의된 패킷들을 하나하나 조합해서 export 하면 됩니다.

 

그렇게 완성된 zip파일의 내용물에는 3858793632.pmd 이름의 덤프파일이 있었습니다. 뒤에 확장자는 pmd 라고 되어 있는데 사실 중요하지 않고 파일헤더가 중요합니다. MDMP 라는 파일 시그니쳐가 보입니다.

┌──(vagrant㉿kali)-[/mnt/HTB/forensics_rogue]
└─$ file 3858793632.dmp
3858793632.dmp: Mini DuMP crash report, 13 streams, Mon Jul  4 11:39:18 2022, 0x6 type

 

이렇게 아까 위에서 공격자가 처음으로 수행한 결과물인 덤프파일을 획득하였습니다. 이제는 무엇을 하면 될지 네트워크 패킷의 흐름을 더 분석해보겠습니다.

 

어느 순간부터 SMB3 패킷으로 로컬 도메인인 CORP-DC 에 CORP\athomson 계정으로 ConfidentialShare 라는 파일 또는 디렉토리에 접근하고 있는 것을 볼 수 있습니다. 그리고 그 이후의 행위에 대해서는 SMB3 Encrypted 되어서 자세한 내용을 볼 수 없었는데요.

그래서 SMB3 Encrypted 패킷을 복호화하기 위해서 필요한 것은 무엇인지 알아보았습니다.

https://social.msdn.microsoft.com/Forums/en-US/689077f5-207e-495c-aece-01e345ebb80c/ntlmv2-session-key?forum=os_fileservices 

 

NTLMv2 Session Key

Oh, sorry, I didn't notice that, as username was different to PCAP, small letters vs big, so I thought it was different data. Thanks. But still, still I don't get it. As now we get the encrypted random session key from PCAP, we should therefore decrypt it

social.msdn.microsoft.com

위 글을 읽어보니깐 몇가지 조합을 알면 SMB3 Encrpyted 패킷을 복호화할 수 있을 것 같았습니다.

우선 username, domain, password hash, NTProofStr, Encrypted Session Key를 알아야 하는데, 현재 password hash 를 제외하면 모두 wireshark 패킷을 통해서 알 수 있는 상황입니다.

user= "athomson" 
domain= "CORP"
password_hash = ""
NTProofStr = "d047ccdffaeafb22f222e15e719a34d4"
EncryptedSessionKey = "032c9ca4f6908be613b240062936e2d2"

ResponseKeyNT = HMAC_MD5(password_hash, (user.upper()+domain.upper()).encode('utf16-le'))
KeyExchangeKey = HMAC_MD5(ResponseKeyNT, NTProofStr)
RandomSessionKey = RC4(KeyExchangeKey,EncryptedSessionKey)

 

password hash 의 경우에는 원래라면 Windows 계정의 실제 비밀번호를 알아야 하는데, 그러기 위해서는 알기 쉬운 비밀번호가 아니라면 크래킹하는 수밖에 없습니다. 하지만 이번 경우에서는 정확한 패스워드를 알 필요 없이 단지 password hash 그 자체만으로도 유용하게 사용될 수 있기 때문에 정말 다행인 케이스입니다.

 

lsass.dmp 는 lsass 프로세스를 minidump 한 것이기 때문에 Windows의 credential 정보가 포함되어 있습니다. 이는 여러 도구로 추출할 수 있는데 저는 그 중 유명한 도구인 mimikatz 를 이용해보았습니다.

  .#####.   mimikatz 2.2.0 (x64) #19041 Aug 10 2021 17:19:53
 .## ^ ##.  "A La Vie, A L'Amour" - (oe.eo)
 ## / \ ##  /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
 ## \ / ##       > https://blog.gentilkiwi.com/mimikatz
 '## v ##'       Vincent LE TOUX             ( vincent.letoux@gmail.com )
  '#####'        > https://pingcastle.com / https://mysmartlogon.com ***/

mimikatz(commandline) # sekurlsa::minidump lsass.dmp
Switch to MINIDUMP : 'lsass.dmp'

mimikatz(commandline) # sekurlsa::logonPasswords
Opening : 'lsass.dmp' file for minidump...

Authentication Id : 0 ; 6361112 (00000000:00611018)
Session           : Interactive from 3
User Name         : rpaker
Domain            : WS02
Logon Server      : WS02
Logon Time        : 2022-07-04 오후 8:37:24
SID               : S-1-5-21-900241500-1566882183-2274020907-1001
	msv :	
	 [00000003] Primary
	 * Username : rpaker
	 * Domain   : WS02
	 * NTLM     : a9fdfa038c4b75ebc76dc855dd74f0da
	 * SHA1     : 9400ae28448e1364174dde269b2cce1bca9d7ee8
	tspkg :	
	wdigest :	
	 * Username : rpaker
	 * Domain   : WS02
	 * Password : (null)
	kerberos :	
	 * Username : rpaker
	 * Domain   : WS02
	 * Password : (null)
	ssp :	
	credman :	
	cloudap :	KO

Authentication Id : 0 ; 3857660 (00000000:003adcfc)
Session           : RemoteInteractive from 2
User Name         : athomson
Domain            : CORP
Logon Server      : CORP-DC
Logon Time        : 2022-07-04 오후 8:32:10
SID               : S-1-5-21-288640240-4143160774-4193478011-1110
	msv :	
	 [00000003] Primary
	 * Username : athomson
	 * Domain   : CORP
	 * NTLM     : 88d84bad705f61fcdea0d771301c3a7d
	 * SHA1     : 60570041018a9e38fbee99a3e1f7bc18712018ba
	 * DPAPI    : 022e4b6c4a40b4343b8371abbfa9a1a0
	tspkg :	
	wdigest :	
	 * Username : athomson
	 * Domain   : CORP
	 * Password : (null)
	kerberos :	
	 * Username : athomson
	 * Domain   : CORP.LOCAL
	 * Password : (null)
	ssp :	
	credman :	
	cloudap :	KO

 

쭉 여러 정보들이 나오는데 그 중 저희가 필요한 계정인 athomson 의 NTLM hash 값만 추출해옵니다.

 

이제 바로 Python 코드로 작성해보겠습니다. 참고한 원본 코드는 아래와 같습니다.

https://gist.github.com/khr0x40sh/747de1195bbe19f752e5f02dc22fce01

 

Random Session Key calculator based off of data from a packet capture

Random Session Key calculator based off of data from a packet capture - random_session_key_calc.py

gist.github.com

 

import hashlib
import hmac
import argparse

# stolen from impacket. Thank you all for your wonderful contributions to the community
try:
    from Cryptodome.Cipher import ARC4
    from Cryptodome.Cipher import DES
    from Cryptodome.Hash import MD4
except Exception:
    LOG.critical(
        "Warning: You don't have any crypto installed. You need pycryptodomex")
    LOG.critical("See https://pypi.org/project/pycryptodomex/")


def generateEncryptedSessionKey(keyExchangeKey, exportedSessionKey):
    cipher = ARC4.new(keyExchangeKey)
    cipher_encrypt = cipher.encrypt

    sessionKey = cipher_encrypt(exportedSessionKey)
    return sessionKey
###


parser = argparse.ArgumentParser(
    description="Calculate the Random Session Key based on data from a PCAP (maybe).")
parser.add_argument("-u", "--user", required=True, help="User name")
parser.add_argument("-d", "--domain", required=True, help="Domain name")
parser.add_argument("-p", "--password", required=True, help="Password of User")
parser.add_argument("-n", "--ntproofstr", required=True,
                    help="NTProofStr. This can be found in PCAP (provide Hex Stream)")
parser.add_argument("-k", "--key", required=True,
                    help="Encrypted Session Key. This can be found in PCAP (provide Hex Stream)")
parser.add_argument("-v", "--verbose", action="store_true",
                    help="increase output verbosity")

args = parser.parse_args()

# Upper Case User and Domain
user = str(args.user).upper().encode('utf-16le')
domain = str(args.domain).upper().encode('utf-16le')

# Create 'NTLM' Hash of password
#passw = args.password.encode('utf-16le')
#hash1 = hashlib.new('md4', passw)
#password = hash1.digest()
password = bytes(bytearray.fromhex('88d84bad705f61fcdea0d771301c3a7d'))

# Calculate the ResponseNTKey
h = hmac.new(password, digestmod=hashlib.md5)
h.update(user+domain)
respNTKey = h.digest()

# Use NTProofSTR and ResponseNTKey to calculate Key Excahnge Key
NTproofStr = args.ntproofstr.decode('hex')
h = hmac.new(respNTKey, digestmod=hashlib.md5)
h.update(NTproofStr)
KeyExchKey = h.digest()

# Calculate the Random Session Key by decrypting Encrypted Session Key with Key Exchange Key via RC4
RsessKey = generateEncryptedSessionKey(KeyExchKey, args.key.decode('hex'))

if args.verbose:
    print "USER WORK: " + user + "" + domain
    print "PASS HASH: " + password.encode('hex')
    print "RESP NT:   " + respNTKey.encode('hex')
    print "NT PROOF:  " + NTproofStr.encode('hex')
    print "KeyExKey:  " + KeyExchKey.encode('hex')
print "Random SK: " + RsessKey.encode('hex')

원본 코드에서는 password 를 대입하여 hash 해서 사용하지만 저는 hash 값을 그대로 password에 대입하여 사용하였습니다. 이제 드디어 SMB3 Encrypted 복호화에 사용될 Random Session Key를 구해보겠습니다.

┌──(vagrant㉿kali)-[/mnt/HTB_Business/forensics_rogue]
└─$ python calc.hash.py -u athomson -d CORP -n d047ccdffaeafb22f222e15e719a34d4 -k 032c9ca4f6908be613b240062936e2d2 -p test
Random SK: 9ae0af5c19ba0de2ddbe70881d4263ac

우와 드디어 Ransom Session Key가 구해졌습니다.

 

이제 Session Id 값과 위 값으로 암호화된 SMB3 패킷을 복호화해보겠습니다.

위와 같이 Edit -> Preferences 메뉴를 눌러서 Protocols 목록에서 SMB2 를 선택하고 Edit 버튼을 눌러 Session ID 에 맞는 Session Key를 넣어주면, 아래와 같이 Decrypted SMB3 패킷들을 볼 수 있습니다. (Session ID 는 Endian 방식을 잘 지켜주어야 합니다.)

그리고 아래 패킷을 보면 드디어 회사 기밀 정보 중 customer_information.pdf 라는 파일을 훔쳐가고 있는 것을 목격할 수 있습니다.

이제 SMB 프로토콜에서 주고받은 파일을 보기 위해서 아래와 같이 메뉴를 따라가서 눌러줍니다.

그러면 2개의 파일이 나오는데 기밀정보로 보이는 pdf 파일만 추출해서 가져와서 읽어봅니다.

그러면 이렇게 아래와 같이 pdf 파일을 볼 수 있고, 파일 내용 중에는 Flag 내용이 포함되어져 있음을 볼 수 있습니다.

이렇게 문제를 다 풀어볼 수 있었고, 실제로 악성코드를 통해서 공격자가 회사 PC에 접근해서 어떤 행동을 했는지 유추해볼 수 있고 가상으로 추적해볼 수 있는 재밌는 문제였던 것 같습니다.

 

아래는 유사하지만 조금은 다른 참고하기 좋은 다른 CTF 문제의 풀이입니다.

https://medium.com/maverislabs/decrypting-smb3-traffic-with-just-a-pcap-absolutely-maybe-712ed23ff6a2

 

Decrypting SMB3 Traffic with just a PCAP? Absolutely (maybe.)

TL;DR: Given just a PCAP of an SMB3 session, the encrypted SMB3 could be decrypted by cracking the NetNTLMv2 hash and computing the Random…

medium.com

 

- 끝 -

728x90
반응형
댓글