Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

asynchat does not check if terminator is negative integer #55468

Closed
socketpair mannequin opened this issue Feb 20, 2011 · 16 comments
Closed

asynchat does not check if terminator is negative integer #55468

socketpair mannequin opened this issue Feb 20, 2011 · 16 comments
Assignees
Labels
stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@socketpair
Copy link
Mannequin

socketpair mannequin commented Feb 20, 2011

BPO 11259
Nosy @vstinner, @giampaolo, @socketpair
Files
  • z.patch
  • qwe.py: long example how this bug may cause protocol errors
  • shorttest.py: Short test if bug exists in python installation
  • z31.patch: the same pathch, but for python 3.1
  • asynchat_tip.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/giampaolo'
    closed_at = <Date 2014-07-07.22:38:19.205>
    created_at = <Date 2011-02-20.16:40:01.224>
    labels = ['type-bug', 'library']
    title = 'asynchat does not check if terminator is negative integer'
    updated_at = <Date 2014-07-07.22:38:19.204>
    user = 'https://github.com/socketpair'

    bugs.python.org fields:

    activity = <Date 2014-07-07.22:38:19.204>
    actor = 'vstinner'
    assignee = 'giampaolo.rodola'
    closed = True
    closed_date = <Date 2014-07-07.22:38:19.205>
    closer = 'vstinner'
    components = ['Library (Lib)']
    creation = <Date 2011-02-20.16:40:01.224>
    creator = 'socketpair'
    dependencies = []
    files = ['20915', '20916', '20917', '20987', '34310']
    hgrepos = []
    issue_num = 11259
    keywords = ['patch']
    message_count = 16.0
    messages = ['128914', '128921', '128938', '129378', '129546', '129557', '129559', '129973', '129995', '129999', '130102', '182804', '212960', '222377', '222529', '222530']
    nosy_count = 7.0
    nosy_names = ['vstinner', 'giampaolo.rodola', 'Arfrever', 'BreamoreBoy', 'devin', 'socketpair', 'python-dev']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = None
    status = 'closed'
    superseder = None
    type = 'behavior'
    url = 'https://bugs.python.org/issue11259'
    versions = ['Python 3.4', 'Python 3.5']

    @socketpair
    Copy link
    Mannequin Author

    socketpair mannequin commented Feb 20, 2011

    asynchat does not check if terminator is negative integer. so constructions like self.ac_in_buffer[:n] will lead to misbehaviour.

    When that integer goes from net, attack can be crafted. For example, on Content-Length field.

    @socketpair socketpair mannequin added type-security A security issue stdlib Python modules in the Lib dir labels Feb 20, 2011
    @socketpair socketpair mannequin changed the title asynchat asynchat does not check if terminator is negative integer Feb 20, 2011
    @giampaolo
    Copy link
    Contributor

    What do you mean by "constructions like self.ac_in_buffer[:n] will lead to misbehaviour."?
    Please try to be more precise (e.g. by providing a piece of code which demonstrates the issue).

    @socketpair
    Copy link
    Mannequin Author

    socketpair mannequin commented Feb 21, 2011

    asynchat.py: class async_chat: handle_read():
    -----------------------
    elif isinstance(terminator, int) or isinstance(terminator, long):
    # numeric terminator
    n = terminator
    if lb < n:
    self.collect_incoming_data (self.ac_in_buffer)
    self.ac_in_buffer = ''
    self.terminator = self.terminator - lb
    else:
    self.collect_incoming_data (self.ac_in_buffer[:n])
    self.ac_in_buffer = self.ac_in_buffer[n:]
    self.terminator = 0
    self.found_terminator()
    ------------------------------
    suppose, terminator is -10. "if lb < n" never match. So, "else" branch executed.
    next, it will call "self.collect_incoming_data (self.ac_in_buffer[:n])", to push data to user. It should push some data from beginning of the buffer, intead of this, total buffer except last 10 characters pushed.

    Moreover, "self.ac_in_buffer = self.ac_in_buffer[n:]" shoudl give tail of the buffer, ut instead of this, "self.ac_in_buffer" will contain part of the tail.

    Such behaviour may break protocol parsing. In my case, malicious user pass 'Content-Length: -100' and totally break protocol parsing. Crafted values may gain memory leak.

    In any way, author of this code does not thought about negative n in constructions [:n] or [n:].

    @giampaolo
    Copy link
    Contributor

    Can you provide a patch including a test case?

    @socketpair
    Copy link
    Mannequin Author

    socketpair mannequin commented Feb 26, 2011

    Real patch is the first hunk of attached file. Other 2 hunks are optimizations..

    @socketpair
    Copy link
    Mannequin Author

    socketpair mannequin commented Feb 26, 2011

    only first hunk is really the patch. 2 next hunks are optimizations.

    @socketpair
    Copy link
    Mannequin Author

    socketpair mannequin commented Feb 26, 2011

    ===== ORIGINAL ===========

    $ ./qwe.py 10
    read length: 10
    read data: "xxxxxxxxxx"
    should read "test". read: "test"
    
    $ ./qwe.py -10
    read length: -10
    read data: "xxxxxx"
    should read "test". read: "xxxxtest"

    ===== PATCHED ===========

    $ ./qwe.py 10
    read length: 10
    read data: "xxxxxxxxxx"
    should read "test". read: "test"
    
    $ ./qwe.py -10
    read length: -10
    error: uncaptured python exception, closing channel <__main__.http_request_handler connected '' at 0x7fe69b9bf878> (<type 'exceptions.ValueError'>:Negative terminator value is not allowed [/usr/lib/python2.6/asyncore.py|read|78] [/usr/lib/python2.6/asyncore.py|handle_read_event|428] [/tmp/qwe/asynchat.py|handle_read|160] [./qwe.py|found_terminator|19] [/tmp/qwe/asynchat.py|set_terminator|98])
    root@fad:/tmp/qwe#

    @giampaolo
    Copy link
    Contributor

    Can you write an actual patch which includes tests?
    Also, I think the z.patch in attachment is targeted for python 2.x as it does not apply cleanly against the current trunk.

    @socketpair
    Copy link
    Mannequin Author

    socketpair mannequin commented Mar 3, 2011

    actual patch which includes tests
    I do not understand you. Probably I can not write that patch. Do not know how to. Sorry :(

    @giampaolo
    Copy link
    Contributor

    By "writing a test" I mean adding a unittest-based test case in Lib/test/test_asynchat.py which fails before fixing Lib/asynchat.py and succeeds afterwards.

    Now, I'm not even sure I properly understood your bug exactly.
    I've never used negative terminators in asynchat and I'm not even sure why one would want to.

    In this case, taking a look at a test would help me (and others) to understand what you are complaining about exactly and figure out whether this is actually a bug and if it is worth fixing it.

    As for how to properly write a patch see:
    http://www.python.org/dev/faq/
    All new patches should be applied to python 3.3 first so every time you submit a new one you should work on the 3.3 branch (current trunk) which is:
    http://svn.python.org/projects/python/branches/py3k/

    @socketpair
    Copy link
    Mannequin Author

    socketpair mannequin commented Mar 5, 2011

    I've never used negative terminators in asynchat and I'm not even sure why one would want to.
    no one wants :), but terminator numeric value may be achieved from the net, and hackers sometimes use such technique.

    attached shorttest.py do the test. If negative terminator is passed, ValueError exception will raise on patched version, and will not raise in unpatched.

    Currently, I studying test system for python, but I think you will add such simple test faster and cleaner.

    @devin
    Copy link
    Mannequin

    devin mannequin commented Feb 23, 2013

    I agree that this is probably a bug, but can't think of any instances where this in itself would cause a security issue. By sending something like a negative Content-Length, you do indeed get data returned that doesn't really match the data sent on the wire. If you're able to manipulate the Content-Length, though, instead of sending a negative value num, you could instead send len(data) + num.

    Here's a simple example I was able to come up with:

    Server reads data and runs "echo -n > {data}" (or any write the file specified in "data").
    Client is supposed to send Content-Length, then that many bytes, expected to be a file that should be written to.
    Client instead sends "-4\n/etc/passwd.bak".
    Server runs "echo -n > /etc/passwd".

    So that's certainly unexpected bahavior. However, this is a fairly low-level module, and doesn't actually do anything with the data it collects. That's left to the subclass, and subclasses should be responsible for validating any data read off the wire before using it.

    Attached is a patch to tip, including a new test case.

    @devin devin mannequin added type-bug An unexpected behavior, bug, or error and removed type-security A security issue labels Feb 23, 2013
    @devin
    Copy link
    Mannequin

    devin mannequin commented Mar 9, 2014

    updating the patch to the current tip

    @BreamoreBoy
    Copy link
    Mannequin

    BreamoreBoy mannequin commented Jul 5, 2014

    I've no objection to people trying to take this forward but they should be aware that asyncio is recommended for new code.

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Jul 7, 2014

    New changeset f67df13dd512 by Victor Stinner in branch '3.4':
    Issue bpo-11259: asynchat.async_chat().set_terminator() now raises a ValueError if
    http://hg.python.org/cpython/rev/f67df13dd512

    New changeset d164fda9063a by Victor Stinner in branch 'default':
    (Merge 3.4) Issue bpo-11259: asynchat.async_chat().set_terminator() now raises a
    http://hg.python.org/cpython/rev/d164fda9063a

    @vstinner
    Copy link
    Member

    vstinner commented Jul 7, 2014

    This issue is now fixed, thanks for the report. Sorry for the delay :-(

    Asy Mark wrote, asynchat is now deprecated: it's time to switch to the new shiny asyncio module!

    @vstinner vstinner closed this as completed Jul 7, 2014
    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    2 participants