将文件拷贝到kali虚拟机的桌面,在终端中进入桌面,输入下面命令,安装靶场,端口指定为8888:
sudo java -jar webgoat-server-8.0.0.M17.jar --server.port=8888
如图,启动成功:
打开bp的内置浏览器,输入127.0.0.1:8888/WebGoat打开靶场网站:
注册一个账号:
注册成功后点击Broken Authentication中的JWT token,来到第一关:
点击第四关,这一关是一个投票界面,选择Tom用户,然后点击删除按钮,出现一段提示只有管理员可以重置该投票:
点击删除投票,并用bp抓到post请求包,发送到repeater模块,在cookie字段找到JWT:
将这段JWT放到JWT解码网站中解码,发现payload载荷信息中用户是Tom,admin字段值是false:
将这段信息复制到base64加密网站中,将false改为true,并复制加密后除=外的base64密文,并替换原来的payload字段:
和修改payload方法一样,修改JWT头部的算法类型为none,让它不要加密,替换原来的payload字段:
将修改后的header和payload字段替换数据包中的cookie字段,注意加上点,这样后端才能识别,点击send发送,提示重置投票成功:
回到网页刷新,发现票数均变为1:
这关给出了JWT,要求修改exp并爆破密钥
复制这段JWT,vim在桌面新建一个JWT.txt文件,放入复制的密钥:
用下面命令爆破JWT的密钥,字典用1.txt:
hashcat -m 16500 JWT.txt -a 3 -w 3 1.txt
-a 3 代表蛮力破解
-w 3 可以理解为高速破解,就是会让桌面进程无响应的那种高速
JWT.txt 是我把题目要求破解的 token 保存到的文件
按照题目的要求,修改username为WebGoat,并修改时间戳:
输入爆破出的密钥:
将修改后的JWT提交后即可通关:
来到第7关,这一关要求冒充Tom用户为另一个无JWT的非法用户付钱
点击右下角的购买,提示没有JWT:
用bp抓包,发送到repeater模块,发现该数据包有一个单独存放JWT的Authorization字段:
右键here,在新窗口打开,可以查看日志:
复制一个用户的token:
将该token在数据包中替换之前抓到数据包的Authorization字段,发送后依然报错,提示我们在日志中找到的JWT已经过期:
复制Tom用户的exp字段,这里的一串数字就是payload的过期时间戳,复制到网站解码,显示过期时间是2018-5-13:
用一个新的时间戳:
替换原来的exp字段,加密后替换原来的payload,由于没有密钥,JWT头部也需要替换,修改后发送,发现提示成功:
如下图,Java文件经过编译变为class文件(字节码文件),然后由Java虚拟机即JVM运行class文件。Linux和Windows都是不能直接识别class文件的,所以需要JVM来运行。
正是由于JVM的存在,所以Java文件可以在不同平台上运行。
因为Java虚拟机JVM只认识Java文件中的类名,如果类名和文件名不一致,JVM就无法识别,如下面代码:
public class Hello{
public static void main(String[] args){
System.out.println("123456");
}
}
执行它的hello.java文件:
main()函数是Java应用程序的入口函数。main函数是Java中格式固定的、能被JVM识别的函数,只有main函数中的代码才能被执行,main()函数的声明为:public static void main(String args[])。必须这么定义,这是Java的规范。如果没有main函数,JVM就不知道如何执行。 如下面的Java代码:
public class Hello{
public static void main(String[] args){
System.out.println("123456");
}
}
它就相当于php中的这段代码:
.class
文件可以被视为已编译的 .java
文件。它是在 JVM(Java 虚拟机)上运行的文件。
.java
文件只有一个,.class
文件不一定只有一个,它的数量取决于.java
文件中类的个数,有几个类,编译后就有几个.class
文件。
如下图的java代码,void是函数的返回值类型,表示返回值为空,在不需要返回值时使用void。
public class Person{
public int age;
public String name;
public void talk(){
System.out.println("Person 说话了");
}
}
因为不同类型的变量在内存空间中的存储格式是不同的,不同的存储格式有不同的读取方法,只有声明变量的类型,java程序才知道如何读取存储的数据,如下图是小数在内存空间存储,0.25在内存中的存储也是0和1,只有声明合适的类型才能正确读取。
因为java是一种面向对象的编程语言。而面向对象是为了解决系统的可维护性,可扩展性,可重用性。
面向对象的三大特征是封装、继承和多态,面向对象能有效提高编程的效率。
通过封装技术,消息机制可以像搭积木的一样快速开发出一个全新的系统。
通过使用继承我们能够非常方便地复用以前的代码,能够大大的提高开发的效率。
Java是一个典型的面向对象的编程语言,它属于解释型的语言,由于它只在运行时才逐句进行翻译,所以它引用的变量的类型和该变量调出的类的方法在编程时并不能确定,只能在运行时才能确定,类似于**“薛定谔的猫”,不同的是,这个形态时可以人为引导它“塌陷”**到某一具体的类,这样一来,程序员可以在不修改源代码的情况下,就可以让引用的变量绑定不同的类,从而调用不同的方法,让程序可以选择多个状态,这就是面向对象语言的多态性。
避免重复造轮子。子类继承父类的函数,避免了重复写代码。通过使用继承我们能够非常方便地复用以前的代码,能够大大的提高开发的效率。
如果子类不对分类的方法进行重写,那么子类的方法会完全继承父类,不能达成程序员想要实现的功能,如下面的父类:
public class Person{
public int age;
public String name;
public void talk(){
System.out.println("Person 说话了");
}
}
继承但未重写的子类:
public class Student extends Person{
public void talk(){
}
}
子类调用父类的方法:
public class Test
public static void main(String[] args){
Student st1 = new Student ();
stl.talk();
}
}
输出的结果:
这样的结果明显不是我们想要的,重写子类:
public class Student extends Person{
public void talk(){
System.out.println("Student 说话了");
}
}
再次输出,结果为: