예제 #1
0
def analyze(debfile, package="?", group="?", show_errors=False):
    deb = DebFile(filename=debfile)
    tgz = deb.data.tgz()

    if not os.path.exists(debfile):
        # print >> sys.stderr, "%s doesn't exists!" % debfile
        pass

    if not debfile.endswith(".deb"):
        return

    output = {}
    output["package"] = package
    output["group"] = group
    output["build"] = os.path.basename(debfile)
    output["files"] = []
    output["daemon"] = False
    flag = False
    directory = False

    for entry in tgz.getmembers():
        size = entry.size

        # check if package is a daemon
        if "/etc/rc.d/init.d" in entry.name or "/lib/systemd" in entry.name:
            output["daemon"] = True

        # skip 0 byte files only
        if size == 0 and not stat.S_ISDIR(entry.mode):
            continue

        # we are only interested in particular kind of directories
        if stat.S_ISDIR(entry.mode):
            if not ((entry.mode & stat.S_ISUID) or
                    (stat.S_ISGID & entry.mode)):
                continue
            else:
                flag = True
                directory = True

        if not entry.mode & 0o111:
            continue

        # always report setuid files
        if ((entry.mode & stat.S_ISUID) or (stat.S_ISGID & entry.mode)):
            flag = True

        # skip library files
        filename = entry.name.lstrip(".")
        if ("lib" in filename and ".so" in filename) or \
           filename.endswith(".so"):
            continue

        try:
            contents = tgz.extractfile(entry).read()
        except Exception as exc:
            print(exc)

        # invoke checksec
        returncode = -1
        try:
            fh = BytesIO(contents)
            elf = Elf(fh)
            out = process_file(elf)
            returncode = 0
            dataline = "%s,%s,%s,%s" % (package, os.path.basename(debfile),
                                        filename, out)
        except ELFError as exc:
            continue
        except IOError as exc:
            continue

        # print p.returncode, filename
        if returncode == 0 or flag:
            # populate fileinfo object
            fileinfo = {}
            fileinfo["name"] = filename
            fileinfo["size"] = entry.size
            fileinfo["mode"] = entry.mode
            if directory:
                fileinfo["directory"] = directory
            output["files"].append(fileinfo)
        if returncode == 0 and opformat == "csv":
            print(dataline)
        if returncode == 0 and opformat == "json":
            try:
                for kvp in out.rstrip().split(","):
                    key, value = kvp.split("=")
                    fileinfo[key] = value
            except Exception:
                pass

        if opformat == "json":
            print(
                json.dumps(output,
                           sort_keys=True,
                           indent=4,
                           separators=(',', ': ')))
예제 #2
0
def analyze(debfile, package="?", group="?", show_errors=False):
    deb = DebFile(filename=debfile)
    tgz = deb.data.tgz()

    if not os.path.exists(debfile):
        # print >> sys.stderr, "%s doesn't exists!" % debfile
        pass

    if not debfile.endswith(".deb"):
        return

    output = {}
    output["package"] = package
    output["group"] = group
    output["build"] = os.path.basename(debfile)
    output["files"] = []
    output["daemon"] = False
    flag = False
    directory = False

    for entry in tgz.getmembers():
        size = entry.size

        # check if package is a daemon
        if "/etc/rc.d/init.d" in entry.name or "/lib/systemd" in entry.name:
            output["daemon"] = True

        # skip 0 byte files only
        if size == 0 and not stat.S_ISDIR(entry.mode):
            continue

        # we are only interested in particular kind of directories
        if stat.S_ISDIR(entry.mode):
            if not ((entry.mode & stat.S_ISUID) or (stat.S_ISGID & entry.mode)):
                continue
            else:
                flag = True
                directory = True

        if not entry.mode & 0o111:
            continue

        # always report setuid files
        if ((entry.mode & stat.S_ISUID) or (stat.S_ISGID & entry.mode)):
            flag = True

        # skip library files
        filename = entry.name.lstrip(".")
        if ("lib" in filename and ".so" in filename) or \
           filename.endswith(".so"):
            continue

        try:
            contents = tgz.extractfile(entry).read()
        except Exception as exc:
            print(exc)

        # invoke checksec
        returncode = -1
        try:
            fh = BytesIO(contents)
            elf = Elf(fh)
            out = process_file(elf)
            returncode = 0
            dataline = "%s,%s,%s,%s" % (package, os.path.basename(debfile),
                                        filename, out)
        except ELFError as exc:
            continue
        except IOError as exc:
            continue

        # print p.returncode, filename
        if returncode == 0 or flag:
            # populate fileinfo object
            fileinfo = {}
            fileinfo["name"] = filename
            fileinfo["size"] = entry.size
            fileinfo["mode"] = entry.mode
            if directory:
                fileinfo["directory"] = directory
            output["files"].append(fileinfo)
        if returncode == 0 and opformat == "csv":
            print(dataline)
        if returncode == 0 and opformat == "json":
            try:
                for kvp in out.rstrip().split(","):
                    key, value = kvp.split("=")
                    fileinfo[key] = value
            except Exception:
                pass

        if opformat == "json":
            print(json.dumps(output, sort_keys=True, indent=4,
                         separators=(',', ': ')))
