Skip to content

Commit

Permalink
Add DNS tests
Browse files Browse the repository at this point in the history
  • Loading branch information
juffalow committed Jul 26, 2024
1 parent 45568ae commit 4092624
Show file tree
Hide file tree
Showing 9 changed files with 371 additions and 4 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"node-fetch": "^2.6.0",
"ssl-checker": "^2.0.7",
"uglify-js": "^3.6.1",
"whois": "^2.14.2",
"xml2js": "^0.4.22"
},
"repository": {
Expand Down
5 changes: 5 additions & 0 deletions src/Pentest.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,34 @@
import Security from './security';
import DNS from './dns';
import HTML from './html';
import SEO from './seo';
import WordPress from './wordpress';
import { Result } from './Test';

interface PentestResult {
security: Result;
dns: Result;
html: Result;
seo: Result;
wordpress: Result;
}

class Pentest {
public async run(url: string): Promise<PentestResult> {
const general = new DNS();
const security = new Security();
const html = new HTML();
const seo = new SEO();
const wordPress = new WordPress();
const generalResult = <Result> await general.run({ url });
const securityResult = <Result> await security.run({ url });
const htmlResult = <Result> await html.run({ url });
const seoResult = <Result> await seo.run({ url });
const wordPressResult = <Result> await wordPress.run({ url });

return {
security: securityResult,
dns: generalResult,
html: htmlResult,
seo: seoResult,
wordpress: wordPressResult,
Expand Down
55 changes: 55 additions & 0 deletions src/dns/A.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import dns from 'dns';
import whois from 'whois';
import Test, { TestParameters, Result } from '../Test';
import logger from '../logger';

class A extends Test {
public name = 'A';

public async test({ url }: TestParameters): Promise<Result> {
logger.info(`Starting ${this.constructor.name} test...`);

const response = await new Promise((resolve, reject) => {
dns.lookup((new URL(url).hostname), { all: true }, (err, addresses) => {
if (err) {
reject(err);
}

resolve(addresses);
});
});

const addresses = await Promise.all((response as any).map(async (address: any) => {
const organization = await this.getOrganization(address.address);

return `${address.address} - ${organization}`;
}));

return {
status: 'SUCCESS',
title: this.constructor.name,
description: addresses.join('\n'),
};
}

protected async getOrganization(ip: string): Promise<string> {
const organization: string = await new Promise((resolve, reject) => {
whois.lookup(ip, function(err, data) {
if (err) {
reject(err);
}

const organization = data.split('\n')
.filter((line: string) => line.includes('OrgName'))
.map((line: string) => line.split(':')[1].trim())
.pop();

resolve(organization);
});
});

return organization;
}
}

export default A;
63 changes: 63 additions & 0 deletions src/dns/DMARC.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import dns from 'dns';
import Test, { TestParameters, Result } from '../Test';
import logger from '../logger';

class DMARC extends Test {
public name = 'DMARC';

public async test({ url }: TestParameters): Promise<Result> {
logger.info(`Starting ${this.constructor.name} test...`);

const response: any = await new Promise((resolve, reject) => {
dns.resolveTxt(`_dmarc.${(new URL(url).hostname)}`, (err, records) => {
if (err) {
reject(err);
}

resolve(records);
});
});

if (response.length === 0) {
return {
status: 'WARNING',
title: this.constructor.name,
description: 'No DMARC record found for this domain.',
}
}

const record = response.shift().shift();

if (record.includes('p=none')) {
return {
status: 'ERROR',
title: this.constructor.name,
description: 'Email that fails DMARC Compliance tests will be delivered to the recipient\'s inbox.',
};
}

if (record.includes('p=quarantine')) {
return {
status: 'WARNING',
title: this.constructor.name,
description: 'Email that fails DMARC Compliance tests will be marked as spam.',
};
}

if (record.includes('p=reject')) {
return {
status: 'SUCCESS',
title: this.constructor.name,
description: 'Email that fails DMARC Compliance tests will be rejected.',
};
}

return {
status: 'ERROR',
title: this.constructor.name,
description: 'Invalid DMARC policy found!',
};
}
}

export default DMARC;
39 changes: 39 additions & 0 deletions src/dns/NS.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import whois from 'whois';
import Test, { TestParameters, Result } from '../Test';
import logger from '../logger';

class NS extends Test {
public name = 'NS';

public async test({ url }: TestParameters): Promise<Result> {
logger.info(`Starting ${this.constructor.name} test...`);

const nameServers = await this.getNameServers((new URL(url).hostname));

return {
status: 'SUCCESS',
title: this.constructor.name,
description: nameServers.join('\n'),
};
}

protected async getNameServers(domain: string): Promise<string[]> {
const nameServers: string[] = await new Promise((resolve, reject) => {
whois.lookup(domain, function(err, data) {
if (err) {
reject(err);
}

const nameServers = data.split('\n')
.filter((line: string) => line.includes('Name Server'))
.map((line: string) => line.split(':')[1].trim());

resolve(nameServers);
});
});

return nameServers;
}
}

export default NS;
43 changes: 43 additions & 0 deletions src/dns/RegistrationDate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import whois from 'whois';
import Test, { TestParameters, Result } from '../Test';
import logger from '../logger';

class RegistrationDate extends Test {
public name = 'RegistrationDate';

public async test({ url }: TestParameters): Promise<Result> {
logger.info(`Starting ${this.constructor.name} test...`);

const registrationDate = await this.getRegistrationDate((new URL(url).hostname));

const diffInMs = (new Date(registrationDate)).getTime() - (new Date()).getTime();
const diffInDays = diffInMs / (1000 * 60 * 60 * 24);

return {
status: diffInDays < 7 ? 'ERROR' : diffInDays < 30 ? 'WARNING' : 'SUCCESS',
title: this.constructor.name,
description: `Approximately ${Math.floor(diffInDays)} days until domain expires.`,
};
}

protected async getRegistrationDate(domain: string): Promise<string> {
const date: string = await new Promise((resolve, reject) => {
whois.lookup(domain, function(err, data) {
if (err) {
reject(err);
}

const d = data.split('\n')
.filter((line: string) => line.includes('Expiration Date'))
.map((line: string) => line.split(': ')[1].trim())
.shift();

resolve(d);
});
});

return date;
}
}

export default RegistrationDate;
47 changes: 47 additions & 0 deletions src/dns/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import Test, { TestParameters, Result } from '../Test';
import A from './A';
import NS from './NS';
import DMARC from './DMARC';
import RegistrationDate from './RegistrationDate';

export default class DNS extends Test {
public name = 'DNS';

constructor() {
super();
this.tests = [
new RegistrationDate(),
new NS(),
new A(),
new DMARC(),
];
}

public async test(params: TestParameters): Promise<Result> {
const tests = this.getTests();
const results = [];

for (const test of tests) {
let result = null;

try {
result = await test.run(params);
} catch (error) {
result = {
status: 'ERROR',
title: test.name,
description: 'Test failed or cannot be run!',
}
}

results.push(result);
}

return {
status: this.getStatus(results.map(result => result.status)),
title: this.name,
description: '',
results,
};
}
}
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ program
const results = await pentest.run(url);

const report = Report.get(config.report.format);
report.write([ results.security, results.html, results.seo, results.wordpress ]);
report.write([ results.security, results.dns, results.html, results.seo, results.wordpress ]);
});

program
Expand Down
Loading

0 comments on commit 4092624

Please sign in to comment.