ssrf
原理
SSRF(Server-Side Request Forgery:服务器端请求伪造)是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下,SSRF是要目标网站的内部系统。(因为他是从内部系统访问的,所有可以通过它攻击外网无法访问的内部系统,也就是把目标网站当中间人)
形成原因
SSRF形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能,且没有对目标地址做过滤与限制。比如从指定URL地址获取网页文本内容,加载指定地址的图片,文档,等等。
实验
分析这段源码可以看到虽然禁用了diet端口探测,file文件的关键字段,但是在下面一段发现可以查看php的版本。
在php的信息里可以看到主机的信息,这就可以用bp来抓包爆破剩下的主机
发现开放了3个服务器我们进行以此访问,发现在2的时候显示了go,away。
我们再来利用bp来抓包用暴力破解模块看一下发现6379端口暴露了
这个是redis服务的端口
接下来就可以利用redis未授权的漏洞来访问,由于这台内网主机上还存在一个http服务,我们可以将webshell写入其web目录,然后利用ssrf漏洞进行访问。但是我们尝试发现不能直接在/var/www/html目录下写文件,我们继续用bp的破解模块来查看有啥目录,发现有个upload目录。
然后利用工具生成一段代码
将生成的这段代码进行url encode加密,最后进行提交,我们发现在upload下面生成了对应的php代码,然后就可以进行访问了。
csrf
什么是csrf
跨站请求伪造,冒用Cookie中的信息,发起请求攻击。CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的
实验
dvwa靶场下的csrf(high)
<?php
$change = false;
$request_type = "html";
$return_message = "Request Failed";
if ($_SERVER['REQUEST_METHOD'] == "POST" && array_key_exists ("CONTENT_TYPE", $_SERVER) && $_SERVER['CONTENT_TYPE'] == "application/json") {
$data = json_decode(file_get_contents('php://input'), true);
$request_type = "json";
if (array_key_exists("HTTP_USER_TOKEN", $_SERVER) &&
array_key_exists("password_new", $data) &&
array_key_exists("password_conf", $data) &&
array_key_exists("Change", $data)) {
$token = $_SERVER['HTTP_USER_TOKEN'];
$pass_new = $data["password_new"];
$pass_conf = $data["password_conf"];
$change = true;
}
} else {
if (array_key_exists("user_token", $_REQUEST) &&
array_key_exists("password_new", $_REQUEST) &&
array_key_exists("password_conf", $_REQUEST) &&
array_key_exists("Change", $_REQUEST)) {
$token = $_REQUEST["user_token"];
$pass_new = $_REQUEST["password_new"];
$pass_conf = $_REQUEST["password_conf"];
$change = true;
}
}
if ($change) {
// Check Anti-CSRF token
checkToken( $token, $_SESSION[ 'session_token' ], 'index.php' );
// Do the passwords match?
if( $pass_new == $pass_conf ) {
// They do!
$pass_new = mysqli_real_escape_string ($GLOBALS["___mysqli_ston"], $pass_new);
$pass_new = md5( $pass_new );
// Update the database
$insert = "UPDATE `users` SET password = '" . $pass_new . "' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert );
// Feedback for the user
$return_message = "Password Changed.";
}
else {
// Issue with passwords matching
$return_message = "Passwords did not match.";
}
mysqli_close($GLOBALS["___mysqli_ston"]);
if ($request_type == "json") {
generateSessionToken();
header ("Content-Type: application/json");
print json_encode (array("Message" =>$return_message));
exit;
} else {
echo "<pre>" . $return_message . "</pre>";
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>
代码新增了token机制,用户每次访问更改密码页面时,服务器会返回一个随机的token,之后每次向服务器发起请求,服务器会优先验证token,如果token正确,那么才会处理请求。
所以我们在发起请求之前需要获取服务器返回的user_token,利用user_token绕过验证。这里我们可以使用burpsuit的CSRF Token Tracker插件可以直接绕过user_token验证。
1.在bp里面安装安装CSRF Token Tracker插件
2.进入插件之后添加主机和名(名就是token的名字,这里是user_token),还有抓取到的token值也需要添加上去
3.再重新抓包到重放模块,这时我们会发现不管怎么修改密码,都会返回200。200代表成功
防御思路
- 验证hyttp头部的referer字段
Referer 字段记录了该 HTTP 请求的来源地址,若请求来源不一致,则认为可能是 CSRF 攻击而拒绝该请求 - 在请求地址中添加 token 并验证(这个通常可以完美防御csrf)
在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。但难点在于如何将token 以参数的形式加入请求。
3.在 HTTP 头中自定义属性并验证
这种方法也是使用 token 并进行验证,和上一种方法不同的是,这里并不是把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。通过 XMLHttpRequest 这个类,可以一次性给所有该类请求加上 csrftoken 这个 HTTP 头属性,并把 token 值放入其中。