From ec6e16eae66c3c033599a11959ec3511aa28aef5 Mon Sep 17 00:00:00 2001 From: delorean Date: Tue, 27 Jun 2023 18:27:29 -0500 Subject: [PATCH] initial --- README.md | 28 +++++++ go.mod | 19 +++++ go.sum | 27 +++++++ index.html | 140 ++++++++++++++++++++++++++++++++++ main.go | 219 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 433 insertions(+) create mode 100644 README.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 index.html create mode 100644 main.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..852a0f5 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +# evilcloud + +file upload service, with a dark side. + +spawns a fully functional file uploading app that logs relevant ip and browser information on whoever visits uploaded files. very effective when paired with a convincing domain (picbin.co, filebin.org, etc). + +# usage + +1. cloaked irc user or discord nerd says ur mom's a hoe +2. you upload a pic/video/whatever file to evilcloud +3. you send the person the link returned (ex. https://image-box.co/uploads/fj238as3.png), make them think it's some titties or something, get creative +4. victim clicks the link, thinking it's yet another image upload site, nothing to worry about +5. your console lights up with their ip and browser info paired with whatever uri was visited +6. profit + +# installation + +don't forget to create tls keys (ex. with letsencrypt) for the domain + +``` +git clone https://git.supernets.org/delorean/evilcloud +edit the global config vars in main.go to your liking +go mod tidy +go build . +./evilcloud +``` + + diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f25ebcf --- /dev/null +++ b/go.mod @@ -0,0 +1,19 @@ +module evilcloud + +go 1.20 + +require ( + github.com/boltdb/bolt v1.3.1 + github.com/gabriel-vasile/mimetype v1.4.2 + github.com/gorilla/mux v1.8.0 + github.com/landlock-lsm/go-landlock v0.0.0-20230225094210-7a98d7db83f2 + github.com/rs/zerolog v1.29.1 +) + +require ( + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.6.0 // indirect + kernel.org/pub/linux/libs/security/libcap/psx v1.2.66 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..825f36e --- /dev/null +++ b/go.sum @@ -0,0 +1,27 @@ +github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/landlock-lsm/go-landlock v0.0.0-20230225094210-7a98d7db83f2 h1:kTSOM+yiVubrJQI/LJ67EGxYqrqC0C5VkfRurbFg7J4= +github.com/landlock-lsm/go-landlock v0.0.0-20230225094210-7a98d7db83f2/go.mod h1:oCxtVqzP6dNPgAQK+4okeQk9BcxjkttF8MG4DmoT6Sk= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc= +github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +kernel.org/pub/linux/libs/security/libcap/psx v1.2.66 h1:ikIhPzfkSSAEwBOU+2DWhoF+xnGUhvlMTfQjBVhvzQY= +kernel.org/pub/linux/libs/security/libcap/psx v1.2.66/go.mod h1:+l6Ee2F59XiJ2I6WR5ObpC1utCQJZ/VLsEbQCD8RG24= diff --git a/index.html b/index.html new file mode 100644 index 0000000..ce8f457 --- /dev/null +++ b/index.html @@ -0,0 +1,140 @@ + + + + + + filetray + + + +
+

filetray

+
+
+
+
Choose File
+
No file chosen...
+ +
+
+ + +
+
+ + + + diff --git a/main.go b/main.go new file mode 100644 index 0000000..df17607 --- /dev/null +++ b/main.go @@ -0,0 +1,219 @@ +package main + +import ( + "crypto/tls" + "fmt" + "io" + "math/rand" + "net/http" + "os" + "strconv" + "strings" + "time" + + "github.com/boltdb/bolt" + "github.com/gabriel-vasile/mimetype" + "github.com/gorilla/mux" + "github.com/landlock-lsm/go-landlock/landlock" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" +) + +var db *bolt.DB + +// config +var ( + index = "index.html" + folder = "data" + dbfile = "dbfile.db" + filelen = 6 + lport = "443" + vhost = "filetray.co" + key = "privkey.pem" + cert = "cert.pem" +) + +// end config + +func redir(w http.ResponseWriter, r *http.Request) { + target := "https://" + r.Host + r.URL.Path + if len(r.URL.RawQuery) > 0 { + target += "?" + r.URL.RawQuery + } + http.Redirect(w, r, target, + http.StatusTemporaryRedirect) +} + +func NameGen() string { + const chars = "abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ123456789" + ll := len(chars) + b := make([]byte, filelen) + rand.Read(b) // generates len(b) random bytes + for i := int64(0); i < int64(filelen); i++ { + b[i] = chars[int(b[i])%ll] + } + return string(b) +} + +func CheckFile(name string) bool { // false if doesn't exist, true if exists + tfd, err := os.Open(folder + "/" + name) + if err != nil { + return false + } + tfd.Close() + return true +} + +func UploadHandler(w http.ResponseWriter, r *http.Request) { + // expiry sanitize + sanExpiry := int64(86400) + + file, _, err := r.FormFile("file") + if err != nil { + w.WriteHeader(http.StatusBadRequest) + return + } + defer file.Close() + + mtype, err := mimetype.DetectReader(file) + if err != nil { + w.Write([]byte("error detecting the mime type of your file\n")) + return + } + file.Seek(0, 0) + + // generate + check name + var name string + for { + id := NameGen() + name = id + mtype.Extension() + if !CheckFile(name) { + break + } + } + + err = db.Update(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte("expiry")) + err := b.Put([]byte(name), []byte(strconv.FormatInt(time.Now().Unix()+sanExpiry, 10))) + return err + }) + if err != nil { + log.Error().Err(err).Msg("Failed to put expiry") + } + + log.Info().Int64("expiry", sanExpiry).Msg("Writing new file") + + f, err := os.OpenFile(folder+"/"+name, os.O_WRONLY|os.O_CREATE, 0644) + if err != nil { + log.Error().Err(err).Msg("Error opening a file for write") + w.WriteHeader(http.StatusInternalServerError) // change to json + return + } + defer f.Close() + + io.Copy(f, file) + + w.Write([]byte("https://" + vhost + "/uploads/" + name)) +} + +func Expiry() { + for { + removed := 0 + db.Update(func(tx *bolt.Tx) error { + b := tx.Bucket([]byte("expiry")) + c := b.Cursor() + for k, v := c.First(); k != nil; k, v = c.Next() { + expiryTime, err := strconv.ParseInt(string(v), 10, 64) + if err != nil { + log.Error().Err(err).Bytes("k", k).Bytes("v", v).Msg("Expiry time could not be parsed") + continue + } + if time.Now().After(time.Unix(expiryTime, 0)) { + os.Remove(folder + "/" + string(k)) + removed += 1 + c.Delete() + } + } + return nil + }) + if removed >= 1 { + log.Info().Int("amount", removed).Msg("Purged based on expiry") + } + time.Sleep(5 * time.Second) + } +} + +func main() { + log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) + + err := landlock.V2.BestEffort().RestrictPaths( + landlock.RWDirs("./"+folder), + landlock.RWFiles(dbfile), + landlock.RWFiles(index), + ) + + if err != nil { + log.Warn().Err(err).Msg("Could not landlock") + } + + _, err = os.Open("/etc/passwd") + if err == nil { + log.Warn().Msg("Landlock failed, could open /etc/passwd") + } else { + log.Info().Err(err).Msg("Landlocked") + } + + db, err = bolt.Open(dbfile, 0600, nil) + if err != nil { + log.Fatal().Err(err).Msg("dangerous database activity") + } + db.Update(func(tx *bolt.Tx) error { + _, err := tx.CreateBucketIfNotExists([]byte("expiry")) + if err != nil { + log.Fatal().Err(err).Msg("Error creating expiry bucket") + return err + } + return nil + }) + + r := mux.NewRouter() + r.HandleFunc("/", UploadHandler).Methods("POST") + r.HandleFunc("/uploads/{name}", func(w http.ResponseWriter, r *http.Request) { // upload hits + vars := mux.Vars(r) + if !CheckFile(vars["name"]) { + w.WriteHeader(http.StatusNotFound) + } else { + t := time.Now() + deets := fmt.Sprintf("HIT -> %s visited by %s at %d:%d %s %d\n `--- User Agent: %s", r.RequestURI, strings.Split(r.RemoteAddr, ":")[0], t.Hour(), t.Minute(), t.Month(), t.Day(), r.UserAgent()) + log.Info().Err(err).Msg(deets) + + http.ServeFile(w, r, folder+"/"+vars["name"]) + } + }).Methods("GET") + r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + http.ServeFile(w, r, index) + }).Methods("GET") + http.Handle("/", r) + + go Expiry() + + serv := &http.Server{ + Addr: ":" + lport, + Handler: r, + ErrorLog: nil, + //ReadTimeout: 20 * time.Second, + //WriteTimeout: 20 * time.Second, + IdleTimeout: 20 * time.Second, + TLSConfig: &tls.Config{ServerName: "heehee"}, + } + + log.Info().Err(err).Msg("Listening...") + + go http.ListenAndServe(":80", http.HandlerFunc(redir)) + if err := serv.ListenAndServeTLS(cert, key); err != nil { + log.Fatal().Err(err).Msg("Error starting TLS server") + } + + db.Close() +} +