要在代码洞穴中实际执行代码,我尝试了两种不同的方法,两种方法都导致了sigsegv。
第一个方法是将入口点更改为代码洞穴的开始。第二个是“窃取”原始代码中的一些第一条指令,并跳转到我的代码洞穴中,然后在执行注入的代码后,我将首先执行被盗的指令,然后跳转到最后一条被盗的指令之后的指令。原始程序。
我还更改了代码洞穴所在的部分的访问标志。
以下是在gdb中调试程序的屏幕截图:
这是代码洞穴所在部分的标志:
[19] 0x555555556058->0x555555556160 at 0x00002058: .eh_frame ALLOC LOAD READONLY CODE HAS_CONTENTS
这是Valgrind的输出。
所以这里有一个实际上允许执行本节中的代码的方法。
我还考虑过将新节添加到二进制文件中并在其中编写代码。如果有人有经验,我会很感激的。
编辑:我想我知道我的错是-我为该部分设置了可执行标志,但其中的段不是可执行的。但是似乎我发现的代码洞穴也不属于任何部分,因为代码洞穴的开头实际上是一个部分的结尾,而代码洞穴的结尾实际上是另一部分的开头。在它们之间没有其他部分。
编辑2:我将代码洞穴更改为
.fini
部分,属于可执行段。但是,我仍然对部分(和段)之间的空白感到困惑。这是
readelf
输出的屏幕截图Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000000318 00000318
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.gnu.propert NOTE 0000000000000338 00000338
0000000000000020 0000000000000000 A 0 0 8
[ 3] .note.gnu.build-i NOTE 0000000000000358 00000358
0000000000000024 0000000000000000 A 0 0 4
[ 4] .note.ABI-tag NOTE 000000000000037c 0000037c
0000000000000020 0000000000000000 A 0 0 4
[ 5] .gnu.hash GNU_HASH 00000000000003a0 000003a0
0000000000000024 0000000000000000 A 6 0 8
[ 6] .dynsym DYNSYM 00000000000003c8 000003c8
00000000000000a8 0000000000000018 A 7 1 8
[ 7] .dynstr STRTAB 0000000000000470 00000470
0000000000000082 0000000000000000 A 0 0 1
[ 8] .gnu.version VERSYM 00000000000004f2 000004f2
000000000000000e 0000000000000002 A 6 0 2
[ 9] .gnu.version_r VERNEED 0000000000000500 00000500
0000000000000020 0000000000000000 A 7 1 8
[10] .rela.dyn RELA 0000000000000520 00000520
00000000000000c0 0000000000000018 A 6 0 8
[11] .rela.plt RELA 00000000000005e0 000005e0
0000000000000018 0000000000000018 AI 6 24 8
[12] .init PROGBITS 0000000000001000 00001000
000000000000001b 0000000000000000 AX 0 0 4
[13] .plt PROGBITS 0000000000001020 00001020
0000000000000020 0000000000000010 AX 0 0 16
[14] .plt.got PROGBITS 0000000000001040 00001040
0000000000000010 0000000000000010 AX 0 0 16
[15] .plt.sec PROGBITS 0000000000001050 00001050
0000000000000010 0000000000000010 AX 0 0 16
[16] .text PROGBITS 0000000000001060 00001060
0000000000000185 0000000000000000 AX 0 0 16
[17] .fini PROGBITS 00000000000011e8 000011e8
000000000000000d 0000000000000000 AX 0 0 4
[18] .rodata PROGBITS 0000000000002000 00002000
0000000000000012 0000000000000000 A 0 0 4
[19] .eh_frame_hdr PROGBITS 0000000000002014 00002014
0000000000000044 0000000000000000 A 0 0 4
[20] .eh_frame PROGBITS 0000000000002058 00002058
0000000000000108 0000000000000000 A 0 0 8
[21] .init_array INIT_ARRAY 0000000000003db8 00002db8
0000000000000008 0000000000000008 WA 0 0 8
[22] .fini_array FINI_ARRAY 0000000000003dc0 00002dc0
0000000000000008 0000000000000008 WA 0 0 8
[23] .dynamic DYNAMIC 0000000000003dc8 00002dc8
00000000000001f0 0000000000000010 WA 7 0 8
[24] .got PROGBITS 0000000000003fb8 00002fb8
0000000000000048 0000000000000008 WA 0 0 8
[25] .data PROGBITS 0000000000004000 00003000
0000000000000010 0000000000000000 WA 0 0 8
[26] .bss NOBITS 0000000000004010 00003010
0000000000000008 0000000000000000 WA 0 0 1
[27] .comment PROGBITS 0000000000000000 00003010
000000000000002a 0000000000000001 MS 0 0 1
[28] .symtab SYMTAB 0000000000000000 00003040
0000000000000618 0000000000000018 29 46 8
[29] .strtab STRTAB 0000000000000000 00003658
0000000000000202 0000000000000000 0 0 1
[30] .shstrtab STRTAB 0000000000000000 0000385a
000000000000011a 0000000000000000 0 0 1
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x00000000000002d8 0x00000000000002d8 R E 0x8
INTERP 0x0000000000000318 0x0000000000000318 0x0000000000000318
0x000000000000001c 0x000000000000001c R E 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x00000000000005f8 0x00000000000005f8 R E 0x1000
LOAD 0x0000000000001000 0x0000000000001000 0x0000000000001000
0x00000000000001f5 0x00000000000001f5 R E 0x1000
LOAD 0x0000000000002000 0x0000000000002000 0x0000000000002000
0x0000000000000160 0x0000000000000160 R E 0x1000
LOAD 0x0000000000002db8 0x0000000000003db8 0x0000000000003db8
0x0000000000000258 0x0000000000000260 RWE 0x1000
DYNAMIC 0x0000000000002dc8 0x0000000000003dc8 0x0000000000003dc8
0x00000000000001f0 0x00000000000001f0 RWE 0x8
NOTE 0x0000000000000338 0x0000000000000338 0x0000000000000338
0x0000000000000020 0x0000000000000020 R E 0x8
NOTE 0x0000000000000358 0x0000000000000358 0x0000000000000358
0x0000000000000044 0x0000000000000044 R E 0x4
GNU_PROPERTY 0x0000000000000338 0x0000000000000338 0x0000000000000338
0x0000000000000020 0x0000000000000020 R E 0x8
GNU_EH_FRAME 0x0000000000002014 0x0000000000002014 0x0000000000002014
0x0000000000000044 0x0000000000000044 R E 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RWE 0x10
GNU_RELRO 0x0000000000002db8 0x0000000000003db8 0x0000000000003db8
0x0000000000000248 0x0000000000000248 R E 0x1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
03 .init .plt .plt.got .plt.sec .text .fini
04 .rodata .eh_frame_hdr .eh_frame
05 .init_array .fini_array .dynamic .got .data .bss
06 .dynamic
07 .note.gnu.property
08 .note.gnu.build-id .note.ABI-tag
09 .note.gnu.property
10 .eh_frame_hdr
11
12 .init_array .fini_array .dynamic .got
可以看出,.fini节从
11e8
开始,大小为d
。下一部分-.rodata从2000
开始。这是否意味着11e8 + d
和2000
之间的空间不属于任何部分?该段也结束于11F5
,这是属于它的最后一个段的末尾-.fini
。编辑3:设法解决了这个问题-必须选择属于可执行段的段。仍然对节的大小有些困惑。
实际上设法将代码注入二进制文件中,但是,我从一个只有
.text
节的程序集中得到了指令:.text
.globl _start
_start:
#save the base pointer
pushq %rbp
pushq %rbx
mov %rsp,%rbp
#write syscall = 1
movq , %rax
#print to stdout
movq , %rdi
#9 character long string
movq , %rdx
# push "INJECTED\n" to the stack
movq q4312078qx0a, %rcx
pushq %rcx
movq q4312078qx44455443454a4e49, %rcx
pushq %rcx
movq %rsp, %rsi
syscall
#remove the string
pop %rcx
pop %rcx
movq q4312078q, %rax
movq q4312078q, %rdi
movq q4312078q, %rdx
pop %rbx
pop %rbp
ret
它在原始程序执行之前打印“ INJECTED”。当这种有效载荷起作用时,实现更好且实际可用的喷油器还有哪些其他想法?也许可以调用受害二进制文件链接的
libc
函数或某些其他库函数?因为似乎要从代码中获取实际指令,所以我们想注入,这有点麻烦。#1 楼
执行ELF文件时,OS加载程序不关心节,而只关心段(即程序头)。您需要确保您的代码属于可执行段。可以看到,.fini节从11e8开始,大小为d。
下一部分-.rodata从2000。这是否表示11e8 + d和2000之间的
空间不属于任何部分?该段也以11F5结尾,这是该段最后一个段的结尾-.fini。
是的,11F5和2000之间的空格是一种“无人区”。从理论上讲,这些字节将不会出现在内存中。但是,实际上,内存保护和映射以页面粒度(0x1000)起作用,因此这些字节被映射到内存中并且可以执行,因此您的补丁程序可以工作。为了使所有内容“合法”,最好将段的长度延长到2000。
评论
是的,谢谢。如果我错了,请纠正我,但查看readelf输出,.fini节从11e8开始,大小为d。下一部分从2000开始。实际上是否表示从11e8 + d到2000的空间不属于任何部分?
–纳扎尔·帕斯捷尔纳克(Nazar Pasternak)
20/11/28在13:24
@NazarPasternak对不起,我从这里看不到您的屏幕;)无论如何,您应该查看的是细分,而不是板块。
–伊戈尔·斯科钦斯基♦
20-11-28在13:25
@NazarPasternak只需将所有相关信息添加到问题中(也可以是段)
–伊戈尔·斯科钦斯基♦
20-11-28在13:27
是的,但是要弄清楚我的代码将驻留在哪个段中,我需要知道它当前在哪个段中:(
–纳扎尔·帕斯捷尔纳克(Nazar Pasternak)
20-11-28在13:28
评论
谢谢。您可以用代码段替换图像,以便于阅读和复制/粘贴吗?@IgorSkochinsky完成。还写了关于我的进度的另一个编辑。也许您会对如何实现更好的喷油器有一些想法?感谢您的帮助!
在边界上增加了答案。最好单独提出一个有关使用libc函数的问题。