环境搭建

这里使用docker搭建环境:

docker run -d -p 127.0.0.1:8080:8080 -p 127.0.0.1:9090:9090 webgoat:webgoat

注意保证8080和9090端口空闲,不可以自定义端口,否则webwolf将无法使用。

或者使用java17运行Github最新版的jar包,我使用的是8.2.2版本。

注意:docker运行的和jar包版本有一些出入。

工具

官方推荐的是OWASP ZAP来做报文拦截和分析。可以设置断点,帮助分析,也可以模拟重复请求。

General

HTTP Basics

2

本题意在让用户体验Http请求的发送,只要能够发送请求就通过了。

随便输入一个,点击GO,成功发送请求即通过。

3

本题意在让用户运用浏览器的开发者工具或者ZAP等抓包工具对请求进行抓取查看。只要能够查看到请求的参数,就能获得本题的答案。

问发送表单请求时用的HTTP方法,填POST。

问magic number,先随便填一个,用调试工具查看请求,就能看到magic_num了

image-20221214215326848

HTTP Proxies

6

意图:通过软件代理,劫持数据包,修改通信内容。

答案:可以用推荐的ZAP工具,也可以用Burp之类的其他工具,在软件提供的浏览器中来到WegGoat发送请求,通过断点拦截post请求,然后对内容进行修改。修改有四处:

  1. 更改Http方法为GET
  2. 删去请求体
  3. 将原来请求体中的内容作为参数加入第一行的路径,记得把空格变成加号(+)
  4. 添加一个请求头。

之后发送,就可以通过了

Developer Tools

4

意图是学会简单使用浏览器的开发者工具。F12打开,进入Console,输入提示中的代码回车执行,就可以看到输出了,将phoneHome Response is 后面的数字拷贝出来作为答案提交通过。

image-20221217203523840

6

意图:学会使用开发者工具Network模块

答案:查看network请求的Payload,就找到答案了

image-20221217203945750

CIA Traid

意图:了解安全属性的三个方面:机密(数据不开放给未授权用户)、完整(整个过程中数据保持准确可信完整)、可用(数据可被授权用户访问)

答案:3142

Crypto Basics

2

意图:了解base64编解码

答案:将给出的base64编码放在在线解码网站中解码,就可以看到以冒号分隔的用户名和密码

3

意图:了解xor编码

答案:WebSphere {xor} password decoder and encoder (strelitzia.net) 在这里解密,xor带有加密,但是默认密码如果不改的话还是会被很轻松找出。答案是databasepassword

4

意图:了解hash算法,并了解这种加密的缺点(彩虹表攻击)

答案:查彩虹表https://www.cmd5.com/。第一个是password,第二个是admin

6

意图:了解签名,用openssl动手操作给文本签名

答案:这题比较麻烦。

  1. 首先把私钥复制下来,到test.pem
  2. openssl rsa -modulus -in test.pem -out test.modulus -noout,将模数输出到文件。务必要进入文件删除前面的Modulus=和最后的换行
  3. openssl dgst -sign test.pem -sha256 -out modulus.signature test.modulus 用私钥给模数签名。
  4. openssl enc -base64 -in modulus.signature -out signature.base64 转为base64,变成可见字符。
  5. 将前面的模数和最后的base64编码复制过去,通过

8

这个题还是有一定难度的。这里我总结了两个做法,第一种是参照晚上的题解(WebGoat 8.1 靶场 刷题通关教程全攻略 - General - CodeAntenna),第二种是我在通过第一种方法通关后找到的更方便的解法。

首先先将镜像运行起来,然后通过docker exec -it <containerid> bash的方法进入容器进行初步调查。探索了/home和尝试搜索secret关键字后无果,于是目标盯上了没有权限读取的/root目录。执行whoami命令,发现自己只是一个webgoat用户,不是root用户,也不知道root的密码。怎么办呢?

方法一

因为是容器,其实是可以在物理机任意修改容器内的文件的,第一种方法就是将/etc/passwd复制出来,改成一个自己的密码之后再复制回去覆盖掉原文件。

