title: 浅析命令执行漏洞
date: 2022-12-01 00 :02 :36
tags: 漏洞
categories: 学习笔记
漏洞描述
命令执行漏洞是指服务器没有对执行的命令进行过滤,用户可以随意执行系统命令,命令执行漏洞属于高危漏洞之一
如PHP的命令执行漏洞主要是基于一些函数的参数过滤不足导致,可以执行命令的函数有**system( )、exec( )、shell_exec( )、passthru( )、pcntl_execl( )、popen( )、proc_open( )**等,当攻击者可以控制这些函数中的参数时,就可以将恶意的系统命令拼接到正常命令中,从而造成命令执行攻击
PHP执行命令是继承WebServer用户的权限,这个用户一般都有权限向Web目录写文件,可见该漏洞的危害性相当大
漏洞原理
应用程序有时需要调用一些执行系统命令的函数,如在PHP中,使用system、exec、shell_exec、passthru、popen、proc_popen等函数可以执行系统命令,当黑客能控制这些函数中的参数时,就可以将恶意的系统命令拼接到正常命令中,从而造成命令执行漏洞
常见危险函数
php代码相关
eval()
assert()
preg_replace
call_user_func()
call_user_func_array()
create_function
array_map()
系统命令执行相关
system()
passthru()
exec()
pcntl_exec()
shell_exec()
popen()
proc_open()
`(反单引号)
ob_start()
特殊函数
phpinfo()
#这个文件里面包含了PHP的编译选项,启动的扩展、版本、服务器配置信息、环境变量、操作系统信息、path变量等非常重要的敏感配置信息
symlink():
#一般是在linux服务器上使用的,为一个目标建立一个连接,在读取这个链接所连接的文件的内容,并返回内容
getenv
#获取一个环境变量的值
putenv($a)
#添加$a到服务器环境变量,但环境变量仅存活于当前请求期间。 在请求结束时环境会恢复到初始状态
危险函数:
system
system — 执行外部程序,并且显示输出
该函数会把执行结果输出
并把输出结果的最后一行作为字符串返回
如果执行失败则返回false
这个也最为常用
语法
system(string $command, int &$result_code = null): string|false
同 C 版本的 system() 函数一样,本函数执行 command 参数所指定的命令,并且输出执行结果。
如果 PHP 运行在服务器模块中,system() 函数还会尝试在每行输出完毕之后,自动刷新 web 服务器的输出缓存。
如果要获取一个命令未经任何处理的原始输出,请使用 passthru() 函数。
参数
command
要执行的命令。
result_code
如果提供 result_code 参数,则外部命令执行后的返回状态将会被设置到此变量中
返回值
成功则返回命令输出的最后一行,失败则返回 false
例子
<?php
echo '<pre>';
// 输出 shell 命令 "ls" 的返回结果
// 并且将输出的最后一样内容返回到 $last_line。
// 将命令的返回值保存到 $retval。
$last_line = system('ls', $retval);
// 打印更多信息
echo '
</pre>
<hr />Last line of the output: ' . $last_line . '
<hr />Return value: ' . $retval;
?>
exec
exec — 执行一个外部程序
不输出结果
返回执行结果的最后一行
可以使用output进行输出
语法
exec(string $command, array &$output = null, int &$result_code = null): string|false
//exec() 执行 command 参数所指定的命令。
参数
command
要执行的命令。
output
如果提供了 output 参数, 那么会用命令执行的输出填充此数组, 每行输出填充数组中的一个元素。 数组中的数据不包含行尾的空白字符,例如 \n 字符。 请注意,如果数组中已经包含了部分元素,exec() 函数会在数组末尾追加内容。如果你不想在数组末尾进行追加, 请在传入 exec() 函数之前 对数组使用 unset() 函数进行重置。
result_code
如果同时提供 output 和 result_code 参数,命令执行后的返回状态会被写入到此变量。
返回值
命令执行结果的最后一行内容。 如果你需要获取未经处理的全部输出数据, 请使用 passthru() 函数。
失败时返回 false。
如果想要获取命令的输出内容, 请确保使用 output 参数。
例子
<?php
// 输出运行中的 php/httpd 进程的创建者用户名
// (在可以执行 "whoami" 命令的系统上)
$output=null;
$retval=null;
exec('whoami', $output, $retval);
echo "Returned with status $retval and output:\n";
print_r($output);
?>
输出:
Returned with status 0 and output:
Array
(
[0] => cmb
)
passthru
passthru — 执行外部程序并且显示原始输出
此函数只调用命令
并把运行结果原样地直接输出
没有返回值。
语法
passthru(string $command, int &$result_code = null): ?bool
同 exec() 函数类似, passthru() 函数 也是用来执行外部命令(command
)的。 当所执行的 Unix 命令输出二进制数据, 并且需要直接传送到浏览器的时候, 需要用此函数来替代 exec() 或 system() 函数。 常用来执行诸如 pbmplus 之类的可以直接输出图像流的命令。 通过设置 Content-type 为 image/gif
, 然后调用 pbmplus 程序输出 gif 文件, 就可以从 PHP 脚本中直接输出图像到浏览器。
参数
command
要执行的命令。
result_code
如果提供 result_code 参数, Unix 命令的返回状态会被记录到此参数
返回值
成功时返回 null, 或者在失败时返回 false。
例子
<?php
highlight_file(__FILE__);
passthru('ls');
?>
shell_exec
shell_exec — 通过 shell 执行命令并将完整的输出以字符串的方式返回
不输出结果,返回执行结果
使用反引号(``)时调用的就是此函数
语法
shell_exec(string $command): string|false|null
参数
command
要执行的命令。
返回值
string 包含已执行命令的输出,如果无法建立管道,则为 false,如果发生错误或者命令不产生输出则为 null
注意:当进程执行过程中发生错误,或者进程不产生输出的情况下,都会返回 null。使用本函数无法检测执行是否成功。当需要访问程序退出代码时,应使用 exec()。
例子
<?php
$output = shell_exec('ls -lart');
echo "<pre>$output</pre>";
?>
命令连接符
windows系统
“|”:直接执行后面的语句
例如:ping www.baidu.com|whoami
“||”:如果前面执行的语句执行出错,则执行后面的语句
例如:png www.baidu.com||whoami
“&”:如果前面的语句为假则直接执行后面的语句,前面的语句可真可假
例如:png www.baidu.com&whoami或者ping www.baidu.com&whoami
“&&”:如果前面的语句为真先执行第一个命令后执行第二个命令;为假则直接出错,也不执行后面的语句
例如:ping www.baidu.com&&whoami png www.baidu.com&&whoami
Linux系统
“;”执行完前面的命令执行后面的
“|”:显示后面语句的执行结果
“||”:当前面的语句执行出错时,执行后面的语句
“&”:如果前面的语句为假,则直接指向后面的语句,前面的语句可真可假
“&&”:如果前面的语句为假则直接出错,也不执行后面的语句
常用命令
Windows
netstat -ano
:查看所有进程
(1)netstat –ano|findstr [指定端口号]:该命令查看哪个程序或进程占用了端口
tasklist
:列出所有任务及进程号
(1)tasklist|findstr [进程名称]:找到进程名称对应的详细信息,例如PID
taskkill
:杀进程
(1)强制结束进程,按名称:taskkill /f /im notepad.exe(关闭记事本)
(2)强制结束进程,按 PID:taskkill /f /pid 1234(关闭 PID 为 1234 的进程)
--help或/?
:查看帮助信息
cd
:切换目录
D:
:跳转到其他硬盘
ping
:测试IP
ipconfig
:查看网络详情,类似于linux的ifconfig
dir
:显示目录中的文件内容,类似于linux的ls
type
:查看文件,类似于linux的cat、less、more;用法:type 文件名
md
:创建文件夹,类似于linux的mkdir;用法:md 目录名
tree
:查看目录结构
tracert
:路由跟踪,确定IP数据包访问目标时所选择的路径;用法:tracert 域名或IP
copy
:复制文本文件;用法:copy 文件1 文件2
注:
参数/b指定以二进制格式复制、合并文件,用于图像类/声音类文件
参数/a指定以ASCII格式复制、合并文件,用于txt等文档类文件
图片马制作:copy x.jpg/b + x.php/a xx.jpg
net start
服务名;net stop 服务名
cls
:清空cmd命令行,类似于linux的clear
ctrl+C
:结束或退出cmd正在执行的脚本
find
:查找
find /c “所要搜索的文件所包含的字符串” 文件的绝对路径
for
:对一个或一组文件,字符串或命令结果中的每一个对象执行特定命令
(1)找出C盘下的所有文件,并将所有文件名都输出出来
for /r C: %i in (*) do @echo %i
(2)找出C盘下所有后缀是.txt的文件,并将其输出
for /r C: %i in (*.txt) do @echo %i
(3)找出C盘下所有后缀是.txt和.jpg的文件,并将其输出
for /r C: %i in (*.txt,*.jpg) do @echo %i
Linux
cd
:切换当前工作目录;用法:cd后面加目录
(1)cd /root:进入/root 目录
(2)cd …/:返回上一级目录
(3)cd ./:进入当前目录
ls
:显示指定工作目录下的内容;用法:ls 文件或目录
(1)ls:./ 查看当前目录所有的文件和目录
(2)ls -l:以长格式显示目录下的内容列表
(3)ls -a:查看所有的文件,包括隐藏文件,以.开头的文件
cp
:拷贝文件;用法:cp 要复制的文件 目标路径
(1)cp xx.txt /home/backup.txt ,拷贝文件至/home目录下并且重命名为bak.txt
(2) cp xx –r /home:拷贝xx目录到/home目录下
cat
:查看文件内容;用法:cat 文件绝对路径
(1)cat test.txt:查看test.txt文件内容
echo
:回显;用法:输入什么就打印什么
(1)echo hello
>
:表示追加覆盖;常见用法echo world > test.txt
>>
:表示追加;常见用法echo world >> test.txt
find
:查找指定文件;用法:find 目录 -name 文件
(1)find /home -name “*.txt” :查找/home目录下,所有以.txt 结尾的文件或者目录。
groupadd
:创建组;用法:groupadd 组名;注:在/etc/group中查看组名;注:将某用户加入root用户组:usermod –g root 用户名
groupdel
:删除组;用法:groupdel 组名
grep
:用于查找文件里符合条件的字符串;用法:grep 参数 目标
-r:指定要查找目标的是目录而非文件时使用
-n:显示具体行数
–include:指定后缀文件
(1)grep -rn “eval“ target:搜索target目标(目录/文件)中是否含有eval的文件,并且确定在所含有的文件中是第几行
(2)grep -rn --include=‘*.php’ ‘eval(’ target:搜索target目标(目录/文件)中是否含有eval的文件(注:这里是指定只搜索.php后缀的文件),并
且确定在所含有的文件中是第几行
head
:默认查看文件前10行内容;用法:head 文件名;如果查看前20行,用法:head -20 文件名
tail
:默认查看文件后10行内容;用法:tail 文件名,如果查看后20行,用法:tail -20 文件名
more或less
:分页查看文件内容;用法:more 文件名或less 文件名
注:cat 和 more 同时使用例如: cat test.txt |more 分页显示 text 内容,|符号是管道符,用于把|前的输出作为后面命令的输入
useradd
:创建用户;用法:useradd 用户名,注:在/etc/passwd中可查看
(1)将用户添加到指定组中: useradd -g 组名 用户
userdel
:删除用户;用法:userdel 用户名
passwd
: 设置密码;passwd 用户名,不加用户名默认修改当前用户
vi
:修改文件(命令行模式、文本输入模式、末行模式),vi或vim打开一个文件,首先是命令行模式,然后按 i 进入文本输入模式,可以
在文件里写入字符等信息。写完后,按 esc 进入命令模式,然后输入:进入末行模式,例如输入 :wq 表示保存退出。如果想直接退出,不
保存,可以执行 :q , 如果无法退出可以使用 q! 强制退出。
id
:显示用户的ID,以及所属群组的ID
ifconfig
:显示网络详情
netstat
:显示网络状态
netstat –anplt:查看所有tcp端口
netstat –anplu:查看所有udp端口
kill
:删除执行中的程序或工作
kill -9:强制执行
ping
:检测主机;用法:ping ip
ps
:显示当前进程的状态,类似于 windows 的任务管理器
reboot
:重启;用法:reboot -f(强制重启)
su
:切换用户;用法:su 用户名
sudo
:使用root用户执行命令;用法:sudo 命令
uname
:显示系统信息;用法:uname –a(显示系统详细信息)
whoami
:显示自身用户名称
--help
:命令使用详情查询;用法:命令 –help
clear
:清空命令行
pwd
:显示当前所在的目录
mkdir
:创建目录;用法:mkdir 目录名
rmdir
:删除空目录,非空不可删除;用法:rmdir 空目录名称
rm
:删除文件或者目录,用法:rm –rf 文件名或目录 (-r 表示递归,-f 表示强制)
touch
:创建文件;用法:touch 文件名,如果文件存在,则修改当前文件时间,文件内容不变
mv
:重命名或者移动文件/目录;用法: mv 原文件名 新文件名 或 mv 原文件位置 新文件位置
chmod
:修改文件或目录的权限
chmod u+x 目录/文件:给该目录/文件所有者赋予执行权限
chmod ug-x 目录/文件:给该目录/文件所有者和组用户减去执行权限
chmod 777 目录/文件:给该目录/文件所有者、组用户、其他用户赋予所有权限
chmod 764 目录/文件:给该目录/文件所有者赋予全部权限,组用户赋予读写权限,其他用户赋予读权限
scp
:复制文件和目录
(1)从本地复制到远程
scp local_file remote_username@remote_ip:remote_folder
或者
scp local_file remote_username@remote_ip:remote_file
(2)从远程复制到本地
scp remote_username@remote_ip:remote_folder local_file
或者
scp remote_username@remote_ip:remote_file local_file
部分文章内容和图片应用自:
https://blog.csdn.net/weixin_44604541/article/details/109558036
https://blog.csdn.net/LYJ20010728/article/details/117349106
https://blog.csdn.net/qq_41617034/article/details/115583211
感谢这几位师傅了