Skip to content

Commit

Permalink
添加EvilPot测试靶场:一个专门用于让扫描器产生误报的靶场,编写插件应该尽量避免能在这个靶场扫描出结果 (#1805)
Browse files Browse the repository at this point in the history
  • Loading branch information
chinaykc authored Jul 3, 2024
1 parent daeac75 commit cb8b04a
Show file tree
Hide file tree
Showing 8 changed files with 351 additions and 1 deletion.
11 changes: 10 additions & 1 deletion tests/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
# 测试靶场

## Evil Pot

这里依靠社区力量收集了几个常用的靶站,可以通过 docker/docker-compose 一键启用。活动开始后,我们注意到在这个repo 中 https://github.com/c0ny1/vulstudy ,作者已经收集了 12 个靶站,这些靶站基本符合我们的要求,所以后续提交中与该 repo 中靶站有所重复的将不再收录。
`evilpot`目录下是我们实现的一个用于提高插件质量的测试靶场。

`evilpot`集成了一些常见的容易导致扫描器误报的情况,编写插件的过程应该尽量避免能在这个靶场扫描出结果。

## 常用靶场

这里依靠社区力量收集了几个常用的靶站,可以通过 docker/docker-compose 一键启用。活动开始后,我们注意到在这个repo
https://github.com/c0ny1/vulstudy ,作者已经收集了 12 个靶站,这些靶站基本符合我们的要求,所以后续提交中与该 repo
中靶站有所重复的将不再收录。

已有的靶站列表:

Expand Down
24 changes: 24 additions & 0 deletions tests/evilpot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Evil Pot
===

邪恶的罐子

一个专门用于让扫描器产生误报的靶场

编写插件应该尽量避免能在这个靶场扫描出结果

## 默认监听端口

- 8887: evil server 让扫描器产生误报 困难模式
- 普通模式的基础上对所有请求元素进行拆解计算sha1/md5/base64
- 8888: evil server 让扫描器产生误报 普通模式
- 常见状态码
- 常见报错信息
- 常见页面
- 常见登录框
- 常见xml头
- 1-1000的sha1/md5/base64
- 回显完整请求
- 尝试计算请求中的算式
- 尝试进行`sleep``wait for`的执行
- 8889: echo server 回显所有读到的数据
24 changes: 24 additions & 0 deletions tests/evilpot/evil/echo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package evil

import (
"io"
"log"
"net"
)

func ServeEchoServer(addr string) error {
server, err := net.Listen("tcp", addr)
if err != nil {
return err
}
for {
conn, err := server.Accept()
if err != nil {
log.Println(err)
continue
}
go func() {
_, _ = io.Copy(conn, conn)
}()
}
}
223 changes: 223 additions & 0 deletions tests/evilpot/evil/evil.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
package evil

import (
"bytes"
"crypto/md5"
"crypto/sha1"
"encoding/base64"
"encoding/hex"
"log"
"net/http"
"net/http/httputil"
"net/url"
"regexp"
"strconv"
"sync"
"time"

"github.com/dengsgo/math-engine/engine"
)

func ServeEvilServer(addr string, hard bool) error {
return http.ListenAndServe(addr, NewEvilServeMux(hard))
}

func NewEvilServeMux(hard bool) *http.ServeMux {
s := http.NewServeMux()
mathRe := regexp.MustCompile(`\d+\s*[-+*/]\s*\d+`)
sleepRe := regexp.MustCompile(`(?i)sleep\((\d+)\)`)
waitForRe := regexp.MustCompile(`(?i)waitfor\s+delay\s+'0:0:(\d+)'`)
s.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
buf := bufPool.Get().(*bytes.Buffer)
defer func() {
buf.Reset()
bufPool.Put(buf)
}()

buf.Write(CommonEvilResponse)

data, err := httputil.DumpRequest(request, true)
if err != nil {
log.Println(err)
}
buf.Write(data)

if hard {
Split(data, SepFunc, func(bytes []byte) bool {
GenEvilContent(buf, bytes)
return true
})
}

unescape, _ := url.PathUnescape(string(data))
unescape, _ = url.QueryUnescape(unescape)
if hard {
Split([]byte(unescape), SepFunc, func(bytes []byte) bool {
GenEvilContent(buf, bytes)
return true
})
}

// 处理 sleep 和 WAITFOR DELAY
sleepMatches := sleepRe.FindAllStringSubmatch(unescape, -1)
for _, match := range sleepMatches {
if len(match) > 1 {
sleepTime, _ := strconv.Atoi(match[1])
if sleepTime > 50 {
time.Sleep(time.Millisecond * time.Duration(sleepTime))
} else {
time.Sleep(time.Second * time.Duration(sleepTime))
}
}
}

waitForMatches := waitForRe.FindAllStringSubmatch(unescape, -1)
for _, match := range waitForMatches {
if len(match) > 1 {
waitTime, _ := strconv.Atoi(match[1])
if waitTime > 50 {
time.Sleep(time.Millisecond * time.Duration(waitTime))
} else {
time.Sleep(time.Second * time.Duration(waitTime))
}
}
}

for _, expr := range mathRe.FindAllString(unescape, -1) {
r, err := engine.ParseAndExec(expr)
if err != nil {
log.Println(err)
continue
}
GenEvilContent(buf, []byte(strconv.Itoa(int(r))))
}

_, _ = writer.Write(buf.Bytes())
})
return s
}

var bufPool = sync.Pool{New: func() any {
return bytes.NewBuffer(nil)
}}

