Learning code review by hunting 0days in public code repositories

Learning code review by hunting 0days in public code repositories

·

7 min read

Intro:

Hello there! I am Centaurus, I always wanted to get involved with secure code review but I've never had the chance to do so... Or should I say I was just intimidated by it, so what's a better way to learn hacking other than just hacking something?

Summary:

For this blog, we will be looking at the source code of a public "Php" CMS that has few stars and few forks, so it's not a famous one, well it's perfect for me as someone who is just getting started with code review. I won't be sharing the CMS name ofc for privacy reasons, and for what it is worth the CMS is archived by now, nevertheless, by the time this blog post goes public the developer will be informed about the findings. Yet it's worth noting that since the repository is archived I am not responsible for whether the dev mitigates the bugs or not...

Setting things up:

Since the CMS uses "Php" and "MySQL", I didn't want to go through any troubles and I just used XAMPP to host the project locally. Next, I created a database and imported the project's SQL schema into it. Yep that's it we good to go... Well not this fast, we will also need Burp to inspect the HTTP traffic and VScode to browse the project's code.

Unauthenticated findings:

Unauthenticated error-based SQLi:

My approach was pretty basic, I noticed that the CMS provides some unauthenticated features such as a search box so logically I would test those endpoints before moving to the authenticated ones:

To my surprise, although the devs used mysqli_real_escape_string within the registration process and other endpoints, they forgot about it in the search feature. This is what the code looked like:

The devs referenced the user-controlled search parameter directly into the SQL query without applying any filters or parameterization to the user-supplied value. Essentially the query had a die function that would throw an error if your search value broke the SQL syntax

PoC:

Category unauthenticated SQLi:

This is no different than the previous one. The CMS supported listing posts based on their categories, and apparently, each category had its ID, the URL looked like this http://localhost/category.php?category=1 and by looking at the code within the category.php file, as expected the ID was referenced within the SQL query with no filtering of any kind.

PoC 1:

If you haven't noticed yet, there are two different queries within the code, the first one for a user with the "Admin" role and the second one for regular users. Basically, the admin can see every post including drafts while regular users or unauthenticated visitors can only see the published posts

In this case, if we use the SQLi to comment out the rest of the query AND post_status = 'published' we can every post including the drafts even tho we are not authenticated, this can be exploited by supplying the category ID and a comment as follows http://localhost/category.php?category=1--+

PoC 2:

Retrieving data from the database:

Author unauthenticated SQLi:

Again this is no different than the previous ones, a single quoted SQLi within the WHERE clause context. but this time in another endpoint that allows the listing of posts based on the author's name. The URL looked as follows http://localhost/author_posts.php?author=admin&p_id=1 and while the p_id parameter looks like a good target for SQLis it's the author parameter that is vulnerable. The vulnerable code was within the author_posts.php file as follows:

PoC:

Authenticated findings:

At this point, I ran out of unauthenticated endpoints and decided to start the post-authentication testing, for this, I used two accounts 1 administrative account and another low-user account. Having accounts with different privileges is useful for many attack vectors such as blind xss's or privileges escalation bugs.

Blind XSS ( low privilege user ):

To my surprise, the low privileges user's account had almost no functionalities, except one feature that allowed it to comment on published posts. So what are the attack vectors here? Stored XSS and CSRF? yes, they're both correct guesses, but user's comments must be approved by an admin. This fact makes the logic behind both attacks very unlikely or at least increases the complexity of the attack. But again every feature can introduce a bug, the fact that the admin has to approve comments tells us that he's going to see whatever content we submit, so let's take a look at how our comments are reflected within the admin panel and the code.

Fair enough the admin panel looks fancy, but is the code fancy too? Apparently, the comments on the admin panel are handled by a file called view_all_comments.php. This is the code:

So to keep it short, this code fetches every comment from the database, and reflects it within the admin panel using the echo function of "Php" and as expected no filters are used, which introduced a blind xss within the admin panel. So in other words a regular user would submit <svg/onload=alert(document.domain)> as a comment and by the time the admin opens the comment section to approve or un-apporove a comment the XSS payload will be executed.

This ofc would allow a low privileges user to perform any action on behalf of the admin. It should be noted that blind XSS's are just regular stored/persistent XSS's that are executed in contexts that require additional privileges.

Remote code execution ( Admin privileges ):

The admin account settings provide a file upload feature for a profile picture. Mainly the admin settings were handled by a code located at the profile.php file. By looking at the file upload code it was clear to me that the feature is vulnerable to an unrestricted file upload vulnerability that most likely would lead to an RCE:

So basically what the code does is just receive a file and place it within this path ../images/<image_name> This means we need to traverse from the admin directory to the web root to access our uploaded image. Secondly I don't see any restrictions applied to the feature itself so we would be able to upload a Php webshell and execute it.

PoC:
Uploading the webshell:

Accessing the webshell and executing commands:

Honestly, bugs within admin panels never surprise me, as it's expected to be a safe zone that is accessed only by trusted admins. But this is a misconception for instance we could have used the previous blind XSS to gain access to the admin panel and pivot to the server using the unrestricted file upload.

This vulnerability also exists within the add_posts.php code which is responsible for publishing new blog posts:

But before I close this blog, it is worth noting that the image name is actually not escaped, it would look like the dev has escaped every other parameter that is referenced within the SQL query but totally forgot about the image name. And since the dev is using the Php die function to echo errors into HTTP responses we could simply trigger the SQLi by adding a single quote at the end of the file name.

From admin privileges RCE to User Privilege RCE:

Now since we got a remote code execution, it's still a requirement that we have admin privileges to exploit it, well we could do better. I have tried to look for ways to create posts or upload images using my low privileges user's session, this is usually by replacing the administrative session using our low privileges user session, but nevertheless, none of what I tried worked until I noticed this endpoint http://localhost/admin/posts.php?source=edit_post&p_id=3, This administrative endpoint allows the admin to edit posts after they have been published, so let's take a look at the posts.php code.

So the posts.php code is expecting a source parameter to route the GET parameters to another backend code, which is the edit_post.php in my case.

And there it is, the backend code doesn't actually check the session of whoever issued the request, in other words a low privileges user can issue an HTTP requests to edit one of the posts and submit a webshell instead of an actual post image. This privileges escalation bug allowed me to exploit the unrestricted file upload RCE with my low privileges user and since the CMS allows self registration this is almost an unauthenticated RCE. It's also worth noting that this would also allow us to exploit the SQLi within the file name of the image.

Conclusion:

Although there are still other bugs I haven't mentioned within this blog, I think that this blog is getting too long and boring, also the remaining bugs are just your typical stored XSS that require administrative privileges, SQLis within the admin panel, and CSRFs within administrative actions. I will probably share them within the second part of this blog. But for now have a great day, night, weekend or whenever this post finds you.