Quiz 1:
Password Guessing
If you can't get this one on your own, stop now.
Quiz 2:
HTTP Headers
You can use either GET or POST to complete this one.
The object is to spoof that you were referred from some other page, which you
have to guess. The key is simply adding
a “Referer:” in the POST/GET request that you send. (much crap delete from the server response)
telnet quiz.ngsec.biz 8080
POST
/game1/level2/validate_l33t.php?login=admin&password=ngsec HTTP/1.0
Referer: http://www.ngsec.com
Host: quiz.ngsec.biz
HTTP/1.1 200 OK
Date: Wed, 13 Aug 2003 16:28:46 GMT
Connection: close
Content-Type: text/html
***purged***
<p
class="txt"><b>CONGRATULATIONS!!! Authentication
Completed!</b></p>
<p class="txt">At this point
<b>you should update your score</b> filling this form.</p>
***purged***
Connection to host lost.
C:\paw>
NOTE: Make sure you capture the
provided link in the response in order to submit your username/password so that
the next quiz-link will be emailed to you.
Quiz 3:
PHP Variable passing
Follow the link provided to view the source of
validate_NGrules.php.
In the source, we can see that 2 variable are
checked and used to set the value of variable #3 ($state). We can just pass $state in the GET request
and bypass the
security checking.
http://quiz.ngsec.biz:8080/game1/level3/validate_NGrules.php?login=&password=&state=NGauthenticated
Quiz 4:
More PHP Variable jerking
In the provided link to the pseudo code, we see: $fd=@fopen($auth_file,"r");
This gives us an opportunity to specify the
$auth_file in a GET parameter.
Naturally, on a given system there are hundreds of files that we could
specify to fake our authentication.
But, since the game provides us a sample file of
"auth_file-format.txt" in the same directory, we can just use that. The auth_file-format.txt file contains
"user password" which we can now specify in our GET request, such as:
http://quiz.ngsec.biz:8080/game1/level4/validate_tryforfun.php?login=user&password=password&auth_file=auth_file-format.txt
(Naturally, we get the base URL from the
<FORM> fields in the HTML source.
This tells us where to submit our login request.)
Quiz 5:
PHP Injection playtime
The SQL statement is: SELECT * FROM $table WHERE
user='$login' AND pass='$password'"
I modify the SQL statement by using a password of 'test'
or pass!='' (since we can be sure the admin did not leave the password
blank). This translates into a URL of:
http://quiz2.ngsec.biz:8080/game1/level5/validate_achtung.php?login=admin&password=test%27+or+pass%21%3d%27%27%27
Which expands to the SQL statement below:
SELECT * FROM $table WHERE user='$login' AND
pass='$password' or pass!=''
Quiz 6:
Overflowing variables
This quiz presents us with 2 variables of interest, error_on_auth
and user. The error_on_auth is 1
byte, and user is allocated 128 bytes.
You need to think about how these values are stored in memory in order
to pass this quiz. (more later)
We can submit data for user and pass. If not NULL, then the value passed is copied
into memory allocated for user and pass. If we send 132 bytes for user, and nothing
for pass, then we overflow the space allocated for user (which is then filled
with arbitrary data), and begin to fill memory for the next variable error_on_auth. If we dump a value of zero at the right
location, then we can effectively change the pre-defined value of error_on_auth
from 1 to 0, which will make the program 'think' that we are authenticated ( if
error_on_auth=='0' ). By sending
132 bytes of arbitrary data followed by a zero to user, we successfully change
the value of error_on_auth and fool the program into authenticating us.
If you have basic math skillz, you are probably
wondering "why 132 bytes instead of 129?" The answer lies in the fact that memory is accessed using the
WORD size, which is 4 bytes. Even
though error_on_auth is CHAR which is 1 byte, it still occupies 4 bytes
in memory. The first 3 bytes can be
ignored, since the last byte is the only one that is relevant.
Just for fun, I have provided two possible
solutions, the first overflowing the user variable, the second taking
the longer route and overflowing the pass variable. Not that the none of the values are really
important, except for the final zero which overwrites the error_on_auth
CHAR value of 1.
http://quiz.ngsec.biz:8080/game1/level6/validate_replicant.cgi?login=123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.10&password=
http://quiz.ngsec.biz:8080/game1/level6/validate_replicant.cgi?login=&password=123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.1234567890
Quiz 7:
Abusing non-terminated STRNCPY()
The strcpy() function is the most common type
of buffer issue. To prevent security
issues, the use of strncpy() has become common. This function allows a programmer to copy a
value into another value while restricting the number of bytes copied. This quiz requires the user to know that
when strncpy() copies a number of bytes less that the size of the
buffer, it will append a NULL ( \0 ) onto the string. Likewise, if the number of bytes copied is equal or greater than
the size of the buffer, the function will not append the NULL ( \0 ) string
terminator since it simply would not fit in memory. In the "validate_net-dreamer.txt" source, we see that
the program has the REAL username and password stored in a static variable
called "correct".
Ideally, we would like to print this out to the browser and make life
super easy for us. This is quite easily
done using the technique described above.
We simply provide a password that is a full 128 bytes or longer,
preventing the strncpy() function from appending the string terminator
(\0). Then, the program is kind enough
to provide an error page (show_error()) which echos back our invalid
username and password. Since the
password string is not terminated with a \0,
the printf() function continues to print bytes until it finally
reaches a \0 which happens to be at the end of the correct[128] buffer
contents. This is because pass[128]
is located in memory directly next to correct[128].
To complete, simply enter any username (osama?) and
128 (or more) arbitrary characters for your password. The view the error page for the correct username/password.
http://quiz.ngsec.biz:8080/game1/level7/validate_net-dreamer.cgi?login=osama&password=12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
Either your username (osama) or password
(12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678Correct
user is beowulf with password athlon ) are incorrect. Please go back and try
again.
Quiz 8:
Authentication & enciphers
This one really stumped me for a bit, which made me
feel all the more silly when I finally figured it out. The sample authentication file was so obvious
that I cannot believe I didn't catch it immediately. The key lies in the fact that all the password and usernames are
of the same length, implying a simple encipherment algorithm. A quick crypto-analysis of the
username/password pairs reveals a pattern.
Each character of the password must be one half of the alphabet away
from the corresponding character in the username, plus its position in the
username string. Such that if the
username is "abc", then the password would be "npr". The login page restricts usernames to 6
characters, so I used "abcdef" with password of
"nprtvx". Apparently, any
username with a properly formatted password will work. The given username/password are correct, but
fail to meet the 6 character minimum that is required.
Quiz 9:
Disassembling executables
This quiz provides the user a Linux executable call "validate_onlyforyoureyes." My first thought was to simply try and run "strings" and see what ASCII text was visible in the program. Good idea, but nothing worthwhile resulted. My next thought was that since I had a local executable, I could just write a PERL driver and brute force the password, but I was pretty sure there had to be a better way. The program is 4992 bytes in length, which seemed to make it fairly reasonable to try and reverse engineer.
I opened the program using "HEDIT.EXE" on
my Windows box. HEDIT, in case your
unaware, is a very bare bones utility for poking around in binary files. I love it.
Its fairly easy to locate the various key areas of the executable just
by quickly scrolling through the Hex and ASCII viewer. Again, I was unable to locate any clear text
usernames and passwords, so I assumed they must be somehow obfuscated within
the code. At location 0x608 through
0x6d9 I noticed what seemed to be a pattern of individual ASCII letters, each
separated by 7 bytes. Looking at the
bytes, I found a pattern. It appeared
that the first 3 bytes were an address or offset, followed by a WORD with the
least significant byte being ASCII.
After some tedious effort, I was able to produce the following chart:
STARTING @ BYTE 0x608-0x6d9
c6 85 88 Z (0x5a)
c6 85 89 g (0x67)
c6 85 8a a (0x61)
c6 85 8b l (0x6c)
c6 85 8c o (0x6f)
c6 85 8d p (0x70)
c6 85 8e a (0x61)
c6 85 8f n (0x6e)
c6 85 90 t (0x74)
c6 85 91 e (0x65)
c6 85 92 NULL (0x00)
c6 85 b8 Z (0x5a)
c6 85 b9 i (0x69)
c6 85 ba n (0x6e)
c6 85 bb c (0x63)
c6 85 bc o (0x6f)
c6 85 bd m (0x6d)
c6 85 be p (0x70)
c6 85 bf e (0x65)
c6 85 c0 t (0x74)
c6 85 c1 e (0x65)
c6 85 c2 n (0x6e)
c6 85 c3 c (0x63)
c6 85 c4 i (0x69)
c6 85 c5 a (0x61)
c6 85 c6 NULL (0x00)
c6 86 f0 M (0x4d)
c6 86 f1 o (0x6f)
c6 86 f2 D (0x44)
c6 85 f3 NULL (0x00)
It turns out that the first two, provide the
password and username. I am still mystified what the "MoD" is there
for, I will assume its a hidden shout-out to Phiber-Optic and the old
"Masters of Destruction" crew (?)
Anyone at NGSec care to comment?
FINAL NOTE: Does anyone know if the 0xc6 is a one-byte op-code for X86? That would make sense to me, but I haven’t bothered to look up what OP-code 0xc6 is…
UPDATE: Ok, 0xc6 is the opcode
for the “mov” instruction. So:
c6 85 88 Z (0x5a)
will translate to:
mov 0x8588,0x5a
Just wanted to clear that up for anyone (probably nobody) who is interested… =)
Quiz 10:
Haven’t attempted this one yet. Waiting until I have a few free and
uninterrupted hours.