基于CTF探讨Web漏洞的利用与防范_漏洞利用场景ctf-程序员宅基地

技术标签: CTF  web安全  安全  web  前端  网络安全  

写在前面

Copyright [2023] [Myon⁶]. All rights reserved.

基于自己之前在CTF中Web方向的学习,总结出与Web相关的漏洞利用方法,主要包括:密码爆破、文件上传、SQL注入、PHP伪协议、反序列化漏洞、命令执行漏洞、文件包含漏洞、Vim文件泄露、HTTP协议、Cookie伪造、Git源码泄露,并就此总结出相关的防御应对措施。

原本是在W1R3S上进行了包括:信息收集、FTP渗透、Web渗透、John爆破、ssh远程登录、sudo提权等相关的渗透测试,但是考虑到内容太多,这里我主要总结从web渗透开始以及后续的测试,实质就是一个文件包含漏洞的利用。

本人程序员宅基地地址:http://myon6.blog.csdn.net

期待大家的关注与支持!

目录

一、基本原理概述

1、Web漏洞利用

(1)SQL注入

(2)Git泄露与命令执行漏洞

(3)文件上传

(4)PHP伪协议与文件包含漏洞

(5)密码爆破

(6)Cookie伪造

(7)反序列化漏洞

(8)Vim文件泄露

(9)HTTP协议

2、基于W1R3S的渗透测试

(1)信息收集

(2)FTP渗透

(3)Web渗透

(4)John爆破

(5)ssh远程登录

(6)sudo提权

二、详细过程

1、Web漏洞利用

(1)SQL注入

(2)Git泄露与命令执行漏洞

(3)文件上传

(4)PHP伪协议与文件包含漏洞

(5)密码爆破

(6)Cookie伪造

(7)反序列化漏洞

(8)Vim文件泄露

(9)HTTP协议

2、基于W1R3S的Web渗透测试

三、结果分析

1、SQL注入

2、Git泄露与命令执行漏洞

3、文件上传

4、PHP伪协议与文件包含漏洞

5、密码爆破

6、Cookie伪造

7、反序列化漏洞

8、Vim文件泄露

9、HTTP协议

10、基于W1R3S的Web渗透测试

四、总结体会与防御措施


背景介绍

随着Web2.0、社交网络、微博等等一系列新型的互联网产品的诞生,基于Web环境的互联网应用越来越广泛,企业信息化的过程中各种应用都架设在Web平台上,Web业务的迅速发展也引起黑客们的强烈关注,接踵而至的就是Web安全威胁的凸显,黑客利用网站操作系统的漏洞和Web服务程序的SQL注入漏洞等得到Web服务器的控制权限,轻则篡改网页内容,重则窃取重要内部数据,更为严重的则是在网页中植入恶意代码,使得网站访问者受到侵害。这也使得越来越多的用户关注应用层的安全问题,对Web应用安全的关注度也逐渐升温。

一、基本原理概述

1、Web漏洞利用

(1)SQL注入

SQL注入是一种非常常见的数据库攻击手段,SQL注入漏洞也是网络世界中最普遍的漏洞之一,我们可以通过在表单中填写包含SQL关键字的数据来使数据库执行非常规代码。

(2)Git泄露与命令执行漏洞

开发人员使用 git 进行版本控制,如果配置不当,会将 .git 文件夹直接部署到线上环境,引起git 泄露漏洞,我们可以通过 .git文件恢复网站源码,来获取一些敏感信息。

(3)文件上传

由于web的过滤不够严格,导致在上传的位置上,用户可以上传一些带有脚本的文件,web端对脚本文件进行php解析,可以任意执行脚本文件。

(4)PHP伪协议与文件包含漏洞

PHP伪协议是PHP支持的协议与封装协议,我们可以使用它实现文件读取,文件包含漏洞也是一种注入型漏洞,其本质就是输入一段用户能够控制的脚本或者代码,并让服务端执行。

