一:首先来了解一下linux下常见的攻击缓解机制:

CANARY:(金丝雀值,指的是矿工曾利用金丝雀来确认是否有气体泄漏,如果金丝雀因为气体泄漏而中毒死亡,可以给矿工预警),类似于windows GS技术,当栈溢出发生时,canary值将在已保存的指令指针被重写前先改变。系统检测这个值是否改变,栈溢出发生了,保存的指令指针可能也被修改了,因此不能安全返回,函数会调用__stack_chk_fail函数。这个函数会丢出一个错误然后退出进程。缺点:仅保护了sip,未保护应用变量,覆写GOT绕过。
FORTIFY:Compile Time Buffer Checks,确定函数执行栈的大小,以避免缓冲区溢出攻击。
NX:No Execute.现代处理器支持一种称为NX的特性使得系统控制各部分的执行的内存。即程序栈不可执行。
PIE:随机化加载程序的内存地址。
RELRO:RELocation Read-Only (RELRO) 重定位只读,它能够保护库函数的调用不受攻击者重定向的影响。
——————–
二.ELF动态装载机制详解:
从栈上执行shellcode到NX,从return2libc到ASLR, 从ROP泄露内存地址RELRO,攻与守的对抗技术在不断升级,进而催生出一种有效的针对没有libc文件和system函数的情况下实施ROP攻击的方法——return to dl-resolve。
一个应用由elf二进制文件和数个动态库构成,它们都是elf格式, ELF符号(函数或全局变量)使用elf_ sym结构体描述,[st_name]为相对.dynstr段开始的偏移,[st _info]为导出后函数的虚拟地址(没导出时为null)elf解析流程如图:

.rel.plt结构体定义:

typedef uint32_t Elf32_Addr;
typedef uint32_t Elf32_Word;
typedef struct
{
Elf32_Addr r_offset; /* Address */
Elf32_Word r_info; /* Relocation type and symbol index */
} Elf32_Rel;
#define ELF32_R_SYM(val) ((val) >> 8)
#define ELF32_R_TYPE(val) ((val) & 0xff) .dynsym结构体定义: typedef struct
{
Elf32_Word st_name; /* Symbol name (string tbl index) */
Elf32_Addr st_value; /* Symbol value */
Elf32_Word st_size; /* Symbol size */
unsigned char st_info; /* Symbol type and binding */
unsigned char st_other; /* Symbol visibility under glibc>=2.2 */
Elf32_Section st_shndx; /* Section index */
} Elf32_Sym;

我们readelf -d 查看JUMPREL(.rel.plt)段的地址如图:

# readelf -d pwn1

Dynamic section at offset 0xf14 contains  entries:
标记 类型 名称/值
0x00000001 (NEEDED) 共享库:[libc.so.]
0x0000000c (INIT) 0x804837c
0x0000000d (FINI) 0x80486e4
0x00000019 (INIT_ARRAY) 0x8049f08
0x0000001b (INIT_ARRAYSZ) (bytes)
0x0000001a (FINI_ARRAY) 0x8049f0c
0x0000001c (FINI_ARRAYSZ) (bytes)
0x6ffffef5 (GNU_HASH) 0x80481ac
0x00000005 (STRTAB) 0x8048280
0x00000006 (SYMTAB) 0x80481d0
0x0000000a (STRSZ) (bytes)
0x0000000b (SYMENT) (bytes)
0x00000015 (DEBUG) 0x0
0x00000003 (PLTGOT) 0x804a000
0x00000002 (PLTRELSZ) (bytes)
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0x804833c
0x00000011 (REL) 0x804832c
0x00000012 (RELSZ) (bytes)
0x00000013 (RELENT) (bytes)
0x6ffffffe (VERNEED) 0x804830c
0x6fffffff (VERNEEDNUM)
0x6ffffff0 (VERSYM) 0x80482f4
0x00000000 (NULL) 0x0
  readelf -S 查看rel节的信息:
# readelf -S pwn1
共有 30 个节头,从偏移量 0x1160 开始: 节头:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
[ ] NULL
[ ] .interp PROGBITS A
[ ] .note.ABI-tag NOTE A
[ ] .note.gnu.build-i NOTE A
[ ] .gnu.hash GNU_HASH 080481ac 0001ac A
[ ] .dynsym DYNSYM 080481d0 0001d0 0000b0 A
[ ] .dynstr STRTAB A
[ ] .gnu.version VERSYM 080482f4 0002f4 A
[ ] .gnu.version_r VERNEED 0804830c 00030c A
[ ] .rel.dyn REL 0804832c 00032c A
[] .rel.plt REL 0804833c 00033c A
[] .init PROGBITS 0804837c 00037c AX
[] .plt PROGBITS 080483a0 0003a0 AX
[] .text PROGBITS 0002b2 AX
[] .fini PROGBITS 080486e4 0006e4 AX
[] .rodata PROGBITS 080486f8 0006f8 A
[] .eh_frame_hdr PROGBITS 00002c A
[] .eh_frame PROGBITS 0000c0 A
[] .init_array INIT_ARRAY 08049f08 000f08 WA
[] .fini_array FINI_ARRAY 08049f0c 000f0c WA
[] .jcr PROGBITS 08049f10 000f10 WA
[] .dynamic DYNAMIC 08049f14 000f14 0000e8 WA
[] .got PROGBITS 08049ffc 000ffc WA
[] .got.plt PROGBITS 0804a000 00002c WA
[] .data PROGBITS 0804a02c 00102c WA
[] .bss NOBITS 0804a040 WA
...
  readelf -r 查看程序的链接库函数:
