Guides

Everyone gets stuck at games now and then. In an attempt to help some of those people, I publish guides to some games that I've beaten. Choose a game or browse through all of them.

Project Euler 10: Sum of First Primes

In the post about Project Euler 7, I described how to obtain a list of primes. These are not enough: the last one is 1,299,827, and we need all up to 2,000,000. The first 1,000,000 prime numbers can be found at the same site. Here is a ZIP file of the 1,000,000 first primes. Download the file, unzip it and format it as in problem 7.

Summing the first ones is fast and simple. This Perl script does it well:

1
2
3
4
5
6
7
8
9
my $sum = 0;
open( PRIMES, '<', 'dat/primes-1000000-first.txt' ) or die $!;
while ( <PRIMES> ) {
        chomp;
        last if $_ >= 2000000;
        $sum += $_;
}
close( PRIMES );
print $sum, "\n";

Project Euler 7: The 10001st Prime Number

This mission can be solved by calculating lots of prime numbers. However, we do not want to put extra effort into our solutions, do we? After a bit of searching, I found a list of the 100000 first prime numbers (100008, actually). I saved this file. Unfortunately, it is not in an optimal format. I wrote a short Perl script that creates a new file, in which each prime number is on a separate line:

1
2
3
4
5
6
7
8
9
10
11
12
13
# read the file from utm.edu
open( PRIMES, '<', 'dat/100000.txt' ) or die $!;
# this is the file that we will write to
open( TO, '>', 'dat/primes-100000-first.txt' ) or die $!;
while ( <PRIMES> ) { # for each line
        for ( split / +/ ) { # split, separating by spaces, and for each piece
                if ( m/^\d+$/ ) { # if it is a number
                        print TO "$_\n"; # print the number to the file
                }
        }
}
close( TO );
close( PRIMES );

Of course, you need to replace the filenames.

Now, it is a piece of cake to find the 10001st prime number. Just do:

head -10001 dat/primes-100000-first.txt | tail -1

Which finds the 10001 first primes and outputs the last one of them.

Or you could open it in notepad and start counting rows.

Project Euler 9: Pythagorean Triplets, Sum=1000

There is exactly one Pythagorean triplet (a^2+b^2=c^2) in which a+b+c=1000. Since all terms are positive, we can try all alternatives for 0 < a,b < 1000, which is less than 1000^2. This Perl script does it all:

1
2
3
4
5
6
7
8
9
10
11
12
# first, generate pairs of a and b
for ( my $a = 1; $a < 1000; $a++ ) {
        for ( my $b = $a; $b < 1000; $b++ ) {
                # c is then calculated from these
                my $c = sqrt( $a*$a + $b*$b );
                if ( $a+$b+$c == 1000 ) {
                        # print and exit if we found the answer
                        printf "%d*%d*%d=%d\n", $a, $b, $c, $a*$b*$c;
                        exit;
                }
        }
}

There is probably a faster solution without a square root, but this one is fast enough.

HBH Basic Web 7: Encrypt ASCII Cookie

Basic web hacking mission 7 of the Hellbound Hacker series is a prime example of why I dislike their “hacking challenges”. Some of them are not about hacking!

This time Mr. Deitry decided to make a cookie login script and he said he decrypted it from ASCII encryption, and for you to login you need to encrypt it. And after you login there is another login but its a Login that uses SQL databases, but he thinks that the SQL login page is vulnerable to a simple SQL injection, and when he gets back from his vacation he would fix it.

In this mission, whatever you do, don’t try to think by yourself! Instead, follow the instructions blindly. Upon inspecting the cookies set by this mission, for which I recommend the Firefox plugin Add N Edit Cookies, we find two of them:

username=sam
password=jillisdead

We are asked for the username. I tried a lot of methods on this one. I used the username “sam”, and I changed the value of the “username” cookie to my username. No matter what I tried, I could not solve it. So I read the mission description again. Mr. Deitry “decrypted it from ASCII encryption, and for you to login you need to encrypt it”.

For some reason, the value of the cookie set needs to be changed, regardless of who was logging in! Please disregard that this mission has no connection whatsoever to reality. What sane login system would require such actions from its users?

