1st import into tree

This commit is contained in:
Rui Reis 2016-12-15 17:41:58 +00:00
parent 1d06a57fbb
commit 6b097ec81b
73 changed files with 41019 additions and 0 deletions

1214
uninformed/1.1.txt Normal file

File diff suppressed because it is too large Load Diff

1219
uninformed/1.2.txt Normal file

File diff suppressed because it is too large Load Diff

752
uninformed/1.3.txt Normal file
View File

@ -0,0 +1,752 @@
==Uninformed Research==
|=-----------------------=[ Smart Parking Meters ]=---------------------=|
|=----------------------------------------------------------------------=|
|=------------------=[ h1kari <h1kari@dachb0den.com> ]=-----------------=|
--=[ Contents ]=----------------------------------------------------------
1 - Introduction
2 - ISO7816
3 - Synchronous Cards
3.1 - Memory Cards
3.2 - Parking Meter Debit Cards
3.3 - The Simple Hack
4 - Memory Dump
5 - Synchronous Smart Card Protocol Sniffing
5.1 - Sniffer Design
5.2 - Sniffer Code
6 - Protocol Analysis
6.1 - Decoding Data
6.2 - Timing Graph
6.3 - Conclusions
7 - Conclusion
--[ 1 - Introduction ]----------------------------------------------------
If this whitepaper looks a little familiar to you, I'm going to admit
off the bat that it's based a bit on Phrack 48-10/11 (Electronic Telephone
Cards: How to make your own!) and is using a similar format to Phrack
62-15 (Introduction for Playing Cards for Smart Profits). I highly
recommend you read both of them if you're trying to learn about smart
cards.
I'm sure that many of you that live near a major city have seen
parking meters that require you to pay money in order to park in a spot.
Upon initial analysis of these devices you'll notice there is a slot for
money to go in. On some, there is also a slot for a Parking Meter Debit
Card that you can purchase from the city. This article will analyze these
Parking Meters and their Debit Cards, show how they tick, and show how you
can defeat their security.
The end goal however is to provide enough information so you can
create your own tools to learn more about smart cards and how they work.
I have no intention of having people use this article to rip off the
government, this is for educational purposes only. My only hope is that by
getting this information out there, security systems will be designed more
thoroughly in the future.
PARKING METER
_,-----,_
,-' `-,
/ ._________. \
/ , | 00:00 <+-,-+------ Time/Credits Display
Meter Status ----+>'-''---------''-'<+----- Meter Status
| ,-------, |
| |\ |<+-------+----- Coin Slot
Smart Card Slot -----\--+->\ | | /
\ '----\--' /
\ /
\ /
\ /
\-----------/
| ,-------, |
Money --------+-+-->o | |
| | | |
| | | |
| '-------' |
\---------/
| |
For those not familiar with these devices, you can go to various
locations around town and purchase these Parking Meter Debit Cards that
are preloaded with $10, $20, or $50. To explain how to use these, I will
quote off of the instructions provided on the back of the cards:
.--------------------------------------------------------------------.
/ \
| PARKING METER DEBIT CARD |
| |
| 1. Insert debit card into meter in direction shown by arrow. |
| The dollar balance of the card will flash 4 times. |
| 2. The Meter will increment in 6 min. segments. |
| 3. When desired time is displayed, remove card. |
| |
| DID YOU BUY TOO MUCH TIME? |
| TO OBTAIN EXTRA TIME REFUND |
| |
| * Insert the same debit card that was used to purchase time |
| on the meter. Full 6 minute increments will be credited to |
| card. Increments of less than 6 minutes will be lost. |
| |
| Parking cards may be used for ************** meters |
| which have yellow posts. |
| |
\--------------------------------------------------------------------/
NOTE: The increments are now 4 min due to raising prices
I'm not including a lot of information that's provided in those
Phrack's that were mentioned, so if things look a little incomplete,
please read through them before emailing me with questions.
Here's a list of all of my resources:
- The ISO7816 Standard
- Phrack 48-10/11 & 62-15
- Towitoko ChipDrive 130
- Homebrew Synchronous Protocol Sniffer (Schematics Included)
- A few Parking Meter Debit Cards
- A few Parking Meters
- Computer with a Parallel Port
- A business card or two
--[ 2 - ISO7816 ]---------------------------------------------------------
The ISO 7816 standard is one of the few resources we have to work with
when reverse engineering a smart card. It provides us with basic knowledge
of pin layouts, what the different pins do, and how to interface with
them. Unfortunately, it mostly covers asynchronous cards and doesn't
really touch on how synchronous cards work. To get more detailed
information on this please read Phrack 48-10/11.
--[ 3 - Synchronous Cards ]-----------------------------------------------
Synchronous protocols are usually used with memory cards mainly to
reduce cost (since the card doesn't require an internal clock) and because
usually memory cards don't require much logic and are used for simple
applications. Asynchronous cards on the other hand have an internal clock
and can communicate with the reader at a fixed rate across the I/O line
(usually 9600 baud), asynchronous cards are usually used with processor
cards where more interaction is required (see Phrack 62-15).
----[ 3.1 - Memory Cards ]------------------------------------------------
Memory cards use a very simple protocol for sending data. First off,
because synchronous cards don't know anything about timing, their clock is
provided by the reader. In this situation, the reader can set the I/O line
when the clock is low (0v) and the card can set the I/O line when the
clock is high (5v). To dump all of the memory from a card, the reader
first sets the Reset line high to reset the card and keeps the clock
ticking. The first time the Reset line is low and the Clock is raised the
card will set the I/O line to whatever the 0 bit is in memory, the second
time it's raised, the card will set the I/O line to whatever the 1 bit is
in memory, etc. This is repeated until all of the data is dumped from the
card.
__________________
_| |___________________________________________ Reset
: :
: _____ : _____ _____ _____ _____
_:_______| |____:_| |_____| |_____| |_____| Clk
: : : : : : : : : :
_:_______:__________:_:_____:_____:_____:_____:_____:_____:_____
_:___n___|_____0____:_|_____1_____|_____2_____|_____3_____|___4_ (Address)
: : : : :
_: :_______:___________:___________:___________
_XXXXXXXXXXXXXXXXXXXX_______|___________|___________|___________ Data
Bit n Bit 0 Bit 1 Bit2 Bit3
(Borrowed from Stephane Bausson's paper re-published in Phrack 48-10)
----[ 3.1 - Parking Meter Debit Cards ]-----------------------------------
Parking Meter Debit Cards behave very similarly to standard memory
cards, however they also have to provide some basic security to make sure
people can't get free parking. This is done by using a method similar to
the European Telephone Cards (SLE4406) where there is a section of memory
on the card that acts as a one-way counter where bits are set to a certain
amount of credits, then a security fuse is blown, and now the set bits can
only be flipped from 1 -> 0. This is a standard security mechanism that
makes it so people cannot recharge their cards once the credits have been
used. The only catch is that the way that the parking meters work makes it
so you can refund unused credits to the card.
----[ 3.2 - Parking Meter Debit Cards ]-----------------------------------
If my little introduction to Synchronous Smart Cards just went right
over your head, here's an example of how to attack Parking Meters without
having to deal with electronics or code. If you ever try putting an
invalid card into a parking meter, you'll notice that after about 90
seconds of flashing error messages, it will switch over to Out-of-Order
status. Now, for convenience sake, most cities allow you to park for free
in Out-of-Order spots. (Anyone see a loophole here???)
.----------------------------------------------------------------------.
| : |
| : |
| : |
| : |
| : |
| : |
| : |
| : |
| : <- insert folded side |
| : |
| : |
| : |
| : |
| : |
| : |
| : |
| : |
| : |
'----------------------------------------------------------------------'
One simple method you can use for making it less obvious that
something in the slot is making it be Out-of-Order is to fold a business
card in half (preferably not yours) and insert it into the smart card
slot. It should be the perfect length that it will go in and be very
difficult to notice and/or take out. When you're finished parking, you
should be able to pull the business card out using a credit card or small
flathead screwdriver.
--[ 4 - Memory Dump ]-----------------------------------------------------
To explain how the cards handle credits and refunds, I'll first show
you how the memory on the card is laid out. This dump was done using my
Towitoko ChipDrive 130 using Towitoko's SmartCard Editor Software (very
useful). I highly suggest that you use a commercial smart card reader or
some sort of non-dumb reader for dealing with synchronous cards, dumb
mouse (and most home-brew) readers only work with asynchronous cards.
0x00: 9814 ff3c 9200 46b1 ffff ffff ffff ffff
0x10: ffff ffff ffff ff00 0000 0000 0000 0000
0x20: 0000 0000 0000 0000 0000 0000 0000 0000
0x30: 0000 0000 0000 0000 0000 0000 0000 0000
0x40: 0000 0000 0000 0000 0000 0000 0000 0000
0x50: 0000 0000 f8ff ffff ffff ffff fffc ffff
0x60: ffff ffff ffff ffff ffff ffff ffff ffff
0x70: ffff ffff ffff ffff ffff ffff ffff ffff
0x80: ffff ffff ffff ffff ffff ffff ffff ffff
0x90: ffff ffff ffff ffff ffff ffff ffff ffff
0xa0: fcff ffff ffff ffff ffff ffff ffff ffff
0xb0: ffff ffff ffff ffff ffff ffff ffff ffff
0xc0: ffff ffff
Now.. if we convert over the 0x50 line to bits and analyze it, we'll
notice this (note that bit-endianness is reversed):
0x50: 0000 0000 0000 0000 0000 0000 0000 0000
0x54: 0001 1111 1111 1111 1111 1111 1111 1111
0x58: 1111 1111 1111 1111 1111 1111 1111 1111
0x5a: 1111 1111 0011 1111 1111 1111 1111 1111
For every bit that is 1 between 0x17 and 0x55:1 (note: :x notation
specifies bit offset), you get $0.10 on your card. For every bit that is 0
between 0x5b and 0xb0 you get $0.10 in refunds. The total of these two
counters equals the amount of credits on your card. Now, how they handle
people using the refunds is by having the buffer of bits inbetween 0x55:1
and 0x5b that can be used if there are refund bits that can be spent. This
only allows the user to use ~ $5 worth of refund bits. On this particular
card, the user has $0.60 worth of credits and $0.20 worth of refunds
making a total of $0.80 on the card (I know, I'm poor :-/).
--[ 5 - Synchronous Smart Card Protocol Sniffing ]------------------------
Now that we've figured out how they store credits on the card, we need
to figure out how the reader writes to the card. To do this, we'll need
to somehow sniff the connection and reverse engineer their protocol. The
following section will show you how to make your own synchronous smart
card protocol sniffer and give you code for sniffing the connection.
----[ 5.1 - Sniffer Design ]----------------------------------------------
There's plenty of commercial hardware out there (Season) that allow
you to sniff asynchronous smart cards, but it's a totally different story
for synchronous cards. I wasn't able to find any hardware to do this (and
being totally dumb when it comes to electronics) found someone to help me
out with this design (thx XElf). It basically taps the lines between a
smart card and the reader and runs the signals through an externally
powered buffer to make sure our parallel port doesn't drain the
connection.
My personal implementation consists of a smart card socket I ripped
out of an old smart card reader, a peet's coffee card that I made ISO7816
pinouts on using copper tape, all connected by torn apart floppy drive
cables, and powered by a ripped apart usb cable. You should be able to
find some pics on the net if you search around, although I guarantee
whatever you come up with will be less ghetto than me.
Parallel Port
D10 - Ack - I6 o-------------------------,
|
D11 - Busy - I7 o-----------------------------,
| |
D12 - Paper Out - I5 o---------------------------------,
| | |
D13 - Select - I4 o-------------------------------------,
| | | |
D25 - Gnd o-----, | | | |
| | | | |
| | | | |
External 5V (USB) | | | | |
| | | | |
5V o------------------, | | | | |
| | | | | |
0V o-------*----*-----|---*-------------------|---|---|---|-----,
| | | | | | | | |
| | ,--==--==--==--==--==--==--==--==--==--==--, |
__+__ | |_ 20 19 18 17 16 15 14 13 12 11 | |
///// | | ] 74HCT541N | |
| |' 1 2 3 4 5 6 7 8 9 10 | |
| '--==--==--==--==--==--==--==--==--==--==--' |
| | | | | | | | | | | |
| | '---*---*---* | | | | '-----'
'-----*---------, ,---|---* | | |
| | ,-|---|---* | |
Smart Card | | | | | | *---|------,
,----------,----------, | | | | | | | *----, |
,-------|--* Vcc | Gnd *--|-* | | | ,-, ,-, ,-, ,-, | |
| |----------|----------| | | | | | | | | | | | | | |
| ,-----|--* Reset | Vpp | | | | | | | | | | | | | | |
| | |----------|----------| | | | | |_| |_| |_| |_| | |
| | ,---|--* Clock | I/O *--|---|-* | |r1 |r2 |r3 |r4 | |
| | | |----------|----------| | | | | |10k|10k|10k|10k | |
| | | ,-|--* RF1 | RF2 *--|---* | | | | | | | |
| | | | '----------'----------' | | | '---*---*---*---' | |
| | *-|-------------------------|-|-|----------------------' |
| *-|-|-------------------------|-|-|------------------------'
| | | | | | |
| | | | Smart Card Reader | | |
| | | | ,----------,----------, | | |
'-------|--* Vcc | Gnd *--|-' | |
| | | |----------|----------| | |
'-----|--* Reset | Vpp | | |
| | |----------|----------| | |
'---|--* Clock | I/O *--|---' |
| |----------|----------| |
'-|--* RF1 | RF2 *--|-----'
'----------'----------'
----[ 5.2 - Sniffer Code ]------------------------------------------------
To monitor the connection, compile and run this code with a log
filename as an argument. This code is written for openbsd and uses it's
i386_iopl() function to get access to writing to the ports. You may need
to modify it to work on other OSs. Due to file i/o speed limitations, it
will log to the file whenever you hit ctrl+c.
/*
* Synchronous Smart Card Logger v1.0 [synclog.c]
* by h1kari <h1kari@dachb0den.com>
*/
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <machine/sysarch.h>
#include <i386/pio.h>
#define BASE 0x378
#define DATA (BASE)
#define STATUS (BASE + 1)
#define CONTROL (BASE + 2)
#define ECR (BASE + 0x402)
#define BUF_MAX (1024 * 1024 * 8) /* max log size 8mb */
int bufi = 0;
u_char buf[BUF_MAX];
char *logfile;
void
die(int signo)
{
int i, b;
FILE *fh;
/* open logfile and write output */
if((fh = fopen(logfile, "w")) == NULL) {
perror("unable to open lpt log file");
exit(1);
}
for(i = 0; i < bufi; i++)
printbits(fh, buf[i]);
/* flush and exit out */
fflush(fh);
fclose(fh);
_exit(0);
}
int
printbits(FILE *fh, int b)
{
fprintf(fh, "%d%d%d%d\n",
(b >> 7) & 1, (b >> 6) & 1,
(b >> 5) & 1, (b >> 4) & 1);
}
int
main(int argc, char *argv[])
{
unsigned char a, b, c;
unsigned int *ptraddr;
unsigned int address;
if(argc < 2) {
fprintf(stderr, "usage: %s <file>\n", argv[0]);
exit(1);
}
logfile = argv[1];
/* enable port writing privileges */
if(i386_iopl(3)) {
printf("You need to be superuser to use this\n");
exit(1);
}
/* clear status flags */
outb(STATUS, inb(STATUS) & 0x0f);
/* set epp mode, just in case */
outb(ECR, (inb(ECR) & 0x1f) | 0x80);
/* log to file when we get ctrl+c */
signal(SIGINT, die);
/* fetch dataz0r */
c = 0;
while(bufi < BUF_MAX) {
/* select low nibble */
outb(CONTROL, (inb(CONTROL) & 0xf0) | 0x04);
/* read low nibble */
if((b = inb(STATUS)) == c)
continue;
buf[bufi++] = c = b; /* save last state bits */
}
printf("buffer overflow!\n");
die(0);
}
It might also help to drop the priority level when running it, if it
looks like you're having timing issues:
# nice -n -20 ./synclog file.log
--[ 6 - Protocol Analysis ]-----------------------------------------------
Once we get our log of the connection, we'll need to run it through
some tools to analyze and decode the protocol. I've put together a couple
of simple tools that'll make your life a lot easier. One will simply
decode the bytes that are transferred across based on the state changes.
The other will graph out the whole conversation 2-dimensionally so you
can graphically view patterns in the connection.
----[ 6.1 - Decoding Data ]-----------------------------------------------
For decoding the data, we simply record bits to an input buffer when
the clock is in one state, and to an output buffer when the clock is in
the other. Then dump all of the bytes and reset our counter whenever
there's a reset. This should give us a dump of the data that's being
transferred between the two devices.
/*
* Synchronous Smart Card Log Analyzer v1.0 [analyze.c]
* by h1kari <h1kari@dachb0den.com>
*/
#include <stdio.h>
#ifdef PRINTBITS
#define BYTESPERROW 8
#else
#define BYTESPERROW 16
#endif
void
pushbit(u_char *byte, u_char bit, u_char n)
{
/* add specified bit to their byte */
*byte &= ~(1 << (7 - n));
*byte |= (bit << (7 - n));
}
void
printbuf(u_char *buf, int len, char *io)
{
int i, b;
printf("%s:\n", io);
for(i = 0; i < len; i++) {
#ifdef PRINTBITS
int j;
for(j = 7; j >= 0; j--)
printf("%d", (buf[i] >> j) & 1);
putchar(' ');
#else
printf("%02x ", buf[i]);
#endif
if((i % BYTESPERROW) == BYTESPERROW - 1)
printf("\n");
}
if((i % BYTESPERROW) != 0) {
printf("\n");
}
}
int
main(int argc, char *argv[])
{
u_char ibit, obit;
u_char ibyte, obyte;
u_char clk, rst, bit;
u_char lclk;
u_char ibuf[1024 * 1024], obuf[1024 * 1024];
int ii = 0, oi = 0;
char line[1024];
FILE *fh;
if(argc < 2) {
fprintf(stderr, "usage: %s <file>\n", argv[0]);
exit(1);
}
if((fh = fopen(argv[1], "r")) == NULL) {
perror("unable to open lpt log\n");
exit(1);
}
lclk = 2;
while(fgets(line, 1024, fh) != NULL) {
bit = line[0] - 48;
rst = line[2] - 48;
clk = line[3] - 48;
bit = bit ? 0 : 1;
if(lclk == 2) lclk = clk;
/* print out buffers when we get a reset */
if(rst) {
if(ii > 0 && oi > 0) {
printbuf(ibuf, ii, "input");
printbuf(obuf, oi, "output");
}
ibit = obit = 0;
ibyte = obyte = 0;
ii = oi = 0;
}
/* if clock high input */
if(clk) {
/* incr on clock change */
if(lclk != clk) obit++;
pushbit(&ibyte, bit, ibit);
/* otherwise output */
} else {
/* incr on clock change */
if(lclk != clk) ibit++;
pushbit(&obyte, bit, obit);
}
/* next byte */
if(ibit == 8) {
ibuf[ii++] = ibyte;
ibit = 0;
}
if(obit == 8) {
obuf[oi++] = obyte;
obit = 0;
}
/* save last clock */
lclk = clk;
}
}
----[ 6.2 - Timing Graph ]------------------------------------------------
Sometimes it really helps to see data graphically instead of just a
bunch of hex and 1's and 0's, so my friend pr0le threw together this perl
script that creates an image with a time diagram of the lines. By
analyzing this it made it easier to see how they were performing reads
and writes to the card.
#!/usr/bin/perl
use GD;
my $logfile = shift || die "usage: $0 <logfile>\n";
open( F, "<$logfile" );
my @lines = <F>;
close( F );
my $len = 3;
my $im_len = scalar( @lines );
my $w = $im_len * $len;
my $h = 100;
my $im = new GD::Image( $w, $h );
my $white = $im->colorAllocate( 255, 255, 255 );
my $black = $im->colorAllocate( 0, 0, 0 );
$im->fill( 0, 0, $white );
my $i = 1;
my $init = 0;
my ($bit1,$bit2,$rst,$clk);
my ($lbit1,$lbit2,$lrst,$lclk) = (undef,undef,undef,undef);
my ($x1, $y1, $x2, $y2);
foreach my $line ( @lines ) {
($bit1,$bit2,$rst,$clk) = ($line =~ m/^(\d)(\d)(\d)(\d)/);
if( $init ) {
&print_bit( $lbit1, $bit1, 10 );
&print_bit( $lbit2, $bit2, 30 );
&print_bit( $lrst, $rst, 50 );
&print_bit( $lclk, $clk, 70 );
}
($lbit1,$lbit2,$lrst,$lclk) = ($bit1,$bit2,$rst,$clk);
$init = 1;
$i++;
}
open( F, ">$logfile.jpg" );
binmode F;
print F $im->jpeg;
close( F );
exit;
sub print_bit {
my ($old, $new, $ybase) = @_;
if( $new != $old ) {
if( $new ) {
$im->line( $i*$len, $ybase+10, $i*$len, $ybase+20, $black );
$im->line( $i*$len, $ybase+20, $i*$len+$len, $ybase+20, $black );
} else {
$im->line( $i*$len, $ybase+20, $i*$len, $ybase+10, $black );
$im->line( $i*$len, $ybase+10, $i*$len+$len, $ybase+10, $black );
}
} else {
if( $new ) {
$im->line( $i*$len, $ybase+20, $i*$len+$len, $ybase+20, $black );
} else {
$im->line( $i*$len, $ybase+10, $i*$len+$len, $ybase+10, $black );
}
}
return;
}
----[ 6.3 - Conclusions ]-------------------------------------------------
This code showed how the reserved lines on the smart card are used in
conjunction with credit increments and decrements. This is an analysis of
how it triggers a credit deduct or add on the card:
DEDUCT $0.10:
___________ ___________
_________| |___________| |__________________ Reset
____________________________________
_____________________| |_____ Clk
___________
_________| |__________________________________________ I/O
___________
_________| |__________________________________________ Rsv1
Then issue write command:
00011001 00101000 11111111 00111100
01001001 00000000 01100010 10001101
11111111 11111111 01110111 10101101
ADD $0.20:
___________ ___________ _____
_________| |___________| |____________| Reset
____________________________________
_____________________| |_____ Clk
_____________________________________________
|__________________ I/O
___________________________________
_________| |__________________ Rsv1
Then issue write command:
00011001 00101000 11111111 00111100
01001001 00000000 01100010 10001101
11111111 11111111 01110111 10101101
_____
__________________________________________________________| Reset
________ ___________ ____________
| |___________| |___________| |_____ Clk
____________________ ________________________
| |___________| |_____ I/O
____________________ ________________________
| 1 Credit |___________| 2 Credits |_____ Rsv1
Since the parking meter will refund whatever remaining amount there is
to the card and doesn't have to do it one at a time like with decrements,
the write command supports writing multiple credits back onto the card.
Simply repeat the waveform above and assert Reset when you're finished
"refunding" however many credits you want.
--[ 7 - Conclusion ]------------------------------------------------------
By now, you're probably thinking that this article sucks because there
isn't any ./code that will just give you more $. Unfortunately, most
security smart card protocols are fairly proprietary and whatever code I
released probably wouldn't work in your particular city. And all of the
data and waveforms I've included in this article probably gives the city
it does correspond to, enough info to start camping white vans on my
front lawn. ;-o
Instead of lame vendor specific code, we're aiming to give you
something much more powerful in the next part to this article which will
allow you to emulate arbitrary smart cards and simple electronic
protocols (thx spidey). So stay tuned for the next uninformed article
from Dachb0den Labs.
-h1kari 0ut

380
uninformed/1.4.txt Normal file
View File

@ -0,0 +1,380 @@
Loop Detection
Peter Silberman
peter.silberman@gmail.com
1) Foreword
Abstract: During the course of this paper the reader will gain new knowledge
about previous and new research on the subject of loop detection. The topic of
loop detection will be applied to the field of binary analysis and a case study
will given to illustrate its uses. All of the implementations provided in this
document have been written in C/C++ using Interactive Disassembler (IDA)
plug-ins.
Thanks: The author would like to thank Pedram Amini, thief, Halvar Flake,
skape, trew, Johnny Cache and everyone else at nologin who help with ideas, and
kept those creative juices flowing.
2) Introduction
The goal of this paper is to educate the reader both about why loop detection
is important and how it can be used. When a security researcher thinks of
insecure coding practices, things like calls to strcpy and sprintf are some of
the first things to come to mind. These function calls are considered low
hanging fruit. Some security researchers think of integer overflows or
off-by-one copy errors as types of vulnerabilities. However, not many people
consider, or think to consider, the mis-usage of loops as a security problem.
With that said, loops have been around since the beginning of time (e.g. first
coding languages). The need for a language to iterate over data to analyze
each object or character has always been there. Still, not everyone thinks to
look at a loop for security problems. What if a loop doesn't terminate
correctly? Depending on the operation the loop is performing, it's possible
that it could corrupt surrounding memory regions if not properly managed. If
the loop frees memory that no longer exists or is not memory, a double-free bug
could've been found. These are all things that could, and do, happen in a
loop.
As the low hanging fruit is eliminated in software by security researchers and
companies doing decent to moderate QA testing, the security researchers have to
look elsewhere to find vulnerabilities in software. One area that has only
been touched on briefly in the public relm, is how loops operate when
translated to binaries BugScan is an example of a company that has implemented
"buffer iteration" detection but hasn't talked publically about it.
http://www.logiclibrary.com. The reader may ask: why would one want to look at
loops? Well, a lot of companies implement their own custom string routines,
like strcpy and strcat, which tend to be just as dangerous as the standard
string routines. These functions tend to go un-analyzed because there is no
quick way to say that they are copying a buffer. Due to this reason, loop
detection can help the security research identify areas of interest. During
the course of this article the reader will learn of the different ways to
detect loops using graph analysis, how to implement loop detection, see a new
loop detection IDA plug-in, and a case study that will tie it all together.
3) Algorithms Used to Detect Loops
A lot of research has been done on the subject of loop detection. The
research, however, was not done for the purpose of finding and exploiting
vulnerabilities that exist inside of loops. Most research has been done with
an interest in recognizing and optimizing loops A good article about loop
optimization and compiler optimization is
http://www.cs.princeton.edu/courses/archive/spring03/cs320/notes/loops.pdf .
Research on the optimization of loops has led scientists to classify various
types of loops. There are two distinct categories to which any loop will
belong. Either the loop will be an irreducible loop Irreducible loops are
defined as "loops with multiple entry [points]"
(http://portal.acm.org/citation.cfm?id=236114.236115) or a reducible loop
Reducible loops are defined as "loops with one entry [point]"
(http://portal.acm.org/citation.cfm?id=236114.236115). Given that there are
two different distinct categories, it stands to reason that the two types of
loops are detected in different fashions. Two popular papers on loop detection
are Interval Finding Algorithm and Identifying Loops Using DJ Graphs. This
document will cover the most widely accepted theory on loop detection.
3.1) Natural Loop Detection
One of the most well known algorithms for loop detection is demonstrated in the
book Compilers Principles, Techniques, and Tools by Alfred V. Aho, Ravi Sethi
and Jeffrey D. Ullman. In this algorithm, the authors use a technique that
consists of two components to find natural loops A natural loop "Has a single
entry point. The header dominates all nodes in the loop."
(http://www-2.cs.cmu.edu/afs/cs.cmu.edu/academic/class/15745-s03/public/lectures/L7_handouts.pdf
all loops are not natural loops.
The first component of natural loop detection is to build a dominator tree out
of the control flow graph (CFG). A dominator can be found when all paths to a
given node have to go through another node. A control flow graph is essentially
a map of code execution with directional information. The algorithm in the
book calls for the finding of all the dominators in a CFG. Let's look at the
actual algorithm.
Starting from the entry node, the algorithm needs to check if there is a path
to the slave from the entry node. This path has to avoid the master node. If
it is possible to get to the slave node without touching the master node, it
can be determined that the master node does not dominate the slave node. If it
is not possible to get to the slave node, it is determined that the master node
does dominate the slave. To implement this routine the user would call the
is_path_to(ea_t from, ea_t to, ea_t avoid) function included in loopdetection.cpp.
This function will essentially check to see if there is a path from the
parameter from that can get to the parameter to, and will avoid the node
specified in avoid. Figure illustrates this algorithm.
As the reader can see from Figure 1, there is a loop in this CFG. Let B to C
to D be the path of nodes that create a loop, it will be represented as
B->C->D. There is also another loop from nodes B->D. Using the algorithm
described above it is possible to verify which of these nodes is involved in
the natural loop. The first question to ask is if the flow of the program can
get from A to D while avoiding B. As the reader can see, it is impossible in
this case to get to D avoiding B. As such, a call to the is_path_to function
will tell the user that B Dominates D. This can be represented as B Dom D, and
B Dom C. This is due to the fact that there is no way to reach C or D without
going through B. One question that might be asked is how exactly does this
demonstrate a loop? The answer is that, in fact, it doesn't. The second
component of the natural loop detection checks to see if there is a link, or
backedge, from D to B that would allow the flow of the program to return to
node B to complete the loop. In the case of B->D there exists a backedge that
does complete the loop.
3.2) Problems with Natural Loop Detection
There is a very big problem with natural loops. The problem is with the
natural loop definition which is ``a single entry point whose header dominates
all the nodes in the loop''. Natural loop detection does not deal with
irreducible loops, as defined previously. This problem can be demonstrated in
figure
As the reader can see both B and D are entry points into C. Also neither D nor
B dominates C. This throws a huge wrench into the algorithm and makes it only
able to pick up loops that fall under the specification of a natural loop or
reducible loop It is important to note that it is next that it is next to
impossible to reproduce
4) A Different Approach to Loop Detection
The reader has seen how to detect dominators within a CFG and how to use that
as a component to find natural loops. The previous chapter described why
natural loop detection was flawed when trying to detect irreducible loops. For
binary auditing, the tool will need to be able to pick up all loops and then
let the user deduce whether or not the loops are interesting. This chapter
will introduce the loop algorithm used in the IDA plug-in to detect loops.
To come up with an algorithm that was robust enough to detect both loops in the
irreducible and reducible loop categories, the author decided to modify the
previous definition of a natural loop. The new definition reads "a loop can
have multiple entry points and at least one link that creates a cycle." This
definition avoids the use of dominators to detect loops in the CFG.
The way this alternative algorithm works is by first making a call to the
is_reference_to(ea_t to, ea_t ref) function. The function is_reference_to will
determine if there is a reference from the ea_t specified by ref to the
parameter to. This check within the loop detection algorithm determines if
there is a backedge or link that would complete a loop. The reason this check
is done first is for speed. If there is no reference that would complete a
loop then there is no reason to call is_path_to, thus preventing unnecessary
calculations. However, if there is a link or backedge, a call to the
overloaded function is_path_to(ea_t from, ea_t to) is used to determine if the
nodes that are being examined can even reach each other. The is_path_to function
simulates all possible code execution conditions by following all possible
edges to determine if the flow of execution could ever reach parameter to when
starting at parameter from. The function is_path_to(ea_t from, ea_t to) returns
one (true) if there is indeed a path going from from to to. With both of these
functions returning one, it can be deduced that these nodes are involved in the
loop.
4.1) Problems with new approach
In every algorithm there can exists small problems, that make the algorithm far
from optimal. This problem applies to the new approach presented above. The
algorithm presented above has not been optimized for performance. The algorithm
runs in a time of O(N2), which carries quite a load if there are more than 600
or so nodes.
The reason that the algorithm is so time consuming is that instead of
implementing a Breadth First Search (BFS), a Depth First Search (DFS) was
implemented, in the is_path_to function which computes all possible paths to and
from a given node. Depth First Search is much more expensive than Breadth First
Search, and because of that the algorithm may in some rare cases suffer. If
the reader is interested in how to implement a more efficient algorithm for
finding the dominators, the reader should check out Compiler Design
Implementation by Steven S. Muchnick.
It should be noted that in future of this plug-in there will be optimizations
made to the code. The optimizations will specifically deal new implementations
of a Breadth First Search instead of the Depth First Search, as well as other
small optimizations.
5) Loop Detection Using IDA Plug-ins
In every algorithm and theory there exists small problems. It is important to
understand the algorithm presented
The plug-in described in this document uses the Function Analyzer Class
(functionanalyzer) that was developed by Pedram Amini
(http://labs.idefense.com) as the base class. The Loop Detection
(loopdetection) class uses inheritance to glean its attributes from Function
Analyzer. The reason inheritance is used is primarily for ease of development.
Inheritance is also used so that instead of having to re-add functions to a new
version of Function Analyzer, the user only has to replace the old file. The
final reason inheritance is used is for code conformity, which is accomplished
by creating virtual functions. These virtual functions allow the user to
override methods that are implemented in the Function Analyzer. This means
that if a user understands the structure of function analyzer, they should not
have a hard time understanding loop detections structure.
5.1) Plug-in Usage
To best utilize this plug-in the user needs to understand its features and
capabilities. When a user runs the plug-in they will be prompted with a window
that is shown in figure . Each of the options shown in figure are described
individually.
Graph Loop
This feature will visualize the loops, marking the entry of a loop with green
border, the exit of a loop with a red border and a loop node with a yellow
border. Highlight Function Calls This option allows the user to highlight the
background of any function call made within the loop. The highlighting is done
within IDA View.
Output Stack Information
This is a feature that is only enabled with the graph loop option. When this
option is enabled the graph will contain information about the stack of the
function including the variables name, whether or not it is an argument, and
the size of the variable. This option is a great feature for static auditing.
Highlight Code
This option is very similar to Highlight Function except instead of just
highlighting function calls within loops it will highlight all the code that is
executed within the loops. This makes it easier to read the loops in IDA View
Verbose Output
This feature allows the user to see how the program is working and will give
more information about what the plug-in is doing.
Auto Commenting
This option adds comments to loops nodes, such as where the loop begins, where
it exits, and other useful information so that the user doesn't have to
continually look at the graph.
All Loops Highlighting of Functions
This feature will find every loop within the IDA database. It will then
highlight any call to any function within a loop. The highlighting is done
within the IDA View making navigation of code easier.
All Loops Highlighting of Code
This option will find every loop within the database. It will then highlight
all segments of code involved in a loop. The highlighting of code will allow
for easier navigation of code within the IDA View.
Natural Loops
This detection feature allows the user to only see natural loops. It may not
pick up all loops but is an educational implementation of the previously
discussed algorithm.
Recursive Function Calls
This detection option will allow the user to see where recursive function calls
are located.
5.2) Known Issues
There a couple of known issues with this plug-in. It does not deal with rep*
instructions, nor does it deal with mov** instructions that might result in
copied buffers. Future versions will deal with these instructions, but since
it is open-sourced the user can make changes as they see fit. Another issue is
that of ``no-interest''. By this the author means detecting loops that aren't
of interest or don't pose a security risk. These loops, for example, may be
just counting loops that don't write memory. Halvar Flake describes this topic
in his talk that was given at Blackhat Windows 2004. Feel free to read his
paper and make changes accordingly. The author will also update the plug-in
with these options at a later date.
5.3) Case Study: Zone Alarm
For a case study the author chose Zone Alarm's vsdatant.sys driver. This
driver does a lot of the dirty work for Zone Alarm such as packet filtering,
application monitoring, and other kernel level duties. Some may wonder why it
would be worthwhile to find loops in a driver. In Zone Alarm's case, the user
can hope to find miscalculations in lengths where they didn't convert a signed
to unsigned value properly and therefore may cause an overflow when looping.
Anytime an application takes data in remotely that may be type-casted at some
point, there is always a great chance for loops that overflow their bounds.
When analyzing the Zone Alarm driver the user needs to select certain options
to get a better idea of what is going on with loops. First, the user should
select verbose output and All Loops Highlighting of Functions to see if there
are any dangerous function calls within the loop. This is illustrated in
figure .
After running through the loop detection phase, some interesting results are
found that are shown in figure .
Visiting the address 0x00011a21 in IDA shows the loop. To begin, the reader
will need to find the loop's entry point, which is at:
.text:00011A1E jz short loc_11A27
At the loop's entry point, the reader will notice:
.text:00011A27 push 206B6444h ; Tag
.text:00011A2C push edi ; NumberOfBytes
.text:00011A2D push 1 ; PoolType
.text:00011A2F call ebp ;ExAllocatePoolWithTag
At this point, the reader can see that every time the loop passes through its
entry point it will allocate memory. To determine if the attacker can cause a
double free error, further investigation is needed.
.text:00011A31 mov esi, eax
.text:00011A33 test esi, esi
.text:00011A35 jz short loc_11A8F
If the memory allocation within the loop fails, the loop terminates correctly.
The next call in the loop is to ZwQuerySystemInformation which tries to acquire
the SystemProcessAndThreadsInformation.
.text:00011A46 mov eax, [esp+14h+var_4]
.text:00011A4A add edi, edi
.text:00011A4C inc eax
.text:00011A4D cmp eax, 0Fh
.text:00011A50 mov [esp+14h+var_4], eax
.text:00011A54 jl short loc_11A1C
This part of the loop is quite un-interesting. In this segment the code
increments a counter in eax until eax is greater than 15. It is obvious that
it is not possible to cause a double free error in this case because the user
has no control over the loop condition or data within the loop. This ends the
investigation into a possible double free error.
Above is a good example of how to analyze loops that may be of interest. With
all binary analysis it is important to not only identify dangerous function
calls but to also identify if the attacker can control data that might be
manipulated or referenced within a loop.
6) Conclusion
During the course of this paper, the reader has had a chance to learn about the
different types of loops and some of the method of detecting them. The reader
has also gotten an in-depth view of the new IDA plug-in released with this
article. Hopefully now when the reader sees a loop, whether in code or binary,
the reader can explore the loop and determine if it is a security risk or not.
Bibliography
Tarjan, R. E. 1974. Testing flow graph reducibility. J
Comput. Syst. Sci. 9, 355-365.
Sreedhar, Vugranam, Guang Gao, Yong-Fong Lee. Identifying
loops using DJ graphs.
http://portal.acm.org/citation.cfm?id=236114.236115
Flake, Halvar. Automated Reverse Engineering.
http://www.blackhat.com/presentations/win-usa-04/bh-win-04-flake.pdf

