题目地址:http://pwnable.kr/play.php
按题目提示连接 ssh unlink@pwnable.kr -p2222 (pw: guest)
ls 发现和之前的题目一样: 三个文件分别是 flag,unlink,unlink.c
先查看unlink.c 源码如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct tagOBJ{ struct tagOBJ* fd; struct tagOBJ* bk; char buf[8]; }OBJ; void shell(){ system("/bin/sh"); } void unlink(OBJ* P){ OBJ* BK; OBJ* FD; BK=P->bk; FD=P->fd; FD->bk=BK; BK->fd=FD; } int main(int argc, char* argv[]){ malloc(1024); OBJ* A = (OBJ*)malloc(sizeof(OBJ)); OBJ* B = (OBJ*)malloc(sizeof(OBJ)); OBJ* C = (OBJ*)malloc(sizeof(OBJ)); // double linked list: A <-> B <-> C A->fd = B; B->bk = A; B->fd = C; C->bk = B; printf("here is stack address leak: %p\n", &A); printf("here is heap address leak: %p\n", A); printf("now that you have leaks, get shell!\n"); // heap overflow! gets(A->buf); // exploit this unlink! unlink(B); return 0; }很明显是模拟的 Unlink 堆溢出漏洞,和题目一致,不知道这个可以先去看看这篇文章 :http://www.evil0x.com/posts/24617.html
在 gets(A->buf) 处有堆溢出,我们可以通过这个来改写A,B,C的堆空间内容。
重点当然是在unlink上 , unlink(B)做的其实就是将 B 从双向链表中取出来。
在这个双向链表中,fd指向前一个节点,bk指向后一个节点。
unlink() 所作的就是:
(B->fd)->bk=B->bk
(B->bk)->fd=B->fd
因为 OBJ 结构体的第一个成员就是fd 所以上式 == *(*B+4) = *(B+4)
**(B+4) = *B
利用2式 我们可以通过重写B在堆中的 fd 与 bk 可以实现任意内存写入
在典型的 Unlink 漏洞中是通过重写GOT中 free() 函数的地址为 我们的 shellcode 地址,但是这种方法应该早就被修复了(上面那篇文章中提到了)。
所以我们就只能是修改别的函数的返回值地址 , 下面
objdump -S unlink
看一下汇编
main() 函数如下 :
0804852f <main>: 804852f: 8d 4c 24 04 lea 0x4(%esp),