次のように、シェルに関するいくつかの情報を出力するスクリプトがあります。
field1: value1
field2: value2
...
fieldn: valuen
これらのフィールド/値は次のとおりです。
CmdLine: C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe -EncodedCommand <base64_encodedcommand>
エンコードされたコマンドは非常に大きくなる可能性があるため(たとえば、2つの大きな端末画面以上)、これを処理する方法を探していました。私が時間をかけていることは次のとおりです。
command_that_generates_strings | awk '{for (i=1;i<=NF;i++) if (tolower($i) ~/^-encodedcommand/) {i++; "echo "$i" | base64 -d | iconv -f UTF-16LE -t UTF8 | grep -i <specific_identifier_here> | sed -E \"s#.+#<better_identifier_here#g\"" | getline x; print x} else {print $i}}'
読みやすさのために:
command_that_generates_strings | awk '{
for (i=1;i<=NF;i++)
if (tolower($i) ~/^-encodedcommand/) {
i++; "echo "$i" |
base64 -d |
iconv -f UTF-16LE -t UTF8 |
grep -i <specific_identifier_here> |
sed -E \"s#.+#<better_identifier_here#g\"" |
getline x; print x
} else {print $i}}'
(はい、iconv
その理由は、悪いことにbase64コンテンツがgrepが好きではないutf16le形式だからです。私はこれをbashとzshの両方で「反成功的に」実行しました)
CmdLine: yaddayadda
しかし、期待どおりに正しく動作しません。に置き換えるのではなく、エンコードさ<better_identifier_here>
れたコマンドを置き換えて他のすべてを分離し、何らかの方法で出力を次のように並べ替えるようです。
A-string
B-string
C-string
CmdLine:
C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe
D-string
EncodedCommand
...
N-string
<better_identifier_here>
...
Y-string
Z-string
0-string
1-string
...
(上記の「EncodedCommand」は、コマンドラインのbase64エンコーディングコマンドではなく、実際の文字列です。)
たぶん私が探しているものを達成するためのもう一つのより良い方法がありますか?予想される結果は次のとおりです。
field1: value1
field2: value2
...
<better_identifier_here>
...
fieldn: valuen
- ここでより有用な例を見てみましょう。
入力する:
field1: value1
field2: value2
...
CmdLine: C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe -EncodedCommand PABpAG4AcwBlAHIAdAAgAHAAbwB3AGUAcgBzAGgAZQBsAGwACgBtAHUAbAB0AGkAbABpAG4AZQAKAHMAYwByAGkAcAB0AAoAaABlAHIAZQAgAC0AIABpAHQAJwBsAGwAIABiAGUAIABlAG4AYwBvAGQAZQBkACAAYQBzACAAdQB0AGYAMQA2AGwAZQAKAGEAbgBkACAAdABoAGUAbgAgAGUAbgBjAG8AZABlAGQAIABpAG4AIABiAGEAcwBlADYANAA+AA==
...
fieldn: valuen
"be encoded"
これにより、文字列がエンコードされたコマンドの一部であることを認識し、「CmdLine」行全体を「エンコードされたペイロードの検出」に置き換えることができるようになります。
サンプル出力は次のとおりです。
field1: value1
field2: value2
...
Encoded payload found.
...
fieldn: valuen
答え1
あなたが欲しいとしましょう:
-encodedcommand
(大文字と小文字を区別しない)Base64でエンコードされたデータの後にスペースがある項目を探します。- 複数行の UTF16-LE エンコード文字列とみなされるものとしてデコードします。
- UTF16-LEをデコードして実際のテキストを取得します。
- パターン(大文字と小文字を区別しない)に一致するデコードされたテキストの行を新しい行に置き換えます。
- 結果を再びUTF16-LEにエンコードします。
- そしてbase64を返します。
これにより、次のことができます。
your-cmd | perl -MMIME::Base64 -MEncode -pe '
s{\s-encodedcommand\s+\K\S+}{
encode_base64(
encode(
"UTF16LE",
decode(
"UTF16LE",
decode_base64($&)
) =~ s/^.*bad content.*$/new better content/mgir
), ""
)
}gie'
はい。そしてyour-cmd
:
echo 'CmdLine: ... -EncodedCommand MQANAAoAMgANAAoAMwANAAoANAANAAoA'
MQANAAoAMgANAAoAMwANAAoANAANAAoA
出力はUTF16-LEエンコードでbase64にエンコードされますseq -f $'%g\r' 4
。
これをMSDOS行区切り文字を使用してs/^3\r$/new\r/mgir
1に置き換えると、次のようになります。3
new
CmdLine: ... -EncodedCommand MQANAAoAMgANAAoAbgBlAHcADQAKADQADQAKAA==
どこ:
echo MQANAAoAMgANAAoAbgBlAHcADQAKADQADQAKAA== |
base64 -d |
hexdump -C
以下を提供します。
00000000 31 00 0d 00 0a 00 32 00 0d 00 0a 00 6e 00 65 00 |1.....2.....n.e.|
00000010 77 00 0d 00 0a 00 34 00 0d 00 0a 00 |w.....4.....|
0000001c
Microsoftのバージョンを識別できる場所
1
2
new
4
明示的に要求されたようにエンコードされたテキストから文字列のみを検出し、文字列がある場合は行全体をデコードされたコンテンツ(おそらくUTF-8でエンコードされている)に置き換えたい場合
your-cmd | perl -MMIME::Base64 -MEncode -pe '
if (/^\s*cmdline:.*\s-encodedcommand\s+(\S+)/i) {
$text = decode("UTF16LE", decode_base64($1));
if ($text =~ /encoded as/) {
$_ = encode("UTF-8", "$text\n");
# or "$text\r\n" if meant to be DOS-style or:
# $_ = "Encoded payload found\n";
}
}'
(1行に1つしかないと仮定します-encodedcommand
。多くの場合、最後の項目のみが考慮されます。最初の項目を考慮するにはに.*
置き換えます.*?
。)
サンプルでは、以下を提供します。
field1: value1
field2: value2
...
<insert powershell
multiline
script
here - it'll be encoded as utf16le
and then encoded in base64>
...
fieldn: valuen
1デフォルトでは、Perlは入力をISO8859-1(latin1とも呼ばれる)エンコードとして扱います。扱っている部分はASCIIなので違いはなく、少なくともlatin1ではデコードの問題は発生しません。 UTF-8の場合は、その-C
オプションを追加しperl
てそのencode("UTF-8"...)
部分をスキップできます。
バイト順の表示はUTF-8の一部ではありませんが、時にはMicrosoftファイルにあります。この場合、CmdLine
最初の行にある場合、/^\s*cmdline.../i
先頭にU + FEFF BOM文字があるため、正規表現は一致しません。その後、行の先頭にオプションのU + FEFF文字を受け入れる-C
ように正規表現を渡して変更できます。/^\x{feff}?\s*cmdline.../i
答え2
これまで動作しているように見える唯一の解決策は、エンコードコマンドがUTF16LEであることを受け入れ、\u0000
コンテンツを生成するスクリプトの検索にnullバイトを手動で含めることです。jq
上記の例では、(within)のように-EncodedCommand
大文字と小文字、またはの可能性を検討してください。-encodedcommand
jq
restofjq |
if(if((split(" ")[1] | ascii_downcase)=="-encodedcommand")
then (
split(" ")[2] |
@base64d |
test("\u0000b\u0000e\u0000 \u0000e\u0000n\u0000c\u0000o\u0000d\u0000e\u0000d\u0000")
) else empty end
) then "Encoded payload found!" else empty end
(読みやすいように改行を追加しました。)
split(" ")
split(" ")[0]
実際にエンコードされたコマンド-EncodedCommand
は、次のようにpowershellコマンドラインを作成します。split(" ")[1]
split(" ")[2]
コンテンツがUTF16LEにあるため、そうしよ@base64d | test("be encoded")
うとすると、UTF16LEにNULL値があるため失敗します。これにより、be encoded
エンコードコマンドでコンテンツが見つかると、フィールドは次のように出力されます。Encoded payload found!