As you likely know, we have two public demos of Snipe-IT, the version that’s on the master branch, and the version that’s on develop. We’ve had these public demos for years, so we’ve learned a thing or two about how people behave on public demos. 99% of the time, folks use the demos for their intended purpose, but that 1% can make things really annoying.
We’ve seen it all, truly, from clowns trying to say they “hacked” the application because they changed the site name – a field that is editable in the settings, so hardly a hack – to “Hacked by Blah”, to folks legitimately trying to discover exploits.
We’re open source, so one would think they would just download a copy of the software and hack to their hearts content, but hey, whatever. More on that later.
It always feel kind of gross to me to have to put extra code into the software specifically because of the demo (disallowing fields to be edited that would normally be editable, disallowing uploads, etc), but sometimes we have to do that. (Nothing quite like the embarrassment of being on a sales call with a potential customer and they noticed that someone changed a username on the demo to something profane. This is also why we reset the demo database every hour. Sigh.)
We constantly monitor our systems errors using a variety of tooling, and one that we have always found incredibly valuable is Rollbar. They’re affordable and give real-time error alerting on 500 errors, javascript errors, etc.
This evening, we caught a few weird rollbars coming through on the demo that we’ve never seen on a hosted instance, so we immediately checked it out.
Before we continue, I want to be VERY clear that this was not a security incident, and Snipe-IT users do not need to be concerned about the security and integrity of their systems. This story is just about one of the many ways we use tools to identify and thwart bad actors.
A few things stood out right away. First, the 500s were coming through on the login, which we never see any issues with. Second, the requests were all coming from the same IP – a windows machine running Chrome, with an IP out of Pakistan. (These headers can easily be forged though, so it’s more about the pattern than the actual browser/OS.)
We could easily (and have in the past) block them at the server level, since this is clearly abuse of our systems, but we decided to dig a little deeper. (What else does one do on a Saturday night, right?)
The particular error it was triggering was:
TypeError mb_strtolower(): Argument #1 ($string) must be of type string, array given
which is strange, since there are no array fields on the login, and all of that magic happens on the Laravel backend.
The stack trace pointed to this section of app/Http/Controllers/Auth/LoginController.php:556:
return $this->limiter()->tooManyAttempts( $this->throttleKey($request), // this is the line that was throwing the error $maxLoginAttempts, $lockoutTime );
Here’s where Rollbar comes in again, this time for quickly identifying problem actors. We noticed there were fields being posted to the login form that we don’t actually have on the login page, which clearly indicates that someone was editing the DOM in their browser and adding those fields to post to the form (or using an http intercept tool to be able to post arbitrary fields – either way, the method doesn’t really matter.)
In Laravel, arrays are noted with the array key appended, so this means someone was posting form fields with the names of username.$acunetix
and username[]
, neither of which are valid form field names for our login.
They also tried to pass us a java payload (lol we don’t run java) to execute a wget
or cURL
to an XSS site:
So it’s now crystal clear what this person was doing. They were throwing random field payloads at the login to see if they could trigger an XSS attack or an RCE.
The 500 was triggered because Laravel’s login throttling handler isn’t expecting an array for the username field, so it caused a crash.
The fix here was very simple. We have a custom validator called not_array
, which prevents people from sending array payloads when a string is expected, so we implemented that on the username and password fields, since there would never be a valid reason to pass an array there.
You’ll see this kind of thing a lot with public demos, especially from folks looking to get a few bucks from the maintainer/company by disclosing the issue in return for payment (aka “beg bounty programs”).
TLDR;
To the baby hackers out there, this is why you download and run the code yourself. When you trigger weird errors, we can see what you’re doing.
To the aspiring blue-teamers and developers out there, remember that even non-security tools can provide super useful information.
Until next time, continue to Kick Assets!