What is meant by “ASCII encryption” is the corresponding, binary ASCII values for each character. This would be the same as “Unicode encryption”, since the first 128 characters are the same for both ASCII and Unicode. To find what “sam” is when ASCII encrypted, google for things like [ascii to binary]. When you have found that, edit the “username” cookie to the encrypted value, e.g. 101010101010101010101010. When that has been done, you can login with the previous username.

To bypass the next field, you must only remember that the mission text talked about an SQL injection. First, check what error message you get when putting an apostrophe in the field.

Congratulations! The server-side check for successful SQL injections isn too advanced.

Failure to Install GD with CPAN: LDS/GD-2.35.tar.gz

I decided to install the GD image library for Perl on my working station, and as usual, using CPAN. However, after running install GD, I was faced with an error.

make: *** [GD.o] Error 1
  LDS/GD-2.35.tar.gz
  /usr/bin/make -- NOT OK
Running make test
  Can't test without successful make
Running make install
  Make had returned bad status, install seems impossible
Failed during this command:
 LDS/GD-2.35.tar.gz                           : make NO

Unable to find the cause, I turned to apt-get, which installed GD without any problems.

$ sudo apt-cache search libgd perl 
libgd-gd2-perl - Perl module wrapper for libgd - gd2 variant
libgd-graph-perl - Graph Plotting Module for Perl 5
libgd-text-perl - Text utilities for use with GD
ruby1.8 - Interpreter of object-oriented scripting language Ruby 1.8
calamaris - log analyzer for Squid or Oops proxy log files
libgd-barcode-perl - Library to create barcode images (GD::Barcode)
libgd-gd1-noxpm-perl - Perl module wrapper for libgd (old version against GD 1.8.x)
libgd-gd1-perl - Perl module wrapper for libgd (old version against GD 1.8.x)
libgd-gd2-noxpm-perl - Perl module wrapper for libgd - gd2 variant without XPM support
libgd-graph3d-perl - Create 3D Graphs with GD and GD::Graph
libgd-perl - Perl module wrapper for libgd
libgd-securityimage-perl - Security image (captcha) generator.
libgdk-pixbuf-perl - Perl module for the gdkpixbuf library
$ sudo apt-get install libgd-perl

Done!

HTS Realistic 5: Find the Hidden Hash

Damn Telemarketers!: Telemarketers are invading peoples privacy and peace and quiet. Get the password for the administrative section of the site to delete their database and return the privacy of their victims!

Realistic mission 5 of Hack This Site is quite fun, since it involves several vulnerabilities. You are supposed to clear a spammer’s database.

From: spiffomatic64

Message: Yo! This is Spiffomatic64 from Hackthissite.org! I’m a bit of a hacker myself as you can see, but I recently came upon a problem I couldn’t resolve…..
Lately I’ve been getting calls day and night from the telemarketing place. I’ve gone to their website and hacked it once deleting all of their phone numbers so they wouldn’t call me anymore. That was a temporary fix but they put their database back up, this time with an encrypted password. When I hacked them I noticed everything they used was 10 years out of date and the new password seems to be a ‘message digest’. I have done some research and I think it could be something like a co called hash value. I think you could somehow reverse engineer it or brute force it. I also think it would be a good idea to look around the server for anything that may help you.

Don’t just skim that through; read everything that Spiffomatic has to say. It’s quite helpful. Now, for their site. As you’ve probably seen, it consists of four visible sections: Home, News, Database and Contact.

The Home page contains nothing but an image and few email addresses, and the Contact page is equally useless. Don’t forget to check the source anyway, though, just to be sure. The Database page has nothing but a password input field. Inputting anything just gives you a “invalid password” message. Since entering “\”, “‘” and “”" characters still gives you the same message, we can assume that this field is not vulnerable to SQL injections.

We can’t find any vulnerability from the News page, either. However, the news items contain valuable information. We find that the administrator’s girlfriend’s name is Haley, which invites us to try that name as a password. Unfortunately, it didn’t work. We are also told something about “zapp”, which I have no idea of what it is. Next, we are told that they had some problems with Google:

