6 ms·
Played around with python for a similar attack and while it needs import and usage of f-string's i was rather taken back how easy it would be to spam the intern
by oneweekwonder 5y ago
Played around with python for a similar attack and while it needs import and usage of f-string's i was rather taken back how easy it would be to spam the internet with `f"""{exec("import urllib.request;urllib.request.urlopen('http://localhost:8000').read http://localhost:8000').read()")}"""` and variants, see what servers bite and then try to send them a more potent attack.
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.
- staticassertion 5y agoCan you elaborate? I don't see how you would exploit Python with a string like that unless there's an `eval` somewhere in Python's logger? I wouldn't exactly put it past the language, for sure, but I'm not aware of that being the case. 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.
- Quekid5 5y agoPython 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.)
- detaro 5y agoThis is no more a vulnerability than that >>> x=5 >>> print(x) has access to X. A problem if, as parent asks, > there's an `eval` somewhere in Python's logger
- oneweekwonder 5y agoIn my hypothetical scenario im not targeting the python logger but rather `''.format()` and f-strings that parse user input naively. A lot of people on /r/ mentions that they started to get '${jndi:...' in their server logs. 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 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.
- detaro 5y agof-strings don't "parse user input". .format doesn't have access to objects not explicitly provided to the call, and can't call functions. So again, how do you intend to trigger any of this if not through a hypothetical logger that uses eval?
- oneweekwonder 5y agoThanks for invalidating my naive/fud scenario, I must apologize for fearmongering, when I played with it in a py repl it really felt like a vector for attack. I up-voted all parties trying to prove me wrong, and someone already down-voted me(rightfully).
- staticassertion 5y agoIt's cool, I also poked at it a bit thinking there was potential. Certainly the Flask article makes some good points about it.
- staticassertion 5y agoI don't think this is right. .format() is not running any attacker controlled code. It might be formatting attacker controlled input, but the attacker has no control over the execution. > 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.
- _flux 5y agoYou may find that actually making this code to use data from user-provided data will make the code look quite unnatural and I doubt it would be accidentally written. 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?
- Quekid5 5y agoYeah, that's why I was quite skeptical about the exact scenario... it would probably look very out of place, but I don't have enough RW experience in Python to say for sure.
- oneweekwonder 5y agoThe author of flask(and a lot more python stuff) goes a bit into detail here[0]. 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/ https://lucumr.pocoo.org/2016/12/29/careful-with-str-format/
- ptx 5y agoPython f-strings don't work like that. The expression is evaluated when the string constant is defined, not when it's used, so your scenario is "code execution leads to code execution". >>> def server(userdata): ... print("Your data:", userdata) ... >>> value = f"Printing... {print('Eval!')}" Eval! >>> server(value) Your data: Printing... None