예제 #3
0
        #   filename.endswith(".so")):
        #   continue

        try:
            contents = a.read(size)
        except Exception:
            continue

        # invoke checksec only on files
        returncode = -1
        if not directory:
            try:
                fh = cStringIO.StringIO(contents)
                elf = Elf(fh)
                if opformat == "json":
                    out = process_file(elf, deps = True)
                    # polkit check 2
                    if "polkit" in out:
                        output["polkit"] = True
                else:
                    out = process_file(elf)
                dataline = "%s,%s,%s,mode=%s,%s" % (package, os.path.basename(rpmfile),
                                            filename, oct(entry.mode), out)
                returncode = 0
            except ELFError as exc:
                if show_errors:
                    print >> sys.stderr, "%s,%s,Not an ELF binary" % \
                        (filename, str(exc))
                continue
            except IOError as exc:
                if show_errors:
예제 #4
0
def analyze(rpmfile, show_errors=False, opformat="json"):
    """Analyse single RPM file"""
    if not os.path.exists(rpmfile):
        print >> sys.stderr, "%s doesn't exists!" % rpmfile
        return

    if not rpmfile.endswith(".rpm"):
        # print >> sys.stderr, "skipping %s" % os.path.basename(rpmfile)
        return

    try:
        a = libarchive.Archive(rpmfile)
    except Exception as exc:
        print >> sys.stderr, rpmfile, str(exc)
        return

    try:
        ts = rpm.TransactionSet()
        ts.setVSFlags(rpm._RPMVSF_NOSIGNATURES)
        fd = os.open(rpmfile, os.O_RDONLY)
        h = ts.hdrFromFdno(fd)
        os.close(fd)
    except Exception as exc:
        print >> sys.stderr, rpmfile, str(exc)
        return

    # create lookup dictionary
    # print dir(h)
    # print dir(rpm)
    nvr = h[rpm.RPMTAG_NVR]
    package = h[rpm.RPMTAG_NAME]
    group = h[rpm.RPMTAG_GROUP]
    caps = h[rpm.RPMTAG_FILECAPS]
    names = h['FILENAMES']
    groups = h[rpm.RPMTAG_FILEGROUPNAME]
    users = h[rpm.RPMTAG_FILEUSERNAME]
    lookup = defaultdict(list)
    for n, u, g in zip(names, users, groups):
        lookup[n].append((u, g))

    filecaps = []
    for i, cap in enumerate(caps):
        if cap:
            filecaps.append([names[i], cap])

    pols = []
    lines = ""
    output = {}
    output["package"] = package
    output["group"] = group
    output["build"] = os.path.basename(rpmfile)
    output["files"] = []
    output["daemon"] = False
    output["nvr"] = nvr
    output["filecaps"] = filecaps
    output["polkit"] = False
    output["caps"] = False
    output["pols"] = pols

    if filecaps:
        output["caps"] = True

    flag = False

    for entry in a:
        directory = False
        size = entry.size
        # polkit checks, "startswith" is better but ...
        if "/etc/polkit" in entry.pathname or \
           "/usr/share/PolicyKit" in entry.pathname or \
           "/usr/share/polkit-1" in entry.pathname:
            pols.append(entry.pathname)
            output["polkit"] = True

        # check if package is a daemon
        if "/etc/rc.d/init.d" in entry.pathname or \
           "/lib/systemd" in entry.pathname:
            output["daemon"] = True

        # skip 0 byte files only
        # NOTE: size can be 0 due to compression also!
        if size == 0 and not stat.S_ISDIR(entry.mode):
            continue

        # we are only interested in particular kind of directories
        if stat.S_ISDIR(entry.mode):
            if not ((entry.mode & stat.S_ISUID) or
                    (stat.S_ISGID & entry.mode)):
                continue
            else:
                flag = True
                directory = True

        # check for executable flag
        # if not (entry.mode & 0111):
        #    continue

        # always report setxid files
        if ((entry.mode & stat.S_ISUID) or (stat.S_ISGID & entry.mode)):
            flag = True

        # skip library files
        filename = entry.pathname.lstrip(".")
        # if not flag and (("lib" in filename and ".so" in filename) or \
        #   filename.endswith(".so")):
        #   continue

        try:
            contents = a.read(size)
        except Exception:
            continue

        # invoke checksec only on files
        returncode = -1
        if not directory:
            try:
                fh = cStringIO(contents)
                elf = Elf(fh)
                if opformat == "json":
                    out = process_file(elf, deps=True)
                    # polkit check 2
                    if "polkit" in out:
                        output["polkit"] = True
                else:
                    out = process_file(elf)
                dataline = "%s,%s,%s,mode=%s,%s" % (package,
                                                    os.path.basename(rpmfile),
                                                    filename, oct(entry.mode),
                                                    out)
                returncode = 0
            except ELFError as exc:
                if show_errors:
                    print >> sys.stderr, "%s,%s,Not an ELF binary" % \
                        (filename, str(exc))
                continue
            except IOError as exc:
                if show_errors:
                    print >> sys.stderr, "%s,%s,Not an ELF binary" % \
                        (filename, str(exc))
                continue
        if flag or returncode == 0:
            # populate fileinfo object
            fileinfo = {}
            fileinfo["name"] = filename
            fileinfo["size"] = entry.size
            fileinfo["mode"] = entry.mode
            fileinfo["user"], fileinfo["group"] = lookup[filename][0]
            if directory:
                fileinfo["directory"] = directory
            output["files"].append(fileinfo)

        if returncode == 0 and opformat == "csv":
            lines = lines + dataline + "\n"
        else:
            # print >> sys.stderr, dataline
            pass
        if returncode == 0 and opformat == "json":
            try:
                for kvp in out.split(","):
                    key, value = kvp.split("=")
                    fileinfo[key] = value
            except Exception:
                pass
    a.close()

    if opformat == "json":
        return json.dumps(output)
    else:
        return lines.rstrip()