docker cp <containerid>:/etc/passwd ~/passwd 复制出来

mkpasswd -m sha-512 123456创建一个密码,然后把这个密码放到passwd中root对应后面的x处。

docker cp ~/passwd <containerid>:/etc/passwd将文件复制回去

重新进入容器,su root,然后输入自己设置的密码123456,就可以切换到root用户了。进入root中,发现果然有一个叫做default_secret的文件,然后按照webgoat的题目提示进行解密就可以了。这里作者也是想暗示,默认的secret不可靠吧,一定要记得改掉。

方法二

目标怀疑是/root下的东西时,可以直接用docker cp <containerid>:/root ~把整个目录和内部的内容全部复制出来,之后想怎么看就怎么看,不用在乎容器内的权限问题了。

本章最后一节还提到了,要准备开始应对未来的量子计算机,使用新的加密方法了。诚然,如果以后量子计算机得到应用,现在这些很多加密算法所依赖的破解时间就不复存在,无法继续保护数据。

Injection

SQL Injection (intro)

2

意图:熟悉SQL

答案:select department from Employees where first_name=’Bob’(只要能查出来Bob Franco的部门数据即可。

3

意图:熟悉DML类SQL(数据管理)

答案:update employees set department=’Sales’ where first_name=’Tobi’

4

意图:熟悉DDL类SQL(数据定义类)

答案:ALTER TABLE employees ADD phone VARCHAR(20);

5

意图:熟悉DCL类SQL(数据控制)

答案:GRANT SELECT, INSERT, UPDATE, DELETE ON grant_rights TO unauthorized_user;

9

意图:体验SQL注入

答案:SELECT * FROM user_data WHERE first_name = ‘John’ AND last_name = ‘’ or ‘1’ = ‘1’

10

意图:数字型SQL注入。

答案:SELECT * From user_data WHERE Login_Count = 0 and userid= 0 OR 1 = 1

后面的UserID是可以输入字符串的,而前面的Login_Count输入的内容要被转化为数字,因此只能在userid处注入。因为注入的直接是数字,所以叫做数字型SQL注入。

11

意图:使用SQL注入破坏系统安全的机密性

答案:SELECT * FROM employees WHERE last_name = ‘ haha or '1' = '1-- ‘ AND auth_tan = ‘ ‘;

--表示后面的内容为注释。

12

意图:使用SQL注入破坏系统安全的完整性

答案:SELECT * FROM employees WHERE last_name = ‘Smith‘ AND auth_tan = ‘3SL99A'; update employees set salary = 114514 where last_name = 'Smith‘;

13

意图:使用SQL注入破坏系统可用性

答案:Smith’;drop table access_log;–

先输入Smith查找自己的记录,这次不像前几次,没有给出SQL语句,要靠自己猜测。

SQL Injection(advanced)

3

意图:使用UNION和多语句连接等技巧查询其他表。

答案:haha' UNION select userid, user_name, ' ', ' ', password, cookie, 0 from user_system_data-- 或者 haha'; select * from user_system_data --。密码答案passW0rD

根据题目提示,可以使用UNION关键字或者连接另一个查询语句来获得其他表中的内容。使用UNION的时候注意需要保持检索的列数和类型一致,无关内容可以自己在select中用一些常量进行替代。

5

意图:练习SQL盲注

答案:用户名tom 密码thisisasecretfortomonly

这道题可以说是非常麻烦困难。注入的入口只有一个,就是在Registry的用户名输入框,后台在检查用户名是否存在的时候使用的SQL查询语句有注入漏洞,其他都是安全的。还有一点想吐槽的就是,明明题目中给的是Tom,答案为什么是小写的tom。。但是仍然可以从这个题中学习到一些知识。

发现漏洞的过程在于,使用haha' or 1=2--之类的用户名注册账号时,每次都会返回创建成功。这里一开始感觉很奇怪,后来还是理解了。后台判断的逻辑就是这个查询语句是否有输出,如果没有输出就判断用户不存在,于是重新插入一个。

虽然有漏洞但是利用会比较难。如果想要修改tom用户的密码,需要知道所在的数据库表名,这个还是很难猜测的。于是先从当前表的字段猜起,获得tom用户的密码,就可以进行登录。猜测该表中应该还有一个字段password,用来存储用户的密码。输入一个语句试验一下,例如haha' and password='123,发现没有报错(如果使用了不存在的字段名查询会报错),说明确实有这样一个password字段。接下来就是猜测tom的密码了。本题的困难之处在于,可以利用的漏洞是一个只会回答yes或者no的盲注漏洞,不能获得任何信息。但是这样依然比直接猜密码强,因为可以借助substring函数对密码的每一位进行分别猜测,效率要比直接暴力破解高很多。这个破解过程可以借助其他工具,因为比较麻烦,我也没有尝试。

我采用了另一种投机取巧的方法:直接通过本章第3题的入口,通过select * from INFORMATION_SCHEMA.TABLES查找所有表名,其中有个CHALLENGE_USERS的表应该就是本题中使用的表。直接select获得密码即可。算是通过第三题解决了第五题。

6

答案:43234

SQL Injection(mitigation)

本部分参考:WebGoat SQL injection mitigation lessons 5 6 9 10 | by PVXs | Medium

5

意图:使用preparedStatement编写安全、没有SQL注入漏洞的代码。

答案:getConnection
PreparedStatement statement
prepareStatement
?
?
statement.setString(1, name)
statement.setString(2, mail)

6

意图:使用安全的Java代码连接JDBC并从数据库中查询数据。

答案:

try {
    Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPW);
    PreparedStatement statement = conn.prepareStatement("SELECT status FROM users WHERE name=? AND mail=?");
    statement.setString(1, "name");
    statement.setString(2, "mail");
    statement.executeUpdate();
} catch (Exception e) {
    System.out.println("Oops. Somethint went wrong!");
}

