写在前面:逆向工程小白,仅供参考,如有错误,欢迎指正
实验室有台K3C路由器,趁老师不在,逆向玩玩。听老师说这个固件是官改,就去网上查查有没有相关固件。

固件地址:https://download.csdn.net/download/fjh1997/15566880
备份:https://www.right.com.cn/forum/thread-318971-1-1.html http://iytc.net/tools/k3c_v121_fs.bin


使用binwalk提取固件内的根文件系统:

wget http://iytc.net/tools/k3c_v121_fs.bin
binwalk -M -d -e k3c_v121_fs.bin
#注意要加-M表示Recursively 递归提取,比较彻底,

在提取出来的squashfs-root可以找到www,这个里面放的是我们网页根目录的东西。注意到里面有个cgi-bin打开一看是个lua脚本:

#!/usr/bin/lua
require "luci.cacheloader"
require "luci.sgi.cgi"
luci.dispatcher.indexcache     = "/tmp/luci-indexcache"
luci.dispatcher.dataindexcache = "/tmp/luci-dataindexcache"
luci.sgi.cgi.run()

这对应于我们路由器首页的的cgi-bin,但我们首页进去明显是一个登录页面,不太对。我们就可以用以下命令搜索这个登录页面存在固件的哪个文件里:

grep -rna "请输入密码" .

可以看到一个资源文件:

grep -rna "zh-cn.js" . #(在macos下最好用ggrep,使用brew install grep即可)

我们看一下谁引用了这个资源文件:

那么谁引用了这个文件呢?查一下,没查到/

grep -rna "luci-mod-base.list" .

扩大范围试试:

grep -rna "luci-mod-base" .


去这个文件里看看,发现了登录验证内容:

发现这个登录引用了名为"luci.data.guide"的包,来验证当前输入的密码是否正确。既然当前的dispacher.lua脚本位置在/usr/lib/lua/luci目录下,那么我们就去/usr/lib/lua/luci/data目录下找:
找到guide.lua发现引用了guide_plt.lua

去guide_plt.lua里面看看发现引用了luci.adapter.libphi_cgi的get_conf函数来获得密码:

引用了set_conf函数来修改密码:

于是去目录/usr/lib/lua/luci/adapter/下面寻找,发现了一个.so文件,去这个这个文件里面找get_conf和set_conf函数,使用ghidra,搜索字符串"get_conf"和"set_conf",


使用右键


继续跟,

