Hi,

Bernhard Schuster wrote:
> 
> I just got my nano 8GB 2G black..
> And after 2 days of extrem usage I got around a song which makes the nano
> reboot.
> If you are interested.. :-D

Let me guess... The song that you are playing is a kind of malformed
mp3. Either the size of the file or the mp3 stream does not conform to
standards...

Right ? :)

Actually we already know how to make it crash like this. ;)

What could be really interesting would be:

1) Code injection
-----------------
Quite easy in fact. As images, files and the inside of an mp3 are not
really checked. The big problem here is to get the precise address in
memory where the code is stored (maybe we can just get the address out
of a memory dump supposing that the dump start at 0x0 (or 0xFFFFFFFF).

2) Redirection of control flow
------------------------------
Our goal will be to take advantage of flaws like stack-overflows.
But you first have to know about the *stack-frame* concept.

The processor use a part of the memory to store temporary variables
(through push/pop operations) called the "stack". The stack is therefore
just a pile of machine words:

      0xfff | xxxx | higher addresses
            | .... |
      0x12b | 1234 |
      0x127 | 5678 | <- a 'pop' will get this value out
      0x123 |      | <- a 'push' will store something in here
            | .... |
      0x000 |      | lower addresses

Naturally, you need to know where is the top of the stack (the stack is
upside-down, so what looks like bottom is top and vice-versa). This
information is stored in a special register called sp (stack pointer).

      0xfff | xxxx | higher addresses
            | .... |
      0x12b | 1234 |
 sp-> 0x127 | 5678 |
      0x123 |      |
            | .... |
      0x000 |      | lower addresses

Here, sp value is 0x127.

When a 'push 9abc' occurs, sp is decremented and the value is stored on
the stack:

      0xfff | xxxx | higher addresses
            | .... |
      0x12b | 1234 |
      0x127 | 5678 |
 sp-> 0x123 | 9abc | <- new_sp = old_sp-4
            | .... |
      0x000 |      | lower addresses

When a 'pop reg1' occurs, sp is incremented and the value is pushed to
the register reg1.

      0xfff | xxxx | higher addresses
            | .... |
      0x12b | 1234 |
 sp-> 0x127 | 5678 | <- new_sp = old_sp+4
      0x123 | 9abc |
            | .... |
      0x000 |      | lower addresses

and reg1=9abc

Note that the value of the memory word 0x123 isn't cleared.

Ok, the problem is that most of the programming languages want to deal
with inter-procedural stuff, meaning that they want to have the ability
to deal with function calls and to embed them into each others.

So we have to store not only the stack pointer sp (pointing to the top
of the stack) but also the base pointer bp (pointing to the bottom of
the stack).

The pair (sp,bp) is called a 'stack frame' defining a totally fresh
memory stack for a function.

So the stack would look that way if we could get as much registers as we
want to store stack frames:

      0xfff | xxxx | higher addresses
            | .... |
bp1-> 0x10a | 0fcd | <- bottom of the stack frame #1
            | .... |
      0x12b | 1234 |
sp1-> 0x127 | 5678 | <- top of the stack frame #1
bp2-> 0x123 | 9abc |  <- bottom of the stack frame #2
            | .... |
sp2-> 0x01e | def0 | <- top of the stack frame #2
            | .... |
      0x000 |      | lower addresses

But we need to manage with only one register for sp and one register for
bp (see later).

A third, and last, important piece of information is the instruction
pointer (ip) which locates where is the current assembly instruction to
be executed.

      0xfff | xxxx | higher addresses
            | .... |
 bp-> 0x10a | 0fcd | <- bottom of the stack frame
            | .... |
      0x12b | 1234 |
 sp-> 0x127 | 5678 | <- top of the stack frame
      0x123 |      |
            | .... |                             --+
 ip-> 0x007 | push | <- instruction to be executed | code of functions
            | .... |                               | is stored here.
      0x000 |      | lower addresses             --+


Ok, we have everything now to explain function call.

Basically when a function foo(arg1, arg2) is called by a function bar()
the machine proceed that way:

1) The function bar() push the arguments of the function foo() on the stack:

 bp-> 0x12b | xxxx |
      0x127 | xxxx |
      0x123 | arg2 |
 sp-> 0x11f | arg1 |

2) Then call the function foo() through a 'call foo' which also means
means that:
 a) the value of ip off bar is saved on the stack in order to get back
