逆向集成在谷歌语音程序中的Obi200固件:第三部分

阅读量    45421 |   稿费 150

分享到: QQ空间 新浪微博 微信 QQ facebook twitter

 

传送门

逆向集成在谷歌语音程序中的OBi200固件: 第一部分

https://www.anquanke.com/post/id/86765

逆向Google Voice设备OBi200 (二)

https://bbs.pediy.com/thread-221922.htm

 

前言

在本系列的第一部分中,我针对OBi200的固件进行了分析,并且尝试通过利用一些远程命令执行漏洞来获得Shell。在第二部分中,我介绍了如何区分串口针脚以及如何利用串口访问控制台。在这篇文章中,主要讲解如何从目标源代码交叉编译第三方二进制文件、如何调试Obi二进制文件中的崩溃,此外还会介绍一些其它有趣的发现。

 

相关工具

在获取到控制台到设备的访问权限后,我们就要深入到下一步,但在此之前,首先需要一些辅助的工具。举例来说,如果我们能在设备上正确地运行tcpdump,那我们便能够掌握到关于监听服务的更多信息:

其内置的busybox比较老,同时也有一些限制:

# busybox
BusyBox v1.16.2 (2015-06-18 14:18:21 PDT) multi-call binary.
Copyright (C) 1998-2009 Erik Andersen, Rob Landley, Denys Vlasenko
and others. Licensed under GPLv2.
See source distribution for full notice.

由于这块板没有运行gdb的资源,所以我还需要构建gdbserver。为了建立gdbserver和其它实用工具,我需要有一个能够编译OBi的工具链(Toolchain)。

 

工具链

如果我们能使用crosstool-NG来获得交叉编译的ARM工具链,会使我们接下来的过程变得非常简单。在安装之后,我选择了预先配置好的arm-unknown-linux-uclibcgnueabi工具链,并通过运行ct-ng build来编译它。编译的过程需要花费一些时间,最终我们得到了可以在OBi目标上运行的二进制文件。

接下来,我从源代码交叉编译tcpdump、gdbserver、busybox、strace和一些其他工具,完成后再通过netcat将它们转移到OBi。其中的大多数项目都有一些关于交叉编译的文档可以在网上搜索到,例如我们可以参考gdbserver的维基百科:

当然,我们还可以创建一个加密币的“矿工”:

这一尝试仅仅是为了好玩。尽管这是一个令人印象深刻的硬件,但事实上它并不非常完美。

 

调试过程

接下来,我将之前提到的这些工具都复制到OBi上,就可以开始更深入地探索之旅了。回想到我们在第一部分提及过的,以前在一些类似的Obihai软件组件中披露的诸多漏洞,我对OBi200(出厂的固件版本)进行了测试,以验证其是否存在相同的漏洞。下面是针对一个用于准备发送到OBi IPC Socket的命令字符串静态缓冲区的溢出漏洞的尝试:

GET http://192.168.5.83/wifi?checkssid=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA HTTP/1.1
Host: 192.168.5.83
Authorization: REMOVED
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36
Upgrade-Insecure-Requests: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9

正如我们所推测的那样,OBi出现了崩溃并立即重新启动。接下来让我们对这一崩溃进行调试。

由于OBi具有watchdog守护进程,因此gdbserver很难终止并重新启动主二进制文件,所以我使用了多模式(Multi Mode)连接到当前正在运行的进程:

pgrep obiapp

gdbserver —multi localhost:3617

在另一台机器上,我连接了gdb客户端:

在这里,需要注意的是,执行的gdb是由crosstool-NG生成的,而并不是由发行版的包管理器安装的。此外,主机和目标的配置需要与我们当前的调试环境一致。

接下来,我连接到正在运行的obiapp进程,并继续执行线程。


在运行上图所示的HTTP请求之后,我们成功捕获到崩溃,被转储的堆栈和寄存器如下所示:


在这里,我注意到,程序在进行到无效的内存地址0x41414140时会出现段错误(Segmentation Fault),距离上面HTTP请求中的有效载荷“AAAA”只有0x00000001的距离。这表明,攻击者可能能够控制返回地址并中断程序流,最终导致能够执行恶意代码。遗憾的是,在打算对这一漏洞进行更深入利用之前,我提早更新了已经修复这一溢出漏洞的OBi固件,并且已经将精力放在了其他地方。

 

其它发现

在这里,我想聊一聊OBi中还没有完全探索的一些领域,这些地方也非常有趣。我们从硬编码密钥(Hard-coded keys)开始,请参阅下面从obiapp二进制代码反编译得到的伪代码:

signed int __fastcall sub_8C964(const char a1, signed int a2)
{
signed int v2; // r10@1
const char v3; // r8@1
signed int result; // r0@3
int v5; // r5@5
int v6; // r4@5
void v7; // r0@6
void v8; // r10@6
int v9; // r0@6
int v10; // r0@6
size_t v11; // r4@6
FILE *v12; // r5@6
char v13; // [sp+10h] [bp-130h]@6
char dest; // [sp+9Fh] [bp-A1h]@1
char v15; // [sp+E0h] [bp-60h]@6
int v16; // [sp+110h] [bp-30h]@6
int v17; // [sp+114h] [bp-2Ch]@6

v2 = a2;
v3 = a1;
memcpy(&dest, “Nd6o5nSwyGkjfxFTeTU7OrUbGySOldH+WATDn6/D5GfeU/zatF9EO4LAMELvnFq0”, 0x41u);
if ( v2 > 15 && !strncmp(v3, “Salted__”, 8u) )
{
v5 = ((int ()(void))EVP_aes_256_cbc)();
v6 = EVP_md5();
strlen(&dest);
if ( EVP_BytesToKey(v5, v6, v3 + 8, &dest) == 32 )
{
v7 = malloc(v2 - 16);
v17 = v2 - 16;
v16 = 0;
v8 = v7;
v9 = EVP_CIPHER_CTX_init(&v13);
v10 = EVP_aes_256_cbc(v9);
EVP_DecryptInit_ex(&v13, v10, 0, &v15);
EVP_DecryptInit_ex(&v13, 0, 0, 0);
EVP_DecryptUpdate(&v13, v8, &v17, v3 + 16);
EVP_DecryptFinal_ex(&v13, (char )v8 + v17, &v16);
v11 = v16 + v17;
v12 = fopen(“/tmp/module.tgz”, “wb”);
if ( v11 == fwrite(v8, 1u, v11, v12) )
{
syslog(150, “Wrote plaintext; len: %dn”, v11);
fclose(v12);
EVP_CIPHER_CTX_cleanup(&v13);
free(v8);
result = 0;
}
else
{
syslog(150, “Error writing plaintext to file.n”);
fclose(v12);
EVP_CIPHER_CTX_cleanup(&v13);
free(v8);
result = -1;
}
}
else
{
syslog(150, “Error initializing context.n”);
result = -1;
}
}
else
{
syslog(150, “Invalid module file.n”);
result = -1;
}
return result;
}

这个函数似乎可以解密从Obihai的服务器发送的Lua脚本模块。我们注意到上面复制到dest中的静态字符串,它最终会作为EVP_BytesToKey中的数据参数传递。盐(Salt)被作为第一个参数传递给这个函数,但是我并没能确认它到底是动态还是NULL。

在反编译代码过程中,还有另一个有趣的发现:

char byte_26D6B8 = ‘U’; // weak
char aNknown[7] = “NKNOWN”; // weak
char aOb100UnitInfo[16] = “OB100 UNIT INFO”; // weak
char aThisisthesecre[27] = “thisisthesecretofobihaimfd”; // weak
char aThisisanothers[31] = “thisisanothersecretofobihaimfd”; // weak

上面有两个很有趣的“秘密”(Secret)。由于它们提到一个不同的OBi模型,因此我不确定这些变量是否也用在我的模型之中。我发现它们唯一的用法是在这里:

sub_A3440((int)&v32, (int)aThisisthesecre, 0x1Au);
sub_A351C((int)&v34, (int)&v32);
sub_A2870((int)&v32);
sub_A3440((int)&v32, (int)aThisisanothers, 0x1Eu);
sub_A3440((int)&v32, (int)(&v34 + 1), 0xFu);
sub_A3440((int)&v32, v15, v11);
sub_A351C((int)&v33, (int)&v32);
if ( !memcmp(&v33, &v35, 0x10u) )
{
v16 = v11 - v10;
v17 = malloc(v11 - v10);
if ( v17 )
{
RC4_set_key(&v31, 15, &v34);
RC4(&v31, v16, (const char )(v15 + v10), v17);
memcpy((void )(v15 + v10), v17, v16);
free((void *)v17);
}

/
Snipped
/

if ( !memcmp((const void )(v30 + v15), (const void )(v30 + v15 + 9), 9u)
&& !memcmp((const void )(v30 + v15), (const void )(v30 + v15 + 18), 9u) )
return 1;
syslog(0, “p2p hn validation error %d!n”, v30);
result = -1;
}
else
{
syslog(0, “UNIT DATA checksum validation error:n”);
result = -1;
}

从系统日志消息来看,这似乎是某种报告功能,可能会发回Obihai。

在OBi中,还有很多我没有探索过的领域,例如通过云界面(包括Lua脚本)的配置与维护过程、在SIP或其它UDP协议中发生的潜在崩溃等。此外,还有一些集成(OBIEXTRAS)可以用于设备,这就使得其攻击面相当大。

 

漏洞反馈

在研究过程中,我还发现了其他一些漏洞,包括若干中危漏洞和一个高危漏洞。目前,我仍然在与Obihai合作处理这些漏洞,并可能会在发布修补程序之后披露这些漏洞。

分享到: QQ空间 新浪微博 微信 QQ facebook twitter
|推荐阅读
|发表评论
|评论列表
加载更多