This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Python 2.7 : Buffer Overflow vulnerability in exec() function
Type: crash Stage: resolved
Components: Interpreter Core Versions: Python 2.7
process
Status: closed Resolution: wont fix
Dependencies: Superseder:
Assigned To: Nosy List: benjamin.peterson, brett.cannon, hadimene, josh.r, ncoghlan, serhiy.storchaka, terry.reedy, yselivanov
Priority: normal Keywords:

Created on 2018-02-03 17:09 by hadimene, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
poc.py hadimene, 2018-02-03 17:09
poc-print.py hadimene, 2018-02-03 17:29
Messages (7)
msg311561 - (view) Author: (hadimene) * Date: 2018-02-03 17:09
Hello !

Recently while debugging my python code I discovered an stack-based Buffer overflow Vulnerability in Python 2.7 and lower versions .
This vulnerability is caused by exec() builtin function when we create "recursive" function using exec() ...

Example :
We want to Print "hello World !" str and we encode print "hello world" ) using chr() or unichr()

print "hello World " 

becomes

exec(chr(112)+chr(114)+chr(105)+chr(110)+chr(116)+chr(40)+chr(39)+chr(104)+chr(101)+chr(108)+chr(108)+chr(111)+chr(32)+chr(119)+chr(111)+chr(114)+chr(108)+chr(100)+chr(32)+chr(33)+chr(32)+chr(39)+chr(41)+chr(10)+chr(35))

and if we re-encode the result : exec() the result would be

exec(chr(101)+chr(120)+chr(101)+chr(99)+chr(40)+chr(99)+chr(104)+chr(114)+chr(40)+chr(49)+chr(49)+chr(50)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(49)+chr(49)+chr(52)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(49)+chr(48)+chr(53)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(49)+chr(49)+chr(48)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(49)+chr(49)+chr(54)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(52)+chr(48)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(51)+chr(57)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(49)+chr(48)+chr(52)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(49)+chr(48)+chr(49)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(49)+chr(48)+chr(56)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(49)+chr(48)+chr(56)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(49)+chr(49)+chr(49)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(51)+chr(50)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(49)+chr(49)+chr(57)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(49)+chr(49)+chr(49)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(49)+chr(49)+chr(52)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(49)+chr(48)+chr(56)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(49)+chr(48)+chr(48)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(51)+chr(50)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(51)+chr(51)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(51)+chr(50)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(51)+chr(57)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(52)+chr(49)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(49)+chr(48)+chr(41)+chr(43)+chr(99)+chr(104)+chr(114)+chr(40)+chr(51)+chr(53)+chr(41)+chr(41)+chr(35))

If you do this manipulation 6-7 times and you run the encoded script then the Python Interpreter program will crash with a Segmentation Fault as error :
(https://lepetithacker.files.wordpress.com/2018/01/capture-dc3a9cran-2018-01-31-191359.png)

We can check the Segmentation Fault using gdb ( GNU Debugger ) https://lepetithacker.files.wordpress.com/2018/01/capture-dc3a9cran-2018-01-31-202241.png )

To get an Segmentation Fault error you can just run poc.py !

Conclusion

In my opinion , to patch this vulnerability developers need to give more memory/buffer to the exec() arguments , and verify if the buffer can contains exec() arguments in integrality without any overflow !
An attacker could control the memory of an server written in python if the builtin function exec() is used and python version i of the server is 2.7 or lower (every version of python2 could be vulnerable like Python 2.9 but I didn't tried yet )
msg311562 - (view) Author: Josh Rosenberg (josh.r) * (Python triager) Date: 2018-02-03 17:20
A server that exposes arbitrary exec's to user-submitted data can already be controlled. exec can do anything that Python can do, that's the whole point. Sure, crashing Python is bad, but it could also keep Python alive and start dumping the database to arbitrary people, deleting files, etc.

Also, your Proof of Concept code is cluttered with pointless garbage AFAICT. Do you really need all the unused multiline strings to trigger this?
msg311563 - (view) Author: (hadimene) * Date: 2018-02-03 17:29
Hello !

Thanks for the fast response but I tested and print() appears to be vulnerable too using chr() characters and yes the junk comments are useless ...
msg311564 - (view) Author: (hadimene) * Date: 2018-02-03 17:34
the comments lines are not needed !
msg311918 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-02-09 23:58
I am pretty sure that if one deletes the prefix 'exec(' and suffic ')' and just executes argument expression that has something on the order of 10000 chr(nn) calls added together, one would get the same result.  In other words, I believe that the outer exec and the origin of the expression and the individual nn values are irrelevant.

It is known that the Python compiler handles at least some recursive expressions with recursion and therefore has limits on the complexity of expressions it can handle.  The stackoverflow crash, instead of an exception, *is* a bug.  It was fixed sometime in 3.x.  With 3.6.4:

C:\Users\Terry>python f:/dev/tem/poc.py
RecursionError: maximum recursion depth exceeded during compilation

Perhaps one of the compiler experts knows whether the fix cannot be backported (within reasonable effort) or just has not been.
msg311919 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-02-10 00:02
#32758 is about situations where stackoverflow *can* occur in 3.x.
msg311943 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-02-10 08:23
I was going to write that this issue was fixed in Python 3 and it was decided to not backport the fix to Python 2. This is mostly true. But unfortunately there is a similar way of crashing Python 3
(issue32758).

This isn't a vulnerability. To exploit this bug the attacker need ability to execute an arbitrary code. An in that case crashing Python is not the worst result.

This bug can cause a problem with generated code (as in your joke example). In any case I have doubts that the fix for Python 3 will be backported to Python 2. I don't see a simple solution, the code of Python 2 and Python 3 is different enough, and there is less than 2 years of official support of Python 2.7 left. I suggest to close this issue with the resolution "wont fix".
History
Date User Action Args
2022-04-11 14:58:57adminsetgithub: 76938
2018-03-15 08:21:54serhiy.storchakasettype: security -> crash
2018-03-15 08:21:20serhiy.storchakasetstatus: open -> closed
resolution: wont fix
stage: resolved
2018-02-10 08:23:18serhiy.storchakasetmessages: + msg311943
2018-02-10 00:02:11terry.reedysetnosy: + serhiy.storchaka
messages: + msg311919
2018-02-09 23:58:33terry.reedysetnosy: + yselivanov, benjamin.peterson, terry.reedy, brett.cannon, ncoghlan
messages: + msg311918
2018-02-03 17:34:50hadimenesetmessages: + msg311564
2018-02-03 17:29:44hadimenesetfiles: + poc-print.py

messages: + msg311563
2018-02-03 17:20:41josh.rsetnosy: + josh.r
messages: + msg311562
2018-02-03 17:09:12hadimenecreate