嗨,朋友你好,我是闪石星曜CyberSecurity创始人Power7089。
今天为大家带来的是【炼石计划@Java代码审计】Java代码审计之Web漏洞篇之目录穿越篇漏洞。配合JtopCMS实战讲解。内部课程文章部分分享给大家学习,如果你想利用碎片化时间系统学习Java代码审计欢迎加入我们。
【炼石计划@Java代码审计】是一个利用碎片化时间即可从入门到提升系统化学习Java代码审计的成长型知识星球。这里不仅注重夯实基础,更加专注实战进阶。强烈推荐加入我们,一起来内卷Java代码审计。
温馨提示,星球人数即将破千,价格将会上调,火速扫描加入!
进入正文
在前面的任意文件上传漏洞和任意文件读取与下载漏洞两章节中简单提到了目录穿越漏洞,本节我们配合JTopCms详细讲解下目录穿越漏洞。
目录穿越漏洞,也叫做目录遍历/路径遍历漏洞。常发生于文件上传,文件下载,文件下载等处。由于后端直接接受使用前端传来的文件名,并没有对文件名进行过滤,从而导致攻击者可通过使用../
的方式进行目录穿越,以达到下载任意文件,删除任意文件,或是将文件上传到任意目录下。
其中../
在Windows和Linux系统下意思均为向上一层目录。
任意文件上传和任意读取与下载章节案例代码均存在目录穿越漏洞,大家可以打开前两期代码回顾学习。
下面两处代码来自Java开源漏洞代码。从中可以看到,目录遍历漏洞明显特征就是直接拼接了前端传来的文件名,并且对敏感字符没有进行过滤。
大家自行分析调试研究。
来自:https://github.com/j3ers3/Hello-Java-Sec/blob/master/src/main/java/com/best/hello/controller/Traversal.java/**
* @poc http://127.0.0.1:8888/Traversal/download?filename=../../../../../../../etc/passwd
*/
@ApiOperation(value = "vul:任意文件下载")
@GetMapping("/download")
public String download(String filename, HttpServletRequest request, HttpServletResponse response) {
String filePath = System.getProperty("user.dir") + "/logs/" + filename;
log.info("[vul] 目录遍历:" + filePath);try {
File file = new File(filePath);
InputStream fis = new BufferedInputStream(new FileInputStream(file));
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
fis.close();response.reset();
response.addHeader("Content-Disposition", "attachment;filename=" + filename);
response.addHeader("Content-Length", "" + file.length());
OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
response.setContentType("application/octet-stream");
toClient.write(buffer);
toClient.flush();
toClient.close();
return "下载文件成功:" + filePath;
} catch (Exception e) {
e.printStackTrace();
return "未找到文件:" + filePath;
}
}/**
* @poc http://127.0.0.1:8888/Traversal/download/safe?filename=../
*/
@ApiOperation(value = "safe:过滤../")
@GetMapping("/download/safe")
public String download_safe(String filename) {if (!Security.checkTraversal(filename)) {
String filePath = System.getProperty("user.dir") + "/logs/" + filename;
return "安全路径:" + filePath;
} else {
return "检测到非法遍历";
}
}
来自:https://github.com/JoyChou93/java-sec-code/blob/master/src/main/java/org/joychou/controller/PathTraversal.java
public class PathTraversal {protected final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* http://localhost:8080/path_traversal/vul?filepath=../../../../../etc/passwd
*/
@GetMapping("/path_traversal/vul")
public String getImage(String filepath) throws IOException {
return getImgBase64(filepath);
}@GetMapping("/path_traversal/sec")
public String getImageSec(String filepath) throws IOException {
if (SecurityUtil.pathFilter(filepath) == null) {
logger.info("Illegal file path: " + filepath);
return "Bad boy. Illegal file path.";
}
return getImgBase64(filepath);
}private String getImgBase64(String imgFile) throws IOException {
logger.info("Working directory: " + System.getProperty("user.dir"));
logger.info("File path: " + imgFile);File f = new File(imgFile);
if (f.exists() && !f.isDirectory()) {
byte[] data = Files.readAllBytes(Paths.get(imgFile));
return new String(Base64.encodeBase64(data));
} else {
return "File doesn't exist or is not a file.";
}
}public static void main(String[] argv) throws IOException {
String aa = new String(Files.readAllBytes(Paths.get("pom.xml")), StandardCharsets.UTF_8);
System.out.println(aa);
}
}public static String pathFilter(String filepath) {
String temp = filepath;// use while to sovle multi urlencode
while (temp.indexOf('%') != -1) {
try {
temp = URLDecoder.decode(temp, "utf-8");
} catch (UnsupportedEncodingException e) {
logger.info("Unsupported encoding exception: " + filepath);
return null;
} catch (Exception e) {
logger.info(e.toString());
return null;
}
}
目录穿越漏洞绕过并不是百分百好使。在这里仅是提供一些思路。在做黑盒测试时可以尝试使用这些绕过方法。在做代码审计时还得具体代码具体分析。
比如上面漏洞代码中所提供的一处代码是安全代码,使用了while循环解码URL中字符,防范了各种URL编码来绕过。
单次的URL编码,../
结果为:..%2F
,%2E%2E%2F
。
进行两次URL编码
. = %252e
/ = %252f
\ = %255c
对字符进行Unicode编码后再进行URL编码
. = %u002e
/ = %u2215
\ = %u2216
. = %c0%2e, %e0%40%ae, %c0ae
/ = %c0%af, %e0%80%af, %c0%2f
\ = %c0%5c, %c0%80%5c
.: %c0%2e, %e0%40%ae, %c0ae
/: %c0%af, %e0%80%af, %c0%2f
\: %c0%5c, %c0%80%5c
也就是大家熟知的00阶段,用于判断后缀名,使用空字节URL编码绕过。
../../../../../passwd%00.jpg
../
仅做一次判断删除或替换../
情况,可使用..././
方式绕过。
%u002e%u002e%u2215
相对于前面章节给出的敏感文件,下面更全面一些。
C:/Users/Administrator/NTUser.dat
C:/Documents and Settings/Administrator/NTUser.dat
C:/apache/logs/access.log
C:/apache/logs/error.log
C:/apache/php/php.ini
C:/boot.ini
C:/inetpub/wwwroot/global.asa
C:/MySQL/data/hostname.err
C:/MySQL/data/mysql.err
C:/MySQL/data/mysql.log
C:/MySQL/my.cnf
C:/MySQL/my.ini
C:/php4/php.ini
C:/php5/php.ini
C:/php/php.ini
C:/Program Files/Apache Group/Apache2/conf/httpd.conf
C:/Program Files/Apache Group/Apache/conf/httpd.conf
C:/Program Files/Apache Group/Apache/logs/access.log
C:/Program Files/Apache Group/Apache/logs/error.log
C:/Program Files/FileZilla Server/FileZilla Server.xml
C:/Program Files/MySQL/data/hostname.err
C:/Program Files/MySQL/data/mysql-bin.log
C:/Program Files/MySQL/data/mysql.err
C:/Program Files/MySQL/data/mysql.log
C:/Program Files/MySQL/my.ini
C:/Program Files/MySQL/my.cnf
C:/Program Files/MySQL/MySQL Server 5.0/data/hostname.err
C:/Program Files/MySQL/MySQL Server 5.0/data/mysql-bin.log
C:/Program Files/MySQL/MySQL Server 5.0/data/mysql.err
C:/Program Files/MySQL/MySQL Server 5.0/data/mysql.log
C:/Program Files/MySQL/MySQL Server 5.0/my.cnf
C:/Program Files/MySQL/MySQL Server 5.0/my.ini
C:/Program Files (x86)/Apache Group/Apache2/conf/httpd.conf
C:/Program Files (x86)/Apache Group/Apache/conf/httpd.conf
C:/Program Files (x86)/Apache Group/Apache/conf/access.log
C:/Program Files (x86)/Apache Group/Apache/conf/error.log
C:/Program Files (x86)/FileZilla Server/FileZilla Server.xml
C:/Program Files (x86)/xampp/apache/conf/httpd.conf
C:/WINDOWS/php.ini C:/WINDOWS/Repair/SAM
C:/Windows/repair/system C:/Windows/repair/software
C:/Windows/repair/security
C:/WINDOWS/System32/drivers/etc/hosts
C:/Windows/win.ini
C:/WINNT/php.ini
C:/WINNT/win.ini
C:/xampp/apache/bin/php.ini
C:/xampp/apache/logs/access.log
C:/xampp/apache/logs/error.log
C:/Windows/Panther/Unattend/Unattended.xml
C:/Windows/Panther/Unattended.xml
C:/Windows/debug/NetSetup.log
C:/Windows/system32/config/AppEvent.Evt
C:/Windows/system32/config/SecEvent.Evt
C:/Windows/system32/config/default.sav
C:/Windows/system32/config/security.sav
C:/Windows/system32/config/software.sav
C:/Windows/system32/config/system.sav
C:/Windows/system32/config/regback/default
C:/Windows/system32/config/regback/sam
C:/Windows/system32/config/regback/security
C:/Windows/system32/config/regback/system
C:/Windows/system32/config/regback/software
C:/Program Files/MySQL/MySQL Server 5.1/my.ini
C:/Windows/System32/inetsrv/config/schema/ASPNET_schema.xml
C:/Windows/System32/inetsrv/config/applicationHost.config
C:/inetpub/logs/LogFiles/W3SVC1/u_ex[YYMMDD].log
/etc/passwd
/etc/shadow
/etc/aliases
/etc/anacrontab
/etc/apache2/apache2.conf
/etc/apache2/httpd.conf
/etc/at.allow
/etc/at.deny
/etc/bashrc
/etc/bootptab
/etc/chrootUsers
/etc/chttp.conf
/etc/cron.allow
/etc/cron.deny
/etc/crontab
/etc/cups/cupsd.conf
/etc/exports
/etc/fstab
/etc/ftpaccess
/etc/ftpchroot
/etc/ftphosts
/etc/groups
/etc/grub.conf
/etc/hosts
/etc/hosts.allow
/etc/hosts.deny
/etc/httpd/access.conf
/etc/httpd/conf/httpd.conf
/etc/httpd/httpd.conf
/etc/httpd/logs/access_log
/etc/httpd/logs/access.log
/etc/httpd/logs/error_log
/etc/httpd/logs/error.log
/etc/httpd/php.ini
/etc/httpd/srm.conf
/etc/inetd.conf
/etc/inittab
/etc/issue
/etc/lighttpd.conf
/etc/lilo.conf
/etc/logrotate.d/ftp
/etc/logrotate.d/proftpd
/etc/logrotate.d/vsftpd.log
/etc/lsb-release
/etc/motd
/etc/modules.conf
/etc/motd
/etc/mtab
/etc/my.cnf
/etc/my.conf
/etc/mysql/my.cnf
/etc/network/interfaces
/etc/networks
/etc/npasswd
/etc/passwd
/etc/php4.4/fcgi/php.ini
/etc/php4/apache2/php.ini
/etc/php4/apache/php.ini
/etc/php4/cgi/php.ini
/etc/php4/apache2/php.ini
/etc/php5/apache2/php.ini
/etc/php5/apache/php.ini
/etc/php/apache2/php.ini
/etc/php/apache/php.ini
/etc/php/cgi/php.ini
/etc/php.ini
/etc/php/php4/php.ini
/etc/php/php.ini
/etc/printcap
/etc/profile
/etc/proftp.conf
/etc/proftpd/proftpd.conf
/etc/pure-ftpd.conf
/etc/pureftpd.passwd
/etc/pureftpd.pdb
/etc/pure-ftpd/pure-ftpd.conf
/etc/pure-ftpd/pure-ftpd.pdb
/etc/pure-ftpd/putreftpd.pdb
/etc/redhat-release
/etc/resolv.conf
/etc/samba/smb.conf
/etc/snmpd.conf
/etc/ssh/ssh_config
/etc/ssh/sshd_config
/etc/ssh/ssh_host_dsa_key
/etc/ssh/ssh_host_dsa_key.pub
/etc/ssh/ssh_host_key
/etc/ssh/ssh_host_key.pub
/etc/sysconfig/network
/etc/syslog.conf
/etc/termcap
/etc/vhcs2/proftpd/proftpd.conf
/etc/vsftpd.chroot_list
/etc/vsftpd.conf
/etc/vsftpd/vsftpd.conf
/etc/wu-ftpd/ftpaccess
/etc/wu-ftpd/ftphosts
/etc/wu-ftpd/ftpusers
/logs/pure-ftpd.log
/logs/security_debug_log
/logs/security_log
/opt/lampp/etc/httpd.conf
/opt/xampp/etc/php.ini
/proc/cpuinfo
/proc/filesystems
/proc/interrupts
/proc/ioports
/proc/meminfo
/proc/modules
/proc/mounts
/proc/stat
/proc/swaps
/proc/version
/proc/self/net/arp
/root/anaconda-ks.cfg
/usr/etc/pure-ftpd.conf
/usr/lib/php.ini
/usr/lib/php/php.ini
/usr/local/apache/conf/modsec.conf
/usr/local/apache/conf/php.ini
/usr/local/apache/log
/usr/local/apache/logs
/usr/local/apache/logs/access_log
/usr/local/apache/logs/access.log
/usr/local/apache/audit_log
/usr/local/apache/error_log
/usr/local/apache/error.log
/usr/local/cpanel/logs
/usr/local/cpanel/logs/access_log
/usr/local/cpanel/logs/error_log
/usr/local/cpanel/logs/license_log
/usr/local/cpanel/logs/login_log
/usr/local/cpanel/logs/stats_log
/usr/local/etc/httpd/logs/access_log
/usr/local/etc/httpd/logs/error_log
/usr/local/etc/php.ini
/usr/local/etc/pure-ftpd.conf
/usr/local/etc/pureftpd.pdb
/usr/local/lib/php.ini
/usr/local/php4/httpd.conf
/usr/local/php4/httpd.conf.php
/usr/local/php4/lib/php.ini
/usr/local/php5/httpd.conf
/usr/local/php5/httpd.conf.php
/usr/local/php5/lib/php.ini
/usr/local/php/httpd.conf
/usr/local/php/httpd.conf.ini
/usr/local/php/lib/php.ini
/usr/local/pureftpd/etc/pure-ftpd.conf
/usr/local/pureftpd/etc/pureftpd.pdn
/usr/local/pureftpd/sbin/pure-config.pl
/usr/local/www/logs/httpd_log
/usr/local/Zend/etc/php.ini
/usr/sbin/pure-config.pl
/var/adm/log/xferlog
/var/apache2/config.inc
/var/apache/logs/access_log
/var/apache/logs/error_log
/var/cpanel/cpanel.config
/var/lib/mysql/my.cnf
/var/lib/mysql/mysql/user.MYD
/var/local/www/conf/php.ini
/var/log/apache2/access_log
/var/log/apache2/access.log
/var/log/apache2/error_log
/var/log/apache2/error.log
/var/log/apache/access_log
/var/log/apache/access.log
/var/log/apache/error_log
/var/log/apache/error.log
/var/log/apache-ssl/access.log
/var/log/apache-ssl/error.log
/var/log/auth.log
/var/log/boot
/var/htmp
/var/log/chttp.log
/var/log/cups/error.log
/var/log/daemon.log
/var/log/debug
/var/log/dmesg
/var/log/dpkg.log
/var/log/exim_mainlog
/var/log/exim/mainlog
/var/log/exim_paniclog
/var/log/exim.paniclog
/var/log/exim_rejectlog
/var/log/exim/rejectlog
/var/log/faillog
/var/log/ftplog
/var/log/ftp-proxy
/var/log/ftp-proxy/ftp-proxy.log
/var/log/httpd/access_log
/var/log/httpd/access.log
/var/log/httpd/error_log
/var/log/httpd/error.log
/var/log/httpsd/ssl.access_log
/var/log/httpsd/ssl_log
/var/log/kern.log
/var/log/lastlog
/var/log/lighttpd/access.log
/var/log/lighttpd/error.log
/var/log/lighttpd/lighttpd.access.log
/var/log/lighttpd/lighttpd.error.log
/var/log/mail.info
/var/log/mail.log
/var/log/maillog
/var/log/mail.warn
/var/log/message
/var/log/messages
/var/log/mysqlderror.log
/var/log/mysql.log
/var/log/mysql/mysql-bin.log
/var/log/mysql/mysql.log
/var/log/mysql/mysql-slow.log
/var/log/proftpd
/var/log/pureftpd.log
/var/log/pure-ftpd/pure-ftpd.log
/var/log/secure
/var/log/vsftpd.log
/var/log/wtmp
/var/log/xferlog
/var/log/yum.log
/var/mysql.log
/var/run/utmp
/var/spool/cron/crontabs/root
/var/webmin/miniserv.log
/var/www/log/access_log
/var/www/log/error_log
/var/www/logs/access_log
/var/www/logs/error_log
/var/www/logs/access.log
/var/www/logs/error.log
~/.atfp_history
~/.bash_history
~/.bash_logout
~/.bash_profile
~/.bashrc
~/.gtkrc
~/.login
~/.logout
~/.mysql_history
~/.nano_history
~/.php_history
~/.profile
~/.ssh/authorized_keys
~/.ssh/id_dsa
~/.ssh/id_dsa.pub
~/.ssh/id_rsa
~/.ssh/id_rsa.pub
~/.ssh/identity
~/.ssh/identity.pub
~/.viminfo
~/.wm_style
~/.Xdefaults
~/.xinitrc
~/.Xresources
~/.xsession
该系统内还存在其他漏洞,但本节我们的视角仅放在目录穿越漏洞处。目录穿越漏洞配合文件下载功能可以实现任意文件下载。
https://www.jtopcms.com/
关注本公众号,后台回复关键字 jtopcms ,即可获取下载地址。
名称 | 版本 |
---|---|
JTopCMS | V3版本为开源版本,V4为商业版本。我们使用的是V3版本。 |
Java版本 | JDK1.7+即可,我使用的是JDK1.8_261 |
IDEA | 版本随意,我用的最新版(破解方式可看之前发过的主题:https://t.zsxq.com/089yMeGC6) |
mysql | 5.5.29(我用的PHPstudy集成的Mysql,该版本可从软件管理处下载) |
Tomcat | Tomcat8.5.1(版本只要是Tomcat7+都可以) |
(我装的IDEA新版中下载了中文插件,对于功能指引都是以中文讲述,英文版的朋友自行对照)
①、使用IDEA打开JTopCMS,如果有如下图提示,勾选Maven项目,如下图所示:
进入后,耐心等待一会,IDEA自动下载相关依赖。
②、如果你的系统中Java有多个版本,请检查下文件-项目结构-项目
中SDK是否为1.8
,如下图所示:
③、下面给项目添加 Tomcat 运行环境,点击左上侧编辑配置...
,进入运行/调试配置页面,点击左上侧加号,选择 Tomcat 服务器下本地,如下图所示:
④、下面配置 Tomcat 安装路径,点击配置后,在 Tomcat 主目录中选择你所安装的 Tomcat 路径,如下图所示:
⑤、防止与其他软件冲突,Tomcat 服务器设置下端口号,自己随意。注意!并且勾选端口号旁边的一个选项,中文是部署 Tomcat 实例中配置的应用程序
如下图所示:
⑥、部署下工件,点击部署
,点击加号,选择工件,选择部署为war_exploded
,如下图所示:
⑦、修改下应用程序上下文也就是URL访问路径,删除默认路径,如下图所示:
⑧、修改下项目中配置文件信息,cs.properties
为项目配置文件,位于CJTopCMSV3-JTopCMSV3.0.2-OP\WebContent\WEB-INF\config\cs.properties
。
修改back_port
为访问端口号,要与 Tomcat 中设置的端口号一致
修改db_name
为jtopcmsv3
。
修改db_pw
为数据库密码。如下图所示:
①、打开PHPstudy,在软件管理-数据库
下自行安装Mysql5.5.29
版本,如下图所示:
②、在首页处启动Mysql5.5.29。然后命令行进入Mysql。
创建一个名为jtopcmsv3
的数据库。
进入jtopcmsv3
数据库。
如下图所示:
③、导入数据,数据文件在\JTopCMSV3-JTopCMSV3.0.2-OP\initData
目录下,使用source命令导入。回车即可。如下图所示:
注意:如果路径是反斜杠尾部可以不用加分号;
,如果路径是正斜杠需要加分号;
,否则会报错。
至此,配置完毕。
IDEA启动项目。
后端管理地址:http://127.0.0.1:7089/login_page
,登录账号密码为admin/jtopcms
。
前台地址需要在后端管理的站点维护-站点与栏目维护
下进行配置后才可以访问。
这个系统存在下载文件功能,但开发人员对下载目录和下载文件名做了限制,以及限制读取/下载WEB-INF
目录文件。
如何确定的下载功能?
本项目中文档文件下下用户手册。部署环境后通过抓取下载数据包确定路径后全局搜索downloadResFile
。使用经典关键字download
等都可以确定存在下载功能。
代码太多了,节约时间。我是通过部署环境后抓取下载功能数据包,在代码中全局搜索路径确定的下载文件代码,如下图所示:
根据下载路径downloadResFile
全局搜索,最终定位下载文件功能代码位于JTopCMSV3-JTopCMSV3.0.2-OP\src\cn\com\mjsoft\cms\resources\controller\ManageSiteFileAndCheckController.java
中。如下图所示:
点击进入ManageSiteFileAndCheckController.java
代码文件。第208行到第311行为下载功能代码,如下图所示:
开始分析代码,按照我当时的思路写下来的,部分步骤省略,代码不难,自行分析即可。
①、通过BurpSuite抓包也可以看到传入了三个参数,主要关注entry
和downFileInfo
这两,个刚看到时感觉就跟路径和文件名有关。在代码中分别第216行和218行处接受了这两个参数,并且使用了SystemSafeCharUtil.decodeFromWeb()
自己写的类对参数进行了处理,如下图所示:
②、跟进SystemSafeCharUtil.decodeFromWeb
,进入SystemSafeCharUtil.java
工具类,在第408到434行对参数进行了处理。判断了是否为空,并将传入的参数在做了解码操作后赋值给了target
,最后target
又做了一步decodeDangerChar
操作,如下图所示:
③、继续跟进decodeDangerChar
方法,对target做了一些替换操作,有点奇怪当时也没多想,反正没有过滤../
敏感字符,也就放过去了,继续了后面的跟踪,但其实这是绕过目录穿越限制的关键地方,下面再说。代码如下图所示:
④、回到ManageSiteFileAndCheckController.java
继续分析。第233行使用tempRoot + ".zip";
拼接了下载文件的名称赋值给zipName
,双击选中zipName
跟踪发现在第265行处使用到了zipName
,如下图所示:
⑤、跟进resService.getFullFilePathByManager
进行分析,进入到ResourcesService.java
代码中,位于JTopCMSV3-JTopCMSV3.0.2-OP\src\cn\com\mjsoft\cms\resources\service\ResourcesService.java
。在第2085行到2102行过滤了敏感字符,如下图所示:
⑥、过滤的挺全面的,考虑的挺周到的,在这绕了一会没绕过去。然后想到了当时奇奇怪怪的替换字符,研究了下发现,如果路径中/文件名中存在那些字符,则会替换成对应的字符。代码如下图所示:
通过代码可以得到如果路径中存在**!4**
则会被替换成..
,**!11**
会被替换成\\
。这样说的话路径中存在**!4****!11**
的话就可以向上遍历目录了。下面渗透测试验证一下。
渗透测试验证在Windows环境下。
①、先在桌面下新建一个名为power7089.txt
的文件,内容随意,如下图所示:
②、进入JTopCMS内容管理系统后台,访问站点门户-模板管理
功能,选择任意一个文件夹后点击下载,此时使用BurpSuite进行抓包,丢入Repeater模块下,将downFileInfo
改为power7089.txt
,在entry
后面加上**!4****!11**
,经过多次尝试最终穿越当前目录,读取到了桌面上的power7089.txt
文件,如下图所示:
③、在响应处右键选择Request in browser - in original session
,copy链接,如下图所示:
④、需要在浏览器开着BurpSuite代理的情况下访问上述链接,最终成功下载了桌面上的power7089.txt
文件,如下图所示:
(备注:如果抓不到数据包,可以试下在HTTP history中点击show all显示全部,因为下载的MIME type是压缩。文件如下图所示:)
至此,目录穿越漏洞讲解完毕。其中JTopCMS审计过程仅提炼了几个重要的点来讲解,因为代码不难,大家自行调试分析学习一下吧。代码审计自己动手分析的每一个过程都很重要!不懂的地方可以将问题整理完成后在星球里面向我提问!
外部交流群
微信添加好友Power_7089
备注Java代审外部群,稍等片刻,拉你进交流群。