2021_09_15_ciscn_2019_n_1

ciscn_2019_n_1

前言

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

准备工作

在做题之前,建议每一个同学在ubunut中安装pwntools。
python环境完备的基本一个pip3 install pwntools就行。如果报错的话再去搜索一下具体问题。

做题流程

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

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

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

运行题目程序

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

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

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

checksec查保护

比较简单,如果需要安装就按提示安装或者搜索安装方式就行。
2021_09_15_ciscn_2019_n_1

程序逻辑分析

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

输入数字,把数字存在v1这个内存快中,然后判断v2内存块是不是11.28125,如果是,就能拿到flag,不是就输出"Its value should be 11.28125"
想要拿flag,需要使v2为11.28125.但是我们输入的变量是存在v1,似乎并没有任何方式能够改变v2的值。
回想一下,刚刚我们说到v1和v2的内存空间是连续的。在ida中我们其实能够发现v1内存块的大小是0x30,那么想一想,如果我们在给v1赋值的时候,输入了比0x30还大的字符串,会发生什么呢。
当字符串填满了v1的0x30的空间,由于gets函数并不会检查内控空间中发生的溢出,多出来的字符串会继续向下存入,也就是相当于越过v1内存块的界限,存进v2内存块中了。
这样只要我们巧妙地构造我们输入的字符串,先用0x30个任意字符将v1填满,再在后面加上11.28125,是不是v2的值就变成了我们想要的?

脚本编写

我们直接略过漏洞点的寻找,开始编写脚本。
我们的目标很明确,当程序要我们输入number的时候,我们给它发一大串字符串,其中前0x30个字符是任意的垃圾字符,之后是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这个东西有一个大致的理解。
在这之前有一个问题必须要理解。
之前说到我们需要输入一大串字符串传入程序,一般的思维方式就是执行程序,然后在该输入的时候把要输入的东西输进去就行。看起来比较直观也比较简单,所以为什么要花力气用编程语言写脚本来执行这些呢?
ttz您来写。我写不下去了。就大概讲一下为什么要用脚本以及如何正确理解payload。

然后回归正题,关于字符串的构造。
第一句很简单,就是垃圾字符的填充。
但是具体要填充多少,每道题可能都不太一样,可以通过ida查看。
然后是下面那个11.28125在内存中的表示。
关于如何找到11.28125的内存表示,第一种方式是直接在ida中查看,第二种方式是直接进制转化的方式,但是这个方法存在大小端序的问题,直接转化的话是大端序表示,而内存中应当是小端序,萌萌新可能会被这个点坑很久()
ida查看的话直接找到伪代码对应汇编的比较v2与11.28125的那一段,找到表示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’
然后我们用这个脚本演示一下吧。
2021_09_15_ciscn_2019_n_1

上一篇:BUUCTF-ciscn_2019_n_1


下一篇:ciscn_2019_ne_5