18.9.19 Jarvis OJ PWN----Smashes

先checksec一下

我的天,有栈保护,nx,咋办……

IDA进去,我们可以看见有个函数挺关键的,如下

我们可以看到stdin是可以无限输入的,但是只有接收输入时接收到'\n',才会继续执行(跳出while循环),找不出栈溢出的办法

然后看了大佬的操作之后发现:可以故意触发canary来攻击(SSP(Stack Smashing Protector ) leak)

先介绍一下好了,SSP外号叫金丝雀。应对“栈溢出”(也称缓存区溢出),需要一些对策。比如GCC的“Stack-Smashing Protector”机制(在数组后插入一些金丝雀(Canary, 因为大家在矿井作业时,会用金丝雀来预警,如果金丝雀死了,那证明有毒气),在函数执行完成返回之前会检查一下Canary,如果canary被改掉,则不再继续执行,中止程序,避免执行攻击者的代码。

在IDA中我们可以看到这个check canary的函数,如下图

我先去搜了一下函数_stack_chk_fail(从大佬那边看来的源码,链接:https://veritas501.space/2017/03/10/JarvisOJ_WP/)

void 
__attribute__ ((noreturn)) 
__stack_chk_fail (void) {   
    __fortify_fail ("stack smashing detected"); 
}

void 
__attribute__ ((noreturn)) 
__fortify_fail (msg)
   const char *msg; {
      /* The loop is added only to keep gcc happy. */
         while (1)
              __libc_message (2, "*** %s ***: %s terminated\n", msg, __libc_argv[0] ?: "<unknown>") 
} 
libc_hidden_def (__fortify_fail)

我们可以看到有个很关键的参数教_libc_argv[0],这是指向第一个启动参数的指针,我们在覆盖的时候也覆盖掉,那不就,就可以输出我们想要的了

可能有些人有点懵,启动参数作用是什么,我起始也不是特别了解,但是我们平时自己编写main函数的时候,是不是基本不加参数,但其实有时候已经帮你添加好了,我们来看一下main函数的原型:

int main(int argc,char* argv[])
{
   return 0;
}

VC++6.0会给你默认的启动函数,所以main函数的那两个参数是不用输的,但是每当调用默认启动函数中提供的函数是,都要调用第二个参数,所以说覆盖argv[0],即使有栈保护,也可以输出我们想要的

接下来我们要找一下flag在哪里,总不可能让我们凭空造吧,也没看到很难得算法(那不就是逆向了么),关键函数中有一个memset赋值语句,如下

我们在HEX里面观察0x600D20LL处的值,那里就存放着与flag有关的语句

直接把地址0x600D20输很多遍覆盖掉argv[0],结果如下

的确是溢出了栈,但是没有flag,WHY…………明明地址就在那之后啊……

后来我就根据字符串PCTF去找flag的地址到底在哪里,在IDA里面反正是找不到别的地方有flag相关的了,怕不是运行的时候被映射到别的地方去了

直接在gdb-peda中找字符串PCTF就好了(find PCTF),发现的确有两处地址

找到地址之后就好说,上脚本

#代码主体

cn.recv()
payload=p64(0x400D20)*300
cn.sendline(payload)
cn.interactive()

猜你喜欢

转载自blog.csdn.net/qq_42192672/article/details/82776113