首先說明,偽造訪問來路不是什么光明正大的事情,目的就是為了欺騙服務(wù)器。原本以為給 XMLHTTP 對象增加一個 Referer 的header 就可以,結(jié)果卻沒有任何作用,改用 ServerXMLHTTP 也如此。
無意間發(fā)現(xiàn)公司內(nèi)部項(xiàng)目使用的 paypal 扣款程序里面有 WinHttp.WinHttpRequest.5.1 對象,它負(fù)責(zé)把客戶的信用卡信息提交到 paypal 的服務(wù)器,看來是一個核心的遠(yuǎn)程訪問方法,google一下發(fā)現(xiàn)它居然用可以成功偽造所有 http 請求的 header 信息!下面的代碼通過偽造 referer 的值,假裝從百度首頁提交一個表單到指定的 url 去:
1 2 3 4 5 6 7 8 9 10 | var url = "http://www.yourtarget.com"; var param = "name=david&age=30"; var obj = new ActiveXObject("WinHttp.WinHttpRequest.5.1"); obj.Open("POST", url, false); obj.Option(4) = 13056; obj.Option(6) = false; //false可以不自動跳轉(zhuǎn),截取服務(wù)端返回的302狀態(tài)。 obj.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); obj.setRequestHeader("Referer", "http://www.baidu.com"); obj.Send(param); WScript.Echo(obj.responseText); |
保存為 xxx.js 文件,在命令行中運(yùn)行 cscript.exe xxx.js。
從msdn得知,WinHttp.WinHttpRequest.5.1 是 msxml 4.0 的底層對象,也就是說 XMLHTTP/ServerXMLHTTP 也是在它的基礎(chǔ)上封裝而來。用 WinHttpRequest 發(fā)的請求,連 Fiddler 也監(jiān)測不到,看來確實(shí)是比較底層的東西。
---------------------------邪惡的分割線------------------------
既然可以用它來偽造所有 http 請求的 header,那 Cookies、Sessionid 自然也就可以得到并傳遞了。下面是實(shí)戰(zhàn)代碼,用命令行登錄博客園,共三次請求,第一次請求獲取表單的 VIEWSTATE 和 EVENTVALIDATION,第二次帶賬戶登錄,第三次帶Cookie訪問其首頁:
//封裝成遠(yuǎn)程訪問的函數(shù)
function RemoteCall(method, url, param, header){
var obj = new ActiveXObject("WinHttp.WinHttpRequest.5.1");
obj.Open(method||"GET", url, false);
obj.Option(4) = 13056;
obj.Option(6) = false;
if(method=="POST"){
obj.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
}
if(header){
for(var key in header){
if(key=="Cookie"){//根據(jù) MSDN 的建議,設(shè)置Cookie前,先設(shè)置一個無用的值
obj.setRequestHeader("Cookie", "string");
}
obj.setRequestHeader(key, header[key]);
}
}
obj.Send(param);
return obj;
}
//第一次遠(yuǎn)程訪問博客園的登錄入口
var url = "http://passport.cnblogs.com/login.aspx";
var objFirst = RemoteCall("GET", url, null);
//取得 viewstate 與 eventvalidation
var viewstate = objFirst.responseText.match(/id="__VIEWSTATE" value="(.*?)" \/>/)[1];
var eventvalidation = objFirst.responseText.match(/id="__EVENTVALIDATION" value="(.*?)" \/>/)[1];
//輸入自己的賬戶與密碼
var username = "";
var password = "";
var param = ""
+ "__VIEWSTATE="+encodeURIComponent(viewstate)
+ "&__EVENTVALIDATION="+encodeURIComponent(eventvalidation)
+ "&tbUserName="+username
+ "&tbPassword="+password
+ "&btnLogin="+encodeURIComponent("登 錄");
var objSecond = RemoteCall("POST", url, param);
//登錄成功后服務(wù)器執(zhí)行 Response.Redirect 跳轉(zhuǎn),即向客戶端發(fā)送了 302 狀態(tài)代碼
WScript.Echo(objSecond.status); //302即登錄成功, 如果是200,則登錄失敗,頁面沒有跳轉(zhuǎn)
//帶上登錄成功后的cookie,再次訪問其首頁
var json = {"Cookie": objSecond.getResponseHeader("Set-Cookie")};
var objThird = RemoteCall("GET", "http://www.cnblogs.com", null, json);
WScript.Echo(objThird.responseText);
上面的代碼其實(shí)已經(jīng)有一定惡意,我只為證明使用 WinHttpRequest 確實(shí)可以模擬瀏覽器發(fā)送請求,服務(wù)端也無法區(qū)別是從瀏覽器來的,還是從命令行來的。這證明到一點(diǎn),從客戶端提交來的任何數(shù)據(jù)都不可信,因?yàn)榘l(fā)送的 http 數(shù)據(jù)包不但表單值可以修改,連數(shù)據(jù)包的header都可以隨意修改。同時也說明,使用 VIEWSTATE 對表單的安全性無任何用處。