SQL Dump Probing

I witnessed this attack recently, basically it's just some web crawler trying different file names that somebody could have given a mysql dump that they by accident left inside a public directory of a web project.

Disclaimer: What's explained in this post could be used in dual use cases. Explaining how the attacker works will ultimately help everybody preventing attacks and raise awareness for the attacks.

Now, I don't know who would do such a thing, but it's literally the worst idea to do, since it contains private data of your customers/subscribers or your own md5 hashed password or other stuff.

I was alerted to the attack by a graylog2 stream for 404 errors at work. I know it's maybe a bit paranoid, but we have that. Most of the times it's search engine bots or crawlers that try to access something that doesn't exist or try to post to some imaginary form they picked up in an XHR request.

This time the crawler was trying to download files with file names like

  • sql.sql
  • dump.sql
  • dump.tar.gz
  • dumper/dumper.php (added 2017-12-1)

and so on.

I have made a quick overview of file names and possibly file endings (it actually tries many of them).

base = [
    "backup",
    "db_backup",
    "db",
    "dbdump",
    "dump",
    "mysql",
    "site",
    "sql",
    "wordpress"
]

suffix = [
    ".gz",
    ".sql",
    ".tar.bz2",
    ".tar.gz",
    ".tgz",
    ".zip"
]

This strategy is very similar to what wpscan does to secure (or expose) your WordPress installation. Also CMSploit uses the same method just combined with a prefix, base and suffix for possible temporary editor file names of config files that contain database login information, which is about as bad.

In order to make a quick list of the file names I wrote a tiny double loop golang tool that generates a list of base names plus suffix for me:

package main

import(
    "fmt"

    "github.com/BurntSushi/toml"
)

type Config struct {
    BaseNames[]string `toml:"base"`
    Suffix []string `toml:"suffix"`
}

func main(){
    var conf Config

    if _, err := toml.DecodeFile("file-list.toml", &conf); err != nil {
        fmt.Println(err)
        return
    }

    fmt.Printf("%#v\n", conf.BaseNames)
    fmt.Printf("%#v\n", conf.Suffix)

    for _, base := range conf.BaseNames {
        for _, suf := range conf.Suffix {
            fmt.Println(base + suf)
        }
    }
}

So I assume the attacker has something that runs through a queue of domains and just tries HTTP GET requests with the file name combinations (and usually nobody looks in the 404 error logs):

package main

import(
    "fmt"
    "net/http"
//    "io/ioutil"

    "github.com/BurntSushi/toml"
)

type Config struct {
    BaseNames[]string `toml:"base"`
    Suffix []string `toml:"suffix"`
}

var domain string = "https://jonathanmh.com/"

func main(){
    var conf Config

    if _, err := toml.DecodeFile("file-list.toml", &conf); err != nil {
        fmt.Println(err)
        return
    }

    fmt.Printf("%#v\n", conf.BaseNames)
    fmt.Printf("%#v\n", conf.Suffix)

    for _, base := range conf.BaseNames {
        for _, suf := range conf.Suffix {
            fmt.Println("requesting "+domain+base + suf)
            resp, err := http.Get(domain+base+suf)
            if err != nil {
                fmt.Println(err)
            }
            defer resp.Body.Close()
//            body, err := ioutil.ReadAll(resp.Body)

            fmt.Println(resp.Status) // if this is not 404, something's there!
        }
    }
}

What my request function is missing is the queue for domains, parallel requests and what to do if a file has been found.

Fighting Back?

What can one do to prevent those attacks? I checked the IP addresses that the requests were made from and they are quite random, ranging from the Ukraine to the US. I assume proxied.

Now I originally had the idea to respond. Just very very very slowly. Maybe with a line by line piece of some lyrics

Never...
gonna...
let...
you...
down...
Never...
gonna...
give...
you...
up...

Maybe. I just today stumbled across that gzip bombs still are a thing: How to defend your website with ZIP bombs. Now that sounds like a good idea if you want to be taken off the list or at least slow down the attacker (if of course they would fall for that).

Since I expect that to be a quite automated process I'm optimistic it would go some way without discovery.

Now what's left to do is to write some rewrite rules for the web server that is being hit, either Apache2 or Nginx in most cases. Be prepared I wrote a small variation for that too that would just have to be adjusted for the zip bomb:

package main

import(
    "fmt"

    "github.com/BurntSushi/toml"
)

var target string = "http://www.fakeresponse.com/api/?sleep=10000"

type Config struct {
    BaseNames[]string `toml:"base"`
    Suffix []string `toml:"suffix"`
}

func main(){
    var conf Config

    if _, err := toml.DecodeFile("file-list.toml", &conf); err != nil {
        fmt.Println(err)
        return
    }

    fmt.Printf("%#v\n", conf.BaseNames)
    fmt.Printf("%#v\n", conf.Suffix)

    for _, base := range conf.BaseNames {
        for _, suf := range conf.Suffix {
            fmt.Printf("RedirectMatch 301 ^/%s %s\n", base+suf, target)
        }
    }
}

I'm looking forward to what's going to happen next and will first check if the shady bot actually follows HTTP redirects.

How do you deal with people probing your web projects? Did you ever actually have a file exposed?

Tagged with: #apache2 #cmsploit #infosec #insec #Nginx #sqlprobe

Thank you for reading! If you have any comments, additions or questions, please tweet or toot them at me!