当前位置:   article > 正文

全网最硬核PWN入门_图解分析

pwn入门

PWN知识只有不断的重复,实践才能熟悉掌握。以下知识点以LINUX系统环境下为主要说明(Windows的会有点区别)。

Linux环境下的基础知识

从C源码到可执行文件的生成过程

在这里插入图片描述

程序的编译与链接

在这里插入图片描述

什么是可执行文件

在这里插入图片描述

可执行文件分类PE/ELF

在这里插入图片描述

ELF文件格式

附:关于LINUX(Linux Foundation Referenced Specifications)

在这里插入图片描述

区分节和段的存储区域

在这里插入图片描述

加载ELF / 查看节和段区分布命令

在这里插入图片描述
注:这里有两条命令和分别查看磁盘和内存中的ELF节和段的分布。

  • 磁盘上查看节分布:objdump -s [elf文件]

  • 内存进程上查看段分布:
    方法一:
    可先 ,./elf文件 & //&后台进程挂起,显示pid
    然后,cat /proc/[pid]/maps //查看段分布

    方法二:
    gdb ./elf文件 //先gdb调试
    vmmap //查看段分布

段(segment)与节(section)

在这里插入图片描述

程序数据在内存中的组织分布

在这里插入图片描述
以上例子仅供参照。可以自己写一个demo然后调试一步一步查看相应信息。

大端序与小端序存储

在这里插入图片描述

关键寄存器

在这里插入图片描述
右图是CSAPP里面的,看不清没关系(网上一大堆),
关键了解最重要的三个寄存器作用:

  • RIP控制CPU执行指令
  • RSP,RBP控制函数栈帧区域(栈帧这里分享两篇硬核文章,就不重复造轮子了,好的资源就得充分利用。)

C语言函数调用栈(一)
C语言函数调用栈(二)
这两篇能帮你熟悉函数递归调用详细过程,同时了解PWN中栈利用最重要的一环知识—栈帧。
注:这两篇内容量对于初学者来说有点大,不过别灰心,只要肯多花时间一定能了解的大概(本人当初也是这么过来的,当你想放弃的时候就就参照笨笨的博主,当初我可是看了好多遍的。这样你总会信心倍增了吧,哈哈哈。)最后一点就是学习一起的最好动力就是兴趣(跟你智商高低没多大关系),如果你没兴趣,友情劝退还是别浪费时间了,这世界这么多选择,赶紧找个自己喜欢的方向发展才是对自己最好的。(哈哈哈,太哲学了,赶紧继续正题了)

静态链接与动态链接

  • 静态链接
    简单举例来说,就是你用的东西都是你自己买好的,专属于你。

在这里插入图片描述

  • 动态链接
    我用的东西都是借别人的,在需要的时候从有的地方借来用用就好了,跟别人共享着使用。

在这里插入图片描述

常用汇编指令影响范围(牢记)

  • leave等价
    mov esp, ebp;
    pop ebp

  • RETN 等价 POP EIP; sub sp, n //还起到平衡堆栈的作用
    改变ESP 和 EIP(near)

  • RETF等价pop eip;pop cs
    改变EIP和CS(far)

  • CALL 等价 PUSH [EIP+硬编码数]
    改变ESP 和 EIP

  • JMP 本质只改变eip

intel 和 AT&T汇编格式

这在我别的文章也有专门的讲解,这里简单对照即可。

  • intel
    opcode dst, src //源和目的操作位与AT&T正相反

  • AT&T
    opcodel src, dst //同时寄存器前多个%,l是代表long长整型
    在这里插入图片描述

溢出防护机制

全面了解保护机制
1. LINUX漏洞缓解机制介绍
2.推荐作者,分析的都很详细,文章例子在他文章里附的github链接里

PIE(Position-independent code)

  • 每次加载时,程序的基址libc的基址都发生变化。

在计算中,与位置无关的代码(PIC )或与位置无关的可执行文件(PIE)是机器代码的主体,它们被放置在主存储器中的某个位置,无论其绝对地址如何,都可以正确执行 。
PIC通常用于共享库,因此可以将相同的库代码加载到每个程序地址空间中不与使用中的其他内存(例如,其他共享库)重叠的位置。 PIC还用于缺少MMU的较旧的计算机系统上,因此,即使在无MMU的系统的单个地址空间内,操作系统也可以使应用程序彼此远离。

位置无关的代码必须使用相对寻址。

ASLR(Address space layout randomization)

  • 每次加载时,libc的基址发生变化。

地址空间布局随机化(ASLR)是一种计算机安全技术,可防止利用内存损坏漏洞。 为了防止攻击者可靠地跳转到内存中的某个特定漏洞利用功能,ASLR随机排列进程的关键数据区域的地址空间位置,包括可执行文件的基础以及堆栈,堆的位置 和共享库。
LINUX下关闭ASLR

echo 0 > /proc/sys/kernel/randomize_va_space
  • 1

NX bit (no-execute)

NX位(不执行)是一项用于CPU的技术,用于分隔内存区域,供处理器指令(代码)存储或数据存储使用,该功能通常仅在哈佛体系结构处理器中才能使用。 但是,出于安全原因,NX位越来越多地用于常规的von Neumann体系结构处理器中。

DEP( Data Execution Prevention)

操作系统的系统级内存保护功能。标记内存页为不可执行。

RELRO(RELocation Read-Only,只读重定位)

这个机制启动等级有部分开启和完全开启。

Canary

对抗canary策略

1,泄露canary值
2,泄露fs:28H内的值
3,覆写fs:28H副本值
4,劫持stack_chk_fail
5,stack smashing
6,逐字节爆破(BROP gadget,相对限制多)

GOT(global offset table)| PLT(procedure linkage table)

GOT和PLT的理解对漏洞成因分析是很重要的,同时理解也是很绕的,分享一下各位大神的分析(望大家多多支持各位作者的分享精神)

1.GOT表 和 PLT表[这篇看完基本做PWN题就能搞懂了]
2.这里附个视频讲解的,给看文字比较难懂的同学
3.二进制漏洞挖掘之栈溢出-开启RELRO[这篇分析的很详细,加深对LINUX保护机制的理解,后半部分理解需要一定的知识积累]
4.Linux二进制ELF程序查找symbol过程分析[这篇跟3类似,从保护机制上分析PLT和GOT的内容]

建议:为了加深理解印象,最好自己一步一步调试跟进去看看。

过程:
1,gdb调试看看got表,查看哪些函数还未被加载。
在这里插入图片描述
2,这里看个PUTS函数,下断

在这里插入图片描述
3,断下si跟进
在这里插入图片描述4,来到plt表
在这里插入图片描述
5,重新运行,直接n步过
在这里插入图片描述
6,继续看看got表

在这里插入图片描述
已被填入puts真正地址
在这里插入图片描述

7,查看上面plt表中第一个jmp [got表里面的地址](0x804a014)

在这里插入图片描述
结论:plt 表中,jmp [地址]。
第一次还未装载函数时,地址=got表地址(去找到函数真正地址);
第二次执行,地址=函数真正地址。

泄露libc地址

原理:动态连接程序中,本程序中含有的函数达不到需要实现的目的,需要借助动态链接库中的函数实现其目的。

查找使用的动态链接库信息

原理:由于在分页机制,在LINUX系统下是以4k为单位,即12位(2^12=4k),所以利用此规则,即便开启了地址随机化保护机制,地址的后三位(在页中的偏移)也是不变的。
下图举例说明:
在这里插入图片描述然后在在线libc库查就好了
在这里插入图片描述
这里的offset都是偏移RVA。还需要得出
基址=puts(VA) - puts(offset)

在线工具网站1
在线工具网站2

注:当然方法还有别的,只要达到目的都可行。

工具

ldd

1.概述>
ldd命令 用于打印程序或者库文件所依赖的共享库列表。

2.语法>
ldd(选项)(参数)

选项

--version:打印指令版本号;
-v:详细信息模式,打印所有相关信息;
-u:打印未使用的直接依赖;
-d:执行重定位和报告任何丢失的对象;
-r:执行数据对象和函数的重定位,并且报告任何丢失的对象和函数;
--help:显示帮助信息。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

参数
文件:指定可执行程序或者文库。

3.实例>
在这里插入图片描述
红色标记处是一个软链接(相当于win下的快捷键)
可到/lib/x86_64-linux-gnu/目录下
命令:file libc.so.6查看链接属性

4.原理补充说明

首先ldd不是一个可执行程序,而只是一个shell脚本。

ldd能够显示可执行模块的dependency,其原理是通过设置一系列的环境变量。

ldd显示可执行模块的dependency的工作原理,其实质是通过ld-linux.so(elf动态库的装载器)来实现的。我们知道,ld- linux.so模块会先于executable模块程序工作,并获得控制权,因此当上述的那些环境变量被设置时,ld-linux.so选择了显示可执行模块的dependency。

实际上可以直接执行ld-linux.so模块,如:/lib/ld-linux.so.2 --list program(这相当于ldd program)

objdump

objdump 有点像那个快速查看之类的工具,就是以一种可阅读的格式让你更多地了解二进制文件可能带有的附加信息。对于一般只想让自己程序跑起来的程序员,这个命令没有更多意义,对于想进一步了解系统的程序员,应该掌握这种工具,至少你可以自己写写shellcode了,或者看看人家给的 exploit 中的 shellcode 是什么东西。

常用命令选项:

  • objdump -D -b binary -m i386 [file]
    -D表示对全部文件进行反汇编;
    -b表示二进制;
    -m表示指令集架构;
    file就是我们要反汇编的二进制文件;
    同时我们也可以指定big-endian或little-endian(-EB或-EL);

objdump -f [file] *显示file的文件头信息;

objdump -t file *输出目标文件的符号表;

objdump -h file *显示file的Section Header信息;

objdump -x file 显示file的全部Header信息;

-S file *输出目标文件的符号表, 当gcc -g时打印更明显;[S大写]
-s file 除了显示file的全部Header信息,还显示他们对应的十六进制文件代码;

-d file *反汇编file中的需要执行指令的那些section;
-D file 与-d类似,但反汇编file中的所有section;

-R *显示动态链接重定位信息;
-r 显示重定位信息;

objdump -s libc.so>test.txt 输出到txt文件

  • 查看PLT表
    objdump -d -j .plt file
  • 查看GOT表
    objdump -R file

注:*号的一帮经常用。

readelf

1.概述>
readelf命令,一般用于查看ELF格式的文件信息,常见的文件如在Linux上的可执行文件,动态库(.so)或者静态库(.a) 等包含ELF格式的文件。

2.常用参数>
语法:readelf (选项)(file)
-h (elf header),显示elf文件开始的文件头信息。
-l (program headers),segments 显示程序头(段头)信息(如果有数据的话)。
-S (section headers),sections 显示节头信息(如果有数据的话)。
-g (section groups),显示节组信息(如果有数据的话)。
-s (symbols) 显示符号表段中的项(如果有数据的话)。
-e headers 显示全部头信息,等价于: -h -l -S 。
-r relocs 显示可重定位段的信息。
-d dynamic 显示动态段的信息。
-V version-info 显示版本段的信息。

附:命令参数参考:GNU Binary Utilities(英文版)

ROPgadget

概述>
查找文件中一些需要的指令字符串等。

看帮助手册吧
命令:ROPgadget -h

常用命令

ROPgadget --binary [file] --string [...]	//后面根据需要自己补充,如下另一个使用例子
ROPgadget --binary 文件名 --only "pop|ret" | grep rdi
  • 1
  • 2

GCC

工具篇_GCC

补充常用保护相关参数

-no-pie:关闭地址随机化

-fno-stack-protector:关闭堆栈保护

-z execstack:堆栈可执行

-m32: 生成32位文件
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

GDB

工具篇_GDB

[附] vim查看文件二进制数据

命令行模式下:
%!xxd [-g 1] 转换成16进制模式看 //[ ]内可选
%!xxd -r 还原

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/260226?site
推荐阅读
相关标签
  

闽ICP备14008679号