to the right place in the code of bar when foo will return.

      0xfff |   xxxx   | higher addresses
            |   ....   |
 bp-> 0x10a |   xxxx   | <- bottom of the stack frame of bar()
            |   ....   |
      0x127 |   xxxx   |
      0x123 |   arg2   |
      0x11f |   arg1   |
 sp-> 0x11c | bar's ip | <- top of the stack frame of bar()
            |   ....   |
            |    nop   | <- start of the assembly code of bar()
 ip-> 0x00a | call foo | <- instruction to be executed
            |   ....   |
      0x008 |    nop   | <- start of the assembly code of foo()
            |   ....   |
      0x000 |          | lower addresses

  b) The content of ip is set to the beginning of foo()

      0xfff |   xxxx   | higher addresses
            |   ....   |
 bp-> 0x10a |   xxxx   | <- bottom of the stack frame of bar()
            |   ....   |
      0x127 |   xxxx   |
      0x123 |   arg2   |
      0x11f |   arg1   |
 sp-> 0x11c | bar's ip | <- top of the stack frame of bar()
            |   ....   |
            |    nop   | <- start of the assembly code of bar()
      0x00a | call foo |
            |   ....   |
 ip-> 0x008 |    nop   | <- start of the assembly code of foo()
            |   ....   |
      0x000 |          | lower addresses

  c) A new stack-frame is created by pushing bar's bp onto the stack and
setting bp to sp

        0xfff |   xxxx   | higher addresses
              |   ....   |
        0x10a |   xxxx   | <- bottom of the stack frame of bar()
              |   ....   |
        0x127 |   xxxx   |
        0x123 |   arg2   |
        0x11f |   arg1   |
   sp-> 0x11c | bar's ip |
bp=sp-> 0x119 | bar's bp | <- top of the stack frame of foo()
              |   ....   |
              |    nop   | <- start of the assembly code of bar()
        0x00a | call foo |
              |   ....   |
   ip-> 0x008 |    nop   | <- start of the assembly code of foo()
              |   ....   |
        0x000 |          | lower addresses

At this point foo() can be executed.

When foo() will hit an assembly instruction called 'return', the
reversed operations will be executed, meaning that:

 a) The content of the register sp will be set to bp.

 b) The content of the memory cell pointed by sp will be popped to bp
    (and sp will be incremented in consequence, pointing therefore to
     bar's ip).

 c) The content of the memory cell pointed by sp will be popped to ip
    (restoring the saved ip in bar() function).

Weeeeeeeell, it's nice but how can we take advantage of this to redirect
the execution flow ?

That's here that you need to know a trick !

In this very basic execution model, there are no type and if, for
example, I want to store a string there might be some places where I can
overwrite outside of the memory space intended to store the string.


      0xfff |   xxxx   | higher addresses
            |   ....   |
      0x10a |   xxxx   | <- bottom of the stack frame of bar()
            |   ....   |
      0x127 |   xxxx   |
      0x123 |   arg2   |
      0x11f |   arg1   |
 sp-> 0x11c | bar's ip |
 sp-> 0x119 | bar's bp | <- top of the stack frame of foo()
            |  mnoprst | <- last char
            |  ghijkl  |
first char->|  abcdef  |
            |   ....   |
            |    nop   | <- start of the assembly code of bar()
      0x00a | call foo |
            |   ....   |
 ip-> 0x008 |    nop   | <- start of the assembly code of foo()
            |   ....   |
      0x000 |          | lower addresses

When overwriting with a string, the part of the memory affected by the
rewrite will be *upward*. Meaning that if you are good enough to guess
where is located the beginning of the string you can also overwrite the
saved bar's bp and saved bar's ip.

Indeed, you are good enough to replace bar's saved ip by the location of
your injected code the system will jump to execute the code you just set
into the castle.

So, basically this is the technique we would like to use to get some of
our code inside the Nano and try use it to dump the whole memory.

Of course this is a _very_classical_ stack-overflow attack and this is
overdocumented on the Net. I would just recommand:

- Smashing the stack for fun and profit par AlephOne (Phrack 49, 1996).
- The frame pointer overwrite par Klog (Phrack 55, 1999).
- and many others...

That's all folks ! :)
-- 
Emmanuel Fleury              | Room:  261
Associate Professor,         | Phone: +33 (0)5 40 00 69 34
LaBRI, Domaine Universitaire | Fax:   +33 (0)5 40 00 66 69
351, Cours de la Libération  | Email: [EMAIL PROTECTED]
33405 Talence Cedex, France  | URL:   http://www.labri.fr/~fleury

_______________________________________________
Linux4nano-dev mailing list
[email protected]
https://mail.gna.org/listinfo/linux4nano-dev
http://www.linux4nano.org

Reply via email to