├── requirements.txt ├── img ├── img.png └── img_1.png ├── config.py ├── logo.py ├── main.py ├── Readme.md └── Scripts └── Scan.py /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp==3.9.3 2 | asyncio==3.4.3 3 | -------------------------------------------------------------------------------- /img/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Re1axCyber/PyKunwu_Cli/HEAD/img/img.png -------------------------------------------------------------------------------- /img/img_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Re1axCyber/PyKunwu_Cli/HEAD/img/img_1.png -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | url="https://ti.moresec.cn" 2 | apikey="13d28c00f252ddde4371c56a4e2f47ab8ab718b5f81e2f63d82f8d974cc78b07" -------------------------------------------------------------------------------- /logo.py: -------------------------------------------------------------------------------- 1 | kw_logo = """ 2 | __ __ _ __ _______ ____ 3 | / //_/_ _____| | /| / /_ ______/ ___/ / / _/ 4 | / ,< / // / _ \ |/ |/ / // /___/ /__/ /___/ / 5 | /_/|_|\_,_/_//_/__/|__/\_,_/ \___/____/___/ 6 | [+] Name:Py_Kunwu_Cli 7 | [+] Author:Re1axCyber 8 | [+] Github:github.com/Re1axCyber/PyKunwu_Cli 9 | """ 10 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | from logo import * 3 | from Scripts import Scan 4 | import asyncio 5 | 6 | 7 | async def main(): 8 | parser = argparse.ArgumentParser(description="一个简单的命令行参数解析示例") 9 | parser.add_argument("--CloudScan", help="是否启用云端扫描", default="True", type=bool) 10 | parser.add_argument("--path", '-p', help="扫描文件的路径",type=str) 11 | args = parser.parse_args() 12 | await Scan.get_type(args.path) 13 | 14 | 15 | if __name__ == '__main__': 16 | 17 | print(kw_logo) 18 | print("--------------------------start----------------------------\n") 19 | #asyncio.run(main()) 20 | loop = asyncio.get_event_loop() 21 | loop.run_until_complete(main()) 22 | print("--------------------------end----------------------------\n") 23 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 |

KunWu

5 |

6 | Static Badge 7 | Static Badge 8 | 9 |

KunWu_Cli」Python重构版本

10 |

模糊规则/污点分析模拟执行/机器学习 三种高效检测策略,精准无误地发现 WebShell 风险

