ChogeLog

主にセキュリティ関係の記録やWrite-up。たまーに日記も。

イベントID 1029に記録されるユーザー名に注意

Microsoft-Windows-TerminalServices-RDPClient/OperationalイベントID 1029に記録されるユーザー名について、単純には解析できなかったのでメモとして記録しておきます。

なお、本記事の内容は以下の記事とほぼ同じ内容なので、英語が得意な方はこちら👇を読むことをオススメします。

nullsec.us

イベントID 1029の概要

イベントID 1029は、RDP接続を試行する際に接続元の端末に記録されます。
記録される内容は下図の通りで、接続しようとしたユーザー名をハッシュ化&エンコードした値が記録されます。

イベントID 1029の例(元のユーザー名は「TEST」)

注意点として、存在しないユーザー名を入力した場合や、RDP接続に失敗した場合も記録されます。

イベントID 1029の解析

ログに Base64(SHA256(UserName)) is = … と記載されているので、ユーザー名のSHA256を計算した後にBase64エンコードすればこの値が生成されると考えられます。
ということで、先ほどの例で使用した「TEST」を計算してみます。

「TEST」をSHA256→Base64エンコード

…が、計算結果は
OTRlZTA1OTMzNWU1ODdlNTAxY2M0YmY5MDYxM2UwODE0ZjAwYTdiMDhiYzdjNjQ4ZmQ4NjVhMmFmNmEyMmNjMg==
となっており、イベントログに記録された値
zzV6ChUo2bTS/UpOyeSYs3PXpzH5m4DwLJuB+bpyHbY=
と明らかに異なります。

そこでイベントID 1029について調べてみたところ、どうやら実際は以下の流れで計算されていることが分かりました。

  1. ユーザー名をUTF-16LEエンコードする
  2. 1のSHA256を計算し、バイナリで出力する
  3. 2をBase64エンコードする

つまり、実際は Base64(SHA256binary(UTF-16LE(UserName)) と書いた方が正しいようです。( Base64(SHA256(UserName)) じゃ分からんやろ…)

ということで、 CyberChefBase64(SHA256binary(UTF-16LE(UserName)) を計算してみたところ、ログの値と同じ結果になりました🎉

Base64(SHA256binary(UTF-16LE(UserName))を計算した結果

Pythonの場合は以下のようなコードで計算可能です。

import hashlib
import base64

# 計算したいユーザー名
username = 'TEST'

# UTF-16LEにエンコード
utf16_username = username.encode('utf-16le')

# SHA256を計算し、バイナリ形式で取得
hash_username = hashlib.sha256(utf16_username).digest()

# Base64エンコード
base64_username = base64.b64encode(hash_username)

# UTF-8にデコード
result = base64_username.decode('utf-8')

print('ユーザー名: ' + username)
print('Base64(SHA256binary(UTF-16LE(UserName)) is = ' + result)

上記のコードを実行すると以下のように出力されます。

Pythonで計算した結果

まとめ

本記事ではMicrosoft-Windows-TerminalServices-RDPClient/OperationalのイベントID 1029に記録されるユーザー名の解析方法について紹介しました。
それにしても Base64(SHA256(UserName)) という表記はトラップすぎますね…。
ということで、イベントID 1029のユーザー名を解析する際はご注意ください。