Closed robert-scheck closed 5 years ago
See the tempfile module to create temporary files more securely, and to clean up afterwards: https://docs.python.org/3/library/tempfile.html https://docs.python.org/2.7/library/tempfile.html
Now the zipwalk
removes the tmp files, also add a umask to create the tmp files only for the service user (0600). In the actual implementation it is not (easy) possible to use the tempflile lib.
I put a note to the backlog to re-implement this function in a later release. But the actual implementation works as expected (for zip archives). I'm open for some suggestions or implementation ideas 😉 .
I am sorry, but the actual implementation is securitywise still bad, given the /tmp
directory is directly consumed rather a safe temporary directory by using something like mktemp
(whatever the Python replacement for that is) or an application specific private directory such as /var/lib/macromilter/tmp
(similar like amavisd-new does). Leak and crash example based on the initial situation above (works also as unprivileged local user) applicable to latest commit fdd6828 in testing branch:
7b. touch /tmp/hardlink.zip
7c. chmod 666 /tmp/hardlink.zip
7d. ln /tmp/hardlink.zip /tmp/test2.zip
Content is leaked to world readable /tmp/hardlink.zip
given a predictable filename.
OK, I didn't noticed that problem. Maybe the mkstemp brings a better solution for that?
I've updated the method with the mkstemp
function. In my opinion it fixed the mentioned problem.
I'm not a python guy…how does this work logically now? Reading documentation tempfile.mkstemp()
creates a temporary file while I would have assumed using tempfile.mkdtemp()
to create a temporary working directory for unzipping into (and removing this temporary directory afterwards).
I used the mkstemp
to create new temp files to obfuscate the real filename and made it unpredictable. mkdtemp
only creates a temp folder but doesn't change the real file name.
I think booth are possible solution but the mkstemp
seems to me more secure.
Now, the zipwalk
method reads the OLE-files or archives and saves it to a random named temp file.
It also reads only the ole file objects to a generator and after the walk finished returns it.
After the generator was return, the files will be deleted in the /temp
folder.
implemented and released with 3.6
With 7d018ef, the new ZIP walk was introduced. Unfortunately it also leaks the content of nested ZIP files to
/tmp
directory – world readable by default. Reproducer:cd MacroMilter/test_mails/
zip test1.zip zipwithinfectedandnotinfectedword.zip
zip test2.zip test1.zip
zip test3.zip test2.zip
zip test4.zip test3.zip
zip test5.zip test4.zip
zip test6.zip test5.zip
ls -l /tmp/*.zip
From my point of view, MacroMilter should in any case clean up afterwards and it should not directly use
/tmp
, but a collision-free directory. Hardcoding e.g./tmp/macromilter
might lead to new issues (a local user could create that directory with modified permissions to gain the content), thus I would suggest something like either/var/lib/macromilter/tmp
(similar like amavisd-new does) or the usage of something similar likemktemp
(but in Python), while still applying more restrictive directory permissions.A regular user might mitigate this issue by setting in
/usr/lib/systemd/system/macromilter.service
e.g.which however still keeps the extracted files until logrotate (while nested ZIP files are hopefully not that common).