Google was grabbing links it shouldn’t be so I have taken extra precautions.

Now, how do you take extra precautions when search engines are grabbing links that they shouldn’t? Well, you edit robots.txt to disallow it. Let’s take a look at the robots.txt of Compu-Global-Hyper-Mega-Net: http://www.hackthissite.org/missions/realistic/5/robots.txt.

Disallow: /lib/
Disallow: /secret/

Nice to know. Check those folders out, and you will find that directory listing is not disabled. Begin with secret/, since it seems most interesting. There are two files: admin.php and admin.bak.php. The prior is the script that validates passwords, and the latter seems to be a backup of the prior. However, when we access it, we get:

error matching hash 3184342944a094dd5dbe6fccaeb8dc96

Note that the specific hash might be different for you. As Spiffomatic64 said, this is a message digest (MD). Probably, it’s the message digest of the password that you are going to enter. But how are we supposed to know the algorithm of the hashing function? Remember the other directory disallowed from robots.txt? Let’s check lib/.

There is only one file here–”hash”. The hashing algorithm, perhaps? Download the file and open it in your favourite text-editor. Uh-oh. A lot of bogus characters, followed by:

Error: MDupdate MD already done.
Error: MDupdate called with illegal count value %d.
3.4.4 [FreeBSD] 20050518
MIC

In most cases when you encounter such a file, using a hex editor lets you read parts of it. There are many, for example XVI32 for Windows and hexedit for Linux. Now, look for something that you recognize. You will probably find this part in the file:

do_global_ctors_aux
/usr/src/lib/csu/i386-elf/crtn.S
md4.c
MDblock
md4driver.c

Which reveals that the encryption algorithm used is MD4. Use any MD4 collision finder to crack the hash. I’ve written a simple MD4 collision finder in perl, which you can use. If you don’t happen to like Perl, there is a lot of free tools available out there, including online reverse-lookup databases.

Going back to the “Database” page and entering the password completes the challenge.

HTS Realistic 4: UNION ALL the Products

Fischer’s Animal Products: A company slaughtering animals and turning their skin into overpriced products sold to rich bastards! Help animal rights activists increase political awareness by hacking their mailing list.

So I finally got around to write a walkthrough/guide for Hack This Site realistic mission 4. Your objective is to get the email addresses of the subscribers to the news letter of Fischer’s Animal Products.

From: SaveTheWhales

Message: Hello, I was referred to you by a friend who says you know how to hack into computers and web sites - well I was wondering if you could help me out here. There’s this local store who is killing hundreds of animals a day exclusively for the purpose of selling jackets and purses etc out of their skin! I have been to their website and they have an email list for their customers. I was wondering if you could somehow hack in and send me every email address on that list? I want to send them a message letting them know of the murder they are wearing. Just reply to this message with a list of the email addresses. Please? Their website is at http://www.hackthissite.org/missions/realistic/4/. Thanks so much!!

Start by investigating every part of Fischer’s the site. There are essentially two parts which might be vulnerable. The most visible one is the email form. A clearly visible input-field, where you just add your email address and are given a “Email added successfully” message. As you’ve seen through other missions containing SQL injections, the first step is attempting to get out of the string. Try registering an email address containing apostrophes, both single and double.

Error inserting into table “email”! Email not valid! Please contact an administrator of Fischer’s.

Unsuccessful. However, we got an important piece of information: the table name is “email”.

Now for the other part of the website; the product lists. There are two product lists, “fur coats” and “alligator accessories” (how this would have anything with whales to do is beyond me). If you’ve been as observant as you should be, you’ve noticed that both are the same file–products.php–with the category ID as an argument.

What do we want to accomplish? If we wanted to select something else from that table, we could attempt to change the WHERE part of the SELECT statement by changing the category argument to something like “1 OR categpory = 2″ (which happens to give you both categories of products on one page). However, we want to add information from another table: the “email” table. This is were the MySQL command UNION comes in very handy. Using UNION, we can merge the results of two SELECT statements into one. For example, we could:

SELECT * FROM table1 UNION ALL SELECT * FROM table2;