11 | 12 | # ✈️ 1# 工具概述 13 | 14 | 本项目为默安科技打造的新一代 WebShell 检测工具「KunWu_Cli」的Python重构版本 15 | 16 | 原项目地址:[https://github.com/kunwu2023/kunwu/](https://github.com/kunwu2023/kunwu/) 17 | 18 | 本项目结构主体结构如下: 19 | 20 | | 名称 | 说明 | 21 | |-----------|------------| 22 | | main.py | 程序入口点 | 23 | | Scan.py | 扫描模块核心代码 | 24 | | config.py | 工具模块代码 | 25 | | logo.py | Kunwu logo | 26 | | config.py | 程序配置文件 | 27 | 28 | # 📝 2# TODO 29 | 30 | * [x] 在基于原项目的基础上加入了异步检测的代码 31 | * [x] 对代码进行了部分优化 32 | 33 | # 🚨 3# 快速开始 34 | 35 | ### 3.1 安装依赖包 36 | 37 | ``` 38 | pip install -r requirements.txt 39 | ``` 40 | 41 | 如果pip安装速度慢,可以采用国内源进行安装: 42 | 43 | ``` 44 | pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/ 45 | ``` 46 | 47 | ### 3.2 运行 48 | 49 | ``` 50 | python3 main.py --path /path/to/file 51 | ``` 52 | 53 | ### 3.3 运行结果示例 54 | 55 | ![img/img.png](img/img.png) 56 | ![img/img_1.png](img/img_1.png) 57 | 58 | 59 | # 🙏 4# 感谢各位师傅 60 | 61 | ## Stargazers 62 | 63 | [![Stargazers repo roster for @Re1axCyber/PyKunwu_Cli](http://reporoster.com/stars/Re1axCyber/PyKunwu_Cli)](https://github.com/Re1axCyber/PyKunwu_Cli/stargazers) 64 | 65 | 66 | ## Forkers 67 | 68 | [![Forkers repo roster for @Re1axCyber/PyKunwu_Cli](http://reporoster.com/forks/Re1axCyber/PyKunwu_Cli)](https://github.com/Re1axCyber/PyKunwu_Cli/network/members) 69 | 70 | 71 | ## Star History 72 | 73 | [![Star History Chart](https://api.star-history.com/svg?repos=Re1axCyber/PyKunwu_Cli&type=Date)](https://star-history.com/#Re1axCyber/PyKunwu_Cli&Date) 74 | -------------------------------------------------------------------------------- /Scripts/Scan.py: -------------------------------------------------------------------------------- 1 | import aiohttp 2 | from config import * 3 | import os,base64,hashlib,json 4 | from time import sleep 5 | 6 | 7 | def calc_md5(content): 8 | try: 9 | h = hashlib.md5() 10 | h.update(content.encode()) 11 | return h.hexdigest() 12 | except Exception as e: 13 | print(f"[-] 出现错误:{e}") 14 | pass 15 | 16 | 17 | async def upload_file(file_md5, file_text): 18 | try: 19 | conn = aiohttp.TCPConnector(ssl=False) 20 | async with aiohttp.ClientSession(connector=conn) as session: 21 | headers = {"Content-Type": "application/json"} 22 | data = {"webshell_text": str(base64.b64encode(bytes(file_text, encoding='utf-8')).decode())} 23 | # print(data) 24 | # print(url+"/api/v1/anonymous_see_file?apikey="+apikey+"&md5="+file_md5) 25 | 26 | async with session.get(url + "/api/v1/anonymous_see_file?apikey=" + apikey + "&md5=" + file_md5, json=data, 27 | headers=headers) as check_resp: 28 | print("[.] 正在进行历史结果探测") 29 | resp = await check_resp.text() 30 | result = json.loads(resp)["result"] 31 | if result != "": 32 | print(f"[+] 云端结果已存在,云端扫描结果为:{result}") 33 | else: 34 | print("[.] 云端结果不存在,开始上传") 35 | async with session.post(url + "/api/v1/anonymous_up_file?apikey=" + apikey + "&md5=" + file_md5, 36 | json=data, headers=headers) as resp: 37 | print(resp.status) 38 | print(await resp.json()) 39 | print("[+] 文件上传成功") 40 | print() 41 | for i in range(0, 10): 42 | print("[.] 正在等待云端扫描返回结果") 43 | async with session.get(url + "/api/v1/anonymous_see_file?apikey=" + apikey + "&md5=" + file_md5, 44 | json=data, headers=headers) as upload_resp: 45 | response = await upload_resp.text() 46 | print(json.loads(response)) 47 | result = json.loads(response)["result"] 48 | print(f"[+] 云端扫描结果为:{result}") 49 | if result != "": 50 | break 51 | elif i == 12 and result == "" : 52 | print("[-] 云端响应结果超时") 53 | sleep(3) 54 | except Exception as e: 55 | print(f"[-] 扫描出现错误:{e}") 56 | pass 57 | 58 | async def list_files(dir_path): 59 | for root, dirs, files in os.walk(dir_path): 60 | for f in files: 61 | print(os.path.join(root, f)) 62 | await upload_file(calc_md5(file_text(os.path.join(root, f))), file_text(os.path.join(root, f))) 63 | 64 | 65 | async def get_type(filepath): 66 | if os.path.exists(filepath): 67 | if os.path.isdir(filepath): 68 | print("{} 是一个文件夹".format(filepath)) 69 | await list_files(filepath) 70 | else: 71 | print("{} 是一个文件".format(filepath)) 72 | await upload_file(calc_md5(file_text(filepath)), file_text(filepath)) 73 | # file_text(path) 74 | else: 75 | print("{} 不存在或者不是一个文件或文件夹".format(filepath)) 76 | 77 | 78 | def file_text(path): 79 | try: 80 | text = open(path, 'r', encoding='utf-8').read() 81 | return text 82 | except Exception as e: 83 | print(f"[-] 文件读取出现错误:{e}") 84 | pass 85 | 86 | 87 | # get_type(path) 88 | # print(os.stat(path).st_size) 89 | # print(os.path.basename(path)) 90 | --------------------------------------------------------------------------------