我们从一个简单的爬虫开始,这个爬虫很简单,访问指定的 URL,并且获取内容并计算长度,这里我们给定 5 个 URL。第一版的代码十分简单,顺序获取每个 URL 的内容,当第一个请求完成、计算完长度后,再开始第二个请求。
我们多运行几次看看结果。
大约需要花费 14-16 秒不等,这段代码并没有什么好看的,我们把关注点放在后面的代码上。现在我们使用多线程来改写这端代码。
再来看一下结果,很明显,我们的耗时已经降低到 10s 左右了:
从这两段代码中,已经可以看出并发对于处理任务的好处了,但是使用原生的
执行一下,会发现耗时与上一个版本一样,稳定在 10s 左右。
可以看到我们调用了
渗透爬虫软件 资源采集 劫持域名 提取抓料子 六合·色站·彩票·博彩·金融 接渗透拿站,各大网站数据-拖库-提权联系 域名劫持 DNS 入侵网站 联系:@hacker_HouZiM
我们多运行几次看看结果。
大约需要花费 14-16 秒不等,这段代码并没有什么好看的,我们把关注点放在后面的代码上。现在我们使用多线程来改写这端代码。
再来看一下结果,很明显,我们的耗时已经降低到 10s 左右了:
从这两段代码中,已经可以看出并发对于处理任务的好处了,但是使用原生的
threading模块还是略显麻烦,Python 已经给我们内置了一个处理并发任务的库concurrent,我们借用这个库修改一下我们的代码,之所以修改成这个库的原因还有一个,那就是引出我们后面会谈到的Future。执行一下,会发现耗时与上一个版本一样,稳定在 10s 左右。
可以看到我们调用了
concurrent库中的futures,那么到底什么是futures?简单的讲,这个对象代表一种异步的操作,可以表示为一个需要延时进行的操作,当然这个操作的状态可能已经完成,也有可能尚未完成,如果你写 JS 的话,可以理解为是类似Promise的对象。在 Python 中,标准库中其实有两个Future类,一个是concurrent.futures.Future,另外一个是asyncio.Future,这两个类很类似,不完全相同,这些实现差异以及 API 的差异我们先按下暂且不谈,有兴趣的同学可以参考下相关的文档。Future是我们后面讨论的asyncio异步编程的基础,因此这里多说两句。Future代表的是一个未来的某一个时刻一定会执行的操作(可能已经执行完成了,但是无论如何他一定有一个确切的运行时间),一般情况下用户无需手动从零开始创建一个 Future,而是应当借助框架中的 API 生成。比如调用concurrent.futures.Executor.submit()时,框架会为 "异步操作" 进行一个排期,来决定何时运行这个操作,这时候就会生成一个Future对象。渗透爬虫软件 资源采集 劫持域名 提取抓料子 六合·色站·彩票·博彩·金融 接渗透拿站,各大网站数据-拖库-提权联系 域名劫持 DNS 入侵网站 联系:@hacker_HouZiM
拿到
从头部加密信息来看,是用的 PHPJiaMi,看到代码里面有
直接解该文件没成功,说明存在调用才会解密的情况,从
把原来的
然后把
把
渗透爬虫软件 资源采集 劫持域名 提取抓料子 六合·色站·彩票·博彩·金融 接渗透拿站,各大网站数据-拖库-提权联系 域名劫持 DNS 入侵网站 联系:@hacker_HouZiM
UploadFile.class.php,部分代码如下:从头部加密信息来看,是用的 PHPJiaMi,看到代码里面有
eval,那这种方式解密成功率就很大了。直接解该文件没成功,说明存在调用才会解密的情况,从
index.php 里发现了调用的代码。 if($_FILES) {
include 'UploadFile.class.php';
$dist = 'upload';
$upload = new UploadFile($dist, 'upfile');
$data = $upload->upload();
}
?>把原来的
index.php 拿过来,我们需要在上面2中的代码前构造表单里的变量,让它能成功执行,所以我们最终的 index.php 是这个样子<?php
$_FILES["upfile"] = array(
"name" => "1303.jpg",
"type" => "image/jpeg",
"tmp_name" => "/tmp/php/phpSDsuf7",
"error" => 0,
"size" => 1024
);
// 上面的代码是加的
if($_FILES) {
include 'UploadFile.class.php';
$dist = 'upload';
$upload = new UploadFile($dist, 'upfile');
$data = $upload->upload();
}
?><!DOCTYPE html>
<html>
....后面省略
然后把
index.php 和 UploadFile.class.php 打个 zip 包, 注意 index 所在的目录不要打包进去$ zip -r mytest.zip index.php UploadFile.class.php
把
mytest.zip 上传后,如果出现解密失败,点后面的重试,就能看到结果了。渗透爬虫软件 资源采集 劫持域名 提取抓料子 六合·色站·彩票·博彩·金融 接渗透拿站,各大网站数据-拖库-提权联系 域名劫持 DNS 入侵网站 联系:@hacker_HouZiM
程序通过判断文件名来对请求进行不同的处理。跟进 handlePhpCgi 后可以看到对请求参数、请求头进行解析后将执行权交给 php,解析过程如下:
对参数进行解析后,将其储存以键值对的形式(_TYPE_KEY=VALUE,TYPE 为 GET、POST、SERVER),并以 \n 分隔储存到一字符串中,调试如下:
然后进行认证检查,将检查的结果赋值给 AUTHORIZED_GROUP 并保存到字符串中作为全局变量传递给 php:
在整个解析流程中并没有对参数中的 \n 进行过滤,所以如果通过注入 \n 进而注入 AUTHORIZED_GROUP 就可以绕过认证检查,未经授权执行 php 脚本。
在认证通过后程序获取 $_POST["SERVICES"] 参数,将其拼接到字符串中进行包含。/htdocs/webinc/getcfg/ 目录(也可以通过 ../ 跳转目录)下为路由的配置文件,比如 DEVICE.ACCOUNT.xml.php 中保存着路由的管理密码:
渗透爬虫软件 资源采集 劫持域名 提取抓料子 六合·色站·彩票·博彩·金融 接渗透拿站,各大网站数据-拖库-提权联系 域名劫持 DNS 入侵网站 联系:@hacker_HouZiM
对参数进行解析后,将其储存以键值对的形式(_TYPE_KEY=VALUE,TYPE 为 GET、POST、SERVER),并以 \n 分隔储存到一字符串中,调试如下:
然后进行认证检查,将检查的结果赋值给 AUTHORIZED_GROUP 并保存到字符串中作为全局变量传递给 php:
在整个解析流程中并没有对参数中的 \n 进行过滤,所以如果通过注入 \n 进而注入 AUTHORIZED_GROUP 就可以绕过认证检查,未经授权执行 php 脚本。
在认证通过后程序获取 $_POST["SERVICES"] 参数,将其拼接到字符串中进行包含。/htdocs/webinc/getcfg/ 目录(也可以通过 ../ 跳转目录)下为路由的配置文件,比如 DEVICE.ACCOUNT.xml.php 中保存着路由的管理密码:
渗透爬虫软件 资源采集 劫持域名 提取抓料子 六合·色站·彩票·博彩·金融 接渗透拿站,各大网站数据-拖库-提权联系 域名劫持 DNS 入侵网站 联系:@hacker_HouZiM
当应用程序尝试加载已注册的类scrobj.dll时,该类会被加载到内存中。COM 运行时会请求所需类的新对象,这会导致 WSC 运行时返回注册表查找实现脚本文件的 URL。然后,WSC 运行时加载该脚本文件,并在进程内执行其中包含的嵌入式脚本。关键在于,只要 scrobj.dll(以及任何关联的脚本语言库,例如JScript.dll )在 VBOX 看来是有效的已签名 DLL,那么脚本代码就会运行,因为它永远不会被加固代码检查。这将导致任意代码在加固进程内运行。首先,让我们检查一下 scrobj.dll 是否可能被 VBOX 允许加载。以下屏幕截图显示该 DLL 既由 Microsoft 签名,也属于TrustedInstaller所有。
那么,一个有效的 Scriptlet 文件是什么样的呢?它是一个简单的 XML 文件,我不会详细解释每个 XML 元素的含义,只会指出其中的脚本块,它会执行任意的 JScript 代码。在这个例子中,Scriptlet 加载后只会启动计算器进程。
渗透爬虫软件 资源采集 劫持域名 提取抓料子 六合·色站·彩票·博彩·金融 接渗透拿站,各大网站数据-拖库-提权联系 域名劫持 DNS 入侵网站 联系:@hacker_HouZiM
那么,一个有效的 Scriptlet 文件是什么样的呢?它是一个简单的 XML 文件,我不会详细解释每个 XML 元素的含义,只会指出其中的脚本块,它会执行任意的 JScript 代码。在这个例子中,Scriptlet 加载后只会启动计算器进程。
渗透爬虫软件 资源采集 劫持域名 提取抓料子 六合·色站·彩票·博彩·金融 接渗透拿站,各大网站数据-拖库-提权联系 域名劫持 DNS 入侵网站 联系:@hacker_HouZiM
通过搜索 banner,我找到了这个网站的源代码:https://github.com/bearice/tunnel-manager/blob/master/src/API.hs。
通过阅读源码,我发现了一个比较有意思的未公开 API:
在调用这个 API 时,会读取 /data/:name.log。再看看创建 Docker 时候:
注意这一行:
由于这个 API 运行在容器外,但是容器内的 /data 可以操控,于是通过创建软链接即可读取到容器外的文件。
在容器内:
接着访问 logs:
Bingo,至此通过 Docker 配合 API 的文件读取完成。
渗透爬虫软件 资源采集 劫持域名 提取抓料子 六合·色站·彩票·博彩·金融 接渗透拿站,各大网站数据-拖库-提权联系 域名劫持 DNS 入侵网站 联系:@hacker_HouZiM
通过阅读源码,我发现了一个比较有意思的未公开 API:
tunnelLogs :: String -> IO String
tunnelLogs name = do
let path = flags_dataDir </> name <.> "log"
sh $ "tail " ++ escape path
...
get "/tunnel/:name/logs" $ do
name <- param "name"
logs <- liftIO $ tunnelLogs name
text $ L.pack logs
在调用这个 API 时,会读取 /data/:name.log。再看看创建 Docker 时候:
注意这一行:
,"-v "++flags_dataDir++":/data", portDef, flags_image
由于这个 API 运行在容器外,但是容器内的 /data 可以操控,于是通过创建软链接即可读取到容器外的文件。
在容器内:
root@fff2:/data# rm fff.log && ln -s /etc/shadow fff.log
ln -s /etc/shadow fff.log
接着访问 logs:
Bingo,至此通过 Docker 配合 API 的文件读取完成。
渗透爬虫软件 资源采集 劫持域名 提取抓料子 六合·色站·彩票·博彩·金融 接渗透拿站,各大网站数据-拖库-提权联系 域名劫持 DNS 入侵网站 联系:@hacker_HouZiM
任何实际的身份验证(例如使用 WPA2 等协议实现)都发生在关联序列之后。由于关联序列中没有真正的身份验证环节,因此可以使用 MAC 地址和 SSID 冒充任何接入点 (AP)。STA 只有在后续的身份验证阶段才能识别出伪造的 AP。这使得关联序列中的任何漏洞都极具价值。攻击者如果发现关联过程中的漏洞,就可以嗅探受害者的无线探测请求,冒充 STA 正在寻找的 AP,然后触发漏洞而无需经过任何身份验证。
在查找漏洞时,我们得益于博通代码高度模块化的设计,它处理了 802.11 系列的不同协议以及固件本身的不同功能。本例中主要相关的函数是 wlc_attach_module,它将每个不同的协议或功能抽象为一个独立的模块。wlc_attach_module 调用的各种初始化函数的名称极具指示意义。以下是一些示例代码:
每个模块初始化函数都会安装处理程序,这些处理程序会在接收或生成数据包时被调用。这些回调函数负责解析接收到的数据包中与特定协议相关的上下文,或者为传出的数据包生成与协议相关的数据。我们主要关注后者,因为这是解析攻击者控制数据的代码,所以这里相关的函数是 wlc_iem_add_parse_fn,其原型如下:
这里第二个和第三个参数尤为重要。`subtype_bitfield` 是一个位域,其中包含解析器所处理的不同数据包子类型(例如探测请求、探测响应、关联请求等)。第三个参数
wlc_iem_add_parse_fn 函数由 wlc_module_attach 中的各种模块初始化函数调用。通过编写一些代码来解析传递给它的参数,我们可以创建一个列表,列出关联序列每个阶段调用的解析器。通过将搜索范围缩小到此列表,我们可以避免在与我们无关的代码区域查找错误:这些区域仅在用户完成与接入点 (AP) 的完整关联和身份验证过程后才会出现。我们可能在这些区域中发现的任何错误都将无法满足我们最重要的标准——无需用户交互即可触发。
渗透爬虫软件 资源采集 劫持域名 提取抓料子 六合·色站·彩票·博彩·金融 接渗透拿站,各大网站数据-拖库-提权联系 域名劫持 DNS 入侵网站 联系:@hacker_HouZiM
在查找漏洞时,我们得益于博通代码高度模块化的设计,它处理了 802.11 系列的不同协议以及固件本身的不同功能。本例中主要相关的函数是 wlc_attach_module,它将每个不同的协议或功能抽象为一个独立的模块。wlc_attach_module 调用的各种初始化函数的名称极具指示意义。以下是一些示例代码:
prot_g = wlc_prot_g_attach(wlc);
wlc->prot_g = prot_g;
如果 (!prot_g) {
转到失败;
}
prot_n = wlc_prot_n_attach(wlc);
wlc->prot_n = prot_n;
如果 (!prot_n) {
转到失败;
}
ccx = wlc_ccx_attach(wlc);
wlc->ccx = ccx;
如果 (!ccx) {
转到失败;
}
amsdu = wlc_amsdu_attach(wlc);
wlc->amsdu = amsdu;
如果 (!amsdu) {
转到失败;
}
每个模块初始化函数都会安装处理程序,这些处理程序会在接收或生成数据包时被调用。这些回调函数负责解析接收到的数据包中与特定协议相关的上下文,或者为传出的数据包生成与协议相关的数据。我们主要关注后者,因为这是解析攻击者控制数据的代码,所以这里相关的函数是 wlc_iem_add_parse_fn,其原型如下:
void wlc_iem_add_parse_fn(iem_info *iem, uint32 subtype_bitfield,
uint32 iem_type,callback_fn_t fn,void *arg)
这里第二个和第三个参数尤为重要。`subtype_bitfield` 是一个位域,其中包含解析器所处理的不同数据包子类型(例如探测请求、探测响应、关联请求等)。第三个参数
iem_type 包含解析器所处理的 IE 类型。wlc_iem_add_parse_fn 函数由 wlc_module_attach 中的各种模块初始化函数调用。通过编写一些代码来解析传递给它的参数,我们可以创建一个列表,列出关联序列每个阶段调用的解析器。通过将搜索范围缩小到此列表,我们可以避免在与我们无关的代码区域查找错误:这些区域仅在用户完成与接入点 (AP) 的完整关联和身份验证过程后才会出现。我们可能在这些区域中发现的任何错误都将无法满足我们最重要的标准——无需用户交互即可触发。
渗透爬虫软件 资源采集 劫持域名 提取抓料子 六合·色站·彩票·博彩·金融 接渗透拿站,各大网站数据-拖库-提权联系 域名劫持 DNS 入侵网站 联系:@hacker_HouZiM
❤1
我们首先来看一下如何实现写入原语。溢出的结构体类型为 wlc_pm_st,用于处理电源管理状态,包括进入和退出省电模式。该结构体定义如下:
从漏洞利用的角度来看,该结构体中的四个成员尤其值得控制:类型为 wl_timer 的 pspoll_timer 和 apsd_trigger_timer,以及类型为 wlc_hwtimer_to_t 的 pm2_rcv_timer 和 pm2_ret_timer。我们先来看后者。
在处理数据包并触发溢出后,会调用函数 wlc_hwtimer_del_timeout,并接收 pm2_ret_timer 作为参数:
从代码可以看出,通过覆盖
通过使用 struct wl_timer 类型的 pspoll_timer 成员,可以实现限制较少的写入原语。该结构体由关联过程中定期触发的回调函数处理[c]:
如函数末尾所示,我们在这里使用了一个更加便捷的写入原语。实际上,我们可以将存储在 field_1c 中的值写入存储在 field_18 中的地址。这样,我们就可以向任何内存地址写入任意值,而不再受限于之前使用的写入原语。
下一个问题是如何利用我们的写入原语实现完整的代码执行。为此,我们将考虑两种方法:一种方法需要我们预先知道固件内存地址(或者通过多次使芯片崩溃来暴力破解这些地址),另一种方法实现起来更困难,但对内存地址的要求最低。我们首先来看第一种方法。
为了实现写入原语,我们需要用我们控制的内存地址覆盖 pspoll_timer。由于 wlc->current_wmm_ie 和 wlc->ps 的地址对于给定的固件版本是已知且一致的,并且我们可以完全覆盖它们的内容,因此我们可以将 pspoll_timer 指向这些对象中的任何位置。对于创建一个伪 wl_timer 对象,wlc->current_wmm_ie 和 wlc->ps 之间的未使用区域是理想的选择。将我们的虚拟定时器对象放置在那里,我们将使 field_18 指向我们要覆盖的地址(偏移量减去 14),并使 field_1c 保存我们要用来覆盖该内存的内容。触发覆盖后,我们只需等待定时器函数被调用,它就会自动执行覆盖操作。
渗透爬虫软件 资源采集 劫持域名 提取抓料子 六合·色站·彩票·博彩·金融 接渗透拿站,各大网站数据-拖库-提权联系 域名劫持 DNS 入侵网站 联系:@hacker_HouZiM
从漏洞利用的角度来看,该结构体中的四个成员尤其值得控制:类型为 wl_timer 的 pspoll_timer 和 apsd_trigger_timer,以及类型为 wlc_hwtimer_to_t 的 pm2_rcv_timer 和 pm2_ret_timer。我们先来看后者。
在处理数据包并触发溢出后,会调用函数 wlc_hwtimer_del_timeout,并接收 pm2_ret_timer 作为参数:
从代码可以看出,通过覆盖
newto 的值并使其指向攻击者控制的位置,可以将 next->timeout 指向的内存位置的内容递增 newto->timeout 的值。这相当于一个“写任意内容”的原语,但其限制在于必须知道被覆盖内存位置的原始内容。通过使用 struct wl_timer 类型的 pspoll_timer 成员,可以实现限制较少的写入原语。该结构体由关联过程中定期触发的回调函数处理[c]:
如函数末尾所示,我们在这里使用了一个更加便捷的写入原语。实际上,我们可以将存储在 field_1c 中的值写入存储在 field_18 中的地址。这样,我们就可以向任何内存地址写入任意值,而不再受限于之前使用的写入原语。
下一个问题是如何利用我们的写入原语实现完整的代码执行。为此,我们将考虑两种方法:一种方法需要我们预先知道固件内存地址(或者通过多次使芯片崩溃来暴力破解这些地址),另一种方法实现起来更困难,但对内存地址的要求最低。我们首先来看第一种方法。
为了实现写入原语,我们需要用我们控制的内存地址覆盖 pspoll_timer。由于 wlc->current_wmm_ie 和 wlc->ps 的地址对于给定的固件版本是已知且一致的,并且我们可以完全覆盖它们的内容,因此我们可以将 pspoll_timer 指向这些对象中的任何位置。对于创建一个伪 wl_timer 对象,wlc->current_wmm_ie 和 wlc->ps 之间的未使用区域是理想的选择。将我们的虚拟定时器对象放置在那里,我们将使 field_18 指向我们要覆盖的地址(偏移量减去 14),并使 field_1c 保存我们要用来覆盖该内存的内容。触发覆盖后,我们只需等待定时器函数被调用,它就会自动执行覆盖操作。
渗透爬虫软件 资源采集 劫持域名 提取抓料子 六合·色站·彩票·博彩·金融 接渗透拿站,各大网站数据-拖库-提权联系 域名劫持 DNS 入侵网站 联系:@hacker_HouZiM