mandibule icon indicating copy to clipboard operation
mandibule copied to clipboard

program stuck at "starting ..."

Open Hackerl opened this issue 3 years ago • 6 comments

For my last issue: https://github.com/ixty/mandibule/issues/2 I commit the patch: https://github.com/Hackerl/mandibule/commit/92de629dee87e149481c10924d3db2a23280605f

unsigned long mandibule_beg(int aligned)
{
    if(!aligned)
        return (unsigned long)mandibule_beg;

    unsigned long align_size = (unsigned long)mandibule_beg % 0x1000;

    return (unsigned long)mandibule_beg - (align_size == 0 ? 0x1000 : align_size);
}

After successful compilation, it can run successfully, but the process is stuck. image I modified the source code to output detailed logs, and found that the program was stuck in a system call. stuck log:

./mandibule $(pwd)/toinject $(pidof target)
> syscall: 10
> syscall: 9
> syscall: 9
> syscall: 9
> syscall: 9
> syscall: 9
> syscall: 9
> syscall: 9
> syscall: 9
> syscall: 3
> syscall: 3
> syscall: 158
> syscall: 158
> syscall: 18446744073709551615
> syscall: 18446744073709551615
> syscall: 18446744073709551615
> syscall: 18446744073709551615
> syscall: 18446744073709551615
> syscall: 18446744073709551615
> syscall: 18446744073709551615
> syscall: 18446744073709551615

after syscall 158, the output of syscall will be messy, so I guess there is a problem with the system call 158. What's interesting is that I shortened the name of the injected program "toinject" a bit, and renamed it to "toinj" and it could run successfully. success log:

./mandibule $(pwd)/toinj $(pidof target)
> syscall: 10
> syscall: 9
> syscall: 9
> syscall: 9
> syscall: 9
> syscall: 9
> syscall: 9
> syscall: 9
> syscall: 9
> syscall: 3
> syscall: 3
> syscall: 158
> syscall: 158
> syscall: 10
> syscall: 10
> syscall: 10
> syscall: 10
> syscall: 10
> syscall: 10
> syscall: 11
> syscall: 11
> syscall: 39
> syscall: 39
> syscall: 5
> syscall: 5
> syscall: 12
> syscall: 12
> syscall: 12
> syscall: 12
> syscall: 1
> syscall: 1
> syscall: 1
> syscall: 1
> syscall: 1
> syscall: 1
> syscall: 35
> syscall: 35
> syscall: 1
> syscall: 1
> syscall: 35
> syscall: 35
> syscall: 1
> syscall: 1
> syscall: 35
> syscall: 35
> syscall: 1
> syscall: 1
> syscall: 231
> shellcode executed!
> restored memory & registers
> successfully injected shellcode into pid 15313

Can continue to run after the system call 158, I am going to debug further, I will add information here later.

Hackerl avatar Oct 31 '20 04:10 Hackerl

filename length >= 8 will trigger bug. image stuck: image

Hackerl avatar Oct 31 '20 09:10 Hackerl

Things are getting weird, I try to set the environment variable to output "ld.so" log. When i run "./mandibule ./toinject -e LD_DEBUG=all $(pidof target)", is works.