readelf -r pwn1

重定位节 '.rel.dyn' 位于偏移量 0x32c 含有 2 个条目:
 Offset     Info    Type            Sym.Value  Sym. Name
08049ffc R_386_GLOB_DAT __gmon_start__
0804a040 R_386_COPY 0804a040 stdout
重定位节 '.rel.plt' 位于偏移量 0x33c 含有 8 个条目: Offset Info Type Sym.Value Sym. Name 0804a00c 00000107 R_386_JUMP_SLOT 00000000 read 0804a010 00000207 R_386_JUMP_SLOT 00000000 __gmon_start__ 0804a014 00000307 R_386_JUMP_SLOT 00000000 strchr 0804a018 00000407 R_386_JUMP_SLOT 00000000 __libc_start_main 0804a01c 00000507 R_386_JUMP_SLOT 00000000 write 0804a020 00000607 R_386_JUMP_SLOT 00000000 setvbuf 0804a024 00000707 R_386_JUMP_SLOT 00000000 atoi 0804a028 00000807 R_386_JUMP_SLOT 00000000 shutdown 

readelf -s 查看.dynsym(运行时所需)和.symtab(编译时的符号信息)节区信息:

# readelf -s pwn1

Symbol table '.dynsym' contains  entries:
Num: Value Size Type Bind Vis Ndx Name
: NOTYPE LOCAL DEFAULT UND
: FUNC GLOBAL DEFAULT UND read@GLIBC_2. ()
: NOTYPE WEAK DEFAULT UND __gmon_start__
: FUNC GLOBAL DEFAULT UND strchr@GLIBC_2. ()
: FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2. ()
: FUNC GLOBAL DEFAULT UND write@GLIBC_2. ()
: FUNC GLOBAL DEFAULT UND setvbuf@GLIBC_2. ()
: FUNC GLOBAL DEFAULT UND atoi@GLIBC_2. ()
: FUNC GLOBAL DEFAULT UND shutdown@GLIBC_2. ()
: 0804a040 OBJECT GLOBAL DEFAULT stdout@GLIBC_2. ()
: 080486fc OBJECT GLOBAL DEFAULT _IO_stdin_used
Symbol table '.symtab' contains  entries:
Num: Value Size Type Bind Vis Ndx Name
: NOTYPE LOCAL DEFAULT UND
: SECTION LOCAL DEFAULT
...

下面看下重定位过程:.symtab(编译时符号地址)+RELSZ对应于.dynsym(运行时符号地址)的偏移,.dynstr中的st_name的地址对应于STRTAB+.dynsym中的偏移:

gdb-peda$ x/x 0x80481d0(SYMTAB)+
0x80481e0: 0x0000001a
gdb-peda$ x/s 0x8048280(STRTAB)+0x1a
0x804829a: "read"

查看.rel.plt的read函数汇编:

gdb-peda$ x/5i read
0x80483b0 <read@plt>: jmp DWORD PTR ds:0x804a00c
0x80483b6 <read@plt+>: push 0x0
0x80483bb <read@plt+>: jmp 0x80483a0
0x80483c0 <__gmon_start__@plt>: jmp DWORD PTR ds:0x804a010
0x80483c6 <__gmon_start__@plt+>: push 0x8
gdb-peda$ x/wx 0x804a00c
0x804a00c <read@got.plt>: 0x080483b6

由于延迟绑定的机制,第一次调用read函数时寻找真正位置进行绑定。当我们第一次调用read时,其对应的GOT表里并没有存放read的真实地址,而是下一条指令的地址。第二、三行,把reloc_arg=0x0作为参数推入栈中,跳到0x80483a0继续执行。跟随:

gdb-peda$ x/10i 0x80483a0
0x80483a0: push DWORD PTR ds:0x804a004
0x80483a6: jmp DWORD PTR ds:0x804a008

0x80483a0把(link map = *(GOT+4))压栈,*(GOT+8)保存着 _dl runtime _resolve函数的地址,该函数将真实read地址写入GOT,随后将控制权转交read函数

_dl_runtime_resolve(link_map, rel_offset);

根据rel_offset找到rel _entry:

Elf32_Rel * rel_entry = JMPREL + rel_offset;

由rel_entry->r_info定位符号信息

Elf32_Sym *sym_entry = SYMTAB[ELF32_R_SYM(rel_entry->r_info)];

再定位符号信息中的符号名:

char *sym_name = STRTAB + sym_entry->st_name;

