記号と1,2,A,zでだけで作る難読化シェル芸

これはひどいw
kanataほぼ7年前に追加

結果

A=$(. 2>&1);A=${A##*.};${A:$((++z*++z*++z*z-z+++z)):$((z=z^z||++z))}${A:$((++z*++z---z)):$((z=z^z||++z))}${A:$((++z*++z*z)):$((z=z^z||++z))} -- {z..A};${@:$((++z*++z*++z---z+++z---z+++z---z)):$((z=z^z||++z))}${@:$((++z*++z*++z---z+++z---z+++z)):$((z=z^z||++z))}${@:$((++z+++z+--z)):$((z=z^z||++z))}${@:$((++z*++z*++z---z+++z---z)):$((z=z^z||++z))}

ちゃんとdateが実行される

$ A=$(. 2>&1);A=${A##*.};${A:$((++z*++z*++z*z-z+++z)):$((z=z^z||++z))}${A:$((++z*++z---z)):$((z=z^z||++z))}${A:$((++z*++z*z)):$((z=z^z||++z))} -- {z..A};${@:$((++z*++z*++z---z+++z---z+++z---z)):$((z=z^z||++z))}${@:$((++z*++z*++z---z+++z---z+++z)):$((z=z^z||++z))}${@:$((++z+++z+--z)):$((z=z^z||++z))}${@:$((++z*++z*++z---z+++z---z)):$((z=z^z||++z))}
20171218日 月曜日 19:00:55 JST

使ってる文字種は…

$ echo 'A=$(. 2>&1);A=${A##*.};${A:$((++z*++z*++z*z-z+++z)):$((z=z^z||++z))}${A:$((++z*++z---z)):$((z=z^z||++z))}${A:$((++z*++z*z)):$((z=z^z||++z))} -- {z..A};${@:$((++z*++z*++z---z+++z---z+++z---z)):$((z=z^z||++z))}${@:$((++z*++z*++z---z+++z---z+++z)):$((z=z^z||++z))}${@:$((++z+++z+--z)):$((z=z^z||++z))}${@:$((++z*++z*++z---z+++z---z)):$((z=z^z||++z))}'|grep -o .|sort -u|tr -d '\n'
 #$&()*+-.12:;=>@A^z{|}

#$&()*+-.12:;=>@A^z{|} だけ。理論上はこれで何でも書ける。

解説

基本原理

こんな感じで変数展開を駆使する

$ a="abcdefghijklmnopqrstuvwxyz"
$ ${a:3:1}${a:0:1}${a:19:1}${a:4:1}
2017年 12月 17日 日曜日 17:24:21 JST

それでは、実際に順を追ってやってみましょう。

記号と1,2だけでアルファベットを得る

記号だけでアルファベット得るには、以下のエラーメッセージを使います。

$ .
-bash: .: ファイル名が引数として必要です
.: 使用法: . filename [arguments]

エラーメッセージは、標準エラー出力の方にでるので標準出力に向けるよう1と2を使ってリダイレクトします。
(この後1と2は使いません)
編集結果は変数に入れます。Aとzしか使えない縛りなので、ここではAを使います。

$ A=$(. 2>&1);
$ echo $A
-bash: .: ファイル名が引数として必要です .: 使用法: . filename [arguments]

使っているディストリや言語環境でメッセージが異なったりします。
そのため、変数展開で変化のない箇所だけ取り出します。

$ A=${A##*.};
$ echo $A
filename [arguments]

アルファベットaefgilmnrstuを得ることができました。
これからコマンドを実行するには、bashの 変数展開を使います。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
f i l e n a m e [ a r g u m e n t s ]

変数展開を利用すると、この文字列を切り出すsubstringのような機能を実現できます。この配列からlsの実行は、以下でできます。

${A:3:1}${A:19:1}

さて、このままだと使えるアルファベットが限定されています。dateもできませんし、echo,grep...よく使うコマンドも大半が利用できません。なんとか使えるアルファベットを増やす必要があります。

ブレース展開でアルファベット小文字を得る

使えるアルファベットを増やすには、ブレース展開を使うのがよさそうです。Aとzだけでアルファベットを全て得られます。

$ echo {A..z}
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [  ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z

これを変数に入れればいいですね。ただ直接入れられません。echoとかで出力した結果を変数に入れる必要があります。
あ。。。echoが使えませんね。使えるアルファベット(aefgilmnrstu)からechoの代替を探しましょう。

正解は・・・!これ

$ set -- {z..A}

さっきの変数展開を駆使して、setを実行します。実行結果は、なんと位置パラメータに入る仕様です。

$ ${A:19:1}${A:4:1}${A:18:1} -- {z..A}
$ echo $@
z y x w v u t s r q p o n m l k j i h g f e d c b a ` _ ^ ] [ Z Y X W V U T S R Q P O N M L K J I H G F E D C B A

やったね!これでdateも実行できるはずです。試してみます。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
z y x w v u t s r q p o n m l k j i h g f e d c b a ` _ ^ ] [ Z Y X W V U T S R Q P O N M L K J I H G F E D C B A
$ ${@:23:1}${@:26:1}${@:7:1}${@:22:1}
20171218日 月曜日 19:22:14 JST

できましたね!まだ終わりじゃないです。

数字使っている所をなんとかする

まだ数字が入っている所がありますね。
これを何とかしましょう。もう一つの文字zをここで変数として使います。

算術式展開 を使います。数字を一切使わずに目的の数値を計算して出力します。

しんどいのは、一度計算に利用した変数zは、0に戻ることもなく、そのまま次の処理に引き継がれることです。

こんな感じで計算しておりますが、前提として変数zの初期値が1であったり、0であったりする必要があります。

$((z=z^z))                           #  0 自分自身でXORすると0になる。何回実行しても0。
$((z=z^z||++z))                      #  1 なんかよくわかんないけど1になる。何回実行しても1。
$((++z*++z---z))                     #  4 変数zの初期値が1前提
$((++z+++z+--z))                     #  7 変数zの初期値が1前提
$((++z*++z*z))                       # 18 変数zの初期値が1前提
$((++z*++z*++z*z-z+++z))             # 19 変数zの初期値が0前提
$((++z*++z*++z---z+++z---z))         # 22 変数zの初期値が1前提
$((++z*++z*++z---z+++z---z+++z---z)) # 23 変数zの初期値が1前提
$((++z*++z*++z))                     # 24 変数zの初期値が1前提
$((++z*++z*++z---z+++z---z+++z))     # 26 変数zの初期値が1前提

全部載せるのが大変なので、dateで使う数値だけに絞っています。

調整して完成!

そんなわけで、まとめるとこんな感じ

A=$(. 2>&1);                                              # .のエラーメッセージを変数に格納
A=${A##*.};                                               # エラーメッセージの環境依存の無い箇所だけ抽出
${A:$((++z*++z*++z*z-z+++z)):$((z=z^z||++z))}             # s
${A:$((++z*++z---z)):$((z=z^z||++z))}                     # e
${A:$((++z*++z*z)):$((z=z^z||++z))} -- {z..A};            # t -- {z..A}
${@:$((++z*++z*++z---z+++z---z+++z---z)):$((z=z^z||++z))} # d
${@:$((++z*++z*++z---z+++z---z+++z)):$((z=z^z||++z))}     # a
${@:$((++z+++z+--z)):$((z=z^z||++z))}                     # t
${@:$((++z*++z*++z---z+++z---z)):$((z=z^z||++z))}         # e

経緯

SECCON2017オンライン予選問題 Powerful_Shell の難読化最後の部分と

${;}=+$();${=}=${;};${+}=++${;};${@}=++${;};${.}=++${;};${[}=++${;};${]}=++${;};${(}=++${;};${)}=++${;};${&}=++${;};${|}=++${;};${"}="["+"$(@{})"[${)}]+"$(@{})"["${+}${|}"]+"$(@{})"["${@}${=}"]+"$?"[${+}]+"]";${;}="".("$(@{})"["${+}${[}"]+"$(@{})"["${+}${(}"]+"$(@{})"[${=}]+"$(@{})"[${[}]+"$?"[${+}]+"$(@{})"[${.}]);${;}="$(@{})"["${+}${[}"]+"$(@{})"[${[}]+"${;}"["${@}${)}"];"${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${(}${+}+${"}${&}${@}+${"}${+}${=}${+}+${"}${|}${)}+${"}${+}${=}${=}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${[}${]}+${"}${&}${=}+${"}${+}${+}${[}+${"}${+}${+}${+}+${"}${+}${=}${|}+${"}${+}${+}${@}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${(}${|}+${"}${+}${+}${=}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${+}${+}${[}+${"}${.}${@}+${"}${+}${+}${(}+${"}${+}${=}${[}+${"}${+}${=}${+}+${"}${.}${@}+${"}${+}${+}${@}+${"}${|}${)}+${"}${+}${+}${]}+${"}${+}${+}${]}+${"}${+}${+}${|}+${"}${+}${+}${+}+${"}${+}${+}${[}+${"}${+}${=}${=}+${"}${.}${|}+${"}${+}${.}+${"}${+}${=}+${"}${)}${.}+${"}${+}${=}${@}+${"}${[}${=}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${.}${@}+${"}${[}${]}+${"}${+}${=}${+}+${"}${+}${+}${.}+${"}${.}${@}+${"}${.}${|}+${"}${&}${=}+${"}${[}${&}+${"}${+}${+}${|}+${"}${(}${|}+${"}${+}${+}${[}+${"}${.}${(}+${"}${)}${@}+${"}${]}${+}+${"}${[}${|}+${"}${[}${|}+${"}${.}${|}+${"}${[}${+}+${"}${+}${@}${.}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${|}+${"}${)}${+}+${"}${+}${+}${+}+${"}${+}${+}${+}+${"}${+}${=}${=}+${"}${.}${@}+${"}${)}${[}+${"}${+}${+}${+}+${"}${|}${&}+${"}${.}${.}+${"}${.}${|}+${"}${]}${|}+${"}${+}${.}+${"}${+}${=}+${"}${|}+${"}${&}${)}+${"}${+}${+}${[}+${"}${+}${=}${]}+${"}${+}${+}${(}+${"}${+}${=}${+}+${"}${[}${]}+${"}${)}${@}+${"}${+}${+}${+}+${"}${+}${+}${]}+${"}${+}${+}${(}+${"}${.}${@}+${"}${.}${[}+${"}${&}${.}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${.}+${"}${.}${(}+${"}${(}${|}+${"}${(}${)}+${"}${(}${)}+${"}${)}${|}+${"}${)}${&}+${"}${+}${@}${]}+${"}${.}${[}+${"}${+}${.}+${"}${+}${=}+${"}${+}${@}${]}|${;}"|&${;}

難読化されたPowershellの問題

と、Masato Kinugawaさんの以下を見て感銘を受けまして、何とか記号だけでシェル芸したい!と思ったわけなんです(結局記号だけは無理だったw)


コメント

クリップボードから画像を追加 (サイズの上限: 100 MB)