当前位置:首页 » 《随便一记》 » 正文

2021_09_15_ciscn_2019_n_1_m0_51187558的博客

28 人参与  2021年11月17日 15:03  分类 : 《随便一记》  评论

点击全文阅读


ciscn_2019_n_1

前言

每日一题pwn方向的第二题。也是初入漏洞利用的一道特别基础的题。
大家都应该尝试着做过了上一道,也就是test your nc。从解法来说其实那道题的难度真的只是半脚踩在入门的门坎上。就像wp中所说的那样,目前pwn题的核心是通过漏洞挖掘与利用来提权,而nc这道题可以说是不需要任何漏洞的挖掘与利用,做出这道题并不代表你已经入门pwn了。
虽然如此,从ciscn_2019_n_1这道题开始,我们真正要开始尝试迈过pwn题的那一道门槛,面对一些简单的漏洞进行利用了。

准备工作

在做题之前,建议每一个同学在ubunut中安装pwntools。
pwntools集成了做pwn题的很多模块,具体可以看看https://zhuanlan.zhihu.com/p/83373740这篇文章
pwntools的安装也并不困难。pwntools的github官方文档上有安装指令,如果跟着执行报错的话可以到网上找一些文章参考一下 ,需要注意的是我默认大家的系统都是ubuntu18.04及以上,默认支持python3,所以相对应的pip也是pip3,而不是pip。
当遇见报错,可以复制搜索一下,大概率会搜索到类似问题的解决方法。

做题流程

这里要提一个大致的流程。对于执行顺序其实并没有那么多硬性规定,只是对于萌新也许能少走一些弯路。
流程大致是这样的:

  1. 拿到题目附件,将它在对应的操作系统环境下打开(一般来说是ubuntu)。先执行一下,了解一下程序的大致运行结果。
  2. checksec命令,了解程序的保护方式。针对不同的保护方式,大致了解题目的难度等级。(萌萌新的题目应该大多是没有任何保护的,但是之后的很多题都会附加很多复杂的保护)
  3. 用ida打开题目,对题目进行一个程序逻辑的逆向。
  4. 通过逆向找到程序的漏洞点。
  5. 思考漏洞利用方式,并开始编写脚本(适当时动态调试辅助脚本编写)。
  6. 脚本编写完成后,先在本地尝试getshell。成功的话连接远程拿flag。

整个流程最关键也是最难的就是第6步。在这个wp中,我会尽可能地详细地将编写这个脚本的所有步骤和思路讲出来。其他的步骤也会进行适当的解释。

运行题目程序

这也是流程中的第一步,总的来说这一步并不是必要的,但是运行一下总归能帮助大家提升对于程序逻辑的理解(尤其是逆向以及语言功底比较弱的同学)
现在我们将程序放进了ubuntu系统中,请添加图片描述

可以看到这个文件夹下的ciscn_2019_n_1文件。
这时我们会碰到今天的第一个坑。
如果我们直接./ciscn_2019_n_1,请添加图片描述
就会出现如图的情况。
这是因为这个文件虽然可执行,但是我们并没有可执行权限。
这个情况直接利用chmod +x ciscn_2019_n_1来将文件权限改成可执行就行。
具体的原理可以搜索一下chmod指令。
请添加图片描述
通过ls -l指令目,可以看到ciscn_2019_n_1文件的权限是rwx,意味着它已经能够被执行。这时候再./ciscn_2019_n_1,程序就成功被执行了。
执行的话可以看到程序要求我们猜数。
(我这个颜色有点诡异,这就调一下)
请添加图片描述

可以看到连续两次程序都说,我们输入的值要为11.28125,但是我们输入了这个11.28125,程序还是没有什么让人提得起兴趣的反映。这很奇怪,待会儿让我们在ida中一探究竟()。

checksec查保护

比较简单,如果需要安装就按提示安装或者搜索安装方式就行。
请添加图片描述

程序逻辑分析

用ida64打开。
f5反编译
在这里插入图片描述
出现了这样一串代码。
稍微分析一下,双击func()进入函数内
我们在这里插入图片描述在这里插入图片描述
这个程序的代码逻辑非常简单。
定义了两个变量,一个是整形的v1,另外一个是浮点型v2。
这里需要了解的一个知识点就是,当我们定义变量,计算机会为我们在内存中开辟一块内存空间来存储我们的变量的值。而且这个空间是连续的,开辟了v1以后再开辟v2,他们的内存块是接在一起的。
如图所示。在这里插入图片描述

输入数字,把数字存在v1这个内存快中,然后判断v2内存块是不是11.28125,如果是,就能拿到flag,不是就输出"Its value should be 11.28125"
想要拿flag,需要使v2为11.28125.但是我们输入的变量是存在v1,似乎并没有任何方式能够改变v2的值。
回想一下,刚刚我们说到v1和v2的内存空间是连续的。并且v1的内存空间是有限制的,比如说假如v1的内存空间大小是10,那么如果我们输入了大小超过十的字符串,那么数据依然会继续输入,不过是向下溢出到了v2的内存空间中了。这样,如果我们知道v1的内存空间大小,再巧妙地构造我们输入的字符串,用任意字符将v1填满,再在后面加上11.28125,是不是v2的值就变成了我们想要的?
那么如何寻找v1的内存块大小呢?
其实我们可以通过ida看到v1的大小。
这里提供两种本质上都是一样的方法,大家都看看,相互辅助理解吧。

  1. 查看伪代码中变量定义时与rbp的偏移
    在这里插入图片描述
    如图,大家可以把rbp暂且理解为一个基准线,或者0度线,把它当成0。前面的rsp暂且不用管,只看后面的rbp。[rbp-30h]的意思就是这个v1开始的地方与rbp的偏移是0x30(后面的h代表这是一个十六进制数),可以理解为它开始的地址就是rbp-30h的地方。

