mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
fix some mistakes:(
This commit is contained in:
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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(""), "<>\"':()&")) // <>"':()&
|
||||
requestCtx.Response.AppendBody(fasthttp.AppendHTMLEscapeBytes([]byte(""), []byte("<>\"':()&"))) // <>"':()&
|
||||
|
||||
// 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)
|
||||
|
||||
Reference in New Issue
Block a user