文章发布至看雪《KCTF 2021秋季赛 第九题 万事俱备》
初步分析 易语言? 拿到程序,发现是易语言写的,还有点奇怪,直接x64dbg调试先看,跑起来发现易语言只是套了个外壳: Py脚本 从temp目录找到check.py和对应的CPython2.7解释器,不用想解释器肯定是改过的,先定位到程序版本: 程序版本是2.7.18,从官网下载源码编译,https://www.python.org/ftp/python/2.7.18/Python-2.7.18.tgz
Windows:解压源码,进入PCBuild目录,打开pcbuild.sln,选择Debug模式编译python和pythoncore 其他的模块,如socket等按需编译即可(如果import失败则编译) 编译报错: Python执行原理 温顾一遍解释器原理也是有必要的,首先定位到几个关键点: PyObject基类 PyEval_EvalFrameEx函数 解释器dispatcher run_pyc_file函数 执行pyc opcode.h里面定义各种opcode宏,大于90是带参数的 直接各种调试下断点,栈回溯即可摸清执行流程 详细分析 处理Opcode 目前还没找到很简单的方法,目前用了两种方式: 1、编写测试代码生成,用两个解释器生成pyc,再用dis模块反汇编对比,这里可写个脚本提高下效率,这种方式能找到到绝大部分。 2、对于方式1不好生成的指令,通过IDA对比PyEval_EvalFrameEx函数,手动识别特征代码(字符串、关系调用等)
重新编译python 替换了源码中的Include/opcode.h和Lib/opcode.py,最终生成python可以执行check.py,开始以为作者在解释器上做了大量工作,事实上并没有。
//恢复的opcode如下 #define NOP 65 #define STOP_CODE 61 #define POP_TOP 30 #define ROT_TWO 52 #define ROT_THREE 56 #define DUP_TOP 13 #define ROT_FOUR 16 #define UNARY_POSITIVE 32 #define UNARY_NEGATIVE 89 #define UNARY_NOT 57 #define UNARY_CONVERT 87 #define UNARY_INVERT 25 #define BINARY_POWER 77 #define BINARY_MULTIPLY 69 #define BINARY_DIVIDE 71 #define BINARY_MODULO 14 #define BINARY_ADD 81 #define BINARY_SUBTRACT 53 #define BINARY_SUBSCR 40 #define BINARY_FLOOR_DIVIDE 76 #define BINARY_TRUE_DIVIDE 48 #define INPLACE_FLOOR_DIVIDE 26 #define INPLACE_TRUE_DIVIDE 63 #define SLICE 0 #define SLICE_1 1 #define SLICE_2 2 #define SLICE_3 3 #define STORE_SLICE 4 #define STORE_SLICE_1 5 #define STORE_SLICE_2 6 #define STORE_SLICE_3 7 #define DELETE_SLICE 8 #define DELETE_SLICE_1 9 #define DELETE_SLICE_2 10 #define DELETE_SLICE_3 11 #define STORE_MAP 64 #define INPLACE_ADD 17 #define INPLACE_SUBTRACT 86 #define INPLACE_MULTIPLY 20 #define INPLACE_DIVIDE 74 #define INPLACE_MODULO 67 #define STORE_SUBSCR 73 #define DELETE_SUBSCR 23 #define BINARY_LSHIFT 66 #define BINARY_RSHIFT 19 #define BINARY_AND 18 #define BINARY_XOR 88 #define BINARY_OR 85 #define INPLACE_POWER 33 #define GET_ITER 70 #define PRINT_EXPR 39 #define PRINT_ITEM 59 #define PRINT_NEWLINE 15 #define PRINT_ITEM_TO 62 #define PRINT_NEWLINE_TO 24 #define INPLACE_LSHIFT 41 #define INPLACE_RSHIFT 72 #define INPLACE_AND 45 #define INPLACE_XOR 37 #define INPLACE_OR 29 #define BREAK_LOOP 50 #define WITH_CLEANUP 42 #define LOAD_LOCALS 83 #define RETURN_VALUE 46 #define IMPORT_STAR 28 #define EXEC_STMT 51 #define YIELD_VALUE 60 #define POP_BLOCK 22 #define END_FINALLY 31 #define BUILD_CLASS 54 #define HAVE_ARGUMENT 90 /* Opcodes from here have an argument: */ #define STORE_NAME 112 #define DELETE_NAME 127 #define UNPACK_SEQUENCE 107 #define FOR_ITER 108 #define LIST_APPEND 141 #define STORE_ATTR 102 #define DELETE_ATTR 137 #define STORE_GLOBAL 98 #define DELETE_GLOBAL 114 #define DUP_TOPX 110 #define LOAD_CONST 131 #define LOAD_NAME 94 #define BUILD_TUPLE 106 #define BUILD_LIST 133 #define BUILD_SET 116 #define BUILD_MAP 139 #define LOAD_ATTR 140 #define COMPARE_OP 95 #define IMPORT_NAME 124 #define IMPORT_FROM 135 #define JUMP_FORWARD 115 #define JUMP_IF_FALSE_OR_POP 123 #define JUMP_IF_TRUE_OR_POP 128 #define JUMP_ABSOLUTE 118 #define POP_JUMP_IF_FALSE 92 #define POP_JUMP_IF_TRUE 120 #define LOAD_GLOBAL 138 #define CONTINUE_LOOP 113 #define SETUP_LOOP 93 #define SETUP_EXCEPT 111 #define SETUP_FINALLY 130 #define LOAD_FAST 109 #define STORE_FAST 119 #define DELETE_FAST 142 #define RAISE_VARARGS 134 #define CALL_FUNCTION 90 #define MAKE_FUNCTION 126 #define BUILD_SLICE 105 #define MAKE_CLOSURE 136 #define LOAD_CLOSURE 132 #define LOAD_DEREF 125 #define STORE_DEREF 122 #define CALL_FUNCTION_VAR 99 #define CALL_FUNCTION_KW 100 #define CALL_FUNCTION_VAR_KW 101 #define SETUP_WITH 143 #define EXTENDED_ARG 145 #define SET_ADD 146 #define MAP_ADD 147 反汇编pyc 使用uncompyle6,发现反编译都失败了,最后选择了Decompyle++ Decompyle++仓库:https://github.
文章发布至看雪《KCTF 2021秋季赛 第七题 声名远扬》
起点 32位,无保护,ida搜索字符串没有看到错误输出,没有明显的函数处理过程 发现Duilib写的,下载源码,编译lib,https://github.com/duilib/duilib,pct,sigmake制作签名文件,应用之~ 识别了500多个还可以了,阅读源码,跟踪按钮事件,CNotifyPump::NotifyPump->CNotifyPump::LoopDispatch,进而跟踪到按钮消息处理函数sub_89D2D0。 分析出大致流程如下: int __userpurge sub_89D2D0@<eax>(int a1@<ecx>, int a2@<ebx>, int a3@<edi>, int a4@<esi>, int a5) { v13 = a1; result = a1; if ( *(_DWORD *)(a1 + 1384) == *(_DWORD *)(a5 + 136) ) { //... v10 = sub_89E530(a1a, a2a); //编码函数 //... sub_89D600(&v15, a2, a3, a4, v7, (int)v16); //校验函数 (*(void (__thiscall **)(_DWORD, char *))(**(_DWORD **)(v13 + 1388) + 44))(*(_DWORD *)(v13 + 1388), v16); //结果提示 } return result; } 分析 关键代码1(编码函数),一个简单的类似base64的编码,这里我想的是直接通过ida脚本去把表提出来。 for ( i = 0; ; i += v11 ) { v2 = get_len(a2); v11 = v2 - i; v27 = '@'; Src = *(_BYTE *)sub_89E970(v30, (int)&v27); //从编码表中替换 v26 = 64; v32 = *(_BYTE *)sub_89E970(v30, (int)&v26); v25 = 64; v33 = *(_BYTE *)sub_89E970(v30, (int)&v25); v24 = 0x40; v34 = *(_BYTE *)sub_89E970(v30, (int)&v24); if ( !
问题点 最近在更新rk3399的android板子时,用到了Linux_Upgrade_Tool工具 https://github.com/rockchip-linux/tools/tree/master/linux/Linux_Upgrade_Tool/Linux_Upgrade_Tool
查看文档 按照文档刷system分区,死活出错! 看了一圈没找到有用的,这些人做事也太不严谨了,难道di这功能没测试过?
时间紧,还是先自己解决吧,上gdb,下puts断点,bt栈回溯,发现这里抛错了,上ida看看代码
跟进去,发现wordexp返回失败 继续在此下断点,i r $rax查看返回值是2
查看man文档,以及相关定义,返回WRDE_BADCHAR,发现存在\n,果不其然 https://man7.org/linux/man-pages/man3/wordexp.3.html https://sites.uclouvain.be/SystInfo/usr/include/wordexp.h.html
WRDE_BADCHAR /* A metachar appears in the wrong place. */ 改下内存,抹掉\n set *(char*)0x7fff295c99e0=0x00 改后测试通过 Patch二进制 内存补丁都是crack的惯用伎俩,这里没必要写代码,直接用ida给split_commandline函数打个patch即可。 在下面找了个没调用的函数free_commandline(不然写代码空间不够) split_commandline函数入口 ... //跳到修复的shellcode .text:0000000000404B6C E9 9F 00 00 00 jmp _Z16free_commandlinePPci ; free_commandline(char **,int) retrump标签 ... .text:0000000000404C10 57 push rdi //保存参数 .text:0000000000404C11 E8 52 BA FF FF call j_strlen_ifunc //获取字符串长度 .text:0000000000404C16 5F pop rdi //恢复参数 .text:0000000000404C17 48 8D 44 07 FF lea rax, [rdi+rax-1] //拿到最后一个字符地址 .
遇到android11模拟器启动,直接segment fault,简单分析了下原因。
启动模拟器命令: ./emulator -writable-system -netdelay none -netspeed full @android11_x86_64 -no-window gdb –args 调试启动,报错后bt栈回溯如下: #0 0x000000000e95b080 in ?? () #1 0x00007fffeb1e76aa in ?? () from /home/install/android-sdk/emulator/lib64/gles_swiftshader/libGLESv2.so #2 0x00007fffeb1e6afd in ?? () from /home/install/android-sdk/emulator/lib64/gles_swiftshader/libGLESv2.so #3 0x00007fffeb1e68b1 in ?? () from /home/install/android-sdk/emulator/lib64/gles_swiftshader/libGLESv2.so #4 0x00007fffeb1e6803 in ?? () from /home/install/android-sdk/emulator/lib64/gles_swiftshader/libGLESv2.so #5 0x00007fffeb1db921 in ?? () from /home/install/android-sdk/emulator/lib64/gles_swiftshader/libGLESv2.so #6 0x00007ffff79beea5 in start_thread () from /lib64/libpthread.so.0 #7 0x00007ffff69d79fd in clone () from /lib64/libc.so.6 很奇怪,0xe95b080没有所属模块,开始以为是跑飞了,后面disassembly发现是动态分配的内存,然后代码没执行权限。
想到了selinux,一看果然开启在,于是setenforce 0 临时关掉,it works…
前置:
pixel3 内核分支android-msm-crosshatch-4.9-pie-qpr1 编译方法:
下载代码不说了,aosp常规操作,如何编译内核,参考官方文档Building Kernels
首先执行build/config.sh配置,选择Kernel Hacking -> Tracers,勾选Function和Dynamic Trace等各项。config.sh完成后你会发现配置保存到了private/msm-google/arch/arm64/configs/b1c1_defconfig。
参考官方使用Ftrace的文档,还是手动配置b1c1_defconfig来得实在。
配置CONFIG_FTRACE=y和CONFIG_DYNAMIC_FTRACE=y,然后执行SKIP_MRPROPER=1 build/build.sh,开始编译
产物在out/android-msm-bluecross-4.9/dist/Image.lz4-dtb
使用fastboot boot Image.lz4-dtb 先加载内核测试,先不用刷进去
Ftrace使用:
参考文档Using ftrace,功能点很多
cd /sys/kernel/debug/tracing //进入tracefs目录
echo function > current_tracer //设置函数跟踪
echo SyS_kill > set_ftrace_filter //过滤kill调用,可用来跟踪壳的反调试
echo 1 > tracing_on //开启跟踪
cat trace //查看日志
echo 0 > tracing_on //关闭跟踪
问题:
ftrace的几个编译错误 执行优化:LTO vmlinux.o时若提示错误,多半是内存不够,使用mkswap命令开大点 内核编译ftrace后,查看available_tracers没有生效 因为CONFIG_TRACE和CONFIG_DYNAMIC_FTRACE=y根本没写进去 当执行build.sh会在check_config里面提示配置不一致 修改build/_setup_env.sh里check_config为return 0,然后手动修改out/android-msm-bluecross-4.9/private/msm-google/defconfig添加两项配置CONFIG_FTRACE=y,CONFIG_DYNAMIC_FTRACE=y。 PS:这个Kconfig也是奇怪,通过menuconfig死活新增不了这两个配置 相关资料
AndroidP-Ftrace 功能使用踩坑全过程记录 程序动态分析工具调研 ftrace(五)-trace_options 其他记录
构建bootimg (SKIP_MRPROPER=1 BUILD_BOOT_IMG=1 KERNEL_CMDLINE=“console=ttyUSB0,115200” ./build/build.sh)
Author: BlackINT3 2020.12.2
前言 本文档主要讲述了从硬件拆解、固件提取/分析、漏洞挖掘、利用到披露的整个过程。
无线路由器简介 无线路由器在家庭中十分常见,您可以使用这种硬件设备连接到互联网运营商的主缆线或 xDSL 互联网网络。无线路由器又可称为 Wi-Fi 路由器,同时具备无线接入点和路由器的网络功能。
路由器将本地网络连接到其他本地网络或互联网。无线接入点使用 900 MHz 以及 2.4、3.6、5 和 60 GHz 频段的无线电频率将设备以无线方式连接到网络。最新无线路由器基于第二代 IEEE 802.11ac 标准,通常简称为第二代。有时,无线路由器也指无线局域网 (WLAN) 设备。无线网络又可称为 Wi-Fi 网络。
无线路由器安全 无线路由器面临许多安全问题,从密码破解到命令执行,以及后门植入、流量拦截等,常见漏洞分类如下:
Wi-Fi密码破解漏洞 Web漏洞 后门漏洞 缓冲区溢出漏洞 其他漏洞 Linksys简介 Linksys是美国Belkin旗下一个销售家用与小型业务用网络产品的部门,主要经营宽带与无线路由器。期间被思科收购后卖给Belkin,主要占领高端家用和商用路由国外市场。
实例分析 硬件分析 首先拿到Linksys EA7500实物,外观如下:
拆解外壳后,能看到整个PCB做工很精致,芯片也都用屏蔽罩覆盖,芯片附近能找到4Pin针脚,经测试分析是UART口。
固件提取及分析 拆开屏蔽罩,找到NorFlash芯片,通过编程器我们拿到了固件。可通过Binwalk拆包分析,得到了UBoot和Rootfs,如下图所示:
首先分析启动流程,从/etc/initab,跟踪到/etc/system/sysinit如下所示:
漏洞分析 通过对固件分析,我们摸清了系统启动和功能模块的流程,也得到启动密码,可通过UART进入shell,进而调试分析。
在分析过程中,我们发现smb服务脚本在解析路径时,未严格过滤,存在路径穿越漏洞:
漏洞利用 任意访问rootfs 经过分析,我们可以通过U盘,格式化ext3系统,同时伪造.smb_share.nfo配置文件作为payload触发漏洞,文件如下所示:
{index:1|name:"rootfs"|drive:"+DRIVE+"|label:"/tmp/sda1"|folder:"/../../.."|readonly:0|groups:"root,"}, 命令执行 在得到rootfs访问权限后,我们考虑通过crontab服务来获取执行权限。但此处存在问题,smb服务以admin身份运行,而crontab目录需要root权限,因此不能直接写。
在继续分析脚本后,我们发现另一处漏洞,配置文件中name字段可伪造成文件路径,绕过检查,执行chmod 777 ,从而实现权限提升。
这里我们选择修改定时任务sysevent_tick.sh的权限,来执行命令,伪造的配置文件如下:
{index:2|name:"../cron/cron.everyminute/sysevent_tick.sh"|drive:"+DRIVE+"|label:"/tmp/sda1"|folder:"/../../.."|readonly:0|groups:"root,"}, 经过上述操作,再利用nc反弹shell我们拿到root权限:
后门植入 我们不能利用mount rw的方式来修改固件,因此得换另一种方式。可以修改路由器的配置区,Linksys路由器的配置中存在可执行shell脚本。
通过Hook /etc/guardian/register.sh如下来实现后门植入:
利用脚本及演示 Python3利用脚本片段如下:
脚本可获取登录和wifi密码、反弹shell、植入后门实现开机反弹shell:
漏洞披露 2020.12.2 通过Bugcrowd平台将漏洞反馈给了Belkin公司。 2021.