time_formatter攻防世界学习

time_formatter

前言:这题说实话分析量蛮大的,首先是程序内壁比较绕,而且调用了之前许多没有见到的函数---如snprintf_che,以及strsup(好像打错了),getegid(),并且对于一般的题目考察堆的方向是比较少的。

还是学了一些东西吧。
废话不多说,开始吧:

1.查看保护

在这里插入图片描述

保护极高了已经!!!就很恐惧!!!

2.运行收集信息

在这里插入图片描述
好家伙上来就报菜名嗷,更加恐惧了,不过有个提示嗷,一般报菜名的题目都是和堆有关的,至少我见的不多几道是这样。

3.ida查看

在这里插入图片描述
这里解释一些课外东西:
1.getegid:getegid()用来取得执行目前进程有效组识别码. 有效的组识别码用来决定进程执行时组的权限.

返回值:返回有效的组识别码.

2.setresgid:与市民对应,设置有效的组识别码
另外函数名字我做了一些变化,你们看的时候对照着自己写的看!
在这里插入图片描述
这里的returnnumb是返回一个整数,用来做判断
先看first函数:
在这里插入图片描述
注意看v0获得的是sub 400d74这个函数的返回值,我们点进去看看:
在这里插入图片描述
要写的不会的函数备注我写旁边了,这里我复制下来看的清楚:
1.strcspn:C 库函数 size_t strcspn(const char *str1, const char

*str2) 检索字符串 str1 开头连续有几个字符都不含字符串

str2 中的字符。

2.mallocother是我自己写的;
点进去malloc这个看看:
在这里插入图片描述
继续写以前没有见过的函数:
1.strdup:调用malloc函数去开辟空间存储参数的数值,并且返回指针类型。另外值得注意的是这里malloc申请的空间并不一定是传入进去字符串的长度,我后面在exp试了试,得出的这个结论。

2.err:错误流,不用管,我也不会

3.getenv:写旁边了,对题目影响不大。

4.另外就是这个参数可变的fprintf_chk,是把参数按照格式化要求转换之后存储到,开头给出的文件流(个人理解,建议百度)

然后返回了v5,v5就是我们输入进去的语句指针,最后把这个指针给了first函数的v0。
我们回到v0看看:
在这里插入图片描述
这里的aboutstr是我自己起的名字,其实就是比较,比较完之后把刚刚输入句子的指针给了全局变量ptr。
而这里的ptr也就是解体的关键所在了。

这里我们点击进去sboutstr函数看一下:
在这里插入图片描述
这里再次简述一下函数strspn的意思:
比较str1里面的元素是否都在str2里面,有则输出不一样元素的下标,没有的话,输出str1的长度。这里要求if判断成功,所以必须str1里面元素都在规定的accept里面,并且注意这里没有小写的i,这点我们后面再说:

到此我们算是吧first函数过了一遍了。


second函数没有什么意思,可以不看,直接看第三个函数sub400e43:
在这里插入图片描述

这个函数和之前一样,给指针给全局变量value,但是没有检测是否在accept中。
并且也是malloc开辟空间。
所以现在有了两次malloc的机会。
在这里插入图片描述
划线的地方都是这个漏洞执行的关键,他这里会把相对应的参数格式化后传递给command,所以呢这里我们要做的就是负责让command中有system,那这里参数中可以改的就是ptr了,那么我们能不能一开始就在ptr里面输入bin/sh呢,这是不行的,因为accept里面没有小写的字母。


继续看,选项5的函数:
在这里插入图片描述

询问是否退出前free了我们的全局变量。

那么想到的是什么?
use after free漏洞,去间接的修改我们ptr里面的内容。
思路:
1.首先随便给ptr数值让它申请,但是最好和后面要填的参数长度相同。
2.然后选择5,free掉,没有置空,所以这个时候ptr成为了悬挂指针。
3.然后我们再次去申请差不多大的value,就会让ptr和value指向同一片地址,这个时候我们在去用value修改ptr。
4.然后选择4,command中有了命令,执行之后获得shell。
exp如下,并且还要做一些解释:

from pwn import *
context.log_level='debug'
p=process("./time_formatter")
def func(a):
	p.recvuntil("> ")
	p.sendline(a)
func('1')
payload1='a'*8
p.sendline(payload1)
func('5')
p.sendline('N')
func('3')

p.sendline('\';/bin/sh;\'')
func('4')
p.interactive()

这里要解释的就是最后的p.sendline('\';/bin/sh;\''),为什么不写p.sendline('/bin/sh')呢?
我们看看选项4转换的时候:
在这里插入图片描述
这里我们传入进去的数字是用 ‘ %s ’包裹起来的,导致我们的/bin/sh是完全没有办法输入,使用我们要保证前后闭合就要 p.sendline(' ' /bin/sh ' '),这样可以嘛?不行,因为这样会在我们输的时候,p.sendline这里的单引号闭合了,所以使用转义字符 \ ',但是又因为要在system里面输入多个命令,所以要使用 ; 来让两个命令都执行,所以要写:p.sendline('\';/bin/sh\''),就可以了。


题目还是很麻烦的题目,主要是复杂。
关于堆的知识这里附上链接ctfwiki,我最喜欢的网站:
https://wiki.x10sec.org/pwn/linux/glibc-heap/use_after_free-zh/

在这里插入图片描述
睡觉了睡觉了!!!

posted @ 2021-10-21 20:35  写不完作业还要玩  阅读(165)  评论(0编辑  收藏  举报