同理,下面的v2开始的地方是rbp-4h,z这样就能算出v1的内存空间是0x30-0x4 = 0x2c。

借用一张很直观的图来帮助大家理解
请添加图片描述
2. 利用stack窗口查看。

在ida的伪代码页面,双击v1或者v2变,我们能较为直观的看到两个变量在内存中的大致排布,左边标出了偏移量。
所以稍加计算便也能算出0x2c这个数。
在这里插入图片描述

脚本编写

我们直接略过漏洞点的寻找,开始编写脚本。
我们的目标很明确,当程序要我们输入number的时候,我们给它发一大串字符串,其中前0x2c个字符是任意的垃圾字符,之后是11.28125的16进制表示。
这里有一个坑。就是如何正确地找到11.28125在计算机内存中的表示。

完整的脚本如下,具体每一句都会有详细的解释。

from pwn import *#导入pwntools模块,python基础知识,没有pwntools的同学可以自行搜索安装方式。
#p = process('./ciscn_n_1')#以本地运行的方式加载程序,一般来说先是本地测试脚本,能打通再远端连接。
p = remote('node3.buuoj.cn',27494)#以远程连接的方式加载程序。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        

payload = b'a'*0x2c#这两行放在外面重点讲
payload += p64(0x41348000)#11.28125在内存中的十六进制表示

p.send(payload)#将payload发送

p.interactive()#与远端程序交互

然后着重讲一下

payload = b'a'*0x2c
payload += p64(0x41348000)

这两句。就是构造字符串的过程,payload就是0x2c个a加上0x4134800的机器码。配合上后面的p.send(payload),将payload发送给程序。
首先需要对payload这个东西有一个大致的理解。
payload并不是什么python的关键字,只是一个非常普通的变量,(你甚至可以给它取任何名字,只是处于习惯问题我们通常给它命名为payload)我们先把要输的字符串存进这个变量,再直接通过变量与程序交互,会使脚本看起来简明干净很多。
然后回归正题,关于字符串的构造。
第一句很简单,就是垃圾字符的填充。
但是具体要填充多少,每道题可能都不太一样,可以通过ida查看。
然后是下面那个11.28125在内存中的表示。
关于如何找到11.28125的内存表示,第一种方式是直接在ida中查看,第二种方式是直接进制转化的方式,但是这个方法存在大小端序的问题,直接转化的话是大端序表示,而内存中应当是小端序,萌萌新可能会被这个点坑很久(关于大小端序的问题可以自行搜索)
ida查看的话直接找到伪代码对应汇编的比较v2与11.28125的那一段,找到表示11.28125的字符串,点进去。
在这里插入图片描述
稍微有点汇编基础的同学应该能一眼看出来这个指令就是将浮点寄存器xmm0的值与dword_3007f4进行比较。所以很显然dword_3007f4就是我们要的11.28125。
在这里插入图片描述

这样我们就找了0x41348000
然后我们将它填进去。
可能会有同学疑惑为什么这里不是直接payload = 0x41348000
或者payload = b’0x41348000’

Payload不是直接payload = b’0x41348000’是怎么回事呢?Payload相信大家都很熟悉,但是Payload不是直接payload = b’0x41348000’是怎么回事呢,下面就让小编带大家一起了解吧。

Payload不是直接payload = b’0x41348000’,其实就是我们需要输入的不是字符串,大家可能会很惊讶Payload怎么会不是直接payload = b’0x41348000’呢?但事实就是这样,小编也感到非常惊讶。

这就是关于Payload不是直接payload = b’0x41348000’的事情了,大家有什么想法呢,欢迎在评论区告诉小编一起讨论哦!
()

P64(0x41348000)指将整数进行64位格式的打包,其实就是把一串人能读懂的数字转换成机器码,大概长这样 ‘/x00/x80/x34/x41’

getshell

然后我们用这个脚本演示一下吧。
在这里插入图片描述
cat flag成功。
这一步骤也有很多要注意的点。
前文中我们一直说要写python脚本,但是编写python脚本的工具,以及如何执行python脚本并没有提及。
这里我推荐ubuntu上一个ui很好看,也很智能的代码编辑器sublime text。
你甚至能直接在ubuntu的应用商店下载它。
然后输入subl ciscn_2019_n_1.py指令,subl会自动为你创建一个带有python格式高亮的名字为ciscn_2019_n_1.py的空文件。
然后输入脚本,ctrl+s保存,脚本就会存在你创建时所在的路径中。
这个时候,保持你的题目和你的脚本处于同一路径,然后python3 ciscn_2019_n_1.py,你就成功执行了这个py脚本。
()


点击全文阅读


本文链接:http://zhangshiyu.com/post/30994.html

脚本  程序  变量  
<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1