首页
论坛
课程
招聘
[原创]2016 hctf ->fpwn
2019-6-10 10:33 5249

[原创]2016 hctf ->fpwn

2019-6-10 10:33
5249

2016HCTF -->


https://github.com/zh-explorer/hctf2016-fheap


  源码已公布,我们gcc 编译:

gcc main.c -pie -fpic -o pwn



执行程序,因为存在\n的原因,我们输入的字符必须少于一位




感觉程序的逻辑不复杂,算是 中规中矩的pwn吧


ida静态:


    1 create:


    首先刚进去就:

ptr = (char *)malloc(0x20uLL);


  if ( nbytes <= 0x1000 )   //我们输入的size必须小于等于 0x1000


nbytesa = strlen(&buf);

    if ( nbytesa > 0xF )  ;


   当申请的size 大于0xf的时候:

dest = (char *)malloc(nbytesa);

           为dest申请内存,然后:

strncpy(dest, &buf, nbytesa);    //直接往dest重写东西


    之后将dest的内存地址放到ptr的第一位

*(_QWORD *)ptr = dest;  


    ptr+3的位置放freeLong函数地址:


ptr+4的位置来存储str_size


*((_DWORD *)ptr + 4) = nbytesa;   


接着:

    

if ( !*((_DWORD *)&Strings + 4 * i) )

      {

        *((_DWORD *)&Strings + 4 * i) = 1;

        *((_QWORD *)&Strings + 2 * i + 1) = ptr;

        printf("The string id is %d\n", (unsigned int)i);

        break;

      }


    String全局变量,地址->.bss:00000000002020C0

        String[i].inuse = 1

    String[i].str = ptr <--存储的我们申请的string的写入地址空间


    当申请的size小于0xF的时候:

strncpy(ptr, &buf, nbytesa);

    ptr的第一位存储size

*((_QWORD *)ptr + 3) = freeShort;


    ptr的第三位存储freeShort

    




总结:

    1.当size大于0xf时:

    string结构的结构:

    struct string{

    *buf; //1


    freeLong;  //3

    size;  //4

}


 2.当size<=15时:

    struct string{

    *buf;   //1


    SIZE;

    freeShort;  //4

}


至此我们搞懂了这个程序的数据结构



看第二个delete:


*((_DWORD *)&Strings + 4 * v1) = 0;   将全局变量String里存储的inuse置为0,但是ptr却没有置为0,存在uaf



    gdb调试一波:



当我建立三个string之后(前两个size->5   最后一个size->20)




溢出思路:

    我们先申请两个个小于0xf的堆块,然后将其释放,之后申请0x20的堆块,这样子我们就可以在原来string1的位置开始写入数据了,首先覆盖掉free函数指针,改为我们的所需要控制的函数指针,便可以劫持程序执行流

但是因为程序开启保护pie,我们需先泄露程序基地址,然后才可以去的libc中的函数地址




因为低三位不变得原因,我们将低三位覆盖进去就行(是call puts函数得低三位):

readelf -a pwn | grep -E "free"


objdump -d -M intel pwn | grep puts


     dbf:    e8 9c fb ff ff           call   960 <puts@plt>


objdump -d -M intel pwn | grep printf

beichen@ubuntu:~/桌面/19lanmao/uaf/2016hctf$ objdump -d -M intel pwn | grep printf

00000000000009a0 <printf@plt>:

     d96:    e8 05 fc ff ff           call   9a0 <printf@plt>

     df7:    e8 a4 fb ff ff           call   9a0 <printf@plt>

     ef1:    e8 aa fa ff ff           call   9a0 <printf@plt>

     f3d:    e8 5e fa ff ff           call   9a0 <printf@plt>

    10db:    e8 c0 f8 ff ff           call   9a0 <printf@plt>

beichen@ubuntu:~/桌面/19lanmao/uaf/2016hctf$


用这个0xd96得就行




再确定printf函数得参数偏移时:


于此处下断,进去后:




hex(0x7ffdc6278cb8 - 0x7ffdc6278c38)  /  8  +  6

>>> hex(0x7ffdc6278cb8 - 0x7ffdc6278c38)

'0x80'

>>> 0x80/8

16.0

>>> 16+6

22



为printf函数得第22个,那便为格式化串得第21个字符



exp:





执行:


[公告]《安卓APP加固攻与防》训练营!Android逆向分析技能,干货满满,报名免费赠送一部手机!

上传的附件:
  • pwn (13.36kb,6次下载)
收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回