2017-05-19 3 views
4

以下の機能が100%安全なコード噴射攻撃であることを確認したかったのです。具体的には、呼び出し側が実行可能なLuaコードを含むテーブルを取得したり、関数引数を介して関数に渡されたものをコンパイルするようにする関数の引数を誰でも見つけることができますか?これは安全ですか? (デシリアライゼーションを取る)

(コルーチンとデバッグライブラリと似たようなものを自分のアプリケーションに制限されているので、私はこのオフビートのアプローチをとった関数の呼び出し元が引数の「関数」テキストキー制約について知っているだろう;下記参照)

試み#1:(FAIL /危険な)すべての偉大なフィードバックのための

--[[ string2table(s : string) 

    De-serialise the string argument into a Lua table. 

    s should define a string serialised Lua constructor 

    However, no value of s can: 
     embed any code that can be executed at any stage by the caller 
     cause a runtime error during exec of the function 

    Pre: 
     Requires Lua v5.3 
     string2table() is in the global env. 
     The caller has no acccess to load or pcall. i.e the caller is in a jail 

     s should represent a serialised Lua constructor as a string starting with "{". 
     s cannot not be pre-compiled or the function will return an error. 
     s must not encode any table key containing the text "function". 

    Return Value: 

     On success 

      table : s de-serialised into a lua table. Bascially pcall(load(s)) 

     On fail 

      nil, errmsg 
]] 

function string2table(s) 
    if type(s) ~= "string" then return nil, "call format: string2table(string)" end 
    if string.find(s, "{") ~= 1 then return nil, "string arg must begin with '{'" end -- just a hint, this affords no protection 
    s = "return"..string.gsub(s, "function", "fun\\99tion")  -- NB \99 = "c" 
    -- The return & gsub above prevents embedding any code in s. 
    -- Specifically re the gsub: 
    --  when the text 'function' appears in a lua string it gets converted to 'function' ie no effect. 
    --  when the text 'function' appears outside of a lua string it gets converted to 'fun\99tion' causing the pcall to fail. 
    -- The cost of the gsub aprroach is that s can't define any table key with the text "function" in it. 
    -- However any "function" text embedded in a string will be unaffected. 

    local jail = {} 
    local f, err = load(s, "string2table:", "t", jail) 
    if err then return nil, err end -- it didnt compile, return the error 
    local ok, torErrmsg = pcall(f) 

    if not ok then return nil, torErrmsg end -- runtime error occured 
    return torErrmsg -- all ok, return the table 
end 

--[[ Example arguments: 

     "{s = \"function\"}"           -- rv = true, {s = "function"} 
     "{f = (function() while true do end end)()}"     -- value is a function call; rv = nil, [string "string2table:"]:1: ')' expected near '\' 
     "{[(function() while true do end return 123 end)()] = 456}" -- key is a function call; rv = nil, [string "string2table:"]:1: ')' expected near '\' 
     "{a = t.IdontExist}"           -- runtime error; rv = nil, [string "string2table:"]:1: attempt to index a nil value (global 't') 

]] 

感謝。特にEgor。

初期フィードバックに基づく試行#2。試行#2では、文字列ライブラリのメタメソッドも無効になりました。 S = "{( 'A'):担当者(99):見つける(() '* ':担当者(99)..' B')}"

--[[ string2table(s : string) 

De-serialise the string argument into a Lua table. 

s should define a string serialised Lua constructor 

However, no value of s can: 
    embed any code that can be executed at any stage by the caller 
    cause a runtime error during exec of the function 

Pre: 
    Requires Lua v5.3 
    string2table() is in the global env. 
    The caller has no acccess to load or pcall. i.e the caller is in a jail 
    Assumes the string library is present/visible. 

    s should represent a serialised Lua constructor as a string starting with "{". 
    s cannot not be pre-compiled or the function will return an error. 
    s must not encode any table key containing the text "function". 

Warning: 
    Inefficient (invokes Lua compiler). 
     Recommend JSON & JSON lib for frequent use over this function. 

Return Value: 

    On success 

     table : s de-serialised into a lua table. Bascially pcall(load(s)) 

    On fail 

     nil, errmsg 
]] 

