Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

program stuck at "starting ..." #3

Open
Hackerl opened this issue Oct 31, 2020 · 6 comments
Open

program stuck at "starting ..." #3

Hackerl opened this issue Oct 31, 2020 · 6 comments

Comments

@Hackerl
Copy link

Hackerl commented Oct 31, 2020

For my last issue: #2
I commit the patch: Hackerl@92de629

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
Copy link
Author

Hackerl commented Oct 31, 2020

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

@Hackerl
Copy link
Author

Hackerl commented Nov 1, 2020

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
Copy link
Author

Hackerl commented Nov 1, 2020

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.

@uidn0158
Copy link

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

@Hackerl
Copy link
Author

Hackerl commented Jul 29, 2021

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
Copy link
Author

Hackerl commented Aug 1, 2021

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants