注明:本篇学习笔记是入门学习pwn时的随笔,所以不具有任何参考价值 ,仅作为对学习路线回顾参考的笔记以及入门纪念。
使用 Kali Linux , 称霸局域网 ![doge]
调试,调试!
Ida中的静态调试显示的函数和输出之间的距离,有时候会因为各种原因而显示错误,需要用pwndbg动态调试观察一下。淦,gdb显示的地址有时候也不对
IDA基本操作 (静态调试)
shift + F12
space
F5
ctrl + F
Pwndbg基本操作(动态调试)
Pwndbg + 文件名 进入对某个文件的调试
r 运行
b + 地址/函数 设置断点
checksec + 文件名 查看保护措施
stack + 数字 查看栈段
vmmap' 显示虚拟内存的的空间分布(观察读写的权 限是否有冲突-w与x不同时出现
plt 查看文件里的plt表项
x + 地址 显示该地址的内容和地址
got 查看got中保存的函数数量及其字节、数据等信息
disass + 地址 反汇编地址的数据,进而查看其汇编代码或plt
c 继续执行程序,直到遇到断点/程序中断
start 开始执行程序,会停到main函数;如果没有main函数,则会停到程 序的入口
s 附近
backtrace 显示函数调用栈段的状态
return 快速回到mian函数
求求了,用用py吧
(context.arch = “amd64”) 调整攻击环境
shellcode.sh()
print(xxx) 更清楚地查看shellcode
print(asm(xxx)) 查看shellcode的机器码
获取shellcode : 1.shellstore 2.pwntools – shellcraft.sh() (后面就是方法)
Print(asm(shellcode.(amd64.)sh()))
嘿嘿嘿·,脚本(介绍一下大致模板,最简单的那种啊,别误会)
vim exp.py
from pwn import *
(context.arch = "amd64")
io = process("本地文件路径") //与本地文件交互
OR
io = remote("IP", 端口 )
io.recvline() //接受程序给的文件
payload = b'”x”(字节型的数据) + p32(劫持程序的地址) //将一个整数的地址转化成字节型的数据 32位的 ebp占4个字节,64位的·ebp占8个字节
io.send(payload) //发送数据
OR
io.sendline(payload) //发送一行数据,相当于在数据末尾加/n;
io.interactive() //交互
from pwn import *
(context.arch = "amd64")
io = process("本地文件路径") //与本地文件交互
OR
io = remote("IP", 端口 )
io.recvline() //接受程序给的文件
asm(shellcode.(amd64.)sh()) //获取shellcode的机器码
payload = asm( shellcode.(amd64.)sh()),lhust( 112, b’A ) /*补充字节流(这里就是A )到112 */ + p32( 劫持程序的地址(可以是全局变量的地址) )
io.send(payload) //发送数据
OR
io.sendline(payload) //发送一行数据,相当于在数据末尾加/n;
io.interactive() //交互
还有很多呐!
呐,shellcode注意啥啊
bss默认可执行,因此我们可以通过全局变量向其输入shellcode
gets 漏洞
未初始化的全局变量保存在bss里
不会算数,py来救
使用python计算栈段之间的距离
0x….(高地址) – 0x…(低地址)
>>>十进制数
Hex(十进制)
>>>十六进制
保护措施
1-NX 栈不可执行
2-ASLR 让函数的栈、共享连接库、堆段进行地址随机化,
0 – 未打开;1 – 部分随机化;2 – 全部随机化
关闭ASLR – “echo 0 > /proc/sys/kernel/randomize_va_space”
3-Canary(金丝雀) 在调用一个函数,刚创建栈帧时,首先把一个值(canary)放在低地址空间里,在销毁 函数时,先检查这个值(canary)是否发生改变,如果值改变,就会其强行将程序退出
4-Pie 编译时打开开关,随机化elf文件映像(text,bss。data)
程序进不去怎么办
修改文件权限
#!/bin/sh
gcc -fno-stack-protector -z execstack -no-pie -g -o re2stack ret2stack.c
-fno-stack-protector 关闭canary,使栈溢出首先可行
-z execstack 打开栈的可执行权限
-no-pie 关闭pie
-g 带上调试信息,便于观看(一定要带着re2stack.c)
-o 输出文件名
请问字节是啥
8比特 – 1 字节
每4比特可以直接写成一个16进制的值,
每两个16进制数就是1个字节
ROP!!!
没有连续的代码,但是通过一段一段的这个函数中包含的代码片段,达到相同的执行效果,即模拟程序的执行
其中思想的不同:没有一步到位的地址一次覆盖到tet,调用shell(即调用shell攻击目标,无法通过一个地址一次,所以需要,自己将程序中的指令组合起来,起到shell的作用)
我们所需要的为eaxebx…赋值的代码本来就存在,但是不连续,我们需要把他们组成一个链式结构(gadget),所以需要溢出很长的一段数据,把这些调成想要的格式,使其能够连续工作,并使其最后一条指令为ret。
对于系统调用,要在所有以ret结尾的代码中,找出个代码片段,它们的作用分别是pop eax、pop ebx、pop ecx、pop edx,pop一个寄存器的指令可以将数值直接写到栈上
PS:系统调用 —— 本质上只是一段函数,X86使用中断进行系统调用,第一个栈帧是main函数的栈帧,在main函数之前执行的所有函数都是没有栈帧的
ret2syscall
因为需要执行大量代码段,故通过局部变量溢出, 组合一些gadget执行大量的代码片段,故将从ret开始的一大段栈空间,覆盖成gadget地址和对应的参数,此时,在main函数返回时,就会返回到已经被覆盖掉的,现在是ret的地址, 并执行指令
(ret把当前栈顶的值pop到eip)ret等效于pop eip
get --binary 文件名 -- only “ pop | ret 要寻找的指令|管道符 grep xx 把输入参数中含有xx的命令显示出来
Ret = pop xxx 即把xxx弹出到eip
Xor 清空寄存器
下面是示例!
Int 0x80 ( eax = 0xb , ebx = …, ecx = 0,edx = 0 )进行系统调用( int – 中断指令 ),通过寄存器传参,来确定要调用哪一个函数。在执行int 0x80 这个汇编代码对应的机器码时,要确保四个寄存器都已经存储了对应的函数所需要的参数,即0xb这一个系统调用号对应的sys_execve() 对应的内核里的函数的调用号,而0xb 在这里·也带代表了那个函数
下面使用pwntools便捷获取/bin/sh的地址
使用next传入生成器
最后一层是要输入的垃圾数据,倒数第三行是要给
倒数第二层输入的数据,以此类推
动态链接
当我们使用file命令去查看一些文件的属性时,下面两点也会被显示出来:
动态链接:gcc -fno-pie -o dytest xxx.py dynamically link
静态链接:gcc -fno-poe --static -o statest xxx.py statically link
本块主要讨论动态链接
动态链接相关结构
dynamic section 为操作系统描述了整个动态链接的完整内容
提供动态链接相关信息
link_map 保存进程载入的动态链接库的链表
dl_runtime_resolve 解析第一次在动态链接的函数的真实地址
装载器中用于解析动态链接库中函数的实际地址的函数
got 全局的符号、变量地址
got.plt 全局的函数地址
动态占用内存小(其库函数占用少)
动态链接过程
ldd 文件名 查看文件用到的所有动态链接库
下面分流程分析
text —— 代码节;foo@olt —— foo是自己写的函数;plt是代码段中存放函数真实地址的一个节; PLT0(PLT最开始的两段指令)
因为foo是个动态链接库中的代码,所以call foo,并不能直接跳转到它自己代码段里的foo函数,只能去代码段中的plt节,而每个被调用的动态链接库中的函数都会在其中创立一个表项,
1、call foo@plt 进程首次调用 foo
2、jmp *(foo@GOT) 跳转到 .plt 中的 foo 表项,plt 中的代码立即跳转到.got.plt 中记录的地址
3、push 由于进程是第一次调用 foo,故.got.plt 中记录的地址是 foo@plt+1
4、jmp 回到 .plt 是,解析 foo 的实际地址
5、push *(GOT+4) 跳转到 .plt 头部,为 dl_runtime_resolve 函数传参
6、push *(GOT+4) 跳转到 .plt 头部,为 dl_runtime_resolve 函数传参
7、call_fix_up dl_runtime_resolve 函数解析 foo 的真正地址填入 .got.plt 中
8、ret 0xc 此后 .got.plt 中保存的是 foo 的真实地址
9、call foo@plt 系统第二次调用foo
10、jum *(foo@GOT) 直接自 .got.plt 跳转到 foo 的真实地址,没有了第一次的解析地址过程
ok,接下来展示完整流程
IDA的细节
init 用作初始化的一个节,记录了初始化代码
plt 存放函数真实地址的一个节
got 存放数据的节
ret2libc
往往依赖于rop所需要的各种gadget创造执行shellcode的环境,但其目标是返回libc里的system函数这一类可以为我们提供一个shell的函数