◐ Shell
clean mode source ↗

Issue 14001: CVE-2012-0845 Python v2.7.2 / v3.2.2 (SimpleXMLRPCServer): DoS (excessive CPU usage) by processing malformed XMLRPC / HTTP POST request

A denial of service flaw was found in the way Simple XML-RPC Server module of Python processed client connections, that were closed prior the complete request body has been received. A remote attacker could use this flaw to cause Python Simple XML-RPC based server process to consume excessive amount of CPU.

Credit:
Issue reported by Daniel Callaghan

References:
[1] https://bugzilla.redhat.com/show_bug.cgi?id=789790

Steps to reproduce:
------------------
A) for v3.2.2 version:

1) start server:
cat s.py 
#!/usr/local/bin/python3

from xmlrpc.server import SimpleXMLRPCServer
server = SimpleXMLRPCServer(('127.0.0.1', 12345))
server.serve_forever()

2) # top

3) issue request from client:
echo -e 'POST /RPC2 HTTP/1.0\r\nContent-Length: 100\r\n\r\nlol bye' | nc localhost 12345

Return to 'top' screen and see, how CPU consumption on particular host quickly moves to 100%.

B) for v2.7.2 version:

1) start server:

cat s.py 
#!/usr/bin/python

from SimpleXMLRPCServer import SimpleXMLRPCServer

server = SimpleXMLRPCServer(('127.0.0.1', 12345))
server.serve_forever()

Steps 2) and 3) for v2.7.2 version are identical to
those for v3.2.2 version.
With test.
test_xmlrpc has a timeout detection code which is simply broken (and it's actually documented): I just removed it, so if the server loops, the test will block. I think it's acceptable since other tests behave in the same way, and those days we have faulthandler that can be used to pinpoint such deadlocks/loops easily. Also, I've noticed that people are more inclined to fix tests that block than mere failing tests :-)
The test fails on 2.6 and 2.7, because of a EPIPE, which is normal in
this case (well, at least expected):
"""
test_partial_post (test.test_xmlrpc.SimpleServerTestCase) ...
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 47844)
Traceback (most recent call last):
  File "/home/cf/python/cpython/Lib/SocketServer.py", line 283, in
_handle_request_noblock
    self.process_request(request, client_address)
  File "/home/cf/python/cpython/Lib/SocketServer.py", line 309, in
process_request
    self.finish_request(request, client_address)
  File "/home/cf/python/cpython/Lib/SocketServer.py", line 322, in
finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/home/cf/python/cpython/Lib/SocketServer.py", line 617, in __init__
    self.handle()
  File "/home/cf/python/cpython/Lib/BaseHTTPServer.py", line 329, in handle
    self.handle_one_request()
  File "/home/cf/python/cpython/Lib/BaseHTTPServer.py", line 323, in
handle_one_request
    method()
  File "/home/cf/python/cpython/Lib/SimpleXMLRPCServer.py", line 490, in do_POST
    self.send_response(200)
  File "/home/cf/python/cpython/Lib/BaseHTTPServer.py", line 384, in
send_response
    self.send_header('Server', self.version_string())
  File "/home/cf/python/cpython/Lib/BaseHTTPServer.py", line 390, in send_header
    self.wfile.write("%s: %s\r\n" % (keyword, value))
  File "/home/cf/python/cpython/Lib/socket.py", line 318, in write
    self.flush()
  File "/home/cf/python/cpython/Lib/socket.py", line 297, in flush
    self._sock.sendall(buffer(data, write_offset, buffer_size))
error: [Errno 32] Broken pipe
"""

What should I do? Remove the test?