BlackBox Level1 – Welcome to the GDB

Welcome.  This blog will be about the BlackBox wargame on the SmashTheStack Network. Today we will be starting off the wargame with Level1.  Since BlackBox is a more advanced wargame, basic ssh and linux experience will be assumed.  Also, the actual password for the next level will be replaced on this page with a string Y’s.  If you want to do the level, do it.

According to the BlackBox webpage, level1 can be accessed via username/password level1/level1 on blackbox.smashthestack.org port 2225.  Upon logging in a quick directory listing shows a SUID program for user level2 group level1, named login2.  This must be the program we’re going to exploit.  A quick run of the program gives the following

level1@blackbox:~$ ./login2
Username: level1
Password: level1
Invalid username or password
level1@blackbox:~$ ./login2
Username: level2
Password: level2
Invalid username or password

Now we know the program probably isn’t linked directly to /etc/passwd or /etc/shadow since level1/level1 wasn’t valid.  Additionally the simple attempt of level2/level2 didn’t work, so more digging is needed.  First to notice, no source code is available.  Thus, we’ll have to resort to other attempts to reverse engineer the program.  First we’ll start with determining the file type of the program with the file command:

level1@blackbox:~$ file login2
login2: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.4.1, statically linked, for GNU/Linux 2.4.1, not stripped

Now we know we have an executable.  Quick attack for static strings would be to run strings on the program and testing each result as a username/password.  This will result in n^2 attempts where n is the number of strings returned from the strings command.  Unfortunately, running strings and taking the number of lines (strings login2 | wc -l), we see that there are 2279 lines and with the n^2 algorithm that would be aprox 2*10^7652, or a number far to large to check.  IF we could test 1 million (1*10^6) login/pass combo’s per second, it would still take [(2*10^7652)/(1*10^6) ] seconds to test all of those combos (which is still 2.3*10^7641 DAYS, I don’t know if we have a term for how large that number is).  So, we need a better approach.

The approach we will take has to do with reverse engineering.  We will try to figure out specifically which string the program tests as the username and password.  To do this we will use the command line debugging tool gdb.  To load the program use the command “gdb <program to debug>”.  In our case, from the home directory, “gdb login2”.  From here the first two commands we need to know are the “run” command, which starts the loaded program, and the “disass” command which disassembles and shows the assembly code of a function or memory address.  Type “run” to test that the program runs correctly in gdb, then disassemble the main function to attempt to understand the program with the “disass main” command.  (For a gdb cheat sheet head on over to darkdust.net or google.)  Since main is a little long, I will assume you can follow along on your own screen.

One easy way to get an idea of what is happening in the assembly is to look at the call instructions.  These are where functions were called in the original program.  Our asm code has the following calls:

0x08048292 <main+24>: call 0x8072ec0 <_ZNSsC1Ev>
0x0804829d <main+35>: call 0x8072ec0 <_ZNSsC1Ev>
0x080482b1 <main+55>: call 0x806d8f0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
0x080482c4 <main+74>: call 0x806b2e0 <_ZSt7getlineIcSt11char_traitsIcESaIcEERSt13basic_istreamIT_T0_ES7_RSbIS4_S5_T1_E>
0x080482d8 <main+94>: call 0x806d8f0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
0x080482eb <main+113>: call 0x806b2e0 <_ZSt7getlineIcSt11char_traitsIcESaIcEERSt13basic_istreamIT_T0_ES7_RSbIS4_S5_T1_E>
0x080482fe <main+132>: call 0x80483ee <_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_EPKS3_>
0x08048317 <main+157>: call 0x80483ee <_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_EPKS3_>
0x08048343 <main+201>: call 0x806d8f0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
0x08048353 <main+217>: call 0x806bf10 <_ZNSolsEPFRSoS_E>
0x0804835f <main+229>: call 0x80b5ab0 <system>
0x08048375 <main+251>: call 0x806d8f0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>
0x08048385 <main+267>: call 0x806bf10 <_ZNSolsEPFRSoS_E>
0x08048390 <main+278>: call 0x8074e40 <_ZNSsD1Ev>
0x080483a3 <main+297>: call 0x8074e40 <_ZNSsD1Ev>
0x080483b3 <main+313>: call 0x8074e40 <_ZNSsD1Ev>
0x080483ce <main+340>: call 0x8074e40 <_ZNSsD1Ev>
0x080483dc <main+354>: call 0x80a5180 <_Unwind_Resume>

At this point we can google the mangled function names, such as <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>, and figure out which function it was in c, in this case it’s the printf function.  Additionally, <_ZSt7getlineIcSt11char_traitsIcESaIcEERSt13basic_istreamIT_T0_ES7_RSbIS4_S5_T1_E> is get line from user and <_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_EPKS3_> is string compare!

Great!  Now, knowing what we do we can assume the first set of print/getline get’s the username and the second set of print/getline get’s the password.  We also then see two string compares, one at main+132 and one at main+157.  First we’ll look at the username, then we’ll do the password.

0x080482a2 <main+40>: movl $0x80ffe48,0x4(%esp)
0x080482aa <main+48>: movl $0x8130f60,(%esp)
0x080482b1 <main+55>: call 0x806d8f0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc>

So what is happening here?  Well, when a function is called, it’s parameters are often put on the stack.  So in the first case of the printf function, two parameters are moved in, both are memory addresses, the first of a string and the second of an int.  We see the use of printf(string, stringlen);.  If we want to examine memory in gdb we use the “x” command.  The usage we will use is “x/1s 0x080ffe48”.  This means examine one string at memory 0x080ffe48 (the memory address passed as a string to printf).  We get the following:

(gdb) x/1s 0x080ffe48
0x80ffe48 <_IO_stdin_used+4>: “Username: “

Just what we expected!  The first string printed by the program was “Username: “, and that is what we have found through reverse engineering the assembly.  Now for the input.

0x080482b6 <main+60>: lea 0xfffffff4(%ebp),%eax
0x080482b9 <main+63>: mov %eax,0x4(%esp)
0x080482bd <main+67>: movl $0x8130ec0,(%esp)
0x080482c4 <main+74>: call 0x806b2e0 <_ZSt7getlineIcSt11char_traitsIcESaIcEERSt13basic_istreamIT_T0_ES7_RSbIS4_S5_T1_E>

Now what is happening here is only slightly more involved due to the lea command.  But what is happening is lea is loading the address of a variable declared in the program (such as char inputUserName[128];) and putting it on the stack as the first parameter.  The second movl command is just supplying another memory address, in this case a number, the length of the array.  This is fine and dandy, but let’s move on to the string compare for username:

0x080482f0 <main+118>: movl $0x80ffe5e,0x4(%esp)
0x080482f8 <main+126>: lea 0xfffffff4(%ebp),%eax
0x080482fb <main+129>: mov %eax,(%esp)
0x080482fe <main+132>: call 0x80483ee <_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_EPKS3_>

We know string comparing needs two strings strcmp(s1, s2) and returns a value.  We see the setup here, movl $0x80ffe5e,0x4(%esp) loads in one of the strings.  So let’s examine that memory value, looking for 1 string

(gdb) x/1s 0x080ffe5e
0x80ffe5e <_IO_stdin_used+26>: “level2”

Well what do you know, a string.  Looks like this is the user name.  Can double check by examining the other value loaded in but you can see the way it is referenced (lea from ebp) that it’s a variable from within the C program, the same one getline used for getting user input.  Alright!  We have the username, now onto the password!  It’s all the same for the password:

0x08048309 <main+143>: movl $0x80ffe65,0x4(%esp)
0x08048311 <main+151>: lea 0xfffffff0(%ebp),%eax
0x08048314 <main+154>: mov %eax,(%esp)
0x08048317 <main+157>: call 0x80483ee <_ZSteqIcSt11char_traitsIcESaIcEEbRKSbIT_T0_T1_EPKS3_>

(gdb) x/1s 0x080ffe65
0x80ffe65 <_IO_stdin_used+33>: “YYYYYYYY”

And there we have it.  Run the program (from the shell, not gdb, otherwise your privileges won’t be escalated) and use the username/password we found above.

level1@blackbox:~$ ./login2
Username: level2
Password: YYYYYYYY
Welcome, level 2!
sh-3.1$ whoami
level2

So that long assembly primer was BlackBox Level1 from SmashTheStack.org.  Assembly is extremely important to know if you want to truly understand how computers are working, and understand security.  For security, strcmp is not a secure function.  You cannot use string compare without providing two strings and when your strings are in plain text, not only can your program see them, but so can the person controlling your program, and users are always in control of their system.  Remember, nothing to do with computers is magic, it’s all very well defined.  Every bit on a computer means nothing without context, but in the correct context all is understood.

This entry was posted in BlackBox, Smash The Stack, Wargames and tagged , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published.