(5)密码爆破

密码爆破又叫暴力猜解,简单来说就是将密码逐个尝试, 直到找出真正的密码为止, 本质上是利用了穷举法。

(6)Cookie伪造

一个脆弱的站点或者web应用可能把存储敏感状态信息直接在cookies,在浏览器手动改cookie的名称和值再刷新页面可能足以获得提升的权限。

(7)反序列化漏洞

PHP反序列化漏洞也叫PHP对象注入,形成的原因是程序未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程,从而导致代码执行、文件操作、执行数据库操作等参数不可控。

(8)Vim文件泄露

当开发人员在线上环境中使用vim编辑器,在使用过程中会留下vim编辑器缓存,当vim异常退出时,缓存会一直留在服务器上,引起网站源码泄露。

(9)HTTP协议

HTTP协议(超文本传输协议HyperText Transfer Protocol),它是基于TCP协议的应用层传输协议,简单来说就是客户端和服务端进行数据传输的一种规则。

2、基于W1R3S的渗透测试

w1r3s是一台存在着很多漏洞的靶机,可为我们提供相关的漏洞进行渗透测试。

(1)信息收集

信息收集就像一场战争中的“深入敌后”的一项“情报收集”任务。在开始渗透测试工作之前,我们通过要对目标使用各种工具进行信息收集工作,找出目标的漏洞和弱点,然后利用这些漏洞和弱点进行攻击,使得渗透任务得以顺利地完成。

(2)FTP渗透

FTP全名File Transfer Protocol,一种可以通过网络传输文件的协议,FTP协议是不安全的,不支持加密传输,它使用客户端到服务器这种类型,客户端启动后尝试对服务器发起连接请求,然后提供登录凭证,如果正确则开启会话。

(3)Web渗透

通过模拟恶意黑客的攻击方法,来评估Web站点安全的一种评估方法。常见的Web漏洞通常包括:输入输出验证不充分、设计缺陷、环境缺陷、sql注入、xss、csrf、目录穿越、文件上传、代码注入、命令注入、信息泄漏、暴力破解、越权漏洞、非授权对象引用、业务逻辑缺陷、框架漏洞、基础环境漏洞。

(4)John爆破

破解密码方式简单而粗暴,理论上只要时间上面允许,可以破译绝大多数用户密码,支持多种不同类型的系统架构,主要目的是破解不够牢固的Unix/Linux系统密码。

(5)ssh远程登录

SSH(Secure Shell )是一种安全通道协议,主要用来实现字符界面的远程的登录、远程复制等功能,SSH协议对通信双方的数据传输进行了加密处理,其中包括用户登录时输入的用户口令,因此SSH协议具有很好的安全性。

(6)sudo提权

是一种 Linux 命令,用于提升用户权限以执行特权操作,在执行sudo命令时,将普通用户的权限提升为root用户的权限,以便执行需要root权限的操作。

二、详细过程

1、Web漏洞利用

(1)SQL注入

这里我主要以sqlmap来演示,当然手工注入也是可以的。

(1)尝试列出所以数据库:

sqlmap -u "http://61.147.171.105:54285/?id=1" --dbs

(2)可以看到有一个名为cyber的数据库,我们指定列出它的表

sqlmap -u "http://61.147.171.105:54285/?id=1" -D cyber –tables

(3)这个数据库里只有一个表,且和数据库同名,我们继续列出指定表的字段

sqlmap -u "http://61.147.171.105:54285/?id=1" -D cyber -T cyber --columns

(4)尝试获取指定字段中的数据

sqlmap -u "http://61.147.171.105:54285/?id=1" -D cyber -T cyber -C pw --dump

(2)Git泄露与命令执行漏洞

(1)在About里发现网站是使用Git、PHP、Bootstrap搭建的

使用dirsearch扫一下

(2)从结果可以看出确实存在.git 目录,我们这里使用Githack来下载并恢复.git文件,切换到Githack所在位置,执行命令:python Githack.py url

