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

DoS smtpd vulnerability #45138

Closed
giampaolo opened this issue Jun 28, 2007 · 17 comments
Closed

DoS smtpd vulnerability #45138

giampaolo opened this issue Jun 28, 2007 · 17 comments
Assignees
Labels
stdlib Python modules in the Lib dir type-security A security issue

Comments

@giampaolo
Copy link
Contributor

BPO 1745035
Nosy @warsaw, @birkenfeld, @jcea, @josiahcarlson, @giampaolo
Files
  • smtpd.py
  • smtpd.diff
  • smtpd.diff: Updated patch (fixes described issue and adds a smaller timeout for asyncore.loop)
  • issue1745035-saviosena-101121.diff
  • issue1745035-101123-saviosena.diff
  • issue1745035-101123-saviosena.diff
  • issue1745035-101123-saviosena.diff
  • 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/josiahcarlson'
    closed_at = <Date 2010-12-03.07:38:35.871>
    created_at = <Date 2007-06-28.19:44:15.000>
    labels = ['type-security', 'library']
    title = 'DoS smtpd vulnerability'
    updated_at = <Date 2010-12-03.07:38:35.869>
    user = 'https://github.com/giampaolo'

    bugs.python.org fields:

    activity = <Date 2010-12-03.07:38:35.869>
    actor = 'georg.brandl'
    assignee = 'josiahcarlson'
    closed = True
    closed_date = <Date 2010-12-03.07:38:35.871>
    closer = 'georg.brandl'
    components = ['Library (Lib)']
    creation = <Date 2007-06-28.19:44:15.000>
    creator = 'giampaolo.rodola'
    dependencies = []
    files = ['8586', '8587', '9272', '19763', '19787', '19788', '19790']
    hgrepos = []
    issue_num = 1745035
    keywords = ['patch']
    message_count = 17.0
    messages = ['32418', '32419', '32420', '56019', '56627', '61599', '74047', '74073', '116697', '121874', '122064', '122231', '122232', '122235', '122239', '122241', '123195']
    nosy_count = 9.0
    nosy_names = ['barry', 'georg.brandl', 'jafo', 'jcea', 'josiahcarlson', 'giampaolo.rodola', 'BreamoreBoy', 'henriquebastos', 'saviosena']
    pr_nums = []
    priority = 'high'
    resolution = 'fixed'
    stage = None
    status = 'closed'
    superseder = None
    type = 'security'
    url = 'https://bugs.python.org/issue1745035'
    versions = ['Python 2.6', 'Python 2.5', 'Python 3.1', 'Python 2.7', 'Python 3.2']

    @giampaolo
    Copy link
    Contributor Author

    Method "collect_incoming_data" of "SMTPChannel" class should stop buffering if received lines are too long (possible Denial-of-Service attacks).
    Without truncating such buffer a simple malicious script sending extremely long lines without "\r\n" terminator could easily saturate system resources.

    @giampaolo giampaolo added stdlib Python modules in the Lib dir labels Jun 28, 2007
    @giampaolo
    Copy link
    Contributor Author

    --- malicious script

    import socket
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(("127.0.0.1", 8025))
    while 1:
        s.sendall('x' * 1024)

    --- proposed smtpd.py patch

    124a125

        self.\_\_in_buffer_len = 0
    

    135a137,139

        self.\_\_in_buffer_len += len(data)
        if self.\_\_in_buffer_len \> 4096:
            self.\_\_line = []
    

    @giampaolo
    Copy link
    Contributor Author

    Sorry, I realized I've forgotten to reset to zero the bytes counter.
    Here's the patch of the patch:

    124a125

        self.\_\_in_buffer_len = 0
    

    135a137,140

        self.\_\_in_buffer_len += len(data)
        if self.\_\_in_buffer_len \> 4096:
            self.\_\_line = []
            self.\_\_in_buffer_len = 0
    

    141a147

        self.\_\_in_buffer_len = 0
    

    @jafo
    Copy link
    Mannequin

    jafo mannequin commented Sep 19, 2007

    Patch is inline above.

    RFC2822 says lines MUST be less than 998 bytes long, so this should be fine.

    What does this do when a line longer than 4096 bytes is found? Does it
    report an error to the SMTP client? That's my only concern.

    @jafo jafo mannequin assigned warsaw Sep 19, 2007
    @giampaolo
    Copy link
    Contributor Author

    What does this do when a line longer than 4096 bytes
    is found? Does it report an error to the SMTP client?
    That's my only concern.

    Sorry for replying so late.
    No, it does not report the error and this is bad.
    I've searched through RFCs and I found that RFC 821 and RFC 2821 at
    chapter 4.2.2 say that a 500 "Syntax error, command unrecognized"
    response could be used to report errors such as command lines too long.

    Modified smtpd.py in attachment. It should be definitively fine for
    inclusion now.

    @giampaolo giampaolo added type-security A security issue labels Oct 21, 2007
    @giampaolo
    Copy link
    Contributor Author

    I update this bug as GvR requested here:
    http://groups.google.it/group/python-dev2/browse_thread/thread/33cad7b7c1cdb19f?hl=it
    The patch in attachment fixes what discussed before.

    In addition it sets a smaller timeout for asyncore.loop() for permitting
    to stop the daemon via KeyboardInterrupt immediately.

    @josiahcarlson
    Copy link
    Mannequin

    josiahcarlson mannequin commented Sep 29, 2008

    The patch does not work as Giampaolo intends. If the patch were applied
    as-is, no emails longer than 998 bytes could be sent.

    Instead, incrementing linelen in the collect_incoming_data() method
    should only be performed if self.terminator == '\r\n'.

    I can apply a modified version of this patch against trunk after 2.6 is
    released. Backports to 2.5 and 2.6 should then be discussed.

    @josiahcarlson josiahcarlson mannequin assigned josiahcarlson and unassigned warsaw Sep 29, 2008
    @giampaolo
    Copy link
    Contributor Author

    Yes, you're right. I mixed up SMTP with FTP which does not send data on
    the same connection used for receiving commands.

    @BreamoreBoy
    Copy link
    Mannequin

    BreamoreBoy mannequin commented Sep 17, 2010

    Given the title, type and severity shouldn't someone take a look at this?

    @saviosena
    Copy link
    Mannequin

    saviosena mannequin commented Nov 21, 2010

    The definite (and only?) solution would be to implement 'Message Size Declaration[1]' Service Extension[2]. We can limit the size of commands and text lines, but not the message size as a whole[3]. RFC1870 was created exactly with the purpose of solving DoS issues[4].

    [1] RFC 1870
    [2] RFC 1869
    [3] RFC 2821, 4.5.3.1
    [4] RFC 1870, 9.0

    I'm willing to implement a fix (actually, I'm already working on that :-)) --- but I'd make good use of advices since I'm new to this project.

    The minimalistic fix to this issue would be to implement Message Size Extension alone and apart from subclasses awareness --- without any changes to the interface, not even to allow changes in the default maximum message size [once SMPTServer is fully-RFC1869-compliant changing these values will be straightforward].

    A second (extensive!) approach is to implement a complete ESMTPServer. That's a way bigger task though. It would be wise in this case to implement all the standard extensions, plus support (parsing/error handling) to all RFC1869.

    Any thoughts?
    My best regards.

    NOTE: In my opinion there's no bug, really. All non-extented SMPT servers are vulnerable to resource exhaustion. Maybe we should take this as a feature request not a bug-fix request.

    @saviosena
    Copy link
    Mannequin

    saviosena mannequin commented Nov 22, 2010

    The attached patch adopts the minimalistic approach described in previous post. It pretends to implement Message Size Extension, defining a maximum message data size to 32M bytes and maximum command length to 512 bytes.

    In my opinion this is the best way to accomplish a patch to the DoS issue alone. It's still a good idea though to implement full ESMTP support -- I know, I'm repeating myself.

    Please note this is my first patch. I'm new to Python and even though I made my best to be in conformance with the "standards" and good practices I may have missed something. Please review this patch with clinical eyes.

    For the records: this work is due to Python Bug Day. It worked to attract another curious developer. :-) This project is really awesome. Congratz you all.

    My best regards.

    @saviosena
    Copy link
    Mannequin

    saviosena mannequin commented Nov 23, 2010

    Attaching a more concise patch, as requested by georg.brandl.

    @giampaolo
    Copy link
    Contributor Author

    I think data_size_limit and command_size_limit should be class attributes instead of instance attributes.

    @saviosena
    Copy link
    Mannequin

    saviosena mannequin commented Nov 23, 2010

    Previous patch was incorrect. I'm attaching another one, I'm really sorry.

    @giampaolo, about making the limits class attributes, it's not a good idea IMHO. According to RFC1869 command sizes can change depending on which Service Extensions are supported.

    @saviosena
    Copy link
    Mannequin

    saviosena mannequin commented Nov 23, 2010

    size_limits are not class attributes instead of instance attributes, as suggested by giampaolo.rodola.

    @giampaolo
    Copy link
    Contributor Author

    AFAICT patch looks ok to me.

    @birkenfeld
    Copy link
    Member

    Committed in r86955. Thanks!

    @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-security A security issue
    Projects
    None yet
    Development

    No branches or pull requests

    3 participants