mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-06-22 02:40:49 +00:00
161 lines
3.6 KiB
Go
161 lines
3.6 KiB
Go
package Plugins
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"github.com/shadow1ng/fscan/Common"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// MemcachedScanResult 表示Memcached扫描结果
|
|
type MemcachedScanResult struct {
|
|
Success bool
|
|
Error error
|
|
Stats string
|
|
}
|
|
|
|
// MemcachedScan 检测Memcached未授权访问
|
|
func MemcachedScan(info *Common.HostInfo) error {
|
|
// 设置全局超时上下文
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(Common.GlobalTimeout)*time.Second)
|
|
defer cancel()
|
|
|
|
realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports)
|
|
Common.LogDebug(fmt.Sprintf("开始扫描 Memcached %s", realhost))
|
|
|
|
// 尝试连接并检查未授权访问
|
|
result := tryMemcachedConnection(ctx, info, Common.Timeout)
|
|
|
|
if result.Success {
|
|
// 保存成功结果
|
|
scanResult := &Common.ScanResult{
|
|
Time: time.Now(),
|
|
Type: Common.VULN,
|
|
Target: info.Host,
|
|
Status: "vulnerable",
|
|
Details: map[string]interface{}{
|
|
"port": info.Ports,
|
|
"service": "memcached",
|
|
"type": "unauthorized-access",
|
|
"description": "Memcached unauthorized access",
|
|
"stats": result.Stats,
|
|
},
|
|
}
|
|
Common.SaveResult(scanResult)
|
|
Common.LogSuccess(fmt.Sprintf("Memcached %s 未授权访问", realhost))
|
|
}
|
|
|
|
// 检查是否因为全局超时而退出
|
|
select {
|
|
case <-ctx.Done():
|
|
if ctx.Err() == context.DeadlineExceeded {
|
|
Common.LogDebug("Memcached扫描全局超时")
|
|
return fmt.Errorf("全局超时")
|
|
}
|
|
default:
|
|
}
|
|
|
|
Common.LogDebug(fmt.Sprintf("Memcached扫描完成: %s", realhost))
|
|
return result.Error
|
|
}
|
|
|
|
// tryMemcachedConnection 尝试连接Memcached并检查未授权访问
|
|
func tryMemcachedConnection(ctx context.Context, info *Common.HostInfo, timeoutSeconds int64) *MemcachedScanResult {
|
|
realhost := fmt.Sprintf("%s:%v", info.Host, info.Ports)
|
|
timeout := time.Duration(timeoutSeconds) * time.Second
|
|
|
|
// 创建结果通道
|
|
resultChan := make(chan *MemcachedScanResult, 1)
|
|
|
|
// 创建连接上下文,带超时
|
|
connCtx, connCancel := context.WithTimeout(ctx, timeout)
|
|
defer connCancel()
|
|
|
|
// 在协程中尝试连接
|
|
go func() {
|
|
// 构建结果结构
|
|
result := &MemcachedScanResult{
|
|
Success: false,
|
|
Error: nil,
|
|
Stats: "",
|
|
}
|
|
|
|
// 建立TCP连接
|
|
client, err := Common.WrapperTcpWithTimeout("tcp", realhost, timeout)
|
|
if err != nil {
|
|
result.Error = err
|
|
select {
|
|
case <-connCtx.Done():
|
|
case resultChan <- result:
|
|
}
|
|
return
|
|
}
|
|
defer client.Close()
|
|
|
|
// 设置操作截止时间
|
|
if err := client.SetDeadline(time.Now().Add(timeout)); err != nil {
|
|
result.Error = err
|
|
select {
|
|
case <-connCtx.Done():
|
|
case resultChan <- result:
|
|
}
|
|
return
|
|
}
|
|
|
|
// 发送stats命令
|
|
if _, err := client.Write([]byte("stats\n")); err != nil {
|
|
result.Error = err
|
|
select {
|
|
case <-connCtx.Done():
|
|
case resultChan <- result:
|
|
}
|
|
return
|
|
}
|
|
|
|
// 读取响应
|
|
rev := make([]byte, 1024)
|
|
n, err := client.Read(rev)
|
|
if err != nil {
|
|
result.Error = err
|
|
select {
|
|
case <-connCtx.Done():
|
|
case resultChan <- result:
|
|
}
|
|
return
|
|
}
|
|
|
|
// 检查响应是否包含统计信息
|
|
response := string(rev[:n])
|
|
if strings.Contains(response, "STAT") {
|
|
result.Success = true
|
|
result.Stats = response
|
|
}
|
|
|
|
// 发送结果
|
|
select {
|
|
case <-connCtx.Done():
|
|
case resultChan <- result:
|
|
}
|
|
}()
|
|
|
|
// 等待结果或上下文取消
|
|
select {
|
|
case result := <-resultChan:
|
|
return result
|
|
case <-connCtx.Done():
|
|
if ctx.Err() != nil {
|
|
// 全局上下文取消
|
|
return &MemcachedScanResult{
|
|
Success: false,
|
|
Error: ctx.Err(),
|
|
}
|
|
}
|
|
// 连接超时
|
|
return &MemcachedScanResult{
|
|
Success: false,
|
|
Error: fmt.Errorf("连接超时"),
|
|
}
|
|
}
|
|
}
|