func GenEvilContent(dst *bytes.Buffer, data []byte) {
dst.Write(data)
hashMD5 := md5.Sum(data)
dst.Write(hashMD5[:])
dst.WriteString(" ")
dst.WriteString(hex.EncodeToString(hashMD5[:]))
dst.WriteString(" ")
dst.WriteString(base64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(hashMD5[:]))))
dst.WriteString(" ")
hashSha1 := sha1.Sum(data)
dst.Write(hashSha1[:])
dst.WriteString(hex.EncodeToString(hashSha1[:]))
dst.WriteString(" ")
dst.WriteString(base64.StdEncoding.EncodeToString([]byte(hex.EncodeToString(hashSha1[:]))))
dst.WriteString(" ")
dst.WriteString(base64.StdEncoding.EncodeToString(data))
dst.WriteString(" ")
}

// CommonEvilResponse
// 常见md5/sha1/base64 (1-1000的数字)
// 常见登录表单
// 常见错误信息
var CommonEvilResponse = []byte(`<html>
<head>
<title>Level1</title>
<title>OA系统</title>
</head>
<center><h1>Level1</h1></center>
<header>
<h1>OA系统</h1>
<nav>
<ul>
<li><a href="#">首页</a></li>
<li><a href="#">通知公告</a></li>
<li><a href="#">个人中心</a></li>
<li><a href="#">退出登录</a></li>
</ul>
</nav>
</header>
<main>
<section class="banner">
<h2>欢迎使用OA系统</h2>
<p>这是一款集办公、管理、协同于一体的企业级应用软件。</p>
</section>
<form action="/login" method="POST">
<div>
<label for="username">用户名:</label>
<input type="text" id="username" name="username" required>
</div>
<div>
<label for="password">密码:</label>
<input type="password" id="password" name="password" required>
</div>
<button type="submit">登录</button>
</form>
<section class="news">
<h2>新闻动态</h2>
<ul>
<li><a href="#">公司年会隆重举行</a></li>
<li><a href="#">财务部门完成年度结算</a></li>
<li><a href="#">研发部门推出新产品</a></li>
</ul>
</section>
<section class="notice">
<h2>通知公告</h2>
<ul>
<li><a href="#">关于2022年春节放假的通知</a></li>
<li><a href="#">办公室搬迁通知</a></li>
</ul>
</section>
</main>
<footer>
<p>&copy; 2023 OA系统 版权所有</p>
</footer>
<h1>Oops! Something went wrong.</h1>
<p>We're sorry, but an error has occurred while processing your request. Please try again later.</p>
<p>Error Code: 400</p>
<p>Error Code: 401</p>
<p>Error Code: 403</p>
<p>Error Code: 404</p>
<p>Error Code: 500</p>
<p>Error Code: 501</p>
<p>Error Code: 502</p>
<p>Error Code: 503</p>
{
"error": {
"code": 404,
"message": "未找到请求的资源",
"details": "请检查您的请求URL是否正确,并确保所请求的资源存在。"
}
}
</body>
</html>
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<!-- a padding to disable MSIE and Chrome friendly error page -->
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.1" encoding="UTF-8"?>`)

func init() {
buf := bytes.NewBuffer(nil)
buf.Write(CommonEvilResponse)
for i := 0; i < 1000; i++ {
GenEvilContent(buf, []byte(strconv.Itoa(i)))
}
buf.WriteString("\nroot:x:0:0:root:/root:/bin/bash\n")
CommonEvilResponse = buf.Bytes()
}
44 changes: 44 additions & 0 deletions tests/evilpot/evil/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package evil

var SepFunc = func(b byte) bool {
if 48 <= b && b <= 57 {
return false
}
if b >= 128 {
return false
}
if b >= 65 && b <= 90 {
return false
}
if b >= 97 && b <= 122 {
return false
}
return true
}

func Split(data []byte, sep func(b byte) bool, handler func([]byte) bool) {
if sep == nil {
sep = SepFunc
}
visible := 0
invisible := 0
for i := 0; i < len(data); i++ {
if !sep(data[i]) {
continue
}
invisible = i
if invisible == visible {
visible++
continue
}
b := data[visible:invisible]
if !handler(b) {
return
}
visible = invisible + 1
}
if visible < len(data) {
handler(data[visible:])
}
return
}
5 changes: 5 additions & 0 deletions tests/evilpot/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/chaitin/xray/tests/evilpot

go 1.21

require github.com/dengsgo/math-engine v0.0.0-20230823154425-78f211b48149
2 changes: 2 additions & 0 deletions tests/evilpot/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/dengsgo/math-engine v0.0.0-20230823154425-78f211b48149 h1:TkVfb0s14IUHDGvjQfq3f0PZnV1zh609did4DrnD4q4=
github.com/dengsgo/math-engine v0.0.0-20230823154425-78f211b48149/go.mod h1:zkR27k4K0I8FS6rkEd8qBhPeS8i3X2FKfvSPdF64OpQ=
19 changes: 19 additions & 0 deletions tests/evilpot/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package main

import (
"flag"
"log"

"github.com/chaitin/xray/tests/evilpot/evil"
)

func main() {
evilHardAddr := flag.String("evil-hard", ":8887", "evil server 困难模式 监听地址")
evilAddr := flag.String("evil", ":8888", "evil server 监听地址")
echoAddr := flag.String("echo", ":8889", "echo server 监听地址")
flag.Parse()
go func() { log.Fatalln(evil.ServeEvilServer(*evilHardAddr, true)) }()
go func() { log.Fatalln(evil.ServeEvilServer(*evilAddr, false)) }()
go func() { log.Fatalln(evil.ServeEchoServer(*echoAddr)) }()
select {}
}

0 comments on commit cb8b04a

Please sign in to comment.