周报
周报
心情随笔|2024-8-2|Last edited: 2024-9-6
type
status
date
slug
summary
tags
category
icon
password
AI summary

0x01

进度

做了一下春秋杯的题,发现还是有些新东西的,学会了orw之外的沙箱绕过,还有自己手写了一个单字节爆破的脚本,也算是锻炼了下我的编程水平
之外就是做了下buu的前面几道逆向题,学会了ida的一些快捷键,练习了ida动态调试,记忆最深刻的是迷宫题(当时还不知道叫这个名字),就一步步的硬调,最后调出来了,相当有成就感
还有就是学习了arm汇编,主要是跟着azeria-labs,熟悉了arm的寄存器,掌握了str和ldr两条相当重要的对内存操作的汇编以及初步学习了它的寻址方式(现在就看到立即数寻址)

思考

感觉自己逆向水平不足,需要锻炼逆向水平,现在的想法就是做一些逆向题来提高逆向水平
还有就是打一些国际赛,拓展一下见识,看看pwn题有什么新活
剩下的部分我的想法是学完arm汇编后,做一些arm-pwn巩固一下(发现了一个网站ropemporium,挺好的)

0x02

记录

复现一下cve,首先在官网下载固件
notion image
Snipaste_2024-07-19_18-22-56
查看下文件类型是u-boot
notion image
u-boot
使用binwalk提取文件系统
  • M 参数,递归扫描文件
  • e 参数,提取固件中的文件
安装binwalk(推荐)
如非必要不要选择下面的安装方式(笔者曾尝试过,这样会删除很多依赖,辛辛苦苦搭起来ubuntu环境全烂了)
提取完后如图所示
notion image
bin
接下来我们将goahead的环境搭起来,goahead在bin目录下
qemu启动goahead
notion image
ld
看报错,缺少lib目录下ld,我们在当前目录下创建lib并将ld放在文件夹下即可
有很多缺少库的报错,我们根据报错将库放入即可
最后结构如图所示
notion image
tree
qemu运行,然后不出意外的又失败了
notion image
qemu
可以看见goahead报错cannot open pid file,我们就去程序里找
ida搜索字符串
notion image
string
是无法fopenoff_480e50
notion image
open
发现是没有/var/run/goahead.pid,创建一个
notion image
pid
又报错please execute nvram_daemon first!
notion image
nvram
发现缺失/var/run/nvramd.pid
notion image
nvramd
报错failed to convert to binary ip data
notion image
data
定位到lan_ipaddr
notion image
lan
卡住…
看见网上的办法都是ida远程调试hook掉,待我研究研究qemu远程调试

疑问

如何确定是哪个二进制文件?我看网上全是直接开始分析goahead,但是在漏洞挖掘中我们是不知道哪里有漏洞的,如何确定漏洞所在的文件?

0x03

记录

书接上回,让我们看看如何解决failed to convert to binary ip data报错
notion image
data
经过本人实测,远程调试patch是最可靠的方法
具体操作如下
1.虚拟机选择桥接
notion image
vm
2.将在ida的dbgsrv目录下linux_serverlinux_server64文件复制到ubuntu下
notion image
dbg
notion image
linux
3.赋予linux_serverlinux_server64可执行权限
sudo chmod +x ./linux_server linux_server64
4.ifconfig查看虚拟机ip
notion image
ip
5.在ubuntu上运行linux_server并运行goahead
sudo qemu-mipsel -g 1234 -L ./ ./bin/goahead
在ida里填好ip,端口
notion image
port
6.打断点,运行
notion image
jmp
7.修改v0的值为0,即可继续运行
notion image
v0
打开http://192.168.0.105/dir_login.asp,即可进入登陆界面(不能在ubuntu打开,困扰了我好久😢,用kali打开的,本机也可)
notion image
kali
搭好之后我们要登录进去,我选择修改前端(也可以patch)
_DIR-816.img.extracted/squashfs-root/etc_ro/web中找到dir_login.asp,注释掉禁止输入空字符的js即可
至于为什么这样做,主要是为了绕过登录代码
这个程序的登录逻辑是从nvram_bufget获得用户名和密码放在v2,v3。用户输入的用户名和密码经过base64编码放在var和v7中,解码后的用户名和密码放在v10,v11中
v2,v3值为0,当v10,v11为0时即可绕过检查
notion image
login
访问http://192.168.0.5/d_wizard_step1_start.asp
notion image
set
找到漏洞点,ls测试一下
notion image
test
不行,那用burp抓下包
notion image
error
在datetime处注入命令
notion image
cmd
发过去,success
notion image
success
详细看下代码,从web获得输入的datetime的值放在var
&unk_47c2b8date -s \"%s\",var可以由用户控制,存在命令注入
notion image
code

疑问

复现cve最大的感触是寻找漏洞才是最关键的,这个漏洞出现在cgi上,cgi更容易产生漏洞?

0x04

记录

准备复现一下小米路由器的cve
官网下载https://www1.miwifi.com/miwifi_download.html
notion image
下载稳定版
binwalk -Me miwifi_ra70_firmware_cc424_1.0.168.bin解压
得到2B4.ubi,需要ubi_reader
ubi_reader下载
pip install --user ubi_reader
ubireader_extract_images 2B4.ubi提取出ubifs-root
notion image
binwalk -Me img-870537086_vol-ubi_rootfs.ubifs提取出squashfs-root
notion image
小米的前端是lua写的,但是只有编译好的字节码文件,没有源文件,所以我们要进行反编译
对lua进行反编译,我用的是unluac反编译器,但不能对小米的程序进行反编译,所幸有的师傅出了专门的反编译工具unluac for MiWifi
我们首先安装反编译器(注意,需要有java环境)
安装完后,对lua文件进行反编译
java -jar /home/tr0upe/tools/unluac_miwifi/build/unluac.jar xqdatacenter.lua > dis.lua即可得到反编译后的文件
notion image
由于我没学过lua,分析了好久也没弄清楚,所以先搁置了,去搞环境搭建
这次环境搭建是系统仿真,之前没弄过,遇到了好多问题
arm64的系统仿真需要内核与磁盘镜像,我直接用的ZIKH26师傅的,感谢师傅
按照ZIKH26师傅写的运行./net
notion image
发现网桥不存在
sudo apt install libvirt-daemon-system libvirt-clients virt-manager安装 libvirt 相关包
notion image
error,依赖关系不满足
sudo apt-get update试一下
notion image
怀疑是网络问题,ping一下试试
notion image
域名解析失败,应该是dns服务器的问题,换个dns试试
sudo vim /etc/resolv.conf添加如下框住的dns
notion image
保存后重新ping一下
notion image
success,接下来起手
然后sudo apt install libvirt-daemon-system libvirt-clients virt-manager安装 libvirt 相关包
添加网桥brctl addbr virbr0
运行./net.sh无报错,接着运行./start.sh
发现没有分配ipv4地址,不知道宿主机如何与qemu通信
notion image
重启了一下虚拟机,然后打不开了😭
notion image

疑问

对一个没学过的语言,逆向出来如何快速进行代码审计,还有就是qemu仿真太折磨人了,叕叕把我的虚拟机干爆了🤮

0x05

记录

上次把虚拟机干爆了,这回重新搭个新的
选择了ubuntu的最新版本24.04
首先是安装环境

安装qemu

安装依赖

安装成功后ifconfig查看,virbr0会被分配ip
notion image
运行net.sh后运行start.sh
进入qemu后是无ip的,我们要分配一个
分配完后ip add查看
notion image
然后和宿主机互ping,能ping通就行
notion image
notion image
ok,接下来我们要将squashfs-root传入qemu
用scp命令传文件进去
notion image
在qemu里unzip解压
notion image
/sbin/procd &,启动进程管理器
notion image
/etc/init.d/sysapihttpd start启动sysapihttpd
发现缺少/var/lock/procd_sysapihttpd.lock这个文件
notion image
创建相应的文件,重新执行后,usock: No such file or directory报错
创建var/run/ubus.sock文件,启动/sbin/ubusd &
检查相关程序启动
notion image
notion image
nmap在主机扫段口试试
notion image
http80端口存在
但是打不开网址,curl报错
notion image
用strace跟踪一下
notion image
getsockopt报错,ida patch完后,传回qemu按下图命令覆盖
notion image
/etc/init.d/sysapihttpd start重新启动
访问ip地址
notion image

疑问

qemu仿真问题好多啊,解决完一个又冒出新的😂
缺少仿真思路,遇到问题就卡住了,仿真过程中应该有相通的地方,总结仿真思路,遇见常见的问题也能应对

0x06

记录

复现cve

出现web界面后,我们是登不上去的
原因是只启动了部分服务,按照路由器的流程配置会出现各种各样的问题,我们搭建环境的目的是验证漏洞,所以不需要完整配置,跳过配置界面就行
grep -r "init.html"查找在哪里重定向至init.html
notion image
可以看到跳转的代码
notion image
只要满足XQSysUtil.getInitInfo() 返回true,就可不跳转到init.html
查找相关代码
notion image
xiaoqiang.XQPreference 中调用get方法获取与 XQConfigs.PREF_IS_INITED 相关的值,并将其存储在局部变量 initted
只要initted为true,则进入到if代码块,返回true
notion image
只要value值为真,则return value
value值从get(config, "common", key)
notion image
从上述信息可知,config为"xiaoqiang",key为"INITTED"
执行
value值变为1,可以不重定向至init.html
重新访问ip,进入到登陆界面
notion image
用设定的密码winmt登录入路由器后台
notion image
启动
查看90909091端口正常即可
notion image
运行exp,拿shell
notion image

cs基础

根据注释要求完成代码
hw01
lab01

0x07

cisc & risc

  • cisc(complex instruction set computer)复杂指令计算机。例如x86,amd64
  • risc(reduced instruction set computer)精简指令集计算机,例如mips,arm

mips大小端

  • mips大端序
  • mipsel小端序

mips寄存器

通用寄存器
寄存器
汇编名称
解释
r0
$zero
总是为0
r1
$at
保留给汇编程序
r2-r3
$v0-$v1
储存返回值
r4-r7
$a0-$a3
储存参数
r8-r15
$t0-$t7
临时变量
r16-r23
$s0-$s7
保存
r24-r25
$t8-$t9
其他临时变量
r26-r27
$k0-$k1
为操作系统保留
r28
$gp
全局指针
r29
$sp
栈指针
r30
$fp
帧指针
r31
$ra
返回地址

mips指令格式

R类型 两个操作数和结果都在寄存器的运算指令。 如sub rd, rs, rt I类型
  • 运算指令: 一个寄存器、 、一个立即数。如 :ori rt, rs, imm16
  • LOAD和STORE指令。如:lw rt,rs, imm16
  • 条件分支指令。如:beq rs,rt,imm16
J类型 无条件跳转指令。如: j target

mips指令字段含义

op:操作码
rs:第一个源操作数寄存器
rt:第二个源操作数寄存器
rd:结果寄存器
shamt:移位指令的偏移量
func:R类型指令的op字段是000000,具体操作由func字段给定。例如:func为100000,表示加法运算
immediate:立即数或load/store指令和分支指令的偏移地址
target address:无条件转移地址的低26位。
notion image

常用R型、I型、J型指令编解码表

notion image
notion image
notion image

汇编形式与指令的对应

一条指令为0xaf8020,则对应的汇编形式为?
0xaf8020的32位:0000 0000 1010 1111 1000 0000 0010 0000
指令的前6位为000000,可知这是R类型指令,按照R类型格式
rs = 00101,rt = 01111,rd = 10000, shamt = 00000, funct = 100000
1.根据R类型指令解码表,得知是add操作
2.rs,rt,rd十进制是5,15,16,可知rs,rt,rd为:$a1,$t7,$s0
故汇编为add $s0, $a1, $t7

mips系统调用

