fix some mistakes:(

This commit is contained in:
amammad
2023-09-14 23:39:28 +10:00
parent b5a257ca7c
commit 0d3b944207
3 changed files with 6629 additions and 3575 deletions

View File

@@ -1,12 +1,17 @@
/** Provides models of commonly used functions and types in the fasthttp packages. */
/**
* Provides classes for working with the [fasthttp](github.com/valyala/fasthttp) package.
*/
import go
private import semmle.go.security.RequestForgeryCustomizations
private import semmle.go.security.SafeUrlFlowCustomizations
import semmle.go.security.Xss
/** Provides models of commonly used functions and types in the fasthttp packages. */
/**
* Provides classes for working with the [fasthttp](github.com/valyala/fasthttp) package.
*/
module Fasthttp {
/**
* use following class when you are using Fasthttp in a query to fully suppoers additional steps
*/
bindingset[this]
abstract class AdditionalStep extends string {
/**
@@ -15,9 +20,13 @@ module Fasthttp {
abstract predicate hasTaintStep(DataFlow::Node pred, DataFlow::Node succ);
}
string fasthttpPackage() { result = "github.com/valyala/fasthttp" }
/**
* Provide models for sanitizer/Dangerous Functions of fasthttp
*/
module Functions {
/**
* following Functions don't sanitize user provided file paths
*/
class FileSystemAccess extends FileSystemAccess::Range, DataFlow::CallNode {
FileSystemAccess() {
exists(DataFlow::Function f |
@@ -30,28 +39,12 @@ module Fasthttp {
)
}
override DataFlow::Node getAPathArgument() {
this.getTarget().getName() =
[
"ServeFile", "ServeFileUncompressed", "ServeFileBytes", "ServeFileBytesUncompressed",
"SaveMultipartFile"
] and
result = this.getArgument(1)
}
}
private class Redirect extends Http::Redirect::Range, DataFlow::CallNode {
Redirect() {
exists(DataFlow::Function f |
f.hasQualifiedName("github.com/valyala/fasthttp", "DoRedirects") and this = f.getACall()
)
}
override DataFlow::Node getUrl() { result = this.getArgument(0) }
override Http::ResponseWriter getResponseWriter() { result.getANode() = this.getArgument(1) }
override DataFlow::Node getAPathArgument() { result = this.getArgument(1) }
}
/**
* Provide some functions of fasthttp which can be used as sanitizer for XSS
*/
private class HtmlQuoteSanitizer extends SharedXss::Sanitizer {
HtmlQuoteSanitizer() {
exists(DataFlow::CallNode c |
@@ -64,14 +57,34 @@ module Fasthttp {
}
}
/**
* Get* send a HTTP GET request
* Post send a HTTP POST request
* these Functions first arguments is a URL
*/
class SSRFSink extends RequestForgery::Sink {
SSRFSink() {
exists(DataFlow::Function f |
f.hasQualifiedName("github.com/valyala/fasthttp",
[
"DialDualStack", "Dial", "DialTimeout", "DialDualStackTimeout", "Get", "GetDeadline",
"GetTimeout", "Post", "Do", "DoDeadline", "DoTimeout"
]) and
["Get", "GetDeadline", "GetTimeout", "Post"]) and
this = f.getACall().getArgument(1)
)
}
override DataFlow::Node getARequest() { result = this }
override string getKind() { result = "URL" }
}
/**
* First argument of following functions need Additional steps
* look at URI module, additional steps part for more information
*/
class SSRFSinkDo extends RequestForgery::Sink {
SSRFSinkDo() {
exists(DataFlow::Function f |
f.hasQualifiedName("github.com/valyala/fasthttp",
["Do", "DoDeadline", "DoTimeout", "DoRedirects"]) and
this = f.getACall().getArgument(0)
)
}
@@ -80,42 +93,64 @@ module Fasthttp {
override string getKind() { result = "URL" }
}
}
module RequestHeader {
class UntrustedFlowSource extends UntrustedFlowSource::Range instanceof DataFlow::Node {
UntrustedFlowSource() {
exists(DataFlow::Method m |
m.hasQualifiedName("github.com/valyala/fasthttp.RequestHeader",
[
"Header", "TrailerHeader", "RequestURI", "Host", "UserAgent", "ContentEncoding",
"ContentType", "Cookie", "CookieBytes", "MultipartFormBoundary", "Peek", "PeekAll",
"PeekBytes", "PeekKeys", "PeekTrailerKeys", "Referer", "RawHeaders"
]) and
this = m.getACall()
or
m.hasQualifiedName("github.com/valyala/fasthttp.RequestHeader", ["Write"]) and
this = m.getACall().getArgument(0)
/**
* Following Functions only accept TCP address + Port in their first argument
*/
class SSRFSinkDial extends RequestForgery::Sink {
SSRFSinkDial() {
exists(DataFlow::Function f |
f.hasQualifiedName("github.com/valyala/fasthttp",
["DialDualStack", "Dial", "DialTimeout", "DialDualStackTimeout"]) and
this = f.getACall().getArgument(0)
)
}
override DataFlow::Node getARequest() { result = this }
override string getKind() { result = "TCP Addr + Port" }
}
}
/**
* Provide modeling for fasthttp.URI Type
*/
module URI {
/**
* Fasthttp has its own uri creating/manipulation methods and these methods usaully are used in code
* Pred can be an user controlled value like any potential part of URL and succ is the URI instance
* So if we called a method like `URIInstance.SetHost(pred)` then the URIInstance is succ
*/
class URIAdditionalStep extends AdditionalStep {
URIAdditionalStep() { this = "URI additioanl steps" }
override predicate hasTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(DataFlow::MethodCallNode m, DataFlow::Variable frn |
m.getTarget()
.hasQualifiedName("github.com/valyala/fasthttp.URI", ["SetHost", "SetHostBytes"]) and
pred = m.getArgument(0) and
(
m.getTarget()
.hasQualifiedName("github.com/valyala/fasthttp.URI",
["SetHost", "SetHostBytes", "Update", "UpdateBytes"]) and
pred = m.getArgument(0)
or
m.getTarget().hasQualifiedName("github.com/valyala/fasthttp.URI", "Parse") and
pred = m.getArgument([0, 1])
) and
frn.getARead() = m.getReceiver() and
succ = frn.getARead()
)
or
// CopyTo method copy receiver to first argument
exists(DataFlow::MethodCallNode m |
m.getTarget().hasQualifiedName("github.com/valyala/fasthttp.URI", "CopyTo") and
pred = m.getReceiver() and
succ = m.getArgument(1)
)
}
}
/**
* Provide Remote user controllable sources which are part of the incoming URL
*/
class UntrustedFlowSource extends UntrustedFlowSource::Range instanceof DataFlow::Node {
UntrustedFlowSource() {
exists(DataFlow::Method m |
@@ -130,7 +165,13 @@ module Fasthttp {
}
}
/**
* Provide modeling for fasthttp.Args Type
*/
module Args {
/**
* Provide Remote user controllable sources which are part of the incoming URL Parameters
*/
class UntrustedFlowSource extends UntrustedFlowSource::Range instanceof DataFlow::Node {
UntrustedFlowSource() {
exists(DataFlow::Method m |
@@ -145,9 +186,16 @@ module Fasthttp {
}
}
/**
* Provide modeling for fasthttp.TCPDialer Type
*/
module TCPDialer {
class SSRFSink extends RequestForgery::Sink {
SSRFSink() {
/**
* Provide Methods which can be used as dangerous SSRF Sinks
* Following Methods only accept TCP address + Port in their first argument
*/
class SSRFSinkDial extends RequestForgery::Sink {
SSRFSinkDial() {
exists(DataFlow::Method m |
m.hasQualifiedName("github.com/valyala/fasthttp.TCPDialer",
["Dial", "DialTimeout", "DialDualStack", "DialDualStackTimeout"]) and
@@ -157,16 +205,24 @@ module Fasthttp {
override DataFlow::Node getARequest() { result = this }
override string getKind() { result = "Host" }
override string getKind() { result = "TCP Addr + Port" }
}
}
/**
* Provide modeling for fasthttp.Client Type
*/
module Client {
/**
* Get* send a HTTP GET request
* Post send a HTTP POST request
* these Functions first arguments is a URL
*/
class SSRFSink extends RequestForgery::Sink {
SSRFSink() {
exists(DataFlow::Method m |
m.hasQualifiedName("github.com/valyala/fasthttp.Client",
["Get", "GetDeadline", "GetTimeout", "Post", "Do", "DoDeadline", "DoTimeout"]) and
["Get", "GetDeadline", "GetTimeout", "Post"]) and
this = m.getACall().getArgument(0)
)
}
@@ -175,9 +231,163 @@ module Fasthttp {
override string getKind() { result = "URL" }
}
/**
* First argument of following methods need Additional steps
* Look at Request module, additional steps part for more information
*/
class SSRFSinkDo extends RequestForgery::Sink {
SSRFSinkDo() {
exists(DataFlow::Method m |
m.hasQualifiedName("github.com/valyala/fasthttp.Client",
["Do", "DoDeadline", "DoTimeout", "DoRedirects"]) and
this = m.getACall().getArgument(0)
)
}
override DataFlow::Node getARequest() { result = this }
// Kind can be vary because input is a fasthttp.URI type
override string getKind() { result = "URL" }
}
}
/**
* Provide modeling for fasthttp.PipelineClient Type
*/
module PipelineClient {
/**
* First argument of following methods need Additional steps
* Look at Request module, additional steps part for more information
*/
class SSRFSinkDo extends RequestForgery::Sink {
SSRFSinkDo() {
exists(DataFlow::Method m |
m.hasQualifiedName("github.com/valyala/fasthttp.PipelineClient",
["Do", "DoDeadline", "DoTimeout"]) and
this = m.getACall().getArgument(0)
)
}
override DataFlow::Node getARequest() { result = this }
// Kind can be vary because input is a fasthttp.URI type
override string getKind() { result = "URL" }
}
}
/**
* Provide modeling for fasthttp.HostClient Type
*/
module HostClient {
/**
* Get* send a HTTP GET request
* Post send a HTTP POST request
* these Functions first arguments is a URL
*/
class SSRFSink extends RequestForgery::Sink {
SSRFSink() {
exists(DataFlow::Method m |
m.hasQualifiedName("github.com/valyala/fasthttp.HostClient",
["Get", "GetDeadline", "GetTimeout", "Post"]) and
this = m.getACall().getArgument(1)
)
}
override DataFlow::Node getARequest() { result = this }
override string getKind() { result = "URL" }
}
/**
* first argument of following methods need Additional steps
* Look at Request module, additional steps part for more information
*/
class SSRFSinkDo extends RequestForgery::Sink {
SSRFSinkDo() {
exists(DataFlow::Method m |
m.hasQualifiedName("github.com/valyala/fasthttp.HostClient",
["Do", "DoDeadline", "DoTimeout", "DoRedirects"]) and
this = m.getACall().getArgument(0)
)
}
override DataFlow::Node getARequest() { result = this }
// Kind can be vary because input is a fasthttp.URI type
override string getKind() { result = "URL" }
}
}
/**
* Provide modeling for fasthttp.LBClient Type
*/
module LBClient {
/**
* first argument of following methods need Additional steps
* Look at Request module, additional steps part for more information
*/
class SSRFSinkDo extends RequestForgery::Sink {
SSRFSinkDo() {
exists(DataFlow::Method m |
m.hasQualifiedName("github.com/valyala/fasthttp.LBClient",
["Do", "DoDeadline", "DoTimeout"]) and
this = m.getACall().getArgument(0)
)
}
override DataFlow::Node getARequest() { result = this }
// Kind can be vary because input is a fasthttp.URI type
override string getKind() { result = "URL" }
}
}
/**
* Provide modeling for fasthttp.Response Type
*/
module Response {
/**
* Following Method need paht sanitizer before using it, so it is a dangerous method
*/
class FileSystemAccess extends FileSystemAccess::Range, DataFlow::CallNode {
FileSystemAccess() {
exists(DataFlow::Method mcn |
mcn.hasQualifiedName("github.com/valyala/fasthttp.Response", "SendFile") and
this = mcn.getACall()
)
}
override DataFlow::Node getAPathArgument() { result = this.getArgument(0) }
}
/**
* Following methods can pass provide writing to HTTP Response Body
* These methods can be dangerous if they are user controllable
*/
class HttpResponseBodySink extends SharedXss::Sink {
HttpResponseBodySink() {
exists(DataFlow::Method m |
m.hasQualifiedName("github.com/valyala/fasthttp.Response",
[
"AppendBody", "AppendBodyString", "SetBody", "SetBodyString", "SetBodyRaw",
"SetBodyStream"
]) and
this = m.getACall().getArgument(0)
)
}
}
}
/**
* Provide modeling for fasthttp.Request Type
*/
module Request {
/**
* Pred can be an user controlled value like any potential part of URL and succ is the URI instance
* So if we called a method like `RequestInstance.SetHost(pred)` then the RequestInstance is succ
* for SetURI the argument type is fasthttp.URI which is already modeled, look at URI module
*/
class RequestAdditionalStep extends AdditionalStep {
RequestAdditionalStep() { this = "Request additioanl steps" }
@@ -193,6 +403,9 @@ module Fasthttp {
}
}
/**
* Provide remote user controllable sources which can be many part of request
*/
class UntrustedFlowSource extends UntrustedFlowSource::Range instanceof DataFlow::Node {
UntrustedFlowSource() {
exists(DataFlow::Method m |
@@ -214,36 +427,10 @@ module Fasthttp {
}
}
module Response {
class FileSystemAccess extends FileSystemAccess::Range, DataFlow::CallNode {
FileSystemAccess() {
exists(DataFlow::Method mcn |
mcn.hasQualifiedName("github.com/valyala/fasthttp.Response", "SendFile") and
this = mcn.getACall()
)
}
override DataFlow::Node getAPathArgument() {
this.getTarget().getName() = "SendFile" and
result = this.getArgument(0)
}
}
class HttpResponseBodySink extends SharedXss::Sink {
HttpResponseBodySink() {
exists(DataFlow::Method m |
m.hasQualifiedName("github.com/valyala/fasthttp.Response",
[
"AppendBody", "AppendBodyString", "SetBody", "SetBodyString", "SetBodyRaw",
"SetBodyStream"
]) and
this = m.getACall().getArgument(0)
)
}
}
}
module RequestCtx {
/**
* Following Methods don't sanitize user provided file paths
*/
class FileSystemAccess extends FileSystemAccess::Range, DataFlow::CallNode {
FileSystemAccess() {
exists(DataFlow::Method mcn |
@@ -259,6 +446,9 @@ module Fasthttp {
}
}
/**
* Following Methods can be dangerous if they take user controlled URL as thery first argument
*/
private class Redirect extends Http::Redirect::Range, DataFlow::CallNode {
Redirect() {
exists(DataFlow::Function f |
@@ -272,6 +462,9 @@ module Fasthttp {
override Http::ResponseWriter getResponseWriter() { none() }
}
/**
* Provide remote user controllable sources
*/
class UntrustedFlowSource extends UntrustedFlowSource::Range instanceof DataFlow::Node {
UntrustedFlowSource() {
exists(DataFlow::Method m |
@@ -283,3 +476,28 @@ module Fasthttp {
}
}
}
/**
* Provide Methods of fasthttp.RequestHeader which mostly used as remote user controlled sources
*/
module RequestHeader {
/**
* Provide Methods of fasthttp.RequestHeader as remote user controlled sources mostly from HTTP Request Headers
*/
class UntrustedFlowSource extends UntrustedFlowSource::Range instanceof DataFlow::Node {
UntrustedFlowSource() {
exists(DataFlow::Method m |
m.hasQualifiedName("github.com/valyala/fasthttp.RequestHeader",
[
"Header", "TrailerHeader", "RequestURI", "Host", "UserAgent", "ContentEncoding",
"ContentType", "Cookie", "CookieBytes", "MultipartFormBoundary", "Peek", "PeekAll",
"PeekBytes", "PeekKeys", "PeekTrailerKeys", "Referer", "RawHeaders"
]) and
this = m.getACall()
or
m.hasQualifiedName("github.com/valyala/fasthttp.RequestHeader", "Write") and
this = m.getACall().getArgument(0)
)
}
}
}

View File

@@ -20,38 +20,67 @@ func fasthttpClient() {
log.Println(resByte)
// #SSRF
res := &fasthttp.Response{}
req := &fasthttp.Request{}
uri := fasthttp.AcquireURI()
uri2 := fasthttp.AcquireURI()
fasthttp.Get(resByte, "http://127.0.0.1:8909")
fasthttp.GetDeadline(resByte, "http://127.0.0.1:8909", time.Time{})
fasthttp.GetTimeout(resByte, "http://127.0.0.1:8909", 5)
fasthttp.Post(resByte, "http://127.0.0.1:8909", nil)
log.Println(string(resByte))
fasthttp.Do(req, res)
fasthttp.DoRedirects(req, res, 2)
fasthttp.DoDeadline(req, res, time.Time{})
fasthttp.DoTimeout(req, res, 5)
// additional steps
uri.SetHost("UserControlled.com:80")
uri.SetHostBytes([]byte("UserControlled.com:80"))
uri.Update("http://httpbin.org/ip")
uri.UpdateBytes([]byte("http://httpbin.org/ip"))
uri.Parse(nil, []byte("http://httpbin.org/ip"))
uri.CopyTo(uri2)
req.SetHost("UserControlled.com:80")
req.SetHostBytes([]byte("UserControlled.com:80"))
req.SetRequestURI("https://UserControlled.com")
req.SetRequestURIBytes([]byte("https://UserControlled.com"))
req.SetURI(uri)
hostClient := &fasthttp.HostClient{
Addr: "localhost:8080",
}
hostClient.Get(resByte, "http://127.0.0.1:8909")
hostClient.GetDeadline(resByte, "http://127.0.0.1:8909", time.Time{})
hostClient.GetTimeout(resByte, "http://127.0.0.1:8909", 5)
hostClient.Post(resByte, "http://127.0.0.1:8909", nil)
hostClient.Do(req, res)
hostClient.DoDeadline(req, res, time.Time{})
hostClient.DoRedirects(req, res, 2)
hostClient.DoTimeout(req, res, 5)
var lbclient fasthttp.LBClient
lbclient.Clients = append(lbclient.Clients, hostClient)
lbclient.Do(req, res)
lbclient.DoDeadline(req, res, time.Time{})
lbclient.DoTimeout(req, res, 5)
// #SSRF
client := fasthttp.Client{}
client.Get(resByte, "http://127.0.0.1:8909")
client.GetDeadline(resByte, "http://127.0.0.1:8909", time.Time{})
client.GetTimeout(resByte, "http://127.0.0.1:8909", 5)
client.Post(resByte, "http://127.0.0.1:8909", nil)
res := &fasthttp.Response{}
req := &fasthttp.Request{}
uri := fasthttp.URI{}
// additional steps
uri.SetHost("UserControlled.com:80")
uri.SetHostBytes([]byte("UserControlled.com:80"))
req.SetHost("UserControlled.com:80")
req.SetHostBytes([]byte("UserControlled.com:80"))
req.SetRequestURI("https://UserControlled.com")
req.SetRequestURIBytes([]byte("https://UserControlled.com"))
req.SetURI(&uri)
fasthttp.Do(req, res)
fasthttp.DoDeadline(req, res, time.Time{})
fasthttp.DoTimeout(req, res, 5)
client.Do(req, res)
client.DoDeadline(req, res, time.Time{})
client.DoRedirects(req, res, 2)
client.DoTimeout(req, res, 5)
// #SSRF
pipelineClient := fasthttp.PipelineClient{}
pipelineClient.Do(req, res)
pipelineClient.DoDeadline(req, res, time.Time{})
pipelineClient.DoTimeout(req, res, 5)
tcpDialer := fasthttp.TCPDialer{}
tcpDialer.Dial("127.0.0.1:8909")
tcpDialer.DialTimeout("127.0.0.1:8909", 5)
@@ -59,29 +88,34 @@ func fasthttpClient() {
tcpDialer.DialDualStackTimeout("127.0.0.1:8909", 5)
}
func main() {
fasthttpServer()
fasthttpClient()
}
func fasthttpServer() {
ln, err := net.Listen("tcp4", "127.0.0.1:8080")
if err != nil {
log.Fatalf("error in net.Listen: %v", err)
}
requestHandler := func(ctx *fasthttp.RequestCtx) {
filePath := ctx.QueryArgs().Peek("filePath")
requestHandler := func(requestCtx *fasthttp.RequestCtx) {
filePath := requestCtx.QueryArgs().Peek("filePath")
// File System Access
_ = ctx.Response.SendFile(string(filePath))
ctx.SendFile(string(filePath))
ctx.SendFileBytes(filePath)
fileHeader, _ := ctx.FormFile("file")
_ = requestCtx.Response.SendFile(string(filePath))
requestCtx.SendFile(string(filePath))
requestCtx.SendFileBytes(filePath)
fileHeader, _ := requestCtx.FormFile("file")
_ = fasthttp.SaveMultipartFile(fileHeader, string(filePath))
fasthttp.ServeFile(ctx, string(filePath))
fasthttp.ServeFileUncompressed(ctx, string(filePath))
fasthttp.ServeFileBytes(ctx, filePath)
fasthttp.ServeFileBytesUncompressed(ctx, filePath)
fasthttp.ServeFile(requestCtx, string(filePath))
fasthttp.ServeFileUncompressed(requestCtx, string(filePath))
fasthttp.ServeFileBytes(requestCtx, filePath)
fasthttp.ServeFileBytesUncompressed(requestCtx, filePath)
dstWriter := &bufio.Writer{}
dstReader := &bufio.Reader{}
// user controlled methods as source
requestHeader := &fasthttp.RequestHeader{}
ctx.Request.Header.CopyTo(requestHeader)
requestCtx.Request.Header.CopyTo(requestHeader)
requestHeader.Write(dstWriter)
requestHeader.Header()
requestHeader.TrailerHeader()
@@ -102,82 +136,76 @@ func fasthttpServer() {
requestHeader.Referer()
requestHeader.RawHeaders()
// multipart.Form is already implemented
//ctx.MultipartForm()
ctx.URI().Path()
ctx.URI().PathOriginal()
// requestCtx.MultipartForm()
requestCtx.URI().Path()
requestCtx.URI().PathOriginal()
newURI := &fasthttp.URI{}
ctx.URI().CopyTo(newURI)
ctx.URI().FullURI()
ctx.URI().LastPathSegment()
ctx.URI().QueryString()
ctx.URI().String()
ctx.URI().WriteTo(dstWriter)
requestCtx.URI().CopyTo(newURI)
requestCtx.URI().FullURI()
requestCtx.URI().LastPathSegment()
requestCtx.URI().QueryString()
requestCtx.URI().String()
requestCtx.URI().WriteTo(dstWriter)
newArgs := &fasthttp.Args{}
//or ctx.PostArgs()
ctx.URI().QueryArgs().CopyTo(newArgs)
ctx.URI().QueryArgs().Peek("arg1")
ctx.URI().QueryArgs().PeekBytes([]byte("arg1"))
ctx.URI().QueryArgs().PeekMulti("arg1")
ctx.URI().QueryArgs().PeekMultiBytes([]byte("arg1"))
ctx.URI().QueryArgs().QueryString()
ctx.URI().QueryArgs().String()
ctx.URI().QueryArgs().WriteTo(dstWriter)
//or requestCtx.PostArgs()
requestCtx.URI().QueryArgs().CopyTo(newArgs)
requestCtx.URI().QueryArgs().Peek("arg1")
requestCtx.URI().QueryArgs().PeekBytes([]byte("arg1"))
requestCtx.URI().QueryArgs().PeekMulti("arg1")
requestCtx.URI().QueryArgs().PeekMultiBytes([]byte("arg1"))
requestCtx.URI().QueryArgs().QueryString()
requestCtx.URI().QueryArgs().String()
requestCtx.URI().QueryArgs().WriteTo(dstWriter)
// not sure what is the best way to write query for following
//ctx.URI().QueryArgs().VisitAll(type func(,))
//requestCtx.URI().QueryArgs().VisitAll(type func(,))
ctx.Path()
requestCtx.Path()
// multipart.Form is already implemented
// ctx.FormFile("FileName")
// ctx.FormValue("ValueName")
ctx.Referer()
ctx.PostBody()
ctx.RequestBodyStream()
ctx.RequestURI()
ctx.UserAgent()
ctx.Host()
// requestCtx.FormFile("FileName")
// requestCtx.FormValue("ValueName")
requestCtx.Referer()
requestCtx.PostBody()
requestCtx.RequestBodyStream()
requestCtx.RequestURI()
requestCtx.UserAgent()
requestCtx.Host()
ctx.Request.Host()
ctx.Request.Body()
ctx.Request.RequestURI()
ctx.Request.BodyGunzip()
ctx.Request.BodyInflate()
ctx.Request.BodyUnbrotli()
ctx.Request.BodyStream()
ctx.Request.BodyWriteTo(dstWriter)
ctx.Request.WriteTo(dstWriter)
ctx.Request.BodyUncompressed()
ctx.Request.ReadBody(dstReader, 100, 1000)
ctx.Request.ReadLimitBody(dstReader, 100)
ctx.Request.ContinueReadBodyStream(dstReader, 100, true)
ctx.Request.ContinueReadBody(dstReader, 100)
requestCtx.Request.Host()
requestCtx.Request.Body()
requestCtx.Request.RequestURI()
requestCtx.Request.BodyGunzip()
requestCtx.Request.BodyInflate()
requestCtx.Request.BodyUnbrotli()
requestCtx.Request.BodyStream()
requestCtx.Request.BodyWriteTo(dstWriter)
requestCtx.Request.WriteTo(dstWriter)
requestCtx.Request.BodyUncompressed()
requestCtx.Request.ReadBody(dstReader, 100, 1000)
requestCtx.Request.ReadLimitBody(dstReader, 100)
requestCtx.Request.ContinueReadBodyStream(dstReader, 100, true)
requestCtx.Request.ContinueReadBody(dstReader, 100)
// not sure what is the best way to write query for following
//ctx.Request.Header.VisitAllCookie()
//requestCtx.Request.Header.VisitAllCookie()
// Xss Sinks
ctx.Response.AppendBody([]byte("user Controlled"))
ctx.Response.AppendBodyString("user Controlled")
rspWriter := ctx.Response.BodyWriter()
requestCtx.Response.AppendBody([]byte("user Controlled"))
requestCtx.Response.AppendBodyString("user Controlled")
rspWriter := requestCtx.Response.BodyWriter()
rspWriter.Write([]byte("XSS"))
ctx.Response.SetBody([]byte("user Controlled"))
ctx.Response.SetBodyString("user Controlled")
ctx.Response.SetBodyRaw([]byte("user Controlled"))
ctx.Response.SetBodyStream(dstReader, 100)
dstByte := []byte("init")
// sanitizers
fasthttp.AppendQuotedArg(dstByte, []byte("xsss"))
fasthttp.AppendHTMLEscape(dstByte, "xss")
fasthttp.AppendHTMLEscapeBytes(dstByte, []byte("xss"))
requestCtx.Response.SetBody([]byte("user Controlled"))
requestCtx.Response.SetBodyString("user Controlled")
requestCtx.Response.SetBodyRaw([]byte("user Controlled"))
requestCtx.Response.SetBodyStream(dstReader, 100)
// TODO: unstrusted Remote IP from Header?
// TODO: open redirect Sinks
req := &fasthttp.Request{}
res := &fasthttp.Response{}
// there are additional steps from other scope
req.SetRequestURI("https://userControlled.com")
fasthttp.DoRedirects(req, res, 2)
ctx.Redirect("https://userControlled.com", 301)
ctx.RedirectBytes([]byte("https://userControlled.com"), 301)
// sanitizers
requestCtx.Response.AppendBody(fasthttp.AppendQuotedArg([]byte(""), []byte("<>\"':()&"))) // %3C%3E%22%27%3A%28%29%26
requestCtx.Response.AppendBody(fasthttp.AppendHTMLEscape([]byte(""), "<>\"':()&")) // &lt;&gt;&#34;&#39;:()&amp;
requestCtx.Response.AppendBody(fasthttp.AppendHTMLEscapeBytes([]byte(""), []byte("<>\"':()&"))) // &lt;&gt;&#34;&#39;:()&amp;
// open redirect Sinks
requestCtx.Redirect("https://userControlled.com", 301)
requestCtx.RedirectBytes([]byte("https://userControlled.com"), 301)
}
if err := fasthttp.Serve(ln, requestHandler); err != nil {
log.Fatalf("error in Serve: %v", err)