目录
一、环境的配置
(1)安装docker
(2)WebGoat获取
(3)burp suite的配置
二、Introduction
三、General
(1)HTTP Basics
(2)HTTP Proxies
(3)Developer Tools
(4)CIA Triad
(5)Crypto Basics
四、(A1)Injection
(1)SQL Injection(intro)
(2)SQL Injection(advanced)
(3)SQL Injection(mitigation)
(4)Path traversal
五、(A2) Broken Authentication
(1)Authentication Bypassess身份验证绕过
(2)JWT tokens
这里用的时vm中的kali虚拟机安装的,建议以root身份来运行
kali安装docker环境_欧晨eli的博客-CSDN博客_kali安装docker
sudo docker pull webgoat/webgoat-8.0
sudo docker pull webgoat/webwolf
sudo docker pull webgoat/goatandwolf
之后输入 docker images,
kali里面自带burp suite,启动burp suite,因为这里的话要用到8080端口来开docker,所以我们将burp suite的代理换成8081,
然后打开kali自带的Firefox浏览器,我们选择
然后我们拉到最下面
代理设置完成,安装证书,搜索http://burp
保存到一个路径里面,还是原来那个页面
导入下载的证书,出现我画圈的那个就是成功了,最后,我们再输入about:config
搜索network.proxy.allow_hijacking_localhost,双击改为true,不然burp suite就没办法抓到本地127.0.0.1的包了。
这玩意没啥东西,就是介绍
这里讲了一些http中基本的知识
第一页说了目标,一些知识点,看不懂的朋友可以用浏览器翻译一下,这里就直接上题目了
先到第2页,我们随便输入一个字符串,然后burp suite抓包,将几个get型放掉
看到是post型,我们再放掉这个包,看到我们提交成功了,并且上面那个第二页的2也变成了绿色,说明我们成功了
第3页,他问我们刚才抓的那个包是什么类型的,明显是post型,然后下面那个空我们不知道是什么,随便填一个抓包,
成功过关
这一关是介绍另一款抓包软件ZAP的,我们用的是burp suite是一样的,抓包,按照他的要求进行修改
提交,成功
这一部分介绍了浏览器上的开发者工具。
按要求在控制台输入响应函数,得到一个随机数:
下面一关,要我们抓包,我们点击go,抓包,拿到数据提交
这里是将信息安全三要素(机密性,完整性,可用性),题目答案是CADB(我的是这样)
这一关教你一些解码、编码、加密等知识
第2页,他给了我们一串字符,叫我们拿去做base64的解码,这个在burp suite里面自带的有解码的模块,我们点击decode
可以看到解码成功
第3页,这是一串用IBM的WebSphere工具中的编码规则处理的,网上找一个工具
以上工具地址:WebSphere Password Decoder (sysman.nl)
第4页,解密两段hash串,直接在网上搜cmd5,直接解密,
第6页,破解RSA密码,他给了我们密钥,对,就是老长那一段,复制到一个文件里,然后我们使用Kali自带的openssl来进行破解,
openssl rsa -in /root/key.key -modulus
-in 后面跟你的路径
然后
echo -n "9C2484492F65191FC6BF085D50B452EFB3F5EE299D426C44949A2DCBD19110A3E8849006B3E565E0DA79B17607F1EB9E08C3102FCAFC421F40F04EC7A83D62D7C575B8BF3EA19DC63E86E9C7ACAFA7CC83E330E7B60C55DF3B6CDA5251421A32B6A56DFF7DC3E90EB2EDAAC2581628123042B6FC3C189FCEA062BDF4570CADFB5163D379FF691376AE7AC47458B78952051BBEF1C64ED3768F6493E7F64899EFA6359D0B0FC8DB192BFC44565C5BD1E2BE29F60BB6864185C9C70255CE7F4BCB776A910640C85067ACA24E86B92229BF0B1BD28050E987A82E4C16D67B9F063E110B89D424F3AFA84A2460870F892570401B316244147952CB350D8779A077A1" | openssl dgst -sign ./privatekey -sha256 -out ./dgst.txt
base64 ./dgst.txt > result
生成的result即为签名
这里是一些SQL注入的知识
第2页,请看示例表。尝试检索员工 Bob Franco 的部门。请注意,您已在此分配中被授予完全管理员权限,无需身份验证即可访问所有数据。
我们写一个sql查询语句来查询
SELECT department FROM employees WHERE first_name='Bob'
SELECT department FROM employees WHERE userid=96134
这两个都可以,employees在题目中给出来了,
其他语句都可以试试,只要是能定位到Bob的就可以,注意:如果是字符串类型的要加单引号。
第3页,他让我们将Development改成Sales,首先我们要知道update这个函数怎么用,
SQL UPDATE 语句 | 菜鸟教程 (runoob.com)
我们在本地MySQL命令行里实战一下:
刚开始是这样的,然后我们修改
update users set username='hhh' where id=1
然后再看这道题:
update employees set department='Sales' where first_name='Tobi'
第4页, 要我们在表employees上面加上一列phone
这里要用到alter,MySql中增加一列_西红柿天尊的博客-CSDN博客_mysql 增加列
后面的not null是限制条件,可加可不加
第5页, 尝试授予用户组“未经授权的用户”更改表的权限
MySQL授予权限(Grant语句) - MySQL教程™ (yiibai.com)
第9页,字符型SQL注入,非常简单的一个构造闭合
第10页,数值型SQL注入
这里让我们取出所有数据,但是给我们的查询语句中只有user_id 能查到之前的数据,我们构造一个恒等式 1 or 1=1,由于1=1恒成立,所以将所有数据取出来了
第11页, enmmm,讲了一大堆,就是要我们把所有数据拿出来,这里还是构造恒等式,但是要用单引号闭合,在 TAN 输入框中输入,1' or '1'='1 即可。
第12页, 觉得工资低了,想改一下,就是改数据,这里只给了一个select 查询语句,我们要自己构造出一个update语句
1'; update employees set salary=10000000 where last_name='Smith';--+
这里完整的语句应该是
SELECT * FROM employees WHERE last_name = '1' AND auth_tan = '1';
update employees set salary=1000000 where last_name='Smith';--+';
上面的查询语句无所谓,因为我们只是来修改数据的,通过 '; 来闭合成一个select 语句,并且可以插入第二个update语句,--+ 是url中的注释符,是为了将后面的 '; 注释掉不让他发挥作用。
第13页, 说好像有个访问日志会记录所有的访问信息,要我们在没有人发现我们的行为之前删掉记录(删库跑路了属于是)
输入SELECT,查一下,
在这里构造闭合发现不行,说明注入点不在这里,我们回到上一关或上上一关,反正是能注入的地方都可以,输入
1'; drop table access_log;--+
回到13页再查一下,发现记录消失了
第3页,要我们查另一张表的数据,
法一:用union select联合查询
mysql多表联合查询 - 简书 (jianshu.com)
这里联合查询要保证字段数一样,并且相应字段的数据类型要一样,我们看到 user_data 字段数为7,所以我们这里可以使用重复查一列来凑7个字段,第一位和最后一位必须为数值型,所以只能为userid,其他位随意
1' union select userid,user_name,password,password,password,cookie,userid
法二:新构造一个SQL语句,我们使用
1' ; select * from user_system_data ;--+'
第5页,要我们以Tom的身份登录,本来想试试弱密码和万能密码的,好像都不行,那我们就找一下注入点吧,登录界面输一下,抓包,用kali自带的sqlmap来判断注入点,
保存到一个txt文件里面,然后用
sqlmap -r 文件路径
还有几个地方都提示不是注入点,去注册页面看看,当我们用Tom这个名字注册的时候发现没有问题,但是当我们用tom这个名字注册他会提醒我们该用户名已存在,说明我们要登录的用户名应该是tom,抓包看看
保存到txt文件中,sqlmap一下,
说明username_reg处位注入点,sqlmap 跑一下,
账号:tom 密码:thisisasecretfortomonly
这里主要讲了如何防御SQL注入
第5页,
Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPW);
PreparedStatement stmt = conn.prepareStatement("SELECT status FROM users WHERE name=? AND mail=?");
stmt.setString(1, "asif001");//这里的第二个参数随便填
stmt.setString(2,"[email protected]");//这里的第二个参数随便填
第6页,
try {
Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPW);
System.out.println(conn);
PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users WHERE name=?");
stmt.setString(1, "asif001");
ResultSet results = stmt.executeQuery();
} catch (Exception e) {
System.out.println("Oops. Something went wrong!");
}
第9页,在之前一题的基础上加了过滤,限制输入中不能出现空格,我们可以通过加注释的方法来达到空格的目的:
Dave'/**/OR/**/'1'='1
第12页,
104.130.219.202
目录遍历
第2页,让我们上传一个文件上去,并且让我们保存到指定目录下,我们先创建一个非空文件,如何点击头像那里进行上传,点击update,他告诉我们目前的保存路径为
我们可以看到两个很重要的信息,第一个是我们的保存路径多了一个自己的用户名,第二个是我们上次的文件名字为Full Name,而且他也告诉我们是Linux系统,所以直接在Full Name处修改为../test 即可,这样就保存到上一级路径中了
第3页, 他告诉我们../ 被删除了,我们该怎么绕过呢?
常见的有 双写绕过,大小写绕过 等
这里通过双写绕过,输入:....//test 即可成功
第4页,这一关还是看怎么绕过,我们先抓包看看,发现他这次的保存文件名就为我们创建目录的名字,那不就好改了吗,直接在文件名前加个 ../
成功
第5页, 路径遍历不仅限于文件上载,在检索文件时,路径遍历可能从系统中检索其他文件。在此分配中,尝试查找名为 path-traversal-secret.jpg 文件
我们抓包,放到重发模块,send一下
我们看到返回的数据中加了一个 ?id=2.jpg 我们在发送包里修改一下
返回的数据中在我们输入的后面加上了一个 .jpg ,所以我们将id值改为 path-traversal-secret
没有,加上 ../ ,
发现不仅400了,还显示我们有非法字符,把 ../ url编码一下:%2e%2e%2f,
找到了,叫我们把我们的用户名进行SHA-512 hash编码作为答案
工具网上都有,我用的是:sha512在线解密 在线加密 (ttmd5.com)
成功
注:本题多有借鉴博主维梓梓,下面是他的博客地址:
维梓梓的博客_CSDN博客-WEB安全,漏洞复现,中间件漏洞复现领域博主
第2页,通过回答两个问题来重置密码,我们抓包看看,根据上面的例子,我们尝试将两个secQuestion0,secQuestion1删除试试,
提交后发现不行,试着将secQuestion0,secQuestion1改为secQuestion2 secQuestion3,或者其他都行,只要前面有secQuestion0,后面数字不为0,1
看看源码:
@RestController
@AssignmentHints({"auth-bypass.hints.verify.1", "auth-bypass.hints.verify.2", "auth-bypass.hints.verify.3", "auth-bypass.hints.verify.4"})
public class VerifyAccount extends AssignmentEndpoint {
@Autowired
private WebSession webSession;
@Autowired
UserSessionData userSessionData;
@PostMapping(path = "/auth-bypass/verify-account", produces = {"application/json"})
@ResponseBody
public AttackResult completed(@RequestParam String userId, @RequestParam String verifyMethod, HttpServletRequest req) throws ServletException, IOException {
AccountVerificationHelper verificationHelper = new AccountVerificationHelper();
Map submittedAnswers = parseSecQuestions(req);
if (verificationHelper.didUserLikelylCheat((HashMap) submittedAnswers)) {
return trackProgress(failed()
.feedback("verify-account.cheated")
.output("Yes, you guessed correctly, but see the feedback message")
.build());
}
// else
if (verificationHelper.verifyAccount(Integer.valueOf(userId), (HashMap) submittedAnswers)) {
userSessionData.setValue("account-verified-id", userId);
return trackProgress(success()
.feedback("verify-account.success")
.build());
} else {
return trackProgress(failed()
.feedback("verify-account.failed")
.build());
}
}
private HashMap parseSecQuestions(HttpServletRequest req) {
Map userAnswers = new HashMap<>();
List paramNames = Collections.list(req.getParameterNames());
for (String paramName : paramNames) {
//String paramName = req.getParameterNames().nextElement();
if (paramName.contains("secQuestion")) {
userAnswers.put(paramName, req.getParameter(paramName));
}
}
return (HashMap) userAnswers;
}
}
大致意思为:如果参数名包含"secQuestion",则将参数名作为userAnswers的key,参数值作为value存入。但是没有判定参数名后面的数字是否原先设置好的数字,所以我们给一个没有出现过得并且能通过验证的key即可
JWT分为三部分,头部(Header),声明(Claims),签名(Signature),三个部分以英文句号.隔开。JWT的内容以Base64URL进行了编码。
1、头部(Header)
以第2页的JWT为例,其中的头部解码后是这样的
{
“alg”:“HS256”,
“typ”:“JWT”
}
alg:是说明这个JWT的签名使用的算法的参数,常见值用HS256(默认),HS512等,也可以为None。HS256表示HMAC SHA256。
typ:说明这个token的类型为JWT
2、声明(Claims)
上面的例子的声明解码后是:
{
"exp": 1416471934, "user_name": "user",
"scope": [ "read", "write" ],
"authorities": [ "ROLE_ADMIN", "ROLE_USER" ],
"jti": "9bc92a44-0b1a-4c5e-be70-da52075b9a84",
"client_id": "my-client-with-secret"
}
其中有些字段是JWT的固定参数,有特定的含义;而另一些是服务器自定义的参数,用来表示通话信息等。
JWT固定参数有:
iss:发行人
exp:到期时间
sub:主题
aud:用户
nbf:在此之前不可用
iat:发布时间
jti:JWT ID用于标识该JWT
这段JSON同样以Base64 URL 编码后作为JWT的一部分。
3、签名
服务器有一个不会发送给客户端的密码(secret),用头部中指定的算法对头部和声明的内容用此密码进行加密,生成的字符串就是JWT的签名。
下面是一个用HS256生成JWT的代码例子
HMACSHA256(base64UrlEncode(header) + “.” + base64UrlEncode(payload),secret)
l 流程:
1、用户端登录,用户名和密码在请求中被发往服务器
2、(确认登录信息正确后)服务器生成JSON头部和声明,将登录信息写入JSON的声明中(通常不应写入密码,因为JWT是不加密的),并用secret用指定算法进行加密,生成该用户的JWT。此时,服务器并没有保存登录状态信息。
3、服务器将JWT(通过响应)返回给客户端
4、用户下次会话时,客户端会自动将JWT写在HTTP请求头部的Authorization字段中
5、服务器对JWT进行验证,若验证成功,则确认此用户的登录状态
6、服务器返回响应
l Base64 URL编码
在HTTP传输过程中,Base64编码中的"=","+","/"等特殊符号通过URL解码通常容易产生歧义,因此产生了与URL兼容的Base64 URL编码
在Base64 URL编码中,"+“会变成”-","/“会变成”_","="会被去掉,以此达到url safe的目的。
第4页,
让我们通过改令牌越权成为管理员,
我们先切换用户,点击那个小垃圾桶,reset votes
抓包,
发现有一个令牌,我们用下面这个网站看一下 JSON Web Tokens - jwt.io
可以看到右边为解码后的内容,然后我们要以admin来登录才可以,但是他没有给我们密钥,根据我们前面给的知识,alg的值可以为空,这样就不需要密钥了,然后将头部进行base64编码,
然后就是将声明中的admin值改为true,再次进行base64编码,将这两次的编码合在一起,并且在两句之间加上一个” . “,语句的最后也加上一个 "." 。
send一下,
第5页,他给了我们一个令牌,让我们去找密钥,然后将username改为webgoat后加密再提交,但我们不知道密钥为什么,所以需要爆破
https://github.com/first20hours/google-10000-english
将这个文件复制到kali中作为我们的爆破字典,并且将他给我们的token保存到一个文件中,然后再kali中输入
hashcat -m 16500 token.txt -a 3 -w 3 20k.txt
-m 16500 ,这里的16500对应的就是jwt的token爆破;
-a 3 , 代表蛮力破解
-w 3 , 可以理解为高速破解,就是会让桌面进程无响应的那种高速
token.txt , 是我把题目要求破解的token保存到的文件
20k.txt , 就是google提供的10000个单词/词组/短语
爆出来了,是shipping
然后再用我们上一个用的那个网站,JSON WebyouTokens - jwt.io
先将他给的token放进去,刚开始是这样的
直接改,然后左边会自动生成,提交
但是你有可能发现提交失败了,那是因为这个token他有时间限制的,
这个时间只有1分钟,对我们来说应该是不够的,所以我们修改一下exp(截止时间),这里你可以修改为一个比较大的数, 或者你也可以在Unix时间戳(Unix timestamp)转换工具 - 在线工具 (usey.cn)
看一下你当前的时间戳,然后改一下exp使得你当前的时间戳在截止时间前就可以了。
第7页,要我们让Tom为我们买东西,并且他还给了一个有缺陷的登录日志,我们点进去在里面找到token复制,然后抓包试试
发现不行,我们将这个token解密一下,
可以看到应该是时间过期了,改一下,并且这里的alg是HS512,我们可以直接将他改为none来避免爆破密钥
然后base64编码,. 连接,最后放到 Authorization(授权) 值里面就可以了
第8页,Jerry想要删除Tom的Twitter账号,
点击删除Tom,抓包
像前面几关一样,我们改一些值,然后base64之后提交发现不行,查了一下,需要配合SQL注入漏洞来进行,我们看一下源码
文件位置大概位于 \WebGoat-8.0.0.M26 (1).zip\WebGoat-8.0.0.M26\webgoat-lessons\jwt\src\main\java\org\owasp\webgoat\jwt\JWTFinal
这里有一个SQL语句,下面的图片来源于
05.WebGoat之身份验证缺陷 - 简书 (jianshu.com)
盗一下大佬的图
疑问:
a. 如何影响提交参数影响签名查询结果为自己定义的
是否可以通过;指定查询链,改写kid查询的结果控制输出(签名)
分别将kid修改为:
webgoat_key';select 'test
(失败,hsqldb语法不支持改语法,但支持SELECT 1 FROM
INFORMATION_SCHEMA.SYSTEM_USERS)
webgoat_key';create table tk(key varchar(32));insert into tk values('test');select key from tk where key='test
(失败,未知原因)
结论:尝试失败
通过luyten反编译jar包或查看WebGoat源码得知结果:
根据代码,可借助jwt_keys表查询将secret自定义,且secret必须为base64编码
后面应该会更吧