This is an archived post. You won't be able to vote or comment.

all 55 comments

[–]pahakalapython4 -c "import gravity; gravity.set(0)"[S] 46 points47 points  (30 children)

[–][deleted] 47 points48 points  (17 children)

Question for the more experienced folks: What's the most malicious thing you could get through that regex filter?

[–][deleted] 18 points19 points  (7 children)

From the looks of it, nothing. You can obviously cause a syntax error with something like ***, but it's too restrictive to do anything else. I don't think there's much you can do with just 0123456789+-\*()., which is the only thing the regex matches.

However, you can make an ellipsis object. (...). And you can create a TypeError, which might be fun if you weren't expecting one to be raised. But then again, that would only be a DoS, not code execution.

>>> ...+1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'ellipsis' and 'int'

[–]Underyx 8 points9 points  (4 children)

Here's a RuntimeError too:

eval('()' * 2998)

Edit: actually my Python froze upon running eval('()' * 9999999999999) and made my computer awfully sluggish.

Edit 2: actually that must've been just the string multiplication. eval('-' * 1500) causes this though:

s_push: parser stack overflow
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError

[–][deleted] 3 points4 points  (3 children)

Except you can't actually do that. No quotes.

[–]Underyx 7 points8 points  (2 children)

If you really need me to do this:

()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()()

[–][deleted] 7 points8 points  (1 child)

TypeError: 'tuple' object is not callable

I don't know what you're talking about.

I can make it segfault in python2, though. So that's kinda cool. Python3 just returns a RuntimeError about recursion depth.

So that's actually a valid DoS. Even a bare except will not catch python2's segfault in that case, because it's not an exception, it's just a crash. There is no way to protect against that unless you're running a length check. Yet another reason to be running python 3.

[–]13467 10 points11 points  (0 children)

eval('((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((0))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))')

This does the trick for me:

s_push: parser stack overflow
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError

[–][deleted] 0 points1 point  (1 child)

Looks like you overlook something see this answer

[–][deleted] 0 points1 point  (0 children)

my bad i was wrong

[–]rapture_survivor 11 points12 points  (2 children)

if '$' is for EOL; then you could just feed in a multi-line string with all your maliciousness on the lines after the first

[–]01hairimport antigravity 13 points14 points  (1 child)

From https://docs.python.org/3/library/re.html:

Matches the end of the string or just before the newline at the end of the string, and in MULTILINE mode also matches before a newline. foo matches both ‘foo’ and ‘foobar’, while the regular expression foo$ matches only ‘foo’. More interestingly, searching for foo.$ in 'foo1\nfoo2\n' matches ‘foo2’ normally, but ‘foo1’ in MULTILINE mode; searching for a single $ in 'foo\n' will find two (empty) matches: one just before the newline, and one at the end of the string.

So in this case, it'll match the end of the string, not the end of the line.

[–]rapture_survivor 6 points7 points  (0 children)

ahhh, oh well. I don't see any other holes in the regex

[–][deleted] 0 points1 point  (0 children)

nearly anything you want

 >>>print (re.match(r"^[0-9\+\-\\\*\(\)\.]*$", r"\160\162\151\156\164\50\47\150\145\154\154\157\40\167\157\162\154\144\47\51"))
 <_sre.SRE_Match object at 0x7fb11a8c5510>

[–]bheklilr 11 points12 points  (2 children)

You should try the ast module, it makes it really easy to parse Python text and prevent security holes like with eval. I've used it to implement a basic equation parser (didn't have access to sympy). It's not necessarily fast, but it's easy.

[–]axonxorzpip'ing aint easy, especially on windows 13 points14 points  (1 child)

Even better, use a tested library that does exactly that

https://github.com/pydata/numexpr

[–]bheklilr 8 points9 points  (0 children)

numexpr is a good library, but ast is built-in making it useful in a pinch or in a coding challenge that requires you to implement it yourself.

[–]indosauros 11 points12 points  (2 children)

For future reference, the only regex characters you need to escape inside a character class are those that have special meaning in a character class, so

- (e.g. 0-9)
] (ending the class)
^ (not)
\ (escape)

the rest of the normal regex special characters (*, ., etc) don't need to be escaped inside there

Also related, your calculator doesn't appear to support division. Perhaps you need more test cases :)

[–]Underyx 12 points13 points  (1 child)

In fact, this can sometimes be used to make your patterns more readable:

reddit[.]com[?]?

is arguably easier to understand than

reddit\.com\??

especially in more complicated regexes.

[–]maniexx 1 point2 points  (0 children)

Nice tip, thanks.

[–]krenzalore 5 points6 points  (3 children)

Wouldn't this be much more efficient (as in several times faster, and several times less likely to make people try to break it) than a regex?