The result would be getting all rows from table1 and all rows from table2. Note that this assumes that the number of columns in table1 and table2 are equal. If they are not, the command will not work. UNION ALL is used instead of simply UNION in order to preserve duplicate rows. It is good practice to use UNION ALL in order to avoid unexpected errors. Let’s assume that the initial query could be something like this:

SELECT * FROM products WHERE category = 1;

We also want the rows from the email table. Therefore, we’ll try looking for another category: 1 UNION ALL SELECT * FROM email, resulting in the following final query:

SELECT * FROM products WHERE category = 1 UNION ALL SELECT * FROM email;

Which is exactly what we want. However, this results in nothing of value. Remember the assumption made earlier when we UNIONed table1 and table2? They must be of the same number of columns. We can assume that “email” has fewer columns than “products” does, since the products table should be more advanced. Therefore, we add columns to the email table:

SELECT * FROM products WHERE category = 1 UNION ALL SELECT *, NULL FROM email;

NULL means nothing–it is just an empty column. This doesn’t work either, so we’ll have to keep adding NULLs until we get some results. It will finally work at three NULLs:

SELECT * FROM products WHERE category = 1 UNION ALL SELECT *, NULL, NULL, NULL FROM email;

Below the category 1 products, you can see ten broken images. Viewing the source-code, you will find that the sources of these are email addresses! Rearranging the column order will give you a more eligible format.

SELECT * FROM products WHERE category = 1 UNION ALL SELECT NULL, *, NULL, NULL FROM email;

Just copy the list and email it to SaveTheWhales!

HackQuest: JavaScript: Ok, finally it’s secure. Or?

Name: Ok, finally it’s secure. Or?
Place: London, UK
Target: MicroWorld building

This time its them. We want access to their fire alarm system.

Search for the form:

73
74
75
76
77
78
79
80
            <form name="LayoutBereich1FORM" action="" method=
            "post">
              <input id="Eingabefeld1" type="TEXT" name=
              "inputbox1" value="" size="30" maxlength="30">
              <input type="BUTTON" name="Schaltfl&auml;chen1"
              value="Enter Password" id="Schaltflaechen1"
              onclick="testEncode(this.form)">
            </form>

Eingabefeld1/inputbox1 is the only field. testEncode() is called onclick.

39
40
41
42
43
44
45
function testEncode(form) {
	var dater = new Date();
	Day = dater.getDate();
	dater = null;
	var Ret = encode (form.inputbox1.value, Day)
	location = Ret + ".html"
}

Now, the date seems to matter. Day is set using getDate(), which returns the current day of the month, from 1 to 31. In my current case, it is 17, since the date is the 17th of July.

Next, the variable Ret is set to encode( form.inputbox1.value, Day ). The first argument sent to encode() is the password, and the second argument has already been described. encode() is a function defined on the page.

47
48
49
50
51
52
53
54
55
56
57
58
59
function encode (OrigString, CipherVal) {
	Ref="0123456789abcdefghijklmnopqrstuvwxyz._~ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	CipherVal = parseInt(CipherVal)
	var Temp=""
	for (Count=0; Count < OrigString.length; Count++) {
		var TempChar = OrigString.substring (Count, Count+1)
		var Conv = cton(TempChar)
		var Cipher=Conv^CipherVal
		Cipher=ntoc(Cipher)
		Temp += Cipher
	}
	return (Temp)
}

The first line defines Ref as a long string. Next, CipherVal–the second argument, i.e. the day of the month–is changed from a string to an integer. A for loop runs one time for every character in OrigString, which is the password that you entered, incrementing Count each time.

In the loop, TempChar is set to the character at position Count of OrigString, similar to the substring() usage in the previous Jedi Mindtricks challenge. Next, Conv is set to cton(TempChar). The cton() function is set below encode():

61
62
63
function cton (Char) {
	return (Ref.indexOf(Char));
}

The indexOf() function returns the position of the first occurence of a string in another string. Here, the position of Char in Ref is returned. For example, if Char was “j”, 19 would be returned.

