Search code examples
pythonformat-string

Meaning of characters in % string formatting (printf-style formatting)


I'm currently working through a format string exploit (writeUp config console picoctf) and came across that weird syntax (as part of the python script used for the pwn):

payload += ("%%%du|%%17$hn|" % 2493).rjust(16)

I know that the author intends to achieve to override a memory address with the above value (2493). I can achieve the same goal using the following syntax:

payload += "%2493x%17$hn".rjust(16)

So I do know about what the $ and hn means in the second part.

I'm mainly confused by the multiple '%' in the first version above and that the ' % 2493' appears outside the hyphens. I tried to google that but it will only lead to the standard format string explanations.

Someone can explain the first version above or perhaps has a link where the same is explained.


Solution

  • The % you see outside of the quotation marks is an operator (the same operator that takes a modulus for numbers). When its left argument is a string, it does "old style" string formatting. This was the main kind of string formatting until Python 2.6 introduced str.format, so you'll see it a lot in older code. The formatting language used by the % operator is very closely inspired by C's printf, so some programmers who are more used to C may also prefer it over the newer and perhaps more "Pythonic" formatting methods.

    In your example, the most relevant part of the format string is %d, which formats an argument as an integer. % is the character used to introduce substitutions in a format string, which is why you have another funny feature in the format string in two other places. If you want a single percent sign in the output, you need to put two in the format string: %%. You have that twice, once just before the %d and once later.

    The string you get at the end, "%2493x%17$hn" doesn't mean anything special to Python, but it might in some other language or in some special context. It would not work as a format string again, since %17$ is not a valid format specifier (%2493x is valid, though probably only by coincidence).