BUUCTF PWN wp--[第五空间2019 决赛]PWN5

第一步  checksec ,本题为32位

分析一下保护机制:

  1. Arch: i386-32-little
    • 程序是为32位的i386架构(即Intel 80386及其兼容处理器)编译的,并且使用的是小端字节序(little-endian)。
  2. RELRO: Partial RELRO
    • RELRO(Relocation Read-Only)是一种安全特性,用于减少对全局偏移表(GOT)的攻击。它分为两种:Partial RELRO和Full RELRO。
    • Partial RELRO意味着程序的某些部分(如.dynamic段)是只读的,但并不是全部。意味着攻击者可能仍然能够修改GOT中的某些条目,但难度比没有RELRO时要大。
  3. Stack: Canary found
    • 栈保护是一种防止栈溢出攻击的机制。Canary(金丝雀)是一种特殊的值,它在函数返回之前被放置在栈帧的局部变量和返回地址之间。如果发生栈溢出,Canary值会被覆盖,程序检测到Canary值改变后,会立即终止,从而防止攻击者通过覆盖返回地址来执行任意代码。
  4. NX: NX enabled
    • NX(No eXecute)是一种硬件特性,用于将内存区域标记为不可执行。这意味着即使攻击者能够将恶意代码注入到程序的内存中,也无法执行这些代码,因为标记为NX的内存区域不允许执行指令。
  5. PIE: No PIE (0x8048000)
    • PIE(Position Independent Executable)是一种安全特性,它使得程序的代码可以在加载时随机化其内存地址,从而增加攻击者预测内存地址的难度。
    • No PIE意味着程序没有使用PIE,其代码段加载地址是固定的(0x8048000)。这增加了攻击者利用固定地址进行攻击的可能性。

第二步  进入主函数

重点分析一下16-32行代码:

fd = open("/dev/urandom", 0);

  • 这行代码打开了一个特殊的设备文件/dev/urandom,该文件提供了高质量的随机数。open函数的第二个参数是模式,通常应该使用O_RDONLY来表示只读模式,但这里直接使用了数字0,这在大多数系统上等同于O_RDONLY。

read(fd, &dword_804C044, 4u);

  • 从/dev/urandom读取4个字节的数据到变量dword_804C044中。这个变量似乎是一个全局变量,其地址是硬编码的(例如,在ELF文件中,地址可能是一个固定的地址)。

 

printf("your name:");

  • 输出提示信息,询问用户的名字。

 

read(0, buf, 0x63u);

  • 从标准输入(文件描述符0)读取最多99个字节(0x63是99的十六进制表示)到缓冲区buf中。这里没有检查read的返回值,也没有检查缓冲区溢出的可能性,这是一个潜在的安全风险。

 

printf("Hello,");

  • 输出问候语。

 

printf(buf);

  • 输出用户输入的名字。由于之前没有对buf进行任何处理,这里存在一个格式化字符串漏洞!!!,攻击者可以构造输入来利用这个漏洞。

 

printf("your passwd:");

  • 输出提示信息,询问用户的密码。

 

read(0, nptr, 0xFu);

  • 从标准输入读取最多15个字节(0xF是15的十六进制表示)到缓冲区nptr中。这里同样没有检查read的返回值,也没有检查缓冲区溢出的可能性。

 

if ( atoi(nptr) == dword_804C044 )

  • 使用atoi函数将nptr指向的字符串转换成整数,并与之前从/dev/urandom读取的随机数进行比较。(因此我们构建攻击载荷的地址即为dword_804C044的地址=0x804C044

 

{

  puts("ok!!");

  system("/bin/sh");

}

  • 如果输入的整数与随机数相等,则输出"ok!!"并执行/bin/sh,给予攻击者一个shell。

第三步  因为该题存在格式化字符串漏洞,所以我们使用输入AAA来确定偏移量的方法(如图所示,该偏移量位10)

地址有了,偏移量有了,开始编写脚本

第四步  

详细分析一下:

from pwn import*

  • 这行代码导入了pwntools库中的所有模块。pwntools是一个强大的工具集,它提供了很多用于二进制分析和利用的功能。

 

io.recvuntil(':')

  • recvuntil函数用于从远程服务器接收数据,直到指定的字符串(在这个例子中是':')被接收到为止。这通常用于同步,确保脚本在正确的时刻发送或接收数据。

 

payload = p32(0x804C044) + b'%10$n'

  • 这里构造了一个payload。p32函数将32位整数转换为其小端序的字符串表示,这里转换的是地址0x804C044,这个地址应该是之前提到的全局变量dword_804C044的地址。
  • b'%10$n'是一个格式化字符串,它告诉printf函数将第10个参数的值写入到指针指向的地址。在格式化字符串漏洞利用中,这通常用于写入任意值到任意地址。
  • 在这个上下文中,%10$n表示写入的值将是printf的第10个参数,但由于p32(0x804C044)没有在printf调用中作为参数,它实际上利用了格式化字符串漏洞,将栈上的某个值写入到地址0x804C044。

 

io.sendline(payload)

  • 将构造的payload发送到远程服务器。由于之前调用了recvuntil(':'),这个payload将作为用户的名字发送。

 

io.recvuntil(':')

  • 再次接收数据,直到遇到':',这次是为了同步到密码提示。

 

io.sendline('4')

  • 发送字符串'4'作为密码。这是因为在格式化字符串漏洞利用中,我们已经将dword_804C044的值覆盖为了4(或者至少我们希望是这样),所以输入'4'应该会使atoi(nptr) == dword_804C044的条件成立。

 

io.interactive()

  • 这行代码将脚本切换到交互模式,允许用户与远程服务器进行交互。如果之前的利用成功,这将提供一个shell。

运行成功

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

无 双

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

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

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

打赏作者

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

抵扣说明:

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

余额充值