Hello Full Disclosure mailing list! Legends of IdleOn is a popular free-to-play game on Android, iOS, Steam, and Web. While playing around with it last year, I got curious and noticed a trivial way to manipulate the random number generator.
After six months of radio silence from the developer, including asking the Discord moderators for help getting the developer's attention, I've decided to publish this publicly: https://gist.github.com/soatok/3cbf09501d1fd9e67e552c7165b0e81a Disclosure Timeline Note: All dates are in YYYY-MM-DD format (as per ISO 8601 and other standards). *Date* *Action* 2023-07-06 Emailed lava at lavaflame2 dot com with these details and a recommended fix. 2023-08-06 A month later, I follow up just asking if Lava has received my messages. 2023-11-15 Additional follow-up email 2023-11-15 Mentioned knowing an exploit in Discord, passed details onto moderator (*Hotair*) 2023-11-15 Additional follow-up email (as I cannot DM lava) 2024-01-16 Given a lack of repsonse after more than 6 months, public disclosure. Screenshots are also available <https://imgur.com/gallery/aMrpl5y> for some of my outreach attempts. <https://gist.github.com/soatok/3cbf09501d1fd9e67e552c7165b0e81a#exploit> Exploit This is easiest to do in the browser version of the game. You can use a Google Account for both Steam and Web in order to load an existing account in the web mode. Easy peasy. Press F12 to open your developer tools. Run the following code: // Make a native copy of your browser's Math.random functionMath.originalRandom = Math.random // Now replace itMath.random = () => Math.originalRandom() / 100000000000; Open the Arcade. Press Launch. Notice all of the balls always fall to the right. You can score unlimited jackpots. There are some other use cases where you want high numbers. There are yet others where you want to pingpong between high and low numbers for the desired effect. Math.originalRandom = Math.random;Math.lowRandom = function() { return Math.originalRandom() / 100000000000;} Math.highRandom = function() { return 1 - Math.lowRandom();} let breakCycle = false;function luckyCycle() { return setTimeout(function() { if (breakCycle) return; // console.log('rng on'); Math.random = Math.lowRandom; return setTimeout(function() { //console.log('rng off'); Math.random = Math.highRandom; return setTimeout(luckyCycle, 30000); }, 30000); });} Then you can just Math.random = /* desired other function, such as Math.lowRandom */ your way to winning big. <https://gist.github.com/soatok/3cbf09501d1fd9e67e552c7165b0e81a#impact> Impact - Millions of Gems <https://imgur.com/gallery/xR4Ie9o> - See https://soatok.idleonefficiency.com for what controlling RNG outputs looks like on an account <https://gist.github.com/soatok/3cbf09501d1fd9e67e552c7165b0e81a#mitigation> Mitigation Lava could mitigate this risk with one line of code, followed by a search and replace: + const LavaMath = Object.freeze(Math) And then replace any calls to Math.random with LavaMath.random, and then this would no longer be possible. (Yes, I included this one-liner in my email to Lava in July 2023.) <https://gist.github.com/soatok/3cbf09501d1fd9e67e552c7165b0e81a#advanced-exploit>Advanced Exploit Compile Chromium with a custom RNG that returns a low value (less than 0.000001) 9/10 times, then defers to the normal LCG the rest of the time. You'll win most luck-based things (Arcade Balls, Gaming Plants, etc.). The mitigation I suggest doesn't defend against this, but using a secure RNG instead of Math.random would likely generate farier numers *anyway*. <https://gist.github.com/soatok/3cbf09501d1fd9e67e552c7165b0e81a#update> Update The /r/idleon mods censored the link to this Gist from their subreddit <https://old.reddit.com/r/idleon/comments/197ypyv/legends_of_idleon_rng_manipulation/ki3xind/?context=4> (Archive <https://web.archive.org/web/20240116112102/https://old.reddit.com/r/idleon/comments/197ypyv/legends_of_idleon_rng_manipulation/> ). The actual exploit code that makes this an easy win is not included in this disclosure, but a clever mind can concoct their own with minimal iteration. After this disclosure, their community response has been limited to: 1. Censoring my post from Reddit 2. Falsely flagging my Steam Community post as an advertisement 3. Angry Discord PMs from people who think my goal is to "enable cheating" That does not include: 1. Mitigating the issue 2. Acknowledging the receipt of any of my attempts to disclose privately 3. Any communication whatsoever They have not succeeded in censoring my GitHub Gist, nor my review on the Steam store that links to my Gist, but that may be in the works. Thus, I thought I'd share it with Full Disclosure (with additional context). All URLs are also archived on archive.org and archive.today, should they attempt to invoke the Streisand Effect. Happy hacking, Soatok _______________________________________________ Sent through the Full Disclosure mailing list https://nmap.org/mailman/listinfo/fulldisclosure Web Archives & RSS: https://seclists.org/fulldisclosure/