代码执行原理
代码的执行来自于缺乏严格的过滤或者用户控制数据的逃逸。在这里由于攻击者可以控制部分或者所有内容传递给这些未进行严格过滤的函数,从而导致提交的内容会被作为PHP代码执行。如PHP的eval函数,可以将字符串代表的代码作为PHP代码执行,当用户能够控制这段字符串时,将产生代码注入漏洞(也称命令执行)。
PHP常见的代码执行函数
eval(),assert()
eval()
eval() 函数把字符串按照 PHP 代码来计算。
该字符串必须是合法的 PHP 代码,且必须以分号结尾。
assert()
断言函数,检查一个断言是否为 FALSE
preg_repalce + /e
模式preg_repalce( pattern,replacement,subject)
搜索 subject 中匹配 pattern 的部分, 以 replacement 进行替换。
preg_replace()函数原本是执行一个正则表达式的搜索和替换,但因为存在危险的/e修饰符,使 preg_replace() 将 replacement 参数当作 PHP 代码。
调用函数过滤不严
call_user_func()和array_map()等数十个函数都有调用其他函数的功能,其中的一个参数是要调用的函数 ,第二个参数作为调用函数的参数。
其余同类型的函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14call_user_func() call_user_func_array() array_map()
usort() uasort() uksort() array_filter()
array_ reduce() array_diff_uassoc() array_diff_ukey()
array_ udiff() array_ udiff_ assoc() array_udiff_uassoc()
array_intersect_assoc() array_intersect_uassoc()
array_uintersect() array_uintersect_assoc()
array_uintersect_uassoc() array_walk() array_walk_recursive()
xml_set_character_data_handler() xml_set_default_handler()
xml_set_element_handler() xml_set_end_namespace_decl_handler()
xml_set_external_entity_ref_handler() xml_set_notation_decl_handler()
xml_set_processing_instruction_handler()
xml_set_start_namespace_decl_handler()
xml_set_unparsed_entity_decl_handler() stream_filter_register()
set_error_handler() register_shutdown_function() register_tick_function()
动态函数执行
php动态函数的写法为”变量(参数)”
任意代码执行利用
eval()与asser()
1 |
|
preg_replace()
1 |
|
但是在php7中,不在支持preg_replace()的/e模式。
在上述的代码之中,是直接在preg_replace()函数中第一个参数参数处出现了/e,但是即使在第一个参数处无/e,也有可能出现任意代码执行,前提是第一个参数可控。
1 |
|
%00截断 需要php版本要小于5.3.4
call_user_func()
1 |
|
第一个参数是被调用的函数,第二个参数是调用函数的参数。
动态函数
1 |
|
这段代码的意思是,将GET请求的a参数当做函数,b参数当做函数的参数
命令执行
代码执行漏洞指的是可以执行PHP脚本代码,而命令执行代码指的是可以执行系统或应用指令的漏洞,php命令执行漏洞主要是基于一些函数的参数过滤不严导致的。可以执行命令的函数有system() exec() shell_exec() passthru() pcntl_exec() popen() proc_open 一共七个函数,另外单引号也可以执行命令,不过实际上这种方式也是调用的shell_exec()函数
php执行命令一般是继承webserver的权限,可以直接写入文件。
exec() shell_exec() passthru() system()(还有反引号)
这四个函数是可以直接传入命令,然后函数会返回执行结果,但是system()比较特殊,他可以直接返回并打印出来,不需要echo也可以。
1 |
|
popen()函数和proc_open()函数不会直接返回执行结果,而是返回一个文件指针,但是命令的确是执行了。
popen()函数有两个参数,第一个是要执行的命令,第二个是指针文件的连接模式。(r,w分别是读和写)
1 |
|
这个是将whoami执行出来的命令输出到D盘的1.txt文件中,可以在d盘中的1.txt中找到。
常用的绕过
空格绕过
<
符号
重定向符号,使用cat
命令从hello.txt
中读出
${IFS},$IFS$9
IFS 是 shell 的特殊环境变量,shell 根据 IFS 的值,默认是 space, tab, newline 来拆解读入的变量,然后对特殊字符进行处理,最后重新组合赋值给该变量。
${IFS},$IFS,$IFS$9,首先$IFS在linux下表示分隔符,单纯的cat$IFShello.txt,$IFS与hello.txt没有边界,所以导致输不出来结果,然而如果加一个{}就固定了变量名,同理在后面加个$可以起到截断的作用,而且也不必是$9,其余1-8也可以。
%09
在php环境下可以
命令分割符
%0a, %0d
换行与回车符号
;
符号
在 shell 中,使用连续指令功能的符号就是”分号
&&
符号
前一个命令执行成功才会执行下一条命令||
符号
前一个命令执行失败才会执行下一条命令
&
符号
表示将前一个命令设置进入后台|
符号
管道符,将前一个命令的输出作为后一个命令的输入
黑名单
1 | v=hel;x=lo;cat $v$x |
编码绕过