发现了lua_register注册函数。
去(lua5.1官方手册上看了一下https://www.lua.org/manual/5.1/manual.html)
发现第三个参数是一个数组:

void luaL_register (lua_State *L,const char *libname,const luaL_Reg *l);

luaL_Reg他的结构体是:

typedef struct luaL_Reg {const char *name;lua_CFunction func;
} luaL_Reg;

也就是一个是函数名一个是函数的地址,这个组成一个luaL_Reg结构体,多个这样的结构体组成一个数组,我们把数组开头的元素的地址作为我们的第三个参数也就是PTR_DAT_0002406c + 0x4010,其中PTR_DAT_0002406c =0x20000相加得到0x24010。
luaL_Reg 数组必须以一对name与 func 皆为 NULL 结束。
这与我们逆向的结果吻合。

可以参考这篇博客:https://www.jianshu.com/p/6f5ab6d67ffc
比较详细,讲怎么注册函数才能给lua作为动态链接库用。

换言之里面的FUN_0012fd4就是我们get_conf的函数位置,也就是说get_conf对应结构体中的const char *name;,FUN_0012fd4对应结构体中的lua_CFunction func;我们跟进去看看:

很明显,这个函数里面要调用PTR_00024078 + 0x2ce8这个函数,继续追踪,首先看PTR_00024078 结果发现:

这个指针指向的是0x000000地址,如果相加的话,也就是PTR_00024078 + 0x2ce8=0x2ce8,但显然不对,我们没有找到这个地址但函数。

注意到整个动态链接库的起始段地址是以0x10000开头:
那么我们不妨猜一下PTR_00024078的指针指向的就是这个0x10000地址,那么PTR_00024078 + 0x2ce8=0x12ce8,
而之前函数 luaL_register 的第二个参数指向的地方就是PTR_00024078 + 0x3e18=0x13e18,去那个地方看看:

发现果然第二个参数指的是一个字符串叫做libphi-cgi,那么这个get-conf指向的就是函数0x12ce8
去这个函数看看,发现这个函数调用了cal_getvalue这个外部函数。

去打开外部链接库看看,发现有个库libcal.so可疑,去看看,

在cal_getvalue里面发现capi_getvalue调用

很显然capi_getvalue与libcapi.so 有关,再去看看:

结果发现,capi_getvalue调用了外部函数help_sendMsgToServer,显然是与help相关的库导入的,问题是目前有两个,libhelper.so和 libugwhelper.so 至于该用哪个,不太确定,我们在root目录下用命令

grep -rna "help_sendMsgToServer" . 

可以看到

可以看到在libugwhelper.so里面,再去找找:

发现这个函数里面主要在与ubus做交互,ubus是啥,网上查了一下,发现是openwrt用于进程间通讯的程序。说明本质上这个程序获取账号密码或者修改账号密码的本质都是向ubus发送数据,再由ubus来执行。
之后去github上面查了help_sendMsgToServer这个函数,居然查到了源码(https://github.com/paldier/k3c_code/blob/master/ugw/feeds_ugw/framework/helper/libugwhelper/src/ugw_framework.c),这下就基本不用怎么逆向了。


这里面的注释也基本符合我的猜测,这个函数就是给ubus发送信息的。其中第三第四个参数IN const char *pcServerName, 和 IN const char *pcOper引发了我的兴趣,这应该是发送给ubus表示自己要调用的服务名,servername和操作operation,也就是,puvar6和7我看了看,和前面的那个思路一样,一个是0x1207c一个是0x120a8


说明服务名是csd操作名是get。
去固件里查了下这个程序发现确实存在,逆向这个试试

打开字符串的列表,发现里面有很多文件的路径,会不会就是密码的存放路径呢?这些文件名字中大都有“run”,待会就用这个来过滤系统调用。
我们登到路由器里面查看进程,发现确实有这个进程,进程id为13340:

然后编写了个改账号密码的脚本来测试下系统调用:

local plt = require("luci.data.guide_plt")
local errcode, result
errcode, result = plt.modify_account_plt("admin", "admin")

保存为test.lua文件然后使用命令lua test.lua来执行。这样是手动调用来修改密码,同时在此之前,在另一个地方打开终端使用strace来追踪系统调用:

strace -p 13340 2>&1 |grep run

我们注意到csd这个程序有访问/tmp目录内的文件,但我们知道/tmp目录中的文件是临时的,一般不会拿来保存密码,同时还注意到有对/opt/lantiq/config/.run-data.xml的access的请求,但却没有写入操作,这说明该程序可能唤起了一个子进程来写文件。

我们给strace加上-f参数来试试:

strace  -f -p 13340 2>&1 |grep run


结果神奇的事情发生了,我们还看到了程序使用execve唤起了openssl的加密,密码是HALLELUJAH,加密后的文件写入了/opt/lantiq/config/.run-data.xml这个与我们对csd程序中的函数进行逆向的结果吻合(可以查找字符串/opt/lantiq/config/.run-data.xml找到):

既然这样的话,那么我们使用同样的命令对该文件进行解密不就行了么?于是,我使用以下命令,果然执行了成功的解密(源码文件也证实了我这点:https://github.com/paldier/k3c_code/blob/master/ugw/feeds_ugw/framework/libscapi/src/scapi_crypt.c):

openssl aes-256-cbc -base64 -d -in /opt/lantiq/config/.run-data.xml -out result.xml -pass pass:HALLELUJAH

解密出来的是一个xml文件,在里面可以看到密码:

总结:openwrt嵌入式系统修改密码的方式是使用ubus调用csd服务,而csd服务并不会专门给修改密码定义函数,csd只接收传进来的对象然后把他们添加或者修改成为临时的xml文件再对临时的xml文件进行加密,最终存储在flash里面。

记录一次使用ghidra逆向分析斐讯K3官改固件web登录验证的经历相关推荐

  1. 2020斐讯k3刷什么固件_斐讯K2/K3/K2P等路由器搭建收费wifi集成教程

    前言: 1.你需要安装尔雅云固件 2.安装上边的你一般需要安装breed引导 3.安装了breed引导,你实际可以按照openwrt.dd-wrt.lede等固件 4.实际尔雅云固件就是openwrt ...

  2. 斐讯k3搭建nginx+php+MariaDB(mysql )的教程

    安装nginx+php+MariaDB 以前用k3安装了onmp,中间踩了不少坑.以前发到贴吧的,现在发过来记录一下,顺便给大家参考一下. 斐讯k3性能比较强,拿来建小型网站还是可以的.但是内置储存太 ...

  3. 玩转斐讯K3详细刷机——直接刷LEDE

    版权声明:本文为博主原创文章,未经博主允许不得转载.博客不用于商业活动,博主对博客的使用,拥有最终解释权 本文为原创作品,未经本人同意,禁止转载,禁止用于商业用途!本人对博客使用拥有最终解释权 欢迎关 ...

  4. 斐讯k3怎么设置虚拟服务器,斐讯 K3 无线路由器无线中继设置教程

    斐讯 K3 无线路由器无线中继设置教程- 2017-04-12 1.斐讯K3默认的IP地址是192.168.2.1,DHCP服务开启.这些设置好后,在"功能设置"里点开" ...

  5. 斐讯k3怎么设置虚拟服务器,斐讯K3路由器无线中继怎么设置?

    斐讯K3这款外包装采用纯黑配色.高档材质,简约设计强大的无线性能,若用来做无线中继,必定有非常好的的网速,如果不考虑功耗,那么用来当作"无线网卡"使用,也是不错的选择.要发挥出最大 ...

  6. 斐讯路由器设置linux,Windows10系统怎么给斐讯K3路由器开启Telnet

    斐讯K3路由器在刷机之前大神都会告诫我们最好给K3开启Telnet,那么Windows 10系统最简单的开启Telnet的方法是什么呢?下面一起来看看. 对于Windows10来说最强大的就是兼容各种 ...

  7. 树莓派挂载斐讯K3上SMB共享的移动硬盘文件

    最近在使用树莓派时录制视频时,发现录制上3小时左右的视频呢,就用到了差不多3GB的储存空间,对于我的树莓派8GB的SD卡来说呢肯定是不适宜的.所以我就萌发出了在树莓派上挂载斐讯路由器上的移动硬盘来用作 ...

  8. 斐讯K3 在openwrt上如何手动安装阿里云盘aliyun-dav

    感觉网络上很多的东西,不那么复杂的,是没有教程让它变复杂. 斐讯K3 在openwrt上如何手动安装阿里云盘aliyun-dav,这很正常的需求吧,只有固件打包在里面的,没有手动安装的. 于是,本人不 ...

  9. cfe刷机教程 斐讯k3_斐讯K3全版本刷机教程2019-不用降级开telnet拆机TTL

    斐讯K3由于更新了新的固件,想要刷入第三方固件,之前的刷机方法可能不行了,这里分享2019年最新的斐讯K3刷机方法,不用降级,不用开telnet,不用拆机TTL,非常的方便且快捷,下面就给大家说说怎么 ...

  10. 二进制逆向工程师_利用Ghidra逆向分析Go二进制程序(下篇)

    (接上文) 动态分配字符串结构 在第一种情况下,字符串结构是在运行时创建的,为此,需要使用一系列汇编指令在字符串操作之前设置相应的结构.由于指令集的不同,不同的架构之间的结构也是不同的.让我们通过几个 ...

最新文章

  1. AI 还原康乾盛世三代皇帝的样貌,简直太太太好玩了!
  2. 玩转Regsvr32命令
  3. 阿里Druid数据库连接池配置解释
  4. img打 webpack_webpack打包html里面img后src为“[object Module]”问题
  5. linux ssh 推送文件_WinSCP软件双系统(Win-Linux)文件传输教程
  6. Apache Storm:如何使用Flux配置KafkaBolt
  7. [剑指offer]面试题第[36]题[JAVA][二叉搜索树与双向链表][递归]
  8. java遍历jsonarray数组_java-JSON-遍历JSONArray
  9. php 数组重新打乱_php打乱数组二维数组多维数组的简单实例
  10. 使用rsync+inotify配置触发式(实时)远程同步
  11. go map二维数据追加
  12. 第六章 jQuery 选择器——课后作业:
  13. 国遥新天地java_三维空间信息系统-国遥新天地.PDF
  14. 转化二进制数的c语言程序,c语言实现二进制数转换为十进制
  15. c加加语言complex的用法,complex的用法总结大全
  16. https://www.jb51.net/article/146628.htm
  17. html5 树开花效果,几种不用经常照顾的灌木花卉,开成花树后太美了
  18. ssm+Vue计算机毕业设计医院人事及科室病区管理(程序+LW文档)
  19. linux shell logout,.bash_pfofile、.bash_logout和.bashrc区别
  20. 计算机等级考试照片用ps怎么调,Photoshop教程:用PS消除照片中的杂色条纹

热门文章

  1. 实验1 matlab图像处理初步,1.实验一 MatLab数字图像处理初步
  2. 某处发现百分百恢复覆盖的分区数据恢复方法(掌握)
  3. html表单下拉美化教程,使用css美化html表单控件详细示例(表单美化)
  4. 电梯远程监控维护系统方案
  5. mac os+selenium2+chrome驱动+python3
  6. 手机安全修改IMEI的方法
  7. Windows7安装VC2015-2019_redist.x64提示“设置失败0xc8000222-未指定的错误”
  8. 手工杀毒辅助软件(PC Hunter) V1.51 免费绿色版
  9. Linux中使用iOStream头文件,linux中C++编译提示找不到iostream文件
  10. C#自动注册dll方法