Bug 20004 - python-bottle new security issue CVE-2016-9964
Summary: python-bottle new security issue CVE-2016-9964
Status: RESOLVED FIXED
Alias: None
Product: Mageia
Classification: Unclassified
Component: Security (show other bugs)
Version: 5
Hardware: All Linux
Priority: Normal normal
Target Milestone: ---
Assignee: QA Team
QA Contact: Sec team
URL: https://lwn.net/Vulnerabilities/709842/
Whiteboard: MGA5-64-OK advisory MGA5-32-OK
Keywords: validated_update
Depends on:
Blocks:
 
Reported: 2016-12-22 00:35 CET by David Walser
Modified: 2017-01-29 23:31 CET (History)
4 users (show)

See Also:
Source RPM: python-bottle-0.12.9-1.mga6.src.rpm
CVE: CVE-2016-9964
Status comment:


Attachments

Description David Walser 2016-12-22 00:35:39 CET
Debian has issued an advisory on December 20:
https://www.debian.org/security/2016/dsa-3743

The issue is fixed upstream in 0.12.11.

The Debian bug has a link to the upstream fix:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=848392

Mageia 5 is also affected.
David Walser 2016-12-22 00:36:14 CET

Whiteboard: (none) => MGA5TOO

Comment 1 Philippe Makowski 2016-12-22 10:33:48 CET
Freeze push asked for cauldron.

For Mageia 5

New packages python-bottle-0.12.11-1.mga5.noarch.rpm and python3-bottle-0.12.11-1.mga5.noarch.rpm from python-bottle-0.12.11-1.mga5.src.rpm

redirect() in bottle.py in bottle 0.12.10 doesn't filter a "\r\n" sequence, which leads to a CRLF attack, as demonstrated by a redirect("233\r\nSet-Cookie: name=salt") call. 


Ref :
https://lwn.net/Vulnerabilities/709842/
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-9964

CVE: (none) => CVE-2016-9964
Version: Cauldron => 5
Assignee: makowski.mageia => qa-bugs
Whiteboard: MGA5TOO => (none)

Comment 2 Lewis Smith 2017-01-07 13:13:58 CET
While I am logged in...
No previous bugs for this package.
 Project site: http://bottlepy.org/
 Examples page: https://bottlepy.org/docs/dev/tutorial.html
To persue.

CC: (none) => lewyssmith

Comment 3 Lewis Smith 2017-01-11 11:58:36 CET
I am looking into this for x64.
Comment 4 Len Lawrence 2017-01-11 13:12:45 CET
I started on this about two weeks ago and tried to run one of the tutorial scripts but that failed on importing bottle - no such module.  Left it on the back-burner, so over to you Lewis.

CC: (none) => tarazed25

Comment 5 Lewis Smith 2017-01-13 10:43:53 CET
Notes on running bottlepy
------------------------
 https://bottlepy.org/docs/dev/tutorial.html
is good, does not explain some very basic points.
You can put bottle scripts anywhere, call them what you like, with extension .py
The essential link between the browser and the script is defined by:
 @route('/whatever')
which defines the path = procedure to run (here 'whatever') when the browser is pointed at it. Paths can comprise >1 part e.g:
 @route('/wrong/url')
in which case both parts need to be cited in the browser. A part can be 'generic' such that whatever one cites in the browser for it becomes a parameter to the destination procedure e.g.
 @route('/hello/<name>')
A single script can contain many procedures = paths, each identified by its own @route.

From the script directory, start by running it:
 $ python[3] scriptname.py
Bottle v0.12.7 server starting up (using WSGIRefServer())...
Listening on http://localhost:8080/
Hit Ctrl-C to quit.

*Then* point a browser at http://localhost:8080/<pathname>

The following example script (say testbottle.py) is so short it does not warrant being an attachment:
--------------------------------------
from bottle import route, run, template

@route('/hello/<name>')
def index(name):
    return template('<b>Hello {{name}}</b>!', name=name)

