@@ -15,7 +15,7 @@ import scala.sys.process._
15
15
*/
16
16
class HomeController @ Inject ()(ws : WSClient , cc : MessagesControllerComponents )(implicit ec : ExecutionContext ) extends MessagesAbstractController (cc) {
17
17
18
- def index = Action { implicit request =>
18
+ def index : Action [ AnyContent ] = Action { implicit request =>
19
19
Ok (Html (s """
20
20
<html>
21
21
<body>
@@ -41,7 +41,7 @@ class HomeController @Inject()(ws: WSClient, cc: MessagesControllerComponents)(i
41
41
/**
42
42
* Command injection & XSS directly from directly called query parameter
43
43
*/
44
- def attackerQuerySimple = Action { implicit request =>
44
+ def attackerQuerySimple : Action [ AnyContent ] = Action { implicit request =>
45
45
val address = request.getQueryString(" address" )
46
46
47
47
// [RuleTest] Command Injection
@@ -56,14 +56,15 @@ class HomeController @Inject()(ws: WSClient, cc: MessagesControllerComponents)(i
56
56
/**
57
57
* Command injection & XSS directly from directly called query parameter
58
58
*/
59
- def attackerQueryPatternMatching = Action { implicit request =>
59
+ def attackerQueryPatternMatching : Action [ AnyContent ] = Action { implicit request =>
60
60
61
61
val addressRE = " (.*):(\\ d+)" .r
62
62
val address = request.cookies.get(" address" ).get.value
63
63
64
64
address match {
65
- // [RuleTest] Command Injection
65
+ // [RuleTest] Command Injection
66
66
case addressRE(address, port) => s " ping ${address}" .!
67
+ case _ =>
67
68
}
68
69
// [RuleTest] Cross-Site Scripting: Reflected
69
70
Ok (Html (s " Host ${address} pinged " )) as HTML
@@ -72,7 +73,7 @@ class HomeController @Inject()(ws: WSClient, cc: MessagesControllerComponents)(i
72
73
/**
73
74
* XSS directly from directly called query parameter
74
75
*/
75
- def attackerQuery = Action { implicit request =>
76
+ def attackerQuery : Action [ AnyContent ] = Action { implicit request =>
76
77
77
78
val result = request.getQueryString(" attacker" ).map { command =>
78
79
// Render the command directly from query parameter, this is the obvious example
@@ -87,21 +88,21 @@ class HomeController @Inject()(ws: WSClient, cc: MessagesControllerComponents)(i
87
88
/**
88
89
* XSS through query string parsed by generated router from conf/routes file.
89
90
*/
90
- def attackerRouteControlledQuery (attacker : String ) = Action { implicit request =>
91
+ def attackerRouteControlledQuery (attacker : String ): Action [ AnyContent ] = Action { implicit request =>
91
92
Ok (Html (attacker)) as HTML
92
93
}
93
94
94
95
/**
95
96
* XSS through path binding parsed by generated router from conf/routes file.
96
97
*/
97
- def attackerRouteControlledPath (attacker : String ) = Action { implicit request =>
98
+ def attackerRouteControlledPath (attacker : String ): Action [ AnyContent ] = Action { implicit request =>
98
99
Ok (Html (attacker)) as HTML
99
100
}
100
101
101
102
/**
102
103
* XSS through attacker controlled info in cookie
103
104
*/
104
- def attackerCookie = Action { implicit request =>
105
+ def attackerCookie : Action [ AnyContent ] = Action { implicit request =>
105
106
// User cookies have no message authentication by default, so an attacker can pass in a cookie
106
107
val result = request.cookies.get(" attacker" ).map { attackerCookie =>
107
108
// Render the command
@@ -114,7 +115,7 @@ class HomeController @Inject()(ws: WSClient, cc: MessagesControllerComponents)(i
114
115
/**
115
116
* XSS through attacker controlled header
116
117
*/
117
- def attackerHeader = Action { implicit request =>
118
+ def attackerHeader : Action [ AnyContent ] = Action { implicit request =>
118
119
// Request headers are also unvalidated by default.
119
120
// The usual example is pulling the Location header to do an unsafe redirect
120
121
val result = request.headers.get(" Attacker" ).map { command =>
@@ -128,7 +129,7 @@ class HomeController @Inject()(ws: WSClient, cc: MessagesControllerComponents)(i
128
129
/**
129
130
* Unbound redirect through Header
130
131
*/
131
- def attackerOpenRedirect = Action { implicit request =>
132
+ def attackerOpenRedirect : Action [ AnyContent ] = Action { implicit request =>
132
133
request.headers.get(" Location" ) match {
133
134
case Some (attackerLocation) =>
134
135
// Also see https://github.com/playframework/playframework/issues/6450
@@ -142,7 +143,7 @@ class HomeController @Inject()(ws: WSClient, cc: MessagesControllerComponents)(i
142
143
/**
143
144
* XSS through URL encoded form input.
144
145
*/
145
- def attackerFormInput = Action { implicit request =>
146
+ def attackerFormInput : Action [ AnyContent ] = Action { implicit request =>
146
147
val boundForm = FormData .form.bindFromRequest()
147
148
boundForm.fold(badData => BadRequest (" Bad form binding" ), userData => {
148
149
// Render the attacker command as HTML
@@ -154,7 +155,7 @@ class HomeController @Inject()(ws: WSClient, cc: MessagesControllerComponents)(i
154
155
/**
155
156
* XSS through attacker controlled flash cookie.
156
157
*/
157
- def attackerFlash = Action { implicit request =>
158
+ def attackerFlash : Action [ AnyContent ] = Action { implicit request =>
158
159
// Flash is usually handled with
159
160
// Redirect(routes.HomeController.attackerFlash()).flashing("info" -> "Some text")
160
161
// but if the user puts HTML in it and then renders it,
@@ -170,14 +171,14 @@ class HomeController @Inject()(ws: WSClient, cc: MessagesControllerComponents)(i
170
171
}
171
172
172
173
// Render a boring form
173
- def constraintForm = Action { implicit request =>
174
+ def constraintForm : Action [ AnyContent ] = Action { implicit request =>
174
175
Ok (views.html.index(FormData .customForm))
175
176
}
176
177
177
178
/**
178
179
* XSS through custom constraint with user input
179
180
*/
180
- def attackerConstraintForm = Action { implicit request =>
181
+ def attackerConstraintForm : Action [ AnyContent ] = Action { implicit request =>
181
182
182
183
// Bind a form that uses the i18n messages api, but the user input is reflected in the error message
183
184
// Play takes a raw string here and escapes everything, but it may be possible to escape this...
@@ -196,7 +197,7 @@ class HomeController @Inject()(ws: WSClient, cc: MessagesControllerComponents)(i
196
197
/**
197
198
* XSS involving Twirl template
198
199
*/
199
- def twirlXSS = Action { implicit request =>
200
+ def twirlXSS = Action { implicit request : MessagesRequest [ AnyContent ] =>
200
201
request.getQueryString(" xss" ).map { payload =>
201
202
Ok (views.html.xss(payload))
202
203
}.getOrElse(Ok (" Missing xss param" ))
@@ -205,7 +206,7 @@ class HomeController @Inject()(ws: WSClient, cc: MessagesControllerComponents)(i
205
206
/**
206
207
* SSRF attacks done with Play WS
207
208
*/
208
- def attackerSSRF = Action .async { implicit request =>
209
+ def attackerSSRF : Action [ AnyContent ] = Action .async { implicit request =>
209
210
// Play WS does not have a whitelist of valid URLs, so if you're calling it
210
211
// directly with user input, you're open to SSRF. The best thing to do is
211
212
// to place WS access in a wrapper, i.e.
@@ -222,7 +223,7 @@ class HomeController @Inject()(ws: WSClient, cc: MessagesControllerComponents)(i
222
223
/**
223
224
* Command injection with custom body parser
224
225
*/
225
- def attackerCustomBodyParser = Action (bodyParser = BodyParser { header : RequestHeader =>
226
+ def attackerCustomBodyParser : Action [ Foo ] = Action (bodyParser = BodyParser { ( header : RequestHeader ) => {
226
227
// request header is a request without a body
227
228
// http://localhost:9000/attackerCustomBodyParser?address=/etc/passwd
228
229
val result = header.getQueryString(" filename" ).map { filename =>
@@ -231,7 +232,7 @@ class HomeController @Inject()(ws: WSClient, cc: MessagesControllerComponents)(i
231
232
}.getOrElse(" No filename found!" )
232
233
233
234
Accumulator .done(Right (Foo (bar = result)))
234
- }) { implicit request : Request [Foo ] =>
235
+ }} ) { implicit request : Request [Foo ] =>
235
236
val foo : Foo = request.body
236
237
Ok (foo.bar)
237
238
}
@@ -313,4 +314,7 @@ object FormData {
313
314
314
315
315
316
case class UserData (name : String , age: Int )
317
+ object UserData {
318
+ def unapply (u : UserData ): Option [(String , Int )] = Some ((u.name, u.age))
319
+ }
316
320
}
0 commit comments