572
uninformed/1.5.txt Normal file
View File

@ -0,0 +1,572 @@
Social Zombies - Aspects of Trojan Networks
May, 2005
warlord
warlord / nologin.org
1) Introduction
While I'm sitting here and writing this article, my firewall is
getting hammered by lots and lots of packets that I never asked for.
How come? In the last couple of years we saw the internet grow into
a dangerous place for the uninitiated, with worms and viruses
looming almost everywhere, often times infecting systems without
user interaction. This article will focus on the subclass of malware
commonly referred to as worms, and introduce some new ideas to the
concept of worm networks.
2) Worm Infection Vectors
The worms around today can mostly be put into one the four
categories discussed in the following sections.
2.1) Mail
The mail worm is the simplest type of worm. It's primary
mode of propagation is through social engineering. By sending large
quantities of mail with content that deceives people and/or triggers
their curiosity, recipients are tricked into running an attached
program. Once executed, the program will send out copies of itself
via email to recipients found in the victims address book. This type
of worm is usually stopped quickly when antivirus companies update
their signature files, and mail servers running those AV products
start filtering the worm mails out. Users, in general, are becoming
more and more aware of this type of malware, and many won't run
attachments sent in mail anymore. Regardless, this method of
infection still manages to be successful.
2.2) Browser
Browser-based worms, which primarily work against Internet Explorer,
make use of vulnerabilities that exist in web-browsers. What
generally happens is that when a users visits a malicious website,
an exploit will make Internet Explorer download and execute code. As
there are well known vulnerabilities in Internet Explorer at all
times that are not yet fixed, the bad guys usually have a couple of
days or weeks to spread their code. Of course, the infection rate
heavily depends on the number of visitors on the website hosting the
exploit. One approach that has been used in the past to gain access
to a wider 'audience' involved sending mail to thousands of users in
an attempt to get the users to visit a malicious website. Another
approach involved hacking advertisement companies and changing their
content in order to make them serve exploits and malware on high
profile sites.
2.3) Peer to Peer
The peer to peer worm is quite similar to the mail worm; it's all
about social engineering. Users hunting for the latest mp3s or
pictures of their most beloved celebrity find similarly named
programs and scripts, trying to deceive the user to download and
execute them. Once active on the users system, the malcode will make
sure it's being hosted by the users p2p application to spread
further. Even if downloaded, host based anti-virus scanners with
recent signatures will catch most of these programs before they can
be run.
2.4) Active
This one is the most dangerous worm, as it doesn't require any sort
of user interaction at all. It also requires the highest level of
skill to write. Active worms spread by scanning the internet for one
or more types of vulnerabilities. Once a vulnerable target is
found, an exploit attempt is made that, if successful, results in
the uploading of the worm to the attacked site where propagation can
continue in the same form. These worms are usually spotted first by
an increasing number of hosts scanning the internet, most often
scanning for a single port. These worms also usually exploit
weaknesses that are well-known to the public for hours, days, weeks
or months. Examples of this type of worm include the Wank worm,
Code Red, Sadmind, SQL Slammer, Blaster, Sasser and others. As the
use of firewalls and NAT routers increases, and as anti-exploit
techniques like the one employed by Windows XP SP2 become more
common, these worms will find less hosts to infect. To this point,
from the time of this writing, it's been a while since the last big
active worm hit the net.
Other active infection vectors include code spreading via unset or
weak passwords on CIFS Common Internet File System. The
protocol used to exchange data between Windows hosts via network
shares. shares, IRC and instant messaging networks, Usenet, and
virtually every other data exchange protocol.
3) Motives
3.1) Ego
Media attention often is a major motivation behind a worm. Coders
bolstering their ego by seeing reports on their worm on major sites
on the internet as well as tv news and newspapers with paniced
warnings of the latest doomsday threat which may take down the
planet and result in a 'Digital Pearl Harbor' seems
to be quite often the case. Huge media attention usually also means
huge law enforcement attention, and big efforts will be made to
catch the perpetrator. Though especially wide open (public) WIFI
networks can make it quite difficult to catch the perpetrator by
technological means, people boasting on IRC and, as in the case of
Sasser, bounties, can quickly result in the worm's author being
taken into custody.
3.2) DDoS
The reason for a DDoS botnet is usually either the wish to have
enough firepower to virtually shoot people/sites/organizations off
the net, or extortion, or a combination of both. The extortion of
gambling websites before big sports events is just one example of
many cases of extortion involving DDoS. The attacker usually takes
the website down for a couple of hours to demonstrate his ability to
do so whenever it pleases him, and sends a mail to the owner of the
website, asking for money to keep the firepower away from his site.
This sort of business model is well known for millenia, and merely
found new applications online.
3.3) Spamming
This one is also about money in the end. Infected machines are
(ab)used as spam zombies. Each machine sends their master's
unsolicited mail to lots and lots of unwilling recipients. The
owners of these systems usually offer their services to the spam
industry and thus make money of it.
3.4) Adware
Yet another reason involving money. Just like on TV and Google,
advertisements can be sold. The more people seeing the
advertisement, the more money can be requested from the people that
pay for their slogan to be displayed on some end users Windows. (Of
course, it could be Linux and MacOS too, but, face it, no adware
attacks those)
3.5) Hacking
A worm that infects and backdoors a couple thousand hosts is a great
way to quickly and easily obtain data from those systems. Examples
of data that may be worth stealing includes accounts for online
games, credit card numbers, personal information that can be used in
identity theft scams, and more. There has even been a report that
items of online games were being stolen to sell those later on
E-bay. Already having compromised one machine, enhancing the
influence into some network can be much easier of course. Take for
example the case of a heavily firewalled company. A hacker can't get
inside using an active approach, but notices that one of his malware
serving websites infected a host within that network. Using a
connect-back approach, where the infected node connects to the
attacker, a can tunnel can be built through the firewall thereby
allowing the attacker to reach the internal network.
4) Botnets
While I did mention DDoS and spam as reasons for infection already,
what I left out so far was the infrastructure of hundreds or
thousands of compromised machines, which is usually called a
botnet. Once a worm has infected lots of systems, an
attacker needs some way to control his zombies. Most often the nodes
are made to connect to an IRC server and join a (password protected)
secret channel. Depending on the malware in use, the attacker can
usually command single or all nodes sitting on the channel to, for
example, DDoS a host into oblivion, look for game CD keys and dump
those into the channel, install additional software on the infected
machines, or do a whole lot of other operations. While such an
approach may be quite effective, it has several shortcomings.
- IRC is a plaintext protocol.
Unless every node builds an SSL tunnel to an SSL-capable IRCD,
everything that goes on in the channel will be sent from the IRCD to
all nodes connected, which means that someone sniffing from an
infected honeypot can see everything going on in the channel,
including commands and passwords to control the botnet. Such a
weakness allows botnets to be stolen or destroyed (f.ex. by issuing
a command to make them connect to a new IRCD which is on IP
127.0.0.1).
- It's a single point of failure.
What if the IRCD goes down because some victim contacted the admin
of the IRC server? On top of this, an IRC Op (a IRC administrator)
could render the channel inaccessible. If an attacker is left
without a way to communicate with all of the zombie hosts, they
become useless.
A way around this dilemma is to make use of dynamic DNS sites like
www.dyndns.org. Instead of making the zombies connect to
irc.somehost.com, the attacker can install a dyndns client which
then allows drones to reference a hostname that can be directed to a
new address by the attacker. This allows the attacker to migrate
zombies from one IRC server to the next without issue. Though this
solves the problem of reliability, IRC should not be considered
secure enough to operate a botnet successfully.
The question, then, is what is a better solution? It seems the
author of the trojan Phatbot already tried to find a way
around this problem. His approach was to include peer to peer
functionality in his code. He ripped the code of the P2P project
``Waste'' and incorporated it into his creation. The problem was,
though, that Waste itself didn't include an easy way to exchange
cryptographic keys that are required to successfully operate the
network, and, as such, neither did Phatbot. The author is not aware
of any case where Phatbot's P2P functionality was actually used.
Then again, considering people won't run around telling everyone
about it (well, not all of them at least), it's possible that such a
case is just not publicly known.
To keep a botnet up and running, it requires reliability,
authentication, secrecy, encryption and scalability. How can all of
those goals be achieved? What would the basic functionality of a
perfect botnet require? Consider the following points:
- An easy way to quickly send commands to all nodes
- Untraceability of the source IP address of a command
- Impossibile to judge from an intercepted command packet which node it was
addressed to
- Authentication schemes to make sure only authorized personnel operate the
zombie network
- Encryption to conceal communication
- Safe software upgrade mechanisms to allow for functionality enhancements
- Containment; so that a single compromised node doesn't endanger the entire
network
- Reliability; to make sure the network is still up and running when most of
its nodes have gone
- Stealthiness on the infected host as well as on the network
At this point one should distinguish between unlinked and
linked, or passive, botnets. Unlinked means each node is on
its own. The nodes poll some central resource for information.
Information can include commands to download software updates, to
execute a program at a certain time, or the order a DDoS on a given
target machine. A linked botnet means the nodes don't do anything by
themselves but wait for command packets instead. Both approaches
have advantages and disadvantages. While a linked botnet can react
faster and may be more stealthy considering the fact that it doesn't
build up periodic network connections to look out for commands, it
also won't work for infected nodes sitting behind firewalls. Those
nodes may be able to reach a website to look for commands, which
means an unlinked approach would work for them, but command packets
like in the linked approach won't reach them, as the firewall will
filter those out. Also, consider the case of trying to build up a
botnet with the next Windows worm. Infected Windows machines are
generally home users with dynamic IP addresses. End-user machines
change IPs regularly or are turned off because the owner is at work
or on a hunting weekend. Good luck trying to keep an up-to-date list
of infected IPs. So basically, depending on the purpose of the
botnet, one needs to decide which approach to use. A combination of
both might be best. The nodes could, for example, poll a resource of
information once a day, where commands that don't require immediate
attention are waiting for them. On the other hand if there's
something urgent, sending command packets to certain nodes could
still be an option. Imagine a sort of unlinked botnet. No node knows
about another node and nor does it ever contact one of its brothers,
which perfectly achieves our goal of containment. These nodes
periodically contact what the author has labeled a resource
of information to retrieve their latest orders. What could such a
resource look like?
The following attributes are desirable:
- It shouldn't be a single point for failure, like a single host that makes
the whole system break down once it's removed.
- It should be highly anonymous, meaning connecting there shouldn't be
suspicious activity. To the contrary, the more people requesting information
from it the better. This way the nodes' connections would vanish in the
masses.
- The system shouldn't be owned by the botnet master. Anonymity is one of the
botnet's primary goals after all.
- It should be easy to post messages there, so that commands to the botnet can
be sent easily.
There are several options to achieve these goals. It could be:
- Usenet: Messages posted to a large newsgroup which contain
steganographically hidden commands that are cryptographically signed
achieves all of the above mentioned goals.
- P2P networks: The nodes link to a server once in a while and, like hundreds
of thousands of other people, search for a certain term (``xxx''), and find
command files. File size could be an indicator for the nodes that a certain
file may be a command file.
- The Web itself: This one would potentially be slow, but of course it's also
possible to setup a website that includes commands, and register that site
with a search engine. To find said site, the zombies would connect to the
search engine and submit a keyword. A special title of the website would
make it possible to identify the right page between thousands of other hits
on the keyword, without visiting each of them.
Using those methods, it would be possible to administer even large
botnets without even having to know the IP adresses of the nodes.
The ``distance'' between botnet owner and botnet drone would be as
large as possible since there would be no direct connection between
the two. These approaches also face several problems, though:
How would the botnet master determine the number of infected hosts
that are up and running? Only in the case of the website would
estimation of the number of nodes be possible by inspecting the
access logs, even logging were to be enabled. In the case of the
Usenet approach a command of ``DDoS Ebay/Yahoo/Amazon/CNN'' might
just reach the last 5 remaining hosts, and the attacker would only
be left with the knowledge that it somehow didn't work. The problem
is, however, that the attacker would not know the number of zombies
that would actually take part in the attack. The same problem occurs
with the type and location of the infected hosts. Some might be high
profile, such as those connecting from big corporations, game
developers, or financial institutions. The attacker might be
interested in abusing those for something other than Spam and DDoS,
if he knew about them in particular. If the attacker wants to bounce
his connections over 5 of his compromised nodes to make sure he
can't be traced, then it is required that he be able to communicate
with 5 nodes only and that he must know address information about
the nodes. If the attacker doesn't have a clue which IP addresses
his nodes have, how can he tell 5 of them where to connect to?
Besides the obvious problem of timing, of course. If the nodes poll
for a new command file once every 24 hours, he'd have to wait 24
hours in the worst case until the last node finds out it's supposed
to bind a port and forward the connection to somewhere else.
4.1) The Linked Network
Though I called this approach a passive network, as the nodes idle
and wait for commands to come to them, this type of botnet is in
fact quite active. The mechanisms described now will not (easily)
work when most of the nodes are on dynamic IP addresses. It is thus
more interesting for nodes installed after exploiting some kind of
server software. Of course, while not solving the uptime problem, a
rogue dyndns account can always give a dynamic IP a static hostname.
This kind of network focuses on all of its nodes forming some kind
of self-organizing peer to peer network. A node that infects some
other host can send over the botnet program and make the new host
link to itself, thus becoming that node's parent. This technique can
make the infected hosts form a sort of tree structure over time, as
each newly infected host tries to link to the infecting host.
Updates, information, and commands can be transmitted using this
worm network to reach each node, no matter which node it was sent
from, as each node informs both child nodes as well as its parent
nodes. In its early (or final) stages, a network of this type might
look like this piece of ascii art:
Level
0 N
/ \
1 N N
/ \ /
2 N N N
To make sure a 'successful' node that infects lots of hosts doesn't
become the parent of all of those hosts, nodes must refuse link
requests from child nodes after a certain number have been linked
(say 5). The parent can instead in form the would-be child to link
to one of its already established children instead. By keeping track
of the number of nodes linked to each location in the tree, a parent
can even try to keep the tree thats hierarchically below it well
balanced. This way a certain node would know about its parent and up
to 5 children, thus keeping the number of other hosts that someone
who compromises a node rather low, while still making sure to have a
network that's as effective as possible. Depending on the number of
nodes in the entire network, the amount of children that may link to
a parent node could be easily changed to make the network scale
better. As each node may be some final link as well as a parent
node, every host runs the same program. There's no need for special
'client' and 'server' nodes.
Whats the problem with a tree structure? Well, what if a parent
fails? Say a node has 3 children, each having 2 children of its own.
Now this node fails because the owner decides to reinstall the host.
Are we left with 3 networks that can't communicate with each other
any more? Not necessarily. While possibly giving a forensics expert
information on additional hosts, to increase reliability each node
has to know about at least one more upstream node that it can try to
link to if its parent is gone. An ideal candidate could be the
parent's parent. In order to make sure that all nodes are still
linked to the network, a periodic (once a day) sort of ``ping''
through the entire network has to happen in any case. By giving a
child node the IP of its ``grandparent'', the direct parent of the
child node always knows that the fail-over node, the one its kids
will try to link to if it should fail, is still up and running.
Though this may help to address the issue of parent death, another
issue remains. If the topmost node fails, there are no more
upstream nodes that the children could link to. Thats why in this
case the children should have the ip of one(!) of its siblings as
the fail-over address so that they can make this one the new top
node in the case of a fail-over condition. Making use of the
node-based ping, each node also knows how many of its children are
still up and running. By including this number into the ping sent to
the parent, the topmost node could always tell the number of linked
hosts. In order to not have to rely on connecting to the topmost
node to collect this type of information, a simple command can be
implemented to make the topmost node report this info to any node on
the network that asks for it. Using a public key stored into all the
nodes, it's even possible to encrypt every piece of information
thats destined for the botnet owner, making sure that no one besides
the owner can decrypt the data. Although this type of botnet may
give a forensics expert or someone with a sniffer information on
other nodes that are part of the network, it also offers fast
response times and more flexibility in the (ab)use of the network
compared to the previous approach with the unlinked nodes. It's a
sort of trade off between the biggest possible level of anonymity on
one hand, and flexibility on the other. It is a huge step up
compared to all of the zombies sitting on IRC servers right now,
where a single channel contains the zombies of the entire botnet. By
employing cryptography to store the IPs of the child and parent
nodes, and keeping those IPs only in RAM mitigates the problem
further.
Once a drone network of this type has been established with several
hundreds of hosts, there are lots of possibilities of putting it to
use. To conceal the originating IP address of a connection, hopping
over several nodes of the drone network to a target host can be
easily accomplished. A command packet tells one node to bind a port.
Once it receives a connection on it, it is told to command a second
node to do the same, and from then on node 1 forwards all the
traffic to node 2. Node 2 does the same, and forwards to node 3,
then 4, maybe 5, until finally the last node connects to the
intended destination IP. By encrypting the entire connection from
the original source IP address up to the last node, a possible
investigator sniffing node 2 will not see the commands (and thus the
IP addresses) which tell node 3 to connect to node 4, node 4 to node
5, and of course especially not the destination host's address. An
idle timeout makes sure that connections don't stay up forever.
As manually updating several hundreds or thousands of hosts is
tedious work, an easy updating system should be coded into the
nodes. There are basically two possible ways to realize that. A
command, distributed from node to node all over the network, could
make each node replace itself with a newer version which it may
download from a certain HTTP address. The other way is by updating
the server software on one node, which in turn distributes this
update to all the nodes it's linked to (children and
parent), which do just the same. Cryptographic signatures are a must
of course to make sure someone doesn't replace all of the precious
nodes with SETI@home. Vlad902 suggested a simple and effective way
to do that. Each node gets an MD5 hash hardcoded into it. Whenever
someone offers a software update, it will download the first X bytes
and see wether they hash to the hardcoded value. If they do, the
update will be installed. Of course, a forensics expert may extract
the hash out of an identified node. However, due to the nature of
cryptographic hashes, he won't be able to tell which byte sequence
generates that hash. This will prevent the forensics export from
creating a malicious update to take down the network. As the value
used to generate the hash has to be considered compromised after an
update, each update has to supply a new hash value to look out for.
Further security mechanisms could include making the network
completely memory resident, and parents keeping track of kids, and
reinfecting those if necessary. What never hit the hard-disk can
obviously not be found by forensics. Also, commands should be
time-stamped to make sure a certain command will only work once, and
replay attacks (sending a sniffed command packet to trigger a
response from a node) will fail. Using public key cryptography to
sign and encrypt data and communication is always a nice idea too,
but it also has 2 disadvantages:
- It usually produces quite a big overhead to incorporate into the code.
- Holding the one and only private key matching to a public key thats been
found on hundreds of hacked hosts is quite incriminating evidence.
An additional feature could be the incorporation of global unique
identifiers into the network, providing each node with a unique ID
that's set upon installation on each new victim. While the network
master would have to keep track of host addresses and unique IDs, he
could use this feature to his advantage. Imagine a sort of
traceroute within the node network. The master wants to know where a
certain host is linked to. Every node knows the IDs of all of the
child nodes linked hierarchically below it. So he asks the topmost
node to find out the path to the node he's interested in. The
topmost node realizes it's linked somewhere under child 2, and in
turn asks child 2. This node knows it's linked somewhere below child
4, and so on and so on. In the end, the master gets his information,
a couple of IDs, while no node thats not directly linked to another
gets to know the IPs of further hosts that are linked to the
network.
Since a portscan shouldn't reveal a compromised host, a raw socket
must be used to sniff command packets off the wire. Also, command
packets should be structured as unsuspicious as possible, to make it
look like the host just got hit by yet another packet of ``internet
background noise''. DNS replies or certain values in TCP SYN packets
could do the trick.
4.2) The Hybrid
There is a way to combine both the anonymity of an unlinked network
with the quick response time of the linked approach. This can be
done by employing a technique first envisioned in the description of
a so-called ``Warhol Worm''. While no node knows anything about
other nodes, the network master keeps track of the IPs of infected
hosts. To distribute a command to a couple or maybe all of the
nodes, he first of all prepares an encrypted file containing the IPs
of all active nodes, and combines that with the command to execute.
He then sends this commandfile to the first node on the list. This
node executes the command, takes itself from the list, and goes top
to bottom through the list, until it finds another active node,
which it transmits the command file to. This way each node will only
get to know about other nodes when receiving commandfiles, which are
subsequently erased after the file has been successfully transmitted
to another node. By calling certain nodes by their unique IDs, it's
even possible to make certain nodes take different actions than all
the others. By preparing different files and sending them to
different nodes at start already, quite a fast distribution time can
be achieved. Of course, should someone accomplish to not only sniff
the commandfile, but also decrypt it, he has an entire list of
infected hosts. Someone sniffing a node will still also see an
incoming connection from somewhere, and an outgoing connection to
somewhere else, and thus get to know about 2 more nodes. Thats just
the same as depicted in the passive approach. Whats different is
that a binary analysis of a node will not divulge information on
another host of the network. As sniffing is probably more of a
threat than binary analysis though, and considering a linked network
offers way more flexibility, the Hybrid is most likely an inferior
approach.
5) Conclusion
When it comes to botnets, the malcode development is still in it's
infancy, and while today's networks are very basic and easily
detected, the reader should by now have realized that there are far
better and stealthier ways to link compromised hosts into a network.
And who knows, maybe one or more advanced networks are already in
use nowadays, and even though some of their nodes have been spotted
and removed already, the network itself has just not been identified
as being one yet.
Bibliography
The Honeypot Project. Know Your Enemy: Tracking Botnets.
http://www.honeynet.org/papers/bots/
Weaver, Nicholas C. Warhol Worms: The Potential for Very
Fast Internet Plagues.
http://www.cs.berkeley.edu/ nweaver/warhol.html
Paxson, Vern, Stuart Staniford Nicholas Weaver. How to
0wn the Internet in Your Spare Time.
http://www.icir.org/vern/papers/cdc-usenix-sec02/
Zalewski, Michael. Writing Internet Worms for Fun and
Profit.
http://www.securitymap.net/sdm/docs/virus/worm.txt

