Using a pow File¶
A pow
file is just a bash script, where you make calls to the
kapow route
command.
Starting Kapow! using a pow file¶
1 | $ kapow server example.pow
|
With the example.pow
:
1 2 3 4 5 6 7 8 9 | $ cat example.pow
#
# This is a simple example of a pow file
#
echo '[*] Starting my script'
# We add 2 Kapow! routes
kapow route add /my/route -c 'echo hello world | kapow set /response/body'
kapow route add -X POST /echo -c 'kapow get /request/body | kapow set /response/body'
|
Note
Kapow! can be fully configured using just pow
files
Load More Than One pow File¶
You can load more than one pow
file at time. This can help you keep
your pow
files tidy.
1 2 3 | $ ls pow-files/
example-1.pow example-2.pow
$ kapow server <(cat pow-files/*.pow)
|
Add a New Route¶
Warning
Be aware that if you register more than one route with exactly the same path, only the first route added will be used.
GET route¶
Defining a route:
1 | $ kapow route add /my/route -c 'echo hello world | kapow set /response/body'
|
Calling route:
1 2 | $ curl http://localhost:8080/my/route
hello world
|
POST route¶
Defining a route:
1 | $ kapow route add -X POST /echo -c 'kapow get /request/body | kapow set /response/body'
|
Calling a route:
1 2 | $ curl -d 'hello world' -X POST http://localhost:8080/echo
hello world
|
Adding URL params¶
Defining a route:
1 | $ kapow route add '/echo/{message}' -c 'kapow get /request/matches/message | kapow set /response/body'
|
Calling a route:
1 2 | $ curl http://localhost:8080/echo/hello%20world
hello world
|
Listing Routes¶
You can list the active routes in the Kapow! server.
1 2 | $ kapow route list
[{"id":"20c98328-0b82-11ea-90a8-784f434dfbe2","method":"GET","url_pattern":"/echo/{message}","entrypoint":"/bin/sh -c","command":"kapow get /request/matches/message | kapow set /response/body"}]
|
Or, if you want human-readable output, you can use jq:
1 2 3 4 5 6 7 8 9 10 | $ kapow route list | jq
[
{
"id": "20c98328-0b82-11ea-90a8-784f434dfbe2",
"method": "GET",
"url_pattern": "/echo/{message}",
"entrypoint": "/bin/sh -c",
"command": "kapow get /request/matches/message | kapow set /response/body",
}
]
|
Note
Kapow! has a HTTP Control Interface, bound by default to
localhost:8081
.
Deleting Routes¶
You need the ID of a route to delete it. Running the command used in the listing routes example, you can obtain the ID of the route, and then delete it by typing:
1 | $ kapow route remove 20c98328-0b82-11ea-90a8-784f434dfbe2
|
Writing Multiline pow Files¶
If you need to write more complex actions, you can leverage multiline commands:
1 2 3 4 5 | $ cat multiline.pow
kapow route add /log_and_stuff - <<-'EOF'
echo this is a quite long sentence and other stuff | tee log.txt | kapow set /response/body
cat log.txt | kapow set /response/body
EOF
|
Warning
Be aware of the “-“ at the end of the kapow route add
command.
It tells kapow route add
to read commands from stdin
.
Warning
If you want to learn more about multiline usage, see: Here Doc
Add or Modify an HTTP Header¶
You may want to add some extra HTTP header to the response.
In this example we’ll be adding the header X-Content-Type-Options
to the response.
1 2 3 4 5 6 7 8 9 | $ cat sniff.pow
kapow route add /sec-hello-world - <<-'EOF'
kapow set /response/headers/X-Content-Type-Options nosniff
kapow set /response/headers/Content-Type text/plain
echo this will be interpreted as plain text | kapow set /response/body
EOF
$ kapow server nosniff.pow
|
Testing with curl:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | $ curl -v http://localhost:8080/sec-hello-world
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /sec-hello-word HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< X-Content-Type-Options: nosniff
< Date: Wed, 20 Nov 2019 10:56:46 GMT
< Content-Length: 24
< Content-Type: text/plain
<
this will be interpreted as plain text
|
Warning
Please be aware that if you don’t explicitly specify the value of
the Content-Type
header, Kapow! will guess it, effectively
negating the effect of the X-Content-Type-Options
header.
Note
You can read more about the X-Content-Type-Options: nosniff
header here.
Modify JSON by Using Shell Commands¶
Note
Nowadays Web services are JSON
-based, so making your script JSON
aware is
probably a good choice. In order to be able to extract data from a JSON
document as well as composing JSON
documents from a script, you can leverage
jq.
Example #1¶
In this example our Kapow! service will receive a JSON
value with an incorrect
date, then our pow
file will fix it and return the correct value to the user.
1 2 3 4 5 | $ cat fix_date.pow
kapow route add -X POST /fix-date - <<-'EOF'
kapow set /response/headers/Content-Type application/json
kapow get /request/body | jq --arg newdate "$(date +'%Y-%m-%d_%H-%M-%S')" '.incorrectDate=$newdate' | kapow set /response/body
EOF
|
Call the service with curl:
1 2 3 4 | $ curl -X POST http://localhost:8080/fix-date -H 'Content-Type: application/json' -d '{"incorrectDate": "no way, Jose"}'
{
"incorrectDate": "2019-11-22_10-42-06"
}
|
Example #2¶
In this example we extract the name
field from the incoming JSON
document in
order to generate a two-attribute JSON
response.
$ cat echo-attribute.pow
kapow route add -X POST /echo-attribute - <<-'EOF'
JSON_WHO=$(kapow get /request/body | jq -r .name)
kapow set /response/headers/Content-Type application/json
kapow set /response/status 200
jq --arg greet Hello --arg value "${JSON_WHO:-World}" --null-input '{ greet: $greet, to: $value }' | kapow set /response/body
EOF
Call the service with curl:
1 2 3 4 5 | $ curl -X POST http://localhost:8080/echo-attribute -H 'Content-Type: application/json' -d '{"name": "MyName"}'
{
"greet": "Hello",
"to": "MyName"
}
|
Upload Files¶
Example #1¶
Uploading a file using Kapow! is very simple:
1 2 3 4 | $ cat upload.pow
kapow route add -X POST /upload-file - <<-'EOF'
kapow get /request/files/data/content | kapow set /response/body
EOF
|
1 2 3 4 | $ cat results.json
{"hello": "world"}
$ curl -X POST -H 'Content-Type: multipart/form-data' -F data=@results.json http://localhost:8080/upload-file
{"hello": "world"}
|
Example #2¶
In this example we reply the line count of the file received in the request:
1 2 3 4 5 6 7 8 9 10 11 12 13 | $ cat count-file-lines.pow
kapow route add -X POST /count-file-lines - <<-'EOF'
# Get sent file
FNAME=$(kapow get /request/files/myfile/filename)
# Counting file lines
LCOUNT=$(kapow get /request/files/myfile/content | wc -l)
kapow set /response/status 200
echo "$FNAME has $LCOUNT lines" | kapow set /response/body
EOF
|
1 2 3 4 5 | $ cat file.txt
hello
World
$ curl -F myfile=@file.txt http://localhost:8080/count-file-lines
file.txt has 2 lines
|
Protecting Against Parameter Injection Attacks¶
When you resolve variable values be careful to tokenize correctly by using double quotes. Otherwise you could be vulnerable to parameter injection attacks.
This example is VULNERABLE to parameter injection
In this example, an attacker can inject arbitrary parameters to ls.
1 2 3 4 | $ cat command-injection.pow
kapow route add '/vulnerable/{value}' - <<-'EOF'
ls $(kapow get /request/matches/value) | kapow set /response/body
EOF
|
Exploiting using curl:
1 | $ curl http://localhost:8080/vulnerable/-lai%20hello
|
This example is NOT VULNERABLE to parameter injection
Note how we add double quotes when we recover value data from the request:
1 2 3 4 | $ cat command-injection.pow
kapow route add '/not-vulnerable/{value}' - <<-'EOF'
ls -- "$(kapow get /request/matches/value)" | kapow set /response/body
EOF
|
Warning
Quotes around parameters only protect against the injection of additional arguments, but not against turning a non-option into option or vice-versa. Note that for many commands we can leverage double-dash to signal the end of the options. See the “Security Concern” section on the docs.
Sending HTTP error codes¶
You can specify custom status code for HTTP
response:
1 2 3 4 5 | $ cat error.pow
kapow route add /error - <<-'EOF'
kapow set /response/status 401
echo -n '401 error' | kapow set /response/body
EOF
|
Testing with curl:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $ curl -v http://localhost:8080/error
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /error HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 401 Unauthorized
< Date: Wed, 20 Nov 2019 14:06:44 GMT
< Content-Length: 10
< Content-Type: text/plain; charset=utf-8
<
401 error
|
How to redirect using HTTP¶
In this example we’ll redirect our users to Google
:
1 2 3 4 5 | $ cat redirect.pow
kapow route add /redirect - <<-'EOF'
kapow set /response/headers/Location https://google.com
kapow set /response/status 301
EOF
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $ curl -v http://localhost:8080/redirect
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /redirect HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 301 Moved Permanently
< Location: http://google.com
< Date: Wed, 20 Nov 2019 11:39:24 GMT
< Content-Length: 0
<
* Connection #0 to host localhost left intact
|
How to Execute Two Processes in Parallel¶
We want to ping two machines parallel. Kapow! can get IP addresses from query params:
1 2 3 4 5 6 | $ cat parallel.pow
kapow route add '/parallel/{ip1}/{ip2}' - <<-'EOF'
ping -c 1 -- "$(kapow get /request/matches/ip1)" | kapow set /response/body &
ping -c 1 -- "$(kapow get /request/matches/ip2)" | kapow set /response/body &
wait
EOF
|
Calling with curl:
1 | $ curl -v http://localhost:8080/parallel/10.0.0.1/10.10.10.1
|
Manage Cookies¶
If you track down some user state, Kapow! allows you manage Request/Response Cookies.
In the next example we’ll set a cookie:
1 2 3 4 5 6 7 8 9 10 | $ cat cookie.pow
kapow route add /setcookie - <<-'EOF'
CURRENT_STATUS=$(kapow get /request/cookies/kapow-status)
if [ -z "$CURRENT_STATUS" ]; then
kapow set /response/cookies/Kapow-Status 'Kapow Cookie Set'
fi
echo -n OK | kapow set /response/body
EOF
|
Calling with curl:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | $ curl -v http://localhost:8080/setcookie
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /setcookie HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Set-Cookie: Kapow-Status="Kapow Cookie Set"
< Date: Fri, 22 Nov 2019 10:44:42 GMT
< Content-Length: 3
< Content-Type: text/plain; charset=utf-8
<
OK
* Connection #0 to host localhost left intact
|