kernelsmith
I like making things and breaking things
Joshua Smith (@kernelsmith)
Michael Flanders
Josh
"Jock"
"Nerd"
Ezekiel 25:17
Nuclear ICBMs
Broken
Michael
Trouble Maker
Infamous
Dental Office
Motorhead
Pistola
"Most athletic" in HS
Suspended for semester for DoS'ing school
"Most likely to be famous" in HS
Used to work in a dental office
President of the National Honor Society in HS
Can recite Pulp Fiction Ezekiel 25:17 speech
Used to flip motorcycles
Was in charge of 50 nuclear ICBMS on 9/11
Bought a pistol off a Dell employee in a Lowe's parking lot
Since DefCon 23, surgeries +=2, metal +=2
Josh
BS Aeronautical Engr
MA Management of Info Sys
Maj, USAF (Ret)
"FuzzOps" Mgr & Senior Security Researcher
Michael
BS Electrical & Computer Engr
UT Austin
Vuln Intelligence Intern @ZDI
Analyzing Submitted Cases
Original vulnerability
How not to fix it
How to learn nothing from the last one
How to take a better whack at it
How to do it pretty well
Lingering concerns
https://slides.com/kernelsmith/bsidesaustin2018/
ZDI-14-385 / CVE-2014-8420
Disclaimer
Late 2014
Brandon Perry
Dell Sonicwall GMS Virtual Appliance
Web App Auth'd -> root on VA
Command Injection
AKA CVE-2014-8420
"Global Management Systems provides a holistic way to manage your entire network security environment by business processes and service levels."
Typically easy for VAs
Mount virtual disk & partitions in another (Linux) VM
Explore filesystem
Grab bins, source, bytecode etc
Alter boot files/services to get shell
RE & decompile as nec. (JSP etc)
If you can get a shell (from exploit or above)
Debug
Explore
Tar-up & pull bins, source, bytecode etc
Is...a bit messy
*.sh
dispatcher
gmc.jar
XmlRpcClient.class
ApplianceMainPage.class
HostConfigManager.class
hostConfig.jsp
0.0.0.0:21009 (TCP)
java (XML-RPC)
0.0.0.0:8035 (TCP)
dispatcher (XML-RPC)
Input
Input
The input validation is here
The bug (root cause) is here
Post -> /appliance/applianceMainPage
Add vmdk to another VM & explore
lsblk /dev/sdb -o name,label,fstype,size
NAME LABEL FSTYPE SIZE
sdb 250G
├─sdb1 ROOT ext3 7.5G
├─sdb2 SAFEMODE ext3 1.9G
├─sdb3 SYSINFO ext3 102M
├─sdb4 1K # auto-mounting Linux systems will call this 00
├─sdb5 swap 1.9G
└─sdb6 DATA ext4 238.7G
Mount each & explore
In ROOT:
conf.img detect-box.sh GMSVP-image.ext2
img.config initrd.img modules.tar.bz2
root.img sw.conf vmlinux
*.sh
dispatcher
gmc.*
XmlRpcClient.*
ApplianceMainPage.*
HostConfigManager.*
hostConfig.jsp
Lots of potentially interesting items but...
mount -t ext2 GMSVP-image.ext2 /mnt/GMSVP-image/
cd /mnt/GMSVP-image
# try to find the page by name
find . -iname "*appliancemainpage*"
./Tomcat/webapps/appliance/WEB-INF/classes/com/sonicwall/\
appliance/servlets/ApplianceMainPage.class
#snip
./Tomcat/webapps/appliance/applianceMainPage.jsp
# try to find the page using a string on the page
grep -Rni "IPv4 Settings" * 2>/dev/null
Tomcat/webapps/appliance/hostConfig.jsp:500:
<span class=objItemSpacing><font class=sectionFont> IPv4 Settings </font></span>
ApplianceMainPage.*
hostConfig.jsp
Decompile w/favorite java decompiler
*.sh
dispatcher
gmc.*
XmlRpcClient.*
ApplianceMainPage.*
HostConfigManager.*
hostConfig.jsp
Posts are handled by `doPost` in jsp
grep -R "doPost" * | grep -v LogUtil
classes/com/sonicwall/appliance/servlets/ApplianceMainPage.class
#snip
$ grep -R XMLRPCClient *
util/XMLRPCClient.java: public class XMLRPCClient
# looking there you'll also find
config.setServerURL(new URL("http://localhost:21009"));
$ netstat -antp | grep 21009
tcp 0 0 :::21009 :::* LISTEN 2094/java
$ ps aux | grep 2094
root 2094 0.0 2.0 559896 63004 ? Sl /opt/GMSVP/jre/bin/java -cp...
Now it's just "following your nose"
Refs HostConfigManager & data stored in hmInfo
hmInfo = (HashMap)XMLRPCClient.obtainRpcClient().invoke("get_hostname");
XmlRpcClient.*
HostConfigManager.*
*.sh
dispatcher
gmc.jar
XmlRpcClient.*
ApplianceMainPage.*
HostConfigManager.*
hostConfig.jsp
Java command line
The `-cp` option lists the class paths
The -D sets a property value
-cp /opt/GMSVP//Scheduler/gmc.jar:\
/opt/GMSVP//Scheduler/applianceUtil.jar \
#snip
-DconfigFile=/opt/GMSVP//conf/sgmsConfig.xml com.sonicwall.appliance.gmc.GMCService \
./GMCService.properties
So configFile set to sgmsConfig.xml for GMCService
Properties file defines the XML-RPC interface
gmc.jar
0.0.0.0:21009 (TCP)
java (XML-RPC)
Where does the GMC service handle the RPC?
GMCService.properties:
gmc.service.port=21009
[method]get_hostname=com.sonicwall.appliance.gmc.DispatcherHandler
[method]route=com.sonicwall.appliance.gmc.DispatcherHandler
[method]set_hostname=com.sonicwall.appliance.gmc.DispatcherHandler
#snip
SocketXmlRpcClient client = new SocketXmlRpcClient();
return client.execute(methodName, params);
DispatchHandler.class
So...moar XML-RPC?
*.sh
dispatcher
gmc.jar
XmlRpcClient.*
ApplianceMainPage.*
HostConfigManager.*
hostConfig.jsp
0.0.0.0:21009 (TCP)
java (XML-RPC)
0.0.0.0:8035 (TCP)
dispatcher (XML-RPC)
DispatcherHandler.class
SocketXmlRpcClient.class
XmlRpcSocketTransportFactory.class
XmlRpcSocketTransport.class
socket = new Socket("127.0.0.1", 8035);
So what's on 8035?
$ netstat -antp |grep 8035
tcp 0 0 0.0.0.0:8035 0.0.0.0:* LISTEN 1886/dispatcher
$ ps aux | grep 1886
root 1886 0.0 0.0 ... /opt/vsa/bin/dispatcher -d -c \
/mnt/old_root/mnt/rootdev/00/default.xml
gmc.jar
0.0.0.0:21009 (TCP)
java (XML-RPC)
dispatcher
0.0.0.0:8035 (TCP)
dispatcher (XML-RPC)
*.sh
dispatcher
gmc.jar
XmlRpcClient.*
ApplianceMainPage.*
HostConfigManager.*
hostConfig.jsp
Dispatcher binary
ConfigManager::updateHostName(char const*, char const*)
//...
mov esi, offset aSetname_shName ; "/setName.sh --name="
mov rdi, rbx
call __ZNSs6appendEPKcm ; std::string::append(char const*,ulong)
//...
call __ZN4snwl6systemERKSs ; snwl::system(std::string const&)
Not all vulnerable fields follow
the same path:
//for the route vuln, dispatcher: calls
snwl::system("/sbin/route add", attacker_str)
// -> in libsnwlcommon.so
system("/sbin/route add, attacker_str")
dispatcher
*.sh
ZDI-14-385 / CVE-2014-8420
DNS -> dnsSetup.sh
Domain -> setName.sh
Gateway -> gwSetup.sh
Hostname -> setName.sh
IP -> ifSetup.sh
Netmask -> ifSetup.sh
NTP -> ntpSetup.sh
Route -> system("/sbin/route add", str)
post = {
'action' => 'host_config',
'task' => 'save',
'hostname' => "fdsa",
'domain' => 'example.com',
'ip' => "`#{payload.encoded}`",
'subnetMask' => '255.255.255.0',
'gateway' => '192.168.1.254',
'dnsServer1' => '8.8.8.8',
'dnsServer2' => '',
'dnsServer3' => ''
}
However, vendor knows code base way better than you/us
How not to do it
Don't normally test patches
2014: Nearly 1400 submissions (430 published)
2017: Nearly 2400 submissions (1009 published)
+ research + conferences + software installation etc...
It couldn't hurt to change the injection char right?
But...
*.sh
dispatcher.cpp
gmc.jar
XmlRpcClient.*
ApplianceMainPage.*
HostConfigManager.*
hostConfig.jsp
ApplianceMainPage.class
ApplianceMainPage.*
if(paramValues[i] != null && paramValues[i].indexOf('`') >= 0)
{
badParamName = paramName;
badParamValue = paramValues[i];
isValid = false;
break;
}
//...
if(!isValid)
throw new ServletException((new
StringBuilder()).append("LinuxCommandInjectionAttempt:")\
.append(badParamName).append(":").append(badParamValue).toString());
else
return isValid;
}
Thoughts?
ZDI-15-231 / CVE-2015-3990
Failed patch of ZDI-14-385
Command injection in multiple fields can't be fixed by looking for a `
How not to do it
Now...you know I gotta take a peek
*.sh
dispatcher.cpp
gmc.jar
XmlRpcClient.*
ApplianceMainPage.*
HostConfigManager.*
hostConfig.jsp
ApplianceMainPage.*
ApplianceMainPage.*
protected boolean validateFormElementForCommandInjection(HttpServletRequest request)
throws ServletException
{
boolean isValid = true;
Enumeration parameterNames = request.getParameterNames();
String commandSubstitutePattern = ".*\\$\\(.*\\).*"; // <---
//<snip>
if(paramValues[i] != null && paramValues[i].indexOf('`') >= 0)
{
badParamName = paramName;
badParamValue = paramValues[i];
isValid = false;
break;
}
if(paramValues[i] != null && paramValues[i].matches(commandSubstitutePattern))
{ //<snip>
Thoughts?
ZDI-16-164 / CVE-2016-2396
Failed patch of ZDI-15-231
Command injection in multiple fields can't be fixed by looking for ` and stripping out $()
How not to do it
I quickly tried all injection approaches I could think of
Fail.
Yay!
Right?
Don't have the time to pursue further, put on backburner
But, did write a script to "auto-mount"
January 2018
hostConfig.jsp
Domain/Host
Regex
ApplianceMainPage.class
$() and `` check
Normal User
Josh
hostConfigManager.class
Command Injection
Domain/Host
Regex
/^([a-zA-Z][-a-zA-Z0-9]*[a-zA-Z0-9]\.)+[a-zA-Z][-a-zA-Z0-9]*[a-z0-9]$/g
/(?=^.{1,254}$)(^(?:[a-zA-Z0-9-_]{1,63}\.?)+(?:[a-zA-Z0-9]{2,})$)/g
hostConfig.jsp Version 8.0
hostConfig.jsp Version 8.2+
ZDI-16-164 / CVE-2016-2396
Input
*.sh
dispatcher.cpp
gmc.jar
XmlRpcClient.class
ApplianceMainPage.class
HostConfigManager.class
hostConfig.jsp
public Object execute(final XmlRpcRequest request)
throws XmlRpcException {
...
if (this.checkPayload(methodName, params, ret)) {
final SocketXmlRpcClient client =
new SocketXmlRpcClient();
ret = client.execute(methodName, params);
}
return ret;
}
gmc.jar
dispatcher.cpp
*.sh
DispatcherHandler.class
private boolean checkPayload(String methodName,
Object[] params,
Object returnMsg)
{
boolean ret = false;
switch (methodName)
{
case "set_hostname":
ret = validateHostName(params, returnMsg); break;
case "set_net_if":
ret = validateNetInterface(params, returnMsg); break;
case "set_dns":
ret = validateDNS(params, returnMsg); break;
case "route":
ret = validateRoute(params, returnMsg); break;
case "set_ntp":
ret = validateNTP(params, returnMsg); break;
default:
ret = true;
}
return ret;
}
private static String hostnamePattern =
"(?=^.{1,64}$)^[a-zA-Z0-9-]+(?<!-)$";
private static String domainPattern =
"(?=^.{1,254}$)(^(?:[a-zA-Z0-9-_]{1,63}\\.?)+(?:[a-zA-Z0-9]{2,})$)";
/(?=^.{1,254}$)(^(?:[a-zA-Z0-9-_]{1,63}\.?)+(?:[a-zA-Z0-9]{2,})$)/g
DDI-VRT-2016-55
Input
*.sh
dispatcher.cpp
gmc.jar
XmlRpcClient.class
ApplianceMainPage.class
HostConfigManager.class
hostConfig.jsp
0.0.0.0:21009 (TCP)
java (XML-RPC)
0.0.0.0:8035 (TCP)
dispatcher (XML-RPC)
gmc.service.port=21009
[method]set_hostname=com.sonicwall.appliance.gmc.DispatcherHandler
[method]set_net_if=com.sonicwall.appliance.gmc.DispatcherHandler
[method]set_dns=com.sonicwall.appliance.gmc.DispatcherHandler
[method]route=com.sonicwall.appliance.gmc.DispatcherHandler
[method]set_ntp=com.sonicwall.appliance.gmc.DispatcherHandler
[method]set_time_config=com.sonicwall.appliance.gmc.DispatcherHandler
{
case "set_hostname":
case "set_net_if":
case "set_dns":
case "route":
case "set_ntp":
default:
ret = true;
}
checkPayload(...)
The Digital Defense Bugs
. $VSA_HOME/bin/functions.sh
...
MYTZ=`getParam "$1"`
...
if [ -n "$MYTZ" ]; then
rm /etc/localtime
ln -s /usr/share/zoneinfo/ \
$MYTZ/etc/localtime
fi
defaultTimeZone.put("3", new String[] { "3", "America/Anchorage", ...);
defaultTimeZone.put("4", new String[] { "4", "America/Los_Angeles", ...);
defaultTimeZone.put("290", new String[] { "290", "Pacific/Auckland", ...);
defaultTimeZone.put("300", new String[] { "300", "Pacific/Tongatapu", ...);
this.webserver = new GMCWebServer(getPort());
this.webserver.setParanoid(true);
this.webserver.acceptClient("127.0.0.1");
Probably Not Much, But Let's Check Anyways
Input
*.sh
dispatcher.cpp
gmc.jar
XmlRpcClient.class
ApplianceMainPage.class
HostConfigManager.class
hostConfig.jsp
0.0.0.0:21009 (TCP)
java (XML-RPC)
0.0.0.0:8035 (TCP)
dispatcher (XML-RPC)
`whoami`
$(whoami)
Security bug fixes should probably be reviewed by someone with a security background
Patching the crunchy outer shell is easier, but riskier
Coordinated disclosure works
Sometimes you have to be patient
Dell has made some great improvements but...
XRefs to
snwl::system()
Stock photos FTW!
Joshua Smith (@kernelsmith)
Michael Flanders
Questions?
https://github.com/thezdi
https://slides.com/kernelsmith/BSidesAustin2018
Josh
"Jock"
"Nerd"
Ezekiel 25:17
Nuclear ICBMs
Broken
Michael
Trouble Maker
Infamous
Dental Office
Motorhead
Pistola
"Most athletic" in HS
Suspended for semester for DoS'ing school
"Most likely to be famous" in HS
Used to work in a dental office
President of the National Honor Society in HS
Can recite Pulp Fiction Ezekiel 25:17 speech
Used to flip motorcycles
Was in charge of 50 nuclear ICBMS on 9/11
Bought a pistol off a Dell employee in a Lowe's parking lot
Since DefCon 23 surgeries +=2, metal +=2
By kernelsmith