Line 54 contains ^, the bitwise XOR operator. To conduct a bitwise XOR, you compare each bit of two numbers. When the two are not eqal, that bit of the new number is 1. When they are not, it is set to 0. For example, 19^6=21:


10011=19
00110=6
10101=21

Cipher is set to Conv^CipherVal, and ntoc() is called with the result as an argument.

65
66
67
function ntoc (Val) {
	return (Ref.substring(Val, Val+1))
}

Just like the previous occurence of substring(), this returns the character from Ref at position Val, which is position Cipher. The result is appended to Temp, and after the return, Temp is returned, and testEncode sets the location to the returned string with the “.html” suffix.


Now, you should be coming to a sad realisation: the password cannot be figured out through only the source code. In fact, this has nothing to do with JavaScript at all. It’s just an incredibly stupid category for this challenge.

Instead, start looking at what is different from other challenges. You’ve probably noticed that the location does not follow the standard; the URL is http://www.hackquest.de/modules/HackQuest/hacking/274/octodron/274.php. What an Octodron is, I have no idea, and neither does Google. One of those racing tracks that is formed like an 8, making you return to where you started? A misspelt octodon? Anyway, this should catch your eye.

The next part is just about testing as you would for any vulnerability. After a while, you might find that there is a nice directory-listing at /modules/HackQuest/hacking/274/octodron. ClickThisHiddenFile.php? Yes, please.

HackQuest: JavaScript: Jedi Mindtricks

Name: Jedi mindtricks.
Place: Mexico City, Mexico
Target: Twilight Security Company

At least five major MSA agents came from here. Take them off the internet for good.

The source code is obfuscated, through URL-encoding it and then fixing it with JavaScript. Generalizing the code, we have:

1
2
3
m = '%3C%21...html%3E';
d = unescape(m);
document.write(d);

If we could only get hold of d, this challenge would be a lot easier. The formerly mentioned JavaScript injection comes in handy. However, trying to inject the intuitive javascript:alert(d) would end up with nothing but a hard-to-manage alert-box. Instead, we will put it on the page. Just using document.write(d) will result in the tags being interpreted by your browser. Therefore, we put it all inside a textarea.

javascript:document.write('<textarea>'+d+'</textarea>')

This will give you the whole source code inside a nice textarea field. Put your cursor in it, select everything with ctrl+A and then paste it into a text editor for an easy overview. As always, start by finding the form.

67
68
69
70
71
72
      <form name="LayoutBereich1FORM" action="" method="post">
        <input id="Eingabefeld1" type="TEXT" name="Eingabefeld1"
        value="" size="30" maxlength="30"> <input type="BUTTON"
        name="Schaltflächen1" value="Enter Password" id=
        "Schaltflaechen1" onclick="return PassConfirm()">
      </form>

Only one field this time, “Eingabefeld1″. Submitting calls PassConfirm().

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
function PassConfirm() {
 
  var y="alphabravocharliedeltax";
  var x="lidocaineadrenalineekel";
  var z="sidewinderamraamphoenix";
 
  var s = "";
  for (Count=0; Count < y.length; Count++) {
 
		var t1 = y.substring (Count, Count+1);
		var t2 = z.substring (Count, Count+1);
		var t3 = x.substring (Count, Count+1);
 
		if (t1 * t2 * t3 >= 5 || t3^t1 >= 3)
  	  s=s+t1;
		else {
	  	if (t3 == t2)
				 s=s+t3;
	  	if (t2 == t1)
				 s=s+t2;
	  	if (t1 == t3)
				 s=s+t3;
		}
  }
 
  var x=document.LayoutBereich1FORM.Eingabefeld1.value
  if (x==s) {
    y = s + ".php"
    window.open(y,"_self")
  } else {
    alert("Dooh, try again!")
  }
}

First, x, y and z are set to some strings. A for-loop then starts. It increments Count and is run from 0 until Count < y.length. y.length is the amount of characters in "alphabravocharliedeltax", which is 23.

In the for loop, the three variables t1, t2 and t3 are first initialised using the substring() function. substring() is a built-in JavaScript function that extracts a part of a string. In this case, it only takes one character, the one at position Count (remember that the first character is character 0).

