-1

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.

Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
Zapho Oxx
  • 275
  • 1
  • 16
  • Probably the author of the code (I'm not going to read this long article) wants to use `payload` later like this: `real_payload = payload % (val1, val2, val3,...)`. I'm not sure about that because `%17$hn` would lead to a `unsupported format character '$' (0x24)...` exception. Anyway from the snippet you've posted, they are meaningless. – Pablo Feb 04 '18 at 21:14
  • hi all, i just realised that it might actually be a python formatting thing i wasnt aware of as I typically use python3 and the .format() syntax instead of the old python2 % syntax. So "%d" % 5 will replace %d with with the value 5 and %% will place a single %. Mystery solved. Thanks for your support people. – Zapho Oxx Feb 04 '18 at 21:21

2 Answers2

3

$ and hm means nothing special, they are just characters within you string. Simply run the string formatting code and you'll see:

>>> "%%%du|%%17$hn|" % 2493
'%2493u|%17$hn|'

In the above string %d is getting replaced by your number 2493 and %% is used to display % in your string as single % carries a special meaning in %-string formatting. Rest are normal string character.

%-formatting (also known as printf-style string formatting) is a old style of Python's string formatting which is these days is generally done by using str.format function. PEP 3101 proposed the replacement of the % operator with the new, advanced string formatting.

A very nice comparison between both is available at: "Python string formatting: % vs. .format"


From the "printf-style String Formatting" document, it allows following conversion types:

Conversion   Meaning
'd'          Signed integer decimal.     
'i'          Signed integer decimal.     
'o'          Signed octal value.
'u'          Obsolete type – it is identical to 'd'.    
'x'          Signed hexadecimal (lowercase).    
'X'          Signed hexadecimal (uppercase).    
'e'          Floating point exponential format (lowercase).
'E'          Floating point exponential format (uppercase).
'f'          Floating point decimal format.
'F'          Floating point decimal format. 
'g'          Floating point format. Uses lowercase exponential format if exponent is less than -4 or not less than precision, decimal format otherwise.
'G'          Floating point format. Uses uppercase exponential format if exponent is less than -4 or not less than precision, decimal format otherwise.
'c'          Single character (accepts integer or single character string).  
'r'          String (converts any Python object using repr()).  
's'          String (converts any Python object using str()).   
'a'          String (converts any Python object using ascii()). 
'%'          No argument is converted, results in a '%' character in the result.

and has conversion flags characters as:

+------+--------------------------------------------------------------------------------------------------------------+
| Flag | Meaning                                                                                                      |
+------+--------------------------------------------------------------------------------------------------------------+
| '#'  | The value conversion will use the “alternate form” (where defined below).                                    |
+------+--------------------------------------------------------------------------------------------------------------+
| '0'  | The conversion will be zero padded for numeric values.                                                       |
+------+--------------------------------------------------------------------------------------------------------------+
| '-'  | The converted value is left adjusted (overrides the '0' conversion if both are given).                       |
+------+--------------------------------------------------------------------------------------------------------------+
| ' '  | (a space) A blank should be left before a positive number (or empty string) produced by a signed conversion. |
+------+--------------------------------------------------------------------------------------------------------------+
| '+'  | A sign character ('+' or '-') will precede the conversion (overrides a “space” flag).                        |
+------+--------------------------------------------------------------------------------------------------------------+
Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
1

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).

Blckknght
  • 100,903
  • 11
  • 120
  • 169