[转载]高恪再次开启SSH以及升级逻辑、逆向分析

前言

继上次添加SSH后,现在有个淘汰的京东云一代,想要发挥余热,于是乎又去下载了一份高恪S2A版本(因为其不包含MT7615N驱动,故无法使用5G WiFi频段),由于我只是想使用其并发多拨的功能,因此关系不大。

按照前文的流程,卡卡一顿改完后,刷入设备,成功取得ssh,但是升级后就没了,但是官方上没有找到升级包的下载地址,于是乎有了本文的后续分析。

同时在分析中发现,有疑似后门的程序。

升级流程

/usr/lib/lua/luci/controller/admin/system.lua

网页上的检查升级按钮,最终会调用到这个lua中,但是这并不是明文,而是已经编译成luac的字节码。

反编译流程在这里不在展开,网上有许多现成的资料,需要留意的是openwrt中使用了魔改的lua。

关于升级检查的功能,主要位于prepare_onlineupgrade_inifile方法内。

/sbin/onlineupgrade.sh

通过对反编译后的system.lua分析,可知更新流程,会请求http://update.go-cloud.cn/RN1200/GOCLOUD-S2A_WL.ini检查是否存在新版本(URL后半段与具体型号有关)。

请求流程最终调用/sbin/onlineupgrade.sh脚本完成。

手动下载该配置文件后,发现配置文件非明文,采用Rijndael算法进行加密。再次返回system.lua分析,查找解密的密钥,通过在设备上运行以下lua脚本获得密钥:

require("luci")
require("luci.sys")

print("luci.sys.get_crypto_key:" .. luci.sys.get_crypto_key())
print("luci.sys.get_crypto_old_key(这是用于解密升级包的密钥):" .. luci.sys.get_crypto_old_key())

获得密钥后,简单的通过命令行ccrypt -d GOCLOUD-S2A_WL.ini -K <PASSWORD> -c即可得到明文的配置文件,如下:

version=5.2.2.22550
date=2023-06-26
size=12058628
url=http://update.gocloud.cn/GOCLOUD-S2A_WL-5.2.2.22550.bin.web
name=GOCLOUD-S2A_WL-5.2.2.22550.bin.web
md5=af4daf2bcc2521b3f4ddd5afe25125c3
standard=S2A_WL
log=5.2.2.22550(2023.06.26)主要更新:<br />1.  特征库合并到最新<br />2.  修正一个交换机管理相关的配置兼容问题<br /><br />5.2.2.22540(2023.06.24)主要更新:<br />2.  优化一个AC相关的问题<br /><br />5.2.2.22513(2023.06.07)主要更新:<br />1.  SDWAN自组网代理模式优化<br />3.  POE网关桌面版支持网段冲突自动规避;<br /><br />5.2.2.22479(2023.05.30)主要更新:<br />1.  部分型号优化SDWAN二层自组网<br />2.  部分型号优化SDWAN三层自组网,支持对等组网<br />3.  软路由接口概览显示协商速率;<br />4.  软路由网吧版加强游戏更新服务器上传流量的控制,大幅降低P2P上传导致宽带重拨的概率<br />5.  软路由网吧版解决部分机器不能安装的问题<br />6.  加快付费产品加入云管平台的速度;优化长Ping快捷配置,不再使用114<br /><br />5.2.2.22360(2023.04.18)主要更新:<br />1.  部分型号支持SDWAN二层自组网(公测)<br />2.  部分型号比如POE网关桌面版、弱电箱专用路由、WiFi6路由支持手机首次连接路由弹portal引导到快速向导,方便施工开局<br />3.  POE网关桌面版支持一机一码认证;<br /><br />5.2.2.21901(2022.10.26)主要更新:<br />1.  修正一个潜在的安全问题,请务必及时更新<br /><br />5.2.2.21650(2022.06.23)主要更新:<br />1.  完善SDWAN自组网私有部署, 部分官方路由支持服务端【支持创建组网】, 部分官方路由仅仅支持分支节点【允许加入组网】<br />2.  完善I225网卡驱动<br />3.  完善软路由控制台,在识别不到网卡时做恰当的提示<br />4.  默认关闭dns重定向保护;<br /><br />5.2.2.21466(2022.04.28)主要更新:<br />1.  支持SDWAN私有部署, 部分官方路由支持服务端【支持创建组网】, 部分官方路由仅仅支持分支节点【允许加入组网】<br />2.  AP管理支持显示上联接口的协商状态<br />3.  流控例外支持配置目的IP组例外<br /><br />

