Closed Hackerl closed 1 year ago
hello, thanks for your interest in this project. i'm sorry i havent gotten back to you sooner. i havent really had the time or will to take a look into all the issues you opened, but it looks like you spent quite a bit of effort into it :)
To answer this specific question, i dont remember, but it looks like dead code, i probably used it as a debug env var the child had access to - to differenciate program output while being launched normally versus being injected.
Thanks for your reply. I refactored based on your project. I separated the shellcode into a separate dynamic library. The process of ptrace is placed in a separate program, so that the standard library can be used for development, and the problems I raised here have been fixed. But currently only supports x64. I pass parameters directly through registers. The shellcode also has three parts. One part calls Malloc to allocate enough memory, which can reduce the probability of multi-threaded program crashes. The second part is the elf loader you write. The third part calls free to release the requested memory. Project: https://github.com/Hackerl/pangolin In addition, I implemented an interesting python injection tool with it: https://github.com/Hackerl/pyinject
My English is not good, these are from Google Translate, if my words are offensive, please forgive me.
@Hackerl 你好,看了你fork后修复的内存泄露,测试了下,内存泄露依旧存在
@Hackerl 你好,看了你fork后修复的内存泄露,测试了下,内存泄露依旧存在
你指的是重复进行注入,被注入的进程中发生内存泄露? 可以使用我重构的版本:https://github.com/Hackerl/pangolin 虽然在注入之后会申请一块内存作为栈,并且不会释放,这种场景用于创建新线程驻留在目标进程中,也适用于golang这种自己管理栈并且栈空间比较小的场景。 但只要不重复注入,就不会有多余的内存泄露。
@Hackerl 你好,看了你fork后修复的内存泄露,测试了下,内存泄露依旧存在
你指的是重复进行注入,被注入的进程中发生内存泄露?
是的,每次注入完成后,target进程的内存占用就会增长一点
可以使用我重构的版本:https://github.com/Hackerl/pangolin
我测试了下,是可以注入的,但是target在退出的时候有个Segmentation fault
[root@localhost bin]# ./target
> started.
...................> elf loader start
> target: /home/admin/code/pangolin/bin/inject
> mapping '/home/admin/code/pangolin/bin/inject' into memory at 0x1000000
> load segment addr 0x400000 len 0x1000 => 0x400000
> load segment addr 0x601db8 len 0x1000 => 0x601000
> max addr 0x1613000
> loading interp '/lib64/ld-linux-x86-64.so.2'
> mapping '/lib64/ld-linux-x86-64.so.2' into memory at 0x1613000
> load segment addr 0x1613000 len 0x29000 => 0x1613000
> load segment addr 0x183b560 len 0x2000 => 0x183b000
> max addr 0x184e000
> eop 0x1614080
> setting auxv
> set auxv[3] to 0x400040
> set auxv[4] to 0x38
> set auxv[5] to 0x9
> set auxv[9] to 0x400980
> set auxv[7] to 0x400000
> eop 0x1614080
> fake stack: 0x7ffa7a9dede0
> starting ...
# oh hai from pid 354481
# arg 0: /home/admin/code/pangolin/bin/inject
# arg 1: 1
# arg 2: 2 3
# env: MANMAP=1
# env: GS=0x0
# env: FS=0x7ffa7a9e2f40
# :)
# :)
# :)
# bye!
Segmentation fault (core dumped)
虽然在注入之后会申请一块内存作为栈,并且不会释放,这种场景用于创建新线程驻留在目标进程中,也适用于golang这种自己管理栈并且栈空间比较小的场景。 但只要不重复注入,就不会有多余的内存泄露。
如果在注入代码退出后有内存泄露,那么在生产环境上需要重复注入的场景就不适合了,我们之前使用criu的compel库进行过注入,是没有泄露的
@Hackerl 你好,看了你fork后修复的内存泄露,测试了下,内存泄露依旧存在
你指的是重复进行注入,被注入的进程中发生内存泄露?
是的,每次注入完成后,target进程的内存占用就会增长一点
可以使用我重构的版本:https://github.com/Hackerl/pangolin
我测试了下,是可以注入的,但是target在退出的时候有个Segmentation fault
[root@localhost bin]# ./target > started. ...................> elf loader start > target: /home/admin/code/pangolin/bin/inject > mapping '/home/admin/code/pangolin/bin/inject' into memory at 0x1000000 > load segment addr 0x400000 len 0x1000 => 0x400000 > load segment addr 0x601db8 len 0x1000 => 0x601000 > max addr 0x1613000 > loading interp '/lib64/ld-linux-x86-64.so.2' > mapping '/lib64/ld-linux-x86-64.so.2' into memory at 0x1613000 > load segment addr 0x1613000 len 0x29000 => 0x1613000 > load segment addr 0x183b560 len 0x2000 => 0x183b000 > max addr 0x184e000 > eop 0x1614080 > setting auxv > set auxv[3] to 0x400040 > set auxv[4] to 0x38 > set auxv[5] to 0x9 > set auxv[9] to 0x400980 > set auxv[7] to 0x400000 > eop 0x1614080 > fake stack: 0x7ffa7a9dede0 > starting ... # oh hai from pid 354481 # arg 0: /home/admin/code/pangolin/bin/inject # arg 1: 1 # arg 2: 2 3 # env: MANMAP=1 # env: GS=0x0 # env: FS=0x7ffa7a9e2f40 # :) # :) # :) # bye! Segmentation fault (core dumped)
虽然在注入之后会申请一块内存作为栈,并且不会释放,这种场景用于创建新线程驻留在目标进程中,也适用于golang这种自己管理栈并且栈空间比较小的场景。 但只要不重复注入,就不会有多余的内存泄露。
如果在注入代码退出后有内存泄露,那么在生产环境上需要重复注入的场景就不适合了,我们之前使用criu的compel库进行过注入,是没有泄露的
因为我的需求是注入之后驻留线程,所以肯定需要保留一块空间,为了避免重复注入,我设置了新线程名称"xxx",然后遍历进程的线程,根据/proc/pid/task/id/comm来判断是否存在线程"xxx",来判断是否已经注入。 另外能否将编译后的产出以及core dump发给我,我看看原因,根据我的使用体验来说,应该是比较稳定的。 如果你不需要驻留在进程内,可以参考commit,将"loader_main"函数还原,应该就不会有内存泄漏问题了。
void loader_main(void *ptr) {
LOG("elf loader start");
struct CLoaderArgs *loader_args = ptr;
elf_loader(loader_args);
__exit(0);
}
bin.tar.gz 我的系统是Centos8.3.2011,内核4.18,gcc 8.3.1
bin.tar.gz 我的系统是Centos8.3.2011,内核4.18,gcc 8.3.1
crash原因是你的gcc默认编译出来的产物是EXEC类型:
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400960
Start of program headers: 64 (bytes into file)
Start of section headers: 11616 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 30
Section header string table index: 29
EXEC类型的elf加载进内存的时候,地址是固定的,不会加上随机基地址。 所以target在运行时,代码段在0x400000,将inject注入进去后,由于inject也是EXEC类型,所以elf loader将其代码段加载到了0x400000,覆盖了原有的内存空间,导致crash。 要进行注入必须满足以下任意一点:
EXEC类型的elf加载进内存的时候,地址是固定的,不会加上随机基地址。 所以target在运行时,代码段在0x400000,将inject注入进去后,由于inject也是EXEC类型,所以elf loader将其代码段加载到了0x400000,覆盖了原有的内存空间,导致crash。 要进行注入必须满足以下任意一点:
- 目标程序DYN,注入程序EXEC
- 目标程序EXEC,注入程序DYN
感谢解答,使用g++ -fpie -pie -o inject inject.cpp
编译后问题解决,但是还是存在内存泄露的问题:
在用最新代码,即不修改"loader_main"函数的情况下,每次注入完成后,target的VIRT就会增长13732,并且mapping '/home/admin/code/pangolin/bin/inject' into memory at
的点每次都会增加
........................................................> elf loader start
> target: /home/admin/code/pangolin/bin/inject
> mapping '/home/admin/code/pangolin/bin/inject' into memory at 0x1000000
> load segment addr 0x1000000 len 0x1000 => 0x1000000
> load segment addr 0x1200d98 len 0x1000 => 0x1200000
> max addr 0x1212000
> loading interp '/lib64/ld-linux-x86-64.so.2'
> mapping '/lib64/ld-linux-x86-64.so.2' into memory at 0x1212000
> load segment addr 0x1212000 len 0x29000 => 0x1212000
> load segment addr 0x143a560 len 0x2000 => 0x143a000
> max addr 0x144d000
> eop 0x1213080
> setting auxv
> set auxv[3] to 0x1000040
> set auxv[4] to 0x38
> set auxv[5] to 0x9
> set auxv[9] to 0x1000880
> set auxv[7] to 0x1000000
> eop 0x1213080
> fake stack: 0x7facb3dd0de0
> starting ...
# oh hai from pid 384857
# bye!
...........> elf loader start
> target: /home/admin/code/pangolin/bin/inject
> mapping '/home/admin/code/pangolin/bin/inject' into memory at 0x2000000
> load segment addr 0x2000000 len 0x1000 => 0x2000000
> load segment addr 0x2200d98 len 0x1000 => 0x2200000
> max addr 0x2212000
> loading interp '/lib64/ld-linux-x86-64.so.2'
> mapping '/lib64/ld-linux-x86-64.so.2' into memory at 0x2212000
> load segment addr 0x2212000 len 0x29000 => 0x2212000
> load segment addr 0x243a560 len 0x2000 => 0x243a000
> max addr 0x244d000
> eop 0x2213080
> setting auxv
> set auxv[3] to 0x2000040
> set auxv[4] to 0x38
> set auxv[5] to 0x9
> set auxv[9] to 0x2000880
> set auxv[7] to 0x2000000
> eop 0x2213080
> fake stack: 0x7facb3d97de0
> starting ...
# oh hai from pid 384857
# bye!
EXEC类型的elf加载进内存的时候,地址是固定的,不会加上随机基地址。 所以target在运行时,代码段在0x400000,将inject注入进去后,由于inject也是EXEC类型,所以elf loader将其代码段加载到了0x400000,覆盖了原有的内存空间,导致crash。 要进行注入必须满足以下任意一点:
- 目标程序DYN,注入程序EXEC
- 目标程序EXEC,注入程序DYN
感谢解答,使用
g++ -fpie -pie -o inject inject.cpp
编译后问题解决,但是还是存在内存泄露的问题: 在用最新代码,即不修改"loader_main"函数的情况下,每次注入完成后,target的VIRT就会增长13732,并且mapping '/home/admin/code/pangolin/bin/inject' into memory at
的点每次都会增加........................................................> elf loader start > target: /home/admin/code/pangolin/bin/inject > mapping '/home/admin/code/pangolin/bin/inject' into memory at 0x1000000 > load segment addr 0x1000000 len 0x1000 => 0x1000000 > load segment addr 0x1200d98 len 0x1000 => 0x1200000 > max addr 0x1212000 > loading interp '/lib64/ld-linux-x86-64.so.2' > mapping '/lib64/ld-linux-x86-64.so.2' into memory at 0x1212000 > load segment addr 0x1212000 len 0x29000 => 0x1212000 > load segment addr 0x143a560 len 0x2000 => 0x143a000 > max addr 0x144d000 > eop 0x1213080 > setting auxv > set auxv[3] to 0x1000040 > set auxv[4] to 0x38 > set auxv[5] to 0x9 > set auxv[9] to 0x1000880 > set auxv[7] to 0x1000000 > eop 0x1213080 > fake stack: 0x7facb3dd0de0 > starting ... # oh hai from pid 384857 # bye! ...........> elf loader start > target: /home/admin/code/pangolin/bin/inject > mapping '/home/admin/code/pangolin/bin/inject' into memory at 0x2000000 > load segment addr 0x2000000 len 0x1000 => 0x2000000 > load segment addr 0x2200d98 len 0x1000 => 0x2200000 > max addr 0x2212000 > loading interp '/lib64/ld-linux-x86-64.so.2' > mapping '/lib64/ld-linux-x86-64.so.2' into memory at 0x2212000 > load segment addr 0x2212000 len 0x29000 => 0x2212000 > load segment addr 0x243a560 len 0x2000 => 0x243a000 > max addr 0x244d000 > eop 0x2213080 > setting auxv > set auxv[3] to 0x2000040 > set auxv[4] to 0x38 > set auxv[5] to 0x9 > set auxv[9] to 0x2000880 > set auxv[7] to 0x2000000 > eop 0x2213080 > fake stack: 0x7facb3d97de0 > starting ... # oh hai from pid 384857 # bye!
符合预期,可以用我说的遍历/proc避免重复注入
I want to know the purpose of this environment variable.