This commit is contained in:
delorean 2023-06-27 18:27:29 -05:00
commit ec6e16eae6
5 changed files with 433 additions and 0 deletions

28
README.md Normal file
View File

@ -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
```

19
go.mod Normal file
View File

@ -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
)

27
go.sum Normal file
View File

@ -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=

140
index.html Normal file
View File

@ -0,0 +1,140 @@
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="//code.jquery.com/jquery-1.10.2.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>filetray</title>
<style>
body {
font-family: sans-serif;
background-image: url('https://i.pinimg.com/originals/fd/b2/1c/fdb21c0e4f3dbb6ccd9a63c68fce8645.gif');
background-size: cover;
}
@media (prefers-color-scheme: dark) {
body {
background: black;
background-image: url('https://i.pinimg.com/originals/fd/b2/1c/fdb21c0e4f3dbb6ccd9a63c68fce8645.gif');
background-size: cover;
color: white;
}
}
.container {
padding-right: 15px;
padding-left: 15px;
margin-right: auto;
margin-left: auto;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}
@media (min-width: 768px) {
.container {
width: 750px;
}
}
@media (min-width: 992px) {
.container {
width: 970px;
}
}
@media (min-width: 1200px) {
.container {
width: 1170px;
}
}
input,select {
margin-bottom: 1em;
}
.file-upload{display:block;text-align:center;font-family: Helvetica, Arial, sans-serif;font-size: 12px; margin-bottom: 20px; width: 300px;}
.file-upload .file-select{display:block;border: 2px solid #dce4ec;color: #34495e;cursor:pointer;height:40px;line-height:40px;text-align:left;background:#FFFFFF;overflow:hidden;position:relative;}
.file-upload .file-select .file-select-button{background:#dce4ec;padding:0 10px;display:inline-block;height:40px;line-height:40px;}
.file-upload .file-select .file-select-name{line-height:40px;display:inline-block;padding:0 10px;}
.file-upload .file-select:hover{border-color:#34495e;transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;}
.file-upload .file-select:hover .file-select-button{background:#34495e;color:#FFFFFF;transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;}
.file-upload.active .file-select{border-color:#3fa46a;transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;}
.file-upload.active .file-select .file-select-button{background:#3fa46a;color:#FFFFFF;transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;}
.file-upload .file-select input[type=file]{z-index:100;cursor:pointer;position:absolute;height:100%;width:100%;top:0;left:0;opacity:0;filter:alpha(opacity=0);}
.file-upload .file-select.file-select-disabled{opacity:0.65;}
.file-upload .file-select.file-select-disabled:hover{cursor:default;display:block;border: 2px solid #dce4ec;color: #34495e;cursor:pointer;height:40px;line-height:40px;margin-top:5px;text-align:left;background:#FFFFFF;overflow:hidden;position:relative;}
.file-upload .file-select.file-select-disabled:hover .file-select-button{background:#dce4ec;color:#666666;padding:0 10px;display:inline-block;height:40px;line-height:40px;}
.file-upload .file-select.file-select-disabled:hover .file-select-name{line-height:40px;display:inline-block;padding:0 10px;}
.subform {
display: flex;
flex-direction: column;
align-items: center;
}
button {
display: inline-block;
border: 0;
outline: 0;
margin: 0;
padding: 15px;
height: 44px;
color: #fff;
font: 19px/15px 'Oswald', 'HelveticaNeue', 'Helvetica Neue', Helvetica, Arial, "Lucida Grande", sans-serif;
font-weight: bold;
text-transform: uppercase;
cursor: pointer;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
-moz-box-sizing: border-box; /* Firefox, other Gecko */
box-sizing: border-box; /* Opera/IE 8+ */
-webkit-font-smoothing:antialiased;
-webkit-text-size-adjust:none;
box-shadow: 0 1px 2px rgba(0,0,0,.15);
}
button:hover {
background: #c93c1d;
-webkit-transition:all .25s ease-in-out;
-moz-transition:all .25s ease-in-out;
-o-transition:all .25s ease-in-out;
transition:all .25s ease-in-out;
}
button:active {
background: #ae3318;
}
button.light {
background: #fff;
color: #555759;
}
button.light:hover {
background: #ff009d;
color: #fff;
}
</style>
</head>
<body>
<div class="container">
<h1 style="font-size: 3em; color: #ffffff;">filetray</h1>
<form method="POST" class="subform" enctype="multipart/form-data">
<div class="file-upload">
<div class="file-select">
<div class="file-select-button" id="fileName">Choose File</div>
<div class="file-select-name" id="noFile">No file chosen...</div>
<input type="file" name="file" id="chooseFile">
</div>
</div>
<!-- <input type="file" name="file" /> -->
<button class="light" type="submit">upload</button>
</form>
</div>
</body>
</html>
<script>
$('#chooseFile').bind('change', function () {
var filename = $("#chooseFile").val();
if (/^\s*$/.test(filename)) {
$(".file-upload").removeClass('active');
$("#noFile").text("No file chosen...");
}
else {
$(".file-upload").addClass('active');
$("#noFile").text(filename.replace("C:\\fakepath\\", ""));
}
});
</script>

219
main.go Normal file
View File

@ -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()
}