510
uninformed/1.6.txt Normal file
View File

@ -0,0 +1,510 @@
Mac OS X PPC Shellcode Tricks
H D Moore
hdm[at]metasploit.com
Last modified: 05/09/2005
0) Foreword
Abstract:
Developing shellcode for Mac OS X is not particularly difficult, but there are
a number of tips and techniques that can make the process easier and more eff
ective. The independent data and instruction caches of the PowerPC processor
can cause a variety of problems with exploit and shellcode development. The
common practice of patching opcodes at run-time is much more involved when the
instruction cache is in incoherent mode. NULL-free shellcode can be improved by
taking advantage of index registers and the reserved bits found in many
opcodes, saving space otherwise taken by standard NULL evasion techniques. The
Mac OS X operating system introduces a few challenges to unsuspecting
developers; system calls change their return address based on whether they
succeed and oddities in the Darwin kernel can prevent standard execve()
shellcode from working properly with a threaded process. The virtual memory
layout on Mac OS X can be abused to overcome instruction cache obstacles and
develop even smaller shellcode.
Thanks:
The author would like to thank B-r00t, Dino Dai Zovi, LSD, Palante, Optyx, and
the entire Uninformed Journal staff.
1) Introduction
With the introduction of Mac OS X, Apple has been viewed with mixed feelings by
the security community. On one hand, the BSD core offers the familiar Unix
security model that security veterans already understand. On the other, the
amount of proprietary extensions, network-enabled software, and growing mass of
advisories is giving some a cause for concern. Exploiting buffer overflows,
format strings, and other memory-corruption vulnerabilities on Mac OS X is a
bit different from what most exploit developers are familiar with. The
incoherent instruction cache, combined with the RISC fixed-length instruction
set, raises the bar for exploit and payload developers.
On September 12th of 2003, B-r00t published a paper titled "Smashing the Mac
for Fun and Profit". B-root's paper covered the basics of Mac OS X shellcode
development and built on the PowerPC work by LSD, Palante, and Ghandi. This
paper is an attempt to extend, rather than replace, the material already
available on writing shellcode for the Mac OS X operating system. The first
section covers the fundamentals of the PowerPC architecture and what you need
to know to start writing shellcode. The second section focuses on avoiding NULL
bytes and other characters through careful use of the PowerPC instruction set.
The third section investigates some of the unique behavior of the Mac OS X
platform and introduces some useful techniques.
2) PowerPC Basics
The PowerPC (PPC) architecture uses a reduced instruction set consisting of
32-bit fixed-width opcodes. Each opcode is exactly four bytes long and can only
be executed by the processor if the opcode is word-aligned in memory.
2.1) Registers
PowerPC processors have thirty-two 32-bit general-purpose registers (r0-r31)
PowerPC 64-bit processors have 64-bit general-purpose registers, but still use
32-bit opcodes, thirty-two 64-bit floating-point registers (f0-f31), a link
register (lr), a count register (ctr), and a handful of other registers for
tracking things like branch conditions, integer overflows, and various machine
state flags. Some PowerPC processors also contain a vector-processing unit
(AltiVec, etc), which can add another thirty-two 128-bit registers to the set.
On the Darwin/Mac OS X platform, r0 is used to store the system call number, r1
is used as a stack pointer, and r3 to r7 are used to pass arguments to a system
call. General-purpose registers between r3 and r12 are considered volatile and
should be preserved before the execution of any system call or library
function.
;;
;; Demonstrate execution of the reboot system call
;;
main:
li r0, 55 ; #define SYS_reboot 55
sc
2.2) Branches
Unlike the IA32 platform, PowerPC does not have a call or jmp instruction.
Execution flow is controlled by one of the many branch instructions. A branch
can redirect execution to a relative address, absolute address, or the value
stored in either the link or count registers. Conditional branches are
performed based on one of four bit fields in the condition register. The count
register can also be used as a condition for branching and some instructions
will automatically decrement the count register. A branch instruction can
automatically set the link register to be the address following the branch,
which is a very simple way to get the absolute address of any relative location
in memory.
;;
;; Demonstrate GetPC() through a branch and link instruction
;;
main:
xor. r5, r5, r5 ; xor r5 with r5, storing the value in r5
; the condition register is updated by the . modifier
ppcGetPC: