get_started_3dsctf_2016预期解和非预期解

前言

很久没有pwn了,最近复现漏洞发现还是得回看一下,遇到很有意思的一题,这题不是一般的模版题,特别地,这是一道只有非预期解才能打通远程的题;因为远程返回不了flag相关文字,被迫从简单ret2flag函数变成getshell。

网上题解很多都是照搬别人的思路,基本上不说那些和平常题目不一样的细节是为什么,甚至错误解释了部分细节,而这些细节恐怕才是本题考点。彻底搞懂再发博客也许会更好

本篇文章将和网上的文章有所不同,这些细节会讲清楚:

大家都在说程序必须要正常退出才会有回显,但为什么是这样的?其本质是什么

为什么按之前的办法算不对这个的偏移

真的需要伪造a1a2,才会正常exit吗

mprotect的payload传参为什么有些奇怪?

分析

首先这题没有canary保护,而且直接就给了gets(),还有后门函数,这里还以为这就是可以秒的ret2text

但是,一切才刚刚开始

这题看起来复杂了很多,有好多没用到的函数,这是因为这题采用了静态编译的缘故,比如双击函数你会发现不是熟悉的extern了

目前整个库都在文件内,这对于漏洞利用来说是个好消息,于是网上有至少三种做题方案,其中的非预期非常值得学习一下

但还是让我们跟着作者思路走,看到一个后门函数名为get_flag

没有被引用,那看来是要我们ret to这里了,注意是ret to里面的这里以绕过判断:0x80489B8

坑点1:此gets为外平栈

刚开始做题由于习惯了函数自己平栈的题,所以没有注意到导致算错了偏移值,这个函数内部并没有标准的push ebp;mov ebp,esp;操作,说明这是外部平栈的

照这样来说,外平栈一般使用esp+x辅助定位,内平栈则是ebp-x辅助定位

而且是靠esp来进行寻址而非ebp,以前学到过,这应该是某种编译器的优化动作

光是这一点,这里就有坑了,没有内平栈,就是没有old ebp的存在,那么我们计算偏移的时候就不需要+4。而且这里使用pattern指令来计算偏移会有偏差,也许和下一个坑点有关联

有趣的是,这个静态编译里的其它函数有好多反而是内平栈的,也许这又是编译器的一个有趣的行为

坑点2:怪异的返回文字行为(在pwntools上)

解决完这个坑点后,你会发现,这个程序的返回文字行为非常奇怪,正常执行倒是没啥,但pwntools上如果一开始就等待接收”Qual a palavrinha magica? “是不行的,我看到一些师傅的payload里都后期注释掉了等待接收这句话的代码。但是如果send payload以后,你会发现还是能正常返回的,所以没有问题。这里我也没搞懂为什么会这样

坑点3:fopen需要正常的exit

坑点还没有结束。这个点,也是很多人没有搞清楚的点,直接就说需要exit,但是为什么需要exit,不知道

其实建议先看看文件流的相关内容,fopen函数就是打开了一个文件的输入流,它不会立即输出在用户shell上(或者说标准输出流上)

那么,如果它一直待在这个文件输入流,那么自然不会把内容推送到用户shell上(或者说标准输出流上)

输出该内容有两种方式:

1.用户显式地调用fflush() 

2.正常情况下的exit()

那么,只要我们满足条件其一,被读入文件流的flag就会被推送到用户shell上(或者说标准输出流上)啦

预期解

自此,预期解思路已经非常明显了,那就是溢出偏移0x38

然后不需要覆盖old_ebp,直接盖住返回地址,让它跳到我们需要的地方:0x80489B8

当执行完fopen再度返回的时候,我们让返回的函数变为fflush,或者exit,以让文件流把内容“吐”到标准输出流上

payload:网上大多使用的exit

所以说,根本就不需要伪造a1a2,exit也能正常执行,这本来就是两者独立的事情

实际上按刚刚提到的本质,那么fflush也理应能打通,

事实正是如此

打远程不知道为什么返回不了flag,坑点2发威了_(:з」∠)_

非预期解:ret2syscall

感谢https://www.shawroot.cc/2010.html,很精美的博客

那么,除了直接getshell以外应该没有别的办法了。

这么大个文件,ROPgadget资源应该挺丰富的吧,理清一下思路,首先是/bin/sh字符串

没有,问题不大,其实这个可以自己布置

然后就是各种rop小段

很丰富,然后思考一下,发现system、execve这些都没有,因为即使是静态编译,但是plt里没有就是没有了

32位下的syscall,在执行int 0x80触发execve()启动前,我们需要控制的寄存器是eax(使其值变为0xb),ebx(使其指向/bin/sh),ecx(使其null),edx(使其null),寻找一下:

下面这个漂亮滴很呐(赞赏)

最后就是重定向到int 0x80

如果应用ret2syscall本题最大的问题在于怎么给ebx赋值”/bin/sh”,可以知道其实程序内部是没有相关字符串的

我们也不可能直接赋值给寄存器,这是因为,寄存器的mov只能直接赋予一个整数给寄存器,如果希望赋值的是字符串,那就要通过指针来做赋值,所以我们直接赋值”/bin/sh”是不行的

既然是通过指针来赋值,那当然越方便越好,像栈空间其实就不是很好,其内存地址每次都会移动,而bss、got段则相对不会

两种思路:第一种是read调用,read 到 bss,前人之述备矣。第二种是直接用寄存器写入,https://www.shawroot.cc/2010.html

不需要调用read函数,直接通过mov来更改指针指向,然后写入,是一种值得学习的技巧,下次没有read就能用上了

比如:我们希望操控edx为“/bin/sh”

就要让一个可读写内存区域的值变为“/bin/sh”,然后让edx读取

这是一个8字节的字符串,对于32位来说,使用寄存器需要分开两次写入:“/bin”、“/sh”

而且我们还需要一个mov赋值的gadget,要求是对两个寄存器之间进行赋值,那么我们就可以通过操控被赋值的寄存器的指向地址,写入我们想写入的数据到我们想要的地方,

使用ROPgadget –binary ./get_started_3dsctf_2016 –only “mov|ret”寻找一下

注意我们需要找到的是这种形式的:mov [eax],ebx ,这样就能赋值给eax指向的地址,然后我们操作eax的值来实现任意写

ROPgadget –binary ./get_started_3dsctf_2016 –only “mov|ret” | grep “\[edx\]”

而且带gs的是有地址限定的

这样,我们就具备了任意写的能力,edx指向某个地址,然后写入eax 的东西

然后,我们还需要找个有写入权限(w)的区域

也可以像我这样,写到bss段一段间隔的尾巴

玄学的来了

所以最后的ret2syscall如下所示,看p4的就好,p3直接pop edx不知道为什么玄学地不行了,如果你下断点会发现第一下ret会乱跳,不知道为什么QwQ

最后,这个我远程也没有打通

非预期解:ret2mprotect执行shellcode

感谢https://xz.aliyun.com/t/7233?time__1311=n4%2BxnD0GDtGQG%3De0%3DG8DlhjT4cjYDuGDmuR7wD&alichlgref=https%3A%2F%2Fwww.google.com%2F

该方法适用场景

  • 没有system之类的函数可用
  • 或者需要修改某一些区域的权限以达到自己想做的操作的时候

利用流程

ret to mprotect->修改可控区域内存,加入可执行权限(有必要的话还得再添加写入权限)->布置shellcode->跳转到shellcode->shell

函数原型

int mprotect(const void* start, size_t len, int prot); – void* start: 区段开始位置 – size_t len: 区段的大小 – int prot:区段的权限(可以用8进制来表示,rwx就是7啦)

由此可知我们需要一个控制三个参数的gadget

shellcode生成

目前还不太会写,慢慢学吧,先使用pwntools自带的

可以使用msfvenom生成,听说这样免杀效果棒棒的,但不太方便而且暂时不需要

也可以直接一句pwntools命令:

asm(shellcraft.sh())

疑惑:为什么本次利用mprotect的传参如此奇怪?

为什么第一次就ret到mprotect?edx,ecx,ebx,全都没有设定好呀,这是很疑惑的地方,而且把mprotect放到后面,是不能成功get shell的,试着通过调试搞明白

第一次操控ret时,我们即将ret到mprotect

其寄存器情况如下,可见,我们调用mprotect时的确并没有完成对ebx、ecx、edx的控制,但我们看到即将对这几个寄存器赋值,赋予了栈上的值,那么接下来会发生什么?

在该点

其寄存器被成功赋值

所以,这种外平栈的,一般就是进去以后再从栈中吸收参数,

而紧接着的p32(pop_edx_ecx_ebx),其实就是因为外平栈,即,调用者自己处理恢复环境的工作

实际上充当的作用是栈平衡+恢复环境,以让栈顶正确指向下一个函数read。

这样我们就完全明白了,知道这种外平栈的该怎么控制了

等下,怎么最后还有一个p32(mprotect_start)呢,这是干嘛的,哦,跳转到这里执行shellcode

最后,这个我远程打通了

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇
粤ICP备20015830号