(3)进入下载文件所在目录查看

打开flag.php,但是并没有看到什么

在index.php里发现有用代码

(4)代码审计

使用get请求方式给page传参,如果没传,默认page=home 

(这也是为什么我们打开题目链接进去是在home页面)

$file会接收传入的$page并且在其前面拼接templates/,在其后面拼接.php

strpos() 函数会在'$file'这个字符串中进行查找,是否存在'..'

当字符串里有'..',则会返回一个数(即'..'第一次出现的位置),结果为true

与右边的false并不恒等,此时就会执行or右边的die()函数,输出 Detected hacking attempt!

file_exists() 函数还会检查我们传入的page拼接后是否存在

(5)构造payload

这里实际上是一个命令执行漏洞

我们可以直接在第一个assert()函数处就调用cat命令来获取flag

首先传入的page肯定不能有 '..',使strpos() 函数返回false,false和右边的false恒等

构造payload:?page=123') or system("cat templates/flag.php");//

在最后添加注释//,确保后面的代码不会执行

(3)文件上传

(1)在源码中找到默认登录账户和密码

(2)登陆成功后上传一句话木马

(3)这里没有任何的绕过,直接上蚁剑尝试连接

(4)PHP伪协议与文件包含漏洞

(1)打开题目链接,代码审计

file2被放入了file_get_contents() 函数,且要求返回值为 hello ctf

file1是要包含的文件,且flag应该是在文件flag.php里面

我们要想办法来读取这个文件,使用php://filter伪协议来读取源代码

即 file1=php://filter/read=convert.base64-encode/resource=flag.php

这里出现了file_get_contents()函数,想到用php://input来绕过

(2)构造payload

/?file1=php://filter/read=convert.base64-encode/resource=flag.php&file2=php://input,且post传入 hello ctf

(3)得到一串base64编码

PD9waHAKZWNobyAiV1JPTkcgV0FZISI7Ci8vICRmbGFnID0gY3liZXJwZWFjZXtjMjNkY2VlOWYxZTc0NTRlNzVlMTA5OGJlMmZhM2IzOH0=,解码即可得到PHP源码。

(5)密码爆破

(1)根据题目描述我们先试用御剑扫一下,发现存在shell后门,

(2)访问shell.ph,需要连接密码

(3)这里直接使用bp来爆破密码

抓包后发到Intruder 模块,并设置爆破的位置和用来爆破的字典

(4)开始攻击

爆破过程中,我们按长度排序,长度不一样的就是密码

至此,我们爆破出了密码是 hack

(6)Cookie伪造

题目要求只有管理员才能拿到flag

(1)在cookie里找到了一些东西

(2)通过查看发现web构架发现为flask,想到session伪造

(3)将cookie值进行base64解码

输出是json格式存储,还有一堆乱码,应该就是数据签名。

(4)使用Python脚本进行session伪造

根据前面base64解码得到session(json)格式,我们将name伪造为admin,并对session数据进行加密。

(5)将伪造的cookie传给session即可

(7)反序列化漏洞

(1)代码审计

这里出现了一个__wakeup()函数,在进行PHP反序列化时,会先调用这个函数,但是如果序列化字符串中表示对象属性个数的值大于真实的属性个数时就会跳过__wakeup()的执行。

(2)脚本编写

<?php

class xctf{

public $flag = '111';

public function __wakeup(){

exit('bad requests');

}

}

$Myon = new xctf();

$Myon = serialize($Myon);

echo $Myon;

?>

(3)构造payload

上面输出的是O:4:"xctf":1:{s:4:"flag";s:3:"111";}

可以看到__wakeup()函数起作用了,我们需要将xctf的参值改为2(任何大于1的数),由于与反序列化规则不符,就会反序列化失败,从而绕过__wakeup()函数。

(8)Vim文件泄露

(1)访问.index.php.swp将文件下载下来,发到centos里