> started.
...> target pid: 22143
> arg[0]: ./toinject
> env[0]: LD_DEBUG=all
> args size: 64
> auxv len: 320
av[0]: ./toinject
env[0]: LD_DEBUG=all
> auto-detected manual mapping address 0x55820a000000
> mapping './toinject' into memory at 0x55820a000000
> reading elf file './toinject'
> loading elf at: 0x55820a000000
> seg[0] load: 0 addr 0x40 size 0x268
> seg[1] load: 0 addr 0x2a8 size 0x1c
> seg[2] load: 1 addr 0x0 size 0x680
> load segment addr 0x55820a000000 len 0x1000 => 0x55820a000000
> seg[3] load: 1 addr 0x1000 size 0x2bd
> load segment addr 0x55820a001000 len 0x1000 => 0x55820a001000
> seg[4] load: 1 addr 0x2000 size 0x158
> load segment addr 0x55820a002000 len 0x1000 => 0x55820a002000
> seg[5] load: 1 addr 0x3de8 size 0x278
> load segment addr 0x55820a003de8 len 0x1000 => 0x55820a003000
> seg[6] load: 0 addr 0x3df8 size 0x1e0
> seg[7] load: 0 addr 0x2c4 size 0x44
> seg[8] load: 0 addr 0x2038 size 0x34
> seg[9] load: 0 addr 0x0 size 0x0
> seg[10] load: 0 addr 0x3de8 size 0x218
> program base: 0x55820a000000
> max vaddr 0x55820a015000
> loading interp '/lib64/ld-linux-x86-64.so.2'
> reading elf file '/lib64/ld-linux-x86-64.so.2'
> loading elf at: 0x55820a015000
> seg[0] load: 1 addr 0x0 size 0xf08
> load segment addr 0x55820a015000 len 0x1000 => 0x55820a015000
> seg[1] load: 1 addr 0x1000 size 0x1db20
> load segment addr 0x55820a016000 len 0x1e000 => 0x55820a016000
> seg[2] load: 1 addr 0x1f000 size 0x73dc
> load segment addr 0x55820a034000 len 0x8000 => 0x55820a034000
> seg[3] load: 1 addr 0x27640 size 0x1b50
> load segment addr 0x55820a03c640 len 0x2000 => 0x55820a03c000
> seg[4] load: 0 addr 0x27e78 size 0x170
> seg[5] load: 0 addr 0x238 size 0x24
> seg[6] load: 0 addr 0x23620 size 0x6d4
> seg[7] load: 0 addr 0x0 size 0x0
> seg[8] load: 0 addr 0x27640 size 0x9c0
> program base: 0x55820a016000
> max vaddr 0x55820a04f000
> eop 0x55820a016090
> setting auxv
> set auxv[3] to 0x55820a000040
> set auxv[5] to 0xb
> set auxv[9] to 0x55820a001090
> set auxv[7] to 0x55820a000000
> eop 0x55820a016090
> starting ...

     22143:
     22143:     WARNING: Unsupported flag value(s) of 0x8000000 in DT_FLAGS_1.
     22143:
     22143:     file=libc.so.6 [0];  needed by ./toinject [0]
     22143:     find library=libc.so.6 [0]; searching
     22143:      search cache=/etc/ld.so.cache
     22143:       trying file=/lib/x86_64-linux-gnu/libc.so.6
     22143:
     22143:     file=libc.so.6 [0];  generating link map
     22143:       dynamic: 0x00007fcaf7f40b80  base: 0x00007fcaf7d86000   size: 0x00000000001c0800
     22143:         entry: 0x00007fcaf7daa1b0  phdr: 0x00007fcaf7d86040  phnum:                 12
     22143:
     22143:     checking for version `GLIBC_2.2.5' in file /lib/x86_64-linux-gnu/libc.so.6 [0] required by file ./toinject [0]
     22143:     checking for version `GLIBC_2.3' in file /lib64/ld-linux-x86-64.so.2 [0] required by file /lib/x86_64-linux-gnu/libc.so.6 [0]
     22143:     checking for version `GLIBC_PRIVATE' in file /lib64/ld-linux-x86-64.so.2 [0] required by file /lib/x86_64-linux-gnu/libc.so.6 [0]
     22143:
     22143:     Initial object scopes
     22143:     object=./toinject [0]
     22143:      scope 0: ./toinject /lib/x86_64-linux-gnu/libc.so.6 /lib64/ld-linux-x86-64.so.2
     22143:
     22143:     object=linux-vdso.so.1 [0]
     22143:      scope 0: ./toinject /lib/x86_64-linux-gnu/libc.so.6 /lib64/ld-linux-x86-64.so.2
     22143:      scope 1: linux-vdso.so.1
     22143:
     22143:     object=/lib/x86_64-linux-gnu/libc.so.6 [0]
     22143:      scope 0: ./toinject /lib/x86_64-linux-gnu/libc.so.6 /lib64/ld-linux-x86-64.so.2
     22143:
     22143:     object=/lib64/ld-linux-x86-64.so.2 [0]
     22143:      no scope
     22143:
     22143:
     22143:     relocation processing: /lib/x86_64-linux-gnu/libc.so.6 (lazy)
     22143:     symbol=_res;  lookup in file=./toinject [0]
     22143:     symbol=_res;  lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
     22143:     binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `_res' [GLIBC_2.2.5]
     22143:     symbol=stderr;  lookup in file=./toinject [0]
     22143:     symbol=stderr;  lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
     22143:     binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `stderr' [GLIBC_2.2.5]
     22143:     symbol=error_one_per_line;  lookup in file=./toinject [0]
     22143:     symbol=error_one_per_line;  lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
     22143:     binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `error_one_per_line' [GLIBC_2.2.5]
     22143:     symbol=__morecore;  lookup in file=./toinject [0]
     22143:     symbol=__morecore;  lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
     22143:     binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__morecore' [GLIBC_2.2.5]
     22143:     symbol=__key_encryptsession_pk_LOCAL;  lookup in file=./toinject [0]
     22143:     symbol=__key_encryptsession_pk_LOCAL;  lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
     22143:     binding file /lib/x86_64-linux-gnu/libc.so.6 [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `__key_encryptsession_pk_LOCAL' [GLIBC_2.2.5]
     22143:     symbol=__libpthread_freeres;  lookup in file=./toinject [0]
     22143:     symbol=__libpthread_freeres;  lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
     22143:     symbol=__libpthread_freeres;  lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
...

When i run "./mandibule ./toinject -e LD_DEBUG=all $(pidof target)", modify the file name to shorter as I did before, It's stuck.

> started.
......> target pid: 22162
> arg[0]: ./to
> env[0]: LD_DEBUG=all
> args size: 58
> auxv len: 320
av[0]: ./to
env[0]: LD_DEBUG=all
> auto-detected manual mapping address 0x555e44000000
> mapping './to' into memory at 0x555e44000000
> reading elf file './to'
> loading elf at: 0x555e44000000
> seg[0] load: 0 addr 0x40 size 0x268
> seg[1] load: 0 addr 0x2a8 size 0x1c
> seg[2] load: 1 addr 0x0 size 0x680
> load segment addr 0x555e44000000 len 0x1000 => 0x555e44000000
> seg[3] load: 1 addr 0x1000 size 0x2bd
> load segment addr 0x555e44001000 len 0x1000 => 0x555e44001000
> seg[4] load: 1 addr 0x2000 size 0x158
> load segment addr 0x555e44002000 len 0x1000 => 0x555e44002000
> seg[5] load: 1 addr 0x3de8 size 0x278
> load segment addr 0x555e44003de8 len 0x1000 => 0x555e44003000
> seg[6] load: 0 addr 0x3df8 size 0x1e0
> seg[7] load: 0 addr 0x2c4 size 0x44
> seg[8] load: 0 addr 0x2038 size 0x34
> seg[9] load: 0 addr 0x0 size 0x0
> seg[10] load: 0 addr 0x3de8 size 0x218
> program base: 0x555e44000000
> max vaddr 0x555e44015000
> loading interp '/lib64/ld-linux-x86-64.so.2'
> reading elf file '/lib64/ld-linux-x86-64.so.2'
> loading elf at: 0x555e44015000
> seg[0] load: 1 addr 0x0 size 0xf08
> load segment addr 0x555e44015000 len 0x1000 => 0x555e44015000
> seg[1] load: 1 addr 0x1000 size 0x1db20
> load segment addr 0x555e44016000 len 0x1e000 => 0x555e44016000
> seg[2] load: 1 addr 0x1f000 size 0x73dc
> load segment addr 0x555e44034000 len 0x8000 => 0x555e44034000
> seg[3] load: 1 addr 0x27640 size 0x1b50
> load segment addr 0x555e4403c640 len 0x2000 => 0x555e4403c000
> seg[4] load: 0 addr 0x27e78 size 0x170
> seg[5] load: 0 addr 0x238 size 0x24
> seg[6] load: 0 addr 0x23620 size 0x6d4
> seg[7] load: 0 addr 0x0 size 0x0
> seg[8] load: 0 addr 0x27640 size 0x9c0
> program base: 0x555e44016000
> max vaddr 0x555e4404f000
> eop 0x555e44016090
> setting auxv
> set auxv[3] to 0x555e44000040
> set auxv[5] to 0xb
> set auxv[9] to 0x555e44001090
> set auxv[7] to 0x555e44000000
> eop 0x555e44016090
> starting ...

     22162:
     22162:     WARNING: Unsupported flag value(s) of 0x8000000 in DT_FLAGS_1.
     22162:
     22162:     file=libc.so.6 [0];  needed by ./to [0]
     22162:     find library=libc.so.6 [0]; searching
     22162:      search cache=/etc/ld.so.cache
     22162:       trying file=/lib/x86_64-linux-gnu/libc.so.6
     22162:
     22162:     file=libc.so.6 [0];  generating link map
     22162:       dynamic: 0x00007f5d7f725b80  base: 0x00007f5d7f56b000   size: 0x00000000001c0800
     22162:         entry: 0x00007f5d7f58f1b0  phdr: 0x00007f5d7f56b040  phnum:                 12
     22162:
     22162:     checking for version `GLIBC_2.2.5' in file /lib/x86_64-linux-gnu/libc.so.6 [0] required by file ./to [0]
     22162:     checking for version `GLIBC_2.3' in file /lib64/ld-linux-x86-64.so.2 [0] required by file /lib/x86_64-linux-gnu/libc.so.6 [0]
     22162:     checking for version `GLIBC_PRIVATE' in file /lib64/ld-linux-x86-64.so.2 [0] required by file /lib/x86_64-linux-gnu/libc.so.6 [0]
     22162:
     22162:     Initial object scopes
     22162:     object=./to [0]
     22162:      scope 0: ./to /lib/x86_64-linux-gnu/libc.so.6 /lib64/ld-linux-x86-64.so.2
     22162:
     22162:     object=linux-vdso.so.1 [0]
     22162:      scope 0: ./to /lib/x86_64-linux-gnu/libc.so.6 /lib64/ld-linux-x86-64.so.2
     22162:      scope 1: linux-vdso.so.1
     22162:
     22162:     object=/lib/x86_64-linux-gnu/libc.so.6 [0]
     22162:      scope 0: ./to /lib/x86_64-linux-gnu/libc.so.6 /lib64/ld-linux-x86-64.so.2
     22162:
     22162:     object=/lib64/ld-linux-x86-64.so.2 [0]
     22162:      no scope
     22162:
     22162:
     22162:     relocation processing: /lib/x86_64-linux-gnu/libc.so.6 (lazy)
===============> stuck

But I removed the environment variable, the situation is just the opposite, it seems I need to learn the source code of glibc. Screenshot: image image

Hackerl avatar Nov 01 '20 04:11 Hackerl

For debugging, I defined the "nanosleep" system call in "icrt_syscall.h".

_syscall2(SYS_nanosleep,_nanosleep, int,    void*, void*)

Pause the process for 30 seconds when jumping to the entry address.

    struct timespec req = {};
    struct timespec rem = {};

    req.tv_sec = 30;

    printf("pause");
    _nanosleep(&req, &rem);
    printf("run");

    // all done
    printf("> starting ...\n\n");
    FIX_SP_JMP(stackptr, eop);

Then modify "pt_inject" function, detach target process when shellcode execute.

    // execute code now
    printf("> running shellcode..\n");

    if(_ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0)
        _pt_fail("> _pt_detach error\n");

    printf("detach");

    return 0;

During the 30-second pause time, I used gdb to attach to the target process, and then resume thread execution. When the program is running in "ld.so", a segmentation error occurs, the error instruction is "movaps [rbp+var_70], xmm0". image The reason is that the memory parameter of the "movaps" instruction requires 16-byte alignment, but the custom fake stack does not consider this.

Hackerl avatar Nov 01 '20 12:11 Hackerl

For debugging, I defined the "nanosleep" system call in "icrt_syscall.h".

_syscall2(SYS_nanosleep,_nanosleep, int,    void*, void*)

Pause the process for 30 seconds when jumping to the entry address.

    struct timespec req = {};
    struct timespec rem = {};

    req.tv_sec = 30;

    printf("pause");
    _nanosleep(&req, &rem);
    printf("run");

    // all done
    printf("> starting ...\n\n");
    FIX_SP_JMP(stackptr, eop);

Then modify "pt_inject" function, detach target process when shellcode execute.

    // execute code now
    printf("> running shellcode..\n");

    if(_ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0)
        _pt_fail("> _pt_detach error\n");

    printf("detach");

    return 0;

During the 30-second pause time, I used gdb to attach to the target process, and then resume thread execution. When the program is running in "ld.so", a segmentation error occurs, the error instruction is "movaps [rbp+var_70], xmm0". image The reason is that the memory parameter of the "movaps" instruction requires 16-byte alignment, but the custom fake stack does not consider this.

Hello Hackerl, I try the software on arm64, but I got different behavior as you mentioned, I can run it in arm64 using named "toinject", but stucked using named "toinj" Could you kindly share your test code which support me to debug the issues? Thanks a lots.

  1. Failed using named "toinj" image

  2. Success using named "toinject" image

uidn0158 avatar Jul 29 '21 07:07 uidn0158

For debugging, I defined the "nanosleep" system call in "icrt_syscall.h".

_syscall2(SYS_nanosleep,_nanosleep, int,    void*, void*)

Pause the process for 30 seconds when jumping to the entry address.

    struct timespec req = {};
    struct timespec rem = {};

    req.tv_sec = 30;

    printf("pause");
    _nanosleep(&req, &rem);
    printf("run");

    // all done
    printf("> starting ...\n\n");
    FIX_SP_JMP(stackptr, eop);

Then modify "pt_inject" function, detach target process when shellcode execute.

    // execute code now
    printf("> running shellcode..\n");

    if(_ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0)
        _pt_fail("> _pt_detach error\n");

    printf("detach");

    return 0;

During the 30-second pause time, I used gdb to attach to the target process, and then resume thread execution. When the program is running in "ld.so", a segmentation error occurs, the error instruction is "movaps [rbp+var_70], xmm0". image The reason is that the memory parameter of the "movaps" instruction requires 16-byte alignment, but the custom fake stack does not consider this.

Hello Hackerl, I try the software on arm64, but I got different behavior as you mentioned, I can run it in arm64 using named "toinject", but stucked using named "toinj" Could you kindly share your test code which support me to debug the issues? Thanks a lots.

  1. Failed using named "toinj" image
  2. Success using named "toinject" image

Hello, the reason for this problem is that the fake stack is not aligned to 16 bytes. I fixed this error and dealt with some other bugs. look here: https://github.com/Hackerl/mandibule In addition, I refactored the entire project, but currently only supports x64. If you are interested, you can add support for arm64. look here: https://github.com/Hackerl/pangolin

Hackerl avatar Jul 29 '21 07:07 Hackerl

For debugging, I defined the "nanosleep" system call in "icrt_syscall.h".

_syscall2(SYS_nanosleep,_nanosleep, int,    void*, void*)

Pause the process for 30 seconds when jumping to the entry address.

    struct timespec req = {};
    struct timespec rem = {};

    req.tv_sec = 30;

    printf("pause");
    _nanosleep(&req, &rem);
    printf("run");

    // all done
    printf("> starting ...\n\n");
    FIX_SP_JMP(stackptr, eop);

Then modify "pt_inject" function, detach target process when shellcode execute.

    // execute code now
    printf("> running shellcode..\n");

    if(_ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0)
        _pt_fail("> _pt_detach error\n");

    printf("detach");

    return 0;

During the 30-second pause time, I used gdb to attach to the target process, and then resume thread execution. When the program is running in "ld.so", a segmentation error occurs, the error instruction is "movaps [rbp+var_70], xmm0". image The reason is that the memory parameter of the "movaps" instruction requires 16-byte alignment, but the custom fake stack does not consider this.

Hello Hackerl, I try the software on arm64, but I got different behavior as you mentioned, I can run it in arm64 using named "toinject", but stucked using named "toinj" Could you kindly share your test code which support me to debug the issues? Thanks a lots.

  1. Failed using named "toinj" image
  2. Success using named "toinject" image

hello, I just supported multiple cpu architectures, aarch64 has been tested, and the rest of the architecture is still being prepared. https://github.com/Hackerl/pangolin/tree/arch

Hackerl avatar Aug 01 '21 04:08 Hackerl