The following condition check is just bogus. The product of strings (t1*t2*t3 or t3^t1) will never be of a numerical value, and thus only the else-block will be executed. What the else-block effectively does is that it appends the character to s if two of the three strings have the same character at that position With this information, we can go through x, y and z and find the password. The first one is at Count==1, where the x and z substrings are equal and thus "i" is added to s. The next is at Count==2, and the at Count==8. In my case, the final s was ideaeex.

Next s is checked to be equal to the password entered, and if it was right, the challenge is cleared.

HackQuest: JavaScript: What you mean its not THAT easy?

This challenge presents a more modern (and unnecessary) way of entering the code.

Name: What you mean its not THAT easy?
Place: Berlin, Germany
Target: MAD central

This german security agent needs some info uploaded, so they realize the MicroWorld threat.

It’s a little more difficult to find the form now, but that’s still were we should start. Searching the source code for “form” reveals that everything is even printed through the JavaScript:

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
        <!-- Key-code script by Bart Jellema -->
    var usermulcode=10
 
    var code=0   // the entered code
    var mul=1    // the multiplied digits
    var digit=0  // number of digits entered so far
    var fails=0  // number of tries done
    function Clear_code()
    {
      document.codepad.thecode.value=''
      code=0     
      mul=1
      digit=0
    }
    function Enter_code(number)
    {
      code=code*10+number        
      mul=mul*number          
      document.codepad.thecode.value=code
      digit++   
 
      if (digit==4) 
      {
        if (mul==120)              
        {
          window.open (code+".php", "_self")
        }
        else
        {
          fails++          
          code=0     
          mul=1
          digit=0
          if (fails<3) {
              if(fails==1){
                  document.codepad.thecode.value="Try again"
              }
              if(fails==2){
                  document.codepad.thecode.value="Last time"
              }
          } else {
              document.codepad.thecode.value="Bye!"
          }
        }
      }
    }
 
        function keycodepad(mulcode)
        {
         usermulcode=mulcode
         document.write("<table><tr><td><form name=\"codepad\">");
         document.write("<input type=\"button\" value=\" 1 \" onClick=\"Enter_code(1)\">");
         document.write("<input type=\"button\" value=\" 2 \" onClick=\"Enter_code(2)\">");
         document.write("<input type=\"button\" value=\" 3 \" onClick=\"Enter_code(3)\">");
         document.write("<input type=\"button\" value=\" 4 \" onClick=\"Enter_code(4)\"><br>");
         document.write("<input type=\"button\" value=\" 5 \" onClick=\"Enter_code(5)\">");
         document.write("<input type=\"button\" value=\" 6 \" onClick=\"Enter_code(6)\">");
         document.write("<input type=\"button\" value=\" 7 \" onClick=\"Enter_code(7)\">");
         document.write("<input type=\"button\" value=\" 8 \" onClick=\"Enter_code(8)\"><br>");
         document.write("<input type=\"button\" value=\" 9 \" onClick=\"Enter_code(9)\">");
         document.write("<input type=\"button\" value=\" 0 \" onClick=\"Enter_code(0)\">");
         document.write("<input type=\"button\" value=\" C \" onClick=\"Clear_code()\"><br>");
         document.write("<input type=\"text\" name=\"thecode\" size=9 value=\"\"><br>");
         document.write("<\/form><\/table>");
        }
 
        <!-- Key-codescriptbyBartJellema-->

It is initialised at line 95 by the call keycodepad(24). Apparently, the variable “mulcode” is thus set to “24″, and after that “usermulcode”. Every click on a number calls Enter_code() with the number clicked as an argument. We will therefore dissect Enter_code(number), line by line.

First, code is multiplied by 10 and then the number is added to it. The effect of this is that number is appended to the right of the existing code. From the start, code equals 0 (line 27), and it is reset to that if C is pressed (from the Clear_code() function).

Next, mul is multiplied by the number pressed. mul starts off as 1 and is reset to 1 by Clear_code(). The line after that just updates the “display” to show the full code. After that, digit is incremented. As can be seen from line 29, digit is the number of digits that have been pressed (although this is reset by Clear_code() to 0).

