Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Tls Tester #6

Merged
merged 2 commits into from
Sep 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ module.exports = {
'import/no-unresolved': ['error', { commonjs: true }],
'no-unused-expressions': ['error', { allowShortCircuit: true, allowTernary: true }],
'object-curly-newline': ['error', { multiline: true }],
'no-multiple-empty-lines': ['error', { max: 2, maxBOF: 0, maxEOF: 1 }]
'no-multiple-empty-lines': ['error', { max: 2, maxBOF: 0, maxEOF: 1 }],
'newline-per-chained-call': 'off'
},
env: { node: true },
parserOptions: { ecmaVersion: 2021 },
parser: 'babel-eslint', // required for private class members as eslint only supports ECMA Stage 4, will be able to remove in the future
settings: {
'import/resolver': {
node: {
Expand Down
7 changes: 2 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ config.*.json
!config.test.json

.vscode
*.code-workspace
logs
# avajs
.nyc_output
coverage/



77 changes: 77 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
FROM node:14-alpine

ARG LOCAL_USER_ID
ARG LOCAL_GROUP_ID

# Create an environment variable in our image for the non-root user we want to use.
# ENV USER 1000
ENV USER tls_scanner
ENV GROUP purpleteam
ENV TESTSSL_VERSION 3.0.5
RUN echo user is: ${USER}, LOCAL_USER_ID is: ${LOCAL_USER_ID}, group is: ${GROUP}, LOCAL_GROUP_ID is: ${LOCAL_GROUP_ID}

# Following taken from: https://github.com/mhart/alpine-node/issues/48#issuecomment-430902787
RUN apk add --no-cache shadow && \
apk add --no-cache bash procps drill git coreutils libidn curl socat openssl xxd && \
if [ -z "`getent group $LOCAL_GROUP_ID`" ]; then \
addgroup -S -g $LOCAL_GROUP_ID $GROUP; \
else \
groupmod -n $GROUP `getent group $LOCAL_GROUP_ID | cut -d: -f1`; \
fi && \
if [ -z "`getent passwd $LOCAL_USER_ID`" ]; then \
adduser -S -u $LOCAL_USER_ID -G $GROUP -s /bin/sh $USER; \
else \
usermod -l $USER -g $LOCAL_GROUP_ID -d /home/$USER -m `getent passwd $LOCAL_USER_ID | cut -d: -f1`; \
fi

# Useful for running commands as root in development
# RUN apk add --no-cache sudo && \
# echo "$USER ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/$USER && \
# chmod 0440 /etc/sudoers.d/$USER

ENV WORKDIR /usr/src/app/

# Home is required for npm install. System account with no ability to login to shell
# For standard node image:
#RUN useradd --create-home --system --shell /bin/false $USER
# For node alpine:
# RUN addgroup -S $USER && adduser -S $USER -G $GROUP

RUN mkdir -p $WORKDIR && chown $USER:$GROUP --recursive $WORKDIR

WORKDIR $WORKDIR

RUN curl -sSL https://github.com/drwetter/testssl.sh/archive/refs/tags/${TESTSSL_VERSION}.tar.gz > testssl.sh-${TESTSSL_VERSION}.tar.gz && \
mkdir --mode=750 --parents ${WORKDIR}unpack-testssl/ ${WORKDIR}testssl/ ${WORKDIR}testssl/etc/ ${WORKDIR}testssl/bin/ && \
tar --extract --file=testssl.sh-${TESTSSL_VERSION}.tar.gz --directory=${WORKDIR}unpack-testssl/ --strip 1 && \
cp -r ${WORKDIR}unpack-testssl/etc/. ${WORKDIR}testssl/etc/ && \
cp -r ${WORKDIR}unpack-testssl/bin/. ${WORKDIR}testssl/bin/ && \
cp ${WORKDIR}unpack-testssl/testssl.sh ${WORKDIR}testssl/ && \
chown $USER:$GROUP --recursive ${WORKDIR}testssl/ && \
rm -rf ${WORKDIR}unpack-testssl/ && \
rm testssl.sh-${TESTSSL_VERSION}.tar.gz
# ln -s ${WORKDIR}testssl/ /usr/local/bin/testssl/

ENV PATH="${WORKDIR}testssl:${PATH}"

# For npm@5 or later, copy the automatically generated package-lock.json instead.
COPY package*.json $WORKDIR

RUN cd $WORKDIR && npm install

# String expansion doesn't work currently: https://github.com/moby/moby/issues/35018
# COPY --chown=${USER}:GROUP . $WORKDIR
COPY --chown=tls_scanner:purpleteam . $WORKDIR

# Here I used to chown and chmod as shown here: http://f1.holisticinfosecforwebdevelopers.com/chap03.html#vps-countermeasures-docker-the-default-user-is-root
# Problem is, each of these commands creates another layer of all the files modified and thus adds over 100MB to the image: https://www.datawire.io/not-engineer-running-3-5gb-docker-images/
# In a prod environment, it may? make sense to do the following, similar to the similar commented out line in the NodeGoat Dockerfile.
#RUN chmod -R g-s,o-rx /home/$USER && chmod -R o-wrx $WORKDIR

# Then all further actions including running the containers should
# be done under non-root user, unless root is actually required.
USER $USER

EXPOSE 3020

CMD ["npm", "start"]
37 changes: 29 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,45 @@
</a>
<br/>
<br/>
<h2>purpleteam tls checker</h2><br/>
TLS checking component of <a href="https://purpleteam-labs.com/" title="purpleteam">purpleteam</a> - Todo
<h2>purpleteam tls scanner</h2><br/>
TLS scanning component of <a href="https://purpleteam-labs.com/" title="purpleteam"><em>PurpleTeam</em></a> - Currently in alpha
<br/><br/>

<a href="https://www.gnu.org/licenses/agpl-3.0" title="license">
<img src="https://img.shields.io/badge/License-AGPL%20v3-blue.svg" alt="GNU AGPL">
</a>

<a href="https://github.com/purpleteam-labs/purpleteam-tls-checker/commits/main" title="pipeline status">
<img src="https://github.com/purpleteam-labs/purpleteam-tls-checker/workflows/Node.js%20CI/badge.svg" alt="pipeline status">
<a href="https://github.com/purpleteam-labs/purpleteam-tls-scanner/commits/main" title="pipeline status">
<img src="https://github.com/purpleteam-labs/purpleteam-tls-scanner/workflows/Node.js%20CI/badge.svg" alt="pipeline status">
</a>

<a href='https://coveralls.io/github/purpleteam-labs/purpleteam-tls-checker?branch=main'>
<img src='https://coveralls.io/repos/github/purpleteam-labs/purpleteam-tls-checker/badge.svg?branch=main' alt='test coverage'>
<a href='https://coveralls.io/github/purpleteam-labs/purpleteam-tls-scanner?branch=main'>
<img src='https://coveralls.io/repos/github/purpleteam-labs/purpleteam-tls-scanner/badge.svg?branch=main' alt='test coverage'>
</a>

<a href="https://github.com/purpleteam-labs/purpleteam-tls-checker/releases" title="latest release">
<img src="https://img.shields.io/github/v/release/purpleteam-labs/purpleteam-tls-checker?color=%23794fb8&include_prereleases" alt="GitHub release (latest SemVer including pre-releases)">
<a href="https://github.com/purpleteam-labs/purpleteam-tls-scanner/releases" title="latest release">
<img src="https://img.shields.io/github/v/release/purpleteam-labs/purpleteam-tls-scanner?color=%23794fb8&include_prereleases" alt="GitHub release (latest SemVer including pre-releases)">
</a>
<br/><br/>
</div>


If you are setting up the tls-scanner, you will be targeting the `local` environment.

Clone or fork this repository.

If you are developing this project:

`cd` to the repository root directory and run:
```shell
npm install
```

# Configuration

Copy the config/config.example.json to config/config.local.json.
Use the config/config.js for documentation and further examples.

<br>

Once you have worked through the above steps, head back to the [local setup](https://purpleteam-labs.com/doc/local/set-up/) documentation to continue setting up the other _PurpleTeam_ components.
7 changes: 7 additions & 0 deletions bin/purpleteamCucumber
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env node

// Following code taken from https://github.com/cucumber/cucumber-js/blob/cfc9b4a1db5b97d95350ce41144ae69084096adc/bin/cucumber-js
// then modified

require('app-module-path/cwd');
require('../src/scripts/runCuc').default();
20 changes: 20 additions & 0 deletions config/config.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"logger": {
"level": "debug"
},
"host": {
"host": "172.25.0.140"
},
"emissary": {
"report": {
"dir": "/var/log/purpleteam/outcomes/"
}
},
"cucumber": {
"tagExpression": "@tls_scan",
"timeout": 1800000
},
"results": {
"dir": "/var/log/purpleteam/outcomes/"
}
}
152 changes: 152 additions & 0 deletions config/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// Copyright (C) 2017-2021 BinaryMist Limited. All rights reserved.

// This file is part of PurpleTeam.

// PurpleTeam is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation version 3.

// PurpleTeam is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with this PurpleTeam project. If not, see <https://www.gnu.org/licenses/>.

const convict = require('convict');
const { duration } = require('convict-format-with-moment');
const path = require('path');

convict.addFormat(duration);

const schema = {
env: {
doc: 'The application environment.',
format: ['cloud', 'local', 'test'],
default: 'cloud',
env: 'NODE_ENV'
},
logger: {
level: {
doc: 'Write all log events with this level and below. Syslog levels used: https://github.com/winstonjs/winston#logging-levels',
format: ['emerg', 'alert', 'crit', 'error', 'warning', 'notice', 'info', 'debug'],
default: 'notice'
}
},
processMonitoring: {
on: {
doc: 'Whether or not to capture and log process events.',
format: 'Boolean',
default: false
},
interval: {
doc: 'The interval in milliseconds to capture and log the process events.',
format: 'duration',
default: 10000
}
},
debug: {
execArgvDebugString: {
doc: 'The process.execArgv debug string if the process is running with it. Used to initiate child processes with in order to debug them.',
format: String,
default: process.execArgv.indexOf('--inspect-brk=0.0.0.0') !== -1 ? '--inspect-brk=0.0.0.0' : undefined
},
firstChildProcessInspectPort: {
doc: 'The first child process debug port to attach to as defined in the .vscode launch.json',
format: 'port',
default: 9329
}
},
host: {
port: {
doc: 'The port of this host.',
format: 'port',
default: 3020,
env: 'PORT'
},
host: {
doc: 'The IP address or hostname of this host.',
format: String,
default: '240.0.0.0'
}
},
redis: {
clientCreationOptions: {
doc: 'The options used for creating the redis client.',
format: (val) => typeof val === 'object',
default: {
port: 6379,
host: 'redis'
// "host": "172.17.0.2" // host networking or not running in container
}
}
},
messageChannelHeartBeatInterval: {
doc: 'This is used to send heart beat messages every n milliseconds. Primarily to keep the orchestrator\'s testerWatcher longPoll timeout from being reached.',
format: 'duration',
default: 15000
},
emissary: {
report: {
dir: {
doc: 'The location of the report.',
format: String,
default: '/var/log/purpleteam/outcomes/'
}
}
},
sut: {
tlsScannerSeverity: {
doc: 'The attack strength of the active scanner.',
format: ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL'],
default: undefined
},
alertThreshold: {
doc: 'The number of alerts specified by the Build User that the alerts found by Zap should not exceed.',
format: 'int',
default: 0
}
},
cucumber: {
features: {
doc: 'The location of the feature files.',
format: String,
default: 'src/features'
},
steps: {
doc: 'The location of the step files.',
format: String,
default: 'src/steps'
},
tagExpression: {
doc: 'The tag expression without the \'--tag\' to run Cucumber with.',
format: String,
default: 'not @simple_math'
},
binary: {
doc: 'The location of the Cucumber binary.',
format: String,
// default: `${process.cwd()}/node_modules/.bin/cucumber-js`
default: `${process.cwd()}/bin/purpleteamCucumber`
},
timeout: {
doc: 'The value used to set the timeout (https://github.com/cucumber/cucumber-js/blob/master/docs/support_files/timeouts.md)',
format: 'duration',
default: 5000
}
},
results: {
dir: {
doc: 'The location of the results.',
format: String,
default: '/var/log/purpleteam/outcomes/'
}
}
};

const config = convict(schema);
config.loadFile(path.join(__dirname, `config.${process.env.NODE_ENV}.json`));
config.validate();

module.exports = config;
41 changes: 41 additions & 0 deletions healthcheck.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (C) 2017-2021 BinaryMist Limited. All rights reserved.

// This file is part of PurpleTeam.

// PurpleTeam is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation version 3.

// PurpleTeam is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with this PurpleTeam project. If not, see <https://www.gnu.org/licenses/>.

const http = require('http');
require('convict');
const config = require('./config/config');

const options = {
host: config.get('host.host'),
port: config.get('host.port'),
path: '/status',
timeout: 2000
};

/* eslint-disable no-console */
const request = http.request(options, (res) => {
console.log(`StatusCode: ${res.statusCode}`);
if (res.statusCode === 200) process.exit(0);
process.exit(1);
});

request.on('error', (err) => {
console.log(`ERROR: ${err}`);
process.exit(1);
});
/* eslint-enable no-console */

request.end();
Loading