老规矩,ssh/nc进去,查看文件权限,查看文件类型,查看文件保护机制
|
|
|
|
|
|
OK,去看代码,这里使用了网络编程socket的基础知识,哇,很强,代码很长…
这里面用了超级多的判断,一共五个步骤,全是je判断,我突然想到,爆破,然后就开始gdb调试,调试的时候,去修改对应的标志位,这里需要了解eflags寄存器的基础知识,以及不同标志位对应的位置
搞定,这道题目中,只用了je判断,而je指令对应的就是ZF,零标志位,嘿嘿,只要关注这个就好了
在调试的时候,使用set $eflag=… 就好了
首先我们发现调试到第一个cmp的时候,ZF=0,而且eflags的值为0x293=0b001010010011(之后就默认不写前面两个0)
小知识,eflags寄存器的值,对应的不同标志位是反过来的,也就是说我们要从右往左数第几位,比如上图中ZF的位置是6,则是倒过来数的第7位….
|
|
修改ZF位,将数值改为0b1011010011=0x2d3…重复多次,把所有je,jne,jns判断都改变对应的标志位,这样就可以成功绕过所有的判断,获取到flag,但是这种是需要在服务器上面调试,才有用的…我发现在服务器上面使用gdb调试,他直接就爆了这个错误:single stepping until exit from function xxx,which has no line number information…
对不起,我知道了,你编译的时候没有加上-g选项,所以我没法调试,难受…也不能给你安装插件peda或者pwndbg,所以爆破,是不行的…
这里加上一点自己发现的小知识,如果知道一个elf文件是否编译的时候添加-g 即可调试的选项:在我的ubuntu 64位系统下面试的…
helno是没加-g选项的elf文件,hel是加了-g选项的elf文件
|
|
而且如果要能够调试,那就需要更高的权限…想办法去提权是不可能的,会被ban的…(以后试试)
好吧,开始找下一种方法,就是想办法去符合他们的那么多个if判断的条件,好像这个方法,才是一个正常人应该首先想到的办法…我的思路可能一直都很偏…
这里发现5个不同阶段,代表这个五个不同的知识点,main函数参数,进程通信,环境变量,文件操作,网络编程…
好嘛,一个一个来,老实说,这个真的很考验你的编程功底,尤其是如果有过一定的linux下C++开发经验的话,应该就会很轻松…
OK,第一阶段
|
|
要求我们使用100个参数,加上第65位是空,第66位是一个字符串”\x20\x0a\x0d”,嘿嘿,这里我们可以不用python来写脚本,因为python写脚本对于这个程序要说,是比较麻烦的(第5阶段的网络编程,是不好写脚本的,所以我们用C)
C语言中有一个execve函数,可以执行程序,并且给程序附加main函数参数和环境变量…这个函数需要百度仔细学习一下,才能搞懂…
|
|
所以我就把第三阶段,也一起写在这里
第三阶段是要求我们
|
|
这个什么意思呢?就是说有一个环境变量”\xde\xad\xbe\xef”,或者说是一个key,要求他的值是 \xca\xfe\xba\xbe ,所以我们在执行函数之前,需要这么写…
|
|
嘿嘿,第一阶段和第三阶段完成…
那么就开始解决第二阶段,这个进程通信,怎么解决呢?首先看程序
|
|
第一个read函数的第一个参数为0,实际上就是stdin输入,即标准输入,但是第二次调用read函数的第一个参数是2,这个是stderr输入…1就是对应的是stdout…这些是linux文件描述符的基本知识
所谓的文件描述符是一个低级的正整数。最前面的三个文件描述符(0,1,2)分别与标准输入(stdin),标准输出(stdout)和标准错误(stderr)对应。
进程之间通信是需要用到管道的,就好像搭桥一样.这里我们用最简单好用的管道,无名管道pipe,有名管道是fifo
|
|
平常我们使用键盘输入的时候就是使用的标准输入的参数,stdin,然而同时他们要求我们也使用stderr,那就不是很好办了…这里我们就需要使用进程之间通信的工具–pipe了.
可以百度一下进程之间的通信,就可以理解管道的重要性和管道的使用方法…
这里我们就直接上代码了,其实每个知识点结合代码看完之后,就差不多懂了
|
|
分析一下代码,其实程序的流程很简单,就是建立子进程和父进程之间的管道,关闭掉子进程的读通道和父进程的写通道,就变成了父读子写通道了…然后把子进程对应的内容,通过管道输入到父进程,这样就成功的让stderr这个问题给解决了…
nice,那就下一个step了,第四个,分析代码
|
|
这个就是在本地读取一个文件,并且里面的前4个字节是特定的字符串…
这里有一个问题需要解决的就是我们写的脚本放在那里?文件读取,是要求文件的目录的,首先在pwnable.kr服务器上面,我们对于tmp目录是有写入权限的,然后有一个程序如何在不同目录运行的问题,留到最后分析,其实就是一个ln命令…
那么第四阶段的分析结果就是这样:
|
|
OK,第五段,网络编程…嘿嘿嘿,正好在学习,发现这个很简单,这要写一个客户端程序,连接上它服务端的端口,发送一段数据就行…
|
|
原程序代码中
所以这五个过程就这么愉快的解决了,那么回到当初那个不在同一个文件如何操作的问题,由于execve这个函数是开辟一个子线程去运行一个elf文件,而当前目录是/tmp目录,当我们的input程序调用到system打开flag 的函数的时候,就会找不到文件,所以我们要在/tmp目录下面建立一个link连接,所以在命令行中输入这个就好了,嘿嘿.
|
|
然而这个命令是有问题的,它会报错,说我们不能使用硬链接,由于权限不够…真的难受,查看一下这个命令,发现加上-s选项,就是添加一个软连接,就好了,硬链接是在该目录下生成对应一模一样的文件,两处对改文件的修改,都会导致文件的修改(由于input2目录下我们是没有对flag操作的权限的,所以生成硬链接是不可能的,不知道为什么那些大佬的博客可以)…软连接是生成一个镜像文件,这样子,就可以保证在同一目录下了….
然而在我上创.c文件到tmp目录下的时候,我发现运行之后的结果只有这个
|
|
哇,为什么没有打开flag啊,明明我已经创建了一个flag的镜像链接了,这是假的吧,测试了很久,明明正常来说,所有用户对于tmp目录下都存在着读写权限,但是我们好像不能在tmp目录下使用ls命令,看下面peimission denied,尴尬,好像我们创建的软连接flag这个文件是没有用的,权限不足,无法打开
真可怜,又捣鼓了很久,发现一个超级神奇的事情,当我们在tmp下创建一个目录链接的时候,我们竟然能查看该目录,而且这个目录下面还有别人写的exp,为什么目录链接已经存在了,我们还能创建目录链接?这个问题,没有想清楚,可能环境问题就是玄学吧…所以就这样能够运行我的代码了,而且也学到了如何使用python来写脚本,快乐….
|
|
C总代码附上:由于执行程序execve函数是开启进程的问题,要把这个函数写在后面,也就是在文件读写之后
|
|
网上的代码,喜欢加上sleep函数,我觉得只要你把stage的顺序给安排好了,应该就没有问题,我觉得唯一需要加sleep暂停的地方就是网络编程之前,写在注释里了…因为服务端程序只接受一次消息,没有for循环…所以暂停一下,让子进程处理一下之前的消息,也是可以的
|
|
所以说,说不定,后来者,也能看到我写在里面的代码….
顺便分析一下,别人的py代码,发现,好像我的python基础好垃圾啊…
这里顺便学习了一下pwntools中的process函数(pwntools-process函数),还有这个函数remotepwntools-remote,这个真的好用,比写C语言代码好太多了,它能够自带标准输入输出作为参数…我以前还觉得python没有C好,真香,
|
|
结语
写了4000字,真的快乐
学习过程中使用过的链接
C语言分析代码:https://werewblog.wordpress.com/2016/01/11/pwnable-kr-input/
pwntools文档:https://pwntools-docs-zh.readthedocs.io/zh_CN/dev/about.html