Unless the following condition is true, Enter_code() ends here. The if statement checks whether digit==4, i.e. if four digits have been pressed. If mul==120, we have succeeded and are referred to another page. If not, the wrong-code handling sets in. It seems as if it is so easy as to find four digits between 1 and 9 where the product equals 120. However, it is not (what you mean it’s not THAT easy?). It seems that we have to find the correct combination, and through only the JavaScript, this is not possible. The usermulcode variable is of no use since it is not use in this script. We can find al combinations using a simple Perl script, though:

1
2
3
4
5
6
7
8
9
10
11
12
@n = 2..9;
foreach my $a (@n) {
  foreach my $b (@n) {
    foreach my $c (@n) {
      foreach my $d (@n) {
        if ( $a*$b*$c*$d == 120 ) {
          print $a, $b, $c, $d, "\n";
        }
      }
    }
  }
}

Since the URL is only dependant on the code (line 49), we can actually generate a nice list of possible solution URLs. Just replace line 7 in the perl script above with:

7
print 'http://www.hackquest.de/modules/HackQuest/hacking/824/', $a, $b, $c, $d, '.php', "\n";
http://www.hackquest.de/modules/HackQuest/hacking/824/2256.php
http://www.hackquest.de/modules/HackQuest/hacking/824/2265.php
http://www.hackquest.de/modules/HackQuest/hacking/824/2345.php
http://www.hackquest.de/modules/HackQuest/hacking/824/2354.php
http://www.hackquest.de/modules/HackQuest/hacking/824/2435.php
http://www.hackquest.de/modules/HackQuest/hacking/824/2453.php
http://www.hackquest.de/modules/HackQuest/hacking/824/2526.php
http://www.hackquest.de/modules/HackQuest/hacking/824/2534.php
http://www.hackquest.de/modules/HackQuest/hacking/824/2543.php
http://www.hackquest.de/modules/HackQuest/hacking/824/2562.php
http://www.hackquest.de/modules/HackQuest/hacking/824/2625.php
http://www.hackquest.de/modules/HackQuest/hacking/824/2652.php
http://www.hackquest.de/modules/HackQuest/hacking/824/3245.php
http://www.hackquest.de/modules/HackQuest/hacking/824/3254.php
http://www.hackquest.de/modules/HackQuest/hacking/824/3425.php
http://www.hackquest.de/modules/HackQuest/hacking/824/3452.php
http://www.hackquest.de/modules/HackQuest/hacking/824/3524.php
http://www.hackquest.de/modules/HackQuest/hacking/824/3542.php
http://www.hackquest.de/modules/HackQuest/hacking/824/4235.php
http://www.hackquest.de/modules/HackQuest/hacking/824/4253.php
http://www.hackquest.de/modules/HackQuest/hacking/824/4325.php
http://www.hackquest.de/modules/HackQuest/hacking/824/4352.php
http://www.hackquest.de/modules/HackQuest/hacking/824/4523.php
http://www.hackquest.de/modules/HackQuest/hacking/824/4532.php
http://www.hackquest.de/modules/HackQuest/hacking/824/5226.php
http://www.hackquest.de/modules/HackQuest/hacking/824/5234.php
http://www.hackquest.de/modules/HackQuest/hacking/824/5243.php
http://www.hackquest.de/modules/HackQuest/hacking/824/5262.php
http://www.hackquest.de/modules/HackQuest/hacking/824/5324.php
http://www.hackquest.de/modules/HackQuest/hacking/824/5342.php
http://www.hackquest.de/modules/HackQuest/hacking/824/5423.php
http://www.hackquest.de/modules/HackQuest/hacking/824/5432.php
http://www.hackquest.de/modules/HackQuest/hacking/824/5622.php
http://www.hackquest.de/modules/HackQuest/hacking/824/6225.php
http://www.hackquest.de/modules/HackQuest/hacking/824/6252.php
http://www.hackquest.de/modules/HackQuest/hacking/824/6522.php

Just start testing.

Earlier Posts »
FireStats iconAnvänder FireStats