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)