By Sano
7/16/22
edited: 10/27/22
(special thanks to mark)
Bugs are everywhere – in games, in everyday software where they are played off as features, and in our own code.
So what do you do when you find a bug? Best practices would call for you to create a bug report and tell the party responsible (and maybe even get compensated – or at least thanked – for your efforts). When I found a security bug in Google Chrome I didn’t go the standard route. My first thought was "Man this would make a cool level in Hackpunk.”
Thanks for asking – and yes it was a leading question. Hackpunk is a game I am developing where you can write, play and distribute levels of a 3D puzzle game. (The elevator pitch is Super Mario Maker meets Roblox. I am not in love with that description but it usually gets the point across.)
Some might say the bug isn’t that big a deal – especially since it requires access to a user’s unlocked computer to exploit. But IMHO it is a serious security flaw – as is anything that exposes stored passwords.
Here’s the issue. When you want to see your stored site passwords in Google you would normally go to your settings in Chrome chrome://settings/passwords
. From there you would be asked to authenticate with the OS before seeing the actual password. This is a basic and reasonable security measure.
But in reality you don’t need to authenticate with the OS to see the stored password. Instead, just surf to the site in question – just don’t login. Instead, register for the site. Don’t worry about what username (or email) you’re using. But when it comes time to enter the password for the new account use the Autofill feature in Chrome to use the password associated with the account whose credentials you’re after. Now submit your faux registration. When you do so Chrome will politely ask you if you want to save the new faux credentials. In that dialog box there’s a convenient eye icon that when clicked reveals the password you are about to save. Congrats, you just exposed the stored password.
I call this the Autofill Leak. It has been confirmed to be an issue on MacOS and Windows.
- Get access to an unlocked computer.
- Go to the site from which you want the stored password
- Logout if the user is logged in.
- Register for the site using a new username or email
- When it comes time to set your password use the Chrome Autofill feature to set the password.
- Submit and Chrome will ask you if you want to save the password.
- In that dialog box click the eye icon next to the password
- You now have the password.
Yeah, that is the whole security flaw. I know what you’re thinking – who cares? The user has access to the unlocked computer anyway and can do a ton of damage (including logging into sites using stored credentials). But there are cases where the illicit access is short-term (typically for a temporarily unattended computer). This gives a hacker an opportunity to quickly harvest passwords for later usage. In addition, while I have not tested this, the hack may give an evil doer the ability to harvest passwords from a drive removed from a computer – passwords that are otherwise encrypted at rest and inaccessible.
Hackpunk uses a custom networking system and a unique interface builder that allows the in-game target IOT devices to have their own GUIs. In this codeblock we create a control for entering codes to unlock a door:
door_gui.lua
local num_buttons[]
local code
local username
local current_code
local clear
local gui = new GUI()
Start(){
--input field
username = gui.inputField("username")
-- password code
for i=1,i<10,i++ do
num_buttons[i] = gui.button(i * 1,i * 1,2,2,i.toString())
end
clear = gui.button(10,0,2,1,"clear")
}
Update(){
if clear.isPressed() do
current_code = ''
code = ''
end
if username in security.usernames
do
local window = gui.window.default('Autofill?')
local yes = gui.button(10,1,1,1,'yes')
if choice.isPressed() do
-- auto fill password for that username
current_code = security.hide(security.passwords.get(username))
else do
window.destroy()
end
end
if code.length == 4
do
if code in security.passwords
do
code = ''
-- show gui for 2 seconds
gui.window.approval('door open',2)
door.open
if !(username in security.usernames)
do
local window = gui.window.default('Save password?',5)
local eye = gui.button(10,1,1,1,'View password')
local shown = false
window.add(eye)
if eye.isPressed()
do
if(shown) do
currrent_code = security.show(current_code)
else do
current_code = security.hide(current_code)
end
end
end
else do
code = ''
gui.window.warning('wrong',2)
end
end
if gui.buttonPressedEvent.eventData in num_buttons
do
-- when the button is pressed to add to the code
code += gui.buttonPressedEvent.eventData.name
current_code = security.hide(code)
end
}
This code has deliberately recreated the bug I found in Chrome. If you use the same technique that I used to exploit the weakness in Chrome, you can open an in-game door that you would not otherwise be able to open.
Yeah! I have in the works a Lua-powered fully injectable GUI system. The way it works is pretty simple, it just leverages the Unity UI system but uses Lua commands to instantiate interface items.
So this is definitely something I have thought about a lot! My goal is to create a game that a relatively sophisticated player can wade right into – without having to study as if they were cramming for a big exam beforehand. Having said that, we also want to make resources available for the player who shows initiative. We plan to make available multiple booklets, handbooks and manuals. The idea of breaking up the manuals and having the player decide how to use them reflects the spirit of a hacking game. Nobody will be spoon fed solutions – but I also do not want them to feel like a failure. So there will be resources available to help them. And, just like in real life, the resources will range in quality. Expect to find some deliberately poor/obtuse writing – which will accurately reflect the actual state of the majority of real world documentation.
I hope savvy users print out the documentation and use them as guidebooks. But how to exactly play will be up to the user.
Man, I wish I was well thought out enough as a creative to say I have a well articulated design philosophy. In reality I just thought it was a cool thing to do: put a real world security flaw in my own game. And then I took it further and made security exploits the whole point of the game
I want players of the game to feel like they have found something out for themselves – to get that same great feeling I got when I found that Chrome bug. By looking at the in-game code they will be able to find and exploit mistakes made by other people and use them for their own goals. If the game player feels like a real hacker, I will have achieved my goal.
I guess if I had to state a design philosophy it would be that I want the player to experience what I have experienced.
The player/creator/hacker has many tools at their disposal including the aforementioned GUI system, Premade IOT devices (that they can customize) and a level designer.
The level design of Hackpunk is very clear. The idea is if you were stuck in a room with nothing but a computer would you be able to get out of your imprisonment.
By the way, though the level builder is still in the works, it was pretty much stolen beat for beat from the good people at Valve. I love their portal level editor.
Level design for a puzzle game is key because you need the level design to guide players. You need to engineer serendipity, which will mean players will stumble upon hints to the solution of the problem. The way I like to look at it is this: player interacts with world -> world reveals itself to player -> player finds new ways to interact with world
and so on. Level design is definitely a great way to telegraph things to the players and can be discussed further in another dev log.