Function 関数のひとつめの引数で
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
Function 関数の一つめの作る関数の引数部分にユーザ入力を入れれるとすると任意のコードは実行できるのかを試してみました
Function 関数のひとつめの引数にユーザ入力の値を入れられるとしたら 好きなコードを実行してなにか悪いことできるのかな と思いました
Function 関数は引数が 2 つ以上あるときに 1 つめは引数名で 2 つめが関数本体になります
なので 2 つめの関数本体のテキストと一緒に指定しないとまともに動かないので 1 つめだけをユーザ入力にするなんて普通はありえないはずです
2 つめの本体もユーザ入力可能ならそこに書いたコードはそのまま実行されるわけで好き勝手やり放題です
ですが 今回は 1 つめの引数指定のところだけでなにかできるかな と思ったので考えてみました
getFromTextbox() のところで自分の入力が取得されるとします
getArgs で取れる引数や不定です
この関数を実行させて alert を出すのが目標です
なので
のように 渡される引数より多いくらい引数を並べて最後の引数のデフォルト引数でやりたい処理を書けば関数が呼び出されたときに実行されます
……と思ったのですがこんなエラーがでてしまいました
SyntaxError: Function arg string contains parenthesis
「()」 は使えなくされているようです
普通に関数定義するときには問題なく Function 関数の場合のみです
関数実行を禁止するため でしょうか
それにしてはちょっと手抜き感のあるチェックなので別の意図があるのかもしれません
理由はなんであっても目標達成するには () 抜きで alert させる必要があります
他にもありそうですが 今思いつくのはこの 2 つです
getter は先に作っておかないとだめで さらに作るときに () がいるのでだめです
なのでタグ機能を使って実行させる方針にします
単純にこれできます
ですが タグ呼び出しだと引数の自由度があまりなく alert だから良いものの 好きに関数呼び出しはちょっと難しいです
もう少し自由度のある方法にしたいものです
これだとアラートがでません
考えてみればタグ機能の引数を直接呼び出す形にするとこうなります
配列の要素の文字列ですから評価されるはずがないです
となりました
最後の要素が body になるので ${} を使って body 部分を後ろに持ってくるようにしています
第一引数は ["a", "b"] になりますが 文字列化するときに自動で 「,」 で join されるので a と b の引数と言う形で構文エラーにはなりません
あとはこのまま
としたいですが () を消さないとなので unicode 形式にします
user_input 変数に入れる段階で () にされては意味が無いので \\u にしてエスケープしています
作られる関数はこうなります
これだと x に関数が入るだけで実行されません
なのでもう一回タグ機能で関数呼び出しします
コレで完成です
${} の中の () を unicode 形式にするだけで好きにコードをかけます
これでアラートが表示されます
Function 関数は引数が 2 つ以上あるときに 1 つめは引数名で 2 つめが関数本体になります
なので 2 つめの関数本体のテキストと一緒に指定しないとまともに動かないので 1 つめだけをユーザ入力にするなんて普通はありえないはずです
2 つめの本体もユーザ入力可能ならそこに書いたコードはそのまま実行されるわけで好き勝手やり放題です
ですが 今回は 1 つめの引数指定のところだけでなにかできるかな と思ったので考えてみました
function fn(){
var user_input = getFromTextbox()
var body = "return null"
var args = getArgs()
return Function(user_input, body)(...args)
}
var user_input = getFromTextbox()
var body = "return null"
var args = getArgs()
return Function(user_input, body)(...args)
}
getFromTextbox() のところで自分の入力が取得されるとします
getArgs で取れる引数や不定です
この関数を実行させて alert を出すのが目標です
簡単には行かなかった
引数名を書くところですが 「,」 で複数書くことができ デフォルト引数も設定できますなので
var user_input = "a,b,c,d,e,f,g,h,i,j,x=alert(1)"
のように 渡される引数より多いくらい引数を並べて最後の引数のデフォルト引数でやりたい処理を書けば関数が呼び出されたときに実行されます
……と思ったのですがこんなエラーがでてしまいました
SyntaxError: Function arg string contains parenthesis
「()」 は使えなくされているようです
普通に関数定義するときには問題なく Function 関数の場合のみです
関数実行を禁止するため でしょうか
それにしてはちょっと手抜き感のあるチェックなので別の意図があるのかもしれません
理由はなんであっても目標達成するには () 抜きで alert させる必要があります
タグ
() なしで関数実行となると getter にアクセスするか テンプレートストリングのタグ機能が思いつきます他にもありそうですが 今思いつくのはこの 2 つです
getter は先に作っておかないとだめで さらに作るときに () がいるのでだめです
なのでタグ機能を使って実行させる方針にします
var user_input = "a,b,c,d,e,f,g,h,i,j,x=alert`1`"
単純にこれできます
ですが タグ呼び出しだと引数の自由度があまりなく alert だから良いものの 好きに関数呼び出しはちょっと難しいです
もう少し自由度のある方法にしたいものです
eval
eval に文字列入れるのが簡単そう ということで試してみましたがeval `alert(1)`
これだとアラートがでません
考えてみればタグ機能の引数を直接呼び出す形にするとこうなります
const arr = ["alert(1)"]
arr.raw = ["alert(1)"]
eval(arr)
arr.raw = ["alert(1)"]
eval(arr)
配列の要素の文字列ですから評価されるはずがないです
Function
Function 関数ならいけそう ということで Function 関数の中にさらに Function 関数をもってくることにしましたFunction `a${"alert(100)"}b`
function anonymous(a,b
/*``*/) {
alert(100)
}
/*``*/) {
alert(100)
}
となりました
最後の要素が body になるので ${} を使って body 部分を後ろに持ってくるようにしています
第一引数は ["a", "b"] になりますが 文字列化するときに自動で 「,」 で join されるので a と b の引数と言う形で構文エラーにはなりません
あとはこのまま
var user_input = "a,b,c,d,e,f,g,h,i,j,x=Function`a${'alert(100)'}b`"
としたいですが () を消さないとなので unicode 形式にします
var user_input = "a,b,c,d,e,f,g,h,i,j,x=Function`a${'alert\\u0028100\\u0029'}b`"
user_input 変数に入れる段階で () にされては意味が無いので \\u にしてエスケープしています
作られる関数はこうなります
ƒ anonymous(a,b,c,d,e,f,g,h,i,j,x=Function`a${'alert\u0028100\u0029'}b`
/*``*/) {
}
/*``*/) {
}
これだと x に関数が入るだけで実行されません
なのでもう一回タグ機能で関数呼び出しします
var user_input = "a,b,c,d,e,f,g,h,i,j,x=Function`a${'alert\\u0028100\\u0029'}b```"
コレで完成です
${} の中の () を unicode 形式にするだけで好きにコードをかけます
var user_input = 'a,b,c,d,e,f,g,h,i,j,x=Function`a${ 'var value=1;alert\\u0028 value \\u0029;' }b```'
Function(user_input, "return null")("abc")
Function(user_input, "return null")("abc")
これでアラートが表示されます