summaryrefslogtreecommitdiff
path: root/python-plugins/zipbomb/plugin.py
blob: be8c12f235502ea3f6b15b5537f8c31d8cb0f48b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

import io
import zipfile

from pychrysalide.analysis.scan import ScanRegisteredItem
from pychrysalide.analysis.scan.exprs import ScanLiteralExpression
from pychrysalide.core import get_rost_root_namespace
from pychrysalide.plugins import PluginModule


class ZipBombKeyword(ScanRegisteredItem):
    """Introduce a new keyword in the ROST grammar."""

    _name = 'is_zip_bomb'


    def _reduce(self, ctx, scope):

        expr = None

        try:

            has_bomb = False

            # compress < 10% plain => bomb
            ZIP_BOMB_RATIO = 0.01

            data = io.BytesIO(ctx.content.data)

            zf = zipfile.ZipFile(data)

            info = zf.infolist()

            for i in info:

                ratio = i.compress_size / i.file_size

                has_bomb = ratio < ZIP_BOMB_RATIO

                if has_bomb:
                    break

            expr = ScanLiteralExpression(has_bomb)

        except:
            pass

        return expr


class ZipBombChecker(PluginModule):
    """Check for ZIP bombs."""

    _name = 'ZipBombChecker'
    _desc = 'Check if a ZIP archive may contain heavy files on extraction'
    _version = '0.1'
    _url = 'https://www.chrysalide.re/'

    _actions = ( )


    def __init__(self):
        """Create a ZipBombChecker plugin instance."""

        super().__init__()

        ns = get_rost_root_namespace()

        kw = ZipBombKeyword()

        ns.register_item(kw)