Aiur

zellux 的博客

ICS Lab3 简易攻略

Permalink

这个 Lab 应该比上一个 Lab 简单不少, Lab 的说明文档也差不多把基本的过关要点都提到了,所以这里主要介绍一下几个相关工具的使用,帮助大家进一步熟悉 Linux 命令行   ;-) 首先从主页上下载一个压缩包,最简单的方法是直接在命令行使用 wget 工具 wget http://10.132.143.100/lab2007/buflab-handout.tar

顺便提一下 wget 的功能很强大,除了可以在后台运行,它还支持 ftp https http 等协议,提供整个网站下载的功能(类似于 Windows 下的 WebZIP )

接着使用 tar 命令解压这个文件

1
tar xvf  buflab-handout.tar

其中, x 参数表示解压工作, v 表示显示解压所得的文件列表, f 及其后面跟着的文件 名指定了待解压文件

这样在当前目录下就多出了三个文件: bufbomb, makecookie, sendstring

接下来使用 makecookie 得到自己学号对应的 cookie 号,用法是 ./makecookie 学号

这个 cookie 号在后面的几个关卡中都有可能会用到,同时 http://10.132.143.234/bufbombstatus.html 中可以通过自己的 cookie 号随时获得自己现在的过关情况。

和上一个 Lab 一样,这里介绍一下怎么过 Level 0 。

这个热身关和两个函数有关, test() 和 smoke() ,正常情况下 smoke 不会被任何函数调用,我们要做的就是输入一串特定的字符,使得 smoke 被调用。另外这个关卡简单之处在于 smoke 被调用后就直接退出程序,我们在破坏了栈的数据后不需要恢复原样。

注意到 test 中调用了 getbuf 函数,联系到 CS:APP Section 3.13 ,看来只要把 getbuf 的返回地址改成 smoke 的地址就行了。

召唤 gdb 监视 bufbomb 的运行,设置断点在 getbuf ,使用 run -t 学号 运行,程序停在 getbuf 的第三行,使用 disas 查看当前函数 (getbuf) 的汇编代码

1
2
3
4
5
0x08048ab3 :  lea    0xffffffe8(%ebp),%eax
0x08048ab6 :  sub    $0x24,%esp
0x08048ab9 :  push   %eax
0x08048aba :  call   0x8048bbc
0x08048abf :  mov    $0x1,%eax

看来这里的 %eax 保存了字符串的首字节地址,从第一句可以算出,它与 %ebp 指向的地址相差了 24 。

也就是说我们输入 24 个字符后,接下来输入的 4 个字符会覆盖掉原来的帧指针,再之后的 4 个字符就会覆盖函数的返回地址。把这个地址覆盖成 smoke 的就行,用 disas smoke 得到 smoke 的地址为 0x08048964 。

知道了这些后,我们就来构造这条特殊的字符串,新建一个文本文件(当然也可以在 sendstring 中键盘输入,不过调试起来比较麻烦),输入

1
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 64 89 04 08

最后四个字节就是 smoke 的地址,注意是 little endian 约定。假设保存文件为 ans.txt

但这只是文本格式的指令,需要把它转换为二进制值, sendstring 工具可以帮助我们生成二进制串:cat ans.txt | ./sendstring > raw.txt

这行命令用到了 shell 的管道和重定向功能,它的作用是把 ans.txt 的内容放到 sendstring 中,把 sendstring 生成的内容放到 raw.txt 中。这样在 raw.txt 中包含了最后的二进制代码。

回到 gdb ,使用 run -t 学号 < raw.txt 运行程序,程序停在 getbuf 中的断点后,使用几个 ni 命令往下运行,等调用完 Gets 函数后(一般是在 0x08048abf ),查看当前的帧指针附近的信息:

1
2
(gdb) p/x *(int*) ebp@2
$ 1 = {0x0, 0x8048964}

看来我们已经成功得把返回地址改掉了,使用 c(ontinue) 继续运行,就可以看到成功信息了。

后面几关(除了最后一个)和这个热身关差不多,只是返回地址需要指向 buf 数组,运行嵌在其中的代码再返回原来的地址,要获得嵌入的二进制代码,可以先写一个包含汇编指令的 .s 文件,使用 gcc -c 把这个文件编译成 relocatable object ,再用 objdump -d 得到这段二进制代码。大致思路 pdf 上已经写得很详细了,这里不再赘述。

关于最后一关, CS:APP 书上有一个类似的题目 (3.38, P236) ,我记得我当时做的时候栈帧地址也是会跳动的,只是没有 Level 4 那个那么明显,有兴趣的同学可以试一下。

程序的下载地址: http://10.132.141.124/study/ics/bufbomb.c

其他几个提示

输入的文本格式的二进制代码计算字节数比较麻烦,可以每 10 个字节一行,写完后使用 vim 的 shift+j 快捷键把这几行都拼起来。

本地过关后记得查看网站确定一下。

gdb 的 run 命令会自动根据上一次的参数运行程序,所以第一次输入 run -t 学号 < raw.txt 后,以后只要简单的使用 r 就可以了。

建议开两个 PieTTY 窗口,一个 gdb 调试,一个修改、生成二进制文本,很方便。

评论