Skip to content

Instantly share code, notes, and snippets.

@CYBERAG3NT12
Forked from smx-smx/XZ Backdoor Analysis
Created April 1, 2024 04:27
Show Gist options
  • Save CYBERAG3NT12/a79c7badf09ede07a13449ff83839e67 to your computer and use it in GitHub Desktop.
Save CYBERAG3NT12/a79c7badf09ede07a13449ff83839e67 to your computer and use it in GitHub Desktop.

Revisions

  1. @smx-smx smx-smx revised this gist Apr 1, 2024. 1 changed file with 17 additions and 0 deletions.
    17 changes: 17 additions & 0 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -398,3 +398,20 @@ Thread 3.1 "sshd" hit Breakpoint 1, 0x00007ffff73d1d00 in ?? () from /lib/x86_64
    return real_RSA_public_decrypt(flen, from, to, rsa_key);
    return result;
    ```

    ### Binary patch for `sshd` to disable seccomp and chroot (allows Frida tracing of `[net]` processes)
    ```shell
    > fc /b sshd sshd_patched
    Comparing files sshd sshd_patched
    0001332A: 75 90
    0001332B: 6D 90
    ----
    0004FC24: 41 C3
    0004FC25: 54 90
    ----
    00109010: 01 00
    ```

    - 0001332A: changes the following JMP to not be taken: https://github.com/openssh/openssh-portable/blob/43e7c1c07cf6aae7f4394ca8ae91a3efc46514e2/sshd.c#L448-L449
    - 0004FC24: changes the `ssh_sandbox_child` function to be a no-op: https://github.com/openssh/openssh-portable/blob/43e7c1c07cf6aae7f4394ca8ae91a3efc46514e2/sandbox-seccomp-filter.c#L490
    - 00109010: changes the default value of `privsep_chroot` from 1 to 0 (probably redundant, since it gets overwritten)
  2. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 14 additions and 8 deletions.
    22 changes: 14 additions & 8 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -353,15 +353,21 @@ Once attached, set relevant breakpoints and restore the original bytes ("\xF3\x0


    ##### breakpoint on RSA_public_decrypt hook
    Run this gdb script on the sshd listener process
    (this new gdbinit script should account for eventual differences in library load address - it didn't happen for me in the first tests but it did later on)
    ```
    (gdb) find /b 0x7ffff73bf000, 0x7ffff73e8000, 0xF3, 0x0F, 0x1E, 0xFA, 0x41, 0x57, 0xB9, 0xAE, 0x00, 0x00, 0x00, 0x31
    0x7ffff73d1d00
    1 pattern found.
    (gdb) hbreak *0x7ffff73d1d00
    Hardware assisted breakpoint 1 at 0x7ffff73d1d00
    (gdb) set follow-fork-mode child
    (gdb) c
    ...
    set pagination off
    set follow-fork-mode child
    catch load
    # now we forked, wait for lzma
    catch load liblzma
    c
    # now we have lzma
    # 0x12750: offset from base
    hbreak *(lzma_crc32 - 0x2640 + 0x12750)
    set disassembly-flavor intel
    set pagination on
    c
    ```

    Now connect via https://gist.github.com/keeganryan/a6c22e1045e67c17e88a606dfdf95ae4
  3. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 10 additions and 2 deletions.
    12 changes: 10 additions & 2 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -246,6 +246,7 @@ Note how, instead of `size`, the malware passes an EncodedStringID instead
    ## Dynamic analysis
    ### Analyzing the initialization routine
    1. Replace the `endbr64` in `get_cpuid` with a `jmp .` ("\xeb\xfe")
    ```shell
    root@debian:~# cat /usr/lib/x86_64-linux-gnu/liblzma.so.5.6.1 > liblzma.so.5.6.1
    @@ -255,16 +256,23 @@ root@debian:~# perl -pe 's/\xF3\x0F\x1E\xFA\x55\x48\x89\xF5\x4C\x89\xCE/\xEB\xFE
    ```
    # env -i LC_LANG=C LD_PRELOAD=$PWD/liblzma.so.5.6.1 /usr/sbin/sshd -h
    ```
    NOTE: [anarazel](https://github.com/anarazel) recommends using `LD_LIBRARY_PATH` with a symlink instead, since `LD_PRELOAD` changes the initialization order and could

    ###

    2b. or use this gdbinit file to do it all at once
    ```shell
    # cat gdbinit
    set confirm off
    unset env

    ## comment this out if you don't want to debug the initialization code
    ## (or use LD_LIBRARY_PATH instead)
    set env LD_PRELOAD=/root/sshd/liblzma.so.5.6.1
    set env LANG=C
    file /usr/sbin/sshd
    set args -h
    ## start sshd on port 2022
    set args -p 2022
    set disassembly-flavor intel
    set confirm on
    set startup-with-shell off
    @@ -274,7 +282,7 @@ show args

    # gdb -x gdbinit
    (gdb) r
    Starting program: /usr/sbin/sshd -h
    Starting program: /usr/sbin/sshd -p 222
    ^C <-- send CTRL-C
    Program received signal SIGINT, Interrupt.
    0x00007ffff7f8a7f0 in ?? ()
  4. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,6 @@
    ### Discord Room for discussion
    https://discord.gg/TSD7H8Ww

    ##### Init routines
    - `Llzma_delta_props_decoder` -> `backdoor_ctx_save`
    - `Llzma_block_param_encoder_0` -> `backdoor_init`
  5. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 7 additions and 2 deletions.
    9 changes: 7 additions & 2 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -58,14 +58,18 @@
    - `Llzma_stream_flags_compare_1` -> `get_rodata_ptr`
    ----
    ##### Probable function hooking (to be verified)
    ##### Verified or Suspected function hooking
    - `Llzma_index_memusage_0` -> `apply_entries`
    - `Llzma_check_init_part_0` -> `apply_one_entry`
    - `Lrc_read_init_part_0` -> `apply_one_entry_internal`
    - `Llzma_lzma_optimum_fast_0` -> `install_entries`
    - `Llzip_decoder_memconfig_part_0` -> `installed_func_0`
    - `Llzma_index_stream_size_1` -> `installed_func_1` -> `RSA_public_decrypt hook/detour` (thanks [q3k](https://github.com/q3k))
    - `Llzma_index_prealloc_0` -> `RSA_public_decrypt GOT hook/detour`
    - `Llzma_index_stream_size_1` -> `check_special_rsa_key` -> (thanks [q3k](https://github.com/q3k))
    - Called from `Llzma_index_prealloc_0`, it checks if the supplied RSA key is the special key to bypass the normal authentication flow
    - `Lindex_decode_1` -> `installed_func_2`
    - `Lindex_encode_1` -> `installed_func_3`
    - `Llzma2_decoder_end_1` -> `apply_one_entry_ex`
    @@ -82,6 +86,7 @@
    ----
    ##### core functionality
    - `Llzma_delta_props_encode_part_0` -> `resolve_imports` (including `system()`)
    - `Llzma_index_stream_flags_0` -> `process_shared_libraries`
    - Reads the list of loaded libraries through `_r_debug->r_map`, and calls `process_shared_libraries_map` to traverse it
  6. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -111,7 +111,7 @@ __int64 check_software_breakpoint(_DWORD *code_addr, __int64 a2, int a3)
    ```

    ----
    Function backdoor_init (0xA7849)
    Function backdoor_init (0xA784)

    ```c
    __int64 backdoor_init(rootkit_ctx *ctx, DWORD *prev_got_ptr)
  7. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 6 additions and 4 deletions.
    10 changes: 6 additions & 4 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -77,6 +77,8 @@
    ##### lzma allocator / call hiding
    ----
    - `Lstream_decoder_mt_end_0` -> `get_lzma_allocator_addr`
    - `Linit_pric_table_part_1` -> `fake_lzma_allocator`
    - `Lstream_decode_1` -> `fake_lzma_free`
    ----
    ##### core functionality
    @@ -177,8 +179,7 @@ char *get_lzma_allocator_addr()
    char *mem;
    // Llookup_filter_part_0 holds the relative offset of `_Ldecoder_1` - 180h (0xC930)
    // by adding 0x160, it gets to 0xCA90 (Lx86_coder_destroy), which is subsequently used as scratch space
    // for creating the `lzma_allocator` struct (data starts after 8 bytes, at 0xCA98, which is the beginning of a .data segment)
    // by adding 0x180, it gets to 0xCAB0 (Lx86_coder_destroy), Since the caller adds +8, we get to 0xCAB8, which is the lzma_allocator itself
    mem = (char *)Llookup_filter_part_0;
    for ( i = 0; i <= 0xB; ++i )
    mem += 32;
    @@ -188,8 +189,9 @@ char *get_lzma_allocator_addr()

    The interface for `lzma_allocator` can be viewed for example here: https://github.com/frida/xz/blob/e70f5800ab5001c9509d374dbf3e7e6b866c43fe/src/liblzma/api/lzma/base.h#L378-L440

    The malware initializes it in `parse_elf_init` (TODO: find which functions are used for `alloc` and `free`).
    - NOTE: the function used for alloc is very likely `import_lookup_ex`, which turns `lzma_alloc` into an import resolution function.
    Therefore, the allocator is `Linit_pric_table_part_1` and free is `Lstream_decode_1`

    - NOTE: the function used for alloc is very likely `import_lookup_ex`, which turns `lzma_alloc` into an import resolution function.
    this is used a lot in `resolve_imports`, e.g.:
    ```c
    system_func = lzma_alloc(STR_system_, lzma_allocator);
  8. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 14 additions and 0 deletions.
    14 changes: 14 additions & 0 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -360,3 +360,17 @@ Thread 3.1 "sshd" hit Breakpoint 1, 0x00007ffff73d1d00 in ?? () from /lib/x86_64
    #5 0x00000001f74b5d7a in ?? ()
    #6 0x0000000000000000 in ?? ()
    ```

    ##### RSA_public_decrypt GOT hook (Llzma_index_prealloc_0)
    ```c
    /** the following happens during pubkey login **/

    params[0] = 1; // should we call original?
    // this call checks if the supplied RSA key is special
    result = installed_func_1(rsa_key, global_ctx, params);
    // if still 1, the payload didn't trigger, call the original function
    // if 0, bypass validation
    if ( params[0] )
    return real_RSA_public_decrypt(flen, from, to, rsa_key);
    return result;
    ```
  9. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -353,7 +353,7 @@ Now connect via https://gist.github.com/keeganryan/a6c22e1045e67c17e88a606dfdf95
    Thread 3.1 "sshd" hit Breakpoint 1, 0x00007ffff73d1d00 in ?? () from /lib/x86_64-linux-gnu/liblzma.so.5
    (gdb) bt
    #0 0x00007ffff73d1d00 in ?? () from /lib/x86_64-linux-gnu/liblzma.so.5
    #1 0x00007ffff73d1ae7 in ?? () from /lib/x86_64-linux-gnu/liblzma.so.5
    #1 0x00007ffff73d1ae7 in ?? () from /lib/x86_64-linux-gnu/liblzma.so.5 <-- Llzma_index_prealloc_0 (offset 0x48 in vtable)
    #2 0x00005555556bdd00 in ?? ()
    #3 0x0000000100000004 in ?? ()
    #4 0x00007fffffffdeb0 in ?? ()
  10. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 31 additions and 1 deletion.
    32 changes: 31 additions & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -329,4 +329,34 @@ Since the modified code is part of `lzma_crc64`, 0xA710 has a simple call counte
    ```

    At this point, you can issue `detach` and attach with other debuggers if needed.
    Once attached, set relevant breakpoints and restore the original bytes ("\xF3\x0F\x1E\xFA")


    Once attached, set relevant breakpoints and restore the original bytes ("\xF3\x0F\x1E\xFA")


    ##### breakpoint on RSA_public_decrypt hook
    ```
    (gdb) find /b 0x7ffff73bf000, 0x7ffff73e8000, 0xF3, 0x0F, 0x1E, 0xFA, 0x41, 0x57, 0xB9, 0xAE, 0x00, 0x00, 0x00, 0x31
    0x7ffff73d1d00
    1 pattern found.
    (gdb) hbreak *0x7ffff73d1d00
    Hardware assisted breakpoint 1 at 0x7ffff73d1d00
    (gdb) set follow-fork-mode child
    (gdb) c
    ...
    ```

    Now connect via https://gist.github.com/keeganryan/a6c22e1045e67c17e88a606dfdf95ae4

    ```
    ...
    Thread 3.1 "sshd" hit Breakpoint 1, 0x00007ffff73d1d00 in ?? () from /lib/x86_64-linux-gnu/liblzma.so.5
    (gdb) bt
    #0 0x00007ffff73d1d00 in ?? () from /lib/x86_64-linux-gnu/liblzma.so.5
    #1 0x00007ffff73d1ae7 in ?? () from /lib/x86_64-linux-gnu/liblzma.so.5
    #2 0x00005555556bdd00 in ?? ()
    #3 0x0000000100000004 in ?? ()
    #4 0x00007fffffffdeb0 in ?? ()
    #5 0x00000001f74b5d7a in ?? ()
    #6 0x0000000000000000 in ?? ()
    ```
  11. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -316,6 +316,7 @@ Since the modified code is part of `lzma_crc64`, 0xA710 has a simple call counte
    ```c
    if ( call_counter == 1 )
    {
    /** NOTE: some of these fields are unverified and guessed **/
    rootkit_ctx.head = 1LL;
    memset(&rootkit_ctx.runtime_offset, 0, 32);
    rootkit_ctx.prev_got_ptr = prev_got_ptr;
  12. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 24 additions and 1 deletion.
    25 changes: 24 additions & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -297,12 +297,35 @@ Program received signal SIGINT, Interrupt.
    #7 0x00007f8cb3b5c60c in _dl_start_final (arg=0x7ffe17e402e0)
    at ./elf/rtld.c:498
    #8 _dl_start (arg=0x7ffe17e402e0) at ./elf/rtld.c:585
    #9 0x00007f8cb3b5b4d8 in _start () from /lib64/ld-linux-x86-64.so.2
    #9 0x00007f8cb3b5b4d8 in _start () from /lib64/ld-li
    nux-x86-64.so.2
    #10 0x0000000000000002 in ?? ()
    #11 0x00007ffe17e40fa1 in ?? ()
    #12 0x00007ffe17e40fb0 in ?? ()
    #13 0x0000000000000000 in ?? ()
    ```

    NOTE: `_get_cpuid` will call function 0xA710, whose purpose is to detect if we're at the right point to initialize the backdoor
    Why?
    Because `elf_machine_rela` will call `_get_cpuid` for both `lzma_crc32` and `lzma_crc64`.
    Since the modified code is part of `lzma_crc64`, 0xA710 has a simple call counter in it to trace how many times it has been called, and make sure the modification doesn't trigger for `lzma_crc32`.

    - first call (0): -> `lzma_crc32`
    - second call (1): -> `lzma_crc64`

    ```c
    if ( call_counter == 1 )
    {
    rootkit_ctx.head = 1LL;
    memset(&rootkit_ctx.runtime_offset, 0, 32);
    rootkit_ctx.prev_got_ptr = prev_got_ptr;
    backdoor_init(&rootkit_ctx, prev_got_ptr); // replace cpuid got entry
    }
    ++call_counter;
    cpuid(a1, &v5, &v6, &v7, &rootkit_ctx);
    return v5;
    }
    ```

    At this point, you can issue `detach` and attach with other debuggers if needed.
    Once attached, set relevant breakpoints and restore the original bytes ("\xF3\x0F\x1E\xFA")
  13. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -305,4 +305,4 @@ Program received signal SIGINT, Interrupt.
    ```

    At this point, you can issue `detach` and attach with other debuggers if needed.
    Once attached, set relevant breakpoints and replace the original bytes ("\xF3\x0F\x1E\xFA")
    Once attached, set relevant breakpoints and restore the original bytes ("\xF3\x0F\x1E\xFA")
  14. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -302,4 +302,7 @@ Program received signal SIGINT, Interrupt.
    #11 0x00007ffe17e40fa1 in ?? ()
    #12 0x00007ffe17e40fb0 in ?? ()
    #13 0x0000000000000000 in ?? ()
    ```
    ```

    At this point, you can issue `detach` and attach with other debuggers if needed.
    Once attached, set relevant breakpoints and replace the original bytes ("\xF3\x0F\x1E\xFA")
  15. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 0 additions and 22 deletions.
    22 changes: 0 additions & 22 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -302,26 +302,4 @@ Program received signal SIGINT, Interrupt.
    #11 0x00007ffe17e40fa1 in ?? ()
    #12 0x00007ffe17e40fb0 in ?? ()
    #13 0x0000000000000000 in ?? ()
    (gdb) bt
    #0 0x00007f8cb3b067f0 in ?? () from /root/sshd/liblzma.so.5.6.1
    #1 0x00007f8cb3b08c29 in lzma_crc32 () from /root/sshd/liblzma.so.5.6.1
    #2 0x00007f8cb3b4ffab in elf_machine_rela (skip_ifunc=<optimized out>,
    reloc_addr_arg=0x7f8cb3b3dda0 <lzma_crc32@got[plt]>, version=<optimized out>, sym=0x7f8cb3b03018,
    reloc=0x7f8cb3b04fc8, scope=0x7f8cb3b3f4f8, map=0x7f8cb3b3f170) at ../sysdeps/x86_64/dl-machine.h:300
    #3 elf_dynamic_do_Rela (skip_ifunc=<optimized out>, lazy=<optimized out>, nrelative=<optimized out>,
    relsize=<optimized out>, reladdr=<optimized out>, scope=<optimized out>, map=0x7f8cb3b3f170)
    at ./elf/do-rel.h:147
    #4 _dl_relocate_object (l=l@entry=0x7f8cb3b3f170, scope=<optimized out>, reloc_mode=<optimized out>,
    consider_profiling=<optimized out>, consider_profiling@entry=0) at ./elf/dl-reloc.c:301
    #5 0x00007f8cb3b5e6e9 in dl_main (phdr=<optimized out>, phnum=<optimized out>, user_entry=<optimized out>,
    auxv=<optimized out>) at ./elf/rtld.c:2318
    #6 0x00007f8cb3b5af0f in _dl_sysdep_start (start_argptr=start_argptr@entry=0x7ffe17e402e0,
    dl_main=dl_main@entry=0x7f8cb3b5c900 <dl_main>) at ../sysdeps/unix/sysv/linux/dl-sysdep.c:140
    #7 0x00007f8cb3b5c60c in _dl_start_final (arg=0x7ffe17e402e0) at ./elf/rtld.c:498
    #8 _dl_start (arg=0x7ffe17e402e0) at ./elf/rtld.c:585
    #9 0x00007f8cb3b5b4d8 in _start () from /lib64/ld-linux-x86-64.so.2
    #10 0x0000000000000002 in ?? ()
    #11 0x00007ffe17e40fa1 in ?? ()
    #12 0x00007ffe17e40fb0 in ?? ()
    #13 0x0000000000000000 in ?? ()
    ```
  16. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 25 additions and 0 deletions.
    25 changes: 25 additions & 0 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -246,6 +246,31 @@ root@debian:~# perl -pe 's/\xF3\x0F\x1E\xFA\x55\x48\x89\xF5\x4C\x89\xCE/\xEB\xFE
    # env -i LC_LANG=C LD_PRELOAD=$PWD/liblzma.so.5.6.1 /usr/sbin/sshd -h
    ```

    2b. or use this gdbinit file to do it all at once
    ```shell
    # cat gdbinit
    set confirm off
    unset env
    set env LD_PRELOAD=/root/sshd/liblzma.so.5.6.1
    set env LANG=C
    file /usr/sbin/sshd
    set args -h
    set disassembly-flavor intel
    set confirm on
    set startup-with-shell off

    show env
    show args

    # gdb -x gdbinit
    (gdb) r
    Starting program: /usr/sbin/sshd -h
    ^C <-- send CTRL-C
    Program received signal SIGINT, Interrupt.
    0x00007ffff7f8a7f0 in ?? ()
    ```


    3. Attach to the frozen process with your favourite debugger (`gdb attach pid`)
    ```
    (gdb) bt
  17. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -234,7 +234,7 @@ __int64 Llzma_index_buffer_encode_0(Elf64_Ehdr **p_elf, struct_elf_info *elf_inf
    Note how, instead of `size`, the malware passes an EncodedStringID instead
    ##### Dynamic analysis
    ## Dynamic analysis
    1. Replace the `endbr64` in `get_cpuid` with a `jmp .` ("\xeb\xfe")
    ```shell
  18. @smx-smx smx-smx revised this gist Mar 31, 2024. 1 changed file with 66 additions and 1 deletion.
    67 changes: 66 additions & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -234,4 +234,69 @@ __int64 Llzma_index_buffer_encode_0(Elf64_Ehdr **p_elf, struct_elf_info *elf_inf
    Note how, instead of `size`, the malware passes an EncodedStringID instead
    #####
    ##### Dynamic analysis
    1. Replace the `endbr64` in `get_cpuid` with a `jmp .` ("\xeb\xfe")
    ```shell
    root@debian:~# cat /usr/lib/x86_64-linux-gnu/liblzma.so.5.6.1 > liblzma.so.5.6.1
    root@debian:~# perl -pe 's/\xF3\x0F\x1E\xFA\x55\x48\x89\xF5\x4C\x89\xCE/\xEB\xFE\x90\x90\x55\x48\x89\xF5\x4C\x89\xCE/g' -i liblzma.so.5.6.1
    ```
    2. Force sshd to use the modified library with `LD_PRELOAD`
    ```
    # env -i LC_LANG=C LD_PRELOAD=$PWD/liblzma.so.5.6.1 /usr/sbin/sshd -h
    ```

    3. Attach to the frozen process with your favourite debugger (`gdb attach pid`)
    ```
    (gdb) bt
    #0 0x00007f8cb3b067f0 in ?? () from /root/sshd/liblzma.so.5.6.1
    #1 0x00007f8cb3b08c29 in lzma_crc32 () from /root/sshd/liblzma.so.5.6.1
    #2 0x00007f8cb3b4ffab in elf_machine_rela (skip_ifunc=<optimized out>,
    reloc_addr_arg=0x7f8cb3b3dda0 <lzma_crc32@got[plt]>,
    version=<optimized out>, sym=0x7f8cb3b03018, reloc=0x7f8cb3b04fc8,
    scope=0x7f8cb3b3f4f8, map=0x7f8cb3b3f170)
    at ../sysdeps/x86_64/dl-machine.h:300
    #3 elf_dynamic_do_Rela (skip_ifunc=<optimized out>, lazy=<optimized out>,
    nrelative=<optimized out>, relsize=<optimized out>,
    reladdr=<optimized out>, scope=<optimized out>, map=0x7f8cb3b3f170)
    at ./elf/do-rel.h:147
    #4 _dl_relocate_object (l=l@entry=0x7f8cb3b3f170, scope=<optimized out>,
    reloc_mode=<optimized out>, consider_profiling=<optimized out>,
    consider_profiling@entry=0) at ./elf/dl-reloc.c:301
    #5 0x00007f8cb3b5e6e9 in dl_main (phdr=<optimized out>, phnum=<optimized out>,
    user_entry=<optimized out>, auxv=<optimized out>) at ./elf/rtld.c:2318
    #6 0x00007f8cb3b5af0f in _dl_sysdep_start (
    start_argptr=start_argptr@entry=0x7ffe17e402e0,
    dl_main=dl_main@entry=0x7f8cb3b5c900 <dl_main>)
    at ../sysdeps/unix/sysv/linux/dl-sysdep.c:140
    #7 0x00007f8cb3b5c60c in _dl_start_final (arg=0x7ffe17e402e0)
    at ./elf/rtld.c:498
    #8 _dl_start (arg=0x7ffe17e402e0) at ./elf/rtld.c:585
    #9 0x00007f8cb3b5b4d8 in _start () from /lib64/ld-linux-x86-64.so.2
    #10 0x0000000000000002 in ?? ()
    #11 0x00007ffe17e40fa1 in ?? ()
    #12 0x00007ffe17e40fb0 in ?? ()
    #13 0x0000000000000000 in ?? ()
    (gdb) bt
    #0 0x00007f8cb3b067f0 in ?? () from /root/sshd/liblzma.so.5.6.1
    #1 0x00007f8cb3b08c29 in lzma_crc32 () from /root/sshd/liblzma.so.5.6.1
    #2 0x00007f8cb3b4ffab in elf_machine_rela (skip_ifunc=<optimized out>,
    reloc_addr_arg=0x7f8cb3b3dda0 <lzma_crc32@got[plt]>, version=<optimized out>, sym=0x7f8cb3b03018,
    reloc=0x7f8cb3b04fc8, scope=0x7f8cb3b3f4f8, map=0x7f8cb3b3f170) at ../sysdeps/x86_64/dl-machine.h:300
    #3 elf_dynamic_do_Rela (skip_ifunc=<optimized out>, lazy=<optimized out>, nrelative=<optimized out>,
    relsize=<optimized out>, reladdr=<optimized out>, scope=<optimized out>, map=0x7f8cb3b3f170)
    at ./elf/do-rel.h:147
    #4 _dl_relocate_object (l=l@entry=0x7f8cb3b3f170, scope=<optimized out>, reloc_mode=<optimized out>,
    consider_profiling=<optimized out>, consider_profiling@entry=0) at ./elf/dl-reloc.c:301
    #5 0x00007f8cb3b5e6e9 in dl_main (phdr=<optimized out>, phnum=<optimized out>, user_entry=<optimized out>,
    auxv=<optimized out>) at ./elf/rtld.c:2318
    #6 0x00007f8cb3b5af0f in _dl_sysdep_start (start_argptr=start_argptr@entry=0x7ffe17e402e0,
    dl_main=dl_main@entry=0x7f8cb3b5c900 <dl_main>) at ../sysdeps/unix/sysv/linux/dl-sysdep.c:140
    #7 0x00007f8cb3b5c60c in _dl_start_final (arg=0x7ffe17e402e0) at ./elf/rtld.c:498
    #8 _dl_start (arg=0x7ffe17e402e0) at ./elf/rtld.c:585
    #9 0x00007f8cb3b5b4d8 in _start () from /lib64/ld-linux-x86-64.so.2
    #10 0x0000000000000002 in ?? ()
    #11 0x00007ffe17e40fa1 in ?? ()
    #12 0x00007ffe17e40fb0 in ?? ()
    #13 0x0000000000000000 in ?? ()
    ```
  19. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -86,7 +86,7 @@
    - `Llzma_index_encoder_init_1` -> `process_shared_libraries_map`
    - Traverses the list of loaded libraries, looking for specific libraries
    - func @0x7620 : It does indirect calls on the vtable configured by `backdoor_vtbl_init`, and is called by the `RSA_public_decrypt` upon certain conditions are met
    - func @0x7620 : It does indirect calls on the vtable configured by `backdoor_vtbl_init`, and is called by the `RSA_public_decrypt` hook (func#1) upon certain conditions are met
    Software Breakpoint check, method 1
    -----
  20. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -20,7 +20,8 @@
    - `Lx86_code_part_0` -> `code_dasm`
    -----

    - `Llzma_delta_decoder_init_part_0` -> `backdoor_ctx_init`
    - `Llzma_delta_decoder_init_part_0` -> `backdoor_vtbl_init`
    - It sets up a vtable with core functions used by the backdoor

    - `Lstream_decoder_memconfig_part_1` -> `get_lzma_allocator`

    @@ -85,6 +86,8 @@
    - `Llzma_index_encoder_init_1` -> `process_shared_libraries_map`
    - Traverses the list of loaded libraries, looking for specific libraries
    - func @0x7620 : It does indirect calls on the vtable configured by `backdoor_vtbl_init`, and is called by the `RSA_public_decrypt` upon certain conditions are met
    Software Breakpoint check, method 1
    -----
  21. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -81,8 +81,8 @@
    ##### core functionality
    - `Llzma_delta_props_encode_part_0` -> `resolve_imports` (including `system()`)
    - `Llzma_index_stream_flags_0` -> `process_shared_libraries`
    - Reads the list of loaded libraries through `_r_debug->r_map`, and calls `process_shared_library_map` to traverse it
    - `Llzma_index_encoder_init_1` -> `process_shared_library_map`
    - Reads the list of loaded libraries through `_r_debug->r_map`, and calls `process_shared_libraries_map` to traverse it
    - `Llzma_index_encoder_init_1` -> `process_shared_libraries_map`
    - Traverses the list of loaded libraries, looking for specific libraries
    Software Breakpoint check, method 1
  22. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 4 additions and 0 deletions.
    4 changes: 4 additions & 0 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -80,6 +80,10 @@
    ----
    ##### core functionality
    - `Llzma_delta_props_encode_part_0` -> `resolve_imports` (including `system()`)
    - `Llzma_index_stream_flags_0` -> `process_shared_libraries`
    - Reads the list of loaded libraries through `_r_debug->r_map`, and calls `process_shared_library_map` to traverse it
    - `Llzma_index_encoder_init_1` -> `process_shared_library_map`
    - Traverses the list of loaded libraries, looking for specific libraries
    Software Breakpoint check, method 1
    -----
  23. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -64,7 +64,7 @@
    - `Llzma_lzma_optimum_fast_0` -> `install_entries`
    - `Llzip_decoder_memconfig_part_0` -> `installed_func_0`
    - `Llzma_index_stream_size_1` -> `installed_func_1` -> `RSA_public_decrypt hook/detour` (thanks [q3k](https://gist.github.com/q3k))
    - `Llzma_index_stream_size_1` -> `installed_func_1` -> `RSA_public_decrypt hook/detour` (thanks [q3k](https://github.com/q3k))
    - `Lindex_decode_1` -> `installed_func_2`
    - `Lindex_encode_1` -> `installed_func_3`
    - `Llzma2_decoder_end_1` -> `apply_one_entry_ex`
  24. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -64,7 +64,7 @@
    - `Llzma_lzma_optimum_fast_0` -> `install_entries`
    - `Llzip_decoder_memconfig_part_0` -> `installed_func_0`
    - `Llzma_index_stream_size_1` -> `installed_func_1`
    - `Llzma_index_stream_size_1` -> `installed_func_1` -> `RSA_public_decrypt hook/detour` (thanks [q3k](https://gist.github.com/q3k))
    - `Lindex_decode_1` -> `installed_func_2`
    - `Lindex_encode_1` -> `installed_func_3`
    - `Llzma2_decoder_end_1` -> `apply_one_entry_ex`
  25. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -199,7 +199,7 @@ The third `lzma_allocator` field, `opaque`, is abused to pass information about
    This is highlighted quite well by function `Llzma_index_buffer_encode_0`:

    ```c
    __int64 Llzma_index_buffer_encode_0(Elf64_Ehdr **p_elf, struct_segment *elf_info, struct_ctx *ctx)
    __int64 Llzma_index_buffer_encode_0(Elf64_Ehdr **p_elf, struct_elf_info *elf_info, struct_ctx *ctx)
    {
    _QWORD *lzma_allocator;
    __int64 result;
  26. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -195,7 +195,7 @@ The malware initializes it in `parse_elf_init` (TODO: find which functions are u
    ++ctx->num_imports;
    ```

    The third `lzma_allocator` field, `opaque`, is abused to pass information about the loaded ELF file "fake allocator" functions.
    The third `lzma_allocator` field, `opaque`, is abused to pass information about the loaded ELF file to the "fake allocator" function.
    This is highlighted quite well by function `Llzma_index_buffer_encode_0`:

    ```c
  27. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 20 additions and 12 deletions.
    32 changes: 20 additions & 12 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -195,23 +195,31 @@ The malware initializes it in `parse_elf_init` (TODO: find which functions are u
    ++ctx->num_imports;
    ```

    The third `lzma_allocator` field, `opaque`, is abused to pass additional data to the "allocator" functions, e.g. (in `Llzma_index_buffer_encode_0`):
    The third `lzma_allocator` field, `opaque`, is abused to pass information about the loaded ELF file "fake allocator" functions.
    This is highlighted quite well by function `Llzma_index_buffer_encode_0`:

    ```c
    __int64 Llzma_index_buffer_encode_0(Elf64_Ehdr **p_elf, struct_segment *elf_info, struct_ctx *ctx)
    {
    _QWORD *lzma_allocator;
    __int64 result;
    __int64 fn_read;
    __int64 fn_errno_location;

    lzma_allocator = get_lzma_allocator();
    result = parse_elf(*a1, a2);
    result = parse_elf(*p_elf, elf_info); // reads elf into elf_info
    if ( (_DWORD)result )
    {
    lzma_allocator[2] = a2; // <-- sets the `opaque` field to some data that will be used by the fake allocator function
    v6 = lzma_alloc(STR_read_, lzma_allocator);
    *(_QWORD *)(a3 + 72) = v6;
    if ( v6 )
    ++*(_DWORD *)a3;
    v7 = lzma_alloc(STR___errno_location_, lzma_allocator);
    *(_QWORD *)(a3 + 80) = v7;
    if ( v7 )
    ++*(_DWORD *)a3;
    return *(_DWORD *)a3 == 2;
    lzma_allocator[2] = elf_info; // set opaque field to the parsed elf info
    fn_read = lzma_alloc(STR_read_, lzma_allocator);
    ctx->fn_read = fn_read;
    if ( fn_read )
    ++ctx->num_imports;
    fn_errno_location = lzma_alloc(STR___errno_location_, lzma_allocator);
    ctx->fn_errno_location = fn_errno_location;
    if ( fn_errno_location )
    ++ctx->num_imports;
    return ctx->num_imports == 2; // true if we found both imports
    }
    return result;
    }
  28. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -195,7 +195,7 @@ The malware initializes it in `parse_elf_init` (TODO: find which functions are u
    ++ctx->num_imports;
    ```

    The third field, `opaque`, is used to pass additional data to the functions, e.g. (in `Llzma_index_buffer_encode_0`):
    The third `lzma_allocator` field, `opaque`, is abused to pass additional data to the "allocator" functions, e.g. (in `Llzma_index_buffer_encode_0`):

    ```c
    lzma_allocator = get_lzma_allocator();
  29. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -182,8 +182,8 @@ char *get_lzma_allocator_addr()
    The interface for `lzma_allocator` can be viewed for example here: https://github.com/frida/xz/blob/e70f5800ab5001c9509d374dbf3e7e6b866c43fe/src/liblzma/api/lzma/base.h#L378-L440

    The malware initializes it in `parse_elf_init` (TODO: find which functions are used for `alloc` and `free`).
    - NOTE: the function used for alloc is very likely `import_lookup_ex`, which turns `lzma_alloc` into an import resolution function:
    e.g. from `resolve_imports`:
    - NOTE: the function used for alloc is very likely `import_lookup_ex`, which turns `lzma_alloc` into an import resolution function.
    this is used a lot in `resolve_imports`, e.g.:
    ```c
    system_func = lzma_alloc(STR_system_, lzma_allocator);
    ctx->system = system_func;
  30. @smx-smx smx-smx revised this gist Mar 30, 2024. 1 changed file with 17 additions and 0 deletions.
    17 changes: 17 additions & 0 deletions backdoor_analysis.md
    Original file line number Diff line number Diff line change
    @@ -77,6 +77,10 @@
    ----
    - `Lstream_decoder_mt_end_0` -> `get_lzma_allocator_addr`
    ----
    ##### core functionality
    - `Llzma_delta_props_encode_part_0` -> `resolve_imports` (including `system()`)
    Software Breakpoint check, method 1
    -----
    @@ -178,6 +182,19 @@ char *get_lzma_allocator_addr()
    The interface for `lzma_allocator` can be viewed for example here: https://github.com/frida/xz/blob/e70f5800ab5001c9509d374dbf3e7e6b866c43fe/src/liblzma/api/lzma/base.h#L378-L440

    The malware initializes it in `parse_elf_init` (TODO: find which functions are used for `alloc` and `free`).
    - NOTE: the function used for alloc is very likely `import_lookup_ex`, which turns `lzma_alloc` into an import resolution function:
    e.g. from `resolve_imports`:
    ```c
    system_func = lzma_alloc(STR_system_, lzma_allocator);
    ctx->system = system_func;
    if ( system_func )
    ++ctx->num_imports;
    shutdown_func = lzma_alloc(STR_shutdown_, lzma_allocator);
    ctx->shutdown = shutdown_func;
    if ( shutdown_func )
    ++ctx->num_imports;
    ```

    The third field, `opaque`, is used to pass additional data to the functions, e.g. (in `Llzma_index_buffer_encode_0`):

    ```c