Skip to content

Commit b142086

Browse files
authored
Merge pull request #16 from Hackmanit/dev
Added curl command to output/report + various bug fixes / improvements + updated deps
2 parents 3faa406 + 1797c45 commit b142086

File tree

8 files changed

+101
-32
lines changed

8 files changed

+101
-32
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ wcvs -u https://example.com -hw "file:/home/user/Documents/wordlist-header.txt"
115115
- `--setbody/-sb` specifies the body which shall be added to the request
116116
- `--contenttype/-ct` specifies the value of the Content-Type header
117117
- `--useragentchrome/-uac` changes the User-Agent from `WebCacheVulnerabilityScanner v{Version-Number}` to `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36`. While the same can be achieved with e.g. `-sh "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...`, this flag provides a quicker way.
118+
- `--cacheheader/-ch` specify a custom cache header (case-insensitive)
118119

119120
#### If you want to specify more than 1 cookie, parameter or header you need to specify a file which contains them. Take a look at the [available templates](https://github.com/Hackmanit/Web-Cache-Vulnerability-Scanner/tree/master/templates).
120121

@@ -137,6 +138,8 @@ wcvs -u https://example.com -post -sb "file:/home/user/Documents/body.txt"
137138
wcvs -u https://example.com -post -sb "{}" -ct "application/json"
138139
139140
wcvs -u https://example.com -uac
141+
142+
wcvs -u https://example.com -ch "X-Custom-Cache-Header"
140143
```
141144

142145
## Generate a JSON Report

go.mod

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ module github.com/Hackmanit/Web-Cache-Vulnerability-Scanner
33
go 1.16
44

55
require (
6-
github.com/fatih/color v1.15.0 // indirect
7-
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4
8-
golang.org/x/time v0.0.0-20220411224347-583f2d630306
6+
github.com/fatih/color v1.16.0
7+
golang.org/x/net v0.19.0
8+
golang.org/x/time v0.5.0
9+
moul.io/http2curl v1.0.0 // indirect
910
)

go.sum

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,56 @@
1-
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
2-
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
1+
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
2+
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
33
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
44
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
55
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
6-
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
7-
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
8-
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
9-
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
6+
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
7+
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
8+
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
9+
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
10+
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
11+
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
12+
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
13+
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
14+
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
15+
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
16+
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
17+
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
18+
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
19+
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
20+
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
21+
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
22+
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
23+
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
24+
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
25+
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1026
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
11-
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
27+
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
28+
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1229
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
13-
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
30+
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1431
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
32+
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
33+
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
34+
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
35+
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
36+
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
1537
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
16-
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
38+
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
39+
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
40+
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
41+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
42+
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
1743
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
18-
golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w=
19-
golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
44+
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
45+
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
46+
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
47+
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
48+
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
49+
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
2050
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
51+
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
52+
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
53+
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
54+
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
55+
moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8=
56+
moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE=

pkg/recon.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"errors"
66
"fmt"
77
"io"
8-
"io/ioutil"
98
"net/http"
109
"net/url"
1110
"strings"
@@ -145,8 +144,8 @@ func CheckCache(stat string) (CacheStruct, []error) {
145144
msg := fmt.Sprintf("%s header was found: %s \n", key, val)
146145
PrintVerbose(msg, NoColor, 1)
147146
case "x-cache", "cf-cache-status", "x-drupal-cache", "x-varnish-cache", "akamai-cache-status", "server-timing", "x-iinfo", "x-nc", "x-hs-cf-cache-status", "x-proxy-cache", "x-cache-hits", "x-cache-status", customCacheHeader:
148-
// CacheHeader flag might not be set. Continue in this case
149-
if customCacheHeader == "" {
147+
// CacheHeader flag might not be set (=> ""). Continue in this case
148+
if key == "" {
150149
continue
151150
}
152151
cache.Indicator = key
@@ -1220,7 +1219,7 @@ func GetWebsite(requrl string, setStatusCode bool, cacheBuster bool) (WebsiteStr
12201219

12211220
defer resp.Body.Close()
12221221

1223-
body, err := ioutil.ReadAll(resp.Body)
1222+
body, err := io.ReadAll(resp.Body)
12241223
if err != nil {
12251224
msg := fmt.Sprintf("%s: ioutil.ReadAll: %s", errorString, err.Error())
12261225
Print(msg+"\n", Red)

pkg/report.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ type (
1717
}
1818

1919
reportRequest struct {
20-
URL string `json:"-"`
21-
Reason string `json:"reason"`
22-
Request string `json:"request"`
23-
Response string `json:"response"`
20+
URL string `json:"-"`
21+
Reason string `json:"reason"`
22+
CurlCommand string `json:"curlCommand"`
23+
Request string `json:"request"`
24+
Response string `json:"response"`
2425
}
2526

2627
reportSettings struct {

pkg/requests.go

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import (
44
"bytes"
55
"errors"
66
"fmt"
7-
"io/ioutil"
7+
"io"
88
"net/http"
99
"net/http/httputil"
1010
"strings"
1111
"sync"
12+
13+
"moul.io/http2curl"
1214
)
1315

1416
const (
@@ -130,7 +132,9 @@ func checkPoisoningIndicators(repResult *reportResult, request reportRequest, su
130132
Print(success, Green)
131133
msg := "URL: " + request.URL + "\n"
132134
Print(msg, Green)
133-
msg = "Reason: " + request.Reason + "\n\n"
135+
msg = "Reason: " + request.Reason + "\n"
136+
Print(msg, Green)
137+
msg = "Curl: " + request.CurlCommand + "\n\n"
134138
Print(msg, Green)
135139
repResult.Vulnerable = true
136140
repResult.Requests = append(repResult.Requests, request)
@@ -273,18 +277,38 @@ func firstRequest(rp requestParams) ([]byte, int, reportRequest, http.Header, er
273277
}
274278

275279
waitLimiter(rp.identifier)
276-
resp, err = newClient.Do(req)
280+
var dumpReqBytes []byte
281+
var bodyBackup []byte
282+
if req.Body != nil {
283+
// Backup the request body, because it can only be read once
284+
bodyBackup, err = io.ReadAll(req.Body)
285+
if err != nil {
286+
msg = fmt.Sprintf("%s: io.ReadAll: %s\n", rp.identifier, err.Error())
287+
Print(msg, Red)
288+
return body, -1, repRequest, nil, errors.New(msg)
289+
}
290+
// Restore the request body for the first use
291+
req.Body = io.NopCloser(bytes.NewReader(bodyBackup))
292+
// Dump the request including the body
293+
dumpReqBytes, _ = httputil.DumpRequest(req, true)
294+
} else {
295+
// Dump the request without the body
296+
dumpReqBytes, _ = httputil.DumpRequest(req, false)
297+
}
298+
repRequest.Request = string(dumpReqBytes)
277299

300+
// Do request
301+
resp, err = newClient.Do(req)
278302
if err != nil {
279303
msg = fmt.Sprintf("%s: newClient.Do: %s\n", rp.identifier, err.Error())
280304
Print(msg, Red)
281305
return body, -1, repRequest, nil, errors.New(msg)
282306
} else {
283307
defer resp.Body.Close()
284308

285-
body, err = ioutil.ReadAll(resp.Body)
309+
body, err = io.ReadAll(resp.Body)
286310
if err != nil {
287-
msg = fmt.Sprintf("%s: ioutil.ReadAll: %s\n", rp.identifier, err.Error())
311+
msg = fmt.Sprintf("%s: io.ReadAll: %s\n", rp.identifier, err.Error())
288312
Print(msg, Red)
289313
return body, -1, repRequest, nil, errors.New(msg)
290314
}
@@ -299,8 +323,14 @@ func firstRequest(rp requestParams) ([]byte, int, reportRequest, http.Header, er
299323
return body, -1, repRequest, nil, errors.New(msg)
300324
}
301325

302-
requestBytes, _ := httputil.DumpRequestOut(req, true)
303-
repRequest.Request = string(requestBytes)
326+
// Add the request as curl command to the report
327+
command, err := http2curl.GetCurlCommand(req)
328+
if err != nil {
329+
PrintVerbose("Error: firstRequest: "+err.Error()+"\n", Yellow, 1)
330+
}
331+
commandFixed := strings.Replace(command.String(), "-d ''", "-d '"+string(bodyBackup)+"'", 1)
332+
repRequest.CurlCommand = commandFixed
333+
PrintVerbose("Curl command: "+repRequest.CurlCommand+"\n", NoColor, 2)
304334

305335
responseBytes, _ := httputil.DumpResponse(resp, true)
306336
repRequest.Response = string(responseBytes)

pkg/utils.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package pkg
33
import (
44
"context"
55
"fmt"
6-
"io/ioutil"
76
"log"
87
"math/rand"
98
"net/http"
@@ -65,7 +64,7 @@ func ReadLocalFile(path string, name string) []string {
6564
PrintFatal("Please make sure that path: is lowercase")
6665
}
6766

68-
w, err := ioutil.ReadFile(path)
67+
w, err := os.ReadFile(path)
6968
if err != nil {
7069
additional := ""
7170
if name == "header" {

web-cache-vulnerability-scanner.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
"golang.org/x/net/http2"
1818
)
1919

20-
const version = "1.1.0"
20+
const version = "1.1.1"
2121

2222
var (
2323
currentDate string

0 commit comments

Comments
 (0)