(2)使用vim -r index.php.swp恢复文件

(3)代码审计

给password传入"Give_Me_Your_Flag"且要先经过base64编码

就会输出Oh You got my password!并且调用system函数执行传入的cmd命令

(4)将字符串base64编码

(5) 构造payload

postpassword=R2l2ZV9NZV9Zb3VyX0ZsYWc=&&cmd=cat /flag

(9)HTTP协议

使用bp抓包改包重发

(1)请求头写 x-forwarded-for: 127.0.0.1

换一种 client-ip: 127.0.0.1

(2)请求头写 referer: pornhub.com

(3)请求头写 user-agent: Chrome

(4)请求头写 via: Clash.win

拿到一个路径

2、基于W1R3S的Web渗透测试

(1)直接访问目标ip地址

查看靶机80端口的web服务,发现是个apache的主页

(2)使用dirsearch对目标主机80端口的web服务进行目录爆破

dirsearch -u 192.168.88.131

爆出两个可疑目录/administrator和/wordpress

(wordpress这个框架存在很多漏洞)

(3)使用whatweb命令查询,发现该网站的cms为Cuppa

(4)使用searchsploit命令查询Cuppa cms是否存在漏洞

searchsploit cuppa cms

(5)发现存在一处漏洞, 漏洞详情保存在25971.txt中, 将它导出来

searchsploit cuppa cms -m 25971.txt

(6)查看漏洞详情得知, 该cms可通过文件包含漏洞读取任意文件

(7)使用curl命令提交Post请求:

curl -X POST -d urlConfig=../../../../../../../../../etc/passwd http://192.168.88.131/administrator/alerts/alertConfigField.php

用同样的方法尝试读取shadow文件,该文件是用来存放用户名密码的

curl -X POST -d urlConfig=../../../../../../../../../etc/shadow http://192.168.88.131/administrator/alerts/alertConfigField.php

发现两处很明显的用户信息

分别对应着www-data用户:加密密码,w1r3s用户:加密密码

(8)使用john爆破

破解成功,得到:

用户 www-data  密码 www-data

用户 w1r3s  密码 computer

(9)ssh远程登录

远程登录成功

whoami  查看一下当前用户是谁

uname -a   查看系统状态

sudo -l   查看当前用户权限

可以看到当前用户具有所有权限

(10)sudo提权

因为w1r3s这个用户具有全权限,这里可以直接提权至root用户

sudo su 

提权成功

切换到root根目录,直接找到flag

三、结果分析

1、SQL注入

拿到flag cyberpeace{818e277716501adc71a98b501c4d7a99}

总结一些sqlmap常用的参数:

-D 选择使用哪个数据库    -T 选择使用哪个表    -C 选择使用哪个列

--tables 列出当前的表  --columns 列出当前的列 --dump 获取字段中的数据

2、Git泄露与命令执行漏洞

传入page后查看源码,找到flag

cyberpeace{1f150d17210f2080d18800a5a99e9f9b}

3、文件上传

连接成功,并且在根目录下面找到

flag=NSSCTF{96cd0bd4-f5e6-4fbf-8b09-c38f244d4aa6}

4、PHP伪协议与文件包含漏洞

Base64解码后得到PHP源码

拿到 $flag = cyberpeace{c23dcee9f1e7454e75e1098be2fa3b38}

存在文件包含时使用PHP伪协议,可能遇到的文件包含函数:

1、include 2、require 3、include_once 4、require_once 5、highlight_file

6、show_source 7、flie 8、readfile 9、file_get_contents

10、file_put_contents 11、fopen

5、密码爆破

将密码修改成正确的密码后放包

查看页面响应,已经显示出flag

flag{0bd17d36fcc7c9771191be6e558833ec}

6、Cookie伪造

将伪造的cookie传给session后,便可使用伪造的admin身份拿到flag

NSSCTF{df845e3b-f834-405e-9a49-3f847c5341fe}

关于session的作用:

