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)