HTTP 參數污染(HTTP Parameter Pollution,HPP)是「操弄網站對請求參數的處理方式」的攻擊。攻擊者注入額外參數,網站若信任這些值,就可能產生非預期行為。HPP 漏洞發生在伺服器端或客戶端,後者在瀏覽器中即可看到效果,前者則必須靠輸入與輸出反推伺服器邏輯——因此 HPP 比起其他漏洞,更需要實驗與耐心

伺服器端 HPP(Server-Side HPP)#

概念#

伺服器端 HPP 的目標是送出意料之外的參數組合,讓伺服器內部程式回傳意外結果。攻擊者看不到伺服器程式碼,只能從輸入與輸出反推。

範例:銀行轉帳的相同參數重複#

假設銀行用 URL 參數驅動轉帳:

https://www.bank.com/transfer?from=12345&to=67890&amount=5000

fromtoamount 分別代表來源、目的、金額。如果攻擊者送出兩個 from

https://www.bank.com/transfer?from=12345&to=67890&amount=5000&from=ABCDEF

伺服器處理多個同名參數的策略因平台而異——一旦驗證階段用第一個 from、執行階段用第二個 from,攻擊者就能轉走別人帳戶的錢。

各伺服器處理重複參數的方式不同:

  • PHP / Apache:取最後一個
  • Apache Tomcat:取第一
  • ASP / IIS全部接收

詳細差異可參考 Luca Carettoni 與 Stefano di Paolo 在 AppSec EU 09 的整理。

範例:陣列順序錯位#

如果伺服器用陣列接收參數,順序就成了關鍵。考慮一段 Ruby 後端:

user.account = 12345
def prepare_transfer(params)
  params << user.account
  transfer_money(params)
end
def transfer_money(params)
  to = params[0]
  amount = params[1]
  from = params[2]
  transfer(to, amount, from)
end

正常 URL:

https://www.bank.com/transfer?to=67890&amount=5000

進入 prepare_transferparams = [67890, 5000],再被附加 user.account 後變成 [67890, 5000, 12345],最後正確轉帳。

但攻擊者多塞一個 from

https://www.bank.com/transfer?to=67890&amount=5000&from=ABCDEF

params 會先是 [67890, 5000, "ABCDEF"],再加上 user.account 變成 [67890, 5000, "ABCDEF", 12345]transfer_moneyparams[2] 當作 from——拿到的是 ABCDEF不是受害者的帳戶

同樣的命名參數,如果後端程式以陣列順序而非鍵名取值,就有機會被錯位污染。

客戶端 HPP(Client-Side HPP)#

客戶端 HPP 注入額外參數,目標是影響瀏覽器端最終生成的 URL 或內容

範例:URL 編碼夾帶額外參數#

考慮以下伺服器程式碼:

<? $val=htmlspecialchars($_GET['par'],ENT_QUOTES); ?>
<a href="/page.php?action=view&par='.<?=$val?>.'">View Me!</a>

攻擊者帶入:

http://host/page.php?par=123%26action=edit

關鍵:%26& 的 URL 編碼。

  • 第一次解析時 %26 仍是字串,par 的整個值是 "123%26action=edit"action=edit 不會被切成獨立參數
  • htmlspecialchars%26 轉成 HTML 實體 &amp;
  • 最終輸出:<a href="/page.php?action=view&par=123&amp;action=edit">

於是 href 多了一個 action=edit,當使用者點擊時,這個被偷渡進來的參數就可能改變應用行為。

三個案例分別在 HackerOne 與 Twitter,雖然都涉及 URL 參數,但沒有兩個是用同樣方法找到或同樣根因——再次證明 HPP 需要全方位測試。

案例 1:HackerOne Social Sharing Buttons#

漏洞描述#

HackerOne 部落格底部提供「分享到 Twitter / Facebook」按鈕,會把當前文章 URL 帶入分享連結。研究者發現可在文章 URL 後追加額外參數:

https://hackerone.com/blog/introducing-signal&u=https://vk.com/durov

被 HackerOne 拼接後,產生的 Facebook 分享連結變成:

https://www.facebook.com/sharer.php?u=https://hackerone.com/blog/introducing-signal?&u=https://vk.com/durov

Facebook 對重複的 u 參數取最後一個,分享出去的連結最終指向 vk.com/durov

同樣手法也能竄改 Twitter 預設文字:

https://hackerone.com/blog/introducing-signal?&u=https://vk.com/durov&text=another_site:https://vk.com/durov

Takeaways#

凡是「網站接收使用者內容、轉接到第三方服務、並用當前 URL 動態產生輸出」的場景,都值得測試 HPP。

案例 2:Twitter Unsubscribe Notifications#

漏洞描述#

研究者 Mert Tasci 取消電子報訂閱時注意到一條像這樣的 URL(簡化過):

https://twitter.com/i/u?iid=F6542&uid=1134885524&nid=22+26&sig=647192e86e28fb6691db2502c5ef6cf3xxx

uid 是當前登入帳戶的 ID。直接把 uid 換成另一名使用者的 ID 並無效——Twitter 用 sig 驗證 URL 沒被竄改。

但 Tasci 並未放棄。他塞進第二個 uid

https://twitter.com/i/u?iid=F6542&uid=2321301342&uid=1134885524&nid=22+26&sig=647192e86e28fb6691db2502c5ef6cf3xxx

成功——他取消了另一名使用者的電子報訂閱。

漏洞精彩之處在於:Twitter 用第一個 uidsig 做簽章驗證(驗證通過),卻用第二個 uid 執行取消訂閱動作。

Takeaways#

  • 耐心:第一次嘗試(換 uid)失敗時若放棄,就拿不到 $700
  • 盯住自動遞增整數欄位:例如 UID,這類值常與權限相關(第 16 章 IDOR 會延伸討論)

案例 3:Twitter Web Intents#

背景#

Twitter Web Intents 提供彈出視窗,讓非 Twitter 網站上的使用者快速完成 follow、like、retweet、tweet 等操作。透過 GET 請求觸發:

https://twitter.com/intent/intentType?parameter_name=parameterValue

Figure 3-1: 早期版本的 Twitter Web Intents——使用者可在不離開頁面的情況下與 Twitter 內容互動

漏洞描述#

研究者 Eric Rafaloff 發現四種 intent 全部受 HPP 影響。以 follow 為例,傳入兩個 screen_name

https://twitter.com/intent/follow?screen_name=twitter&screen_name=ericrtest3

伺服器產生的 HTML 形如:

<form
  class="follow"
  id="follow_btn_form"
  action="/intent/follow?screen_name=ericrtest3"
  method="post"
>
  <input type="hidden" name="authenticity_token" value="..." />
  <input type="hidden" name="screen_name" value="twitter" />
  <input type="hidden" name="profile_id" value="783214" />
  <button class="button" type="submit"><b></b><strong>Follow</strong></button>
</form>

關鍵不一致:

  • 顯示用第一個 screen_nametwitter,畫面看起來在追蹤官方帳號)
  • 送出form action 用第二個 screen_nameericrtest3

於是使用者「以為自己 follow 了 Twitter 官方」,實際上 follow 了攻擊者帳號。

同樣手法可在 like intent 注入無關的 screen_name

https://twitter.com/intent/like?tweet_id=6616252302978211845&screen_name=ericrtest3

點 Like 後,旁邊的 Follow 按鈕指向的卻是 ericrtest3

Takeaways#

一個地方有 HPP,常常代表系統性問題。發現一處後值得在整個平台尋找類似行為。

章末總結#

  • HPP 的風險取決於後端如何處理多個同名參數,以及污染後的參數被用在何處
  • 因為看不到伺服器程式碼,找這類漏洞比其他漏洞更需要試錯
  • 建議的測試切入點:
    • 內容會被分享到第三方服務(社群網站)的「分享連結」
    • 帶有 ID、UID 等遞增整數的 URL
    • 同時包含「驗證簽章」與「實際動作」的 URL,可嘗試插入第二份參數讓兩端各自取值
  • 找到一處 HPP,就把整個平台再掃一遍——往往不是孤例