from bottle import redirect
@route('/wrong/url')
def wrong():
    redirect("http://localhost/")

run(host='localhost', port=8080)
-------------------------------
With testbootle.py running from a terminal:

http://localhost:8080/hello/example [any word suffices] yields
"Hello example!"                   [the word given]

http://localhost:8080/wrong/url yields the result of -> http://localhost/
"It works!"
Comment 6 Lewis Smith 2017-01-13 11:16:56 CET
Testing Mageia 5 x64

BEFORE update:   python-bottle-0.12.7-4.mga5   python3-bottle-0.12.7-4.mga5

Running the test script in Comment 5 gave the indicated results from both Python & Python3. Trying instead: 
 redirect("233\r\nSet-Cookie: name=salt")
given in Comment 1 supposed to trigger the fault
 http://localhost:8080/wrong/url yielded:
"Error: 404 Not Found
Sorry, the requested URL 'http://localhost:8080/wrong/233' caused an error:
Not found: '/wrong/233'"
and on the console:
 127.0.0.1 - - [13/Jan/2017 10:51:11] "GET /wrong/url HTTP/1.1" 303 0
 127.0.0.1 - - [13/Jan/2017 10:51:11] "GET /wrong/233 HTTP/1.1" 404 738
whereas in the correct base example, just the 303 line is output with "It works!".

This is inconclusive as a test case; never mind.

AFTER update:   python-bottle-0.12.11-1.mga5   python3-bottle-0.12.11-1.mga5

The correct test script gave correct output for both tests, python & python3.
Using instead the given POC
 redirect("233\r\nSet-Cookie: name=salt")
 http://localhost:8080/wrong/url yielded for both Pyhons:
"Error: 500 Internal Server Error
Sorry, the requested URL 'http://localhost:8080/wrong/url' caused an error:
Internal Server Error"
and on the console:
 Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/bottle.py", line 861, in _handle
    return route.call(**args)
  File "/usr/lib/python2.7/site-packages/bottle.py", line 1739, in wrapper
    rv = callback(*a, **ka)
  File "testbottle.py", line 10, in wrong
    redirect("233\r\nSet-Cookie: name=salt")
  File "/usr/lib/python2.7/site-packages/bottle.py", line 2426, in redirect
    res.set_header('Location', urljoin(request.url, url))
  File "/usr/lib/python2.7/site-packages/bottle.py", line 1546, in set_header
    self._headers[_hkey(name)] = [_hval(value)]
  File "/usr/lib/python2.7/site-packages/bottle.py", line 1409, in _hval
    raise ValueError("Header value must not contain control characters: %r" % value)
ValueError: Header value must not contain control characters: 'http://localhost:8080/wrong/233\r\nSet-Cookie: name=salt'
127.0.0.1 - - [13/Jan/2017 11:06:06] "GET /wrong/url HTTP/1.1" 500 750

This is quite a different result. Can Philippe say whether this is what is meant to happen? Reluctant to OK this without more expert comment.
Comment 7 David Walser 2017-01-13 12:00:46 CET
Philippe, please make sure you stay CC'd on a bug when you assign it to QA.

CC: (none) => makowski.mageia