Service
Code in $v0对应功能的调用码
Arguments所需参数
Results返回值
print_int打印一个整型
$v0 = 1
$a0 = integer to be printed将要打印的整型赋值给 $a0
print_float打印一个浮点
$v0 = 2
$f12 = float to be printed将要打印的浮点赋值给 $f12
print_double打印双精度
$v0 = 3
$f12 = double to be printed将要打印的双精度赋值给 $f12
print_string
$v0 = 4
$a0 = address of string in memory将要打印的字符串的地址赋值给 $a0
read_int
$v0 = 5
integer returned in $v0将读取的整型赋值给 $v0
read_float读取浮点
$v0 = 6
float returned in $v0将读取的浮点赋值给 $v0
read_double读取双精度
$v0 = 7
double returned in $v0将读取的双精度赋值给 $v0
read_string读取字符串
$v0 = 8
$a0 = memory address of string input buffer将读取的字符串地址赋值给 $a0 $a1 = length of string buffer (n)将读取的字符串长度赋值给 $a1
sbrk动态分配内存
$v0 = 9
$a0 = amount需要分配的空间大小
address in $v0将分配好的空间首地址给 $v0
exit退出
$v0 =10

mips汇编分析

该程序输出一个hello world
1.LI(Load Immediate)指令用于将一个立即数存入一个通用寄存器。 2.LA(Load Address) 指令用于将一个地址或标签存入一个寄存器
data段存放变量str的ascii码hello world
text段是要执行的程序,li指令将4载入$v0寄存器中,la指令str地址载入$a0寄存器,syscall进行系统调用,即打印hello world

0x08

记录

冀信

冀信vpn一掉线就连不上,难绷😅

ROP3

不给libc,又是最喜欢的测libc环节🤣
测出libc本地patch完后打one_gadget

babypie

泄露canary后单字节覆盖

ret2libc

经典ret2libc

rop-gets

静态编译的程序,ropgadget生成rop chain秒了

羊城杯

psstack

总感觉做麻烦了
这道题的核心就栈溢出,不过其他啥也没有,刚刚够覆盖返回地址
保护
notion image
主要思路是劫持rbp为bss段,返回地址改到0x4006c4重新进行read,因为改了rbp,所以可以写到bss段里
第二次read结束,程序运行到0x4006db时可以将栈迁移到bss段执行,所以第二次read在bss布置puts泄露libc,最后接上start重新运行程序
本来是想打one_gadget的,发现都不行,就同上进行栈迁移,执行system("/bin/sh"),结果还是不行,卡在了汇编的一步
然后只能打execve(/bin/sh, 0, 0),结果rop链刚好差8字节,只能在进行栈迁移,在进行read

httpd

这道题很有意思,跟固件漏洞很想,主要考察的是代码审计
notion image
ida反汇编没有main函数,打开start查看
notion image
可以确定sub_13ed是main函数,有点疑惑ida没有识别出来
程序主要逻辑
照例查看文件
notion image
运行程序试试
notion image
Internal Error迅速定位至
notion image
查询chdir的功能,改变当前的工作目录,类似linux中的cd
我的电脑没有该目录,创建该目录,重新运行
notion image
Bad Request错误,定位到
notion image
根据空格读取输入,输入需要类似a a a,执行
notion image
接下来输入需要Host: 前缀
notion image
Host: 前缀后需要输入ip格式
notion image
第三次输入前缀需要是Content-Length:
notion image
Content-Length: 后面要控制长度
notion image
第一次输入的第一个空格前必须是get,第一个空格后以/开头,第二个空格后是HTTP/1.0
notion image
第一次scanf第二个参数,v34 = /,v35可以由用户控制
notion image
notion image
然后v35赋给haystack后,sub_1F74会检查scanf第二个参数
检查会ban掉sh,bin,&,|,;,$,{,},`
接下来会将标准输出,标准错误放在/dev/null
notion image
接下来执行popen,haystack是用户能控制的,存在命令注入
简单了解下popen, 可以执行系统命令,例如fp = popen("ls -l", "r");
这样我们只需用s""h绕过检查即可弹shell
notion image
可以看到执行了命令但是没有回显
反弹shell
notion image

疑问

这周主要打比赛和培训,算是复习了下基础,主要的疑问是有的程序ida反编译不显示main函数(倒不是很影响做题)

0x09

下载锐捷固件网址https://reyee.ruijie.com/en-global/support/documents/slide_RGEW1200WirelessRoutersfirmware/#
点击download
notion image
binwalk命令解压binwalk -Me EW_3.0\\(1\\)B11P204_EW1200I_10153001_install_encypto.bin
发现解压失败
notion image
说明固件被加密了
对于被加密的固件,一般下列有几种方法
1.找之前未加密的最后一版固件,未加密固件为了升级为加密固件,其中会包含对加密固件的解密,可以找到解密的部分进行研究
2.直接分析加密后的固件,寻找具备特定规律的字节码,编写解密脚本
不过我没在官网上找到未加密的固件,故采用第二种方法分析
010editor打开固件
看见文件末全是\\x80
notion image
一般文件末会填充\\xff\\x00,这里有大量\\x80,猜测为单字节异或
易得\\x7f
python decrypt.py EW_3.0\\(1\\)B11P204_EW1200I_10153001_install_encypto.bin decrypt.bin运行下面的脚本解密
解密的文件再用binwalk -Me decrypt.bin解密
成功拿到解密的文件
notion image
注意到/usr/lib/lua目录下存放许多lua文件,主要是将前端的数据传给后端
notion image
/usr/lib/lua/luci/controller/eweb目录下,存放着api.lua
配置了路由
这段代码的含义是访问/api/auth路径时,会调用rpc_auth函数,nil是一个可选参数,.sysauth = false表示禁用系统认证。也就是说,访问/api/auth路径时,不需要用户登录或提供token
rpc_auth函数引入了四个模块分别是jsonrpchttpltn12_tbl
_tbl引入了luci.modules.noauth,从名称可以看出,这是处理不需要认证的部分
http.getenv("HTTP_CONTENT_LENGTH")获取http请求长度信息,tonumber将字符串转化为数字,如果大于1000字节,则返回too long data
http.prepare_content("application/json")设置http响应的Content-Typeapplication/json
jsonrpc.handle(_tbl, http.source())使用jsonrpc模块的handle函数,_tbl传入的是luci.modules.noauth返回的表,该表包含了login singleLogin merge checkNet四个函数。http.source是http的输入流
ltn12.pump.all()将输出传到http.write(),将结果写入http响应
luci.ltn12.pump.all()rawsource 中的数据传输到 decoder:sink(),即将原始数据解析为 JSON 格式,并存入解码器。stat表示数据传输的状态,若成功则为True
local json = decoder:get()获得解码后的json数据,json的method字段类型为string则将tbl, json.method传入resolve函数
luci.util.split(method, ".")将method字段以.分割,例如传入noauth.merge分割成{"noauth", "merge"}
if not type(mod) == "table" then break end检测mod是否为一个表table,不是表则退出循环
当调用resolve(mod, "luci.modules.noauth.merge")时:
1.method分割成luci, modules, noauthmerge
2.#path - 1为3
3.第一轮循环mod更新为luci表,第二轮循环更新为modules,第三轮更新为noauth
4.最后type(mod) == "table"检测是否为表类型,是的话返回True,and只有前面是True时执行,#path为4,path[#path]即为merge,or当type(mod) == "table" and rawget(mod, path[#path])返回false或nil时,执行or后面的表达式,mod = rawget(mod, "merge"),返回merge函数
method字段为mergelocal res = {luci.util.copcall(method, ...)}调用luci.util中的copcall函数
f为merge,传入coxpcall函数中
oldpcall(coroutine.create, f),在一个新的协程(可以理解为一种特殊的线程)中运行函数f,然后就触发了merge函数
引入了luci.modules.cmd模块,调用cmd的devSta.set函数
 
sctf_factory锐捷未授权rce复现(未完)
Loading...