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

New ZIP walk leaks content of nested ZIP files to /tmp #31

Closed
robert-scheck opened this issue Oct 31, 2017 · 8 comments
Closed

New ZIP walk leaks content of nested ZIP files to /tmp #31

robert-scheck opened this issue Oct 31, 2017 · 8 comments
Assignees
Labels
Milestone

Comments

@robert-scheck
Copy link
Contributor

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:

  1. cd MacroMilter/test_mails/
  2. zip test1.zip zipwithinfectedandnotinfectedword.zip
  3. zip test2.zip test1.zip
  4. zip test3.zip test2.zip
  5. zip test4.zip test3.zip
  6. zip test5.zip test4.zip
  7. zip test6.zip test5.zip
  8. Try to mail test6.zip (fails as expected)
  9. ls -l /tmp/*.zip
$ ls -l /tmp/*.zip
-rw-r--r-- 1 macromilter macromilter 12970 31. Okt 03:13 /tmp/test1.zip
-rw-r--r-- 1 macromilter macromilter 13138 31. Okt 03:13 /tmp/test2.zip
-rw-r--r-- 1 macromilter macromilter 13306 31. Okt 03:13 /tmp/test3.zip
-rw-r--r-- 1 macromilter macromilter 13474 31. Okt 03:13 /tmp/test4.zip
-rw-r--r-- 1 macromilter macromilter 13642 31. Okt 03:13 /tmp/test5.zip
-rw-r--r-- 1 macromilter macromilter 12746 31. Okt 03:13 /tmp/zipwithinfectedandnotinfectedword.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 like mktemp (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.

[Service]
PrivateTmp=true

which however still keeps the extracted files until logrotate (while nested ZIP files are hopefully not that common).

@decalage2
Copy link

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

@sbidy sbidy added this to the 3.4 milestone Oct 31, 2017
@sbidy sbidy self-assigned this Oct 31, 2017
@sbidy sbidy added the bug label Oct 31, 2017
@sbidy sbidy modified the milestones: 3.4, 3.5 Jan 3, 2018
sbidy added a commit that referenced this issue Jan 3, 2018
@sbidy
Copy link
Owner

sbidy commented Jan 3, 2018

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 😉 .

@robert-scheck
Copy link
Contributor Author

robert-scheck commented Jan 3, 2018

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.

@sbidy
Copy link
Owner

sbidy commented Jan 4, 2018

OK, I didn't noticed that problem.
Maybe the mkstemp brings a better solution for that?

sbidy added a commit that referenced this issue Jan 4, 2018
@sbidy
Copy link
Owner

sbidy commented Jan 4, 2018

I've updated the method with the mkstemp function. In my opinion it fixed the mentioned problem.

tmp_fs, tmpfpath = tempfile.mkstemp(suffix=extn)

@robert-scheck
Copy link
Contributor Author

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).

@sbidy
Copy link
Owner

sbidy commented Jan 5, 2018

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.

@sbidy
Copy link
Owner

sbidy commented Jan 3, 2019

implemented and released with 3.6

@sbidy sbidy closed this as completed Jan 3, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants