banner

[Rule] Rules  [Home] Main Forum  [Portal] Portal  
[Members] Member Listing  [Statistics] Statistics  [Search] Search  [Reading Room] Reading Room 
[Register] Register  
[Login] Loginhttp  | https  ]
 
Forum Index Thảo luận hệ điều hành *nix Linux Execute-only binary vulnerability ?  XML
  [Discussion]   Linux Execute-only binary vulnerability ? 25/10/2009 15:36:51 (+0700) | #1 | 196651
[Avatar]
WinDak
Researcher

Joined: 27/01/2002 11:15:00
Messages: 223
Offline
[Profile] [PM]
Chào mọi người,

Mấy hôm nay ngồi chơi cái wargame ở io.smashthestack.org, tiện thể tìm hiểu thêm về Linux. Hôm nay mình phát hiện mọi điều khá "thú vị" và cũng hơi bất ngờ... nên share cùng mọi người.

Đầu tiên với account có quyền sysadmin mình tạo 1 file như thế này :
Code:
int main(int argc, char* argv[]) {
  int a = 1;
  int b = 1;
  char x = 'A';
  char y = 'B';
  return 0;
}

Compile : gcc -o test test.c

Sau đó mình tạo một user mới và copy file "test" này vào home folder của user này, chmod +s và remove read perm chgrp thành user. Sau khi làm xong thì nó trông như thế này :
Code:
-rws--x--x 1 windak user    6255 2009-10-25 02:50 test

Login thử vào bằng user : "user" và "cat test" -> permission denied,
thử gdb :
...(gdb) disass main
...No symbol table is loaded
thử execute ./test -> ok

Như mọi người biết, 1 khi một chương trình được execute thì nó sẽ được load vào memory, như vậy trên lí thuyết nếu ta execute cái binary này và read từ memory ra, ta sẽ có thể dumb được source của nó ==> READ được nó ?!!??

Mình nghi ngờ với khả năng này, do cũng chưa bao h liếc qua cái source kernel... Thế là test thử :

Vẫn là quyền của "user" mình tạo file này :
Code:
#include <stdio.h>                                      
#include <stdlib.h>                                     
#include <signal.h>                                     
#include <syscall.h>                                    
#include <sys/ptrace.h>                                 
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/user.h>
#include <unistd.h>
#include <errno.h>
int main(void) 
{                                                                                                                                                                                                          
        long long counter = 0;  /*  machine instruction counter */
        int wait_val;           /*  child's return value        */
        int pid;                /*  child's process id          */

        puts("Please wait");
        struct user_regs_struct regs;
        long ins;                    

        switch (pid = fork()) {
        case -1:               
                perror("fork");
                break;         
        case 0: /*  child process starts        */
                ptrace(PTRACE_TRACEME, 0, 0, 0);
                
                execl("/home/user/test", "test", NULL);
                
                break;
                /*  child process ends  */
        default:/*  parent process starts       */
                wait(&wait_val);
                /*
                 *   parent waits for child to stop at next
                 *   instruction (execl())
                 */
                while (wait_val == 1407 ) {
                        counter++;
                        if (ptrace(PTRACE_SINGLESTEP, pid, 0, 0) != 0)
                                perror("ptrace");
                        if (ptrace(PTRACE_GETREGS,pid,0,®s)!=0){
                         // perror("ptrace");
                        }
                        else {
                                ins = ptrace(PTRACE_PEEKTEXT, pid,
                                 regs.eip, NULL);

                                printf("Instruction executed: %lx\n", ins);
                        }
                        wait(&wait_val);
                        /*   wait for next instruction to complete  */
                }
                /*
                 * continue to stop, wait and release until
                 * the child is finished; wait_val != 1407
                 * Low=0177L and High=05 (SIGTRAP)
                 */
        }
        printf("Number of machine instructions : %lld\n", counter);
        return 0;
}

code này mình chép từ đây : http://tldp.org/LDP/LG/issue81/sandeep.html có chỉnh sửa một chút
compile :
gcc -o ptrace ptrace.c

Đoạn code trên của mình thật ra chỉ làm mỗi công việc là debug cái file test sau khi nó được nhét vào memory và in ra nó đang execute đoạn mã nào.

Sau đấy mình run thử
user@windak-pc$ ./ptrace > see
windak@windak-pc$./ptrace > how

Đồng thời trên 1 terminal khác dưới quyền "windak" mình run :
Code:
gdb test
(gdb) disass main
Dump of assembler code for function main:
0x0804831c <main+0>:    push   %ebp
0x0804831d <main+1>:    mov    %esp,%ebp
....
0x08048338 <main+28>:   movl   $0x1,-0x4(%ebp)
0x0804833f <main+35>:   movl   $0x1,-0x8(%ebp)
0x08048346 <main+42>:   movb   $0x41,-0x9(%ebp)
0x0804834a <main+46>:   movb   $0x42,-0xa(%ebp)
0x0804834e <main+50>:   mov    $0x0,%eax
0x08048353 <main+55>:   leave
0x08048354 <main+56>:   ret
(gdb) x/20 0x0804831c
0x804831c <main>:       0x83e58955      0xe48318ec      0x0000b8f0      0xc0830000
0x804832c <main+16>:    0x0fc0830f      0xc104e8c1      0xc42904e0      0x01fc45c7
0x804833c <main+32>:    0xc7000000      0x0001f845      0x45c60000      0x45c641f7
0x804834c <main+48>:    0x00b842f6      0xc9000000      0x909090c3      0x90909090
0x804835c:      0x90909090      0x5de58955      0x26748dc3      0x27bc8d00


Và thật ngạc nhiên... mình cũng tìm được đoạn code sau trong cả see và how :
Code:
Instruction executed: 83e58955
Instruction executed: ec83e589
Instruction executed: 8318ec83
Instruction executed: b8f0e483
Instruction executed: b8
Instruction executed: 830fc083
Instruction executed: c10fc083
Instruction executed: c104e8c1
Instruction executed: 2904e0c1
Instruction executed: 45c7c429
Instruction executed: 1fc45c7
Instruction executed: 1f845c7
Instruction executed: 41f745c6
Instruction executed: 42f645c6
Instruction executed: b8
Instruction executed: 9090c3c9
Instruction executed: 909090c3


Như vậy có thât sự đã "READ" được nó ?!? .. Liệu đây có phải là một bug của Linux kernel hay mình đang mơ ngủ =,,= nhầm lẫn chỗ nào đó....

Đây là thông số máy của mình
Code:
$ uname -a
Linux windak-pc 2.6.28-11-generic #42-Ubuntu SMP Fri Apr 17 01:57:59 UTC 2009 i686 GNU/Linux
$ gcc -v
Reading specs from /usr/lib/gcc/i486-linux-gnu/3.4.6/specs
Configured with: ../src/configure -v --enable-languages=c,c++,f77,pascal --prefix=/usr --libexecdir=/usr/lib --with-gxx-include-dir=/usr/include/c++/3.4 --enable-shared --with-system-zlib --enable-nls --without-included-gettext --program-suffix=-3.4 --enable-__cxa_atexit --enable-clocale=gnu --enable-libstdcxx-debug --with-tune=pentium4 i486-linux-gnu
Thread model: posix
gcc version 3.4.6 (Ubuntu 3.4.6-1ubuntu2)


Giờ đi ngủ, hi vọng mai tỉnh táo sẽ xem xét lại lần nữa. Mọi người xem cùng nhé.
wd.
-- w~ --
[Up] [Print Copy]
  [Discussion]   Linux Execute-only binary vulnerability ? 27/10/2009 03:17:20 (+0700) | #2 | 196750
StarGhost
Elite Member

[Minus]    0    [Plus]
Joined: 29/03/2005 20:34:22
Messages: 662
Location: The Queen
Offline
[Profile] [PM]
Bạn không mơ ngủ, và đây cũng không phải là bug của Linux. Linux cho phép cái này để phục vụ debugging. GDB thông báo "Permission denied" là vì nó tiến hành open() cái executable trước khi ptrace() nên bị denied, chứ không phải là không trace được.

Tuy nhiên, bạn chỉ có thể đọc được binary của executable này và các file bạn có read permission. Ngoài ra thì không còn gì khác. Hơn nữa, bạn cũng phải tốn khá nhiều công sức mới recover được chính xác cái binary đó, chỉ dựa vào việc peek qua ptrace.
Mind your thought.
[Up] [Print Copy]
  [Discussion]   Linux Execute-only binary vulnerability ? 27/10/2009 05:33:58 (+0700) | #3 | 196761
[Avatar]
WinDak
Researcher

Joined: 27/01/2002 11:15:00
Messages: 223
Offline
[Profile] [PM]
smilie Hi StarGhost,
Mình cũng không nghĩ cái này là bug của Linux mà là do design, chỉ càm thấy nó hơi nonsense và unrational một tí vì vẫn leak được sau khi mà loại bỏ cái read permission đi.

Từ đó vẫn còn thắc mắc trong đầu lý do nào phần code/data segment của nó trong memory lại không được bảo vệ ? Liệu có phải là do khó khăn trong design hay là sự bất cẩn ?
-- w~ --
[Up] [Print Copy]
  [Discussion]   Linux Execute-only binary vulnerability ? 28/10/2009 12:05:29 (+0700) | #4 | 196828
[Avatar]
gamma95
Researcher

Joined: 20/05/2003 07:15:41
Messages: 1377
Location: aaa&quot;&gt;
Offline
[Profile] [PM] [ICQ]

WinDak wrote:
smilie Hi StarGhost,
Mình cũng không nghĩ cái này là bug của Linux mà là do design, chỉ càm thấy nó hơi nonsense và unrational một tí vì vẫn leak được sau khi mà loại bỏ cái read permission đi.

Từ đó vẫn còn thắc mắc trong đầu lý do nào phần code/data segment của nó trong memory lại không được bảo vệ ? Liệu có phải là do khó khăn trong design hay là sự bất cẩn ?
 

Mình nghĩ do thằng ptrace thôi
Cánh chym không mỏi
lol
[Up] [Print Copy]
  [Discussion]   Linux Execute-only binary vulnerability ? 28/10/2009 22:26:20 (+0700) | #5 | 196853
lamer
Elite Member

[Minus]    0    [Plus]
Joined: 26/02/2008 13:28:49
Messages: 215
Offline
[Profile] [PM]
Quyền truy cập tập tin khác với quyền truy cập bộ nhớ.
[Up] [Print Copy]
  [Discussion]   Linux Execute-only binary vulnerability ? 29/10/2009 00:07:14 (+0700) | #6 | 196887
[Avatar]
WinDak
Researcher

Joined: 27/01/2002 11:15:00
Messages: 223
Offline
[Profile] [PM]
Hi anh lamer,
smilie vậy có phải là không hợp lý không ? Cho dù có sự khác biệt về 2 quyền, vẫn tốt hơn nếu như ta block quyền access memory nếu như không có quyền access tập tin ?
Giải sử mình có 1 tập tin chỉ muốn người khác execute thôi, không muốn bị xem trộm các thông tin bên trong => (datastructure, giải thuật v.v.. ) impossible ?
Nếu có cách nào như vậy xin chỉ dẫn ^^.


Mình nghĩ do thằng ptrace thôi
 

@gamma : rất có thể là khả năng này, ptrace là kernel function như vậy nghĩa là người develop nó không check quyền của user đang execute ? nếu có thời gian tớ sẽ ngó qua thử cái này.

Một cái nữa mình đã thử là thử fopen(/etc/shadow) khi đang ptrace thì bị block ngay tại trận, như vậy ptrace không care đến cái SUID mà mình đã set.

Kết luận đến đây: Nếu có những thông tin private, cách tốt nhất là tạo file riêng và set permission cho nó, không nên để trong file binary.

wd.
-- w~ --
[Up] [Print Copy]
  [Discussion]   Linux Execute-only binary vulnerability ? 29/10/2009 01:50:55 (+0700) | #7 | 196899
StarGhost
Elite Member

[Minus]    0    [Plus]
Joined: 29/03/2005 20:34:22
Messages: 662
Location: The Queen
Offline
[Profile] [PM]

WinDak wrote:
Một cái nữa mình đã thử là thử fopen(/etc/shadow) khi đang ptrace thì bị block ngay tại trận, như vậy ptrace không care đến cái SUID mà mình đã set. 

Không hiểu câu này của bạn. Bạn cơ bản không thể ptrace() được process có suid hoặc sgid, trừ phi process của bạn có euid là root. Một ví dụ điển hình là khi dùng gdb để debug suid/sgid programs.

Nếu bạn muốn dấu algorithm này kia thì mình có một cách này. Đầu tiên bạn viết program của bạn như bình thường. Sau đó set permission cho nó, ví dụ 700, trong đó owner là bạn. Sau đó bạn viết một suid program khác gọi cái program này (dùng execve()).
Mind your thought.
[Up] [Print Copy]
  [Discussion]   Linux Execute-only binary vulnerability ? 29/10/2009 02:00:03 (+0700) | #8 | 196900
[Avatar]
WinDak
Researcher

Joined: 27/01/2002 11:15:00
Messages: 223
Offline
[Profile] [PM]

StarGhost wrote:

WinDak wrote:
Một cái nữa mình đã thử là thử fopen(/etc/shadow) khi đang ptrace thì bị block ngay tại trận, như vậy ptrace không care đến cái SUID mà mình đã set. 

Không hiểu câu này của bạn. Bạn cơ bản không thể ptrace() được process có suid hoặc sgid, trừ phi process của bạn có euid là root. Một ví dụ điển hình là khi dùng gdb để debug suid/sgid programs.
 


Không phải không thể, như bạn xem kỹ bài ở trên mình vẫn có thể ptrace được SUID program, trong khi ptrace của tớ euid là "user". Vấn đề là khi đó thì euid mình vẫn chỉ là euid của ptrace chứ không được copy từ SUID của process child.

StarGhost wrote:

Nếu bạn muốn dấu algorithm này kia thì mình có một cách này. Đầu tiên bạn viết program của bạn như bình thường. Sau đó set permission cho nó, ví dụ 700, trong đó owner là bạn. Sau đó bạn viết một suid program khác gọi cái program này (dùng execve()). 

Theo lý thuyết đây chắc là 1 cách smilie. Mình sẽ thử nghiệm

Thanks.
wd.
-- w~ --
[Up] [Print Copy]
  [Discussion]   Linux Execute-only binary vulnerability ? 29/10/2009 02:53:09 (+0700) | #9 | 196911
StarGhost
Elite Member

[Minus]    0    [Plus]
Joined: 29/03/2005 20:34:22
Messages: 662
Location: The Queen
Offline
[Profile] [PM]

WinDak wrote:
Không phải không thể, như bạn xem kỹ bài ở trên mình vẫn có thể ptrace được SUID program, trong khi ptrace của tớ euid là "user". Vấn đề là khi đó thì euid mình vẫn chỉ là euid của ptrace chứ không được copy từ SUID của process child. 

Như vậy thì có gì mâu thuẫn? Nếu bạn gọi ptrace() trước, thì process sẽ không có suid/sgid. Nếu process đã có suid/sgid rồi, thì bạn không thể ptrace() được nữa. Đây là nguyên tắc security cho ptrace().
Mind your thought.
[Up] [Print Copy]
  [Discussion]   Linux Execute-only binary vulnerability ? 29/10/2009 03:07:16 (+0700) | #10 | 196913
[Avatar]
WinDak
Researcher

Joined: 27/01/2002 11:15:00
Messages: 223
Offline
[Profile] [PM]

StarGhost wrote:

WinDak wrote:
Không phải không thể, như bạn xem kỹ bài ở trên mình vẫn có thể ptrace được SUID program, trong khi ptrace của tớ euid là "user". Vấn đề là khi đó thì euid mình vẫn chỉ là euid của ptrace chứ không được copy từ SUID của process child. 

Như vậy thì có gì mâu thuẫn? Nếu bạn gọi ptrace() trước, thì process sẽ không có suid/sgid. Nếu process đã có suid/sgid rồi, thì bạn không thể ptrace() được nữa. Đây là nguyên tắc security cho ptrace(). 


Có ai nói mâu thuẫn gì đâu smilie, vì chưa hiểu ý StarGhost là sau khi run thì mới ptrace, cái này mình chưa thử, nếu ptrace trước thì sẽ chạy được, như ở trên đã trình bày.

Câu hỏi ở đây là lí do gì ptrace vẫn có khả năng trace vào memory của process ? Nếu protect process memory đi trong trường hợp này thì sẽ hợp lí hơn.

Vừa search ra cái này http://www.quantumg.net/sudojump.php mọi người xem cùng chơi.

wd.



-- w~ --
[Up] [Print Copy]
  [Discussion]   Linux Execute-only binary vulnerability ? 29/10/2009 03:32:40 (+0700) | #11 | 196919
puffy
Member

[Minus]    0    [Plus]
Joined: 29/07/2009 17:23:58
Messages: 7
Offline
[Profile] [PM]
tui thấy chả có gì lạ ở đây hết. Ông hiểu nhầm nhiều thứ
- Cái suid program của ông tuy ông có suid bit, nhưng ông không call mấy cái seteuid để change effective id thì nó vẫn execute với euid là user invoke nó. Tui thí dụ
Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

int main(int argc, char **argv)
{
   int a = 1;
   int b = 1;
   char x = 'A';
   char y = 'B';
   int euid, uid;
   euid = geteuid();
   uid = getuid();
   printf("euid: %d\nuid: %d\n",euid,uid);
   sleep(100000);
   exit(EXIT_SUCCESS);
}


output:
Code:
root@bsd# ls -l /tmp/test
-rws--x--x  1 puffy  monkey  6704 Oct 28 14:09 /tmp/test*
root@bsd# /tmp/test
euid: 0
uid: 0
^C
root@bsd# su -l monkey
-bash-3.2$ /tmp/test
euid: 1000
uid: 1000
^C
-bash-3.2$ logout
root@bsd# su -l puffy
-bash-3.2$ /tmp/test
euid: 1002
uid: 1002
^C
-bash-3.2$


