diff --git a/Papers/api/module.php b/Papers/api/module.php
index 2c5e1a1..914d8fd 100755
--- a/Papers/api/module.php
+++ b/Papers/api/module.php
@@ -10,11 +10,10 @@ define('__CHANGELOGS__', __INCLUDES__ . "changelog/");
define('__HELPFILES__', __INCLUDES__ . "help/");
define('__DOWNLOAD__', __INCLUDES__ . "download/");
define('__UPLOAD__', __INCLUDES__ . "upload/");
+define('__SSL_TEMPLATE__', __SCRIPTS__ . "ssl.cnf");
/*
- Determine the type of file that has been uploaded and move it to the appropriate
- directory. If it's a .zip it is an injection set and will be unpacked. If it is
- an .exe it will be moved to __WINDL__, etc.
+ Import keys
*/
if (!empty($_FILES)) {
$response = [];
@@ -159,6 +158,7 @@ class Papers extends Module
}
private function buildCert($paramsObj) {
$certInfo = array();
+ $req = array();
$params = (array)$paramsObj;
$keyName = (array_key_exists('keyName', $params)) ? $params['keyName'] : "newCert";
@@ -174,28 +174,21 @@ class Papers extends Module
if (array_key_exists('bitSize', $params)) {
$certInfo['-b'] = $params['bitSize'];
}
- if (array_key_exists('country', $params)) {
- $certInfo['-c'] = $params['country'];
- }
- if (array_key_exists('state', $params)) {
- $certInfo['-st'] = $params['state'];
- }
- if (array_key_exists('city', $params)) {
- $certInfo['-l'] = $params['city'];
- }
- if (array_key_exists('organization', $params)) {
- $certInfo['-o'] = $params['organization'];
- }
- if (array_key_exists('section', $params)) {
- $certInfo['-ou'] = $params['section'];
- }
- if (array_key_exists('commonName', $params)) {
- $certInfo['-cn'] = $params['commonName'];
- }
- if (array_key_exists('email', $params)) {
- $certInfo['-email'] = $params['email'];
+
+ $req[':C:'] = array_key_exists('country', $params) ? $params['country'] : "US";
+ $req[':ST:'] = array_key_exists('state', $params) ? $params['state'] : "CA";
+ $req[':LOC:'] = array_key_exists('city', $params) ? $params['city'] : "San Jose";
+ $req[':ORG:'] = array_key_exists('organization', $params) ? $params['organization'] : "SecTrust";
+ $req[':OU:'] = array_key_exists('section', $params) ? $params['section'] : "Certificate Issue";
+ $req[':COM:'] = array_key_exists('commonName', $params) ? $params['commonName'] : $keyName;
+
+ if (array_key_exists('sans', $params)) {
+ $req[':SAN:'] = $params['sans'];
}
+ // Generate an OpenSSL config file
+ $certInfo['--config'] = $this->generateSSLConfig($keyName, $req);
+
// Build the argument string to pass to buildCert.sh
foreach ($certInfo as $k => $v) {
$argString .= $k . " \"" . $v . "\" ";
@@ -210,6 +203,9 @@ class Papers extends Module
$this->respond(false, "Failed to build key pair. Check the logs for details.");
return;
}
+
+ // Delete the OpenSSL conf file
+ unlink($certInfo['--config']);
if (array_key_exists('container', $params) || array_key_exists('encrypt', $params)) {
$cryptInfo = array();
@@ -256,6 +252,39 @@ class Papers extends Module
}
$this->respond(true, "Keys created successfully!");
}
+
+ /*
+ Generates an OpenSSL config file based on the passed in requirements ($req)
+ and returns the path to the file.
+ */
+ private function generateSSLConfig($keyName, $req) {
+ $conf = file_get_contents(__SSL_TEMPLATE__);
+
+ foreach ($req as $k => $v) {
+ $conf = str_replace($k, $v, $conf);
+ }
+
+ // Add the common name as a SAN
+ $conf .= "\nDNS.1 = " . $req[':COM:'];
+
+ // Add additional SANs if they were provided
+ if (isset($req[':SAN:'])) {
+ $x = 2;
+ foreach (explode(",", $req[':SAN:']) as $san) {
+
+ // Skip the common name if it was included in the list since
+ // we already added it above
+ if ($san == $req[':COM:']) { continue; }
+
+ $conf .= "\nDNS." . $x . " = " . $san;
+ $x++;
+ }
+ }
+
+ $path = __SCRIPTS__ . hash('md5', $keyName . time()) . ".cnf";
+ file_put_contents($path, $conf);
+ return $path;
+ }
private function loadCertificates() {
$certs = $this->getKeys(__SSLSTORE__);
@@ -268,7 +297,7 @@ class Papers extends Module
$keys = scandir($dir);
$certs = array();
foreach ($keys as $key) {
- if ($key == "." || $key == "..") {continue;}
+ if (substr($key, 0, 1) == ".") {continue;}
$parts = explode(".", $key);
$fname = $parts[0];
@@ -323,7 +352,7 @@ class Papers extends Module
$contents = scandir($keyDir);
$certs = array();
foreach ($contents as $cert) {
- if ($cert == "." || $cert == "..") {continue;}
+ if (substr($cert, 0, 1) == ".") {continue;}
$parts = explode(".", $cert);
$fname = $parts[0];
$type = "." . $parts[1];
@@ -356,7 +385,7 @@ class Papers extends Module
private function clearDownloadArchive() {
foreach (scandir(__DOWNLOAD__) as $file) {
- if ($file == "." || $file == "..") {continue;}
+ if (substr($file, 0, 1) == ".") {continue;}
unlink(__DOWNLOAD__ . $file);
}
$files = glob(__DOWNLOAD__ . "*");
@@ -380,7 +409,7 @@ class Papers extends Module
$msg = "Failed to delete the following files:";
$keyDir = ($keyType == "SSH") ? __SSHSTORE__ : __SSLSTORE__;
foreach (scandir($keyDir) as $cert) {
- if ($cert == "." || $cert == "..") {continue;}
+ if (substr($cert, 0, 1) == ".") {continue;}
if (explode(".",$cert)[0] == $delCert) {
if (!unlink($keyDir . $cert)) {
$res = False;
@@ -527,7 +556,7 @@ class Papers extends Module
$dir = ($type == "error") ? __LOGS__ : __CHANGELOGS__;
$contents = array();
foreach (scandir($dir) as $log) {
- if ($log == "." || $log == "..") {continue;}
+ if (substr($log, 0, 1) == ".") {continue;}
array_push($contents, $log);
}
$this->respond(true, null, $contents);
diff --git a/Papers/includes/changelog/Version 1.5 b/Papers/includes/changelog/Version 1.5
new file mode 100644
index 0000000..c6eb0dd
--- /dev/null
+++ b/Papers/includes/changelog/Version 1.5
@@ -0,0 +1,5 @@
+January 3, 2018
+- Added option to include SANs in certificates
+- Changed key output from .pem to .key
+- Added default Certificate Info if none is included in the build request
+- Fixed a bug where the Certificate Info fields remained after switching to SSH key build mode
diff --git a/Papers/includes/download/.gitignore b/Papers/includes/download/.gitignore
new file mode 100644
index 0000000..49cc8ef
Binary files /dev/null and b/Papers/includes/download/.gitignore differ
diff --git a/Papers/includes/help/build.help b/Papers/includes/help/build.help
index a4c6349..0af322b 100755
--- a/Papers/includes/help/build.help
+++ b/Papers/includes/help/build.help
@@ -20,7 +20,12 @@ This value indicates how long the certificate will be valid. A default value of
Signature Algorithm
-SHA-1 is considered to be too weak these days, or it will be soon enough, so SHA-256 is selected by default.
+SHA-1 has officially been broken so SHA-256 is selected by default.
+
+
+
+Subject Alternative Names (SAN)
+A comma-delimited list of SANs. These are alternative names that will be considered valid when verifying the certificate. For example if you're spoofing multiple sites during a pentest you'll want to add SANs (*.company1.com, *.company2.com, *.com).
diff --git a/Papers/includes/logs/.gitignore b/Papers/includes/logs/.gitignore
new file mode 100644
index 0000000..49cc8ef
Binary files /dev/null and b/Papers/includes/logs/.gitignore differ
diff --git a/Papers/includes/scripts/buildCert.sh b/Papers/includes/scripts/buildCert.sh
index f87d160..d06d7b8 100755
--- a/Papers/includes/scripts/buildCert.sh
+++ b/Papers/includes/scripts/buildCert.sh
@@ -23,7 +23,7 @@ help() {
echo -e '\t-o,--orgnaization:\t\tOrganization';
echo -e '\t-ou,--organizationalUnit:\tOrganizational Unit';
echo -e '\t-cn,--commonName:\t\tCommon Name';
- echo -e '\t-email,--emailAddress:\t\tEmail Address';
+ echo -e '\t--config:\t\t\tOpenSSL config file';
echo '';
}
@@ -41,37 +41,37 @@ while [ "$#" -gt 0 ]
do
if [[ "$1" == "-d" || "$1" == "--days" ]]; then
- DAYS="$2";
+ DAYS="$2";
fi
if [[ "$1" == "-b" || "$1" == "--bitSize" ]]; then
- BITSIZE="$2";
+ BITSIZE="$2";
fi
if [[ "$1" == "-k" || "$1" == "--keyName" ]]; then
- KEYNAME="$2";
+ KEYNAME="$2";
fi
if [[ "$1" == "-sa" || "$1" == "--sigAlgo" ]]; then
- SIGALGO="$2";
+ SIGALGO="$2";
fi
if [[ "$1" == "-c" || "$1" == "--country" ]]; then
COUNTRY="$2"
fi
if [[ "$1" == "-st" || "$1" == "--state" ]]; then
- STATE="$2"
+ STATE="$2"
fi
if [[ "$1" == "-l" || "$1" == "--locality" ]]; then
- LOCALITY="$2"
+ LOCALITY="$2"
fi
if [[ "$1" == "-o" || "$1" == "--organization" ]]; then
- ORGANIZATION="$2"
+ ORGANIZATION="$2"
fi
if [[ "$1" == "-ou" || "$1" == "--organizationalUnit" ]]; then
- OU="$2"
+ OU="$2"
fi
if [[ "$1" == "-cn" || "$1" == "--commonName" ]]; then
- CN="$2"
+ CN="$2"
fi
-if [[ "$1" == "-email" || "$1" == "--emailAddress" ]]; then
- EMAIL="$2"
+if [[ "$1" == "--config" ]]; then
+ CONF="$2"
fi
shift
@@ -104,14 +104,11 @@ fi
if [ -n "$CN" ]; then
subj="$subj/CN=$CN";
fi
-if [ -n "$EMAIL" ]; then
- subj="$subj/emailAddress=$EMAIL";
-fi
if [ -n "$subj" ]; then
- openssl req -x509 -nodes -batch -days $DAYS -newkey rsa:$BITSIZE -$SIGALGO -keyout $ssl_store$KEYNAME.pem -out $ssl_store$KEYNAME.cer -subj "$subj";
+ openssl req -x509 -nodes -batch -days $DAYS -newkey rsa:$BITSIZE -$SIGALGO -keyout $ssl_store$KEYNAME.key -out $ssl_store$KEYNAME.cer -subj "$subj";
else
- openssl req -x509 -nodes -batch -days $DAYS -newkey rsa:$BITSIZE -$SIGALGO -keyout $ssl_store$KEYNAME.pem -out $ssl_store$KEYNAME.cer;
+ openssl req -x509 -nodes -batch -days $DAYS -newkey rsa:$BITSIZE -$SIGALGO -keyout $ssl_store$KEYNAME.key -out $ssl_store$KEYNAME.cer -config $CONF;
fi
echo "Complete";
diff --git a/Papers/includes/scripts/cfgHelper.py b/Papers/includes/scripts/cfgHelper.py
index 90d448a..274b00b 100755
--- a/Papers/includes/scripts/cfgHelper.py
+++ b/Papers/includes/scripts/cfgHelper.py
@@ -15,7 +15,7 @@ class ConfigHelper:
def checkSSLCertsExist(self):
- flags = [".pem", ".cer"]
+ flags = [".key", ".cer"]
if os.path.isdir(self.ssl_dir):
for file in os.listdir(self.ssl_dir):
for flag in flags:
@@ -64,7 +64,7 @@ class ConfigHelper:
index = 0
cert = keyName + ".cer"
- key = keyName + ".pem"
+ key = keyName + ".key"
with open(self.nginxConf, "w") as out:
for line in self.lines:
@@ -84,7 +84,7 @@ class ConfigHelper:
def replaceSSLConfig(self, newKey):
cert = newKey + ".cer"
- key = newKey + ".pem"
+ key = newKey + ".key"
currentKey = self.currentSSLCerts[0].rsplit(".")[0]
index = 0
@@ -94,7 +94,7 @@ class ConfigHelper:
if (currentKey + ".cer") in line:
line = "\t\tssl_certificate /etc/nginx/ssl/" + cert + ";\n"
- if (currentKey + ".pem") in line:
+ if (currentKey + ".key") in line:
line = "\t\tssl_certificate_key /etc/nginx/ssl/" + key + ";\n"
index = index + 1
diff --git a/Papers/includes/scripts/copyKeys.sh b/Papers/includes/scripts/copyKeys.sh
index 4b7f30d..b100a54 100755
--- a/Papers/includes/scripts/copyKeys.sh
+++ b/Papers/includes/scripts/copyKeys.sh
@@ -3,8 +3,8 @@
# Author: sud0nick
# Date: Jan 2016
-if ! cp $1.pem /etc/nginx/ssl/; then
- echo "Failed to copy $1.pem to /etc/nginx/ssl/";
+if ! cp $1.key /etc/nginx/ssl/; then
+ echo "Failed to copy $1.key to /etc/nginx/ssl/";
fi
if ! cp $1.cer /etc/nginx/ssl/; then
diff --git a/Papers/includes/scripts/encryptKeys.sh b/Papers/includes/scripts/encryptKeys.sh
index bdb3f5c..918a945 100755
--- a/Papers/includes/scripts/encryptKeys.sh
+++ b/Papers/includes/scripts/encryptKeys.sh
@@ -90,7 +90,7 @@ done;
# Generate a password on the private key
if [ $ENCRYPT_KEYS = true ]; then
- openssl rsa -$ALGO -in $ssl_store$KEY.pem -out $ssl_store$KEY.pem -passout pass:"$PASS";
+ openssl rsa -$ALGO -in $ssl_store$KEY.key -out $ssl_store$KEY.key -passout pass:"$PASS";
fi
# If a container type is present but not an algo or pass then use
@@ -104,7 +104,7 @@ if [ -n "$CONTAINER" ]; then
fi
# Generate a container for the public and private keys
- openssl $CONTAINER -$CALGO -export -nodes -out $ssl_store$KEY.pfx -inkey $ssl_store$KEY.pem -in $ssl_store$KEY.cer -passin pass:"$PASS" -passout pass:"$CPASS";
+ openssl $CONTAINER -$CALGO -export -nodes -out $ssl_store$KEY.pfx -inkey $ssl_store$KEY.key -in $ssl_store$KEY.cer -passin pass:"$PASS" -passout pass:"$CPASS";
fi
echo "Complete"
diff --git a/Papers/includes/scripts/genSSHKeys.sh b/Papers/includes/scripts/genSSHKeys.sh
index f3beef0..674d8fa 100755
--- a/Papers/includes/scripts/genSSHKeys.sh
+++ b/Papers/includes/scripts/genSSHKeys.sh
@@ -55,5 +55,5 @@ if [[ -z $KEYNAME ]]; then
exit;
fi
-ssh-keygen -q -b $BITSIZE -t rsa -N "$PASSWORD" -f $SSH_STORE$KEYNAME.pem -C $COMMENT
-mv $SSH_STORE$KEYNAME.pem.pub $SSH_STORE$KEYNAME.pub
+ssh-keygen -q -b $BITSIZE -t rsa -N "$PASSWORD" -f $SSH_STORE$KEYNAME.key -C $COMMENT
+mv $SSH_STORE$KEYNAME.key.pub $SSH_STORE$KEYNAME.pub
diff --git a/Papers/includes/scripts/readKeys.sh b/Papers/includes/scripts/readKeys.sh
index cd70ec9..5ea9f77 100755
--- a/Papers/includes/scripts/readKeys.sh
+++ b/Papers/includes/scripts/readKeys.sh
@@ -11,7 +11,7 @@ while read p; do
IN_SERVER_BLOCK=true;
fi
else
- if [[ $p == *".cer;" || $p == *".pem;" ]]; then
+ if [[ $p == *".cer;" || $p == *".key;" ]]; then
echo $p | cut -d '/' -f 5 | tr -d ';';
fi
fi
diff --git a/Papers/includes/scripts/ssl.cnf b/Papers/includes/scripts/ssl.cnf
new file mode 100644
index 0000000..a8e4c6c
--- /dev/null
+++ b/Papers/includes/scripts/ssl.cnf
@@ -0,0 +1,17 @@
+[req]
+prompt = no
+distinguished_name = req_distinguished_name
+x509_extensions = req_ext
+
+[req_distinguished_name]
+organizationName = :ORG:
+organizationalUnitName = :OU:
+localityName = :LOC:
+stateOrProvinceName = :ST:
+countryName = :C:
+commonName = :COM:
+
+[req_ext]
+subjectAltName = @alt_names
+
+[alt_names]
\ No newline at end of file
diff --git a/Papers/includes/scripts/testEncrypt.sh b/Papers/includes/scripts/testEncrypt.sh
index 10821e1..bffb14f 100755
--- a/Papers/includes/scripts/testEncrypt.sh
+++ b/Papers/includes/scripts/testEncrypt.sh
@@ -23,7 +23,7 @@ while [ "$#" -gt 0 ]
do
if [[ "$1" == "-k" ]]; then
- KEY="$2.pem"
+ KEY="$2.key"
fi
if [[ "$1" == "-d" ]]; then
KEYDIR="$2"
diff --git a/Papers/includes/scripts/unpackKeyArchive.sh b/Papers/includes/scripts/unpackKeyArchive.sh
index a4c9240..d409d48 100755
--- a/Papers/includes/scripts/unpackKeyArchive.sh
+++ b/Papers/includes/scripts/unpackKeyArchive.sh
@@ -39,14 +39,14 @@ output=$(unzip $FILE.zip -d $DL_DIR);
# keys are destined for the SSH directory
if [[ $output == *".pub"* ]]; then
mv $FILE.pub /pineapple/modules/Papers/includes/ssh/
- mv $FILE.pem /pineapple/modules/Papers/includes/ssh/
+ mv $FILE.key /pineapple/modules/Papers/includes/ssh/
fi
# If the archive contained a .cer these
# keys are destined for the SSL directory
if [[ $output == *".cer"* ]]; then
mv $FILE.cer /pineapple/modules/Papers/includes/ssl/
- mv $FILE.pem /pineapple/modules/Papers/includes/ssl/
+ mv $FILE.key /pineapple/modules/Papers/includes/ssl/
fi
# Clear the download directory
diff --git a/Papers/includes/ssh/.gitignore b/Papers/includes/ssh/.gitignore
new file mode 100644
index 0000000..49cc8ef
Binary files /dev/null and b/Papers/includes/ssh/.gitignore differ
diff --git a/Papers/includes/ssl/.gitignore b/Papers/includes/ssl/.gitignore
new file mode 100644
index 0000000..49cc8ef
Binary files /dev/null and b/Papers/includes/ssl/.gitignore differ
diff --git a/Papers/js/module.js b/Papers/js/module.js
index d5d63fa..b93f7a7 100755
--- a/Papers/js/module.js
+++ b/Papers/js/module.js
@@ -5,6 +5,7 @@ registerController('PapersController', ['$api', '$scope', '$sce', '$http', funct
$scope.certBitSize = "2048";
$scope.certDaysValid = "365";
$scope.certSigAlgo = "sha256";
+ $scope.certSANs = "";
$scope.certKeyName = "";
$scope.modifyCertInfo = false;
$scope.certInfoCountry = "";
@@ -130,6 +131,9 @@ registerController('PapersController', ['$api', '$scope', '$sce', '$http', funct
if ($scope.certDaysValid != ''){
params['days'] = $scope.certDaysValid;
}
+ if ($scope.certSANs != '') {
+ params['sans'] = $scope.certSANs;
+ }
if ($scope.certEncryptKeysBool === true) {
params['encrypt'] = "";
params['algo'] = $scope.certEncryptAlgo;
@@ -168,6 +172,7 @@ registerController('PapersController', ['$api', '$scope', '$sce', '$http', funct
$scope.certDaysValid = "365";
$scope.certBitSize = "2048";
$scope.certSigAlgo = "sha256";
+ $scope.certSANs = "";
$scope.certKeyName = "";
$scope.certInfoCountry = "";
$scope.certInfoState = "";
diff --git a/Papers/module.html b/Papers/module.html
index d8f086f..2d0cade 100755
--- a/Papers/module.html
+++ b/Papers/module.html
@@ -209,43 +209,50 @@ $(document).on('mouseenter', '.papers_hoverDanger', function() {