目錄
- 黑馬javaweb353集復雜的條件查詢-引數名sql注入案例
- 實作分析
- 代碼分析
- 重點分析
- 嘗試利用漏洞
- sqlmap跑一下
- 加固思路
黑馬javaweb353集復雜的條件查詢-引數名sql注入案例
? 因專業原因,被迫學起了java,不過還好有舍友給我推了黑馬的學習資料,每個學期都穩過,
? 在學習程序中,發現老師寫的一處代碼存在sql注入問題,而這個注入問題并不是常見的引數內容注入,而是因為引數名可控導致注入,
? 因此記錄一下,與大家分享,
https://www.bilibili.com/video/BV1qv4y1o79t?p=354
在353集中,老師演示了一個復雜的條件查詢案例,
大致功能如下:(根據姓名,或籍貫、郵箱進行查詢)

實作分析
- 需要判斷用戶是否輸入了姓名、籍貫等
- 如果不存在則直接執行原sql陳述句
- 如果存在則拼接sql陳述句(例:and name like ‘%test%’)

代碼分析
list.jsp
將name等資料利用form表單發送到findUserByPageServlet

findUserByPageServlet.java
將引數名和引數存入一個map集合中,發送到一個實作類UserServiceImpl的findUserByPage方法中

UserServiceImpl.java
將map集合傳入一個資料庫操作實作類中(userDao)

重點分析
UserDaoImpl.java
public int findTotalCout(Map<String, String[]> condition) {
String sql = "select count(*) from user where 1=1";
StringBuilder sb = new StringBuilder(sql);
//遍歷map
Set<String> keySets = condition.keySet();
//定義一個引數的集合
List<Object> params = new ArrayList<Object>();
for (String key : keySets) {
//排除分頁條件引數
if("currentPage".equals(key)||"rows".equals(key)){
continue;
}
//獲取value
String value = condition.get(key)[0];
//判斷value是否有值
if (value != null && !"".equals(value)){
//有值
sb.append(" and "+key+" like ?");
params.add("%"+value+"%");
}
}
return template.queryForObject(sb.toString(),Integer.class,params.toArray());
}
? 大概邏輯就是,利用for回圈遍歷map集合,然后將鍵名存入key中,如果key存在且引數值存在,則將key帶入sql陳述句中拼接,
拼接陳述句:
select count(*) from user where 1=1 and name like '%?%';
而value做了預處理,不存在sql注入,
但是key沒有做預處理,我們可以通過控制引數名拼接sql陳述句,所以出現sql注入,

嘗試利用漏洞
輸入一些值進行查詢

利用burp抓包,正常查詢

當我通過burp修改引數名為**1 'and name **時,發現報錯,看到了sql陳述句,因為tomcat本身原因,遇到特殊字符會修改成html編碼傳輸到后臺進行處理,

而將引數名改成1 and name 又訪問正常,說明存在注入,
且后臺陳述句為:
select count(*) from user where 1=1 and 1 and name like "%text%"
查詢時出現了聚合函式,且tomcat不允許帶有特殊字符這個限制,所以照成不了顯注,但是可以形成時間注入及報錯注入,

sqlmap跑一下
注意:將引數名利用*代替(表示sql會在那個地方載入payload)
POST /day17/findUserByPageServlet HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:92.0) Gecko/20100101 Firefox/92.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 22
Origin: http://localhost:8081
Connection: close
Referer: http://localhost:8081/day17/findUserByPageServlet?currentPage=1&rows=5
Cookie: JSESSIONID=84FF7F7AB1AAE9A01A9396DDC07E24CA; Idea-dab618b2=533e5dc9-f76f-4a1a-9ce3-526e903cd644
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
X-Forwarded-For: 127.0.0.4
X-Originating-IP: 127.0.0.4
X-Remote-IP: 127.0.0.4
X-Remote-Addr: 127.0.0.4
*=test&address=&email=
sqlmap -r "/Users/tiger/Desktop/未命名.txt" --dbs --batch

加固思路
如果使用預處理去加固的話,會導致查詢查不出
因為預處理相當于利用問號拼接,拼接后會在欄位名兩旁添加類似雙引號的字符,導致查詢不出結果
select * from user where 1=1 and 'name' like '%t%' limit 0,5

不用預處理

所以需要更換思路,過濾字串
java專案中如何防止sql注入?
static String reg = "(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|"
+ "(\\b(select|update|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute)\\b)";
static Pattern sqlPattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE);//表示忽略大小寫
@Override
public List<User> finByPage(int start, int rows, Map<String, String[]> condition) {
String sql = "select * from user where 1=1 ";
StringBuilder sb = new StringBuilder(sql);
//遍歷map
Set<String> keySets = condition.keySet();
//定義一個引數的集合
List<Object> params = new ArrayList<Object>();
for (String key : keySets) {
//排除分頁條件引數
if("currentPage".equals(key)||"rows".equals(key)){
continue;
}
//獲取value
String value = condition.get(key)[0];
//判斷value是否有值
if (value != null && !"".equals(value)){
//判斷是否為注入
boolean sqlValid = isSqlValid(key);
if (!sqlValid){
return null;
}
//有值
sb.append(" and "+key+" like ?");
params.add("%"+value+"%");
}
}
//添加分頁查詢
sb.append(" limit ?,?");
//添加分頁查詢引數值
params.add(start);
params.add(rows);
System.out.println(sb);
System.out.println(params);
return template.query(sb.toString(),new BeanPropertyRowMapper<User>(User.class),params.toArray());
}
public static boolean isSqlValid(String str) {
Matcher matcher = sqlPattern.matcher(str);
if (matcher.find()) {
System.out.println("引數存在非法字符,請確認:"+matcher.group());//獲取非法字符:or
return false;
}
return true;
}
在判斷value值過后,加一層判斷,
將鍵名帶入isSqlValid方法中判斷,如果是注入陳述句,將會回傳一個false,并且直接回傳一個空值,

再利用sqlmap跑,已經失敗了

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/301436.html
標籤:其他
上一篇:檔案上傳漏洞專題
下一篇:C++入門——機房預約系統
