Web/Greyctf Survey
DESC

Your honest feedback is appreciated 😃 (but if you give us a good rating we'll give you a flag)
中文翻譯
你的誠實回饋我們會非常感激 😃 (但如果你給我們一個好評,我們會給你一面旗幟)
Author: jro
challenge attach link:
- challenge website url: http://challs.nusgreyhats.org:33334/
- file attach: https://drive.google.com/uc?export=download&id=1fvz_8s4drwOTR8z0ppvmnflq8gEzosBU
Background Knowledge
- 對於 js 語法與內建功能的了解。
- 知道資料型態的相關知識。
Solve
本題一進場,就是一個拉霸,然後可以 submit vote。按下按鈕會往
/vote送一個 POST 的 Request,然後得到資料後會用alert顯示給使用者。
根據這樣的結果,我未看原始碼先猜問題就出在這個 /vote,因為看起來就只有他可以注入我的惡意 payload。打開原始碼,直奔
/vote那邊看過去,果然應證了我的猜測,在第 29 至第 42 行之間,顯示了出現flag的方法:讓score > 1就可以了。jsif(vote < 1 && vote > -1) { score += parseInt(vote); if(score > 1) { score = -0.42069; return res.status(200).json({ "error": false, "msg": config.flag, }); } return res.status(200).json({ "error": false, "data": score, "msg": "Vote submitted successfully" }); }已經可以從第 12 行知道
score的初始值是,要讓他大於 1 的方法就是讓他加上 就可以達成,可是在第 29 行卻擋住了我們的念想,因為 vote只接受介於 -1 ~ 1 之間,還不包含上下界。不過也不是完全沒有希望,因為他在處理
score與vote相加時,使用到了parseInt這個 js 內建函式,將vote轉為整數。但是眾所週知, js 這個語言的資料型別轉換,總是會出現翻車場面...。果不其然,上網搜尋了一下找到了一篇對岸的文章:他很好的解釋了
parseInt在轉換數字上的漏洞。用比較白話來說,就是在
parseInt進行轉換時,由於他的原始參數只接受String這個型別,所以如果送入的型別不是String的話,會先把資料用toString的這個方法轉換成String型別,在轉換成整數。但是
toString這個方法在處理數字時,會有一點翻車:當小數點超過一定位數,會自動轉成科學記號。可是parseInt才不管你什麼科學不科學記號,他只認「數字」,碰到非數字的東西,全部都會幹掉不管。因此若是送超過小數位數的資料進去時,他就會先把資料轉成
String然後再轉成整數。文章中也說明他測試了之後只要數字只要小於
,那麼就會轉換成科學符號,然後最後會因為科學符號的小數點,只取最前面的一個數字轉成整數。 例如
這串數字,會在 toString的助攻之下轉變成"1.43e-7",然後在轉換成整數的過程中,因為.不是數字,因此後面的東西通通被省略,也就留下了數字1當成被轉換後的結果。因此parseInt(0.000000143)的輸出結果會變成1。
利用上面這個
翻車的特性,我使用Hackbar這個 chrome 擴展,利用Network頁面將請求封包轉成 cURL 格式再餵進Hackbar中,送入精心調製的POST BODY,就得到答案了。
神奇的狀況
我這邊使用的是
0.0000002這個 payload。理所當然的可以得到答案,但是...
我如果改為使用
2e-7,一樣可以得到答案...再進一步,我測試了
1.43e-7是不能得到 flag 的,可是
1.43e-8就可以了...是不是很神奇!! 🫠
嘔對了...改用
0.0000000143一樣行得通喔...到現在也沒搞懂為啥...


