Various Style Tricks for Solaris SPARC Heap Overflows

As we saw in Chapter 10, every heap exploit that uses internal heap pointer manipulation macros or functions to write to arbitrary memory addresses also inserts one of the long words used in the exploit's fake chunk in the middle of the payload ( nop + shellcode). This is a problem, because we may hit this long word. When we encounter this long word, our execution will be terminated ; this word will most likely be an illegal instruction. Typically, exploits will insert a "jump some byte forward" instruction somewhere in the middle of the nop buffer, and assume that this will jump over the problematic long word and take us to the shellcode. We will introduce a novel nop strategy at this point that will make heap overflows much more reliable. Rather then inserting the "jump forward" instruction somewhere in the middle of the nop buffer, we will use alternative nops to reach our goal. Here is the nop pair taken from the dtspcd exploit:

 0x2c7f8:        bn,a   0x2c7f4 0x2c7fc:        xor  %l1, %l1, %l2 

The trick lies within the branch that is not within the annual instruction; we will use this to jump over the next xor instruction. In essence, we simply make the long word overwrite one of the xor instructions; thus, we jump right over it. There are two possible methods with which to accomplish this type of nop buffer arrangement.

Here is an unsuccessful jump to nop buffer.

 0x2c800:        bn,a   0x2c7fc 0x2c804:        xor  %l1, %l1, %l2 0x2c808:        bn,a   0x2c804 0x2c80c:        xor  %l1, %l1, %l2 0x2c810:        bn,a   0x2c80c 0x2c814:        xor  %l1, %l1, %l2 0x2c818:        bn,a   0x2c814 0x2c81c:        xor  %l1, %l1, %l2 0x2c820:        std  %f62, [ %i0 + 0x1ac ]                       -> overwritten with the fake chunk's long word 

Let's assume that we used address 0x2c800 within our fake chunk to overwrite the thr_jmp_table . This address unfortunately overwrites one of the branch instructions rather than a required xor instruction. This jump, even though successful, will die with an illegal instruction.

Here is a successful jump to nop buffer.

 0x2c804:        xor  %l1, %l1, %l2 0x2c808:        bn,a   0x2c804 0x2c80c:        xor  %l1, %l1, %l2 0x2c810:        bn,a   0x2c80c 0x2c814:        xor  %l1, %l1, %l2 0x2c818:        bn,a   0x2c814 0x2c81c:        xor  %l1, %l1, %l2 0x2c820:        bn,a   0x2c81c 0x2c824:        std  %f62, [ %i0 + 0x1ac ] 

Let's assume that this time we used address 0x2c804 within our fake chunk. Everything will work just fine, because the long word will overwrite one of the xor instructions, and we will happily jump over it. Rather determining which possibility is correct, we save time because we have only two possibilities. If we try every possible heap address twice, we are sure to hit our target. Again from the dtspcd exploit:

 self.exploit((each+self.ldso_base), self.retaddr_base)      self.exploit((each+self.ldso_base), self.retaddr_base+4)          self.retaddr_base += self.increment 

As we can see, every possible retaddr is tried twice with an increment of 4. In doing this, we assume that the first retaddr_base may overwrite a branch instruction rather than a xor instruction. If both won't work for us, then we can assume that heap address is not correct. We now calculate a new address by adding the incremental offset ( self.increment ) to our current heap address. This technique will make heap-based exploits much more reliable.

We will end this section by briefly explaining the SPARC shellcode we used in the dtspcd exploit. This shellcode assumes that incoming connections will always be tied to socket zero. At the time of writing, this is correct for every revision of the Solaris OS running dtspcd . Let's see how the shellcode reaches it goals in three simple steps.

Let's look at the first step.

 write(0, "/bin/ksh", 8); 

The shellcode writes the string "/bin/ksh" to the network socket in order to let the exploit (or client depending on how you view the exploitation of vulnerable systems) know that exploitation was successful. This will tell the exploit to stop brute forcing, and that the proxy loop should be entered. You may be thinking, why "/bin/ksh" ? The reason behind choosing Korn Shell is we do not want to increase the shellcode size by inserting a string like Success or Owned . We will use the string that will be used by the exec () system call, thus saving space.

Next, we have the second step.

 for(i=0; i < 3; i++) fcntl(0, F_DUP2FD, i); 

We will simply duplicate stdin , stdout , and stderr file descriptors for socket number zero.

On to the third step.

 exec("/bin/ksh", NULL); 

There you have the usual shell spawning trick, Solaris/SPARC style. This assembly component uses the string "/bin/ksh" , which is also used in the write() component, to inform the exploit that we have successful execution.



The Shellcoder's Handbook. Discovering and Exploiting Security
Hacking Ubuntu: Serious Hacks Mods and Customizations (ExtremeTech)
ISBN: N/A
EAN: 2147483647
Year: 2003
Pages: 198
Authors: Neal Krawetz

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net