αααααα αααΆααααααααΌαααΆαααααααααα»αααααΆα 2014 ααα»αααααααα»αααΎααααααα·ααα αααααααΆαααΆαααααααααΎ Habre α αΎαααΆαα·αααΆαααΎααααααΊααααααααα αααα»αα’αα‘α»ααααα αΆαααΆαααααα»αααααα α’αααΈααΆ ααα»ααααα₯α‘αΌαααααααα»αααΆαααααΎαααΆαα αααα»αααα ααααΈααααΆαα αααα»αααΆααα·αα’αααΈααΆααα»αααΆ ααα»αααααααα ααααΆααΆααΉαααΆααααααααααααααΆααααααΆααααΆααα

ααΆααΌαα
α’αααααααααααααααααα»αααααααα·α
α’αΆαααΎαααααΆαααααααΆαααααααα "αα½ααααα
αΌα" LD_PRELOAD.
1. ααΆαααααααΆαααααΈαααααΆααα’αααααααα·ααααΆαααΉαααΆααααα½ααα»αααΆα
αα αααα’αΆα αα αααααααΆαα ΠΏ α₯.
αααα αΆααααααΎαααΆαα½αα§ααΆα ααααα»ααΆαα
#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 ./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)
αααααΈαααα’αΆα αααααααα½αα’αΆαααααααΎαααα OS ααα»ααααααααΌαααααΆαα―αααΆααα ααΈααα libc.so. ααΆβααΊβααΆβαααααΆαααβαααβαααβαααααβααΌαβααΆαβα α βααΌααααααβααααααααβαα·αβαα»αααΆαβααΌαααααΆαβααΌα βααΆβ ααΆαααΎαα αα α, Malloc, printf αα αααα αααααα·ααααα»αα αααααα½ααααααα α αΌαβααααΎβα±ααβααααΆααβααΆβαααβ:
# 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. ααΆαααΊα αΆααααααΆαααααααα
αααααΉαααΈααΆαααααΆαααα αααααα’αΆα ααΎαααΆα ααΎαα ααααααΎααααα αααα»αααΆαα»α ααΆααααΌαααΆαα’αα»ααααα ααΆα αααΆααααΆααααΆαα·ααΈααα’αααα»αααΎααααΈααα±ααααΎαααΊαα»αααΆαα αααα»αααΊααα ααα»αααααααα»αα αΆααα’αΆααααααααΎαααααΎαααααΆαααααΎααα αααα»ααααααα’αααααααΎααααΆααα
αααααΆαααα αααααααααΆααααααΆααααΆαααααΎα αα·αααΆαααα·ααααααααα½αααααΉαααααΆααΌα
α’.α‘. α αΌαα αΆααααααΎαααΆαααα
ααΌα αααααΆααααααΆααααΆαααΎ α’αααα’αΆα αααααΆαααααααΆααααααααααΌααααα»ααααααααΎα’ααα 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, αααα·αα· ααΆααΎαα ααα»ααααααΆααα·α αααααΌα 5-10 ααΌα ααααΆααΊααααΌαααΆαααΎααααΈαααααααα½αααα
α’.α’. ααααααααα αα»ααααα
ααΆαααΎααΎαααΆαααααΎ getenv() ααΎααααΈααα½αααΆαααααα LD_PRELOADααα»ααααααααΆααα·ααΈ "ααααα·αααΆα" αααααααααααΎααααΈαα ααα α’ααααΈ- α’αααα ααΎαβααΉαβαα·αβααααΎβαα»αααΆαβααααα·αβαααααβαα ααα»ααααβααΉαβαααβαα βααΎβα’αΆαα ** ααα·ααααΆαααααααααΆαα»αα αααΆααα ααααααααα·ααααΆαα
#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 αα½α Hacker αααααααΌαααΆαααΆαα αααα»αα’αααα αα αΆααααα αΎα αααααΊαα½αααα’αΆα α’αΆαααΆ αα·ααα»αααΆαα»ααααααααα·ααααα·ααΆαααααΆαααΆαα½αα ααΆααΆααα·αααΆαα ααΆαααααααα½αα’αΆαααα αααα»αα’αααα αα αΆα ααΆα’αααααααΆ αα ααΆαααααααααααααααα·ααΈαα·αααα’ ααα»ααααααΎαααα’αΆα ααααααααααΆααααΆααααααα·αααΆαα·αααααΆααααΆααΎααααΆαααΌα ααααα ?
ααΎααααΈααααΎααΌα αααααΎαααααΌααααααΎααα»αααΆααααααααααΆαααααΆαααααα½αααααααΎαα αα βαααα»αβααΆ()αααααΎαααααΆααα αΆααααΆαααα‘αΎα 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) [-]
α’.α£. /proc/αααα½αα―α/
αααααΆαααΆαααΆααααα ααΆαα αα αΆααα·ααααααΆααααααα α»αααααααααα’αααα’αΆα αααααααααΆααααα½αααΆαααα LD_PRELOAD, ααααΆα /proc/. α αΌαα αΆααααααΎαααΆαα½αααΉαααΆαααΆααααααα /proc/{PID}/ααα·ααααΆα.
ααΆααα·αααΆααααααααααΆαααΆααααααααΆαα αααα·αααΎα ** ααα·ααααΆα ΠΈ /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 ΠΈ α’α·α.
α’.α€. αααααΎαααΈ 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) [-]
α’.α₯. Syscalls
ααΆα αΆααααΌα ααΆααΆαααααΊααΆααα’αα ααα»ααααααΎαααΉααα αααα½ααααα αΆα ααααα·αααΎααΎαααΉαααΆαααΆαα α αααααααααααααααΆαααα ααΊααα ααΆααΉαααααααααΎαααΆαααααΆααα αΆααααΆααααΌαα ααΆααΆααα·αααΆαα αααααααααΆαααΆααααααααΊα’αΆαααααααΎααααΆαααααααα (x86_64) αααααααΆααΆαα’αα»ααααααΆααΎααααΈααααΎαααΆαααΎα ld.so.preload.
#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) [+]
α αΎααααα αΆαααααΆααααααααααΆαα αααααααα ααααΈ αα½α'A:
ptrace ααΊααΆα§ααααααααα’αα»ααααΆαα±ααααααΎαααΆαααααΎααααΈαααααα αα·ααααααααααααααΎαααΆαααααααΎαααΆααα½ααααααααα ααΎα αα·αααααΆααααααΌααα·αααααα αα·αααΆαα α»ααααααααααααΆα ααΆααααααΆαα»αααΆααααααααΌαααΆαααααΎααΎααααΈαααααΎαα ααα»α ααααα αααα»ααααααα·ααΈααααΆααααα α»α αα·ααααα½ααα·αα·αααααΆαα α ααΆαααααααααα
ααααΎαααΆαααα’αΆα α αΆααααααΎαααΆαααΆααααααΆαα α ααΌαααααααααΌα fork(2) α αΎααααααΆααααααααΎαααΆαααΌαααααααα’αΆα ααααα·ααααα· PTRACE_TRACEME αααααΆααααααΆα (ααΆααααααΆ) αααααααα·ααααα· exec(3)α αααααΆααα·αααα ααααΎαααΆαααα’αΆα α αΆααααααΎαααααΆααααα α»αααααΎαααΆααααααΆαααααΆαααααααααΎ PTRACE_ATTACH α
αα αααααΆαααΆα ααααΎαααΆααα»ααΆααααααΆααααααααααΆααα½αααΆααααααΆ ααΎαααααΈααΆαααααΆαααααααΌαααΆααααα·αα’αΎααΎαααααα (ααααΈααΎααααααΊ SIGKILL αααααααΎαααΆαααΆααααααΆα) ααααΎαααΆαααααΉαααααΌαααΆαααΌαααααΉαα’αααΈαααα αΆααααααααΆαα α αααα αΆα (2) αααααΆααααΈαααααΆα’αΆα ααΎα αα·αααααααααααΉαααΆαααααααΎαααΆααα»ααΆα αα»ααααααΆα αΆααααααΎαα αααααΆααααααααΎαααΆαααα’αα»ααααΆαα±ααααΌαααααααααΎαααΆα αααα»αααααΈαααααα·αα’αΎααΎααΉααααααΆαααααΆαααααΎαα ααΆ α¬αααααΌααααααΆαααααααααααα½ααα·α)α
ααΌα αααα αααααααααΆαααΊααΎααααΈαααα½ααα·αα·αααααααΎαααΆα αααααααααααΆαα»ααααααΆαα α ααααααααααααααΈαα½αα α αΎαααααα·αααΎα αΆαααΆα α αααααααααααααα‘αΆααα ααΆαα»αααΆααααααα
#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
