集训慢慢接近了尾声,樊荣学长给我们讲了几节课关于溢出的知识,最后一讲给我们出了一道习题:文件pwn1.
之前讲的习题都是比较简单的,所以直接用gdb进行了反汇编,今天是使用了IDA进行反汇编。
学长说socket编程的开头都是差不多的,所以找到fork函数,从这个函数向下开始分析:
使用F5,会把汇编代码转换成C语言的代码:
先来看看fork函数的作用:
fork函数时计算机程序设计中的分叉函数,也就是创建一个子进程。他的返回值:若成功调用一次则返回两个值:父进程返回子进程的ID,子进程返回0.否则出错返回-1.
可以通过fork的返回值判断当前进程是子进程还是父进程。
再来看我们的程序,如果fork的返回值是0,break跳出循环执行下面的程序。
再来看v9,v9是一个函数指针,定义了一个空函数。
再来看看send函数和recv函数的作用:
send函数是客户端向服务器发送请求和服务器向客户端发送应答所用到的函数。
int send( SOCKET s, const char FAR *buf, int len, int flags );
第一个参数指定发送端套接字描述符;
第二个参数指明一个存放应用程序要发送数据的缓冲区;
第三个参数指明实际要发送的数据的字节数;
第四个参数一般置0。
recv函数是客户端接受服务器端的数据和服务器接受客户端的数据所用到的函数。 int recv( SOCKET s, char FAR *buf, int len, int flags);
第一个参数指定接收端套接字描述符;
第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;
第三个参数指明buf的长度;
第四个参数一般置0。
再来看我们的程序:send(v11,"Input your answer:\n",20u,0)将Input your answer:发送到客户端。
然后recv(v11,&v2,120u,0)等待用户发送回来的信息,然后复制到v2中,实际复制的长度是120u。
至此,下面就开始执行函数v9,但是v9是一个空函数,所以我们需要覆盖掉v9这个函数,让其来执行我们希望执行的函数,可以看到有一个win函数,F5一下可以看到,他的作用就是讲flag.txt中的内容复制给了flag,然后将flag返回。至此,如果我们让程序执行了win函数,然后程序会继续执行send(v11,flag,v1,0)将flag发送到客户端。我们就可以找到flag。
OK,那么如何让程序执行win函数呢,当然需要找到win函数的地址,然后去覆盖掉v9的地址。
我们可以看到win函数的地址是:0804883C
现在来找v2的大小,需要看汇编:
看画红框的地方,lea命令将esp+18h的地址传送到了eax中,然后将eax的内容放到了esp+4中,也就是说,esp+18h就是buf(v2)的其实地址,第二个红框中esp+80h是buf(v2)的结束地址,算一下,buf(v2)的长度是104
然后进行覆盖:
完工!~