├── .gitignore ├── Model ├── File.py ├── Function.py └── Variable.py ├── README.md ├── controller └── CodeAudit.py ├── func.json └── main.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ -------------------------------------------------------------------------------- /Model/File.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | from Model import Function 3 | from Model import Variable 4 | 5 | ''' 6 | 文件模型 用来存储文件的方法行数以及调用的变量 7 | ''' 8 | class File: 9 | def __init__(self,filename): 10 | self.file_name = filename 11 | # 文件所有方法 12 | self.funcs = {} 13 | # 文件所有变量 14 | self.vars = {} 15 | # 危险代码 16 | self.danger_line = {} 17 | 18 | # 添加方法 19 | def add_func(self,func,line): 20 | try: 21 | function = Function.Function(func, line) 22 | self.funcs[func] = function 23 | except Exception as e: 24 | print(e) 25 | exit(10087) 26 | 27 | # 获取某个方法 28 | def get_func(self,func_name): 29 | if func_name in self.funcs: 30 | return self.funcs[func_name] 31 | else: 32 | return None 33 | 34 | # 添加变量 35 | def add_variable(self,var_name,line): 36 | try: 37 | variable = Variable.Variable(var_name,line) 38 | self.vars[var_name] = variable 39 | except Exception as e: 40 | print(e) 41 | exit(10088) 42 | 43 | # 获取某个变量 44 | def get_variable(self,var_name): 45 | if var_name in self.vars: 46 | return self.vars[var_name] 47 | else: 48 | return None 49 | 50 | # 获取文件地址和文件名 51 | def get_file_name(self): 52 | return self.file_name -------------------------------------------------------------------------------- /Model/Function.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | ''' 4 | 函数模型 用来记录函数所在的行数以及调用的变量 5 | ''' 6 | class Function: 7 | def __init__(self,func_name,line): 8 | self.func_name = func_name # 函数名 9 | self.line = line # 所在行数 10 | 11 | # 获取行数 12 | def get_line(self): 13 | return self.line 14 | 15 | # 获取方法名 16 | def get_func_name(self): 17 | return self.func_name -------------------------------------------------------------------------------- /Model/Variable.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | ''' 3 | 变量模型 记录变量所在的行数 4 | ''' 5 | 6 | class Variable: 7 | def __init__(self,var_name,line): 8 | self.var_name = var_name 9 | self.line = line 10 | 11 | # 获取变量行数 12 | def get_line(self): 13 | return self.line -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ```c# 2 | __ ___ __ _ __ 3 | ____ / /_ ____ / | __ __ ____/ / (_) / /_ 4 | / __ \/ __ \/ __ \ / /| | / / / / / __ / / / / __/ 5 | / /_/ / / / / /_/ / / ___ | / /_/ / / /_/ / / / / /_ 6 | / .___/_/ /_/ .___/ /_/ |_| \__,_/ \__,_/ /_/ \__/ 7 | /_/ /_/ 8 | ``` 9 | 10 | # phpAudit 11 | 12 | PHP代码审计系统(开发中……) 13 | 14 | ## 安装 15 | 16 | ` git clone https://github.com/ETOCheney/phpAudit ` 17 | 18 | ## 使用 19 | 20 | #### 获取帮助 21 | 22 | ` python main.py -h ` 23 | 24 | #### 开始扫描 25 | 26 | ` python main.py -P [php文件地址] ` 27 | 28 | #### GUI界面 29 | 30 | 开发中…… 31 | 32 | # 其他想法 33 | 34 | 基于构建AST树、程序控制流程图。对php代码进行数据流信息收集、对调用函数过滤,查看是否有危险操作,变量是否被过滤。之后对手机的信息做污点分析等 35 | 36 | 但限于CFG算法没接触暂时写一个基于正则匹配 -------------------------------------------------------------------------------- /controller/CodeAudit.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import os 3 | import re 4 | import chardet 5 | from Model import File 6 | import json 7 | 8 | ''' 9 | 审计类 10 | ''' 11 | 12 | 13 | class FileList: 14 | 15 | def __init__(self, file_path, rule): 16 | # 切换工作目录至php代码的目录 17 | os.chdir(file_path) 18 | self.files = self.dir_list() 19 | self.rule = rule 20 | # 保存php工程目录 21 | self.php_path = file_path 22 | self.rule_dict = {} 23 | self.count = 0 24 | # 获取规则 25 | self.rule_dict = self.jsonfile_load(self.rule) 26 | 27 | # 目录遍历 28 | def dir_list(self, file_path='.'): 29 | path = os.listdir(file_path) 30 | files = [] 31 | for i in path: 32 | temp = file_path + '/' + i 33 | if os.path.isdir(temp): 34 | # 如果为文件 则递归读取 35 | files.extend(self.dir_list(temp)) 36 | # 判断文件后缀是否为.php 37 | elif i[-4:] == '.php': 38 | files.append(temp) 39 | return files 40 | 41 | # 规则匹配初始化 42 | def audit_init(self): 43 | # 初始化php项目 44 | os.chdir(self.php_path) # 切换工作目录至PHP代码目录 45 | # 逐个php文件处理 46 | for i in self.files: 47 | # 为每个文件创建文件对象 48 | file_ood = File.File(i) 49 | file_content = self.php_file_read(i) 50 | for index, v in enumerate(file_content): 51 | self.audit_print(v, file_ood, index) 52 | print("共发现" + str(self.count) + "个可疑漏洞点") 53 | 54 | # 规则匹配 并打印 取出函数和形参 用作命令行 55 | def audit_print(self, content, file_ood, line): 56 | # 匹配取出所有的方法 57 | for k,v in self.rule_dict.items(): 58 | regular = k 59 | result = re.findall(regular,content) 60 | # print(regular) 61 | if len(result) > 0: 62 | for i in result: 63 | print("--------------------------------") 64 | print("[*] "+ v) 65 | print("[*] file:"+file_ood.get_file_name()) 66 | print("[*] line:"+str(line+1)) 67 | print("[*] code:"+content.strip()[:40]) 68 | self.count+=1 69 | 70 | # 规则匹配 存储危险函数列表 用于后期UI版 71 | def audit_gui(self,content,file_ood,line): 72 | pass 73 | 74 | # txt读入列表 75 | def txt_to_list(self, file_name): 76 | # 获取程序当前路径 77 | path = os.path.dirname(os.path.realpath(__file__)) 78 | # 切换至当前路径 79 | os.chdir(path + '\\..\\') 80 | str_list = [] 81 | # 逐行读取危险函数文件 82 | with open(file_name, 'r') as f: 83 | for line in f: 84 | str_list.append(line.split()[0]) 85 | return str_list 86 | 87 | # json读取 88 | def jsonfile_load(self, file_name): 89 | # 获取程序当前路径 90 | path = os.path.dirname(os.path.realpath(__file__)) 91 | # 切换至当前路径 92 | os.chdir(path + '\\..\\') 93 | with open(file_name, 'r') as f: 94 | rule_dict = json.load(f) 95 | return rule_dict 96 | 97 | # php文件读取 98 | def php_file_read(self, file): 99 | with open(file, 'rb') as f: 100 | fstr = self.unified_code(f.read()) 101 | flist = fstr.split('\n') 102 | # 返回读取的文件列表 103 | return flist 104 | 105 | # 编码统一转换为utf-8 106 | def unified_code(self, string): 107 | try: 108 | # 获取编码 109 | string_code = chardet.detect(string)['encoding'] 110 | # 编码统一 111 | finall_string = string.decode(string_code).encode('utf-8').decode('utf-8') 112 | return finall_string 113 | 114 | except Exception as e: 115 | print("编码转换失败") 116 | return '' 117 | -------------------------------------------------------------------------------- /func.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ETOCheney/phpAudit/03e83caa543f6089717a7100c2b0bf96d10b2d85/func.json -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | from controller import CodeAudit 3 | import getopt 4 | import sys 5 | from PyQt5.QtWidgets import QApplication, QMainWindow 6 | 7 | if __name__ == "__main__": 8 | # 获取输入参数 9 | argv = sys.argv[1:] 10 | hello = ''' 11 | __ ___ __ _ __ 12 | ____ / /_ ____ / | __ __ ____/ / (_) / /_ 13 | / __ \/ __ \/ __ \ / /| | / / / / / __ / / / / __/ 14 | / /_/ / / / / /_/ / / ___ | / /_/ / / /_/ / / / / /_ 15 | / .___/_/ /_/ .___/ /_/ |_| \__,_/ \__,_/ /_/ \__/ 16 | /_/ /_/ 17 | 18 | version:0.1.2(开发中……) 19 | ''' 20 | # 解析参数 21 | try: 22 | opts, args = getopt.getopt(argv, "HP:G", ["help", "path="]) 23 | except getopt.GetoptError: 24 | print("Try -H for more information!") 25 | sys.exit(2) 26 | if len(opts) <=0: 27 | print("Try -H for more information!") 28 | sys.exit(2) 29 | for opt, arg in opts: 30 | if opt in ("-H", "--help"): 31 | print(hello) 32 | print("main.py -P [phpProject] -------- 开始扫描") 33 | print("") 34 | print("-H --help 获取帮助") 35 | print("-P --path 指定扫描目录") 36 | print("-G 启动ui版") 37 | sys.exit(0) 38 | elif opt in ("-P", "--path"): 39 | print(arg) 40 | if '/' in arg or '\\' in arg: 41 | path = arg 42 | else: 43 | print("文件路径不要使用\\,使用/或者使用\\\\") 44 | exit(0) 45 | elif opt in ("-G"): 46 | win = windows.Ui_MainWindow() 47 | 48 | if 'path' in dir(): 49 | f = CodeAudit.FileList(path, "func.json") 50 | f.audit_init() 51 | elif 'win' in dir(): 52 | app = QApplication(sys.argv) 53 | MainWindow = QMainWindow() 54 | win.setupUi(MainWindow) 55 | MainWindow.show() 56 | sys.exit(app.exec_()) 57 | --------------------------------------------------------------------------------