So i personally believe log4sh type attacks across languages will become a lot more common. Because the risk is relatively low and a lot can be automated.
The reason this works in the java library is that the library explicitly adds functionality to evaluate the strings that are passed in, and has a meta-language for computing based on those values.
Python 3.10.1 (main, Dec 11 2021, 17:22:55) [GCC 11.1.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print(f"""{print("hello")}""")
hello
None
So Python runs the expression in { } and interpolates the result into the string.Presumably the { } has access to anything that's in scope.
(I'm not quite sure how common patterns are, but I assume the person is replying to is imagining a scenario where an attack is able to put some string payload into the { } before interpolation.)
>>> x=5
>>> print(x)
has access to X. A problem if, as parent asks,> there's an `eval` somewhere in Python's logger
So malicious actors is already shotgunning the log4sh attack so what stop them from spamming `{exec("import urllib.request;urllib.request.urlopen('http://example.com').read()")}` and see what stick.
While my example is for python im sure other languages will have similar issues and we will see a rise in format string attacks.
I up-voted all parties trying to prove me wrong, and someone already down-voted me(rightfully).
> o what stop them from spamming
Well I can't imagine how I would actually get that to turn into anything other than just a raw string that gets printed to the screen? Like I said, unless there's an eval somewhere it's not an issue.
edit: OK, I see the problem now. The flask article is a lot clearer.
The attacker can't control execution at all, or even really cause execution. What they can do is get your string to include information it should not - quite a footgun, but nothing close to RCE.
edit2: I maybe see a way this could be bad (if the attacker controls the format string that you call .format on), but I can't actually get it working myself.
So here's the thing. The attack as you've described does not work. Python won't just execute that string, you'll get a KeyError. What you need to do is, given a value provided to the string, call some sort of methods on that value such that you can perform your attack. This should be possible.
edit:
I'm trying to get this attack to work. So far, nah.
My assumptions are:
1. Attacker has full control over format string
2. `requests` is imported already (obviously you could just use the stdlib but I'm lazy)
3. An object or class is passed in
In theory I can construct a class from an object like this:
Foo.__class__('requests', (requests.Request,), dict())()
<Request [None]>
But so far that manifests as...>>> "{0.__class__('requests', (requests.Request,), dict())()}".format(Foo) Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: type object 'Foo' has no attribute '__class__('requests', (requests'
It seems that Python does not just naively execute what's inside of this thing.
Similarly,
>>> "{0.__init__((lambda: requests.get('google.com'))())}".format(Foo) Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: type object 'Foo' has no attribute '__init__((lambda'
If there's a way to exploit this for actual code execution I can't find it easily.
For example:
>>> user_data='{print("helo"}}'
>>> print(user_data)
{print("helo"}}
>>> print(f"{user_data}")
{print("helo"}}
>>> print(f"user_data")
user_data
>>> print(user_data.format())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'print("helo"'
Maybe there's some other way to express this bug?And as pointed out by another commenter my scenario is imaginary because user input needs to be passed to a f-strings. But I did update my original example with a tested `exec` because then you can import modules.
I do see my imaginary attack as low effort for a grey- or black-hat to automate and weaponize.
As mentioned/asked by parent, will we see mini renaissance of format string vulnerabilities, and I believe the answer is yes.
[0]: https://lucumr.pocoo.org/2016/12/29/careful-with-str-format/
>>> def server(userdata):
... print("Your data:", userdata)
...
>>> value = f"Printing... {print('Eval!')}"
Eval!
>>> server(value)
Your data: Printing... None