Comment 8 Philippe Makowski 2017-01-13 14:02:01 CET
(In reply to David Walser from comment #7)
> Philippe, please make sure you stay CC'd on a bug when you assign it to QA.

I receive all qa-bugs, so no need.
I'll reply, but I quite busy at work, so let me some times
Comment 9 Philippe Makowski 2017-01-14 20:48:33 CET
(In reply to Lewis Smith from comment #6)
> This is quite a different result. Can Philippe say whether this is what is
> meant to happen? Reluctant to OK this without more expert comment.

All is correct, you can validate

Lewis get "It works!" because it have Apache running on its system, and seems that you don't.
Lewis Smith 2017-01-15 12:19:26 CET

Whiteboard: (none) => MGA5-64-OK

Lewis Smith 2017-01-15 13:09:49 CET

Whiteboard: MGA5-64-OK => MGA5-64-OK advisory

Comment 10 Len Lawrence 2017-01-29 01:54:44 CET
Hold this until I have time to test it on 32bit vbox.
Comment 11 Len Lawrence 2017-01-29 18:17:50 CET
Testing on i586 in virtualbox.

Used a tutorial script based on comment 5 and ran it under python and python3.
------------------------------------------------------------------- 
from bottle import route, run, template

@route('/hello/<name>')
def hello(name='pal'):
    return template("<b>Hello {{name}}, howzitgoan?<b>", name=name)

from bottle import redirect
@route('/wrong/url')
def wrong():
    redirect("http://localhost/")

run(host='localhost', port=8080, debug=True)
-------------------------------------------------------------------
This worked as expected both before and after updating python[3]-bottle.
terminal:
127.0.0.1 - - [29/Jan/2017 16:40:51] "GET /hello/Suzy HTTP/1.1" 200 29
"Hello Suzy, howzitgoan?"
127.0.0.1 - - [29/Jan/2017 16:42:07] "GET /wrong/url HTTP/1.1" 303 0
"It works!"

But, after update, on Ctrl-C the script issues a warning, e.g.

127.0.0.1 - - [29/Jan/2017 16:53:20] "GET /hello/Bill HTTP/1.1" 200 29
127.0.0.1 - - [29/Jan/2017 16:53:45] "GET /wrong/url HTTP/1.1" 303 0
^Csys:1: ResourceWarning: unclosed <socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080)>

The hint in the advisory about a PoC does not lead to a useful test, as Lewis observed but for sake of completeness:

from bottle import route, run, redirect

@route('/poctest/')
def poctest():
    redirect("233\r\nSet-Cookie:name=salt")

run(host='localhost', port=8080, debug=True)

Before update:
127.0.0.1 - - [29/Jan/2017 12:54:19] "GET /poctest HTTP/1.1" 404 734
127.0.0.1 - - [29/Jan/2017 12:54:26] "GET /poctest/ HTTP/1.1" 404 736

After update:

In browser:
ValueError("Header value must not contain control characters: 'http://localhost:8080/poctest/233\\r\\nSet-Cookie:name=salt'",)
then a Traceback which is also echoed on the terminal.

Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/bottle.py", line 861, in _handle
    return route.call(**args)
  File "/usr/lib/python2.7/site-packages/bottle.py", line 1739, in wrapper
    rv = callback(*a, **ka)
  File "poc.py", line 6, in poctest
    redirect("233\r\nSet-Cookie:name=salt")
  File "/usr/lib/python2.7/site-packages/bottle.py", line 2426, in redirect
    res.set_header('Location', urljoin(request.url, url))
  File "/usr/lib/python2.7/site-packages/bottle.py", line 1546, in set_header
    self._headers[_hkey(name)] = [_hval(value)]
  File "/usr/lib/python2.7/site-packages/bottle.py", line 1409, in _hval
    raise ValueError("Header value must not contain control characters: %r" % value)
ValueError: Header value must not contain control characters: 'http://localhost:8080/poctest/233\r\nSet-Cookie:name=salt'
127.0.0.1 - - [29/Jan/2017 17:01:48] "GET /poctest/ HTTP/1.1" 500 1977

Basic agreement with the earlier 64bit tests so OK for 32-bits.
Len Lawrence 2017-01-29 18:18:15 CET

Whiteboard: MGA5-64-OK advisory => MGA5-64-OK advisory MGA5-32-OK

Lewis Smith 2017-01-29 21:57:33 CET

Keywords: (none) => validated_update
CC: (none) => sysadmin-bugs

Comment 12 Mageia Robot 2017-01-29 23:31:59 CET
An update for this issue has been pushed to the Mageia Updates repository.

http://advisories.mageia.org/MGASA-2017-0031.html

Status: NEW => RESOLVED
Resolution: (none) => FIXED


Note You need to log in before you can comment on or make changes to this bug.