- Ông xác định mấy thứ sau: cái ptrace của ông khi ông invoke nó với user 'windak' thì nó có euid là gì ? Sau khi ptrace fork thì child process của ông có euid là gì. Child process của ptrace gọi execl() thì process image của nó được thay bởi test, tuy nhiên cái program test này của ông không thực sự change cái euid của nó, nên nó vẫn có euid là id của user 'windak'. Vậy có gì mà parent process k0 access đc memory của nó.
- Tương tự ông thử xác định xem khi ông invoke cái program ptrace kia với account là 'user' thì cuối cùng cái euid của program 'test' có được change thành id của windak k0, hay vẫn là id của 'user' ?
[Up] [Print Copy]
  [Discussion]   Linux Execute-only binary vulnerability ? 29/10/2009 04:04:24 (+0700) | #12 | 196922
[Avatar]
WinDak
Researcher

Joined: 27/01/2002 11:15:00
Messages: 223
Offline
[Profile] [PM]
Hi bác puffy,
Có thể mình sơ xuất trong chuyện seteuid, mình sẽ test lại như bác nói, để xem nếu nó seteuid thì có ptrace từ đầu được không và khi đó thì "test" sẽ có euid là j.

Chỉ confirm lại phát nữa là ở ví dụ trên mình chạy ptrace dưới quyền "user", mà "user" dĩ nhiên không có quyền read cái test, khi ptrace invoke vào "test", "test" cũng không có quyền của "windak"

Thanks.
wd.
-- w~ --
[Up] [Print Copy]
  [Discussion]   Linux Execute-only binary vulnerability ? 29/10/2009 05:43:20 (+0700) | #13 | 196927
StarGhost
Elite Member

[Minus]    0    [Plus]
Joined: 29/03/2005 20:34:22
Messages: 662
Location: The Queen
Offline
[Profile] [PM]
@puffy: cái vụ seteuid() của bạn mình không đồng ý nhé. Không biết bsd kernel hoạt động ra sao, chứ trong linux thì chả cần seteuid(), chỉ cần SUID bit được set trong file permission thi khi file đó được chạy, euid sẽ tự động được set luôn thành file owner.
Mind your thought.
[Up] [Print Copy]
  [Discussion]   Linux Execute-only binary vulnerability ? 29/10/2009 08:52:00 (+0700) | #14 | 196941
[Avatar]
WinDak
Researcher

Joined: 27/01/2002 11:15:00
Messages: 223
Offline
[Profile] [PM]

StarGhost wrote:
@puffy: cái vụ seteuid() của bạn mình không đồng ý nhé. Không biết bsd kernel hoạt động ra sao, chứ trong linux thì chả cần seteuid(), chỉ cần SUID bit được set trong file permission thi khi file đó được chạy, euid sẽ tự động được set luôn thành file owner. 


Confirm đúng như StarGhost nói khi chạy trên máy mình.

Cũng cám ơn bác puffy, nhờ vậy biết linux != bsd chỗ này, trước giờ tưởng như nhau hệch hệch smilie

Code:
cat test.c
int main(int argc, char* argv[]) {
  int a = 1;
  int b = 1;
  char x = 'A';
  char y = 'B';
  printf ("Euid : %d, ID: %d \n", geteuid(), getuid());
  return 0;
}
....
windak@windak-pc$./test
Euid : 1000, ID: 1000
....
user@windak-pc$./test
Euid : 1000, ID: 1001


Ngoài ra cách xử dụng wrap của StarGhost
Code:
int main(){
  execl("/home/user/test","test",0);
  return 0;
}

gcc -o wrap wrap.c
ls -al :
Code:
-rwx------ 1 windak windak    6582 2009-10-28 20:27 test
-rws--x--x 1 windak user    6368 2009-10-28 20:31 wrap


cũng rất hiệu quả smilie
Code:
user@windak-pc$./wrap
Euid : 1000, ID: 1001
user@windak-pc$./ptrace
Please wait...
Number of machine instructions : 115862
...
windak@windak-pc$./ptrace
Please wait...
Euid : 1000, ID: 1000
Number of machine instructions : 237642


Thanks các bác
wd.
-- w~ --
[Up] [Print Copy]
[digg] [delicious] [google] [yahoo] [technorati] [reddit] [stumbleupon]
Go to: 
 Users currently in here 
1 Anonymous

Powered by JForum - Extended by HVAOnline
 hvaonline.net  |  hvaforum.net  |  hvazone.net  |  hvanews.net  |  vnhacker.org
1999 - 2013 © v2012|0504|218|