根据得到的符号名搜索动态库,找到地址后填充至.got.plt对应位置。
三.攻击过程分析
逆向思维:
1.控制*sym_name(改为system)需要控制*sym_entry;
2.再前面就是控制*rel_entry;
正向思维:
1.通过将eip覆盖为.rel.plt地址,传递一个可控的rel _offset,使rel_entry落在可控区域;
2.伪造rel_entry使sym_entry落在可控区域,伪造sym_entry使sym_name落在可控区域;
3.伪造sym_name为‘system’

参考文献:
1. http://www.freebuf.com/author/fubeerf
2.https://fedoraproject.org/wiki/Security_Features?rd=Security/Features
3. http://www.inforsec.org/wp/?p=389
4. http://rk700.github.io/article/2015/08/09/return-to-dl-resolve
5. http://drops.wooyun.org/binary/14360

pwn学习之dl_resolve学习篇的更多相关文章

  1. 从零开始学习jQuery (一) 入门篇

    本系列文章导航 从零开始学习jQuery (一) 入门篇 一.摘要 本系列文章将带您进入jQuery的精彩世界, 其中有很多作者具体的使用经验和解决方案,  即使你会使用jQuery也能在阅读中发现些 ...

  2. RabbitMQ学习总结 第三篇:工作队列Work Queue

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  3. XMPP学习记录之实战篇

    在学习iOS以来一直想要研究即时聊天方面的技术,因工作原因此计划一直搁浅,近日偷得时闲开始着手与XMPP的学习.在学习之前我一直认为XMPP对我来说是一个很有难度的挑战,在了解了协议的具体形式后,才发 ...

  4. [原]零基础学习视频解码之android篇系列文章

    截止今天,<零基础学习视频解码系列文章>.<零基础学习在Android进行SDL开发系列文章>以及<零基础学习视频解码之android篇>系列文章基本算是告一段落了 ...

  5. RabbitMQ学习总结 第四篇:发布/订阅 Publish/Subscribe

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  6. RabbitMQ学习总结 第五篇:路由Routing

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  7. RabbitMQ学习总结 第六篇:Topic类型的exchange

    目录 RabbitMQ学习总结 第一篇:理论篇 RabbitMQ学习总结 第二篇:快速入门HelloWorld RabbitMQ学习总结 第三篇:工作队列Work Queue RabbitMQ学习总结 ...

  8. 学习KnockOut第三篇之List

    学习KnockOut第三篇之List 欲看此篇---------------------------------------------可先看上篇.          第一步,先搭建一个大概的框架起来 ...

  9. Noah的学习笔记之Python篇:命令行解析

    Noah的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 3.命令行解析 注:本文全原创,作者:Noah Zhang  (http://www.cnblogs.com/noahzn/) ...

随机推荐

  1. 如何完全卸载SQL Server 2005

    用过SQL Server 2005的朋友都应该知道,不管是安装还是完全卸载都是件很头疼的事情. 下面跟大家分享一下如何完全卸载SQL Server 2005(手动卸载步骤哦~~). 一.停止sql的服 ...

  2. FTP链接mac

    mac下一般用smb服务来进行远程文件访问,但要用FTP的话,高版本的mac os默认关掉了,可以用如下命令打开: sudo -s launchctl load -w /System/Library/ ...

  3. Swift - 37 - 值类型和引用类型的简单理解

    //: Playground - noun: a place where people can play import UIKit // 值类型:指的是当一个变量赋值给另外一个变量的时候, 是copy ...

  4. ajax+FormData+javascript 实现无刷新表单注册

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  5. PHP iconv()编码转换函数用法示例

    PHP iconv()字符编码转换函数的用法,iconv()函数,在php5中是内置的,语法格式:iconv("UTF- 8","GB2312//IGNORE" ...

  6. 【行为型】Command模式

    命令模式是指将用户的请求封装成(命令)对象,从而可将用户不同的请求进行参数化.对这些请求排序或记录请求日志.以及支持回滚恢复操作.记得以前刚开始使用Photoshop时,就发现它的操作历史记录面板特别 ...

  7. 11061160_11061151_Pair Project: Elevator Scheduler软件工程结对编程作业总结

    软件工程结对编程作业总结 11061160  顾泽鹏 11061151  庞梦劼 一.关于结对编程 这次的软工任务既不是单打独斗的个人任务,也不是集思广益的团队项目,而是人数为两人的结对编程.两个人合 ...

  8. jsp语法与标签

    语法: <% 多行java代码 %> 在一个JSP页面中可以有多个脚本片断,在两个或多个脚本片断之间可以嵌入文本.HTML标记和其他JSP元素. 举例: <% int x = 10; ...

  9. 【学习笔记】【oc】类的包装类 协议 category

    1.类的两种包装类: 将基本数据包装成对象:NSValue:NSNumber; NSValue是NSNumber的父类, NSValue用来封装一些基本数据, NSValue是一个通用的包装类,用来包 ...

  10. html文字有光晕

    <style> .tb{ font-size:40px; filter:glow(color=pink,direction=); font-family:华文行楷; } </styl ...