type
status
date
slug
summary
tags
category
icon
password
就拿这道题当作IO类型的题目的开篇之题吧。
 
这道题的整体不复杂但其中对程序的执行流的控制还是很有趣的,也算是比较好理解的题目。
不知道为什么我在我这里理论上是没问题的了,但我就是打不通,换了很多的ogg总是不能满足条件,不管了,快被这个问题逼疯了。直接来思路吧
 
这道题的出题人的github在这里。里面有源码可以看一看
 
notion image
 
在ida中就是这个样子这里程序一开始就给了我们一个sleep的地址,于是我们就知道libc的地址,可以少去泄露libc的地址这一步。
然后就用了
这两个函数将输出重定向了,因此这题我们在拿到shell之后还有进行输出重定向,这样才能将flag打印在屏幕上。具体可以参考我的这篇文章
 
然后就是5个循环,这五个循环的作用为在第一个输入时,读入8个字节的数据,然后再第2次输入时将之前读入的8个字节当作地址向其中读入1个字节,将上述的过程进行5次。
 
就是可以让我们实现5次任意地址的修改一个字节,然后程序就会直接调用exit函数,将程序结束。
就以上的真个过程来看,这道题我们已经拿到了libc的地址,并可以进行5个地址的任意写,但由于这道题开启了pie于是我们写的地址就只能是在libc上,并且这道题还没有栈溢出等可以直接操作的漏洞。于是我们就要看在程序执行exit的函数过程中我们能不能对其下手,控制程序执行我们修改后的地址。
 
exit这个函数在程序中是一个比较特殊的函数,它在被调用的过程中对IO进行遍历,去执行在IO上的命令,于是我们很多时候就可以通过修改IO上的数据内容从而达到控制程序执行流的这样一个操作。
 
在这题中有两个做法一个直接修改IO上的内容,一个修改在调用某一个函数时的内容。
这里先讲第2种。
 
当我们在gdb进入exit 函数的内部进行调试时,会进入如下的样子
notion image
__run_exit_handlers 这个函数就是我们在关注的函数中的一个
此时我们在进入__run_exit_handlers 这个函数中,
notion image
在这里__call_tls_dtors 这个函数不用管
然后一直步过到这里
notion image
来到__run_exit_handlers+230 的这个位置,这里程序执行的为call rdx 这里指令,而此时的rdx中的值为
程序就会去执行_dl_fini 这个函数,我们进入其中
一直来到这里_dl_fini+126 这个位置。
notion image
这里程序会执行
这里程序执行的过程为将rip的内容加0x2165e4,取这里的的地址然后跳转执行其中内容,在这里程序已经表明最后就是执行rtld_lock_default_lock_recursive 这个函数的地址
 
然后这里rip的地址不能直接使用当前的rip的地址,要使用下一个命令的地址0x7ffff7c10964
 
于是把其打印出来就是这个过程
notion image
先取0x7ffff7c10964+0x2165e4 里的0x00007ffff7c00d20 这个作为目标地址跳转过去
notion image
这里面刚好就是rtld_lock_default_lock_recursive 这个函数
 
notion image
就像这个里面的一样
notion image
由于在这里_rtld_global+3848 这个地址是在libc上的,于是我可以考虑直接修改这里地址里的内容为ogg,那么程序就会从_rtld_global+3848 这个地址里取到ogg,然后直接执行,就可以满足我们的要求。
notion image
 
这就是我们说的第2种解法
exp
 
 
第2种办法就是ctfwiki上的办法,这里简单调试看一下
基本思路就是在程序执行exit函数过程中会遍历IO_2_1_stdout 函数,并找到这个函数的最后一位IO_2_1_stdout+216 的地址,在这里找到_IO_file_jumps 函数,
notion image
notion image
_IO_file_jumps 函数
notion image
然后程序就会跳转到_IO_file_jumps+88 这里执行_IO_file_setbuf 函数。
于是我们就可以想能不能先修改IO_2_1_stdout+216 的地址为程序中的一个其他地址fake_addr1,然后修改我们fake_addr1+0x58的地址为ogg,那程序在遍历IO_2_1_stdout 函数之后就会找到IO_2_1_stdout+216 中被我修改的fake_addr1,然后再跳转执行fake_addr1+0x58,然后就可以执行我们的ogg了。
 
 
具体过程就在这里首先我们要先来到这里
notion image
进入其中,程序会执行_IO_cleanup 函数
我们再其中一直步过到这里
notion image
此时程序就要跳转执行rax+0x58 的地址,而我们看一看此时的rax的值,就会发现为_IO_file_jumps 的地址,这不就是我们之前说的程序再执行exit 函数过程中,会遍历IO_2_1_stdout 函数,并找到这个函数的最后一位IO_2_1_stdout+216 的地址,在这里找到_IO_file_jumps 函数,然后跳转执行_IO_file_jumps+0x58 的地址。
notion image
 
于是这里我们就可以考虑上文提到的办法
先修改IO_2_1_stdout+216 的地址为程序中的一个其他地址fake_addr1,然后修改我们fake_addr1+0x58的地址为ogg,那程序在遍历IO_2_1_stdout 函数之后就会找到IO_2_1_stdout+216 中被我修改的fake_addr1,然后再跳转执行fake_addr1+0x58,然后就可以执行我们的ogg了。
 
但是由于我们只能修改5个字节的数于是我们就要考虑如何找个一个地址,然后这个地址的往下0x58,刚好也有一个libc地址,这样我们修改这个两个地址可以满足我们的要求,
 
notion image
于是我们就找到这个地址,0x7ffff7bc4668 (IO_2_1_stdout+72) 这个地址,而这个地址的0x58位之后刚好有一个0x7ffff7bc37a0 (_IO_wide_data_1) 于是我就可以修改
这里的内容为0x7ffff7bc4668 这个,这里用了2个字节,然后我们在修改
这里的内容为ogg,这里要用到3个字节,于是我们就刚好用完这5个字节,然后程序就会满足我们的条件。
notion image
exp
 
这道就当是对IO类型的入门了,可惜没打通,我也不知道是什么原因。
这道题对IO的利用可谓奇妙,同时IO堵塞复杂也可见一斑。等后面就要开始更多的IO学习了
任重而道远。
 
 
 
 
《明朝那些事》malloc,free源码分析
Loading...
wgiegie
wgiegie
一个苦逼的ctf干饭人🍚
公告
🎉NotionNext 4.5已经上线🎉
-- 感谢您的支持 ---
👏欢迎更新体验👏