記号と1,2,A,zでだけで作る難読化シェル芸
これはひどいw
結果¶
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))}
2017年 12月 18日 月曜日 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}
2017年 12月 18日 月曜日 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)
Comments