目的:我试图利用x86-64中的RIP模式。即使程序集本身按预期执行,shellcode也不会。
问题:简单地说,我尝试了这个,
jmp l1
str1: db "some string"
l1:
other code
lea rax, [rel str1]
我在不同地方使用了上述内容,仅在某些地方失败并在其他地方成功。我试图玩,并在失败时找不到任何模式。当变量(str1:db指令)位置在访问它的指令之后,它永远不会失败(在我的观察中)。但是,我想删除空值,因此我在访问它之前放置了变量定义。
调试查找
在调试时,我发现失败的jmp指向一些不正确的指令地址。
例如:(在gdb中)
(code + 18) jmp [code +27] //jmp pointing incorrectly to in-between 2
(code + 22) ... (this part has label)
(code + 24) some instruction // this is where I intended the jmp
(code + 28) some other instruction
代码 这是一个示例代码,我试图生成一个Execve Shell。它非常大,所以我确定了罪魁祸首JMP的位置。
global _start
section .text
_start:
xor rax,rax
mov rsi,rax
mov rdi,rsi
mov rdx,rdi
mov r8,rdx
mov rcx,r8
mov rbx,rcx
jmp gg //failing (jumping somewhere unintended)
p2: db "/bin/sh"
gg:
xor rax,rax
lea rdi, [rel p2]
mov [rdi+7], byte al //null terminating using 0x00 from rax
mov [rdi+8], rdi
mov [rdi+16],rax
lea rsi,[rdi+8]
lea rdx,[rdi+16]
mov al,59
syscall
修改:1 修改了代码以包含失败的指令
修改:2 我使用的C中的Shellcode。
#include<stdio.h>
#include<string.h>
unsigned char code[] = \
"\x48\x31\xc0\x48\x89\xc6\x48\x89\xf7\x48\x89\xfa\x49\x89\xd0\x4c\x89\xc1\x48\x89\xcb\xeb\x07\x2f\x62\x69\x6e\x2f\x73\x68\x48\x31\x48\x31\xc0\x48\x8d\x3d\xef\xff\xff\xff\x88\x47\x07\x48\x89\x7f\x08\x48\x89\x47\x10\x48\x8d\x77\x08\x48\x8d\x57\x10\xb0\x3b\x0f\x05";
main()
{
printf("Shellcode Length: %d\n", (int)strlen(code));
int (*ret)() = (int(*)())code;
ret();
}
编辑3 我会通过放置以下代码将Hexdump放入一个Bash文件并通过传递filename作为参数来运行它。从ShellStorm接收它。
`for i in $(objdump -d $1 -M intel |grep "^ " |cut -f2); do echo -n '\x'$i`;
答案 0 :(得分:3)
TL; DR :用于将独立shell代码程序shellExec
转换为shell代码漏洞利用字符串的方法存在问题。
根据给出的信息,我怀疑问题是您使用反汇编输出生成最终字节流的方式,该最终字节流将转换为您的shell代码字符串。可能反汇编输出有令人困惑的输出和可能重复的值。在尝试反汇编数据时(与代码混合),它尝试输出最短的可编码指令以完成所有数据的使用,然后发现你有一个JMP目标,并在备份重新同步时复制了一些字节。无论使用什么过程将反汇编转换为二进制都没有考虑到这种问题。
不要使用反汇编输出来生成二进制文件。使用shell代码生成您的独立可执行文件(我相信shellExec
是您的文件中的文件)并使用 OBJCOPY 和 HEXDUMP 等工具生成 C shell代码字符串:
objcopy -j.text -O binary execShell execShell.bin
hexdump -v -e '"\\""x" 1/1 "%02x" ""' execShell.bin
objcopy
命令获取execShell
可执行文件并仅提取.text
部分(使用-j.text
选项)并将二进制数据输出到文件{{1} }。 execShell.bin
命令只是重新格式化二进制文件并以可在 C 字符串中使用的形式输出。此过程不涉及解析任何令人困惑的反汇编输出,因此不会遇到您遇到的问题。 hexdump
的输出应如下所示:
\ X48 \ X31 \ XC0 \ X48 \ X89 \ XC6 \ X48 \ X89 \ XF7 \ X48 \ X89 \ XFA \ X49 \ X89 \ XD0 \ x4c \ X89 \ XC1 \ X48 \ X89 \ XCB \ XEB \ X07 \ X2F \ X62 \ X69 \ x6e \ X2F \ X73 \ X68的 \ X48 \ X31 \ XC0 \ X48 \ x8d \ X3D \ XEF \ XFF \ XFF \ XFF \ X88 \ X47 \ X07 \ X48 \ X89 \ 0x7F部分\ X08 \ X48 \ X89 \ X47 \ X10 \ X48 \ x8d \ X77 \ X08 \ X48 \ x8d \ X57 \ X10 \ XB0 \ X3B \ X0F \ X05
这与你的略有不同:
\ X48 \ X31 \ XC0 \ X48 \ X89 \ XC6 \ X48 \ X89 \ XF7 \ X48 \ X89 \ XFA \ X49 \ X89 \ XD0 \ x4c \ X89 \ XC1 \ X48 \ X89 \ XCB \ XEB \ X07 \ X2F \ X62 \ X69 \ x6e \ X2F \ X73 \ X68的 \ X48 \ X31 \ X48 \ X31 \ XC0 \ X48 \ x8d \ X3D \ XEF \ XFF \ XFF \ XFF \ X88 \ X47 \ X07 \ X48 \ X89 \ 0x7F部分\ X08 \ X48 \ X89 \ X47 \ X10 \ X48 \ x8d \ X77 \ X08 \ X48 \ x8d \ X57 \ X10 \ XB0 \ X3B \ X0F \ X05
我突出了它的不同之处。在字符串hexdump
之后,您的输出引入了额外的/bin/sh
。 shell代码字符串中的额外2个字节负责代码未在目标可执行文件中按预期运行。
答案 1 :(得分:0)
我可以在使用nasm
更改//
后使用;
编译代码,但我并没有尝试执行它。
nasm -f elf64 a.s -o a
然后我可以用以下代码查看代码:
objdump -d a
您要问的代码部分就像(jmp
)
12: 48 89 cb mov %rcx,%rbx
15: eb 07 jmp 1e <gg>
0000000000000017 <p2>:
17: 2f (bad)
18: 62 (bad)
19: 69 .byte 0x69
1a: 6e outsb %ds:(%rsi),(%dx)
1b: 2f (bad)
1c: 73 68 jae 86 <gg+0x68>
000000000000001e <gg>:
1e: 48 31 c0 xor %rax,%rax
但是,以下是一些问题:
mov [rdi+7], byte al ;null terminating using 0x00 from rax
mov [rdi+8], rdi
mov [rdi+16],rax
您正在尝试写入READ-ONLY内存。代码无法修改
mov rdi / rax可能未对齐
如果该代码成功,则会在gg:
覆盖您的代码。
另外,在gg:
之前放置一个by对齐是个好主意:
p2: "..."
align 16
gg:
xor rax,rax
因此,由于代码是只读的,所以你必须手动将零放在那里。
p2: db "..."
db 0
db 0, 0, 0, 0, 0, 0, 0, 0
db 0, 0, 0, 0, 0, 0, 0, 0
如果您知道它已对齐,dq
也会有效。
但请注意,您没有对齐p2
,因此您无法确定(例如,如果您的代码更改,则对齐很可能也会发生更改。)您可能希望这样做:
align 16
p2: db "..."
db 0
dq 0
dq 0
最后一点,[rel p2]
非常有限。据我所知,这些指令中的相对偏移限制为-127和+128。但是,在我的64位处理器上,它使用32位偏移量。您可能一直在运行这样的问题,取决于您的汇编程序,它决定它太远了。在您的情况下,一种解决方案是将lea
指令放在jmp
之前的数据上。我想如果偏移量溢出,编译器应该生成错误。另一种可能性是某种方式得到优化并且jmp
没有得到正确的更新。
作为旁注,以下内容未得到很好的优化:
xor rax,rax
mov rsi,rax
mov rdi,rsi
mov rdx,rdi
mov r8,rdx
对所有寄存器使用xor
或每次重复使用rax而不是切换会更好地工作(更可能并行工作)。现在,您将所有说明绑定到上一个(即在rsi
中复制rdi
之前),您需要将rax
复制到rsi
。{{1}将删除该依赖关系。)我认为在这种情况下你不会看到任何差异,但是要记住好的优化。
通过对齐并在代码中添加零,我得到:
mov rdi,rax
请注意,在反汇编时,如果您的数据代表一条指令,它最终可能会使用有效代码中的字节,因此无法显示您的预期结果。即它最终无法找到目的地标签。不过,我们在这里很好。