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=(',', ': ')))
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=(',', ': ')))
# 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:
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()