├── __init__.py
├── benchmark
├── include.py
├── directory
│ ├── exclude.py
│ └── inlcude.py
└── go-sec-code
│ ├── favicon.ico
│ ├── go-sec-code.png
│ ├── .gitignore
│ ├── static
│ ├── xml
│ │ └── xxe.xml
│ └── xss
│ │ ├── poc.svg
│ │ └── poc.pdf
│ ├── main.go
│ ├── conf
│ └── app.conf
│ ├── controllers
│ ├── crlfi.go
│ ├── default.go
│ ├── favicon.go
│ ├── ssti.go
│ ├── upload.go
│ ├── zipslip.go
│ ├── xxe.go
│ ├── traversal.go
│ ├── cmdi.go
│ ├── xss.go
│ ├── jsonp.go
│ ├── ssrf.go
│ ├── cors.go
│ └── sqli.go
│ ├── models
│ └── user.go
│ ├── views
│ ├── ssti.tpl
│ ├── xss.tpl
│ ├── xxe.tpl
│ ├── fileUpload.tpl
│ └── index.tpl
│ ├── cmd
│ └── taint
│ │ └── main.go
│ ├── go.mod
│ ├── utils
│ ├── gogs.go
│ └── securityUtils.go
│ ├── README.md
│ ├── routers
│ └── router.go
│ └── go.sum
├── .gitignore
├── utils
├── __init__.py
└── util.py
├── requirements.txt
├── module
├── __init__.py
├── common_scan.py
└── taint_sink_scan.py
├── chatgptscan.py
├── manager
├── __init__.py
├── select.py
└── manager.py
├── loader
├── __init__.py
├── project.py
└── loader.py
├── cli.py
└── README.md
/__init__.py:
--------------------------------------------------------------------------------
1 | pass
--------------------------------------------------------------------------------
/benchmark/include.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/benchmark/directory/exclude.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/benchmark/directory/inlcude.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__
2 | .vscode
3 | test
--------------------------------------------------------------------------------
/utils/__init__.py:
--------------------------------------------------------------------------------
1 | from utils.util import *
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | fire == 0.5.0
2 | openai
3 | typing
--------------------------------------------------------------------------------
/module/__init__.py:
--------------------------------------------------------------------------------
1 | from module.common_scan import *
2 | from module.taint_sink_scan import *
--------------------------------------------------------------------------------
/chatgptscan.py:
--------------------------------------------------------------------------------
1 | import fire
2 | import cli
3 |
4 | if __name__ == "__main__":
5 | fire.Fire(cli.ChatGPTScan)
--------------------------------------------------------------------------------
/benchmark/go-sec-code/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YulinSec/ChatGPTScanner/HEAD/benchmark/go-sec-code/favicon.ico
--------------------------------------------------------------------------------
/benchmark/go-sec-code/go-sec-code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/YulinSec/ChatGPTScanner/HEAD/benchmark/go-sec-code/go-sec-code.png
--------------------------------------------------------------------------------
/manager/__init__.py:
--------------------------------------------------------------------------------
1 | # manager.py: a warpper of openai api
2 | # select.py: define content to analyse
3 | from manager.manager import *
--------------------------------------------------------------------------------
/loader/__init__.py:
--------------------------------------------------------------------------------
1 | # loader.py: load project
2 | # project.py: define project
3 | from loader.loader import *
4 | from loader.project import *
--------------------------------------------------------------------------------
/benchmark/go-sec-code/.gitignore:
--------------------------------------------------------------------------------
1 | tmp/*
2 | go-sec-code
3 | *.tmp
4 | .vscode
5 | __debug_bin
6 | static/upload/*
7 | static/unzip/*
8 | cmd/*/*.json
--------------------------------------------------------------------------------
/benchmark/go-sec-code/static/xml/xxe.xml:
--------------------------------------------------------------------------------
1 |
2 | ]>
3 |
xss content:{{.xss}}
26 |3 |
4 | 5 | > Go-sec-code is a project for learning Go vulnerability code. 6 | 7 | ### 🏠 [Homepage](https://github.com/cokeBeer/go-sec-code) 8 | - [Introduction](#introduction) 9 | - [Install](#install) 10 | - [漏洞说明](#漏洞说明) 11 | - [SSTI](#ssti) 12 | - [XXE](#xxe) 13 | - [SSRF](#ssrf) 14 | - [Path Traversal](#path-traversal) 15 | ## Introduction 16 | 17 | 用beego作为后端框架开发的go语言靶场,目前已经完成 18 | 19 | - CommandInjection 20 | - GET参数注入 21 | - Host头注入 22 | - git参数注入 23 | - 安全代码 24 | - Cors 25 | - 反射型Cors 26 | - any-origin-with-credential 27 | - 安全代码 28 | - CRLFInjection 29 | - 安全代码 30 | - FileUpload 31 | - 利用POST参数任意目录写文件 32 | - 安全代码 33 | - JSONP 34 | - 无防护 35 | - 空Referer绕过 36 | - 安全代码 37 | - PathTraversal 38 | - 无防护 39 | - 错误使用Clean() 40 | - 安全代码(过滤) 41 | - 安全代码(前缀检查) 42 | - SQLInjection 43 | - 数字型注入 44 | - 字符型注入 45 | - 错误的ORM使用 46 | - 错误的SQL生成器使用 47 | - 数字型安全代码 48 | - 字符型安全代码 49 | - ORM安全代码 50 | - SSRF 51 | - 无防护 52 | - 混淆绕过 53 | - 302绕过 54 | - 安全代码(白名单) 55 | - SSTI 56 | - 漏洞代码 57 | - 安全代码 58 | - XSS 59 | - 反射型xss 60 | - 存储型xss 61 | - SVG型xss 62 | - PDF型xss 63 | - 基于过滤的修复 64 | - 基于CSP的修复 65 | - XXE 66 | - 漏洞代码 67 | - 安全代码 68 | - ZipSlip 69 | - 漏洞代码 70 | 71 | 72 | 73 | ## Install 74 | 75 | 运行需要安装beego和bee 76 | 77 | 参考:[beego和bee安装](https://github.com/beego/beedoc/blob/master/zh-CN/quickstart.md) 78 | 79 | 然后执行 80 | 81 | ``` 82 | git clone https://github.com/cokeBeer/go-sec-code 83 | cd go-sec-code 84 | bee run 85 | ``` 86 | 87 | 服务器就运行在http://localhost:233 上了 88 | 89 |  90 | 91 | 为了测试SQLInjection,需要连接数据库。这里使用mysql,先执行下面的语句创建数据库和表 92 | 93 | ```sql 94 | create database goseccode; 95 | create table user( 96 | id int, 97 | username varchar(40), 98 | password varchar(40), 99 | ); 100 | insert into user values(1,"admin","admin@123"); 101 | insert into user values(2,"test","test@123"); 102 | ``` 103 | 104 | 然后找到sqlinjection.go,修改source变量的值 105 | 106 | ```go 107 | source := "username:password@tcp(127.0.0.1:3306)/goseccode" 108 | ``` 109 | 110 | 即可连接数据库 111 | ## 漏洞说明 112 | 113 | ### SSTI 114 | go语言本身提供的模版引擎仅支持简单的渲染功能,不像php、java、python 的模版引擎支持多种功能。这里在设计漏洞代码的时候找到了一个go 语言模版引擎常用的增强库[sprig](https://github.com/Masterminds/sprig),有2.9k个star。这个增强库提供了一些常用的模版函数,其中`env`这个方法可以用来读取环境变量,能造成信息泄露。其他函数经检查,都较为安全。 115 | 116 | ### XXE 117 | 118 | go语言本身提供的xml解析库直接忽略了xml文档中的entity和dtd标签。这里在设计漏洞代码的时候找到了一个go语言实现的libxml2库[libxml2](https://github.com/lestrrat-go/libxml2),有193个star。这个增强库可以设置支持entity。其他go语言实现的xml库大多不支持entity和dtd标签,或者是直接封装了go语言本身提供的xml库。 119 | 120 | ### SSRF 121 | 122 | SSRF提供了三种漏洞情形,一种安全情形。其中第二种漏洞情形用来表示黑名单不完善的情况,第三种漏洞情形来表示黑名单较为完善的情况。黑名单一般要用到字符串比较函数来实现。go语言中进行字符串比较的函数主要是`strings.HasSuffix`。这个函数在比较时不考虑大小写,如果直接使用这个函数进行比较,会导致大小写绕过。更安全的写法是使用`strings.ToLower`先将域名统一转换为小写再进行比较。 123 | 124 | ### Path Traversal 125 | 126 | go语言提供了`filepath.Clean()`方法来规范化路径。但是这个方法不会规范没有以`/`开头的相对路径,例如`../../secret`。简单地使用`filepath.Clean()`方法来规范化路径会导致路径变遍历。比较安全的写法是使用`filepath.Join()`将指定目录(例如`static/`)与传入的参数进行拼接,然后使用`strings.HasPrefix()`方法来检查是否发生了目录穿越 -------------------------------------------------------------------------------- /benchmark/go-sec-code/controllers/cors.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "encoding/json" 5 | "go-sec-code/utils" 6 | 7 | beego "github.com/beego/beego/v2/server/web" 8 | ) 9 | 10 | type CorsVuln1Controller struct { 11 | beego.Controller 12 | } 13 | 14 | type CorsVuln2Controller struct { 15 | beego.Controller 16 | } 17 | 18 | type CorsSafe1Controller struct { 19 | beego.Controller 20 | } 21 | 22 | func (c *CorsVuln1Controller) Get() { 23 | origin := c.Ctx.Request.Header.Get("Origin") 24 | c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Origin", origin) 25 | c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE") 26 | c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, X-Extra-Header, Content-Type, Accept, Authorization") 27 | c.Ctx.ResponseWriter.Header().Set("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type") 28 | c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Credentials", "true") 29 | jsonp := make(map[string]interface{}) 30 | jsonp["username"] = "admin" 31 | jsonp["password"] = "admin@123" 32 | data, err := json.Marshal(jsonp) 33 | if err != nil { 34 | panic(err) 35 | } 36 | c.Ctx.ResponseWriter.Write(data) 37 | } 38 | 39 | func (c *CorsVuln2Controller) Get() { 40 | c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Origin", "*") 41 | c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE") 42 | c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, X-Extra-Header, Content-Type, Accept, Authorization") 43 | c.Ctx.ResponseWriter.Header().Set("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type") 44 | c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Credentials", "true") 45 | jsonp := make(map[string]interface{}) 46 | jsonp["username"] = "admin" 47 | jsonp["password"] = "admin@123" 48 | data, err := json.Marshal(jsonp) 49 | if err != nil { 50 | panic(err) 51 | } 52 | c.Ctx.ResponseWriter.Write(data) 53 | } 54 | 55 | func (c *CorsSafe1Controller) Get() { 56 | origin := c.Ctx.Request.Header.Get("origin") 57 | whitelists := []string{"localhost:233", "example.com"} 58 | corsFilter := utils.CorsFilter{} 59 | if origin != "" && corsFilter.DoFilter(origin, whitelists) { 60 | c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Origin", origin) 61 | c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE") 62 | c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, X-Extra-Header, Content-Type, Accept, Authorization") 63 | c.Ctx.ResponseWriter.Header().Set("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type") 64 | c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Credentials", "true") 65 | } 66 | jsonp := make(map[string]interface{}) 67 | jsonp["username"] = "admin" 68 | jsonp["password"] = "admin@123" 69 | data, err := json.Marshal(jsonp) 70 | if err != nil { 71 | panic(err) 72 | } 73 | c.Ctx.ResponseWriter.Write(data) 74 | } 75 | -------------------------------------------------------------------------------- /benchmark/go-sec-code/routers/router.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "go-sec-code/controllers" 5 | 6 | beego "github.com/beego/beego/v2/server/web" 7 | ) 8 | 9 | func init() { 10 | beego.Router("/", &controllers.MainController{}) 11 | beego.Router("/favicon.ico", &controllers.FaviconController{}) 12 | beego.Router("/commandInject/vuln", &controllers.CommandInjectVuln1Controller{}) 13 | beego.Router("/commandInject/vuln/host", &controllers.CommandInjectVuln2Controller{}) 14 | beego.Router("/commandInject/vuln/git", &controllers.CommandInjectVuln3Controller{}) 15 | beego.Router("/commandInject/safe", &controllers.CommandInjectSafe1Controller{}) 16 | beego.Router("/cors/vuln/reflect", &controllers.CorsVuln1Controller{}) 17 | beego.Router("/cors/vuln/any-origin-with-credential", &controllers.CorsVuln2Controller{}) 18 | beego.Router("/cors/safe", &controllers.CorsSafe1Controller{}) 19 | beego.Router("/crlfInjection/safe", &controllers.CRLFSafe1Controller{}) 20 | beego.Router("/fileUpload/vuln", &controllers.FileUploadVuln1Controller{}) 21 | beego.Router("/fileUpload/safe", &controllers.FileUploadSafe1Controller{}) 22 | beego.Router("/jsonp/vuln/noCheck", &controllers.JsonpVuln1Controller{}) 23 | beego.Router("/jsonp/vuln/emptyReferer", &controllers.JsonpVuln1Controller{}) 24 | beego.Router("/jsonp/safe", &controllers.JsonpSafe1Controller{}) 25 | beego.Router("/pathTraversal/vuln", &controllers.PathTraversalVuln1Controller{}) 26 | beego.Router("/pathTraversal/vuln/clean", &controllers.PathTraversalVuln2Controller{}) 27 | beego.Router("/pathTraversal/safe/filter", &controllers.PathTraversalSafe1Controller{}) 28 | beego.Router("/pathTraversal/safe/check", &controllers.PathTraversalSafe2Controller{}) 29 | beego.Router("/sqlInjection/native/vuln/integer", &controllers.SqlInjectionVuln1Controller{}) 30 | beego.Router("/sqlInjection/native/vuln/string", &controllers.SqlInjectionVuln2Controller{}) 31 | beego.Router("/sqlInjection/orm/vuln/xorm", &controllers.SqlInjectionVuln3Controller{}) 32 | beego.Router("/sqlInjection/generator/vuln/squirrel", &controllers.SqlInjectionVuln4Controller{}) 33 | beego.Router("/sqlInjection/native/safe/integer", &controllers.SqlInjectionSafe1Controller{}) 34 | beego.Router("/sqlInjection/native/safe/string", &controllers.SqlInjectionSafe2Controller{}) 35 | beego.Router("/sqlInjection/orm/safe/beego", &controllers.SqlInjectionSafe3Controller{}) 36 | beego.Router("/ssrf/vuln", &controllers.SSRFVuln1Controller{}) 37 | beego.Router("/ssrf/vuln/obfuscation", &controllers.SSRFVuln2Controller{}) 38 | beego.Router("/ssrf/vuln/302", &controllers.SSRFVuln3Controller{}) 39 | beego.Router("/ssrf/safe/whitelists", &controllers.SSRFSafe1Controller{}) 40 | beego.Router("/ssti/vuln", &controllers.SSTIVuln1Controller{}) 41 | beego.Router("/ssti/safe", &controllers.SSTISafe1Controller{}) 42 | beego.Router("/xss/vuln", &controllers.XSSVuln1Controller{}) 43 | beego.Router("/xss/vuln/store", &controllers.XSSVuln2Controller{}) 44 | beego.Router("/xss/vuln/svg", &controllers.XSSVuln3Controller{}) 45 | beego.Router("/xss/vuln/pdf", &controllers.XSSVuln4Controller{}) 46 | beego.Router("/xss/safe", &controllers.XSSSafe1Controller{}) 47 | beego.Router("/xss/safe/svg", &controllers.XSSSafe2Controller{}) 48 | beego.Router("/xxe/vuln", &controllers.XXEVuln1Controller{}) 49 | beego.Router("/xxe/safe", &controllers.XXESafe1Controller{}) 50 | beego.Router("/zipslip/vuln", &controllers.ZipSlipVuln1Controller{}) 51 | } 52 | -------------------------------------------------------------------------------- /manager/manager.py: -------------------------------------------------------------------------------- 1 | import openai 2 | from loader.project import * 3 | from loader.loader import * 4 | from manager.select import * 5 | 6 | # Act as a web security expert and ready to receive project 7 | SYSTEM_PROMPT_1 = "You are a web security expert and I will send you a project" 8 | # General security assessment 9 | NEED_PROMPT_1 = "Please analyse code above and tell me vulnerabilities in it. Mark every vulnerability with info, warn, medium, high or critical by severity" 10 | # A need prefix to make gpt work better 11 | NEED_PREFIX = "Please analyse code above. " 12 | # Find all taint chains from a given source 13 | NEED_PROMPT_2 = "Can {} become input or parameter of dangerous function calls? Give me the function call chain in format of {}" 14 | # Find all taint chains to a given sink 15 | NEED_PROMPT_3 = "Can remote input in request become input or parameter of {} in a function call chain? Give me the function call chain in format of {}" 16 | # One function call perline format 17 | DEFUALT_TAINT_FORMAT = "one function call per line" 18 | # Editor format 19 | EDITOR_TAINT_FORMAT = "number\n function name\n file name\n line number\n code snippet less than 3 lines\n" 20 | # Semgrep report format 21 | SEMGREP_FORMAT = "semgrep report" 22 | # CodeQL report format 23 | CodeQL_FORMAT = "CodeQL report" 24 | 25 | # General security assessment 26 | 27 | 28 | def need_prompt_1() -> str: 29 | return NEED_PROMPT_1 30 | 31 | # Find all taint chains from a given source 32 | 33 | 34 | def need_prompt_2(source: str, format=DEFUALT_TAINT_FORMAT) -> str: 35 | return NEED_PREFIX + NEED_PROMPT_2.format(source, format) 36 | 37 | # Find all taint chains to a given sink 38 | 39 | 40 | def need_prompt_3(sink: str, format=DEFUALT_TAINT_FORMAT) -> str: 41 | return NEED_PREFIX + NEED_PROMPT_3.format(sink, format) 42 | 43 | 44 | def match_include(path: str, include: typing.List[str]): 45 | if len(include) == 0: 46 | return True 47 | for v in include: 48 | if path.startswith(v): 49 | return True 50 | return False 51 | 52 | 53 | def _ask(messages): 54 | return openai.ChatCompletion.create( 55 | model="gpt-3.5-turbo", 56 | messages=messages 57 | ) 58 | 59 | 60 | def build_message(messages, pro: Project, select: Select, dry=False): 61 | for path in pro.content: 62 | if match_include(path, select.include) and path not in select.exclude: 63 | if dry: 64 | print(path) 65 | for k, v in enumerate(pro.content[path]): 66 | messages.append( 67 | {"role": "user", "content": "relative path: {}, part number: {}\n{}".format(path, k, v)}) 68 | 69 | # add verify=Fasle in openai/api_requestor.py#request_raw L524 to bypass ssl verification 70 | 71 | 72 | class Manager(): 73 | def set_key(self, api_key: str): 74 | openai.api_key = api_key 75 | 76 | def set_proxy(self, proxy: str): 77 | openai.proxy = proxy 78 | 79 | # ask by src, use with load_one 80 | def ask_src(self, src: typing.List[str]): 81 | messages = [ 82 | {"role": "system", "content": SYSTEM_PROMPT_1}] 83 | for chunk in src: 84 | messages.append({"role": "user", "content": chunk}) 85 | messages.append( 86 | {"role": "user", "content": NEED_PROMPT_1}) 87 | 88 | return _ask(messages) 89 | 90 | # ask by project and select 91 | def ask(self, pro: Project, select: Select, dry=False): 92 | messages = [ 93 | {"role": "system", "content": SYSTEM_PROMPT_1}] 94 | build_message(messages, pro, select, dry) 95 | messages.append( 96 | {"role": "user", "content": NEED_PROMPT_1}) 97 | if dry: 98 | return 99 | return _ask(messages) 100 | 101 | # ask by project, question and select 102 | def ask_question(self, pro: Project, select: Select, question: str, dry=False): 103 | messages = [ 104 | {"role": "system", "content": SYSTEM_PROMPT_1}] 105 | build_message(messages, pro, select, dry) 106 | messages.append( 107 | {"role": "user", "content": question} 108 | ) 109 | if dry: 110 | return 111 | return _ask(messages) 112 | 113 | # load project by select pack and ask by question 114 | def execute_task(self, task: Task, dry=False): 115 | pro = load_project(task.root, task.language) 116 | return self.ask(pro, task.select, dry) 117 | 118 | # load project by select pack and ask by question 119 | def execute_task_question(self, task: Task, question: str, dry=False): 120 | pro = load_project(task.root, task.language) 121 | return self.ask_question(pro, task.select, question, dry) 122 | -------------------------------------------------------------------------------- /benchmark/go-sec-code/views/index.tpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |Go-sec-code is a project for learning Go vulnerability code.
15 |