其中载明了升级包的地址,但是直接访问,却发现返回404,将主机名修改为update.go-cloud.cn即可正常访问(完整地址为http://update.go-cloud.cn/RN1200/GOCLOUD-S2A_WL-5.2.2.22550.bin.web

*.bin.web文件下载后,依葫芦画瓢使用ccrypt命令解密即可。

解密后是一个标准的tar格式文件,继续tar xf <FILENAME>

解包后包含两个文件:

  • firmware.bin

  • firmware.ini

通过查看,firmware.bin文件只是简单描述设备型号,不需要处理。firmware.bin是一个uImage文件,那么就回到了最开始的工作了。

$ binwalk firmware.bin

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             uImage header, header size: 64 bytes, header CRC: 0x159706CA, created: 2023-06-26 07:34:15, image size: 1363048 bytes, Data Address: 0x81001000, Entry Point: 0x81001000, data CRC: 0x4166CAA3, OS: Linux, CPU: MIPS, image type: OS Kernel Image, compression type: lzma, image name: "OpenWrt Linux-3.10.14-169495"
64            0x40            LZMA compressed data, properties: 0x6D, dictionary size: 8388608 bytes, uncompressed size: 4143424 bytes
1363112       0x14CCA8        Squashfs filesystem, little endian, version 4.0, compression:xz, size: 10582460 bytes, 4019 inodes, blocksize: 262144 bytes, created: 2023-06-26 07:34:13

开启SSH

这一部分其实是老活了。

经过检查,固件中仍然包含dropbear,那么只需要简单的开启即可。修改/etc/rc.local

(
    sleep 5
    chmod 755 /etc/init.d/dropbear
    /etc/init.d/dropbear enable
    /etc/init.d/dropbear restart
) &

exit 0

同时修改ssh端口为22,这一步可选,不修改,默认为22222,/etc/config/dropbear

config dropbear
        option PasswordAuth 'on'
        option RootPasswordAuth 'on'
        option Port         '22'

打包、升级

其实打包后的固件可直接通过breed刷机,但是这样可能配置信息就没了,而要通过系统自己的升级流程,就需要反过来操作一遍解包的流程。

# 将固件与ini文件重新打包成tar
tar -cvf output.bin.web firmware.bin firmware.ini
# 对tar进行加密
ccrypt -e output.bin.web -K <PASSWORD>

随后即可通过web的升级功能,选择本地升级即可。

意外的发现

因为在系统里发现了一些有趣的东西,也一起分享一下。

截止目前为止,高恪依旧是基于OpenWRT 14.07进行魔改的,内核版本为3.10.14,相对版本较为陈旧是否与长期不支持IPv6有关?

以下内容涉及到lua及其反编译,本人并不擅长,结论仅供参考,请各位自行分析。

以下所有内容都可能与云管有关,但部分组件为开机自启动,即使未开启云管功能依旧运行。

n2n

这一部分猜测是与云管有关系,但是因为n2n是二层的网络架构,同时设备上也有dropbear可以开启SSH(虽然官方固件并不开启,也不允许用户自行开启,却保留了dropbear),在技术上可以遥控路由器做任何事情。

当然n2n组件并未在开机时自动启动。

/etc/init.d/n2n

下面是最新版本5.2.2.22550的内容,对比官方发布的底包,是有所不同的,在底包中,开启n2n的同时,会开启dropbear,并监听在n2n ip的22222端口,供远程访问。

#!/bin/sh /etc/rc.common
# Copyright (C) 2008 OpenWrt.org
START=99


start() {
	enable=$(uci -q get n2n.global.enable)
	if [ "$enable" == "0" ]; then
		pidfile="/tmp/n2n-edge.pid"
		if test -f "$pidfile" ; then
			kill -9 `cat $pidfile`
			rm -f "$pidfile"
		fi
		exit
	fi

	sysctl -w net.core.rmem_max=10485760
	sysctl -w "net.ipv4.udp_mem=3000 12000 48000"
	sysctl -w net.ipv4.udp_rmem_min=180224

	ipaddr=$(uci -q get n2n.global.ipaddr)
	community=$(uci -q get n2n.global.community)
	token=$(uci -q get n2n.global.token)
	sdwan_ip=$(uci -q get n2n.global.sdwan_ip)
	serial=$(leval luci.sys.get_serial_number)
	wan=$(uci -q get n2n.global.wan)
	if [ -z "$wan" ]; then
		wan='auto'
	fi

	if [ -z "$sdwan_ip" ]; then
		speedlimit=$(uci -q get n2n.global.speedlimit)
		if [ -z "$speedlimit" ]; then
			speedlimit=250
		fi
		flags=$(uci -q get n2n.global.flags)
		if [ -z "$flags" ]; then
			flags=0
		fi
		master=$(uci -q get n2n.global.master)
		if [ -z "$master" ]; then
			master="n2n.gocloud.cn"
		fi
		edge -r -l $master -a static:$ipaddr -c $community -S $serial -x $speedlimit -T $token -d n2n -F $flags -w "$wan"
	else
		edge -r -P $sdwan_ip -a static:$ipaddr -c $community -S $serial -T $token -d n2n -F 0 -w "$wan"
	fi
}


stop() {
	/usr/lib/lua/spyder/tools/fw_n2n stop 1>/dev/null 2>&1
	pidfile=/tmp/n2n-edge.pid
	if test -r $pidfile; then
		kill `cat $pidfile`
		rm -f $pidfile
	fi
	if pgrep edge; then
		killall -9 edge
	fi
}

/usr/lib/lua/luci/model/cbi/admin_system/remotedb.lua

虽然新版中n2n开启时,不再直接开启dropbear,但是新版本多了一个remotedb的组件,位于/usr/lib/lua/luci/model/cbi/admin_system/remotedb.lua,其反编译后的代码大概长这样

db.parse = function(l_1_0, l_1_1)
  -- function num : 0_0
  do
    if not l_1_0:formvalue(l_1_1) then
      local l_1_2, l_1_3, l_1_4, l_1_5, l_1_6, l_1_7, l_1_8 = l_1_0.default
    end
    -- DECOMPILER ERROR at PC6: Confused about usage of register: R2 in 'UnsetPending'

    -- DECOMPILER ERROR at PC8: Confused about usage of register: R2 in 'UnsetPending'

    if l_1_2 and l_1_2 == "1" then
      (os.execute)("chmod 755 /etc/init.d/dropbear")
      ;
      (os.execute)("/etc/init.d/dropbear restart")
    else
      ;
      (os.execute)("killall dropbear")
      ;
      (os.execute)("chmod 644 /etc/init.d/dropbear")
    end
    -- DECOMPILER ERROR at PC29: Confused about usage of register: R2 in 'UnsetPending'

    l_1_0:write(l_1_1, l_1_2)
  end
end

可以看到其可以接受两个参数,决定开启或者关闭dropbear,那么再深入一步,看看是否有地方用到了这个模块呢。

发现在/usr/lib/lua/luci/controller/admin/system.lua中有使用,但是因为反编译的一些原因,无法具体的深入分析。猜测可能与授权有关。

/usr/sbin/realtimed

设备启动后,存在一个进程realtimed,启动参数为/usr/bin/lua /usr/sbin/realtimed -p 65527,大抵是在本地开启一个http服务(端口65527),具体用途未深入分析。另外还会监听一个端口65528,从下面节选的一段反编译代码来看,也与spyder组件相关

local verify_spydersign = function()
  -- function num : 0_20
  if (require("app")).DEBUG then
    return true
  end
  local buf = tmpbuf:rewind()
  local key = (buf:putw(Unknown_Type_Error, Unknown_Type_Error, Unknown_Type_Error, Unknown_Type_Error, Unknown_Type_Error)):str()
  ;
  (buf:rewind()):putstr("spyder.sign")
  local fnames = (fs.listdir)("/usr/lib/lua/spyder")
  ;
  (table.sort)(fnames)
  local loadfile = function(fpath)
    -- function num : 0_20_0 , upvalues : buf
    buf:putc((fs.access)(fpath, fs.X_OK) == Unknown_Type_Error and Unknown_Type_Error or Unknown_Type_Error)
    file_get_content(fpath, buf)
  end

  for _,fname in ipairs(fnames) do
    if fname:match("%.lua$") then
      loadfile("/usr/lib/lua/spyder/" .. fname)
    end
  end
  loadfile("/usr/sbin/spyder")
  loadfile("/etc/init.d/spyder")
  aes_pencrypt(buf, md5(key))
  do
    local fdata = file_get_content("/etc/spyder.sign")
    do return not fdata or md5(buf) == fdata end
    -- DECOMPILER ERROR: 2 unprocessed JMP targets
  end
end

/usr/sbin/spyder

设备启动后同样存在spyder的服务,从名字看,与spider非常像,于是我也反编译粗略看了一眼,基本上是与spyder.gocloud.cn/115.28.230.105进行某些交互(实际运行时输出信息显示,连接的IP有所不同)。

$ tail -f /proc/15093/fd/3
01-11 16:50:50 info *** a.luyou.gocloud.cn resolved as 119.45.50.138
01-01 01:00:51 info *** worker connected
01-01 01:00:51 info *** SEND-REQ: create /login2 1
01-01 01:00:51 info *** RECV-RESP: 0 /login2 1
01-01 01:00:51 info *** set forbid_reset=0
01-01 01:00:51 info *** sync date to 2023-01-01 01:00:51
01-01 01:00:52 info *** SEND-REQ: read /data/app 2
01-01 01:00:52 info *** RECV-RESP: 0 /data/app 2
01-01 01:00:53 info *** scheduled next iplearning 46163 seconds later
01-01 01:00:52 info *** 60 /data/null requests done.

那么交互可以产生哪些效果呢,于是我注意到了一个文件/usr/lib/lua/spyder/cmd.lua,反编译后的代码大概长这样

routes["/cmd/execsh"] = function(l_1_0)
  -- function num : 0_0
  do
    if l_1_0.body then
      local l_1_1, l_1_2 = (l_1_0.body):str()
    end
    local l_1_3 = nil
    ;
    (log.info)("execsh: ", l_1_3)
    if type(l_1_3) == "string" then
      if l_1_3 == "reboot" then
        reply(l_1_0, Unknown_Type_Error)
        ;
        (tasklet.sleep)(Unknown_Type_Error)
      end
      ;
      (os.execute)(l_1_3 .. " &")
    else
      -- DECOMPILER ERROR at PC35: Overwrote pending register: R2 in 'AssignReg'

    end
    return Unknown_Type_Error
  end
end
routes["/cmd/execlua"] = function(l_3_0)
  -- function num : 0_2
  do
    if l_3_0.body then
      local l_3_1, l_3_2 = (l_3_0.body):str()
    end
    -- DECOMPILER ERROR at PC7: Confused about usage of register: R1 in 'UnsetPending'

    local l_3_3 = nil
    if not loadstring(l_3_1) then
      (log.error)("execlua syntax error")
    else
      local l_3_4, l_3_5 = , pcall(loadstring(l_3_1))
      if not l_3_5 then
        (log.error)("execlua runtime error: ", R7_PC25)
      end
    end
    do
      return Unknown_Type_Error
    end
  end
end

大概意思就是可以执行任意shell以及任意lua脚本。

最后

我个人觉得realtimedspyder两个组件还是有点可疑的,一为开机自启动,二为这两个组件停止后,会自动重启。

但是相关内容实在太多了,本人才疏学浅,看不完了。如果有其他感兴趣的大佬,可以接着分析一波,甚至中间人后tcpdump实锤一波。

附本次分析的镜像文件(已开启SSH),可breed直接刷入MT7621设备:点击下载(也可使用SX系列在x86虚拟机内分析,大部分内容都是相似的)


この記事はhttp://www.chieng.cn から来て、再現してください!
打赏 支付宝打赏 微信打赏

评论

Top