initial
This commit is contained in:
commit
ec6e16eae6
28
README.md
Normal file
28
README.md
Normal 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
19
go.mod
Normal 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
27
go.sum
Normal 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
140
index.html
Normal 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
219
main.go
Normal 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()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user