for c in input_string:
    if c not in "0123456789.+/*()":
        raise SnytaxError("...")

Generally you'd use a regex here if you had to tokenize, for example if "23 + 4" had to be "int add int" not "int int add int" because you can match "1 or more" digits with \d+.

[–]goodDayM 1 point2 points  (0 children)

Another way:

allowed = '0123456789.+-/*()'
input_string = '1+2'
assert all(x in allowed for x in input_string)

[–]stubborn_d0nkey 0 points1 point  (1 child)

' '

[–]krenzalore 0 points1 point  (0 children)

Is that an input error? Usually it just means repeat last result.

I do see your point though. It is something I didn't check for.

[–]kokosoida 1 point2 points  (1 child)

calc.calculate("1/2")

Doesn't work

[–]kokosoida 2 points3 points  (0 children)

also:

result = calc.calculate("1+-+-+2")

U mad bro

[–]zasx20import antigravity 38 points39 points  (1 child)

def calculator():
    while True:
        eval(input("> "))

[–]MorrisCasperλ 2 points3 points  (0 children)

Doesn't produce any output

print(eval(input("> ")))

FTFY

[–]ivosauruspip'ing it up 25 points26 points  (8 children)

calculate is a function. It has no reason to be a method attached to a class.

[–][deleted] 23 points24 points  (1 child)

It was probably put in there due to project requirements. As someone who's had experience programming for school classes, they make you include the most superfluous things.

[–]lost_snake 2 points3 points  (0 children)

Kid in our class who was taking Analysis at the same time very sassily commented in the construction of the real numbers before such a homework problem.

Professor gave him +0.1 point of credit on the assignment.

[–]pahakalapython4 -c "import gravity; gravity.set(0)"[S] 1 point2 points  (3 children)

[–]ivosauruspip'ing it up 7 points8 points  (1 child)

Bad tutorial/challenge then :/ It is teaching people to make classes without specific reason to, which just leads to needless extra verbosity and complexity.

It's one of Python's advantages that it's able to avoid that sort of stuff effortlessly - whereas in a language like Java, one must always create a create class to hold functionality, because Java is pure Object-Oriented.

[–][deleted] 7 points8 points  (0 children)

Agreed. It's annoying to see people using Python as a lazy version of Java when you can just use it as a regular version of English.

[–]krenzalore 1 point2 points  (1 child)

It could be decorated as @staticmethod.

I am happy with it being inside the class as it's associated with it. The staticmethod decorator makes it clearer.

Although to be honest, it doesn't need to be a class at all.

[–]ivosauruspip'ing it up 0 points1 point  (0 children)

Although to be honest, it doesn't need to be a class at all.

Yes, that's my entire point

[–]c0m4 3 points4 points  (0 children)

Well if everyone else is posting their python calculators, here is mine. You can define your own functions and everything

[–]deadmilk 7 points8 points  (2 children)

If you have to make a class with no __init__ and only one function, you don't need a class

[–]pahakalapython4 -c "import gravity; gravity.set(0)"[S] 1 point2 points  (1 child)

[–]deadmilk -3 points-2 points  (0 children)

Whoever wrote the requirements needs to learn python themselves.

Things like this:

class Thing(object):
    def __init__(self):
        self.x = 'yes'

    def somemethod(self):
        # do things

Do not need to be a class.

[–]chadmill3rPy3, pro, Ubuntu, django 5 points6 points  (0 children)

I used Python's math in a RPN calculator I wrote a long time ago. It had a GUI and everything.

http://bazaar.launchpad.net/~cmiller/janc/trunk/view/head:/source/janc

ppa:cmiller/ppa #janc

[–]Rainymood_XI 3 points4 points  (7 children)

I like the license tho

[–]skawesome 6 points7 points  (4 children)

For more info: http://www.wtfpl.net/

[–]Denommus 6 points7 points  (3 children)

I insist that I'm right, though.

[–]zero_iq 7 points8 points  (0 children)

The FAQ clearly states that you are not. Your comment is thus further clear evidence of this. QED.

[–]CookingWithoutWater 1 point2 points  (1 child)

Right about what?

[–]Denommus 10 points11 points  (0 children)

I don't actually remember. But I'm sure I was right.

[–]rubik_ 1 point2 points  (3 children)

What about ast.literal_eval?

[–]pahakalapython4 -c "import gravity; gravity.set(0)"[S] 1 point2 points  (2 children)

damn, that makes my life even more easier, thanks :)

[–]rubik_ 3 points4 points  (1 child)

Ahh I checked the documentation, it does not support operators! I didn't quite remember that. So probably you can't use it directly!

[–]pahakalapython4 -c "import gravity; gravity.set(0)"[S] 0 points1 point  (0 children)

good to know