do 

    local s_load   = load 
    local string_mt  = getmetatable("") 

    function string2table(s) 
     if type(s) ~= "string" then return nil, "call format: string2table(string)" end 
     if string.find(s, "{") ~= 1 then return nil, "string arg must begin with '{'" end -- just a hint, this affords no protection 
     s = "return"..string.gsub(s, "function", "fun\\99tion")  -- NB \99 = "c" 
     -- The return & gsub above prevents embedding most code from being embedded in s. 
     -- Specifically re the gsub: 
     --  when the text 'function' appears in a lua string it gets converted to 'function' ie no effect. 
     --  when the text 'function' appears outside of a lua string it gets converted to 'fun\99tion' causing the pcall to fail. 
     -- The cost of the gsub aprroach is that s can't define any table key with the text "function" in it. 
     -- However any "function" text embedded in a string will be unaffected. 

     -- gsub option: string.gsub(s, "%f[%w_]function%f[^%w_]", "fun\\99tion") 
     -- This variation above should safely allows keys with ..'function'.. in the key text to still load e.g. "{functional = true}" 
     -- [ed: I simply havent used this alt. gsub yet because im still learning Lua patterns and %f still confuses me] 

     local jail = {} 

     -- The string library's metatable represents a gaping hole in the jail. Temporarily close it. 
     -- This will ensure strings like this "{('a'):rep(99):find(('.*'):rep(99)..'b')}" are caught as an error. 
     string_mt.__index = nil -- disable string lib metatable 

     local f, err = s_load(s, "string2table:", "t", jail) -- "t" means only text chunks 
     if err then return nil, err end -- it didnt compile, return the error 
     local ok, torErrmsg = pcall(f) 

     string_mt.__index = string 
     if not ok then return nil, torErrmsg end -- runtime error occured 
     return torErrmsg -- all ok, return the table 
    end 
end 

--[[ quick test cases: 

    "{s = \"function\"}"           -- rv = true, {s = "function"} 
    "{f = (function() while true do end end)()}"     -- value is a function call; rv = nil, [string "luaDoStringLua:simple"]:1: ')' expected near '\' 
    "{[(function() while true do end return 123 end)()] = 456}" -- key is a function call; rv = nil, [string "luaDoStringLua:simple"]:1: ')' expected near '\' 
    "{a = t.IdontExist}"           -- runtime error; rv = nil, [string "luaDoStringLua:simple"]:1: attempt to index a nil value (global 't') 
    "{('a'):rep(99):find(('.*'):rep(99)..'b')}"      -- If string if exec'd it will hang the Lua interpreter. 
]] 
+1

単語 "function"を含む識別子を部分文字列として使用できるようにするには、次のように入力します。string.gsub(s、 "%f [%w_]関数%f [^%w_]"、 "fun \\ 99tion" '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' :: –

+1

いくつかの入力文字列があなたのLua VMをハングするかもしれません: 'string2table(" {( 'a' .. 'b')} ")' –

+0

また、IIRCの悪質なバイトコードもインタプリタに問題を引き起こす可能性があるため、ソースコードのみを読み込むようにしたいと考えています。 –

答えて

0

私はどのような方法を見つけることができませんでしそれを壊すのです。あなたはこれを行うことにより、Luaの5.2+でjailテーブルを取得することができます:

local jail = string2table("{_ENV}")[1] 

しかし、あなたは string2table後に刑務所テーブルに物事を追加する場合、それは問題ではありません新しい刑務所のテーブルが毎回生成されるため、実行されます。 (ただテーブルを再利用しないでください!)

私はLuaのサンドボックス化が安全だとはよく分かっているとは思いません。私が見落としたことがあるかもしれません。

また、string.find(s, "{") ~= 1string.sub(s, 1, 1) ~= "{"に置き換えることを検討してください。そうすれば、文字列全体を検索して最初の文字が開始中かどうかを確認する必要はありません。

関連する問題