9

意图:绕过一些过滤输入的语句,进行SQL注入

答案:aha';/**/select/**/*/**/from/**/user_system_data--

重复上次的答案发现现在加了过滤条件,不能输入空格。但是在SQL里面即使不用任何空格,多行注释/**/也可以达到分隔关键词的效果。于是将所有空格替换为多行注释,问题解决。

10

意图:绕过更多输入过滤语句,进行SQL注入

答案:aha';/**/selselectect/**/*/**/frfromom/**/user_system_data--

这次对sql关键词进行了查找删除,但是可以采用frfromom这种形式

12

意图:对preparedStatement的OrderBy进行盲注。

答案:104.130.219.202

根据上一节的提示,Order By语句后面可以使用case when(…) then x else y的形式注入含有条件判断的sql语句,这里就算是做了一层preparedStatement防范也还是会被利用。

整个界面没有什么输入的地方,但是注意到点击表头的字段进行排序显示的时候会向后端发送请求,查看这个请求的内容,发现其中直接在请求参数里面直接包含了排序的依据字段。通过Burp等工具,启动proxy对请求进行拦截修改:

image-20230101085401731

这里就实现了SQL盲注,可以用when里面的条件,配合上substring函数,就可以对数据库的内容进行猜测。题目中已经给出了ip地址后面的内容,我们只需要猜测得到前三位就可以了。一个猜测的测试如下:(case+when+(select+substring(ip,3,1)+from+servers+where+hostname='webgoat-prd')+=+'4'+then+status+else+ip+end。如果猜对,返回的结果就是按照status排序的,不然就是按照ip排序的。

substring函数的三个参数的意思分别是字段名、子串开始位置和截取长度,每次猜对一位再猜下一位。最后前三位猜完是104。

Path traversal

2

意图:利用Path traversal漏洞改写文件

答案:在Full Name处写一个含有../的路径,例如../ooo就可以在规定路径外写文件。

正常选择头像后提交,下面提示图片被成功上传到系统的规定路径下了,发现最后的路径文件名和用户名相同。在用户名出写一个含有../的路径跳脱到规定路径外就通过了。