题目地址: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)