由于http协议是一个无状态的协议,也就是说同一个用户第一次请求和第二次请求是完全没有关系的,但是现在的网站基本上有登录使用的功能,这就要求必须实现有状态,而session机制实现的就是这个功能。用户第一次请求后,将产生的状态信息保存在session中,这时可以把session当做一个容器,它保存了正在使用的所有用户的状态信息;这段状态信息分配了一个唯一的标识符用来标识用户的身份,将其保存在响应对象的cookie中;当第二次请求时,解析cookie中的标识符,拿到标识符后去session找到对应的用户的信息。

7、反序列化漏洞

我们正确的payload为:?code=O:4:"xctf":2:{s:4:"flag";s:3:"111";}

传入后即可拿到flag

在php中与序列化相关的函数为:

serialize()  序列化  // 将一个类的实例(对象)序列化为字符串

unserialize() 反序列化  // 将已序列化的变量(字符串)变回原来 PHP的值

8、Vim文件泄露

Post传参后拿到flag

NSSCTF{b8776bdb-b398-4544-b006-72ee55c5a531}

使用 vim -r 来查看当前目录下的所有swp文件;也可以使用 vim -r filename 来恢复文件,这样上次意外退出没有保存的修改就会覆盖文件。

9、HTTP协议

访问拿到的路径

在源码里找到另一个路径,继续访问,拿到flag

NSSCTF{d295698b-50ae-47ed-8393-2463797931d3}

10、基于W1R3S的Web渗透测试

前期我们是需要先进行信息收集,确定靶机IP,以及对靶机进行端口扫描,确定开放的端口和服务,探测出可能存在的漏洞,这对我们进行后续的渗透具有极其重要的作用。

从最初不知道登录密码

到最后彻底拿下整台靶机

四、总结体会与防御措施

从上面的Web漏洞利用中我们可以看到:Web安全漏洞的危害之大,而且无处不在,只要稍不注意就有可能导致个人信息的泄露。在Internet大众化及Web技术飞速演变的今天,在线安全所面临的挑战日益严峻,伴随着在线信息和服务的可用性的提升,以及基于Web的攻击和破坏的增长,安全风险达到了前所未有的高度。上面的CTF赛题大多其取材于真实环境渗透,只说一句话:开发和安全缺一不可!

1、针对注入漏洞,我们通常可以通过适当、及时地检查与清理用户的输入,来防范此类威胁,严格限制web应用的数据库的操作权限,给用户提供仅能满足需求的最低权限,从而最大限度的减少注入攻击对数据库的危害。

2、针对身份验证相关的漏洞,我们可以通过实施健全的会话管理控制、多因素身份验证、限制和监视失败的登录尝试,避免使用默认密码,进行弱密码检查,使用服务端,安全,内置的会话管理,确保对于每次登录生成随机会话ID,会话ID不应该在URL中,且应该及时销毁。

3、针对敏感数据泄漏,我们可以对系统处理、存储或传输的数据分类,并根据分类进行访问控制,对于没必要存放的、重要的敏感数据,应当尽快清除,或者通过PCI DSS标记或拦截。未存储的数据不能被窃取。

4、针对受损的访问控制带来的未经授权的信息泄露、数据被直接修改或破坏,我们可以通对前后端同时对用户输入信息进行校验,双重验证机制,执行关键操作前必须验证用户身份,验证用户是否具备操作数据的权限。

5、针对不安全的反序列化漏洞,我们需要对任何序列化对象进行完整性检测,比如数字签名以防止数据篡改或恶意对象,限制或监管入的和出的来自反序列化的容器或服务器的网络链接。

6、针对任意文件上传和读取下载,我们通过设置白名单,即只能下载/访问某个目录下的文件,权限给到最低,正则严格判断用户输入参数的格式,php.ini配置open_basedir限定文件访问范围。

注:Copyright [2023] [Myon⁶]. All rights reserved.

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Myon5/article/details/134728890

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法